From 690b41450173408d92e5de0ed9d97d70bfa4edd9 Mon Sep 17 00:00:00 2001 From: "jk7744.park" Date: Tue, 8 Sep 2015 22:06:25 +0900 Subject: [PATCH] tizen 2.3.1 release --- .gitattributes | 1 + .gitignore | 288 +- .mailmap | 65 +- .travis.yml | 14 + .vimrc | 5 + .ycm_extra_conf.py | 66 + CODING_STYLE | 166 +- DISTRO_PORTING | 64 +- LICENSE => LICENSE.GPL2 | 0 LICENSE.LGPL2.1 | 502 + LICENSE.MIT | 19 + Makefile-man.am | 1477 + Makefile.am | 6201 +- NEWS | 2964 + README | 180 +- TODO | 747 +- autogen.sh | 114 +- catalog/Makefile | 1 + catalog/systemd.catalog | 280 + catalog/systemd.fr.catalog | 260 + catalog/systemd.it.catalog | 254 + catalog/systemd.ru.catalog | 294 + configure.ac | 1115 +- debian/README.Debian | 27 - debian/changelog | 436 - debian/compat | 1 - debian/control | 129 - debian/copyright | 23 - debian/debian-fixup | 16 - debian/debian-fixup.service | 10 - debian/ifup@.service | 8 - debian/init-functions | 99 - debian/lib-init-rw.automount | 15 - debian/lib-init-rw.mount | 10 - debian/libpam-systemd.install | 2 - debian/libpam-systemd.postinst | 7 - debian/libpam-systemd.prerm | 20 - debian/libsystemd-daemon-dev.install | 3 - debian/libsystemd-daemon0.install | 1 - debian/libsystemd-daemon0.symbols | 12 - debian/libsystemd-login-dev.install | 3 - debian/libsystemd-login0.install | 1 - debian/libsystemd-login0.symbols | 21 - debian/pam-configs/systemd | 6 - debian/rules | 65 - debian/source/format | 1 - debian/source/options | 1 - debian/systemd-gui.install | 3 - debian/systemd-hack-up-the-source.hook | 9 - debian/systemd-sysv.install | 7 - debian/systemd-sysv.links | 7 - debian/systemd.dirs | 1 - debian/systemd.install | 38 - debian/systemd.links | 55 - debian/systemd.postinst | 45 - debian/systemd.postrm | 18 - debian/systemd.preinst | 18 - docs/.gitignore | 2 + docs/Makefile | 1 + docs/gtk-doc.make | 256 + docs/gudev/.gitignore | 19 + docs/gudev/Makefile.am | 115 + docs/gudev/gudev-docs.xml | 52 + docs/gudev/gudev-sections.txt | 102 + docs/gudev/gudev.types | 4 + docs/gudev/version.xml.in | 1 + docs/libudev/.gitignore | 19 + docs/libudev/Makefile.am | 109 + docs/libudev/libudev-docs.xml | 40 + docs/libudev/libudev-sections.txt | 135 + docs/libudev/libudev.types | 0 docs/libudev/version.xml.in | 1 + docs/sysvinit/.gitignore | 1 + {units/fedora => docs/sysvinit}/Makefile | 0 docs/sysvinit/README.in | 27 + docs/var-log/.gitignore | 1 + docs/var-log/Makefile | 1 + docs/var-log/README.in | 26 + hwdb/.gitignore | 4 + hwdb/20-OUI.hwdb | 70100 ++++++++++++++++++ hwdb/20-acpi-vendor.hwdb | 6593 ++ hwdb/20-bluetooth-vendor-product.hwdb | 904 + hwdb/20-net-ifname.hwdb | 5 + hwdb/20-pci-classes.hwdb | 531 + hwdb/20-pci-vendor-model.hwdb | 72036 +++++++++++++++++++ hwdb/20-sdio-classes.hwdb | 33 + hwdb/20-sdio-vendor-model.hwdb | 177 + hwdb/20-usb-classes.hwdb | 339 + hwdb/20-usb-vendor-model.hwdb | 49953 +++++++++++++ hwdb/60-keyboard.hwdb | 1104 + hwdb/Makefile | 1 + hwdb/ids-update.pl | 340 + hwdb/sdio.ids | 84 + introspect.awk | 13 - libsystemd-daemon.pc.in | 19 - libsystemd-login.pc.in | 18 - m4/.gitignore | 1 + m4/attributes.m4 | 77 +- m4/gtk-doc.m4 | 67 + m4/libgcrypt.m4 | 123 + man/.gitignore | 6 +- man/binfmt.d.xml | 69 +- man/bootchart.conf.xml | 164 + man/bootctl.xml | 114 + man/bootup.xml | 318 + man/busctl.xml | 197 + man/crypttab.xml | 388 + man/custom-html.xsl | 184 + man/custom-man.xsl | 64 + man/daemon.xml | 277 +- man/halt.xml | 39 +- man/hostname.xml | 37 +- man/hostnamectl.xml | 253 + man/journalctl.xml | 916 + man/journald.conf.xml | 469 + man/kernel-command-line.xml | 330 + man/kernel-install.xml | 185 + man/less-variables.xml | 29 + man/libsystemd-pkgconfig.xml | 12 + man/locale.conf.xml | 27 +- man/localectl.xml | 248 + man/localtime.xml | 103 + man/loginctl.xml | 453 + man/logind.conf.xml | 307 + man/machine-id.xml | 52 +- man/machine-info.xml | 68 +- man/machinectl.xml | 277 + man/modules-load.d.xml | 84 +- man/nss-myhostname.xml | 133 + man/os-release.xml | 285 +- man/pam_systemd.xml | 262 +- man/runlevel.xml | 20 +- man/sd-daemon.xml | 82 +- man/sd-id128.xml | 173 + man/sd-journal.xml | 125 + man/sd-login.xml | 139 + man/sd-readahead.xml | 20 +- man/sd_booted.xml | 59 +- man/sd_bus_creds_get_pid.xml | 453 + man/sd_bus_creds_new_from_pid.xml | 275 + man/sd_bus_error.xml | 415 + man/sd_bus_label_escape.xml | 111 + man/sd_bus_message_get_cookie.xml | 152 + man/sd_bus_message_get_monotonic_usec.xml | 183 + man/sd_bus_new.xml | 145 + man/sd_bus_open_user.xml | 217 + man/sd_bus_request_name.xml | 228 + man/sd_get_seats.xml | 141 + man/sd_id128_get_machine.xml | 137 + man/sd_id128_randomize.xml | 116 + man/sd_id128_to_string.xml | 136 + man/sd_is_fifo.xml | 107 +- man/sd_journal_add_match.xml | 220 + man/sd_journal_get_catalog.xml | 141 + man/sd_journal_get_cursor.xml | 150 + man/sd_journal_get_cutoff_realtime_usec.xml | 144 + man/sd_journal_get_data.xml | 250 + man/sd_journal_get_fd.xml | 349 + man/sd_journal_get_realtime_usec.xml | 146 + man/sd_journal_get_usage.xml | 103 + man/sd_journal_next.xml | 213 + man/sd_journal_open.xml | 253 + man/sd_journal_print.xml | 265 + man/sd_journal_query_unique.xml | 215 + man/sd_journal_seek_head.xml | 179 + man/sd_journal_stream_fd.xml | 170 + man/sd_listen_fds.xml | 71 +- man/sd_login_monitor_new.xml | 245 + man/sd_notify.xml | 96 +- man/sd_pid_get_session.xml | 213 + man/sd_readahead.xml | 46 +- man/sd_seat_get_active.xml | 183 + man/sd_session_is_active.xml | 318 + man/sd_uid_get_state.xml | 189 + man/sd_watchdog_enabled.xml | 170 + man/shutdown.xml | 29 +- man/standard-options.xml | 30 + man/sysctl.d.xml | 97 +- man/systemadm.xml | 111 - man/systemctl.xml | 2540 +- man/systemd-activate.xml | 172 + man/systemd-analyze.xml | 304 + man/systemd-ask-password-console.service.xml | 96 + man/systemd-ask-password.xml | 32 +- man/systemd-backlight@.service.xml | 92 + man/systemd-binfmt.service.xml | 76 + man/systemd-bootchart.xml | 335 + man/systemd-bus-proxyd.xml | 109 + man/systemd-bus-proxyd@.service.xml | 81 + man/systemd-cat.xml | 194 + man/systemd-cgls.xml | 67 +- man/systemd-cgtop.xml | 270 + man/systemd-coredumpctl.xml | 198 + man/systemd-cryptsetup-generator.xml | 194 + man/systemd-cryptsetup@.service.xml | 87 + man/systemd-delta.xml | 216 + man/systemd-detect-virt.xml | 140 + man/systemd-efi-boot-generator.xml | 88 + man/systemd-fsck@.service.xml | 113 + man/systemd-fstab-generator.xml | 124 + man/systemd-getty-generator.xml | 101 + man/systemd-gpt-auto-generator.xml | 104 + man/systemd-halt.service.xml | 125 + man/systemd-hostnamed.service.xml | 87 + man/systemd-inhibit.xml | 194 + man/systemd-initctl.service.xml | 76 + man/systemd-journal-gatewayd.service.xml | 302 + man/systemd-journald.service.xml | 253 + man/systemd-localed.service.xml | 89 + man/systemd-loginctl.xml | 457 - man/systemd-logind.conf.xml | 175 - man/systemd-logind.service.xml | 131 + man/systemd-machine-id-setup.xml | 121 + man/systemd-machined.service.xml | 85 + man/systemd-modules-load.service.xml | 100 + man/systemd-networkd.service.xml | 435 + man/systemd-notify.xml | 32 +- man/systemd-nspawn.xml | 534 +- man/systemd-quotacheck.service.xml | 102 + man/systemd-random-seed.service.xml | 75 + man/systemd-readahead-replay.service.xml | 203 + man/systemd-remount-fs.service.xml | 93 + man/systemd-rfkill@.service.xml | 92 + man/systemd-run.xml | 204 + man/systemd-shutdownd.service.xml | 77 + man/systemd-sleep.conf.xml | 179 + man/systemd-socket-proxyd.xml | 195 + man/systemd-suspend.service.xml | 155 + man/systemd-sysctl.service.xml | 77 + man/systemd-system-update-generator.xml | 79 + man/systemd-system.conf.xml | 388 + man/systemd-timedated.service.xml | 88 + man/systemd-tmpfiles.xml | 111 +- man/systemd-tty-ask-password-agent.xml | 154 + man/systemd-udevd.service.xml | 195 + man/systemd-update-utmp.service.xml | 76 + man/systemd-user-sessions.service.xml | 77 + man/systemd-vconsole-setup.service.xml | 118 + man/systemd.automount.xml | 33 +- man/systemd.conf.xml | 162 - man/systemd.device.xml | 95 +- man/systemd.exec.xml | 965 +- man/systemd.journal-fields.xml | 602 + man/systemd.kill.xml | 216 + man/systemd.mount.xml | 192 +- man/systemd.path.xml | 80 +- man/systemd.preset.xml | 203 + man/systemd.resource-control.xml | 368 + man/systemd.scope.xml | 100 + man/systemd.service.xml | 947 +- man/systemd.slice.xml | 121 + man/systemd.snapshot.xml | 19 +- man/systemd.socket.xml | 395 +- man/systemd.special.xml | 1100 + man/systemd.special.xml.in | 725 - man/systemd.swap.xml | 112 +- man/systemd.target.xml | 17 +- man/systemd.time.xml | 293 + man/systemd.timer.xml | 111 +- man/systemd.unit.xml | 1183 +- man/systemd.xml | 464 +- man/telinit.xml | 18 +- man/timedatectl.xml | 247 + man/timezone.xml | 90 - man/tmpfiles.d.xml | 362 +- man/udev.xml | 1051 + man/udevadm.xml | 602 + man/user-system-options.xml | 45 + man/vconsole.conf.xml | 31 +- network/80-container-host0.network | 6 + network/99-default.link | 3 + packaging/apply-conf.sh | 16 + packaging/systemd.manifest | 11 + packaging/systemd.spec | 659 +- packaging/tizen-bootchart.conf | 21 + packaging/tizen-journald.conf | 33 + packaging/tizen-system-mobile.conf | 50 + packaging/tizen-system-wearable.conf | 44 + po/.gitignore | 3 + po/LINGUAS | 4 + po/Makefile.in.in | 222 + po/POTFILES.in | 9 +- po/POTFILES.skip | 37 +- po/fr.po | 397 + po/it.po | 379 + po/pl.po | 393 +- po/ru.po | 295 + rules/.gitignore | 1 + rules/42-usb-hid-pm.rules | 39 + rules/50-firmware.rules | 3 + rules/50-udev-default.rules | 69 + rules/60-cdrom_id.rules | 20 + rules/60-drm.rules | 3 + rules/60-keyboard.rules | 22 + rules/60-persistent-alsa.rules | 14 + rules/60-persistent-input.rules | 38 + rules/60-persistent-serial.rules | 20 + rules/60-persistent-storage-tape.rules | 25 + rules/60-persistent-storage.rules | 87 + rules/60-persistent-v4l.rules | 21 + rules/61-accelerometer.rules | 3 + rules/64-btrfs.rules | 13 + rules/75-net-description.rules | 14 + rules/75-probe_mtd.rules | 7 + rules/75-tty-description.rules | 12 + rules/78-sound-card.rules | 86 + rules/80-drivers.rules | 13 + rules/80-net-setup-link.rules | 15 + rules/95-udev-late.rules | 4 + rules/99-systemd.rules.in | 70 + rules/Makefile | 1 + shell-completion/bash/bootctl | 60 + shell-completion/bash/busctl | 89 + shell-completion/bash/hostnamectl | 61 + shell-completion/bash/journalctl | 114 + shell-completion/bash/kernel-install | 50 + shell-completion/bash/localectl | 92 + shell-completion/bash/loginctl | 109 + shell-completion/bash/machinectl | 97 + shell-completion/bash/systemctl | 229 + shell-completion/bash/systemd-analyze | 86 + shell-completion/bash/systemd-coredumpctl | 85 + shell-completion/bash/systemd-delta | 61 + shell-completion/bash/systemd-run | 63 + shell-completion/bash/timedatectl | 76 + shell-completion/bash/udevadm | 97 + shell-completion/zsh/_bootctl | 25 + shell-completion/zsh/_busctl | 54 + shell-completion/zsh/_hostnamectl | 32 + shell-completion/zsh/_journalctl | 93 + shell-completion/zsh/_kernel-install | 26 + shell-completion/zsh/_localectl | 88 + shell-completion/zsh/_loginctl | 106 + shell-completion/zsh/_machinectl | 42 + shell-completion/zsh/_sd_hosts_or_user_at_host | 5 + shell-completion/zsh/_sd_machines | 13 + shell-completion/zsh/_sd_outputmodes | 5 + shell-completion/zsh/_systemctl | 341 + shell-completion/zsh/_systemd | 83 + shell-completion/zsh/_systemd-analyze | 44 + shell-completion/zsh/_systemd-coredumpctl | 36 + shell-completion/zsh/_systemd-delta | 15 + shell-completion/zsh/_systemd-inhibit | 33 + shell-completion/zsh/_systemd-nspawn | 24 + shell-completion/zsh/_systemd-run | 33 + shell-completion/zsh/_systemd-tmpfiles | 10 + shell-completion/zsh/_timedatectl | 65 + shell-completion/zsh/_udevadm | 141 + src/.gitignore | 13 +- src/70-uaccess.rules | 72 - src/71-seat.rules | 22 - src/73-seat-late.rules.in | 17 - src/99-systemd.rules.in | 55 - src/Makefile | 8 +- src/ac-power.c | 111 - src/ac-power/Makefile | 1 + src/ac-power/ac-power.c | 37 + src/activate/Makefile | 1 + src/activate/activate.c | 434 + src/analyze/.gitignore | 1 + src/analyze/Makefile | 1 + src/analyze/analyze.c | 1307 + src/ask-password-api.c | 576 - src/ask-password-api.h | 33 - src/ask-password.c | 184 - src/ask-password/Makefile | 1 + src/ask-password/ask-password.c | 182 + src/automount.c | 869 - src/automount.h | 67 - src/backlight/Makefile | 1 + src/backlight/backlight.c | 341 + src/binfmt.c | 164 - src/binfmt/Makefile | 1 + src/binfmt/binfmt.c | 221 + src/boot/Makefile | 1 + src/boot/boot-efi.c | 190 + src/boot/boot-loader.c | 132 + src/boot/boot-loader.h | 25 + src/boot/boot.h | 64 + src/boot/bootctl.c | 288 + src/bootchart/Makefile | 1 + src/bootchart/bootchart.c | 507 + src/bootchart/bootchart.conf | 21 + src/bootchart/bootchart.h | 135 + src/bootchart/store.c | 508 + src/bootchart/store.h | 35 + src/bootchart/svg.c | 1326 + src/bootchart/svg.h | 27 + src/bridge.c | 367 - src/build.h | 63 - src/bus-driverd/Makefile | 1 + src/bus-driverd/bus-driverd.c | 957 + src/bus-errors.h | 58 - src/bus-proxyd/Makefile | 1 + src/bus-proxyd/bus-proxyd.c | 784 + src/cgls.c | 154 - src/cgls/Makefile | 1 + src/cgls/cgls.c | 217 + src/cgroup-attr.c | 102 - src/cgroup-attr.h | 49 - src/cgroup-show.c | 257 - src/cgroup-show.h | 28 - src/cgroup-util.c | 1076 - src/cgroup-util.h | 72 - src/cgroup.c | 515 - src/cgroup.h | 93 - src/cgroups-agent.c | 101 - src/cgroups-agent/Makefile | 1 + src/cgroups-agent/cgroups-agent.c | 68 + src/cgtop/Makefile | 1 + src/cgtop/cgtop.c | 851 + src/compat-libs/.gitignore | 1 + src/compat-libs/libsystemd-daemon.pc.in | 19 + src/{ => compat-libs}/libsystemd-daemon.sym | 0 src/compat-libs/libsystemd-id128.pc.in | 18 + src/compat-libs/libsystemd-id128.sym | 21 + src/compat-libs/libsystemd-journal.pc.in | 19 + src/compat-libs/libsystemd-journal.sym | 111 + src/compat-libs/libsystemd-login.pc.in | 18 + src/compat-libs/libsystemd-login.sym | 87 + src/compat-libs/linkwarning.h | 33 + src/condition.c | 321 - src/condition.h | 69 - src/conf-parser.c | 754 - src/conf-parser.h | 133 - src/core/.gitignore | 2 + src/core/Makefile | 1 + src/core/async.c | 72 + src/core/async.h | 25 + src/core/audit-fd.c | 73 + src/core/audit-fd.h | 25 + src/core/automount.c | 891 + src/core/automount.h | 69 + src/core/build.h | 96 + src/core/busname.c | 601 + src/core/busname.h | 65 + src/core/cgroup.c | 968 + src/core/cgroup.h | 122 + src/core/condition.c | 215 + src/core/condition.h | 26 + src/core/dbus-automount.c | 36 + src/core/dbus-automount.h | 26 + src/core/dbus-busname.c | 35 + src/core/dbus-busname.h | 27 + src/core/dbus-cgroup.c | 530 + src/core/dbus-cgroup.h | 29 + src/core/dbus-client-track.c | 251 + src/core/dbus-client-track.h | 42 + src/core/dbus-device.c | 31 + src/core/dbus-device.h | 27 + src/core/dbus-execute.c | 802 + src/core/dbus-execute.h | 46 + src/core/dbus-job.c | 224 + src/core/dbus-job.h | 30 + src/core/dbus-kill.c | 123 + src/core/dbus-kill.h | 30 + src/core/dbus-manager.c | 1740 + src/core/dbus-manager.h | 32 + src/core/dbus-mount.c | 150 + src/core/dbus-mount.h | 30 + src/core/dbus-path.c | 88 + src/core/dbus-path.h | 27 + src/core/dbus-scope.c | 220 + src/core/dbus-scope.h | 32 + src/core/dbus-service.c | 265 + src/core/dbus-service.h | 30 + src/core/dbus-slice.c | 55 + src/core/dbus-slice.h | 30 + src/core/dbus-snapshot.c | 50 + src/core/dbus-snapshot.h | 28 + src/core/dbus-socket.c | 152 + src/core/dbus-socket.h | 30 + src/core/dbus-swap.c | 95 + src/core/dbus-swap.h | 31 + src/core/dbus-target.c | 30 + src/core/dbus-target.h | 26 + src/core/dbus-timer.c | 148 + src/core/dbus-timer.h | 26 + src/core/dbus-unit.c | 979 + src/core/dbus-unit.h | 39 + src/core/dbus.c | 1141 + src/core/dbus.h | 34 + src/core/device.c | 673 + src/core/device.h | 54 + src/core/execute.c | 2627 + src/core/execute.h | 244 + src/core/hostname-setup.c | 92 + src/core/hostname-setup.h | 24 + src/core/ima-setup.c | 110 + src/core/ima-setup.h | 26 + src/core/job.c | 1166 + src/core/job.h | 226 + src/core/kill.c | 67 + src/core/kill.h | 64 + src/core/killall.c | 228 + src/core/killall.h | 24 + src/core/kmod-setup.c | 123 + src/core/kmod-setup.h | 24 + src/core/load-dropin.c | 214 + src/core/load-dropin.h | 29 + src/core/load-fragment-gperf.gperf.m4 | 299 + src/core/load-fragment.c | 3079 + src/core/load-fragment.h | 96 + src/core/locale-setup.c | 165 + src/core/locale-setup.h | 24 + src/core/loopback-setup.c | 205 + src/core/loopback-setup.h | 24 + src/core/machine-id-setup.c | 237 + src/core/machine-id-setup.h | 24 + src/core/macros.systemd.in | 78 + src/core/main.c | 1996 + src/core/manager.c | 2940 + src/core/manager.h | 318 + src/core/mount-setup.c | 416 + src/core/mount-setup.h | 33 + src/core/mount.c | 1841 + src/core/mount.h | 128 + src/core/namespace.c | 519 + src/core/namespace.h | 38 + src/core/org.freedesktop.systemd1.conf | 96 + src/core/org.freedesktop.systemd1.policy.in.in | 41 + src/core/org.freedesktop.systemd1.service | 11 + src/core/path.c | 809 + src/core/path.h | 106 + src/core/scope.c | 563 + src/core/scope.h | 72 + src/core/selinux-access.c | 270 + src/core/selinux-access.h | 44 + src/core/selinux-setup.c | 127 + src/core/selinux-setup.h | 26 + src/core/service.c | 3937 + src/core/service.h | 226 + src/core/shutdown.c | 467 + src/core/slice.c | 322 + src/core/slice.h | 46 + src/core/smack-setup.c | 173 + src/core/smack-setup.h | 26 + src/core/snapshot.c | 307 + src/core/snapshot.h | 49 + src/core/socket.c | 2468 + src/core/socket.h | 178 + src/core/swap.c | 1492 + src/core/swap.h | 130 + src/core/switch-root.c | 167 + src/core/switch-root.h | 24 + src/core/sysfs-show.h | 24 + src/core/system.conf | 50 + src/core/systemd.pc.in | 26 + src/core/target.c | 240 + src/core/target.h | 44 + src/core/tcpwrap.c | 68 + src/core/tcpwrap.h | 26 + src/core/timer.c | 649 + src/core/timer.h | 99 + src/core/transaction.c | 1148 + src/core/transaction.h | 54 + src/core/umount.c | 608 + src/core/umount.h | 30 + src/core/unit-printf.c | 449 + src/core/unit-printf.h | 28 + src/core/unit.c | 3268 + src/core/unit.h | 643 + src/core/user.conf | 40 + src/cryptsetup-generator.c | 296 - src/cryptsetup.c | 529 - src/cryptsetup/Makefile | 1 + src/cryptsetup/cryptsetup-generator.c | 553 + src/cryptsetup/cryptsetup.c | 652 + src/dbus-automount.c | 57 - src/dbus-automount.h | 33 - src/dbus-common.c | 1047 - src/dbus-common.h | 174 - src/dbus-device.c | 58 - src/dbus-device.h | 34 - src/dbus-execute.c | 357 - src/dbus-execute.h | 190 - src/dbus-job.c | 349 - src/dbus-job.h | 36 - src/dbus-loop.c | 263 - src/dbus-loop.h | 30 - src/dbus-manager.c | 1525 - src/dbus-manager.h | 31 - src/dbus-mount.c | 157 - src/dbus-mount.h | 34 - src/dbus-path.c | 105 - src/dbus-path.h | 33 - src/dbus-service.c | 134 - src/dbus-service.h | 34 - src/dbus-snapshot.c | 87 - src/dbus-snapshot.h | 33 - src/dbus-socket.c | 126 - src/dbus-socket.h | 34 - src/dbus-swap.c | 100 - src/dbus-swap.h | 35 - src/dbus-target.c | 55 - src/dbus-target.h | 33 - src/dbus-timer.c | 125 - src/dbus-timer.h | 34 - src/dbus-unit.c | 788 - src/dbus-unit.h | 207 - src/dbus.c | 1338 - src/dbus.h | 53 - src/dbus1-generator/Makefile | 1 + src/dbus1-generator/dbus1-generator.c | 354 + src/def.h | 37 - src/delta/Makefile | 1 + src/delta/delta.c | 636 + src/detect-virt.c | 48 - src/detect-virt/Makefile | 1 + src/detect-virt/detect-virt.c | 169 + src/device.c | 613 - src/device.h | 59 - src/efi-boot-generator/Makefile | 1 + src/efi-boot-generator/efi-boot-generator.c | 124 + src/execute.c | 1997 - src/execute.h | 230 - src/exit-status.c | 177 - src/exit-status.h | 84 - src/fdset.c | 167 - src/fdset.h | 40 - src/fsck.c | 406 - src/fsck/Makefile | 1 + src/fsck/fsck.c | 378 + src/fstab-generator/Makefile | 1 + src/fstab-generator/fstab-generator.c | 656 + src/generate-kbd-model-map | 33 - src/getty-generator.c | 182 - src/getty-generator/Makefile | 1 + src/getty-generator/getty-generator.c | 239 + src/gnome-ask-password-agent.vala | 276 - src/gpt-auto-generator/Makefile | 1 + src/gpt-auto-generator/gpt-auto-generator.c | 492 + src/gudev/.gitignore | 7 + src/gudev/Makefile | 1 + src/gudev/gjs-example.js | 75 + src/gudev/gudev-1.0.pc.in | 11 + src/gudev/gudev.h | 32 + src/gudev/gudevclient.c | 525 + src/gudev/gudevclient.h | 99 + src/gudev/gudevdevice.c | 1014 + src/gudev/gudevdevice.h | 130 + src/gudev/gudevenumerator.c | 429 + src/gudev/gudevenumerator.h | 106 + src/gudev/gudevenums.h | 48 + src/gudev/gudevenumtypes.c.template | 39 + src/gudev/gudevenumtypes.h.template | 24 + src/gudev/gudevmarshal.list | 1 + src/gudev/gudevprivate.h | 40 + src/gudev/gudevtypes.h | 50 + src/gudev/seed-example-enum.js | 38 + src/gudev/seed-example.js | 72 + src/hashmap.c | 720 - src/hashmap.h | 90 - src/hostname-setup.c | 187 - src/hostname-setup.h | 27 - src/hostname/.gitignore | 1 + src/hostname/Makefile | 1 + src/hostname/hostnamectl.c | 492 + src/hostname/hostnamed.c | 652 + src/hostname/org.freedesktop.hostname1.conf | 27 + src/hostname/org.freedesktop.hostname1.policy.in | 50 + src/hostname/org.freedesktop.hostname1.service | 12 + src/hostnamed.c | 623 - src/initctl.c | 442 - src/initctl/Makefile | 1 + src/initctl/initctl.c | 439 + src/initreq.h | 77 - src/install.c | 1954 - src/install.h | 89 - src/ioprio.h | 57 - src/job.c | 762 - src/job.h | 179 - src/journal/.gitignore | 2 + src/journal/Makefile | 1 + src/journal/browse.html | 544 + src/journal/cat.c | 180 + src/journal/catalog.c | 690 + src/journal/catalog.h | 38 + src/journal/compress.c | 216 + src/journal/compress.h | 35 + src/journal/coredump.c | 284 + src/journal/coredumpctl.c | 595 + src/journal/fsprg.c | 390 + src/journal/fsprg.h | 66 + src/journal/journal-authenticate.c | 563 + src/journal/journal-authenticate.h | 44 + src/journal/journal-def.h | 216 + src/journal/journal-file.c | 2991 + src/journal/journal-file.h | 223 + src/journal/journal-gatewayd.c | 1058 + src/journal/journal-internal.h | 143 + src/journal/journal-qrcode.c | 138 + src/journal/journal-qrcode.h | 30 + src/journal/journal-send.c | 572 + src/journal/journal-vacuum.c | 339 + src/journal/journal-vacuum.h | 26 + src/journal/journal-verify.c | 1264 + src/journal/journal-verify.h | 26 + src/journal/journalctl.c | 1937 + src/journal/journald-console.c | 111 + src/journal/journald-console.h | 26 + src/journal/journald-gperf.gperf | 40 + src/journal/journald-kmsg.c | 475 + src/journal/journald-kmsg.h | 31 + src/journal/journald-native.c | 429 + src/journal/journald-native.h | 30 + src/journal/journald-rate-limit.c | 264 + src/journal/journald-rate-limit.h | 31 + src/journal/journald-server.c | 1677 + src/journal/journald-server.h | 175 + src/journal/journald-stream.c | 476 + src/journal/journald-stream.h | 28 + src/journal/journald-syslog.c | 495 + src/journal/journald-syslog.h | 36 + src/journal/journald.c | 130 + src/journal/journald.conf | 33 + src/journal/lookup3.c | 1009 + src/journal/lookup3.h | 24 + src/journal/microhttpd-util.c | 41 + src/journal/microhttpd-util.h | 28 + src/journal/mmap-cache.c | 636 + src/journal/mmap-cache.h | 55 + src/journal/sd-journal.c | 2693 + src/journal/test-catalog.c | 181 + src/journal/test-journal-enum.c | 55 + src/journal/test-journal-flush.c | 71 + src/journal/test-journal-init.c | 60 + src/journal/test-journal-interleaving.c | 298 + src/journal/test-journal-match.c | 76 + src/journal/test-journal-send.c | 78 + src/journal/test-journal-stream.c | 185 + src/journal/test-journal-syslog.c | 44 + src/journal/test-journal-verify.c | 151 + src/journal/test-journal.c | 190 + src/journal/test-mmap-cache.c | 80 + src/kbd-model-map | 72 - src/kernel-install/50-depmod.install | 8 + src/kernel-install/90-loaderentry.install | 87 + src/kernel-install/kernel-install | 136 + src/kmod-setup.c | 82 - src/kmod-setup.h | 27 - src/kmsg-syslogd.c | 513 - src/label.c | 413 - src/label.h | 51 - src/libsystemd-dhcp/Makefile | 1 + src/libsystemd-dhcp/dhcp-internal.h | 55 + src/libsystemd-dhcp/dhcp-lease.c | 244 + src/libsystemd-dhcp/dhcp-lease.h | 57 + src/libsystemd-dhcp/dhcp-network.c | 109 + src/libsystemd-dhcp/dhcp-option.c | 184 + src/libsystemd-dhcp/dhcp-packet.c | 190 + src/libsystemd-dhcp/dhcp-protocol.h | 121 + src/libsystemd-dhcp/sd-dhcp-client.c | 1051 + src/libsystemd-dhcp/test-dhcp-client.c | 496 + src/libsystemd-dhcp/test-dhcp-option.c | 378 + src/libsystemd-login.sym | 35 - src/libsystemd/.gitignore | 2 + src/libsystemd/Makefile | 1 + src/libsystemd/libsystemd.pc.in | 18 + src/libsystemd/libsystemd.sym.m4 | 382 + src/libsystemd/sd-bus/.gitignore | 1 + src/libsystemd/sd-bus/DIFFERENCES | 28 + src/libsystemd/sd-bus/GVARIANT-SERIALIZATION | 63 + src/libsystemd/sd-bus/Makefile | 1 + src/libsystemd/sd-bus/PORTING-DBUS1 | 575 + src/libsystemd/sd-bus/bus-bloom.c | 149 + src/libsystemd/sd-bus/bus-bloom.h | 43 + src/libsystemd/sd-bus/bus-container.c | 241 + src/libsystemd/sd-bus/bus-container.h | 27 + src/libsystemd/sd-bus/bus-control.c | 1231 + src/libsystemd/sd-bus/bus-control.h | 30 + src/libsystemd/sd-bus/bus-convenience.c | 442 + src/libsystemd/sd-bus/bus-creds.c | 925 + src/libsystemd/sd-bus/bus-creds.h | 77 + src/libsystemd/sd-bus/bus-dump.c | 426 + src/libsystemd/sd-bus/bus-dump.h | 31 + src/libsystemd/sd-bus/bus-error-mapping.gperf | 49 + src/libsystemd/sd-bus/bus-error.c | 504 + src/libsystemd/sd-bus/bus-error.h | 42 + src/libsystemd/sd-bus/bus-gvariant.c | 249 + src/libsystemd/sd-bus/bus-gvariant.h | 26 + src/libsystemd/sd-bus/bus-internal.c | 305 + src/libsystemd/sd-bus/bus-internal.h | 335 + src/libsystemd/sd-bus/bus-introspect.c | 212 + src/libsystemd/sd-bus/bus-introspect.h | 42 + src/libsystemd/sd-bus/bus-kernel.c | 1498 + src/libsystemd/sd-bus/bus-kernel.h | 83 + src/libsystemd/sd-bus/bus-match.c | 1078 + src/libsystemd/sd-bus/bus-match.h | 93 + src/libsystemd/sd-bus/bus-message.c | 5567 ++ src/libsystemd/sd-bus/bus-message.h | 246 + src/libsystemd/sd-bus/bus-objects.c | 2507 + src/libsystemd/sd-bus/bus-objects.h | 26 + src/libsystemd/sd-bus/bus-protocol.h | 147 + src/libsystemd/sd-bus/bus-signature.c | 160 + src/libsystemd/sd-bus/bus-signature.h | 31 + src/libsystemd/sd-bus/bus-socket.c | 1105 + src/libsystemd/sd-bus/bus-socket.h | 39 + src/libsystemd/sd-bus/bus-type.c | 179 + src/libsystemd/sd-bus/bus-type.h | 36 + src/libsystemd/sd-bus/bus-util.c | 1232 + src/libsystemd/sd-bus/bus-util.h | 180 + src/libsystemd/sd-bus/busctl.c | 533 + src/libsystemd/sd-bus/kdbus.h | 961 + src/libsystemd/sd-bus/sd-bus.c | 3126 + src/libsystemd/sd-bus/sd-memfd.c | 321 + src/libsystemd/sd-bus/test-bus-chat.c | 581 + src/libsystemd/sd-bus/test-bus-cleanup.c | 80 + src/libsystemd/sd-bus/test-bus-creds.c | 46 + src/libsystemd/sd-bus/test-bus-error.c | 115 + src/libsystemd/sd-bus/test-bus-gvariant.c | 201 + src/libsystemd/sd-bus/test-bus-introspect.c | 66 + src/libsystemd/sd-bus/test-bus-kernel-benchmark.c | 303 + src/libsystemd/sd-bus/test-bus-kernel-bloom.c | 115 + src/libsystemd/sd-bus/test-bus-kernel.c | 188 + src/libsystemd/sd-bus/test-bus-marshal.c | 324 + src/libsystemd/sd-bus/test-bus-match.c | 145 + src/libsystemd/sd-bus/test-bus-memfd.c | 180 + src/libsystemd/sd-bus/test-bus-objects.c | 500 + src/libsystemd/sd-bus/test-bus-server.c | 224 + src/libsystemd/sd-bus/test-bus-signature.c | 163 + src/libsystemd/sd-bus/test-bus-zero-copy.c | 197 + src/libsystemd/sd-daemon/sd-daemon.c | 537 + src/libsystemd/sd-event/Makefile | 1 + src/libsystemd/sd-event/event-util.h | 30 + src/libsystemd/sd-event/sd-event.c | 2296 + src/libsystemd/sd-event/test-event.c | 248 + src/libsystemd/sd-id128/Makefile | 1 + src/libsystemd/sd-id128/libsystemd-id128.pc.in | 18 + src/libsystemd/sd-id128/sd-id128.c | 226 + src/libsystemd/sd-resolve/Makefile | 1 + src/libsystemd/sd-resolve/resolve-util.h | 29 + src/libsystemd/sd-resolve/sd-resolve.c | 1261 + src/libsystemd/sd-resolve/test-resolve.c | 163 + src/libsystemd/sd-rtnl/Makefile | 1 + src/libsystemd/sd-rtnl/rtnl-internal.h | 108 + src/libsystemd/sd-rtnl/rtnl-message.c | 1032 + src/libsystemd/sd-rtnl/rtnl-util.c | 171 + src/libsystemd/sd-rtnl/rtnl-util.h | 46 + src/libsystemd/sd-rtnl/sd-rtnl.c | 872 + src/libsystemd/sd-rtnl/test-rtnl.c | 394 + src/libsystemd/sd-utf8/Makefile | 1 + src/libsystemd/sd-utf8/sd-utf8.c | 36 + src/libudev/.gitignore | 1 + src/libudev/Makefile | 1 + src/libudev/libudev-device-private.c | 191 + src/libudev/libudev-device.c | 1873 + src/libudev/libudev-enumerate.c | 970 + src/libudev/libudev-hwdb-def.h | 74 + src/libudev/libudev-hwdb.c | 396 + src/libudev/libudev-list.c | 355 + src/libudev/libudev-monitor.c | 854 + src/libudev/libudev-private.h | 176 + src/libudev/libudev-queue-private.c | 406 + src/libudev/libudev-queue.c | 480 + src/libudev/libudev-util.c | 442 + src/libudev/libudev.c | 315 + src/libudev/libudev.h | 205 + src/libudev/libudev.pc.in | 17 + src/libudev/libudev.sym | 114 + src/linux/auto_dev-ioctl.h | 229 - src/list.h | 128 - src/load-dropin.c | 150 - src/load-dropin.h | 31 - src/load-fragment-gperf.gperf.m4 | 219 - src/load-fragment.c | 2424 - src/load-fragment.h | 90 - src/locale-setup.c | 251 - src/locale-setup.h | 27 - src/locale/.gitignore | 1 + src/locale/Makefile | 1 + src/locale/generate-kbd-model-map | 31 + src/locale/kbd-model-map | 65 + src/locale/localectl.c | 822 + src/locale/localed.c | 1162 + src/locale/org.freedesktop.locale1.conf | 27 + src/locale/org.freedesktop.locale1.policy.in | 40 + src/locale/org.freedesktop.locale1.service | 12 + src/localed.c | 1429 - src/log.c | 593 - src/log.h | 102 - src/login/.gitignore | 4 + src/login/70-power-switch.rules | 13 + src/login/70-uaccess.rules | 75 + src/login/71-seat.rules.in | 48 + src/login/73-seat-late.rules.in | 17 + src/login/Makefile | 1 + src/login/inhibit.c | 285 + src/login/login-shared.c | 29 + src/login/login-shared.h | 24 + src/login/loginctl.c | 1326 + src/login/logind-acl.c | 287 + src/login/logind-acl.h | 57 + src/login/logind-action.c | 173 + src/login/logind-action.h | 51 + src/login/logind-button.c | 283 + src/login/logind-button.h | 48 + src/login/logind-core.c | 516 + src/login/logind-dbus.c | 2492 + src/login/logind-device.c | 126 + src/login/logind-device.h | 47 + src/login/logind-gperf.gperf | 32 + src/login/logind-inhibit.c | 478 + src/login/logind-inhibit.h | 94 + src/login/logind-seat-dbus.c | 448 + src/login/logind-seat.c | 661 + src/login/logind-seat.h | 98 + src/login/logind-session-dbus.c | 698 + src/login/logind-session-device.c | 483 + src/login/logind-session-device.h | 59 + src/login/logind-session.c | 1140 + src/login/logind-session.h | 177 + src/login/logind-user-dbus.c | 364 + src/login/logind-user.c | 693 + src/login/logind-user.h | 93 + src/login/logind.c | 1167 + src/login/logind.conf | 26 + src/login/logind.h | 179 + src/login/multi-seat-x.c | 108 + src/login/org.freedesktop.login1.conf | 174 + src/login/org.freedesktop.login1.policy.in | 273 + src/login/org.freedesktop.login1.service | 12 + src/login/pam-module.c | 548 + src/login/sd-login.c | 774 + src/login/sysfs-show.c | 186 + src/login/systemd-user | 8 + src/login/test-inhibit.c | 113 + src/login/test-login-shared.c | 41 + src/login/test-login-tables.c | 35 + src/login/test-login.c | 239 + src/login/user-sessions.c | 81 + src/loginctl.c | 1914 - src/logind-acl.c | 287 - src/logind-acl.h | 60 - src/logind-dbus.c | 1504 - src/logind-device.c | 86 - src/logind-device.h | 48 - src/logind-gperf.gperf | 22 - src/logind-seat-dbus.c | 403 - src/logind-seat.c | 499 - src/logind-seat.h | 82 - src/logind-session-dbus.c | 515 - src/logind-session.c | 945 - src/logind-session.h | 124 - src/logind-user-dbus.c | 411 - src/logind-user.c | 587 - src/logind-user.h | 86 - src/logind.c | 1228 - src/logind.h | 128 - src/loopback-setup.c | 274 - src/loopback-setup.h | 27 - src/machine-id-main.c | 35 - src/machine-id-setup.c | 196 - src/machine-id-setup.h | 27 - src/machine-id-setup/Makefile | 1 + src/machine-id-setup/machine-id-setup-main.c | 99 + src/machine/Makefile | 1 + src/machine/machine-dbus.c | 282 + src/machine/machine.c | 436 + src/machine/machine.h | 109 + src/machine/machinectl.c | 907 + src/machine/machined-dbus.c | 788 + src/machine/machined.c | 355 + src/machine/machined.h | 72 + src/machine/org.freedesktop.machine1.conf | 54 + src/machine/org.freedesktop.machine1.service | 12 + src/machine/test-machine-tables.c | 30 + src/macro.h | 184 - src/main.c | 1597 - src/manager.c | 3174 - src/manager.h | 299 - src/missing.h | 183 - src/modules-load.c | 143 - src/modules-load/Makefile | 1 + src/modules-load/modules-load.c | 309 + src/mount-setup.c | 420 - src/mount-setup.h | 36 - src/mount.c | 1886 - src/mount.h | 110 - src/namespace.c | 334 - src/namespace.h | 34 - src/network/.gitignore | 2 + src/network/Makefile | 1 + src/network/networkd-address.c | 418 + src/network/networkd-link.c | 1049 + src/network/networkd-manager.c | 464 + src/network/networkd-netdev-gperf.gperf | 25 + src/network/networkd-netdev.c | 414 + src/network/networkd-network-gperf.gperf | 44 + src/network/networkd-network.c | 332 + src/network/networkd-route.c | 273 + src/network/networkd.c | 102 + src/network/networkd.h | 366 + src/network/test-network.c | 77 + src/notify.c | 217 - src/notify/Makefile | 1 + src/notify/notify.c | 227 + src/nspawn.c | 888 - src/nspawn/Makefile | 1 + src/nspawn/nspawn.c | 2224 + src/nss-myhostname/Makefile | 1 + src/nss-myhostname/ifconf.h | 68 + src/nss-myhostname/netlink.c | 206 + src/nss-myhostname/nss-myhostname.c | 533 + src/org.freedesktop.hostname1.conf | 27 - src/org.freedesktop.hostname1.policy.in | 49 - src/org.freedesktop.hostname1.service | 12 - src/org.freedesktop.locale1.conf | 27 - src/org.freedesktop.locale1.policy.in | 39 - src/org.freedesktop.locale1.service | 12 - src/org.freedesktop.login1.conf | 86 - src/org.freedesktop.login1.policy.in | 89 - src/org.freedesktop.login1.service | 12 - src/org.freedesktop.systemd1.conf | 92 - src/org.freedesktop.systemd1.policy.in.in | 41 - src/org.freedesktop.systemd1.service | 11 - src/org.freedesktop.timedate1.conf | 27 - src/org.freedesktop.timedate1.policy.in | 61 - src/org.freedesktop.timedate1.service | 12 - src/pager.c | 134 - src/pager.h | 28 - src/pam-module.c | 622 - src/path-lookup.c | 345 - src/path-lookup.h | 40 - src/path.c | 717 - src/path.h | 93 - src/polkit.c | 190 - src/polkit.h | 35 - src/python-systemd/.gitignore | 2 + src/python-systemd/Makefile | 1 + src/python-systemd/__init__.py | 18 + src/python-systemd/_daemon.c | 331 + src/python-systemd/_journal.c | 157 + src/python-systemd/_reader.c | 1107 + src/python-systemd/daemon.py | 55 + src/python-systemd/docs/.gitignore | 1 + src/python-systemd/docs/conf.py | 279 + src/python-systemd/docs/daemon.rst | 18 + src/python-systemd/docs/default.css | 196 + src/python-systemd/docs/id128.rst | 40 + src/python-systemd/docs/index.rst | 24 + src/python-systemd/docs/journal.rst | 64 + src/python-systemd/docs/layout.html | 17 + src/python-systemd/docs/login.rst | 28 + src/python-systemd/id128.c | 163 + src/python-systemd/journal.py | 548 + src/python-systemd/login.c | 376 + src/python-systemd/pyutil.c | 80 + src/python-systemd/pyutil.h | 54 + src/quotacheck.c | 120 - src/quotacheck/Makefile | 1 + src/quotacheck/quotacheck.c | 105 + src/random-seed.c | 143 - src/random-seed/Makefile | 1 + src/random-seed/random-seed.c | 166 + src/ratelimit.c | 56 - src/ratelimit.h | 53 - src/rc-local-generator/Makefile | 1 + src/rc-local-generator/rc-local-generator.c | 102 + src/readahead-collect.c | 692 - src/readahead-common.c | 269 - src/readahead-common.h | 50 - src/readahead-replay.c | 371 - src/readahead/Makefile | 1 + src/readahead/readahead-analyze.c | 146 + src/readahead/readahead-collect.c | 668 + src/readahead/readahead-common.c | 398 + src/readahead/readahead-common.h | 64 + src/readahead/readahead-replay.c | 315 + src/readahead/readahead.c | 188 + src/readahead/sd-readahead.c | 89 + src/remount-api-vfs.c | 150 - src/remount-fs/Makefile | 1 + src/remount-fs/remount-fs.c | 164 + src/reply-password.c | 109 - src/reply-password/Makefile | 1 + src/reply-password/reply-password.c | 109 + src/rfkill/Makefile | 1 + src/rfkill/rfkill.c | 141 + src/run/Makefile | 1 + src/run/run.c | 508 + src/sd-daemon.c | 526 - src/sd-daemon.h | 277 - src/sd-login.c | 726 - src/sd-login.h | 121 - src/sd-readahead.c | 76 - src/sd-readahead.h | 81 - src/securebits.h | 45 - src/selinux-setup.c | 112 - src/selinux-setup.h | 29 - src/service.c | 3530 - src/service.h | 183 - src/set.c | 118 - src/set.h | 69 - src/shared/.gitignore | 4 + src/shared/Makefile | 1 + src/shared/MurmurHash2.c | 86 + src/shared/MurmurHash2.h | 33 + src/shared/acl-util.c | 154 + src/shared/acl-util.h | 28 + src/shared/acpi-fpdt.c | 162 + src/shared/acpi-fpdt.h | 26 + src/shared/apparmor-util.c | 41 + src/shared/apparmor-util.h | 26 + src/shared/architecture.c | 163 + src/shared/architecture.h | 115 + src/shared/ask-password-api.c | 573 + src/shared/ask-password-api.h | 30 + src/shared/audit.c | 85 + src/shared/audit.h | 29 + src/shared/boot-timestamps.c | 67 + src/shared/boot-timestamps.h | 27 + src/shared/bus-errors.h | 58 + src/shared/bus-label.c | 102 + src/shared/bus-label.h | 25 + src/shared/calendarspec.c | 944 + src/shared/calendarspec.h | 57 + src/shared/capability.c | 213 + src/shared/capability.h | 42 + src/shared/cgroup-show.c | 292 + src/shared/cgroup-show.h | 33 + src/shared/cgroup-util.c | 1732 + src/shared/cgroup-util.h | 133 + src/shared/condition-util.c | 266 + src/shared/condition-util.h | 79 + src/shared/conf-files.c | 174 + src/shared/conf-files.h | 29 + src/shared/conf-parser.c | 981 + src/shared/conf-parser.h | 216 + src/shared/def.h | 78 + src/shared/dev-setup.c | 84 + src/shared/dev-setup.h | 24 + src/shared/device-nodes.c | 74 + src/shared/device-nodes.h | 25 + src/shared/efivars.c | 464 + src/shared/efivars.h | 46 + src/shared/env-util.c | 453 + src/shared/env-util.h | 45 + src/shared/errno-list.c | 59 + src/shared/errno-list.h | 27 + src/shared/exit-status.c | 218 + src/shared/exit-status.h | 103 + src/shared/fdset.c | 236 + src/shared/fdset.h | 53 + src/shared/fileio-label.c | 55 + src/shared/fileio-label.h | 29 + src/shared/fileio.c | 783 + src/shared/fileio.h | 42 + src/shared/gunicode.c | 110 + src/shared/gunicode.h | 28 + src/shared/hashmap.c | 959 + src/shared/hashmap.h | 116 + src/shared/hwclock.c | 154 + src/shared/hwclock.h | 28 + src/shared/ima-util.c | 34 + src/shared/ima-util.h | 26 + src/shared/initreq.h | 77 + src/shared/install-printf.c | 156 + src/shared/install-printf.h | 25 + src/shared/install.c | 2037 + src/shared/install.h | 99 + src/shared/ioprio.h | 55 + src/shared/label.c | 478 + src/shared/label.h | 54 + src/shared/linux/Makefile | 1 + src/shared/linux/auto_dev-ioctl.h | 228 + src/{ => shared}/linux/fanotify.h | 0 src/shared/list.h | 132 + src/shared/log.c | 999 + src/shared/log.h | 174 + src/shared/logs-show.c | 1289 + src/shared/logs-show.h | 71 + src/shared/macro.h | 364 + src/shared/missing.h | 365 + src/shared/mkdir-label.c | 53 + src/shared/mkdir.c | 143 + src/shared/mkdir.h | 43 + src/shared/net-util.c | 289 + src/shared/net-util.h | 64 + src/shared/output-mode.h | 46 + src/shared/pager.c | 152 + src/shared/pager.h | 30 + src/shared/path-lookup.c | 385 + src/shared/path-lookup.h | 47 + src/shared/path-util.c | 509 + src/shared/path-util.h | 68 + src/shared/prioq.c | 306 + src/shared/prioq.h | 42 + src/shared/ptyfwd.c | 386 + src/shared/ptyfwd.h | 27 + src/shared/ratelimit.c | 57 + src/shared/ratelimit.h | 57 + src/shared/refcnt.h | 34 + src/shared/replace-var.c | 111 + src/shared/replace-var.h | 24 + src/shared/seccomp-util.c | 89 + src/shared/seccomp-util.h | 28 + src/shared/securebits.h | 45 + src/shared/selinux-util.c | 51 + src/shared/selinux-util.h | 27 + src/shared/set.c | 140 + src/shared/set.h | 79 + src/shared/siphash24.c | 135 + src/shared/siphash24.h | 6 + src/shared/sleep-config.c | 267 + src/shared/sleep-config.h | 26 + src/shared/smack-util.c | 91 + src/shared/smack-util.h | 36 + src/shared/socket-label.c | 145 + src/shared/socket-util.c | 656 + src/shared/socket-util.h | 107 + src/shared/sparse-endian.h | 87 + src/shared/spawn-ask-password-agent.c | 67 + src/shared/spawn-ask-password-agent.h | 25 + src/shared/spawn-polkit-agent.c | 98 + src/shared/spawn-polkit-agent.h | 25 + src/shared/special.h | 122 + src/shared/specifier.c | 182 + src/shared/specifier.h | 39 + src/shared/strbuf.c | 201 + src/shared/strbuf.h | 56 + src/shared/strv.c | 524 + src/shared/strv.h | 117 + src/shared/strxcpyx.c | 100 + src/shared/strxcpyx.h | 33 + src/shared/test-tables.h | 51 + src/shared/time-dst.c | 332 + src/shared/time-dst.h | 26 + src/shared/time-util.c | 825 + src/shared/time-util.h | 96 + src/shared/udev-util.h | 44 + src/shared/unit-name.c | 599 + src/shared/unit-name.h | 114 + src/shared/utf8.c | 296 + src/shared/utf8.h | 39 + src/shared/util.c | 6271 ++ src/shared/util.h | 876 + src/shared/utmp-wtmp.c | 403 + src/shared/utmp-wtmp.h | 35 + src/shared/virt.c | 297 + src/shared/virt.h | 35 + src/shared/watchdog.c | 169 + src/shared/watchdog.h | 28 + src/shared/xml.c | 216 + src/shared/xml.h | 34 + src/shutdown.c | 469 - src/shutdownd.c | 371 - src/shutdownd.h | 46 - src/shutdownd/Makefile | 1 + src/shutdownd/shutdownd.c | 471 + src/sleep/Makefile | 1 + src/sleep/sleep.c | 219 + src/snapshot.c | 308 - src/snapshot.h | 53 - src/socket-proxy/Makefile | 1 + src/socket-proxy/socket-proxyd.c | 665 + src/socket-util.c | 652 - src/socket-util.h | 102 - src/socket.c | 2136 - src/socket.h | 155 - src/spawn-agent.c | 120 - src/spawn-agent.h | 28 - src/special.h | 88 - src/specifier.c | 108 - src/specifier.h | 37 - src/stdout-syslog-bridge.c | 710 - src/strv.c | 690 - src/strv.h | 79 - src/swap.c | 1387 - src/swap.h | 114 - src/sysctl.c | 266 - src/sysctl/Makefile | 1 + src/sysctl/sysctl.c | 326 + src/sysfs-show.c | 187 - src/sysfs-show.h | 27 - src/system-update-generator/Makefile | 1 + .../system-update-generator.c | 81 + src/system.conf | 26 - src/systemadm.vala | 1018 - src/systemctl-bash-completion.sh | 150 - src/systemctl.c | 5296 -- src/systemctl/Makefile | 1 + src/systemctl/systemctl.c | 6491 ++ src/systemd-analyze | 264 - src/systemd-interfaces.vala | 167 - src/systemd-logind.conf | 16 - src/systemd/Makefile | 1 + src/systemd/_sd-common.h | 78 + src/systemd/sd-bus-protocol.h | 102 + src/systemd/sd-bus-vtable.h | 138 + src/systemd/sd-bus.h | 355 + src/systemd/sd-daemon.h | 264 + src/systemd/sd-dhcp-client.h | 74 + src/systemd/sd-event.h | 126 + src/systemd/sd-id128.h | 113 + src/systemd/sd-journal.h | 157 + src/systemd/sd-login.h | 196 + src/systemd/sd-memfd.h | 57 + src/systemd/sd-messages.h | 90 + src/systemd/sd-readahead.h | 73 + src/systemd/sd-resolve.h | 148 + src/systemd/sd-rtnl.h | 111 + src/systemd/sd-shutdown.h | 120 + src/systemd/sd-utf8.h | 34 + src/target.c | 223 - src/target.h | 47 - src/tcpwrap.c | 68 - src/tcpwrap.h | 29 - src/test-cgroup.c | 104 - src/test-daemon.c | 37 - src/test-engine.c | 99 - src/test-env-replace.c | 127 - src/test-hostname.c | 37 - src/test-install.c | 264 - src/test-job-type.c | 84 - src/test-login.c | 170 - src/test-loopback.c | 37 - src/test-ns.c | 60 - src/test-strv.c | 66 - src/test/Makefile | 1 + src/test/test-architecture.c | 52 + src/test/test-boot-timestamps.c | 98 + src/test/test-calendarspec.c | 88 + src/test/test-cgroup-mask.c | 110 + src/test/test-cgroup-util.c | 263 + src/test/test-cgroup.c | 105 + src/test/test-daemon.c | 37 + src/test/test-date.c | 61 + src/test/test-device-nodes.c | 57 + src/test/test-ellipsize.c | 45 + src/test/test-engine.c | 99 + src/test/test-env-replace.c | 218 + src/test/test-fileio.c | 304 + src/test/test-hashmap.c | 534 + src/test/test-helper.h | 31 + src/test/test-hostname.c | 38 + src/test/test-id128.c | 78 + src/test/test-install.c | 265 + src/test/test-job-type.c | 105 + src/test/test-libudev.c | 510 + src/test/test-list.c | 109 + src/test/test-log.c | 53 + src/test/test-loopback.c | 37 + src/test/test-namespace.c | 145 + src/test/test-ns.c | 73 + src/test/test-path-util.c | 166 + src/test/test-prioq.c | 170 + src/test/test-replace-var.c | 46 + src/test/test-sched-prio.c | 95 + src/test/test-sleep.c | 67 + src/test/test-strbuf.c | 92 + src/test/test-strip-tab-ansi.c | 52 + src/test/test-strv.c | 427 + src/test/test-strxcpyx.c | 101 + src/test/test-tables.c | 102 + src/test/test-time.c | 136 + src/test/test-tmpfiles.c | 51 + src/test/test-udev.c | 167 + src/test/test-unit-file.c | 387 + src/test/test-unit-name.c | 201 + src/test/test-utf8.c | 77 + src/test/test-util.c | 630 + src/test/test-watchdog.c | 51 + src/test/test-xml.c | 83 + src/timedate/.gitignore | 1 + src/timedate/Makefile | 1 + src/timedate/org.freedesktop.timedate1.conf | 27 + src/timedate/org.freedesktop.timedate1.policy.in | 62 + src/timedate/org.freedesktop.timedate1.service | 12 + src/timedate/timedatectl.c | 619 + src/timedate/timedated.c | 870 + src/timedated.c | 911 - src/timer.c | 510 - src/timer.h | 83 - src/timestamp.c | 39 - src/tmpfiles.c | 1042 - src/tmpfiles/Makefile | 1 + src/tmpfiles/tmpfiles.c | 1517 + src/tty-ask-password-agent.c | 752 - src/tty-ask-password-agent/Makefile | 1 + .../tty-ask-password-agent.c | 755 + src/uaccess.c | 90 - src/udev/.gitignore | 5 + src/udev/.vimrc | 4 + src/udev/Makefile | 1 + src/udev/accelerometer/accelerometer.c | 343 + src/udev/ata_id/ata_id.c | 691 + src/udev/cdrom_id/cdrom_id.c | 1098 + src/udev/collect/collect.c | 492 + src/udev/mtd_probe/mtd_probe.c | 54 + src/udev/mtd_probe/mtd_probe.h | 49 + src/udev/mtd_probe/probe_smartmedia.c | 95 + src/udev/net/.gitignore | 1 + src/udev/net/Makefile | 1 + src/udev/net/ethtool-util.c | 194 + src/udev/net/ethtool-util.h | 56 + src/udev/net/link-config-gperf.gperf | 36 + src/udev/net/link-config.c | 486 + src/udev/net/link-config.h | 98 + src/udev/scsi_id/.gitignore | 1 + src/udev/scsi_id/README | 4 + src/udev/scsi_id/scsi.h | 97 + src/udev/scsi_id/scsi_id.c | 632 + src/udev/scsi_id/scsi_id.h | 73 + src/udev/scsi_id/scsi_serial.c | 966 + src/udev/udev-builtin-blkid.c | 223 + src/udev/udev-builtin-btrfs.c | 64 + src/udev/udev-builtin-firmware.c | 198 + src/udev/udev-builtin-hwdb.c | 215 + src/udev/udev-builtin-input_id.c | 219 + src/udev/udev-builtin-keyboard.c | 163 + src/udev/udev-builtin-kmod.c | 135 + src/udev/udev-builtin-net_id.c | 605 + src/udev/udev-builtin-net_setup_link.c | 106 + src/udev/udev-builtin-path_id.c | 611 + src/udev/udev-builtin-uaccess.c | 94 + src/udev/udev-builtin-usb_id.c | 481 + src/udev/udev-builtin.c | 152 + src/udev/udev-ctrl.c | 485 + src/udev/udev-event.c | 912 + src/udev/udev-node.c | 370 + src/udev/udev-rules.c | 2648 + src/udev/udev-watch.c | 161 + src/udev/udev.conf | 3 + src/udev/udev.h | 220 + src/udev/udev.pc.in | 5 + src/udev/udevadm-control.c | 167 + src/udev/udevadm-hwdb.c | 664 + src/udev/udevadm-info.c | 532 + src/udev/udevadm-monitor.c | 283 + src/udev/udevadm-settle.c | 240 + src/udev/udevadm-test-builtin.c | 120 + src/udev/udevadm-test.c | 167 + src/udev/udevadm-trigger.c | 233 + src/udev/udevadm.c | 152 + src/udev/udevd.c | 1416 + src/udev/v4l_id/v4l_id.c | 83 + src/umount.c | 640 - src/umount.h | 33 - src/unit-name.c | 448 - src/unit-name.h | 57 - src/unit.c | 2619 - src/unit.h | 548 - src/update-utmp.c | 420 - src/update-utmp/Makefile | 1 + src/update-utmp/update-utmp.c | 298 + src/user-sessions.c | 100 - src/user.conf | 17 - src/util.c | 5713 -- src/util.h | 509 - src/utmp-wtmp.c | 424 - src/utmp-wtmp.h | 38 - src/vconsole-setup.c | 459 - src/vconsole/Makefile | 1 + src/vconsole/vconsole-setup.c | 308 + src/virt.c | 314 - src/virt.h | 38 - sysctl.d/.gitignore | 1 + sysctl.d/50-coredump.conf.in | 10 + sysctl.d/50-default.conf | 24 + sysctl.d/Makefile | 1 + systemd.pc.in | 20 - test/.gitignore | 5 + test/Makefile | 20 + test/README.testsuite | 48 + test/TEST-01-BASIC/Makefile | 10 + test/TEST-01-BASIC/test.sh | 74 + test/TEST-02-CRYPTSETUP/Makefile | 1 + test/TEST-02-CRYPTSETUP/test.sh | 97 + test/TEST-03-JOBS/Makefile | 1 + test/TEST-03-JOBS/test-jobs.sh | 41 + test/TEST-03-JOBS/test.sh | 79 + test/TEST-04-SECCOMP/Makefile | 1 + test/TEST-04-SECCOMP/test-seccomp.sh | 13 + test/TEST-04-SECCOMP/test.sh | 79 + test/TEST-04-SECCOMP/will-fail.service | 8 + test/TEST-04-SECCOMP/will-fail2.service | 6 + test/TEST-04-SECCOMP/will-not-fail.service | 9 + test/TEST-04-SECCOMP/will-not-fail2.service | 6 + {test2 => test}/a.service | 0 {test2 => test}/b.service | 0 {test2 => test}/c.service | 0 {test2 => test}/d.service | 0 test/daughter.service | 7 + {test2 => test}/e.service | 0 test/end.service | 6 + {test2 => test}/f.service | 0 {test2 => test}/g.service | 0 test/grandchild.service | 7 + {test2 => test}/h.service | 0 test/hello-after-sleep.target | 5 + test/hello.service | 5 + test/parent-deep.slice | 5 + test/parent.slice | 5 + test/rule-syntax-check.py | 63 + test/rules-test.sh | 28 + test/sched_idle_bad.service | 6 + test/sched_idle_ok.service | 6 + test/sched_rr_bad.service | 8 + test/sched_rr_change.service | 9 + test/sched_rr_ok.service | 6 + test/sleep.service | 6 + test/son.service | 8 + test/sys.tar.xz | Bin 0 -> 165116 bytes test/test-functions | 1167 + test/testsuite.target | 6 + test/udev-test.pl | 1530 + test/unstoppable.service | 5 + test1/default.target | 1 - test1/exec-demo.service | 9 - test1/fifo-demo.service | 8 - test1/fifo-demo.socket | 6 - test1/mail-transfer-agent.service | 1 - test1/mail-transfer-agent.socket | 1 - test1/multiuser.target | 2 - test1/multiuser.target.wants/exec-demo.service | 1 - test1/multiuser.target.wants/fifo-demo.socket | 1 - .../mail-transfer-agent.socket | 1 - test1/multiuser.target.wants/permissions.service | 1 - test1/multiuser.target.wants/systemd-logger.socket | 1 - test1/permissions.service | 11 - test1/postfix.service | 7 - test1/postfix.socket | 13 - test1/syslog.service | 5 - test1/syslog.socket | 8 - test1/systemd-logger.service | 13 - test1/systemd-logger.socket | 5 - test2/Makefile | 7 - tmpfiles.d/Makefile | 1 + tmpfiles.d/legacy.conf | 28 +- tmpfiles.d/systemd-nologin.conf | 11 + tmpfiles.d/systemd.conf | 19 +- tmpfiles.d/tmp.conf | 10 +- tmpfiles.d/x11.conf | 6 +- tools/check-includes.pl | 23 + tools/make-directive-index.py | 320 + tools/make-man-index.py | 136 + tools/make-man-rules.py | 119 + tools/xml_helper.py | 34 + units/.gitignore | 109 +- units/basic.target | 12 +- units/bluetooth.target | 7 +- units/busnames.target | 10 + units/console-getty.service.m4.in | 31 + units/console-shell.service.m4 | 43 - units/console-shell.service.m4.in | 31 + units/container-getty@.service.m4.in | 29 + units/cryptsetup.target | 7 +- units/debug-shell.service.in | 33 + units/dev-hugepages.mount | 6 +- units/dev-mqueue.mount | 6 +- units/emergency.service | 30 - units/emergency.service.in | 28 + units/emergency.target | 7 +- units/fedora/halt-local.service | 20 - units/fedora/prefdm.service | 20 - units/fedora/rc-local.service | 18 - units/final.target | 7 +- units/frugalware/display-manager.service | 16 - units/fsck-root.service.in | 23 - units/fsck@.service.in | 20 - units/getty.target | 6 +- units/getty@.service.m4 | 44 +- units/graphical.target | 11 +- units/halt-local.service.in | 20 + units/halt.service.in | 16 - units/halt.target | 11 +- units/hibernate.target | 13 + units/http-daemon.target | 14 - units/hybrid-sleep.target | 13 + units/initrd-cleanup.service.in | 18 + units/initrd-fs.target | 16 + units/initrd-parse-etc.service.in | 22 + units/initrd-root-fs.target | 15 + units/initrd-switch-root.service.in | 20 + units/initrd-switch-root.target | 16 + units/initrd-udevadm-cleanup-db.service.in | 18 + units/initrd.target | 17 + units/kexec.service.in | 16 - units/kexec.target | 11 +- units/kmod-static-nodes.service.in | 18 + units/local-fs-pre.target | 8 +- units/local-fs.target | 12 +- units/machine.slice | 11 + units/mail-transfer-agent.target | 14 - units/mandriva/prefdm.service | 21 - units/media.mount | 16 - units/multi-user.target | 12 +- units/network-online.target | 11 + units/network.target | 8 +- units/nss-lookup.target | 11 +- units/nss-user-lookup.target | 14 + units/org.freedesktop.DBus.busname | 12 + units/org.freedesktop.hostname1.busname | 14 + units/org.freedesktop.locale1.busname | 14 + units/org.freedesktop.login1.busname | 15 + units/org.freedesktop.machine1.busname | 14 + units/org.freedesktop.timedate1.busname | 14 + units/paths.target | 10 + units/plymouth-halt.service | 18 - units/plymouth-kexec.service | 18 - units/plymouth-poweroff.service | 18 - units/plymouth-quit-wait.service | 15 - units/plymouth-quit.service | 15 - units/plymouth-read-write.service | 16 - units/plymouth-reboot.service | 18 - units/plymouth-start.service | 22 - units/poweroff.service.in | 16 - units/poweroff.target | 11 +- units/printer.target | 7 +- units/proc-sys-fs-binfmt_misc.automount | 9 +- units/proc-sys-fs-binfmt_misc.mount | 6 +- units/quotacheck.service.in | 20 - units/quotaon.service | 19 - units/quotaon.service.in | 19 + units/rc-local.service.in | 20 + units/reboot.service.in | 16 - units/reboot.target | 11 +- units/remote-fs-pre.target | 12 +- units/remote-fs.target | 10 +- units/remount-rootfs.service | 20 - units/rescue.service.m4 | 40 - units/rescue.service.m4.in | 29 + units/rescue.target | 11 +- units/rpcbind.target | 8 +- units/serial-getty@.service.m4 | 37 +- units/shutdown.target | 7 +- units/sigpwr.target | 7 +- units/sleep.target | 13 + units/slices.target | 12 + units/slp/var-cache.automount | 5 - units/slp/var-cache.mount | 9 - units/slp/var-lib.automount | 5 - units/slp/var-lib.mount | 9 - units/slp/var-lock.mount | 9 - units/slp/var-log.automount | 5 - units/slp/var-log.mount | 9 - units/smartcard.target | 7 +- units/sockets.target | 7 +- units/sound.target | 7 +- units/suse/halt-local.service | 20 - units/suse/rc-local.service | 18 - units/suspend.target | 13 + units/swap.target | 7 +- units/sys-fs-fuse-connections.mount | 6 +- units/sys-kernel-config.mount | 6 +- units/sys-kernel-debug.mount | 6 +- units/sys-kernel-security.mount | 17 - units/sysinit.target | 7 +- units/syslog.socket | 44 +- units/syslog.target | 19 - units/system-update.target | 16 + units/system.slice | 14 + units/systemd-ask-password-console.path | 7 +- units/systemd-ask-password-console.service.in | 7 +- units/systemd-ask-password-plymouth.path | 19 - units/systemd-ask-password-plymouth.service.in | 18 - units/systemd-ask-password-wall.path | 7 +- units/systemd-ask-password-wall.service.in | 8 +- units/systemd-backlight@.service.in | 21 + units/systemd-binfmt.service.in | 8 +- units/systemd-bus-driverd.service.in | 15 + units/systemd-bus-proxyd.socket | 13 + units/systemd-bus-proxyd@.service.in | 17 + units/systemd-fsck-root.service.in | 22 + units/systemd-fsck@.service.in | 21 + units/systemd-halt.service.in | 17 + units/systemd-hibernate.service.in | 17 + units/systemd-hostnamed.service.in | 12 +- units/systemd-hybrid-sleep.service.in | 17 + units/systemd-initctl.service.in | 7 +- units/systemd-initctl.socket | 7 +- units/systemd-journal-flush.service.in | 18 + units/systemd-journal-gatewayd.service.in | 19 + units/systemd-journal-gatewayd.socket | 15 + units/systemd-journald.service.in | 27 + units/systemd-journald.socket | 28 + units/systemd-kexec.service.in | 17 + units/systemd-kmsg-syslogd.service.in | 19 - units/systemd-localed.service.in | 10 +- units/systemd-logind.service.in | 23 +- units/systemd-machined.service.in | 19 + units/systemd-modules-load.service.in | 8 +- units/systemd-networkd.service.in | 25 + units/systemd-nspawn@.service.in | 17 + units/systemd-poweroff.service.in | 17 + units/systemd-quotacheck.service.in | 20 + units/systemd-random-seed-load.service.in | 18 - units/systemd-random-seed-save.service.in | 17 - units/systemd-random-seed.service.in | 21 + units/systemd-readahead-collect.service.in | 12 +- units/systemd-readahead-done.service.in | 6 +- units/systemd-readahead-done.timer | 9 +- units/systemd-readahead-drop.service | 19 + units/systemd-readahead-replay.service.in | 10 +- units/systemd-reboot.service.in | 17 + units/systemd-remount-api-vfs.service.in | 20 - units/systemd-remount-fs.service.in | 22 + units/systemd-rfkill@.service.in | 21 + units/systemd-shutdownd.service.in | 7 +- units/systemd-shutdownd.socket | 9 +- units/systemd-stdout-syslog-bridge.service.in | 24 - units/systemd-stdout-syslog-bridge.socket | 21 - units/systemd-suspend.service.in | 17 + units/systemd-sysctl.service.in | 7 +- units/systemd-timedated.service.in | 10 +- units/systemd-tmpfiles-clean.service.in | 5 +- units/systemd-tmpfiles-clean.timer | 5 +- units/systemd-tmpfiles-setup-dev.service.in | 18 + units/systemd-tmpfiles-setup.service.in | 13 +- units/systemd-udev-settle.service.in | 25 + units/systemd-udev-trigger.service.in | 20 + units/systemd-udevd-control.socket | 19 + units/systemd-udevd-kernel.socket | 19 + units/systemd-udevd.service.in | 23 + units/systemd-update-utmp-runlevel.service.in | 15 +- units/systemd-update-utmp-shutdown.service.in | 16 - units/systemd-update-utmp.service.in | 21 + units/systemd-user-sessions.service.in | 7 +- units/systemd-vconsole-setup.service.in | 7 +- units/time-sync.target | 8 +- units/timers.target | 10 + units/tmp.mount | 20 + units/umount.target | 7 +- units/user.slice | 11 + units/user/.gitignore | 4 +- units/user/basic.target | 13 + units/user/default.target | 10 +- units/user/exit.service.in | 18 - units/user/exit.target | 11 +- units/user/systemd-bus-driverd.service.in | 14 + units/user/systemd-bus-proxyd.socket | 13 + units/user/systemd-bus-proxyd@.service.in | 16 + units/user/systemd-exit.service.in | 17 + units/user@.service.in | 17 +- units/var-lock.mount | 16 - units/var-run.mount | 16 - units/x-.slice | 12 + 1738 files changed, 504762 insertions(+), 103914 deletions(-) create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 .vimrc create mode 100644 .ycm_extra_conf.py rename LICENSE => LICENSE.GPL2 (100%) create mode 100644 LICENSE.LGPL2.1 create mode 100644 LICENSE.MIT create mode 100644 Makefile-man.am create mode 100644 NEWS create mode 120000 catalog/Makefile create mode 100644 catalog/systemd.catalog create mode 100644 catalog/systemd.fr.catalog create mode 100644 catalog/systemd.it.catalog create mode 100644 catalog/systemd.ru.catalog delete mode 100644 debian/README.Debian delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100755 debian/debian-fixup delete mode 100644 debian/debian-fixup.service delete mode 100644 debian/ifup@.service delete mode 100644 debian/init-functions delete mode 100644 debian/lib-init-rw.automount delete mode 100644 debian/lib-init-rw.mount delete mode 100644 debian/libpam-systemd.install delete mode 100644 debian/libpam-systemd.postinst delete mode 100644 debian/libpam-systemd.prerm delete mode 100644 debian/libsystemd-daemon-dev.install delete mode 100644 debian/libsystemd-daemon0.install delete mode 100644 debian/libsystemd-daemon0.symbols delete mode 100644 debian/libsystemd-login-dev.install delete mode 100644 debian/libsystemd-login0.install delete mode 100644 debian/libsystemd-login0.symbols delete mode 100644 debian/pam-configs/systemd delete mode 100755 debian/rules delete mode 100644 debian/source/format delete mode 100644 debian/source/options delete mode 100644 debian/systemd-gui.install delete mode 100755 debian/systemd-hack-up-the-source.hook delete mode 100644 debian/systemd-sysv.install delete mode 100644 debian/systemd-sysv.links delete mode 100644 debian/systemd.dirs delete mode 100644 debian/systemd.install delete mode 100644 debian/systemd.links delete mode 100644 debian/systemd.postinst delete mode 100644 debian/systemd.postrm delete mode 100644 debian/systemd.preinst create mode 100644 docs/.gitignore create mode 120000 docs/Makefile create mode 100644 docs/gtk-doc.make create mode 100644 docs/gudev/.gitignore create mode 100644 docs/gudev/Makefile.am create mode 100644 docs/gudev/gudev-docs.xml create mode 100644 docs/gudev/gudev-sections.txt create mode 100644 docs/gudev/gudev.types create mode 100644 docs/gudev/version.xml.in create mode 100644 docs/libudev/.gitignore create mode 100644 docs/libudev/Makefile.am create mode 100644 docs/libudev/libudev-docs.xml create mode 100644 docs/libudev/libudev-sections.txt create mode 100644 docs/libudev/libudev.types create mode 100644 docs/libudev/version.xml.in create mode 100644 docs/sysvinit/.gitignore rename {units/fedora => docs/sysvinit}/Makefile (100%) create mode 100644 docs/sysvinit/README.in create mode 100644 docs/var-log/.gitignore create mode 120000 docs/var-log/Makefile create mode 100644 docs/var-log/README.in create mode 100644 hwdb/.gitignore create mode 100644 hwdb/20-OUI.hwdb create mode 100644 hwdb/20-acpi-vendor.hwdb create mode 100644 hwdb/20-bluetooth-vendor-product.hwdb create mode 100644 hwdb/20-net-ifname.hwdb create mode 100644 hwdb/20-pci-classes.hwdb create mode 100644 hwdb/20-pci-vendor-model.hwdb create mode 100644 hwdb/20-sdio-classes.hwdb create mode 100644 hwdb/20-sdio-vendor-model.hwdb create mode 100644 hwdb/20-usb-classes.hwdb create mode 100644 hwdb/20-usb-vendor-model.hwdb create mode 100644 hwdb/60-keyboard.hwdb create mode 120000 hwdb/Makefile create mode 100755 hwdb/ids-update.pl create mode 100644 hwdb/sdio.ids delete mode 100644 introspect.awk delete mode 100644 libsystemd-daemon.pc.in delete mode 100644 libsystemd-login.pc.in create mode 100644 m4/gtk-doc.m4 create mode 100644 m4/libgcrypt.m4 create mode 100644 man/bootchart.conf.xml create mode 100644 man/bootctl.xml create mode 100644 man/bootup.xml create mode 100644 man/busctl.xml create mode 100644 man/crypttab.xml create mode 100644 man/custom-html.xsl create mode 100644 man/custom-man.xsl create mode 100644 man/hostnamectl.xml create mode 100644 man/journalctl.xml create mode 100644 man/journald.conf.xml create mode 100644 man/kernel-command-line.xml create mode 100644 man/kernel-install.xml create mode 100644 man/less-variables.xml create mode 100644 man/libsystemd-pkgconfig.xml create mode 100644 man/localectl.xml create mode 100644 man/localtime.xml create mode 100644 man/loginctl.xml create mode 100644 man/logind.conf.xml create mode 100644 man/machinectl.xml create mode 100644 man/nss-myhostname.xml create mode 100644 man/sd-id128.xml create mode 100644 man/sd-journal.xml create mode 100644 man/sd-login.xml create mode 100644 man/sd_bus_creds_get_pid.xml create mode 100644 man/sd_bus_creds_new_from_pid.xml create mode 100644 man/sd_bus_error.xml create mode 100644 man/sd_bus_label_escape.xml create mode 100644 man/sd_bus_message_get_cookie.xml create mode 100644 man/sd_bus_message_get_monotonic_usec.xml create mode 100644 man/sd_bus_new.xml create mode 100644 man/sd_bus_open_user.xml create mode 100644 man/sd_bus_request_name.xml create mode 100644 man/sd_get_seats.xml create mode 100644 man/sd_id128_get_machine.xml create mode 100644 man/sd_id128_randomize.xml create mode 100644 man/sd_id128_to_string.xml create mode 100644 man/sd_journal_add_match.xml create mode 100644 man/sd_journal_get_catalog.xml create mode 100644 man/sd_journal_get_cursor.xml create mode 100644 man/sd_journal_get_cutoff_realtime_usec.xml create mode 100644 man/sd_journal_get_data.xml create mode 100644 man/sd_journal_get_fd.xml create mode 100644 man/sd_journal_get_realtime_usec.xml create mode 100644 man/sd_journal_get_usage.xml create mode 100644 man/sd_journal_next.xml create mode 100644 man/sd_journal_open.xml create mode 100644 man/sd_journal_print.xml create mode 100644 man/sd_journal_query_unique.xml create mode 100644 man/sd_journal_seek_head.xml create mode 100644 man/sd_journal_stream_fd.xml create mode 100644 man/sd_login_monitor_new.xml create mode 100644 man/sd_pid_get_session.xml create mode 100644 man/sd_seat_get_active.xml create mode 100644 man/sd_session_is_active.xml create mode 100644 man/sd_uid_get_state.xml create mode 100644 man/sd_watchdog_enabled.xml create mode 100644 man/standard-options.xml delete mode 100644 man/systemadm.xml create mode 100644 man/systemd-activate.xml create mode 100644 man/systemd-analyze.xml create mode 100644 man/systemd-ask-password-console.service.xml create mode 100644 man/systemd-backlight@.service.xml create mode 100644 man/systemd-binfmt.service.xml create mode 100644 man/systemd-bootchart.xml create mode 100644 man/systemd-bus-proxyd.xml create mode 100644 man/systemd-bus-proxyd@.service.xml create mode 100644 man/systemd-cat.xml create mode 100644 man/systemd-cgtop.xml create mode 100644 man/systemd-coredumpctl.xml create mode 100644 man/systemd-cryptsetup-generator.xml create mode 100644 man/systemd-cryptsetup@.service.xml create mode 100644 man/systemd-delta.xml create mode 100644 man/systemd-detect-virt.xml create mode 100644 man/systemd-efi-boot-generator.xml create mode 100644 man/systemd-fsck@.service.xml create mode 100644 man/systemd-fstab-generator.xml create mode 100644 man/systemd-getty-generator.xml create mode 100644 man/systemd-gpt-auto-generator.xml create mode 100644 man/systemd-halt.service.xml create mode 100644 man/systemd-hostnamed.service.xml create mode 100644 man/systemd-inhibit.xml create mode 100644 man/systemd-initctl.service.xml create mode 100644 man/systemd-journal-gatewayd.service.xml create mode 100644 man/systemd-journald.service.xml create mode 100644 man/systemd-localed.service.xml delete mode 100644 man/systemd-loginctl.xml delete mode 100644 man/systemd-logind.conf.xml create mode 100644 man/systemd-logind.service.xml create mode 100644 man/systemd-machine-id-setup.xml create mode 100644 man/systemd-machined.service.xml create mode 100644 man/systemd-modules-load.service.xml create mode 100644 man/systemd-networkd.service.xml create mode 100644 man/systemd-quotacheck.service.xml create mode 100644 man/systemd-random-seed.service.xml create mode 100644 man/systemd-readahead-replay.service.xml create mode 100644 man/systemd-remount-fs.service.xml create mode 100644 man/systemd-rfkill@.service.xml create mode 100644 man/systemd-run.xml create mode 100644 man/systemd-shutdownd.service.xml create mode 100644 man/systemd-sleep.conf.xml create mode 100644 man/systemd-socket-proxyd.xml create mode 100644 man/systemd-suspend.service.xml create mode 100644 man/systemd-sysctl.service.xml create mode 100644 man/systemd-system-update-generator.xml create mode 100644 man/systemd-system.conf.xml create mode 100644 man/systemd-timedated.service.xml create mode 100644 man/systemd-tty-ask-password-agent.xml create mode 100644 man/systemd-udevd.service.xml create mode 100644 man/systemd-update-utmp.service.xml create mode 100644 man/systemd-user-sessions.service.xml create mode 100644 man/systemd-vconsole-setup.service.xml delete mode 100644 man/systemd.conf.xml create mode 100644 man/systemd.journal-fields.xml create mode 100644 man/systemd.kill.xml create mode 100644 man/systemd.preset.xml create mode 100644 man/systemd.resource-control.xml create mode 100644 man/systemd.scope.xml create mode 100644 man/systemd.slice.xml create mode 100644 man/systemd.special.xml delete mode 100644 man/systemd.special.xml.in create mode 100644 man/systemd.time.xml create mode 100644 man/timedatectl.xml delete mode 100644 man/timezone.xml create mode 100644 man/udev.xml create mode 100644 man/udevadm.xml create mode 100644 man/user-system-options.xml create mode 100644 network/80-container-host0.network create mode 100644 network/99-default.link create mode 100644 packaging/apply-conf.sh create mode 100644 packaging/systemd.manifest create mode 100644 packaging/tizen-bootchart.conf create mode 100644 packaging/tizen-journald.conf create mode 100644 packaging/tizen-system-mobile.conf create mode 100644 packaging/tizen-system-wearable.conf create mode 100644 po/LINGUAS create mode 100644 po/Makefile.in.in create mode 100644 po/fr.po create mode 100644 po/it.po create mode 100644 po/ru.po create mode 100644 rules/.gitignore create mode 100644 rules/42-usb-hid-pm.rules create mode 100644 rules/50-firmware.rules create mode 100644 rules/50-udev-default.rules create mode 100644 rules/60-cdrom_id.rules create mode 100644 rules/60-drm.rules create mode 100644 rules/60-keyboard.rules create mode 100644 rules/60-persistent-alsa.rules create mode 100644 rules/60-persistent-input.rules create mode 100644 rules/60-persistent-serial.rules create mode 100644 rules/60-persistent-storage-tape.rules create mode 100644 rules/60-persistent-storage.rules create mode 100644 rules/60-persistent-v4l.rules create mode 100644 rules/61-accelerometer.rules create mode 100644 rules/64-btrfs.rules create mode 100644 rules/75-net-description.rules create mode 100644 rules/75-probe_mtd.rules create mode 100644 rules/75-tty-description.rules create mode 100644 rules/78-sound-card.rules create mode 100644 rules/80-drivers.rules create mode 100644 rules/80-net-setup-link.rules create mode 100644 rules/95-udev-late.rules create mode 100644 rules/99-systemd.rules.in create mode 120000 rules/Makefile create mode 100644 shell-completion/bash/bootctl create mode 100644 shell-completion/bash/busctl create mode 100644 shell-completion/bash/hostnamectl create mode 100644 shell-completion/bash/journalctl create mode 100644 shell-completion/bash/kernel-install create mode 100644 shell-completion/bash/localectl create mode 100644 shell-completion/bash/loginctl create mode 100644 shell-completion/bash/machinectl create mode 100644 shell-completion/bash/systemctl create mode 100644 shell-completion/bash/systemd-analyze create mode 100644 shell-completion/bash/systemd-coredumpctl create mode 100644 shell-completion/bash/systemd-delta create mode 100644 shell-completion/bash/systemd-run create mode 100644 shell-completion/bash/timedatectl create mode 100644 shell-completion/bash/udevadm create mode 100644 shell-completion/zsh/_bootctl create mode 100644 shell-completion/zsh/_busctl create mode 100644 shell-completion/zsh/_hostnamectl create mode 100644 shell-completion/zsh/_journalctl create mode 100644 shell-completion/zsh/_kernel-install create mode 100644 shell-completion/zsh/_localectl create mode 100644 shell-completion/zsh/_loginctl create mode 100644 shell-completion/zsh/_machinectl create mode 100644 shell-completion/zsh/_sd_hosts_or_user_at_host create mode 100644 shell-completion/zsh/_sd_machines create mode 100644 shell-completion/zsh/_sd_outputmodes create mode 100644 shell-completion/zsh/_systemctl create mode 100644 shell-completion/zsh/_systemd create mode 100644 shell-completion/zsh/_systemd-analyze create mode 100644 shell-completion/zsh/_systemd-coredumpctl create mode 100644 shell-completion/zsh/_systemd-delta create mode 100644 shell-completion/zsh/_systemd-inhibit create mode 100644 shell-completion/zsh/_systemd-nspawn create mode 100644 shell-completion/zsh/_systemd-run create mode 100644 shell-completion/zsh/_systemd-tmpfiles create mode 100644 shell-completion/zsh/_timedatectl create mode 100644 shell-completion/zsh/_udevadm delete mode 100644 src/70-uaccess.rules delete mode 100644 src/71-seat.rules delete mode 100644 src/73-seat-late.rules.in delete mode 100644 src/99-systemd.rules.in delete mode 100644 src/ac-power.c create mode 120000 src/ac-power/Makefile create mode 100644 src/ac-power/ac-power.c create mode 120000 src/activate/Makefile create mode 100644 src/activate/activate.c create mode 100644 src/analyze/.gitignore create mode 120000 src/analyze/Makefile create mode 100644 src/analyze/analyze.c delete mode 100644 src/ask-password-api.c delete mode 100644 src/ask-password-api.h delete mode 100644 src/ask-password.c create mode 120000 src/ask-password/Makefile create mode 100644 src/ask-password/ask-password.c delete mode 100644 src/automount.c delete mode 100644 src/automount.h create mode 120000 src/backlight/Makefile create mode 100644 src/backlight/backlight.c delete mode 100644 src/binfmt.c create mode 120000 src/binfmt/Makefile create mode 100644 src/binfmt/binfmt.c create mode 120000 src/boot/Makefile create mode 100644 src/boot/boot-efi.c create mode 100644 src/boot/boot-loader.c create mode 100644 src/boot/boot-loader.h create mode 100644 src/boot/boot.h create mode 100644 src/boot/bootctl.c create mode 120000 src/bootchart/Makefile create mode 100644 src/bootchart/bootchart.c create mode 100644 src/bootchart/bootchart.conf create mode 100644 src/bootchart/bootchart.h create mode 100644 src/bootchart/store.c create mode 100644 src/bootchart/store.h create mode 100644 src/bootchart/svg.c create mode 100644 src/bootchart/svg.h delete mode 100644 src/bridge.c delete mode 100644 src/build.h create mode 120000 src/bus-driverd/Makefile create mode 100644 src/bus-driverd/bus-driverd.c delete mode 100644 src/bus-errors.h create mode 120000 src/bus-proxyd/Makefile create mode 100644 src/bus-proxyd/bus-proxyd.c delete mode 100644 src/cgls.c create mode 120000 src/cgls/Makefile create mode 100644 src/cgls/cgls.c delete mode 100644 src/cgroup-attr.c delete mode 100644 src/cgroup-attr.h delete mode 100644 src/cgroup-show.c delete mode 100644 src/cgroup-show.h delete mode 100644 src/cgroup-util.c delete mode 100644 src/cgroup-util.h delete mode 100644 src/cgroup.c delete mode 100644 src/cgroup.h delete mode 100644 src/cgroups-agent.c create mode 120000 src/cgroups-agent/Makefile create mode 100644 src/cgroups-agent/cgroups-agent.c create mode 120000 src/cgtop/Makefile create mode 100644 src/cgtop/cgtop.c create mode 100644 src/compat-libs/.gitignore create mode 100644 src/compat-libs/libsystemd-daemon.pc.in rename src/{ => compat-libs}/libsystemd-daemon.sym (100%) create mode 100644 src/compat-libs/libsystemd-id128.pc.in create mode 100644 src/compat-libs/libsystemd-id128.sym create mode 100644 src/compat-libs/libsystemd-journal.pc.in create mode 100644 src/compat-libs/libsystemd-journal.sym create mode 100644 src/compat-libs/libsystemd-login.pc.in create mode 100644 src/compat-libs/libsystemd-login.sym create mode 100644 src/compat-libs/linkwarning.h delete mode 100644 src/condition.c delete mode 100644 src/condition.h delete mode 100644 src/conf-parser.c delete mode 100644 src/conf-parser.h create mode 100644 src/core/.gitignore create mode 120000 src/core/Makefile create mode 100644 src/core/async.c create mode 100644 src/core/async.h create mode 100644 src/core/audit-fd.c create mode 100644 src/core/audit-fd.h create mode 100644 src/core/automount.c create mode 100644 src/core/automount.h create mode 100644 src/core/build.h create mode 100644 src/core/busname.c create mode 100644 src/core/busname.h create mode 100644 src/core/cgroup.c create mode 100644 src/core/cgroup.h create mode 100644 src/core/condition.c create mode 100644 src/core/condition.h create mode 100644 src/core/dbus-automount.c create mode 100644 src/core/dbus-automount.h create mode 100644 src/core/dbus-busname.c create mode 100644 src/core/dbus-busname.h create mode 100644 src/core/dbus-cgroup.c create mode 100644 src/core/dbus-cgroup.h create mode 100644 src/core/dbus-client-track.c create mode 100644 src/core/dbus-client-track.h create mode 100644 src/core/dbus-device.c create mode 100644 src/core/dbus-device.h create mode 100644 src/core/dbus-execute.c create mode 100644 src/core/dbus-execute.h create mode 100644 src/core/dbus-job.c create mode 100644 src/core/dbus-job.h create mode 100644 src/core/dbus-kill.c create mode 100644 src/core/dbus-kill.h create mode 100644 src/core/dbus-manager.c create mode 100644 src/core/dbus-manager.h create mode 100644 src/core/dbus-mount.c create mode 100644 src/core/dbus-mount.h create mode 100644 src/core/dbus-path.c create mode 100644 src/core/dbus-path.h create mode 100644 src/core/dbus-scope.c create mode 100644 src/core/dbus-scope.h create mode 100644 src/core/dbus-service.c create mode 100644 src/core/dbus-service.h create mode 100644 src/core/dbus-slice.c create mode 100644 src/core/dbus-slice.h create mode 100644 src/core/dbus-snapshot.c create mode 100644 src/core/dbus-snapshot.h create mode 100644 src/core/dbus-socket.c create mode 100644 src/core/dbus-socket.h create mode 100644 src/core/dbus-swap.c create mode 100644 src/core/dbus-swap.h create mode 100644 src/core/dbus-target.c create mode 100644 src/core/dbus-target.h create mode 100644 src/core/dbus-timer.c create mode 100644 src/core/dbus-timer.h create mode 100644 src/core/dbus-unit.c create mode 100644 src/core/dbus-unit.h create mode 100644 src/core/dbus.c create mode 100644 src/core/dbus.h create mode 100644 src/core/device.c create mode 100644 src/core/device.h create mode 100644 src/core/execute.c create mode 100644 src/core/execute.h create mode 100644 src/core/hostname-setup.c create mode 100644 src/core/hostname-setup.h create mode 100644 src/core/ima-setup.c create mode 100644 src/core/ima-setup.h create mode 100644 src/core/job.c create mode 100644 src/core/job.h create mode 100644 src/core/kill.c create mode 100644 src/core/kill.h create mode 100644 src/core/killall.c create mode 100644 src/core/killall.h create mode 100644 src/core/kmod-setup.c create mode 100644 src/core/kmod-setup.h create mode 100644 src/core/load-dropin.c create mode 100644 src/core/load-dropin.h create mode 100644 src/core/load-fragment-gperf.gperf.m4 create mode 100644 src/core/load-fragment.c create mode 100644 src/core/load-fragment.h create mode 100644 src/core/locale-setup.c create mode 100644 src/core/locale-setup.h create mode 100644 src/core/loopback-setup.c create mode 100644 src/core/loopback-setup.h create mode 100644 src/core/machine-id-setup.c create mode 100644 src/core/machine-id-setup.h create mode 100644 src/core/macros.systemd.in create mode 100644 src/core/main.c create mode 100644 src/core/manager.c create mode 100644 src/core/manager.h create mode 100644 src/core/mount-setup.c create mode 100644 src/core/mount-setup.h create mode 100644 src/core/mount.c create mode 100644 src/core/mount.h create mode 100644 src/core/namespace.c create mode 100644 src/core/namespace.h create mode 100644 src/core/org.freedesktop.systemd1.conf create mode 100644 src/core/org.freedesktop.systemd1.policy.in.in create mode 100644 src/core/org.freedesktop.systemd1.service create mode 100644 src/core/path.c create mode 100644 src/core/path.h create mode 100644 src/core/scope.c create mode 100644 src/core/scope.h create mode 100644 src/core/selinux-access.c create mode 100644 src/core/selinux-access.h create mode 100644 src/core/selinux-setup.c create mode 100644 src/core/selinux-setup.h create mode 100644 src/core/service.c create mode 100644 src/core/service.h create mode 100644 src/core/shutdown.c create mode 100644 src/core/slice.c create mode 100644 src/core/slice.h create mode 100644 src/core/smack-setup.c create mode 100644 src/core/smack-setup.h create mode 100644 src/core/snapshot.c create mode 100644 src/core/snapshot.h create mode 100644 src/core/socket.c create mode 100644 src/core/socket.h create mode 100644 src/core/swap.c create mode 100644 src/core/swap.h create mode 100644 src/core/switch-root.c create mode 100644 src/core/switch-root.h create mode 100644 src/core/sysfs-show.h create mode 100644 src/core/system.conf create mode 100644 src/core/systemd.pc.in create mode 100644 src/core/target.c create mode 100644 src/core/target.h create mode 100644 src/core/tcpwrap.c create mode 100644 src/core/tcpwrap.h create mode 100644 src/core/timer.c create mode 100644 src/core/timer.h create mode 100644 src/core/transaction.c create mode 100644 src/core/transaction.h create mode 100644 src/core/umount.c create mode 100644 src/core/umount.h create mode 100644 src/core/unit-printf.c create mode 100644 src/core/unit-printf.h create mode 100644 src/core/unit.c create mode 100644 src/core/unit.h create mode 100644 src/core/user.conf delete mode 100644 src/cryptsetup-generator.c delete mode 100644 src/cryptsetup.c create mode 120000 src/cryptsetup/Makefile create mode 100644 src/cryptsetup/cryptsetup-generator.c create mode 100644 src/cryptsetup/cryptsetup.c delete mode 100644 src/dbus-automount.c delete mode 100644 src/dbus-automount.h delete mode 100644 src/dbus-common.c delete mode 100644 src/dbus-common.h delete mode 100644 src/dbus-device.c delete mode 100644 src/dbus-device.h delete mode 100644 src/dbus-execute.c delete mode 100644 src/dbus-execute.h delete mode 100644 src/dbus-job.c delete mode 100644 src/dbus-job.h delete mode 100644 src/dbus-loop.c delete mode 100644 src/dbus-loop.h delete mode 100644 src/dbus-manager.c delete mode 100644 src/dbus-manager.h delete mode 100644 src/dbus-mount.c delete mode 100644 src/dbus-mount.h delete mode 100644 src/dbus-path.c delete mode 100644 src/dbus-path.h delete mode 100644 src/dbus-service.c delete mode 100644 src/dbus-service.h delete mode 100644 src/dbus-snapshot.c delete mode 100644 src/dbus-snapshot.h delete mode 100644 src/dbus-socket.c delete mode 100644 src/dbus-socket.h delete mode 100644 src/dbus-swap.c delete mode 100644 src/dbus-swap.h delete mode 100644 src/dbus-target.c delete mode 100644 src/dbus-target.h delete mode 100644 src/dbus-timer.c delete mode 100644 src/dbus-timer.h delete mode 100644 src/dbus-unit.c delete mode 100644 src/dbus-unit.h delete mode 100644 src/dbus.c delete mode 100644 src/dbus.h create mode 120000 src/dbus1-generator/Makefile create mode 100644 src/dbus1-generator/dbus1-generator.c delete mode 100644 src/def.h create mode 120000 src/delta/Makefile create mode 100644 src/delta/delta.c delete mode 100644 src/detect-virt.c create mode 120000 src/detect-virt/Makefile create mode 100644 src/detect-virt/detect-virt.c delete mode 100644 src/device.c delete mode 100644 src/device.h create mode 120000 src/efi-boot-generator/Makefile create mode 100644 src/efi-boot-generator/efi-boot-generator.c delete mode 100644 src/execute.c delete mode 100644 src/execute.h delete mode 100644 src/exit-status.c delete mode 100644 src/exit-status.h delete mode 100644 src/fdset.c delete mode 100644 src/fdset.h delete mode 100644 src/fsck.c create mode 120000 src/fsck/Makefile create mode 100644 src/fsck/fsck.c create mode 120000 src/fstab-generator/Makefile create mode 100644 src/fstab-generator/fstab-generator.c delete mode 100755 src/generate-kbd-model-map delete mode 100644 src/getty-generator.c create mode 120000 src/getty-generator/Makefile create mode 100644 src/getty-generator/getty-generator.c delete mode 100644 src/gnome-ask-password-agent.vala create mode 120000 src/gpt-auto-generator/Makefile create mode 100644 src/gpt-auto-generator/gpt-auto-generator.c create mode 100644 src/gudev/.gitignore create mode 120000 src/gudev/Makefile create mode 100755 src/gudev/gjs-example.js create mode 100644 src/gudev/gudev-1.0.pc.in create mode 100644 src/gudev/gudev.h create mode 100644 src/gudev/gudevclient.c create mode 100644 src/gudev/gudevclient.h create mode 100644 src/gudev/gudevdevice.c create mode 100644 src/gudev/gudevdevice.h create mode 100644 src/gudev/gudevenumerator.c create mode 100644 src/gudev/gudevenumerator.h create mode 100644 src/gudev/gudevenums.h create mode 100644 src/gudev/gudevenumtypes.c.template create mode 100644 src/gudev/gudevenumtypes.h.template create mode 100644 src/gudev/gudevmarshal.list create mode 100644 src/gudev/gudevprivate.h create mode 100644 src/gudev/gudevtypes.h create mode 100755 src/gudev/seed-example-enum.js create mode 100755 src/gudev/seed-example.js delete mode 100644 src/hashmap.c delete mode 100644 src/hashmap.h delete mode 100644 src/hostname-setup.c delete mode 100644 src/hostname-setup.h create mode 100644 src/hostname/.gitignore create mode 120000 src/hostname/Makefile create mode 100644 src/hostname/hostnamectl.c create mode 100644 src/hostname/hostnamed.c create mode 100644 src/hostname/org.freedesktop.hostname1.conf create mode 100644 src/hostname/org.freedesktop.hostname1.policy.in create mode 100644 src/hostname/org.freedesktop.hostname1.service delete mode 100644 src/hostnamed.c delete mode 100644 src/initctl.c create mode 120000 src/initctl/Makefile create mode 100644 src/initctl/initctl.c delete mode 100644 src/initreq.h delete mode 100644 src/install.c delete mode 100644 src/install.h delete mode 100644 src/ioprio.h delete mode 100644 src/job.c delete mode 100644 src/job.h create mode 100644 src/journal/.gitignore create mode 120000 src/journal/Makefile create mode 100644 src/journal/browse.html create mode 100644 src/journal/cat.c create mode 100644 src/journal/catalog.c create mode 100644 src/journal/catalog.h create mode 100644 src/journal/compress.c create mode 100644 src/journal/compress.h create mode 100644 src/journal/coredump.c create mode 100644 src/journal/coredumpctl.c create mode 100644 src/journal/fsprg.c create mode 100644 src/journal/fsprg.h create mode 100644 src/journal/journal-authenticate.c create mode 100644 src/journal/journal-authenticate.h create mode 100644 src/journal/journal-def.h create mode 100644 src/journal/journal-file.c create mode 100644 src/journal/journal-file.h create mode 100644 src/journal/journal-gatewayd.c create mode 100644 src/journal/journal-internal.h create mode 100644 src/journal/journal-qrcode.c create mode 100644 src/journal/journal-qrcode.h create mode 100644 src/journal/journal-send.c create mode 100644 src/journal/journal-vacuum.c create mode 100644 src/journal/journal-vacuum.h create mode 100644 src/journal/journal-verify.c create mode 100644 src/journal/journal-verify.h create mode 100644 src/journal/journalctl.c create mode 100644 src/journal/journald-console.c create mode 100644 src/journal/journald-console.h create mode 100644 src/journal/journald-gperf.gperf create mode 100644 src/journal/journald-kmsg.c create mode 100644 src/journal/journald-kmsg.h create mode 100644 src/journal/journald-native.c create mode 100644 src/journal/journald-native.h create mode 100644 src/journal/journald-rate-limit.c create mode 100644 src/journal/journald-rate-limit.h create mode 100644 src/journal/journald-server.c create mode 100644 src/journal/journald-server.h create mode 100644 src/journal/journald-stream.c create mode 100644 src/journal/journald-stream.h create mode 100644 src/journal/journald-syslog.c create mode 100644 src/journal/journald-syslog.h create mode 100644 src/journal/journald.c create mode 100644 src/journal/journald.conf create mode 100644 src/journal/lookup3.c create mode 100644 src/journal/lookup3.h create mode 100644 src/journal/microhttpd-util.c create mode 100644 src/journal/microhttpd-util.h create mode 100644 src/journal/mmap-cache.c create mode 100644 src/journal/mmap-cache.h create mode 100644 src/journal/sd-journal.c create mode 100644 src/journal/test-catalog.c create mode 100644 src/journal/test-journal-enum.c create mode 100644 src/journal/test-journal-flush.c create mode 100644 src/journal/test-journal-init.c create mode 100644 src/journal/test-journal-interleaving.c create mode 100644 src/journal/test-journal-match.c create mode 100644 src/journal/test-journal-send.c create mode 100644 src/journal/test-journal-stream.c create mode 100644 src/journal/test-journal-syslog.c create mode 100644 src/journal/test-journal-verify.c create mode 100644 src/journal/test-journal.c create mode 100644 src/journal/test-mmap-cache.c delete mode 100644 src/kbd-model-map create mode 100644 src/kernel-install/50-depmod.install create mode 100644 src/kernel-install/90-loaderentry.install create mode 100644 src/kernel-install/kernel-install delete mode 100644 src/kmod-setup.c delete mode 100644 src/kmod-setup.h delete mode 100644 src/kmsg-syslogd.c delete mode 100644 src/label.c delete mode 100644 src/label.h create mode 120000 src/libsystemd-dhcp/Makefile create mode 100644 src/libsystemd-dhcp/dhcp-internal.h create mode 100644 src/libsystemd-dhcp/dhcp-lease.c create mode 100644 src/libsystemd-dhcp/dhcp-lease.h create mode 100644 src/libsystemd-dhcp/dhcp-network.c create mode 100644 src/libsystemd-dhcp/dhcp-option.c create mode 100644 src/libsystemd-dhcp/dhcp-packet.c create mode 100644 src/libsystemd-dhcp/dhcp-protocol.h create mode 100644 src/libsystemd-dhcp/sd-dhcp-client.c create mode 100644 src/libsystemd-dhcp/test-dhcp-client.c create mode 100644 src/libsystemd-dhcp/test-dhcp-option.c delete mode 100644 src/libsystemd-login.sym create mode 100644 src/libsystemd/.gitignore create mode 120000 src/libsystemd/Makefile create mode 100644 src/libsystemd/libsystemd.pc.in create mode 100644 src/libsystemd/libsystemd.sym.m4 create mode 100644 src/libsystemd/sd-bus/.gitignore create mode 100644 src/libsystemd/sd-bus/DIFFERENCES create mode 100644 src/libsystemd/sd-bus/GVARIANT-SERIALIZATION create mode 120000 src/libsystemd/sd-bus/Makefile create mode 100644 src/libsystemd/sd-bus/PORTING-DBUS1 create mode 100644 src/libsystemd/sd-bus/bus-bloom.c create mode 100644 src/libsystemd/sd-bus/bus-bloom.h create mode 100644 src/libsystemd/sd-bus/bus-container.c create mode 100644 src/libsystemd/sd-bus/bus-container.h create mode 100644 src/libsystemd/sd-bus/bus-control.c create mode 100644 src/libsystemd/sd-bus/bus-control.h create mode 100644 src/libsystemd/sd-bus/bus-convenience.c create mode 100644 src/libsystemd/sd-bus/bus-creds.c create mode 100644 src/libsystemd/sd-bus/bus-creds.h create mode 100644 src/libsystemd/sd-bus/bus-dump.c create mode 100644 src/libsystemd/sd-bus/bus-dump.h create mode 100644 src/libsystemd/sd-bus/bus-error-mapping.gperf create mode 100644 src/libsystemd/sd-bus/bus-error.c create mode 100644 src/libsystemd/sd-bus/bus-error.h create mode 100644 src/libsystemd/sd-bus/bus-gvariant.c create mode 100644 src/libsystemd/sd-bus/bus-gvariant.h create mode 100644 src/libsystemd/sd-bus/bus-internal.c create mode 100644 src/libsystemd/sd-bus/bus-internal.h create mode 100644 src/libsystemd/sd-bus/bus-introspect.c create mode 100644 src/libsystemd/sd-bus/bus-introspect.h create mode 100644 src/libsystemd/sd-bus/bus-kernel.c create mode 100644 src/libsystemd/sd-bus/bus-kernel.h create mode 100644 src/libsystemd/sd-bus/bus-match.c create mode 100644 src/libsystemd/sd-bus/bus-match.h create mode 100644 src/libsystemd/sd-bus/bus-message.c create mode 100644 src/libsystemd/sd-bus/bus-message.h create mode 100644 src/libsystemd/sd-bus/bus-objects.c create mode 100644 src/libsystemd/sd-bus/bus-objects.h create mode 100644 src/libsystemd/sd-bus/bus-protocol.h create mode 100644 src/libsystemd/sd-bus/bus-signature.c create mode 100644 src/libsystemd/sd-bus/bus-signature.h create mode 100644 src/libsystemd/sd-bus/bus-socket.c create mode 100644 src/libsystemd/sd-bus/bus-socket.h create mode 100644 src/libsystemd/sd-bus/bus-type.c create mode 100644 src/libsystemd/sd-bus/bus-type.h create mode 100644 src/libsystemd/sd-bus/bus-util.c create mode 100644 src/libsystemd/sd-bus/bus-util.h create mode 100644 src/libsystemd/sd-bus/busctl.c create mode 100644 src/libsystemd/sd-bus/kdbus.h create mode 100644 src/libsystemd/sd-bus/sd-bus.c create mode 100644 src/libsystemd/sd-bus/sd-memfd.c create mode 100644 src/libsystemd/sd-bus/test-bus-chat.c create mode 100644 src/libsystemd/sd-bus/test-bus-cleanup.c create mode 100644 src/libsystemd/sd-bus/test-bus-creds.c create mode 100644 src/libsystemd/sd-bus/test-bus-error.c create mode 100644 src/libsystemd/sd-bus/test-bus-gvariant.c create mode 100644 src/libsystemd/sd-bus/test-bus-introspect.c create mode 100644 src/libsystemd/sd-bus/test-bus-kernel-benchmark.c create mode 100644 src/libsystemd/sd-bus/test-bus-kernel-bloom.c create mode 100644 src/libsystemd/sd-bus/test-bus-kernel.c create mode 100644 src/libsystemd/sd-bus/test-bus-marshal.c create mode 100644 src/libsystemd/sd-bus/test-bus-match.c create mode 100644 src/libsystemd/sd-bus/test-bus-memfd.c create mode 100644 src/libsystemd/sd-bus/test-bus-objects.c create mode 100644 src/libsystemd/sd-bus/test-bus-server.c create mode 100644 src/libsystemd/sd-bus/test-bus-signature.c create mode 100644 src/libsystemd/sd-bus/test-bus-zero-copy.c create mode 100644 src/libsystemd/sd-daemon/sd-daemon.c create mode 120000 src/libsystemd/sd-event/Makefile create mode 100644 src/libsystemd/sd-event/event-util.h create mode 100644 src/libsystemd/sd-event/sd-event.c create mode 100644 src/libsystemd/sd-event/test-event.c create mode 120000 src/libsystemd/sd-id128/Makefile create mode 100644 src/libsystemd/sd-id128/libsystemd-id128.pc.in create mode 100644 src/libsystemd/sd-id128/sd-id128.c create mode 120000 src/libsystemd/sd-resolve/Makefile create mode 100644 src/libsystemd/sd-resolve/resolve-util.h create mode 100644 src/libsystemd/sd-resolve/sd-resolve.c create mode 100644 src/libsystemd/sd-resolve/test-resolve.c create mode 120000 src/libsystemd/sd-rtnl/Makefile create mode 100644 src/libsystemd/sd-rtnl/rtnl-internal.h create mode 100644 src/libsystemd/sd-rtnl/rtnl-message.c create mode 100644 src/libsystemd/sd-rtnl/rtnl-util.c create mode 100644 src/libsystemd/sd-rtnl/rtnl-util.h create mode 100644 src/libsystemd/sd-rtnl/sd-rtnl.c create mode 100644 src/libsystemd/sd-rtnl/test-rtnl.c create mode 120000 src/libsystemd/sd-utf8/Makefile create mode 100644 src/libsystemd/sd-utf8/sd-utf8.c create mode 100644 src/libudev/.gitignore create mode 120000 src/libudev/Makefile create mode 100644 src/libudev/libudev-device-private.c create mode 100644 src/libudev/libudev-device.c create mode 100644 src/libudev/libudev-enumerate.c create mode 100644 src/libudev/libudev-hwdb-def.h create mode 100644 src/libudev/libudev-hwdb.c create mode 100644 src/libudev/libudev-list.c create mode 100644 src/libudev/libudev-monitor.c create mode 100644 src/libudev/libudev-private.h create mode 100644 src/libudev/libudev-queue-private.c create mode 100644 src/libudev/libudev-queue.c create mode 100644 src/libudev/libudev-util.c create mode 100644 src/libudev/libudev.c create mode 100644 src/libudev/libudev.h create mode 100644 src/libudev/libudev.pc.in create mode 100644 src/libudev/libudev.sym delete mode 100644 src/linux/auto_dev-ioctl.h delete mode 100644 src/list.h delete mode 100644 src/load-dropin.c delete mode 100644 src/load-dropin.h delete mode 100644 src/load-fragment-gperf.gperf.m4 delete mode 100644 src/load-fragment.c delete mode 100644 src/load-fragment.h delete mode 100644 src/locale-setup.c delete mode 100644 src/locale-setup.h create mode 100644 src/locale/.gitignore create mode 120000 src/locale/Makefile create mode 100755 src/locale/generate-kbd-model-map create mode 100644 src/locale/kbd-model-map create mode 100644 src/locale/localectl.c create mode 100644 src/locale/localed.c create mode 100644 src/locale/org.freedesktop.locale1.conf create mode 100644 src/locale/org.freedesktop.locale1.policy.in create mode 100644 src/locale/org.freedesktop.locale1.service delete mode 100644 src/localed.c delete mode 100644 src/log.c delete mode 100644 src/log.h create mode 100644 src/login/.gitignore create mode 100644 src/login/70-power-switch.rules create mode 100644 src/login/70-uaccess.rules create mode 100644 src/login/71-seat.rules.in create mode 100644 src/login/73-seat-late.rules.in create mode 120000 src/login/Makefile create mode 100644 src/login/inhibit.c create mode 100644 src/login/login-shared.c create mode 100644 src/login/login-shared.h create mode 100644 src/login/loginctl.c create mode 100644 src/login/logind-acl.c create mode 100644 src/login/logind-acl.h create mode 100644 src/login/logind-action.c create mode 100644 src/login/logind-action.h create mode 100644 src/login/logind-button.c create mode 100644 src/login/logind-button.h create mode 100644 src/login/logind-core.c create mode 100644 src/login/logind-dbus.c create mode 100644 src/login/logind-device.c create mode 100644 src/login/logind-device.h create mode 100644 src/login/logind-gperf.gperf create mode 100644 src/login/logind-inhibit.c create mode 100644 src/login/logind-inhibit.h create mode 100644 src/login/logind-seat-dbus.c create mode 100644 src/login/logind-seat.c create mode 100644 src/login/logind-seat.h create mode 100644 src/login/logind-session-dbus.c create mode 100644 src/login/logind-session-device.c create mode 100644 src/login/logind-session-device.h create mode 100644 src/login/logind-session.c create mode 100644 src/login/logind-session.h create mode 100644 src/login/logind-user-dbus.c create mode 100644 src/login/logind-user.c create mode 100644 src/login/logind-user.h create mode 100644 src/login/logind.c create mode 100644 src/login/logind.conf create mode 100644 src/login/logind.h create mode 100644 src/login/multi-seat-x.c create mode 100644 src/login/org.freedesktop.login1.conf create mode 100644 src/login/org.freedesktop.login1.policy.in create mode 100644 src/login/org.freedesktop.login1.service create mode 100644 src/login/pam-module.c create mode 100644 src/login/sd-login.c create mode 100644 src/login/sysfs-show.c create mode 100644 src/login/systemd-user create mode 100644 src/login/test-inhibit.c create mode 100644 src/login/test-login-shared.c create mode 100644 src/login/test-login-tables.c create mode 100644 src/login/test-login.c create mode 100644 src/login/user-sessions.c delete mode 100644 src/loginctl.c delete mode 100644 src/logind-acl.c delete mode 100644 src/logind-acl.h delete mode 100644 src/logind-dbus.c delete mode 100644 src/logind-device.c delete mode 100644 src/logind-device.h delete mode 100644 src/logind-gperf.gperf delete mode 100644 src/logind-seat-dbus.c delete mode 100644 src/logind-seat.c delete mode 100644 src/logind-seat.h delete mode 100644 src/logind-session-dbus.c delete mode 100644 src/logind-session.c delete mode 100644 src/logind-session.h delete mode 100644 src/logind-user-dbus.c delete mode 100644 src/logind-user.c delete mode 100644 src/logind-user.h delete mode 100644 src/logind.c delete mode 100644 src/logind.h delete mode 100644 src/loopback-setup.c delete mode 100644 src/loopback-setup.h delete mode 100644 src/machine-id-main.c delete mode 100644 src/machine-id-setup.c delete mode 100644 src/machine-id-setup.h create mode 120000 src/machine-id-setup/Makefile create mode 100644 src/machine-id-setup/machine-id-setup-main.c create mode 120000 src/machine/Makefile create mode 100644 src/machine/machine-dbus.c create mode 100644 src/machine/machine.c create mode 100644 src/machine/machine.h create mode 100644 src/machine/machinectl.c create mode 100644 src/machine/machined-dbus.c create mode 100644 src/machine/machined.c create mode 100644 src/machine/machined.h create mode 100644 src/machine/org.freedesktop.machine1.conf create mode 100644 src/machine/org.freedesktop.machine1.service create mode 100644 src/machine/test-machine-tables.c delete mode 100644 src/macro.h delete mode 100644 src/main.c delete mode 100644 src/manager.c delete mode 100644 src/manager.h delete mode 100644 src/missing.h delete mode 100644 src/modules-load.c create mode 120000 src/modules-load/Makefile create mode 100644 src/modules-load/modules-load.c delete mode 100644 src/mount-setup.c delete mode 100644 src/mount-setup.h delete mode 100644 src/mount.c delete mode 100644 src/mount.h delete mode 100644 src/namespace.c delete mode 100644 src/namespace.h create mode 100644 src/network/.gitignore create mode 120000 src/network/Makefile create mode 100644 src/network/networkd-address.c create mode 100644 src/network/networkd-link.c create mode 100644 src/network/networkd-manager.c create mode 100644 src/network/networkd-netdev-gperf.gperf create mode 100644 src/network/networkd-netdev.c create mode 100644 src/network/networkd-network-gperf.gperf create mode 100644 src/network/networkd-network.c create mode 100644 src/network/networkd-route.c create mode 100644 src/network/networkd.c create mode 100644 src/network/networkd.h create mode 100644 src/network/test-network.c delete mode 100644 src/notify.c create mode 120000 src/notify/Makefile create mode 100644 src/notify/notify.c delete mode 100644 src/nspawn.c create mode 120000 src/nspawn/Makefile create mode 100644 src/nspawn/nspawn.c create mode 120000 src/nss-myhostname/Makefile create mode 100644 src/nss-myhostname/ifconf.h create mode 100644 src/nss-myhostname/netlink.c create mode 100644 src/nss-myhostname/nss-myhostname.c delete mode 100644 src/org.freedesktop.hostname1.conf delete mode 100644 src/org.freedesktop.hostname1.policy.in delete mode 100644 src/org.freedesktop.hostname1.service delete mode 100644 src/org.freedesktop.locale1.conf delete mode 100644 src/org.freedesktop.locale1.policy.in delete mode 100644 src/org.freedesktop.locale1.service delete mode 100644 src/org.freedesktop.login1.conf delete mode 100644 src/org.freedesktop.login1.policy.in delete mode 100644 src/org.freedesktop.login1.service delete mode 100644 src/org.freedesktop.systemd1.conf delete mode 100644 src/org.freedesktop.systemd1.policy.in.in delete mode 100644 src/org.freedesktop.systemd1.service delete mode 100644 src/org.freedesktop.timedate1.conf delete mode 100644 src/org.freedesktop.timedate1.policy.in delete mode 100644 src/org.freedesktop.timedate1.service delete mode 100644 src/pager.c delete mode 100644 src/pager.h delete mode 100644 src/pam-module.c delete mode 100644 src/path-lookup.c delete mode 100644 src/path-lookup.h delete mode 100644 src/path.c delete mode 100644 src/path.h delete mode 100644 src/polkit.c delete mode 100644 src/polkit.h create mode 100644 src/python-systemd/.gitignore create mode 120000 src/python-systemd/Makefile create mode 100644 src/python-systemd/__init__.py create mode 100644 src/python-systemd/_daemon.c create mode 100644 src/python-systemd/_journal.c create mode 100644 src/python-systemd/_reader.c create mode 100644 src/python-systemd/daemon.py create mode 100644 src/python-systemd/docs/.gitignore create mode 100644 src/python-systemd/docs/conf.py create mode 100644 src/python-systemd/docs/daemon.rst create mode 100644 src/python-systemd/docs/default.css create mode 100644 src/python-systemd/docs/id128.rst create mode 100644 src/python-systemd/docs/index.rst create mode 100644 src/python-systemd/docs/journal.rst create mode 100644 src/python-systemd/docs/layout.html create mode 100644 src/python-systemd/docs/login.rst create mode 100644 src/python-systemd/id128.c create mode 100644 src/python-systemd/journal.py create mode 100644 src/python-systemd/login.c create mode 100644 src/python-systemd/pyutil.c create mode 100644 src/python-systemd/pyutil.h delete mode 100644 src/quotacheck.c create mode 120000 src/quotacheck/Makefile create mode 100644 src/quotacheck/quotacheck.c delete mode 100644 src/random-seed.c create mode 120000 src/random-seed/Makefile create mode 100644 src/random-seed/random-seed.c delete mode 100644 src/ratelimit.c delete mode 100644 src/ratelimit.h create mode 120000 src/rc-local-generator/Makefile create mode 100644 src/rc-local-generator/rc-local-generator.c delete mode 100644 src/readahead-collect.c delete mode 100644 src/readahead-common.c delete mode 100644 src/readahead-common.h delete mode 100644 src/readahead-replay.c create mode 120000 src/readahead/Makefile create mode 100644 src/readahead/readahead-analyze.c create mode 100644 src/readahead/readahead-collect.c create mode 100644 src/readahead/readahead-common.c create mode 100644 src/readahead/readahead-common.h create mode 100644 src/readahead/readahead-replay.c create mode 100644 src/readahead/readahead.c create mode 100644 src/readahead/sd-readahead.c delete mode 100644 src/remount-api-vfs.c create mode 120000 src/remount-fs/Makefile create mode 100644 src/remount-fs/remount-fs.c delete mode 100644 src/reply-password.c create mode 120000 src/reply-password/Makefile create mode 100644 src/reply-password/reply-password.c create mode 120000 src/rfkill/Makefile create mode 100644 src/rfkill/rfkill.c create mode 120000 src/run/Makefile create mode 100644 src/run/run.c delete mode 100644 src/sd-daemon.c delete mode 100644 src/sd-daemon.h delete mode 100644 src/sd-login.c delete mode 100644 src/sd-login.h delete mode 100644 src/sd-readahead.c delete mode 100644 src/sd-readahead.h delete mode 100644 src/securebits.h delete mode 100644 src/selinux-setup.c delete mode 100644 src/selinux-setup.h delete mode 100644 src/service.c delete mode 100644 src/service.h delete mode 100644 src/set.c delete mode 100644 src/set.h create mode 100644 src/shared/.gitignore create mode 120000 src/shared/Makefile create mode 100644 src/shared/MurmurHash2.c create mode 100644 src/shared/MurmurHash2.h create mode 100644 src/shared/acl-util.c create mode 100644 src/shared/acl-util.h create mode 100644 src/shared/acpi-fpdt.c create mode 100644 src/shared/acpi-fpdt.h create mode 100644 src/shared/apparmor-util.c create mode 100644 src/shared/apparmor-util.h create mode 100644 src/shared/architecture.c create mode 100644 src/shared/architecture.h create mode 100644 src/shared/ask-password-api.c create mode 100644 src/shared/ask-password-api.h create mode 100644 src/shared/audit.c create mode 100644 src/shared/audit.h create mode 100644 src/shared/boot-timestamps.c create mode 100644 src/shared/boot-timestamps.h create mode 100644 src/shared/bus-errors.h create mode 100644 src/shared/bus-label.c create mode 100644 src/shared/bus-label.h create mode 100644 src/shared/calendarspec.c create mode 100644 src/shared/calendarspec.h create mode 100644 src/shared/capability.c create mode 100644 src/shared/capability.h create mode 100644 src/shared/cgroup-show.c create mode 100644 src/shared/cgroup-show.h create mode 100644 src/shared/cgroup-util.c create mode 100644 src/shared/cgroup-util.h create mode 100644 src/shared/condition-util.c create mode 100644 src/shared/condition-util.h create mode 100644 src/shared/conf-files.c create mode 100644 src/shared/conf-files.h create mode 100644 src/shared/conf-parser.c create mode 100644 src/shared/conf-parser.h create mode 100644 src/shared/def.h create mode 100644 src/shared/dev-setup.c create mode 100644 src/shared/dev-setup.h create mode 100644 src/shared/device-nodes.c create mode 100644 src/shared/device-nodes.h create mode 100644 src/shared/efivars.c create mode 100644 src/shared/efivars.h create mode 100644 src/shared/env-util.c create mode 100644 src/shared/env-util.h create mode 100644 src/shared/errno-list.c create mode 100644 src/shared/errno-list.h create mode 100644 src/shared/exit-status.c create mode 100644 src/shared/exit-status.h create mode 100644 src/shared/fdset.c create mode 100644 src/shared/fdset.h create mode 100644 src/shared/fileio-label.c create mode 100644 src/shared/fileio-label.h create mode 100644 src/shared/fileio.c create mode 100644 src/shared/fileio.h create mode 100644 src/shared/gunicode.c create mode 100644 src/shared/gunicode.h create mode 100644 src/shared/hashmap.c create mode 100644 src/shared/hashmap.h create mode 100644 src/shared/hwclock.c create mode 100644 src/shared/hwclock.h create mode 100644 src/shared/ima-util.c create mode 100644 src/shared/ima-util.h create mode 100644 src/shared/initreq.h create mode 100644 src/shared/install-printf.c create mode 100644 src/shared/install-printf.h create mode 100644 src/shared/install.c create mode 100644 src/shared/install.h create mode 100644 src/shared/ioprio.h create mode 100644 src/shared/label.c create mode 100644 src/shared/label.h create mode 120000 src/shared/linux/Makefile create mode 100644 src/shared/linux/auto_dev-ioctl.h rename src/{ => shared}/linux/fanotify.h (100%) create mode 100644 src/shared/list.h create mode 100644 src/shared/log.c create mode 100644 src/shared/log.h create mode 100644 src/shared/logs-show.c create mode 100644 src/shared/logs-show.h create mode 100644 src/shared/macro.h create mode 100644 src/shared/missing.h create mode 100644 src/shared/mkdir-label.c create mode 100644 src/shared/mkdir.c create mode 100644 src/shared/mkdir.h create mode 100644 src/shared/net-util.c create mode 100644 src/shared/net-util.h create mode 100644 src/shared/output-mode.h create mode 100644 src/shared/pager.c create mode 100644 src/shared/pager.h create mode 100644 src/shared/path-lookup.c create mode 100644 src/shared/path-lookup.h create mode 100644 src/shared/path-util.c create mode 100644 src/shared/path-util.h create mode 100644 src/shared/prioq.c create mode 100644 src/shared/prioq.h create mode 100644 src/shared/ptyfwd.c create mode 100644 src/shared/ptyfwd.h create mode 100644 src/shared/ratelimit.c create mode 100644 src/shared/ratelimit.h create mode 100644 src/shared/refcnt.h create mode 100644 src/shared/replace-var.c create mode 100644 src/shared/replace-var.h create mode 100644 src/shared/seccomp-util.c create mode 100644 src/shared/seccomp-util.h create mode 100644 src/shared/securebits.h create mode 100644 src/shared/selinux-util.c create mode 100644 src/shared/selinux-util.h create mode 100644 src/shared/set.c create mode 100644 src/shared/set.h create mode 100644 src/shared/siphash24.c create mode 100644 src/shared/siphash24.h create mode 100644 src/shared/sleep-config.c create mode 100644 src/shared/sleep-config.h create mode 100644 src/shared/smack-util.c create mode 100644 src/shared/smack-util.h create mode 100644 src/shared/socket-label.c create mode 100644 src/shared/socket-util.c create mode 100644 src/shared/socket-util.h create mode 100644 src/shared/sparse-endian.h create mode 100644 src/shared/spawn-ask-password-agent.c create mode 100644 src/shared/spawn-ask-password-agent.h create mode 100644 src/shared/spawn-polkit-agent.c create mode 100644 src/shared/spawn-polkit-agent.h create mode 100644 src/shared/special.h create mode 100644 src/shared/specifier.c create mode 100644 src/shared/specifier.h create mode 100644 src/shared/strbuf.c create mode 100644 src/shared/strbuf.h create mode 100644 src/shared/strv.c create mode 100644 src/shared/strv.h create mode 100644 src/shared/strxcpyx.c create mode 100644 src/shared/strxcpyx.h create mode 100644 src/shared/test-tables.h create mode 100644 src/shared/time-dst.c create mode 100644 src/shared/time-dst.h create mode 100644 src/shared/time-util.c create mode 100644 src/shared/time-util.h create mode 100644 src/shared/udev-util.h create mode 100644 src/shared/unit-name.c create mode 100644 src/shared/unit-name.h create mode 100644 src/shared/utf8.c create mode 100644 src/shared/utf8.h create mode 100644 src/shared/util.c create mode 100644 src/shared/util.h create mode 100644 src/shared/utmp-wtmp.c create mode 100644 src/shared/utmp-wtmp.h create mode 100644 src/shared/virt.c create mode 100644 src/shared/virt.h create mode 100644 src/shared/watchdog.c create mode 100644 src/shared/watchdog.h create mode 100644 src/shared/xml.c create mode 100644 src/shared/xml.h delete mode 100644 src/shutdown.c delete mode 100644 src/shutdownd.c delete mode 100644 src/shutdownd.h create mode 120000 src/shutdownd/Makefile create mode 100644 src/shutdownd/shutdownd.c create mode 120000 src/sleep/Makefile create mode 100644 src/sleep/sleep.c delete mode 100644 src/snapshot.c delete mode 100644 src/snapshot.h create mode 120000 src/socket-proxy/Makefile create mode 100644 src/socket-proxy/socket-proxyd.c delete mode 100644 src/socket-util.c delete mode 100644 src/socket-util.h delete mode 100644 src/socket.c delete mode 100644 src/socket.h delete mode 100644 src/spawn-agent.c delete mode 100644 src/spawn-agent.h delete mode 100644 src/special.h delete mode 100644 src/specifier.c delete mode 100644 src/specifier.h delete mode 100644 src/stdout-syslog-bridge.c delete mode 100644 src/strv.c delete mode 100644 src/strv.h delete mode 100644 src/swap.c delete mode 100644 src/swap.h delete mode 100644 src/sysctl.c create mode 120000 src/sysctl/Makefile create mode 100644 src/sysctl/sysctl.c delete mode 100644 src/sysfs-show.c delete mode 100644 src/sysfs-show.h create mode 120000 src/system-update-generator/Makefile create mode 100644 src/system-update-generator/system-update-generator.c delete mode 100644 src/system.conf delete mode 100644 src/systemadm.vala delete mode 100644 src/systemctl-bash-completion.sh delete mode 100644 src/systemctl.c create mode 120000 src/systemctl/Makefile create mode 100644 src/systemctl/systemctl.c delete mode 100755 src/systemd-analyze delete mode 100644 src/systemd-interfaces.vala delete mode 100644 src/systemd-logind.conf create mode 120000 src/systemd/Makefile create mode 100644 src/systemd/_sd-common.h create mode 100644 src/systemd/sd-bus-protocol.h create mode 100644 src/systemd/sd-bus-vtable.h create mode 100644 src/systemd/sd-bus.h create mode 100644 src/systemd/sd-daemon.h create mode 100644 src/systemd/sd-dhcp-client.h create mode 100644 src/systemd/sd-event.h create mode 100644 src/systemd/sd-id128.h create mode 100644 src/systemd/sd-journal.h create mode 100644 src/systemd/sd-login.h create mode 100644 src/systemd/sd-memfd.h create mode 100644 src/systemd/sd-messages.h create mode 100644 src/systemd/sd-readahead.h create mode 100644 src/systemd/sd-resolve.h create mode 100644 src/systemd/sd-rtnl.h create mode 100644 src/systemd/sd-shutdown.h create mode 100644 src/systemd/sd-utf8.h delete mode 100644 src/target.c delete mode 100644 src/target.h delete mode 100644 src/tcpwrap.c delete mode 100644 src/tcpwrap.h delete mode 100644 src/test-cgroup.c delete mode 100644 src/test-daemon.c delete mode 100644 src/test-engine.c delete mode 100644 src/test-env-replace.c delete mode 100644 src/test-hostname.c delete mode 100644 src/test-install.c delete mode 100644 src/test-job-type.c delete mode 100644 src/test-login.c delete mode 100644 src/test-loopback.c delete mode 100644 src/test-ns.c delete mode 100644 src/test-strv.c create mode 120000 src/test/Makefile create mode 100644 src/test/test-architecture.c create mode 100644 src/test/test-boot-timestamps.c create mode 100644 src/test/test-calendarspec.c create mode 100644 src/test/test-cgroup-mask.c create mode 100644 src/test/test-cgroup-util.c create mode 100644 src/test/test-cgroup.c create mode 100644 src/test/test-daemon.c create mode 100644 src/test/test-date.c create mode 100644 src/test/test-device-nodes.c create mode 100644 src/test/test-ellipsize.c create mode 100644 src/test/test-engine.c create mode 100644 src/test/test-env-replace.c create mode 100644 src/test/test-fileio.c create mode 100644 src/test/test-hashmap.c create mode 100644 src/test/test-helper.h create mode 100644 src/test/test-hostname.c create mode 100644 src/test/test-id128.c create mode 100644 src/test/test-install.c create mode 100644 src/test/test-job-type.c create mode 100644 src/test/test-libudev.c create mode 100644 src/test/test-list.c create mode 100644 src/test/test-log.c create mode 100644 src/test/test-loopback.c create mode 100644 src/test/test-namespace.c create mode 100644 src/test/test-ns.c create mode 100644 src/test/test-path-util.c create mode 100644 src/test/test-prioq.c create mode 100644 src/test/test-replace-var.c create mode 100644 src/test/test-sched-prio.c create mode 100644 src/test/test-sleep.c create mode 100644 src/test/test-strbuf.c create mode 100644 src/test/test-strip-tab-ansi.c create mode 100644 src/test/test-strv.c create mode 100644 src/test/test-strxcpyx.c create mode 100644 src/test/test-tables.c create mode 100644 src/test/test-time.c create mode 100644 src/test/test-tmpfiles.c create mode 100644 src/test/test-udev.c create mode 100644 src/test/test-unit-file.c create mode 100644 src/test/test-unit-name.c create mode 100644 src/test/test-utf8.c create mode 100644 src/test/test-util.c create mode 100644 src/test/test-watchdog.c create mode 100644 src/test/test-xml.c create mode 100644 src/timedate/.gitignore create mode 120000 src/timedate/Makefile create mode 100644 src/timedate/org.freedesktop.timedate1.conf create mode 100644 src/timedate/org.freedesktop.timedate1.policy.in create mode 100644 src/timedate/org.freedesktop.timedate1.service create mode 100644 src/timedate/timedatectl.c create mode 100644 src/timedate/timedated.c delete mode 100644 src/timedated.c delete mode 100644 src/timer.c delete mode 100644 src/timer.h delete mode 100644 src/timestamp.c delete mode 100644 src/tmpfiles.c create mode 120000 src/tmpfiles/Makefile create mode 100644 src/tmpfiles/tmpfiles.c delete mode 100644 src/tty-ask-password-agent.c create mode 120000 src/tty-ask-password-agent/Makefile create mode 100644 src/tty-ask-password-agent/tty-ask-password-agent.c delete mode 100644 src/uaccess.c create mode 100644 src/udev/.gitignore create mode 100644 src/udev/.vimrc create mode 120000 src/udev/Makefile create mode 100644 src/udev/accelerometer/accelerometer.c create mode 100644 src/udev/ata_id/ata_id.c create mode 100644 src/udev/cdrom_id/cdrom_id.c create mode 100644 src/udev/collect/collect.c create mode 100644 src/udev/mtd_probe/mtd_probe.c create mode 100644 src/udev/mtd_probe/mtd_probe.h create mode 100644 src/udev/mtd_probe/probe_smartmedia.c create mode 100644 src/udev/net/.gitignore create mode 120000 src/udev/net/Makefile create mode 100644 src/udev/net/ethtool-util.c create mode 100644 src/udev/net/ethtool-util.h create mode 100644 src/udev/net/link-config-gperf.gperf create mode 100644 src/udev/net/link-config.c create mode 100644 src/udev/net/link-config.h create mode 100644 src/udev/scsi_id/.gitignore create mode 100644 src/udev/scsi_id/README create mode 100644 src/udev/scsi_id/scsi.h create mode 100644 src/udev/scsi_id/scsi_id.c create mode 100644 src/udev/scsi_id/scsi_id.h create mode 100644 src/udev/scsi_id/scsi_serial.c create mode 100644 src/udev/udev-builtin-blkid.c create mode 100644 src/udev/udev-builtin-btrfs.c create mode 100644 src/udev/udev-builtin-firmware.c create mode 100644 src/udev/udev-builtin-hwdb.c create mode 100644 src/udev/udev-builtin-input_id.c create mode 100644 src/udev/udev-builtin-keyboard.c create mode 100644 src/udev/udev-builtin-kmod.c create mode 100644 src/udev/udev-builtin-net_id.c create mode 100644 src/udev/udev-builtin-net_setup_link.c create mode 100644 src/udev/udev-builtin-path_id.c create mode 100644 src/udev/udev-builtin-uaccess.c create mode 100644 src/udev/udev-builtin-usb_id.c create mode 100644 src/udev/udev-builtin.c create mode 100644 src/udev/udev-ctrl.c create mode 100644 src/udev/udev-event.c create mode 100644 src/udev/udev-node.c create mode 100644 src/udev/udev-rules.c create mode 100644 src/udev/udev-watch.c create mode 100644 src/udev/udev.conf create mode 100644 src/udev/udev.h create mode 100644 src/udev/udev.pc.in create mode 100644 src/udev/udevadm-control.c create mode 100644 src/udev/udevadm-hwdb.c create mode 100644 src/udev/udevadm-info.c create mode 100644 src/udev/udevadm-monitor.c create mode 100644 src/udev/udevadm-settle.c create mode 100644 src/udev/udevadm-test-builtin.c create mode 100644 src/udev/udevadm-test.c create mode 100644 src/udev/udevadm-trigger.c create mode 100644 src/udev/udevadm.c create mode 100644 src/udev/udevd.c create mode 100644 src/udev/v4l_id/v4l_id.c delete mode 100644 src/umount.c delete mode 100644 src/umount.h delete mode 100644 src/unit-name.c delete mode 100644 src/unit-name.h delete mode 100644 src/unit.c delete mode 100644 src/unit.h delete mode 100644 src/update-utmp.c create mode 120000 src/update-utmp/Makefile create mode 100644 src/update-utmp/update-utmp.c delete mode 100644 src/user-sessions.c delete mode 100644 src/user.conf delete mode 100644 src/util.c delete mode 100644 src/util.h delete mode 100644 src/utmp-wtmp.c delete mode 100644 src/utmp-wtmp.h delete mode 100644 src/vconsole-setup.c create mode 120000 src/vconsole/Makefile create mode 100644 src/vconsole/vconsole-setup.c delete mode 100644 src/virt.c delete mode 100644 src/virt.h create mode 100644 sysctl.d/.gitignore create mode 100644 sysctl.d/50-coredump.conf.in create mode 100644 sysctl.d/50-default.conf create mode 120000 sysctl.d/Makefile delete mode 100644 systemd.pc.in create mode 100644 test/.gitignore create mode 100644 test/Makefile create mode 100644 test/README.testsuite create mode 100644 test/TEST-01-BASIC/Makefile create mode 100755 test/TEST-01-BASIC/test.sh create mode 120000 test/TEST-02-CRYPTSETUP/Makefile create mode 100755 test/TEST-02-CRYPTSETUP/test.sh create mode 120000 test/TEST-03-JOBS/Makefile create mode 100755 test/TEST-03-JOBS/test-jobs.sh create mode 100755 test/TEST-03-JOBS/test.sh create mode 120000 test/TEST-04-SECCOMP/Makefile create mode 100755 test/TEST-04-SECCOMP/test-seccomp.sh create mode 100755 test/TEST-04-SECCOMP/test.sh create mode 100644 test/TEST-04-SECCOMP/will-fail.service create mode 100644 test/TEST-04-SECCOMP/will-fail2.service create mode 100644 test/TEST-04-SECCOMP/will-not-fail.service create mode 100644 test/TEST-04-SECCOMP/will-not-fail2.service rename {test2 => test}/a.service (100%) rename {test2 => test}/b.service (100%) rename {test2 => test}/c.service (100%) rename {test2 => test}/d.service (100%) create mode 100644 test/daughter.service rename {test2 => test}/e.service (100%) create mode 100644 test/end.service rename {test2 => test}/f.service (100%) rename {test2 => test}/g.service (100%) create mode 100644 test/grandchild.service rename {test2 => test}/h.service (100%) create mode 100644 test/hello-after-sleep.target create mode 100644 test/hello.service create mode 100644 test/parent-deep.slice create mode 100644 test/parent.slice create mode 100755 test/rule-syntax-check.py create mode 100755 test/rules-test.sh create mode 100644 test/sched_idle_bad.service create mode 100644 test/sched_idle_ok.service create mode 100644 test/sched_rr_bad.service create mode 100644 test/sched_rr_change.service create mode 100644 test/sched_rr_ok.service create mode 100644 test/sleep.service create mode 100644 test/son.service create mode 100644 test/sys.tar.xz create mode 100644 test/test-functions create mode 100644 test/testsuite.target create mode 100755 test/udev-test.pl create mode 100644 test/unstoppable.service delete mode 120000 test1/default.target delete mode 100644 test1/exec-demo.service delete mode 100644 test1/fifo-demo.service delete mode 100644 test1/fifo-demo.socket delete mode 120000 test1/mail-transfer-agent.service delete mode 120000 test1/mail-transfer-agent.socket delete mode 100644 test1/multiuser.target delete mode 120000 test1/multiuser.target.wants/exec-demo.service delete mode 120000 test1/multiuser.target.wants/fifo-demo.socket delete mode 120000 test1/multiuser.target.wants/mail-transfer-agent.socket delete mode 120000 test1/multiuser.target.wants/permissions.service delete mode 120000 test1/multiuser.target.wants/systemd-logger.socket delete mode 100644 test1/permissions.service delete mode 100644 test1/postfix.service delete mode 100644 test1/postfix.socket delete mode 100644 test1/syslog.service delete mode 100644 test1/syslog.socket delete mode 100644 test1/systemd-logger.service delete mode 100644 test1/systemd-logger.socket delete mode 100644 test2/Makefile create mode 120000 tmpfiles.d/Makefile create mode 100644 tmpfiles.d/systemd-nologin.conf create mode 100755 tools/check-includes.pl create mode 100755 tools/make-directive-index.py create mode 100755 tools/make-man-index.py create mode 100644 tools/make-man-rules.py create mode 100644 tools/xml_helper.py create mode 100644 units/busnames.target create mode 100644 units/console-getty.service.m4.in delete mode 100644 units/console-shell.service.m4 create mode 100644 units/console-shell.service.m4.in create mode 100644 units/container-getty@.service.m4.in create mode 100644 units/debug-shell.service.in delete mode 100644 units/emergency.service create mode 100644 units/emergency.service.in delete mode 100644 units/fedora/halt-local.service delete mode 100644 units/fedora/prefdm.service delete mode 100644 units/fedora/rc-local.service delete mode 100644 units/frugalware/display-manager.service delete mode 100644 units/fsck-root.service.in delete mode 100644 units/fsck@.service.in create mode 100644 units/halt-local.service.in delete mode 100644 units/halt.service.in create mode 100644 units/hibernate.target delete mode 100644 units/http-daemon.target create mode 100644 units/hybrid-sleep.target create mode 100644 units/initrd-cleanup.service.in create mode 100644 units/initrd-fs.target create mode 100644 units/initrd-parse-etc.service.in create mode 100644 units/initrd-root-fs.target create mode 100644 units/initrd-switch-root.service.in create mode 100644 units/initrd-switch-root.target create mode 100644 units/initrd-udevadm-cleanup-db.service.in create mode 100644 units/initrd.target delete mode 100644 units/kexec.service.in create mode 100644 units/kmod-static-nodes.service.in create mode 100644 units/machine.slice delete mode 100644 units/mail-transfer-agent.target delete mode 100644 units/mandriva/prefdm.service delete mode 100644 units/media.mount create mode 100644 units/network-online.target create mode 100644 units/nss-user-lookup.target create mode 100644 units/org.freedesktop.DBus.busname create mode 100644 units/org.freedesktop.hostname1.busname create mode 100644 units/org.freedesktop.locale1.busname create mode 100644 units/org.freedesktop.login1.busname create mode 100644 units/org.freedesktop.machine1.busname create mode 100644 units/org.freedesktop.timedate1.busname create mode 100644 units/paths.target delete mode 100644 units/plymouth-halt.service delete mode 100644 units/plymouth-kexec.service delete mode 100644 units/plymouth-poweroff.service delete mode 100644 units/plymouth-quit-wait.service delete mode 100644 units/plymouth-quit.service delete mode 100644 units/plymouth-read-write.service delete mode 100644 units/plymouth-reboot.service delete mode 100644 units/plymouth-start.service delete mode 100644 units/poweroff.service.in delete mode 100644 units/quotacheck.service.in delete mode 100644 units/quotaon.service create mode 100644 units/quotaon.service.in create mode 100644 units/rc-local.service.in delete mode 100644 units/reboot.service.in delete mode 100644 units/remount-rootfs.service delete mode 100644 units/rescue.service.m4 create mode 100644 units/rescue.service.m4.in create mode 100644 units/sleep.target create mode 100644 units/slices.target delete mode 100644 units/slp/var-cache.automount delete mode 100644 units/slp/var-cache.mount delete mode 100644 units/slp/var-lib.automount delete mode 100644 units/slp/var-lib.mount delete mode 100644 units/slp/var-lock.mount delete mode 100644 units/slp/var-log.automount delete mode 100644 units/slp/var-log.mount delete mode 100644 units/suse/halt-local.service delete mode 100644 units/suse/rc-local.service create mode 100644 units/suspend.target delete mode 100644 units/sys-kernel-security.mount delete mode 100644 units/syslog.target create mode 100644 units/system-update.target create mode 100644 units/system.slice delete mode 100644 units/systemd-ask-password-plymouth.path delete mode 100644 units/systemd-ask-password-plymouth.service.in create mode 100644 units/systemd-backlight@.service.in create mode 100644 units/systemd-bus-driverd.service.in create mode 100644 units/systemd-bus-proxyd.socket create mode 100644 units/systemd-bus-proxyd@.service.in create mode 100644 units/systemd-fsck-root.service.in create mode 100644 units/systemd-fsck@.service.in create mode 100644 units/systemd-halt.service.in create mode 100644 units/systemd-hibernate.service.in create mode 100644 units/systemd-hybrid-sleep.service.in create mode 100644 units/systemd-journal-flush.service.in create mode 100644 units/systemd-journal-gatewayd.service.in create mode 100644 units/systemd-journal-gatewayd.socket create mode 100644 units/systemd-journald.service.in create mode 100644 units/systemd-journald.socket create mode 100644 units/systemd-kexec.service.in delete mode 100644 units/systemd-kmsg-syslogd.service.in create mode 100644 units/systemd-machined.service.in create mode 100644 units/systemd-networkd.service.in create mode 100644 units/systemd-nspawn@.service.in create mode 100644 units/systemd-poweroff.service.in create mode 100644 units/systemd-quotacheck.service.in delete mode 100644 units/systemd-random-seed-load.service.in delete mode 100644 units/systemd-random-seed-save.service.in create mode 100644 units/systemd-random-seed.service.in create mode 100644 units/systemd-readahead-drop.service create mode 100644 units/systemd-reboot.service.in delete mode 100644 units/systemd-remount-api-vfs.service.in create mode 100644 units/systemd-remount-fs.service.in create mode 100644 units/systemd-rfkill@.service.in delete mode 100644 units/systemd-stdout-syslog-bridge.service.in delete mode 100644 units/systemd-stdout-syslog-bridge.socket create mode 100644 units/systemd-suspend.service.in create mode 100644 units/systemd-tmpfiles-setup-dev.service.in create mode 100644 units/systemd-udev-settle.service.in create mode 100644 units/systemd-udev-trigger.service.in create mode 100644 units/systemd-udevd-control.socket create mode 100644 units/systemd-udevd-kernel.socket create mode 100644 units/systemd-udevd.service.in delete mode 100644 units/systemd-update-utmp-shutdown.service.in create mode 100644 units/systemd-update-utmp.service.in create mode 100644 units/timers.target create mode 100644 units/tmp.mount create mode 100644 units/user.slice create mode 100644 units/user/basic.target delete mode 100644 units/user/exit.service.in create mode 100644 units/user/systemd-bus-driverd.service.in create mode 100644 units/user/systemd-bus-proxyd.socket create mode 100644 units/user/systemd-bus-proxyd@.service.in create mode 100644 units/user/systemd-exit.service.in delete mode 100644 units/var-lock.mount delete mode 100644 units/var-run.mount create mode 100644 units/x-.slice diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1841508 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.[ch] whitespace=tab-in-indent,trailing-space diff --git a/.gitignore b/.gitignore index f4a8a45..45d4ed2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,100 +1,210 @@ -test-install -org.freedesktop.hostname1.xml -org.freedesktop.locale1.xml -org.freedesktop.timedate1.xml -libsystemd-daemon.pc -libsystemd-login.pc -test-login -systemd-loginctl -systemd-localed -systemd-timedated -systemd-uaccess -systemd-logind -systemd-hostnamed -systemd-binfmt -systemd-getty-generator -systemd-nspawn -systemd-stdio-bridge -systemd-machine-id-setup -systemd-detect-virt -systemd-sysctl -test-strv -systemd-ac-power -systemd-timestamp -systemd-cryptsetup -systemd-cryptsetup-generator -systemd-tty-ask-password-agent -systemd-fsck -systemd-quotacheck -systemd-user-sessions -systemd-shutdown -systemd-tmpfiles -systemd-readahead-collect -systemd-readahead-replay -systemd-reply-password -systemd-gnome-ask-password-agent -systemd-ask-password -systemd-kmsg-syslogd -systemd-remount-api-vfs -test-hostname -systemd-modules-load -systemd-vconsole-setup -systemd-shutdownd -systemd-random-seed -systemd-update-utmp -test-env-replace -systemd-cgls -systemd.pc -test-cgroup -.libs/ -systemd-notify -test-daemon -systemd-install -org.freedesktop.systemd1.*.xml -test-ns -test-loopback -systemd-cgroups-agent -systemd-initctl -systemd -test-engine -test-job-type -systemd-stdout-syslog-bridge -systemctl -systemadm -.dirstamp -*.1 -*.3 -*.5 -*.7 -*.8 -*.html -*~ -*.tar.gz -*.o -*.lo *.a +*.cache +*.html *.la +*.lo +*.log +*.o +*.plist +*.pyc +*.stamp +*.trs +*~ .deps/ +.dirstamp +.libs/ +/*.tar.bz2 +/*.tar.gz +/*.tar.xz +/Makefile +/TAGS +/accelerometer +/ata_id +/bootctl +/build-aux +/busctl +/cdrom_id +/collect +/coverage/ +/defined +/exported +/exported-* +/gtk-doc.make +/hostnamectl +/install-tree +/journalctl +/libsystemd-*.c +/libtool +/localectl +/loginctl +/machinectl +/mtd_probe +/scsi_id +/systemadm +/systemctl +/systemd +/systemd-ac-power +/systemd-activate +/systemd-analyze +/systemd-ask-password +/systemd-backlight +/systemd-binfmt +/systemd-bootchart +/systemd-bus-proxyd +/systemd-bus-driverd +/systemd-cat +/systemd-cgls +/systemd-cgroups-agent +/systemd-cgtop +/systemd-coredump +/systemd-coredumpctl +/systemd-cryptsetup +/systemd-cryptsetup-generator +/systemd-dbus1-generator +/systemd-delta +/systemd-detect-virt +/systemd-efi-boot-generator +/systemd-fsck +/systemd-fstab-generator +/systemd-getty-generator +/systemd-gnome-ask-password-agent +/systemd-gpt-auto-generator +/systemd-hostnamed +/systemd-inhibit +/systemd-initctl +/systemd-journal-gatewayd +/systemd-journald +/systemd-kmsg-syslogd +/systemd-localed +/systemd-logind +/systemd-machine-id-setup +/systemd-machined +/systemd-modules-load +/systemd-multi-seat-x +/systemd-networkd +/systemd-notify +/systemd-nspawn +/systemd-quotacheck +/systemd-random-seed +/systemd-rc-local-generator +/systemd-readahead +/systemd-remount-api-vfs +/systemd-remount-fs +/systemd-reply-password +/systemd-rfkill +/systemd-run +/systemd-shutdown +/systemd-shutdownd +/systemd-sleep +/systemd-socket-proxyd +/systemd-sysctl +/systemd-system-update-generator +/systemd-timedated +/systemd-tmpfiles +/systemd-tty-ask-password-agent +/systemd-uaccess +/systemd-udevd +/systemd-update-utmp +/systemd-user-sessions +/systemd-vconsole-setup +/tags +/test-architecture +/test-boot-timestamp +/test-bus-chat +/test-bus-creds +/test-bus-error +/test-bus-gvariant +/test-bus-cleanup +/test-bus-introspect +/test-bus-kernel +/test-bus-kernel-benchmark +/test-bus-kernel-bloom +/test-bus-marshal +/test-bus-match +/test-bus-memfd +/test-bus-objects +/test-bus-server +/test-bus-signature +/test-bus-zero-copy +/test-calendarspec +/test-catalog +/test-cgroup +/test-cgroup-mask +/test-cgroup-util +/test-daemon +/test-date +/test-device-nodes +/test-dhcp-client +/test-dhcp-option +/test-resolve +/test-ellipsize +/test-engine +/test-env-replace +/test-event +/test-fileio +/test-hashmap +/test-hostname +/test-id128 +/test-inhibit +/test-install +/test-job-type +/test-journal +/test-journal-enum +/test-journal-flush +/test-journal-init +/test-journal-interleaving +/test-journal-match +/test-journal-send +/test-journal-stream +/test-journal-syslog +/test-journal-verify +/test-libsystemd-sym* +/test-libsystemd-*-sym* +/test-libudev +/test-libudev-sym* +/test-list +/test-log +/test-login +/test-login-shared +/test-login-tables +/test-loopback +/test-machine-tables +/test-mmap-cache +/test-namespace +/test-network +/test-ns +/test-path-util +/test-prioq +/test-replace-var +/test-rtnl +/test-sched-prio +/test-sleep +/test-strbuf +/test-strip-tab-ansi +/test-strv +/test-strxcpyx +/test-tables +/test-time +/test-tmpfiles +/test-udev +/test-unit-file +/test-unit-name +/test-utf8 +/test-util +/test-watchdog +/test-xml +/timedatectl +/udevadm +/undefined +/v4l_id Makefile.in +__pycache__/ aclocal.m4 -*.cache -compile -config.guess config.h config.h.in config.log config.status -config.sub configure -depcomp -install-sh -missing stamp-* -*.stamp -Makefile -ltmain.sh -*.tar.bz2 -*.tar.gz -*.tar.xz -libtool -.vimrc +.\#* +\#*\# diff --git a/.mailmap b/.mailmap index 04b1c6c..7617f32 100644 --- a/.mailmap +++ b/.mailmap @@ -1,4 +1,65 @@ -Kay Sievers +Kay Sievers +Kay Sievers +Kay Sievers +Kay Sievers +Kay Sievers +Kay Sievers +Greg Kroah-Hartman +Greg Kroah-Hartman +Greg Kroah-Hartman +Greg Kroah-Hartman +Greg Kroah-Hartman +Greg Kroah-Hartman +Harald Hoyer +David Zeuthen +David Zeuthen +David Zeuthen +Hannes Reinecke +Scott James Remnant +Scott James Remnant +Alan Jenkins +Alan Jenkins +Marco d'Itri Robert Gerus Robert "arachnist" Gerus -Zbigniew Jędrzejewski-Szmek Zbyszek Szmek Fabiano Fidêncio Fabiano Fidencio +Martin Pitt +Martin Pitt +Daniel J Walsh +Dave Reisner +Diego Elio Pettenò +Daniel Elstner +Frederic Crozat +Ian Campbell +Jerone Young +Luis Felipe Strano Moraes +Mario Limonciello +Matthias Clasen +Michal Soltys +Piter PUNK +Richard Hughes +Robby Workman +Shawn Landden +Simon Peeters +Tobias Klauser +Miklos Vajna +William Jon McCann +Yin Kangkai +Zbigniew Jędrzejewski-Szmek +Lennart Poettering +Ananth N Mavinakayanahalli +Ananth N Mavinakayanahalli +Ted Ts'o +Tobias Klauser +Tobias Klauser +Tobias Klauser +Tobias Klauser +Patrick Mansfield +Christophe Varoqui +Daniel Stekloff +Michael Buesch +Olaf Hering +Robert Love +Arnd Bergmann +Tom Rini +Paul Mundt +Atul Sabharwal diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7e5251c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: c +compiler: + - gcc +before_install: + - sudo apt-get update -qq + - sudo apt-get install autotools-dev automake autoconf libtool libdbus-1-dev libcap-dev libblkid-dev libpam-dev libcryptsetup-dev libaudit-dev libacl1-dev libattr1-dev libselinux-dev liblzma-dev libgcrypt-dev libqrencode-dev libmicrohttpd-dev gtk-doc-tools gperf python2.7-dev +script: ./autogen.sh && ./configure --enable-gtk-doc --enable-gtk-doc-pdf && make V=1 && sudo ./systemd-machine-id-setup && make check && make distcheck +after_failure: cat test-suite.log +notifications: + irc: + channels: + - "irc.freenode.org#systemd" + on_success: change + on_failure: always diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..b802c90 --- /dev/null +++ b/.vimrc @@ -0,0 +1,5 @@ +" 'set exrc' in ~/.vimrc will read .vimrc from the current directory +set tabstop=8 +set shiftwidth=8 +set expandtab +set makeprg=GCC_COLORS=\ make diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000..a90610d --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,66 @@ +import itertools +import os +import subprocess + +def GetFlagsFromMakefile(varname): + return subprocess.check_output([ + "make", "-s", "print-%s" % varname]).decode().split() + + +def Flatten(lists): + return list(itertools.chain.from_iterable(lists)) + + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return flags + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[ len(path_flag): ] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def FlagsForFile(filename): + relative_to = DirectoryOfThisScript() + + return { + 'flags': MakeRelativePathsInFlagsAbsolute(flags, relative_to), + 'do_cache': True + } + +flags = Flatten(map(GetFlagsFromMakefile, [ + 'AM_CPPFLAGS', + 'CPPFLAGS', + 'AM_CFLAGS', + 'CFLAGS', +])) + +# these flags cause crashes in libclang, so remove them +flags.remove('-Wlogical-op') +flags.remove('-Wsuggest-attribute=noreturn') + +# vim: set et ts=2 sw=2: diff --git a/CODING_STYLE b/CODING_STYLE index 9341b48..996897b 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -1,27 +1,169 @@ - 8ch indent, no tabs -- structs in MixedCase, variables, functions in lower_case +- Variables and functions *must* be static, unless they have a + prototype, and are supposed to be exported. -- the destructors always unregister the object from the next bigger +- structs in MixedCase (with exceptions, such as public API structs), + variables + functions in lower_case. + +- The destructors always unregister the object from the next bigger object, not the other way around -- to minimize strict aliasing violations we prefer unions over casting +- To minimize strict aliasing violations we prefer unions over casting -- for robustness reasons destructors should be able to destruct +- For robustness reasons destructors should be able to destruct half-initialized objects, too -- error codes are returned as negative Exxx. i.e. return -EINVAL. There +- Error codes are returned as negative Exxx. i.e. return -EINVAL. There are some exceptions: for constructors its is OK to return NULL on OOM. For lookup functions NULL is fine too for "not found". + Be strict with this. When you write a function that can fail due to + more than one cause, it *really* should have "int" as return value + for the error code. + +- Don't bother with error checking whether writing to stdout/stderr + worked. + +- Do not log errors from "library" code, only do so from "main + program" code. (With one exception: it's OK to log with DEBUG level + from any code, with the exception of maybe inner loops). + +- Always check OOM. There's no excuse. In program code you can use + "log_oom()" for then printing a short message, but not in "library" code. + - Do not issue NSS requests (that includes user name and host name - lookups) from the main daemon as this might trigger deadlocks when - we those lookups involve synchronously talking to services that we - would need to start up. + lookups) from PID 1 as this might trigger deadlocks when those + lookups involve synchronously talking to services that we would need + to start up + +- Don't synchronously talk to any other service from PID 1, due to + risk of deadlocks + +- Avoid fixed sized string buffers, unless you really know the maximum + size and that maximum size is small. They are a source of errors, + since they possibly result in truncated strings. Often it is nicer + to use dynamic memory, alloca() or VLAs. If you do allocate fixed + size strings on the stack, then it's probably only OK if you either + use a maximum size such as LINE_MAX, or count in detail the maximum + size a string can have. (DECIMAL_STR_MAX and DECIMAL_STR_WIDTH + macros are your friends for this!) + + Or in other words, if you use "char buf[256]" then you are likely + doing something wrong! + +- Stay uniform. For example, always use "usec_t" for time + values. Don't usec mix msec, and usec and whatnot. + +- Make use of _cleanup_free_ and friends. It makes your code much + nicer to read! + +- Be exceptionally careful when formatting and parsing floating point + numbers. Their syntax is locale dependent (i.e. "5.000" in en_US is + generally understood as 5, while on de_DE as 5000.). + +- Try to use this: + + void foo() { + } + + instead of this: + + void foo() + { + } + + But it's OK if you don't. + +- Don't write "foo ()", write "foo()". + +- Please use streq() and strneq() instead of strcmp(), strncmp() where applicable. + +- Please do not allocate variables on the stack in the middle of code, + even if C99 allows it. Wrong: + + { + a = 5; + int b; + b = a; + } + + Right: + + { + int b; + a = 5; + b = a; + } + +- Unless you allocate an array, "double" is always the better choice + than "float". Processors speak "double" natively anyway, so this is + no speed benefit, and on calls like printf() "float"s get upgraded + to "double"s anyway, so there is no point. + +- Don't invoke functions when you allocate variables on the stack. Wrong: + + { + int a = foobar(); + uint64_t x = 7; + } + + Right: + + { + int a; + uint64_t x = 7; + + a = foobar(); + } + +- Use "goto" for cleaning up, and only use it for that. i.e. you may + only jump to the end of a function, and little else. Never jump + backwards! + +- Think about the types you use. If a value cannot sensibly be + negative don't use "int", but use "unsigned". + +- Don't use types like "short". They *never* make sense. Use ints, + longs, long longs, all in unsigned+signed fashion, and the fixed + size types uint32_t and so on, as well as size_t but nothing else. + +- Public API calls (i.e. functions exported by our shared libraries) + must be marked "_public_" and need to be prefixed with "sd_". No + other functions should be prefixed like that. + +- In public API calls you *must* validate all your input arguments for + programming error with assert_return() and return a sensible return + code. In all other calls it is recommended to check for programming + errors with a more brutal assert(). We are more forgiving to public + users then for ourselves! Note that assert() and assert_return() + really only should be used for detecting programming errors, not for + runtime errors. assert() and assert_return() by usage of _likely_() + inform the compiler that he shouldn't expect these checks to fail, + and they inform fellow programmers about the expected validity and + range of parameters. + +- Never use strtol(), atoi() and similar calls. Use safe_atoli(), + safe_atou32() and suchlike instead. They are much nicer to use in + most cases and correctly check for parsing errors. -- Do not access any directories outside of /etc/, /dev, /lib from the - init daemon to avoid deadlocks with the automounter. +- For every function you add, think about whether it is a "logging" + function or a "non-logging" function. "Logging" functions do logging + on their own, "non-logging" function never log on their own and + expect their callers to log. All functions in "library" code, + i.e. in src/shared/ and suchlike must be "non-logging". Everytime a + "logging" function calls a "non-logging" function it should log + about the resulting errors. If a "logging" function calls another + "logging" function, then it should not generate log messages, so + that log messages are not generated twice for the same errors. -- Don't synchronously talk to any other service, due to risk of - deadlocks. +- Avoid static variables, except for caches and very few other + cases. Think about thread-safety! While most of our code is never + used in threaded environments at least the library code should make + sure it works correctly in them. Instead of doing a lot of locking + for that we tend to prefer using TLS to do per-thread caching (which + only works for small, fixed-size cache objects), or we disable + caching for any thread that is not the main thread. Use + is_main_thread() to detect whether the calling thread is the main + thread. diff --git a/DISTRO_PORTING b/DISTRO_PORTING index 2b08bf8..d799e53 100644 --- a/DISTRO_PORTING +++ b/DISTRO_PORTING @@ -4,55 +4,31 @@ HOWTO: You need to make the follow changes to adapt systemd to your distribution: - 0) Make your distribution recognized via the autoconf checks - in configure.ac. Grep for the word "fedora" (case - insensitively) and you should be able to find the places where - you need to add/change things. - - 1) Patch src/hostname-setup.c so that systemd knows where to - read your host name from. You might also want to update - status_welcome() in util.c. - - 2) Check the unit files in units/ if they match your - distribution. Most likely you will have to make additions to - units/*.m4 and create a copy of units/fedora/ with changes for - your distribution. - - 3) Adjust Makefile.am to register the unit files you added in - step 2. Also you might need to update the m4 invocation in - Makefile.am. Grep for the word "fedora" (case insensitively) - and you should be able to find the places where you need to - add/change things. - - 4) Try it out. Play around with 'systemd --test --system' for + 1) Find the right configure parameters for: + + --with-rootprefix= + --with-sysvinit-path= + --with-sysvrcnd-path= + --with-rc-local-script-path-start= + --with-rc-local-script-path-stop= + --with-kbd-loadkeys= + --with-kbd-setfont= + --with-tty-gid= + + 2) Try it out. Play around with 'systemd --test --system' for a test run of systemd without booting. This will read the unit files and print the initial transaction it would execute during boot-up. This will also inform you about ordering loops and suchlike. CONTRIBUTING UPSTREAM: - We are interested in merging your changes upstream, if they - are for a big, and well-known distribution. Unfortunately we - don't have the time and resources to maintain - distribution-specific patches for all distributions on the - planet, hence please do not send us patches that add systemd - support for non-mainstream or niche distributions. - Thank you for understanding. - -BE CONSIDERATE: - We'd like to keep differences between the distributions - minimal. This both simplifies our maintenance work, as well - as it helps administrators to move from one distribution to - another. + We do generally no longer accept distribution-specific + patches to systemd upstream. If you have to make changes to + systemd's source code to make it work on your distribution: + unless your code is generic enough to be generally useful, we + are unlikely to merge it. Please always consider adopting the + upstream defaults. If that is not possible, please maintain + the relevant patches downstream. - Hence we'd like to ask you to keep your changes minimal, and - not rename any units without a very good reason (if you need a - particular name for compatibility reasons, consider using - alias names via symlinks). Before you make changes that change - semantics from upstream, please talk to us! - - In SysV almost every distribution uses a different - nomenclature and different locations for the boot-up - scripts. We'd like to avoid chaos like that with systemd right - from the beginning. So please, be considerate! + Thank you for understanding. diff --git a/LICENSE b/LICENSE.GPL2 similarity index 100% rename from LICENSE rename to LICENSE.GPL2 diff --git a/LICENSE.LGPL2.1 b/LICENSE.LGPL2.1 new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/LICENSE.LGPL2.1 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSE.MIT b/LICENSE.MIT new file mode 100644 index 0000000..fd44f73 --- /dev/null +++ b/LICENSE.MIT @@ -0,0 +1,19 @@ +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile-man.am b/Makefile-man.am new file mode 100644 index 0000000..aad3f44 --- /dev/null +++ b/Makefile-man.am @@ -0,0 +1,1477 @@ +# Do not edit. Generated by make-man-rules.py. +# Regenerate with 'make all update-man-list'. + +MANPAGES += \ + man/bootup.7 \ + man/busctl.1 \ + man/daemon.7 \ + man/halt.8 \ + man/hostname.5 \ + man/journalctl.1 \ + man/journald.conf.5 \ + man/kernel-command-line.7 \ + man/kernel-install.8 \ + man/locale.conf.5 \ + man/localtime.5 \ + man/machine-id.5 \ + man/machine-info.5 \ + man/os-release.5 \ + man/runlevel.8 \ + man/sd-daemon.3 \ + man/sd-id128.3 \ + man/sd-journal.3 \ + man/sd_booted.3 \ + man/sd_id128_get_machine.3 \ + man/sd_id128_randomize.3 \ + man/sd_id128_to_string.3 \ + man/sd_is_fifo.3 \ + man/sd_journal_add_match.3 \ + man/sd_journal_get_catalog.3 \ + man/sd_journal_get_cursor.3 \ + man/sd_journal_get_cutoff_realtime_usec.3 \ + man/sd_journal_get_data.3 \ + man/sd_journal_get_fd.3 \ + man/sd_journal_get_realtime_usec.3 \ + man/sd_journal_get_usage.3 \ + man/sd_journal_next.3 \ + man/sd_journal_open.3 \ + man/sd_journal_print.3 \ + man/sd_journal_query_unique.3 \ + man/sd_journal_seek_head.3 \ + man/sd_journal_stream_fd.3 \ + man/sd_listen_fds.3 \ + man/sd_notify.3 \ + man/sd_watchdog_enabled.3 \ + man/shutdown.8 \ + man/sysctl.d.5 \ + man/systemctl.1 \ + man/systemd-activate.8 \ + man/systemd-analyze.1 \ + man/systemd-ask-password-console.service.8 \ + man/systemd-ask-password.1 \ + man/systemd-cat.1 \ + man/systemd-cgls.1 \ + man/systemd-cgtop.1 \ + man/systemd-delta.1 \ + man/systemd-detect-virt.1 \ + man/systemd-efi-boot-generator.8 \ + man/systemd-fsck@.service.8 \ + man/systemd-fstab-generator.8 \ + man/systemd-getty-generator.8 \ + man/systemd-gpt-auto-generator.8 \ + man/systemd-halt.service.8 \ + man/systemd-inhibit.1 \ + man/systemd-initctl.service.8 \ + man/systemd-journald.service.8 \ + man/systemd-machine-id-setup.1 \ + man/systemd-notify.1 \ + man/systemd-nspawn.1 \ + man/systemd-remount-fs.service.8 \ + man/systemd-run.1 \ + man/systemd-shutdownd.service.8 \ + man/systemd-sleep.conf.5 \ + man/systemd-socket-proxyd.8 \ + man/systemd-suspend.service.8 \ + man/systemd-sysctl.service.8 \ + man/systemd-system-update-generator.8 \ + man/systemd-system.conf.5 \ + man/systemd-tmpfiles.8 \ + man/systemd-tty-ask-password-agent.1 \ + man/systemd-udevd.service.8 \ + man/systemd-update-utmp.service.8 \ + man/systemd.1 \ + man/systemd.automount.5 \ + man/systemd.device.5 \ + man/systemd.exec.5 \ + man/systemd.journal-fields.7 \ + man/systemd.kill.5 \ + man/systemd.mount.5 \ + man/systemd.path.5 \ + man/systemd.preset.5 \ + man/systemd.resource-control.5 \ + man/systemd.scope.5 \ + man/systemd.service.5 \ + man/systemd.slice.5 \ + man/systemd.snapshot.5 \ + man/systemd.socket.5 \ + man/systemd.special.7 \ + man/systemd.swap.5 \ + man/systemd.target.5 \ + man/systemd.time.7 \ + man/systemd.timer.5 \ + man/systemd.unit.5 \ + man/telinit.8 \ + man/tmpfiles.d.5 \ + man/udev.7 \ + man/udevadm.8 +MANPAGES_ALIAS += \ + man/SD_ALERT.3 \ + man/SD_CRIT.3 \ + man/SD_DEBUG.3 \ + man/SD_EMERG.3 \ + man/SD_ERR.3 \ + man/SD_ID128_CONST_STR.3 \ + man/SD_ID128_FORMAT_STR.3 \ + man/SD_ID128_FORMAT_VAL.3 \ + man/SD_ID128_MAKE.3 \ + man/SD_INFO.3 \ + man/SD_JOURNAL_APPEND.3 \ + man/SD_JOURNAL_CURRENT_USER.3 \ + man/SD_JOURNAL_FOREACH.3 \ + man/SD_JOURNAL_FOREACH_BACKWARDS.3 \ + man/SD_JOURNAL_FOREACH_DATA.3 \ + man/SD_JOURNAL_FOREACH_UNIQUE.3 \ + man/SD_JOURNAL_INVALIDATE.3 \ + man/SD_JOURNAL_LOCAL_ONLY.3 \ + man/SD_JOURNAL_NOP.3 \ + man/SD_JOURNAL_RUNTIME_ONLY.3 \ + man/SD_JOURNAL_SUPPRESS_LOCATION.3 \ + man/SD_JOURNAL_SYSTEM.3 \ + man/SD_LISTEN_FDS_START.3 \ + man/SD_NOTICE.3 \ + man/SD_WARNING.3 \ + man/init.1 \ + man/poweroff.8 \ + man/reboot.8 \ + man/sd_id128_equal.3 \ + man/sd_id128_from_string.3 \ + man/sd_id128_get_boot.3 \ + man/sd_id128_t.3 \ + man/sd_is_mq.3 \ + man/sd_is_socket.3 \ + man/sd_is_socket_inet.3 \ + man/sd_is_socket_unix.3 \ + man/sd_is_special.3 \ + man/sd_journal.3 \ + man/sd_journal_add_conjunction.3 \ + man/sd_journal_add_disjunction.3 \ + man/sd_journal_close.3 \ + man/sd_journal_enumerate_data.3 \ + man/sd_journal_enumerate_unique.3 \ + man/sd_journal_flush_matches.3 \ + man/sd_journal_get_catalog_for_message_id.3 \ + man/sd_journal_get_cutoff_monotonic_usec.3 \ + man/sd_journal_get_data_threshold.3 \ + man/sd_journal_get_events.3 \ + man/sd_journal_get_monotonic_usec.3 \ + man/sd_journal_get_timeout.3 \ + man/sd_journal_next_skip.3 \ + man/sd_journal_open_container.3 \ + man/sd_journal_open_directory.3 \ + man/sd_journal_open_files.3 \ + man/sd_journal_perror.3 \ + man/sd_journal_previous.3 \ + man/sd_journal_previous_skip.3 \ + man/sd_journal_printv.3 \ + man/sd_journal_process.3 \ + man/sd_journal_reliable_fd.3 \ + man/sd_journal_restart_data.3 \ + man/sd_journal_restart_unique.3 \ + man/sd_journal_seek_cursor.3 \ + man/sd_journal_seek_monotonic_usec.3 \ + man/sd_journal_seek_realtime_usec.3 \ + man/sd_journal_seek_tail.3 \ + man/sd_journal_send.3 \ + man/sd_journal_sendv.3 \ + man/sd_journal_set_data_threshold.3 \ + man/sd_journal_test_cursor.3 \ + man/sd_journal_wait.3 \ + man/sd_notifyf.3 \ + man/systemd-ask-password-console.path.8 \ + man/systemd-ask-password-wall.path.8 \ + man/systemd-ask-password-wall.service.8 \ + man/systemd-fsck-root.service.8 \ + man/systemd-fsck.8 \ + man/systemd-hibernate.service.8 \ + man/systemd-hybrid-sleep.service.8 \ + man/systemd-initctl.8 \ + man/systemd-initctl.socket.8 \ + man/systemd-journald.8 \ + man/systemd-journald.socket.8 \ + man/systemd-kexec.service.8 \ + man/systemd-poweroff.service.8 \ + man/systemd-reboot.service.8 \ + man/systemd-remount-fs.8 \ + man/systemd-shutdown.8 \ + man/systemd-shutdownd.8 \ + man/systemd-shutdownd.socket.8 \ + man/systemd-sleep.8 \ + man/systemd-sysctl.8 \ + man/systemd-tmpfiles-clean.service.8 \ + man/systemd-tmpfiles-clean.timer.8 \ + man/systemd-tmpfiles-setup-dev.service.8 \ + man/systemd-tmpfiles-setup.service.8 \ + man/systemd-udevd-control.socket.8 \ + man/systemd-udevd-kernel.socket.8 \ + man/systemd-udevd.8 \ + man/systemd-update-utmp-runlevel.service.8 \ + man/systemd-update-utmp.8 \ + man/systemd-user.conf.5 +man/SD_ALERT.3: man/sd-daemon.3 +man/SD_CRIT.3: man/sd-daemon.3 +man/SD_DEBUG.3: man/sd-daemon.3 +man/SD_EMERG.3: man/sd-daemon.3 +man/SD_ERR.3: man/sd-daemon.3 +man/SD_ID128_CONST_STR.3: man/sd-id128.3 +man/SD_ID128_FORMAT_STR.3: man/sd-id128.3 +man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3 +man/SD_ID128_MAKE.3: man/sd-id128.3 +man/SD_INFO.3: man/sd-daemon.3 +man/SD_JOURNAL_APPEND.3: man/sd_journal_get_fd.3 +man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3 +man/SD_JOURNAL_FOREACH.3: man/sd_journal_next.3 +man/SD_JOURNAL_FOREACH_BACKWARDS.3: man/sd_journal_next.3 +man/SD_JOURNAL_FOREACH_DATA.3: man/sd_journal_get_data.3 +man/SD_JOURNAL_FOREACH_UNIQUE.3: man/sd_journal_query_unique.3 +man/SD_JOURNAL_INVALIDATE.3: man/sd_journal_get_fd.3 +man/SD_JOURNAL_LOCAL_ONLY.3: man/sd_journal_open.3 +man/SD_JOURNAL_NOP.3: man/sd_journal_get_fd.3 +man/SD_JOURNAL_RUNTIME_ONLY.3: man/sd_journal_open.3 +man/SD_JOURNAL_SUPPRESS_LOCATION.3: man/sd_journal_print.3 +man/SD_JOURNAL_SYSTEM.3: man/sd_journal_open.3 +man/SD_LISTEN_FDS_START.3: man/sd_listen_fds.3 +man/SD_NOTICE.3: man/sd-daemon.3 +man/SD_WARNING.3: man/sd-daemon.3 +man/init.1: man/systemd.1 +man/poweroff.8: man/halt.8 +man/reboot.8: man/halt.8 +man/sd_id128_equal.3: man/sd-id128.3 +man/sd_id128_from_string.3: man/sd_id128_to_string.3 +man/sd_id128_get_boot.3: man/sd_id128_get_machine.3 +man/sd_id128_t.3: man/sd-id128.3 +man/sd_is_mq.3: man/sd_is_fifo.3 +man/sd_is_socket.3: man/sd_is_fifo.3 +man/sd_is_socket_inet.3: man/sd_is_fifo.3 +man/sd_is_socket_unix.3: man/sd_is_fifo.3 +man/sd_is_special.3: man/sd_is_fifo.3 +man/sd_journal.3: man/sd_journal_open.3 +man/sd_journal_add_conjunction.3: man/sd_journal_add_match.3 +man/sd_journal_add_disjunction.3: man/sd_journal_add_match.3 +man/sd_journal_close.3: man/sd_journal_open.3 +man/sd_journal_enumerate_data.3: man/sd_journal_get_data.3 +man/sd_journal_enumerate_unique.3: man/sd_journal_query_unique.3 +man/sd_journal_flush_matches.3: man/sd_journal_add_match.3 +man/sd_journal_get_catalog_for_message_id.3: man/sd_journal_get_catalog.3 +man/sd_journal_get_cutoff_monotonic_usec.3: man/sd_journal_get_cutoff_realtime_usec.3 +man/sd_journal_get_data_threshold.3: man/sd_journal_get_data.3 +man/sd_journal_get_events.3: man/sd_journal_get_fd.3 +man/sd_journal_get_monotonic_usec.3: man/sd_journal_get_realtime_usec.3 +man/sd_journal_get_timeout.3: man/sd_journal_get_fd.3 +man/sd_journal_next_skip.3: man/sd_journal_next.3 +man/sd_journal_open_container.3: man/sd_journal_open.3 +man/sd_journal_open_directory.3: man/sd_journal_open.3 +man/sd_journal_open_files.3: man/sd_journal_open.3 +man/sd_journal_perror.3: man/sd_journal_print.3 +man/sd_journal_previous.3: man/sd_journal_next.3 +man/sd_journal_previous_skip.3: man/sd_journal_next.3 +man/sd_journal_printv.3: man/sd_journal_print.3 +man/sd_journal_process.3: man/sd_journal_get_fd.3 +man/sd_journal_reliable_fd.3: man/sd_journal_get_fd.3 +man/sd_journal_restart_data.3: man/sd_journal_get_data.3 +man/sd_journal_restart_unique.3: man/sd_journal_query_unique.3 +man/sd_journal_seek_cursor.3: man/sd_journal_seek_head.3 +man/sd_journal_seek_monotonic_usec.3: man/sd_journal_seek_head.3 +man/sd_journal_seek_realtime_usec.3: man/sd_journal_seek_head.3 +man/sd_journal_seek_tail.3: man/sd_journal_seek_head.3 +man/sd_journal_send.3: man/sd_journal_print.3 +man/sd_journal_sendv.3: man/sd_journal_print.3 +man/sd_journal_set_data_threshold.3: man/sd_journal_get_data.3 +man/sd_journal_test_cursor.3: man/sd_journal_get_cursor.3 +man/sd_journal_wait.3: man/sd_journal_get_fd.3 +man/sd_notifyf.3: man/sd_notify.3 +man/systemd-ask-password-console.path.8: man/systemd-ask-password-console.service.8 +man/systemd-ask-password-wall.path.8: man/systemd-ask-password-console.service.8 +man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.service.8 +man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8 +man/systemd-fsck.8: man/systemd-fsck@.service.8 +man/systemd-hibernate.service.8: man/systemd-suspend.service.8 +man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8 +man/systemd-initctl.8: man/systemd-initctl.service.8 +man/systemd-initctl.socket.8: man/systemd-initctl.service.8 +man/systemd-journald.8: man/systemd-journald.service.8 +man/systemd-journald.socket.8: man/systemd-journald.service.8 +man/systemd-kexec.service.8: man/systemd-halt.service.8 +man/systemd-poweroff.service.8: man/systemd-halt.service.8 +man/systemd-reboot.service.8: man/systemd-halt.service.8 +man/systemd-remount-fs.8: man/systemd-remount-fs.service.8 +man/systemd-shutdown.8: man/systemd-halt.service.8 +man/systemd-shutdownd.8: man/systemd-shutdownd.service.8 +man/systemd-shutdownd.socket.8: man/systemd-shutdownd.service.8 +man/systemd-sleep.8: man/systemd-suspend.service.8 +man/systemd-sysctl.8: man/systemd-sysctl.service.8 +man/systemd-tmpfiles-clean.service.8: man/systemd-tmpfiles.8 +man/systemd-tmpfiles-clean.timer.8: man/systemd-tmpfiles.8 +man/systemd-tmpfiles-setup-dev.service.8: man/systemd-tmpfiles.8 +man/systemd-tmpfiles-setup.service.8: man/systemd-tmpfiles.8 +man/systemd-udevd-control.socket.8: man/systemd-udevd.service.8 +man/systemd-udevd-kernel.socket.8: man/systemd-udevd.service.8 +man/systemd-udevd.8: man/systemd-udevd.service.8 +man/systemd-update-utmp-runlevel.service.8: man/systemd-update-utmp.service.8 +man/systemd-update-utmp.8: man/systemd-update-utmp.service.8 +man/systemd-user.conf.5: man/systemd-system.conf.5 +man/SD_ALERT.html: man/sd-daemon.html + $(html-alias) + +man/SD_CRIT.html: man/sd-daemon.html + $(html-alias) + +man/SD_DEBUG.html: man/sd-daemon.html + $(html-alias) + +man/SD_EMERG.html: man/sd-daemon.html + $(html-alias) + +man/SD_ERR.html: man/sd-daemon.html + $(html-alias) + +man/SD_ID128_CONST_STR.html: man/sd-id128.html + $(html-alias) + +man/SD_ID128_FORMAT_STR.html: man/sd-id128.html + $(html-alias) + +man/SD_ID128_FORMAT_VAL.html: man/sd-id128.html + $(html-alias) + +man/SD_ID128_MAKE.html: man/sd-id128.html + $(html-alias) + +man/SD_INFO.html: man/sd-daemon.html + $(html-alias) + +man/SD_JOURNAL_APPEND.html: man/sd_journal_get_fd.html + $(html-alias) + +man/SD_JOURNAL_CURRENT_USER.html: man/sd_journal_open.html + $(html-alias) + +man/SD_JOURNAL_FOREACH.html: man/sd_journal_next.html + $(html-alias) + +man/SD_JOURNAL_FOREACH_BACKWARDS.html: man/sd_journal_next.html + $(html-alias) + +man/SD_JOURNAL_FOREACH_DATA.html: man/sd_journal_get_data.html + $(html-alias) + +man/SD_JOURNAL_FOREACH_UNIQUE.html: man/sd_journal_query_unique.html + $(html-alias) + +man/SD_JOURNAL_INVALIDATE.html: man/sd_journal_get_fd.html + $(html-alias) + +man/SD_JOURNAL_LOCAL_ONLY.html: man/sd_journal_open.html + $(html-alias) + +man/SD_JOURNAL_NOP.html: man/sd_journal_get_fd.html + $(html-alias) + +man/SD_JOURNAL_RUNTIME_ONLY.html: man/sd_journal_open.html + $(html-alias) + +man/SD_JOURNAL_SUPPRESS_LOCATION.html: man/sd_journal_print.html + $(html-alias) + +man/SD_JOURNAL_SYSTEM.html: man/sd_journal_open.html + $(html-alias) + +man/SD_LISTEN_FDS_START.html: man/sd_listen_fds.html + $(html-alias) + +man/SD_NOTICE.html: man/sd-daemon.html + $(html-alias) + +man/SD_WARNING.html: man/sd-daemon.html + $(html-alias) + +man/init.html: man/systemd.html + $(html-alias) + +man/poweroff.html: man/halt.html + $(html-alias) + +man/reboot.html: man/halt.html + $(html-alias) + +man/sd_id128_equal.html: man/sd-id128.html + $(html-alias) + +man/sd_id128_from_string.html: man/sd_id128_to_string.html + $(html-alias) + +man/sd_id128_get_boot.html: man/sd_id128_get_machine.html + $(html-alias) + +man/sd_id128_t.html: man/sd-id128.html + $(html-alias) + +man/sd_is_mq.html: man/sd_is_fifo.html + $(html-alias) + +man/sd_is_socket.html: man/sd_is_fifo.html + $(html-alias) + +man/sd_is_socket_inet.html: man/sd_is_fifo.html + $(html-alias) + +man/sd_is_socket_unix.html: man/sd_is_fifo.html + $(html-alias) + +man/sd_is_special.html: man/sd_is_fifo.html + $(html-alias) + +man/sd_journal.html: man/sd_journal_open.html + $(html-alias) + +man/sd_journal_add_conjunction.html: man/sd_journal_add_match.html + $(html-alias) + +man/sd_journal_add_disjunction.html: man/sd_journal_add_match.html + $(html-alias) + +man/sd_journal_close.html: man/sd_journal_open.html + $(html-alias) + +man/sd_journal_enumerate_data.html: man/sd_journal_get_data.html + $(html-alias) + +man/sd_journal_enumerate_unique.html: man/sd_journal_query_unique.html + $(html-alias) + +man/sd_journal_flush_matches.html: man/sd_journal_add_match.html + $(html-alias) + +man/sd_journal_get_catalog_for_message_id.html: man/sd_journal_get_catalog.html + $(html-alias) + +man/sd_journal_get_cutoff_monotonic_usec.html: man/sd_journal_get_cutoff_realtime_usec.html + $(html-alias) + +man/sd_journal_get_data_threshold.html: man/sd_journal_get_data.html + $(html-alias) + +man/sd_journal_get_events.html: man/sd_journal_get_fd.html + $(html-alias) + +man/sd_journal_get_monotonic_usec.html: man/sd_journal_get_realtime_usec.html + $(html-alias) + +man/sd_journal_get_timeout.html: man/sd_journal_get_fd.html + $(html-alias) + +man/sd_journal_next_skip.html: man/sd_journal_next.html + $(html-alias) + +man/sd_journal_open_container.html: man/sd_journal_open.html + $(html-alias) + +man/sd_journal_open_directory.html: man/sd_journal_open.html + $(html-alias) + +man/sd_journal_open_files.html: man/sd_journal_open.html + $(html-alias) + +man/sd_journal_perror.html: man/sd_journal_print.html + $(html-alias) + +man/sd_journal_previous.html: man/sd_journal_next.html + $(html-alias) + +man/sd_journal_previous_skip.html: man/sd_journal_next.html + $(html-alias) + +man/sd_journal_printv.html: man/sd_journal_print.html + $(html-alias) + +man/sd_journal_process.html: man/sd_journal_get_fd.html + $(html-alias) + +man/sd_journal_reliable_fd.html: man/sd_journal_get_fd.html + $(html-alias) + +man/sd_journal_restart_data.html: man/sd_journal_get_data.html + $(html-alias) + +man/sd_journal_restart_unique.html: man/sd_journal_query_unique.html + $(html-alias) + +man/sd_journal_seek_cursor.html: man/sd_journal_seek_head.html + $(html-alias) + +man/sd_journal_seek_monotonic_usec.html: man/sd_journal_seek_head.html + $(html-alias) + +man/sd_journal_seek_realtime_usec.html: man/sd_journal_seek_head.html + $(html-alias) + +man/sd_journal_seek_tail.html: man/sd_journal_seek_head.html + $(html-alias) + +man/sd_journal_send.html: man/sd_journal_print.html + $(html-alias) + +man/sd_journal_sendv.html: man/sd_journal_print.html + $(html-alias) + +man/sd_journal_set_data_threshold.html: man/sd_journal_get_data.html + $(html-alias) + +man/sd_journal_test_cursor.html: man/sd_journal_get_cursor.html + $(html-alias) + +man/sd_journal_wait.html: man/sd_journal_get_fd.html + $(html-alias) + +man/sd_notifyf.html: man/sd_notify.html + $(html-alias) + +man/systemd-ask-password-console.path.html: man/systemd-ask-password-console.service.html + $(html-alias) + +man/systemd-ask-password-wall.path.html: man/systemd-ask-password-console.service.html + $(html-alias) + +man/systemd-ask-password-wall.service.html: man/systemd-ask-password-console.service.html + $(html-alias) + +man/systemd-fsck-root.service.html: man/systemd-fsck@.service.html + $(html-alias) + +man/systemd-fsck.html: man/systemd-fsck@.service.html + $(html-alias) + +man/systemd-hibernate.service.html: man/systemd-suspend.service.html + $(html-alias) + +man/systemd-hybrid-sleep.service.html: man/systemd-suspend.service.html + $(html-alias) + +man/systemd-initctl.html: man/systemd-initctl.service.html + $(html-alias) + +man/systemd-initctl.socket.html: man/systemd-initctl.service.html + $(html-alias) + +man/systemd-journald.html: man/systemd-journald.service.html + $(html-alias) + +man/systemd-journald.socket.html: man/systemd-journald.service.html + $(html-alias) + +man/systemd-kexec.service.html: man/systemd-halt.service.html + $(html-alias) + +man/systemd-poweroff.service.html: man/systemd-halt.service.html + $(html-alias) + +man/systemd-reboot.service.html: man/systemd-halt.service.html + $(html-alias) + +man/systemd-remount-fs.html: man/systemd-remount-fs.service.html + $(html-alias) + +man/systemd-shutdown.html: man/systemd-halt.service.html + $(html-alias) + +man/systemd-shutdownd.html: man/systemd-shutdownd.service.html + $(html-alias) + +man/systemd-shutdownd.socket.html: man/systemd-shutdownd.service.html + $(html-alias) + +man/systemd-sleep.html: man/systemd-suspend.service.html + $(html-alias) + +man/systemd-sysctl.html: man/systemd-sysctl.service.html + $(html-alias) + +man/systemd-tmpfiles-clean.service.html: man/systemd-tmpfiles.html + $(html-alias) + +man/systemd-tmpfiles-clean.timer.html: man/systemd-tmpfiles.html + $(html-alias) + +man/systemd-tmpfiles-setup-dev.service.html: man/systemd-tmpfiles.html + $(html-alias) + +man/systemd-tmpfiles-setup.service.html: man/systemd-tmpfiles.html + $(html-alias) + +man/systemd-udevd-control.socket.html: man/systemd-udevd.service.html + $(html-alias) + +man/systemd-udevd-kernel.socket.html: man/systemd-udevd.service.html + $(html-alias) + +man/systemd-udevd.html: man/systemd-udevd.service.html + $(html-alias) + +man/systemd-update-utmp-runlevel.service.html: man/systemd-update-utmp.service.html + $(html-alias) + +man/systemd-update-utmp.html: man/systemd-update-utmp.service.html + $(html-alias) + +man/systemd-user.conf.html: man/systemd-system.conf.html + $(html-alias) + + +if ENABLE_BACKLIGHT +MANPAGES += \ + man/systemd-backlight@.service.8 +MANPAGES_ALIAS += \ + man/systemd-backlight.8 +man/systemd-backlight.8: man/systemd-backlight@.service.8 +man/systemd-backlight.html: man/systemd-backlight@.service.html + $(html-alias) + +endif + +if ENABLE_BINFMT +MANPAGES += \ + man/binfmt.d.5 \ + man/systemd-binfmt.service.8 +MANPAGES_ALIAS += \ + man/systemd-binfmt.8 +man/systemd-binfmt.8: man/systemd-binfmt.service.8 +man/systemd-binfmt.html: man/systemd-binfmt.service.html + $(html-alias) + +endif + +if ENABLE_BOOTCHART +MANPAGES += \ + man/bootchart.conf.5 \ + man/systemd-bootchart.1 +MANPAGES_ALIAS += \ + # + + +endif + +if ENABLE_COREDUMP +MANPAGES += \ + man/systemd-coredumpctl.1 +MANPAGES_ALIAS += \ + # + + +endif + +if ENABLE_EFI +MANPAGES += \ + man/bootctl.1 +MANPAGES_ALIAS += \ + # + + +endif + +if ENABLE_HOSTNAMED +MANPAGES += \ + man/hostnamectl.1 \ + man/systemd-hostnamed.service.8 +MANPAGES_ALIAS += \ + man/systemd-hostnamed.8 +man/systemd-hostnamed.8: man/systemd-hostnamed.service.8 +man/systemd-hostnamed.html: man/systemd-hostnamed.service.html + $(html-alias) + +endif + +if ENABLE_KDBUS +MANPAGES += \ + man/sd_bus_creds_get_pid.3 \ + man/sd_bus_creds_new_from_pid.3 \ + man/sd_bus_error.3 \ + man/sd_bus_label_escape.3 \ + man/sd_bus_message_get_cookie.3 \ + man/sd_bus_message_get_monotonic_usec.3 \ + man/sd_bus_new.3 \ + man/sd_bus_open_user.3 \ + man/sd_bus_request_name.3 \ + man/systemd-bus-proxyd.8 \ + man/systemd-bus-proxyd@.service.8 +MANPAGES_ALIAS += \ + man/sd_bus_creds_get_audit_login_uid.3 \ + man/sd_bus_creds_get_audit_session_id.3 \ + man/sd_bus_creds_get_cgroup.3 \ + man/sd_bus_creds_get_cmdline.3 \ + man/sd_bus_creds_get_comm.3 \ + man/sd_bus_creds_get_exe.3 \ + man/sd_bus_creds_get_gid.3 \ + man/sd_bus_creds_get_mask.3 \ + man/sd_bus_creds_get_owner_uid.3 \ + man/sd_bus_creds_get_pid_starttime.3 \ + man/sd_bus_creds_get_selinux_context.3 \ + man/sd_bus_creds_get_session.3 \ + man/sd_bus_creds_get_slice.3 \ + man/sd_bus_creds_get_tid.3 \ + man/sd_bus_creds_get_tid_comm.3 \ + man/sd_bus_creds_get_uid.3 \ + man/sd_bus_creds_get_unique_name.3 \ + man/sd_bus_creds_get_unit.3 \ + man/sd_bus_creds_get_user_unit.3 \ + man/sd_bus_creds_get_well_known_names.3 \ + man/sd_bus_creds_has_bounding_cap.3 \ + man/sd_bus_creds_has_effective_cap.3 \ + man/sd_bus_creds_has_inheritable_cap.3 \ + man/sd_bus_creds_has_permitted_cap.3 \ + man/sd_bus_creds_ref.3 \ + man/sd_bus_creds_unref.3 \ + man/sd_bus_default_system.3 \ + man/sd_bus_default_user.3 \ + man/sd_bus_error_copy.3 \ + man/sd_bus_error_free.3 \ + man/sd_bus_error_get_errno.3 \ + man/sd_bus_error_has_name.3 \ + man/sd_bus_error_is_set.3 \ + man/sd_bus_error_set.3 \ + man/sd_bus_error_set_const.3 \ + man/sd_bus_error_set_errno.3 \ + man/sd_bus_error_set_errnof.3 \ + man/sd_bus_label_unescape.3 \ + man/sd_bus_message_get_realtime_usec.3 \ + man/sd_bus_message_get_reply_cookie.3 \ + man/sd_bus_message_get_seqnum.3 \ + man/sd_bus_open_system.3 \ + man/sd_bus_open_system_container.3 \ + man/sd_bus_open_system_remote.3 \ + man/sd_bus_ref.3 \ + man/sd_bus_release_name.3 \ + man/sd_bus_unref.3 \ + man/systemd-bus-proxyd.socket.8 +man/sd_bus_creds_get_audit_login_uid.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_audit_session_id.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_cgroup.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_cmdline.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_comm.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_exe.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_gid.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_mask.3: man/sd_bus_creds_new_from_pid.3 +man/sd_bus_creds_get_owner_uid.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_pid_starttime.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_selinux_context.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_session.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_slice.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_tid.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_tid_comm.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_uid.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_unique_name.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_unit.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_user_unit.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_get_well_known_names.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_has_bounding_cap.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_has_effective_cap.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_has_inheritable_cap.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_has_permitted_cap.3: man/sd_bus_creds_get_pid.3 +man/sd_bus_creds_ref.3: man/sd_bus_creds_new_from_pid.3 +man/sd_bus_creds_unref.3: man/sd_bus_creds_new_from_pid.3 +man/sd_bus_default_system.3: man/sd_bus_open_user.3 +man/sd_bus_default_user.3: man/sd_bus_open_user.3 +man/sd_bus_error_copy.3: man/sd_bus_error.3 +man/sd_bus_error_free.3: man/sd_bus_error.3 +man/sd_bus_error_get_errno.3: man/sd_bus_error.3 +man/sd_bus_error_has_name.3: man/sd_bus_error.3 +man/sd_bus_error_is_set.3: man/sd_bus_error.3 +man/sd_bus_error_set.3: man/sd_bus_error.3 +man/sd_bus_error_set_const.3: man/sd_bus_error.3 +man/sd_bus_error_set_errno.3: man/sd_bus_error.3 +man/sd_bus_error_set_errnof.3: man/sd_bus_error.3 +man/sd_bus_label_unescape.3: man/sd_bus_label_escape.3 +man/sd_bus_message_get_realtime_usec.3: man/sd_bus_message_get_monotonic_usec.3 +man/sd_bus_message_get_reply_cookie.3: man/sd_bus_message_get_cookie.3 +man/sd_bus_message_get_seqnum.3: man/sd_bus_message_get_monotonic_usec.3 +man/sd_bus_open_system.3: man/sd_bus_open_user.3 +man/sd_bus_open_system_container.3: man/sd_bus_open_user.3 +man/sd_bus_open_system_remote.3: man/sd_bus_open_user.3 +man/sd_bus_ref.3: man/sd_bus_new.3 +man/sd_bus_release_name.3: man/sd_bus_request_name.3 +man/sd_bus_unref.3: man/sd_bus_new.3 +man/systemd-bus-proxyd.socket.8: man/systemd-bus-proxyd@.service.8 +man/sd_bus_creds_get_audit_login_uid.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_audit_session_id.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_cgroup.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_cmdline.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_comm.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_exe.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_gid.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_mask.html: man/sd_bus_creds_new_from_pid.html + $(html-alias) + +man/sd_bus_creds_get_owner_uid.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_pid_starttime.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_selinux_context.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_session.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_slice.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_tid.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_tid_comm.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_uid.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_unique_name.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_unit.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_user_unit.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_get_well_known_names.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_has_bounding_cap.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_has_effective_cap.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_has_inheritable_cap.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_has_permitted_cap.html: man/sd_bus_creds_get_pid.html + $(html-alias) + +man/sd_bus_creds_ref.html: man/sd_bus_creds_new_from_pid.html + $(html-alias) + +man/sd_bus_creds_unref.html: man/sd_bus_creds_new_from_pid.html + $(html-alias) + +man/sd_bus_default_system.html: man/sd_bus_open_user.html + $(html-alias) + +man/sd_bus_default_user.html: man/sd_bus_open_user.html + $(html-alias) + +man/sd_bus_error_copy.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_free.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_get_errno.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_has_name.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_is_set.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_set.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_set_const.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_set_errno.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_error_set_errnof.html: man/sd_bus_error.html + $(html-alias) + +man/sd_bus_label_unescape.html: man/sd_bus_label_escape.html + $(html-alias) + +man/sd_bus_message_get_realtime_usec.html: man/sd_bus_message_get_monotonic_usec.html + $(html-alias) + +man/sd_bus_message_get_reply_cookie.html: man/sd_bus_message_get_cookie.html + $(html-alias) + +man/sd_bus_message_get_seqnum.html: man/sd_bus_message_get_monotonic_usec.html + $(html-alias) + +man/sd_bus_open_system.html: man/sd_bus_open_user.html + $(html-alias) + +man/sd_bus_open_system_container.html: man/sd_bus_open_user.html + $(html-alias) + +man/sd_bus_open_system_remote.html: man/sd_bus_open_user.html + $(html-alias) + +man/sd_bus_ref.html: man/sd_bus_new.html + $(html-alias) + +man/sd_bus_release_name.html: man/sd_bus_request_name.html + $(html-alias) + +man/sd_bus_unref.html: man/sd_bus_new.html + $(html-alias) + +man/systemd-bus-proxyd.socket.html: man/systemd-bus-proxyd@.service.html + $(html-alias) + +endif + +if ENABLE_LOCALED +MANPAGES += \ + man/localectl.1 \ + man/systemd-localed.service.8 +MANPAGES_ALIAS += \ + man/systemd-localed.8 +man/systemd-localed.8: man/systemd-localed.service.8 +man/systemd-localed.html: man/systemd-localed.service.html + $(html-alias) + +endif + +if ENABLE_LOGIND +MANPAGES += \ + man/loginctl.1 \ + man/logind.conf.5 \ + man/systemd-logind.service.8 +MANPAGES_ALIAS += \ + man/systemd-logind.8 +man/systemd-logind.8: man/systemd-logind.service.8 +man/systemd-logind.html: man/systemd-logind.service.html + $(html-alias) + +endif + +if ENABLE_MACHINED +MANPAGES += \ + man/machinectl.1 \ + man/systemd-machined.service.8 +MANPAGES_ALIAS += \ + man/systemd-machined.8 +man/systemd-machined.8: man/systemd-machined.service.8 +man/systemd-machined.html: man/systemd-machined.service.html + $(html-alias) + +endif + +if ENABLE_NETWORKD +MANPAGES += \ + man/systemd-networkd.service.8 +MANPAGES_ALIAS += \ + man/systemd-networkd.8 +man/systemd-networkd.8: man/systemd-networkd.service.8 +man/systemd-networkd.html: man/systemd-networkd.service.html + $(html-alias) + +endif + +if ENABLE_QUOTACHECK +MANPAGES += \ + man/systemd-quotacheck.service.8 +MANPAGES_ALIAS += \ + man/systemd-quotacheck.8 +man/systemd-quotacheck.8: man/systemd-quotacheck.service.8 +man/systemd-quotacheck.html: man/systemd-quotacheck.service.html + $(html-alias) + +endif + +if ENABLE_RANDOMSEED +MANPAGES += \ + man/systemd-random-seed.service.8 +MANPAGES_ALIAS += \ + man/systemd-random-seed.8 +man/systemd-random-seed.8: man/systemd-random-seed.service.8 +man/systemd-random-seed.html: man/systemd-random-seed.service.html + $(html-alias) + +endif + +if ENABLE_READAHEAD +MANPAGES += \ + man/sd-readahead.3 \ + man/sd_readahead.3 \ + man/systemd-readahead-replay.service.8 +MANPAGES_ALIAS += \ + man/systemd-readahead-collect.service.8 \ + man/systemd-readahead-done.service.8 \ + man/systemd-readahead-done.timer.8 \ + man/systemd-readahead.8 +man/systemd-readahead-collect.service.8: man/systemd-readahead-replay.service.8 +man/systemd-readahead-done.service.8: man/systemd-readahead-replay.service.8 +man/systemd-readahead-done.timer.8: man/systemd-readahead-replay.service.8 +man/systemd-readahead.8: man/systemd-readahead-replay.service.8 +man/systemd-readahead-collect.service.html: man/systemd-readahead-replay.service.html + $(html-alias) + +man/systemd-readahead-done.service.html: man/systemd-readahead-replay.service.html + $(html-alias) + +man/systemd-readahead-done.timer.html: man/systemd-readahead-replay.service.html + $(html-alias) + +man/systemd-readahead.html: man/systemd-readahead-replay.service.html + $(html-alias) + +endif + +if ENABLE_RFKILL +MANPAGES += \ + man/systemd-rfkill@.service.8 +MANPAGES_ALIAS += \ + man/systemd-rfkill.8 +man/systemd-rfkill.8: man/systemd-rfkill@.service.8 +man/systemd-rfkill.html: man/systemd-rfkill@.service.html + $(html-alias) + +endif + +if ENABLE_TIMEDATED +MANPAGES += \ + man/systemd-timedated.service.8 \ + man/timedatectl.1 +MANPAGES_ALIAS += \ + man/systemd-timedated.8 +man/systemd-timedated.8: man/systemd-timedated.service.8 +man/systemd-timedated.html: man/systemd-timedated.service.html + $(html-alias) + +endif + +if ENABLE_VCONSOLE +MANPAGES += \ + man/systemd-vconsole-setup.service.8 \ + man/vconsole.conf.5 +MANPAGES_ALIAS += \ + man/systemd-vconsole-setup.8 +man/systemd-vconsole-setup.8: man/systemd-vconsole-setup.service.8 +man/systemd-vconsole-setup.html: man/systemd-vconsole-setup.service.html + $(html-alias) + +endif + +if HAVE_KMOD +MANPAGES += \ + man/modules-load.d.5 \ + man/systemd-modules-load.service.8 +MANPAGES_ALIAS += \ + man/systemd-modules-load.8 +man/systemd-modules-load.8: man/systemd-modules-load.service.8 +man/systemd-modules-load.html: man/systemd-modules-load.service.html + $(html-alias) + +endif + +if HAVE_LIBCRYPTSETUP +MANPAGES += \ + man/crypttab.5 \ + man/systemd-cryptsetup-generator.8 \ + man/systemd-cryptsetup@.service.8 +MANPAGES_ALIAS += \ + man/systemd-cryptsetup.8 +man/systemd-cryptsetup.8: man/systemd-cryptsetup@.service.8 +man/systemd-cryptsetup.html: man/systemd-cryptsetup@.service.html + $(html-alias) + +endif + +if HAVE_MICROHTTPD +MANPAGES += \ + man/systemd-journal-gatewayd.service.8 +MANPAGES_ALIAS += \ + man/systemd-journal-gatewayd.8 \ + man/systemd-journal-gatewayd.socket.8 +man/systemd-journal-gatewayd.8: man/systemd-journal-gatewayd.service.8 +man/systemd-journal-gatewayd.socket.8: man/systemd-journal-gatewayd.service.8 +man/systemd-journal-gatewayd.html: man/systemd-journal-gatewayd.service.html + $(html-alias) + +man/systemd-journal-gatewayd.socket.html: man/systemd-journal-gatewayd.service.html + $(html-alias) + +endif + +if HAVE_MYHOSTNAME +MANPAGES += \ + man/nss-myhostname.8 +MANPAGES_ALIAS += \ + # + + +endif + +if HAVE_PAM +MANPAGES += \ + man/pam_systemd.8 \ + man/sd-login.3 \ + man/sd_get_seats.3 \ + man/sd_login_monitor_new.3 \ + man/sd_pid_get_session.3 \ + man/sd_seat_get_active.3 \ + man/sd_session_is_active.3 \ + man/sd_uid_get_state.3 \ + man/systemd-user-sessions.service.8 +MANPAGES_ALIAS += \ + man/sd_get_machine_names.3 \ + man/sd_get_sessions.3 \ + man/sd_get_uids.3 \ + man/sd_login_monitor.3 \ + man/sd_login_monitor_flush.3 \ + man/sd_login_monitor_get_events.3 \ + man/sd_login_monitor_get_fd.3 \ + man/sd_login_monitor_get_timeout.3 \ + man/sd_login_monitor_unref.3 \ + man/sd_pid_get_machine_name.3 \ + man/sd_pid_get_owner_uid.3 \ + man/sd_pid_get_slice.3 \ + man/sd_pid_get_unit.3 \ + man/sd_pid_get_user_unit.3 \ + man/sd_seat_can_graphical.3 \ + man/sd_seat_can_multi_session.3 \ + man/sd_seat_can_tty.3 \ + man/sd_seat_get_sessions.3 \ + man/sd_session_get_class.3 \ + man/sd_session_get_display.3 \ + man/sd_session_get_remote_host.3 \ + man/sd_session_get_remote_user.3 \ + man/sd_session_get_seat.3 \ + man/sd_session_get_service.3 \ + man/sd_session_get_state.3 \ + man/sd_session_get_tty.3 \ + man/sd_session_get_type.3 \ + man/sd_session_get_uid.3 \ + man/sd_session_get_vt.3 \ + man/sd_session_is_remote.3 \ + man/sd_uid_get_seats.3 \ + man/sd_uid_get_sessions.3 \ + man/sd_uid_is_on_seat.3 \ + man/systemd-user-sessions.8 +man/sd_get_machine_names.3: man/sd_get_seats.3 +man/sd_get_sessions.3: man/sd_get_seats.3 +man/sd_get_uids.3: man/sd_get_seats.3 +man/sd_login_monitor.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_flush.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_get_events.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_get_timeout.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_unref.3: man/sd_login_monitor_new.3 +man/sd_pid_get_machine_name.3: man/sd_pid_get_session.3 +man/sd_pid_get_owner_uid.3: man/sd_pid_get_session.3 +man/sd_pid_get_slice.3: man/sd_pid_get_session.3 +man/sd_pid_get_unit.3: man/sd_pid_get_session.3 +man/sd_pid_get_user_unit.3: man/sd_pid_get_session.3 +man/sd_seat_can_graphical.3: man/sd_seat_get_active.3 +man/sd_seat_can_multi_session.3: man/sd_seat_get_active.3 +man/sd_seat_can_tty.3: man/sd_seat_get_active.3 +man/sd_seat_get_sessions.3: man/sd_seat_get_active.3 +man/sd_session_get_class.3: man/sd_session_is_active.3 +man/sd_session_get_display.3: man/sd_session_is_active.3 +man/sd_session_get_remote_host.3: man/sd_session_is_active.3 +man/sd_session_get_remote_user.3: man/sd_session_is_active.3 +man/sd_session_get_seat.3: man/sd_session_is_active.3 +man/sd_session_get_service.3: man/sd_session_is_active.3 +man/sd_session_get_state.3: man/sd_session_is_active.3 +man/sd_session_get_tty.3: man/sd_session_is_active.3 +man/sd_session_get_type.3: man/sd_session_is_active.3 +man/sd_session_get_uid.3: man/sd_session_is_active.3 +man/sd_session_get_vt.3: man/sd_session_is_active.3 +man/sd_session_is_remote.3: man/sd_session_is_active.3 +man/sd_uid_get_seats.3: man/sd_uid_get_state.3 +man/sd_uid_get_sessions.3: man/sd_uid_get_state.3 +man/sd_uid_is_on_seat.3: man/sd_uid_get_state.3 +man/systemd-user-sessions.8: man/systemd-user-sessions.service.8 +man/sd_get_machine_names.html: man/sd_get_seats.html + $(html-alias) + +man/sd_get_sessions.html: man/sd_get_seats.html + $(html-alias) + +man/sd_get_uids.html: man/sd_get_seats.html + $(html-alias) + +man/sd_login_monitor.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_login_monitor_flush.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_login_monitor_get_events.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_login_monitor_get_fd.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_login_monitor_get_timeout.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_login_monitor_unref.html: man/sd_login_monitor_new.html + $(html-alias) + +man/sd_pid_get_machine_name.html: man/sd_pid_get_session.html + $(html-alias) + +man/sd_pid_get_owner_uid.html: man/sd_pid_get_session.html + $(html-alias) + +man/sd_pid_get_slice.html: man/sd_pid_get_session.html + $(html-alias) + +man/sd_pid_get_unit.html: man/sd_pid_get_session.html + $(html-alias) + +man/sd_pid_get_user_unit.html: man/sd_pid_get_session.html + $(html-alias) + +man/sd_seat_can_graphical.html: man/sd_seat_get_active.html + $(html-alias) + +man/sd_seat_can_multi_session.html: man/sd_seat_get_active.html + $(html-alias) + +man/sd_seat_can_tty.html: man/sd_seat_get_active.html + $(html-alias) + +man/sd_seat_get_sessions.html: man/sd_seat_get_active.html + $(html-alias) + +man/sd_session_get_class.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_display.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_remote_host.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_remote_user.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_seat.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_service.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_state.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_tty.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_type.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_uid.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_get_vt.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_session_is_remote.html: man/sd_session_is_active.html + $(html-alias) + +man/sd_uid_get_seats.html: man/sd_uid_get_state.html + $(html-alias) + +man/sd_uid_get_sessions.html: man/sd_uid_get_state.html + $(html-alias) + +man/sd_uid_is_on_seat.html: man/sd_uid_get_state.html + $(html-alias) + +man/systemd-user-sessions.html: man/systemd-user-sessions.service.html + $(html-alias) + +endif + +if HAVE_PYTHON +MANPAGES += \ + man/systemd.directives.7 \ + man/systemd.index.7 +MANPAGES_ALIAS += \ + # + + +endif + +EXTRA_DIST += \ + man/binfmt.d.xml \ + man/bootchart.conf.xml \ + man/bootctl.xml \ + man/bootup.xml \ + man/busctl.xml \ + man/crypttab.xml \ + man/daemon.xml \ + man/halt.xml \ + man/hostname.xml \ + man/hostnamectl.xml \ + man/journalctl.xml \ + man/journald.conf.xml \ + man/kernel-command-line.xml \ + man/kernel-install.xml \ + man/less-variables.xml \ + man/libsystemd-pkgconfig.xml \ + man/locale.conf.xml \ + man/localectl.xml \ + man/localtime.xml \ + man/loginctl.xml \ + man/logind.conf.xml \ + man/machine-id.xml \ + man/machine-info.xml \ + man/machinectl.xml \ + man/modules-load.d.xml \ + man/nss-myhostname.xml \ + man/os-release.xml \ + man/pam_systemd.xml \ + man/runlevel.xml \ + man/sd-daemon.xml \ + man/sd-id128.xml \ + man/sd-journal.xml \ + man/sd-login.xml \ + man/sd-readahead.xml \ + man/sd_booted.xml \ + man/sd_bus_creds_get_pid.xml \ + man/sd_bus_creds_new_from_pid.xml \ + man/sd_bus_error.xml \ + man/sd_bus_label_escape.xml \ + man/sd_bus_message_get_cookie.xml \ + man/sd_bus_message_get_monotonic_usec.xml \ + man/sd_bus_new.xml \ + man/sd_bus_open_user.xml \ + man/sd_bus_request_name.xml \ + man/sd_get_seats.xml \ + man/sd_id128_get_machine.xml \ + man/sd_id128_randomize.xml \ + man/sd_id128_to_string.xml \ + man/sd_is_fifo.xml \ + man/sd_journal_add_match.xml \ + man/sd_journal_get_catalog.xml \ + man/sd_journal_get_cursor.xml \ + man/sd_journal_get_cutoff_realtime_usec.xml \ + man/sd_journal_get_data.xml \ + man/sd_journal_get_fd.xml \ + man/sd_journal_get_realtime_usec.xml \ + man/sd_journal_get_usage.xml \ + man/sd_journal_next.xml \ + man/sd_journal_open.xml \ + man/sd_journal_print.xml \ + man/sd_journal_query_unique.xml \ + man/sd_journal_seek_head.xml \ + man/sd_journal_stream_fd.xml \ + man/sd_listen_fds.xml \ + man/sd_login_monitor_new.xml \ + man/sd_notify.xml \ + man/sd_pid_get_session.xml \ + man/sd_readahead.xml \ + man/sd_seat_get_active.xml \ + man/sd_session_is_active.xml \ + man/sd_uid_get_state.xml \ + man/sd_watchdog_enabled.xml \ + man/shutdown.xml \ + man/standard-options.xml \ + man/sysctl.d.xml \ + man/systemctl.xml \ + man/systemd-activate.xml \ + man/systemd-analyze.xml \ + man/systemd-ask-password-console.service.xml \ + man/systemd-ask-password.xml \ + man/systemd-backlight@.service.xml \ + man/systemd-binfmt.service.xml \ + man/systemd-bootchart.xml \ + man/systemd-bus-proxyd.xml \ + man/systemd-bus-proxyd@.service.xml \ + man/systemd-cat.xml \ + man/systemd-cgls.xml \ + man/systemd-cgtop.xml \ + man/systemd-coredumpctl.xml \ + man/systemd-cryptsetup-generator.xml \ + man/systemd-cryptsetup@.service.xml \ + man/systemd-delta.xml \ + man/systemd-detect-virt.xml \ + man/systemd-efi-boot-generator.xml \ + man/systemd-fsck@.service.xml \ + man/systemd-fstab-generator.xml \ + man/systemd-getty-generator.xml \ + man/systemd-gpt-auto-generator.xml \ + man/systemd-halt.service.xml \ + man/systemd-hostnamed.service.xml \ + man/systemd-inhibit.xml \ + man/systemd-initctl.service.xml \ + man/systemd-journal-gatewayd.service.xml \ + man/systemd-journald.service.xml \ + man/systemd-localed.service.xml \ + man/systemd-logind.service.xml \ + man/systemd-machine-id-setup.xml \ + man/systemd-machined.service.xml \ + man/systemd-modules-load.service.xml \ + man/systemd-networkd.service.xml \ + man/systemd-notify.xml \ + man/systemd-nspawn.xml \ + man/systemd-quotacheck.service.xml \ + man/systemd-random-seed.service.xml \ + man/systemd-readahead-replay.service.xml \ + man/systemd-remount-fs.service.xml \ + man/systemd-rfkill@.service.xml \ + man/systemd-run.xml \ + man/systemd-shutdownd.service.xml \ + man/systemd-sleep.conf.xml \ + man/systemd-socket-proxyd.xml \ + man/systemd-suspend.service.xml \ + man/systemd-sysctl.service.xml \ + man/systemd-system-update-generator.xml \ + man/systemd-system.conf.xml \ + man/systemd-timedated.service.xml \ + man/systemd-tmpfiles.xml \ + man/systemd-tty-ask-password-agent.xml \ + man/systemd-udevd.service.xml \ + man/systemd-update-utmp.service.xml \ + man/systemd-user-sessions.service.xml \ + man/systemd-vconsole-setup.service.xml \ + man/systemd.automount.xml \ + man/systemd.device.xml \ + man/systemd.directives.xml \ + man/systemd.exec.xml \ + man/systemd.index.xml \ + man/systemd.journal-fields.xml \ + man/systemd.kill.xml \ + man/systemd.mount.xml \ + man/systemd.path.xml \ + man/systemd.preset.xml \ + man/systemd.resource-control.xml \ + man/systemd.scope.xml \ + man/systemd.service.xml \ + man/systemd.slice.xml \ + man/systemd.snapshot.xml \ + man/systemd.socket.xml \ + man/systemd.special.xml \ + man/systemd.swap.xml \ + man/systemd.target.xml \ + man/systemd.time.xml \ + man/systemd.timer.xml \ + man/systemd.unit.xml \ + man/systemd.xml \ + man/telinit.xml \ + man/timedatectl.xml \ + man/tmpfiles.d.xml \ + man/udev.xml \ + man/udevadm.xml \ + man/user-system-options.xml \ + man/vconsole.conf.xml diff --git a/Makefile.am b/Makefile.am index 1f29a92..529b525 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,330 +1,376 @@ +# -*- Mode: makefile; indent-tabs-mode: t -*- +# # This file is part of systemd. # -# Copyright 2010 Lennart Poettering +# Copyright 2010-2012 Lennart Poettering +# Copyright 2010-2012 Kay Sievers +# Copyright 2013 Zbigniew Jędrzejewski-Szmek +# Copyright 2013 David Strauss # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. +# Lesser General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . -ACLOCAL_AMFLAGS = -I m4 +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} +AM_MAKEFLAGS = --no-print-directory +AUTOMAKE_OPTIONS = color-tests parallel-tests + +SUBDIRS = . po + +# remove targets if the command fails +.DELETE_ON_ERROR: + +# keep intermediate files +.SECONDARY: -SUBDIRS = po +# Keep the test-suite.log +.PRECIOUS: $(TEST_SUITE_LOG) Makefile -LIBSYSTEMD_LOGIN_CURRENT=0 -LIBSYSTEMD_LOGIN_REVISION=6 -LIBSYSTEMD_LOGIN_AGE=0 +LIBUDEV_CURRENT=5 +LIBUDEV_REVISION=0 +LIBUDEV_AGE=4 + +LIBGUDEV_CURRENT=2 +LIBGUDEV_REVISION=0 +LIBGUDEV_AGE=2 + +LIBSYSTEMD_LOGIN_CURRENT=9 +LIBSYSTEMD_LOGIN_REVISION=3 +LIBSYSTEMD_LOGIN_AGE=9 LIBSYSTEMD_DAEMON_CURRENT=0 -LIBSYSTEMD_DAEMON_REVISION=0 +LIBSYSTEMD_DAEMON_REVISION=12 LIBSYSTEMD_DAEMON_AGE=0 +LIBSYSTEMD_ID128_CURRENT=0 +LIBSYSTEMD_ID128_REVISION=28 +LIBSYSTEMD_ID128_AGE=0 + +LIBSYSTEMD_JOURNAL_CURRENT=11 +LIBSYSTEMD_JOURNAL_REVISION=5 +LIBSYSTEMD_JOURNAL_AGE=11 + +LIBSYSTEMD_CURRENT=0 +LIBSYSTEMD_REVISION=1 +LIBSYSTEMD_AGE=0 + # Dirs of external packages dbuspolicydir=@dbuspolicydir@ dbussessionservicedir=@dbussessionservicedir@ dbussystemservicedir=@dbussystemservicedir@ -dbusinterfacedir=@dbusinterfacedir@ -udevrulesdir=@udevrulesdir@ pamlibdir=@pamlibdir@ +pamconfdir=@pamconfdir@ pkgconfigdatadir=$(datadir)/pkgconfig pkgconfiglibdir=$(libdir)/pkgconfig polkitpolicydir=$(datadir)/polkit-1/actions -bashcompletiondir=$(sysconfdir)/bash_completion.d +bashcompletiondir=@bashcompletiondir@ +zshcompletiondir=@zshcompletiondir@ +rpmmacrosdir=$(prefix)/lib/rpm/macros.d +sysvinitdir=$(SYSTEM_SYSVINIT_PATH) +sysvrcnddir=$(SYSTEM_SYSVRCND_PATH) +varlogdir=$(localstatedir)/log +systemdstatedir=$(localstatedir)/lib/systemd +catalogstatedir=$(systemdstatedir)/catalog # Our own, non-special dirs pkgsysconfdir=$(sysconfdir)/systemd userunitdir=$(prefix)/lib/systemd/user +userpresetdir=$(prefix)/lib/systemd/user-preset tmpfilesdir=$(prefix)/lib/tmpfiles.d -usergeneratordir=$(pkglibexecdir)/user-generators +sysctldir=$(prefix)/lib/sysctl.d +networkdir=$(rootprefix)/lib/systemd/network pkgincludedir=$(includedir)/systemd - -# And these are the special ones for / -rootdir=@rootdir@ -rootbindir=$(rootdir)/bin -rootlibexecdir=$(rootdir)/lib/systemd systemgeneratordir=$(rootlibexecdir)/system-generators +usergeneratordir=$(prefix)/lib/systemd/user-generators systemshutdowndir=$(rootlibexecdir)/system-shutdown -systemunitdir=$(rootdir)/lib/systemd/system +systemsleepdir=$(rootlibexecdir)/system-sleep +systemunitdir=$(rootprefix)/lib/systemd/system +systempresetdir=$(rootprefix)/lib/systemd/system-preset +udevlibexecdir=$(rootprefix)/lib/udev +udevhomedir=$(udevlibexecdir) +udevrulesdir=$(udevlibexecdir)/rules.d +udevhwdbdir=$(udevlibexecdir)/hwdb.d +catalogdir=$(prefix)/lib/systemd/catalog +kernelinstalldir = $(prefix)/lib/kernel/install.d + +# And these are the special ones for / +rootprefix=@rootprefix@ +rootbindir=$(rootprefix)/bin +rootlibexecdir=$(rootprefix)/lib/systemd + +CLEANFILES = $(BUILT_SOURCES) +DISTCLEANFILES = +EXTRA_DIST = +BUILT_SOURCES = +INSTALL_EXEC_HOOKS = +UNINSTALL_EXEC_HOOKS = +INSTALL_DATA_HOOKS = +UNINSTALL_DATA_HOOKS = +DISTCLEAN_LOCAL_HOOKS = +CLEAN_LOCAL_HOOKS = +pkginclude_HEADERS = +noinst_LTLIBRARIES = +lib_LTLIBRARIES = +include_HEADERS = +noinst_DATA = +pkgconfiglib_DATA = +polkitpolicy_in_in_files = +polkitpolicy_in_files = +polkitpolicy_files = +dist_udevrules_DATA = +nodist_udevrules_DATA = +dist_pkgsysconf_DATA = +dist_pkgdata_DATA = +dist_dbuspolicy_DATA = +dist_dbussystemservice_DATA = +check_PROGRAMS = +check_DATA = +tests= +manual_tests = +if ENABLE_TESTS +noinst_PROGRAMS = $(manual_tests) $(tests) +TESTS = $(tests) +else +noinst_PROGRAMS = +TESTS = +endif +udevlibexec_PROGRAMS = + +.PHONY: $(INSTALL_EXEC_HOOKS) $(UNINSTALL_EXEC_HOOKS) \ + $(INSTALL_DATA_HOOKS) $(UNINSTALL_DATA_HOOKS) \ + $(DISTCLEAN_LOCAL_HOOKS) $(CLEAN_LOCAL_HOOKS) AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ - -DSYSTEM_CONFIG_FILE=\"$(pkgsysconfdir)/system.conf\" \ + -DPKGSYSCONFDIR=\"$(pkgsysconfdir)\" \ -DSYSTEM_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/system\" \ -DSYSTEM_DATA_UNIT_PATH=\"$(systemunitdir)\" \ -DSYSTEM_SYSVINIT_PATH=\"$(SYSTEM_SYSVINIT_PATH)\" \ -DSYSTEM_SYSVRCND_PATH=\"$(SYSTEM_SYSVRCND_PATH)\" \ - -DUSER_CONFIG_FILE=\"$(pkgsysconfdir)/user.conf\" \ -DUSER_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/user\" \ -DUSER_DATA_UNIT_PATH=\"$(userunitdir)\" \ + -DCATALOG_DATABASE=\"$(catalogstatedir)/database\" \ -DSYSTEMD_CGROUP_AGENT_PATH=\"$(rootlibexecdir)/systemd-cgroups-agent\" \ - -DSYSTEMD_BINARY_PATH=\"$(rootbindir)/systemd\" \ + -DSYSTEMD_BINARY_PATH=\"$(rootlibexecdir)/systemd\" \ -DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \ + -DSYSTEMD_SLEEP_BINARY_PATH=\"$(rootlibexecdir)/systemd-sleep\" \ -DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \ -DSYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH=\"$(rootbindir)/systemd-tty-ask-password-agent\" \ -DSYSTEMD_STDIO_BRIDGE_BINARY_PATH=\"$(bindir)/systemd-stdio-bridge\" \ - -DRUNTIME_DIR=\"/run\" \ - -DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \ + -DROOTPREFIX=\"$(rootprefix)\" \ + -DRANDOM_SEED_DIR=\"$(localstatedir)/lib/systemd/\" \ + -DRANDOM_SEED=\"$(localstatedir)/lib/systemd/random-seed\" \ -DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \ -DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \ -DUSER_GENERATOR_PATH=\"$(usergeneratordir)\" \ -DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \ - -DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \ - -I $(top_srcdir)/src - -if TARGET_GENTOO -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/usr/bin/loadkeys\" \ - -DKBD_SETFONT=\"/usr/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -if TARGET_ARCH -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/usr/bin/loadkeys\" \ - -DKBD_SETFONT=\"/usr/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -if TARGET_FRUGALWARE -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/usr/bin/loadkeys\" \ - -DKBD_SETFONT=\"/usr/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -if TARGET_MANDRIVA -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/bin/loadkeys\" \ - -DKBD_SETFONT=\"/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -if TARGET_MEEGO -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/bin/loadkeys\" \ - -DKBD_SETFONT=\"/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -if TARGET_ANGSTROM -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/usr/bin/loadkeys\" \ - -DKBD_SETFONT=\"/usr/bin/setfont\" \ - -DDEFAULT_FONT=\"LatArCyrHeb-16\" -else -AM_CPPFLAGS += \ - -DKBD_LOADKEYS=\"/bin/loadkeys\" \ - -DKBD_SETFONT=\"/bin/setfont\" \ - -DDEFAULT_FONT=\"latarcyrheb-sun16\" -endif -endif -endif -endif -endif -endif - + -DSYSTEM_SLEEP_PATH=\"$(systemsleepdir)\" \ + -DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \ + -DX_SERVER=\"$(bindir)/X\" \ + -DUDEVLIBEXECDIR=\"$(udevlibexecdir)\" \ + -DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \ + -DQUOTACHECK=\"$(QUOTACHECK)\" \ + -DKEXEC=\"$(KEXEC)\" \ + -I $(top_srcdir)/src \ + -I $(top_builddir)/src/shared \ + -I $(top_srcdir)/src/shared \ + -I $(top_srcdir)/src/network \ + -I $(top_srcdir)/src/login \ + -I $(top_srcdir)/src/journal \ + -I $(top_srcdir)/src/systemd \ + -I $(top_builddir)/src/core \ + -I $(top_srcdir)/src/core \ + -I $(top_srcdir)/src/libudev \ + -I $(top_srcdir)/src/udev \ + -I $(top_srcdir)/src/udev/net \ + -I $(top_builddir)/src/udev \ + -I $(top_srcdir)/src/libsystemd/sd-bus \ + -I $(top_srcdir)/src/libsystemd/sd-event \ + -I $(top_srcdir)/src/libsystemd/sd-rtnl \ + $(OUR_CPPFLAGS) + +AM_CFLAGS = $(OUR_CFLAGS) +AM_LDFLAGS = $(OUR_LDFLAGS) + +# ------------------------------------------------------------------------------ +define move-to-rootlibdir + if test "$(libdir)" != "$(rootlibdir)"; then \ + $(MKDIR_P) $(DESTDIR)$(rootlibdir) && \ + so_img_name=$$(readlink $(DESTDIR)$(libdir)/$$libname) && \ + so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \ + $(LN_S) -f $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/$$libname && \ + mv $(DESTDIR)$(libdir)/$$libname.* $(DESTDIR)$(rootlibdir); \ + fi +endef + +INSTALL_DIRS = + +RUNLEVEL1_TARGET_WANTS = +RUNLEVEL2_TARGET_WANTS = +RUNLEVEL3_TARGET_WANTS = +RUNLEVEL4_TARGET_WANTS = +RUNLEVEL5_TARGET_WANTS = +SHUTDOWN_TARGET_WANTS = +LOCAL_FS_TARGET_WANTS = +MULTI_USER_TARGET_WANTS = +SYSINIT_TARGET_WANTS = +SOCKETS_TARGET_WANTS = +BUSNAMES_TARGET_WANTS = +TIMERS_TARGET_WANTS = +USER_SOCKETS_TARGET_WANTS = +USER_BUSNAMES_TARGET_WANTS = + +SYSTEM_UNIT_ALIASES = +USER_UNIT_ALIASES = + +GENERAL_ALIASES = + +install-target-wants-hook: + what="$(RUNLEVEL1_TARGET_WANTS)" && wants=runlevel1.target && dir=$(systemunitdir) && $(add-wants) + what="$(RUNLEVEL2_TARGET_WANTS)" && wants=runlevel2.target && dir=$(systemunitdir) && $(add-wants) + what="$(RUNLEVEL3_TARGET_WANTS)" && wants=runlevel3.target && dir=$(systemunitdir) && $(add-wants) + what="$(RUNLEVEL4_TARGET_WANTS)" && wants=runlevel4.target && dir=$(systemunitdir) && $(add-wants) + what="$(RUNLEVEL5_TARGET_WANTS)" && wants=runlevel5.target && dir=$(systemunitdir) && $(add-wants) + what="$(SHUTDOWN_TARGET_WANTS)" && wants=shutdown.target && dir=$(systemunitdir) && $(add-wants) + what="$(LOCAL_FS_TARGET_WANTS)" && wants=local-fs.target && dir=$(systemunitdir) && $(add-wants) + what="$(MULTI_USER_TARGET_WANTS)" && wants=multi-user.target && dir=$(systemunitdir) && $(add-wants) + what="$(SYSINIT_TARGET_WANTS)" && wants=sysinit.target && dir=$(systemunitdir) && $(add-wants) + what="$(SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(systemunitdir) && $(add-wants) + what="$(BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(systemunitdir) && $(add-wants) + what="$(TIMERS_TARGET_WANTS)" && wants=timers.target && dir=$(systemunitdir) && $(add-wants) + what="$(SLICES_TARGET_WANTS)" && wants=slices.target && dir=$(systemunitdir) && $(add-wants) + what="$(USER_SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(userunitdir) && $(add-wants) + what="$(USER_BUSNAMES_TARGET_WANTS)" && wants=busnames.target && dir=$(userunitdir) && $(add-wants) + +define add-wants + [ -z "$$what" ] || ( \ + dir=$(DESTDIR)$$dir/$$wants.wants && \ + $(MKDIR_P) -m 0755 $$dir && \ + cd $$dir && \ + rm -f $$what && \ + for i in $$what; do $(LN_S) ../$$i . || exit $$? ; done ) +endef + +install-directories-hook: + $(MKDIR_P) $(addprefix $(DESTDIR),$(INSTALL_DIRS)) + +install-aliases-hook: + set -- $(SYSTEM_UNIT_ALIASES) && \ + dir=$(systemunitdir) && $(install-aliases) + set -- $(USER_UNIT_ALIASES) && \ + dir=$(userunitdir) && $(install-aliases) + set -- $(GENERAL_ALIASES) && \ + dir= && $(install-aliases) + +define install-aliases + while [ -n "$$1" ]; do \ + $(MKDIR_P) `dirname $(DESTDIR)$$dir/$$2` && \ + rm -f $(DESTDIR)$$dir/$$2 && \ + $(LN_S) $$1 $(DESTDIR)$$dir/$$2 && \ + shift 2 || exit $$?; \ + done +endef + +INSTALL_EXEC_HOOKS += \ + install-target-wants-hook \ + install-directories-hook \ + install-aliases-hook + +# ------------------------------------------------------------------------------ +AM_V_M4 = $(AM_V_M4_$(V)) +AM_V_M4_ = $(AM_V_M4_$(AM_DEFAULT_VERBOSITY)) +AM_V_M4_0 = @echo " M4 " $@; + +AM_V_XSLT = $(AM_V_XSLT_$(V)) +AM_V_XSLT_ = $(AM_V_XSLT_$(AM_DEFAULT_VERBOSITY)) +AM_V_XSLT_0 = @echo " XSLT " $@; + +AM_V_GPERF = $(AM_V_GPERF_$(V)) +AM_V_GPERF_ = $(AM_V_GPERF_$(AM_DEFAULT_VERBOSITY)) +AM_V_GPERF_0 = @echo " GPERF " $@; + +AM_V_LN = $(AM_V_LN_$(V)) +AM_V_LN_ = $(AM_V_LN_$(AM_DEFAULT_VERBOSITY)) +AM_V_LN_0 = @echo " LN " $@; + +# ------------------------------------------------------------------------------ rootbin_PROGRAMS = \ - systemd \ systemctl \ - systemd-loginctl \ systemd-notify \ systemd-ask-password \ systemd-tty-ask-password-agent \ - systemd-tmpfiles \ systemd-machine-id-setup bin_PROGRAMS = \ systemd-cgls \ - systemd-stdio-bridge \ - systemd-nspawn + systemd-cgtop \ + systemd-nspawn \ + systemd-detect-virt \ + systemd-delta \ + systemd-analyze \ + systemd-run dist_bin_SCRIPTS = \ - src/systemd-analyze + src/kernel-install/kernel-install -if HAVE_GTK -bin_PROGRAMS += \ - systemadm \ - systemd-gnome-ask-password-agent -endif +dist_kernelinstall_SCRIPTS = \ + src/kernel-install/50-depmod.install \ + src/kernel-install/90-loaderentry.install rootlibexec_PROGRAMS = \ - systemd-stdout-syslog-bridge \ + systemd \ systemd-cgroups-agent \ systemd-initctl \ systemd-update-utmp \ - systemd-random-seed \ systemd-shutdownd \ systemd-shutdown \ - systemd-modules-load \ - systemd-remount-api-vfs \ - systemd-kmsg-syslogd \ - systemd-vconsole-setup \ + systemd-remount-fs \ systemd-reply-password \ - systemd-readahead-collect \ - systemd-readahead-replay \ - systemd-user-sessions \ systemd-fsck \ - systemd-quotacheck \ - systemd-timestamp \ systemd-ac-power \ - systemd-detect-virt \ systemd-sysctl \ - systemd-logind \ - systemd-uaccess - -if ENABLE_BINFMT -rootlibexec_PROGRAMS += \ - systemd-binfmt -endif - -if ENABLE_HOSTNAMED -rootlibexec_PROGRAMS += \ - systemd-hostnamed -endif - -if ENABLE_TIMEDATED -rootlibexec_PROGRAMS += \ - systemd-timedated -endif - -if ENABLE_LOCALED -rootlibexec_PROGRAMS += \ - systemd-localed -endif + systemd-sleep \ + systemd-bus-proxyd \ + systemd-socket-proxyd systemgenerator_PROGRAMS = \ - systemd-getty-generator - -if HAVE_LIBCRYPTSETUP -rootlibexec_PROGRAMS += \ - systemd-cryptsetup - -systemgenerator_PROGRAMS += \ - systemd-cryptsetup-generator -endif - -lib_LTLIBRARIES = \ - libsystemd-daemon.la \ - libsystemd-login.la - -pkginclude_HEADERS = \ - src/sd-daemon.h \ - src/sd-login.h - -noinst_PROGRAMS = \ - test-engine \ - test-job-type \ - test-ns \ - test-loopback \ - test-hostname \ - test-daemon \ - test-cgroup \ - test-env-replace \ - test-strv \ - test-login \ - test-install - -if HAVE_PAM -pamlib_LTLIBRARIES = \ - pam_systemd.la -endif - -dist_pkgsysconf_DATA = \ - src/system.conf \ - src/user.conf \ - src/systemd-logind.conf - -dist_dbuspolicy_DATA = \ - src/org.freedesktop.systemd1.conf \ - src/org.freedesktop.login1.conf - -if ENABLE_HOSTNAMED -dist_dbuspolicy_DATA += \ - src/org.freedesktop.hostname1.conf -endif - -if ENABLE_TIMEDATED -dist_dbuspolicy_DATA += \ - src/org.freedesktop.timedate1.conf -endif - -if ENABLE_LOCALED -dist_dbuspolicy_DATA += \ - src/org.freedesktop.locale1.conf -endif - -dist_dbussystemservice_DATA = \ - src/org.freedesktop.systemd1.service \ - src/org.freedesktop.login1.service - -if ENABLE_HOSTNAMED -dist_dbussystemservice_DATA += \ - src/org.freedesktop.hostname1.service -endif - -if ENABLE_TIMEDATED -dist_dbussystemservice_DATA += \ - src/org.freedesktop.timedate1.service -endif - -if ENABLE_LOCALED -dist_dbussystemservice_DATA += \ - src/org.freedesktop.locale1.service -endif - -dist_udevrules_DATA = \ - src/70-uaccess.rules \ - src/71-seat.rules - -nodist_udevrules_DATA = \ - src/73-seat-late.rules \ - src/99-systemd.rules - -dbusinterface_DATA = \ - org.freedesktop.systemd1.Manager.xml \ - org.freedesktop.systemd1.Job.xml \ - org.freedesktop.systemd1.Unit.xml \ - org.freedesktop.systemd1.Service.xml \ - org.freedesktop.systemd1.Socket.xml \ - org.freedesktop.systemd1.Timer.xml \ - org.freedesktop.systemd1.Target.xml \ - org.freedesktop.systemd1.Device.xml \ - org.freedesktop.systemd1.Mount.xml \ - org.freedesktop.systemd1.Automount.xml \ - org.freedesktop.systemd1.Snapshot.xml \ - org.freedesktop.systemd1.Swap.xml \ - org.freedesktop.systemd1.Path.xml - -if ENABLE_HOSTNAMED -dbusinterface_DATA += \ - org.freedesktop.hostname1.xml -endif - -if ENABLE_TIMEDATED -dbusinterface_DATA += \ - org.freedesktop.timedate1.xml -endif - -if ENABLE_LOCALED -dbusinterface_DATA += \ - org.freedesktop.locale1.xml -endif + systemd-getty-generator \ + systemd-fstab-generator \ + systemd-system-update-generator dist_bashcompletion_DATA = \ - src/systemctl-bash-completion.sh - -dist_tmpfiles_DATA = \ - tmpfiles.d/systemd.conf \ - tmpfiles.d/tmp.conf \ - tmpfiles.d/x11.conf - -if HAVE_SYSV_COMPAT -dist_tmpfiles_DATA += \ - tmpfiles.d/legacy.conf -endif + shell-completion/bash/busctl \ + shell-completion/bash/journalctl \ + shell-completion/bash/systemctl \ + shell-completion/bash/systemd-analyze \ + shell-completion/bash/systemd-delta \ + shell-completion/bash/systemd-run \ + shell-completion/bash/udevadm \ + shell-completion/bash/kernel-install + +dist_zshcompletion_DATA = \ + shell-completion/zsh/_systemctl \ + shell-completion/zsh/_journalctl \ + shell-completion/zsh/_udevadm \ + shell-completion/zsh/_kernel-install \ + shell-completion/zsh/_systemd-nspawn \ + shell-completion/zsh/_systemd-analyze \ + shell-completion/zsh/_systemd-run \ + shell-completion/zsh/_sd_hosts_or_user_at_host \ + shell-completion/zsh/_systemd-delta \ + shell-completion/zsh/_systemd + +dist_sysctl_DATA = \ + sysctl.d/50-default.conf dist_systemunit_DATA = \ units/graphical.target \ @@ -337,14 +383,18 @@ dist_systemunit_DATA = \ units/halt.target \ units/kexec.target \ units/local-fs.target \ - units/local-fs-pre.target \ + units/local-fs-pre.target \ + units/initrd.target \ + units/initrd-fs.target \ + units/initrd-root-fs.target \ units/remote-fs.target \ - units/remote-fs-pre.target \ - units/cryptsetup.target \ + units/remote-fs-pre.target \ units/network.target \ + units/network-online.target \ units/nss-lookup.target \ - units/mail-transfer-agent.target \ - units/http-daemon.target \ + units/nss-user-lookup.target \ + units/hibernate.target \ + units/hybrid-sleep.target \ units/poweroff.target \ units/reboot.target \ units/rescue.target \ @@ -354,1711 +404,4678 @@ dist_systemunit_DATA = \ units/final.target \ units/umount.target \ units/sigpwr.target \ + units/sleep.target \ units/sockets.target \ + units/busnames.target \ + units/timers.target \ + units/paths.target \ + units/suspend.target \ units/swap.target \ + units/slices.target \ + units/system.slice \ + units/x-.slice \ units/systemd-initctl.socket \ - units/systemd-stdout-syslog-bridge.socket \ units/systemd-shutdownd.socket \ units/syslog.socket \ units/dev-hugepages.mount \ units/dev-mqueue.mount \ units/sys-kernel-config.mount \ units/sys-kernel-debug.mount \ - units/sys-kernel-security.mount \ units/sys-fs-fuse-connections.mount \ - units/var-run.mount \ - units/media.mount \ - units/remount-rootfs.service \ + units/tmp.mount \ units/printer.target \ units/sound.target \ units/bluetooth.target \ units/smartcard.target \ - units/systemd-readahead-done.timer \ - units/systemd-tmpfiles-clean.timer \ - units/quotaon.service \ units/systemd-ask-password-wall.path \ units/systemd-ask-password-console.path \ - units/syslog.target - -if HAVE_SYSV_COMPAT -dist_systemunit_DATA += \ - units/var-lock.mount -endif - -if ENABLE_BINFMT -dist_systemunit_DATA += \ - units/proc-sys-fs-binfmt_misc.automount \ - units/proc-sys-fs-binfmt_misc.mount -endif + units/systemd-udevd-control.socket \ + units/systemd-udevd-kernel.socket \ + units/system-update.target \ + units/initrd-switch-root.target nodist_systemunit_DATA = \ units/getty@.service \ units/serial-getty@.service \ units/console-shell.service \ + units/console-getty.service \ + units/container-getty@.service \ units/systemd-initctl.service \ - units/systemd-stdout-syslog-bridge.service \ units/systemd-shutdownd.service \ - units/systemd-logind.service \ - units/systemd-kmsg-syslogd.service \ - units/systemd-modules-load.service \ - units/systemd-vconsole-setup.service \ - units/systemd-remount-api-vfs.service \ + units/systemd-remount-fs.service \ + units/systemd-update-utmp.service \ units/systemd-update-utmp-runlevel.service \ - units/systemd-update-utmp-shutdown.service \ - units/systemd-random-seed-save.service \ - units/systemd-random-seed-load.service \ - units/systemd-readahead-collect.service \ - units/systemd-readahead-replay.service \ - units/systemd-readahead-done.service \ - units/systemd-tmpfiles-setup.service \ - units/systemd-tmpfiles-clean.service \ - units/systemd-user-sessions.service \ units/systemd-ask-password-wall.service \ units/systemd-ask-password-console.service \ units/systemd-sysctl.service \ - units/halt.service \ - units/poweroff.service \ - units/reboot.service \ - units/kexec.service \ - units/fsck@.service \ - units/fsck-root.service \ - units/quotacheck.service \ + units/emergency.service \ units/rescue.service \ - units/user@.service - -if ENABLE_BINFMT -nodist_systemunit_DATA += \ - units/systemd-binfmt.service -endif - -if ENABLE_HOSTNAMED -nodist_systemunit_DATA += \ - units/systemd-hostnamed.service -endif - -if ENABLE_TIMEDATED -nodist_systemunit_DATA += \ - units/systemd-timedated.service -endif - -if ENABLE_LOCALED -nodist_systemunit_DATA += \ - units/systemd-localed.service -endif + units/user@.service \ + units/systemd-hibernate.service \ + units/systemd-hybrid-sleep.service \ + units/systemd-suspend.service \ + units/systemd-halt.service \ + units/systemd-poweroff.service \ + units/systemd-reboot.service \ + units/systemd-kexec.service \ + units/systemd-fsck@.service \ + units/systemd-fsck-root.service \ + units/systemd-udevd.service \ + units/systemd-udev-trigger.service \ + units/systemd-udev-settle.service \ + units/debug-shell.service \ + units/initrd-parse-etc.service \ + units/initrd-cleanup.service \ + units/initrd-udevadm-cleanup-db.service \ + units/initrd-switch-root.service \ + units/systemd-nspawn@.service dist_userunit_DATA = \ + units/user/basic.target \ units/user/default.target \ units/user/exit.target nodist_userunit_DATA = \ - units/user/exit.service + units/user/systemd-exit.service -EXTRA_DIST = \ +EXTRA_DIST += \ units/getty@.service.m4 \ units/serial-getty@.service.m4 \ - units/console-shell.service.m4 \ - units/rescue.service.m4 \ + units/console-shell.service.m4.in \ + units/console-getty.service.m4.in \ + units/container-getty@.service.m4.in \ + units/rescue.service.m4.in \ units/systemd-initctl.service.in \ - units/systemd-stdout-syslog-bridge.service.in \ units/systemd-shutdownd.service.in \ - units/systemd-logind.service.in \ - units/systemd-kmsg-syslogd.service.in \ - units/systemd-modules-load.service.in \ - units/systemd-vconsole-setup.service.in \ - units/systemd-remount-api-vfs.service.in \ + units/systemd-remount-fs.service.in \ + units/systemd-update-utmp.service.in \ units/systemd-update-utmp-runlevel.service.in \ - units/systemd-update-utmp-shutdown.service.in \ - units/systemd-random-seed-save.service.in \ - units/systemd-random-seed-load.service.in \ - units/systemd-readahead-collect.service.in \ - units/systemd-readahead-replay.service.in \ - units/systemd-readahead-done.service.in \ - units/systemd-tmpfiles-setup.service.in \ - units/systemd-tmpfiles-clean.service.in \ - units/systemd-user-sessions.service.in \ units/systemd-ask-password-wall.service.in \ units/systemd-ask-password-console.service.in \ units/systemd-sysctl.service.in \ - units/halt.service.in \ - units/poweroff.service.in \ - units/reboot.service.in \ - units/kexec.service.in \ - units/user/exit.service.in \ - units/fsck@.service.in \ - units/fsck-root.service.in \ - units/quotacheck.service.in \ + units/emergency.service.in \ + units/systemd-halt.service.in \ + units/systemd-poweroff.service.in \ + units/systemd-reboot.service.in \ + units/systemd-kexec.service.in \ + units/user/systemd-exit.service.in \ + units/systemd-fsck@.service.in \ + units/systemd-fsck-root.service.in \ units/user@.service.in \ - systemd.pc.in \ - libsystemd-daemon.pc.in \ - libsystemd-login.pc.in \ - src/libsystemd-daemon.sym \ - src/libsystemd-login.sym \ - introspect.awk \ - src/73-seat-late.rules.in \ - src/99-systemd.rules.in + units/systemd-udevd.service \ + units/systemd-udev-trigger.service \ + units/systemd-udev-settle.service \ + units/debug-shell.service.in \ + units/systemd-hibernate.service.in \ + units/systemd-hybrid-sleep.service.in \ + units/systemd-suspend.service.in \ + units/quotaon.service.in \ + units/initrd-parse-etc.service.in \ + units/initrd-cleanup.service.in \ + units/initrd-udevadm-cleanup-db.service.in \ + units/initrd-switch-root.service.in \ + units/systemd-nspawn@.service.in -if ENABLE_BINFMT -EXTRA_DIST += \ - units/systemd-binfmt.service.in -endif +CLEANFILES += \ + units/console-shell.service.m4 \ + units/console-getty.service.m4 \ + units/container-getty@.service.m4 \ + units/rescue.service.m4 \ + units/user@.service.m4 -if ENABLE_HOSTNAMED -EXTRA_DIST += \ - units/systemd-hostnamed.service.in -endif +if HAVE_SYSV_COMPAT +nodist_systemunit_DATA += \ + units/rc-local.service \ + units/halt-local.service -if ENABLE_TIMEDATED -EXTRA_DIST += \ - units/systemd-timedated.service.in +systemgenerator_PROGRAMS += \ + systemd-rc-local-generator endif -if ENABLE_LOCALED EXTRA_DIST += \ - units/systemd-localed.service.in -endif + units/rc-local.service.in \ + units/halt-local.service.in -if TARGET_FEDORA -dist_systemunit_DATA += \ - units/fedora/prefdm.service \ - units/fedora/rc-local.service \ - units/fedora/halt-local.service -endif +# automake is broken and can't handle files with a dash in front +# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14728#8 +units-install-hook: + mv $(DESTDIR)$(systemunitdir)/x-.slice $(DESTDIR)/$(systemunitdir)/-.slice -if TARGET_MANDRIVA -dist_systemunit_DATA += \ - units/mandriva/prefdm.service \ - units/fedora/rc-local.service \ - units/fedora/halt-local.service -endif +units-uninstall-hook: + rm -f $(DESTDIR)/$(systemunitdir)/-.slice -if TARGET_SLP -dist_systemunit_DATA += \ - units/slp/var-lib.mount \ - units/slp/var-lib.automount \ - units/slp/var-cache.mount \ - units/slp/var-cache.automount \ - units/slp/var-log.mount \ - units/slp/var-log.automount \ - units/slp/var-lock.mount -endif +INSTALL_DATA_HOOKS += units-install-hook +UNINSTALL_DATA_HOOKS += units-uninstall-hook -if TARGET_FRUGALWARE -dist_systemunit_DATA += \ - units/frugalware/display-manager.service -endif +dist_doc_DATA = \ + README \ + NEWS \ + LICENSE.LGPL2.1 \ + LICENSE.GPL2 \ + LICENSE.MIT \ + DISTRO_PORTING -if TARGET_SUSE -dist_systemunit_DATA += \ - units/suse/rc-local.service \ - units/suse/halt-local.service -endif +@INTLTOOL_POLICY_RULE@ -if HAVE_PLYMOUTH -dist_systemunit_DATA += \ - units/plymouth-start.service \ - units/plymouth-read-write.service \ - units/plymouth-quit.service \ - units/plymouth-quit-wait.service \ - units/plymouth-reboot.service \ - units/plymouth-kexec.service \ - units/plymouth-poweroff.service \ - units/plymouth-halt.service \ - units/systemd-ask-password-plymouth.path +# ------------------------------------------------------------------------------ -nodist_systemunit_DATA += \ - units/systemd-ask-password-plymouth.service +MANPAGES = +MANPAGES_ALIAS = -EXTRA_DIST += \ - units/systemd-ask-password-plymouth.service.in -endif +include Makefile-man.am -dist_doc_DATA = \ - README \ - LICENSE \ - DISTRO_PORTING \ - src/sd-daemon.h \ - src/sd-daemon.c \ - src/sd-readahead.h \ - src/sd-readahead.c +.PHONY: man update-man-list +man: $(MANPAGES) $(MANPAGES_ALIAS) $(HTML_FILES) $(HTML_ALIAS) -pkgconfigdata_DATA = \ - systemd.pc +XML_FILES = \ + ${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,${patsubst %.8,%.xml,$(MANPAGES)}}}}} +HTML_FILES = \ + ${XML_FILES:.xml=.html} +HTML_ALIAS = \ + ${patsubst %.1,%.html,${patsubst %.3,%.html,${patsubst %.5,%.html,${patsubst %.7,%.html,${patsubst %.8,%.html,$(MANPAGES_ALIAS)}}}}} -pkgconfiglib_DATA = \ - libsystemd-daemon.pc \ - libsystemd-login.pc +if ENABLE_MANPAGES +man_MANS = \ + $(MANPAGES) \ + $(MANPAGES_ALIAS) -# Passed through intltool only -polkitpolicy_in_files = \ - src/org.freedesktop.login1.policy.in +noinst_DATA += \ + $(HTML_FILES) \ + $(HTML_ALIAS) -if ENABLE_HOSTNAMED -polkitpolicy_in_files += \ - src/org.freedesktop.hostname1.policy.in -endif +CLEANFILES += \ + $(man_MANS) \ + $(HTML_FILES) \ + $(HTML_ALIAS) -if ENABLE_TIMEDATED -polkitpolicy_in_files += \ - src/org.freedesktop.timedate1.policy.in -endif +docs/html/man: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_LN)$(LN_S) -f ../../man $@ -if ENABLE_LOCALED -polkitpolicy_in_files += \ - src/org.freedesktop.locale1.policy.in -endif +noinst_DATA += \ + docs/html/man -# First passed through sed, followed by intltool -polkitpolicy_in_in_files = \ - src/org.freedesktop.systemd1.policy.in.in +CLEANFILES += \ + docs/html/man -nodist_polkitpolicy_DATA = \ - $(polkitpolicy_in_files:.policy.in=.policy) \ - $(polkitpolicy_in_in_files:.policy.in.in=.policy) +if HAVE_PYTHON +man/index.html: man/systemd.index.html + $(AM_V_LN)$(LN_S) -f systemd.index.html $@ + +noinst_DATA += \ + man/index.html + +CLEANFILES += \ + man/index.html + +XML_GLOB = $(wildcard $(top_srcdir)/man/*.xml $(top_builddir)/man/*.xml) +NON_INDEX_XML_FILES = $(filter-out man/systemd.index.xml,$(XML_FILES)) +SOURCE_XML_FILES = $(filter-out man/systemd.directives.xml,$(NON_INDEX_XML_FILES)) + +update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB) + $(AM_V_GEN)$(PYTHON) $^ > $(top_srcdir)/Makefile-man.tmp + $(AM_V_at)mv $(top_srcdir)/Makefile-man.tmp $(top_srcdir)/Makefile-man.am + @echo "Makefile-man.am has been regenerated" + +man/systemd.index.xml: $(top_srcdir)/tools/make-man-index.py $(NON_INDEX_XML_FILES) + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(PYTHON) $< $@ $(filter-out $<,$^) + +man/systemd.directives.xml: $(top_srcdir)/tools/make-directive-index.py $(SOURCE_XML_FILES) + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(PYTHON) $< $@ $(filter-out $<,$^) EXTRA_DIST += \ - $(polkitpolicy_in_files) \ - $(polkitpolicy_in_in_files) + man/systemd.index.xml \ + man/index.html \ + man/systemd.directives.xml -@INTLTOOL_POLICY_RULE@ +CLEANFILES += \ + man/systemd.index.xml \ + man/systemd.directives.xml -noinst_LTLIBRARIES = \ - libsystemd-basic.la \ - libsystemd-core.la +endif + +endif -libsystemd_basic_la_SOURCES = \ - src/util.c \ - src/virt.c \ - src/label.c \ - src/hashmap.c \ - src/set.c \ - src/strv.c \ - src/conf-parser.c \ - src/socket-util.c \ - src/log.c \ - src/ratelimit.c \ - src/exit-status.c - -libsystemd_basic_la_CFLAGS = \ +EXTRA_DIST += \ + $(XML_FILES) \ + $(HTML_FILES) \ + $(HTML_ALIAS) \ + $(man_MANS) \ + tools/make-man-index.py \ + tools/make-directive-index.py \ + tools/make-man-rules.py \ + tools/xml_helper.py + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-shared.la + +libsystemd_shared_la_SOURCES = \ + src/shared/linux/auto_dev-ioctl.h \ + src/shared/linux/fanotify.h \ + src/shared/ioprio.h \ + src/shared/missing.h \ + src/shared/initreq.h \ + src/shared/securebits.h \ + src/shared/special.h \ + src/shared/list.h \ + src/shared/macro.h \ + src/shared/def.h \ + src/shared/sparse-endian.h \ + src/shared/refcnt.h \ + src/shared/udev-util.h \ + src/shared/bus-errors.h \ + src/shared/device-nodes.c \ + src/shared/device-nodes.h \ + src/shared/util.c \ + src/shared/util.h \ + src/shared/virt.c \ + src/shared/virt.h \ + src/shared/architecture.c \ + src/shared/architecture.h \ + src/shared/efivars.c \ + src/shared/efivars.h \ + src/shared/path-util.c \ + src/shared/path-util.h \ + src/shared/time-util.c \ + src/shared/time-util.h \ + src/shared/hashmap.c \ + src/shared/hashmap.h \ + src/shared/siphash24.c \ + src/shared/siphash24.h \ + src/shared/set.c \ + src/shared/set.h \ + src/shared/fdset.c \ + src/shared/fdset.h \ + src/shared/prioq.c \ + src/shared/prioq.h \ + src/shared/sleep-config.c \ + src/shared/sleep-config.h \ + src/shared/strv.c \ + src/shared/strv.h \ + src/shared/env-util.c \ + src/shared/env-util.h \ + src/shared/strbuf.c \ + src/shared/strbuf.h \ + src/shared/strxcpyx.c \ + src/shared/strxcpyx.h \ + src/shared/conf-parser.c \ + src/shared/conf-parser.h \ + src/shared/log.c \ + src/shared/log.h \ + src/shared/ratelimit.h \ + src/shared/ratelimit.c \ + src/shared/exit-status.c \ + src/shared/exit-status.h \ + src/shared/utf8.c \ + src/shared/utf8.h \ + src/shared/gunicode.c \ + src/shared/gunicode.h \ + src/shared/pager.c \ + src/shared/pager.h \ + src/shared/socket-util.c \ + src/shared/socket-util.h \ + src/shared/conf-files.c \ + src/shared/conf-files.h \ + src/shared/cgroup-util.c \ + src/shared/cgroup-util.h \ + src/shared/cgroup-show.c \ + src/shared/cgroup-show.h \ + src/shared/unit-name.c \ + src/shared/unit-name.h \ + src/shared/utmp-wtmp.c \ + src/shared/utmp-wtmp.h \ + src/shared/watchdog.c \ + src/shared/watchdog.h \ + src/shared/spawn-ask-password-agent.c \ + src/shared/spawn-ask-password-agent.h \ + src/shared/replace-var.c \ + src/shared/replace-var.h \ + src/shared/spawn-polkit-agent.c \ + src/shared/spawn-polkit-agent.h \ + src/shared/hwclock.c \ + src/shared/hwclock.h \ + src/shared/time-dst.c \ + src/shared/time-dst.h \ + src/shared/calendarspec.c \ + src/shared/calendarspec.h \ + src/shared/fileio.c \ + src/shared/fileio.h \ + src/shared/output-mode.h \ + src/shared/MurmurHash2.c \ + src/shared/MurmurHash2.h \ + src/shared/acpi-fpdt.h \ + src/shared/acpi-fpdt.c \ + src/shared/boot-timestamps.h \ + src/shared/boot-timestamps.c \ + src/shared/mkdir.c \ + src/shared/mkdir.h \ + src/shared/smack-util.c \ + src/shared/smack-util.h \ + src/shared/apparmor-util.c \ + src/shared/apparmor-util.h \ + src/shared/ima-util.c \ + src/shared/ima-util.h \ + src/shared/ptyfwd.c \ + src/shared/ptyfwd.h \ + src/shared/net-util.c \ + src/shared/net-util.h \ + src/shared/errno-list.c \ + src/shared/errno-list.h \ + src/shared/audit.c \ + src/shared/audit.h \ + src/shared/xml.c \ + src/shared/xml.h \ + src/shared/condition-util.c \ + src/shared/condition-util.h \ + src/shared/bus-label.c \ + src/shared/bus-label.h + +nodist_libsystemd_shared_la_SOURCES = \ + src/shared/errno-from-name.h \ + src/shared/errno-to-name.h + +libsystemd_shared_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-units.la + +libsystemd_units_la_SOURCES = \ + src/shared/install.c \ + src/shared/install.h \ + src/shared/install-printf.c \ + src/shared/install-printf.h \ + src/shared/path-lookup.c \ + src/shared/path-lookup.h \ + src/shared/specifier.c \ + src/shared/specifier.h + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-label.la + +libsystemd_label_la_SOURCES = \ + src/shared/socket-label.c \ + src/shared/label.c \ + src/shared/label.h \ + src/shared/selinux-util.c \ + src/shared/selinux-util.h \ + src/shared/mkdir-label.c \ + src/shared/ask-password-api.c \ + src/shared/ask-password-api.h \ + src/shared/fileio-label.c \ + src/shared/fileio-label.h \ + src/shared/dev-setup.c \ + src/shared/dev-setup.h + +libsystemd_label_la_CFLAGS = \ $(AM_CFLAGS) \ $(SELINUX_CFLAGS) -libsystemd_basic_la_LIBADD = \ - $(SELINUX_LIBS) \ - $(CAP_LIBS) +libsystemd_label_la_LIBADD = \ + $(SELINUX_LIBS) -libsystemd_core_la_SOURCES = \ - src/unit.c \ - src/job.c \ - src/manager.c \ - src/path-lookup.c \ - src/load-fragment.c \ - src/service.c \ - src/automount.c \ - src/mount.c \ - src/swap.c \ - src/device.c \ - src/target.c \ - src/snapshot.c \ - src/socket.c \ - src/timer.c \ - src/path.c \ - src/load-dropin.c \ - src/execute.c \ - src/utmp-wtmp.c \ - src/dbus.c \ - src/dbus-manager.c \ - src/dbus-unit.c \ - src/dbus-job.c \ - src/dbus-service.c \ - src/dbus-socket.c \ - src/dbus-timer.c \ - src/dbus-target.c \ - src/dbus-mount.c \ - src/dbus-automount.c \ - src/dbus-swap.c \ - src/dbus-snapshot.c \ - src/dbus-device.c \ - src/dbus-execute.c \ - src/dbus-path.c \ - src/cgroup.c \ - src/mount-setup.c \ - src/hostname-setup.c \ - src/selinux-setup.c \ - src/loopback-setup.c \ - src/kmod-setup.c \ - src/locale-setup.c \ - src/machine-id-setup.c \ - src/specifier.c \ - src/unit-name.c \ - src/fdset.c \ - src/namespace.c \ - src/tcpwrap.c \ - src/cgroup-util.c \ - src/condition.c \ - src/dbus-common.c \ - src/sd-daemon.c \ - src/install.c \ - src/cgroup-attr.c +# ------------------------------------------------------------------------------ -nodist_libsystemd_core_la_SOURCES = \ - src/load-fragment-gperf.c \ - src/load-fragment-gperf-nulstr.c +if HAVE_SECCOMP +noinst_LTLIBRARIES += \ + libsystemd-seccomp.la -EXTRA_DIST += \ - src/load-fragment-gperf.gperf.m4 +libsystemd_seccomp_la_SOURCES = \ + src/shared/seccomp-util.h \ + src/shared/seccomp-util.c -libsystemd_core_la_CFLAGS = \ +libsystemd_seccomp_la_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(UDEV_CFLAGS) \ - $(LIBWRAP_CFLAGS) \ - $(PAM_CFLAGS) \ - $(AUDIT_CFLAGS) + $(SECCOMP_CFLAGS) -libsystemd_core_la_LIBADD = \ - libsystemd-basic.la \ - $(DBUS_LIBS) \ - $(UDEV_LIBS) \ - $(LIBWRAP_LIBS) \ - $(PAM_LIBS) \ - $(AUDIT_LIBS) \ +libsystemd_seccomp_la_LIBADD = \ + $(SECCOMP_LIBS) +endif + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-logs.la + +libsystemd_logs_la_SOURCES = \ + src/shared/logs-show.c \ + src/shared/logs-show.h + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-capability.la + +libsystemd_capability_la_SOURCES = \ + src/shared/capability.c \ + src/shared/capability.h + +libsystemd_capability_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + +libsystemd_capability_la_LIBADD = \ $(CAP_LIBS) -# This is needed because automake is buggy in how it generates the -# rules for C programs, but not Vala programs. We therefore can't -# list the .h files as dependencies if we want make dist to work. +# ------------------------------------------------------------------------------ +if HAVE_ACL +noinst_LTLIBRARIES += \ + libsystemd-acl.la -EXTRA_DIST += \ - ${libsystemd_basic_la_SOURCES:.c=.h} \ - ${libsystemd_core_la_SOURCES:.c=.h} \ - ${libsystemd_daemon_la_SOURCES:.c=.h} \ - src/macro.h \ - src/def.h \ - src/ioprio.h \ - src/missing.h \ - src/list.h \ - src/securebits.h \ - src/linux/auto_dev-ioctl.h \ - src/linux/fanotify.h \ - src/initreq.h \ - src/sd-readahead.h \ - src/special.h \ - src/dbus-common.h \ - src/bus-errors.h \ - src/cgroup-show.h \ - src/build.h \ - src/shutdownd.h \ - src/umount.h \ - src/readahead-common.h \ - src/ask-password-api.h \ - src/pager.h \ - src/sysfs-show.h \ - src/polkit.h \ - src/logind.h \ - src/logind-device.h \ - src/logind-seat.h \ - src/logind-session.h \ - src/logind-user.h \ - src/logind-acl.h \ - src/dbus-loop.h \ - src/spawn-agent.h - -if HAVE_XSLTPROC -MANPAGES = \ - man/systemd.1 \ - man/systemctl.1 \ - man/systemadm.1 \ - man/systemd-cgls.1 \ - man/systemd-nspawn.1 \ - man/systemd-tmpfiles.8 \ - man/systemd-notify.1 \ - man/sd_notify.3 \ - man/sd_readahead.3 \ - man/sd_booted.3 \ - man/sd_listen_fds.3 \ - man/sd_is_fifo.3 \ - man/systemd.unit.5 \ - man/systemd.service.5 \ - man/systemd.socket.5 \ - man/systemd.mount.5 \ - man/systemd.automount.5 \ - man/systemd.swap.5 \ - man/systemd.timer.5 \ - man/systemd.path.5 \ - man/systemd.target.5 \ - man/systemd.device.5 \ - man/systemd.snapshot.5 \ - man/systemd.exec.5 \ - man/daemon.7 \ - man/sd-daemon.7 \ - man/sd-readahead.7 \ - man/runlevel.8 \ - man/telinit.8 \ - man/halt.8 \ - man/shutdown.8 \ - man/pam_systemd.8 \ - man/systemd.conf.5 \ - man/systemd-logind.conf.5 \ - man/tmpfiles.d.5 \ - man/hostname.5 \ - man/timezone.5 \ - man/machine-id.5 \ - man/vconsole.conf.5 \ - man/locale.conf.5 \ - man/os-release.5 \ - man/machine-info.5 \ - man/modules-load.d.5 \ - man/sysctl.d.5 \ - man/systemd-ask-password.1 \ - man/systemd-loginctl.1 +libsystemd_acl_la_SOURCES = \ + src/shared/acl-util.c \ + src/shared/acl-util.h -if ENABLE_BINFMT -MANPAGES += \ - man/binfmt.d.5 -endif - -MANPAGES_ALIAS = \ - man/reboot.8 \ - man/poweroff.8 \ - man/sd_is_socket.3 \ - man/sd_is_socket_unix.3 \ - man/sd_is_socket_inet.3 \ - man/sd_notifyf.3 \ - man/init.1 - -man/reboot.8: man/halt.8 -man/poweroff.8: man/halt.8 -man/sd_is_socket.3: man/sd_is_fifo.3 -man/sd_is_socket_unix.3: man/sd_is_fifo.3 -man/sd_is_socket_inet.3: man/sd_is_fifo.3 -man/sd_notifyf.3: man/sd_notify.3 -man/init.1: man/systemd.1 - -dist_man_MANS = \ - $(MANPAGES) \ - $(MANPAGES_ALIAS) +libsystemd_acl_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(ACL_CFLAGS) -nodist_man_MANS = \ - man/systemd.special.7 +libsystemd_acl_la_LIBADD = \ + $(ACL_LIBS) +endif -XML_FILES = \ - ${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,${patsubst %.8,%.xml,$(MANPAGES)}}}}} +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-core.la -XML_IN_FILES = \ - ${patsubst %.1,%.xml.in,${patsubst %.3,%.xml.in,${patsubst %.5,%.xml.in,${patsubst %.7,%.xml.in,${patsubst %.8,%.xml.in,$(nodist_man_MANS)}}}}} +libsystemd_core_la_SOURCES = \ + src/core/unit.c \ + src/core/unit.h \ + src/core/unit-printf.c \ + src/core/unit-printf.h \ + src/core/job.c \ + src/core/job.h \ + src/core/manager.c \ + src/core/manager.h \ + src/core/transaction.c \ + src/core/transaction.h \ + src/core/load-fragment.c \ + src/core/load-fragment.h \ + src/core/service.c \ + src/core/service.h \ + src/core/socket.c \ + src/core/socket.h \ + src/core/busname.c \ + src/core/busname.h \ + src/core/target.c \ + src/core/target.h \ + src/core/snapshot.c \ + src/core/snapshot.h \ + src/core/device.c \ + src/core/device.h \ + src/core/mount.c \ + src/core/mount.h \ + src/core/automount.c \ + src/core/automount.h \ + src/core/swap.c \ + src/core/swap.h \ + src/core/timer.c \ + src/core/timer.h \ + src/core/path.c \ + src/core/path.h \ + src/core/slice.c \ + src/core/slice.h \ + src/core/scope.c \ + src/core/scope.h \ + src/core/load-dropin.c \ + src/core/load-dropin.h \ + src/core/execute.c \ + src/core/execute.h \ + src/core/kill.c \ + src/core/kill.h \ + src/core/dbus.c \ + src/core/dbus.h \ + src/core/dbus-manager.c \ + src/core/dbus-manager.h \ + src/core/dbus-unit.c \ + src/core/dbus-unit.h \ + src/core/dbus-job.c \ + src/core/dbus-job.h \ + src/core/dbus-service.c \ + src/core/dbus-service.h \ + src/core/dbus-socket.c \ + src/core/dbus-socket.h \ + src/core/dbus-busname.c \ + src/core/dbus-busname.h \ + src/core/dbus-target.c \ + src/core/dbus-target.h \ + src/core/dbus-snapshot.c \ + src/core/dbus-snapshot.h \ + src/core/dbus-device.c \ + src/core/dbus-device.h \ + src/core/dbus-mount.c \ + src/core/dbus-mount.h \ + src/core/dbus-automount.c \ + src/core/dbus-automount.h \ + src/core/dbus-swap.c \ + src/core/dbus-swap.h \ + src/core/dbus-timer.c \ + src/core/dbus-timer.h \ + src/core/dbus-path.c \ + src/core/dbus-path.h \ + src/core/dbus-slice.c \ + src/core/dbus-slice.h \ + src/core/dbus-scope.c \ + src/core/dbus-scope.h \ + src/core/dbus-execute.c \ + src/core/dbus-execute.h \ + src/core/dbus-kill.c \ + src/core/dbus-kill.h \ + src/core/dbus-cgroup.c \ + src/core/dbus-cgroup.h \ + src/core/dbus-client-track.c \ + src/core/dbus-client-track.h \ + src/core/cgroup.c \ + src/core/cgroup.h \ + src/core/selinux-access.c \ + src/core/selinux-access.h \ + src/core/selinux-setup.c \ + src/core/selinux-setup.h \ + src/core/smack-setup.c \ + src/core/smack-setup.h \ + src/core/ima-setup.c \ + src/core/ima-setup.h \ + src/core/locale-setup.h \ + src/core/locale-setup.c \ + src/core/hostname-setup.c \ + src/core/hostname-setup.h \ + src/core/machine-id-setup.c \ + src/core/machine-id-setup.h \ + src/core/mount-setup.c \ + src/core/mount-setup.h \ + src/core/loopback-setup.h \ + src/core/loopback-setup.c \ + src/core/condition.c \ + src/core/condition.h \ + src/core/namespace.c \ + src/core/namespace.h \ + src/core/tcpwrap.c \ + src/core/tcpwrap.h \ + src/core/build.h \ + src/core/sysfs-show.h \ + src/core/switch-root.h \ + src/core/switch-root.c \ + src/core/killall.h \ + src/core/killall.c \ + src/core/audit-fd.c \ + src/core/audit-fd.h \ + src/core/async.c \ + src/core/async.h + +if HAVE_KMOD +libsystemd_core_la_SOURCES += \ + src/core/kmod-setup.c \ + src/core/kmod-setup.h +endif -dist_noinst_DATA = \ - ${XML_FILES:.xml=.html} +nodist_libsystemd_core_la_SOURCES = \ + src/core/load-fragment-gperf.c \ + src/core/load-fragment-gperf-nulstr.c -nodist_noinst_DATA = \ - ${XML_IN_FILES:.xml.in=.html} +libsystemd_core_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(LIBWRAP_CFLAGS) \ + $(PAM_CFLAGS) \ + $(AUDIT_CFLAGS) \ + $(CAP_CFLAGS) \ + $(KMOD_CFLAGS) \ + $(APPARMOR_CFLAGS) \ + $(SECCOMP_CFLAGS) \ + -pthread -EXTRA_DIST += \ - $(XML_FILES) \ - $(XML_IN_FILES) \ - ${nodist_man_MANS:=.in} \ - ${XML_IN_FILES:.xml.in=.html.in} +libsystemd_core_la_LIBADD = \ + libsystemd-capability.la \ + libsystemd-units.la \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la \ + libsystemd-internal.la \ + $(LIBWRAP_LIBS) \ + $(PAM_LIBS) \ + $(AUDIT_LIBS) \ + $(CAP_LIBS) \ + $(KMOD_LIBS) \ + $(APPARMOR_LIBS) \ + $(SECCOMP_LIBS) + +if HAVE_SECCOMP +libsystemd_core_la_LIBADD += \ + libsystemd-seccomp.la endif +src/core/load-fragment-gperf-nulstr.c: src/core/load-fragment-gperf.gperf + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(AWK) 'BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; print "const char load_fragment_gperf_nulstr[] ="} ; keyword==1 { print "\"" $$1 "\\0\"" } ; /%%/ { keyword=1} ; END { print ";" }' < $< > $@ + +EXTRA_DIST += \ + src/core/load-fragment-gperf.gperf.m4 + +CLEANFILES += \ + src/core/load-fragment-gperf.gperf \ + src/core/load-fragment-gperf.c \ + src/core/load-fragment-gperf-nulstr.c \ + src/shared/errno-list.txt \ + src/shared/errno-from-name.gperf + +BUILT_SOURCES += \ + src/shared/errno-from-name.h \ + src/shared/errno-to-name.h + +src/shared/errno-list.txt: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - < /dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+[0-9]/ { print $$2; }' > $@ + +src/shared/errno-from-name.gperf: src/shared/errno-list.txt + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct errno_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' < $< > $@ + +src/shared/errno-from-name.h: src/shared/errno-from-name.gperf + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_errno -H hash_errno_name -p -C < $< > $@ + +src/shared/errno-to-name.h: src/shared/errno-list.txt + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' < $< > $@ + +# ------------------------------------------------------------------------------ systemd_SOURCES = \ - src/main.c + src/core/main.c systemd_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(UDEV_CFLAGS) + $(SECCOMP_CFLAGS) systemd_LDADD = \ - libsystemd-core.la + libsystemd-core.la \ + $(RT_LIBS) + +dist_pkgsysconf_DATA += \ + src/core/system.conf \ + src/core/user.conf + +dist_dbuspolicy_DATA += \ + src/core/org.freedesktop.systemd1.conf + +dist_dbussystemservice_DATA += \ + src/core/org.freedesktop.systemd1.service + +polkitpolicy_in_in_files += \ + src/core/org.freedesktop.systemd1.policy.in.in + +pkgconfigdata_DATA = \ + src/core/systemd.pc + +nodist_rpmmacros_DATA = \ + src/core/macros.systemd + +EXTRA_DIST += \ + src/core/systemd.pc.in \ + src/core/macros.systemd.in + +CLEANFILES += \ + src/core/macros.systemd \ + src/core/org.freedesktop.systemd1.policy.in + +# ------------------------------------------------------------------------------ +manual_tests += \ + test-engine \ + test-ns \ + test-loopback \ + test-hostname \ + test-daemon \ + test-cgroup \ + test-install \ + test-watchdog \ + test-log + +tests += \ + test-job-type \ + test-env-replace \ + test-strbuf \ + test-strv \ + test-path-util \ + test-strxcpyx \ + test-unit-name \ + test-unit-file \ + test-utf8 \ + test-ellipsize \ + test-util \ + test-tmpfiles \ + test-namespace \ + test-date \ + test-sleep \ + test-replace-var \ + test-sched-prio \ + test-calendarspec \ + test-strip-tab-ansi \ + test-cgroup-util \ + test-cgroup-mask \ + test-prioq \ + test-fileio \ + test-time \ + test-hashmap \ + test-list \ + test-tables \ + test-device-nodes \ + test-xml \ + test-architecture + +EXTRA_DIST += \ + test/sched_idle_bad.service \ + test/sched_idle_ok.service \ + test/sched_rr_bad.service \ + test/sched_rr_ok.service \ + test/sched_rr_change.service \ + test/son.service \ + test/daughter.service \ + test/parent.slice + +EXTRA_DIST += \ + src/test/test-helper.h + +test_device_nodes_SOURCES = \ + src/test/test-device-nodes.c + +test_device_nodes_LDADD = \ + libsystemd-shared.la test_engine_SOURCES = \ - src/test-engine.c + src/test/test-engine.c -test_engine_CFLAGS = $(systemd_CFLAGS) -test_engine_LDADD = $(systemd_LDADD) +test_engine_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_engine_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) test_job_type_SOURCES = \ - src/test-job-type.c + src/test/test-job-type.c + +test_job_type_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) -test_job_type_CFLAGS = $(systemd_CFLAGS) -test_job_type_LDADD = $(systemd_LDADD) +test_job_type_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) test_ns_SOURCES = \ - src/test-ns.c + src/test/test-ns.c -test_ns_CFLAGS = $(systemd_CFLAGS) -test_ns_LDADD = $(systemd_LDADD) +test_ns_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_ns_LDADD = \ + libsystemd-core.la test_loopback_SOURCES = \ - src/test-loopback.c \ - src/loopback-setup.c + src/test/test-loopback.c test_loopback_LDADD = \ - libsystemd-basic.la + libsystemd-core.la test_hostname_SOURCES = \ - src/test-hostname.c \ - src/hostname-setup.c + src/test/test-hostname.c test_hostname_LDADD = \ - libsystemd-basic.la + libsystemd-core.la + +if ENABLE_EFI +manual_tests += \ + test-boot-timestamp + +test_boot_timestamp_SOURCES = \ + src/test/test-boot-timestamps.c + +test_boot_timestamp_LDADD = \ + libsystemd-shared.la +endif + +test_unit_name_SOURCES = \ + src/test/test-unit-name.c + +test_unit_name_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_unit_name_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) + +test_unit_file_SOURCES = \ + src/test/test-unit-file.c + +test_unit_file_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_unit_file_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) + +test_utf8_SOURCES = \ + src/test/test-utf8.c + +test_utf8_LDADD = \ + libsystemd-shared.la + +test_util_SOURCES = \ + src/test/test-util.c + +test_util_LDADD = \ + libsystemd-core.la + +test_tmpfiles_SOURCES = \ + src/test/test-tmpfiles.c + +test_tmpfiles_LDADD = \ + libsystemd-shared.la + +test_namespace_SOURCES = \ + src/test/test-namespace.c + +test_namespace_LDADD = \ + libsystemd-core.la + +test_hashmap_SOURCES = \ + src/test/test-hashmap.c + +test_hashmap_LDADD = \ + libsystemd-core.la + +test_xml_SOURCES = \ + src/test/test-xml.c + +test_xml_LDADD = \ + libsystemd-shared.la + +test_list_SOURCES = \ + src/test/test-list.c + +test_list_LDADD = \ + libsystemd-core.la + +test_tables_SOURCES = \ + src/test/test-tables.c \ + src/shared/test-tables.h + +test_tables_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_tables_LDADD = \ + libsystemd-logs.la \ + libsystemd-journal-internal.la \ + libsystemd-core.la \ + $(RT_LIBS) + +test_prioq_SOURCES = \ + src/test/test-prioq.c + +test_prioq_LDADD = \ + libsystemd-core.la + +test_fileio_SOURCES = \ + src/test/test-fileio.c + +test_fileio_LDADD = \ + libsystemd-core.la + +test_time_SOURCES = \ + src/test/test-time.c + +test_time_LDADD = \ + libsystemd-core.la + +test_architecture_SOURCES = \ + src/test/test-architecture.c + +test_architecture_LDADD = \ + libsystemd-shared.la + +test_log_SOURCES = \ + src/test/test-log.c + +test_log_LDADD = \ + libsystemd-core.la + +test_ellipsize_SOURCES = \ + src/test/test-ellipsize.c + +test_ellipsize_LDADD = \ + libsystemd-core.la + +test_date_SOURCES = \ + src/test/test-date.c + +test_date_LDADD = \ + libsystemd-core.la + +test_sleep_SOURCES = \ + src/test/test-sleep.c + +test_sleep_LDADD = \ + libsystemd-core.la + +test_replace_var_SOURCES = \ + src/test/test-replace-var.c + +test_replace_var_LDADD = \ + libsystemd-shared.la + +test_calendarspec_SOURCES = \ + src/test/test-calendarspec.c + +test_calendarspec_LDADD = \ + libsystemd-shared.la + +test_strip_tab_ansi_SOURCES = \ + src/test/test-strip-tab-ansi.c + +test_strip_tab_ansi_LDADD = \ + libsystemd-shared.la test_daemon_SOURCES = \ - src/test-daemon.c + src/test/test-daemon.c test_daemon_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la + libsystemd-internal.la \ + libsystemd-shared.la test_cgroup_SOURCES = \ - src/test-cgroup.c \ - src/cgroup-util.c - -test_cgroup_CFLAGS = \ - $(AM_CFLAGS) + src/test/test-cgroup.c test_cgroup_LDADD = \ - libsystemd-basic.la + libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la -test_env_replace_SOURCES = \ - src/test-env-replace.c +test_cgroup_mask_SOURCES = \ + src/test/test-cgroup-mask.c -test_env_replace_CFLAGS = \ - $(AM_CFLAGS) +test_cgroup_mask_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DTEST_DIR=\"$(abs_top_srcdir)/test\" + +test_cgroup_mask_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_cgroup_mask_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) + +test_cgroup_util_SOURCES = \ + src/test/test-cgroup-util.c + +test_cgroup_util_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_env_replace_SOURCES = \ + src/test/test-env-replace.c test_env_replace_LDADD = \ - libsystemd-basic.la + libsystemd-shared.la -test_strv_SOURCES = \ - src/test-strv.c \ - src/specifier.c +test_strbuf_SOURCES = \ + src/test/test-strbuf.c -test_strv_CFLAGS = \ - $(AM_CFLAGS) +test_strbuf_LDADD = \ + libsystemd-shared.la + +test_strv_SOURCES = \ + src/test/test-strv.c test_strv_LDADD = \ - libsystemd-basic.la + libsystemd-units.la \ + libsystemd-internal.la \ + libsystemd-shared.la -test_login_SOURCES = \ - src/test-login.c +test_path_util_SOURCES = \ + src/test/test-path-util.c -test_login_CFLAGS = \ - $(AM_CFLAGS) +test_path_util_LDADD = \ + libsystemd-shared.la -test_login_LDADD = \ - libsystemd-basic.la \ - libsystemd-login.la +test_strxcpyx_SOURCES = \ + src/test/test-strxcpyx.c -test_install_SOURCES = \ - src/test-install.c \ - src/install.c \ - src/path-lookup.c \ - src/unit-name.c +test_strxcpyx_LDADD = \ + libsystemd-shared.la -test_install_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) +test_install_SOURCES = \ + src/test/test-install.c test_install_LDADD = \ - libsystemd-basic.la + libsystemd-units.la \ + libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la -systemd_stdout_syslog_bridge_SOURCES = \ - src/stdout-syslog-bridge.c \ - src/tcpwrap.c +test_watchdog_SOURCES = \ + src/test/test-watchdog.c -systemd_stdout_syslog_bridge_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(LIBWRAP_LIBS) +test_watchdog_LDADD = \ + libsystemd-shared.la -systemd_initctl_SOURCES = \ - src/initctl.c \ - src/dbus-common.c +test_sched_prio_SOURCES = \ + src/test/test-sched-prio.c + +test_sched_prio_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DTEST_DIR=\"$(abs_top_srcdir)/test\" -systemd_initctl_CFLAGS = \ +test_sched_prio_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) + $(SECCOMP_CFLAGS) + +test_sched_prio_LDADD = \ + libsystemd-core.la \ + $(RT_LIBS) + +# ------------------------------------------------------------------------------ +## .PHONY so it always rebuilds it +.PHONY: coverage lcov-run lcov-report coverage-sync + +# run lcov from scratch, always +coverage: + $(MAKE) lcov-run + $(MAKE) lcov-report + +coverage_dir = coverage +coverage_opts = --base-directory $(srcdir) --directory $(builddir) --rc 'geninfo_adjust_src_path=$(abspath $(srcdir))=>$(abspath $(builddir))' + +if ENABLE_COVERAGE +# reset run coverage tests +lcov-run: + @rm -rf $(coverage_dir) + lcov $(coverage_opts) --zerocounters + -$(MAKE) check + +# generate report based on current coverage data +lcov-report: + $(MKDIR_P) $(coverage_dir) + lcov $(coverage_opts) --compat-libtool --capture --no-external \ + | sed 's|$(abspath $(builddir))|$(abspath $(srcdir))|' > $(coverage_dir)/.lcov.info + genhtml -t "systemd test coverage" -o $(coverage_dir) $(coverage_dir)/.lcov.info + @echo "Coverage report generated in $(abs_builddir)/$(coverage_dir)/index.html" + +# lcov doesn't work properly with vpath builds, make sure that bad +# output is not uploaded by mistake. +coverage-sync: coverage + test "$(builddir)" = "$(srcdir)" + rsync -rlv --delete --omit-dir-times coverage/ $(www_target)/coverage + +else +lcov-run lcov-report: + echo "Need to reconfigure with --enable-coverage" +endif + +# ------------------------------------------------------------------------------ +systemd_analyze_SOURCES = \ + src/analyze/analyze.c + +systemd_analyze_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_initctl_SOURCES = \ + src/initctl/initctl.c systemd_initctl_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) + libsystemd-internal.la \ + libsystemd-shared.la +# ------------------------------------------------------------------------------ systemd_update_utmp_SOURCES = \ - src/update-utmp.c \ - src/dbus-common.c \ - src/utmp-wtmp.c + src/update-utmp/update-utmp.c systemd_update_utmp_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ $(AUDIT_CFLAGS) systemd_update_utmp_LDADD = \ - libsystemd-basic.la \ - $(DBUS_LIBS) \ + libsystemd-internal.la \ + libsystemd-shared.la \ $(AUDIT_LIBS) -systemd_random_seed_SOURCES = \ - src/random-seed.c - -systemd_random_seed_CFLAGS = \ - $(AM_CFLAGS) +# ------------------------------------------------------------------------------ +systemd_shutdownd_SOURCES = \ + src/shutdownd/shutdownd.c -systemd_random_seed_LDADD = \ - libsystemd-basic.la +systemd_shutdownd_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_shutdownd_SOURCES = \ - src/utmp-wtmp.c \ - src/shutdownd.c +dist_doc_DATA += \ + src/systemd/sd-shutdown.h -systemd_shutdownd_CFLAGS = \ - $(AM_CFLAGS) +# ------------------------------------------------------------------------------ +systemd_shutdown_SOURCES = \ + src/core/umount.c \ + src/core/umount.h \ + src/core/shutdown.c \ + src/core/mount-setup.c \ + src/core/mount-setup.h \ + src/core/killall.h \ + src/core/killall.c -systemd_shutdownd_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la +systemd_shutdown_LDADD = \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la -systemd_hostnamed_SOURCES = \ - src/hostnamed.c \ - src/dbus-common.c \ - src/polkit.c +# ------------------------------------------------------------------------------ +if HAVE_KMOD +systemd_modules_load_SOURCES = \ + src/modules-load/modules-load.c -systemd_hostnamed_CFLAGS = \ +systemd_modules_load_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) + $(KMOD_CFLAGS) -systemd_hostnamed_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) +systemd_modules_load_LDADD = \ + libsystemd-shared.la \ + $(KMOD_LIBS) -systemd_localed_SOURCES = \ - src/localed.c \ - src/dbus-common.c \ - src/polkit.c +rootlibexec_PROGRAMS += \ + systemd-modules-load -systemd_localed_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) +nodist_systemunit_DATA += \ + units/systemd-modules-load.service -systemd_localed_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) +SYSINIT_TARGET_WANTS += \ + systemd-modules-load.service + +if ENABLE_TMPFILES +nodist_systemunit_DATA += \ + units/kmod-static-nodes.service -dist_pkgdata_DATA = \ - src/kbd-model-map +SYSINIT_TARGET_WANTS += \ + kmod-static-nodes.service +endif +endif -dist_noinst_SCRIPT = \ - src/generate-kbd-model-map +EXTRA_DIST += \ + units/systemd-modules-load.service.in \ + units/kmod-static-nodes.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_TMPFILES +systemd_tmpfiles_SOURCES = \ + src/tmpfiles/tmpfiles.c + +systemd_tmpfiles_LDADD = \ + libsystemd-units.la \ + libsystemd-label.la \ + libsystemd-capability.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +rootbin_PROGRAMS += \ + systemd-tmpfiles + +dist_systemunit_DATA += \ + units/systemd-tmpfiles-clean.timer + +nodist_systemunit_DATA += \ + units/systemd-tmpfiles-setup-dev.service \ + units/systemd-tmpfiles-setup.service \ + units/systemd-tmpfiles-clean.service + +dist_tmpfiles_DATA = \ + tmpfiles.d/systemd.conf \ + tmpfiles.d/systemd-nologin.conf \ + tmpfiles.d/tmp.conf \ + tmpfiles.d/x11.conf + +if HAVE_SYSV_COMPAT +dist_tmpfiles_DATA += \ + tmpfiles.d/legacy.conf +endif + +SYSINIT_TARGET_WANTS += \ + systemd-tmpfiles-setup-dev.service \ + systemd-tmpfiles-setup.service + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_systemd-tmpfiles + +TIMERS_TARGET_WANTS += \ + systemd-tmpfiles-clean.timer + +INSTALL_DIRS += \ + $(tmpfilesdir) \ + $(sysconfdir)/tmpfiles.d +endif + +EXTRA_DIST += \ + units/systemd-tmpfiles-setup-dev.service.in \ + units/systemd-tmpfiles-setup.service.in \ + units/systemd-tmpfiles-clean.service.in + +# ------------------------------------------------------------------------------ +systemd_machine_id_setup_SOURCES = \ + src/machine-id-setup/machine-id-setup-main.c \ + src/core/machine-id-setup.c \ + src/core/machine-id-setup.h + +systemd_machine_id_setup_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_sysctl_SOURCES = \ + src/sysctl/sysctl.c + +systemd_sysctl_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_sleep_SOURCES = \ + src/sleep/sleep.c + +systemd_sleep_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_fsck_SOURCES = \ + src/fsck/fsck.c + +systemd_fsck_LDADD = \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_ac_power_SOURCES = \ + src/ac-power/ac-power.c + +systemd_ac_power_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_detect_virt_SOURCES = \ + src/detect-virt/detect-virt.c + +systemd_detect_virt_LDADD = \ + libsystemd-shared.la + +systemd-detect-virt-install-hook: + -$(SETCAP) cap_dac_override,cap_sys_ptrace=ep $(DESTDIR)$(bindir)/systemd-detect-virt + +INSTALL_EXEC_HOOKS += \ + systemd-detect-virt-install-hook + +# ------------------------------------------------------------------------------ +systemd_delta_SOURCES = \ + src/delta/delta.c + +systemd_delta_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_getty_generator_SOURCES = \ + src/getty-generator/getty-generator.c + +systemd_getty_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_fstab_generator_SOURCES = \ + src/fstab-generator/fstab-generator.c \ + src/core/mount-setup.c + +systemd_fstab_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_system_update_generator_SOURCES = \ + src/system-update-generator/system-update-generator.c + +systemd_system_update_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +if ENABLE_EFI +# ------------------------------------------------------------------------------ +systemgenerator_PROGRAMS += \ + systemd-efi-boot-generator + +systemd_efi_boot_generator_SOURCES = \ + src/efi-boot-generator/efi-boot-generator.c + +systemd_efi_boot_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +bootctl_SOURCES = \ + src/boot/boot.h \ + src/boot/boot-loader.h \ + src/boot/bootctl.c \ + src/boot/boot-loader.c \ + src/boot/boot-efi.c + +bootctl_LDADD = \ + libsystemd-shared.la \ + libsystemd-internal.la + +bin_PROGRAMS += \ + bootctl + +dist_bashcompletion_DATA += \ + shell-completion/bash/bootctl + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_bootctl + +endif + +# ------------------------------------------------------------------------------ +if HAVE_BLKID +systemgenerator_PROGRAMS += \ + systemd-gpt-auto-generator + +systemd_gpt_auto_generator_SOURCES = \ + src/gpt-auto-generator/gpt-auto-generator.c + +systemd_gpt_auto_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la \ + $(BLKID_LIBS) + +systemd_gpt_auto_generator_CFLAGS = \ + $(AM_CFLAGS) \ + $(BLKID_CFLAGS) +endif + +# ------------------------------------------------------------------------------ +if ENABLE_KDBUS +systemgenerator_PROGRAMS += \ + systemd-dbus1-generator + +systemd_dbus1_generator_SOURCES = \ + src/dbus1-generator/dbus1-generator.c + +systemd_dbus1_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la + +dbus1-generator-install-hook: + $(AM_V_at)$(MKDIR_P) $(DESTDIR)$(usergeneratordir) + $(AM_V_LN)$(LN_S) -f $(systemgeneratordir)/systemd-dbus1-generator $(DESTDIR)$(usergeneratordir)/systemd-dbus1-generator + +dbus1-generator-uninstall-hook: + rm -f $(DESTDIR)$(usergeneratordir)/systemd-dbus1-generator + +INSTALL_EXEC_HOOKS += dbus1-generator-install-hook +UNINSTALL_EXEC_HOOKS += dbus1-generator-uninstall-hook +endif + +# ------------------------------------------------------------------------------ +systemd_rc_local_generator_SOURCES = \ + src/rc-local-generator/rc-local-generator.c + +systemd_rc_local_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_remount_fs_SOURCES = \ + src/remount-fs/remount-fs.c \ + src/core/mount-setup.c \ + src/core/mount-setup.h + +systemd_remount_fs_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_cgroups_agent_SOURCES = \ + src/cgroups-agent/cgroups-agent.c + +systemd_cgroups_agent_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemctl_SOURCES = \ + src/systemctl/systemctl.c + +systemctl_LDADD = \ + libsystemd-units.la \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-logs.la \ + libsystemd-journal-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_notify_SOURCES = \ + src/notify/notify.c \ + src/readahead/sd-readahead.c + +systemd_notify_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_ask_password_SOURCES = \ + src/ask-password/ask-password.c + +systemd_ask_password_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_reply_password_SOURCES = \ + src/reply-password/reply-password.c + +systemd_reply_password_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_cgls_SOURCES = \ + src/cgls/cgls.c + +systemd_cgls_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_cgtop_SOURCES = \ + src/cgtop/cgtop.c + +systemd_cgtop_LDADD = \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_nspawn_SOURCES = \ + src/nspawn/nspawn.c \ + src/core/mount-setup.c \ + src/core/mount-setup.h \ + src/core/loopback-setup.c \ + src/core/loopback-setup.h + +systemd_nspawn_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +systemd_nspawn_LDADD = \ + libsystemd-label.la \ + libsystemd-capability.la \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la + +if HAVE_SECCOMP +systemd_nspawn_LDADD += \ + libsystemd-seccomp.la \ + $(SECCOMP_LIBS) +endif + +# ------------------------------------------------------------------------------ +systemd_run_SOURCES = \ + src/run/run.c + +systemd_run_LDADD = \ + libsystemd-label.la \ + libsystemd-capability.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_bus_proxyd_SOURCES = \ + src/bus-proxyd/bus-proxyd.c + +systemd_bus_proxyd_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +bus-proxyd-install-hook: + $(AM_V_at)$(MKDIR_P) $(DESTDIR)$(bindir) + $(AM_V_LN)$(LN_S) -f ../lib/systemd/systemd-bus-proxyd $(DESTDIR)$(bindir)/systemd-stdio-bridge + +bus-proxyd-uninstall-hook: + rm -f $(DESTDIR)$(bindir)/systemd-stdio-bridge + +INSTALL_EXEC_HOOKS += bus-proxyd-install-hook +UNINSTALL_EXEC_HOOKS += bus-proxyd-uninstall-hook + +if ENABLE_KDBUS +nodist_systemunit_DATA += \ + units/systemd-bus-proxyd@.service + +dist_systemunit_DATA += \ + units/systemd-bus-proxyd.socket + +dist_userunit_DATA += \ + units/user/systemd-bus-proxyd.socket \ + units/user/systemd-bus-proxyd@.service +endif + +EXTRA_DIST += \ + units/systemd-bus-proxyd@.service.in + +# ------------------------------------------------------------------------------ +systemd_tty_ask_password_agent_SOURCES = \ + src/tty-ask-password-agent/tty-ask-password-agent.c + +systemd_tty_ask_password_agent_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +libsystemd_internal_la_SOURCES = \ + src/systemd/sd-bus.h \ + src/systemd/sd-bus-protocol.h \ + src/systemd/sd-bus-vtable.h \ + src/systemd/sd-memfd.h \ + src/systemd/sd-utf8.h \ + src/systemd/sd-event.h \ + src/systemd/sd-rtnl.h \ + src/systemd/sd-resolve.h \ + src/systemd/sd-login.h \ + src/systemd/sd-id128.h \ + src/systemd/sd-daemon.h \ + src/libsystemd/sd-bus/sd-bus.c \ + src/libsystemd/sd-bus/bus-control.c \ + src/libsystemd/sd-bus/bus-control.h \ + src/libsystemd/sd-bus/bus-error.c \ + src/libsystemd/sd-bus/bus-error.h \ + src/libsystemd/sd-bus/bus-internal.c \ + src/libsystemd/sd-bus/bus-internal.h \ + src/libsystemd/sd-bus/bus-socket.c \ + src/libsystemd/sd-bus/bus-socket.h \ + src/libsystemd/sd-bus/bus-kernel.c \ + src/libsystemd/sd-bus/bus-kernel.h \ + src/libsystemd/sd-bus/bus-container.c \ + src/libsystemd/sd-bus/bus-container.h \ + src/libsystemd/sd-bus/bus-message.c \ + src/libsystemd/sd-bus/bus-message.h \ + src/libsystemd/sd-bus/bus-creds.c \ + src/libsystemd/sd-bus/bus-creds.h \ + src/libsystemd/sd-bus/bus-signature.c \ + src/libsystemd/sd-bus/bus-signature.h \ + src/libsystemd/sd-bus/bus-type.c \ + src/libsystemd/sd-bus/bus-type.h \ + src/libsystemd/sd-bus/bus-match.c \ + src/libsystemd/sd-bus/bus-match.h \ + src/libsystemd/sd-bus/bus-bloom.c \ + src/libsystemd/sd-bus/bus-bloom.h \ + src/libsystemd/sd-bus/bus-introspect.c \ + src/libsystemd/sd-bus/bus-introspect.h \ + src/libsystemd/sd-bus/bus-objects.c \ + src/libsystemd/sd-bus/bus-objects.h \ + src/libsystemd/sd-bus/bus-gvariant.c \ + src/libsystemd/sd-bus/bus-gvariant.h \ + src/libsystemd/sd-bus/bus-convenience.c \ + src/libsystemd/sd-bus/bus-util.c \ + src/libsystemd/sd-bus/bus-util.h \ + src/libsystemd/sd-bus/bus-protocol.h \ + src/libsystemd/sd-bus/kdbus.h \ + src/libsystemd/sd-bus/sd-memfd.c \ + src/libsystemd/sd-utf8/sd-utf8.c \ + src/libsystemd/sd-event/sd-event.c \ + src/libsystemd/sd-event/event-util.h \ + src/libsystemd/sd-rtnl/sd-rtnl.c \ + src/libsystemd/sd-rtnl/rtnl-internal.h \ + src/libsystemd/sd-rtnl/rtnl-message.c \ + src/libsystemd/sd-rtnl/rtnl-util.h \ + src/libsystemd/sd-rtnl/rtnl-util.c \ + src/libsystemd/sd-resolve/sd-resolve.c \ + src/libsystemd/sd-resolve/resolve-util.h \ + src/libsystemd/sd-id128/sd-id128.c \ + src/libsystemd/sd-daemon/sd-daemon.c \ + src/login/sd-login.c \ + src/login/login-shared.c \ + src/login/login-shared.h + +nodist_libsystemd_internal_la_SOURCES = \ + src/libsystemd/libsystemd.sym \ + src/libsystemd/sd-bus/bus-error-mapping.c + +libsystemd_internal_la_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + +libsystemd_internal_la_LIBADD = \ + $(RT_LIBS) + +noinst_LTLIBRARIES += \ + libsystemd-internal.la + +libsystemd_dump_la_SOURCES = \ + src/libsystemd/sd-bus/bus-dump.c \ + src/libsystemd/sd-bus/bus-dump.h + +libsystemd_dump_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + +noinst_LTLIBRARIES += \ + libsystemd-dump.la + +EXTRA_DIST += \ + src/libsystemd/libsystemd.sym.m4 \ + src/libsystemd/libsystemd.pc.in \ + src/libsystemd/sd-bus/bus-error-mapping.gperf \ + src/libsystemd/sd-bus/DIFFERENCES \ + src/libsystemd/sd-bus/GVARIANT-SERIALIZATION + +CLEANFILES += \ + src/libsystemd/libsystemd.sym \ + src/libsystemd/sd-bus/bus-error-mapping.c + +BUILT_SOURCES += \ + src/libsystemd/libsystemd.sym + +libsystemd_la_SOURCES = \ + $(libsystemd_internal_la_SOURCES) \ + $(libsystemd_journal_internal_la_SOURCES) + +nodist_libsystemd_la_SOURCES = \ + $(nodist_libsystemd_internal_la_SOURCES) + +libsystemd_la_CFLAGS = \ + $(libsystemd_internal_la_CFLAGS) \ + $(libsystemd_journal_internal_la_CFLAGS) + +libsystemd_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBSYSTEMD_CURRENT):$(LIBSYSTEMD_REVISION):$(LIBSYSTEMD_AGE) \ + -Wl,--version-script=$(top_builddir)/src/libsystemd/libsystemd.sym + +libsystemd_la_LIBADD = \ + libsystemd-shared.la \ + $(libsystemd_journal_internal_la_LIBADD) \ + $(RT_LIBS) \ + -lresolv + +libsystemd-install-hook: + libname=libsystemd.so && $(move-to-rootlibdir) + +libsystemd-uninstall-hook: + rm -f $(DESTDIR)$(rootlibdir)/libsystemd.so* + +INSTALL_EXEC_HOOKS += libsystemd-install-hook +UNINSTALL_EXEC_HOOKS += libsystemd-uninstall-hook + +pkgconfiglib_DATA += \ + src/libsystemd/libsystemd.pc + +pkginclude_HEADERS += \ + src/systemd/sd-login.h \ + src/systemd/sd-id128.h \ + src/systemd/sd-daemon.h + +if ENABLE_KDBUS +pkginclude_HEADERS += \ + src/systemd/sd-bus.h \ + src/systemd/sd-bus-protocol.h \ + src/systemd/sd-bus-vtable.h \ + src/systemd/sd-memfd.h \ + src/systemd/sd-utf8.h \ + src/systemd/sd-event.h \ + src/systemd/sd-rtnl.h \ + src/systemd/sd-resolve.h +endif + +lib_LTLIBRARIES += \ + libsystemd.la + +tests += \ + test-bus-marshal \ + test-bus-signature \ + test-bus-chat \ + test-bus-cleanup \ + test-bus-server \ + test-bus-match \ + test-bus-kernel \ + test-bus-kernel-bloom \ + test-bus-kernel-benchmark \ + test-bus-memfd \ + test-bus-zero-copy \ + test-bus-introspect \ + test-bus-objects \ + test-bus-error \ + test-bus-creds \ + test-bus-gvariant \ + test-event \ + test-rtnl \ + test-resolve + +bin_PROGRAMS += \ + busctl + +test_bus_marshal_SOURCES = \ + src/libsystemd/sd-bus/test-bus-marshal.c + +test_bus_marshal_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) \ + $(CAP_LIBS) + +test_bus_marshal_CFLAGS = \ + $(AM_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(CAP_CFLAGS) + +test_bus_signature_SOURCES = \ + src/libsystemd/sd-bus/test-bus-signature.c + +test_bus_signature_LDADD = \ + libsystemd-shared.la \ + libsystemd-internal.la + +test_bus_chat_SOURCES = \ + src/libsystemd/sd-bus/test-bus-chat.c + +test_bus_chat_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + +test_bus_chat_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_cleanup_SOURCES = \ + src/libsystemd/sd-bus/test-bus-cleanup.c + +test_bus_cleanup_CFLAGS = \ + $(AM_CFLAGS) \ + $(SECCOMP_CFLAGS) + +test_bus_cleanup_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_server_SOURCES = \ + src/libsystemd/sd-bus/test-bus-server.c + +test_bus_server_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + +test_bus_server_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_objects_SOURCES = \ + src/libsystemd/sd-bus/test-bus-objects.c + +test_bus_objects_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) \ + -pthread + +test_bus_objects_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(CAP_LIBS) + +test_bus_error_SOURCES = \ + src/libsystemd/sd-bus/test-bus-error.c + +test_bus_error_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_gvariant_SOURCES = \ + src/libsystemd/sd-bus/test-bus-gvariant.c + +test_bus_gvariant_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(GLIB_LIBS) \ + $(CAP_LIBS) + +test_bus_gvariant_CFLAGS = \ + $(AM_CFLAGS) \ + $(GLIB_CFLAGS) + $(CAP_CFLAGS) + +test_bus_creds_SOURCES = \ + src/libsystemd/sd-bus/test-bus-creds.c + +test_bus_creds_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la + +test_bus_match_SOURCES = \ + src/libsystemd/sd-bus/test-bus-match.c + +test_bus_match_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_kernel_SOURCES = \ + src/libsystemd/sd-bus/test-bus-kernel.c + +test_bus_kernel_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(CAP_LIBS) + +test_bus_kernel_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + +test_bus_kernel_bloom_SOURCES = \ + src/libsystemd/sd-bus/test-bus-kernel-bloom.c + +test_bus_kernel_bloom_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_kernel_benchmark_SOURCES = \ + src/libsystemd/sd-bus/test-bus-kernel-benchmark.c + +test_bus_kernel_benchmark_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_memfd_SOURCES = \ + src/libsystemd/sd-bus/test-bus-memfd.c + +test_bus_memfd_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_bus_zero_copy_SOURCES = \ + src/libsystemd/sd-bus/test-bus-zero-copy.c + +test_bus_zero_copy_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(CAP_LIBS) + +test_bus_zero_copy_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + +test_bus_introspect_SOURCES = \ + src/libsystemd/sd-bus/test-bus-introspect.c + +test_bus_introspect_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_event_SOURCES = \ + src/libsystemd/sd-event/test-event.c + +test_event_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_rtnl_SOURCES = \ + src/libsystemd/sd-rtnl/test-rtnl.c + +test_rtnl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_resolve_SOURCES = \ + src/systemd/sd-resolve.h \ + src/libsystemd/sd-resolve/test-resolve.c + +test_resolve_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + -lresolv + +test_resolve_CFLAGS = \ + $(AM_CFLAGS) \ + -pthread + +busctl_SOURCES = \ + src/libsystemd/sd-bus/busctl.c + +busctl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la \ + libsystemd-dump.la \ + libsystemd-capability.la \ + $(CAP_LIBS) + +busctl_CFLAGS = \ + $(AM_CFLAGS) \ + $(CAP_CFLAGS) + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libsystemd-dhcp.la + +libsystemd_dhcp_la_SOURCES = \ + src/systemd/sd-dhcp-client.h \ + src/libsystemd-dhcp/sd-dhcp-client.c \ + src/libsystemd-dhcp/dhcp-lease.h \ + src/libsystemd-dhcp/dhcp-lease.c \ + src/libsystemd-dhcp/dhcp-network.c \ + src/libsystemd-dhcp/dhcp-option.c \ + src/libsystemd-dhcp/dhcp-packet.c \ + src/libsystemd-dhcp/dhcp-internal.h \ + src/libsystemd-dhcp/dhcp-protocol.h + +libsystemd_dhcp_la_LIBADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_dhcp_option_SOURCES = \ + src/libsystemd-dhcp/dhcp-protocol.h \ + src/libsystemd-dhcp/dhcp-internal.h \ + src/libsystemd-dhcp/test-dhcp-option.c + +test_dhcp_option_LDADD = \ + libsystemd-dhcp.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +test_dhcp_client_SOURCES = \ + src/systemd/sd-dhcp-client.h \ + src/libsystemd-dhcp/dhcp-protocol.h \ + src/libsystemd-dhcp/dhcp-internal.h \ + src/libsystemd-dhcp/test-dhcp-client.c + +test_dhcp_client_LDADD = \ + libsystemd-dhcp.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +tests += \ + test-dhcp-option \ + test-dhcp-client + +# ------------------------------------------------------------------------------ +if ENABLE_GTK_DOC +SUBDIRS += \ + docs/libudev + +noinst_DATA += \ + docs/html/libudev \ + docs/html/gudev +endif + +include_HEADERS += \ + src/libudev/libudev.h + +lib_LTLIBRARIES += \ + libudev.la + +libudev_la_SOURCES =\ + src/libudev/libudev.sym \ + src/libudev/libudev-private.h \ + src/libudev/libudev.c \ + src/libudev/libudev-list.c \ + src/libudev/libudev-util.c \ + src/libudev/libudev-device.c \ + src/libudev/libudev-enumerate.c \ + src/libudev/libudev-monitor.c \ + src/libudev/libudev-queue.c \ + src/libudev/libudev-hwdb-def.h \ + src/libudev/libudev-hwdb.c + +libudev_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=hidden + +libudev_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/libudev/libudev.sym + +libudev_la_LIBADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +pkgconfiglib_DATA += \ + src/libudev/libudev.pc + +EXTRA_DIST += \ + src/libudev/libudev.pc.in + +CLEANFILES += \ + src/libudev/libudev.pc \ + docs/html/libudev \ + docs/html/gudev + +docs/html/libudev: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_LN)$(LN_S) -f ../libudev/html $@ + +docs/html/gudev: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_LN)$(LN_S) -f ../gudev/html $@ + +# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed +libudev-install-hook: + libname=libudev.so && $(move-to-rootlibdir) + +libudev-uninstall-hook: + rm -f $(DESTDIR)$(rootlibdir)/libudev.so* + +INSTALL_EXEC_HOOKS += libudev-install-hook +UNINSTALL_EXEC_HOOKS += libudev-uninstall-hook + +# ------------------------------------------------------------------------------ +noinst_LTLIBRARIES += \ + libudev-internal.la + +libudev_internal_la_SOURCES =\ + $(libudev_la_SOURCES) \ + src/libudev/libudev-device-private.c \ + src/libudev/libudev-queue-private.c + +libudev_internal_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=default + +# ------------------------------------------------------------------------------ +INSTALL_DIRS += \ + $(sysconfdir)/udev/rules.d \ + $(sysconfdir)/udev/hwdb.d + +dist_network_DATA = \ + network/99-default.link \ + network/80-container-host0.network + +dist_udevrules_DATA += \ + rules/99-systemd.rules \ + rules/42-usb-hid-pm.rules \ + rules/50-udev-default.rules \ + rules/60-drm.rules \ + rules/60-keyboard.rules \ + rules/60-persistent-storage-tape.rules \ + rules/60-persistent-serial.rules \ + rules/60-persistent-input.rules \ + rules/60-persistent-alsa.rules \ + rules/60-persistent-storage.rules \ + rules/64-btrfs.rules \ + rules/75-net-description.rules \ + rules/75-tty-description.rules \ + rules/78-sound-card.rules \ + rules/80-net-setup-link.rules \ + rules/95-udev-late.rules + +dist_udevhwdb_DATA = \ + hwdb/20-pci-vendor-model.hwdb \ + hwdb/20-pci-classes.hwdb \ + hwdb/20-usb-vendor-model.hwdb \ + hwdb/20-usb-classes.hwdb \ + hwdb/20-sdio-vendor-model.hwdb \ + hwdb/20-sdio-classes.hwdb \ + hwdb/20-bluetooth-vendor-product.hwdb \ + hwdb/20-acpi-vendor.hwdb \ + hwdb/20-OUI.hwdb \ + hwdb/20-net-ifname.hwdb \ + hwdb/60-keyboard.hwdb + +udevconfdir = $(sysconfdir)/udev +dist_udevconf_DATA = \ + src/udev/udev.conf + +sharepkgconfigdir = $(datadir)/pkgconfig +sharepkgconfig_DATA = \ + src/udev/udev.pc + +EXTRA_DIST += \ + rules/99-systemd.rules.in \ + src/udev/udev.pc.in + +CLEANFILES += \ + rules/99-systemd.rules \ + src/udev/udev.pc + +EXTRA_DIST += \ + units/systemd-udevd.service.in \ + units/systemd-udev-trigger.service.in \ + units/systemd-udev-settle.service.in + +CLEANFILES += \ + units/systemd-udevd.service \ + units/systemd-udev-trigger.service \ + units/systemd-udev-settle.service + +SOCKETS_TARGET_WANTS += \ + systemd-udevd-control.socket \ + systemd-udevd-kernel.socket +SYSINIT_TARGET_WANTS += \ + systemd-udevd.service \ + systemd-udev-trigger.service + +rootbin_PROGRAMS += \ + udevadm + +rootlibexec_PROGRAMS += \ + systemd-udevd + +noinst_LTLIBRARIES += \ + libudev-core.la + +src/udev/keyboard-keys.txt: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@ + +src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys.txt + $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print tolower(substr($$1 ,5)) ", " $$1 }' < $< > $@ + +src/udev/keyboard-keys-from-name.h: src/udev/keyboard-keys-from-name.gperf + $(AM_V_GPERF)$(GPERF) -L ANSI-C -t -N keyboard_lookup_key -H hash_key_name -p -C < $< > $@ + +src/udev/keyboard-keys-to-name.h: src/udev/keyboard-keys.txt + $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@ + +libudev_core_la_SOURCES = \ + src/udev/udev.h \ + src/udev/udev-event.c \ + src/udev/udev-watch.c \ + src/udev/udev-node.c \ + src/udev/udev-rules.c \ + src/udev/udev-ctrl.c \ + src/udev/udev-builtin.c \ + src/udev/udev-builtin-btrfs.c \ + src/udev/udev-builtin-hwdb.c \ + src/udev/udev-builtin-input_id.c \ + src/udev/udev-builtin-keyboard.c \ + src/udev/udev-builtin-net_id.c \ + src/udev/udev-builtin-net_setup_link.c \ + src/udev/udev-builtin-path_id.c \ + src/udev/udev-builtin-usb_id.c \ + src/udev/net/link-config.h \ + src/udev/net/link-config.c \ + src/udev/net/ethtool-util.h \ + src/udev/net/ethtool-util.c + +nodist_libudev_core_la_SOURCES = \ + src/udev/keyboard-keys-from-name.h \ + src/udev/keyboard-keys-to-name.h \ + src/udev/net/link-config-gperf.c + +BUILT_SOURCES += \ + $(nodist_libudev_core_la_SOURCES) + +CLEANFILES += \ + src/udev/keyboard-keys-from-name.gperf \ + src/udev/keyboard-keys.txt \ + src/udev/net/link-config-gperf.c + +EXTRA_DIST += \ + src/udev/net/link-config-gperf.gperf + +libudev_core_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(BLKID_CFLAGS) \ + $(KMOD_CFLAGS) + +libudev_core_la_LIBADD = \ + libudev-internal.la \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la \ + $(BLKID_LIBS) \ + $(KMOD_LIBS) + +libudev_core_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DFIRMWARE_PATH="$(FIRMWARE_PATH)" + +if ENABLE_FIRMWARE +libudev_core_la_SOURCES += \ + src/udev/udev-builtin-firmware.c + +dist_udevrules_DATA += \ + rules/50-firmware.rules +endif + +if HAVE_KMOD +libudev_core_la_SOURCES += \ + src/udev/udev-builtin-kmod.c + +dist_udevrules_DATA += \ + rules/80-drivers.rules +endif + +if HAVE_BLKID +libudev_core_la_SOURCES += \ + src/udev/udev-builtin-blkid.c +endif + +if HAVE_ACL +libudev_core_la_SOURCES += \ + src/udev/udev-builtin-uaccess.c \ + src/login/logind-acl.c \ + src/login/sd-login.c \ + src/systemd/sd-login.h \ + src/login/login-shared.c \ + src/login/login-shared.h + +libudev_core_la_LIBADD += \ + libsystemd-acl.la +endif + +systemd_udevd_SOURCES = \ + src/udev/udevd.c + +systemd_udevd_LDADD = \ + libudev-core.la + +udevadm_SOURCES = \ + src/udev/udevadm.c \ + src/udev/udevadm-info.c \ + src/udev/udevadm-control.c \ + src/udev/udevadm-monitor.c \ + src/udev/udevadm-hwdb.c \ + src/udev/udevadm-settle.c \ + src/udev/udevadm-trigger.c \ + src/udev/udevadm-test.c \ + src/udev/udevadm-test-builtin.c + +udevadm_LDADD = \ + libudev-core.la + +# Update hwdb on installation. Do not bother if installing +# in DESTDIR, since this is likely for packaging purposes. +hwdb-update-hook: + -test -n "$(DESTDIR)" || $(rootbindir)/udevadm hwdb --update + +INSTALL_DATA_HOOKS += \ + hwdb-update-hook + +hwdb-remove-hook: + -test -n "$(DESTDIR)" || rm -f /etc/udev/hwdb.bin + +# ------------------------------------------------------------------------------ +TESTS += \ + test/udev-test.pl \ + test/rules-test.sh + +manual_tests += \ + test-libudev \ + test-udev + +test_libudev_SOURCES = \ + src/test/test-libudev.c + +test_libudev_LDADD = \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la + +test_udev_SOURCES = \ + src/test/test-udev.c + +test_udev_LDADD = \ + libudev-core.la \ + $(BLKID_LIBS) \ + $(KMOD_LIBS) \ + $(SELINUX_LIBS) + +if HAVE_ACL +test_udev_LDADD += \ + libsystemd-acl.la +endif + +check_DATA += \ + test/sys + +# packed sysfs test tree +test/sys: + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)tar -C test/ -xJf $(top_srcdir)/test/sys.tar.xz + +test-sys-distclean: + -rm -rf test/sys +DISTCLEAN_LOCAL_HOOKS += test-sys-distclean + +EXTRA_DIST += \ + test/sys.tar.xz \ + test/udev-test.pl \ + test/rules-test.sh \ + test/rule-syntax-check.py + +# ------------------------------------------------------------------------------ +ata_id_SOURCES = \ + src/udev/ata_id/ata_id.c + +ata_id_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + ata_id + +# ------------------------------------------------------------------------------ +cdrom_id_SOURCES = \ + src/udev/cdrom_id/cdrom_id.c + +cdrom_id_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + cdrom_id + +dist_udevrules_DATA += \ + rules/60-cdrom_id.rules + +# ------------------------------------------------------------------------------ +collect_SOURCES = \ + src/udev/collect/collect.c + +collect_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + collect + +# ------------------------------------------------------------------------------ +scsi_id_SOURCES =\ + src/udev/scsi_id/scsi_id.c \ + src/udev/scsi_id/scsi_serial.c \ + src/udev/scsi_id/scsi.h \ + src/udev/scsi_id/scsi_id.h + +scsi_id_LDADD = \ + libudev-internal.la \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + scsi_id + +EXTRA_DIST += \ + src/udev/scsi_id/README + +# ------------------------------------------------------------------------------ +v4l_id_SOURCES = \ + src/udev/v4l_id/v4l_id.c + +v4l_id_LDADD = \ + libudev-internal.la + +udevlibexec_PROGRAMS += \ + v4l_id + +dist_udevrules_DATA += \ + rules/60-persistent-v4l.rules + +# ------------------------------------------------------------------------------ +accelerometer_SOURCES = \ + src/udev/accelerometer/accelerometer.c + +accelerometer_LDADD = \ + libudev-internal.la -lm \ + libsystemd-shared.la + +udevlibexec_PROGRAMS += \ + accelerometer + +dist_udevrules_DATA += \ + rules/61-accelerometer.rules + +# ------------------------------------------------------------------------------ +if ENABLE_GUDEV +if ENABLE_GTK_DOC +SUBDIRS += \ + docs/gudev +endif + +libgudev_includedir = \ + $(includedir)/gudev-1.0/gudev + +libgudev_include_HEADERS = \ + src/gudev/gudev.h \ + src/gudev/gudevenums.h \ + src/gudev/gudevenumtypes.h \ + src/gudev/gudevtypes.h \ + src/gudev/gudevclient.h \ + src/gudev/gudevdevice.h \ + src/gudev/gudevenumerator.h + +lib_LTLIBRARIES += libgudev-1.0.la + +pkgconfiglib_DATA += \ + src/gudev/gudev-1.0.pc + +CLEANFILES += \ + src/gudev/gudev-1.0.pc + +libgudev_1_0_la_SOURCES = \ + src/gudev/gudevenums.h \ + src/gudev/gudevenumtypes.h \ + src/gudev/gudevenumtypes.h\ + src/gudev/gudevtypes.h \ + src/gudev/gudevclient.h \ + src/gudev/gudevclient.c \ + src/gudev/gudevdevice.h \ + src/gudev/gudevdevice.c \ + src/gudev/gudevenumerator.h \ + src/gudev/gudevenumerator.c \ + src/gudev/gudevprivate.h + +nodist_libgudev_1_0_la_SOURCES = \ + src/gudev/gudevmarshal.h \ + src/gudev/gudevmarshal.c \ + src/gudev/gudevenumtypes.h \ + src/gudev/gudevenumtypes.c + +BUILT_SOURCES += \ + $(nodist_libgudev_1_0_la_SOURCES) + +libgudev_1_0_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_builddir)/src\ + -I$(top_srcdir)/src\ + -I$(top_builddir)/src/gudev \ + -I$(top_srcdir)/src/gudev \ + -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ + -D_GUDEV_COMPILATION \ + -DG_LOG_DOMAIN=\"GUdev\" + +libgudev_1_0_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=default \ + $(GLIB_CFLAGS) + +libgudev_1_0_la_LIBADD = \ + libudev.la \ + $(GLIB_LIBS) + +libgudev_1_0_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBGUDEV_CURRENT):$(LIBGUDEV_REVISION):$(LIBGUDEV_AGE) \ + -export-dynamic -no-undefined \ + -export-symbols-regex '^g_udev_.*' + +src/gudev/gudevmarshal.h: src/gudev/gudevmarshal.list + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@ + +src/gudev/gudevmarshal.c: src/gudev/gudevmarshal.list + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)echo '#include "gudevmarshal.h"' > $@ && \ + glib-genmarshal $< --prefix=g_udev_marshal --body >> $@ + +src/gudev/gudevenumtypes.%: src/gudev/gudevenumtypes.%.template src/gudev/gudevenums.h + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)glib-mkenums --template $^ > $@ + +if HAVE_INTROSPECTION +-include $(INTROSPECTION_MAKEFILE) + +src/gudev/GUdev-1.0.gir: libgudev-1.0.la + +src_gudev_GUdev_1_0_gir_INCLUDES = GObject-2.0 + +src_gudev_GUdev_1_0_gir_CFLAGS = \ + $(AM_CFLAGS) \ + $(INCLUDES) \ + -D_GUDEV_COMPILATION \ + -D_GUDEV_WORK_AROUND_DEV_T_BUG \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src/gudev \ + -I$(top_builddir)/src/gudev + +src_gudev_GUdev_1_0_gir_LIBS = libgudev-1.0.la + +src_gudev_GUdev_1_0_gir_SCANNERFLAGS = \ + --pkg-export=gudev-1.0 \ + --warn-all + +src_gudev_GUdev_1_0_gir_FILES = \ + src/gudev/gudev.h \ + src/gudev/gudevtypes.h \ + src/gudev/gudevenums.h \ + src/gudev/gudevenumtypes.h \ + src/gudev/gudevclient.h \ + src/gudev/gudevdevice.h \ + src/gudev/gudevenumerator.h \ + src/gudev/gudevclient.c \ + src/gudev/gudevdevice.c \ + src/gudev/gudevenumerator.c + +INTROSPECTION_GIRS = src/gudev/GUdev-1.0.gir +INTROSPECTION_SCANNER_ARGS = --c-include=gudev/gudev.h + +girdir = $(datadir)/gir-1.0 +gir_DATA = \ + src/gudev/GUdev-1.0.gir + +typelibsdir = $(libdir)/girepository-1.0 +typelibs_DATA = \ + src/gudev/GUdev-1.0.typelib + +CLEANFILES += $(gir_DATA) $(typelibs_DATA) +endif # HAVE_INTROSPECTION + +# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed +libgudev-install-hook: + libname=libgudev-1.0.so && $(move-to-rootlibdir) + +libgudev-uninstall-hook: + rm -f $(DESTDIR)$(rootlibdir)/libgudev-1.0.so* + +INSTALL_EXEC_HOOKS += libgudev-install-hook +UNINSTALL_EXEC_HOOKS += libgudev-uninstall-hook +endif + +EXTRA_DIST += \ + src/gudev/gudev-1.0.pc.in \ + src/gudev/gudevmarshal.list \ + src/gudev/gudevenumtypes.h.template \ + src/gudev/gudevenumtypes.c.template \ + src/gudev/gjs-example.js \ + src/gudev/seed-example-enum.js \ + src/gudev/seed-example.js + +# ------------------------------------------------------------------------------ +mtd_probe_SOURCES = \ + src/udev/mtd_probe/mtd_probe.c \ + src/udev/mtd_probe/mtd_probe.h \ + src/udev/mtd_probe/probe_smartmedia.c + +dist_udevrules_DATA += \ + rules/75-probe_mtd.rules + +udevlibexec_PROGRAMS += \ + mtd_probe + +# ------------------------------------------------------------------------------ +test_id128_SOURCES = \ + src/test/test-id128.c + +test_id128_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +tests += \ + test-id128 + +# ------------------------------------------------------------------------------ + +rootlibexec_PROGRAMS += \ + systemd-activate + +systemd_activate_SOURCES = \ + src/activate/activate.c + +systemd_activate_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +systemd_journald_SOURCES = \ + src/journal/journald.c \ + src/journal/journald-server.h + +systemd_journald_LDADD = \ + libsystemd-journal-core.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +systemd_cat_SOURCES = \ + src/journal/cat.c + +systemd_cat_LDADD = \ + libsystemd-journal-core.la + +# using _CFLAGS = in the conditional below would suppress AM_CFLAGS +journalctl_CFLAGS = \ + $(AM_CFLAGS) + +journalctl_SOURCES = \ + src/journal/journalctl.c + +journalctl_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-logs.la \ + libsystemd-shared.la + +if HAVE_ACL +journalctl_LDADD += \ + libsystemd-acl.la +endif + +if HAVE_QRENCODE +journalctl_SOURCES += \ + src/journal/journal-qrcode.c \ + src/journal/journal-qrcode.h + +journalctl_CFLAGS += \ + $(QRENCODE_CFLAGS) + +journalctl_LDADD += \ + $(QRENCODE_LIBS) +endif + +test_journal_SOURCES = \ + src/journal/test-journal.c + +test_journal_LDADD = \ + libsystemd-journal-core.la + +test_journal_send_SOURCES = \ + src/journal/test-journal-send.c + +test_journal_send_LDADD = \ + libsystemd-journal-core.la + +test_journal_syslog_SOURCES = \ + src/journal/test-journal-syslog.c + +test_journal_syslog_LDADD = \ + libsystemd-journal-core.la + +test_journal_match_SOURCES = \ + src/journal/test-journal-match.c + +test_journal_match_LDADD = \ + libsystemd-journal-core.la + +test_journal_enum_SOURCES = \ + src/journal/test-journal-enum.c + +test_journal_enum_LDADD = \ + libsystemd-journal-core.la + +test_journal_stream_SOURCES = \ + src/journal/test-journal-stream.c + +test_journal_stream_LDADD = \ + libsystemd-journal-core.la + +test_journal_flush_SOURCES = \ + src/journal/test-journal-flush.c + +test_journal_flush_LDADD = \ + libsystemd-journal-core.la + +test_journal_init_SOURCES = \ + src/journal/test-journal-init.c + +test_journal_init_LDADD = \ + libsystemd-journal-core.la + +test_journal_verify_SOURCES = \ + src/journal/test-journal-verify.c + +test_journal_verify_LDADD = \ + libsystemd-journal-core.la + +test_journal_interleaving_SOURCES = \ + src/journal/test-journal-interleaving.c + +test_journal_interleaving_LDADD = \ + libsystemd-journal-core.la + +test_mmap_cache_SOURCES = \ + src/journal/test-mmap-cache.c + +test_mmap_cache_LDADD = \ + libsystemd-journal-core.la + +test_catalog_SOURCES = \ + src/journal/test-catalog.c + +test_catalog_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DCATALOG_DIR=\"$(abs_top_srcdir)/catalog\" + +test_catalog_LDADD = \ + libsystemd-journal-core.la + +libsystemd_journal_core_la_SOURCES = \ + src/journal/journald-kmsg.c \ + src/journal/journald-kmsg.h \ + src/journal/journald-syslog.c \ + src/journal/journald-syslog.h \ + src/journal/journald-stream.c \ + src/journal/journald-stream.h \ + src/journal/journald-server.c \ + src/journal/journald-server.h \ + src/journal/journald-console.c \ + src/journal/journald-console.h \ + src/journal/journald-native.c \ + src/journal/journald-native.h \ + src/journal/journald-rate-limit.c \ + src/journal/journald-rate-limit.h \ + src/journal/journal-internal.h + +nodist_libsystemd_journal_core_la_SOURCES = \ + src/journal/journald-gperf.c + +libsystemd_journal_core_la_LIBADD = \ + libsystemd-journal-internal.la \ + libudev-internal.la \ + libsystemd-capability.la \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +if HAVE_ACL +libsystemd_journal_core_la_LIBADD += \ + libsystemd-acl.la +endif + +noinst_LTLIBRARIES += \ + libsystemd-journal-core.la + +journal-install-hook: + -$(MKDIR_P) $(DESTDIR)/var/log/journal + -chown 0:0 $(DESTDIR)/var/log/journal + -chmod 755 $(DESTDIR)/var/log/journal + -setfacl -nm g:adm:rx,d:g:adm:rx $(DESTDIR)/var/log/journal/ + -setfacl -nm g:wheel:rx,d:g:wheel:rx $(DESTDIR)/var/log/journal/ + +journal-uninstall-hook: + -rmdir $(DESTDIR)/var/log/journal/ + +INSTALL_EXEC_HOOKS += journal-install-hook +UNINSTALL_EXEC_HOOKS += journal-uninstall-hook + +# ------------------------------------------------------------------------------ +# Update catalog on installation. Do not bother if installing +# in DESTDIR, since this is likely for packaging purposes. +catalog-update-hook: + -test -n "$(DESTDIR)" || $(rootbindir)/journalctl --update-catalog + +INSTALL_DATA_HOOKS += \ + catalog-update-hook + +catalog-remove-hook: + -test -n "$(DESTDIR)" || rm -f $(catalogstatedir)/database + +UNINSTALL_DATA_HOOKS += \ + catalog-remove-hook + +manual_tests += \ + test-journal-enum + +tests += \ + test-journal \ + test-journal-send \ + test-journal-syslog \ + test-journal-match \ + test-journal-stream \ + test-journal-init \ + test-journal-verify \ + test-journal-interleaving \ + test-journal-flush \ + test-mmap-cache \ + test-catalog + +pkginclude_HEADERS += \ + src/systemd/sd-journal.h \ + src/systemd/sd-messages.h \ + src/systemd/_sd-common.h + +libsystemd_journal_internal_la_SOURCES = \ + src/journal/sd-journal.c \ + src/systemd/sd-journal.h \ + src/systemd/_sd-common.h \ + src/journal/journal-file.c \ + src/journal/journal-file.h \ + src/journal/journal-vacuum.c \ + src/journal/journal-vacuum.h \ + src/journal/journal-verify.c \ + src/journal/journal-verify.h \ + src/journal/lookup3.c \ + src/journal/lookup3.h \ + src/journal/journal-send.c \ + src/journal/journal-def.h \ + src/journal/compress.h \ + src/journal/catalog.c \ + src/journal/catalog.h \ + src/journal/mmap-cache.c \ + src/journal/mmap-cache.h + +# using _CFLAGS = in the conditional below would suppress AM_CFLAGS +libsystemd_journal_internal_la_CFLAGS = + $(AM_CFLAGS) + +libsystemd_journal_internal_la_LIBADD = + +if HAVE_XZ +libsystemd_journal_internal_la_SOURCES += \ + src/journal/compress.c + +libsystemd_journal_internal_la_CFLAGS += \ + $(XZ_CFLAGS) + +libsystemd_journal_internal_la_LIBADD += \ + $(XZ_LIBS) +endif + +if HAVE_GCRYPT +libsystemd_journal_internal_la_SOURCES += \ + src/journal/journal-authenticate.c \ + src/journal/journal-authenticate.h \ + src/journal/fsprg.c \ + src/journal/fsprg.h + +libsystemd_journal_internal_la_LIBADD += \ + $(GCRYPT_LIBS) + +# fsprg.c is a drop-in file using void pointer arithmetic +libsystemd_journal_internal_la_CFLAGS += \ + $(GCRYPT_CFLAGS) \ + -Wno-pointer-arith +endif + +noinst_LTLIBRARIES += \ + libsystemd-journal-internal.la + +rootlibexec_PROGRAMS += \ + systemd-journald + +rootbin_PROGRAMS += \ + journalctl + +bin_PROGRAMS += \ + systemd-cat + +dist_systemunit_DATA += \ + units/systemd-journald.socket + +nodist_systemunit_DATA += \ + units/systemd-journald.service \ + units/systemd-journal-flush.service + +dist_pkgsysconf_DATA += \ + src/journal/journald.conf + +dist_catalog_DATA = \ + catalog/systemd.fr.catalog \ + catalog/systemd.ru.catalog \ + catalog/systemd.it.catalog \ + catalog/systemd.catalog + +SOCKETS_TARGET_WANTS += \ + systemd-journald.socket +SYSINIT_TARGET_WANTS += \ + systemd-journald.service \ + systemd-journal-flush.service + +EXTRA_DIST += \ + units/systemd-journald.service.in \ + units/systemd-journal-flush.service.in \ + src/journal/journald-gperf.gperf + +CLEANFILES += \ + src/journal/journald-gperf.c + +# ------------------------------------------------------------------------------ +if HAVE_MICROHTTPD +gatewayddocumentrootdir=$(pkgdatadir)/gatewayd + +rootlibexec_PROGRAMS += \ + systemd-journal-gatewayd + +systemd_journal_gatewayd_SOURCES = \ + src/journal/journal-gatewayd.c \ + src/journal/microhttpd-util.h \ + src/journal/microhttpd-util.c + +systemd_journal_gatewayd_LDADD = \ + libsystemd-logs.la \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-shared.la \ + $(MICROHTTPD_LIBS) + +systemd_journal_gatewayd_CFLAGS = \ + $(AM_CFLAGS) \ + $(MICROHTTPD_CFLAGS) + +systemd_journal_gatewayd_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DDOCUMENT_ROOT=\"$(gatewayddocumentrootdir)\" + +dist_systemunit_DATA += \ + units/systemd-journal-gatewayd.socket + +nodist_systemunit_DATA += \ + units/systemd-journal-gatewayd.service + +dist_gatewayddocumentroot_DATA = \ + src/journal/browse.html + +endif + +EXTRA_DIST += \ + units/systemd-journal-gatewayd.service.in + +# ------------------------------------------------------------------------------ + +systemd_socket_proxyd_SOURCES = \ + src/socket-proxy/socket-proxyd.c + +systemd_socket_proxyd_LDADD = \ + libsystemd-logs.la \ + libsystemd-internal.la \ + libsystemd-journal-internal.la \ + libsystemd-shared.la + +# ------------------------------------------------------------------------------ +if ENABLE_COREDUMP +systemd_coredump_SOURCES = \ + src/journal/coredump.c + +systemd_coredump_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la + +rootlibexec_PROGRAMS += \ + systemd-coredump + +systemd_coredumpctl_SOURCES = \ + src/journal/coredumpctl.c + +systemd_coredumpctl_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +bin_PROGRAMS += \ + systemd-coredumpctl + +dist_bashcompletion_DATA += \ + shell-completion/bash/systemd-coredumpctl + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_systemd-coredumpctl + +sysctl_DATA = \ + sysctl.d/50-coredump.conf + +CLEANFILES += \ + sysctl.d/50-coredump.conf +endif + +EXTRA_DIST += \ + sysctl.d/50-coredump.conf.in + +# ------------------------------------------------------------------------------ +if ENABLE_BINFMT +systemd_binfmt_SOURCES = \ + src/binfmt/binfmt.c + +systemd_binfmt_LDADD = \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-binfmt + +dist_systemunit_DATA += \ + units/proc-sys-fs-binfmt_misc.automount \ + units/proc-sys-fs-binfmt_misc.mount + +nodist_systemunit_DATA += \ + units/systemd-binfmt.service + +INSTALL_DIRS += \ + $(prefix)/lib/binfmt.d \ + $(sysconfdir)/binfmt.d + +SYSINIT_TARGET_WANTS += \ + systemd-binfmt.service \ + proc-sys-fs-binfmt_misc.automount + +endif + +EXTRA_DIST += \ + units/systemd-binfmt.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_VCONSOLE +systemd_vconsole_setup_SOURCES = \ + src/vconsole/vconsole-setup.c + +systemd_vconsole_setup_LDADD = \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-vconsole-setup + +nodist_systemunit_DATA += \ + units/systemd-vconsole-setup.service + +SYSINIT_TARGET_WANTS += \ + systemd-vconsole-setup.service +endif + +EXTRA_DIST += \ + units/systemd-vconsole-setup.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_READAHEAD +systemd_readahead_SOURCES = \ + src/readahead/readahead.c \ + src/readahead/readahead-collect.c \ + src/readahead/readahead-replay.c \ + src/readahead/readahead-analyze.c \ + src/readahead/readahead-common.c \ + src/readahead/readahead-common.h + +systemd_readahead_LDADD = \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la + +dist_doc_DATA += \ + src/readahead/sd-readahead.c \ + src/systemd/sd-readahead.h + +rootlibexec_PROGRAMS += \ + systemd-readahead + +dist_systemunit_DATA += \ + units/systemd-readahead-drop.service \ + units/systemd-readahead-done.timer + +nodist_systemunit_DATA += \ + units/systemd-readahead-collect.service \ + units/systemd-readahead-replay.service \ + units/systemd-readahead-done.service + +endif + +EXTRA_DIST += \ + units/systemd-readahead-collect.service.in \ + units/systemd-readahead-replay.service.in \ + units/systemd-readahead-done.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_BOOTCHART +systemd_bootchart_SOURCES = \ + src/bootchart/bootchart.c \ + src/bootchart/bootchart.h \ + src/bootchart/store.c \ + src/bootchart/store.h \ + src/bootchart/svg.c \ + src/bootchart/svg.h + +systemd_bootchart_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-bootchart + +dist_pkgsysconf_DATA += \ + src/bootchart/bootchart.conf +endif + +# ------------------------------------------------------------------------------ +if ENABLE_QUOTACHECK +rootlibexec_PROGRAMS += \ + systemd-quotacheck + +nodist_systemunit_DATA += \ + units/systemd-quotacheck.service + +systemd_quotacheck_SOURCES = \ + src/quotacheck/quotacheck.c + +systemd_quotacheck_LDADD = \ + libsystemd-shared.la +endif + +EXTRA_DIST += \ + units/systemd-quotacheck.service.in + +nodist_systemunit_DATA += \ + units/quotaon.service + +# ------------------------------------------------------------------------------ +if ENABLE_RANDOMSEED +rootlibexec_PROGRAMS += \ + systemd-random-seed + +nodist_systemunit_DATA += \ + units/systemd-random-seed.service + +systemd_random_seed_SOURCES = \ + src/random-seed/random-seed.c + +systemd_random_seed_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +SYSINIT_TARGET_WANTS += \ + systemd-random-seed.service + +endif + +EXTRA_DIST += \ + units/systemd-random-seed.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_BACKLIGHT +rootlibexec_PROGRAMS += \ + systemd-backlight + +nodist_systemunit_DATA += \ + units/systemd-backlight@.service + +systemd_backlight_SOURCES = \ + src/backlight/backlight.c + +systemd_backlight_LDADD = \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la +endif + +EXTRA_DIST += \ + units/systemd-backlight@.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_RFKILL +rootlibexec_PROGRAMS += \ + systemd-rfkill + +nodist_systemunit_DATA += \ + units/systemd-rfkill@.service + +systemd_rfkill_SOURCES = \ + src/rfkill/rfkill.c + +systemd_rfkill_LDADD = \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la +endif + +EXTRA_DIST += \ + units/systemd-rfkill@.service.in + +# ------------------------------------------------------------------------------ +if HAVE_LIBCRYPTSETUP +rootlibexec_PROGRAMS += \ + systemd-cryptsetup + +systemgenerator_PROGRAMS += \ + systemd-cryptsetup-generator + +dist_systemunit_DATA += \ + units/cryptsetup.target + +systemd_cryptsetup_SOURCES = \ + src/cryptsetup/cryptsetup.c + +systemd_cryptsetup_CFLAGS = \ + $(AM_CFLAGS) \ + $(LIBCRYPTSETUP_CFLAGS) + +systemd_cryptsetup_LDADD = \ + libsystemd-label.la \ + libudev-internal.la \ + libsystemd-shared.la \ + $(LIBCRYPTSETUP_LIBS) + +systemd_cryptsetup_generator_SOURCES = \ + src/cryptsetup/cryptsetup-generator.c + +systemd_cryptsetup_generator_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la + +SYSINIT_TARGET_WANTS += \ + cryptsetup.target + +endif + +# ------------------------------------------------------------------------------ +if ENABLE_HOSTNAMED +systemd_hostnamed_SOURCES = \ + src/hostname/hostnamed.c + +systemd_hostnamed_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-hostnamed + +nodist_systemunit_DATA += \ + units/systemd-hostnamed.service + +dist_systemunit_DATA += \ + units/org.freedesktop.hostname1.busname + +dist_dbuspolicy_DATA += \ + src/hostname/org.freedesktop.hostname1.conf + +dist_dbussystemservice_DATA += \ + src/hostname/org.freedesktop.hostname1.service + +polkitpolicy_files += \ + src/hostname/org.freedesktop.hostname1.policy + +SYSTEM_UNIT_ALIASES += \ + systemd-hostnamed.service dbus-org.freedesktop.hostname1.service + +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.hostname1.busname + +hostnamectl_SOURCES = \ + src/hostname/hostnamectl.c + +hostnamectl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +bin_PROGRAMS += \ + hostnamectl + +dist_bashcompletion_DATA += \ + shell-completion/bash/hostnamectl + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_hostnamectl + +endif + +polkitpolicy_in_files += \ + src/hostname/org.freedesktop.hostname1.policy.in + +EXTRA_DIST += \ + units/systemd-hostnamed.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_KDBUS +systemd_bus_driverd_SOURCES = \ + src/bus-driverd/bus-driverd.c + +systemd_bus_driverd_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-bus-driverd + +nodist_systemunit_DATA += \ + units/systemd-bus-driverd.service + +dist_systemunit_DATA += \ + units/org.freedesktop.DBus.busname + +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.DBus.busname + +nodist_userunit_DATA += \ + units/user/systemd-bus-driverd.service + +USER_BUSNAMES_TARGET_WANTS += \ + org.freedesktop.DBus.busname + +USER_UNIT_ALIASES += \ + $(systemunitdir)/org.freedesktop.DBus.busname org.freedesktop.DBus.busname +endif + +EXTRA_DIST += \ + units/systemd-bus-driverd.service.in \ + units/user/systemd-bus-driverd.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_LOCALED +systemd_localed_SOURCES = \ + src/locale/localed.c + +systemd_localed_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +nodist_systemunit_DATA += \ + units/systemd-localed.service + +dist_systemunit_DATA += \ + units/org.freedesktop.locale1.busname + +rootlibexec_PROGRAMS += \ + systemd-localed + +dist_dbuspolicy_DATA += \ + src/locale/org.freedesktop.locale1.conf + +dist_dbussystemservice_DATA += \ + src/locale/org.freedesktop.locale1.service + +polkitpolicy_files += \ + src/locale/org.freedesktop.locale1.policy + +SYSTEM_UNIT_ALIASES += \ + systemd-localed.service dbus-org.freedesktop.locale1.service + +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.locale1.busname + +dist_pkgdata_DATA += \ + src/locale/kbd-model-map + +dist_noinst_SCRIPT = \ + src/locale/generate-kbd-model-map + +update-kbd-model-map: src/locale/generate-kbd-model-map + $PYTHON $< >src/locale/kbd-model-map + +localectl_SOURCES = \ + src/locale/localectl.c + +localectl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +bin_PROGRAMS += \ + localectl + +dist_bashcompletion_DATA += \ + shell-completion/bash/localectl + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_localectl + +endif + +.PHONY: update-kbd-model-map + +polkitpolicy_in_files += \ + src/locale/org.freedesktop.locale1.policy.in + +EXTRA_DIST += \ + units/systemd-localed.service.in + +# ------------------------------------------------------------------------------ +if ENABLE_TIMEDATED +systemd_timedated_SOURCES = \ + src/timedate/timedated.c + +systemd_timedated_LDADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libsystemd-shared.la + +rootlibexec_PROGRAMS += \ + systemd-timedated + +dist_dbussystemservice_DATA += \ + src/timedate/org.freedesktop.timedate1.service + +dist_dbuspolicy_DATA += \ + src/timedate/org.freedesktop.timedate1.conf + +nodist_systemunit_DATA += \ + units/systemd-timedated.service + +dist_systemunit_DATA += \ + units/org.freedesktop.timedate1.busname + +polkitpolicy_files += \ + src/timedate/org.freedesktop.timedate1.policy + +INSTALL_DIRS += \ + $(prefix)/lib/systemd/ntp-units.d \ + $(sysconfdir)/systemd/ntp-units.d + +SYSTEM_UNIT_ALIASES += \ + systemd-timedated.service dbus-org.freedesktop.timedate1.service + +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.timedate1.busname + +timedatectl_SOURCES = \ + src/timedate/timedatectl.c + +timedatectl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +bin_PROGRAMS += \ + timedatectl + +dist_bashcompletion_DATA += \ + shell-completion/bash/timedatectl + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_timedatectl +endif + +polkitpolicy_in_files += \ + src/timedate/org.freedesktop.timedate1.policy.in + +EXTRA_DIST += \ + units/systemd-timedated.service.in + +# ------------------------------------------------------------------------------ +if HAVE_MYHOSTNAME +libnss_myhostname_la_SOURCES = \ + src/nss-myhostname/nss-myhostname.c \ + src/nss-myhostname/ifconf.h \ + src/nss-myhostname/netlink.c + +libnss_myhostname_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -module \ + -export-dynamic \ + -avoid-version \ + -shared \ + -shrext .so.2 + +lib_LTLIBRARIES += \ + libnss_myhostname.la +endif + +# ------------------------------------------------------------------------------ +if ENABLE_MACHINED +systemd_machined_SOURCES = \ + src/machine/machined.c \ + src/machine/machined.h + +systemd_machined_LDADD = \ + libsystemd-machine-core.la + +rootlibexec_PROGRAMS += \ + systemd-machined + +libsystemd_machine_core_la_SOURCES = \ + src/machine/machined-dbus.c \ + src/machine/machine.c \ + src/machine/machine.h \ + src/machine/machine-dbus.c + +libsystemd_machine_core_la_LIBADD = \ + libsystemd-label.la \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la + +noinst_LTLIBRARIES += \ + libsystemd-machine-core.la + +machinectl_SOURCES = \ + src/machine/machinectl.c + +machinectl_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +rootbin_PROGRAMS += \ + machinectl + +dist_bashcompletion_DATA += \ + shell-completion/bash/machinectl + +test_machine_tables_SOURCES = \ + src/machine/test-machine-tables.c + +test_machine_tables_LDADD = \ + libsystemd-machine-core.la + +tests += \ + test-machine-tables + +nodist_systemunit_DATA += \ + units/systemd-machined.service + +dist_systemunit_DATA += \ + units/machine.slice \ + units/org.freedesktop.machine1.busname + +dist_dbussystemservice_DATA += \ + src/machine/org.freedesktop.machine1.service + +dist_dbuspolicy_DATA += \ + src/machine/org.freedesktop.machine1.conf + +dist_zshcompletion_DATA += \ + shell-completion/zsh/_machinectl + +SYSTEM_UNIT_ALIASES += \ + systemd-machined.service dbus-org.freedesktop.machine1.service + +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.machine1.busname + +EXTRA_DIST += \ + units/systemd-machined.service.in + +endif + +# ------------------------------------------------------------------------------ +if ENABLE_NETWORKD +rootlibexec_PROGRAMS += \ + systemd-networkd + +systemd_networkd_SOURCES = \ + src/network/networkd.h \ + src/network/networkd.c \ + src/network/networkd-link.c \ + src/network/networkd-netdev.c \ + src/network/networkd-network.c \ + src/network/networkd-address.c \ + src/network/networkd-route.c \ + src/network/networkd-manager.c + +nodist_systemd_networkd_SOURCES = \ + src/network/networkd-network-gperf.c \ + src/network/networkd-netdev-gperf.c + +systemd_networkd_LDADD = \ + libudev-internal.la \ + libsystemd-internal.la \ + libsystemd-dhcp.la \ + libsystemd-label.la \ + libsystemd-shared.la -systemd_timedated_SOURCES = \ - src/timedated.c \ - src/dbus-common.c \ - src/polkit.c +nodist_systemunit_DATA += \ + units/systemd-networkd.service + +GENERAL_ALIASES += \ + $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-networkd.service + +test_network_SOURCES = \ + src/network/test-network.c \ + src/network/networkd.h \ + src/network/networkd-link.c \ + src/network/networkd-netdev.c \ + src/network/networkd-network.c \ + src/network/networkd-address.c \ + src/network/networkd-route.c \ + src/network/networkd-manager.c \ + src/network/networkd-network-gperf.c \ + src/network/networkd-netdev-gperf.c + +test_network_LDADD = \ + libudev-internal.la \ + libsystemd-internal.la \ + libsystemd-dhcp.la \ + libsystemd-label.la \ + libsystemd-shared.la + +tests += \ + test-network -systemd_timedated_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) +EXTRA_DIST += \ + src/network/networkd-network-gperf.gperf \ + src/network/networkd-netdev-gperf.gperf \ + units/systemd-networkd.service.in -systemd_timedated_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) +CLEANFILES += \ + src/network/networkd-network-gperf.c \ + src/network/networkd-netdev-gperf.c +endif +# ------------------------------------------------------------------------------ +if ENABLE_LOGIND systemd_logind_SOURCES = \ - src/logind.c \ - src/logind-dbus.c \ - src/logind-device.c \ - src/logind-seat.c \ - src/logind-seat-dbus.c \ - src/logind-session.c \ - src/logind-session-dbus.c \ - src/logind-user.c \ - src/logind-user-dbus.c \ - src/dbus-common.c \ - src/dbus-loop.c \ - src/cgroup-util.c \ - src/polkit.c + src/login/logind.c \ + src/login/logind.h nodist_systemd_logind_SOURCES = \ - src/logind-gperf.c - -EXTRA_DIST += \ - src/logind-gperf.gperf - -systemd_logind_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(UDEV_CFLAGS) \ - $(ACL_CFLAGS) + src/login/logind-gperf.c systemd_logind_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) \ - $(UDEV_LIBS) \ - $(ACL_LIBS) - -systemd_uaccess_SOURCES = \ - src/uaccess.c + libsystemd-logind-core.la + +libsystemd_logind_core_la_SOURCES = \ + src/login/logind-core.c \ + src/login/logind-device.c \ + src/login/logind-device.h \ + src/login/logind-button.c \ + src/login/logind-button.h \ + src/login/logind-action.c \ + src/login/logind-action.h \ + src/login/logind-seat.c \ + src/login/logind-seat.h \ + src/login/logind-session.c \ + src/login/logind-session.h \ + src/login/logind-session-device.c \ + src/login/logind-session-device.h \ + src/login/logind-user.c \ + src/login/logind-user.h \ + src/login/logind-inhibit.c \ + src/login/logind-inhibit.h \ + src/login/logind-dbus.c \ + src/login/logind-session-dbus.c \ + src/login/logind-seat-dbus.c \ + src/login/logind-user-dbus.c \ + src/login/logind-acl.h \ + src/login/login-shared.c \ + src/login/login-shared.h + +libsystemd_logind_core_la_LIBADD = \ + libsystemd-label.la \ + libsystemd-capability.la \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la if HAVE_ACL -systemd_logind_SOURCES += \ - src/logind-acl.c +libsystemd_logind_core_la_SOURCES += \ + src/login/logind-acl.c -systemd_uaccess_SOURCES += \ - src/logind-acl.c +libsystemd_logind_core_la_LIBADD += \ + libsystemd-acl.la endif -systemd_uaccess_CFLAGS = \ - $(AM_CFLAGS) \ - $(UDEV_CFLAGS) \ - $(ACL_CFLAGS) +noinst_LTLIBRARIES += \ + libsystemd-logind-core.la -systemd_uaccess_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - libsystemd-login.la \ - $(UDEV_LIBS) \ - $(ACL_LIBS) +systemd_user_sessions_SOURCES = \ + src/login/user-sessions.c -systemd_shutdown_SOURCES = \ - src/mount-setup.c \ - src/umount.c \ - src/shutdown.c +systemd_user_sessions_LDADD = \ + libsystemd-shared.la -systemd_shutdown_CFLAGS = \ - $(AM_CFLAGS) \ - $(UDEV_CFLAGS) +rootlibexec_PROGRAMS += \ + systemd-logind \ + systemd-user-sessions -systemd_shutdown_LDADD = \ - libsystemd-basic.la \ - $(UDEV_LIBS) +loginctl_SOURCES = \ + src/login/loginctl.c \ + src/login/sysfs-show.c -systemd_modules_load_SOURCES = \ - src/modules-load.c +loginctl_LDADD = \ + libsystemd-internal.la \ + libudev-internal.la \ + libsystemd-shared.la -systemd_modules_load_CFLAGS = \ - $(AM_CFLAGS) +rootbin_PROGRAMS += \ + loginctl -systemd_modules_load_LDADD = \ - libsystemd-basic.la +dist_bashcompletion_DATA += \ + shell-completion/bash/loginctl -systemd_tmpfiles_SOURCES = \ - src/tmpfiles.c +dist_zshcompletion_DATA += \ + shell-completion/zsh/_loginctl \ + shell-completion/zsh/_systemd-inhibit -systemd_tmpfiles_CFLAGS = \ - $(AM_CFLAGS) +systemd_inhibit_SOURCES = \ + src/login/inhibit.c -systemd_tmpfiles_LDADD = \ - libsystemd-basic.la +systemd_inhibit_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_machine_id_setup_SOURCES = \ - src/machine-id-setup.c \ - src/machine-id-main.c +rootbin_PROGRAMS += \ + systemd-inhibit -systemd_machine_id_setup_CFLAGS = \ - $(AM_CFLAGS) +test_login_SOURCES = \ + src/login/test-login.c -systemd_machine_id_setup_LDADD = \ - libsystemd-basic.la +test_login_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_sysctl_SOURCES = \ - src/sysctl.c +test_login_shared_SOURCES = \ + src/login/test-login-shared.c -systemd_sysctl_CFLAGS = \ - $(AM_CFLAGS) +test_login_shared_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_sysctl_LDADD = \ - libsystemd-basic.la +test_inhibit_SOURCES = \ + src/login/test-inhibit.c -systemd_binfmt_SOURCES = \ - src/binfmt.c +test_inhibit_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_binfmt_CFLAGS = \ - $(AM_CFLAGS) +test_login_tables_SOURCES = \ + src/login/test-login-tables.c -systemd_binfmt_LDADD = \ - libsystemd-basic.la +test_login_tables_LDADD = \ + libsystemd-logind-core.la -systemd_fsck_SOURCES = \ - src/fsck.c \ - src/dbus-common.c +manual_tests += \ + test-login \ + test-inhibit -systemd_fsck_CFLAGS = \ - $(AM_CFLAGS) \ - $(UDEV_CFLAGS) \ - $(DBUS_CFLAGS) +tests += \ + test-login-tables \ + test-login-shared -systemd_fsck_LDADD = \ - libsystemd-basic.la \ - $(UDEV_LIBS) \ - $(DBUS_LIBS) +if HAVE_PAM +pam_systemd_la_SOURCES = \ + src/login/pam-module.c -systemd_quotacheck_SOURCES = \ - src/quotacheck.c +pam_systemd_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(PAM_CFLAGS) \ + -fvisibility=hidden -systemd_quotacheck_CFLAGS = \ - $(AM_CFLAGS) +pam_systemd_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -module \ + -export-dynamic \ + -avoid-version \ + -shared \ + -export-symbols-regex '^pam_sm_.*' -systemd_quotacheck_LDADD = \ - libsystemd-basic.la +pam_systemd_la_LIBADD = \ + libsystemd-capability.la \ + libsystemd-internal.la \ + libsystemd-shared.la \ + $(PAM_LIBS) -systemd_timestamp_SOURCES = \ - src/timestamp.c +pamlib_LTLIBRARIES = \ + pam_systemd.la -systemd_timestamp_CFLAGS = \ - $(AM_CFLAGS) +dist_pamconf_DATA = \ + src/login/systemd-user +endif -systemd_timestamp_LDADD = \ - libsystemd-basic.la +nodist_systemunit_DATA += \ + units/systemd-logind.service \ + units/systemd-user-sessions.service -systemd_ac_power_SOURCES = \ - src/ac-power.c +dist_systemunit_DATA += \ + units/user.slice \ + units/org.freedesktop.login1.busname -systemd_ac_power_CFLAGS = \ - $(AM_CFLAGS) \ - $(UDEV_CFLAGS) +dist_dbussystemservice_DATA += \ + src/login/org.freedesktop.login1.service -systemd_ac_power_LDADD = \ - libsystemd-basic.la \ - $(UDEV_LIBS) +dist_dbuspolicy_DATA += \ + src/login/org.freedesktop.login1.conf -systemd_detect_virt_SOURCES = \ - src/detect-virt.c +dist_pkgsysconf_DATA += \ + src/login/logind.conf -systemd_detect_virt_CFLAGS = \ - $(AM_CFLAGS) +polkitpolicy_files += \ + src/login/org.freedesktop.login1.policy -systemd_detect_virt_LDADD = \ - libsystemd-basic.la +INSTALL_DIRS += \ + $(systemdstatedir) -systemd_cryptsetup_SOURCES = \ - src/cryptsetup.c \ - src/ask-password-api.c +MULTI_USER_TARGET_WANTS += \ + systemd-logind.service \ + systemd-user-sessions.service -systemd_cryptsetup_CFLAGS = \ - $(LIBCRYPTSETUP_CFLAGS) \ - $(UDEV_CFLAGS) \ - $(AM_CFLAGS) +SYSTEM_UNIT_ALIASES += \ + systemd-logind.service dbus-org.freedesktop.login1.service -systemd_cryptsetup_LDADD = \ - $(LIBCRYPTSETUP_LIBS) \ - $(UDEV_LIBS) \ - libsystemd-basic.la +BUSNAMES_TARGET_WANTS += \ + org.freedesktop.login1.busname -systemd_cryptsetup_generator_SOURCES = \ - src/cryptsetup-generator.c \ - src/unit-name.c +if ENABLE_MULTI_SEAT_X -systemd_cryptsetup_generator_CFLAGS = \ - $(AM_CFLAGS) +systemd_multi_seat_x_SOURCES = \ + src/login/multi-seat-x.c -systemd_cryptsetup_generator_LDADD = \ - libsystemd-basic.la +systemd_multi_seat_x_LDADD = \ + libsystemd-label.la \ + libsystemd-shared.la -systemd_getty_generator_SOURCES = \ - src/getty-generator.c \ - src/unit-name.c +rootlibexec_PROGRAMS += \ + systemd-multi-seat-x -systemd_getty_generator_CFLAGS = \ - $(AM_CFLAGS) +endif -systemd_getty_generator_LDADD = \ - libsystemd-basic.la +dist_udevrules_DATA += \ + src/login/70-uaccess.rules \ + src/login/70-power-switch.rules -systemd_user_sessions_SOURCES = \ - src/user-sessions.c \ - src/cgroup-util.c +nodist_udevrules_DATA += \ + src/login/71-seat.rules \ + src/login/73-seat-late.rules -systemd_user_sessions_CFLAGS = \ - $(AM_CFLAGS) +CLEANFILES += \ + src/login/logind-gperf.c \ + src/login/71-seat.rules \ + src/login/73-seat-late.rules +endif -systemd_user_sessions_LDADD = \ - libsystemd-basic.la +polkitpolicy_in_files += \ + src/login/org.freedesktop.login1.policy.in -systemd_vconsole_setup_SOURCES = \ - src/vconsole-setup.c +EXTRA_DIST += \ + src/login/logind-gperf.gperf \ + src/login/71-seat.rules.in \ + src/login/73-seat-late.rules.in \ + units/systemd-logind.service.in \ + units/systemd-user-sessions.service.in -systemd_vconsole_setup_CFLAGS = \ - $(AM_CFLAGS) +# ------------------------------------------------------------------------------ +if HAVE_PYTHON_DEVEL +pkgpyexec_LTLIBRARIES = \ + _journal.la \ + id128.la \ + _daemon.la \ + _reader.la \ + login.la -systemd_vconsole_setup_LDADD = \ - libsystemd-basic.la +_journal_la_SOURCES = \ + src/python-systemd/_journal.c -systemd_remount_api_vfs_SOURCES = \ - src/remount-api-vfs.c \ - src/mount-setup.c \ - src/exit-status.c +_journal_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=default \ + $(PYTHON_DEVEL_CFLAGS) -systemd_remount_api_vfs_CFLAGS = \ - $(AM_CFLAGS) +_journal_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -shared \ + -module \ + -avoid-version -systemd_remount_api_vfs_LDADD = \ - libsystemd-basic.la +_journal_la_LIBADD = \ + $(PYTHON_DEVEL_LIBS) \ + libsystemd.la -systemd_cgroups_agent_SOURCES = \ - src/cgroups-agent.c \ - src/dbus-common.c +id128_la_SOURCES = \ + src/python-systemd/id128.c \ + src/python-systemd/id128-constants.h \ + src/python-systemd/pyutil.c \ + src/python-systemd/pyutil.h -systemd_cgroups_agent_CFLAGS = \ +id128_la_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) - -systemd_cgroups_agent_LDADD = \ - libsystemd-basic.la \ - $(DBUS_LIBS) + -fvisibility=default \ + $(PYTHON_DEVEL_CFLAGS) \ + -I$(top_builddir)/src/python-systemd -systemd_kmsg_syslogd_SOURCES = \ - src/kmsg-syslogd.c \ - src/fdset.c +id128_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -shared \ + -module \ + -avoid-version -systemd_kmsg_syslogd_CFLAGS = \ - $(AM_CFLAGS) +id128_la_LIBADD = \ + $(PYTHON_DEVEL_LIBS) \ + libsystemd-shared.la \ + libsystemd.la -systemd_kmsg_syslogd_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la +_daemon_la_SOURCES = \ + src/python-systemd/_daemon.c \ + src/python-systemd/pyutil.c \ + src/python-systemd/pyutil.h -systemctl_SOURCES = \ - src/systemctl.c \ - src/utmp-wtmp.c \ - src/dbus-common.c \ - src/path-lookup.c \ - src/cgroup-show.c \ - src/cgroup-util.c \ - src/exit-status.c \ - src/unit-name.c \ - src/pager.c \ - src/install.c \ - src/spawn-agent.c - -systemctl_CFLAGS = \ +_daemon_la_CFLAGS = \ $(AM_CFLAGS) \ - $(DBUS_CFLAGS) + -fvisibility=default \ + $(PYTHON_DEVEL_CFLAGS) \ + -I$(top_builddir)/src/python-systemd -systemctl_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(DBUS_LIBS) - -systemd_loginctl_SOURCES = \ - src/loginctl.c \ - src/dbus-common.c \ - src/cgroup-show.c \ - src/cgroup-util.c \ - src/pager.c \ - src/sysfs-show.c - -systemd_loginctl_CFLAGS = \ - $(AM_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(UDEV_CFLAGS) +_daemon_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -shared \ + -module \ + -avoid-version -systemd_loginctl_LDADD = \ - libsystemd-basic.la \ - $(DBUS_LIBS) \ - $(UDEV_LIBS) +_daemon_la_LIBADD = \ + $(PYTHON_DEVEL_LIBS) \ + libsystemd-shared.la \ + libsystemd.la -systemd_notify_SOURCES = \ - src/notify.c \ - src/sd-readahead.c +_reader_la_SOURCES = \ + src/python-systemd/_reader.c \ + src/python-systemd/pyutil.c \ + src/python-systemd/pyutil.h -systemd_notify_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la +_reader_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=default \ + $(PYTHON_DEVEL_CFLAGS) -systemd_ask_password_SOURCES = \ - src/ask-password.c \ - src/ask-password-api.c +_reader_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -shared \ + -module \ + -avoid-version -systemd_ask_password_LDADD = \ - libsystemd-basic.la +_reader_la_LIBADD = \ + $(PYTHON_DEVEL_LIBS) \ + libsystemd-shared.la \ + libsystemd.la -systemd_reply_password_SOURCES = \ - src/reply-password.c +login_la_SOURCES = \ + src/python-systemd/login.c \ + src/python-systemd/pyutil.c \ + src/python-systemd/pyutil.h -systemd_reply_password_LDADD = \ - libsystemd-basic.la +login_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=default \ + $(PYTHON_DEVEL_CFLAGS) + +login_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -shared \ + -module \ + -avoid-version -systemd_readahead_collect_SOURCES = \ - src/readahead-collect.c \ - src/readahead-common.c +login_la_LIBADD = \ + $(PYTHON_DEVEL_LIBS) \ + libsystemd-shared.la \ + libsystemd.la -systemd_readahead_collect_CFLAGS = \ - $(UDEV_CFLAGS) +dist_pkgpyexec_PYTHON = \ + src/python-systemd/journal.py \ + src/python-systemd/daemon.py \ + src/python-systemd/__init__.py -systemd_readahead_collect_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(UDEV_LIBS) +src/python-systemd/id128-constants.h: src/systemd/sd-messages.h + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)$(SED) -n -r 's/,//g; s/#define (SD_MESSAGE_[A-Z0-9_]+)\s.*/add_id(m, "\1", \1) JOINER/p' <$< >$@ -systemd_readahead_replay_SOURCES = \ - src/readahead-replay.c \ - src/readahead-common.c +BUILT_SOURCES += \ + src/python-systemd/id128-constants.h -systemd_readahead_replay_CFLAGS = \ - $(UDEV_CFLAGS) +SPHINXOPTS = -D version=$(VERSION) -D release=$(VERSION) +sphinx-%: + $(AM_V_at)test -n "$(SPHINX_BUILD)" || { echo " *** sphinx-build is not available"; exit 1; } + $(AM_V_GEN)PYTHONPATH=$(DESTDIR)$(pyexecdir) LD_LIBRARY_PATH=$(DESTDIR)$(libdir) $(SPHINX_BUILD) -b $* $(SPHINXOPTS) $(top_srcdir)/src/python-systemd/docs $(top_builddir)/docs/html/python-systemd/ + $(AM_V_at)echo Output has been generated in $(abs_top_builddir)/docs/html/python-systemd/ -systemd_readahead_replay_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(UDEV_LIBS) +python-shell: + $(AM_V_at)echo "Starting python with $(DESTDIR)$(pyexecdir)" + $(AM_V_at)PYTHONPATH=$(DESTDIR)$(pyexecdir) LD_LIBRARY_PATH=$(DESTDIR)$(libdir) $(PYTHON) -systemd_cgls_SOURCES = \ - src/cgls.c \ - src/cgroup-show.c \ - src/cgroup-util.c \ - src/pager.c +destdir-sphinx: all + dir="$$(mktemp -d /tmp/systemd-install.XXXXXX)" && \ + $(MAKE) DESTDIR="$$dir" install && \ + $(MAKE) DESTDIR="$$dir" sphinx-html && \ + rm -rf "$$dir" -systemd_cgls_CFLAGS = \ - $(AM_CFLAGS) +endif -systemd_cgls_LDADD = \ - libsystemd-basic.la +CLEAN_LOCAL_HOOKS += clean-sphinx -systemd_nspawn_SOURCES = \ - src/nspawn.c \ - src/cgroup-util.c \ - src/loopback-setup.c +.PHONY: python-shell destdir-sphinx clean-sphinx clean-python -systemd_nspawn_CFLAGS = \ - $(AM_CFLAGS) +clean-sphinx: + -rm -rf docs/html/python-systemd/ -systemd_nspawn_LDADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la +# Remove Python stuff, e.g. to force rebuilding for a different Python version. +clean-python: + -rm -rf src/python-systemd/.libs src/python-systemd/*.l[ao] + -rm -f _daemon.la id128.la _journal.la login.la _reader.la + +# ------------------------------------------------------------------------------ +if ENABLE_COMPAT_LIBS +EXTRA_DIST += \ + src/compat-libs/linkwarning.h -systemd_stdio_bridge_SOURCES = \ - src/bridge.c +libsystemd-%.c: src/compat-libs/libsystemd-%.sym + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)sed -r -n 's/^ +(sd_.*);/obsolete_lib(\1,$(notdir $(basename $<)));/p' <$< >$@ -systemd_stdio_bridge_LDADD = \ - libsystemd-basic.la +BUILT_SOURCES += \ + libsystemd-journal.c \ + libsystemd-login.c \ + libsystemd-id128.c \ + libsystemd-daemon.c -systemadm_SOURCES = \ - src/systemadm.vala \ - src/systemd-interfaces.vala +libsystemd_journal_la_SOURCES = \ + libsystemd-journal.c \ + src/compat-libs/libsystemd-journal.sym -systemadm_CFLAGS = \ +libsystemd_journal_la_CPPFLAGS = \ $(AM_CFLAGS) \ - $(GTK_CFLAGS) \ - -Wno-unused-variable \ - -Wno-unused-function \ - -Wno-shadow \ - -Wno-format-nonliteral + -imacros$(top_srcdir)/src/compat-libs/linkwarning.h -systemadm_VALAFLAGS = \ - --pkg=posix \ - --pkg=gtk+-2.0 \ - -g +libsystemd_journal_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBSYSTEMD_JOURNAL_CURRENT):$(LIBSYSTEMD_JOURNAL_REVISION):$(LIBSYSTEMD_JOURNAL_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-journal.sym -systemadm_LDADD = \ - $(GTK_LIBS) +libsystemd_journal_la_LIBADD = \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-shared.la -systemd_gnome_ask_password_agent_SOURCES = \ - src/gnome-ask-password-agent.vala +libsystemd_login_la_SOURCES = \ + libsystemd-login.c \ + src/compat-libs/libsystemd-login.sym -systemd_gnome_ask_password_agent_CFLAGS = \ +libsystemd_login_la_CPPFLAGS = \ $(AM_CFLAGS) \ - $(LIBNOTIFY_CFLAGS) \ - $(GTK_CFLAGS) \ - -Wno-unused-variable \ - -Wno-unused-function \ - -Wno-shadow \ - -Wno-format-nonliteral - -systemd_gnome_ask_password_agent_VALAFLAGS = \ - --pkg=posix \ - --pkg=gtk+-2.0 \ - --pkg=linux \ - --pkg=gio-unix-2.0 \ - --pkg=libnotify -if LIBNOTIFY07 -systemd_gnome_ask_password_agent_VALAFLAGS += \ - -D LIBNOTIFY07 -endif -systemd_gnome_ask_password_agent_VALAFLAGS += \ - -g - -systemd_gnome_ask_password_agent_LDADD = \ - $(LIBNOTIFY_LIBS) \ - $(GTK_LIBS) + -imacros$(top_srcdir)/src/compat-libs/linkwarning.h -systemd_tty_ask_password_agent_SOURCES = \ - src/tty-ask-password-agent.c \ - src/ask-password-api.c \ - src/utmp-wtmp.c +libsystemd_login_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-login.sym -systemd_tty_ask_password_agent_LDADD = \ - libsystemd-basic.la +libsystemd_login_la_LIBADD = \ + libsystemd-internal.la \ + libsystemd-shared.la -pam_systemd_la_SOURCES = \ - src/pam-module.c \ - src/dbus-common.c +libsystemd_id128_la_SOURCES = \ + libsystemd-id128.c \ + src/compat-libs/libsystemd-id128.sym -pam_systemd_la_CFLAGS = \ +libsystemd_id128_la_CPPFLAGS = \ $(AM_CFLAGS) \ - $(PAM_CFLAGS) \ - $(DBUS_CFLAGS) \ - -fvisibility=hidden + -imacros$(top_srcdir)/src/compat-libs/linkwarning.h -pam_systemd_la_LDFLAGS = \ - -module \ - -export-dynamic \ - -avoid-version \ - -shared \ - -export-symbols-regex '^pam_sm_.*' +libsystemd_id128_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info $(LIBSYSTEMD_ID128_CURRENT):$(LIBSYSTEMD_ID128_REVISION):$(LIBSYSTEMD_ID128_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-id128.sym -pam_systemd_la_LIBADD = \ - libsystemd-basic.la \ - libsystemd-daemon.la \ - $(PAM_LIBS) \ - $(DBUS_LIBS) +libsystemd_id128_la_LIBADD = \ + libsystemd-internal.la \ + libsystemd-shared.la libsystemd_daemon_la_SOURCES = \ - src/sd-daemon.c + libsystemd-daemon.c \ + src/compat-libs/libsystemd-daemon.sym -libsystemd_daemon_la_CFLAGS = \ - $(AM_CFLAGS) \ - -fvisibility=hidden \ - -DSD_EXPORT_SYMBOLS +libsystemd_daemon_la_CPPFLAGS = \ + $(AM_CFLAGS) \ + -imacros$(top_srcdir)/src/compat-libs/linkwarning.h libsystemd_daemon_la_LDFLAGS = \ - -shared \ - -version-info $(LIBSYSTEMD_DAEMON_CURRENT):$(LIBSYSTEMD_DAEMON_REVISION):$(LIBSYSTEMD_DAEMON_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/libsystemd-daemon.sym + $(AM_LDFLAGS) \ + -version-info $(LIBSYSTEMD_DAEMON_CURRENT):$(LIBSYSTEMD_DAEMON_REVISION):$(LIBSYSTEMD_DAEMON_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-daemon.sym + +libsystemd_daemon_la_LIBADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + +lib_LTLIBRARIES += \ + libsystemd-journal.la \ + libsystemd-login.la \ + libsystemd-id128.la \ + libsystemd-daemon.la + +pkgconfiglib_DATA += \ + src/compat-libs/libsystemd-journal.pc \ + src/compat-libs/libsystemd-login.pc \ + src/compat-libs/libsystemd-id128.pc \ + src/compat-libs/libsystemd-daemon.pc # move lib from $(libdir) to $(rootlibdir) and update devel link, if needed -libsystemd-daemon-install-hook: - if test "$(libdir)" != "$(rootlibdir)"; then \ - mkdir -p $(DESTDIR)$(rootlibdir) && \ - so_img_name=$$(readlink $(DESTDIR)$(libdir)/libsystemd-daemon.so) && \ - so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \ - ln -sf $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/libsystemd-daemon.so && \ - mv $(DESTDIR)$(libdir)/libsystemd-daemon.so.* $(DESTDIR)$(rootlibdir); \ - fi +compat-lib-install-hook: + libname=libsystemd-login.so && $(move-to-rootlibdir) + libname=libsystemd-journal.so && $(move-to-rootlibdir) + libname=libsystemd-id128.so && $(move-to-rootlibdir) + libname=libsystemd-daemon.so && $(move-to-rootlibdir) -libsystemd-daemon-uninstall-hook: +compat-lib-uninstall-hook: + rm -f $(DESTDIR)$(rootlibdir)/libsystemd-login.so* + rm -f $(DESTDIR)$(rootlibdir)/libsystemd-journal.so* + rm -f $(DESTDIR)$(rootlibdir)/libsystemd-id128.so* rm -f $(DESTDIR)$(rootlibdir)/libsystemd-daemon.so* -libsystemd_login_la_SOURCES = \ - src/sd-login.c \ - src/cgroup-util.c +INSTALL_EXEC_HOOKS += compat-lib-install-hook +UNINSTALL_EXEC_HOOKS += compat-lib-uninstall-hook +endif -libsystemd_login_la_CFLAGS = \ - $(AM_CFLAGS) \ - -fvisibility=hidden +EXTRA_DIST += \ + src/compat-libs/libsystemd-journal.pc.in \ + src/compat-libs/libsystemd-login.pc.in \ + src/compat-libs/libsystemd-id128.pc.in \ + src/compat-libs/libsystemd-daemon.pc.in + +# ------------------------------------------------------------------------------ +substitutions = \ + '|rootlibexecdir=$(rootlibexecdir)|' \ + '|rootbindir=$(rootbindir)|' \ + '|bindir=$(bindir)|' \ + '|SYSTEMCTL=$(rootbindir)/systemctl|' \ + '|SYSTEMD_NOTIFY=$(rootbindir)/systemd-notify|' \ + '|pkgsysconfdir=$(pkgsysconfdir)|' \ + '|SYSTEM_CONFIG_UNIT_PATH=$(pkgsysconfdir)/system|' \ + '|USER_CONFIG_UNIT_PATH=$(pkgsysconfdir)/user|' \ + '|pkgdatadir=$(pkgdatadir)|' \ + '|systemunitdir=$(systemunitdir)|' \ + '|userunitdir=$(userunitdir)|' \ + '|systempresetdir=$(systempresetdir)|' \ + '|userpresetdir=$(userpresetdir)|' \ + '|udevhwdbdir=$(udevhwdbdir)|' \ + '|udevrulesdir=$(udevrulesdir)|' \ + '|catalogdir=$(catalogdir)|' \ + '|tmpfilesdir=$(tmpfilesdir)|' \ + '|sysctldir=$(sysctldir)|' \ + '|systemgeneratordir=$(systemgeneratordir)|' \ + '|usergeneratordir=$(usergeneratordir)|' \ + '|PACKAGE_VERSION=$(PACKAGE_VERSION)|' \ + '|PACKAGE_NAME=$(PACKAGE_NAME)|' \ + '|PACKAGE_URL=$(PACKAGE_URL)|' \ + '|RANDOM_SEED_DIR=$(localstatedir)/lib/systemd/|' \ + '|RANDOM_SEED=$(localstatedir)/lib/systemd/random-seed|' \ + '|prefix=$(prefix)|' \ + '|exec_prefix=$(exec_prefix)|' \ + '|libdir=$(libdir)|' \ + '|includedir=$(includedir)|' \ + '|VERSION=$(VERSION)|' \ + '|rootprefix=$(rootprefix)|' \ + '|udevlibexecdir=$(udevlibexecdir)|' \ + '|SUSHELL=$(SUSHELL)|' \ + '|DEBUGTTY=$(DEBUGTTY)|' \ + '|KILL=$(KILL)|' \ + '|KMOD=$(KMOD)|' \ + '|MKDIR_P=$(MKDIR_P)|' \ + '|QUOTAON=$(QUOTAON)|' \ + '|QUOTACHECK=$(QUOTACHECK)|' \ + '|SYSTEM_SYSVINIT_PATH=$(sysvinitdir)|' \ + '|VARLOGDIR=$(varlogdir)|' \ + '|RC_LOCAL_SCRIPT_PATH_START=$(RC_LOCAL_SCRIPT_PATH_START)|' \ + '|RC_LOCAL_SCRIPT_PATH_STOP=$(RC_LOCAL_SCRIPT_PATH_STOP)|' \ + '|PYTHON=$(PYTHON)|' \ + '|PYTHON_BINARY=$(PYTHON_BINARY)|' -libsystemd_login_la_LDFLAGS = \ - -shared \ - -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/libsystemd-login.sym +SED_PROCESS = \ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ + $(SED) $(subst '|,-e 's|@,$(subst =,\@|,$(subst |',|g',$(substitutions)))) \ + < $< > $@ -libsystemd_login_la_LIBADD = \ - libsystemd-basic.la +units/%: units/%.in + $(SED_PROCESS) -# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed -libsystemd-login-install-hook: - if test "$(libdir)" != "$(rootlibdir)"; then \ - mkdir -p $(DESTDIR)$(rootlibdir) && \ - so_img_name=$$(readlink $(DESTDIR)$(libdir)/libsystemd-login.so) && \ - so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \ - ln -sf $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/libsystemd-login.so && \ - mv $(DESTDIR)$(libdir)/libsystemd-login.so.* $(DESTDIR)$(rootlibdir); \ - fi +man/%: man/%.in + $(SED_PROCESS) -libsystemd-login-uninstall-hook: - rm -f $(DESTDIR)$(rootlibdir)/libsystemd-login.so* +sysctl.d/%: sysctl.d/%.in + $(SED_PROCESS) -SED_PROCESS = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(SED) -e 's,@rootlibexecdir\@,$(rootlibexecdir),g' \ - -e 's,@rootbindir\@,$(rootbindir),g' \ - -e 's,@bindir\@,$(bindir),g' \ - -e 's,@SYSTEMCTL\@,$(rootbindir)/systemctl,g' \ - -e 's,@SYSTEMD_NOTIFY\@,$(rootbindir)/systemd-notify,g' \ - -e 's,@pkgsysconfdir\@,$(pkgsysconfdir),g' \ - -e 's,@pkgdatadir\@,$(pkgdatadir),g' \ - -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \ - -e 's,@systemunitdir\@,$(systemunitdir),g' \ - -e 's,@userunitdir\@,$(userunitdir),g' \ - -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ - -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ - -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' \ - -e 's,@prefix\@,$(prefix),g' \ - -e 's,@exec_prefix\@,$(exec_prefix),g' \ - -e 's,@libdir\@,$(libdir),g' \ - -e 's,@includedir\@,$(includedir),g' \ - < $< > $@ || rm $@ - -units/%: units/%.in Makefile +%.pc: %.pc.in $(SED_PROCESS) -man/%: man/%.in Makefile +src/core/macros.%: src/core/macros.%.in $(SED_PROCESS) -%.pc: %.pc.in Makefile +src/%.policy.in: src/%.policy.in.in $(SED_PROCESS) -src/%.policy.in: src/%.policy.in.in Makefile +%.rules: %.rules.in $(SED_PROCESS) -src/%.rules: src/%.rules.in Makefile +%.sh: %.sh.in $(SED_PROCESS) + $(AM_V_GEN)chmod +x $@ src/%.c: src/%.gperf - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(GPERF) < $< > $@ + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_GPERF)$(GPERF) < $< > $@ src/%: src/%.m4 - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(M4) -P $(M4_DEFINES) < $< > $@ || rm $@ - -src/load-fragment-gperf-nulstr.c: src/load-fragment-gperf.gperf - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(AWK) 'BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; print "const char load_fragment_gperf_nulstr[] ="} ; keyword==1 { print "\"" $$1 "\\0\"" } ; /%%/ { keyword=1} ; END { print ";" }' < $< > $@ || rm $@ + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ -M4_PROCESS_SYSTEM = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(M4) -P $(M4_DEFINES) -DFOR_SYSTEM=1 < $< > $@ || rm $@ +units/%: units/%.m4 + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_SYSTEM=1 < $< > $@ -M4_PROCESS_USER = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(M4) -P $(M4_DEFINES) -DFOR_USER=1 < $< > $@ || rm $@ +units/user/%: units/%.m4 + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_USER=1 < $< > $@ -units/%: units/%.m4 Makefile - $(M4_PROCESS_SYSTEM) +if ENABLE_POLKIT +nodist_polkitpolicy_DATA = \ + $(polkitpolicy_files) \ + $(polkitpolicy_in_in_files:.policy.in.in=.policy) +endif -units/user/%: units/%.m4 Makefile - $(M4_PROCESS_USER) +EXTRA_DIST += \ + $(polkitpolicy_in_files) \ + $(polkitpolicy_in_in_files) -CLEANFILES = \ +CLEANFILES += \ $(nodist_systemunit_DATA) \ $(nodist_userunit_DATA) \ - $(nodist_man_MANS) \ - ${XML_IN_FILES:.xml.in=.html} \ $(pkgconfigdata_DATA) \ $(pkgconfiglib_DATA) \ - $(nodist_polkitpolicy_DATA) \ - src/73-seat-late.rules \ - src/99-systemd.rules \ - src/load-fragment-gperf.gperf \ - src/load-fragment-gperf.c \ - src/load-fragment-gperf-nulstr.c \ - src/logind-gperf.c - -if HAVE_VALAC -CLEANFILES += \ - ${systemadm_SOURCES:.vala=.c} -endif + $(nodist_polkitpolicy_DATA) + +# ------------------------------------------------------------------------------ +if ENABLE_MANPAGES +man/custom-entities.ent: + $(AM_V_GEN)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)(echo '' && \ + printf '$(subst '|,\n,$(substitutions))))') \ + > $@ # ' + +DISTCLEANFILES += \ + man/custom-entities.ent -if HAVE_XSLTPROC XSLTPROC_FLAGS = \ --nonet \ - --param funcsynopsis.style "'ansi'" + --xinclude \ + --stringparam man.output.quietly 1 \ + --stringparam funcsynopsis.style ansi \ + --stringparam man.authors.section.enabled 0 \ + --stringparam man.copyright.section.enabled 0 \ + --stringparam systemd.version $(VERSION) \ + --path '$(builddir)/man:$(srcdir)/man' XSLTPROC_PROCESS_MAN = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< - -XSLTPROC_PROCESS_MAN_IN = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o ${@:.in=} $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< && \ - mv ${@:.in=} $@ + $(AM_V_XSLT)$(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-man.xsl $< XSLTPROC_PROCESS_HTML = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/xhtml-1_1/docbook.xsl $< - -XSLTPROC_PROCESS_HTML_IN = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(XSLTPROC) -o ${@:.in=} $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/xhtml-1_1/docbook.xsl $< && \ - mv ${@:.in=} $@ - -man/%.1: man/%.xml - $(XSLTPROC_PROCESS_MAN) - -man/%.1.in: man/%.xml.in - $(XSLTPROC_PROCESS_MAN) - -man/%.3: man/%.xml - $(XSLTPROC_PROCESS_MAN) + $(AM_V_XSLT)$(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-html.xsl $< -man/%.3.in: man/%.xml.in +man/%.1: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) -man/%.5: man/%.xml +man/%.3: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) -man/%.5.in: man/%.xml.in +man/%.5: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) -man/%.7: man/%.xml +man/%.7: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) -man/%.7.in: man/%.xml.in - $(XSLTPROC_PROCESS_MAN_IN) - -man/%.8: man/%.xml +man/%.8: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) -man/%.8.in: man/%.xml.in - $(XSLTPROC_PROCESS_MAN_IN) - -man/%.html: man/%.xml +man/%.html: man/%.xml man/custom-html.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_HTML) -man/%.html.in: man/%.xml.in - $(XSLTPROC_PROCESS_HTML_IN) +define html-alias + $(AM_V_LN)$(LN_S) -f $(notdir $<) $@ +endef -CLEANFILES += \ - $(dist_man_MANS) \ - ${nodist_man_MANS:=.in} \ - ${XML_FILES:.xml=.html} \ - ${XML_IN_FILES:.xml.in=.html.in} endif -DBUS_PREPROCESS = $(CPP) -P $(DBUS_CFLAGS) -imacros dbus/dbus-protocol.h +EXTRA_DIST += \ + man/custom-html.xsl \ + man/custom-man.xsl -org.freedesktop.systemd1.%.xml: systemd - $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.$* $< $@.tmp && \ - $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ - $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp +# ------------------------------------------------------------------------------ +if HAVE_SYSV_COMPAT +sysvinit_DATA = \ + docs/sysvinit/README -org.freedesktop.hostname1.xml: systemd-hostnamed - $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.hostname1 $< $@.tmp && \ - $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ - $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp +varlog_DATA = \ + docs/var-log/README -org.freedesktop.locale1.xml: systemd-localed - $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.locale1 $< $@.tmp && \ - $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ - $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp +docs/sysvinit/README: docs/sysvinit/README.in + $(SED_PROCESS) -org.freedesktop.timedate1.xml: systemd-timedated - $(AM_V_GEN)$(LIBTOOL) --mode=execute $(OBJCOPY) -O binary -j introspect.timedate1 $< $@.tmp && \ - $(STRINGS) $@.tmp | $(AWK) -f $(srcdir)/introspect.awk | \ - $(DBUS_PREPROCESS) -o $@ - && rm $@.tmp +docs/var-log/README: docs/var-log/README.in + $(SED_PROCESS) CLEANFILES += \ - $(dbusinterface_DATA) - -install-data-hook: - $(MKDIR_P) -m 0755 \ - $(DESTDIR)$(tmpfilesdir) \ - $(DESTDIR)$(sysconfdir)/tmpfiles.d \ - $(DESTDIR)$(prefix)/lib/modules-load.d \ - $(DESTDIR)$(sysconfdir)/modules-load.d \ - $(DESTDIR)$(prefix)/lib/sysctl.d \ - $(DESTDIR)$(sysconfdir)/sysctl.d \ - $(DESTDIR)$(systemshutdowndir) \ - $(DESTDIR)$(systemgeneratordir) \ - $(DESTDIR)$(usergeneratordir) -if ENABLE_BINFMT - $(MKDIR_P) -m 0755 \ - $(DESTDIR)$(prefix)/lib/binfmt.d \ - $(DESTDIR)$(sysconfdir)/binfmt.d -endif - $(MKDIR_P) -m 0755 \ - $(DESTDIR)$(systemunitdir) \ - $(DESTDIR)$(userunitdir) \ - $(DESTDIR)$(systemunitdir)/sysinit.target.wants \ - $(DESTDIR)$(systemunitdir)/sockets.target.wants \ - $(DESTDIR)$(systemunitdir)/basic.target.wants \ - $(DESTDIR)$(systemunitdir)/shutdown.target.wants \ - $(DESTDIR)$(systemunitdir)/local-fs.target.wants \ - $(DESTDIR)$(systemunitdir)/runlevel1.target.wants \ - $(DESTDIR)$(systemunitdir)/runlevel2.target.wants \ - $(DESTDIR)$(systemunitdir)/runlevel3.target.wants \ - $(DESTDIR)$(systemunitdir)/runlevel4.target.wants \ - $(DESTDIR)$(systemunitdir)/runlevel5.target.wants \ - $(DESTDIR)$(systemunitdir)/multi-user.target.wants \ - $(DESTDIR)$(systemunitdir)/graphical.target.wants \ - $(DESTDIR)$(pkgsysconfdir)/system \ - $(DESTDIR)$(pkgsysconfdir)/system/sysinit.target.wants \ - $(DESTDIR)$(pkgsysconfdir)/system/local-fs.target.wants \ - $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants \ - $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants \ - $(DESTDIR)$(pkgsysconfdir)/user \ - $(DESTDIR)$(dbussessionservicedir) \ - $(DESTDIR)$(sysconfdir)/xdg/systemd - ( cd $(DESTDIR)$(sysconfdir)/xdg/systemd/ && \ - rm -f user && \ - $(LN_S) $(pkgsysconfdir)/user user ) - ( cd $(DESTDIR)$(systemunitdir)/sockets.target.wants && \ - rm -f systemd-initctl.socket systemd-stdout-syslog-bridge.socket systemd-shutdownd.socket syslog.socket && \ - $(LN_S) ../systemd-stdout-syslog-bridge.socket systemd-stdout-syslog-bridge.socket && \ - $(LN_S) ../systemd-initctl.socket systemd-initctl.socket && \ - $(LN_S) ../systemd-shutdownd.socket systemd-shutdownd.socket && \ - $(LN_S) ../syslog.socket syslog.socket ) - ( cd $(DESTDIR)$(systemunitdir)/runlevel1.target.wants && \ - rm -f systemd-update-utmp-runlevel.service && \ - $(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service ) - ( cd $(DESTDIR)$(systemunitdir)/runlevel2.target.wants && \ - rm -f systemd-update-utmp-runlevel.service && \ - $(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service ) - ( cd $(DESTDIR)$(systemunitdir)/runlevel3.target.wants && \ - rm -f systemd-update-utmp-runlevel.service && \ - $(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service ) - ( cd $(DESTDIR)$(systemunitdir)/runlevel4.target.wants && \ - rm -f systemd-update-utmp-runlevel.service && \ - $(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service ) - ( cd $(DESTDIR)$(systemunitdir)/runlevel5.target.wants && \ - rm -f systemd-update-utmp-runlevel.service && \ - $(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service ) - ( cd $(DESTDIR)$(systemunitdir)/shutdown.target.wants && \ - rm -f systemd-update-utmp-shutdown.service \ - systemd-random-seed-save.service && \ - $(LN_S) ../systemd-update-utmp-shutdown.service systemd-update-utmp-shutdown.service && \ - $(LN_S) ../systemd-random-seed-save.service systemd-random-seed-save.service ) - ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \ - rm -f systemd-remount-api-vfs.service \ - fsck-root.service \ - remount-rootfs.service \ - var-run.mount \ - media.mount && \ - $(LN_S) ../systemd-remount-api-vfs.service systemd-remount-api-vfs.service && \ - $(LN_S) ../fsck-root.service fsck-root.service && \ - $(LN_S) ../remount-rootfs.service remount-rootfs.service && \ - $(LN_S) ../var-run.mount var-run.mount && \ - $(LN_S) ../media.mount media.mount ) - ( cd $(DESTDIR)$(userunitdir) && \ - rm -f shutdown.target sockets.target bluetooth.target printer.target sound.target && \ - $(LN_S) $(systemunitdir)/shutdown.target shutdown.target && \ - $(LN_S) $(systemunitdir)/sockets.target sockets.target && \ - $(LN_S) $(systemunitdir)/bluetooth.target bluetooth.target && \ - $(LN_S) $(systemunitdir)/printer.target printer.target && \ - $(LN_S) $(systemunitdir)/sound.target sound.target ) - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f runlevel0.target runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target runlevel6.target && \ - $(LN_S) poweroff.target runlevel0.target && \ - $(LN_S) rescue.target runlevel1.target && \ - $(LN_S) multi-user.target runlevel2.target && \ - $(LN_S) multi-user.target runlevel3.target && \ - $(LN_S) multi-user.target runlevel4.target && \ - $(LN_S) graphical.target runlevel5.target && \ - $(LN_S) reboot.target runlevel6.target ) - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.login1.service autovt@.service && \ - $(LN_S) graphical.target default.target && \ - $(LN_S) reboot.target ctrl-alt-del.target && \ - $(LN_S) systemd-logind.service dbus-org.freedesktop.login1.service && \ - $(LN_S) getty@.service autovt@.service ) - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f getty.target systemd-user-sessions.service systemd-ask-password-wall.path systemd-logind.service && \ - $(LN_S) ../getty.target getty.target && \ - $(LN_S) ../systemd-user-sessions.service systemd-user-sessions.service && \ - $(LN_S) ../systemd-ask-password-wall.path systemd-ask-password-wall.path && \ - $(LN_S) ../systemd-logind.service systemd-logind.service ) - ( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \ - rm -f remote-fs.target && \ - $(LN_S) $(systemunitdir)/remote-fs.target remote-fs.target ) - ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ - rm -f dev-hugepages.mount \ - dev-mqueue.mount \ - sys-kernel-config.mount \ - sys-kernel-debug.mount \ - sys-kernel-security.mount \ - sys-fs-fuse-connections.mount \ - systemd-vconsole-setup.service \ - systemd-modules-load.service \ - systemd-random-seed-load.service \ - systemd-tmpfiles-setup.service \ - systemd-sysctl.service \ - systemd-ask-password-console.path \ - systemd-kmsg-syslogd.service \ - cryptsetup.target && \ - $(LN_S) ../dev-hugepages.mount dev-hugepages.mount && \ - $(LN_S) ../dev-mqueue.mount dev-mqueue.mount && \ - $(LN_S) ../sys-kernel-config.mount sys-kernel-config.mount && \ - $(LN_S) ../sys-kernel-debug.mount sys-kernel-debug.mount && \ - $(LN_S) ../sys-kernel-security.mount sys-kernel-security.mount && \ - $(LN_S) ../sys-fs-fuse-connections.mount sys-fs-fuse-connections.mount && \ - $(LN_S) ../systemd-vconsole-setup.service systemd-vconsole-setup.service && \ - $(LN_S) ../systemd-modules-load.service systemd-modules-load.service && \ - $(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service && \ - $(LN_S) ../systemd-tmpfiles-setup.service systemd-tmpfiles-setup.service && \ - $(LN_S) ../systemd-sysctl.service systemd-sysctl.service && \ - $(LN_S) ../systemd-ask-password-console.path systemd-ask-password-console.path && \ - $(LN_S) ../systemd-kmsg-syslogd.service && \ - $(LN_S) ../cryptsetup.target cryptsetup.target ) -if ENABLE_BINFMT - ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ - rm -f systemd-binfmt.service \ - proc-sys-fs-binfmt_misc.automount && \ - $(LN_S) ../systemd-binfmt.service systemd-binfmt.service && \ - $(LN_S) ../proc-sys-fs-binfmt_misc.automount proc-sys-fs-binfmt_misc.automount ) -endif -if ENABLE_HOSTNAMED - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f dbus-org.freedesktop.hostname1.service && \ - $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service ) -endif -if ENABLE_TIMEDATED - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f dbus-org.freedesktop.timedate1.service && \ - $(LN_S) systemd-timedated.service dbus-org.freedesktop.timedate1.service ) -endif -if ENABLE_LOCALED - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f dbus-org.freedesktop.locale1.service && \ - $(LN_S) systemd-localed.service dbus-org.freedesktop.locale1.service ) -endif - ( cd $(DESTDIR)$(systemunitdir)/basic.target.wants && \ - rm -f systemd-tmpfiles-clean.timer && \ - $(LN_S) ../systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.timer ) - ( cd $(DESTDIR)$(dbussessionservicedir) && \ - rm -f org.freedesktop.systemd1.service && \ - $(LN_S) ../system-services/org.freedesktop.systemd1.service org.freedesktop.systemd1.service ) -if HAVE_PLYMOUTH - $(MKDIR_P) -m 0755 \ - $(DESTDIR)$(SYSTEM_SYSVINIT_PATH) \ - $(DESTDIR)$(systemunitdir)/reboot.target.wants \ - $(DESTDIR)$(systemunitdir)/kexec.target.wants \ - $(DESTDIR)$(systemunitdir)/poweroff.target.wants \ - $(DESTDIR)$(systemunitdir)/halt.target.wants - ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ - rm -f plymouth-start.service plymouth-read-write.service && \ - $(LN_S) ../plymouth-start.service plymouth-start.service && \ - $(LN_S) ../plymouth-read-write.service plymouth-read-write.service ) - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f plymouth-quit.service plymouth-quit-wait.service && \ - $(LN_S) ../plymouth-quit.service plymouth-quit.service && \ - $(LN_S) ../plymouth-quit-wait.service plymouth-quit-wait.service ) - ( cd $(DESTDIR)$(systemunitdir)/reboot.target.wants && \ - rm -f plymouth-reboot.service && \ - $(LN_S) ../plymouth-reboot.service plymouth-reboot.service ) - ( cd $(DESTDIR)$(systemunitdir)/kexec.target.wants && \ - rm -f plymouth-kexec.service && \ - $(LN_S) ../plymouth-kexec.service plymouth-kexec.service ) - ( cd $(DESTDIR)$(systemunitdir)/poweroff.target.wants && \ - rm -f plymouth-poweroff.service && \ - $(LN_S) ../plymouth-poweroff.service plymouth-poweroff.service ) - ( cd $(DESTDIR)$(systemunitdir)/halt.target.wants && \ - rm -f plymouth-halt.service && \ - $(LN_S) ../plymouth-halt.service plymouth-halt.service ) -endif -if TARGET_MEEGO - $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f network.target && \ - $(LN_S) $(systemunitdir)/network.target network.target ) - ( cd $(DESTDIR)$(pkgsysconfdir)/system/sysinit.target.wants && \ - rm -f * ) - ( cd $(DESTDIR)$(pkgsysconfdir)/system/local-fs.target.wants && \ - rm -f * ) - ( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \ - rm -f * ) - ( cd $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants && \ - rm -f * ) -endif - -if TARGET_FEDORA - $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f rc-local.service && \ - $(LN_S) $(systemunitdir)/rc-local.service rc-local.service ) - ( cd $(DESTDIR)$(systemunitdir)/final.target.wants && \ - rm -f halt-local.service && \ - $(LN_S) $(systemunitdir)/halt-local.service halt-local.service ) - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f display-manager.service single.service && \ - $(LN_S) prefdm.service display-manager.service && \ - $(LN_S) rescue.service single.service ) - ( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \ - rm -f display-manager.service && \ - $(LN_S) $(systemunitdir)/display-manager.service display-manager.service ) -endif - -if TARGET_MANDRIVA - $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f rc-local.service && \ - $(LN_S) $(systemunitdir)/rc-local.service rc-local.service ) - ( cd $(DESTDIR)$(systemunitdir)/final.target.wants && \ - rm -f halt-local.service && \ - $(LN_S) $(systemunitdir)/halt-local.service halt-local.service ) - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f display-manager.service dm.service single.service && \ - $(LN_S) prefdm.service display-manager.service && \ - $(LN_S) prefdm.service dm.service && \ - $(LN_S) rescue.service single.service ) - ( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \ - rm -f display-manager.service && \ - $(LN_S) $(systemunitdir)/display-manager.service display-manager.service ) -endif - -if TARGET_SLP - rm -rf $(DESTDIR)$(systemunitdir)/runlevel?.target* - - ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \ - rm -f fsck-root.service media.mount && \ - $(LN_S) ../var-lib.automount var-lib.automount && \ - $(LN_S) ../var-cache.automount var-cache.automount && \ - $(LN_S) ../var-log.automount var-log.automount && \ - $(LN_S) ../var-lock.mount var-lock.mount ) - - ( cd $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants && \ - rm -f getty@tty1.service serial-getty@serial_console && \ - $(LN_S) $(systemunitdir)/serial-getty@.service serial-getty@serial_console.service ) - - ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ - rm -f proc-sys-fs-binfmt_misc.automount \ - sys-kernel-security.automount \ - cryptsetup.target ) -else - ( cd $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants && \ - rm -f getty@tty1.service && \ - $(LN_S) $(systemunitdir)/getty@.service getty@tty1.service ) + docs/sysvinit/README \ + docs/var-log/README endif -if TARGET_DEBIAN_OR_UBUNTU - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f runlevel5.target && \ - $(LN_S) multi-user.target runlevel5.target ) -endif +EXTRA_DIST += \ + docs/sysvinit/README.in \ + docs/var-log/README.in + +SOCKETS_TARGET_WANTS += \ + systemd-initctl.socket \ + systemd-shutdownd.socket -if TARGET_SUSE - $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants - ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ - rm -f rc-local.service && \ - $(LN_S) $(systemunitdir)/rc-local.service rc-local.service ) - ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f local.service && \ - $(LN_S) rc-local.service local.service ) - ( cd $(DESTDIR)$(systemunitdir)/final.target.wants && \ - rm -f halt-local.service && \ - $(LN_S) $(systemunitdir)/halt-local.service halt-local.service ) +if HAVE_SYSV_COMPAT +RUNLEVEL1_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service +RUNLEVEL2_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service +RUNLEVEL3_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service +RUNLEVEL4_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service +RUNLEVEL5_TARGET_WANTS += \ + systemd-update-utmp-runlevel.service endif +SYSINIT_TARGET_WANTS += \ + systemd-update-utmp.service +LOCAL_FS_TARGET_WANTS += \ + systemd-remount-fs.service \ + tmp.mount +MULTI_USER_TARGET_WANTS += \ + getty.target \ + systemd-ask-password-wall.path +SYSINIT_TARGET_WANTS += \ + dev-hugepages.mount \ + dev-mqueue.mount \ + sys-kernel-config.mount \ + sys-kernel-debug.mount \ + sys-fs-fuse-connections.mount \ + systemd-sysctl.service \ + systemd-ask-password-console.path if HAVE_SYSV_COMPAT - ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \ - rm -f var-lock.mount && \ - $(LN_S) ../var-lock.mount var-lock.mount ) +SYSTEM_UNIT_ALIASES += \ + poweroff.target runlevel0.target \ + rescue.target runlevel1.target \ + multi-user.target runlevel2.target \ + multi-user.target runlevel3.target \ + multi-user.target runlevel4.target \ + graphical.target runlevel5.target \ + reboot.target runlevel6.target endif -install-exec-hook: libsystemd-daemon-install-hook libsystemd-login-install-hook +SYSTEM_UNIT_ALIASES += \ + graphical.target default.target \ + reboot.target ctrl-alt-del.target \ + getty@.service autovt@.service + +USER_UNIT_ALIASES += \ + $(systemunitdir)/shutdown.target shutdown.target \ + $(systemunitdir)/sockets.target sockets.target \ + $(systemunitdir)/busnames.target busnames.target \ + $(systemunitdir)/timers.target timers.target \ + $(systemunitdir)/paths.target paths.target \ + $(systemunitdir)/bluetooth.target bluetooth.target \ + $(systemunitdir)/printer.target printer.target \ + $(systemunitdir)/sound.target sound.target \ + $(systemunitdir)/smartcard.target smartcard.target + +GENERAL_ALIASES += \ + $(systemunitdir)/remote-fs.target $(pkgsysconfdir)/system/multi-user.target.wants/remote-fs.target \ + $(systemunitdir)/getty@.service $(pkgsysconfdir)/system/getty.target.wants/getty@tty1.service \ + $(pkgsysconfdir)/user $(sysconfdir)/xdg/systemd/user \ + ../system-services/org.freedesktop.systemd1.service $(dbussessionservicedir)/org.freedesktop.systemd1.service + +if HAVE_SYSV_COMPAT +INSTALL_DIRS += \ + $(systemunitdir)/runlevel1.target.wants \ + $(systemunitdir)/runlevel2.target.wants \ + $(systemunitdir)/runlevel3.target.wants \ + $(systemunitdir)/runlevel4.target.wants \ + $(systemunitdir)/runlevel5.target.wants +endif -uninstall-hook: libsystemd-daemon-uninstall-hook libsystemd-login-uninstall-hook +INSTALL_DIRS += \ + $(prefix)/lib/modules-load.d \ + $(sysconfdir)/modules-load.d \ + $(prefix)/lib/systemd/network \ + $(sysconfdir)/systemd/network \ + $(prefix)/lib/sysctl.d \ + $(sysconfdir)/sysctl.d \ + $(prefix)/lib/kernel/install.d \ + $(sysconfdir)/kernel/install.d \ + $(systemshutdowndir) \ + $(systemsleepdir) \ + $(systemgeneratordir) \ + $(usergeneratordir) \ + \ + $(userunitdir) \ + $(pkgsysconfdir)/system \ + $(pkgsysconfdir)/system/multi-user.target.wants \ + $(pkgsysconfdir)/system/getty.target.wants \ + $(pkgsysconfdir)/user \ + $(dbussessionservicedir) \ + $(sysconfdir)/xdg/systemd + +install-exec-hook: $(INSTALL_EXEC_HOOKS) + +uninstall-hook: $(UNINSTALL_DATA_HOOKS) $(UNINSTALL_EXEC_HOOKS) + +install-data-hook: $(INSTALL_DATA_HOOKS) + +distclean-local: $(DISTCLEAN_LOCAL_HOOKS) + +clean-local: $(CLEAN_LOCAL_HOOKS) + rm -rf $(abs_srcdir)/install-tree + rm -f $(abs_srcdir)/hwdb/usb.ids $(abs_srcdir)/hwdb/pci.ids $(abs_srcdir)/hwdb/oui.txt \ + $(abs_srcdir)/hwdb/iab.txt DISTCHECK_CONFIGURE_FLAGS = \ --with-dbuspolicydir=$$dc_install_base/$(dbuspolicydir) \ --with-dbussessionservicedir=$$dc_install_base/$(dbussessionservicedir) \ --with-dbussystemservicedir=$$dc_install_base/$(dbussystemservicedir) \ - --with-dbusinterfacedir=$$dc_install_base/$(dbusinterfacedir) \ - --with-udevrulesdir=$$dc_install_base/$(udevrulesdir) \ + --with-bashcompletiondir=$$dc_install_base/$(bashcompletiondir) \ + --with-zshcompletiondir=$$dc_install_base/$(zshcompletiondir) \ --with-pamlibdir=$$dc_install_base/$(pamlibdir) \ - --with-rootdir=$$dc_install_base/$(rootdir) + --with-pamconfdir=$$dc_install_base/$(pamconfdir) \ + --with-rootprefix=$$dc_install_base \ + --disable-split-usr \ + --enable-kdbus \ + --enable-compat-libs + +if HAVE_SYSV_COMPAT +DISTCHECK_CONFIGURE_FLAGS += \ + --with-sysvinit-path=$$dc_install_base/$(sysvinitdir) \ + --with-sysvrcnd-path=$$dc_install_base/$(sysvrcnddir) +else +DISTCHECK_CONFIGURE_FLAGS += \ + --with-sysvinit-path= \ + --with-sysvrcnd-path= +endif + +if ENABLE_GTK_DOC +DISTCHECK_CONFIGURE_FLAGS += \ + --enable-gtk-doc +endif +.PHONY: hwdb-update +hwdb-update: + ( cd $(top_srcdir)/hwdb && \ + wget -N http://www.linux-usb.org/usb.ids \ + http://pci-ids.ucw.cz/v2.2/pci.ids \ + http://standards.ieee.org/develop/regauth/oui/oui.txt \ + http://standards.ieee.org/develop/regauth/iab/iab.txt && \ + ./ids-update.pl ) + +.PHONY: kdbus-update +kdbus-update: + ( cd $(top_srcdir)/src/libsystemd/ && \ + wget -N https://d-bus.googlecode.com/git/kdbus.h ) + +.PHONY: upload upload: all distcheck - cp -v systemd-$(VERSION).tar.bz2 /home/lennart/git.fedora/systemd/ - scp systemd-$(VERSION).tar.bz2 fdo:/srv/www.freedesktop.org/www/software/systemd/ + cp -v systemd-$(VERSION).tar.xz /home/lennart/git.fedora/systemd/ + scp systemd-$(VERSION).tar.xz fdo:/srv/www.freedesktop.org/www/software/systemd/ scp man/*.html tango:public/systemd-man/ +www_target = www.freedesktop.org:/srv/www.freedesktop.org/www/software/systemd +.PHONY: doc-sync +doc-sync: all destdir-sphinx + gtkdoc-rebase --html-dir=docs/libudev/html --online + rsync -rlv --delete docs/libudev/html/ --omit-dir-times $(www_target)/libudev/ + gtkdoc-rebase --html-dir=docs/gudev/html --online + rsync -rlv --delete docs/gudev/html/ --omit-dir-times $(www_target)/gudev/ + rsync -rlv --delete-excluded --include="*.html" --exclude="*" --omit-dir-times man/ $(www_target)/man/ + rsync -rlv --delete --omit-dir-times docs/html/python-systemd/ $(www_target)/python-systemd/ + +.PHONY: git-tag git-tag: git tag "v$(VERSION)" -m "systemd $(VERSION)" -update-kbd-model-map: - src/generate-kbd-model-map > src/kbd-model-map +.PHONY: install-tree +install-tree: all + rm -rf $(abs_srcdir)/install-tree + $(MAKE) install DESTDIR=$(abs_srcdir)/install-tree + tree $(abs_srcdir)/install-tree + +# Let's run all tests of the test suite, but under valgrind. Let's +# exclude the one perl script we have in there +.PHONY: valgrind-tests +valgrind-tests: $(TESTS) + $(AM_V_GEN)for f in $(filter-out %.pl, $^); do \ + if file $$f | grep -q shell; then \ + echo -e "$${x}Skipping non-binary $$f"; else \ + echo -e "$${x}Running $$f"; \ + libtool --mode=execute valgrind -q --leak-check=full --max-stackframe=5242880 --error-exitcode=55 $(builddir)/$$f ; fi; \ + x="\n\n"; \ + done + +exported-%: % + $(AM_V_GEN)nm -g --defined-only $(builddir)/.libs/$(<:.la=.so) 2>&1 /dev/null | grep " T " | cut -d" " -f3 > $@ + +exported: $(addprefix exported-, $(lib_LTLIBRARIES)) + $(AM_V_GEN)cat $^ > $@ + +.PHONY: check-api-docs +check-api-docs: exported man + $(AM_V_GEN)for symbol in `cat exported` ; do \ + if test -f $(builddir)/man/$$symbol.html ; then \ + echo " Symbol $$symbol() is documented." ; \ + else \ + echo "‣ Symbol $$symbol() lacks documentation." ; \ + fi ; \ + done + +OBJECT_VARIABLES:=$(filter %_OBJECTS,$(.VARIABLES)) +ALL_OBJECTS:=$(foreach v,$(OBJECT_VARIABLES),$($(v))) + +undefined defined: $(ALL_OBJECTS) + $(AM_V_GEN)for f in $(ALL_OBJECTS) ; do \ + nm -g --$@-only `echo $(builddir)/"$$f" | sed -e 's,\([^/]*\).lo$$,.libs/\1.o,'` ; \ + done | cut -c 20- | cut -d @ -f 1 | sort -u > $@ + +CLEANFILES += \ + defined \ + undefined + +.PHONY: check-api-unused +check-api-unused: defined undefined exported + ( cat exported undefined ) | sort -u | diff -u - defined | grep ^+ | grep -v ^+++ | cut -c2- + +.PHONY: check-includes +check-includes: $(top_srcdir)/tools/check-includes.pl + $(AM_V_GEN) find * -name '*.[hcS]' -type f -print | sort -u \ + | xargs $(top_srcdir)/tools/check-includes.pl + +EXTRA_DIST += \ + $(top_srcdir)/tools/check-includes.pl + +# Stupid test that everything purported to be exported really is +define generate-sym-test + $(AM_V_at)$(MKDIR_P) $(dir $@) + $(AM_V_at)printf '#include \n' > $@ + $(AM_V_at)printf '#include "%s"\n' $(notdir $(filter %.h, $^)) >> $@ + $(AM_V_at)printf 'void* functions[] = {\n' >> $@ + $(AM_V_GEN)sed -r -n 's/^ +([a-zA-Z0-9_]+);/\1,/p' $< >> $@ + $(AM_V_at)printf '};\nint main(void) {\n' >> $@ + $(AM_V_at)printf 'unsigned i; for (i=0;i> $@ + $(AM_V_at)printf 'return 0; }\n' >> $@ +endef + +test-libsystemd-sym.c: \ + $(top_builddir)/src/libsystemd/libsystemd.sym \ + src/systemd/sd-journal.h \ + src/systemd/sd-daemon.h \ + src/systemd/sd-login.h \ + src/systemd/sd-bus.h \ + src/systemd/sd-utf8.h + $(generate-sym-test) + +test-libudev-sym.c: \ + src/libudev/libudev.sym \ + src/udev/udev.h + $(generate-sym-test) + +test_libsystemd_sym_SOURCES = \ + test-libsystemd-sym.c +test_libsystemd_sym_LDADD = \ + libsystemd.la + +test_libudev_sym_SOURCES = \ + test-libudev-sym.c +test_libudev_sym_LDADD = \ + libudev.la + +BUILT_SOURCES += \ + $(test_libsystemd_sym_SOURCES) \ + $(test_libudev_sym_SOURCES) + +tests += \ + test-libsystemd-sym \ + test-libudev-sym + +if ENABLE_COMPAT_LIBS +test-libsystemd-daemon-sym.c: \ + src/compat-libs/libsystemd-daemon.sym \ + src/systemd/sd-daemon.h + $(generate-sym-test) + +test-libsystemd-id128-sym.c: \ + src/compat-libs/libsystemd-id128.sym \ + src/systemd/sd-id128.h + $(generate-sym-test) + +test-libsystemd-journal-sym.c: \ + src/compat-libs/libsystemd-journal.sym \ + src/systemd/sd-journal.h + $(generate-sym-test) + +test-libsystemd-login-sym.c: \ + src/compat-libs/libsystemd-login.sym \ + src/systemd/sd-login.h + $(generate-sym-test) + +test_libsystemd_daemon_sym_SOURCES = \ + test-libsystemd-daemon-sym.c +test_libsystemd_daemon_sym_LDADD = \ + libsystemd-daemon.la + +test_libsystemd_id128_sym_SOURCES = \ + test-libsystemd-id128-sym.c +test_libsystemd_id128_sym_LDADD = \ + libsystemd-id128.la + +test_libsystemd_journal_sym_SOURCES = \ + test-libsystemd-journal-sym.c +test_libsystemd_journal_sym_LDADD = \ + libsystemd-journal.la + +test_libsystemd_login_sym_SOURCES = \ + test-libsystemd-login-sym.c +test_libsystemd_login_sym_LDADD = \ + libsystemd-login.la + +BUILT_SOURCES += \ + $(test_libsystemd_journal_sym_SOURCES) \ + $(test_libsystemd_login_sym_SOURCES) \ + $(test_libsystemd_id128_sym_SOURCES) \ + $(test_libsystemd_daemon_sym_SOURCES) + +tests += \ + test-libsystemd-journal-sym \ + test-libsystemd-login-sym \ + test-libsystemd-id128-sym \ + test-libsystemd-daemon-sym +endif + +.PHONY: cppcheck +cppcheck: + cppcheck --enable=all -q $(top_srcdir) + +# Used to extract compile flags for YCM. +print-%: + @echo $($*) + +git-contrib: + @git shortlog -s `git describe --abbrev=0`.. | cut -c8- | awk '{ print $$0 "," }' | sort -u diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..46d2420 --- /dev/null +++ b/NEWS @@ -0,0 +1,2964 @@ +systemd System and Service Manager + +CHANGES WITH 210: + + * systemd will now relabel /dev after loading the SMACK policy + according to SMACK rules. + + * A new unit file option AppArmoreProfile= has been added to + set the AppArmor profile for the processes of a unit. + + * A new condition check ConditionArchitecture= has been added + to conditionalize units based on the system architecture, as + reported by uname()'s "machine" field. + + * systemd-networkd now supports matching on the system + virtualization, architecture, kernel command line, host name + and machine ID. + + * logind is now a lot more aggressive when suspending the + machine due to a closed laptop lid. Instead of acting only + on the lid close action it will continuously watch the lid + status and act on it. This is useful for laptops where the + power button is on the outside of the chassis so that it can + be reached without opening the lid (such as the Lenovo + Yoga). On those machines logind will now immediately + re-suspend the machine if the power button has been + accidentally pressed while the laptop was suspended and in a + backpack or similar. + + * logind will now watch SW_DOCK switches and inhibit reaction + to the lid switch if it is pressed. This means that logind + will not suspend the machine anymore if the lid is closed + and the systemd is docked, if the laptop supports SW_DOCK + notifications via the input layer. Note that ACPI docking + stations do not generate this currently. Also note that this + logic is usually not fully sufficient and Desktop + Environments should take a lid switch inhibitor lock when an + external display is connected, as systemd will not watch + this on its own. + + * nspawn will now make use of the devices cgroup controller by + default, and only permit creation of and access to the usual + API device nodes like /dev/null or /dev/random, as well as + access to (but not creation of) the pty devices. + + * We will now ship a default .network file for + systemd-networkd that automatically configures DHCP for + network interfaces created by nspawn's --network-veth or + --network-bridge= switches. + + * systemd will now understand the usual M, K, G, T suffixes + according to SI conventions (i.e. to the base 1000) when + referring to throughput and hardware metrics. It will stay + with IEC conventions (i.e. to the base 1024) for software + metrics, according to what is customary according to + Wikipedia. We explicitly document which base applies for + each configuration option. + + * The DeviceAllow= setting in unit files now supports a syntax + to whitelist an entire group of devices node majors at once, + based on the /proc/devices listing. For example, with the + string "char-pts" it is now possible to whitelist all + current and future pseudo-TTYs at once. + + * sd-event learned a new "post" event source. Event sources of + this type are triggered by the dispatching of any event + source of a type that is not "post". This is useful for + implementing clean-up and check event sources that are + triggered by other work being done in the program. + + * systemd-networkd is no longer statically enabled, but uses + the usual [Install] sections so that it can be + enabled/disabled using systemctl. It still is enabled by + default however. + + * When creating a veth interface pair with systemd-nspawn the + host side will now be prefixed with "vb-" if + --network-bridge= is used, and with "ve-" if --network-veth + is used. This way it is easy to distinguish these cases on + the host, for example to apply different configuration to + them with systemd-networkd. + + * The compatibility libraries for libsystemd-journal.so, + libsystem-id128.so, libsystemd-login.so and + libsystemd-daemon.so do not make use of IFUNC + anymore. Instead we now build libsystemd.so multiple times + under these alternative names. This means that the footprint + is drastically increased, but given that these are + transitional compatibility libraries this shouldn't matter + much. This change has been made necessary to support the ARM + platform for these compatibility libraries, as the ARM + toolchain isn't really at the same level as the toolchain + for other architectures like x86 and does not support + IFUNC. Please make sure to use --enable-compat-libs only + during a transitional period! + + Contributions from: Andreas Fuchs, Armin K, Colin Walters, + Daniel Mack, Dave Reisner, David Herrmann, Djalal Harouni, + Holger Schurig, Jason A. Donenfeld, Jason St. John, Jasper + St. Pierre, Kay Sievers, Lennart Poettering, Łukasz Stelmach, + Marcel Holtmann, Michael Scherer, Michal Sekletar, Mike + Gilbert, Samuli Suominen, Thomas Bächler, Thomas Hindoe + Paaboel Andersen, Tom Gundersen, Umut Tezduyar Lindskog, + Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2014-02-24 + +CHANGES WITH 209: + + * A new component "systemd-networkd" has been added that can + be used to configure local network interfaces statically or + via DHCP. It is capable of bringing up bridges, VLANs, and + bonding. Currently, no hook-ups for interactive network + configuration are provided. Use this for your initrd, + container, embedded, or server setup if you need a simple, + yet powerful, network configuration solution. This + configuration subsystem is quite nifty, as it allows wildcard + hotplug matching in interfaces. For example, with a single + configuration snippet, you can configure that all Ethernet + interfaces showing up are automatically added to a bridge, + or similar. It supports link-sensing and more. + + * A new tool "systemd-socket-proxyd" has been added which can + act as a bidirectional proxy for TCP sockets. This is + useful for adding socket activation support to services that + do not actually support socket activation, including virtual + machines and the like. + + * Add a new tool to save/restore rfkill state on + shutdown/boot. + + * Save/restore state of keyboard backlights in addition to + display backlights on shutdown/boot. + + * udev learned a new SECLABEL{} construct to label device + nodes with a specific security label when they appear. For + now, only SECLABEL{selinux} is supported, but the syntax is + prepared for additional security frameworks. + + * udev gained a new scheme to configure link-level attributes + from files in /etc/systemd/network/*.link. These files can + match against MAC address, device path, driver name and type, + and will apply attributes like the naming policy, link speed, + MTU, duplex settings, Wake-on-LAN settings, MAC address, MAC + address assignment policy (randomized, ...). + + * The configuration of network interface naming rules for + "permanent interface names" has changed: a new NamePolicy= + setting in the [Link] section of .link files determines the + priority of possible naming schemes (onboard, slot, mac, + path). The default value of this setting is determined by + /usr/lib/net/links/99-default.link. Old + 80-net-name-slot.rules udev configuration file has been + removed, so local configuration overriding this file should + be adapated to override 99-default.link instead. + + * When the User= switch is used in a unit file, also + initialize $SHELL= based on the user database entry. + + * systemd no longer depends on libdbus. All communication is + now done with sd-bus, systemd's low-level bus library + implementation. + + * kdbus support has been added to PID 1 itself. When kdbus is + enabled, this causes PID 1 to set up the system bus and + enable support for a new ".busname" unit type that + encapsulates bus name activation on kdbus. It works a little + bit like ".socket" units, except for bus names. A new + generator has been added that converts classic dbus1 service + activation files automatically into native systemd .busname + and .service units. + + * sd-bus: add a light-weight vtable implementation that allows + defining objects on the bus with a simple static const + vtable array of its methods, signals and properties. + + * systemd will not generate or install static dbus + introspection data anymore to /usr/share/dbus-1/interfaces, + as the precise format of these files is unclear, and + nothing makes use of it. + + * A proxy daemon is now provided to proxy clients connecting + via classic D-Bus AF_UNIX sockets to kdbus, to provide full + compatibility with classic D-Bus. + + * A bus driver implementation has been added that supports the + classic D-Bus bus driver calls on kdbus, also for + compatibility purposes. + + * A new API "sd-event.h" has been added that implements a + minimal event loop API built around epoll. It provides a + couple of features that direct epoll usage is lacking: + prioritization of events, scales to large numbers of timer + events, per-event timer slack (accuracy), system-wide + coalescing of timer events, exit handlers, watchdog + supervision support using systemd's sd_notify() API, child + process handling. + + * A new API "sd-rntl.h" has been added that provides an API + around the route netlink interface of the kernel, similar in + style to "sd-bus.h". + + * A new API "sd-dhcp-client.h" has been added that provides a + small DHCPv4 client-side implementation. This is used by + "systemd-networkd". + + * There is a new kernel command line option + "systemd.restore_state=0|1". When set to "0", none of the + systemd tools will restore saved runtime state to hardware + devices. More specifically, the rfkill and backlight states + are not restored. + + * The FsckPassNo= compatibility option in mount/service units + has been removed. The fstab generator will now add the + necessary dependencies automatically, and does not require + PID1's support for that anymore. + + * journalctl gained a new switch, --list-boots, that lists + recent boots with their times and boot IDs. + + * The various tools like systemctl, loginctl, timedatectl, + busctl, systemd-run, ... have gained a new switch "-M" to + connect to a specific, local OS container (as direct + connection, without requiring SSH). This works on any + container that is registered with machined, such as those + created by libvirt-lxc or nspawn. + + * systemd-run and systemd-analyze also gained support for "-H" + to connect to remote hosts via SSH. This is particularly + useful for systemd-run because it enables queuing of jobs + onto remote systems. + + * machinectl gained a new command "login" to open a getty + login in any local container. This works with any container + that is registered with machined (such as those created by + libvirt-lxc or nspawn), and which runs systemd inside. + + * machinectl gained a new "reboot" command that may be used to + trigger a reboot on a specific container that is registered + with machined. This works on any container that runs an init + system of some kind. + + * systemctl gained a new "list-timers" command to print a nice + listing of installed timer units with the times they elapse + next. + + * Alternative reboot() parameters may now be specified on the + "systemctl reboot" command line and are passed to the + reboot() system call. + + * systemctl gained a new --job-mode= switch to configure the + mode to queue a job with. This is a more generic version of + --fail, --irreversible, and --ignore-dependencies, which are + still available but not advertised anymore. + + * /etc/systemd/system.conf gained new settings to configure + various default timeouts of units, as well as the default + start limit interval and burst. These may still be overridden + within each Unit. + + * PID1 will now export on the bus profile data of the security + policy upload process (such as the SELinux policy upload to + the kernel). + + * journald: when forwarding logs to the console, include + timestamps (following the setting in + /sys/module/printk/parameters/time). + + * OnCalendar= in timer units now understands the special + strings "yearly" and "annually". (Both are equivalent) + + * The accuracy of timer units is now configurable with the new + AccuracySec= setting. It defaults to 1min. + + * A new dependency type JoinsNamespaceOf= has been added that + allows running two services within the same /tmp and network + namespace, if PrivateNetwork= or PrivateTmp= are used. + + * A new command "cat" has been added to systemctl. It outputs + the original unit file of a unit, and concatenates the + contents of additional "drop-in" unit file snippets, so that + the full configuration is shown. + + * systemctl now supports globbing on the various "list-xyz" + commands, like "list-units" or "list-sockets", as well as on + those commands which take multiple unit names. + + * journalctl's --unit= switch gained support for globbing. + + * All systemd daemons now make use of the watchdog logic so + that systemd automatically notices when they hang. + + * If the $container_ttys environment variable is set, + getty-generator will automatically spawn a getty for each + listed tty. This is useful for container managers to request + login gettys to be spawned on as many ttys as needed. + + * %h, %s, %U specifier support is not available anymore when + used in unit files for PID 1. This is because NSS calls are + not safe from PID 1. They stay available for --user + instances of systemd, and as special case for the root user. + + * loginctl gained a new "--no-legend" switch to turn off output + of the legend text. + + * The "sd-login.h" API gained three new calls: + sd_session_is_remote(), sd_session_get_remote_user(), + sd_session_get_remote_host() to query information about + remote sessions. + + * The udev hardware database now also carries vendor/product + information of SDIO devices. + + * The "sd-daemon.h" API gained a new sd_watchdog_enabled() to + determine whether watchdog notifications are requested by + the system manager. + + * Socket-activated per-connection services now include a + short description of the connection parameters in the + description. + + * tmpfiles gained a new "--boot" option. When this is not used, + only lines where the command character is not suffixed with + "!" are executed. When this option is specified, those + options are executed too. This partitions tmpfiles + directives into those that can be safely executed at any + time, and those which should be run only at boot (for + example, a line that creates /run/nologin). + + * A new API "sd-resolve.h" has been added which provides a simple + asynchronous wrapper around glibc NSS host name resolution + calls, such as getaddrinfo(). In contrast to glibc's + getaddrinfo_a(), it does not use signals. In contrast to most + other asynchronous name resolution libraries, this one does + not reimplement DNS, but reuses NSS, so that alternate + host name resolution systems continue to work, such as mDNS, + LDAP, etc. This API is based on libasyncns, but it has been + cleaned up for inclusion in systemd. + + * The APIs "sd-journal.h", "sd-login.h", "sd-id128.h", + "sd-daemon.h" are no longer found in individual libraries + libsystemd-journal.so, libsystemd-login.so, + libsystemd-id128.so, libsystemd-daemon.so. Instead, we have + merged them into a single library, libsystemd.so, which + provides all symbols. The reason for this is cyclic + dependencies, as these libraries tend to use each other's + symbols. So far, we've managed to workaround that by linking + a copy of a good part of our code into each of these + libraries again and again, which, however, makes certain + things hard to do, like sharing static variables. Also, it + substantially increases footprint. With this change, there + is only one library for the basic APIs systemd + provides. Also, "sd-bus.h", "sd-memfd.h", "sd-event.h", + "sd-rtnl.h", "sd-resolve.h", "sd-utf8.h" are found in this + library as well, however are subject to the --enable-kdbus + switch (see below). Note that "sd-dhcp-client.h" is not part + of this library (this is because it only consumes, never + provides, services of/to other APIs). To make the transition + easy from the separate libraries to the unified one, we + provide the --enable-compat-libs compile-time switch which + will generate stub libraries that are compatible with the + old ones but redirect all calls to the new one. + + * All of the kdbus logic and the new APIs "sd-bus.h", + "sd-memfd.h", "sd-event.h", "sd-rtnl.h", "sd-resolve.h", + and "sd-utf8.h" are compile-time optional via the + "--enable-kdbus" switch, and they are not compiled in by + default. To make use of kdbus, you have to explicitly enable + the switch. Note however, that neither the kernel nor the + userspace API for all of this is considered stable yet. We + want to maintain the freedom to still change the APIs for + now. By specifying this build-time switch, you acknowledge + that you are aware of the instability of the current + APIs. + + * Also, note that while kdbus is pretty much complete, + it lacks one thing: proper policy support. This means you + can build a fully working system with all features; however, + it will be highly insecure. Policy support will be added in + one of the next releases, at the same time that we will + declare the APIs stable. + + * When the kernel command-line argument "kdbus" is specified, + systemd will automatically load the kdbus.ko kernel module. At + this stage of development, it is only useful for testing kdbus + and should not be used in production. Note: if "--enable-kdbus" + is specified, and the kdbus.ko kernel module is available, and + "kdbus" is added to the kernel command line, the entire system + runs with kdbus instead of dbus-daemon, with the above mentioned + problem of missing the system policy enforcement. Also a future + version of kdbus.ko or a newer systemd will not be compatible with + each other, and will unlikely be able to boot the machine if only + one of them is updated. + + * systemctl gained a new "import-environment" command which + uploads the caller's environment (or parts thereof) into the + service manager so that it is inherited by services started + by the manager. This is useful to upload variables like + $DISPLAY into the user service manager. + + * A new PrivateDevices= switch has been added to service units + which allows running a service with a namespaced /dev + directory that does not contain any device nodes for + physical devices. More specifically, it only includes devices + such as /dev/null, /dev/urandom, and /dev/zero which are API + entry points. + + * logind has been extended to support behaviour like VT + switching on seats that do not support a VT. This makes + multi-session available on seats that are not the first seat + (seat0), and on systems where kernel support for VTs has + been disabled at compile-time. + + * If a process holds a delay lock for system sleep or shutdown + and fails to release it in time, we will now log its + identity. This makes it easier to identify processes that + cause slow suspends or power-offs. + + * When parsing /etc/crypttab, support for a new key-slot= + option as supported by Debian is added. It allows indicating + which LUKS slot to use on disk, speeding up key loading. + + * The sd_journald_sendv() API call has been checked and + officially declared to be async-signal-safe so that it may + be invoked from signal handlers for logging purposes. + + * Boot-time status output is now enabled automatically after a + short timeout if boot does not progress, in order to give + the user an indication what she or he is waiting for. + + * The boot-time output has been improved to show how much time + remains until jobs expire. + + * The KillMode= switch in service units gained a new possible + value "mixed". If set, and the unit is shut down, then the + initial SIGTERM signal is sent only to the main daemon + process, while the following SIGKILL signal is sent to + all remaining processes of the service. + + * When a scope unit is registered, a new property "Controller" + may be set. If set to a valid bus name, systemd will send a + RequestStop() signal to this name when it would like to shut + down the scope. This may be used to hook manager logic into + the shutdown logic of scope units. Also, scope units may now + be put in a special "abandoned" state, in which case the + manager process which created them takes no further + responsibilities for it. + + * When reading unit files, systemd will now verify + the access mode of these files, and warn about certain + suspicious combinations. This has been added to make it + easier to track down packaging bugs where unit files are + marked executable or world-writable. + + * systemd-nspawn gained a new "--setenv=" switch to set + container-wide environment variables. The similar option in + systemd-activate was renamed from "--environment=" to + "--setenv=" for consistency. + + * systemd-nspawn has been updated to create a new kdbus domain + for each container that is invoked, thus allowing each + container to have its own set of system and user buses, + independent of the host. + + * systemd-nspawn gained a new --drop-capability= switch to run + the container with less capabilities than the default. Both + --drop-capability= and --capability= now take the special + string "all" for dropping or keeping all capabilities. + + * systemd-nspawn gained new switches for executing containers + with specific SELinux labels set. + + * systemd-nspawn gained a new --quiet switch to not generate + any additional output but the container's own console + output. + + * systemd-nspawn gained a new --share-system switch to run a + container without PID namespacing enabled. + + * systemd-nspawn gained a new --register= switch to control + whether the container is registered with systemd-machined or + not. This is useful for containers that do not run full + OS images, but only specific apps. + + * systemd-nspawn gained a new --keep-unit which may be used + when invoked as the only program from a service unit, and + results in registration of the unit service itself in + systemd-machined, instead of a newly opened scope unit. + + * systemd-nspawn gained a new --network-interface= switch for + moving arbitrary interfaces to the container. The new + --network-veth switch creates a virtual Ethernet connection + between host and container. The new --network-bridge= + switch then allows assigning the host side of this virtual + Ethernet connection to a bridge device. + + * systemd-nspawn gained a new --personality= switch for + setting the kernel personality for the container. This is + useful when running a 32bit container on a 64bit host. A + similar option Personality= is now also available in service + units. + + * logind will now also track a "Desktop" identifier for each + session which encodes the desktop environment of it. This is + useful for desktop environments that want to identify + multiple running sessions of itself easily. + + * A new SELinuxContext= setting for service units has been + added that allows setting a specific SELinux execution + context for a service. + + * Most systemd client tools will now honour $SYSTEMD_LESS for + settings of the "less" pager. By default, these tools will + override $LESS to allow certain operations to work, such as + jump-to-the-end. With $SYSTEMD_LESS, it is possible to + influence this logic. + + * systemd's "seccomp" hook-up has been changed to make use of + the libseccomp library instead of using its own + implementation. This has benefits for portability among + other things. + + * For usage together with SystemCallFilter=, a new + SystemCallErrorNumber= setting has been introduced that + allows configuration of a system error number to return on + filtered system calls, instead of immediately killing the + process. Also, SystemCallArchitectures= has been added to + limit access to system calls of a particular architecture + (in order to turn off support for unused secondary + architectures). There is also a global + SystemCallArchitectures= setting in system.conf now to turn + off support for non-native system calls system-wide. + + * systemd requires a kernel with a working name_to_handle_at(), + please see the kernel config requirements in the README file. + + Contributions from: Adam Williamson, Alex Jia, Anatol Pomozov, + Ansgar Burchardt, AppleBloom, Auke Kok, Bastien Nocera, + Chengwei Yang, Christian Seiler, Colin Guthrie, Colin Walters, + Cristian Rodríguez, Daniel Buch, Daniele Medri, Daniel J + Walsh, Daniel Mack, Dan McGee, Dave Reisner, David Coppa, + David Herrmann, David Strauss, Djalal Harouni, Dmitry Pisklov, + Elia Pinto, Florian Weimer, George McCollister, Goffredo + Baroncelli, Greg Kroah-Hartman, Hendrik Brueckner, Igor + Zhbanov, Jan Engelhardt, Jan Janssen, Jason A. Donenfeld, + Jason St. John, Jasper St. Pierre, Jóhann B. Guðmundsson, Jose + Ignacio Naranjo, Karel Zak, Kay Sievers, Kristian Høgsberg, + Lennart Poettering, Lubomir Rintel, Lukas Nykryn, Lukasz + Skalski, Łukasz Stelmach, Luke Shumaker, Mantas Mikulėnas, + Marc-Antoine Perennou, Marcel Holtmann, Marcos Felipe Rasia de + Mello, Marko Myllynen, Martin Pitt, Matthew Monaco, Michael + Marineau, Michael Scherer, Michał Górny, Michal Sekletar, + Michele Curti, Oleksii Shevchuk, Olivier Brunel, Patrik Flykt, + Pavel Holica, Raudi, Richard Marko, Ronny Chevalier, Sébastien + Luttringer, Sergey Ptashnick, Shawn Landden, Simon Peeters, + Stefan Beller, Susant Sahani, Sylvain Plantefeve, Sylvia Else, + Tero Roponen, Thomas Bächler, Thomas Hindoe Paaboel Andersen, + Tom Gundersen, Umut Tezduyar Lindskog, Unai Uribarri, Václav + Pavlín, Vincent Batts, WaLyong Cho, William Giokas, Yang + Zhiyong, Yin Kangkai, Yuxuan Shui, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2014-02-20 + +CHANGES WITH 208: + + * logind has gained support for facilitating privileged input + and drm device access for unprivileged clients. This work is + useful to allow Wayland display servers (and similar + programs, such as kmscon) to run under the user's ID and + access input and drm devices which are normally + protected. When this is used (and the kernel is new enough) + logind will "mute" IO on the file descriptors passed to + Wayland as long as it is in the background and "unmute" it + if it returns into the foreground. This allows secure + session switching without allowing background sessions to + eavesdrop on input and display data. This also introduces + session switching support if VT support is turned off in the + kernel, and on seats that are not seat0. + + * A new kernel command line option luks.options= is understood + now which allows specifiying LUKS options for usage for LUKS + encrypted partitions specified with luks.uuid=. + + * tmpfiles.d(5) snippets may now use specifier expansion in + path names. More specifically %m, %b, %H, %v, are now + replaced by the local machine id, boot id, hostname, and + kernel version number. + + * A new tmpfiles.d(5) command "m" has been introduced which + may be used to change the owner/group/access mode of a file + or directory if it exists, but do nothing if it doesn't. + + * This release removes high-level support for the + MemorySoftLimit= cgroup setting. The underlying kernel + cgroup attribute memory.soft_limit= is currently badly + designed and likely to be removed from the kernel API in its + current form, hence we shouldn't expose it for now. + + * The memory.use_hierarchy cgroup attribute is now enabled for + all cgroups systemd creates in the memory cgroup + hierarchy. This option is likely to be come the built-in + default in the kernel anyway, and the non-hierarchial mode + never made much sense in the intrinsically hierarchial + cgroup system. + + * A new field _SYSTEMD_SLICE= is logged along with all journal + messages containing the slice a message was generated + from. This is useful to allow easy per-customer filtering of + logs among other things. + + * systemd-journald will no longer adjust the group of journal + files it creates to the "systemd-journal" group. Instead we + rely on the journal directory to be owned by the + "systemd-journal" group, and its setgid bit set, so that the + kernel file system layer will automatically enforce that + journal files inherit this group assignment. The reason for + this change is that we cannot allow NSS look-ups from + journald which would be necessary to resolve + "systemd-journal" to a numeric GID, because this might + create deadlocks if NSS involves synchronous queries to + other daemons (such as nscd, or sssd) which in turn are + logging clients of journald and might block on it, which + would then dead lock. A tmpfiles.d(5) snippet included in + systemd will make sure the setgid bit and group are + properly set on the journal directory if it exists on every + boot. However, we recommend adjusting it manually after + upgrades too (or from RPM scriptlets), so that the change is + not delayed until next reboot. + + * Backlight and random seed files in /var/lib/ have moved into + the /var/lib/systemd/ directory, in order to centralize all + systemd generated files in one directory. + + * Boot time performance measurements (as displayed by + "systemd-analyze" for example) will now read ACPI 5.0 FPDT + performance information if that's available to determine how + much time BIOS and boot loader initialization required. With + a sufficiently new BIOS you hence no longer need to boot + with Gummiboot to get access to such information. + + Contributions from: Andrey Borzenkov, Chen Jie, Colin Walters, + Cristian Rodríguez, Dave Reisner, David Herrmann, David + Mackey, David Strauss, Eelco Dolstra, Evan Callicoat, Gao + feng, Harald Hoyer, Jimmie Tauriainen, Kay Sievers, Lennart + Poettering, Lukas Nykryn, Mantas Mikulėnas, Martin Pitt, + Michael Scherer, Michał Górny, Mike Gilbert, Patrick McCarty, + Sebastian Ott, Tom Gundersen, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2013-10-02 + +CHANGES WITH 207: + + * The Restart= option for services now understands a new + on-watchdog setting, which will restart the service + automatically if the service stops sending out watchdog keep + alive messages (as configured with WatchdogSec=). + + * The getty generator (which is responsible for bringing up a + getty on configured serial consoles) will no longer only + start a getty on the primary kernel console but on all + others, too. This makes the order in which console= is + specified on the kernel command line less important. + + * libsystemd-logind gained a new sd_session_get_vt() call to + retrieve the VT number of a session. + + * If the option "tries=0" is set for an entry of /etc/crypttab + its passphrase is queried indefinitely instead of any + maximum number of tries. + + * If a service with a configure PID file terminates its PID + file will now be removed automatically if it still exists + afterwards. This should put an end to stale PID files. + + * systemd-run will now also take relative binary path names + for execution and no longer insists on absolute paths. + + * InaccessibleDirectories= and ReadOnlyDirectories= now take + paths that are optionally prefixed with "-" to indicate that + it should not be considered a failure if they don't exist. + + * journalctl -o (and similar commands) now understands a new + output mode "short-precise", it is similar to "short" but + shows timestamps with usec accuracy. + + * The option "discard" (as known from Debian) is now + synonymous to "allow-discards" in /etc/crypttab. In fact, + "discard" is preferred now (since it is easier to remember + and type). + + * Some licensing clean-ups were made, so that more code is now + LGPL-2.1 licensed than before. + + * A minimal tool to save/restore the display backlight + brightness across reboots has been added. It will store the + backlight setting as late as possible at shutdown, and + restore it as early as possible during reboot. + + * A logic to automatically discover and enable home and swap + partitions on GPT disks has been added. With this in place + /etc/fstab becomes optional for many setups as systemd can + discover certain partitions located on the root disk + automatically. Home partitions are recognized under their + GPT type ID 933ac7e12eb44f13b8440e14e2aef915. Swap + partitions are recognized under their GPT type ID + 0657fd6da4ab43c484e50933c84b4f4f. + + * systemd will no longer pass any environment from the kernel + or initrd to system services. If you want to set an + environment for all services, do so via the kernel command + line systemd.setenv= assignment. + + * The systemd-sysctl tool no longer natively reads the file + /etc/sysctl.conf. If desired, the file should be symlinked + from /etc/sysctl.d/99-sysctl.conf. Apart from providing + legacy support by a symlink rather than built-in code, it + also makes the otherwise hidden order of application of the + different files visible. (Note that this partly reverts to a + pre-198 application order of sysctl knobs!) + + * The "systemctl set-log-level" and "systemctl dump" commands + have been moved to systemd-analyze. + + * systemd-run learned the new --remain-after-exit switch, + which causes the scope unit not to be cleaned up + automatically after the process terminated. + + * tmpfiles learned a new --exclude-prefix= switch to exclude + certain paths from operation. + + * journald will now automatically flush all messages to disk + as soon as a message of the log priorities CRIT, ALERT or + EMERG is received. + + Contributions from: Andrew Cook, Brandon Philips, Christian + Hesse, Christoph Junghans, Colin Walters, Daniel Schaal, + Daniel Wallace, Dave Reisner, David Herrmann, Gao feng, George + McCollister, Giovanni Campagna, Hannes Reinecke, Harald Hoyer, + Herczeg Zsolt, Holger Hans Peter Freyther, Jan Engelhardt, + Jesper Larsen, Kay Sievers, Khem Raj, Lennart Poettering, + Lukas Nykryn, Maciej Wereski, Mantas Mikulėnas, Marcel + Holtmann, Martin Pitt, Michael Biebl, Michael Marineau, + Michael Scherer, Michael Stapelberg, Michal Sekletar, Michał + Górny, Olivier Brunel, Ondrej Balaz, Ronny Chevalier, Shawn + Landden, Steven Hiscocks, Thomas Bächler, Thomas Hindoe + Paaboel Andersen, Tom Gundersen, Umut Tezduyar, WANG Chao, + William Giokas, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2013-09-13 + +CHANGES WITH 206: + + * The documentation has been updated to cover the various new + concepts introduced with 205. + + * Unit files now understand the new %v specifier which + resolves to the kernel version string as returned by "uname + -r". + + * systemctl now supports filtering the unit list output by + load state, active state and sub state, using the new + --state= parameter. + + * "systemctl status" will now show the results of the + condition checks (like ConditionPathExists= and similar) of + the last start attempts of the unit. They are also logged to + the journal. + + * "journalctl -b" may now be used to look for boot output of a + specific boot. Try "journalctl -b -1" for the previous boot, + but the syntax is substantially more powerful. + + * "journalctl --show-cursor" has been added which prints the + cursor string the last shown log line. This may then be used + with the new "journalctl --after-cursor=" switch to continue + browsing logs from that point on. + + * "journalctl --force" may now be used to force regeneration + of an FSS key. + + * Creation of "dead" device nodes has been moved from udev + into kmod and tmpfiles. Previously, udev would read the kmod + databases to pre-generate dead device nodes based on meta + information contained in kernel modules, so that these would + be auto-loaded on access rather then at boot. As this + doesn't really have much to do with the exposing actual + kernel devices to userspace this has always been slightly + alien in the udev codebase. Following the new scheme kmod + will now generate a runtime snippet for tmpfiles from the + module meta information and it now is tmpfiles' job to the + create the nodes. This also allows overriding access and + other parameters for the nodes using the usual tmpfiles + facilities. As side effect this allows us to remove the + CAP_SYS_MKNOD capability bit from udevd entirely. + + * logind's device ACLs may now be applied to these "dead" + devices nodes too, thus finally allowing managed access to + devices such as /dev/snd/sequencer whithout loading the + backing module right-away. + + * A new RPM macro has been added that may be used to apply + tmpfiles configuration during package installation. + + * systemd-detect-virt and ConditionVirtualization= now can + detect User-Mode-Linux machines (UML). + + * journald will now implicitly log the effective capabilities + set of processes in the message metadata. + + * systemd-cryptsetup has gained support for TrueCrypt volumes. + + * The initrd interface has been simplified (more specifically, + support for passing performance data via environment + variables and fsck results via files in /run has been + removed). These features were non-essential, and are + nowadays available in a much nicer way by having systemd in + the initrd serialize its state and have the hosts systemd + deserialize it again. + + * The udev "keymap" data files and tools to apply keyboard + specific mappings of scan to key codes, and force-release + scan code lists have been entirely replaced by a udev + "keyboard" builtin and a hwdb data file. + + * systemd will now honour the kernel's "quiet" command line + argument also during late shutdown, resulting in a + completely silent shutdown when used. + + * There's now an option to control the SO_REUSEPORT socket + option in .socket units. + + * Instance units will now automatically get a per-template + subslice of system.slice unless something else is explicitly + configured. For example, instances of sshd@.service will now + implicitly be placed in system-sshd.slice rather than + system.slice as before. + + * Test coverage support may now be enabled at build time. + + Contributions from: Dave Reisner, Frederic Crozat, Harald + Hoyer, Holger Hans Peter Freyther, Jan Engelhardt, Jan + Janssen, Jason St. John, Jesper Larsen, Kay Sievers, Lennart + Poettering, Lukas Nykryn, Maciej Wereski, Martin Pitt, Michael + Olbrich, Ramkumar Ramachandra, Ross Lagerwall, Shawn Landden, + Thomas H.P. Andersen, Tom Gundersen, Tomasz Torcz, William + Giokas, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2013-07-23 + +CHANGES WITH 205: + + * Two new unit types have been introduced: + + Scope units are very similar to service units, however, are + created out of pre-existing processes -- instead of PID 1 + forking off the processes. By using scope units it is + possible for system services and applications to group their + own child processes (worker processes) in a powerful way + which then maybe used to organize them, or kill them + together, or apply resource limits on them. + + Slice units may be used to partition system resources in an + hierarchial fashion and then assign other units to them. By + default there are now three slices: system.slice (for all + system services), user.slice (for all user sessions), + machine.slice (for VMs and containers). + + Slices and scopes have been introduced primarily in + context of the work to move cgroup handling to a + single-writer scheme, where only PID 1 + creates/removes/manages cgroups. + + * There's a new concept of "transient" units. In contrast to + normal units these units are created via an API at runtime, + not from configuration from disk. More specifically this + means it is now possible to run arbitrary programs as + independent services, with all execution parameters passed + in via bus APIs rather than read from disk. Transient units + make systemd substantially more dynamic then it ever was, + and useful as a general batch manager. + + * logind has been updated to make use of scope and slice units + for managing user sessions. As a user logs in he will get + his own private slice unit, to which all sessions are added + as scope units. We also added support for automatically + adding an instance of user@.service for the user into the + slice. Effectively logind will no longer create cgroup + hierarchies on its own now, it will defer entirely to PID 1 + for this by means of scope, service and slice units. Since + user sessions this way become entities managed by PID 1 + the output of "systemctl" is now a lot more comprehensive. + + * A new mini-daemon "systemd-machined" has been added which + may be used by virtualization managers to register local + VMs/containers. nspawn has been updated accordingly, and + libvirt will be updated shortly. machined will collect a bit + of meta information about the VMs/containers, and assign + them their own scope unit (see above). The collected + meta-data is then made available via the "machinectl" tool, + and exposed in "ps" and similar tools. machined/machinectl + is compile-time optional. + + * As discussed earlier, the low-level cgroup configuration + options ControlGroup=, ControlGroupModify=, + ControlGroupPersistent=, ControlGroupAttribute= have been + removed. Please use high-level attribute settings instead as + well as slice units. + + * A new bus call SetUnitProperties() has been added to alter + various runtime parameters of a unit. This is primarily + useful to alter cgroup parameters dynamically in a nice way, + but will be extended later on to make more properties + modifiable at runtime. systemctl gained a new set-properties + command that wraps this call. + + * A new tool "systemd-run" has been added which can be used to + run arbitrary command lines as transient services or scopes, + while configuring a number of settings via the command + line. This tool is currently very basic, however already + very useful. We plan to extend this tool to even allow + queuing of execution jobs with time triggers from the + command line, similar in fashion to "at". + + * nspawn will now inform the user explicitly that kernels with + audit enabled break containers, and suggest the user to turn + off audit. + + * Support for detecting the IMA and AppArmor security + frameworks with ConditionSecurity= has been added. + + * journalctl gained a new "-k" switch for showing only kernel + messages, mimicking dmesg output; in addition to "--user" + and "--system" switches for showing only user's own logs + and system logs. + + * systemd-delta can now show information about drop-in + snippets extending unit files. + + * libsystemd-bus has been substantially updated but is still + not available as public API. + + * systemd will now look for the "debug" argument on the kernel + command line and enable debug logging, similar to + "systemd.log_level=debug" already did before. + + * "systemctl set-default", "systemctl get-default" has been + added to configure the default.target symlink, which + controls what to boot into by default. + + * "systemctl set-log-level" has been added as a convenient + way to raise and lower systemd logging threshold. + + * "systemd-analyze plot" will now show the time the various + generators needed for execution, as well as information + about the unit file loading. + + * libsystemd-journal gained a new sd_journal_open_files() call + for opening specific journal files. journactl also gained a + new switch to expose this new functionality. Previously we + only supported opening all files from a directory, or all + files from the system, as opening individual files only is + racy due to journal file rotation. + + * systemd gained the new DefaultEnvironment= setting in + /etc/systemd/system.conf to set environment variables for + all services. + + * If a privileged process logs a journal message with the + OBJECT_PID= field set, then journald will automatically + augment this with additional OBJECT_UID=, OBJECT_GID=, + OBJECT_COMM=, OBJECT_EXE=, ... fields. This is useful if + system services want to log events about specific client + processes. journactl/systemctl has been updated to make use + of this information if all log messages regarding a specific + unit is requested. + + Contributions from: Auke Kok, Chengwei Yang, Colin Walters, + Cristian Rodríguez, Daniel Albers, Daniel Wallace, Dave + Reisner, David Coppa, David King, David Strauss, Eelco + Dolstra, Gabriel de Perthuis, Harald Hoyer, Jan Alexander + Steffens, Jan Engelhardt, Jan Janssen, Jason St. John, Johan + Heikkilä, Karel Zak, Karol Lewandowski, Kay Sievers, Lennart + Poettering, Lukas Nykryn, Mantas Mikulėnas, Marius Vollmer, + Martin Pitt, Michael Biebl, Michael Olbrich, Michael Tremer, + Michal Schmidt, Michał Bartoszkiewicz, Nirbheek Chauhan, + Pierre Neidhardt, Ross Burton, Ross Lagerwall, Sean McGovern, + Thomas Hindoe Paaboel Andersen, Tom Gundersen, Umut Tezduyar, + Václav Pavlín, Zachary Cook, Zbigniew Jędrzejewski-Szmek, + Łukasz Stelmach, 장동준 + +CHANGES WITH 204: + + * The Python bindings gained some minimal support for the APIs + exposed by libsystemd-logind. + + * ConditionSecurity= gained support for detecting SMACK. Since + this condition already supports SELinux and AppArmor we only + miss IMA for this. Patches welcome! + + Contributions from: Karol Lewandowski, Lennart Poettering, + Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 203: + + * systemd-nspawn will now create /etc/resolv.conf if + necessary, before bind-mounting the host's file onto it. + + * systemd-nspawn will now store meta information about a + container on the container's cgroup as extended attribute + fields, including the root directory. + + * The cgroup hierarchy has been reworked in many ways. All + objects any of the components systemd creates in the cgroup + tree are now suffixed. More specifically, user sessions are + now placed in cgroups suffixed with ".session", users in + cgroups suffixed with ".user", and nspawn containers in + cgroups suffixed with ".nspawn". Furthermore, all cgroup + names are now escaped in a simple scheme to avoid collision + of userspace object names with kernel filenames. This work + is preparation for making these objects relocatable in the + cgroup tree, in order to allow easy resource partitioning of + these objects without causing naming conflicts. + + * systemctl list-dependencies gained the new switches + --plain, --reverse, --after and --before. + + * systemd-inhibit now shows the process name of processes that + have taken an inhibitor lock. + + * nss-myhostname will now also resolve "localhost" + implicitly. This makes /etc/hosts an optional file and + nicely handles that on IPv6 ::1 maps to both "localhost" and + the local hostname. + + * libsystemd-logind.so gained a new call + sd_get_machine_names() to enumerate running containers and + VMs (currently only supported by very new libvirt and + nspawn). sd_login_monitor can now be used to watch + VMs/containers coming and going. + + * .include is not allowed recursively anymore, and only in + unit files. Usually it is better to use drop-in snippets in + .d/*.conf anyway, as introduced with systemd 198. + + * systemd-analyze gained a new "critical-chain" command that + determines the slowest chain of units run during system + boot-up. It is very useful for tracking down where + optimizing boot time is the most beneficial. + + * systemd will no longer allow manipulating service paths in + the name=systemd:/system cgroup tree using ControlGroup= in + units. (But is still fine with it in all other dirs.) + + * There's a new systemd-nspawn@.service service file that may + be used to easily run nspawn containers as system + services. With the container's root directory in + /var/lib/container/foobar it is now sufficient to run + "systemctl start systemd-nspawn@foobar.service" to boot it. + + * systemd-cgls gained a new parameter "--machine" to list only + the processes within a certain container. + + * ConditionSecurity= now can check for "apparmor". We still + are lacking checks for SMACK and IMA for this condition + check though. Patches welcome! + + * A new configuration file /etc/systemd/sleep.conf has been + added that may be used to configure which kernel operation + systemd is supposed to execute when "suspend", "hibernate" + or "hybrid-sleep" is requested. This makes the new kernel + "freeze" state accessible to the user. + + * ENV{SYSTEMD_WANTS} in udev rules will now implicitly escape + the passed argument if applicable. + + Contributions from: Auke Kok, Colin Guthrie, Colin Walters, + Cristian Rodríguez, Daniel Buch, Daniel Wallace, Dave Reisner, + Evangelos Foutras, Greg Kroah-Hartman, Harald Hoyer, Josh + Triplett, Kay Sievers, Lennart Poettering, Lukas Nykryn, + MUNEDA Takahiro, Mantas Mikulėnas, Mirco Tischler, Nathaniel + Chen, Nirbheek Chauhan, Ronny Chevalier, Ross Lagerwall, Tom + Gundersen, Umut Tezduyar, Ville Skyttä, Zbigniew + Jędrzejewski-Szmek + +CHANGES WITH 202: + + * The output of 'systemctl list-jobs' got some polishing. The + '--type=' argument may now be passed more than once. A new + command 'systemctl list-sockets' has been added which shows + a list of kernel sockets systemd is listening on with the + socket units they belong to, plus the units these socket + units activate. + + * The experimental libsystemd-bus library got substantial + updates to work in conjunction with the (also experimental) + kdbus kernel project. It works well enough to exchange + messages with some sophistication. Note that kdbus is not + ready yet, and the library is mostly an elaborate test case + for now, and not installable. + + * systemd gained a new unit 'systemd-static-nodes.service' + that generates static device nodes earlier during boot, and + can run in conjunction with udev. + + * libsystemd-login gained a new call sd_pid_get_user_unit() + to retrieve the user systemd unit a process is running + in. This is useful for systems where systemd is used as + session manager. + + * systemd-nspawn now places all containers in the new /machine + top-level cgroup directory in the name=systemd + hierarchy. libvirt will soon do the same, so that we get a + uniform separation of /system, /user and /machine for system + services, user processes and containers/virtual + machines. This new cgroup hierarchy is also useful to stick + stable names to specific container instances, which can be + recognized later this way (this name may be controlled + via systemd-nspawn's new -M switch). libsystemd-login also + gained a new call sd_pid_get_machine_name() to retrieve the + name of the container/VM a specific process belongs to. + + * bootchart can now store its data in the journal. + + * libsystemd-journal gained a new call + sd_journal_add_conjunction() for AND expressions to the + matching logic. This can be used to express more complex + logical expressions. + + * journactl can now take multiple --unit= and --user-unit= + switches. + + * The cryptsetup logic now understands the "luks.key=" kernel + command line switch for specifying a file to read the + decryption key from. Also, if a configured key file is not + found the tool will now automatically fall back to prompting + the user. + + * Python systemd.journal module was updated to wrap recently + added functions from libsystemd-journal. The interface was + changed to bring the low level interface in s.j._Reader + closer to the C API, and the high level interface in + s.j.Reader was updated to wrap and convert all data about + an entry. + + Contributions from: Anatol Pomozov, Auke Kok, Harald Hoyer, + Henrik Grindal Bakken, Josh Triplett, Kay Sievers, Lennart + Poettering, Lukas Nykryn, Mantas Mikulėnas Marius Vollmer, + Martin Jansa, Martin Pitt, Michael Biebl, Michal Schmidt, + Mirco Tischler, Pali Rohar, Simon Peeters, Steven Hiscocks, + Tom Gundersen, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 201: + + * journalctl --update-catalog now understands a new --root= + option to operate on catalogs found in a different root + directory. + + * During shutdown after systemd has terminated all running + services a final killing loop kills all remaining left-over + processes. We will now print the name of these processes + when we send SIGKILL to them, since this usually indicates a + problem. + + * If /etc/crypttab refers to password files stored on + configured mount points automatic dependencies will now be + generated to ensure the specific mount is established first + before the key file is attempted to be read. + + * 'systemctl status' will now show information about the + network sockets a socket unit is listening on. + + * 'systemctl status' will also shown information about any + drop-in configuration file for units. (Drop-In configuration + files in this context are files such as + /etc/systemd/systemd/foobar.service.d/*.conf) + + * systemd-cgtop now optionally shows summed up CPU times of + cgroups. Press '%' while running cgtop to switch between + percentage and absolute mode. This is useful to determine + which cgroups use up the most CPU time over the entire + runtime of the system. systemd-cgtop has also been updated + to be 'pipeable' for processing with further shell tools. + + * 'hostnamectl set-hostname' will now allow setting of FQDN + hostnames. + + * The formatting and parsing of time span values has been + changed. The parser now understands fractional expressions + such as "5.5h". The formatter will now output fractional + expressions for all time spans under 1min, i.e. "5.123456s" + rather than "5s 123ms 456us". For time spans under 1s + millisecond values are shown, for those under 1ms + microsecond values are shown. This should greatly improve + all time-related output of systemd. + + * libsystemd-login and libsystemd-journal gained new + functions for querying the poll() events mask and poll() + timeout value for integration into arbitrary event + loops. + + * localectl gained the ability to list available X11 keymaps + (models, layouts, variants, options). + + * 'systemd-analyze dot' gained the ability to filter for + specific units via shell-style globs, to create smaller, + more useful graphs. I.e. it's now possible to create simple + graphs of all the dependencies between only target units, or + of all units that Avahi has dependencies with. + + Contributions from: Cristian Rodríguez, Dr. Tilmann Bubeck, + Harald Hoyer, Holger Hans Peter Freyther, Kay Sievers, Kelly + Anderson, Koen Kooi, Lennart Poettering, Maksim Melnikau, + Marc-Antoine Perennou, Marius Vollmer, Martin Pitt, Michal + Schmidt, Oleksii Shevchuk, Ronny Chevalier, Simon McVittie, + Steven Hiscocks, Thomas Weißschuh, Umut Tezduyar, Václav + Pavlín, Zbigniew Jędrzejewski-Szmek, Łukasz Stelmach + +CHANGES WITH 200: + + * The boot-time readahead implementation for rotating media + will now read the read-ahead data in multiple passes which + consist of all read requests made in equidistant time + intervals. This means instead of strictly reading read-ahead + data in its physical order on disk we now try to find a + middle ground between physical and access time order. + + * /etc/os-release files gained a new BUILD_ID= field for usage + on operating systems that provide continuous builds of OS + images. + + Contributions from: Auke Kok, Eelco Dolstra, Kay Sievers, + Lennart Poettering, Lukas Nykryn, Martin Pitt, Václav Pavlín + William Douglas, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 199: + + * systemd-python gained an API exposing libsystemd-daemon. + + * The SMACK setup logic gained support for uploading CIPSO + security policy. + + * Behaviour of PrivateTmp=, ReadWriteDirectories=, + ReadOnlyDirectories= and InaccessibleDirectories= has + changed. The private /tmp and /var/tmp directories are now + shared by all processes of a service (which means + ExecStartPre= may now leave data in /tmp that ExecStart= of + the same service can still access). When a service is + stopped its temporary directories are immediately deleted + (normal clean-up with tmpfiles is still done in addition to + this though). + + * By default, systemd will now set a couple of sysctl + variables in the kernel: the safe sysrq options are turned + on, IP route verification is turned on, and source routing + disabled. The recently added hardlink and softlink + protection of the kernel is turned on. These settings should + be reasonably safe, and good defaults for all new systems. + + * The predictable network naming logic may now be turned off + with a new kernel command line switch: net.ifnames=0. + + * A new libsystemd-bus module has been added that implements a + pretty complete D-Bus client library. For details see: + + http://lists.freedesktop.org/archives/systemd-devel/2013-March/009797.html + + * journald will now explicitly flush the journal files to disk + at the latest 5min after each write. The file will then also + be marked offline until the next write. This should increase + reliability in case of a crash. The synchronization delay + can be configured via SyncIntervalSec= in journald.conf. + + * There's a new remote-fs-setup.target unit that can be used + to pull in specific services when at least one remote file + system is to be mounted. + + * There are new targets timers.target and paths.target as + canonical targets to pull user timer and path units in + from. This complements sockets.target with a similar + purpose for socket units. + + * libudev gained a new call udev_device_set_attribute_value() + to set sysfs attributes of a device. + + * The udev daemon now sets the default number of worker + processes executed in parallel based on the number of available + CPUs instead of the amount of available RAM. This is supposed + to provide a more reliable default and limit a too aggressive + paralellism for setups with 1000s of devices connected. + + Contributions from: Auke Kok, Colin Walters, Cristian + Rodríguez, Daniel Buch, Dave Reisner, Frederic Crozat, Hannes + Reinecke, Harald Hoyer, Jan Alexander Steffens, Jan + Engelhardt, Josh Triplett, Kay Sievers, Lennart Poettering, + Mantas Mikulėnas, Martin Pitt, Mathieu Bridon, Michael Biebl, + Michal Schmidt, Michal Sekletar, Miklos Vajna, Nathaniel Chen, + Oleksii Shevchuk, Ozan Çağlayan, Thomas Hindoe Paaboel + Andersen, Tollef Fog Heen, Tom Gundersen, Umut Tezduyar, + Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 198: + + * Configuration of unit files may now be extended via drop-in + files without having to edit/override the unit files + themselves. More specifically, if the administrator wants to + change one value for a service file foobar.service he can + now do so by dropping in a configuration snippet into + /etc/systemd/system/foobar.service.d/*.conf. The unit logic + will load all these snippets and apply them on top of the + main unit configuration file, possibly extending or + overriding its settings. Using these drop-in snippets is + generally nicer than the two earlier options for changing + unit files locally: copying the files from + /usr/lib/systemd/system/ to /etc/systemd/system/ and editing + them there; or creating a new file in /etc/systemd/system/ + that incorporates the original one via ".include". Drop-in + snippets into these .d/ directories can be placed in any + directory systemd looks for units in, and the usual + overriding semantics between /usr/lib, /etc and /run apply + for them too. + + * Most unit file settings which take lists of items can now be + reset by assigning the empty string to them. For example, + normally, settings such as Environment=FOO=BAR append a new + environment variable assignment to the environment block, + each time they are used. By assigning Environment= the empty + string the environment block can be reset to empty. This is + particularly useful with the .d/*.conf drop-in snippets + mentioned above, since this adds the ability to reset list + settings from vendor unit files via these drop-ins. + + * systemctl gained a new "list-dependencies" command for + listing the dependencies of a unit recursively. + + * Inhibitors are now honored and listed by "systemctl + suspend", "systemctl poweroff" (and similar) too, not only + GNOME. These commands will also list active sessions by + other users. + + * Resource limits (as exposed by the various control group + controllers) can now be controlled dynamically at runtime + for all units. More specifically, you can now use a command + like "systemctl set-cgroup-attr foobar.service cpu.shares + 2000" to alter the CPU shares a specific service gets. These + settings are stored persistently on disk, and thus allow the + administrator to easily adjust the resource usage of + services with a few simple commands. This dynamic resource + management logic is also available to other programs via the + bus. Almost any kernel cgroup attribute and controller is + supported. + + * systemd-vconsole-setup will now copy all font settings to + all allocated VTs, where it previously applied them only to + the foreground VT. + + * libsystemd-login gained the new sd_session_get_tty() API + call. + + * This release drops support for a few legacy or + distribution-specific LSB facility names when parsing init + scripts: $x-display-manager, $mail-transfer-agent, + $mail-transport-agent, $mail-transfer-agent, $smtp, + $null. Also, the mail-transfer-agent.target unit backing + this has been removed. Distributions which want to retain + compatibility with this should carry the burden for + supporting this themselves and patch support for these back + in, if they really need to. Also, the facilities $syslog and + $local_fs are now ignored, since systemd does not support + early-boot LSB init scripts anymore, and these facilities + are implied anyway for normal services. syslog.target has + also been removed. + + * There are new bus calls on PID1's Manager object for + cancelling jobs, and removing snapshot units. Previously, + both calls were only available on the Job and Snapshot + objects themselves. + + * systemd-journal-gatewayd gained SSL support. + + * The various "environment" files, such as /etc/locale.conf + now support continuation lines with a backslash ("\") as + last character in the line, similar in style (but different) + to how this is supported in shells. + + * For normal user processes the _SYSTEMD_USER_UNIT= field is + now implicitly appended to every log entry logged. systemctl + has been updated to filter by this field when operating on a + user systemd instance. + + * nspawn will now implicitly add the CAP_AUDIT_WRITE and + CAP_AUDIT_CONTROL capabilities to the capabilities set for + the container. This makes it easier to boot unmodified + Fedora systems in a container, which however still requires + audit=0 to be passed on the kernel command line. Auditing in + kernel and userspace is unfortunately still too broken in + context of containers, hence we recommend compiling it out + of the kernel or using audit=0. Hopefully this will be fixed + one day for good in the kernel. + + * nspawn gained the new --bind= and --bind-ro= parameters to + bind mount specific directories from the host into the + container. + + * nspawn will now mount its own devpts file system instance + into the container, in order not to leak pty devices from + the host into the container. + + * systemd will now read the firmware boot time performance + information from the EFI variables, if the used boot loader + supports this, and takes it into account for boot performance + analysis via "systemd-analyze". This is currently supported + only in conjunction with Gummiboot, but could be supported + by other boot loaders too. For details see: + + http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface + + * A new generator has been added that automatically mounts the + EFI System Partition (ESP) to /boot, if that directory + exists, is empty, and no other file system has been + configured to be mounted there. + + * logind will now send out PrepareForSleep(false) out + unconditionally, after coming back from suspend. This may be + used by applications as asynchronous notification for + system resume events. + + * "systemctl unlock-sessions" has been added, that allows + unlocking the screens of all user sessions at once, similar + how "systemctl lock-sessions" already locked all users + sessions. This is backed by a new D-Bus call UnlockSessions(). + + * "loginctl seat-status" will now show the master device of a + seat. (i.e. the device of a seat that needs to be around for + the seat to be considered available, usually the graphics + card). + + * tmpfiles gained a new "X" line type, that allows + configuration of files and directories (with wildcards) that + shall be excluded from automatic cleanup ("aging"). + + * udev default rules set the device node permissions now only + at "add" events, and do not change them any longer with a + later "change" event. + + * The log messages for lid events and power/sleep keypresses + now carry a message ID. + + * We now have a substantially larger unit test suite, but this + continues to be work in progress. + + * udevadm hwdb gained a new --root= parameter to change the + root directory to operate relative to. + + * logind will now issue a background sync() request to the kernel + early at shutdown, so that dirty buffers are flushed to disk early + instead of at the last moment, in order to optimize shutdown + times a little. + + * A new bootctl tool has been added that is an interface for + certain boot loader operations. This is currently a preview + and is likely to be extended into a small mechanism daemon + like timedated, localed, hostnamed, and can be used by + graphical UIs to enumerate available boot options, and + request boot into firmware operations. + + * systemd-bootchart has been relicensed to LGPLv2.1+ to match + the rest of the package. It also has been updated to work + correctly in initrds. + + * Policykit previously has been runtime optional, and is now + also compile time optional via a configure switch. + + * systemd-analyze has been reimplemented in C. Also "systemctl + dot" has moved into systemd-analyze. + + * "systemctl status" with no further parameters will now print + the status of all active or failed units. + + * Operations such as "systemctl start" can now be executed + with a new mode "--irreversible" which may be used to queue + operations that cannot accidentally be reversed by a later + job queuing. This is by default used to make shutdown + requests more robust. + + * The Python API of systemd now gained a new module for + reading journal files. + + * A new tool kernel-install has been added that can install + kernel images according to the Boot Loader Specification: + + http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec + + * Boot time console output has been improved to provide + animated boot time output for hanging jobs. + + * A new tool systemd-activate has been added which can be used + to test socket activation with, directly from the command + line. This should make it much easier to test and debug + socket activation in daemons. + + * journalctl gained a new "--reverse" (or -r) option to show + journal output in reverse order (i.e. newest line first). + + * journalctl gained a new "--pager-end" (or -e) option to jump + to immediately jump to the end of the journal in the + pager. This is only supported in conjunction with "less". + + * journalctl gained a new "--user-unit=" option, that works + similar to "--unit=" but filters for user units rather than + system units. + + * A number of unit files to ease adoption of systemd in + initrds has been added. This moves some minimal logic from + the various initrd implementations into systemd proper. + + * The journal files are now owned by a new group + "systemd-journal", which exists specifically to allow access + to the journal, and nothing else. Previously, we used the + "adm" group for that, which however possibly covers more + than just journal/log file access. This new group is now + already used by systemd-journal-gatewayd to ensure this + daemon gets access to the journal files and as little else + as possible. Note that "make install" will also set FS ACLs + up for /var/log/journal to give "adm" and "wheel" read + access to it, in addition to "systemd-journal" which owns + the journal files. We recommend that packaging scripts also + add read access to "adm" + "wheel" to /var/log/journal, and + all existing/future journal files. To normal users and + administrators little changes, however packagers need to + ensure to create the "systemd-journal" system group at + package installation time. + + * The systemd-journal-gatewayd now runs as unprivileged user + systemd-journal-gateway:systemd-journal-gateway. Packaging + scripts need to create these system user/group at + installation time. + + * timedated now exposes a new boolean property CanNTP that + indicates whether a local NTP service is available or not. + + * systemd-detect-virt will now also detect xen PVs + + * The pstore file system is now mounted by default, if it is + available. + + * In addition to the SELinux and IMA policies we will now also + load SMACK policies at early boot. + + Contributions from: Adel Gadllah, Aleksander Morgado, Auke + Kok, Ayan George, Bastien Nocera, Colin Walters, Daniel Buch, + Daniel Wallace, Dave Reisner, David Herrmann, David Strauss, + Eelco Dolstra, Enrico Scholz, Frederic Crozat, Harald Hoyer, + Jan Janssen, Jonathan Callen, Kay Sievers, Lennart Poettering, + Lukas Nykryn, Mantas Mikulėnas, Marc-Antoine Perennou, Martin + Pitt, Mauro Dreissig, Max F. Albrecht, Michael Biebl, Michael + Olbrich, Michal Schmidt, Michal Sekletar, Michal Vyskocil, + Michał Bartoszkiewicz, Mirco Tischler, Nathaniel Chen, Nestor + Ovroy, Oleksii Shevchuk, Paul W. Frields, Piotr Drąg, Rob + Clark, Ryan Lortie, Simon McVittie, Simon Peeters, Steven + Hiscocks, Thomas Hindoe Paaboel Andersen, Tollef Fog Heen, Tom + Gundersen, Umut Tezduyar, William Giokas, Zbigniew + Jędrzejewski-Szmek, Zeeshan Ali (Khattak) + +CHANGES WITH 197: + + * Timer units now support calendar time events in addition to + monotonic time events. That means you can now trigger a unit + based on a calendar time specification such as "Thu,Fri + 2013-*-1,5 11:12:13" which refers to 11:12:13 of the first + or fifth day of any month of the year 2013, given that it is + a thursday or friday. This brings timer event support + considerably closer to cron's capabilities. For details on + the supported calendar time specification language see + systemd.time(7). + + * udev now supports a number of different naming policies for + network interfaces for predictable names, and a combination + of these policies is now the default. Please see this wiki + document for details: + + http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames + + * Auke Kok's bootchart implementation has been added to the + systemd tree. It's an optional component that can graph the + boot in quite some detail. It's one of the best bootchart + implementations around and minimal in its code and + dependencies. + + * nss-myhostname has been integrated into the systemd source + tree. nss-myhostname guarantees that the local hostname + always stays resolvable via NSS. It has been a weak + requirement of systemd-hostnamed since a long time, and + since its code is actually trivial we decided to just + include it in systemd's source tree. It can be turned off + with a configure switch. + + * The read-ahead logic is now capable of properly detecting + whether a btrfs file system is on SSD or rotating media, in + order to optimize the read-ahead scheme. Previously, it was + only capable of detecting this on traditional file systems + such as ext4. + + * In udev, additional device properties are now read from the + IAB in addition to the OUI database. Also, Bluetooth company + identities are attached to the devices as well. + + * In service files %U may be used as specifier that is + replaced by the configured user name of the service. + + * nspawn may now be invoked without a controlling TTY. This + makes it suitable for invocation as its own service. This + may be used to set up a simple containerized server system + using only core OS tools. + + * systemd and nspawn can now accept socket file descriptors + when they are started for socket activation. This enables + implementation of socket activated nspawn + containers. i.e. think about autospawning an entire OS image + when the first SSH or HTTP connection is received. We expect + that similar functionality will also be added to libvirt-lxc + eventually. + + * journalctl will now suppress ANSI color codes when + presenting log data. + + * systemctl will no longer show control group information for + a unit if a the control group is empty anyway. + + * logind can now automatically suspend/hibernate/shutdown the + system on idle. + + * /etc/machine-info and hostnamed now also expose the chassis + type of the system. This can be used to determine whether + the local system is a laptop, desktop, handset or + tablet. This information may either be configured by the + user/vendor or is automatically determined from ACPI and DMI + information if possible. + + * A number of PolicyKit actions are now bound together with + "imply" rules. This should simplify creating UIs because + many actions will now authenticate similar ones as well. + + * Unit files learnt a new condition ConditionACPower= which + may be used to conditionalize a unit depending on whether an + AC power source is connected or not, of whether the system + is running on battery power. + + * systemctl gained a new "is-failed" verb that may be used in + shell scripts and suchlike to check whether a specific unit + is in the "failed" state. + + * The EnvironmentFile= setting in unit files now supports file + globbing, and can hence be used to easily read a number of + environment files at once. + + * systemd will no longer detect and recognize specific + distributions. All distribution-specific #ifdeffery has been + removed, systemd is now fully generic and + distribution-agnostic. Effectively, not too much is lost as + a lot of the code is still accessible via explicit configure + switches. However, support for some distribution specific + legacy configuration file formats has been dropped. We + recommend distributions to simply adopt the configuration + files everybody else uses now and convert the old + configuration from packaging scripts. Most distributions + already did that. If that's not possible or desirable, + distributions are welcome to forward port the specific + pieces of code locally from the git history. + + * When logging a message about a unit systemd will now always + log the unit name in the message meta data. + + * localectl will now also discover system locale data that is + not stored in locale archives, but directly unpacked. + + * logind will no longer unconditionally use framebuffer + devices as seat masters, i.e. as devices that are required + to be existing before a seat is considered preset. Instead, + it will now look for all devices that are tagged as + "seat-master" in udev. By default framebuffer devices will + be marked as such, but depending on local systems other + devices might be marked as well. This may be used to + integrate graphics cards using closed source drivers (such + as NVidia ones) more nicely into logind. Note however, that + we recommend using the open source NVidia drivers instead, + and no udev rules for the closed-source drivers will be + shipped from us upstream. + + Contributions from: Adam Williamson, Alessandro Crismani, Auke + Kok, Colin Walters, Daniel Wallace, Dave Reisner, David + Herrmann, David Strauss, Dimitrios Apostolou, Eelco Dolstra, + Eric Benoit, Giovanni Campagna, Hannes Reinecke, Henrik + Grindal Bakken, Hermann Gausterer, Kay Sievers, Lennart + Poettering, Lukas Nykryn, Mantas Mikulėnas, Marcel Holtmann, + Martin Pitt, Matthew Monaco, Michael Biebl, Michael Terry, + Michal Schmidt, Michal Sekletar, Michał Bartoszkiewicz, Oleg + Samarin, Pekka Lundstrom, Philip Nilsson, Ramkumar + Ramachandra, Richard Yao, Robert Millan, Sami Kerola, Shawn + Landden, Thomas Hindoe Paaboel Andersen, Thomas Jarosch, + Tollef Fog Heen, Tom Gundersen, Umut Tezduyar, Zbigniew + Jędrzejewski-Szmek + +CHANGES WITH 196: + + * udev gained support for loading additional device properties + from an indexed database that is keyed by vendor/product IDs + and similar device identifiers. For the beginning this + "hwdb" is populated with data from the well-known PCI and + USB database, but also includes PNP, ACPI and OID data. In + the longer run this indexed database shall grow into + becoming the one central database for non-essential + userspace device metadata. Previously, data from the PCI/USB + database was only attached to select devices, since the + lookup was a relatively expensive operation due to O(n) time + complexity (with n being the number of entries in the + database). Since this is now O(1), we decided to add in this + data for all devices where this is available, by + default. Note that the indexed database needs to be rebuilt + when new data files are installed. To achieve this you need + to update your packaging scripts to invoke "udevadm hwdb + --update" after installation of hwdb data files. For + RPM-based distributions we introduced the new + %udev_hwdb_update macro for this purpose. + + * The Journal gained support for the "Message Catalog", an + indexed database to link up additional information with + journal entries. For further details please check: + + http://www.freedesktop.org/wiki/Software/systemd/catalog + + The indexed message catalog database also needs to be + rebuilt after installation of message catalog files. Use + "journalctl --update-catalog" for this. For RPM-based + distributions we introduced the %journal_catalog_update + macro for this purpose. + + * The Python Journal bindings gained support for the standard + Python logging framework. + + * The Journal API gained new functions for checking whether + the underlying file system of a journal file is capable of + properly reporting file change notifications, or whether + applications that want to reflect journal changes "live" + need to recheck journal files continuously in appropriate + time intervals. + + * It is now possible to set the "age" field for tmpfiles + entries to 0, indicating that files matching this entry + shall always be removed when the directories are cleaned up. + + * coredumpctl gained a new "gdb" verb which invokes gdb + right-away on the selected coredump. + + * There's now support for "hybrid sleep" on kernels that + support this, in addition to "suspend" and "hibernate". Use + "systemctl hybrid-sleep" to make use of this. + + * logind's HandleSuspendKey= setting (and related settings) + now gained support for a new "lock" setting to simply + request the screen lock on all local sessions, instead of + actually executing a suspend or hibernation. + + * systemd will now mount the EFI variables file system by + default. + + * Socket units now gained support for configuration of the + SMACK security label. + + * timedatectl will now output the time of the last and next + daylight saving change. + + * We dropped support for various legacy and distro-specific + concepts, such as insserv, early-boot SysV services + (i.e. those for non-standard runlevels such as 'b' or 'S') + or ArchLinux /etc/rc.conf support. We recommend the + distributions who still need support this to either continue + to maintain the necessary patches downstream, or find a + different solution. (Talk to us if you have questions!) + + * Various systemd components will now bypass PolicyKit checks + for root and otherwise handle properly if PolicyKit is not + found to be around. This should fix most issues for + PolicyKit-less systems. Quite frankly this should have been + this way since day one. It is absolutely our intention to + make systemd work fine on PolicyKit-less systems, and we + consider it a bug if something doesn't work as it should if + PolicyKit is not around. + + * For embedded systems it is now possible to build udev and + systemd without blkid and/or kmod support. + + * "systemctl switch-root" is now capable of switching root + more than once. I.e. in addition to transitions from the + initrd to the host OS it is now possible to transition to + further OS images from the host. This is useful to implement + offline updating tools. + + * Various other additions have been made to the RPM macros + shipped with systemd. Use %udev_rules_update() after + installing new udev rules files. %_udevhwdbdir, + %_udevrulesdir, %_journalcatalogdir, %_tmpfilesdir, + %_sysctldir are now available which resolve to the right + directories for packages to place various data files in. + + * journalctl gained the new --full switch (in addition to + --all, to disable ellipsation for long messages. + + Contributions from: Anders Olofsson, Auke Kok, Ben Boeckel, + Colin Walters, Cosimo Cecchi, Daniel Wallace, Dave Reisner, + Eelco Dolstra, Holger Hans Peter Freyther, Kay Sievers, + Chun-Yi Lee, Lekensteyn, Lennart Poettering, Mantas Mikulėnas, + Marti Raudsepp, Martin Pitt, Mauro Dreissig, Michael Biebl, + Michal Schmidt, Michal Sekletar, Miklos Vajna, Nis Martensen, + Oleksii Shevchuk, Olivier Brunel, Ramkumar Ramachandra, Thomas + Bächler, Thomas Hindoe Paaboel Andersen, Tom Gundersen, Tony + Camuso, Umut Tezduyar, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 195: + + * journalctl gained new --since= and --until= switches to + filter by time. It also now supports nice filtering for + units via --unit=/-u. + + * Type=oneshot services may use ExecReload= and do the + right thing. + + * The journal daemon now supports time-based rotation and + vacuuming, in addition to the usual disk-space based + rotation. + + * The journal will now index the available field values for + each field name. This enables clients to show pretty drop + downs of available match values when filtering. The bash + completion of journalctl has been updated + accordingly. journalctl gained a new switch -F to list all + values a certain field takes in the journal database. + + * More service events are now written as structured messages + to the journal, and made recognizable via message IDs. + + * The timedated, localed and hostnamed mini-services which + previously only provided support for changing time, locale + and hostname settings from graphical DEs such as GNOME now + also have a minimal (but very useful) text-based client + utility each. This is probably the nicest way to changing + these settings from the command line now, especially since + it lists available options and is fully integrated with bash + completion. + + * There's now a new tool "systemd-coredumpctl" to list and + extract coredumps from the journal. + + * We now install a README each in /var/log/ and + /etc/rc.d/init.d explaining where the system logs and init + scripts went. This hopefully should help folks who go to + that dirs and look into the otherwise now empty void and + scratch their heads. + + * When user-services are invoked (by systemd --user) the + $MANAGERPID env var is set to the PID of systemd. + + * SIGRTMIN+24 when sent to a --user instance will now result + in immediate termination of systemd. + + * gatewayd received numerous feature additions such as a + "follow" mode, for live syncing and filtering. + + * browse.html now allows filtering and showing detailed + information on specific entries. Keyboard navigation and + mouse screen support has been added. + + * gatewayd/journalctl now supports HTML5/JSON + Server-Sent-Events as output. + + * The SysV init script compatibility logic will now + heuristically determine whether a script supports the + "reload" verb, and only then make this available as + "systemctl reload". + + * "systemctl status --follow" has been removed, use "journalctl + -u" instead. + + * journald.conf's RuntimeMinSize=, PersistentMinSize= settings + have been removed since they are hardly useful to be + configured. + + * And I'd like to take the opportunity to specifically mention + Zbigniew for his great contributions. Zbigniew, you rock! + + Contributions from: Andrew Eikum, Christian Hesse, Colin + Guthrie, Daniel J Walsh, Dave Reisner, Eelco Dolstra, Ferenc + Wágner, Kay Sievers, Lennart Poettering, Lukas Nykryn, Mantas + Mikulėnas, Martin Mikkelsen, Martin Pitt, Michael Olbrich, + Michael Stapelberg, Michal Schmidt, Sebastian Ott, Thomas + Bächler, Umut Tezduyar, Will Woods, Wulf C. Krueger, Zbigniew + Jędrzejewski-Szmek, Сковорода Никита Андреевич + +CHANGES WITH 194: + + * If /etc/vconsole.conf is non-existent or empty we will no + longer load any console font or key map at boot by + default. Instead the kernel defaults will be left + intact. This is definitely the right thing to do, as no + configuration should mean no configuration, and hard-coding + font names that are different on all archs is probably a bad + idea. Also, the kernel default key map and font should be + good enough for most cases anyway, and mostly identical to + the userspace fonts/key maps we previously overloaded them + with. If distributions want to continue to default to a + non-kernel font or key map they should ship a default + /etc/vconsole.conf with the appropriate contents. + + Contributions from: Colin Walters, Daniel J Walsh, Dave + Reisner, Kay Sievers, Lennart Poettering, Lukas Nykryn, Tollef + Fog Heen, Tom Gundersen, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 193: + + * journalctl gained a new --cursor= switch to show entries + starting from the specified location in the journal. + + * We now enforce a size limit on journal entry fields exported + with "-o json" in journalctl. Fields larger than 4K will be + assigned null. This can be turned off with --all. + + * An (optional) journal gateway daemon is now available as + "systemd-journal-gatewayd.service". This service provides + access to the journal via HTTP and JSON. This functionality + will be used to implement live log synchronization in both + pull and push modes, but has various other users too, such + as easy log access for debugging of embedded devices. Right + now it is already useful to retrieve the journal via HTTP: + + # systemctl start systemd-journal-gatewayd.service + # wget http://localhost:19531/entries + + This will download the journal contents in a + /var/log/messages compatible format. The same as JSON: + + # curl -H"Accept: application/json" http://localhost:19531/entries + + This service is also accessible via a web browser where a + single static HTML5 app is served that uses the JSON logic + to enable the user to do some basic browsing of the + journal. This will be extended later on. Here's an example + screenshot of this app in its current state: + + http://0pointer.de/public/journal-gatewayd + + Contributions from: Kay Sievers, Lennart Poettering, Robert + Milasan, Tom Gundersen + +CHANGES WITH 192: + + * The bash completion logic is now available for journalctl + too. + + * We don't mount the "cpuset" controller anymore together with + "cpu" and "cpuacct", as "cpuset" groups generally cannot be + started if no parameters are assigned to it. "cpuset" hence + broke code that assumed it it could create "cpu" groups and + just start them. + + * journalctl -f will now subscribe to terminal size changes, + and line break accordingly. + + Contributions from: Dave Reisner, Kay Sievers, Lennart + Poettering, Lukas Nykrynm, Mirco Tischler, Václav Pavlín + +CHANGES WITH 191: + + * nspawn will now create a symlink /etc/localtime in the + container environment, copying the host's timezone + setting. Previously this has been done via a bind mount, but + since symlinks cannot be bind mounted this has now been + changed to create/update the appropriate symlink. + + * journalctl -n's line number argument is now optional, and + will default to 10 if omitted. + + * journald will now log the maximum size the journal files may + take up on disk. This is particularly useful if the default + built-in logic of determining this parameter from the file + system size is used. Use "systemctl status + systemd-journald.service" to see this information. + + * The multi-seat X wrapper tool has been stripped down. As X + is now capable of enumerating graphics devices via udev in a + seat-aware way the wrapper is not strictly necessary + anymore. A stripped down temporary stop-gap is still shipped + until the upstream display managers have been updated to + fully support the new X logic. Expect this wrapper to be + removed entirely in one of the next releases. + + * HandleSleepKey= in logind.conf has been split up into + HandleSuspendKey= and HandleHibernateKey=. The old setting + is not available anymore. X11 and the kernel are + distuingishing between these keys and we should too. This + also means the inhibition lock for these keys has been split + into two. + + Contributions from: Dave Airlie, Eelco Dolstra, Lennart + Poettering, Lukas Nykryn, Václav Pavlín + +CHANGES WITH 190: + + * Whenever a unit changes state we'll now log this to the + journal and show along the unit's own log output in + "systemctl status". + + * ConditionPathIsMountPoint= can now properly detect bind + mount points too. (Previously, a bind mount of one file + system to another place in the same file system could not be + detected as mount, since they shared struct stat's st_dev + field.) + + * We will now mount the cgroup controllers cpu, cpuacct, + cpuset and the controllers net_cls, net_prio together by + default. + + * nspawn containers will now have a virtualized boot + ID. (i.e. /proc/sys/kernel/random/boot_id is now mounted + over with a randomized ID at container initialization). This + has the effect of making "journalctl -b" do the right thing + in a container. + + * The JSON output journal serialization has been updated not + to generate "endless" list objects anymore, but rather one + JSON object per line. This is more in line how most JSON + parsers expect JSON objects. The new output mode + "json-pretty" has been added to provide similar output, but + neatly aligned for readability by humans. + + * We dropped all explicit sync() invocations in the shutdown + code. The kernel does this implicitly anyway in the kernel + reboot() syscall. halt(8)'s -n option is now a compatibility + no-op. + + * We now support virtualized reboot() in containers, as + supported by newer kernels. We will fall back to exit() if + CAP_SYS_REBOOT is not available to the container. Also, + nspawn makes use of this now and will actually reboot the + container if the containerized OS asks for that. + + * journalctl will only show local log output by default + now. Use --merge (-m) to show remote log output, too. + + * libsystemd-journal gained the new sd_journal_get_usage() + call to determine the current disk usage of all journal + files. This is exposed in the new "journalctl --disk-usage" + command. + + * journald gained a new configuration setting SplitMode= in + journald.conf which may be used to control how user journals + are split off. See journald.conf(5) for details. + + * A new condition type ConditionFileNotEmpty= has been added. + + * tmpfiles' "w" lines now support file globbing, to write + multiple files at once. + + * We added Python bindings for the journal submission + APIs. More Python APIs for a number of selected APIs will + likely follow. Note that we intend to add native bindings + only for the Python language, as we consider it common + enough to deserve bindings shipped within systemd. There are + various projects outside of systemd that provide bindings + for languages such as PHP or Lua. + + * Many conditions will now resolve specifiers such as %i. In + addition, PathChanged= and related directives of .path units + now support specifiers as well. + + * There's now a new RPM macro definition for the system preset + dir: %_presetdir. + + * journald will now warn if it can't forward a message to the + syslog daemon because it's socket is full. + + * timedated will no longer write or process /etc/timezone, + except on Debian. As we do not support late mounted /usr + anymore /etc/localtime always being a symlink is now safe, + and hence the information in /etc/timezone is not necessary + anymore. + + * logind will now always reserve one VT for a text getty (VT6 + by default). Previously if more than 6 X sessions where + started they took up all the VTs with auto-spawned gettys, + so that no text gettys were available anymore. + + * udev will now automatically inform the btrfs kernel logic + about btrfs RAID components showing up. This should make + simple hotplug based btrfs RAID assembly work. + + * PID 1 will now increase its RLIMIT_NOFILE to 64K by default + (but not for its children which will stay at the kernel + default). This should allow setups with a lot more listening + sockets. + + * systemd will now always pass the configured timezone to the + kernel at boot. timedated will do the same when the timezone + is changed. + + * logind's inhibition logic has been updated. By default, + logind will now handle the lid switch, the power and sleep + keys all the time, even in graphical sessions. If DEs want + to handle these events on their own they should take the new + handle-power-key, handle-sleep-key and handle-lid-switch + inhibitors during their runtime. A simple way to achiveve + that is to invoke the DE wrapped in an invocation of: + + systemd-inhibit --what=handle-power-key:handle-sleep-key:handle-lid-switch ... + + * Access to unit operations is now checked via SELinux taking + the unit file label and client process label into account. + + * systemd will now notify the administrator in the journal + when he over-mounts a non-empty directory. + + * There are new specifiers that are resolved in unit files, + for the host name (%H), the machine ID (%m) and the boot ID + (%b). + + Contributions from: Allin Cottrell, Auke Kok, Brandon Philips, + Colin Guthrie, Colin Walters, Daniel J Walsh, Dave Reisner, + Eelco Dolstra, Jan Engelhardt, Kay Sievers, Lennart + Poettering, Lucas De Marchi, Lukas Nykryn, Mantas Mikulėnas, + Martin Pitt, Matthias Clasen, Michael Olbrich, Pierre Schmitz, + Shawn Landden, Thomas Hindoe Paaboel Andersen, Tom Gundersen, + Václav Pavlín, Yin Kangkai, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 189: + + * Support for reading structured kernel messages from + /dev/kmsg has now been added and is enabled by default. + + * Support for reading kernel messages from /proc/kmsg has now + been removed. If you want kernel messages in the journal + make sure to run a recent kernel (>= 3.5) that supports + reading structured messages from /dev/kmsg (see + above). /proc/kmsg is now exclusive property of classic + syslog daemons again. + + * The libudev API gained the new + udev_device_new_from_device_id() call. + + * The logic for file system namespace (ReadOnlyDirectory=, + ReadWriteDirectoy=, PrivateTmp=) has been reworked not to + require pivot_root() anymore. This means fewer temporary + directories are created below /tmp for this feature. + + * nspawn containers will now see and receive all submounts + made on the host OS below the root file system of the + container. + + * Forward Secure Sealing is now supported for Journal files, + which provide cryptographical sealing of journal files so + that attackers cannot alter log history anymore without this + being detectable. Lennart will soon post a blog story about + this explaining it in more detail. + + * There are two new service settings RestartPreventExitStatus= + and SuccessExitStatus= which allow configuration of exit + status (exit code or signal) which will be excepted from the + restart logic, resp. consider successful. + + * journalctl gained the new --verify switch that can be used + to check the integrity of the structure of journal files and + (if Forward Secure Sealing is enabled) the contents of + journal files. + + * nspawn containers will now be run with /dev/stdin, /dev/fd/ + and similar symlinks pre-created. This makes running shells + as container init process a lot more fun. + + * The fstab support can now handle PARTUUID= and PARTLABEL= + entries. + + * A new ConditionHost= condition has been added to match + against the hostname (with globs) and machine ID. This is + useful for clusters where a single OS image is used to + provision a large number of hosts which shall run slightly + different sets of services. + + * Services which hit the restart limit will now be placed in a + failure state. + + Contributions from: Bertram Poettering, Dave Reisner, Huang + Hang, Kay Sievers, Lennart Poettering, Lukas Nykryn, Martin + Pitt, Simon Peeters, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 188: + + * When running in --user mode systemd will now become a + subreaper (PR_SET_CHILD_SUBREAPER). This should make the ps + tree a lot more organized. + + * A new PartOf= unit dependency type has been introduced that + may be used to group services in a natural way. + + * "systemctl enable" may now be used to enable instances of + services. + + * journalctl now prints error log levels in red, and + warning/notice log levels in bright white. It also supports + filtering by log level now. + + * cgtop gained a new -n switch (similar to top), to configure + the maximum number of iterations to run for. It also gained + -b, to run in batch mode (accepting no input). + + * The suffix ".service" may now be omitted on most systemctl + command lines involving service unit names. + + * There's a new bus call in logind to lock all sessions, as + well as a loginctl verb for it "lock-sessions". + + * libsystemd-logind.so gained a new call sd_journal_perror() + that works similar to libc perror() but logs to the journal + and encodes structured information about the error number. + + * /etc/crypttab entries now understand the new keyfile-size= + option. + + * shutdown(8) now can send a (configurable) wall message when + a shutdown is cancelled. + + * The mount propagation mode for the root file system will now + default to "shared", which is useful to make containers work + nicely out-of-the-box so that they receive new mounts from + the host. This can be undone locally by running "mount + --make-rprivate /" if needed. + + * The prefdm.service file has been removed. Distributions + should maintain this unit downstream if they intend to keep + it around. However, we recommend writing normal unit files + for display managers instead. + + * Since systemd is a crucial part of the OS we will now + default to a number of compiler switches that improve + security (hardening) such as read-only relocations, stack + protection, and suchlike. + + * The TimeoutSec= setting for services is now split into + TimeoutStartSec= and TimeoutStopSec= to allow configuration + of individual time outs for the start and the stop phase of + the service. + + Contributions from: Artur Zaprzala, Arvydas Sidorenko, Auke + Kok, Bryan Kadzban, Dave Reisner, David Strauss, Harald Hoyer, + Jim Meyering, Kay Sievers, Lennart Poettering, Mantas + Mikulėnas, Martin Pitt, Michal Schmidt, Michal Sekletar, Peter + Alfredsen, Shawn Landden, Simon Peeters, Terence Honles, Tom + Gundersen, Zbigniew Jędrzejewski-Szmek + +CHANGES WITH 187: + + * The journal and id128 C APIs are now fully documented as man + pages. + + * Extra safety checks have been added when transitioning from + the initial RAM disk to the main system to avoid accidental + data loss. + + * /etc/crypttab entries now understand the new keyfile-offset= + option. + + * systemctl -t can now be used to filter by unit load state. + + * The journal C API gained the new sd_journal_wait() call to + make writing synchronous journal clients easier. + + * journalctl gained the new -D switch to show journals from a + specific directory. + + * journalctl now displays a special marker between log + messages of two different boots. + + * The journal is now explicitly flushed to /var via a service + systemd-journal-flush.service, rather than implicitly simply + by seeing /var/log/journal to be writable. + + * journalctl (and the journal C APIs) can now match for much + more complex expressions, with alternatives and + disjunctions. + + * When transitioning from the initial RAM disk to the main + system we will now kill all processes in a killing spree to + ensure no processes stay around by accident. + + * Three new specifiers may be used in unit files: %u, %h, %s + resolve to the user name, user home directory resp. user + shell. This is useful for running systemd user instances. + + * We now automatically rotate journal files if their data + object hash table gets a fill level > 75%. We also size the + hash table based on the configured maximum file size. This + together should lower hash collisions drastically and thus + speed things up a bit. + + * journalctl gained the new "--header" switch to introspect + header data of journal files. + + * A new setting SystemCallFilters= has been added to services + which may be used to apply blacklists or whitelists to + system calls. This is based on SECCOMP Mode 2 of Linux 3.5. + + * nspawn gained a new --link-journal= switch (and quicker: -j) + to link the container journal with the host. This makes it + very easy to centralize log viewing on the host for all + guests while still keeping the journal files separated. + + * Many bugfixes and optimizations + + Contributions from: Auke Kok, Eelco Dolstra, Harald Hoyer, Kay + Sievers, Lennart Poettering, Malte Starostik, Paul Menzel, Rex + Tsai, Shawn Landden, Tom Gundersen, Ville Skyttä, Zbigniew + Jędrzejewski-Szmek + +CHANGES WITH 186: + + * Several tools now understand kernel command line arguments, + which are only read when run in an initial RAM disk. They + usually follow closely their normal counterparts, but are + prefixed with rd. + + * There's a new tool to analyze the readahead files that are + automatically generated at boot. Use: + + /usr/lib/systemd/systemd-readahead analyze /.readahead + + * We now provide an early debug shell on tty9 if this enabled. Use: + + systemctl enable debug-shell.service + + * All plymouth related units have been moved into the Plymouth + package. Please make sure to upgrade your Plymouth version + as well. + + * systemd-tmpfiles now supports getting passed the basename of + a configuration file only, in which case it will look for it + in all appropriate directories automatically. + + * udevadm info now takes a /dev or /sys path as argument, and + does the right thing. Example: + + udevadm info /dev/sda + udevadm info /sys/class/block/sda + + * systemctl now prints a warning if a unit is stopped but a + unit that might trigger it continues to run. Example: a + service is stopped but the socket that activates it is left + running. + + * "systemctl status" will now mention if the log output was + shortened due to rotation since a service has been started. + + * The journal API now exposes functions to determine the + "cutoff" times due to rotation. + + * journald now understands SIGUSR1 and SIGUSR2 for triggering + immediately flushing of runtime logs to /var if possible, + resp. for triggering immediate rotation of the journal + files. + + * It is now considered an error if a service is attempted to + be stopped that is not loaded. + + * XDG_RUNTIME_DIR now uses numeric UIDs instead of usernames. + + * systemd-analyze now supports Python 3 + + * tmpfiles now supports cleaning up directories via aging + where the first level dirs are always kept around but + directories beneath it automatically aged. This is enabled + by prefixing the age field with '~'. + + * Seat objects now expose CanGraphical, CanTTY properties + which is required to deal with very fast bootups where the + display manager might be running before the graphics drivers + completed initialization. + + * Seat objects now expose a State property. + + * We now include RPM macros for service enabling/disabling + based on the preset logic. We recommend RPM based + distributions to make use of these macros if possible. This + makes it simpler to reuse RPM spec files across + distributions. + + * We now make sure that the collected systemd unit name is + always valid when services log to the journal via + STDOUT/STDERR. + + * There's a new man page kernel-command-line(7) detailing all + command line options we understand. + + * The fstab generator may now be disabled at boot by passing + fstab=0 on the kernel command line. + + * A new kernel command line option modules-load= is now understood + to load a specific kernel module statically, early at boot. + + * Unit names specified on the systemctl command line are now + automatically escaped as needed. Also, if file system or + device paths are specified they are automatically turned + into the appropriate mount or device unit names. Example: + + systemctl status /home + systemctl status /dev/sda + + * The SysVConsole= configuration option has been removed from + system.conf parsing. + + * The SysV search path is no longer exported on the D-Bus + Manager object. + + * The Names= option is been removed from unit file parsing. + + * There's a new man page bootup(7) detailing the boot process. + + * Every unit and every generator we ship with systemd now + comes with full documentation. The self-explanatory boot is + complete. + + * A couple of services gained "systemd-" prefixes in their + name if they wrap systemd code, rather than only external + code. Among them fsck@.service which is now + systemd-fsck@.service. + + * The HaveWatchdog property has been removed from the D-Bus + Manager object. + + * systemd.confirm_spawn= on the kernel command line should now + work sensibly. + + * There's a new man page crypttab(5) which details all options + we actually understand. + + * systemd-nspawn gained a new --capability= switch to pass + additional capabilities to the container. + + * timedated will now read known NTP implementation unit names + from /usr/lib/systemd/ntp-units.d/*.list, + systemd-timedated-ntp.target has been removed. + + * journalctl gained a new switch "-b" that lists log data of + the current boot only. + + * The notify socket is in the abstract namespace again, in + order to support daemons which chroot() at start-up. + + * There is a new Storage= configuration option for journald + which allows configuration of where log data should go. This + also provides a way to disable journal logging entirely, so + that data collected is only forwarded to the console, the + kernel log buffer or another syslog implementation. + + * Many bugfixes and optimizations + + Contributions from: Auke Kok, Colin Guthrie, Dave Reisner, + David Strauss, Eelco Dolstra, Kay Sievers, Lennart Poettering, + Lukas Nykryn, Michal Schmidt, Michal Sekletar, Paul Menzel, + Shawn Landden, Tom Gundersen + +CHANGES WITH 185: + + * "systemctl help " now shows the man page if one is + available. + + * Several new man pages have been added. + + * MaxLevelStore=, MaxLevelSyslog=, MaxLevelKMsg=, + MaxLevelConsole= can now be specified in + journald.conf. These options allow reducing the amount of + data stored on disk or forwarded by the log level. + + * TimerSlackNSec= can now be specified in system.conf for + PID1. This allows system-wide power savings. + + Contributions from: Dave Reisner, Kay Sievers, Lauri Kasanen, + Lennart Poettering, Malte Starostik, Marc-Antoine Perennou, + Matthias Clasen + +CHANGES WITH 184: + + * logind is now capable of (optionally) handling power and + sleep keys as well as the lid switch. + + * journalctl now understands the syntax "journalctl + /usr/bin/avahi-daemon" to get all log output of a specific + daemon. + + * CapabilityBoundingSet= in system.conf now also influences + the capability bound set of usermode helpers of the kernel. + + Contributions from: Daniel Drake, Daniel J. Walsh, Gert + Michael Kulyk, Harald Hoyer, Jean Delvare, Kay Sievers, + Lennart Poettering, Matthew Garrett, Matthias Clasen, Paul + Menzel, Shawn Landden, Tero Roponen, Tom Gundersen + +CHANGES WITH 183: + + * Note that we skipped 139 releases here in order to set the + new version to something that is greater than both udev's + and systemd's most recent version number. + + * udev: all udev sources are merged into the systemd source tree now. + All future udev development will happen in the systemd tree. It + is still fully supported to use the udev daemon and tools without + systemd running, like in initramfs or other init systems. Building + udev though, will require the *build* of the systemd tree, but + udev can be properly *run* without systemd. + + * udev: /lib/udev/devices/ are not read anymore; systemd-tmpfiles + should be used to create dead device nodes as workarounds for broken + subsystems. + + * udev: RUN+="socket:..." and udev_monitor_new_from_socket() is + no longer supported. udev_monitor_new_from_netlink() needs to be + used to subscribe to events. + + * udev: when udevd is started by systemd, processes which are left + behind by forking them off of udev rules, are unconditionally cleaned + up and killed now after the event handling has finished. Services or + daemons must be started as systemd services. Services can be + pulled-in by udev to get started, but they can no longer be directly + forked by udev rules. + + * udev: the daemon binary is called systemd-udevd now and installed + in /usr/lib/systemd/. Standalone builds or non-systemd systems need + to adapt to that, create symlink, or rename the binary after building + it. + + * libudev no longer provides these symbols: + udev_monitor_from_socket() + udev_queue_get_failed_list_entry() + udev_get_{dev,sys,run}_path() + The versions number was bumped and symbol versioning introduced. + + * systemd-loginctl and systemd-journalctl have been renamed + to loginctl and journalctl to match systemctl. + + * The config files: /etc/systemd/systemd-logind.conf and + /etc/systemd/systemd-journald.conf have been renamed to + logind.conf and journald.conf. Package updates should rename + the files to the new names on upgrade. + + * For almost all files the license is now LGPL2.1+, changed + from the previous GPL2.0+. Exceptions are some minor stuff + of udev (which will be changed to LGPL2.1 eventually, too), + and the MIT licensed sd-daemon.[ch] library that is suitable + to be used as drop-in files. + + * systemd and logind now handle system sleep states, in + particular suspending and hibernating. + + * logind now implements a sleep/shutdown/idle inhibiting logic + suitable for a variety of uses. Soonishly Lennart will blog + about this in more detail. + + * var-run.mount and var-lock.mount are no longer provided + (which prevously bind mounted these directories to their new + places). Distributions which have not converted these + directories to symlinks should consider stealing these files + from git history and add them downstream. + + * We introduced the Documentation= field for units and added + this to all our shipped units. This is useful to make it + easier to explore the boot and the purpose of the various + units. + + * All smaller setup units (such as + systemd-vconsole-setup.service) now detect properly if they + are run in a container and are skipped when + appropriate. This guarantees an entirely noise-free boot in + Linux container environments such as systemd-nspawn. + + * A framework for implementing offline system updates is now + integrated, for details see: + http://freedesktop.org/wiki/Software/systemd/SystemUpdates + + * A new service type Type=idle is available now which helps us + avoiding ugly interleaving of getty output and boot status + messages. + + * There's now a system-wide CapabilityBoundingSet= option to + globally reduce the set of capabilities for the + system. This is useful to drop CAP_SYS_MKNOD, CAP_SYS_RAWIO, + CAP_NET_RAW, CAP_SYS_MODULE, CAP_SYS_TIME, CAP_SYS_PTRACE or + even CAP_NET_ADMIN system-wide for secure systems. + + * There are now system-wide DefaultLimitXXX= options to + globally change the defaults of the various resource limits + for all units started by PID 1. + + * Harald Hoyer's systemd test suite has been integrated into + systemd which allows easy testing of systemd builds in qemu + and nspawn. (This is really awesome! Ask us for details!) + + * The fstab parser is now implemented as generator, not inside + of PID 1 anymore. + + * systemctl will now warn you if .mount units generated from + /etc/fstab are out of date due to changes in fstab that + haven't been read by systemd yet. + + * systemd is now suitable for usage in initrds. Dracut has + already been updated to make use of this. With this in place + initrds get a slight bit faster but primarily are much + easier to introspect and debug since "systemctl status" in + the host system can be used to introspect initrd services, + and the journal from the initrd is kept around too. + + * systemd-delta has been added, a tool to explore differences + between user/admin configuration and vendor defaults. + + * PrivateTmp= now affects both /tmp and /var/tmp. + + * Boot time status messages are now much prettier and feature + proper english language. Booting up systemd has never been + so sexy. + + * Read-ahead pack files now include the inode number of all + files to pre-cache. When the inode changes the pre-caching + is not attempted. This should be nicer to deal with updated + packages which might result in changes of read-ahead + patterns. + + * We now temporaritly lower the kernel's read_ahead_kb variable + when collecting read-ahead data to ensure the kernel's + built-in read-ahead does not add noise to our measurements + of necessary blocks to pre-cache. + + * There's now RequiresMountsFor= to add automatic dependencies + for all mounts necessary for a specific file system path. + + * MountAuto= and SwapAuto= have been removed from + system.conf. Mounting file systems at boot has to take place + in systemd now. + + * nspawn now learned a new switch --uuid= to set the machine + ID on the command line. + + * nspawn now learned the -b switch to automatically search + for an init system. + + * vt102 is now the default TERM for serial TTYs, upgraded from + vt100. + + * systemd-logind now works on VT-less systems. + + * The build tree has been reorganized. The individual + components now have directories of their own. + + * A new condition type ConditionPathIsReadWrite= is now available. + + * nspawn learned the new -C switch to create cgroups for the + container in other hierarchies. + + * We now have support for hardware watchdogs, configurable in + system.conf. + + * The scheduled shutdown logic now has a public API. + + * We now mount /tmp as tmpfs by default, but this can be + masked and /etc/fstab can override it. + + * Since udisks doesn't make use of /media anymore we are not + mounting a tmpfs on it anymore. + + * journalctl gained a new --local switch to only interleave + locally generated journal files. + + * We can now load the IMA policy at boot automatically. + + * The GTK tools have been split off into a systemd-ui. + + Contributions from: Andreas Schwab, Auke Kok, Ayan George, + Colin Guthrie, Daniel Mack, Dave Reisner, David Ward, Elan + Ruusamäe, Frederic Crozat, Gergely Nagy, Guillermo Vidal, + Hannes Reinecke, Harald Hoyer, Javier Jardón, Kay Sievers, + Lennart Poettering, Lucas De Marchi, Léo Gillot-Lamure, + Marc-Antoine Perennou, Martin Pitt, Matthew Monaco, Maxim + A. Mikityanskiy, Michael Biebl, Michael Olbrich, Michal + Schmidt, Nis Martensen, Patrick McCarty, Roberto Sassu, Shawn + Landden, Sjoerd Simons, Sven Anders, Tollef Fog Heen, Tom + Gundersen + +CHANGES WITH 44: + + * This is mostly a bugfix release + + * Support optional initialization of the machine ID from the + KVM or container configured UUID. + + * Support immediate reboots with "systemctl reboot -ff" + + * Show /etc/os-release data in systemd-analyze output + + * Many bugfixes for the journal, including endianness fixes and + ensuring that disk space enforcement works + + * sd-login.h is C++ comptaible again + + * Extend the /etc/os-release format on request of the Debian + folks + + * We now refuse non-UTF8 strings used in various configuration + and unit files. This is done to ensure we don't pass invalid + data over D-Bus or expose it elsewhere. + + * Register Mimo USB Screens as suitable for automatic seat + configuration + + * Read SELinux client context from journal clients in a race + free fashion + + * Reorder configuration file lookup order. /etc now always + overrides /run in order to allow the administrator to always + and unconditionally override vendor supplied or + automatically generated data. + + * The various user visible bits of the journal now have man + pages. We still lack man pages for the journal API calls + however. + + * We now ship all man pages in HTML format again in the + tarball. + + Contributions from: Dave Reisner, Dirk Eibach, Frederic + Crozat, Harald Hoyer, Kay Sievers, Lennart Poettering, Marti + Raudsepp, Michal Schmidt, Shawn Landden, Tero Roponen, Thierry + Reding + +CHANGES WITH 43: + + * This is mostly a bugfix release + + * systems lacking /etc/os-release are no longer supported. + + * Various functionality updates to libsystemd-login.so + + * Track class of PAM logins to distuingish greeters from + normal user logins. + + Contributions from: Kay Sievers, Lennart Poettering, Michael + Biebl + +CHANGES WITH 42: + + * This is an important bugfix release for v41. + + * Building man pages is now optional which should be useful + for those building systemd from git but unwilling to install + xsltproc. + + * Watchdog support for supervising services is now usable. In + a future release support for hardware watchdogs + (i.e. /dev/watchdog) will be added building on this. + + * Service start rate limiting is now configurable and can be + turned off per service. When a start rate limit is hit a + reboot can automatically be triggered. + + * New CanReboot(), CanPowerOff() bus calls in systemd-logind. + + Contributions from: Benjamin Franzke, Bill Nottingham, + Frederic Crozat, Lennart Poettering, Michael Olbrich, Michal + Schmidt, Michał Górny, Piotr Drąg + +CHANGES WITH 41: + + * The systemd binary is installed /usr/lib/systemd/systemd now; + An existing /sbin/init symlink needs to be adapted with the + package update. + + * The code that loads kernel modules has been ported to invoke + libkmod directly, instead of modprobe. This means we do not + support systems with module-init-tools anymore. + + * Watchdog support is now already useful, but still not + complete. + + * A new kernel command line option systemd.setenv= is + understood to set system wide environment variables + dynamically at boot. + + * We now limit the set of capabilities of systemd-journald. + + * We now set SIGPIPE to ignore by default, since it only is + useful in shell pipelines, and has little use in general + code. This can be disabled with IgnoreSIPIPE=no in unit + files. + + Contributions from: Benjamin Franzke, Kay Sievers, Lennart + Poettering, Michael Olbrich, Michal Schmidt, Tom Gundersen, + William Douglas + +CHANGES WITH 40: + + * This is mostly a bugfix release + + * We now expose the reason why a service failed in the + "Result" D-Bus property. + + * Rudimentary service watchdog support (will be completed over + the next few releases.) + + * When systemd forks off in order execute some service we will + now immediately changes its argv[0] to reflect which process + it will execute. This is useful to minimize the time window + with a generic argv[0], which makes bootcharts more useful + + Contributions from: Alvaro Soliverez, Chris Paulson-Ellis, Kay + Sievers, Lennart Poettering, Michael Olbrich, Michal Schmidt, + Mike Kazantsev, Ray Strode + +CHANGES WITH 39: + + * This is mostly a test release, but incorporates many + bugfixes. + + * New systemd-cgtop tool to show control groups by their + resource usage. + + * Linking against libacl for ACLs is optional again. If + disabled, support tracking device access for active logins + goes becomes unavailable, and so does access to the user + journals by the respective users. + + * If a group "adm" exists, journal files are automatically + owned by them, thus allow members of this group full access + to the system journal as well as all user journals. + + * The journal now stores the SELinux context of the logging + client for all entries. + + * Add C++ inclusion guards to all public headers + + * New output mode "cat" in the journal to print only text + messages, without any meta data like date or time. + + * Include tiny X server wrapper as a temporary stop-gap to + teach XOrg udev display enumeration. This is used by display + managers such as gdm, and will go away as soon as XOrg + learned native udev hotplugging for display devices. + + * Add new systemd-cat tool for executing arbitrary programs + with STDERR/STDOUT connected to the journal. Can also act as + BSD logger replacement, and does so by default. + + * Optionally store all locally generated coredumps in the + journal along with meta data. + + * systemd-tmpfiles learnt four new commands: n, L, c, b, for + writing short strings to files (for usage for /sys), and for + creating symlinks, character and block device nodes. + + * New unit file option ControlGroupPersistent= to make cgroups + persistent, following the mechanisms outlined in + http://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups + + * Support multiple local RTCs in a sane way + + * No longer monopolize IO when replaying readahead data on + rotating disks, since we might starve non-file-system IO to + death, since fanotify() will not see accesses done by blkid, + or fsck. + + * Don't show kernel threads in systemd-cgls anymore, unless + requested with new -k switch. + + Contributions from: Dan Horák, Kay Sievers, Lennart + Poettering, Michal Schmidt + +CHANGES WITH 38: + + * This is mostly a test release, but incorporates many + bugfixes. + + * The git repository moved to: + git://anongit.freedesktop.org/systemd/systemd + ssh://git.freedesktop.org/git/systemd/systemd + + * First release with the journal + http://0pointer.de/blog/projects/the-journal.html + + * The journal replaces both systemd-kmsg-syslogd and + systemd-stdout-bridge. + + * New sd_pid_get_unit() API call in libsystemd-logind + + * Many systemadm clean-ups + + * Introduce remote-fs-pre.target which is ordered before all + remote mounts and may be used to start services before all + remote mounts. + + * Added Mageia support + + * Add bash completion for systemd-loginctl + + * Actively monitor PID file creation for daemons which exit in + the parent process before having finished writing the PID + file in the daemon process. Daemons which do this need to be + fixed (i.e. PID file creation must have finished before the + parent exits), but we now react a bit more gracefully to them. + + * Add colourful boot output, mimicking the well-known output + of existing distributions. + + * New option PassCredentials= for socket units, for + compatibility with a recent kernel ABI breakage. + + * /etc/rc.local is now hooked in via a generator binary, and + thus will no longer act as synchronization point during + boot. + + * systemctl list-unit-files now supports --root=. + + * systemd-tmpfiles now understands two new commands: z, Z for + relabelling files according to the SELinux database. This is + useful to apply SELinux labels to specific files in /sys, + among other things. + + * Output of SysV services is now forwarded to both the console + and the journal by default, not only just the console. + + * New man pages for all APIs from libsystemd-login. + + * The build tree got reorganized and a the build system is a + lot more modular allowing embedded setups to specifically + select the components of systemd they are interested in. + + * Support for Linux systems lacking the kernel VT subsystem is + restored. + + * configure's --with-rootdir= got renamed to + --with-rootprefix= to follow the naming used by udev and + kmod + + * Unless specified otherwise we'll now install to /usr instead + of /usr/local by default. + + * Processes with '@' in argv[0][0] are now excluded from the + final shut-down killing spree, following the logic explained + in: + http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + + * All processes remaining in a service cgroup when we enter + the START or START_PRE states are now killed with + SIGKILL. That means it is no longer possible to spawn + background processes from ExecStart= lines (which was never + supported anyway, and bad style). + + * New PropagateReloadTo=/PropagateReloadFrom= options to bind + reloading of units together. + + Contributions from: Bill Nottingham, Daniel J. Walsh, Dave + Reisner, Dexter Morgan, Gregs Gregs, Jonathan Nieder, Kay + Sievers, Lennart Poettering, Michael Biebl, Michal Schmidt, + Michał Górny, Ran Benita, Thomas Jarosch, Tim Waugh, Tollef + Fog Heen, Tom Gundersen, Zbigniew Jędrzejewski-Szmek diff --git a/README b/README index 15afb2c..b918132 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -systemd System and Session Manager +systemd System and Service Manager DETAILS: http://0pointer.de/blog/projects/systemd.html @@ -7,11 +7,11 @@ WEB SITE: http://www.freedesktop.org/wiki/Software/systemd GIT: - git://anongit.freedesktop.org/systemd - ssh://git.freedesktop.org/git/systemd + git://anongit.freedesktop.org/systemd/systemd + ssh://git.freedesktop.org/git/systemd/systemd GITWEB: - http://cgit.freedesktop.org/systemd/ + http://cgit.freedesktop.org/systemd/systemd MAILING LIST: http://lists.freedesktop.org/mailman/listinfo/systemd-devel @@ -24,54 +24,155 @@ BUG REPORTS: https://bugs.freedesktop.org/enter_bug.cgi?product=systemd AUTHOR: - Lennart Poettering with major support from Kay Sievers + Lennart Poettering + Kay Sievers + ...and many others LICENSE: - GPLv2+ for all code, except sd-daemon.[ch] which is MIT + LGPLv2.1+ for all code + - except sd-readahead.[ch] which is MIT + - except src/shared/MurmurHash2.c which is Public Domain + - except src/shared/siphash24.c which is CC0 Public Domain + - except src/journal/lookup3.c which is Public Domain + - except src/udev/* which is (currently still) GPLv2, GPLv2+ REQUIREMENTS: - Linux kernel >= 2.6.39 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6) - libudev >= 172 - dbus >= 1.4.0 + Linux kernel >= 3.0 + CONFIG_DEVTMPFS + CONFIG_CGROUPS (it's OK to disable all controllers) + CONFIG_INOTIFY_USER + CONFIG_SIGNALFD + CONFIG_TIMERFD + CONFIG_EPOLL + CONFIG_NET + CONFIG_SYSFS + CONFIG_PROC_FS + CONFIG_FHANDLE (libudev, mount and bind mount handling) + + Linux kernel >= 3.8 for Smack support + + Udev will fail to work with the legacy layout: + CONFIG_SYSFS_DEPRECATED=n + + Legacy hotplug slows down the system and confuses udev: + CONFIG_UEVENT_HELPER_PATH="" + + Userspace firmware loading is deprecated, will go away, and + sometimes causes problems: + CONFIG_FW_LOADER_USER_HELPER=n + + Some udev rules and virtualization detection relies on it: + CONFIG_DMIID + + Support for some SCSI devices serial number retrieval, to + create additional symlinks in /dev/disk/ and /dev/tape: + CONFIG_BLK_DEV_BSG + + Optional but strongly recommended: + CONFIG_IPV6 + CONFIG_AUTOFS4_FS + CONFIG_TMPFS_POSIX_ACL + CONFIG_TMPFS_XATTR + CONFIG_SECCOMP + + For systemd-bootchart, several proc debug interfaces are required: + CONFIG_SCHEDSTATS + CONFIG_SCHED_DEBUG + + For UEFI systems: + CONFIG_EFI_VARS + CONFIG_EFI_PARTITION + + Note that kernel auditing is broken when used with systemd's + container code. When using systemd in conjunction with + containers, please make sure to either turn off auditing at + runtime using the kernel command line option "audit=0", or + turn it off at kernel compile time using: + CONFIG_AUDIT=n + + glibc >= 2.14 libcap - gtk+ >= 2.20 (optional) + libseccomp >= 1.0.0 (optional) + libblkid >= 2.20 (from util-linux) (optional) + libkmod >= 15 (optional) PAM >= 1.1.2 (optional) libcryptsetup (optional) libaudit (optional) + libacl (optional) + libattr (optional) libselinux (optional) + liblzma (optional) tcpwrappers (optional) - libnotify (optional) + libgcrypt (optional) + libqrencode (optional) + libmicrohttpd (optional) + libpython (optional) + make, gcc, and similar tools + + To sucessfully use --compat-libs, gcc >= 4.8 seems necessary. - When you build from git you need the following additional dependencies: + During runtime, you need the following additional + dependencies: + + util-linux >= v2.19 (requires fsck -l, agetty -s), + v2.21 required for tests in test/ + dbus >= 1.4.0 (strictly speaking optional, but recommended) + sulogin (from util-linux >= 2.22 or sysvinit-tools, optional but recommended, + required for tests in test/) + dracut (optional) + PolicyKit (optional) + + When building from git, you need the following additional + dependencies: - vala >= 0.10 docbook-xsl xsltproc automake autoconf libtool + intltool gperf - make, gcc, and similar tools + gtkdocize (optional) + python (optional) + python-lxml (optional, but required to build the indices) + sphinx (optional) + + When systemd-hostnamed is used, it is strongly recommended to + install nss-myhostname to ensure that, in a world of + dynamically changing hostnames, the hostname stays resolvable + under all circumstances. In fact, systemd-hostnamed will warn + if nss-myhostname is not installed. - During runtime you need the following dependencies: + To build HTML documentation for python-systemd using sphinx, + please first install systemd (using 'make install'), and then + invoke sphinx-build with 'make sphinx-', with + being 'html' or 'latexpdf'. If using DESTDIR for installation, + pass the same DESTDIR to 'make sphinx-html' invocation. - util-linux > v2.18 (requires fsck -l, agetty -s) - sulogin (from sysvinit-tools, optional but recommended) - plymouth (optional) - dracut (optional) +USERS AND GROUPS: + Default udev rules use the following standard system group + names, which need to be resolvable by getgrnam() at any time, + even in the very early boot stages, where no other databases + and network are available: - When systemd-hostnamed is used it is strongly recommended to - install nss-myhostname to ensure that in a world of - dynamically changing hostnames the hostname stays resolveable - under all circumstances. In fact, systemd-hostnamed will warn - if nss-myhostname is not installed. Packagers are encouraged to - add a dependency on nss-myhostname to the package that - includes systemd-hostnamed. + tty, dialout, kmem, video, audio, lp, floppy, cdrom, tape, disk + + During runtime, the journal daemon requires the + "systemd-journal" system group to exist. New journal files will + be readable by this group (but not writable), which may be used + to grant specific users read access. - Note that D-Bus can link against libsystemd-login.so, which - results in a cyclic build dependency. To accomodate for this - please build D-Bus without systemd first, then build systemd, - then rebuild D-Bus with systemd support. + It is also recommended to grant read access to all journal + files to the system groups "wheel" and "adm" with a command + like the following in the post installation script of the + package: + + # setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal/ + + The journal gateway daemon requires the + "systemd-journal-gateway" system user and group to + exist. During execution this network facing service will drop + privileges and assume this uid/gid for security reasons. WARNINGS: systemd will warn you during boot if /etc/mtab is not a @@ -80,24 +181,19 @@ WARNINGS: systemd will warn you during boot if /usr is on a different file system than /. While in systemd itself very little will - break if /usr is on a separate partition many of its + break if /usr is on a separate partition, many of its dependencies very likely will break sooner or later in one - form or another. For example udev rules tend to refer to + form or another. For example, udev rules tend to refer to binaries in /usr, binaries that link to libraries in /usr or binaries that refer to data files in /usr. Since these - breakages are not always directly visible systemd will warn + breakages are not always directly visible, systemd will warn about this, since this kind of file system setup is not really supported anymore by the basic set of Linux OS components. For more information on this issue consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken -ENGINEERING AND CONSULTING SERVICES: - ProFUSION offers professional - engineering and consulting services for systemd for embedded - and other use. Please contact Gustavo Barbieri - for more information. - - Disclaimer: This notice is not a recommendation or official - endorsement. However, ProFUSION's upstream work has been very - beneficial for the systemd project. + To run systemd under valgrind, compile with VALGRIND defined + (e.g. ./configure CPPFLAGS='... -DVALGRIND=1'). Otherwise, + false positives will be triggered by code which violates + some rules but is actually safe. diff --git a/TODO b/TODO index 9149018..b7dff10 100644 --- a/TODO +++ b/TODO @@ -1,86 +1,594 @@ Bugfixes: +* enabling an instance unit creates a pointless link, and + the unit will be started with getty@getty.service: + $ systemctl enable getty@.service + ln -s '/usr/lib/systemd/system/getty@.service' '/etc/systemd/system/getty.target.wants/getty@.service' -* swap units that are activated by one name but shown in the kernel under another are semi-broken +* Dangling symlinks of .automount unit files in .wants/ directories, set up + automount points even when the original .automount file did not exist + anymore. Only the .mount unit was still around. -* NM should pull in network.target (PENDING) - https://bugzilla.redhat.com/show_bug.cgi?id=692008 +* properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point. -* make anaconda write timeout=0 for encrypted devices +* shorten the message to sane length: -* service: pid file reading after reload doesn't work, since we don't reset the pid variable + Cannot add dependency job for unit display-manager.service, ignoring: Unit display-manager.service failed to load: No such file or directory. See system logs and 'systemctl status display-manager.service' for details. -* make sure timeouts are applied to Type=oneshot services. +* systemctl --root=container/ set-default ... is totally borked. -* Dangling symlinks of .automount unit files in .wants/ directories, set up - automount points even when the original .automount file did not exist - anymore. Only the .mount unit was still around. +External: + +* Fedora: when installing fedora with yum --installroot /var/run is a directory, not a symlink + https://bugzilla.redhat.com/show_bug.cgi?id=975864 + +* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros. -* make polkit checks async +* Fedora: post FPC ticket to move add %tmpfiles_create to the packaging guidelines Features: -* unset container= in PID1? +* logind: watch drm connectors and if we see a number of connectors != + 1 avoid processing the lid switch. + +* logind: avoid processing the lid switch for 3min (or so) after + startup and 1min (or so) after coming back from suspend, in order to + give USB docking stations time to pop up a video device, which could + act as lid-switch blocker. -* if we can not get user quota for tmpfs, mount a separate tmpfs instance - for every user in /run/user/$USER with a configured maximum size +* machined: provide calls GetMachineByAddress() on the manager + interface to get the machine for a local IP address, and + GetAddress() on the Machine interface to get the Address for a + machine. Implement via forking off child process which quickly joins + the cotnainer and passes data to parent. Show this in "machinectl + status", and use it to implement NSS module to provide automatic + name resolution for containers. -* default to actual 32bit PIDs, via /proc/sys/kernel/pid_max +* add generator that pulls in systemd-network from containers when + CAP_NET_ADMIN is set, more than the loopback device is defined, even + when it is otherwise off -* add an option to make mounts private/shareable and so on, enable this for root by default +* MessageQueueMessageSize= and RLimitFSIZE= (and suchlike) should use parse_iec_size(). -* internal restart counter for units (focus on auto-respawn) +* man: move .link, .network and .netdev documentation into their own + man pages maybe called "systemd.link(5)", "systemd.network(5)" and + "systemd.netdev(5)" or so. -* finer-grained auto-respawn settings (rate-limit) +* "busctl status" works only as root on dbus1, since we cannot read + /proc/$PID/exe -* be able to specify a forced restart of service A where service B depends on, in case B - needs to be auto-respawned? +* systemctl (and possibly related tools): support a new switch that + allows enumerating units in local containers recursively. "systemctl + list-units -R" or so should not only lists on the host, but also the + services in all containers in a pretty way, to give an overview of + the entire system. Also, maybe add "systemctl list-machines" which + works like "machinectl list" but includes information about the + health status of each registered machine. For that we should + probably implement something that encodes the system health status + in a single enum state, i.e. something like a system-wide state + starting → running → failed → stopping, that is based on the current + job queue and a check for failed services. Maybe then change + "systemctl status" without args to output this state along with a + selection of other data, such as the uptime or so. -* Something is wrong with symlink handling of "autovt@.service" in "systemctl list-unit-files" +* Add a seccomp-based filter for socket() calls to limit services to + specific address families (for example: AF_UNIX), inspired by + Android's sandboxing -* introduce sd_log_open() to create a connection to the syslog bridge via sd-daemon.h +* implement Distribute= in socket units to allow running multiple + service instances processing the listening socket, and open this up + for ReusePort= -* when a bus name of a service disappears from the bus make sure to queue further activation requests +* add a timelimit to generator invocation + +* 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. + +* New service property: maximum CPU and wallclock runtime for a service + +* 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 + it are fully stopped. This can later be used for app management by + desktop UIs such as gnome-shell to freeze apps that are not visible + on screen, not unlike how job control works on the shell + +* completions: + - busctl zsh completion is outdated + - systemd-nspawn -Z/-L/-q is missing for zsh + - systemd-nspawn completion is missing for bash + - manager property enumeration was broken when systemd moved to /usr/lib/ + +* cgroups: + - implement system-wide DefaultCPUAccounting=1 switch (and similar for blockio, memory?) + - implement per-slice CPUFairScheduling=1 switch + - handle jointly mounted controllers correctly + - introduce high-level settings for RT budget, swappiness + - how to reset dynamically changed unit cgroup attributes sanely? + - when reloading configuration, apply new cgroup configuration + - when recursively showing the cgroup hierarchy, optionally also show + the hierarchies of child processes + +* transient units: + - allow creating auxiliary units with the same call + - add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt + - ensure scope units may be started only a single time + +* Automatically configure swap partition to use for hibernation by looking for largest swap partition on the root disk? + +* when we detect low battery and no AC on boot, show pretty splash and refuse boot + +* machined, localed: when we try to kill an empty cgroup, generate an ESRCH error over the bus + +* libsystemd-journal, libsystemd-login, libudev: add calls to easily attach these objects to sd-event event loops + +* be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1 + +* unify dispatch table in systemctl_main() and friends + +* Automatically configure swap partition to use for hibernation by looking for largest swap partition on the root disk? + +* socket-proxyd: Use sd-resolve to resolve the server address + +* rfkill,backlight: we probably should run the load tools inside of the udev rules so that the state is properly initialized by the time other software sees it + +* move config_parse_path_strv() out of conf-parser.c + +* After coming back from hibernation reset hibernation swap partition using the /dev/snapshot ioctl APIs + +* If we try to find a unit via a dangling symlink, generate a clean + error. Currently, we just ignore it and read the unit from the search + path anyway. + +* refuse boot if /etc/os-release is missing or /etc/machine-id cannot be set up + +* given that logind now lets PID 1 do all nasty work, we can + probably reduce the capability set it retains substantially. + (we need CAP_SYS_ADMIN for drmSetMaster(), so maybe not worth it) + +* btrfs raid assembly: some .device jobs stay stuck in the queue + +* make sure gdm doesn't use multi-user-x but the new default X configuration file, and then remove multi-user-x from systemd + +* man: the documentation of Restart= currently is very misleading and suggests the tools from ExecStartPre= might get restarted. + +* load .d/*.conf dropins for device units + +* gparted needs to disable auto-activation of mount units somehow, or + maybe we should stop doing auto-activation of this after boot + entirely. https://bugzilla.gnome.org/show_bug.cgi?id=701676 + Maybe take a BSD lock at the disk device node and teach udev to + check for that and suppress event handling. + +* something pulls in pcre as shared object dependency into our daemons such as hostnamed. + +* allow implementation of InaccessibleDirectories=/ plus + ReadOnlyDirectories=... for whitelisting files for a service. + +* sd-bus: + - when kdbus doesn't take our message without memfds, try again with memfds + - implement monitor logic + - see if we can drop more message validation on the sending side + - add API to clone sd_bus_message objects + - systemd-bus-proxyd needs to enforce good old XML policy + - upload minimal kdbus policy into the kernel at boot + - kdbus: matches against source or destination pids for an "strace -p"-like feel. Problem: The PID info needs to be available in userspace too... + - longer term: priority inheritance + - check sender of response messages + - dbus spec updates: + - kdbus mapping + - NameLost/NameAcquired obsolete + - GVariant + - "const" properties (posted) + - port exit-on-idle logic to byebye ioctl + - update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now + - allow updating attach flags during runtime + - pid1: peek into activating message when activating a service + - test bloom filter generation indexes + - introduce sd_bus_emit_object_added()/sd_bus_emit_object_removed() that automatically includes the build-in interfaces in the list + - port to sd-resolve for connecting to TCP dbus servers + - constructors for bus messages should probably not be OK with a NULL bus pointer + +* sd-event + - allow multiple signal handlers per signal? + +* in the final killing spree, detect processes from the root directory, and + complain loudly if they have argv[0][0] == '@' set. + https://bugzilla.redhat.com/show_bug.cgi?id=961044 + +* investigate endianness issues of UUID vs. GUID + +* dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we + should be able to safely try another attempt when the bus call LoadUnit() is invoked. + +* add a pam module that passes the hdd passphrase into the PAM stack and then expires it, for usage by gdm auto-login. + +* add a pam module that on password changes updates any LUKS slot where the password matches + +* maybe add a generator that looks for "systemd.run=" on the kernel cmdline for container usercases... + +* timedatctl, localectl: possibly make some commands work without the daemon, for chroot situations... + +* timedatectl: print a nicer message when enabling ntp fails because ntpd/chrony are not installed + +* cgtop: make cgtop useful in a container + +* test/: + - add 'set -e' to scripts in test/ + - make stuff in test/ work with separate output dir + +* systemctl delete x.snapshot leaves no trace in logs (at least at default level). + +* make the coredump collector tool move itself into the user's cgroup + so that the coredump is properly written to the user's own journal + file. + +* seems that when we follow symlinks to units we prefer the symlink + destination path over /etc and /usr. We shouldn't do that. Instead + /etc should always override /run+/usr and also any symlink + destination. + +* when isolating, try to figure out a way how we implicitly can order + all units we stop before the isolating unit... + +* teach ConditionKernelCommandLine= globs or regexes (in order to match foobar={no,0,off}) + +* after all byte-wise realloc() is slow, even on glibc, so i guess we + need manual exponential loops after all + +* BootLoaderSpec: drop allowing ext234 for $BOOT. Clarify that the + kernel has to be in $BOOT. Clarify that the boot loader should be + installed to the ESP. Define a way how an installer can figure out + whether a BLS compliant boot loader is installed. + +* think about requeuing jobs when daemon-reload is issued? usecase: + the initrd issues a reload after fstab from the host is accessible + and we might want to requeue the mounts local-fs acquired through + that automatically. + +* systemd-inhibit: make taking delay locks useful: support sending SIGINT or SIGTERM on PrepareForSleep() + +* journal-or-kmsg is currently broken? See reverted commit 4a01181e460686d8b4a543b1dfa7f77c9e3c5ab8. + +* remove any syslog support from log.c -- we probably can't do this before split-off udev is gone for good + +* shutdown logging: store to EFI var, and store to USB stick? + +* write UI tool that pops up emergency messages from the journal as notification + +* think about window-manager-run-as-user-service problem: exit 0 → activate shutdown.target; exit != 0 → restart service + +* use "log level" rather than "log priority" everywhere + +* timedate: have global on/off switches for auto-time (NTP), and auto-timezone that connman can subscribe to. + +* merge unit_kill_common() and unit_kill_context() + +* introduce ExecCondition= in services + +* EFI: + - write man page for efi boot generator + - 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 + +* maybe do not install getty@tty1.service symlink in /etc but in /usr? + +* re-enable "make check" for gtk-doc (broken for unknown reason) + +* fstab: add new mount option x-systemd-after=/foobar/waldo to allow manual dependencies to other mount points + https://bugzilla.redhat.com/show_bug.cgi?id=812826 + +* print a nicer explanation if people use variable/specifier expansion in ExecStart= for the first word + +* mount: turn dependency information from /proc/self/mountinfo into dependency information between systemd units. + +* logind: + - logind: optionally, ignore idle-hint logic for autosuspend, block suspend as long as a session is around + - When we update the kernel all kind of hibernation should be prohibited until shutdown/reboot + - logind: wakelock/opportunistic suspend support + - Add pretty name for seats in logind + - logind: allow showing logout dialog from system? + - logind: add equivalent to sd_pid_get_owner_uid() to the D-Bus API + - we should probably handle SIGTERM/SIGINT to not leave dot files around, just in case + - when logging out, remove user-owned sysv and posix IPC objects + - session scopes/user unit: add RequiresMountsFor for the home directory of the user + - add Suspend() bus calls which take timestamps to fix double suspend issues when somebody hits suspend and closes laptop quickly. + - if pam_systemd is invoked by su from a process that is outside of a + any session we should probably just become a NOP, since that's + usually not a real user session but just some system code that just + needs setuid(). + +* exec: when deinitializating a tty device fix the perms and group, too, not only when initializing. Set access mode/gid to 0620/tty. + +* service: watchdog logic: for testing purposes allow ping, but do not require pong + +* journal: + - import and delete pstore filesystem content at startup + - journald: also get thread ID from client, plus thread name + - journal: when waiting for journal additions in the client always sleep at least 1s or so, in order to minimize wakeups + - add API to close/reopen/get fd for journal client fd in libsystemd-journal. + - fallback to /dev/log based logging in libsystemd-journal, if we can't log natively? + - declare the local journal protocol stable in the wiki interface chart + - journal: reuse XZ context + - sd-journal: speed up sd_journal_get_data() with transparent hash table in bg + - journald: when dropping msgs due to ratelimit make sure to write + "dropped %u messages" not only when we are about to print the next + message that works, but alraedy after a short tiemout + - check if we can make journalctl by default use --follow mode inside of less if called without args? + - maybe add API to send pairs of iovecs via sd_journal_send + - journal: when writing journal auto-rotate if time jumps backwards + - journal: add a setgid "systemd-journal" utility to invoke from libsystemd-journal, which passes fds via STDOUT and does PK access + - journactl: support negative filtering, i.e. FOOBAR!="waldo", + and !FOOBAR for events without FOOBAR. + - journal: send out marker messages every now and then, and immediately sync with fdatasync() afterwards, in order to have hourly guaranteed syncs. + - journal-send.c, log.c: when the log socket is clogged, and we drop, count this and write a message about this when it gets unclogged again. + - journal: find a way to allow dropping history early, based on priority, other rules + - journal: When used on NFS, check payload hashes + - journald: check whether it is OK if the client can still modify delivered journal entries + - journal live copy, based on libneon (client) and libmicrohttpd (server) + - journald: add kernel cmdline option to disable ratelimiting for debug purposes + - refuse taking lower-case variable names in sd_journal_send() and friends. + - journald: we currently rotate only after MaxUse+MaxFilesize has been reached. + - journal: deal nicely with byte-by-byte copied files, especially regards header + - journal: store euid in journal if it differs from uid + - journal: sanely deal with entries which are larger than the individual file size, but where the components would fit + - Replace utmp, wtmp, btmp, and lastlog completely with journal + - journalctl: instead --after-cursor= maybe have a --cursor=XYZ+1 syntax? + - tmpfiles: when applying ownership to /run/log/journal, also do this for the journal fails contained in it + - when a kernel driver logs in a tight loop, we should ratelimit that too. + - journald: optionally, log debug messages to /run but everything else to /var + - journald: when we drop syslog messages because the syslog socket is + full, make sure to write how many messages are lost as first thing + to syslog when it works again. + - journald: make sure ratelimit is actually really per-service with the new cgroup changes + - change systemd-journal-flush into a service that stays around during + boot, and causes the journal to be moved back to /run on shutdown, + so that we don't keep /var busy. This needs to happen synchronously, + hence doing this via signals is not going to work. + +* document: + - document that deps in [Unit] sections ignore Alias= fields in + [Install] units of other units, unless those units are disabled + - man: clarify that time-sync.target is not only sysv compat but also useful otherwise. Same for similar targets + - document the exit codes when services fail before they are exec()ed + - document that service reload may be implemented as service reexec + - document in wiki how to map ical recurrence events to systemd timer unit calendar specifications + - add a man page containing packaging guidelines and recommending usage of things like Documentation=, PrivateTmp=, PrivateNetwork= and ReadOnlyDirectories=/etc /usr. + - document systemd-journal-flush.service properly + - documentation: recommend to connect the timer units of a service to the service via Also= in [Install] + - man: document the very specific env the shutdown drop-in tools live in + - man: extend runlevel(8) to mention that runlevels suck, and are dead. Maybe add runlevel(7) with a note about that too + - 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 + +* systemctl: + - systemctl list-jobs - show dependencies + - add systemctl switch to dump transaction without executing it + - Add a verbose mode to "systemctl start" and friends that explains what is being done or not done + - "systemctl disable" on a static unit prints no message and does + nothing. "systemctl enable" does nothing, and gives a bad message + about it. Should fix both to print nice actionable messages. + - print nice message from systemctl --failed if there are no entries shown, and hook that into ExecStartPre of rescue.service/emergency.service + - add new command to systemctl: "systemctl system-reexec" which reexecs as many daemons as virtually possible + - systemctl enable: improve the success messages (i.e. more human readable, less shell-like) + - systemctl enable: fail if target to alias into doesn't exist? maybe show how many units are enabled afterwards? + - systemctl: "Journal has been rotated since unit was started." message is misleading + - support "systemctl stop foobar@.service" to stop all units matching a certain template + - Something is wrong with symlink handling of "autovt@.service" in "systemctl list-unit-files" + - rework wait filter to not require match callback + - better error message if you run systemctl without systemd running + - systemctl status output should should include list of triggering units and their status + - in systemctl list-timers show time triggering units ran last + +* unit install: + - "systemctl mask" should find all names by which a unit is accessible + (i.e. by scanning for symlinks to it) and link them all to /dev/null + - "systemctl disable" of a unit instance removes all symlinks, but should + only remove the instance symlink (systemctl disable of a template + unit however should remove them all). + - systemctl list-unit-files should list generated files (and probably with a new state "generated" for them, or so) + - systemctl: maybe add "systemctl add-wants" or so... + +* introduce ntp.service (or suchlike) as symlink that is used to arbitrate between various NTP implementations + +* deal with sendmail/postfix exclusivity + +* timer units: + - timer events with system resume + - timer units should get the ability to trigger when: + o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET) + o DST changes + - Support 2012-02~4 as syntax for specifying the fourth to last day of the month. + - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1 + - when parsing calendar timestamps support the UTC timezone (even if we won't support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200 + - Modulate timer frequency based on battery state + - anacron-like feature + +* update the kernel's TZ (sys_tz) when DST changes + +* sync down the system time to the RTC when: + - CLOCK_REALTIME makes jumps (the user explicitely requested a time set) + - DST/timezone changes && ntp is active && RTC-in-localtime (never do it without ntp) + This takes care of syncing ntpdate updates to the RTC, and DST updates for localtime + mode, it will never touch the RTC if the no reliable time source is active or the + user did not request anything like it. + +* if booted in "quiet" mode, and an error happens, turn on status + output again, so that the emergency mode isn't totally + surprising. Also, terminate plymouth. + +* libunwind support for coredump pattern hook, and includes this in + the message for coredumps. After all, libunwind is now capable to + unwind coredumps since a few weeks ago. This probably requires that + we have nice support for multi-line messages on display in + logs-show.c. Alternatively: use libelfutil, which seems to be the + better supported alternative. + +* add libsystemd-password or so to query passwords during boot using the password agent logic + +* If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle(). + +* fedup: add --unit to systemctl switch-root somehow +* fedup: don't delete initrd on switch-root +* fedup: generator + +* timedated: refuse time changes when NTP is on + +* clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed + +* on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?), get rid of systemd-update-utmp-runlevel + +* add "provisioning" instructions to setup an empty /etc + /var + - used to setup a new container from a shared /usr + - superset of tmpfiles model + - instructions shipped by packages and stored in /usr/lib/ + - compose /etc/passwd and /etc/group, copy files + - able to create uid + gid used by packages, for file ownership + +* make repeated alt-ctrl-del presses printing a dump, or even force a reboot without + waiting for the timeout + +* hostnamed: before returning information from /etc/machine-info.conf check the modification data and reread. Similar for localed, ... + +* currently x-systemd.timeout is lost in the initrd, since crypttab is copied into dracut, but fstab isn't + +* nspawn: + - nspawn: consider changing users for -u with /usr/bin/getent, so that NSS resolving works correctly + - nspawn: --read-only is not applied recursively to submounts + - bind mount read-only the cgroup tree higher than nspawn + - nspawn: make it work for dwalsh and shared /usr containers -- tmpfs mounts as command line parameters + - refuses to boot containers without /etc/machine-id (OK?), and with empty /etc/machine-id (not OK). + - support taking a btrfs snapshot at startup and dropping it afterwards + - maybe: hookup nspawn and PrivateNetwork=yes with "ip netns" + - allow booting disk images with a GPT signature using the bootloaderspec partition uuids + +* cryptsetup: + - cryptsetup-generator: allow specification of passwords in crypttab itself + - move cryptsetup key caching into kernel keyctl? + https://bugs.freedesktop.org/show_bug.cgi?id=54982 + - support rd.luks.allow-discards= kernel cmdline params in cryptsetup generator + +* hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it + https://bugs.freedesktop.org/show_bug.cgi?id=54712 + +* after deserializing sockets in socket.c we should reapply sockopts and things + +* make timer units go away after they elapsed + +* http://lists.freedesktop.org/archives/systemd-devel/2012-September/006502.html + (network and remote-fs on shutdown) + +* come up with a nice way to write queue/read_ahead_kb for a block device without interfering with readahead + +* move PID 1 segfaults to /var/lib/systemd/coredump? + +* create /sbin/init symlinks from the build system + +* Query Paul Moore about relabelling socket fds while they are open + +* allow writing multiple conditions in unit files on one line -* something like ConditionExec= or ExecStartPre= without failure state +* explore multiple service instances per listening socket idea -* service restart retry configuration +* MountFlags=shared acts as MountFlags=slave right now. -* tmpfiles: apply "x" on "D" too (see patch from William Douglas) -* tmpfiles: support generation of char/block devices, symlinks and one-line files (think sysfs) +* ReadOnlyDirectories= is not applied recursively to submounts -* Introduce ControlGroupPersistant=yes to set +t on the tasks file when creating the cgroup +* drop PID 1 reloading, only do reexecing (difficult: Reload() + currently is properly synchronous, Reexec() is weird, because we + can't delay the response properly until we are back, so instead of + being properly synchronous we just keep open the fd and close it + when done. That means clients don't get a successful method reply, + but much rather a disconnect on success. -* don't set $HOME in services unless requested +* properly handle loop back mounts via fstab, especially regards to fsck/passno -* remove hacks in vala code and require libnotify 0.7 +* allow services with no ExecStart= but with an ExecStop= + +* dracut-shutdown needs to be ordered before unmounting /boot + +* initialize the hostname from the fs label of /, if /etc/hostname does not exist? + +* rename "userspace" to "core-os" + +* syscall filter: optionally don't enforce no new privs? + +* load-fragment: when loading a unit file via a chain of symlinks + verify that it isn't masked via any of the names traversed. + +* introduce Type=pid-file + +* change Requires=basic.target to RequisiteOverride=basic.target + +* when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr + +* automount: implement expire: + - set superblock timeout AUTOFS_DEV_IOCTL_TIMEOUT_CMD + - periodically run AUTOFS_DEV_IOCTL_EXPIRE_CMD + - every timeout/4 (original autofs logic) + - blocking, needs a thread + - run until -EAGAIN + - receive expire packet on pipe if kernel tells the timeout is over + - call umount + - answer expire packet on pipe with AUTOFS_DEV_IOCTL_{READY,FAIL}_CMD + - AUTOFS_DEV_IOCTL_EXPIRE_CMD returns + +* ExecOnFailure=/usr/bin/foo + +* udev: + - remove src/udev/udev-builtin-firmware.c (CONFIG_FW_LOADER_USER_HELPER=n) + - move to LGPL + - kill scsi_id + - add trigger --subsystem-match=usb/usb_device device + - reimport udev db after MOVE events for devices without dev_t + +* when a service has the same env var set twice we actually store it twice and return that in systemctl show -p... We should only show the last setting + +* introduce mix of BindTo and Requisite + +* add DeleteSocketsOnStop=yes|no option to socket units + +* There's currently no way to cancel fsck (used to be possible via C-c or c on the console) + +* add option to sockets to avoid activation. Instead just drop packets/connections, see http://cyberelk.net/tim/2012/02/15/portreserve-systemd-solution/ + +* default unix qlen is too small (10). bump sysctl? add sockopt? + +* save coredump in Windows/Mozilla minidump format + +* support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) + +* default to actual 32bit PIDs, via /proc/sys/kernel/pid_max + +* be able to specify a forced restart of service A where service B depends on, in case B + needs to be auto-respawned? + +* when a bus name of a service disappears from the bus make sure to queue further activation requests + +* tmpfiles: + - check systemd-tmpfiles for selinux context hookup for mknod(), symlink() and similar + - apply "x" on "D" too (see patch from William Douglas) + +* for services: don't set $HOME in services unless requested * hide PAM/TCPWrap options in fragment parser when compile time disabled -* when we automatically restart a service, ensure we retsart its rdeps, too. +* when we automatically restart a service, ensure we restart its rdeps, too. * allow Type=simple with PIDFile= https://bugzilla.redhat.com/show_bug.cgi?id=723942 * move PAM code into its own binary -* warn if the user stops a service but not its associated socket - -* logind: spawn user@..service on login - -* logind: non-local X11 server handling - * implement Register= switch in .socket units to enable registration in Avahi, RPC and other socket registration services. -* make sure people don't leave processes around after ExecStartPre= - * make sure systemd-ask-password-wall does not shutdown systemd-ask-password-console too early -* readahead: use BTRFS_IOC_DEFRAG_RANGE instead of BTRFS_IOC_DEFRAG ioctl, with START_IO - -* readahead: check whether a btrfs volume includes ssd by checking mount flag "ssd" - -* support sd_notify() style notification when reload begins (RELOADING=1), reload is finished (READY=1) +* support sd_notify() style notification when reload begins (RELOADING=1), reload is finished (READY=1), and add ReloadSignal= then to use in combination * support sd_notify() style notification when shutting down, to make auto-exit bus services work (STOPPING=1) @@ -88,51 +596,49 @@ Features: when we start a service in order to avoid confusion when a user assumes starting a service is enough to make it accessible +* support User= and Group= attributes for AF_UNIX sockets. (difficult, requires NSS from PID 1?) + * Make it possible to set the keymap independently from the font on the kernel cmdline. Right now setting one resets also the other. -* move nss-myhostname into systemd - * and a dbus call to generate target from current state -* detect LXC with $container=lxc - -* drop /.readahead on bigger upgrades with yum - -* add inode nr check to readahead to suppress preloading changed files +* readahead: + - drop /.readahead on bigger upgrades with yum + - move readahead files into /var (look for them with .path units?) + - readahead: use BTRFS_IOC_DEFRAG_RANGE instead of BTRFS_IOC_DEFRAG ioctl, with START_IO + - readahead: when bumping /sys readahead variable save mtime and compare later to detect changes + - readahead: make use of EXT4_IOC_MOVE_EXT, as used by http://e4rat.sourceforge.net/ * add support for /bin/mount -s * GC unreferenced jobs (such as .device jobs) -* cgroup_notify_empty(): recursively check groups up the tree, too - -* when failing to start a service due to ratelimiting, try again later, if restart=always is set - * write blog stories about: + - hwdb: what belongs into it, lsusb - enabling dbus services - status update - how to make changes to sysctl and sysfs attributes - remote access - - cgroup best pratices to avoid stepping on each others toes - how to pass throw-away units to systemd, or dynamically change properties of existing units - how to integrate cgconfig and suchlike with systemd - - security properties - - xinetd conversion - - details of instantiated @.service setups + - testing with Harald's awesome test kit + - auto-restart + - how to develop against journal browsing APIs + - the journal HTTP iface + - non-cgroup resource management + - dynamic resource management with cgroups + - refreshed, longer missions statement + - calendar time events + - init=/bin/sh vs. "emergency" mode, vs. "rescue" mode, vs. "multi-user" mode, vs. "graphical" mode, and the debug shell + - how to create your own target + - instantiated apache, dovecot and so on + - hooking a script into various stages of shutdown/rearly booot * allow port=0 in .socket units -* move readahead files into /var, look for them with .path units - -* teach dbus to activate all services it finds in /etc/systemd/services/org-*.service - * support systemd.mask= on the kernel command line. -* when key file cannot be found, read it from kbd in cryptsetup - -* reuse mkdtemp namespace dirs in /tmp? - * recreate systemd's D-Bus private socket file on SIGUSR2 * Support --test based on current system state @@ -141,86 +647,77 @@ Features: * maybe introduce ExecRestartPre= -* configurable jitter for timer events - -* timer events with system resume - -* timer events on calendar time - -* Support ProcessNeededForShutdown=true to allow stuff like mdmon to - be killed very late after the rootfs is read only? If implement pass - this to shutdown binary via command line argument. - * dot output for --test showing the 'initial transaction' -* calendar time support in timer, iCalendar semantics for the timer stuff (RFC2445) - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=99ee5315dac6211e972fa3f23bcc9a0343ff58c4 - -* implicitly import "defaults" settings file into all types -* exec settings override -* writable cgroups dbus properties for live changes - -* read config fragments for all units from /lib/systemd/system/foobar.service.d/ to override/extend specific settings - -* port over to LISTEN_FDS/LISTEN_PID: - - rpcbind (/var/run/rpcbind.sock!) HAVEPATCH - - cups HAVEPATCH - - postfix, saslauthd - - apache/samba - - libvirtd (/var/run/libvirt/libvirt-sock-ro) - - bluetoothd (/var/run/sdp! @/org/bluez/audio!) - - distccd - -* auditd service files - * fingerprint.target, wireless.target, gps.target, netdevice.target * io priority during initialization -* if a service fails too often, make the service enter failed mode, and the socket, too. +* drop cap bounding set in readahead and other services -* new deps "Triggers" and "TriggeredBy" +* systemd-python: + - figure out a simple way to wait for journal events in a way that + works with ^C + - add documentation to systemd.daemon -* systemctl list-jobs - show dependencies +* bootchart: + - plot per-process IO utilization + - group processes based on service association (cgroups) + - document initcall_debug + - kernel cmdline "bootchart" option for simplicity? -* add systemctl switch to dump transaction without executing it +* udev-link-config: + - Make sure ID_PATH is always exported and complete for + network devices where possible, so we can safely rely + on Path= matching -* suspend, resume support? +* sd-rtnl: + - add support for exiting containers without reading them fully first + - add support for more attribute types -* drop cap bounding set in readahead and other services +* networkd: + - add more keys to [Route] and [Address] sections + - add support for more DHCPv4 options (and, longer term, other kinds of dynamic config) + - add proper initrd support (in particular generate .network/.link files based on /proc/cmdline) + - add reduced [Link] support to .network files External: * dbus: - - get process transport into dbus for systemctl -P/-H (PENDING) - - dbus --user - natively watch for dbus-*.service symlinks (PENDING) - - allow specification of socket mode/umask when allocating DBusServer - - allow disabling of fd passing when connecting a AF_UNIX connection - - allow disabling of UID passing for AUTH EXTERNAL - -* systemd --user - PR_SET_CHILD_REAPER patch: https://lkml.org/lkml/2011/7/28/426 + - teach dbus to activate all services it finds in /etc/systemd/services/org-*.service * fix alsa mixer restore to not print error when no config is stored -* udisks should not use udisks-part-id, instead use blkid. also not probe /dev/loopxxx +* make cryptsetup lower --iter-time -* snd-seq should go, https://bugzilla.redhat.com/show_bug.cgi?id=676095 +* patch kernel for xattr support in /dev, /proc/, /sys? -* gnome-shell python script/glxinfo/is-accelerated must die +* NTP: the kernel's 11-minutes-mode syncs the system time to the RTC, but only + in an ~30 minutes window. It does not adjust larger differences. Find a way + to tell the kernel, to always do a full time sync when the RTC is in UTC and + we are in 11-minutes-mode. When we trust the system time to NTP we also want + the RTC to sync up. -* make cryptsetup lower --iter-time +* kernel: add device_type = "fb", "fbcon" to class "graphics" -* patch kernel for xattr support in /dev, /proc/, /sys and /sys/fs/cgroup? +* drop accountsservice's StandardOutput=syslog and Type=dbus fields -* patch kernel for cpu feature modalias for autoloading aes/kvm/... - http://git.kernel.org/?p=linux/kernel/git/ak/linux-misc-2.6.git;a=shortlog;h=refs/heads/cpuid-match - (Rafael J. Wysocki's sysdev rework is on the way. After that CPUs can be exported a proper bus.) +* dbus upstream still refers to dbus.target and shouldn't -* kernel: add /proc/sys file exposing CAP_LAST_CAP? sysconf? +* dbus: in fedora, make /var/lib/dbus/machine-id a symlink to /etc/machine-id -* kernel: add device_type = "fb", "fbcon" to class "graphics" +* add "# export SYSTEMD_PAGER=" to bash login + +* /usr/bin/service should actually show the new command line + +* fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus= + +* fedora: F20: go timer units all the way, leave cron.daily for cron + +* neither pkexec nor sudo initialize environ[] from the PAM environment? + +* fedora: update policy to declare access mode and ownership of unit files to root:root 0644, and add an rpmlint check for it Regularly: @@ -230,8 +727,14 @@ Regularly: * Use PR_SET_PROCTITLE_AREA if it becomes available in the kernel -* %m in printf() instead of strerror(); - * pahole * set_put(), hashmap_put() return values check. i.e. == 0 doesn't free()! + +* use secure_getenv() instead of getenv() where appropriate + +* link up selected blog stories from man pages and unit files Documentation= fields + +Scheduled for removal or fixing: + +* xxxOverridable dependencies (probably: fix) diff --git a/autogen.sh b/autogen.sh index b2b680a..20f013a 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,83 +1,79 @@ -#!/bin/bash +#!/bin/sh # This file is part of systemd. # -# Copyright 2010 Lennart Poettering -# # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. +# Lesser General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . -AM_VERSION=1.11 -AC_VERSION=2.63 - -run_versioned() { - local P - local V - - V=$(echo "$2" | sed -e 's,\.,,g') - - if [ -e "`which $1$V 2> /dev/null`" ] ; then - P="$1$V" - else - if [ -e "`which $1-$2 2> /dev/null`" ] ; then - P="$1-$2" - else - P="$1" - fi - fi +set -e - shift 2 - "$P" "$@" -} - -set -ex - -if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then - cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ - chmod +x .git/hooks/pre-commit && \ - echo "Activated pre-commit hook." +if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then + # This part is allowed to fail + cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ + chmod +x .git/hooks/pre-commit && \ + echo "Activated pre-commit hook." || : fi -if type -p colorgcc > /dev/null ; then - export CC=colorgcc +if which gtkdocize >/dev/null 2>/dev/null; then + gtkdocize --docdir docs/ --flavour no-tmpl + gtkdocargs=--enable-gtk-doc +else + echo "You don't have gtk-doc installed, and thus won't be able to generate the documentation." + rm -f docs/gtk-doc.make + echo 'EXTRA_DIST =' > docs/gtk-doc.make fi +intltoolize --force --automake +autoreconf --force --install --symlink + libdir() { - echo $(cd $1/$(gcc -print-multi-os-directory); pwd) + echo $(cd "$1/$(gcc -print-multi-os-directory)"; pwd) } -if [ "x$1" = "xam" ] ; then - run_versioned automake "$AM_VERSION" -a -c --foreign - ./config.status -else - rm -rf autom4te.cache - rm -f config.cache +args="\ +--sysconfdir=/etc \ +--localstatedir=/var \ +--libdir=$(libdir /usr/lib) \ +$gtkdocargs" - libtoolize -c --force - intltoolize -c -f - run_versioned aclocal "$AM_VERSION" -I m4 - run_versioned autoconf "$AC_VERSION" -Wall - run_versioned autoheader "$AC_VERSION" - run_versioned automake "$AM_VERSION" --copy --foreign --add-missing +if [ ! -L /bin ]; then +args="$args \ +--with-rootprefix= \ +--with-rootlibdir=$(libdir /lib) \ +" +fi - if [ "x$1" != "xac" ]; then - CFLAGS="$CFLAGS -g -O0" ./configure \ - --sysconfdir=/etc \ - --localstatedir=/var \ - --libexecdir=/usr/lib \ - --libdir=$(libdir /usr/local/lib) \ - --with-rootdir= \ - "$@" +if [ "x$1" = "xc" ]; then + ./configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args + make clean +elif [ "x$1" = "xg" ]; then + ./configure CFLAGS='-g -Og -ftrapv' --enable-compat-libs --enable-kdbus $args make clean - fi +elif [ "x$1" = "xa" ]; then + ./configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' --enable-compat-libs --enable-kdbus $args + make clean +elif [ "x$1" = "xl" ]; then + ./configure CC=clang CFLAGS='-g -O0 -ftrapv -Wno-gnu' --enable-compat-libs --enable-kdbus $args + make clean +elif [ "x$1" = "xs" ]; then + scan-build ./configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args + scan-build make +else + echo + echo "----------------------------------------------------------------" + echo "Initialized build system. For a common configuration please run:" + echo "----------------------------------------------------------------" + echo + echo "./configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args" + echo fi diff --git a/catalog/Makefile b/catalog/Makefile new file mode 120000 index 0000000..bd10475 --- /dev/null +++ b/catalog/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/catalog/systemd.catalog b/catalog/systemd.catalog new file mode 100644 index 0000000..3c2fe64 --- /dev/null +++ b/catalog/systemd.catalog @@ -0,0 +1,280 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +# Message catalog for systemd's own messages + +# The catalog format is documented on +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# For an explanation why we do all this, see https://xkcd.com/1024/ + +-- f77379a8490b408bbe5f6940505a777b +Subject: The Journal has been started +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system journal process has been starting up, opened the journal +files for writing and is now ready to process requests. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: The Journal has been stopped +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system journal process has shut down and closed all currently +active journal files. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: Messages from a service have been suppressed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +A service has logged too many messages within a time period. Messages +from the service have been dropped. + +Note that only messages from the service in question have been +dropped, other services' messages are unaffected. + +The limits when messages are dropped may be configured with +RateLimitInterval= and RateLimitBurst= in +/etc/systemd/journald.conf. See journald.conf(5) for details. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Journal messages have been missed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Kernel messages have been lost as the journal system has been unable +to process them quickly enough. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Process @COREDUMP_PID@ (@COREDUMP_COMM@) dumped core +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Process @COREDUMP_PID@ (@COREDUMP_COMM@) crashed and dumped core. + +This usually indicates a programming error in the crashing program and +should be reported to its vendor as a bug. + +-- fc2e22bc6ee647b6b90729ab34a250b1 de +Subject: Speicherabbild für Prozess @COREDUMP_PID@ (@COREDUMP_COMM) generiert +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Prozess @COREDUMP_PID@ (@COREDUMP_COMM@) ist abgebrochen worden und +ein Speicherabbild wurde generiert. + +Üblicherweise ist dies ein Hinweis auf einen Programmfehler und sollte +als Fehler dem jeweiligen Hersteller gemeldet werden. + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: A new session @SESSION_ID@ has been created for user @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A new session with the ID @SESSION_ID@ has been created for the user @USER_ID@. + +The leading process of the session is @LEADER@. + +-- 3354939424b4456d9802ca8333ed424a +Subject: A session @SESSION_ID@ has been terminated +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A session with the ID @SESSION_ID@ has been terminated. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: A new seat @SEAT_ID@ is now available +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A new seat @SEAT_ID@ has been configured and is now available. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: A seat @SEAT_ID@ has now been removed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A seat @SEAT_ID@ has been removed and is no longer available. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Time change +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system clock has been changed to @REALTIME@ microseconds after January 1st, 1970. + +-- c7a787079b354eaaa9e77b371893cd27 de +Subject: Zeitänderung +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Die System-Zeit wurde geändert auf @REALTIME@ Mikrosekunden nach dem 1. Januar 1970. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Time zone change to @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system timezone has been changed to @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: System start-up is now complete +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +All system services necessary queued for starting at boot have been +successfully started. Note that this does not mean that the machine is +now idle as services might still be busy with completing start-up. + +Kernel start-up required @KERNEL_USEC@ microseconds. + +Initial RAM disk start-up required @INITRD_USEC@ microseconds. + +Userspace start-up required @USERSPACE_USEC@ microseconds. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: System sleep state @SLEEP@ entered +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system has now entered the @SLEEP@ sleep state. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: System sleep state @SLEEP@ left +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The system has now left the @SLEEP@ sleep state. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: System shutdown initiated +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Systemd shutdown has been initiated. The shutdown has now begun and +all system services are terminated and all file systems unmounted. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: Unit @UNIT@ has begun with start-up +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has begun starting up. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: Unit @UNIT@ has finished start-up +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has finished starting up. + +The start-up result is @RESULT@. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: Unit @UNIT@ has begun shutting down +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has begun shutting down. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: Unit @UNIT@ has finished shutting down +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has finished shutting down. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: Unit @UNIT@ has failed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has failed. + +The result is @RESULT@. + +-- d34d037fff1847e6ae669a370e694725 +Subject: Unit @UNIT@ has begun with reloading its configuration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has begun with reloading its configuration + +-- 7b05ebc668384222baa8881179cfda54 +Subject: Unit @UNIT@ has finished reloading its configuration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Unit @UNIT@ has finished reloading its configuration + +The result is @RESULT@. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: Process @EXECUTABLE@ could not be executed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The process @EXECUTABLE@ could not be executed and failed. + +The error number returned while executing this process is @ERRNO@. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: One or more messages could not be forwarded to syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +One or more messages could not be forwarded to the syslog service +running side-by-side with journald. This usually indicates that the +syslog implementation has not been able to keep up with the speed of +messages queued. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Mount point is not empty +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The directory @WHERE@ is specified as the mount point (second field in +/etc/fstab or Where= field in systemd unit file) and is not empty. +This does not interfere with mounting, but the pre-exisiting files in +this directory become inaccessible. To see those over-mounted files, +please manually mount the underlying file system to a secondary +location. + +-- 24d8d4452573402496068381a6312df2 +Subject: A virtual machine or container has been started +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The virtual machine @NAME@ with its leader PID @LEADER@ has been +started is now ready to use. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: A virtual machine or container has been terminated +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +The virtual machine @NAME@ with its leader PID @LEADER@ has been +shut down. diff --git a/catalog/systemd.fr.catalog b/catalog/systemd.fr.catalog new file mode 100644 index 0000000..3524562 --- /dev/null +++ b/catalog/systemd.fr.catalog @@ -0,0 +1,260 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# Copyright 2013 Sylvain Plantefève +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +# Message catalog for systemd's own messages +# French translation + +# Le format du catalogue de messages est décrit (en anglais) içi : +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +-- f77379a8490b408bbe5f6940505a777b +Subject: Le Journal a été démarré +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le processus du journal système a démarré, ouvert ses fichiers en écriture +et est prêt à traiter les requêtes. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: Le Journal a été arrêté +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le processus du journal système a été arrêté et tous ses fichiers actifs +ont été fermés. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: Des messages d'un service ont été supprimés +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +Un service a essayé d'enregistrer un trop grand nombre de messages sur un +intervalle de temps donné. Des messages de ce service ont été évincés. + +Notez que seuls des messages de ce service ont été évincés, les messages des +autres services ne sont pas affectés. + +Les limites définissant ce comportement peuvent être configurées avec les +paramètres RateLimitInterval= et RateLimitBurst= dans le fichier +/etc/systemd/journald.conf. Voir journald.conf(5) pour plus de détails. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Des messages du Journal ont été manqués +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Des messages du noyau ont été manqués car le journal système n'a pas été +capable de les traiter suffisament vite. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Le processus @COREDUMP_PID@ (@COREDUMP_COMM@) a généré un fichier « core » +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Le processus @COREDUMP_PID@ (@COREDUMP_COMM@) a planté et généré un fichier « core ». + +Cela indique généralement une erreur de programmation dans le programme +incriminé, et cela devrait être notifié à son concepteur comme un défaut (bug). + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: Une nouvelle session @SESSION_ID@ a été créée pour l'utilisateur @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Une nouvelle session a été créée pour l'utilisateur @USER_ID@ avec +l'identifiant (ID) @SESSION_ID@. + +Le processus maître de la session est @LEADER@. + +-- 3354939424b4456d9802ca8333ed424a +Subject: La session @SESSION_ID@ s'est terminée +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +La session d'identifiant (ID) @SESSION_ID@ s'est terminée. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: Un nouveau poste (seat) @SEAT_ID@ est disponible +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Un nouveau poste (seat) @SEAT_ID@ a été configuré et est maintenant disponible. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: Le poste (seat) @SEAT_ID@ a été retiré +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Le poste (seat) @SEAT_ID@ a été retiré et n'est plus disponible. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Changement d'heure +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'horloge système a été modifiée et positionnée à @REALTIME@ microsecondes +après le 1er janvier 1970. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Fuseau horaire modifié en @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le fuseau horaire du système a été modifié et positionné à @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: Le démarrage du système est terminé +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Tous les services nécessaires au démarrage du système ont été lancés avec +succès. Notez que cela ne signifie pas que le système est maintenant au +repos, car des services peuvent encore être en train de terminer leur +démarrage. + +Le chargement du noyau a nécessité @KERNEL_USEC@ microsecondes. + +Le chargement du « RAM disk » initial a nécessité @INITRD_USEC@ microsecondes. + +Le chargement de l'espace utilisateur a nécessité @USERSPACE_USEC@ microsecondes. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: Le système entre dans l'état de repos (sleep state) @SLEEP@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le système est maintenant à l'état de repos (sleep state) @SLEEP@. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: Le système sorti de l'état de repos (sleep state) @SLEEP@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le système est maintenant sorti de l'état de repos (sleep state) @SLEEP@. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: Arrêt du système amorcé +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'arrêt du système a été amorcé. L'arrêt a maintenant commencé, tous les +services du système sont terminés et tous les systèmes de fichiers sont +démontés. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: L'unité (unit) @UNIT@ a commencé à démarrer +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a commencé à démarrer. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: L'unité (unit) @UNIT@ a terminé son démarrage +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a terminé son démarrage, avec le résultat @RESULT@. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: L'unité (unit) @UNIT@ a commencé à s'arrêter +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a commencé à s'arrêter. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: L'unité (unit) @UNIT@ a terminé son arrêt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a terminé son arrêt. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: L'unité (unit) @UNIT@ a échoué +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a échoué, avec le résultat @RESULT@. + +-- d34d037fff1847e6ae669a370e694725 +Subject: L'unité (unit) @UNIT@ a commencé à recharger sa configuration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a commencé à recharger sa configuration. + +-- 7b05ebc668384222baa8881179cfda54 +Subject: L'unité (unit) @UNIT@ a terminé de recharger configuration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unité (unit) @UNIT@ a terminé de recharger configuration, +avec le résultat @RESULT@. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: Le processus @EXECUTABLE@ n'a pas pu être exécuté +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le processus @EXECUTABLE@ n'a pas pu être exécuté, et a donc echoué. + +Le code d'erreur renvoyé est @ERRNO@. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: Un ou plusieurs messages n'ont pas pu être transmis à syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Un ou plusieurs messages n'ont pas pu être transmis au service syslog +s'exécutant conjointement avec journald. Cela indique généralement que +l'implémentation de syslog utilisée n'a pas été capable de suivre la cadence +du flux de messages. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Le point de montage n'est pas vide +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Le répertoire @WHERE@ est spécifié comme point de montage (second champ du +fichier /etc/fstab, ou champ Where= dans une unité (unit) systemd) et n'est pas +vide. +Cela ne perturbe pas le montage du système de fichiers, mais les fichiers +préalablement présents dans ce répertoire sont devenus inaccessibles. +Pour atteindre ces fichiers, veuillez monter manuellement le système de +fichiers sous-jacent à un autre emplacement. + +-- 24d8d4452573402496068381a6312df2 +Subject: Une machine virtuelle ou un conteneur (container) a été démarré +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +La machine virtuelle @NAME@ a été démarrée avec le PID maître @LEADER@, +et est maintenant prête à l'emploi. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: Une machine virtuelle ou un conteneur (container) a été arrêté +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +La machine virtuelle @NAME@ avec le PID maître @LEADER@ a été arrêtée. diff --git a/catalog/systemd.it.catalog b/catalog/systemd.it.catalog new file mode 100644 index 0000000..861b92b --- /dev/null +++ b/catalog/systemd.it.catalog @@ -0,0 +1,254 @@ +# This file is part of systemd. +# +# Copyright 2013 Daniele Medri +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +# Message catalog for systemd's own messages + +-- f77379a8490b408bbe5f6940505a777b +Subject: Il registro è stato avviato +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il processo relativo al registro di sistema è stato avviato, ha aperto i +file in scrittura ed è ora pronto a gestire richieste. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: Il registro è stato terminato +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il processo relativo al registro di sistema è stato terminato e ha chiuso +tutti i file attivi. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: I messaggi di un servizio sono stati soppressi +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +Un servizio ha registrato troppi messaggi in un dato periodo di tempo. +I messaggi del servizio sono stati eliminati. + +Solo i messaggi del servizio indicato sono stati +eliminati, i messaggi degli altri servizi rimangono invariati. + +I limiti oltre i quali i messaggi si eliminano si configurano +con RateLimitInterval= e RateLimitBurst= in +/etc/systemd/journald.conf. Vedi journald.conf(5) per maggiori informazioni. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: I messaggi di un servizio sono stati perduti +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +I messaggi del kernel sono stati perduti perché, il registro di sistema +non è stato in grado di gestirli abbastanza velocemente. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Il processo @COREDUMP_PID@ (@COREDUMP_COMM@) ha generato un dump. +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Il processo @COREDUMP_PID@ (@COREDUMP_COMM@) si è bloccato generando un dump. + +Questo di solito capita per un errore di programmazione nell'applicazione e +dovrebbe essere segnalato al vendor come un bug. + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: La nuova sessione @SESSION_ID@ è stata creata per l'utente @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Una nuova sessione con ID @SESSION_ID@ è stata creata per l'utente @USER_ID@. + +Il processo primario della sessione è @LEADER@. + +-- 3354939424b4456d9802ca8333ed424a +Subject: La sessione @SESSION_ID@ è terminata +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +La sessione con ID @SESSION_ID@ è terminata. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: La nuova postazione @SEAT_ID@ è ora disponibile +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +La nuova postazione @SEAT_ID@ è stata configurata ed è ora disponibile. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: La postazione @SEAT_ID@ è stata rimossa +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +La postazione @SEAT_ID@ è stata rimossa e non è più disponibile. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Cambio d'orario +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'orologio di sistema è cambiato in @REALTIME@ microsecondi dal 1 gennaio, 1970. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Il fuso orario è cambiato in @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il fuso orario di sistema è cambiato in @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: Avvio del sistema completato. +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Tutti i servizi di sistema richiesti per la fase di avvio sono stati eseguiti +con successo. Nota che la macchina potrebbe non essere ancora pronta in quanto +i servizi attivati sono in fase di completamento. + +L'avvio del kernel ha richiesto @KERNEL_USEC@ microsecondi. + +L'avvio del disco RAM ha richiesto @INITRD_USEC@ microsecondi. + +L'avvio dello userspace ha richiesto @USERSPACE_USEC@ microsecondi. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: Il sistema è entrato in fase di pausa @SLEEP@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il sistema è entrato nello stato di pausa @SLEEP@. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: Il sistema è uscito dalla fase di pausa @SLEEP@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il sistema è uscito dallo stato di pausa @SLEEP@. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: Il sistema è in fase di spegnimento +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Systemd è in fase di spegnimento. Tutti i servizi di sistema +saranno terminati e tutti i file systems smontati. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: L'unità @UNIT@ inizia la fase di avvio +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ ha iniziato la fase di avvio. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: L'unità @UNIT@ termina la fase di avvio +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ ha terminato la fase di avvio. + +La fase di avvio è @RESULT@. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: L'unità @UNIT@ inizia la fase di spegnimento +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ ha iniziato la fase di spegnimento. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: L'unità @UNIT@ termina la fase di spegnimento +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ ha terminato la fase di spegnimento. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: L'unità @UNIT@ è fallita +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ è fallita. + +Il risultato è @RESULT@. + +-- d34d037fff1847e6ae669a370e694725 +Subject: L'unità @UNIT@ inizia a caricare la propria configurazione +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ è iniziata ricaricando la propria configurazione + +-- 7b05ebc668384222baa8881179cfda54 +Subject: L'unità @UNIT@ termina il caricamento della propria configurazione +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +L'unità @UNIT@ è terminata ricaricando la propria configurazione + +Il risultato è @RESULT@. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: Il processo @EXECUTABLE@ non può essere eseguito +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Il processo @EXECUTABLE@ non può essere eseguito e termina. + +Il numero di errore restituito durante l'esecuzione del processo è @ERRNO@. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: Uno o più messaggi non possono essere inoltrati a syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Uno o più messaggi non possono essere inviati al servizio syslog +eseguito in parallelo a journald. Questo di solito capita perché, +l'implementazione di syslog non sta al passo con la +velocità dei messaggi accodati. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Il punto di montaggio non è vuoto +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +La directory @WHERE@ è specificata come punto di montaggio (secondo campo +in /etc/fstab o nel campo Where= del file unità di systemd) e non è vuoto. +Questo non interferisce con il montaggio, ma i file pre-esistenti in questa +directory diventano inaccessibili. Per visualizzare i file, si suggerisce +di montare manualmente il file system indicato in una posizione secondaria. + +-- 24d8d4452573402496068381a6312df2 +Subject: Avviata macchina virtuale o container +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +La macchina virtuale @NAME@ con PID primario @LEADER@ è stata +avviata ed è pronta all'uso. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: Terminata macchina virtuale o container +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +La macchina virtuale @NAME@ con PID primario @LEADER@ è stata spenta. diff --git a/catalog/systemd.ru.catalog b/catalog/systemd.ru.catalog new file mode 100644 index 0000000..f995324 --- /dev/null +++ b/catalog/systemd.ru.catalog @@ -0,0 +1,294 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# Copyright 2013 Sergey Ptashnick +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +# Message catalog for systemd's own messages +# Russian translation + +# Формат каталога сообщений описан по ссылке +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# Перед каждым элементом в комментарии указан Subject исходного +# сообщения (на английском). + +# Subject: The Journal has been started +-- f77379a8490b408bbe5f6940505a777b +Subject: Запущена служба журналирования +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Процесс, отвечающий за журналирование системных событий, успешно запустился, +открыл для записи файлы журнала, и готов обрабатывать запросы. + +# Subject: The Journal has been stopped +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: Служба журналирования остановлена +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Процесс, отвечающий за журналирование системных событий, завершил работу и +закрыл все свои файлы. + +# Subject: Messages from a service have been suppressed +-- a596d6fe7bfa4994828e72309e95d61e +Subject: Часть сообщений от службы пропущена +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +Служба отправила слишком много сообщений за короткий промежуток времени. +Часть сообщений была пропущена. + +Обратите внимание, что были пропущены сообщения только от этой службы, +сообщения других служб не затронуты. + +Предел, после которого служба журнала начинает игнорировать сообщения, +настраивается параметрами RateLimitInterval= и RateLimitBurst= в файле +/etc/systemd/journald.conf. Подробности смотрите на странице руководства +journald.conf(5). + +# Subject: Journal messages have been missed +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Часть сообщений ядра пропущена +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Часть сообщений, поступивших от ядра, была потеряна, так как служба +журналирования не успела их обработать. + +# Subject: Process @COREDUMP_PID@ (@COREDUMP_COMM@) dumped core +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Процесс @COREDUMP_PID@ (@COREDUMP_COMM@) сбросил дамп памяти +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Процесс @COREDUMP_PID@ (@COREDUMP_COMM@) завершился из-за критической ошибки. +Записан дамп памяти. + +Вероятно, это произошло из-за ошибки, допущенной в коде программы. +Рекомендуется сообщить ее разработчикам о возникшей проблеме. + +# Subject: A new session @SESSION_ID@ has been created for user @USER_ID@ +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: Для пользователя @USER_ID@ создан новый сеанс @SESSION_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Для пользователя @USER_ID@ создан новый сеанс с идентификатором @SESSION_ID@. + +Главный процесс нового сеанса имеет индентификатор @LEADER@. + +# Subject: A session @SESSION_ID@ has been terminated +-- 3354939424b4456d9802ca8333ed424a +Subject: Сеанс @SESSION_ID@ завершен +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Сеанс с идентификатором @SESSION_ID@ завершился. + +# Subject: A new seat @SEAT_ID@ is now available +-- fcbefc5da23d428093f97c82a9290f7b +Subject: Добавлено новое рабочее место @SEAT_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Новое рабочее место (seat) @SEAT_ID@ полностью настроено и готово к +использованию. + +# Subject: A seat @SEAT_ID@ has now been removed +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: Рабочее место @SEAT_ID@ отключено +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Рабочее место (seat) @SEAT_ID@ было отключено. + +# Subject: Time change +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Переведены системные часы +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Системные часы были переведены. Сейчас они показывают @REALTIME@ микросекунд +с момента 00:00:00 1 января 1970 года. + +# Subject: Time zone change to @TIMEZONE@ +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Часовой пояс изменен на @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Системный часовой пояс был изменен. Новое значение: @TIMEZONE@. + +# Subject: System start-up is now complete +-- b07a249cd024414a82dd00cd181378ff +Subject: Запуск системы завершен +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Все системные службы, запуск которых предписан настройками, были запущены. +Впрочем, это еще не означает, что система в данный момент ничем не занята, +так как некоторые службы могут продолжать инициализацию даже после того, как +отчитались о своем запуске. + +Запуск ядра занял @KERNEL_USEC@ микросекунд. + +Процессы начального RAM-диска (initrd) отработали за @INITRD_USEC@ микросекунд. + +Запуск системных служб занял @USERSPACE_USEC@ микросекунд. + +# Subject: System sleep state @SLEEP@ entered +-- 6bbd95ee977941e497c48be27c254128 +Subject: Система перешла в состояние сна (@SLEEP@) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Система была переведена в состояние сна (@SLEEP@). + +# Subject: System sleep state @SLEEP@ left +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: Система вышла из состояния сна (@SLEEP@) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Система была выведена из состояния сна (@SLEEP@). + +# Subject: System shutdown initiated +-- 98268866d1d54a499c4e98921d93bc40 +Subject: Подготовка системы к выключению +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Начат процесс подготовки к выключению компьютера. Останавливаются все системные +службы, отмонтируются все файловые системы. + +# Subject: Unit @UNIT@ has begun with start-up +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: Начинается запуск юнита @UNIT@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Начат процесс запуска юнита @UNIT@. + +# Subject: Unit @UNIT@ has finished start-up +-- 39f53479d3a045ac8e11786248231fbf +Subject: Запуск юнита @UNIT@ завершен +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Процесс запуска юнита @UNIT@ был завершен. + +Результат: @RESULT@. + +# Subject: Unit @UNIT@ has begun shutting down +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: Начинается остановка юнита @UNIT@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Начат процесс остановки юнита @UNIT@. + +# Subject: Unit @UNIT@ has finished shutting down +-- 9d1aaa27d60140bd96365438aad20286 +Subject: Завершена остановка юнита @UNIT@. +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Процесс остановки юнита @UNIT@ был завершен. + +# Subject: Unit @UNIT@ has failed +-- be02cf6855d2428ba40df7e9d022f03d +Subject: Ошибка юнита @UNIT@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Произошел сбой юнита @UNIT@. + +Результат: @RESULT@. + +# Subject: Unit @UNIT@ has begun with reloading its configuration +-- d34d037fff1847e6ae669a370e694725 +Subject: Юнит @UNIT@ начал перечитывать свои настройки +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Юнит @UNIT@ начал процесс перечитывания своей конфигурации. + +# Subject: Unit @UNIT@ has finished reloading its configuration +-- 7b05ebc668384222baa8881179cfda54 +Subject: Юнит @UNIT@ завершил перечитывание своих настроек +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Юнит @UNIT@ завершил процесс перечитывания своей конфигурации. + +Результат: @RESULT@. + +# Subject: Process @EXECUTABLE@ could not be executed +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: Не удалось запустить процесс @EXECUTABLE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Сбой: не удалось запустить процесс @EXECUTABLE@. + +Код ошибки: @ERRNO@. + +# Subject: One or more messages could not be forwarded to syslog +-- 0027229ca0644181a76c4e92458afa2e +Subject: Часть сообщений не удалось передать процессу syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Не удалось передать некоторые сообщения демону системного лога (syslog), +дублирующему работу службы системного журнала. Скорее всего, причина в том, что +используемая реализация syslog не успевает обрабатывать сообщения с достаточной +скоростью. + +# Subject: Mount point is not empty +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Каталог, являющийся точкой монтирования, не пуст +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Каталог @WHERE@, который был указан в качестве точки монтирования (во втором +столбце файла /etc/fstab, либо в параметре Where= файла конфигурации юнита), +не является пустым. Это никак не мешает монтированию, однако ранее находившиеся +в нем файлы будут недоступны. Чтобы получить к ним доступ, вы можете вручную +перемонтировать нижележащую файловую систему в другую точку. + +# Subject: A virtual machine or container has been started +-- 24d8d4452573402496068381a6312df2 +Subject: Запущена виртуальная машина/контейнер +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Виртуальная машина @NAME@ (идентификатор главного процесса: @LEADER@) запущена и +готова к работе. + +# Subject: A virtual machine or container has been terminated +-- 58432bd3bace477cb514b56381b8a758 +Subject: Остановлена виртуальная машина/контейнер +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Виртуальная машина @NAME@ (идентификатор главного процесса: @LEADER@) выключена. diff --git a/configure.ac b/configure.ac index 5f60249..7920d6c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,47 +1,52 @@ +# # This file is part of systemd. # -# Copyright 2010 Lennart Poettering +# Copyright 2010-2012 Lennart Poettering +# Copyright 2010-2012 Kay Sievers # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. +# Lesser General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . -AC_PREREQ(2.63) +AC_PREREQ([2.64]) + +AC_INIT([systemd], + [210], + [http://bugs.freedesktop.org/enter_bug.cgi?product=systemd], + [systemd], + [http://www.freedesktop.org/wiki/Software/systemd]) -AC_INIT([systemd],[37],[systemd-devel@lists.freedesktop.org]) -AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_SRCDIR([src/core/main.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_AUX_DIR([build-aux]) + AC_USE_SYSTEM_EXTENSIONS AC_SYS_LARGEFILE - -AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax subdir-objects dist-bzip2]) - -AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/wiki/Software/systemd]) - +AC_PREFIX_DEFAULT([/usr]) +AM_MAINTAINER_MODE([enable]) +AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects check-news]) +AM_SILENT_RULES([yes]) AC_CANONICAL_HOST AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.]) AS_IF([test "x$host_cpu" = "xmips" || test "x$host_cpu" = "xmipsel" || test "x$host_cpu" = "xmips64" || test "x$host_cpu" = "xmips64el"], [AC_DEFINE(ARCH_MIPS, [], [Whether on mips arch])]) -AM_SILENT_RULES([yes]) - -AC_CHECK_PROG([STOW], [stow], [yes], [no]) +LT_PREREQ(2.2) +LT_INIT([disable-static]) -AS_IF([test "x$STOW" = "xyes" && test -d /usr/local/stow], [ - AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) - ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" -]) +AS_IF([test "x$enable_static" = "xyes"], [AC_MSG_ERROR([--enable-static is not supported by systemd])]) +AS_IF([test "x$enable_largefile" = "xno"], [AC_MSG_ERROR([--disable-largefile is not supported by systemd])]) # i18n stuff for the PolicyKit policy files IT_PROG_INTLTOOL([0.40.0]) @@ -52,39 +57,79 @@ AC_SUBST(GETTEXT_PACKAGE) AC_PROG_MKDIR_P AC_PROG_LN_S AC_PROG_SED +AC_PROG_GREP AC_PROG_AWK -AC_PROG_CC AC_PROG_CC_C99 -AM_PROG_CC_C_O -AC_PROG_GCC_TRADITIONAL -AC_CHECK_TOOL(OBJCOPY, objcopy) +AC_PATH_PROG([M4], [m4]) +AC_PATH_PROG([XSLTPROC], [xsltproc]) + +AC_PATH_PROG([QUOTAON], [quotaon], [/usr/sbin/quotaon]) +AC_PATH_PROG([QUOTACHECK], [quotacheck], [/usr/sbin/quotacheck]) + +AC_PATH_PROG([SETCAP], [setcap], [/usr/sbin/setcap]) + +AC_PATH_PROG([KILL], [kill], [/usr/bin/kill]) + +AC_PATH_PROG([KMOD], [kmod], [/usr/bin/kmod]) + +AC_PATH_PROG([KEXEC], [kexec], [/usr/sbin/kexec]) + +M4_DEFINES= + +# gtkdocize greps for '^GTK_DOC_CHECK', so it needs to be on its own line +m4_ifdef([GTK_DOC_CHECK], [ +GTK_DOC_CHECK([1.18],[--flavour no-tmpl])], + [AM_CONDITIONAL([ENABLE_GTK_DOC], [false]) + enable_gtk_doc=no]) + +AS_IF([test "x$enable_gtk_doc" = "xyes" -a "x$XSLTPROC" = x], [ + AC_MSG_ERROR([*** GTK doc requested but xsltproc not found]) +]) + +m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [ +GOBJECT_INTROSPECTION_CHECK([1.31.1]) +], [ + AM_CONDITIONAL([HAVE_INTROSPECTION], [false]) + enable_introspection=no]) + AC_CHECK_TOOL(STRINGS, strings) AC_CHECK_TOOL(GPERF, gperf) if test -z "$GPERF" ; then AC_MSG_ERROR([*** gperf not found]) fi -CC_CHECK_CFLAGS_APPEND([ \ +# ------------------------------------------------------------------------------ +address_sanitizer_cflags= +address_sanitizer_cppflags= +address_sanitizer_ldflags= +AC_ARG_ENABLE(address-sanitizer, AS_HELP_STRING([--enable-address-sanitizer], [enable -fsanitize=address])) +AS_IF([test "x$enable_address_sanitizer" = "xyes"], [ + CC_CHECK_FLAG_APPEND([with_as_cflags], [CFLAGS], [-fsanitize=address]) + AS_IF([test -z "$with_as_cflags"], + [AC_MSG_ERROR([*** -fsanitize=address is not supported])]) + address_sanitizer_cflags="$with_as_cflags -fno-omit-frame-pointer -DVALGRIND=1" + address_sanitizer_cppflags="-DVALGRIND=1" + address_sanitizer_ldflags="-Wc,-fsanitize=address" + ]) + +CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -pipe \ -Wall \ - -W \ -Wextra \ -Wno-inline \ - -Wvla \ -Wundef \ - -Wformat=2 \ + "-Wformat=2 -Wformat-security -Wformat-nonliteral" \ -Wlogical-op \ -Wsign-compare \ - -Wformat-security \ -Wmissing-include-dirs \ - -Wformat-nonliteral \ -Wold-style-definition \ -Wpointer-arith \ -Winit-self \ -Wdeclaration-after-statement \ -Wfloat-equal \ + -Wsuggest-attribute=noreturn \ -Wmissing-prototypes \ -Wstrict-prototypes \ -Wredundant-decls \ @@ -92,7 +137,6 @@ CC_CHECK_CFLAGS_APPEND([ \ -Wmissing-noreturn \ -Wshadow \ -Wendif-labels \ - -Wcast-align \ -Wstrict-aliasing=2 \ -Wwrite-strings \ -Wno-long-long \ @@ -100,55 +144,291 @@ CC_CHECK_CFLAGS_APPEND([ \ -Wno-unused-parameter \ -Wno-missing-field-initializers \ -Wno-unused-result \ - -Wp,-D_FORTIFY_SOURCE=2 \ + -Werror=overflow \ + -Wdate-time \ + -Wnested-externs \ -ffast-math \ -fno-common \ -fdiagnostics-show-option \ + -fdiagnostics-color \ -fno-strict-aliasing \ -fvisibility=hidden \ -ffunction-sections \ -fdata-sections \ + -fstack-protector \ + --param=ssp-buffer-size=4]) +AS_CASE([$CFLAGS], [*-O[[12345\ ]]*], + [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -flto])], + [AC_MSG_RESULT([skipping -flto, optimization not enabled])]) +AC_SUBST([OUR_CFLAGS], "$with_cflags $address_sanitizer_cflags") + +AS_CASE([$CFLAGS], [*-O[[12345\ ]]*], + [CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\ + -Wp,-D_FORTIFY_SOURCE=2])], + [AC_MSG_RESULT([skipping -D_FORTIFY_SOURCE, optimization not enabled])]) +AC_SUBST([OUR_CPPFLAGS], "$with_cppflags $address_sanitizer_cppflags") + +CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\ -Wl,--as-needed \ - -Wl,--gc-sections]) + -Wl,--no-undefined \ + -Wl,--gc-sections \ + -Wl,-z,relro \ + -Wl,-z,now \ + -Wl,-fuse-ld=gold]) +AC_SUBST([OUR_LDFLAGS], "$with_ldflags $address_sanitizer_ldflags") + +AC_CHECK_SIZEOF(pid_t) +AC_CHECK_SIZEOF(uid_t) + +# ------------------------------------------------------------------------------ +# we use python to build the man page index, and for systemd-python +have_python=no +AC_ARG_WITH([python], + [AS_HELP_STRING([--without-python], [Disable building the man page index and systemd-python (default: test)])]) + +have_lxml=no +AS_IF([test "x$with_python" != "xno"], [ + AM_PATH_PYTHON(,, [:]) + AS_IF(["$PYTHON" -c 'import lxml' 2>/dev/null], [have_lxml=yes], [have_lxml=no]) + AS_IF([test "$PYTHON" != : -a $have_lxml = yes], [have_python=yes]) +]) +AM_CONDITIONAL([HAVE_PYTHON], [test "x$have_python" = "xyes"]) +AS_IF([test "x$PYTHON_BINARY" = "x"], + [AS_IF([test "x$have_python" = "xyes"], + [PYTHON_BINARY="$(which "$PYTHON")"], + [PYTHON_BINARY=/usr/bin/python])]) +AC_ARG_VAR(PYTHON_BINARY, [Python binary used to launch installed scripts]) + +AS_IF([test "x$have_python" != "xyes" -a "x$enable_python_devel" = "xyes"], + [AC_MSG_ERROR([*** python-devel support requires --with-python])]) + +have_python_devel=no +AC_ARG_ENABLE(python_devel, AS_HELP_STRING([--disable-python-devel], [Do not build python modules])) +AS_IF([test "x$have_python" = "xyes" -a "x$enable_python_devel" != "xno"], [ + PKG_CHECK_MODULES([PYTHON_DEVEL], [python-${PYTHON_VERSION}], + [have_python_devel=yes], + [PKG_CHECK_MODULES([PYTHON_DEVEL], [python], + [have_python_devel=yes], + [have_python_devel=no])]) + AS_IF([test "x$have_python_devel" = xno -a "x$enable_python_devel" = xyes], + [AC_MSG_ERROR([*** python-devel support requested but libraries not found])]) + AC_PATH_PROGS(SPHINX_BUILD, sphinx-build-${PYTHON_VERSION} sphinx-build) +]) +AM_CONDITIONAL([HAVE_PYTHON_DEVEL], [test "$have_python_devel" = "yes"]) -LT_PREREQ(2.2) -LT_INIT +# ------------------------------------------------------------------------------ -AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([*** POSIX RT library not found])]) AC_SEARCH_LIBS([dlsym], [dl], [], [AC_MSG_ERROR([*** Dynamic linking loader library not found])]) +AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])]) +AC_CHECK_HEADERS([linux/btrfs.h], [], []) + +# unconditionally pull-in librt with old glibc versions +AC_SEARCH_LIBS([clock_gettime], [rt], [], []) save_LIBS="$LIBS" LIBS= AC_SEARCH_LIBS([cap_init], [cap], [], [AC_MSG_ERROR([*** POSIX caps library not found])]) -AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])]) CAP_LIBS="$LIBS" -LIBS="$save_LIBS" AC_SUBST(CAP_LIBS) +LIBS= +AC_SEARCH_LIBS([mq_open], [rt], [], [AC_MSG_ERROR([*** POSIX RT library not found])]) +RT_LIBS="$LIBS" +AC_SUBST(RT_LIBS) +LIBS="$save_LIBS" + +AC_CHECK_FUNCS([fanotify_init fanotify_mark]) +AC_CHECK_FUNCS([__secure_getenv secure_getenv]) +AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns], [], [], [[#include +#include +#include +#include +#include ]]) + # This makes sure pkg.m4 is available. m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config]) -PKG_CHECK_MODULES(UDEV, [ libudev >= 166 ]) -AC_SUBST(UDEV_CFLAGS) -AC_SUBST(UDEV_LIBS) +# ------------------------------------------------------------------------------ +have_dbus=no +AC_ARG_ENABLE(dbus, AS_HELP_STRING([--disable-dbus], [disable usage of dbus-1 in tests])) +AS_IF([test "x$enable_dbus" != "xno"], [ + PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.3.2], + [AC_DEFINE(HAVE_DBUS, 1, [Define if dbus-1 library is available]) have_dbus=yes], + [have_dbus=no]) + AS_IF([test "x$have_dbus" = "xno" -a "x$enable_dbus" = "xyes"], + [AC_MSG_ERROR([*** dbus-1 support requested but libraries not found])])]) +AM_CONDITIONAL(HAVE_DBUS, [test "$have_dbus" = "yes"]) + +# ------------------------------------------------------------------------------ +have_compat_libs=no +AC_ARG_ENABLE([compat_libs], AS_HELP_STRING([--enable-compat-libs],[Enable creation of compatibility libraries]), + [case "${enableval}" in + yes) have_compat_libs=yes ;; + no) have_compat_libs=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-compat-libs) ;; + esac], + [have_compat_libs=no]) +AM_CONDITIONAL([ENABLE_COMPAT_LIBS], [test "$have_compat_libs" = "yes"]) + +# ------------------------------------------------------------------------------ +have_coverage=no +AC_ARG_ENABLE(coverage, AS_HELP_STRING([--enable-coverage], [enable test coverage])) +if test "x$enable_coverage" = "xyes" ; then + AC_CHECK_PROG(lcov_found, [lcov], [yes], [no]) + if test "x$lcov_found" = xno ; then + AC_MSG_ERROR([*** lcov support requested but the program was not found]) + else + lcov_version_major="`lcov --version | cut -d ' ' -f 4 | cut -d '.' -f 1`" + lcov_version_minor="`lcov --version | cut -d ' ' -f 4 | cut -d '.' -f 2`" + if test "$lcov_version_major" -eq 1 -a "$lcov_version_minor" -lt 10; then + AC_MSG_ERROR([*** lcov version is too old. 1.10 required]) + else + have_coverage=yes + CC_CHECK_FLAGS_APPEND([with_coverage_cflags], [CFLAGS], [\ + -fprofile-arcs \ + -ftest-coverage]) + AC_SUBST([OUR_CFLAGS], "$with_cflags $with_coverage_cflags") + fi + fi +fi +AM_CONDITIONAL(ENABLE_COVERAGE, [test "$have_coverage" = "yes"]) + +# ------------------------------------------------------------------------------ +have_kmod=no +AC_ARG_ENABLE(kmod, AS_HELP_STRING([--disable-kmod], [disable loadable modules support])) +if test "x$enable_kmod" != "xno"; then + PKG_CHECK_EXISTS([ libkmod ], have_kmod=yes, have_kmod=no) + if test "x$have_kmod" = "xyes"; then + PKG_CHECK_MODULES(KMOD, [ libkmod >= 15 ], + [AC_DEFINE(HAVE_KMOD, 1, [Define if kmod is available])], + AC_MSG_ERROR([*** kmod version >= 15 not found])) + fi + if test "x$have_kmod" = xno -a "x$enable_kmod" = xyes; then + AC_MSG_ERROR([*** kmod support requested, but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_KMOD, [test "$have_kmod" = "yes"]) + +# ------------------------------------------------------------------------------ +have_blkid=no +AC_ARG_ENABLE(blkid, AS_HELP_STRING([--disable-blkid], [disable blkid support])) +if test "x$enable_blkid" != "xno"; then + PKG_CHECK_MODULES(BLKID, [ blkid >= 2.20 ], + [AC_DEFINE(HAVE_BLKID, 1, [Define if blkid is available]) have_blkid=yes], have_blkid=no) + if test "x$have_blkid" = xno -a "x$enable_blkid" = xyes; then + AC_MSG_ERROR([*** blkid support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_BLKID, [test "$have_blkid" = "yes"]) + +# ------------------------------------------------------------------------------ +have_seccomp=no +AC_ARG_ENABLE(seccomp, AS_HELP_STRING([--disable-seccomp], [Disable optional SECCOMP support])) +if test "x$enable_seccomp" != "xno"; then + PKG_CHECK_MODULES(SECCOMP, [libseccomp >= 1.0.0], + [AC_DEFINE(HAVE_SECCOMP, 1, [Define if seccomp is available]) + have_seccomp=yes + M4_DEFINES="$M4_DEFINES -DHAVE_SECCOMP"], + [have_seccomp=no]) + if test "x$have_seccomp" = "xno" -a "x$enable_seccomp" = "xyes"; then + AC_MSG_ERROR([*** seccomp support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_SECCOMP, [test "$have_seccomp" = "yes"]) + +# ------------------------------------------------------------------------------ +have_ima=yes +AC_ARG_ENABLE([ima], AS_HELP_STRING([--disable-ima],[Disable optional IMA support]), + [case "${enableval}" in + yes) have_ima=yes ;; + no) have_ima=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-ima) ;; + esac], + [have_ima=yes]) + +if test "x${have_ima}" != xno ; then + AC_DEFINE(HAVE_IMA, 1, [Define if IMA is available]) +fi + +# ------------------------------------------------------------------------------ +have_chkconfig=yes +AC_ARG_ENABLE([chkconfig], AS_HELP_STRING([--disable-chkconfig],[Disable optional chkconfig support]), + [case "${enableval}" in + yes) have_chkconfig=yes ;; + no) have_chkconfig=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-chkconfig) ;; + esac], + [AC_PATH_PROG(CHKCONFIG, chkconfig) + if test -z "$CHKCONFIG"; then + have_chkconfig=no + else + have_chkconfig=yes + fi]) -PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.3.2 ]) -AC_SUBST(DBUS_CFLAGS) -AC_SUBST(DBUS_LIBS) +if test "x${have_chkconfig}" != xno ; then + AC_DEFINE(HAVE_CHKCONFIG, 1, [Define if CHKCONFIG is available]) +fi +# ------------------------------------------------------------------------------ have_selinux=no AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support])) if test "x$enable_selinux" != "xno"; then - PKG_CHECK_MODULES(SELINUX, [ libselinux ], - [AC_DEFINE(HAVE_SELINUX, 1, [Define if SELinux is available]) have_selinux=yes], have_selinux=no) - AC_SUBST(SELINUX_CFLAGS) - AC_SUBST(SELINUX_LIBS) + PKG_CHECK_MODULES([SELINUX], [libselinux >= 2.1.9], + [AC_DEFINE(HAVE_SELINUX, 1, [Define if SELinux is available]) + have_selinux=yes + M4_DEFINES="$M4_DEFINES -DHAVE_SELINUX"], + [have_selinux=no]) if test "x$have_selinux" = xno -a "x$enable_selinux" = xyes; then AC_MSG_ERROR([*** SELinux support requested but libraries not found]) fi fi AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"]) +have_apparmor=no +AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--disable-apparmor], [Disable optional AppArmor support])) +if test "x$enable_apparmor" != "xno"; then + PKG_CHECK_MODULES([APPARMOR], [libapparmor], + [AC_DEFINE(HAVE_APPARMOR, 1, [Define if AppArmor is available]) + have_apparmor=yes + M4_DEFINES="$M4_DEFINES -DHAVE_APPARMOR"], + [have_apparmor=no]) + if test "x$have_apparmor" = xno -a "x$enable_apparmor" = xyes; then + AC_MSG_ERROR([*** AppArmor support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"]) + + +AC_ARG_WITH(debug-shell, + AS_HELP_STRING([--with-debug-shell=PATH], + [Path to debug shell binary]), + [SUSHELL="$withval"],[ + AS_IF([test "x${have_selinux}" != "xno"], [SUSHELL="/sbin/sushell"] , [SUSHELL="/bin/sh"])]) + +AC_SUBST(SUSHELL) + +AC_ARG_WITH([debug-tty], + AS_HELP_STRING([--with-debug-tty=PATH], + [Specify the tty device for debug shell]), + [DEBUGTTY="$withval"], + [DEBUGTTY=/dev/tty9]) + +AC_SUBST(DEBUGTTY) + +# ------------------------------------------------------------------------------ +have_xz=no +AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support])) +if test "x$enable_xz" != "xno"; then + PKG_CHECK_MODULES(XZ, [ liblzma ], + [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available]) have_xz=yes], have_xz=no) + if test "x$have_xz" = xno -a "x$enable_xz" = xyes; then + AC_MSG_ERROR([*** Xz support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_XZ, [test "$have_xz" = "yes"]) + +# ------------------------------------------------------------------------------ AC_ARG_ENABLE([tcpwrap], AS_HELP_STRING([--disable-tcpwrap],[Disable optional TCP wrappers support]), [case "${enableval}" in @@ -166,6 +446,7 @@ if test "x${have_tcpwrap}" != xno ; then fi have_tcpwrap=no else + M4_DEFINES="$M4_DEFINES -DHAVE_LIBWRAP" have_tcpwrap=yes fi else @@ -173,6 +454,7 @@ else fi AC_SUBST(LIBWRAP_LIBS) +# ------------------------------------------------------------------------------ AC_ARG_ENABLE([pam], AS_HELP_STRING([--disable-pam],[Disable optional PAM support]), [case "${enableval}" in @@ -201,6 +483,7 @@ if test "x${have_pam}" != xno ; then if test "x$have_pam" = xyes ; then PAM_LIBS="-lpam -lpam_misc" AC_DEFINE(HAVE_PAM, 1, [PAM available]) + M4_DEFINES="$M4_DEFINES -DHAVE_PAM" else have_pam=no fi @@ -210,6 +493,7 @@ fi AC_SUBST(PAM_LIBS) AM_CONDITIONAL([HAVE_PAM], [test "x$have_pam" != xno]) +# ------------------------------------------------------------------------------ AC_ARG_ENABLE([acl], AS_HELP_STRING([--disable-acl],[Disable optional ACL support]), [case "${enableval}" in @@ -247,6 +531,110 @@ fi AC_SUBST(ACL_LIBS) AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno]) +# ------------------------------------------------------------------------------ +AC_ARG_ENABLE([xattr], + AS_HELP_STRING([--disable-xattr],[Disable optional XATTR support]), + [case "${enableval}" in + yes) have_xattr=yes ;; + no) have_xattr=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-xattr) ;; + esac], + [have_xattr=auto]) + +if test "x${have_xattr}" != xno ; then + AC_CHECK_HEADERS( + [attr/xattr.h], + [have_xattr=yes], + [if test "x$have_xattr" = xyes ; then + AC_MSG_ERROR([*** XATTR headers not found.]) + fi]) + + AC_CHECK_LIB( + [attr], + [fsetxattr], + [have_xattr=yes], + [if test "x$have_xattr" = xyes ; then + AC_MSG_ERROR([*** libattr not found.]) + fi]) + + if test "x$have_xattr" = xyes ; then + XATTR_LIBS="-lattr" + AC_DEFINE(HAVE_XATTR, 1, [XATTR available]) + else + have_xattr=no + fi +else + XATTR_LIBS= +fi +AC_SUBST(XATTR_LIBS) +AM_CONDITIONAL([HAVE_XATTR], [test "x$have_xattr" != xno]) + +# ------------------------------------------------------------------------------ +AC_ARG_ENABLE([smack], AS_HELP_STRING([--disable-smack],[Disable optional SMACK support]), + [case "${enableval}" in + yes) have_smack=yes ;; + no) have_smack=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-smack) ;; + esac], + [have_smack=auto]) + +if test "x${have_xattr}" = xno; then + if test "x${have_smack}" = xyes; then + AC_MSG_ERROR(SMACK requires xattr support) + else + have_smack=no + fi +else + if test "x${have_smack}" = xauto; then + M4_DEFINES="$M4_DEFINES -DHAVE_SMACK" + have_smack=yes + fi +fi + +AC_ARG_WITH(smack-run-label, +AS_HELP_STRING([--with-smack-run-label=STRING], + [run systemd --system with a specific SMACK label]), + [AC_DEFINE_UNQUOTED(SMACK_RUN_LABEL, ["$withval"], [Run with a smack label])], + []) + +if test "x${have_smack}" = xyes ; then + AC_DEFINE(HAVE_SMACK, 1, [Define if SMACK is available]) +fi + +# ------------------------------------------------------------------------------ +AC_ARG_ENABLE([gcrypt], + AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]), + [case "${enableval}" in + yes) have_gcrypt=yes ;; + no) have_gcrypt=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-gcrypt) ;; + esac], + [have_gcrypt=auto]) + +if test "x${have_gcrypt}" != xno ; then + AM_PATH_LIBGCRYPT( + [1.4.5], + [have_gcrypt=yes], + [if test "x$have_gcrypt" = xyes ; then + AC_MSG_ERROR([*** GCRYPT headers not found.]) + fi]) + + if test "x$have_gcrypt" = xyes ; then + GCRYPT_LIBS="$LIBGCRYPT_LIBS" + GCRYPT_CFLAGS="$LIBGCRYPT_CFLAGS" + AC_DEFINE(HAVE_GCRYPT, 1, [GCRYPT available]) + else + have_gcrypt=no + fi +else + GCRYPT_LIBS= + GCRYPT_CFLAGS= +fi +AC_SUBST(GCRYPT_LIBS) +AC_SUBST(GCRYPT_CFLAGS) +AM_CONDITIONAL([HAVE_GCRYPT], [test "x$have_gcrypt" != xno]) + +# ------------------------------------------------------------------------------ AC_ARG_ENABLE([audit], AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]), [case "${enableval}" in @@ -283,333 +671,530 @@ else fi AC_SUBST(AUDIT_LIBS) +# ------------------------------------------------------------------------------ have_libcryptsetup=no AC_ARG_ENABLE(libcryptsetup, AS_HELP_STRING([--disable-libcryptsetup], [disable libcryptsetup tools])) if test "x$enable_libcryptsetup" != "xno"; then - PKG_CHECK_MODULES(LIBCRYPTSETUP, [ libcryptsetup ], + PKG_CHECK_MODULES(LIBCRYPTSETUP, [ libcryptsetup >= 1.6.0 ], [AC_DEFINE(HAVE_LIBCRYPTSETUP, 1, [Define if libcryptsetup is available]) have_libcryptsetup=yes], have_libcryptsetup=no) - AC_SUBST(LIBCRYPTSETUP_CFLAGS) - AC_SUBST(LIBCRYPTSETUP_LIBS) if test "x$have_libcryptsetup" = xno -a "x$enable_libcryptsetup" = xyes; then AC_MSG_ERROR([*** libcryptsetup support requested but libraries not found]) fi fi AM_CONDITIONAL(HAVE_LIBCRYPTSETUP, [test "$have_libcryptsetup" = "yes"]) +# ------------------------------------------------------------------------------ +have_qrencode=no +AC_ARG_ENABLE(qrencode, AS_HELP_STRING([--disable-qrencode], [disable qrencode support])) +if test "x$enable_qrencode" != "xno"; then + PKG_CHECK_MODULES(QRENCODE, [ libqrencode ], + [AC_DEFINE(HAVE_QRENCODE, 1, [Define if qrencode is available]) have_qrencode=yes], have_qrencode=no) + if test "x$have_qrencode" = xno -a "x$enable_qrencode" = xyes; then + AC_MSG_ERROR([*** qrencode support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_QRENCODE, [test "$have_qrencode" = "yes"]) + +# ------------------------------------------------------------------------------ +have_microhttpd=no +AC_ARG_ENABLE(microhttpd, AS_HELP_STRING([--disable-microhttpd], [disable microhttpd support])) +if test "x$enable_microhttpd" != "xno"; then + PKG_CHECK_MODULES(MICROHTTPD, [libmicrohttpd >= 0.9.5], + [AC_DEFINE(HAVE_MICROHTTPD, 1, [Define if microhttpd is available]) have_microhttpd=yes], have_microhttpd=no) + if test "x$have_microhttpd" = xno -a "x$enable_microhttpd" = xyes; then + AC_MSG_ERROR([*** microhttpd support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_MICROHTTPD, [test "$have_microhttpd" = "yes"]) + +# ------------------------------------------------------------------------------ have_binfmt=no AC_ARG_ENABLE(binfmt, AS_HELP_STRING([--disable-binfmt], [disable binfmt tool])) if test "x$enable_binfmt" != "xno"; then - have_binfmt=yes + have_binfmt=yes fi AM_CONDITIONAL(ENABLE_BINFMT, [test "$have_binfmt" = "yes"]) +# ------------------------------------------------------------------------------ +have_vconsole=no +AC_ARG_ENABLE(vconsole, AS_HELP_STRING([--disable-vconsole], [disable vconsole tool])) +if test "x$enable_vconsole" != "xno"; then + have_vconsole=yes +fi +AM_CONDITIONAL(ENABLE_VCONSOLE, [test "$have_vconsole" = "yes"]) + +# ------------------------------------------------------------------------------ +have_readahead=no +AC_ARG_ENABLE(readahead, AS_HELP_STRING([--disable-readahead], [disable readahead tools])) +if test "x$enable_readahead" != "xno"; then + have_readahead=yes +fi +AM_CONDITIONAL(ENABLE_READAHEAD, [test "$have_readahead" = "yes"]) + +# ------------------------------------------------------------------------------ +have_bootchart=no +AC_ARG_ENABLE(bootchart, AS_HELP_STRING([--disable-bootchart], [disable bootchart tool])) +if test "x$enable_bootchart" != "xno"; then + have_bootchart=yes +fi +AM_CONDITIONAL(ENABLE_BOOTCHART, [test "$have_bootchart" = "yes"]) + +# ------------------------------------------------------------------------------ +have_quotacheck=no +AC_ARG_ENABLE(quotacheck, AS_HELP_STRING([--disable-quotacheck], [disable quotacheck tools])) +if test "x$enable_quotacheck" != "xno"; then + have_quotacheck=yes +fi +AM_CONDITIONAL(ENABLE_QUOTACHECK, [test "$have_quotacheck" = "yes"]) + +# ------------------------------------------------------------------------------ +have_tmpfiles=no +AC_ARG_ENABLE(tmpfiles, AS_HELP_STRING([--disable-tmpfiles], [disable tmpfiles support])) +if test "x$enable_tmpfiles" != "xno"; then + have_tmpfiles=yes +fi +AM_CONDITIONAL(ENABLE_TMPFILES, [test "$have_tmpfiles" = "yes"]) + +# ------------------------------------------------------------------------------ +have_randomseed=no +AC_ARG_ENABLE(randomseed, AS_HELP_STRING([--disable-randomseed], [disable randomseed tools])) +if test "x$enable_randomseed" != "xno"; then + have_randomseed=yes +fi +AM_CONDITIONAL(ENABLE_RANDOMSEED, [test "$have_randomseed" = "yes"]) + +# ------------------------------------------------------------------------------ +have_backlight=no +AC_ARG_ENABLE(backlight, AS_HELP_STRING([--disable-backlight], [disable backlight tools])) +if test "x$enable_backlight" != "xno"; then + have_backlight=yes +fi +AM_CONDITIONAL(ENABLE_BACKLIGHT, [test "$have_backlight" = "yes"]) + +# ------------------------------------------------------------------------------ +have_rfkill=no +AC_ARG_ENABLE(rfkill, AS_HELP_STRING([--disable-rfkill], [disable rfkill tools])) +if test "x$enable_rfkill" != "xno"; then + have_rfkill=yes +fi +AM_CONDITIONAL(ENABLE_RFKILL, [test "$have_rfkill" = "yes"]) + +# ------------------------------------------------------------------------------ +have_logind=no +AC_ARG_ENABLE(logind, AS_HELP_STRING([--disable-logind], [disable login daemon])) +if test "x$enable_logind" != "xno"; then + have_logind=yes +fi +AM_CONDITIONAL(ENABLE_LOGIND, [test "$have_logind" = "yes"]) +AS_IF([test "$have_logind" = "yes"], [ AC_DEFINE(HAVE_LOGIND, [1], [Logind support available]) ]) + +# ------------------------------------------------------------------------------ +have_machined=no +AC_ARG_ENABLE(machined, AS_HELP_STRING([--disable-machined], [disable machine daemon])) +if test "x$enable_machined" != "xno"; then + have_machined=yes +fi +AM_CONDITIONAL(ENABLE_MACHINED, [test "$have_machined" = "yes"]) +AS_IF([test "$have_machined" = "yes"], [ AC_DEFINE(HAVE_MACHINED, [1], [Machined support available]) ]) + +# ------------------------------------------------------------------------------ have_hostnamed=no AC_ARG_ENABLE(hostnamed, AS_HELP_STRING([--disable-hostnamed], [disable hostname daemon])) if test "x$enable_hostnamed" != "xno"; then - have_hostnamed=yes + have_hostnamed=yes fi AM_CONDITIONAL(ENABLE_HOSTNAMED, [test "$have_hostnamed" = "yes"]) +# ------------------------------------------------------------------------------ have_timedated=no AC_ARG_ENABLE(timedated, AS_HELP_STRING([--disable-timedated], [disable timedate daemon])) if test "x$enable_timedated" != "xno"; then - have_timedated=yes + have_timedated=yes fi AM_CONDITIONAL(ENABLE_TIMEDATED, [test "$have_timedated" = "yes"]) +# ------------------------------------------------------------------------------ have_localed=no AC_ARG_ENABLE(localed, AS_HELP_STRING([--disable-localed], [disable locale daemon])) if test "x$enable_localed" != "xno"; then - have_localed=yes + have_localed=yes fi AM_CONDITIONAL(ENABLE_LOCALED, [test "$have_localed" = "yes"]) -have_gtk=no -AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools])) -if test "x$enable_gtk" != "xno"; then - PKG_CHECK_MODULES(GTK, [ gtk+-2.0 glib-2.0 > 2.26 gio-unix-2.0 ], - [AC_DEFINE(HAVE_GTK, 1, [Define if GTK is available]) have_gtk=yes], have_gtk=no) - AC_SUBST(GTK_CFLAGS) - AC_SUBST(GTK_LIBS) - if test "x$have_gtk" = xno -a "x$enable_gtk" = xyes; then - AC_MSG_ERROR([*** gtk support requested but libraries not found]) - fi +# ------------------------------------------------------------------------------ +have_coredump=no +AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook])) +if test "x$enable_coredump" != "xno"; then + have_coredump=yes fi -AM_CONDITIONAL(HAVE_GTK, [test "$have_gtk" = "yes"]) - -if test "$have_gtk" = "yes"; then - PKG_CHECK_MODULES(LIBNOTIFY, [ libnotify ]) - PKG_CHECK_EXISTS([ libnotify >= 0.7.0 ], [ libnotify07=yes ]) - - AC_SUBST(LIBNOTIFY_CFLAGS) - AC_SUBST(LIBNOTIFY_LIBS) +AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"]) + +# ------------------------------------------------------------------------------ +have_polkit=no +AC_ARG_ENABLE(polkit, AS_HELP_STRING([--disable-polkit], [disable PolicyKit support])) +if test "x$enable_polkit" != "xno"; then + AC_DEFINE(ENABLE_POLKIT, 1, [Define if PolicyKit support is to be enabled]) + have_polkit=yes fi -AM_CONDITIONAL(LIBNOTIFY07, [ test "$libnotify07" = "yes" ]) +AM_CONDITIONAL(ENABLE_POLKIT, [test "x$have_polkit" = "xyes"]) -AM_PROG_VALAC([0.10]) -AC_SUBST(VAPIDIR) -AM_CONDITIONAL(HAVE_VALAC, test x"$VALAC" != x) - -AC_ARG_ENABLE([docs], - [AS_HELP_STRING([--disable-docs], - [Disable documentation building])], - [XSLTPROC=], - [AC_PATH_PROG([XSLTPROC], [xsltproc])]) -AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC" != x) - -AC_PATH_PROG([M4], [m4]) +# ------------------------------------------------------------------------------ +AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd])) +if test "x$enable_networkd" != "xno"; then + AC_DEFINE(ENABLE_NETWORKD, 1, [Define if networkd support is to be enabled]) + have_networkd=yes +fi +AM_CONDITIONAL(ENABLE_NETWORKD, [test "x$have_networkd" = "xyes"]) + +# ------------------------------------------------------------------------------ +have_efi=no +AC_ARG_ENABLE(efi, AS_HELP_STRING([--disable-efi], [disable EFI support])) +if test "x$enable_efi" != "xno"; then + AC_DEFINE(ENABLE_EFI, 1, [Define if EFI support is to be enabled]) + have_efi=yes +fi +AM_CONDITIONAL(ENABLE_EFI, [test "x$have_efi" = "xyes"]) -AC_ARG_WITH(distro, AS_HELP_STRING([--with-distro=DISTRO],[Specify the distribution to target: One of fedora, suse, debian, ubuntu, arch, gentoo, slackware, altlinux or other])) -if test "z$with_distro" = "z"; then - if test "$cross_compiling" = yes; then - AC_MSG_WARN([Target distribution cannot be reliably detected when cross-compiling. You should specify it with --with-distro (see $0 --help for recognized distros)]) - else - test -f "/etc/redhat-release" && with_distro="fedora" - test -f "/etc/SuSE-release" && with_distro="suse" - test -f "/etc/debian_version" && with_distro="debian" - test -f "/etc/arch-release" && with_distro="arch" - test -f "/etc/gentoo-release" && with_distro="gentoo" - test -f "/etc/slackware-version" && with_distro="slackware" - test -f "/etc/frugalware-release" && with_distro="frugalware" - test -f "/etc/altlinux-release" && with_distro="altlinux" - test -f "/etc/mandriva-release" && with_distro="mandriva" - test -f "/etc/meego-release" && with_distro="meego" - test -f "/etc/angstrom-version" && with_distro="angstrom" - if test "x`lsb_release -is 2>/dev/null`" = "xUbuntu"; then - with_distro="ubuntu" - fi - fi - if test "z$with_distro" = "z"; then - with_distro=`uname -s` - fi +# ------------------------------------------------------------------------------ +have_multi_seat_x=no +AC_ARG_ENABLE(multi_seat_x, AS_HELP_STRING([--disable-multi-seat-x], [do not build multi-seat-x])) +if test "x$enable_multi_seat_x" != "xno"; then + have_multi_seat_x=yes +fi +AM_CONDITIONAL(ENABLE_MULTI_SEAT_X, [test "$have_multi_seat_x" = "yes"]) + +# ------------------------------------------------------------------------------ +have_kdbus=no +AC_ARG_ENABLE(kdbus, AS_HELP_STRING([--enable-kdbus], [do connect to kdbus by default])) +if test "x$enable_kdbus" = "xyes"; then + AC_DEFINE(ENABLE_KDBUS, 1, [Define if kdbus support is to be enabled]) + have_kdbus=yes + M4_DEFINES="$M4_DEFINES -DENABLE_KDBUS" +fi +AM_CONDITIONAL(ENABLE_KDBUS, [test "$have_kdbus" = "yes"]) + +# ------------------------------------------------------------------------------ +AC_ARG_WITH(rc-local-script-path-start, + AS_HELP_STRING([--with-rc-local-script-path-start=PATH], + [Path to /etc/rc.local]), + [RC_LOCAL_SCRIPT_PATH_START="$withval"], + [RC_LOCAL_SCRIPT_PATH_START="/etc/rc.local"]) + +AC_ARG_WITH(rc-local-script-path-stop, + AS_HELP_STRING([--with-rc-local-script-path-stop=PATH], + [Path to /usr/sbin/halt.local]), + [RC_LOCAL_SCRIPT_PATH_STOP="$withval"], + [RC_LOCAL_SCRIPT_PATH_STOP="/usr/sbin/halt.local"]) + +AC_DEFINE_UNQUOTED(RC_LOCAL_SCRIPT_PATH_START, ["$RC_LOCAL_SCRIPT_PATH_START"], [Path of /etc/rc.local script]) +AC_DEFINE_UNQUOTED(RC_LOCAL_SCRIPT_PATH_STOP, ["$RC_LOCAL_SCRIPT_PATH_STOP"], [Path of /usr/sbin/halt.local script]) + +AC_SUBST(RC_LOCAL_SCRIPT_PATH_START) +AC_SUBST(RC_LOCAL_SCRIPT_PATH_STOP) + +# ------------------------------------------------------------------------------ +AC_ARG_WITH(kbd-loadkeys, + AS_HELP_STRING([--with-kbd-loadkeys=PATH], + [Path to loadkeys]), + [KBD_LOADKEYS="$withval"], + [KBD_LOADKEYS="/usr/bin/loadkeys"]) + +AC_ARG_WITH(kbd-setfont, + AS_HELP_STRING([--with-kbd-setfont=PATH], + [Path to setfont]), + [KBD_SETFONT="$withval"], + [KBD_SETFONT="/usr/bin/setfont"]) + +AC_DEFINE_UNQUOTED(KBD_LOADKEYS, ["$KBD_LOADKEYS"], [Path of loadkeys]) +AC_DEFINE_UNQUOTED(KBD_SETFONT, ["$KBD_SETFONT"], [Path of setfont]) + +AC_SUBST(KBD_LOADKEYS) +AC_SUBST(KBD_SETFONT) + +AC_ARG_WITH(telinit, + AS_HELP_STRING([--with-telinit=PATH], + [Path to telinit]), + [TELINIT="$withval"], + [TELINIT="/lib/sysvinit/telinit"]) + +AC_DEFINE_UNQUOTED(TELINIT, ["$TELINIT"], [Path to telinit]) + +AC_SUBST(TELINIT) + +AC_CHECK_HEADERS_ONCE([valgrind/memcheck.h valgrind/valgrind.h]) + +# ------------------------------------------------------------------------------ +have_myhostname=no +AC_ARG_ENABLE(myhostname, AS_HELP_STRING([--disable-myhostname], [disable nss-myhostname support])) +if test "x$enable_myhostname" != "xno"; then + AC_HEADER_STDC + AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h nss.h sys/ioctl.h sys/auxv.h]) + + AC_C_CONST + AC_TYPE_SIZE_T + AC_HEADER_TIME + + AC_FUNC_MALLOC + AC_FUNC_SELECT_ARGTYPES + AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn]) + + have_myhostname=yes fi -with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]' ` -AC_DEFINE_UNQUOTED(DISTRIBUTION, ["${with_distro}"], [Target Distribution]) +AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"]) + +# ------------------------------------------------------------------------------ +AC_ARG_WITH(firmware-path, + AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]], + [Firmware search path (default="")]), + [], [with_firmware_path=""]) +OLD_IFS=$IFS +IFS=: +for i in $with_firmware_path; do + if test "x${FIRMWARE_PATH}" = "x"; then + FIRMWARE_PATH="\\\"${i}/\\\"" + else + FIRMWARE_PATH="${FIRMWARE_PATH}, \\\"${i}/\\\"" + fi +done +IFS=$OLD_IFS +AC_SUBST(FIRMWARE_PATH) +AS_IF([test "x${FIRMWARE_PATH}" != "x"], [ AC_DEFINE(HAVE_FIRMWARE, 1, [Define if FIRMWARE is available]) ]) +AM_CONDITIONAL(ENABLE_FIRMWARE, [test "x${FIRMWARE_PATH}" != "x"]) + +# ------------------------------------------------------------------------------ +AC_ARG_ENABLE([gudev], + AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]), + [], [enable_gudev=yes]) +AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 gio-2.0]) ]) +AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"]) +AS_IF([test "x$enable_gudev" = "xyes"], [ AC_DEFINE(HAVE_GLIB, 1, [Define if glib is available]) ]) + +# ------------------------------------------------------------------------------ +have_manpages=no +AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages])) +AS_IF([test "x$enable_manpages" != xno], [have_manpages=yes]) +AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"]) + +# ------------------------------------------------------------------------------ # Location of the init scripts as mandated by LSB SYSTEM_SYSVINIT_PATH=/etc/init.d SYSTEM_SYSVRCND_PATH=/etc/rc.d -M4_DEFINES= -have_plymouth=no - -case $with_distro in - fedora) - SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d - AC_DEFINE(TARGET_FEDORA, [], [Target is Fedora/RHEL]) - M4_DEFINES=-DTARGET_FEDORA=1 - have_plymouth=yes - ;; - suse) - SYSTEM_SYSVRCND_PATH=/etc/init.d - AC_DEFINE(TARGET_SUSE, [], [Target is openSUSE/SLE]) - M4_DEFINES=-DTARGET_SUSE=1 - have_plymouth=yes - ;; - debian) - SYSTEM_SYSVRCND_PATH=/etc - AC_DEFINE(TARGET_DEBIAN, [], [Target is Debian]) - M4_DEFINES=-DTARGET_DEBIAN=1 - ;; - ubuntu) - SYSTEM_SYSVRCND_PATH=/etc - AC_DEFINE(TARGET_UBUNTU, [], [Target is Ubuntu]) - M4_DEFINES=-DTARGET_UBUNTU=1 - ;; - arch) - SYSTEM_SYSVINIT_PATH=/etc/rc.d - SYSTEM_SYSVRCND_PATH=/etc - AC_DEFINE(TARGET_ARCH, [], [Target is ArchLinux]) - M4_DEFINES=-DTARGET_ARCH=1 - ;; - gentoo) - SYSTEM_SYSVINIT_PATH= - SYSTEM_SYSVRCND_PATH= - AC_DEFINE(TARGET_GENTOO, [], [Target is Gentoo]) - M4_DEFINES=-DTARGET_GENTOO=1 - ;; - slackware) - SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d - AC_DEFINE(TARGET_SLACKWARE, [], [Target is Slackware]) - M4_DEFINES=-DTARGET_SLACKWARE=1 - ;; - frugalware) - SYSTEM_SYSVINIT_PATH=/etc/rc.d - AC_DEFINE(TARGET_FRUGALWARE, [], [Target is Frugalware]) - M4_DEFINES=-DTARGET_FRUGALWARE=1 - have_plymouth=yes - ;; - altlinux) - SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d - AC_DEFINE(TARGET_ALTLINUX, [], [Target is ALTLinux]) - M4_DEFINES=-DTARGET_ALTLINUX=1 - have_plymouth=yes - ;; - slp) - SYSTEM_SYSVINIT_PATH= - SYSTEM_SYSVRCND_PATH= - SPECIAL_SYSLOG_SERVICE=syslog.service - AC_DEFINE(TARGET_SLP, [], [Target is SLP]) - M4_DEFINES=-DTARGET_SLP=1 - ;; - - mandriva) - SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d - AC_DEFINE(TARGET_MANDRIVA, [], [Target is Mandriva]) - M4_DEFINES=-DTARGET_MANDRIVA=1 - have_plymouth=yes - ;; - meego) - SYSTEM_SYSVINIT_PATH= - SYSTEM_SYSVRCND_PATH= - AC_DEFINE(TARGET_MEEGO, [], [Target is MeeGo]) - M4_DEFINES=-DTARGET_MEEGO=1 - ;; - angstrom) - SYSTEM_SYSVRCND_PATH=/etc - AC_DEFINE(TARGET_ANGSTROM, [], [Target is Ångström]) - M4_DEFINES=-DTARGET_ANGSTROM=1 - ;; - other) - ;; - *) - AC_MSG_ERROR([Your distribution (${with_distro}) is not yet supported, SysV init scripts could not be found! (patches welcome); you can specify --with-distro=other to skip this check]) - ;; -esac - AC_ARG_WITH([sysvinit-path], - [AS_HELP_STRING([--with-sysvinit-path=PATH], - [Specify the path to where the SysV init scripts are located @<:@default=based on distro@:>@])], - [SYSTEM_SYSVINIT_PATH="$withval"], - []) - -AC_ARG_WITH([sysvrcd-path], - [AS_HELP_STRING([--with-sysvrcd-path=PATH], - [Specify the path to the base directory for the SysV rcN.d directories @<:@default=based on distro@:>@])], - [SYSTEM_SYSVRCND_PATH="$withval"], + [AS_HELP_STRING([--with-sysvinit-path=PATH], + [Specify the path to where the SysV init scripts are located])], + [SYSTEM_SYSVINIT_PATH="$withval"], []) -AC_SUBST(SYSTEM_SYSVINIT_PATH) -AC_SUBST(SYSTEM_SYSVRCND_PATH) -AC_SUBST(M4_DEFINES) +AC_ARG_WITH([sysvrcnd-path], + [AS_HELP_STRING([--with-sysvrcnd-path=PATH], + [Specify the path to the base directory for the SysV rcN.d directories])], + [SYSTEM_SYSVRCND_PATH="$withval"], + []) if test "x${SYSTEM_SYSVINIT_PATH}" != "x" -a "x${SYSTEM_SYSVRCND_PATH}" != "x"; then AC_DEFINE(HAVE_SYSV_COMPAT, [], [SysV init scripts and rcN.d links are supported.]) SYSTEM_SYSV_COMPAT="yes" M4_DEFINES="$M4_DEFINES -DHAVE_SYSV_COMPAT" elif test "x${SYSTEM_SYSVINIT_PATH}" != "x" -o "x${SYSTEM_SYSVRCND_PATH}" != "x"; then - AC_MSG_ERROR([*** You need both --with-sysvinit-path=PATH and --with-sysvrcd-path=PATH to enable SysV compatibility support, or both empty to disable it.]) + AC_MSG_ERROR([*** You need both --with-sysvinit-path=PATH and --with-sysvrcnd-path=PATH to enable SysV compatibility support, or both empty to disable it.]) else SYSTEM_SYSV_COMPAT="no" fi +AC_SUBST(SYSTEM_SYSVINIT_PATH) +AC_SUBST(SYSTEM_SYSVRCND_PATH) +AC_SUBST(M4_DEFINES) + +AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes") + AC_ARG_WITH([tty-gid], [AS_HELP_STRING([--with-tty-gid=GID], [Specify the numeric GID of the 'tty' group])], [AC_DEFINE_UNQUOTED(TTY_GID, [$withval], [GID of the 'tty' group])], []) -AC_ARG_ENABLE(plymouth, AS_HELP_STRING([--enable-plymouth], [enable plymouth support])) -if test -n "$enable_plymouth"; then - have_plymouth="$enable_plymouth" -fi - -AM_CONDITIONAL(TARGET_FEDORA, test x"$with_distro" = xfedora) -AM_CONDITIONAL(TARGET_SUSE, test x"$with_distro" = xsuse) -AM_CONDITIONAL(TARGET_DEBIAN, test x"$with_distro" = xdebian) -AM_CONDITIONAL(TARGET_UBUNTU, test x"$with_distro" = xubuntu) -AM_CONDITIONAL(TARGET_DEBIAN_OR_UBUNTU, test x"$with_distro" = xdebian -o x"$with_distro" = xubuntu) -AM_CONDITIONAL(TARGET_ARCH, test x"$with_distro" = xarch) -AM_CONDITIONAL(TARGET_GENTOO, test x"$with_distro" = xgentoo) -AM_CONDITIONAL(TARGET_SLACKWARE, test x"$with_distro" = xslackware) -AM_CONDITIONAL(TARGET_FRUGALWARE, test x"$with_distro" = xfrugalware) -AM_CONDITIONAL(TARGET_ALTLINUX, test x"$with_distro" = xaltlinux) -AM_CONDITIONAL(TARGET_SLP, test x"$with_distro" = xslp) -AM_CONDITIONAL(TARGET_MANDRIVA, test x"$with_distro" = xmandriva) -AM_CONDITIONAL(TARGET_MEEGO, test x"$with_distro" = xmeego) -AM_CONDITIONAL(TARGET_ANGSTROM, test x"$with_distro" = xangstrom) - -AM_CONDITIONAL(HAVE_PLYMOUTH, test "$have_plymouth" = "yes") -AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes") - AC_ARG_WITH([dbuspolicydir], AS_HELP_STRING([--with-dbuspolicydir=DIR], [D-Bus policy directory]), [], - [with_dbuspolicydir=`pkg-config --variable=sysconfdir dbus-1`/dbus-1/system.d]) + [with_dbuspolicydir=$($PKG_CONFIG --variable=sysconfdir dbus-1)/dbus-1/system.d]) AC_ARG_WITH([dbussessionservicedir], AS_HELP_STRING([--with-dbussessionservicedir=DIR], [D-Bus session service directory]), [], - [with_dbussessionservicedir=`pkg-config --variable=session_bus_services_dir dbus-1`]) + [with_dbussessionservicedir=$($PKG_CONFIG --variable=session_bus_services_dir dbus-1)]) AC_ARG_WITH([dbussystemservicedir], AS_HELP_STRING([--with-dbussystemservicedir=DIR], [D-Bus system service directory]), [], - [with_dbussystemservicedir=`pkg-config --variable=session_bus_services_dir dbus-1`/../system-services]) + [with_dbussystemservicedir=$(readlink -m $($PKG_CONFIG --variable=session_bus_services_dir dbus-1)/../system-services)]) AC_ARG_WITH([dbusinterfacedir], AS_HELP_STRING([--with-dbusinterfacedir=DIR], [D-Bus interface directory]), [], - [with_dbusinterfacedir=`pkg-config --variable=session_bus_services_dir dbus-1`/../interfaces]) + [with_dbusinterfacedir=$(readlink -m $($PKG_CONFIG --variable=session_bus_services_dir dbus-1)/../interfaces)]) -AC_ARG_WITH([udevrulesdir], - AS_HELP_STRING([--with-udevrulesdir=DIR], [Diectory for udev rules]), +AC_ARG_WITH([bashcompletiondir], + AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]), [], - [with_udevrulesdir=`pkg-config --variable=udevdir udev`/rules.d]) + [AS_IF([$($PKG_CONFIG --exists bash-completion)], [ + with_bashcompletiondir=$($PKG_CONFIG --variable=completionsdir bash-completion) + ] , [ + with_bashcompletiondir=${datadir}/bash-completion/completions + ])]) -AC_ARG_WITH([pamlibdir], - AS_HELP_STRING([--with-pamlibdir=DIR], [Diectory for PAM modules]), - [], - [with_pamlibdir=/lib/`$CC -print-multi-os-directory`/security]) +AC_ARG_WITH([zshcompletiondir], + AS_HELP_STRING([--with-zshcompletiondir=DIR], [Zsh completions directory]), + [], [with_zshcompletiondir=${datadir}/zsh/site-functions]) -AC_ARG_WITH([rootdir], - AS_HELP_STRING([--with-rootdir=DIR], [Root directory for files necessary for boot]), - [], - [with_rootdir=${ac_default_prefix}]) +AC_ARG_WITH([rootprefix], + AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and kernel modules]), + [], [with_rootprefix=${ac_default_prefix}]) AC_ARG_WITH([rootlibdir], AS_HELP_STRING([--with-rootlibdir=DIR], [Root directory for libraries necessary for boot]), [], [with_rootlibdir=${libdir}]) +AC_ARG_WITH([pamlibdir], + AS_HELP_STRING([--with-pamlibdir=DIR], [Directory for PAM modules]), + [], + [with_pamlibdir=${with_rootlibdir}/security]) + +AC_ARG_WITH([pamconfdir], + AS_HELP_STRING([--with-pamconfdir=DIR], [Directory for PAM configuration]), + [], + [with_pamconfdir=${sysconfdir}/pam.d]) + +AC_ARG_ENABLE([split-usr], + AS_HELP_STRING([--enable-split-usr], [Assume that /bin, /sbin aren\'t symlinks into /usr]), + [], + [AS_IF([test "x${ac_default_prefix}" != "x${with_rootprefix}"], [ + enable_split_usr=yes + ], [ + enable_split_usr=no + ])]) + +AS_IF([test "x${enable_split_usr}" = "xyes"], [ + AC_DEFINE(HAVE_SPLIT_USR, 1, [Define if /bin, /sbin aren't symlinks into /usr]) +]) + +# Work around intltoolize and gtk-doc problems in VPATH builds +AM_CONDITIONAL([ENABLE_GTK_DOC_TESTS], [test "x$0" = "x./configure"], + [Define to do gtk-doc tests]) +AS_IF([test "x$0" != "x./configure"], [ + AC_SUBST([INTLTOOL_UPDATE], [/bin/true]) +]) + +AC_ARG_ENABLE(tests, + [AC_HELP_STRING([--disable-tests], [disable tests])], + enable_tests=$enableval, enable_tests=yes) +AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes]) + AC_SUBST([dbuspolicydir], [$with_dbuspolicydir]) AC_SUBST([dbussessionservicedir], [$with_dbussessionservicedir]) AC_SUBST([dbussystemservicedir], [$with_dbussystemservicedir]) AC_SUBST([dbusinterfacedir], [$with_dbusinterfacedir]) -AC_SUBST([udevrulesdir], [$with_udevrulesdir]) +AC_SUBST([bashcompletiondir], [$with_bashcompletiondir]) +AC_SUBST([zshcompletiondir], [$with_zshcompletiondir]) AC_SUBST([pamlibdir], [$with_pamlibdir]) -AC_SUBST([rootdir], [$with_rootdir]) +AC_SUBST([pamconfdir], [$with_pamconfdir]) +AC_SUBST([rootprefix], [$with_rootprefix]) AC_SUBST([rootlibdir], [$with_rootlibdir]) -AC_CONFIG_FILES([Makefile po/Makefile.in]) +AC_CONFIG_FILES([ + Makefile po/Makefile.in + docs/libudev/Makefile + docs/libudev/version.xml + docs/gudev/Makefile + docs/gudev/version.xml +]) + AC_OUTPUT AC_MSG_RESULT([ $PACKAGE_NAME $VERSION - Distribution: ${with_distro} - SysV compatibility: ${SYSTEM_SYSV_COMPAT} - SysV init scripts: ${SYSTEM_SYSVINIT_PATH} - SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH} - Gtk: ${have_gtk} libcryptsetup: ${have_libcryptsetup} tcpwrap: ${have_tcpwrap} PAM: ${have_pam} AUDIT: ${have_audit} + IMA: ${have_ima} + AppArmor: ${have_apparmor} SELinux: ${have_selinux} + SECCOMP: ${have_seccomp} + SMACK: ${have_smack} + XZ: ${have_xz} ACL: ${have_acl} + XATTR: ${have_xattr} + GCRYPT: ${have_gcrypt} + QRENCODE: ${have_qrencode} + MICROHTTPD: ${have_microhttpd} + CHKCONFIG: ${have_chkconfig} binfmt: ${have_binfmt} + vconsole: ${have_vconsole} + readahead: ${have_readahead} + bootchart: ${have_bootchart} + quotacheck: ${have_quotacheck} + tmpfiles: ${have_tmpfiles} + randomseed: ${have_randomseed} + backlight: ${have_backlight} + rfkill: ${have_rfkill} + logind: ${have_logind} + machined: ${have_machined} hostnamed: ${have_hostnamed} timedated: ${have_timedated} localed: ${have_localed} - plymouth: ${have_plymouth} + networkd: ${have_networkd} + coredump: ${have_coredump} + polkit: ${have_polkit} + efi: ${have_efi} + kmod: ${have_kmod} + blkid: ${have_blkid} + dbus: ${have_dbus} + nss-myhostname: ${have_myhostname} + gudev: ${enable_gudev} + gintrospection: ${enable_introspection} + multi-seat-x: ${have_multi_seat_x} + kdbus: ${have_kdbus} + Python: ${have_python} + Python Headers: ${have_python_devel} + man pages: ${have_manpages} + gtk-doc: ${enable_gtk_doc} + test coverage: ${have_coverage} + Split /usr: ${enable_split_usr} + SysV compatibility: ${SYSTEM_SYSV_COMPAT} + compatibility libraries: ${have_compat_libs} + prefix: ${prefix} - root dir: ${with_rootdir} + rootprefix: ${with_rootprefix} + sysconf dir: ${sysconfdir} + datarootdir: ${datarootdir} + includedir: ${includedir} + include_prefix: ${INCLUDE_PREFIX} lib dir: ${libdir} rootlib dir: ${with_rootlibdir} - pam modules dir: ${with_pamlibdir} - udev rules dir: ${with_udevrulesdir} - dbus policy dir: ${with_dbuspolicydir} - dbus session dir: ${with_dbussessionservicedir} - dbus system dir: ${with_dbussystemservicedir} - dbus interfaces dir: ${with_dbusinterfacedir} + SysV init scripts: ${SYSTEM_SYSVINIT_PATH} + SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH} + Build Python: ${PYTHON} + Installation Python: ${PYTHON_BINARY} + sphinx binary: ${SPHINX_BUILD} + firmware path: ${FIRMWARE_PATH} + PAM modules dir: ${with_pamlibdir} + PAM configuration dir: ${with_pamconfdir} + D-Bus policy dir: ${with_dbuspolicydir} + D-Bus session dir: ${with_dbussessionservicedir} + D-Bus system dir: ${with_dbussystemservicedir} + D-Bus interfaces dir: ${with_dbusinterfacedir} + Bash completions dir: ${with_bashcompletiondir} + Zsh completions dir: ${with_zshcompletiondir} + Extra start script: ${RC_LOCAL_SCRIPT_PATH_START} + Extra stop script: ${RC_LOCAL_SCRIPT_PATH_STOP} + Debug shell: ${SUSHELL} @ ${DEBUGTTY} + + CFLAGS: ${OUR_CFLAGS} ${CFLAGS} + CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} + LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} + PYTHON_CFLAGS: ${PYTHON_DEVEL_CFLAGS} + PYTHON_LIBS: ${PYTHON_DEVEL_LIBS} ]) diff --git a/debian/README.Debian b/debian/README.Debian deleted file mode 100644 index a4cdcde..0000000 --- a/debian/README.Debian +++ /dev/null @@ -1,27 +0,0 @@ -systemd for Debian -================== - -systemd can be installed alongside sysvinit and will not change the -behaviour of the system out of the box. This is intentional. To test -systemd, add: - -init=/bin/systemd - -to the kernel command line and then rebooting, or install the -systemd-sysv package. - -Known bugs and problems -======================= - -The PAM module makes su exit with an error after running the command, -hiding the real exit status of the process. - -Older ifupdown's postinst has a bug where it ends up creating -/etc/network/run as a normal directory rather than a symlink to -/run. This can cause network interfaces to not -start correctly on boot. The easiest way to fix this is to run: - - mv /etc/network/run /lib/init/rw/network - ln -s /run /etc/network/run - - -- Tollef Fog Heen , Wed, 12 Oct 2011 08:43:50 +0200 diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 5eb39dc..0000000 --- a/debian/changelog +++ /dev/null @@ -1,436 +0,0 @@ -systemd (37-1slp2+s1) unstable; urgency=low - - * Merge with Debian. - * slp: use new M4_DEFINES variable in Makefile.am instead of M4_DISTRO_FLAG. - - -- Rafal Krypa Fri, 14 Oct 2011 10:16:47 +0200 - -systemd (37-1) unstable; urgency=low - - [ Tollef Fog Heen ] - * New upstream version - * Change the type of the debian-fixup service to oneshot. - Closes: #642961 - * Add ConditionPathIsDirectory to lib-init-rw.automount and - lib-init-rw.mount so we only activate the unit if the directory - exists. Closes: #633059 - * If a sysv service exists in both rcS and rcN.d runlevels, drop the - rcN.d ones to avoid loops. Closes: #637037 - * Blacklist fuse init script, we do the same work already internally. - Closes: #643700 - * Update README.Debian slightly for /run rather than /lib/init/rw - - [ Josh Triplett ] - * Do a one-time migration of the $TMPTIME setting from /etc/default/rcS to - /etc/tmpfiles.d/tmp.conf. If /etc/default/rcS has a TMPTIME setting of - "infinite" or equivalent, migrate it to an /etc/tmpfiles.d/tmp.conf that - overrides the default /usr/lib/tmpfiles.d/tmp.conf and avoids clearing - /tmp. Closes: #643698 - - -- Tollef Fog Heen Wed, 28 Sep 2011 20:04:13 +0200 - -systemd (36-1slp2+s1) unstable; urgency=low - - * Merge with Debian. - * Remove debian-fixup service. - * Versioned dependency on dh-autoreconf. - - -- Rafal Krypa Thu, 29 Sep 2011 16:06:45 +0200 - -systemd (36-1) unstable; urgency=low - - [ Tollef Fog Heen ] - * New upstream release. Closes: #634618 - - Various man page fixes. Closes: #623521 - * Add debian-fixup service that symlinks mtab to /proc/mounts and - migrates /var/run and /var/lock to symlinks to /run - - [ Michael Biebl ] - * Build for libnotify 0.7. - * Bump Build-Depends on libudev to (>= 172). - * Add Build-Depends on libacl1-dev. Required for building systemd-logind - with ACL support. - * Split libsystemd-login and libsystemd-daemon into separate binary - packages. - * As autoreconf doesn't like intltool, override dh_autoreconf and call - intltoolize and autoreconf ourselves. - * Add Build-Depends on intltool. - * Do a one-time migration of the hwclock configuration. If UTC is set to - "no" in /etc/default/rcS, create /etc/adjtime and add the "LOCAL" setting. - * Remove /cgroup cleanup code from postinst. - * Add Build-Depends on gperf. - - -- Tollef Fog Heen Wed, 14 Sep 2011 08:25:17 +0200 - -systemd (29-1) unstable; urgency=low - - [ Tollef Fog Heen ] - * New upstream version, Closes: #630510 - - Includes typo fixes in documentation. Closes: #623520 - * Fall back to the init script reload function if a native .service file - doesn't know how to reload. Closes: #628186 - * Add hard dependency on udev. Closes: #627921 - - [ Michael Biebl ] - * hwclock-load.service is no longer installed, so we don't need to remove it - anymore in debian/rules. - * Install /usr/lib directory for binfmt.d, modules-load.d, tmpfiles.d and - sysctl.d. - * Remove obsolete conffiles from /etc/tmpfiles.d on upgrades. Those files - are installed in /usr/lib/tmpfiles.d now. - * Depend on util-linux (>= 2.19.1-2) which provides whole-disk locking - support in fsck and remove our revert patch. - * Don't choke when systemd was compiled with a different CAP_LAST_CAP then - what it is run with. Patch cherry-picked from upstream Git. - Closes: #628081 - * Enable dev-hugepages.automount and dev-mqueue.automount only when enabled - in kernel. Patch cherry-picked from upstream Git. Closes: #624522 - - -- Tollef Fog Heen Wed, 08 Jun 2011 16:14:31 +0200 - -systemd (25-2slp2+s10) unstable; urgency=low - - [ Rafal Krypa ] - * Allow disabling of documentation build by "--disable-docs" configure flag. - - [ Mike McCormack ] - * Install the .pc file under libdir - * rpm: Add spec file - - [ Karol Lewandowski ] - * slp: Start getty on board-agnostic serial device - * slp: Kill mkcompatdev hack - * slp: Kill mdev - * slp: Get rid of mnt-db.(auto)mount - it's c110-specific - * rpm: Start getty on board-agnostic serial device - * Move .pc files to proper location - - -- Karol Lewandowski Tue, 27 Sep 2011 20:32:14 +0900 - -systemd (25-2slp2+s9) unstable; urgency=low - - * debian: Don't conflict with klogd - - -- Karol Lewandowski Mon, 05 Sep 2011 15:33:26 +0200 - -systemd (25-2slp2+s8) unstable; urgency=low - - * slp: Re-add broken mmc devices faster in bootup sequence - * slp: Adjust mount points to new fs layout - * slp: Drop unused media.mount - * slp: Move SLP-specific rules back to proper place - - -- Karol Lewandowski Wed, 31 Aug 2011 20:03:11 +0200 - -systemd (25-2slp2+s7) unstable; urgency=low - - * Add libsystemd-daemon library - * Expand few more variables for libsystemd-daemon.pc.in - * Add myself to list of maintainers - - -- Karol Lewandowski Thu, 04 Aug 2011 14:59:48 +0200 - -systemd (25-2slp2+s6) unstable; urgency=low - - * Add /var/lock -> /run/lock bind mount point - - -- Karol Lewandowski Thu, 14 Jul 2011 16:11:04 +0200 - -systemd (25-2slp2+s5) unstable; urgency=low - - * Limit amount of systemd-tagged ttys - * HACK: Decrease log level to avoid console lockups on Limo REV2.0 - boards - * Kill SysV-compatibility runlevel directories - - -- Karol Lewandowski Tue, 21 Jun 2011 13:33:54 +0200 - -systemd (25-2slp2+s4) unstable; urgency=low - - * Revert "Customize sysv-rc scripts path on SLP" - * Revert "Don't start readahead related services on slp" - * slp: Merge slp-specific parts in makefile - * slp: Make bind-mounting /var/run and /var/lock unconditional - * slp: Bind mount /var/{cache,lib,log} like it's done on SLP - * slp: Don't install Debian-specific /lib/init/rw auto mount point - - -- Karol Lewandowski Thu, 09 Jun 2011 14:50:14 +0200 - -systemd (25-2slp2+s3) unstable; urgency=low - - * slp: Create compatibility /run directory - * Make sure we remount rootfs read-writable - - -- Karol Lewandowski Wed, 08 Jun 2011 16:06:15 +0200 - -systemd (25-2slp2+s2) unstable; urgency=low - - * Add usr/etc once again - * debian: Don't try to delete LICENSE - it isn't installed anymore - * Add slp-compatible mount fstab replacements - * slp: Drop unit files for busybox logging deamons - - -- Karol Lewandowski Fri, 27 May 2011 17:50:32 +0200 - -systemd (25-2slp2+s1) unstable; urgency=low - - * debian: Avoid using GNU-specific options in installation scripts - * Merge slp2-customizations for systemd - - -- Karol Lewandowski Tue, 24 May 2011 17:00:39 +0200 - -systemd (25-2) experimental; urgency=low - - * Handle downgrades more gracefully by removing diversion of - /lib/lsb/init-functions on downgrades to << 25-1. - * Cherry-pick a133bf10d09f788079b82f63faa7058a27ba310b from upstream, - avoids assert when dumping properties. Closes: #624094 - * Remove "local" in non-function context in init-functions wrapper. - - -- Tollef Fog Heen Wed, 27 Apr 2011 22:20:04 +0200 - -systemd (25-1) experimental; urgency=low - - * New upstream release, target experimental due to initscripts - dependency. - - Fixes where to look for locale config. Closes: #619166 - * Depend on initscripts >= 2.88dsf-13.4 for /run transition. - * Add Conflicts on klogd, since it doesn't work correctly with the - kmg→/dev/log bridge. Closes: #622555 - * Add suggests on Python for systemd-analyze. - * Divert /lib/lsb/init-functions instead of (ab)using - /etc/lsb-base-logging.sh for diverting calls to /etc/init.d/* - * Remove obsolete conffile /etc/lsb-base-logging.sh. Closes: #619093 - * Backport 3a90ae048233021833ae828c1fc6bf0eeab46197 from master: - mkdir /run/systemd/system when starting up - - -- Tollef Fog Heen Sun, 24 Apr 2011 09:02:04 +0200 - -systemd (24-0slp2+s4) unstable; urgency=low - - * slp: Add service to generate slp-compatible devices at bootup - * slp: Tag slp-specific ttys - * slp: Use kernel tty device name - - -- Karol Lewandowski Wed, 04 May 2011 14:56:35 +0200 - -systemd (24-0slp2+s3) unstable; urgency=low - - * Fix: Don't use const pointer for for const data - * slp: Fixup serial-getty@ once again - * slp: Don't mount binfmt_misc nor security fs; disable cryptsetup - target - * slp: Don't use accept4() - - -- Karol Lewandowski Wed, 20 Apr 2011 19:35:24 +0200 - -systemd (24-0slp2+s2) unstable; urgency=low - - * debian: Update systemd.install to match upstream changes - * Fixup serial-getty@ service on slp - * Move busybox services to units/slp - * Automatically install busybox services for slp - * Install only serial-getty@ on slp - * Revert "debian: Don't try to remove service files which aren't - installed on slp" - - -- Karol Lewandowski Fri, 15 Apr 2011 12:12:29 +0200 - -systemd (24-0slp2+s1) unstable; urgency=low - - * Sync with upstream - - -- Karol Lewandowski Wed, 13 Apr 2011 19:28:40 +0200 - -systemd (20-1) unstable; urgency=low - - * New upstream version - * Install systemd-machine-id-setup - * Call systemd-machine-id-setup in postinst - * Cherry-pick b8a021c9e276adc9bed5ebfa39c3cab0077113c6 from upstream to - prevent dbus assert error. - * Enable TCP wrapper support. Closes: #618409 - * Enable SELinux support. Closes: #618412 - * Make getty start after Apache2 and OpenVPN (which are the only two - known users of X-Interactive: yes). Closes: #618419 - - -- Tollef Fog Heen Fri, 11 Mar 2011 19:14:21 +0100 - -systemd (19-1slp2+s3) unstable; urgency=low - - * debian: Don't remove doc/LICENSE - it isn't installed anymore - * Revert "debian/systemd.install: include SLP config directory - /usr/etc" - * debian: Don't try to remove service files which aren't installed on - slp - - -- Karol Lewandowski Wed, 13 Apr 2011 19:09:28 +0200 - -systemd (19-1slp2+s2) unstable; urgency=low - - * Add missing piece to make --with-distro=slp really work - * Customize sysv-rc scripts path on SLP - * Install serial-getty by default on SLP - * Don't install getty@ services on SLP - * Add busybox klogd service for slp - * Add busybox syslogd service for slp - * Don't start readahead related services on slp - * Pretty print SLP name - * Change default log level to debug - - -- Karol Lewandowski Wed, 13 Apr 2011 11:54:03 +0200 - -systemd (19-1slp2+s1) unstable; urgency=low - - * Set myself as SLP maintainer. - * Disable GUI, PAM, AUDIT, cryptsetup. - * Add versioned build dependency on linux-libc-dev. - * debian/systemd.install: include SLP config directory /usr/etc - * Drop version specification from util-linux dependency in systemd package. - * Initial customization for SLP. - - -- Rafal Krypa Fri, 04 Mar 2011 13:26:14 +0100 - -systemd (19-1) UNRELEASED; urgency=low - - * New upstream release - * Add systemd-tmpfiles to systemd package. - * Add ifup@.service for handling hotplugged interfaces from - udev. Closes: #610871 - * Mask mtab.service and udev-mtab.service as they are pointless when - /etc/mtab is a symlink to /proc/mounts - * Add breaks on lvm2 (<< 2.02.84-1) since older versions have udev rules - that don't work well with systemd causing delays on bootup. - - -- Tollef Fog Heen Thu, 17 Feb 2011 07:36:22 +0100 - -systemd (17-1) experimental; urgency=low - - [ Tollef Fog Heen ] - * New upstream release - * Clarify ifupdown instructions in README.Debian somewhat. - Closes: #613320 - * Silently skip masked services in lsb-base-logging.sh instead of - failing. Initial implementation by Michael Biebl. Closes: #612551 - * Disable systemd-vconsole-setup.service for now. - - [ Michael Biebl ] - * Bump build dependency on valac-0.10 to (>= 0.10.3). - * Improve regex in lsb-base-logging.sh for X-Interactive scripts. - Closes: #613325 - - -- Tollef Fog Heen Wed, 16 Feb 2011 21:06:16 +0100 - -systemd (16-1) experimental; urgency=low - - [ Tollef Fog Heen ] - * New upstream release. Closes: #609611 - * Get rid of now obsolete patches that are upstream. - * Use the built-in cryptsetup support in systemd, build-depend on - libcryptsetup-dev (>= 2:1.2.0-1) to get a libcryptsetup in /lib. - * Don't use systemctl redirect for init scripts with X-Interactive: true - - [ Michael Biebl ] - * Update package description - * Use v8 debhelper syntax - * Make single-user mode work - * Run hwclock-save.service on shutdown - * Remove dependencies on legacy sysv mount scripts, as we use native - mounting. - - -- Tollef Fog Heen Sun, 16 Jan 2011 11:04:13 +0100 - -systemd (15-1) UNRELEASED; urgency=low - - [ Tollef Fog Heen ] - * New upstream version, thanks a lot to Michael Biebl for help with - preparing this version. - - This version handles cycle breaking better. Closes: #609225 - * Add libaudit-dev to build-depends - * /usr/share/systemd/session has been renamed to /usr/share/systemd/user - upstream, adjust build system accordingly. - * Remove -s from getty serial console invocation. - * Add dependency on new util-linux to make sure /sbin/agetty exists - * Don't mount /var/lock with gid=lock (Debian has no such group). - * Document problem with ifupdown's /etc/network/run being a normal - directory. - - [ Michael Biebl ] - * Revert upstream change which requires libnotify 0.7 (not yet available in - Debian). - * Use dh-autoreconf for updating the build system. - * Revert upstream commit which uses fsck -l (needs a newer version of - util-linux). - * Explicitly disable cryptsetup support to not accidentally pick up a - libcryptsetup dependency in a tainted build environment, as the library - is currently installed in /usr/lib. - * Remove autogenerated man pages and vala C sources, so they are rebuilt. - * Use native systemd mount support: - - Use MountAuto=yes and SwapAuto=yes (default) in system.conf - - Mask SysV init mount, check and cleanup scripts. - - Create an alias (symlink) for checkroot (→ remount-rootfs.service) as - synchronization point for SysV init scripts. - * Mask x11-common, rmnologin, hostname, bootmisc and bootlogd. - * Create an alias for procps (→ systemd-sysctl.service) and - urandom (→ systemd-random-seed-load.service). - * Create an alias for module-init-tools (→ systemd-modules-load.service) and - a symlink from /etc/modules-load.d/modules.conf → /etc/modules. - * Install lsb-base hook which redirects calls to SysV init scripts to - systemctl: /etc/init.d/ → systemctl - * Install a (auto)mount unit to mount /lib/init/rw early during boot. - - -- Tollef Fog Heen Sat, 20 Nov 2010 09:28:01 +0100 - -systemd (11-2) UNRELEASED; urgency=low - - * Tighten depends from systemd-* on systemd to ensure they're upgraded - in lockstep. Thanks to Michael Biebl for the patch. - * Add missing #DEBHELPER# token to libpam-systemd - * Stop messing with runlevel5/multi-user.target symlink, this is handled - correctly upstream. - * Stop shipping /cgroup in the package. - * Remove tmpwatch services, Debian doesn't have or use tmpwatch. - * Make sure to enable GTK bits. - * Ship password agent - * Clean up cgroups properly on upgrades, thanks to Michael Biebl for the - patch. Closes: #599577 - - -- Tollef Fog Heen Tue, 02 Nov 2010 21:47:10 +0100 - -systemd (11-1) experimental; urgency=low - - * New upstream version. Closes: #597284 - * Add pam-auth-update calls to libpam-systemd's postinst and prerm - * Make systemd-sysv depend on systemd - * Now mounts the cgroup fs in /sys/fs/cgroup. Closes: #595966 - * Add libnotify-dev to build-depends (needed for systemadm) - - -- Tollef Fog Heen Thu, 07 Oct 2010 22:01:19 +0200 - -systemd (8-2) experimental; urgency=low - - * Hardcode udev rules dir in configure call. - * Remove README.source as it's no longer accurate. - - -- Tollef Fog Heen Mon, 30 Aug 2010 21:10:26 +0200 - -systemd (8-1) experimental; urgency=low - - * New upstream release - * Only ship the top /cgroup - * Pass --with-rootdir= to configure, to make it think / is / rather - than // - * Add PAM module package - * Fix up dependencies in local-fs.target. Closes: #594420 - * Move systemadm to its own package. Closes: #588451 - * Update standards-version (no changes needed) - * Update README.Debian to explain how to use systemd. - * Add systemd-sysv package that provides /sbin/init and friends. - - -- Tollef Fog Heen Sat, 07 Aug 2010 07:31:38 +0200 - -systemd (0~git+20100605+dfd8ee-1) experimental; urgency=low - - * Initial release, upload to experimental. Closes: #580814 - - -- Tollef Fog Heen Fri, 30 Apr 2010 21:02:25 +0200 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control deleted file mode 100644 index 2eed354..0000000 --- a/debian/control +++ /dev/null @@ -1,129 +0,0 @@ -Source: systemd -Section: admin -Priority: extra -Maintainer: Rafal Krypa , Karol Lewandowski , DongGi Jang -X-Original-Maintainer: Tollef Fog Heen -Standards-Version: 3.9.1 -Vcs-Git: git://git.err.no/systemd/ -Vcs-Browser: http://git.err.no/cgi-bin/gitweb.cgi?p=systemd;a=summary -Homepage: http://www.freedesktop.org/wiki/Software/systemd -Build-Depends: debhelper (>= 7.0.50), - libcap-dev, - pkg-config, - libudev-dev (>= 172), - libdbus-1-dev (>= 1.3.2~), - libdbus-glib-1-dev, - xsltproc, - docbook-xsl, - docbook-xml, - m4, - dh-autoreconf (>= 4), - intltool, - libacl1-dev, - linux-libc-dev (>= 2.6.31), - gperf - -Package: systemd -Architecture: linux-any -Section: admin -Priority: extra -Recommends: libpam-systemd -Suggests: systemd-gui, python -Depends: ${shlibs:Depends}, ${misc:Depends}, util-linux, udev -Breaks: lvm2 (<< 2.02.84-1) -Description: system and service manager - systemd is a replacement for sysvinit. It is dependency-based and - able to read the LSB init script headers in addition to parsing rcN.d - links as hints. - . - It also provides process supervision using cgroups and the ability to - not only depend on other init script being started, but also - availability of a given mount point or dbus service. - -Package: systemd-sysv -Architecture: linux-any -Section: admin -Priority: extra -Conflicts: sysvinit, upstart, runit-run -Replaces: sysvinit -Depends: systemd (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: system and service manager - SysV links - systemd is a replacement for sysvinit. It is dependency-based and - able to read the LSB init script headers in addition to parsing rcN.d - links as hints. - . - It also provides process supervision using cgroups and the ability to - not only depend on other init script being started, but also - availability of a given mount point or dbus service. - . - This package provides the manual pages and links needed for systemd - to replace sysvinit. - -Package: libpam-systemd -Architecture: linux-any -Section: admin -Priority: extra -Depends: systemd (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: system and service manager - PAM module - systemd is a replacement for sysvinit. It is dependency-based and - able to read the LSB init script headers in addition to parsing rcN.d - links as hints. - . - It also provides process supervision using cgroups and the ability to - not only depend on other init script being started, but also - availability of a given mount point or dbus service. - . - This package contains the PAM module which registers user sessions in - the systemd control group hierarchy - -Package: systemd-gui -Architecture: linux-any -Section: admin -Priority: extra -Depends: systemd (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: system and service manager - GUI - systemd is a replacement for sysvinit. It is dependency-based and - able to read the LSB init script headers in addition to parsing rcN.d - links as hints. - . - It also provides process supervision using cgroups and the ability to - not only depend on other init script being started, but also - availability of a given mount point or dbus service. - . - This package contains the graphical frontend for systemd. - -Package: libsystemd-login0 -Architecture: linux-any -Section: libs -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: systemd login utility library - The libsystemd-login library provides an interface for the - systemd-logind service which is used to track user sessions and seats. - -Package: libsystemd-login-dev -Architecture: linux-any -Section: libdevel -Depends: libsystemd-login0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: systemd login utility library - development files - The libsystemd-login library provides an interface for the - systemd-logind service which is used to track user sessions and seats. - . - This package contains the development files - -Package: libsystemd-daemon0 -Architecture: linux-any -Section: libs -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: systemd utility library - The sd-daemon library provides a reference implementation of various - APIs for new-style daemons, as implemented by the systemd init system. - -Package: libsystemd-daemon-dev -Architecture: linux-any -Section: libdevel -Depends: libsystemd-daemon0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} -Description: systemd utility library - development files - The sd-daemon library provides a reference implementation of various - APIs for new-style daemons, as implemented by the systemd init system. - . - This package contains the development files diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index dd56ec7..0000000 --- a/debian/copyright +++ /dev/null @@ -1,23 +0,0 @@ -Downloaded from http://cgit.freedesktop.org/systemd/, packaged by -Tollef Fog Heen 2010-04-30 21:00. - -Copyright: - - Copyright 2010 Lennart Poettering - Copyright 2010 Maarten Lankhorst - Copyright 1995-2004 Miquel van Smoorenburg - -Authors: - - Lennart Poettering - Kay Sievers - -Licence: - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - -please see /usr/share/common-licenses/GPL-2 for the full text of the -GPL version 2. diff --git a/debian/debian-fixup b/debian/debian-fixup deleted file mode 100755 index 399afb8..0000000 --- a/debian/debian-fixup +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/sh - -set -e - -if [ ! -L /etc/mtab ]; then - ln -sf /proc/mounts /etc/mtab -fi -if [ ! -L /var/run ]; then - rm -rf /var/run - ln -s /run /var/run -fi -if [ ! -L /var/lock ]; then - rm -rf /var/lock - ln -s /run/lock /var/lock -fi -exit 0 diff --git a/debian/debian-fixup.service b/debian/debian-fixup.service deleted file mode 100644 index 6848466..0000000 --- a/debian/debian-fixup.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Various fixups to make systemd work better on Debian -Before=var-run.mount var-lock.mount -After=remount-rootfs.service -DefaultDependencies=no - -[Service] -ExecStart=/lib/systemd/debian-fixup -Type=oneshot -RemainAfterExit=true diff --git a/debian/ifup@.service b/debian/ifup@.service deleted file mode 100644 index 4d5cc8c..0000000 --- a/debian/ifup@.service +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=Start ifup for %I -After=local-fs.target - -[Service] -ExecStart=/sbin/ifup --allow=hotplug %I -ExecStop=/sbin/ifdown %I -RemainAfterExit=true diff --git a/debian/init-functions b/debian/init-functions deleted file mode 100644 index 81e4bd7..0000000 --- a/debian/init-functions +++ /dev/null @@ -1,99 +0,0 @@ -# -*-Shell-script-*- -# /lib/lsb/init-functions - -. /lib/lsb/init-functions.systemd - -if [ -e /sys/fs/cgroup/systemd ] ; then - # Some init scripts use "set -e" and "set -u", we don't want that - # here - set +e - set +u - - if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] ; then - # If we are called by a maintainer script, chances are good that a - # new or updated sysv init script was installed. Reload daemon to - # pick up any changes. - echo "Reloading systemd" - systemctl daemon-reload - fi - - # Redirect SysV init scripts when executed by the user - if [ $PPID -ne 1 ] && [ -z "$init" ] && [ -z "$_SYSTEMCTL_SKIP_REDIRECT" ] ; then - case $(readlink -f "$0") in - /etc/init.d/*) - # Don't redirect if the init script has X-Interactive: true - if ! grep -qs "^# X-Interactive:.*true" "$0"; then - _use_systemctl=1 - fi - # Redirect if there's a matching .service file in /etc or /lib - prog=${0##*/} - service="${prog%.sh}.service" - fp=$(systemctl -p FragmentPath show $service 2>/dev/null | sed 's/^FragmentPath=//') - case "$fp" in - /lib/systemd/system/*|/etc/systemd/system/*) - _use_systemctl=1 - ;; - esac - # Some services can't reload through the .service file, - # but can through the init script. - if [ "$(systemctl -p CanReload show $service 2>/dev/null)" = "CanReload=no" ] && [ "$1" = "reload" ]; then - _use_systemctl=0 - fi - ;; - esac - else - export _SYSTEMCTL_SKIP_REDIRECT="true" - fi -else - _use_systemctl=0 -fi - -systemctl_redirect () { - local s - local rc - local prog=${1##*/} - local command=$2 - - case "$command" in - start) - s="Starting $prog (via systemctl)" - ;; - stop) - s="Stopping $prog (via systemctl)" - ;; - reload|force-reload) - s="Reloading $prog configuration (via systemctl)" - ;; - restart) - s="Restarting $prog (via systemctl)" - ;; - esac - - service="${prog%.sh}.service" - - # Don't try to run masked services. Don't check for errors, if - # this errors, we'll just call systemctl and possibly explode - # there. - state=$(systemctl -p LoadState show $service 2>/dev/null) - [ "$state" = "LoadState=masked" ] && return 0 - - [ "$command" = status ] || log_daemon_msg "$s" "$service" - /bin/systemctl $command "$service" - rc=$? - [ "$command" = status ] || log_end_msg $rc - - return $rc -} - -if [ "$_use_systemctl" = "1" ]; then - if [ "x$1" = xstart -o \ - "x$1" = xstop -o \ - "x$1" = xrestart -o \ - "x$1" = xreload -o \ - "x$1" = xforce-reload -o \ - "x$1" = xstatus ] ; then - - systemctl_redirect $0 $1 - exit $? - fi -fi diff --git a/debian/lib-init-rw.automount b/debian/lib-init-rw.automount deleted file mode 100644 index f32a921..0000000 --- a/debian/lib-init-rw.automount +++ /dev/null @@ -1,15 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[Unit] -Description=Debian early rw Automount Point -DefaultDependencies=no -Before=basic.target -ConditionPathIsDirectory=/lib/init/rw - -[Automount] -Where=/lib/init/rw diff --git a/debian/lib-init-rw.mount b/debian/lib-init-rw.mount deleted file mode 100644 index f3650d2..0000000 --- a/debian/lib-init-rw.mount +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Debian early rw mount -DefaultDependencies=no -ConditionPathIsDirectory=/lib/init/rw - -[Mount] -What=tmpfs -Where=/lib/init/rw -Type=tmpfs -Options=mode=0755,nosuid diff --git a/debian/libpam-systemd.install b/debian/libpam-systemd.install deleted file mode 100644 index 18b8af9..0000000 --- a/debian/libpam-systemd.install +++ /dev/null @@ -1,2 +0,0 @@ -lib/security/pam_systemd.so -usr/share/man/man8/pam_systemd.8 diff --git a/debian/libpam-systemd.postinst b/debian/libpam-systemd.postinst deleted file mode 100644 index c6177d8..0000000 --- a/debian/libpam-systemd.postinst +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/sh - -set -e - -pam-auth-update --package - -#DEBHELPER# diff --git a/debian/libpam-systemd.prerm b/debian/libpam-systemd.prerm deleted file mode 100644 index 7b57168..0000000 --- a/debian/libpam-systemd.prerm +++ /dev/null @@ -1,20 +0,0 @@ -#! /bin/sh - -set -e - -# pam-auth-update --remove removes the named profile from the active config. -# It arguably should be called during deconfigure as well, but deconfigure -# can happen in some cases during a dist-upgrade and we don't want to -# deconfigure all PAM modules in the middle of a dist-upgrade by accident. -# -# More importantly, with the current implementation, --remove also removes -# all local preferences for the named config (such as whether it's enabled -# or disabled), which we don't want to do on deconfigure. -# -# This may need to change later as pam-auth-update evolves. - -if [ "$1" = "remove" ] ; then - pam-auth-update --package --remove systemd -fi - -#DEBHELPER# diff --git a/debian/libsystemd-daemon-dev.install b/debian/libsystemd-daemon-dev.install deleted file mode 100644 index 3a20bfc..0000000 --- a/debian/libsystemd-daemon-dev.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/lib/libsystemd-daemon.so -usr/lib/pkgconfig/libsystemd-daemon.pc -usr/include/systemd/sd-daemon.h diff --git a/debian/libsystemd-daemon0.install b/debian/libsystemd-daemon0.install deleted file mode 100644 index 48d464a..0000000 --- a/debian/libsystemd-daemon0.install +++ /dev/null @@ -1 +0,0 @@ -lib/libsystemd-daemon.so.* diff --git a/debian/libsystemd-daemon0.symbols b/debian/libsystemd-daemon0.symbols deleted file mode 100644 index 5c064cc..0000000 --- a/debian/libsystemd-daemon0.symbols +++ /dev/null @@ -1,12 +0,0 @@ -libsystemd-daemon.so.0 libsystemd-daemon0 #MINVER# - LIBSYSTEMD_DAEMON_31@LIBSYSTEMD_DAEMON_31 31 - sd_booted@LIBSYSTEMD_DAEMON_31 31 - sd_is_fifo@LIBSYSTEMD_DAEMON_31 31 - sd_is_mq@LIBSYSTEMD_DAEMON_31 31 - sd_is_socket@LIBSYSTEMD_DAEMON_31 31 - sd_is_socket_inet@LIBSYSTEMD_DAEMON_31 31 - sd_is_socket_unix@LIBSYSTEMD_DAEMON_31 31 - sd_is_special@LIBSYSTEMD_DAEMON_31 31 - sd_listen_fds@LIBSYSTEMD_DAEMON_31 31 - sd_notify@LIBSYSTEMD_DAEMON_31 31 - sd_notifyf@LIBSYSTEMD_DAEMON_31 31 diff --git a/debian/libsystemd-login-dev.install b/debian/libsystemd-login-dev.install deleted file mode 100644 index d6a0367..0000000 --- a/debian/libsystemd-login-dev.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/lib/libsystemd-login.so -usr/lib/pkgconfig/libsystemd-login.pc -usr/include/systemd/sd-login.h diff --git a/debian/libsystemd-login0.install b/debian/libsystemd-login0.install deleted file mode 100644 index 02ccaf8..0000000 --- a/debian/libsystemd-login0.install +++ /dev/null @@ -1 +0,0 @@ -lib/libsystemd-login.so.* diff --git a/debian/libsystemd-login0.symbols b/debian/libsystemd-login0.symbols deleted file mode 100644 index 9441669..0000000 --- a/debian/libsystemd-login0.symbols +++ /dev/null @@ -1,21 +0,0 @@ -libsystemd-login.so.0 libsystemd-login0 #MINVER# - LIBSYSTEMD_LOGIN_31@LIBSYSTEMD_LOGIN_31 31 - sd_get_seats@LIBSYSTEMD_LOGIN_31 31 - sd_get_sessions@LIBSYSTEMD_LOGIN_31 31 - sd_get_uids@LIBSYSTEMD_LOGIN_31 31 - sd_login_monitor_flush@LIBSYSTEMD_LOGIN_31 31 - sd_login_monitor_get_fd@LIBSYSTEMD_LOGIN_31 31 - sd_login_monitor_new@LIBSYSTEMD_LOGIN_31 31 - sd_login_monitor_unref@LIBSYSTEMD_LOGIN_31 31 - sd_pid_get_owner_uid@LIBSYSTEMD_LOGIN_31 31 - sd_pid_get_session@LIBSYSTEMD_LOGIN_31 31 - sd_seat_can_multi_session@LIBSYSTEMD_LOGIN_31 31 - sd_seat_get_active@LIBSYSTEMD_LOGIN_31 31 - sd_seat_get_sessions@LIBSYSTEMD_LOGIN_31 31 - sd_session_get_seat@LIBSYSTEMD_LOGIN_31 31 - sd_session_get_uid@LIBSYSTEMD_LOGIN_31 31 - sd_session_is_active@LIBSYSTEMD_LOGIN_31 31 - sd_uid_get_seats@LIBSYSTEMD_LOGIN_31 31 - sd_uid_get_sessions@LIBSYSTEMD_LOGIN_31 31 - sd_uid_get_state@LIBSYSTEMD_LOGIN_31 31 - sd_uid_is_on_seat@LIBSYSTEMD_LOGIN_31 31 diff --git a/debian/pam-configs/systemd b/debian/pam-configs/systemd deleted file mode 100644 index b31ad4b..0000000 --- a/debian/pam-configs/systemd +++ /dev/null @@ -1,6 +0,0 @@ -Name: Register user sessions in the systemd control group hierarchy -Default: yes -Priority: 0 -Session-Type: Additional -Session: - optional pam_systemd.so diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 2766f13..0000000 --- a/debian/rules +++ /dev/null @@ -1,65 +0,0 @@ -#! /usr/bin/make -f - -DISTRIBUTION := SLP - -#export DH_VERBOSE=1 -#export DEB_BUILD_OPTIONS="nostrip" - -ifeq ($(DISTRIBUTION),SLP) -DH_OPTIONS += -Nlibpam-systemd -Nsystemd-gui -export DH_OPTIONS -endif - -override_dh_auto_configure: -ifeq ($(DISTRIBUTION),SLP) - dh_auto_configure -- \ - --with-rootdir= \ - --with-rootlibdir=/lib \ - --with-udevrulesdir=/lib/udev/rules.d \ - --disable-gtk \ - --disable-libcryptsetup \ - --disable-audit \ - --disable-pam \ - --disable-tcpwrap \ - --disable-selinux \ - --with-distro=slp -else - dh_auto_configure -- \ - --with-rootdir= \ - --with-rootlibdir=/lib \ - --with-udevrulesdir=/lib/udev/rules.d \ - --enable-gtk \ - --enable-libcryptsetup \ - --enable-tcpwrap \ - --enable-selinux -endif - -override_dh_auto_clean: - dh_auto_clean - rm -f man/*.[1358] - rm -f src/systemadm.c - rm -f src/gnome-ask-password-agent.c - rm -f src/systemd-interfaces.c - -override_dh_install: -ifneq ($(DISTRIBUTION),SLP) - rm debian/tmp/lib/security/pam_systemd.la -endif - rm debian/tmp/usr/lib/*.la - rm debian/tmp/lib/systemd/system/sysinit.target.wants/systemd-vconsole-setup.service - chmod +x debian/debian-fixup - dh_install -O--parallel --fail-missing -ifneq ($(DISTRIBUTION),SLP) - dh_install -plibpam-systemd debian/pam-configs /usr/share -endif - dh_install debian/ifup@.service /lib/systemd/system - -autoreconf: - intltoolize -f - autoreconf -f -i - -override_dh_autoreconf: - dh_autoreconf debian/rules -- autoreconf - -%: - dh $@ --parallel --with autoreconf diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/source/options b/debian/source/options deleted file mode 100644 index 7423a2d..0000000 --- a/debian/source/options +++ /dev/null @@ -1 +0,0 @@ -single-debian-patch diff --git a/debian/systemd-gui.install b/debian/systemd-gui.install deleted file mode 100644 index ca6555b..0000000 --- a/debian/systemd-gui.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/bin/systemadm -usr/share/man/man1/systemadm.1 -usr/bin/systemd-gnome-ask-password-agent diff --git a/debian/systemd-hack-up-the-source.hook b/debian/systemd-hack-up-the-source.hook deleted file mode 100755 index 7ccca0a..0000000 --- a/debian/systemd-hack-up-the-source.hook +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -set -e - -set -x - -find -name Makefile -type l -print -delete -rm -r test1 test2 src/Makefile -. /usr/share/gitpkg/hooks/quilt-patches-deb-export-hook diff --git a/debian/systemd-sysv.install b/debian/systemd-sysv.install deleted file mode 100644 index 0f6f677..0000000 --- a/debian/systemd-sysv.install +++ /dev/null @@ -1,7 +0,0 @@ -usr/share/man/man8/telinit.8 -usr/share/man/man1/init.1 -usr/share/man/man8/runlevel.8 -usr/share/man/man8/shutdown.8 -usr/share/man/man8/poweroff.8 -usr/share/man/man8/reboot.8 -usr/share/man/man8/halt.8 diff --git a/debian/systemd-sysv.links b/debian/systemd-sysv.links deleted file mode 100644 index dca459f..0000000 --- a/debian/systemd-sysv.links +++ /dev/null @@ -1,7 +0,0 @@ -/bin/systemd /sbin/init -/bin/systemctl /sbin/telinit -/bin/systemctl /sbin/runlevel -/bin/systemctl /sbin/shutdown -/bin/systemctl /sbin/poweroff -/bin/systemctl /sbin/reboot -/bin/systemctl /sbin/halt diff --git a/debian/systemd.dirs b/debian/systemd.dirs deleted file mode 100644 index f5bdd21..0000000 --- a/debian/systemd.dirs +++ /dev/null @@ -1 +0,0 @@ -run diff --git a/debian/systemd.install b/debian/systemd.install deleted file mode 100644 index 8a2a894..0000000 --- a/debian/systemd.install +++ /dev/null @@ -1,38 +0,0 @@ -etc -usr/etc -bin/systemd -bin/systemctl -bin/systemd-notify -bin/systemd-tty-ask-password-agent -bin/systemd-ask-password -bin/systemd-machine-id-setup -bin/systemd-tmpfiles -bin/systemd-loginctl -lib/systemd/ -lib/udev/rules.d/ -usr/bin/systemd-cgls -usr/bin/systemd-nspawn -usr/bin/systemd-stdio-bridge -usr/bin/systemd-analyze -usr/share/man/man1/systemd-notify.1 -usr/share/man/man1/systemd-cgls.1 -usr/share/man/man1/systemd.1 -usr/share/man/man1/systemctl.1 -usr/share/man/man1/systemd-nspawn.1 -usr/share/man/man1/systemd-ask-password.1 -usr/share/man/man1/systemd-loginctl.1 -usr/share/man/man3 -usr/share/man/man5 -usr/share/man/man7 -usr/share/man/man8/systemd-tmpfiles.8 -usr/share/dbus-1 -usr/share/doc -usr/share/pkgconfig -usr/share/polkit-1 -usr/share/systemd/kbd-model-map -usr/lib/binfmt.d -usr/lib/modules-load.d -usr/lib/sysctl.d -usr/lib/systemd -usr/lib/tmpfiles.d -debian/init-functions lib/lsb diff --git a/debian/systemd.links b/debian/systemd.links deleted file mode 100644 index 007035b..0000000 --- a/debian/systemd.links +++ /dev/null @@ -1,55 +0,0 @@ -# These are all services which have native implementations -# So we mask them by linking against /dev/null or create an alias -/lib/systemd/system/systemd-random-seed-load.service /lib/systemd/system/urandom.service -/lib/systemd/system/systemd-sysctl.service /lib/systemd/system/procps.service - -/lib/systemd/system/systemd-modules-load.service /lib/systemd/system/module-init-tools.service -/etc/modules /etc/modules-load.d/modules.conf - -/dev/null /lib/systemd/system/x11-common.service -/dev/null /lib/systemd/system/hostname.service -/dev/null /lib/systemd/system/rmnologin.service -/dev/null /lib/systemd/system/bootmisc.service - -# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=643700 -/dev/null /lib/systemd/system/fuse.service - -# Although bootlogd is disabled by default (via /etc/default/bootlogd) -# by masking them we avoid spawning a shell uselessly thrice during boot. -# Besides, bootlogd doesn't look particularly useful in a systemd world. -/dev/null /lib/systemd/system/bootlogd.service -/dev/null /lib/systemd/system/stop-bootlogd-single.service -/dev/null /lib/systemd/system/stop-bootlogd.service - -# These are pointless, /etc/mtab should be a symlink -/dev/null /lib/systemd/system/mtab.service -/dev/null /lib/systemd/system/udev-mtab.service - -# TODO: make hwclock a symlink to hwclock-load.service? -# Before this can happen we need to ensure that the 85-hwclock.rules -# udev rule is not triggered when running systemd. -/dev/null /lib/systemd/system/hwclock.service -/dev/null /lib/systemd/system/hwclockfirst.service - -# We use native mount support so mask those services -# TODO: check if any sysv init script depends on those facilities -/dev/null /lib/systemd/system/mountkernfs.service -/dev/null /lib/systemd/system/mountdevsubfs.service -/dev/null /lib/systemd/system/mountall.service -/dev/null /lib/systemd/system/mountall-bootclean.service -/dev/null /lib/systemd/system/mountnfs.service -/dev/null /lib/systemd/system/mountnfs-bootclean.service -/dev/null /lib/systemd/system/checkfs.service -# We need checkroot as synchronisation point, so symlink it to remount-rootfs -/lib/systemd/system/remount-rootfs.service /lib/systemd/system/checkroot.service - -# We use the built-in cryptsetup support -/dev/null /lib/systemd/system/cryptdisks.service -/dev/null /lib/systemd/system/cryptdisks-early.service - -# Single user mode is implemented natively, don't use legacy SysV init scripts -# to avoid spawning sulogin twice. -/dev/null /lib/systemd/system/single.service -/dev/null /lib/systemd/system/killprocs.service - -# TODO: mtab/udev-mtab (symlink /etc/mtab to /proc/self/mounts in postinst) diff --git a/debian/systemd.postinst b/debian/systemd.postinst deleted file mode 100644 index 7f7c2da..0000000 --- a/debian/systemd.postinst +++ /dev/null @@ -1,45 +0,0 @@ -#! /bin/sh - -set -e - -if [ -n "$2" ]; then - systemctl daemon-reexec || true -fi - -# Do a one-time migration of the local time setting -if dpkg --compare-versions "$2" lt "33-1"; then - if [ -f /etc/default/rcS ]; then - . /etc/default/rcS - fi - if [ "$UTC" = "no" ] && [ ! -e /etc/adjtime ]; then - printf "0.0 0 0.0\n0\nLOCAL" > /etc/adjtime - fi -fi - -# Do a one-time migration of the TMPTIME setting -if dpkg --compare-versions "$2" lt "36-2"; then - if [ -f /etc/default/rcS ]; then - . /etc/default/rcS - fi - if [ ! -e /etc/tmpfiles.d/tmp.conf ]; then - case "$TMPTIME" in - -*|infinite|infinity) - cat > /etc/tmpfiles.d/tmp.conf < /dev/null 2>&1 ; then \ + echo " DOC Introspecting gobjects"; \ + scanobj_options=""; \ + gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$(?)" = "0"; then \ + if test "x$(V)" = "x1"; then \ + scanobj_options="--verbose"; \ + fi; \ + fi; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ + gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ + else \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + @touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp + @true + +#### xml #### + +sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) + @echo ' DOC Building XML' + @_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) + @touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### html #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo ' DOC Building HTML' + @rm -rf html + @mkdir html + @mkhtml_options=""; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$(?)" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkhtml_options="$$mkhtml_options --verbose"; \ + fi; \ + fi; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \ + if test "$(?)" = "0"; then \ + mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \ + fi; \ + cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + -@test "x$(HTML_IMAGES)" = "x" || \ + for file in $(HTML_IMAGES) ; do \ + if test -f $(abs_srcdir)/$$file ; then \ + cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ + fi; \ + if test -f $(abs_builddir)/$$file ; then \ + cp $(abs_builddir)/$$file $(abs_builddir)/html; \ + fi; \ + done; + @echo ' DOC Fixing cross-references' + @gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + @touch html-build.stamp + +#### pdf #### + +pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo ' DOC Building PDF' + @rm -f $(DOC_MODULE).pdf + @mkpdf_options=""; \ + gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$(?)" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkpdf_options="$$mkpdf_options --verbose"; \ + fi; \ + fi; \ + if test "x$(HTML_IMAGES)" != "x"; then \ + for img in $(HTML_IMAGES); do \ + part=`dirname $$img`; \ + echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \ + if test $$? != 0; then \ + mkpdf_options="$$mkpdf_options --imgdir=$$part"; \ + fi; \ + done; \ + fi; \ + gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS) + @touch pdf-build.stamp + +############## + +clean-local: + @rm -f *~ *.bak + @rm -rf .libs + +distclean-local: + @rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \ + $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + @if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + rm -f $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types; \ + fi + +maintainer-clean-local: clean + @rm -rf xml html + +install-data-local: + @installfiles=`echo $(builddir)/html/*`; \ + if test "$$installfiles" = '$(builddir)/html/*'; \ + then echo 1>&2 'Nothing to install' ; \ + else \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + $(mkinstalldirs) $${installdir} ; \ + for i in $$installfiles; do \ + echo ' $(INSTALL_DATA) '$$i ; \ + $(INSTALL_DATA) $$i $${installdir}; \ + done; \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ + $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ + fi; \ + $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \ + fi + +uninstall-local: + @if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + rm -rf $${installdir} + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +dist-hook: dist-check-gtkdoc dist-hook-local + @mkdir $(distdir)/html + @cp ./html/* $(distdir)/html + @-cp ./$(DOC_MODULE).pdf $(distdir)/ + @-cp ./$(DOC_MODULE).types $(distdir)/ + @-cp ./$(DOC_MODULE)-sections.txt $(distdir)/ + @cd $(distdir) && rm -f $(DISTCLEANFILES) + @$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html + +.PHONY : dist-hook-local docs diff --git a/docs/gudev/.gitignore b/docs/gudev/.gitignore new file mode 100644 index 0000000..e6f2371 --- /dev/null +++ b/docs/gudev/.gitignore @@ -0,0 +1,19 @@ +/*.bak +/gtk-doc.make +/version.xml +/Makefile +/gudev-overrides.txt +/gudev-decl-list.txt +/gudev-decl.txt +/gudev-undeclared.txt +/gudev-undocumented.txt +/gudev-unused.txt +/gudev.args +/gudev.hierarchy +/gudev.interfaces +/gudev.prerequisites +/gudev.signals +/html/ +/xml/ +/*.stamp +/tmpl/ diff --git a/docs/gudev/Makefile.am b/docs/gudev/Makefile.am new file mode 100644 index 0000000..6593303 --- /dev/null +++ b/docs/gudev/Makefile.am @@ -0,0 +1,115 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.10 at least. +AUTOMAKE_OPTIONS = 1.10 color-tests + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=gudev + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +#DOC_MODULE_VERSION=2 + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=$(top_srcdir)/src/gudev $(top_builddir)/src/gudev + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS= + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=g_udev + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir) + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS=>/dev/null 2>&1 + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(top_srcdir)/src/gudev/*.h +CFILE_GLOB=$(top_srcdir)/src/gudev/*.c + +# Extra header to include when scanning, which are not under DOC_SOURCE_DIR +# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h +EXTRA_HFILES= + +# Header files to ignore when scanning. Use base file name, no paths +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES=gudevenumtypes.h gudevmarshal.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = version.xml + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# Hack, hack. You silly gtk-doc, you must not add CFLAGS multiple +# times when calling gcc; it surely can not work with options that must +# be listed only once. +# Kill CFLAGS here because gtk-doc thinks adding CFLAGS to CC _and_ also +# adding CFLAGS itself again would work. +override CFLAGS= +override LDFLAGS= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_CFLAGS = \ + $(GLIB_CFLAGS) \ + -I$(top_srcdir)/src/gudev \ + -I$(top_builddir)/src/gudev + +GTKDOC_LIBS = \ + $(GLIB_LIBS) \ + $(top_builddir)/libgudev-1.0.la + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/docs/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += version.xml.in + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt +#DISTCLEANFILES += + +# Comment this out if you want your docs-status tested during 'make check' +if ENABLE_GTK_DOC +if ENABLE_GTK_DOC_TESTS +#TESTS_ENVIRONMENT = cd $(top_srcdir) +#TESTS = $(GTKDOC_CHECK) +endif +endif diff --git a/docs/gudev/gudev-docs.xml b/docs/gudev/gudev-docs.xml new file mode 100644 index 0000000..3e7e50a --- /dev/null +++ b/docs/gudev/gudev-docs.xml @@ -0,0 +1,52 @@ + + +]> + + + GUdev Reference Manual + + For version &version; — the latest version of this + documentation can be found at + + http://www.freedesktop.org/software/systemd/gudev/ + . + + + 2009-2012 + David Zeuthen <davidz@redhat.com> + Bastien Nocera <hadess@hadess.net> + + + + + API Reference + + + + + + + Object Hierarchy + + + + + API Index + + + + + Index of new symbols in 165 + + + + + Index of deprecated API + + + + + diff --git a/docs/gudev/gudev-sections.txt b/docs/gudev/gudev-sections.txt new file mode 100644 index 0000000..90765ee --- /dev/null +++ b/docs/gudev/gudev-sections.txt @@ -0,0 +1,102 @@ +
+gudevclient +GUdevClient +GUdevClient +GUdevClientClass +GUdevDeviceType +GUdevDeviceNumber +g_udev_client_new +g_udev_client_query_by_subsystem +g_udev_client_query_by_device_number +g_udev_client_query_by_device_file +g_udev_client_query_by_sysfs_path +g_udev_client_query_by_subsystem_and_name + +G_UDEV_CLIENT +G_UDEV_IS_CLIENT +G_UDEV_TYPE_CLIENT +g_udev_client_get_type +G_UDEV_CLIENT_CLASS +G_UDEV_IS_CLIENT_CLASS +G_UDEV_CLIENT_GET_CLASS + +GUdevClientPrivate +
+ +
+gudevdevice +GUdevDevice +GUdevDevice +GUdevDeviceClass +g_udev_device_get_subsystem +g_udev_device_get_devtype +g_udev_device_get_name +g_udev_device_get_number +g_udev_device_get_sysfs_path +g_udev_device_get_driver +g_udev_device_get_action +g_udev_device_get_seqnum +g_udev_device_get_device_type +g_udev_device_get_device_number +g_udev_device_get_device_file +g_udev_device_get_device_file_symlinks +g_udev_device_get_parent +g_udev_device_get_parent_with_subsystem +g_udev_device_get_tags +g_udev_device_get_is_initialized +g_udev_device_get_usec_since_initialized +g_udev_device_get_property_keys +g_udev_device_has_property +g_udev_device_get_property +g_udev_device_get_property_as_int +g_udev_device_get_property_as_uint64 +g_udev_device_get_property_as_double +g_udev_device_get_property_as_boolean +g_udev_device_get_property_as_strv +g_udev_device_get_sysfs_attr_keys +g_udev_device_has_sysfs_attr +g_udev_device_get_sysfs_attr +g_udev_device_get_sysfs_attr_as_int +g_udev_device_get_sysfs_attr_as_uint64 +g_udev_device_get_sysfs_attr_as_double +g_udev_device_get_sysfs_attr_as_boolean +g_udev_device_get_sysfs_attr_as_strv + +G_UDEV_DEVICE +G_UDEV_IS_DEVICE +G_UDEV_TYPE_DEVICE +g_udev_device_get_type +G_UDEV_DEVICE_CLASS +G_UDEV_IS_DEVICE_CLASS +G_UDEV_DEVICE_GET_CLASS + +GUdevDevicePrivate +
+ +
+gudevenumerator +GUdevEnumerator +GUdevEnumerator +GUdevEnumeratorClass +g_udev_enumerator_new +g_udev_enumerator_add_match_subsystem +g_udev_enumerator_add_nomatch_subsystem +g_udev_enumerator_add_match_sysfs_attr +g_udev_enumerator_add_nomatch_sysfs_attr +g_udev_enumerator_add_match_property +g_udev_enumerator_add_match_name +g_udev_enumerator_add_match_tag +g_udev_enumerator_add_match_is_initialized +g_udev_enumerator_add_sysfs_path +g_udev_enumerator_execute + +G_UDEV_ENUMERATOR +G_UDEV_IS_ENUMERATOR +G_UDEV_TYPE_ENUMERATOR +g_udev_enumerator_get_type +G_UDEV_ENUMERATOR_CLASS +G_UDEV_IS_ENUMERATOR_CLASS +G_UDEV_ENUMERATOR_GET_CLASS + +GUdevEnumeratorPrivate +
diff --git a/docs/gudev/gudev.types b/docs/gudev/gudev.types new file mode 100644 index 0000000..a89857a --- /dev/null +++ b/docs/gudev/gudev.types @@ -0,0 +1,4 @@ +g_udev_device_type_get_type +g_udev_device_get_type +g_udev_client_get_type +g_udev_enumerator_get_type diff --git a/docs/gudev/version.xml.in b/docs/gudev/version.xml.in new file mode 100644 index 0000000..d78bda9 --- /dev/null +++ b/docs/gudev/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/docs/libudev/.gitignore b/docs/libudev/.gitignore new file mode 100644 index 0000000..f8dd67c --- /dev/null +++ b/docs/libudev/.gitignore @@ -0,0 +1,19 @@ +/gtk-doc.make +/version.xml +/Makefile +/libudev-overrides.txt +/libudev-decl-list.txt +/libudev-decl.txt +/libudev-undeclared.txt +/libudev-undocumented.txt +/libudev-unused.txt +/libudev.args +/libudev.hierarchy +/libudev.interfaces +/libudev.prerequisites +/libudev.signals +/html/ +/xml/ +/*.stamp +/*.bak +/tmpl/ diff --git a/docs/libudev/Makefile.am b/docs/libudev/Makefile.am new file mode 100644 index 0000000..cf9a452 --- /dev/null +++ b/docs/libudev/Makefile.am @@ -0,0 +1,109 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.10 at least. +AUTOMAKE_OPTIONS = 1.10 color-tests + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=libudev + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +#DOC_MODULE_VERSION=2 + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=$(top_srcdir)/src/libudev + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS= + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=udev + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir) + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS=>/dev/null 2>&1 + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(top_srcdir)/src/libudev/libudev*.h +CFILE_GLOB=$(top_srcdir)/src/libudev/libudev*.c + +# Extra header to include when scanning, which are not under DOC_SOURCE_DIR +# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h +EXTRA_HFILES= + +# Header files to ignore when scanning. Use base file name, no paths +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES = libudev-private.h libudev-hwdb-def.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = version.xml + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# Hack, hack. You silly gtk-doc, you must not add CFLAGS multiple +# times when calling gcc; it surely can not work with options that must +# be listed only once. +# Kill CFLAGS here because gtk-doc thinks adding CFLAGS to CC _and_ also +# adding CFLAGS itself again would work. +override CFLAGS= +override LDFLAGS= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_CFLAGS= +GTKDOC_LIBS= + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/docs/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += version.xml.in + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt +#DISTCLEANFILES += + +# Comment this out if you want your docs-status tested during 'make check' +if ENABLE_GTK_DOC +if ENABLE_GTK_DOC_TESTS +#TESTS_ENVIRONMENT = cd $(top_srcdir) +#TESTS = $(GTKDOC_CHECK) +endif +endif diff --git a/docs/libudev/libudev-docs.xml b/docs/libudev/libudev-docs.xml new file mode 100644 index 0000000..454cd31 --- /dev/null +++ b/docs/libudev/libudev-docs.xml @@ -0,0 +1,40 @@ + + +]> + + + libudev Reference Manual + + For version &version; — the latest version of this + documentation can be found at + + http://www.freedesktop.org/software/systemd/libudev/ + . + + + 2009-2012 + Kay Sievers <kay@vrfy.org> + + + + + API Reference + + + + + + + + + + + + + Index + + + diff --git a/docs/libudev/libudev-sections.txt b/docs/libudev/libudev-sections.txt new file mode 100644 index 0000000..c154645 --- /dev/null +++ b/docs/libudev/libudev-sections.txt @@ -0,0 +1,135 @@ +
+libudev +udev +udev +udev_ref +udev_unref +udev_new +udev_set_log_fn +udev_get_log_priority +udev_set_log_priority +udev_get_userdata +udev_set_userdata +
+ +
+libudev-list +udev_list +udev_list_entry +udev_list_entry_get_next +udev_list_entry_get_by_name +udev_list_entry_get_name +udev_list_entry_get_value +udev_list_entry_foreach +
+ +
+libudev-device +udev_device +udev_device +udev_device_ref +udev_device_unref +udev_device_get_udev +udev_device_new_from_syspath +udev_device_new_from_devnum +udev_device_new_from_subsystem_sysname +udev_device_new_from_device_id +udev_device_new_from_environment +udev_device_get_parent +udev_device_get_parent_with_subsystem_devtype +udev_device_get_devpath +udev_device_get_subsystem +udev_device_get_devtype +udev_device_get_syspath +udev_device_get_sysname +udev_device_get_sysnum +udev_device_get_devnode +udev_device_get_is_initialized +udev_device_get_devlinks_list_entry +udev_device_get_properties_list_entry +udev_device_get_tags_list_entry +udev_device_get_property_value +udev_device_get_driver +udev_device_get_devnum +udev_device_get_action +udev_device_get_sysattr_value +udev_device_set_sysattr_value +udev_device_get_sysattr_list_entry +udev_device_get_seqnum +udev_device_get_usec_since_initialized +udev_device_has_tag +
+ +
+libudev-monitor +udev_monitor +udev_monitor +udev_monitor_ref +udev_monitor_unref +udev_monitor_get_udev +udev_monitor_new_from_netlink +udev_monitor_enable_receiving +udev_monitor_set_receive_buffer_size +udev_monitor_get_fd +udev_monitor_receive_device +udev_monitor_filter_add_match_subsystem_devtype +udev_monitor_filter_add_match_tag +udev_monitor_filter_update +udev_monitor_filter_remove +
+ +
+libudev-enumerate +udev_enumerate +udev_enumerate +udev_enumerate_ref +udev_enumerate_unref +udev_enumerate_get_udev +udev_enumerate_new +udev_enumerate_add_match_subsystem +udev_enumerate_add_nomatch_subsystem +udev_enumerate_add_match_sysattr +udev_enumerate_add_nomatch_sysattr +udev_enumerate_add_match_property +udev_enumerate_add_match_tag +udev_enumerate_add_match_parent +udev_enumerate_add_match_is_initialized +udev_enumerate_add_match_sysname +udev_enumerate_add_syspath +udev_enumerate_scan_devices +udev_enumerate_scan_subsystems +udev_enumerate_get_list_entry +
+ +
+libudev-queue +udev_queue +udev_queue +udev_queue_ref +udev_queue_unref +udev_queue_get_udev +udev_queue_new +udev_queue_get_udev_is_active +udev_queue_get_queue_is_empty +udev_queue_get_seqnum_is_finished +udev_queue_get_seqnum_sequence_is_finished +udev_queue_get_queued_list_entry +udev_queue_get_kernel_seqnum +udev_queue_get_udev_seqnum +
+ +
+libudev-hwdb +udev_hwdb +udev_hwdb +udev_hwdb_ref +udev_hwdb_unref +udev_hwdb_new +udev_hwdb_get_properties_list_entry +
+ +
+libudev-util +udev_util +udev_util_encode_string +
diff --git a/docs/libudev/libudev.types b/docs/libudev/libudev.types new file mode 100644 index 0000000..e69de29 diff --git a/docs/libudev/version.xml.in b/docs/libudev/version.xml.in new file mode 100644 index 0000000..d78bda9 --- /dev/null +++ b/docs/libudev/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/docs/sysvinit/.gitignore b/docs/sysvinit/.gitignore new file mode 100644 index 0000000..c3fea74 --- /dev/null +++ b/docs/sysvinit/.gitignore @@ -0,0 +1 @@ +/README diff --git a/units/fedora/Makefile b/docs/sysvinit/Makefile similarity index 100% rename from units/fedora/Makefile rename to docs/sysvinit/Makefile diff --git a/docs/sysvinit/README.in b/docs/sysvinit/README.in new file mode 100644 index 0000000..996402d --- /dev/null +++ b/docs/sysvinit/README.in @@ -0,0 +1,27 @@ +You are looking for the traditional init scripts in @SYSTEM_SYSVINIT_PATH@, +and they are gone? + +Here's an explanation on what's going on: + +You are running a systemd-based OS where traditional init scripts have +been replaced by native systemd services files. Service files provide +very similar functionality to init scripts. To make use of service +files simply invoke "systemctl", which will output a list of all +currently running services (and other units). Use "systemctl +list-unit-files" to get a listing of all known unit files, including +stopped, disabled and masked ones. Use "systemctl start +foobar.service" and "systemctl stop foobar.service" to start or stop a +service, respectively. For further details, please refer to +systemctl(1). + +Note that traditional init scripts continue to function on a systemd +system. An init script @SYSTEM_SYSVINIT_PATH@/foobar is implicitly mapped +into a service unit foobar.service during system initialization. + +Thank you! + +Further reading: + man:systemctl(1) + man:systemd(1) + http://0pointer.de/blog/projects/systemd-for-admins-3.html + http://www.freedesktop.org/wiki/Software/systemd/Incompatibilities diff --git a/docs/var-log/.gitignore b/docs/var-log/.gitignore new file mode 100644 index 0000000..c3fea74 --- /dev/null +++ b/docs/var-log/.gitignore @@ -0,0 +1 @@ +/README diff --git a/docs/var-log/Makefile b/docs/var-log/Makefile new file mode 120000 index 0000000..50be211 --- /dev/null +++ b/docs/var-log/Makefile @@ -0,0 +1 @@ +../../src/Makefile \ No newline at end of file diff --git a/docs/var-log/README.in b/docs/var-log/README.in new file mode 100644 index 0000000..2e64fb1 --- /dev/null +++ b/docs/var-log/README.in @@ -0,0 +1,26 @@ +You are looking for the traditional text log files in @VARLOGDIR@, and +they are gone? + +Here's an explanation on what's going on: + +You are running a systemd-based OS where traditional syslog has been +replaced with the Journal. The journal stores the same (and more) +information as classic syslog. To make use of the journal and access +the collected log data simply invoke "journalctl", which will output +the logs in the identical text-based format the syslog files in +@VARLOGDIR@ used to be. For further details, please refer to +journalctl(1). + +Alternatively, consider installing one of the traditional syslog +implementations available for your distribution, which will generate +the classic log files for you. Syslog implementations such as +syslog-ng or rsyslog may be installed side-by-side with the journal +and will continue to function the way they always did. + +Thank you! + +Further reading: + man:journalctl(1) + man:systemd-journald.service(8) + man:journald.conf(5) + http://0pointer.de/blog/projects/the-journal.html diff --git a/hwdb/.gitignore b/hwdb/.gitignore new file mode 100644 index 0000000..a29233b --- /dev/null +++ b/hwdb/.gitignore @@ -0,0 +1,4 @@ +/pci.ids +/usb.ids +/oui.txt +/iab.txt diff --git a/hwdb/20-OUI.hwdb b/hwdb/20-OUI.hwdb new file mode 100644 index 0000000..a51a00a --- /dev/null +++ b/hwdb/20-OUI.hwdb @@ -0,0 +1,70100 @@ +# This file is part of systemd. +# +# Data imported from: +# http://standards.ieee.org/develop/regauth/oui/oui.txt +# http://standards.ieee.org/develop/regauth/iab/iab.txt + +OUI:0050C2000* + ID_OUI_FROM_DATABASE=T.L.S. Corp. + +OUI:0050C2001* + ID_OUI_FROM_DATABASE=JMBS Developpements + +OUI:0050C2002* + ID_OUI_FROM_DATABASE=Integrated Automation Solutions + +OUI:0050C2003* + ID_OUI_FROM_DATABASE=Microsoft + +OUI:0050C2004* + ID_OUI_FROM_DATABASE=SCI Technology Inc. + +OUI:0050C2005* + ID_OUI_FROM_DATABASE=GD California, Inc. + +OUI:0050C2006* + ID_OUI_FROM_DATABASE=Project Management Enterprises, Inc. + +OUI:0050C2007* + ID_OUI_FROM_DATABASE=Clive Green & Co. Ltd. + +OUI:0050C2008* + ID_OUI_FROM_DATABASE=Portable Add-Ons + +OUI:0050C2009* + ID_OUI_FROM_DATABASE=Datakinetics Ltd. + +OUI:0050C200A* + ID_OUI_FROM_DATABASE=Tharsys + +OUI:0050C200B* + ID_OUI_FROM_DATABASE=IO Limited + +OUI:0050C200C* + ID_OUI_FROM_DATABASE=Vbrick Systems Inc. + +OUI:0050C200D* + ID_OUI_FROM_DATABASE=Opus Telecom Inc. + +OUI:0050C200E* + ID_OUI_FROM_DATABASE=TTTech + +OUI:0050C200F* + ID_OUI_FROM_DATABASE=XLN-t + +OUI:0050C2010* + ID_OUI_FROM_DATABASE=Moisture Systems + +OUI:0050C2011* + ID_OUI_FROM_DATABASE=Bihl + Wiedemann GmbH + +OUI:0050C2012* + ID_OUI_FROM_DATABASE=Floware System Solutions Ltd. + +OUI:0050C2013* + ID_OUI_FROM_DATABASE=Sensys Technologies Inc. + +OUI:0050C2014* + ID_OUI_FROM_DATABASE=Canal + + +OUI:0050C2015* + ID_OUI_FROM_DATABASE=Leroy Automatique Industrielle + +OUI:0050C2016* + ID_OUI_FROM_DATABASE=DSP Design Ltd. + +OUI:0050C2017* + ID_OUI_FROM_DATABASE=Hunter Technology Inc. + +OUI:0050C2018* + ID_OUI_FROM_DATABASE=CAD-UL GmbH + +OUI:0050C2019* + ID_OUI_FROM_DATABASE=Emtac Technology Corp. + +OUI:0050C201A* + ID_OUI_FROM_DATABASE=Skylake Talix + +OUI:0050C201B* + ID_OUI_FROM_DATABASE=Cross Products Ltd. + +OUI:0050C201C* + ID_OUI_FROM_DATABASE=Tadiran Scopus + +OUI:0050C201D* + ID_OUI_FROM_DATABASE=Princeton Gamma Tech + +OUI:0050C201E* + ID_OUI_FROM_DATABASE=CallTech International Limited + +OUI:0050C201F* + ID_OUI_FROM_DATABASE=KBS Industrieelektronik GmbH + +OUI:0050C2020* + ID_OUI_FROM_DATABASE=Icon Research Ltd. + +OUI:0050C2021* + ID_OUI_FROM_DATABASE=DRS Technologies Canada Co. + +OUI:0050C2022* + ID_OUI_FROM_DATABASE=Ashling Microsystems Ltd. + +OUI:0050C2023* + ID_OUI_FROM_DATABASE=Zabacom, Inc. + +OUI:0050C2024* + ID_OUI_FROM_DATABASE=IPITEK + +OUI:0050C2025* + ID_OUI_FROM_DATABASE=Teracom Telematica Ltda. + +OUI:0050C2026* + ID_OUI_FROM_DATABASE=Abatis Systems Corp. + +OUI:0050C2027* + ID_OUI_FROM_DATABASE=Industrial Control Links + +OUI:0050C2028* + ID_OUI_FROM_DATABASE=The Frensch Corporation (Pty) Ltd. + +OUI:0050C2029* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + +OUI:0050C202A* + ID_OUI_FROM_DATABASE=VersaLogic Corp. + +OUI:0050C202B* + ID_OUI_FROM_DATABASE=Nova Engineering Inc. + +OUI:0050C202C* + ID_OUI_FROM_DATABASE=Narrowband Telecommunications + +OUI:0050C202D* + ID_OUI_FROM_DATABASE=Innocor LTD + +OUI:0050C202E* + ID_OUI_FROM_DATABASE=Turtle Mountain Corp + +OUI:0050C202F* + ID_OUI_FROM_DATABASE=Sinetica Corp + +OUI:0050C2030* + ID_OUI_FROM_DATABASE=Lockheed Martin Tactical Defense Systems Eagan + +OUI:0050C2031* + ID_OUI_FROM_DATABASE=Eloquence Ltd + +OUI:0050C2032* + ID_OUI_FROM_DATABASE=MotionIO + +OUI:0050C2033* + ID_OUI_FROM_DATABASE=Doble Engineering Company + +OUI:0050C2034* + ID_OUI_FROM_DATABASE=Ing. Buero W. Kanis GmbH + +OUI:0050C2035* + ID_OUI_FROM_DATABASE=Alliant Techsystems, Inc. + +OUI:0050C2036* + ID_OUI_FROM_DATABASE=Arcturus Networks Inc. + +OUI:0050C2037* + ID_OUI_FROM_DATABASE=E.I.S.M. + +OUI:0050C2038* + ID_OUI_FROM_DATABASE=Etheira Technologies + +OUI:0050C2039* + ID_OUI_FROM_DATABASE=Apex Signal Corp + +OUI:0050C203A* + ID_OUI_FROM_DATABASE=PLLB Elettronica SPA + +OUI:0050C203B* + ID_OUI_FROM_DATABASE=VNR Electronique SA + +OUI:0050C203C* + ID_OUI_FROM_DATABASE=BrainBoxes Ltd + +OUI:0050C203D* + ID_OUI_FROM_DATABASE=ISDN Gateway Technology AG + +OUI:0050C203E* + ID_OUI_FROM_DATABASE=MSU UK Ltd + +OUI:0050C203F* + ID_OUI_FROM_DATABASE=Celotek Corp + +OUI:0050C2040* + ID_OUI_FROM_DATABASE=MiSPO Co., Ltd. + +OUI:0050C2041* + ID_OUI_FROM_DATABASE=Damler Chrysler Rail System (Signal) AB + +OUI:0050C2042* + ID_OUI_FROM_DATABASE=B.E.A.R. Solutions (Australasia) Pty, Ltd + +OUI:0050C2043* + ID_OUI_FROM_DATABASE=Curtis, Inc. + +OUI:0050C2045* + ID_OUI_FROM_DATABASE=Chase Manhattan Bank + +OUI:0050C2047* + ID_OUI_FROM_DATABASE=B. R. Electronics + +OUI:0050C2048* + ID_OUI_FROM_DATABASE=Cybectec Inc. + +OUI:0050C2049* + ID_OUI_FROM_DATABASE=Computer Concepts Corp + +OUI:0050C204A* + ID_OUI_FROM_DATABASE=Telecom Analysis Systems, LP + +OUI:0050C204B* + ID_OUI_FROM_DATABASE=Tecstar Demo Systems Division + +OUI:0050C204C* + ID_OUI_FROM_DATABASE=New Standard Engineering NV + +OUI:0050C204E* + ID_OUI_FROM_DATABASE=Industrial Electronic Engineers, Inc. + +OUI:0050C204F* + ID_OUI_FROM_DATABASE=Luma Corporation + +OUI:0050C2050* + ID_OUI_FROM_DATABASE=Dataprobe, Inc. + +OUI:0050C2051* + ID_OUI_FROM_DATABASE=JSR Ultrasonics + +OUI:0050C2052* + ID_OUI_FROM_DATABASE=Mayo Foundation + +OUI:0050C2054* + ID_OUI_FROM_DATABASE=Optionexist Limited + +OUI:0050C2055* + ID_OUI_FROM_DATABASE=San Castle Technologies, Inc. + +OUI:0050C2056* + ID_OUI_FROM_DATABASE=Base 2 + +OUI:0050C2057* + ID_OUI_FROM_DATABASE=Lite F GmBH + +OUI:0050C2058* + ID_OUI_FROM_DATABASE=Vision Research, Inc. + +OUI:0050C2059* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty, Ltd + +OUI:0050C205A* + ID_OUI_FROM_DATABASE=Sonifex Ltd + +OUI:0050C205B* + ID_OUI_FROM_DATABASE=Radiometer Medical A/S + +OUI:0050C205C* + ID_OUI_FROM_DATABASE=Nortel Networks PLC (UK) + +OUI:0050C205D* + ID_OUI_FROM_DATABASE=Ignitus Communications, LLC + +OUI:0050C205E* + ID_OUI_FROM_DATABASE=DIVA Systems + +OUI:0050C205F* + ID_OUI_FROM_DATABASE=Malden Electronics Ltd + +OUI:0050C2061* + ID_OUI_FROM_DATABASE=Simple Network Magic Corporation + +OUI:0050C2063* + ID_OUI_FROM_DATABASE=Ticketmaster Corp + +OUI:0050C2065* + ID_OUI_FROM_DATABASE=Clever Devices, Ltd. + +OUI:0050C2067* + ID_OUI_FROM_DATABASE=Riverlink Computers, Ltd. + +OUI:0050C2068* + ID_OUI_FROM_DATABASE=Seabridge + +OUI:0050C2069* + ID_OUI_FROM_DATABASE=EC Elettronica S.R.L. + +OUI:0050C206A* + ID_OUI_FROM_DATABASE=Unimark + +OUI:0050C206B* + ID_OUI_FROM_DATABASE=NCast Corporation + +OUI:0050C206C* + ID_OUI_FROM_DATABASE=WaveCom Electronics, Inc. + +OUI:0050C206D* + ID_OUI_FROM_DATABASE=Advanced Signal Corp. + +OUI:0050C206E* + ID_OUI_FROM_DATABASE=Avtron Manufacturing Inc. + +OUI:0050C206F* + ID_OUI_FROM_DATABASE=Digital Services Group + +OUI:0050C2070* + ID_OUI_FROM_DATABASE=Katchall Technologies Group + +OUI:0050C2071* + ID_OUI_FROM_DATABASE=NetVision Telecom + +OUI:0050C2072* + ID_OUI_FROM_DATABASE=Neuberger Gebaeudeautomation GmbH & Co. + +OUI:0050C2073* + ID_OUI_FROM_DATABASE=Alstom Signalling Ltd. + +OUI:0050C2074* + ID_OUI_FROM_DATABASE=Edge Tech Co., Ltd. + +OUI:0050C2075* + ID_OUI_FROM_DATABASE=ENTTEC Pty Ltd. + +OUI:0050C2076* + ID_OUI_FROM_DATABASE=Litton Guidance & Control Systems + +OUI:0050C2077* + ID_OUI_FROM_DATABASE=Saco Smartvision Inc. + +OUI:0050C2078* + ID_OUI_FROM_DATABASE=Reselec AG + +OUI:0050C2079* + ID_OUI_FROM_DATABASE=Flextel S.p.A + +OUI:0050C207A* + ID_OUI_FROM_DATABASE=RadioTel + +OUI:0050C207B* + ID_OUI_FROM_DATABASE=Trikon Technologies Ltd. + +OUI:0050C207C* + ID_OUI_FROM_DATABASE=PLLB elettronica spa + +OUI:0050C207D* + ID_OUI_FROM_DATABASE=Caspian Networks + +OUI:0050C207E* + ID_OUI_FROM_DATABASE=JL-teknik + +OUI:0050C207F* + ID_OUI_FROM_DATABASE=Dunti Corporation + +OUI:0050C2080* + ID_OUI_FROM_DATABASE=AIM + +OUI:0050C2081* + ID_OUI_FROM_DATABASE=Matuschek Messtechnik GmbH + +OUI:0050C2082* + ID_OUI_FROM_DATABASE=GFI Chrono Time + +OUI:0050C2083* + ID_OUI_FROM_DATABASE=ARD SA + +OUI:0050C2084* + ID_OUI_FROM_DATABASE=DIALOG4 System Engineering GmbH + +OUI:0050C2085* + ID_OUI_FROM_DATABASE=Crossport Systems + +OUI:0050C2086* + ID_OUI_FROM_DATABASE=Validyne Engineering Corp. + +OUI:0050C2087* + ID_OUI_FROM_DATABASE=Monitor Business Machines Ltd. + +OUI:0050C2088* + ID_OUI_FROM_DATABASE=TELINC Corporation + +OUI:0050C2089* + ID_OUI_FROM_DATABASE=Fenwal Italia S.P.A. + +OUI:0050C208A* + ID_OUI_FROM_DATABASE=Rising Edge Technologies + +OUI:0050C208B* + ID_OUI_FROM_DATABASE=HYPERCHIP Inc. + +OUI:0050C208C* + ID_OUI_FROM_DATABASE=IP Unity + +OUI:0050C208D* + ID_OUI_FROM_DATABASE=Kylink Communications Corp. + +OUI:0050C208E* + ID_OUI_FROM_DATABASE=BSQUARE + +OUI:0050C208F* + ID_OUI_FROM_DATABASE=General Industries Argentina + +OUI:0050C2090* + ID_OUI_FROM_DATABASE=Invensys Controls Network Systems + +OUI:0050C2091* + ID_OUI_FROM_DATABASE=StorLogic, Inc. + +OUI:0050C2092* + ID_OUI_FROM_DATABASE=DigitAll World Co., Ltd + +OUI:0050C2093* + ID_OUI_FROM_DATABASE=KOREALINK + +OUI:0050C2094* + ID_OUI_FROM_DATABASE=Analytical Spectral Devices, Inc. + +OUI:0050C2095* + ID_OUI_FROM_DATABASE=SEATECH + +OUI:0050C2096* + ID_OUI_FROM_DATABASE=Utronix Elektronikutreckling AB + +OUI:0050C2097* + ID_OUI_FROM_DATABASE=IMV Invertomatic + +OUI:0050C2098* + ID_OUI_FROM_DATABASE=EPEL Industrial, S.A. + +OUI:0050C2099* + ID_OUI_FROM_DATABASE=Case Information & Communications + +OUI:0050C209A* + ID_OUI_FROM_DATABASE=NBO Development Center Sekusui Chemical Co. Ltd. + +OUI:0050C209B* + ID_OUI_FROM_DATABASE=Seffle Instrument AB + +OUI:0050C209C* + ID_OUI_FROM_DATABASE=RF Applications, Inc. + +OUI:0050C209D* + ID_OUI_FROM_DATABASE=ZELPOS + +OUI:0050C209E* + ID_OUI_FROM_DATABASE=Infinitec Networks, Inc. + +OUI:0050C209F* + ID_OUI_FROM_DATABASE=MetaWave Vedeo Systems + +OUI:0050C20A0* + ID_OUI_FROM_DATABASE=CYNAPS + +OUI:0050C20A1* + ID_OUI_FROM_DATABASE=Visable Genetics, Inc. + +OUI:0050C20A2* + ID_OUI_FROM_DATABASE=Jäger Computergesteuerte Messtechnik GmbH + +OUI:0050C20A3* + ID_OUI_FROM_DATABASE=BaSyTec GmbH + +OUI:0050C20A4* + ID_OUI_FROM_DATABASE=Bounty Systems Pty Ltd. + +OUI:0050C20A5* + ID_OUI_FROM_DATABASE=Mobiltex Data Ltd. + +OUI:0050C20A6* + ID_OUI_FROM_DATABASE=Arula Systems, Inc. + +OUI:0050C20A7* + ID_OUI_FROM_DATABASE=WaterCove Networks + +OUI:0050C20A8* + ID_OUI_FROM_DATABASE=Kaveri Networks + +OUI:0050C20A9* + ID_OUI_FROM_DATABASE=Radiant Networks Plc + +OUI:0050C20AA* + ID_OUI_FROM_DATABASE=Log-In, Inc. + +OUI:0050C20AB* + ID_OUI_FROM_DATABASE=Fastware.Net, LLC + +OUI:0050C20AC* + ID_OUI_FROM_DATABASE=Honeywell GNO + +OUI:0050C20AD* + ID_OUI_FROM_DATABASE=BMC Messsysteme GmbH + +OUI:0050C20AE* + ID_OUI_FROM_DATABASE=Zarak Systems Corp. + +OUI:0050C20AF* + ID_OUI_FROM_DATABASE=Latus Lightworks, Inc. + +OUI:0050C20B0* + ID_OUI_FROM_DATABASE=LMI Technologies, Inc. + +OUI:0050C20B1* + ID_OUI_FROM_DATABASE=Beeline Networks, Inc. + +OUI:0050C20B2* + ID_OUI_FROM_DATABASE=R F Micro Devices + +OUI:0050C20B3* + ID_OUI_FROM_DATABASE=SMX Corporation + +OUI:0050C20B4* + ID_OUI_FROM_DATABASE=Wavefly Corporation + +OUI:0050C20B5* + ID_OUI_FROM_DATABASE=Extreme Copper, Inc. + +OUI:0050C20B6* + ID_OUI_FROM_DATABASE=ApSecure Technologies (Canada), Inc. + +OUI:0050C20B7* + ID_OUI_FROM_DATABASE=RYMIC + +OUI:0050C20B8* + ID_OUI_FROM_DATABASE=LAN Controls, Inc. + +OUI:0050C20B9* + ID_OUI_FROM_DATABASE=Helmut Mauell GmbH + +OUI:0050C20BA* + ID_OUI_FROM_DATABASE=Pro-Active + +OUI:0050C20BB* + ID_OUI_FROM_DATABASE=MAZet GmbH + +OUI:0050C20BC* + ID_OUI_FROM_DATABASE=Infolink Software AG + +OUI:0050C20BD* + ID_OUI_FROM_DATABASE=Tattile + +OUI:0050C20BE* + ID_OUI_FROM_DATABASE=Stella Electronics & Tagging + +OUI:0050C20C0* + ID_OUI_FROM_DATABASE=Imigix Ltd. + +OUI:0050C20C1* + ID_OUI_FROM_DATABASE=Casabyte + +OUI:0050C20C2* + ID_OUI_FROM_DATABASE=Alchemy Semiconductor, Inc. + +OUI:0050C20C3* + ID_OUI_FROM_DATABASE=Tonbu, Inc. + +OUI:0050C20C4* + ID_OUI_FROM_DATABASE=InterEpoch Technology, Inc. + +OUI:0050C20C5* + ID_OUI_FROM_DATABASE=SAIA Burgess Controls AG + +OUI:0050C20C6* + ID_OUI_FROM_DATABASE=Advanced Medical Information Technologies, Inc. + +OUI:0050C20C7* + ID_OUI_FROM_DATABASE=TransComm Technology System, Inc. + +OUI:0050C20C8* + ID_OUI_FROM_DATABASE=The Trane Company + +OUI:0050C20C9* + ID_OUI_FROM_DATABASE=DSS Networks, Inc. + +OUI:0050C20CA* + ID_OUI_FROM_DATABASE=J D Richards + +OUI:0050C20CB* + ID_OUI_FROM_DATABASE=STUDIEL + +OUI:0050C20CC* + ID_OUI_FROM_DATABASE=AlphaMedia Co., Ltd + +OUI:0050C20CD* + ID_OUI_FROM_DATABASE=LINET OY + +OUI:0050C20CE* + ID_OUI_FROM_DATABASE=RFL Electronics, Inc. + +OUI:0050C20CF* + ID_OUI_FROM_DATABASE=PCSC + +OUI:0050C20D0* + ID_OUI_FROM_DATABASE=Telefrang AB + +OUI:0050C20D1* + ID_OUI_FROM_DATABASE=Renaissance Networking, Inc. + +OUI:0050C20D2* + ID_OUI_FROM_DATABASE=Real World Computing Partnership + +OUI:0050C20D3* + ID_OUI_FROM_DATABASE=Lake Technology, Ltd. + +OUI:0050C20D4* + ID_OUI_FROM_DATABASE=Palm, Inc. + +OUI:0050C20D5* + ID_OUI_FROM_DATABASE=Zelax + +OUI:0050C20D6* + ID_OUI_FROM_DATABASE=Inco Startec GmbH + +OUI:0050C20D7* + ID_OUI_FROM_DATABASE=Summit Avionics, Inc. + +OUI:0050C20D8* + ID_OUI_FROM_DATABASE=Charlotte's Web Networks + +OUI:0050C20D9* + ID_OUI_FROM_DATABASE=Loewe Opta GmbH + +OUI:0050C20DA* + ID_OUI_FROM_DATABASE=Motion Analysis Corp. + +OUI:0050C20DB* + ID_OUI_FROM_DATABASE=Cyberex + +OUI:0050C20DC* + ID_OUI_FROM_DATABASE=Elbit Systems Ltd. + +OUI:0050C20DD* + ID_OUI_FROM_DATABASE=Interisa Electronica, S.A. + +OUI:0050C20DE* + ID_OUI_FROM_DATABASE=Frederick Engineering + +OUI:0050C20DF* + ID_OUI_FROM_DATABASE=Innovation Institute, Inc. + +OUI:0050C20E0* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C20E1* + ID_OUI_FROM_DATABASE=Inspiration Technology P/L + +OUI:0050C20E2* + ID_OUI_FROM_DATABASE=Visual Circuits Corp. + +OUI:0050C20E3* + ID_OUI_FROM_DATABASE=Lanex S.A. + +OUI:0050C20E4* + ID_OUI_FROM_DATABASE=Collabo Tec. Co., Ltd. + +OUI:0050C20E5* + ID_OUI_FROM_DATABASE=Clearwater Networks + +OUI:0050C20E6* + ID_OUI_FROM_DATABASE=RouteFree, Inc. + +OUI:0050C20E7* + ID_OUI_FROM_DATABASE=Century Geophysical Corp. + +OUI:0050C20E8* + ID_OUI_FROM_DATABASE=Audio Design Associates, Inc. + +OUI:0050C20E9* + ID_OUI_FROM_DATABASE=Smartmedia LLC + +OUI:0050C20EA* + ID_OUI_FROM_DATABASE=iReady Corporation + +OUI:0050C20EB* + ID_OUI_FROM_DATABASE=iREZ Technologies LLC + +OUI:0050C20EC* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C20ED* + ID_OUI_FROM_DATABASE=Valley Products Corporation + +OUI:0050C20EE* + ID_OUI_FROM_DATABASE=Industrial Indexing Systems, Inc. + +OUI:0050C20EF* + ID_OUI_FROM_DATABASE=Movaz Networks, Inc. + +OUI:0050C20F0* + ID_OUI_FROM_DATABASE=VHB Technologies, Inc. + +OUI:0050C20F1* + ID_OUI_FROM_DATABASE=Polyvision Corporation + +OUI:0050C20F2* + ID_OUI_FROM_DATABASE=KMS Systems, Inc. + +OUI:0050C20F3* + ID_OUI_FROM_DATABASE=Young Computer Co., Ltd. + +OUI:0050C20F4* + ID_OUI_FROM_DATABASE=Sysnet Co., Ltd. + +OUI:0050C20F5* + ID_OUI_FROM_DATABASE=Spectra Technologies Holding Co., Ltd. + +OUI:0050C20F6* + ID_OUI_FROM_DATABASE=Carl Baasel Lasertechnik GmbH + +OUI:0050C20F7* + ID_OUI_FROM_DATABASE=Foss NIRSystems, Inc. + +OUI:0050C20F8* + ID_OUI_FROM_DATABASE=Tecnint HTE S.r.L. + +OUI:0050C20F9* + ID_OUI_FROM_DATABASE=Raven Industries + +OUI:0050C20FA* + ID_OUI_FROM_DATABASE=GE Lubrizol, LLC + +OUI:0050C20FB* + ID_OUI_FROM_DATABASE=PIUSYS Co., Ltd. + +OUI:0050C20FC* + ID_OUI_FROM_DATABASE=Kimmon Manufacturing Co., Ltd. + +OUI:0050C20FD* + ID_OUI_FROM_DATABASE=Inducomp Corporation + +OUI:0050C20FE* + ID_OUI_FROM_DATABASE=Energy ICT + +OUI:0050C20FF* + ID_OUI_FROM_DATABASE=IPAXS Corporation + +OUI:0050C2100* + ID_OUI_FROM_DATABASE=Corelatus A.B. + +OUI:0050C2101* + ID_OUI_FROM_DATABASE=LAUD Electronic Design AS + +OUI:0050C2102* + ID_OUI_FROM_DATABASE=Million Tech Development Ltd. + +OUI:0050C2103* + ID_OUI_FROM_DATABASE=Green Hills Software, Inc. + +OUI:0050C2104* + ID_OUI_FROM_DATABASE=Adescom Inc. + +OUI:0050C2105* + ID_OUI_FROM_DATABASE=Lumentis AB + +OUI:0050C2106* + ID_OUI_FROM_DATABASE=MATSUOKA + +OUI:0050C2107* + ID_OUI_FROM_DATABASE=NewHer Systems + +OUI:0050C2108* + ID_OUI_FROM_DATABASE=Balogh S.A. + +OUI:0050C2109* + ID_OUI_FROM_DATABASE=ITK Dr. Kassen GmbH + +OUI:0050C210A* + ID_OUI_FROM_DATABASE=Quinx AG + +OUI:0050C210B* + ID_OUI_FROM_DATABASE=MarekMicro GmbH + +OUI:0050C210C* + ID_OUI_FROM_DATABASE=Photonic Bridges, Inc. + +OUI:0050C210D* + ID_OUI_FROM_DATABASE=Implementa GmbH + +OUI:0050C210E* + ID_OUI_FROM_DATABASE=Unipower AB + +OUI:0050C210F* + ID_OUI_FROM_DATABASE=Perceptics Corp. + +OUI:0050C2110* + ID_OUI_FROM_DATABASE=QuesCom + +OUI:0050C2111* + ID_OUI_FROM_DATABASE=Endusis Limited + +OUI:0050C2112* + ID_OUI_FROM_DATABASE=Compuworx + +OUI:0050C2113* + ID_OUI_FROM_DATABASE=Ace Electronics, Inc. + +OUI:0050C2114* + ID_OUI_FROM_DATABASE=Quest Innovations + +OUI:0050C2115* + ID_OUI_FROM_DATABASE=Vidco, Inc. + +OUI:0050C2116* + ID_OUI_FROM_DATABASE=DSP Design, Ltd. + +OUI:0050C2117* + ID_OUI_FROM_DATABASE=Wintegra Ltd. + +OUI:0050C2118* + ID_OUI_FROM_DATABASE=Microbit 2.0 AB + +OUI:0050C2119* + ID_OUI_FROM_DATABASE=Global Opto Communication Tech. Corp + +OUI:0050C211A* + ID_OUI_FROM_DATABASE=Teamaxess Ticketing GmbH + +OUI:0050C211B* + ID_OUI_FROM_DATABASE=Digital Vision AB + +OUI:0050C211C* + ID_OUI_FROM_DATABASE=Stonefly Networks + +OUI:0050C211D* + ID_OUI_FROM_DATABASE=Destiny Networks, Inc. + +OUI:0050C211E* + ID_OUI_FROM_DATABASE=Volvo Car Corporation + +OUI:0050C211F* + ID_OUI_FROM_DATABASE=CSS Industrie Computer GmbH + +OUI:0050C2120* + ID_OUI_FROM_DATABASE=XStore, Inc. + +OUI:0050C2121* + ID_OUI_FROM_DATABASE=COE Limited + +OUI:0050C2122* + ID_OUI_FROM_DATABASE=Diva Systems + +OUI:0050C2123* + ID_OUI_FROM_DATABASE=Seranoa Networks, Inc. + +OUI:0050C2124* + ID_OUI_FROM_DATABASE=Tokai Soft Corporation + +OUI:0050C2125* + ID_OUI_FROM_DATABASE=Tecwings GmBh + +OUI:0050C2126* + ID_OUI_FROM_DATABASE=Marvell Hispana S.L. + +OUI:0050C2127* + ID_OUI_FROM_DATABASE=TPA Traffic & Parking Automation BV + +OUI:0050C2128* + ID_OUI_FROM_DATABASE=Pycon, Inc. + +OUI:0050C2129* + ID_OUI_FROM_DATABASE=TTPCom Ltd. + +OUI:0050C212A* + ID_OUI_FROM_DATABASE=Symbolic Sound Corp. + +OUI:0050C212B* + ID_OUI_FROM_DATABASE=Dong A Eltek Co., Ltd. + +OUI:0050C212C* + ID_OUI_FROM_DATABASE=Delta Tau Data Systems, Inc. + +OUI:0050C212D* + ID_OUI_FROM_DATABASE=Megisto Systems, Inc. + +OUI:0050C212E* + ID_OUI_FROM_DATABASE=RUNCOM + +OUI:0050C212F* + ID_OUI_FROM_DATABASE=HAAG-STREIT AG + +OUI:0050C2130* + ID_OUI_FROM_DATABASE=U.S. Traffic Corporation + +OUI:0050C2131* + ID_OUI_FROM_DATABASE=InBus Engineering, Inc. + +OUI:0050C2132* + ID_OUI_FROM_DATABASE=Procon Electronics + +OUI:0050C2133* + ID_OUI_FROM_DATABASE=ChipWrights, Inc. + +OUI:0050C2134* + ID_OUI_FROM_DATABASE=DRS Photronics + +OUI:0050C2135* + ID_OUI_FROM_DATABASE=ELAD SRL + +OUI:0050C2136* + ID_OUI_FROM_DATABASE=Tensilica, Inc. + +OUI:0050C2137* + ID_OUI_FROM_DATABASE=Uniwell Systems (UK) Ltd. + +OUI:0050C2138* + ID_OUI_FROM_DATABASE=Delphin Technology AG + +OUI:0050C2139* + ID_OUI_FROM_DATABASE=SR Research Ltd. + +OUI:0050C213A* + ID_OUI_FROM_DATABASE=Tex Computer SRL + +OUI:0050C213B* + ID_OUI_FROM_DATABASE=Vaisala Oyj + +OUI:0050C213C* + ID_OUI_FROM_DATABASE=NBG Industrial Automation B.V. + +OUI:0050C213D* + ID_OUI_FROM_DATABASE=Formula One Management Ltd. + +OUI:0050C213E* + ID_OUI_FROM_DATABASE=AVerMedia Systems, Inc. + +OUI:0050C213F* + ID_OUI_FROM_DATABASE=Sentito Networks + +OUI:0050C2140* + ID_OUI_FROM_DATABASE=ITS, Inc. + +OUI:0050C2141* + ID_OUI_FROM_DATABASE=Time Terminal Adductor Group AB + +OUI:0050C2142* + ID_OUI_FROM_DATABASE=Instrumeter A/S + +OUI:0050C2143* + ID_OUI_FROM_DATABASE=AARTESYS AG + +OUI:0050C2144* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2145* + ID_OUI_FROM_DATABASE=ELC Lighting + +OUI:0050C2146* + ID_OUI_FROM_DATABASE=APCON, Inc. + +OUI:0050C2147* + ID_OUI_FROM_DATABASE=UniSUR + +OUI:0050C2148* + ID_OUI_FROM_DATABASE=Alltec GmbH + +OUI:0050C2149* + ID_OUI_FROM_DATABASE=Haag-Streit AG + +OUI:0050C214A* + ID_OUI_FROM_DATABASE=DYCEC, S.A. + +OUI:0050C214B* + ID_OUI_FROM_DATABASE=HECUBA Elektronik + +OUI:0050C214C* + ID_OUI_FROM_DATABASE=Optibase Ltd. + +OUI:0050C214D* + ID_OUI_FROM_DATABASE=wellink, Ltd. + +OUI:0050C214E* + ID_OUI_FROM_DATABASE=Corinex Global + +OUI:0050C214F* + ID_OUI_FROM_DATABASE=Telephonics Corp. + +OUI:0050C2150* + ID_OUI_FROM_DATABASE=Torse + +OUI:0050C2151* + ID_OUI_FROM_DATABASE=Redux Communications Ltd. + +OUI:0050C2152* + ID_OUI_FROM_DATABASE=AirVast Technology Inc. + +OUI:0050C2153* + ID_OUI_FROM_DATABASE=Advanced Devices SpA + +OUI:0050C2154* + ID_OUI_FROM_DATABASE=Jostra AB + +OUI:0050C2155* + ID_OUI_FROM_DATABASE=Enea Real Time AB + +OUI:0050C2156* + ID_OUI_FROM_DATABASE=CommServ Solutions Inc. + +OUI:0050C2157* + ID_OUI_FROM_DATABASE=nCore, Inc. + +OUI:0050C2158* + ID_OUI_FROM_DATABASE=Communication Solutions, Inc. + +OUI:0050C2159* + ID_OUI_FROM_DATABASE=Standard Comm. Corp. + +OUI:0050C215A* + ID_OUI_FROM_DATABASE=Plextek Limited + +OUI:0050C215B* + ID_OUI_FROM_DATABASE=Dune Networks + +OUI:0050C215C* + ID_OUI_FROM_DATABASE=Aoptix Technologies + +OUI:0050C215D* + ID_OUI_FROM_DATABASE=Cepheid + +OUI:0050C215E* + ID_OUI_FROM_DATABASE=Celite Systems, Inc. + +OUI:0050C215F* + ID_OUI_FROM_DATABASE=Pulsar GmbH + +OUI:0050C2160* + ID_OUI_FROM_DATABASE=TTI - Telecom International Ltd. + +OUI:0050C2161* + ID_OUI_FROM_DATABASE=J&B Engineering Group S.L. + +OUI:0050C2162* + ID_OUI_FROM_DATABASE=Teseda Corporation + +OUI:0050C2163* + ID_OUI_FROM_DATABASE=Computerwise, Inc. + +OUI:0050C2164* + ID_OUI_FROM_DATABASE=Acunia N.V. + +OUI:0050C2165* + ID_OUI_FROM_DATABASE=IPCAST + +OUI:0050C2166* + ID_OUI_FROM_DATABASE=Infineer Ltd. + +OUI:0050C2167* + ID_OUI_FROM_DATABASE=Precision Filters, Inc. + +OUI:0050C2168* + ID_OUI_FROM_DATABASE=ExtremeSpeed Inc. + +OUI:0050C2169* + ID_OUI_FROM_DATABASE=Nordson Corp. + +OUI:0050C216A* + ID_OUI_FROM_DATABASE=Time Domain + +OUI:0050C216B* + ID_OUI_FROM_DATABASE=Masterclock, Inc. + +OUI:0050C216C* + ID_OUI_FROM_DATABASE=Brijing Embedor Embedded Internet Tech. Co. Ltd. + +OUI:0050C216D* + ID_OUI_FROM_DATABASE=Postec Data Systems Ltd. + +OUI:0050C216E* + ID_OUI_FROM_DATABASE=PMC + +OUI:0050C216F* + ID_OUI_FROM_DATABASE=Dickson Technologies + +OUI:0050C2170* + ID_OUI_FROM_DATABASE=Taishodo Seiko Co., Ltd. + +OUI:0050C2171* + ID_OUI_FROM_DATABASE=Quantronix, Inc. + +OUI:0050C2172* + ID_OUI_FROM_DATABASE=SAET I.S. S.r.l. + +OUI:0050C2173* + ID_OUI_FROM_DATABASE=DeMeTec GmbH + +OUI:0050C2174* + ID_OUI_FROM_DATABASE=N&P Technologies + +OUI:0050C2175* + ID_OUI_FROM_DATABASE=Sei S.p.A. + +OUI:0050C2176* + ID_OUI_FROM_DATABASE=Wavium AB + +OUI:0050C2177* + ID_OUI_FROM_DATABASE=Unicoi Systems + +OUI:0050C2178* + ID_OUI_FROM_DATABASE=Partner Voxstream A/S + +OUI:0050C2179* + ID_OUI_FROM_DATABASE=Verifiber LLC + +OUI:0050C217A* + ID_OUI_FROM_DATABASE=WOLF Industrial Systems Inc. + +OUI:0050C217B* + ID_OUI_FROM_DATABASE=Broadstorm Telecom + +OUI:0050C217C* + ID_OUI_FROM_DATABASE=Jeffress Engineering Pty Ltd + +OUI:0050C217D* + ID_OUI_FROM_DATABASE=Cognex Corporation + +OUI:0050C217E* + ID_OUI_FROM_DATABASE=Binary Wave Technologies Inc. + +OUI:0050C217F* + ID_OUI_FROM_DATABASE=PDQ Manufacturing + +OUI:0050C2180* + ID_OUI_FROM_DATABASE=Zultys Technologies + +OUI:0050C2181* + ID_OUI_FROM_DATABASE=Task 84 Spa + +OUI:0050C2182* + ID_OUI_FROM_DATABASE=wolf-inf-tec + +OUI:0050C2183* + ID_OUI_FROM_DATABASE=Mixbaal S.A. de C.V. + +OUI:0050C2184* + ID_OUI_FROM_DATABASE=H M Computing Limited + +OUI:0050C2185* + ID_OUI_FROM_DATABASE=Optical Wireless Link Inc. + +OUI:0050C2186* + ID_OUI_FROM_DATABASE=Pantec Engineering AG + +OUI:0050C2187* + ID_OUI_FROM_DATABASE=Cyan Technology Ltd + +OUI:0050C2188* + ID_OUI_FROM_DATABASE=dresden-elektronik + +OUI:0050C2189* + ID_OUI_FROM_DATABASE=CC Systems AB + +OUI:0050C218A* + ID_OUI_FROM_DATABASE=Basler Electric Company + +OUI:0050C218B* + ID_OUI_FROM_DATABASE=Teradyne Inc. + +OUI:0050C218C* + ID_OUI_FROM_DATABASE=Technodrive srl + +OUI:0050C218D* + ID_OUI_FROM_DATABASE=CCII Systems (Pty) Ltd + +OUI:0050C218E* + ID_OUI_FROM_DATABASE=SPARR ELECTRONICS LTD + +OUI:0050C218F* + ID_OUI_FROM_DATABASE=MATSUI MFG CO.,LTD + +OUI:0050C2190* + ID_OUI_FROM_DATABASE=Goerlitz AG + +OUI:0050C2191* + ID_OUI_FROM_DATABASE=Partner Voxstream A/S + +OUI:0050C2192* + ID_OUI_FROM_DATABASE=Advanced Concepts, Inc. + +OUI:0050C2193* + ID_OUI_FROM_DATABASE=LaserBit Communications Corp. + +OUI:0050C2194* + ID_OUI_FROM_DATABASE=COMINFO + +OUI:0050C2195* + ID_OUI_FROM_DATABASE=Momentum Data Systems + +OUI:0050C2196* + ID_OUI_FROM_DATABASE=Netsynt Spa + +OUI:0050C2197* + ID_OUI_FROM_DATABASE=EPM Tecnologia e Equipamentos + +OUI:0050C2198* + ID_OUI_FROM_DATABASE=PotsTek, Inc + +OUI:0050C2199* + ID_OUI_FROM_DATABASE=Survalent Technology Corporation + +OUI:0050C219A* + ID_OUI_FROM_DATABASE=AZIO TECHNOLOGY CO. + +OUI:0050C219B* + ID_OUI_FROM_DATABASE=Wilcoxon Research, Inc. + +OUI:0050C219C* + ID_OUI_FROM_DATABASE=Artec Design + +OUI:0050C219D* + ID_OUI_FROM_DATABASE=ELECTREX S.R.L + +OUI:0050C219E* + ID_OUI_FROM_DATABASE=Paltronics, Inc. + +OUI:0050C219F* + ID_OUI_FROM_DATABASE=Fleetwood Electronics Ltd + +OUI:0050C21A0* + ID_OUI_FROM_DATABASE=SCA Data Systems + +OUI:0050C21A1* + ID_OUI_FROM_DATABASE=Portalplayer, Inc + +OUI:0050C21A2* + ID_OUI_FROM_DATABASE=ABB Switzerland Inc + +OUI:0050C21A3* + ID_OUI_FROM_DATABASE=Tidel Engineering, L.P. + +OUI:0050C21A4* + ID_OUI_FROM_DATABASE=Protech Optronics Co. Ltd. + +OUI:0050C21A5* + ID_OUI_FROM_DATABASE=NORCO + +OUI:0050C21A6* + ID_OUI_FROM_DATABASE=RF Code + +OUI:0050C21A7* + ID_OUI_FROM_DATABASE=Alpha Beta Technologies, Inc. + +OUI:0050C21A8* + ID_OUI_FROM_DATABASE=ANOVA BROADBAND + +OUI:0050C21A9* + ID_OUI_FROM_DATABASE=Axotec Technologies GmbH + +OUI:0050C21AA* + ID_OUI_FROM_DATABASE=BitBox Ltd + +OUI:0050C21AB* + ID_OUI_FROM_DATABASE=Streaming Networks + +OUI:0050C21AC* + ID_OUI_FROM_DATABASE=Beckmann+Egle GmbH + +OUI:0050C21AD* + ID_OUI_FROM_DATABASE=Remia s.r.o. + +OUI:0050C21AE* + ID_OUI_FROM_DATABASE=Home Director, Inc + +OUI:0050C21AF* + ID_OUI_FROM_DATABASE=PESA Switching Systems, Inc. + +OUI:0050C21B0* + ID_OUI_FROM_DATABASE=BLANKOM Antennentechnik GmbH + +OUI:0050C21B1* + ID_OUI_FROM_DATABASE=Axes Technologies + +OUI:0050C21B2* + ID_OUI_FROM_DATABASE=SIGOS Systemintegration GmbH + +OUI:0050C21B3* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C21B4* + ID_OUI_FROM_DATABASE=DSP Group Inc. + +OUI:0050C21B5* + ID_OUI_FROM_DATABASE=Thrane & Thrane A/S + +OUI:0050C21B6* + ID_OUI_FROM_DATABASE=DTS, Inc. + +OUI:0050C21B7* + ID_OUI_FROM_DATABASE=MosChip USA + +OUI:0050C21B8* + ID_OUI_FROM_DATABASE=Electronic Systems Development + +OUI:0050C21B9* + ID_OUI_FROM_DATABASE=EmCom Technology Inc. + +OUI:0050C21BA* + ID_OUI_FROM_DATABASE=INTERZEAG AG + +OUI:0050C21BB* + ID_OUI_FROM_DATABASE=Email Metering + +OUI:0050C21BC* + ID_OUI_FROM_DATABASE=DINEC International + +OUI:0050C21BD* + ID_OUI_FROM_DATABASE=AIOI Systems Co., Ltd. + +OUI:0050C21BE* + ID_OUI_FROM_DATABASE=Sedia Electronics + +OUI:0050C21BF* + ID_OUI_FROM_DATABASE=International Test & Engineering Services Co.,Ltd. + +OUI:0050C21C0* + ID_OUI_FROM_DATABASE=WillMonius Inc. + +OUI:0050C21C1* + ID_OUI_FROM_DATABASE=InfinitiNetworks Inc. + +OUI:0050C21C2* + ID_OUI_FROM_DATABASE=Weltronics Corp. + +OUI:0050C21C3* + ID_OUI_FROM_DATABASE=TT electronic manufacturing services ltd + +OUI:0050C21C4* + ID_OUI_FROM_DATABASE=Palm Solutions Group + +OUI:0050C21C5* + ID_OUI_FROM_DATABASE=Flander Oy + +OUI:0050C21C6* + ID_OUI_FROM_DATABASE=Remco Italia Spa + +OUI:0050C21C7* + ID_OUI_FROM_DATABASE=TWIN DEVELOPMENT S.A. + +OUI:0050C21C8* + ID_OUI_FROM_DATABASE=Euphony technology CO., LTD. + +OUI:0050C21C9* + ID_OUI_FROM_DATABASE=modas GmbH + +OUI:0050C21CA* + ID_OUI_FROM_DATABASE=EVER Sp. z o.o. + +OUI:0050C21CB* + ID_OUI_FROM_DATABASE=quantumBEAM Limited + +OUI:0050C21CC* + ID_OUI_FROM_DATABASE=WaveIP ltd. + +OUI:0050C21CD* + ID_OUI_FROM_DATABASE=INCAA Informatica Italia srl + +OUI:0050C21CE* + ID_OUI_FROM_DATABASE=Datatek Applications, Inc. + +OUI:0050C21CF* + ID_OUI_FROM_DATABASE=LIFETIME MEMORY PRODUCTS, INC. + +OUI:0050C21D0* + ID_OUI_FROM_DATABASE=Yazaki North America, Inc. + +OUI:0050C21D1* + ID_OUI_FROM_DATABASE=Benchmark Electronics + +OUI:0050C21D2* + ID_OUI_FROM_DATABASE=Shenyang Internet Technology Inc + +OUI:0050C21D3* + ID_OUI_FROM_DATABASE=Synopsys + +OUI:0050C21D4* + ID_OUI_FROM_DATABASE=Phase IV Engineering Inc. + +OUI:0050C21D5* + ID_OUI_FROM_DATABASE=Redpoint Controls + +OUI:0050C21D6* + ID_OUI_FROM_DATABASE=shanghai trend intelligent systems CO.,LTD + +OUI:0050C21D7* + ID_OUI_FROM_DATABASE=Pleora Technologies Inc. + +OUI:0050C21D8* + ID_OUI_FROM_DATABASE=Guardian Controls International + +OUI:0050C21D9* + ID_OUI_FROM_DATABASE=EDC + +OUI:0050C21DA* + ID_OUI_FROM_DATABASE=GFI Chrono Time + +OUI:0050C21DB* + ID_OUI_FROM_DATABASE=Applied Systems Engineering, Inc. + +OUI:0050C21DC* + ID_OUI_FROM_DATABASE=Imarda New Zealand Limited + +OUI:0050C21DD* + ID_OUI_FROM_DATABASE=Peiker acustic GmbH & Co. KG + +OUI:0050C21DE* + ID_OUI_FROM_DATABASE=ReliOn Inc. + +OUI:0050C21DF* + ID_OUI_FROM_DATABASE=Lulea University of Technology + +OUI:0050C21E0* + ID_OUI_FROM_DATABASE=Cognex Corporation + +OUI:0050C21E1* + ID_OUI_FROM_DATABASE=Automaatiotekniikka Seppo Saari Oy + +OUI:0050C21E2* + ID_OUI_FROM_DATABASE=DIGITRONIC Automationsanlagen GmbH + +OUI:0050C21E3* + ID_OUI_FROM_DATABASE=Bluesocket, Inc. + +OUI:0050C21E4* + ID_OUI_FROM_DATABASE=Soronti, Inc. + +OUI:0050C21E5* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C21E6* + ID_OUI_FROM_DATABASE=United Tri-Tech Corporation + +OUI:0050C21E7* + ID_OUI_FROM_DATABASE=Smith Meter, Inc. + +OUI:0050C21E8* + ID_OUI_FROM_DATABASE=Metrotech + +OUI:0050C21E9* + ID_OUI_FROM_DATABASE=Ranch Networks + +OUI:0050C21EA* + ID_OUI_FROM_DATABASE=DAVE S.r.L. + +OUI:0050C21EB* + ID_OUI_FROM_DATABASE=Data Respons A/S + +OUI:0050C21EC* + ID_OUI_FROM_DATABASE=COSMO co.,ltd. + +OUI:0050C21ED* + ID_OUI_FROM_DATABASE=EMKA-electronic AG + +OUI:0050C21EE* + ID_OUI_FROM_DATABASE=Perto Periféricos de Automação S.A. + +OUI:0050C21EF* + ID_OUI_FROM_DATABASE=M2 Technology Pty Ltd + +OUI:0050C21F0* + ID_OUI_FROM_DATABASE=EXI Wireless Systems Inc. + +OUI:0050C21F1* + ID_OUI_FROM_DATABASE=SKY Computers, Inc. + +OUI:0050C21F2* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:0050C21F3* + ID_OUI_FROM_DATABASE=Radionor Communications AS + +OUI:0050C21F4* + ID_OUI_FROM_DATABASE=Covia, Inc + +OUI:0050C21F5* + ID_OUI_FROM_DATABASE=Abest Communication Corp. + +OUI:0050C21F6* + ID_OUI_FROM_DATABASE=BAE SYSTEMS Controls + +OUI:0050C21F7* + ID_OUI_FROM_DATABASE=ARC'Créations + +OUI:0050C21F8* + ID_OUI_FROM_DATABASE=ULTRACKER TECHNOLOGY + +OUI:0050C21F9* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C21FA* + ID_OUI_FROM_DATABASE=SP Controls, Inc + +OUI:0050C21FB* + ID_OUI_FROM_DATABASE=Willowglen Systems Inc. + +OUI:0050C21FC* + ID_OUI_FROM_DATABASE=EDD Srl + +OUI:0050C21FD* + ID_OUI_FROM_DATABASE=SouthWing S.L. + +OUI:0050C21FE* + ID_OUI_FROM_DATABASE=Safetran Traffic Systems Inc. + +OUI:0050C21FF* + ID_OUI_FROM_DATABASE=Product Design Dept., Sohwa Corporation + +OUI:0050C2200* + ID_OUI_FROM_DATABASE=Whittier Mailing Products, Inc. + +OUI:0050C2201* + ID_OUI_FROM_DATABASE=OlympusNDT + +OUI:0050C2202* + ID_OUI_FROM_DATABASE=Audio Riders Oy + +OUI:0050C2204* + ID_OUI_FROM_DATABASE=Algodue Elettronica srl + +OUI:0050C2205* + ID_OUI_FROM_DATABASE=SystIng + +OUI:0050C2206* + ID_OUI_FROM_DATABASE=Windmill Innovations + +OUI:0050C2207* + ID_OUI_FROM_DATABASE=Solectron Ind.Com.Servs.Exportadora do Brasil Ltda. + +OUI:0050C2208* + ID_OUI_FROM_DATABASE=nNovia, Inc. + +OUI:0050C2209* + ID_OUI_FROM_DATABASE=LK Ltd + +OUI:0050C220A* + ID_OUI_FROM_DATABASE=Ferrari electronic AG + +OUI:0050C220B* + ID_OUI_FROM_DATABASE=Rafael + +OUI:0050C220C* + ID_OUI_FROM_DATABASE=Communication and Telemechanical Systems Company Limited + +OUI:0050C220D* + ID_OUI_FROM_DATABASE=Varisys Ltd + +OUI:0050C220E* + ID_OUI_FROM_DATABASE=PYRAMID Computer Systeme GmbH + +OUI:0050C220F* + ID_OUI_FROM_DATABASE=OMICRON electronics GmbH + +OUI:0050C2210* + ID_OUI_FROM_DATABASE=Innovics Wireless Inc + +OUI:0050C2211* + ID_OUI_FROM_DATABASE=Hochschule für Technik, Wirtschaft und Kultur Leipzig (FH) + +OUI:0050C2212* + ID_OUI_FROM_DATABASE=4Links Limited + +OUI:0050C2213* + ID_OUI_FROM_DATABASE=SysAware S.A.R.L. + +OUI:0050C2214* + ID_OUI_FROM_DATABASE=Oshimi System Design Inc. + +OUI:0050C2215* + ID_OUI_FROM_DATABASE=VoiceCom AG + +OUI:0050C2216* + ID_OUI_FROM_DATABASE=Level Control Systems + +OUI:0050C2217* + ID_OUI_FROM_DATABASE=Linn Products Ltd + +OUI:0050C2218* + ID_OUI_FROM_DATABASE=Nansen S. A. - Instrumentos de Precisão + +OUI:0050C2219* + ID_OUI_FROM_DATABASE=Aeroflex GmbH + +OUI:0050C221A* + ID_OUI_FROM_DATABASE=MST SYSTEMS LIMITED + +OUI:0050C221B* + ID_OUI_FROM_DATABASE=General Dynamics Decision Systems + +OUI:0050C221C* + ID_OUI_FROM_DATABASE=Fracarro Radioindustrie SPA + +OUI:0050C221D* + ID_OUI_FROM_DATABASE=ESG Elektroniksystem u. Logistik GmbH + +OUI:0050C221E* + ID_OUI_FROM_DATABASE=Applied Technologies Associates + +OUI:0050C221F* + ID_OUI_FROM_DATABASE=Monitor Business Machines Ltd + +OUI:0050C2220* + ID_OUI_FROM_DATABASE=Serveron Corporation + +OUI:0050C2221* + ID_OUI_FROM_DATABASE=Getinge IT Solutions ApS + +OUI:0050C2222* + ID_OUI_FROM_DATABASE=imo-elektronik GmbH + +OUI:0050C2223* + ID_OUI_FROM_DATABASE=visicontrol GmbH + +OUI:0050C2224* + ID_OUI_FROM_DATABASE=PANNOCOM Ltd. + +OUI:0050C2225* + ID_OUI_FROM_DATABASE=Pigeon Point Systems LLC + +OUI:0050C2226* + ID_OUI_FROM_DATABASE=Ross Video Limited + +OUI:0050C2227* + ID_OUI_FROM_DATABASE=Intelligent Photonics Control + +OUI:0050C2228* + ID_OUI_FROM_DATABASE=Intelligent Media Technologies, Inc. + +OUI:0050C2229* + ID_OUI_FROM_DATABASE=eko systems inc. + +OUI:0050C222A* + ID_OUI_FROM_DATABASE=Crescendo Networks + +OUI:0050C222B* + ID_OUI_FROM_DATABASE=Riegl Laser Measurement Systems GmbH + +OUI:0050C222C* + ID_OUI_FROM_DATABASE=Intrinsity + +OUI:0050C222D* + ID_OUI_FROM_DATABASE=asetek Inc. + +OUI:0050C222E* + ID_OUI_FROM_DATABASE=LORD INGENIERIE + +OUI:0050C222F* + ID_OUI_FROM_DATABASE=HTEC Limited + +OUI:0050C2230* + ID_OUI_FROM_DATABASE=AutoTOOLS group Co. Ltd. + +OUI:0050C2231* + ID_OUI_FROM_DATABASE=Legra Systems, Inc. + +OUI:0050C2232* + ID_OUI_FROM_DATABASE=SIMET + +OUI:0050C2233* + ID_OUI_FROM_DATABASE=EdenTree Technologies, Inc. + +OUI:0050C2234* + ID_OUI_FROM_DATABASE=Silverback Systems + +OUI:0050C2235* + ID_OUI_FROM_DATABASE=POLIMAR ELEKTRONIK LTD. + +OUI:0050C2236* + ID_OUI_FROM_DATABASE=JLCooper Electronics + +OUI:0050C2237* + ID_OUI_FROM_DATABASE=Tandata Systems Ltd + +OUI:0050C2238* + ID_OUI_FROM_DATABASE=Schwer+Kopka GmbH + +OUI:0050C2239* + ID_OUI_FROM_DATABASE=Stins Coman + +OUI:0050C223A* + ID_OUI_FROM_DATABASE=Chantry Networks + +OUI:0050C223B* + ID_OUI_FROM_DATABASE=Envara + +OUI:0050C223C* + ID_OUI_FROM_DATABASE=Wheatstone Corporation + +OUI:0050C223D* + ID_OUI_FROM_DATABASE=Gauging Systems Inc + +OUI:0050C223E* + ID_OUI_FROM_DATABASE=Kallastra Inc. + +OUI:0050C223F* + ID_OUI_FROM_DATABASE=Halliburton - NUMAR + +OUI:0050C2240* + ID_OUI_FROM_DATABASE=Geoquip Ltd + +OUI:0050C2241* + ID_OUI_FROM_DATABASE=Contronics Automacao Ltda + +OUI:0050C2242* + ID_OUI_FROM_DATABASE=MDS SCIEX + +OUI:0050C2243* + ID_OUI_FROM_DATABASE=RGB Spectrum + +OUI:0050C2244* + ID_OUI_FROM_DATABASE=intec GmbH + +OUI:0050C2245* + ID_OUI_FROM_DATABASE=Hauppauge Computer Works, Inc. + +OUI:0050C2246* + ID_OUI_FROM_DATABASE=Hardmeier + +OUI:0050C2247* + ID_OUI_FROM_DATABASE=Gradual Tecnologia Ltda. + +OUI:0050C2248* + ID_OUI_FROM_DATABASE=Dixtal Biomedica Ind. Com. Ltda. + +OUI:0050C2249* + ID_OUI_FROM_DATABASE=Bender GmbH & Co. KG + +OUI:0050C224A* + ID_OUI_FROM_DATABASE=CDS Rail + +OUI:0050C224B* + ID_OUI_FROM_DATABASE=Azimuth Systems, Inc. + +OUI:0050C224C* + ID_OUI_FROM_DATABASE=Supertel + +OUI:0050C224D* + ID_OUI_FROM_DATABASE=METTLER-TOLEDO HI-SPEED + +OUI:0050C224E* + ID_OUI_FROM_DATABASE=Scharff Weisberg Systems Integration Inc + +OUI:0050C224F* + ID_OUI_FROM_DATABASE=Macronet s.r.l. + +OUI:0050C2250* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2251* + ID_OUI_FROM_DATABASE=DGT Sp. z o.o. + +OUI:0050C2252* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C2253* + ID_OUI_FROM_DATABASE=DSM-Messtechnik GmbH + +OUI:0050C2254* + ID_OUI_FROM_DATABASE=Thales Communications Ltd + +OUI:0050C2255* + ID_OUI_FROM_DATABASE=STMicroelectronics (R&D) Ltd + +OUI:0050C2256* + ID_OUI_FROM_DATABASE=Information Technology Corp. + +OUI:0050C2257* + ID_OUI_FROM_DATABASE=Digicast Networks + +OUI:0050C2258* + ID_OUI_FROM_DATABASE=Spacesaver Corporation + +OUI:0050C2259* + ID_OUI_FROM_DATABASE=Omicron Ceti AB + +OUI:0050C225A* + ID_OUI_FROM_DATABASE=Zendex Corporation + +OUI:0050C225B* + ID_OUI_FROM_DATABASE=Winford Engineering + +OUI:0050C225C* + ID_OUI_FROM_DATABASE=Softhill Technologies Ltd. + +OUI:0050C225D* + ID_OUI_FROM_DATABASE=RDTECH + +OUI:0050C225E* + ID_OUI_FROM_DATABASE=MITE Hradec Kralove, s.r.o. + +OUI:0050C225F* + ID_OUI_FROM_DATABASE=Handtmann Maschinenfabrik GmbH&Co.KG + +OUI:0050C2260* + ID_OUI_FROM_DATABASE=BIOTAGE + +OUI:0050C2261* + ID_OUI_FROM_DATABASE=Tattile Srl + +OUI:0050C2262* + ID_OUI_FROM_DATABASE=Shanghai Gaozhi Science&Technology Development Ltd. + +OUI:0050C2263* + ID_OUI_FROM_DATABASE=Vansco Electronics Oy + +OUI:0050C2264* + ID_OUI_FROM_DATABASE=Confidence Direct Ltd + +OUI:0050C2265* + ID_OUI_FROM_DATABASE=BELIK S.P.R.L. + +OUI:0050C2266* + ID_OUI_FROM_DATABASE=ATOM GIKEN Co.,Ltd. + +OUI:0050C2267* + ID_OUI_FROM_DATABASE=Allen Martin Conservation Ltd + +OUI:0050C2268* + ID_OUI_FROM_DATABASE=Parabit Systems + +OUI:0050C2269* + ID_OUI_FROM_DATABASE=Technisyst Pty Ltd + +OUI:0050C226A* + ID_OUI_FROM_DATABASE=FG SYNERYS + +OUI:0050C226B* + ID_OUI_FROM_DATABASE=Continental Gateway Limited + +OUI:0050C226C* + ID_OUI_FROM_DATABASE=Crystal Vision Ltd + +OUI:0050C226D* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C226E* + ID_OUI_FROM_DATABASE=ZP Engineering srl + +OUI:0050C226F* + ID_OUI_FROM_DATABASE=Digital Recorders Inc + +OUI:0050C2270* + ID_OUI_FROM_DATABASE=S4 Technology Pty Ltd + +OUI:0050C2271* + ID_OUI_FROM_DATABASE=VLSIP TECHNOLOGIES INC. + +OUI:0050C2272* + ID_OUI_FROM_DATABASE=Verex Technology + +OUI:0050C2273* + ID_OUI_FROM_DATABASE=Servicios Condumex, S. A. de C. V. + +OUI:0050C2274* + ID_OUI_FROM_DATABASE=Fundación TECNALIA Research & Innovation + +OUI:0050C2275* + ID_OUI_FROM_DATABASE=Extreme Engineering Solutions + +OUI:0050C2276* + ID_OUI_FROM_DATABASE=Tieline Research Pty Ltd + +OUI:0050C2277* + ID_OUI_FROM_DATABASE=T/R Systems, Inc. + +OUI:0050C2278* + ID_OUI_FROM_DATABASE=Replicom Ltd. + +OUI:0050C2279* + ID_OUI_FROM_DATABASE=PATLITE Corporation + +OUI:0050C227A* + ID_OUI_FROM_DATABASE=Maestro Pty Ltd + +OUI:0050C227B* + ID_OUI_FROM_DATABASE=LinkSecurity A/S + +OUI:0050C227C* + ID_OUI_FROM_DATABASE=Danlaw Inc + +OUI:0050C227D* + ID_OUI_FROM_DATABASE=ALLIED TELESIS K.K. + +OUI:0050C227E* + ID_OUI_FROM_DATABASE=AnaLogic Computers Ltd. + +OUI:0050C227F* + ID_OUI_FROM_DATABASE=Air Broadband Communications, Inc. + +OUI:0050C2280* + ID_OUI_FROM_DATABASE=AGECODAGIS SARL + +OUI:0050C2281* + ID_OUI_FROM_DATABASE=CabTronix GmbH + +OUI:0050C2282* + ID_OUI_FROM_DATABASE=Telvent + +OUI:0050C2283* + ID_OUI_FROM_DATABASE=ANSITEX CORP. + +OUI:0050C2284* + ID_OUI_FROM_DATABASE=Micronet Ltd. + +OUI:0050C2285* + ID_OUI_FROM_DATABASE=Littwin GmbH & Co KG + +OUI:0050C2286* + ID_OUI_FROM_DATABASE=ATEME + +OUI:0050C2287* + ID_OUI_FROM_DATABASE=TECNEW Electronics Engineering Cr., Ltd. + +OUI:0050C2288* + ID_OUI_FROM_DATABASE=RPM Systems Corporation + +OUI:0050C2289* + ID_OUI_FROM_DATABASE=Rototype S.p.A. + +OUI:0050C228A* + ID_OUI_FROM_DATABASE=Real Time Systems + +OUI:0050C228B* + ID_OUI_FROM_DATABASE=Orion Technologies, Incorporated + +OUI:0050C228C* + ID_OUI_FROM_DATABASE=Futaba Corporation + +OUI:0050C228D* + ID_OUI_FROM_DATABASE=AXODE SA + +OUI:0050C228E* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C228F* + ID_OUI_FROM_DATABASE=Spellman High Voltage Electronics Corp + +OUI:0050C2290* + ID_OUI_FROM_DATABASE=EBNEURO SPA + +OUI:0050C2291* + ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX + +OUI:0050C2292* + ID_OUI_FROM_DATABASE=AMIRIX Systems + +OUI:0050C2293* + ID_OUI_FROM_DATABASE=IP Unity + +OUI:0050C2294* + ID_OUI_FROM_DATABASE=EPSa GmbH + +OUI:0050C2295* + ID_OUI_FROM_DATABASE=LOGOSOL, INC. + +OUI:0050C2296* + ID_OUI_FROM_DATABASE=OpVista + +OUI:0050C2297* + ID_OUI_FROM_DATABASE=KINETICS + +OUI:0050C2298* + ID_OUI_FROM_DATABASE=Harvad University + +OUI:0050C2299* + ID_OUI_FROM_DATABASE=CAD-UL GmbH + +OUI:0050C229A* + ID_OUI_FROM_DATABASE=Packet Techniques Inc. + +OUI:0050C229B* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C229C* + ID_OUI_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +OUI:0050C229D* + ID_OUI_FROM_DATABASE=Globe Wireless + +OUI:0050C229E* + ID_OUI_FROM_DATABASE=SELEX Communications Ltd + +OUI:0050C229F* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:0050C22A0* + ID_OUI_FROM_DATABASE=Sterling Industry Consult GmbH + +OUI:0050C22A1* + ID_OUI_FROM_DATABASE=Infinetix Corp + +OUI:0050C22A2* + ID_OUI_FROM_DATABASE=Epelsa, SL + +OUI:0050C22A3* + ID_OUI_FROM_DATABASE=West-Com Nurse Call Systems, Inc. + +OUI:0050C22A4* + ID_OUI_FROM_DATABASE=Xipher Embedded Networking + +OUI:0050C22A5* + ID_OUI_FROM_DATABASE=Septier Communication Ltd + +OUI:0050C22A6* + ID_OUI_FROM_DATABASE=Brannstroms Elektronik AB + +OUI:0050C22A7* + ID_OUI_FROM_DATABASE=Micro System Architecturing srl + +OUI:0050C22A8* + ID_OUI_FROM_DATABASE=DVTel Israel Ltd. + +OUI:0050C22A9* + ID_OUI_FROM_DATABASE=Dr. Staiger, Mohilo + Co GmbH + +OUI:0050C22AA* + ID_OUI_FROM_DATABASE=DEUTA Werke GmbH + +OUI:0050C22AB* + ID_OUI_FROM_DATABASE=AUM Infotech Private Limited + +OUI:0050C22AC* + ID_OUI_FROM_DATABASE=BBI Engineering, Inc. + +OUI:0050C22AD* + ID_OUI_FROM_DATABASE=ABB T&D Spa + +OUI:0050C22AE* + ID_OUI_FROM_DATABASE=Quest Retail Technology Pty Ltd + +OUI:0050C22AF* + ID_OUI_FROM_DATABASE=CSA Computer & Antriebstechnik GmbH + +OUI:0050C22B0* + ID_OUI_FROM_DATABASE=Telda Electronics + +OUI:0050C22B2* + ID_OUI_FROM_DATABASE=Smiths Detection + +OUI:0050C22B3* + ID_OUI_FROM_DATABASE=Embedded Systems Design + +OUI:0050C22B4* + ID_OUI_FROM_DATABASE=Polatis Ltd + +OUI:0050C22B5* + ID_OUI_FROM_DATABASE=Hobbes Computer Network Accessories + +OUI:0050C22B6* + ID_OUI_FROM_DATABASE=Softier Inc. + +OUI:0050C22B7* + ID_OUI_FROM_DATABASE=Rafi GmbH & Co. KG + +OUI:0050C22B8* + ID_OUI_FROM_DATABASE=Admiral Secure Products, Ltd. + +OUI:0050C22B9* + ID_OUI_FROM_DATABASE=Richmond Sound Design Ltd. + +OUI:0050C22BA* + ID_OUI_FROM_DATABASE=NORCO INDUSTRIAL TECHNOLOGY INC + +OUI:0050C22BB* + ID_OUI_FROM_DATABASE=TA Instruments Ltd + +OUI:0050C22BC* + ID_OUI_FROM_DATABASE=Uster Technologies AG + +OUI:0050C22BD* + ID_OUI_FROM_DATABASE=StorLink Semi + +OUI:0050C22BE* + ID_OUI_FROM_DATABASE=Lipowsky Industrie-Elektronik GmbH + +OUI:0050C22BF* + ID_OUI_FROM_DATABASE=PERAX + +OUI:0050C22C0* + ID_OUI_FROM_DATABASE=Magellan Technology Pty Ltd + +OUI:0050C22C1* + ID_OUI_FROM_DATABASE=Stage Tec Entwicklungsgesellschaft für professionelle Audio + +OUI:0050C22C2* + ID_OUI_FROM_DATABASE=Smarteye Corporation + +OUI:0050C22C3* + ID_OUI_FROM_DATABASE=Digital SP Ltd + +OUI:0050C22C4* + ID_OUI_FROM_DATABASE=Invensys Energy Systens (NZ) Limited + +OUI:0050C22C5* + ID_OUI_FROM_DATABASE=Elman srl + +OUI:0050C22C6* + ID_OUI_FROM_DATABASE=Initial Electronic Security Systems + +OUI:0050C22C7* + ID_OUI_FROM_DATABASE=Siliquent Technologies Ltd + +OUI:0050C22C8* + ID_OUI_FROM_DATABASE=SELCO + +OUI:0050C22C9* + ID_OUI_FROM_DATABASE=Roseman Engineering Ltd. + +OUI:0050C22CA* + ID_OUI_FROM_DATABASE=PUTERCOM CO., LTD + +OUI:0050C22CB* + ID_OUI_FROM_DATABASE=FACTS Engineering LLC + +OUI:0050C22CC* + ID_OUI_FROM_DATABASE=EMBEDDED TOOLSMITHS + +OUI:0050C22CD* + ID_OUI_FROM_DATABASE=DataWind Research + +OUI:0050C22CE* + ID_OUI_FROM_DATABASE=Ross Video Limited + +OUI:0050C22CF* + ID_OUI_FROM_DATABASE=Diseño de Sistemas en Silicio S.A. + +OUI:0050C22D0* + ID_OUI_FROM_DATABASE=Worth Data, Inc. + +OUI:0050C22D1* + ID_OUI_FROM_DATABASE=Miritek, Inc. + +OUI:0050C22D2* + ID_OUI_FROM_DATABASE=AIRNET COMMUNICATIONS CORP + +OUI:0050C22D3* + ID_OUI_FROM_DATABASE=Gerber Scientific Products, Inc. + +OUI:0050C22D4* + ID_OUI_FROM_DATABASE=Integrated System Solution Corp. + +OUI:0050C22D5* + ID_OUI_FROM_DATABASE=PIXY AG + +OUI:0050C22D6* + ID_OUI_FROM_DATABASE=WIS Technologies + +OUI:0050C22D7* + ID_OUI_FROM_DATABASE=Neo Electronics Ltd + +OUI:0050C22D8* + ID_OUI_FROM_DATABASE=SYN-TECH SYSTEMS INC + +OUI:0050C22DA* + ID_OUI_FROM_DATABASE=PYRAMID Computer GmbH + +OUI:0050C22DB* + ID_OUI_FROM_DATABASE=AutoTOOLS group Co. Ltd. + +OUI:0050C22DC* + ID_OUI_FROM_DATABASE=Wiener, Plein & Baus GmbH + +OUI:0050C22DD* + ID_OUI_FROM_DATABASE=Westek Technology Ltd + +OUI:0050C22DE* + ID_OUI_FROM_DATABASE=Research Applications + +OUI:0050C22DF* + ID_OUI_FROM_DATABASE=MICREL-NKE + +OUI:0050C22E0* + ID_OUI_FROM_DATABASE=Baxter Healthcare + +OUI:0050C22E1* + ID_OUI_FROM_DATABASE=Access IS + +OUI:0050C22E2* + ID_OUI_FROM_DATABASE=Ballard Technology, Inc. + +OUI:0050C22E3* + ID_OUI_FROM_DATABASE=MG Industrieelektronik GmbH + +OUI:0050C22E4* + ID_OUI_FROM_DATABASE=iamba LTD. + +OUI:0050C22E5* + ID_OUI_FROM_DATABASE=Transtech DSP + +OUI:0050C22E6* + ID_OUI_FROM_DATABASE=DALSA + +OUI:0050C22E7* + ID_OUI_FROM_DATABASE=SafeView, Inc. + +OUI:0050C22E8* + ID_OUI_FROM_DATABASE=S.M.V. Systemelektronik GmbH + +OUI:0050C22E9* + ID_OUI_FROM_DATABASE=SRI International + +OUI:0050C22EA* + ID_OUI_FROM_DATABASE=QUBIsoft S.r.l. + +OUI:0050C22EB* + ID_OUI_FROM_DATABASE=Lingg & Janke OHG + +OUI:0050C22EC* + ID_OUI_FROM_DATABASE=CHENGDU BOOK DIGITAL CO., LTD + +OUI:0050C22ED* + ID_OUI_FROM_DATABASE=4RF Communications Ltd + +OUI:0050C22EE* + ID_OUI_FROM_DATABASE=SHF Communication Technologies AG + +OUI:0050C22EF* + ID_OUI_FROM_DATABASE=Profline B.V. + +OUI:0050C22F0* + ID_OUI_FROM_DATABASE=LECO Corporation + +OUI:0050C22F1* + ID_OUI_FROM_DATABASE=Geometrics, Inc. + +OUI:0050C22F2* + ID_OUI_FROM_DATABASE=Eurotek Srl + +OUI:0050C22F3* + ID_OUI_FROM_DATABASE=Crossbow Technology, Inc. + +OUI:0050C22F4* + ID_OUI_FROM_DATABASE=Efficient Channel Coding + +OUI:0050C22F5* + ID_OUI_FROM_DATABASE=ADChips + +OUI:0050C22F6* + ID_OUI_FROM_DATABASE=Clifford Chance LLP + +OUI:0050C22F7* + ID_OUI_FROM_DATABASE=GILLAM-FEI S.A. + +OUI:0050C22F8* + ID_OUI_FROM_DATABASE=SavvyCorp.com Ltd + +OUI:0050C22F9* + ID_OUI_FROM_DATABASE=Digilent Inc. + +OUI:0050C22FA* + ID_OUI_FROM_DATABASE=Tornado Modular Systems, Ltd + +OUI:0050C22FB* + ID_OUI_FROM_DATABASE=Arthur Industries Inc., dba On Hold Media Group + +OUI:0050C22FC* + ID_OUI_FROM_DATABASE=Blackline Systems Corporation + +OUI:0050C22FD* + ID_OUI_FROM_DATABASE=American Microsystems LTD + +OUI:0050C22FE* + ID_OUI_FROM_DATABASE=Saab AB + +OUI:0050C22FF* + ID_OUI_FROM_DATABASE=Patria Advanced Solutions + +OUI:0050C2300* + ID_OUI_FROM_DATABASE=Soredex Instrumentarium Oyj + +OUI:0050C2301* + ID_OUI_FROM_DATABASE=Delphi Display Systems, Inc. + +OUI:0050C2302* + ID_OUI_FROM_DATABASE=EuroDesign embedded technologies GmbH + +OUI:0050C2303* + ID_OUI_FROM_DATABASE=CI Systems Ltd. + +OUI:0050C2304* + ID_OUI_FROM_DATABASE=COMERSON S.r.l. + +OUI:0050C2305* + ID_OUI_FROM_DATABASE=Symbium Corporation + +OUI:0050C2306* + ID_OUI_FROM_DATABASE=Noran Tel Communications Ltd. + +OUI:0050C2307* + ID_OUI_FROM_DATABASE=UNIONDIGITAL.,CO.LTD + +OUI:0050C2308* + ID_OUI_FROM_DATABASE=FiveCo + +OUI:0050C2309* + ID_OUI_FROM_DATABASE=Rackmaster Systems, Inc. + +OUI:0050C230A* + ID_OUI_FROM_DATABASE=Innings Telecom Inc. + +OUI:0050C230B* + ID_OUI_FROM_DATABASE=VX Technologies Inc. + +OUI:0050C230C* + ID_OUI_FROM_DATABASE=TEAMLOG + +OUI:0050C230D* + ID_OUI_FROM_DATABASE=SETARAM + +OUI:0050C230E* + ID_OUI_FROM_DATABASE=Obvius + +OUI:0050C230F* + ID_OUI_FROM_DATABASE=Digicontrole Lda + +OUI:0050C2310* + ID_OUI_FROM_DATABASE=CYBERTRON CO., LTD. + +OUI:0050C2311* + ID_OUI_FROM_DATABASE=Comodo + +OUI:0050C2312* + ID_OUI_FROM_DATABASE=Dese Technologies SL + +OUI:0050C2313* + ID_OUI_FROM_DATABASE=SAIA Burgess Controls AG + +OUI:0050C2314* + ID_OUI_FROM_DATABASE=MicroBee Systems, Inc + +OUI:0050C2315* + ID_OUI_FROM_DATABASE=ifak system GmbH + +OUI:0050C2316* + ID_OUI_FROM_DATABASE=Dataline AB + +OUI:0050C2317* + ID_OUI_FROM_DATABASE=Cosine Systems, Inc. + +OUI:0050C2318* + ID_OUI_FROM_DATABASE=Milmega Ltd + +OUI:0050C2319* + ID_OUI_FROM_DATABASE=Invatron Systems Corp. + +OUI:0050C231A* + ID_OUI_FROM_DATABASE=Zodiak Data Systems + +OUI:0050C231B* + ID_OUI_FROM_DATABASE=Datacon + +OUI:0050C231C* + ID_OUI_FROM_DATABASE=Casa Systems Inc. + +OUI:0050C231D* + ID_OUI_FROM_DATABASE=Imarda New Zealand Limited + +OUI:0050C231E* + ID_OUI_FROM_DATABASE=C3-ilex, LLC + +OUI:0050C231F* + ID_OUI_FROM_DATABASE=Geotech Instruments, LLC + +OUI:0050C2320* + ID_OUI_FROM_DATABASE=DTASENSOR S.p.A. + +OUI:0050C2321* + ID_OUI_FROM_DATABASE=UXP + +OUI:0050C2322* + ID_OUI_FROM_DATABASE=BQT Solutions (Australia) Limited + +OUI:0050C2323* + ID_OUI_FROM_DATABASE=Red Rock Networks + +OUI:0050C2324* + ID_OUI_FROM_DATABASE=ODIXION + +OUI:0050C2325* + ID_OUI_FROM_DATABASE=Federal Aviation Administration + +OUI:0050C2326* + ID_OUI_FROM_DATABASE=Navionics S.p.A. + +OUI:0050C2327* + ID_OUI_FROM_DATABASE=Dornier GmbH + +OUI:0050C2328* + ID_OUI_FROM_DATABASE=I.C.S. Electronics Limited + +OUI:0050C2329* + ID_OUI_FROM_DATABASE=Imax + +OUI:0050C232A* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C232B* + ID_OUI_FROM_DATABASE=Digital Multimedia Technologies Spa + +OUI:0050C232C* + ID_OUI_FROM_DATABASE=Integrated Silicon Solution (Taiwan), Inc. + +OUI:0050C232D* + ID_OUI_FROM_DATABASE=Consens Zeiterfassung GMBH + +OUI:0050C232E* + ID_OUI_FROM_DATABASE=MANUSA-GEST, S.L. + +OUI:0050C232F* + ID_OUI_FROM_DATABASE=PULTRONICS + +OUI:0050C2330* + ID_OUI_FROM_DATABASE=Sicon S.r.l. + +OUI:0050C2331* + ID_OUI_FROM_DATABASE=Broadcast Sports Inc + +OUI:0050C2332* + ID_OUI_FROM_DATABASE=PUNJAB COMMUNICATIONS LTD + +OUI:0050C2333* + ID_OUI_FROM_DATABASE=Radix Corporation + +OUI:0050C2334* + ID_OUI_FROM_DATABASE=Picture Elements, Inc. + +OUI:0050C2335* + ID_OUI_FROM_DATABASE=Nimcat Networks + +OUI:0050C2336* + ID_OUI_FROM_DATABASE=Golden River Traffic + +OUI:0050C2337* + ID_OUI_FROM_DATABASE=ETI + +OUI:0050C2338* + ID_OUI_FROM_DATABASE=Ernitec A/S + +OUI:0050C2339* + ID_OUI_FROM_DATABASE=CEGELEC SUD EST + +OUI:0050C233A* + ID_OUI_FROM_DATABASE=United Telecoms Ltd + +OUI:0050C233B* + ID_OUI_FROM_DATABASE=MultimediaLED + +OUI:0050C233C* + ID_OUI_FROM_DATABASE=SkipJam + +OUI:0050C233D* + ID_OUI_FROM_DATABASE=General Dynamics Decision Systems + +OUI:0050C233E* + ID_OUI_FROM_DATABASE=CA Technology, Inc + +OUI:0050C233F* + ID_OUI_FROM_DATABASE=EXYS bvba + +OUI:0050C2340* + ID_OUI_FROM_DATABASE=Virtu + +OUI:0050C2341* + ID_OUI_FROM_DATABASE=Novx Systems + +OUI:0050C2342* + ID_OUI_FROM_DATABASE=St. Michael Strategies + +OUI:0050C2343* + ID_OUI_FROM_DATABASE=ABB Xiamen Switchgear Co. Ltd. + +OUI:0050C2344* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C2345* + ID_OUI_FROM_DATABASE=ACT + +OUI:0050C2346* + ID_OUI_FROM_DATABASE=biokeysystem + +OUI:0050C2347* + ID_OUI_FROM_DATABASE=Row Seven Ltd + +OUI:0050C2348* + ID_OUI_FROM_DATABASE=KoolSpan, Inc. + +OUI:0050C2349* + ID_OUI_FROM_DATABASE=SSI Schaefer Peem + +OUI:0050C234A* + ID_OUI_FROM_DATABASE=NIE Corporation + +OUI:0050C234B* + ID_OUI_FROM_DATABASE=Ecutel Systems, Inc. + +OUI:0050C234C* + ID_OUI_FROM_DATABASE=Chuo Electric Works Co., LTD. + +OUI:0050C234D* + ID_OUI_FROM_DATABASE=BMK professional electronics GmbH + +OUI:0050C234E* + ID_OUI_FROM_DATABASE=ABB Power Technologies S.p.A. Unità  Operativa SACE (PTMV) + +OUI:0050C234F* + ID_OUI_FROM_DATABASE=North Pole Engineering, Inc. + +OUI:0050C2350* + ID_OUI_FROM_DATABASE=Kinesys Projects Limited + +OUI:0050C2351* + ID_OUI_FROM_DATABASE=Finesystem Co., Ltd + +OUI:0050C2352* + ID_OUI_FROM_DATABASE=LUCEO + +OUI:0050C2353* + ID_OUI_FROM_DATABASE=Crossing Informationssysteme GmbH + +OUI:0050C2354* + ID_OUI_FROM_DATABASE=Advanced IP Communications + +OUI:0050C2355* + ID_OUI_FROM_DATABASE=IHM + +OUI:0050C2356* + ID_OUI_FROM_DATABASE=Baytech Cinema + +OUI:0050C2357* + ID_OUI_FROM_DATABASE=Athena Semiconductor + +OUI:0050C2358* + ID_OUI_FROM_DATABASE=ALCEA + +OUI:0050C2359* + ID_OUI_FROM_DATABASE=Kramer Electronics Ltd. + +OUI:0050C235A* + ID_OUI_FROM_DATABASE=Advanced Si-Net Co., LTD. + +OUI:0050C235B* + ID_OUI_FROM_DATABASE=VLSIP TECHNOLOGIES, INC + +OUI:0050C235C* + ID_OUI_FROM_DATABASE=Ratotec GmbH + +OUI:0050C235D* + ID_OUI_FROM_DATABASE=NetTest A/S + +OUI:0050C235E* + ID_OUI_FROM_DATABASE=Jobin Yvon,Inc + +OUI:0050C235F* + ID_OUI_FROM_DATABASE=F.Imm. S.r.L. + +OUI:0050C2360* + ID_OUI_FROM_DATABASE=Digital Receiver Technology, Inc. + +OUI:0050C2361* + ID_OUI_FROM_DATABASE=Contec + +OUI:0050C2362* + ID_OUI_FROM_DATABASE=AZD Praha s.r.o. + +OUI:0050C2363* + ID_OUI_FROM_DATABASE=Septentrio nv/sa + +OUI:0050C2364* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C2365* + ID_OUI_FROM_DATABASE=Vishay Nobel AB + +OUI:0050C2366* + ID_OUI_FROM_DATABASE=Vanguard Technology Corp. + +OUI:0050C2367* + ID_OUI_FROM_DATABASE=CANMAX Technology Ltd. + +OUI:0050C2368* + ID_OUI_FROM_DATABASE=ASPEL S.A. + +OUI:0050C2369* + ID_OUI_FROM_DATABASE=Always On Wireless + +OUI:0050C236A* + ID_OUI_FROM_DATABASE=Optronic Partner pr AB + +OUI:0050C236B* + ID_OUI_FROM_DATABASE=Minerva Technology Inc + +OUI:0050C236C* + ID_OUI_FROM_DATABASE=RISCO Group + +OUI:0050C236D* + ID_OUI_FROM_DATABASE=Oplink Communications + +OUI:0050C236E* + ID_OUI_FROM_DATABASE=Minicom Advanced Systems Ltd + +OUI:0050C236F* + ID_OUI_FROM_DATABASE=XIMEA s.r.o. + +OUI:0050C2370* + ID_OUI_FROM_DATABASE=Europe Technologies + +OUI:0050C2371* + ID_OUI_FROM_DATABASE=DIGITAL ART SYSTEM + +OUI:0050C2372* + ID_OUI_FROM_DATABASE=ELV Elektronik AG + +OUI:0050C2373* + ID_OUI_FROM_DATABASE=Companion Worlds, inc. + +OUI:0050C2374* + ID_OUI_FROM_DATABASE=Owasys Advanced Wireless Devices + +OUI:0050C2375* + ID_OUI_FROM_DATABASE=TIR Systems Ltd. + +OUI:0050C2376* + ID_OUI_FROM_DATABASE=CLEODE + +OUI:0050C2377* + ID_OUI_FROM_DATABASE=Xycom VME + +OUI:0050C2378* + ID_OUI_FROM_DATABASE=Daintree Networks Inc + +OUI:0050C2379* + ID_OUI_FROM_DATABASE=Control LAN S.A. + +OUI:0050C237A* + ID_OUI_FROM_DATABASE=IDA Corporation + +OUI:0050C237B* + ID_OUI_FROM_DATABASE=freescale semiconductor + +OUI:0050C237C* + ID_OUI_FROM_DATABASE=MODIA SYSTEMS Co., Ltd + +OUI:0050C237D* + ID_OUI_FROM_DATABASE=VeroTrak Inc. + +OUI:0050C237E* + ID_OUI_FROM_DATABASE=Ni.Co. S.r.l. + +OUI:0050C237F* + ID_OUI_FROM_DATABASE=Foresearch + +OUI:0050C2380* + ID_OUI_FROM_DATABASE=EKE-Electronics Ltd. + +OUI:0050C2381* + ID_OUI_FROM_DATABASE=Realtime Engineering AG + +OUI:0050C2382* + ID_OUI_FROM_DATABASE=Colorado vNet + +OUI:0050C2383* + ID_OUI_FROM_DATABASE=ICS Electronics + +OUI:0050C2384* + ID_OUI_FROM_DATABASE=Wireless Reading Systems Holding ASA + +OUI:0050C2385* + ID_OUI_FROM_DATABASE=SUNGJIN NEOTECH Co.Ltd. + +OUI:0050C2386* + ID_OUI_FROM_DATABASE=Precision System Science Co.,Ltd + +OUI:0050C2387* + ID_OUI_FROM_DATABASE=Inoteska s.r.o. + +OUI:0050C2388* + ID_OUI_FROM_DATABASE=IEE Inc + +OUI:0050C2389* + ID_OUI_FROM_DATABASE=Exavio Inc. + +OUI:0050C238A* + ID_OUI_FROM_DATABASE=Embedtronics Enterprise + +OUI:0050C238B* + ID_OUI_FROM_DATABASE=InterBridge,Inc. + +OUI:0050C238C* + ID_OUI_FROM_DATABASE=EPSILON SRL + +OUI:0050C238D* + ID_OUI_FROM_DATABASE=A&G Soluzioni Digitali + +OUI:0050C238E* + ID_OUI_FROM_DATABASE=Nordic Alarm AB + +OUI:0050C238F* + ID_OUI_FROM_DATABASE=TTC Telecom + +OUI:0050C2390* + ID_OUI_FROM_DATABASE=TC Communications + +OUI:0050C2391* + ID_OUI_FROM_DATABASE=Esensors, Inc. + +OUI:0050C2392* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C2393* + ID_OUI_FROM_DATABASE=SYS TEC electronic GmbH + +OUI:0050C2394* + ID_OUI_FROM_DATABASE=Embedit A/S + +OUI:0050C2395* + ID_OUI_FROM_DATABASE=vidisys gmbh + +OUI:0050C2396* + ID_OUI_FROM_DATABASE=RapidWave Inc. + +OUI:0050C2397* + ID_OUI_FROM_DATABASE=MANGO DSP Ltd. + +OUI:0050C2398* + ID_OUI_FROM_DATABASE=InHand Electronics, Inc. + +OUI:0050C2399* + ID_OUI_FROM_DATABASE=Advanced Micro Controls Inc. + +OUI:0050C239A* + ID_OUI_FROM_DATABASE=Optical Air Data Systems + +OUI:0050C239B* + ID_OUI_FROM_DATABASE=YUYAMA MFG. CO., LTD. + +OUI:0050C239C* + ID_OUI_FROM_DATABASE=TIYODA MFG CO.,LTD. + +OUI:0050C239D* + ID_OUI_FROM_DATABASE=DigitalDeck, Inc. + +OUI:0050C239E* + ID_OUI_FROM_DATABASE=A.R.G ElectroDesign Ltd + +OUI:0050C239F* + ID_OUI_FROM_DATABASE=Isensix + +OUI:0050C23A0* + ID_OUI_FROM_DATABASE=StreetFire Sound Labs, LLC + +OUI:0050C23A1* + ID_OUI_FROM_DATABASE=Samsoft + +OUI:0050C23A2* + ID_OUI_FROM_DATABASE=Vegas Amusement + +OUI:0050C23A3* + ID_OUI_FROM_DATABASE=Star Link Communication Pvt. Ltd. + +OUI:0050C23A4* + ID_OUI_FROM_DATABASE=Silvertree Engineering Ltd + +OUI:0050C23A5* + ID_OUI_FROM_DATABASE=LabJack Corporation + +OUI:0050C23A6* + ID_OUI_FROM_DATABASE=IntelliDesign Pty Ltd + +OUI:0050C23A7* + ID_OUI_FROM_DATABASE=Elektrotechnik & Elektronik Oltmann GmbH + +OUI:0050C23A8* + ID_OUI_FROM_DATABASE=Engim, Inc. + +OUI:0050C23A9* + ID_OUI_FROM_DATABASE=Westronic Systems Inc. + +OUI:0050C23AA* + ID_OUI_FROM_DATABASE=Networked Robotics Corporation + +OUI:0050C23AB* + ID_OUI_FROM_DATABASE=taskit Rechnertechnik GmbH + +OUI:0050C23AC* + ID_OUI_FROM_DATABASE=InAccess Networks + +OUI:0050C23AD* + ID_OUI_FROM_DATABASE=Spirent Communications (Scotland) Limited + +OUI:0050C23AE* + ID_OUI_FROM_DATABASE=Hankuk Tapi Computer Co., Ltd + +OUI:0050C23AF* + ID_OUI_FROM_DATABASE=Norbit ODM AS + +OUI:0050C23B0* + ID_OUI_FROM_DATABASE=Microtarget Tecnologia Digital Ltda. + +OUI:0050C23B1* + ID_OUI_FROM_DATABASE=RDC Specstroy-Svyaz Ltd + +OUI:0050C23B2* + ID_OUI_FROM_DATABASE=Tennessee Valley Authority + +OUI:0050C23B3* + ID_OUI_FROM_DATABASE=Media Lab., Inc. + +OUI:0050C23B4* + ID_OUI_FROM_DATABASE=Contrôle Analytique inc. + +OUI:0050C23B5* + ID_OUI_FROM_DATABASE=NEC TOKIN Corporation + +OUI:0050C23B6* + ID_OUI_FROM_DATABASE=Arecont Vision, LLC + +OUI:0050C23B7* + ID_OUI_FROM_DATABASE=Mindspeed Technologies + +OUI:0050C23B8* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C23B9* + ID_OUI_FROM_DATABASE=Gilbarco Autotank AB + +OUI:0050C23BA* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C23BB* + ID_OUI_FROM_DATABASE=IMAGO Technologies GmbH + +OUI:0050C23BC* + ID_OUI_FROM_DATABASE=Tyzx, Inc. + +OUI:0050C23BD* + ID_OUI_FROM_DATABASE=Bigbang L.T.D. + +OUI:0050C23BE* + ID_OUI_FROM_DATABASE=Pauly Steuer- und Regelanlagen GmbH & Co. KG + +OUI:0050C23BF* + ID_OUI_FROM_DATABASE=Audio Processing Technology Ltd + +OUI:0050C23C0* + ID_OUI_FROM_DATABASE=EDA Industries Srl + +OUI:0050C23C1* + ID_OUI_FROM_DATABASE=MicroTek Electronics, Inc. + +OUI:0050C23C2* + ID_OUI_FROM_DATABASE=Casabyte Inc. + +OUI:0050C23C3* + ID_OUI_FROM_DATABASE=4g Technologies, L.P. + +OUI:0050C23C4* + ID_OUI_FROM_DATABASE=Sypris Electronics + +OUI:0050C23C5* + ID_OUI_FROM_DATABASE=Silicon Optix Canada Inc. + +OUI:0050C23C6* + ID_OUI_FROM_DATABASE=Net Optics + +OUI:0050C23C7* + ID_OUI_FROM_DATABASE=Salent Technologies Ltd + +OUI:0050C23C8* + ID_OUI_FROM_DATABASE=Wheels of Zeus Inc. + +OUI:0050C23C9* + ID_OUI_FROM_DATABASE=Dilax Intelcom AG + +OUI:0050C23CA* + ID_OUI_FROM_DATABASE=ABB Inc. + +OUI:0050C23CB* + ID_OUI_FROM_DATABASE=Analytica GmbH + +OUI:0050C23CC* + ID_OUI_FROM_DATABASE=LINKWELL TELESYSTEMS PRIVATE LIMITED + +OUI:0050C23CD* + ID_OUI_FROM_DATABASE=Micro-Measurements + +OUI:0050C23CE* + ID_OUI_FROM_DATABASE=Ward Leonard Electric Company + +OUI:0050C23CF* + ID_OUI_FROM_DATABASE=Technovare Systems, Inc. + +OUI:0050C23D0* + ID_OUI_FROM_DATABASE=Micro-Robotics Limited + +OUI:0050C23D1* + ID_OUI_FROM_DATABASE=Braintronics BV + +OUI:0050C23D2* + ID_OUI_FROM_DATABASE=Adilec Enginyeria SL + +OUI:0050C23D3* + ID_OUI_FROM_DATABASE=American LED-gible Inc. + +OUI:0050C23D4* + ID_OUI_FROM_DATABASE=Wisnu and Supak Co.Ltd. + +OUI:0050C23D5* + ID_OUI_FROM_DATABASE=Fluke Biomedical, Radiation Management Services + +OUI:0050C23D6* + ID_OUI_FROM_DATABASE=Comlab Inc. + +OUI:0050C23D7* + ID_OUI_FROM_DATABASE=TTC TELEKOMUNIKACE Ltd + +OUI:0050C23D8* + ID_OUI_FROM_DATABASE=Key Systems , Inc. + +OUI:0050C23D9* + ID_OUI_FROM_DATABASE=Bavaria Digital Technik GmbH + +OUI:0050C23DA* + ID_OUI_FROM_DATABASE=M5 Data Limited + +OUI:0050C23DB* + ID_OUI_FROM_DATABASE=Osmetech Inc. + +OUI:0050C23DC* + ID_OUI_FROM_DATABASE=3D perception + +OUI:0050C23DD* + ID_OUI_FROM_DATABASE=ELMIC GmbH + +OUI:0050C23DE* + ID_OUI_FROM_DATABASE=ABB Power Technologies + +OUI:0050C23DF* + ID_OUI_FROM_DATABASE=BiODE Inc. + +OUI:0050C23E0* + ID_OUI_FROM_DATABASE=Oy Stinghorn Ltd + +OUI:0050C23E1* + ID_OUI_FROM_DATABASE=NeuLion Incorporated + +OUI:0050C23E2* + ID_OUI_FROM_DATABASE=SysNova + +OUI:0050C23E3* + ID_OUI_FROM_DATABASE=CSIRO - Division of Exploration and Mining + +OUI:0050C23E4* + ID_OUI_FROM_DATABASE=CUE, a.s. + +OUI:0050C23E5* + ID_OUI_FROM_DATABASE=Vacon Plc + +OUI:0050C23E6* + ID_OUI_FROM_DATABASE=CRDE + +OUI:0050C23E7* + ID_OUI_FROM_DATABASE=Revolution Education Ltd + +OUI:0050C23E8* + ID_OUI_FROM_DATABASE=Conformative Systems, Inc. + +OUI:0050C23E9* + ID_OUI_FROM_DATABASE=MedAvant Healthcare + +OUI:0050C23EA* + ID_OUI_FROM_DATABASE=Alro Information Systems SA + +OUI:0050C23EB* + ID_OUI_FROM_DATABASE=ISS International + +OUI:0050C23EC* + ID_OUI_FROM_DATABASE=Teneros + +OUI:0050C23ED* + ID_OUI_FROM_DATABASE=The Board Room Inc. + +OUI:0050C23EE* + ID_OUI_FROM_DATABASE=Commoca, Inc + +OUI:0050C23EF* + ID_OUI_FROM_DATABASE=PAT Industries, DBA Pacific Advanced Technology + +OUI:0050C23F0* + ID_OUI_FROM_DATABASE=megatec electronic GmbH + +OUI:0050C23F1* + ID_OUI_FROM_DATABASE=Salland Electronics Holding BV + +OUI:0050C23F2* + ID_OUI_FROM_DATABASE=STL GmbH + +OUI:0050C23F3* + ID_OUI_FROM_DATABASE=Hytec Geraetebau GmbH + +OUI:0050C23F4* + ID_OUI_FROM_DATABASE=MC TECHNOLOGY GmbH + +OUI:0050C23F5* + ID_OUI_FROM_DATABASE=Phaedrus Limited + +OUI:0050C23F6* + ID_OUI_FROM_DATABASE=dAFTdATA Limited + +OUI:0050C23F7* + ID_OUI_FROM_DATABASE=Advantage R&D + +OUI:0050C23F8* + ID_OUI_FROM_DATABASE=Superna Ltd + +OUI:0050C23F9* + ID_OUI_FROM_DATABASE=Sintium Ltd + +OUI:0050C23FA* + ID_OUI_FROM_DATABASE=Tumsan + +OUI:0050C23FB* + ID_OUI_FROM_DATABASE=Pigeon Point Systems LLC + +OUI:0050C23FC* + ID_OUI_FROM_DATABASE=Weinberger Deutschland GmbH + +OUI:0050C23FD* + ID_OUI_FROM_DATABASE=HARTMANN software GbR + +OUI:0050C23FE* + ID_OUI_FROM_DATABASE=HaiVision Systems Inc + +OUI:0050C23FF* + ID_OUI_FROM_DATABASE=Cast Iron Systems + +OUI:0050C2400* + ID_OUI_FROM_DATABASE=SmartMotor AS + +OUI:0050C2401* + ID_OUI_FROM_DATABASE=Promess Incorporated + +OUI:0050C2402* + ID_OUI_FROM_DATABASE=Numeron Sp. z o.o. + +OUI:0050C2403* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2404* + ID_OUI_FROM_DATABASE=NanShanBridge Co.Ltd + +OUI:0050C2405* + ID_OUI_FROM_DATABASE=Guralp Systems Limited + +OUI:0050C2406* + ID_OUI_FROM_DATABASE=CoreStreet, Ltd + +OUI:0050C2407* + ID_OUI_FROM_DATABASE=AIE Etudes + +OUI:0050C2408* + ID_OUI_FROM_DATABASE=TERN, Inc. + +OUI:0050C2409* + ID_OUI_FROM_DATABASE=KTEC LTD + +OUI:0050C240A* + ID_OUI_FROM_DATABASE=Contec Steuerungstechnik & Automation GmbH + +OUI:0050C240B* + ID_OUI_FROM_DATABASE=Center VOSPI JSC + +OUI:0050C240C* + ID_OUI_FROM_DATABASE=Applied Materials UK Ltd + +OUI:0050C240D* + ID_OUI_FROM_DATABASE=Afonics Fibreoptics Ltd + +OUI:0050C240E* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C240F* + ID_OUI_FROM_DATABASE=BIR,INC. + +OUI:0050C2410* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + +OUI:0050C2411* + ID_OUI_FROM_DATABASE=Multimessage Systems Ltd. + +OUI:0050C2412* + ID_OUI_FROM_DATABASE=TSB Solutions Inc. + +OUI:0050C2413* + ID_OUI_FROM_DATABASE=Goodrich + +OUI:0050C2414* + ID_OUI_FROM_DATABASE=Talleres de Escoriaza SA + +OUI:0050C2415* + ID_OUI_FROM_DATABASE=SensoTech GmbH + +OUI:0050C2416* + ID_OUI_FROM_DATABASE=SELCO s.r.l. + +OUI:0050C2417* + ID_OUI_FROM_DATABASE=QT systems ab + +OUI:0050C2418* + ID_OUI_FROM_DATABASE=Planea Oy + +OUI:0050C2419* + ID_OUI_FROM_DATABASE=Mecsel Oy + +OUI:0050C241A* + ID_OUI_FROM_DATABASE=Bluewater Systems Ltd + +OUI:0050C241B* + ID_OUI_FROM_DATABASE=LogiM GmbH Software und Entwicklung + +OUI:0050C241C* + ID_OUI_FROM_DATABASE=Infrasafe, Inc. + +OUI:0050C241D* + ID_OUI_FROM_DATABASE=Altronic, Inc. + +OUI:0050C241E* + ID_OUI_FROM_DATABASE=Videotek Sistemas Eletronicos Ltda. + +OUI:0050C241F* + ID_OUI_FROM_DATABASE=Avionica, Inc + +OUI:0050C2420* + ID_OUI_FROM_DATABASE=Boundless Technologies + +OUI:0050C2421* + ID_OUI_FROM_DATABASE=EFSYS + +OUI:0050C2422* + ID_OUI_FROM_DATABASE=Gekeler Martina + +OUI:0050C2423* + ID_OUI_FROM_DATABASE=Power-One Inc. + +OUI:0050C2424* + ID_OUI_FROM_DATABASE=Metrolab Technology SA + +OUI:0050C2425* + ID_OUI_FROM_DATABASE=Pinnacle Technology + +OUI:0050C2426* + ID_OUI_FROM_DATABASE=STOM System + +OUI:0050C2427* + ID_OUI_FROM_DATABASE=Scheidt & Bachmann GmbH + +OUI:0050C2428* + ID_OUI_FROM_DATABASE=Roxar A/S + +OUI:0050C2429* + ID_OUI_FROM_DATABASE=Matthews Australasia + +OUI:0050C242A* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C242B* + ID_OUI_FROM_DATABASE=VLSIP TECHNOLOGIES, INC. + +OUI:0050C242C* + ID_OUI_FROM_DATABASE=Trapeze ITS U.S.A., LLC + +OUI:0050C242D* + ID_OUI_FROM_DATABASE=Argo-Tech + +OUI:0050C242E* + ID_OUI_FROM_DATABASE=Oelmann Elektronik GmbH + +OUI:0050C242F* + ID_OUI_FROM_DATABASE=Win4NET + +OUI:0050C2430* + ID_OUI_FROM_DATABASE=Arcom Digital + +OUI:0050C2431* + ID_OUI_FROM_DATABASE=Octatron, Inc. + +OUI:0050C2432* + ID_OUI_FROM_DATABASE=Topway Industries Ltd. + +OUI:0050C2433* + ID_OUI_FROM_DATABASE=Idetech Europe S.A. + +OUI:0050C2434* + ID_OUI_FROM_DATABASE=ImperativeNetworks + +OUI:0050C2435* + ID_OUI_FROM_DATABASE=ADATEL TELECOMUNICACIONES S.A. + +OUI:0050C2436* + ID_OUI_FROM_DATABASE=Satellite Services BV + +OUI:0050C2437* + ID_OUI_FROM_DATABASE=PowerWAN, Inc + +OUI:0050C2438* + ID_OUI_FROM_DATABASE=Telecom Protection Technologies Limited + +OUI:0050C2439* + ID_OUI_FROM_DATABASE=Peleton Photonic Systems + +OUI:0050C243A* + ID_OUI_FROM_DATABASE=ProDesign GmbH + +OUI:0050C243B* + ID_OUI_FROM_DATABASE=A3IP + +OUI:0050C243C* + ID_OUI_FROM_DATABASE=Ducommun LaBarge Technologies, Inc + +OUI:0050C243D* + ID_OUI_FROM_DATABASE=Ann Arbor Sensor Systems LLC + +OUI:0050C243E* + ID_OUI_FROM_DATABASE=Coppercom + +OUI:0050C243F* + ID_OUI_FROM_DATABASE=ARVOO Imaging Products BV + +OUI:0050C2440* + ID_OUI_FROM_DATABASE=Advanced Modular Computers Ltd. + +OUI:0050C2441* + ID_OUI_FROM_DATABASE=Sammi Information Systems Co.,Ltd + +OUI:0050C2442* + ID_OUI_FROM_DATABASE=Pico Computing, Inc. + +OUI:0050C2443* + ID_OUI_FROM_DATABASE=Pickering Laboratories + +OUI:0050C2444* + ID_OUI_FROM_DATABASE=Offshore Systems Ltd + +OUI:0050C2445* + ID_OUI_FROM_DATABASE=MICRONIC s.r.o. + +OUI:0050C2446* + ID_OUI_FROM_DATABASE=Micro Technic A-S + +OUI:0050C2447* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2448* + ID_OUI_FROM_DATABASE=Comtech Systems Inc. + +OUI:0050C2449* + ID_OUI_FROM_DATABASE=BLEILE DATENTECHNIK GmbH + +OUI:0050C244A* + ID_OUI_FROM_DATABASE=ELETTRONICA SANTERNO SPA + +OUI:0050C244B* + ID_OUI_FROM_DATABASE=Solace Systems, Inc. + +OUI:0050C244C* + ID_OUI_FROM_DATABASE=Computime Systems UK Ltd. + +OUI:0050C244D* + ID_OUI_FROM_DATABASE=Electro-Matic Products, Inc. + +OUI:0050C244E* + ID_OUI_FROM_DATABASE=QQ Technology,Inc + +OUI:0050C244F* + ID_OUI_FROM_DATABASE=kippdata GmbH + +OUI:0050C2450* + ID_OUI_FROM_DATABASE=Enconair Ecological Chambers Inc. + +OUI:0050C2451* + ID_OUI_FROM_DATABASE=HAMEG GmbH + +OUI:0050C2452* + ID_OUI_FROM_DATABASE=SCAME SISTEMI s.r.l. + +OUI:0050C2453* + ID_OUI_FROM_DATABASE=Erhardt + Leimer GmbH + +OUI:0050C2454* + ID_OUI_FROM_DATABASE=Brivo Systems, LLC + +OUI:0050C2455* + ID_OUI_FROM_DATABASE=AirCell, Inc. + +OUI:0050C2456* + ID_OUI_FROM_DATABASE=DRDC Valcartier + +OUI:0050C2457* + ID_OUI_FROM_DATABASE=Danbridge + +OUI:0050C2458* + ID_OUI_FROM_DATABASE=HRZ data GmbH + +OUI:0050C2459* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C245A* + ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH + +OUI:0050C245B* + ID_OUI_FROM_DATABASE=Matra Electronique + +OUI:0050C245C* + ID_OUI_FROM_DATABASE=Deister Electronic GmbH + +OUI:0050C245D* + ID_OUI_FROM_DATABASE=Digital Engineering, Inc. + +OUI:0050C245E* + ID_OUI_FROM_DATABASE=Halliburton - Sperry Drilling Service + +OUI:0050C245F* + ID_OUI_FROM_DATABASE=T2C Marketing AB + +OUI:0050C2460* + ID_OUI_FROM_DATABASE=Vitelnet + +OUI:0050C2461* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C2462* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2463* + ID_OUI_FROM_DATABASE=Codem Systems, Inc. + +OUI:0050C2464* + ID_OUI_FROM_DATABASE=XYTAC system technologies + +OUI:0050C2465* + ID_OUI_FROM_DATABASE=PDTS GmbH + +OUI:0050C2466* + ID_OUI_FROM_DATABASE=LONAP Limited + +OUI:0050C2467* + ID_OUI_FROM_DATABASE=United Western Technologies + +OUI:0050C2468* + ID_OUI_FROM_DATABASE=Network I/O + +OUI:0050C2469* + ID_OUI_FROM_DATABASE=BiPOM Electronics, Inc. + +OUI:0050C246A* + ID_OUI_FROM_DATABASE=ISE GmbH + +OUI:0050C246B* + ID_OUI_FROM_DATABASE=EASYTECH GmbH + +OUI:0050C246C* + ID_OUI_FROM_DATABASE=CAMCO GmbH + +OUI:0050C246D* + ID_OUI_FROM_DATABASE=Paul Scherrer Institut (PSI) + +OUI:0050C246E* + ID_OUI_FROM_DATABASE=Avenir Technologies Inc. + +OUI:0050C246F* + ID_OUI_FROM_DATABASE=Neuroware + +OUI:0050C2470* + ID_OUI_FROM_DATABASE=Cybectec inc. + +OUI:0050C2471* + ID_OUI_FROM_DATABASE=Pixtree Technologies, inc. + +OUI:0050C2472* + ID_OUI_FROM_DATABASE=KOP Ltd + +OUI:0050C2473* + ID_OUI_FROM_DATABASE=Sensus Metering Systems Israel + +OUI:0050C2474* + ID_OUI_FROM_DATABASE=Venue 1, Inc. + +OUI:0050C2475* + ID_OUI_FROM_DATABASE=ISEPOS GmbH + +OUI:0050C2476* + ID_OUI_FROM_DATABASE=Ascon S.p.a. + +OUI:0050C2477* + ID_OUI_FROM_DATABASE=SEV Tidsystem AB + +OUI:0050C2478* + ID_OUI_FROM_DATABASE=Metafix Inc. + +OUI:0050C2479* + ID_OUI_FROM_DATABASE=Unlimited Bandwidth LLC + +OUI:0050C247A* + ID_OUI_FROM_DATABASE=Efficient Channel Coding + +OUI:0050C247B* + ID_OUI_FROM_DATABASE=Pitney Bowes, Inc + +OUI:0050C247C* + ID_OUI_FROM_DATABASE=AUCONET GmbH + +OUI:0050C247D* + ID_OUI_FROM_DATABASE=WIT Inc + +OUI:0050C247E* + ID_OUI_FROM_DATABASE=Energie Umwelt Systemtechnik GmbH + +OUI:0050C247F* + ID_OUI_FROM_DATABASE=BRIT Inc. + +OUI:0050C2480* + ID_OUI_FROM_DATABASE=SELKOM GmbH + +OUI:0050C2481* + ID_OUI_FROM_DATABASE=Computer Sciences Corp + +OUI:0050C2482* + ID_OUI_FROM_DATABASE=PRIAMUS SYSTEM TECHNOLOGIES AG + +OUI:0050C2483* + ID_OUI_FROM_DATABASE=SES + +OUI:0050C2484* + ID_OUI_FROM_DATABASE=Kooltech LLC + +OUI:0050C2485* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C2486* + ID_OUI_FROM_DATABASE=Safegate International AB + +OUI:0050C2487* + ID_OUI_FROM_DATABASE=Eridon Corporation + +OUI:0050C2488* + ID_OUI_FROM_DATABASE=DA SISTEMI SPA + +OUI:0050C2489* + ID_OUI_FROM_DATABASE=EREE Electronique + +OUI:0050C248A* + ID_OUI_FROM_DATABASE=Mobile Matrix, Inc. + +OUI:0050C248B* + ID_OUI_FROM_DATABASE=ADS-TEC GmbH + +OUI:0050C248C* + ID_OUI_FROM_DATABASE=UNITON AG + +OUI:0050C248D* + ID_OUI_FROM_DATABASE=Metron Sp. z o.o. + +OUI:0050C248E* + ID_OUI_FROM_DATABASE=Teledyne Tekmar + +OUI:0050C248F* + ID_OUI_FROM_DATABASE=DENGYOSHA co.,LTD. + +OUI:0050C2490* + ID_OUI_FROM_DATABASE=Cloanto Corporation + +OUI:0050C2491* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2492* + ID_OUI_FROM_DATABASE=TRAFSYS AS + +OUI:0050C2493* + ID_OUI_FROM_DATABASE=Artis GmbH + +OUI:0050C2494* + ID_OUI_FROM_DATABASE=Ultimate Technology, Inc. + +OUI:0050C2495* + ID_OUI_FROM_DATABASE=VAZA Elektronik AB + +OUI:0050C2496* + ID_OUI_FROM_DATABASE=Acutelogic Corporation + +OUI:0050C2497* + ID_OUI_FROM_DATABASE=Advanced Driver Information Technology GmbH + +OUI:0050C2498* + ID_OUI_FROM_DATABASE=Quartet Technology, Inc. + +OUI:0050C2499* + ID_OUI_FROM_DATABASE=Trellia Networks + +OUI:0050C249A* + ID_OUI_FROM_DATABASE=TelASIC Communications, Inc. + +OUI:0050C249B* + ID_OUI_FROM_DATABASE=vg controls, inc + +OUI:0050C249C* + ID_OUI_FROM_DATABASE=Envisacor Technologies Inc. + +OUI:0050C249D* + ID_OUI_FROM_DATABASE=Critical Link + +OUI:0050C249E* + ID_OUI_FROM_DATABASE=Armorlink CO .Ltd + +OUI:0050C249F* + ID_OUI_FROM_DATABASE=GCS, Inc + +OUI:0050C24A0* + ID_OUI_FROM_DATABASE=Advanced technologies & Engineering (pty) Ltd + +OUI:0050C24A1* + ID_OUI_FROM_DATABASE=Pigeon Point Systems LLC + +OUI:0050C24A2* + ID_OUI_FROM_DATABASE=SPECS GmbH + +OUI:0050C24A3* + ID_OUI_FROM_DATABASE=Protium Technologies, Inc. + +OUI:0050C24A4* + ID_OUI_FROM_DATABASE=IEEE P1609 WG + +OUI:0050C24A5* + ID_OUI_FROM_DATABASE=Teledyne Monitor Labs + +OUI:0050C24A6* + ID_OUI_FROM_DATABASE=BUYANG ELECTRONICS INDUSTRIAL CO., LTD. + +OUI:0050C24A7* + ID_OUI_FROM_DATABASE=iseg Spezialelektronik GmbH + +OUI:0050C24A8* + ID_OUI_FROM_DATABASE=CYJAYA Korea + +OUI:0050C24A9* + ID_OUI_FROM_DATABASE=Faber Electronics BV + +OUI:0050C24AA* + ID_OUI_FROM_DATABASE=HEINEN ELEKTRONIK GmbH + +OUI:0050C24AB* + ID_OUI_FROM_DATABASE=JVF Communications Ltd + +OUI:0050C24AC* + ID_OUI_FROM_DATABASE=Doramu Co.,Ltd. + +OUI:0050C24AD* + ID_OUI_FROM_DATABASE=OpenPeak, Inc. + +OUI:0050C24AE* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C24AF* + ID_OUI_FROM_DATABASE=Orbis Oy + +OUI:0050C24B0* + ID_OUI_FROM_DATABASE=Esmart Distribution Pte Ltd + +OUI:0050C24B1* + ID_OUI_FROM_DATABASE=Nsfocus Information Technology Co.,Ltd + +OUI:0050C24B2* + ID_OUI_FROM_DATABASE=TESLA, a.s. + +OUI:0050C24B3* + ID_OUI_FROM_DATABASE=ANSA Corporation + +OUI:0050C24B4* + ID_OUI_FROM_DATABASE=Matrix Audio Designs + +OUI:0050C24B5* + ID_OUI_FROM_DATABASE=Valley Tecnologia + +OUI:0050C24B6* + ID_OUI_FROM_DATABASE=General Resources Co., LTD. + +OUI:0050C24B7* + ID_OUI_FROM_DATABASE=GFI Chrono Time + +OUI:0050C24B8* + ID_OUI_FROM_DATABASE=Shenzhen Hongdian Technologies.,Ltd + +OUI:0050C24B9* + ID_OUI_FROM_DATABASE=Rose Technologies + +OUI:0050C24BA* + ID_OUI_FROM_DATABASE=Mistletoe Technologies + +OUI:0050C24BB* + ID_OUI_FROM_DATABASE=Protonic Holland + +OUI:0050C24BC* + ID_OUI_FROM_DATABASE=Saia Burgess Controls AG + +OUI:0050C24BD* + ID_OUI_FROM_DATABASE=Argon ST + +OUI:0050C24BE* + ID_OUI_FROM_DATABASE=Digital Dynamics, Inc. + +OUI:0050C24BF* + ID_OUI_FROM_DATABASE=Westinghouse Rail Systems Ltd + +OUI:0050C24C0* + ID_OUI_FROM_DATABASE=Bio-logic Systems Corp + +OUI:0050C24C1* + ID_OUI_FROM_DATABASE=Movaz Networks, Inc. + +OUI:0050C24C2* + ID_OUI_FROM_DATABASE=Elbit Systems + +OUI:0050C24C3* + ID_OUI_FROM_DATABASE=Quantum3D, Inc. + +OUI:0050C24C4* + ID_OUI_FROM_DATABASE=Black Diamond Video, Inc. + +OUI:0050C24C5* + ID_OUI_FROM_DATABASE=eXray Broadband Inc. + +OUI:0050C24C6* + ID_OUI_FROM_DATABASE=Rubin Ltd. + +OUI:0050C24C7* + ID_OUI_FROM_DATABASE=Transbit Sp.z o.o. + +OUI:0050C24C8* + ID_OUI_FROM_DATABASE=Neets + +OUI:0050C24C9* + ID_OUI_FROM_DATABASE=Scirocco AB + +OUI:0050C24CA* + ID_OUI_FROM_DATABASE=Yarg Biometrics Limited + +OUI:0050C24CB* + ID_OUI_FROM_DATABASE=Verint Systems Ltd + +OUI:0050C24CC* + ID_OUI_FROM_DATABASE=ImpediMed Limited + +OUI:0050C24CD* + ID_OUI_FROM_DATABASE=Bixi Systems AG + +OUI:0050C24CE* + ID_OUI_FROM_DATABASE=Open Date Equipment Limited + +OUI:0050C24CF* + ID_OUI_FROM_DATABASE=Ziehl-Abegg AG + +OUI:0050C24D0* + ID_OUI_FROM_DATABASE=RCS Energy Management Ltd + +OUI:0050C24D1* + ID_OUI_FROM_DATABASE=SLICAN sp. z o.o. + +OUI:0050C24D2* + ID_OUI_FROM_DATABASE=Twoway CATV SERVICE INC. + +OUI:0050C24D3* + ID_OUI_FROM_DATABASE=ELPROC sp. z o.o. + +OUI:0050C24D4* + ID_OUI_FROM_DATABASE=Herholdt Controls srl + +OUI:0050C24D5* + ID_OUI_FROM_DATABASE=SEBA Design Pty Ltd + +OUI:0050C24D6* + ID_OUI_FROM_DATABASE=Ingenieurbüro Schober + +OUI:0050C24D7* + ID_OUI_FROM_DATABASE=Delta Tau Data Systems, Inc. + +OUI:0050C24D8* + ID_OUI_FROM_DATABASE=Avantry Ltd. + +OUI:0050C24D9* + ID_OUI_FROM_DATABASE=GE Security Kampro + +OUI:0050C24DA* + ID_OUI_FROM_DATABASE=MEDIORNET GmbH + +OUI:0050C24DB* + ID_OUI_FROM_DATABASE=Alfing Montagetechnik GmbH + +OUI:0050C24DC* + ID_OUI_FROM_DATABASE=Ace Electronics Inc. + +OUI:0050C24DD* + ID_OUI_FROM_DATABASE=Truteq Wireless (PTY) Ltd. + +OUI:0050C24DE* + ID_OUI_FROM_DATABASE=General Dynamics C4 Systems + +OUI:0050C24DF* + ID_OUI_FROM_DATABASE=Thermo Electron + +OUI:0050C24E0* + ID_OUI_FROM_DATABASE=Telematrix + +OUI:0050C24E1* + ID_OUI_FROM_DATABASE=SS Telecoms CC + +OUI:0050C24E2* + ID_OUI_FROM_DATABASE=Applied Research Laboratories: UT + +OUI:0050C24E3* + ID_OUI_FROM_DATABASE=Romteck Pty Ltd + +OUI:0050C24E4* + ID_OUI_FROM_DATABASE=Embigence GmbH + +OUI:0050C24E5* + ID_OUI_FROM_DATABASE=Sedo Systems Ltd + +OUI:0050C24E6* + ID_OUI_FROM_DATABASE=Photonic Bridges Inc. + +OUI:0050C24E7* + ID_OUI_FROM_DATABASE=Computerized Elevator Contol + +OUI:0050C24E8* + ID_OUI_FROM_DATABASE=SATEL sp. z o.o. + +OUI:0050C24E9* + ID_OUI_FROM_DATABASE=Seachange international + +OUI:0050C24EA* + ID_OUI_FROM_DATABASE=PMC + +OUI:0050C24EB* + ID_OUI_FROM_DATABASE=Mandozzi Elettronica SA + +OUI:0050C24EC* + ID_OUI_FROM_DATABASE=Thales Defence and Security Systems GmbH + +OUI:0050C24ED* + ID_OUI_FROM_DATABASE=Lab X Technologies, LLC + +OUI:0050C24EE* + ID_OUI_FROM_DATABASE=Beijing Corelogic Communication Co., Ltd. + +OUI:0050C24EF* + ID_OUI_FROM_DATABASE=Creative Retail Entertainment + +OUI:0050C24F0* + ID_OUI_FROM_DATABASE=MedAvant Healthcare + +OUI:0050C24F1* + ID_OUI_FROM_DATABASE=Packet Island Inc. + +OUI:0050C24F2* + ID_OUI_FROM_DATABASE=Tantronic AG + +OUI:0050C24F3* + ID_OUI_FROM_DATABASE=Autronica Fire & Security + +OUI:0050C24F4* + ID_OUI_FROM_DATABASE=O2RUN + +OUI:0050C24F5* + ID_OUI_FROM_DATABASE=Monroe Electronics, Inc. + +OUI:0050C24F6* + ID_OUI_FROM_DATABASE=REAL D + +OUI:0050C24F7* + ID_OUI_FROM_DATABASE=WaveIP Ltd. + +OUI:0050C24F8* + ID_OUI_FROM_DATABASE=Prodco International Inc. + +OUI:0050C24F9* + ID_OUI_FROM_DATABASE=RTDS Technologies Inc. + +OUI:0050C24FA* + ID_OUI_FROM_DATABASE=Cambridge Technology, Inc. + +OUI:0050C24FB* + ID_OUI_FROM_DATABASE=BES Technology Group + +OUI:0050C24FC* + ID_OUI_FROM_DATABASE=Hwayoung RF Solution Inc + +OUI:0050C24FD* + ID_OUI_FROM_DATABASE=Network Automation mxc AB + +OUI:0050C24FE* + ID_OUI_FROM_DATABASE=GEM ELETTRONICA Srl + +OUI:0050C24FF* + ID_OUI_FROM_DATABASE=Dakty GmbH + +OUI:0050C2500* + ID_OUI_FROM_DATABASE=Orenco Systems, Inc. + +OUI:0050C2501* + ID_OUI_FROM_DATABASE=IBEX UK Limited + +OUI:0050C2502* + ID_OUI_FROM_DATABASE=Criterion Systems Limited + +OUI:0050C2503* + ID_OUI_FROM_DATABASE=RESPIRONICS INC. + +OUI:0050C2504* + ID_OUI_FROM_DATABASE=Aphex Systems Ltd. + +OUI:0050C2505* + ID_OUI_FROM_DATABASE=Computerwise, Inc. + +OUI:0050C2506* + ID_OUI_FROM_DATABASE=7+ Kft + +OUI:0050C2507* + ID_OUI_FROM_DATABASE=Micro Connect Pty Ltd + +OUI:0050C2508* + ID_OUI_FROM_DATABASE=PUTERCOM ENTERPRISE CO., LTD. + +OUI:0050C2509* + ID_OUI_FROM_DATABASE=Hillcrest Laboratories, Inc. + +OUI:0050C250A* + ID_OUI_FROM_DATABASE=Monitor Business Machines Ltd + +OUI:0050C250B* + ID_OUI_FROM_DATABASE=Logic Beach Inc + +OUI:0050C250C* + ID_OUI_FROM_DATABASE=AIRWISE TECHNOLOGY CO., LTD. + +OUI:0050C250D* + ID_OUI_FROM_DATABASE=Clearsonics Pty. Ltd. + +OUI:0050C250E* + ID_OUI_FROM_DATABASE=Fibresavers Corporation + +OUI:0050C250F* + ID_OUI_FROM_DATABASE=Polystar Instruments AB + +OUI:0050C2510* + ID_OUI_FROM_DATABASE=Summit Developmen + +OUI:0050C2511* + ID_OUI_FROM_DATABASE=Tecna Srl + +OUI:0050C2512* + ID_OUI_FROM_DATABASE=Linear Acoustic, Inc + +OUI:0050C2513* + ID_OUI_FROM_DATABASE=Genie Network Resource Management Inc. + +OUI:0050C2514* + ID_OUI_FROM_DATABASE=Tadian Electronics Systems LTD + +OUI:0050C2515* + ID_OUI_FROM_DATABASE=Monaghan Engineering, Inc. + +OUI:0050C2516* + ID_OUI_FROM_DATABASE=SOWA ELECTRIC CO., LTD. + +OUI:0050C2517* + ID_OUI_FROM_DATABASE=Solid State Logic + +OUI:0050C2518* + ID_OUI_FROM_DATABASE=Christ Elektronik GmbH + +OUI:0050C2519* + ID_OUI_FROM_DATABASE=DBMCORP, Inc. + +OUI:0050C251A* + ID_OUI_FROM_DATABASE=SpeasTech, Inc. + +OUI:0050C251B* + ID_OUI_FROM_DATABASE=Beta Lasermike Ltd + +OUI:0050C251C* + ID_OUI_FROM_DATABASE=TOA Systems + +OUI:0050C251D* + ID_OUI_FROM_DATABASE=VELUX + +OUI:0050C251E* + ID_OUI_FROM_DATABASE=Alcon Technologies + +OUI:0050C251F* + ID_OUI_FROM_DATABASE=Traquair Data Systems, Inc. + +OUI:0050C2520* + ID_OUI_FROM_DATABASE=McCain Traffic Supply + +OUI:0050C2521* + ID_OUI_FROM_DATABASE=ARIS TECHNOLOGIES + +OUI:0050C2522* + ID_OUI_FROM_DATABASE=Mark IV IDS Corp. + +OUI:0050C2523* + ID_OUI_FROM_DATABASE=AMRDEC Prototype Integration Facility + +OUI:0050C2524* + ID_OUI_FROM_DATABASE=Motec Pty Ltd + +OUI:0050C2525* + ID_OUI_FROM_DATABASE=VASTech + +OUI:0050C2526* + ID_OUI_FROM_DATABASE=AC SYSTEMS, s.r.o. + +OUI:0050C2527* + ID_OUI_FROM_DATABASE=IRTrans + +OUI:0050C2528* + ID_OUI_FROM_DATABASE=tattile srl + +OUI:0050C2529* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C252A* + ID_OUI_FROM_DATABASE=OMNITRONICS PTY LTD + +OUI:0050C252B* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C252C* + ID_OUI_FROM_DATABASE=VITEC MULTIMEDIA + +OUI:0050C252D* + ID_OUI_FROM_DATABASE=Smartcom-Bulgaria AD + +OUI:0050C252E* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C252F* + ID_OUI_FROM_DATABASE=Gesellschaft für Rationalisierung und Rechentechnik mbH + +OUI:0050C2530* + ID_OUI_FROM_DATABASE=Innovation, Institute, Inc + +OUI:0050C2531* + ID_OUI_FROM_DATABASE=Orion Technologies, Incorporated + +OUI:0050C2532* + ID_OUI_FROM_DATABASE=NVE Corporation + +OUI:0050C2533* + ID_OUI_FROM_DATABASE=NanShanBridge Co.Ltd + +OUI:0050C2534* + ID_OUI_FROM_DATABASE=Hyundai J. Comm + +OUI:0050C2535* + ID_OUI_FROM_DATABASE=MMS Servis s.r.o. + +OUI:0050C2536* + ID_OUI_FROM_DATABASE=C2 DIAGNOSTICS + +OUI:0050C2537* + ID_OUI_FROM_DATABASE=DST CONTROL AB + +OUI:0050C2538* + ID_OUI_FROM_DATABASE=EtherTek Circuits + +OUI:0050C2539* + ID_OUI_FROM_DATABASE=Detection Technology Inc. + +OUI:0050C253A* + ID_OUI_FROM_DATABASE=Image Control Design Limited + +OUI:0050C253B* + ID_OUI_FROM_DATABASE=Teleks Co. Ltd. + +OUI:0050C253C* + ID_OUI_FROM_DATABASE=Marposs SPA + +OUI:0050C253D* + ID_OUI_FROM_DATABASE=Digital communications Technologies + +OUI:0050C253E* + ID_OUI_FROM_DATABASE=Honeywell GNO + +OUI:0050C253F* + ID_OUI_FROM_DATABASE=Ellips B.V. + +OUI:0050C2540* + ID_OUI_FROM_DATABASE=Mesure Controle Commande + +OUI:0050C2541* + ID_OUI_FROM_DATABASE=WAVES SYSTEM + +OUI:0050C2542* + ID_OUI_FROM_DATABASE=AVerMedia Technologies, Inc. + +OUI:0050C2543* + ID_OUI_FROM_DATABASE=DIGI SESN AG + +OUI:0050C2544* + ID_OUI_FROM_DATABASE=Zetera + +OUI:0050C2545* + ID_OUI_FROM_DATABASE=SecuInfo Co., Ltd. + +OUI:0050C2546* + ID_OUI_FROM_DATABASE=Universidad de Chile Facultad de Medicina + +OUI:0050C2547* + ID_OUI_FROM_DATABASE=BLANKOM Antennentechnik GmbH + +OUI:0050C2548* + ID_OUI_FROM_DATABASE=I.T.W. Betaprint + +OUI:0050C2549* + ID_OUI_FROM_DATABASE=Netsynt S.p.A. + +OUI:0050C254A* + ID_OUI_FROM_DATABASE=IPTC Tech. Comm. AB + +OUI:0050C254B* + ID_OUI_FROM_DATABASE=Innopsys + +OUI:0050C254C* + ID_OUI_FROM_DATABASE=Sintecnos srl + +OUI:0050C254D* + ID_OUI_FROM_DATABASE=Silent System + +OUI:0050C254E* + ID_OUI_FROM_DATABASE=Convergent Design + +OUI:0050C254F* + ID_OUI_FROM_DATABASE=Valtronic SA + +OUI:0050C2550* + ID_OUI_FROM_DATABASE=LJU Automatisierungstechnik GmbH + +OUI:0050C2551* + ID_OUI_FROM_DATABASE=Innovative Neurotroncs + +OUI:0050C2552* + ID_OUI_FROM_DATABASE=Elfiq Inc. + +OUI:0050C2553* + ID_OUI_FROM_DATABASE=ATH system + +OUI:0050C2554* + ID_OUI_FROM_DATABASE=Weinzierl Engineering GmbH + +OUI:0050C2555* + ID_OUI_FROM_DATABASE=Control Alternative Solutions, Inc. + +OUI:0050C2556* + ID_OUI_FROM_DATABASE=Freiburger BlickZentrum + +OUI:0050C2557* + ID_OUI_FROM_DATABASE=Netcomsec Co Ltd + +OUI:0050C2558* + ID_OUI_FROM_DATABASE=Bedo Elektronik GmbH + +OUI:0050C2559* + ID_OUI_FROM_DATABASE=Fail Safe Solutions LLC + +OUI:0050C255A* + ID_OUI_FROM_DATABASE=Valde Systems, Inc. + +OUI:0050C255B* + ID_OUI_FROM_DATABASE=MATRIX TELECOM PVT. LTD. + +OUI:0050C255C* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C255D* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C255E* + ID_OUI_FROM_DATABASE=HANZAS ELEKTRONIKA, SIA + +OUI:0050C255F* + ID_OUI_FROM_DATABASE=Moog Broad Reach + +OUI:0050C2560* + ID_OUI_FROM_DATABASE=Procon Electronics + +OUI:0050C2561* + ID_OUI_FROM_DATABASE=Seitec Elektronik GmbH + +OUI:0050C2562* + ID_OUI_FROM_DATABASE=C21 Technology Limited + +OUI:0050C2563* + ID_OUI_FROM_DATABASE=ORTRAT, S.L. + +OUI:0050C2564* + ID_OUI_FROM_DATABASE=Last Mile Gear + +OUI:0050C2565* + ID_OUI_FROM_DATABASE=WORKPOWER TECNOLOGIA ELETRONICA LTDA-EPP + +OUI:0050C2566* + ID_OUI_FROM_DATABASE=ubinetsys.co..ltd + +OUI:0050C2567* + ID_OUI_FROM_DATABASE=Tess GmbH + +OUI:0050C2568* + ID_OUI_FROM_DATABASE=GeoFocus, LLC + +OUI:0050C2569* + ID_OUI_FROM_DATABASE=Twinwin Technplogy Co.,Ltd. + +OUI:0050C256A* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C256B* + ID_OUI_FROM_DATABASE=Dataton Utvecklings AB + +OUI:0050C256C* + ID_OUI_FROM_DATABASE=Targeted Technologies, LLC + +OUI:0050C256D* + ID_OUI_FROM_DATABASE=Computrol Fuel Systems Inc. + +OUI:0050C256E* + ID_OUI_FROM_DATABASE=LAB-EL ELEKTRONIKA LABORATORYJNA S.J. + +OUI:0050C256F* + ID_OUI_FROM_DATABASE=GMA, LLC + +OUI:0050C2570* + ID_OUI_FROM_DATABASE=Ellex Medical Pty Ltd + +OUI:0050C2571* + ID_OUI_FROM_DATABASE=Oberon Service srl + +OUI:0050C2572* + ID_OUI_FROM_DATABASE=Chell Instruments Ltd + +OUI:0050C2573* + ID_OUI_FROM_DATABASE=DATAMICRO Co., Ltd. + +OUI:0050C2574* + ID_OUI_FROM_DATABASE=Ingeniería Almudí S.L. + +OUI:0050C2575* + ID_OUI_FROM_DATABASE=SOLYSTIC + +OUI:0050C2576* + ID_OUI_FROM_DATABASE=Visi-tech Systems Ltd + +OUI:0050C2577* + ID_OUI_FROM_DATABASE=Advanced Software Technologies + +OUI:0050C2578* + ID_OUI_FROM_DATABASE=Delphi Display Systems, Inc. + +OUI:0050C2579* + ID_OUI_FROM_DATABASE=Gastager Systemtechnik GmbH + +OUI:0050C257A* + ID_OUI_FROM_DATABASE=Pigeon Point Systems LLC + +OUI:0050C257B* + ID_OUI_FROM_DATABASE=ptswitch + +OUI:0050C257C* + ID_OUI_FROM_DATABASE=CYBERSYS + +OUI:0050C257D* + ID_OUI_FROM_DATABASE=Sierra Video Systems + +OUI:0050C257E* + ID_OUI_FROM_DATABASE=Digital Way + +OUI:0050C257F* + ID_OUI_FROM_DATABASE=Orderite, Inc. + +OUI:0050C2580* + ID_OUI_FROM_DATABASE=Buyang Electronics Industrial co.,Ltd. + +OUI:0050C2581* + ID_OUI_FROM_DATABASE=Devitech ApS + +OUI:0050C2582* + ID_OUI_FROM_DATABASE=AllSun A/S + +OUI:0050C2583* + ID_OUI_FROM_DATABASE=Jünger Audio-Studiotechnik GmbH + +OUI:0050C2584* + ID_OUI_FROM_DATABASE=Toyota Motorsport GmbH + +OUI:0050C2585* + ID_OUI_FROM_DATABASE=Wireless Cables Inc + +OUI:0050C2586* + ID_OUI_FROM_DATABASE=Genetix Ltd + +OUI:0050C2587* + ID_OUI_FROM_DATABASE=Dynalco + +OUI:0050C2588* + ID_OUI_FROM_DATABASE=Federal Electronics + +OUI:0050C2589* + ID_OUI_FROM_DATABASE=HORIBA MEDICAL + +OUI:0050C258A* + ID_OUI_FROM_DATABASE=Dixell S.p.a. + +OUI:0050C258B* + ID_OUI_FROM_DATABASE=Innovative Dynamics GmbH + +OUI:0050C258C* + ID_OUI_FROM_DATABASE=Lattice Semiconductor Corp. (LPA) + +OUI:0050C258D* + ID_OUI_FROM_DATABASE=ZAO + +OUI:0050C258E* + ID_OUI_FROM_DATABASE=Penny & Giles Aerospace Ltd + +OUI:0050C258F* + ID_OUI_FROM_DATABASE=XoIP Systems Pty Ltd + +OUI:0050C2590* + ID_OUI_FROM_DATABASE=EM Motorsport Ltd + +OUI:0050C2591* + ID_OUI_FROM_DATABASE=Grosvenor Technology Ltd + +OUI:0050C2592* + ID_OUI_FROM_DATABASE=PaloDEx Group Oy + +OUI:0050C2593* + ID_OUI_FROM_DATABASE=Broadlight + +OUI:0050C2594* + ID_OUI_FROM_DATABASE=Pixel Velocity, Inc. + +OUI:0050C2595* + ID_OUI_FROM_DATABASE=Callpod, Inc. + +OUI:0050C2596* + ID_OUI_FROM_DATABASE=SPANSION + +OUI:0050C2597* + ID_OUI_FROM_DATABASE=Nautel Limited + +OUI:0050C2598* + ID_OUI_FROM_DATABASE=Bundesamt für Strahlenschutz + +OUI:0050C2599* + ID_OUI_FROM_DATABASE=Fen Technology Limited + +OUI:0050C259A* + ID_OUI_FROM_DATABASE=MultiTrode Pty Ltd + +OUI:0050C259B* + ID_OUI_FROM_DATABASE=SAPEC + +OUI:0050C259C* + ID_OUI_FROM_DATABASE=DELSAT GROUP S.A. + +OUI:0050C259D* + ID_OUI_FROM_DATABASE=DSS Networks, Inc. + +OUI:0050C259E* + ID_OUI_FROM_DATABASE=Legerity + +OUI:0050C259F* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:0050C25A0* + ID_OUI_FROM_DATABASE=Rudolph Technologies, Inc. + +OUI:0050C25A1* + ID_OUI_FROM_DATABASE=Vestfold Butikkdata AS + +OUI:0050C25A2* + ID_OUI_FROM_DATABASE=iNET Systems Inc. + +OUI:0050C25A3* + ID_OUI_FROM_DATABASE=LUMEL S.A. + +OUI:0050C25A4* + ID_OUI_FROM_DATABASE=Federal State Unitary Enterprise Experimental Factory for Sc + +OUI:0050C25A5* + ID_OUI_FROM_DATABASE=Equipos de Telecomunicación Optoelectronicos, S.A. + +OUI:0050C25A6* + ID_OUI_FROM_DATABASE=Plastic Logic + +OUI:0050C25A7* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C25A8* + ID_OUI_FROM_DATABASE=ETAP NV + +OUI:0050C25A9* + ID_OUI_FROM_DATABASE=AYC Telecom Ltd + +OUI:0050C25AA* + ID_OUI_FROM_DATABASE=Transenna AB + +OUI:0050C25AB* + ID_OUI_FROM_DATABASE=Eaton Corporation Electrical Group Data Center Solutions - Pulizzi + +OUI:0050C25AC* + ID_OUI_FROM_DATABASE=Kinemetrics, Inc. + +OUI:0050C25AD* + ID_OUI_FROM_DATABASE=Emcom Systems + +OUI:0050C25AE* + ID_OUI_FROM_DATABASE=CPS EUROPE B.V. + +OUI:0050C25AF* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C25B0* + ID_OUI_FROM_DATABASE=INCOTEC GmbH + +OUI:0050C25B1* + ID_OUI_FROM_DATABASE=Rosta Ltd + +OUI:0050C25B2* + ID_OUI_FROM_DATABASE=Syntronic AB + +OUI:0050C25B3* + ID_OUI_FROM_DATABASE=HITECOM System + +OUI:0050C25B4* + ID_OUI_FROM_DATABASE=Terrascience Systems Ltd. + +OUI:0050C25B5* + ID_OUI_FROM_DATABASE=RAFAEL + +OUI:0050C25B6* + ID_OUI_FROM_DATABASE=Kontron (Beijing) Technology Co.,Ltd. + +OUI:0050C25B7* + ID_OUI_FROM_DATABASE=AVerMedia Technologies, Inc. + +OUI:0050C25B8* + ID_OUI_FROM_DATABASE=WestfaliaSurge GmbH + +OUI:0050C25B9* + ID_OUI_FROM_DATABASE=Taiwan Video & Monitor + +OUI:0050C25BA* + ID_OUI_FROM_DATABASE=SAIA Burgess Controls AG + +OUI:0050C25BB* + ID_OUI_FROM_DATABASE=UNIC TECHNOLOGIES INC + +OUI:0050C25BC* + ID_OUI_FROM_DATABASE=Guangzhou Hui Si Information Technologies Inc. + +OUI:0050C25BD* + ID_OUI_FROM_DATABASE=Nomus Comm-Systems + +OUI:0050C25BE* + ID_OUI_FROM_DATABASE=Card Access Services Pty Ltd + +OUI:0050C25BF* + ID_OUI_FROM_DATABASE=Techimp Systems S.r.l. + +OUI:0050C25C0* + ID_OUI_FROM_DATABASE=Pyott-Boone Electronics + +OUI:0050C25C1* + ID_OUI_FROM_DATABASE=R. L. Drake Company + +OUI:0050C25C2* + ID_OUI_FROM_DATABASE=Intuitive Surgical + +OUI:0050C25C3* + ID_OUI_FROM_DATABASE=KS System GmbH + +OUI:0050C25C4* + ID_OUI_FROM_DATABASE=ProMik GmbH + +OUI:0050C25C5* + ID_OUI_FROM_DATABASE=Radiant Imaging, Inc. + +OUI:0050C25C6* + ID_OUI_FROM_DATABASE=Technische Alternative GmbH + +OUI:0050C25C7* + ID_OUI_FROM_DATABASE=InSync Technology Ltd + +OUI:0050C25C8* + ID_OUI_FROM_DATABASE=Georgia Tech Research Institute + +OUI:0050C25C9* + ID_OUI_FROM_DATABASE=Shenzhen Quanlong Technique Co.Ltd + +OUI:0050C25CA* + ID_OUI_FROM_DATABASE=Buyang Electronics Industrial Co., Ltd. + +OUI:0050C25CB* + ID_OUI_FROM_DATABASE=Kobold Sistemi s.r.l. + +OUI:0050C25CC* + ID_OUI_FROM_DATABASE=ENSEO + +OUI:0050C25CD* + ID_OUI_FROM_DATABASE=RADA Electronics Industries Ltd. + +OUI:0050C25CE* + ID_OUI_FROM_DATABASE=Roke Manor Research Ltd + +OUI:0050C25CF* + ID_OUI_FROM_DATABASE=Innomed Medical Inc + +OUI:0050C25D0* + ID_OUI_FROM_DATABASE=Automata Spa + +OUI:0050C25D1* + ID_OUI_FROM_DATABASE=Meucci Solutions + +OUI:0050C25D2* + ID_OUI_FROM_DATABASE=DA-Design Oy + +OUI:0050C25D3* + ID_OUI_FROM_DATABASE=Wexiodisk AB + +OUI:0050C25D4* + ID_OUI_FROM_DATABASE=Buyang Electronics Industrial Co., Ltd. + +OUI:0050C25D5* + ID_OUI_FROM_DATABASE=Cannon Technologies + +OUI:0050C25D6* + ID_OUI_FROM_DATABASE=BioAccess Tecnologia em Biometria Ltda. + +OUI:0050C25D7* + ID_OUI_FROM_DATABASE=Synrad, Inc. + +OUI:0050C25D8* + ID_OUI_FROM_DATABASE=TECHNIFOR SAS + +OUI:0050C25D9* + ID_OUI_FROM_DATABASE=Crimson Microsystems, Inc. + +OUI:0050C25DA* + ID_OUI_FROM_DATABASE=TONNA ELECTRONIQUE + +OUI:0050C25DB* + ID_OUI_FROM_DATABASE=CEGELEC SUD EST + +OUI:0050C25DC* + ID_OUI_FROM_DATABASE=RM Michaelides Software & Elektronik GmbH + +OUI:0050C25DD* + ID_OUI_FROM_DATABASE=SomerData ltd + +OUI:0050C25DE* + ID_OUI_FROM_DATABASE=Magal Senstar Inc. + +OUI:0050C25DF* + ID_OUI_FROM_DATABASE=Gnutek Ltd. + +OUI:0050C25E0* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C25E1* + ID_OUI_FROM_DATABASE=Ittiam Systems (P) Ltd + +OUI:0050C25E2* + ID_OUI_FROM_DATABASE=PYRAMID Computer GmbH + +OUI:0050C25E3* + ID_OUI_FROM_DATABASE=Computechnic AG + +OUI:0050C25E4* + ID_OUI_FROM_DATABASE=Buyang Electronics Industrial Co., Ltd. + +OUI:0050C25E5* + ID_OUI_FROM_DATABASE=Stresstech OY + +OUI:0050C25E6* + ID_OUI_FROM_DATABASE=Musatel + +OUI:0050C25E7* + ID_OUI_FROM_DATABASE=EADS TEST & SERVICES + +OUI:0050C25E8* + ID_OUI_FROM_DATABASE=Info-Chip Communications Ltd. + +OUI:0050C25E9* + ID_OUI_FROM_DATABASE=Micro Technology Services Inc. + +OUI:0050C25EA* + ID_OUI_FROM_DATABASE=Micro Elektronische Producten + +OUI:0050C25EB* + ID_OUI_FROM_DATABASE=Garper Telecomunicaciones, S.L. + +OUI:0050C25EC* + ID_OUI_FROM_DATABASE=ASiS Technologies Pte Ltd + +OUI:0050C25ED* + ID_OUI_FROM_DATABASE=AQUAROTTER A FRANKE COMPANY + +OUI:0050C25EE* + ID_OUI_FROM_DATABASE=Condre Corporation + +OUI:0050C25EF* + ID_OUI_FROM_DATABASE=pikkerton GmbH + +OUI:0050C25F0* + ID_OUI_FROM_DATABASE=DIAS Infrared GmbH + +OUI:0050C25F1* + ID_OUI_FROM_DATABASE=Technomarine JSC + +OUI:0050C25F2* + ID_OUI_FROM_DATABASE=ESEM Grünau GmbH & Co. KG + +OUI:0050C25F3* + ID_OUI_FROM_DATABASE=POSNET Polska S.A. + +OUI:0050C25F4* + ID_OUI_FROM_DATABASE=TeamProjects BV + +OUI:0050C25F5* + ID_OUI_FROM_DATABASE=Genesis inc + +OUI:0050C25F6* + ID_OUI_FROM_DATABASE=CAMBRIDGE CONSULTANTS LTD + +OUI:0050C25F7* + ID_OUI_FROM_DATABASE=Metrologic Group + +OUI:0050C25F8* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C25F9* + ID_OUI_FROM_DATABASE=ROTHARY Solutions AG + +OUI:0050C25FA* + ID_OUI_FROM_DATABASE=LEA d.o.o. + +OUI:0050C25FB* + ID_OUI_FROM_DATABASE=All-Systems Electronics Pty Ltd + +OUI:0050C25FC* + ID_OUI_FROM_DATABASE=FilmLight Limited + +OUI:0050C25FD* + ID_OUI_FROM_DATABASE=MEG Electronic Inc. + +OUI:0050C25FE* + ID_OUI_FROM_DATABASE=Novacomm + +OUI:0050C25FF* + ID_OUI_FROM_DATABASE=Gazelle Monitoring Systems + +OUI:0050C2600* + ID_OUI_FROM_DATABASE=Protec Fire Detection plc + +OUI:0050C2601* + ID_OUI_FROM_DATABASE=MedAvant Healthcare + +OUI:0050C2602* + ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX + +OUI:0050C2603* + ID_OUI_FROM_DATABASE=Cerus Corp + +OUI:0050C2604* + ID_OUI_FROM_DATABASE=HCJB Global + +OUI:0050C2605* + ID_OUI_FROM_DATABASE=Swistec GmbH + +OUI:0050C2606* + ID_OUI_FROM_DATABASE=Shenzhen Huazhong Technology Inc + +OUI:0050C2607* + ID_OUI_FROM_DATABASE=Telecom FM + +OUI:0050C2608* + ID_OUI_FROM_DATABASE=Silex Industrial Automation Ltd. + +OUI:0050C2609* + ID_OUI_FROM_DATABASE=Toptech Systems, Inc. + +OUI:0050C260A* + ID_OUI_FROM_DATABASE=Gradual Tecnologia Ltda. + +OUI:0050C260B* + ID_OUI_FROM_DATABASE=Shanghai QianJin Electronic Equipment Co. Ltd. + +OUI:0050C260C* + ID_OUI_FROM_DATABASE=IDENTIC AB + +OUI:0050C260D* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C260E* + ID_OUI_FROM_DATABASE=Automation and Control Technology, Inc. + +OUI:0050C260F* + ID_OUI_FROM_DATABASE=Kommunikations- & Sicherheitssysteme Gesellschaft m.b.H + +OUI:0050C2610* + ID_OUI_FROM_DATABASE=FDT Manufacturing, LLC + +OUI:0050C2611* + ID_OUI_FROM_DATABASE=Brookhaven National Laboratory + +OUI:0050C2612* + ID_OUI_FROM_DATABASE=IHP-GmbH + +OUI:0050C2613* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C2614* + ID_OUI_FROM_DATABASE=SICOM AS + +OUI:0050C2615* + ID_OUI_FROM_DATABASE=Axis Electronics + +OUI:0050C2616* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:0050C2617* + ID_OUI_FROM_DATABASE=NARINET, INC. + +OUI:0050C2618* + ID_OUI_FROM_DATABASE=Intergrated Security Mfg. Ltd + +OUI:0050C2619* + ID_OUI_FROM_DATABASE=Linkbit, Inc. + +OUI:0050C261A* + ID_OUI_FROM_DATABASE=Communication Components Inc. + +OUI:0050C261B* + ID_OUI_FROM_DATABASE=NCI Technologies Inc. + +OUI:0050C261C* + ID_OUI_FROM_DATABASE=TestPro Systems, Inc. + +OUI:0050C261D* + ID_OUI_FROM_DATABASE=Sutus Inc + +OUI:0050C261E* + ID_OUI_FROM_DATABASE=LESTER ELECTRONICS LTD + +OUI:0050C261F* + ID_OUI_FROM_DATABASE=Imagine Communications + +OUI:0050C2620* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +OUI:0050C2621* + ID_OUI_FROM_DATABASE=Version-T + +OUI:0050C2622* + ID_OUI_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +OUI:0050C2623* + ID_OUI_FROM_DATABASE=SAFELINE SL + +OUI:0050C2624* + ID_OUI_FROM_DATABASE=Comtest Networks + +OUI:0050C2625* + ID_OUI_FROM_DATABASE=EBNeuro SpA + +OUI:0050C2626* + ID_OUI_FROM_DATABASE=Winsys Informatica ltda + +OUI:0050C2627* + ID_OUI_FROM_DATABASE=JungleSystem Co., Ltd. + +OUI:0050C2628* + ID_OUI_FROM_DATABASE=DARE Development + +OUI:0050C2629* + ID_OUI_FROM_DATABASE=MacDonald Humfrey (Products) Ltd + +OUI:0050C262A* + ID_OUI_FROM_DATABASE=Prisma Engineering srl + +OUI:0050C262B* + ID_OUI_FROM_DATABASE=First Control Systems AB + +OUI:0050C262C* + ID_OUI_FROM_DATABASE=AirMatrix, Inc. + +OUI:0050C262D* + ID_OUI_FROM_DATABASE=Procon Electronics + +OUI:0050C262E* + ID_OUI_FROM_DATABASE=TDM Ingénierie + +OUI:0050C262F* + ID_OUI_FROM_DATABASE=QES + +OUI:0050C2630* + ID_OUI_FROM_DATABASE=Aurora Flight Sciences + +OUI:0050C2631* + ID_OUI_FROM_DATABASE=Fraunhofer IIS + +OUI:0050C2632* + ID_OUI_FROM_DATABASE=RoseTechnology A/S + +OUI:0050C2633* + ID_OUI_FROM_DATABASE=Rice University + +OUI:0050C2634* + ID_OUI_FROM_DATABASE=Sohon Inc + +OUI:0050C2635* + ID_OUI_FROM_DATABASE=Shockfish SA + +OUI:0050C2636* + ID_OUI_FROM_DATABASE=dSPACE GmbH + +OUI:0050C2637* + ID_OUI_FROM_DATABASE=Omnitrol Networks, Inc. + +OUI:0050C2638* + ID_OUI_FROM_DATABASE=HUNGAROCOM Telecommunication Ltd. + +OUI:0050C2639* + ID_OUI_FROM_DATABASE=Qstreams Networks Inc. + +OUI:0050C263A* + ID_OUI_FROM_DATABASE=3DSP Corporation + +OUI:0050C263B* + ID_OUI_FROM_DATABASE=Powis Corporation + +OUI:0050C263C* + ID_OUI_FROM_DATABASE=dPict Imaging, Inc. + +OUI:0050C263D* + ID_OUI_FROM_DATABASE=IDERs Inc + +OUI:0050C263E* + ID_OUI_FROM_DATABASE=T2 Communication Ltd + +OUI:0050C263F* + ID_OUI_FROM_DATABASE=Speech Technology Center, Ltd. + +OUI:0050C2640* + ID_OUI_FROM_DATABASE=IAC + +OUI:0050C2641* + ID_OUI_FROM_DATABASE=NEO Information Systems Co., Ltd. + +OUI:0050C2642* + ID_OUI_FROM_DATABASE=Stanton Technologies Sdn Bhd + +OUI:0050C2643* + ID_OUI_FROM_DATABASE=Enatel Limited + +OUI:0050C2644* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2645* + ID_OUI_FROM_DATABASE=The Software Group Limited + +OUI:0050C2646* + ID_OUI_FROM_DATABASE=TRUTOUCH TECHNOLOGIES INC + +OUI:0050C2647* + ID_OUI_FROM_DATABASE=R&D Technology Solutionz Limited + +OUI:0050C2648* + ID_OUI_FROM_DATABASE=Fidelity Comtech, Inc. + +OUI:0050C2649* + ID_OUI_FROM_DATABASE=Pan-STARRS + +OUI:0050C264A* + ID_OUI_FROM_DATABASE=CPqD + +OUI:0050C264B* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C264C* + ID_OUI_FROM_DATABASE=CIS Corporation + +OUI:0050C264D* + ID_OUI_FROM_DATABASE=Tera Information System Labs + +OUI:0050C264E* + ID_OUI_FROM_DATABASE=Northern Power + +OUI:0050C264F* + ID_OUI_FROM_DATABASE=MA Lighting Technology GmbH + +OUI:0050C2650* + ID_OUI_FROM_DATABASE=Liquid Breaker, LLC + +OUI:0050C2651* + ID_OUI_FROM_DATABASE=STAER SPA + +OUI:0050C2652* + ID_OUI_FROM_DATABASE=Wideco Sweden AB + +OUI:0050C2653* + ID_OUI_FROM_DATABASE=Doble Engineering + +OUI:0050C2654* + ID_OUI_FROM_DATABASE=PaloDEx Group Oy + +OUI:0050C2655* + ID_OUI_FROM_DATABASE=Physik Instrumente (PI) GmbH&Co.KG + +OUI:0050C2656* + ID_OUI_FROM_DATABASE=LDA Audio Video Profesional + +OUI:0050C2657* + ID_OUI_FROM_DATABASE=MONYTEL S.A. + +OUI:0050C2658* + ID_OUI_FROM_DATABASE=OpenPKG GmbH + +OUI:0050C2659* + ID_OUI_FROM_DATABASE=Dorsett Technologies, Inc. + +OUI:0050C265A* + ID_OUI_FROM_DATABASE=Hisstema AB + +OUI:0050C265B* + ID_OUI_FROM_DATABASE=Silverbrook Research + +OUI:0050C265C* + ID_OUI_FROM_DATABASE=VTZ d.o.o. + +OUI:0050C265D* + ID_OUI_FROM_DATABASE=Redfone Communications LLC + +OUI:0050C265E* + ID_OUI_FROM_DATABASE=Cantion A/S + +OUI:0050C265F* + ID_OUI_FROM_DATABASE=Invocon, Inc. + +OUI:0050C2660* + ID_OUI_FROM_DATABASE=IZISOFT + +OUI:0050C2661* + ID_OUI_FROM_DATABASE=P.C.E. + +OUI:0050C2662* + ID_OUI_FROM_DATABASE=Asia Pacific Card & System Sdn Bhd + +OUI:0050C2663* + ID_OUI_FROM_DATABASE=COE Limited + +OUI:0050C2664* + ID_OUI_FROM_DATABASE=Westel Wireless Systems + +OUI:0050C2665* + ID_OUI_FROM_DATABASE=NetworkSound, Inc + +OUI:0050C2666* + ID_OUI_FROM_DATABASE=Xworks NZ Limited + +OUI:0050C2668* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2669* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C266A* + ID_OUI_FROM_DATABASE=ABB Xiamen Transmission and Distribution Automation Equipmen + +OUI:0050C266B* + ID_OUI_FROM_DATABASE=flsystem + +OUI:0050C266C* + ID_OUI_FROM_DATABASE=DESY + +OUI:0050C266D* + ID_OUI_FROM_DATABASE=DIGITEK S.p.A. + +OUI:0050C266E* + ID_OUI_FROM_DATABASE=Linear Systems Ltd. + +OUI:0050C266F* + ID_OUI_FROM_DATABASE=Nilan A/S + +OUI:0050C2670* + ID_OUI_FROM_DATABASE=Naim Audio + +OUI:0050C2671* + ID_OUI_FROM_DATABASE=Skyline Products, Inc + +OUI:0050C2672* + ID_OUI_FROM_DATABASE=DDS Elettronica srl + +OUI:0050C2673* + ID_OUI_FROM_DATABASE=Ferrari electronic AG + +OUI:0050C2674* + ID_OUI_FROM_DATABASE=Protech Optronics Co., Ltd. + +OUI:0050C2675* + ID_OUI_FROM_DATABASE=Kenton Research Ltd + +OUI:0050C2676* + ID_OUI_FROM_DATABASE=EDS + +OUI:0050C2677* + ID_OUI_FROM_DATABASE=ProconX Pty Ltd + +OUI:0050C2678* + ID_OUI_FROM_DATABASE=IHM + +OUI:0050C2679* + ID_OUI_FROM_DATABASE=Industrial Vacuum Systems + +OUI:0050C267A* + ID_OUI_FROM_DATABASE=CC Systems AB + +OUI:0050C267B* + ID_OUI_FROM_DATABASE=Sparton Electronics + +OUI:0050C267C* + ID_OUI_FROM_DATABASE=AirCell, Inc. + +OUI:0050C267D* + ID_OUI_FROM_DATABASE=ESA Messtechnik GmbH + +OUI:0050C267E* + ID_OUI_FROM_DATABASE=SAIA Burgess Controls AG + +OUI:0050C267F* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2680* + ID_OUI_FROM_DATABASE=Honey Network Research Limited + +OUI:0050C2681* + ID_OUI_FROM_DATABASE=Owasys Advanced Wireless Devices + +OUI:0050C2682* + ID_OUI_FROM_DATABASE=Commet AB + +OUI:0050C2683* + ID_OUI_FROM_DATABASE=MEGGITT Safety System + +OUI:0050C2684* + ID_OUI_FROM_DATABASE=REASON Tecnologia S.A. + +OUI:0050C2685* + ID_OUI_FROM_DATABASE=Datamars SA + +OUI:0050C2686* + ID_OUI_FROM_DATABASE=ANNAX Anzeigesysteme GmbH + +OUI:0050C2687* + ID_OUI_FROM_DATABASE=Access Specialties, Inc + +OUI:0050C2688* + ID_OUI_FROM_DATABASE=Elk Products + +OUI:0050C2689* + ID_OUI_FROM_DATABASE=RF Code, Inc. + +OUI:0050C268A* + ID_OUI_FROM_DATABASE=Zhuhai Jiahe Electronics Co.,LTD + +OUI:0050C268B* + ID_OUI_FROM_DATABASE=SIMTEK INC. + +OUI:0050C268C* + ID_OUI_FROM_DATABASE=Isochron Inc + +OUI:0050C268D* + ID_OUI_FROM_DATABASE=CXR Larus Corporation + +OUI:0050C268E* + ID_OUI_FROM_DATABASE=SELCO + +OUI:0050C268F* + ID_OUI_FROM_DATABASE=BERTRONIC SRL + +OUI:0050C2690* + ID_OUI_FROM_DATABASE=GHL Systems Berhad + +OUI:0050C2691* + ID_OUI_FROM_DATABASE=Interopix, Inc. + +OUI:0050C2692* + ID_OUI_FROM_DATABASE=Mate Media Access Technologies + +OUI:0050C2693* + ID_OUI_FROM_DATABASE=Tech Comm, Inc. + +OUI:0050C2694* + ID_OUI_FROM_DATABASE=Initel srl + +OUI:0050C2695* + ID_OUI_FROM_DATABASE=Purelink Technology, inc. + +OUI:0050C2696* + ID_OUI_FROM_DATABASE=Casabyte Inc. + +OUI:0050C2697* + ID_OUI_FROM_DATABASE=Monarch Instrument + +OUI:0050C2698* + ID_OUI_FROM_DATABASE=Navtech Radar Ltd + +OUI:0050C2699* + ID_OUI_FROM_DATABASE=Bulletendpoints Enterprises Inc + +OUI:0050C269A* + ID_OUI_FROM_DATABASE=StoreTech Limited + +OUI:0050C269B* + ID_OUI_FROM_DATABASE=Tsien (UK) Ltd + +OUI:0050C269C* + ID_OUI_FROM_DATABASE=Bug Labs, Inc. + +OUI:0050C269D* + ID_OUI_FROM_DATABASE=Dvation.co.,Ltd + +OUI:0050C269E* + ID_OUI_FROM_DATABASE=Ideus AB + +OUI:0050C269F* + ID_OUI_FROM_DATABASE=Total RF, LLC + +OUI:0050C26A0* + ID_OUI_FROM_DATABASE=GFP Lab S.r.l. + +OUI:0050C26A1* + ID_OUI_FROM_DATABASE=PRICOL LIMITED + +OUI:0050C26A2* + ID_OUI_FROM_DATABASE=Cadi Scientific Pte Ltd + +OUI:0050C26A3* + ID_OUI_FROM_DATABASE=CreaTech Electronics Co. + +OUI:0050C26A4* + ID_OUI_FROM_DATABASE=TELETASK + +OUI:0050C26A5* + ID_OUI_FROM_DATABASE=FHF Funke+Huster Fernsig GmbH + +OUI:0050C26A6* + ID_OUI_FROM_DATABASE=Victory Concept Industries Ltd. + +OUI:0050C26A7* + ID_OUI_FROM_DATABASE=Hoer GmbH & Co. Industrie-Electronic KG + +OUI:0050C26A8* + ID_OUI_FROM_DATABASE=Delcan Technologies, Inc + +OUI:0050C26A9* + ID_OUI_FROM_DATABASE=Armida Technologies Corporation + +OUI:0050C26AA* + ID_OUI_FROM_DATABASE=Ifox - Industria e Comercio Ltda + +OUI:0050C26AB* + ID_OUI_FROM_DATABASE=Softwareentwicklung + +OUI:0050C26AC* + ID_OUI_FROM_DATABASE=Thales UK + +OUI:0050C26AD* + ID_OUI_FROM_DATABASE=Heim- & Bürokommunikation + +OUI:0050C26AE* + ID_OUI_FROM_DATABASE=Qualisys AB + +OUI:0050C26AF* + ID_OUI_FROM_DATABASE=Nanoradio AB + +OUI:0050C26B0* + ID_OUI_FROM_DATABASE=Smart Key International Limited + +OUI:0050C26B1* + ID_OUI_FROM_DATABASE=Burk Technology + +OUI:0050C26B2* + ID_OUI_FROM_DATABASE=Edgeware AB + +OUI:0050C26B3* + ID_OUI_FROM_DATABASE=4RF Communications Ltd + +OUI:0050C26B4* + ID_OUI_FROM_DATABASE=SOMESCA + +OUI:0050C26B5* + ID_OUI_FROM_DATABASE=TRIUMF + +OUI:0050C26B6* + ID_OUI_FROM_DATABASE=CommoDaS GmbH + +OUI:0050C26B7* + ID_OUI_FROM_DATABASE=System LSI CO.Ltd. + +OUI:0050C26B8* + ID_OUI_FROM_DATABASE=Epec Oy + +OUI:0050C26B9* + ID_OUI_FROM_DATABASE=unipo GmbH + +OUI:0050C26BA* + ID_OUI_FROM_DATABASE=Fertron Controle e Automacao Industrial Ltda. + +OUI:0050C26BB* + ID_OUI_FROM_DATABASE=Ele.Mag S.r.l. + +OUI:0050C26BC* + ID_OUI_FROM_DATABASE=Paraytec Ltd + +OUI:0050C26BD* + ID_OUI_FROM_DATABASE=Mitron Oy + +OUI:0050C26BE* + ID_OUI_FROM_DATABASE=ESTEC Co.,Ltd. + +OUI:0050C26BF* + ID_OUI_FROM_DATABASE=Optoplan as + +OUI:0050C26C0* + ID_OUI_FROM_DATABASE=GLOSTER SANTE EUROPE + +OUI:0050C26C1* + ID_OUI_FROM_DATABASE=RADIUS Sweden AB + +OUI:0050C26C2* + ID_OUI_FROM_DATABASE=HoseoTelnet Inc... + +OUI:0050C26C3* + ID_OUI_FROM_DATABASE=iTRACS Corporation + +OUI:0050C26C4* + ID_OUI_FROM_DATABASE=REXXON GmbH + +OUI:0050C26C5* + ID_OUI_FROM_DATABASE=Oerlikon Contraves AG + +OUI:0050C26C6* + ID_OUI_FROM_DATABASE=MedAvant Healthcare Solutions + +OUI:0050C26C7* + ID_OUI_FROM_DATABASE=QuickCircuit Ltd. + +OUI:0050C26C8* + ID_OUI_FROM_DATABASE=B&S MEDIA CO., LTD. + +OUI:0050C26C9* + ID_OUI_FROM_DATABASE=NETAMI + +OUI:0050C26CA* + ID_OUI_FROM_DATABASE=Dynamic Hearing Pty Ltd + +OUI:0050C26CB* + ID_OUI_FROM_DATABASE=Stream Processors + +OUI:0050C26CC* + ID_OUI_FROM_DATABASE=Widmer Time Recorder Co., Inc. + +OUI:0050C26CD* + ID_OUI_FROM_DATABASE=RGM SPA + +OUI:0050C26CE* + ID_OUI_FROM_DATABASE=EMITALL Surveillance S.A, + +OUI:0050C26CF* + ID_OUI_FROM_DATABASE=Microway + +OUI:0050C26D0* + ID_OUI_FROM_DATABASE=EDS Systemtechnik + +OUI:0050C26D1* + ID_OUI_FROM_DATABASE=Schnick-Schnack-Systems GmbH + +OUI:0050C26D2* + ID_OUI_FROM_DATABASE=Lumistar Incorporated + +OUI:0050C26D3* + ID_OUI_FROM_DATABASE=DigiSensory technologies Pty Ltd + +OUI:0050C26D4* + ID_OUI_FROM_DATABASE=Etani Electronics Co.,Ltd. + +OUI:0050C26D5* + ID_OUI_FROM_DATABASE=Becker Electronics GmbH + +OUI:0050C26D6* + ID_OUI_FROM_DATABASE=ADL Electronics Ltd. + +OUI:0050C26D7* + ID_OUI_FROM_DATABASE=Mavenir System, Inc. + +OUI:0050C26D8* + ID_OUI_FROM_DATABASE=BL Healthcare, Inc. + +OUI:0050C26D9* + ID_OUI_FROM_DATABASE=Ajeco Oy + +OUI:0050C26DA* + ID_OUI_FROM_DATABASE=Techno Fittings S.r.l. + +OUI:0050C26DB* + ID_OUI_FROM_DATABASE=Gebhardt Ventilatoren GmbH + +OUI:0050C26DC* + ID_OUI_FROM_DATABASE=L-3 Communications Mobile-Vision, Inc. + +OUI:0050C26DD* + ID_OUI_FROM_DATABASE=Zmicro Systems Inc + +OUI:0050C26DE* + ID_OUI_FROM_DATABASE=Laser Tools & Technics Corp. + +OUI:0050C26DF* + ID_OUI_FROM_DATABASE=QR Sciences Ltd + +OUI:0050C26E0* + ID_OUI_FROM_DATABASE=FIRSTTRUST Co.,Ltd. + +OUI:0050C26E1* + ID_OUI_FROM_DATABASE=NewOnSys Ltd. + +OUI:0050C26E2* + ID_OUI_FROM_DATABASE=PHYTEC Messtechnik GmbH + +OUI:0050C26E3* + ID_OUI_FROM_DATABASE=Miros AS + +OUI:0050C26E4* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C26E5* + ID_OUI_FROM_DATABASE=Boeckeler Instruments, Inc. + +OUI:0050C26E6* + ID_OUI_FROM_DATABASE=Lanetco + +OUI:0050C26E7* + ID_OUI_FROM_DATABASE=Axis Network Technology + +OUI:0050C26E8* + ID_OUI_FROM_DATABASE=Anymax + +OUI:0050C26E9* + ID_OUI_FROM_DATABASE=Bando electronic communication Co.Lltd + +OUI:0050C26EA* + ID_OUI_FROM_DATABASE=FIRSTEC SA + +OUI:0050C26EB* + ID_OUI_FROM_DATABASE=Harrison Audio, LLC + +OUI:0050C26EC* + ID_OUI_FROM_DATABASE=Netistix Technologies Corporation + +OUI:0050C26ED* + ID_OUI_FROM_DATABASE=Sechan Electronics, Inc. + +OUI:0050C26EE* + ID_OUI_FROM_DATABASE=Interactive Electronic Systems + +OUI:0050C26EF* + ID_OUI_FROM_DATABASE=Pneumopartners LaenneXT SA + +OUI:0050C26F0* + ID_OUI_FROM_DATABASE=Stanley Security Solutions, Inc. + +OUI:0050C26F1* + ID_OUI_FROM_DATABASE=ITS Telecom + +OUI:0050C26F2* + ID_OUI_FROM_DATABASE=Laser Electronics Ltd + +OUI:0050C26F3* + ID_OUI_FROM_DATABASE=E3Switch LLC + +OUI:0050C26F4* + ID_OUI_FROM_DATABASE=Cryogenic Control Systems, Inc. + +OUI:0050C26F5* + ID_OUI_FROM_DATABASE=Kitron Microelectronics AB + +OUI:0050C26F6* + ID_OUI_FROM_DATABASE=AV SatCom AS + +OUI:0050C26F7* + ID_OUI_FROM_DATABASE=infoplan Gesellschaftfür Informationssysteme mbH + +OUI:0050C26F8* + ID_OUI_FROM_DATABASE=RV Technology Limited + +OUI:0050C26F9* + ID_OUI_FROM_DATABASE=Revox GmbH + +OUI:0050C26FA* + ID_OUI_FROM_DATABASE=DCN + +OUI:0050C26FB* + ID_OUI_FROM_DATABASE=WaveIP + +OUI:0050C26FC* + ID_OUI_FROM_DATABASE=Acte Sp. z o.o. + +OUI:0050C26FD* + ID_OUI_FROM_DATABASE=SAIA Burgess Controls AG + +OUI:0050C26FE* + ID_OUI_FROM_DATABASE=Blue Origin + +OUI:0050C26FF* + ID_OUI_FROM_DATABASE=St. Michael Strategies Inc. + +OUI:0050C2700* + ID_OUI_FROM_DATABASE=GEM-MED SL + +OUI:0050C2701* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2702* + ID_OUI_FROM_DATABASE=SPM Instrument AB + +OUI:0050C2703* + ID_OUI_FROM_DATABASE=SAE IT-systems GmbH & Co. KG + +OUI:0050C2704* + ID_OUI_FROM_DATABASE=The Dini Group, La Jolla inc. + +OUI:0050C2705* + ID_OUI_FROM_DATABASE=Hauch & Bach ApS + +OUI:0050C2706* + ID_OUI_FROM_DATABASE=DioDigiWorks. CO., LTD. + +OUI:0050C2707* + ID_OUI_FROM_DATABASE=DTech Labs Inc + +OUI:0050C2708* + ID_OUI_FROM_DATABASE=Smartek d.o.o. + +OUI:0050C2709* + ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A + +OUI:0050C270A* + ID_OUI_FROM_DATABASE=Efficient Channel Coding + +OUI:0050C270B* + ID_OUI_FROM_DATABASE=B.E.A.R. Solutions (Australasia) Pty, Ltd + +OUI:0050C270C* + ID_OUI_FROM_DATABASE=Exertus + +OUI:0050C270D* + ID_OUI_FROM_DATABASE=ela-soft GmbH & Co. KG + +OUI:0050C270E* + ID_OUI_FROM_DATABASE=AUDICO SYSTEMS OY + +OUI:0050C270F* + ID_OUI_FROM_DATABASE=Zumbach Electronic AG + +OUI:0050C2710* + ID_OUI_FROM_DATABASE=Wharton Electronics Ltd + +OUI:0050C2711* + ID_OUI_FROM_DATABASE=LINKIT S.R.L. + +OUI:0050C2712* + ID_OUI_FROM_DATABASE=Pasan SA + +OUI:0050C2713* + ID_OUI_FROM_DATABASE=3DX-Ray Limited + +OUI:0050C2714* + ID_OUI_FROM_DATABASE=T.E.AM., S. A. + +OUI:0050C2715* + ID_OUI_FROM_DATABASE=RIEXINGER Elektronik + +OUI:0050C2716* + ID_OUI_FROM_DATABASE=MITROL S.R.L. + +OUI:0050C2717* + ID_OUI_FROM_DATABASE=MB Connect Line GmbH + +OUI:0050C2718* + ID_OUI_FROM_DATABASE=illunis LLC + +OUI:0050C2719* + ID_OUI_FROM_DATABASE=ennovatis GmbH + +OUI:0050C271A* + ID_OUI_FROM_DATABASE=Logus Broadband Wireless Solutions Inc. + +OUI:0050C271B* + ID_OUI_FROM_DATABASE=ADVA Optical Networking + +OUI:0050C271C* + ID_OUI_FROM_DATABASE=Elmec Inc. + +OUI:0050C271D* + ID_OUI_FROM_DATABASE=MG s.r.l. + +OUI:0050C271E* + ID_OUI_FROM_DATABASE=ASKI Industrie Elektronik Ges.m.b.H. + +OUI:0050C271F* + ID_OUI_FROM_DATABASE=ASC telecom AG + +OUI:0050C2720* + ID_OUI_FROM_DATABASE=Colorado Engineering Inc. + +OUI:0050C2721* + ID_OUI_FROM_DATABASE=Spectrum Communications FZE + +OUI:0050C2722* + ID_OUI_FROM_DATABASE=Centric TSolve BV + +OUI:0050C2723* + ID_OUI_FROM_DATABASE=Power Electronics + +OUI:0050C2724* + ID_OUI_FROM_DATABASE=HSC-Regelungstechnik GmbH + +OUI:0050C2725* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C2726* + ID_OUI_FROM_DATABASE=eta systemi CKB + +OUI:0050C2727* + ID_OUI_FROM_DATABASE=Pelweckyj Videotechnik GmbH + +OUI:0050C2728* + ID_OUI_FROM_DATABASE=InterDigital Canada Ltd + +OUI:0050C2729* + ID_OUI_FROM_DATABASE=SP Controls, Inc + +OUI:0050C272A* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C272B* + ID_OUI_FROM_DATABASE=Sequestered Solutions + +OUI:0050C272C* + ID_OUI_FROM_DATABASE=Richard Griessbach Feinmechanik GmbH + +OUI:0050C272D* + ID_OUI_FROM_DATABASE=Physical Acoustics Corporation + +OUI:0050C272E* + ID_OUI_FROM_DATABASE=SNCF EIM PAYS DE LOIRE + +OUI:0050C272F* + ID_OUI_FROM_DATABASE=Priority Electronics Ltd + +OUI:0050C2730* + ID_OUI_FROM_DATABASE=haber & koenig electronics gmbh + +OUI:0050C2731* + ID_OUI_FROM_DATABASE=Spirent Communications + +OUI:0050C2732* + ID_OUI_FROM_DATABASE=Schlumberger K.K. + +OUI:0050C2733* + ID_OUI_FROM_DATABASE=Cimetrics Research Pty Ltd + +OUI:0050C2734* + ID_OUI_FROM_DATABASE=CardioMEMS Inc. + +OUI:0050C2735* + ID_OUI_FROM_DATABASE=Ant Lamp, Inc + +OUI:0050C2736* + ID_OUI_FROM_DATABASE=Nika Ltd + +OUI:0050C2737* + ID_OUI_FROM_DATABASE=Teradici Corporation + +OUI:0050C2738* + ID_OUI_FROM_DATABASE=Miracom Technology Co., Ltd. + +OUI:0050C2739* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:0050C273A* + ID_OUI_FROM_DATABASE=Naturela Ltd. + +OUI:0050C273B* + ID_OUI_FROM_DATABASE=On Air Networks + +OUI:0050C273C* + ID_OUI_FROM_DATABASE=Simicon + +OUI:0050C273D* + ID_OUI_FROM_DATABASE=cryptiris + +OUI:0050C273E* + ID_OUI_FROM_DATABASE=Quantec Networks GmbH + +OUI:0050C273F* + ID_OUI_FROM_DATABASE=MEDAV GmbH + +OUI:0050C2740* + ID_OUI_FROM_DATABASE=McQuay China + +OUI:0050C2741* + ID_OUI_FROM_DATABASE=Dain + +OUI:0050C2742* + ID_OUI_FROM_DATABASE=Fantuzzi Reggiane + +OUI:0050C2743* + ID_OUI_FROM_DATABASE=Elektro-Top 3000 Ltd. + +OUI:0050C2744* + ID_OUI_FROM_DATABASE=Avonaco Systems, Inc. + +OUI:0050C2745* + ID_OUI_FROM_DATABASE=ACISA + +OUI:0050C2746* + ID_OUI_FROM_DATABASE=Realtronix Company + +OUI:0050C2747* + ID_OUI_FROM_DATABASE=CDSA Dam Neck + +OUI:0050C2748* + ID_OUI_FROM_DATABASE=Letechnic Ltd + +OUI:0050C2749* + ID_OUI_FROM_DATABASE=Affolter Technologies SA + +OUI:0050C274A* + ID_OUI_FROM_DATABASE=MONITOR ELECTRONICS LTD + +OUI:0050C274B* + ID_OUI_FROM_DATABASE=STAR-Dundee Ltd + +OUI:0050C274C* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C274D* + ID_OUI_FROM_DATABASE=Beceem Communications, Inc. + +OUI:0050C274E* + ID_OUI_FROM_DATABASE=TRONICO + +OUI:0050C274F* + ID_OUI_FROM_DATABASE=German Technologies + +OUI:0050C2750* + ID_OUI_FROM_DATABASE=Brightlights Intellectual Property Ltd + +OUI:0050C2751* + ID_OUI_FROM_DATABASE=e&s Engineering & Software GmbH + +OUI:0050C2752* + ID_OUI_FROM_DATABASE=LOBER, S.A. + +OUI:0050C2753* + ID_OUI_FROM_DATABASE=ABB + +OUI:0050C2754* + ID_OUI_FROM_DATABASE=Abeo Corporation + +OUI:0050C2755* + ID_OUI_FROM_DATABASE=Teletek Electronics + +OUI:0050C2756* + ID_OUI_FROM_DATABASE=Chesapeake Sciences Corp + +OUI:0050C2757* + ID_OUI_FROM_DATABASE=E S P Technologies Ltd + +OUI:0050C2758* + ID_OUI_FROM_DATABASE=AixSolve GmbH + +OUI:0050C2759* + ID_OUI_FROM_DATABASE=Sequentric Energy Systems, LLC + +OUI:0050C275A* + ID_OUI_FROM_DATABASE=Gaisler Research AB + +OUI:0050C275B* + ID_OUI_FROM_DATABASE=DMT System S.p.A. + +OUI:0050C275C* + ID_OUI_FROM_DATABASE=STÖRK-TRONIC Störk GmbH&Co. KG + +OUI:0050C275D* + ID_OUI_FROM_DATABASE=Fluid Analytics, Inc. + +OUI:0050C275E* + ID_OUI_FROM_DATABASE=Sky-Skan, Incorporated + +OUI:0050C275F* + ID_OUI_FROM_DATABASE=B. Rexroth the identity company GmbH + +OUI:0050C2760* + ID_OUI_FROM_DATABASE=AR'S CO., LTD. + +OUI:0050C2761* + ID_OUI_FROM_DATABASE=Elbit Systems of America - Fort Worth Operations + +OUI:0050C2762* + ID_OUI_FROM_DATABASE=Assembly Contracts Limited + +OUI:0050C2763* + ID_OUI_FROM_DATABASE=XtendWave + +OUI:0050C2764* + ID_OUI_FROM_DATABASE=Argus-Spectrum + +OUI:0050C2765* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2766* + ID_OUI_FROM_DATABASE=Gutermann Technology GmbH + +OUI:0050C2767* + ID_OUI_FROM_DATABASE=EID + +OUI:0050C2768* + ID_OUI_FROM_DATABASE=Control Service do Brasil Ltda + +OUI:0050C2769* + ID_OUI_FROM_DATABASE=BES GmbH + +OUI:0050C276A* + ID_OUI_FROM_DATABASE=Digidrive Audio Limited + +OUI:0050C276B* + ID_OUI_FROM_DATABASE=Putercom Enterprise Co., LTD. + +OUI:0050C276C* + ID_OUI_FROM_DATABASE=EFG CZ spol. s r.o. + +OUI:0050C276D* + ID_OUI_FROM_DATABASE=Mobilisme + +OUI:0050C276E* + ID_OUI_FROM_DATABASE=Crinia Corporation + +OUI:0050C276F* + ID_OUI_FROM_DATABASE=Control and Robotics Solutions + +OUI:0050C2770* + ID_OUI_FROM_DATABASE=Cadex Electronics Inc. + +OUI:0050C2771* + ID_OUI_FROM_DATABASE=ZigBee Alliance + +OUI:0050C2772* + ID_OUI_FROM_DATABASE=IES Elektronikentwicklung + +OUI:0050C2773* + ID_OUI_FROM_DATABASE=Pointe Conception Medical Inc. + +OUI:0050C2774* + ID_OUI_FROM_DATABASE=GeoSIG Ltd. + +OUI:0050C2775* + ID_OUI_FROM_DATABASE=Laserdyne Technologies + +OUI:0050C2776* + ID_OUI_FROM_DATABASE=Integrated Security Corporation + +OUI:0050C2777* + ID_OUI_FROM_DATABASE=Euro Display Srl + +OUI:0050C2778* + ID_OUI_FROM_DATABASE=SunGard Vivista + +OUI:0050C2779* + ID_OUI_FROM_DATABASE=Coral Telecom Ltd + +OUI:0050C277A* + ID_OUI_FROM_DATABASE=Smith Meter, Inc + +OUI:0050C277B* + ID_OUI_FROM_DATABASE=Itibia Technologies, Inc. + +OUI:0050C277C* + ID_OUI_FROM_DATABASE=ATEC SRL + +OUI:0050C277D* + ID_OUI_FROM_DATABASE=Lincoln Industrial + +OUI:0050C277E* + ID_OUI_FROM_DATABASE=Cominfo Inc. + +OUI:0050C277F* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2780* + ID_OUI_FROM_DATABASE=IQ Solutions GmbH & Co. KG + +OUI:0050C2781* + ID_OUI_FROM_DATABASE=Starling Advanced Communications + +OUI:0050C2782* + ID_OUI_FROM_DATABASE=Phytec Mestechnik GmbH + +OUI:0050C2783* + ID_OUI_FROM_DATABASE=NORMA systems GmbH + +OUI:0050C2784* + ID_OUI_FROM_DATABASE=Lewis Controls Inc. + +OUI:0050C2785* + ID_OUI_FROM_DATABASE=Icon Time Systems + +OUI:0050C2786* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2787* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd + +OUI:0050C2788* + ID_OUI_FROM_DATABASE=HOSA TECHNOLOGY, INC. + +OUI:0050C2789* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:0050C278A* + ID_OUI_FROM_DATABASE=LEVEL TELECOM + +OUI:0050C278B* + ID_OUI_FROM_DATABASE=OMICRON electronics GmbH + +OUI:0050C278C* + ID_OUI_FROM_DATABASE=Giga-tronics, Inc. + +OUI:0050C278D* + ID_OUI_FROM_DATABASE=Telairity + +OUI:0050C278E* + ID_OUI_FROM_DATABASE=GLOBALCOM ENGINEERING SRL + +OUI:0050C278F* + ID_OUI_FROM_DATABASE=ELMAR electronic + +OUI:0050C2790* + ID_OUI_FROM_DATABASE=GE Security-Kampro + +OUI:0050C2791* + ID_OUI_FROM_DATABASE=M Squared Lasers Limited + +OUI:0050C2792* + ID_OUI_FROM_DATABASE=SMARTRO Co.,Ltd. + +OUI:0050C2793* + ID_OUI_FROM_DATABASE=Enertex Bayern GmbH + +OUI:0050C2794* + ID_OUI_FROM_DATABASE=COMSONICS, INC. + +OUI:0050C2795* + ID_OUI_FROM_DATABASE=Ameli Spa + +OUI:0050C2796* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C2797* + ID_OUI_FROM_DATABASE=Tiefenbach Control Systems GmbH + +OUI:0050C2798* + ID_OUI_FROM_DATABASE=Indefia + +OUI:0050C2799* + ID_OUI_FROM_DATABASE=AAVD + +OUI:0050C279A* + ID_OUI_FROM_DATABASE=JMC America, LLC + +OUI:0050C279B* + ID_OUI_FROM_DATABASE=Schniewindt GmbH & Co. KG + +OUI:0050C279C* + ID_OUI_FROM_DATABASE=Vital Systems Inc + +OUI:0050C279D* + ID_OUI_FROM_DATABASE=MiraTrek + +OUI:0050C279E* + ID_OUI_FROM_DATABASE=Benshaw Canada Controls, Inc. + +OUI:0050C279F* + ID_OUI_FROM_DATABASE=ZAO NPC + +OUI:0050C27A0* + ID_OUI_FROM_DATABASE=MedAvant Healthcare + +OUI:0050C27A1* + ID_OUI_FROM_DATABASE=Field Design Service + +OUI:0050C27A2* + ID_OUI_FROM_DATABASE=RaySat Israel LTD + +OUI:0050C27A3* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiam + +OUI:0050C27A4* + ID_OUI_FROM_DATABASE=Calibre UK LTD + +OUI:0050C27A5* + ID_OUI_FROM_DATABASE=Quantum Medical Imaging + +OUI:0050C27A6* + ID_OUI_FROM_DATABASE=ASIANA IDT + +OUI:0050C27A7* + ID_OUI_FROM_DATABASE=Guidance Navigation Limited + +OUI:0050C27A8* + ID_OUI_FROM_DATABASE=Integrated Design Tools, Inc. + +OUI:0050C27A9* + ID_OUI_FROM_DATABASE=Delta Tau Data Systems, Inc + +OUI:0050C27AA* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C27AB* + ID_OUI_FROM_DATABASE=General Microsystems Sdn Bhd + +OUI:0050C27AC* + ID_OUI_FROM_DATABASE=IUSA SA DE CV + +OUI:0050C27AD* + ID_OUI_FROM_DATABASE=Turun Turvatekniikka Oy + +OUI:0050C27AE* + ID_OUI_FROM_DATABASE=Global Tel-Link + +OUI:0050C27AF* + ID_OUI_FROM_DATABASE=C2 Microsystems + +OUI:0050C27B0* + ID_OUI_FROM_DATABASE=IMP Telekom + +OUI:0050C27B1* + ID_OUI_FROM_DATABASE=ATEME + +OUI:0050C27B2* + ID_OUI_FROM_DATABASE=A.D.I Video technologies + +OUI:0050C27B3* + ID_OUI_FROM_DATABASE=Elmec, Inc. + +OUI:0050C27B4* + ID_OUI_FROM_DATABASE=T 1 Engineering + +OUI:0050C27B5* + ID_OUI_FROM_DATABASE=DIT-MCO International + +OUI:0050C27B6* + ID_OUI_FROM_DATABASE=Alstom (Schweiz) AG + +OUI:0050C27B7* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C27B8* + ID_OUI_FROM_DATABASE=Design 2000 Pty Ltd + +OUI:0050C27B9* + ID_OUI_FROM_DATABASE=Technovare Systems, Inc. + +OUI:0050C27BA* + ID_OUI_FROM_DATABASE=Infodev Electronic Designers Intl. + +OUI:0050C27BB* + ID_OUI_FROM_DATABASE=InRay Solutions Ltd. + +OUI:0050C27BC* + ID_OUI_FROM_DATABASE=EIDOS SPA + +OUI:0050C27BD* + ID_OUI_FROM_DATABASE=PROMATE ELECTRONIC CO.LTD + +OUI:0050C27BE* + ID_OUI_FROM_DATABASE=Powerlinx, Inc. + +OUI:0050C27BF* + ID_OUI_FROM_DATABASE=Zoe Medical + +OUI:0050C27C0* + ID_OUI_FROM_DATABASE=European Industrial Electronics B.V. + +OUI:0050C27C1* + ID_OUI_FROM_DATABASE=Primary Integration Encorp LLC + +OUI:0050C27C2* + ID_OUI_FROM_DATABASE=DSR Information Technologies Ltd. + +OUI:0050C27C3* + ID_OUI_FROM_DATABASE=AST INCORPORATED + +OUI:0050C27C4* + ID_OUI_FROM_DATABASE=MoBaCon + +OUI:0050C27C5* + ID_OUI_FROM_DATABASE=Venture Research Inc. + +OUI:0050C27C6* + ID_OUI_FROM_DATABASE=Lyngdorf Audio Aps + +OUI:0050C27C7* + ID_OUI_FROM_DATABASE=Pyrosequencing AB + +OUI:0050C27C8* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C27C9* + ID_OUI_FROM_DATABASE=Bluebell Opticom Limited + +OUI:0050C27CA* + ID_OUI_FROM_DATABASE=CEDAR Audio Limited + +OUI:0050C27CB* + ID_OUI_FROM_DATABASE=ViewPlus Technologies, Inc. + +OUI:0050C27CC* + ID_OUI_FROM_DATABASE=SWECO JAPS AB + +OUI:0050C27CD* + ID_OUI_FROM_DATABASE=Precision MicroControl Corporation + +OUI:0050C27CE* + ID_OUI_FROM_DATABASE=AirCell Inc. + +OUI:0050C27CF* + ID_OUI_FROM_DATABASE=Emitech Corporation + +OUI:0050C27D0* + ID_OUI_FROM_DATABASE=Radar Tronic ltd. + +OUI:0050C27D1* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C27D2* + ID_OUI_FROM_DATABASE=Bittitalo Oy + +OUI:0050C27D3* + ID_OUI_FROM_DATABASE=Highrail Systems Limited + +OUI:0050C27D4* + ID_OUI_FROM_DATABASE=WR Systems, Ltd. + +OUI:0050C27D5* + ID_OUI_FROM_DATABASE=Deuta-Werke GmbH + +OUI:0050C27D6* + ID_OUI_FROM_DATABASE=International Mining Technologies + +OUI:0050C27D7* + ID_OUI_FROM_DATABASE=Newtec A/S + +OUI:0050C27D8* + ID_OUI_FROM_DATABASE=InnoScan K/S + +OUI:0050C27D9* + ID_OUI_FROM_DATABASE=Volumatic Limited + +OUI:0050C27DA* + ID_OUI_FROM_DATABASE=HTEC Limited + +OUI:0050C27DB* + ID_OUI_FROM_DATABASE=Mueller Elektronik + +OUI:0050C27DC* + ID_OUI_FROM_DATABASE=aiXtrusion GmbH + +OUI:0050C27DD* + ID_OUI_FROM_DATABASE=LS Elektronik AB + +OUI:0050C27DE* + ID_OUI_FROM_DATABASE=Cascade Technologies Ltd + +OUI:0050C27E0* + ID_OUI_FROM_DATABASE=C&D Technologies, Inc + +OUI:0050C27E1* + ID_OUI_FROM_DATABASE=Zeltiq Aesthetics, Inc. + +OUI:0050C27E2* + ID_OUI_FROM_DATABASE=DIGITROL LTD + +OUI:0050C27E3* + ID_OUI_FROM_DATABASE=Progentech Limited + +OUI:0050C27E4* + ID_OUI_FROM_DATABASE=Meta Vision Systems Ltd. + +OUI:0050C27E5* + ID_OUI_FROM_DATABASE=Nystrom Engineering + +OUI:0050C27E6* + ID_OUI_FROM_DATABASE=Empirix Italy S.p.A. + +OUI:0050C27E7* + ID_OUI_FROM_DATABASE=V2Green, Inc. + +OUI:0050C27E8* + ID_OUI_FROM_DATABASE=Mistral Solutions Pvt. Ltd + +OUI:0050C27E9* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C27EA* + ID_OUI_FROM_DATABASE=Monitor Business Machines Ltd. + +OUI:0050C27EB* + ID_OUI_FROM_DATABASE=Sesol Industrial Computer + +OUI:0050C27EC* + ID_OUI_FROM_DATABASE=Lyngsoe Systems + +OUI:0050C27ED* + ID_OUI_FROM_DATABASE=Genesis Automation Inc. + +OUI:0050C27EE* + ID_OUI_FROM_DATABASE=NH Research + +OUI:0050C27EF* + ID_OUI_FROM_DATABASE=GFI Chrono Time + +OUI:0050C27F0* + ID_OUI_FROM_DATABASE=Network Harbor, Inc. + +OUI:0050C27F1* + ID_OUI_FROM_DATABASE=STUHL Regelsysteme GmbH + +OUI:0050C27F2* + ID_OUI_FROM_DATABASE=Logotherm Regelsysteme GmbH + +OUI:0050C27F3* + ID_OUI_FROM_DATABASE=SOREC + +OUI:0050C27F4* + ID_OUI_FROM_DATABASE=Wireless Cables Inc + +OUI:0050C27F5* + ID_OUI_FROM_DATABASE=ACE Carwash Systems + +OUI:0050C27F6* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C27F7* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C27F8* + ID_OUI_FROM_DATABASE=Wise Industria de Telecomunicações Ldta. + +OUI:0050C27F9* + ID_OUI_FROM_DATABASE=Karl DUNGS GmbH & Co. KG + +OUI:0050C27FA* + ID_OUI_FROM_DATABASE=AutomationX GmbH + +OUI:0050C27FB* + ID_OUI_FROM_DATABASE=Qtron Pty Ltd + +OUI:0050C27FC* + ID_OUI_FROM_DATABASE=TIS Dialog LLC + +OUI:0050C27FD* + ID_OUI_FROM_DATABASE=Adeneo + +OUI:0050C27FE* + ID_OUI_FROM_DATABASE=Wireless Cables Inc. + +OUI:0050C27FF* + ID_OUI_FROM_DATABASE=Shenzhen MaiWei Cable TV Equipment CO.,LTD. + +OUI:0050C2800* + ID_OUI_FROM_DATABASE=Delphi Display Systems, Inc. + +OUI:0050C2801* + ID_OUI_FROM_DATABASE=JANUS srl + +OUI:0050C2803* + ID_OUI_FROM_DATABASE=dB Broadcast Limited + +OUI:0050C2804* + ID_OUI_FROM_DATABASE=SoftSwitching Technologies + +OUI:0050C2805* + ID_OUI_FROM_DATABASE=MultimediaLED + +OUI:0050C2806* + ID_OUI_FROM_DATABASE=CET + +OUI:0050C2807* + ID_OUI_FROM_DATABASE=TECHNOMARK + +OUI:0050C2808* + ID_OUI_FROM_DATABASE=ITB CompuPhase + +OUI:0050C2809* + ID_OUI_FROM_DATABASE=Varma Electronics Oy + +OUI:0050C280A* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C280B* + ID_OUI_FROM_DATABASE=Open Video, Inc. + +OUI:0050C280C* + ID_OUI_FROM_DATABASE=Luxpert Technologies Co., Ltd. + +OUI:0050C280D* + ID_OUI_FROM_DATABASE=Acube Systems s.r.l. + +OUI:0050C280E* + ID_OUI_FROM_DATABASE=Bruno International Ltd. + +OUI:0050C280F* + ID_OUI_FROM_DATABASE=Selekron Microcontrol s.l. + +OUI:0050C2810* + ID_OUI_FROM_DATABASE=Alphion Corporation + +OUI:0050C2811* + ID_OUI_FROM_DATABASE=Open System Solutions Limited + +OUI:0050C2812* + ID_OUI_FROM_DATABASE=Femto SA + +OUI:0050C2813* + ID_OUI_FROM_DATABASE=Intelleflex Corporation + +OUI:0050C2814* + ID_OUI_FROM_DATABASE=Telvent + +OUI:0050C2815* + ID_OUI_FROM_DATABASE=microC Design SRL + +OUI:0050C2816* + ID_OUI_FROM_DATABASE=Intelight Inc. + +OUI:0050C2817* + ID_OUI_FROM_DATABASE=Odin TeleSystems Inc + +OUI:0050C2818* + ID_OUI_FROM_DATABASE=Wireless Value BV + +OUI:0050C2819* + ID_OUI_FROM_DATABASE=Cabinplant A/S + +OUI:0050C281A* + ID_OUI_FROM_DATABASE=InfoGLOBAL + +OUI:0050C281B* + ID_OUI_FROM_DATABASE=Brain Tech Co., Ltd + +OUI:0050C281C* + ID_OUI_FROM_DATABASE=Telcom + +OUI:0050C281D* + ID_OUI_FROM_DATABASE=IT SALUX CO., LTD. + +OUI:0050C281E* + ID_OUI_FROM_DATABASE=Channelot Ltd. + +OUI:0050C281F* + ID_OUI_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +OUI:0050C2820* + ID_OUI_FROM_DATABASE=TESCAN, s.r.o. + +OUI:0050C2821* + ID_OUI_FROM_DATABASE=MISCO Refractometer + +OUI:0050C2822* + ID_OUI_FROM_DATABASE=Winner Technology Co, Ltd. + +OUI:0050C2823* + ID_OUI_FROM_DATABASE=Robot Visual Systems GmbH + +OUI:0050C2824* + ID_OUI_FROM_DATABASE=SMT d.o.o. + +OUI:0050C2825* + ID_OUI_FROM_DATABASE=Funkwerk Information Technologies Karlsfeld GmbH + +OUI:0050C2826* + ID_OUI_FROM_DATABASE=HEWI Heinrich Wilke GmbH + +OUI:0050C2827* + ID_OUI_FROM_DATABASE=Enero Solutions inc. + +OUI:0050C2828* + ID_OUI_FROM_DATABASE=SLICAN sp. z o.o. + +OUI:0050C2829* + ID_OUI_FROM_DATABASE=Intellectronika + +OUI:0050C282A* + ID_OUI_FROM_DATABASE=VDC Display Systems + +OUI:0050C282B* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C282C* + ID_OUI_FROM_DATABASE=Vitel Net + +OUI:0050C282D* + ID_OUI_FROM_DATABASE=Elmec, Inc. + +OUI:0050C282E* + ID_OUI_FROM_DATABASE=LogiCom GmbH + +OUI:0050C282F* + ID_OUI_FROM_DATABASE=Momentum Data Systems + +OUI:0050C2830* + ID_OUI_FROM_DATABASE=CompuShop Services LLC + +OUI:0050C2831* + ID_OUI_FROM_DATABASE=St Jude Medical, Inc. + +OUI:0050C2832* + ID_OUI_FROM_DATABASE=S1nn GmbH & Co. KG + +OUI:0050C2833* + ID_OUI_FROM_DATABASE=LaserLinc, Inc. + +OUI:0050C2834* + ID_OUI_FROM_DATABASE=ANTEK GmbH + +OUI:0050C2835* + ID_OUI_FROM_DATABASE=Communications Laboratories Inc + +OUI:0050C2836* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C2837* + ID_OUI_FROM_DATABASE=ID-KARTA s.r.o. + +OUI:0050C2838* + ID_OUI_FROM_DATABASE=T PROJE MUHENDISLIK DIS. TIC. LTD. STI. + +OUI:0050C2839* + ID_OUI_FROM_DATABASE=IMS Röntgensysteme GmbH + +OUI:0050C283A* + ID_OUI_FROM_DATABASE=Syr-Tec Engineering & Marketing + +OUI:0050C283B* + ID_OUI_FROM_DATABASE=O. Bay AG + +OUI:0050C283C* + ID_OUI_FROM_DATABASE=hema electronic GmbH + +OUI:0050C283D* + ID_OUI_FROM_DATABASE=beroNet GmbH + +OUI:0050C283E* + ID_OUI_FROM_DATABASE=KPE spol. s r.o. + +OUI:0050C283F* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2840* + ID_OUI_FROM_DATABASE=Residential Control Systems + +OUI:0050C2841* + ID_OUI_FROM_DATABASE=Connection Electronics Ltd. + +OUI:0050C2842* + ID_OUI_FROM_DATABASE=Quantum Controls BV + +OUI:0050C2843* + ID_OUI_FROM_DATABASE=Xtensor Systems Inc. + +OUI:0050C2844* + ID_OUI_FROM_DATABASE=Prodigy Electronics Limited + +OUI:0050C2845* + ID_OUI_FROM_DATABASE=VisualSonics Inc. + +OUI:0050C2846* + ID_OUI_FROM_DATABASE=ESP-Planning Co. + +OUI:0050C2847* + ID_OUI_FROM_DATABASE=Lars Morich Kommunikationstechnik GmbH + +OUI:0050C2848* + ID_OUI_FROM_DATABASE=DASA ROBOT Co., Ltd. + +OUI:0050C2849* + ID_OUI_FROM_DATABASE=Design Analysis Associates, Inc. + +OUI:0050C284A* + ID_OUI_FROM_DATABASE=Keystone Electronic Solutions + +OUI:0050C284B* + ID_OUI_FROM_DATABASE=TASK SISTEMAS DE COMPUTACAO LTDA + +OUI:0050C284C* + ID_OUI_FROM_DATABASE=Performance Motion Devices + +OUI:0050C284D* + ID_OUI_FROM_DATABASE=BMTI + +OUI:0050C284E* + ID_OUI_FROM_DATABASE=DRACO SYSTEMS + +OUI:0050C284F* + ID_OUI_FROM_DATABASE=Gamber-Johnson LLC + +OUI:0050C2850* + ID_OUI_FROM_DATABASE=K.K. Rocky + +OUI:0050C2851* + ID_OUI_FROM_DATABASE=SPJ Embedded Technologies Pvt. Ltd. + +OUI:0050C2852* + ID_OUI_FROM_DATABASE=eInfochips Ltd. + +OUI:0050C2853* + ID_OUI_FROM_DATABASE=Ettus Research LLC + +OUI:0050C2854* + ID_OUI_FROM_DATABASE=Ratioplast-Optoelectronics GmbH + +OUI:0050C2855* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2856* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2857* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2858* + ID_OUI_FROM_DATABASE=Wireless Acquisition LLC + +OUI:0050C2859* + ID_OUI_FROM_DATABASE=Nuvation + +OUI:0050C285A* + ID_OUI_FROM_DATABASE=ART s.r.l. + +OUI:0050C285B* + ID_OUI_FROM_DATABASE=Boreste + +OUI:0050C285C* + ID_OUI_FROM_DATABASE=B S E + +OUI:0050C285D* + ID_OUI_FROM_DATABASE=Ing. Knauseder Mechatronik GmbH + +OUI:0050C285E* + ID_OUI_FROM_DATABASE=Radiometer Medical ApS + +OUI:0050C285F* + ID_OUI_FROM_DATABASE=General Dynamics C4 Systems + +OUI:0050C2860* + ID_OUI_FROM_DATABASE=Eutron S.p.A. + +OUI:0050C2861* + ID_OUI_FROM_DATABASE=Grantronics Pty Ltd + +OUI:0050C2862* + ID_OUI_FROM_DATABASE=Elsys AG + +OUI:0050C2863* + ID_OUI_FROM_DATABASE=Advanced Technology Solutions + +OUI:0050C2864* + ID_OUI_FROM_DATABASE=ATG Automatisierungstechnik GERA GmbH + +OUI:0050C2865* + ID_OUI_FROM_DATABASE=Persy Control Services B.v. + +OUI:0050C2866* + ID_OUI_FROM_DATABASE=Saia Burgess Controls AG + +OUI:0050C2867* + ID_OUI_FROM_DATABASE=Syntronics + +OUI:0050C2868* + ID_OUI_FROM_DATABASE=Aethon, Inc. + +OUI:0050C2869* + ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH + +OUI:0050C286A* + ID_OUI_FROM_DATABASE=USM Systems, Ltd + +OUI:0050C286B* + ID_OUI_FROM_DATABASE=OMB Sistemas Electronicos S.A. + +OUI:0050C286C* + ID_OUI_FROM_DATABASE=Condigi Televagt A/S + +OUI:0050C286D* + ID_OUI_FROM_DATABASE=Tieline Research Pty Ltd + +OUI:0050C286E* + ID_OUI_FROM_DATABASE=HANYANG ELECTRIC CP., LTD + +OUI:0050C286F* + ID_OUI_FROM_DATABASE=b-plus GmbH + +OUI:0050C2870* + ID_OUI_FROM_DATABASE=LOGEL S.R.L. + +OUI:0050C2871* + ID_OUI_FROM_DATABASE=R-S-I Elektrotechnik GmbH & Co. KG + +OUI:0050C2872* + ID_OUI_FROM_DATABASE=Oliotalo - Objecthouse Oy + +OUI:0050C2873* + ID_OUI_FROM_DATABASE=XRONET Corporation + +OUI:0050C2874* + ID_OUI_FROM_DATABASE=Arcos Technologies Ltd. + +OUI:0050C2875* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2876* + ID_OUI_FROM_DATABASE=Privatquelle Gruber GmbH & CO KG + +OUI:0050C2877* + ID_OUI_FROM_DATABASE=Motion Analysis Corp + +OUI:0050C2878* + ID_OUI_FROM_DATABASE=Acoustic Research Laboratories Pty Ltd + +OUI:0050C2879* + ID_OUI_FROM_DATABASE=MILESYS + +OUI:0050C287A* + ID_OUI_FROM_DATABASE=Spectrum Management, LC + +OUI:0050C287B* + ID_OUI_FROM_DATABASE=UAVNavigation S.L. + +OUI:0050C287C* + ID_OUI_FROM_DATABASE=Arcontia AB + +OUI:0050C287D* + ID_OUI_FROM_DATABASE=AT&T Government Solutions + +OUI:0050C287E* + ID_OUI_FROM_DATABASE=SCM PRODUCTS, INC. + +OUI:0050C287F* + ID_OUI_FROM_DATABASE=Optoelettronica Italia S.r.l. + +OUI:0050C2880* + ID_OUI_FROM_DATABASE=Creation Technologies Chicago + +OUI:0050C2881* + ID_OUI_FROM_DATABASE=InnoTrans Communications, Inc. + +OUI:0050C2882* + ID_OUI_FROM_DATABASE=WARECUBE,INC. + +OUI:0050C2883* + ID_OUI_FROM_DATABASE=Neocontrol Soluções em Automação + +OUI:0050C2884* + ID_OUI_FROM_DATABASE=IP Thinking A/S + +OUI:0050C2885* + ID_OUI_FROM_DATABASE=OOO "NTK "IMOS" + +OUI:0050C2886* + ID_OUI_FROM_DATABASE=Transas Scandinavia AB + +OUI:0050C2887* + ID_OUI_FROM_DATABASE=Inventis Technology Pty Limited + +OUI:0050C2888* + ID_OUI_FROM_DATABASE=IADEA CORPORATION + +OUI:0050C2889* + ID_OUI_FROM_DATABASE=ACS MOTION CONTROL + +OUI:0050C288A* + ID_OUI_FROM_DATABASE=Continental Electronics Corp. + +OUI:0050C288B* + ID_OUI_FROM_DATABASE=Hollis Electronics Company LLC + +OUI:0050C288C* + ID_OUI_FROM_DATABASE=Z-App Systems + +OUI:0050C288D* + ID_OUI_FROM_DATABASE=L3 Communications Nova Engineering + +OUI:0050C288E* + ID_OUI_FROM_DATABASE=Cardinal Scale Mfg Co + +OUI:0050C288F* + ID_OUI_FROM_DATABASE=Keynote SIGOS GmbH + +OUI:0050C2890* + ID_OUI_FROM_DATABASE=BAE Systems Hägglunds AB + +OUI:0050C2891* + ID_OUI_FROM_DATABASE=Admiral Secure Products, Ltd. + +OUI:0050C2892* + ID_OUI_FROM_DATABASE=Trakce a.s. + +OUI:0050C2893* + ID_OUI_FROM_DATABASE=EIZO Technologies GmbH + +OUI:0050C2894* + ID_OUI_FROM_DATABASE=Shockfish SA + +OUI:0050C2895* + ID_OUI_FROM_DATABASE=Marine Communications Limited + +OUI:0050C2896* + ID_OUI_FROM_DATABASE=Blankom + +OUI:0050C2897* + ID_OUI_FROM_DATABASE=ODF Optronics, Inc. + +OUI:0050C2898* + ID_OUI_FROM_DATABASE=Veeco Process Equipment, Inc. + +OUI:0050C2899* + ID_OUI_FROM_DATABASE=Inico Technologies Ltd. + +OUI:0050C289A* + ID_OUI_FROM_DATABASE=Neptune Technology Group, Inc. + +OUI:0050C289B* + ID_OUI_FROM_DATABASE=Sensata Technologies, Inc. + +OUI:0050C289C* + ID_OUI_FROM_DATABASE=Mediana + +OUI:0050C289D* + ID_OUI_FROM_DATABASE=Systemtechnik GmbH + +OUI:0050C289E* + ID_OUI_FROM_DATABASE=Broadcast Electronics + +OUI:0050C289F* + ID_OUI_FROM_DATABASE=Datalink Technologies Gateways Inc. + +OUI:0050C28A0* + ID_OUI_FROM_DATABASE=Specialized Communications Corp. + +OUI:0050C28A1* + ID_OUI_FROM_DATABASE=Intune Networks Limited + +OUI:0050C28A2* + ID_OUI_FROM_DATABASE=UAVISION Engenharia de Sistemas + +OUI:0050C28A3* + ID_OUI_FROM_DATABASE=RTW GmbH & Co.KG + +OUI:0050C28A4* + ID_OUI_FROM_DATABASE=BALOGH T.A.G Corporation + +OUI:0050C28A5* + ID_OUI_FROM_DATABASE=Mocon, Inc. + +OUI:0050C28A6* + ID_OUI_FROM_DATABASE=SELCO + +OUI:0050C28A7* + ID_OUI_FROM_DATABASE=PIXEYE LTD + +OUI:0050C28A8* + ID_OUI_FROM_DATABASE=ALTEK ELECTRONICS + +OUI:0050C28A9* + ID_OUI_FROM_DATABASE=Intelligent Security Systems + +OUI:0050C28AA* + ID_OUI_FROM_DATABASE=ATS Elektronik GmbH + +OUI:0050C28AB* + ID_OUI_FROM_DATABASE=Nanomotion Ltd. + +OUI:0050C28AC* + ID_OUI_FROM_DATABASE=Telsa s.r.l + +OUI:0050C28AD* + ID_OUI_FROM_DATABASE=Thales Communications, Inc + +OUI:0050C28AE* + ID_OUI_FROM_DATABASE=DESARROLLO DE SISTEMAS INTEGRADOS DE CONTROL S.A. + +OUI:0050C28AF* + ID_OUI_FROM_DATABASE=Xelerated + +OUI:0050C28B0* + ID_OUI_FROM_DATABASE=BK Innovation, Inc. + +OUI:0050C28B1* + ID_OUI_FROM_DATABASE=RingCube Technologies, Inc. + +OUI:0050C28B2* + ID_OUI_FROM_DATABASE=SERVAIND SA. + +OUI:0050C28B3* + ID_OUI_FROM_DATABASE=VTQ Videtronik GmbH + +OUI:0050C28B4* + ID_OUI_FROM_DATABASE=Sandar Telecast AS + +OUI:0050C28B5* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C28B6* + ID_OUI_FROM_DATABASE=Shadrinskiy Telefonny Zavod + +OUI:0050C28B7* + ID_OUI_FROM_DATABASE=Calnex Solutions Limited + +OUI:0050C28B8* + ID_OUI_FROM_DATABASE=DSS Networks, Inc. + +OUI:0050C28B9* + ID_OUI_FROM_DATABASE=ACD Elektronik Gmbh + +OUI:0050C28BA* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C28BB* + ID_OUI_FROM_DATABASE=smtag international ag + +OUI:0050C28BC* + ID_OUI_FROM_DATABASE=Honeywell Sensotec + +OUI:0050C28BD* + ID_OUI_FROM_DATABASE=Matrix Switch Corporation + +OUI:0050C28BE* + ID_OUI_FROM_DATABASE=The Pennsylvania State University + +OUI:0050C28BF* + ID_OUI_FROM_DATABASE=ARISTO Graphic Systeme GmbH & Co. KG + +OUI:0050C28C0* + ID_OUI_FROM_DATABASE=S.C.E. s.r.l. + +OUI:0050C28C1* + ID_OUI_FROM_DATABASE=Heraeus Noblelight GmbH + +OUI:0050C28C2* + ID_OUI_FROM_DATABASE=Access Control Systems JSC + +OUI:0050C28C3* + ID_OUI_FROM_DATABASE=Byte Paradigm + +OUI:0050C28C4* + ID_OUI_FROM_DATABASE=Soldig Industria e Comercio de Equipamentos Eletronicos LTDA + +OUI:0050C28C5* + ID_OUI_FROM_DATABASE=Vortex Engineering pvt ltd + +OUI:0050C28C6* + ID_OUI_FROM_DATABASE=Gradual Tecnologia Ltda. + +OUI:0050C28C7* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:0050C28C8* + ID_OUI_FROM_DATABASE=Pumatronix Equipamentos Eletrônicos Ltda + +OUI:0050C28C9* + ID_OUI_FROM_DATABASE=A+S Aktuatorik und Sensorik GmbH + +OUI:0050C28CA* + ID_OUI_FROM_DATABASE=Altair semiconductor Ltd + +OUI:0050C28CB* + ID_OUI_FROM_DATABASE=Beonic Corporation + +OUI:0050C28CC* + ID_OUI_FROM_DATABASE=LyconSys GmbH & Co.KG + +OUI:0050C28CD* + ID_OUI_FROM_DATABASE=Cambridge Sound Management, LLC + +OUI:0050C28CE* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C28CF* + ID_OUI_FROM_DATABASE=GigaLinx Ltd. + +OUI:0050C28D0* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C28D1* + ID_OUI_FROM_DATABASE=Bachmann Monitoring GmbH + +OUI:0050C28D2* + ID_OUI_FROM_DATABASE=TTi Ltd + +OUI:0050C28D3* + ID_OUI_FROM_DATABASE=IFAM GmbH + +OUI:0050C28D4* + ID_OUI_FROM_DATABASE=Internet Protocolo Lógica SL + +OUI:0050C28D5* + ID_OUI_FROM_DATABASE=Peek Traffic Corp + +OUI:0050C28D6* + ID_OUI_FROM_DATABASE=UltraVision Security Systems, Inc. + +OUI:0050C28D7* + ID_OUI_FROM_DATABASE=Polygon Informatics Ltd. + +OUI:0050C28D8* + ID_OUI_FROM_DATABASE=Array Technologies Inc + +OUI:0050C28D9* + ID_OUI_FROM_DATABASE=Industrial Control and Communication Limited + +OUI:0050C28DA* + ID_OUI_FROM_DATABASE=DOCUTEMP, INC + +OUI:0050C28DB* + ID_OUI_FROM_DATABASE=DCOM Network Technology (Pty) Ltd + +OUI:0050C28DC* + ID_OUI_FROM_DATABASE=Frame Systems Limited + +OUI:0050C28DD* + ID_OUI_FROM_DATABASE=GIMCON + +OUI:0050C28DE* + ID_OUI_FROM_DATABASE=Coherix, Inc + +OUI:0050C28DF* + ID_OUI_FROM_DATABASE=Dipl.-Ing. W. Nophut GmbH + +OUI:0050C28E0* + ID_OUI_FROM_DATABASE=Shenzhen Pennda Technologies Co., Ltd. + +OUI:0050C28E1* + ID_OUI_FROM_DATABASE=Deutscher Weterdienst + +OUI:0050C28E2* + ID_OUI_FROM_DATABASE=Wireless Cables Inc + +OUI:0050C28E3* + ID_OUI_FROM_DATABASE=bioMérieux Italia S.p.A. + +OUI:0050C28E4* + ID_OUI_FROM_DATABASE=MaCaPS International Limited + +OUI:0050C28E5* + ID_OUI_FROM_DATABASE=Berthel GmbH + +OUI:0050C28E6* + ID_OUI_FROM_DATABASE=Sandel Avionics, Inc. + +OUI:0050C28E7* + ID_OUI_FROM_DATABASE=MKT Systemtechnik + +OUI:0050C28E8* + ID_OUI_FROM_DATABASE=Friedrich Kuhnt GmbH + +OUI:0050C28E9* + ID_OUI_FROM_DATABASE=UNIDATA + +OUI:0050C28EA* + ID_OUI_FROM_DATABASE=ATEME + +OUI:0050C28EB* + ID_OUI_FROM_DATABASE=C-COM Satellite Systems Inc. + +OUI:0050C28EC* + ID_OUI_FROM_DATABASE=Balfour Beatty Rail GmbH + +OUI:0050C28ED* + ID_OUI_FROM_DATABASE=AT-Automation Technology GmbH + +OUI:0050C28EE* + ID_OUI_FROM_DATABASE=PCSC + +OUI:0050C28EF* + ID_OUI_FROM_DATABASE=Technologies Sensio Inc + +OUI:0050C28F0* + ID_OUI_FROM_DATABASE=Xentras Communications + +OUI:0050C28F1* + ID_OUI_FROM_DATABASE=Detection Technologies Ltd. + +OUI:0050C28F2* + ID_OUI_FROM_DATABASE=Schneider Electric GmbH + +OUI:0050C28F3* + ID_OUI_FROM_DATABASE=Curtis Door Systems Inc + +OUI:0050C28F4* + ID_OUI_FROM_DATABASE=Critical Link + +OUI:0050C28F5* + ID_OUI_FROM_DATABASE=tec5 AG + +OUI:0050C28F6* + ID_OUI_FROM_DATABASE=K-MAC Corp. + +OUI:0050C28F7* + ID_OUI_FROM_DATABASE=TGE Co., Ltd. + +OUI:0050C28F8* + ID_OUI_FROM_DATABASE=RMSD LTD + +OUI:0050C28F9* + ID_OUI_FROM_DATABASE=Honeywell International + +OUI:0050C28FA* + ID_OUI_FROM_DATABASE=TELIUM s.c. + +OUI:0050C28FB* + ID_OUI_FROM_DATABASE=Alfred Kuhse GmbH + +OUI:0050C28FC* + ID_OUI_FROM_DATABASE=Symetrics Industries + +OUI:0050C28FD* + ID_OUI_FROM_DATABASE=Sindoma Müh Mim Ýnþ Elk San Tic Ltd. + +OUI:0050C28FE* + ID_OUI_FROM_DATABASE=Cross Country Systems AB + +OUI:0050C28FF* + ID_OUI_FROM_DATABASE=Luceat + +OUI:0050C2900* + ID_OUI_FROM_DATABASE=Magor Communications Corp + +OUI:0050C2901* + ID_OUI_FROM_DATABASE=Research Applications Incorp + +OUI:0050C2902* + ID_OUI_FROM_DATABASE=China Railway Signal & Communication Corp. + +OUI:0050C2903* + ID_OUI_FROM_DATABASE=EcoAxis Systems Pvt. Ltd. + +OUI:0050C2904* + ID_OUI_FROM_DATABASE=R2Sonic, LLC + +OUI:0050C2905* + ID_OUI_FROM_DATABASE=Link Communications, Inc + +OUI:0050C2906* + ID_OUI_FROM_DATABASE=Gidel + +OUI:0050C2907* + ID_OUI_FROM_DATABASE=Cristal Controles Ltee + +OUI:0050C2908* + ID_OUI_FROM_DATABASE=Codex Digital Ltd + +OUI:0050C2909* + ID_OUI_FROM_DATABASE=Elisra Electronic Systems + +OUI:0050C290A* + ID_OUI_FROM_DATABASE=Board Level Limited + +OUI:0050C290B* + ID_OUI_FROM_DATABASE=E.ON ES Sverige AB + +OUI:0050C290C* + ID_OUI_FROM_DATABASE=LSS GmbH + +OUI:0050C290D* + ID_OUI_FROM_DATABASE=EVK DI Kerschhaggl GmbH + +OUI:0050C290E* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C290F* + ID_OUI_FROM_DATABASE=INTEGRA Biosciences AG + +OUI:0050C2910* + ID_OUI_FROM_DATABASE=Autotank AB + +OUI:0050C2911* + ID_OUI_FROM_DATABASE=Vapor Rail + +OUI:0050C2912* + ID_OUI_FROM_DATABASE=ASSET InterTech, Inc. + +OUI:0050C2913* + ID_OUI_FROM_DATABASE=Selex Sensors & Airborne Systems + +OUI:0050C2914* + ID_OUI_FROM_DATABASE=IO-Connect + +OUI:0050C2915* + ID_OUI_FROM_DATABASE=Verint Systems Ltd. + +OUI:0050C2916* + ID_OUI_FROM_DATABASE=CHK GridSense P/L + +OUI:0050C2917* + ID_OUI_FROM_DATABASE=CIRTEM + +OUI:0050C2918* + ID_OUI_FROM_DATABASE=Design Lightning Corp + +OUI:0050C2919* + ID_OUI_FROM_DATABASE=AHV Systems, Inc. + +OUI:0050C291A* + ID_OUI_FROM_DATABASE=Xtone Networks + +OUI:0050C291B* + ID_OUI_FROM_DATABASE=Embedded Data Systems, LLC + +OUI:0050C291C* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C291D* + ID_OUI_FROM_DATABASE=Rosendahl Studiotechnik GmbH + +OUI:0050C291E* + ID_OUI_FROM_DATABASE=Automation Tec + +OUI:0050C291F* + ID_OUI_FROM_DATABASE=2NCOMM DESIGN SRL + +OUI:0050C2920* + ID_OUI_FROM_DATABASE=Rogue Engineering Inc. + +OUI:0050C2921* + ID_OUI_FROM_DATABASE=iQue RFID Technologies BV + +OUI:0050C2922* + ID_OUI_FROM_DATABASE=Metrum Sweden AB + +OUI:0050C2923* + ID_OUI_FROM_DATABASE=Amicus Wireless + +OUI:0050C2924* + ID_OUI_FROM_DATABASE=Link Electric & Safety Control Co. + +OUI:0050C2925* + ID_OUI_FROM_DATABASE=PHB Eletronica Ltda. + +OUI:0050C2926* + ID_OUI_FROM_DATABASE=DITEST FAHRZEUGDIAGNOSE GMBH + +OUI:0050C2927* + ID_OUI_FROM_DATABASE=ATIS group s.r.o. + +OUI:0050C2928* + ID_OUI_FROM_DATABASE=Cinetix GmbH + +OUI:0050C2929* + ID_OUI_FROM_DATABASE=Flight Deck Resources + +OUI:0050C292A* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C292B* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:0050C292C* + ID_OUI_FROM_DATABASE=Exatrol Corporation + +OUI:0050C292D* + ID_OUI_FROM_DATABASE=APProSoftware.com + +OUI:0050C292E* + ID_OUI_FROM_DATABASE=Goanna Technologies Pty Ltd + +OUI:0050C292F* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2930* + ID_OUI_FROM_DATABASE=NETA Elektronik AS + +OUI:0050C2931* + ID_OUI_FROM_DATABASE=Korea Telecom Internet Solutions (KTIS) + +OUI:0050C2932* + ID_OUI_FROM_DATABASE=SMAVIS Inc. + +OUI:0050C2933* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2934* + ID_OUI_FROM_DATABASE=Xilar Corp. + +OUI:0050C2935* + ID_OUI_FROM_DATABASE=Image Video + +OUI:0050C2936* + ID_OUI_FROM_DATABASE=Margaritis Engineering + +OUI:0050C2937* + ID_OUI_FROM_DATABASE=BigBear + +OUI:0050C2938* + ID_OUI_FROM_DATABASE=Postec Data Systems Ltd + +OUI:0050C2939* + ID_OUI_FROM_DATABASE=Mosaic Dynamic Solutions + +OUI:0050C293A* + ID_OUI_FROM_DATABASE=ALPHATRONICS nv + +OUI:0050C293B* + ID_OUI_FROM_DATABASE=Reliatronics Inc. + +OUI:0050C293C* + ID_OUI_FROM_DATABASE=FractureCode Corporation + +OUI:0050C293D* + ID_OUI_FROM_DATABASE=Lighting Science Group Corporation + +OUI:0050C293E* + ID_OUI_FROM_DATABASE=RCS Communication Test Systems Ltd. + +OUI:0050C293F* + ID_OUI_FROM_DATABASE=TSB Solutions Inc. + +OUI:0050C2940* + ID_OUI_FROM_DATABASE=Phitek Systems Ltd. + +OUI:0050C2941* + ID_OUI_FROM_DATABASE=Rolbit + +OUI:0050C2942* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2943* + ID_OUI_FROM_DATABASE=QuanZhou TDX Electronics Co., Ltd. + +OUI:0050C2944* + ID_OUI_FROM_DATABASE=Wireonair A/S + +OUI:0050C2945* + ID_OUI_FROM_DATABASE=Ex-i Flow Measurement Ltd. + +OUI:0050C2946* + ID_OUI_FROM_DATABASE=MEGWARE Computer GmbH + +OUI:0050C2947* + ID_OUI_FROM_DATABASE=IMEXHIGHWAY cvba + +OUI:0050C2948* + ID_OUI_FROM_DATABASE=ELECTRONIA + +OUI:0050C2949* + ID_OUI_FROM_DATABASE=taskit GmbH + +OUI:0050C294A* + ID_OUI_FROM_DATABASE=TRUMEDIA TECHNOLOGIES + +OUI:0050C294B* + ID_OUI_FROM_DATABASE=Piller engineering Ltd. + +OUI:0050C294C* + ID_OUI_FROM_DATABASE=TEMIX + +OUI:0050C294D* + ID_OUI_FROM_DATABASE=C&H technology ltd. + +OUI:0050C294E* + ID_OUI_FROM_DATABASE=Zynix Original Sdn. Bhd. + +OUI:0050C294F* + ID_OUI_FROM_DATABASE=IT-Designers GmbH + +OUI:0050C2950* + ID_OUI_FROM_DATABASE=Tele and Radio Research Institute + +OUI:0050C2951* + ID_OUI_FROM_DATABASE=EL.C.A. soc. coop. + +OUI:0050C2952* + ID_OUI_FROM_DATABASE=Tech Fass s.r.o. + +OUI:0050C2953* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2954* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2955* + ID_OUI_FROM_DATABASE=Roessmann Engineering + +OUI:0050C2956* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2957* + ID_OUI_FROM_DATABASE=STRATEC Control Systems + +OUI:0050C2958* + ID_OUI_FROM_DATABASE=Sensoptics Ltd + +OUI:0050C2959* + ID_OUI_FROM_DATABASE=DECTRIS Ltd. + +OUI:0050C295A* + ID_OUI_FROM_DATABASE=TechnoAP + +OUI:0050C295B* + ID_OUI_FROM_DATABASE=AS Solar GmbH + +OUI:0050C295C* + ID_OUI_FROM_DATABASE=Resurgent Health & Medical + +OUI:0050C295D* + ID_OUI_FROM_DATABASE=full electronic system + +OUI:0050C295E* + ID_OUI_FROM_DATABASE=BEEcube Inc. + +OUI:0050C295F* + ID_OUI_FROM_DATABASE=METRONIC APARATURA KONTROLNO - POMIAROWA + +OUI:0050C2960* + ID_OUI_FROM_DATABASE=kuroneko dennnou kenkyuushitsu + +OUI:0050C2961* + ID_OUI_FROM_DATABASE=Picsolve International Limited + +OUI:0050C2962* + ID_OUI_FROM_DATABASE=Shockfish SA + +OUI:0050C2963* + ID_OUI_FROM_DATABASE=Lécureux SA + +OUI:0050C2964* + ID_OUI_FROM_DATABASE=IQ Automation GmbH + +OUI:0050C2965* + ID_OUI_FROM_DATABASE=Emitech Corporation + +OUI:0050C2966* + ID_OUI_FROM_DATABASE=PCM Industries + +OUI:0050C2967* + ID_OUI_FROM_DATABASE=Watthour Engineering Co., Inc. + +OUI:0050C2968* + ID_OUI_FROM_DATABASE=BuLogics, Inc. + +OUI:0050C2969* + ID_OUI_FROM_DATABASE=Gehrke Kommunikationssysteme GmbH + +OUI:0050C296A* + ID_OUI_FROM_DATABASE=Elektrobit Wireless Communications Ltd + +OUI:0050C296B* + ID_OUI_FROM_DATABASE=Electronic Media Services Ltd + +OUI:0050C296C* + ID_OUI_FROM_DATABASE=Aqua Cooler Pty Ltd + +OUI:0050C296D* + ID_OUI_FROM_DATABASE=Keene Electronics Ltd. + +OUI:0050C296E* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C296F* + ID_OUI_FROM_DATABASE=Varec Inc. + +OUI:0050C2970* + ID_OUI_FROM_DATABASE=Tsuji Electronics Co.,Ltd + +OUI:0050C2971* + ID_OUI_FROM_DATABASE=Ipitek + +OUI:0050C2972* + ID_OUI_FROM_DATABASE=Switch Science (Panini Keikaku) + +OUI:0050C2973* + ID_OUI_FROM_DATABASE=Systèmes Pran + +OUI:0050C2974* + ID_OUI_FROM_DATABASE=EMAC, INC. + +OUI:0050C2975* + ID_OUI_FROM_DATABASE=Pyramid Technical Consultants + +OUI:0050C2976* + ID_OUI_FROM_DATABASE=SANDS INSTRUMENTATION INDIA PVT LTD + +OUI:0050C2977* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2978* + ID_OUI_FROM_DATABASE=LOGITAL DIGITAL MEDIA srl + +OUI:0050C2979* + ID_OUI_FROM_DATABASE=Far South Networks (Pty) Ltd + +OUI:0050C297A* + ID_OUI_FROM_DATABASE=KST Technology Co., Ltd + +OUI:0050C297B* + ID_OUI_FROM_DATABASE=SMARTQUANTUM SA + +OUI:0050C297C* + ID_OUI_FROM_DATABASE=Creacon Technologies B.V. + +OUI:0050C297D* + ID_OUI_FROM_DATABASE=Soehnle Professional GmbH & Co.KG + +OUI:0050C297E* + ID_OUI_FROM_DATABASE=RF Industries + +OUI:0050C297F* + ID_OUI_FROM_DATABASE=C&I Co.Ltd + +OUI:0050C2980* + ID_OUI_FROM_DATABASE=Digital Payment Technologies + +OUI:0050C2981* + ID_OUI_FROM_DATABASE=Novotronik GmbH + +OUI:0050C2982* + ID_OUI_FROM_DATABASE=Triple Ring Technologies, Inc. + +OUI:0050C2983* + ID_OUI_FROM_DATABASE=Bogart Engineering + +OUI:0050C2984* + ID_OUI_FROM_DATABASE=Atel Corporation + +OUI:0050C2985* + ID_OUI_FROM_DATABASE=Earnestcom Sdn Bhd + +OUI:0050C2986* + ID_OUI_FROM_DATABASE=DSCI + +OUI:0050C2987* + ID_OUI_FROM_DATABASE=Joinsoon Electronics MFG. Co., Ltd + +OUI:0050C2988* + ID_OUI_FROM_DATABASE=Pantel International + +OUI:0050C2989* + ID_OUI_FROM_DATABASE=Psigenics Corporation + +OUI:0050C298A* + ID_OUI_FROM_DATABASE=MEV Limited + +OUI:0050C298B* + ID_OUI_FROM_DATABASE=TI2000 TECNOLOGIA INFORMATICA 2000 + +OUI:0050C298C* + ID_OUI_FROM_DATABASE=MGM-Devices Oy + +OUI:0050C298D* + ID_OUI_FROM_DATABASE=Mecos AG + +OUI:0050C298E* + ID_OUI_FROM_DATABASE=Link Technologies, Inc + +OUI:0050C298F* + ID_OUI_FROM_DATABASE=BELIK S.P.R.L. + +OUI:0050C2990* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2991* + ID_OUI_FROM_DATABASE=UGL Limited + +OUI:0050C2992* + ID_OUI_FROM_DATABASE=IDT Sound Processing Corporation + +OUI:0050C2993* + ID_OUI_FROM_DATABASE=UNETCONVERGENCE CO., LTD + +OUI:0050C2994* + ID_OUI_FROM_DATABASE=Xafax Nederland bv + +OUI:0050C2995* + ID_OUI_FROM_DATABASE=Inter Control Hermann Köhler Elektrik GmbH&Co.KG + +OUI:0050C2996* + ID_OUI_FROM_DATABASE=Commercial Timesharing Inc. + +OUI:0050C2997* + ID_OUI_FROM_DATABASE=Depro Électronique + +OUI:0050C2998* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2999* + ID_OUI_FROM_DATABASE=Cambustion Ltd + +OUI:0050C299A* + ID_OUI_FROM_DATABASE=Miromico AG + +OUI:0050C299B* + ID_OUI_FROM_DATABASE=Bettini srl + +OUI:0050C299C* + ID_OUI_FROM_DATABASE=CaTs3 Limited + +OUI:0050C299D* + ID_OUI_FROM_DATABASE=Powersense A/S + +OUI:0050C299E* + ID_OUI_FROM_DATABASE=Engage Technologies + +OUI:0050C299F* + ID_OUI_FROM_DATABASE=Sietron Elektronik + +OUI:0050C29A0* + ID_OUI_FROM_DATABASE=Trs Systems, Inc. + +OUI:0050C29A1* + ID_OUI_FROM_DATABASE=ComAp s.r.o + +OUI:0050C29A2* + ID_OUI_FROM_DATABASE=SAMsystems GmbH + +OUI:0050C29A3* + ID_OUI_FROM_DATABASE=Computerwise, Inc. + +OUI:0050C29A4* + ID_OUI_FROM_DATABASE=Entwicklung Hard- & Software + +OUI:0050C29A5* + ID_OUI_FROM_DATABASE=Conolog Corporation + +OUI:0050C29A6* + ID_OUI_FROM_DATABASE=Metodo2 + +OUI:0050C29A7* + ID_OUI_FROM_DATABASE=Thales Communications & Security S.A. + +OUI:0050C29A8* + ID_OUI_FROM_DATABASE=DOMIS SA + +OUI:0050C29A9* + ID_OUI_FROM_DATABASE=General Dynamics C4 Systems + +OUI:0050C29AA* + ID_OUI_FROM_DATABASE=TEKO TELECOM SpA + +OUI:0050C29AB* + ID_OUI_FROM_DATABASE=Electrodata Inc. + +OUI:0050C29AC* + ID_OUI_FROM_DATABASE=Questek Australia Pty Ltd + +OUI:0050C29AD* + ID_OUI_FROM_DATABASE=Chronos Technology Ltd. + +OUI:0050C29AE* + ID_OUI_FROM_DATABASE=Esensors, Inc. + +OUI:0050C29AF* + ID_OUI_FROM_DATABASE=KRESS-NET Krzysztof Rutecki + +OUI:0050C29B0* + ID_OUI_FROM_DATABASE=Ebru GmbH + +OUI:0050C29B1* + ID_OUI_FROM_DATABASE=Bon Hora GmbH + +OUI:0050C29B2* + ID_OUI_FROM_DATABASE=TempSys + +OUI:0050C29B3* + ID_OUI_FROM_DATABASE=Kahler Automation + +OUI:0050C29B4* + ID_OUI_FROM_DATABASE=EUKREA ELECTROMATIQUE SARL + +OUI:0050C29B5* + ID_OUI_FROM_DATABASE=Telegamma srl + +OUI:0050C29B6* + ID_OUI_FROM_DATABASE=ACTECH + +OUI:0050C29B7* + ID_OUI_FROM_DATABASE=St. Michael Strategies + +OUI:0050C29B8* + ID_OUI_FROM_DATABASE=Sound Player Systems e.K. + +OUI:0050C29B9* + ID_OUI_FROM_DATABASE=ISA - Intelligent Sensing Anywhere, S.A. + +OUI:0050C29BA* + ID_OUI_FROM_DATABASE=Connor-Winfield + +OUI:0050C29BB* + ID_OUI_FROM_DATABASE=OMICRON electronics GmbH + +OUI:0050C29BC* + ID_OUI_FROM_DATABASE=Vester Elektronik GmbH + +OUI:0050C29BD* + ID_OUI_FROM_DATABASE=Sensitron Semiconductor + +OUI:0050C29BE* + ID_OUI_FROM_DATABASE=Xad Communications Ltd + +OUI:0050C29BF* + ID_OUI_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +OUI:0050C29C0* + ID_OUI_FROM_DATABASE=Stuyts Engineering Haarlem BV + +OUI:0050C29C1* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:0050C29C2* + ID_OUI_FROM_DATABASE=Team Enginers + +OUI:0050C29C3* + ID_OUI_FROM_DATABASE=GE Security-Kampro + +OUI:0050C29C4* + ID_OUI_FROM_DATABASE=Vitel Net + +OUI:0050C29C5* + ID_OUI_FROM_DATABASE=Scansonic MI GmbH + +OUI:0050C29C6* + ID_OUI_FROM_DATABASE=Protronic GmbH + +OUI:0050C29C7* + ID_OUI_FROM_DATABASE=Kumera Drives Oy + +OUI:0050C29C8* + ID_OUI_FROM_DATABASE=ethermetrics + +OUI:0050C29C9* + ID_OUI_FROM_DATABASE=LUMINEX Lighting Control Equipment + +OUI:0050C29CA* + ID_OUI_FROM_DATABASE=ESAB-ATAS GmbH + +OUI:0050C29CB* + ID_OUI_FROM_DATABASE=NIS-time GmbH + +OUI:0050C29CC* + ID_OUI_FROM_DATABASE=Hirotech, Inc + +OUI:0050C29CD* + ID_OUI_FROM_DATABASE=Uwe Schneider GmbH + +OUI:0050C29CE* + ID_OUI_FROM_DATABASE=Ronan Engineering + +OUI:0050C29CF* + ID_OUI_FROM_DATABASE=Intuitive Surgical, Inc + +OUI:0050C29D0* + ID_OUI_FROM_DATABASE=J. DITTRICH ELEKTRONIC GmbH & Co. KG + +OUI:0050C29D1* + ID_OUI_FROM_DATABASE=Bladelius Design Group AB + +OUI:0050C29D2* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C29D3* + ID_OUI_FROM_DATABASE=Telemetrie Elektronik GmbH + +OUI:0050C29D4* + ID_OUI_FROM_DATABASE=FIRST + +OUI:0050C29D5* + ID_OUI_FROM_DATABASE=Netpower Labs AB + +OUI:0050C29D6* + ID_OUI_FROM_DATABASE=Innovation, Institute, Inc + +OUI:0050C29D7* + ID_OUI_FROM_DATABASE=Melex Inc. + +OUI:0050C29D8* + ID_OUI_FROM_DATABASE=SAMSUNG HEAVY INDUSTRIES CO.,LTD. + +OUI:0050C29D9* + ID_OUI_FROM_DATABASE=CNS Systems, Inc. + +OUI:0050C29DA* + ID_OUI_FROM_DATABASE=NEUTRONIK e.K. + +OUI:0050C29DB* + ID_OUI_FROM_DATABASE=Walter Grotkasten + +OUI:0050C29DC* + ID_OUI_FROM_DATABASE=FTM Marketing Limited + +OUI:0050C29DD* + ID_OUI_FROM_DATABASE=Institut Dr. Foerster + +OUI:0050C29DE* + ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX + +OUI:0050C29DF* + ID_OUI_FROM_DATABASE=CODEC Co., Ltd. + +OUI:0050C29E0* + ID_OUI_FROM_DATABASE=DST Swiss AG + +OUI:0050C29E1* + ID_OUI_FROM_DATABASE=Enreduce Energy Control AB + +OUI:0050C29E2* + ID_OUI_FROM_DATABASE=E-ViEWS SAFETY SYSTEMS, INC + +OUI:0050C29E3* + ID_OUI_FROM_DATABASE=SAI Informationstechnik + +OUI:0050C29E4* + ID_OUI_FROM_DATABASE=Pyxis Controls WLL + +OUI:0050C29E5* + ID_OUI_FROM_DATABASE=Halliburton Far East Pte Ltd + +OUI:0050C29E6* + ID_OUI_FROM_DATABASE=Kumho Electric, Inc. + +OUI:0050C29E7* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C29E8* + ID_OUI_FROM_DATABASE=Hammock Corporation + +OUI:0050C29E9* + ID_OUI_FROM_DATABASE=Ciemme Sistemi Spa + +OUI:0050C29EA* + ID_OUI_FROM_DATABASE=SISMODULAR - Engenharia, Lda + +OUI:0050C29EB* + ID_OUI_FROM_DATABASE=AFORE Solutions Inc. + +OUI:0050C29EC* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C29ED* + ID_OUI_FROM_DATABASE=Picell B.V. + +OUI:0050C29EE* + ID_OUI_FROM_DATABASE=Michael Stevens & Partners Ltd + +OUI:0050C29EF* + ID_OUI_FROM_DATABASE=WoKa-Elektronik GmbH + +OUI:0050C29F0* + ID_OUI_FROM_DATABASE=Veracity UK Ltd + +OUI:0050C29F1* + ID_OUI_FROM_DATABASE=IDEAS s.r.l. + +OUI:0050C29F2* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C29F3* + ID_OUI_FROM_DATABASE=Vision Technologies, Inc. + +OUI:0050C29F4* + ID_OUI_FROM_DATABASE=FSR Inc. + +OUI:0050C29F5* + ID_OUI_FROM_DATABASE=Commex Technologies + +OUI:0050C29F6* + ID_OUI_FROM_DATABASE=Ion Sense Inc. + +OUI:0050C29F7* + ID_OUI_FROM_DATABASE=Dave Jones Design + +OUI:0050C29F8* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd + +OUI:0050C29F9* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C29FA* + ID_OUI_FROM_DATABASE=Teranex A Division of Silicon Optix + +OUI:0050C29FB* + ID_OUI_FROM_DATABASE=Villbau Kft. + +OUI:0050C29FC* + ID_OUI_FROM_DATABASE=ECTEC INC. + +OUI:0050C29FD* + ID_OUI_FROM_DATABASE=Bitt technology-A Ltd. + +OUI:0050C29FE* + ID_OUI_FROM_DATABASE=SPECTRA EMBEDDED SYSTEMS + +OUI:0050C29FF* + ID_OUI_FROM_DATABASE=Humphrey Products + +OUI:0050C2A00* + ID_OUI_FROM_DATABASE=Technovare Systems + +OUI:0050C2A01* + ID_OUI_FROM_DATABASE=Patronics International LTD + +OUI:0050C2A02* + ID_OUI_FROM_DATABASE=Reference, LLC. + +OUI:0050C2A03* + ID_OUI_FROM_DATABASE=EEG Enterprises Inc + +OUI:0050C2A04* + ID_OUI_FROM_DATABASE=TP Radio + +OUI:0050C2A05* + ID_OUI_FROM_DATABASE=Adgil Design Inc. + +OUI:0050C2A06* + ID_OUI_FROM_DATABASE=Cloos Schweisstechnik GmbH + +OUI:0050C2A07* + ID_OUI_FROM_DATABASE=Dynon Instruments + +OUI:0050C2A08* + ID_OUI_FROM_DATABASE=LabJack Corporation + +OUI:0050C2A09* + ID_OUI_FROM_DATABASE=Innovative American Technology + +OUI:0050C2A0A* + ID_OUI_FROM_DATABASE=ACD Elektronik Gmbh + +OUI:0050C2A0B* + ID_OUI_FROM_DATABASE=I.D.S. Ingegneria Dei Sistemi S.p.A. + +OUI:0050C2A0C* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2A0D* + ID_OUI_FROM_DATABASE=CHARLYROBOT + +OUI:0050C2A0E* + ID_OUI_FROM_DATABASE=Engicam srl + +OUI:0050C2A0F* + ID_OUI_FROM_DATABASE=Visualware Inc + +OUI:0050C2A10* + ID_OUI_FROM_DATABASE=Essential Design & Integration P/L + +OUI:0050C2A11* + ID_OUI_FROM_DATABASE=OJSC Rawenstvo + +OUI:0050C2A12* + ID_OUI_FROM_DATABASE=HCE Engineering S.r.l. + +OUI:0050C2A13* + ID_OUI_FROM_DATABASE=Talyst, Inc. + +OUI:0050C2A14* + ID_OUI_FROM_DATABASE=Elbit Systems of America - Tallahassee Operations + +OUI:0050C2A15* + ID_OUI_FROM_DATABASE=Industrial Computing Ltd + +OUI:0050C2A16* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:0050C2A17* + ID_OUI_FROM_DATABASE=Winners Satellite Electronics Corp. + +OUI:0050C2A18* + ID_OUI_FROM_DATABASE=Eoslink + +OUI:0050C2A19* + ID_OUI_FROM_DATABASE=Icon Time Systems + +OUI:0050C2A1A* + ID_OUI_FROM_DATABASE=DDL + +OUI:0050C2A1B* + ID_OUI_FROM_DATABASE=Realtime Systems Ltd. + +OUI:0050C2A1C* + ID_OUI_FROM_DATABASE=Microtechnica + +OUI:0050C2A1D* + ID_OUI_FROM_DATABASE=SAMH Engineering Services + +OUI:0050C2A1E* + ID_OUI_FROM_DATABASE=MAMAC Systems, Inc. + +OUI:0050C2A1F* + ID_OUI_FROM_DATABASE=Flight Data Systems Pty Ltd + +OUI:0050C2A20* + ID_OUI_FROM_DATABASE=Quorum Technologies Ltd + +OUI:0050C2A21* + ID_OUI_FROM_DATABASE=ISAC SRL + +OUI:0050C2A22* + ID_OUI_FROM_DATABASE=Nippon Manufacturing Service Corporation (abbreviated as 'nms') + +OUI:0050C2A23* + ID_OUI_FROM_DATABASE=Agility Mfg, Inc. + +OUI:0050C2A24* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2A25* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2A26* + ID_OUI_FROM_DATABASE=Preferred Oil, LLC + +OUI:0050C2A27* + ID_OUI_FROM_DATABASE=meconet e. K. + +OUI:0050C2A28* + ID_OUI_FROM_DATABASE=KENDA ELECTRONIC SYSTEMS LIMITED + +OUI:0050C2A29* + ID_OUI_FROM_DATABASE=Luminex Corporation + +OUI:0050C2A2A* + ID_OUI_FROM_DATABASE=Custom Control Concepts + +OUI:0050C2A2B* + ID_OUI_FROM_DATABASE=APRILIA RACING S.R.L. + +OUI:0050C2A2C* + ID_OUI_FROM_DATABASE=KWS-Electronic GmbH + +OUI:0050C2A2D* + ID_OUI_FROM_DATABASE=Inventure Inc. + +OUI:0050C2A2E* + ID_OUI_FROM_DATABASE=Yuyama Mfg. Co., Ltd. + +OUI:0050C2A2F* + ID_OUI_FROM_DATABASE=DragonFly Scientific LLC + +OUI:0050C2A30* + ID_OUI_FROM_DATABASE=D-TA Systems + +OUI:0050C2A31* + ID_OUI_FROM_DATABASE=Coolit Systems, Inc. + +OUI:0050C2A32* + ID_OUI_FROM_DATABASE=Harris Designs of NRV, Inc. + +OUI:0050C2A33* + ID_OUI_FROM_DATABASE=Fuji Firmware + +OUI:0050C2A34* + ID_OUI_FROM_DATABASE=Casabyte Inc. + +OUI:0050C2A35* + ID_OUI_FROM_DATABASE=Appareo Systems, LLC + +OUI:0050C2A36* + ID_OUI_FROM_DATABASE=Shenzhen Shangji electronic Co.Ltd + +OUI:0050C2A37* + ID_OUI_FROM_DATABASE=Software Systems Plus + +OUI:0050C2A38* + ID_OUI_FROM_DATABASE=Tred Displays + +OUI:0050C2A39* + ID_OUI_FROM_DATABASE=Industrial Data Products Ltd + +OUI:0050C2A3A* + ID_OUI_FROM_DATABASE=Telecor Inc. + +OUI:0050C2A3B* + ID_OUI_FROM_DATABASE=IPcontrols GmbH + +OUI:0050C2A3C* + ID_OUI_FROM_DATABASE=Brähler ICS Konferenztechnik AG + +OUI:0050C2A3D* + ID_OUI_FROM_DATABASE=OWANDY + +OUI:0050C2A3E* + ID_OUI_FROM_DATABASE=DUEVI SNC DI MORA E SANTESE + +OUI:0050C2A3F* + ID_OUI_FROM_DATABASE=LHA Systems CC + +OUI:0050C2A40* + ID_OUI_FROM_DATABASE=Mosberger Consulting LLC + +OUI:0050C2A41* + ID_OUI_FROM_DATABASE=Meiryo Denshi Corp. + +OUI:0050C2A42* + ID_OUI_FROM_DATABASE=RealVision Inc. + +OUI:0050C2A43* + ID_OUI_FROM_DATABASE=NKS Co.Ltd. + +OUI:0050C2A44* + ID_OUI_FROM_DATABASE=TORC Technologies + +OUI:0050C2A45* + ID_OUI_FROM_DATABASE=Sofradir-EC + +OUI:0050C2A46* + ID_OUI_FROM_DATABASE=Softronics Ltd. + +OUI:0050C2A47* + ID_OUI_FROM_DATABASE=PRIMETECH ENGINEERING CORP. + +OUI:0050C2A48* + ID_OUI_FROM_DATABASE=Thales Optronics Limited + +OUI:0050C2A49* + ID_OUI_FROM_DATABASE=Wayne Dalton Corp. + +OUI:0050C2A4A* + ID_OUI_FROM_DATABASE=DITRON S.r.l. + +OUI:0050C2A4B* + ID_OUI_FROM_DATABASE=L-3 Communications Mobile-Vision, Inc. + +OUI:0050C2A4C* + ID_OUI_FROM_DATABASE=VasoNova, Inc. + +OUI:0050C2A4D* + ID_OUI_FROM_DATABASE=LevelStar LLC. + +OUI:0050C2A4E* + ID_OUI_FROM_DATABASE=Conduant Corporation + +OUI:0050C2A4F* + ID_OUI_FROM_DATABASE=Deuta GmbH + +OUI:0050C2A50* + ID_OUI_FROM_DATABASE=i-RED Infrarot Systeme GmbH + +OUI:0050C2A51* + ID_OUI_FROM_DATABASE=Y-products co.ltd. + +OUI:0050C2A52* + ID_OUI_FROM_DATABASE=The VON Corporation + +OUI:0050C2A53* + ID_OUI_FROM_DATABASE=Quality & Design + +OUI:0050C2A54* + ID_OUI_FROM_DATABASE=Diamond Point International (Europe) Ltd + +OUI:0050C2A55* + ID_OUI_FROM_DATABASE=Arrowvale Electronics + +OUI:0050C2A56* + ID_OUI_FROM_DATABASE=ReaMetrix, Inc. + +OUI:0050C2A57* + ID_OUI_FROM_DATABASE=Juice Technologies, LLC + +OUI:0050C2A58* + ID_OUI_FROM_DATABASE=EPL + +OUI:0050C2A59* + ID_OUI_FROM_DATABASE=GSP Sprachtechnologie GmbH + +OUI:0050C2A5A* + ID_OUI_FROM_DATABASE=ITAS A/S + +OUI:0050C2A5B* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2A5C* + ID_OUI_FROM_DATABASE=JSC "Component-ASU" + +OUI:0050C2A5D* + ID_OUI_FROM_DATABASE=MECC CO., LTD. + +OUI:0050C2A5E* + ID_OUI_FROM_DATABASE=Ansen Investment Holdings Ltd. + +OUI:0050C2A5F* + ID_OUI_FROM_DATABASE=Alga Microwave Inc + +OUI:0050C2A60* + ID_OUI_FROM_DATABASE=Arrow Central Europe GmbH - Division Spoerle + +OUI:0050C2A61* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2A62* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + +OUI:0050C2A63* + ID_OUI_FROM_DATABASE=EMS Industries + +OUI:0050C2A64* + ID_OUI_FROM_DATABASE=tetronik GmbH AEN + +OUI:0050C2A65* + ID_OUI_FROM_DATABASE=Mark-O-Print GmbH + +OUI:0050C2A66* + ID_OUI_FROM_DATABASE=DVTech + +OUI:0050C2A67* + ID_OUI_FROM_DATABASE=GSS Avionics Limited + +OUI:0050C2A68* + ID_OUI_FROM_DATABASE=X-Pert Paint Mixing Systems + +OUI:0050C2A69* + ID_OUI_FROM_DATABASE=Advanced Integrated Systems + +OUI:0050C2A6A* + ID_OUI_FROM_DATABASE=Infocrossing + +OUI:0050C2A6B* + ID_OUI_FROM_DATABASE=Explorer Inc. + +OUI:0050C2A6C* + ID_OUI_FROM_DATABASE=Figment Design Laboratories + +OUI:0050C2A6D* + ID_OUI_FROM_DATABASE=DTV Innovations + +OUI:0050C2A6E* + ID_OUI_FROM_DATABASE=Screen Technics Pty Limited + +OUI:0050C2A6F* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2A70* + ID_OUI_FROM_DATABASE=Reliable System Services Corp + +OUI:0050C2A71* + ID_OUI_FROM_DATABASE=Purite Ltd + +OUI:0050C2A72* + ID_OUI_FROM_DATABASE=Gamber-Johnson LLC. + +OUI:0050C2A73* + ID_OUI_FROM_DATABASE=KYOEI ENGINEERING Co.,Ltd. + +OUI:0050C2A74* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2A75* + ID_OUI_FROM_DATABASE=JTL Systems Ltd. + +OUI:0050C2A76* + ID_OUI_FROM_DATABASE=Roesch & Walter Industrie-Elektronik GmbH + +OUI:0050C2A77* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2A78* + ID_OUI_FROM_DATABASE=Apantac LLC + +OUI:0050C2A79* + ID_OUI_FROM_DATABASE=Saintronic + +OUI:0050C2A7A* + ID_OUI_FROM_DATABASE=DetNet South Africa PTY (LTD) + +OUI:0050C2A7B* + ID_OUI_FROM_DATABASE=Orange Tree Technologies + +OUI:0050C2A7C* + ID_OUI_FROM_DATABASE=Pneu-Logic Corporation + +OUI:0050C2A7D* + ID_OUI_FROM_DATABASE=Vitel Net + +OUI:0050C2A7E* + ID_OUI_FROM_DATABASE=Independent Project Engineering Ltd + +OUI:0050C2A7F* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2A80* + ID_OUI_FROM_DATABASE=ARD SA + +OUI:0050C2A81* + ID_OUI_FROM_DATABASE=BPC circuits Ltd + +OUI:0050C2A82* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2A83* + ID_OUI_FROM_DATABASE=Techno Sobi Co. Ltd. + +OUI:0050C2A84* + ID_OUI_FROM_DATABASE=Lino Manfrotto +Co spa + +OUI:0050C2A85* + ID_OUI_FROM_DATABASE=JOYSYSTEM + +OUI:0050C2A86* + ID_OUI_FROM_DATABASE=LIMAB AB + +OUI:0050C2A87* + ID_OUI_FROM_DATABASE=Littlemore Scientific + +OUI:0050C2A88* + ID_OUI_FROM_DATABASE=S-SYS + +OUI:0050C2A89* + ID_OUI_FROM_DATABASE=CA Traffic Ltd + +OUI:0050C2A8A* + ID_OUI_FROM_DATABASE=Audio Engineering Ltd. + +OUI:0050C2A8B* + ID_OUI_FROM_DATABASE=Navicron Oy + +OUI:0050C2A8C* + ID_OUI_FROM_DATABASE=Redwire, LLC + +OUI:0050C2A8D* + ID_OUI_FROM_DATABASE=Frontier Electronic Systems Corp. + +OUI:0050C2A8E* + ID_OUI_FROM_DATABASE=BFI Industrie-Elektronik GmbH & Co.KG + +OUI:0050C2A8F* + ID_OUI_FROM_DATABASE=Quantum3D, Inc. + +OUI:0050C2A90* + ID_OUI_FROM_DATABASE=S.two Corporation + +OUI:0050C2A91* + ID_OUI_FROM_DATABASE=Ceron Tech Co.,LTD + +OUI:0050C2A92* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2A93* + ID_OUI_FROM_DATABASE=SPX Dehydration & Filtration + +OUI:0050C2A94* + ID_OUI_FROM_DATABASE=Par-Tech, Inc. + +OUI:0050C2A95* + ID_OUI_FROM_DATABASE=INNOVACIONES Microelectrónicas SL (AnaFocus) + +OUI:0050C2A96* + ID_OUI_FROM_DATABASE=FEP SRL + +OUI:0050C2A97* + ID_OUI_FROM_DATABASE=MICROSYSTEMES + +OUI:0050C2A98* + ID_OUI_FROM_DATABASE=Sentry 360 Security + +OUI:0050C2A99* + ID_OUI_FROM_DATABASE=Haivision Systems Inc + +OUI:0050C2A9A* + ID_OUI_FROM_DATABASE=Absolutron. LLC + +OUI:0050C2A9B* + ID_OUI_FROM_DATABASE=PDQ Manufacturing Inc. + +OUI:0050C2A9C* + ID_OUI_FROM_DATABASE=Eberspächer Electronics GmbH & Co. KG + +OUI:0050C2A9D* + ID_OUI_FROM_DATABASE=Joehl & Koeferli AG + +OUI:0050C2A9E* + ID_OUI_FROM_DATABASE=Procon Engineering Limited + +OUI:0050C2A9F* + ID_OUI_FROM_DATABASE=YellowSoft Co., Ltd. + +OUI:0050C2AA0* + ID_OUI_FROM_DATABASE=Smith Meter, Inc. + +OUI:0050C2AA1* + ID_OUI_FROM_DATABASE=ELREM ELECTRONIC AG + +OUI:0050C2AA2* + ID_OUI_FROM_DATABASE=ELPA sas + +OUI:0050C2AA3* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2AA4* + ID_OUI_FROM_DATABASE=PSi Printer Systems international GmbH + +OUI:0050C2AA5* + ID_OUI_FROM_DATABASE=Tampere University of Technology + +OUI:0050C2AA6* + ID_OUI_FROM_DATABASE=Bassett Electronic Systems ltd + +OUI:0050C2AA7* + ID_OUI_FROM_DATABASE=Endeas Oy + +OUI:0050C2AA8* + ID_OUI_FROM_DATABASE=Nexans Cabling Solutions + +OUI:0050C2AA9* + ID_OUI_FROM_DATABASE=SAN GIORGIO S.E.I.N. srl + +OUI:0050C2AAA* + ID_OUI_FROM_DATABASE=Flexible Picture Systems + +OUI:0050C2AAB* + ID_OUI_FROM_DATABASE=BRS Sistemas Eletrônicos + +OUI:0050C2AAC* + ID_OUI_FROM_DATABASE=VisiCon GmbH + +OUI:0050C2AAD* + ID_OUI_FROM_DATABASE=Update Systems Inc. + +OUI:0050C2AAE* + ID_OUI_FROM_DATABASE=OUTLINE srl + +OUI:0050C2AAF* + ID_OUI_FROM_DATABASE=Santa Barbara Instrument Group + +OUI:0050C2AB0* + ID_OUI_FROM_DATABASE=FRAKO Kondensatoren- und Anlagenbau GmbH + +OUI:0050C2AB1* + ID_OUI_FROM_DATABASE=Bitmanufaktur GmbH + +OUI:0050C2AB2* + ID_OUI_FROM_DATABASE=ProCom Systems, Inc. + +OUI:0050C2AB3* + ID_OUI_FROM_DATABASE=Compañía de Instrumentacion y control, S.L. + +OUI:0050C2AB4* + ID_OUI_FROM_DATABASE=n3k Informatik GmbH + +OUI:0050C2AB5* + ID_OUI_FROM_DATABASE=METTLER-TOLEDO HI-SPEED + +OUI:0050C2AB6* + ID_OUI_FROM_DATABASE=Gygax Embedded Engineering GEE.ch + +OUI:0050C2AB7* + ID_OUI_FROM_DATABASE=Twinfalls Technologies + +OUI:0050C2AB8* + ID_OUI_FROM_DATABASE=AHM Limited (CLiKAPAD) + +OUI:0050C2AB9* + ID_OUI_FROM_DATABASE=Showtacle + +OUI:0050C2ABA* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2ABB* + ID_OUI_FROM_DATABASE=Volantic AB + +OUI:0050C2ABC* + ID_OUI_FROM_DATABASE=Barrick + +OUI:0050C2ABD* + ID_OUI_FROM_DATABASE=Monitor Business Machines Ltd. + +OUI:0050C2ABE* + ID_OUI_FROM_DATABASE=AP Labs + +OUI:0050C2ABF* + ID_OUI_FROM_DATABASE=MCC Computer Company + +OUI:0050C2AC0* + ID_OUI_FROM_DATABASE=DS PRO Audio Ltda + +OUI:0050C2AC1* + ID_OUI_FROM_DATABASE=DAISHIN-DENSHI Co., Ltd + +OUI:0050C2AC2* + ID_OUI_FROM_DATABASE=OpenXS B.V. + +OUI:0050C2AC3* + ID_OUI_FROM_DATABASE=Diversified Control, Inc. + +OUI:0050C2AC4* + ID_OUI_FROM_DATABASE=Orion Technologies, Incorporated + +OUI:0050C2AC5* + ID_OUI_FROM_DATABASE=E-Motion System, Inc. + +OUI:0050C2AC6* + ID_OUI_FROM_DATABASE=Marathon Products, Inc. + +OUI:0050C2AC7* + ID_OUI_FROM_DATABASE=WaveIP + +OUI:0050C2AC8* + ID_OUI_FROM_DATABASE=Palladio Systeme GmbH + +OUI:0050C2AC9* + ID_OUI_FROM_DATABASE=Steinbeis-Transferzentrum Embedded Design und Networking + +OUI:0050C2ACA* + ID_OUI_FROM_DATABASE=Soft & Control Technology s.r.o. + +OUI:0050C2ACB* + ID_OUI_FROM_DATABASE=U-CARE INC. + +OUI:0050C2ACC* + ID_OUI_FROM_DATABASE=StockerYale + +OUI:0050C2ACD* + ID_OUI_FROM_DATABASE=MeshWorks Wireless Oy + +OUI:0050C2ACE* + ID_OUI_FROM_DATABASE=ChronoLogic Pty. Ltd. + +OUI:0050C2ACF* + ID_OUI_FROM_DATABASE=SP Controls, Inc + +OUI:0050C2AD0* + ID_OUI_FROM_DATABASE=Geonautics Australia Pty Ltd + +OUI:0050C2AD1* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2AD2* + ID_OUI_FROM_DATABASE=Rafael + +OUI:0050C2AD3* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2AD4* + ID_OUI_FROM_DATABASE=Global Rainmakers Inc. + +OUI:0050C2AD5* + ID_OUI_FROM_DATABASE=Mighty Lube Systematic Lubrication, Inc. + +OUI:0050C2AD6* + ID_OUI_FROM_DATABASE=Unisensor A/S + +OUI:0050C2AD7* + ID_OUI_FROM_DATABASE=Air Monitors Ltd + +OUI:0050C2AD8* + ID_OUI_FROM_DATABASE=Incyma + +OUI:0050C2AD9* + ID_OUI_FROM_DATABASE=elettrondata srl + +OUI:0050C2ADA* + ID_OUI_FROM_DATABASE=Essepie Srl + +OUI:0050C2ADB* + ID_OUI_FROM_DATABASE=GO engineering GmbH + +OUI:0050C2ADC* + ID_OUI_FROM_DATABASE=Synthesechemie Dr. Penth GmbH + +OUI:0050C2ADD* + ID_OUI_FROM_DATABASE=General Dynamics C4 Sysems + +OUI:0050C2ADE* + ID_OUI_FROM_DATABASE=Neoptix Inc. + +OUI:0050C2ADF* + ID_OUI_FROM_DATABASE=Altinex, Inc + +OUI:0050C2AE0* + ID_OUI_FROM_DATABASE=AT4 wireless.S.A + +OUI:0050C2AE1* + ID_OUI_FROM_DATABASE=EVERCARE + +OUI:0050C2AE2* + ID_OUI_FROM_DATABASE=Power Medical Interventions + +OUI:0050C2AE3* + ID_OUI_FROM_DATABASE=PSD + +OUI:0050C2AE4* + ID_OUI_FROM_DATABASE=Advanced Electronic Designs, Inc. + +OUI:0050C2AE5* + ID_OUI_FROM_DATABASE=ABS Gesellschaft f. Automatisierung, Bildverarbeitung und Software mbH + +OUI:0050C2AE6* + ID_OUI_FROM_DATABASE=VECOM USA + +OUI:0050C2AE7* + ID_OUI_FROM_DATABASE=Redwood Systems + +OUI:0050C2AE8* + ID_OUI_FROM_DATABASE=Bit-Lab PTY LTD + +OUI:0050C2AE9* + ID_OUI_FROM_DATABASE=ClearCorp Enterprises, Inc + +OUI:0050C2AEA* + ID_OUI_FROM_DATABASE=EMBEDIA + +OUI:0050C2AEB* + ID_OUI_FROM_DATABASE=UMLogics Corporation + +OUI:0050C2AEC* + ID_OUI_FROM_DATABASE=Fritz Pauker Ingenieure GmbH + +OUI:0050C2AED* + ID_OUI_FROM_DATABASE=3Roam + +OUI:0050C2AEE* + ID_OUI_FROM_DATABASE=IPtec, Inc. + +OUI:0050C2AEF* + ID_OUI_FROM_DATABASE=National CineMedia + +OUI:0050C2AF0* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2AF1* + ID_OUI_FROM_DATABASE=Green Goose + +OUI:0050C2AF2* + ID_OUI_FROM_DATABASE=ACD Elektronik Gmbh + +OUI:0050C2AF3* + ID_OUI_FROM_DATABASE=Palomar Products, Inc. + +OUI:0050C2AF4* + ID_OUI_FROM_DATABASE=Dixell S.p.A. + +OUI:0050C2AF5* + ID_OUI_FROM_DATABASE=Kramara s.r.o. + +OUI:0050C2AF6* + ID_OUI_FROM_DATABASE=Energid + +OUI:0050C2AF7* + ID_OUI_FROM_DATABASE=Midwest Microwave Solutions Inc. + +OUI:0050C2AF8* + ID_OUI_FROM_DATABASE=Global Satellite Engineering + +OUI:0050C2AF9* + ID_OUI_FROM_DATABASE=Ingenieurbuero Bickele und Buehler GmbH + +OUI:0050C2AFA* + ID_OUI_FROM_DATABASE=Absolute Fire Solutions Inc. + +OUI:0050C2AFC* + ID_OUI_FROM_DATABASE=Odus Technologies SA + +OUI:0050C2AFD* + ID_OUI_FROM_DATABASE=HomeScenario, Inc. + +OUI:0050C2AFE* + ID_OUI_FROM_DATABASE=Trolex Limited + +OUI:0050C2AFF* + ID_OUI_FROM_DATABASE=XoByte LLC + +OUI:0050C2B00* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2B01* + ID_OUI_FROM_DATABASE=HSR Harald L. Reuter + +OUI:0050C2B02* + ID_OUI_FROM_DATABASE=MASTER CO LTD + +OUI:0050C2B03* + ID_OUI_FROM_DATABASE=Spider Tecnologia Ind. e Com. Ltda. + +OUI:0050C2B04* + ID_OUI_FROM_DATABASE=Ubiquiti Networks + +OUI:0050C2B05* + ID_OUI_FROM_DATABASE=POLA s.r.l. + +OUI:0050C2B06* + ID_OUI_FROM_DATABASE=CompuDesigns, Inc. + +OUI:0050C2B07* + ID_OUI_FROM_DATABASE=FARECO + +OUI:0050C2B08* + ID_OUI_FROM_DATABASE=Goerlitz AG + +OUI:0050C2B09* + ID_OUI_FROM_DATABASE=Harper Chalice Group Limited + +OUI:0050C2B0A* + ID_OUI_FROM_DATABASE=Indutherm Giesstechnologie GmbH + +OUI:0050C2B0B* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:0050C2B0C* + ID_OUI_FROM_DATABASE=SMARTB TECHNOLOGIES + +OUI:0050C2B0D* + ID_OUI_FROM_DATABASE=Japan Electronics System, Inc + +OUI:0050C2B0E* + ID_OUI_FROM_DATABASE=KYAB Lulea AB + +OUI:0050C2B0F* + ID_OUI_FROM_DATABASE=NARA Controls Inc. + +OUI:0050C2B10* + ID_OUI_FROM_DATABASE=Marine Entertainment Systems Ltd + +OUI:0050C2B11* + ID_OUI_FROM_DATABASE=EXEL s.r.l + +OUI:0050C2B12* + ID_OUI_FROM_DATABASE=CM Elektronik GmbH + +OUI:0050C2B13* + ID_OUI_FROM_DATABASE=Measy Electronics Co., Ltd. + +OUI:0050C2B14* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2B15* + ID_OUI_FROM_DATABASE=PhotoTelesis LP + +OUI:0050C2B16* + ID_OUI_FROM_DATABASE=Neothings, Inc. + +OUI:0050C2B17* + ID_OUI_FROM_DATABASE=Elcoteq Design Center Oy + +OUI:0050C2B18* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:0050C2B19* + ID_OUI_FROM_DATABASE=Polytron Corporation + +OUI:0050C2B1A* + ID_OUI_FROM_DATABASE=ELCUS + +OUI:0050C2B1B* + ID_OUI_FROM_DATABASE=Integrated Control Corp. + +OUI:0050C2B1C* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2B1D* + ID_OUI_FROM_DATABASE=Telegenix + +OUI:0050C2B1E* + ID_OUI_FROM_DATABASE=Abbott Medical Optics + +OUI:0050C2B1F* + ID_OUI_FROM_DATABASE=SCA Schucker GmbH & Co. + +OUI:0050C2B20* + ID_OUI_FROM_DATABASE=FIVE9 NETWORK SYSTEMS LLC + +OUI:0050C2B21* + ID_OUI_FROM_DATABASE=Phytron-Elektronik GmbH + +OUI:0050C2B22* + ID_OUI_FROM_DATABASE=FarSite Communications Limited + +OUI:0050C2B23* + ID_OUI_FROM_DATABASE=Ronyo Technologies s.r.o. + +OUI:0050C2B24* + ID_OUI_FROM_DATABASE=Teledyne Defence Limited + +OUI:0050C2B25* + ID_OUI_FROM_DATABASE=Triax A/S + +OUI:0050C2B26* + ID_OUI_FROM_DATABASE=Elko Systems + +OUI:0050C2B27* + ID_OUI_FROM_DATABASE=ATEME + +OUI:0050C2B28* + ID_OUI_FROM_DATABASE=Micromax Pty. Ltd. + +OUI:0050C2B29* + ID_OUI_FROM_DATABASE=Integra LifeSciences (Ireland) Ltd + +OUI:0050C2B2A* + ID_OUI_FROM_DATABASE=Trench Austria GmbH + +OUI:0050C2B2B* + ID_OUI_FROM_DATABASE=CosmoData Informatica Ltda. + +OUI:0050C2B2C* + ID_OUI_FROM_DATABASE=Concepteers, LLC + +OUI:0050C2B2D* + ID_OUI_FROM_DATABASE=Datasat Digital Entertainment + +OUI:0050C2B2E* + ID_OUI_FROM_DATABASE=ACT + +OUI:0050C2B2F* + ID_OUI_FROM_DATABASE=IntelliVision Technologies, Corp + +OUI:0050C2B30* + ID_OUI_FROM_DATABASE=Applied Micro Electronics "AME" BV + +OUI:0050C2B31* + ID_OUI_FROM_DATABASE=Shop Safe AG + +OUI:0050C2B32* + ID_OUI_FROM_DATABASE=Byres Security Inc + +OUI:0050C2B33* + ID_OUI_FROM_DATABASE=Numcore Ltd + +OUI:0050C2B34* + ID_OUI_FROM_DATABASE=Meisol co.,ltd + +OUI:0050C2B35* + ID_OUI_FROM_DATABASE=haneron + +OUI:0050C2B36* + ID_OUI_FROM_DATABASE=CRDE + +OUI:0050C2B37* + ID_OUI_FROM_DATABASE=IAdea Corporation + +OUI:0050C2B38* + ID_OUI_FROM_DATABASE=Grenmore Ltd + +OUI:0050C2B39* + ID_OUI_FROM_DATABASE=siXis, Inc. + +OUI:0050C2B3A* + ID_OUI_FROM_DATABASE=Nikon Systems Inc. + +OUI:0050C2B3B* + ID_OUI_FROM_DATABASE=Sportvision Inc. + +OUI:0050C2B3C* + ID_OUI_FROM_DATABASE=JanasCard + +OUI:0050C2B3D* + ID_OUI_FROM_DATABASE=AMS + +OUI:0050C2B3E* + ID_OUI_FROM_DATABASE=Sage Consultants + +OUI:0050C2B3F* + ID_OUI_FROM_DATABASE=M-Tronic Design and Technology GmbH + +OUI:0050C2B40* + ID_OUI_FROM_DATABASE=Tecnint HTE SRL + +OUI:0050C2B41* + ID_OUI_FROM_DATABASE=Tata Power Company, Strategic Electronics Division + +OUI:0050C2B42* + ID_OUI_FROM_DATABASE=ETM Electromatic Incorporated + +OUI:0050C2B43* + ID_OUI_FROM_DATABASE=J-Systems Inc. + +OUI:0050C2B44* + ID_OUI_FROM_DATABASE=Ampcontrol Pty Ltd + +OUI:0050C2B45* + ID_OUI_FROM_DATABASE=Efftronics Systems (P) Ltd + +OUI:0050C2B46* + ID_OUI_FROM_DATABASE=Mobileye + +OUI:0050C2B47* + ID_OUI_FROM_DATABASE=MCS MICRONIC Computer Systeme GmbH + +OUI:0050C2B48* + ID_OUI_FROM_DATABASE=MTD GmbH + +OUI:0050C2B49* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2B4A* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2B4B* + ID_OUI_FROM_DATABASE=Chitose Co.,Ltd + +OUI:0050C2B4C* + ID_OUI_FROM_DATABASE=ElectroCom + +OUI:0050C2B4D* + ID_OUI_FROM_DATABASE=Troll Systems Corporation + +OUI:0050C2B4E* + ID_OUI_FROM_DATABASE=AixControl GmbH + +OUI:0050C2B4F* + ID_OUI_FROM_DATABASE=Sencon UK Ltd. + +OUI:0050C2B50* + ID_OUI_FROM_DATABASE=SELCO + +OUI:0050C2B51* + ID_OUI_FROM_DATABASE=Aeroflex GmbH + +OUI:0050C2B52* + ID_OUI_FROM_DATABASE=SMH Technologies + +OUI:0050C2B53* + ID_OUI_FROM_DATABASE=Prodco + +OUI:0050C2B54* + ID_OUI_FROM_DATABASE=APG Cash Drawer, LLC + +OUI:0050C2B55* + ID_OUI_FROM_DATABASE=SANYO ELECTRONIC INDUSTRIES CO.,LTD + +OUI:0050C2B56* + ID_OUI_FROM_DATABASE=SINOVIA SA + +OUI:0050C2B57* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2B58* + ID_OUI_FROM_DATABASE=Real D + +OUI:0050C2B59* + ID_OUI_FROM_DATABASE=SLICAN sp. z o.o. + +OUI:0050C2B5A* + ID_OUI_FROM_DATABASE=GREEN Center s.r.o. + +OUI:0050C2B5B* + ID_OUI_FROM_DATABASE=Timberline Mfg Company + +OUI:0050C2B5C* + ID_OUI_FROM_DATABASE=ADI Video Technologies + +OUI:0050C2B5D* + ID_OUI_FROM_DATABASE=Plitron Manufacturing Inc. + +OUI:0050C2B5E* + ID_OUI_FROM_DATABASE=Palgiken Co.,Ltd. + +OUI:0050C2B5F* + ID_OUI_FROM_DATABASE=North Bridge Technologies + +OUI:0050C2B60* + ID_OUI_FROM_DATABASE=OOO NPF ATIS + +OUI:0050C2B61* + ID_OUI_FROM_DATABASE=Nayos LTD + +OUI:0050C2B62* + ID_OUI_FROM_DATABASE=Measurement Technology NW + +OUI:0050C2B63* + ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A + +OUI:0050C2B64* + ID_OUI_FROM_DATABASE=FEW Bauer GmbH + +OUI:0050C2B65* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2B66* + ID_OUI_FROM_DATABASE=Deuta-Werke GmbH + +OUI:0050C2B67* + ID_OUI_FROM_DATABASE=RC Systems Co. Inc. + +OUI:0050C2B68* + ID_OUI_FROM_DATABASE=Electronic Systems Protection, Inc. + +OUI:0050C2B69* + ID_OUI_FROM_DATABASE=Thetis S.p.A. + +OUI:0050C2B6A* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2B6B* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2B6C* + ID_OUI_FROM_DATABASE=Drinelec + +OUI:0050C2B6D* + ID_OUI_FROM_DATABASE=Sound Metrics Corp + +OUI:0050C2B6F* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2B70* + ID_OUI_FROM_DATABASE=Nisshin Electronics co.,ltd. + +OUI:0050C2B71* + ID_OUI_FROM_DATABASE=Digitale Analoge COMponenten West Electronic Vertriebs GmbH + +OUI:0050C2B72* + ID_OUI_FROM_DATABASE=Advanced Desktop Systems Ltd + +OUI:0050C2B73* + ID_OUI_FROM_DATABASE=ARKRAY, Inc. Kyoto Laboratory + +OUI:0050C2B74* + ID_OUI_FROM_DATABASE=AXED Jakubowski Wojciechowski sp.j. + +OUI:0050C2B75* + ID_OUI_FROM_DATABASE=Blankom + +OUI:0050C2B76* + ID_OUI_FROM_DATABASE=ITF Fröschl GmbH + +OUI:0050C2B77* + ID_OUI_FROM_DATABASE=KRISTECH + +OUI:0050C2B78* + ID_OUI_FROM_DATABASE=Folink + +OUI:0050C2B79* + ID_OUI_FROM_DATABASE=MITSUYA LABORATORIES INC. + +OUI:0050C2B7A* + ID_OUI_FROM_DATABASE=Schnoor Industrieelektronik GmbH & Co. KG + +OUI:0050C2B7B* + ID_OUI_FROM_DATABASE=QUARTECH CORPORATION + +OUI:0050C2B7C* + ID_OUI_FROM_DATABASE=Bettini srl + +OUI:0050C2B7D* + ID_OUI_FROM_DATABASE=ELETECH Srl + +OUI:0050C2B7E* + ID_OUI_FROM_DATABASE=NARETRENDS + +OUI:0050C2B7F* + ID_OUI_FROM_DATABASE=Enatel + +OUI:0050C2B80* + ID_OUI_FROM_DATABASE=iScreen LLC + +OUI:0050C2B81* + ID_OUI_FROM_DATABASE=GHL Advanced Technolgy GmbH & Co. KG + +OUI:0050C2B82* + ID_OUI_FROM_DATABASE=TANABIKI Inc. + +OUI:0050C2B83* + ID_OUI_FROM_DATABASE=Advanced Storage Concepts, Inc. + +OUI:0050C2B84* + ID_OUI_FROM_DATABASE=Innovate Software Solutions Pvt Ltd + +OUI:0050C2B85* + ID_OUI_FROM_DATABASE=SilverNet + +OUI:0050C2B86* + ID_OUI_FROM_DATABASE=ASTO + +OUI:0050C2B87* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2B88* + ID_OUI_FROM_DATABASE=Gigatronik Köln GmbH + +OUI:0050C2B89* + ID_OUI_FROM_DATABASE=ENTEC Electric & Electronic Co., LTD. + +OUI:0050C2B8A* + ID_OUI_FROM_DATABASE=MicroPoise + +OUI:0050C2B8B* + ID_OUI_FROM_DATABASE=FBB + +OUI:0050C2B8C* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2B8D* + ID_OUI_FROM_DATABASE=CEMSI + +OUI:0050C2B8E* + ID_OUI_FROM_DATABASE=WAC (Israel) Ltd. + +OUI:0050C2B8F* + ID_OUI_FROM_DATABASE=Gentec + +OUI:0050C2B90* + ID_OUI_FROM_DATABASE=NAONWORKS Co., Ltd + +OUI:0050C2B91* + ID_OUI_FROM_DATABASE=Finnet-Service Ltd. + +OUI:0050C2B92* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C2B93* + ID_OUI_FROM_DATABASE=EMC PARTNER AG + +OUI:0050C2B94* + ID_OUI_FROM_DATABASE=Tritech International Ltd + +OUI:0050C2B95* + ID_OUI_FROM_DATABASE=Rx Monitoring Services + +OUI:0050C2B96* + ID_OUI_FROM_DATABASE=Onix Electronic Systems Inc + +OUI:0050C2B97* + ID_OUI_FROM_DATABASE=ikerlan + +OUI:0050C2B98* + ID_OUI_FROM_DATABASE=Southwest Research Institute + +OUI:0050C2B99* + ID_OUI_FROM_DATABASE=Greenlight Innovation Corp. + +OUI:0050C2B9A* + ID_OUI_FROM_DATABASE=Talo, NV Inc + +OUI:0050C2B9B* + ID_OUI_FROM_DATABASE=Telventy Energia S.A. + +OUI:0050C2B9C* + ID_OUI_FROM_DATABASE=Dave srl + +OUI:0050C2B9D* + ID_OUI_FROM_DATABASE=W. Vershoven GmbH + +OUI:0050C2B9E* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2B9F* + ID_OUI_FROM_DATABASE=AUDIOSCOPE 2K SRL + +OUI:0050C2BA0* + ID_OUI_FROM_DATABASE=txtr GmbH + +OUI:0050C2BA1* + ID_OUI_FROM_DATABASE=Transtechnik GmbH & Co.KG + +OUI:0050C2BA2* + ID_OUI_FROM_DATABASE=Logical Tools s.r.l. + +OUI:0050C2BA3* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2BA4* + ID_OUI_FROM_DATABASE=CUSTOS MOBILE S.L. + +OUI:0050C2BA5* + ID_OUI_FROM_DATABASE=InterCel Pty Ltd + +OUI:0050C2BA6* + ID_OUI_FROM_DATABASE=Jomitek + +OUI:0050C2BA7* + ID_OUI_FROM_DATABASE=RaumComputer Entwicklungs- und Vertriebs GmbH + +OUI:0050C2BA8* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2BA9* + ID_OUI_FROM_DATABASE=SISS Technology Inc. + +OUI:0050C2BAA* + ID_OUI_FROM_DATABASE=NetworkFX Communications, LLC + +OUI:0050C2BAB* + ID_OUI_FROM_DATABASE=iDeal Teknoloji Bilisim Cozumleri A.S. + +OUI:0050C2BAC* + ID_OUI_FROM_DATABASE=VITECO VNPT JSC + +OUI:0050C2BAD* + ID_OUI_FROM_DATABASE=Prediktor AS + +OUI:0050C2BAE* + ID_OUI_FROM_DATABASE=Fiber Connections Inc. + +OUI:0050C2BAF* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C2BB0* + ID_OUI_FROM_DATABASE=Gainbrain + +OUI:0050C2BB1* + ID_OUI_FROM_DATABASE=Pro4tech + +OUI:0050C2BB2* + ID_OUI_FROM_DATABASE=St Michael Strategies Inc + +OUI:0050C2BB3* + ID_OUI_FROM_DATABASE=ClimateWell AB (publ) + +OUI:0050C2BB4* + ID_OUI_FROM_DATABASE=JSC Electrical Equipment Factory + +OUI:0050C2BB5* + ID_OUI_FROM_DATABASE=MROAD INFORMATION SYSTEM + +OUI:0050C2BB6* + ID_OUI_FROM_DATABASE=Quarch Technology Ltd + +OUI:0050C2BB7* + ID_OUI_FROM_DATABASE=General Dynamics C4 Systems + +OUI:0050C2BB8* + ID_OUI_FROM_DATABASE=MoeTronix + +OUI:0050C2BB9* + ID_OUI_FROM_DATABASE=Toptech Systems, Inc. + +OUI:0050C2BBA* + ID_OUI_FROM_DATABASE=Systemteq Limited + +OUI:0050C2BBB* + ID_OUI_FROM_DATABASE=GHL Systems Berhad + +OUI:0050C2BBC* + ID_OUI_FROM_DATABASE=ImpactSystems + +OUI:0050C2BBD* + ID_OUI_FROM_DATABASE=ITS Telecom + +OUI:0050C2BBE* + ID_OUI_FROM_DATABASE=Onlinepizza Norden AB + +OUI:0050C2BBF* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2BC0* + ID_OUI_FROM_DATABASE=Galaxia Electronics + +OUI:0050C2BC1* + ID_OUI_FROM_DATABASE=Sentec Ltd + +OUI:0050C2BC2* + ID_OUI_FROM_DATABASE=XSLENT Energy Technologies LLC + +OUI:0050C2BC3* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2BC4* + ID_OUI_FROM_DATABASE=Wheatstone Corporation + +OUI:0050C2BC5* + ID_OUI_FROM_DATABASE=Toptechnology SRL + +OUI:0050C2BC6* + ID_OUI_FROM_DATABASE=MireroTack + +OUI:0050C2BC7* + ID_OUI_FROM_DATABASE=PTS GmbH + +OUI:0050C2BC8* + ID_OUI_FROM_DATABASE=AGWTech Ltd + +OUI:0050C2BC9* + ID_OUI_FROM_DATABASE=Nextmove Technologies + +OUI:0050C2BCA* + ID_OUI_FROM_DATABASE=Aitecsystem Co.,Ltd. + +OUI:0050C2BCB* + ID_OUI_FROM_DATABASE=ARTEIXO TELECOM + +OUI:0050C2BCC* + ID_OUI_FROM_DATABASE=VVDN TECHNOLOGIES PVT. LTD. + +OUI:0050C2BCD* + ID_OUI_FROM_DATABASE=Highlight Parking Systems Ltd + +OUI:0050C2BCE* + ID_OUI_FROM_DATABASE=TV Portal Co., Ltd. + +OUI:0050C2BCF* + ID_OUI_FROM_DATABASE=Epiko, elektronski sistemi d.o.o. + +OUI:0050C2BD0* + ID_OUI_FROM_DATABASE=EDC wifi + +OUI:0050C2BD1* + ID_OUI_FROM_DATABASE=Ariem Technologies Pvt Ltd + +OUI:0050C2BD2* + ID_OUI_FROM_DATABASE=Percello Ltd. + +OUI:0050C2BD3* + ID_OUI_FROM_DATABASE=Postjet Systems Ltd + +OUI:0050C2BD4* + ID_OUI_FROM_DATABASE=Global Security Devices + +OUI:0050C2BD5* + ID_OUI_FROM_DATABASE=RF-Embedded GmbH + +OUI:0050C2BD6* + ID_OUI_FROM_DATABASE=BG Systems, Inc. + +OUI:0050C2BD7* + ID_OUI_FROM_DATABASE=SLAT + +OUI:0050C2BD8* + ID_OUI_FROM_DATABASE=b.a.b-technologie gmbh + +OUI:0050C2BD9* + ID_OUI_FROM_DATABASE=AMS Controls, Inc. + +OUI:0050C2BDA* + ID_OUI_FROM_DATABASE=Digital Lumens + +OUI:0050C2BDB* + ID_OUI_FROM_DATABASE=GasTOPS Ltd. + +OUI:0050C2BDC* + ID_OUI_FROM_DATABASE=SS Systems LLC + +OUI:0050C2BDE* + ID_OUI_FROM_DATABASE=Evo-Teh d.o.o. + +OUI:0050C2BDF* + ID_OUI_FROM_DATABASE=Euro-Konsult Sp. z o.o. + +OUI:0050C2BE0* + ID_OUI_FROM_DATABASE=Phaedrus Limited + +OUI:0050C2BE1* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C2BE2* + ID_OUI_FROM_DATABASE=Convergent Bioscience Ltd. + +OUI:0050C2BE3* + ID_OUI_FROM_DATABASE=Jiskoot Ltd + +OUI:0050C2BE4* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2BE5* + ID_OUI_FROM_DATABASE=RF Code, Inc + +OUI:0050C2BE6* + ID_OUI_FROM_DATABASE=Docobo Ltd + +OUI:0050C2BE7* + ID_OUI_FROM_DATABASE=Genetec Inc. + +OUI:0050C2BE8* + ID_OUI_FROM_DATABASE=VEHICLE TESTING EQUIPMENT, S.L. + +OUI:0050C2BE9* + ID_OUI_FROM_DATABASE=ZUCCHETTI SPA + +OUI:0050C2BEA* + ID_OUI_FROM_DATABASE=Daeyoung inc. + +OUI:0050C2BEB* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2BEC* + ID_OUI_FROM_DATABASE=DRS Laruel Technologies + +OUI:0050C2BED* + ID_OUI_FROM_DATABASE=Touch Revolution Inc. + +OUI:0050C2BEF* + ID_OUI_FROM_DATABASE=SOCIEDAD IBERICA DE CONSTRUCCIONES ELECTRICAS, S.A. (SICE) + +OUI:0050C2BF0* + ID_OUI_FROM_DATABASE=AIM + +OUI:0050C2BF1* + ID_OUI_FROM_DATABASE=Amatic Industries GmbH + +OUI:0050C2BF2* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2BF3* + ID_OUI_FROM_DATABASE=Wanco Inc. + +OUI:0050C2BF4* + ID_OUI_FROM_DATABASE=Monarch Innovative Technologies Pvt Ltd + +OUI:0050C2BF5* + ID_OUI_FROM_DATABASE=AILES ELECTRONICS CO., LTD. + +OUI:0050C2BF6* + ID_OUI_FROM_DATABASE=NOLAM EMBEDDED SYSTEMS + +OUI:0050C2BF7* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:0050C2BF8* + ID_OUI_FROM_DATABASE=Crtiical Link + +OUI:0050C2BF9* + ID_OUI_FROM_DATABASE=Vitel Net + +OUI:0050C2BFA* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2BFB* + ID_OUI_FROM_DATABASE=ECS Srl + +OUI:0050C2BFC* + ID_OUI_FROM_DATABASE=Altronix Corporation + +OUI:0050C2BFD* + ID_OUI_FROM_DATABASE=Ernemann Cine Tec GmbH + +OUI:0050C2BFE* + ID_OUI_FROM_DATABASE=Ingeteam Paneles S.A.U. + +OUI:0050C2BFF* + ID_OUI_FROM_DATABASE=I.S.A. S.r.l. + +OUI:0050C2C00* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2C01* + ID_OUI_FROM_DATABASE=QUERCUS TECHNOLOGIES, S.L. + +OUI:0050C2C02* + ID_OUI_FROM_DATABASE=Hanning Elektro-Werke GmbH & Co. KG + +OUI:0050C2C03* + ID_OUI_FROM_DATABASE=Volumatic Limited. + +OUI:0050C2C04* + ID_OUI_FROM_DATABASE=SoGEME + +OUI:0050C2C05* + ID_OUI_FROM_DATABASE=Doppler Systems LLC + +OUI:0050C2C06* + ID_OUI_FROM_DATABASE=ANALOG WAY + +OUI:0050C2C07* + ID_OUI_FROM_DATABASE=CIO Informatique Industrielle + +OUI:0050C2C08* + ID_OUI_FROM_DATABASE=juiceboss + +OUI:0050C2C09* + ID_OUI_FROM_DATABASE=Globe Wireless + +OUI:0050C2C0A* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C2C0B* + ID_OUI_FROM_DATABASE=ProSourcing GmbH + +OUI:0050C2C0C* + ID_OUI_FROM_DATABASE=Altierre + +OUI:0050C2C0D* + ID_OUI_FROM_DATABASE=Fr. SauterAG + +OUI:0050C2C0E* + ID_OUI_FROM_DATABASE=AVItronic GmbH + +OUI:0050C2C0F* + ID_OUI_FROM_DATABASE=DYCEC, S.A. + +OUI:0050C2C10* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2C11* + ID_OUI_FROM_DATABASE=ART Antriebs- und Regeltechnik GmbH + +OUI:0050C2C12* + ID_OUI_FROM_DATABASE=OKI DENKI BOHSAI CO.,LTD. + +OUI:0050C2C13* + ID_OUI_FROM_DATABASE=Dantec Dynamics A/S + +OUI:0050C2C14* + ID_OUI_FROM_DATABASE=Spectronix Corporation + +OUI:0050C2C15* + ID_OUI_FROM_DATABASE=INO - Institut National d'Optique + +OUI:0050C2C16* + ID_OUI_FROM_DATABASE=OMICRON electronics GmbH + +OUI:0050C2C17* + ID_OUI_FROM_DATABASE=Axis-Shield PoC AS + +OUI:0050C2C18* + ID_OUI_FROM_DATABASE=Linuxstamp Designs, LLC + +OUI:0050C2C19* + ID_OUI_FROM_DATABASE=Ibercomp SA + +OUI:0050C2C1A* + ID_OUI_FROM_DATABASE=SAM Co., Ltd. + +OUI:0050C2C1B* + ID_OUI_FROM_DATABASE=Graesslin GmbH + +OUI:0050C2C1C* + ID_OUI_FROM_DATABASE=Becton Dickinson + +OUI:0050C2C1D* + ID_OUI_FROM_DATABASE=Powerbase Energy Systems Inc. + +OUI:0050C2C1E* + ID_OUI_FROM_DATABASE=Peperoni-Light + +OUI:0050C2C1F* + ID_OUI_FROM_DATABASE=Specialist Electronics Services Ltd + +OUI:0050C2C20* + ID_OUI_FROM_DATABASE=SRC Computers, LLC + +OUI:0050C2C22* + ID_OUI_FROM_DATABASE=Audient Ltd + +OUI:0050C2C23* + ID_OUI_FROM_DATABASE=Vidicon LLC + +OUI:0050C2C24* + ID_OUI_FROM_DATABASE=Qualnetics Corporation + +OUI:0050C2C26* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd + +OUI:0050C2C27* + ID_OUI_FROM_DATABASE=Qtechnology A/S + +OUI:0050C2C28* + ID_OUI_FROM_DATABASE=ELREHA GmbH + +OUI:0050C2C29* + ID_OUI_FROM_DATABASE=Newtel Engineering S.r.l. + +OUI:0050C2C2A* + ID_OUI_FROM_DATABASE=RealTime Systems Ltd + +OUI:0050C2C2B* + ID_OUI_FROM_DATABASE=Z-App Systems, Inc. + +OUI:0050C2C2C* + ID_OUI_FROM_DATABASE=bach-messtechnik gmbh + +OUI:0050C2C2D* + ID_OUI_FROM_DATABASE=Digitale Analoge COMponenten West Electronic Vertriebs GmbH + +OUI:0050C2C2E* + ID_OUI_FROM_DATABASE=DISMUNTEL SAL + +OUI:0050C2C2F* + ID_OUI_FROM_DATABASE=REFLEX CES + +OUI:0050C2C30* + ID_OUI_FROM_DATABASE=Wagner Group GmbH + +OUI:0050C2C31* + ID_OUI_FROM_DATABASE=4D Technology Corporation + +OUI:0050C2C32* + ID_OUI_FROM_DATABASE=Procon Electronics + +OUI:0050C2C34* + ID_OUI_FROM_DATABASE=Kyuhen + +OUI:0050C2C35* + ID_OUI_FROM_DATABASE=Insitu, Inc. + +OUI:0050C2C36* + ID_OUI_FROM_DATABASE=SET GmbH + +OUI:0050C2C37* + ID_OUI_FROM_DATABASE=B.E.A.R. Solutions (Australasia) Pty, Ltd + +OUI:0050C2C38* + ID_OUI_FROM_DATABASE=Computer Automation Technology Inc + +OUI:0050C2C39* + ID_OUI_FROM_DATABASE=SECAD SA + +OUI:0050C2C3A* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2C3B* + ID_OUI_FROM_DATABASE=ELEKTRO-AUTOMATIK GmbH & Co. KG + +OUI:0050C2C3C* + ID_OUI_FROM_DATABASE=ELSIST S.r.l. + +OUI:0050C2C3D* + ID_OUI_FROM_DATABASE=PLA ELECTRO APPLIANCES PVT. LTD. + +OUI:0050C2C3E* + ID_OUI_FROM_DATABASE=Sysacom + +OUI:0050C2C3F* + ID_OUI_FROM_DATABASE=ANXeBusiness Corporation + +OUI:0050C2C40* + ID_OUI_FROM_DATABASE=BAE Systems Bofors AB + +OUI:0050C2C41* + ID_OUI_FROM_DATABASE=COMPRION GmbH + +OUI:0050C2C42* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2C43* + ID_OUI_FROM_DATABASE=Cammegh Limited + +OUI:0050C2C44* + ID_OUI_FROM_DATABASE=Beijing Zhongherongzhi Elec.&Tech.Co.,Ltd. + +OUI:0050C2C45* + ID_OUI_FROM_DATABASE=Galvamat & Unican Technologies SA + +OUI:0050C2C46* + ID_OUI_FROM_DATABASE=QNE GmbH & Co. KG + +OUI:0050C2C47* + ID_OUI_FROM_DATABASE=Weltek Technologies Co. Ltd. + +OUI:0050C2C48* + ID_OUI_FROM_DATABASE=Cytek Media Systems, INC. + +OUI:0050C2C49* + ID_OUI_FROM_DATABASE=Elektronic Thoma GmbH + +OUI:0050C2C4A* + ID_OUI_FROM_DATABASE=Herrick Technology Laboratories, Inc. + +OUI:0050C2C4B* + ID_OUI_FROM_DATABASE=R.V.R. elettronica s.p.a. + +OUI:0050C2C4C* + ID_OUI_FROM_DATABASE=Lancier Monitoring GmbH + +OUI:0050C2C4D* + ID_OUI_FROM_DATABASE=Industrial Automation Systems + +OUI:0050C2C4E* + ID_OUI_FROM_DATABASE=Elaso AG + +OUI:0050C2C4F* + ID_OUI_FROM_DATABASE=Powersense A/S + +OUI:0050C2C50* + ID_OUI_FROM_DATABASE=Beceem Communications, Inc. + +OUI:0050C2C51* + ID_OUI_FROM_DATABASE=InForce Computing, Inc. + +OUI:0050C2C52* + ID_OUI_FROM_DATABASE=Smartfield, Inc. + +OUI:0050C2C53* + ID_OUI_FROM_DATABASE=Eilersen Electric A/S + +OUI:0050C2C54* + ID_OUI_FROM_DATABASE=HPC Platform + +OUI:0050C2C55* + ID_OUI_FROM_DATABASE=Watterott electronic + +OUI:0050C2C56* + ID_OUI_FROM_DATABASE=Spirent Communications + +OUI:0050C2C57* + ID_OUI_FROM_DATABASE=High Speed Design, Inc. + +OUI:0050C2C58* + ID_OUI_FROM_DATABASE=Foerster-Technik GmbH + +OUI:0050C2C59* + ID_OUI_FROM_DATABASE=SKD System AB + +OUI:0050C2C5A* + ID_OUI_FROM_DATABASE=Commotive A/S + +OUI:0050C2C5B* + ID_OUI_FROM_DATABASE=MICRO TECHNICA + +OUI:0050C2C5C* + ID_OUI_FROM_DATABASE=WAVECOM ELEKTRONIK AG + +OUI:0050C2C5D* + ID_OUI_FROM_DATABASE=SweMet AB + +OUI:0050C2C5E* + ID_OUI_FROM_DATABASE=CellPlus technologies, Inc. + +OUI:0050C2C5F* + ID_OUI_FROM_DATABASE=Icon Time Systems + +OUI:0050C2C60* + ID_OUI_FROM_DATABASE=Integration Technologies Limited + +OUI:0050C2C61* + ID_OUI_FROM_DATABASE=HaiVision Systems Incorporated + +OUI:0050C2C62* + ID_OUI_FROM_DATABASE=Zeus Systems Private Limited + +OUI:0050C2C63* + ID_OUI_FROM_DATABASE=Potter Electric Signal Company + +OUI:0050C2C64* + ID_OUI_FROM_DATABASE=Pal Software Service Co.,Ltd. + +OUI:0050C2C65* + ID_OUI_FROM_DATABASE=Micro I/O Servicos de Electronica, Lda + +OUI:0050C2C66* + ID_OUI_FROM_DATABASE=KS Beschallungstechnik GmbH + +OUI:0050C2C67* + ID_OUI_FROM_DATABASE=Practical Control Ltd + +OUI:0050C2C68* + ID_OUI_FROM_DATABASE=Broadsoft PacketSmart, Inc. + +OUI:0050C2C69* + ID_OUI_FROM_DATABASE=REBO CO.,LTD. + +OUI:0050C2C6A* + ID_OUI_FROM_DATABASE=ELECTRONICA KELD + +OUI:0050C2C6B* + ID_OUI_FROM_DATABASE=SiGarden Sp z o.o. + +OUI:0050C2C6C* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C2C6D* + ID_OUI_FROM_DATABASE=Deansoft CO., Ltd. + +OUI:0050C2C6E* + ID_OUI_FROM_DATABASE=TBS Holding AG + +OUI:0050C2C6F* + ID_OUI_FROM_DATABASE=MSB Elektronik und Geraetebau GmbH + +OUI:0050C2C70* + ID_OUI_FROM_DATABASE=Wilke Technology GmbH + +OUI:0050C2C71* + ID_OUI_FROM_DATABASE=Sequoia Technology Group Ltd + +OUI:0050C2C72* + ID_OUI_FROM_DATABASE=Quail + +OUI:0050C2C73* + ID_OUI_FROM_DATABASE=Industry Controls, Inc. + +OUI:0050C2C74* + ID_OUI_FROM_DATABASE=Wapice Ltd. + +OUI:0050C2C75* + ID_OUI_FROM_DATABASE=Rovsing A/S + +OUI:0050C2C76* + ID_OUI_FROM_DATABASE=GridManager A/S + +OUI:0050C2C77* + ID_OUI_FROM_DATABASE=AIM Co.,Ltd + +OUI:0050C2C78* + ID_OUI_FROM_DATABASE=9Solutions Oy + +OUI:0050C2C79* + ID_OUI_FROM_DATABASE=CODESYSTEM Co.,Ltd + +OUI:0050C2C7A* + ID_OUI_FROM_DATABASE=Protonic Holland + +OUI:0050C2C7B* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:0050C2C7C* + ID_OUI_FROM_DATABASE=Scienlab Electronic Systems GmbH + +OUI:0050C2C7D* + ID_OUI_FROM_DATABASE=TAE Antriebstechnik GmbH + +OUI:0050C2C7E* + ID_OUI_FROM_DATABASE=Buerkert Werke GmbH + +OUI:0050C2C7F* + ID_OUI_FROM_DATABASE=Kinects Solutions Inc + +OUI:0050C2C80* + ID_OUI_FROM_DATABASE=Reko-vek + +OUI:0050C2C81* + ID_OUI_FROM_DATABASE=Odyssee Systemes SAS + +OUI:0050C2C82* + ID_OUI_FROM_DATABASE=Kyosha Industries + +OUI:0050C2C83* + ID_OUI_FROM_DATABASE=Gronic Systems GmbH + +OUI:0050C2C84* + ID_OUI_FROM_DATABASE=DOMIS + +OUI:0050C2C85* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2C86* + ID_OUI_FROM_DATABASE=Bruckner & Jarosch Ingenieurgesellschaft mbH + +OUI:0050C2C87* + ID_OUI_FROM_DATABASE=LECO Corporation + +OUI:0050C2C88* + ID_OUI_FROM_DATABASE=CSI Controles e Sistemas Industriais Ltda. + +OUI:0050C2C89* + ID_OUI_FROM_DATABASE=Creative Micro Design + +OUI:0050C2C8A* + ID_OUI_FROM_DATABASE=Automated Media Services, Inc. + +OUI:0050C2C8B* + ID_OUI_FROM_DATABASE=OCAS AS + +OUI:0050C2C8C* + ID_OUI_FROM_DATABASE=Lanmark Controls Inc. + +OUI:0050C2C8D* + ID_OUI_FROM_DATABASE=Emergency Message Controls LLC + +OUI:0050C2C8E* + ID_OUI_FROM_DATABASE=SDD ITG + +OUI:0050C2C8F* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2C90* + ID_OUI_FROM_DATABASE=REALD + +OUI:0050C2C91* + ID_OUI_FROM_DATABASE=Media Technologies Ltd. + +OUI:0050C2C92* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2C93* + ID_OUI_FROM_DATABASE=SENSAIR Pty Ltd + +OUI:0050C2C94* + ID_OUI_FROM_DATABASE=ISIS ENGINEERING, S.A. + +OUI:0050C2C95* + ID_OUI_FROM_DATABASE=IPSES S.r.l. + +OUI:0050C2C96* + ID_OUI_FROM_DATABASE=CyberCraft + +OUI:0050C2C97* + ID_OUI_FROM_DATABASE=MSTRONIC CO., LTD. + +OUI:0050C2C98* + ID_OUI_FROM_DATABASE=Criticare Systems, Inc + +OUI:0050C2C99* + ID_OUI_FROM_DATABASE=HJPC Corporation dba Pactron + +OUI:0050C2C9A* + ID_OUI_FROM_DATABASE=PACOMP Sp. z o.o. + +OUI:0050C2C9B* + ID_OUI_FROM_DATABASE=Sm electronic co. + +OUI:0050C2C9C* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2C9D* + ID_OUI_FROM_DATABASE=Radius Sweden AB + +OUI:0050C2C9E* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2C9F* + ID_OUI_FROM_DATABASE=xxter b.v. + +OUI:0050C2CA0* + ID_OUI_FROM_DATABASE=Kiefer technic GmbH + +OUI:0050C2CA1* + ID_OUI_FROM_DATABASE=Wayne Kerr Electronics + +OUI:0050C2CA2* + ID_OUI_FROM_DATABASE=The Logical Company + +OUI:0050C2CA3* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2CA4* + ID_OUI_FROM_DATABASE=Vox Technologies + +OUI:0050C2CA5* + ID_OUI_FROM_DATABASE=YOKOWO CO.,LTD + +OUI:0050C2CA6* + ID_OUI_FROM_DATABASE=Vidisys GmbH + +OUI:0050C2CA7* + ID_OUI_FROM_DATABASE=Thermo Fisher Scientific + +OUI:0050C2CA8* + ID_OUI_FROM_DATABASE=Systems With Intelligence Inc. + +OUI:0050C2CA9* + ID_OUI_FROM_DATABASE=Intelligent Devices + +OUI:0050C2CAA* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2CAB* + ID_OUI_FROM_DATABASE=SAE IT-systems GmbH & Co. KG + +OUI:0050C2CAC* + ID_OUI_FROM_DATABASE=PURVIS Systems Incorporated + +OUI:0050C2CAD* + ID_OUI_FROM_DATABASE=Pacific Coast Engineering + +OUI:0050C2CAE* + ID_OUI_FROM_DATABASE=Campbell Scientific Canada Corp. + +OUI:0050C2CAF* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2CB0* + ID_OUI_FROM_DATABASE=Konsmetal S.A. + +OUI:0050C2CB1* + ID_OUI_FROM_DATABASE=ZK Celltest Inc + +OUI:0050C2CB2* + ID_OUI_FROM_DATABASE=Moravian Instruments + +OUI:0050C2CB3* + ID_OUI_FROM_DATABASE=Deuta-Werke GmbH + +OUI:0050C2CB4* + ID_OUI_FROM_DATABASE=GEA Farm Technologies GmbH + +OUI:0050C2CB6* + ID_OUI_FROM_DATABASE=Krontek Pty Ltd + +OUI:0050C2CB7* + ID_OUI_FROM_DATABASE=inotech GmbH + +OUI:0050C2CB8* + ID_OUI_FROM_DATABASE=Raith GmbH + +OUI:0050C2CB9* + ID_OUI_FROM_DATABASE=Micro Technic A/S + +OUI:0050C2CBA* + ID_OUI_FROM_DATABASE=DELTA TAU DATA SYSTEMS + +OUI:0050C2CBB* + ID_OUI_FROM_DATABASE=Coptonix GmbH + +OUI:0050C2CBC* + ID_OUI_FROM_DATABASE=CP ELETRONICA SA + +OUI:0050C2CBD* + ID_OUI_FROM_DATABASE=Hi Tech Electronics Ltd + +OUI:0050C2CBE* + ID_OUI_FROM_DATABASE=CODE BLUE CORPORATION + +OUI:0050C2CBF* + ID_OUI_FROM_DATABASE=Megacon AB + +OUI:0050C2CC0* + ID_OUI_FROM_DATABASE=World Time Solutions Limited + +OUI:0050C2CC1* + ID_OUI_FROM_DATABASE=Level 3 Communications + +OUI:0050C2CC2* + ID_OUI_FROM_DATABASE=ConectaIP Tecnologia S.L. + +OUI:0050C2CC3* + ID_OUI_FROM_DATABASE=viscount systems inc. + +OUI:0050C2CC4* + ID_OUI_FROM_DATABASE=General Dynamics C4S + +OUI:0050C2CC5* + ID_OUI_FROM_DATABASE=Tecnovum AG + +OUI:0050C2CC6* + ID_OUI_FROM_DATABASE=KDT + +OUI:0050C2CC7* + ID_OUI_FROM_DATABASE=TOPROOT Technology Corp. Ltd., + +OUI:0050C2CC9* + ID_OUI_FROM_DATABASE=Promess GmbH + +OUI:0050C2CCA* + ID_OUI_FROM_DATABASE=SANMINA SHENZHEN + +OUI:0050C2CCB* + ID_OUI_FROM_DATABASE=CaptiveAire Systems Inc. + +OUI:0050C2CCC* + ID_OUI_FROM_DATABASE=Smartech-technology + +OUI:0050C2CCD* + ID_OUI_FROM_DATABASE=FUJI DATA SYSTEM Co.,Ltd. + +OUI:0050C2CCE* + ID_OUI_FROM_DATABASE=Mac-Gray Corporation + +OUI:0050C2CCF* + ID_OUI_FROM_DATABASE=TASK SISTEMAS DE COMPUTACAO LTDA + +OUI:0050C2CD0* + ID_OUI_FROM_DATABASE=MME Mueller Mikroelektronik + +OUI:0050C2CD1* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2CD2* + ID_OUI_FROM_DATABASE=SIM2 Multimedia S.p.A. + +OUI:0050C2CD3* + ID_OUI_FROM_DATABASE=Covidence A/S + +OUI:0050C2CD4* + ID_OUI_FROM_DATABASE=SCHRAML GmbH + +OUI:0050C2CD5* + ID_OUI_FROM_DATABASE=Arcos Technologies Ltd. + +OUI:0050C2CD6* + ID_OUI_FROM_DATABASE=Arktan Systems + +OUI:0050C2CD7* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2CD8* + ID_OUI_FROM_DATABASE=IT-IS International Ltd. + +OUI:0050C2CD9* + ID_OUI_FROM_DATABASE=NDC Infrared Engineering, Inc. + +OUI:0050C2CDA* + ID_OUI_FROM_DATABASE=taskit GmbH + +OUI:0050C2CDB* + ID_OUI_FROM_DATABASE=RUTTER INC + +OUI:0050C2CDC* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C2CDD* + ID_OUI_FROM_DATABASE=K.C.C. SHOKAI LIMITED + +OUI:0050C2CDE* + ID_OUI_FROM_DATABASE=Axotec Technologies GmbH + +OUI:0050C2CDF* + ID_OUI_FROM_DATABASE=CoreEL TEchnologies (I) Pvt Ltd + +OUI:0050C2CE0* + ID_OUI_FROM_DATABASE=Industrial Control Links, Inc. + +OUI:0050C2CE1* + ID_OUI_FROM_DATABASE=Satellink Inc. + +OUI:0050C2CE2* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2CE3* + ID_OUI_FROM_DATABASE=Industrial Automatics Design Bureau + +OUI:0050C2CE4* + ID_OUI_FROM_DATABASE=TEKTRONIK + +OUI:0050C2CE5* + ID_OUI_FROM_DATABASE=Maretron, LLP + +OUI:0050C2CE6* + ID_OUI_FROM_DATABASE=APLICA TECHNOLOGIES + +OUI:0050C2CE7* + ID_OUI_FROM_DATABASE=Echola Systems + +OUI:0050C2CE8* + ID_OUI_FROM_DATABASE=Thomas & Betts + +OUI:0050C2CEA* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2CEB* + ID_OUI_FROM_DATABASE=Toyon Research Corporation + +OUI:0050C2CEC* + ID_OUI_FROM_DATABASE=Erhardt+Leimer GmbH + +OUI:0050C2CED* + ID_OUI_FROM_DATABASE=AeroMechanical Services Ltd, FLYHT + +OUI:0050C2CEE* + ID_OUI_FROM_DATABASE=EMBED-IT OG + +OUI:0050C2CEF* + ID_OUI_FROM_DATABASE=Lupatecnologia e Sistemas Ltda + +OUI:0050C2CF0* + ID_OUI_FROM_DATABASE=Inviso B.V. + +OUI:0050C2CF1* + ID_OUI_FROM_DATABASE=TelGaAs, Inc. + +OUI:0050C2CF2* + ID_OUI_FROM_DATABASE=Weiss Robotics GmbH & Co. KG + +OUI:0050C2CF3* + ID_OUI_FROM_DATABASE=Daiken Automacao Ltda + +OUI:0050C2CF4* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:0050C2CF5* + ID_OUI_FROM_DATABASE=AirCell Inc. + +OUI:0050C2CF6* + ID_OUI_FROM_DATABASE=Epec Oy + +OUI:0050C2CF7* + ID_OUI_FROM_DATABASE=Armour Home Electronics LTD + +OUI:0050C2CF8* + ID_OUI_FROM_DATABASE=beks Kommunikacios Technika kft + +OUI:0050C2CF9* + ID_OUI_FROM_DATABASE=Elbit Systems of America + +OUI:0050C2CFA* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2CFB* + ID_OUI_FROM_DATABASE=New Embedded Technology + +OUI:0050C2CFC* + ID_OUI_FROM_DATABASE=Tritium Pty Ltd + +OUI:0050C2CFD* + ID_OUI_FROM_DATABASE=AIRFOLC,INC. + +OUI:0050C2CFE* + ID_OUI_FROM_DATABASE=Techleader + +OUI:0050C2CFF* + ID_OUI_FROM_DATABASE=Infrasafe, Inc. + +OUI:0050C2D00* + ID_OUI_FROM_DATABASE=Bodensee Gravitymeter Geosystem GmbH + +OUI:0050C2D01* + ID_OUI_FROM_DATABASE=Aanderaa Data Instruments + +OUI:0050C2D02* + ID_OUI_FROM_DATABASE=SURVALENT TECHNOLOGY CORP + +OUI:0050C2D03* + ID_OUI_FROM_DATABASE=Peekel Instruments B.V. + +OUI:0050C2D04* + ID_OUI_FROM_DATABASE=Tehama Wireless + +OUI:0050C2D06* + ID_OUI_FROM_DATABASE=nCk Research LLC + +OUI:0050C2D07* + ID_OUI_FROM_DATABASE=IAF GmbH + +OUI:0050C2D08* + ID_OUI_FROM_DATABASE=Reimesch Kommunikationssysteme GmbH + +OUI:0050C2D09* + ID_OUI_FROM_DATABASE=Guardtec, Inc. + +OUI:0050C2D0A* + ID_OUI_FROM_DATABASE=Airpoint Co., Ltd. + +OUI:0050C2D0B* + ID_OUI_FROM_DATABASE=CODACO ELECTRONIC s.r.o. + +OUI:0050C2D0C* + ID_OUI_FROM_DATABASE=JVL Industri Elektronik + +OUI:0050C2D0D* + ID_OUI_FROM_DATABASE=DECA Card Engineering GmbH + +OUI:0050C2D0E* + ID_OUI_FROM_DATABASE=Weinert Engineering GmbH + +OUI:0050C2D0F* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2D10* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Ltd. + +OUI:0050C2D11* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2D12* + ID_OUI_FROM_DATABASE=Tokyo Weld Co.,Ltd. + +OUI:0050C2D13* + ID_OUI_FROM_DATABASE=GUNMA ELECTRONICS CO LTD + +OUI:0050C2D14* + ID_OUI_FROM_DATABASE=SAET I.S. + +OUI:0050C2D15* + ID_OUI_FROM_DATABASE=MSR-Office GmbH + +OUI:0050C2D16* + ID_OUI_FROM_DATABASE=Imricor Medical Systems, Inc. + +OUI:0050C2D17* + ID_OUI_FROM_DATABASE=CUE, a.s. + +OUI:0050C2D18* + ID_OUI_FROM_DATABASE=Glyn GmbH & Co.KG + +OUI:0050C2D19* + ID_OUI_FROM_DATABASE=Applied Medical Technologies, Inc DBA AirClean Systems + +OUI:0050C2D1A* + ID_OUI_FROM_DATABASE=GILLAM-FEI S.A. + +OUI:0050C2D1B* + ID_OUI_FROM_DATABASE=TECHKON GmbH + +OUI:0050C2D1C* + ID_OUI_FROM_DATABASE=Recon Dynamics, LLC + +OUI:0050C2D1D* + ID_OUI_FROM_DATABASE=Moco Media Pty Ltd + +OUI:0050C2D1E* + ID_OUI_FROM_DATABASE=Tobila Systems, Inc. + +OUI:0050C2D1F* + ID_OUI_FROM_DATABASE=Olympus NDT Canada Inc. + +OUI:0050C2D20* + ID_OUI_FROM_DATABASE=7+ Kft + +OUI:0050C2D21* + ID_OUI_FROM_DATABASE=Innovative Circuit Technology + +OUI:0050C2D22* + ID_OUI_FROM_DATABASE=eMDee Technology, Inc. + +OUI:0050C2D23* + ID_OUI_FROM_DATABASE=Bluestone Technology GmbH + +OUI:0050C2D24* + ID_OUI_FROM_DATABASE=Expro North Sea + +OUI:0050C2D25* + ID_OUI_FROM_DATABASE=VAF Instruments BV + +OUI:0050C2D26* + ID_OUI_FROM_DATABASE=RCH GROUP + +OUI:0050C2D27* + ID_OUI_FROM_DATABASE=Fr.Sauter AG + +OUI:0050C2D28* + ID_OUI_FROM_DATABASE=Digitale Analoge COMponenten West Electronic Vertriebs GmbH + +OUI:0050C2D29* + ID_OUI_FROM_DATABASE=Axible Technologies + +OUI:0050C2D2A* + ID_OUI_FROM_DATABASE=Millennium Electronics Pty.Ltd. + +OUI:0050C2D2B* + ID_OUI_FROM_DATABASE=Video Tech Laboratories, Inc. + +OUI:0050C2D2C* + ID_OUI_FROM_DATABASE=Schneider Electric Motion USA + +OUI:0050C2D2D* + ID_OUI_FROM_DATABASE=CADI SCIENTIFIC PTE LTD + +OUI:0050C2D2E* + ID_OUI_FROM_DATABASE=RS Gesellschaft fur Informationstechnik mbH & Co KG + +OUI:0050C2D2F* + ID_OUI_FROM_DATABASE=Key Systems, Inc. + +OUI:0050C2D30* + ID_OUI_FROM_DATABASE=ACTIV Financial Systems, Inc. + +OUI:0050C2D31* + ID_OUI_FROM_DATABASE=UNGAVA Technologies Inc. + +OUI:0050C2D32* + ID_OUI_FROM_DATABASE=RealTime Systems Ltd + +OUI:0050C2D33* + ID_OUI_FROM_DATABASE=Maddalena S.p.A + +OUI:0050C2D34* + ID_OUI_FROM_DATABASE=GAON TECH corp. + +OUI:0050C2D35* + ID_OUI_FROM_DATABASE=UG Systems GmbH & Co. KG + +OUI:0050C2D36* + ID_OUI_FROM_DATABASE=Enatel Limited + +OUI:0050C2D37* + ID_OUI_FROM_DATABASE=LJT & Associates, Inc. + +OUI:0050C2D38* + ID_OUI_FROM_DATABASE=Kyowa Electronics Co.,Ltd. + +OUI:0050C2D39* + ID_OUI_FROM_DATABASE=Apex NV + +OUI:0050C2D3A* + ID_OUI_FROM_DATABASE=WellSense Technologies + +OUI:0050C2D3B* + ID_OUI_FROM_DATABASE=Gitsn Inc. + +OUI:0050C2D3C* + ID_OUI_FROM_DATABASE=ASSYSTEM France + +OUI:0050C2D3D* + ID_OUI_FROM_DATABASE=Tellabs Operations Inc. + +OUI:0050C2D3E* + ID_OUI_FROM_DATABASE=Synatec Electronic GmbH + +OUI:0050C2D3F* + ID_OUI_FROM_DATABASE=CSS, LLC + +OUI:0050C2D40* + ID_OUI_FROM_DATABASE=demmel products + +OUI:0050C2D41* + ID_OUI_FROM_DATABASE=AREA ENERGY, INC. + +OUI:0050C2D42* + ID_OUI_FROM_DATABASE=Hagenuk KMT GmbH + +OUI:0050C2D43* + ID_OUI_FROM_DATABASE=DSP4YOU Ltd + +OUI:0050C2D44* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2D45* + ID_OUI_FROM_DATABASE=Technagon GmbH + +OUI:0050C2D46* + ID_OUI_FROM_DATABASE=Thales Nederland BV + +OUI:0050C2D47* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2D48* + ID_OUI_FROM_DATABASE=Watermark Estate Management Services, LLC + +OUI:0050C2D49* + ID_OUI_FROM_DATABASE=Smith Meter, Inc + +OUI:0050C2D4A* + ID_OUI_FROM_DATABASE=ATH system + +OUI:0050C2D4B* + ID_OUI_FROM_DATABASE=Indra Australia + +OUI:0050C2D4C* + ID_OUI_FROM_DATABASE=DALOG Diagnosesysteme GmbH + +OUI:0050C2D4D* + ID_OUI_FROM_DATABASE=Yardney Technical Products Inc. + +OUI:0050C2D4E* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2D4F* + ID_OUI_FROM_DATABASE=SECOM GmbH + +OUI:0050C2D50* + ID_OUI_FROM_DATABASE=Solbrig Electronics, Inc. + +OUI:0050C2D51* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:0050C2D52* + ID_OUI_FROM_DATABASE=F+D Feinwerk- und Drucktechnik GmbH + +OUI:0050C2D53* + ID_OUI_FROM_DATABASE=Telemerkki Oy + +OUI:0050C2D54* + ID_OUI_FROM_DATABASE=ABtrack s.r.l. + +OUI:0050C2D55* + ID_OUI_FROM_DATABASE=Sterna Security + +OUI:0050C2D56* + ID_OUI_FROM_DATABASE=SELEX Communications Limited + +OUI:0050C2D57* + ID_OUI_FROM_DATABASE=Hijikata Denki Corp. + +OUI:0050C2D58* + ID_OUI_FROM_DATABASE=NIK-ELEKTRONIKA Ltd + +OUI:0050C2D59* + ID_OUI_FROM_DATABASE=BUANCO SYSTEM A/S + +OUI:0050C2D5A* + ID_OUI_FROM_DATABASE=Embedded Monitoring Systems Ltd. + +OUI:0050C2D5B* + ID_OUI_FROM_DATABASE=Infinition Inc. + +OUI:0050C2D5C* + ID_OUI_FROM_DATABASE=Ibetor S.L. + +OUI:0050C2D5D* + ID_OUI_FROM_DATABASE=GLOBALCOM ENGINEERING SRL + +OUI:0050C2D5E* + ID_OUI_FROM_DATABASE=infinitec co., ltd. + +OUI:0050C2D5F* + ID_OUI_FROM_DATABASE=Embedded Solution Co., Ltd. + +OUI:0050C2D60* + ID_OUI_FROM_DATABASE=Nihon Kessho Koogaku Co., Ltd. + +OUI:0050C2D61* + ID_OUI_FROM_DATABASE=system2 GmbH + +OUI:0050C2D62* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2D63* + ID_OUI_FROM_DATABASE=DATAREGIS S.A. + +OUI:0050C2D64* + ID_OUI_FROM_DATABASE=TV1 GmbH + +OUI:0050C2D65* + ID_OUI_FROM_DATABASE=TX Technology Corp + +OUI:0050C2D66* + ID_OUI_FROM_DATABASE=Uvax Concepts + +OUI:0050C2D67* + ID_OUI_FROM_DATABASE=KLING & FREITAG GmbH + +OUI:0050C2D68* + ID_OUI_FROM_DATABASE=HiSpeed Data, Inc. + +OUI:0050C2D69* + ID_OUI_FROM_DATABASE=GHL Systems Bhd + +OUI:0050C2D6A* + ID_OUI_FROM_DATABASE=A&T Corporation, Electrics Group , LAS R&D Unit, + +OUI:0050C2D6B* + ID_OUI_FROM_DATABASE=Nemec Automation + +OUI:0050C2D6C* + ID_OUI_FROM_DATABASE=ALPHA Corporation + +OUI:0050C2D6D* + ID_OUI_FROM_DATABASE=Pro-Digital Industria Eletronica + +OUI:0050C2D6E* + ID_OUI_FROM_DATABASE=BC Illumination, Inc. + +OUI:0050C2D6F* + ID_OUI_FROM_DATABASE=Imtron Messtechnik GmbH + +OUI:0050C2D70* + ID_OUI_FROM_DATABASE=C. Rob. Hammerstein GmbH & Co. KG + +OUI:0050C2D71* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2D72* + ID_OUI_FROM_DATABASE=Scale-Tron, Inc. + +OUI:0050C2D73* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2D74* + ID_OUI_FROM_DATABASE=Computech International + +OUI:0050C2D75* + ID_OUI_FROM_DATABASE=Collectric AB + +OUI:0050C2D76* + ID_OUI_FROM_DATABASE=Telvent + +OUI:0050C2D77* + ID_OUI_FROM_DATABASE=Fr.SauterAG + +OUI:0050C2D78* + ID_OUI_FROM_DATABASE=P4Q Electronics + +OUI:0050C2D79* + ID_OUI_FROM_DATABASE=DSI RF Systems, Inc. + +OUI:0050C2D7A* + ID_OUI_FROM_DATABASE=Transbit Sp. z o.o. + +OUI:0050C2D7B* + ID_OUI_FROM_DATABASE=OWITA GmbH + +OUI:0050C2D7C* + ID_OUI_FROM_DATABASE=Microcubs Systems Pvt Ltd + +OUI:0050C2D7D* + ID_OUI_FROM_DATABASE=Voltech Instruments + +OUI:0050C2D7E* + ID_OUI_FROM_DATABASE=LYNX Technik AG + +OUI:0050C2D7F* + ID_OUI_FROM_DATABASE=HMI Technologies + +OUI:0050C2D80* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2D81* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:0050C2D82* + ID_OUI_FROM_DATABASE=Audio Authority Corp + +OUI:0050C2D83* + ID_OUI_FROM_DATABASE=Blankom + +OUI:0050C2D84* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C2D85* + ID_OUI_FROM_DATABASE=VITEC + +OUI:0050C2D86* + ID_OUI_FROM_DATABASE=ECOMM ERA + +OUI:0050C2D87* + ID_OUI_FROM_DATABASE=Electrolight Shivuk (1994) Ltd. + +OUI:0050C2D88* + ID_OUI_FROM_DATABASE=T+A elektroakustik GmbH & Co KG + +OUI:0050C2D89* + ID_OUI_FROM_DATABASE=Visual Telecommunication Network, Inc + +OUI:0050C2D8A* + ID_OUI_FROM_DATABASE=OptoLink Industria e Comercio Ltda + +OUI:0050C2D8B* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2D8C* + ID_OUI_FROM_DATABASE=iRphotonics + +OUI:0050C2D8D* + ID_OUI_FROM_DATABASE=CS-Instruments + +OUI:0050C2D8E* + ID_OUI_FROM_DATABASE=LSD Science&Technology Co.,Ltd. + +OUI:0050C2D8F* + ID_OUI_FROM_DATABASE=Syes srl + +OUI:0050C2D90* + ID_OUI_FROM_DATABASE=Dumps Electronic + +OUI:0050C2D91* + ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX + +OUI:0050C2D92* + ID_OUI_FROM_DATABASE=Manz + +OUI:0050C2D93* + ID_OUI_FROM_DATABASE=Axlon AB + +OUI:0050C2D94* + ID_OUI_FROM_DATABASE=Software Effect Enterprises, Inc + +OUI:0050C2D95* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:0050C2D96* + ID_OUI_FROM_DATABASE=CONTEC GmbH + +OUI:0050C2D97* + ID_OUI_FROM_DATABASE=ERS electronic GmbH + +OUI:0050C2D98* + ID_OUI_FROM_DATABASE=Rong Shun Xuan Corp. + +OUI:0050C2D99* + ID_OUI_FROM_DATABASE=T-Industry, s.r.o. + +OUI:0050C2D9A* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2D9B* + ID_OUI_FROM_DATABASE=Intuitive Surgical, Inc + +OUI:0050C2D9C* + ID_OUI_FROM_DATABASE=Gamber Johnson LLC + +OUI:0050C2D9D* + ID_OUI_FROM_DATABASE=Mistral Solutions Pvt. Ltd + +OUI:0050C2D9F* + ID_OUI_FROM_DATABASE=BitWise Controls + +OUI:0050C2DA0* + ID_OUI_FROM_DATABASE=Precision Remotes + +OUI:0050C2DA1* + ID_OUI_FROM_DATABASE=MangoDSP + +OUI:0050C2DA2* + ID_OUI_FROM_DATABASE=metraTec GmbH + +OUI:0050C2DA3* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:0050C2DA4* + ID_OUI_FROM_DATABASE=Deuta-Werke GmbH + +OUI:0050C2DA5* + ID_OUI_FROM_DATABASE=megatec electronic GmbH + +OUI:0050C2DA6* + ID_OUI_FROM_DATABASE=Manitowoc Ice + +OUI:0050C2DA7* + ID_OUI_FROM_DATABASE=Capton + +OUI:0050C2DA8* + ID_OUI_FROM_DATABASE=Sine Systems, Inc. + +OUI:0050C2DA9* + ID_OUI_FROM_DATABASE=Tieline Research Pty Ltd + +OUI:0050C2DAA* + ID_OUI_FROM_DATABASE=M & PAUL, INC + +OUI:0050C2DAB* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2DAC* + ID_OUI_FROM_DATABASE=RFL Electronics + +OUI:0050C2DAD* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2DAE* + ID_OUI_FROM_DATABASE=Spang Power Electronics + +OUI:0050C2DAF* + ID_OUI_FROM_DATABASE=eumig industrie-tv GmbH + +OUI:0050C2DB0* + ID_OUI_FROM_DATABASE=IMAGO Technologies GmbH + +OUI:0050C2DB1* + ID_OUI_FROM_DATABASE=RF Code, Inc + +OUI:0050C2DB2* + ID_OUI_FROM_DATABASE=SoftwareCannery + +OUI:0050C2DB3* + ID_OUI_FROM_DATABASE=LAUDA DR. R. WOBSER GMBH & CO. KG + +OUI:0050C2DB4* + ID_OUI_FROM_DATABASE=ZAO NPC "Kompjuternie Technologii" + +OUI:0050C2DB5* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2DB6* + ID_OUI_FROM_DATABASE=PROSOFT-SYSTEMS LTD + +OUI:0050C2DB7* + ID_OUI_FROM_DATABASE=SOREL GmbH Mikroelektronik + +OUI:0050C2DB8* + ID_OUI_FROM_DATABASE=Comsat VertriebsgmbH + +OUI:0050C2DB9* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2DBA* + ID_OUI_FROM_DATABASE=M.P. Electronics + +OUI:0050C2DBB* + ID_OUI_FROM_DATABASE=Esensors, Inc. + +OUI:0050C2DBC* + ID_OUI_FROM_DATABASE=Nantes Systems Private Limited + +OUI:0050C2DBD* + ID_OUI_FROM_DATABASE=Margento R&D + +OUI:0050C2DBE* + ID_OUI_FROM_DATABASE=WITHSYSTEM Co.,Ltd + +OUI:0050C2DBF* + ID_OUI_FROM_DATABASE=One-Nemoto Engineering Corporation + +OUI:0050C2DC0* + ID_OUI_FROM_DATABASE=Security Services Group (SSG) + +OUI:0050C2DC1* + ID_OUI_FROM_DATABASE=Acrux Technology Limited + +OUI:0050C2DC2* + ID_OUI_FROM_DATABASE=TESSERA TECHNOLOGY INC. + +OUI:0050C2DC3* + ID_OUI_FROM_DATABASE=ZED Ziegler Electronic Devices GmbH + +OUI:0050C2DC4* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:0050C2DC5* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2DC6* + ID_OUI_FROM_DATABASE=Fluid Components International + +OUI:0050C2DC7* + ID_OUI_FROM_DATABASE=AGT Holdings Limited + +OUI:0050C2DC8* + ID_OUI_FROM_DATABASE=T2M2 GmbH + +OUI:0050C2DC9* + ID_OUI_FROM_DATABASE=KinotonGmbH + +OUI:0050C2DCA* + ID_OUI_FROM_DATABASE=Tele Data Control + +OUI:0050C2DCB* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2DCC* + ID_OUI_FROM_DATABASE=Instrumentel Limited + +OUI:0050C2DCD* + ID_OUI_FROM_DATABASE=dilitronics GmbH + +OUI:0050C2DCE* + ID_OUI_FROM_DATABASE=Mecsel Oy + +OUI:0050C2DCF* + ID_OUI_FROM_DATABASE=MCS Engenharia ltda + +OUI:0050C2DD0* + ID_OUI_FROM_DATABASE=IDC Solutions Pty Ltd + +OUI:0050C2DD1* + ID_OUI_FROM_DATABASE=Brankamp GmbH + +OUI:0050C2DD2* + ID_OUI_FROM_DATABASE=Electronic Applications, Inc. + +OUI:0050C2DD3* + ID_OUI_FROM_DATABASE=Rohde & Schwarz Topex SA + +OUI:0050C2DD4* + ID_OUI_FROM_DATABASE=SYSTECH + +OUI:0050C2DD5* + ID_OUI_FROM_DATABASE=Friend Spring Industrial Co., Ltd. + +OUI:0050C2DD6* + ID_OUI_FROM_DATABASE=Transas Marine International AB + +OUI:0050C2DD7* + ID_OUI_FROM_DATABASE=Tornado Modular Systems + +OUI:0050C2DD8* + ID_OUI_FROM_DATABASE=Selex Systems Integration Inc + +OUI:0050C2DD9* + ID_OUI_FROM_DATABASE=Metraware + +OUI:0050C2DDA* + ID_OUI_FROM_DATABASE=rbz robot design s.l. + +OUI:0050C2DDB* + ID_OUI_FROM_DATABASE=LUCEO + +OUI:0050C2DDC* + ID_OUI_FROM_DATABASE=Vision & Control GmbH + +OUI:0050C2DDD* + ID_OUI_FROM_DATABASE=A&A GENERAL SRL + +OUI:0050C2DDE* + ID_OUI_FROM_DATABASE=DRS ITS + +OUI:0050C2DDF* + ID_OUI_FROM_DATABASE=Device GmbH + +OUI:0050C2DE0* + ID_OUI_FROM_DATABASE=INTERNET PROTOCOLO LOGICA SL + +OUI:0050C2DE1* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China) + +OUI:0050C2DE2* + ID_OUI_FROM_DATABASE=SEQUTEC INC + +OUI:0050C2DE3* + ID_OUI_FROM_DATABASE=Breakaway Systems LLC + +OUI:0050C2DE4* + ID_OUI_FROM_DATABASE=EGS Technologies Ltd + +OUI:0050C2DE5* + ID_OUI_FROM_DATABASE=Neets + +OUI:0050C2DE6* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2DE7* + ID_OUI_FROM_DATABASE=Elan Systems + +OUI:0050C2DE8* + ID_OUI_FROM_DATABASE=Visual Productions + +OUI:0050C2DE9* + ID_OUI_FROM_DATABASE=Dacom West GmbH + +OUI:0050C2DEA* + ID_OUI_FROM_DATABASE=Cerner Corporation + +OUI:0050C2DEB* + ID_OUI_FROM_DATABASE=Ruwisch & Kollegen GmbH + +OUI:0050C2DEC* + ID_OUI_FROM_DATABASE=VendNovation LLC + +OUI:0050C2DED* + ID_OUI_FROM_DATABASE=Lee Laser + +OUI:0050C2DEF* + ID_OUI_FROM_DATABASE=Powersense A/S + +OUI:0050C2DF0* + ID_OUI_FROM_DATABASE=Koncar Electrical Engineering Institute + +OUI:0050C2DF1* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2DF2* + ID_OUI_FROM_DATABASE=Ocean Sonics + +OUI:0050C2DF3* + ID_OUI_FROM_DATABASE=INSEVIS GmbH + +OUI:0050C2DF4* + ID_OUI_FROM_DATABASE=Potter Electric Signal + +OUI:0050C2DF5* + ID_OUI_FROM_DATABASE=EtherLight + +OUI:0050C2DF6* + ID_OUI_FROM_DATABASE=HINO ENGINEERING, INC + +OUI:0050C2DF7* + ID_OUI_FROM_DATABASE=Combilent + +OUI:0050C2DF8* + ID_OUI_FROM_DATABASE=Tommotek (WA) Pty Ltd. + +OUI:0050C2DF9* + ID_OUI_FROM_DATABASE=Jenny Science AG + +OUI:0050C2DFA* + ID_OUI_FROM_DATABASE=MAC Valves, Inc. + +OUI:0050C2DFB* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:0050C2DFC* + ID_OUI_FROM_DATABASE=I-Evo Ltd + +OUI:0050C2DFD* + ID_OUI_FROM_DATABASE=Wotbox ltd + +OUI:0050C2DFE* + ID_OUI_FROM_DATABASE=Xitek Design Limited + +OUI:0050C2DFF* + ID_OUI_FROM_DATABASE=TANTAL ELECTRONICA, SL + +OUI:0050C2E00* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2E01* + ID_OUI_FROM_DATABASE=Tyco Traffic & Transportation + +OUI:0050C2E02* + ID_OUI_FROM_DATABASE=Cleverscope + +OUI:0050C2E03* + ID_OUI_FROM_DATABASE=ICU Scandinavia Schweiz GmbH + +OUI:0050C2E04* + ID_OUI_FROM_DATABASE=Sec.Eng Systems Pty Ltd + +OUI:0050C2E05* + ID_OUI_FROM_DATABASE=NOCOSIUM + +OUI:0050C2E06* + ID_OUI_FROM_DATABASE=Ebner Electronic GmbH + +OUI:0050C2E07* + ID_OUI_FROM_DATABASE=Protagon Process Technologies GmbH + +OUI:0050C2E08* + ID_OUI_FROM_DATABASE=KST Technology + +OUI:0050C2E09* + ID_OUI_FROM_DATABASE=ATEME + +OUI:0050C2E0A* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2E0B* + ID_OUI_FROM_DATABASE=Seartech + +OUI:0050C2E0C* + ID_OUI_FROM_DATABASE=YOUHO ELECTRIC IND.,LTD. + +OUI:0050C2E0D* + ID_OUI_FROM_DATABASE=Unixmedia Srl + +OUI:0050C2E0E* + ID_OUI_FROM_DATABASE=PMAC JAPAN + +OUI:0050C2E0F* + ID_OUI_FROM_DATABASE=Trentino Systems + +OUI:0050C2E10* + ID_OUI_FROM_DATABASE=Radinetworks Co., Ltd + +OUI:0050C2E11* + ID_OUI_FROM_DATABASE=RF Neulink + +OUI:0050C2E12* + ID_OUI_FROM_DATABASE=Kago Electronics BV + +OUI:0050C2E13* + ID_OUI_FROM_DATABASE=Automation Assist Japan Company + +OUI:0050C2E14* + ID_OUI_FROM_DATABASE=Calixto Systems Pvt Ltd + +OUI:0050C2E15* + ID_OUI_FROM_DATABASE=IHI Scube Co.,Ltd + +OUI:0050C2E16* + ID_OUI_FROM_DATABASE=Jetstream Ltd. + +OUI:0050C2E17* + ID_OUI_FROM_DATABASE=Gall Tankdatensysteme GmbH + +OUI:0050C2E18* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd. + +OUI:0050C2E19* + ID_OUI_FROM_DATABASE=Zoe Medical + +OUI:0050C2E1A* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:0050C2E1B* + ID_OUI_FROM_DATABASE=Embedded Labs + +OUI:0050C2E1C* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2E1D* + ID_OUI_FROM_DATABASE=Holdline Tecnologia e Sistemas Ltda + +OUI:0050C2E1E* + ID_OUI_FROM_DATABASE=Lo-Q plc + +OUI:0050C2E1F* + ID_OUI_FROM_DATABASE=ELVEES + +OUI:0050C2E20* + ID_OUI_FROM_DATABASE=Divelbiss Corporation + +OUI:0050C2E21* + ID_OUI_FROM_DATABASE=Norwia AS + +OUI:0050C2E22* + ID_OUI_FROM_DATABASE=Michael Riedel Transformatorenbau GmbH + +OUI:0050C2E23* + ID_OUI_FROM_DATABASE=VITEC + +OUI:0050C2E24* + ID_OUI_FROM_DATABASE=DiTEST Fahrzeugdiagnose GmbH + +OUI:0050C2E25* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2E26* + ID_OUI_FROM_DATABASE=Cinetix s.r.l. + +OUI:0050C2E27* + ID_OUI_FROM_DATABASE=CONTROL SYSTEMS Srl + +OUI:0050C2E28* + ID_OUI_FROM_DATABASE=Teplovodokhran + +OUI:0050C2E29* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2E2A* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2E2B* + ID_OUI_FROM_DATABASE=Plant Integrity Limited + +OUI:0050C2E2C* + ID_OUI_FROM_DATABASE=EN ElectronicNetwork Hamburg GmbH + +OUI:0050C2E2D* + ID_OUI_FROM_DATABASE=Funkwerk IT Karlsfeld GmbH + +OUI:0050C2E2E* + ID_OUI_FROM_DATABASE=DS! Ingenieurbuero + +OUI:0050C2E2F* + ID_OUI_FROM_DATABASE=Beam Ltd + +OUI:0050C2E30* + ID_OUI_FROM_DATABASE=Goennheimer Elektronic GmbH + +OUI:0050C2E31* + ID_OUI_FROM_DATABASE=ENSIS Co., Ltd. + +OUI:0050C2E32* + ID_OUI_FROM_DATABASE=Oshoksh Corporation + +OUI:0050C2E33* + ID_OUI_FROM_DATABASE=Morita Technical Center Company + +OUI:0050C2E34* + ID_OUI_FROM_DATABASE=HGL Dynamics + +OUI:0050C2E35* + ID_OUI_FROM_DATABASE=Omnica Corporation + +OUI:0050C2E36* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2E37* + ID_OUI_FROM_DATABASE=FUJI DATA SYSTEM Co., Ltd + +OUI:0050C2E38* + ID_OUI_FROM_DATABASE=Aesir Copenhagen + +OUI:0050C2E39* + ID_OUI_FROM_DATABASE=Telemetrics Inc. + +OUI:0050C2E3B* + ID_OUI_FROM_DATABASE=Nanosolution Inc. + +OUI:0050C2E3C* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2E3D* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:0050C2E3E* + ID_OUI_FROM_DATABASE=Monnit Corp. + +OUI:0050C2E3F* + ID_OUI_FROM_DATABASE=VISITO S.R.L. + +OUI:0050C2E40* + ID_OUI_FROM_DATABASE=Ecrin Systems + +OUI:0050C2E41* + ID_OUI_FROM_DATABASE=Higeco S.r.l. + +OUI:0050C2E42* + ID_OUI_FROM_DATABASE=Wings for Media SL + +OUI:0050C2E43* + ID_OUI_FROM_DATABASE=Technica Engineering GmbH + +OUI:0050C2E44* + ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH + +OUI:0050C2E45* + ID_OUI_FROM_DATABASE=Stichting Sunrise + +OUI:0050C2E46* + ID_OUI_FROM_DATABASE=Industrea Mining Technology + +OUI:0050C2E47* + ID_OUI_FROM_DATABASE=ENIKA.CZ + +OUI:0050C2E48* + ID_OUI_FROM_DATABASE=ITW Reyflex North America + +OUI:0050C2E49* + ID_OUI_FROM_DATABASE=CTF TECHNOLOGIES DO BRASIL LTDA + +OUI:0050C2E4A* + ID_OUI_FROM_DATABASE=GHL Systems Bhd + +OUI:0050C2E4B* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2E4C* + ID_OUI_FROM_DATABASE=Applied Micro Electronics "AME" BV + +OUI:0050C2E4D* + ID_OUI_FROM_DATABASE=PCSC + +OUI:0050C2E4E* + ID_OUI_FROM_DATABASE=Institute For Information Industry + +OUI:0050C2E4F* + ID_OUI_FROM_DATABASE=Wine Technology Marlborough + +OUI:0050C2E50* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:0050C2E51* + ID_OUI_FROM_DATABASE=Motec Pty Ltd + +OUI:0050C2E52* + ID_OUI_FROM_DATABASE=Famas System S.p.A. + +OUI:0050C2E53* + ID_OUI_FROM_DATABASE=NEXT video systems Hard- and Software Development GmbH + +OUI:0050C2E54* + ID_OUI_FROM_DATABASE=Arcos Technologies LTD + +OUI:0050C2E55* + ID_OUI_FROM_DATABASE=TTi Ltd + +OUI:0050C2E56* + ID_OUI_FROM_DATABASE=RFENGINE CO., LTD. + +OUI:0050C2E57* + ID_OUI_FROM_DATABASE=EOLANE MONTCEAU + +OUI:0050C2E58* + ID_OUI_FROM_DATABASE=Agri-hitech LLC + +OUI:0050C2E59* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2E5A* + ID_OUI_FROM_DATABASE=FUTEC INC. + +OUI:0050C2E5B* + ID_OUI_FROM_DATABASE=CAIPO Automazione Industriale s.r.l. + +OUI:0050C2E5C* + ID_OUI_FROM_DATABASE=MCOPIA Co., Ltd + +OUI:0050C2E5D* + ID_OUI_FROM_DATABASE=T8 Ltd + +OUI:0050C2E5E* + ID_OUI_FROM_DATABASE=OREP + +OUI:0050C2E5F* + ID_OUI_FROM_DATABASE=Pantec Engineering AG + +OUI:0050C2E60* + ID_OUI_FROM_DATABASE=TAIYO SEIKI CO.,LTD. + +OUI:0050C2E61* + ID_OUI_FROM_DATABASE=Detech Electronics ApS + +OUI:0050C2E62* + ID_OUI_FROM_DATABASE=SAE IT-systems GmbH & Co. KG + +OUI:0050C2E63* + ID_OUI_FROM_DATABASE=Prima sistemi + +OUI:0050C2E64* + ID_OUI_FROM_DATABASE=Edgeware AB + +OUI:0050C2E65* + ID_OUI_FROM_DATABASE=IB Elektronik GmbH + +OUI:0050C2E66* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2E67* + ID_OUI_FROM_DATABASE=Critical Link, LLC + +OUI:0050C2E68* + ID_OUI_FROM_DATABASE=Kyoritsu Electric Corporation + +OUI:0050C2E69* + ID_OUI_FROM_DATABASE=Netmaker + +OUI:0050C2E6A* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2E6B* + ID_OUI_FROM_DATABASE=Sika Technology AG + +OUI:0050C2E6C* + ID_OUI_FROM_DATABASE=SAMSUNG Electronics Co.,Ltd.(LED Division) + +OUI:0050C2E6D* + ID_OUI_FROM_DATABASE=Allerta Inc + +OUI:0050C2E6E* + ID_OUI_FROM_DATABASE=Power-One Italia S.p.A + +OUI:0050C2E6F* + ID_OUI_FROM_DATABASE=Leyden Engineering + +OUI:0050C2E70* + ID_OUI_FROM_DATABASE=DORLET S.A. + +OUI:0050C2E71* + ID_OUI_FROM_DATABASE=traffic network solutions s.l + +OUI:0050C2E73* + ID_OUI_FROM_DATABASE=ACS Motion Control Ltd. + +OUI:0050C2E74* + ID_OUI_FROM_DATABASE=Will corp. + +OUI:0050C2E75* + ID_OUI_FROM_DATABASE=FSM AG + +OUI:0050C2E76* + ID_OUI_FROM_DATABASE=Embedded Solution Bank Co., Ltd. + +OUI:0050C2E77* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:0050C2E78* + ID_OUI_FROM_DATABASE=TASK SISTEMAS DE COMPUTACAO LTDA + +OUI:0050C2E79* + ID_OUI_FROM_DATABASE=MCS MICRONIC Computer Systeme GmbH + +OUI:0050C2E7A* + ID_OUI_FROM_DATABASE=Lightel + +OUI:0050C2E7B* + ID_OUI_FROM_DATABASE=ATOM GIKEN Co.,Ltd. + +OUI:0050C2E7C* + ID_OUI_FROM_DATABASE=sp controls, inc + +OUI:0050C2E7D* + ID_OUI_FROM_DATABASE=AEL Microsystems Limited + +OUI:0050C2E7E* + ID_OUI_FROM_DATABASE=Swareflex GmbH + +OUI:0050C2E7F* + ID_OUI_FROM_DATABASE=LS Control A/S + +OUI:0050C2E80* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2E81* + ID_OUI_FROM_DATABASE=Adaptive Technologies, Inc. + +OUI:0050C2E82* + ID_OUI_FROM_DATABASE=Xplore Technologies Corp + +OUI:0050C2E83* + ID_OUI_FROM_DATABASE=Witree Co.,Ltd + +OUI:0050C2E84* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd. + +OUI:0050C2E85* + ID_OUI_FROM_DATABASE=Cosmo Life Co.,Ltd + +OUI:0050C2E86* + ID_OUI_FROM_DATABASE=Multisuns Corporation + +OUI:0050C2E87* + ID_OUI_FROM_DATABASE=Lamson Safes & Security + +OUI:0050C2E88* + ID_OUI_FROM_DATABASE=Pivitec, LLC + +OUI:0050C2E89* + ID_OUI_FROM_DATABASE=PROTEQSEN + +OUI:0050C2E8A* + ID_OUI_FROM_DATABASE=Macronet s.r.l. + +OUI:0050C2E8B* + ID_OUI_FROM_DATABASE=RPA Electronic Solutions, Inc. + +OUI:0050C2E8C* + ID_OUI_FROM_DATABASE=Epec Oy + +OUI:0050C2E8D* + ID_OUI_FROM_DATABASE=SystemAdvanced Co,Ltd + +OUI:0050C2E8E* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:0050C2E8F* + ID_OUI_FROM_DATABASE=STT Condigi A/S + +OUI:0050C2E90* + ID_OUI_FROM_DATABASE=GS Elektromedizinische Geraete G. Stemple GmbH + +OUI:0050C2E91* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2E92* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2E93* + ID_OUI_FROM_DATABASE=Perceptive Pixel Inc. + +OUI:0050C2E94* + ID_OUI_FROM_DATABASE=ANA-U GmbH + +OUI:0050C2E95* + ID_OUI_FROM_DATABASE=Dlite Comercio, Importadora e Serviços de Automação Ltda + +OUI:0050C2E96* + ID_OUI_FROM_DATABASE=PROYECSON S.A. + +OUI:0050C2E97* + ID_OUI_FROM_DATABASE=Arista Systems Corporation + +OUI:0050C2E98* + ID_OUI_FROM_DATABASE=i3 International Inc. + +OUI:0050C2E99* + ID_OUI_FROM_DATABASE=UV Networks, Inc. + +OUI:0050C2E9A* + ID_OUI_FROM_DATABASE=Solace Systems + +OUI:0050C2E9B* + ID_OUI_FROM_DATABASE=Hentschel System GmbH + +OUI:0050C2E9C* + ID_OUI_FROM_DATABASE=SPARQ systems + +OUI:0050C2E9D* + ID_OUI_FROM_DATABASE=nicai-systems + +OUI:0050C2E9E* + ID_OUI_FROM_DATABASE=American Microsystems, Ltd. + +OUI:0050C2E9F* + ID_OUI_FROM_DATABASE=DataSoft Corporation + +OUI:0050C2EA0* + ID_OUI_FROM_DATABASE=Robert Bosch Healthcare, Inc. + +OUI:0050C2EA1* + ID_OUI_FROM_DATABASE=TEX COMPUTER SRL + +OUI:0050C2EA2* + ID_OUI_FROM_DATABASE=ThinkRF Corp + +OUI:0050C2EA3* + ID_OUI_FROM_DATABASE=Subsea Systems, Inc. + +OUI:0050C2EA4* + ID_OUI_FROM_DATABASE=head + +OUI:0050C2EA5* + ID_OUI_FROM_DATABASE=Aerodata AG + +OUI:0050C2EA6* + ID_OUI_FROM_DATABASE=Powersense A/S + +OUI:0050C2EA7* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2EA8* + ID_OUI_FROM_DATABASE=MB Connect Line GmbH + +OUI:0050C2EA9* + ID_OUI_FROM_DATABASE=METTLER-TOLEDO HI-SPEED + +OUI:0050C2EAA* + ID_OUI_FROM_DATABASE=BAE Systems + +OUI:0050C2EAB* + ID_OUI_FROM_DATABASE=Warp9 Tech Design, Inc. + +OUI:0050C2EAC* + ID_OUI_FROM_DATABASE=Alias ip + +OUI:0050C2EAD* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2EAE* + ID_OUI_FROM_DATABASE=Alyrica Networks + +OUI:0050C2EAF* + ID_OUI_FROM_DATABASE=Aircell + +OUI:0050C2EB0* + ID_OUI_FROM_DATABASE=Pulse Communication Systems Pvt. Ltd. + +OUI:0050C2EB1* + ID_OUI_FROM_DATABASE=PDU EXPERT UK LTD + +OUI:0050C2EB2* + ID_OUI_FROM_DATABASE=Otaki Electric Corporation + +OUI:0050C2EB3* + ID_OUI_FROM_DATABASE=AR RF/Microwave Instrumentation + +OUI:0050C2EB4* + ID_OUI_FROM_DATABASE=Wishtek Technology, Inc. + +OUI:0050C2EB5* + ID_OUI_FROM_DATABASE=Covidence A/S + +OUI:0050C2EB6* + ID_OUI_FROM_DATABASE=Monsoon Solutions, Inc. + +OUI:0050C2EB7* + ID_OUI_FROM_DATABASE=Saab AB + +OUI:0050C2EB8* + ID_OUI_FROM_DATABASE=dspnor + +OUI:0050C2EB9* + ID_OUI_FROM_DATABASE=ALPHA-MOS + +OUI:0050C2EBA* + ID_OUI_FROM_DATABASE=West-Com Nurse Call Systems, Inc. + +OUI:0050C2EBB* + ID_OUI_FROM_DATABASE=TimeTerminal Adductor Group AB + +OUI:0050C2EBC* + ID_OUI_FROM_DATABASE=Diehl AKO Stiftung & Co. KG + +OUI:0050C2EBD* + ID_OUI_FROM_DATABASE=Droplet Measurement Technologies + +OUI:0050C2EBE* + ID_OUI_FROM_DATABASE=Global Tecnologia LTDA. + +OUI:0050C2EBF* + ID_OUI_FROM_DATABASE=CIVOLUTION + +OUI:0050C2EC0* + ID_OUI_FROM_DATABASE=UgMO Technologies + +OUI:0050C2EC1* + ID_OUI_FROM_DATABASE=ANT Group s.r.l + +OUI:0050C2EC2* + ID_OUI_FROM_DATABASE=Ixonos Plc + +OUI:0050C2EC3* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2EC4* + ID_OUI_FROM_DATABASE=Logical Electromechanical Sys Inc. + +OUI:0050C2EC5* + ID_OUI_FROM_DATABASE=RSUPPORT Co., Ltd. + +OUI:0050C2EC6* + ID_OUI_FROM_DATABASE=INFRONICS SYSTEMS LIMITED + +OUI:0050C2EC7* + ID_OUI_FROM_DATABASE=LIQUID ROBOTICS, INC + +OUI:0050C2EC8* + ID_OUI_FROM_DATABASE=IBERNEX INGENIERIA, S.L. + +OUI:0050C2EC9* + ID_OUI_FROM_DATABASE=Amsterdam Scientific Instruments BV + +OUI:0050C2ECA* + ID_OUI_FROM_DATABASE=BitWise Controls + +OUI:0050C2ECB* + ID_OUI_FROM_DATABASE=FAL Corp + +OUI:0050C2ECC* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2ECD* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:0050C2ECE* + ID_OUI_FROM_DATABASE=easii ic adiis + +OUI:0050C2ECF* + ID_OUI_FROM_DATABASE=TAIWAN HIPLUS CORPORATION + +OUI:0050C2ED0* + ID_OUI_FROM_DATABASE=Nippon Systemware Co.,Ltd. + +OUI:0050C2ED1* + ID_OUI_FROM_DATABASE=Arcontia Technology AB + +OUI:0050C2ED2* + ID_OUI_FROM_DATABASE=Klangspektrum GmbH + +OUI:0050C2ED3* + ID_OUI_FROM_DATABASE=ECO MONITORING UTILITY SYSTEMS LTD + +OUI:0050C2ED4* + ID_OUI_FROM_DATABASE=TAMAGAWA ELECTRONICS CO.,LTD. + +OUI:0050C2ED5* + ID_OUI_FROM_DATABASE=RFL Electronics Inc. + +OUI:0050C2ED6* + ID_OUI_FROM_DATABASE=Cat AB + +OUI:0050C2ED7* + ID_OUI_FROM_DATABASE=FBT Elettronica spa + +OUI:0050C2ED8* + ID_OUI_FROM_DATABASE=AVocation Systems, Inc. + +OUI:0050C2ED9* + ID_OUI_FROM_DATABASE=Plasmatronics pty ltd + +OUI:0050C2EDA* + ID_OUI_FROM_DATABASE=Joint Stock Company "Svyaz Inginiring M" + +OUI:0050C2EDB* + ID_OUI_FROM_DATABASE=BELIK S.P.R.L. + +OUI:0050C2EDC* + ID_OUI_FROM_DATABASE=Eyelock Corporation + +OUI:0050C2EDD* + ID_OUI_FROM_DATABASE=EBNEURO SPA + +OUI:0050C2EDE* + ID_OUI_FROM_DATABASE=Smart Grid Networks + +OUI:0050C2EDF* + ID_OUI_FROM_DATABASE=Monitor Business Machines + +OUI:0050C2EE0* + ID_OUI_FROM_DATABASE=osf Hansjuergen Meier GmbH & Co. KG + +OUI:0050C2EE1* + ID_OUI_FROM_DATABASE=Procon Electronics + +OUI:0050C2EE2* + ID_OUI_FROM_DATABASE=System Industrie Electronic GmbH + +OUI:0050C2EE3* + ID_OUI_FROM_DATABASE=Tecnint HTE Srl + +OUI:0050C2EE4* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2EE5* + ID_OUI_FROM_DATABASE=Cytec Zylindertechnik GmbH + +OUI:0050C2EE6* + ID_OUI_FROM_DATABASE=B:TECH, a. s. + +OUI:0050C2EE7* + ID_OUI_FROM_DATABASE=Syes srl + +OUI:0050C2EE8* + ID_OUI_FROM_DATABASE=Kamacho Scale Co., Ltd. + +OUI:0050C2EE9* + ID_OUI_FROM_DATABASE=QUANTA S.r.l. + +OUI:0050C2EEA* + ID_OUI_FROM_DATABASE=Positioneering Limited + +OUI:0050C2EEB* + ID_OUI_FROM_DATABASE=fibrisTerre GmbH + +OUI:0050C2EEC* + ID_OUI_FROM_DATABASE=Yuyama Mfg. Co., Ltd. + +OUI:0050C2EED* + ID_OUI_FROM_DATABASE=Future Design Controls, Inc + +OUI:0050C2EEE* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd + +OUI:0050C2EEF* + ID_OUI_FROM_DATABASE=IDTRONIC GmbH + +OUI:0050C2EF0* + ID_OUI_FROM_DATABASE=Homaetrix Ltd + +OUI:0050C2EF1* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2EF2* + ID_OUI_FROM_DATABASE=Specialty Microwave Corp + +OUI:0050C2EF3* + ID_OUI_FROM_DATABASE=Smart Power Electronics GmbH & Co. KG + +OUI:0050C2EF4* + ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A + +OUI:0050C2EF5* + ID_OUI_FROM_DATABASE=Human Network Labs, Inc. + +OUI:0050C2EF6* + ID_OUI_FROM_DATABASE=Netline Communication Technologies + +OUI:0050C2EF7* + ID_OUI_FROM_DATABASE=Amstelland Electronic BV + +OUI:0050C2EF8* + ID_OUI_FROM_DATABASE=HCL Technologies + +OUI:0050C2EF9* + ID_OUI_FROM_DATABASE=HORIBA ABX + +OUI:0050C2EFA* + ID_OUI_FROM_DATABASE=Predictive Sensor Technology + +OUI:0050C2EFB* + ID_OUI_FROM_DATABASE=Norbit ODM AS + +OUI:0050C2EFD* + ID_OUI_FROM_DATABASE=Sanmina + +OUI:0050C2EFE* + ID_OUI_FROM_DATABASE=PLR Information Systems Ltd. + +OUI:0050C2EFF* + ID_OUI_FROM_DATABASE=Zephyrus Electronics LTD. + +OUI:0050C2F00* + ID_OUI_FROM_DATABASE=Syscom Instruments + +OUI:0050C2F01* + ID_OUI_FROM_DATABASE=Mango DSP, Inc + +OUI:0050C2F02* + ID_OUI_FROM_DATABASE=BMR + +OUI:0050C2F03* + ID_OUI_FROM_DATABASE=Wren Sound Systems + +OUI:0050C2F04* + ID_OUI_FROM_DATABASE=KINKI ROENTGEN INDUSTRIAL CO.,LTD + +OUI:0050C2F05* + ID_OUI_FROM_DATABASE=ESI Ventures + +OUI:0050C2F06* + ID_OUI_FROM_DATABASE=Micro-Key BV + +OUI:0050C2F07* + ID_OUI_FROM_DATABASE=Icon Research Ltd + +OUI:0050C2F08* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2F09* + ID_OUI_FROM_DATABASE=Wheatstone Corporation + +OUI:0050C2F0A* + ID_OUI_FROM_DATABASE=HASCOM International Pty Ltd + +OUI:0050C2F0B* + ID_OUI_FROM_DATABASE=Treehaven Technologies, Inc. + +OUI:0050C2F0C* + ID_OUI_FROM_DATABASE=SKYCHANNEL LTD + +OUI:0050C2F0D* + ID_OUI_FROM_DATABASE=Bluetest AB + +OUI:0050C2F0E* + ID_OUI_FROM_DATABASE=Micro Technic A/S + +OUI:0050C2F0F* + ID_OUI_FROM_DATABASE=AeroVision Avionics, Inc. + +OUI:0050C2F10* + ID_OUI_FROM_DATABASE=Wincor Nixdorf Sp. z o.o. + +OUI:0050C2F11* + ID_OUI_FROM_DATABASE=Organis GmbH + +OUI:0050C2F12* + ID_OUI_FROM_DATABASE=General Industrial Controls Pvt Ltd + +OUI:0050C2F13* + ID_OUI_FROM_DATABASE=Packet Plus, Inc. + +OUI:0050C2F14* + ID_OUI_FROM_DATABASE=VISION SYSTEMS AERONAUTIC + +OUI:0050C2F15* + ID_OUI_FROM_DATABASE=Sascal Displays Ltd + +OUI:0050C2F16* + ID_OUI_FROM_DATABASE=Peter Huber Kältemaschinenbau GmbH + +OUI:0050C2F17* + ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd + +OUI:0050C2F18* + ID_OUI_FROM_DATABASE=Vitec Multimedia + +OUI:0050C2F19* + ID_OUI_FROM_DATABASE=Netlink Bilisim Sistemleri San. ve Tic. Ltd. Sti. + +OUI:0050C2F1A* + ID_OUI_FROM_DATABASE=Aqua Management + +OUI:0050C2F1B* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2F1C* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:0050C2F1D* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + +OUI:0050C2F1E* + ID_OUI_FROM_DATABASE=Dell'Orto S.P.A. + +OUI:0050C2F1F* + ID_OUI_FROM_DATABASE=Verified Energy, LLC. + +OUI:0050C2F20* + ID_OUI_FROM_DATABASE=Unfors Instruments AB + +OUI:0050C2F21* + ID_OUI_FROM_DATABASE=SEITEC Co. Ltd + +OUI:0050C2F22* + ID_OUI_FROM_DATABASE=Harland Simon plc + +OUI:0050C2F23* + ID_OUI_FROM_DATABASE=Electro-Motive Diesel + +OUI:0050C2F24* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2F25* + ID_OUI_FROM_DATABASE=Samway Electronic SRL + +OUI:0050C2F26* + ID_OUI_FROM_DATABASE=WaveIP + +OUI:0050C2F27* + ID_OUI_FROM_DATABASE=ELAN SYSTEMS + +OUI:0050C2F28* + ID_OUI_FROM_DATABASE=Vertex Antennentechnik GmbH + +OUI:0050C2F29* + ID_OUI_FROM_DATABASE=RADYNE CORPORATION + +OUI:0050C2F2A* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2F2B* + ID_OUI_FROM_DATABASE=Bio Guard component & technologies + +OUI:0050C2F2C* + ID_OUI_FROM_DATABASE=Terratel Technology s.r.o. + +OUI:0050C2F2D* + ID_OUI_FROM_DATABASE=Robert Bosch Healthcare Systems, Inc. + +OUI:0050C2F2E* + ID_OUI_FROM_DATABASE=H&L Instruments, LLC + +OUI:0050C2F2F* + ID_OUI_FROM_DATABASE=Arcos Technologies LTD + +OUI:0050C2F30* + ID_OUI_FROM_DATABASE=Miris AB + +OUI:0050C2F31* + ID_OUI_FROM_DATABASE=Ruetz Technologies GmbH + +OUI:0050C2F32* + ID_OUI_FROM_DATABASE=Net4Things + +OUI:0050C2F33* + ID_OUI_FROM_DATABASE=Applied Micro Electronics "AME" BV + +OUI:0050C2F34* + ID_OUI_FROM_DATABASE=Sequip S+E GmbH + +OUI:0050C2F35* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:0050C2F36* + ID_OUI_FROM_DATABASE=Visitech AS + +OUI:0050C2F37* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:0050C2F38* + ID_OUI_FROM_DATABASE=AeroControl, Inc. + +OUI:0050C2F39* + ID_OUI_FROM_DATABASE=Inforce Computing, Inc. + +OUI:0050C2F3A* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2F3B* + ID_OUI_FROM_DATABASE=TAMS firmware co. + +OUI:0050C2F3C* + ID_OUI_FROM_DATABASE=Vemco Sp. z o. o. + +OUI:0050C2F3D* + ID_OUI_FROM_DATABASE=Project service S.a.s + +OUI:0050C2F3E* + ID_OUI_FROM_DATABASE=Vtron Pty Ltd + +OUI:0050C2F3F* + ID_OUI_FROM_DATABASE=DENSEI COMMUNICATION Inc. + +OUI:0050C2F40* + ID_OUI_FROM_DATABASE=iBWorld co.,ltd. + +OUI:0050C2F41* + ID_OUI_FROM_DATABASE=FairyDevices Inc. + +OUI:0050C2F42* + ID_OUI_FROM_DATABASE=DSPCon + +OUI:0050C2F43* + ID_OUI_FROM_DATABASE=Special Systems Engineering Center LLC + +OUI:0050C2F44* + ID_OUI_FROM_DATABASE=Steinbichler Optotechnik GmbH + +OUI:0050C2F45* + ID_OUI_FROM_DATABASE=HUSTY M.Styczen J.Hupert Sp.J. + +OUI:0050C2F46* + ID_OUI_FROM_DATABASE=Reason Tecnologia S.A. + +OUI:0050C2F47* + ID_OUI_FROM_DATABASE=cadac,inc. + +OUI:0050C2F48* + ID_OUI_FROM_DATABASE=Midas Technology DBA Phoenix Audio Technologies + +OUI:0050C2F49* + ID_OUI_FROM_DATABASE=Green Instruments A/S + +OUI:0050C2F4A* + ID_OUI_FROM_DATABASE=Z-App Systems, Inc. + +OUI:0050C2F4B* + ID_OUI_FROM_DATABASE=Supranet + +OUI:0050C2F4C* + ID_OUI_FROM_DATABASE=Enistic Limited + +OUI:0050C2F4D* + ID_OUI_FROM_DATABASE=KNOWHOW INFOCOM INC. + +OUI:0050C2F4E* + ID_OUI_FROM_DATABASE=Heinzinger electronic GmbH + +OUI:0050C2F4F* + ID_OUI_FROM_DATABASE=BAP Precision Ltd. + +OUI:0050C2F50* + ID_OUI_FROM_DATABASE=Moritex Corporation + +OUI:0050C2F51* + ID_OUI_FROM_DATABASE=NDC Infrared Engineering, Inc. + +OUI:0050C2F52* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2F53* + ID_OUI_FROM_DATABASE=BAYCOM OPTO-ELECTRONICS TECHNOLOGY CO.,LTD. + +OUI:0050C2F54* + ID_OUI_FROM_DATABASE=Hella Gutmann Solutions GmbH + +OUI:0050C2F55* + ID_OUI_FROM_DATABASE=Honeywell International Inc. + +OUI:0050C2F56* + ID_OUI_FROM_DATABASE=Monsoon Solutions, Inc. + +OUI:0050C2F57* + ID_OUI_FROM_DATABASE=Reach Technologies Inc. + +OUI:0050C2F58* + ID_OUI_FROM_DATABASE=IEEE-SA + +OUI:0050C2F59* + ID_OUI_FROM_DATABASE=G3 Technologies + +OUI:0050C2F5A* + ID_OUI_FROM_DATABASE=Sentry 360 Security + +OUI:0050C2F5B* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:0050C2F5C* + ID_OUI_FROM_DATABASE=DSP DESIGN LTD + +OUI:0050C2F5D* + ID_OUI_FROM_DATABASE=SMARTB TECHNOLOGIES + +OUI:0050C2F5E* + ID_OUI_FROM_DATABASE=Y-cam Solutions Ltd + +OUI:0050C2F5F* + ID_OUI_FROM_DATABASE=BORYEU TECHNOLOGY CO.,LTD + +OUI:0050C2F60* + ID_OUI_FROM_DATABASE=Deckma GmbH + +OUI:0050C2F61* + ID_OUI_FROM_DATABASE=Brauch Elektronik GmbH&Co.KG + +OUI:0050C2F62* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2F63* + ID_OUI_FROM_DATABASE=Triax A/S + +OUI:0050C2F64* + ID_OUI_FROM_DATABASE=Chrisso Technologies LLC + +OUI:0050C2F65* + ID_OUI_FROM_DATABASE=Telebyte Inc. + +OUI:0050C2F66* + ID_OUI_FROM_DATABASE=GWT LLC + +OUI:0050C2F67* + ID_OUI_FROM_DATABASE=Celestial Audio + +OUI:0050C2F68* + ID_OUI_FROM_DATABASE=NEWTEC A/S + +OUI:0050C2F69* + ID_OUI_FROM_DATABASE=Safe Place Solutions Ltd + +OUI:0050C2F6A* + ID_OUI_FROM_DATABASE=OFI Inc. (dba 2D2C) + +OUI:0050C2F6B* + ID_OUI_FROM_DATABASE=Algodue Elettronica Srl + +OUI:0050C2F6C* + ID_OUI_FROM_DATABASE=Pro Design Electronic GmbH + +OUI:0050C2F6D* + ID_OUI_FROM_DATABASE=Pro Design Electronic GmbH + +OUI:0050C2F6E* + ID_OUI_FROM_DATABASE=Smith Meter, Inc. + +OUI:0050C2F6F* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2F70* + ID_OUI_FROM_DATABASE=Noralta Technologies Inc + +OUI:0050C2F71* + ID_OUI_FROM_DATABASE=RF CODE, INC + +OUI:0050C2F72* + ID_OUI_FROM_DATABASE=MaxDeTec AG + +OUI:0050C2F73* + ID_OUI_FROM_DATABASE=DELTACAST.TV + +OUI:0050C2F74* + ID_OUI_FROM_DATABASE=Thor Technologies Pty Ltd + +OUI:0050C2F75* + ID_OUI_FROM_DATABASE=PumpWell Solutions Ltd. + +OUI:0050C2F76* + ID_OUI_FROM_DATABASE=Rong Jie(FuZhou)Electronics Co.,Ltd + +OUI:0050C2F77* + ID_OUI_FROM_DATABASE=SYSTEMTECHNIK GmbH + +OUI:0050C2F78* + ID_OUI_FROM_DATABASE=Gets MSS S.A. + +OUI:0050C2F79* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:0050C2F7A* + ID_OUI_FROM_DATABASE=C3 LLC + +OUI:0050C2F7B* + ID_OUI_FROM_DATABASE=MCM Electronics + +OUI:0050C2F7C* + ID_OUI_FROM_DATABASE=Atonometrics, Inc. + +OUI:0050C2F7D* + ID_OUI_FROM_DATABASE=D-Hike Electroncs Technology Co.,Ltd + +OUI:0050C2F7E* + ID_OUI_FROM_DATABASE=TruTeq Wireless (Pty) Ltd + +OUI:0050C2F7F* + ID_OUI_FROM_DATABASE=Dynamic Design + +OUI:0050C2F80* + ID_OUI_FROM_DATABASE=SYS TEC electronic GmbH + +OUI:0050C2F81* + ID_OUI_FROM_DATABASE=PLDA + +OUI:0050C2F82* + ID_OUI_FROM_DATABASE=Sincair Systems International + +OUI:0050C2F83* + ID_OUI_FROM_DATABASE=GSP Sprachtechnologie GmbH + +OUI:0050C2F84* + ID_OUI_FROM_DATABASE=Dynon Instruments + +OUI:0050C2F85* + ID_OUI_FROM_DATABASE=Enetics, Inc. + +OUI:0050C2F86* + ID_OUI_FROM_DATABASE=Audio Power Labs + +OUI:0050C2F87* + ID_OUI_FROM_DATABASE=Vaisala Oyj + +OUI:0050C2F88* + ID_OUI_FROM_DATABASE=RTC Manufacturing Inc. + +OUI:0050C2F89* + ID_OUI_FROM_DATABASE=CSA Engineering AG + +OUI:0050C2F8A* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:0050C2F8B* + ID_OUI_FROM_DATABASE=comlet Verteilte Systeme GmbH + +OUI:0050C2F8C* + ID_OUI_FROM_DATABASE=UBSTechnology Co., Ltd + +OUI:0050C2F8D* + ID_OUI_FROM_DATABASE=GUANGDONG EAST POWER CO.,LTD. + +OUI:0050C2F8E* + ID_OUI_FROM_DATABASE=GPO + +OUI:0050C2F8F* + ID_OUI_FROM_DATABASE=Computerwise, Inc. + +OUI:0050C2F90* + ID_OUI_FROM_DATABASE=SecureTech Systems, Inc. + +OUI:0050C2F91* + ID_OUI_FROM_DATABASE=RE2 Inc + +OUI:0050C2F92* + ID_OUI_FROM_DATABASE=CONET Solutions GmbH + +OUI:0050C2F93* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:0050C2F94* + ID_OUI_FROM_DATABASE=Digital Barriers + +OUI:0050C2F95* + ID_OUI_FROM_DATABASE=TTi LTD (Thurlby Thandar Instruments LTD) + +OUI:0050C2F96* + ID_OUI_FROM_DATABASE=JLCooper Electronics + +OUI:0050C2F97* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:0050C2F98* + ID_OUI_FROM_DATABASE=Infotech North America + +OUI:0050C2F99* + ID_OUI_FROM_DATABASE=Dr. Neumann elektronik GmbH + +OUI:0050C2F9A* + ID_OUI_FROM_DATABASE=Telvent + +OUI:0050C2F9B* + ID_OUI_FROM_DATABASE=NEWELL TECHNOLOGIES LIMITED + +OUI:0050C2F9C* + ID_OUI_FROM_DATABASE=R&D KOMETEH + +OUI:0050C2F9D* + ID_OUI_FROM_DATABASE=JSC "Kaluga Teletypes Manufacturing Plant" + +OUI:0050C2F9E* + ID_OUI_FROM_DATABASE=Matsusada Precision Inc. + +OUI:0050C2F9F* + ID_OUI_FROM_DATABASE=Nanjing SAC Power Grid Automation Co., Ltd. + +OUI:0050C2FA0* + ID_OUI_FROM_DATABASE=Amplus Communication Pte Ltd + +OUI:0050C2FA1* + ID_OUI_FROM_DATABASE=N-Hands GmbH und Co KG + +OUI:0050C2FA2* + ID_OUI_FROM_DATABASE=Power-One + +OUI:0050C2FA3* + ID_OUI_FROM_DATABASE=Xemex NV + +OUI:0050C2FA5* + ID_OUI_FROM_DATABASE=Intuitive Surgical, Inc. + +OUI:0050C2FA6* + ID_OUI_FROM_DATABASE=Hilkom digital GmbH + +OUI:0050C2FA7* + ID_OUI_FROM_DATABASE=Exelis Inc. + +OUI:0050C2FA8* + ID_OUI_FROM_DATABASE=Yash SiQure Technologies India Pvt. Ltd. + +OUI:0050C2FA9* + ID_OUI_FROM_DATABASE=Hijet Print d.o.o. + +OUI:0050C2FAA* + ID_OUI_FROM_DATABASE=YJSYSTEM + +OUI:0050C2FAB* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:0050C2FAC* + ID_OUI_FROM_DATABASE=ADETEL GROUP + +OUI:0050C2FAD* + ID_OUI_FROM_DATABASE=Finishing Brands + +OUI:0050C2FAE* + ID_OUI_FROM_DATABASE=ATI Automacao Telecomunicacoes e Informatica Ltda + +OUI:0050C2FAF* + ID_OUI_FROM_DATABASE=Vremya-CH JSC + +OUI:0050C2FB0* + ID_OUI_FROM_DATABASE=Tateishi Kobisha Co.LTD + +OUI:0050C2FB1* + ID_OUI_FROM_DATABASE=MATELEX + +OUI:0050C2FB2* + ID_OUI_FROM_DATABASE=Preston Industries dba PolyScience + +OUI:0050C2FB3* + ID_OUI_FROM_DATABASE=CT Company + +OUI:0050C2FB4* + ID_OUI_FROM_DATABASE=MC-monitoring SA + +OUI:0050C2FB5* + ID_OUI_FROM_DATABASE=Assembly Contracts Limited + +OUI:0050C2FB6* + ID_OUI_FROM_DATABASE=ARGUS-SPECTRUM + +OUI:0050C2FB7* + ID_OUI_FROM_DATABASE=Pounce Consulting + +OUI:0050C2FB8* + ID_OUI_FROM_DATABASE=TECHNO CO.,LTD. + +OUI:0050C2FB9* + ID_OUI_FROM_DATABASE=Coral Telecom Ltd + +OUI:0050C2FBA* + ID_OUI_FROM_DATABASE=Elbit Systems of America + +OUI:0050C2FBB* + ID_OUI_FROM_DATABASE=ACIDA GmbH + +OUI:0050C2FBC* + ID_OUI_FROM_DATABASE=Leroy Somer + +OUI:0050C2FBD* + ID_OUI_FROM_DATABASE=FHF Funke+Huster Fernsig GmbH + +OUI:0050C2FBE* + ID_OUI_FROM_DATABASE=senTec Elektronik GmbH + +OUI:0050C2FBF* + ID_OUI_FROM_DATABASE=MYLOGIC + +OUI:0050C2FC0* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:0050C2FC1* + ID_OUI_FROM_DATABASE=Motec Pty Ltd + +OUI:0050C2FC2* + ID_OUI_FROM_DATABASE=ELTA + +OUI:0050C2FC3* + ID_OUI_FROM_DATABASE=HSDC Sp. z o.o. + +OUI:0050C2FC4* + ID_OUI_FROM_DATABASE=Kyowadensi + +OUI:0050C2FC5* + ID_OUI_FROM_DATABASE=Sakura Seiki Co.,Ltd. + +OUI:0050C2FC6* + ID_OUI_FROM_DATABASE=Critical Link + +OUI:0050C2FC7* + ID_OUI_FROM_DATABASE=SERCOM Regeltechniek + +OUI:0050C2FC8* + ID_OUI_FROM_DATABASE=Far South Networks + +OUI:0050C2FC9* + ID_OUI_FROM_DATABASE=Mehta Tech, Inc. + +OUI:0050C2FCA* + ID_OUI_FROM_DATABASE=Telemisis Ltd + +OUI:0050C2FCB* + ID_OUI_FROM_DATABASE=Propagation Systems Limited + +OUI:0050C2FCC* + ID_OUI_FROM_DATABASE=Soudronic AG + +OUI:0050C2FCD* + ID_OUI_FROM_DATABASE=Jinyoung Contech + +OUI:0050C2FCE* + ID_OUI_FROM_DATABASE=KOYO ELECTRIC + +OUI:0050C2FCF* + ID_OUI_FROM_DATABASE=DINTEK Shanghai Electronic Ltd + +OUI:0050C2FD0* + ID_OUI_FROM_DATABASE=Simple Solutions + +OUI:0050C2FD1* + ID_OUI_FROM_DATABASE=Enyx SA + +OUI:0050C2FD2* + ID_OUI_FROM_DATABASE=Autonomic Controls. Inc + +OUI:0050C2FD3* + ID_OUI_FROM_DATABASE=Aster Electric Co.,Ltd. + +OUI:0050C2FD4* + ID_OUI_FROM_DATABASE=Insitu, Inc. + +OUI:0050C2FD5* + ID_OUI_FROM_DATABASE=American Microsystems, Ltd. + +OUI:0050C2FD6* + ID_OUI_FROM_DATABASE=City Computing Ltd + +OUI:0050C2FD7* + ID_OUI_FROM_DATABASE=Deuta-Werke GmbH + +OUI:0050C2FD8* + ID_OUI_FROM_DATABASE=Ease Inc. + +OUI:0050C2FD9* + ID_OUI_FROM_DATABASE=Figment Design Laboratories + +OUI:0050C2FDA* + ID_OUI_FROM_DATABASE=ELAN SYSTEMS + +OUI:0050C2FDB* + ID_OUI_FROM_DATABASE=The Security Center Inc + +OUI:0050C2FDC* + ID_OUI_FROM_DATABASE=QUERCUS TECHNOLOGIES, S.L. + +OUI:0050C2FDD* + ID_OUI_FROM_DATABASE=Toptech Systems, Inc. + +OUI:0050C2FDE* + ID_OUI_FROM_DATABASE=Peek Traffic + +OUI:0050C2FDF* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:0050C2FE0* + ID_OUI_FROM_DATABASE=Azurtest + +OUI:0050C2FE1* + ID_OUI_FROM_DATABASE=dotOcean + +OUI:0050C2FE2* + ID_OUI_FROM_DATABASE=Pulsotronic Anlagentechnik GmbH + +OUI:0050C2FE4* + ID_OUI_FROM_DATABASE=RTT Mobile Interpretation + +OUI:0050C2FE5* + ID_OUI_FROM_DATABASE=Scandinova Systems AB + +OUI:0050C2FE6* + ID_OUI_FROM_DATABASE=Exibea AB + +OUI:0050C2FE7* + ID_OUI_FROM_DATABASE=Erhardt+Leimer GmbH + +OUI:0050C2FE8* + ID_OUI_FROM_DATABASE=Mango DSP, Inc. + +OUI:0050C2FE9* + ID_OUI_FROM_DATABASE=MB Connect Line GmbH + +OUI:0050C2FEA* + ID_OUI_FROM_DATABASE=Brunel GmbH Section Communications + +OUI:0050C2FEB* + ID_OUI_FROM_DATABASE=Axible Technologies + +OUI:0050C2FEC* + ID_OUI_FROM_DATABASE=First System Technology Co., Ltd. + +OUI:0050C2FED* + ID_OUI_FROM_DATABASE=LOGISOL Kft. + +OUI:0050C2FEE* + ID_OUI_FROM_DATABASE=Sparks Instruments SA + +OUI:0050C2FEF* + ID_OUI_FROM_DATABASE=Task Sistemas de Computacao + +OUI:0050C2FF0* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:0050C2FF1* + ID_OUI_FROM_DATABASE=DiTEST FAHRZEUGDIAGNOSE GMBH + +OUI:0050C2FF2* + ID_OUI_FROM_DATABASE=GLOBALCOM ENGINEERING SRL + +OUI:0050C2FF3* + ID_OUI_FROM_DATABASE=CONTROL SYSTEMS Srl + +OUI:0050C2FF4* + ID_OUI_FROM_DATABASE=Burk Technology + +OUI:0050C2FF5* + ID_OUI_FROM_DATABASE=Flexkom Internet Pazarlama Bilipim ve Eoitim Hiz.Inp.Mim.Muh.Oto.Enerji San. Tic. A.p. + +OUI:0050C2FF6* + ID_OUI_FROM_DATABASE=Booyco Electronics + +OUI:0050C2FF7* + ID_OUI_FROM_DATABASE=Human Intech + +OUI:0050C2FF8* + ID_OUI_FROM_DATABASE=KST technology + +OUI:0050C2FF9* + ID_OUI_FROM_DATABASE=Penttech AB + +OUI:0050C2FFA* + ID_OUI_FROM_DATABASE=Nupoint Systems Inc. + +OUI:0050C2FFB* + ID_OUI_FROM_DATABASE=SEFRAM + +OUI:0050C2FFC* + ID_OUI_FROM_DATABASE=Spirent Communications + +OUI:0050C2FFD* + ID_OUI_FROM_DATABASE=Touchless Biometric Systems AG + +OUI:0050C2FFE* + ID_OUI_FROM_DATABASE=Sensata Technologies + +OUI:0050C2FFF* + ID_OUI_FROM_DATABASE=MSR-Solutions GmbH + +OUI:40D855000* + ID_OUI_FROM_DATABASE=XRONOS.INC + +OUI:40D855001* + ID_OUI_FROM_DATABASE=Vemotion + +OUI:40D855002* + ID_OUI_FROM_DATABASE=Hangzhou Chenxiao Technologies Co. Ltd. + +OUI:40D855003* + ID_OUI_FROM_DATABASE=AlphaNavigation coltd + +OUI:40D855004* + ID_OUI_FROM_DATABASE=CR Magnetics, Inc. + +OUI:40D855005* + ID_OUI_FROM_DATABASE=Monarch Instrument + +OUI:40D855006* + ID_OUI_FROM_DATABASE=Bactest Limited + +OUI:40D855007* + ID_OUI_FROM_DATABASE=Digital Audio SA + +OUI:40D855008* + ID_OUI_FROM_DATABASE=Kaori Industria Eletronica Ltda + +OUI:40D855009* + ID_OUI_FROM_DATABASE=ClearSite Communications Inc. + +OUI:40D85500A* + ID_OUI_FROM_DATABASE=Sarana Sistem Mikro + +OUI:40D85500B* + ID_OUI_FROM_DATABASE=Aircell + +OUI:40D85500C* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D85500D* + ID_OUI_FROM_DATABASE=HuNS + +OUI:40D85500E* + ID_OUI_FROM_DATABASE=Brightwell Dispensers + +OUI:40D85500F* + ID_OUI_FROM_DATABASE=DIGITAL DYNAMICS, INC. + +OUI:40D855010* + ID_OUI_FROM_DATABASE=APG CASH DRAWER + +OUI:40D855011* + ID_OUI_FROM_DATABASE=Flexim Security Oy + +OUI:40D855012* + ID_OUI_FROM_DATABASE=Sencon Inc. + +OUI:40D855013* + ID_OUI_FROM_DATABASE=Grande Vitesse Systems + +OUI:40D855014* + ID_OUI_FROM_DATABASE=Toni Studio + +OUI:40D855015* + ID_OUI_FROM_DATABASE=BITMILL srl + +OUI:40D855016* + ID_OUI_FROM_DATABASE=Par-Tech, Inc. + +OUI:40D855017* + ID_OUI_FROM_DATABASE=Franke Aquarotter GmbH + +OUI:40D855018* + ID_OUI_FROM_DATABASE=STANEO SAS + +OUI:40D855019* + ID_OUI_FROM_DATABASE=Nautel Limited + +OUI:40D85501A* + ID_OUI_FROM_DATABASE=MEGGITT DEFENSE SYSTEMS INC. + +OUI:40D85501B* + ID_OUI_FROM_DATABASE=Audio Enhancement + +OUI:40D85501C* + ID_OUI_FROM_DATABASE=BERG Cloud Limited + +OUI:40D85501D* + ID_OUI_FROM_DATABASE=Scharco Elektronik GmbH + +OUI:40D85501E* + ID_OUI_FROM_DATABASE=A2S + +OUI:40D85501F* + ID_OUI_FROM_DATABASE=Sitep Italia Spa + +OUI:40D855020* + ID_OUI_FROM_DATABASE=ENTEC Electric & Electronic CO., LTD. + +OUI:40D855021* + ID_OUI_FROM_DATABASE=SMT D.O.O. + +OUI:40D855022* + ID_OUI_FROM_DATABASE=Digimerge Technology Inc + +OUI:40D855023* + ID_OUI_FROM_DATABASE=Shanghai o-solution electronics & Technology Co., Ltd. + +OUI:40D855024* + ID_OUI_FROM_DATABASE=Electrical Geodesics Incorporated + +OUI:40D855025* + ID_OUI_FROM_DATABASE=Rosemount Analytical + +OUI:40D855026* + ID_OUI_FROM_DATABASE=Symetrics Industries + +OUI:40D855027* + ID_OUI_FROM_DATABASE=GRUPO EPELSA S.L. + +OUI:40D855028* + ID_OUI_FROM_DATABASE=Integrated Control Corp. + +OUI:40D855029* + ID_OUI_FROM_DATABASE=Depro Electronique + +OUI:40D85502A* + ID_OUI_FROM_DATABASE=Tinkerforge GmbH + +OUI:40D85502B* + ID_OUI_FROM_DATABASE=Nomatronics + +OUI:40D85502C* + ID_OUI_FROM_DATABASE=InventLab s.c. + +OUI:40D85502D* + ID_OUI_FROM_DATABASE=Elgama Sistemos + +OUI:40D85502E* + ID_OUI_FROM_DATABASE=Circuitec Ind. Equip. Eletr. Ltda + +OUI:40D85502F* + ID_OUI_FROM_DATABASE=Adva Technologies + +OUI:40D855030* + ID_OUI_FROM_DATABASE=Tecnologias Plexus + +OUI:40D855031* + ID_OUI_FROM_DATABASE=Dommel GmbH + +OUI:40D855032* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:40D855033* + ID_OUI_FROM_DATABASE=Ermes Elettronica s.r.l. + +OUI:40D855034* + ID_OUI_FROM_DATABASE=Dacom West GmbH + +OUI:40D855035* + ID_OUI_FROM_DATABASE=Mesotech International, Inc. + +OUI:40D855036* + ID_OUI_FROM_DATABASE=Schweers informationstechnologie GmbH + +OUI:40D855037* + ID_OUI_FROM_DATABASE=Software Workshop + +OUI:40D855038* + ID_OUI_FROM_DATABASE=Special Measurements Labs LLC + +OUI:40D855039* + ID_OUI_FROM_DATABASE=CI Systems Ltd + +OUI:40D85503A* + ID_OUI_FROM_DATABASE=Socus networks + +OUI:40D85503B* + ID_OUI_FROM_DATABASE=Telcomkorea + +OUI:40D85503C* + ID_OUI_FROM_DATABASE=Computer System Co.,Ltd + +OUI:40D85503D* + ID_OUI_FROM_DATABASE=Tekelek Europe Ltd + +OUI:40D85503E* + ID_OUI_FROM_DATABASE=Vishay Celtron Technologies, Inc. + +OUI:40D85503F* + ID_OUI_FROM_DATABASE=UniSVR Global Information Technology Corp. + +OUI:40D855040* + ID_OUI_FROM_DATABASE=GHL Systems Berhad + +OUI:40D855041* + ID_OUI_FROM_DATABASE=T.Q.M. Itaca Technology s.r.l. + +OUI:40D855042* + ID_OUI_FROM_DATABASE=Mango Communicaitons Inc. + +OUI:40D855043* + ID_OUI_FROM_DATABASE=SchulerControl GmbH + +OUI:40D855044* + ID_OUI_FROM_DATABASE=An Chen Computer Co. Ltd. + +OUI:40D855045* + ID_OUI_FROM_DATABASE=Genadsystem + +OUI:40D855046* + ID_OUI_FROM_DATABASE=Circuitlink Pty Ltd + +OUI:40D855047* + ID_OUI_FROM_DATABASE=Dos&Donts SRL + +OUI:40D855048* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D855049* + ID_OUI_FROM_DATABASE=Thermo Fisher Scientific + +OUI:40D85504A* + ID_OUI_FROM_DATABASE=Gateway Technologies SA de CV + +OUI:40D85504B* + ID_OUI_FROM_DATABASE=Vital Tech Industria e Comercio Ltda + +OUI:40D85504C* + ID_OUI_FROM_DATABASE=Serveron Corporation + +OUI:40D85504D* + ID_OUI_FROM_DATABASE=MACHINEPERFORMANCE ApS + +OUI:40D85504E* + ID_OUI_FROM_DATABASE=Honeywell Aerospace/Intelligent Automation Corp. + +OUI:40D85504F* + ID_OUI_FROM_DATABASE=Haein S&S Co., Ltd + +OUI:40D855050* + ID_OUI_FROM_DATABASE=ATG UV Technology + +OUI:40D855051* + ID_OUI_FROM_DATABASE=CS Instruments Asia + +OUI:40D855052* + ID_OUI_FROM_DATABASE=DAN ELECTRONICS SYSTEM (P) LIMITED + +OUI:40D855053* + ID_OUI_FROM_DATABASE=Amantys Ltd + +OUI:40D855054* + ID_OUI_FROM_DATABASE=VITEC + +OUI:40D855055* + ID_OUI_FROM_DATABASE=Helmholtz Zentrum Dresden Rossendorf e.V. + +OUI:40D855056* + ID_OUI_FROM_DATABASE=GROUP 57 + +OUI:40D855057* + ID_OUI_FROM_DATABASE=Tammermatic Group Oy + +OUI:40D855058* + ID_OUI_FROM_DATABASE=Energy Team S.p.A. + +OUI:40D855059* + ID_OUI_FROM_DATABASE=COLONIAL ASSEMBLY and DESIGN + +OUI:40D85505A* + ID_OUI_FROM_DATABASE=Ultra Electronics Flightline Systems + +OUI:40D85505B* + ID_OUI_FROM_DATABASE=Data Flow Systems, Inc. + +OUI:40D85505C* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:40D85505D* + ID_OUI_FROM_DATABASE=Leica Biosystems + +OUI:40D85505E* + ID_OUI_FROM_DATABASE=inoage GmbH + +OUI:40D85505F* + ID_OUI_FROM_DATABASE=EPSa GmbH + +OUI:40D855060* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D855061* + ID_OUI_FROM_DATABASE=Cominfo, Inc. + +OUI:40D855062* + ID_OUI_FROM_DATABASE=Tech Source Inc + +OUI:40D855063* + ID_OUI_FROM_DATABASE=Protonic Holland + +OUI:40D855064* + ID_OUI_FROM_DATABASE=HIPODROMO DE AGUA CALIENTE, S.A. DE C.V. + +OUI:40D855065* + ID_OUI_FROM_DATABASE=Parallel Wireless + +OUI:40D855066* + ID_OUI_FROM_DATABASE=TeraTron GmbH + +OUI:40D855067* + ID_OUI_FROM_DATABASE=Tronic Control ltd. + +OUI:40D855068* + ID_OUI_FROM_DATABASE=Oki Seatec Co., Ltd. + +OUI:40D855069* + ID_OUI_FROM_DATABASE=Smartcom-Bulgaria AD + +OUI:40D85506A* + ID_OUI_FROM_DATABASE=elgris + +OUI:40D85506B* + ID_OUI_FROM_DATABASE=BRS Sistemas Eletronicos + +OUI:40D85506C* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:40D85506D* + ID_OUI_FROM_DATABASE=BroadSoft, INC + +OUI:40D85506E* + ID_OUI_FROM_DATABASE=C-COM Satellite Systems Inc. + +OUI:40D85506F* + ID_OUI_FROM_DATABASE=DORLET SA + +OUI:40D855070* + ID_OUI_FROM_DATABASE=JSC Electrical Equipment Factory + +OUI:40D855071* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:40D855072* + ID_OUI_FROM_DATABASE=CT Company + +OUI:40D855073* + ID_OUI_FROM_DATABASE=Diamond Technologies, Inc + +OUI:40D855074* + ID_OUI_FROM_DATABASE=Sphere Medical Ltd + +OUI:40D855075* + ID_OUI_FROM_DATABASE=Teraflops + +OUI:40D855076* + ID_OUI_FROM_DATABASE=INTERNET PROTOCOLO LOGICA SL + +OUI:40D855077* + ID_OUI_FROM_DATABASE=TOEC TECHNOLOGY CO.,LTD + +OUI:40D855078* + ID_OUI_FROM_DATABASE=NACHI-FUJIKOSHI CORP + +OUI:40D855079* + ID_OUI_FROM_DATABASE=DelfiSolutions A/S + +OUI:40D85507A* + ID_OUI_FROM_DATABASE=4embedded + +OUI:40D85507B* + ID_OUI_FROM_DATABASE=IPS Technology Limited + +OUI:40D85507C* + ID_OUI_FROM_DATABASE=Agramkow Fluid Systems A/S + +OUI:40D85507D* + ID_OUI_FROM_DATABASE=Wuxi SiNeng New Energy Co., Ltd. + +OUI:40D85507E* + ID_OUI_FROM_DATABASE=TESCOM CORPORATION + +OUI:40D85507F* + ID_OUI_FROM_DATABASE=Wheatstone Corporation + +OUI:40D855080* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:40D855081* + ID_OUI_FROM_DATABASE=Sicon srl + +OUI:40D855082* + ID_OUI_FROM_DATABASE=ard sa + +OUI:40D855083* + ID_OUI_FROM_DATABASE=DELOPT + +OUI:40D855084* + ID_OUI_FROM_DATABASE=Papendorf Software Engineering GmbH + +OUI:40D855085* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:40D855086* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:40D855087* + ID_OUI_FROM_DATABASE=Bestel China + +OUI:40D855088* + ID_OUI_FROM_DATABASE=JEL SYSTEM CO., LTD. + +OUI:40D855089* + ID_OUI_FROM_DATABASE=WUHAN XINGTUXINKE ELECTRONIC CO.,LTD + +OUI:40D85508A* + ID_OUI_FROM_DATABASE=Leder Elektronik Design + +OUI:40D85508B* + ID_OUI_FROM_DATABASE=MeshWorks Wireless Oy + +OUI:40D85508C* + ID_OUI_FROM_DATABASE=Magnescale Co.,Ltd + +OUI:40D85508D* + ID_OUI_FROM_DATABASE=Boehme Nachrichtentechnik + +OUI:40D85508E* + ID_OUI_FROM_DATABASE=Lyngsoe Systems + +OUI:40D85508F* + ID_OUI_FROM_DATABASE=Excelitas + +OUI:40D855090* + ID_OUI_FROM_DATABASE=Axxess Identification Ltd + +OUI:40D855091* + ID_OUI_FROM_DATABASE=KDT + +OUI:40D855092* + ID_OUI_FROM_DATABASE=Wasserbauer GmbH + +OUI:40D855093* + ID_OUI_FROM_DATABASE=Sentry 360 Security + +OUI:40D855094* + ID_OUI_FROM_DATABASE=Nomad Digital Limited + +OUI:40D855095* + ID_OUI_FROM_DATABASE=Heart Force Medical + +OUI:40D855096* + ID_OUI_FROM_DATABASE=Comtel Electronics GmbH + +OUI:40D855097* + ID_OUI_FROM_DATABASE=Burton Technical Services LLC + +OUI:40D855098* + ID_OUI_FROM_DATABASE=Dave Srl + +OUI:40D855099* + ID_OUI_FROM_DATABASE=idcell co.ltd + +OUI:40D85509A* + ID_OUI_FROM_DATABASE=CoherentPlus Sdn Bhd + +OUI:40D85509B* + ID_OUI_FROM_DATABASE=Tokyo Denki Gijutsu Kogyo + +OUI:40D85509C* + ID_OUI_FROM_DATABASE=Keyware Solutions Inc. + +OUI:40D85509D* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:40D85509E* + ID_OUI_FROM_DATABASE=NanoPulse, Inc. + +OUI:40D85509F* + ID_OUI_FROM_DATABASE=Bascules Robbe nv + +OUI:40D8550A0* + ID_OUI_FROM_DATABASE=Quantronix, Inc. + +OUI:40D8550A1* + ID_OUI_FROM_DATABASE=ADVALY SYSTEM Inc. + +OUI:40D8550A2* + ID_OUI_FROM_DATABASE=Xemex NV + +OUI:40D8550A3* + ID_OUI_FROM_DATABASE=Telefrank GmbH + +OUI:40D8550A4* + ID_OUI_FROM_DATABASE=Resch Electronic Innovation GmbH + +OUI:40D8550A5* + ID_OUI_FROM_DATABASE=WooshCom Corporation + +OUI:40D8550A6* + ID_OUI_FROM_DATABASE=Alumbra Produtos Elétricos e Eletrônicos Ltda + +OUI:40D8550A7* + ID_OUI_FROM_DATABASE=First Design System Inc. + +OUI:40D8550A8* + ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH + +OUI:40D8550A9* + ID_OUI_FROM_DATABASE=Apantac LLC + +OUI:40D8550AA* + ID_OUI_FROM_DATABASE=Thermal Imaging Radar, LLC + +OUI:40D8550AB* + ID_OUI_FROM_DATABASE=Enel doo Belgrade + +OUI:40D8550AC* + ID_OUI_FROM_DATABASE=Fraunhofer HHI + +OUI:40D8550AD* + ID_OUI_FROM_DATABASE=Space Micro + +OUI:40D8550AE* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D8550AF* + ID_OUI_FROM_DATABASE=EnVerv Inc. + +OUI:40D8550B0* + ID_OUI_FROM_DATABASE=Micrologic + +OUI:40D8550B1* + ID_OUI_FROM_DATABASE=Nanjing TIANSU Automation Control System Co., Ltd. + +OUI:40D8550B2* + ID_OUI_FROM_DATABASE=Ever Trend Technology Development Limited + +OUI:40D8550B3* + ID_OUI_FROM_DATABASE=T.W.S. srl + +OUI:40D8550B4* + ID_OUI_FROM_DATABASE=MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD. + +OUI:40D8550B5* + ID_OUI_FROM_DATABASE=DATA SHARING CONSULTING + +OUI:40D8550B6* + ID_OUI_FROM_DATABASE=Telvent + +OUI:40D8550B7* + ID_OUI_FROM_DATABASE=ACD Elektronik GmbH + +OUI:40D8550B8* + ID_OUI_FROM_DATABASE=Ferlin Trading BV + +OUI:40D8550B9* + ID_OUI_FROM_DATABASE=WxBR Sistemas de Telecomunicacoes Ltda + +OUI:40D8550BA* + ID_OUI_FROM_DATABASE=PCH Engineering A/S + +OUI:40D8550BB* + ID_OUI_FROM_DATABASE=Whiptail + +OUI:40D8550BC* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D8550BD* + ID_OUI_FROM_DATABASE=iCOGNIZE GmbH + +OUI:40D8550BE* + ID_OUI_FROM_DATABASE=Manufacturing System Insights Inc + +OUI:40D8550BF* + ID_OUI_FROM_DATABASE=Shenzhen SETEC Power Co.,Ltd + +OUI:40D8550C0* + ID_OUI_FROM_DATABASE=ACT + +OUI:40D8550C1* + ID_OUI_FROM_DATABASE=Xepto Computing Inc + +OUI:40D8550C2* + ID_OUI_FROM_DATABASE=SC Techswarm SRL + +OUI:40D8550C3* + ID_OUI_FROM_DATABASE=APG CASH DRAWER + +OUI:40D8550C4* + ID_OUI_FROM_DATABASE=Inspired Systems + +OUI:40D8550C5* + ID_OUI_FROM_DATABASE=M.M. Elektrolab + +OUI:40D8550C6* + ID_OUI_FROM_DATABASE=comtime GmbH + +OUI:40D8550C7* + ID_OUI_FROM_DATABASE=insensiv GmbH + +OUI:40D8550C8* + ID_OUI_FROM_DATABASE=Mettler Toledo Hispeed + +OUI:40D8550C9* + ID_OUI_FROM_DATABASE=QUANTAFLOW + +OUI:40D8550CA* + ID_OUI_FROM_DATABASE=NEUTRIK AG + +OUI:40D8550CB* + ID_OUI_FROM_DATABASE=ReliOn Inc + +OUI:40D8550CC* + ID_OUI_FROM_DATABASE=ATEME + +OUI:40D8550CD* + ID_OUI_FROM_DATABASE=Logical Product + +OUI:40D8550CE* + ID_OUI_FROM_DATABASE=EST Analytical + +OUI:40D8550CF* + ID_OUI_FROM_DATABASE=Clark-MXR, Inc. + +OUI:40D8550D0* + ID_OUI_FROM_DATABASE=Icraft Oy + +OUI:40D8550D1* + ID_OUI_FROM_DATABASE=Cantada Inc + +OUI:40D8550D2* + ID_OUI_FROM_DATABASE=ELAN SYSTEMS + +OUI:40D8550D3* + ID_OUI_FROM_DATABASE=LECO Corporation + +OUI:40D8550D4* + ID_OUI_FROM_DATABASE=Mitsubishi Heavy Industries, Ltd. + +OUI:40D8550D5* + ID_OUI_FROM_DATABASE=Shimizu Electric Co., Ltd. + +OUI:40D8550D6* + ID_OUI_FROM_DATABASE=deskontrol electronics + +OUI:40D8550D7* + ID_OUI_FROM_DATABASE=Avant Technologies,Inc + +OUI:40D8550D8* + ID_OUI_FROM_DATABASE=NEXT! s.c. S.Piela B.Dryja + +OUI:40D8550D9* + ID_OUI_FROM_DATABASE=YUKO ELECTRIC CO.,LTD + +OUI:40D8550DA* + ID_OUI_FROM_DATABASE=Devialet SA + +OUI:40D8550DB* + ID_OUI_FROM_DATABASE=Top Connect OU + +OUI:40D8550DC* + ID_OUI_FROM_DATABASE=NVS Technologies Inc + +OUI:40D8550DD* + ID_OUI_FROM_DATABASE=Embed Limited + +OUI:40D8550DE* + ID_OUI_FROM_DATABASE=Vishay Nobel AB + +OUI:40D8550DF* + ID_OUI_FROM_DATABASE=Xadi Inc + +OUI:40D8550E0* + ID_OUI_FROM_DATABASE=Richter + +OUI:40D8550E1* + ID_OUI_FROM_DATABASE=STV Electronic GmbH + +OUI:40D8550E2* + ID_OUI_FROM_DATABASE=Keocko International + +OUI:40D8550E3* + ID_OUI_FROM_DATABASE=Medigus Ltd + +OUI:40D8550E4* + ID_OUI_FROM_DATABASE=ARAGO SYSTEMS + +OUI:40D8550E5* + ID_OUI_FROM_DATABASE=Triton Electronics LTD + +OUI:40D8550E6* + ID_OUI_FROM_DATABASE=Kyoritsu Electric Corp. + +OUI:40D8550E7* + ID_OUI_FROM_DATABASE=LIGHTSTAR + +OUI:40D8550E8* + ID_OUI_FROM_DATABASE=HEITEC AG + +OUI:40D8550E9* + ID_OUI_FROM_DATABASE=HAMEG GmbH + +OUI:40D8550EA* + ID_OUI_FROM_DATABASE=A-Z-E + +OUI:40D8550EB* + ID_OUI_FROM_DATABASE=WANTECH Networks + +OUI:40D8550EC* + ID_OUI_FROM_DATABASE=Sentry 360 Security + +OUI:40D8550ED* + ID_OUI_FROM_DATABASE=IntelliDesign Pty Ltd + +OUI:40D8550EE* + ID_OUI_FROM_DATABASE=Siegmar Zander HuSWare + +OUI:40D8550EF* + ID_OUI_FROM_DATABASE=GeneSys Elektronik GmbH + +OUI:40D8550F0* + ID_OUI_FROM_DATABASE=Redwood Systems + +OUI:40D8550F1* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + +OUI:40D8550F2* + ID_OUI_FROM_DATABASE=SigmaPhi Electronics + +OUI:40D8550F3* + ID_OUI_FROM_DATABASE=ECON Systems Inc. + +OUI:40D8550F4* + ID_OUI_FROM_DATABASE=MB Connect Line GmbH + +OUI:40D8550F5* + ID_OUI_FROM_DATABASE=CST Group + +OUI:40D8550F7* + ID_OUI_FROM_DATABASE=Comline Elektronik Elektrotechnik GmbH + +OUI:40D8550F8* + ID_OUI_FROM_DATABASE=Better Place + +OUI:40D8550F9* + ID_OUI_FROM_DATABASE=Invisua Lighting BV + +OUI:40D8550FA* + ID_OUI_FROM_DATABASE=Marmitek BV + +OUI:40D8550FB* + ID_OUI_FROM_DATABASE=InfoMac Sp. z o. o. Sp. k. + +OUI:40D8550FC* + ID_OUI_FROM_DATABASE=eumig industrie-tv GmbH + +OUI:40D8550FD* + ID_OUI_FROM_DATABASE=MONOGRAM technologies ltd + +OUI:40D8550FE* + ID_OUI_FROM_DATABASE=Cytech Technology Pte Ltd + +OUI:40D8550FF* + ID_OUI_FROM_DATABASE=YUYAMA MFG.CO.,LTD. + +OUI:40D855100* + ID_OUI_FROM_DATABASE=TASK SISTEMAS DE COMPUTACAO S.A. + +OUI:40D855101* + ID_OUI_FROM_DATABASE=e.p.g. Elettronica Srl + +OUI:40D855102* + ID_OUI_FROM_DATABASE=Power Electronics + +OUI:40D855103* + ID_OUI_FROM_DATABASE=Peek Traffic Corporation + +OUI:40D855104* + ID_OUI_FROM_DATABASE=IMPLE SISTEMAS ELETRONICOS EMBARCADOS LTDA + +OUI:40D855105* + ID_OUI_FROM_DATABASE=Tieline Research Pty Ltd + +OUI:40D855106* + ID_OUI_FROM_DATABASE=Orbital A/S + +OUI:40D855107* + ID_OUI_FROM_DATABASE=Smith Meter, Inc + +OUI:40D855108* + ID_OUI_FROM_DATABASE=ALPHA DESIGN CO.,LTD. + +OUI:40D855109* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:40D85510A* + ID_OUI_FROM_DATABASE=DAVIS DERBY LIMITED + +OUI:40D85510B* + ID_OUI_FROM_DATABASE=So-Cool Corporation. + +OUI:40D85510C* + ID_OUI_FROM_DATABASE=Contrans TI sp. z o.o. + +OUI:40D85510D* + ID_OUI_FROM_DATABASE=Rite-Tech Industrial CO., Ltd. + +OUI:40D85510E* + ID_OUI_FROM_DATABASE=HKS-Prozesstechnik GmbH + +OUI:40D85510F* + ID_OUI_FROM_DATABASE=CAVALRY STORAGE INC + +OUI:40D855110* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D855111* + ID_OUI_FROM_DATABASE=Grupo Epelsa S.L. + +OUI:40D855112* + ID_OUI_FROM_DATABASE=Halliburton - Sperry Drilling Service + +OUI:40D855113* + ID_OUI_FROM_DATABASE=Testbook Ltd + +OUI:40D855114* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D855115* + ID_OUI_FROM_DATABASE=MESA Electronic GmbH + +OUI:40D855116* + ID_OUI_FROM_DATABASE=Uniscan LLC + +OUI:40D855117* + ID_OUI_FROM_DATABASE=RCS Energy Management Limited + +OUI:40D855118* + ID_OUI_FROM_DATABASE=University of Nebraska -- Lincoln + +OUI:40D855119* + ID_OUI_FROM_DATABASE=OOO Group of Industrial Technologies + +OUI:40D85511A* + ID_OUI_FROM_DATABASE=Sicon srl + +OUI:40D85511B* + ID_OUI_FROM_DATABASE=nanoTRONIC GmbH + +OUI:40D85511C* + ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH + +OUI:40D85511D* + ID_OUI_FROM_DATABASE=ACD Elektronik GmBH + +OUI:40D85511E* + ID_OUI_FROM_DATABASE=CEMSI, Inc. + +OUI:40D85511F* + ID_OUI_FROM_DATABASE=KOMPAN Pawel Sokolowski + +OUI:40D855120* + ID_OUI_FROM_DATABASE=ObjectFab GmbH + +OUI:40D855121* + ID_OUI_FROM_DATABASE=shanghai Anjian Information technology co. , ltd. + +OUI:40D855122* + ID_OUI_FROM_DATABASE=ATX Networks Ltd. + +OUI:40D855123* + ID_OUI_FROM_DATABASE=ZAO NPC Kompjuternie Technologii + +OUI:40D855124* + ID_OUI_FROM_DATABASE=Debug s.r.l. + +OUI:40D855125* + ID_OUI_FROM_DATABASE=Scandyna A/S + +OUI:40D855126* + ID_OUI_FROM_DATABASE=TTI LTD + +OUI:40D855127* + ID_OUI_FROM_DATABASE=LIGHTSTAR + +OUI:40D855128* + ID_OUI_FROM_DATABASE=Akse srl + +OUI:40D855129* + ID_OUI_FROM_DATABASE=DSP DESIGN + +OUI:40D85512A* + ID_OUI_FROM_DATABASE=Jadpod Communication Company Limited + +OUI:40D85512B* + ID_OUI_FROM_DATABASE=Mango DSP, Inc. + +OUI:40D85512C* + ID_OUI_FROM_DATABASE=NSP Europe Ltd + +OUI:40D85512D* + ID_OUI_FROM_DATABASE=Biotage Sweden AB + +OUI:40D85512E* + ID_OUI_FROM_DATABASE=Canfield Scientific, Inc. + +OUI:40D855130* + ID_OUI_FROM_DATABASE=GSP Sprachtechnologie GmbH + +OUI:40D855131* + ID_OUI_FROM_DATABASE=EMAC, INC. + +OUI:40D855132* + ID_OUI_FROM_DATABASE=AeroVision Avionics, Inc + +OUI:40D855133* + ID_OUI_FROM_DATABASE=Tattile srl + +OUI:40D855134* + ID_OUI_FROM_DATABASE=digitech GmbH & Co. KG + +OUI:40D855135* + ID_OUI_FROM_DATABASE=GLOBALCOM ENGINEERING SRL + +OUI:40D855136* + ID_OUI_FROM_DATABASE=Devriecom B.V. + +OUI:40D855137* + ID_OUI_FROM_DATABASE=GDE Polska + +OUI:40D855138* + ID_OUI_FROM_DATABASE=Calon Associates Limited + +OUI:40D855139* + ID_OUI_FROM_DATABASE=WOW System + +OUI:40D85513A* + ID_OUI_FROM_DATABASE=Supplier Ind. e Com de Eletroeletrônicos + +OUI:40D85513B* + ID_OUI_FROM_DATABASE=Davin Technologies Co.,Ltd + +OUI:40D85513C* + ID_OUI_FROM_DATABASE=shanghai anjian Information technology co. , ltd. + +OUI:40D85513D* + ID_OUI_FROM_DATABASE=Perm Scientific-Industrial Instrument Making Company JSC + +OUI:40D85513E* + ID_OUI_FROM_DATABASE=hanatech + +OUI:40D85513F* + ID_OUI_FROM_DATABASE=Zhejiang Wellsun Electric Meter Co.,Ltd + +OUI:40D855140* + ID_OUI_FROM_DATABASE=InnoTrans Communications, Inc + +OUI:40D855141* + ID_OUI_FROM_DATABASE=Key Systems, Inc. + +OUI:40D855142* + ID_OUI_FROM_DATABASE=Tetracore, Inc. + +OUI:40D855143* + ID_OUI_FROM_DATABASE=Tokyo Drawing Ltd. + +OUI:40D855144* + ID_OUI_FROM_DATABASE=Venco + +OUI:40D855145* + ID_OUI_FROM_DATABASE=Weber Marking Systems GmbH + +OUI:40D855146* + ID_OUI_FROM_DATABASE=Pleiger Elektronik GmbH and Co. KG + +OUI:40D855147* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D855148* + ID_OUI_FROM_DATABASE=SEIKO TIME SYSTEMS INC. + +OUI:40D855149* + ID_OUI_FROM_DATABASE=Engage Technologies + +OUI:40D85514A* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D85514C* + ID_OUI_FROM_DATABASE=PLT + +OUI:40D85514D* + ID_OUI_FROM_DATABASE=SOMFY SAS + +OUI:40D85514E* + ID_OUI_FROM_DATABASE=Marposs S.p.A + +OUI:40D85514F* + ID_OUI_FROM_DATABASE=TDS Software Solutions Pty Ltd + +OUI:40D855150* + ID_OUI_FROM_DATABASE=SHIKINO HIGH-TECH + +OUI:40D855151* + ID_OUI_FROM_DATABASE=Progress Rail Services, Inspection and Information Systems + +OUI:40D855152* + ID_OUI_FROM_DATABASE=Home Automation Europe + +OUI:40D855153* + ID_OUI_FROM_DATABASE=BlinkPipe Ltd + +OUI:40D855154* + ID_OUI_FROM_DATABASE=iart + +OUI:40D855155* + ID_OUI_FROM_DATABASE=Telefrang AB + +OUI:40D855156* + ID_OUI_FROM_DATABASE=Emphysys, Inc. + +OUI:40D855157* + ID_OUI_FROM_DATABASE=Hitachi Power Solutions Co., Ltd. + +OUI:40D855158* + ID_OUI_FROM_DATABASE=Exibea AB + +OUI:40D855159* + ID_OUI_FROM_DATABASE=PLATINUM GmbH + +OUI:40D85515A* + ID_OUI_FROM_DATABASE=DORLET S.A.U + +OUI:40D85515B* + ID_OUI_FROM_DATABASE=SQF Spezialelektronik GmbH + +OUI:40D85515C* + ID_OUI_FROM_DATABASE=Spectratech Inc. + +OUI:40D85515D* + ID_OUI_FROM_DATABASE=Actronic Technologies + +OUI:40D85515E* + ID_OUI_FROM_DATABASE=Prodco International Inc. + +OUI:40D85515F* + ID_OUI_FROM_DATABASE=CT COMPANY + +OUI:40D855160* + ID_OUI_FROM_DATABASE=Thermo Fisher Sceintific + +OUI:40D855161* + ID_OUI_FROM_DATABASE=Solidscape Inc + +OUI:40D855162* + ID_OUI_FROM_DATABASE=LUNA-NEXUS + +OUI:40D855163* + ID_OUI_FROM_DATABASE=KMtronic LTD + +OUI:40D855164* + ID_OUI_FROM_DATABASE=NFT Automatisierungssysteme GmbH + +OUI:40D855165* + ID_OUI_FROM_DATABASE=TECHBOARD SRL + +OUI:40D855166* + ID_OUI_FROM_DATABASE=Anhui Jiante Network Technology Co., Ltd. + +OUI:40D855167* + ID_OUI_FROM_DATABASE=Assembly Contracts Ltd + +OUI:40D855168* + ID_OUI_FROM_DATABASE=OPASCA Systems GmbH + +OUI:40D855169* + ID_OUI_FROM_DATABASE=Photop Koncent + +OUI:40D85516A* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D85516B* + ID_OUI_FROM_DATABASE=TECHWAY + +OUI:40D85516D* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D85516E* + ID_OUI_FROM_DATABASE=Secuinfo Co.Ltd + +OUI:40D85516F* + ID_OUI_FROM_DATABASE=BrightLeaf Power + +OUI:40D855170* + ID_OUI_FROM_DATABASE=ICS Eletronics + +OUI:40D855171* + ID_OUI_FROM_DATABASE=Sicon srl + +OUI:40D855172* + ID_OUI_FROM_DATABASE=YAWATA ELECTRIC INDUSTRIAL CO.,LTD. + +OUI:40D855173* + ID_OUI_FROM_DATABASE=Contec Steuerungstechnik & Automation GmbH + +OUI:40D855174* + ID_OUI_FROM_DATABASE=EcoGuard AB + +OUI:40D855175* + ID_OUI_FROM_DATABASE=AHB Systeme GmbH + +OUI:40D855176* + ID_OUI_FROM_DATABASE=Schneider Electric Motion, Inc. USA + +OUI:40D855177* + ID_OUI_FROM_DATABASE=TRI Engineering co.,ltd. + +OUI:40D855178* + ID_OUI_FROM_DATABASE=REDER Domotic GmbH + +OUI:40D855179* + ID_OUI_FROM_DATABASE=Servo-Robot Inc. + +OUI:40D85517A* + ID_OUI_FROM_DATABASE=ARGUS-SPECTRUM + +OUI:40D85517B* + ID_OUI_FROM_DATABASE=LUCEO + +OUI:40D85517C* + ID_OUI_FROM_DATABASE=Critical Link + +OUI:40D85517D* + ID_OUI_FROM_DATABASE=Kiwigrid GmbH + +OUI:40D85517E* + ID_OUI_FROM_DATABASE=TOKHATEC + +OUI:40D85517F* + ID_OUI_FROM_DATABASE=Telvent + +OUI:40D855180* + ID_OUI_FROM_DATABASE=BroadSoft Inc + +OUI:40D855181* + ID_OUI_FROM_DATABASE=eROCCA + +OUI:40D855182* + ID_OUI_FROM_DATABASE=Georg Neumann GmbH + +OUI:40D855183* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:40D855184* + ID_OUI_FROM_DATABASE=Satkirit Ltd + +OUI:40D855185* + ID_OUI_FROM_DATABASE=Standard Change Makers + +OUI:40D855186* + ID_OUI_FROM_DATABASE=KST technology + +OUI:40D855187* + ID_OUI_FROM_DATABASE=CDEX Corp. + +OUI:40D855188* + ID_OUI_FROM_DATABASE=Array Corporation + +OUI:40D855189* + ID_OUI_FROM_DATABASE=Yoozma Corporation + +OUI:40D85518A* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D85518B* + ID_OUI_FROM_DATABASE=Diagnosys Test Systems Ltd + +OUI:40D85518C* + ID_OUI_FROM_DATABASE=EOS S.r.l. + +OUI:40D85518D* + ID_OUI_FROM_DATABASE=Zoe Medical + +OUI:40D85518E* + ID_OUI_FROM_DATABASE=Kerun Visual Technology Co., Ltd.(Shenzhen) + +OUI:40D85518F* + ID_OUI_FROM_DATABASE=Beat Sensing co. , ltd. + +OUI:40D855190* + ID_OUI_FROM_DATABASE=Spider Tecnologia Ind. e Com Ltda + +OUI:40D855191* + ID_OUI_FROM_DATABASE=Soukai Electric + +OUI:40D855192* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSTEMS + +OUI:40D855193* + ID_OUI_FROM_DATABASE=FORZA SILICON CORP. + +OUI:40D855194* + ID_OUI_FROM_DATABASE=RF Code + +OUI:40D855195* + ID_OUI_FROM_DATABASE=TONNA ELECTRONIQUE + +OUI:40D855196* + ID_OUI_FROM_DATABASE=Advanced Micro Controls Inc. + +OUI:40D855197* + ID_OUI_FROM_DATABASE=Berg Cloud Limited + +OUI:40D855198* + ID_OUI_FROM_DATABASE=devboards GmbH + +OUI:40D855199* + ID_OUI_FROM_DATABASE=PRESSOL Schmiergeraete GmbH + +OUI:40D85519A* + ID_OUI_FROM_DATABASE=Rohde&Schwarz Topex SA + +OUI:40D85519B* + ID_OUI_FROM_DATABASE=Northern Star Technologies + +OUI:40D85519C* + ID_OUI_FROM_DATABASE=Parris Service Corporation + +OUI:40D85519D* + ID_OUI_FROM_DATABASE=EMAC, Inc. + +OUI:40D85519E* + ID_OUI_FROM_DATABASE=Thirdwayv Inc. + +OUI:40D85519F* + ID_OUI_FROM_DATABASE=Patria Aviation Oy + +OUI:40D8551A0* + ID_OUI_FROM_DATABASE=Futaba Corporation + +OUI:40D8551A1* + ID_OUI_FROM_DATABASE=KRONOTECH SRL + +OUI:40D8551A2* + ID_OUI_FROM_DATABASE=HIPODROMO DE AGUA CALIENTE, S.A. DE C.V. + +OUI:40D8551A3* + ID_OUI_FROM_DATABASE=Noritake Itron Corporation + +OUI:40D8551A4* + ID_OUI_FROM_DATABASE=cibite AG + +OUI:40D8551A5* + ID_OUI_FROM_DATABASE=DemoPad + +OUI:40D8551A6* + ID_OUI_FROM_DATABASE=RB-LINK Wireless + +OUI:40D8551A7* + ID_OUI_FROM_DATABASE=ENTEC Electric & Electronic CO., LTD + +OUI:40D8551A8* + ID_OUI_FROM_DATABASE=Multiobrabotka + +OUI:40D8551A9* + ID_OUI_FROM_DATABASE=Lubino s.r.o. + +OUI:40D8551AA* + ID_OUI_FROM_DATABASE=Broachlink Technology Co.,Limited + +OUI:40D8551AB* + ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited + +OUI:40D8551AC* + ID_OUI_FROM_DATABASE=ELAN SYSTEMS + +OUI:40D8551AD* + ID_OUI_FROM_DATABASE=WICHER DIGITAL TECHNIK + +OUI:40D8551AE* + ID_OUI_FROM_DATABASE=Autonomous Solutions, Inc + +OUI:40D8551AF* + ID_OUI_FROM_DATABASE=Vigitron Inc. + +OUI:40D8551B0* + ID_OUI_FROM_DATABASE=Shin-ei Electronic Measuring Co.,Ltd. + +OUI:40D8551B1* + ID_OUI_FROM_DATABASE=Logos 01 S.r.l. + +OUI:40D8551B2* + ID_OUI_FROM_DATABASE=AGE A. Gilg Elektronik + +OUI:40D8551B3* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:40D8551B4* + ID_OUI_FROM_DATABASE=Inforce Computing Inc. + +OUI:40D8551B5* + ID_OUI_FROM_DATABASE=A+EC Klein Ingenieurbuero + +OUI:40D8551B6* + ID_OUI_FROM_DATABASE=Magic Systems + +OUI:40D8551B7* + ID_OUI_FROM_DATABASE=TEWS Elektronik GmbH & Co. KG + +OUI:40D8551B8* + ID_OUI_FROM_DATABASE=Orion Systems, Inc + +OUI:40D8551B9* + ID_OUI_FROM_DATABASE=Beking Industrieele automatisering + +OUI:40D8551BA* + ID_OUI_FROM_DATABASE=Creative Lighting And Sound Systems Pty Ltd + +OUI:40D8551BB* + ID_OUI_FROM_DATABASE=Micromega Dynamics SA + +OUI:40D8551BC* + ID_OUI_FROM_DATABASE=KbDevice,Inc. + +OUI:40D8551BD* + ID_OUI_FROM_DATABASE=HORIBA ABX + +OUI:40D8551BE* + ID_OUI_FROM_DATABASE=PEEK TRAFFIC + +OUI:40D8551BF* + ID_OUI_FROM_DATABASE=shanghai mingding information tech co.Ltd + +OUI:40D8551C0* + ID_OUI_FROM_DATABASE=NPB Automation AB + +OUI:40D8551C1* + ID_OUI_FROM_DATABASE=Triamec Motion AG + +OUI:40D8551C2* + ID_OUI_FROM_DATABASE=Digital Display Systems + +OUI:40D8551C3* + ID_OUI_FROM_DATABASE=Cornfed Systems LLC + +OUI:40D8551C4* + ID_OUI_FROM_DATABASE=QED Advanced Systems Limited + +OUI:40D8551C6* + ID_OUI_FROM_DATABASE=Device Solutions Ltd + +OUI:40D8551C7* + ID_OUI_FROM_DATABASE=Wexiödisk AB + +OUI:40D8551C8* + ID_OUI_FROM_DATABASE=Sensata Technologies + +OUI:40D8551C9* + ID_OUI_FROM_DATABASE=Andy-L Ltd. + +OUI:40D8551CA* + ID_OUI_FROM_DATABASE=Rigel Engineering + +OUI:40D8551CB* + ID_OUI_FROM_DATABASE=MG S.r.l. + +OUI:40D8551CD* + ID_OUI_FROM_DATABASE=YXLON International A/S + +OUI:40D8551CE* + ID_OUI_FROM_DATABASE=Peter Huber + +OUI:40D8551CF* + ID_OUI_FROM_DATABASE=Omnik New Energy Co., Ltd + +OUI:40D8551D0* + ID_OUI_FROM_DATABASE=Webeasy BV + +OUI:40D8551D1* + ID_OUI_FROM_DATABASE=Founder Broadband Network Service Co.,Ltd. + +OUI:40D8551D2* + ID_OUI_FROM_DATABASE=InventLab s.c. + +OUI:40D8551D3* + ID_OUI_FROM_DATABASE=Kaluga Teletypes Manufacturing Plant + +OUI:40D8551D4* + ID_OUI_FROM_DATABASE=Prisma Engineering srl + +OUI:40D8551D5* + ID_OUI_FROM_DATABASE=FST21 Ltd. + +OUI:40D8551D6* + ID_OUI_FROM_DATABASE=EMS Computers Pty Ltd + +OUI:40D8551D7* + ID_OUI_FROM_DATABASE=Wheatstone Corporation + +OUI:40D8551D8* + ID_OUI_FROM_DATABASE=Owl Computing Technologies, Inc. + +OUI:40D8551D9* + ID_OUI_FROM_DATABASE=Commercial Wireless Systems International LLC. + +OUI:40D8551DA* + ID_OUI_FROM_DATABASE=Energy Technology and Control Ltd. + +OUI:40D8551DB* + ID_OUI_FROM_DATABASE=NIPPON TECHNO LAB.,INC, + +OUI:40D8551DC* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:40D8551DD* + ID_OUI_FROM_DATABASE=BaOpt Benelux bv + +OUI:40D8551DE* + ID_OUI_FROM_DATABASE=Vidisys GmbH + +OUI:40D8551DF* + ID_OUI_FROM_DATABASE=Chengdu Meihuan Technology Co.,Ltd + +OUI:40D8551E0* + ID_OUI_FROM_DATABASE=Embedded Technology Corporation + +OUI:40D8551E1* + ID_OUI_FROM_DATABASE=AD QUALITE + +OUI:40D8551E2* + ID_OUI_FROM_DATABASE=ELNEC s.r.o. + +OUI:40D8551E3* + ID_OUI_FROM_DATABASE=Mega Electronics Ltd + +OUI:40D8551E4* + ID_OUI_FROM_DATABASE=STEK Ltd + +OUI:40D855EE6* + ID_OUI_FROM_DATABASE=Narinet, Inc. + +OUI:000000* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000001* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000002* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000003* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000004* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000005* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000006* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000007* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000008* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:000009* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:00000A* + ID_OUI_FROM_DATABASE=OMRON TATEISI ELECTRONICS CO. + +OUI:00000B* + ID_OUI_FROM_DATABASE=MATRIX CORPORATION + +OUI:00000C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00000D* + ID_OUI_FROM_DATABASE=FIBRONICS LTD. + +OUI:00000E* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED + +OUI:00000F* + ID_OUI_FROM_DATABASE=NEXT, INC. + +OUI:000010* + ID_OUI_FROM_DATABASE=SYTEK INC. + +OUI:000011* + ID_OUI_FROM_DATABASE=NORMEREL SYSTEMES + +OUI:000012* + ID_OUI_FROM_DATABASE=INFORMATION TECHNOLOGY LIMITED + +OUI:000013* + ID_OUI_FROM_DATABASE=CAMEX + +OUI:000014* + ID_OUI_FROM_DATABASE=NETRONIX + +OUI:000015* + ID_OUI_FROM_DATABASE=DATAPOINT CORPORATION + +OUI:000016* + ID_OUI_FROM_DATABASE=DU PONT PIXEL SYSTEMS . + +OUI:000017* + ID_OUI_FROM_DATABASE=TEKELEC + +OUI:000018* + ID_OUI_FROM_DATABASE=WEBSTER COMPUTER CORPORATION + +OUI:000019* + ID_OUI_FROM_DATABASE=APPLIED DYNAMICS INTERNATIONAL + +OUI:00001A* + ID_OUI_FROM_DATABASE=ADVANCED MICRO DEVICES + +OUI:00001B* + ID_OUI_FROM_DATABASE=NOVELL INC. + +OUI:00001C* + ID_OUI_FROM_DATABASE=BELL TECHNOLOGIES + +OUI:00001D* + ID_OUI_FROM_DATABASE=CABLETRON SYSTEMS, INC. + +OUI:00001E* + ID_OUI_FROM_DATABASE=TELSIST INDUSTRIA ELECTRONICA + +OUI:00001F* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:000020* + ID_OUI_FROM_DATABASE=DATAINDUSTRIER DIAB AB + +OUI:000021* + ID_OUI_FROM_DATABASE=SUREMAN COMP. & COMMUN. CORP. + +OUI:000022* + ID_OUI_FROM_DATABASE=VISUAL TECHNOLOGY INC. + +OUI:000023* + ID_OUI_FROM_DATABASE=ABB INDUSTRIAL SYSTEMS AB + +OUI:000024* + ID_OUI_FROM_DATABASE=CONNECT AS + +OUI:000025* + ID_OUI_FROM_DATABASE=RAMTEK CORP. + +OUI:000026* + ID_OUI_FROM_DATABASE=SHA-KEN CO., LTD. + +OUI:000027* + ID_OUI_FROM_DATABASE=JAPAN RADIO COMPANY + +OUI:000028* + ID_OUI_FROM_DATABASE=PRODIGY SYSTEMS CORPORATION + +OUI:000029* + ID_OUI_FROM_DATABASE=IMC NETWORKS CORP. + +OUI:00002A* + ID_OUI_FROM_DATABASE=TRW - SEDD/INP + +OUI:00002B* + ID_OUI_FROM_DATABASE=CRISP AUTOMATION, INC + +OUI:00002C* + ID_OUI_FROM_DATABASE=AUTOTOTE LIMITED + +OUI:00002D* + ID_OUI_FROM_DATABASE=CHROMATICS INC + +OUI:00002E* + ID_OUI_FROM_DATABASE=SOCIETE EVIRA + +OUI:00002F* + ID_OUI_FROM_DATABASE=TIMEPLEX INC. + +OUI:000030* + ID_OUI_FROM_DATABASE=VG LABORATORY SYSTEMS LTD + +OUI:000031* + ID_OUI_FROM_DATABASE=QPSX COMMUNICATIONS PTY LTD + +OUI:000032* + ID_OUI_FROM_DATABASE=Marconi plc + +OUI:000033* + ID_OUI_FROM_DATABASE=EGAN MACHINERY COMPANY + +OUI:000034* + ID_OUI_FROM_DATABASE=NETWORK RESOURCES CORPORATION + +OUI:000035* + ID_OUI_FROM_DATABASE=SPECTRAGRAPHICS CORPORATION + +OUI:000036* + ID_OUI_FROM_DATABASE=ATARI CORPORATION + +OUI:000037* + ID_OUI_FROM_DATABASE=OXFORD METRICS LIMITED + +OUI:000038* + ID_OUI_FROM_DATABASE=CSS LABS + +OUI:000039* + ID_OUI_FROM_DATABASE=TOSHIBA CORPORATION + +OUI:00003A* + ID_OUI_FROM_DATABASE=CHYRON CORPORATION + +OUI:00003B* + ID_OUI_FROM_DATABASE=i Controls, Inc. + +OUI:00003C* + ID_OUI_FROM_DATABASE=AUSPEX SYSTEMS INC. + +OUI:00003D* + ID_OUI_FROM_DATABASE=UNISYS + +OUI:00003E* + ID_OUI_FROM_DATABASE=SIMPACT + +OUI:00003F* + ID_OUI_FROM_DATABASE=SYNTREX, INC. + +OUI:000040* + ID_OUI_FROM_DATABASE=APPLICON, INC. + +OUI:000041* + ID_OUI_FROM_DATABASE=ICE CORPORATION + +OUI:000042* + ID_OUI_FROM_DATABASE=METIER MANAGEMENT SYSTEMS LTD. + +OUI:000043* + ID_OUI_FROM_DATABASE=MICRO TECHNOLOGY + +OUI:000044* + ID_OUI_FROM_DATABASE=CASTELLE CORPORATION + +OUI:000045* + ID_OUI_FROM_DATABASE=FORD AEROSPACE & COMM. CORP. + +OUI:000046* + ID_OUI_FROM_DATABASE=OLIVETTI NORTH AMERICA + +OUI:000047* + ID_OUI_FROM_DATABASE=NICOLET INSTRUMENTS CORP. + +OUI:000048* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:000049* + ID_OUI_FROM_DATABASE=APRICOT COMPUTERS, LTD + +OUI:00004A* + ID_OUI_FROM_DATABASE=ADC CODENOLL TECHNOLOGY CORP. + +OUI:00004B* + ID_OUI_FROM_DATABASE=ICL DATA OY + +OUI:00004C* + ID_OUI_FROM_DATABASE=NEC CORPORATION + +OUI:00004D* + ID_OUI_FROM_DATABASE=DCI CORPORATION + +OUI:00004E* + ID_OUI_FROM_DATABASE=AMPEX CORPORATION + +OUI:00004F* + ID_OUI_FROM_DATABASE=LOGICRAFT, INC. + +OUI:000050* + ID_OUI_FROM_DATABASE=RADISYS CORPORATION + +OUI:000051* + ID_OUI_FROM_DATABASE=HOB ELECTRONIC GMBH & CO. KG + +OUI:000052* + ID_OUI_FROM_DATABASE=Intrusion.com, Inc. + +OUI:000053* + ID_OUI_FROM_DATABASE=COMPUCORP + +OUI:000054* + ID_OUI_FROM_DATABASE=Schnieder Electric + +OUI:000055* + ID_OUI_FROM_DATABASE=COMMISSARIAT A L`ENERGIE ATOM. + +OUI:000056* + ID_OUI_FROM_DATABASE=DR. B. STRUCK + +OUI:000057* + ID_OUI_FROM_DATABASE=SCITEX CORPORATION LTD. + +OUI:000058* + ID_OUI_FROM_DATABASE=RACORE COMPUTER PRODUCTS INC. + +OUI:000059* + ID_OUI_FROM_DATABASE=HELLIGE GMBH + +OUI:00005A* + ID_OUI_FROM_DATABASE=SysKonnect GmbH + +OUI:00005B* + ID_OUI_FROM_DATABASE=ELTEC ELEKTRONIK AG + +OUI:00005C* + ID_OUI_FROM_DATABASE=TELEMATICS INTERNATIONAL INC. + +OUI:00005D* + ID_OUI_FROM_DATABASE=CS TELECOM + +OUI:00005E* + ID_OUI_FROM_DATABASE=ICANN, IANA Department + +OUI:00005F* + ID_OUI_FROM_DATABASE=SUMITOMO ELECTRIC IND., LTD. + +OUI:000060* + ID_OUI_FROM_DATABASE=KONTRON ELEKTRONIK GMBH + +OUI:000061* + ID_OUI_FROM_DATABASE=GATEWAY COMMUNICATIONS + +OUI:000062* + ID_OUI_FROM_DATABASE=BULL HN INFORMATION SYSTEMS + +OUI:000063* + ID_OUI_FROM_DATABASE=BARCO CONTROL ROOMS GMBH + +OUI:000064* + ID_OUI_FROM_DATABASE=YOKOGAWA DIGITAL COMPUTER CORP + +OUI:000065* + ID_OUI_FROM_DATABASE=Network General Corporation + +OUI:000066* + ID_OUI_FROM_DATABASE=TALARIS SYSTEMS, INC. + +OUI:000067* + ID_OUI_FROM_DATABASE=SOFT * RITE, INC. + +OUI:000068* + ID_OUI_FROM_DATABASE=ROSEMOUNT CONTROLS + +OUI:000069* + ID_OUI_FROM_DATABASE=CONCORD COMMUNICATIONS INC + +OUI:00006A* + ID_OUI_FROM_DATABASE=COMPUTER CONSOLES INC. + +OUI:00006B* + ID_OUI_FROM_DATABASE=SILICON GRAPHICS INC./MIPS + +OUI:00006D* + ID_OUI_FROM_DATABASE=CRAY COMMUNICATIONS, LTD. + +OUI:00006E* + ID_OUI_FROM_DATABASE=ARTISOFT, INC. + +OUI:00006F* + ID_OUI_FROM_DATABASE=Madge Ltd. + +OUI:000070* + ID_OUI_FROM_DATABASE=HCL LIMITED + +OUI:000071* + ID_OUI_FROM_DATABASE=ADRA SYSTEMS INC. + +OUI:000072* + ID_OUI_FROM_DATABASE=MINIWARE TECHNOLOGY + +OUI:000073* + ID_OUI_FROM_DATABASE=SIECOR CORPORATION + +OUI:000074* + ID_OUI_FROM_DATABASE=RICOH COMPANY LTD. + +OUI:000075* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000076* + ID_OUI_FROM_DATABASE=ABEKAS VIDEO SYSTEM + +OUI:000077* + ID_OUI_FROM_DATABASE=INTERPHASE CORPORATION + +OUI:000078* + ID_OUI_FROM_DATABASE=LABTAM LIMITED + +OUI:000079* + ID_OUI_FROM_DATABASE=NETWORTH INCORPORATED + +OUI:00007A* + ID_OUI_FROM_DATABASE=DANA COMPUTER INC. + +OUI:00007B* + ID_OUI_FROM_DATABASE=RESEARCH MACHINES + +OUI:00007C* + ID_OUI_FROM_DATABASE=AMPERE INCORPORATED + +OUI:00007D* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:00007E* + ID_OUI_FROM_DATABASE=CLUSTRIX CORPORATION + +OUI:00007F* + ID_OUI_FROM_DATABASE=LINOTYPE-HELL AG + +OUI:000080* + ID_OUI_FROM_DATABASE=CRAY COMMUNICATIONS A/S + +OUI:000081* + ID_OUI_FROM_DATABASE=BAY NETWORKS + +OUI:000082* + ID_OUI_FROM_DATABASE=LECTRA SYSTEMES SA + +OUI:000083* + ID_OUI_FROM_DATABASE=TADPOLE TECHNOLOGY PLC + +OUI:000084* + ID_OUI_FROM_DATABASE=SUPERNET + +OUI:000085* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:000086* + ID_OUI_FROM_DATABASE=MEGAHERTZ CORPORATION + +OUI:000087* + ID_OUI_FROM_DATABASE=HITACHI, LTD. + +OUI:000088* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:000089* + ID_OUI_FROM_DATABASE=CAYMAN SYSTEMS INC. + +OUI:00008A* + ID_OUI_FROM_DATABASE=DATAHOUSE INFORMATION SYSTEMS + +OUI:00008B* + ID_OUI_FROM_DATABASE=INFOTRON + +OUI:00008C* + ID_OUI_FROM_DATABASE=Alloy Computer Products (Australia) Pty Ltd + +OUI:00008D* + ID_OUI_FROM_DATABASE=Cryptek Inc. + +OUI:00008E* + ID_OUI_FROM_DATABASE=SOLBOURNE COMPUTER, INC. + +OUI:00008F* + ID_OUI_FROM_DATABASE=Raytheon + +OUI:000090* + ID_OUI_FROM_DATABASE=MICROCOM + +OUI:000091* + ID_OUI_FROM_DATABASE=ANRITSU CORPORATION + +OUI:000092* + ID_OUI_FROM_DATABASE=COGENT DATA TECHNOLOGIES + +OUI:000093* + ID_OUI_FROM_DATABASE=PROTEON INC. + +OUI:000094* + ID_OUI_FROM_DATABASE=ASANTE TECHNOLOGIES + +OUI:000095* + ID_OUI_FROM_DATABASE=SONY TEKTRONIX CORP. + +OUI:000096* + ID_OUI_FROM_DATABASE=MARCONI ELECTRONICS LTD. + +OUI:000097* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:000098* + ID_OUI_FROM_DATABASE=CROSSCOMM CORPORATION + +OUI:000099* + ID_OUI_FROM_DATABASE=MTX, INC. + +OUI:00009A* + ID_OUI_FROM_DATABASE=RC COMPUTER A/S + +OUI:00009B* + ID_OUI_FROM_DATABASE=INFORMATION INTERNATIONAL, INC + +OUI:00009C* + ID_OUI_FROM_DATABASE=ROLM MIL-SPEC COMPUTERS + +OUI:00009D* + ID_OUI_FROM_DATABASE=LOCUS COMPUTING CORPORATION + +OUI:00009E* + ID_OUI_FROM_DATABASE=MARLI S.A. + +OUI:00009F* + ID_OUI_FROM_DATABASE=AMERISTAR TECHNOLOGIES INC. + +OUI:0000A0* + ID_OUI_FROM_DATABASE=SANYO Electric Co., Ltd. + +OUI:0000A1* + ID_OUI_FROM_DATABASE=MARQUETTE ELECTRIC CO. + +OUI:0000A2* + ID_OUI_FROM_DATABASE=BAY NETWORKS + +OUI:0000A3* + ID_OUI_FROM_DATABASE=NETWORK APPLICATION TECHNOLOGY + +OUI:0000A4* + ID_OUI_FROM_DATABASE=ACORN COMPUTERS LIMITED + +OUI:0000A5* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:0000A6* + ID_OUI_FROM_DATABASE=NETWORK GENERAL CORPORATION + +OUI:0000A7* + ID_OUI_FROM_DATABASE=NETWORK COMPUTING DEVICES INC. + +OUI:0000A8* + ID_OUI_FROM_DATABASE=STRATUS COMPUTER INC. + +OUI:0000A9* + ID_OUI_FROM_DATABASE=NETWORK SYSTEMS CORP. + +OUI:0000AA* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:0000AB* + ID_OUI_FROM_DATABASE=LOGIC MODELING CORPORATION + +OUI:0000AC* + ID_OUI_FROM_DATABASE=CONWARE COMPUTER CONSULTING + +OUI:0000AD* + ID_OUI_FROM_DATABASE=BRUKER INSTRUMENTS INC. + +OUI:0000AE* + ID_OUI_FROM_DATABASE=DASSAULT ELECTRONIQUE + +OUI:0000AF* + ID_OUI_FROM_DATABASE=NUCLEAR DATA INSTRUMENTATION + +OUI:0000B0* + ID_OUI_FROM_DATABASE=RND-RAD NETWORK DEVICES + +OUI:0000B1* + ID_OUI_FROM_DATABASE=ALPHA MICROSYSTEMS INC. + +OUI:0000B2* + ID_OUI_FROM_DATABASE=TELEVIDEO SYSTEMS, INC. + +OUI:0000B3* + ID_OUI_FROM_DATABASE=CIMLINC INCORPORATED + +OUI:0000B4* + ID_OUI_FROM_DATABASE=EDIMAX COMPUTER COMPANY + +OUI:0000B5* + ID_OUI_FROM_DATABASE=DATABILITY SOFTWARE SYS. INC. + +OUI:0000B6* + ID_OUI_FROM_DATABASE=MICRO-MATIC RESEARCH + +OUI:0000B7* + ID_OUI_FROM_DATABASE=DOVE COMPUTER CORPORATION + +OUI:0000B8* + ID_OUI_FROM_DATABASE=SEIKOSHA CO., LTD. + +OUI:0000B9* + ID_OUI_FROM_DATABASE=MCDONNELL DOUGLAS COMPUTER SYS + +OUI:0000BA* + ID_OUI_FROM_DATABASE=SIIG, INC. + +OUI:0000BB* + ID_OUI_FROM_DATABASE=TRI-DATA + +OUI:0000BC* + ID_OUI_FROM_DATABASE=Rockwell Automation + +OUI:0000BD* + ID_OUI_FROM_DATABASE=MITSUBISHI CABLE COMPANY + +OUI:0000BE* + ID_OUI_FROM_DATABASE=THE NTI GROUP + +OUI:0000BF* + ID_OUI_FROM_DATABASE=SYMMETRIC COMPUTER SYSTEMS + +OUI:0000C0* + ID_OUI_FROM_DATABASE=WESTERN DIGITAL CORPORATION + +OUI:0000C1* + ID_OUI_FROM_DATABASE=Madge Ltd. + +OUI:0000C2* + ID_OUI_FROM_DATABASE=INFORMATION PRESENTATION TECH. + +OUI:0000C3* + ID_OUI_FROM_DATABASE=HARRIS CORP COMPUTER SYS DIV + +OUI:0000C4* + ID_OUI_FROM_DATABASE=WATERS DIV. OF MILLIPORE + +OUI:0000C5* + ID_OUI_FROM_DATABASE=FARALLON COMPUTING/NETOPIA + +OUI:0000C6* + ID_OUI_FROM_DATABASE=EON SYSTEMS + +OUI:0000C7* + ID_OUI_FROM_DATABASE=ARIX CORPORATION + +OUI:0000C8* + ID_OUI_FROM_DATABASE=ALTOS COMPUTER SYSTEMS + +OUI:0000C9* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:0000CA* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0000CB* + ID_OUI_FROM_DATABASE=COMPU-SHACK ELECTRONIC GMBH + +OUI:0000CC* + ID_OUI_FROM_DATABASE=DENSAN CO., LTD. + +OUI:0000CD* + ID_OUI_FROM_DATABASE=Allied Telesis Labs Ltd + +OUI:0000CE* + ID_OUI_FROM_DATABASE=MEGADATA CORP. + +OUI:0000CF* + ID_OUI_FROM_DATABASE=HAYES MICROCOMPUTER PRODUCTS + +OUI:0000D0* + ID_OUI_FROM_DATABASE=DEVELCON ELECTRONICS LTD. + +OUI:0000D1* + ID_OUI_FROM_DATABASE=ADAPTEC INCORPORATED + +OUI:0000D2* + ID_OUI_FROM_DATABASE=SBE, INC. + +OUI:0000D3* + ID_OUI_FROM_DATABASE=WANG LABORATORIES INC. + +OUI:0000D4* + ID_OUI_FROM_DATABASE=PURE DATA LTD. + +OUI:0000D5* + ID_OUI_FROM_DATABASE=MICROGNOSIS INTERNATIONAL + +OUI:0000D6* + ID_OUI_FROM_DATABASE=PUNCH LINE HOLDING + +OUI:0000D7* + ID_OUI_FROM_DATABASE=DARTMOUTH COLLEGE + +OUI:0000D8* + ID_OUI_FROM_DATABASE=NOVELL, INC. + +OUI:0000D9* + ID_OUI_FROM_DATABASE=NIPPON TELEGRAPH & TELEPHONE + +OUI:0000DA* + ID_OUI_FROM_DATABASE=ATEX + +OUI:0000DB* + ID_OUI_FROM_DATABASE=British Telecommunications plc + +OUI:0000DC* + ID_OUI_FROM_DATABASE=HAYES MICROCOMPUTER PRODUCTS + +OUI:0000DD* + ID_OUI_FROM_DATABASE=TCL INCORPORATED + +OUI:0000DE* + ID_OUI_FROM_DATABASE=CETIA + +OUI:0000DF* + ID_OUI_FROM_DATABASE=BELL & HOWELL PUB SYS DIV + +OUI:0000E0* + ID_OUI_FROM_DATABASE=QUADRAM CORP. + +OUI:0000E1* + ID_OUI_FROM_DATABASE=GRID SYSTEMS + +OUI:0000E2* + ID_OUI_FROM_DATABASE=ACER TECHNOLOGIES CORP. + +OUI:0000E3* + ID_OUI_FROM_DATABASE=INTEGRATED MICRO PRODUCTS LTD + +OUI:0000E4* + ID_OUI_FROM_DATABASE=IN2 GROUPE INTERTECHNIQUE + +OUI:0000E5* + ID_OUI_FROM_DATABASE=SIGMEX LTD. + +OUI:0000E6* + ID_OUI_FROM_DATABASE=APTOR PRODUITS DE COMM INDUST + +OUI:0000E7* + ID_OUI_FROM_DATABASE=STAR GATE TECHNOLOGIES + +OUI:0000E8* + ID_OUI_FROM_DATABASE=ACCTON TECHNOLOGY CORP. + +OUI:0000E9* + ID_OUI_FROM_DATABASE=ISICAD, INC. + +OUI:0000EA* + ID_OUI_FROM_DATABASE=UPNOD AB + +OUI:0000EB* + ID_OUI_FROM_DATABASE=MATSUSHITA COMM. IND. CO. LTD. + +OUI:0000EC* + ID_OUI_FROM_DATABASE=MICROPROCESS + +OUI:0000ED* + ID_OUI_FROM_DATABASE=APRIL + +OUI:0000EE* + ID_OUI_FROM_DATABASE=NETWORK DESIGNERS, LTD. + +OUI:0000EF* + ID_OUI_FROM_DATABASE=KTI + +OUI:0000F0* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. + +OUI:0000F1* + ID_OUI_FROM_DATABASE=MAGNA COMPUTER CORPORATION + +OUI:0000F2* + ID_OUI_FROM_DATABASE=SPIDER COMMUNICATIONS + +OUI:0000F3* + ID_OUI_FROM_DATABASE=GANDALF DATA LIMITED + +OUI:0000F4* + ID_OUI_FROM_DATABASE=Allied Telesis + +OUI:0000F5* + ID_OUI_FROM_DATABASE=DIAMOND SALES LIMITED + +OUI:0000F6* + ID_OUI_FROM_DATABASE=APPLIED MICROSYSTEMS CORP. + +OUI:0000F7* + ID_OUI_FROM_DATABASE=YOUTH KEEP ENTERPRISE CO LTD + +OUI:0000F8* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:0000F9* + ID_OUI_FROM_DATABASE=QUOTRON SYSTEMS INC. + +OUI:0000FA* + ID_OUI_FROM_DATABASE=MICROSAGE COMPUTER SYSTEMS INC + +OUI:0000FB* + ID_OUI_FROM_DATABASE=RECHNER ZUR KOMMUNIKATION + +OUI:0000FC* + ID_OUI_FROM_DATABASE=MEIKO + +OUI:0000FD* + ID_OUI_FROM_DATABASE=HIGH LEVEL HARDWARE + +OUI:0000FE* + ID_OUI_FROM_DATABASE=ANNAPOLIS MICRO SYSTEMS + +OUI:0000FF* + ID_OUI_FROM_DATABASE=CAMTEC ELECTRONICS LTD. + +OUI:000100* + ID_OUI_FROM_DATABASE=EQUIP'TRANS + +OUI:000102* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:000103* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:000104* + ID_OUI_FROM_DATABASE=DVICO Co., Ltd. + +OUI:000105* + ID_OUI_FROM_DATABASE=Beckhoff Automation GmbH + +OUI:000106* + ID_OUI_FROM_DATABASE=Tews Datentechnik GmbH + +OUI:000107* + ID_OUI_FROM_DATABASE=Leiser GmbH + +OUI:000108* + ID_OUI_FROM_DATABASE=AVLAB Technology, Inc. + +OUI:000109* + ID_OUI_FROM_DATABASE=Nagano Japan Radio Co., Ltd. + +OUI:00010A* + ID_OUI_FROM_DATABASE=CIS TECHNOLOGY INC. + +OUI:00010B* + ID_OUI_FROM_DATABASE=Space CyberLink, Inc. + +OUI:00010C* + ID_OUI_FROM_DATABASE=System Talks Inc. + +OUI:00010D* + ID_OUI_FROM_DATABASE=CORECO, INC. + +OUI:00010E* + ID_OUI_FROM_DATABASE=Bri-Link Technologies Co., Ltd + +OUI:00010F* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:000110* + ID_OUI_FROM_DATABASE=Gotham Networks + +OUI:000111* + ID_OUI_FROM_DATABASE=iDigm Inc. + +OUI:000112* + ID_OUI_FROM_DATABASE=Shark Multimedia Inc. + +OUI:000113* + ID_OUI_FROM_DATABASE=OLYMPUS CORPORATION + +OUI:000114* + ID_OUI_FROM_DATABASE=KANDA TSUSHIN KOGYO CO., LTD. + +OUI:000115* + ID_OUI_FROM_DATABASE=EXTRATECH CORPORATION + +OUI:000116* + ID_OUI_FROM_DATABASE=Netspect Technologies, Inc. + +OUI:000117* + ID_OUI_FROM_DATABASE=CANAL + + +OUI:000118* + ID_OUI_FROM_DATABASE=EZ Digital Co., Ltd. + +OUI:000119* + ID_OUI_FROM_DATABASE=RTUnet (Australia) + +OUI:00011A* + ID_OUI_FROM_DATABASE=Hoffmann und Burmeister GbR + +OUI:00011B* + ID_OUI_FROM_DATABASE=Unizone Technologies, Inc. + +OUI:00011C* + ID_OUI_FROM_DATABASE=Universal Talkware Corporation + +OUI:00011D* + ID_OUI_FROM_DATABASE=Centillium Communications + +OUI:00011E* + ID_OUI_FROM_DATABASE=Precidia Technologies, Inc. + +OUI:00011F* + ID_OUI_FROM_DATABASE=RC Networks, Inc. + +OUI:000120* + ID_OUI_FROM_DATABASE=OSCILLOQUARTZ S.A. + +OUI:000121* + ID_OUI_FROM_DATABASE=Watchguard Technologies, Inc. + +OUI:000122* + ID_OUI_FROM_DATABASE=Trend Communications, Ltd. + +OUI:000123* + ID_OUI_FROM_DATABASE=DIGITAL ELECTRONICS CORP. + +OUI:000124* + ID_OUI_FROM_DATABASE=Acer Incorporated + +OUI:000125* + ID_OUI_FROM_DATABASE=YAESU MUSEN CO., LTD. + +OUI:000126* + ID_OUI_FROM_DATABASE=PAC Labs + +OUI:000127* + ID_OUI_FROM_DATABASE=OPEN Networks Pty Ltd + +OUI:000128* + ID_OUI_FROM_DATABASE=EnjoyWeb, Inc. + +OUI:000129* + ID_OUI_FROM_DATABASE=DFI Inc. + +OUI:00012A* + ID_OUI_FROM_DATABASE=Telematica Sistems Inteligente + +OUI:00012B* + ID_OUI_FROM_DATABASE=TELENET Co., Ltd. + +OUI:00012C* + ID_OUI_FROM_DATABASE=Aravox Technologies, Inc. + +OUI:00012D* + ID_OUI_FROM_DATABASE=Komodo Technology + +OUI:00012E* + ID_OUI_FROM_DATABASE=PC Partner Ltd. + +OUI:00012F* + ID_OUI_FROM_DATABASE=Twinhead International Corp + +OUI:000130* + ID_OUI_FROM_DATABASE=Extreme Networks + +OUI:000131* + ID_OUI_FROM_DATABASE=Bosch Security Systems, Inc. + +OUI:000132* + ID_OUI_FROM_DATABASE=Dranetz - BMI + +OUI:000133* + ID_OUI_FROM_DATABASE=KYOWA Electronic Instruments C + +OUI:000134* + ID_OUI_FROM_DATABASE=Selectron Systems AG + +OUI:000135* + ID_OUI_FROM_DATABASE=KDC Corp. + +OUI:000136* + ID_OUI_FROM_DATABASE=CyberTAN Technology, Inc. + +OUI:000137* + ID_OUI_FROM_DATABASE=IT Farm Corporation + +OUI:000138* + ID_OUI_FROM_DATABASE=XAVi Technologies Corp. + +OUI:000139* + ID_OUI_FROM_DATABASE=Point Multimedia Systems + +OUI:00013A* + ID_OUI_FROM_DATABASE=SHELCAD COMMUNICATIONS, LTD. + +OUI:00013B* + ID_OUI_FROM_DATABASE=BNA SYSTEMS + +OUI:00013C* + ID_OUI_FROM_DATABASE=TIW SYSTEMS + +OUI:00013D* + ID_OUI_FROM_DATABASE=RiscStation Ltd. + +OUI:00013E* + ID_OUI_FROM_DATABASE=Ascom Tateco AB + +OUI:00013F* + ID_OUI_FROM_DATABASE=Neighbor World Co., Ltd. + +OUI:000140* + ID_OUI_FROM_DATABASE=Sendtek Corporation + +OUI:000141* + ID_OUI_FROM_DATABASE=CABLE PRINT + +OUI:000142* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000143* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000144* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:000145* + ID_OUI_FROM_DATABASE=WINSYSTEMS, INC. + +OUI:000146* + ID_OUI_FROM_DATABASE=Tesco Controls, Inc. + +OUI:000147* + ID_OUI_FROM_DATABASE=Zhone Technologies + +OUI:000148* + ID_OUI_FROM_DATABASE=X-traWeb Inc. + +OUI:000149* + ID_OUI_FROM_DATABASE=T.D.T. Transfer Data Test GmbH + +OUI:00014A* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:00014B* + ID_OUI_FROM_DATABASE=Ennovate Networks, Inc. + +OUI:00014C* + ID_OUI_FROM_DATABASE=Berkeley Process Control + +OUI:00014D* + ID_OUI_FROM_DATABASE=Shin Kin Enterprises Co., Ltd + +OUI:00014E* + ID_OUI_FROM_DATABASE=WIN Enterprises, Inc. + +OUI:00014F* + ID_OUI_FROM_DATABASE=ADTRAN INC + +OUI:000150* + ID_OUI_FROM_DATABASE=GILAT COMMUNICATIONS, LTD. + +OUI:000151* + ID_OUI_FROM_DATABASE=Ensemble Communications + +OUI:000152* + ID_OUI_FROM_DATABASE=CHROMATEK INC. + +OUI:000153* + ID_OUI_FROM_DATABASE=ARCHTEK TELECOM CORPORATION + +OUI:000154* + ID_OUI_FROM_DATABASE=G3M Corporation + +OUI:000155* + ID_OUI_FROM_DATABASE=Promise Technology, Inc. + +OUI:000156* + ID_OUI_FROM_DATABASE=FIREWIREDIRECT.COM, INC. + +OUI:000157* + ID_OUI_FROM_DATABASE=SYSWAVE CO., LTD + +OUI:000158* + ID_OUI_FROM_DATABASE=Electro Industries/Gauge Tech + +OUI:000159* + ID_OUI_FROM_DATABASE=S1 Corporation + +OUI:00015A* + ID_OUI_FROM_DATABASE=Digital Video Broadcasting + +OUI:00015B* + ID_OUI_FROM_DATABASE=ITALTEL S.p.A/RF-UP-I + +OUI:00015C* + ID_OUI_FROM_DATABASE=CADANT INC. + +OUI:00015D* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:00015E* + ID_OUI_FROM_DATABASE=BEST TECHNOLOGY CO., LTD. + +OUI:00015F* + ID_OUI_FROM_DATABASE=DIGITAL DESIGN GmbH + +OUI:000160* + ID_OUI_FROM_DATABASE=ELMEX Co., LTD. + +OUI:000161* + ID_OUI_FROM_DATABASE=Meta Machine Technology + +OUI:000162* + ID_OUI_FROM_DATABASE=Cygnet Technologies, Inc. + +OUI:000163* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000164* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000165* + ID_OUI_FROM_DATABASE=AirSwitch Corporation + +OUI:000166* + ID_OUI_FROM_DATABASE=TC GROUP A/S + +OUI:000167* + ID_OUI_FROM_DATABASE=HIOKI E.E. CORPORATION + +OUI:000168* + ID_OUI_FROM_DATABASE=VITANA CORPORATION + +OUI:000169* + ID_OUI_FROM_DATABASE=Celestix Networks Pte Ltd. + +OUI:00016A* + ID_OUI_FROM_DATABASE=ALITEC + +OUI:00016B* + ID_OUI_FROM_DATABASE=LightChip, Inc. + +OUI:00016C* + ID_OUI_FROM_DATABASE=FOXCONN + +OUI:00016D* + ID_OUI_FROM_DATABASE=CarrierComm Inc. + +OUI:00016E* + ID_OUI_FROM_DATABASE=Conklin Corporation + +OUI:00016F* + ID_OUI_FROM_DATABASE=Inkel Corp. + +OUI:000170* + ID_OUI_FROM_DATABASE=ESE Embedded System Engineer'g + +OUI:000171* + ID_OUI_FROM_DATABASE=Allied Data Technologies + +OUI:000172* + ID_OUI_FROM_DATABASE=TechnoLand Co., LTD. + +OUI:000173* + ID_OUI_FROM_DATABASE=AMCC + +OUI:000174* + ID_OUI_FROM_DATABASE=CyberOptics Corporation + +OUI:000175* + ID_OUI_FROM_DATABASE=Radiant Communications Corp. + +OUI:000176* + ID_OUI_FROM_DATABASE=Orient Silver Enterprises + +OUI:000177* + ID_OUI_FROM_DATABASE=EDSL + +OUI:000178* + ID_OUI_FROM_DATABASE=MARGI Systems, Inc. + +OUI:000179* + ID_OUI_FROM_DATABASE=WIRELESS TECHNOLOGY, INC. + +OUI:00017A* + ID_OUI_FROM_DATABASE=Chengdu Maipu Electric Industrial Co., Ltd. + +OUI:00017B* + ID_OUI_FROM_DATABASE=Heidelberger Druckmaschinen AG + +OUI:00017C* + ID_OUI_FROM_DATABASE=AG-E GmbH + +OUI:00017D* + ID_OUI_FROM_DATABASE=ThermoQuest + +OUI:00017E* + ID_OUI_FROM_DATABASE=ADTEK System Science Co., Ltd. + +OUI:00017F* + ID_OUI_FROM_DATABASE=Experience Music Project + +OUI:000180* + ID_OUI_FROM_DATABASE=AOpen, Inc. + +OUI:000181* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000182* + ID_OUI_FROM_DATABASE=DICA TECHNOLOGIES AG + +OUI:000183* + ID_OUI_FROM_DATABASE=ANITE TELECOMS + +OUI:000184* + ID_OUI_FROM_DATABASE=SIEB & MEYER AG + +OUI:000185* + ID_OUI_FROM_DATABASE=Hitachi Aloka Medical, Ltd. + +OUI:000186* + ID_OUI_FROM_DATABASE=Uwe Disch + +OUI:000187* + ID_OUI_FROM_DATABASE=I2SE GmbH + +OUI:000188* + ID_OUI_FROM_DATABASE=LXCO Technologies ag + +OUI:000189* + ID_OUI_FROM_DATABASE=Refraction Technology, Inc. + +OUI:00018A* + ID_OUI_FROM_DATABASE=ROI COMPUTER AG + +OUI:00018B* + ID_OUI_FROM_DATABASE=NetLinks Co., Ltd. + +OUI:00018C* + ID_OUI_FROM_DATABASE=Mega Vision + +OUI:00018D* + ID_OUI_FROM_DATABASE=AudeSi Technologies + +OUI:00018E* + ID_OUI_FROM_DATABASE=Logitec Corporation + +OUI:00018F* + ID_OUI_FROM_DATABASE=Kenetec, Inc. + +OUI:000190* + ID_OUI_FROM_DATABASE=SMK-M + +OUI:000191* + ID_OUI_FROM_DATABASE=SYRED Data Systems + +OUI:000192* + ID_OUI_FROM_DATABASE=Texas Digital Systems + +OUI:000193* + ID_OUI_FROM_DATABASE=Hanbyul Telecom Co., Ltd. + +OUI:000194* + ID_OUI_FROM_DATABASE=Capital Equipment Corporation + +OUI:000195* + ID_OUI_FROM_DATABASE=Sena Technologies, Inc. + +OUI:000196* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000197* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000198* + ID_OUI_FROM_DATABASE=Darim Vision + +OUI:000199* + ID_OUI_FROM_DATABASE=HeiSei Electronics + +OUI:00019A* + ID_OUI_FROM_DATABASE=LEUNIG GmbH + +OUI:00019B* + ID_OUI_FROM_DATABASE=Kyoto Microcomputer Co., Ltd. + +OUI:00019C* + ID_OUI_FROM_DATABASE=JDS Uniphase Inc. + +OUI:00019D* + ID_OUI_FROM_DATABASE=E-Control Systems, Inc. + +OUI:00019E* + ID_OUI_FROM_DATABASE=ESS Technology, Inc. + +OUI:00019F* + ID_OUI_FROM_DATABASE=ReadyNet + +OUI:0001A0* + ID_OUI_FROM_DATABASE=Infinilink Corporation + +OUI:0001A1* + ID_OUI_FROM_DATABASE=Mag-Tek, Inc. + +OUI:0001A2* + ID_OUI_FROM_DATABASE=Logical Co., Ltd. + +OUI:0001A3* + ID_OUI_FROM_DATABASE=GENESYS LOGIC, INC. + +OUI:0001A4* + ID_OUI_FROM_DATABASE=Microlink Corporation + +OUI:0001A5* + ID_OUI_FROM_DATABASE=Nextcomm, Inc. + +OUI:0001A6* + ID_OUI_FROM_DATABASE=Scientific-Atlanta Arcodan A/S + +OUI:0001A7* + ID_OUI_FROM_DATABASE=UNEX TECHNOLOGY CORPORATION + +OUI:0001A8* + ID_OUI_FROM_DATABASE=Welltech Computer Co., Ltd. + +OUI:0001A9* + ID_OUI_FROM_DATABASE=BMW AG + +OUI:0001AA* + ID_OUI_FROM_DATABASE=Airspan Communications, Ltd. + +OUI:0001AB* + ID_OUI_FROM_DATABASE=Main Street Networks + +OUI:0001AC* + ID_OUI_FROM_DATABASE=Sitara Networks, Inc. + +OUI:0001AD* + ID_OUI_FROM_DATABASE=Coach Master International d.b.a. CMI Worldwide, Inc. + +OUI:0001AE* + ID_OUI_FROM_DATABASE=Trex Enterprises + +OUI:0001AF* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:0001B0* + ID_OUI_FROM_DATABASE=Fulltek Technology Co., Ltd. + +OUI:0001B1* + ID_OUI_FROM_DATABASE=General Bandwidth + +OUI:0001B2* + ID_OUI_FROM_DATABASE=Digital Processing Systems, Inc. + +OUI:0001B3* + ID_OUI_FROM_DATABASE=Precision Electronic Manufacturing + +OUI:0001B4* + ID_OUI_FROM_DATABASE=Wayport, Inc. + +OUI:0001B5* + ID_OUI_FROM_DATABASE=Turin Networks, Inc. + +OUI:0001B6* + ID_OUI_FROM_DATABASE=SAEJIN T&M Co., Ltd. + +OUI:0001B7* + ID_OUI_FROM_DATABASE=Centos, Inc. + +OUI:0001B8* + ID_OUI_FROM_DATABASE=Netsensity, Inc. + +OUI:0001B9* + ID_OUI_FROM_DATABASE=SKF Condition Monitoring + +OUI:0001BA* + ID_OUI_FROM_DATABASE=IC-Net, Inc. + +OUI:0001BB* + ID_OUI_FROM_DATABASE=Frequentis + +OUI:0001BC* + ID_OUI_FROM_DATABASE=Brains Corporation + +OUI:0001BD* + ID_OUI_FROM_DATABASE=Peterson Electro-Musical Products, Inc. + +OUI:0001BE* + ID_OUI_FROM_DATABASE=Gigalink Co., Ltd. + +OUI:0001BF* + ID_OUI_FROM_DATABASE=Teleforce Co., Ltd. + +OUI:0001C0* + ID_OUI_FROM_DATABASE=CompuLab, Ltd. + +OUI:0001C1* + ID_OUI_FROM_DATABASE=Vitesse Semiconductor Corporation + +OUI:0001C2* + ID_OUI_FROM_DATABASE=ARK Research Corp. + +OUI:0001C3* + ID_OUI_FROM_DATABASE=Acromag, Inc. + +OUI:0001C4* + ID_OUI_FROM_DATABASE=NeoWave, Inc. + +OUI:0001C5* + ID_OUI_FROM_DATABASE=Simpler Networks + +OUI:0001C6* + ID_OUI_FROM_DATABASE=Quarry Technologies + +OUI:0001C7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0001C8* + ID_OUI_FROM_DATABASE=THOMAS CONRAD CORP. + +OUI:0001C8* + ID_OUI_FROM_DATABASE=CONRAD CORP. + +OUI:0001C9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0001CA* + ID_OUI_FROM_DATABASE=Geocast Network Systems, Inc. + +OUI:0001CB* + ID_OUI_FROM_DATABASE=EVR + +OUI:0001CC* + ID_OUI_FROM_DATABASE=Japan Total Design Communication Co., Ltd. + +OUI:0001CD* + ID_OUI_FROM_DATABASE=ARtem + +OUI:0001CE* + ID_OUI_FROM_DATABASE=Custom Micro Products, Ltd. + +OUI:0001CF* + ID_OUI_FROM_DATABASE=Alpha Data Parallel Systems, Ltd. + +OUI:0001D0* + ID_OUI_FROM_DATABASE=VitalPoint, Inc. + +OUI:0001D1* + ID_OUI_FROM_DATABASE=CoNet Communications, Inc. + +OUI:0001D2* + ID_OUI_FROM_DATABASE=inXtron, Inc. + +OUI:0001D3* + ID_OUI_FROM_DATABASE=PAXCOMM, Inc. + +OUI:0001D4* + ID_OUI_FROM_DATABASE=Leisure Time, Inc. + +OUI:0001D5* + ID_OUI_FROM_DATABASE=HAEDONG INFO & COMM CO., LTD + +OUI:0001D6* + ID_OUI_FROM_DATABASE=manroland AG + +OUI:0001D7* + ID_OUI_FROM_DATABASE=F5 Networks, Inc. + +OUI:0001D8* + ID_OUI_FROM_DATABASE=Teltronics, Inc. + +OUI:0001D9* + ID_OUI_FROM_DATABASE=Sigma, Inc. + +OUI:0001DA* + ID_OUI_FROM_DATABASE=WINCOMM Corporation + +OUI:0001DB* + ID_OUI_FROM_DATABASE=Freecom Technologies GmbH + +OUI:0001DC* + ID_OUI_FROM_DATABASE=Activetelco + +OUI:0001DD* + ID_OUI_FROM_DATABASE=Avail Networks + +OUI:0001DE* + ID_OUI_FROM_DATABASE=Trango Systems, Inc. + +OUI:0001DF* + ID_OUI_FROM_DATABASE=ISDN Communications, Ltd. + +OUI:0001E0* + ID_OUI_FROM_DATABASE=Fast Systems, Inc. + +OUI:0001E1* + ID_OUI_FROM_DATABASE=Kinpo Electronics, Inc. + +OUI:0001E2* + ID_OUI_FROM_DATABASE=Ando Electric Corporation + +OUI:0001E3* + ID_OUI_FROM_DATABASE=Siemens AG + +OUI:0001E4* + ID_OUI_FROM_DATABASE=Sitera, Inc. + +OUI:0001E5* + ID_OUI_FROM_DATABASE=Supernet, Inc. + +OUI:0001E6* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0001E7* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0001E8* + ID_OUI_FROM_DATABASE=Force10 Networks, Inc. + +OUI:0001E9* + ID_OUI_FROM_DATABASE=Litton Marine Systems B.V. + +OUI:0001EA* + ID_OUI_FROM_DATABASE=Cirilium Corp. + +OUI:0001EB* + ID_OUI_FROM_DATABASE=C-COM Corporation + +OUI:0001EC* + ID_OUI_FROM_DATABASE=Ericsson Group + +OUI:0001ED* + ID_OUI_FROM_DATABASE=SETA Corp. + +OUI:0001EE* + ID_OUI_FROM_DATABASE=Comtrol Europe, Ltd. + +OUI:0001EF* + ID_OUI_FROM_DATABASE=Camtel Technology Corp. + +OUI:0001F0* + ID_OUI_FROM_DATABASE=Tridium, Inc. + +OUI:0001F1* + ID_OUI_FROM_DATABASE=Innovative Concepts, Inc. + +OUI:0001F2* + ID_OUI_FROM_DATABASE=Mark of the Unicorn, Inc. + +OUI:0001F3* + ID_OUI_FROM_DATABASE=QPS, Inc. + +OUI:0001F4* + ID_OUI_FROM_DATABASE=Enterasys Networks + +OUI:0001F5* + ID_OUI_FROM_DATABASE=ERIM S.A. + +OUI:0001F6* + ID_OUI_FROM_DATABASE=Association of Musical Electronics Industry + +OUI:0001F7* + ID_OUI_FROM_DATABASE=Image Display Systems, Inc. + +OUI:0001F8* + ID_OUI_FROM_DATABASE=Texio Technology Corporation + +OUI:0001F9* + ID_OUI_FROM_DATABASE=TeraGlobal Communications Corp. + +OUI:0001FA* + ID_OUI_FROM_DATABASE=HOROSCAS + +OUI:0001FB* + ID_OUI_FROM_DATABASE=DoTop Technology, Inc. + +OUI:0001FC* + ID_OUI_FROM_DATABASE=Keyence Corporation + +OUI:0001FD* + ID_OUI_FROM_DATABASE=Digital Voice Systems, Inc. + +OUI:0001FE* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:0001FF* + ID_OUI_FROM_DATABASE=Data Direct Networks, Inc. + +OUI:000200* + ID_OUI_FROM_DATABASE=Net & Sys Co., Ltd. + +OUI:000201* + ID_OUI_FROM_DATABASE=IFM Electronic gmbh + +OUI:000202* + ID_OUI_FROM_DATABASE=Amino Communications, Ltd. + +OUI:000203* + ID_OUI_FROM_DATABASE=Woonsang Telecom, Inc. + +OUI:000204* + ID_OUI_FROM_DATABASE=Bodmann Industries Elektronik GmbH + +OUI:000205* + ID_OUI_FROM_DATABASE=Hitachi Denshi, Ltd. + +OUI:000206* + ID_OUI_FROM_DATABASE=Telital R&D Denmark A/S + +OUI:000207* + ID_OUI_FROM_DATABASE=VisionGlobal Network Corp. + +OUI:000208* + ID_OUI_FROM_DATABASE=Unify Networks, Inc. + +OUI:000209* + ID_OUI_FROM_DATABASE=Shenzhen SED Information Technology Co., Ltd. + +OUI:00020A* + ID_OUI_FROM_DATABASE=Gefran Spa + +OUI:00020B* + ID_OUI_FROM_DATABASE=Native Networks, Inc. + +OUI:00020C* + ID_OUI_FROM_DATABASE=Metro-Optix + +OUI:00020D* + ID_OUI_FROM_DATABASE=Micronpc.com + +OUI:00020E* + ID_OUI_FROM_DATABASE=ECI Telecom, Ltd + +OUI:00020F* + ID_OUI_FROM_DATABASE=AATR + +OUI:000210* + ID_OUI_FROM_DATABASE=Fenecom + +OUI:000211* + ID_OUI_FROM_DATABASE=Nature Worldwide Technology Corp. + +OUI:000212* + ID_OUI_FROM_DATABASE=SierraCom + +OUI:000213* + ID_OUI_FROM_DATABASE=S.D.E.L. + +OUI:000214* + ID_OUI_FROM_DATABASE=DTVRO + +OUI:000215* + ID_OUI_FROM_DATABASE=Cotas Computer Technology A/B + +OUI:000216* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000217* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000218* + ID_OUI_FROM_DATABASE=Advanced Scientific Corp + +OUI:000219* + ID_OUI_FROM_DATABASE=Paralon Technologies + +OUI:00021A* + ID_OUI_FROM_DATABASE=Zuma Networks + +OUI:00021B* + ID_OUI_FROM_DATABASE=Kollmorgen-Servotronix + +OUI:00021C* + ID_OUI_FROM_DATABASE=Network Elements, Inc. + +OUI:00021D* + ID_OUI_FROM_DATABASE=Data General Communication Ltd. + +OUI:00021E* + ID_OUI_FROM_DATABASE=SIMTEL S.R.L. + +OUI:00021F* + ID_OUI_FROM_DATABASE=Aculab PLC + +OUI:000220* + ID_OUI_FROM_DATABASE=CANON FINETECH INC. + +OUI:000221* + ID_OUI_FROM_DATABASE=DSP Application, Ltd. + +OUI:000222* + ID_OUI_FROM_DATABASE=Chromisys, Inc. + +OUI:000223* + ID_OUI_FROM_DATABASE=ClickTV + +OUI:000224* + ID_OUI_FROM_DATABASE=C-COR + +OUI:000225* + ID_OUI_FROM_DATABASE=One Stop Systems + +OUI:000226* + ID_OUI_FROM_DATABASE=XESystems, Inc. + +OUI:000227* + ID_OUI_FROM_DATABASE=ESD Electronic System Design GmbH + +OUI:000228* + ID_OUI_FROM_DATABASE=Necsom, Ltd. + +OUI:000229* + ID_OUI_FROM_DATABASE=Adtec Corporation + +OUI:00022A* + ID_OUI_FROM_DATABASE=Asound Electronic + +OUI:00022B* + ID_OUI_FROM_DATABASE=SAXA, Inc. + +OUI:00022C* + ID_OUI_FROM_DATABASE=ABB Bomem, Inc. + +OUI:00022D* + ID_OUI_FROM_DATABASE=Agere Systems + +OUI:00022E* + ID_OUI_FROM_DATABASE=TEAC Corp. R& D + +OUI:00022F* + ID_OUI_FROM_DATABASE=P-Cube, Ltd. + +OUI:000230* + ID_OUI_FROM_DATABASE=Intersoft Electronics + +OUI:000231* + ID_OUI_FROM_DATABASE=Ingersoll-Rand + +OUI:000232* + ID_OUI_FROM_DATABASE=Avision, Inc. + +OUI:000233* + ID_OUI_FROM_DATABASE=Mantra Communications, Inc. + +OUI:000234* + ID_OUI_FROM_DATABASE=Imperial Technology, Inc. + +OUI:000235* + ID_OUI_FROM_DATABASE=Paragon Networks International + +OUI:000236* + ID_OUI_FROM_DATABASE=INIT GmbH + +OUI:000237* + ID_OUI_FROM_DATABASE=Cosmo Research Corp. + +OUI:000238* + ID_OUI_FROM_DATABASE=Serome Technology, Inc. + +OUI:000239* + ID_OUI_FROM_DATABASE=Visicom + +OUI:00023A* + ID_OUI_FROM_DATABASE=ZSK Stickmaschinen GmbH + +OUI:00023B* + ID_OUI_FROM_DATABASE=Ericsson + +OUI:00023C* + ID_OUI_FROM_DATABASE=Creative Technology, Ltd. + +OUI:00023D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc. + +OUI:00023E* + ID_OUI_FROM_DATABASE=Selta Telematica S.p.a + +OUI:00023F* + ID_OUI_FROM_DATABASE=Compal Electronics, Inc. + +OUI:000240* + ID_OUI_FROM_DATABASE=Seedek Co., Ltd. + +OUI:000241* + ID_OUI_FROM_DATABASE=Amer.com + +OUI:000242* + ID_OUI_FROM_DATABASE=Videoframe Systems + +OUI:000243* + ID_OUI_FROM_DATABASE=Raysis Co., Ltd. + +OUI:000244* + ID_OUI_FROM_DATABASE=SURECOM Technology Co. + +OUI:000245* + ID_OUI_FROM_DATABASE=Lampus Co, Ltd. + +OUI:000246* + ID_OUI_FROM_DATABASE=All-Win Tech Co., Ltd. + +OUI:000247* + ID_OUI_FROM_DATABASE=Great Dragon Information Technology (Group) Co., Ltd. + +OUI:000248* + ID_OUI_FROM_DATABASE=Pilz GmbH & Co. + +OUI:000249* + ID_OUI_FROM_DATABASE=Aviv Infocom Co, Ltd. + +OUI:00024A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00024B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00024C* + ID_OUI_FROM_DATABASE=SiByte, Inc. + +OUI:00024D* + ID_OUI_FROM_DATABASE=Mannesman Dematic Colby Pty. Ltd. + +OUI:00024E* + ID_OUI_FROM_DATABASE=Datacard Group + +OUI:00024F* + ID_OUI_FROM_DATABASE=IPM Datacom S.R.L. + +OUI:000250* + ID_OUI_FROM_DATABASE=Geyser Networks, Inc. + +OUI:000251* + ID_OUI_FROM_DATABASE=Soma Networks, Inc. + +OUI:000252* + ID_OUI_FROM_DATABASE=Carrier Corporation + +OUI:000253* + ID_OUI_FROM_DATABASE=Televideo, Inc. + +OUI:000254* + ID_OUI_FROM_DATABASE=WorldGate + +OUI:000255* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:000256* + ID_OUI_FROM_DATABASE=Alpha Processor, Inc. + +OUI:000257* + ID_OUI_FROM_DATABASE=Microcom Corp. + +OUI:000258* + ID_OUI_FROM_DATABASE=Flying Packets Communications + +OUI:000259* + ID_OUI_FROM_DATABASE=Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group + +OUI:00025A* + ID_OUI_FROM_DATABASE=Catena Networks + +OUI:00025B* + ID_OUI_FROM_DATABASE=Cambridge Silicon Radio + +OUI:00025C* + ID_OUI_FROM_DATABASE=SCI Systems (Kunshan) Co., Ltd. + +OUI:00025D* + ID_OUI_FROM_DATABASE=Calix Networks + +OUI:00025E* + ID_OUI_FROM_DATABASE=High Technology Ltd + +OUI:00025F* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000260* + ID_OUI_FROM_DATABASE=Accordion Networks, Inc. + +OUI:000261* + ID_OUI_FROM_DATABASE=Tilgin AB + +OUI:000262* + ID_OUI_FROM_DATABASE=Soyo Group Soyo Com Tech Co., Ltd + +OUI:000263* + ID_OUI_FROM_DATABASE=UPS Manufacturing SRL + +OUI:000264* + ID_OUI_FROM_DATABASE=AudioRamp.com + +OUI:000265* + ID_OUI_FROM_DATABASE=Virditech Co. Ltd. + +OUI:000266* + ID_OUI_FROM_DATABASE=Thermalogic Corporation + +OUI:000267* + ID_OUI_FROM_DATABASE=NODE RUNNER, INC. + +OUI:000268* + ID_OUI_FROM_DATABASE=Harris Government Communications + +OUI:000269* + ID_OUI_FROM_DATABASE=Nadatel Co., Ltd + +OUI:00026A* + ID_OUI_FROM_DATABASE=Cocess Telecom Co., Ltd. + +OUI:00026B* + ID_OUI_FROM_DATABASE=BCM Computers Co., Ltd. + +OUI:00026C* + ID_OUI_FROM_DATABASE=Philips CFT + +OUI:00026D* + ID_OUI_FROM_DATABASE=Adept Telecom + +OUI:00026E* + ID_OUI_FROM_DATABASE=NeGeN Access, Inc. + +OUI:00026F* + ID_OUI_FROM_DATABASE=Senao International Co., Ltd. + +OUI:000270* + ID_OUI_FROM_DATABASE=Crewave Co., Ltd. + +OUI:000271* + ID_OUI_FROM_DATABASE=Zhone Technologies + +OUI:000272* + ID_OUI_FROM_DATABASE=CC&C Technologies, Inc. + +OUI:000273* + ID_OUI_FROM_DATABASE=Coriolis Networks + +OUI:000274* + ID_OUI_FROM_DATABASE=Tommy Technologies Corp. + +OUI:000275* + ID_OUI_FROM_DATABASE=SMART Technologies, Inc. + +OUI:000276* + ID_OUI_FROM_DATABASE=Primax Electronics Ltd. + +OUI:000277* + ID_OUI_FROM_DATABASE=Cash Systemes Industrie + +OUI:000278* + ID_OUI_FROM_DATABASE=Samsung Electro-Mechanics Co., Ltd. + +OUI:000279* + ID_OUI_FROM_DATABASE=Control Applications, Ltd. + +OUI:00027A* + ID_OUI_FROM_DATABASE=IOI Technology Corporation + +OUI:00027B* + ID_OUI_FROM_DATABASE=Amplify Net, Inc. + +OUI:00027C* + ID_OUI_FROM_DATABASE=Trilithic, Inc. + +OUI:00027D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00027E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00027F* + ID_OUI_FROM_DATABASE=ask-technologies.com + +OUI:000280* + ID_OUI_FROM_DATABASE=Mu Net, Inc. + +OUI:000281* + ID_OUI_FROM_DATABASE=Madge Ltd. + +OUI:000282* + ID_OUI_FROM_DATABASE=ViaClix, Inc. + +OUI:000283* + ID_OUI_FROM_DATABASE=Spectrum Controls, Inc. + +OUI:000284* + ID_OUI_FROM_DATABASE=AREVA T&D + +OUI:000285* + ID_OUI_FROM_DATABASE=Riverstone Networks + +OUI:000286* + ID_OUI_FROM_DATABASE=Occam Networks + +OUI:000287* + ID_OUI_FROM_DATABASE=Adapcom + +OUI:000288* + ID_OUI_FROM_DATABASE=GLOBAL VILLAGE COMMUNICATION + +OUI:000289* + ID_OUI_FROM_DATABASE=DNE Technologies + +OUI:00028A* + ID_OUI_FROM_DATABASE=Ambit Microsystems Corporation + +OUI:00028B* + ID_OUI_FROM_DATABASE=VDSL Systems OY + +OUI:00028C* + ID_OUI_FROM_DATABASE=Micrel-Synergy Semiconductor + +OUI:00028D* + ID_OUI_FROM_DATABASE=Movita Technologies, Inc. + +OUI:00028E* + ID_OUI_FROM_DATABASE=Rapid 5 Networks, Inc. + +OUI:00028F* + ID_OUI_FROM_DATABASE=Globetek, Inc. + +OUI:000290* + ID_OUI_FROM_DATABASE=Woorigisool, Inc. + +OUI:000291* + ID_OUI_FROM_DATABASE=Open Network Co., Ltd. + +OUI:000292* + ID_OUI_FROM_DATABASE=Logic Innovations, Inc. + +OUI:000293* + ID_OUI_FROM_DATABASE=Solid Data Systems + +OUI:000294* + ID_OUI_FROM_DATABASE=Tokyo Sokushin Co., Ltd. + +OUI:000295* + ID_OUI_FROM_DATABASE=IP.Access Limited + +OUI:000296* + ID_OUI_FROM_DATABASE=Lectron Co,. Ltd. + +OUI:000297* + ID_OUI_FROM_DATABASE=C-COR.net + +OUI:000298* + ID_OUI_FROM_DATABASE=Broadframe Corporation + +OUI:000299* + ID_OUI_FROM_DATABASE=Apex, Inc. + +OUI:00029A* + ID_OUI_FROM_DATABASE=Storage Apps + +OUI:00029B* + ID_OUI_FROM_DATABASE=Kreatel Communications AB + +OUI:00029C* + ID_OUI_FROM_DATABASE=3COM + +OUI:00029D* + ID_OUI_FROM_DATABASE=Merix Corp. + +OUI:00029E* + ID_OUI_FROM_DATABASE=Information Equipment Co., Ltd. + +OUI:00029F* + ID_OUI_FROM_DATABASE=L-3 Communication Aviation Recorders + +OUI:0002A0* + ID_OUI_FROM_DATABASE=Flatstack Ltd. + +OUI:0002A1* + ID_OUI_FROM_DATABASE=World Wide Packets + +OUI:0002A2* + ID_OUI_FROM_DATABASE=Hilscher GmbH + +OUI:0002A3* + ID_OUI_FROM_DATABASE=ABB Switzerland Ltd, Power Systems + +OUI:0002A4* + ID_OUI_FROM_DATABASE=AddPac Technology Co., Ltd. + +OUI:0002A5* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0002A6* + ID_OUI_FROM_DATABASE=Effinet Systems Co., Ltd. + +OUI:0002A7* + ID_OUI_FROM_DATABASE=Vivace Networks + +OUI:0002A8* + ID_OUI_FROM_DATABASE=Air Link Technology + +OUI:0002A9* + ID_OUI_FROM_DATABASE=RACOM, s.r.o. + +OUI:0002AA* + ID_OUI_FROM_DATABASE=PLcom Co., Ltd. + +OUI:0002AB* + ID_OUI_FROM_DATABASE=CTC Union Technologies Co., Ltd. + +OUI:0002AC* + ID_OUI_FROM_DATABASE=3PAR data + +OUI:0002AD* + ID_OUI_FROM_DATABASE=HOYA Corporation + +OUI:0002AE* + ID_OUI_FROM_DATABASE=Scannex Electronics Ltd. + +OUI:0002AF* + ID_OUI_FROM_DATABASE=TeleCruz Technology, Inc. + +OUI:0002B0* + ID_OUI_FROM_DATABASE=Hokubu Communication & Industrial Co., Ltd. + +OUI:0002B1* + ID_OUI_FROM_DATABASE=Anritsu, Ltd. + +OUI:0002B2* + ID_OUI_FROM_DATABASE=Cablevision + +OUI:0002B3* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:0002B4* + ID_OUI_FROM_DATABASE=DAPHNE + +OUI:0002B5* + ID_OUI_FROM_DATABASE=Avnet, Inc. + +OUI:0002B6* + ID_OUI_FROM_DATABASE=Acrosser Technology Co., Ltd. + +OUI:0002B7* + ID_OUI_FROM_DATABASE=Watanabe Electric Industry Co., Ltd. + +OUI:0002B8* + ID_OUI_FROM_DATABASE=WHI KONSULT AB + +OUI:0002B9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0002BA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0002BB* + ID_OUI_FROM_DATABASE=Continuous Computing Corp + +OUI:0002BC* + ID_OUI_FROM_DATABASE=LVL 7 Systems, Inc. + +OUI:0002BD* + ID_OUI_FROM_DATABASE=Bionet Co., Ltd. + +OUI:0002BE* + ID_OUI_FROM_DATABASE=Totsu Engineering, Inc. + +OUI:0002BF* + ID_OUI_FROM_DATABASE=dotRocket, Inc. + +OUI:0002C0* + ID_OUI_FROM_DATABASE=Bencent Tzeng Industry Co., Ltd. + +OUI:0002C1* + ID_OUI_FROM_DATABASE=Innovative Electronic Designs, Inc. + +OUI:0002C2* + ID_OUI_FROM_DATABASE=Net Vision Telecom + +OUI:0002C3* + ID_OUI_FROM_DATABASE=Arelnet Ltd. + +OUI:0002C4* + ID_OUI_FROM_DATABASE=Vector International BVBA + +OUI:0002C5* + ID_OUI_FROM_DATABASE=Evertz Microsystems Ltd. + +OUI:0002C6* + ID_OUI_FROM_DATABASE=Data Track Technology PLC + +OUI:0002C7* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC Co., Ltd. + +OUI:0002C8* + ID_OUI_FROM_DATABASE=Technocom Communications Technology (pte) Ltd + +OUI:0002C9* + ID_OUI_FROM_DATABASE=Mellanox Technologies + +OUI:0002CA* + ID_OUI_FROM_DATABASE=EndPoints, Inc. + +OUI:0002CB* + ID_OUI_FROM_DATABASE=TriState Ltd. + +OUI:0002CC* + ID_OUI_FROM_DATABASE=M.C.C.I + +OUI:0002CD* + ID_OUI_FROM_DATABASE=TeleDream, Inc. + +OUI:0002CE* + ID_OUI_FROM_DATABASE=FoxJet, Inc. + +OUI:0002CF* + ID_OUI_FROM_DATABASE=ZyGate Communications, Inc. + +OUI:0002D0* + ID_OUI_FROM_DATABASE=Comdial Corporation + +OUI:0002D1* + ID_OUI_FROM_DATABASE=Vivotek, Inc. + +OUI:0002D2* + ID_OUI_FROM_DATABASE=Workstation AG + +OUI:0002D3* + ID_OUI_FROM_DATABASE=NetBotz, Inc. + +OUI:0002D4* + ID_OUI_FROM_DATABASE=PDA Peripherals, Inc. + +OUI:0002D5* + ID_OUI_FROM_DATABASE=ACR + +OUI:0002D6* + ID_OUI_FROM_DATABASE=NICE Systems + +OUI:0002D7* + ID_OUI_FROM_DATABASE=EMPEG Ltd + +OUI:0002D8* + ID_OUI_FROM_DATABASE=BRECIS Communications Corporation + +OUI:0002D9* + ID_OUI_FROM_DATABASE=Reliable Controls + +OUI:0002DA* + ID_OUI_FROM_DATABASE=ExiO Communications, Inc. + +OUI:0002DB* + ID_OUI_FROM_DATABASE=NETSEC + +OUI:0002DC* + ID_OUI_FROM_DATABASE=Fujitsu General Limited + +OUI:0002DD* + ID_OUI_FROM_DATABASE=Bromax Communications, Ltd. + +OUI:0002DE* + ID_OUI_FROM_DATABASE=Astrodesign, Inc. + +OUI:0002DF* + ID_OUI_FROM_DATABASE=Net Com Systems, Inc. + +OUI:0002E0* + ID_OUI_FROM_DATABASE=ETAS GmbH + +OUI:0002E1* + ID_OUI_FROM_DATABASE=Integrated Network Corporation + +OUI:0002E2* + ID_OUI_FROM_DATABASE=NDC Infared Engineering + +OUI:0002E3* + ID_OUI_FROM_DATABASE=LITE-ON Communications, Inc. + +OUI:0002E4* + ID_OUI_FROM_DATABASE=JC HYUN Systems, Inc. + +OUI:0002E5* + ID_OUI_FROM_DATABASE=Timeware Ltd. + +OUI:0002E6* + ID_OUI_FROM_DATABASE=Gould Instrument Systems, Inc. + +OUI:0002E7* + ID_OUI_FROM_DATABASE=CAB GmbH & Co KG + +OUI:0002E8* + ID_OUI_FROM_DATABASE=E.D.&A. + +OUI:0002E9* + ID_OUI_FROM_DATABASE=CS Systemes De Securite - C3S + +OUI:0002EA* + ID_OUI_FROM_DATABASE=Focus Enhancements + +OUI:0002EB* + ID_OUI_FROM_DATABASE=Pico Communications + +OUI:0002EC* + ID_OUI_FROM_DATABASE=Maschoff Design Engineering + +OUI:0002ED* + ID_OUI_FROM_DATABASE=DXO Telecom Co., Ltd. + +OUI:0002EE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0002EF* + ID_OUI_FROM_DATABASE=CCC Network Systems Group Ltd. + +OUI:0002F0* + ID_OUI_FROM_DATABASE=AME Optimedia Technology Co., Ltd. + +OUI:0002F1* + ID_OUI_FROM_DATABASE=Pinetron Co., Ltd. + +OUI:0002F2* + ID_OUI_FROM_DATABASE=eDevice, Inc. + +OUI:0002F3* + ID_OUI_FROM_DATABASE=Media Serve Co., Ltd. + +OUI:0002F4* + ID_OUI_FROM_DATABASE=PCTEL, Inc. + +OUI:0002F5* + ID_OUI_FROM_DATABASE=VIVE Synergies, Inc. + +OUI:0002F6* + ID_OUI_FROM_DATABASE=Equipe Communications + +OUI:0002F7* + ID_OUI_FROM_DATABASE=ARM + +OUI:0002F8* + ID_OUI_FROM_DATABASE=SEAKR Engineering, Inc. + +OUI:0002F9* + ID_OUI_FROM_DATABASE=MIMOS Berhad + +OUI:0002FA* + ID_OUI_FROM_DATABASE=DX Antenna Co., Ltd. + +OUI:0002FB* + ID_OUI_FROM_DATABASE=Baumuller Aulugen-Systemtechnik GmbH + +OUI:0002FC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0002FD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0002FE* + ID_OUI_FROM_DATABASE=Viditec, Inc. + +OUI:0002FF* + ID_OUI_FROM_DATABASE=Handan BroadInfoCom + +OUI:000300* + ID_OUI_FROM_DATABASE=Barracuda Networks, Inc. + +OUI:000301* + ID_OUI_FROM_DATABASE=Avantas Networks Corporation + +OUI:000302* + ID_OUI_FROM_DATABASE=Charles Industries, Ltd. + +OUI:000303* + ID_OUI_FROM_DATABASE=JAMA Electronics Co., Ltd. + +OUI:000304* + ID_OUI_FROM_DATABASE=Pacific Broadband Communications + +OUI:000305* + ID_OUI_FROM_DATABASE=MSC Vertriebs GmbH + +OUI:000306* + ID_OUI_FROM_DATABASE=Fusion In Tech Co., Ltd. + +OUI:000307* + ID_OUI_FROM_DATABASE=Secure Works, Inc. + +OUI:000308* + ID_OUI_FROM_DATABASE=AM Communications, Inc. + +OUI:000309* + ID_OUI_FROM_DATABASE=Texcel Technology PLC + +OUI:00030A* + ID_OUI_FROM_DATABASE=Argus Technologies + +OUI:00030B* + ID_OUI_FROM_DATABASE=Hunter Technology, Inc. + +OUI:00030C* + ID_OUI_FROM_DATABASE=Telesoft Technologies Ltd. + +OUI:00030D* + ID_OUI_FROM_DATABASE=Uniwill Computer Corp. + +OUI:00030E* + ID_OUI_FROM_DATABASE=Core Communications Co., Ltd. + +OUI:00030F* + ID_OUI_FROM_DATABASE=Digital China (Shanghai) Networks Ltd. + +OUI:000310* + ID_OUI_FROM_DATABASE=E-Globaledge Corporation + +OUI:000311* + ID_OUI_FROM_DATABASE=Micro Technology Co., Ltd. + +OUI:000312* + ID_OUI_FROM_DATABASE=TR-Systemtechnik GmbH + +OUI:000313* + ID_OUI_FROM_DATABASE=Access Media SPA + +OUI:000314* + ID_OUI_FROM_DATABASE=Teleware Network Systems + +OUI:000315* + ID_OUI_FROM_DATABASE=Cidco Incorporated + +OUI:000316* + ID_OUI_FROM_DATABASE=Nobell Communications, Inc. + +OUI:000317* + ID_OUI_FROM_DATABASE=Merlin Systems, Inc. + +OUI:000318* + ID_OUI_FROM_DATABASE=Cyras Systems, Inc. + +OUI:000319* + ID_OUI_FROM_DATABASE=Infineon AG + +OUI:00031A* + ID_OUI_FROM_DATABASE=Beijing Broad Telecom Ltd., China + +OUI:00031B* + ID_OUI_FROM_DATABASE=Cellvision Systems, Inc. + +OUI:00031C* + ID_OUI_FROM_DATABASE=Svenska Hardvarufabriken AB + +OUI:00031D* + ID_OUI_FROM_DATABASE=Taiwan Commate Computer, Inc. + +OUI:00031E* + ID_OUI_FROM_DATABASE=Optranet, Inc. + +OUI:00031F* + ID_OUI_FROM_DATABASE=Condev Ltd. + +OUI:000320* + ID_OUI_FROM_DATABASE=Xpeed, Inc. + +OUI:000321* + ID_OUI_FROM_DATABASE=Reco Research Co., Ltd. + +OUI:000322* + ID_OUI_FROM_DATABASE=IDIS Co., Ltd. + +OUI:000323* + ID_OUI_FROM_DATABASE=Cornet Technology, Inc. + +OUI:000324* + ID_OUI_FROM_DATABASE=SANYO Consumer Electronics Co., Ltd. + +OUI:000325* + ID_OUI_FROM_DATABASE=Arima Computer Corp. + +OUI:000326* + ID_OUI_FROM_DATABASE=Iwasaki Information Systems Co., Ltd. + +OUI:000327* + ID_OUI_FROM_DATABASE=ACT'L + +OUI:000328* + ID_OUI_FROM_DATABASE=Mace Group, Inc. + +OUI:000329* + ID_OUI_FROM_DATABASE=F3, Inc. + +OUI:00032A* + ID_OUI_FROM_DATABASE=UniData Communication Systems, Inc. + +OUI:00032B* + ID_OUI_FROM_DATABASE=GAI Datenfunksysteme GmbH + +OUI:00032C* + ID_OUI_FROM_DATABASE=ABB Switzerland Ltd + +OUI:00032D* + ID_OUI_FROM_DATABASE=IBASE Technology, Inc. + +OUI:00032E* + ID_OUI_FROM_DATABASE=Scope Information Management, Ltd. + +OUI:00032F* + ID_OUI_FROM_DATABASE=Global Sun Technology, Inc. + +OUI:000330* + ID_OUI_FROM_DATABASE=Imagenics, Co., Ltd. + +OUI:000331* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000332* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000333* + ID_OUI_FROM_DATABASE=Digitel Co., Ltd. + +OUI:000334* + ID_OUI_FROM_DATABASE=Newport Electronics + +OUI:000335* + ID_OUI_FROM_DATABASE=Mirae Technology + +OUI:000336* + ID_OUI_FROM_DATABASE=Zetes Technologies + +OUI:000337* + ID_OUI_FROM_DATABASE=Vaone, Inc. + +OUI:000338* + ID_OUI_FROM_DATABASE=Oak Technology + +OUI:000339* + ID_OUI_FROM_DATABASE=Eurologic Systems, Ltd. + +OUI:00033A* + ID_OUI_FROM_DATABASE=Silicon Wave, Inc. + +OUI:00033B* + ID_OUI_FROM_DATABASE=TAMI Tech Co., Ltd. + +OUI:00033C* + ID_OUI_FROM_DATABASE=Daiden Co., Ltd. + +OUI:00033D* + ID_OUI_FROM_DATABASE=ILSHin Lab + +OUI:00033E* + ID_OUI_FROM_DATABASE=Tateyama System Laboratory Co., Ltd. + +OUI:00033F* + ID_OUI_FROM_DATABASE=BigBand Networks, Ltd. + +OUI:000340* + ID_OUI_FROM_DATABASE=Floware Wireless Systems, Ltd. + +OUI:000341* + ID_OUI_FROM_DATABASE=Axon Digital Design + +OUI:000342* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000343* + ID_OUI_FROM_DATABASE=Martin Professional A/S + +OUI:000344* + ID_OUI_FROM_DATABASE=Tietech.Co., Ltd. + +OUI:000345* + ID_OUI_FROM_DATABASE=Routrek Networks Corporation + +OUI:000346* + ID_OUI_FROM_DATABASE=Hitachi Kokusai Electric, Inc. + +OUI:000347* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:000348* + ID_OUI_FROM_DATABASE=Norscan Instruments, Ltd. + +OUI:000349* + ID_OUI_FROM_DATABASE=Vidicode Datacommunicatie B.V. + +OUI:00034A* + ID_OUI_FROM_DATABASE=RIAS Corporation + +OUI:00034B* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:00034C* + ID_OUI_FROM_DATABASE=Shanghai DigiVision Technology Co., Ltd. + +OUI:00034D* + ID_OUI_FROM_DATABASE=Chiaro Networks, Ltd. + +OUI:00034E* + ID_OUI_FROM_DATABASE=Pos Data Company, Ltd. + +OUI:00034F* + ID_OUI_FROM_DATABASE=Sur-Gard Security + +OUI:000350* + ID_OUI_FROM_DATABASE=BTICINO SPA + +OUI:000351* + ID_OUI_FROM_DATABASE=Diebold, Inc. + +OUI:000352* + ID_OUI_FROM_DATABASE=Colubris Networks + +OUI:000353* + ID_OUI_FROM_DATABASE=Mitac, Inc. + +OUI:000354* + ID_OUI_FROM_DATABASE=Fiber Logic Communications + +OUI:000355* + ID_OUI_FROM_DATABASE=TeraBeam Internet Systems + +OUI:000356* + ID_OUI_FROM_DATABASE=Wincor Nixdorf International GmbH + +OUI:000357* + ID_OUI_FROM_DATABASE=Intervoice-Brite, Inc. + +OUI:000358* + ID_OUI_FROM_DATABASE=Hanyang Digitech Co., Ltd. + +OUI:000359* + ID_OUI_FROM_DATABASE=DigitalSis + +OUI:00035A* + ID_OUI_FROM_DATABASE=Photron Limited + +OUI:00035B* + ID_OUI_FROM_DATABASE=BridgeWave Communications + +OUI:00035C* + ID_OUI_FROM_DATABASE=Saint Song Corp. + +OUI:00035D* + ID_OUI_FROM_DATABASE=Bosung Hi-Net Co., Ltd. + +OUI:00035E* + ID_OUI_FROM_DATABASE=Metropolitan Area Networks, Inc. + +OUI:00035F* + ID_OUI_FROM_DATABASE=Prüftechnik Condition Monitoring GmbH & Co. KG + +OUI:000360* + ID_OUI_FROM_DATABASE=PAC Interactive Technology, Inc. + +OUI:000361* + ID_OUI_FROM_DATABASE=Widcomm, Inc. + +OUI:000362* + ID_OUI_FROM_DATABASE=Vodtel Communications, Inc. + +OUI:000363* + ID_OUI_FROM_DATABASE=Miraesys Co., Ltd. + +OUI:000364* + ID_OUI_FROM_DATABASE=Scenix Semiconductor, Inc. + +OUI:000365* + ID_OUI_FROM_DATABASE=Kira Information & Communications, Ltd. + +OUI:000366* + ID_OUI_FROM_DATABASE=ASM Pacific Technology + +OUI:000367* + ID_OUI_FROM_DATABASE=Jasmine Networks, Inc. + +OUI:000368* + ID_OUI_FROM_DATABASE=Embedone Co., Ltd. + +OUI:000369* + ID_OUI_FROM_DATABASE=Nippon Antenna Co., Ltd. + +OUI:00036A* + ID_OUI_FROM_DATABASE=Mainnet, Ltd. + +OUI:00036B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00036C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00036D* + ID_OUI_FROM_DATABASE=Runtop, Inc. + +OUI:00036E* + ID_OUI_FROM_DATABASE=Nicon Systems (Pty) Limited + +OUI:00036F* + ID_OUI_FROM_DATABASE=Telsey SPA + +OUI:000370* + ID_OUI_FROM_DATABASE=NXTV, Inc. + +OUI:000371* + ID_OUI_FROM_DATABASE=Acomz Networks Corp. + +OUI:000372* + ID_OUI_FROM_DATABASE=ULAN + +OUI:000373* + ID_OUI_FROM_DATABASE=Aselsan A.S + +OUI:000374* + ID_OUI_FROM_DATABASE=Control Microsystems + +OUI:000375* + ID_OUI_FROM_DATABASE=NetMedia, Inc. + +OUI:000376* + ID_OUI_FROM_DATABASE=Graphtec Technology, Inc. + +OUI:000377* + ID_OUI_FROM_DATABASE=Gigabit Wireless + +OUI:000378* + ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. + +OUI:000379* + ID_OUI_FROM_DATABASE=Proscend Communications, Inc. + +OUI:00037A* + ID_OUI_FROM_DATABASE=Taiyo Yuden Co., Ltd. + +OUI:00037B* + ID_OUI_FROM_DATABASE=IDEC IZUMI Corporation + +OUI:00037C* + ID_OUI_FROM_DATABASE=Coax Media + +OUI:00037D* + ID_OUI_FROM_DATABASE=Stellcom + +OUI:00037E* + ID_OUI_FROM_DATABASE=PORTech Communications, Inc. + +OUI:00037F* + ID_OUI_FROM_DATABASE=Atheros Communications, Inc. + +OUI:000380* + ID_OUI_FROM_DATABASE=SSH Communications Security Corp. + +OUI:000381* + ID_OUI_FROM_DATABASE=Ingenico International + +OUI:000382* + ID_OUI_FROM_DATABASE=A-One Co., Ltd. + +OUI:000383* + ID_OUI_FROM_DATABASE=Metera Networks, Inc. + +OUI:000384* + ID_OUI_FROM_DATABASE=AETA + +OUI:000385* + ID_OUI_FROM_DATABASE=Actelis Networks, Inc. + +OUI:000386* + ID_OUI_FROM_DATABASE=Ho Net, Inc. + +OUI:000387* + ID_OUI_FROM_DATABASE=Blaze Network Products + +OUI:000388* + ID_OUI_FROM_DATABASE=Fastfame Technology Co., Ltd. + +OUI:000389* + ID_OUI_FROM_DATABASE=Plantronics + +OUI:00038A* + ID_OUI_FROM_DATABASE=America Online, Inc. + +OUI:00038B* + ID_OUI_FROM_DATABASE=PLUS-ONE I&T, Inc. + +OUI:00038C* + ID_OUI_FROM_DATABASE=Total Impact + +OUI:00038D* + ID_OUI_FROM_DATABASE=PCS Revenue Control Systems, Inc. + +OUI:00038E* + ID_OUI_FROM_DATABASE=Atoga Systems, Inc. + +OUI:00038F* + ID_OUI_FROM_DATABASE=Weinschel Corporation + +OUI:000390* + ID_OUI_FROM_DATABASE=Digital Video Communications, Inc. + +OUI:000391* + ID_OUI_FROM_DATABASE=Advanced Digital Broadcast, Ltd. + +OUI:000392* + ID_OUI_FROM_DATABASE=Hyundai Teletek Co., Ltd. + +OUI:000393* + ID_OUI_FROM_DATABASE=Apple + +OUI:000394* + ID_OUI_FROM_DATABASE=Connect One + +OUI:000395* + ID_OUI_FROM_DATABASE=California Amplifier + +OUI:000396* + ID_OUI_FROM_DATABASE=EZ Cast Co., Ltd. + +OUI:000397* + ID_OUI_FROM_DATABASE=Watchfront Limited + +OUI:000398* + ID_OUI_FROM_DATABASE=WISI + +OUI:000399* + ID_OUI_FROM_DATABASE=Dongju Informations & Communications Co., Ltd. + +OUI:00039A* + ID_OUI_FROM_DATABASE=SiConnect + +OUI:00039B* + ID_OUI_FROM_DATABASE=NetChip Technology, Inc. + +OUI:00039C* + ID_OUI_FROM_DATABASE=OptiMight Communications, Inc. + +OUI:00039D* + ID_OUI_FROM_DATABASE=Qisda Corporation + +OUI:00039E* + ID_OUI_FROM_DATABASE=Tera System Co., Ltd. + +OUI:00039F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003A0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003A1* + ID_OUI_FROM_DATABASE=HIPER Information & Communication, Inc. + +OUI:0003A2* + ID_OUI_FROM_DATABASE=Catapult Communications + +OUI:0003A3* + ID_OUI_FROM_DATABASE=MAVIX, Ltd. + +OUI:0003A4* + ID_OUI_FROM_DATABASE=Imation Corp. + +OUI:0003A5* + ID_OUI_FROM_DATABASE=Medea Corporation + +OUI:0003A6* + ID_OUI_FROM_DATABASE=Traxit Technology, Inc. + +OUI:0003A7* + ID_OUI_FROM_DATABASE=Unixtar Technology, Inc. + +OUI:0003A8* + ID_OUI_FROM_DATABASE=IDOT Computers, Inc. + +OUI:0003A9* + ID_OUI_FROM_DATABASE=AXCENT Media AG + +OUI:0003AA* + ID_OUI_FROM_DATABASE=Watlow + +OUI:0003AB* + ID_OUI_FROM_DATABASE=Bridge Information Systems + +OUI:0003AC* + ID_OUI_FROM_DATABASE=Fronius Schweissmaschinen + +OUI:0003AD* + ID_OUI_FROM_DATABASE=Emerson Energy Systems AB + +OUI:0003AE* + ID_OUI_FROM_DATABASE=Allied Advanced Manufacturing Pte, Ltd. + +OUI:0003AF* + ID_OUI_FROM_DATABASE=Paragea Communications + +OUI:0003B0* + ID_OUI_FROM_DATABASE=Xsense Technology Corp. + +OUI:0003B1* + ID_OUI_FROM_DATABASE=Hospira Inc. + +OUI:0003B2* + ID_OUI_FROM_DATABASE=Radware + +OUI:0003B3* + ID_OUI_FROM_DATABASE=IA Link Systems Co., Ltd. + +OUI:0003B4* + ID_OUI_FROM_DATABASE=Macrotek International Corp. + +OUI:0003B5* + ID_OUI_FROM_DATABASE=Entra Technology Co. + +OUI:0003B6* + ID_OUI_FROM_DATABASE=QSI Corporation + +OUI:0003B7* + ID_OUI_FROM_DATABASE=ZACCESS Systems + +OUI:0003B8* + ID_OUI_FROM_DATABASE=NetKit Solutions, LLC + +OUI:0003B9* + ID_OUI_FROM_DATABASE=Hualong Telecom Co., Ltd. + +OUI:0003BA* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:0003BB* + ID_OUI_FROM_DATABASE=Signal Communications Limited + +OUI:0003BC* + ID_OUI_FROM_DATABASE=COT GmbH + +OUI:0003BD* + ID_OUI_FROM_DATABASE=OmniCluster Technologies, Inc. + +OUI:0003BE* + ID_OUI_FROM_DATABASE=Netility + +OUI:0003BF* + ID_OUI_FROM_DATABASE=Centerpoint Broadband Technologies, Inc. + +OUI:0003C0* + ID_OUI_FROM_DATABASE=RFTNC Co., Ltd. + +OUI:0003C1* + ID_OUI_FROM_DATABASE=Packet Dynamics Ltd + +OUI:0003C2* + ID_OUI_FROM_DATABASE=Solphone K.K. + +OUI:0003C3* + ID_OUI_FROM_DATABASE=Micronik Multimedia + +OUI:0003C4* + ID_OUI_FROM_DATABASE=Tomra Systems ASA + +OUI:0003C5* + ID_OUI_FROM_DATABASE=Mobotix AG + +OUI:0003C6* + ID_OUI_FROM_DATABASE=ICUE Systems, Inc. + +OUI:0003C7* + ID_OUI_FROM_DATABASE=hopf Elektronik GmbH + +OUI:0003C8* + ID_OUI_FROM_DATABASE=CML Emergency Services + +OUI:0003C9* + ID_OUI_FROM_DATABASE=TECOM Co., Ltd. + +OUI:0003CA* + ID_OUI_FROM_DATABASE=MTS Systems Corp. + +OUI:0003CB* + ID_OUI_FROM_DATABASE=Nippon Systems Development Co., Ltd. + +OUI:0003CC* + ID_OUI_FROM_DATABASE=Momentum Computer, Inc. + +OUI:0003CD* + ID_OUI_FROM_DATABASE=Clovertech, Inc. + +OUI:0003CE* + ID_OUI_FROM_DATABASE=ETEN Technologies, Inc. + +OUI:0003CF* + ID_OUI_FROM_DATABASE=Muxcom, Inc. + +OUI:0003D0* + ID_OUI_FROM_DATABASE=KOANKEISO Co., Ltd. + +OUI:0003D1* + ID_OUI_FROM_DATABASE=Takaya Corporation + +OUI:0003D2* + ID_OUI_FROM_DATABASE=Crossbeam Systems, Inc. + +OUI:0003D3* + ID_OUI_FROM_DATABASE=Internet Energy Systems, Inc. + +OUI:0003D4* + ID_OUI_FROM_DATABASE=Alloptic, Inc. + +OUI:0003D5* + ID_OUI_FROM_DATABASE=Advanced Communications Co., Ltd. + +OUI:0003D6* + ID_OUI_FROM_DATABASE=RADVision, Ltd. + +OUI:0003D7* + ID_OUI_FROM_DATABASE=NextNet Wireless, Inc. + +OUI:0003D8* + ID_OUI_FROM_DATABASE=iMPath Networks, Inc. + +OUI:0003D9* + ID_OUI_FROM_DATABASE=Secheron SA + +OUI:0003DA* + ID_OUI_FROM_DATABASE=Takamisawa Cybernetics Co., Ltd. + +OUI:0003DB* + ID_OUI_FROM_DATABASE=Apogee Electronics Corp. + +OUI:0003DC* + ID_OUI_FROM_DATABASE=Lexar Media, Inc. + +OUI:0003DD* + ID_OUI_FROM_DATABASE=Comark Corp. + +OUI:0003DE* + ID_OUI_FROM_DATABASE=OTC Wireless + +OUI:0003DF* + ID_OUI_FROM_DATABASE=Desana Systems + +OUI:0003E0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0003E1* + ID_OUI_FROM_DATABASE=Winmate Communication, Inc. + +OUI:0003E2* + ID_OUI_FROM_DATABASE=Comspace Corporation + +OUI:0003E3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003E4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003E5* + ID_OUI_FROM_DATABASE=Hermstedt SG + +OUI:0003E6* + ID_OUI_FROM_DATABASE=Entone, Inc. + +OUI:0003E7* + ID_OUI_FROM_DATABASE=Logostek Co. Ltd. + +OUI:0003E8* + ID_OUI_FROM_DATABASE=Wavelength Digital Limited + +OUI:0003E9* + ID_OUI_FROM_DATABASE=Akara Canada, Inc. + +OUI:0003EA* + ID_OUI_FROM_DATABASE=Mega System Technologies, Inc. + +OUI:0003EB* + ID_OUI_FROM_DATABASE=Atrica + +OUI:0003EC* + ID_OUI_FROM_DATABASE=ICG Research, Inc. + +OUI:0003ED* + ID_OUI_FROM_DATABASE=Shinkawa Electric Co., Ltd. + +OUI:0003EE* + ID_OUI_FROM_DATABASE=MKNet Corporation + +OUI:0003EF* + ID_OUI_FROM_DATABASE=Oneline AG + +OUI:0003F0* + ID_OUI_FROM_DATABASE=Redfern Broadband Networks + +OUI:0003F1* + ID_OUI_FROM_DATABASE=Cicada Semiconductor, Inc. + +OUI:0003F2* + ID_OUI_FROM_DATABASE=Seneca Networks + +OUI:0003F3* + ID_OUI_FROM_DATABASE=Dazzle Multimedia, Inc. + +OUI:0003F4* + ID_OUI_FROM_DATABASE=NetBurner + +OUI:0003F5* + ID_OUI_FROM_DATABASE=Chip2Chip + +OUI:0003F6* + ID_OUI_FROM_DATABASE=Allegro Networks, Inc. + +OUI:0003F7* + ID_OUI_FROM_DATABASE=Plast-Control GmbH + +OUI:0003F8* + ID_OUI_FROM_DATABASE=SanCastle Technologies, Inc. + +OUI:0003F9* + ID_OUI_FROM_DATABASE=Pleiades Communications, Inc. + +OUI:0003FA* + ID_OUI_FROM_DATABASE=TiMetra Networks + +OUI:0003FB* + ID_OUI_FROM_DATABASE=ENEGATE Co.,Ltd. + +OUI:0003FC* + ID_OUI_FROM_DATABASE=Intertex Data AB + +OUI:0003FD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003FE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0003FF* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:000400* + ID_OUI_FROM_DATABASE=LEXMARK INTERNATIONAL, INC. + +OUI:000401* + ID_OUI_FROM_DATABASE=Osaki Electric Co., Ltd. + +OUI:000402* + ID_OUI_FROM_DATABASE=Nexsan Technologies, Ltd. + +OUI:000403* + ID_OUI_FROM_DATABASE=Nexsi Corporation + +OUI:000404* + ID_OUI_FROM_DATABASE=Makino Milling Machine Co., Ltd. + +OUI:000405* + ID_OUI_FROM_DATABASE=ACN Technologies + +OUI:000406* + ID_OUI_FROM_DATABASE=Fa. Metabox AG + +OUI:000407* + ID_OUI_FROM_DATABASE=Topcon Positioning Systems, Inc. + +OUI:000408* + ID_OUI_FROM_DATABASE=Sanko Electronics Co., Ltd. + +OUI:000409* + ID_OUI_FROM_DATABASE=Cratos Networks + +OUI:00040A* + ID_OUI_FROM_DATABASE=Sage Systems + +OUI:00040B* + ID_OUI_FROM_DATABASE=3com Europe Ltd. + +OUI:00040C* + ID_OUI_FROM_DATABASE=Kanno Works, Ltd. + +OUI:00040D* + ID_OUI_FROM_DATABASE=Avaya, Inc. + +OUI:00040E* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:00040F* + ID_OUI_FROM_DATABASE=Asus Network Technologies, Inc. + +OUI:000410* + ID_OUI_FROM_DATABASE=Spinnaker Networks, Inc. + +OUI:000411* + ID_OUI_FROM_DATABASE=Inkra Networks, Inc. + +OUI:000412* + ID_OUI_FROM_DATABASE=WaveSmith Networks, Inc. + +OUI:000413* + ID_OUI_FROM_DATABASE=SNOM Technology AG + +OUI:000414* + ID_OUI_FROM_DATABASE=Umezawa Musen Denki Co., Ltd. + +OUI:000415* + ID_OUI_FROM_DATABASE=Rasteme Systems Co., Ltd. + +OUI:000416* + ID_OUI_FROM_DATABASE=Parks S/A Comunicacoes Digitais + +OUI:000417* + ID_OUI_FROM_DATABASE=ELAU AG + +OUI:000418* + ID_OUI_FROM_DATABASE=Teltronic S.A.U. + +OUI:000419* + ID_OUI_FROM_DATABASE=Fibercycle Networks, Inc. + +OUI:00041A* + ID_OUI_FROM_DATABASE=Ines Test and Measurement GmbH & CoKG + +OUI:00041B* + ID_OUI_FROM_DATABASE=Bridgeworks Ltd. + +OUI:00041C* + ID_OUI_FROM_DATABASE=ipDialog, Inc. + +OUI:00041D* + ID_OUI_FROM_DATABASE=Corega of America + +OUI:00041E* + ID_OUI_FROM_DATABASE=Shikoku Instrumentation Co., Ltd. + +OUI:00041F* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment, Inc. + +OUI:000420* + ID_OUI_FROM_DATABASE=Slim Devices, Inc. + +OUI:000421* + ID_OUI_FROM_DATABASE=Ocular Networks + +OUI:000422* + ID_OUI_FROM_DATABASE=Gordon Kapes, Inc. + +OUI:000423* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:000424* + ID_OUI_FROM_DATABASE=TMC s.r.l. + +OUI:000425* + ID_OUI_FROM_DATABASE=Atmel Corporation + +OUI:000426* + ID_OUI_FROM_DATABASE=Autosys + +OUI:000427* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000428* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000429* + ID_OUI_FROM_DATABASE=Pixord Corporation + +OUI:00042A* + ID_OUI_FROM_DATABASE=Wireless Networks, Inc. + +OUI:00042B* + ID_OUI_FROM_DATABASE=IT Access Co., Ltd. + +OUI:00042C* + ID_OUI_FROM_DATABASE=Minet, Inc. + +OUI:00042D* + ID_OUI_FROM_DATABASE=Sarian Systems, Ltd. + +OUI:00042E* + ID_OUI_FROM_DATABASE=Netous Technologies, Ltd. + +OUI:00042F* + ID_OUI_FROM_DATABASE=International Communications Products, Inc. + +OUI:000430* + ID_OUI_FROM_DATABASE=Netgem + +OUI:000431* + ID_OUI_FROM_DATABASE=GlobalStreams, Inc. + +OUI:000432* + ID_OUI_FROM_DATABASE=Voyetra Turtle Beach, Inc. + +OUI:000433* + ID_OUI_FROM_DATABASE=Cyberboard A/S + +OUI:000434* + ID_OUI_FROM_DATABASE=Accelent Systems, Inc. + +OUI:000435* + ID_OUI_FROM_DATABASE=Comptek International, Inc. + +OUI:000436* + ID_OUI_FROM_DATABASE=ELANsat Technologies, Inc. + +OUI:000437* + ID_OUI_FROM_DATABASE=Powin Information Technology, Inc. + +OUI:000438* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000439* + ID_OUI_FROM_DATABASE=Rosco Entertainment Technology, Inc. + +OUI:00043A* + ID_OUI_FROM_DATABASE=Intelligent Telecommunications, Inc. + +OUI:00043B* + ID_OUI_FROM_DATABASE=Lava Computer Mfg., Inc. + +OUI:00043C* + ID_OUI_FROM_DATABASE=SONOS Co., Ltd. + +OUI:00043D* + ID_OUI_FROM_DATABASE=INDEL AG + +OUI:00043E* + ID_OUI_FROM_DATABASE=Telencomm + +OUI:00043F* + ID_OUI_FROM_DATABASE=ESTeem Wireless Modems, Inc + +OUI:000440* + ID_OUI_FROM_DATABASE=cyberPIXIE, Inc. + +OUI:000441* + ID_OUI_FROM_DATABASE=Half Dome Systems, Inc. + +OUI:000442* + ID_OUI_FROM_DATABASE=NACT + +OUI:000443* + ID_OUI_FROM_DATABASE=Agilent Technologies, Inc. + +OUI:000444* + ID_OUI_FROM_DATABASE=Western Multiplex Corporation + +OUI:000445* + ID_OUI_FROM_DATABASE=LMS Skalar Instruments GmbH + +OUI:000446* + ID_OUI_FROM_DATABASE=CYZENTECH Co., Ltd. + +OUI:000447* + ID_OUI_FROM_DATABASE=Acrowave Systems Co., Ltd. + +OUI:000448* + ID_OUI_FROM_DATABASE=Polaroid Corporation + +OUI:000449* + ID_OUI_FROM_DATABASE=Mapletree Networks + +OUI:00044A* + ID_OUI_FROM_DATABASE=iPolicy Networks, Inc. + +OUI:00044B* + ID_OUI_FROM_DATABASE=NVIDIA + +OUI:00044C* + ID_OUI_FROM_DATABASE=JENOPTIK + +OUI:00044D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00044E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00044F* + ID_OUI_FROM_DATABASE=Leukhardt Systemelektronik GmbH + +OUI:000450* + ID_OUI_FROM_DATABASE=DMD Computers SRL + +OUI:000451* + ID_OUI_FROM_DATABASE=Medrad, Inc. + +OUI:000452* + ID_OUI_FROM_DATABASE=RocketLogix, Inc. + +OUI:000453* + ID_OUI_FROM_DATABASE=YottaYotta, Inc. + +OUI:000454* + ID_OUI_FROM_DATABASE=Quadriga UK + +OUI:000455* + ID_OUI_FROM_DATABASE=ANTARA.net + +OUI:000456* + ID_OUI_FROM_DATABASE=Cambium Networks Limited + +OUI:000457* + ID_OUI_FROM_DATABASE=Universal Access Technology, Inc. + +OUI:000458* + ID_OUI_FROM_DATABASE=Fusion X Co., Ltd. + +OUI:000459* + ID_OUI_FROM_DATABASE=Veristar Corporation + +OUI:00045A* + ID_OUI_FROM_DATABASE=The Linksys Group, Inc. + +OUI:00045B* + ID_OUI_FROM_DATABASE=Techsan Electronics Co., Ltd. + +OUI:00045C* + ID_OUI_FROM_DATABASE=Mobiwave Pte Ltd + +OUI:00045D* + ID_OUI_FROM_DATABASE=BEKA Elektronik + +OUI:00045E* + ID_OUI_FROM_DATABASE=PolyTrax Information Technology AG + +OUI:00045F* + ID_OUI_FROM_DATABASE=Avalue Technology, Inc. + +OUI:000460* + ID_OUI_FROM_DATABASE=Knilink Technology, Inc. + +OUI:000461* + ID_OUI_FROM_DATABASE=EPOX Computer Co., Ltd. + +OUI:000462* + ID_OUI_FROM_DATABASE=DAKOS Data & Communication Co., Ltd. + +OUI:000463* + ID_OUI_FROM_DATABASE=Bosch Security Systems + +OUI:000464* + ID_OUI_FROM_DATABASE=Pulse-Link Inc + +OUI:000465* + ID_OUI_FROM_DATABASE=i.s.t isdn-support technik GmbH + +OUI:000466* + ID_OUI_FROM_DATABASE=ARMITEL Co. + +OUI:000467* + ID_OUI_FROM_DATABASE=Wuhan Research Institute of MII + +OUI:000468* + ID_OUI_FROM_DATABASE=Vivity, Inc. + +OUI:000469* + ID_OUI_FROM_DATABASE=Innocom, Inc. + +OUI:00046A* + ID_OUI_FROM_DATABASE=Navini Networks + +OUI:00046B* + ID_OUI_FROM_DATABASE=Palm Wireless, Inc. + +OUI:00046C* + ID_OUI_FROM_DATABASE=Cyber Technology Co., Ltd. + +OUI:00046D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00046E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00046F* + ID_OUI_FROM_DATABASE=Digitel S/A Industria Eletronica + +OUI:000470* + ID_OUI_FROM_DATABASE=ipUnplugged AB + +OUI:000471* + ID_OUI_FROM_DATABASE=IPrad + +OUI:000472* + ID_OUI_FROM_DATABASE=Telelynx, Inc. + +OUI:000473* + ID_OUI_FROM_DATABASE=Photonex Corporation + +OUI:000474* + ID_OUI_FROM_DATABASE=LEGRAND + +OUI:000475* + ID_OUI_FROM_DATABASE=3 Com Corporation + +OUI:000476* + ID_OUI_FROM_DATABASE=3 Com Corporation + +OUI:000477* + ID_OUI_FROM_DATABASE=Scalant Systems, Inc. + +OUI:000478* + ID_OUI_FROM_DATABASE=G. Star Technology Corporation + +OUI:000479* + ID_OUI_FROM_DATABASE=Radius Co., Ltd. + +OUI:00047A* + ID_OUI_FROM_DATABASE=AXXESSIT ASA + +OUI:00047B* + ID_OUI_FROM_DATABASE=Schlumberger + +OUI:00047C* + ID_OUI_FROM_DATABASE=Skidata AG + +OUI:00047D* + ID_OUI_FROM_DATABASE=Pelco + +OUI:00047E* + ID_OUI_FROM_DATABASE=Siqura B.V. + +OUI:00047F* + ID_OUI_FROM_DATABASE=Chr. Mayr GmbH & Co. KG + +OUI:000480* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:000481* + ID_OUI_FROM_DATABASE=Econolite Control Products, Inc. + +OUI:000482* + ID_OUI_FROM_DATABASE=Medialogic Corp. + +OUI:000483* + ID_OUI_FROM_DATABASE=Deltron Technology, Inc. + +OUI:000484* + ID_OUI_FROM_DATABASE=Amann GmbH + +OUI:000485* + ID_OUI_FROM_DATABASE=PicoLight + +OUI:000486* + ID_OUI_FROM_DATABASE=ITTC, University of Kansas + +OUI:000487* + ID_OUI_FROM_DATABASE=Cogency Semiconductor, Inc. + +OUI:000488* + ID_OUI_FROM_DATABASE=Eurotherm Controls + +OUI:000489* + ID_OUI_FROM_DATABASE=YAFO Networks, Inc. + +OUI:00048A* + ID_OUI_FROM_DATABASE=Temia Vertriebs GmbH + +OUI:00048B* + ID_OUI_FROM_DATABASE=Poscon Corporation + +OUI:00048C* + ID_OUI_FROM_DATABASE=Nayna Networks, Inc. + +OUI:00048D* + ID_OUI_FROM_DATABASE=Tone Commander Systems, Inc. + +OUI:00048E* + ID_OUI_FROM_DATABASE=Ohm Tech Labs, Inc. + +OUI:00048F* + ID_OUI_FROM_DATABASE=TD Systems Corporation + +OUI:000490* + ID_OUI_FROM_DATABASE=Optical Access + +OUI:000491* + ID_OUI_FROM_DATABASE=Technovision, Inc. + +OUI:000492* + ID_OUI_FROM_DATABASE=Hive Internet, Ltd. + +OUI:000493* + ID_OUI_FROM_DATABASE=Tsinghua Unisplendour Co., Ltd. + +OUI:000494* + ID_OUI_FROM_DATABASE=Breezecom, Ltd. + +OUI:000495* + ID_OUI_FROM_DATABASE=Tejas Networks India Limited + +OUI:000496* + ID_OUI_FROM_DATABASE=Extreme Networks + +OUI:000497* + ID_OUI_FROM_DATABASE=MacroSystem Digital Video AG + +OUI:000498* + ID_OUI_FROM_DATABASE=Mahi Networks + +OUI:000499* + ID_OUI_FROM_DATABASE=Chino Corporation + +OUI:00049A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00049B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00049C* + ID_OUI_FROM_DATABASE=Surgient Networks, Inc. + +OUI:00049D* + ID_OUI_FROM_DATABASE=Ipanema Technologies + +OUI:00049E* + ID_OUI_FROM_DATABASE=Wirelink Co., Ltd. + +OUI:00049F* + ID_OUI_FROM_DATABASE=Freescale Semiconductor + +OUI:0004A0* + ID_OUI_FROM_DATABASE=Verity Instruments, Inc. + +OUI:0004A1* + ID_OUI_FROM_DATABASE=Pathway Connectivity + +OUI:0004A2* + ID_OUI_FROM_DATABASE=L.S.I. Japan Co., Ltd. + +OUI:0004A3* + ID_OUI_FROM_DATABASE=Microchip Technology, Inc. + +OUI:0004A4* + ID_OUI_FROM_DATABASE=NetEnabled, Inc. + +OUI:0004A5* + ID_OUI_FROM_DATABASE=Barco Projection Systems NV + +OUI:0004A6* + ID_OUI_FROM_DATABASE=SAF Tehnika Ltd. + +OUI:0004A7* + ID_OUI_FROM_DATABASE=FabiaTech Corporation + +OUI:0004A8* + ID_OUI_FROM_DATABASE=Broadmax Technologies, Inc. + +OUI:0004A9* + ID_OUI_FROM_DATABASE=SandStream Technologies, Inc. + +OUI:0004AA* + ID_OUI_FROM_DATABASE=Jetstream Communications + +OUI:0004AB* + ID_OUI_FROM_DATABASE=Comverse Network Systems, Inc. + +OUI:0004AC* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:0004AD* + ID_OUI_FROM_DATABASE=Malibu Networks + +OUI:0004AE* + ID_OUI_FROM_DATABASE=Sullair Corporation + +OUI:0004AF* + ID_OUI_FROM_DATABASE=Digital Fountain, Inc. + +OUI:0004B0* + ID_OUI_FROM_DATABASE=ELESIGN Co., Ltd. + +OUI:0004B1* + ID_OUI_FROM_DATABASE=Signal Technology, Inc. + +OUI:0004B2* + ID_OUI_FROM_DATABASE=ESSEGI SRL + +OUI:0004B3* + ID_OUI_FROM_DATABASE=Videotek, Inc. + +OUI:0004B4* + ID_OUI_FROM_DATABASE=CIAC + +OUI:0004B5* + ID_OUI_FROM_DATABASE=Equitrac Corporation + +OUI:0004B6* + ID_OUI_FROM_DATABASE=Stratex Networks, Inc. + +OUI:0004B7* + ID_OUI_FROM_DATABASE=AMB i.t. Holding + +OUI:0004B8* + ID_OUI_FROM_DATABASE=Kumahira Co., Ltd. + +OUI:0004B9* + ID_OUI_FROM_DATABASE=S.I. Soubou, Inc. + +OUI:0004BA* + ID_OUI_FROM_DATABASE=KDD Media Will Corporation + +OUI:0004BB* + ID_OUI_FROM_DATABASE=Bardac Corporation + +OUI:0004BC* + ID_OUI_FROM_DATABASE=Giantec, Inc. + +OUI:0004BD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0004BE* + ID_OUI_FROM_DATABASE=OptXCon, Inc. + +OUI:0004BF* + ID_OUI_FROM_DATABASE=VersaLogic Corp. + +OUI:0004C0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0004C1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0004C2* + ID_OUI_FROM_DATABASE=Magnipix, Inc. + +OUI:0004C3* + ID_OUI_FROM_DATABASE=CASTOR Informatique + +OUI:0004C4* + ID_OUI_FROM_DATABASE=Allen & Heath Limited + +OUI:0004C5* + ID_OUI_FROM_DATABASE=ASE Technologies, USA + +OUI:0004C6* + ID_OUI_FROM_DATABASE=Yamaha Motor Co., Ltd. + +OUI:0004C7* + ID_OUI_FROM_DATABASE=NetMount + +OUI:0004C8* + ID_OUI_FROM_DATABASE=LIBA Maschinenfabrik GmbH + +OUI:0004C9* + ID_OUI_FROM_DATABASE=Micro Electron Co., Ltd. + +OUI:0004CA* + ID_OUI_FROM_DATABASE=FreeMs Corp. + +OUI:0004CB* + ID_OUI_FROM_DATABASE=Tdsoft Communication, Ltd. + +OUI:0004CC* + ID_OUI_FROM_DATABASE=Peek Traffic B.V. + +OUI:0004CD* + ID_OUI_FROM_DATABASE=Extenway Solutions Inc + +OUI:0004CE* + ID_OUI_FROM_DATABASE=Patria Ailon + +OUI:0004CF* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:0004D0* + ID_OUI_FROM_DATABASE=Softlink s.r.o. + +OUI:0004D1* + ID_OUI_FROM_DATABASE=Drew Technologies, Inc. + +OUI:0004D2* + ID_OUI_FROM_DATABASE=Adcon Telemetry GmbH + +OUI:0004D3* + ID_OUI_FROM_DATABASE=Toyokeiki Co., Ltd. + +OUI:0004D4* + ID_OUI_FROM_DATABASE=Proview Electronics Co., Ltd. + +OUI:0004D5* + ID_OUI_FROM_DATABASE=Hitachi Information & Communication Engineering, Ltd. + +OUI:0004D6* + ID_OUI_FROM_DATABASE=Takagi Industrial Co., Ltd. + +OUI:0004D7* + ID_OUI_FROM_DATABASE=Omitec Instrumentation Ltd. + +OUI:0004D8* + ID_OUI_FROM_DATABASE=IPWireless, Inc. + +OUI:0004D9* + ID_OUI_FROM_DATABASE=Titan Electronics, Inc. + +OUI:0004DA* + ID_OUI_FROM_DATABASE=Relax Technology, Inc. + +OUI:0004DB* + ID_OUI_FROM_DATABASE=Tellus Group Corp. + +OUI:0004DC* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0004DD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0004DE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0004DF* + ID_OUI_FROM_DATABASE=Teracom Telematica Ltda. + +OUI:0004E0* + ID_OUI_FROM_DATABASE=Procket Networks + +OUI:0004E1* + ID_OUI_FROM_DATABASE=Infinior Microsystems + +OUI:0004E2* + ID_OUI_FROM_DATABASE=SMC Networks, Inc. + +OUI:0004E3* + ID_OUI_FROM_DATABASE=Accton Technology Corp. + +OUI:0004E4* + ID_OUI_FROM_DATABASE=Daeryung Ind., Inc. + +OUI:0004E5* + ID_OUI_FROM_DATABASE=Glonet Systems, Inc. + +OUI:0004E6* + ID_OUI_FROM_DATABASE=Banyan Network Private Limited + +OUI:0004E7* + ID_OUI_FROM_DATABASE=Lightpointe Communications, Inc + +OUI:0004E8* + ID_OUI_FROM_DATABASE=IER, Inc. + +OUI:0004E9* + ID_OUI_FROM_DATABASE=Infiniswitch Corporation + +OUI:0004EA* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0004EB* + ID_OUI_FROM_DATABASE=Paxonet Communications, Inc. + +OUI:0004EC* + ID_OUI_FROM_DATABASE=Memobox SA + +OUI:0004ED* + ID_OUI_FROM_DATABASE=Billion Electric Co., Ltd. + +OUI:0004EE* + ID_OUI_FROM_DATABASE=Lincoln Electric Company + +OUI:0004EF* + ID_OUI_FROM_DATABASE=Polestar Corp. + +OUI:0004F0* + ID_OUI_FROM_DATABASE=International Computers, Ltd + +OUI:0004F1* + ID_OUI_FROM_DATABASE=WhereNet + +OUI:0004F2* + ID_OUI_FROM_DATABASE=Polycom + +OUI:0004F3* + ID_OUI_FROM_DATABASE=FS FORTH-SYSTEME GmbH + +OUI:0004F4* + ID_OUI_FROM_DATABASE=Infinite Electronics Inc. + +OUI:0004F5* + ID_OUI_FROM_DATABASE=SnowShore Networks, Inc. + +OUI:0004F6* + ID_OUI_FROM_DATABASE=Amphus + +OUI:0004F7* + ID_OUI_FROM_DATABASE=Omega Band, Inc. + +OUI:0004F8* + ID_OUI_FROM_DATABASE=QUALICABLE TV Industria E Com., Ltda + +OUI:0004F9* + ID_OUI_FROM_DATABASE=Xtera Communications, Inc. + +OUI:0004FA* + ID_OUI_FROM_DATABASE=NBS Technologies Inc. + +OUI:0004FB* + ID_OUI_FROM_DATABASE=Commtech, Inc. + +OUI:0004FC* + ID_OUI_FROM_DATABASE=Stratus Computer (DE), Inc. + +OUI:0004FD* + ID_OUI_FROM_DATABASE=Japan Control Engineering Co., Ltd. + +OUI:0004FE* + ID_OUI_FROM_DATABASE=Pelago Networks + +OUI:0004FF* + ID_OUI_FROM_DATABASE=Acronet Co., Ltd. + +OUI:000500* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000501* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000502* + ID_OUI_FROM_DATABASE=Apple + +OUI:000503* + ID_OUI_FROM_DATABASE=ICONAG + +OUI:000504* + ID_OUI_FROM_DATABASE=Naray Information & Communication Enterprise + +OUI:000505* + ID_OUI_FROM_DATABASE=Systems Integration Solutions, Inc. + +OUI:000506* + ID_OUI_FROM_DATABASE=Reddo Networks AB + +OUI:000507* + ID_OUI_FROM_DATABASE=Fine Appliance Corp. + +OUI:000508* + ID_OUI_FROM_DATABASE=Inetcam, Inc. + +OUI:000509* + ID_OUI_FROM_DATABASE=AVOC Nishimura Ltd. + +OUI:00050A* + ID_OUI_FROM_DATABASE=ICS Spa + +OUI:00050B* + ID_OUI_FROM_DATABASE=SICOM Systems, Inc. + +OUI:00050C* + ID_OUI_FROM_DATABASE=Network Photonics, Inc. + +OUI:00050D* + ID_OUI_FROM_DATABASE=Midstream Technologies, Inc. + +OUI:00050E* + ID_OUI_FROM_DATABASE=3ware, Inc. + +OUI:00050F* + ID_OUI_FROM_DATABASE=Tanaka S/S Ltd. + +OUI:000510* + ID_OUI_FROM_DATABASE=Infinite Shanghai Communication Terminals Ltd. + +OUI:000511* + ID_OUI_FROM_DATABASE=Complementary Technologies Ltd + +OUI:000512* + ID_OUI_FROM_DATABASE=MeshNetworks, Inc. + +OUI:000513* + ID_OUI_FROM_DATABASE=VTLinx Multimedia Systems, Inc. + +OUI:000514* + ID_OUI_FROM_DATABASE=KDT Systems Co., Ltd. + +OUI:000515* + ID_OUI_FROM_DATABASE=Nuark Co., Ltd. + +OUI:000516* + ID_OUI_FROM_DATABASE=SMART Modular Technologies + +OUI:000517* + ID_OUI_FROM_DATABASE=Shellcomm, Inc. + +OUI:000518* + ID_OUI_FROM_DATABASE=Jupiters Technology + +OUI:000519* + ID_OUI_FROM_DATABASE=Siemens Building Technologies AG, + +OUI:00051A* + ID_OUI_FROM_DATABASE=3Com Europe Ltd. + +OUI:00051B* + ID_OUI_FROM_DATABASE=Magic Control Technology Corporation + +OUI:00051C* + ID_OUI_FROM_DATABASE=Xnet Technology Corp. + +OUI:00051D* + ID_OUI_FROM_DATABASE=Airocon, Inc. + +OUI:00051E* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:00051F* + ID_OUI_FROM_DATABASE=Taijin Media Co., Ltd. + +OUI:000520* + ID_OUI_FROM_DATABASE=Smartronix, Inc. + +OUI:000521* + ID_OUI_FROM_DATABASE=Control Microsystems + +OUI:000522* + ID_OUI_FROM_DATABASE=LEA*D Corporation, Inc. + +OUI:000523* + ID_OUI_FROM_DATABASE=AVL List GmbH + +OUI:000524* + ID_OUI_FROM_DATABASE=BTL System (HK) Limited + +OUI:000525* + ID_OUI_FROM_DATABASE=Puretek Industrial Co., Ltd. + +OUI:000526* + ID_OUI_FROM_DATABASE=IPAS GmbH + +OUI:000527* + ID_OUI_FROM_DATABASE=SJ Tek Co. Ltd + +OUI:000528* + ID_OUI_FROM_DATABASE=New Focus, Inc. + +OUI:000529* + ID_OUI_FROM_DATABASE=Shanghai Broadan Communication Technology Co., Ltd + +OUI:00052A* + ID_OUI_FROM_DATABASE=Ikegami Tsushinki Co., Ltd. + +OUI:00052B* + ID_OUI_FROM_DATABASE=HORIBA, Ltd. + +OUI:00052C* + ID_OUI_FROM_DATABASE=Supreme Magic Corporation + +OUI:00052D* + ID_OUI_FROM_DATABASE=Zoltrix International Limited + +OUI:00052E* + ID_OUI_FROM_DATABASE=Cinta Networks + +OUI:00052F* + ID_OUI_FROM_DATABASE=Leviton Network Solutions + +OUI:000530* + ID_OUI_FROM_DATABASE=Andiamo Systems, Inc. + +OUI:000531* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000532* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000533* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:000534* + ID_OUI_FROM_DATABASE=Northstar Engineering Ltd. + +OUI:000535* + ID_OUI_FROM_DATABASE=Chip PC Ltd. + +OUI:000536* + ID_OUI_FROM_DATABASE=Danam Communications, Inc. + +OUI:000537* + ID_OUI_FROM_DATABASE=Nets Technology Co., Ltd. + +OUI:000538* + ID_OUI_FROM_DATABASE=Merilus, Inc. + +OUI:000539* + ID_OUI_FROM_DATABASE=A Brand New World in Sweden AB + +OUI:00053A* + ID_OUI_FROM_DATABASE=Willowglen Services Pte Ltd + +OUI:00053B* + ID_OUI_FROM_DATABASE=Harbour Networks Ltd., Co. Beijing + +OUI:00053C* + ID_OUI_FROM_DATABASE=Xircom + +OUI:00053D* + ID_OUI_FROM_DATABASE=Agere Systems + +OUI:00053E* + ID_OUI_FROM_DATABASE=KID Systeme GmbH + +OUI:00053F* + ID_OUI_FROM_DATABASE=VisionTek, Inc. + +OUI:000540* + ID_OUI_FROM_DATABASE=FAST Corporation + +OUI:000541* + ID_OUI_FROM_DATABASE=Advanced Systems Co., Ltd. + +OUI:000542* + ID_OUI_FROM_DATABASE=Otari, Inc. + +OUI:000543* + ID_OUI_FROM_DATABASE=IQ Wireless GmbH + +OUI:000544* + ID_OUI_FROM_DATABASE=Valley Technologies, Inc. + +OUI:000545* + ID_OUI_FROM_DATABASE=Internet Photonics + +OUI:000546* + ID_OUI_FROM_DATABASE=KDDI Network & Solultions Inc. + +OUI:000547* + ID_OUI_FROM_DATABASE=Starent Networks + +OUI:000548* + ID_OUI_FROM_DATABASE=Disco Corporation + +OUI:000549* + ID_OUI_FROM_DATABASE=Salira Optical Network Systems + +OUI:00054A* + ID_OUI_FROM_DATABASE=Ario Data Networks, Inc. + +OUI:00054B* + ID_OUI_FROM_DATABASE=Eaton Automation AG + +OUI:00054C* + ID_OUI_FROM_DATABASE=RF Innovations Pty Ltd + +OUI:00054D* + ID_OUI_FROM_DATABASE=Brans Technologies, Inc. + +OUI:00054E* + ID_OUI_FROM_DATABASE=Philips + +OUI:000550* + ID_OUI_FROM_DATABASE=Vcomms Connect Limited + +OUI:000551* + ID_OUI_FROM_DATABASE=F & S Elektronik Systeme GmbH + +OUI:000552* + ID_OUI_FROM_DATABASE=Xycotec Computer GmbH + +OUI:000553* + ID_OUI_FROM_DATABASE=DVC Company, Inc. + +OUI:000554* + ID_OUI_FROM_DATABASE=Rangestar Wireless + +OUI:000555* + ID_OUI_FROM_DATABASE=Japan Cash Machine Co., Ltd. + +OUI:000556* + ID_OUI_FROM_DATABASE=360 Systems + +OUI:000557* + ID_OUI_FROM_DATABASE=Agile TV Corporation + +OUI:000558* + ID_OUI_FROM_DATABASE=Synchronous, Inc. + +OUI:000559* + ID_OUI_FROM_DATABASE=Intracom S.A. + +OUI:00055A* + ID_OUI_FROM_DATABASE=Power Dsine Ltd. + +OUI:00055B* + ID_OUI_FROM_DATABASE=Charles Industries, Ltd. + +OUI:00055C* + ID_OUI_FROM_DATABASE=Kowa Company, Ltd. + +OUI:00055D* + ID_OUI_FROM_DATABASE=D-Link Systems, Inc. + +OUI:00055E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00055F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000560* + ID_OUI_FROM_DATABASE=LEADER COMM.CO., LTD + +OUI:000561* + ID_OUI_FROM_DATABASE=nac Image Technology, Inc. + +OUI:000562* + ID_OUI_FROM_DATABASE=Digital View Limited + +OUI:000563* + ID_OUI_FROM_DATABASE=J-Works, Inc. + +OUI:000564* + ID_OUI_FROM_DATABASE=Tsinghua Bitway Co., Ltd. + +OUI:000565* + ID_OUI_FROM_DATABASE=Tailyn Communication Company Ltd. + +OUI:000566* + ID_OUI_FROM_DATABASE=Secui.com Corporation + +OUI:000567* + ID_OUI_FROM_DATABASE=Etymonic Design, Inc. + +OUI:000568* + ID_OUI_FROM_DATABASE=Piltofish Networks AB + +OUI:000569* + ID_OUI_FROM_DATABASE=VMware, Inc. + +OUI:00056A* + ID_OUI_FROM_DATABASE=Heuft Systemtechnik GmbH + +OUI:00056B* + ID_OUI_FROM_DATABASE=C.P. Technology Co., Ltd. + +OUI:00056C* + ID_OUI_FROM_DATABASE=Hung Chang Co., Ltd. + +OUI:00056D* + ID_OUI_FROM_DATABASE=Pacific Corporation + +OUI:00056E* + ID_OUI_FROM_DATABASE=National Enhance Technology, Inc. + +OUI:00056F* + ID_OUI_FROM_DATABASE=Innomedia Technologies Pvt. Ltd. + +OUI:000570* + ID_OUI_FROM_DATABASE=Baydel Ltd. + +OUI:000571* + ID_OUI_FROM_DATABASE=Seiwa Electronics Co. + +OUI:000572* + ID_OUI_FROM_DATABASE=Deonet Co., Ltd. + +OUI:000573* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000574* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000575* + ID_OUI_FROM_DATABASE=CDS-Electronics BV + +OUI:000576* + ID_OUI_FROM_DATABASE=NSM Technology Ltd. + +OUI:000577* + ID_OUI_FROM_DATABASE=SM Information & Communication + +OUI:000579* + ID_OUI_FROM_DATABASE=Universal Control Solution Corp. + +OUI:00057A* + ID_OUI_FROM_DATABASE=Overture Networks + +OUI:00057B* + ID_OUI_FROM_DATABASE=Chung Nam Electronic Co., Ltd. + +OUI:00057C* + ID_OUI_FROM_DATABASE=RCO Security AB + +OUI:00057D* + ID_OUI_FROM_DATABASE=Sun Communications, Inc. + +OUI:00057E* + ID_OUI_FROM_DATABASE=Eckelmann Steuerungstechnik GmbH + +OUI:00057F* + ID_OUI_FROM_DATABASE=Acqis Technology + +OUI:000580* + ID_OUI_FROM_DATABASE=FibroLAN Ltd. + +OUI:000581* + ID_OUI_FROM_DATABASE=Snell + +OUI:000582* + ID_OUI_FROM_DATABASE=ClearCube Technology + +OUI:000583* + ID_OUI_FROM_DATABASE=ImageCom Limited + +OUI:000584* + ID_OUI_FROM_DATABASE=AbsoluteValue Systems, Inc. + +OUI:000585* + ID_OUI_FROM_DATABASE=Juniper Networks, Inc. + +OUI:000586* + ID_OUI_FROM_DATABASE=Lucent Technologies + +OUI:000587* + ID_OUI_FROM_DATABASE=Locus, Incorporated + +OUI:000588* + ID_OUI_FROM_DATABASE=Sensoria Corp. + +OUI:000589* + ID_OUI_FROM_DATABASE=National Datacomputer + +OUI:00058A* + ID_OUI_FROM_DATABASE=Netcom Co., Ltd. + +OUI:00058B* + ID_OUI_FROM_DATABASE=IPmental, Inc. + +OUI:00058C* + ID_OUI_FROM_DATABASE=Opentech Inc. + +OUI:00058D* + ID_OUI_FROM_DATABASE=Lynx Photonic Networks, Inc. + +OUI:00058E* + ID_OUI_FROM_DATABASE=Flextronics International GmbH & Co. Nfg. KG + +OUI:00058F* + ID_OUI_FROM_DATABASE=CLCsoft co. + +OUI:000590* + ID_OUI_FROM_DATABASE=Swissvoice Ltd. + +OUI:000591* + ID_OUI_FROM_DATABASE=Active Silicon Ltd + +OUI:000592* + ID_OUI_FROM_DATABASE=Pultek Corp. + +OUI:000593* + ID_OUI_FROM_DATABASE=Grammar Engine Inc. + +OUI:000594* + ID_OUI_FROM_DATABASE=IXXAT Automation GmbH + +OUI:000595* + ID_OUI_FROM_DATABASE=Alesis Corporation + +OUI:000596* + ID_OUI_FROM_DATABASE=Genotech Co., Ltd. + +OUI:000597* + ID_OUI_FROM_DATABASE=Eagle Traffic Control Systems + +OUI:000598* + ID_OUI_FROM_DATABASE=CRONOS S.r.l. + +OUI:000599* + ID_OUI_FROM_DATABASE=DRS Test and Energy Management or DRS-TEM + +OUI:00059A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00059B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00059C* + ID_OUI_FROM_DATABASE=Kleinknecht GmbH, Ing. Büro + +OUI:00059D* + ID_OUI_FROM_DATABASE=Daniel Computing Systems, Inc. + +OUI:00059E* + ID_OUI_FROM_DATABASE=Zinwell Corporation + +OUI:00059F* + ID_OUI_FROM_DATABASE=Yotta Networks, Inc. + +OUI:0005A0* + ID_OUI_FROM_DATABASE=MOBILINE Kft. + +OUI:0005A1* + ID_OUI_FROM_DATABASE=Zenocom + +OUI:0005A2* + ID_OUI_FROM_DATABASE=CELOX Networks + +OUI:0005A3* + ID_OUI_FROM_DATABASE=QEI, Inc. + +OUI:0005A4* + ID_OUI_FROM_DATABASE=Lucid Voice Ltd. + +OUI:0005A5* + ID_OUI_FROM_DATABASE=KOTT + +OUI:0005A6* + ID_OUI_FROM_DATABASE=Extron Electronics + +OUI:0005A7* + ID_OUI_FROM_DATABASE=Hyperchip, Inc. + +OUI:0005A8* + ID_OUI_FROM_DATABASE=WYLE ELECTRONICS + +OUI:0005A9* + ID_OUI_FROM_DATABASE=Princeton Networks, Inc. + +OUI:0005AA* + ID_OUI_FROM_DATABASE=Moore Industries International Inc. + +OUI:0005AB* + ID_OUI_FROM_DATABASE=Cyber Fone, Inc. + +OUI:0005AC* + ID_OUI_FROM_DATABASE=Northern Digital, Inc. + +OUI:0005AD* + ID_OUI_FROM_DATABASE=Topspin Communications, Inc. + +OUI:0005AE* + ID_OUI_FROM_DATABASE=Mediaport USA + +OUI:0005AF* + ID_OUI_FROM_DATABASE=InnoScan Computing A/S + +OUI:0005B0* + ID_OUI_FROM_DATABASE=Korea Computer Technology Co., Ltd. + +OUI:0005B1* + ID_OUI_FROM_DATABASE=ASB Technology BV + +OUI:0005B2* + ID_OUI_FROM_DATABASE=Medison Co., Ltd. + +OUI:0005B3* + ID_OUI_FROM_DATABASE=Asahi-Engineering Co., Ltd. + +OUI:0005B4* + ID_OUI_FROM_DATABASE=Aceex Corporation + +OUI:0005B5* + ID_OUI_FROM_DATABASE=Broadcom Technologies + +OUI:0005B6* + ID_OUI_FROM_DATABASE=INSYS Microelectronics GmbH + +OUI:0005B7* + ID_OUI_FROM_DATABASE=Arbor Technology Corp. + +OUI:0005B8* + ID_OUI_FROM_DATABASE=Electronic Design Associates, Inc. + +OUI:0005B9* + ID_OUI_FROM_DATABASE=Airvana, Inc. + +OUI:0005BA* + ID_OUI_FROM_DATABASE=Area Netwoeks, Inc. + +OUI:0005BB* + ID_OUI_FROM_DATABASE=Myspace AB + +OUI:0005BC* + ID_OUI_FROM_DATABASE=Resorsys Ltd. + +OUI:0005BD* + ID_OUI_FROM_DATABASE=ROAX BV + +OUI:0005BE* + ID_OUI_FROM_DATABASE=Kongsberg Seatex AS + +OUI:0005BF* + ID_OUI_FROM_DATABASE=JustEzy Technology, Inc. + +OUI:0005C0* + ID_OUI_FROM_DATABASE=Digital Network Alacarte Co., Ltd. + +OUI:0005C1* + ID_OUI_FROM_DATABASE=A-Kyung Motion, Inc. + +OUI:0005C2* + ID_OUI_FROM_DATABASE=Soronti, Inc. + +OUI:0005C3* + ID_OUI_FROM_DATABASE=Pacific Instruments, Inc. + +OUI:0005C4* + ID_OUI_FROM_DATABASE=Telect, Inc. + +OUI:0005C5* + ID_OUI_FROM_DATABASE=Flaga HF + +OUI:0005C6* + ID_OUI_FROM_DATABASE=Triz Communications + +OUI:0005C7* + ID_OUI_FROM_DATABASE=I/F-COM A/S + +OUI:0005C8* + ID_OUI_FROM_DATABASE=VERYTECH + +OUI:0005C9* + ID_OUI_FROM_DATABASE=LG Innotek Co., Ltd. + +OUI:0005CA* + ID_OUI_FROM_DATABASE=Hitron Technology, Inc. + +OUI:0005CB* + ID_OUI_FROM_DATABASE=ROIS Technologies, Inc. + +OUI:0005CC* + ID_OUI_FROM_DATABASE=Sumtel Communications, Inc. + +OUI:0005CD* + ID_OUI_FROM_DATABASE=Denon, Ltd. + +OUI:0005CE* + ID_OUI_FROM_DATABASE=Prolink Microsystems Corporation + +OUI:0005CF* + ID_OUI_FROM_DATABASE=Thunder River Technologies, Inc. + +OUI:0005D0* + ID_OUI_FROM_DATABASE=Solinet Systems + +OUI:0005D1* + ID_OUI_FROM_DATABASE=Metavector Technologies + +OUI:0005D2* + ID_OUI_FROM_DATABASE=DAP Technologies + +OUI:0005D3* + ID_OUI_FROM_DATABASE=eProduction Solutions, Inc. + +OUI:0005D4* + ID_OUI_FROM_DATABASE=FutureSmart Networks, Inc. + +OUI:0005D5* + ID_OUI_FROM_DATABASE=Speedcom Wireless + +OUI:0005D6* + ID_OUI_FROM_DATABASE=L-3 Linkabit + +OUI:0005D7* + ID_OUI_FROM_DATABASE=Vista Imaging, Inc. + +OUI:0005D8* + ID_OUI_FROM_DATABASE=Arescom, Inc. + +OUI:0005D9* + ID_OUI_FROM_DATABASE=Techno Valley, Inc. + +OUI:0005DA* + ID_OUI_FROM_DATABASE=Apex Automationstechnik + +OUI:0005DB* + ID_OUI_FROM_DATABASE=PSI Nentec GmbH + +OUI:0005DC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0005DD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0005DE* + ID_OUI_FROM_DATABASE=Gi Fone Korea, Inc. + +OUI:0005DF* + ID_OUI_FROM_DATABASE=Electronic Innovation, Inc. + +OUI:0005E0* + ID_OUI_FROM_DATABASE=Empirix Corp. + +OUI:0005E1* + ID_OUI_FROM_DATABASE=Trellis Photonics, Ltd. + +OUI:0005E2* + ID_OUI_FROM_DATABASE=Creativ Network Technologies + +OUI:0005E3* + ID_OUI_FROM_DATABASE=LightSand Communications, Inc. + +OUI:0005E4* + ID_OUI_FROM_DATABASE=Red Lion Controls Inc. + +OUI:0005E5* + ID_OUI_FROM_DATABASE=Renishaw PLC + +OUI:0005E6* + ID_OUI_FROM_DATABASE=Egenera, Inc. + +OUI:0005E7* + ID_OUI_FROM_DATABASE=Netrake an AudioCodes Company + +OUI:0005E8* + ID_OUI_FROM_DATABASE=TurboWave, Inc. + +OUI:0005E9* + ID_OUI_FROM_DATABASE=Unicess Network, Inc. + +OUI:0005EA* + ID_OUI_FROM_DATABASE=Rednix + +OUI:0005EB* + ID_OUI_FROM_DATABASE=Blue Ridge Networks, Inc. + +OUI:0005EC* + ID_OUI_FROM_DATABASE=Mosaic Systems Inc. + +OUI:0005ED* + ID_OUI_FROM_DATABASE=Technikum Joanneum GmbH + +OUI:0005EE* + ID_OUI_FROM_DATABASE=Siemens AB, Infrastructure & Cities, Building Technologies Division, IC BT SSP SP BA PR + +OUI:0005EF* + ID_OUI_FROM_DATABASE=ADOIR Digital Technology + +OUI:0005F0* + ID_OUI_FROM_DATABASE=SATEC + +OUI:0005F1* + ID_OUI_FROM_DATABASE=Vrcom, Inc. + +OUI:0005F2* + ID_OUI_FROM_DATABASE=Power R, Inc. + +OUI:0005F3* + ID_OUI_FROM_DATABASE=Webyn + +OUI:0005F4* + ID_OUI_FROM_DATABASE=System Base Co., Ltd. + +OUI:0005F5* + ID_OUI_FROM_DATABASE=Geospace Technologies + +OUI:0005F6* + ID_OUI_FROM_DATABASE=Young Chang Co. Ltd. + +OUI:0005F7* + ID_OUI_FROM_DATABASE=Analog Devices, Inc. + +OUI:0005F8* + ID_OUI_FROM_DATABASE=Real Time Access, Inc. + +OUI:0005F9* + ID_OUI_FROM_DATABASE=TOA Corporation + +OUI:0005FA* + ID_OUI_FROM_DATABASE=IPOptical, Inc. + +OUI:0005FB* + ID_OUI_FROM_DATABASE=ShareGate, Inc. + +OUI:0005FC* + ID_OUI_FROM_DATABASE=Schenck Pegasus Corp. + +OUI:0005FD* + ID_OUI_FROM_DATABASE=PacketLight Networks Ltd. + +OUI:0005FE* + ID_OUI_FROM_DATABASE=Traficon N.V. + +OUI:0005FF* + ID_OUI_FROM_DATABASE=SNS Solutions, Inc. + +OUI:000600* + ID_OUI_FROM_DATABASE=Toshiba Teli Corporation + +OUI:000601* + ID_OUI_FROM_DATABASE=Otanikeiki Co., Ltd. + +OUI:000602* + ID_OUI_FROM_DATABASE=Cirkitech Electronics Co. + +OUI:000603* + ID_OUI_FROM_DATABASE=Baker Hughes Inc. + +OUI:000604* + ID_OUI_FROM_DATABASE=@Track Communications, Inc. + +OUI:000605* + ID_OUI_FROM_DATABASE=Inncom International, Inc. + +OUI:000606* + ID_OUI_FROM_DATABASE=RapidWAN, Inc. + +OUI:000607* + ID_OUI_FROM_DATABASE=Omni Directional Control Technology Inc. + +OUI:000608* + ID_OUI_FROM_DATABASE=At-Sky SAS + +OUI:000609* + ID_OUI_FROM_DATABASE=Crossport Systems + +OUI:00060A* + ID_OUI_FROM_DATABASE=Blue2space + +OUI:00060B* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:00060C* + ID_OUI_FROM_DATABASE=Melco Industries, Inc. + +OUI:00060D* + ID_OUI_FROM_DATABASE=Wave7 Optics + +OUI:00060E* + ID_OUI_FROM_DATABASE=IGYS Systems, Inc. + +OUI:00060F* + ID_OUI_FROM_DATABASE=Narad Networks Inc + +OUI:000610* + ID_OUI_FROM_DATABASE=Abeona Networks Inc + +OUI:000611* + ID_OUI_FROM_DATABASE=Zeus Wireless, Inc. + +OUI:000612* + ID_OUI_FROM_DATABASE=Accusys, Inc. + +OUI:000613* + ID_OUI_FROM_DATABASE=Kawasaki Microelectronics Incorporated + +OUI:000614* + ID_OUI_FROM_DATABASE=Prism Holdings + +OUI:000615* + ID_OUI_FROM_DATABASE=Kimoto Electric Co., Ltd. + +OUI:000616* + ID_OUI_FROM_DATABASE=Tel Net Co., Ltd. + +OUI:000617* + ID_OUI_FROM_DATABASE=Redswitch Inc. + +OUI:000618* + ID_OUI_FROM_DATABASE=DigiPower Manufacturing Inc. + +OUI:000619* + ID_OUI_FROM_DATABASE=Connection Technology Systems + +OUI:00061A* + ID_OUI_FROM_DATABASE=Zetari Inc. + +OUI:00061B* + ID_OUI_FROM_DATABASE=Notebook Development Lab. Lenovo Japan Ltd. + +OUI:00061C* + ID_OUI_FROM_DATABASE=Hoshino Metal Industries, Ltd. + +OUI:00061D* + ID_OUI_FROM_DATABASE=MIP Telecom, Inc. + +OUI:00061E* + ID_OUI_FROM_DATABASE=Maxan Systems + +OUI:00061F* + ID_OUI_FROM_DATABASE=Vision Components GmbH + +OUI:000620* + ID_OUI_FROM_DATABASE=Serial System Ltd. + +OUI:000621* + ID_OUI_FROM_DATABASE=Hinox, Co., Ltd. + +OUI:000622* + ID_OUI_FROM_DATABASE=Chung Fu Chen Yeh Enterprise Corp. + +OUI:000623* + ID_OUI_FROM_DATABASE=MGE UPS Systems France + +OUI:000624* + ID_OUI_FROM_DATABASE=Gentner Communications Corp. + +OUI:000625* + ID_OUI_FROM_DATABASE=The Linksys Group, Inc. + +OUI:000626* + ID_OUI_FROM_DATABASE=MWE GmbH + +OUI:000627* + ID_OUI_FROM_DATABASE=Uniwide Technologies, Inc. + +OUI:000628* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000629* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:00062A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00062B* + ID_OUI_FROM_DATABASE=INTRASERVER TECHNOLOGY + +OUI:00062C* + ID_OUI_FROM_DATABASE=Bivio Networks + +OUI:00062D* + ID_OUI_FROM_DATABASE=TouchStar Technologies, L.L.C. + +OUI:00062E* + ID_OUI_FROM_DATABASE=Aristos Logic Corp. + +OUI:00062F* + ID_OUI_FROM_DATABASE=Pivotech Systems Inc. + +OUI:000630* + ID_OUI_FROM_DATABASE=Adtranz Sweden + +OUI:000631* + ID_OUI_FROM_DATABASE=Calix + +OUI:000632* + ID_OUI_FROM_DATABASE=Mesco Engineering GmbH + +OUI:000633* + ID_OUI_FROM_DATABASE=Cross Match Technologies GmbH + +OUI:000634* + ID_OUI_FROM_DATABASE=GTE Airfone Inc. + +OUI:000635* + ID_OUI_FROM_DATABASE=PacketAir Networks, Inc. + +OUI:000636* + ID_OUI_FROM_DATABASE=Jedai Broadband Networks + +OUI:000637* + ID_OUI_FROM_DATABASE=Toptrend-Meta Information (ShenZhen) Inc. + +OUI:000638* + ID_OUI_FROM_DATABASE=Sungjin C&C Co., Ltd. + +OUI:000639* + ID_OUI_FROM_DATABASE=Newtec + +OUI:00063A* + ID_OUI_FROM_DATABASE=Dura Micro, Inc. + +OUI:00063B* + ID_OUI_FROM_DATABASE=Arcturus Networks Inc. + +OUI:00063C* + ID_OUI_FROM_DATABASE=Intrinsyc Software International Inc. + +OUI:00063D* + ID_OUI_FROM_DATABASE=Microwave Data Systems Inc. + +OUI:00063E* + ID_OUI_FROM_DATABASE=Opthos Inc. + +OUI:00063F* + ID_OUI_FROM_DATABASE=Everex Communications Inc. + +OUI:000640* + ID_OUI_FROM_DATABASE=White Rock Networks + +OUI:000641* + ID_OUI_FROM_DATABASE=ITCN + +OUI:000642* + ID_OUI_FROM_DATABASE=Genetel Systems Inc. + +OUI:000643* + ID_OUI_FROM_DATABASE=SONO Computer Co., Ltd. + +OUI:000644* + ID_OUI_FROM_DATABASE=Neix,Inc + +OUI:000645* + ID_OUI_FROM_DATABASE=Meisei Electric Co. Ltd. + +OUI:000646* + ID_OUI_FROM_DATABASE=ShenZhen XunBao Network Technology Co Ltd + +OUI:000647* + ID_OUI_FROM_DATABASE=Etrali S.A. + +OUI:000648* + ID_OUI_FROM_DATABASE=Seedsware, Inc. + +OUI:000649* + ID_OUI_FROM_DATABASE=3M Deutschland GmbH + +OUI:00064A* + ID_OUI_FROM_DATABASE=Honeywell Co., Ltd. (KOREA) + +OUI:00064B* + ID_OUI_FROM_DATABASE=Alexon Co., Ltd. + +OUI:00064C* + ID_OUI_FROM_DATABASE=Invicta Networks, Inc. + +OUI:00064D* + ID_OUI_FROM_DATABASE=Sencore + +OUI:00064E* + ID_OUI_FROM_DATABASE=Broad Net Technology Inc. + +OUI:00064F* + ID_OUI_FROM_DATABASE=PRO-NETS Technology Corporation + +OUI:000650* + ID_OUI_FROM_DATABASE=Tiburon Networks, Inc. + +OUI:000651* + ID_OUI_FROM_DATABASE=Aspen Networks Inc. + +OUI:000652* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000653* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000654* + ID_OUI_FROM_DATABASE=Winpresa Building Automation Technologies GmbH + +OUI:000655* + ID_OUI_FROM_DATABASE=Yipee, Inc. + +OUI:000656* + ID_OUI_FROM_DATABASE=Tactel AB + +OUI:000657* + ID_OUI_FROM_DATABASE=Market Central, Inc. + +OUI:000658* + ID_OUI_FROM_DATABASE=Helmut Fischer GmbH Institut für Elektronik und Messtechnik + +OUI:000659* + ID_OUI_FROM_DATABASE=EAL (Apeldoorn) B.V. + +OUI:00065A* + ID_OUI_FROM_DATABASE=Strix Systems + +OUI:00065B* + ID_OUI_FROM_DATABASE=Dell Computer Corp. + +OUI:00065C* + ID_OUI_FROM_DATABASE=Malachite Technologies, Inc. + +OUI:00065D* + ID_OUI_FROM_DATABASE=Heidelberg Web Systems + +OUI:00065E* + ID_OUI_FROM_DATABASE=Photuris, Inc. + +OUI:00065F* + ID_OUI_FROM_DATABASE=ECI Telecom - NGTS Ltd. + +OUI:000660* + ID_OUI_FROM_DATABASE=NADEX Co., Ltd. + +OUI:000661* + ID_OUI_FROM_DATABASE=NIA Home Technologies Corp. + +OUI:000662* + ID_OUI_FROM_DATABASE=MBM Technology Ltd. + +OUI:000663* + ID_OUI_FROM_DATABASE=Human Technology Co., Ltd. + +OUI:000664* + ID_OUI_FROM_DATABASE=Fostex Corporation + +OUI:000665* + ID_OUI_FROM_DATABASE=Sunny Giken, Inc. + +OUI:000666* + ID_OUI_FROM_DATABASE=Roving Networks + +OUI:000667* + ID_OUI_FROM_DATABASE=Tripp Lite + +OUI:000668* + ID_OUI_FROM_DATABASE=Vicon Industries Inc. + +OUI:000669* + ID_OUI_FROM_DATABASE=Datasound Laboratories Ltd + +OUI:00066A* + ID_OUI_FROM_DATABASE=InfiniCon Systems, Inc. + +OUI:00066B* + ID_OUI_FROM_DATABASE=Sysmex Corporation + +OUI:00066C* + ID_OUI_FROM_DATABASE=Robinson Corporation + +OUI:00066D* + ID_OUI_FROM_DATABASE=Compuprint S.P.A. + +OUI:00066E* + ID_OUI_FROM_DATABASE=Delta Electronics, Inc. + +OUI:00066F* + ID_OUI_FROM_DATABASE=Korea Data Systems + +OUI:000670* + ID_OUI_FROM_DATABASE=Upponetti Oy + +OUI:000671* + ID_OUI_FROM_DATABASE=Softing AG + +OUI:000672* + ID_OUI_FROM_DATABASE=Netezza + +OUI:000673* + ID_OUI_FROM_DATABASE=TKH Security Solutions USA + +OUI:000674* + ID_OUI_FROM_DATABASE=Spectrum Control, Inc. + +OUI:000675* + ID_OUI_FROM_DATABASE=Banderacom, Inc. + +OUI:000676* + ID_OUI_FROM_DATABASE=Novra Technologies Inc. + +OUI:000677* + ID_OUI_FROM_DATABASE=SICK AG + +OUI:000678* + ID_OUI_FROM_DATABASE=Marantz Brand Company + +OUI:000679* + ID_OUI_FROM_DATABASE=Konami Corporation + +OUI:00067A* + ID_OUI_FROM_DATABASE=JMP Systems + +OUI:00067B* + ID_OUI_FROM_DATABASE=Toplink C&C Corporation + +OUI:00067C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00067D* + ID_OUI_FROM_DATABASE=Takasago Ltd. + +OUI:00067E* + ID_OUI_FROM_DATABASE=WinCom Systems, Inc. + +OUI:00067F* + ID_OUI_FROM_DATABASE=Digeo, Inc. + +OUI:000680* + ID_OUI_FROM_DATABASE=Card Access, Inc. + +OUI:000681* + ID_OUI_FROM_DATABASE=Goepel Electronic GmbH + +OUI:000682* + ID_OUI_FROM_DATABASE=Convedia + +OUI:000683* + ID_OUI_FROM_DATABASE=Bravara Communications, Inc. + +OUI:000684* + ID_OUI_FROM_DATABASE=Biacore AB + +OUI:000685* + ID_OUI_FROM_DATABASE=NetNearU Corporation + +OUI:000686* + ID_OUI_FROM_DATABASE=ZARDCOM Co., Ltd. + +OUI:000687* + ID_OUI_FROM_DATABASE=Omnitron Systems Technology, Inc. + +OUI:000688* + ID_OUI_FROM_DATABASE=Telways Communication Co., Ltd. + +OUI:000689* + ID_OUI_FROM_DATABASE=yLez Technologies Pte Ltd + +OUI:00068A* + ID_OUI_FROM_DATABASE=NeuronNet Co. Ltd. R&D Center + +OUI:00068B* + ID_OUI_FROM_DATABASE=AirRunner Technologies, Inc. + +OUI:00068C* + ID_OUI_FROM_DATABASE=3Com Corporation + +OUI:00068D* + ID_OUI_FROM_DATABASE=SEPATON, Inc. + +OUI:00068E* + ID_OUI_FROM_DATABASE=HID Corporation + +OUI:00068F* + ID_OUI_FROM_DATABASE=Telemonitor, Inc. + +OUI:000690* + ID_OUI_FROM_DATABASE=Euracom Communication GmbH + +OUI:000691* + ID_OUI_FROM_DATABASE=PT Inovacao + +OUI:000692* + ID_OUI_FROM_DATABASE=Intruvert Networks, Inc. + +OUI:000693* + ID_OUI_FROM_DATABASE=Flexus Computer Technology, Inc. + +OUI:000694* + ID_OUI_FROM_DATABASE=Mobillian Corporation + +OUI:000695* + ID_OUI_FROM_DATABASE=Ensure Technologies, Inc. + +OUI:000696* + ID_OUI_FROM_DATABASE=Advent Networks + +OUI:000697* + ID_OUI_FROM_DATABASE=R & D Center + +OUI:000698* + ID_OUI_FROM_DATABASE=egnite GmbH + +OUI:000699* + ID_OUI_FROM_DATABASE=Vida Design Co. + +OUI:00069A* + ID_OUI_FROM_DATABASE=e & Tel + +OUI:00069B* + ID_OUI_FROM_DATABASE=AVT Audio Video Technologies GmbH + +OUI:00069C* + ID_OUI_FROM_DATABASE=Transmode Systems AB + +OUI:00069D* + ID_OUI_FROM_DATABASE=Petards Ltd + +OUI:00069E* + ID_OUI_FROM_DATABASE=UNIQA, Inc. + +OUI:00069F* + ID_OUI_FROM_DATABASE=Kuokoa Networks + +OUI:0006A0* + ID_OUI_FROM_DATABASE=Mx Imaging + +OUI:0006A1* + ID_OUI_FROM_DATABASE=Celsian Technologies, Inc. + +OUI:0006A2* + ID_OUI_FROM_DATABASE=Microtune, Inc. + +OUI:0006A3* + ID_OUI_FROM_DATABASE=Bitran Corporation + +OUI:0006A4* + ID_OUI_FROM_DATABASE=INNOWELL Corp. + +OUI:0006A5* + ID_OUI_FROM_DATABASE=PINON Corp. + +OUI:0006A6* + ID_OUI_FROM_DATABASE=Artistic Licence Engineering Ltd + +OUI:0006A7* + ID_OUI_FROM_DATABASE=Primarion + +OUI:0006A8* + ID_OUI_FROM_DATABASE=KC Technology, Inc. + +OUI:0006A9* + ID_OUI_FROM_DATABASE=Universal Instruments Corp. + +OUI:0006AA* + ID_OUI_FROM_DATABASE=VT Miltope + +OUI:0006AB* + ID_OUI_FROM_DATABASE=W-Link Systems, Inc. + +OUI:0006AC* + ID_OUI_FROM_DATABASE=Intersoft Co. + +OUI:0006AD* + ID_OUI_FROM_DATABASE=KB Electronics Ltd. + +OUI:0006AE* + ID_OUI_FROM_DATABASE=Himachal Futuristic Communications Ltd + +OUI:0006AF* + ID_OUI_FROM_DATABASE=Xalted Networks + +OUI:0006B0* + ID_OUI_FROM_DATABASE=Comtech EF Data Corp. + +OUI:0006B1* + ID_OUI_FROM_DATABASE=Sonicwall + +OUI:0006B2* + ID_OUI_FROM_DATABASE=Linxtek Co. + +OUI:0006B3* + ID_OUI_FROM_DATABASE=Diagraph Corporation + +OUI:0006B4* + ID_OUI_FROM_DATABASE=Vorne Industries, Inc. + +OUI:0006B5* + ID_OUI_FROM_DATABASE=Source Photonics, Inc. + +OUI:0006B6* + ID_OUI_FROM_DATABASE=Nir-Or Israel Ltd. + +OUI:0006B7* + ID_OUI_FROM_DATABASE=TELEM GmbH + +OUI:0006B8* + ID_OUI_FROM_DATABASE=Bandspeed Pty Ltd + +OUI:0006B9* + ID_OUI_FROM_DATABASE=A5TEK Corp. + +OUI:0006BA* + ID_OUI_FROM_DATABASE=Westwave Communications + +OUI:0006BB* + ID_OUI_FROM_DATABASE=ATI Technologies Inc. + +OUI:0006BC* + ID_OUI_FROM_DATABASE=Macrolink, Inc. + +OUI:0006BD* + ID_OUI_FROM_DATABASE=BNTECHNOLOGY Co., Ltd. + +OUI:0006BE* + ID_OUI_FROM_DATABASE=Baumer Optronic GmbH + +OUI:0006BF* + ID_OUI_FROM_DATABASE=Accella Technologies Co., Ltd. + +OUI:0006C0* + ID_OUI_FROM_DATABASE=United Internetworks, Inc. + +OUI:0006C1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0006C2* + ID_OUI_FROM_DATABASE=Smartmatic Corporation + +OUI:0006C3* + ID_OUI_FROM_DATABASE=Schindler Elevator Ltd. + +OUI:0006C4* + ID_OUI_FROM_DATABASE=Piolink Inc. + +OUI:0006C5* + ID_OUI_FROM_DATABASE=INNOVI Technologies Limited + +OUI:0006C6* + ID_OUI_FROM_DATABASE=lesswire AG + +OUI:0006C7* + ID_OUI_FROM_DATABASE=RFNET Technologies Pte Ltd (S) + +OUI:0006C8* + ID_OUI_FROM_DATABASE=Sumitomo Metal Micro Devices, Inc. + +OUI:0006C9* + ID_OUI_FROM_DATABASE=Technical Marketing Research, Inc. + +OUI:0006CA* + ID_OUI_FROM_DATABASE=American Computer & Digital Components, Inc. (ACDC) + +OUI:0006CB* + ID_OUI_FROM_DATABASE=Jotron Electronics A/S + +OUI:0006CC* + ID_OUI_FROM_DATABASE=JMI Electronics Co., Ltd. + +OUI:0006CD* + ID_OUI_FROM_DATABASE=Leaf Imaging Ltd. + +OUI:0006CE* + ID_OUI_FROM_DATABASE=DATENO + +OUI:0006CF* + ID_OUI_FROM_DATABASE=Thales Avionics In-Flight Systems, LLC + +OUI:0006D0* + ID_OUI_FROM_DATABASE=Elgar Electronics Corp. + +OUI:0006D1* + ID_OUI_FROM_DATABASE=Tahoe Networks, Inc. + +OUI:0006D2* + ID_OUI_FROM_DATABASE=Tundra Semiconductor Corp. + +OUI:0006D3* + ID_OUI_FROM_DATABASE=Alpha Telecom, Inc. U.S.A. + +OUI:0006D4* + ID_OUI_FROM_DATABASE=Interactive Objects, Inc. + +OUI:0006D5* + ID_OUI_FROM_DATABASE=Diamond Systems Corp. + +OUI:0006D6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0006D7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0006D8* + ID_OUI_FROM_DATABASE=Maple Optical Systems + +OUI:0006D9* + ID_OUI_FROM_DATABASE=IPM-Net S.p.A. + +OUI:0006DA* + ID_OUI_FROM_DATABASE=ITRAN Communications Ltd. + +OUI:0006DB* + ID_OUI_FROM_DATABASE=ICHIPS Co., Ltd. + +OUI:0006DC* + ID_OUI_FROM_DATABASE=Syabas Technology (Amquest) + +OUI:0006DD* + ID_OUI_FROM_DATABASE=AT & T Laboratories - Cambridge Ltd + +OUI:0006DE* + ID_OUI_FROM_DATABASE=Flash Technology + +OUI:0006DF* + ID_OUI_FROM_DATABASE=AIDONIC Corporation + +OUI:0006E0* + ID_OUI_FROM_DATABASE=MAT Co., Ltd. + +OUI:0006E1* + ID_OUI_FROM_DATABASE=Techno Trade s.a + +OUI:0006E2* + ID_OUI_FROM_DATABASE=Ceemax Technology Co., Ltd. + +OUI:0006E3* + ID_OUI_FROM_DATABASE=Quantitative Imaging Corporation + +OUI:0006E4* + ID_OUI_FROM_DATABASE=Citel Technologies Ltd. + +OUI:0006E5* + ID_OUI_FROM_DATABASE=Fujian Newland Computer Ltd. Co. + +OUI:0006E6* + ID_OUI_FROM_DATABASE=DongYang Telecom Co., Ltd. + +OUI:0006E7* + ID_OUI_FROM_DATABASE=Bit Blitz Communications Inc. + +OUI:0006E8* + ID_OUI_FROM_DATABASE=Optical Network Testing, Inc. + +OUI:0006E9* + ID_OUI_FROM_DATABASE=Intime Corp. + +OUI:0006EA* + ID_OUI_FROM_DATABASE=ELZET80 Mikrocomputer GmbH&Co. KG + +OUI:0006EB* + ID_OUI_FROM_DATABASE=Global Data + +OUI:0006EC* + ID_OUI_FROM_DATABASE=Harris Corporation + +OUI:0006ED* + ID_OUI_FROM_DATABASE=Inara Networks + +OUI:0006EE* + ID_OUI_FROM_DATABASE=Shenyang Neu-era Information & Technology Stock Co., Ltd + +OUI:0006EF* + ID_OUI_FROM_DATABASE=Maxxan Systems, Inc. + +OUI:0006F0* + ID_OUI_FROM_DATABASE=Digeo, Inc. + +OUI:0006F1* + ID_OUI_FROM_DATABASE=Optillion + +OUI:0006F2* + ID_OUI_FROM_DATABASE=Platys Communications + +OUI:0006F3* + ID_OUI_FROM_DATABASE=AcceLight Networks + +OUI:0006F4* + ID_OUI_FROM_DATABASE=Prime Electronics & Satellitics Inc. + +OUI:0006F5* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:0006F6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0006F7* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:0006F8* + ID_OUI_FROM_DATABASE=CPU Technology, Inc. + +OUI:0006F9* + ID_OUI_FROM_DATABASE=Mitsui Zosen Systems Research Inc. + +OUI:0006FA* + ID_OUI_FROM_DATABASE=IP SQUARE Co, Ltd. + +OUI:0006FB* + ID_OUI_FROM_DATABASE=Hitachi Printing Solutions, Ltd. + +OUI:0006FC* + ID_OUI_FROM_DATABASE=Fnet Co., Ltd. + +OUI:0006FD* + ID_OUI_FROM_DATABASE=Comjet Information Systems Corp. + +OUI:0006FE* + ID_OUI_FROM_DATABASE=Ambrado, Inc + +OUI:0006FF* + ID_OUI_FROM_DATABASE=Sheba Systems Co., Ltd. + +OUI:000700* + ID_OUI_FROM_DATABASE=Zettamedia Korea + +OUI:000701* + ID_OUI_FROM_DATABASE=RACAL-DATACOM + +OUI:000702* + ID_OUI_FROM_DATABASE=Varian Medical Systems + +OUI:000703* + ID_OUI_FROM_DATABASE=CSEE Transport + +OUI:000704* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:000705* + ID_OUI_FROM_DATABASE=Endress & Hauser GmbH & Co + +OUI:000706* + ID_OUI_FROM_DATABASE=Sanritz Corporation + +OUI:000707* + ID_OUI_FROM_DATABASE=Interalia Inc. + +OUI:000708* + ID_OUI_FROM_DATABASE=Bitrage Inc. + +OUI:000709* + ID_OUI_FROM_DATABASE=Westerstrand Urfabrik AB + +OUI:00070A* + ID_OUI_FROM_DATABASE=Unicom Automation Co., Ltd. + +OUI:00070B* + ID_OUI_FROM_DATABASE=Novabase SGPS, SA + +OUI:00070C* + ID_OUI_FROM_DATABASE=SVA-Intrusion.com Co. Ltd. + +OUI:00070D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00070E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00070F* + ID_OUI_FROM_DATABASE=Fujant, Inc. + +OUI:000710* + ID_OUI_FROM_DATABASE=Adax, Inc. + +OUI:000711* + ID_OUI_FROM_DATABASE=Acterna + +OUI:000712* + ID_OUI_FROM_DATABASE=JAL Information Technology + +OUI:000713* + ID_OUI_FROM_DATABASE=IP One, Inc. + +OUI:000714* + ID_OUI_FROM_DATABASE=Brightcom + +OUI:000715* + ID_OUI_FROM_DATABASE=General Research of Electronics, Inc. + +OUI:000716* + ID_OUI_FROM_DATABASE=J & S Marine Ltd. + +OUI:000717* + ID_OUI_FROM_DATABASE=Wieland Electric GmbH + +OUI:000718* + ID_OUI_FROM_DATABASE=iCanTek Co., Ltd. + +OUI:000719* + ID_OUI_FROM_DATABASE=Mobiis Co., Ltd. + +OUI:00071A* + ID_OUI_FROM_DATABASE=Finedigital Inc. + +OUI:00071B* + ID_OUI_FROM_DATABASE=CDVI Americas Ltd + +OUI:00071C* + ID_OUI_FROM_DATABASE=AT&T Fixed Wireless Services + +OUI:00071D* + ID_OUI_FROM_DATABASE=Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A. + +OUI:00071E* + ID_OUI_FROM_DATABASE=Tri-M Engineering / Nupak Dev. Corp. + +OUI:00071F* + ID_OUI_FROM_DATABASE=European Systems Integration + +OUI:000720* + ID_OUI_FROM_DATABASE=Trutzschler GmbH & Co. KG + +OUI:000721* + ID_OUI_FROM_DATABASE=Formac Elektronik GmbH + +OUI:000722* + ID_OUI_FROM_DATABASE=The Nielsen Company + +OUI:000723* + ID_OUI_FROM_DATABASE=ELCON Systemtechnik GmbH + +OUI:000724* + ID_OUI_FROM_DATABASE=Telemax Co., Ltd. + +OUI:000725* + ID_OUI_FROM_DATABASE=Bematech International Corp. + +OUI:000726* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co., Ltd. + +OUI:000727* + ID_OUI_FROM_DATABASE=Zi Corporation (HK) Ltd. + +OUI:000728* + ID_OUI_FROM_DATABASE=Neo Telecom + +OUI:000729* + ID_OUI_FROM_DATABASE=Kistler Instrumente AG + +OUI:00072A* + ID_OUI_FROM_DATABASE=Innovance Networks + +OUI:00072B* + ID_OUI_FROM_DATABASE=Jung Myung Telecom Co., Ltd. + +OUI:00072C* + ID_OUI_FROM_DATABASE=Fabricom + +OUI:00072D* + ID_OUI_FROM_DATABASE=CNSystems + +OUI:00072E* + ID_OUI_FROM_DATABASE=North Node AB + +OUI:00072F* + ID_OUI_FROM_DATABASE=Intransa, Inc. + +OUI:000730* + ID_OUI_FROM_DATABASE=Hutchison OPTEL Telecom Technology Co., Ltd. + +OUI:000731* + ID_OUI_FROM_DATABASE=Ophir-Spiricon LLC + +OUI:000732* + ID_OUI_FROM_DATABASE=AAEON Technology Inc. + +OUI:000733* + ID_OUI_FROM_DATABASE=DANCONTROL Engineering + +OUI:000734* + ID_OUI_FROM_DATABASE=ONStor, Inc. + +OUI:000735* + ID_OUI_FROM_DATABASE=Flarion Technologies, Inc. + +OUI:000736* + ID_OUI_FROM_DATABASE=Data Video Technologies Co., Ltd. + +OUI:000737* + ID_OUI_FROM_DATABASE=Soriya Co. Ltd. + +OUI:000738* + ID_OUI_FROM_DATABASE=Young Technology Co., Ltd. + +OUI:000739* + ID_OUI_FROM_DATABASE=Scotty Group Austria Gmbh + +OUI:00073A* + ID_OUI_FROM_DATABASE=Inventel Systemes + +OUI:00073B* + ID_OUI_FROM_DATABASE=Tenovis GmbH & Co KG + +OUI:00073C* + ID_OUI_FROM_DATABASE=Telecom Design + +OUI:00073D* + ID_OUI_FROM_DATABASE=Nanjing Postel Telecommunications Co., Ltd. + +OUI:00073E* + ID_OUI_FROM_DATABASE=China Great-Wall Computer Shenzhen Co., Ltd. + +OUI:00073F* + ID_OUI_FROM_DATABASE=Woojyun Systec Co., Ltd. + +OUI:000740* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:000741* + ID_OUI_FROM_DATABASE=Sierra Automated Systems + +OUI:000742* + ID_OUI_FROM_DATABASE=Current Technologies, LLC + +OUI:000743* + ID_OUI_FROM_DATABASE=Chelsio Communications + +OUI:000744* + ID_OUI_FROM_DATABASE=Unico, Inc. + +OUI:000745* + ID_OUI_FROM_DATABASE=Radlan Computer Communications Ltd. + +OUI:000746* + ID_OUI_FROM_DATABASE=TURCK, Inc. + +OUI:000747* + ID_OUI_FROM_DATABASE=Mecalc + +OUI:000748* + ID_OUI_FROM_DATABASE=The Imaging Source Europe + +OUI:000749* + ID_OUI_FROM_DATABASE=CENiX Inc. + +OUI:00074A* + ID_OUI_FROM_DATABASE=Carl Valentin GmbH + +OUI:00074B* + ID_OUI_FROM_DATABASE=Daihen Corporation + +OUI:00074C* + ID_OUI_FROM_DATABASE=Beicom Inc. + +OUI:00074D* + ID_OUI_FROM_DATABASE=Zebra Technologies Corp. + +OUI:00074E* + ID_OUI_FROM_DATABASE=IPFRONT Inc + +OUI:00074F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000750* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000751* + ID_OUI_FROM_DATABASE=m-u-t AG + +OUI:000752* + ID_OUI_FROM_DATABASE=Rhythm Watch Co., Ltd. + +OUI:000753* + ID_OUI_FROM_DATABASE=Beijing Qxcomm Technology Co., Ltd. + +OUI:000754* + ID_OUI_FROM_DATABASE=Xyterra Computing, Inc. + +OUI:000755* + ID_OUI_FROM_DATABASE=Lafon + +OUI:000756* + ID_OUI_FROM_DATABASE=Juyoung Telecom + +OUI:000757* + ID_OUI_FROM_DATABASE=Topcall International AG + +OUI:000758* + ID_OUI_FROM_DATABASE=Dragonwave + +OUI:000759* + ID_OUI_FROM_DATABASE=Boris Manufacturing Corp. + +OUI:00075A* + ID_OUI_FROM_DATABASE=Air Products and Chemicals, Inc. + +OUI:00075B* + ID_OUI_FROM_DATABASE=Gibson Guitars + +OUI:00075C* + ID_OUI_FROM_DATABASE=Eastman Kodak Company + +OUI:00075D* + ID_OUI_FROM_DATABASE=Celleritas Inc. + +OUI:00075E* + ID_OUI_FROM_DATABASE=Ametek Power Instruments + +OUI:00075F* + ID_OUI_FROM_DATABASE=VCS Video Communication Systems AG + +OUI:000760* + ID_OUI_FROM_DATABASE=TOMIS Information & Telecom Corp. + +OUI:000761* + ID_OUI_FROM_DATABASE=Logitech Europe SA + +OUI:000762* + ID_OUI_FROM_DATABASE=Group Sense Limited + +OUI:000763* + ID_OUI_FROM_DATABASE=Sunniwell Cyber Tech. Co., Ltd. + +OUI:000764* + ID_OUI_FROM_DATABASE=YoungWoo Telecom Co. Ltd. + +OUI:000765* + ID_OUI_FROM_DATABASE=Jade Quantum Technologies, Inc. + +OUI:000766* + ID_OUI_FROM_DATABASE=Chou Chin Industrial Co., Ltd. + +OUI:000767* + ID_OUI_FROM_DATABASE=Yuxing Electronics Company Limited + +OUI:000768* + ID_OUI_FROM_DATABASE=Danfoss A/S + +OUI:000769* + ID_OUI_FROM_DATABASE=Italiana Macchi SpA + +OUI:00076A* + ID_OUI_FROM_DATABASE=NEXTEYE Co., Ltd. + +OUI:00076B* + ID_OUI_FROM_DATABASE=Stralfors AB + +OUI:00076C* + ID_OUI_FROM_DATABASE=Daehanet, Inc. + +OUI:00076D* + ID_OUI_FROM_DATABASE=Flexlight Networks + +OUI:00076E* + ID_OUI_FROM_DATABASE=Sinetica Corporation Limited + +OUI:00076F* + ID_OUI_FROM_DATABASE=Synoptics Limited + +OUI:000770* + ID_OUI_FROM_DATABASE=Locusnetworks Corporation + +OUI:000771* + ID_OUI_FROM_DATABASE=Embedded System Corporation + +OUI:000772* + ID_OUI_FROM_DATABASE=Alcatel Shanghai Bell Co., Ltd. + +OUI:000773* + ID_OUI_FROM_DATABASE=Ascom Powerline Communications Ltd. + +OUI:000774* + ID_OUI_FROM_DATABASE=GuangZhou Thinker Technology Co. Ltd. + +OUI:000775* + ID_OUI_FROM_DATABASE=Valence Semiconductor, Inc. + +OUI:000776* + ID_OUI_FROM_DATABASE=Federal APD + +OUI:000777* + ID_OUI_FROM_DATABASE=Motah Ltd. + +OUI:000778* + ID_OUI_FROM_DATABASE=GERSTEL GmbH & Co. KG + +OUI:000779* + ID_OUI_FROM_DATABASE=Sungil Telecom Co., Ltd. + +OUI:00077A* + ID_OUI_FROM_DATABASE=Infoware System Co., Ltd. + +OUI:00077B* + ID_OUI_FROM_DATABASE=Millimetrix Broadband Networks + +OUI:00077C* + ID_OUI_FROM_DATABASE=Westermo Teleindustri AB + +OUI:00077D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00077E* + ID_OUI_FROM_DATABASE=Elrest GmbH + +OUI:00077F* + ID_OUI_FROM_DATABASE=J Communications Co., Ltd. + +OUI:000780* + ID_OUI_FROM_DATABASE=Bluegiga Technologies OY + +OUI:000781* + ID_OUI_FROM_DATABASE=Itron Inc. + +OUI:000782* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:000783* + ID_OUI_FROM_DATABASE=SynCom Network, Inc. + +OUI:000784* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000785* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000786* + ID_OUI_FROM_DATABASE=Wireless Networks Inc. + +OUI:000787* + ID_OUI_FROM_DATABASE=Idea System Co., Ltd. + +OUI:000788* + ID_OUI_FROM_DATABASE=Clipcomm, Inc. + +OUI:000789* + ID_OUI_FROM_DATABASE=DONGWON SYSTEMS + +OUI:00078A* + ID_OUI_FROM_DATABASE=Mentor Data System Inc. + +OUI:00078B* + ID_OUI_FROM_DATABASE=Wegener Communications, Inc. + +OUI:00078C* + ID_OUI_FROM_DATABASE=Elektronikspecialisten i Borlange AB + +OUI:00078D* + ID_OUI_FROM_DATABASE=NetEngines Ltd. + +OUI:00078E* + ID_OUI_FROM_DATABASE=Garz & Friche GmbH + +OUI:00078F* + ID_OUI_FROM_DATABASE=Emkay Innovative Products + +OUI:000790* + ID_OUI_FROM_DATABASE=Tri-M Technologies (s) Limited + +OUI:000791* + ID_OUI_FROM_DATABASE=International Data Communications, Inc. + +OUI:000792* + ID_OUI_FROM_DATABASE=Sütron Electronic GmbH + +OUI:000793* + ID_OUI_FROM_DATABASE=Shin Satellite Public Company Limited + +OUI:000794* + ID_OUI_FROM_DATABASE=Simple Devices, Inc. + +OUI:000795* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) + +OUI:000796* + ID_OUI_FROM_DATABASE=LSI Systems, Inc. + +OUI:000797* + ID_OUI_FROM_DATABASE=Netpower Co., Ltd. + +OUI:000798* + ID_OUI_FROM_DATABASE=Selea SRL + +OUI:000799* + ID_OUI_FROM_DATABASE=Tipping Point Technologies, Inc. + +OUI:00079A* + ID_OUI_FROM_DATABASE=Verint Systems Inc + +OUI:00079B* + ID_OUI_FROM_DATABASE=Aurora Networks + +OUI:00079C* + ID_OUI_FROM_DATABASE=Golden Electronics Technology Co., Ltd. + +OUI:00079D* + ID_OUI_FROM_DATABASE=Musashi Co., Ltd. + +OUI:00079E* + ID_OUI_FROM_DATABASE=Ilinx Co., Ltd. + +OUI:00079F* + ID_OUI_FROM_DATABASE=Action Digital Inc. + +OUI:0007A0* + ID_OUI_FROM_DATABASE=e-Watch Inc. + +OUI:0007A1* + ID_OUI_FROM_DATABASE=VIASYS Healthcare GmbH + +OUI:0007A2* + ID_OUI_FROM_DATABASE=Opteon Corporation + +OUI:0007A3* + ID_OUI_FROM_DATABASE=Ositis Software, Inc. + +OUI:0007A4* + ID_OUI_FROM_DATABASE=GN Netcom Ltd. + +OUI:0007A5* + ID_OUI_FROM_DATABASE=Y.D.K Co. Ltd. + +OUI:0007A6* + ID_OUI_FROM_DATABASE=Home Automation, Inc. + +OUI:0007A7* + ID_OUI_FROM_DATABASE=A-Z Inc. + +OUI:0007A8* + ID_OUI_FROM_DATABASE=Haier Group Technologies Ltd. + +OUI:0007A9* + ID_OUI_FROM_DATABASE=Novasonics + +OUI:0007AA* + ID_OUI_FROM_DATABASE=Quantum Data Inc. + +OUI:0007AB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0007AC* + ID_OUI_FROM_DATABASE=Eolring + +OUI:0007AD* + ID_OUI_FROM_DATABASE=Pentacon GmbH Foto-und Feinwerktechnik + +OUI:0007AE* + ID_OUI_FROM_DATABASE=Britestream Networks, Inc. + +OUI:0007AF* + ID_OUI_FROM_DATABASE=N-TRON Corporation + +OUI:0007B0* + ID_OUI_FROM_DATABASE=Office Details, Inc. + +OUI:0007B1* + ID_OUI_FROM_DATABASE=Equator Technologies + +OUI:0007B2* + ID_OUI_FROM_DATABASE=Transaccess S.A. + +OUI:0007B3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0007B4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0007B5* + ID_OUI_FROM_DATABASE=Any One Wireless Ltd. + +OUI:0007B6* + ID_OUI_FROM_DATABASE=Telecom Technology Ltd. + +OUI:0007B7* + ID_OUI_FROM_DATABASE=Samurai Ind. Prods Eletronicos Ltda + +OUI:0007B8* + ID_OUI_FROM_DATABASE=Corvalent Corporation + +OUI:0007B9* + ID_OUI_FROM_DATABASE=Ginganet Corporation + +OUI:0007BA* + ID_OUI_FROM_DATABASE=UTStarcom, Inc. + +OUI:0007BB* + ID_OUI_FROM_DATABASE=Candera Inc. + +OUI:0007BC* + ID_OUI_FROM_DATABASE=Identix Inc. + +OUI:0007BD* + ID_OUI_FROM_DATABASE=Radionet Ltd. + +OUI:0007BE* + ID_OUI_FROM_DATABASE=DataLogic SpA + +OUI:0007BF* + ID_OUI_FROM_DATABASE=Armillaire Technologies, Inc. + +OUI:0007C0* + ID_OUI_FROM_DATABASE=NetZerver Inc. + +OUI:0007C1* + ID_OUI_FROM_DATABASE=Overture Networks, Inc. + +OUI:0007C2* + ID_OUI_FROM_DATABASE=Netsys Telecom + +OUI:0007C3* + ID_OUI_FROM_DATABASE=Thomson + +OUI:0007C4* + ID_OUI_FROM_DATABASE=JEAN Co. Ltd. + +OUI:0007C5* + ID_OUI_FROM_DATABASE=Gcom, Inc. + +OUI:0007C6* + ID_OUI_FROM_DATABASE=VDS Vosskuhler GmbH + +OUI:0007C7* + ID_OUI_FROM_DATABASE=Synectics Systems Limited + +OUI:0007C8* + ID_OUI_FROM_DATABASE=Brain21, Inc. + +OUI:0007C9* + ID_OUI_FROM_DATABASE=Technol Seven Co., Ltd. + +OUI:0007CA* + ID_OUI_FROM_DATABASE=Creatix Polymedia Ges Fur Kommunikaitonssysteme + +OUI:0007CB* + ID_OUI_FROM_DATABASE=Freebox SA + +OUI:0007CC* + ID_OUI_FROM_DATABASE=Kaba Benzing GmbH + +OUI:0007CD* + ID_OUI_FROM_DATABASE=NMTEL Co., Ltd. + +OUI:0007CE* + ID_OUI_FROM_DATABASE=Cabletime Limited + +OUI:0007CF* + ID_OUI_FROM_DATABASE=Anoto AB + +OUI:0007D0* + ID_OUI_FROM_DATABASE=Automat Engenharia de Automação Ltda. + +OUI:0007D1* + ID_OUI_FROM_DATABASE=Spectrum Signal Processing Inc. + +OUI:0007D2* + ID_OUI_FROM_DATABASE=Logopak Systeme GmbH & Co. KG + +OUI:0007D3* + ID_OUI_FROM_DATABASE=SPGPrints B.V. + +OUI:0007D4* + ID_OUI_FROM_DATABASE=Zhejiang Yutong Network Communication Co Ltd. + +OUI:0007D5* + ID_OUI_FROM_DATABASE=3e Technologies Int;., Inc. + +OUI:0007D6* + ID_OUI_FROM_DATABASE=Commil Ltd. + +OUI:0007D7* + ID_OUI_FROM_DATABASE=Caporis Networks AG + +OUI:0007D8* + ID_OUI_FROM_DATABASE=Hitron Systems Inc. + +OUI:0007D9* + ID_OUI_FROM_DATABASE=Splicecom + +OUI:0007DA* + ID_OUI_FROM_DATABASE=Neuro Telecom Co., Ltd. + +OUI:0007DB* + ID_OUI_FROM_DATABASE=Kirana Networks, Inc. + +OUI:0007DC* + ID_OUI_FROM_DATABASE=Atek Co, Ltd. + +OUI:0007DD* + ID_OUI_FROM_DATABASE=Cradle Technologies + +OUI:0007DE* + ID_OUI_FROM_DATABASE=eCopilt AB + +OUI:0007DF* + ID_OUI_FROM_DATABASE=Vbrick Systems Inc. + +OUI:0007E0* + ID_OUI_FROM_DATABASE=Palm Inc. + +OUI:0007E1* + ID_OUI_FROM_DATABASE=WIS Communications Co. Ltd. + +OUI:0007E2* + ID_OUI_FROM_DATABASE=Bitworks, Inc. + +OUI:0007E3* + ID_OUI_FROM_DATABASE=Navcom Technology, Inc. + +OUI:0007E4* + ID_OUI_FROM_DATABASE=SoftRadio Co., Ltd. + +OUI:0007E5* + ID_OUI_FROM_DATABASE=Coup Corporation + +OUI:0007E6* + ID_OUI_FROM_DATABASE=edgeflow Canada Inc. + +OUI:0007E7* + ID_OUI_FROM_DATABASE=FreeWave Technologies + +OUI:0007E8* + ID_OUI_FROM_DATABASE=EdgeWave + +OUI:0007E9* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:0007EA* + ID_OUI_FROM_DATABASE=Massana, Inc. + +OUI:0007EB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0007EC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0007ED* + ID_OUI_FROM_DATABASE=Altera Corporation + +OUI:0007EE* + ID_OUI_FROM_DATABASE=telco Informationssysteme GmbH + +OUI:0007EF* + ID_OUI_FROM_DATABASE=Lockheed Martin Tactical Systems + +OUI:0007F0* + ID_OUI_FROM_DATABASE=LogiSync LLC + +OUI:0007F1* + ID_OUI_FROM_DATABASE=TeraBurst Networks Inc. + +OUI:0007F2* + ID_OUI_FROM_DATABASE=IOA Corporation + +OUI:0007F3* + ID_OUI_FROM_DATABASE=Thinkengine Networks + +OUI:0007F4* + ID_OUI_FROM_DATABASE=Eletex Co., Ltd. + +OUI:0007F5* + ID_OUI_FROM_DATABASE=Bridgeco Co AG + +OUI:0007F6* + ID_OUI_FROM_DATABASE=Qqest Software Systems + +OUI:0007F7* + ID_OUI_FROM_DATABASE=Galtronics + +OUI:0007F8* + ID_OUI_FROM_DATABASE=ITDevices, Inc. + +OUI:0007F9* + ID_OUI_FROM_DATABASE=Sensaphone + +OUI:0007FA* + ID_OUI_FROM_DATABASE=ITT Co., Ltd. + +OUI:0007FB* + ID_OUI_FROM_DATABASE=Giga Stream UMTS Technologies GmbH + +OUI:0007FC* + ID_OUI_FROM_DATABASE=Adept Systems Inc. + +OUI:0007FD* + ID_OUI_FROM_DATABASE=LANergy Ltd. + +OUI:0007FE* + ID_OUI_FROM_DATABASE=Rigaku Corporation + +OUI:0007FF* + ID_OUI_FROM_DATABASE=Gluon Networks + +OUI:000800* + ID_OUI_FROM_DATABASE=MULTITECH SYSTEMS, INC. + +OUI:000801* + ID_OUI_FROM_DATABASE=HighSpeed Surfing Inc. + +OUI:000802* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000803* + ID_OUI_FROM_DATABASE=Cos Tron + +OUI:000804* + ID_OUI_FROM_DATABASE=ICA Inc. + +OUI:000805* + ID_OUI_FROM_DATABASE=Techno-Holon Corporation + +OUI:000806* + ID_OUI_FROM_DATABASE=Raonet Systems, Inc. + +OUI:000807* + ID_OUI_FROM_DATABASE=Access Devices Limited + +OUI:000808* + ID_OUI_FROM_DATABASE=PPT Vision, Inc. + +OUI:000809* + ID_OUI_FROM_DATABASE=Systemonic AG + +OUI:00080A* + ID_OUI_FROM_DATABASE=Espera-Werke GmbH + +OUI:00080B* + ID_OUI_FROM_DATABASE=Birka BPA Informationssystem AB + +OUI:00080C* + ID_OUI_FROM_DATABASE=VDA Elettronica spa + +OUI:00080D* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:00080E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00080F* + ID_OUI_FROM_DATABASE=Proximion Fiber Optics AB + +OUI:000810* + ID_OUI_FROM_DATABASE=Key Technology, Inc. + +OUI:000811* + ID_OUI_FROM_DATABASE=VOIX Corporation + +OUI:000812* + ID_OUI_FROM_DATABASE=GM-2 Corporation + +OUI:000813* + ID_OUI_FROM_DATABASE=Diskbank, Inc. + +OUI:000814* + ID_OUI_FROM_DATABASE=TIL Technologies + +OUI:000815* + ID_OUI_FROM_DATABASE=CATS Co., Ltd. + +OUI:000816* + ID_OUI_FROM_DATABASE=Bluelon ApS + +OUI:000817* + ID_OUI_FROM_DATABASE=EmergeCore Networks LLC + +OUI:000818* + ID_OUI_FROM_DATABASE=Pixelworks, Inc. + +OUI:000819* + ID_OUI_FROM_DATABASE=Banksys + +OUI:00081A* + ID_OUI_FROM_DATABASE=Sanrad Intelligence Storage Communications (2000) Ltd. + +OUI:00081B* + ID_OUI_FROM_DATABASE=Windigo Systems + +OUI:00081C* + ID_OUI_FROM_DATABASE=@pos.com + +OUI:00081D* + ID_OUI_FROM_DATABASE=Ipsil, Incorporated + +OUI:00081E* + ID_OUI_FROM_DATABASE=Repeatit AB + +OUI:00081F* + ID_OUI_FROM_DATABASE=Pou Yuen Tech Corp. Ltd. + +OUI:000820* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000821* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000822* + ID_OUI_FROM_DATABASE=InPro Comm + +OUI:000823* + ID_OUI_FROM_DATABASE=Texa Corp. + +OUI:000824* + ID_OUI_FROM_DATABASE=Nuance Document Imaging + +OUI:000825* + ID_OUI_FROM_DATABASE=Acme Packet + +OUI:000826* + ID_OUI_FROM_DATABASE=Colorado Med Tech + +OUI:000827* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:000828* + ID_OUI_FROM_DATABASE=Koei Engineering Ltd. + +OUI:000829* + ID_OUI_FROM_DATABASE=Aval Nagasaki Corporation + +OUI:00082A* + ID_OUI_FROM_DATABASE=Powerwallz Network Security + +OUI:00082B* + ID_OUI_FROM_DATABASE=Wooksung Electronics, Inc. + +OUI:00082C* + ID_OUI_FROM_DATABASE=Homag AG + +OUI:00082D* + ID_OUI_FROM_DATABASE=Indus Teqsite Private Limited + +OUI:00082E* + ID_OUI_FROM_DATABASE=Multitone Electronics PLC + +OUI:00082F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000830* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000831* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000832* + ID_OUI_FROM_DATABASE=Cisco + +OUI:00084E* + ID_OUI_FROM_DATABASE=DivergeNet, Inc. + +OUI:00084F* + ID_OUI_FROM_DATABASE=Qualstar Corporation + +OUI:000850* + ID_OUI_FROM_DATABASE=Arizona Instrument Corp. + +OUI:000851* + ID_OUI_FROM_DATABASE=Canadian Bank Note Company, Ltd. + +OUI:000852* + ID_OUI_FROM_DATABASE=Davolink Co. Inc. + +OUI:000853* + ID_OUI_FROM_DATABASE=Schleicher GmbH & Co. Relaiswerke KG + +OUI:000854* + ID_OUI_FROM_DATABASE=Netronix, Inc. + +OUI:000855* + ID_OUI_FROM_DATABASE=NASA-Goddard Space Flight Center + +OUI:000856* + ID_OUI_FROM_DATABASE=Gamatronic Electronic Industries Ltd. + +OUI:000857* + ID_OUI_FROM_DATABASE=Polaris Networks, Inc. + +OUI:000858* + ID_OUI_FROM_DATABASE=Novatechnology Inc. + +OUI:000859* + ID_OUI_FROM_DATABASE=ShenZhen Unitone Electronics Co., Ltd. + +OUI:00085A* + ID_OUI_FROM_DATABASE=IntiGate Inc. + +OUI:00085B* + ID_OUI_FROM_DATABASE=Hanbit Electronics Co., Ltd. + +OUI:00085C* + ID_OUI_FROM_DATABASE=Shanghai Dare Technologies Co. Ltd. + +OUI:00085D* + ID_OUI_FROM_DATABASE=Aastra + +OUI:00085E* + ID_OUI_FROM_DATABASE=PCO AG + +OUI:00085F* + ID_OUI_FROM_DATABASE=Picanol N.V. + +OUI:000860* + ID_OUI_FROM_DATABASE=LodgeNet Entertainment Corp. + +OUI:000861* + ID_OUI_FROM_DATABASE=SoftEnergy Co., Ltd. + +OUI:000862* + ID_OUI_FROM_DATABASE=NEC Eluminant Technologies, Inc. + +OUI:000863* + ID_OUI_FROM_DATABASE=Entrisphere Inc. + +OUI:000864* + ID_OUI_FROM_DATABASE=Fasy S.p.A. + +OUI:000865* + ID_OUI_FROM_DATABASE=JASCOM CO., LTD + +OUI:000866* + ID_OUI_FROM_DATABASE=DSX Access Systems, Inc. + +OUI:000867* + ID_OUI_FROM_DATABASE=Uptime Devices + +OUI:000868* + ID_OUI_FROM_DATABASE=PurOptix + +OUI:000869* + ID_OUI_FROM_DATABASE=Command-e Technology Co.,Ltd. + +OUI:00086A* + ID_OUI_FROM_DATABASE=Securiton Gmbh + +OUI:00086B* + ID_OUI_FROM_DATABASE=MIPSYS + +OUI:00086C* + ID_OUI_FROM_DATABASE=Plasmon LMS + +OUI:00086D* + ID_OUI_FROM_DATABASE=Missouri FreeNet + +OUI:00086E* + ID_OUI_FROM_DATABASE=Hyglo AB + +OUI:00086F* + ID_OUI_FROM_DATABASE=Resources Computer Network Ltd. + +OUI:000870* + ID_OUI_FROM_DATABASE=Rasvia Systems, Inc. + +OUI:000871* + ID_OUI_FROM_DATABASE=NORTHDATA Co., Ltd. + +OUI:000872* + ID_OUI_FROM_DATABASE=Sorenson Communications + +OUI:000873* + ID_OUI_FROM_DATABASE=DapTechnology B.V. + +OUI:000874* + ID_OUI_FROM_DATABASE=Dell Computer Corp. + +OUI:000875* + ID_OUI_FROM_DATABASE=Acorp Electronics Corp. + +OUI:000876* + ID_OUI_FROM_DATABASE=SDSystem + +OUI:000877* + ID_OUI_FROM_DATABASE=Liebert-Hiross Spa + +OUI:000878* + ID_OUI_FROM_DATABASE=Benchmark Storage Innovations + +OUI:000879* + ID_OUI_FROM_DATABASE=CEM Corporation + +OUI:00087A* + ID_OUI_FROM_DATABASE=Wipotec GmbH + +OUI:00087B* + ID_OUI_FROM_DATABASE=RTX Telecom A/S + +OUI:00087C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00087D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00087E* + ID_OUI_FROM_DATABASE=Bon Electro-Telecom Inc. + +OUI:00087F* + ID_OUI_FROM_DATABASE=SPAUN electronic GmbH & Co. KG + +OUI:000880* + ID_OUI_FROM_DATABASE=BroadTel Canada Communications inc. + +OUI:000881* + ID_OUI_FROM_DATABASE=DIGITAL HANDS CO.,LTD. + +OUI:000882* + ID_OUI_FROM_DATABASE=SIGMA CORPORATION + +OUI:000883* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000884* + ID_OUI_FROM_DATABASE=Index Braille AB + +OUI:000885* + ID_OUI_FROM_DATABASE=EMS Dr. Thomas Wünsche + +OUI:000886* + ID_OUI_FROM_DATABASE=Hansung Teliann, Inc. + +OUI:000887* + ID_OUI_FROM_DATABASE=Maschinenfabrik Reinhausen GmbH + +OUI:000888* + ID_OUI_FROM_DATABASE=OULLIM Information Technology Inc,. + +OUI:000889* + ID_OUI_FROM_DATABASE=Echostar Technologies Corp + +OUI:00088A* + ID_OUI_FROM_DATABASE=Minds@Work + +OUI:00088B* + ID_OUI_FROM_DATABASE=Tropic Networks Inc. + +OUI:00088C* + ID_OUI_FROM_DATABASE=Quanta Network Systems Inc. + +OUI:00088D* + ID_OUI_FROM_DATABASE=Sigma-Links Inc. + +OUI:00088E* + ID_OUI_FROM_DATABASE=Nihon Computer Co., Ltd. + +OUI:00088F* + ID_OUI_FROM_DATABASE=ADVANCED DIGITAL TECHNOLOGY + +OUI:000890* + ID_OUI_FROM_DATABASE=AVILINKS SA + +OUI:000891* + ID_OUI_FROM_DATABASE=Lyan Inc. + +OUI:000892* + ID_OUI_FROM_DATABASE=EM Solutions + +OUI:000893* + ID_OUI_FROM_DATABASE=LE INFORMATION COMMUNICATION INC. + +OUI:000894* + ID_OUI_FROM_DATABASE=InnoVISION Multimedia Ltd. + +OUI:000895* + ID_OUI_FROM_DATABASE=DIRC Technologie GmbH & Co.KG + +OUI:000896* + ID_OUI_FROM_DATABASE=Printronix, Inc. + +OUI:000897* + ID_OUI_FROM_DATABASE=Quake Technologies + +OUI:000898* + ID_OUI_FROM_DATABASE=Gigabit Optics Corporation + +OUI:000899* + ID_OUI_FROM_DATABASE=Netbind, Inc. + +OUI:00089A* + ID_OUI_FROM_DATABASE=Alcatel Microelectronics + +OUI:00089B* + ID_OUI_FROM_DATABASE=ICP Electronics Inc. + +OUI:00089C* + ID_OUI_FROM_DATABASE=Elecs Industry Co., Ltd. + +OUI:00089D* + ID_OUI_FROM_DATABASE=UHD-Elektronik + +OUI:00089E* + ID_OUI_FROM_DATABASE=Beijing Enter-Net co.LTD + +OUI:00089F* + ID_OUI_FROM_DATABASE=EFM Networks + +OUI:0008A0* + ID_OUI_FROM_DATABASE=Stotz Feinmesstechnik GmbH + +OUI:0008A1* + ID_OUI_FROM_DATABASE=CNet Technology Inc. + +OUI:0008A2* + ID_OUI_FROM_DATABASE=ADI Engineering, Inc. + +OUI:0008A3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0008A4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0008A5* + ID_OUI_FROM_DATABASE=Peninsula Systems Inc. + +OUI:0008A6* + ID_OUI_FROM_DATABASE=Multiware & Image Co., Ltd. + +OUI:0008A7* + ID_OUI_FROM_DATABASE=iLogic Inc. + +OUI:0008A8* + ID_OUI_FROM_DATABASE=Systec Co., Ltd. + +OUI:0008A9* + ID_OUI_FROM_DATABASE=SangSang Technology, Inc. + +OUI:0008AA* + ID_OUI_FROM_DATABASE=KARAM + +OUI:0008AB* + ID_OUI_FROM_DATABASE=EnerLinx.com, Inc. + +OUI:0008AC* + ID_OUI_FROM_DATABASE=Eltromat GmbH + +OUI:0008AD* + ID_OUI_FROM_DATABASE=Toyo-Linx Co., Ltd. + +OUI:0008AE* + ID_OUI_FROM_DATABASE=PacketFront Network Products AB + +OUI:0008AF* + ID_OUI_FROM_DATABASE=Novatec Corporation + +OUI:0008B0* + ID_OUI_FROM_DATABASE=BKtel communications GmbH + +OUI:0008B1* + ID_OUI_FROM_DATABASE=ProQuent Systems + +OUI:0008B2* + ID_OUI_FROM_DATABASE=SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD + +OUI:0008B3* + ID_OUI_FROM_DATABASE=Fastwel + +OUI:0008B4* + ID_OUI_FROM_DATABASE=SYSPOL + +OUI:0008B5* + ID_OUI_FROM_DATABASE=TAI GUEN ENTERPRISE CO., LTD + +OUI:0008B6* + ID_OUI_FROM_DATABASE=RouteFree, Inc. + +OUI:0008B7* + ID_OUI_FROM_DATABASE=HIT Incorporated + +OUI:0008B8* + ID_OUI_FROM_DATABASE=E.F. Johnson + +OUI:0008B9* + ID_OUI_FROM_DATABASE=KAON MEDIA Co., Ltd. + +OUI:0008BA* + ID_OUI_FROM_DATABASE=Erskine Systems Ltd + +OUI:0008BB* + ID_OUI_FROM_DATABASE=NetExcell + +OUI:0008BC* + ID_OUI_FROM_DATABASE=Ilevo AB + +OUI:0008BD* + ID_OUI_FROM_DATABASE=TEPG-US + +OUI:0008BE* + ID_OUI_FROM_DATABASE=XENPAK MSA Group + +OUI:0008BF* + ID_OUI_FROM_DATABASE=Aptus Elektronik AB + +OUI:0008C0* + ID_OUI_FROM_DATABASE=ASA SYSTEMS + +OUI:0008C1* + ID_OUI_FROM_DATABASE=Avistar Communications Corporation + +OUI:0008C2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0008C3* + ID_OUI_FROM_DATABASE=Contex A/S + +OUI:0008C4* + ID_OUI_FROM_DATABASE=Hikari Co.,Ltd. + +OUI:0008C5* + ID_OUI_FROM_DATABASE=Liontech Co., Ltd. + +OUI:0008C6* + ID_OUI_FROM_DATABASE=Philips Consumer Communications + +OUI:0008C7* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0008C8* + ID_OUI_FROM_DATABASE=Soneticom, Inc. + +OUI:0008C9* + ID_OUI_FROM_DATABASE=TechniSat Digital GmbH + +OUI:0008CA* + ID_OUI_FROM_DATABASE=TwinHan Technology Co.,Ltd + +OUI:0008CB* + ID_OUI_FROM_DATABASE=Zeta Broadband Inc. + +OUI:0008CC* + ID_OUI_FROM_DATABASE=Remotec, Inc. + +OUI:0008CD* + ID_OUI_FROM_DATABASE=With-Net Inc + +OUI:0008CE* + ID_OUI_FROM_DATABASE=IPMobileNet Inc. + +OUI:0008CF* + ID_OUI_FROM_DATABASE=Nippon Koei Power Systems Co., Ltd. + +OUI:0008D0* + ID_OUI_FROM_DATABASE=Musashi Engineering Co., LTD. + +OUI:0008D1* + ID_OUI_FROM_DATABASE=KAREL INC. + +OUI:0008D2* + ID_OUI_FROM_DATABASE=ZOOM Networks Inc. + +OUI:0008D3* + ID_OUI_FROM_DATABASE=Hercules Technologies S.A.S. + +OUI:0008D4* + ID_OUI_FROM_DATABASE=IneoQuest Technologies, Inc + +OUI:0008D5* + ID_OUI_FROM_DATABASE=Vanguard Networks Solutions, LLC + +OUI:0008D6* + ID_OUI_FROM_DATABASE=HASSNET Inc. + +OUI:0008D7* + ID_OUI_FROM_DATABASE=HOW CORPORATION + +OUI:0008D8* + ID_OUI_FROM_DATABASE=Dowkey Microwave + +OUI:0008D9* + ID_OUI_FROM_DATABASE=Mitadenshi Co.,LTD + +OUI:0008DA* + ID_OUI_FROM_DATABASE=SofaWare Technologies Ltd. + +OUI:0008DB* + ID_OUI_FROM_DATABASE=Corrigent Systems + +OUI:0008DC* + ID_OUI_FROM_DATABASE=Wiznet + +OUI:0008DD* + ID_OUI_FROM_DATABASE=Telena Communications, Inc. + +OUI:0008DE* + ID_OUI_FROM_DATABASE=3UP Systems + +OUI:0008DF* + ID_OUI_FROM_DATABASE=Alistel Inc. + +OUI:0008E0* + ID_OUI_FROM_DATABASE=ATO Technology Ltd. + +OUI:0008E1* + ID_OUI_FROM_DATABASE=Barix AG + +OUI:0008E2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0008E3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0008E4* + ID_OUI_FROM_DATABASE=Envenergy Inc + +OUI:0008E5* + ID_OUI_FROM_DATABASE=IDK Corporation + +OUI:0008E6* + ID_OUI_FROM_DATABASE=Littlefeet + +OUI:0008E7* + ID_OUI_FROM_DATABASE=SHI ControlSystems,Ltd. + +OUI:0008E8* + ID_OUI_FROM_DATABASE=Excel Master Ltd. + +OUI:0008E9* + ID_OUI_FROM_DATABASE=NextGig + +OUI:0008EA* + ID_OUI_FROM_DATABASE=Motion Control Engineering, Inc + +OUI:0008EB* + ID_OUI_FROM_DATABASE=ROMWin Co.,Ltd. + +OUI:0008EC* + ID_OUI_FROM_DATABASE=Optical Zonu Corporation + +OUI:0008ED* + ID_OUI_FROM_DATABASE=ST&T Instrument Corp. + +OUI:0008EE* + ID_OUI_FROM_DATABASE=Logic Product Development + +OUI:0008EF* + ID_OUI_FROM_DATABASE=DIBAL,S.A. + +OUI:0008F0* + ID_OUI_FROM_DATABASE=Next Generation Systems, Inc. + +OUI:0008F1* + ID_OUI_FROM_DATABASE=Voltaire + +OUI:0008F2* + ID_OUI_FROM_DATABASE=C&S Technology + +OUI:0008F3* + ID_OUI_FROM_DATABASE=WANY + +OUI:0008F4* + ID_OUI_FROM_DATABASE=Bluetake Technology Co., Ltd. + +OUI:0008F5* + ID_OUI_FROM_DATABASE=YESTECHNOLOGY Co.,Ltd. + +OUI:0008F6* + ID_OUI_FROM_DATABASE=Sumitomo Electric System Solutions Co., Ltd. + +OUI:0008F7* + ID_OUI_FROM_DATABASE=Hitachi Ltd, Semiconductor & Integrated Circuits Gr + +OUI:0008F8* + ID_OUI_FROM_DATABASE=UTC CCS + +OUI:0008F9* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:0008FA* + ID_OUI_FROM_DATABASE=Karl E.Brinkmann GmbH + +OUI:0008FB* + ID_OUI_FROM_DATABASE=SonoSite, Inc. + +OUI:0008FC* + ID_OUI_FROM_DATABASE=Gigaphoton Inc. + +OUI:0008FD* + ID_OUI_FROM_DATABASE=BlueKorea Co., Ltd. + +OUI:0008FE* + ID_OUI_FROM_DATABASE=UNIK C&C Co.,Ltd. + +OUI:0008FF* + ID_OUI_FROM_DATABASE=Trilogy Communications Ltd + +OUI:000900* + ID_OUI_FROM_DATABASE=TMT + +OUI:000901* + ID_OUI_FROM_DATABASE=Shenzhen Shixuntong Information & Technoligy Co + +OUI:000902* + ID_OUI_FROM_DATABASE=Redline Communications Inc. + +OUI:000903* + ID_OUI_FROM_DATABASE=Panasas, Inc + +OUI:000904* + ID_OUI_FROM_DATABASE=MONDIAL electronic + +OUI:000905* + ID_OUI_FROM_DATABASE=iTEC Technologies Ltd. + +OUI:000906* + ID_OUI_FROM_DATABASE=Esteem Networks + +OUI:000907* + ID_OUI_FROM_DATABASE=Chrysalis Development + +OUI:000908* + ID_OUI_FROM_DATABASE=VTech Technology Corp. + +OUI:000909* + ID_OUI_FROM_DATABASE=Telenor Connect A/S + +OUI:00090A* + ID_OUI_FROM_DATABASE=SnedFar Technology Co., Ltd. + +OUI:00090B* + ID_OUI_FROM_DATABASE=MTL Instruments PLC + +OUI:00090C* + ID_OUI_FROM_DATABASE=Mayekawa Mfg. Co. Ltd. + +OUI:00090D* + ID_OUI_FROM_DATABASE=LEADER ELECTRONICS CORP. + +OUI:00090E* + ID_OUI_FROM_DATABASE=Helix Technology Inc. + +OUI:00090F* + ID_OUI_FROM_DATABASE=Fortinet Inc. + +OUI:000910* + ID_OUI_FROM_DATABASE=Simple Access Inc. + +OUI:000911* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000912* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000913* + ID_OUI_FROM_DATABASE=SystemK Corporation + +OUI:000914* + ID_OUI_FROM_DATABASE=COMPUTROLS INC. + +OUI:000915* + ID_OUI_FROM_DATABASE=CAS Corp. + +OUI:000916* + ID_OUI_FROM_DATABASE=Listman Home Technologies, Inc. + +OUI:000917* + ID_OUI_FROM_DATABASE=WEM Technology Inc + +OUI:000918* + ID_OUI_FROM_DATABASE=SAMSUNG TECHWIN CO.,LTD + +OUI:000919* + ID_OUI_FROM_DATABASE=MDS Gateways + +OUI:00091A* + ID_OUI_FROM_DATABASE=Macat Optics & Electronics Co., Ltd. + +OUI:00091B* + ID_OUI_FROM_DATABASE=Digital Generation Inc. + +OUI:00091C* + ID_OUI_FROM_DATABASE=CacheVision, Inc + +OUI:00091D* + ID_OUI_FROM_DATABASE=Proteam Computer Corporation + +OUI:00091E* + ID_OUI_FROM_DATABASE=Firstech Technology Corp. + +OUI:00091F* + ID_OUI_FROM_DATABASE=A&D Co., Ltd. + +OUI:000920* + ID_OUI_FROM_DATABASE=EpoX COMPUTER CO.,LTD. + +OUI:000921* + ID_OUI_FROM_DATABASE=Planmeca Oy + +OUI:000922* + ID_OUI_FROM_DATABASE=TST Biometrics GmbH + +OUI:000923* + ID_OUI_FROM_DATABASE=Heaman System Co., Ltd + +OUI:000924* + ID_OUI_FROM_DATABASE=Telebau GmbH + +OUI:000925* + ID_OUI_FROM_DATABASE=VSN Systemen BV + +OUI:000926* + ID_OUI_FROM_DATABASE=YODA COMMUNICATIONS, INC. + +OUI:000927* + ID_OUI_FROM_DATABASE=TOYOKEIKI CO.,LTD. + +OUI:000928* + ID_OUI_FROM_DATABASE=Telecore + +OUI:000929* + ID_OUI_FROM_DATABASE=Sanyo Industries (UK) Limited + +OUI:00092A* + ID_OUI_FROM_DATABASE=MYTECS Co.,Ltd. + +OUI:00092B* + ID_OUI_FROM_DATABASE=iQstor Networks, Inc. + +OUI:00092C* + ID_OUI_FROM_DATABASE=Hitpoint Inc. + +OUI:00092D* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:00092E* + ID_OUI_FROM_DATABASE=B&Tech System Inc. + +OUI:00092F* + ID_OUI_FROM_DATABASE=Akom Technology Corporation + +OUI:000930* + ID_OUI_FROM_DATABASE=AeroConcierge Inc. + +OUI:000931* + ID_OUI_FROM_DATABASE=Future Internet, Inc. + +OUI:000932* + ID_OUI_FROM_DATABASE=Omnilux + +OUI:000933* + ID_OUI_FROM_DATABASE=Ophit Co.Ltd. + +OUI:000934* + ID_OUI_FROM_DATABASE=Dream-Multimedia-Tv GmbH + +OUI:000935* + ID_OUI_FROM_DATABASE=Sandvine Incorporated + +OUI:000936* + ID_OUI_FROM_DATABASE=Ipetronik GmbH & Co. KG + +OUI:000937* + ID_OUI_FROM_DATABASE=Inventec Appliance Corp + +OUI:000938* + ID_OUI_FROM_DATABASE=Allot Communications + +OUI:000939* + ID_OUI_FROM_DATABASE=ShibaSoku Co.,Ltd. + +OUI:00093A* + ID_OUI_FROM_DATABASE=Molex Fiber Optics + +OUI:00093B* + ID_OUI_FROM_DATABASE=HYUNDAI NETWORKS INC. + +OUI:00093C* + ID_OUI_FROM_DATABASE=Jacques Technologies P/L + +OUI:00093D* + ID_OUI_FROM_DATABASE=Newisys,Inc. + +OUI:00093E* + ID_OUI_FROM_DATABASE=C&I Technologies + +OUI:00093F* + ID_OUI_FROM_DATABASE=Double-Win Enterpirse CO., LTD + +OUI:000940* + ID_OUI_FROM_DATABASE=AGFEO GmbH & Co. KG + +OUI:000941* + ID_OUI_FROM_DATABASE=Allied Telesis K.K. + +OUI:000942* + ID_OUI_FROM_DATABASE=Wireless Technologies, Inc + +OUI:000943* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000944* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000945* + ID_OUI_FROM_DATABASE=Palmmicro Communications Inc + +OUI:000946* + ID_OUI_FROM_DATABASE=Cluster Labs GmbH + +OUI:000947* + ID_OUI_FROM_DATABASE=Aztek, Inc. + +OUI:000948* + ID_OUI_FROM_DATABASE=Vista Control Systems, Corp. + +OUI:000949* + ID_OUI_FROM_DATABASE=Glyph Technologies Inc. + +OUI:00094A* + ID_OUI_FROM_DATABASE=Homenet Communications + +OUI:00094B* + ID_OUI_FROM_DATABASE=FillFactory NV + +OUI:00094C* + ID_OUI_FROM_DATABASE=Communication Weaver Co.,Ltd. + +OUI:00094D* + ID_OUI_FROM_DATABASE=Braintree Communications Pty Ltd + +OUI:00094E* + ID_OUI_FROM_DATABASE=BARTECH SYSTEMS INTERNATIONAL, INC + +OUI:00094F* + ID_OUI_FROM_DATABASE=elmegt GmbH & Co. KG + +OUI:000950* + ID_OUI_FROM_DATABASE=Independent Storage Corporation + +OUI:000951* + ID_OUI_FROM_DATABASE=Apogee Imaging Systems + +OUI:000952* + ID_OUI_FROM_DATABASE=Auerswald GmbH & Co. KG + +OUI:000953* + ID_OUI_FROM_DATABASE=Linkage System Integration Co.Ltd. + +OUI:000954* + ID_OUI_FROM_DATABASE=AMiT spol. s. r. o. + +OUI:000955* + ID_OUI_FROM_DATABASE=Young Generation International Corp. + +OUI:000956* + ID_OUI_FROM_DATABASE=Network Systems Group, Ltd. (NSG) + +OUI:000957* + ID_OUI_FROM_DATABASE=Supercaller, Inc. + +OUI:000958* + ID_OUI_FROM_DATABASE=INTELNET S.A. + +OUI:000959* + ID_OUI_FROM_DATABASE=Sitecsoft + +OUI:00095A* + ID_OUI_FROM_DATABASE=RACEWOOD TECHNOLOGY + +OUI:00095B* + ID_OUI_FROM_DATABASE=Netgear, Inc. + +OUI:00095C* + ID_OUI_FROM_DATABASE=Philips Medical Systems - Cardiac and Monitoring Systems (CM + +OUI:00095D* + ID_OUI_FROM_DATABASE=Dialogue Technology Corp. + +OUI:00095E* + ID_OUI_FROM_DATABASE=Masstech Group Inc. + +OUI:00095F* + ID_OUI_FROM_DATABASE=Telebyte, Inc. + +OUI:000960* + ID_OUI_FROM_DATABASE=YOZAN Inc. + +OUI:000961* + ID_OUI_FROM_DATABASE=Switchgear and Instrumentation Ltd + +OUI:000962* + ID_OUI_FROM_DATABASE=Sonitor Technologies AS + +OUI:000963* + ID_OUI_FROM_DATABASE=Dominion Lasercom Inc. + +OUI:000964* + ID_OUI_FROM_DATABASE=Hi-Techniques, Inc. + +OUI:000965* + ID_OUI_FROM_DATABASE=HyunJu Computer Co., Ltd. + +OUI:000966* + ID_OUI_FROM_DATABASE=Thales Navigation + +OUI:000967* + ID_OUI_FROM_DATABASE=Tachyon, Inc + +OUI:000968* + ID_OUI_FROM_DATABASE=TECHNOVENTURE, INC. + +OUI:000969* + ID_OUI_FROM_DATABASE=Meret Optical Communications + +OUI:00096A* + ID_OUI_FROM_DATABASE=Cloverleaf Communications Inc. + +OUI:00096B* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:00096C* + ID_OUI_FROM_DATABASE=Imedia Semiconductor Corp. + +OUI:00096D* + ID_OUI_FROM_DATABASE=Powernet Technologies Corp. + +OUI:00096E* + ID_OUI_FROM_DATABASE=GIANT ELECTRONICS LTD. + +OUI:00096F* + ID_OUI_FROM_DATABASE=Beijing Zhongqing Elegant Tech. Corp.,Limited + +OUI:000970* + ID_OUI_FROM_DATABASE=Vibration Research Corporation + +OUI:000971* + ID_OUI_FROM_DATABASE=Time Management, Inc. + +OUI:000972* + ID_OUI_FROM_DATABASE=Securebase,Inc + +OUI:000973* + ID_OUI_FROM_DATABASE=Lenten Technology Co., Ltd. + +OUI:000974* + ID_OUI_FROM_DATABASE=Innopia Technologies, Inc. + +OUI:000975* + ID_OUI_FROM_DATABASE=fSONA Communications Corporation + +OUI:000976* + ID_OUI_FROM_DATABASE=Datasoft ISDN Systems GmbH + +OUI:000977* + ID_OUI_FROM_DATABASE=Brunner Elektronik AG + +OUI:000978* + ID_OUI_FROM_DATABASE=AIJI System Co., Ltd. + +OUI:000979* + ID_OUI_FROM_DATABASE=Advanced Television Systems Committee, Inc. + +OUI:00097A* + ID_OUI_FROM_DATABASE=Louis Design Labs. + +OUI:00097B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00097C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00097D* + ID_OUI_FROM_DATABASE=SecWell Networks Oy + +OUI:00097E* + ID_OUI_FROM_DATABASE=IMI TECHNOLOGY CO., LTD + +OUI:00097F* + ID_OUI_FROM_DATABASE=Vsecure 2000 LTD. + +OUI:000980* + ID_OUI_FROM_DATABASE=Power Zenith Inc. + +OUI:000981* + ID_OUI_FROM_DATABASE=Newport Networks + +OUI:000982* + ID_OUI_FROM_DATABASE=Loewe Opta GmbH + +OUI:000983* + ID_OUI_FROM_DATABASE=GlobalTop Technology, Inc. + +OUI:000984* + ID_OUI_FROM_DATABASE=MyCasa Network Inc. + +OUI:000985* + ID_OUI_FROM_DATABASE=Auto Telecom Company + +OUI:000986* + ID_OUI_FROM_DATABASE=Metalink LTD. + +OUI:000987* + ID_OUI_FROM_DATABASE=NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD. + +OUI:000988* + ID_OUI_FROM_DATABASE=Nudian Electron Co., Ltd. + +OUI:000989* + ID_OUI_FROM_DATABASE=VividLogic Inc. + +OUI:00098A* + ID_OUI_FROM_DATABASE=EqualLogic Inc + +OUI:00098B* + ID_OUI_FROM_DATABASE=Entropic Communications, Inc. + +OUI:00098C* + ID_OUI_FROM_DATABASE=Option Wireless Sweden + +OUI:00098D* + ID_OUI_FROM_DATABASE=Velocity Semiconductor + +OUI:00098E* + ID_OUI_FROM_DATABASE=ipcas GmbH + +OUI:00098F* + ID_OUI_FROM_DATABASE=Cetacean Networks + +OUI:000990* + ID_OUI_FROM_DATABASE=ACKSYS Communications & systems + +OUI:000991* + ID_OUI_FROM_DATABASE=GE Fanuc Automation Manufacturing, Inc. + +OUI:000992* + ID_OUI_FROM_DATABASE=InterEpoch Technology,INC. + +OUI:000993* + ID_OUI_FROM_DATABASE=Visteon Corporation + +OUI:000994* + ID_OUI_FROM_DATABASE=Cronyx Engineering + +OUI:000995* + ID_OUI_FROM_DATABASE=Castle Technology Ltd + +OUI:000996* + ID_OUI_FROM_DATABASE=RDI + +OUI:000997* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000998* + ID_OUI_FROM_DATABASE=Capinfo Company Limited + +OUI:000999* + ID_OUI_FROM_DATABASE=CP GEORGES RENAULT + +OUI:00099A* + ID_OUI_FROM_DATABASE=ELMO COMPANY, LIMITED + +OUI:00099B* + ID_OUI_FROM_DATABASE=Western Telematic Inc. + +OUI:00099C* + ID_OUI_FROM_DATABASE=Naval Research Laboratory + +OUI:00099D* + ID_OUI_FROM_DATABASE=Haliplex Communications + +OUI:00099E* + ID_OUI_FROM_DATABASE=Testech, Inc. + +OUI:00099F* + ID_OUI_FROM_DATABASE=VIDEX INC. + +OUI:0009A0* + ID_OUI_FROM_DATABASE=Microtechno Corporation + +OUI:0009A1* + ID_OUI_FROM_DATABASE=Telewise Communications, Inc. + +OUI:0009A2* + ID_OUI_FROM_DATABASE=Interface Co., Ltd. + +OUI:0009A3* + ID_OUI_FROM_DATABASE=Leadfly Techologies Corp. Ltd. + +OUI:0009A4* + ID_OUI_FROM_DATABASE=HARTEC Corporation + +OUI:0009A5* + ID_OUI_FROM_DATABASE=HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD + +OUI:0009A6* + ID_OUI_FROM_DATABASE=Ignis Optics, Inc. + +OUI:0009A7* + ID_OUI_FROM_DATABASE=Bang & Olufsen A/S + +OUI:0009A8* + ID_OUI_FROM_DATABASE=Eastmode Pte Ltd + +OUI:0009A9* + ID_OUI_FROM_DATABASE=Ikanos Communications + +OUI:0009AA* + ID_OUI_FROM_DATABASE=Data Comm for Business, Inc. + +OUI:0009AB* + ID_OUI_FROM_DATABASE=Netcontrol Oy + +OUI:0009AC* + ID_OUI_FROM_DATABASE=LANVOICE + +OUI:0009AD* + ID_OUI_FROM_DATABASE=HYUNDAI SYSCOMM, INC. + +OUI:0009AE* + ID_OUI_FROM_DATABASE=OKANO ELECTRIC CO.,LTD + +OUI:0009AF* + ID_OUI_FROM_DATABASE=e-generis + +OUI:0009B0* + ID_OUI_FROM_DATABASE=Onkyo Corporation + +OUI:0009B1* + ID_OUI_FROM_DATABASE=Kanematsu Electronics, Ltd. + +OUI:0009B2* + ID_OUI_FROM_DATABASE=L&F Inc. + +OUI:0009B3* + ID_OUI_FROM_DATABASE=MCM Systems Ltd + +OUI:0009B4* + ID_OUI_FROM_DATABASE=KISAN TELECOM CO., LTD. + +OUI:0009B5* + ID_OUI_FROM_DATABASE=3J Tech. Co., Ltd. + +OUI:0009B6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0009B7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0009B8* + ID_OUI_FROM_DATABASE=Entise Systems + +OUI:0009B9* + ID_OUI_FROM_DATABASE=Action Imaging Solutions + +OUI:0009BA* + ID_OUI_FROM_DATABASE=MAKU Informationstechik GmbH + +OUI:0009BB* + ID_OUI_FROM_DATABASE=MathStar, Inc. + +OUI:0009BC* + ID_OUI_FROM_DATABASE=Digital Safety Technologies, Inc + +OUI:0009BD* + ID_OUI_FROM_DATABASE=Epygi Technologies, Ltd. + +OUI:0009BE* + ID_OUI_FROM_DATABASE=Mamiya-OP Co.,Ltd. + +OUI:0009BF* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0009C0* + ID_OUI_FROM_DATABASE=6WIND + +OUI:0009C1* + ID_OUI_FROM_DATABASE=PROCES-DATA A/S + +OUI:0009C2* + ID_OUI_FROM_DATABASE=Onity, Inc. + +OUI:0009C3* + ID_OUI_FROM_DATABASE=NETAS + +OUI:0009C4* + ID_OUI_FROM_DATABASE=Medicore Co., Ltd + +OUI:0009C5* + ID_OUI_FROM_DATABASE=KINGENE Technology Corporation + +OUI:0009C6* + ID_OUI_FROM_DATABASE=Visionics Corporation + +OUI:0009C7* + ID_OUI_FROM_DATABASE=Movistec + +OUI:0009C8* + ID_OUI_FROM_DATABASE=SINAGAWA TSUSHIN KEISOU SERVICE + +OUI:0009C9* + ID_OUI_FROM_DATABASE=BlueWINC Co., Ltd. + +OUI:0009CA* + ID_OUI_FROM_DATABASE=iMaxNetworks(Shenzhen)Limited. + +OUI:0009CB* + ID_OUI_FROM_DATABASE=HBrain + +OUI:0009CC* + ID_OUI_FROM_DATABASE=Moog GmbH + +OUI:0009CD* + ID_OUI_FROM_DATABASE=HUDSON SOFT CO.,LTD. + +OUI:0009CE* + ID_OUI_FROM_DATABASE=SpaceBridge Semiconductor Corp. + +OUI:0009CF* + ID_OUI_FROM_DATABASE=iAd GmbH + +OUI:0009D0* + ID_OUI_FROM_DATABASE=Solacom Technologies Inc. + +OUI:0009D1* + ID_OUI_FROM_DATABASE=SERANOA NETWORKS INC + +OUI:0009D2* + ID_OUI_FROM_DATABASE=Mai Logic Inc. + +OUI:0009D3* + ID_OUI_FROM_DATABASE=Western DataCom Co., Inc. + +OUI:0009D4* + ID_OUI_FROM_DATABASE=Transtech Networks + +OUI:0009D5* + ID_OUI_FROM_DATABASE=Signal Communication, Inc. + +OUI:0009D6* + ID_OUI_FROM_DATABASE=KNC One GmbH + +OUI:0009D7* + ID_OUI_FROM_DATABASE=DC Security Products + +OUI:0009D8* + ID_OUI_FROM_DATABASE=Fält Communications AB + +OUI:0009D9* + ID_OUI_FROM_DATABASE=Neoscale Systems, Inc + +OUI:0009DA* + ID_OUI_FROM_DATABASE=Control Module Inc. + +OUI:0009DB* + ID_OUI_FROM_DATABASE=eSpace + +OUI:0009DC* + ID_OUI_FROM_DATABASE=Galaxis Technology AG + +OUI:0009DD* + ID_OUI_FROM_DATABASE=Mavin Technology Inc. + +OUI:0009DE* + ID_OUI_FROM_DATABASE=Samjin Information & Communications Co., Ltd. + +OUI:0009DF* + ID_OUI_FROM_DATABASE=Vestel Komunikasyon Sanayi ve Ticaret A.S. + +OUI:0009E0* + ID_OUI_FROM_DATABASE=XEMICS S.A. + +OUI:0009E1* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:0009E2* + ID_OUI_FROM_DATABASE=Sinbon Electronics Co., Ltd. + +OUI:0009E3* + ID_OUI_FROM_DATABASE=Angel Iglesias S.A. + +OUI:0009E4* + ID_OUI_FROM_DATABASE=K Tech Infosystem Inc. + +OUI:0009E5* + ID_OUI_FROM_DATABASE=Hottinger Baldwin Messtechnik GmbH + +OUI:0009E6* + ID_OUI_FROM_DATABASE=Cyber Switching Inc. + +OUI:0009E7* + ID_OUI_FROM_DATABASE=ADC Techonology + +OUI:0009E8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0009E9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0009EA* + ID_OUI_FROM_DATABASE=YEM Inc. + +OUI:0009EB* + ID_OUI_FROM_DATABASE=HuMANDATA LTD. + +OUI:0009EC* + ID_OUI_FROM_DATABASE=Daktronics, Inc. + +OUI:0009ED* + ID_OUI_FROM_DATABASE=CipherOptics + +OUI:0009EE* + ID_OUI_FROM_DATABASE=MEIKYO ELECTRIC CO.,LTD + +OUI:0009EF* + ID_OUI_FROM_DATABASE=Vocera Communications + +OUI:0009F0* + ID_OUI_FROM_DATABASE=Shimizu Technology Inc. + +OUI:0009F1* + ID_OUI_FROM_DATABASE=Yamaki Electric Corporation + +OUI:0009F2* + ID_OUI_FROM_DATABASE=Cohu, Inc., Electronics Division + +OUI:0009F3* + ID_OUI_FROM_DATABASE=WELL Communication Corp. + +OUI:0009F4* + ID_OUI_FROM_DATABASE=Alcon Laboratories, Inc. + +OUI:0009F5* + ID_OUI_FROM_DATABASE=Emerson Network Power Co.,Ltd + +OUI:0009F6* + ID_OUI_FROM_DATABASE=Shenzhen Eastern Digital Tech Ltd. + +OUI:0009F7* + ID_OUI_FROM_DATABASE=SED, a division of Calian + +OUI:0009F8* + ID_OUI_FROM_DATABASE=UNIMO TECHNOLOGY CO., LTD. + +OUI:0009F9* + ID_OUI_FROM_DATABASE=ART JAPAN CO., LTD. + +OUI:0009FB* + ID_OUI_FROM_DATABASE=Philips Patient Monitoring + +OUI:0009FC* + ID_OUI_FROM_DATABASE=IPFLEX Inc. + +OUI:0009FD* + ID_OUI_FROM_DATABASE=Ubinetics Limited + +OUI:0009FE* + ID_OUI_FROM_DATABASE=Daisy Technologies, Inc. + +OUI:0009FF* + ID_OUI_FROM_DATABASE=X.net 2000 GmbH + +OUI:000A00* + ID_OUI_FROM_DATABASE=Mediatek Corp. + +OUI:000A01* + ID_OUI_FROM_DATABASE=SOHOware, Inc. + +OUI:000A02* + ID_OUI_FROM_DATABASE=ANNSO CO., LTD. + +OUI:000A03* + ID_OUI_FROM_DATABASE=ENDESA SERVICIOS, S.L. + +OUI:000A04* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:000A05* + ID_OUI_FROM_DATABASE=Widax Corp. + +OUI:000A06* + ID_OUI_FROM_DATABASE=Teledex LLC + +OUI:000A07* + ID_OUI_FROM_DATABASE=WebWayOne Ltd + +OUI:000A08* + ID_OUI_FROM_DATABASE=ALPINE ELECTRONICS, INC. + +OUI:000A09* + ID_OUI_FROM_DATABASE=TaraCom Integrated Products, Inc. + +OUI:000A0A* + ID_OUI_FROM_DATABASE=SUNIX Co., Ltd. + +OUI:000A0B* + ID_OUI_FROM_DATABASE=Sealevel Systems, Inc. + +OUI:000A0C* + ID_OUI_FROM_DATABASE=Scientific Research Corporation + +OUI:000A0D* + ID_OUI_FROM_DATABASE=FCI Deutschland GmbH + +OUI:000A0E* + ID_OUI_FROM_DATABASE=Invivo Research Inc. + +OUI:000A0F* + ID_OUI_FROM_DATABASE=Ilryung Telesys, Inc + +OUI:000A10* + ID_OUI_FROM_DATABASE=FAST media integrations AG + +OUI:000A11* + ID_OUI_FROM_DATABASE=ExPet Technologies, Inc + +OUI:000A12* + ID_OUI_FROM_DATABASE=Azylex Technology, Inc + +OUI:000A13* + ID_OUI_FROM_DATABASE=Honeywell Video Systems + +OUI:000A14* + ID_OUI_FROM_DATABASE=TECO a.s. + +OUI:000A15* + ID_OUI_FROM_DATABASE=Silicon Data, Inc + +OUI:000A16* + ID_OUI_FROM_DATABASE=Lassen Research + +OUI:000A17* + ID_OUI_FROM_DATABASE=NESTAR COMMUNICATIONS, INC + +OUI:000A18* + ID_OUI_FROM_DATABASE=Vichel Inc. + +OUI:000A19* + ID_OUI_FROM_DATABASE=Valere Power, Inc. + +OUI:000A1A* + ID_OUI_FROM_DATABASE=Imerge Ltd + +OUI:000A1B* + ID_OUI_FROM_DATABASE=Stream Labs + +OUI:000A1C* + ID_OUI_FROM_DATABASE=Bridge Information Co., Ltd. + +OUI:000A1D* + ID_OUI_FROM_DATABASE=Optical Communications Products Inc. + +OUI:000A1E* + ID_OUI_FROM_DATABASE=Red-M Products Limited + +OUI:000A1F* + ID_OUI_FROM_DATABASE=ART WARE Telecommunication Co., Ltd. + +OUI:000A20* + ID_OUI_FROM_DATABASE=SVA Networks, Inc. + +OUI:000A21* + ID_OUI_FROM_DATABASE=Integra Telecom Co. Ltd + +OUI:000A22* + ID_OUI_FROM_DATABASE=Amperion Inc + +OUI:000A23* + ID_OUI_FROM_DATABASE=Parama Networks Inc + +OUI:000A24* + ID_OUI_FROM_DATABASE=Octave Communications + +OUI:000A25* + ID_OUI_FROM_DATABASE=CERAGON NETWORKS + +OUI:000A26* + ID_OUI_FROM_DATABASE=CEIA S.p.A. + +OUI:000A27* + ID_OUI_FROM_DATABASE=Apple + +OUI:000A28* + ID_OUI_FROM_DATABASE=Motorola + +OUI:000A29* + ID_OUI_FROM_DATABASE=Pan Dacom Networking AG + +OUI:000A2A* + ID_OUI_FROM_DATABASE=QSI Systems Inc. + +OUI:000A2B* + ID_OUI_FROM_DATABASE=Etherstuff + +OUI:000A2C* + ID_OUI_FROM_DATABASE=Active Tchnology Corporation + +OUI:000A2D* + ID_OUI_FROM_DATABASE=Cabot Communications Limited + +OUI:000A2E* + ID_OUI_FROM_DATABASE=MAPLE NETWORKS CO., LTD + +OUI:000A2F* + ID_OUI_FROM_DATABASE=Artnix Inc. + +OUI:000A30* + ID_OUI_FROM_DATABASE=Johnson Controls-ASG + +OUI:000A31* + ID_OUI_FROM_DATABASE=HCV Consulting + +OUI:000A32* + ID_OUI_FROM_DATABASE=Xsido Corporation + +OUI:000A33* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:000A34* + ID_OUI_FROM_DATABASE=Identicard Systems Incorporated + +OUI:000A35* + ID_OUI_FROM_DATABASE=Xilinx + +OUI:000A36* + ID_OUI_FROM_DATABASE=Synelec Telecom Multimedia + +OUI:000A37* + ID_OUI_FROM_DATABASE=Procera Networks, Inc. + +OUI:000A38* + ID_OUI_FROM_DATABASE=Apani Networks + +OUI:000A39* + ID_OUI_FROM_DATABASE=LoPA Information Technology + +OUI:000A3A* + ID_OUI_FROM_DATABASE=J-THREE INTERNATIONAL Holding Co., Ltd. + +OUI:000A3B* + ID_OUI_FROM_DATABASE=GCT Semiconductor, Inc + +OUI:000A3C* + ID_OUI_FROM_DATABASE=Enerpoint Ltd. + +OUI:000A3D* + ID_OUI_FROM_DATABASE=Elo Sistemas Eletronicos S.A. + +OUI:000A3E* + ID_OUI_FROM_DATABASE=EADS Telecom + +OUI:000A3F* + ID_OUI_FROM_DATABASE=Data East Corporation + +OUI:000A40* + ID_OUI_FROM_DATABASE=Crown Audio -- Harmanm International + +OUI:000A41* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000A42* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000A43* + ID_OUI_FROM_DATABASE=Chunghwa Telecom Co., Ltd. + +OUI:000A44* + ID_OUI_FROM_DATABASE=Avery Dennison Deutschland GmbH + +OUI:000A45* + ID_OUI_FROM_DATABASE=Audio-Technica Corp. + +OUI:000A46* + ID_OUI_FROM_DATABASE=ARO WELDING TECHNOLOGIES SAS + +OUI:000A47* + ID_OUI_FROM_DATABASE=Allied Vision Technologies + +OUI:000A48* + ID_OUI_FROM_DATABASE=Albatron Technology + +OUI:000A49* + ID_OUI_FROM_DATABASE=F5 Networks, Inc. + +OUI:000A4A* + ID_OUI_FROM_DATABASE=Targa Systems Ltd. + +OUI:000A4B* + ID_OUI_FROM_DATABASE=DataPower Technology, Inc. + +OUI:000A4C* + ID_OUI_FROM_DATABASE=Molecular Devices Corporation + +OUI:000A4D* + ID_OUI_FROM_DATABASE=Noritz Corporation + +OUI:000A4E* + ID_OUI_FROM_DATABASE=UNITEK Electronics INC. + +OUI:000A4F* + ID_OUI_FROM_DATABASE=Brain Boxes Limited + +OUI:000A50* + ID_OUI_FROM_DATABASE=REMOTEK CORPORATION + +OUI:000A51* + ID_OUI_FROM_DATABASE=GyroSignal Technology Co., Ltd. + +OUI:000A52* + ID_OUI_FROM_DATABASE=AsiaRF Ltd. + +OUI:000A53* + ID_OUI_FROM_DATABASE=Intronics, Incorporated + +OUI:000A54* + ID_OUI_FROM_DATABASE=Laguna Hills, Inc. + +OUI:000A55* + ID_OUI_FROM_DATABASE=MARKEM Corporation + +OUI:000A56* + ID_OUI_FROM_DATABASE=HITACHI Maxell Ltd. + +OUI:000A57* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company - Standards + +OUI:000A58* + ID_OUI_FROM_DATABASE=Freyer & Siegel Elektronik GmbH & Co. KG + +OUI:000A59* + ID_OUI_FROM_DATABASE=HW server + +OUI:000A5A* + ID_OUI_FROM_DATABASE=GreenNET Technologies Co.,Ltd. + +OUI:000A5B* + ID_OUI_FROM_DATABASE=Power-One as + +OUI:000A5C* + ID_OUI_FROM_DATABASE=Carel s.p.a. + +OUI:000A5D* + ID_OUI_FROM_DATABASE=FingerTec Worldwide Sdn Bhd + +OUI:000A5E* + ID_OUI_FROM_DATABASE=3COM Corporation + +OUI:000A5F* + ID_OUI_FROM_DATABASE=almedio inc. + +OUI:000A60* + ID_OUI_FROM_DATABASE=Autostar Technology Pte Ltd + +OUI:000A61* + ID_OUI_FROM_DATABASE=Cellinx Systems Inc. + +OUI:000A62* + ID_OUI_FROM_DATABASE=Crinis Networks, Inc. + +OUI:000A63* + ID_OUI_FROM_DATABASE=DHD GmbH + +OUI:000A64* + ID_OUI_FROM_DATABASE=Eracom Technologies + +OUI:000A65* + ID_OUI_FROM_DATABASE=GentechMedia.co.,ltd. + +OUI:000A66* + ID_OUI_FROM_DATABASE=MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD. + +OUI:000A67* + ID_OUI_FROM_DATABASE=OngCorp + +OUI:000A68* + ID_OUI_FROM_DATABASE=SolarFlare Communications, Inc. + +OUI:000A69* + ID_OUI_FROM_DATABASE=SUNNY bell Technology Co., Ltd. + +OUI:000A6A* + ID_OUI_FROM_DATABASE=SVM Microwaves s.r.o. + +OUI:000A6B* + ID_OUI_FROM_DATABASE=Tadiran Telecom Business Systems LTD + +OUI:000A6C* + ID_OUI_FROM_DATABASE=Walchem Corporation + +OUI:000A6D* + ID_OUI_FROM_DATABASE=EKS Elektronikservice GmbH + +OUI:000A6E* + ID_OUI_FROM_DATABASE=Harmonic, Inc + +OUI:000A6F* + ID_OUI_FROM_DATABASE=ZyFLEX Technologies Inc + +OUI:000A70* + ID_OUI_FROM_DATABASE=MPLS Forum + +OUI:000A71* + ID_OUI_FROM_DATABASE=Avrio Technologies, Inc + +OUI:000A72* + ID_OUI_FROM_DATABASE=STEC, INC. + +OUI:000A73* + ID_OUI_FROM_DATABASE=Scientific Atlanta + +OUI:000A74* + ID_OUI_FROM_DATABASE=Manticom Networks Inc. + +OUI:000A75* + ID_OUI_FROM_DATABASE=Caterpillar, Inc + +OUI:000A76* + ID_OUI_FROM_DATABASE=Beida Jade Bird Huaguang Technology Co.,Ltd + +OUI:000A77* + ID_OUI_FROM_DATABASE=Bluewire Technologies LLC + +OUI:000A78* + ID_OUI_FROM_DATABASE=OLITEC + +OUI:000A79* + ID_OUI_FROM_DATABASE=Allied Telesis K.K. corega division + +OUI:000A7A* + ID_OUI_FROM_DATABASE=Kyoritsu Electric Co., Ltd. + +OUI:000A7B* + ID_OUI_FROM_DATABASE=Cornelius Consult + +OUI:000A7C* + ID_OUI_FROM_DATABASE=Tecton Ltd + +OUI:000A7D* + ID_OUI_FROM_DATABASE=Valo, Inc. + +OUI:000A7E* + ID_OUI_FROM_DATABASE=The Advantage Group + +OUI:000A7F* + ID_OUI_FROM_DATABASE=Teradon Industries, Inc + +OUI:000A80* + ID_OUI_FROM_DATABASE=Telkonet Inc. + +OUI:000A81* + ID_OUI_FROM_DATABASE=TEIMA Audiotex S.L. + +OUI:000A82* + ID_OUI_FROM_DATABASE=TATSUTA SYSTEM ELECTRONICS CO.,LTD. + +OUI:000A83* + ID_OUI_FROM_DATABASE=SALTO SYSTEMS S.L. + +OUI:000A84* + ID_OUI_FROM_DATABASE=Rainsun Enterprise Co., Ltd. + +OUI:000A85* + ID_OUI_FROM_DATABASE=PLAT'C2,Inc + +OUI:000A86* + ID_OUI_FROM_DATABASE=Lenze + +OUI:000A87* + ID_OUI_FROM_DATABASE=Integrated Micromachines Inc. + +OUI:000A88* + ID_OUI_FROM_DATABASE=InCypher S.A. + +OUI:000A89* + ID_OUI_FROM_DATABASE=Creval Systems, Inc. + +OUI:000A8A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000A8B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000A8C* + ID_OUI_FROM_DATABASE=Guardware Systems Ltd. + +OUI:000A8D* + ID_OUI_FROM_DATABASE=EUROTHERM LIMITED + +OUI:000A8E* + ID_OUI_FROM_DATABASE=Invacom Ltd + +OUI:000A8F* + ID_OUI_FROM_DATABASE=Aska International Inc. + +OUI:000A90* + ID_OUI_FROM_DATABASE=Bayside Interactive, Inc. + +OUI:000A91* + ID_OUI_FROM_DATABASE=HemoCue AB + +OUI:000A92* + ID_OUI_FROM_DATABASE=Presonus Corporation + +OUI:000A93* + ID_OUI_FROM_DATABASE=W2 Networks, Inc. + +OUI:000A94* + ID_OUI_FROM_DATABASE=ShangHai cellink CO., LTD + +OUI:000A95* + ID_OUI_FROM_DATABASE=Apple + +OUI:000A96* + ID_OUI_FROM_DATABASE=MEWTEL TECHNOLOGY INC. + +OUI:000A97* + ID_OUI_FROM_DATABASE=SONICblue, Inc. + +OUI:000A98* + ID_OUI_FROM_DATABASE=M+F Gwinner GmbH & Co + +OUI:000A99* + ID_OUI_FROM_DATABASE=Calamp Wireless Networks Inc + +OUI:000A9A* + ID_OUI_FROM_DATABASE=Aiptek International Inc + +OUI:000A9B* + ID_OUI_FROM_DATABASE=TB Group Inc + +OUI:000A9C* + ID_OUI_FROM_DATABASE=Server Technology, Inc. + +OUI:000A9D* + ID_OUI_FROM_DATABASE=King Young Technology Co. Ltd. + +OUI:000A9E* + ID_OUI_FROM_DATABASE=BroadWeb Corportation + +OUI:000A9F* + ID_OUI_FROM_DATABASE=Pannaway Technologies, Inc. + +OUI:000AA0* + ID_OUI_FROM_DATABASE=Cedar Point Communications + +OUI:000AA1* + ID_OUI_FROM_DATABASE=V V S Limited + +OUI:000AA2* + ID_OUI_FROM_DATABASE=SYSTEK INC. + +OUI:000AA3* + ID_OUI_FROM_DATABASE=SHIMAFUJI ELECTRIC CO.,LTD. + +OUI:000AA4* + ID_OUI_FROM_DATABASE=SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD + +OUI:000AA5* + ID_OUI_FROM_DATABASE=MAXLINK INDUSTRIES LIMITED + +OUI:000AA6* + ID_OUI_FROM_DATABASE=Hochiki Corporation + +OUI:000AA7* + ID_OUI_FROM_DATABASE=FEI Electron Optics + +OUI:000AA8* + ID_OUI_FROM_DATABASE=ePipe Pty. Ltd. + +OUI:000AA9* + ID_OUI_FROM_DATABASE=Brooks Automation GmbH + +OUI:000AAA* + ID_OUI_FROM_DATABASE=AltiGen Communications Inc. + +OUI:000AAB* + ID_OUI_FROM_DATABASE=Toyota Technical Development Corporation + +OUI:000AAC* + ID_OUI_FROM_DATABASE=TerraTec Electronic GmbH + +OUI:000AAD* + ID_OUI_FROM_DATABASE=Stargames Corporation + +OUI:000AAE* + ID_OUI_FROM_DATABASE=Rosemount Process Analytical + +OUI:000AAF* + ID_OUI_FROM_DATABASE=Pipal Systems + +OUI:000AB0* + ID_OUI_FROM_DATABASE=LOYTEC electronics GmbH + +OUI:000AB1* + ID_OUI_FROM_DATABASE=GENETEC Corporation + +OUI:000AB2* + ID_OUI_FROM_DATABASE=Fresnel Wireless Systems + +OUI:000AB3* + ID_OUI_FROM_DATABASE=Fa. GIRA + +OUI:000AB4* + ID_OUI_FROM_DATABASE=ETIC Telecommunications + +OUI:000AB5* + ID_OUI_FROM_DATABASE=Digital Electronic Network + +OUI:000AB6* + ID_OUI_FROM_DATABASE=COMPUNETIX, INC + +OUI:000AB7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000AB8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000AB9* + ID_OUI_FROM_DATABASE=Astera Technologies Corp. + +OUI:000ABA* + ID_OUI_FROM_DATABASE=Arcon Technology Limited + +OUI:000ABB* + ID_OUI_FROM_DATABASE=Taiwan Secom Co,. Ltd + +OUI:000ABC* + ID_OUI_FROM_DATABASE=Seabridge Ltd. + +OUI:000ABD* + ID_OUI_FROM_DATABASE=Rupprecht & Patashnick Co. + +OUI:000ABE* + ID_OUI_FROM_DATABASE=OPNET Technologies CO., LTD. + +OUI:000ABF* + ID_OUI_FROM_DATABASE=HIROTA SS + +OUI:000AC0* + ID_OUI_FROM_DATABASE=Fuyoh Video Industry CO., LTD. + +OUI:000AC1* + ID_OUI_FROM_DATABASE=Futuretel + +OUI:000AC2* + ID_OUI_FROM_DATABASE=FiberHome Telecommunication Technologies CO.,LTD + +OUI:000AC3* + ID_OUI_FROM_DATABASE=eM Technics Co., Ltd. + +OUI:000AC4* + ID_OUI_FROM_DATABASE=Daewoo Teletech Co., Ltd + +OUI:000AC5* + ID_OUI_FROM_DATABASE=Color Kinetics + +OUI:000AC6* + ID_OUI_FROM_DATABASE=Overture Networks. + +OUI:000AC7* + ID_OUI_FROM_DATABASE=Unication Group + +OUI:000AC8* + ID_OUI_FROM_DATABASE=ZPSYS CO.,LTD. (Planning&Management) + +OUI:000AC9* + ID_OUI_FROM_DATABASE=Zambeel Inc + +OUI:000ACA* + ID_OUI_FROM_DATABASE=YOKOYAMA SHOKAI CO.,Ltd. + +OUI:000ACB* + ID_OUI_FROM_DATABASE=XPAK MSA Group + +OUI:000ACC* + ID_OUI_FROM_DATABASE=Winnow Networks, Inc. + +OUI:000ACD* + ID_OUI_FROM_DATABASE=Sunrich Technology Limited + +OUI:000ACE* + ID_OUI_FROM_DATABASE=RADIANTECH, INC. + +OUI:000ACF* + ID_OUI_FROM_DATABASE=PROVIDEO Multimedia Co. Ltd. + +OUI:000AD0* + ID_OUI_FROM_DATABASE=Niigata Develoment Center, F.I.T. Co., Ltd. + +OUI:000AD1* + ID_OUI_FROM_DATABASE=MWS + +OUI:000AD2* + ID_OUI_FROM_DATABASE=JEPICO Corporation + +OUI:000AD3* + ID_OUI_FROM_DATABASE=INITECH Co., Ltd + +OUI:000AD4* + ID_OUI_FROM_DATABASE=CoreBell Systems Inc. + +OUI:000AD5* + ID_OUI_FROM_DATABASE=Brainchild Electronic Co., Ltd. + +OUI:000AD6* + ID_OUI_FROM_DATABASE=BeamReach Networks + +OUI:000AD7* + ID_OUI_FROM_DATABASE=Origin ELECTRIC CO.,LTD. + +OUI:000AD8* + ID_OUI_FROM_DATABASE=IPCserv Technology Corp. + +OUI:000AD9* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:000ADA* + ID_OUI_FROM_DATABASE=Vindicator Technologies + +OUI:000ADB* + ID_OUI_FROM_DATABASE=SkyPilot Network, Inc + +OUI:000ADC* + ID_OUI_FROM_DATABASE=RuggedCom Inc. + +OUI:000ADD* + ID_OUI_FROM_DATABASE=Allworx Corp. + +OUI:000ADE* + ID_OUI_FROM_DATABASE=Happy Communication Co., Ltd. + +OUI:000ADF* + ID_OUI_FROM_DATABASE=Gennum Corporation + +OUI:000AE0* + ID_OUI_FROM_DATABASE=Fujitsu Softek + +OUI:000AE1* + ID_OUI_FROM_DATABASE=EG Technology + +OUI:000AE2* + ID_OUI_FROM_DATABASE=Binatone Electronics International, Ltd + +OUI:000AE3* + ID_OUI_FROM_DATABASE=YANG MEI TECHNOLOGY CO., LTD + +OUI:000AE4* + ID_OUI_FROM_DATABASE=Wistron Corp. + +OUI:000AE5* + ID_OUI_FROM_DATABASE=ScottCare Corporation + +OUI:000AE6* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) + +OUI:000AE7* + ID_OUI_FROM_DATABASE=ELIOP S.A. + +OUI:000AE8* + ID_OUI_FROM_DATABASE=Cathay Roxus Information Technology Co. LTD + +OUI:000AE9* + ID_OUI_FROM_DATABASE=AirVast Technology Inc. + +OUI:000AEA* + ID_OUI_FROM_DATABASE=ADAM ELEKTRONIK LTD. ŞTI + +OUI:000AEB* + ID_OUI_FROM_DATABASE=Shenzhen Tp-Link Technology Co; Ltd. + +OUI:000AEC* + ID_OUI_FROM_DATABASE=Koatsu Gas Kogyo Co., Ltd. + +OUI:000AED* + ID_OUI_FROM_DATABASE=HARTING Systems GmbH & Co KG + +OUI:000AEE* + ID_OUI_FROM_DATABASE=GCD Hard- & Software GmbH + +OUI:000AEF* + ID_OUI_FROM_DATABASE=OTRUM ASA + +OUI:000AF0* + ID_OUI_FROM_DATABASE=SHIN-OH ELECTRONICS CO., LTD. R&D + +OUI:000AF1* + ID_OUI_FROM_DATABASE=Clarity Design, Inc. + +OUI:000AF2* + ID_OUI_FROM_DATABASE=NeoAxiom Corp. + +OUI:000AF3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000AF4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000AF5* + ID_OUI_FROM_DATABASE=Airgo Networks, Inc. + +OUI:000AF6* + ID_OUI_FROM_DATABASE=Emerson Climate Technologies Retail Solutions, Inc. + +OUI:000AF7* + ID_OUI_FROM_DATABASE=Broadcom Corp. + +OUI:000AF8* + ID_OUI_FROM_DATABASE=American Telecare Inc. + +OUI:000AF9* + ID_OUI_FROM_DATABASE=HiConnect, Inc. + +OUI:000AFA* + ID_OUI_FROM_DATABASE=Traverse Technologies Australia + +OUI:000AFB* + ID_OUI_FROM_DATABASE=Ambri Limited + +OUI:000AFC* + ID_OUI_FROM_DATABASE=Core Tec Communications, LLC + +OUI:000AFD* + ID_OUI_FROM_DATABASE=Viking Electronic Services + +OUI:000AFE* + ID_OUI_FROM_DATABASE=NovaPal Ltd + +OUI:000AFF* + ID_OUI_FROM_DATABASE=Kilchherr Elektronik AG + +OUI:000B00* + ID_OUI_FROM_DATABASE=FUJIAN START COMPUTER EQUIPMENT CO.,LTD + +OUI:000B01* + ID_OUI_FROM_DATABASE=DAIICHI ELECTRONICS CO., LTD. + +OUI:000B02* + ID_OUI_FROM_DATABASE=Dallmeier electronic + +OUI:000B03* + ID_OUI_FROM_DATABASE=Taekwang Industrial Co., Ltd + +OUI:000B04* + ID_OUI_FROM_DATABASE=Volktek Corporation + +OUI:000B05* + ID_OUI_FROM_DATABASE=Pacific Broadband Networks + +OUI:000B06* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:000B07* + ID_OUI_FROM_DATABASE=Voxpath Networks + +OUI:000B08* + ID_OUI_FROM_DATABASE=Pillar Data Systems + +OUI:000B09* + ID_OUI_FROM_DATABASE=Ifoundry Systems Singapore + +OUI:000B0A* + ID_OUI_FROM_DATABASE=dBm Optics + +OUI:000B0B* + ID_OUI_FROM_DATABASE=Corrent Corporation + +OUI:000B0C* + ID_OUI_FROM_DATABASE=Agile Systems Inc. + +OUI:000B0D* + ID_OUI_FROM_DATABASE=Air2U, Inc. + +OUI:000B0E* + ID_OUI_FROM_DATABASE=Trapeze Networks + +OUI:000B0F* + ID_OUI_FROM_DATABASE=Bosch Rexroth + +OUI:000B10* + ID_OUI_FROM_DATABASE=11wave Technonlogy Co.,Ltd + +OUI:000B11* + ID_OUI_FROM_DATABASE=HIMEJI ABC TRADING CO.,LTD. + +OUI:000B12* + ID_OUI_FROM_DATABASE=NURI Telecom Co., Ltd. + +OUI:000B13* + ID_OUI_FROM_DATABASE=ZETRON INC + +OUI:000B14* + ID_OUI_FROM_DATABASE=ViewSonic Corporation + +OUI:000B15* + ID_OUI_FROM_DATABASE=Platypus Technology + +OUI:000B16* + ID_OUI_FROM_DATABASE=Communication Machinery Corporation + +OUI:000B17* + ID_OUI_FROM_DATABASE=MKS Instruments + +OUI:000B19* + ID_OUI_FROM_DATABASE=Vernier Networks, Inc. + +OUI:000B1A* + ID_OUI_FROM_DATABASE=Industrial Defender, Inc. + +OUI:000B1B* + ID_OUI_FROM_DATABASE=Systronix, Inc. + +OUI:000B1C* + ID_OUI_FROM_DATABASE=SIBCO bv + +OUI:000B1D* + ID_OUI_FROM_DATABASE=LayerZero Power Systems, Inc. + +OUI:000B1E* + ID_OUI_FROM_DATABASE=KAPPA opto-electronics GmbH + +OUI:000B1F* + ID_OUI_FROM_DATABASE=I CON Computer Co. + +OUI:000B20* + ID_OUI_FROM_DATABASE=Hirata corporation + +OUI:000B21* + ID_OUI_FROM_DATABASE=G-Star Communications Inc. + +OUI:000B22* + ID_OUI_FROM_DATABASE=Environmental Systems and Services + +OUI:000B23* + ID_OUI_FROM_DATABASE=Siemens Subscriber Networks + +OUI:000B24* + ID_OUI_FROM_DATABASE=AirLogic + +OUI:000B25* + ID_OUI_FROM_DATABASE=Aeluros + +OUI:000B26* + ID_OUI_FROM_DATABASE=Wetek Corporation + +OUI:000B27* + ID_OUI_FROM_DATABASE=Scion Corporation + +OUI:000B28* + ID_OUI_FROM_DATABASE=Quatech Inc. + +OUI:000B29* + ID_OUI_FROM_DATABASE=LS(LG) Industrial Systems co.,Ltd + +OUI:000B2A* + ID_OUI_FROM_DATABASE=HOWTEL Co., Ltd. + +OUI:000B2B* + ID_OUI_FROM_DATABASE=HOSTNET CORPORATION + +OUI:000B2C* + ID_OUI_FROM_DATABASE=Eiki Industrial Co. Ltd. + +OUI:000B2D* + ID_OUI_FROM_DATABASE=Danfoss Inc. + +OUI:000B2E* + ID_OUI_FROM_DATABASE=Cal-Comp Electronics (Thailand) Public Company Limited Taipe + +OUI:000B2F* + ID_OUI_FROM_DATABASE=bplan GmbH + +OUI:000B30* + ID_OUI_FROM_DATABASE=Beijing Gongye Science & Technology Co.,Ltd + +OUI:000B31* + ID_OUI_FROM_DATABASE=Yantai ZhiYang Scientific and technology industry CO., LTD + +OUI:000B32* + ID_OUI_FROM_DATABASE=VORMETRIC, INC. + +OUI:000B33* + ID_OUI_FROM_DATABASE=Vivato Technologies + +OUI:000B34* + ID_OUI_FROM_DATABASE=ShangHai Broadband Technologies CO.LTD + +OUI:000B35* + ID_OUI_FROM_DATABASE=Quad Bit System co., Ltd. + +OUI:000B36* + ID_OUI_FROM_DATABASE=Productivity Systems, Inc. + +OUI:000B37* + ID_OUI_FROM_DATABASE=MANUFACTURE DES MONTRES ROLEX SA + +OUI:000B38* + ID_OUI_FROM_DATABASE=Knürr GmbH + +OUI:000B39* + ID_OUI_FROM_DATABASE=Keisoku Giken Co.,Ltd. + +OUI:000B3A* + ID_OUI_FROM_DATABASE=QuStream Corporation + +OUI:000B3B* + ID_OUI_FROM_DATABASE=devolo AG + +OUI:000B3C* + ID_OUI_FROM_DATABASE=Cygnal Integrated Products, Inc. + +OUI:000B3D* + ID_OUI_FROM_DATABASE=CONTAL OK Ltd. + +OUI:000B3E* + ID_OUI_FROM_DATABASE=BittWare, Inc + +OUI:000B3F* + ID_OUI_FROM_DATABASE=Anthology Solutions Inc. + +OUI:000B40* + ID_OUI_FROM_DATABASE=Oclaro + +OUI:000B41* + ID_OUI_FROM_DATABASE=Ing. Büro Dr. Beutlhauser + +OUI:000B42* + ID_OUI_FROM_DATABASE=commax Co., Ltd. + +OUI:000B43* + ID_OUI_FROM_DATABASE=Microscan Systems, Inc. + +OUI:000B44* + ID_OUI_FROM_DATABASE=Concord IDea Corp. + +OUI:000B45* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000B46* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000B47* + ID_OUI_FROM_DATABASE=Advanced Energy + +OUI:000B48* + ID_OUI_FROM_DATABASE=sofrel + +OUI:000B49* + ID_OUI_FROM_DATABASE=RF-Link System Inc. + +OUI:000B4A* + ID_OUI_FROM_DATABASE=Visimetrics (UK) Ltd + +OUI:000B4B* + ID_OUI_FROM_DATABASE=VISIOWAVE SA + +OUI:000B4C* + ID_OUI_FROM_DATABASE=Clarion (M) Sdn Bhd + +OUI:000B4D* + ID_OUI_FROM_DATABASE=Emuzed + +OUI:000B4E* + ID_OUI_FROM_DATABASE=VertexRSI, General Dynamics SatCOM Technologies, Inc. + +OUI:000B4F* + ID_OUI_FROM_DATABASE=Verifone, INC. + +OUI:000B50* + ID_OUI_FROM_DATABASE=Oxygnet + +OUI:000B51* + ID_OUI_FROM_DATABASE=Micetek International Inc. + +OUI:000B52* + ID_OUI_FROM_DATABASE=JOYMAX ELECTRONICS CO. LTD. + +OUI:000B53* + ID_OUI_FROM_DATABASE=INITIUM Co., Ltd. + +OUI:000B54* + ID_OUI_FROM_DATABASE=BiTMICRO Networks, Inc. + +OUI:000B55* + ID_OUI_FROM_DATABASE=ADInstruments + +OUI:000B56* + ID_OUI_FROM_DATABASE=Cybernetics + +OUI:000B57* + ID_OUI_FROM_DATABASE=Silicon Laboratories + +OUI:000B58* + ID_OUI_FROM_DATABASE=Astronautics C.A LTD + +OUI:000B59* + ID_OUI_FROM_DATABASE=ScriptPro, LLC + +OUI:000B5A* + ID_OUI_FROM_DATABASE=HyperEdge + +OUI:000B5B* + ID_OUI_FROM_DATABASE=Rincon Research Corporation + +OUI:000B5C* + ID_OUI_FROM_DATABASE=Newtech Co.,Ltd + +OUI:000B5D* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED + +OUI:000B5E* + ID_OUI_FROM_DATABASE=Audio Engineering Society Inc. + +OUI:000B5F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000B60* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000B61* + ID_OUI_FROM_DATABASE=Friedrich Lütze GmbH & Co. KG + +OUI:000B62* + ID_OUI_FROM_DATABASE=ib-mohnen KG + +OUI:000B63* + ID_OUI_FROM_DATABASE=Kaleidescape + +OUI:000B64* + ID_OUI_FROM_DATABASE=Kieback & Peter GmbH & Co KG + +OUI:000B65* + ID_OUI_FROM_DATABASE=Sy.A.C. srl + +OUI:000B66* + ID_OUI_FROM_DATABASE=Teralink Communications + +OUI:000B67* + ID_OUI_FROM_DATABASE=Topview Technology Corporation + +OUI:000B68* + ID_OUI_FROM_DATABASE=Addvalue Communications Pte Ltd + +OUI:000B69* + ID_OUI_FROM_DATABASE=Franke Finland Oy + +OUI:000B6A* + ID_OUI_FROM_DATABASE=Asiarock Incorporation + +OUI:000B6B* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:000B6C* + ID_OUI_FROM_DATABASE=Sychip Inc. + +OUI:000B6D* + ID_OUI_FROM_DATABASE=SOLECTRON JAPAN NAKANIIDA + +OUI:000B6E* + ID_OUI_FROM_DATABASE=Neff Instrument Corp. + +OUI:000B6F* + ID_OUI_FROM_DATABASE=Media Streaming Networks Inc + +OUI:000B70* + ID_OUI_FROM_DATABASE=Load Technology, Inc. + +OUI:000B71* + ID_OUI_FROM_DATABASE=Litchfield Communications Inc. + +OUI:000B72* + ID_OUI_FROM_DATABASE=Lawo AG + +OUI:000B73* + ID_OUI_FROM_DATABASE=Kodeos Communications + +OUI:000B74* + ID_OUI_FROM_DATABASE=Kingwave Technology Co., Ltd. + +OUI:000B75* + ID_OUI_FROM_DATABASE=Iosoft Ltd. + +OUI:000B76* + ID_OUI_FROM_DATABASE=ET&T Technology Co. Ltd. + +OUI:000B77* + ID_OUI_FROM_DATABASE=Cogent Systems, Inc. + +OUI:000B78* + ID_OUI_FROM_DATABASE=TAIFATECH INC. + +OUI:000B79* + ID_OUI_FROM_DATABASE=X-COM, Inc. + +OUI:000B7A* + ID_OUI_FROM_DATABASE=L-3 Linkabit + +OUI:000B7B* + ID_OUI_FROM_DATABASE=Test-Um Inc. + +OUI:000B7C* + ID_OUI_FROM_DATABASE=Telex Communications + +OUI:000B7D* + ID_OUI_FROM_DATABASE=SOLOMON EXTREME INTERNATIONAL LTD. + +OUI:000B7E* + ID_OUI_FROM_DATABASE=SAGINOMIYA Seisakusho Inc. + +OUI:000B7F* + ID_OUI_FROM_DATABASE=Align Engineering LLC + +OUI:000B80* + ID_OUI_FROM_DATABASE=Lycium Networks + +OUI:000B81* + ID_OUI_FROM_DATABASE=Kaparel Corporation + +OUI:000B82* + ID_OUI_FROM_DATABASE=Grandstream Networks, Inc. + +OUI:000B83* + ID_OUI_FROM_DATABASE=DATAWATT B.V. + +OUI:000B84* + ID_OUI_FROM_DATABASE=BODET + +OUI:000B85* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000B86* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:000B87* + ID_OUI_FROM_DATABASE=American Reliance Inc. + +OUI:000B88* + ID_OUI_FROM_DATABASE=Vidisco ltd. + +OUI:000B89* + ID_OUI_FROM_DATABASE=Top Global Technology, Ltd. + +OUI:000B8A* + ID_OUI_FROM_DATABASE=MITEQ Inc. + +OUI:000B8B* + ID_OUI_FROM_DATABASE=KERAJET, S.A. + +OUI:000B8C* + ID_OUI_FROM_DATABASE=Flextronics + +OUI:000B8D* + ID_OUI_FROM_DATABASE=Avvio Networks + +OUI:000B8E* + ID_OUI_FROM_DATABASE=Ascent Corporation + +OUI:000B8F* + ID_OUI_FROM_DATABASE=AKITA ELECTRONICS SYSTEMS CO.,LTD. + +OUI:000B90* + ID_OUI_FROM_DATABASE=ADVA Optical Networking Ltd. + +OUI:000B91* + ID_OUI_FROM_DATABASE=Aglaia Gesellschaft für Bildverarbeitung und Kommunikation mbH + +OUI:000B92* + ID_OUI_FROM_DATABASE=Ascom Danmark A/S + +OUI:000B93* + ID_OUI_FROM_DATABASE=Ritter Elektronik + +OUI:000B94* + ID_OUI_FROM_DATABASE=Digital Monitoring Products, Inc. + +OUI:000B95* + ID_OUI_FROM_DATABASE=eBet Gaming Systems Pty Ltd + +OUI:000B96* + ID_OUI_FROM_DATABASE=Innotrac Diagnostics Oy + +OUI:000B97* + ID_OUI_FROM_DATABASE=Matsushita Electric Industrial Co.,Ltd. + +OUI:000B98* + ID_OUI_FROM_DATABASE=NiceTechVision + +OUI:000B99* + ID_OUI_FROM_DATABASE=SensAble Technologies, Inc. + +OUI:000B9A* + ID_OUI_FROM_DATABASE=Shanghai Ulink Telecom Equipment Co. Ltd. + +OUI:000B9B* + ID_OUI_FROM_DATABASE=Sirius System Co, Ltd. + +OUI:000B9C* + ID_OUI_FROM_DATABASE=TriBeam Technologies, Inc. + +OUI:000B9D* + ID_OUI_FROM_DATABASE=TwinMOS Technologies Inc. + +OUI:000B9E* + ID_OUI_FROM_DATABASE=Yasing Technology Corp. + +OUI:000B9F* + ID_OUI_FROM_DATABASE=Neue ELSA GmbH + +OUI:000BA0* + ID_OUI_FROM_DATABASE=T&L Information Inc. + +OUI:000BA1* + ID_OUI_FROM_DATABASE=SYSCOM Ltd. + +OUI:000BA2* + ID_OUI_FROM_DATABASE=Sumitomo Electric Networks, Inc + +OUI:000BA3* + ID_OUI_FROM_DATABASE=Siemens AG, I&S + +OUI:000BA4* + ID_OUI_FROM_DATABASE=Shiron Satellite Communications Ltd. (1996) + +OUI:000BA5* + ID_OUI_FROM_DATABASE=Quasar Cipta Mandiri, PT + +OUI:000BA6* + ID_OUI_FROM_DATABASE=Miyakawa Electric Works Ltd. + +OUI:000BA7* + ID_OUI_FROM_DATABASE=Maranti Networks + +OUI:000BA8* + ID_OUI_FROM_DATABASE=HANBACK ELECTRONICS CO., LTD. + +OUI:000BA9* + ID_OUI_FROM_DATABASE=CloudShield Technologies, Inc. + +OUI:000BAA* + ID_OUI_FROM_DATABASE=Aiphone co.,Ltd + +OUI:000BAB* + ID_OUI_FROM_DATABASE=Advantech Technology (CHINA) Co., Ltd. + +OUI:000BAC* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:000BAD* + ID_OUI_FROM_DATABASE=PC-PoS Inc. + +OUI:000BAE* + ID_OUI_FROM_DATABASE=Vitals System Inc. + +OUI:000BAF* + ID_OUI_FROM_DATABASE=WOOJU COMMUNICATIONS Co,.Ltd + +OUI:000BB0* + ID_OUI_FROM_DATABASE=Sysnet Telematica srl + +OUI:000BB1* + ID_OUI_FROM_DATABASE=Super Star Technology Co., Ltd. + +OUI:000BB2* + ID_OUI_FROM_DATABASE=SMALLBIG TECHNOLOGY + +OUI:000BB3* + ID_OUI_FROM_DATABASE=RiT technologies Ltd. + +OUI:000BB4* + ID_OUI_FROM_DATABASE=RDC Semiconductor Inc., + +OUI:000BB5* + ID_OUI_FROM_DATABASE=nStor Technologies, Inc. + +OUI:000BB6* + ID_OUI_FROM_DATABASE=Metalligence Technology Corp. + +OUI:000BB7* + ID_OUI_FROM_DATABASE=Micro Systems Co.,Ltd. + +OUI:000BB8* + ID_OUI_FROM_DATABASE=Kihoku Electronic Co. + +OUI:000BB9* + ID_OUI_FROM_DATABASE=Imsys AB + +OUI:000BBA* + ID_OUI_FROM_DATABASE=Harmonic, Inc + +OUI:000BBB* + ID_OUI_FROM_DATABASE=Etin Systems Co., Ltd + +OUI:000BBC* + ID_OUI_FROM_DATABASE=En Garde Systems, Inc. + +OUI:000BBD* + ID_OUI_FROM_DATABASE=Connexionz Limited + +OUI:000BBE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000BBF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000BC0* + ID_OUI_FROM_DATABASE=China IWNComm Co., Ltd. + +OUI:000BC1* + ID_OUI_FROM_DATABASE=Bay Microsystems, Inc. + +OUI:000BC2* + ID_OUI_FROM_DATABASE=Corinex Communication Corp. + +OUI:000BC3* + ID_OUI_FROM_DATABASE=Multiplex, Inc. + +OUI:000BC4* + ID_OUI_FROM_DATABASE=BIOTRONIK GmbH & Co + +OUI:000BC5* + ID_OUI_FROM_DATABASE=SMC Networks, Inc. + +OUI:000BC6* + ID_OUI_FROM_DATABASE=ISAC, Inc. + +OUI:000BC7* + ID_OUI_FROM_DATABASE=ICET S.p.A. + +OUI:000BC8* + ID_OUI_FROM_DATABASE=AirFlow Networks + +OUI:000BC9* + ID_OUI_FROM_DATABASE=Electroline Equipment + +OUI:000BCA* + ID_OUI_FROM_DATABASE=DATAVAN International Corporation + +OUI:000BCB* + ID_OUI_FROM_DATABASE=Fagor Automation , S. Coop + +OUI:000BCC* + ID_OUI_FROM_DATABASE=JUSAN, S.A. + +OUI:000BCD* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000BCE* + ID_OUI_FROM_DATABASE=Free2move AB + +OUI:000BCF* + ID_OUI_FROM_DATABASE=AGFA NDT INC. + +OUI:000BD0* + ID_OUI_FROM_DATABASE=XiMeta Technology Americas Inc. + +OUI:000BD1* + ID_OUI_FROM_DATABASE=Aeronix, Inc. + +OUI:000BD2* + ID_OUI_FROM_DATABASE=Remopro Technology Inc. + +OUI:000BD3* + ID_OUI_FROM_DATABASE=cd3o + +OUI:000BD4* + ID_OUI_FROM_DATABASE=Beijing Wise Technology & Science Development Co.Ltd + +OUI:000BD5* + ID_OUI_FROM_DATABASE=Nvergence, Inc. + +OUI:000BD6* + ID_OUI_FROM_DATABASE=Paxton Access Ltd + +OUI:000BD7* + ID_OUI_FROM_DATABASE=DORMA Time + Access GmbH + +OUI:000BD8* + ID_OUI_FROM_DATABASE=Industrial Scientific Corp. + +OUI:000BD9* + ID_OUI_FROM_DATABASE=General Hydrogen + +OUI:000BDA* + ID_OUI_FROM_DATABASE=EyeCross Co.,Inc. + +OUI:000BDB* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:000BDC* + ID_OUI_FROM_DATABASE=AKCP + +OUI:000BDD* + ID_OUI_FROM_DATABASE=TOHOKU RICOH Co., LTD. + +OUI:000BDE* + ID_OUI_FROM_DATABASE=TELDIX GmbH + +OUI:000BDF* + ID_OUI_FROM_DATABASE=Shenzhen RouterD Networks Limited + +OUI:000BE0* + ID_OUI_FROM_DATABASE=SercoNet Ltd. + +OUI:000BE1* + ID_OUI_FROM_DATABASE=Nokia NET Product Operations + +OUI:000BE2* + ID_OUI_FROM_DATABASE=Lumenera Corporation + +OUI:000BE3* + ID_OUI_FROM_DATABASE=Key Stream Co., Ltd. + +OUI:000BE4* + ID_OUI_FROM_DATABASE=Hosiden Corporation + +OUI:000BE5* + ID_OUI_FROM_DATABASE=HIMS International Corporation + +OUI:000BE6* + ID_OUI_FROM_DATABASE=Datel Electronics + +OUI:000BE7* + ID_OUI_FROM_DATABASE=COMFLUX TECHNOLOGY INC. + +OUI:000BE8* + ID_OUI_FROM_DATABASE=AOIP + +OUI:000BE9* + ID_OUI_FROM_DATABASE=Actel Corporation + +OUI:000BEA* + ID_OUI_FROM_DATABASE=Zultys Technologies + +OUI:000BEB* + ID_OUI_FROM_DATABASE=Systegra AG + +OUI:000BEC* + ID_OUI_FROM_DATABASE=NIPPON ELECTRIC INSTRUMENT, INC. + +OUI:000BED* + ID_OUI_FROM_DATABASE=ELM Inc. + +OUI:000BEE* + ID_OUI_FROM_DATABASE=inc.jet, Incorporated + +OUI:000BEF* + ID_OUI_FROM_DATABASE=Code Corporation + +OUI:000BF0* + ID_OUI_FROM_DATABASE=MoTEX Products Co., Ltd. + +OUI:000BF1* + ID_OUI_FROM_DATABASE=LAP Laser Applikations + +OUI:000BF2* + ID_OUI_FROM_DATABASE=Chih-Kan Technology Co., Ltd. + +OUI:000BF3* + ID_OUI_FROM_DATABASE=BAE SYSTEMS + +OUI:000BF5* + ID_OUI_FROM_DATABASE=Shanghai Sibo Telecom Technology Co.,Ltd + +OUI:000BF6* + ID_OUI_FROM_DATABASE=Nitgen Co., Ltd + +OUI:000BF7* + ID_OUI_FROM_DATABASE=NIDEK CO.,LTD + +OUI:000BF8* + ID_OUI_FROM_DATABASE=Infinera + +OUI:000BF9* + ID_OUI_FROM_DATABASE=Gemstone communications, Inc. + +OUI:000BFA* + ID_OUI_FROM_DATABASE=EXEMYS SRL + +OUI:000BFB* + ID_OUI_FROM_DATABASE=D-NET International Corporation + +OUI:000BFC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000BFD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000BFE* + ID_OUI_FROM_DATABASE=CASTEL Broadband Limited + +OUI:000BFF* + ID_OUI_FROM_DATABASE=Berkeley Camera Engineering + +OUI:000C00* + ID_OUI_FROM_DATABASE=BEB Industrie-Elektronik AG + +OUI:000C01* + ID_OUI_FROM_DATABASE=Abatron AG + +OUI:000C02* + ID_OUI_FROM_DATABASE=ABB Oy + +OUI:000C03* + ID_OUI_FROM_DATABASE=HDMI Licensing, LLC + +OUI:000C04* + ID_OUI_FROM_DATABASE=Tecnova + +OUI:000C05* + ID_OUI_FROM_DATABASE=RPA Reserch Co., Ltd. + +OUI:000C06* + ID_OUI_FROM_DATABASE=Nixvue Systems Pte Ltd + +OUI:000C07* + ID_OUI_FROM_DATABASE=Iftest AG + +OUI:000C08* + ID_OUI_FROM_DATABASE=HUMEX Technologies Corp. + +OUI:000C09* + ID_OUI_FROM_DATABASE=Hitachi IE Systems Co., Ltd + +OUI:000C0A* + ID_OUI_FROM_DATABASE=Guangdong Province Electronic Technology Research Institute + +OUI:000C0B* + ID_OUI_FROM_DATABASE=Broadbus Technologies + +OUI:000C0C* + ID_OUI_FROM_DATABASE=APPRO TECHNOLOGY INC. + +OUI:000C0D* + ID_OUI_FROM_DATABASE=Communications & Power Industries / Satcom Division + +OUI:000C0E* + ID_OUI_FROM_DATABASE=XtremeSpectrum, Inc. + +OUI:000C0F* + ID_OUI_FROM_DATABASE=Techno-One Co., Ltd + +OUI:000C10* + ID_OUI_FROM_DATABASE=PNI Corporation + +OUI:000C11* + ID_OUI_FROM_DATABASE=NIPPON DEMPA CO.,LTD. + +OUI:000C12* + ID_OUI_FROM_DATABASE=Micro-Optronic-Messtechnik GmbH + +OUI:000C13* + ID_OUI_FROM_DATABASE=MediaQ + +OUI:000C14* + ID_OUI_FROM_DATABASE=Diagnostic Instruments, Inc. + +OUI:000C15* + ID_OUI_FROM_DATABASE=CyberPower Systems, Inc. + +OUI:000C16* + ID_OUI_FROM_DATABASE=Concorde Microsystems Inc. + +OUI:000C17* + ID_OUI_FROM_DATABASE=AJA Video Systems Inc + +OUI:000C18* + ID_OUI_FROM_DATABASE=Zenisu Keisoku Inc. + +OUI:000C19* + ID_OUI_FROM_DATABASE=Telio Communications GmbH + +OUI:000C1A* + ID_OUI_FROM_DATABASE=Quest Technical Solutions Inc. + +OUI:000C1B* + ID_OUI_FROM_DATABASE=ORACOM Co, Ltd. + +OUI:000C1C* + ID_OUI_FROM_DATABASE=MicroWeb Co., Ltd. + +OUI:000C1D* + ID_OUI_FROM_DATABASE=Mettler & Fuchs AG + +OUI:000C1E* + ID_OUI_FROM_DATABASE=Global Cache + +OUI:000C1F* + ID_OUI_FROM_DATABASE=Glimmerglass Networks + +OUI:000C20* + ID_OUI_FROM_DATABASE=Fi WIn, Inc. + +OUI:000C21* + ID_OUI_FROM_DATABASE=Faculty of Science and Technology, Keio University + +OUI:000C22* + ID_OUI_FROM_DATABASE=Double D Electronics Ltd + +OUI:000C23* + ID_OUI_FROM_DATABASE=Beijing Lanchuan Tech. Co., Ltd. + +OUI:000C24* + ID_OUI_FROM_DATABASE=ANATOR + +OUI:000C25* + ID_OUI_FROM_DATABASE=Allied Telesis Labs, Inc. + +OUI:000C26* + ID_OUI_FROM_DATABASE=Weintek Labs. Inc. + +OUI:000C27* + ID_OUI_FROM_DATABASE=Sammy Corporation + +OUI:000C28* + ID_OUI_FROM_DATABASE=RIFATRON + +OUI:000C29* + ID_OUI_FROM_DATABASE=VMware, Inc. + +OUI:000C2A* + ID_OUI_FROM_DATABASE=OCTTEL Communication Co., Ltd. + +OUI:000C2B* + ID_OUI_FROM_DATABASE=ELIAS Technology, Inc. + +OUI:000C2C* + ID_OUI_FROM_DATABASE=Enwiser Inc. + +OUI:000C2D* + ID_OUI_FROM_DATABASE=FullWave Technology Co., Ltd. + +OUI:000C2E* + ID_OUI_FROM_DATABASE=Openet information technology(shenzhen) Co., Ltd. + +OUI:000C2F* + ID_OUI_FROM_DATABASE=SeorimTechnology Co.,Ltd. + +OUI:000C30* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000C31* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000C32* + ID_OUI_FROM_DATABASE=Avionic Design Development GmbH + +OUI:000C33* + ID_OUI_FROM_DATABASE=Compucase Enterprise Co. Ltd. + +OUI:000C34* + ID_OUI_FROM_DATABASE=Vixen Co., Ltd. + +OUI:000C35* + ID_OUI_FROM_DATABASE=KaVo Dental GmbH & Co. KG + +OUI:000C36* + ID_OUI_FROM_DATABASE=SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD. + +OUI:000C37* + ID_OUI_FROM_DATABASE=Geomation, Inc. + +OUI:000C38* + ID_OUI_FROM_DATABASE=TelcoBridges Inc. + +OUI:000C39* + ID_OUI_FROM_DATABASE=Sentinel Wireless Inc. + +OUI:000C3A* + ID_OUI_FROM_DATABASE=Oxance + +OUI:000C3B* + ID_OUI_FROM_DATABASE=Orion Electric Co., Ltd. + +OUI:000C3C* + ID_OUI_FROM_DATABASE=MediaChorus, Inc. + +OUI:000C3D* + ID_OUI_FROM_DATABASE=Glsystech Co., Ltd. + +OUI:000C3E* + ID_OUI_FROM_DATABASE=Crest Audio + +OUI:000C3F* + ID_OUI_FROM_DATABASE=Cogent Defence & Security Networks, + +OUI:000C40* + ID_OUI_FROM_DATABASE=Altech Controls + +OUI:000C41* + ID_OUI_FROM_DATABASE=Cisco-Linksys + +OUI:000C42* + ID_OUI_FROM_DATABASE=Routerboard.com + +OUI:000C43* + ID_OUI_FROM_DATABASE=Ralink Technology, Corp. + +OUI:000C44* + ID_OUI_FROM_DATABASE=Automated Interfaces, Inc. + +OUI:000C45* + ID_OUI_FROM_DATABASE=Animation Technologies Inc. + +OUI:000C46* + ID_OUI_FROM_DATABASE=Allied Telesyn Inc. + +OUI:000C47* + ID_OUI_FROM_DATABASE=SK Teletech(R&D Planning Team) + +OUI:000C48* + ID_OUI_FROM_DATABASE=QoStek Corporation + +OUI:000C49* + ID_OUI_FROM_DATABASE=Dangaard Telecom RTC Division A/S + +OUI:000C4A* + ID_OUI_FROM_DATABASE=Cygnus Microsystems (P) Limited + +OUI:000C4B* + ID_OUI_FROM_DATABASE=Cheops Elektronik + +OUI:000C4C* + ID_OUI_FROM_DATABASE=Arcor AG&Co. + +OUI:000C4D* + ID_OUI_FROM_DATABASE=Curtiss-Wright Controls Avionics & Electronics + +OUI:000C4E* + ID_OUI_FROM_DATABASE=Winbest Technology CO,LT + +OUI:000C4F* + ID_OUI_FROM_DATABASE=UDTech Japan Corporation + +OUI:000C50* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:000C51* + ID_OUI_FROM_DATABASE=Scientific Technologies Inc. + +OUI:000C52* + ID_OUI_FROM_DATABASE=Roll Systems Inc. + +OUI:000C54* + ID_OUI_FROM_DATABASE=Pedestal Networks, Inc + +OUI:000C55* + ID_OUI_FROM_DATABASE=Microlink Communications Inc. + +OUI:000C56* + ID_OUI_FROM_DATABASE=Megatel Computer (1986) Corp. + +OUI:000C57* + ID_OUI_FROM_DATABASE=MACKIE Engineering Services Belgium BVBA + +OUI:000C58* + ID_OUI_FROM_DATABASE=M&S Systems + +OUI:000C59* + ID_OUI_FROM_DATABASE=Indyme Electronics, Inc. + +OUI:000C5A* + ID_OUI_FROM_DATABASE=IBSmm Embedded Electronics Consulting + +OUI:000C5B* + ID_OUI_FROM_DATABASE=HANWANG TECHNOLOGY CO.,LTD + +OUI:000C5C* + ID_OUI_FROM_DATABASE=GTN Systems B.V. + +OUI:000C5D* + ID_OUI_FROM_DATABASE=CHIC TECHNOLOGY (CHINA) CORP. + +OUI:000C5E* + ID_OUI_FROM_DATABASE=Calypso Medical + +OUI:000C5F* + ID_OUI_FROM_DATABASE=Avtec, Inc. + +OUI:000C60* + ID_OUI_FROM_DATABASE=ACM Systems + +OUI:000C61* + ID_OUI_FROM_DATABASE=AC Tech corporation DBA Advanced Digital + +OUI:000C62* + ID_OUI_FROM_DATABASE=ABB AB, Cewe-Control + +OUI:000C63* + ID_OUI_FROM_DATABASE=Zenith Electronics Corporation + +OUI:000C64* + ID_OUI_FROM_DATABASE=X2 MSA Group + +OUI:000C65* + ID_OUI_FROM_DATABASE=Sunin Telecom + +OUI:000C66* + ID_OUI_FROM_DATABASE=Pronto Networks Inc + +OUI:000C67* + ID_OUI_FROM_DATABASE=OYO ELECTRIC CO.,LTD + +OUI:000C68* + ID_OUI_FROM_DATABASE=SigmaTel, Inc. + +OUI:000C69* + ID_OUI_FROM_DATABASE=National Radio Astronomy Observatory + +OUI:000C6A* + ID_OUI_FROM_DATABASE=MBARI + +OUI:000C6B* + ID_OUI_FROM_DATABASE=Kurz Industrie-Elektronik GmbH + +OUI:000C6C* + ID_OUI_FROM_DATABASE=Elgato Systems LLC + +OUI:000C6D* + ID_OUI_FROM_DATABASE=Edwards Ltd. + +OUI:000C6E* + ID_OUI_FROM_DATABASE=ASUSTEK COMPUTER INC. + +OUI:000C6F* + ID_OUI_FROM_DATABASE=Amtek system co.,LTD. + +OUI:000C70* + ID_OUI_FROM_DATABASE=ACC GmbH + +OUI:000C71* + ID_OUI_FROM_DATABASE=Wybron, Inc + +OUI:000C72* + ID_OUI_FROM_DATABASE=Tempearl Industrial Co., Ltd. + +OUI:000C73* + ID_OUI_FROM_DATABASE=TELSON ELECTRONICS CO., LTD + +OUI:000C74* + ID_OUI_FROM_DATABASE=RIVERTEC CORPORATION + +OUI:000C75* + ID_OUI_FROM_DATABASE=Oriental integrated electronics. LTD + +OUI:000C76* + ID_OUI_FROM_DATABASE=MICRO-STAR INTERNATIONAL CO., LTD. + +OUI:000C77* + ID_OUI_FROM_DATABASE=Life Racing Ltd + +OUI:000C78* + ID_OUI_FROM_DATABASE=In-Tech Electronics Limited + +OUI:000C79* + ID_OUI_FROM_DATABASE=Extel Communications P/L + +OUI:000C7A* + ID_OUI_FROM_DATABASE=DaTARIUS Technologies GmbH + +OUI:000C7B* + ID_OUI_FROM_DATABASE=ALPHA PROJECT Co.,Ltd. + +OUI:000C7C* + ID_OUI_FROM_DATABASE=Internet Information Image Inc. + +OUI:000C7D* + ID_OUI_FROM_DATABASE=TEIKOKU ELECTRIC MFG. CO., LTD + +OUI:000C7E* + ID_OUI_FROM_DATABASE=Tellium Incorporated + +OUI:000C7F* + ID_OUI_FROM_DATABASE=synertronixx GmbH + +OUI:000C80* + ID_OUI_FROM_DATABASE=Opelcomm Inc. + +OUI:000C81* + ID_OUI_FROM_DATABASE=Schneider Electric (Australia) + +OUI:000C82* + ID_OUI_FROM_DATABASE=NETWORK TECHNOLOGIES INC + +OUI:000C83* + ID_OUI_FROM_DATABASE=Logical Solutions + +OUI:000C84* + ID_OUI_FROM_DATABASE=Eazix, Inc. + +OUI:000C85* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000C86* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000C87* + ID_OUI_FROM_DATABASE=AMD + +OUI:000C88* + ID_OUI_FROM_DATABASE=Apache Micro Peripherals, Inc. + +OUI:000C89* + ID_OUI_FROM_DATABASE=AC Electric Vehicles, Ltd. + +OUI:000C8A* + ID_OUI_FROM_DATABASE=Bose Corporation + +OUI:000C8B* + ID_OUI_FROM_DATABASE=Connect Tech Inc + +OUI:000C8C* + ID_OUI_FROM_DATABASE=KODICOM CO.,LTD. + +OUI:000C8D* + ID_OUI_FROM_DATABASE=MATRIX VISION GmbH + +OUI:000C8E* + ID_OUI_FROM_DATABASE=Mentor Engineering Inc + +OUI:000C8F* + ID_OUI_FROM_DATABASE=Nergal s.r.l. + +OUI:000C90* + ID_OUI_FROM_DATABASE=Octasic Inc. + +OUI:000C91* + ID_OUI_FROM_DATABASE=Riverhead Networks Inc. + +OUI:000C92* + ID_OUI_FROM_DATABASE=WolfVision Gmbh + +OUI:000C93* + ID_OUI_FROM_DATABASE=Xeline Co., Ltd. + +OUI:000C94* + ID_OUI_FROM_DATABASE=United Electronic Industries, Inc. (EUI) + +OUI:000C95* + ID_OUI_FROM_DATABASE=PrimeNet + +OUI:000C96* + ID_OUI_FROM_DATABASE=OQO, Inc. + +OUI:000C97* + ID_OUI_FROM_DATABASE=NV ADB TTV Technologies SA + +OUI:000C98* + ID_OUI_FROM_DATABASE=LETEK Communications Inc. + +OUI:000C99* + ID_OUI_FROM_DATABASE=HITEL LINK Co.,Ltd + +OUI:000C9A* + ID_OUI_FROM_DATABASE=Hitech Electronics Corp. + +OUI:000C9B* + ID_OUI_FROM_DATABASE=EE Solutions, Inc + +OUI:000C9C* + ID_OUI_FROM_DATABASE=Chongho information & communications + +OUI:000C9D* + ID_OUI_FROM_DATABASE=UbeeAirWalk, Inc. + +OUI:000C9E* + ID_OUI_FROM_DATABASE=MemoryLink Corp. + +OUI:000C9F* + ID_OUI_FROM_DATABASE=NKE Corporation + +OUI:000CA0* + ID_OUI_FROM_DATABASE=StorCase Technology, Inc. + +OUI:000CA1* + ID_OUI_FROM_DATABASE=SIGMACOM Co., LTD. + +OUI:000CA2* + ID_OUI_FROM_DATABASE=Harmonic Video Network + +OUI:000CA3* + ID_OUI_FROM_DATABASE=Rancho Technology, Inc. + +OUI:000CA4* + ID_OUI_FROM_DATABASE=Prompttec Product Management GmbH + +OUI:000CA5* + ID_OUI_FROM_DATABASE=Naman NZ LTd + +OUI:000CA6* + ID_OUI_FROM_DATABASE=Mintera Corporation + +OUI:000CA7* + ID_OUI_FROM_DATABASE=Metro (Suzhou) Technologies Co., Ltd. + +OUI:000CA8* + ID_OUI_FROM_DATABASE=Garuda Networks Corporation + +OUI:000CA9* + ID_OUI_FROM_DATABASE=Ebtron Inc. + +OUI:000CAA* + ID_OUI_FROM_DATABASE=Cubic Transportation Systems Inc + +OUI:000CAB* + ID_OUI_FROM_DATABASE=COMMEND International + +OUI:000CAC* + ID_OUI_FROM_DATABASE=Citizen Watch Co., Ltd. + +OUI:000CAD* + ID_OUI_FROM_DATABASE=BTU International + +OUI:000CAE* + ID_OUI_FROM_DATABASE=Ailocom Oy + +OUI:000CAF* + ID_OUI_FROM_DATABASE=TRI TERM CO.,LTD. + +OUI:000CB0* + ID_OUI_FROM_DATABASE=Star Semiconductor Corporation + +OUI:000CB1* + ID_OUI_FROM_DATABASE=Salland Engineering (Europe) BV + +OUI:000CB2* + ID_OUI_FROM_DATABASE=Comstar Co., Ltd. + +OUI:000CB3* + ID_OUI_FROM_DATABASE=ROUND Co.,Ltd. + +OUI:000CB4* + ID_OUI_FROM_DATABASE=AutoCell Laboratories, Inc. + +OUI:000CB5* + ID_OUI_FROM_DATABASE=Premier Technolgies, Inc + +OUI:000CB6* + ID_OUI_FROM_DATABASE=NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD + +OUI:000CB7* + ID_OUI_FROM_DATABASE=Nanjing Huazhuo Electronics Co., Ltd. + +OUI:000CB8* + ID_OUI_FROM_DATABASE=MEDION AG + +OUI:000CB9* + ID_OUI_FROM_DATABASE=LEA + +OUI:000CBA* + ID_OUI_FROM_DATABASE=Jamex, Inc. + +OUI:000CBB* + ID_OUI_FROM_DATABASE=ISKRAEMECO + +OUI:000CBC* + ID_OUI_FROM_DATABASE=Iscutum + +OUI:000CBD* + ID_OUI_FROM_DATABASE=Interface Masters, Inc + +OUI:000CBE* + ID_OUI_FROM_DATABASE=Innominate Security Technologies AG + +OUI:000CBF* + ID_OUI_FROM_DATABASE=Holy Stone Ent. Co., Ltd. + +OUI:000CC0* + ID_OUI_FROM_DATABASE=Genera Oy + +OUI:000CC1* + ID_OUI_FROM_DATABASE=Cooper Industries Inc. + +OUI:000CC2* + ID_OUI_FROM_DATABASE=ControlNet (India) Private Limited + +OUI:000CC3* + ID_OUI_FROM_DATABASE=BeWAN systems + +OUI:000CC4* + ID_OUI_FROM_DATABASE=Tiptel AG + +OUI:000CC5* + ID_OUI_FROM_DATABASE=Nextlink Co., Ltd. + +OUI:000CC6* + ID_OUI_FROM_DATABASE=Ka-Ro electronics GmbH + +OUI:000CC7* + ID_OUI_FROM_DATABASE=Intelligent Computer Solutions Inc. + +OUI:000CC8* + ID_OUI_FROM_DATABASE=Xytronix Research & Design, Inc. + +OUI:000CC9* + ID_OUI_FROM_DATABASE=ILWOO DATA & TECHNOLOGY CO.,LTD + +OUI:000CCA* + ID_OUI_FROM_DATABASE=HGST a Western Digital Company + +OUI:000CCB* + ID_OUI_FROM_DATABASE=Design Combus Ltd + +OUI:000CCC* + ID_OUI_FROM_DATABASE=Aeroscout Ltd. + +OUI:000CCD* + ID_OUI_FROM_DATABASE=IEC - TC57 + +OUI:000CCE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000CCF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000CD0* + ID_OUI_FROM_DATABASE=Symetrix + +OUI:000CD1* + ID_OUI_FROM_DATABASE=SFOM Technology Corp. + +OUI:000CD2* + ID_OUI_FROM_DATABASE=Schaffner EMV AG + +OUI:000CD3* + ID_OUI_FROM_DATABASE=Prettl Elektronik Radeberg GmbH + +OUI:000CD4* + ID_OUI_FROM_DATABASE=Positron Public Safety Systems inc. + +OUI:000CD5* + ID_OUI_FROM_DATABASE=Passave Inc. + +OUI:000CD6* + ID_OUI_FROM_DATABASE=PARTNER TECH + +OUI:000CD7* + ID_OUI_FROM_DATABASE=Nallatech Ltd + +OUI:000CD8* + ID_OUI_FROM_DATABASE=M. K. Juchheim GmbH & Co + +OUI:000CD9* + ID_OUI_FROM_DATABASE=Itcare Co., Ltd + +OUI:000CDA* + ID_OUI_FROM_DATABASE=FreeHand Systems, Inc. + +OUI:000CDB* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:000CDC* + ID_OUI_FROM_DATABASE=BECS Technology, Inc + +OUI:000CDD* + ID_OUI_FROM_DATABASE=AOS Technologies AG + +OUI:000CDE* + ID_OUI_FROM_DATABASE=ABB STOTZ-KONTAKT GmbH + +OUI:000CDF* + ID_OUI_FROM_DATABASE=PULNiX America, Inc + +OUI:000CE0* + ID_OUI_FROM_DATABASE=Trek Diagnostics Inc. + +OUI:000CE1* + ID_OUI_FROM_DATABASE=The Open Group + +OUI:000CE2* + ID_OUI_FROM_DATABASE=Rolls-Royce + +OUI:000CE3* + ID_OUI_FROM_DATABASE=Option International N.V. + +OUI:000CE4* + ID_OUI_FROM_DATABASE=NeuroCom International, Inc. + +OUI:000CE5* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:000CE6* + ID_OUI_FROM_DATABASE=Meru Networks Inc + +OUI:000CE7* + ID_OUI_FROM_DATABASE=MediaTek Inc. + +OUI:000CE8* + ID_OUI_FROM_DATABASE=GuangZhou AnJuBao Co., Ltd + +OUI:000CE9* + ID_OUI_FROM_DATABASE=BLOOMBERG L.P. + +OUI:000CEA* + ID_OUI_FROM_DATABASE=aphona Kommunikationssysteme + +OUI:000CEB* + ID_OUI_FROM_DATABASE=CNMP Networks, Inc. + +OUI:000CEC* + ID_OUI_FROM_DATABASE=Spectracom Corp. + +OUI:000CED* + ID_OUI_FROM_DATABASE=Real Digital Media + +OUI:000CEE* + ID_OUI_FROM_DATABASE=jp-embedded + +OUI:000CEF* + ID_OUI_FROM_DATABASE=Open Networks Engineering Ltd + +OUI:000CF0* + ID_OUI_FROM_DATABASE=M & N GmbH + +OUI:000CF1* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:000CF2* + ID_OUI_FROM_DATABASE=GAMESA Eólica + +OUI:000CF3* + ID_OUI_FROM_DATABASE=CALL IMAGE SA + +OUI:000CF4* + ID_OUI_FROM_DATABASE=AKATSUKI ELECTRIC MFG.CO.,LTD. + +OUI:000CF5* + ID_OUI_FROM_DATABASE=InfoExpress + +OUI:000CF6* + ID_OUI_FROM_DATABASE=Sitecom Europe BV + +OUI:000CF7* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000CF8* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000CF9* + ID_OUI_FROM_DATABASE=Xylem Water Solutions + +OUI:000CFA* + ID_OUI_FROM_DATABASE=Digital Systems Corp + +OUI:000CFB* + ID_OUI_FROM_DATABASE=Korea Network Systems + +OUI:000CFC* + ID_OUI_FROM_DATABASE=S2io Technologies Corp + +OUI:000CFD* + ID_OUI_FROM_DATABASE=Hyundai ImageQuest Co.,Ltd. + +OUI:000CFE* + ID_OUI_FROM_DATABASE=Grand Electronic Co., Ltd + +OUI:000CFF* + ID_OUI_FROM_DATABASE=MRO-TEK LIMITED + +OUI:000D00* + ID_OUI_FROM_DATABASE=Seaway Networks Inc. + +OUI:000D01* + ID_OUI_FROM_DATABASE=P&E Microcomputer Systems, Inc. + +OUI:000D02* + ID_OUI_FROM_DATABASE=NEC AccessTechnica, Ltd. + +OUI:000D03* + ID_OUI_FROM_DATABASE=Matrics, Inc. + +OUI:000D04* + ID_OUI_FROM_DATABASE=Foxboro Eckardt Development GmbH + +OUI:000D05* + ID_OUI_FROM_DATABASE=cybernet manufacturing inc. + +OUI:000D06* + ID_OUI_FROM_DATABASE=Compulogic Limited + +OUI:000D07* + ID_OUI_FROM_DATABASE=Calrec Audio Ltd + +OUI:000D08* + ID_OUI_FROM_DATABASE=AboveCable, Inc. + +OUI:000D09* + ID_OUI_FROM_DATABASE=Yuehua(Zhuhai) Electronic CO. LTD + +OUI:000D0A* + ID_OUI_FROM_DATABASE=Projectiondesign as + +OUI:000D0B* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:000D0C* + ID_OUI_FROM_DATABASE=MDI Security Systems + +OUI:000D0D* + ID_OUI_FROM_DATABASE=ITSupported, LLC + +OUI:000D0E* + ID_OUI_FROM_DATABASE=Inqnet Systems, Inc. + +OUI:000D0F* + ID_OUI_FROM_DATABASE=Finlux Ltd + +OUI:000D10* + ID_OUI_FROM_DATABASE=Embedtronics Oy + +OUI:000D11* + ID_OUI_FROM_DATABASE=DENTSPLY - Gendex + +OUI:000D12* + ID_OUI_FROM_DATABASE=AXELL Corporation + +OUI:000D13* + ID_OUI_FROM_DATABASE=Wilhelm Rutenbeck GmbH&Co.KG + +OUI:000D14* + ID_OUI_FROM_DATABASE=Vtech Innovation LP dba Advanced American Telephones + +OUI:000D15* + ID_OUI_FROM_DATABASE=Voipac s.r.o. + +OUI:000D16* + ID_OUI_FROM_DATABASE=UHS Systems Pty Ltd + +OUI:000D17* + ID_OUI_FROM_DATABASE=Turbo Networks Co.Ltd + +OUI:000D18* + ID_OUI_FROM_DATABASE=Mega-Trend Electronics CO., LTD. + +OUI:000D19* + ID_OUI_FROM_DATABASE=ROBE Show lighting + +OUI:000D1A* + ID_OUI_FROM_DATABASE=Mustek System Inc. + +OUI:000D1B* + ID_OUI_FROM_DATABASE=Kyoto Electronics Manufacturing Co., Ltd. + +OUI:000D1C* + ID_OUI_FROM_DATABASE=Amesys Defense + +OUI:000D1D* + ID_OUI_FROM_DATABASE=HIGH-TEK HARNESS ENT. CO., LTD. + +OUI:000D1E* + ID_OUI_FROM_DATABASE=Control Techniques + +OUI:000D1F* + ID_OUI_FROM_DATABASE=AV Digital + +OUI:000D20* + ID_OUI_FROM_DATABASE=ASAHIKASEI TECHNOSYSTEM CO.,LTD. + +OUI:000D21* + ID_OUI_FROM_DATABASE=WISCORE Inc. + +OUI:000D22* + ID_OUI_FROM_DATABASE=Unitronics LTD + +OUI:000D23* + ID_OUI_FROM_DATABASE=Smart Solution, Inc + +OUI:000D24* + ID_OUI_FROM_DATABASE=SENTEC E&E CO., LTD. + +OUI:000D25* + ID_OUI_FROM_DATABASE=SANDEN CORPORATION + +OUI:000D26* + ID_OUI_FROM_DATABASE=Primagraphics Limited + +OUI:000D27* + ID_OUI_FROM_DATABASE=MICROPLEX Printware AG + +OUI:000D28* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000D29* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000D2A* + ID_OUI_FROM_DATABASE=Scanmatic AS + +OUI:000D2B* + ID_OUI_FROM_DATABASE=Racal Instruments + +OUI:000D2C* + ID_OUI_FROM_DATABASE=Patapsco Designs Ltd + +OUI:000D2D* + ID_OUI_FROM_DATABASE=NCT Deutschland GmbH + +OUI:000D2E* + ID_OUI_FROM_DATABASE=Matsushita Avionics Systems Corporation + +OUI:000D2F* + ID_OUI_FROM_DATABASE=AIN Comm.Tech.Co., LTD + +OUI:000D30* + ID_OUI_FROM_DATABASE=IceFyre Semiconductor + +OUI:000D31* + ID_OUI_FROM_DATABASE=Compellent Technologies, Inc. + +OUI:000D32* + ID_OUI_FROM_DATABASE=DispenseSource, Inc. + +OUI:000D33* + ID_OUI_FROM_DATABASE=Prediwave Corp. + +OUI:000D34* + ID_OUI_FROM_DATABASE=Shell International Exploration and Production, Inc. + +OUI:000D35* + ID_OUI_FROM_DATABASE=PAC International Ltd + +OUI:000D36* + ID_OUI_FROM_DATABASE=Wu Han Routon Electronic Co., Ltd + +OUI:000D37* + ID_OUI_FROM_DATABASE=WIPLUG + +OUI:000D38* + ID_OUI_FROM_DATABASE=NISSIN INC. + +OUI:000D39* + ID_OUI_FROM_DATABASE=Network Electronics + +OUI:000D3A* + ID_OUI_FROM_DATABASE=Microsoft Corp. + +OUI:000D3B* + ID_OUI_FROM_DATABASE=Microelectronics Technology Inc. + +OUI:000D3C* + ID_OUI_FROM_DATABASE=i.Tech Dynamic Ltd + +OUI:000D3D* + ID_OUI_FROM_DATABASE=Hammerhead Systems, Inc. + +OUI:000D3E* + ID_OUI_FROM_DATABASE=APLUX Communications Ltd. + +OUI:000D3F* + ID_OUI_FROM_DATABASE=VTI Instruments Corporation + +OUI:000D40* + ID_OUI_FROM_DATABASE=Verint Loronix Video Solutions + +OUI:000D41* + ID_OUI_FROM_DATABASE=Siemens AG ICM MP UC RD IT KLF1 + +OUI:000D42* + ID_OUI_FROM_DATABASE=Newbest Development Limited + +OUI:000D43* + ID_OUI_FROM_DATABASE=DRS Tactical Systems Inc. + +OUI:000D44* + ID_OUI_FROM_DATABASE=Audio BU - Logitech + +OUI:000D45* + ID_OUI_FROM_DATABASE=Tottori SANYO Electric Co., Ltd. + +OUI:000D46* + ID_OUI_FROM_DATABASE=Parker SSD Drives + +OUI:000D47* + ID_OUI_FROM_DATABASE=Collex + +OUI:000D48* + ID_OUI_FROM_DATABASE=AEWIN Technologies Co., Ltd. + +OUI:000D49* + ID_OUI_FROM_DATABASE=Triton Systems of Delaware, Inc. + +OUI:000D4A* + ID_OUI_FROM_DATABASE=Steag ETA-Optik + +OUI:000D4B* + ID_OUI_FROM_DATABASE=Roku, LLC + +OUI:000D4C* + ID_OUI_FROM_DATABASE=Outline Electronics Ltd. + +OUI:000D4D* + ID_OUI_FROM_DATABASE=Ninelanes + +OUI:000D4E* + ID_OUI_FROM_DATABASE=NDR Co.,LTD. + +OUI:000D4F* + ID_OUI_FROM_DATABASE=Kenwood Corporation + +OUI:000D50* + ID_OUI_FROM_DATABASE=Galazar Networks + +OUI:000D51* + ID_OUI_FROM_DATABASE=DIVR Systems, Inc. + +OUI:000D52* + ID_OUI_FROM_DATABASE=Comart system + +OUI:000D53* + ID_OUI_FROM_DATABASE=Beijing 5w Communication Corp. + +OUI:000D54* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:000D55* + ID_OUI_FROM_DATABASE=SANYCOM Technology Co.,Ltd + +OUI:000D56* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:000D57* + ID_OUI_FROM_DATABASE=Fujitsu I-Network Systems Limited. + +OUI:000D59* + ID_OUI_FROM_DATABASE=Amity Systems, Inc. + +OUI:000D5A* + ID_OUI_FROM_DATABASE=Tiesse SpA + +OUI:000D5B* + ID_OUI_FROM_DATABASE=Smart Empire Investments Limited + +OUI:000D5C* + ID_OUI_FROM_DATABASE=Robert Bosch GmbH, VT-ATMO + +OUI:000D5D* + ID_OUI_FROM_DATABASE=Raritan Computer, Inc + +OUI:000D5E* + ID_OUI_FROM_DATABASE=NEC Personal Products + +OUI:000D5F* + ID_OUI_FROM_DATABASE=Minds Inc + +OUI:000D60* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:000D61* + ID_OUI_FROM_DATABASE=Giga-Byte Technology Co., Ltd. + +OUI:000D62* + ID_OUI_FROM_DATABASE=Funkwerk Dabendorf GmbH + +OUI:000D63* + ID_OUI_FROM_DATABASE=DENT Instruments, Inc. + +OUI:000D64* + ID_OUI_FROM_DATABASE=COMAG Handels AG + +OUI:000D65* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000D66* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000D67* + ID_OUI_FROM_DATABASE=Ericsson + +OUI:000D68* + ID_OUI_FROM_DATABASE=Vinci Systems, Inc. + +OUI:000D69* + ID_OUI_FROM_DATABASE=TMT&D Corporation + +OUI:000D6A* + ID_OUI_FROM_DATABASE=Redwood Technologies LTD + +OUI:000D6B* + ID_OUI_FROM_DATABASE=Mita-Teknik A/S + +OUI:000D6C* + ID_OUI_FROM_DATABASE=M-Audio + +OUI:000D6D* + ID_OUI_FROM_DATABASE=K-Tech Devices Corp. + +OUI:000D6E* + ID_OUI_FROM_DATABASE=K-Patents Oy + +OUI:000D6F* + ID_OUI_FROM_DATABASE=Ember Corporation + +OUI:000D70* + ID_OUI_FROM_DATABASE=Datamax Corporation + +OUI:000D71* + ID_OUI_FROM_DATABASE=boca systems + +OUI:000D72* + ID_OUI_FROM_DATABASE=2Wire, Inc + +OUI:000D73* + ID_OUI_FROM_DATABASE=Technical Support, Inc. + +OUI:000D74* + ID_OUI_FROM_DATABASE=Sand Network Systems, Inc. + +OUI:000D75* + ID_OUI_FROM_DATABASE=Kobian Pte Ltd - Taiwan Branch + +OUI:000D76* + ID_OUI_FROM_DATABASE=Hokuto Denshi Co,. Ltd. + +OUI:000D77* + ID_OUI_FROM_DATABASE=FalconStor Software + +OUI:000D78* + ID_OUI_FROM_DATABASE=Engineering & Security + +OUI:000D79* + ID_OUI_FROM_DATABASE=Dynamic Solutions Co,.Ltd. + +OUI:000D7A* + ID_OUI_FROM_DATABASE=DiGATTO Asia Pacific Pte Ltd + +OUI:000D7B* + ID_OUI_FROM_DATABASE=Consensys Computers Inc. + +OUI:000D7C* + ID_OUI_FROM_DATABASE=Codian Ltd + +OUI:000D7D* + ID_OUI_FROM_DATABASE=Afco Systems + +OUI:000D7E* + ID_OUI_FROM_DATABASE=Axiowave Networks, Inc. + +OUI:000D7F* + ID_OUI_FROM_DATABASE=MIDAS COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch) + +OUI:000D80* + ID_OUI_FROM_DATABASE=Online Development Inc + +OUI:000D81* + ID_OUI_FROM_DATABASE=Pepperl+Fuchs GmbH + +OUI:000D82* + ID_OUI_FROM_DATABASE=PHS srl + +OUI:000D83* + ID_OUI_FROM_DATABASE=Sanmina-SCI Hungary Ltd. + +OUI:000D84* + ID_OUI_FROM_DATABASE=Makus Inc. + +OUI:000D85* + ID_OUI_FROM_DATABASE=Tapwave, Inc. + +OUI:000D86* + ID_OUI_FROM_DATABASE=Huber + Suhner AG + +OUI:000D87* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) + +OUI:000D88* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:000D89* + ID_OUI_FROM_DATABASE=Bils Technology Inc + +OUI:000D8A* + ID_OUI_FROM_DATABASE=Winners Electronics Co., Ltd. + +OUI:000D8B* + ID_OUI_FROM_DATABASE=T&D Corporation + +OUI:000D8C* + ID_OUI_FROM_DATABASE=Shanghai Wedone Digital Ltd. CO. + +OUI:000D8D* + ID_OUI_FROM_DATABASE=Prosoft Technology, Inc + +OUI:000D8E* + ID_OUI_FROM_DATABASE=Koden Electronics Co., Ltd. + +OUI:000D8F* + ID_OUI_FROM_DATABASE=King Tsushin Kogyo Co., LTD. + +OUI:000D90* + ID_OUI_FROM_DATABASE=Factum Electronics AB + +OUI:000D91* + ID_OUI_FROM_DATABASE=Eclipse (HQ Espana) S.L. + +OUI:000D92* + ID_OUI_FROM_DATABASE=Arima Communication Corporation + +OUI:000D93* + ID_OUI_FROM_DATABASE=Apple + +OUI:000D94* + ID_OUI_FROM_DATABASE=AFAR Communications,Inc + +OUI:000D95* + ID_OUI_FROM_DATABASE=Opti-cell, Inc. + +OUI:000D96* + ID_OUI_FROM_DATABASE=Vtera Technology Inc. + +OUI:000D97* + ID_OUI_FROM_DATABASE=Tropos Networks, Inc. + +OUI:000D98* + ID_OUI_FROM_DATABASE=S.W.A.C. Schmitt-Walter Automation Consult GmbH + +OUI:000D99* + ID_OUI_FROM_DATABASE=Orbital Sciences Corp.; Launch Systems Group + +OUI:000D9A* + ID_OUI_FROM_DATABASE=INFOTEC LTD + +OUI:000D9B* + ID_OUI_FROM_DATABASE=Heraeus Electro-Nite International N.V. + +OUI:000D9C* + ID_OUI_FROM_DATABASE=Elan GmbH & Co KG + +OUI:000D9D* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000D9E* + ID_OUI_FROM_DATABASE=TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd. + +OUI:000D9F* + ID_OUI_FROM_DATABASE=RF Micro Devices + +OUI:000DA0* + ID_OUI_FROM_DATABASE=NEDAP N.V. + +OUI:000DA1* + ID_OUI_FROM_DATABASE=MIRAE ITS Co.,LTD. + +OUI:000DA2* + ID_OUI_FROM_DATABASE=Infrant Technologies, Inc. + +OUI:000DA3* + ID_OUI_FROM_DATABASE=Emerging Technologies Limited + +OUI:000DA4* + ID_OUI_FROM_DATABASE=DOSCH & AMAND SYSTEMS AG + +OUI:000DA5* + ID_OUI_FROM_DATABASE=Fabric7 Systems, Inc + +OUI:000DA6* + ID_OUI_FROM_DATABASE=Universal Switching Corporation + +OUI:000DA8* + ID_OUI_FROM_DATABASE=Teletronics Technology Corporation + +OUI:000DA9* + ID_OUI_FROM_DATABASE=T.E.A.M. S.L. + +OUI:000DAA* + ID_OUI_FROM_DATABASE=S.A.Tehnology co.,Ltd. + +OUI:000DAB* + ID_OUI_FROM_DATABASE=Parker Hannifin GmbH Electromechanical Division Europe + +OUI:000DAC* + ID_OUI_FROM_DATABASE=Japan CBM Corporation + +OUI:000DAD* + ID_OUI_FROM_DATABASE=Dataprobe, Inc. + +OUI:000DAE* + ID_OUI_FROM_DATABASE=SAMSUNG HEAVY INDUSTRIES CO., LTD. + +OUI:000DAF* + ID_OUI_FROM_DATABASE=Plexus Corp (UK) Ltd + +OUI:000DB0* + ID_OUI_FROM_DATABASE=Olym-tech Co.,Ltd. + +OUI:000DB1* + ID_OUI_FROM_DATABASE=Japan Network Service Co., Ltd. + +OUI:000DB2* + ID_OUI_FROM_DATABASE=Ammasso, Inc. + +OUI:000DB3* + ID_OUI_FROM_DATABASE=SDO Communication Corperation + +OUI:000DB4* + ID_OUI_FROM_DATABASE=NETASQ + +OUI:000DB5* + ID_OUI_FROM_DATABASE=GLOBALSAT TECHNOLOGY CORPORATION + +OUI:000DB6* + ID_OUI_FROM_DATABASE=Broadcom Corporation + +OUI:000DB7* + ID_OUI_FROM_DATABASE=SANKO ELECTRIC CO,.LTD + +OUI:000DB8* + ID_OUI_FROM_DATABASE=SCHILLER AG + +OUI:000DB9* + ID_OUI_FROM_DATABASE=PC Engines GmbH + +OUI:000DBA* + ID_OUI_FROM_DATABASE=Océ Document Technologies GmbH + +OUI:000DBB* + ID_OUI_FROM_DATABASE=Nippon Dentsu Co.,Ltd. + +OUI:000DBC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000DBD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000DBE* + ID_OUI_FROM_DATABASE=Bel Fuse Europe Ltd.,UK + +OUI:000DBF* + ID_OUI_FROM_DATABASE=TekTone Sound & Signal Mfg., Inc. + +OUI:000DC0* + ID_OUI_FROM_DATABASE=Spagat AS + +OUI:000DC1* + ID_OUI_FROM_DATABASE=SafeWeb Inc + +OUI:000DC3* + ID_OUI_FROM_DATABASE=First Communication, Inc. + +OUI:000DC4* + ID_OUI_FROM_DATABASE=Emcore Corporation + +OUI:000DC5* + ID_OUI_FROM_DATABASE=EchoStar Global B.V. + +OUI:000DC6* + ID_OUI_FROM_DATABASE=DigiRose Technology Co., Ltd. + +OUI:000DC7* + ID_OUI_FROM_DATABASE=COSMIC ENGINEERING INC. + +OUI:000DC8* + ID_OUI_FROM_DATABASE=AirMagnet, Inc + +OUI:000DC9* + ID_OUI_FROM_DATABASE=THALES Elektronik Systeme GmbH + +OUI:000DCA* + ID_OUI_FROM_DATABASE=Tait Electronics + +OUI:000DCB* + ID_OUI_FROM_DATABASE=Petcomkorea Co., Ltd. + +OUI:000DCC* + ID_OUI_FROM_DATABASE=NEOSMART Corp. + +OUI:000DCD* + ID_OUI_FROM_DATABASE=GROUPE TXCOM + +OUI:000DCE* + ID_OUI_FROM_DATABASE=Dynavac Technology Pte Ltd + +OUI:000DCF* + ID_OUI_FROM_DATABASE=Cidra Corp. + +OUI:000DD0* + ID_OUI_FROM_DATABASE=TetraTec Instruments GmbH + +OUI:000DD1* + ID_OUI_FROM_DATABASE=Stryker Corporation + +OUI:000DD2* + ID_OUI_FROM_DATABASE=Simrad Optronics ASA + +OUI:000DD3* + ID_OUI_FROM_DATABASE=SAMWOO Telecommunication Co.,Ltd. + +OUI:000DD4* + ID_OUI_FROM_DATABASE=Symantec Corporation + +OUI:000DD5* + ID_OUI_FROM_DATABASE=O'RITE TECHNOLOGY CO.,LTD + +OUI:000DD6* + ID_OUI_FROM_DATABASE=ITI LTD + +OUI:000DD7* + ID_OUI_FROM_DATABASE=Bright + +OUI:000DD8* + ID_OUI_FROM_DATABASE=BBN + +OUI:000DD9* + ID_OUI_FROM_DATABASE=Anton Paar GmbH + +OUI:000DDA* + ID_OUI_FROM_DATABASE=ALLIED TELESIS K.K. + +OUI:000DDB* + ID_OUI_FROM_DATABASE=AIRWAVE TECHNOLOGIES INC. + +OUI:000DDC* + ID_OUI_FROM_DATABASE=VAC + +OUI:000DDD* + ID_OUI_FROM_DATABASE=Profilo Telra Elektronik Sanayi ve Ticaret. A.Ş + +OUI:000DDE* + ID_OUI_FROM_DATABASE=Joyteck Co., Ltd. + +OUI:000DDF* + ID_OUI_FROM_DATABASE=Japan Image & Network Inc. + +OUI:000DE0* + ID_OUI_FROM_DATABASE=ICPDAS Co.,LTD + +OUI:000DE1* + ID_OUI_FROM_DATABASE=Control Products, Inc. + +OUI:000DE2* + ID_OUI_FROM_DATABASE=CMZ Sistemi Elettronici + +OUI:000DE3* + ID_OUI_FROM_DATABASE=AT Sweden AB + +OUI:000DE4* + ID_OUI_FROM_DATABASE=DIGINICS, Inc. + +OUI:000DE5* + ID_OUI_FROM_DATABASE=Samsung Thales + +OUI:000DE6* + ID_OUI_FROM_DATABASE=YOUNGBO ENGINEERING CO.,LTD + +OUI:000DE7* + ID_OUI_FROM_DATABASE=Snap-on OEM Group + +OUI:000DE8* + ID_OUI_FROM_DATABASE=Nasaco Electronics Pte. Ltd + +OUI:000DE9* + ID_OUI_FROM_DATABASE=Napatech Aps + +OUI:000DEA* + ID_OUI_FROM_DATABASE=Kingtel Telecommunication Corp. + +OUI:000DEB* + ID_OUI_FROM_DATABASE=CompXs Limited + +OUI:000DEC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000DED* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000DEE* + ID_OUI_FROM_DATABASE=Andrew RF Power Amplifier Group + +OUI:000DEF* + ID_OUI_FROM_DATABASE=Soc. Coop. Bilanciai + +OUI:000DF0* + ID_OUI_FROM_DATABASE=QCOM TECHNOLOGY INC. + +OUI:000DF1* + ID_OUI_FROM_DATABASE=IONIX INC. + +OUI:000DF3* + ID_OUI_FROM_DATABASE=Asmax Solutions + +OUI:000DF4* + ID_OUI_FROM_DATABASE=Watertek Co. + +OUI:000DF5* + ID_OUI_FROM_DATABASE=Teletronics International Inc. + +OUI:000DF6* + ID_OUI_FROM_DATABASE=Technology Thesaurus Corp. + +OUI:000DF7* + ID_OUI_FROM_DATABASE=Space Dynamics Lab + +OUI:000DF8* + ID_OUI_FROM_DATABASE=ORGA Kartensysteme GmbH + +OUI:000DF9* + ID_OUI_FROM_DATABASE=NDS Limited + +OUI:000DFA* + ID_OUI_FROM_DATABASE=Micro Control Systems Ltd. + +OUI:000DFB* + ID_OUI_FROM_DATABASE=Komax AG + +OUI:000DFC* + ID_OUI_FROM_DATABASE=ITFOR Inc. + +OUI:000DFD* + ID_OUI_FROM_DATABASE=Huges Hi-Tech Inc., + +OUI:000DFE* + ID_OUI_FROM_DATABASE=Hauppauge Computer Works, Inc. + +OUI:000DFF* + ID_OUI_FROM_DATABASE=CHENMING MOLD INDUSTRY CORP. + +OUI:000E00* + ID_OUI_FROM_DATABASE=Atrie + +OUI:000E01* + ID_OUI_FROM_DATABASE=ASIP Technologies Inc. + +OUI:000E02* + ID_OUI_FROM_DATABASE=Advantech AMT Inc. + +OUI:000E03* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:000E04* + ID_OUI_FROM_DATABASE=CMA/Microdialysis AB + +OUI:000E05* + ID_OUI_FROM_DATABASE=WIRELESS MATRIX CORP. + +OUI:000E06* + ID_OUI_FROM_DATABASE=Team Simoco Ltd + +OUI:000E07* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:000E08* + ID_OUI_FROM_DATABASE=Cisco Linksys LLC + +OUI:000E09* + ID_OUI_FROM_DATABASE=Shenzhen Coship Software Co.,LTD. + +OUI:000E0A* + ID_OUI_FROM_DATABASE=SAKUMA DESIGN OFFICE + +OUI:000E0B* + ID_OUI_FROM_DATABASE=Netac Technology Co., Ltd. + +OUI:000E0C* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:000E0D* + ID_OUI_FROM_DATABASE=Hesch Schröder GmbH + +OUI:000E0E* + ID_OUI_FROM_DATABASE=ESA elettronica S.P.A. + +OUI:000E0F* + ID_OUI_FROM_DATABASE=ERMME + +OUI:000E10* + ID_OUI_FROM_DATABASE=C-guys, Inc. + +OUI:000E11* + ID_OUI_FROM_DATABASE=BDT Büro und Datentechnik GmbH & Co.KG + +OUI:000E12* + ID_OUI_FROM_DATABASE=Adaptive Micro Systems Inc. + +OUI:000E13* + ID_OUI_FROM_DATABASE=Accu-Sort Systems inc. + +OUI:000E14* + ID_OUI_FROM_DATABASE=Visionary Solutions, Inc. + +OUI:000E15* + ID_OUI_FROM_DATABASE=Tadlys LTD + +OUI:000E16* + ID_OUI_FROM_DATABASE=SouthWing S.L. + +OUI:000E18* + ID_OUI_FROM_DATABASE=MyA Technology + +OUI:000E19* + ID_OUI_FROM_DATABASE=LogicaCMG Pty Ltd + +OUI:000E1A* + ID_OUI_FROM_DATABASE=JPS Communications + +OUI:000E1B* + ID_OUI_FROM_DATABASE=IAV GmbH + +OUI:000E1C* + ID_OUI_FROM_DATABASE=Hach Company + +OUI:000E1D* + ID_OUI_FROM_DATABASE=ARION Technology Inc. + +OUI:000E1E* + ID_OUI_FROM_DATABASE=QLogic Corporation + +OUI:000E1F* + ID_OUI_FROM_DATABASE=TCL Networks Equipment Co., Ltd. + +OUI:000E20* + ID_OUI_FROM_DATABASE=ACCESS Systems Americas, Inc. + +OUI:000E21* + ID_OUI_FROM_DATABASE=MTU Friedrichshafen GmbH + +OUI:000E23* + ID_OUI_FROM_DATABASE=Incipient, Inc. + +OUI:000E24* + ID_OUI_FROM_DATABASE=Huwell Technology Inc. + +OUI:000E25* + ID_OUI_FROM_DATABASE=Hannae Technology Co., Ltd + +OUI:000E26* + ID_OUI_FROM_DATABASE=Gincom Technology Corp. + +OUI:000E27* + ID_OUI_FROM_DATABASE=Crere Networks, Inc. + +OUI:000E28* + ID_OUI_FROM_DATABASE=Dynamic Ratings P/L + +OUI:000E29* + ID_OUI_FROM_DATABASE=Shester Communications Inc + +OUI:000E2B* + ID_OUI_FROM_DATABASE=Safari Technologies + +OUI:000E2C* + ID_OUI_FROM_DATABASE=Netcodec co. + +OUI:000E2D* + ID_OUI_FROM_DATABASE=Hyundai Digital Technology Co.,Ltd. + +OUI:000E2E* + ID_OUI_FROM_DATABASE=Edimax Technology Co., Ltd. + +OUI:000E2F* + ID_OUI_FROM_DATABASE=Roche Diagnostics GmbH + +OUI:000E30* + ID_OUI_FROM_DATABASE=AERAS Networks, Inc. + +OUI:000E31* + ID_OUI_FROM_DATABASE=Olympus Soft Imaging Solutions GmbH + +OUI:000E32* + ID_OUI_FROM_DATABASE=Kontron Medical + +OUI:000E33* + ID_OUI_FROM_DATABASE=Shuko Electronics Co.,Ltd + +OUI:000E34* + ID_OUI_FROM_DATABASE=NexGen City, LP + +OUI:000E35* + ID_OUI_FROM_DATABASE=Intel Corp + +OUI:000E36* + ID_OUI_FROM_DATABASE=HEINESYS, Inc. + +OUI:000E37* + ID_OUI_FROM_DATABASE=Harms & Wende GmbH & Co.KG + +OUI:000E38* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000E39* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000E3A* + ID_OUI_FROM_DATABASE=Cirrus Logic + +OUI:000E3B* + ID_OUI_FROM_DATABASE=Hawking Technologies, Inc. + +OUI:000E3C* + ID_OUI_FROM_DATABASE=Transact Technologies Inc + +OUI:000E3D* + ID_OUI_FROM_DATABASE=Televic N.V. + +OUI:000E3E* + ID_OUI_FROM_DATABASE=Sun Optronics Inc + +OUI:000E3F* + ID_OUI_FROM_DATABASE=Soronti, Inc. + +OUI:000E40* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000E41* + ID_OUI_FROM_DATABASE=NIHON MECHATRONICS CO.,LTD. + +OUI:000E42* + ID_OUI_FROM_DATABASE=Motic Incoporation Ltd. + +OUI:000E43* + ID_OUI_FROM_DATABASE=G-Tek Electronics Sdn. Bhd. + +OUI:000E44* + ID_OUI_FROM_DATABASE=Digital 5, Inc. + +OUI:000E45* + ID_OUI_FROM_DATABASE=Beijing Newtry Electronic Technology Ltd + +OUI:000E46* + ID_OUI_FROM_DATABASE=Niigata Seimitsu Co.,Ltd. + +OUI:000E47* + ID_OUI_FROM_DATABASE=NCI System Co.,Ltd. + +OUI:000E48* + ID_OUI_FROM_DATABASE=Lipman TransAction Solutions + +OUI:000E49* + ID_OUI_FROM_DATABASE=Forsway Scandinavia AB + +OUI:000E4A* + ID_OUI_FROM_DATABASE=Changchun Huayu WEBPAD Co.,LTD + +OUI:000E4B* + ID_OUI_FROM_DATABASE=atrium c and i + +OUI:000E4C* + ID_OUI_FROM_DATABASE=Bermai Inc. + +OUI:000E4D* + ID_OUI_FROM_DATABASE=Numesa Inc. + +OUI:000E4E* + ID_OUI_FROM_DATABASE=Waveplus Technology Co., Ltd. + +OUI:000E4F* + ID_OUI_FROM_DATABASE=Trajet GmbH + +OUI:000E50* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:000E51* + ID_OUI_FROM_DATABASE=tecna elettronica srl + +OUI:000E52* + ID_OUI_FROM_DATABASE=Optium Corporation + +OUI:000E53* + ID_OUI_FROM_DATABASE=AV TECH CORPORATION + +OUI:000E54* + ID_OUI_FROM_DATABASE=AlphaCell Wireless Ltd. + +OUI:000E55* + ID_OUI_FROM_DATABASE=AUVITRAN + +OUI:000E56* + ID_OUI_FROM_DATABASE=4G Systems GmbH & Co. KG + +OUI:000E57* + ID_OUI_FROM_DATABASE=Iworld Networking, Inc. + +OUI:000E58* + ID_OUI_FROM_DATABASE=Sonos, Inc. + +OUI:000E59* + ID_OUI_FROM_DATABASE=SAGEM SA + +OUI:000E5A* + ID_OUI_FROM_DATABASE=TELEFIELD inc. + +OUI:000E5B* + ID_OUI_FROM_DATABASE=ParkerVision - Direct2Data + +OUI:000E5C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:000E5D* + ID_OUI_FROM_DATABASE=Triple Play Technologies A/S + +OUI:000E5E* + ID_OUI_FROM_DATABASE=Raisecom Technology + +OUI:000E5F* + ID_OUI_FROM_DATABASE=activ-net GmbH & Co. KG + +OUI:000E60* + ID_OUI_FROM_DATABASE=360SUN Digital Broadband Corporation + +OUI:000E61* + ID_OUI_FROM_DATABASE=MICROTROL LIMITED + +OUI:000E62* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000E63* + ID_OUI_FROM_DATABASE=Lemke Diagnostics GmbH + +OUI:000E64* + ID_OUI_FROM_DATABASE=Elphel, Inc + +OUI:000E65* + ID_OUI_FROM_DATABASE=TransCore + +OUI:000E66* + ID_OUI_FROM_DATABASE=Hitachi Advanced Digital, Inc. + +OUI:000E67* + ID_OUI_FROM_DATABASE=Eltis Microelectronics Ltd. + +OUI:000E68* + ID_OUI_FROM_DATABASE=E-TOP Network Technology Inc. + +OUI:000E69* + ID_OUI_FROM_DATABASE=China Electric Power Research Institute + +OUI:000E6A* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:000E6B* + ID_OUI_FROM_DATABASE=Janitza electronics GmbH + +OUI:000E6C* + ID_OUI_FROM_DATABASE=Device Drivers Limited + +OUI:000E6D* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:000E6E* + ID_OUI_FROM_DATABASE=MAT S.A. (Mircrelec Advanced Technology) + +OUI:000E6F* + ID_OUI_FROM_DATABASE=IRIS Corporation Berhad + +OUI:000E70* + ID_OUI_FROM_DATABASE=in2 Networks + +OUI:000E71* + ID_OUI_FROM_DATABASE=Gemstar Technology Development Ltd. + +OUI:000E72* + ID_OUI_FROM_DATABASE=CTS electronics + +OUI:000E73* + ID_OUI_FROM_DATABASE=Tpack A/S + +OUI:000E74* + ID_OUI_FROM_DATABASE=Solar Telecom. Tech + +OUI:000E75* + ID_OUI_FROM_DATABASE=New York Air Brake Corp. + +OUI:000E76* + ID_OUI_FROM_DATABASE=GEMSOC INNOVISION INC. + +OUI:000E77* + ID_OUI_FROM_DATABASE=Decru, Inc. + +OUI:000E78* + ID_OUI_FROM_DATABASE=Amtelco + +OUI:000E79* + ID_OUI_FROM_DATABASE=Ample Communications Inc. + +OUI:000E7A* + ID_OUI_FROM_DATABASE=GemWon Communications Co., Ltd. + +OUI:000E7B* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:000E7C* + ID_OUI_FROM_DATABASE=Televes S.A. + +OUI:000E7D* + ID_OUI_FROM_DATABASE=Electronics Line 3000 Ltd. + +OUI:000E7E* + ID_OUI_FROM_DATABASE=ionSign Oy + +OUI:000E7F* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000E80* + ID_OUI_FROM_DATABASE=Thomson Technology Inc + +OUI:000E81* + ID_OUI_FROM_DATABASE=Devicescape Software, Inc. + +OUI:000E82* + ID_OUI_FROM_DATABASE=Commtech Wireless + +OUI:000E83* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000E84* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000E85* + ID_OUI_FROM_DATABASE=Catalyst Enterprises, Inc. + +OUI:000E86* + ID_OUI_FROM_DATABASE=Alcatel North America + +OUI:000E87* + ID_OUI_FROM_DATABASE=adp Gauselmann GmbH + +OUI:000E88* + ID_OUI_FROM_DATABASE=VIDEOTRON CORP. + +OUI:000E89* + ID_OUI_FROM_DATABASE=CLEMATIC + +OUI:000E8A* + ID_OUI_FROM_DATABASE=Avara Technologies Pty. Ltd. + +OUI:000E8B* + ID_OUI_FROM_DATABASE=Astarte Technology Co, Ltd. + +OUI:000E8C* + ID_OUI_FROM_DATABASE=Siemens AG A&D ET + +OUI:000E8D* + ID_OUI_FROM_DATABASE=Systems in Progress Holding GmbH + +OUI:000E8E* + ID_OUI_FROM_DATABASE=SparkLAN Communications, Inc. + +OUI:000E8F* + ID_OUI_FROM_DATABASE=Sercomm Corp. + +OUI:000E90* + ID_OUI_FROM_DATABASE=PONICO CORP. + +OUI:000E91* + ID_OUI_FROM_DATABASE=Navico Auckland Ltd + +OUI:000E92* + ID_OUI_FROM_DATABASE=Open Telecom + +OUI:000E93* + ID_OUI_FROM_DATABASE=Milénio 3 Sistemas Electrónicos, Lda. + +OUI:000E94* + ID_OUI_FROM_DATABASE=Maas International BV + +OUI:000E95* + ID_OUI_FROM_DATABASE=Fujiya Denki Seisakusho Co.,Ltd. + +OUI:000E96* + ID_OUI_FROM_DATABASE=Cubic Defense Applications, Inc. + +OUI:000E97* + ID_OUI_FROM_DATABASE=Ultracker Technology CO., Inc + +OUI:000E98* + ID_OUI_FROM_DATABASE=HME Clear-Com LTD. + +OUI:000E99* + ID_OUI_FROM_DATABASE=Spectrum Digital, Inc + +OUI:000E9A* + ID_OUI_FROM_DATABASE=BOE TECHNOLOGY GROUP CO.,LTD + +OUI:000E9B* + ID_OUI_FROM_DATABASE=Ambit Microsystems Corporation + +OUI:000E9C* + ID_OUI_FROM_DATABASE=Benchmark Electronics + +OUI:000E9D* + ID_OUI_FROM_DATABASE=Tiscali UK Ltd + +OUI:000E9E* + ID_OUI_FROM_DATABASE=Topfield Co., Ltd + +OUI:000E9F* + ID_OUI_FROM_DATABASE=TEMIC SDS GmbH + +OUI:000EA0* + ID_OUI_FROM_DATABASE=NetKlass Technology Inc. + +OUI:000EA1* + ID_OUI_FROM_DATABASE=Formosa Teletek Corporation + +OUI:000EA2* + ID_OUI_FROM_DATABASE=McAfee, Inc + +OUI:000EA3* + ID_OUI_FROM_DATABASE=CNCR-IT CO.,LTD,HangZhou P.R.CHINA + +OUI:000EA4* + ID_OUI_FROM_DATABASE=Certance Inc. + +OUI:000EA5* + ID_OUI_FROM_DATABASE=BLIP Systems + +OUI:000EA6* + ID_OUI_FROM_DATABASE=ASUSTEK COMPUTER INC. + +OUI:000EA7* + ID_OUI_FROM_DATABASE=Endace Technology + +OUI:000EA8* + ID_OUI_FROM_DATABASE=United Technologists Europe Limited + +OUI:000EA9* + ID_OUI_FROM_DATABASE=Shanghai Xun Shi Communications Equipment Ltd. Co. + +OUI:000EAA* + ID_OUI_FROM_DATABASE=Scalent Systems, Inc. + +OUI:000EAB* + ID_OUI_FROM_DATABASE=Cray Inc + +OUI:000EAC* + ID_OUI_FROM_DATABASE=MINTRON ENTERPRISE CO., LTD. + +OUI:000EAD* + ID_OUI_FROM_DATABASE=Metanoia Technologies, Inc. + +OUI:000EAE* + ID_OUI_FROM_DATABASE=GAWELL TECHNOLOGIES CORP. + +OUI:000EAF* + ID_OUI_FROM_DATABASE=CASTEL + +OUI:000EB0* + ID_OUI_FROM_DATABASE=Solutions Radio BV + +OUI:000EB1* + ID_OUI_FROM_DATABASE=Newcotech,Ltd + +OUI:000EB2* + ID_OUI_FROM_DATABASE=Micro-Research Finland Oy + +OUI:000EB3* + ID_OUI_FROM_DATABASE=Hewlett-Packard + +OUI:000EB4* + ID_OUI_FROM_DATABASE=GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD. + +OUI:000EB5* + ID_OUI_FROM_DATABASE=Ecastle Electronics Co., Ltd. + +OUI:000EB6* + ID_OUI_FROM_DATABASE=Riverbed Technology, Inc. + +OUI:000EB7* + ID_OUI_FROM_DATABASE=Knovative, Inc. + +OUI:000EB8* + ID_OUI_FROM_DATABASE=Iiga co.,Ltd + +OUI:000EB9* + ID_OUI_FROM_DATABASE=HASHIMOTO Electronics Industry Co.,Ltd. + +OUI:000EBA* + ID_OUI_FROM_DATABASE=HANMI SEMICONDUCTOR CO., LTD. + +OUI:000EBB* + ID_OUI_FROM_DATABASE=Everbee Networks + +OUI:000EBC* + ID_OUI_FROM_DATABASE=Paragon Fidelity GmbH + +OUI:000EBD* + ID_OUI_FROM_DATABASE=Burdick, a Quinton Compny + +OUI:000EBE* + ID_OUI_FROM_DATABASE=B&B Electronics Manufacturing Co. + +OUI:000EBF* + ID_OUI_FROM_DATABASE=Remsdaq Limited + +OUI:000EC0* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000EC1* + ID_OUI_FROM_DATABASE=MYNAH Technologies + +OUI:000EC2* + ID_OUI_FROM_DATABASE=Lowrance Electronics, Inc. + +OUI:000EC3* + ID_OUI_FROM_DATABASE=Logic Controls, Inc. + +OUI:000EC4* + ID_OUI_FROM_DATABASE=Iskra Transmission d.d. + +OUI:000EC5* + ID_OUI_FROM_DATABASE=Digital Multitools Inc + +OUI:000EC6* + ID_OUI_FROM_DATABASE=ASIX ELECTRONICS CORP. + +OUI:000EC7* + ID_OUI_FROM_DATABASE=Motorola Korea + +OUI:000EC8* + ID_OUI_FROM_DATABASE=Zoran Corporation + +OUI:000EC9* + ID_OUI_FROM_DATABASE=YOKO Technology Corp. + +OUI:000ECA* + ID_OUI_FROM_DATABASE=WTSS Inc + +OUI:000ECB* + ID_OUI_FROM_DATABASE=VineSys Technology + +OUI:000ECC* + ID_OUI_FROM_DATABASE=Tableau, LLC + +OUI:000ECD* + ID_OUI_FROM_DATABASE=SKOV A/S + +OUI:000ECE* + ID_OUI_FROM_DATABASE=S.I.T.T.I. S.p.A. + +OUI:000ECF* + ID_OUI_FROM_DATABASE=PROFIBUS Nutzerorganisation e.V. + +OUI:000ED0* + ID_OUI_FROM_DATABASE=Privaris, Inc. + +OUI:000ED1* + ID_OUI_FROM_DATABASE=Osaka Micro Computer. + +OUI:000ED2* + ID_OUI_FROM_DATABASE=Filtronic plc + +OUI:000ED3* + ID_OUI_FROM_DATABASE=Epicenter, Inc. + +OUI:000ED4* + ID_OUI_FROM_DATABASE=CRESITT INDUSTRIE + +OUI:000ED5* + ID_OUI_FROM_DATABASE=COPAN Systems Inc. + +OUI:000ED6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000ED7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000ED8* + ID_OUI_FROM_DATABASE=Aktino, Inc. + +OUI:000ED9* + ID_OUI_FROM_DATABASE=Aksys, Ltd. + +OUI:000EDA* + ID_OUI_FROM_DATABASE=C-TECH UNITED CORP. + +OUI:000EDB* + ID_OUI_FROM_DATABASE=XiNCOM Corp. + +OUI:000EDC* + ID_OUI_FROM_DATABASE=Tellion INC. + +OUI:000EDD* + ID_OUI_FROM_DATABASE=SHURE INCORPORATED + +OUI:000EDE* + ID_OUI_FROM_DATABASE=REMEC, Inc. + +OUI:000EDF* + ID_OUI_FROM_DATABASE=PLX Technology + +OUI:000EE0* + ID_OUI_FROM_DATABASE=Mcharge + +OUI:000EE1* + ID_OUI_FROM_DATABASE=ExtremeSpeed Inc. + +OUI:000EE2* + ID_OUI_FROM_DATABASE=Custom Engineering S.p.A. + +OUI:000EE3* + ID_OUI_FROM_DATABASE=Chiyu Technology Co.,Ltd + +OUI:000EE4* + ID_OUI_FROM_DATABASE=BOE TECHNOLOGY GROUP CO.,LTD + +OUI:000EE5* + ID_OUI_FROM_DATABASE=bitWallet, Inc. + +OUI:000EE6* + ID_OUI_FROM_DATABASE=Adimos Systems LTD + +OUI:000EE7* + ID_OUI_FROM_DATABASE=AAC ELECTRONICS CORP. + +OUI:000EE8* + ID_OUI_FROM_DATABASE=zioncom + +OUI:000EE9* + ID_OUI_FROM_DATABASE=WayTech Development, Inc. + +OUI:000EEA* + ID_OUI_FROM_DATABASE=Shadong Luneng Jicheng Electronics,Co.,Ltd + +OUI:000EEB* + ID_OUI_FROM_DATABASE=Sandmartin(zhong shan)Electronics Co.,Ltd + +OUI:000EEC* + ID_OUI_FROM_DATABASE=Orban + +OUI:000EED* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:000EEE* + ID_OUI_FROM_DATABASE=Muco Industrie BV + +OUI:000EF0* + ID_OUI_FROM_DATABASE=Festo AG & Co. KG + +OUI:000EF1* + ID_OUI_FROM_DATABASE=EZQUEST INC. + +OUI:000EF2* + ID_OUI_FROM_DATABASE=Infinico Corporation + +OUI:000EF3* + ID_OUI_FROM_DATABASE=Smarthome + +OUI:000EF4* + ID_OUI_FROM_DATABASE=Kasda Digital Technology Co.,Ltd + +OUI:000EF5* + ID_OUI_FROM_DATABASE=iPAC Technology Co., Ltd. + +OUI:000EF6* + ID_OUI_FROM_DATABASE=E-TEN Information Systems Co., Ltd. + +OUI:000EF7* + ID_OUI_FROM_DATABASE=Vulcan Portals Inc + +OUI:000EF8* + ID_OUI_FROM_DATABASE=SBC ASI + +OUI:000EF9* + ID_OUI_FROM_DATABASE=REA Elektronik GmbH + +OUI:000EFA* + ID_OUI_FROM_DATABASE=Optoway Technology Incorporation + +OUI:000EFB* + ID_OUI_FROM_DATABASE=Macey Enterprises + +OUI:000EFC* + ID_OUI_FROM_DATABASE=JTAG Technologies B.V. + +OUI:000EFD* + ID_OUI_FROM_DATABASE=FUJINON CORPORATION + +OUI:000EFE* + ID_OUI_FROM_DATABASE=EndRun Technologies LLC + +OUI:000EFF* + ID_OUI_FROM_DATABASE=Megasolution,Inc. + +OUI:000F00* + ID_OUI_FROM_DATABASE=Legra Systems, Inc. + +OUI:000F01* + ID_OUI_FROM_DATABASE=DIGITALKS INC + +OUI:000F02* + ID_OUI_FROM_DATABASE=Digicube Technology Co., Ltd + +OUI:000F03* + ID_OUI_FROM_DATABASE=COM&C CO., LTD + +OUI:000F04* + ID_OUI_FROM_DATABASE=cim-usa inc + +OUI:000F05* + ID_OUI_FROM_DATABASE=3B SYSTEM INC. + +OUI:000F06* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000F07* + ID_OUI_FROM_DATABASE=Mangrove Systems, Inc. + +OUI:000F08* + ID_OUI_FROM_DATABASE=Indagon Oy + +OUI:000F0A* + ID_OUI_FROM_DATABASE=Clear Edge Networks + +OUI:000F0B* + ID_OUI_FROM_DATABASE=Kentima Technologies AB + +OUI:000F0C* + ID_OUI_FROM_DATABASE=SYNCHRONIC ENGINEERING + +OUI:000F0D* + ID_OUI_FROM_DATABASE=Hunt Electronic Co., Ltd. + +OUI:000F0E* + ID_OUI_FROM_DATABASE=WaveSplitter Technologies, Inc. + +OUI:000F0F* + ID_OUI_FROM_DATABASE=Real ID Technology Co., Ltd. + +OUI:000F10* + ID_OUI_FROM_DATABASE=RDM Corporation + +OUI:000F11* + ID_OUI_FROM_DATABASE=Prodrive B.V. + +OUI:000F12* + ID_OUI_FROM_DATABASE=Panasonic Europe Ltd. + +OUI:000F13* + ID_OUI_FROM_DATABASE=Nisca corporation + +OUI:000F14* + ID_OUI_FROM_DATABASE=Mindray Co., Ltd. + +OUI:000F15* + ID_OUI_FROM_DATABASE=Kjaerulff1 A/S + +OUI:000F16* + ID_OUI_FROM_DATABASE=JAY HOW TECHNOLOGY CO., + +OUI:000F17* + ID_OUI_FROM_DATABASE=Insta Elektro GmbH + +OUI:000F18* + ID_OUI_FROM_DATABASE=Industrial Control Systems + +OUI:000F19* + ID_OUI_FROM_DATABASE=Boston Scientific + +OUI:000F1A* + ID_OUI_FROM_DATABASE=Gaming Support B.V. + +OUI:000F1B* + ID_OUI_FROM_DATABASE=Ego Systems Inc. + +OUI:000F1C* + ID_OUI_FROM_DATABASE=DigitAll World Co., Ltd + +OUI:000F1D* + ID_OUI_FROM_DATABASE=Cosmo Techs Co., Ltd. + +OUI:000F1E* + ID_OUI_FROM_DATABASE=Chengdu KT Electric Co.of High & New Technology + +OUI:000F1F* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:000F20* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000F21* + ID_OUI_FROM_DATABASE=Scientific Atlanta, Inc + +OUI:000F22* + ID_OUI_FROM_DATABASE=Helius, Inc. + +OUI:000F23* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F24* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F25* + ID_OUI_FROM_DATABASE=AimValley B.V. + +OUI:000F26* + ID_OUI_FROM_DATABASE=WorldAccxx LLC + +OUI:000F27* + ID_OUI_FROM_DATABASE=TEAL Electronics, Inc. + +OUI:000F28* + ID_OUI_FROM_DATABASE=Itronix Corporation + +OUI:000F29* + ID_OUI_FROM_DATABASE=Augmentix Corporation + +OUI:000F2A* + ID_OUI_FROM_DATABASE=Cableware Electronics + +OUI:000F2B* + ID_OUI_FROM_DATABASE=GREENBELL SYSTEMS + +OUI:000F2C* + ID_OUI_FROM_DATABASE=Uplogix, Inc. + +OUI:000F2D* + ID_OUI_FROM_DATABASE=CHUNG-HSIN ELECTRIC & MACHINERY MFG.CORP. + +OUI:000F2E* + ID_OUI_FROM_DATABASE=Megapower International Corp. + +OUI:000F2F* + ID_OUI_FROM_DATABASE=W-LINX TECHNOLOGY CO., LTD. + +OUI:000F30* + ID_OUI_FROM_DATABASE=Raza Microelectronics Inc + +OUI:000F31* + ID_OUI_FROM_DATABASE=Allied Vision Technologies Canada Inc + +OUI:000F32* + ID_OUI_FROM_DATABASE=Lootom Telcovideo Network Wuxi Co Ltd + +OUI:000F33* + ID_OUI_FROM_DATABASE=DUALi Inc. + +OUI:000F34* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F35* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F36* + ID_OUI_FROM_DATABASE=Accurate Techhnologies, Inc. + +OUI:000F37* + ID_OUI_FROM_DATABASE=Xambala Incorporated + +OUI:000F38* + ID_OUI_FROM_DATABASE=Netstar + +OUI:000F39* + ID_OUI_FROM_DATABASE=IRIS SENSORS + +OUI:000F3A* + ID_OUI_FROM_DATABASE=HISHARP + +OUI:000F3B* + ID_OUI_FROM_DATABASE=Fuji System Machines Co., Ltd. + +OUI:000F3C* + ID_OUI_FROM_DATABASE=Endeleo Limited + +OUI:000F3D* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:000F3E* + ID_OUI_FROM_DATABASE=CardioNet, Inc + +OUI:000F3F* + ID_OUI_FROM_DATABASE=Big Bear Networks + +OUI:000F40* + ID_OUI_FROM_DATABASE=Optical Internetworking Forum + +OUI:000F41* + ID_OUI_FROM_DATABASE=Zipher Ltd + +OUI:000F42* + ID_OUI_FROM_DATABASE=Xalyo Systems + +OUI:000F43* + ID_OUI_FROM_DATABASE=Wasabi Systems Inc. + +OUI:000F44* + ID_OUI_FROM_DATABASE=Tivella Inc. + +OUI:000F45* + ID_OUI_FROM_DATABASE=Stretch, Inc. + +OUI:000F46* + ID_OUI_FROM_DATABASE=SINAR AG + +OUI:000F47* + ID_OUI_FROM_DATABASE=ROBOX SPA + +OUI:000F48* + ID_OUI_FROM_DATABASE=Polypix Inc. + +OUI:000F49* + ID_OUI_FROM_DATABASE=Northover Solutions Limited + +OUI:000F4A* + ID_OUI_FROM_DATABASE=Kyushu-kyohan co.,ltd + +OUI:000F4B* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:000F4C* + ID_OUI_FROM_DATABASE=Elextech INC + +OUI:000F4D* + ID_OUI_FROM_DATABASE=TalkSwitch + +OUI:000F4E* + ID_OUI_FROM_DATABASE=Cellink + +OUI:000F4F* + ID_OUI_FROM_DATABASE=Cadmus Technology Ltd + +OUI:000F50* + ID_OUI_FROM_DATABASE=StreamScale Limited + +OUI:000F51* + ID_OUI_FROM_DATABASE=Azul Systems, Inc. + +OUI:000F52* + ID_OUI_FROM_DATABASE=YORK Refrigeration, Marine & Controls + +OUI:000F53* + ID_OUI_FROM_DATABASE=Solarflare Communications Inc + +OUI:000F54* + ID_OUI_FROM_DATABASE=Entrelogic Corporation + +OUI:000F55* + ID_OUI_FROM_DATABASE=Datawire Communication Networks Inc. + +OUI:000F56* + ID_OUI_FROM_DATABASE=Continuum Photonics Inc + +OUI:000F57* + ID_OUI_FROM_DATABASE=CABLELOGIC Co., Ltd. + +OUI:000F58* + ID_OUI_FROM_DATABASE=Adder Technology Limited + +OUI:000F59* + ID_OUI_FROM_DATABASE=Phonak Communications AG + +OUI:000F5A* + ID_OUI_FROM_DATABASE=Peribit Networks + +OUI:000F5B* + ID_OUI_FROM_DATABASE=Delta Information Systems, Inc. + +OUI:000F5C* + ID_OUI_FROM_DATABASE=Day One Digital Media Limited + +OUI:000F5D* + ID_OUI_FROM_DATABASE=Genexis BV + +OUI:000F5E* + ID_OUI_FROM_DATABASE=Veo + +OUI:000F5F* + ID_OUI_FROM_DATABASE=Nicety Technologies Inc. (NTS) + +OUI:000F60* + ID_OUI_FROM_DATABASE=Lifetron Co.,Ltd + +OUI:000F61* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:000F62* + ID_OUI_FROM_DATABASE=Alcatel Bell Space N.V. + +OUI:000F63* + ID_OUI_FROM_DATABASE=Obzerv Technologies + +OUI:000F64* + ID_OUI_FROM_DATABASE=D&R Electronica Weesp BV + +OUI:000F65* + ID_OUI_FROM_DATABASE=icube Corp. + +OUI:000F66* + ID_OUI_FROM_DATABASE=Cisco-Linksys + +OUI:000F67* + ID_OUI_FROM_DATABASE=West Instruments + +OUI:000F68* + ID_OUI_FROM_DATABASE=Vavic Network Technology, Inc. + +OUI:000F69* + ID_OUI_FROM_DATABASE=SEW Eurodrive GmbH & Co. KG + +OUI:000F6A* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000F6B* + ID_OUI_FROM_DATABASE=GateWare Communications GmbH + +OUI:000F6C* + ID_OUI_FROM_DATABASE=ADDI-DATA GmbH + +OUI:000F6D* + ID_OUI_FROM_DATABASE=Midas Engineering + +OUI:000F6E* + ID_OUI_FROM_DATABASE=BBox + +OUI:000F6F* + ID_OUI_FROM_DATABASE=FTA Communication Technologies + +OUI:000F70* + ID_OUI_FROM_DATABASE=Wintec Industries, inc. + +OUI:000F71* + ID_OUI_FROM_DATABASE=Sanmei Electronics Co.,Ltd + +OUI:000F72* + ID_OUI_FROM_DATABASE=Sandburst + +OUI:000F73* + ID_OUI_FROM_DATABASE=RS Automation Co., Ltd + +OUI:000F74* + ID_OUI_FROM_DATABASE=Qamcom Technology AB + +OUI:000F75* + ID_OUI_FROM_DATABASE=First Silicon Solutions + +OUI:000F76* + ID_OUI_FROM_DATABASE=Digital Keystone, Inc. + +OUI:000F77* + ID_OUI_FROM_DATABASE=DENTUM CO.,LTD + +OUI:000F78* + ID_OUI_FROM_DATABASE=Datacap Systems Inc + +OUI:000F79* + ID_OUI_FROM_DATABASE=Bluetooth Interest Group Inc. + +OUI:000F7A* + ID_OUI_FROM_DATABASE=BeiJing NuQX Technology CO.,LTD + +OUI:000F7B* + ID_OUI_FROM_DATABASE=Arce Sistemas, S.A. + +OUI:000F7C* + ID_OUI_FROM_DATABASE=ACTi Corporation + +OUI:000F7D* + ID_OUI_FROM_DATABASE=Xirrus + +OUI:000F7E* + ID_OUI_FROM_DATABASE=Ablerex Electronics Co., LTD + +OUI:000F7F* + ID_OUI_FROM_DATABASE=UBSTORAGE Co.,Ltd. + +OUI:000F80* + ID_OUI_FROM_DATABASE=Trinity Security Systems,Inc. + +OUI:000F81* + ID_OUI_FROM_DATABASE=PAL Pacific Inc. + +OUI:000F82* + ID_OUI_FROM_DATABASE=Mortara Instrument, Inc. + +OUI:000F83* + ID_OUI_FROM_DATABASE=Brainium Technologies Inc. + +OUI:000F84* + ID_OUI_FROM_DATABASE=Astute Networks, Inc. + +OUI:000F85* + ID_OUI_FROM_DATABASE=ADDO-Japan Corporation + +OUI:000F86* + ID_OUI_FROM_DATABASE=Research In Motion Limited + +OUI:000F87* + ID_OUI_FROM_DATABASE=Maxcess International + +OUI:000F88* + ID_OUI_FROM_DATABASE=AMETEK, Inc. + +OUI:000F89* + ID_OUI_FROM_DATABASE=Winnertec System Co., Ltd. + +OUI:000F8A* + ID_OUI_FROM_DATABASE=WideView + +OUI:000F8B* + ID_OUI_FROM_DATABASE=Orion MultiSystems Inc + +OUI:000F8C* + ID_OUI_FROM_DATABASE=Gigawavetech Pte Ltd + +OUI:000F8D* + ID_OUI_FROM_DATABASE=FAST TV-Server AG + +OUI:000F8E* + ID_OUI_FROM_DATABASE=DONGYANG TELECOM CO.,LTD. + +OUI:000F8F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F90* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000F91* + ID_OUI_FROM_DATABASE=Aerotelecom Co.,Ltd. + +OUI:000F92* + ID_OUI_FROM_DATABASE=Microhard Systems Inc. + +OUI:000F93* + ID_OUI_FROM_DATABASE=Landis+Gyr Ltd. + +OUI:000F94* + ID_OUI_FROM_DATABASE=Genexis BV + +OUI:000F95* + ID_OUI_FROM_DATABASE=ELECOM Co.,LTD Laneed Division + +OUI:000F96* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:000F97* + ID_OUI_FROM_DATABASE=Avanex Corporation + +OUI:000F98* + ID_OUI_FROM_DATABASE=Avamax Co. Ltd. + +OUI:000F99* + ID_OUI_FROM_DATABASE=APAC opto Electronics Inc. + +OUI:000F9A* + ID_OUI_FROM_DATABASE=Synchrony, Inc. + +OUI:000F9B* + ID_OUI_FROM_DATABASE=Ross Video Limited + +OUI:000F9C* + ID_OUI_FROM_DATABASE=Panduit Corp + +OUI:000F9D* + ID_OUI_FROM_DATABASE=DisplayLink (UK) Ltd + +OUI:000F9E* + ID_OUI_FROM_DATABASE=Murrelektronik GmbH + +OUI:000F9F* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:000FA0* + ID_OUI_FROM_DATABASE=CANON KOREA BUSINESS SOLUTIONS INC. + +OUI:000FA1* + ID_OUI_FROM_DATABASE=Gigabit Systems Inc. + +OUI:000FA2* + ID_OUI_FROM_DATABASE=2xWireless + +OUI:000FA3* + ID_OUI_FROM_DATABASE=Alpha Networks Inc. + +OUI:000FA4* + ID_OUI_FROM_DATABASE=Sprecher Automation GmbH + +OUI:000FA5* + ID_OUI_FROM_DATABASE=BWA Technology GmbH + +OUI:000FA6* + ID_OUI_FROM_DATABASE=S2 Security Corporation + +OUI:000FA7* + ID_OUI_FROM_DATABASE=Raptor Networks Technology + +OUI:000FA8* + ID_OUI_FROM_DATABASE=Photometrics, Inc. + +OUI:000FA9* + ID_OUI_FROM_DATABASE=PC Fabrik + +OUI:000FAA* + ID_OUI_FROM_DATABASE=Nexus Technologies + +OUI:000FAB* + ID_OUI_FROM_DATABASE=Kyushu Electronics Systems Inc. + +OUI:000FAC* + ID_OUI_FROM_DATABASE=IEEE 802.11 + +OUI:000FAD* + ID_OUI_FROM_DATABASE=FMN communications GmbH + +OUI:000FAE* + ID_OUI_FROM_DATABASE=E2O Communications + +OUI:000FAF* + ID_OUI_FROM_DATABASE=Dialog Inc. + +OUI:000FB0* + ID_OUI_FROM_DATABASE=Compal Electronics,INC. + +OUI:000FB1* + ID_OUI_FROM_DATABASE=Cognio Inc. + +OUI:000FB2* + ID_OUI_FROM_DATABASE=Broadband Pacenet (India) Pvt. Ltd. + +OUI:000FB3* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:000FB4* + ID_OUI_FROM_DATABASE=Timespace Technology + +OUI:000FB5* + ID_OUI_FROM_DATABASE=NETGEAR Inc + +OUI:000FB6* + ID_OUI_FROM_DATABASE=Europlex Technologies + +OUI:000FB7* + ID_OUI_FROM_DATABASE=Cavium Networks + +OUI:000FB8* + ID_OUI_FROM_DATABASE=CallURL Inc. + +OUI:000FB9* + ID_OUI_FROM_DATABASE=Adaptive Instruments + +OUI:000FBA* + ID_OUI_FROM_DATABASE=Tevebox AB + +OUI:000FBB* + ID_OUI_FROM_DATABASE=Nokia Siemens Networks GmbH & Co. KG. + +OUI:000FBC* + ID_OUI_FROM_DATABASE=Onkey Technologies, Inc. + +OUI:000FBD* + ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD + +OUI:000FBE* + ID_OUI_FROM_DATABASE=e-w/you Inc. + +OUI:000FBF* + ID_OUI_FROM_DATABASE=DGT Sp. z o.o. + +OUI:000FC0* + ID_OUI_FROM_DATABASE=DELCOMp + +OUI:000FC1* + ID_OUI_FROM_DATABASE=WAVE Corporation + +OUI:000FC2* + ID_OUI_FROM_DATABASE=Uniwell Corporation + +OUI:000FC3* + ID_OUI_FROM_DATABASE=PalmPalm Technology, Inc. + +OUI:000FC4* + ID_OUI_FROM_DATABASE=NST co.,LTD. + +OUI:000FC5* + ID_OUI_FROM_DATABASE=KeyMed Ltd + +OUI:000FC6* + ID_OUI_FROM_DATABASE=Eurocom Industries A/S + +OUI:000FC7* + ID_OUI_FROM_DATABASE=Dionica R&D Ltd. + +OUI:000FC8* + ID_OUI_FROM_DATABASE=Chantry Networks + +OUI:000FC9* + ID_OUI_FROM_DATABASE=Allnet GmbH + +OUI:000FCA* + ID_OUI_FROM_DATABASE=A-JIN TECHLINE CO, LTD + +OUI:000FCB* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:000FCC* + ID_OUI_FROM_DATABASE=Netopia, Inc. + +OUI:000FCD* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000FCE* + ID_OUI_FROM_DATABASE=Kikusui Electronics Corp. + +OUI:000FCF* + ID_OUI_FROM_DATABASE=Datawind Research + +OUI:000FD0* + ID_OUI_FROM_DATABASE=ASTRI + +OUI:000FD1* + ID_OUI_FROM_DATABASE=Applied Wireless Identifications Group, Inc. + +OUI:000FD2* + ID_OUI_FROM_DATABASE=EWA Technologies, Inc. + +OUI:000FD3* + ID_OUI_FROM_DATABASE=Digium + +OUI:000FD4* + ID_OUI_FROM_DATABASE=Soundcraft + +OUI:000FD5* + ID_OUI_FROM_DATABASE=Schwechat - RISE + +OUI:000FD6* + ID_OUI_FROM_DATABASE=Sarotech Co., Ltd + +OUI:000FD7* + ID_OUI_FROM_DATABASE=Harman Music Group + +OUI:000FD8* + ID_OUI_FROM_DATABASE=Force, Inc. + +OUI:000FD9* + ID_OUI_FROM_DATABASE=FlexDSL Telecommunications AG + +OUI:000FDA* + ID_OUI_FROM_DATABASE=YAZAKI CORPORATION + +OUI:000FDB* + ID_OUI_FROM_DATABASE=Westell Technologies + +OUI:000FDC* + ID_OUI_FROM_DATABASE=Ueda Japan Radio Co., Ltd. + +OUI:000FDD* + ID_OUI_FROM_DATABASE=SORDIN AB + +OUI:000FDE* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:000FDF* + ID_OUI_FROM_DATABASE=SOLOMON Technology Corp. + +OUI:000FE0* + ID_OUI_FROM_DATABASE=NComputing Co.,Ltd. + +OUI:000FE1* + ID_OUI_FROM_DATABASE=ID DIGITAL CORPORATION + +OUI:000FE2* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Ltd. + +OUI:000FE3* + ID_OUI_FROM_DATABASE=Damm Cellular Systems A/S + +OUI:000FE4* + ID_OUI_FROM_DATABASE=Pantech Co.,Ltd + +OUI:000FE5* + ID_OUI_FROM_DATABASE=MERCURY SECURITY CORPORATION + +OUI:000FE6* + ID_OUI_FROM_DATABASE=MBTech Systems, Inc. + +OUI:000FE7* + ID_OUI_FROM_DATABASE=Lutron Electronics Co., Inc. + +OUI:000FE8* + ID_OUI_FROM_DATABASE=Lobos, Inc. + +OUI:000FE9* + ID_OUI_FROM_DATABASE=GW TECHNOLOGIES CO.,LTD. + +OUI:000FEA* + ID_OUI_FROM_DATABASE=Giga-Byte Technology Co.,LTD. + +OUI:000FEB* + ID_OUI_FROM_DATABASE=Cylon Controls + +OUI:000FEC* + ID_OUI_FROM_DATABASE=ARKUS Inc. + +OUI:000FED* + ID_OUI_FROM_DATABASE=Anam Electronics Co., Ltd + +OUI:000FEE* + ID_OUI_FROM_DATABASE=XTec, Incorporated + +OUI:000FEF* + ID_OUI_FROM_DATABASE=Thales e-Transactions GmbH + +OUI:000FF0* + ID_OUI_FROM_DATABASE=Sunray Co. Ltd. + +OUI:000FF1* + ID_OUI_FROM_DATABASE=nex-G Systems Pte.Ltd + +OUI:000FF2* + ID_OUI_FROM_DATABASE=Loud Technologies Inc. + +OUI:000FF3* + ID_OUI_FROM_DATABASE=Jung Myoung Communications&Technology + +OUI:000FF4* + ID_OUI_FROM_DATABASE=Guntermann & Drunck GmbH + +OUI:000FF5* + ID_OUI_FROM_DATABASE=GN&S company + +OUI:000FF6* + ID_OUI_FROM_DATABASE=Darfon Electronics Corp. + +OUI:000FF7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000FF8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:000FF9* + ID_OUI_FROM_DATABASE=Valcretec, Inc. + +OUI:000FFA* + ID_OUI_FROM_DATABASE=Optinel Systems, Inc. + +OUI:000FFB* + ID_OUI_FROM_DATABASE=Nippon Denso Industry Co., Ltd. + +OUI:000FFC* + ID_OUI_FROM_DATABASE=Merit Li-Lin Ent. + +OUI:000FFD* + ID_OUI_FROM_DATABASE=Glorytek Network Inc. + +OUI:000FFE* + ID_OUI_FROM_DATABASE=G-PRO COMPUTER + +OUI:000FFF* + ID_OUI_FROM_DATABASE=Control4 + +OUI:001000* + ID_OUI_FROM_DATABASE=CABLE TELEVISION LABORATORIES, INC. + +OUI:001001* + ID_OUI_FROM_DATABASE=Citel + +OUI:001002* + ID_OUI_FROM_DATABASE=ACTIA + +OUI:001003* + ID_OUI_FROM_DATABASE=IMATRON, INC. + +OUI:001004* + ID_OUI_FROM_DATABASE=THE BRANTLEY COILE COMPANY,INC + +OUI:001005* + ID_OUI_FROM_DATABASE=UEC COMMERCIAL + +OUI:001006* + ID_OUI_FROM_DATABASE=Thales Contact Solutions Ltd. + +OUI:001007* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001008* + ID_OUI_FROM_DATABASE=VIENNA SYSTEMS CORPORATION + +OUI:001009* + ID_OUI_FROM_DATABASE=HORO QUARTZ + +OUI:00100A* + ID_OUI_FROM_DATABASE=WILLIAMS COMMUNICATIONS GROUP + +OUI:00100B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00100C* + ID_OUI_FROM_DATABASE=ITO CO., LTD. + +OUI:00100D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00100E* + ID_OUI_FROM_DATABASE=MICRO LINEAR COPORATION + +OUI:00100F* + ID_OUI_FROM_DATABASE=INDUSTRIAL CPU SYSTEMS + +OUI:001010* + ID_OUI_FROM_DATABASE=INITIO CORPORATION + +OUI:001011* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001012* + ID_OUI_FROM_DATABASE=PROCESSOR SYSTEMS (I) PVT LTD + +OUI:001013* + ID_OUI_FROM_DATABASE=Kontron America, Inc. + +OUI:001014* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001015* + ID_OUI_FROM_DATABASE=OOmon Inc. + +OUI:001016* + ID_OUI_FROM_DATABASE=T.SQWARE + +OUI:001017* + ID_OUI_FROM_DATABASE=Bosch Access Systems GmbH + +OUI:001018* + ID_OUI_FROM_DATABASE=BROADCOM CORPORATION + +OUI:001019* + ID_OUI_FROM_DATABASE=SIRONA DENTAL SYSTEMS GmbH & Co. KG + +OUI:00101A* + ID_OUI_FROM_DATABASE=PictureTel Corp. + +OUI:00101B* + ID_OUI_FROM_DATABASE=CORNET TECHNOLOGY, INC. + +OUI:00101C* + ID_OUI_FROM_DATABASE=OHM TECHNOLOGIES INTL, LLC + +OUI:00101D* + ID_OUI_FROM_DATABASE=WINBOND ELECTRONICS CORP. + +OUI:00101E* + ID_OUI_FROM_DATABASE=MATSUSHITA ELECTRONIC INSTRUMENTS CORP. + +OUI:00101F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001020* + ID_OUI_FROM_DATABASE=Hand Held Products Inc + +OUI:001021* + ID_OUI_FROM_DATABASE=ENCANTO NETWORKS, INC. + +OUI:001022* + ID_OUI_FROM_DATABASE=SatCom Media Corporation + +OUI:001023* + ID_OUI_FROM_DATABASE=Network Equipment Technologies + +OUI:001024* + ID_OUI_FROM_DATABASE=NAGOYA ELECTRIC WORKS CO., LTD + +OUI:001025* + ID_OUI_FROM_DATABASE=Grayhill, Inc + +OUI:001026* + ID_OUI_FROM_DATABASE=ACCELERATED NETWORKS, INC. + +OUI:001027* + ID_OUI_FROM_DATABASE=L-3 COMMUNICATIONS EAST + +OUI:001028* + ID_OUI_FROM_DATABASE=COMPUTER TECHNICA, INC. + +OUI:001029* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00102A* + ID_OUI_FROM_DATABASE=ZF MICROSYSTEMS, INC. + +OUI:00102B* + ID_OUI_FROM_DATABASE=UMAX DATA SYSTEMS, INC. + +OUI:00102C* + ID_OUI_FROM_DATABASE=Lasat Networks A/S + +OUI:00102D* + ID_OUI_FROM_DATABASE=HITACHI SOFTWARE ENGINEERING + +OUI:00102E* + ID_OUI_FROM_DATABASE=NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD. + +OUI:00102F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001030* + ID_OUI_FROM_DATABASE=EION Inc. + +OUI:001031* + ID_OUI_FROM_DATABASE=OBJECTIVE COMMUNICATIONS, INC. + +OUI:001032* + ID_OUI_FROM_DATABASE=ALTA TECHNOLOGY + +OUI:001033* + ID_OUI_FROM_DATABASE=ACCESSLAN COMMUNICATIONS, INC. + +OUI:001034* + ID_OUI_FROM_DATABASE=GNP Computers + +OUI:001035* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEMS CO., LTD + +OUI:001036* + ID_OUI_FROM_DATABASE=INTER-TEL INTEGRATED SYSTEMS + +OUI:001037* + ID_OUI_FROM_DATABASE=CYQ've Technology Co., Ltd. + +OUI:001038* + ID_OUI_FROM_DATABASE=MICRO RESEARCH INSTITUTE, INC. + +OUI:001039* + ID_OUI_FROM_DATABASE=Vectron Systems AG + +OUI:00103A* + ID_OUI_FROM_DATABASE=DIAMOND NETWORK TECH + +OUI:00103B* + ID_OUI_FROM_DATABASE=HIPPI NETWORKING FORUM + +OUI:00103C* + ID_OUI_FROM_DATABASE=IC ENSEMBLE, INC. + +OUI:00103D* + ID_OUI_FROM_DATABASE=PHASECOM, LTD. + +OUI:00103E* + ID_OUI_FROM_DATABASE=NETSCHOOLS CORPORATION + +OUI:00103F* + ID_OUI_FROM_DATABASE=TOLLGRADE COMMUNICATIONS, INC. + +OUI:001040* + ID_OUI_FROM_DATABASE=INTERMEC CORPORATION + +OUI:001041* + ID_OUI_FROM_DATABASE=BRISTOL BABCOCK, INC. + +OUI:001042* + ID_OUI_FROM_DATABASE=Alacritech, Inc. + +OUI:001043* + ID_OUI_FROM_DATABASE=A2 CORPORATION + +OUI:001044* + ID_OUI_FROM_DATABASE=InnoLabs Corporation + +OUI:001045* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:001046* + ID_OUI_FROM_DATABASE=ALCORN MCBRIDE INC. + +OUI:001047* + ID_OUI_FROM_DATABASE=ECHO ELETRIC CO. LTD. + +OUI:001048* + ID_OUI_FROM_DATABASE=HTRC AUTOMATION, INC. + +OUI:001049* + ID_OUI_FROM_DATABASE=ShoreTel, Inc + +OUI:00104A* + ID_OUI_FROM_DATABASE=The Parvus Corporation + +OUI:00104B* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:00104C* + ID_OUI_FROM_DATABASE=Teledyne LeCroy, Inc + +OUI:00104D* + ID_OUI_FROM_DATABASE=SURTEC INDUSTRIES, INC. + +OUI:00104E* + ID_OUI_FROM_DATABASE=CEOLOGIC + +OUI:00104F* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:001050* + ID_OUI_FROM_DATABASE=RION CO., LTD. + +OUI:001051* + ID_OUI_FROM_DATABASE=CMICRO CORPORATION + +OUI:001052* + ID_OUI_FROM_DATABASE=METTLER-TOLEDO (ALBSTADT) GMBH + +OUI:001053* + ID_OUI_FROM_DATABASE=COMPUTER TECHNOLOGY CORP. + +OUI:001054* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001055* + ID_OUI_FROM_DATABASE=FUJITSU MICROELECTRONICS, INC. + +OUI:001056* + ID_OUI_FROM_DATABASE=SODICK CO., LTD. + +OUI:001057* + ID_OUI_FROM_DATABASE=Rebel.com, Inc. + +OUI:001058* + ID_OUI_FROM_DATABASE=ArrowPoint Communications + +OUI:001059* + ID_OUI_FROM_DATABASE=DIABLO RESEARCH CO. LLC + +OUI:00105A* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:00105B* + ID_OUI_FROM_DATABASE=NET INSIGHT AB + +OUI:00105C* + ID_OUI_FROM_DATABASE=QUANTUM DESIGNS (H.K.) LTD. + +OUI:00105D* + ID_OUI_FROM_DATABASE=Draeger Medical + +OUI:00105E* + ID_OUI_FROM_DATABASE=HEKIMIAN LABORATORIES, INC. + +OUI:00105F* + ID_OUI_FROM_DATABASE=ZODIAC DATA SYSTEMS + +OUI:001060* + ID_OUI_FROM_DATABASE=BILLIONTON SYSTEMS, INC. + +OUI:001061* + ID_OUI_FROM_DATABASE=HOSTLINK CORP. + +OUI:001062* + ID_OUI_FROM_DATABASE=NX SERVER, ILNC. + +OUI:001063* + ID_OUI_FROM_DATABASE=STARGUIDE DIGITAL NETWORKS + +OUI:001064* + ID_OUI_FROM_DATABASE=DNPG, LLC + +OUI:001065* + ID_OUI_FROM_DATABASE=RADYNE CORPORATION + +OUI:001066* + ID_OUI_FROM_DATABASE=ADVANCED CONTROL SYSTEMS, INC. + +OUI:001067* + ID_OUI_FROM_DATABASE=Ericsson + +OUI:001068* + ID_OUI_FROM_DATABASE=COMOS TELECOM + +OUI:001069* + ID_OUI_FROM_DATABASE=HELIOSS COMMUNICATIONS, INC. + +OUI:00106A* + ID_OUI_FROM_DATABASE=DIGITAL MICROWAVE CORPORATION + +OUI:00106B* + ID_OUI_FROM_DATABASE=SONUS NETWORKS, INC. + +OUI:00106C* + ID_OUI_FROM_DATABASE=EDNT GmbH + +OUI:00106D* + ID_OUI_FROM_DATABASE=Axxcelera Broadband Wireless + +OUI:00106E* + ID_OUI_FROM_DATABASE=TADIRAN COM. LTD. + +OUI:00106F* + ID_OUI_FROM_DATABASE=TRENTON TECHNOLOGY INC. + +OUI:001070* + ID_OUI_FROM_DATABASE=CARADON TREND LTD. + +OUI:001071* + ID_OUI_FROM_DATABASE=ADVANET INC. + +OUI:001072* + ID_OUI_FROM_DATABASE=GVN TECHNOLOGIES, INC. + +OUI:001073* + ID_OUI_FROM_DATABASE=Technobox, Inc. + +OUI:001074* + ID_OUI_FROM_DATABASE=ATEN INTERNATIONAL CO., LTD. + +OUI:001075* + ID_OUI_FROM_DATABASE=Segate Technology LLC + +OUI:001076* + ID_OUI_FROM_DATABASE=EUREM GmbH + +OUI:001077* + ID_OUI_FROM_DATABASE=SAF DRIVE SYSTEMS, LTD. + +OUI:001078* + ID_OUI_FROM_DATABASE=NUERA COMMUNICATIONS, INC. + +OUI:001079* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00107A* + ID_OUI_FROM_DATABASE=AmbiCom, Inc. + +OUI:00107B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00107C* + ID_OUI_FROM_DATABASE=P-COM, INC. + +OUI:00107D* + ID_OUI_FROM_DATABASE=AURORA COMMUNICATIONS, LTD. + +OUI:00107E* + ID_OUI_FROM_DATABASE=BACHMANN ELECTRONIC GmbH + +OUI:00107F* + ID_OUI_FROM_DATABASE=CRESTRON ELECTRONICS, INC. + +OUI:001080* + ID_OUI_FROM_DATABASE=METAWAVE COMMUNICATIONS + +OUI:001081* + ID_OUI_FROM_DATABASE=DPS, INC. + +OUI:001082* + ID_OUI_FROM_DATABASE=JNA TELECOMMUNICATIONS LIMITED + +OUI:001083* + ID_OUI_FROM_DATABASE=HEWLETT-PACKARD COMPANY + +OUI:001084* + ID_OUI_FROM_DATABASE=K-BOT COMMUNICATIONS + +OUI:001085* + ID_OUI_FROM_DATABASE=POLARIS COMMUNICATIONS, INC. + +OUI:001086* + ID_OUI_FROM_DATABASE=ATTO Technology, Inc. + +OUI:001087* + ID_OUI_FROM_DATABASE=Xstreamis PLC + +OUI:001088* + ID_OUI_FROM_DATABASE=AMERICAN NETWORKS INC. + +OUI:001089* + ID_OUI_FROM_DATABASE=WebSonic + +OUI:00108A* + ID_OUI_FROM_DATABASE=TeraLogic, Inc. + +OUI:00108B* + ID_OUI_FROM_DATABASE=LASERANIMATION SOLLINGER GmbH + +OUI:00108C* + ID_OUI_FROM_DATABASE=FUJITSU TELECOMMUNICATIONS EUROPE, LTD. + +OUI:00108D* + ID_OUI_FROM_DATABASE=Johnson Controls, Inc. + +OUI:00108E* + ID_OUI_FROM_DATABASE=HUGH SYMONS CONCEPT Technologies Ltd. + +OUI:00108F* + ID_OUI_FROM_DATABASE=RAPTOR SYSTEMS + +OUI:001090* + ID_OUI_FROM_DATABASE=CIMETRICS, INC. + +OUI:001091* + ID_OUI_FROM_DATABASE=NO WIRES NEEDED BV + +OUI:001092* + ID_OUI_FROM_DATABASE=NETCORE INC. + +OUI:001093* + ID_OUI_FROM_DATABASE=CMS COMPUTERS, LTD. + +OUI:001094* + ID_OUI_FROM_DATABASE=Performance Analysis Broadband, Spirent plc + +OUI:001095* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:001096* + ID_OUI_FROM_DATABASE=TRACEWELL SYSTEMS, INC. + +OUI:001097* + ID_OUI_FROM_DATABASE=WinNet Metropolitan Communications Systems, Inc. + +OUI:001098* + ID_OUI_FROM_DATABASE=STARNET TECHNOLOGIES, INC. + +OUI:001099* + ID_OUI_FROM_DATABASE=InnoMedia, Inc. + +OUI:00109A* + ID_OUI_FROM_DATABASE=NETLINE + +OUI:00109B* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:00109C* + ID_OUI_FROM_DATABASE=M-SYSTEM CO., LTD. + +OUI:00109D* + ID_OUI_FROM_DATABASE=CLARINET SYSTEMS, INC. + +OUI:00109E* + ID_OUI_FROM_DATABASE=AWARE, INC. + +OUI:00109F* + ID_OUI_FROM_DATABASE=PAVO, INC. + +OUI:0010A0* + ID_OUI_FROM_DATABASE=INNOVEX TECHNOLOGIES, INC. + +OUI:0010A1* + ID_OUI_FROM_DATABASE=KENDIN SEMICONDUCTOR, INC. + +OUI:0010A2* + ID_OUI_FROM_DATABASE=TNS + +OUI:0010A3* + ID_OUI_FROM_DATABASE=OMNITRONIX, INC. + +OUI:0010A4* + ID_OUI_FROM_DATABASE=XIRCOM + +OUI:0010A5* + ID_OUI_FROM_DATABASE=OXFORD INSTRUMENTS + +OUI:0010A6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0010A7* + ID_OUI_FROM_DATABASE=UNEX TECHNOLOGY CORPORATION + +OUI:0010A8* + ID_OUI_FROM_DATABASE=RELIANCE COMPUTER CORP. + +OUI:0010A9* + ID_OUI_FROM_DATABASE=ADHOC TECHNOLOGIES + +OUI:0010AA* + ID_OUI_FROM_DATABASE=MEDIA4, INC. + +OUI:0010AB* + ID_OUI_FROM_DATABASE=KOITO ELECTRIC INDUSTRIES, LTD. + +OUI:0010AC* + ID_OUI_FROM_DATABASE=IMCI TECHNOLOGIES + +OUI:0010AD* + ID_OUI_FROM_DATABASE=SOFTRONICS USB, INC. + +OUI:0010AE* + ID_OUI_FROM_DATABASE=SHINKO ELECTRIC INDUSTRIES CO. + +OUI:0010AF* + ID_OUI_FROM_DATABASE=TAC SYSTEMS, INC. + +OUI:0010B0* + ID_OUI_FROM_DATABASE=MERIDIAN TECHNOLOGY CORP. + +OUI:0010B1* + ID_OUI_FROM_DATABASE=FOR-A CO., LTD. + +OUI:0010B2* + ID_OUI_FROM_DATABASE=COACTIVE AESTHETICS + +OUI:0010B3* + ID_OUI_FROM_DATABASE=NOKIA MULTIMEDIA TERMINALS + +OUI:0010B4* + ID_OUI_FROM_DATABASE=ATMOSPHERE NETWORKS + +OUI:0010B5* + ID_OUI_FROM_DATABASE=ACCTON TECHNOLOGY CORPORATION + +OUI:0010B6* + ID_OUI_FROM_DATABASE=ENTRATA COMMUNICATIONS CORP. + +OUI:0010B7* + ID_OUI_FROM_DATABASE=COYOTE TECHNOLOGIES, LLC + +OUI:0010B8* + ID_OUI_FROM_DATABASE=ISHIGAKI COMPUTER SYSTEM CO. + +OUI:0010B9* + ID_OUI_FROM_DATABASE=MAXTOR CORP. + +OUI:0010BA* + ID_OUI_FROM_DATABASE=MARTINHO-DAVIS SYSTEMS, INC. + +OUI:0010BB* + ID_OUI_FROM_DATABASE=DATA & INFORMATION TECHNOLOGY + +OUI:0010BC* + ID_OUI_FROM_DATABASE=Aastra Telecom + +OUI:0010BD* + ID_OUI_FROM_DATABASE=THE TELECOMMUNICATION TECHNOLOGY COMMITTEE (TTC) + +OUI:0010BE* + ID_OUI_FROM_DATABASE=MARCH NETWORKS CORPORATION + +OUI:0010BF* + ID_OUI_FROM_DATABASE=InterAir Wireless + +OUI:0010C0* + ID_OUI_FROM_DATABASE=ARMA, Inc. + +OUI:0010C1* + ID_OUI_FROM_DATABASE=OI ELECTRIC CO., LTD. + +OUI:0010C2* + ID_OUI_FROM_DATABASE=WILLNET, INC. + +OUI:0010C3* + ID_OUI_FROM_DATABASE=CSI-CONTROL SYSTEMS + +OUI:0010C4* + ID_OUI_FROM_DATABASE=MEDIA LINKS CO., LTD. + +OUI:0010C5* + ID_OUI_FROM_DATABASE=PROTOCOL TECHNOLOGIES, INC. + +OUI:0010C6* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:0010C7* + ID_OUI_FROM_DATABASE=DATA TRANSMISSION NETWORK + +OUI:0010C8* + ID_OUI_FROM_DATABASE=COMMUNICATIONS ELECTRONICS SECURITY GROUP + +OUI:0010C9* + ID_OUI_FROM_DATABASE=MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO. + +OUI:0010CA* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:0010CB* + ID_OUI_FROM_DATABASE=FACIT K.K. + +OUI:0010CC* + ID_OUI_FROM_DATABASE=CLP COMPUTER LOGISTIK PLANUNG GmbH + +OUI:0010CD* + ID_OUI_FROM_DATABASE=INTERFACE CONCEPT + +OUI:0010CE* + ID_OUI_FROM_DATABASE=VOLAMP, LTD. + +OUI:0010CF* + ID_OUI_FROM_DATABASE=FIBERLANE COMMUNICATIONS + +OUI:0010D0* + ID_OUI_FROM_DATABASE=WITCOM, LTD. + +OUI:0010D1* + ID_OUI_FROM_DATABASE=Top Layer Networks, Inc. + +OUI:0010D2* + ID_OUI_FROM_DATABASE=NITTO TSUSHINKI CO., LTD + +OUI:0010D3* + ID_OUI_FROM_DATABASE=GRIPS ELECTRONIC GMBH + +OUI:0010D4* + ID_OUI_FROM_DATABASE=STORAGE COMPUTER CORPORATION + +OUI:0010D5* + ID_OUI_FROM_DATABASE=IMASDE CANARIAS, S.A. + +OUI:0010D6* + ID_OUI_FROM_DATABASE=ITT - A/CD + +OUI:0010D7* + ID_OUI_FROM_DATABASE=ARGOSY RESEARCH INC. + +OUI:0010D8* + ID_OUI_FROM_DATABASE=CALISTA + +OUI:0010D9* + ID_OUI_FROM_DATABASE=IBM JAPAN, FUJISAWA MT+D + +OUI:0010DA* + ID_OUI_FROM_DATABASE=Kollmorgen Corp + +OUI:0010DB* + ID_OUI_FROM_DATABASE=Juniper Networks, Inc. + +OUI:0010DC* + ID_OUI_FROM_DATABASE=MICRO-STAR INTERNATIONAL CO., LTD. + +OUI:0010DD* + ID_OUI_FROM_DATABASE=ENABLE SEMICONDUCTOR, INC. + +OUI:0010DE* + ID_OUI_FROM_DATABASE=INTERNATIONAL DATACASTING CORPORATION + +OUI:0010DF* + ID_OUI_FROM_DATABASE=RISE COMPUTER INC. + +OUI:0010E0* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:0010E1* + ID_OUI_FROM_DATABASE=S.I. TECH, INC. + +OUI:0010E2* + ID_OUI_FROM_DATABASE=ArrayComm, Inc. + +OUI:0010E3* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0010E4* + ID_OUI_FROM_DATABASE=NSI CORPORATION + +OUI:0010E5* + ID_OUI_FROM_DATABASE=SOLECTRON TEXAS + +OUI:0010E6* + ID_OUI_FROM_DATABASE=APPLIED INTELLIGENT SYSTEMS, INC. + +OUI:0010E7* + ID_OUI_FROM_DATABASE=BreezeCom + +OUI:0010E8* + ID_OUI_FROM_DATABASE=TELOCITY, INCORPORATED + +OUI:0010E9* + ID_OUI_FROM_DATABASE=RAIDTEC LTD. + +OUI:0010EA* + ID_OUI_FROM_DATABASE=ADEPT TECHNOLOGY + +OUI:0010EB* + ID_OUI_FROM_DATABASE=SELSIUS SYSTEMS, INC. + +OUI:0010EC* + ID_OUI_FROM_DATABASE=RPCG, LLC + +OUI:0010ED* + ID_OUI_FROM_DATABASE=SUNDANCE TECHNOLOGY, INC. + +OUI:0010EE* + ID_OUI_FROM_DATABASE=CTI PRODUCTS, INC. + +OUI:0010EF* + ID_OUI_FROM_DATABASE=DBTEL INCORPORATED + +OUI:0010F0* + ID_OUI_FROM_DATABASE=RITTAL-WERK RUDOLF LOH GmbH & Co. + +OUI:0010F1* + ID_OUI_FROM_DATABASE=I-O CORPORATION + +OUI:0010F2* + ID_OUI_FROM_DATABASE=ANTEC + +OUI:0010F3* + ID_OUI_FROM_DATABASE=Nexcom International Co., Ltd. + +OUI:0010F4* + ID_OUI_FROM_DATABASE=Vertical Communications + +OUI:0010F5* + ID_OUI_FROM_DATABASE=AMHERST SYSTEMS, INC. + +OUI:0010F6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0010F7* + ID_OUI_FROM_DATABASE=IRIICHI TECHNOLOGIES Inc. + +OUI:0010F8* + ID_OUI_FROM_DATABASE=TEXIO TECHNOLOGY CORPORATION + +OUI:0010F9* + ID_OUI_FROM_DATABASE=UNIQUE SYSTEMS, INC. + +OUI:0010FA* + ID_OUI_FROM_DATABASE=Apple + +OUI:0010FB* + ID_OUI_FROM_DATABASE=ZIDA TECHNOLOGIES LIMITED + +OUI:0010FC* + ID_OUI_FROM_DATABASE=BROADBAND NETWORKS, INC. + +OUI:0010FD* + ID_OUI_FROM_DATABASE=COCOM A/S + +OUI:0010FE* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:0010FF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001100* + ID_OUI_FROM_DATABASE=Schneider Electric + +OUI:001101* + ID_OUI_FROM_DATABASE=CET Technologies Pte Ltd + +OUI:001102* + ID_OUI_FROM_DATABASE=Aurora Multimedia Corp. + +OUI:001103* + ID_OUI_FROM_DATABASE=kawamura electric inc. + +OUI:001104* + ID_OUI_FROM_DATABASE=TELEXY + +OUI:001105* + ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd. + +OUI:001106* + ID_OUI_FROM_DATABASE=Siemens NV (Belgium) + +OUI:001107* + ID_OUI_FROM_DATABASE=RGB Networks Inc. + +OUI:001108* + ID_OUI_FROM_DATABASE=Orbital Data Corporation + +OUI:001109* + ID_OUI_FROM_DATABASE=Micro-Star International + +OUI:00110A* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:00110B* + ID_OUI_FROM_DATABASE=Franklin Technology Systems + +OUI:00110C* + ID_OUI_FROM_DATABASE=Atmark Techno, Inc. + +OUI:00110D* + ID_OUI_FROM_DATABASE=SANBlaze Technology, Inc. + +OUI:00110E* + ID_OUI_FROM_DATABASE=Tsurusaki Sealand Transportation Co. Ltd. + +OUI:00110F* + ID_OUI_FROM_DATABASE=netplat,Inc. + +OUI:001110* + ID_OUI_FROM_DATABASE=Maxanna Technology Co., Ltd. + +OUI:001111* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:001112* + ID_OUI_FROM_DATABASE=Honeywell CMSS + +OUI:001113* + ID_OUI_FROM_DATABASE=Fraunhofer FOKUS + +OUI:001114* + ID_OUI_FROM_DATABASE=EverFocus Electronics Corp. + +OUI:001115* + ID_OUI_FROM_DATABASE=EPIN Technologies, Inc. + +OUI:001116* + ID_OUI_FROM_DATABASE=COTEAU VERT CO., LTD. + +OUI:001117* + ID_OUI_FROM_DATABASE=CESNET + +OUI:001118* + ID_OUI_FROM_DATABASE=BLX IC Design Corp., Ltd. + +OUI:001119* + ID_OUI_FROM_DATABASE=Solteras, Inc. + +OUI:00111A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00111B* + ID_OUI_FROM_DATABASE=Targa Systems Div L-3 Communications Canada + +OUI:00111C* + ID_OUI_FROM_DATABASE=Pleora Technologies Inc. + +OUI:00111D* + ID_OUI_FROM_DATABASE=Hectrix Limited + +OUI:00111E* + ID_OUI_FROM_DATABASE=EPSG (Ethernet Powerlink Standardization Group) + +OUI:00111F* + ID_OUI_FROM_DATABASE=Doremi Labs, Inc. + +OUI:001120* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001121* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001122* + ID_OUI_FROM_DATABASE=CIMSYS Inc + +OUI:001123* + ID_OUI_FROM_DATABASE=Appointech, Inc. + +OUI:001124* + ID_OUI_FROM_DATABASE=Apple + +OUI:001125* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:001126* + ID_OUI_FROM_DATABASE=Venstar Inc. + +OUI:001127* + ID_OUI_FROM_DATABASE=TASI, Inc + +OUI:001128* + ID_OUI_FROM_DATABASE=Streamit + +OUI:001129* + ID_OUI_FROM_DATABASE=Paradise Datacom Ltd. + +OUI:00112A* + ID_OUI_FROM_DATABASE=Niko NV + +OUI:00112B* + ID_OUI_FROM_DATABASE=NetModule AG + +OUI:00112C* + ID_OUI_FROM_DATABASE=IZT GmbH + +OUI:00112D* + ID_OUI_FROM_DATABASE=iPulse Systems + +OUI:00112E* + ID_OUI_FROM_DATABASE=CEICOM + +OUI:00112F* + ID_OUI_FROM_DATABASE=ASUSTek Computer Inc. + +OUI:001130* + ID_OUI_FROM_DATABASE=Allied Telesis (Hong Kong) Ltd. + +OUI:001131* + ID_OUI_FROM_DATABASE=UNATECH. CO.,LTD + +OUI:001132* + ID_OUI_FROM_DATABASE=Synology Incorporated + +OUI:001133* + ID_OUI_FROM_DATABASE=Siemens Austria SIMEA + +OUI:001134* + ID_OUI_FROM_DATABASE=MediaCell, Inc. + +OUI:001135* + ID_OUI_FROM_DATABASE=Grandeye Ltd + +OUI:001136* + ID_OUI_FROM_DATABASE=Goodrich Sensor Systems + +OUI:001137* + ID_OUI_FROM_DATABASE=AICHI ELECTRIC CO., LTD. + +OUI:001138* + ID_OUI_FROM_DATABASE=TAISHIN CO., LTD. + +OUI:001139* + ID_OUI_FROM_DATABASE=STOEBER ANTRIEBSTECHNIK GmbH + Co. KG. + +OUI:00113A* + ID_OUI_FROM_DATABASE=SHINBORAM + +OUI:00113B* + ID_OUI_FROM_DATABASE=Micronet Communications Inc. + +OUI:00113C* + ID_OUI_FROM_DATABASE=Micronas GmbH + +OUI:00113D* + ID_OUI_FROM_DATABASE=KN SOLTEC CO.,LTD. + +OUI:00113E* + ID_OUI_FROM_DATABASE=JL Corporation + +OUI:00113F* + ID_OUI_FROM_DATABASE=Alcatel DI + +OUI:001140* + ID_OUI_FROM_DATABASE=Nanometrics Inc. + +OUI:001141* + ID_OUI_FROM_DATABASE=GoodMan Corporation + +OUI:001142* + ID_OUI_FROM_DATABASE=e-SMARTCOM INC. + +OUI:001143* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:001144* + ID_OUI_FROM_DATABASE=Assurance Technology Corp + +OUI:001145* + ID_OUI_FROM_DATABASE=ValuePoint Networks + +OUI:001146* + ID_OUI_FROM_DATABASE=Telecard-Pribor Ltd + +OUI:001147* + ID_OUI_FROM_DATABASE=Secom-Industry co.LTD. + +OUI:001148* + ID_OUI_FROM_DATABASE=Prolon Control Systems + +OUI:001149* + ID_OUI_FROM_DATABASE=Proliphix Inc. + +OUI:00114A* + ID_OUI_FROM_DATABASE=KAYABA INDUSTRY Co,.Ltd. + +OUI:00114B* + ID_OUI_FROM_DATABASE=Francotyp-Postalia GmbH + +OUI:00114C* + ID_OUI_FROM_DATABASE=caffeina applied research ltd. + +OUI:00114D* + ID_OUI_FROM_DATABASE=Atsumi Electric Co.,LTD. + +OUI:00114E* + ID_OUI_FROM_DATABASE=690885 Ontario Inc. + +OUI:00114F* + ID_OUI_FROM_DATABASE=US Digital Television, Inc + +OUI:001150* + ID_OUI_FROM_DATABASE=Belkin Corporation + +OUI:001151* + ID_OUI_FROM_DATABASE=Mykotronx + +OUI:001152* + ID_OUI_FROM_DATABASE=Eidsvoll Electronics AS + +OUI:001153* + ID_OUI_FROM_DATABASE=Trident Tek, Inc. + +OUI:001154* + ID_OUI_FROM_DATABASE=Webpro Technologies Inc. + +OUI:001155* + ID_OUI_FROM_DATABASE=Sevis Systems + +OUI:001156* + ID_OUI_FROM_DATABASE=Pharos Systems NZ + +OUI:001157* + ID_OUI_FROM_DATABASE=OF Networks Co., Ltd. + +OUI:001158* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:001159* + ID_OUI_FROM_DATABASE=MATISSE NETWORKS INC + +OUI:00115A* + ID_OUI_FROM_DATABASE=Ivoclar Vivadent AG + +OUI:00115B* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) + +OUI:00115C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00115D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00115E* + ID_OUI_FROM_DATABASE=ProMinent Dosiertechnik GmbH + +OUI:00115F* + ID_OUI_FROM_DATABASE=ITX Security Co., Ltd. + +OUI:001160* + ID_OUI_FROM_DATABASE=ARTDIO Company Co., LTD + +OUI:001161* + ID_OUI_FROM_DATABASE=NetStreams, LLC + +OUI:001162* + ID_OUI_FROM_DATABASE=STAR MICRONICS CO.,LTD. + +OUI:001163* + ID_OUI_FROM_DATABASE=SYSTEM SPA DEPT. ELECTRONICS + +OUI:001164* + ID_OUI_FROM_DATABASE=ACARD Technology Corp. + +OUI:001165* + ID_OUI_FROM_DATABASE=Znyx Networks + +OUI:001166* + ID_OUI_FROM_DATABASE=Taelim Electronics Co., Ltd. + +OUI:001167* + ID_OUI_FROM_DATABASE=Integrated System Solution Corp. + +OUI:001168* + ID_OUI_FROM_DATABASE=HomeLogic LLC + +OUI:001169* + ID_OUI_FROM_DATABASE=EMS Satcom + +OUI:00116A* + ID_OUI_FROM_DATABASE=Domo Ltd + +OUI:00116B* + ID_OUI_FROM_DATABASE=Digital Data Communications Asia Co.,Ltd + +OUI:00116C* + ID_OUI_FROM_DATABASE=Nanwang Multimedia Inc.,Ltd + +OUI:00116D* + ID_OUI_FROM_DATABASE=American Time and Signal + +OUI:00116E* + ID_OUI_FROM_DATABASE=PePLink Ltd. + +OUI:00116F* + ID_OUI_FROM_DATABASE=Netforyou Co., LTD. + +OUI:001170* + ID_OUI_FROM_DATABASE=GSC SRL + +OUI:001171* + ID_OUI_FROM_DATABASE=DEXTER Communications, Inc. + +OUI:001172* + ID_OUI_FROM_DATABASE=COTRON CORPORATION + +OUI:001173* + ID_OUI_FROM_DATABASE=SMART Storage Systems + +OUI:001174* + ID_OUI_FROM_DATABASE=Wibhu Technologies, Inc. + +OUI:001175* + ID_OUI_FROM_DATABASE=PathScale, Inc. + +OUI:001176* + ID_OUI_FROM_DATABASE=Intellambda Systems, Inc. + +OUI:001177* + ID_OUI_FROM_DATABASE=Coaxial Networks, Inc. + +OUI:001178* + ID_OUI_FROM_DATABASE=Chiron Technology Ltd + +OUI:001179* + ID_OUI_FROM_DATABASE=Singular Technology Co. Ltd. + +OUI:00117A* + ID_OUI_FROM_DATABASE=Singim International Corp. + +OUI:00117B* + ID_OUI_FROM_DATABASE=Büchi Labortechnik AG + +OUI:00117C* + ID_OUI_FROM_DATABASE=e-zy.net + +OUI:00117D* + ID_OUI_FROM_DATABASE=ZMD America, Inc. + +OUI:00117E* + ID_OUI_FROM_DATABASE=Progeny, A division of Midmark Corp + +OUI:00117F* + ID_OUI_FROM_DATABASE=Neotune Information Technology Corporation,.LTD + +OUI:001180* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001181* + ID_OUI_FROM_DATABASE=InterEnergy Co.Ltd, + +OUI:001182* + ID_OUI_FROM_DATABASE=IMI Norgren Ltd + +OUI:001183* + ID_OUI_FROM_DATABASE=Datalogic ADC, Inc. + +OUI:001184* + ID_OUI_FROM_DATABASE=Humo Laboratory,Ltd. + +OUI:001185* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001186* + ID_OUI_FROM_DATABASE=Prime Systems, Inc. + +OUI:001187* + ID_OUI_FROM_DATABASE=Category Solutions, Inc + +OUI:001188* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:001189* + ID_OUI_FROM_DATABASE=Aerotech Inc + +OUI:00118A* + ID_OUI_FROM_DATABASE=Viewtran Technology Limited + +OUI:00118B* + ID_OUI_FROM_DATABASE=Alcatel-Lucent, Enterprise Business Group + +OUI:00118C* + ID_OUI_FROM_DATABASE=Missouri Department of Transportation + +OUI:00118D* + ID_OUI_FROM_DATABASE=Hanchang System Corp. + +OUI:00118E* + ID_OUI_FROM_DATABASE=Halytech Mace + +OUI:00118F* + ID_OUI_FROM_DATABASE=EUTECH INSTRUMENTS PTE. LTD. + +OUI:001190* + ID_OUI_FROM_DATABASE=Digital Design Corporation + +OUI:001191* + ID_OUI_FROM_DATABASE=CTS-Clima Temperatur Systeme GmbH + +OUI:001192* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001193* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001194* + ID_OUI_FROM_DATABASE=Chi Mei Communication Systems, Inc. + +OUI:001195* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:001196* + ID_OUI_FROM_DATABASE=Actuality Systems, Inc. + +OUI:001197* + ID_OUI_FROM_DATABASE=Monitoring Technologies Limited + +OUI:001198* + ID_OUI_FROM_DATABASE=Prism Media Products Limited + +OUI:001199* + ID_OUI_FROM_DATABASE=2wcom Systems GmbH + +OUI:00119A* + ID_OUI_FROM_DATABASE=Alkeria srl + +OUI:00119B* + ID_OUI_FROM_DATABASE=Telesynergy Research Inc. + +OUI:00119C* + ID_OUI_FROM_DATABASE=EP&T Energy + +OUI:00119D* + ID_OUI_FROM_DATABASE=Diginfo Technology Corporation + +OUI:00119E* + ID_OUI_FROM_DATABASE=Solectron Brazil + +OUI:00119F* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0011A0* + ID_OUI_FROM_DATABASE=Vtech Engineering Canada Ltd + +OUI:0011A1* + ID_OUI_FROM_DATABASE=VISION NETWARE CO.,LTD + +OUI:0011A2* + ID_OUI_FROM_DATABASE=Manufacturing Technology Inc + +OUI:0011A3* + ID_OUI_FROM_DATABASE=LanReady Technologies Inc. + +OUI:0011A4* + ID_OUI_FROM_DATABASE=JStream Technologies Inc. + +OUI:0011A5* + ID_OUI_FROM_DATABASE=Fortuna Electronic Corp. + +OUI:0011A6* + ID_OUI_FROM_DATABASE=Sypixx Networks + +OUI:0011A7* + ID_OUI_FROM_DATABASE=Infilco Degremont Inc. + +OUI:0011A8* + ID_OUI_FROM_DATABASE=Quest Technologies + +OUI:0011A9* + ID_OUI_FROM_DATABASE=MOIMSTONE Co., LTD + +OUI:0011AA* + ID_OUI_FROM_DATABASE=Uniclass Technology, Co., LTD + +OUI:0011AB* + ID_OUI_FROM_DATABASE=TRUSTABLE TECHNOLOGY CO.,LTD. + +OUI:0011AC* + ID_OUI_FROM_DATABASE=Simtec Electronics + +OUI:0011AD* + ID_OUI_FROM_DATABASE=Shanghai Ruijie Technology + +OUI:0011AE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0011AF* + ID_OUI_FROM_DATABASE=Medialink-i,Inc + +OUI:0011B0* + ID_OUI_FROM_DATABASE=Fortelink Inc. + +OUI:0011B1* + ID_OUI_FROM_DATABASE=BlueExpert Technology Corp. + +OUI:0011B2* + ID_OUI_FROM_DATABASE=2001 Technology Inc. + +OUI:0011B3* + ID_OUI_FROM_DATABASE=YOSHIMIYA CO.,LTD. + +OUI:0011B4* + ID_OUI_FROM_DATABASE=Westermo Teleindustri AB + +OUI:0011B5* + ID_OUI_FROM_DATABASE=Shenzhen Powercom Co.,Ltd + +OUI:0011B6* + ID_OUI_FROM_DATABASE=Open Systems International + +OUI:0011B7* + ID_OUI_FROM_DATABASE=Octalix B.V. + +OUI:0011B8* + ID_OUI_FROM_DATABASE=Liebherr - Elektronik GmbH + +OUI:0011B9* + ID_OUI_FROM_DATABASE=Inner Range Pty. Ltd. + +OUI:0011BA* + ID_OUI_FROM_DATABASE=Elexol Pty Ltd + +OUI:0011BB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0011BC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0011BD* + ID_OUI_FROM_DATABASE=Bombardier Transportation + +OUI:0011BE* + ID_OUI_FROM_DATABASE=AGP Telecom Co. Ltd + +OUI:0011BF* + ID_OUI_FROM_DATABASE=AESYS S.p.A. + +OUI:0011C0* + ID_OUI_FROM_DATABASE=Aday Technology Inc + +OUI:0011C1* + ID_OUI_FROM_DATABASE=4P MOBILE DATA PROCESSING + +OUI:0011C2* + ID_OUI_FROM_DATABASE=United Fiber Optic Communication + +OUI:0011C3* + ID_OUI_FROM_DATABASE=Transceiving System Technology Corporation + +OUI:0011C4* + ID_OUI_FROM_DATABASE=Terminales de Telecomunicacion Terrestre, S.L. + +OUI:0011C5* + ID_OUI_FROM_DATABASE=TEN Technology + +OUI:0011C6* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:0011C7* + ID_OUI_FROM_DATABASE=Raymarine UK Ltd + +OUI:0011C8* + ID_OUI_FROM_DATABASE=Powercom Co., Ltd. + +OUI:0011C9* + ID_OUI_FROM_DATABASE=MTT Corporation + +OUI:0011CA* + ID_OUI_FROM_DATABASE=Long Range Systems, Inc. + +OUI:0011CB* + ID_OUI_FROM_DATABASE=Jacobsons AB + +OUI:0011CC* + ID_OUI_FROM_DATABASE=Guangzhou Jinpeng Group Co.,Ltd. + +OUI:0011CD* + ID_OUI_FROM_DATABASE=Axsun Technologies + +OUI:0011CE* + ID_OUI_FROM_DATABASE=Ubisense Limited + +OUI:0011CF* + ID_OUI_FROM_DATABASE=Thrane & Thrane A/S + +OUI:0011D0* + ID_OUI_FROM_DATABASE=Tandberg Data ASA + +OUI:0011D1* + ID_OUI_FROM_DATABASE=Soft Imaging System GmbH + +OUI:0011D2* + ID_OUI_FROM_DATABASE=Perception Digital Ltd + +OUI:0011D3* + ID_OUI_FROM_DATABASE=NextGenTel Holding ASA + +OUI:0011D4* + ID_OUI_FROM_DATABASE=NetEnrich, Inc + +OUI:0011D5* + ID_OUI_FROM_DATABASE=Hangzhou Sunyard System Engineering Co.,Ltd. + +OUI:0011D6* + ID_OUI_FROM_DATABASE=HandEra, Inc. + +OUI:0011D7* + ID_OUI_FROM_DATABASE=eWerks Inc + +OUI:0011D8* + ID_OUI_FROM_DATABASE=ASUSTek Computer Inc. + +OUI:0011D9* + ID_OUI_FROM_DATABASE=TiVo + +OUI:0011DA* + ID_OUI_FROM_DATABASE=Vivaas Technology Inc. + +OUI:0011DB* + ID_OUI_FROM_DATABASE=Land-Cellular Corporation + +OUI:0011DC* + ID_OUI_FROM_DATABASE=Glunz & Jensen + +OUI:0011DD* + ID_OUI_FROM_DATABASE=FROMUS TEC. Co., Ltd. + +OUI:0011DE* + ID_OUI_FROM_DATABASE=EURILOGIC + +OUI:0011DF* + ID_OUI_FROM_DATABASE=Current Energy + +OUI:0011E0* + ID_OUI_FROM_DATABASE=U-MEDIA Communications, Inc. + +OUI:0011E1* + ID_OUI_FROM_DATABASE=Arcelik A.S + +OUI:0011E2* + ID_OUI_FROM_DATABASE=Hua Jung Components Co., Ltd. + +OUI:0011E3* + ID_OUI_FROM_DATABASE=Thomson, Inc. + +OUI:0011E4* + ID_OUI_FROM_DATABASE=Danelec Electronics A/S + +OUI:0011E5* + ID_OUI_FROM_DATABASE=KCodes Corporation + +OUI:0011E6* + ID_OUI_FROM_DATABASE=Scientific Atlanta + +OUI:0011E7* + ID_OUI_FROM_DATABASE=WORLDSAT - Texas de France + +OUI:0011E8* + ID_OUI_FROM_DATABASE=Tixi.Com + +OUI:0011E9* + ID_OUI_FROM_DATABASE=STARNEX CO., LTD. + +OUI:0011EA* + ID_OUI_FROM_DATABASE=IWICS Inc. + +OUI:0011EB* + ID_OUI_FROM_DATABASE=Innovative Integration + +OUI:0011EC* + ID_OUI_FROM_DATABASE=AVIX INC. + +OUI:0011ED* + ID_OUI_FROM_DATABASE=802 Global + +OUI:0011EE* + ID_OUI_FROM_DATABASE=Estari, Inc. + +OUI:0011EF* + ID_OUI_FROM_DATABASE=Conitec Datensysteme GmbH + +OUI:0011F0* + ID_OUI_FROM_DATABASE=Wideful Limited + +OUI:0011F1* + ID_OUI_FROM_DATABASE=QinetiQ Ltd + +OUI:0011F2* + ID_OUI_FROM_DATABASE=Institute of Network Technologies + +OUI:0011F3* + ID_OUI_FROM_DATABASE=NeoMedia Europe AG + +OUI:0011F4* + ID_OUI_FROM_DATABASE=woori-net + +OUI:0011F5* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP. + +OUI:0011F6* + ID_OUI_FROM_DATABASE=Asia Pacific Microsystems , Inc. + +OUI:0011F7* + ID_OUI_FROM_DATABASE=Shenzhen Forward Industry Co., Ltd + +OUI:0011F8* + ID_OUI_FROM_DATABASE=AIRAYA Corp + +OUI:0011F9* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0011FA* + ID_OUI_FROM_DATABASE=Rane Corporation + +OUI:0011FB* + ID_OUI_FROM_DATABASE=Heidelberg Engineering GmbH + +OUI:0011FC* + ID_OUI_FROM_DATABASE=HARTING Electric Gmbh & Co.KG + +OUI:0011FD* + ID_OUI_FROM_DATABASE=KORG INC. + +OUI:0011FE* + ID_OUI_FROM_DATABASE=Keiyo System Research, Inc. + +OUI:0011FF* + ID_OUI_FROM_DATABASE=Digitro Tecnologia Ltda + +OUI:001200* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001201* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001202* + ID_OUI_FROM_DATABASE=Decrane Aerospace - Audio International Inc. + +OUI:001203* + ID_OUI_FROM_DATABASE=ActivNetworks + +OUI:001204* + ID_OUI_FROM_DATABASE=u10 Networks, Inc. + +OUI:001205* + ID_OUI_FROM_DATABASE=Terrasat Communications, Inc. + +OUI:001206* + ID_OUI_FROM_DATABASE=iQuest (NZ) Ltd + +OUI:001207* + ID_OUI_FROM_DATABASE=Head Strong International Limited + +OUI:001208* + ID_OUI_FROM_DATABASE=Gantner Instruments GmbH + +OUI:001209* + ID_OUI_FROM_DATABASE=Fastrax Ltd + +OUI:00120A* + ID_OUI_FROM_DATABASE=Emerson Climate Technologies GmbH + +OUI:00120B* + ID_OUI_FROM_DATABASE=Chinasys Technologies Limited + +OUI:00120C* + ID_OUI_FROM_DATABASE=CE-Infosys Pte Ltd + +OUI:00120D* + ID_OUI_FROM_DATABASE=Advanced Telecommunication Technologies, Inc. + +OUI:00120E* + ID_OUI_FROM_DATABASE=AboCom + +OUI:00120F* + ID_OUI_FROM_DATABASE=IEEE 802.3 + +OUI:001210* + ID_OUI_FROM_DATABASE=WideRay Corp + +OUI:001211* + ID_OUI_FROM_DATABASE=Protechna Herbst GmbH & Co. KG + +OUI:001212* + ID_OUI_FROM_DATABASE=PLUS Corporation + +OUI:001213* + ID_OUI_FROM_DATABASE=Metrohm AG + +OUI:001214* + ID_OUI_FROM_DATABASE=Koenig & Bauer AG + +OUI:001215* + ID_OUI_FROM_DATABASE=iStor Networks, Inc. + +OUI:001216* + ID_OUI_FROM_DATABASE=ICP Internet Communication Payment AG + +OUI:001217* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001218* + ID_OUI_FROM_DATABASE=ARUZE Corporation + +OUI:001219* + ID_OUI_FROM_DATABASE=Ahead Communication Systems Inc + +OUI:00121A* + ID_OUI_FROM_DATABASE=Techno Soft Systemnics Inc. + +OUI:00121B* + ID_OUI_FROM_DATABASE=Sound Devices, LLC + +OUI:00121C* + ID_OUI_FROM_DATABASE=PARROT S.A. + +OUI:00121D* + ID_OUI_FROM_DATABASE=Netfabric Corporation + +OUI:00121E* + ID_OUI_FROM_DATABASE=Juniper Networks, Inc. + +OUI:00121F* + ID_OUI_FROM_DATABASE=Harding Instruments + +OUI:001220* + ID_OUI_FROM_DATABASE=Cadco Systems + +OUI:001221* + ID_OUI_FROM_DATABASE=B.Braun Melsungen AG + +OUI:001222* + ID_OUI_FROM_DATABASE=Skardin (UK) Ltd + +OUI:001223* + ID_OUI_FROM_DATABASE=Pixim + +OUI:001224* + ID_OUI_FROM_DATABASE=NexQL Corporation + +OUI:001225* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001226* + ID_OUI_FROM_DATABASE=Japan Direx Corporation + +OUI:001227* + ID_OUI_FROM_DATABASE=Franklin Electric Co., Inc. + +OUI:001228* + ID_OUI_FROM_DATABASE=Data Ltd. + +OUI:001229* + ID_OUI_FROM_DATABASE=BroadEasy Technologies Co.,Ltd + +OUI:00122A* + ID_OUI_FROM_DATABASE=VTech Telecommunications Ltd. + +OUI:00122B* + ID_OUI_FROM_DATABASE=Virbiage Pty Ltd + +OUI:00122C* + ID_OUI_FROM_DATABASE=Soenen Controls N.V. + +OUI:00122D* + ID_OUI_FROM_DATABASE=SiNett Corporation + +OUI:00122E* + ID_OUI_FROM_DATABASE=Signal Technology - AISD + +OUI:00122F* + ID_OUI_FROM_DATABASE=Sanei Electric Inc. + +OUI:001230* + ID_OUI_FROM_DATABASE=Picaso Infocommunication CO., LTD. + +OUI:001231* + ID_OUI_FROM_DATABASE=Motion Control Systems, Inc. + +OUI:001232* + ID_OUI_FROM_DATABASE=LeWiz Communications Inc. + +OUI:001233* + ID_OUI_FROM_DATABASE=JRC TOKKI Co.,Ltd. + +OUI:001234* + ID_OUI_FROM_DATABASE=Camille Bauer + +OUI:001235* + ID_OUI_FROM_DATABASE=Andrew Corporation + +OUI:001236* + ID_OUI_FROM_DATABASE=ConSentry Networks + +OUI:001237* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001238* + ID_OUI_FROM_DATABASE=SetaBox Technology Co., Ltd. + +OUI:001239* + ID_OUI_FROM_DATABASE=S Net Systems Inc. + +OUI:00123A* + ID_OUI_FROM_DATABASE=Posystech Inc., Co. + +OUI:00123B* + ID_OUI_FROM_DATABASE=KeRo Systems ApS + +OUI:00123C* + ID_OUI_FROM_DATABASE=Second Rule LLC + +OUI:00123D* + ID_OUI_FROM_DATABASE=GES + +OUI:00123E* + ID_OUI_FROM_DATABASE=ERUNE technology Co., Ltd. + +OUI:00123F* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:001240* + ID_OUI_FROM_DATABASE=AMOI ELECTRONICS CO.,LTD + +OUI:001241* + ID_OUI_FROM_DATABASE=a2i marketing center + +OUI:001242* + ID_OUI_FROM_DATABASE=Millennial Net + +OUI:001243* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001244* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001245* + ID_OUI_FROM_DATABASE=Zellweger Analytics, Inc. + +OUI:001246* + ID_OUI_FROM_DATABASE=T.O.M TECHNOLOGY INC.. + +OUI:001247* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:001248* + ID_OUI_FROM_DATABASE=EMC Corporation (Kashya) + +OUI:001249* + ID_OUI_FROM_DATABASE=Delta Elettronica S.p.A. + +OUI:00124A* + ID_OUI_FROM_DATABASE=Dedicated Devices, Inc. + +OUI:00124B* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:00124C* + ID_OUI_FROM_DATABASE=BBWM Corporation + +OUI:00124D* + ID_OUI_FROM_DATABASE=Inducon BV + +OUI:00124E* + ID_OUI_FROM_DATABASE=XAC AUTOMATION CORP. + +OUI:00124F* + ID_OUI_FROM_DATABASE=Pentair Thermal Management + +OUI:001250* + ID_OUI_FROM_DATABASE=Tokyo Aircaft Instrument Co., Ltd. + +OUI:001251* + ID_OUI_FROM_DATABASE=SILINK + +OUI:001252* + ID_OUI_FROM_DATABASE=Citronix, LLC + +OUI:001253* + ID_OUI_FROM_DATABASE=AudioDev AB + +OUI:001254* + ID_OUI_FROM_DATABASE=Spectra Technologies Holdings Company Ltd + +OUI:001255* + ID_OUI_FROM_DATABASE=NetEffect Incorporated + +OUI:001256* + ID_OUI_FROM_DATABASE=LG INFORMATION & COMM. + +OUI:001257* + ID_OUI_FROM_DATABASE=LeapComm Communication Technologies Inc. + +OUI:001258* + ID_OUI_FROM_DATABASE=Activis Polska + +OUI:001259* + ID_OUI_FROM_DATABASE=THERMO ELECTRON KARLSRUHE + +OUI:00125A* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:00125B* + ID_OUI_FROM_DATABASE=KAIMEI ELECTRONI + +OUI:00125C* + ID_OUI_FROM_DATABASE=Green Hills Software, Inc. + +OUI:00125D* + ID_OUI_FROM_DATABASE=CyberNet Inc. + +OUI:00125E* + ID_OUI_FROM_DATABASE=CAEN + +OUI:00125F* + ID_OUI_FROM_DATABASE=AWIND Inc. + +OUI:001260* + ID_OUI_FROM_DATABASE=Stanton Magnetics,inc. + +OUI:001261* + ID_OUI_FROM_DATABASE=Adaptix, Inc + +OUI:001262* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001263* + ID_OUI_FROM_DATABASE=Data Voice Technologies GmbH + +OUI:001264* + ID_OUI_FROM_DATABASE=daum electronic gmbh + +OUI:001265* + ID_OUI_FROM_DATABASE=Enerdyne Technologies, Inc. + +OUI:001266* + ID_OUI_FROM_DATABASE=Swisscom Hospitality Services SA + +OUI:001267* + ID_OUI_FROM_DATABASE=Panasonic Corporation + +OUI:001268* + ID_OUI_FROM_DATABASE=IPS d.o.o. + +OUI:001269* + ID_OUI_FROM_DATABASE=Value Electronics + +OUI:00126A* + ID_OUI_FROM_DATABASE=OPTOELECTRONICS Co., Ltd. + +OUI:00126B* + ID_OUI_FROM_DATABASE=Ascalade Communications Limited + +OUI:00126C* + ID_OUI_FROM_DATABASE=Visonic Ltd. + +OUI:00126D* + ID_OUI_FROM_DATABASE=University of California, Berkeley + +OUI:00126E* + ID_OUI_FROM_DATABASE=Seidel Elektronik GmbH Nfg.KG + +OUI:00126F* + ID_OUI_FROM_DATABASE=Rayson Technology Co., Ltd. + +OUI:001270* + ID_OUI_FROM_DATABASE=NGES Denro Systems + +OUI:001271* + ID_OUI_FROM_DATABASE=Measurement Computing Corp + +OUI:001272* + ID_OUI_FROM_DATABASE=Redux Communications Ltd. + +OUI:001273* + ID_OUI_FROM_DATABASE=Stoke Inc + +OUI:001274* + ID_OUI_FROM_DATABASE=NIT lab + +OUI:001275* + ID_OUI_FROM_DATABASE=Sentilla Corporation + +OUI:001276* + ID_OUI_FROM_DATABASE=CG Power Systems Ireland Limited + +OUI:001277* + ID_OUI_FROM_DATABASE=Korenix Technologies Co., Ltd. + +OUI:001278* + ID_OUI_FROM_DATABASE=International Bar Code + +OUI:001279* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:00127A* + ID_OUI_FROM_DATABASE=Sanyu Industry Co.,Ltd. + +OUI:00127B* + ID_OUI_FROM_DATABASE=VIA Networking Technologies, Inc. + +OUI:00127C* + ID_OUI_FROM_DATABASE=SWEGON AB + +OUI:00127D* + ID_OUI_FROM_DATABASE=MobileAria + +OUI:00127E* + ID_OUI_FROM_DATABASE=Digital Lifestyles Group, Inc. + +OUI:00127F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001280* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001281* + ID_OUI_FROM_DATABASE=March Networks S.p.A. + +OUI:001282* + ID_OUI_FROM_DATABASE=Qovia + +OUI:001283* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:001284* + ID_OUI_FROM_DATABASE=Lab33 Srl + +OUI:001285* + ID_OUI_FROM_DATABASE=Gizmondo Europe Ltd + +OUI:001286* + ID_OUI_FROM_DATABASE=ENDEVCO CORP + +OUI:001287* + ID_OUI_FROM_DATABASE=Digital Everywhere Unterhaltungselektronik GmbH + +OUI:001288* + ID_OUI_FROM_DATABASE=2Wire, Inc + +OUI:001289* + ID_OUI_FROM_DATABASE=Advance Sterilization Products + +OUI:00128A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00128B* + ID_OUI_FROM_DATABASE=Sensory Networks Inc + +OUI:00128C* + ID_OUI_FROM_DATABASE=Woodward Governor + +OUI:00128D* + ID_OUI_FROM_DATABASE=STB Datenservice GmbH + +OUI:00128E* + ID_OUI_FROM_DATABASE=Q-Free ASA + +OUI:00128F* + ID_OUI_FROM_DATABASE=Montilio + +OUI:001290* + ID_OUI_FROM_DATABASE=KYOWA Electric & Machinery Corp. + +OUI:001291* + ID_OUI_FROM_DATABASE=KWS Computersysteme GmbH + +OUI:001292* + ID_OUI_FROM_DATABASE=Griffin Technology + +OUI:001293* + ID_OUI_FROM_DATABASE=GE Energy + +OUI:001294* + ID_OUI_FROM_DATABASE=SUMITOMO ELECTRIC DEVICE INNOVATIONS, INC + +OUI:001295* + ID_OUI_FROM_DATABASE=Aiware Inc. + +OUI:001296* + ID_OUI_FROM_DATABASE=Addlogix + +OUI:001297* + ID_OUI_FROM_DATABASE=O2Micro, Inc. + +OUI:001298* + ID_OUI_FROM_DATABASE=MICO ELECTRIC(SHENZHEN) LIMITED + +OUI:001299* + ID_OUI_FROM_DATABASE=Ktech Telecommunications Inc + +OUI:00129A* + ID_OUI_FROM_DATABASE=IRT Electronics Pty Ltd + +OUI:00129B* + ID_OUI_FROM_DATABASE=E2S Electronic Engineering Solutions, S.L. + +OUI:00129C* + ID_OUI_FROM_DATABASE=Yulinet + +OUI:00129D* + ID_OUI_FROM_DATABASE=First International Computer do Brasil + +OUI:00129E* + ID_OUI_FROM_DATABASE=Surf Communications Inc. + +OUI:00129F* + ID_OUI_FROM_DATABASE=RAE Systems + +OUI:0012A0* + ID_OUI_FROM_DATABASE=NeoMeridian Sdn Bhd + +OUI:0012A1* + ID_OUI_FROM_DATABASE=BluePacket Communications Co., Ltd. + +OUI:0012A2* + ID_OUI_FROM_DATABASE=VITA + +OUI:0012A3* + ID_OUI_FROM_DATABASE=Trust International B.V. + +OUI:0012A4* + ID_OUI_FROM_DATABASE=ThingMagic, LLC + +OUI:0012A5* + ID_OUI_FROM_DATABASE=Stargen, Inc. + +OUI:0012A6* + ID_OUI_FROM_DATABASE=Dolby Australia + +OUI:0012A7* + ID_OUI_FROM_DATABASE=ISR TECHNOLOGIES Inc + +OUI:0012A8* + ID_OUI_FROM_DATABASE=intec GmbH + +OUI:0012A9* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:0012AA* + ID_OUI_FROM_DATABASE=IEE, Inc. + +OUI:0012AB* + ID_OUI_FROM_DATABASE=WiLife, Inc. + +OUI:0012AC* + ID_OUI_FROM_DATABASE=ONTIMETEK INC. + +OUI:0012AD* + ID_OUI_FROM_DATABASE=IDS GmbH + +OUI:0012AE* + ID_OUI_FROM_DATABASE=HLS HARD-LINE Solutions Inc. + +OUI:0012AF* + ID_OUI_FROM_DATABASE=ELPRO Technologies + +OUI:0012B0* + ID_OUI_FROM_DATABASE=Efore Oyj (Plc) + +OUI:0012B1* + ID_OUI_FROM_DATABASE=Dai Nippon Printing Co., Ltd + +OUI:0012B2* + ID_OUI_FROM_DATABASE=AVOLITES LTD. + +OUI:0012B3* + ID_OUI_FROM_DATABASE=Advance Wireless Technology Corp. + +OUI:0012B4* + ID_OUI_FROM_DATABASE=Work Microwave GmbH + +OUI:0012B5* + ID_OUI_FROM_DATABASE=Vialta, Inc. + +OUI:0012B6* + ID_OUI_FROM_DATABASE=Santa Barbara Infrared, Inc. + +OUI:0012B7* + ID_OUI_FROM_DATABASE=PTW Freiburg + +OUI:0012B8* + ID_OUI_FROM_DATABASE=G2 Microsystems + +OUI:0012B9* + ID_OUI_FROM_DATABASE=Fusion Digital Technology + +OUI:0012BA* + ID_OUI_FROM_DATABASE=FSI Systems, Inc. + +OUI:0012BB* + ID_OUI_FROM_DATABASE=Telecommunications Industry Association TR-41 Committee + +OUI:0012BC* + ID_OUI_FROM_DATABASE=Echolab LLC + +OUI:0012BD* + ID_OUI_FROM_DATABASE=Avantec Manufacturing Limited + +OUI:0012BE* + ID_OUI_FROM_DATABASE=Astek Corporation + +OUI:0012BF* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:0012C0* + ID_OUI_FROM_DATABASE=HotLava Systems, Inc. + +OUI:0012C1* + ID_OUI_FROM_DATABASE=Check Point Software Technologies + +OUI:0012C2* + ID_OUI_FROM_DATABASE=Apex Electronics Factory + +OUI:0012C3* + ID_OUI_FROM_DATABASE=WIT S.A. + +OUI:0012C4* + ID_OUI_FROM_DATABASE=Viseon, Inc. + +OUI:0012C5* + ID_OUI_FROM_DATABASE=V-Show Technology (China) Co.,Ltd + +OUI:0012C6* + ID_OUI_FROM_DATABASE=TGC America, Inc + +OUI:0012C7* + ID_OUI_FROM_DATABASE=SECURAY Technologies Ltd.Co. + +OUI:0012C8* + ID_OUI_FROM_DATABASE=Perfect tech + +OUI:0012C9* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0012CA* + ID_OUI_FROM_DATABASE=Mechatronic Brick Aps + +OUI:0012CB* + ID_OUI_FROM_DATABASE=CSS Inc. + +OUI:0012CC* + ID_OUI_FROM_DATABASE=Bitatek CO., LTD + +OUI:0012CD* + ID_OUI_FROM_DATABASE=ASEM SpA + +OUI:0012CE* + ID_OUI_FROM_DATABASE=Advanced Cybernetics Group + +OUI:0012CF* + ID_OUI_FROM_DATABASE=Accton Technology Corporation + +OUI:0012D0* + ID_OUI_FROM_DATABASE=Gossen-Metrawatt-GmbH + +OUI:0012D1* + ID_OUI_FROM_DATABASE=Texas Instruments Inc + +OUI:0012D2* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0012D3* + ID_OUI_FROM_DATABASE=Zetta Systems, Inc. + +OUI:0012D4* + ID_OUI_FROM_DATABASE=Princeton Technology, Ltd + +OUI:0012D5* + ID_OUI_FROM_DATABASE=Motion Reality Inc. + +OUI:0012D6* + ID_OUI_FROM_DATABASE=Jiangsu Yitong High-Tech Co.,Ltd + +OUI:0012D7* + ID_OUI_FROM_DATABASE=Invento Networks, Inc. + +OUI:0012D8* + ID_OUI_FROM_DATABASE=International Games System Co., Ltd. + +OUI:0012D9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0012DA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0012DB* + ID_OUI_FROM_DATABASE=ZIEHL industrie-elektronik GmbH + Co KG + +OUI:0012DC* + ID_OUI_FROM_DATABASE=SunCorp Industrial Limited + +OUI:0012DD* + ID_OUI_FROM_DATABASE=Shengqu Information Technology (Shanghai) Co., Ltd. + +OUI:0012DE* + ID_OUI_FROM_DATABASE=Radio Components Sweden AB + +OUI:0012DF* + ID_OUI_FROM_DATABASE=Novomatic AG + +OUI:0012E0* + ID_OUI_FROM_DATABASE=Codan Limited + +OUI:0012E1* + ID_OUI_FROM_DATABASE=Alliant Networks, Inc + +OUI:0012E2* + ID_OUI_FROM_DATABASE=ALAXALA Networks Corporation + +OUI:0012E3* + ID_OUI_FROM_DATABASE=Agat-RT, Ltd. + +OUI:0012E4* + ID_OUI_FROM_DATABASE=ZIEHL industrie-electronik GmbH + Co KG + +OUI:0012E5* + ID_OUI_FROM_DATABASE=Time America, Inc. + +OUI:0012E6* + ID_OUI_FROM_DATABASE=SPECTEC COMPUTER CO., LTD. + +OUI:0012E7* + ID_OUI_FROM_DATABASE=Projectek Networking Electronics Corp. + +OUI:0012E8* + ID_OUI_FROM_DATABASE=Fraunhofer IMS + +OUI:0012E9* + ID_OUI_FROM_DATABASE=Abbey Systems Ltd + +OUI:0012EA* + ID_OUI_FROM_DATABASE=Trane + +OUI:0012EB* + ID_OUI_FROM_DATABASE=PDH Solutions, LLC + +OUI:0012EC* + ID_OUI_FROM_DATABASE=Movacolor b.v. + +OUI:0012ED* + ID_OUI_FROM_DATABASE=AVG Advanced Technologies + +OUI:0012EE* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:0012EF* + ID_OUI_FROM_DATABASE=OneAccess SA + +OUI:0012F0* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0012F1* + ID_OUI_FROM_DATABASE=IFOTEC + +OUI:0012F2* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:0012F3* + ID_OUI_FROM_DATABASE=connectBlue AB + +OUI:0012F4* + ID_OUI_FROM_DATABASE=Belco International Co.,Ltd. + +OUI:0012F5* + ID_OUI_FROM_DATABASE=Imarda New Zealand Limited + +OUI:0012F6* + ID_OUI_FROM_DATABASE=MDK CO.,LTD. + +OUI:0012F7* + ID_OUI_FROM_DATABASE=Xiamen Xinglian Electronics Co., Ltd. + +OUI:0012F8* + ID_OUI_FROM_DATABASE=WNI Resources, LLC + +OUI:0012F9* + ID_OUI_FROM_DATABASE=URYU SEISAKU, LTD. + +OUI:0012FA* + ID_OUI_FROM_DATABASE=THX LTD + +OUI:0012FB* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:0012FC* + ID_OUI_FROM_DATABASE=PLANET System Co.,LTD + +OUI:0012FD* + ID_OUI_FROM_DATABASE=OPTIMUS IC S.A. + +OUI:0012FE* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:0012FF* + ID_OUI_FROM_DATABASE=Lely Industries N.V. + +OUI:001300* + ID_OUI_FROM_DATABASE=IT-FACTORY, INC. + +OUI:001301* + ID_OUI_FROM_DATABASE=IronGate S.L. + +OUI:001302* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001303* + ID_OUI_FROM_DATABASE=GateConnect + +OUI:001304* + ID_OUI_FROM_DATABASE=Flaircomm Technologies Co. LTD + +OUI:001305* + ID_OUI_FROM_DATABASE=Epicom, Inc. + +OUI:001306* + ID_OUI_FROM_DATABASE=Always On Wireless + +OUI:001307* + ID_OUI_FROM_DATABASE=Paravirtual Corporation + +OUI:001308* + ID_OUI_FROM_DATABASE=Nuvera Fuel Cells + +OUI:001309* + ID_OUI_FROM_DATABASE=Ocean Broadband Networks + +OUI:00130A* + ID_OUI_FROM_DATABASE=Nortel + +OUI:00130B* + ID_OUI_FROM_DATABASE=Mextal B.V. + +OUI:00130C* + ID_OUI_FROM_DATABASE=HF System Corporation + +OUI:00130D* + ID_OUI_FROM_DATABASE=GALILEO AVIONICA + +OUI:00130E* + ID_OUI_FROM_DATABASE=Focusrite Audio Engineering Limited + +OUI:00130F* + ID_OUI_FROM_DATABASE=EGEMEN Bilgisayar Muh San ve Tic LTD STI + +OUI:001310* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001311* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:001312* + ID_OUI_FROM_DATABASE=Amedia Networks Inc. + +OUI:001313* + ID_OUI_FROM_DATABASE=GuangZhou Post & Telecom Equipment ltd + +OUI:001314* + ID_OUI_FROM_DATABASE=Asiamajor Inc. + +OUI:001315* + ID_OUI_FROM_DATABASE=SONY Computer Entertainment inc, + +OUI:001316* + ID_OUI_FROM_DATABASE=L-S-B Broadcast Technologies GmbH + +OUI:001317* + ID_OUI_FROM_DATABASE=GN Netcom as + +OUI:001318* + ID_OUI_FROM_DATABASE=DGSTATION Co., Ltd. + +OUI:001319* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00131A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00131B* + ID_OUI_FROM_DATABASE=BeCell Innovations Corp. + +OUI:00131C* + ID_OUI_FROM_DATABASE=LiteTouch, Inc. + +OUI:00131D* + ID_OUI_FROM_DATABASE=Scanvaegt International A/S + +OUI:00131E* + ID_OUI_FROM_DATABASE=Peiker acustic GmbH & Co. KG + +OUI:00131F* + ID_OUI_FROM_DATABASE=NxtPhase T&D, Corp. + +OUI:001320* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001321* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001322* + ID_OUI_FROM_DATABASE=DAQ Electronics, Inc. + +OUI:001323* + ID_OUI_FROM_DATABASE=Cap Co., Ltd. + +OUI:001324* + ID_OUI_FROM_DATABASE=Schneider Electric Ultra Terminal + +OUI:001325* + ID_OUI_FROM_DATABASE=Cortina Systems Inc + +OUI:001326* + ID_OUI_FROM_DATABASE=ECM Systems Ltd + +OUI:001327* + ID_OUI_FROM_DATABASE=Data Acquisitions limited + +OUI:001328* + ID_OUI_FROM_DATABASE=Westech Korea Inc., + +OUI:001329* + ID_OUI_FROM_DATABASE=VSST Co., LTD + +OUI:00132A* + ID_OUI_FROM_DATABASE=Sitronics Telecom Solutions + +OUI:00132B* + ID_OUI_FROM_DATABASE=Phoenix Digital + +OUI:00132C* + ID_OUI_FROM_DATABASE=MAZ Brandenburg GmbH + +OUI:00132D* + ID_OUI_FROM_DATABASE=iWise Communications + +OUI:00132E* + ID_OUI_FROM_DATABASE=ITian Coporation + +OUI:00132F* + ID_OUI_FROM_DATABASE=Interactek + +OUI:001330* + ID_OUI_FROM_DATABASE=EURO PROTECTION SURVEILLANCE + +OUI:001331* + ID_OUI_FROM_DATABASE=CellPoint Connect + +OUI:001332* + ID_OUI_FROM_DATABASE=Beijing Topsec Network Security Technology Co., Ltd. + +OUI:001333* + ID_OUI_FROM_DATABASE=BaudTec Corporation + +OUI:001334* + ID_OUI_FROM_DATABASE=Arkados, Inc. + +OUI:001335* + ID_OUI_FROM_DATABASE=VS Industry Berhad + +OUI:001336* + ID_OUI_FROM_DATABASE=Tianjin 712 Communication Broadcasting co., ltd. + +OUI:001337* + ID_OUI_FROM_DATABASE=Orient Power Home Network Ltd. + +OUI:001338* + ID_OUI_FROM_DATABASE=FRESENIUS-VIAL + +OUI:001339* + ID_OUI_FROM_DATABASE=CCV Deutschland GmbH + +OUI:00133A* + ID_OUI_FROM_DATABASE=VadaTech Inc. + +OUI:00133B* + ID_OUI_FROM_DATABASE=Speed Dragon Multimedia Limited + +OUI:00133C* + ID_OUI_FROM_DATABASE=QUINTRON SYSTEMS INC. + +OUI:00133D* + ID_OUI_FROM_DATABASE=Micro Memory Curtiss Wright Co + +OUI:00133E* + ID_OUI_FROM_DATABASE=MetaSwitch + +OUI:00133F* + ID_OUI_FROM_DATABASE=Eppendorf Instrumente GmbH + +OUI:001340* + ID_OUI_FROM_DATABASE=AD.EL s.r.l. + +OUI:001341* + ID_OUI_FROM_DATABASE=Shandong New Beiyang Information Technology Co.,Ltd + +OUI:001342* + ID_OUI_FROM_DATABASE=Vision Research, Inc. + +OUI:001343* + ID_OUI_FROM_DATABASE=Matsushita Electronic Components (Europe) GmbH + +OUI:001344* + ID_OUI_FROM_DATABASE=Fargo Electronics Inc. + +OUI:001345* + ID_OUI_FROM_DATABASE=Eaton Corporation + +OUI:001346* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:001347* + ID_OUI_FROM_DATABASE=BlueTree Wireless Data Inc. + +OUI:001348* + ID_OUI_FROM_DATABASE=Artila Electronics Co., Ltd. + +OUI:001349* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:00134A* + ID_OUI_FROM_DATABASE=Engim, Inc. + +OUI:00134B* + ID_OUI_FROM_DATABASE=ToGoldenNet Technology Inc. + +OUI:00134C* + ID_OUI_FROM_DATABASE=YDT Technology International + +OUI:00134D* + ID_OUI_FROM_DATABASE=Inepro BV + +OUI:00134E* + ID_OUI_FROM_DATABASE=Valox Systems, Inc. + +OUI:00134F* + ID_OUI_FROM_DATABASE=Tranzeo Wireless Technologies Inc. + +OUI:001350* + ID_OUI_FROM_DATABASE=Silver Spring Networks, Inc + +OUI:001351* + ID_OUI_FROM_DATABASE=Niles Audio Corporation + +OUI:001352* + ID_OUI_FROM_DATABASE=Naztec, Inc. + +OUI:001353* + ID_OUI_FROM_DATABASE=HYDAC Filtertechnik GMBH + +OUI:001354* + ID_OUI_FROM_DATABASE=Zcomax Technologies, Inc. + +OUI:001355* + ID_OUI_FROM_DATABASE=TOMEN Cyber-business Solutions, Inc. + +OUI:001356* + ID_OUI_FROM_DATABASE=FLIR Radiation Inc + +OUI:001357* + ID_OUI_FROM_DATABASE=Soyal Technology Co., Ltd. + +OUI:001358* + ID_OUI_FROM_DATABASE=Realm Systems, Inc. + +OUI:001359* + ID_OUI_FROM_DATABASE=ProTelevision Technologies A/S + +OUI:00135A* + ID_OUI_FROM_DATABASE=Project T&E Limited + +OUI:00135B* + ID_OUI_FROM_DATABASE=PanelLink Cinema, LLC + +OUI:00135C* + ID_OUI_FROM_DATABASE=OnSite Systems, Inc. + +OUI:00135D* + ID_OUI_FROM_DATABASE=NTTPC Communications, Inc. + +OUI:00135E* + ID_OUI_FROM_DATABASE=EAB/RWI/K + +OUI:00135F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001360* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001361* + ID_OUI_FROM_DATABASE=Biospace Co., Ltd. + +OUI:001362* + ID_OUI_FROM_DATABASE=ShinHeung Precision Co., Ltd. + +OUI:001363* + ID_OUI_FROM_DATABASE=Verascape, Inc. + +OUI:001364* + ID_OUI_FROM_DATABASE=Paradigm Technology Inc.. + +OUI:001365* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001366* + ID_OUI_FROM_DATABASE=Neturity Technologies Inc. + +OUI:001367* + ID_OUI_FROM_DATABASE=Narayon. Co., Ltd. + +OUI:001368* + ID_OUI_FROM_DATABASE=Saab Danmark A/S + +OUI:001369* + ID_OUI_FROM_DATABASE=Honda Electron Co., LED. + +OUI:00136A* + ID_OUI_FROM_DATABASE=Hach Lange Sarl + +OUI:00136B* + ID_OUI_FROM_DATABASE=E-TEC + +OUI:00136C* + ID_OUI_FROM_DATABASE=TomTom + +OUI:00136D* + ID_OUI_FROM_DATABASE=Tentaculus AB + +OUI:00136E* + ID_OUI_FROM_DATABASE=Techmetro Corp. + +OUI:00136F* + ID_OUI_FROM_DATABASE=PacketMotion, Inc. + +OUI:001370* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001371* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001372* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:001373* + ID_OUI_FROM_DATABASE=BLwave Electronics Co., Ltd + +OUI:001374* + ID_OUI_FROM_DATABASE=Atheros Communications, Inc. + +OUI:001375* + ID_OUI_FROM_DATABASE=American Security Products Co. + +OUI:001376* + ID_OUI_FROM_DATABASE=Tabor Electronics Ltd. + +OUI:001377* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:001378* + ID_OUI_FROM_DATABASE=Qsan Technology, Inc. + +OUI:001379* + ID_OUI_FROM_DATABASE=PONDER INFORMATION INDUSTRIES LTD. + +OUI:00137A* + ID_OUI_FROM_DATABASE=Netvox Technology Co., Ltd. + +OUI:00137B* + ID_OUI_FROM_DATABASE=Movon Corporation + +OUI:00137C* + ID_OUI_FROM_DATABASE=Kaicom co., Ltd. + +OUI:00137D* + ID_OUI_FROM_DATABASE=Dynalab, Inc. + +OUI:00137E* + ID_OUI_FROM_DATABASE=CorEdge Networks, Inc. + +OUI:00137F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001380* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001381* + ID_OUI_FROM_DATABASE=CHIPS & Systems, Inc. + +OUI:001382* + ID_OUI_FROM_DATABASE=Cetacea Networks Corporation + +OUI:001383* + ID_OUI_FROM_DATABASE=Application Technologies and Engineering Research Laboratory + +OUI:001384* + ID_OUI_FROM_DATABASE=Advanced Motion Controls + +OUI:001385* + ID_OUI_FROM_DATABASE=Add-On Technology Co., LTD. + +OUI:001386* + ID_OUI_FROM_DATABASE=ABB Inc./Totalflow + +OUI:001387* + ID_OUI_FROM_DATABASE=27M Technologies AB + +OUI:001388* + ID_OUI_FROM_DATABASE=WiMedia Alliance + +OUI:001389* + ID_OUI_FROM_DATABASE=Redes de Telefonía Móvil S.A. + +OUI:00138A* + ID_OUI_FROM_DATABASE=QINGDAO GOERTEK ELECTRONICS CO.,LTD. + +OUI:00138B* + ID_OUI_FROM_DATABASE=Phantom Technologies LLC + +OUI:00138C* + ID_OUI_FROM_DATABASE=Kumyoung.Co.Ltd + +OUI:00138D* + ID_OUI_FROM_DATABASE=Kinghold + +OUI:00138E* + ID_OUI_FROM_DATABASE=FOAB Elektronik AB + +OUI:00138F* + ID_OUI_FROM_DATABASE=Asiarock Incorporation + +OUI:001390* + ID_OUI_FROM_DATABASE=Termtek Computer Co., Ltd + +OUI:001391* + ID_OUI_FROM_DATABASE=OUEN CO.,LTD. + +OUI:001392* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:001393* + ID_OUI_FROM_DATABASE=Panta Systems, Inc. + +OUI:001394* + ID_OUI_FROM_DATABASE=Infohand Co.,Ltd + +OUI:001395* + ID_OUI_FROM_DATABASE=congatec AG + +OUI:001396* + ID_OUI_FROM_DATABASE=Acbel Polytech Inc. + +OUI:001397* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:001398* + ID_OUI_FROM_DATABASE=TrafficSim Co.,Ltd + +OUI:001399* + ID_OUI_FROM_DATABASE=STAC Corporation. + +OUI:00139A* + ID_OUI_FROM_DATABASE=K-ubique ID Corp. + +OUI:00139B* + ID_OUI_FROM_DATABASE=ioIMAGE Ltd. + +OUI:00139C* + ID_OUI_FROM_DATABASE=Exavera Technologies, Inc. + +OUI:00139D* + ID_OUI_FROM_DATABASE=Marvell Hispana S.L. + +OUI:00139E* + ID_OUI_FROM_DATABASE=Ciara Technologies Inc. + +OUI:00139F* + ID_OUI_FROM_DATABASE=Electronics Design Services, Co., Ltd. + +OUI:0013A0* + ID_OUI_FROM_DATABASE=ALGOSYSTEM Co., Ltd. + +OUI:0013A1* + ID_OUI_FROM_DATABASE=Crow Electronic Engeneering + +OUI:0013A2* + ID_OUI_FROM_DATABASE=MaxStream, Inc + +OUI:0013A3* + ID_OUI_FROM_DATABASE=Siemens Com CPE Devices + +OUI:0013A4* + ID_OUI_FROM_DATABASE=KeyEye Communications + +OUI:0013A5* + ID_OUI_FROM_DATABASE=General Solutions, LTD. + +OUI:0013A6* + ID_OUI_FROM_DATABASE=Extricom Ltd + +OUI:0013A7* + ID_OUI_FROM_DATABASE=BATTELLE MEMORIAL INSTITUTE + +OUI:0013A8* + ID_OUI_FROM_DATABASE=Tanisys Technology + +OUI:0013A9* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:0013AA* + ID_OUI_FROM_DATABASE=ALS & TEC Ltd. + +OUI:0013AB* + ID_OUI_FROM_DATABASE=Telemotive AG + +OUI:0013AC* + ID_OUI_FROM_DATABASE=Sunmyung Electronics Co., LTD + +OUI:0013AD* + ID_OUI_FROM_DATABASE=Sendo Ltd + +OUI:0013AE* + ID_OUI_FROM_DATABASE=Radiance Technologies, Inc. + +OUI:0013AF* + ID_OUI_FROM_DATABASE=NUMA Technology,Inc. + +OUI:0013B0* + ID_OUI_FROM_DATABASE=Jablotron + +OUI:0013B1* + ID_OUI_FROM_DATABASE=Intelligent Control Systems (Asia) Pte Ltd + +OUI:0013B2* + ID_OUI_FROM_DATABASE=Carallon Limited + +OUI:0013B3* + ID_OUI_FROM_DATABASE=Ecom Communications Technology Co., Ltd. + +OUI:0013B4* + ID_OUI_FROM_DATABASE=Appear TV + +OUI:0013B5* + ID_OUI_FROM_DATABASE=Wavesat + +OUI:0013B6* + ID_OUI_FROM_DATABASE=Sling Media, Inc. + +OUI:0013B7* + ID_OUI_FROM_DATABASE=Scantech ID + +OUI:0013B8* + ID_OUI_FROM_DATABASE=RyCo Electronic Systems Limited + +OUI:0013B9* + ID_OUI_FROM_DATABASE=BM SPA + +OUI:0013BA* + ID_OUI_FROM_DATABASE=ReadyLinks Inc + +OUI:0013BB* + ID_OUI_FROM_DATABASE=Smartvue Corporation + +OUI:0013BC* + ID_OUI_FROM_DATABASE=Artimi Ltd + +OUI:0013BD* + ID_OUI_FROM_DATABASE=HYMATOM SA + +OUI:0013BE* + ID_OUI_FROM_DATABASE=Virtual Conexions + +OUI:0013BF* + ID_OUI_FROM_DATABASE=Media System Planning Corp. + +OUI:0013C0* + ID_OUI_FROM_DATABASE=Trix Tecnologia Ltda. + +OUI:0013C1* + ID_OUI_FROM_DATABASE=Asoka USA Corporation + +OUI:0013C2* + ID_OUI_FROM_DATABASE=WACOM Co.,Ltd + +OUI:0013C3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0013C4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0013C5* + ID_OUI_FROM_DATABASE=LIGHTRON FIBER-OPTIC DEVICES INC. + +OUI:0013C6* + ID_OUI_FROM_DATABASE=OpenGear, Inc + +OUI:0013C7* + ID_OUI_FROM_DATABASE=IONOS Co.,Ltd. + +OUI:0013C8* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:0013C9* + ID_OUI_FROM_DATABASE=Beyond Achieve Enterprises Ltd. + +OUI:0013CA* + ID_OUI_FROM_DATABASE=Pico Digital + +OUI:0013CB* + ID_OUI_FROM_DATABASE=Zenitel Norway AS + +OUI:0013CC* + ID_OUI_FROM_DATABASE=Tall Maple Systems + +OUI:0013CD* + ID_OUI_FROM_DATABASE=MTI co. LTD + +OUI:0013CE* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0013CF* + ID_OUI_FROM_DATABASE=4Access Communications + +OUI:0013D0* + ID_OUI_FROM_DATABASE=t+ Medical Ltd + +OUI:0013D1* + ID_OUI_FROM_DATABASE=KIRK telecom A/S + +OUI:0013D2* + ID_OUI_FROM_DATABASE=PAGE IBERICA, S.A. + +OUI:0013D3* + ID_OUI_FROM_DATABASE=MICRO-STAR INTERNATIONAL CO., LTD. + +OUI:0013D4* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:0013D5* + ID_OUI_FROM_DATABASE=RuggedCom + +OUI:0013D6* + ID_OUI_FROM_DATABASE=TII NETWORK TECHNOLOGIES, INC. + +OUI:0013D7* + ID_OUI_FROM_DATABASE=SPIDCOM Technologies SA + +OUI:0013D8* + ID_OUI_FROM_DATABASE=Princeton Instruments + +OUI:0013D9* + ID_OUI_FROM_DATABASE=Matrix Product Development, Inc. + +OUI:0013DA* + ID_OUI_FROM_DATABASE=Diskware Co., Ltd + +OUI:0013DB* + ID_OUI_FROM_DATABASE=SHOEI Electric Co.,Ltd + +OUI:0013DC* + ID_OUI_FROM_DATABASE=IBTEK INC. + +OUI:0013DD* + ID_OUI_FROM_DATABASE=Abbott Diagnostics + +OUI:0013DE* + ID_OUI_FROM_DATABASE=Adapt4, LLC + +OUI:0013DF* + ID_OUI_FROM_DATABASE=Ryvor Corp. + +OUI:0013E0* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:0013E1* + ID_OUI_FROM_DATABASE=Iprobe AB + +OUI:0013E2* + ID_OUI_FROM_DATABASE=GeoVision Inc. + +OUI:0013E3* + ID_OUI_FROM_DATABASE=CoVi Technologies, Inc. + +OUI:0013E4* + ID_OUI_FROM_DATABASE=YANGJAE SYSTEMS CORP. + +OUI:0013E5* + ID_OUI_FROM_DATABASE=TENOSYS, INC. + +OUI:0013E6* + ID_OUI_FROM_DATABASE=Technolution + +OUI:0013E7* + ID_OUI_FROM_DATABASE=Halcro + +OUI:0013E8* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0013E9* + ID_OUI_FROM_DATABASE=VeriWave, Inc. + +OUI:0013EA* + ID_OUI_FROM_DATABASE=Kamstrup A/S + +OUI:0013EB* + ID_OUI_FROM_DATABASE=Sysmaster Corporation + +OUI:0013EC* + ID_OUI_FROM_DATABASE=Sunbay Software AG + +OUI:0013ED* + ID_OUI_FROM_DATABASE=PSIA + +OUI:0013EE* + ID_OUI_FROM_DATABASE=JBX Designs Inc. + +OUI:0013EF* + ID_OUI_FROM_DATABASE=Kingjon Digital Technology Co.,Ltd + +OUI:0013F0* + ID_OUI_FROM_DATABASE=Wavefront Semiconductor + +OUI:0013F1* + ID_OUI_FROM_DATABASE=AMOD Technology Co., Ltd. + +OUI:0013F2* + ID_OUI_FROM_DATABASE=Klas Ltd + +OUI:0013F3* + ID_OUI_FROM_DATABASE=Giga-byte Communications Inc. + +OUI:0013F4* + ID_OUI_FROM_DATABASE=Psitek (Pty) Ltd + +OUI:0013F5* + ID_OUI_FROM_DATABASE=Akimbi Systems + +OUI:0013F6* + ID_OUI_FROM_DATABASE=Cintech + +OUI:0013F7* + ID_OUI_FROM_DATABASE=SMC Networks, Inc. + +OUI:0013F8* + ID_OUI_FROM_DATABASE=Dex Security Solutions + +OUI:0013F9* + ID_OUI_FROM_DATABASE=Cavera Systems + +OUI:0013FA* + ID_OUI_FROM_DATABASE=LifeSize Communications, Inc + +OUI:0013FB* + ID_OUI_FROM_DATABASE=RKC INSTRUMENT INC. + +OUI:0013FC* + ID_OUI_FROM_DATABASE=SiCortex, Inc + +OUI:0013FD* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0013FE* + ID_OUI_FROM_DATABASE=GRANDTEC ELECTRONIC CORP. + +OUI:0013FF* + ID_OUI_FROM_DATABASE=Dage-MTI of MC, Inc. + +OUI:001400* + ID_OUI_FROM_DATABASE=MINERVA KOREA CO., LTD + +OUI:001401* + ID_OUI_FROM_DATABASE=Rivertree Networks Corp. + +OUI:001402* + ID_OUI_FROM_DATABASE=kk-electronic a/s + +OUI:001403* + ID_OUI_FROM_DATABASE=Renasis, LLC + +OUI:001404* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001405* + ID_OUI_FROM_DATABASE=OpenIB, Inc. + +OUI:001406* + ID_OUI_FROM_DATABASE=Go Networks + +OUI:001407* + ID_OUI_FROM_DATABASE=Sperian Protection Instrumentation + +OUI:001408* + ID_OUI_FROM_DATABASE=Eka Systems Inc. + +OUI:001409* + ID_OUI_FROM_DATABASE=MAGNETI MARELLI S.E. S.p.A. + +OUI:00140A* + ID_OUI_FROM_DATABASE=WEPIO Co., Ltd. + +OUI:00140B* + ID_OUI_FROM_DATABASE=FIRST INTERNATIONAL COMPUTER, INC. + +OUI:00140C* + ID_OUI_FROM_DATABASE=GKB CCTV CO., LTD. + +OUI:00140D* + ID_OUI_FROM_DATABASE=Nortel + +OUI:00140E* + ID_OUI_FROM_DATABASE=Nortel + +OUI:00140F* + ID_OUI_FROM_DATABASE=Federal State Unitary Enterprise Leningrad R&D Institute of + +OUI:001410* + ID_OUI_FROM_DATABASE=Suzhou Keda Technology CO.,Ltd + +OUI:001411* + ID_OUI_FROM_DATABASE=Deutschmann Automation GmbH & Co. KG + +OUI:001412* + ID_OUI_FROM_DATABASE=S-TEC electronics AG + +OUI:001413* + ID_OUI_FROM_DATABASE=Trebing & Himstedt Prozeßautomation GmbH & Co. KG + +OUI:001414* + ID_OUI_FROM_DATABASE=Jumpnode Systems LLC. + +OUI:001415* + ID_OUI_FROM_DATABASE=Intec Automation Inc. + +OUI:001416* + ID_OUI_FROM_DATABASE=Scosche Industries, Inc. + +OUI:001417* + ID_OUI_FROM_DATABASE=RSE Informations Technologie GmbH + +OUI:001418* + ID_OUI_FROM_DATABASE=C4Line + +OUI:001419* + ID_OUI_FROM_DATABASE=SIDSA + +OUI:00141A* + ID_OUI_FROM_DATABASE=DEICY CORPORATION + +OUI:00141B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00141C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00141D* + ID_OUI_FROM_DATABASE=LTi DRIVES GmbH + +OUI:00141E* + ID_OUI_FROM_DATABASE=P.A. Semi, Inc. + +OUI:00141F* + ID_OUI_FROM_DATABASE=SunKwang Electronics Co., Ltd + +OUI:001420* + ID_OUI_FROM_DATABASE=G-Links networking company + +OUI:001421* + ID_OUI_FROM_DATABASE=Total Wireless Technologies Pte. Ltd. + +OUI:001422* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:001423* + ID_OUI_FROM_DATABASE=J-S Co. NEUROCOM + +OUI:001424* + ID_OUI_FROM_DATABASE=Merry Electrics CO., LTD. + +OUI:001425* + ID_OUI_FROM_DATABASE=Galactic Computing Corp. + +OUI:001426* + ID_OUI_FROM_DATABASE=NL Technology + +OUI:001427* + ID_OUI_FROM_DATABASE=JazzMutant + +OUI:001428* + ID_OUI_FROM_DATABASE=Vocollect, Inc + +OUI:001429* + ID_OUI_FROM_DATABASE=V Center Technologies Co., Ltd. + +OUI:00142A* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co., Ltd + +OUI:00142B* + ID_OUI_FROM_DATABASE=Edata Communication Inc. + +OUI:00142C* + ID_OUI_FROM_DATABASE=Koncept International, Inc. + +OUI:00142D* + ID_OUI_FROM_DATABASE=Toradex AG + +OUI:00142E* + ID_OUI_FROM_DATABASE=77 Elektronika Kft. + +OUI:00142F* + ID_OUI_FROM_DATABASE=WildPackets + +OUI:001430* + ID_OUI_FROM_DATABASE=ViPowER, Inc + +OUI:001431* + ID_OUI_FROM_DATABASE=PDL Electronics Ltd + +OUI:001432* + ID_OUI_FROM_DATABASE=Tarallax Wireless, Inc. + +OUI:001433* + ID_OUI_FROM_DATABASE=Empower Technologies(Canada) Inc. + +OUI:001434* + ID_OUI_FROM_DATABASE=Keri Systems, Inc + +OUI:001435* + ID_OUI_FROM_DATABASE=CityCom Corp. + +OUI:001436* + ID_OUI_FROM_DATABASE=Qwerty Elektronik AB + +OUI:001437* + ID_OUI_FROM_DATABASE=GSTeletech Co.,Ltd. + +OUI:001438* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001439* + ID_OUI_FROM_DATABASE=Blonder Tongue Laboratories, Inc. + +OUI:00143A* + ID_OUI_FROM_DATABASE=RAYTALK INTERNATIONAL SRL + +OUI:00143B* + ID_OUI_FROM_DATABASE=Sensovation AG + +OUI:00143C* + ID_OUI_FROM_DATABASE=Rheinmetall Canada Inc. + +OUI:00143D* + ID_OUI_FROM_DATABASE=Aevoe Inc. + +OUI:00143E* + ID_OUI_FROM_DATABASE=AirLink Communications, Inc. + +OUI:00143F* + ID_OUI_FROM_DATABASE=Hotway Technology Corporation + +OUI:001440* + ID_OUI_FROM_DATABASE=ATOMIC Corporation + +OUI:001441* + ID_OUI_FROM_DATABASE=Innovation Sound Technology Co., LTD. + +OUI:001442* + ID_OUI_FROM_DATABASE=ATTO CORPORATION + +OUI:001443* + ID_OUI_FROM_DATABASE=Consultronics Europe Ltd + +OUI:001444* + ID_OUI_FROM_DATABASE=Grundfos Holding + +OUI:001445* + ID_OUI_FROM_DATABASE=Telefon-Gradnja d.o.o. + +OUI:001446* + ID_OUI_FROM_DATABASE=SuperVision Solutions LLC + +OUI:001447* + ID_OUI_FROM_DATABASE=BOAZ Inc. + +OUI:001448* + ID_OUI_FROM_DATABASE=Inventec Multimedia & Telecom Corporation + +OUI:001449* + ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. + +OUI:00144A* + ID_OUI_FROM_DATABASE=Taiwan Thick-Film Ind. Corp. + +OUI:00144B* + ID_OUI_FROM_DATABASE=Hifn, Inc. + +OUI:00144C* + ID_OUI_FROM_DATABASE=General Meters Corp. + +OUI:00144D* + ID_OUI_FROM_DATABASE=Intelligent Systems + +OUI:00144E* + ID_OUI_FROM_DATABASE=SRISA + +OUI:00144F* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:001450* + ID_OUI_FROM_DATABASE=Heim Systems GmbH + +OUI:001451* + ID_OUI_FROM_DATABASE=Apple + +OUI:001452* + ID_OUI_FROM_DATABASE=CALCULEX,INC. + +OUI:001453* + ID_OUI_FROM_DATABASE=ADVANTECH TECHNOLOGIES CO.,LTD + +OUI:001454* + ID_OUI_FROM_DATABASE=Symwave + +OUI:001455* + ID_OUI_FROM_DATABASE=Coder Electronics Corporation + +OUI:001456* + ID_OUI_FROM_DATABASE=Edge Products + +OUI:001457* + ID_OUI_FROM_DATABASE=T-VIPS AS + +OUI:001458* + ID_OUI_FROM_DATABASE=HS Automatic ApS + +OUI:001459* + ID_OUI_FROM_DATABASE=Moram Co., Ltd. + +OUI:00145A* + ID_OUI_FROM_DATABASE=Neratec Solutions AG + +OUI:00145B* + ID_OUI_FROM_DATABASE=SeekerNet Inc. + +OUI:00145C* + ID_OUI_FROM_DATABASE=Intronics B.V. + +OUI:00145D* + ID_OUI_FROM_DATABASE=WJ Communications, Inc. + +OUI:00145E* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:00145F* + ID_OUI_FROM_DATABASE=ADITEC CO. LTD + +OUI:001460* + ID_OUI_FROM_DATABASE=Kyocera Wireless Corp. + +OUI:001461* + ID_OUI_FROM_DATABASE=CORONA CORPORATION + +OUI:001462* + ID_OUI_FROM_DATABASE=Digiwell Technology, inc + +OUI:001463* + ID_OUI_FROM_DATABASE=IDCS N.V. + +OUI:001464* + ID_OUI_FROM_DATABASE=Cryptosoft + +OUI:001465* + ID_OUI_FROM_DATABASE=Novo Nordisk A/S + +OUI:001466* + ID_OUI_FROM_DATABASE=Kleinhenz Elektronik GmbH + +OUI:001467* + ID_OUI_FROM_DATABASE=ArrowSpan Inc. + +OUI:001468* + ID_OUI_FROM_DATABASE=CelPlan International, Inc. + +OUI:001469* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00146A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00146B* + ID_OUI_FROM_DATABASE=Anagran, Inc. + +OUI:00146C* + ID_OUI_FROM_DATABASE=Netgear Inc. + +OUI:00146D* + ID_OUI_FROM_DATABASE=RF Technologies + +OUI:00146E* + ID_OUI_FROM_DATABASE=H. Stoll GmbH & Co. KG + +OUI:00146F* + ID_OUI_FROM_DATABASE=Kohler Co + +OUI:001470* + ID_OUI_FROM_DATABASE=Prokom Software SA + +OUI:001471* + ID_OUI_FROM_DATABASE=Eastern Asia Technology Limited + +OUI:001472* + ID_OUI_FROM_DATABASE=China Broadband Wireless IP Standard Group + +OUI:001473* + ID_OUI_FROM_DATABASE=Bookham Inc + +OUI:001474* + ID_OUI_FROM_DATABASE=K40 Electronics + +OUI:001475* + ID_OUI_FROM_DATABASE=Wiline Networks, Inc. + +OUI:001476* + ID_OUI_FROM_DATABASE=MultiCom Industries Limited + +OUI:001477* + ID_OUI_FROM_DATABASE=Nertec Inc. + +OUI:001478* + ID_OUI_FROM_DATABASE=ShenZhen TP-LINK Technologies Co., Ltd. + +OUI:001479* + ID_OUI_FROM_DATABASE=NEC Magnus Communications,Ltd. + +OUI:00147A* + ID_OUI_FROM_DATABASE=Eubus GmbH + +OUI:00147B* + ID_OUI_FROM_DATABASE=Iteris, Inc. + +OUI:00147C* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:00147D* + ID_OUI_FROM_DATABASE=Aeon Digital International + +OUI:00147E* + ID_OUI_FROM_DATABASE=InnerWireless + +OUI:00147F* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:001480* + ID_OUI_FROM_DATABASE=Hitachi-LG Data Storage Korea, Inc + +OUI:001481* + ID_OUI_FROM_DATABASE=Multilink Inc + +OUI:001482* + ID_OUI_FROM_DATABASE=Aurora Networks + +OUI:001483* + ID_OUI_FROM_DATABASE=eXS Inc. + +OUI:001484* + ID_OUI_FROM_DATABASE=Cermate Technologies Inc. + +OUI:001485* + ID_OUI_FROM_DATABASE=Giga-Byte + +OUI:001486* + ID_OUI_FROM_DATABASE=Echo Digital Audio Corporation + +OUI:001487* + ID_OUI_FROM_DATABASE=American Technology Integrators + +OUI:001488* + ID_OUI_FROM_DATABASE=Akorri + +OUI:001489* + ID_OUI_FROM_DATABASE=B15402100 - JANDEI, S.L. + +OUI:00148A* + ID_OUI_FROM_DATABASE=Elin Ebg Traction Gmbh + +OUI:00148B* + ID_OUI_FROM_DATABASE=Globo Electronic GmbH & Co. KG + +OUI:00148C* + ID_OUI_FROM_DATABASE=Fortress Technologies + +OUI:00148D* + ID_OUI_FROM_DATABASE=Cubic Defense Simulation Systems + +OUI:00148E* + ID_OUI_FROM_DATABASE=Tele Power Inc. + +OUI:00148F* + ID_OUI_FROM_DATABASE=Protronic (Far East) Ltd. + +OUI:001490* + ID_OUI_FROM_DATABASE=ASP Corporation + +OUI:001491* + ID_OUI_FROM_DATABASE=Daniels Electronics Ltd. dbo Codan Rado Communications + +OUI:001492* + ID_OUI_FROM_DATABASE=Liteon, Mobile Media Solution SBU + +OUI:001493* + ID_OUI_FROM_DATABASE=Systimax Solutions + +OUI:001494* + ID_OUI_FROM_DATABASE=ESU AG + +OUI:001495* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001496* + ID_OUI_FROM_DATABASE=Phonic Corp. + +OUI:001497* + ID_OUI_FROM_DATABASE=ZHIYUAN Eletronics co.,ltd. + +OUI:001498* + ID_OUI_FROM_DATABASE=Viking Design Technology + +OUI:001499* + ID_OUI_FROM_DATABASE=Helicomm Inc + +OUI:00149A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00149B* + ID_OUI_FROM_DATABASE=Nokota Communications, LLC + +OUI:00149C* + ID_OUI_FROM_DATABASE=HF Company + +OUI:00149D* + ID_OUI_FROM_DATABASE=Sound ID Inc. + +OUI:00149E* + ID_OUI_FROM_DATABASE=UbONE Co., Ltd + +OUI:00149F* + ID_OUI_FROM_DATABASE=System and Chips, Inc. + +OUI:0014A0* + ID_OUI_FROM_DATABASE=Accsense, Inc. + +OUI:0014A1* + ID_OUI_FROM_DATABASE=Synchronous Communication Corp + +OUI:0014A2* + ID_OUI_FROM_DATABASE=Core Micro Systems Inc. + +OUI:0014A3* + ID_OUI_FROM_DATABASE=Vitelec BV + +OUI:0014A4* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:0014A5* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:0014A6* + ID_OUI_FROM_DATABASE=Teranetics, Inc. + +OUI:0014A7* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0014A8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0014A9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0014AA* + ID_OUI_FROM_DATABASE=Ashly Audio, Inc. + +OUI:0014AB* + ID_OUI_FROM_DATABASE=Senhai Electronic Technology Co., Ltd. + +OUI:0014AC* + ID_OUI_FROM_DATABASE=Bountiful WiFi + +OUI:0014AD* + ID_OUI_FROM_DATABASE=Gassner Wiege- und Meßtechnik GmbH + +OUI:0014AE* + ID_OUI_FROM_DATABASE=Wizlogics Co., Ltd. + +OUI:0014AF* + ID_OUI_FROM_DATABASE=Datasym POS Inc. + +OUI:0014B0* + ID_OUI_FROM_DATABASE=Naeil Community + +OUI:0014B1* + ID_OUI_FROM_DATABASE=Avitec AB + +OUI:0014B2* + ID_OUI_FROM_DATABASE=mCubelogics Corporation + +OUI:0014B3* + ID_OUI_FROM_DATABASE=CoreStar International Corp + +OUI:0014B4* + ID_OUI_FROM_DATABASE=General Dynamics United Kingdom Ltd + +OUI:0014B5* + ID_OUI_FROM_DATABASE=PHYSIOMETRIX,INC + +OUI:0014B6* + ID_OUI_FROM_DATABASE=Enswer Technology Inc. + +OUI:0014B7* + ID_OUI_FROM_DATABASE=AR Infotek Inc. + +OUI:0014B8* + ID_OUI_FROM_DATABASE=Hill-Rom + +OUI:0014B9* + ID_OUI_FROM_DATABASE=MSTAR SEMICONDUCTOR + +OUI:0014BA* + ID_OUI_FROM_DATABASE=Carvers SA de CV + +OUI:0014BB* + ID_OUI_FROM_DATABASE=Open Interface North America + +OUI:0014BC* + ID_OUI_FROM_DATABASE=SYNECTIC TELECOM EXPORTS PVT. LTD. + +OUI:0014BD* + ID_OUI_FROM_DATABASE=incNETWORKS, Inc + +OUI:0014BE* + ID_OUI_FROM_DATABASE=Wink communication technology CO.LTD + +OUI:0014BF* + ID_OUI_FROM_DATABASE=Cisco-Linksys LLC + +OUI:0014C0* + ID_OUI_FROM_DATABASE=Symstream Technology Group Ltd + +OUI:0014C1* + ID_OUI_FROM_DATABASE=U.S. Robotics Corporation + +OUI:0014C2* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0014C3* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:0014C4* + ID_OUI_FROM_DATABASE=Vitelcom Mobile Technology + +OUI:0014C5* + ID_OUI_FROM_DATABASE=Alive Technologies Pty Ltd + +OUI:0014C6* + ID_OUI_FROM_DATABASE=Quixant Ltd + +OUI:0014C7* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0014C8* + ID_OUI_FROM_DATABASE=Contemporary Research Corp + +OUI:0014C9* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:0014CA* + ID_OUI_FROM_DATABASE=Key Radio Systems Limited + +OUI:0014CB* + ID_OUI_FROM_DATABASE=LifeSync Corporation + +OUI:0014CC* + ID_OUI_FROM_DATABASE=Zetec, Inc. + +OUI:0014CD* + ID_OUI_FROM_DATABASE=DigitalZone Co., Ltd. + +OUI:0014CE* + ID_OUI_FROM_DATABASE=NF CORPORATION + +OUI:0014CF* + ID_OUI_FROM_DATABASE=INVISIO Communications + +OUI:0014D0* + ID_OUI_FROM_DATABASE=BTI Systems Inc. + +OUI:0014D1* + ID_OUI_FROM_DATABASE=TRENDnet + +OUI:0014D2* + ID_OUI_FROM_DATABASE=Kyuden Technosystems Corporation + +OUI:0014D3* + ID_OUI_FROM_DATABASE=SEPSA + +OUI:0014D4* + ID_OUI_FROM_DATABASE=K Technology Corporation + +OUI:0014D5* + ID_OUI_FROM_DATABASE=Datang Telecom Technology CO. , LCD,Optical Communication Br + +OUI:0014D6* + ID_OUI_FROM_DATABASE=Jeongmin Electronics Co.,Ltd. + +OUI:0014D7* + ID_OUI_FROM_DATABASE=Datastore Technology Corp + +OUI:0014D8* + ID_OUI_FROM_DATABASE=bio-logic SA + +OUI:0014D9* + ID_OUI_FROM_DATABASE=IP Fabrics, Inc. + +OUI:0014DA* + ID_OUI_FROM_DATABASE=Huntleigh Healthcare + +OUI:0014DB* + ID_OUI_FROM_DATABASE=Elma Trenew Electronic GmbH + +OUI:0014DC* + ID_OUI_FROM_DATABASE=Communication System Design & Manufacturing (CSDM) + +OUI:0014DD* + ID_OUI_FROM_DATABASE=Covergence Inc. + +OUI:0014DE* + ID_OUI_FROM_DATABASE=Sage Instruments Inc. + +OUI:0014DF* + ID_OUI_FROM_DATABASE=HI-P Tech Corporation + +OUI:0014E0* + ID_OUI_FROM_DATABASE=LET'S Corporation + +OUI:0014E1* + ID_OUI_FROM_DATABASE=Data Display AG + +OUI:0014E2* + ID_OUI_FROM_DATABASE=datacom systems inc. + +OUI:0014E3* + ID_OUI_FROM_DATABASE=mm-lab GmbH + +OUI:0014E4* + ID_OUI_FROM_DATABASE=infinias, LLC + +OUI:0014E5* + ID_OUI_FROM_DATABASE=Alticast + +OUI:0014E6* + ID_OUI_FROM_DATABASE=AIM Infrarotmodule GmbH + +OUI:0014E7* + ID_OUI_FROM_DATABASE=Stolinx,. Inc + +OUI:0014E8* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0014E9* + ID_OUI_FROM_DATABASE=Nortech International + +OUI:0014EA* + ID_OUI_FROM_DATABASE=S Digm Inc. (Safe Paradigm Inc.) + +OUI:0014EB* + ID_OUI_FROM_DATABASE=AwarePoint Corporation + +OUI:0014EC* + ID_OUI_FROM_DATABASE=Acro Telecom + +OUI:0014ED* + ID_OUI_FROM_DATABASE=Airak, Inc. + +OUI:0014EE* + ID_OUI_FROM_DATABASE=Western Digital Technologies, Inc. + +OUI:0014EF* + ID_OUI_FROM_DATABASE=TZero Technologies, Inc. + +OUI:0014F0* + ID_OUI_FROM_DATABASE=Business Security OL AB + +OUI:0014F1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0014F2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0014F3* + ID_OUI_FROM_DATABASE=ViXS Systems Inc + +OUI:0014F4* + ID_OUI_FROM_DATABASE=DekTec Digital Video B.V. + +OUI:0014F5* + ID_OUI_FROM_DATABASE=OSI Security Devices + +OUI:0014F6* + ID_OUI_FROM_DATABASE=Juniper Networks, Inc. + +OUI:0014F7* + ID_OUI_FROM_DATABASE=CREVIS Co., LTD + +OUI:0014F8* + ID_OUI_FROM_DATABASE=Scientific Atlanta + +OUI:0014F9* + ID_OUI_FROM_DATABASE=Vantage Controls + +OUI:0014FA* + ID_OUI_FROM_DATABASE=AsGa S.A. + +OUI:0014FB* + ID_OUI_FROM_DATABASE=Technical Solutions Inc. + +OUI:0014FC* + ID_OUI_FROM_DATABASE=Extandon, Inc. + +OUI:0014FD* + ID_OUI_FROM_DATABASE=Thecus Technology Corp. + +OUI:0014FE* + ID_OUI_FROM_DATABASE=Artech Electronics + +OUI:0014FF* + ID_OUI_FROM_DATABASE=Precise Automation, Inc. + +OUI:001500* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001501* + ID_OUI_FROM_DATABASE=LexBox + +OUI:001502* + ID_OUI_FROM_DATABASE=BETA tech + +OUI:001503* + ID_OUI_FROM_DATABASE=PROFIcomms s.r.o. + +OUI:001504* + ID_OUI_FROM_DATABASE=GAME PLUS CO., LTD. + +OUI:001505* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:001506* + ID_OUI_FROM_DATABASE=Neo Photonics + +OUI:001507* + ID_OUI_FROM_DATABASE=Renaissance Learning Inc + +OUI:001508* + ID_OUI_FROM_DATABASE=Global Target Enterprise Inc + +OUI:001509* + ID_OUI_FROM_DATABASE=Plus Technology Co., Ltd + +OUI:00150A* + ID_OUI_FROM_DATABASE=Sonoa Systems, Inc + +OUI:00150B* + ID_OUI_FROM_DATABASE=SAGE INFOTECH LTD. + +OUI:00150C* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:00150D* + ID_OUI_FROM_DATABASE=Hoana Medical, Inc. + +OUI:00150E* + ID_OUI_FROM_DATABASE=OPENBRAIN TECHNOLOGIES CO., LTD. + +OUI:00150F* + ID_OUI_FROM_DATABASE=mingjong + +OUI:001510* + ID_OUI_FROM_DATABASE=Techsphere Co., Ltd + +OUI:001511* + ID_OUI_FROM_DATABASE=Data Center Systems + +OUI:001512* + ID_OUI_FROM_DATABASE=Zurich University of Applied Sciences + +OUI:001513* + ID_OUI_FROM_DATABASE=EFS sas + +OUI:001514* + ID_OUI_FROM_DATABASE=Hu Zhou NAVA Networks&Electronics Ltd. + +OUI:001515* + ID_OUI_FROM_DATABASE=Leipold+Co.GmbH + +OUI:001516* + ID_OUI_FROM_DATABASE=URIEL SYSTEMS INC. + +OUI:001517* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001518* + ID_OUI_FROM_DATABASE=Shenzhen 10MOONS Technology Development CO.,Ltd + +OUI:001519* + ID_OUI_FROM_DATABASE=StoreAge Networking Technologies + +OUI:00151A* + ID_OUI_FROM_DATABASE=Hunter Engineering Company + +OUI:00151B* + ID_OUI_FROM_DATABASE=Isilon Systems Inc. + +OUI:00151C* + ID_OUI_FROM_DATABASE=LENECO + +OUI:00151D* + ID_OUI_FROM_DATABASE=M2I CORPORATION + +OUI:00151E* + ID_OUI_FROM_DATABASE=Ethernet Powerlink Standardization Group (EPSG) + +OUI:00151F* + ID_OUI_FROM_DATABASE=Multivision Intelligent Surveillance (Hong Kong) Ltd + +OUI:001520* + ID_OUI_FROM_DATABASE=Radiocrafts AS + +OUI:001521* + ID_OUI_FROM_DATABASE=Horoquartz + +OUI:001522* + ID_OUI_FROM_DATABASE=Dea Security + +OUI:001523* + ID_OUI_FROM_DATABASE=Meteor Communications Corporation + +OUI:001524* + ID_OUI_FROM_DATABASE=Numatics, Inc. + +OUI:001525* + ID_OUI_FROM_DATABASE=Chamberlain Access Solutions + +OUI:001526* + ID_OUI_FROM_DATABASE=Remote Technologies Inc + +OUI:001527* + ID_OUI_FROM_DATABASE=Balboa Instruments + +OUI:001528* + ID_OUI_FROM_DATABASE=Beacon Medical Products LLC d.b.a. BeaconMedaes + +OUI:001529* + ID_OUI_FROM_DATABASE=N3 Corporation + +OUI:00152A* + ID_OUI_FROM_DATABASE=Nokia GmbH + +OUI:00152B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00152C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00152D* + ID_OUI_FROM_DATABASE=TenX Networks, LLC + +OUI:00152E* + ID_OUI_FROM_DATABASE=PacketHop, Inc. + +OUI:00152F* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001530* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:001531* + ID_OUI_FROM_DATABASE=KOCOM + +OUI:001532* + ID_OUI_FROM_DATABASE=Consumer Technologies Group, LLC + +OUI:001533* + ID_OUI_FROM_DATABASE=NADAM.CO.,LTD + +OUI:001534* + ID_OUI_FROM_DATABASE=A Beltrónica-Companhia de Comunicações, Lda + +OUI:001535* + ID_OUI_FROM_DATABASE=OTE Spa + +OUI:001536* + ID_OUI_FROM_DATABASE=Powertech co.,Ltd + +OUI:001537* + ID_OUI_FROM_DATABASE=Ventus Networks + +OUI:001538* + ID_OUI_FROM_DATABASE=RFID, Inc. + +OUI:001539* + ID_OUI_FROM_DATABASE=Technodrive SRL + +OUI:00153A* + ID_OUI_FROM_DATABASE=Shenzhen Syscan Technology Co.,Ltd. + +OUI:00153B* + ID_OUI_FROM_DATABASE=EMH metering GmbH & Co. KG + +OUI:00153C* + ID_OUI_FROM_DATABASE=Kprotech Co., Ltd. + +OUI:00153D* + ID_OUI_FROM_DATABASE=ELIM PRODUCT CO. + +OUI:00153E* + ID_OUI_FROM_DATABASE=Q-Matic Sweden AB + +OUI:00153F* + ID_OUI_FROM_DATABASE=Alcatel Alenia Space Italia + +OUI:001540* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001541* + ID_OUI_FROM_DATABASE=StrataLight Communications, Inc. + +OUI:001542* + ID_OUI_FROM_DATABASE=MICROHARD S.R.L. + +OUI:001543* + ID_OUI_FROM_DATABASE=Aberdeen Test Center + +OUI:001544* + ID_OUI_FROM_DATABASE=coM.s.a.t. AG + +OUI:001545* + ID_OUI_FROM_DATABASE=SEECODE Co., Ltd. + +OUI:001546* + ID_OUI_FROM_DATABASE=ITG Worldwide Sdn Bhd + +OUI:001547* + ID_OUI_FROM_DATABASE=AiZen Solutions Inc. + +OUI:001548* + ID_OUI_FROM_DATABASE=CUBE TECHNOLOGIES + +OUI:001549* + ID_OUI_FROM_DATABASE=Dixtal Biomedica Ind. Com. Ltda + +OUI:00154A* + ID_OUI_FROM_DATABASE=WANSHIH ELECTRONIC CO., LTD + +OUI:00154B* + ID_OUI_FROM_DATABASE=Wonde Proud Technology Co., Ltd + +OUI:00154C* + ID_OUI_FROM_DATABASE=Saunders Electronics + +OUI:00154D* + ID_OUI_FROM_DATABASE=Netronome Systems, Inc. + +OUI:00154E* + ID_OUI_FROM_DATABASE=IEC + +OUI:00154F* + ID_OUI_FROM_DATABASE=one RF Technology + +OUI:001550* + ID_OUI_FROM_DATABASE=Nits Technology Inc + +OUI:001551* + ID_OUI_FROM_DATABASE=RadioPulse Inc. + +OUI:001552* + ID_OUI_FROM_DATABASE=Wi-Gear Inc. + +OUI:001553* + ID_OUI_FROM_DATABASE=Cytyc Corporation + +OUI:001554* + ID_OUI_FROM_DATABASE=Atalum Wireless S.A. + +OUI:001555* + ID_OUI_FROM_DATABASE=DFM GmbH + +OUI:001556* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:001557* + ID_OUI_FROM_DATABASE=Olivetti + +OUI:001558* + ID_OUI_FROM_DATABASE=FOXCONN + +OUI:001559* + ID_OUI_FROM_DATABASE=Securaplane Technologies, Inc. + +OUI:00155A* + ID_OUI_FROM_DATABASE=DAINIPPON PHARMACEUTICAL CO., LTD. + +OUI:00155B* + ID_OUI_FROM_DATABASE=Sampo Corporation + +OUI:00155C* + ID_OUI_FROM_DATABASE=Dresser Wayne + +OUI:00155D* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:00155E* + ID_OUI_FROM_DATABASE=Morgan Stanley + +OUI:00155F* + ID_OUI_FROM_DATABASE=GreenPeak Technologies + +OUI:001560* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001561* + ID_OUI_FROM_DATABASE=JJPlus Corporation + +OUI:001562* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001563* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001564* + ID_OUI_FROM_DATABASE=BEHRINGER Spezielle Studiotechnik GmbH + +OUI:001565* + ID_OUI_FROM_DATABASE=XIAMEN YEALINK NETWORK TECHNOLOGY CO.,LTD + +OUI:001566* + ID_OUI_FROM_DATABASE=A-First Technology Co., Ltd. + +OUI:001567* + ID_OUI_FROM_DATABASE=RADWIN Inc. + +OUI:001568* + ID_OUI_FROM_DATABASE=Dilithium Networks + +OUI:001569* + ID_OUI_FROM_DATABASE=PECO II, Inc. + +OUI:00156A* + ID_OUI_FROM_DATABASE=DG2L Technologies Pvt. Ltd. + +OUI:00156B* + ID_OUI_FROM_DATABASE=Perfisans Networks Corp. + +OUI:00156C* + ID_OUI_FROM_DATABASE=SANE SYSTEM CO., LTD + +OUI:00156D* + ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc. + +OUI:00156E* + ID_OUI_FROM_DATABASE=A. W. Communication Systems Ltd + +OUI:00156F* + ID_OUI_FROM_DATABASE=Xiranet Communications GmbH + +OUI:001570* + ID_OUI_FROM_DATABASE=Symbol TechnologiesWholly owned Subsidiary of Motorola + +OUI:001571* + ID_OUI_FROM_DATABASE=Nolan Systems + +OUI:001572* + ID_OUI_FROM_DATABASE=Red-Lemon + +OUI:001573* + ID_OUI_FROM_DATABASE=NewSoft Technology Corporation + +OUI:001574* + ID_OUI_FROM_DATABASE=Horizon Semiconductors Ltd. + +OUI:001575* + ID_OUI_FROM_DATABASE=Nevis Networks Inc. + +OUI:001576* + ID_OUI_FROM_DATABASE=LABiTec - Labor Biomedical Technologies GmbH + +OUI:001577* + ID_OUI_FROM_DATABASE=Allied Telesis + +OUI:001578* + ID_OUI_FROM_DATABASE=Audio / Video Innovations + +OUI:001579* + ID_OUI_FROM_DATABASE=Lunatone Industrielle Elektronik GmbH + +OUI:00157A* + ID_OUI_FROM_DATABASE=Telefin S.p.A. + +OUI:00157B* + ID_OUI_FROM_DATABASE=Leuze electronic GmbH + Co. KG + +OUI:00157C* + ID_OUI_FROM_DATABASE=Dave Networks, Inc. + +OUI:00157D* + ID_OUI_FROM_DATABASE=POSDATA CO., LTD. + +OUI:00157E* + ID_OUI_FROM_DATABASE=Weidmüller Interface GmbH & Co. KG + +OUI:00157F* + ID_OUI_FROM_DATABASE=ChuanG International Holding CO.,LTD. + +OUI:001580* + ID_OUI_FROM_DATABASE=U-WAY CORPORATION + +OUI:001581* + ID_OUI_FROM_DATABASE=MAKUS Inc. + +OUI:001582* + ID_OUI_FROM_DATABASE=Pulse Eight Limited + +OUI:001583* + ID_OUI_FROM_DATABASE=IVT corporation + +OUI:001584* + ID_OUI_FROM_DATABASE=Schenck Process GmbH + +OUI:001585* + ID_OUI_FROM_DATABASE=Aonvision Technolopy Corp. + +OUI:001586* + ID_OUI_FROM_DATABASE=Xiamen Overseas Chinese Electronic Co., Ltd. + +OUI:001587* + ID_OUI_FROM_DATABASE=Takenaka Seisakusho Co.,Ltd + +OUI:001588* + ID_OUI_FROM_DATABASE=Salutica Allied Solutions Sdn Bhd + +OUI:001589* + ID_OUI_FROM_DATABASE=D-MAX Technology Co.,Ltd + +OUI:00158A* + ID_OUI_FROM_DATABASE=SURECOM Technology Corp. + +OUI:00158B* + ID_OUI_FROM_DATABASE=Park Air Systems Ltd + +OUI:00158C* + ID_OUI_FROM_DATABASE=Liab ApS + +OUI:00158D* + ID_OUI_FROM_DATABASE=Jennic Ltd + +OUI:00158E* + ID_OUI_FROM_DATABASE=Plustek.INC + +OUI:00158F* + ID_OUI_FROM_DATABASE=NTT Advanced Technology Corporation + +OUI:001590* + ID_OUI_FROM_DATABASE=Hectronic GmbH + +OUI:001591* + ID_OUI_FROM_DATABASE=RLW Inc. + +OUI:001592* + ID_OUI_FROM_DATABASE=Facom UK Ltd (Melksham) + +OUI:001593* + ID_OUI_FROM_DATABASE=U4EA Technologies Inc. + +OUI:001594* + ID_OUI_FROM_DATABASE=BIXOLON CO.,LTD + +OUI:001595* + ID_OUI_FROM_DATABASE=Quester Tangent Corporation + +OUI:001596* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:001597* + ID_OUI_FROM_DATABASE=AETA AUDIO SYSTEMS + +OUI:001598* + ID_OUI_FROM_DATABASE=Kolektor group + +OUI:001599* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:00159A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00159B* + ID_OUI_FROM_DATABASE=Nortel + +OUI:00159C* + ID_OUI_FROM_DATABASE=B-KYUNG SYSTEM Co.,Ltd. + +OUI:00159D* + ID_OUI_FROM_DATABASE=Minicom Advanced Systems ltd + +OUI:00159E* + ID_OUI_FROM_DATABASE=Mad Catz Interactive Inc + +OUI:00159F* + ID_OUI_FROM_DATABASE=Terascala, Inc. + +OUI:0015A0* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0015A1* + ID_OUI_FROM_DATABASE=ECA-SINTERS + +OUI:0015A2* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015A3* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015A4* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015A5* + ID_OUI_FROM_DATABASE=DCI Co., Ltd. + +OUI:0015A6* + ID_OUI_FROM_DATABASE=Digital Electronics Products Ltd. + +OUI:0015A7* + ID_OUI_FROM_DATABASE=Robatech AG + +OUI:0015A8* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0015A9* + ID_OUI_FROM_DATABASE=KWANG WOO I&C CO.,LTD + +OUI:0015AA* + ID_OUI_FROM_DATABASE=Rextechnik International Co., + +OUI:0015AB* + ID_OUI_FROM_DATABASE=PRO CO SOUND INC + +OUI:0015AC* + ID_OUI_FROM_DATABASE=Capelon AB + +OUI:0015AD* + ID_OUI_FROM_DATABASE=Accedian Networks + +OUI:0015AE* + ID_OUI_FROM_DATABASE=kyung il + +OUI:0015AF* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc. + +OUI:0015B0* + ID_OUI_FROM_DATABASE=AUTOTELENET CO.,LTD + +OUI:0015B1* + ID_OUI_FROM_DATABASE=Ambient Corporation + +OUI:0015B2* + ID_OUI_FROM_DATABASE=Advanced Industrial Computer, Inc. + +OUI:0015B3* + ID_OUI_FROM_DATABASE=Caretech AB + +OUI:0015B4* + ID_OUI_FROM_DATABASE=Polymap Wireless LLC + +OUI:0015B5* + ID_OUI_FROM_DATABASE=CI Network Corp. + +OUI:0015B6* + ID_OUI_FROM_DATABASE=ShinMaywa Industries, Ltd. + +OUI:0015B7* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:0015B8* + ID_OUI_FROM_DATABASE=Tahoe + +OUI:0015B9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:0015BA* + ID_OUI_FROM_DATABASE=iba AG + +OUI:0015BB* + ID_OUI_FROM_DATABASE=SMA Solar Technology AG + +OUI:0015BC* + ID_OUI_FROM_DATABASE=Develco + +OUI:0015BD* + ID_OUI_FROM_DATABASE=Group 4 Technology Ltd + +OUI:0015BE* + ID_OUI_FROM_DATABASE=Iqua Ltd. + +OUI:0015BF* + ID_OUI_FROM_DATABASE=technicob + +OUI:0015C0* + ID_OUI_FROM_DATABASE=DIGITAL TELEMEDIA CO.,LTD. + +OUI:0015C1* + ID_OUI_FROM_DATABASE=SONY Computer Entertainment inc, + +OUI:0015C2* + ID_OUI_FROM_DATABASE=3M Germany + +OUI:0015C3* + ID_OUI_FROM_DATABASE=Ruf Telematik AG + +OUI:0015C4* + ID_OUI_FROM_DATABASE=FLOVEL CO., LTD. + +OUI:0015C5* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:0015C6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0015C7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0015C8* + ID_OUI_FROM_DATABASE=FlexiPanel Ltd + +OUI:0015C9* + ID_OUI_FROM_DATABASE=Gumstix, Inc + +OUI:0015CA* + ID_OUI_FROM_DATABASE=TeraRecon, Inc. + +OUI:0015CB* + ID_OUI_FROM_DATABASE=Surf Communication Solutions Ltd. + +OUI:0015CC* + ID_OUI_FROM_DATABASE=UQUEST, LTD. + +OUI:0015CD* + ID_OUI_FROM_DATABASE=Exartech International Corp. + +OUI:0015CE* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015CF* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015D0* + ID_OUI_FROM_DATABASE=ARRIS International + +OUI:0015D1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0015D2* + ID_OUI_FROM_DATABASE=Xantech Corporation + +OUI:0015D3* + ID_OUI_FROM_DATABASE=Pantech&Curitel Communications, Inc. + +OUI:0015D4* + ID_OUI_FROM_DATABASE=Emitor AB + +OUI:0015D5* + ID_OUI_FROM_DATABASE=NICEVT + +OUI:0015D6* + ID_OUI_FROM_DATABASE=OSLiNK Sp. z o.o. + +OUI:0015D7* + ID_OUI_FROM_DATABASE=Reti Corporation + +OUI:0015D8* + ID_OUI_FROM_DATABASE=Interlink Electronics + +OUI:0015D9* + ID_OUI_FROM_DATABASE=PKC Electronics Oy + +OUI:0015DA* + ID_OUI_FROM_DATABASE=IRITEL A.D. + +OUI:0015DB* + ID_OUI_FROM_DATABASE=Canesta Inc. + +OUI:0015DC* + ID_OUI_FROM_DATABASE=KT&C Co., Ltd. + +OUI:0015DD* + ID_OUI_FROM_DATABASE=IP Control Systems Ltd. + +OUI:0015DE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0015DF* + ID_OUI_FROM_DATABASE=Clivet S.p.A. + +OUI:0015E0* + ID_OUI_FROM_DATABASE=ST-Ericsson + +OUI:0015E1* + ID_OUI_FROM_DATABASE=Picochip Ltd + +OUI:0015E2* + ID_OUI_FROM_DATABASE=Dr.Ing. Herbert Knauer GmbH + +OUI:0015E3* + ID_OUI_FROM_DATABASE=Dream Technologies Corporation + +OUI:0015E4* + ID_OUI_FROM_DATABASE=Zimmer Elektromedizin + +OUI:0015E5* + ID_OUI_FROM_DATABASE=Cheertek Inc. + +OUI:0015E6* + ID_OUI_FROM_DATABASE=MOBILE TECHNIKA Inc. + +OUI:0015E7* + ID_OUI_FROM_DATABASE=Quantec Tontechnik + +OUI:0015E8* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0015E9* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:0015EA* + ID_OUI_FROM_DATABASE=Tellumat (Pty) Ltd + +OUI:0015EB* + ID_OUI_FROM_DATABASE=ZTE CORPORATION + +OUI:0015EC* + ID_OUI_FROM_DATABASE=Boca Devices LLC + +OUI:0015ED* + ID_OUI_FROM_DATABASE=Fulcrum Microsystems, Inc. + +OUI:0015EE* + ID_OUI_FROM_DATABASE=Omnex Control Systems + +OUI:0015EF* + ID_OUI_FROM_DATABASE=NEC TOKIN Corporation + +OUI:0015F0* + ID_OUI_FROM_DATABASE=EGO BV + +OUI:0015F1* + ID_OUI_FROM_DATABASE=KYLINK Communications Corp. + +OUI:0015F2* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:0015F3* + ID_OUI_FROM_DATABASE=PELTOR AB + +OUI:0015F4* + ID_OUI_FROM_DATABASE=Eventide + +OUI:0015F5* + ID_OUI_FROM_DATABASE=Sustainable Energy Systems + +OUI:0015F6* + ID_OUI_FROM_DATABASE=SCIENCE AND ENGINEERING SERVICES, INC. + +OUI:0015F7* + ID_OUI_FROM_DATABASE=Wintecronics Ltd. + +OUI:0015F8* + ID_OUI_FROM_DATABASE=Kingtronics Industrial Co. Ltd. + +OUI:0015F9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0015FA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0015FB* + ID_OUI_FROM_DATABASE=setex schermuly textile computer gmbh + +OUI:0015FC* + ID_OUI_FROM_DATABASE=Littelfuse Startco + +OUI:0015FD* + ID_OUI_FROM_DATABASE=Complete Media Systems + +OUI:0015FE* + ID_OUI_FROM_DATABASE=SCHILLING ROBOTICS LLC + +OUI:0015FF* + ID_OUI_FROM_DATABASE=Novatel Wireless, Inc. + +OUI:001600* + ID_OUI_FROM_DATABASE=CelleBrite Mobile Synchronization + +OUI:001601* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:001602* + ID_OUI_FROM_DATABASE=CEYON TECHNOLOGY CO.,LTD. + +OUI:001603* + ID_OUI_FROM_DATABASE=COOLKSKY Co., LTD + +OUI:001604* + ID_OUI_FROM_DATABASE=Sigpro + +OUI:001605* + ID_OUI_FROM_DATABASE=YORKVILLE SOUND INC. + +OUI:001606* + ID_OUI_FROM_DATABASE=Ideal Industries + +OUI:001607* + ID_OUI_FROM_DATABASE=Curves International Inc. + +OUI:001608* + ID_OUI_FROM_DATABASE=Sequans Communications + +OUI:001609* + ID_OUI_FROM_DATABASE=Unitech electronics co., ltd. + +OUI:00160A* + ID_OUI_FROM_DATABASE=SWEEX Europe BV + +OUI:00160B* + ID_OUI_FROM_DATABASE=TVWorks LLC + +OUI:00160C* + ID_OUI_FROM_DATABASE=LPL DEVELOPMENT S.A. DE C.V + +OUI:00160D* + ID_OUI_FROM_DATABASE=Be Here Corporation + +OUI:00160E* + ID_OUI_FROM_DATABASE=Optica Technologies Inc. + +OUI:00160F* + ID_OUI_FROM_DATABASE=BADGER METER INC + +OUI:001610* + ID_OUI_FROM_DATABASE=Carina Technology + +OUI:001611* + ID_OUI_FROM_DATABASE=Altecon Srl + +OUI:001612* + ID_OUI_FROM_DATABASE=Otsuka Electronics Co., Ltd. + +OUI:001613* + ID_OUI_FROM_DATABASE=LibreStream Technologies Inc. + +OUI:001614* + ID_OUI_FROM_DATABASE=Picosecond Pulse Labs + +OUI:001615* + ID_OUI_FROM_DATABASE=Nittan Company, Limited + +OUI:001616* + ID_OUI_FROM_DATABASE=BROWAN COMMUNICATION INC. + +OUI:001617* + ID_OUI_FROM_DATABASE=MSI + +OUI:001618* + ID_OUI_FROM_DATABASE=HIVION Co., Ltd. + +OUI:001619* + ID_OUI_FROM_DATABASE=Lancelan Technologies S.L. + +OUI:00161A* + ID_OUI_FROM_DATABASE=Dametric AB + +OUI:00161B* + ID_OUI_FROM_DATABASE=Micronet Corporation + +OUI:00161C* + ID_OUI_FROM_DATABASE=e:cue + +OUI:00161D* + ID_OUI_FROM_DATABASE=Innovative Wireless Technologies, Inc. + +OUI:00161E* + ID_OUI_FROM_DATABASE=Woojinnet + +OUI:00161F* + ID_OUI_FROM_DATABASE=SUNWAVETEC Co., Ltd. + +OUI:001620* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:001621* + ID_OUI_FROM_DATABASE=Colorado Vnet + +OUI:001622* + ID_OUI_FROM_DATABASE=BBH SYSTEMS GMBH + +OUI:001623* + ID_OUI_FROM_DATABASE=Interval Media + +OUI:001624* + ID_OUI_FROM_DATABASE=Teneros, Inc. + +OUI:001625* + ID_OUI_FROM_DATABASE=Impinj, Inc. + +OUI:001626* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001627* + ID_OUI_FROM_DATABASE=embedded-logic DESIGN AND MORE GmbH + +OUI:001628* + ID_OUI_FROM_DATABASE=Ultra Electronics Manufacturing and Card Systems + +OUI:001629* + ID_OUI_FROM_DATABASE=Nivus GmbH + +OUI:00162A* + ID_OUI_FROM_DATABASE=Antik computers & communications s.r.o. + +OUI:00162B* + ID_OUI_FROM_DATABASE=Togami Electric Mfg.co.,Ltd. + +OUI:00162C* + ID_OUI_FROM_DATABASE=Xanboo + +OUI:00162D* + ID_OUI_FROM_DATABASE=STNet Co., Ltd. + +OUI:00162E* + ID_OUI_FROM_DATABASE=Space Shuttle Hi-Tech Co., Ltd. + +OUI:00162F* + ID_OUI_FROM_DATABASE=Geutebrück GmbH + +OUI:001630* + ID_OUI_FROM_DATABASE=Vativ Technologies + +OUI:001631* + ID_OUI_FROM_DATABASE=Xteam + +OUI:001632* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. + +OUI:001633* + ID_OUI_FROM_DATABASE=Oxford Diagnostics Ltd. + +OUI:001634* + ID_OUI_FROM_DATABASE=Mathtech, Inc. + +OUI:001635* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001636* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:001637* + ID_OUI_FROM_DATABASE=CITEL SpA + +OUI:001638* + ID_OUI_FROM_DATABASE=TECOM Co., Ltd. + +OUI:001639* + ID_OUI_FROM_DATABASE=UBIQUAM Co.,Ltd + +OUI:00163A* + ID_OUI_FROM_DATABASE=YVES TECHNOLOGY CO., LTD. + +OUI:00163B* + ID_OUI_FROM_DATABASE=VertexRSI/General Dynamics + +OUI:00163C* + ID_OUI_FROM_DATABASE=Rebox B.V. + +OUI:00163D* + ID_OUI_FROM_DATABASE=Tsinghua Tongfang Legend Silicon Tech. Co., Ltd. + +OUI:00163E* + ID_OUI_FROM_DATABASE=Xensource, Inc. + +OUI:00163F* + ID_OUI_FROM_DATABASE=CReTE SYSTEMS Inc. + +OUI:001640* + ID_OUI_FROM_DATABASE=Asmobile Communication Inc. + +OUI:001641* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:001642* + ID_OUI_FROM_DATABASE=Pangolin + +OUI:001643* + ID_OUI_FROM_DATABASE=Sunhillo Corporation + +OUI:001644* + ID_OUI_FROM_DATABASE=LITE-ON Technology Corp. + +OUI:001645* + ID_OUI_FROM_DATABASE=Power Distribution, Inc. + +OUI:001646* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001647* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001648* + ID_OUI_FROM_DATABASE=SSD Company Limited + +OUI:001649* + ID_OUI_FROM_DATABASE=SetOne GmbH + +OUI:00164A* + ID_OUI_FROM_DATABASE=Vibration Technology Limited + +OUI:00164B* + ID_OUI_FROM_DATABASE=Quorion Data Systems GmbH + +OUI:00164C* + ID_OUI_FROM_DATABASE=PLANET INT Co., Ltd + +OUI:00164D* + ID_OUI_FROM_DATABASE=Alcatel North America IP Division + +OUI:00164E* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00164F* + ID_OUI_FROM_DATABASE=World Ethnic Broadcastin Inc. + +OUI:001650* + ID_OUI_FROM_DATABASE=Herley General Microwave Israel. + +OUI:001651* + ID_OUI_FROM_DATABASE=Exeo Systems + +OUI:001652* + ID_OUI_FROM_DATABASE=Hoatech Technologies, Inc. + +OUI:001653* + ID_OUI_FROM_DATABASE=LEGO System A/S IE Electronics Division + +OUI:001654* + ID_OUI_FROM_DATABASE=Flex-P Industries Sdn. Bhd. + +OUI:001655* + ID_OUI_FROM_DATABASE=FUHO TECHNOLOGY Co., LTD + +OUI:001656* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001657* + ID_OUI_FROM_DATABASE=Aegate Ltd + +OUI:001658* + ID_OUI_FROM_DATABASE=Fusiontech Technologies Inc. + +OUI:001659* + ID_OUI_FROM_DATABASE=Z.M.P. RADWAG + +OUI:00165A* + ID_OUI_FROM_DATABASE=Harman Specialty Group + +OUI:00165B* + ID_OUI_FROM_DATABASE=Grip Audio + +OUI:00165C* + ID_OUI_FROM_DATABASE=Trackflow Ltd + +OUI:00165D* + ID_OUI_FROM_DATABASE=AirDefense, Inc. + +OUI:00165E* + ID_OUI_FROM_DATABASE=Precision I/O + +OUI:00165F* + ID_OUI_FROM_DATABASE=Fairmount Automation + +OUI:001660* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001661* + ID_OUI_FROM_DATABASE=Novatium Solutions (P) Ltd + +OUI:001662* + ID_OUI_FROM_DATABASE=Liyuh Technology Ltd. + +OUI:001663* + ID_OUI_FROM_DATABASE=KBT Mobile + +OUI:001664* + ID_OUI_FROM_DATABASE=Prod-El SpA + +OUI:001665* + ID_OUI_FROM_DATABASE=Cellon France + +OUI:001666* + ID_OUI_FROM_DATABASE=Quantier Communication Inc. + +OUI:001667* + ID_OUI_FROM_DATABASE=A-TEC Subsystem INC. + +OUI:001668* + ID_OUI_FROM_DATABASE=Eishin Electronics + +OUI:001669* + ID_OUI_FROM_DATABASE=MRV Communication (Networks) LTD + +OUI:00166A* + ID_OUI_FROM_DATABASE=TPS + +OUI:00166B* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:00166C* + ID_OUI_FROM_DATABASE=Samsung Electonics Digital Video System Division + +OUI:00166D* + ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific(shenzhen)Co.,Lt + +OUI:00166E* + ID_OUI_FROM_DATABASE=Arbitron Inc. + +OUI:00166F* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001670* + ID_OUI_FROM_DATABASE=SKNET Corporation + +OUI:001671* + ID_OUI_FROM_DATABASE=Symphox Information Co. + +OUI:001672* + ID_OUI_FROM_DATABASE=Zenway enterprise ltd + +OUI:001673* + ID_OUI_FROM_DATABASE=Bury GmbH & Co. KG + +OUI:001674* + ID_OUI_FROM_DATABASE=EuroCB (Phils.), Inc. + +OUI:001675* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001676* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001677* + ID_OUI_FROM_DATABASE=Bihl + Wiedemann GmbH + +OUI:001678* + ID_OUI_FROM_DATABASE=SHENZHEN BAOAN GAOKE ELECTRONICS CO., LTD + +OUI:001679* + ID_OUI_FROM_DATABASE=eOn Communications + +OUI:00167A* + ID_OUI_FROM_DATABASE=Skyworth Overseas Dvelopment Ltd. + +OUI:00167B* + ID_OUI_FROM_DATABASE=Haver&Boecker + +OUI:00167C* + ID_OUI_FROM_DATABASE=iRex Technologies BV + +OUI:00167D* + ID_OUI_FROM_DATABASE=Sky-Line Information Co., Ltd. + +OUI:00167E* + ID_OUI_FROM_DATABASE=DIBOSS.CO.,LTD + +OUI:00167F* + ID_OUI_FROM_DATABASE=Bluebird Soft Inc. + +OUI:001680* + ID_OUI_FROM_DATABASE=Bally Gaming + Systems + +OUI:001681* + ID_OUI_FROM_DATABASE=Vector Informatik GmbH + +OUI:001682* + ID_OUI_FROM_DATABASE=Pro Dex, Inc + +OUI:001683* + ID_OUI_FROM_DATABASE=WEBIO International Co.,.Ltd. + +OUI:001684* + ID_OUI_FROM_DATABASE=Donjin Co.,Ltd. + +OUI:001685* + ID_OUI_FROM_DATABASE=Elisa Oyj + +OUI:001686* + ID_OUI_FROM_DATABASE=Karl Storz Imaging + +OUI:001687* + ID_OUI_FROM_DATABASE=Chubb CSC-Vendor AP + +OUI:001688* + ID_OUI_FROM_DATABASE=ServerEngines LLC + +OUI:001689* + ID_OUI_FROM_DATABASE=Pilkor Electronics Co., Ltd + +OUI:00168A* + ID_OUI_FROM_DATABASE=id-Confirm Inc + +OUI:00168B* + ID_OUI_FROM_DATABASE=Paralan Corporation + +OUI:00168C* + ID_OUI_FROM_DATABASE=DSL Partner AS + +OUI:00168D* + ID_OUI_FROM_DATABASE=KORWIN CO., Ltd. + +OUI:00168E* + ID_OUI_FROM_DATABASE=Vimicro corporation + +OUI:00168F* + ID_OUI_FROM_DATABASE=GN Netcom as + +OUI:001690* + ID_OUI_FROM_DATABASE=J-TEK INCORPORATION + +OUI:001691* + ID_OUI_FROM_DATABASE=Moser-Baer AG + +OUI:001692* + ID_OUI_FROM_DATABASE=Scientific-Atlanta, Inc. + +OUI:001693* + ID_OUI_FROM_DATABASE=PowerLink Technology Inc. + +OUI:001694* + ID_OUI_FROM_DATABASE=Sennheiser Communications A/S + +OUI:001695* + ID_OUI_FROM_DATABASE=AVC Technology (International) Limited + +OUI:001696* + ID_OUI_FROM_DATABASE=QDI Technology (H.K.) Limited + +OUI:001697* + ID_OUI_FROM_DATABASE=NEC Corporation + +OUI:001698* + ID_OUI_FROM_DATABASE=T&A Mobile Phones + +OUI:001699* + ID_OUI_FROM_DATABASE=Tonic DVB Marketing Ltd + +OUI:00169A* + ID_OUI_FROM_DATABASE=Quadrics Ltd + +OUI:00169B* + ID_OUI_FROM_DATABASE=Alstom Transport + +OUI:00169C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00169D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00169E* + ID_OUI_FROM_DATABASE=TV One Ltd + +OUI:00169F* + ID_OUI_FROM_DATABASE=Vimtron Electronics Co., Ltd. + +OUI:0016A0* + ID_OUI_FROM_DATABASE=Auto-Maskin + +OUI:0016A1* + ID_OUI_FROM_DATABASE=3Leaf Networks + +OUI:0016A2* + ID_OUI_FROM_DATABASE=CentraLite Systems, Inc. + +OUI:0016A3* + ID_OUI_FROM_DATABASE=Ingeteam Transmission&Distribution, S.A. + +OUI:0016A4* + ID_OUI_FROM_DATABASE=Ezurio Ltd + +OUI:0016A5* + ID_OUI_FROM_DATABASE=Tandberg Storage ASA + +OUI:0016A6* + ID_OUI_FROM_DATABASE=Dovado FZ-LLC + +OUI:0016A7* + ID_OUI_FROM_DATABASE=AWETA G&P + +OUI:0016A8* + ID_OUI_FROM_DATABASE=CWT CO., LTD. + +OUI:0016A9* + ID_OUI_FROM_DATABASE=2EI + +OUI:0016AA* + ID_OUI_FROM_DATABASE=Kei Communication Technology Inc. + +OUI:0016AB* + ID_OUI_FROM_DATABASE=PBI-Dansensor A/S + +OUI:0016AC* + ID_OUI_FROM_DATABASE=Toho Technology Corp. + +OUI:0016AD* + ID_OUI_FROM_DATABASE=BT-Links Company Limited + +OUI:0016AE* + ID_OUI_FROM_DATABASE=INVENTEL + +OUI:0016AF* + ID_OUI_FROM_DATABASE=Shenzhen Union Networks Equipment Co.,Ltd. + +OUI:0016B0* + ID_OUI_FROM_DATABASE=VK Corporation + +OUI:0016B1* + ID_OUI_FROM_DATABASE=KBS + +OUI:0016B2* + ID_OUI_FROM_DATABASE=DriveCam Inc + +OUI:0016B3* + ID_OUI_FROM_DATABASE=Photonicbridges (China) Co., Ltd. + +OUI:0016B5* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0016B6* + ID_OUI_FROM_DATABASE=Cisco-Linksys + +OUI:0016B7* + ID_OUI_FROM_DATABASE=Seoul Commtech + +OUI:0016B8* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:0016B9* + ID_OUI_FROM_DATABASE=ProCurve Networking + +OUI:0016BA* + ID_OUI_FROM_DATABASE=WEATHERNEWS INC. + +OUI:0016BB* + ID_OUI_FROM_DATABASE=Law-Chain Computer Technology Co Ltd + +OUI:0016BC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0016BD* + ID_OUI_FROM_DATABASE=ATI Industrial Automation + +OUI:0016BE* + ID_OUI_FROM_DATABASE=INFRANET, Inc. + +OUI:0016BF* + ID_OUI_FROM_DATABASE=PaloDEx Group Oy + +OUI:0016C0* + ID_OUI_FROM_DATABASE=Semtech Corporation + +OUI:0016C1* + ID_OUI_FROM_DATABASE=Eleksen Ltd + +OUI:0016C2* + ID_OUI_FROM_DATABASE=Avtec Systems Inc + +OUI:0016C3* + ID_OUI_FROM_DATABASE=BA Systems Inc + +OUI:0016C4* + ID_OUI_FROM_DATABASE=SiRF Technology, Inc. + +OUI:0016C5* + ID_OUI_FROM_DATABASE=Shenzhen Xing Feng Industry Co.,Ltd + +OUI:0016C6* + ID_OUI_FROM_DATABASE=North Atlantic Industries + +OUI:0016C7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0016C8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0016C9* + ID_OUI_FROM_DATABASE=NAT Seattle, Inc. + +OUI:0016CA* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0016CB* + ID_OUI_FROM_DATABASE=Apple + +OUI:0016CC* + ID_OUI_FROM_DATABASE=Xcute Mobile Corp. + +OUI:0016CD* + ID_OUI_FROM_DATABASE=HIJI HIGH-TECH CO., LTD. + +OUI:0016CE* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:0016CF* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:0016D0* + ID_OUI_FROM_DATABASE=ATech elektronika d.o.o. + +OUI:0016D1* + ID_OUI_FROM_DATABASE=ZAT a.s. + +OUI:0016D2* + ID_OUI_FROM_DATABASE=Caspian + +OUI:0016D3* + ID_OUI_FROM_DATABASE=Wistron Corporation + +OUI:0016D4* + ID_OUI_FROM_DATABASE=Compal Communications, Inc. + +OUI:0016D5* + ID_OUI_FROM_DATABASE=Synccom Co., Ltd + +OUI:0016D6* + ID_OUI_FROM_DATABASE=TDA Tech Pty Ltd + +OUI:0016D7* + ID_OUI_FROM_DATABASE=Sunways AG + +OUI:0016D8* + ID_OUI_FROM_DATABASE=Senea AB + +OUI:0016D9* + ID_OUI_FROM_DATABASE=NINGBO BIRD CO.,LTD. + +OUI:0016DA* + ID_OUI_FROM_DATABASE=Futronic Technology Co. Ltd. + +OUI:0016DB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:0016DC* + ID_OUI_FROM_DATABASE=ARCHOS + +OUI:0016DD* + ID_OUI_FROM_DATABASE=Gigabeam Corporation + +OUI:0016DE* + ID_OUI_FROM_DATABASE=FAST Inc + +OUI:0016DF* + ID_OUI_FROM_DATABASE=Lundinova AB + +OUI:0016E0* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:0016E1* + ID_OUI_FROM_DATABASE=SiliconStor, Inc. + +OUI:0016E2* + ID_OUI_FROM_DATABASE=American Fibertek, Inc. + +OUI:0016E3* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP. + +OUI:0016E4* + ID_OUI_FROM_DATABASE=VANGUARD SECURITY ENGINEERING CORP. + +OUI:0016E5* + ID_OUI_FROM_DATABASE=FORDLEY DEVELOPMENT LIMITED + +OUI:0016E6* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:0016E7* + ID_OUI_FROM_DATABASE=Dynamix Promotions Limited + +OUI:0016E8* + ID_OUI_FROM_DATABASE=Sigma Designs, Inc. + +OUI:0016E9* + ID_OUI_FROM_DATABASE=Tiba Medical Inc + +OUI:0016EA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0016EB* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0016EC* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. + +OUI:0016ED* + ID_OUI_FROM_DATABASE=Digital Safety Technologies, Inc + +OUI:0016EE* + ID_OUI_FROM_DATABASE=RoyalDigital Inc. + +OUI:0016EF* + ID_OUI_FROM_DATABASE=Koko Fitness, Inc. + +OUI:0016F0* + ID_OUI_FROM_DATABASE=Dell + +OUI:0016F1* + ID_OUI_FROM_DATABASE=OmniSense, LLC + +OUI:0016F2* + ID_OUI_FROM_DATABASE=Dmobile System Co., Ltd. + +OUI:0016F3* + ID_OUI_FROM_DATABASE=CAST Information Co., Ltd + +OUI:0016F4* + ID_OUI_FROM_DATABASE=Eidicom Co., Ltd. + +OUI:0016F5* + ID_OUI_FROM_DATABASE=Dalian Golden Hualu Digital Technology Co.,Ltd + +OUI:0016F6* + ID_OUI_FROM_DATABASE=Video Products Group + +OUI:0016F7* + ID_OUI_FROM_DATABASE=L-3 Communications, Aviation Recorders + +OUI:0016F8* + ID_OUI_FROM_DATABASE=AVIQTECH TECHNOLOGY CO., LTD. + +OUI:0016F9* + ID_OUI_FROM_DATABASE=CETRTA POT, d.o.o., Kranj + +OUI:0016FA* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:0016FB* + ID_OUI_FROM_DATABASE=SHENZHEN MTC CO.,LTD. + +OUI:0016FC* + ID_OUI_FROM_DATABASE=TOHKEN CO.,LTD. + +OUI:0016FD* + ID_OUI_FROM_DATABASE=Jaty Electronics + +OUI:0016FE* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:0016FF* + ID_OUI_FROM_DATABASE=Wamin Optocomm Mfg Corp + +OUI:001700* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001701* + ID_OUI_FROM_DATABASE=KDE, Inc. + +OUI:001702* + ID_OUI_FROM_DATABASE=Osung Midicom Co., Ltd + +OUI:001703* + ID_OUI_FROM_DATABASE=MOSDAN Internation Co.,Ltd + +OUI:001704* + ID_OUI_FROM_DATABASE=Shinco Electronics Group Co.,Ltd + +OUI:001705* + ID_OUI_FROM_DATABASE=Methode Electronics + +OUI:001706* + ID_OUI_FROM_DATABASE=Techfaith Wireless Communication Technology Limited. + +OUI:001707* + ID_OUI_FROM_DATABASE=InGrid, Inc + +OUI:001708* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001709* + ID_OUI_FROM_DATABASE=Exalt Communications + +OUI:00170A* + ID_OUI_FROM_DATABASE=INEW DIGITAL COMPANY + +OUI:00170B* + ID_OUI_FROM_DATABASE=Contela, Inc. + +OUI:00170C* + ID_OUI_FROM_DATABASE=Twig Com Ltd. + +OUI:00170D* + ID_OUI_FROM_DATABASE=Dust Networks Inc. + +OUI:00170E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00170F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001710* + ID_OUI_FROM_DATABASE=Casa Systems Inc. + +OUI:001711* + ID_OUI_FROM_DATABASE=GE Healthcare Bio-Sciences AB + +OUI:001712* + ID_OUI_FROM_DATABASE=ISCO International + +OUI:001713* + ID_OUI_FROM_DATABASE=Tiger NetCom + +OUI:001714* + ID_OUI_FROM_DATABASE=BR Controls Nederland bv + +OUI:001715* + ID_OUI_FROM_DATABASE=Qstik + +OUI:001716* + ID_OUI_FROM_DATABASE=Qno Technology Inc. + +OUI:001717* + ID_OUI_FROM_DATABASE=Leica Geosystems AG + +OUI:001718* + ID_OUI_FROM_DATABASE=Vansco Electronics Oy + +OUI:001719* + ID_OUI_FROM_DATABASE=AudioCodes USA, Inc + +OUI:00171A* + ID_OUI_FROM_DATABASE=Winegard Company + +OUI:00171B* + ID_OUI_FROM_DATABASE=Innovation Lab Corp. + +OUI:00171C* + ID_OUI_FROM_DATABASE=NT MicroSystems, Inc. + +OUI:00171D* + ID_OUI_FROM_DATABASE=DIGIT + +OUI:00171E* + ID_OUI_FROM_DATABASE=Theo Benning GmbH & Co. KG + +OUI:00171F* + ID_OUI_FROM_DATABASE=IMV Corporation + +OUI:001720* + ID_OUI_FROM_DATABASE=Image Sensing Systems, Inc. + +OUI:001721* + ID_OUI_FROM_DATABASE=FITRE S.p.A. + +OUI:001722* + ID_OUI_FROM_DATABASE=Hanazeder Electronic GmbH + +OUI:001723* + ID_OUI_FROM_DATABASE=Summit Data Communications + +OUI:001724* + ID_OUI_FROM_DATABASE=Studer Professional Audio GmbH + +OUI:001725* + ID_OUI_FROM_DATABASE=Liquid Computing + +OUI:001726* + ID_OUI_FROM_DATABASE=m2c Electronic Technology Ltd. + +OUI:001727* + ID_OUI_FROM_DATABASE=Thermo Ramsey Italia s.r.l. + +OUI:001728* + ID_OUI_FROM_DATABASE=Selex Communications + +OUI:001729* + ID_OUI_FROM_DATABASE=Ubicod Co.LTD + +OUI:00172A* + ID_OUI_FROM_DATABASE=Proware Technology Corp.(By Unifosa) + +OUI:00172B* + ID_OUI_FROM_DATABASE=Global Technologies Inc. + +OUI:00172C* + ID_OUI_FROM_DATABASE=TAEJIN INFOTECH + +OUI:00172D* + ID_OUI_FROM_DATABASE=Axcen Photonics Corporation + +OUI:00172E* + ID_OUI_FROM_DATABASE=FXC Inc. + +OUI:00172F* + ID_OUI_FROM_DATABASE=NeuLion Incorporated + +OUI:001730* + ID_OUI_FROM_DATABASE=Automation Electronics + +OUI:001731* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001732* + ID_OUI_FROM_DATABASE=Science-Technical Center "RISSA" + +OUI:001733* + ID_OUI_FROM_DATABASE=SFR + +OUI:001734* + ID_OUI_FROM_DATABASE=ADC Telecommunications + +OUI:001736* + ID_OUI_FROM_DATABASE=iiTron Inc. + +OUI:001737* + ID_OUI_FROM_DATABASE=Industrie Dial Face S.p.A. + +OUI:001738* + ID_OUI_FROM_DATABASE=International Business Machines + +OUI:001739* + ID_OUI_FROM_DATABASE=Bright Headphone Electronics Company + +OUI:00173A* + ID_OUI_FROM_DATABASE=Reach Systems Inc. + +OUI:00173B* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc. + +OUI:00173C* + ID_OUI_FROM_DATABASE=Extreme Engineering Solutions + +OUI:00173D* + ID_OUI_FROM_DATABASE=Neology + +OUI:00173E* + ID_OUI_FROM_DATABASE=LeucotronEquipamentos Ltda. + +OUI:00173F* + ID_OUI_FROM_DATABASE=Belkin Corporation + +OUI:001740* + ID_OUI_FROM_DATABASE=Bluberi Gaming Technologies Inc + +OUI:001741* + ID_OUI_FROM_DATABASE=DEFIDEV + +OUI:001742* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED + +OUI:001743* + ID_OUI_FROM_DATABASE=Deck Srl + +OUI:001744* + ID_OUI_FROM_DATABASE=Araneo Ltd. + +OUI:001745* + ID_OUI_FROM_DATABASE=INNOTZ CO., Ltd + +OUI:001746* + ID_OUI_FROM_DATABASE=Freedom9 Inc. + +OUI:001747* + ID_OUI_FROM_DATABASE=Trimble + +OUI:001748* + ID_OUI_FROM_DATABASE=Neokoros Brasil Ltda + +OUI:001749* + ID_OUI_FROM_DATABASE=HYUNDAE YONG-O-SA CO.,LTD + +OUI:00174A* + ID_OUI_FROM_DATABASE=SOCOMEC + +OUI:00174B* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00174C* + ID_OUI_FROM_DATABASE=Millipore + +OUI:00174D* + ID_OUI_FROM_DATABASE=DYNAMIC NETWORK FACTORY, INC. + +OUI:00174E* + ID_OUI_FROM_DATABASE=Parama-tech Co.,Ltd. + +OUI:00174F* + ID_OUI_FROM_DATABASE=iCatch Inc. + +OUI:001750* + ID_OUI_FROM_DATABASE=GSI Group, MicroE Systems + +OUI:001751* + ID_OUI_FROM_DATABASE=Online Corporation + +OUI:001752* + ID_OUI_FROM_DATABASE=DAGS, Inc + +OUI:001753* + ID_OUI_FROM_DATABASE=nFore Technology Inc. + +OUI:001754* + ID_OUI_FROM_DATABASE=Arkino HiTOP Corporation Limited + +OUI:001755* + ID_OUI_FROM_DATABASE=GE Security + +OUI:001756* + ID_OUI_FROM_DATABASE=Vinci Labs Oy + +OUI:001757* + ID_OUI_FROM_DATABASE=RIX TECHNOLOGY LIMITED + +OUI:001758* + ID_OUI_FROM_DATABASE=ThruVision Ltd + +OUI:001759* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00175A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00175B* + ID_OUI_FROM_DATABASE=ACS Solutions Switzerland Ltd. + +OUI:00175C* + ID_OUI_FROM_DATABASE=SHARP CORPORATION + +OUI:00175D* + ID_OUI_FROM_DATABASE=Dongseo system. + +OUI:00175E* + ID_OUI_FROM_DATABASE=Zed-3 + +OUI:00175F* + ID_OUI_FROM_DATABASE=XENOLINK Communications Co., Ltd. + +OUI:001760* + ID_OUI_FROM_DATABASE=Naito Densei Machida MFG.CO.,LTD + +OUI:001762* + ID_OUI_FROM_DATABASE=Solar Technology, Inc. + +OUI:001763* + ID_OUI_FROM_DATABASE=Essentia S.p.A. + +OUI:001764* + ID_OUI_FROM_DATABASE=ATMedia GmbH + +OUI:001765* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001766* + ID_OUI_FROM_DATABASE=Accense Technology, Inc. + +OUI:001767* + ID_OUI_FROM_DATABASE=Earforce AS + +OUI:001768* + ID_OUI_FROM_DATABASE=Zinwave Ltd + +OUI:001769* + ID_OUI_FROM_DATABASE=Cymphonix Corp + +OUI:00176A* + ID_OUI_FROM_DATABASE=Avago Technologies + +OUI:00176B* + ID_OUI_FROM_DATABASE=Kiyon, Inc. + +OUI:00176C* + ID_OUI_FROM_DATABASE=Pivot3, Inc. + +OUI:00176D* + ID_OUI_FROM_DATABASE=CORE CORPORATION + +OUI:00176E* + ID_OUI_FROM_DATABASE=DUCATI SISTEMI + +OUI:00176F* + ID_OUI_FROM_DATABASE=PAX Computer Technology(Shenzhen) Ltd. + +OUI:001770* + ID_OUI_FROM_DATABASE=Arti Industrial Electronics Ltd. + +OUI:001771* + ID_OUI_FROM_DATABASE=APD Communications Ltd + +OUI:001772* + ID_OUI_FROM_DATABASE=ASTRO Strobel Kommunikationssysteme GmbH + +OUI:001773* + ID_OUI_FROM_DATABASE=Laketune Technologies Co. Ltd + +OUI:001774* + ID_OUI_FROM_DATABASE=Elesta GmbH + +OUI:001775* + ID_OUI_FROM_DATABASE=TTE Germany GmbH + +OUI:001776* + ID_OUI_FROM_DATABASE=Meso Scale Diagnostics, LLC + +OUI:001777* + ID_OUI_FROM_DATABASE=Obsidian Research Corporation + +OUI:001778* + ID_OUI_FROM_DATABASE=Central Music Co. + +OUI:001779* + ID_OUI_FROM_DATABASE=QuickTel + +OUI:00177A* + ID_OUI_FROM_DATABASE=ASSA ABLOY AB + +OUI:00177B* + ID_OUI_FROM_DATABASE=Azalea Networks inc + +OUI:00177C* + ID_OUI_FROM_DATABASE=Smartlink Network Systems Limited + +OUI:00177D* + ID_OUI_FROM_DATABASE=IDT International Limited + +OUI:00177E* + ID_OUI_FROM_DATABASE=Meshcom Technologies Inc. + +OUI:00177F* + ID_OUI_FROM_DATABASE=Worldsmart Retech + +OUI:001780* + ID_OUI_FROM_DATABASE=Applied Biosystems B.V. + +OUI:001781* + ID_OUI_FROM_DATABASE=Greystone Data System, Inc. + +OUI:001782* + ID_OUI_FROM_DATABASE=LoBenn Inc. + +OUI:001783* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001784* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001785* + ID_OUI_FROM_DATABASE=Sparr Electronics Ltd + +OUI:001786* + ID_OUI_FROM_DATABASE=wisembed + +OUI:001787* + ID_OUI_FROM_DATABASE=Brother, Brother & Sons ApS + +OUI:001788* + ID_OUI_FROM_DATABASE=Philips Lighting BV + +OUI:001789* + ID_OUI_FROM_DATABASE=Zenitron Corporation + +OUI:00178A* + ID_OUI_FROM_DATABASE=DARTS TECHNOLOGIES CORP. + +OUI:00178B* + ID_OUI_FROM_DATABASE=Teledyne Technologies Incorporated + +OUI:00178C* + ID_OUI_FROM_DATABASE=Independent Witness, Inc + +OUI:00178D* + ID_OUI_FROM_DATABASE=Checkpoint Systems, Inc. + +OUI:00178E* + ID_OUI_FROM_DATABASE=Gunnebo Cash Automation AB + +OUI:00178F* + ID_OUI_FROM_DATABASE=NINGBO YIDONG ELECTRONIC CO.,LTD. + +OUI:001790* + ID_OUI_FROM_DATABASE=HYUNDAI DIGITECH Co, Ltd. + +OUI:001791* + ID_OUI_FROM_DATABASE=LinTech GmbH + +OUI:001792* + ID_OUI_FROM_DATABASE=Falcom Wireless Comunications Gmbh + +OUI:001793* + ID_OUI_FROM_DATABASE=Tigi Corporation + +OUI:001794* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001795* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001796* + ID_OUI_FROM_DATABASE=Rittmeyer AG + +OUI:001797* + ID_OUI_FROM_DATABASE=Telsy Elettronica S.p.A. + +OUI:001798* + ID_OUI_FROM_DATABASE=Azonic Technology Co., LTD + +OUI:001799* + ID_OUI_FROM_DATABASE=SmarTire Systems Inc. + +OUI:00179A* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:00179B* + ID_OUI_FROM_DATABASE=Chant Sincere CO., LTD. + +OUI:00179C* + ID_OUI_FROM_DATABASE=DEPRAG SCHULZ GMBH u. CO. + +OUI:00179D* + ID_OUI_FROM_DATABASE=Kelman Limited + +OUI:00179E* + ID_OUI_FROM_DATABASE=Sirit Inc + +OUI:00179F* + ID_OUI_FROM_DATABASE=Apricorn + +OUI:0017A0* + ID_OUI_FROM_DATABASE=RoboTech srl + +OUI:0017A1* + ID_OUI_FROM_DATABASE=3soft inc. + +OUI:0017A2* + ID_OUI_FROM_DATABASE=Camrivox Ltd. + +OUI:0017A3* + ID_OUI_FROM_DATABASE=MIX s.r.l. + +OUI:0017A4* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0017A5* + ID_OUI_FROM_DATABASE=Ralink Technology Corp + +OUI:0017A6* + ID_OUI_FROM_DATABASE=YOSIN ELECTRONICS CO., LTD. + +OUI:0017A7* + ID_OUI_FROM_DATABASE=Mobile Computing Promotion Consortium + +OUI:0017A8* + ID_OUI_FROM_DATABASE=EDM Corporation + +OUI:0017A9* + ID_OUI_FROM_DATABASE=Sentivision + +OUI:0017AA* + ID_OUI_FROM_DATABASE=elab-experience inc. + +OUI:0017AB* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0017AC* + ID_OUI_FROM_DATABASE=O'Neil Product Development Inc. + +OUI:0017AD* + ID_OUI_FROM_DATABASE=AceNet Corporation + +OUI:0017AE* + ID_OUI_FROM_DATABASE=GAI-Tronics + +OUI:0017AF* + ID_OUI_FROM_DATABASE=Enermet + +OUI:0017B0* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0017B1* + ID_OUI_FROM_DATABASE=ACIST Medical Systems, Inc. + +OUI:0017B2* + ID_OUI_FROM_DATABASE=SK Telesys + +OUI:0017B3* + ID_OUI_FROM_DATABASE=Aftek Infosys Limited + +OUI:0017B4* + ID_OUI_FROM_DATABASE=Remote Security Systems, LLC + +OUI:0017B5* + ID_OUI_FROM_DATABASE=Peerless Systems Corporation + +OUI:0017B6* + ID_OUI_FROM_DATABASE=Aquantia + +OUI:0017B7* + ID_OUI_FROM_DATABASE=Tonze Technology Co. + +OUI:0017B8* + ID_OUI_FROM_DATABASE=NOVATRON CO., LTD. + +OUI:0017B9* + ID_OUI_FROM_DATABASE=Gambro Lundia AB + +OUI:0017BA* + ID_OUI_FROM_DATABASE=SEDO CO., LTD. + +OUI:0017BB* + ID_OUI_FROM_DATABASE=Syrinx Industrial Electronics + +OUI:0017BC* + ID_OUI_FROM_DATABASE=Touchtunes Music Corporation + +OUI:0017BD* + ID_OUI_FROM_DATABASE=Tibetsystem + +OUI:0017BE* + ID_OUI_FROM_DATABASE=Tratec Telecom B.V. + +OUI:0017BF* + ID_OUI_FROM_DATABASE=Coherent Research Limited + +OUI:0017C0* + ID_OUI_FROM_DATABASE=PureTech Systems, Inc. + +OUI:0017C1* + ID_OUI_FROM_DATABASE=CM Precision Technology LTD. + +OUI:0017C2* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:0017C3* + ID_OUI_FROM_DATABASE=KTF Technologies Inc. + +OUI:0017C4* + ID_OUI_FROM_DATABASE=Quanta Microsystems, INC. + +OUI:0017C5* + ID_OUI_FROM_DATABASE=SonicWALL + +OUI:0017C6* + ID_OUI_FROM_DATABASE=Cross Match Technologies Inc + +OUI:0017C7* + ID_OUI_FROM_DATABASE=MARA Systems Consulting AB + +OUI:0017C8* + ID_OUI_FROM_DATABASE=KYOCERA Document Solutions Inc. + +OUI:0017C9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:0017CA* + ID_OUI_FROM_DATABASE=Qisda Corporation + +OUI:0017CB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0017CC* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:0017CD* + ID_OUI_FROM_DATABASE=CEC Wireless R&D Ltd. + +OUI:0017CE* + ID_OUI_FROM_DATABASE=Screen Service Spa + +OUI:0017CF* + ID_OUI_FROM_DATABASE=iMCA-GmbH + +OUI:0017D0* + ID_OUI_FROM_DATABASE=Opticom Communications, LLC + +OUI:0017D1* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0017D2* + ID_OUI_FROM_DATABASE=THINLINX PTY LTD + +OUI:0017D3* + ID_OUI_FROM_DATABASE=Etymotic Research, Inc. + +OUI:0017D4* + ID_OUI_FROM_DATABASE=Monsoon Multimedia, Inc + +OUI:0017D5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:0017D6* + ID_OUI_FROM_DATABASE=Bluechips Microhouse Co.,Ltd. + +OUI:0017D7* + ID_OUI_FROM_DATABASE=ION Geophysical Corporation Inc. + +OUI:0017D8* + ID_OUI_FROM_DATABASE=Magnum Semiconductor, Inc. + +OUI:0017D9* + ID_OUI_FROM_DATABASE=AAI Corporation + +OUI:0017DA* + ID_OUI_FROM_DATABASE=Spans Logic + +OUI:0017DB* + ID_OUI_FROM_DATABASE=CANKO TECHNOLOGIES INC. + +OUI:0017DC* + ID_OUI_FROM_DATABASE=DAEMYUNG ZERO1 + +OUI:0017DD* + ID_OUI_FROM_DATABASE=Clipsal Australia + +OUI:0017DE* + ID_OUI_FROM_DATABASE=Advantage Six Ltd + +OUI:0017DF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0017E0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0017E1* + ID_OUI_FROM_DATABASE=DACOS Technologies Co., Ltd. + +OUI:0017E2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0017E3* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E5* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E6* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E7* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E8* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017E9* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017EA* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017EB* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017EC* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0017ED* + ID_OUI_FROM_DATABASE=WooJooIT Ltd. + +OUI:0017EE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0017EF* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:0017F0* + ID_OUI_FROM_DATABASE=SZCOM Broadband Network Technology Co.,Ltd + +OUI:0017F1* + ID_OUI_FROM_DATABASE=Renu Electronics Pvt Ltd + +OUI:0017F2* + ID_OUI_FROM_DATABASE=Apple + +OUI:0017F3* + ID_OUI_FROM_DATABASE=Harris Corparation + +OUI:0017F4* + ID_OUI_FROM_DATABASE=ZERON ALLIANCE + +OUI:0017F5* + ID_OUI_FROM_DATABASE=LIG NEOPTEK + +OUI:0017F6* + ID_OUI_FROM_DATABASE=Pyramid Meriden Inc. + +OUI:0017F7* + ID_OUI_FROM_DATABASE=CEM Solutions Pvt Ltd + +OUI:0017F8* + ID_OUI_FROM_DATABASE=Motech Industries Inc. + +OUI:0017F9* + ID_OUI_FROM_DATABASE=Forcom Sp. z o.o. + +OUI:0017FA* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:0017FB* + ID_OUI_FROM_DATABASE=FA + +OUI:0017FC* + ID_OUI_FROM_DATABASE=Suprema Inc. + +OUI:0017FD* + ID_OUI_FROM_DATABASE=Amulet Hotkey + +OUI:0017FE* + ID_OUI_FROM_DATABASE=TALOS SYSTEM INC. + +OUI:0017FF* + ID_OUI_FROM_DATABASE=PLAYLINE Co.,Ltd. + +OUI:001800* + ID_OUI_FROM_DATABASE=UNIGRAND LTD + +OUI:001801* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:001802* + ID_OUI_FROM_DATABASE=Alpha Networks Inc. + +OUI:001803* + ID_OUI_FROM_DATABASE=ArcSoft Shanghai Co. LTD + +OUI:001804* + ID_OUI_FROM_DATABASE=E-TEK DIGITAL TECHNOLOGY LIMITED + +OUI:001805* + ID_OUI_FROM_DATABASE=Beijing InHand Networking Technology Co.,Ltd. + +OUI:001806* + ID_OUI_FROM_DATABASE=Hokkei Industries Co., Ltd. + +OUI:001807* + ID_OUI_FROM_DATABASE=Fanstel Corp. + +OUI:001808* + ID_OUI_FROM_DATABASE=SightLogix, Inc. + +OUI:001809* + ID_OUI_FROM_DATABASE=CRESYN + +OUI:00180A* + ID_OUI_FROM_DATABASE=Meraki, Inc. + +OUI:00180B* + ID_OUI_FROM_DATABASE=Brilliant Telecommunications + +OUI:00180C* + ID_OUI_FROM_DATABASE=Optelian Access Networks + +OUI:00180D* + ID_OUI_FROM_DATABASE=Terabytes Server Storage Tech Corp + +OUI:00180E* + ID_OUI_FROM_DATABASE=Avega Systems + +OUI:00180F* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001810* + ID_OUI_FROM_DATABASE=IPTrade S.A. + +OUI:001811* + ID_OUI_FROM_DATABASE=Neuros Technology International, LLC. + +OUI:001812* + ID_OUI_FROM_DATABASE=Beijing Xinwei Telecom Technology Co., Ltd. + +OUI:001813* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:001814* + ID_OUI_FROM_DATABASE=Mitutoyo Corporation + +OUI:001815* + ID_OUI_FROM_DATABASE=GZ Technologies, Inc. + +OUI:001816* + ID_OUI_FROM_DATABASE=Ubixon Co., Ltd. + +OUI:001817* + ID_OUI_FROM_DATABASE=D. E. Shaw Research, LLC + +OUI:001818* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001819* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00181A* + ID_OUI_FROM_DATABASE=AVerMedia Information Inc. + +OUI:00181B* + ID_OUI_FROM_DATABASE=TaiJin Metal Co., Ltd. + +OUI:00181C* + ID_OUI_FROM_DATABASE=Exterity Limited + +OUI:00181D* + ID_OUI_FROM_DATABASE=ASIA ELECTRONICS CO.,LTD + +OUI:00181E* + ID_OUI_FROM_DATABASE=GDX Technologies Ltd. + +OUI:00181F* + ID_OUI_FROM_DATABASE=Palmmicro Communications + +OUI:001820* + ID_OUI_FROM_DATABASE=w5networks + +OUI:001821* + ID_OUI_FROM_DATABASE=SINDORICOH + +OUI:001822* + ID_OUI_FROM_DATABASE=CEC TELECOM CO.,LTD. + +OUI:001823* + ID_OUI_FROM_DATABASE=Delta Electronics, Inc. + +OUI:001824* + ID_OUI_FROM_DATABASE=Kimaldi Electronics, S.L. + +OUI:001826* + ID_OUI_FROM_DATABASE=Cale Access AB + +OUI:001827* + ID_OUI_FROM_DATABASE=NEC UNIFIED SOLUTIONS NEDERLAND B.V. + +OUI:001828* + ID_OUI_FROM_DATABASE=e2v technologies (UK) ltd. + +OUI:001829* + ID_OUI_FROM_DATABASE=Gatsometer + +OUI:00182A* + ID_OUI_FROM_DATABASE=Taiwan Video & Monitor + +OUI:00182B* + ID_OUI_FROM_DATABASE=Softier + +OUI:00182C* + ID_OUI_FROM_DATABASE=Ascend Networks, Inc. + +OUI:00182D* + ID_OUI_FROM_DATABASE=Artec Design + +OUI:00182E* + ID_OUI_FROM_DATABASE=XStreamHD, LLC + +OUI:00182F* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001830* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001831* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001832* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001833* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001834* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001835* + ID_OUI_FROM_DATABASE=Thoratec / ITC + +OUI:001836* + ID_OUI_FROM_DATABASE=Reliance Electric Limited + +OUI:001837* + ID_OUI_FROM_DATABASE=Universal ABIT Co., Ltd. + +OUI:001838* + ID_OUI_FROM_DATABASE=PanAccess Communications,Inc. + +OUI:001839* + ID_OUI_FROM_DATABASE=Cisco-Linksys LLC + +OUI:00183A* + ID_OUI_FROM_DATABASE=Westell Technologies + +OUI:00183B* + ID_OUI_FROM_DATABASE=CENITS Co., Ltd. + +OUI:00183C* + ID_OUI_FROM_DATABASE=Encore Software Limited + +OUI:00183D* + ID_OUI_FROM_DATABASE=Vertex Link Corporation + +OUI:00183E* + ID_OUI_FROM_DATABASE=Digilent, Inc + +OUI:00183F* + ID_OUI_FROM_DATABASE=2Wire, Inc + +OUI:001840* + ID_OUI_FROM_DATABASE=3 Phoenix, Inc. + +OUI:001841* + ID_OUI_FROM_DATABASE=High Tech Computer Corp + +OUI:001842* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001843* + ID_OUI_FROM_DATABASE=Dawevision Ltd + +OUI:001844* + ID_OUI_FROM_DATABASE=Heads Up Technologies, Inc. + +OUI:001845* + ID_OUI_FROM_DATABASE=Pulsar-Telecom LLC. + +OUI:001846* + ID_OUI_FROM_DATABASE=Crypto S.A. + +OUI:001847* + ID_OUI_FROM_DATABASE=AceNet Technology Inc. + +OUI:001848* + ID_OUI_FROM_DATABASE=Vecima Networks Inc. + +OUI:001849* + ID_OUI_FROM_DATABASE=Pigeon Point Systems LLC + +OUI:00184A* + ID_OUI_FROM_DATABASE=Catcher, Inc. + +OUI:00184B* + ID_OUI_FROM_DATABASE=Las Vegas Gaming, Inc. + +OUI:00184C* + ID_OUI_FROM_DATABASE=Bogen Communications + +OUI:00184D* + ID_OUI_FROM_DATABASE=Netgear Inc. + +OUI:00184E* + ID_OUI_FROM_DATABASE=Lianhe Technologies, Inc. + +OUI:00184F* + ID_OUI_FROM_DATABASE=8 Ways Technology Corp. + +OUI:001850* + ID_OUI_FROM_DATABASE=Secfone Kft + +OUI:001851* + ID_OUI_FROM_DATABASE=SWsoft + +OUI:001852* + ID_OUI_FROM_DATABASE=StorLink Semiconductors, Inc. + +OUI:001853* + ID_OUI_FROM_DATABASE=Atera Networks LTD. + +OUI:001854* + ID_OUI_FROM_DATABASE=Argard Co., Ltd + +OUI:001855* + ID_OUI_FROM_DATABASE=Aeromaritime Systembau GmbH + +OUI:001856* + ID_OUI_FROM_DATABASE=EyeFi, Inc + +OUI:001857* + ID_OUI_FROM_DATABASE=Unilever R&D + +OUI:001858* + ID_OUI_FROM_DATABASE=TagMaster AB + +OUI:001859* + ID_OUI_FROM_DATABASE=Strawberry Linux Co.,Ltd. + +OUI:00185A* + ID_OUI_FROM_DATABASE=uControl, Inc. + +OUI:00185B* + ID_OUI_FROM_DATABASE=Network Chemistry, Inc + +OUI:00185C* + ID_OUI_FROM_DATABASE=EDS Lab Pte Ltd + +OUI:00185D* + ID_OUI_FROM_DATABASE=TAIGUEN TECHNOLOGY (SHEN-ZHEN) CO., LTD. + +OUI:00185E* + ID_OUI_FROM_DATABASE=Nexterm Inc. + +OUI:00185F* + ID_OUI_FROM_DATABASE=TAC Inc. + +OUI:001860* + ID_OUI_FROM_DATABASE=SIM Technology Group Shanghai Simcom Ltd., + +OUI:001861* + ID_OUI_FROM_DATABASE=Ooma, Inc. + +OUI:001862* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:001863* + ID_OUI_FROM_DATABASE=Veritech Electronics Limited + +OUI:001864* + ID_OUI_FROM_DATABASE=Eaton Corporation + +OUI:001865* + ID_OUI_FROM_DATABASE=Siemens Healthcare Diagnostics Manufacturing Ltd + +OUI:001866* + ID_OUI_FROM_DATABASE=Leutron Vision + +OUI:001867* + ID_OUI_FROM_DATABASE=Datalogic ADC + +OUI:001868* + ID_OUI_FROM_DATABASE=Scientific Atlanta, A Cisco Company + +OUI:001869* + ID_OUI_FROM_DATABASE=KINGJIM + +OUI:00186A* + ID_OUI_FROM_DATABASE=Global Link Digital Technology Co,.LTD + +OUI:00186B* + ID_OUI_FROM_DATABASE=Sambu Communics CO., LTD. + +OUI:00186C* + ID_OUI_FROM_DATABASE=Neonode AB + +OUI:00186D* + ID_OUI_FROM_DATABASE=Zhenjiang Sapphire Electronic Industry CO. + +OUI:00186E* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:00186F* + ID_OUI_FROM_DATABASE=Setha Industria Eletronica LTDA + +OUI:001870* + ID_OUI_FROM_DATABASE=E28 Shanghai Limited + +OUI:001871* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001872* + ID_OUI_FROM_DATABASE=Expertise Engineering + +OUI:001873* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001874* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001875* + ID_OUI_FROM_DATABASE=AnaCise Testnology Pte Ltd + +OUI:001876* + ID_OUI_FROM_DATABASE=WowWee Ltd. + +OUI:001877* + ID_OUI_FROM_DATABASE=Amplex A/S + +OUI:001878* + ID_OUI_FROM_DATABASE=Mackware GmbH + +OUI:001879* + ID_OUI_FROM_DATABASE=dSys + +OUI:00187A* + ID_OUI_FROM_DATABASE=Wiremold + +OUI:00187B* + ID_OUI_FROM_DATABASE=4NSYS Co. Ltd. + +OUI:00187C* + ID_OUI_FROM_DATABASE=INTERCROSS, LLC + +OUI:00187D* + ID_OUI_FROM_DATABASE=Armorlink shanghai Co. Ltd + +OUI:00187E* + ID_OUI_FROM_DATABASE=RGB Spectrum + +OUI:00187F* + ID_OUI_FROM_DATABASE=ZODIANET + +OUI:001880* + ID_OUI_FROM_DATABASE=Maxim Integrated Products + +OUI:001881* + ID_OUI_FROM_DATABASE=Buyang Electronics Industrial Co., Ltd + +OUI:001882* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd. + +OUI:001883* + ID_OUI_FROM_DATABASE=FORMOSA21 INC. + +OUI:001884* + ID_OUI_FROM_DATABASE=Fon Technology S.L. + +OUI:001885* + ID_OUI_FROM_DATABASE=Avigilon Corporation + +OUI:001886* + ID_OUI_FROM_DATABASE=EL-TECH, INC. + +OUI:001887* + ID_OUI_FROM_DATABASE=Metasystem SpA + +OUI:001888* + ID_OUI_FROM_DATABASE=GOTIVE a.s. + +OUI:001889* + ID_OUI_FROM_DATABASE=WinNet Solutions Limited + +OUI:00188A* + ID_OUI_FROM_DATABASE=Infinova LLC + +OUI:00188B* + ID_OUI_FROM_DATABASE=Dell ESG PCBA Test + +OUI:00188C* + ID_OUI_FROM_DATABASE=Mobile Action Technology Inc. + +OUI:00188D* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00188E* + ID_OUI_FROM_DATABASE=Ekahau, Inc. + +OUI:00188F* + ID_OUI_FROM_DATABASE=Montgomery Technology, Inc. + +OUI:001890* + ID_OUI_FROM_DATABASE=RadioCOM, s.r.o. + +OUI:001891* + ID_OUI_FROM_DATABASE=Zhongshan General K-mate Electronics Co., Ltd + +OUI:001892* + ID_OUI_FROM_DATABASE=ads-tec GmbH + +OUI:001893* + ID_OUI_FROM_DATABASE=SHENZHEN PHOTON BROADBAND TECHNOLOGY CO.,LTD + +OUI:001894* + ID_OUI_FROM_DATABASE=zimocom + +OUI:001895* + ID_OUI_FROM_DATABASE=Hansun Technologies Inc. + +OUI:001896* + ID_OUI_FROM_DATABASE=Great Well Electronic LTD + +OUI:001897* + ID_OUI_FROM_DATABASE=JESS-LINK PRODUCTS Co., LTD + +OUI:001898* + ID_OUI_FROM_DATABASE=KINGSTATE ELECTRONICS CORPORATION + +OUI:001899* + ID_OUI_FROM_DATABASE=ShenZhen jieshun Science&Technology Industry CO,LTD. + +OUI:00189A* + ID_OUI_FROM_DATABASE=HANA Micron Inc. + +OUI:00189B* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:00189C* + ID_OUI_FROM_DATABASE=Weldex Corporation + +OUI:00189D* + ID_OUI_FROM_DATABASE=Navcast Inc. + +OUI:00189E* + ID_OUI_FROM_DATABASE=OMNIKEY GmbH. + +OUI:00189F* + ID_OUI_FROM_DATABASE=Lenntek Corporation + +OUI:0018A0* + ID_OUI_FROM_DATABASE=Cierma Ascenseurs + +OUI:0018A1* + ID_OUI_FROM_DATABASE=Tiqit Computers, Inc. + +OUI:0018A2* + ID_OUI_FROM_DATABASE=XIP Technology AB + +OUI:0018A3* + ID_OUI_FROM_DATABASE=ZIPPY TECHNOLOGY CORP. + +OUI:0018A4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0018A5* + ID_OUI_FROM_DATABASE=ADigit Technologies Corp. + +OUI:0018A6* + ID_OUI_FROM_DATABASE=Persistent Systems, LLC + +OUI:0018A7* + ID_OUI_FROM_DATABASE=Yoggie Security Systems LTD. + +OUI:0018A8* + ID_OUI_FROM_DATABASE=AnNeal Technology Inc. + +OUI:0018A9* + ID_OUI_FROM_DATABASE=Ethernet Direct Corporation + +OUI:0018AA* + ID_OUI_FROM_DATABASE=Protec Fire Detection plc + +OUI:0018AB* + ID_OUI_FROM_DATABASE=BEIJING LHWT MICROELECTRONICS INC. + +OUI:0018AC* + ID_OUI_FROM_DATABASE=Shanghai Jiao Da HISYS Technology Co. Ltd. + +OUI:0018AD* + ID_OUI_FROM_DATABASE=NIDEC SANKYO CORPORATION + +OUI:0018AE* + ID_OUI_FROM_DATABASE=TVT CO.,LTD + +OUI:0018AF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:0018B0* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0018B1* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:0018B2* + ID_OUI_FROM_DATABASE=ADEUNIS RF + +OUI:0018B3* + ID_OUI_FROM_DATABASE=TEC WizHome Co., Ltd. + +OUI:0018B4* + ID_OUI_FROM_DATABASE=Dawon Media Inc. + +OUI:0018B5* + ID_OUI_FROM_DATABASE=Magna Carta + +OUI:0018B6* + ID_OUI_FROM_DATABASE=S3C, Inc. + +OUI:0018B7* + ID_OUI_FROM_DATABASE=D3 LED, LLC + +OUI:0018B8* + ID_OUI_FROM_DATABASE=New Voice International AG + +OUI:0018B9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0018BA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0018BB* + ID_OUI_FROM_DATABASE=Eliwell Controls srl + +OUI:0018BC* + ID_OUI_FROM_DATABASE=ZAO NVP Bolid + +OUI:0018BD* + ID_OUI_FROM_DATABASE=SHENZHEN DVBWORLD TECHNOLOGY CO., LTD. + +OUI:0018BE* + ID_OUI_FROM_DATABASE=ANSA Corporation + +OUI:0018BF* + ID_OUI_FROM_DATABASE=Essence Technology Solution, Inc. + +OUI:0018C0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0018C1* + ID_OUI_FROM_DATABASE=Almitec Informática e Comércio + +OUI:0018C2* + ID_OUI_FROM_DATABASE=Firetide, Inc + +OUI:0018C3* + ID_OUI_FROM_DATABASE=CS Corporation + +OUI:0018C4* + ID_OUI_FROM_DATABASE=Raba Technologies LLC + +OUI:0018C5* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0018C6* + ID_OUI_FROM_DATABASE=OPW Fuel Management Systems + +OUI:0018C7* + ID_OUI_FROM_DATABASE=Real Time Automation + +OUI:0018C8* + ID_OUI_FROM_DATABASE=ISONAS Inc. + +OUI:0018C9* + ID_OUI_FROM_DATABASE=EOps Technology Limited + +OUI:0018CA* + ID_OUI_FROM_DATABASE=Viprinet GmbH + +OUI:0018CB* + ID_OUI_FROM_DATABASE=Tecobest Technology Limited + +OUI:0018CC* + ID_OUI_FROM_DATABASE=AXIOHM SAS + +OUI:0018CD* + ID_OUI_FROM_DATABASE=Erae Electronics Industry Co., Ltd + +OUI:0018CE* + ID_OUI_FROM_DATABASE=Dreamtech Co., Ltd + +OUI:0018CF* + ID_OUI_FROM_DATABASE=Baldor Electric Company + +OUI:0018D0* + ID_OUI_FROM_DATABASE=AtRoad, A Trimble Company + +OUI:0018D1* + ID_OUI_FROM_DATABASE=Siemens Home & Office Comm. Devices + +OUI:0018D2* + ID_OUI_FROM_DATABASE=High-Gain Antennas LLC + +OUI:0018D3* + ID_OUI_FROM_DATABASE=TEAMCAST + +OUI:0018D4* + ID_OUI_FROM_DATABASE=Unified Display Interface SIG + +OUI:0018D5* + ID_OUI_FROM_DATABASE=REIGNCOM + +OUI:0018D6* + ID_OUI_FROM_DATABASE=Swirlnet A/S + +OUI:0018D7* + ID_OUI_FROM_DATABASE=Javad Navigation Systems Inc. + +OUI:0018D8* + ID_OUI_FROM_DATABASE=ARCH METER Corporation + +OUI:0018D9* + ID_OUI_FROM_DATABASE=Santosha Internatonal, Inc + +OUI:0018DA* + ID_OUI_FROM_DATABASE=AMBER wireless GmbH + +OUI:0018DB* + ID_OUI_FROM_DATABASE=EPL Technology Ltd + +OUI:0018DC* + ID_OUI_FROM_DATABASE=Prostar Co., Ltd. + +OUI:0018DD* + ID_OUI_FROM_DATABASE=Silicondust Engineering Ltd + +OUI:0018DE* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0018DF* + ID_OUI_FROM_DATABASE=The Morey Corporation + +OUI:0018E0* + ID_OUI_FROM_DATABASE=ANAVEO + +OUI:0018E1* + ID_OUI_FROM_DATABASE=Verkerk Service Systemen + +OUI:0018E2* + ID_OUI_FROM_DATABASE=Topdata Sistemas de Automacao Ltda + +OUI:0018E3* + ID_OUI_FROM_DATABASE=Visualgate Systems, Inc. + +OUI:0018E4* + ID_OUI_FROM_DATABASE=YIGUANG + +OUI:0018E5* + ID_OUI_FROM_DATABASE=Adhoco AG + +OUI:0018E6* + ID_OUI_FROM_DATABASE=Computer Hardware Design SIA + +OUI:0018E7* + ID_OUI_FROM_DATABASE=Cameo Communications, INC. + +OUI:0018E8* + ID_OUI_FROM_DATABASE=Hacetron Corporation + +OUI:0018E9* + ID_OUI_FROM_DATABASE=Numata Corporation + +OUI:0018EA* + ID_OUI_FROM_DATABASE=Alltec GmbH + +OUI:0018EB* + ID_OUI_FROM_DATABASE=BroVis Wireless Networks + +OUI:0018EC* + ID_OUI_FROM_DATABASE=Welding Technology Corporation + +OUI:0018ED* + ID_OUI_FROM_DATABASE=Accutech Ultrasystems Co., Ltd. + +OUI:0018EE* + ID_OUI_FROM_DATABASE=Videology Imaging Solutions, Inc. + +OUI:0018EF* + ID_OUI_FROM_DATABASE=Escape Communications, Inc. + +OUI:0018F0* + ID_OUI_FROM_DATABASE=JOYTOTO Co., Ltd. + +OUI:0018F1* + ID_OUI_FROM_DATABASE=Chunichi Denshi Co.,LTD. + +OUI:0018F2* + ID_OUI_FROM_DATABASE=Beijing Tianyu Communication Equipment Co., Ltd + +OUI:0018F3* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:0018F4* + ID_OUI_FROM_DATABASE=EO TECHNICS Co., Ltd. + +OUI:0018F5* + ID_OUI_FROM_DATABASE=Shenzhen Streaming Video Technology Company Limited + +OUI:0018F6* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:0018F7* + ID_OUI_FROM_DATABASE=Kameleon Technologies + +OUI:0018F8* + ID_OUI_FROM_DATABASE=Cisco-Linksys LLC + +OUI:0018F9* + ID_OUI_FROM_DATABASE=VVOND, Inc. + +OUI:0018FA* + ID_OUI_FROM_DATABASE=Yushin Precision Equipment Co.,Ltd. + +OUI:0018FB* + ID_OUI_FROM_DATABASE=Compro Technology + +OUI:0018FC* + ID_OUI_FROM_DATABASE=Altec Electronic AG + +OUI:0018FD* + ID_OUI_FROM_DATABASE=Optimal Technologies International Inc. + +OUI:0018FE* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0018FF* + ID_OUI_FROM_DATABASE=PowerQuattro Co. + +OUI:001900* + ID_OUI_FROM_DATABASE=Intelliverese - DBA Voicecom + +OUI:001901* + ID_OUI_FROM_DATABASE=F1MEDIA + +OUI:001902* + ID_OUI_FROM_DATABASE=Cambridge Consultants Ltd + +OUI:001903* + ID_OUI_FROM_DATABASE=Bigfoot Networks Inc + +OUI:001904* + ID_OUI_FROM_DATABASE=WB Electronics Sp. z o.o. + +OUI:001905* + ID_OUI_FROM_DATABASE=SCHRACK Seconet AG + +OUI:001906* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001907* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001908* + ID_OUI_FROM_DATABASE=Duaxes Corporation + +OUI:001909* + ID_OUI_FROM_DATABASE=DEVI - Danfoss A/S + +OUI:00190A* + ID_OUI_FROM_DATABASE=HASWARE INC. + +OUI:00190B* + ID_OUI_FROM_DATABASE=Southern Vision Systems, Inc. + +OUI:00190C* + ID_OUI_FROM_DATABASE=Encore Electronics, Inc. + +OUI:00190D* + ID_OUI_FROM_DATABASE=IEEE 1394c + +OUI:00190E* + ID_OUI_FROM_DATABASE=Atech Technology Co., Ltd. + +OUI:00190F* + ID_OUI_FROM_DATABASE=Advansus Corp. + +OUI:001910* + ID_OUI_FROM_DATABASE=Knick Elektronische Messgeraete GmbH & Co. KG + +OUI:001911* + ID_OUI_FROM_DATABASE=Just In Mobile Information Technologies (Shanghai) Co., Ltd. + +OUI:001912* + ID_OUI_FROM_DATABASE=Welcat Inc + +OUI:001913* + ID_OUI_FROM_DATABASE=Chuang-Yi Network Equipment Co.Ltd. + +OUI:001914* + ID_OUI_FROM_DATABASE=Winix Co., Ltd + +OUI:001915* + ID_OUI_FROM_DATABASE=TECOM Co., Ltd. + +OUI:001916* + ID_OUI_FROM_DATABASE=PayTec AG + +OUI:001917* + ID_OUI_FROM_DATABASE=Posiflex Inc. + +OUI:001918* + ID_OUI_FROM_DATABASE=Interactive Wear AG + +OUI:001919* + ID_OUI_FROM_DATABASE=ASTEL Inc. + +OUI:00191A* + ID_OUI_FROM_DATABASE=IRLINK + +OUI:00191B* + ID_OUI_FROM_DATABASE=Sputnik Engineering AG + +OUI:00191C* + ID_OUI_FROM_DATABASE=Sensicast Systems + +OUI:00191D* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:00191E* + ID_OUI_FROM_DATABASE=Beyondwiz Co., Ltd. + +OUI:00191F* + ID_OUI_FROM_DATABASE=Microlink communications Inc. + +OUI:001920* + ID_OUI_FROM_DATABASE=KUME electric Co.,Ltd. + +OUI:001921* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. + +OUI:001922* + ID_OUI_FROM_DATABASE=CM Comandos Lineares + +OUI:001923* + ID_OUI_FROM_DATABASE=Phonex Korea Co., LTD. + +OUI:001924* + ID_OUI_FROM_DATABASE=LBNL Engineering + +OUI:001925* + ID_OUI_FROM_DATABASE=Intelicis Corporation + +OUI:001926* + ID_OUI_FROM_DATABASE=BitsGen Co., Ltd. + +OUI:001927* + ID_OUI_FROM_DATABASE=ImCoSys Ltd + +OUI:001928* + ID_OUI_FROM_DATABASE=Siemens AG, Transportation Systems + +OUI:001929* + ID_OUI_FROM_DATABASE=2M2B Montadora de Maquinas Bahia Brasil LTDA + +OUI:00192A* + ID_OUI_FROM_DATABASE=Antiope Associates + +OUI:00192B* + ID_OUI_FROM_DATABASE=Aclara RF Systems Inc. + +OUI:00192C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00192D* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:00192E* + ID_OUI_FROM_DATABASE=Spectral Instruments, Inc. + +OUI:00192F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001930* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001931* + ID_OUI_FROM_DATABASE=Balluff GmbH + +OUI:001932* + ID_OUI_FROM_DATABASE=Gude Analog- und Digialsysteme GmbH + +OUI:001933* + ID_OUI_FROM_DATABASE=Strix Systems, Inc. + +OUI:001934* + ID_OUI_FROM_DATABASE=TRENDON TOUCH TECHNOLOGY CORP. + +OUI:001935* + ID_OUI_FROM_DATABASE=DUERR DENTAL AG + +OUI:001936* + ID_OUI_FROM_DATABASE=STERLITE OPTICAL TECHNOLOGIES LIMITED + +OUI:001937* + ID_OUI_FROM_DATABASE=CommerceGuard AB + +OUI:001938* + ID_OUI_FROM_DATABASE=UMB Communications Co., Ltd. + +OUI:001939* + ID_OUI_FROM_DATABASE=Gigamips + +OUI:00193A* + ID_OUI_FROM_DATABASE=OESOLUTIONS + +OUI:00193B* + ID_OUI_FROM_DATABASE=Wilibox Deliberant Group LLC + +OUI:00193C* + ID_OUI_FROM_DATABASE=HighPoint Technologies Incorporated + +OUI:00193D* + ID_OUI_FROM_DATABASE=GMC Guardian Mobility Corp. + +OUI:00193E* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:00193F* + ID_OUI_FROM_DATABASE=RDI technology(Shenzhen) Co.,LTD + +OUI:001940* + ID_OUI_FROM_DATABASE=Rackable Systems + +OUI:001941* + ID_OUI_FROM_DATABASE=Pitney Bowes, Inc + +OUI:001942* + ID_OUI_FROM_DATABASE=ON SOFTWARE INTERNATIONAL LIMITED + +OUI:001943* + ID_OUI_FROM_DATABASE=Belden + +OUI:001944* + ID_OUI_FROM_DATABASE=Fossil Partners, L.P. + +OUI:001945* + ID_OUI_FROM_DATABASE=Ten-Tec Inc. + +OUI:001946* + ID_OUI_FROM_DATABASE=Cianet Industria e Comercio S/A + +OUI:001947* + ID_OUI_FROM_DATABASE=Scientific Atlanta, A Cisco Company + +OUI:001948* + ID_OUI_FROM_DATABASE=AireSpider Networks + +OUI:001949* + ID_OUI_FROM_DATABASE=TENTEL COMTECH CO., LTD. + +OUI:00194A* + ID_OUI_FROM_DATABASE=TESTO AG + +OUI:00194B* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:00194C* + ID_OUI_FROM_DATABASE=Fujian Stelcom information & Technology CO.,Ltd + +OUI:00194D* + ID_OUI_FROM_DATABASE=Avago Technologies Sdn Bhd + +OUI:00194E* + ID_OUI_FROM_DATABASE=Ultra Electronics - TCS (Tactical Communication Systems) + +OUI:00194F* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001950* + ID_OUI_FROM_DATABASE=Harman Multimedia + +OUI:001951* + ID_OUI_FROM_DATABASE=NETCONS, s.r.o. + +OUI:001952* + ID_OUI_FROM_DATABASE=ACOGITO Co., Ltd + +OUI:001953* + ID_OUI_FROM_DATABASE=Chainleader Communications Corp. + +OUI:001954* + ID_OUI_FROM_DATABASE=Leaf Corporation. + +OUI:001955* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001956* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001957* + ID_OUI_FROM_DATABASE=Saafnet Canada Inc. + +OUI:001958* + ID_OUI_FROM_DATABASE=Bluetooth SIG, Inc. + +OUI:001959* + ID_OUI_FROM_DATABASE=Staccato Communications Inc. + +OUI:00195A* + ID_OUI_FROM_DATABASE=Jenaer Antriebstechnik GmbH + +OUI:00195B* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:00195C* + ID_OUI_FROM_DATABASE=Innotech Corporation + +OUI:00195D* + ID_OUI_FROM_DATABASE=ShenZhen XinHuaTong Opto Electronics Co.,Ltd + +OUI:00195E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00195F* + ID_OUI_FROM_DATABASE=Valemount Networks Corporation + +OUI:001960* + ID_OUI_FROM_DATABASE=DoCoMo Systems, Inc. + +OUI:001961* + ID_OUI_FROM_DATABASE=Blaupunkt Embedded Systems GmbH + +OUI:001962* + ID_OUI_FROM_DATABASE=Commerciant, LP + +OUI:001963* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:001964* + ID_OUI_FROM_DATABASE=Doorking Inc. + +OUI:001965* + ID_OUI_FROM_DATABASE=YuHua TelTech (ShangHai) Co., Ltd. + +OUI:001966* + ID_OUI_FROM_DATABASE=Asiarock Technology Limited + +OUI:001967* + ID_OUI_FROM_DATABASE=TELDAT Sp.J. + +OUI:001968* + ID_OUI_FROM_DATABASE=Digital Video Networks(Shanghai) CO. LTD. + +OUI:001969* + ID_OUI_FROM_DATABASE=Nortel + +OUI:00196A* + ID_OUI_FROM_DATABASE=MikroM GmbH + +OUI:00196B* + ID_OUI_FROM_DATABASE=Danpex Corporation + +OUI:00196C* + ID_OUI_FROM_DATABASE=ETROVISION TECHNOLOGY + +OUI:00196D* + ID_OUI_FROM_DATABASE=Raybit Systems Korea, Inc + +OUI:00196E* + ID_OUI_FROM_DATABASE=Metacom (Pty) Ltd. + +OUI:00196F* + ID_OUI_FROM_DATABASE=SensoPart GmbH + +OUI:001970* + ID_OUI_FROM_DATABASE=Z-Com, Inc. + +OUI:001971* + ID_OUI_FROM_DATABASE=Guangzhou Unicomp Technology Co.,Ltd + +OUI:001972* + ID_OUI_FROM_DATABASE=Plexus (Xiamen) Co.,ltd + +OUI:001973* + ID_OUI_FROM_DATABASE=Zeugma Systems + +OUI:001974* + ID_OUI_FROM_DATABASE=AboCom Systems, Inc. + +OUI:001975* + ID_OUI_FROM_DATABASE=Beijing Huisen networks technology Inc + +OUI:001976* + ID_OUI_FROM_DATABASE=Xipher Technologies, LLC + +OUI:001977* + ID_OUI_FROM_DATABASE=Aerohive Networks, Inc. + +OUI:001978* + ID_OUI_FROM_DATABASE=Datum Systems, Inc. + +OUI:001979* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00197A* + ID_OUI_FROM_DATABASE=MAZeT GmbH + +OUI:00197B* + ID_OUI_FROM_DATABASE=Picotest Corp. + +OUI:00197C* + ID_OUI_FROM_DATABASE=Riedel Communications GmbH + +OUI:00197D* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd + +OUI:00197E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd + +OUI:00197F* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:001980* + ID_OUI_FROM_DATABASE=Gridpoint Systems + +OUI:001981* + ID_OUI_FROM_DATABASE=Vivox Inc + +OUI:001982* + ID_OUI_FROM_DATABASE=SmarDTV + +OUI:001983* + ID_OUI_FROM_DATABASE=CCT R&D Limited + +OUI:001984* + ID_OUI_FROM_DATABASE=ESTIC Corporation + +OUI:001985* + ID_OUI_FROM_DATABASE=IT Watchdogs, Inc + +OUI:001986* + ID_OUI_FROM_DATABASE=Cheng Hongjian + +OUI:001987* + ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co., Ltd. + +OUI:001988* + ID_OUI_FROM_DATABASE=Wi2Wi, Inc + +OUI:001989* + ID_OUI_FROM_DATABASE=Sonitrol Corporation + +OUI:00198A* + ID_OUI_FROM_DATABASE=Northrop Grumman Systems Corp. + +OUI:00198B* + ID_OUI_FROM_DATABASE=Novera Optics Korea, Inc. + +OUI:00198C* + ID_OUI_FROM_DATABASE=iXSea + +OUI:00198D* + ID_OUI_FROM_DATABASE=Ocean Optics, Inc. + +OUI:00198E* + ID_OUI_FROM_DATABASE=Oticon A/S + +OUI:00198F* + ID_OUI_FROM_DATABASE=Alcatel Bell N.V. + +OUI:001990* + ID_OUI_FROM_DATABASE=ELM DATA Co., Ltd. + +OUI:001991* + ID_OUI_FROM_DATABASE=avinfo + +OUI:001992* + ID_OUI_FROM_DATABASE=ADTRAN INC. + +OUI:001993* + ID_OUI_FROM_DATABASE=Changshu Switchgear MFG. Co.,Ltd. (Former Changshu Switchgea + +OUI:001994* + ID_OUI_FROM_DATABASE=Jorjin Technologies Inc. + +OUI:001995* + ID_OUI_FROM_DATABASE=Jurong Hi-Tech (Suzhou)Co.ltd + +OUI:001996* + ID_OUI_FROM_DATABASE=TurboChef Technologies Inc. + +OUI:001997* + ID_OUI_FROM_DATABASE=Soft Device Sdn Bhd + +OUI:001998* + ID_OUI_FROM_DATABASE=SATO CORPORATION + +OUI:001999* + ID_OUI_FROM_DATABASE=Fujitsu Technology Solutions + +OUI:00199A* + ID_OUI_FROM_DATABASE=EDO-EVI + +OUI:00199B* + ID_OUI_FROM_DATABASE=Diversified Technical Systems, Inc. + +OUI:00199C* + ID_OUI_FROM_DATABASE=CTRING + +OUI:00199D* + ID_OUI_FROM_DATABASE=VIZIO, Inc. + +OUI:00199E* + ID_OUI_FROM_DATABASE=Nifty + +OUI:00199F* + ID_OUI_FROM_DATABASE=DKT A/S + +OUI:0019A0* + ID_OUI_FROM_DATABASE=NIHON DATA SYSTENS, INC. + +OUI:0019A1* + ID_OUI_FROM_DATABASE=LG INFORMATION & COMM. + +OUI:0019A2* + ID_OUI_FROM_DATABASE=ORDYN TECHNOLOGIES + +OUI:0019A3* + ID_OUI_FROM_DATABASE=asteel electronique atlantique + +OUI:0019A4* + ID_OUI_FROM_DATABASE=Austar Technology (hang zhou) Co.,Ltd + +OUI:0019A5* + ID_OUI_FROM_DATABASE=RadarFind Corporation + +OUI:0019A6* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0019A7* + ID_OUI_FROM_DATABASE=ITU-T + +OUI:0019A8* + ID_OUI_FROM_DATABASE=WiQuest Communications + +OUI:0019A9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0019AA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0019AB* + ID_OUI_FROM_DATABASE=Raycom CO ., LTD + +OUI:0019AC* + ID_OUI_FROM_DATABASE=GSP SYSTEMS Inc. + +OUI:0019AD* + ID_OUI_FROM_DATABASE=BOBST SA + +OUI:0019AE* + ID_OUI_FROM_DATABASE=Hopling Technologies b.v. + +OUI:0019AF* + ID_OUI_FROM_DATABASE=Rigol Technologies, Inc. + +OUI:0019B0* + ID_OUI_FROM_DATABASE=HanYang System + +OUI:0019B1* + ID_OUI_FROM_DATABASE=Arrow7 Corporation + +OUI:0019B2* + ID_OUI_FROM_DATABASE=XYnetsoft Co.,Ltd + +OUI:0019B3* + ID_OUI_FROM_DATABASE=Stanford Research Systems + +OUI:0019B4* + ID_OUI_FROM_DATABASE=VideoCast Ltd. + +OUI:0019B5* + ID_OUI_FROM_DATABASE=Famar Fueguina S.A. + +OUI:0019B6* + ID_OUI_FROM_DATABASE=Euro Emme s.r.l. + +OUI:0019B7* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0019B8* + ID_OUI_FROM_DATABASE=Boundary Devices + +OUI:0019B9* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:0019BA* + ID_OUI_FROM_DATABASE=Paradox Security Systems Ltd + +OUI:0019BB* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0019BC* + ID_OUI_FROM_DATABASE=ELECTRO CHANCE SRL + +OUI:0019BD* + ID_OUI_FROM_DATABASE=New Media Life + +OUI:0019BE* + ID_OUI_FROM_DATABASE=Altai Technologies Limited + +OUI:0019BF* + ID_OUI_FROM_DATABASE=Citiway technology Co.,ltd + +OUI:0019C0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0019C1* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:0019C2* + ID_OUI_FROM_DATABASE=Equustek Solutions, Inc. + +OUI:0019C3* + ID_OUI_FROM_DATABASE=Qualitrol + +OUI:0019C4* + ID_OUI_FROM_DATABASE=Infocrypt Inc. + +OUI:0019C5* + ID_OUI_FROM_DATABASE=SONY Computer Entertainment inc, + +OUI:0019C6* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:0019C7* + ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. + +OUI:0019C8* + ID_OUI_FROM_DATABASE=AnyDATA Corporation + +OUI:0019C9* + ID_OUI_FROM_DATABASE=S&C ELECTRIC COMPANY + +OUI:0019CA* + ID_OUI_FROM_DATABASE=Broadata Communications, Inc + +OUI:0019CB* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:0019CC* + ID_OUI_FROM_DATABASE=RCG (HK) Ltd + +OUI:0019CD* + ID_OUI_FROM_DATABASE=Chengdu ethercom information technology Ltd. + +OUI:0019CE* + ID_OUI_FROM_DATABASE=Progressive Gaming International + +OUI:0019CF* + ID_OUI_FROM_DATABASE=SALICRU, S.A. + +OUI:0019D0* + ID_OUI_FROM_DATABASE=Cathexis + +OUI:0019D1* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0019D2* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0019D3* + ID_OUI_FROM_DATABASE=TRAK Microwave + +OUI:0019D4* + ID_OUI_FROM_DATABASE=ICX Technologies + +OUI:0019D5* + ID_OUI_FROM_DATABASE=IP Innovations, Inc. + +OUI:0019D6* + ID_OUI_FROM_DATABASE=LS Cable and System Ltd. + +OUI:0019D7* + ID_OUI_FROM_DATABASE=FORTUNETEK CO., LTD + +OUI:0019D8* + ID_OUI_FROM_DATABASE=MAXFOR + +OUI:0019D9* + ID_OUI_FROM_DATABASE=Zeutschel GmbH + +OUI:0019DA* + ID_OUI_FROM_DATABASE=Welltrans O&E Technology Co. , Ltd. + +OUI:0019DB* + ID_OUI_FROM_DATABASE=MICRO-STAR INTERNATIONAL CO., LTD. + +OUI:0019DC* + ID_OUI_FROM_DATABASE=ENENSYS Technologies + +OUI:0019DD* + ID_OUI_FROM_DATABASE=FEI-Zyfer, Inc. + +OUI:0019DE* + ID_OUI_FROM_DATABASE=MOBITEK + +OUI:0019DF* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:0019E0* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co., Ltd. + +OUI:0019E1* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0019E2* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0019E3* + ID_OUI_FROM_DATABASE=Apple + +OUI:0019E4* + ID_OUI_FROM_DATABASE=2Wire, Inc + +OUI:0019E5* + ID_OUI_FROM_DATABASE=Lynx Studio Technology, Inc. + +OUI:0019E6* + ID_OUI_FROM_DATABASE=TOYO MEDIC CO.,LTD. + +OUI:0019E7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0019E8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0019E9* + ID_OUI_FROM_DATABASE=S-Information Technolgy, Co., Ltd. + +OUI:0019EA* + ID_OUI_FROM_DATABASE=TeraMage Technologies Co., Ltd. + +OUI:0019EB* + ID_OUI_FROM_DATABASE=Pyronix Ltd + +OUI:0019EC* + ID_OUI_FROM_DATABASE=Sagamore Systems, Inc. + +OUI:0019ED* + ID_OUI_FROM_DATABASE=Axesstel Inc. + +OUI:0019EE* + ID_OUI_FROM_DATABASE=CARLO GAVAZZI CONTROLS SPA-Controls Division + +OUI:0019EF* + ID_OUI_FROM_DATABASE=SHENZHEN LINNKING ELECTRONICS CO.,LTD + +OUI:0019F0* + ID_OUI_FROM_DATABASE=UNIONMAN TECHNOLOGY CO.,LTD + +OUI:0019F1* + ID_OUI_FROM_DATABASE=Star Communication Network Technology Co.,Ltd + +OUI:0019F2* + ID_OUI_FROM_DATABASE=Teradyne K.K. + +OUI:0019F3* + ID_OUI_FROM_DATABASE=Cetis, Inc + +OUI:0019F4* + ID_OUI_FROM_DATABASE=Convergens Oy Ltd + +OUI:0019F5* + ID_OUI_FROM_DATABASE=Imagination Technologies Ltd + +OUI:0019F6* + ID_OUI_FROM_DATABASE=Acconet (PTE) Ltd + +OUI:0019F7* + ID_OUI_FROM_DATABASE=Onset Computer Corporation + +OUI:0019F8* + ID_OUI_FROM_DATABASE=Embedded Systems Design, Inc. + +OUI:0019F9* + ID_OUI_FROM_DATABASE=TDK-Lambda + +OUI:0019FA* + ID_OUI_FROM_DATABASE=Cable Vision Electronics CO., LTD. + +OUI:0019FB* + ID_OUI_FROM_DATABASE=BSkyB Ltd + +OUI:0019FC* + ID_OUI_FROM_DATABASE=PT. Ufoakses Sukses Luarbiasa + +OUI:0019FD* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0019FE* + ID_OUI_FROM_DATABASE=SHENZHEN SEECOMM TECHNOLOGY CO.,LTD. + +OUI:0019FF* + ID_OUI_FROM_DATABASE=Finnzymes + +OUI:001A00* + ID_OUI_FROM_DATABASE=MATRIX INC. + +OUI:001A01* + ID_OUI_FROM_DATABASE=Smiths Medical + +OUI:001A02* + ID_OUI_FROM_DATABASE=SECURE CARE PRODUCTS, INC + +OUI:001A03* + ID_OUI_FROM_DATABASE=Angel Electronics Co., Ltd. + +OUI:001A04* + ID_OUI_FROM_DATABASE=Interay Solutions BV + +OUI:001A05* + ID_OUI_FROM_DATABASE=OPTIBASE LTD + +OUI:001A06* + ID_OUI_FROM_DATABASE=OpVista, Inc. + +OUI:001A07* + ID_OUI_FROM_DATABASE=Arecont Vision + +OUI:001A08* + ID_OUI_FROM_DATABASE=Simoco Ltd. + +OUI:001A09* + ID_OUI_FROM_DATABASE=Wayfarer Transit Systems Ltd + +OUI:001A0A* + ID_OUI_FROM_DATABASE=Adaptive Micro-Ware Inc. + +OUI:001A0B* + ID_OUI_FROM_DATABASE=BONA TECHNOLOGY INC. + +OUI:001A0C* + ID_OUI_FROM_DATABASE=Swe-Dish Satellite Systems AB + +OUI:001A0D* + ID_OUI_FROM_DATABASE=HandHeld entertainment, Inc. + +OUI:001A0E* + ID_OUI_FROM_DATABASE=Cheng Uei Precision Industry Co.,Ltd + +OUI:001A0F* + ID_OUI_FROM_DATABASE=Sistemas Avanzados de Control, S.A. + +OUI:001A10* + ID_OUI_FROM_DATABASE=LUCENT TRANS ELECTRONICS CO.,LTD + +OUI:001A11* + ID_OUI_FROM_DATABASE=Google Inc. + +OUI:001A12* + ID_OUI_FROM_DATABASE=Essilor + +OUI:001A13* + ID_OUI_FROM_DATABASE=Wanlida Group Co., LTD + +OUI:001A14* + ID_OUI_FROM_DATABASE=Xin Hua Control Engineering Co.,Ltd. + +OUI:001A15* + ID_OUI_FROM_DATABASE=gemalto e-Payment + +OUI:001A16* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001A17* + ID_OUI_FROM_DATABASE=Teak Technologies, Inc. + +OUI:001A18* + ID_OUI_FROM_DATABASE=Advanced Simulation Technology inc. + +OUI:001A19* + ID_OUI_FROM_DATABASE=Computer Engineering Limited + +OUI:001A1A* + ID_OUI_FROM_DATABASE=Gentex Corporation/Electro-Acoustic Products + +OUI:001A1B* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001A1C* + ID_OUI_FROM_DATABASE=GT&T Engineering Pte Ltd + +OUI:001A1D* + ID_OUI_FROM_DATABASE=PChome Online Inc. + +OUI:001A1E* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:001A1F* + ID_OUI_FROM_DATABASE=Coastal Environmental Systems + +OUI:001A20* + ID_OUI_FROM_DATABASE=CMOTECH Co. Ltd. + +OUI:001A21* + ID_OUI_FROM_DATABASE=Indac B.V. + +OUI:001A22* + ID_OUI_FROM_DATABASE=eQ-3 Entwicklung GmbH + +OUI:001A23* + ID_OUI_FROM_DATABASE=Ice Qube, Inc + +OUI:001A24* + ID_OUI_FROM_DATABASE=Galaxy Telecom Technologies Ltd + +OUI:001A25* + ID_OUI_FROM_DATABASE=DELTA DORE + +OUI:001A26* + ID_OUI_FROM_DATABASE=Deltanode Solutions AB + +OUI:001A27* + ID_OUI_FROM_DATABASE=Ubistar + +OUI:001A28* + ID_OUI_FROM_DATABASE=ASWT Co., LTD. Taiwan Branch H.K. + +OUI:001A29* + ID_OUI_FROM_DATABASE=Johnson Outdoors Marine Electronics, Inc + +OUI:001A2A* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:001A2B* + ID_OUI_FROM_DATABASE=Ayecom Technology Co., Ltd. + +OUI:001A2C* + ID_OUI_FROM_DATABASE=SATEC Co.,LTD + +OUI:001A2D* + ID_OUI_FROM_DATABASE=The Navvo Group + +OUI:001A2E* + ID_OUI_FROM_DATABASE=Ziova Coporation + +OUI:001A2F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001A30* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001A31* + ID_OUI_FROM_DATABASE=SCAN COIN Industries AB + +OUI:001A32* + ID_OUI_FROM_DATABASE=ACTIVA MULTIMEDIA + +OUI:001A33* + ID_OUI_FROM_DATABASE=ASI Communications, Inc. + +OUI:001A34* + ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. + +OUI:001A35* + ID_OUI_FROM_DATABASE=BARTEC GmbH + +OUI:001A36* + ID_OUI_FROM_DATABASE=Aipermon GmbH & Co. KG + +OUI:001A37* + ID_OUI_FROM_DATABASE=Lear Corporation + +OUI:001A38* + ID_OUI_FROM_DATABASE=Sanmina-SCI + +OUI:001A39* + ID_OUI_FROM_DATABASE=Merten GmbH&CoKG + +OUI:001A3A* + ID_OUI_FROM_DATABASE=Dongahelecomm + +OUI:001A3B* + ID_OUI_FROM_DATABASE=Doah Elecom Inc. + +OUI:001A3C* + ID_OUI_FROM_DATABASE=Technowave Ltd. + +OUI:001A3D* + ID_OUI_FROM_DATABASE=Ajin Vision Co.,Ltd + +OUI:001A3E* + ID_OUI_FROM_DATABASE=Faster Technology LLC + +OUI:001A3F* + ID_OUI_FROM_DATABASE=intelbras + +OUI:001A40* + ID_OUI_FROM_DATABASE=A-FOUR TECH CO., LTD. + +OUI:001A41* + ID_OUI_FROM_DATABASE=INOCOVA Co.,Ltd + +OUI:001A42* + ID_OUI_FROM_DATABASE=Techcity Technology co., Ltd. + +OUI:001A43* + ID_OUI_FROM_DATABASE=Logical Link Communications + +OUI:001A44* + ID_OUI_FROM_DATABASE=JWTrading Co., Ltd + +OUI:001A45* + ID_OUI_FROM_DATABASE=GN Netcom as + +OUI:001A46* + ID_OUI_FROM_DATABASE=Digital Multimedia Technology Co., Ltd + +OUI:001A47* + ID_OUI_FROM_DATABASE=Agami Systems, Inc. + +OUI:001A48* + ID_OUI_FROM_DATABASE=Takacom Corporation + +OUI:001A49* + ID_OUI_FROM_DATABASE=Micro Vision Co.,LTD + +OUI:001A4A* + ID_OUI_FROM_DATABASE=Qumranet Inc. + +OUI:001A4B* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001A4C* + ID_OUI_FROM_DATABASE=Crossbow Technology, Inc + +OUI:001A4D* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:001A4E* + ID_OUI_FROM_DATABASE=NTI AG / LinMot + +OUI:001A4F* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:001A50* + ID_OUI_FROM_DATABASE=PheeNet Technology Corp. + +OUI:001A51* + ID_OUI_FROM_DATABASE=Alfred Mann Foundation + +OUI:001A52* + ID_OUI_FROM_DATABASE=Meshlinx Wireless Inc. + +OUI:001A53* + ID_OUI_FROM_DATABASE=Zylaya + +OUI:001A54* + ID_OUI_FROM_DATABASE=Hip Shing Electronics Ltd. + +OUI:001A55* + ID_OUI_FROM_DATABASE=ACA-Digital Corporation + +OUI:001A56* + ID_OUI_FROM_DATABASE=ViewTel Co,. Ltd. + +OUI:001A57* + ID_OUI_FROM_DATABASE=Matrix Design Group, LLC + +OUI:001A58* + ID_OUI_FROM_DATABASE=CCV Deutschland GmbH - Celectronic eHealth Div. + +OUI:001A59* + ID_OUI_FROM_DATABASE=Ircona + +OUI:001A5A* + ID_OUI_FROM_DATABASE=Korea Electric Power Data Network (KDN) Co., Ltd + +OUI:001A5B* + ID_OUI_FROM_DATABASE=NetCare Service Co., Ltd. + +OUI:001A5C* + ID_OUI_FROM_DATABASE=Euchner GmbH+Co. KG + +OUI:001A5D* + ID_OUI_FROM_DATABASE=Mobinnova Corp. + +OUI:001A5E* + ID_OUI_FROM_DATABASE=Thincom Technology Co.,Ltd + +OUI:001A5F* + ID_OUI_FROM_DATABASE=KitWorks.fi Ltd. + +OUI:001A60* + ID_OUI_FROM_DATABASE=Wave Electronics Co.,Ltd. + +OUI:001A61* + ID_OUI_FROM_DATABASE=PacStar Corp. + +OUI:001A62* + ID_OUI_FROM_DATABASE=Data Robotics, Incorporated + +OUI:001A63* + ID_OUI_FROM_DATABASE=Elster Solutions, LLC, + +OUI:001A64* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:001A65* + ID_OUI_FROM_DATABASE=Seluxit + +OUI:001A66* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001A67* + ID_OUI_FROM_DATABASE=Infinite QL Sdn Bhd + +OUI:001A68* + ID_OUI_FROM_DATABASE=Weltec Enterprise Co., Ltd. + +OUI:001A69* + ID_OUI_FROM_DATABASE=Wuhan Yangtze Optical Technology CO.,Ltd. + +OUI:001A6A* + ID_OUI_FROM_DATABASE=Tranzas, Inc. + +OUI:001A6B* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:001A6C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001A6D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001A6E* + ID_OUI_FROM_DATABASE=Impro Technologies + +OUI:001A6F* + ID_OUI_FROM_DATABASE=MI.TEL s.r.l. + +OUI:001A70* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001A71* + ID_OUI_FROM_DATABASE=Diostech Co., Ltd. + +OUI:001A72* + ID_OUI_FROM_DATABASE=Mosart Semiconductor Corp. + +OUI:001A73* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:001A74* + ID_OUI_FROM_DATABASE=Procare International Co + +OUI:001A75* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:001A76* + ID_OUI_FROM_DATABASE=SDT information Technology Co.,LTD. + +OUI:001A77* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001A78* + ID_OUI_FROM_DATABASE=ubtos + +OUI:001A79* + ID_OUI_FROM_DATABASE=TELECOMUNICATION TECHNOLOGIES LTD. + +OUI:001A7A* + ID_OUI_FROM_DATABASE=Lismore Instruments Limited + +OUI:001A7B* + ID_OUI_FROM_DATABASE=Teleco, Inc. + +OUI:001A7C* + ID_OUI_FROM_DATABASE=Hirschmann Multimedia B.V. + +OUI:001A7D* + ID_OUI_FROM_DATABASE=cyber-blue(HK)Ltd + +OUI:001A7E* + ID_OUI_FROM_DATABASE=LN Srithai Comm Ltd. + +OUI:001A7F* + ID_OUI_FROM_DATABASE=GCI Science&Technology Co.,Ltd. + +OUI:001A80* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:001A81* + ID_OUI_FROM_DATABASE=Zelax + +OUI:001A82* + ID_OUI_FROM_DATABASE=PROBA Building Automation Co.,LTD + +OUI:001A83* + ID_OUI_FROM_DATABASE=Pegasus Technologies Inc. + +OUI:001A84* + ID_OUI_FROM_DATABASE=V One Multimedia Pte Ltd + +OUI:001A85* + ID_OUI_FROM_DATABASE=NV Michel Van de Wiele + +OUI:001A86* + ID_OUI_FROM_DATABASE=AdvancedIO Systems Inc + +OUI:001A87* + ID_OUI_FROM_DATABASE=Canhold International Limited + +OUI:001A88* + ID_OUI_FROM_DATABASE=Venergy,Co,Ltd + +OUI:001A89* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001A8A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:001A8B* + ID_OUI_FROM_DATABASE=CHUNIL ELECTRIC IND., CO. + +OUI:001A8C* + ID_OUI_FROM_DATABASE=Astaro AG + +OUI:001A8D* + ID_OUI_FROM_DATABASE=AVECS Bergen GmbH + +OUI:001A8E* + ID_OUI_FROM_DATABASE=3Way Networks Ltd + +OUI:001A8F* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001A90* + ID_OUI_FROM_DATABASE=Trópico Sistemas e Telecomunicações da Amazônia LTDA. + +OUI:001A91* + ID_OUI_FROM_DATABASE=FusionDynamic Ltd. + +OUI:001A92* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001A93* + ID_OUI_FROM_DATABASE=ERCO Leuchten GmbH + +OUI:001A94* + ID_OUI_FROM_DATABASE=Votronic GmbH + +OUI:001A95* + ID_OUI_FROM_DATABASE=Hisense Mobile Communications Technoligy Co.,Ltd. + +OUI:001A96* + ID_OUI_FROM_DATABASE=ECLER S.A. + +OUI:001A97* + ID_OUI_FROM_DATABASE=fitivision technology Inc. + +OUI:001A98* + ID_OUI_FROM_DATABASE=Asotel Communication Limited Taiwan Branch + +OUI:001A99* + ID_OUI_FROM_DATABASE=Smarty (HZ) Information Electronics Co., Ltd + +OUI:001A9A* + ID_OUI_FROM_DATABASE=Skyworth Digital technology(shenzhen)co.ltd. + +OUI:001A9B* + ID_OUI_FROM_DATABASE=ADEC & Parter AG + +OUI:001A9C* + ID_OUI_FROM_DATABASE=RightHand Technologies, Inc. + +OUI:001A9D* + ID_OUI_FROM_DATABASE=Skipper Wireless, Inc. + +OUI:001A9E* + ID_OUI_FROM_DATABASE=ICON Digital International Limited + +OUI:001A9F* + ID_OUI_FROM_DATABASE=A-Link Ltd + +OUI:001AA0* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:001AA1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001AA2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001AA3* + ID_OUI_FROM_DATABASE=DELORME + +OUI:001AA4* + ID_OUI_FROM_DATABASE=Future University-Hakodate + +OUI:001AA5* + ID_OUI_FROM_DATABASE=BRN Phoenix + +OUI:001AA6* + ID_OUI_FROM_DATABASE=Telefunken Radio Communication Systems GmbH &CO.KG + +OUI:001AA7* + ID_OUI_FROM_DATABASE=Torian Wireless + +OUI:001AA8* + ID_OUI_FROM_DATABASE=Mamiya Digital Imaging Co., Ltd. + +OUI:001AA9* + ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD + +OUI:001AAA* + ID_OUI_FROM_DATABASE=Analogic Corp. + +OUI:001AAB* + ID_OUI_FROM_DATABASE=eWings s.r.l. + +OUI:001AAC* + ID_OUI_FROM_DATABASE=Corelatus AB + +OUI:001AAD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001AAE* + ID_OUI_FROM_DATABASE=Savant Systems LLC + +OUI:001AAF* + ID_OUI_FROM_DATABASE=BLUSENS TECHNOLOGY + +OUI:001AB0* + ID_OUI_FROM_DATABASE=Signal Networks Pvt. Ltd., + +OUI:001AB1* + ID_OUI_FROM_DATABASE=Asia Pacific Satellite Industries Co., Ltd. + +OUI:001AB2* + ID_OUI_FROM_DATABASE=Cyber Solutions Inc. + +OUI:001AB3* + ID_OUI_FROM_DATABASE=VISIONITE INC. + +OUI:001AB4* + ID_OUI_FROM_DATABASE=FFEI Ltd. + +OUI:001AB5* + ID_OUI_FROM_DATABASE=Home Network System + +OUI:001AB6* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:001AB7* + ID_OUI_FROM_DATABASE=Ethos Networks LTD. + +OUI:001AB8* + ID_OUI_FROM_DATABASE=Anseri Corporation + +OUI:001AB9* + ID_OUI_FROM_DATABASE=PMC + +OUI:001ABA* + ID_OUI_FROM_DATABASE=Caton Overseas Limited + +OUI:001ABB* + ID_OUI_FROM_DATABASE=Fontal Technology Incorporation + +OUI:001ABC* + ID_OUI_FROM_DATABASE=U4EA Technologies Ltd + +OUI:001ABD* + ID_OUI_FROM_DATABASE=Impatica Inc. + +OUI:001ABE* + ID_OUI_FROM_DATABASE=COMPUTER HI-TECH INC. + +OUI:001ABF* + ID_OUI_FROM_DATABASE=TRUMPF Laser Marking Systems AG + +OUI:001AC0* + ID_OUI_FROM_DATABASE=JOYBIEN TECHNOLOGIES CO., LTD. + +OUI:001AC1* + ID_OUI_FROM_DATABASE=3Com Ltd + +OUI:001AC2* + ID_OUI_FROM_DATABASE=YEC Co.,Ltd. + +OUI:001AC3* + ID_OUI_FROM_DATABASE=Scientific-Atlanta, Inc + +OUI:001AC4* + ID_OUI_FROM_DATABASE=2Wire, Inc + +OUI:001AC5* + ID_OUI_FROM_DATABASE=BreakingPoint Systems, Inc. + +OUI:001AC6* + ID_OUI_FROM_DATABASE=Micro Control Designs + +OUI:001AC7* + ID_OUI_FROM_DATABASE=UNIPOINT + +OUI:001AC8* + ID_OUI_FROM_DATABASE=ISL (Instrumentation Scientifique de Laboratoire) + +OUI:001AC9* + ID_OUI_FROM_DATABASE=SUZUKEN CO.,LTD + +OUI:001ACA* + ID_OUI_FROM_DATABASE=Tilera Corporation + +OUI:001ACB* + ID_OUI_FROM_DATABASE=Autocom Products Ltd + +OUI:001ACC* + ID_OUI_FROM_DATABASE=Celestial Semiconductor, Ltd + +OUI:001ACD* + ID_OUI_FROM_DATABASE=Tidel Engineering LP + +OUI:001ACE* + ID_OUI_FROM_DATABASE=YUPITERU CORPORATION + +OUI:001ACF* + ID_OUI_FROM_DATABASE=C.T. ELETTRONICA + +OUI:001AD0* + ID_OUI_FROM_DATABASE=Albis Technologies AG + +OUI:001AD1* + ID_OUI_FROM_DATABASE=FARGO CO., LTD. + +OUI:001AD2* + ID_OUI_FROM_DATABASE=Eletronica Nitron Ltda + +OUI:001AD3* + ID_OUI_FROM_DATABASE=Vamp Ltd. + +OUI:001AD4* + ID_OUI_FROM_DATABASE=iPOX Technology Co., Ltd. + +OUI:001AD5* + ID_OUI_FROM_DATABASE=KMC CHAIN INDUSTRIAL CO., LTD. + +OUI:001AD6* + ID_OUI_FROM_DATABASE=JIAGNSU AETNA ELECTRIC CO.,LTD + +OUI:001AD7* + ID_OUI_FROM_DATABASE=Christie Digital Systems, Inc. + +OUI:001AD8* + ID_OUI_FROM_DATABASE=AlsterAero GmbH + +OUI:001AD9* + ID_OUI_FROM_DATABASE=International Broadband Electric Communications, Inc. + +OUI:001ADA* + ID_OUI_FROM_DATABASE=Biz-2-Me Inc. + +OUI:001ADB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001ADC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001ADD* + ID_OUI_FROM_DATABASE=PePWave Ltd + +OUI:001ADE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001ADF* + ID_OUI_FROM_DATABASE=Interactivetv Pty Limited + +OUI:001AE0* + ID_OUI_FROM_DATABASE=Mythology Tech Express Inc. + +OUI:001AE1* + ID_OUI_FROM_DATABASE=EDGE ACCESS INC + +OUI:001AE2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001AE3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001AE4* + ID_OUI_FROM_DATABASE=Medicis Technologies Corporation + +OUI:001AE5* + ID_OUI_FROM_DATABASE=Mvox Technologies Inc. + +OUI:001AE6* + ID_OUI_FROM_DATABASE=Atlanta Advanced Communications Holdings Limited + +OUI:001AE7* + ID_OUI_FROM_DATABASE=Aztek Networks, Inc. + +OUI:001AE8* + ID_OUI_FROM_DATABASE=Unify GmbH and Co KG + +OUI:001AE9* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001AEA* + ID_OUI_FROM_DATABASE=Radio Terminal Systems Pty Ltd + +OUI:001AEB* + ID_OUI_FROM_DATABASE=Allied Telesis K.K. + +OUI:001AEC* + ID_OUI_FROM_DATABASE=Keumbee Electronics Co.,Ltd. + +OUI:001AED* + ID_OUI_FROM_DATABASE=INCOTEC GmbH + +OUI:001AEE* + ID_OUI_FROM_DATABASE=Shenztech Ltd + +OUI:001AEF* + ID_OUI_FROM_DATABASE=Loopcomm Technology, Inc. + +OUI:001AF0* + ID_OUI_FROM_DATABASE=Alcatel - IPD + +OUI:001AF1* + ID_OUI_FROM_DATABASE=Embedded Artists AB + +OUI:001AF2* + ID_OUI_FROM_DATABASE=Dynavisions Schweiz AG + +OUI:001AF3* + ID_OUI_FROM_DATABASE=Samyoung Electronics + +OUI:001AF4* + ID_OUI_FROM_DATABASE=Handreamnet + +OUI:001AF5* + ID_OUI_FROM_DATABASE=PENTAONE. CO., LTD. + +OUI:001AF6* + ID_OUI_FROM_DATABASE=Woven Systems, Inc. + +OUI:001AF7* + ID_OUI_FROM_DATABASE=dataschalt e+a GmbH + +OUI:001AF8* + ID_OUI_FROM_DATABASE=Copley Controls Corporation + +OUI:001AF9* + ID_OUI_FROM_DATABASE=AeroVIronment (AV Inc) + +OUI:001AFA* + ID_OUI_FROM_DATABASE=Welch Allyn, Inc. + +OUI:001AFB* + ID_OUI_FROM_DATABASE=Joby Inc. + +OUI:001AFC* + ID_OUI_FROM_DATABASE=ModusLink Corporation + +OUI:001AFD* + ID_OUI_FROM_DATABASE=EVOLIS + +OUI:001AFE* + ID_OUI_FROM_DATABASE=SOFACREAL + +OUI:001AFF* + ID_OUI_FROM_DATABASE=Wizyoung Tech. + +OUI:001B00* + ID_OUI_FROM_DATABASE=Neopost Technologies + +OUI:001B01* + ID_OUI_FROM_DATABASE=Applied Radio Technologies + +OUI:001B02* + ID_OUI_FROM_DATABASE=ED Co.Ltd + +OUI:001B03* + ID_OUI_FROM_DATABASE=Action Technology (SZ) Co., Ltd + +OUI:001B04* + ID_OUI_FROM_DATABASE=Affinity International S.p.a + +OUI:001B05* + ID_OUI_FROM_DATABASE=YMC AG + +OUI:001B06* + ID_OUI_FROM_DATABASE=Ateliers R. LAUMONIER + +OUI:001B07* + ID_OUI_FROM_DATABASE=Mendocino Software + +OUI:001B08* + ID_OUI_FROM_DATABASE=Danfoss Drives A/S + +OUI:001B09* + ID_OUI_FROM_DATABASE=Matrix Telecom Pvt. Ltd. + +OUI:001B0A* + ID_OUI_FROM_DATABASE=Intelligent Distributed Controls Ltd + +OUI:001B0B* + ID_OUI_FROM_DATABASE=Phidgets Inc. + +OUI:001B0C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B0D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B0E* + ID_OUI_FROM_DATABASE=InoTec GmbH Organisationssysteme + +OUI:001B0F* + ID_OUI_FROM_DATABASE=Petratec + +OUI:001B10* + ID_OUI_FROM_DATABASE=ShenZhen Kang Hui Technology Co.,ltd + +OUI:001B11* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:001B12* + ID_OUI_FROM_DATABASE=Apprion + +OUI:001B13* + ID_OUI_FROM_DATABASE=Icron Technologies Corporation + +OUI:001B14* + ID_OUI_FROM_DATABASE=Carex Lighting Equipment Factory + +OUI:001B15* + ID_OUI_FROM_DATABASE=Voxtel, Inc. + +OUI:001B16* + ID_OUI_FROM_DATABASE=Celtro Ltd. + +OUI:001B17* + ID_OUI_FROM_DATABASE=Palo Alto Networks + +OUI:001B18* + ID_OUI_FROM_DATABASE=Tsuken Electric Ind. Co.,Ltd + +OUI:001B19* + ID_OUI_FROM_DATABASE=IEEE I&M Society TC9 + +OUI:001B1A* + ID_OUI_FROM_DATABASE=e-trees Japan, Inc. + +OUI:001B1B* + ID_OUI_FROM_DATABASE=Siemens AG, + +OUI:001B1C* + ID_OUI_FROM_DATABASE=Coherent + +OUI:001B1D* + ID_OUI_FROM_DATABASE=Phoenix International Co., Ltd + +OUI:001B1E* + ID_OUI_FROM_DATABASE=HART Communication Foundation + +OUI:001B1F* + ID_OUI_FROM_DATABASE=DELTA - Danish Electronics, Light & Acoustics + +OUI:001B20* + ID_OUI_FROM_DATABASE=TPine Technology + +OUI:001B21* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001B22* + ID_OUI_FROM_DATABASE=Palit Microsystems ( H.K.) Ltd. + +OUI:001B23* + ID_OUI_FROM_DATABASE=SimpleComTools + +OUI:001B24* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:001B25* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001B26* + ID_OUI_FROM_DATABASE=RON-Telecom ZAO + +OUI:001B27* + ID_OUI_FROM_DATABASE=Merlin CSI + +OUI:001B28* + ID_OUI_FROM_DATABASE=POLYGON, JSC + +OUI:001B29* + ID_OUI_FROM_DATABASE=Avantis.Co.,Ltd + +OUI:001B2A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B2B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B2C* + ID_OUI_FROM_DATABASE=ATRON electronic GmbH + +OUI:001B2D* + ID_OUI_FROM_DATABASE=Med-Eng Systems Inc. + +OUI:001B2E* + ID_OUI_FROM_DATABASE=Sinkyo Electron Inc + +OUI:001B2F* + ID_OUI_FROM_DATABASE=NETGEAR Inc. + +OUI:001B30* + ID_OUI_FROM_DATABASE=Solitech Inc. + +OUI:001B31* + ID_OUI_FROM_DATABASE=Neural Image. Co. Ltd. + +OUI:001B32* + ID_OUI_FROM_DATABASE=QLogic Corporation + +OUI:001B33* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001B34* + ID_OUI_FROM_DATABASE=Focus System Inc. + +OUI:001B35* + ID_OUI_FROM_DATABASE=ChongQing JINOU Science & Technology Development CO.,Ltd + +OUI:001B36* + ID_OUI_FROM_DATABASE=Tsubata Engineering Co.,Ltd. (Head Office) + +OUI:001B37* + ID_OUI_FROM_DATABASE=Computec Oy + +OUI:001B38* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:001B39* + ID_OUI_FROM_DATABASE=Proxicast + +OUI:001B3A* + ID_OUI_FROM_DATABASE=SIMS Corp. + +OUI:001B3B* + ID_OUI_FROM_DATABASE=Yi-Qing CO., LTD + +OUI:001B3C* + ID_OUI_FROM_DATABASE=Software Technologies Group,Inc. + +OUI:001B3D* + ID_OUI_FROM_DATABASE=EuroTel Spa + +OUI:001B3E* + ID_OUI_FROM_DATABASE=Curtis, Inc. + +OUI:001B3F* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:001B40* + ID_OUI_FROM_DATABASE=Network Automation mxc AB + +OUI:001B41* + ID_OUI_FROM_DATABASE=General Infinity Co.,Ltd. + +OUI:001B42* + ID_OUI_FROM_DATABASE=Wise & Blue + +OUI:001B43* + ID_OUI_FROM_DATABASE=Beijing DG Telecommunications equipment Co.,Ltd + +OUI:001B44* + ID_OUI_FROM_DATABASE=SanDisk Corporation + +OUI:001B45* + ID_OUI_FROM_DATABASE=ABB AS, Division Automation Products + +OUI:001B46* + ID_OUI_FROM_DATABASE=Blueone Technology Co.,Ltd + +OUI:001B47* + ID_OUI_FROM_DATABASE=Futarque A/S + +OUI:001B48* + ID_OUI_FROM_DATABASE=Shenzhen Lantech Electronics Co., Ltd. + +OUI:001B49* + ID_OUI_FROM_DATABASE=Roberts Radio limited + +OUI:001B4A* + ID_OUI_FROM_DATABASE=W&W Communications, Inc. + +OUI:001B4B* + ID_OUI_FROM_DATABASE=SANION Co., Ltd. + +OUI:001B4C* + ID_OUI_FROM_DATABASE=Signtech + +OUI:001B4D* + ID_OUI_FROM_DATABASE=Areca Technology Corporation + +OUI:001B4E* + ID_OUI_FROM_DATABASE=Navman New Zealand + +OUI:001B4F* + ID_OUI_FROM_DATABASE=Avaya Inc. + +OUI:001B50* + ID_OUI_FROM_DATABASE=Nizhny Novgorod Factory named after M.Frunze, FSUE (NZiF) + +OUI:001B51* + ID_OUI_FROM_DATABASE=Vector Technology Corp. + +OUI:001B52* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001B53* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B54* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B55* + ID_OUI_FROM_DATABASE=Hurco Automation Ltd. + +OUI:001B56* + ID_OUI_FROM_DATABASE=Tehuti Networks Ltd. + +OUI:001B57* + ID_OUI_FROM_DATABASE=SEMINDIA SYSTEMS PRIVATE LIMITED + +OUI:001B58* + ID_OUI_FROM_DATABASE=ACE CAD Enterprise Co., Ltd. + +OUI:001B59* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:001B5A* + ID_OUI_FROM_DATABASE=Apollo Imaging Technologies, Inc. + +OUI:001B5B* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001B5C* + ID_OUI_FROM_DATABASE=Azuretec Co., Ltd. + +OUI:001B5D* + ID_OUI_FROM_DATABASE=Vololink Pty Ltd + +OUI:001B5E* + ID_OUI_FROM_DATABASE=BPL Limited + +OUI:001B5F* + ID_OUI_FROM_DATABASE=Alien Technology + +OUI:001B60* + ID_OUI_FROM_DATABASE=NAVIGON AG + +OUI:001B61* + ID_OUI_FROM_DATABASE=Digital Acoustics, LLC + +OUI:001B62* + ID_OUI_FROM_DATABASE=JHT Optoelectronics Co.,Ltd. + +OUI:001B63* + ID_OUI_FROM_DATABASE=Apple + +OUI:001B64* + ID_OUI_FROM_DATABASE=IsaacLandKorea Co., Ltd, + +OUI:001B65* + ID_OUI_FROM_DATABASE=China Gridcom Co., Ltd + +OUI:001B66* + ID_OUI_FROM_DATABASE=Sennheiser electronic GmbH & Co. KG + +OUI:001B67* + ID_OUI_FROM_DATABASE=Cisco Systems Inc + +OUI:001B68* + ID_OUI_FROM_DATABASE=Modnnet Co., Ltd + +OUI:001B69* + ID_OUI_FROM_DATABASE=Equaline Corporation + +OUI:001B6A* + ID_OUI_FROM_DATABASE=Powerwave Technologies Sweden AB + +OUI:001B6B* + ID_OUI_FROM_DATABASE=Swyx Solutions AG + +OUI:001B6C* + ID_OUI_FROM_DATABASE=LookX Digital Media BV + +OUI:001B6D* + ID_OUI_FROM_DATABASE=Midtronics, Inc. + +OUI:001B6E* + ID_OUI_FROM_DATABASE=Anue Systems, Inc. + +OUI:001B6F* + ID_OUI_FROM_DATABASE=Teletrak Ltd + +OUI:001B70* + ID_OUI_FROM_DATABASE=IRI Ubiteq, INC. + +OUI:001B71* + ID_OUI_FROM_DATABASE=Telular Corp. + +OUI:001B72* + ID_OUI_FROM_DATABASE=Sicep s.p.a. + +OUI:001B73* + ID_OUI_FROM_DATABASE=DTL Broadcast Ltd + +OUI:001B74* + ID_OUI_FROM_DATABASE=MiraLink Corporation + +OUI:001B75* + ID_OUI_FROM_DATABASE=Hypermedia Systems + +OUI:001B76* + ID_OUI_FROM_DATABASE=Ripcode, Inc. + +OUI:001B77* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001B78* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001B79* + ID_OUI_FROM_DATABASE=FAIVELEY TRANSPORT + +OUI:001B7A* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001B7B* + ID_OUI_FROM_DATABASE=The Tintometer Ltd + +OUI:001B7C* + ID_OUI_FROM_DATABASE=A & R Cambridge + +OUI:001B7D* + ID_OUI_FROM_DATABASE=CXR Anderson Jacobson + +OUI:001B7E* + ID_OUI_FROM_DATABASE=Beckmann GmbH + +OUI:001B7F* + ID_OUI_FROM_DATABASE=TMN Technologies Telecomunicacoes Ltda + +OUI:001B80* + ID_OUI_FROM_DATABASE=LORD Corporation + +OUI:001B81* + ID_OUI_FROM_DATABASE=DATAQ Instruments, Inc. + +OUI:001B82* + ID_OUI_FROM_DATABASE=Taiwan Semiconductor Co., Ltd. + +OUI:001B83* + ID_OUI_FROM_DATABASE=Finsoft Ltd + +OUI:001B84* + ID_OUI_FROM_DATABASE=Scan Engineering Telecom + +OUI:001B85* + ID_OUI_FROM_DATABASE=MAN Diesel SE + +OUI:001B86* + ID_OUI_FROM_DATABASE=Bosch Access Systems GmbH + +OUI:001B87* + ID_OUI_FROM_DATABASE=Deepsound Tech. Co., Ltd + +OUI:001B88* + ID_OUI_FROM_DATABASE=Divinet Access Technologies Ltd + +OUI:001B89* + ID_OUI_FROM_DATABASE=EMZA Visual Sense Ltd. + +OUI:001B8A* + ID_OUI_FROM_DATABASE=2M Electronic A/S + +OUI:001B8B* + ID_OUI_FROM_DATABASE=NEC AccessTechnica, Ltd. + +OUI:001B8C* + ID_OUI_FROM_DATABASE=JMicron Technology Corp. + +OUI:001B8D* + ID_OUI_FROM_DATABASE=Electronic Computer Systems, Inc. + +OUI:001B8E* + ID_OUI_FROM_DATABASE=Hulu Sweden AB + +OUI:001B8F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B90* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001B91* + ID_OUI_FROM_DATABASE=EFKON AG + +OUI:001B92* + ID_OUI_FROM_DATABASE=l-acoustics + +OUI:001B93* + ID_OUI_FROM_DATABASE=JC Decaux SA DNT + +OUI:001B94* + ID_OUI_FROM_DATABASE=T.E.M.A. S.p.A. + +OUI:001B95* + ID_OUI_FROM_DATABASE=VIDEO SYSTEMS SRL + +OUI:001B96* + ID_OUI_FROM_DATABASE=General Sensing + +OUI:001B97* + ID_OUI_FROM_DATABASE=Violin Technologies + +OUI:001B98* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. + +OUI:001B99* + ID_OUI_FROM_DATABASE=KS System GmbH + +OUI:001B9A* + ID_OUI_FROM_DATABASE=Apollo Fire Detectors Ltd + +OUI:001B9B* + ID_OUI_FROM_DATABASE=Hose-McCann Communications + +OUI:001B9C* + ID_OUI_FROM_DATABASE=SATEL sp. z o.o. + +OUI:001B9D* + ID_OUI_FROM_DATABASE=Novus Security Sp. z o.o. + +OUI:001B9E* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP + +OUI:001B9F* + ID_OUI_FROM_DATABASE=Calyptech Pty Ltd + +OUI:001BA0* + ID_OUI_FROM_DATABASE=Awox + +OUI:001BA1* + ID_OUI_FROM_DATABASE=Åmic AB + +OUI:001BA2* + ID_OUI_FROM_DATABASE=IDS Imaging Development Systems GmbH + +OUI:001BA3* + ID_OUI_FROM_DATABASE=Flexit Group GmbH + +OUI:001BA4* + ID_OUI_FROM_DATABASE=S.A.E Afikim + +OUI:001BA5* + ID_OUI_FROM_DATABASE=MyungMin Systems, Inc. + +OUI:001BA6* + ID_OUI_FROM_DATABASE=intotech inc. + +OUI:001BA7* + ID_OUI_FROM_DATABASE=Lorica Solutions + +OUI:001BA8* + ID_OUI_FROM_DATABASE=UBI&MOBI,.Inc + +OUI:001BA9* + ID_OUI_FROM_DATABASE=BROTHER INDUSTRIES, LTD. + +OUI:001BAA* + ID_OUI_FROM_DATABASE=XenICs nv + +OUI:001BAB* + ID_OUI_FROM_DATABASE=Telchemy, Incorporated + +OUI:001BAC* + ID_OUI_FROM_DATABASE=Curtiss Wright Controls Embedded Computing + +OUI:001BAD* + ID_OUI_FROM_DATABASE=iControl Incorporated + +OUI:001BAE* + ID_OUI_FROM_DATABASE=Micro Control Systems, Inc + +OUI:001BAF* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001BB0* + ID_OUI_FROM_DATABASE=BHARAT ELECTRONICS + +OUI:001BB1* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:001BB2* + ID_OUI_FROM_DATABASE=Intellect International NV + +OUI:001BB3* + ID_OUI_FROM_DATABASE=Condalo GmbH + +OUI:001BB4* + ID_OUI_FROM_DATABASE=Airvod Limited + +OUI:001BB5* + ID_OUI_FROM_DATABASE=ZF Electronics GmbH + +OUI:001BB6* + ID_OUI_FROM_DATABASE=Bird Electronic Corp. + +OUI:001BB7* + ID_OUI_FROM_DATABASE=Alta Heights Technology Corp. + +OUI:001BB8* + ID_OUI_FROM_DATABASE=BLUEWAY ELECTRONIC CO;LTD + +OUI:001BB9* + ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. + +OUI:001BBA* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001BBB* + ID_OUI_FROM_DATABASE=RFTech Co.,Ltd + +OUI:001BBC* + ID_OUI_FROM_DATABASE=Silver Peak Systems, Inc. + +OUI:001BBD* + ID_OUI_FROM_DATABASE=FMC Kongsberg Subsea AS + +OUI:001BBE* + ID_OUI_FROM_DATABASE=ICOP Digital + +OUI:001BBF* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:001BC0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:001BC1* + ID_OUI_FROM_DATABASE=HOLUX Technology, Inc. + +OUI:001BC2* + ID_OUI_FROM_DATABASE=Integrated Control Technology Limitied + +OUI:001BC3* + ID_OUI_FROM_DATABASE=Mobisolution Co.,Ltd + +OUI:001BC4* + ID_OUI_FROM_DATABASE=Ultratec, Inc. + +OUI:001BC5* + ID_OUI_FROM_DATABASE=IEEE Registration Authority + +OUI:001BC6* + ID_OUI_FROM_DATABASE=Strato Rechenzentrum AG + +OUI:001BC7* + ID_OUI_FROM_DATABASE=StarVedia Technology Inc. + +OUI:001BC8* + ID_OUI_FROM_DATABASE=MIURA CO.,LTD + +OUI:001BC9* + ID_OUI_FROM_DATABASE=FSN DISPLAY INC + +OUI:001BCA* + ID_OUI_FROM_DATABASE=Beijing Run Technology LTD. Company + +OUI:001BCB* + ID_OUI_FROM_DATABASE=PEMPEK SYSTEMS PTY LTD + +OUI:001BCC* + ID_OUI_FROM_DATABASE=KINGTEK CCTV ALLIANCE CO., LTD. + +OUI:001BCD* + ID_OUI_FROM_DATABASE=DAVISCOMMS (S) PTE LTD + +OUI:001BCE* + ID_OUI_FROM_DATABASE=Measurement Devices Ltd + +OUI:001BCF* + ID_OUI_FROM_DATABASE=Dataupia Corporation + +OUI:001BD0* + ID_OUI_FROM_DATABASE=IDENTEC SOLUTIONS + +OUI:001BD1* + ID_OUI_FROM_DATABASE=SOGESTMATIC + +OUI:001BD2* + ID_OUI_FROM_DATABASE=ULTRA-X ASIA PACIFIC Inc. + +OUI:001BD3* + ID_OUI_FROM_DATABASE=Panasonic Corp. AVC Company + +OUI:001BD4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001BD5* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001BD6* + ID_OUI_FROM_DATABASE=Kelvin Hughes Ltd + +OUI:001BD7* + ID_OUI_FROM_DATABASE=Scientific Atlanta, A Cisco Company + +OUI:001BD8* + ID_OUI_FROM_DATABASE=DVTel LTD + +OUI:001BD9* + ID_OUI_FROM_DATABASE=Edgewater Computer Systems + +OUI:001BDA* + ID_OUI_FROM_DATABASE=UTStarcom Inc + +OUI:001BDB* + ID_OUI_FROM_DATABASE=Valeo VECS + +OUI:001BDC* + ID_OUI_FROM_DATABASE=Vencer Co., Ltd. + +OUI:001BDD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001BDE* + ID_OUI_FROM_DATABASE=Renkus-Heinz, Inc. + +OUI:001BDF* + ID_OUI_FROM_DATABASE=Iskra Sistemi d.d. + +OUI:001BE0* + ID_OUI_FROM_DATABASE=TELENOT ELECTRONIC GmbH + +OUI:001BE1* + ID_OUI_FROM_DATABASE=ViaLogy + +OUI:001BE2* + ID_OUI_FROM_DATABASE=AhnLab,Inc. + +OUI:001BE3* + ID_OUI_FROM_DATABASE=Health Hero Network, Inc. + +OUI:001BE4* + ID_OUI_FROM_DATABASE=TOWNET SRL + +OUI:001BE5* + ID_OUI_FROM_DATABASE=802automation Limited + +OUI:001BE6* + ID_OUI_FROM_DATABASE=VR AG + +OUI:001BE7* + ID_OUI_FROM_DATABASE=Postek Electronics Co., Ltd. + +OUI:001BE8* + ID_OUI_FROM_DATABASE=Ultratronik GmbH + +OUI:001BE9* + ID_OUI_FROM_DATABASE=Broadcom Corporation + +OUI:001BEA* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001BEB* + ID_OUI_FROM_DATABASE=DMP Electronics INC. + +OUI:001BEC* + ID_OUI_FROM_DATABASE=Netio Technologies Co., Ltd + +OUI:001BED* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:001BEE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001BEF* + ID_OUI_FROM_DATABASE=Blossoms Digital Technology Co.,Ltd. + +OUI:001BF0* + ID_OUI_FROM_DATABASE=Value Platforms Limited + +OUI:001BF1* + ID_OUI_FROM_DATABASE=Nanjing SilverNet Software Co., Ltd. + +OUI:001BF2* + ID_OUI_FROM_DATABASE=KWORLD COMPUTER CO., LTD + +OUI:001BF3* + ID_OUI_FROM_DATABASE=TRANSRADIO SenderSysteme Berlin AG + +OUI:001BF4* + ID_OUI_FROM_DATABASE=KENWIN INDUSTRIAL(HK) LTD. + +OUI:001BF5* + ID_OUI_FROM_DATABASE=Tellink Sistemas de Telecomunicación S.L. + +OUI:001BF6* + ID_OUI_FROM_DATABASE=CONWISE Technology Corporation Ltd. + +OUI:001BF7* + ID_OUI_FROM_DATABASE=Lund IP Products AB + +OUI:001BF8* + ID_OUI_FROM_DATABASE=Digitrax Inc. + +OUI:001BF9* + ID_OUI_FROM_DATABASE=Intellitect Water Ltd + +OUI:001BFA* + ID_OUI_FROM_DATABASE=G.i.N. mbH + +OUI:001BFB* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:001BFC* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001BFD* + ID_OUI_FROM_DATABASE=Dignsys Inc. + +OUI:001BFE* + ID_OUI_FROM_DATABASE=Zavio Inc. + +OUI:001BFF* + ID_OUI_FROM_DATABASE=Millennia Media inc. + +OUI:001C00* + ID_OUI_FROM_DATABASE=Entry Point, LLC + +OUI:001C01* + ID_OUI_FROM_DATABASE=ABB Oy Drives + +OUI:001C02* + ID_OUI_FROM_DATABASE=Pano Logic + +OUI:001C03* + ID_OUI_FROM_DATABASE=Betty TV Technology AG + +OUI:001C04* + ID_OUI_FROM_DATABASE=Airgain, Inc. + +OUI:001C05* + ID_OUI_FROM_DATABASE=Nonin Medical Inc. + +OUI:001C06* + ID_OUI_FROM_DATABASE=Siemens Numerical Control Ltd., Nanjing + +OUI:001C07* + ID_OUI_FROM_DATABASE=Cwlinux Limited + +OUI:001C08* + ID_OUI_FROM_DATABASE=Echo360, Inc. + +OUI:001C09* + ID_OUI_FROM_DATABASE=SAE Electronic Co.,Ltd. + +OUI:001C0A* + ID_OUI_FROM_DATABASE=Shenzhen AEE Technology Co.,Ltd. + +OUI:001C0B* + ID_OUI_FROM_DATABASE=SmartAnt Telecom + +OUI:001C0C* + ID_OUI_FROM_DATABASE=TANITA Corporation + +OUI:001C0D* + ID_OUI_FROM_DATABASE=G-Technology, Inc. + +OUI:001C0E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001C0F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001C10* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001C11* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001C12* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001C13* + ID_OUI_FROM_DATABASE=OPTSYS TECHNOLOGY CO., LTD. + +OUI:001C14* + ID_OUI_FROM_DATABASE=VMware, Inc + +OUI:001C15* + ID_OUI_FROM_DATABASE=TXP Corporation + +OUI:001C16* + ID_OUI_FROM_DATABASE=ThyssenKrupp Elevator + +OUI:001C17* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001C18* + ID_OUI_FROM_DATABASE=Sicert S.r.L. + +OUI:001C19* + ID_OUI_FROM_DATABASE=secunet Security Networks AG + +OUI:001C1A* + ID_OUI_FROM_DATABASE=Thomas Instrumentation, Inc + +OUI:001C1B* + ID_OUI_FROM_DATABASE=Hyperstone GmbH + +OUI:001C1C* + ID_OUI_FROM_DATABASE=Center Communication Systems GmbH + +OUI:001C1D* + ID_OUI_FROM_DATABASE=CHENZHOU GOSPELL DIGITAL TECHNOLOGY CO.,LTD + +OUI:001C1E* + ID_OUI_FROM_DATABASE=emtrion GmbH + +OUI:001C1F* + ID_OUI_FROM_DATABASE=Quest Retail Technology Pty Ltd + +OUI:001C20* + ID_OUI_FROM_DATABASE=CLB Benelux + +OUI:001C21* + ID_OUI_FROM_DATABASE=Nucsafe Inc. + +OUI:001C22* + ID_OUI_FROM_DATABASE=Aeris Elettronica s.r.l. + +OUI:001C23* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:001C24* + ID_OUI_FROM_DATABASE=Formosa Wireless Systems Corp. + +OUI:001C25* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:001C26* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:001C27* + ID_OUI_FROM_DATABASE=Sunell Electronics Co. + +OUI:001C28* + ID_OUI_FROM_DATABASE=Sphairon Technologies GmbH + +OUI:001C29* + ID_OUI_FROM_DATABASE=CORE DIGITAL ELECTRONICS CO., LTD + +OUI:001C2A* + ID_OUI_FROM_DATABASE=Envisacor Technologies Inc. + +OUI:001C2B* + ID_OUI_FROM_DATABASE=Alertme.com Limited + +OUI:001C2C* + ID_OUI_FROM_DATABASE=Synapse + +OUI:001C2D* + ID_OUI_FROM_DATABASE=FlexRadio Systems + +OUI:001C2E* + ID_OUI_FROM_DATABASE=HPN Supply Chain + +OUI:001C2F* + ID_OUI_FROM_DATABASE=Pfister GmbH + +OUI:001C30* + ID_OUI_FROM_DATABASE=Mode Lighting (UK ) Ltd. + +OUI:001C31* + ID_OUI_FROM_DATABASE=Mobile XP Technology Co., LTD + +OUI:001C32* + ID_OUI_FROM_DATABASE=Telian Corporation + +OUI:001C33* + ID_OUI_FROM_DATABASE=Sutron + +OUI:001C34* + ID_OUI_FROM_DATABASE=HUEY CHIAO INTERNATIONAL CO., LTD. + +OUI:001C35* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001C36* + ID_OUI_FROM_DATABASE=iNEWiT NV + +OUI:001C37* + ID_OUI_FROM_DATABASE=Callpod, Inc. + +OUI:001C38* + ID_OUI_FROM_DATABASE=Bio-Rad Laboratories, Inc. + +OUI:001C39* + ID_OUI_FROM_DATABASE=S Netsystems Inc. + +OUI:001C3A* + ID_OUI_FROM_DATABASE=Element Labs, Inc. + +OUI:001C3B* + ID_OUI_FROM_DATABASE=AmRoad Technology Inc. + +OUI:001C3C* + ID_OUI_FROM_DATABASE=Seon Design Inc. + +OUI:001C3D* + ID_OUI_FROM_DATABASE=WaveStorm + +OUI:001C3E* + ID_OUI_FROM_DATABASE=ECKey Corporation + +OUI:001C3F* + ID_OUI_FROM_DATABASE=International Police Technologies, Inc. + +OUI:001C40* + ID_OUI_FROM_DATABASE=VDG-Security bv + +OUI:001C41* + ID_OUI_FROM_DATABASE=scemtec Transponder Technology GmbH + +OUI:001C42* + ID_OUI_FROM_DATABASE=Parallels, Inc. + +OUI:001C43* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001C44* + ID_OUI_FROM_DATABASE=Bosch Security Systems BV + +OUI:001C45* + ID_OUI_FROM_DATABASE=Chenbro Micom Co., Ltd. + +OUI:001C46* + ID_OUI_FROM_DATABASE=QTUM + +OUI:001C47* + ID_OUI_FROM_DATABASE=Hangzhou Hollysys Automation Co., Ltd + +OUI:001C48* + ID_OUI_FROM_DATABASE=WiDeFi, Inc. + +OUI:001C49* + ID_OUI_FROM_DATABASE=Zoltan Technology Inc. + +OUI:001C4A* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:001C4B* + ID_OUI_FROM_DATABASE=Gener8, Inc. + +OUI:001C4C* + ID_OUI_FROM_DATABASE=Petrotest Instruments + +OUI:001C4D* + ID_OUI_FROM_DATABASE=Aplix IP Holdings Corporation + +OUI:001C4E* + ID_OUI_FROM_DATABASE=TASA International Limited + +OUI:001C4F* + ID_OUI_FROM_DATABASE=MACAB AB + +OUI:001C50* + ID_OUI_FROM_DATABASE=TCL Technoly Electronics(Huizhou)Co.,Ltd + +OUI:001C51* + ID_OUI_FROM_DATABASE=Celeno Communications + +OUI:001C52* + ID_OUI_FROM_DATABASE=VISIONEE SRL + +OUI:001C53* + ID_OUI_FROM_DATABASE=Synergy Lighting Controls + +OUI:001C54* + ID_OUI_FROM_DATABASE=Hillstone Networks Inc + +OUI:001C55* + ID_OUI_FROM_DATABASE=Shenzhen Kaifa Technology Co. + +OUI:001C56* + ID_OUI_FROM_DATABASE=Pado Systems, Inc. + +OUI:001C57* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001C58* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001C59* + ID_OUI_FROM_DATABASE=DEVON IT + +OUI:001C5A* + ID_OUI_FROM_DATABASE=Advanced Relay Corporation + +OUI:001C5B* + ID_OUI_FROM_DATABASE=Chubb Electronic Security Systems Ltd + +OUI:001C5C* + ID_OUI_FROM_DATABASE=Integrated Medical Systems, Inc. + +OUI:001C5D* + ID_OUI_FROM_DATABASE=Leica Microsystems + +OUI:001C5E* + ID_OUI_FROM_DATABASE=ASTON France + +OUI:001C5F* + ID_OUI_FROM_DATABASE=Winland Electronics, Inc. + +OUI:001C60* + ID_OUI_FROM_DATABASE=CSP Frontier Technologies,Inc. + +OUI:001C61* + ID_OUI_FROM_DATABASE=Galaxy Microsystems LImited + +OUI:001C62* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:001C63* + ID_OUI_FROM_DATABASE=TRUEN + +OUI:001C64* + ID_OUI_FROM_DATABASE=Landis+Gyr + +OUI:001C65* + ID_OUI_FROM_DATABASE=JoeScan, Inc. + +OUI:001C66* + ID_OUI_FROM_DATABASE=UCAMP CO.,LTD + +OUI:001C67* + ID_OUI_FROM_DATABASE=Pumpkin Networks, Inc. + +OUI:001C68* + ID_OUI_FROM_DATABASE=Anhui Sun Create Electronics Co., Ltd + +OUI:001C69* + ID_OUI_FROM_DATABASE=Packet Vision Ltd + +OUI:001C6A* + ID_OUI_FROM_DATABASE=Weiss Engineering Ltd. + +OUI:001C6B* + ID_OUI_FROM_DATABASE=COVAX Co. Ltd + +OUI:001C6C* + ID_OUI_FROM_DATABASE=Jabil Circuit (Guangzhou) Limited + +OUI:001C6D* + ID_OUI_FROM_DATABASE=KYOHRITSU ELECTRONIC INDUSTRY CO., LTD. + +OUI:001C6E* + ID_OUI_FROM_DATABASE=Newbury Networks, Inc. + +OUI:001C6F* + ID_OUI_FROM_DATABASE=Emfit Ltd + +OUI:001C70* + ID_OUI_FROM_DATABASE=NOVACOMM LTDA + +OUI:001C71* + ID_OUI_FROM_DATABASE=Emergent Electronics + +OUI:001C72* + ID_OUI_FROM_DATABASE=Mayer & Cie GmbH & Co KG + +OUI:001C73* + ID_OUI_FROM_DATABASE=Arista Networks, Inc. + +OUI:001C74* + ID_OUI_FROM_DATABASE=Syswan Technologies Inc. + +OUI:001C75* + ID_OUI_FROM_DATABASE=RF Systems GmbH + +OUI:001C76* + ID_OUI_FROM_DATABASE=The Wandsworth Group Ltd + +OUI:001C77* + ID_OUI_FROM_DATABASE=Prodys + +OUI:001C78* + ID_OUI_FROM_DATABASE=WYPLAY SAS + +OUI:001C79* + ID_OUI_FROM_DATABASE=Cohesive Financial Technologies LLC + +OUI:001C7A* + ID_OUI_FROM_DATABASE=Perfectone Netware Company Ltd + +OUI:001C7B* + ID_OUI_FROM_DATABASE=Castlenet Technology Inc. + +OUI:001C7C* + ID_OUI_FROM_DATABASE=PERQ SYSTEMS CORPORATION + +OUI:001C7D* + ID_OUI_FROM_DATABASE=Excelpoint Manufacturing Pte Ltd + +OUI:001C7E* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:001C7F* + ID_OUI_FROM_DATABASE=Check Point Software Technologies + +OUI:001C80* + ID_OUI_FROM_DATABASE=New Business Division/Rhea-Information CO., LTD. + +OUI:001C81* + ID_OUI_FROM_DATABASE=NextGen Venturi LTD + +OUI:001C82* + ID_OUI_FROM_DATABASE=Genew Technologies + +OUI:001C83* + ID_OUI_FROM_DATABASE=New Level Telecom Co., Ltd. + +OUI:001C84* + ID_OUI_FROM_DATABASE=STL Solution Co.,Ltd. + +OUI:001C85* + ID_OUI_FROM_DATABASE=Eunicorn + +OUI:001C86* + ID_OUI_FROM_DATABASE=Cranite Systems, Inc. + +OUI:001C87* + ID_OUI_FROM_DATABASE=Uriver Inc. + +OUI:001C88* + ID_OUI_FROM_DATABASE=TRANSYSTEM INC. + +OUI:001C89* + ID_OUI_FROM_DATABASE=Force Communications, Inc. + +OUI:001C8A* + ID_OUI_FROM_DATABASE=Cirrascale Corporation + +OUI:001C8B* + ID_OUI_FROM_DATABASE=MJ Innovations Ltd. + +OUI:001C8C* + ID_OUI_FROM_DATABASE=DIAL TECHNOLOGY LTD. + +OUI:001C8D* + ID_OUI_FROM_DATABASE=Mesa Imaging + +OUI:001C8E* + ID_OUI_FROM_DATABASE=Alcatel-Lucent IPD + +OUI:001C8F* + ID_OUI_FROM_DATABASE=Advanced Electronic Design, Inc. + +OUI:001C90* + ID_OUI_FROM_DATABASE=Empacket Corporation + +OUI:001C91* + ID_OUI_FROM_DATABASE=Gefen Inc. + +OUI:001C92* + ID_OUI_FROM_DATABASE=Tervela + +OUI:001C93* + ID_OUI_FROM_DATABASE=ExaDigm Inc + +OUI:001C94* + ID_OUI_FROM_DATABASE=LI-COR Biosciences + +OUI:001C95* + ID_OUI_FROM_DATABASE=Opticomm Corporation + +OUI:001C96* + ID_OUI_FROM_DATABASE=Linkwise Technology Pte Ltd + +OUI:001C97* + ID_OUI_FROM_DATABASE=Enzytek Technology Inc., + +OUI:001C98* + ID_OUI_FROM_DATABASE=LUCKY TECHNOLOGY (HK) COMPANY LIMITED + +OUI:001C99* + ID_OUI_FROM_DATABASE=Shunra Software Ltd. + +OUI:001C9A* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001C9B* + ID_OUI_FROM_DATABASE=FEIG ELECTRONIC GmbH + +OUI:001C9C* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001C9D* + ID_OUI_FROM_DATABASE=Liecthi AG + +OUI:001C9E* + ID_OUI_FROM_DATABASE=Dualtech IT AB + +OUI:001C9F* + ID_OUI_FROM_DATABASE=Razorstream, LLC + +OUI:001CA0* + ID_OUI_FROM_DATABASE=Production Resource Group, LLC + +OUI:001CA1* + ID_OUI_FROM_DATABASE=AKAMAI TECHNOLOGIES, INC. + +OUI:001CA2* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:001CA3* + ID_OUI_FROM_DATABASE=Terra + +OUI:001CA4* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:001CA5* + ID_OUI_FROM_DATABASE=Zygo Corporation + +OUI:001CA6* + ID_OUI_FROM_DATABASE=Win4NET + +OUI:001CA7* + ID_OUI_FROM_DATABASE=International Quartz Limited + +OUI:001CA8* + ID_OUI_FROM_DATABASE=AirTies Wireless Networks + +OUI:001CA9* + ID_OUI_FROM_DATABASE=Audiomatica Srl + +OUI:001CAA* + ID_OUI_FROM_DATABASE=Bellon Pty Ltd + +OUI:001CAB* + ID_OUI_FROM_DATABASE=Meyer Sound Laboratories, Inc. + +OUI:001CAC* + ID_OUI_FROM_DATABASE=Qniq Technology Corp. + +OUI:001CAD* + ID_OUI_FROM_DATABASE=Wuhan Telecommunication Devices Co.,Ltd + +OUI:001CAE* + ID_OUI_FROM_DATABASE=WiChorus, Inc. + +OUI:001CAF* + ID_OUI_FROM_DATABASE=Plato Networks Inc. + +OUI:001CB0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001CB1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001CB2* + ID_OUI_FROM_DATABASE=BPT SPA + +OUI:001CB3* + ID_OUI_FROM_DATABASE=Apple + +OUI:001CB4* + ID_OUI_FROM_DATABASE=Iridium Satellite LLC + +OUI:001CB5* + ID_OUI_FROM_DATABASE=Neihua Network Technology Co.,LTD.(NHN) + +OUI:001CB6* + ID_OUI_FROM_DATABASE=Duzon CNT Co., Ltd. + +OUI:001CB7* + ID_OUI_FROM_DATABASE=USC DigiArk Corporation + +OUI:001CB8* + ID_OUI_FROM_DATABASE=CBC Co., Ltd + +OUI:001CB9* + ID_OUI_FROM_DATABASE=KWANG SUNG ELECTRONICS CO., LTD. + +OUI:001CBA* + ID_OUI_FROM_DATABASE=VerScient, Inc. + +OUI:001CBB* + ID_OUI_FROM_DATABASE=MusicianLink + +OUI:001CBC* + ID_OUI_FROM_DATABASE=CastGrabber, LLC + +OUI:001CBD* + ID_OUI_FROM_DATABASE=Ezze Mobile Tech., Inc. + +OUI:001CBE* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001CBF* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001CC0* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001CC1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001CC2* + ID_OUI_FROM_DATABASE=Part II Research, Inc. + +OUI:001CC3* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:001CC4* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001CC5* + ID_OUI_FROM_DATABASE=3COM LTD + +OUI:001CC6* + ID_OUI_FROM_DATABASE=ProStor Systems + +OUI:001CC7* + ID_OUI_FROM_DATABASE=Rembrandt Technologies, LLC d/b/a REMSTREAM + +OUI:001CC8* + ID_OUI_FROM_DATABASE=INDUSTRONIC Industrie-Electronic GmbH & Co. KG + +OUI:001CC9* + ID_OUI_FROM_DATABASE=Kaise Electronic Technology Co., Ltd. + +OUI:001CCA* + ID_OUI_FROM_DATABASE=Shanghai Gaozhi Science & Technology Development Co. + +OUI:001CCB* + ID_OUI_FROM_DATABASE=Forth Corporation Public Company Limited + +OUI:001CCC* + ID_OUI_FROM_DATABASE=Research In Motion Limited + +OUI:001CCD* + ID_OUI_FROM_DATABASE=Alektrona Corporation + +OUI:001CCE* + ID_OUI_FROM_DATABASE=By Techdesign + +OUI:001CCF* + ID_OUI_FROM_DATABASE=LIMETEK + +OUI:001CD0* + ID_OUI_FROM_DATABASE=Circleone Co.,Ltd. + +OUI:001CD1* + ID_OUI_FROM_DATABASE=Waves Audio LTD + +OUI:001CD2* + ID_OUI_FROM_DATABASE=King Champion (Hong Kong) Limited + +OUI:001CD3* + ID_OUI_FROM_DATABASE=ZP Engineering SEL + +OUI:001CD4* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001CD5* + ID_OUI_FROM_DATABASE=ZeeVee, Inc. + +OUI:001CD6* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001CD7* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +OUI:001CD8* + ID_OUI_FROM_DATABASE=BlueAnt Wireless + +OUI:001CD9* + ID_OUI_FROM_DATABASE=GlobalTop Technology Inc. + +OUI:001CDA* + ID_OUI_FROM_DATABASE=Exegin Technologies Limited + +OUI:001CDB* + ID_OUI_FROM_DATABASE=CARPOINT CO.,LTD + +OUI:001CDC* + ID_OUI_FROM_DATABASE=Custom Computer Services, Inc. + +OUI:001CDD* + ID_OUI_FROM_DATABASE=COWBELL ENGINEERING CO., LTD. + +OUI:001CDE* + ID_OUI_FROM_DATABASE=Interactive Multimedia eXchange Inc. + +OUI:001CDF* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:001CE0* + ID_OUI_FROM_DATABASE=DASAN TPS + +OUI:001CE1* + ID_OUI_FROM_DATABASE=INDRA SISTEMAS, S.A. + +OUI:001CE2* + ID_OUI_FROM_DATABASE=Attero Tech, LLC. + +OUI:001CE3* + ID_OUI_FROM_DATABASE=Optimedical Systems + +OUI:001CE4* + ID_OUI_FROM_DATABASE=EleSy JSC + +OUI:001CE5* + ID_OUI_FROM_DATABASE=MBS Electronic Systems GmbH + +OUI:001CE6* + ID_OUI_FROM_DATABASE=INNES + +OUI:001CE7* + ID_OUI_FROM_DATABASE=Rocon PLC Research Centre + +OUI:001CE8* + ID_OUI_FROM_DATABASE=Cummins Inc + +OUI:001CE9* + ID_OUI_FROM_DATABASE=Galaxy Technology Limited + +OUI:001CEA* + ID_OUI_FROM_DATABASE=Scientific-Atlanta, Inc + +OUI:001CEB* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001CEC* + ID_OUI_FROM_DATABASE=Mobilesoft (Aust.) Pty Ltd + +OUI:001CED* + ID_OUI_FROM_DATABASE=ENVIRONNEMENT SA + +OUI:001CEE* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:001CEF* + ID_OUI_FROM_DATABASE=Primax Electronics LTD + +OUI:001CF0* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:001CF1* + ID_OUI_FROM_DATABASE=SUPoX Technology Co. , LTD. + +OUI:001CF2* + ID_OUI_FROM_DATABASE=Tenlon Technology Co.,Ltd. + +OUI:001CF3* + ID_OUI_FROM_DATABASE=EVS BROADCAST EQUIPMENT + +OUI:001CF4* + ID_OUI_FROM_DATABASE=Media Technology Systems Inc + +OUI:001CF5* + ID_OUI_FROM_DATABASE=Wiseblue Technology Limited + +OUI:001CF6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001CF7* + ID_OUI_FROM_DATABASE=AudioScience + +OUI:001CF8* + ID_OUI_FROM_DATABASE=Parade Technologies, Ltd. + +OUI:001CF9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001CFA* + ID_OUI_FROM_DATABASE=Alarm.com + +OUI:001CFB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001CFC* + ID_OUI_FROM_DATABASE=Suminet Communication Technologies (Shanghai) Co., Ltd. + +OUI:001CFD* + ID_OUI_FROM_DATABASE=Universal Electronics + +OUI:001CFE* + ID_OUI_FROM_DATABASE=Quartics Inc + +OUI:001CFF* + ID_OUI_FROM_DATABASE=Napera Networks Inc + +OUI:001D00* + ID_OUI_FROM_DATABASE=Brivo Systems, LLC + +OUI:001D01* + ID_OUI_FROM_DATABASE=Neptune Digital + +OUI:001D02* + ID_OUI_FROM_DATABASE=Cybertech Telecom Development + +OUI:001D03* + ID_OUI_FROM_DATABASE=Design Solutions Inc. + +OUI:001D04* + ID_OUI_FROM_DATABASE=Zipit Wireless, Inc. + +OUI:001D05* + ID_OUI_FROM_DATABASE=iLight + +OUI:001D06* + ID_OUI_FROM_DATABASE=HM Electronics, Inc. + +OUI:001D07* + ID_OUI_FROM_DATABASE=Shenzhen Sang Fei Consumer Communications Co.,Ltd + +OUI:001D08* + ID_OUI_FROM_DATABASE=JIANGSU YINHE ELECTRONICS CO., LTD + +OUI:001D09* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:001D0A* + ID_OUI_FROM_DATABASE=Davis Instruments, Inc. + +OUI:001D0B* + ID_OUI_FROM_DATABASE=Power Standards Lab + +OUI:001D0C* + ID_OUI_FROM_DATABASE=MobileCompia + +OUI:001D0D* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment inc. + +OUI:001D0E* + ID_OUI_FROM_DATABASE=Agapha Technology co., Ltd. + +OUI:001D0F* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co., Ltd. + +OUI:001D10* + ID_OUI_FROM_DATABASE=LightHaus Logic, Inc. + +OUI:001D11* + ID_OUI_FROM_DATABASE=Analogue & Micro Ltd + +OUI:001D12* + ID_OUI_FROM_DATABASE=ROHM CO., LTD. + +OUI:001D13* + ID_OUI_FROM_DATABASE=NextGTV + +OUI:001D14* + ID_OUI_FROM_DATABASE=SPERADTONE INFORMATION TECHNOLOGY LIMITED + +OUI:001D15* + ID_OUI_FROM_DATABASE=Shenzhen Dolphin Electronic Co., Ltd + +OUI:001D16* + ID_OUI_FROM_DATABASE=Efixo + +OUI:001D17* + ID_OUI_FROM_DATABASE=Digital Sky Corporation + +OUI:001D18* + ID_OUI_FROM_DATABASE=Power Innovation GmbH + +OUI:001D19* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:001D1A* + ID_OUI_FROM_DATABASE=OvisLink S.A. + +OUI:001D1B* + ID_OUI_FROM_DATABASE=Sangean Electronics Inc. + +OUI:001D1C* + ID_OUI_FROM_DATABASE=Gennet s.a. + +OUI:001D1D* + ID_OUI_FROM_DATABASE=Inter-M Corporation + +OUI:001D1E* + ID_OUI_FROM_DATABASE=KYUSHU TEN CO.,LTD + +OUI:001D1F* + ID_OUI_FROM_DATABASE=Siauliu Tauro Televizoriai, JSC + +OUI:001D20* + ID_OUI_FROM_DATABASE=COMTREND CO. + +OUI:001D21* + ID_OUI_FROM_DATABASE=Alcad SL + +OUI:001D22* + ID_OUI_FROM_DATABASE=Foss Analytical A/S + +OUI:001D23* + ID_OUI_FROM_DATABASE=SENSUS + +OUI:001D24* + ID_OUI_FROM_DATABASE=Aclara Power-Line Systems Inc. + +OUI:001D25* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001D26* + ID_OUI_FROM_DATABASE=Rockridgesound Technology Co. + +OUI:001D27* + ID_OUI_FROM_DATABASE=NAC-INTERCOM + +OUI:001D28* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:001D29* + ID_OUI_FROM_DATABASE=Doro AB + +OUI:001D2A* + ID_OUI_FROM_DATABASE=SHENZHEN BUL-TECH CO.,LTD. + +OUI:001D2B* + ID_OUI_FROM_DATABASE=Wuhan Pont Technology CO. , LTD + +OUI:001D2C* + ID_OUI_FROM_DATABASE=Wavetrend Technologies (Pty) Limited + +OUI:001D2D* + ID_OUI_FROM_DATABASE=Pylone, Inc. + +OUI:001D2E* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:001D2F* + ID_OUI_FROM_DATABASE=QuantumVision Corporation + +OUI:001D30* + ID_OUI_FROM_DATABASE=YX Wireless S.A. + +OUI:001D31* + ID_OUI_FROM_DATABASE=HIGHPRO INTERNATIONAL R&D CO,.LTD. + +OUI:001D32* + ID_OUI_FROM_DATABASE=Longkay Communication & Technology (Shanghai) Co. Ltd + +OUI:001D33* + ID_OUI_FROM_DATABASE=Maverick Systems Inc. + +OUI:001D34* + ID_OUI_FROM_DATABASE=SYRIS Technology Corp + +OUI:001D35* + ID_OUI_FROM_DATABASE=Viconics Electronics Inc. + +OUI:001D36* + ID_OUI_FROM_DATABASE=ELECTRONICS CORPORATION OF INDIA LIMITED + +OUI:001D37* + ID_OUI_FROM_DATABASE=Thales-Panda Transportation System + +OUI:001D38* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:001D39* + ID_OUI_FROM_DATABASE=MOOHADIGITAL CO., LTD + +OUI:001D3A* + ID_OUI_FROM_DATABASE=mh acoustics LLC + +OUI:001D3B* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001D3C* + ID_OUI_FROM_DATABASE=Muscle Corporation + +OUI:001D3D* + ID_OUI_FROM_DATABASE=Avidyne Corporation + +OUI:001D3E* + ID_OUI_FROM_DATABASE=SAKA TECHNO SCIENCE CO.,LTD + +OUI:001D3F* + ID_OUI_FROM_DATABASE=Mitron Pty Ltd + +OUI:001D40* + ID_OUI_FROM_DATABASE=Living Independently Group, Inc. + +OUI:001D41* + ID_OUI_FROM_DATABASE=Hardy Instruments + +OUI:001D42* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001D43* + ID_OUI_FROM_DATABASE=Shenzhen G-link Digital Technology Co., Ltd. + +OUI:001D44* + ID_OUI_FROM_DATABASE=Krohne + +OUI:001D45* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001D46* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001D47* + ID_OUI_FROM_DATABASE=Covote GmbH & Co KG + +OUI:001D48* + ID_OUI_FROM_DATABASE=Sensor-Technik Wiedemann GmbH + +OUI:001D49* + ID_OUI_FROM_DATABASE=Innovation Wireless Inc. + +OUI:001D4A* + ID_OUI_FROM_DATABASE=Carestream Health, Inc. + +OUI:001D4B* + ID_OUI_FROM_DATABASE=Grid Connect Inc. + +OUI:001D4C* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:001D4D* + ID_OUI_FROM_DATABASE=Adaptive Recognition Hungary, Inc + +OUI:001D4E* + ID_OUI_FROM_DATABASE=TCM Mobile LLC + +OUI:001D4F* + ID_OUI_FROM_DATABASE=Apple + +OUI:001D50* + ID_OUI_FROM_DATABASE=SPINETIX SA + +OUI:001D51* + ID_OUI_FROM_DATABASE=Babcock & Wilcox Power Generation Group, Inc + +OUI:001D52* + ID_OUI_FROM_DATABASE=Defzone B.V. + +OUI:001D53* + ID_OUI_FROM_DATABASE=S&O Electronics (Malaysia) Sdn. Bhd. + +OUI:001D54* + ID_OUI_FROM_DATABASE=Sunnic Technology & Merchandise INC. + +OUI:001D55* + ID_OUI_FROM_DATABASE=ZANTAZ, Inc + +OUI:001D56* + ID_OUI_FROM_DATABASE=Kramer Electronics Ltd. + +OUI:001D57* + ID_OUI_FROM_DATABASE=CAETEC Messtechnik + +OUI:001D58* + ID_OUI_FROM_DATABASE=CQ Inc + +OUI:001D59* + ID_OUI_FROM_DATABASE=Mitra Energy & Infrastructure + +OUI:001D5A* + ID_OUI_FROM_DATABASE=2Wire Inc. + +OUI:001D5B* + ID_OUI_FROM_DATABASE=Tecvan Informática Ltda + +OUI:001D5C* + ID_OUI_FROM_DATABASE=Tom Communication Industrial Co.,Ltd. + +OUI:001D5D* + ID_OUI_FROM_DATABASE=Control Dynamics Pty. Ltd. + +OUI:001D5E* + ID_OUI_FROM_DATABASE=COMING MEDIA CORP. + +OUI:001D5F* + ID_OUI_FROM_DATABASE=OverSpeed SARL + +OUI:001D60* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001D61* + ID_OUI_FROM_DATABASE=BIJ Corporation + +OUI:001D62* + ID_OUI_FROM_DATABASE=InPhase Technologies + +OUI:001D63* + ID_OUI_FROM_DATABASE=Miele & Cie. KG + +OUI:001D64* + ID_OUI_FROM_DATABASE=Adam Communications Systems Int Ltd + +OUI:001D65* + ID_OUI_FROM_DATABASE=Microwave Radio Communications + +OUI:001D66* + ID_OUI_FROM_DATABASE=Hyundai Telecom + +OUI:001D67* + ID_OUI_FROM_DATABASE=AMEC + +OUI:001D68* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:001D69* + ID_OUI_FROM_DATABASE=Knorr-Bremse IT-Services GmbH + +OUI:001D6A* + ID_OUI_FROM_DATABASE=Alpha Networks Inc. + +OUI:001D6B* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001D6C* + ID_OUI_FROM_DATABASE=ClariPhy Communications, Inc. + +OUI:001D6D* + ID_OUI_FROM_DATABASE=Confidant International LLC + +OUI:001D6E* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001D6F* + ID_OUI_FROM_DATABASE=Chainzone Technology Co., Ltd + +OUI:001D70* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001D71* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001D72* + ID_OUI_FROM_DATABASE=Wistron Corporation + +OUI:001D73* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:001D74* + ID_OUI_FROM_DATABASE=Tianjin China-Silicon Microelectronics Co., Ltd. + +OUI:001D75* + ID_OUI_FROM_DATABASE=Radioscape PLC + +OUI:001D76* + ID_OUI_FROM_DATABASE=Eyeheight Ltd. + +OUI:001D77* + ID_OUI_FROM_DATABASE=NSGate + +OUI:001D78* + ID_OUI_FROM_DATABASE=Invengo Information Technology Co.,Ltd + +OUI:001D79* + ID_OUI_FROM_DATABASE=SIGNAMAX LLC + +OUI:001D7A* + ID_OUI_FROM_DATABASE=Wideband Semiconductor, Inc. + +OUI:001D7B* + ID_OUI_FROM_DATABASE=Ice Energy, Inc. + +OUI:001D7C* + ID_OUI_FROM_DATABASE=ABE Elettronica S.p.A. + +OUI:001D7D* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:001D7E* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001D7F* + ID_OUI_FROM_DATABASE=Tekron International Ltd + +OUI:001D80* + ID_OUI_FROM_DATABASE=Beijing Huahuan Eletronics Co.,Ltd + +OUI:001D81* + ID_OUI_FROM_DATABASE=GUANGZHOU GATEWAY ELECTRONICS CO., LTD + +OUI:001D82* + ID_OUI_FROM_DATABASE=GN A/S (GN Netcom A/S) + +OUI:001D83* + ID_OUI_FROM_DATABASE=Emitech Corporation + +OUI:001D84* + ID_OUI_FROM_DATABASE=Gateway, Inc. + +OUI:001D85* + ID_OUI_FROM_DATABASE=Call Direct Cellular Solutions + +OUI:001D86* + ID_OUI_FROM_DATABASE=Shinwa Industries(China) Ltd. + +OUI:001D87* + ID_OUI_FROM_DATABASE=VigTech Labs Sdn Bhd + +OUI:001D88* + ID_OUI_FROM_DATABASE=Clearwire + +OUI:001D89* + ID_OUI_FROM_DATABASE=VaultStor Corporation + +OUI:001D8A* + ID_OUI_FROM_DATABASE=TechTrex Inc + +OUI:001D8B* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:001D8C* + ID_OUI_FROM_DATABASE=La Crosse Technology LTD + +OUI:001D8D* + ID_OUI_FROM_DATABASE=Raytek GmbH + +OUI:001D8E* + ID_OUI_FROM_DATABASE=Alereon, Inc. + +OUI:001D8F* + ID_OUI_FROM_DATABASE=PureWave Networks + +OUI:001D90* + ID_OUI_FROM_DATABASE=EMCO Flow Systems + +OUI:001D91* + ID_OUI_FROM_DATABASE=Digitize, Inc + +OUI:001D92* + ID_OUI_FROM_DATABASE=MICRO-STAR INT'L CO.,LTD. + +OUI:001D93* + ID_OUI_FROM_DATABASE=Modacom + +OUI:001D94* + ID_OUI_FROM_DATABASE=Climax Technology Co., Ltd + +OUI:001D95* + ID_OUI_FROM_DATABASE=Flash, Inc. + +OUI:001D96* + ID_OUI_FROM_DATABASE=WatchGuard Video + +OUI:001D97* + ID_OUI_FROM_DATABASE=Alertus Technologies LLC + +OUI:001D98* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001D99* + ID_OUI_FROM_DATABASE=Cyan Optic, Inc. + +OUI:001D9A* + ID_OUI_FROM_DATABASE=GODEX INTERNATIONAL CO., LTD + +OUI:001D9B* + ID_OUI_FROM_DATABASE=Hokuyo Automatic Co., Ltd. + +OUI:001D9C* + ID_OUI_FROM_DATABASE=Rockwell Automation + +OUI:001D9D* + ID_OUI_FROM_DATABASE=ARTJOY INTERNATIONAL LIMITED + +OUI:001D9E* + ID_OUI_FROM_DATABASE=AXION TECHNOLOGIES + +OUI:001D9F* + ID_OUI_FROM_DATABASE=MATT R.P.Traczynscy Sp.J. + +OUI:001DA0* + ID_OUI_FROM_DATABASE=Heng Yu Electronic Manufacturing Company Limited + +OUI:001DA1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001DA2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001DA3* + ID_OUI_FROM_DATABASE=SabiOso + +OUI:001DA4* + ID_OUI_FROM_DATABASE=Hangzhou System Technology CO., LTD + +OUI:001DA5* + ID_OUI_FROM_DATABASE=WB Electronics + +OUI:001DA6* + ID_OUI_FROM_DATABASE=Media Numerics Limited + +OUI:001DA7* + ID_OUI_FROM_DATABASE=Seamless Internet + +OUI:001DA8* + ID_OUI_FROM_DATABASE=Takahata Electronics Co.,Ltd + +OUI:001DA9* + ID_OUI_FROM_DATABASE=Castles Technology, Co., LTD + +OUI:001DAA* + ID_OUI_FROM_DATABASE=DrayTek Corp. + +OUI:001DAB* + ID_OUI_FROM_DATABASE=SwissQual License AG + +OUI:001DAC* + ID_OUI_FROM_DATABASE=Gigamon Systems LLC + +OUI:001DAD* + ID_OUI_FROM_DATABASE=Sinotech Engineering Consultants, Inc. Geotechnical Enginee + +OUI:001DAE* + ID_OUI_FROM_DATABASE=CHANG TSENG TECHNOLOGY CO., LTD + +OUI:001DAF* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001DB0* + ID_OUI_FROM_DATABASE=FuJian HengTong Information Technology Co.,Ltd + +OUI:001DB1* + ID_OUI_FROM_DATABASE=Crescendo Networks + +OUI:001DB2* + ID_OUI_FROM_DATABASE=HOKKAIDO ELECTRIC ENGINEERING CO.,LTD. + +OUI:001DB3* + ID_OUI_FROM_DATABASE=HPN Supply Chain + +OUI:001DB4* + ID_OUI_FROM_DATABASE=KUMHO ENG CO.,LTD + +OUI:001DB5* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:001DB6* + ID_OUI_FROM_DATABASE=BestComm Networks, Inc. + +OUI:001DB7* + ID_OUI_FROM_DATABASE=Tendril Networks, Inc. + +OUI:001DB8* + ID_OUI_FROM_DATABASE=Intoto Inc. + +OUI:001DB9* + ID_OUI_FROM_DATABASE=Wellspring Wireless + +OUI:001DBA* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:001DBB* + ID_OUI_FROM_DATABASE=Dynamic System Electronics Corp. + +OUI:001DBC* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001DBD* + ID_OUI_FROM_DATABASE=Versamed Inc. + +OUI:001DBE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DBF* + ID_OUI_FROM_DATABASE=Radiient Technologies, Inc. + +OUI:001DC0* + ID_OUI_FROM_DATABASE=Enphase Energy + +OUI:001DC1* + ID_OUI_FROM_DATABASE=Audinate Pty L + +OUI:001DC2* + ID_OUI_FROM_DATABASE=XORTEC OY + +OUI:001DC3* + ID_OUI_FROM_DATABASE=RIKOR TV, Ltd + +OUI:001DC4* + ID_OUI_FROM_DATABASE=AIOI Systems Co., Ltd. + +OUI:001DC5* + ID_OUI_FROM_DATABASE=Beijing Jiaxun Feihong Electricial Co., Ltd. + +OUI:001DC6* + ID_OUI_FROM_DATABASE=SNR Inc. + +OUI:001DC7* + ID_OUI_FROM_DATABASE=L-3 Communications Geneva Aerospace + +OUI:001DC8* + ID_OUI_FROM_DATABASE=Navionics Research Inc., dba SCADAmetrics + +OUI:001DC9* + ID_OUI_FROM_DATABASE=GainSpan Corp. + +OUI:001DCA* + ID_OUI_FROM_DATABASE=PAV Electronics Limited + +OUI:001DCB* + ID_OUI_FROM_DATABASE=Exéns Development Oy + +OUI:001DCC* + ID_OUI_FROM_DATABASE=Hetra Secure Solutions + +OUI:001DCD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DCE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DCF* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD5* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD6* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD7* + ID_OUI_FROM_DATABASE=Algolith + +OUI:001DD8* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:001DD9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.,Ltd. + +OUI:001DDA* + ID_OUI_FROM_DATABASE=Mikroelektronika spol. s r. o. + +OUI:001DDB* + ID_OUI_FROM_DATABASE=C-BEL Corporation + +OUI:001DDC* + ID_OUI_FROM_DATABASE=HangZhou DeChangLong Tech&Info Co.,Ltd + +OUI:001DDD* + ID_OUI_FROM_DATABASE=DAT H.K. LIMITED + +OUI:001DDE* + ID_OUI_FROM_DATABASE=Zhejiang Broadcast&Television Technology Co.,Ltd. + +OUI:001DDF* + ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd. + +OUI:001DE0* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001DE1* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001DE2* + ID_OUI_FROM_DATABASE=Radionor Communications + +OUI:001DE3* + ID_OUI_FROM_DATABASE=Intuicom + +OUI:001DE4* + ID_OUI_FROM_DATABASE=Visioneered Image Systems + +OUI:001DE5* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001DE6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001DE7* + ID_OUI_FROM_DATABASE=Marine Sonic Technology, Ltd. + +OUI:001DE8* + ID_OUI_FROM_DATABASE=Nikko Denki Tsushin Corporation(NDTC) + +OUI:001DE9* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001DEA* + ID_OUI_FROM_DATABASE=Commtest Instruments Ltd + +OUI:001DEB* + ID_OUI_FROM_DATABASE=DINEC International + +OUI:001DEC* + ID_OUI_FROM_DATABASE=Marusys + +OUI:001DED* + ID_OUI_FROM_DATABASE=Grid Net, Inc. + +OUI:001DEE* + ID_OUI_FROM_DATABASE=NEXTVISION SISTEMAS DIGITAIS DE TELEVISÃO LTDA. + +OUI:001DEF* + ID_OUI_FROM_DATABASE=TRIMM, INC. + +OUI:001DF0* + ID_OUI_FROM_DATABASE=Vidient Systems, Inc. + +OUI:001DF1* + ID_OUI_FROM_DATABASE=Intego Systems, Inc. + +OUI:001DF2* + ID_OUI_FROM_DATABASE=Netflix, Inc. + +OUI:001DF3* + ID_OUI_FROM_DATABASE=SBS Science & Technology Co., Ltd + +OUI:001DF4* + ID_OUI_FROM_DATABASE=Magellan Technology Pty Limited + +OUI:001DF5* + ID_OUI_FROM_DATABASE=Sunshine Co,LTD + +OUI:001DF6* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001DF7* + ID_OUI_FROM_DATABASE=R. STAHL Schaltgeräte GmbH + +OUI:001DF8* + ID_OUI_FROM_DATABASE=Webpro Vision Technology Corporation + +OUI:001DF9* + ID_OUI_FROM_DATABASE=Cybiotronics (Far East) Limited + +OUI:001DFA* + ID_OUI_FROM_DATABASE=Fujian LANDI Commercial Equipment Co.,Ltd + +OUI:001DFB* + ID_OUI_FROM_DATABASE=NETCLEUS Systems Corporation + +OUI:001DFC* + ID_OUI_FROM_DATABASE=KSIC + +OUI:001DFD* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001DFE* + ID_OUI_FROM_DATABASE=Palm, Inc + +OUI:001DFF* + ID_OUI_FROM_DATABASE=Network Critical Solutions Ltd + +OUI:001E00* + ID_OUI_FROM_DATABASE=Shantou Institute of Ultrasonic Instruments + +OUI:001E01* + ID_OUI_FROM_DATABASE=Renesas Technology Sales Co., Ltd. + +OUI:001E02* + ID_OUI_FROM_DATABASE=Sougou Keikaku Kougyou Co.,Ltd. + +OUI:001E03* + ID_OUI_FROM_DATABASE=LiComm Co., Ltd. + +OUI:001E04* + ID_OUI_FROM_DATABASE=Hanson Research Corporation + +OUI:001E05* + ID_OUI_FROM_DATABASE=Xseed Technologies & Computing + +OUI:001E06* + ID_OUI_FROM_DATABASE=WIBRAIN + +OUI:001E07* + ID_OUI_FROM_DATABASE=Winy Technology Co., Ltd. + +OUI:001E08* + ID_OUI_FROM_DATABASE=Centec Networks Inc + +OUI:001E09* + ID_OUI_FROM_DATABASE=ZEFATEK Co.,LTD + +OUI:001E0A* + ID_OUI_FROM_DATABASE=Syba Tech Limited + +OUI:001E0B* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001E0C* + ID_OUI_FROM_DATABASE=Sherwood Information Partners, Inc. + +OUI:001E0D* + ID_OUI_FROM_DATABASE=Micran Ltd. + +OUI:001E0E* + ID_OUI_FROM_DATABASE=MAXI VIEW HOLDINGS LIMITED + +OUI:001E0F* + ID_OUI_FROM_DATABASE=Briot International + +OUI:001E10* + ID_OUI_FROM_DATABASE=ShenZhen Huawei Communication Technologies Co.,Ltd. + +OUI:001E11* + ID_OUI_FROM_DATABASE=ELELUX INTERNATIONAL LTD + +OUI:001E12* + ID_OUI_FROM_DATABASE=Ecolab + +OUI:001E13* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E14* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E15* + ID_OUI_FROM_DATABASE=Beech Hill Electronics + +OUI:001E16* + ID_OUI_FROM_DATABASE=Keytronix + +OUI:001E17* + ID_OUI_FROM_DATABASE=STN BV + +OUI:001E18* + ID_OUI_FROM_DATABASE=Radio Activity srl + +OUI:001E19* + ID_OUI_FROM_DATABASE=GTRI + +OUI:001E1A* + ID_OUI_FROM_DATABASE=Best Source Taiwan Inc. + +OUI:001E1B* + ID_OUI_FROM_DATABASE=Digital Stream Technology, Inc. + +OUI:001E1C* + ID_OUI_FROM_DATABASE=SWS Australia Pty Limited + +OUI:001E1D* + ID_OUI_FROM_DATABASE=East Coast Datacom, Inc. + +OUI:001E1E* + ID_OUI_FROM_DATABASE=Honeywell Life Safety + +OUI:001E1F* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001E20* + ID_OUI_FROM_DATABASE=Intertain Inc. + +OUI:001E21* + ID_OUI_FROM_DATABASE=Qisda Co. + +OUI:001E22* + ID_OUI_FROM_DATABASE=ARVOO Imaging Products BV + +OUI:001E23* + ID_OUI_FROM_DATABASE=Electronic Educational Devices, Inc + +OUI:001E24* + ID_OUI_FROM_DATABASE=Zhejiang Bell Technology Co.,ltd + +OUI:001E25* + ID_OUI_FROM_DATABASE=Intek Digital Inc + +OUI:001E26* + ID_OUI_FROM_DATABASE=Digifriends Co. Ltd + +OUI:001E27* + ID_OUI_FROM_DATABASE=SBN TECH Co.,Ltd. + +OUI:001E28* + ID_OUI_FROM_DATABASE=Lumexis Corporation + +OUI:001E29* + ID_OUI_FROM_DATABASE=Hypertherm Inc + +OUI:001E2A* + ID_OUI_FROM_DATABASE=Netgear Inc. + +OUI:001E2B* + ID_OUI_FROM_DATABASE=Radio Systems Design, Inc. + +OUI:001E2C* + ID_OUI_FROM_DATABASE=CyVerse Corporation + +OUI:001E2D* + ID_OUI_FROM_DATABASE=STIM + +OUI:001E2E* + ID_OUI_FROM_DATABASE=SIRTI S.p.A. + +OUI:001E2F* + ID_OUI_FROM_DATABASE=DiMoto Pty Ltd + +OUI:001E30* + ID_OUI_FROM_DATABASE=Shireen Inc + +OUI:001E31* + ID_OUI_FROM_DATABASE=INFOMARK CO.,LTD. + +OUI:001E32* + ID_OUI_FROM_DATABASE=Zensys + +OUI:001E33* + ID_OUI_FROM_DATABASE=Inventec Corporation + +OUI:001E34* + ID_OUI_FROM_DATABASE=CryptoMetrics + +OUI:001E35* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001E36* + ID_OUI_FROM_DATABASE=IPTE + +OUI:001E37* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:001E38* + ID_OUI_FROM_DATABASE=Bluecard Software Technology Co., Ltd. + +OUI:001E39* + ID_OUI_FROM_DATABASE=Comsys Communication Ltd. + +OUI:001E3A* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001E3B* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001E3C* + ID_OUI_FROM_DATABASE=Lyngbox Media AB + +OUI:001E3D* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:001E3E* + ID_OUI_FROM_DATABASE=KMW Inc. + +OUI:001E3F* + ID_OUI_FROM_DATABASE=TrellisWare Technologies, Inc. + +OUI:001E40* + ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co.,Ltd. + +OUI:001E41* + ID_OUI_FROM_DATABASE=Microwave Communication & Component, Inc. + +OUI:001E42* + ID_OUI_FROM_DATABASE=Teltonika + +OUI:001E43* + ID_OUI_FROM_DATABASE=AISIN AW CO.,LTD. + +OUI:001E44* + ID_OUI_FROM_DATABASE=SANTEC + +OUI:001E45* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:001E46* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001E47* + ID_OUI_FROM_DATABASE=PT. Hariff Daya Tunggal Engineering + +OUI:001E48* + ID_OUI_FROM_DATABASE=Wi-Links + +OUI:001E49* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E4A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E4B* + ID_OUI_FROM_DATABASE=City Theatrical + +OUI:001E4C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co., Ltd. + +OUI:001E4D* + ID_OUI_FROM_DATABASE=Welkin Sciences, LLC + +OUI:001E4E* + ID_OUI_FROM_DATABASE=DAKO EDV-Ingenieur- und Systemhaus GmbH + +OUI:001E4F* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:001E50* + ID_OUI_FROM_DATABASE=BATTISTONI RESEARCH + +OUI:001E51* + ID_OUI_FROM_DATABASE=Converter Industry Srl + +OUI:001E52* + ID_OUI_FROM_DATABASE=Apple + +OUI:001E53* + ID_OUI_FROM_DATABASE=Further Tech Co., LTD + +OUI:001E54* + ID_OUI_FROM_DATABASE=TOYO ELECTRIC Corporation + +OUI:001E55* + ID_OUI_FROM_DATABASE=COWON SYSTEMS,Inc. + +OUI:001E56* + ID_OUI_FROM_DATABASE=Bally Wulff Entertainment GmbH + +OUI:001E57* + ID_OUI_FROM_DATABASE=ALCOMA, spol. s r.o. + +OUI:001E58* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:001E59* + ID_OUI_FROM_DATABASE=Silicon Turnkey Express, LLC + +OUI:001E5A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001E5B* + ID_OUI_FROM_DATABASE=Unitron Company, Inc. + +OUI:001E5C* + ID_OUI_FROM_DATABASE=RB GeneralEkonomik + +OUI:001E5D* + ID_OUI_FROM_DATABASE=Holosys d.o.o. + +OUI:001E5E* + ID_OUI_FROM_DATABASE=COmputime Ltd. + +OUI:001E5F* + ID_OUI_FROM_DATABASE=KwikByte, LLC + +OUI:001E60* + ID_OUI_FROM_DATABASE=Digital Lighting Systems, Inc + +OUI:001E61* + ID_OUI_FROM_DATABASE=ITEC GmbH + +OUI:001E62* + ID_OUI_FROM_DATABASE=Siemon + +OUI:001E63* + ID_OUI_FROM_DATABASE=Vibro-Meter SA + +OUI:001E64* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001E65* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001E66* + ID_OUI_FROM_DATABASE=RESOL Elektronische Regelungen GmbH + +OUI:001E67* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001E68* + ID_OUI_FROM_DATABASE=Quanta Computer + +OUI:001E69* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:001E6A* + ID_OUI_FROM_DATABASE=Beijing Bluexon Technology Co.,Ltd + +OUI:001E6B* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:001E6C* + ID_OUI_FROM_DATABASE=Carbon Mountain LLC + +OUI:001E6D* + ID_OUI_FROM_DATABASE=IT R&D Center + +OUI:001E6E* + ID_OUI_FROM_DATABASE=Shenzhen First Mile Communications Ltd + +OUI:001E6F* + ID_OUI_FROM_DATABASE=Magna-Power Electronics, Inc. + +OUI:001E70* + ID_OUI_FROM_DATABASE=Cobham Defence Communications Ltd + +OUI:001E71* + ID_OUI_FROM_DATABASE=MIrcom Group of Companies + +OUI:001E72* + ID_OUI_FROM_DATABASE=PCS + +OUI:001E73* + ID_OUI_FROM_DATABASE=ZTE CORPORATION + +OUI:001E74* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:001E75* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:001E76* + ID_OUI_FROM_DATABASE=Thermo Fisher Scientific + +OUI:001E77* + ID_OUI_FROM_DATABASE=Air2App + +OUI:001E78* + ID_OUI_FROM_DATABASE=Owitek Technology Ltd., + +OUI:001E79* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E7A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001E7B* + ID_OUI_FROM_DATABASE=R.I.CO. S.r.l. + +OUI:001E7C* + ID_OUI_FROM_DATABASE=Taiwick Limited + +OUI:001E7D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001E7E* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001E7F* + ID_OUI_FROM_DATABASE=CBM of America + +OUI:001E80* + ID_OUI_FROM_DATABASE=Last Mile Ltd. + +OUI:001E81* + ID_OUI_FROM_DATABASE=CNB Technology Inc. + +OUI:001E82* + ID_OUI_FROM_DATABASE=SanDisk Corporation + +OUI:001E83* + ID_OUI_FROM_DATABASE=LAN/MAN Standards Association (LMSC) + +OUI:001E84* + ID_OUI_FROM_DATABASE=Pika Technologies Inc. + +OUI:001E85* + ID_OUI_FROM_DATABASE=Lagotek Corporation + +OUI:001E86* + ID_OUI_FROM_DATABASE=MEL Co.,Ltd. + +OUI:001E87* + ID_OUI_FROM_DATABASE=Realease Limited + +OUI:001E88* + ID_OUI_FROM_DATABASE=ANDOR SYSTEM SUPPORT CO., LTD. + +OUI:001E89* + ID_OUI_FROM_DATABASE=CRFS Limited + +OUI:001E8A* + ID_OUI_FROM_DATABASE=eCopy, Inc + +OUI:001E8B* + ID_OUI_FROM_DATABASE=Infra Access Korea Co., Ltd. + +OUI:001E8C* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001E8D* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001E8E* + ID_OUI_FROM_DATABASE=Hunkeler AG + +OUI:001E8F* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:001E90* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co + +OUI:001E91* + ID_OUI_FROM_DATABASE=KIMIN Electronic Co., Ltd. + +OUI:001E92* + ID_OUI_FROM_DATABASE=JEULIN S.A. + +OUI:001E93* + ID_OUI_FROM_DATABASE=CiriTech Systems Inc + +OUI:001E94* + ID_OUI_FROM_DATABASE=SUPERCOM TECHNOLOGY CORPORATION + +OUI:001E95* + ID_OUI_FROM_DATABASE=SIGMALINK + +OUI:001E96* + ID_OUI_FROM_DATABASE=Sepura Plc + +OUI:001E97* + ID_OUI_FROM_DATABASE=Medium Link System Technology CO., LTD, + +OUI:001E98* + ID_OUI_FROM_DATABASE=GreenLine Communications + +OUI:001E99* + ID_OUI_FROM_DATABASE=Vantanol Industrial Corporation + +OUI:001E9A* + ID_OUI_FROM_DATABASE=HAMILTON Bonaduz AG + +OUI:001E9B* + ID_OUI_FROM_DATABASE=San-Eisha, Ltd. + +OUI:001E9C* + ID_OUI_FROM_DATABASE=Fidustron INC + +OUI:001E9D* + ID_OUI_FROM_DATABASE=Recall Technologies, Inc. + +OUI:001E9E* + ID_OUI_FROM_DATABASE=ddm hopt + schuler Gmbh + Co. KG + +OUI:001E9F* + ID_OUI_FROM_DATABASE=Visioneering Systems, Inc. + +OUI:001EA0* + ID_OUI_FROM_DATABASE=XLN-t + +OUI:001EA1* + ID_OUI_FROM_DATABASE=Brunata a/s + +OUI:001EA2* + ID_OUI_FROM_DATABASE=Symx Systems, Inc. + +OUI:001EA3* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001EA4* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001EA5* + ID_OUI_FROM_DATABASE=ROBOTOUS, Inc. + +OUI:001EA6* + ID_OUI_FROM_DATABASE=Best IT World (India) Pvt. Ltd. + +OUI:001EA7* + ID_OUI_FROM_DATABASE=ActionTec Electronics, Inc + +OUI:001EA8* + ID_OUI_FROM_DATABASE=Datang Mobile Communications Equipment CO.,LTD + +OUI:001EA9* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001EAA* + ID_OUI_FROM_DATABASE=E-Senza Technologies GmbH + +OUI:001EAB* + ID_OUI_FROM_DATABASE=TeleWell Oy + +OUI:001EAC* + ID_OUI_FROM_DATABASE=Armadeus Systems + +OUI:001EAD* + ID_OUI_FROM_DATABASE=Wingtech Group Limited + +OUI:001EAE* + ID_OUI_FROM_DATABASE=Continental Automotive Systems + +OUI:001EAF* + ID_OUI_FROM_DATABASE=Ophir Optronics Ltd + +OUI:001EB0* + ID_OUI_FROM_DATABASE=ImesD Electronica S.L. + +OUI:001EB1* + ID_OUI_FROM_DATABASE=Cryptsoft Pty Ltd + +OUI:001EB2* + ID_OUI_FROM_DATABASE=LG innotek + +OUI:001EB3* + ID_OUI_FROM_DATABASE=Primex Wireless + +OUI:001EB4* + ID_OUI_FROM_DATABASE=UNIFAT TECHNOLOGY LTD. + +OUI:001EB5* + ID_OUI_FROM_DATABASE=Ever Sparkle Technologies Ltd + +OUI:001EB6* + ID_OUI_FROM_DATABASE=TAG Heuer SA + +OUI:001EB7* + ID_OUI_FROM_DATABASE=TBTech, Co., Ltd. + +OUI:001EB8* + ID_OUI_FROM_DATABASE=Fortis, Inc. + +OUI:001EB9* + ID_OUI_FROM_DATABASE=Sing Fai Technology Limited + +OUI:001EBA* + ID_OUI_FROM_DATABASE=High Density Devices AS + +OUI:001EBB* + ID_OUI_FROM_DATABASE=BLUELIGHT TECHNOLOGY INC. + +OUI:001EBC* + ID_OUI_FROM_DATABASE=WINTECH AUTOMATION CO.,LTD. + +OUI:001EBD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001EBE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001EBF* + ID_OUI_FROM_DATABASE=Haas Automation Inc. + +OUI:001EC0* + ID_OUI_FROM_DATABASE=Microchip Technology Inc. + +OUI:001EC1* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD + +OUI:001EC2* + ID_OUI_FROM_DATABASE=Apple + +OUI:001EC3* + ID_OUI_FROM_DATABASE=Kozio, Inc. + +OUI:001EC4* + ID_OUI_FROM_DATABASE=Celio Corp + +OUI:001EC5* + ID_OUI_FROM_DATABASE=Middle Atlantic Products Inc + +OUI:001EC6* + ID_OUI_FROM_DATABASE=Obvius Holdings LLC + +OUI:001EC7* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EC8* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EC9* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ECA* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ECB* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ECC* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ECD* + ID_OUI_FROM_DATABASE=KYLAND Technology Co. LTD + +OUI:001ECE* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ECF* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED0* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED1* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED2* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED3* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED4* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED5* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED6* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED7* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED8* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001ED9* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDA* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDB* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDC* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDD* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDE* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EDF* + ID_OUI_FROM_DATABASE=2Wire, Inc. + +OUI:001EE0* + ID_OUI_FROM_DATABASE=Urmet Domus SpA + +OUI:001EE1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001EE2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001EE3* + ID_OUI_FROM_DATABASE=T&W Electronics (ShenZhen) Co.,Ltd + +OUI:001EE4* + ID_OUI_FROM_DATABASE=ACS Solutions France + +OUI:001EE5* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:001EE6* + ID_OUI_FROM_DATABASE=Shenzhen Advanced Video Info-Tech Co., Ltd. + +OUI:001EE7* + ID_OUI_FROM_DATABASE=Epic Systems Inc + +OUI:001EE8* + ID_OUI_FROM_DATABASE=Mytek + +OUI:001EE9* + ID_OUI_FROM_DATABASE=Stoneridge Electronics AB + +OUI:001EEA* + ID_OUI_FROM_DATABASE=Sensor Switch, Inc. + +OUI:001EEB* + ID_OUI_FROM_DATABASE=Talk-A-Phone Co. + +OUI:001EEC* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:001EED* + ID_OUI_FROM_DATABASE=Adventiq Ltd. + +OUI:001EEE* + ID_OUI_FROM_DATABASE=ETL Systems Ltd + +OUI:001EEF* + ID_OUI_FROM_DATABASE=Cantronic International Limited + +OUI:001EF0* + ID_OUI_FROM_DATABASE=Gigafin Networks + +OUI:001EF1* + ID_OUI_FROM_DATABASE=Servimat + +OUI:001EF2* + ID_OUI_FROM_DATABASE=Micro Motion Inc + +OUI:001EF3* + ID_OUI_FROM_DATABASE=From2 + +OUI:001EF4* + ID_OUI_FROM_DATABASE=L-3 Communications Display Systems + +OUI:001EF5* + ID_OUI_FROM_DATABASE=Hitek Automated Inc. + +OUI:001EF6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001EF7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001EF8* + ID_OUI_FROM_DATABASE=Emfinity Inc. + +OUI:001EF9* + ID_OUI_FROM_DATABASE=Pascom Kommunikations systeme GmbH. + +OUI:001EFA* + ID_OUI_FROM_DATABASE=PROTEI Ltd. + +OUI:001EFB* + ID_OUI_FROM_DATABASE=Trio Motion Technology Ltd + +OUI:001EFC* + ID_OUI_FROM_DATABASE=JSC "MASSA-K" + +OUI:001EFD* + ID_OUI_FROM_DATABASE=Microbit 2.0 AB + +OUI:001EFE* + ID_OUI_FROM_DATABASE=LEVEL s.r.o. + +OUI:001EFF* + ID_OUI_FROM_DATABASE=Mueller-Elektronik GmbH & Co. KG + +OUI:001F00* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001F01* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001F02* + ID_OUI_FROM_DATABASE=Pixelmetrix Corporation Pte Ltd + +OUI:001F03* + ID_OUI_FROM_DATABASE=NUM AG + +OUI:001F04* + ID_OUI_FROM_DATABASE=Granch Ltd. + +OUI:001F05* + ID_OUI_FROM_DATABASE=iTAS Technology Corp. + +OUI:001F06* + ID_OUI_FROM_DATABASE=Integrated Dispatch Solutions + +OUI:001F07* + ID_OUI_FROM_DATABASE=AZTEQ Mobile + +OUI:001F08* + ID_OUI_FROM_DATABASE=RISCO LTD + +OUI:001F09* + ID_OUI_FROM_DATABASE=JASTEC CO., LTD. + +OUI:001F0A* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001F0B* + ID_OUI_FROM_DATABASE=Federal State Unitary Enterprise Industrial Union"Electropribor" + +OUI:001F0C* + ID_OUI_FROM_DATABASE=Intelligent Digital Services GmbH + +OUI:001F0D* + ID_OUI_FROM_DATABASE=L3 Communications - Telemetry West + +OUI:001F0E* + ID_OUI_FROM_DATABASE=Japan Kyastem Co., Ltd + +OUI:001F0F* + ID_OUI_FROM_DATABASE=Select Engineered Systems + +OUI:001F10* + ID_OUI_FROM_DATABASE=TOLEDO DO BRASIL INDUSTRIA DE BALANCAS LTDA + +OUI:001F11* + ID_OUI_FROM_DATABASE=OPENMOKO, INC. + +OUI:001F12* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:001F13* + ID_OUI_FROM_DATABASE=S.& A.S. Ltd. + +OUI:001F14* + ID_OUI_FROM_DATABASE=NexG + +OUI:001F15* + ID_OUI_FROM_DATABASE=Bioscrypt Inc + +OUI:001F16* + ID_OUI_FROM_DATABASE=Wistron Corporation + +OUI:001F17* + ID_OUI_FROM_DATABASE=IDX Company, Ltd. + +OUI:001F18* + ID_OUI_FROM_DATABASE=Hakusan.Mfg.Co,.Ltd + +OUI:001F19* + ID_OUI_FROM_DATABASE=BEN-RI ELECTRONICA S.A. + +OUI:001F1A* + ID_OUI_FROM_DATABASE=Prominvest + +OUI:001F1B* + ID_OUI_FROM_DATABASE=RoyalTek Company Ltd. + +OUI:001F1C* + ID_OUI_FROM_DATABASE=KOBISHI ELECTRIC Co.,Ltd. + +OUI:001F1D* + ID_OUI_FROM_DATABASE=Atlas Material Testing Technology LLC + +OUI:001F1E* + ID_OUI_FROM_DATABASE=Astec Technology Co., Ltd + +OUI:001F1F* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:001F20* + ID_OUI_FROM_DATABASE=Logitech Europe SA + +OUI:001F21* + ID_OUI_FROM_DATABASE=Inner Mongolia Yin An Science & Technology Development Co.,L + +OUI:001F22* + ID_OUI_FROM_DATABASE=Source Photonics, Inc. + +OUI:001F23* + ID_OUI_FROM_DATABASE=Interacoustics + +OUI:001F24* + ID_OUI_FROM_DATABASE=DIGITVIEW TECHNOLOGY CO., LTD. + +OUI:001F25* + ID_OUI_FROM_DATABASE=MBS GmbH + +OUI:001F26* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F27* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F28* + ID_OUI_FROM_DATABASE=HPN Supply Chain + +OUI:001F29* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:001F2A* + ID_OUI_FROM_DATABASE=ACCM + +OUI:001F2B* + ID_OUI_FROM_DATABASE=Orange Logic + +OUI:001F2C* + ID_OUI_FROM_DATABASE=Starbridge Networks + +OUI:001F2D* + ID_OUI_FROM_DATABASE=Electro-Optical Imaging, Inc. + +OUI:001F2E* + ID_OUI_FROM_DATABASE=Triangle Research Int'l Pte Ltd + +OUI:001F2F* + ID_OUI_FROM_DATABASE=Berker GmbH & Co. KG + +OUI:001F30* + ID_OUI_FROM_DATABASE=Travelping + +OUI:001F31* + ID_OUI_FROM_DATABASE=Radiocomp + +OUI:001F32* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001F33* + ID_OUI_FROM_DATABASE=Netgear Inc. + +OUI:001F34* + ID_OUI_FROM_DATABASE=Lung Hwa Electronics Co., Ltd. + +OUI:001F35* + ID_OUI_FROM_DATABASE=AIR802 LLC + +OUI:001F36* + ID_OUI_FROM_DATABASE=Bellwin Information Co. Ltd., + +OUI:001F37* + ID_OUI_FROM_DATABASE=Genesis I&C + +OUI:001F38* + ID_OUI_FROM_DATABASE=POSITRON + +OUI:001F39* + ID_OUI_FROM_DATABASE=Construcciones y Auxiliar de Ferrocarriles, S.A. + +OUI:001F3A* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co., Ltd. + +OUI:001F3B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001F3C* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:001F3D* + ID_OUI_FROM_DATABASE=Qbit GmbH + +OUI:001F3E* + ID_OUI_FROM_DATABASE=RP-Technik e.K. + +OUI:001F3F* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:001F40* + ID_OUI_FROM_DATABASE=Speakercraft Inc. + +OUI:001F41* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:001F42* + ID_OUI_FROM_DATABASE=Etherstack plc + +OUI:001F43* + ID_OUI_FROM_DATABASE=ENTES ELEKTRONIK + +OUI:001F44* + ID_OUI_FROM_DATABASE=GE Transportation Systems + +OUI:001F45* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:001F46* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001F47* + ID_OUI_FROM_DATABASE=MCS Logic Inc. + +OUI:001F48* + ID_OUI_FROM_DATABASE=Mojix Inc. + +OUI:001F49* + ID_OUI_FROM_DATABASE=Eurosat Distribution Ltd + +OUI:001F4A* + ID_OUI_FROM_DATABASE=Albentia Systems S.A. + +OUI:001F4B* + ID_OUI_FROM_DATABASE=Lineage Power + +OUI:001F4C* + ID_OUI_FROM_DATABASE=Roseman Engineering Ltd + +OUI:001F4D* + ID_OUI_FROM_DATABASE=Segnetics LLC + +OUI:001F4E* + ID_OUI_FROM_DATABASE=ConMed Linvatec + +OUI:001F4F* + ID_OUI_FROM_DATABASE=Thinkware Co. Ltd. + +OUI:001F50* + ID_OUI_FROM_DATABASE=Swissdis AG + +OUI:001F51* + ID_OUI_FROM_DATABASE=HD Communications Corp + +OUI:001F52* + ID_OUI_FROM_DATABASE=UVT Unternehmensberatung fur Verkehr und Technik GmbH + +OUI:001F53* + ID_OUI_FROM_DATABASE=GEMAC Gesellschaft für Mikroelektronikanwendung Chemnitz mbH + +OUI:001F54* + ID_OUI_FROM_DATABASE=Lorex Technology Inc. + +OUI:001F55* + ID_OUI_FROM_DATABASE=Honeywell Security (China) Co., Ltd. + +OUI:001F56* + ID_OUI_FROM_DATABASE=DIGITAL FORECAST + +OUI:001F57* + ID_OUI_FROM_DATABASE=Phonik Innovation Co.,LTD + +OUI:001F58* + ID_OUI_FROM_DATABASE=EMH Energiemesstechnik GmbH + +OUI:001F59* + ID_OUI_FROM_DATABASE=Kronback Tracers + +OUI:001F5A* + ID_OUI_FROM_DATABASE=Beckwith Electric Co. + +OUI:001F5B* + ID_OUI_FROM_DATABASE=Apple + +OUI:001F5C* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001F5D* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001F5E* + ID_OUI_FROM_DATABASE=Dyna Technology Co.,Ltd. + +OUI:001F5F* + ID_OUI_FROM_DATABASE=Blatand GmbH + +OUI:001F60* + ID_OUI_FROM_DATABASE=COMPASS SYSTEMS CORP. + +OUI:001F61* + ID_OUI_FROM_DATABASE=Talent Communication Networks Inc. + +OUI:001F62* + ID_OUI_FROM_DATABASE=JSC "Stilsoft" + +OUI:001F63* + ID_OUI_FROM_DATABASE=JSC Goodwin-Europa + +OUI:001F64* + ID_OUI_FROM_DATABASE=Beijing Autelan Technology Inc. + +OUI:001F65* + ID_OUI_FROM_DATABASE=KOREA ELECTRIC TERMINAL CO., LTD. + +OUI:001F66* + ID_OUI_FROM_DATABASE=PLANAR LLC + +OUI:001F67* + ID_OUI_FROM_DATABASE=Hitachi,Ltd. + +OUI:001F68* + ID_OUI_FROM_DATABASE=Martinsson Elektronik AB + +OUI:001F69* + ID_OUI_FROM_DATABASE=Pingood Technology Co., Ltd. + +OUI:001F6A* + ID_OUI_FROM_DATABASE=PacketFlux Technologies, Inc. + +OUI:001F6B* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:001F6C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F6D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F6E* + ID_OUI_FROM_DATABASE=Vtech Engineering Corporation + +OUI:001F6F* + ID_OUI_FROM_DATABASE=Fujian Sunnada Communication Co.,Ltd. + +OUI:001F70* + ID_OUI_FROM_DATABASE=Botik Technologies LTD + +OUI:001F71* + ID_OUI_FROM_DATABASE=xG Technology, Inc. + +OUI:001F72* + ID_OUI_FROM_DATABASE=QingDao Hiphone Technology Co,.Ltd + +OUI:001F73* + ID_OUI_FROM_DATABASE=Teraview Technology Co., Ltd. + +OUI:001F74* + ID_OUI_FROM_DATABASE=Eigen Development + +OUI:001F75* + ID_OUI_FROM_DATABASE=GiBahn Media + +OUI:001F76* + ID_OUI_FROM_DATABASE=AirLogic Systems Inc. + +OUI:001F77* + ID_OUI_FROM_DATABASE=HEOL DESIGN + +OUI:001F78* + ID_OUI_FROM_DATABASE=Blue Fox Porini Textile + +OUI:001F79* + ID_OUI_FROM_DATABASE=Lodam Electronics A/S + +OUI:001F7A* + ID_OUI_FROM_DATABASE=WiWide Inc. + +OUI:001F7B* + ID_OUI_FROM_DATABASE=TechNexion Ltd. + +OUI:001F7C* + ID_OUI_FROM_DATABASE=Witelcom AS + +OUI:001F7D* + ID_OUI_FROM_DATABASE=embedded wireless GmbH + +OUI:001F7E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001F7F* + ID_OUI_FROM_DATABASE=Phabrix Limited + +OUI:001F80* + ID_OUI_FROM_DATABASE=Lucas Holding bv + +OUI:001F81* + ID_OUI_FROM_DATABASE=Accel Semiconductor Corp + +OUI:001F82* + ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Co., Ltd + +OUI:001F83* + ID_OUI_FROM_DATABASE=Teleplan Technology Services Sdn Bhd + +OUI:001F84* + ID_OUI_FROM_DATABASE=Gigle Semiconductor + +OUI:001F85* + ID_OUI_FROM_DATABASE=Apriva ISS, LLC + +OUI:001F86* + ID_OUI_FROM_DATABASE=digEcor + +OUI:001F87* + ID_OUI_FROM_DATABASE=Skydigital Inc. + +OUI:001F88* + ID_OUI_FROM_DATABASE=FMS Force Measuring Systems AG + +OUI:001F89* + ID_OUI_FROM_DATABASE=Signalion GmbH + +OUI:001F8A* + ID_OUI_FROM_DATABASE=Ellion Digital Inc. + +OUI:001F8B* + ID_OUI_FROM_DATABASE=Cache IQ + +OUI:001F8C* + ID_OUI_FROM_DATABASE=CCS Inc. + +OUI:001F8D* + ID_OUI_FROM_DATABASE=Ingenieurbuero Stark GmbH und Ko. KG + +OUI:001F8E* + ID_OUI_FROM_DATABASE=Metris USA Inc. + +OUI:001F8F* + ID_OUI_FROM_DATABASE=Shanghai Bellmann Digital Source Co.,Ltd. + +OUI:001F90* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:001F91* + ID_OUI_FROM_DATABASE=DBS Lodging Technologies, LLC + +OUI:001F92* + ID_OUI_FROM_DATABASE=VideoIQ, Inc. + +OUI:001F93* + ID_OUI_FROM_DATABASE=Xiotech Corporation + +OUI:001F94* + ID_OUI_FROM_DATABASE=Lascar Electronics Ltd + +OUI:001F95* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:001F96* + ID_OUI_FROM_DATABASE=APROTECH CO.LTD + +OUI:001F97* + ID_OUI_FROM_DATABASE=BERTANA SRL + +OUI:001F98* + ID_OUI_FROM_DATABASE=DAIICHI-DENTSU LTD. + +OUI:001F99* + ID_OUI_FROM_DATABASE=SERONICS co.ltd + +OUI:001F9A* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:001F9B* + ID_OUI_FROM_DATABASE=POSBRO + +OUI:001F9C* + ID_OUI_FROM_DATABASE=LEDCO + +OUI:001F9D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F9E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001F9F* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:001FA0* + ID_OUI_FROM_DATABASE=A10 Networks + +OUI:001FA1* + ID_OUI_FROM_DATABASE=Gtran Inc + +OUI:001FA2* + ID_OUI_FROM_DATABASE=Datron World Communications, Inc. + +OUI:001FA3* + ID_OUI_FROM_DATABASE=T&W Electronics(Shenzhen)Co.,Ltd. + +OUI:001FA4* + ID_OUI_FROM_DATABASE=ShenZhen Gongjin Electronics Co.,Ltd + +OUI:001FA5* + ID_OUI_FROM_DATABASE=Blue-White Industries + +OUI:001FA6* + ID_OUI_FROM_DATABASE=Stilo srl + +OUI:001FA7* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:001FA8* + ID_OUI_FROM_DATABASE=Smart Energy Instruments Inc. + +OUI:001FA9* + ID_OUI_FROM_DATABASE=Atlanta DTH, Inc. + +OUI:001FAA* + ID_OUI_FROM_DATABASE=Taseon, Inc. + +OUI:001FAB* + ID_OUI_FROM_DATABASE=I.S HIGH TECH.INC + +OUI:001FAC* + ID_OUI_FROM_DATABASE=Goodmill Systems Ltd + +OUI:001FAD* + ID_OUI_FROM_DATABASE=Brown Innovations, Inc + +OUI:001FAE* + ID_OUI_FROM_DATABASE=Blick South Africa (Pty) Ltd + +OUI:001FAF* + ID_OUI_FROM_DATABASE=NextIO, Inc. + +OUI:001FB0* + ID_OUI_FROM_DATABASE=TimeIPS, Inc. + +OUI:001FB1* + ID_OUI_FROM_DATABASE=Cybertech Inc. + +OUI:001FB2* + ID_OUI_FROM_DATABASE=Sontheim Industrie Elektronik GmbH + +OUI:001FB3* + ID_OUI_FROM_DATABASE=2Wire + +OUI:001FB4* + ID_OUI_FROM_DATABASE=SmartShare Systems + +OUI:001FB5* + ID_OUI_FROM_DATABASE=I/O Interconnect Inc. + +OUI:001FB6* + ID_OUI_FROM_DATABASE=Chi Lin Technology Co., Ltd. + +OUI:001FB7* + ID_OUI_FROM_DATABASE=WiMate Technologies Corp. + +OUI:001FB8* + ID_OUI_FROM_DATABASE=Universal Remote Control, Inc. + +OUI:001FB9* + ID_OUI_FROM_DATABASE=Paltronics + +OUI:001FBA* + ID_OUI_FROM_DATABASE=BoYoung Tech. & Marketing, Inc. + +OUI:001FBB* + ID_OUI_FROM_DATABASE=Xenatech Co.,LTD + +OUI:001FBC* + ID_OUI_FROM_DATABASE=EVGA Corporation + +OUI:001FBD* + ID_OUI_FROM_DATABASE=Kyocera Wireless Corp. + +OUI:001FBE* + ID_OUI_FROM_DATABASE=Shenzhen Mopnet Industrial Co.,Ltd + +OUI:001FBF* + ID_OUI_FROM_DATABASE=Fulhua Microelectronics Corp. Taiwan Branch + +OUI:001FC0* + ID_OUI_FROM_DATABASE=Control Express Finland Oy + +OUI:001FC1* + ID_OUI_FROM_DATABASE=Hanlong Technology Co.,LTD + +OUI:001FC2* + ID_OUI_FROM_DATABASE=Jow Tong Technology Co Ltd + +OUI:001FC3* + ID_OUI_FROM_DATABASE=SmartSynch, Inc + +OUI:001FC4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001FC5* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001FC6* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:001FC7* + ID_OUI_FROM_DATABASE=Casio Hitachi Mobile Comunications Co., Ltd. + +OUI:001FC8* + ID_OUI_FROM_DATABASE=Up-Today Industrial Co., Ltd. + +OUI:001FC9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001FCA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:001FCB* + ID_OUI_FROM_DATABASE=NIW Solutions + +OUI:001FCC* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001FCD* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:001FCE* + ID_OUI_FROM_DATABASE=QTECH LLC + +OUI:001FCF* + ID_OUI_FROM_DATABASE=MSI Technology GmbH + +OUI:001FD0* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:001FD1* + ID_OUI_FROM_DATABASE=OPTEX CO.,LTD. + +OUI:001FD2* + ID_OUI_FROM_DATABASE=COMMTECH TECHNOLOGY MACAO COMMERCIAL OFFSHORE LTD. + +OUI:001FD3* + ID_OUI_FROM_DATABASE=RIVA Networks Inc. + +OUI:001FD4* + ID_OUI_FROM_DATABASE=4IPNET, INC. + +OUI:001FD5* + ID_OUI_FROM_DATABASE=MICRORISC s.r.o. + +OUI:001FD6* + ID_OUI_FROM_DATABASE=Shenzhen Allywll + +OUI:001FD7* + ID_OUI_FROM_DATABASE=TELERAD SA + +OUI:001FD8* + ID_OUI_FROM_DATABASE=A-TRUST COMPUTER CORPORATION + +OUI:001FD9* + ID_OUI_FROM_DATABASE=RSD Communications Ltd + +OUI:001FDA* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:001FDB* + ID_OUI_FROM_DATABASE=Network Supply Corp., + +OUI:001FDC* + ID_OUI_FROM_DATABASE=Mobile Safe Track Ltd + +OUI:001FDD* + ID_OUI_FROM_DATABASE=GDI LLC + +OUI:001FDE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001FDF* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001FE0* + ID_OUI_FROM_DATABASE=EdgeVelocity Corp + +OUI:001FE1* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:001FE2* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:001FE3* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:001FE4* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:001FE5* + ID_OUI_FROM_DATABASE=In-Circuit GmbH + +OUI:001FE6* + ID_OUI_FROM_DATABASE=Alphion Corporation + +OUI:001FE7* + ID_OUI_FROM_DATABASE=Simet + +OUI:001FE8* + ID_OUI_FROM_DATABASE=KURUSUGAWA Electronics Industry Inc,. + +OUI:001FE9* + ID_OUI_FROM_DATABASE=Printrex, Inc. + +OUI:001FEA* + ID_OUI_FROM_DATABASE=Applied Media Technologies Corporation + +OUI:001FEB* + ID_OUI_FROM_DATABASE=Trio Datacom Pty Ltd + +OUI:001FEC* + ID_OUI_FROM_DATABASE=Synapse Électronique + +OUI:001FED* + ID_OUI_FROM_DATABASE=Tecan Systems Inc. + +OUI:001FEE* + ID_OUI_FROM_DATABASE=ubisys technologies GmbH + +OUI:001FEF* + ID_OUI_FROM_DATABASE=SHINSEI INDUSTRIES CO.,LTD + +OUI:001FF0* + ID_OUI_FROM_DATABASE=Audio Partnership + +OUI:001FF1* + ID_OUI_FROM_DATABASE=Paradox Hellas S.A. + +OUI:001FF2* + ID_OUI_FROM_DATABASE=VIA Technologies, Inc. + +OUI:001FF3* + ID_OUI_FROM_DATABASE=Apple + +OUI:001FF4* + ID_OUI_FROM_DATABASE=Power Monitors, Inc. + +OUI:001FF5* + ID_OUI_FROM_DATABASE=Kongsberg Defence & Aerospace + +OUI:001FF6* + ID_OUI_FROM_DATABASE=PS Audio International + +OUI:001FF7* + ID_OUI_FROM_DATABASE=Nakajima All Precision Co., Ltd. + +OUI:001FF8* + ID_OUI_FROM_DATABASE=Siemens AG, Sector Industry, Drive Technologies, Motion Control Systems + +OUI:001FF9* + ID_OUI_FROM_DATABASE=Advanced Knowledge Associates + +OUI:001FFA* + ID_OUI_FROM_DATABASE=Coretree, Co, Ltd + +OUI:001FFB* + ID_OUI_FROM_DATABASE=Green Packet Bhd + +OUI:001FFC* + ID_OUI_FROM_DATABASE=Riccius+Sohn GmbH + +OUI:001FFD* + ID_OUI_FROM_DATABASE=Indigo Mobile Technologies Corp. + +OUI:001FFE* + ID_OUI_FROM_DATABASE=HPN Supply Chain + +OUI:001FFF* + ID_OUI_FROM_DATABASE=Respironics, Inc. + +OUI:002000* + ID_OUI_FROM_DATABASE=LEXMARK INTERNATIONAL, INC. + +OUI:002001* + ID_OUI_FROM_DATABASE=DSP SOLUTIONS, INC. + +OUI:002002* + ID_OUI_FROM_DATABASE=SERITECH ENTERPRISE CO., LTD. + +OUI:002003* + ID_OUI_FROM_DATABASE=PIXEL POWER LTD. + +OUI:002004* + ID_OUI_FROM_DATABASE=YAMATAKE-HONEYWELL CO., LTD. + +OUI:002005* + ID_OUI_FROM_DATABASE=SIMPLE TECHNOLOGY + +OUI:002006* + ID_OUI_FROM_DATABASE=GARRETT COMMUNICATIONS, INC. + +OUI:002007* + ID_OUI_FROM_DATABASE=SFA, INC. + +OUI:002008* + ID_OUI_FROM_DATABASE=CABLE & COMPUTER TECHNOLOGY + +OUI:002009* + ID_OUI_FROM_DATABASE=PACKARD BELL ELEC., INC. + +OUI:00200A* + ID_OUI_FROM_DATABASE=SOURCE-COMM CORP. + +OUI:00200B* + ID_OUI_FROM_DATABASE=OCTAGON SYSTEMS CORP. + +OUI:00200C* + ID_OUI_FROM_DATABASE=ADASTRA SYSTEMS CORP. + +OUI:00200D* + ID_OUI_FROM_DATABASE=CARL ZEISS + +OUI:00200E* + ID_OUI_FROM_DATABASE=SATELLITE TECHNOLOGY MGMT, INC + +OUI:00200F* + ID_OUI_FROM_DATABASE=TANBAC CO., LTD. + +OUI:002010* + ID_OUI_FROM_DATABASE=JEOL SYSTEM TECHNOLOGY CO. LTD + +OUI:002011* + ID_OUI_FROM_DATABASE=CANOPUS CO., LTD. + +OUI:002012* + ID_OUI_FROM_DATABASE=CAMTRONICS MEDICAL SYSTEMS + +OUI:002013* + ID_OUI_FROM_DATABASE=DIVERSIFIED TECHNOLOGY, INC. + +OUI:002014* + ID_OUI_FROM_DATABASE=GLOBAL VIEW CO., LTD. + +OUI:002015* + ID_OUI_FROM_DATABASE=ACTIS COMPUTER SA + +OUI:002016* + ID_OUI_FROM_DATABASE=SHOWA ELECTRIC WIRE & CABLE CO + +OUI:002017* + ID_OUI_FROM_DATABASE=ORBOTECH + +OUI:002018* + ID_OUI_FROM_DATABASE=CIS TECHNOLOGY INC. + +OUI:002019* + ID_OUI_FROM_DATABASE=OHLER GmbH + +OUI:00201A* + ID_OUI_FROM_DATABASE=MRV Communications, Inc. + +OUI:00201B* + ID_OUI_FROM_DATABASE=NORTHERN TELECOM/NETWORK + +OUI:00201C* + ID_OUI_FROM_DATABASE=EXCEL, INC. + +OUI:00201D* + ID_OUI_FROM_DATABASE=KATANA PRODUCTS + +OUI:00201E* + ID_OUI_FROM_DATABASE=NETQUEST CORPORATION + +OUI:00201F* + ID_OUI_FROM_DATABASE=BEST POWER TECHNOLOGY, INC. + +OUI:002020* + ID_OUI_FROM_DATABASE=MEGATRON COMPUTER INDUSTRIES PTY, LTD. + +OUI:002021* + ID_OUI_FROM_DATABASE=ALGORITHMS SOFTWARE PVT. LTD. + +OUI:002022* + ID_OUI_FROM_DATABASE=NMS Communications + +OUI:002023* + ID_OUI_FROM_DATABASE=T.C. TECHNOLOGIES PTY. LTD + +OUI:002024* + ID_OUI_FROM_DATABASE=PACIFIC COMMUNICATION SCIENCES + +OUI:002025* + ID_OUI_FROM_DATABASE=CONTROL TECHNOLOGY, INC. + +OUI:002026* + ID_OUI_FROM_DATABASE=AMKLY SYSTEMS, INC. + +OUI:002027* + ID_OUI_FROM_DATABASE=MING FORTUNE INDUSTRY CO., LTD + +OUI:002028* + ID_OUI_FROM_DATABASE=WEST EGG SYSTEMS, INC. + +OUI:002029* + ID_OUI_FROM_DATABASE=TELEPROCESSING PRODUCTS, INC. + +OUI:00202A* + ID_OUI_FROM_DATABASE=N.V. DZINE + +OUI:00202B* + ID_OUI_FROM_DATABASE=ADVANCED TELECOMMUNICATIONS MODULES, LTD. + +OUI:00202C* + ID_OUI_FROM_DATABASE=WELLTRONIX CO., LTD. + +OUI:00202D* + ID_OUI_FROM_DATABASE=TAIYO CORPORATION + +OUI:00202E* + ID_OUI_FROM_DATABASE=DAYSTAR DIGITAL + +OUI:00202F* + ID_OUI_FROM_DATABASE=ZETA COMMUNICATIONS, LTD. + +OUI:002030* + ID_OUI_FROM_DATABASE=ANALOG & DIGITAL SYSTEMS + +OUI:002031* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:002032* + ID_OUI_FROM_DATABASE=ALCATEL TAISEL + +OUI:002033* + ID_OUI_FROM_DATABASE=SYNAPSE TECHNOLOGIES, INC. + +OUI:002034* + ID_OUI_FROM_DATABASE=ROTEC INDUSTRIEAUTOMATION GMBH + +OUI:002035* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:002036* + ID_OUI_FROM_DATABASE=BMC SOFTWARE + +OUI:002037* + ID_OUI_FROM_DATABASE=SEAGATE TECHNOLOGY + +OUI:002038* + ID_OUI_FROM_DATABASE=VME MICROSYSTEMS INTERNATIONAL CORPORATION + +OUI:002039* + ID_OUI_FROM_DATABASE=SCINETS + +OUI:00203A* + ID_OUI_FROM_DATABASE=DIGITAL BI0METRICS INC. + +OUI:00203B* + ID_OUI_FROM_DATABASE=WISDM LTD. + +OUI:00203C* + ID_OUI_FROM_DATABASE=EUROTIME AB + +OUI:00203D* + ID_OUI_FROM_DATABASE=Honeywell ECC + +OUI:00203E* + ID_OUI_FROM_DATABASE=LogiCan Technologies, Inc. + +OUI:00203F* + ID_OUI_FROM_DATABASE=JUKI CORPORATION + +OUI:002040* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002041* + ID_OUI_FROM_DATABASE=DATA NET + +OUI:002042* + ID_OUI_FROM_DATABASE=DATAMETRICS CORP. + +OUI:002043* + ID_OUI_FROM_DATABASE=NEURON COMPANY LIMITED + +OUI:002044* + ID_OUI_FROM_DATABASE=GENITECH PTY LTD + +OUI:002045* + ID_OUI_FROM_DATABASE=ION Networks, Inc. + +OUI:002046* + ID_OUI_FROM_DATABASE=CIPRICO, INC. + +OUI:002047* + ID_OUI_FROM_DATABASE=STEINBRECHER CORP. + +OUI:002048* + ID_OUI_FROM_DATABASE=Marconi Communications + +OUI:002049* + ID_OUI_FROM_DATABASE=COMTRON, INC. + +OUI:00204A* + ID_OUI_FROM_DATABASE=PRONET GMBH + +OUI:00204B* + ID_OUI_FROM_DATABASE=AUTOCOMPUTER CO., LTD. + +OUI:00204C* + ID_OUI_FROM_DATABASE=MITRON COMPUTER PTE LTD. + +OUI:00204D* + ID_OUI_FROM_DATABASE=INOVIS GMBH + +OUI:00204E* + ID_OUI_FROM_DATABASE=NETWORK SECURITY SYSTEMS, INC. + +OUI:00204F* + ID_OUI_FROM_DATABASE=DEUTSCHE AEROSPACE AG + +OUI:002050* + ID_OUI_FROM_DATABASE=KOREA COMPUTER INC. + +OUI:002051* + ID_OUI_FROM_DATABASE=Verilink Corporation + +OUI:002052* + ID_OUI_FROM_DATABASE=RAGULA SYSTEMS + +OUI:002053* + ID_OUI_FROM_DATABASE=HUNTSVILLE MICROSYSTEMS, INC. + +OUI:002054* + ID_OUI_FROM_DATABASE=Sycamore Networks + +OUI:002055* + ID_OUI_FROM_DATABASE=ALTECH CO., LTD. + +OUI:002056* + ID_OUI_FROM_DATABASE=NEOPRODUCTS + +OUI:002057* + ID_OUI_FROM_DATABASE=TITZE DATENTECHNIK GmbH + +OUI:002058* + ID_OUI_FROM_DATABASE=ALLIED SIGNAL INC. + +OUI:002059* + ID_OUI_FROM_DATABASE=MIRO COMPUTER PRODUCTS AG + +OUI:00205A* + ID_OUI_FROM_DATABASE=COMPUTER IDENTICS + +OUI:00205B* + ID_OUI_FROM_DATABASE=Kentrox, LLC + +OUI:00205C* + ID_OUI_FROM_DATABASE=InterNet Systems of Florida, Inc. + +OUI:00205D* + ID_OUI_FROM_DATABASE=NANOMATIC OY + +OUI:00205E* + ID_OUI_FROM_DATABASE=CASTLE ROCK, INC. + +OUI:00205F* + ID_OUI_FROM_DATABASE=GAMMADATA COMPUTER GMBH + +OUI:002060* + ID_OUI_FROM_DATABASE=ALCATEL ITALIA S.p.A. + +OUI:002061* + ID_OUI_FROM_DATABASE=GarrettCom, Inc. + +OUI:002062* + ID_OUI_FROM_DATABASE=SCORPION LOGIC, LTD. + +OUI:002063* + ID_OUI_FROM_DATABASE=WIPRO INFOTECH LTD. + +OUI:002064* + ID_OUI_FROM_DATABASE=PROTEC MICROSYSTEMS, INC. + +OUI:002065* + ID_OUI_FROM_DATABASE=SUPERNET NETWORKING INC. + +OUI:002066* + ID_OUI_FROM_DATABASE=GENERAL MAGIC, INC. + +OUI:002068* + ID_OUI_FROM_DATABASE=ISDYNE + +OUI:002069* + ID_OUI_FROM_DATABASE=ISDN SYSTEMS CORPORATION + +OUI:00206A* + ID_OUI_FROM_DATABASE=OSAKA COMPUTER CORP. + +OUI:00206B* + ID_OUI_FROM_DATABASE=KONICA MINOLTA HOLDINGS, INC. + +OUI:00206C* + ID_OUI_FROM_DATABASE=EVERGREEN TECHNOLOGY CORP. + +OUI:00206D* + ID_OUI_FROM_DATABASE=DATA RACE, INC. + +OUI:00206E* + ID_OUI_FROM_DATABASE=XACT, INC. + +OUI:00206F* + ID_OUI_FROM_DATABASE=FLOWPOINT CORPORATION + +OUI:002070* + ID_OUI_FROM_DATABASE=HYNET, LTD. + +OUI:002071* + ID_OUI_FROM_DATABASE=IBR GMBH + +OUI:002072* + ID_OUI_FROM_DATABASE=WORKLINK INNOVATIONS + +OUI:002073* + ID_OUI_FROM_DATABASE=FUSION SYSTEMS CORPORATION + +OUI:002074* + ID_OUI_FROM_DATABASE=SUNGWOON SYSTEMS + +OUI:002075* + ID_OUI_FROM_DATABASE=MOTOROLA COMMUNICATION ISRAEL + +OUI:002076* + ID_OUI_FROM_DATABASE=REUDO CORPORATION + +OUI:002077* + ID_OUI_FROM_DATABASE=KARDIOS SYSTEMS CORP. + +OUI:002078* + ID_OUI_FROM_DATABASE=RUNTOP, INC. + +OUI:002079* + ID_OUI_FROM_DATABASE=MIKRON GMBH + +OUI:00207A* + ID_OUI_FROM_DATABASE=WiSE Communications, Inc. + +OUI:00207B* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:00207C* + ID_OUI_FROM_DATABASE=AUTEC GmbH + +OUI:00207D* + ID_OUI_FROM_DATABASE=ADVANCED COMPUTER APPLICATIONS + +OUI:00207E* + ID_OUI_FROM_DATABASE=FINECOM Co., Ltd. + +OUI:00207F* + ID_OUI_FROM_DATABASE=KYOEI SANGYO CO., LTD. + +OUI:002080* + ID_OUI_FROM_DATABASE=SYNERGY (UK) LTD. + +OUI:002081* + ID_OUI_FROM_DATABASE=TITAN ELECTRONICS + +OUI:002082* + ID_OUI_FROM_DATABASE=ONEAC CORPORATION + +OUI:002083* + ID_OUI_FROM_DATABASE=PRESTICOM INCORPORATED + +OUI:002084* + ID_OUI_FROM_DATABASE=OCE PRINTING SYSTEMS, GMBH + +OUI:002085* + ID_OUI_FROM_DATABASE=EXIDE ELECTRONICS + +OUI:002086* + ID_OUI_FROM_DATABASE=MICROTECH ELECTRONICS LIMITED + +OUI:002087* + ID_OUI_FROM_DATABASE=MEMOTEC, INC. + +OUI:002088* + ID_OUI_FROM_DATABASE=GLOBAL VILLAGE COMMUNICATION + +OUI:002089* + ID_OUI_FROM_DATABASE=T3PLUS NETWORKING, INC. + +OUI:00208A* + ID_OUI_FROM_DATABASE=SONIX COMMUNICATIONS, LTD. + +OUI:00208B* + ID_OUI_FROM_DATABASE=LAPIS TECHNOLOGIES, INC. + +OUI:00208C* + ID_OUI_FROM_DATABASE=GALAXY NETWORKS, INC. + +OUI:00208D* + ID_OUI_FROM_DATABASE=CMD TECHNOLOGY + +OUI:00208E* + ID_OUI_FROM_DATABASE=CHEVIN SOFTWARE ENG. LTD. + +OUI:00208F* + ID_OUI_FROM_DATABASE=ECI TELECOM LTD. + +OUI:002090* + ID_OUI_FROM_DATABASE=ADVANCED COMPRESSION TECHNOLOGY, INC. + +OUI:002091* + ID_OUI_FROM_DATABASE=J125, NATIONAL SECURITY AGENCY + +OUI:002092* + ID_OUI_FROM_DATABASE=CHESS ENGINEERING B.V. + +OUI:002093* + ID_OUI_FROM_DATABASE=LANDINGS TECHNOLOGY CORP. + +OUI:002094* + ID_OUI_FROM_DATABASE=CUBIX CORPORATION + +OUI:002095* + ID_OUI_FROM_DATABASE=RIVA ELECTRONICS + +OUI:002096* + ID_OUI_FROM_DATABASE=Invensys + +OUI:002097* + ID_OUI_FROM_DATABASE=APPLIED SIGNAL TECHNOLOGY + +OUI:002098* + ID_OUI_FROM_DATABASE=HECTRONIC AB + +OUI:002099* + ID_OUI_FROM_DATABASE=BON ELECTRIC CO., LTD. + +OUI:00209A* + ID_OUI_FROM_DATABASE=THE 3DO COMPANY + +OUI:00209B* + ID_OUI_FROM_DATABASE=ERSAT ELECTRONIC GMBH + +OUI:00209C* + ID_OUI_FROM_DATABASE=PRIMARY ACCESS CORP. + +OUI:00209D* + ID_OUI_FROM_DATABASE=LIPPERT AUTOMATIONSTECHNIK + +OUI:00209E* + ID_OUI_FROM_DATABASE=BROWN'S OPERATING SYSTEM SERVICES, LTD. + +OUI:00209F* + ID_OUI_FROM_DATABASE=MERCURY COMPUTER SYSTEMS, INC. + +OUI:0020A0* + ID_OUI_FROM_DATABASE=OA LABORATORY CO., LTD. + +OUI:0020A1* + ID_OUI_FROM_DATABASE=DOVATRON + +OUI:0020A2* + ID_OUI_FROM_DATABASE=GALCOM NETWORKING LTD. + +OUI:0020A3* + ID_OUI_FROM_DATABASE=Harmonic, Inc + +OUI:0020A4* + ID_OUI_FROM_DATABASE=MULTIPOINT NETWORKS + +OUI:0020A5* + ID_OUI_FROM_DATABASE=API ENGINEERING + +OUI:0020A6* + ID_OUI_FROM_DATABASE=Proxim Wireless + +OUI:0020A7* + ID_OUI_FROM_DATABASE=PAIRGAIN TECHNOLOGIES, INC. + +OUI:0020A8* + ID_OUI_FROM_DATABASE=SAST TECHNOLOGY CORP. + +OUI:0020A9* + ID_OUI_FROM_DATABASE=WHITE HORSE INDUSTRIAL + +OUI:0020AA* + ID_OUI_FROM_DATABASE=Ericsson Television Limited + +OUI:0020AB* + ID_OUI_FROM_DATABASE=MICRO INDUSTRIES CORP. + +OUI:0020AC* + ID_OUI_FROM_DATABASE=INTERFLEX DATENSYSTEME GMBH + +OUI:0020AD* + ID_OUI_FROM_DATABASE=LINQ SYSTEMS + +OUI:0020AE* + ID_OUI_FROM_DATABASE=ORNET DATA COMMUNICATION TECH. + +OUI:0020AF* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:0020B0* + ID_OUI_FROM_DATABASE=GATEWAY DEVICES, INC. + +OUI:0020B1* + ID_OUI_FROM_DATABASE=COMTECH RESEARCH INC. + +OUI:0020B2* + ID_OUI_FROM_DATABASE=GKD Gesellschaft Fur Kommunikation Und Datentechnik + +OUI:0020B3* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:0020B4* + ID_OUI_FROM_DATABASE=TERMA ELEKTRONIK AS + +OUI:0020B5* + ID_OUI_FROM_DATABASE=YASKAWA ELECTRIC CORPORATION + +OUI:0020B6* + ID_OUI_FROM_DATABASE=AGILE NETWORKS, INC. + +OUI:0020B7* + ID_OUI_FROM_DATABASE=NAMAQUA COMPUTERWARE + +OUI:0020B8* + ID_OUI_FROM_DATABASE=PRIME OPTION, INC. + +OUI:0020B9* + ID_OUI_FROM_DATABASE=METRICOM, INC. + +OUI:0020BA* + ID_OUI_FROM_DATABASE=CENTER FOR HIGH PERFORMANCE + +OUI:0020BB* + ID_OUI_FROM_DATABASE=ZAX CORPORATION + +OUI:0020BC* + ID_OUI_FROM_DATABASE=Long Reach Networks Pty Ltd + +OUI:0020BD* + ID_OUI_FROM_DATABASE=NIOBRARA R & D CORPORATION + +OUI:0020BE* + ID_OUI_FROM_DATABASE=LAN ACCESS CORP. + +OUI:0020BF* + ID_OUI_FROM_DATABASE=AEHR TEST SYSTEMS + +OUI:0020C0* + ID_OUI_FROM_DATABASE=PULSE ELECTRONICS, INC. + +OUI:0020C1* + ID_OUI_FROM_DATABASE=SAXA, Inc. + +OUI:0020C2* + ID_OUI_FROM_DATABASE=TEXAS MEMORY SYSTEMS, INC. + +OUI:0020C3* + ID_OUI_FROM_DATABASE=COUNTER SOLUTIONS LTD. + +OUI:0020C4* + ID_OUI_FROM_DATABASE=INET,INC. + +OUI:0020C5* + ID_OUI_FROM_DATABASE=EAGLE TECHNOLOGY + +OUI:0020C6* + ID_OUI_FROM_DATABASE=NECTEC + +OUI:0020C7* + ID_OUI_FROM_DATABASE=AKAI Professional M.I. Corp. + +OUI:0020C8* + ID_OUI_FROM_DATABASE=LARSCOM INCORPORATED + +OUI:0020C9* + ID_OUI_FROM_DATABASE=VICTRON BV + +OUI:0020CA* + ID_OUI_FROM_DATABASE=DIGITAL OCEAN + +OUI:0020CB* + ID_OUI_FROM_DATABASE=PRETEC ELECTRONICS CORP. + +OUI:0020CC* + ID_OUI_FROM_DATABASE=DIGITAL SERVICES, LTD. + +OUI:0020CD* + ID_OUI_FROM_DATABASE=HYBRID NETWORKS, INC. + +OUI:0020CE* + ID_OUI_FROM_DATABASE=LOGICAL DESIGN GROUP, INC. + +OUI:0020CF* + ID_OUI_FROM_DATABASE=TEST & MEASUREMENT SYSTEMS INC + +OUI:0020D0* + ID_OUI_FROM_DATABASE=VERSALYNX CORPORATION + +OUI:0020D1* + ID_OUI_FROM_DATABASE=MICROCOMPUTER SYSTEMS (M) SDN. + +OUI:0020D2* + ID_OUI_FROM_DATABASE=RAD DATA COMMUNICATIONS, LTD. + +OUI:0020D3* + ID_OUI_FROM_DATABASE=OST (OUEST STANDARD TELEMATIQU + +OUI:0020D4* + ID_OUI_FROM_DATABASE=CABLETRON - ZEITTNET INC. + +OUI:0020D5* + ID_OUI_FROM_DATABASE=VIPA GMBH + +OUI:0020D6* + ID_OUI_FROM_DATABASE=BREEZECOM + +OUI:0020D7* + ID_OUI_FROM_DATABASE=JAPAN MINICOMPUTER SYSTEMS CO., Ltd. + +OUI:0020D8* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0020D9* + ID_OUI_FROM_DATABASE=PANASONIC TECHNOLOGIES, INC./MIECO-US + +OUI:0020DA* + ID_OUI_FROM_DATABASE=Alcatel North America ESD + +OUI:0020DB* + ID_OUI_FROM_DATABASE=XNET TECHNOLOGY, INC. + +OUI:0020DC* + ID_OUI_FROM_DATABASE=DENSITRON TAIWAN LTD. + +OUI:0020DD* + ID_OUI_FROM_DATABASE=Cybertec Pty Ltd + +OUI:0020DE* + ID_OUI_FROM_DATABASE=JAPAN DIGITAL LABORAT'Y CO.LTD + +OUI:0020DF* + ID_OUI_FROM_DATABASE=KYOSAN ELECTRIC MFG. CO., LTD. + +OUI:0020E0* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc. + +OUI:0020E1* + ID_OUI_FROM_DATABASE=ALAMAR ELECTRONICS + +OUI:0020E2* + ID_OUI_FROM_DATABASE=INFORMATION RESOURCE ENGINEERING + +OUI:0020E3* + ID_OUI_FROM_DATABASE=MCD KENCOM CORPORATION + +OUI:0020E4* + ID_OUI_FROM_DATABASE=HSING TECH ENTERPRISE CO., LTD + +OUI:0020E5* + ID_OUI_FROM_DATABASE=APEX DATA, INC. + +OUI:0020E6* + ID_OUI_FROM_DATABASE=LIDKOPING MACHINE TOOLS AB + +OUI:0020E7* + ID_OUI_FROM_DATABASE=B&W NUCLEAR SERVICE COMPANY + +OUI:0020E8* + ID_OUI_FROM_DATABASE=DATATREK CORPORATION + +OUI:0020E9* + ID_OUI_FROM_DATABASE=DANTEL + +OUI:0020EA* + ID_OUI_FROM_DATABASE=EFFICIENT NETWORKS, INC. + +OUI:0020EB* + ID_OUI_FROM_DATABASE=CINCINNATI MICROWAVE, INC. + +OUI:0020EC* + ID_OUI_FROM_DATABASE=TECHWARE SYSTEMS CORP. + +OUI:0020ED* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO., LTD. + +OUI:0020EE* + ID_OUI_FROM_DATABASE=GTECH CORPORATION + +OUI:0020EF* + ID_OUI_FROM_DATABASE=USC CORPORATION + +OUI:0020F0* + ID_OUI_FROM_DATABASE=UNIVERSAL MICROELECTRONICS CO. + +OUI:0020F1* + ID_OUI_FROM_DATABASE=ALTOS INDIA LIMITED + +OUI:0020F2* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:0020F3* + ID_OUI_FROM_DATABASE=RAYNET CORPORATION + +OUI:0020F4* + ID_OUI_FROM_DATABASE=SPECTRIX CORPORATION + +OUI:0020F5* + ID_OUI_FROM_DATABASE=PANDATEL AG + +OUI:0020F6* + ID_OUI_FROM_DATABASE=NET TEK AND KARLNET, INC. + +OUI:0020F7* + ID_OUI_FROM_DATABASE=CYBERDATA CORPORATION + +OUI:0020F8* + ID_OUI_FROM_DATABASE=CARRERA COMPUTERS, INC. + +OUI:0020F9* + ID_OUI_FROM_DATABASE=PARALINK NETWORKS, INC. + +OUI:0020FA* + ID_OUI_FROM_DATABASE=GDE SYSTEMS, INC. + +OUI:0020FB* + ID_OUI_FROM_DATABASE=OCTEL COMMUNICATIONS CORP. + +OUI:0020FC* + ID_OUI_FROM_DATABASE=MATROX + +OUI:0020FD* + ID_OUI_FROM_DATABASE=ITV TECHNOLOGIES, INC. + +OUI:0020FE* + ID_OUI_FROM_DATABASE=TOPWARE INC. / GRAND COMPUTER + +OUI:0020FF* + ID_OUI_FROM_DATABASE=SYMMETRICAL TECHNOLOGIES + +OUI:002100* + ID_OUI_FROM_DATABASE=GemTek Technology Co., Ltd. + +OUI:002101* + ID_OUI_FROM_DATABASE=Aplicaciones Electronicas Quasar (AEQ) + +OUI:002102* + ID_OUI_FROM_DATABASE=UpdateLogic Inc. + +OUI:002103* + ID_OUI_FROM_DATABASE=GHI Electronics, LLC + +OUI:002104* + ID_OUI_FROM_DATABASE=Gigaset Communications GmbH + +OUI:002105* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:002106* + ID_OUI_FROM_DATABASE=RIM Testing Services + +OUI:002107* + ID_OUI_FROM_DATABASE=Seowonintech Co Ltd. + +OUI:002108* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002109* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00210A* + ID_OUI_FROM_DATABASE=byd:sign Corporation + +OUI:00210B* + ID_OUI_FROM_DATABASE=GEMINI TRAZE RFID PVT. LTD. + +OUI:00210C* + ID_OUI_FROM_DATABASE=Cymtec Systems, Inc. + +OUI:00210D* + ID_OUI_FROM_DATABASE=SAMSIN INNOTEC + +OUI:00210E* + ID_OUI_FROM_DATABASE=Orpak Systems L.T.D. + +OUI:00210F* + ID_OUI_FROM_DATABASE=Cernium Corp + +OUI:002110* + ID_OUI_FROM_DATABASE=Clearbox Systems + +OUI:002111* + ID_OUI_FROM_DATABASE=Uniphone Inc. + +OUI:002112* + ID_OUI_FROM_DATABASE=WISCOM SYSTEM CO.,LTD + +OUI:002113* + ID_OUI_FROM_DATABASE=Padtec S/A + +OUI:002114* + ID_OUI_FROM_DATABASE=Hylab Technology Inc. + +OUI:002115* + ID_OUI_FROM_DATABASE=PHYWE Systeme GmbH & Co. KG + +OUI:002116* + ID_OUI_FROM_DATABASE=Transcon Electronic Systems, spol. s r. o. + +OUI:002117* + ID_OUI_FROM_DATABASE=Tellord + +OUI:002118* + ID_OUI_FROM_DATABASE=Athena Tech, Inc. + +OUI:002119* + ID_OUI_FROM_DATABASE=Samsung Electro-Mechanics + +OUI:00211A* + ID_OUI_FROM_DATABASE=LInTech Corporation + +OUI:00211B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00211C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00211D* + ID_OUI_FROM_DATABASE=Dataline AB + +OUI:00211E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00211F* + ID_OUI_FROM_DATABASE=SHINSUNG DELTATECH CO.,LTD. + +OUI:002120* + ID_OUI_FROM_DATABASE=Sequel Technologies + +OUI:002121* + ID_OUI_FROM_DATABASE=VRmagic GmbH + +OUI:002122* + ID_OUI_FROM_DATABASE=Chip-pro Ltd. + +OUI:002123* + ID_OUI_FROM_DATABASE=Aerosat Avionics + +OUI:002124* + ID_OUI_FROM_DATABASE=Optos Plc + +OUI:002125* + ID_OUI_FROM_DATABASE=KUK JE TONG SHIN Co.,LTD + +OUI:002126* + ID_OUI_FROM_DATABASE=Shenzhen Torch Equipment Co., Ltd. + +OUI:002127* + ID_OUI_FROM_DATABASE=TP-LINK Technology Co., Ltd. + +OUI:002128* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:002129* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:00212A* + ID_OUI_FROM_DATABASE=Audiovox Corporation + +OUI:00212B* + ID_OUI_FROM_DATABASE=MSA Auer + +OUI:00212C* + ID_OUI_FROM_DATABASE=SemIndia System Private Limited + +OUI:00212D* + ID_OUI_FROM_DATABASE=SCIMOLEX CORPORATION + +OUI:00212E* + ID_OUI_FROM_DATABASE=dresden-elektronik + +OUI:00212F* + ID_OUI_FROM_DATABASE=Phoebe Micro Inc. + +OUI:002130* + ID_OUI_FROM_DATABASE=Keico Hightech Inc. + +OUI:002131* + ID_OUI_FROM_DATABASE=Blynke Inc. + +OUI:002132* + ID_OUI_FROM_DATABASE=Masterclock, Inc. + +OUI:002133* + ID_OUI_FROM_DATABASE=Building B, Inc + +OUI:002134* + ID_OUI_FROM_DATABASE=Brandywine Communications + +OUI:002135* + ID_OUI_FROM_DATABASE=ALCATEL-LUCENT + +OUI:002136* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002137* + ID_OUI_FROM_DATABASE=Bay Controls, LLC + +OUI:002138* + ID_OUI_FROM_DATABASE=Cepheid + +OUI:002139* + ID_OUI_FROM_DATABASE=Escherlogic Inc. + +OUI:00213A* + ID_OUI_FROM_DATABASE=Winchester Systems Inc. + +OUI:00213B* + ID_OUI_FROM_DATABASE=Berkshire Products, Inc + +OUI:00213C* + ID_OUI_FROM_DATABASE=AliphCom + +OUI:00213D* + ID_OUI_FROM_DATABASE=Cermetek Microelectronics, Inc. + +OUI:00213E* + ID_OUI_FROM_DATABASE=TomTom + +OUI:00213F* + ID_OUI_FROM_DATABASE=A-Team Technology Ltd. + +OUI:002140* + ID_OUI_FROM_DATABASE=EN Technologies Inc. + +OUI:002141* + ID_OUI_FROM_DATABASE=RADLIVE + +OUI:002142* + ID_OUI_FROM_DATABASE=Advanced Control Systems doo + +OUI:002143* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002144* + ID_OUI_FROM_DATABASE=SS Telecoms + +OUI:002145* + ID_OUI_FROM_DATABASE=Semptian Technologies Ltd. + +OUI:002146* + ID_OUI_FROM_DATABASE=Sanmina-SCI + +OUI:002147* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:002148* + ID_OUI_FROM_DATABASE=Kaco Solar Korea + +OUI:002149* + ID_OUI_FROM_DATABASE=China Daheng Group ,Inc. + +OUI:00214A* + ID_OUI_FROM_DATABASE=Pixel Velocity, Inc + +OUI:00214B* + ID_OUI_FROM_DATABASE=Shenzhen HAMP Science & Technology Co.,Ltd + +OUI:00214C* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. + +OUI:00214D* + ID_OUI_FROM_DATABASE=Guangzhou Skytone Transmission Technology Com. Ltd. + +OUI:00214E* + ID_OUI_FROM_DATABASE=GS Yuasa Power Supply Ltd. + +OUI:00214F* + ID_OUI_FROM_DATABASE=ALPS Electric Co., Ltd + +OUI:002150* + ID_OUI_FROM_DATABASE=EYEVIEW ELECTRONICS + +OUI:002151* + ID_OUI_FROM_DATABASE=Millinet Co., Ltd. + +OUI:002152* + ID_OUI_FROM_DATABASE=General Satellite Research & Development Limited + +OUI:002153* + ID_OUI_FROM_DATABASE=SeaMicro Inc. + +OUI:002154* + ID_OUI_FROM_DATABASE=D-TACQ Solutions Ltd + +OUI:002155* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002156* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002157* + ID_OUI_FROM_DATABASE=National Datacast, Inc. + +OUI:002158* + ID_OUI_FROM_DATABASE=Style Flying Technology Co. + +OUI:002159* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:00215A* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:00215B* + ID_OUI_FROM_DATABASE=Inotive + +OUI:00215C* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00215D* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00215E* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:00215F* + ID_OUI_FROM_DATABASE=IHSE GmbH + +OUI:002160* + ID_OUI_FROM_DATABASE=Hidea Solutions Co. Ltd. + +OUI:002161* + ID_OUI_FROM_DATABASE=Yournet Inc. + +OUI:002162* + ID_OUI_FROM_DATABASE=Nortel + +OUI:002163* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP + +OUI:002164* + ID_OUI_FROM_DATABASE=Special Design Bureau for Seismic Instrumentation + +OUI:002165* + ID_OUI_FROM_DATABASE=Presstek Inc. + +OUI:002166* + ID_OUI_FROM_DATABASE=NovAtel Inc. + +OUI:002167* + ID_OUI_FROM_DATABASE=HWA JIN T&I Corp. + +OUI:002168* + ID_OUI_FROM_DATABASE=iVeia, LLC + +OUI:002169* + ID_OUI_FROM_DATABASE=Prologix, LLC. + +OUI:00216A* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00216B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00216C* + ID_OUI_FROM_DATABASE=ODVA + +OUI:00216D* + ID_OUI_FROM_DATABASE=Soltech Co., Ltd. + +OUI:00216E* + ID_OUI_FROM_DATABASE=Function ATI (Huizhou) Telecommunications Co., Ltd. + +OUI:00216F* + ID_OUI_FROM_DATABASE=SymCom, Inc. + +OUI:002170* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:002171* + ID_OUI_FROM_DATABASE=Wesung TNC Co., Ltd. + +OUI:002172* + ID_OUI_FROM_DATABASE=Seoultek Valley + +OUI:002173* + ID_OUI_FROM_DATABASE=Ion Torrent Systems, Inc. + +OUI:002174* + ID_OUI_FROM_DATABASE=AvaLAN Wireless + +OUI:002175* + ID_OUI_FROM_DATABASE=Pacific Satellite International Ltd. + +OUI:002176* + ID_OUI_FROM_DATABASE=YMax Telecom Ltd. + +OUI:002177* + ID_OUI_FROM_DATABASE=W. L. Gore & Associates + +OUI:002178* + ID_OUI_FROM_DATABASE=Matuschek Messtechnik GmbH + +OUI:002179* + ID_OUI_FROM_DATABASE=IOGEAR, Inc. + +OUI:00217A* + ID_OUI_FROM_DATABASE=Sejin Electron, Inc. + +OUI:00217B* + ID_OUI_FROM_DATABASE=Bastec AB + +OUI:00217C* + ID_OUI_FROM_DATABASE=2Wire + +OUI:00217D* + ID_OUI_FROM_DATABASE=PYXIS S.R.L. + +OUI:00217E* + ID_OUI_FROM_DATABASE=Telit Communication s.p.a + +OUI:00217F* + ID_OUI_FROM_DATABASE=Intraco Technology Pte Ltd + +OUI:002180* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002181* + ID_OUI_FROM_DATABASE=Si2 Microsystems Limited + +OUI:002182* + ID_OUI_FROM_DATABASE=SandLinks Systems, Ltd. + +OUI:002183* + ID_OUI_FROM_DATABASE=VATECH HYDRO + +OUI:002184* + ID_OUI_FROM_DATABASE=POWERSOFT SRL + +OUI:002185* + ID_OUI_FROM_DATABASE=MICRO-STAR INT'L CO.,LTD. + +OUI:002186* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd + +OUI:002187* + ID_OUI_FROM_DATABASE=Imacs GmbH + +OUI:002188* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:002189* + ID_OUI_FROM_DATABASE=AppTech, Inc. + +OUI:00218A* + ID_OUI_FROM_DATABASE=Electronic Design and Manufacturing Company + +OUI:00218B* + ID_OUI_FROM_DATABASE=Wescon Technology, Inc. + +OUI:00218C* + ID_OUI_FROM_DATABASE=TopControl GMBH + +OUI:00218D* + ID_OUI_FROM_DATABASE=AP Router Ind. Eletronica LTDA + +OUI:00218E* + ID_OUI_FROM_DATABASE=MEKICS CO., LTD. + +OUI:00218F* + ID_OUI_FROM_DATABASE=Avantgarde Acoustic Lautsprechersysteme GmbH + +OUI:002190* + ID_OUI_FROM_DATABASE=Goliath Solutions + +OUI:002191* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:002192* + ID_OUI_FROM_DATABASE=Baoding Galaxy Electronic Technology Co.,Ltd + +OUI:002193* + ID_OUI_FROM_DATABASE=Videofon MV + +OUI:002194* + ID_OUI_FROM_DATABASE=Ping Communication + +OUI:002195* + ID_OUI_FROM_DATABASE=GWD Media Limited + +OUI:002196* + ID_OUI_FROM_DATABASE=Telsey S.p.A. + +OUI:002197* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM + +OUI:002198* + ID_OUI_FROM_DATABASE=Thai Radio Co, LTD + +OUI:002199* + ID_OUI_FROM_DATABASE=Vacon Plc + +OUI:00219A* + ID_OUI_FROM_DATABASE=Cambridge Visual Networks Ltd + +OUI:00219B* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:00219C* + ID_OUI_FROM_DATABASE=Honeywld Technology Corp. + +OUI:00219D* + ID_OUI_FROM_DATABASE=Adesys BV + +OUI:00219E* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:00219F* + ID_OUI_FROM_DATABASE=SATEL OY + +OUI:0021A0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0021A1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0021A2* + ID_OUI_FROM_DATABASE=EKE-Electronics Ltd. + +OUI:0021A3* + ID_OUI_FROM_DATABASE=Micromint + +OUI:0021A4* + ID_OUI_FROM_DATABASE=Dbii Networks + +OUI:0021A5* + ID_OUI_FROM_DATABASE=ERLPhase Power Technologies Ltd. + +OUI:0021A6* + ID_OUI_FROM_DATABASE=Videotec Spa + +OUI:0021A7* + ID_OUI_FROM_DATABASE=Hantle System Co., Ltd. + +OUI:0021A8* + ID_OUI_FROM_DATABASE=Telephonics Corporation + +OUI:0021A9* + ID_OUI_FROM_DATABASE=Mobilink Telecom Co.,Ltd + +OUI:0021AA* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0021AB* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0021AC* + ID_OUI_FROM_DATABASE=Infrared Integrated Systems Ltd + +OUI:0021AD* + ID_OUI_FROM_DATABASE=Nordic ID Oy + +OUI:0021AE* + ID_OUI_FROM_DATABASE=ALCATEL-LUCENT FRANCE - WTD + +OUI:0021AF* + ID_OUI_FROM_DATABASE=Radio Frequency Systems + +OUI:0021B0* + ID_OUI_FROM_DATABASE=Tyco Telecommunications + +OUI:0021B1* + ID_OUI_FROM_DATABASE=DIGITAL SOLUTIONS LTD + +OUI:0021B2* + ID_OUI_FROM_DATABASE=Fiberblaze A/S + +OUI:0021B3* + ID_OUI_FROM_DATABASE=Ross Controls + +OUI:0021B4* + ID_OUI_FROM_DATABASE=APRO MEDIA CO., LTD + +OUI:0021B5* + ID_OUI_FROM_DATABASE=Galvanic Ltd + +OUI:0021B6* + ID_OUI_FROM_DATABASE=Triacta Power Technologies Inc. + +OUI:0021B7* + ID_OUI_FROM_DATABASE=Lexmark International Inc. + +OUI:0021B8* + ID_OUI_FROM_DATABASE=Inphi Corporation + +OUI:0021B9* + ID_OUI_FROM_DATABASE=Universal Devices Inc. + +OUI:0021BA* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0021BB* + ID_OUI_FROM_DATABASE=Riken Keiki Co., Ltd. + +OUI:0021BC* + ID_OUI_FROM_DATABASE=ZALA COMPUTER + +OUI:0021BD* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0021BE* + ID_OUI_FROM_DATABASE=Cisco, Service Provider Video Technology Group + +OUI:0021BF* + ID_OUI_FROM_DATABASE=Hitachi High-Tech Control Systems Corporation + +OUI:0021C0* + ID_OUI_FROM_DATABASE=Mobile Appliance, Inc. + +OUI:0021C1* + ID_OUI_FROM_DATABASE=ABB Oy / Medium Voltage Products + +OUI:0021C2* + ID_OUI_FROM_DATABASE=GL Communications Inc + +OUI:0021C3* + ID_OUI_FROM_DATABASE=CORNELL Communications, Inc. + +OUI:0021C4* + ID_OUI_FROM_DATABASE=Consilium AB + +OUI:0021C5* + ID_OUI_FROM_DATABASE=3DSP Corp + +OUI:0021C6* + ID_OUI_FROM_DATABASE=CSJ Global, Inc. + +OUI:0021C7* + ID_OUI_FROM_DATABASE=Russound + +OUI:0021C8* + ID_OUI_FROM_DATABASE=LOHUIS Networks + +OUI:0021C9* + ID_OUI_FROM_DATABASE=Wavecom Asia Pacific Limited + +OUI:0021CA* + ID_OUI_FROM_DATABASE=ART System Co., Ltd. + +OUI:0021CB* + ID_OUI_FROM_DATABASE=SMS TECNOLOGIA ELETRONICA LTDA + +OUI:0021CC* + ID_OUI_FROM_DATABASE=Flextronics International + +OUI:0021CD* + ID_OUI_FROM_DATABASE=LiveTV + +OUI:0021CE* + ID_OUI_FROM_DATABASE=NTC-Metrotek + +OUI:0021CF* + ID_OUI_FROM_DATABASE=The Crypto Group + +OUI:0021D0* + ID_OUI_FROM_DATABASE=Global Display Solutions Spa + +OUI:0021D1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0021D2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0021D3* + ID_OUI_FROM_DATABASE=BOCOM SECURITY(ASIA PACIFIC) LIMITED + +OUI:0021D4* + ID_OUI_FROM_DATABASE=Vollmer Werke GmbH + +OUI:0021D5* + ID_OUI_FROM_DATABASE=X2E GmbH + +OUI:0021D6* + ID_OUI_FROM_DATABASE=LXI Consortium + +OUI:0021D7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0021D8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0021D9* + ID_OUI_FROM_DATABASE=SEKONIC CORPORATION + +OUI:0021DA* + ID_OUI_FROM_DATABASE=Automation Products Group Inc. + +OUI:0021DB* + ID_OUI_FROM_DATABASE=Santachi Video Technology (Shenzhen) Co., Ltd. + +OUI:0021DC* + ID_OUI_FROM_DATABASE=TECNOALARM S.r.l. + +OUI:0021DD* + ID_OUI_FROM_DATABASE=Northstar Systems Corp + +OUI:0021DE* + ID_OUI_FROM_DATABASE=Firepro Wireless + +OUI:0021DF* + ID_OUI_FROM_DATABASE=Martin Christ GmbH + +OUI:0021E0* + ID_OUI_FROM_DATABASE=CommAgility Ltd + +OUI:0021E1* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0021E2* + ID_OUI_FROM_DATABASE=Creative Electronic GmbH + +OUI:0021E3* + ID_OUI_FROM_DATABASE=SerialTek LLC + +OUI:0021E4* + ID_OUI_FROM_DATABASE=I-WIN + +OUI:0021E5* + ID_OUI_FROM_DATABASE=Display Solution AG + +OUI:0021E6* + ID_OUI_FROM_DATABASE=Starlight Video Limited + +OUI:0021E7* + ID_OUI_FROM_DATABASE=Informatics Services Corporation + +OUI:0021E8* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:0021E9* + ID_OUI_FROM_DATABASE=Apple + +OUI:0021EA* + ID_OUI_FROM_DATABASE=Bystronic Laser AG + +OUI:0021EB* + ID_OUI_FROM_DATABASE=ESP SYSTEMS, LLC + +OUI:0021EC* + ID_OUI_FROM_DATABASE=Solutronic GmbH + +OUI:0021ED* + ID_OUI_FROM_DATABASE=Telegesis + +OUI:0021EE* + ID_OUI_FROM_DATABASE=Full Spectrum Inc. + +OUI:0021EF* + ID_OUI_FROM_DATABASE=Kapsys + +OUI:0021F0* + ID_OUI_FROM_DATABASE=EW3 Technologies LLC + +OUI:0021F1* + ID_OUI_FROM_DATABASE=Tutus Data AB + +OUI:0021F2* + ID_OUI_FROM_DATABASE=EASY3CALL Technology Limited + +OUI:0021F3* + ID_OUI_FROM_DATABASE=Si14 SpA + +OUI:0021F4* + ID_OUI_FROM_DATABASE=INRange Systems, Inc + +OUI:0021F5* + ID_OUI_FROM_DATABASE=Western Engravers Supply, Inc. + +OUI:0021F6* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:0021F7* + ID_OUI_FROM_DATABASE=HPN Supply Chain + +OUI:0021F8* + ID_OUI_FROM_DATABASE=Enseo, Inc. + +OUI:0021F9* + ID_OUI_FROM_DATABASE=WIRECOM Technologies + +OUI:0021FA* + ID_OUI_FROM_DATABASE=A4SP Technologies Ltd. + +OUI:0021FB* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:0021FC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0021FD* + ID_OUI_FROM_DATABASE=DSTA S.L. + +OUI:0021FE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0021FF* + ID_OUI_FROM_DATABASE=Cyfrowy Polsat SA + +OUI:002200* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:002201* + ID_OUI_FROM_DATABASE=Aksys Networks Inc + +OUI:002202* + ID_OUI_FROM_DATABASE=Excito Elektronik i Skåne AB + +OUI:002203* + ID_OUI_FROM_DATABASE=Glensound Electronics Ltd + +OUI:002204* + ID_OUI_FROM_DATABASE=KORATEK + +OUI:002205* + ID_OUI_FROM_DATABASE=WeLink Solutions, Inc. + +OUI:002206* + ID_OUI_FROM_DATABASE=Cyberdyne Inc. + +OUI:002207* + ID_OUI_FROM_DATABASE=Inteno Broadband Technology AB + +OUI:002208* + ID_OUI_FROM_DATABASE=Certicom Corp + +OUI:002209* + ID_OUI_FROM_DATABASE=Omron Healthcare Co., Ltd + +OUI:00220A* + ID_OUI_FROM_DATABASE=OnLive, Inc + +OUI:00220B* + ID_OUI_FROM_DATABASE=National Source Coding Center + +OUI:00220C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00220D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00220E* + ID_OUI_FROM_DATABASE=Indigo Security Co., Ltd. + +OUI:00220F* + ID_OUI_FROM_DATABASE=MoCA (Multimedia over Coax Alliance) + +OUI:002210* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002211* + ID_OUI_FROM_DATABASE=Rohati Systems + +OUI:002212* + ID_OUI_FROM_DATABASE=CAI Networks, Inc. + +OUI:002213* + ID_OUI_FROM_DATABASE=PCI CORPORATION + +OUI:002214* + ID_OUI_FROM_DATABASE=RINNAI KOREA + +OUI:002215* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:002216* + ID_OUI_FROM_DATABASE=SHIBAURA VENDING MACHINE CORPORATION + +OUI:002217* + ID_OUI_FROM_DATABASE=Neat Electronics + +OUI:002218* + ID_OUI_FROM_DATABASE=Verivue Inc. + +OUI:002219* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:00221A* + ID_OUI_FROM_DATABASE=Audio Precision + +OUI:00221B* + ID_OUI_FROM_DATABASE=Morega Systems + +OUI:00221D* + ID_OUI_FROM_DATABASE=Freegene Technology LTD + +OUI:00221E* + ID_OUI_FROM_DATABASE=Media Devices Co., Ltd. + +OUI:00221F* + ID_OUI_FROM_DATABASE=eSang Technologies Co., Ltd. + +OUI:002220* + ID_OUI_FROM_DATABASE=Mitac Technology Corp + +OUI:002221* + ID_OUI_FROM_DATABASE=ITOH DENKI CO,LTD. + +OUI:002222* + ID_OUI_FROM_DATABASE=Schaffner Deutschland GmbH + +OUI:002223* + ID_OUI_FROM_DATABASE=TimeKeeping Systems, Inc. + +OUI:002224* + ID_OUI_FROM_DATABASE=Good Will Instrument Co., Ltd. + +OUI:002225* + ID_OUI_FROM_DATABASE=Thales Avionics Ltd + +OUI:002226* + ID_OUI_FROM_DATABASE=Avaak, Inc. + +OUI:002227* + ID_OUI_FROM_DATABASE=uv-electronic GmbH + +OUI:002228* + ID_OUI_FROM_DATABASE=Breeze Innovations Ltd. + +OUI:002229* + ID_OUI_FROM_DATABASE=Compumedics Ltd + +OUI:00222A* + ID_OUI_FROM_DATABASE=SoundEar A/S + +OUI:00222B* + ID_OUI_FROM_DATABASE=Nucomm, Inc. + +OUI:00222C* + ID_OUI_FROM_DATABASE=Ceton Corp + +OUI:00222D* + ID_OUI_FROM_DATABASE=SMC Networks Inc. + +OUI:00222E* + ID_OUI_FROM_DATABASE=maintech GmbH + +OUI:00222F* + ID_OUI_FROM_DATABASE=Open Grid Computing, Inc. + +OUI:002230* + ID_OUI_FROM_DATABASE=FutureLogic Inc. + +OUI:002231* + ID_OUI_FROM_DATABASE=SMT&C Co., Ltd. + +OUI:002232* + ID_OUI_FROM_DATABASE=Design Design Technology Ltd + +OUI:002233* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:002234* + ID_OUI_FROM_DATABASE=Corventis Inc. + +OUI:002235* + ID_OUI_FROM_DATABASE=Strukton Systems bv + +OUI:002236* + ID_OUI_FROM_DATABASE=VECTOR SP. Z O.O. + +OUI:002237* + ID_OUI_FROM_DATABASE=Shinhint Group + +OUI:002238* + ID_OUI_FROM_DATABASE=LOGIPLUS + +OUI:002239* + ID_OUI_FROM_DATABASE=Indiana Life Sciences Incorporated + +OUI:00223A* + ID_OUI_FROM_DATABASE=Scientific Atlanta, Cisco SPVT Group + +OUI:00223B* + ID_OUI_FROM_DATABASE=Communication Networks, LLC + +OUI:00223C* + ID_OUI_FROM_DATABASE=RATIO Entwicklungen GmbH + +OUI:00223D* + ID_OUI_FROM_DATABASE=JumpGen Systems, LLC + +OUI:00223E* + ID_OUI_FROM_DATABASE=IRTrans GmbH + +OUI:00223F* + ID_OUI_FROM_DATABASE=Netgear Inc. + +OUI:002240* + ID_OUI_FROM_DATABASE=Universal Telecom S/A + +OUI:002241* + ID_OUI_FROM_DATABASE=Apple + +OUI:002242* + ID_OUI_FROM_DATABASE=Alacron Inc. + +OUI:002243* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc. + +OUI:002244* + ID_OUI_FROM_DATABASE=Chengdu Linkon Communications Device Co., Ltd + +OUI:002245* + ID_OUI_FROM_DATABASE=Leine & Linde AB + +OUI:002246* + ID_OUI_FROM_DATABASE=Evoc Intelligent Technology Co.,Ltd. + +OUI:002247* + ID_OUI_FROM_DATABASE=DAC ENGINEERING CO., LTD. + +OUI:002248* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:002249* + ID_OUI_FROM_DATABASE=HOME MULTIENERGY SL + +OUI:00224A* + ID_OUI_FROM_DATABASE=RAYLASE AG + +OUI:00224B* + ID_OUI_FROM_DATABASE=AIRTECH TECHNOLOGIES, INC. + +OUI:00224C* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:00224D* + ID_OUI_FROM_DATABASE=MITAC INTERNATIONAL CORP. + +OUI:00224E* + ID_OUI_FROM_DATABASE=SEEnergy Corp. + +OUI:00224F* + ID_OUI_FROM_DATABASE=Byzoro Networks Ltd. + +OUI:002250* + ID_OUI_FROM_DATABASE=Point Six Wireless, LLC + +OUI:002251* + ID_OUI_FROM_DATABASE=Lumasense Technologies + +OUI:002252* + ID_OUI_FROM_DATABASE=ZOLL Lifecor Corporation + +OUI:002253* + ID_OUI_FROM_DATABASE=Entorian Technologies + +OUI:002254* + ID_OUI_FROM_DATABASE=Bigelow Aerospace + +OUI:002255* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002256* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002257* + ID_OUI_FROM_DATABASE=3Com Europe Ltd + +OUI:002258* + ID_OUI_FROM_DATABASE=Taiyo Yuden Co., Ltd. + +OUI:002259* + ID_OUI_FROM_DATABASE=Guangzhou New Postcom Equipment Co.,Ltd. + +OUI:00225A* + ID_OUI_FROM_DATABASE=Garde Security AB + +OUI:00225B* + ID_OUI_FROM_DATABASE=Teradici Corporation + +OUI:00225C* + ID_OUI_FROM_DATABASE=Multimedia & Communication Technology + +OUI:00225D* + ID_OUI_FROM_DATABASE=Digicable Network India Pvt. Ltd. + +OUI:00225E* + ID_OUI_FROM_DATABASE=Uwin Technologies Co.,LTD + +OUI:00225F* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:002260* + ID_OUI_FROM_DATABASE=AFREEY Inc. + +OUI:002261* + ID_OUI_FROM_DATABASE=Frontier Silicon Ltd + +OUI:002262* + ID_OUI_FROM_DATABASE=BEP Marine + +OUI:002263* + ID_OUI_FROM_DATABASE=Koos Technical Services, Inc. + +OUI:002264* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:002265* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002266* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002267* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:002268* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:002269* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:00226A* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:00226B* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:00226C* + ID_OUI_FROM_DATABASE=LinkSprite Technologies, Inc. + +OUI:00226D* + ID_OUI_FROM_DATABASE=Shenzhen GIEC Electronics Co., Ltd. + +OUI:00226E* + ID_OUI_FROM_DATABASE=Gowell Electronic Limited + +OUI:00226F* + ID_OUI_FROM_DATABASE=3onedata Technology Co. Ltd. + +OUI:002270* + ID_OUI_FROM_DATABASE=ABK North America, LLC + +OUI:002271* + ID_OUI_FROM_DATABASE=Jäger Computergesteuerte Meßtechnik GmbH. + +OUI:002272* + ID_OUI_FROM_DATABASE=American Micro-Fuel Device Corp. + +OUI:002273* + ID_OUI_FROM_DATABASE=Techway + +OUI:002274* + ID_OUI_FROM_DATABASE=FamilyPhone AB + +OUI:002275* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:002276* + ID_OUI_FROM_DATABASE=Triple EYE B.V. + +OUI:002277* + ID_OUI_FROM_DATABASE=NEC Australia Pty Ltd + +OUI:002278* + ID_OUI_FROM_DATABASE=Shenzhen Tongfang Multimedia Technology Co.,Ltd. + +OUI:002279* + ID_OUI_FROM_DATABASE=Nippon Conlux Co., Ltd. + +OUI:00227A* + ID_OUI_FROM_DATABASE=Telecom Design + +OUI:00227B* + ID_OUI_FROM_DATABASE=Apogee Labs, Inc. + +OUI:00227C* + ID_OUI_FROM_DATABASE=Woori SMT Co.,ltd + +OUI:00227D* + ID_OUI_FROM_DATABASE=YE DATA INC. + +OUI:00227E* + ID_OUI_FROM_DATABASE=Chengdu 30Kaitian Communication Industry Co.Ltd + +OUI:00227F* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:002280* + ID_OUI_FROM_DATABASE=A2B Electronics AB + +OUI:002281* + ID_OUI_FROM_DATABASE=Daintree Networks Pty + +OUI:002282* + ID_OUI_FROM_DATABASE=8086 Consultancy + +OUI:002283* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:002284* + ID_OUI_FROM_DATABASE=DESAY A&V SCIENCE AND TECHNOLOGY CO.,LTD + +OUI:002285* + ID_OUI_FROM_DATABASE=NOMUS COMM SYSTEMS + +OUI:002286* + ID_OUI_FROM_DATABASE=ASTRON + +OUI:002287* + ID_OUI_FROM_DATABASE=Titan Wireless LLC + +OUI:002288* + ID_OUI_FROM_DATABASE=Sagrad, Inc. + +OUI:002289* + ID_OUI_FROM_DATABASE=Optosecurity Inc. + +OUI:00228A* + ID_OUI_FROM_DATABASE=Teratronik elektronische systeme gmbh + +OUI:00228B* + ID_OUI_FROM_DATABASE=Kensington Computer Products Group + +OUI:00228C* + ID_OUI_FROM_DATABASE=Photon Europe GmbH + +OUI:00228D* + ID_OUI_FROM_DATABASE=GBS Laboratories LLC + +OUI:00228E* + ID_OUI_FROM_DATABASE=TV-NUMERIC + +OUI:00228F* + ID_OUI_FROM_DATABASE=CNRS + +OUI:002290* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002291* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002292* + ID_OUI_FROM_DATABASE=Cinetal + +OUI:002293* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:002294* + ID_OUI_FROM_DATABASE=Kyocera Corporation + +OUI:002295* + ID_OUI_FROM_DATABASE=SGM Technology for lighting spa + +OUI:002296* + ID_OUI_FROM_DATABASE=LinoWave Corporation + +OUI:002297* + ID_OUI_FROM_DATABASE=XMOS Semiconductor + +OUI:002298* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:002299* + ID_OUI_FROM_DATABASE=SeaMicro Inc. + +OUI:00229A* + ID_OUI_FROM_DATABASE=Lastar, Inc. + +OUI:00229B* + ID_OUI_FROM_DATABASE=AverLogic Technologies, Inc. + +OUI:00229C* + ID_OUI_FROM_DATABASE=Verismo Networks Inc + +OUI:00229D* + ID_OUI_FROM_DATABASE=PYUNG-HWA IND.CO.,LTD + +OUI:00229E* + ID_OUI_FROM_DATABASE=Social Aid Research Co., Ltd. + +OUI:00229F* + ID_OUI_FROM_DATABASE=Sensys Traffic AB + +OUI:0022A0* + ID_OUI_FROM_DATABASE=Delphi Corporation + +OUI:0022A1* + ID_OUI_FROM_DATABASE=Huawei Symantec Technologies Co.,Ltd. + +OUI:0022A2* + ID_OUI_FROM_DATABASE=Xtramus Technologies + +OUI:0022A3* + ID_OUI_FROM_DATABASE=California Eastern Laboratories + +OUI:0022A4* + ID_OUI_FROM_DATABASE=2Wire + +OUI:0022A5* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0022A6* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment America + +OUI:0022A7* + ID_OUI_FROM_DATABASE=Tyco Electronics AMP GmbH + +OUI:0022A8* + ID_OUI_FROM_DATABASE=Ouman Oy + +OUI:0022A9* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:0022AA* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0022AB* + ID_OUI_FROM_DATABASE=Shenzhen Turbosight Technology Ltd + +OUI:0022AC* + ID_OUI_FROM_DATABASE=Hangzhou Siyuan Tech. Co., Ltd + +OUI:0022AD* + ID_OUI_FROM_DATABASE=TELESIS TECHNOLOGIES, INC. + +OUI:0022AE* + ID_OUI_FROM_DATABASE=Mattel Inc. + +OUI:0022AF* + ID_OUI_FROM_DATABASE=Safety Vision + +OUI:0022B0* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:0022B1* + ID_OUI_FROM_DATABASE=Elbit Systems + +OUI:0022B2* + ID_OUI_FROM_DATABASE=4RF Communications Ltd + +OUI:0022B3* + ID_OUI_FROM_DATABASE=Sei S.p.A. + +OUI:0022B4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0022B5* + ID_OUI_FROM_DATABASE=NOVITA + +OUI:0022B6* + ID_OUI_FROM_DATABASE=Superflow Technologies Group + +OUI:0022B7* + ID_OUI_FROM_DATABASE=GSS Grundig SAT-Systems GmbH + +OUI:0022B8* + ID_OUI_FROM_DATABASE=Norcott + +OUI:0022B9* + ID_OUI_FROM_DATABASE=Analogix Seminconductor, Inc + +OUI:0022BA* + ID_OUI_FROM_DATABASE=HUTH Elektronik Systeme GmbH + +OUI:0022BB* + ID_OUI_FROM_DATABASE=beyerdynamic GmbH & Co. KG + +OUI:0022BC* + ID_OUI_FROM_DATABASE=JDSU France SAS + +OUI:0022BD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0022BE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0022BF* + ID_OUI_FROM_DATABASE=SieAmp Group of Companies + +OUI:0022C0* + ID_OUI_FROM_DATABASE=Shenzhen Forcelink Electronic Co, Ltd + +OUI:0022C1* + ID_OUI_FROM_DATABASE=Active Storage Inc. + +OUI:0022C2* + ID_OUI_FROM_DATABASE=Proview Eletrônica do Brasil LTDA + +OUI:0022C3* + ID_OUI_FROM_DATABASE=Zeeport Technology Inc. + +OUI:0022C4* + ID_OUI_FROM_DATABASE=epro GmbH + +OUI:0022C5* + ID_OUI_FROM_DATABASE=INFORSON Co,Ltd. + +OUI:0022C6* + ID_OUI_FROM_DATABASE=Sutus Inc + +OUI:0022C7* + ID_OUI_FROM_DATABASE=SEGGER Microcontroller GmbH & Co. KG + +OUI:0022C8* + ID_OUI_FROM_DATABASE=Applied Instruments B.V. + +OUI:0022C9* + ID_OUI_FROM_DATABASE=Lenord, Bauer & Co GmbH + +OUI:0022CA* + ID_OUI_FROM_DATABASE=Anviz Biometric Tech. Co., Ltd. + +OUI:0022CB* + ID_OUI_FROM_DATABASE=IONODES Inc. + +OUI:0022CC* + ID_OUI_FROM_DATABASE=SciLog, Inc. + +OUI:0022CD* + ID_OUI_FROM_DATABASE=Ared Technology Co., Ltd. + +OUI:0022CE* + ID_OUI_FROM_DATABASE=Cisco, Service Provider Video Technology Group + +OUI:0022CF* + ID_OUI_FROM_DATABASE=PLANEX Communications INC + +OUI:0022D0* + ID_OUI_FROM_DATABASE=Polar Electro Oy + +OUI:0022D1* + ID_OUI_FROM_DATABASE=Albrecht Jung GmbH & Co. KG + +OUI:0022D2* + ID_OUI_FROM_DATABASE=All Earth Comércio de Eletrônicos LTDA. + +OUI:0022D3* + ID_OUI_FROM_DATABASE=Hub-Tech + +OUI:0022D4* + ID_OUI_FROM_DATABASE=ComWorth Co., Ltd. + +OUI:0022D5* + ID_OUI_FROM_DATABASE=Eaton Corp. Electrical Group Data Center Solutions - Pulizzi + +OUI:0022D6* + ID_OUI_FROM_DATABASE=Cypak AB + +OUI:0022D7* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0022D8* + ID_OUI_FROM_DATABASE=Shenzhen GST Security and Safety Technology Limited + +OUI:0022D9* + ID_OUI_FROM_DATABASE=Fortex Industrial Ltd. + +OUI:0022DA* + ID_OUI_FROM_DATABASE=ANATEK, LLC + +OUI:0022DB* + ID_OUI_FROM_DATABASE=Translogic Corporation + +OUI:0022DC* + ID_OUI_FROM_DATABASE=Vigil Health Solutions Inc. + +OUI:0022DD* + ID_OUI_FROM_DATABASE=Protecta Electronics Ltd + +OUI:0022DE* + ID_OUI_FROM_DATABASE=OPPO Digital, Inc. + +OUI:0022DF* + ID_OUI_FROM_DATABASE=TAMUZ Monitors + +OUI:0022E0* + ID_OUI_FROM_DATABASE=Atlantic Software Technologies S.r.L. + +OUI:0022E1* + ID_OUI_FROM_DATABASE=ZORT Labs, LLC. + +OUI:0022E2* + ID_OUI_FROM_DATABASE=WABTEC Transit Division + +OUI:0022E3* + ID_OUI_FROM_DATABASE=Amerigon + +OUI:0022E4* + ID_OUI_FROM_DATABASE=APASS TECHNOLOGY CO., LTD. + +OUI:0022E5* + ID_OUI_FROM_DATABASE=Fisher-Rosemount Systems Inc. + +OUI:0022E6* + ID_OUI_FROM_DATABASE=Intelligent Data + +OUI:0022E7* + ID_OUI_FROM_DATABASE=WPS Parking Systems + +OUI:0022E8* + ID_OUI_FROM_DATABASE=Applition Co., Ltd. + +OUI:0022E9* + ID_OUI_FROM_DATABASE=ProVision Communications + +OUI:0022EA* + ID_OUI_FROM_DATABASE=Rustelcom Inc. + +OUI:0022EB* + ID_OUI_FROM_DATABASE=Data Respons A/S + +OUI:0022EC* + ID_OUI_FROM_DATABASE=IDEALBT TECHNOLOGY CORPORATION + +OUI:0022ED* + ID_OUI_FROM_DATABASE=TSI Power Corporation + +OUI:0022EE* + ID_OUI_FROM_DATABASE=Algo Communication Products Ltd + +OUI:0022EF* + ID_OUI_FROM_DATABASE=Ibis Tek, LLC + +OUI:0022F0* + ID_OUI_FROM_DATABASE=3 Greens Aviation Limited + +OUI:0022F2* + ID_OUI_FROM_DATABASE=SunPower Corp + +OUI:0022F3* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:0022F4* + ID_OUI_FROM_DATABASE=AMPAK Technology, Inc. + +OUI:0022F5* + ID_OUI_FROM_DATABASE=Advanced Realtime Tracking GmbH + +OUI:0022F6* + ID_OUI_FROM_DATABASE=Syracuse Research Corporation + +OUI:0022F7* + ID_OUI_FROM_DATABASE=Conceptronic + +OUI:0022F8* + ID_OUI_FROM_DATABASE=PIMA Electronic Systems Ltd. + +OUI:0022F9* + ID_OUI_FROM_DATABASE=Pollin Electronic GmbH + +OUI:0022FA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0022FB* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0022FC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0022FD* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0022FE* + ID_OUI_FROM_DATABASE=Microprocessor Designs Inc + +OUI:0022FF* + ID_OUI_FROM_DATABASE=NIVIS LLC + +OUI:002300* + ID_OUI_FROM_DATABASE=Cayee Computer Ltd. + +OUI:002301* + ID_OUI_FROM_DATABASE=Witron Technology Limited + +OUI:002302* + ID_OUI_FROM_DATABASE=Cobalt Digital, Inc. + +OUI:002303* + ID_OUI_FROM_DATABASE=LITE-ON IT Corporation + +OUI:002304* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002305* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002306* + ID_OUI_FROM_DATABASE=ALPS Electric Co., Ltd + +OUI:002307* + ID_OUI_FROM_DATABASE=FUTURE INNOVATION TECH CO.,LTD + +OUI:002308* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:002309* + ID_OUI_FROM_DATABASE=Janam Technologies LLC + +OUI:00230A* + ID_OUI_FROM_DATABASE=ARBURG GmbH & Co KG + +OUI:00230B* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00230C* + ID_OUI_FROM_DATABASE=CLOVER ELECTRONICS CO.,LTD. + +OUI:00230D* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:00230E* + ID_OUI_FROM_DATABASE=Gorba AG + +OUI:00230F* + ID_OUI_FROM_DATABASE=Hirsch Electronics Corporation + +OUI:002310* + ID_OUI_FROM_DATABASE=LNC Technology Co., Ltd. + +OUI:002311* + ID_OUI_FROM_DATABASE=Gloscom Co., Ltd. + +OUI:002312* + ID_OUI_FROM_DATABASE=Apple + +OUI:002313* + ID_OUI_FROM_DATABASE=Qool Technologies Ltd. + +OUI:002314* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:002315* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:002316* + ID_OUI_FROM_DATABASE=KISAN ELECTRONICS CO + +OUI:002317* + ID_OUI_FROM_DATABASE=Lasercraft Inc + +OUI:002318* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:002319* + ID_OUI_FROM_DATABASE=Sielox LLC + +OUI:00231A* + ID_OUI_FROM_DATABASE=ITF Co., Ltd. + +OUI:00231B* + ID_OUI_FROM_DATABASE=Danaher Motion - Kollmorgen + +OUI:00231C* + ID_OUI_FROM_DATABASE=Fourier Systems Ltd. + +OUI:00231D* + ID_OUI_FROM_DATABASE=Deltacom Electronics Ltd + +OUI:00231E* + ID_OUI_FROM_DATABASE=Cezzer Multimedia Technologies + +OUI:00231F* + ID_OUI_FROM_DATABASE=Guangda Electronic & Telecommunication Technology Development Co., Ltd. + +OUI:002320* + ID_OUI_FROM_DATABASE=Nicira Networks + +OUI:002321* + ID_OUI_FROM_DATABASE=Avitech International Corp + +OUI:002322* + ID_OUI_FROM_DATABASE=KISS Teknical Solutions, Inc. + +OUI:002323* + ID_OUI_FROM_DATABASE=Zylin AS + +OUI:002324* + ID_OUI_FROM_DATABASE=G-PRO COMPUTER + +OUI:002325* + ID_OUI_FROM_DATABASE=IOLAN Holding + +OUI:002326* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:002327* + ID_OUI_FROM_DATABASE=Shouyo Electronics CO., LTD + +OUI:002328* + ID_OUI_FROM_DATABASE=ALCON TELECOMMUNICATIONS CO., LTD. + +OUI:002329* + ID_OUI_FROM_DATABASE=DDRdrive LLC + +OUI:00232A* + ID_OUI_FROM_DATABASE=eonas IT-Beratung und -Entwicklung GmbH + +OUI:00232B* + ID_OUI_FROM_DATABASE=IRD A/S + +OUI:00232C* + ID_OUI_FROM_DATABASE=Senticare + +OUI:00232D* + ID_OUI_FROM_DATABASE=SandForce + +OUI:00232E* + ID_OUI_FROM_DATABASE=Kedah Electronics Engineering, LLC + +OUI:00232F* + ID_OUI_FROM_DATABASE=Advanced Card Systems Ltd. + +OUI:002330* + ID_OUI_FROM_DATABASE=DIZIPIA, INC. + +OUI:002331* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:002332* + ID_OUI_FROM_DATABASE=Apple + +OUI:002333* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002334* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002335* + ID_OUI_FROM_DATABASE=Linkflex Co.,Ltd + +OUI:002336* + ID_OUI_FROM_DATABASE=METEL s.r.o. + +OUI:002337* + ID_OUI_FROM_DATABASE=Global Star Solutions ULC + +OUI:002338* + ID_OUI_FROM_DATABASE=OJ-Electronics A/S + +OUI:002339* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:00233A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:00233B* + ID_OUI_FROM_DATABASE=C-Matic Systems Ltd + +OUI:00233C* + ID_OUI_FROM_DATABASE=Alflex + +OUI:00233D* + ID_OUI_FROM_DATABASE=Novero holding B.V. + +OUI:00233E* + ID_OUI_FROM_DATABASE=Alcatel-Lucent-IPD + +OUI:00233F* + ID_OUI_FROM_DATABASE=Purechoice Inc + +OUI:002340* + ID_OUI_FROM_DATABASE=MiX Telematics + +OUI:002341* + ID_OUI_FROM_DATABASE=Siemens AB, Infrastructure & Cities, Building Technologies Division, IC BT SSP SP BA PR + +OUI:002342* + ID_OUI_FROM_DATABASE=Coffee Equipment Company + +OUI:002343* + ID_OUI_FROM_DATABASE=TEM AG + +OUI:002344* + ID_OUI_FROM_DATABASE=Objective Interface Systems, Inc. + +OUI:002345* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:002346* + ID_OUI_FROM_DATABASE=Vestac + +OUI:002347* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:002348* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:002349* + ID_OUI_FROM_DATABASE=Helmholtz Centre Berlin for Material and Energy + +OUI:00234B* + ID_OUI_FROM_DATABASE=Inyuan Technology Inc. + +OUI:00234C* + ID_OUI_FROM_DATABASE=KTC AB + +OUI:00234D* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:00234E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:00234F* + ID_OUI_FROM_DATABASE=Luminous Power Technologies Pvt. Ltd. + +OUI:002350* + ID_OUI_FROM_DATABASE=LynTec + +OUI:002351* + ID_OUI_FROM_DATABASE=2Wire + +OUI:002352* + ID_OUI_FROM_DATABASE=DATASENSOR S.p.A. + +OUI:002353* + ID_OUI_FROM_DATABASE=F E T Elettronica snc + +OUI:002354* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:002355* + ID_OUI_FROM_DATABASE=Kinco Automation(Shanghai) Ltd. + +OUI:002356* + ID_OUI_FROM_DATABASE=Packet Forensics LLC + +OUI:002357* + ID_OUI_FROM_DATABASE=Pitronot Technologies and Engineering P.T.E. Ltd. + +OUI:002358* + ID_OUI_FROM_DATABASE=SYSTEL SA + +OUI:002359* + ID_OUI_FROM_DATABASE=Benchmark Electronics ( Thailand ) Public Company Limited + +OUI:00235A* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., Ltd. + +OUI:00235B* + ID_OUI_FROM_DATABASE=Gulfstream + +OUI:00235C* + ID_OUI_FROM_DATABASE=Aprius, Inc. + +OUI:00235D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00235E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00235F* + ID_OUI_FROM_DATABASE=Silicon Micro Sensors GmbH + +OUI:002360* + ID_OUI_FROM_DATABASE=Lookit Technology Co., Ltd + +OUI:002361* + ID_OUI_FROM_DATABASE=Unigen Corporation + +OUI:002362* + ID_OUI_FROM_DATABASE=Goldline Controls + +OUI:002363* + ID_OUI_FROM_DATABASE=Zhuhai RaySharp Technology Co., Ltd. + +OUI:002364* + ID_OUI_FROM_DATABASE=Power Instruments Pte Ltd + +OUI:002365* + ID_OUI_FROM_DATABASE=ELKA-Elektronik GmbH + +OUI:002366* + ID_OUI_FROM_DATABASE=Beijing Siasun Electronic System Co.,Ltd. + +OUI:002367* + ID_OUI_FROM_DATABASE=UniControls a.s. + +OUI:002368* + ID_OUI_FROM_DATABASE=Motorola + +OUI:002369* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:00236A* + ID_OUI_FROM_DATABASE=SmartRG Inc + +OUI:00236B* + ID_OUI_FROM_DATABASE=Xembedded, Inc. + +OUI:00236C* + ID_OUI_FROM_DATABASE=Apple + +OUI:00236D* + ID_OUI_FROM_DATABASE=ResMed Ltd + +OUI:00236E* + ID_OUI_FROM_DATABASE=Burster GmbH & Co KG + +OUI:00236F* + ID_OUI_FROM_DATABASE=DAQ System + +OUI:002370* + ID_OUI_FROM_DATABASE=Snell + +OUI:002371* + ID_OUI_FROM_DATABASE=SOAM Systel + +OUI:002372* + ID_OUI_FROM_DATABASE=MORE STAR INDUSTRIAL GROUP LIMITED + +OUI:002373* + ID_OUI_FROM_DATABASE=GridIron Systems, Inc. + +OUI:002374* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002375* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002376* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:002377* + ID_OUI_FROM_DATABASE=Isotek Electronics Ltd + +OUI:002378* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:002379* + ID_OUI_FROM_DATABASE=Union Business Machines Co. Ltd. + +OUI:00237A* + ID_OUI_FROM_DATABASE=RIM + +OUI:00237B* + ID_OUI_FROM_DATABASE=WHDI LLC + +OUI:00237C* + ID_OUI_FROM_DATABASE=NEOTION + +OUI:00237D* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:00237E* + ID_OUI_FROM_DATABASE=ELSTER GMBH + +OUI:00237F* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:002380* + ID_OUI_FROM_DATABASE=Nanoteq + +OUI:002381* + ID_OUI_FROM_DATABASE=Lengda Technology(Xiamen) Co.,Ltd. + +OUI:002382* + ID_OUI_FROM_DATABASE=Lih Rong Electronic Enterprise Co., Ltd. + +OUI:002383* + ID_OUI_FROM_DATABASE=InMage Systems Inc + +OUI:002384* + ID_OUI_FROM_DATABASE=GGH Engineering s.r.l. + +OUI:002385* + ID_OUI_FROM_DATABASE=ANTIPODE + +OUI:002386* + ID_OUI_FROM_DATABASE=Tour & Andersson AB + +OUI:002387* + ID_OUI_FROM_DATABASE=ThinkFlood, Inc. + +OUI:002388* + ID_OUI_FROM_DATABASE=V.T. Telematica S.p.a. + +OUI:002389* + ID_OUI_FROM_DATABASE=HANGZHOU H3C Technologies Co., Ltd. + +OUI:00238A* + ID_OUI_FROM_DATABASE=Ciena Corporation + +OUI:00238B* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:00238D* + ID_OUI_FROM_DATABASE=Techno Design Co., Ltd. + +OUI:00238E* + ID_OUI_FROM_DATABASE=Pirelli Tyre S.p.A. + +OUI:00238F* + ID_OUI_FROM_DATABASE=NIDEC COPAL CORPORATION + +OUI:002390* + ID_OUI_FROM_DATABASE=Algolware Corporation + +OUI:002391* + ID_OUI_FROM_DATABASE=Maxian + +OUI:002392* + ID_OUI_FROM_DATABASE=Proteus Industries Inc. + +OUI:002393* + ID_OUI_FROM_DATABASE=AJINEXTEK + +OUI:002394* + ID_OUI_FROM_DATABASE=Samjeon + +OUI:002395* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002396* + ID_OUI_FROM_DATABASE=ANDES TECHNOLOGY CORPORATION + +OUI:002397* + ID_OUI_FROM_DATABASE=Westell Technologies Inc. + +OUI:002398* + ID_OUI_FROM_DATABASE=Sky Control + +OUI:002399* + ID_OUI_FROM_DATABASE=VD Division, Samsung Electronics Co. + +OUI:00239A* + ID_OUI_FROM_DATABASE=EasyData Hardware GmbH + +OUI:00239B* + ID_OUI_FROM_DATABASE=Elster Solutions, LLC + +OUI:00239C* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:00239D* + ID_OUI_FROM_DATABASE=Mapower Electronics Co., Ltd + +OUI:00239E* + ID_OUI_FROM_DATABASE=Jiangsu Lemote Technology Corporation Limited + +OUI:00239F* + ID_OUI_FROM_DATABASE=Institut für Prüftechnik + +OUI:0023A0* + ID_OUI_FROM_DATABASE=Hana CNS Co., LTD. + +OUI:0023A1* + ID_OUI_FROM_DATABASE=Trend Electronics Ltd + +OUI:0023A2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0023A3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0023A4* + ID_OUI_FROM_DATABASE=New Concepts Development Corp. + +OUI:0023A5* + ID_OUI_FROM_DATABASE=SageTV, LLC + +OUI:0023A6* + ID_OUI_FROM_DATABASE=E-Mon + +OUI:0023A7* + ID_OUI_FROM_DATABASE=Redpine Signals, Inc. + +OUI:0023A8* + ID_OUI_FROM_DATABASE=Marshall Electronics + +OUI:0023A9* + ID_OUI_FROM_DATABASE=Beijing Detianquan Electromechanical Equipment Co., Ltd + +OUI:0023AA* + ID_OUI_FROM_DATABASE=HFR, Inc. + +OUI:0023AB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0023AC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0023AD* + ID_OUI_FROM_DATABASE=Xmark Corporation + +OUI:0023AE* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:0023AF* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0023B0* + ID_OUI_FROM_DATABASE=COMXION Technology Inc. + +OUI:0023B1* + ID_OUI_FROM_DATABASE=Longcheer Technology (Singapore) Pte Ltd + +OUI:0023B2* + ID_OUI_FROM_DATABASE=Intelligent Mechatronic Systems Inc + +OUI:0023B3* + ID_OUI_FROM_DATABASE=Lyyn AB + +OUI:0023B4* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0023B5* + ID_OUI_FROM_DATABASE=ORTANA LTD + +OUI:0023B6* + ID_OUI_FROM_DATABASE=SECURITE COMMUNICATIONS / HONEYWELL + +OUI:0023B7* + ID_OUI_FROM_DATABASE=Q-Light Co., Ltd. + +OUI:0023B8* + ID_OUI_FROM_DATABASE=Sichuan Jiuzhou Electronic Technology Co.,Ltd + +OUI:0023B9* + ID_OUI_FROM_DATABASE=EADS Deutschland GmbH + +OUI:0023BA* + ID_OUI_FROM_DATABASE=Chroma + +OUI:0023BB* + ID_OUI_FROM_DATABASE=Schmitt Industries + +OUI:0023BC* + ID_OUI_FROM_DATABASE=EQ-SYS GmbH + +OUI:0023BD* + ID_OUI_FROM_DATABASE=Digital Ally, Inc. + +OUI:0023BE* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:0023BF* + ID_OUI_FROM_DATABASE=Mainpine, Inc. + +OUI:0023C0* + ID_OUI_FROM_DATABASE=Broadway Networks + +OUI:0023C1* + ID_OUI_FROM_DATABASE=Securitas Direct AB + +OUI:0023C2* + ID_OUI_FROM_DATABASE=SAMSUNG Electronics. Co. LTD + +OUI:0023C3* + ID_OUI_FROM_DATABASE=LogMeIn, Inc. + +OUI:0023C4* + ID_OUI_FROM_DATABASE=Lux Lumen + +OUI:0023C5* + ID_OUI_FROM_DATABASE=Radiation Safety and Control Services Inc + +OUI:0023C6* + ID_OUI_FROM_DATABASE=SMC Corporation + +OUI:0023C7* + ID_OUI_FROM_DATABASE=AVSystem + +OUI:0023C8* + ID_OUI_FROM_DATABASE=TEAM-R + +OUI:0023C9* + ID_OUI_FROM_DATABASE=Sichuan Tianyi Information Science & Technology Stock CO.,LTD + +OUI:0023CA* + ID_OUI_FROM_DATABASE=Behind The Set, LLC + +OUI:0023CB* + ID_OUI_FROM_DATABASE=Shenzhen Full-join Technology Co.,Ltd + +OUI:0023CC* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0023CD* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:0023CE* + ID_OUI_FROM_DATABASE=KITA DENSHI CORPORATION + +OUI:0023CF* + ID_OUI_FROM_DATABASE=CUMMINS-ALLISON CORP. + +OUI:0023D0* + ID_OUI_FROM_DATABASE=Uniloc USA Inc. + +OUI:0023D1* + ID_OUI_FROM_DATABASE=TRG + +OUI:0023D2* + ID_OUI_FROM_DATABASE=Inhand Electronics, Inc. + +OUI:0023D3* + ID_OUI_FROM_DATABASE=AirLink WiFi Networking Corp. + +OUI:0023D4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0023D5* + ID_OUI_FROM_DATABASE=WAREMA electronic GmbH + +OUI:0023D6* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:0023D7* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:0023D8* + ID_OUI_FROM_DATABASE=Ball-It Oy + +OUI:0023D9* + ID_OUI_FROM_DATABASE=Banner Engineering + +OUI:0023DA* + ID_OUI_FROM_DATABASE=Industrial Computer Source (Deutschland)GmbH + +OUI:0023DB* + ID_OUI_FROM_DATABASE=saxnet gmbh + +OUI:0023DC* + ID_OUI_FROM_DATABASE=Benein, Inc + +OUI:0023DD* + ID_OUI_FROM_DATABASE=ELGIN S.A. + +OUI:0023DE* + ID_OUI_FROM_DATABASE=Ansync Inc. + +OUI:0023DF* + ID_OUI_FROM_DATABASE=Apple + +OUI:0023E0* + ID_OUI_FROM_DATABASE=INO Therapeutics LLC + +OUI:0023E1* + ID_OUI_FROM_DATABASE=Cavena Image Products AB + +OUI:0023E2* + ID_OUI_FROM_DATABASE=SEA Signalisation + +OUI:0023E3* + ID_OUI_FROM_DATABASE=Microtronic AG + +OUI:0023E4* + ID_OUI_FROM_DATABASE=IPnect co. ltd. + +OUI:0023E5* + ID_OUI_FROM_DATABASE=IPaXiom Networks + +OUI:0023E6* + ID_OUI_FROM_DATABASE=Pirkus, Inc. + +OUI:0023E7* + ID_OUI_FROM_DATABASE=Hinke A/S + +OUI:0023E8* + ID_OUI_FROM_DATABASE=Demco Corp. + +OUI:0023E9* + ID_OUI_FROM_DATABASE=F5 Networks, Inc. + +OUI:0023EA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0023EB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0023EC* + ID_OUI_FROM_DATABASE=Algorithmix GmbH + +OUI:0023ED* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0023EE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0023EF* + ID_OUI_FROM_DATABASE=Zuend Systemtechnik AG + +OUI:0023F0* + ID_OUI_FROM_DATABASE=Shanghai Jinghan Weighing Apparatus Co. Ltd. + +OUI:0023F1* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:0023F2* + ID_OUI_FROM_DATABASE=TVLogic + +OUI:0023F3* + ID_OUI_FROM_DATABASE=Glocom, Inc. + +OUI:0023F4* + ID_OUI_FROM_DATABASE=Masternaut + +OUI:0023F5* + ID_OUI_FROM_DATABASE=WILO SE + +OUI:0023F6* + ID_OUI_FROM_DATABASE=Softwell Technology Co., Ltd. + +OUI:0023F8* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:0023F9* + ID_OUI_FROM_DATABASE=Double-Take Software, INC. + +OUI:0023FA* + ID_OUI_FROM_DATABASE=RG Nets, Inc. + +OUI:0023FB* + ID_OUI_FROM_DATABASE=IP Datatel, LLC. + +OUI:0023FC* + ID_OUI_FROM_DATABASE=Ultra Stereo Labs, Inc + +OUI:0023FD* + ID_OUI_FROM_DATABASE=AFT Atlas Fahrzeugtechnik GmbH + +OUI:0023FE* + ID_OUI_FROM_DATABASE=Biodevices, SA + +OUI:0023FF* + ID_OUI_FROM_DATABASE=Beijing HTTC Technology Ltd. + +OUI:002400* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:002401* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:002402* + ID_OUI_FROM_DATABASE=Op-Tection GmbH + +OUI:002403* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002404* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002405* + ID_OUI_FROM_DATABASE=Dilog Nordic AB + +OUI:002406* + ID_OUI_FROM_DATABASE=Pointmobile + +OUI:002407* + ID_OUI_FROM_DATABASE=TELEM SAS + +OUI:002408* + ID_OUI_FROM_DATABASE=Pacific Biosciences + +OUI:002409* + ID_OUI_FROM_DATABASE=The Toro Company + +OUI:00240A* + ID_OUI_FROM_DATABASE=US Beverage Net + +OUI:00240B* + ID_OUI_FROM_DATABASE=Virtual Computer Inc. + +OUI:00240C* + ID_OUI_FROM_DATABASE=DELEC GmbH + +OUI:00240D* + ID_OUI_FROM_DATABASE=OnePath Networks LTD. + +OUI:00240E* + ID_OUI_FROM_DATABASE=Inventec Besta Co., Ltd. + +OUI:00240F* + ID_OUI_FROM_DATABASE=Ishii Tool & Engineering Corporation + +OUI:002410* + ID_OUI_FROM_DATABASE=NUETEQ Technology,Inc. + +OUI:002411* + ID_OUI_FROM_DATABASE=PharmaSmart LLC + +OUI:002412* + ID_OUI_FROM_DATABASE=Benign Technologies Co, Ltd. + +OUI:002413* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002414* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002415* + ID_OUI_FROM_DATABASE=Magnetic Autocontrol GmbH + +OUI:002416* + ID_OUI_FROM_DATABASE=Any Use + +OUI:002417* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:002418* + ID_OUI_FROM_DATABASE=Nextwave Semiconductor + +OUI:00241A* + ID_OUI_FROM_DATABASE=Red Beetle Inc. + +OUI:00241B* + ID_OUI_FROM_DATABASE=iWOW Communications Pte Ltd + +OUI:00241C* + ID_OUI_FROM_DATABASE=FuGang Electronic (DG) Co.,Ltd + +OUI:00241D* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:00241E* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:00241F* + ID_OUI_FROM_DATABASE=DCT-Delta GmbH + +OUI:002420* + ID_OUI_FROM_DATABASE=NetUP Inc. + +OUI:002421* + ID_OUI_FROM_DATABASE=MICRO-STAR INT'L CO., LTD. + +OUI:002422* + ID_OUI_FROM_DATABASE=Knapp Logistik Automation GmbH + +OUI:002423* + ID_OUI_FROM_DATABASE=AzureWave Technologies (Shanghai) Inc. + +OUI:002424* + ID_OUI_FROM_DATABASE=Axis Network Technology + +OUI:002425* + ID_OUI_FROM_DATABASE=Shenzhenshi chuangzhicheng Technology Co.,Ltd + +OUI:002426* + ID_OUI_FROM_DATABASE=NOHMI BOSAI LTD. + +OUI:002427* + ID_OUI_FROM_DATABASE=SSI COMPUTER CORP + +OUI:002428* + ID_OUI_FROM_DATABASE=EnergyICT + +OUI:002429* + ID_OUI_FROM_DATABASE=MK MASTER INC. + +OUI:00242A* + ID_OUI_FROM_DATABASE=Hittite Microwave Corporation + +OUI:00242B* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.,Ltd. + +OUI:00242C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:00242E* + ID_OUI_FROM_DATABASE=Datastrip Inc. + +OUI:00242F* + ID_OUI_FROM_DATABASE=VirtenSys Inc + +OUI:002430* + ID_OUI_FROM_DATABASE=Ruby Tech Corp. + +OUI:002431* + ID_OUI_FROM_DATABASE=Uni-v co.,ltd + +OUI:002432* + ID_OUI_FROM_DATABASE=Neostar Technology Co.,LTD + +OUI:002433* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:002434* + ID_OUI_FROM_DATABASE=Lectrosonics, Inc. + +OUI:002435* + ID_OUI_FROM_DATABASE=WIDE CORPORATION + +OUI:002436* + ID_OUI_FROM_DATABASE=Apple + +OUI:002437* + ID_OUI_FROM_DATABASE=Motorola - BSG + +OUI:002438* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:002439* + ID_OUI_FROM_DATABASE=Digital Barriers Advanced Technologies + +OUI:00243A* + ID_OUI_FROM_DATABASE=Ludl Electronic Products + +OUI:00243B* + ID_OUI_FROM_DATABASE=CSSI (S) Pte Ltd + +OUI:00243C* + ID_OUI_FROM_DATABASE=S.A.A.A. + +OUI:00243D* + ID_OUI_FROM_DATABASE=Emerson Appliance Motors and Controls + +OUI:00243F* + ID_OUI_FROM_DATABASE=Storwize, Inc. + +OUI:002440* + ID_OUI_FROM_DATABASE=Halo Monitoring, Inc. + +OUI:002441* + ID_OUI_FROM_DATABASE=Wanzl Metallwarenfabrik GmbH + +OUI:002442* + ID_OUI_FROM_DATABASE=Axona Limited + +OUI:002443* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:002444* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:002445* + ID_OUI_FROM_DATABASE=CommScope Canada Inc. + +OUI:002446* + ID_OUI_FROM_DATABASE=MMB Research Inc. + +OUI:002447* + ID_OUI_FROM_DATABASE=Kaztek Systems + +OUI:002448* + ID_OUI_FROM_DATABASE=SpiderCloud Wireless, Inc + +OUI:002449* + ID_OUI_FROM_DATABASE=Shen Zhen Lite Star Electronics Technology Co., Ltd + +OUI:00244A* + ID_OUI_FROM_DATABASE=Voyant International + +OUI:00244B* + ID_OUI_FROM_DATABASE=PERCEPTRON INC + +OUI:00244C* + ID_OUI_FROM_DATABASE=Solartron Metrology Ltd + +OUI:00244D* + ID_OUI_FROM_DATABASE=Hokkaido Electronics Corporation + +OUI:00244E* + ID_OUI_FROM_DATABASE=RadChips, Inc. + +OUI:00244F* + ID_OUI_FROM_DATABASE=Asantron Technologies Ltd. + +OUI:002450* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002451* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002452* + ID_OUI_FROM_DATABASE=Silicon Software GmbH + +OUI:002453* + ID_OUI_FROM_DATABASE=Initra d.o.o. + +OUI:002454* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:002455* + ID_OUI_FROM_DATABASE=MuLogic BV + +OUI:002456* + ID_OUI_FROM_DATABASE=2Wire + +OUI:002458* + ID_OUI_FROM_DATABASE=PA Bastion CC + +OUI:002459* + ID_OUI_FROM_DATABASE=ABB STOTZ-KONTAKT GmbH + +OUI:00245A* + ID_OUI_FROM_DATABASE=Nanjing Panda Electronics Company Limited + +OUI:00245B* + ID_OUI_FROM_DATABASE=RAIDON TECHNOLOGY, INC. + +OUI:00245C* + ID_OUI_FROM_DATABASE=Design-Com Technologies Pty. Ltd. + +OUI:00245D* + ID_OUI_FROM_DATABASE=Terberg besturingstechniek B.V. + +OUI:00245E* + ID_OUI_FROM_DATABASE=Hivision Co.,ltd + +OUI:00245F* + ID_OUI_FROM_DATABASE=Vine Telecom CO.,Ltd. + +OUI:002460* + ID_OUI_FROM_DATABASE=Giaval Science Development Co. Ltd. + +OUI:002461* + ID_OUI_FROM_DATABASE=Shin Wang Tech. + +OUI:002462* + ID_OUI_FROM_DATABASE=Rayzone Corporation + +OUI:002463* + ID_OUI_FROM_DATABASE=Phybridge Inc + +OUI:002464* + ID_OUI_FROM_DATABASE=Bridge Technologies Co AS + +OUI:002465* + ID_OUI_FROM_DATABASE=Elentec + +OUI:002466* + ID_OUI_FROM_DATABASE=Unitron nv + +OUI:002467* + ID_OUI_FROM_DATABASE=AOC International (Europe) GmbH + +OUI:002468* + ID_OUI_FROM_DATABASE=Sumavision Technologies Co.,Ltd + +OUI:002469* + ID_OUI_FROM_DATABASE=Smart Doorphones + +OUI:00246A* + ID_OUI_FROM_DATABASE=Solid Year Co., Ltd. + +OUI:00246B* + ID_OUI_FROM_DATABASE=Covia, Inc. + +OUI:00246C* + ID_OUI_FROM_DATABASE=ARUBA NETWORKS, INC. + +OUI:00246D* + ID_OUI_FROM_DATABASE=Weinzierl Engineering GmbH + +OUI:00246E* + ID_OUI_FROM_DATABASE=Phihong USA Corp. + +OUI:00246F* + ID_OUI_FROM_DATABASE=Onda Communication spa + +OUI:002470* + ID_OUI_FROM_DATABASE=AUROTECH ultrasound AS. + +OUI:002471* + ID_OUI_FROM_DATABASE=Fusion MultiSystems dba Fusion-io + +OUI:002472* + ID_OUI_FROM_DATABASE=ReDriven Power Inc. + +OUI:002473* + ID_OUI_FROM_DATABASE=3Com Europe Ltd + +OUI:002474* + ID_OUI_FROM_DATABASE=Autronica Fire And Securirty + +OUI:002475* + ID_OUI_FROM_DATABASE=Compass System(Embedded Dept.) + +OUI:002476* + ID_OUI_FROM_DATABASE=TAP.tv + +OUI:002477* + ID_OUI_FROM_DATABASE=Tibbo Technology + +OUI:002478* + ID_OUI_FROM_DATABASE=Mag Tech Electronics Co Limited + +OUI:002479* + ID_OUI_FROM_DATABASE=Optec Displays, Inc. + +OUI:00247A* + ID_OUI_FROM_DATABASE=FU YI CHENG Technology Co., Ltd. + +OUI:00247B* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:00247C* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00247D* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00247E* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd + +OUI:00247F* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:002480* + ID_OUI_FROM_DATABASE=Meteocontrol GmbH + +OUI:002481* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:002482* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:002483* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:002484* + ID_OUI_FROM_DATABASE=Bang and Olufsen Medicom a/s + +OUI:002485* + ID_OUI_FROM_DATABASE=ConteXtream Ltd + +OUI:002486* + ID_OUI_FROM_DATABASE=DesignArt Networks + +OUI:002487* + ID_OUI_FROM_DATABASE=Blackboard Inc. + +OUI:002488* + ID_OUI_FROM_DATABASE=Centre For Development Of Telematics + +OUI:002489* + ID_OUI_FROM_DATABASE=Vodafone Omnitel N.V. + +OUI:00248A* + ID_OUI_FROM_DATABASE=Kaga Electronics Co., Ltd. + +OUI:00248B* + ID_OUI_FROM_DATABASE=HYBUS CO., LTD. + +OUI:00248C* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:00248D* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:00248E* + ID_OUI_FROM_DATABASE=Infoware ZRt. + +OUI:00248F* + ID_OUI_FROM_DATABASE=DO-MONIX + +OUI:002490* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:002491* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:002492* + ID_OUI_FROM_DATABASE=Motorola, Broadband Solutions Group + +OUI:002493* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002494* + ID_OUI_FROM_DATABASE=Shenzhen Baoxin Tech CO., Ltd. + +OUI:002495* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002496* + ID_OUI_FROM_DATABASE=Ginzinger electronic systems + +OUI:002497* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002498* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002499* + ID_OUI_FROM_DATABASE=Aquila Technologies + +OUI:00249A* + ID_OUI_FROM_DATABASE=Beijing Zhongchuang Telecommunication Test Co., Ltd. + +OUI:00249B* + ID_OUI_FROM_DATABASE=Action Star Enterprise Co., Ltd. + +OUI:00249C* + ID_OUI_FROM_DATABASE=Bimeng Comunication System Co. Ltd + +OUI:00249D* + ID_OUI_FROM_DATABASE=NES Technology Inc. + +OUI:00249E* + ID_OUI_FROM_DATABASE=ADC-Elektronik GmbH + +OUI:00249F* + ID_OUI_FROM_DATABASE=RIM Testing Services + +OUI:0024A0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0024A1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0024A2* + ID_OUI_FROM_DATABASE=Hong Kong Middleware Technology Limited + +OUI:0024A3* + ID_OUI_FROM_DATABASE=Sonim Technologies Inc + +OUI:0024A4* + ID_OUI_FROM_DATABASE=Siklu Communication + +OUI:0024A5* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:0024A6* + ID_OUI_FROM_DATABASE=TELESTAR DIGITAL GmbH + +OUI:0024A7* + ID_OUI_FROM_DATABASE=Advanced Video Communications Inc. + +OUI:0024A8* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:0024A9* + ID_OUI_FROM_DATABASE=Ag Leader Technology + +OUI:0024AA* + ID_OUI_FROM_DATABASE=Dycor Technologies Ltd. + +OUI:0024AB* + ID_OUI_FROM_DATABASE=A7 Engineering, Inc. + +OUI:0024AC* + ID_OUI_FROM_DATABASE=Hangzhou DPtech Technologies Co., Ltd. + +OUI:0024AD* + ID_OUI_FROM_DATABASE=Adolf Thies Gmbh & Co. KG + +OUI:0024AE* + ID_OUI_FROM_DATABASE=Morpho + +OUI:0024AF* + ID_OUI_FROM_DATABASE=EchoStar Technologies + +OUI:0024B0* + ID_OUI_FROM_DATABASE=ESAB AB + +OUI:0024B1* + ID_OUI_FROM_DATABASE=Coulomb Technologies + +OUI:0024B2* + ID_OUI_FROM_DATABASE=Netgear + +OUI:0024B3* + ID_OUI_FROM_DATABASE=Graf-Syteco GmbH & Co. KG + +OUI:0024B4* + ID_OUI_FROM_DATABASE=ESCATRONIC GmbH + +OUI:0024B5* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0024B6* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:0024B7* + ID_OUI_FROM_DATABASE=GridPoint, Inc. + +OUI:0024B8* + ID_OUI_FROM_DATABASE=free alliance sdn bhd + +OUI:0024B9* + ID_OUI_FROM_DATABASE=Wuhan Higheasy Electronic Technology Development Co.Ltd + +OUI:0024BA* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:0024BB* + ID_OUI_FROM_DATABASE=CENTRAL Corporation + +OUI:0024BC* + ID_OUI_FROM_DATABASE=HuRob Co.,Ltd + +OUI:0024BD* + ID_OUI_FROM_DATABASE=Hainzl Industriesysteme GmbH + +OUI:0024BE* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:0024BF* + ID_OUI_FROM_DATABASE=CIAT + +OUI:0024C0* + ID_OUI_FROM_DATABASE=NTI COMODO INC + +OUI:0024C1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0024C2* + ID_OUI_FROM_DATABASE=Asumo Co.,Ltd. + +OUI:0024C3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0024C4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0024C5* + ID_OUI_FROM_DATABASE=Meridian Audio Limited + +OUI:0024C6* + ID_OUI_FROM_DATABASE=Hager Electro SAS + +OUI:0024C7* + ID_OUI_FROM_DATABASE=Mobilarm Ltd + +OUI:0024C8* + ID_OUI_FROM_DATABASE=Broadband Solutions Group + +OUI:0024C9* + ID_OUI_FROM_DATABASE=Broadband Solutions Group + +OUI:0024CA* + ID_OUI_FROM_DATABASE=Tobii Technology AB + +OUI:0024CB* + ID_OUI_FROM_DATABASE=Autonet Mobile + +OUI:0024CC* + ID_OUI_FROM_DATABASE=Fascinations Toys and Gifts, Inc. + +OUI:0024CD* + ID_OUI_FROM_DATABASE=Willow Garage, Inc. + +OUI:0024CE* + ID_OUI_FROM_DATABASE=Exeltech Inc + +OUI:0024CF* + ID_OUI_FROM_DATABASE=Inscape Data Corporation + +OUI:0024D0* + ID_OUI_FROM_DATABASE=Shenzhen SOGOOD Industry CO.,LTD. + +OUI:0024D1* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:0024D2* + ID_OUI_FROM_DATABASE=Askey Computer + +OUI:0024D3* + ID_OUI_FROM_DATABASE=QUALICA Inc. + +OUI:0024D4* + ID_OUI_FROM_DATABASE=FREEBOX SA + +OUI:0024D5* + ID_OUI_FROM_DATABASE=Winward Industrial Limited + +OUI:0024D6* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0024D7* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0024D8* + ID_OUI_FROM_DATABASE=IlSung Precision + +OUI:0024D9* + ID_OUI_FROM_DATABASE=BICOM, Inc. + +OUI:0024DA* + ID_OUI_FROM_DATABASE=Innovar Systems Limited + +OUI:0024DB* + ID_OUI_FROM_DATABASE=Alcohol Monitoring Systems + +OUI:0024DC* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0024DD* + ID_OUI_FROM_DATABASE=Centrak, Inc. + +OUI:0024DE* + ID_OUI_FROM_DATABASE=GLOBAL Technology Inc. + +OUI:0024DF* + ID_OUI_FROM_DATABASE=Digitalbox Europe GmbH + +OUI:0024E0* + ID_OUI_FROM_DATABASE=DS Tech, LLC + +OUI:0024E1* + ID_OUI_FROM_DATABASE=Convey Computer Corp. + +OUI:0024E2* + ID_OUI_FROM_DATABASE=HASEGAWA ELECTRIC CO.,LTD. + +OUI:0024E3* + ID_OUI_FROM_DATABASE=CAO Group + +OUI:0024E4* + ID_OUI_FROM_DATABASE=Withings + +OUI:0024E5* + ID_OUI_FROM_DATABASE=Seer Technology, Inc + +OUI:0024E6* + ID_OUI_FROM_DATABASE=In Motion Technology Inc. + +OUI:0024E7* + ID_OUI_FROM_DATABASE=Plaster Networks + +OUI:0024E8* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:0024E9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd., Storage System Division + +OUI:0024EA* + ID_OUI_FROM_DATABASE=iris-GmbH infrared & intelligent sensors + +OUI:0024EB* + ID_OUI_FROM_DATABASE=ClearPath Networks, Inc. + +OUI:0024EC* + ID_OUI_FROM_DATABASE=United Information Technology Co.,Ltd. + +OUI:0024ED* + ID_OUI_FROM_DATABASE=YT Elec. Co,.Ltd. + +OUI:0024EE* + ID_OUI_FROM_DATABASE=Wynmax Inc. + +OUI:0024EF* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:0024F0* + ID_OUI_FROM_DATABASE=Seanodes + +OUI:0024F1* + ID_OUI_FROM_DATABASE=Shenzhen Fanhai Sanjiang Electronics Co., Ltd. + +OUI:0024F2* + ID_OUI_FROM_DATABASE=Uniphone Telecommunication Co., Ltd. + +OUI:0024F3* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0024F4* + ID_OUI_FROM_DATABASE=Kaminario Technologies Ltd. + +OUI:0024F5* + ID_OUI_FROM_DATABASE=NDS Surgical Imaging + +OUI:0024F6* + ID_OUI_FROM_DATABASE=MIYOSHI ELECTRONICS CORPORATION + +OUI:0024F7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0024F8* + ID_OUI_FROM_DATABASE=Technical Solutions Company Ltd. + +OUI:0024F9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0024FA* + ID_OUI_FROM_DATABASE=Hilger u. Kern GMBH + +OUI:0024FC* + ID_OUI_FROM_DATABASE=QuoPin Co., Ltd. + +OUI:0024FD* + ID_OUI_FROM_DATABASE=Accedian Networks Inc + +OUI:0024FE* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:0024FF* + ID_OUI_FROM_DATABASE=QLogic Corporation + +OUI:002500* + ID_OUI_FROM_DATABASE=Apple + +OUI:002501* + ID_OUI_FROM_DATABASE=JSC "Supertel" + +OUI:002502* + ID_OUI_FROM_DATABASE=NaturalPoint + +OUI:002503* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:002504* + ID_OUI_FROM_DATABASE=Valiant Communications Limited + +OUI:002505* + ID_OUI_FROM_DATABASE=eks Engel GmbH & Co. KG + +OUI:002506* + ID_OUI_FROM_DATABASE=A.I. ANTITACCHEGGIO ITALIA SRL + +OUI:002507* + ID_OUI_FROM_DATABASE=ASTAK Inc. + +OUI:002508* + ID_OUI_FROM_DATABASE=Maquet Cardiopulmonary AG + +OUI:002509* + ID_OUI_FROM_DATABASE=SHARETRONIC Group LTD + +OUI:00250A* + ID_OUI_FROM_DATABASE=Security Expert Co. Ltd + +OUI:00250B* + ID_OUI_FROM_DATABASE=CENTROFACTOR INC + +OUI:00250C* + ID_OUI_FROM_DATABASE=Enertrac + +OUI:00250D* + ID_OUI_FROM_DATABASE=GZT Telkom-Telmor sp. z o.o. + +OUI:00250E* + ID_OUI_FROM_DATABASE=gt german telematics gmbh + +OUI:00250F* + ID_OUI_FROM_DATABASE=On-Ramp Wireless, Inc. + +OUI:002510* + ID_OUI_FROM_DATABASE=Pico-Tesla Magnetic Therapies + +OUI:002511* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. + +OUI:002512* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:002513* + ID_OUI_FROM_DATABASE=CXP DIGITAL BV + +OUI:002514* + ID_OUI_FROM_DATABASE=PC Worth Int'l Co., Ltd. + +OUI:002515* + ID_OUI_FROM_DATABASE=SFR + +OUI:002516* + ID_OUI_FROM_DATABASE=Integrated Design Tools, Inc. + +OUI:002517* + ID_OUI_FROM_DATABASE=Venntis, LLC + +OUI:002518* + ID_OUI_FROM_DATABASE=Power PLUS Communications AG + +OUI:002519* + ID_OUI_FROM_DATABASE=Viaas Inc + +OUI:00251A* + ID_OUI_FROM_DATABASE=Psiber Data Systems Inc. + +OUI:00251B* + ID_OUI_FROM_DATABASE=Philips CareServant + +OUI:00251C* + ID_OUI_FROM_DATABASE=EDT + +OUI:00251D* + ID_OUI_FROM_DATABASE=DSA Encore, LLC + +OUI:00251E* + ID_OUI_FROM_DATABASE=ROTEL TECHNOLOGIES + +OUI:00251F* + ID_OUI_FROM_DATABASE=ZYNUS VISION INC. + +OUI:002520* + ID_OUI_FROM_DATABASE=SMA Railway Technology GmbH + +OUI:002521* + ID_OUI_FROM_DATABASE=Logitek Electronic Systems, Inc. + +OUI:002522* + ID_OUI_FROM_DATABASE=ASRock Incorporation + +OUI:002523* + ID_OUI_FROM_DATABASE=OCP Inc. + +OUI:002524* + ID_OUI_FROM_DATABASE=Lightcomm Technology Co., Ltd + +OUI:002525* + ID_OUI_FROM_DATABASE=CTERA Networks Ltd. + +OUI:002526* + ID_OUI_FROM_DATABASE=Genuine Technologies Co., Ltd. + +OUI:002527* + ID_OUI_FROM_DATABASE=Bitrode Corp. + +OUI:002528* + ID_OUI_FROM_DATABASE=Daido Signal Co., Ltd. + +OUI:002529* + ID_OUI_FROM_DATABASE=COMELIT GROUP S.P.A + +OUI:00252A* + ID_OUI_FROM_DATABASE=Chengdu GeeYa Technology Co.,LTD + +OUI:00252B* + ID_OUI_FROM_DATABASE=Stirling Energy Systems + +OUI:00252C* + ID_OUI_FROM_DATABASE=Entourage Systems, Inc. + +OUI:00252D* + ID_OUI_FROM_DATABASE=Kiryung Electronics + +OUI:00252E* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:00252F* + ID_OUI_FROM_DATABASE=Energy, Inc. + +OUI:002530* + ID_OUI_FROM_DATABASE=Aetas Systems Inc. + +OUI:002531* + ID_OUI_FROM_DATABASE=Cloud Engines, Inc. + +OUI:002532* + ID_OUI_FROM_DATABASE=Digital Recorders + +OUI:002533* + ID_OUI_FROM_DATABASE=WITTENSTEIN AG + +OUI:002535* + ID_OUI_FROM_DATABASE=Minimax GmbH & Co KG + +OUI:002536* + ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd. + +OUI:002537* + ID_OUI_FROM_DATABASE=Runcom Technologies Ltd. + +OUI:002538* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd., Memory Division + +OUI:002539* + ID_OUI_FROM_DATABASE=IfTA GmbH + +OUI:00253A* + ID_OUI_FROM_DATABASE=CEVA, Ltd. + +OUI:00253B* + ID_OUI_FROM_DATABASE=din Dietmar Nocker Facilitymanagement GmbH + +OUI:00253C* + ID_OUI_FROM_DATABASE=2Wire + +OUI:00253D* + ID_OUI_FROM_DATABASE=DRS Consolidated Controls + +OUI:00253E* + ID_OUI_FROM_DATABASE=Sensus Metering Systems + +OUI:002540* + ID_OUI_FROM_DATABASE=Quasar Technologies, Inc. + +OUI:002541* + ID_OUI_FROM_DATABASE=Maquet Critical Care AB + +OUI:002542* + ID_OUI_FROM_DATABASE=Pittasoft + +OUI:002543* + ID_OUI_FROM_DATABASE=MONEYTECH + +OUI:002544* + ID_OUI_FROM_DATABASE=LoJack Corporation + +OUI:002545* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002546* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002547* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002548* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002549* + ID_OUI_FROM_DATABASE=Jeorich Tech. Co.,Ltd. + +OUI:00254A* + ID_OUI_FROM_DATABASE=RingCube Technologies, Inc. + +OUI:00254B* + ID_OUI_FROM_DATABASE=Apple + +OUI:00254C* + ID_OUI_FROM_DATABASE=Videon Central, Inc. + +OUI:00254D* + ID_OUI_FROM_DATABASE=Singapore Technologies Electronics Limited + +OUI:00254E* + ID_OUI_FROM_DATABASE=Vertex Wireless Co., Ltd. + +OUI:00254F* + ID_OUI_FROM_DATABASE=ELETTROLAB Srl + +OUI:002550* + ID_OUI_FROM_DATABASE=Riverbed Technology + +OUI:002551* + ID_OUI_FROM_DATABASE=SE-Elektronic GmbH + +OUI:002552* + ID_OUI_FROM_DATABASE=VXI CORPORATION + +OUI:002553* + ID_OUI_FROM_DATABASE=Pirelli Tyre S.p.A. + +OUI:002554* + ID_OUI_FROM_DATABASE=Pixel8 Networks + +OUI:002555* + ID_OUI_FROM_DATABASE=Visonic Technologies 1993 Ltd + +OUI:002556* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:002557* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:002558* + ID_OUI_FROM_DATABASE=MPEDIA + +OUI:002559* + ID_OUI_FROM_DATABASE=Syphan Technologies Ltd + +OUI:00255A* + ID_OUI_FROM_DATABASE=Tantalus Systems Corp. + +OUI:00255B* + ID_OUI_FROM_DATABASE=CoachComm, LLC + +OUI:00255C* + ID_OUI_FROM_DATABASE=NEC Corporation + +OUI:00255D* + ID_OUI_FROM_DATABASE=Morningstar Corporation + +OUI:00255E* + ID_OUI_FROM_DATABASE=Shanghai Dare Technologies Co.,Ltd. + +OUI:00255F* + ID_OUI_FROM_DATABASE=SenTec AG + +OUI:002560* + ID_OUI_FROM_DATABASE=Ibridge Networks & Communications Ltd. + +OUI:002561* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:002562* + ID_OUI_FROM_DATABASE=interbro Co. Ltd. + +OUI:002563* + ID_OUI_FROM_DATABASE=Luxtera Inc + +OUI:002564* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:002565* + ID_OUI_FROM_DATABASE=Vizimax Inc. + +OUI:002566* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:002567* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:002568* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:002569* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:00256A* + ID_OUI_FROM_DATABASE=inIT - Institut Industrial IT + +OUI:00256B* + ID_OUI_FROM_DATABASE=ATENIX E.E. s.r.l. + +OUI:00256C* + ID_OUI_FROM_DATABASE="Azimut" Production Association JSC + +OUI:00256D* + ID_OUI_FROM_DATABASE=Broadband Forum + +OUI:00256E* + ID_OUI_FROM_DATABASE=Van Breda B.V. + +OUI:00256F* + ID_OUI_FROM_DATABASE=Dantherm Power + +OUI:002570* + ID_OUI_FROM_DATABASE=Eastern Communications Company Limited + +OUI:002571* + ID_OUI_FROM_DATABASE=Zhejiang Tianle Digital Electric Co.,Ltd + +OUI:002572* + ID_OUI_FROM_DATABASE=Nemo-Q International AB + +OUI:002573* + ID_OUI_FROM_DATABASE=ST Electronics (Info-Security) Pte Ltd + +OUI:002574* + ID_OUI_FROM_DATABASE=KUNIMI MEDIA DEVICE Co., Ltd. + +OUI:002575* + ID_OUI_FROM_DATABASE=FiberPlex Technologies, LLC + +OUI:002576* + ID_OUI_FROM_DATABASE=NELI TECHNOLOGIES + +OUI:002577* + ID_OUI_FROM_DATABASE=D-BOX Technologies + +OUI:002578* + ID_OUI_FROM_DATABASE=JSC "Concern "Sozvezdie" + +OUI:002579* + ID_OUI_FROM_DATABASE=J & F Labs + +OUI:00257A* + ID_OUI_FROM_DATABASE=CAMCO Produktions- und Vertriebs-GmbH für Beschallungs- und Beleuchtungsanlagen + +OUI:00257B* + ID_OUI_FROM_DATABASE=STJ ELECTRONICS PVT LTD + +OUI:00257C* + ID_OUI_FROM_DATABASE=Huachentel Technology Development Co., Ltd + +OUI:00257D* + ID_OUI_FROM_DATABASE=PointRed Telecom Private Ltd. + +OUI:00257E* + ID_OUI_FROM_DATABASE=NEW POS Technology Limited + +OUI:00257F* + ID_OUI_FROM_DATABASE=CallTechSolution Co.,Ltd + +OUI:002580* + ID_OUI_FROM_DATABASE=Equipson S.A. + +OUI:002581* + ID_OUI_FROM_DATABASE=x-star networks Inc. + +OUI:002582* + ID_OUI_FROM_DATABASE=Maksat Technologies (P) Ltd + +OUI:002583* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002584* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002585* + ID_OUI_FROM_DATABASE=KOKUYO S&T Co., Ltd. + +OUI:002586* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co., Ltd. + +OUI:002587* + ID_OUI_FROM_DATABASE=Vitality, Inc. + +OUI:002588* + ID_OUI_FROM_DATABASE=Genie Industries, Inc. + +OUI:002589* + ID_OUI_FROM_DATABASE=Hills Industries Limited + +OUI:00258A* + ID_OUI_FROM_DATABASE=Pole/Zero Corporation + +OUI:00258B* + ID_OUI_FROM_DATABASE=Mellanox Technologies Ltd + +OUI:00258C* + ID_OUI_FROM_DATABASE=ESUS ELEKTRONIK SAN. VE DIS. TIC. LTD. STI. + +OUI:00258D* + ID_OUI_FROM_DATABASE=Haier + +OUI:00258E* + ID_OUI_FROM_DATABASE=The Weather Channel + +OUI:00258F* + ID_OUI_FROM_DATABASE=Trident Microsystems, Inc. + +OUI:002590* + ID_OUI_FROM_DATABASE=Super Micro Computer, Inc. + +OUI:002591* + ID_OUI_FROM_DATABASE=NEXTEK, Inc. + +OUI:002592* + ID_OUI_FROM_DATABASE=Guangzhou Shirui Electronic Co., Ltd + +OUI:002593* + ID_OUI_FROM_DATABASE=DatNet Informatikai Kft. + +OUI:002594* + ID_OUI_FROM_DATABASE=Eurodesign BG LTD + +OUI:002595* + ID_OUI_FROM_DATABASE=Northwest Signal Supply, Inc + +OUI:002596* + ID_OUI_FROM_DATABASE=GIGAVISION srl + +OUI:002597* + ID_OUI_FROM_DATABASE=Kalki Communication Technologies + +OUI:002598* + ID_OUI_FROM_DATABASE=Zhong Shan City Litai Electronic Industrial Co. Ltd + +OUI:002599* + ID_OUI_FROM_DATABASE=Hedon e.d. B.V. + +OUI:00259A* + ID_OUI_FROM_DATABASE=CEStronics GmbH + +OUI:00259B* + ID_OUI_FROM_DATABASE=Beijing PKUNITY Microsystems Technology Co., Ltd + +OUI:00259C* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:00259E* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd. + +OUI:00259F* + ID_OUI_FROM_DATABASE=TechnoDigital Technologies GmbH + +OUI:0025A0* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0025A1* + ID_OUI_FROM_DATABASE=Enalasys + +OUI:0025A2* + ID_OUI_FROM_DATABASE=Alta Definicion LINCEO S.L. + +OUI:0025A3* + ID_OUI_FROM_DATABASE=Trimax Wireless, Inc. + +OUI:0025A4* + ID_OUI_FROM_DATABASE=EuroDesign embedded technologies GmbH + +OUI:0025A5* + ID_OUI_FROM_DATABASE=Walnut Media Network + +OUI:0025A6* + ID_OUI_FROM_DATABASE=Central Network Solution Co., Ltd. + +OUI:0025A7* + ID_OUI_FROM_DATABASE=Comverge, Inc. + +OUI:0025A8* + ID_OUI_FROM_DATABASE=Kontron (BeiJing) Technology Co.,Ltd + +OUI:0025A9* + ID_OUI_FROM_DATABASE=Shanghai Embedway Information Technologies Co.,Ltd + +OUI:0025AA* + ID_OUI_FROM_DATABASE=Beijing Soul Technology Co.,Ltd. + +OUI:0025AB* + ID_OUI_FROM_DATABASE=AIO LCD PC BU / TPV + +OUI:0025AC* + ID_OUI_FROM_DATABASE=I-Tech corporation + +OUI:0025AD* + ID_OUI_FROM_DATABASE=Manufacturing Resources International + +OUI:0025AE* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:0025AF* + ID_OUI_FROM_DATABASE=COMFILE Technology + +OUI:0025B0* + ID_OUI_FROM_DATABASE=Schmartz Inc + +OUI:0025B1* + ID_OUI_FROM_DATABASE=Maya-Creation Corporation + +OUI:0025B2* + ID_OUI_FROM_DATABASE=MBDA Deutschland GmbH + +OUI:0025B3* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:0025B4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0025B5* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0025B6* + ID_OUI_FROM_DATABASE=Telecom FM + +OUI:0025B7* + ID_OUI_FROM_DATABASE=Costar electronics, inc., + +OUI:0025B8* + ID_OUI_FROM_DATABASE=Agile Communications, Inc. + +OUI:0025B9* + ID_OUI_FROM_DATABASE=Cypress Solutions Inc + +OUI:0025BA* + ID_OUI_FROM_DATABASE=Alcatel-Lucent IPD + +OUI:0025BB* + ID_OUI_FROM_DATABASE=INNERINT Co., Ltd. + +OUI:0025BC* + ID_OUI_FROM_DATABASE=Apple + +OUI:0025BD* + ID_OUI_FROM_DATABASE=Italdata Ingegneria dell'Idea S.p.A. + +OUI:0025BE* + ID_OUI_FROM_DATABASE=Tektrap Systems Inc. + +OUI:0025BF* + ID_OUI_FROM_DATABASE=Wireless Cables Inc. + +OUI:0025C0* + ID_OUI_FROM_DATABASE=ZillionTV Corporation + +OUI:0025C1* + ID_OUI_FROM_DATABASE=Nawoo Korea Corp. + +OUI:0025C2* + ID_OUI_FROM_DATABASE=RingBell Co.,Ltd. + +OUI:0025C3* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:0025C4* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:0025C5* + ID_OUI_FROM_DATABASE=Star Link Communication Pvt. Ltd. + +OUI:0025C6* + ID_OUI_FROM_DATABASE=kasercorp, ltd + +OUI:0025C7* + ID_OUI_FROM_DATABASE=altek Corporation + +OUI:0025C8* + ID_OUI_FROM_DATABASE=S-Access GmbH + +OUI:0025C9* + ID_OUI_FROM_DATABASE=SHENZHEN HUAPU DIGITAL CO., LTD + +OUI:0025CA* + ID_OUI_FROM_DATABASE=LS Research, LLC + +OUI:0025CB* + ID_OUI_FROM_DATABASE=Reiner SCT + +OUI:0025CC* + ID_OUI_FROM_DATABASE=Mobile Communications Korea Incorporated + +OUI:0025CD* + ID_OUI_FROM_DATABASE=Skylane Optics + +OUI:0025CE* + ID_OUI_FROM_DATABASE=InnerSpace + +OUI:0025CF* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0025D0* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0025D1* + ID_OUI_FROM_DATABASE=Eastern Asia Technology Limited + +OUI:0025D2* + ID_OUI_FROM_DATABASE=InpegVision Co., Ltd + +OUI:0025D3* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc + +OUI:0025D4* + ID_OUI_FROM_DATABASE=Fortress Technologies + +OUI:0025D5* + ID_OUI_FROM_DATABASE=Robonica (Pty) Ltd + +OUI:0025D6* + ID_OUI_FROM_DATABASE=The Kroger Co. + +OUI:0025D7* + ID_OUI_FROM_DATABASE=CEDO + +OUI:0025D8* + ID_OUI_FROM_DATABASE=KOREA MAINTENANCE + +OUI:0025D9* + ID_OUI_FROM_DATABASE=DataFab Systems Inc. + +OUI:0025DA* + ID_OUI_FROM_DATABASE=Secura Key + +OUI:0025DB* + ID_OUI_FROM_DATABASE=ATI Electronics(Shenzhen) Co., LTD + +OUI:0025DC* + ID_OUI_FROM_DATABASE=Sumitomo Electric Networks, Inc + +OUI:0025DD* + ID_OUI_FROM_DATABASE=SUNNYTEK INFORMATION CO., LTD. + +OUI:0025DE* + ID_OUI_FROM_DATABASE=Probits Co., LTD. + +OUI:0025E0* + ID_OUI_FROM_DATABASE=CeedTec Sdn Bhd + +OUI:0025E1* + ID_OUI_FROM_DATABASE=SHANGHAI SEEYOO ELECTRONIC & TECHNOLOGY CO., LTD + +OUI:0025E2* + ID_OUI_FROM_DATABASE=Everspring Industry Co., Ltd. + +OUI:0025E3* + ID_OUI_FROM_DATABASE=Hanshinit Inc. + +OUI:0025E4* + ID_OUI_FROM_DATABASE=OMNI-WiFi, LLC + +OUI:0025E5* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:0025E6* + ID_OUI_FROM_DATABASE=Belgian Monitoring Systems bvba + +OUI:0025E7* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:0025E8* + ID_OUI_FROM_DATABASE=Idaho Technology + +OUI:0025E9* + ID_OUI_FROM_DATABASE=i-mate Development, Inc. + +OUI:0025EA* + ID_OUI_FROM_DATABASE=Iphion BV + +OUI:0025EB* + ID_OUI_FROM_DATABASE=Reutech Radar Systems (PTY) Ltd + +OUI:0025EC* + ID_OUI_FROM_DATABASE=Humanware + +OUI:0025ED* + ID_OUI_FROM_DATABASE=NuVo Technologies LLC + +OUI:0025EE* + ID_OUI_FROM_DATABASE=Avtex Ltd + +OUI:0025EF* + ID_OUI_FROM_DATABASE=I-TEC Co., Ltd. + +OUI:0025F0* + ID_OUI_FROM_DATABASE=Suga Electronics Limited + +OUI:0025F1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0025F2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0025F3* + ID_OUI_FROM_DATABASE=Nordwestdeutsche Zählerrevision + +OUI:0025F4* + ID_OUI_FROM_DATABASE=KoCo Connector AG + +OUI:0025F5* + ID_OUI_FROM_DATABASE=DVS Korea, Co., Ltd + +OUI:0025F6* + ID_OUI_FROM_DATABASE=netTALK.com, Inc. + +OUI:0025F7* + ID_OUI_FROM_DATABASE=Ansaldo STS USA + +OUI:0025F9* + ID_OUI_FROM_DATABASE=GMK electronic design GmbH + +OUI:0025FA* + ID_OUI_FROM_DATABASE=J&M Analytik AG + +OUI:0025FB* + ID_OUI_FROM_DATABASE=Tunstall Healthcare A/S + +OUI:0025FC* + ID_OUI_FROM_DATABASE=ENDA ENDUSTRIYEL ELEKTRONIK LTD. STI. + +OUI:0025FD* + ID_OUI_FROM_DATABASE=OBR Centrum Techniki Morskiej S.A. + +OUI:0025FE* + ID_OUI_FROM_DATABASE=Pilot Electronics Corporation + +OUI:0025FF* + ID_OUI_FROM_DATABASE=CreNova Multimedia Co., Ltd + +OUI:002600* + ID_OUI_FROM_DATABASE=TEAC Australia Pty Ltd. + +OUI:002601* + ID_OUI_FROM_DATABASE=Cutera Inc + +OUI:002602* + ID_OUI_FROM_DATABASE=SMART Temps LLC + +OUI:002603* + ID_OUI_FROM_DATABASE=Shenzhen Wistar Technology Co., Ltd + +OUI:002604* + ID_OUI_FROM_DATABASE=Audio Processing Technology Ltd + +OUI:002605* + ID_OUI_FROM_DATABASE=CC Systems AB + +OUI:002606* + ID_OUI_FROM_DATABASE=RAUMFELD GmbH + +OUI:002607* + ID_OUI_FROM_DATABASE=Enabling Technology Pty Ltd + +OUI:002608* + ID_OUI_FROM_DATABASE=Apple + +OUI:002609* + ID_OUI_FROM_DATABASE=Phyllis Co., Ltd. + +OUI:00260A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00260B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00260C* + ID_OUI_FROM_DATABASE=Dataram + +OUI:00260D* + ID_OUI_FROM_DATABASE=Mercury Systems, Inc. + +OUI:00260E* + ID_OUI_FROM_DATABASE=Ablaze Systems, LLC + +OUI:00260F* + ID_OUI_FROM_DATABASE=Linn Products Ltd + +OUI:002610* + ID_OUI_FROM_DATABASE=Apacewave Technologies + +OUI:002611* + ID_OUI_FROM_DATABASE=Licera AB + +OUI:002612* + ID_OUI_FROM_DATABASE=Space Exploration Technologies + +OUI:002613* + ID_OUI_FROM_DATABASE=Engel Axil S.L. + +OUI:002614* + ID_OUI_FROM_DATABASE=KTNF + +OUI:002615* + ID_OUI_FROM_DATABASE=Teracom Limited + +OUI:002616* + ID_OUI_FROM_DATABASE=Rosemount Inc. + +OUI:002617* + ID_OUI_FROM_DATABASE=OEM Worldwide + +OUI:002618* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:002619* + ID_OUI_FROM_DATABASE=FRC + +OUI:00261A* + ID_OUI_FROM_DATABASE=Femtocomm System Technology Corp. + +OUI:00261B* + ID_OUI_FROM_DATABASE=LAUREL BANK MACHINES CO., LTD. + +OUI:00261C* + ID_OUI_FROM_DATABASE=NEOVIA INC. + +OUI:00261D* + ID_OUI_FROM_DATABASE=COP SECURITY SYSTEM CORP. + +OUI:00261E* + ID_OUI_FROM_DATABASE=QINGBANG ELEC(SZ) CO., LTD + +OUI:00261F* + ID_OUI_FROM_DATABASE=SAE Magnetics (H.K.) Ltd. + +OUI:002620* + ID_OUI_FROM_DATABASE=ISGUS GmbH + +OUI:002621* + ID_OUI_FROM_DATABASE=InteliCloud Technology Inc. + +OUI:002622* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:002623* + ID_OUI_FROM_DATABASE=JRD Communication Inc + +OUI:002624* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:002625* + ID_OUI_FROM_DATABASE=MediaSputnik + +OUI:002626* + ID_OUI_FROM_DATABASE=Geophysical Survey Systems, Inc. + +OUI:002627* + ID_OUI_FROM_DATABASE=Truesell + +OUI:002628* + ID_OUI_FROM_DATABASE=companytec automação e controle ltda. + +OUI:002629* + ID_OUI_FROM_DATABASE=Juphoon System Software Inc. + +OUI:00262A* + ID_OUI_FROM_DATABASE=Proxense, LLC + +OUI:00262B* + ID_OUI_FROM_DATABASE=Wongs Electronics Co. Ltd. + +OUI:00262C* + ID_OUI_FROM_DATABASE=IKT Advanced Technologies s.r.o. + +OUI:00262D* + ID_OUI_FROM_DATABASE=Wistron Corporation + +OUI:00262E* + ID_OUI_FROM_DATABASE=Chengdu Jiuzhou Electronic Technology Inc + +OUI:00262F* + ID_OUI_FROM_DATABASE=HAMAMATSU TOA ELECTRONICS + +OUI:002630* + ID_OUI_FROM_DATABASE=ACOREL S.A.S + +OUI:002631* + ID_OUI_FROM_DATABASE=COMMTACT LTD + +OUI:002632* + ID_OUI_FROM_DATABASE=Instrumentation Technologies d.d. + +OUI:002633* + ID_OUI_FROM_DATABASE=MIR - Medical International Research + +OUI:002634* + ID_OUI_FROM_DATABASE=Infineta Systems, Inc + +OUI:002635* + ID_OUI_FROM_DATABASE=Bluetechnix GmbH + +OUI:002636* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002637* + ID_OUI_FROM_DATABASE=Samsung Electro-Mechanics + +OUI:002638* + ID_OUI_FROM_DATABASE=Xia Men Joyatech Co., Ltd. + +OUI:002639* + ID_OUI_FROM_DATABASE=T.M. Electronics, Inc. + +OUI:00263A* + ID_OUI_FROM_DATABASE=Digitec Systems + +OUI:00263B* + ID_OUI_FROM_DATABASE=Onbnetech + +OUI:00263C* + ID_OUI_FROM_DATABASE=Bachmann Technology GmbH & Co. KG + +OUI:00263D* + ID_OUI_FROM_DATABASE=MIA Corporation + +OUI:00263E* + ID_OUI_FROM_DATABASE=Trapeze Networks + +OUI:00263F* + ID_OUI_FROM_DATABASE=LIOS Technology GmbH + +OUI:002640* + ID_OUI_FROM_DATABASE=Baustem Broadband Technologies, Ltd. + +OUI:002641* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002642* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002643* + ID_OUI_FROM_DATABASE=Alps Electric Co., Ltd + +OUI:002644* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:002645* + ID_OUI_FROM_DATABASE=Circontrol S.A. + +OUI:002646* + ID_OUI_FROM_DATABASE=SHENYANG TONGFANG MULTIMEDIA TECHNOLOGY COMPANY LIMITED + +OUI:002647* + ID_OUI_FROM_DATABASE=WFE TECHNOLOGY CORP. + +OUI:002648* + ID_OUI_FROM_DATABASE=Emitech Corp. + +OUI:00264A* + ID_OUI_FROM_DATABASE=Apple + +OUI:00264C* + ID_OUI_FROM_DATABASE=Shanghai DigiVision Technology Co., Ltd. + +OUI:00264D* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:00264E* + ID_OUI_FROM_DATABASE=Rail & Road Protec GmbH + +OUI:00264F* + ID_OUI_FROM_DATABASE=Krüger &Gothe GmbH + +OUI:002650* + ID_OUI_FROM_DATABASE=2Wire + +OUI:002651* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002652* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002653* + ID_OUI_FROM_DATABASE=DaySequerra Corporation + +OUI:002654* + ID_OUI_FROM_DATABASE=3Com Corporation + +OUI:002655* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:002656* + ID_OUI_FROM_DATABASE=Sansonic Electronics USA + +OUI:002657* + ID_OUI_FROM_DATABASE=OOO NPP EKRA + +OUI:002658* + ID_OUI_FROM_DATABASE=T-Platforms (Cyprus) Limited + +OUI:002659* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:00265A* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:00265B* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:00265C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:00265D* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:00265E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:00265F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:002660* + ID_OUI_FROM_DATABASE=Logiways + +OUI:002661* + ID_OUI_FROM_DATABASE=Irumtek Co., Ltd. + +OUI:002662* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:002663* + ID_OUI_FROM_DATABASE=Shenzhen Huitaiwei Tech. Ltd, co. + +OUI:002664* + ID_OUI_FROM_DATABASE=Core System Japan + +OUI:002665* + ID_OUI_FROM_DATABASE=ProtectedLogic Corporation + +OUI:002666* + ID_OUI_FROM_DATABASE=EFM Networks + +OUI:002667* + ID_OUI_FROM_DATABASE=CARECOM CO.,LTD. + +OUI:002668* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002669* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00266A* + ID_OUI_FROM_DATABASE=ESSENSIUM NV + +OUI:00266B* + ID_OUI_FROM_DATABASE=SHINE UNION ENTERPRISE LIMITED + +OUI:00266C* + ID_OUI_FROM_DATABASE=Inventec + +OUI:00266D* + ID_OUI_FROM_DATABASE=MobileAccess Networks + +OUI:00266E* + ID_OUI_FROM_DATABASE=Nissho-denki Co.,LTD. + +OUI:00266F* + ID_OUI_FROM_DATABASE=Coordiwise Technology Corp. + +OUI:002670* + ID_OUI_FROM_DATABASE=Cinch Connectors + +OUI:002671* + ID_OUI_FROM_DATABASE=AUTOVISION Co., Ltd + +OUI:002672* + ID_OUI_FROM_DATABASE=AAMP of America + +OUI:002673* + ID_OUI_FROM_DATABASE=RICOH COMPANY,LTD. + +OUI:002674* + ID_OUI_FROM_DATABASE=Electronic Solutions, Inc. + +OUI:002675* + ID_OUI_FROM_DATABASE=Aztech Electronics Pte Ltd + +OUI:002676* + ID_OUI_FROM_DATABASE=COMMidt AS + +OUI:002677* + ID_OUI_FROM_DATABASE=DEIF A/S + +OUI:002678* + ID_OUI_FROM_DATABASE=Logic Instrument SA + +OUI:002679* + ID_OUI_FROM_DATABASE=Euphonic Technologies, Inc. + +OUI:00267A* + ID_OUI_FROM_DATABASE=wuhan hongxin telecommunication technologies co.,ltd + +OUI:00267B* + ID_OUI_FROM_DATABASE=GSI Helmholtzzentrum für Schwerionenforschung GmbH + +OUI:00267C* + ID_OUI_FROM_DATABASE=Metz-Werke GmbH & Co KG + +OUI:00267D* + ID_OUI_FROM_DATABASE=A-Max Technology Macao Commercial Offshore Company Limited + +OUI:00267E* + ID_OUI_FROM_DATABASE=Parrot SA + +OUI:00267F* + ID_OUI_FROM_DATABASE=Zenterio AB + +OUI:002680* + ID_OUI_FROM_DATABASE=Lockie Innovation Pty Ltd + +OUI:002681* + ID_OUI_FROM_DATABASE=Interspiro AB + +OUI:002682* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:002683* + ID_OUI_FROM_DATABASE=Ajoho Enterprise Co., Ltd. + +OUI:002684* + ID_OUI_FROM_DATABASE=KISAN SYSTEM + +OUI:002685* + ID_OUI_FROM_DATABASE=Digital Innovation + +OUI:002686* + ID_OUI_FROM_DATABASE=Quantenna Communcations, Inc. + +OUI:002687* + ID_OUI_FROM_DATABASE=ALLIED TELESIS, K.K corega division. + +OUI:002688* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:002689* + ID_OUI_FROM_DATABASE=General Dynamics Robotic Systems + +OUI:00268A* + ID_OUI_FROM_DATABASE=Terrier SC Ltd + +OUI:00268B* + ID_OUI_FROM_DATABASE=Guangzhou Escene Computer Technology Limited + +OUI:00268C* + ID_OUI_FROM_DATABASE=StarLeaf Ltd. + +OUI:00268D* + ID_OUI_FROM_DATABASE=CellTel S.p.A. + +OUI:00268E* + ID_OUI_FROM_DATABASE=Alta Solutions, Inc. + +OUI:00268F* + ID_OUI_FROM_DATABASE=MTA SpA + +OUI:002690* + ID_OUI_FROM_DATABASE=I DO IT + +OUI:002691* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:002692* + ID_OUI_FROM_DATABASE=Mitsubishi Electric Co. + +OUI:002693* + ID_OUI_FROM_DATABASE=QVidium Technologies, Inc. + +OUI:002694* + ID_OUI_FROM_DATABASE=Senscient Ltd + +OUI:002695* + ID_OUI_FROM_DATABASE=ZT Group Int'l Inc + +OUI:002696* + ID_OUI_FROM_DATABASE=NOOLIX Co., Ltd + +OUI:002697* + ID_OUI_FROM_DATABASE=Cheetah Technologies, L.P. + +OUI:002698* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002699* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00269A* + ID_OUI_FROM_DATABASE=Carina System Co., Ltd. + +OUI:00269B* + ID_OUI_FROM_DATABASE=SOKRAT Ltd. + +OUI:00269C* + ID_OUI_FROM_DATABASE=ITUS JAPAN CO. LTD + +OUI:00269D* + ID_OUI_FROM_DATABASE=M2Mnet Co., Ltd. + +OUI:00269E* + ID_OUI_FROM_DATABASE=Quanta Computer Inc + +OUI:0026A0* + ID_OUI_FROM_DATABASE=moblic + +OUI:0026A1* + ID_OUI_FROM_DATABASE=Megger + +OUI:0026A2* + ID_OUI_FROM_DATABASE=Instrumentation Technology Systems + +OUI:0026A3* + ID_OUI_FROM_DATABASE=FQ Ingenieria Electronica S.A. + +OUI:0026A4* + ID_OUI_FROM_DATABASE=Novus Produtos Eletronicos Ltda + +OUI:0026A5* + ID_OUI_FROM_DATABASE=MICROROBOT.CO.,LTD + +OUI:0026A6* + ID_OUI_FROM_DATABASE=TRIXELL + +OUI:0026A7* + ID_OUI_FROM_DATABASE=CONNECT SRL + +OUI:0026A8* + ID_OUI_FROM_DATABASE=DAEHAP HYPER-TECH + +OUI:0026A9* + ID_OUI_FROM_DATABASE=Strong Technologies Pty Ltd + +OUI:0026AA* + ID_OUI_FROM_DATABASE=Kenmec Mechanical Engineering Co., Ltd. + +OUI:0026AB* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:0026AC* + ID_OUI_FROM_DATABASE=Shanghai LUSTER Teraband photonic Co., Ltd. + +OUI:0026AD* + ID_OUI_FROM_DATABASE=Arada Systems, Inc. + +OUI:0026AE* + ID_OUI_FROM_DATABASE=Wireless Measurement Ltd + +OUI:0026AF* + ID_OUI_FROM_DATABASE=Duelco A/S + +OUI:0026B0* + ID_OUI_FROM_DATABASE=Apple + +OUI:0026B1* + ID_OUI_FROM_DATABASE=Navis Auto Motive Systems, Inc. + +OUI:0026B2* + ID_OUI_FROM_DATABASE=Setrix GmbH + +OUI:0026B3* + ID_OUI_FROM_DATABASE=Thales Communications Inc + +OUI:0026B4* + ID_OUI_FROM_DATABASE=Ford Motor Company + +OUI:0026B5* + ID_OUI_FROM_DATABASE=ICOMM Tele Ltd + +OUI:0026B6* + ID_OUI_FROM_DATABASE=Askey Computer + +OUI:0026B7* + ID_OUI_FROM_DATABASE=Kingston Technology Company, Inc. + +OUI:0026B8* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:0026B9* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:0026BA* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0026BB* + ID_OUI_FROM_DATABASE=Apple + +OUI:0026BC* + ID_OUI_FROM_DATABASE=General Jack Technology Ltd. + +OUI:0026BD* + ID_OUI_FROM_DATABASE=JTEC Card & Communication Co., Ltd. + +OUI:0026BE* + ID_OUI_FROM_DATABASE=Schoonderbeek Elektronica Systemen B.V. + +OUI:0026BF* + ID_OUI_FROM_DATABASE=ShenZhen Temobi Science&Tech Development Co.,Ltd + +OUI:0026C0* + ID_OUI_FROM_DATABASE=EnergyHub + +OUI:0026C1* + ID_OUI_FROM_DATABASE=ARTRAY CO., LTD. + +OUI:0026C2* + ID_OUI_FROM_DATABASE=SCDI Co. LTD + +OUI:0026C3* + ID_OUI_FROM_DATABASE=Insightek Corp. + +OUI:0026C4* + ID_OUI_FROM_DATABASE=Cadmos microsystems S.r.l. + +OUI:0026C5* + ID_OUI_FROM_DATABASE=Guangdong Gosun Telecommunications Co.,Ltd + +OUI:0026C6* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0026C7* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0026C8* + ID_OUI_FROM_DATABASE=System Sensor + +OUI:0026C9* + ID_OUI_FROM_DATABASE=Proventix Systems, Inc. + +OUI:0026CA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0026CB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0026CC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0026CD* + ID_OUI_FROM_DATABASE=PurpleComm, Inc. + +OUI:0026CE* + ID_OUI_FROM_DATABASE=Kozumi USA Corp. + +OUI:0026CF* + ID_OUI_FROM_DATABASE=DEKA R&D + +OUI:0026D0* + ID_OUI_FROM_DATABASE=Semihalf + +OUI:0026D1* + ID_OUI_FROM_DATABASE=S Squared Innovations Inc. + +OUI:0026D2* + ID_OUI_FROM_DATABASE=Pcube Systems, Inc. + +OUI:0026D3* + ID_OUI_FROM_DATABASE=Zeno Information System + +OUI:0026D4* + ID_OUI_FROM_DATABASE=IRCA SpA + +OUI:0026D5* + ID_OUI_FROM_DATABASE=Ory Solucoes em Comercio de Informatica Ltda. + +OUI:0026D6* + ID_OUI_FROM_DATABASE=Ningbo Andy Optoelectronic Co., Ltd. + +OUI:0026D7* + ID_OUI_FROM_DATABASE=KM Electornic Technology Co., Ltd. + +OUI:0026D8* + ID_OUI_FROM_DATABASE=Magic Point Inc. + +OUI:0026D9* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:0026DA* + ID_OUI_FROM_DATABASE=Universal Media Corporation /Slovakia/ s.r.o. + +OUI:0026DB* + ID_OUI_FROM_DATABASE=Ionics EMS Inc. + +OUI:0026DC* + ID_OUI_FROM_DATABASE=Optical Systems Design + +OUI:0026DD* + ID_OUI_FROM_DATABASE=Fival Science & Technology Co.,Ltd. + +OUI:0026DE* + ID_OUI_FROM_DATABASE=FDI MATELEC + +OUI:0026DF* + ID_OUI_FROM_DATABASE=TaiDoc Technology Corp. + +OUI:0026E0* + ID_OUI_FROM_DATABASE=ASITEQ + +OUI:0026E1* + ID_OUI_FROM_DATABASE=Stanford University, OpenFlow Group + +OUI:0026E2* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:0026E3* + ID_OUI_FROM_DATABASE=DTI + +OUI:0026E4* + ID_OUI_FROM_DATABASE=CANAL OVERSEAS + +OUI:0026E5* + ID_OUI_FROM_DATABASE=AEG Power Solutions + +OUI:0026E6* + ID_OUI_FROM_DATABASE=Visionhitech Co., Ltd. + +OUI:0026E7* + ID_OUI_FROM_DATABASE=Shanghai ONLAN Communication Tech. Co., Ltd. + +OUI:0026E8* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:0026E9* + ID_OUI_FROM_DATABASE=SP Corp + +OUI:0026EA* + ID_OUI_FROM_DATABASE=Cheerchip Electronic Technology (ShangHai) Co., Ltd. + +OUI:0026EB* + ID_OUI_FROM_DATABASE=Advanced Spectrum Technology Co., Ltd. + +OUI:0026EC* + ID_OUI_FROM_DATABASE=Legrand Home Systems, Inc + +OUI:0026ED* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:0026EE* + ID_OUI_FROM_DATABASE=TKM GmbH + +OUI:0026EF* + ID_OUI_FROM_DATABASE=Technology Advancement Group, Inc. + +OUI:0026F0* + ID_OUI_FROM_DATABASE=cTrixs International GmbH. + +OUI:0026F1* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:0026F2* + ID_OUI_FROM_DATABASE=Netgear + +OUI:0026F3* + ID_OUI_FROM_DATABASE=SMC Networks + +OUI:0026F4* + ID_OUI_FROM_DATABASE=Nesslab + +OUI:0026F5* + ID_OUI_FROM_DATABASE=XRPLUS Inc. + +OUI:0026F6* + ID_OUI_FROM_DATABASE=Military Communication Institute + +OUI:0026F7* + ID_OUI_FROM_DATABASE=Infosys Technologies Ltd. + +OUI:0026F8* + ID_OUI_FROM_DATABASE=Golden Highway Industry Development Co., Ltd. + +OUI:0026F9* + ID_OUI_FROM_DATABASE=S.E.M. srl + +OUI:0026FA* + ID_OUI_FROM_DATABASE=BandRich Inc. + +OUI:0026FB* + ID_OUI_FROM_DATABASE=AirDio Wireless, Inc. + +OUI:0026FC* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:0026FD* + ID_OUI_FROM_DATABASE=Interactive Intelligence + +OUI:0026FE* + ID_OUI_FROM_DATABASE=MKD Technology Inc. + +OUI:0026FF* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:002700* + ID_OUI_FROM_DATABASE=Shenzhen Siglent Technology Co., Ltd. + +OUI:002701* + ID_OUI_FROM_DATABASE=INCOstartec GmbH + +OUI:002702* + ID_OUI_FROM_DATABASE=SolarEdge Technologies + +OUI:002703* + ID_OUI_FROM_DATABASE=Testech Electronics Pte Ltd + +OUI:002704* + ID_OUI_FROM_DATABASE=Accelerated Concepts, Inc + +OUI:002705* + ID_OUI_FROM_DATABASE=Sectronic + +OUI:002706* + ID_OUI_FROM_DATABASE=YOISYS + +OUI:002707* + ID_OUI_FROM_DATABASE=Lift Complex DS, JSC + +OUI:002708* + ID_OUI_FROM_DATABASE=Nordiag ASA + +OUI:002709* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:00270A* + ID_OUI_FROM_DATABASE=IEE S.A. + +OUI:00270B* + ID_OUI_FROM_DATABASE=Adura Technologies + +OUI:00270C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00270D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00270E* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00270F* + ID_OUI_FROM_DATABASE=Envisionnovation Inc + +OUI:002710* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:002711* + ID_OUI_FROM_DATABASE=LanPro Inc + +OUI:002712* + ID_OUI_FROM_DATABASE=MaxVision LLC + +OUI:002713* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:002714* + ID_OUI_FROM_DATABASE=Grainmustards, Co,ltd. + +OUI:002715* + ID_OUI_FROM_DATABASE=Rebound Telecom. Co., Ltd + +OUI:002716* + ID_OUI_FROM_DATABASE=Adachi-Syokai Co., Ltd. + +OUI:002717* + ID_OUI_FROM_DATABASE=CE Digital(Zhenjiang)Co.,Ltd + +OUI:002718* + ID_OUI_FROM_DATABASE=Suzhou NEW SEAUNION Video Technology Co.,Ltd + +OUI:002719* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:00271A* + ID_OUI_FROM_DATABASE=Geenovo Technology Ltd. + +OUI:00271B* + ID_OUI_FROM_DATABASE=Alec Sicherheitssysteme GmbH + +OUI:00271C* + ID_OUI_FROM_DATABASE=MERCURY CORPORATION + +OUI:00271D* + ID_OUI_FROM_DATABASE=Comba Telecom Systems (China) Ltd. + +OUI:00271E* + ID_OUI_FROM_DATABASE=Xagyl Communications + +OUI:00271F* + ID_OUI_FROM_DATABASE=MIPRO Electronics Co., Ltd + +OUI:002720* + ID_OUI_FROM_DATABASE=NEW-SOL COM + +OUI:002721* + ID_OUI_FROM_DATABASE=Shenzhen Baoan Fenda Industrial Co., Ltd + +OUI:002722* + ID_OUI_FROM_DATABASE=Ubiquiti Networks + +OUI:0027F8* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:002A6A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:002AAF* + ID_OUI_FROM_DATABASE=LARsys-Automation GmbH + +OUI:002D76* + ID_OUI_FROM_DATABASE=TITECH GmbH + +OUI:003000* + ID_OUI_FROM_DATABASE=ALLWELL TECHNOLOGY CORP. + +OUI:003001* + ID_OUI_FROM_DATABASE=SMP + +OUI:003002* + ID_OUI_FROM_DATABASE=Expand Networks + +OUI:003003* + ID_OUI_FROM_DATABASE=Phasys Ltd. + +OUI:003004* + ID_OUI_FROM_DATABASE=LEADTEK RESEARCH INC. + +OUI:003005* + ID_OUI_FROM_DATABASE=Fujitsu Siemens Computers + +OUI:003006* + ID_OUI_FROM_DATABASE=SUPERPOWER COMPUTER + +OUI:003007* + ID_OUI_FROM_DATABASE=OPTI, INC. + +OUI:003008* + ID_OUI_FROM_DATABASE=AVIO DIGITAL, INC. + +OUI:003009* + ID_OUI_FROM_DATABASE=Tachion Networks, Inc. + +OUI:00300A* + ID_OUI_FROM_DATABASE=AZTECH Electronics Pte Ltd + +OUI:00300B* + ID_OUI_FROM_DATABASE=mPHASE Technologies, Inc. + +OUI:00300C* + ID_OUI_FROM_DATABASE=CONGRUENCY, LTD. + +OUI:00300D* + ID_OUI_FROM_DATABASE=MMC Technology, Inc. + +OUI:00300E* + ID_OUI_FROM_DATABASE=Klotz Digital AG + +OUI:00300F* + ID_OUI_FROM_DATABASE=IMT - Information Management T + +OUI:003010* + ID_OUI_FROM_DATABASE=VISIONETICS INTERNATIONAL + +OUI:003011* + ID_OUI_FROM_DATABASE=HMS Industrial Networks + +OUI:003012* + ID_OUI_FROM_DATABASE=DIGITAL ENGINEERING LTD. + +OUI:003013* + ID_OUI_FROM_DATABASE=NEC Corporation + +OUI:003014* + ID_OUI_FROM_DATABASE=DIVIO, INC. + +OUI:003015* + ID_OUI_FROM_DATABASE=CP CLARE CORP. + +OUI:003016* + ID_OUI_FROM_DATABASE=ISHIDA CO., LTD. + +OUI:003017* + ID_OUI_FROM_DATABASE=BlueArc UK Ltd + +OUI:003018* + ID_OUI_FROM_DATABASE=Jetway Information Co., Ltd. + +OUI:003019* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00301A* + ID_OUI_FROM_DATABASE=SMARTBRIDGES PTE. LTD. + +OUI:00301B* + ID_OUI_FROM_DATABASE=SHUTTLE, INC. + +OUI:00301C* + ID_OUI_FROM_DATABASE=ALTVATER AIRDATA SYSTEMS + +OUI:00301D* + ID_OUI_FROM_DATABASE=SKYSTREAM, INC. + +OUI:00301E* + ID_OUI_FROM_DATABASE=3COM Europe Ltd. + +OUI:00301F* + ID_OUI_FROM_DATABASE=OPTICAL NETWORKS, INC. + +OUI:003020* + ID_OUI_FROM_DATABASE=TSI, Inc.. + +OUI:003021* + ID_OUI_FROM_DATABASE=HSING TECH. ENTERPRISE CO.,LTD + +OUI:003022* + ID_OUI_FROM_DATABASE=Fong Kai Industrial Co., Ltd. + +OUI:003023* + ID_OUI_FROM_DATABASE=COGENT COMPUTER SYSTEMS, INC. + +OUI:003024* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003025* + ID_OUI_FROM_DATABASE=CHECKOUT COMPUTER SYSTEMS, LTD + +OUI:003026* + ID_OUI_FROM_DATABASE=HeiTel Digital Video GmbH + +OUI:003027* + ID_OUI_FROM_DATABASE=KERBANGO, INC. + +OUI:003028* + ID_OUI_FROM_DATABASE=FASE Saldatura srl + +OUI:003029* + ID_OUI_FROM_DATABASE=OPICOM + +OUI:00302A* + ID_OUI_FROM_DATABASE=SOUTHERN INFORMATION + +OUI:00302B* + ID_OUI_FROM_DATABASE=INALP NETWORKS, INC. + +OUI:00302C* + ID_OUI_FROM_DATABASE=SYLANTRO SYSTEMS CORPORATION + +OUI:00302D* + ID_OUI_FROM_DATABASE=QUANTUM BRIDGE COMMUNICATIONS + +OUI:00302E* + ID_OUI_FROM_DATABASE=Hoft & Wessel AG + +OUI:00302F* + ID_OUI_FROM_DATABASE=GE Aviation System + +OUI:003030* + ID_OUI_FROM_DATABASE=HARMONIX CORPORATION + +OUI:003031* + ID_OUI_FROM_DATABASE=LIGHTWAVE COMMUNICATIONS, INC. + +OUI:003032* + ID_OUI_FROM_DATABASE=MagicRam, Inc. + +OUI:003033* + ID_OUI_FROM_DATABASE=ORIENT TELECOM CO., LTD. + +OUI:003034* + ID_OUI_FROM_DATABASE=SET ENGINEERING + +OUI:003035* + ID_OUI_FROM_DATABASE=Corning Incorporated + +OUI:003036* + ID_OUI_FROM_DATABASE=RMP ELEKTRONIKSYSTEME GMBH + +OUI:003037* + ID_OUI_FROM_DATABASE=Packard Bell Nec Services + +OUI:003038* + ID_OUI_FROM_DATABASE=XCP, INC. + +OUI:003039* + ID_OUI_FROM_DATABASE=SOFTBOOK PRESS + +OUI:00303A* + ID_OUI_FROM_DATABASE=MAATEL + +OUI:00303B* + ID_OUI_FROM_DATABASE=PowerCom Technology + +OUI:00303C* + ID_OUI_FROM_DATABASE=ONNTO CORP. + +OUI:00303D* + ID_OUI_FROM_DATABASE=IVA CORPORATION + +OUI:00303E* + ID_OUI_FROM_DATABASE=Radcom Ltd. + +OUI:00303F* + ID_OUI_FROM_DATABASE=TurboComm Tech Inc. + +OUI:003040* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003041* + ID_OUI_FROM_DATABASE=SAEJIN T & M CO., LTD. + +OUI:003042* + ID_OUI_FROM_DATABASE=DeTeWe-Deutsche Telephonwerke + +OUI:003043* + ID_OUI_FROM_DATABASE=IDREAM TECHNOLOGIES, PTE. LTD. + +OUI:003044* + ID_OUI_FROM_DATABASE=CradlePoint, Inc + +OUI:003045* + ID_OUI_FROM_DATABASE=Village Networks, Inc. (VNI) + +OUI:003046* + ID_OUI_FROM_DATABASE=Controlled Electronic Manageme + +OUI:003047* + ID_OUI_FROM_DATABASE=NISSEI ELECTRIC CO., LTD. + +OUI:003048* + ID_OUI_FROM_DATABASE=Supermicro Computer, Inc. + +OUI:003049* + ID_OUI_FROM_DATABASE=BRYANT TECHNOLOGY, LTD. + +OUI:00304A* + ID_OUI_FROM_DATABASE=Fraunhofer IPMS + +OUI:00304B* + ID_OUI_FROM_DATABASE=ORBACOM SYSTEMS, INC. + +OUI:00304C* + ID_OUI_FROM_DATABASE=APPIAN COMMUNICATIONS, INC. + +OUI:00304D* + ID_OUI_FROM_DATABASE=ESI + +OUI:00304E* + ID_OUI_FROM_DATABASE=BUSTEC PRODUCTION LTD. + +OUI:00304F* + ID_OUI_FROM_DATABASE=PLANET Technology Corporation + +OUI:003050* + ID_OUI_FROM_DATABASE=Versa Technology + +OUI:003051* + ID_OUI_FROM_DATABASE=ORBIT AVIONIC & COMMUNICATION + +OUI:003052* + ID_OUI_FROM_DATABASE=ELASTIC NETWORKS + +OUI:003053* + ID_OUI_FROM_DATABASE=Basler AG + +OUI:003054* + ID_OUI_FROM_DATABASE=CASTLENET TECHNOLOGY, INC. + +OUI:003055* + ID_OUI_FROM_DATABASE=Renesas Technology America, Inc. + +OUI:003056* + ID_OUI_FROM_DATABASE=Beck IPC GmbH + +OUI:003057* + ID_OUI_FROM_DATABASE=QTelNet, Inc. + +OUI:003058* + ID_OUI_FROM_DATABASE=API MOTION + +OUI:003059* + ID_OUI_FROM_DATABASE=KONTRON COMPACT COMPUTERS AG + +OUI:00305A* + ID_OUI_FROM_DATABASE=TELGEN CORPORATION + +OUI:00305B* + ID_OUI_FROM_DATABASE=Toko Inc. + +OUI:00305C* + ID_OUI_FROM_DATABASE=SMAR Laboratories Corp. + +OUI:00305D* + ID_OUI_FROM_DATABASE=DIGITRA SYSTEMS, INC. + +OUI:00305E* + ID_OUI_FROM_DATABASE=Abelko Innovation + +OUI:00305F* + ID_OUI_FROM_DATABASE=Hasselblad + +OUI:003060* + ID_OUI_FROM_DATABASE=Powerfile, Inc. + +OUI:003061* + ID_OUI_FROM_DATABASE=MobyTEL + +OUI:003062* + ID_OUI_FROM_DATABASE=IP Video Networks Inc + +OUI:003063* + ID_OUI_FROM_DATABASE=SANTERA SYSTEMS, INC. + +OUI:003064* + ID_OUI_FROM_DATABASE=ADLINK TECHNOLOGY, INC. + +OUI:003065* + ID_OUI_FROM_DATABASE=Apple + +OUI:003066* + ID_OUI_FROM_DATABASE=RFM + +OUI:003067* + ID_OUI_FROM_DATABASE=BIOSTAR MICROTECH INT'L CORP. + +OUI:003068* + ID_OUI_FROM_DATABASE=CYBERNETICS TECH. CO., LTD. + +OUI:003069* + ID_OUI_FROM_DATABASE=IMPACCT TECHNOLOGY CORP. + +OUI:00306A* + ID_OUI_FROM_DATABASE=PENTA MEDIA CO., LTD. + +OUI:00306B* + ID_OUI_FROM_DATABASE=CMOS SYSTEMS, INC. + +OUI:00306C* + ID_OUI_FROM_DATABASE=Hitex Holding GmbH + +OUI:00306D* + ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES + +OUI:00306E* + ID_OUI_FROM_DATABASE=HEWLETT PACKARD + +OUI:00306F* + ID_OUI_FROM_DATABASE=SEYEON TECH. CO., LTD. + +OUI:003070* + ID_OUI_FROM_DATABASE=1Net Corporation + +OUI:003071* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003072* + ID_OUI_FROM_DATABASE=Intellibyte Inc. + +OUI:003073* + ID_OUI_FROM_DATABASE=International Microsystems, In + +OUI:003074* + ID_OUI_FROM_DATABASE=EQUIINET LTD. + +OUI:003075* + ID_OUI_FROM_DATABASE=ADTECH + +OUI:003076* + ID_OUI_FROM_DATABASE=Akamba Corporation + +OUI:003077* + ID_OUI_FROM_DATABASE=ONPREM NETWORKS + +OUI:003078* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003079* + ID_OUI_FROM_DATABASE=CQOS, INC. + +OUI:00307A* + ID_OUI_FROM_DATABASE=Advanced Technology & Systems + +OUI:00307B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00307C* + ID_OUI_FROM_DATABASE=ADID SA + +OUI:00307D* + ID_OUI_FROM_DATABASE=GRE AMERICA, INC. + +OUI:00307E* + ID_OUI_FROM_DATABASE=Redflex Communication Systems + +OUI:00307F* + ID_OUI_FROM_DATABASE=IRLAN LTD. + +OUI:003080* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003081* + ID_OUI_FROM_DATABASE=ALTOS C&C + +OUI:003082* + ID_OUI_FROM_DATABASE=TAIHAN ELECTRIC WIRE CO., LTD. + +OUI:003083* + ID_OUI_FROM_DATABASE=Ivron Systems + +OUI:003084* + ID_OUI_FROM_DATABASE=ALLIED TELESYN INTERNAIONAL + +OUI:003085* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003086* + ID_OUI_FROM_DATABASE=Transistor Devices, Inc. + +OUI:003087* + ID_OUI_FROM_DATABASE=VEGA GRIESHABER KG + +OUI:003088* + ID_OUI_FROM_DATABASE=Ericsson + +OUI:003089* + ID_OUI_FROM_DATABASE=Spectrapoint Wireless, LLC + +OUI:00308A* + ID_OUI_FROM_DATABASE=NICOTRA SISTEMI S.P.A + +OUI:00308B* + ID_OUI_FROM_DATABASE=Brix Networks + +OUI:00308C* + ID_OUI_FROM_DATABASE=Quantum Corporation + +OUI:00308D* + ID_OUI_FROM_DATABASE=Pinnacle Systems, Inc. + +OUI:00308E* + ID_OUI_FROM_DATABASE=CROSS MATCH TECHNOLOGIES, INC. + +OUI:00308F* + ID_OUI_FROM_DATABASE=MICRILOR, Inc. + +OUI:003090* + ID_OUI_FROM_DATABASE=CYRA TECHNOLOGIES, INC. + +OUI:003091* + ID_OUI_FROM_DATABASE=TAIWAN FIRST LINE ELEC. CORP. + +OUI:003092* + ID_OUI_FROM_DATABASE=ModuNORM GmbH + +OUI:003093* + ID_OUI_FROM_DATABASE=Sonnet Technologies, Inc + +OUI:003094* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003095* + ID_OUI_FROM_DATABASE=Procomp Informatics, Ltd. + +OUI:003096* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003097* + ID_OUI_FROM_DATABASE=AB Regin + +OUI:003098* + ID_OUI_FROM_DATABASE=Global Converging Technologies + +OUI:003099* + ID_OUI_FROM_DATABASE=BOENIG UND KALLENBACH OHG + +OUI:00309A* + ID_OUI_FROM_DATABASE=ASTRO TERRA CORP. + +OUI:00309B* + ID_OUI_FROM_DATABASE=Smartware + +OUI:00309C* + ID_OUI_FROM_DATABASE=Timing Applications, Inc. + +OUI:00309D* + ID_OUI_FROM_DATABASE=Nimble Microsystems, Inc. + +OUI:00309E* + ID_OUI_FROM_DATABASE=WORKBIT CORPORATION. + +OUI:00309F* + ID_OUI_FROM_DATABASE=AMBER NETWORKS + +OUI:0030A0* + ID_OUI_FROM_DATABASE=TYCO SUBMARINE SYSTEMS, LTD. + +OUI:0030A1* + ID_OUI_FROM_DATABASE=WEBGATE Inc. + +OUI:0030A2* + ID_OUI_FROM_DATABASE=Lightner Engineering + +OUI:0030A3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0030A4* + ID_OUI_FROM_DATABASE=Woodwind Communications System + +OUI:0030A5* + ID_OUI_FROM_DATABASE=ACTIVE POWER + +OUI:0030A6* + ID_OUI_FROM_DATABASE=VIANET TECHNOLOGIES, LTD. + +OUI:0030A7* + ID_OUI_FROM_DATABASE=SCHWEITZER ENGINEERING + +OUI:0030A8* + ID_OUI_FROM_DATABASE=OL'E COMMUNICATIONS, INC. + +OUI:0030A9* + ID_OUI_FROM_DATABASE=Netiverse, Inc. + +OUI:0030AA* + ID_OUI_FROM_DATABASE=AXUS MICROSYSTEMS, INC. + +OUI:0030AB* + ID_OUI_FROM_DATABASE=DELTA NETWORKS, INC. + +OUI:0030AC* + ID_OUI_FROM_DATABASE=Systeme Lauer GmbH & Co., Ltd. + +OUI:0030AD* + ID_OUI_FROM_DATABASE=SHANGHAI COMMUNICATION + +OUI:0030AE* + ID_OUI_FROM_DATABASE=Times N System, Inc. + +OUI:0030AF* + ID_OUI_FROM_DATABASE=Honeywell GmbH + +OUI:0030B0* + ID_OUI_FROM_DATABASE=Convergenet Technologies + +OUI:0030B1* + ID_OUI_FROM_DATABASE=TrunkNet + +OUI:0030B2* + ID_OUI_FROM_DATABASE=L-3 Sonoma EO + +OUI:0030B3* + ID_OUI_FROM_DATABASE=San Valley Systems, Inc. + +OUI:0030B4* + ID_OUI_FROM_DATABASE=INTERSIL CORP. + +OUI:0030B5* + ID_OUI_FROM_DATABASE=Tadiran Microwave Networks + +OUI:0030B6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0030B7* + ID_OUI_FROM_DATABASE=Teletrol Systems, Inc. + +OUI:0030B8* + ID_OUI_FROM_DATABASE=RiverDelta Networks + +OUI:0030B9* + ID_OUI_FROM_DATABASE=ECTEL + +OUI:0030BA* + ID_OUI_FROM_DATABASE=AC&T SYSTEM CO., LTD. + +OUI:0030BB* + ID_OUI_FROM_DATABASE=CacheFlow, Inc. + +OUI:0030BC* + ID_OUI_FROM_DATABASE=Optronic AG + +OUI:0030BD* + ID_OUI_FROM_DATABASE=BELKIN COMPONENTS + +OUI:0030BE* + ID_OUI_FROM_DATABASE=City-Net Technology, Inc. + +OUI:0030BF* + ID_OUI_FROM_DATABASE=MULTIDATA GMBH + +OUI:0030C0* + ID_OUI_FROM_DATABASE=Lara Technology, Inc. + +OUI:0030C1* + ID_OUI_FROM_DATABASE=HEWLETT-PACKARD + +OUI:0030C2* + ID_OUI_FROM_DATABASE=COMONE + +OUI:0030C3* + ID_OUI_FROM_DATABASE=FLUECKIGER ELEKTRONIK AG + +OUI:0030C4* + ID_OUI_FROM_DATABASE=Canon Imaging Systems Inc. + +OUI:0030C5* + ID_OUI_FROM_DATABASE=CADENCE DESIGN SYSTEMS + +OUI:0030C6* + ID_OUI_FROM_DATABASE=CONTROL SOLUTIONS, INC. + +OUI:0030C7* + ID_OUI_FROM_DATABASE=Macromate Corp. + +OUI:0030C8* + ID_OUI_FROM_DATABASE=GAD LINE, LTD. + +OUI:0030C9* + ID_OUI_FROM_DATABASE=LuxN, N + +OUI:0030CA* + ID_OUI_FROM_DATABASE=Discovery Com + +OUI:0030CB* + ID_OUI_FROM_DATABASE=OMNI FLOW COMPUTERS, INC. + +OUI:0030CC* + ID_OUI_FROM_DATABASE=Tenor Networks, Inc. + +OUI:0030CD* + ID_OUI_FROM_DATABASE=CONEXANT SYSTEMS, INC. + +OUI:0030CE* + ID_OUI_FROM_DATABASE=Zaffire + +OUI:0030CF* + ID_OUI_FROM_DATABASE=TWO TECHNOLOGIES, INC. + +OUI:0030D0* + ID_OUI_FROM_DATABASE=Tellabs + +OUI:0030D1* + ID_OUI_FROM_DATABASE=INOVA CORPORATION + +OUI:0030D2* + ID_OUI_FROM_DATABASE=WIN TECHNOLOGIES, CO., LTD. + +OUI:0030D3* + ID_OUI_FROM_DATABASE=Agilent Technologies + +OUI:0030D4* + ID_OUI_FROM_DATABASE=AAE Systems, Inc. + +OUI:0030D5* + ID_OUI_FROM_DATABASE=DResearch GmbH + +OUI:0030D6* + ID_OUI_FROM_DATABASE=MSC VERTRIEBS GMBH + +OUI:0030D7* + ID_OUI_FROM_DATABASE=Innovative Systems, L.L.C. + +OUI:0030D8* + ID_OUI_FROM_DATABASE=SITEK + +OUI:0030D9* + ID_OUI_FROM_DATABASE=DATACORE SOFTWARE CORP. + +OUI:0030DA* + ID_OUI_FROM_DATABASE=COMTREND CO. + +OUI:0030DB* + ID_OUI_FROM_DATABASE=Mindready Solutions, Inc. + +OUI:0030DC* + ID_OUI_FROM_DATABASE=RIGHTECH CORPORATION + +OUI:0030DD* + ID_OUI_FROM_DATABASE=INDIGITA CORPORATION + +OUI:0030DE* + ID_OUI_FROM_DATABASE=WAGO Kontakttechnik GmbH + +OUI:0030DF* + ID_OUI_FROM_DATABASE=KB/TEL TELECOMUNICACIONES + +OUI:0030E0* + ID_OUI_FROM_DATABASE=OXFORD SEMICONDUCTOR LTD. + +OUI:0030E1* + ID_OUI_FROM_DATABASE=Network Equipment Technologies, Inc. + +OUI:0030E2* + ID_OUI_FROM_DATABASE=GARNET SYSTEMS CO., LTD. + +OUI:0030E3* + ID_OUI_FROM_DATABASE=SEDONA NETWORKS CORP. + +OUI:0030E4* + ID_OUI_FROM_DATABASE=CHIYODA SYSTEM RIKEN + +OUI:0030E5* + ID_OUI_FROM_DATABASE=Amper Datos S.A. + +OUI:0030E6* + ID_OUI_FROM_DATABASE=Draeger Medical Systems, Inc. + +OUI:0030E7* + ID_OUI_FROM_DATABASE=CNF MOBILE SOLUTIONS, INC. + +OUI:0030E8* + ID_OUI_FROM_DATABASE=ENSIM CORP. + +OUI:0030E9* + ID_OUI_FROM_DATABASE=GMA COMMUNICATION MANUFACT'G + +OUI:0030EA* + ID_OUI_FROM_DATABASE=TeraForce Technology Corporation + +OUI:0030EB* + ID_OUI_FROM_DATABASE=TURBONET COMMUNICATIONS, INC. + +OUI:0030EC* + ID_OUI_FROM_DATABASE=BORGARDT + +OUI:0030ED* + ID_OUI_FROM_DATABASE=Expert Magnetics Corp. + +OUI:0030EE* + ID_OUI_FROM_DATABASE=DSG Technology, Inc. + +OUI:0030EF* + ID_OUI_FROM_DATABASE=NEON TECHNOLOGY, INC. + +OUI:0030F0* + ID_OUI_FROM_DATABASE=Uniform Industrial Corp. + +OUI:0030F1* + ID_OUI_FROM_DATABASE=Accton Technology Corp. + +OUI:0030F2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0030F3* + ID_OUI_FROM_DATABASE=At Work Computers + +OUI:0030F4* + ID_OUI_FROM_DATABASE=STARDOT TECHNOLOGIES + +OUI:0030F5* + ID_OUI_FROM_DATABASE=Wild Lab. Ltd. + +OUI:0030F6* + ID_OUI_FROM_DATABASE=SECURELOGIX CORPORATION + +OUI:0030F7* + ID_OUI_FROM_DATABASE=RAMIX INC. + +OUI:0030F8* + ID_OUI_FROM_DATABASE=Dynapro Systems, Inc. + +OUI:0030F9* + ID_OUI_FROM_DATABASE=Sollae Systems Co., Ltd. + +OUI:0030FA* + ID_OUI_FROM_DATABASE=TELICA, INC. + +OUI:0030FB* + ID_OUI_FROM_DATABASE=AZS Technology AG + +OUI:0030FC* + ID_OUI_FROM_DATABASE=Terawave Communications, Inc. + +OUI:0030FD* + ID_OUI_FROM_DATABASE=INTEGRATED SYSTEMS DESIGN + +OUI:0030FE* + ID_OUI_FROM_DATABASE=DSA GmbH + +OUI:0030FF* + ID_OUI_FROM_DATABASE=DATAFAB SYSTEMS, INC. + +OUI:00336C* + ID_OUI_FROM_DATABASE=SynapSense Corporation + +OUI:0034F1* + ID_OUI_FROM_DATABASE=Radicom Research, Inc. + +OUI:003532* + ID_OUI_FROM_DATABASE=Electro-Metrics Corporation + +OUI:0036F8* + ID_OUI_FROM_DATABASE=Conti Temic microelectronic GmbH + +OUI:0036FE* + ID_OUI_FROM_DATABASE=SuperVision + +OUI:00376D* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:003A98* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003A99* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003A9A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003A9B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003A9C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:003A9D* + ID_OUI_FROM_DATABASE=NEC AccessTechnica, Ltd. + +OUI:003AAF* + ID_OUI_FROM_DATABASE=BlueBit Ltd. + +OUI:003CC5* + ID_OUI_FROM_DATABASE=WONWOO Engineering Co., Ltd + +OUI:003D41* + ID_OUI_FROM_DATABASE=Hatteland Computer AS + +OUI:003EE1* + ID_OUI_FROM_DATABASE=Apple + +OUI:004000* + ID_OUI_FROM_DATABASE=PCI COMPONENTES DA AMZONIA LTD + +OUI:004001* + ID_OUI_FROM_DATABASE=Zero One Technology Co. Ltd. + +OUI:004002* + ID_OUI_FROM_DATABASE=PERLE SYSTEMS LIMITED + +OUI:004003* + ID_OUI_FROM_DATABASE=Emerson Process Management Power & Water Solutions, Inc. + +OUI:004004* + ID_OUI_FROM_DATABASE=ICM CO. LTD. + +OUI:004005* + ID_OUI_FROM_DATABASE=ANI COMMUNICATIONS INC. + +OUI:004006* + ID_OUI_FROM_DATABASE=SAMPO TECHNOLOGY CORPORATION + +OUI:004007* + ID_OUI_FROM_DATABASE=TELMAT INFORMATIQUE + +OUI:004008* + ID_OUI_FROM_DATABASE=A PLUS INFO CORPORATION + +OUI:004009* + ID_OUI_FROM_DATABASE=TACHIBANA TECTRON CO., LTD. + +OUI:00400A* + ID_OUI_FROM_DATABASE=PIVOTAL TECHNOLOGIES, INC. + +OUI:00400B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00400C* + ID_OUI_FROM_DATABASE=GENERAL MICRO SYSTEMS, INC. + +OUI:00400D* + ID_OUI_FROM_DATABASE=LANNET DATA COMMUNICATIONS,LTD + +OUI:00400E* + ID_OUI_FROM_DATABASE=MEMOTEC, INC. + +OUI:00400F* + ID_OUI_FROM_DATABASE=DATACOM TECHNOLOGIES + +OUI:004010* + ID_OUI_FROM_DATABASE=SONIC SYSTEMS, INC. + +OUI:004011* + ID_OUI_FROM_DATABASE=ANDOVER CONTROLS CORPORATION + +OUI:004012* + ID_OUI_FROM_DATABASE=WINDATA, INC. + +OUI:004013* + ID_OUI_FROM_DATABASE=NTT DATA COMM. SYSTEMS CORP. + +OUI:004014* + ID_OUI_FROM_DATABASE=COMSOFT GMBH + +OUI:004015* + ID_OUI_FROM_DATABASE=ASCOM INFRASYS AG + +OUI:004016* + ID_OUI_FROM_DATABASE=ADC - Global Connectivity Solutions Division + +OUI:004017* + ID_OUI_FROM_DATABASE=Silex Technology America + +OUI:004018* + ID_OUI_FROM_DATABASE=ADOBE SYSTEMS, INC. + +OUI:004019* + ID_OUI_FROM_DATABASE=AEON SYSTEMS, INC. + +OUI:00401A* + ID_OUI_FROM_DATABASE=FUJI ELECTRIC CO., LTD. + +OUI:00401B* + ID_OUI_FROM_DATABASE=PRINTER SYSTEMS CORP. + +OUI:00401C* + ID_OUI_FROM_DATABASE=AST RESEARCH, INC. + +OUI:00401D* + ID_OUI_FROM_DATABASE=INVISIBLE SOFTWARE, INC. + +OUI:00401E* + ID_OUI_FROM_DATABASE=ICC + +OUI:00401F* + ID_OUI_FROM_DATABASE=COLORGRAPH LTD + +OUI:004020* + ID_OUI_FROM_DATABASE=TE Connectivity Ltd. + +OUI:004021* + ID_OUI_FROM_DATABASE=RASTER GRAPHICS + +OUI:004022* + ID_OUI_FROM_DATABASE=KLEVER COMPUTERS, INC. + +OUI:004023* + ID_OUI_FROM_DATABASE=LOGIC CORPORATION + +OUI:004024* + ID_OUI_FROM_DATABASE=COMPAC INC. + +OUI:004025* + ID_OUI_FROM_DATABASE=MOLECULAR DYNAMICS + +OUI:004026* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:004027* + ID_OUI_FROM_DATABASE=SMC MASSACHUSETTS, INC. + +OUI:004028* + ID_OUI_FROM_DATABASE=NETCOMM LIMITED + +OUI:004029* + ID_OUI_FROM_DATABASE=COMPEX + +OUI:00402A* + ID_OUI_FROM_DATABASE=CANOGA-PERKINS + +OUI:00402B* + ID_OUI_FROM_DATABASE=TRIGEM COMPUTER, INC. + +OUI:00402C* + ID_OUI_FROM_DATABASE=ISIS DISTRIBUTED SYSTEMS, INC. + +OUI:00402D* + ID_OUI_FROM_DATABASE=HARRIS ADACOM CORPORATION + +OUI:00402E* + ID_OUI_FROM_DATABASE=PRECISION SOFTWARE, INC. + +OUI:00402F* + ID_OUI_FROM_DATABASE=XLNT DESIGNS INC. + +OUI:004030* + ID_OUI_FROM_DATABASE=GK COMPUTER + +OUI:004031* + ID_OUI_FROM_DATABASE=KOKUSAI ELECTRIC CO., LTD + +OUI:004032* + ID_OUI_FROM_DATABASE=DIGITAL COMMUNICATIONS + +OUI:004033* + ID_OUI_FROM_DATABASE=ADDTRON TECHNOLOGY CO., LTD. + +OUI:004034* + ID_OUI_FROM_DATABASE=BUSTEK CORPORATION + +OUI:004035* + ID_OUI_FROM_DATABASE=OPCOM + +OUI:004036* + ID_OUI_FROM_DATABASE=TRIBE COMPUTER WORKS, INC. + +OUI:004037* + ID_OUI_FROM_DATABASE=SEA-ILAN, INC. + +OUI:004038* + ID_OUI_FROM_DATABASE=TALENT ELECTRIC INCORPORATED + +OUI:004039* + ID_OUI_FROM_DATABASE=OPTEC DAIICHI DENKO CO., LTD. + +OUI:00403A* + ID_OUI_FROM_DATABASE=IMPACT TECHNOLOGIES + +OUI:00403B* + ID_OUI_FROM_DATABASE=SYNERJET INTERNATIONAL CORP. + +OUI:00403C* + ID_OUI_FROM_DATABASE=FORKS, INC. + +OUI:00403D* + ID_OUI_FROM_DATABASE=Teradata Corporation + +OUI:00403E* + ID_OUI_FROM_DATABASE=RASTER OPS CORPORATION + +OUI:00403F* + ID_OUI_FROM_DATABASE=SSANGYONG COMPUTER SYSTEMS + +OUI:004040* + ID_OUI_FROM_DATABASE=RING ACCESS, INC. + +OUI:004041* + ID_OUI_FROM_DATABASE=FUJIKURA LTD. + +OUI:004042* + ID_OUI_FROM_DATABASE=N.A.T. GMBH + +OUI:004043* + ID_OUI_FROM_DATABASE=Nokia Siemens Networks GmbH & Co. KG. + +OUI:004044* + ID_OUI_FROM_DATABASE=QNIX COMPUTER CO., LTD. + +OUI:004045* + ID_OUI_FROM_DATABASE=TWINHEAD CORPORATION + +OUI:004046* + ID_OUI_FROM_DATABASE=UDC RESEARCH LIMITED + +OUI:004047* + ID_OUI_FROM_DATABASE=WIND RIVER SYSTEMS + +OUI:004048* + ID_OUI_FROM_DATABASE=SMD INFORMATICA S.A. + +OUI:004049* + ID_OUI_FROM_DATABASE=Roche Diagnostics International Ltd. + +OUI:00404A* + ID_OUI_FROM_DATABASE=WEST AUSTRALIAN DEPARTMENT + +OUI:00404B* + ID_OUI_FROM_DATABASE=MAPLE COMPUTER SYSTEMS + +OUI:00404C* + ID_OUI_FROM_DATABASE=HYPERTEC PTY LTD. + +OUI:00404D* + ID_OUI_FROM_DATABASE=TELECOMMUNICATIONS TECHNIQUES + +OUI:00404E* + ID_OUI_FROM_DATABASE=FLUENT, INC. + +OUI:00404F* + ID_OUI_FROM_DATABASE=SPACE & NAVAL WARFARE SYSTEMS + +OUI:004050* + ID_OUI_FROM_DATABASE=IRONICS, INCORPORATED + +OUI:004051* + ID_OUI_FROM_DATABASE=GRACILIS, INC. + +OUI:004052* + ID_OUI_FROM_DATABASE=STAR TECHNOLOGIES, INC. + +OUI:004053* + ID_OUI_FROM_DATABASE=AMPRO COMPUTERS + +OUI:004054* + ID_OUI_FROM_DATABASE=CONNECTION MACHINES SERVICES + +OUI:004055* + ID_OUI_FROM_DATABASE=METRONIX GMBH + +OUI:004056* + ID_OUI_FROM_DATABASE=MCM JAPAN LTD. + +OUI:004057* + ID_OUI_FROM_DATABASE=LOCKHEED - SANDERS + +OUI:004058* + ID_OUI_FROM_DATABASE=KRONOS, INC. + +OUI:004059* + ID_OUI_FROM_DATABASE=YOSHIDA KOGYO K. K. + +OUI:00405A* + ID_OUI_FROM_DATABASE=GOLDSTAR INFORMATION & COMM. + +OUI:00405B* + ID_OUI_FROM_DATABASE=FUNASSET LIMITED + +OUI:00405C* + ID_OUI_FROM_DATABASE=FUTURE SYSTEMS, INC. + +OUI:00405D* + ID_OUI_FROM_DATABASE=STAR-TEK, INC. + +OUI:00405E* + ID_OUI_FROM_DATABASE=NORTH HILLS ISRAEL + +OUI:00405F* + ID_OUI_FROM_DATABASE=AFE COMPUTERS LTD. + +OUI:004060* + ID_OUI_FROM_DATABASE=COMENDEC LTD + +OUI:004061* + ID_OUI_FROM_DATABASE=DATATECH ENTERPRISES CO., LTD. + +OUI:004062* + ID_OUI_FROM_DATABASE=E-SYSTEMS, INC./GARLAND DIV. + +OUI:004063* + ID_OUI_FROM_DATABASE=VIA TECHNOLOGIES, INC. + +OUI:004064* + ID_OUI_FROM_DATABASE=KLA INSTRUMENTS CORPORATION + +OUI:004065* + ID_OUI_FROM_DATABASE=GTE SPACENET + +OUI:004066* + ID_OUI_FROM_DATABASE=Hitachi Metals, Ltd. + +OUI:004067* + ID_OUI_FROM_DATABASE=OMNIBYTE CORPORATION + +OUI:004068* + ID_OUI_FROM_DATABASE=EXTENDED SYSTEMS + +OUI:004069* + ID_OUI_FROM_DATABASE=LEMCOM SYSTEMS, INC. + +OUI:00406A* + ID_OUI_FROM_DATABASE=KENTEK INFORMATION SYSTEMS,INC + +OUI:00406B* + ID_OUI_FROM_DATABASE=SYSGEN + +OUI:00406C* + ID_OUI_FROM_DATABASE=COPERNIQUE + +OUI:00406D* + ID_OUI_FROM_DATABASE=LANCO, INC. + +OUI:00406E* + ID_OUI_FROM_DATABASE=COROLLARY, INC. + +OUI:00406F* + ID_OUI_FROM_DATABASE=SYNC RESEARCH INC. + +OUI:004070* + ID_OUI_FROM_DATABASE=INTERWARE CO., LTD. + +OUI:004071* + ID_OUI_FROM_DATABASE=ATM COMPUTER GMBH + +OUI:004072* + ID_OUI_FROM_DATABASE=Applied Innovation Inc. + +OUI:004073* + ID_OUI_FROM_DATABASE=BASS ASSOCIATES + +OUI:004074* + ID_OUI_FROM_DATABASE=CABLE AND WIRELESS + +OUI:004075* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:004076* + ID_OUI_FROM_DATABASE=Sun Conversion Technologies + +OUI:004077* + ID_OUI_FROM_DATABASE=MAXTON TECHNOLOGY CORPORATION + +OUI:004078* + ID_OUI_FROM_DATABASE=WEARNES AUTOMATION PTE LTD + +OUI:004079* + ID_OUI_FROM_DATABASE=JUKO MANUFACTURE COMPANY, LTD. + +OUI:00407A* + ID_OUI_FROM_DATABASE=SOCIETE D'EXPLOITATION DU CNIT + +OUI:00407B* + ID_OUI_FROM_DATABASE=SCIENTIFIC ATLANTA + +OUI:00407C* + ID_OUI_FROM_DATABASE=QUME CORPORATION + +OUI:00407D* + ID_OUI_FROM_DATABASE=EXTENSION TECHNOLOGY CORP. + +OUI:00407E* + ID_OUI_FROM_DATABASE=EVERGREEN SYSTEMS, INC. + +OUI:00407F* + ID_OUI_FROM_DATABASE=FLIR Systems + +OUI:004080* + ID_OUI_FROM_DATABASE=ATHENIX CORPORATION + +OUI:004081* + ID_OUI_FROM_DATABASE=MANNESMANN SCANGRAPHIC GMBH + +OUI:004082* + ID_OUI_FROM_DATABASE=LABORATORY EQUIPMENT CORP. + +OUI:004083* + ID_OUI_FROM_DATABASE=TDA INDUSTRIA DE PRODUTOS + +OUI:004084* + ID_OUI_FROM_DATABASE=HONEYWELL ACS + +OUI:004085* + ID_OUI_FROM_DATABASE=SAAB INSTRUMENTS AB + +OUI:004086* + ID_OUI_FROM_DATABASE=MICHELS & KLEBERHOFF COMPUTER + +OUI:004087* + ID_OUI_FROM_DATABASE=UBITREX CORPORATION + +OUI:004088* + ID_OUI_FROM_DATABASE=MOBIUS TECHNOLOGIES, INC. + +OUI:004089* + ID_OUI_FROM_DATABASE=MEIDENSHA CORPORATION + +OUI:00408A* + ID_OUI_FROM_DATABASE=TPS TELEPROCESSING SYS. GMBH + +OUI:00408B* + ID_OUI_FROM_DATABASE=RAYLAN CORPORATION + +OUI:00408C* + ID_OUI_FROM_DATABASE=AXIS COMMUNICATIONS AB + +OUI:00408D* + ID_OUI_FROM_DATABASE=THE GOODYEAR TIRE & RUBBER CO. + +OUI:00408E* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:00408F* + ID_OUI_FROM_DATABASE=WM-DATA MINFO AB + +OUI:004090* + ID_OUI_FROM_DATABASE=ANSEL COMMUNICATIONS + +OUI:004091* + ID_OUI_FROM_DATABASE=PROCOMP INDUSTRIA ELETRONICA + +OUI:004092* + ID_OUI_FROM_DATABASE=ASP COMPUTER PRODUCTS, INC. + +OUI:004093* + ID_OUI_FROM_DATABASE=PAXDATA NETWORKS LTD. + +OUI:004094* + ID_OUI_FROM_DATABASE=SHOGRAPHICS, INC. + +OUI:004095* + ID_OUI_FROM_DATABASE=R.P.T. INTERGROUPS INT'L LTD. + +OUI:004096* + ID_OUI_FROM_DATABASE=Cisco Systems + +OUI:004097* + ID_OUI_FROM_DATABASE=DATEX DIVISION OF + +OUI:004098* + ID_OUI_FROM_DATABASE=DRESSLER GMBH & CO. + +OUI:004099* + ID_OUI_FROM_DATABASE=NEWGEN SYSTEMS CORP. + +OUI:00409A* + ID_OUI_FROM_DATABASE=NETWORK EXPRESS, INC. + +OUI:00409B* + ID_OUI_FROM_DATABASE=HAL COMPUTER SYSTEMS INC. + +OUI:00409C* + ID_OUI_FROM_DATABASE=TRANSWARE + +OUI:00409D* + ID_OUI_FROM_DATABASE=DIGIBOARD, INC. + +OUI:00409E* + ID_OUI_FROM_DATABASE=CONCURRENT TECHNOLOGIES LTD. + +OUI:00409F* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:0040A0* + ID_OUI_FROM_DATABASE=GOLDSTAR CO., LTD. + +OUI:0040A1* + ID_OUI_FROM_DATABASE=ERGO COMPUTING + +OUI:0040A2* + ID_OUI_FROM_DATABASE=KINGSTAR TECHNOLOGY INC. + +OUI:0040A3* + ID_OUI_FROM_DATABASE=MICROUNITY SYSTEMS ENGINEERING + +OUI:0040A4* + ID_OUI_FROM_DATABASE=ROSE ELECTRONICS + +OUI:0040A5* + ID_OUI_FROM_DATABASE=CLINICOMP INTL. + +OUI:0040A6* + ID_OUI_FROM_DATABASE=Cray, Inc. + +OUI:0040A7* + ID_OUI_FROM_DATABASE=ITAUTEC PHILCO S.A. + +OUI:0040A8* + ID_OUI_FROM_DATABASE=IMF INTERNATIONAL LTD. + +OUI:0040A9* + ID_OUI_FROM_DATABASE=DATACOM INC. + +OUI:0040AA* + ID_OUI_FROM_DATABASE=Metso Automation + +OUI:0040AB* + ID_OUI_FROM_DATABASE=ROLAND DG CORPORATION + +OUI:0040AC* + ID_OUI_FROM_DATABASE=SUPER WORKSTATION, INC. + +OUI:0040AD* + ID_OUI_FROM_DATABASE=SMA REGELSYSTEME GMBH + +OUI:0040AE* + ID_OUI_FROM_DATABASE=DELTA CONTROLS, INC. + +OUI:0040AF* + ID_OUI_FROM_DATABASE=DIGITAL PRODUCTS, INC. + +OUI:0040B0* + ID_OUI_FROM_DATABASE=BYTEX CORPORATION, ENGINEERING + +OUI:0040B1* + ID_OUI_FROM_DATABASE=CODONICS INC. + +OUI:0040B2* + ID_OUI_FROM_DATABASE=SYSTEMFORSCHUNG + +OUI:0040B3* + ID_OUI_FROM_DATABASE=ParTech Inc. + +OUI:0040B4* + ID_OUI_FROM_DATABASE=NEXTCOM K.K. + +OUI:0040B5* + ID_OUI_FROM_DATABASE=VIDEO TECHNOLOGY COMPUTERS LTD + +OUI:0040B6* + ID_OUI_FROM_DATABASE=COMPUTERM CORPORATION + +OUI:0040B7* + ID_OUI_FROM_DATABASE=STEALTH COMPUTER SYSTEMS + +OUI:0040B8* + ID_OUI_FROM_DATABASE=IDEA ASSOCIATES + +OUI:0040B9* + ID_OUI_FROM_DATABASE=MACQ ELECTRONIQUE SA + +OUI:0040BA* + ID_OUI_FROM_DATABASE=ALLIANT COMPUTER SYSTEMS CORP. + +OUI:0040BB* + ID_OUI_FROM_DATABASE=GOLDSTAR CABLE CO., LTD. + +OUI:0040BC* + ID_OUI_FROM_DATABASE=ALGORITHMICS LTD. + +OUI:0040BD* + ID_OUI_FROM_DATABASE=STARLIGHT NETWORKS, INC. + +OUI:0040BE* + ID_OUI_FROM_DATABASE=BOEING DEFENSE & SPACE + +OUI:0040BF* + ID_OUI_FROM_DATABASE=CHANNEL SYSTEMS INTERN'L INC. + +OUI:0040C0* + ID_OUI_FROM_DATABASE=VISTA CONTROLS CORPORATION + +OUI:0040C1* + ID_OUI_FROM_DATABASE=BIZERBA-WERKE WILHEIM KRAUT + +OUI:0040C2* + ID_OUI_FROM_DATABASE=APPLIED COMPUTING DEVICES + +OUI:0040C3* + ID_OUI_FROM_DATABASE=FISCHER AND PORTER CO. + +OUI:0040C4* + ID_OUI_FROM_DATABASE=KINKEI SYSTEM CORPORATION + +OUI:0040C5* + ID_OUI_FROM_DATABASE=MICOM COMMUNICATIONS INC. + +OUI:0040C6* + ID_OUI_FROM_DATABASE=FIBERNET RESEARCH, INC. + +OUI:0040C7* + ID_OUI_FROM_DATABASE=RUBY TECH CORPORATION + +OUI:0040C8* + ID_OUI_FROM_DATABASE=MILAN TECHNOLOGY CORPORATION + +OUI:0040C9* + ID_OUI_FROM_DATABASE=NCUBE + +OUI:0040CA* + ID_OUI_FROM_DATABASE=FIRST INTERNAT'L COMPUTER, INC + +OUI:0040CB* + ID_OUI_FROM_DATABASE=LANWAN TECHNOLOGIES + +OUI:0040CC* + ID_OUI_FROM_DATABASE=SILCOM MANUF'G TECHNOLOGY INC. + +OUI:0040CD* + ID_OUI_FROM_DATABASE=TERA MICROSYSTEMS, INC. + +OUI:0040CE* + ID_OUI_FROM_DATABASE=NET-SOURCE, INC. + +OUI:0040CF* + ID_OUI_FROM_DATABASE=STRAWBERRY TREE, INC. + +OUI:0040D0* + ID_OUI_FROM_DATABASE=MITAC INTERNATIONAL CORP. + +OUI:0040D1* + ID_OUI_FROM_DATABASE=FUKUDA DENSHI CO., LTD. + +OUI:0040D2* + ID_OUI_FROM_DATABASE=PAGINE CORPORATION + +OUI:0040D3* + ID_OUI_FROM_DATABASE=KIMPSION INTERNATIONAL CORP. + +OUI:0040D4* + ID_OUI_FROM_DATABASE=GAGE TALKER CORP. + +OUI:0040D5* + ID_OUI_FROM_DATABASE=Sartorius Mechatronics T&H GmbH + +OUI:0040D6* + ID_OUI_FROM_DATABASE=LOCAMATION B.V. + +OUI:0040D7* + ID_OUI_FROM_DATABASE=STUDIO GEN INC. + +OUI:0040D8* + ID_OUI_FROM_DATABASE=OCEAN OFFICE AUTOMATION LTD. + +OUI:0040D9* + ID_OUI_FROM_DATABASE=AMERICAN MEGATRENDS INC. + +OUI:0040DA* + ID_OUI_FROM_DATABASE=TELSPEC LTD + +OUI:0040DB* + ID_OUI_FROM_DATABASE=ADVANCED TECHNICAL SOLUTIONS + +OUI:0040DC* + ID_OUI_FROM_DATABASE=TRITEC ELECTRONIC GMBH + +OUI:0040DD* + ID_OUI_FROM_DATABASE=HONG TECHNOLOGIES + +OUI:0040DE* + ID_OUI_FROM_DATABASE=Elsag Datamat spa + +OUI:0040DF* + ID_OUI_FROM_DATABASE=DIGALOG SYSTEMS, INC. + +OUI:0040E0* + ID_OUI_FROM_DATABASE=ATOMWIDE LTD. + +OUI:0040E1* + ID_OUI_FROM_DATABASE=MARNER INTERNATIONAL, INC. + +OUI:0040E2* + ID_OUI_FROM_DATABASE=MESA RIDGE TECHNOLOGIES, INC. + +OUI:0040E3* + ID_OUI_FROM_DATABASE=QUIN SYSTEMS LTD + +OUI:0040E4* + ID_OUI_FROM_DATABASE=E-M TECHNOLOGY, INC. + +OUI:0040E5* + ID_OUI_FROM_DATABASE=SYBUS CORPORATION + +OUI:0040E6* + ID_OUI_FROM_DATABASE=C.A.E.N. + +OUI:0040E7* + ID_OUI_FROM_DATABASE=ARNOS INSTRUMENTS & COMPUTER + +OUI:0040E8* + ID_OUI_FROM_DATABASE=CHARLES RIVER DATA SYSTEMS,INC + +OUI:0040E9* + ID_OUI_FROM_DATABASE=ACCORD SYSTEMS, INC. + +OUI:0040EA* + ID_OUI_FROM_DATABASE=PLAIN TREE SYSTEMS INC + +OUI:0040EB* + ID_OUI_FROM_DATABASE=MARTIN MARIETTA CORPORATION + +OUI:0040EC* + ID_OUI_FROM_DATABASE=MIKASA SYSTEM ENGINEERING + +OUI:0040ED* + ID_OUI_FROM_DATABASE=NETWORK CONTROLS INT'NATL INC. + +OUI:0040EE* + ID_OUI_FROM_DATABASE=OPTIMEM + +OUI:0040EF* + ID_OUI_FROM_DATABASE=HYPERCOM, INC. + +OUI:0040F0* + ID_OUI_FROM_DATABASE=MicroBrain,Inc. + +OUI:0040F1* + ID_OUI_FROM_DATABASE=CHUO ELECTRONICS CO., LTD. + +OUI:0040F2* + ID_OUI_FROM_DATABASE=JANICH & KLASS COMPUTERTECHNIK + +OUI:0040F3* + ID_OUI_FROM_DATABASE=NETCOR + +OUI:0040F4* + ID_OUI_FROM_DATABASE=CAMEO COMMUNICATIONS, INC. + +OUI:0040F5* + ID_OUI_FROM_DATABASE=OEM ENGINES + +OUI:0040F6* + ID_OUI_FROM_DATABASE=KATRON COMPUTERS INC. + +OUI:0040F7* + ID_OUI_FROM_DATABASE=Polaroid Corporation + +OUI:0040F8* + ID_OUI_FROM_DATABASE=SYSTEMHAUS DISCOM + +OUI:0040F9* + ID_OUI_FROM_DATABASE=COMBINET + +OUI:0040FA* + ID_OUI_FROM_DATABASE=MICROBOARDS, INC. + +OUI:0040FB* + ID_OUI_FROM_DATABASE=CASCADE COMMUNICATIONS CORP. + +OUI:0040FC* + ID_OUI_FROM_DATABASE=IBR COMPUTER TECHNIK GMBH + +OUI:0040FD* + ID_OUI_FROM_DATABASE=LXE + +OUI:0040FE* + ID_OUI_FROM_DATABASE=SYMPLEX COMMUNICATIONS + +OUI:0040FF* + ID_OUI_FROM_DATABASE=TELEBIT CORPORATION + +OUI:0041B4* + ID_OUI_FROM_DATABASE=Wuxi Zhongxing Optoelectronics Technology Co.,Ltd. + +OUI:004252* + ID_OUI_FROM_DATABASE=RLX Technologies + +OUI:0043FF* + ID_OUI_FROM_DATABASE=KETRON S.R.L. + +OUI:004501* + ID_OUI_FROM_DATABASE=Versus Technology, Inc. + +OUI:00464B* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:004D32* + ID_OUI_FROM_DATABASE=Andon Health Co.,Ltd. + +OUI:005000* + ID_OUI_FROM_DATABASE=NEXO COMMUNICATIONS, INC. + +OUI:005001* + ID_OUI_FROM_DATABASE=YAMASHITA SYSTEMS CORP. + +OUI:005002* + ID_OUI_FROM_DATABASE=OMNISEC AG + +OUI:005003* + ID_OUI_FROM_DATABASE=Xrite Inc + +OUI:005004* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:005006* + ID_OUI_FROM_DATABASE=TAC AB + +OUI:005007* + ID_OUI_FROM_DATABASE=SIEMENS TELECOMMUNICATION SYSTEMS LIMITED + +OUI:005008* + ID_OUI_FROM_DATABASE=TIVA MICROCOMPUTER CORP. (TMC) + +OUI:005009* + ID_OUI_FROM_DATABASE=PHILIPS BROADBAND NETWORKS + +OUI:00500A* + ID_OUI_FROM_DATABASE=IRIS TECHNOLOGIES, INC. + +OUI:00500B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00500C* + ID_OUI_FROM_DATABASE=e-Tek Labs, Inc. + +OUI:00500D* + ID_OUI_FROM_DATABASE=SATORI ELECTORIC CO., LTD. + +OUI:00500E* + ID_OUI_FROM_DATABASE=CHROMATIS NETWORKS, INC. + +OUI:00500F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005010* + ID_OUI_FROM_DATABASE=NovaNET Learning, Inc. + +OUI:005012* + ID_OUI_FROM_DATABASE=CBL - GMBH + +OUI:005013* + ID_OUI_FROM_DATABASE=Chaparral Network Storage + +OUI:005014* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005015* + ID_OUI_FROM_DATABASE=BRIGHT STAR ENGINEERING + +OUI:005016* + ID_OUI_FROM_DATABASE=SST/WOODHEAD INDUSTRIES + +OUI:005017* + ID_OUI_FROM_DATABASE=RSR S.R.L. + +OUI:005018* + ID_OUI_FROM_DATABASE=AMIT, Inc. + +OUI:005019* + ID_OUI_FROM_DATABASE=SPRING TIDE NETWORKS, INC. + +OUI:00501A* + ID_OUI_FROM_DATABASE=IQinVision + +OUI:00501B* + ID_OUI_FROM_DATABASE=ABL CANADA, INC. + +OUI:00501C* + ID_OUI_FROM_DATABASE=JATOM SYSTEMS, INC. + +OUI:00501E* + ID_OUI_FROM_DATABASE=Miranda Technologies, Inc. + +OUI:00501F* + ID_OUI_FROM_DATABASE=MRG SYSTEMS, LTD. + +OUI:005020* + ID_OUI_FROM_DATABASE=MEDIASTAR CO., LTD. + +OUI:005021* + ID_OUI_FROM_DATABASE=EIS INTERNATIONAL, INC. + +OUI:005022* + ID_OUI_FROM_DATABASE=ZONET TECHNOLOGY, INC. + +OUI:005023* + ID_OUI_FROM_DATABASE=PG DESIGN ELECTRONICS, INC. + +OUI:005024* + ID_OUI_FROM_DATABASE=NAVIC SYSTEMS, INC. + +OUI:005026* + ID_OUI_FROM_DATABASE=COSYSTEMS, INC. + +OUI:005027* + ID_OUI_FROM_DATABASE=GENICOM CORPORATION + +OUI:005028* + ID_OUI_FROM_DATABASE=AVAL COMMUNICATIONS + +OUI:005029* + ID_OUI_FROM_DATABASE=1394 PRINTER WORKING GROUP + +OUI:00502A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00502B* + ID_OUI_FROM_DATABASE=GENRAD LTD. + +OUI:00502C* + ID_OUI_FROM_DATABASE=SOYO COMPUTER, INC. + +OUI:00502D* + ID_OUI_FROM_DATABASE=ACCEL, INC. + +OUI:00502E* + ID_OUI_FROM_DATABASE=CAMBEX CORPORATION + +OUI:00502F* + ID_OUI_FROM_DATABASE=TollBridge Technologies, Inc. + +OUI:005030* + ID_OUI_FROM_DATABASE=FUTURE PLUS SYSTEMS + +OUI:005031* + ID_OUI_FROM_DATABASE=AEROFLEX LABORATORIES, INC. + +OUI:005032* + ID_OUI_FROM_DATABASE=PICAZO COMMUNICATIONS, INC. + +OUI:005033* + ID_OUI_FROM_DATABASE=MAYAN NETWORKS + +OUI:005036* + ID_OUI_FROM_DATABASE=NETCAM, LTD. + +OUI:005037* + ID_OUI_FROM_DATABASE=KOGA ELECTRONICS CO. + +OUI:005038* + ID_OUI_FROM_DATABASE=DAIN TELECOM CO., LTD. + +OUI:005039* + ID_OUI_FROM_DATABASE=MARINER NETWORKS + +OUI:00503A* + ID_OUI_FROM_DATABASE=DATONG ELECTRONICS LTD. + +OUI:00503B* + ID_OUI_FROM_DATABASE=MEDIAFIRE CORPORATION + +OUI:00503C* + ID_OUI_FROM_DATABASE=TSINGHUA NOVEL ELECTRONICS + +OUI:00503E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00503F* + ID_OUI_FROM_DATABASE=ANCHOR GAMES + +OUI:005040* + ID_OUI_FROM_DATABASE=Panasonic Electric Works Co., Ltd. + +OUI:005041* + ID_OUI_FROM_DATABASE=Coretronic Corporation + +OUI:005042* + ID_OUI_FROM_DATABASE=SCI MANUFACTURING SINGAPORE PTE, LTD. + +OUI:005043* + ID_OUI_FROM_DATABASE=MARVELL SEMICONDUCTOR, INC. + +OUI:005044* + ID_OUI_FROM_DATABASE=ASACA CORPORATION + +OUI:005045* + ID_OUI_FROM_DATABASE=RIOWORKS SOLUTIONS, INC. + +OUI:005046* + ID_OUI_FROM_DATABASE=MENICX INTERNATIONAL CO., LTD. + +OUI:005048* + ID_OUI_FROM_DATABASE=INFOLIBRIA + +OUI:005049* + ID_OUI_FROM_DATABASE=Arbor Networks Inc + +OUI:00504A* + ID_OUI_FROM_DATABASE=ELTECO A.S. + +OUI:00504B* + ID_OUI_FROM_DATABASE=BARCONET N.V. + +OUI:00504C* + ID_OUI_FROM_DATABASE=Galil Motion Control + +OUI:00504D* + ID_OUI_FROM_DATABASE=Tokyo Electron Device Limited + +OUI:00504E* + ID_OUI_FROM_DATABASE=SIERRA MONITOR CORP. + +OUI:00504F* + ID_OUI_FROM_DATABASE=OLENCOM ELECTRONICS + +OUI:005050* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005051* + ID_OUI_FROM_DATABASE=IWATSU ELECTRIC CO., LTD. + +OUI:005052* + ID_OUI_FROM_DATABASE=TIARA NETWORKS, INC. + +OUI:005053* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005054* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005055* + ID_OUI_FROM_DATABASE=DOMS A/S + +OUI:005056* + ID_OUI_FROM_DATABASE=VMware, Inc. + +OUI:005057* + ID_OUI_FROM_DATABASE=BROADBAND ACCESS SYSTEMS + +OUI:005058* + ID_OUI_FROM_DATABASE=VegaStream Group Limted + +OUI:005059* + ID_OUI_FROM_DATABASE=iBAHN + +OUI:00505A* + ID_OUI_FROM_DATABASE=NETWORK ALCHEMY, INC. + +OUI:00505B* + ID_OUI_FROM_DATABASE=KAWASAKI LSI U.S.A., INC. + +OUI:00505C* + ID_OUI_FROM_DATABASE=TUNDO CORPORATION + +OUI:00505E* + ID_OUI_FROM_DATABASE=DIGITEK MICROLOGIC S.A. + +OUI:00505F* + ID_OUI_FROM_DATABASE=BRAND INNOVATORS + +OUI:005060* + ID_OUI_FROM_DATABASE=TANDBERG TELECOM AS + +OUI:005062* + ID_OUI_FROM_DATABASE=KOUWELL ELECTRONICS CORP. ** + +OUI:005063* + ID_OUI_FROM_DATABASE=OY COMSEL SYSTEM AB + +OUI:005064* + ID_OUI_FROM_DATABASE=CAE ELECTRONICS + +OUI:005065* + ID_OUI_FROM_DATABASE=TDK-Lambda Corporation + +OUI:005066* + ID_OUI_FROM_DATABASE=AtecoM GmbH advanced telecomunication modules + +OUI:005067* + ID_OUI_FROM_DATABASE=AEROCOMM, INC. + +OUI:005068* + ID_OUI_FROM_DATABASE=ELECTRONIC INDUSTRIES ASSOCIATION + +OUI:005069* + ID_OUI_FROM_DATABASE=PixStream Incorporated + +OUI:00506A* + ID_OUI_FROM_DATABASE=EDEVA, INC. + +OUI:00506B* + ID_OUI_FROM_DATABASE=SPX-ATEG + +OUI:00506C* + ID_OUI_FROM_DATABASE=Beijer Electronics Products AB + +OUI:00506D* + ID_OUI_FROM_DATABASE=VIDEOJET SYSTEMS + +OUI:00506E* + ID_OUI_FROM_DATABASE=CORDER ENGINEERING CORPORATION + +OUI:00506F* + ID_OUI_FROM_DATABASE=G-CONNECT + +OUI:005070* + ID_OUI_FROM_DATABASE=CHAINTECH COMPUTER CO., LTD. + +OUI:005071* + ID_OUI_FROM_DATABASE=AIWA CO., LTD. + +OUI:005072* + ID_OUI_FROM_DATABASE=CORVIS CORPORATION + +OUI:005073* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005074* + ID_OUI_FROM_DATABASE=ADVANCED HI-TECH CORP. + +OUI:005075* + ID_OUI_FROM_DATABASE=KESTREL SOLUTIONS + +OUI:005076* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:005077* + ID_OUI_FROM_DATABASE=PROLIFIC TECHNOLOGY, INC. + +OUI:005078* + ID_OUI_FROM_DATABASE=MEGATON HOUSE, LTD. + +OUI:00507A* + ID_OUI_FROM_DATABASE=XPEED, INC. + +OUI:00507B* + ID_OUI_FROM_DATABASE=MERLOT COMMUNICATIONS + +OUI:00507C* + ID_OUI_FROM_DATABASE=VIDEOCON AG + +OUI:00507D* + ID_OUI_FROM_DATABASE=IFP + +OUI:00507E* + ID_OUI_FROM_DATABASE=NEWER TECHNOLOGY + +OUI:00507F* + ID_OUI_FROM_DATABASE=DrayTek Corp. + +OUI:005080* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:005081* + ID_OUI_FROM_DATABASE=MURATA MACHINERY, LTD. + +OUI:005082* + ID_OUI_FROM_DATABASE=FORESSON CORPORATION + +OUI:005083* + ID_OUI_FROM_DATABASE=GILBARCO, INC. + +OUI:005084* + ID_OUI_FROM_DATABASE=ATL PRODUCTS + +OUI:005086* + ID_OUI_FROM_DATABASE=TELKOM SA, LTD. + +OUI:005087* + ID_OUI_FROM_DATABASE=TERASAKI ELECTRIC CO., LTD. + +OUI:005088* + ID_OUI_FROM_DATABASE=AMANO CORPORATION + +OUI:005089* + ID_OUI_FROM_DATABASE=SAFETY MANAGEMENT SYSTEMS + +OUI:00508B* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:00508C* + ID_OUI_FROM_DATABASE=RSI SYSTEMS + +OUI:00508D* + ID_OUI_FROM_DATABASE=ABIT COMPUTER CORPORATION + +OUI:00508E* + ID_OUI_FROM_DATABASE=OPTIMATION, INC. + +OUI:00508F* + ID_OUI_FROM_DATABASE=ASITA TECHNOLOGIES INT'L LTD. + +OUI:005090* + ID_OUI_FROM_DATABASE=DCTRI + +OUI:005091* + ID_OUI_FROM_DATABASE=NETACCESS, INC. + +OUI:005092* + ID_OUI_FROM_DATABASE=RIGAKU INDUSTRIAL CORPORATION + +OUI:005093* + ID_OUI_FROM_DATABASE=BOEING + +OUI:005094* + ID_OUI_FROM_DATABASE=PACE plc + +OUI:005095* + ID_OUI_FROM_DATABASE=PERACOM NETWORKS + +OUI:005096* + ID_OUI_FROM_DATABASE=SALIX TECHNOLOGIES, INC. + +OUI:005097* + ID_OUI_FROM_DATABASE=MMC-EMBEDDED COMPUTERTECHNIK GmbH + +OUI:005098* + ID_OUI_FROM_DATABASE=GLOBALOOP, LTD. + +OUI:005099* + ID_OUI_FROM_DATABASE=3COM EUROPE, LTD. + +OUI:00509A* + ID_OUI_FROM_DATABASE=TAG ELECTRONIC SYSTEMS + +OUI:00509B* + ID_OUI_FROM_DATABASE=SWITCHCORE AB + +OUI:00509C* + ID_OUI_FROM_DATABASE=BETA RESEARCH + +OUI:00509D* + ID_OUI_FROM_DATABASE=THE INDUSTREE B.V. + +OUI:00509E* + ID_OUI_FROM_DATABASE=Les Technologies SoftAcoustik Inc. + +OUI:00509F* + ID_OUI_FROM_DATABASE=HORIZON COMPUTER + +OUI:0050A0* + ID_OUI_FROM_DATABASE=DELTA COMPUTER SYSTEMS, INC. + +OUI:0050A1* + ID_OUI_FROM_DATABASE=CARLO GAVAZZI, INC. + +OUI:0050A2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050A3* + ID_OUI_FROM_DATABASE=TransMedia Communications, Inc. + +OUI:0050A4* + ID_OUI_FROM_DATABASE=IO TECH, INC. + +OUI:0050A5* + ID_OUI_FROM_DATABASE=CAPITOL BUSINESS SYSTEMS, LTD. + +OUI:0050A6* + ID_OUI_FROM_DATABASE=OPTRONICS + +OUI:0050A7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050A8* + ID_OUI_FROM_DATABASE=OpenCon Systems, Inc. + +OUI:0050A9* + ID_OUI_FROM_DATABASE=MOLDAT WIRELESS TECHNOLGIES + +OUI:0050AA* + ID_OUI_FROM_DATABASE=KONICA MINOLTA HOLDINGS, INC. + +OUI:0050AB* + ID_OUI_FROM_DATABASE=NALTEC, Inc. + +OUI:0050AC* + ID_OUI_FROM_DATABASE=MAPLE COMPUTER CORPORATION + +OUI:0050AD* + ID_OUI_FROM_DATABASE=CommUnique Wireless Corp. + +OUI:0050AE* + ID_OUI_FROM_DATABASE=FDK Co., Ltd + +OUI:0050AF* + ID_OUI_FROM_DATABASE=INTERGON, INC. + +OUI:0050B0* + ID_OUI_FROM_DATABASE=TECHNOLOGY ATLANTA CORPORATION + +OUI:0050B1* + ID_OUI_FROM_DATABASE=GIDDINGS & LEWIS + +OUI:0050B2* + ID_OUI_FROM_DATABASE=BRODEL GmbH + +OUI:0050B3* + ID_OUI_FROM_DATABASE=VOICEBOARD CORPORATION + +OUI:0050B4* + ID_OUI_FROM_DATABASE=SATCHWELL CONTROL SYSTEMS, LTD + +OUI:0050B5* + ID_OUI_FROM_DATABASE=FICHET-BAUCHE + +OUI:0050B6* + ID_OUI_FROM_DATABASE=GOOD WAY IND. CO., LTD. + +OUI:0050B7* + ID_OUI_FROM_DATABASE=BOSER TECHNOLOGY CO., LTD. + +OUI:0050B8* + ID_OUI_FROM_DATABASE=INOVA COMPUTERS GMBH & CO. KG + +OUI:0050B9* + ID_OUI_FROM_DATABASE=XITRON TECHNOLOGIES, INC. + +OUI:0050BA* + ID_OUI_FROM_DATABASE=D-LINK + +OUI:0050BB* + ID_OUI_FROM_DATABASE=CMS TECHNOLOGIES + +OUI:0050BC* + ID_OUI_FROM_DATABASE=HAMMER STORAGE SOLUTIONS + +OUI:0050BD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050BE* + ID_OUI_FROM_DATABASE=FAST MULTIMEDIA AG + +OUI:0050BF* + ID_OUI_FROM_DATABASE=Metalligence Technology Corp. + +OUI:0050C0* + ID_OUI_FROM_DATABASE=GATAN, INC. + +OUI:0050C1* + ID_OUI_FROM_DATABASE=GEMFLEX NETWORKS, LTD. + +OUI:0050C4* + ID_OUI_FROM_DATABASE=IMD + +OUI:0050C5* + ID_OUI_FROM_DATABASE=ADS Technologies, Inc + +OUI:0050C6* + ID_OUI_FROM_DATABASE=LOOP TELECOMMUNICATION INTERNATIONAL, INC. + +OUI:0050C8* + ID_OUI_FROM_DATABASE=Addonics Technologies, Inc. + +OUI:0050C9* + ID_OUI_FROM_DATABASE=MASPRO DENKOH CORP. + +OUI:0050CA* + ID_OUI_FROM_DATABASE=NET TO NET TECHNOLOGIES + +OUI:0050CB* + ID_OUI_FROM_DATABASE=JETTER + +OUI:0050CC* + ID_OUI_FROM_DATABASE=XYRATEX + +OUI:0050CD* + ID_OUI_FROM_DATABASE=DIGIANSWER A/S + +OUI:0050CE* + ID_OUI_FROM_DATABASE=LG INTERNATIONAL CORP. + +OUI:0050CF* + ID_OUI_FROM_DATABASE=VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE + +OUI:0050D0* + ID_OUI_FROM_DATABASE=MINERVA SYSTEMS + +OUI:0050D1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050D2* + ID_OUI_FROM_DATABASE=CMC Electronics Inc + +OUI:0050D3* + ID_OUI_FROM_DATABASE=DIGITAL AUDIO PROCESSING PTY. LTD. + +OUI:0050D4* + ID_OUI_FROM_DATABASE=JOOHONG INFORMATION & + +OUI:0050D5* + ID_OUI_FROM_DATABASE=AD SYSTEMS CORP. + +OUI:0050D6* + ID_OUI_FROM_DATABASE=ATLAS COPCO TOOLS AB + +OUI:0050D7* + ID_OUI_FROM_DATABASE=TELSTRAT + +OUI:0050D8* + ID_OUI_FROM_DATABASE=UNICORN COMPUTER CORP. + +OUI:0050D9* + ID_OUI_FROM_DATABASE=ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA + +OUI:0050DA* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:0050DB* + ID_OUI_FROM_DATABASE=CONTEMPORARY CONTROL + +OUI:0050DC* + ID_OUI_FROM_DATABASE=TAS TELEFONBAU A. SCHWABE GMBH & CO. KG + +OUI:0050DD* + ID_OUI_FROM_DATABASE=SERRA SOLDADURA, S.A. + +OUI:0050DE* + ID_OUI_FROM_DATABASE=SIGNUM SYSTEMS CORP. + +OUI:0050DF* + ID_OUI_FROM_DATABASE=AirFiber, Inc. + +OUI:0050E1* + ID_OUI_FROM_DATABASE=NS TECH ELECTRONICS SDN BHD + +OUI:0050E2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050E3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0050E4* + ID_OUI_FROM_DATABASE=Apple + +OUI:0050E6* + ID_OUI_FROM_DATABASE=HAKUSAN CORPORATION + +OUI:0050E7* + ID_OUI_FROM_DATABASE=PARADISE INNOVATIONS (ASIA) + +OUI:0050E8* + ID_OUI_FROM_DATABASE=NOMADIX INC. + +OUI:0050EA* + ID_OUI_FROM_DATABASE=XEL COMMUNICATIONS, INC. + +OUI:0050EB* + ID_OUI_FROM_DATABASE=ALPHA-TOP CORPORATION + +OUI:0050EC* + ID_OUI_FROM_DATABASE=OLICOM A/S + +OUI:0050ED* + ID_OUI_FROM_DATABASE=ANDA NETWORKS + +OUI:0050EE* + ID_OUI_FROM_DATABASE=TEK DIGITEL CORPORATION + +OUI:0050EF* + ID_OUI_FROM_DATABASE=SPE Systemhaus GmbH + +OUI:0050F0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0050F1* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:0050F2* + ID_OUI_FROM_DATABASE=MICROSOFT CORP. + +OUI:0050F3* + ID_OUI_FROM_DATABASE=GLOBAL NET INFORMATION CO., Ltd. + +OUI:0050F4* + ID_OUI_FROM_DATABASE=SIGMATEK GMBH & CO. KG + +OUI:0050F6* + ID_OUI_FROM_DATABASE=PAN-INTERNATIONAL INDUSTRIAL CORP. + +OUI:0050F7* + ID_OUI_FROM_DATABASE=VENTURE MANUFACTURING (SINGAPORE) LTD. + +OUI:0050F8* + ID_OUI_FROM_DATABASE=ENTREGA TECHNOLOGIES, INC. + +OUI:0050F9* + ID_OUI_FROM_DATABASE=SENSORMATIC ACD + +OUI:0050FA* + ID_OUI_FROM_DATABASE=OXTEL, LTD. + +OUI:0050FB* + ID_OUI_FROM_DATABASE=VSK ELECTRONICS + +OUI:0050FC* + ID_OUI_FROM_DATABASE=EDIMAX TECHNOLOGY CO., LTD. + +OUI:0050FD* + ID_OUI_FROM_DATABASE=VISIONCOMM CO., LTD. + +OUI:0050FE* + ID_OUI_FROM_DATABASE=PCTVnet ASA + +OUI:0050FF* + ID_OUI_FROM_DATABASE=HAKKO ELECTRONICS CO., LTD. + +OUI:005218* + ID_OUI_FROM_DATABASE=Wuxi Keboda Electron Co.Ltd + +OUI:0054AF* + ID_OUI_FROM_DATABASE=Continental Automotive Systems Inc. + +OUI:005907* + ID_OUI_FROM_DATABASE=LenovoEMC Products USA, LLC + +OUI:005CB1* + ID_OUI_FROM_DATABASE=Gospell DIGITAL TECHNOLOGY CO., LTD + +OUI:005D03* + ID_OUI_FROM_DATABASE=Xilinx, Inc + +OUI:006000* + ID_OUI_FROM_DATABASE=XYCOM INC. + +OUI:006001* + ID_OUI_FROM_DATABASE=InnoSys, Inc. + +OUI:006002* + ID_OUI_FROM_DATABASE=SCREEN SUBTITLING SYSTEMS, LTD + +OUI:006003* + ID_OUI_FROM_DATABASE=TERAOKA WEIGH SYSTEM PTE, LTD. + +OUI:006004* + ID_OUI_FROM_DATABASE=COMPUTADORES MODULARES SA + +OUI:006005* + ID_OUI_FROM_DATABASE=FEEDBACK DATA LTD. + +OUI:006006* + ID_OUI_FROM_DATABASE=SOTEC CO., LTD + +OUI:006007* + ID_OUI_FROM_DATABASE=ACRES GAMING, INC. + +OUI:006008* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:006009* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00600A* + ID_OUI_FROM_DATABASE=SORD COMPUTER CORPORATION + +OUI:00600B* + ID_OUI_FROM_DATABASE=LOGWARE GmbH + +OUI:00600C* + ID_OUI_FROM_DATABASE=Eurotech Inc. + +OUI:00600D* + ID_OUI_FROM_DATABASE=Digital Logic GmbH + +OUI:00600E* + ID_OUI_FROM_DATABASE=WAVENET INTERNATIONAL, INC. + +OUI:00600F* + ID_OUI_FROM_DATABASE=WESTELL, INC. + +OUI:006010* + ID_OUI_FROM_DATABASE=NETWORK MACHINES, INC. + +OUI:006011* + ID_OUI_FROM_DATABASE=CRYSTAL SEMICONDUCTOR CORP. + +OUI:006012* + ID_OUI_FROM_DATABASE=POWER COMPUTING CORPORATION + +OUI:006013* + ID_OUI_FROM_DATABASE=NETSTAL MASCHINEN AG + +OUI:006014* + ID_OUI_FROM_DATABASE=EDEC CO., LTD. + +OUI:006015* + ID_OUI_FROM_DATABASE=NET2NET CORPORATION + +OUI:006016* + ID_OUI_FROM_DATABASE=CLARIION + +OUI:006017* + ID_OUI_FROM_DATABASE=TOKIMEC INC. + +OUI:006018* + ID_OUI_FROM_DATABASE=STELLAR ONE CORPORATION + +OUI:006019* + ID_OUI_FROM_DATABASE=Roche Diagnostics + +OUI:00601A* + ID_OUI_FROM_DATABASE=KEITHLEY INSTRUMENTS + +OUI:00601B* + ID_OUI_FROM_DATABASE=MESA ELECTRONICS + +OUI:00601C* + ID_OUI_FROM_DATABASE=TELXON CORPORATION + +OUI:00601D* + ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES + +OUI:00601E* + ID_OUI_FROM_DATABASE=SOFTLAB, INC. + +OUI:00601F* + ID_OUI_FROM_DATABASE=STALLION TECHNOLOGIES + +OUI:006020* + ID_OUI_FROM_DATABASE=PIVOTAL NETWORKING, INC. + +OUI:006021* + ID_OUI_FROM_DATABASE=DSC CORPORATION + +OUI:006022* + ID_OUI_FROM_DATABASE=VICOM SYSTEMS, INC. + +OUI:006023* + ID_OUI_FROM_DATABASE=PERICOM SEMICONDUCTOR CORP. + +OUI:006024* + ID_OUI_FROM_DATABASE=GRADIENT TECHNOLOGIES, INC. + +OUI:006025* + ID_OUI_FROM_DATABASE=ACTIVE IMAGING PLC + +OUI:006026* + ID_OUI_FROM_DATABASE=VIKING Modular Solutions + +OUI:006027* + ID_OUI_FROM_DATABASE=Superior Modular Products + +OUI:006028* + ID_OUI_FROM_DATABASE=MACROVISION CORPORATION + +OUI:006029* + ID_OUI_FROM_DATABASE=CARY PERIPHERALS INC. + +OUI:00602A* + ID_OUI_FROM_DATABASE=SYMICRON COMPUTER COMMUNICATIONS, LTD. + +OUI:00602B* + ID_OUI_FROM_DATABASE=PEAK AUDIO + +OUI:00602C* + ID_OUI_FROM_DATABASE=LINX Data Terminals, Inc. + +OUI:00602D* + ID_OUI_FROM_DATABASE=ALERTON TECHNOLOGIES, INC. + +OUI:00602E* + ID_OUI_FROM_DATABASE=CYCLADES CORPORATION + +OUI:00602F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:006030* + ID_OUI_FROM_DATABASE=VILLAGE TRONIC ENTWICKLUNG + +OUI:006031* + ID_OUI_FROM_DATABASE=HRK SYSTEMS + +OUI:006032* + ID_OUI_FROM_DATABASE=I-CUBE, INC. + +OUI:006033* + ID_OUI_FROM_DATABASE=ACUITY IMAGING, INC. + +OUI:006034* + ID_OUI_FROM_DATABASE=ROBERT BOSCH GmbH + +OUI:006035* + ID_OUI_FROM_DATABASE=DALLAS SEMICONDUCTOR, INC. + +OUI:006036* + ID_OUI_FROM_DATABASE=AIT Austrian Institute of Technology GmbH + +OUI:006037* + ID_OUI_FROM_DATABASE=NXP Semiconductors + +OUI:006038* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:006039* + ID_OUI_FROM_DATABASE=SanCom Technology, Inc. + +OUI:00603A* + ID_OUI_FROM_DATABASE=QUICK CONTROLS LTD. + +OUI:00603B* + ID_OUI_FROM_DATABASE=AMTEC spa + +OUI:00603C* + ID_OUI_FROM_DATABASE=HAGIWARA SYS-COM CO., LTD. + +OUI:00603D* + ID_OUI_FROM_DATABASE=3CX + +OUI:00603E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00603F* + ID_OUI_FROM_DATABASE=PATAPSCO DESIGNS + +OUI:006040* + ID_OUI_FROM_DATABASE=NETRO CORP. + +OUI:006041* + ID_OUI_FROM_DATABASE=Yokogawa Electric Corporation + +OUI:006042* + ID_OUI_FROM_DATABASE=TKS (USA), INC. + +OUI:006043* + ID_OUI_FROM_DATABASE=iDirect, INC. + +OUI:006044* + ID_OUI_FROM_DATABASE=LITTON/POLY-SCIENTIFIC + +OUI:006045* + ID_OUI_FROM_DATABASE=PATHLIGHT TECHNOLOGIES + +OUI:006046* + ID_OUI_FROM_DATABASE=VMETRO, INC. + +OUI:006047* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:006048* + ID_OUI_FROM_DATABASE=EMC CORPORATION + +OUI:006049* + ID_OUI_FROM_DATABASE=VINA TECHNOLOGIES + +OUI:00604A* + ID_OUI_FROM_DATABASE=SAIC IDEAS GROUP + +OUI:00604B* + ID_OUI_FROM_DATABASE=Safe-com GmbH & Co. KG + +OUI:00604C* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:00604D* + ID_OUI_FROM_DATABASE=MMC NETWORKS, INC. + +OUI:00604E* + ID_OUI_FROM_DATABASE=CYCLE COMPUTER CORPORATION, INC. + +OUI:00604F* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:006050* + ID_OUI_FROM_DATABASE=INTERNIX INC. + +OUI:006051* + ID_OUI_FROM_DATABASE=QUALITY SEMICONDUCTOR + +OUI:006052* + ID_OUI_FROM_DATABASE=PERIPHERALS ENTERPRISE CO., Ltd. + +OUI:006053* + ID_OUI_FROM_DATABASE=TOYODA MACHINE WORKS, LTD. + +OUI:006054* + ID_OUI_FROM_DATABASE=CONTROLWARE GMBH + +OUI:006055* + ID_OUI_FROM_DATABASE=CORNELL UNIVERSITY + +OUI:006056* + ID_OUI_FROM_DATABASE=NETWORK TOOLS, INC. + +OUI:006057* + ID_OUI_FROM_DATABASE=MURATA MANUFACTURING CO., LTD. + +OUI:006058* + ID_OUI_FROM_DATABASE=COPPER MOUNTAIN COMMUNICATIONS, INC. + +OUI:006059* + ID_OUI_FROM_DATABASE=TECHNICAL COMMUNICATIONS CORP. + +OUI:00605A* + ID_OUI_FROM_DATABASE=CELCORE, INC. + +OUI:00605B* + ID_OUI_FROM_DATABASE=IntraServer Technology, Inc. + +OUI:00605C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00605D* + ID_OUI_FROM_DATABASE=SCANIVALVE CORP. + +OUI:00605E* + ID_OUI_FROM_DATABASE=LIBERTY TECHNOLOGY NETWORKING + +OUI:00605F* + ID_OUI_FROM_DATABASE=NIPPON UNISOFT CORPORATION + +OUI:006060* + ID_OUI_FROM_DATABASE=DAWNING TECHNOLOGIES, INC. + +OUI:006061* + ID_OUI_FROM_DATABASE=WHISTLE COMMUNICATIONS CORP. + +OUI:006062* + ID_OUI_FROM_DATABASE=TELESYNC, INC. + +OUI:006063* + ID_OUI_FROM_DATABASE=PSION DACOM PLC. + +OUI:006064* + ID_OUI_FROM_DATABASE=NETCOMM LIMITED + +OUI:006065* + ID_OUI_FROM_DATABASE=BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH + +OUI:006066* + ID_OUI_FROM_DATABASE=LACROIX Trafic + +OUI:006067* + ID_OUI_FROM_DATABASE=ACER NETXUS INC. + +OUI:006068* + ID_OUI_FROM_DATABASE=Dialogic Corporation + +OUI:006069* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:00606A* + ID_OUI_FROM_DATABASE=MITSUBISHI WIRELESS COMMUNICATIONS. INC. + +OUI:00606B* + ID_OUI_FROM_DATABASE=Synclayer Inc. + +OUI:00606C* + ID_OUI_FROM_DATABASE=ARESCOM + +OUI:00606D* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORP. + +OUI:00606E* + ID_OUI_FROM_DATABASE=DAVICOM SEMICONDUCTOR, INC. + +OUI:00606F* + ID_OUI_FROM_DATABASE=CLARION CORPORATION OF AMERICA + +OUI:006070* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:006071* + ID_OUI_FROM_DATABASE=MIDAS LAB, INC. + +OUI:006072* + ID_OUI_FROM_DATABASE=VXL INSTRUMENTS, LIMITED + +OUI:006073* + ID_OUI_FROM_DATABASE=REDCREEK COMMUNICATIONS, INC. + +OUI:006074* + ID_OUI_FROM_DATABASE=QSC AUDIO PRODUCTS + +OUI:006075* + ID_OUI_FROM_DATABASE=PENTEK, INC. + +OUI:006076* + ID_OUI_FROM_DATABASE=SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS + +OUI:006077* + ID_OUI_FROM_DATABASE=PRISA NETWORKS + +OUI:006078* + ID_OUI_FROM_DATABASE=POWER MEASUREMENT LTD. + +OUI:006079* + ID_OUI_FROM_DATABASE=Mainstream Data, Inc. + +OUI:00607A* + ID_OUI_FROM_DATABASE=DVS GmbH + +OUI:00607B* + ID_OUI_FROM_DATABASE=FORE SYSTEMS, INC. + +OUI:00607C* + ID_OUI_FROM_DATABASE=WaveAccess, Ltd. + +OUI:00607D* + ID_OUI_FROM_DATABASE=SENTIENT NETWORKS INC. + +OUI:00607E* + ID_OUI_FROM_DATABASE=GIGALABS, INC. + +OUI:00607F* + ID_OUI_FROM_DATABASE=AURORA TECHNOLOGIES, INC. + +OUI:006080* + ID_OUI_FROM_DATABASE=MICROTRONIX DATACOM LTD. + +OUI:006081* + ID_OUI_FROM_DATABASE=TV/COM INTERNATIONAL + +OUI:006082* + ID_OUI_FROM_DATABASE=NOVALINK TECHNOLOGIES, INC. + +OUI:006083* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:006084* + ID_OUI_FROM_DATABASE=DIGITAL VIDEO + +OUI:006085* + ID_OUI_FROM_DATABASE=Storage Concepts + +OUI:006086* + ID_OUI_FROM_DATABASE=LOGIC REPLACEMENT TECH. LTD. + +OUI:006087* + ID_OUI_FROM_DATABASE=KANSAI ELECTRIC CO., LTD. + +OUI:006088* + ID_OUI_FROM_DATABASE=WHITE MOUNTAIN DSP, INC. + +OUI:006089* + ID_OUI_FROM_DATABASE=XATA + +OUI:00608A* + ID_OUI_FROM_DATABASE=CITADEL COMPUTER + +OUI:00608B* + ID_OUI_FROM_DATABASE=ConferTech International + +OUI:00608C* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:00608D* + ID_OUI_FROM_DATABASE=UNIPULSE CORP. + +OUI:00608E* + ID_OUI_FROM_DATABASE=HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH + +OUI:00608F* + ID_OUI_FROM_DATABASE=TEKRAM TECHNOLOGY CO., LTD. + +OUI:006090* + ID_OUI_FROM_DATABASE=Artiza Networks Inc + +OUI:006091* + ID_OUI_FROM_DATABASE=FIRST PACIFIC NETWORKS, INC. + +OUI:006092* + ID_OUI_FROM_DATABASE=MICRO/SYS, INC. + +OUI:006093* + ID_OUI_FROM_DATABASE=VARIAN + +OUI:006094* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:006095* + ID_OUI_FROM_DATABASE=ACCU-TIME SYSTEMS, INC. + +OUI:006096* + ID_OUI_FROM_DATABASE=T.S. MICROTECH INC. + +OUI:006097* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:006098* + ID_OUI_FROM_DATABASE=HT COMMUNICATIONS + +OUI:006099* + ID_OUI_FROM_DATABASE=SBE, Inc. + +OUI:00609A* + ID_OUI_FROM_DATABASE=NJK TECHNO CO. + +OUI:00609B* + ID_OUI_FROM_DATABASE=ASTRO-MED, INC. + +OUI:00609C* + ID_OUI_FROM_DATABASE=Perkin-Elmer Incorporated + +OUI:00609D* + ID_OUI_FROM_DATABASE=PMI FOOD EQUIPMENT GROUP + +OUI:00609E* + ID_OUI_FROM_DATABASE=ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS + +OUI:00609F* + ID_OUI_FROM_DATABASE=PHAST CORPORATION + +OUI:0060A0* + ID_OUI_FROM_DATABASE=SWITCHED NETWORK TECHNOLOGIES, INC. + +OUI:0060A1* + ID_OUI_FROM_DATABASE=VPNet, Inc. + +OUI:0060A2* + ID_OUI_FROM_DATABASE=NIHON UNISYS LIMITED CO. + +OUI:0060A3* + ID_OUI_FROM_DATABASE=CONTINUUM TECHNOLOGY CORP. + +OUI:0060A4* + ID_OUI_FROM_DATABASE=GEW Technologies (PTY)Ltd + +OUI:0060A5* + ID_OUI_FROM_DATABASE=PERFORMANCE TELECOM CORP. + +OUI:0060A6* + ID_OUI_FROM_DATABASE=PARTICLE MEASURING SYSTEMS + +OUI:0060A7* + ID_OUI_FROM_DATABASE=MICROSENS GmbH & CO. KG + +OUI:0060A8* + ID_OUI_FROM_DATABASE=TIDOMAT AB + +OUI:0060A9* + ID_OUI_FROM_DATABASE=GESYTEC MbH + +OUI:0060AA* + ID_OUI_FROM_DATABASE=INTELLIGENT DEVICES INC. (IDI) + +OUI:0060AB* + ID_OUI_FROM_DATABASE=LARSCOM INCORPORATED + +OUI:0060AC* + ID_OUI_FROM_DATABASE=RESILIENCE CORPORATION + +OUI:0060AD* + ID_OUI_FROM_DATABASE=MegaChips Corporation + +OUI:0060AE* + ID_OUI_FROM_DATABASE=TRIO INFORMATION SYSTEMS AB + +OUI:0060AF* + ID_OUI_FROM_DATABASE=PACIFIC MICRO DATA, INC. + +OUI:0060B0* + ID_OUI_FROM_DATABASE=HEWLETT-PACKARD CO. + +OUI:0060B1* + ID_OUI_FROM_DATABASE=INPUT/OUTPUT, INC. + +OUI:0060B2* + ID_OUI_FROM_DATABASE=PROCESS CONTROL CORP. + +OUI:0060B3* + ID_OUI_FROM_DATABASE=Z-COM, INC. + +OUI:0060B4* + ID_OUI_FROM_DATABASE=GLENAYRE R&D INC. + +OUI:0060B5* + ID_OUI_FROM_DATABASE=KEBA GmbH + +OUI:0060B6* + ID_OUI_FROM_DATABASE=LAND COMPUTER CO., LTD. + +OUI:0060B7* + ID_OUI_FROM_DATABASE=CHANNELMATIC, INC. + +OUI:0060B8* + ID_OUI_FROM_DATABASE=CORELIS Inc. + +OUI:0060B9* + ID_OUI_FROM_DATABASE=NEC Infrontia Corporation + +OUI:0060BA* + ID_OUI_FROM_DATABASE=SAHARA NETWORKS, INC. + +OUI:0060BB* + ID_OUI_FROM_DATABASE=CABLETRON - NETLINK, INC. + +OUI:0060BC* + ID_OUI_FROM_DATABASE=KeunYoung Electronics & Communication Co., Ltd. + +OUI:0060BD* + ID_OUI_FROM_DATABASE=HUBBELL-PULSECOM + +OUI:0060BE* + ID_OUI_FROM_DATABASE=WEBTRONICS + +OUI:0060BF* + ID_OUI_FROM_DATABASE=MACRAIGOR SYSTEMS, INC. + +OUI:0060C0* + ID_OUI_FROM_DATABASE=Nera Networks AS + +OUI:0060C1* + ID_OUI_FROM_DATABASE=WaveSpan Corporation + +OUI:0060C2* + ID_OUI_FROM_DATABASE=MPL AG + +OUI:0060C3* + ID_OUI_FROM_DATABASE=NETVISION CORPORATION + +OUI:0060C4* + ID_OUI_FROM_DATABASE=SOLITON SYSTEMS K.K. + +OUI:0060C5* + ID_OUI_FROM_DATABASE=ANCOT CORP. + +OUI:0060C6* + ID_OUI_FROM_DATABASE=DCS AG + +OUI:0060C7* + ID_OUI_FROM_DATABASE=AMATI COMMUNICATIONS CORP. + +OUI:0060C8* + ID_OUI_FROM_DATABASE=KUKA WELDING SYSTEMS & ROBOTS + +OUI:0060C9* + ID_OUI_FROM_DATABASE=ControlNet, Inc. + +OUI:0060CA* + ID_OUI_FROM_DATABASE=HARMONIC SYSTEMS INCORPORATED + +OUI:0060CB* + ID_OUI_FROM_DATABASE=HITACHI ZOSEN CORPORATION + +OUI:0060CC* + ID_OUI_FROM_DATABASE=EMTRAK, INCORPORATED + +OUI:0060CD* + ID_OUI_FROM_DATABASE=VideoServer, Inc. + +OUI:0060CE* + ID_OUI_FROM_DATABASE=ACCLAIM COMMUNICATIONS + +OUI:0060CF* + ID_OUI_FROM_DATABASE=ALTEON NETWORKS, INC. + +OUI:0060D0* + ID_OUI_FROM_DATABASE=SNMP RESEARCH INCORPORATED + +OUI:0060D1* + ID_OUI_FROM_DATABASE=CASCADE COMMUNICATIONS + +OUI:0060D2* + ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD. + +OUI:0060D3* + ID_OUI_FROM_DATABASE=AT&T + +OUI:0060D4* + ID_OUI_FROM_DATABASE=ELDAT COMMUNICATION LTD. + +OUI:0060D5* + ID_OUI_FROM_DATABASE=MIYACHI TECHNOS CORP. + +OUI:0060D6* + ID_OUI_FROM_DATABASE=NovAtel Wireless Technologies Ltd. + +OUI:0060D7* + ID_OUI_FROM_DATABASE=ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL) + +OUI:0060D8* + ID_OUI_FROM_DATABASE=ELMIC SYSTEMS, INC. + +OUI:0060D9* + ID_OUI_FROM_DATABASE=TRANSYS NETWORKS INC. + +OUI:0060DA* + ID_OUI_FROM_DATABASE=JBM ELECTRONICS CO. + +OUI:0060DB* + ID_OUI_FROM_DATABASE=NTP ELEKTRONIK A/S + +OUI:0060DC* + ID_OUI_FROM_DATABASE=Toyo Network Systems & System Integration Co. LTD + +OUI:0060DD* + ID_OUI_FROM_DATABASE=MYRICOM, INC. + +OUI:0060DE* + ID_OUI_FROM_DATABASE=Kayser-Threde GmbH + +OUI:0060DF* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:0060E0* + ID_OUI_FROM_DATABASE=AXIOM TECHNOLOGY CO., LTD. + +OUI:0060E1* + ID_OUI_FROM_DATABASE=ORCKIT COMMUNICATIONS LTD. + +OUI:0060E2* + ID_OUI_FROM_DATABASE=QUEST ENGINEERING & DEVELOPMENT + +OUI:0060E3* + ID_OUI_FROM_DATABASE=ARBIN INSTRUMENTS + +OUI:0060E4* + ID_OUI_FROM_DATABASE=COMPUSERVE, INC. + +OUI:0060E5* + ID_OUI_FROM_DATABASE=FUJI AUTOMATION CO., LTD. + +OUI:0060E6* + ID_OUI_FROM_DATABASE=SHOMITI SYSTEMS INCORPORATED + +OUI:0060E7* + ID_OUI_FROM_DATABASE=RANDATA + +OUI:0060E8* + ID_OUI_FROM_DATABASE=HITACHI COMPUTER PRODUCTS (AMERICA), INC. + +OUI:0060E9* + ID_OUI_FROM_DATABASE=ATOP TECHNOLOGIES, INC. + +OUI:0060EA* + ID_OUI_FROM_DATABASE=StreamLogic + +OUI:0060EB* + ID_OUI_FROM_DATABASE=FOURTHTRACK SYSTEMS + +OUI:0060EC* + ID_OUI_FROM_DATABASE=HERMARY OPTO ELECTRONICS INC. + +OUI:0060ED* + ID_OUI_FROM_DATABASE=RICARDO TEST AUTOMATION LTD. + +OUI:0060EE* + ID_OUI_FROM_DATABASE=APOLLO + +OUI:0060EF* + ID_OUI_FROM_DATABASE=FLYTECH TECHNOLOGY CO., LTD. + +OUI:0060F0* + ID_OUI_FROM_DATABASE=JOHNSON & JOHNSON MEDICAL, INC + +OUI:0060F1* + ID_OUI_FROM_DATABASE=EXP COMPUTER, INC. + +OUI:0060F2* + ID_OUI_FROM_DATABASE=LASERGRAPHICS, INC. + +OUI:0060F3* + ID_OUI_FROM_DATABASE=Performance Analysis Broadband, Spirent plc + +OUI:0060F4* + ID_OUI_FROM_DATABASE=ADVANCED COMPUTER SOLUTIONS, Inc. + +OUI:0060F5* + ID_OUI_FROM_DATABASE=ICON WEST, INC. + +OUI:0060F6* + ID_OUI_FROM_DATABASE=NEXTEST COMMUNICATIONS PRODUCTS, INC. + +OUI:0060F7* + ID_OUI_FROM_DATABASE=DATAFUSION SYSTEMS + +OUI:0060F8* + ID_OUI_FROM_DATABASE=Loran International Technologies Inc. + +OUI:0060F9* + ID_OUI_FROM_DATABASE=DIAMOND LANE COMMUNICATIONS + +OUI:0060FA* + ID_OUI_FROM_DATABASE=EDUCATIONAL TECHNOLOGY RESOURCES, INC. + +OUI:0060FB* + ID_OUI_FROM_DATABASE=PACKETEER, INC. + +OUI:0060FC* + ID_OUI_FROM_DATABASE=CONSERVATION THROUGH INNOVATION LTD. + +OUI:0060FD* + ID_OUI_FROM_DATABASE=NetICs, Inc. + +OUI:0060FE* + ID_OUI_FROM_DATABASE=LYNX SYSTEM DEVELOPERS, INC. + +OUI:0060FF* + ID_OUI_FROM_DATABASE=QuVis, Inc. + +OUI:006440* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0064A6* + ID_OUI_FROM_DATABASE=Maquet CardioVascular + +OUI:00664B* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:006B9E* + ID_OUI_FROM_DATABASE=VIZIO Inc + +OUI:006BA0* + ID_OUI_FROM_DATABASE=SHENZHEN UNIVERSAL INTELLISYS PTE LTD + +OUI:006DFB* + ID_OUI_FROM_DATABASE=Vutrix (UK) Ltd + +OUI:0070B0* + ID_OUI_FROM_DATABASE=M/A-COM INC. COMPANIES + +OUI:0070B3* + ID_OUI_FROM_DATABASE=DATA RECALL LTD. + +OUI:00738D* + ID_OUI_FROM_DATABASE=Tinno Mobile Technology Corp + +OUI:0073E0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0075E1* + ID_OUI_FROM_DATABASE=Ampt, LLC + +OUI:00789E* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:007DFA* + ID_OUI_FROM_DATABASE=Volkswagen Group of America + +OUI:007F28* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:008000* + ID_OUI_FROM_DATABASE=MULTITECH SYSTEMS, INC. + +OUI:008001* + ID_OUI_FROM_DATABASE=PERIPHONICS CORPORATION + +OUI:008002* + ID_OUI_FROM_DATABASE=SATELCOM (UK) LTD + +OUI:008003* + ID_OUI_FROM_DATABASE=HYTEC ELECTRONICS LTD. + +OUI:008004* + ID_OUI_FROM_DATABASE=ANTLOW COMMUNICATIONS, LTD. + +OUI:008005* + ID_OUI_FROM_DATABASE=CACTUS COMPUTER INC. + +OUI:008006* + ID_OUI_FROM_DATABASE=COMPUADD CORPORATION + +OUI:008007* + ID_OUI_FROM_DATABASE=DLOG NC-SYSTEME + +OUI:008008* + ID_OUI_FROM_DATABASE=DYNATECH COMPUTER SYSTEMS + +OUI:008009* + ID_OUI_FROM_DATABASE=JUPITER SYSTEMS, INC. + +OUI:00800A* + ID_OUI_FROM_DATABASE=JAPAN COMPUTER CORP. + +OUI:00800B* + ID_OUI_FROM_DATABASE=CSK CORPORATION + +OUI:00800C* + ID_OUI_FROM_DATABASE=VIDECOM LIMITED + +OUI:00800D* + ID_OUI_FROM_DATABASE=VOSSWINKEL F.U. + +OUI:00800E* + ID_OUI_FROM_DATABASE=ATLANTIX CORPORATION + +OUI:00800F* + ID_OUI_FROM_DATABASE=STANDARD MICROSYSTEMS + +OUI:008010* + ID_OUI_FROM_DATABASE=COMMODORE INTERNATIONAL + +OUI:008011* + ID_OUI_FROM_DATABASE=DIGITAL SYSTEMS INT'L. INC. + +OUI:008012* + ID_OUI_FROM_DATABASE=INTEGRATED MEASUREMENT SYSTEMS + +OUI:008013* + ID_OUI_FROM_DATABASE=THOMAS-CONRAD CORPORATION + +OUI:008014* + ID_OUI_FROM_DATABASE=ESPRIT SYSTEMS + +OUI:008015* + ID_OUI_FROM_DATABASE=SEIKO SYSTEMS, INC. + +OUI:008016* + ID_OUI_FROM_DATABASE=WANDEL AND GOLTERMANN + +OUI:008017* + ID_OUI_FROM_DATABASE=PFU LIMITED + +OUI:008018* + ID_OUI_FROM_DATABASE=KOBE STEEL, LTD. + +OUI:008019* + ID_OUI_FROM_DATABASE=DAYNA COMMUNICATIONS, INC. + +OUI:00801A* + ID_OUI_FROM_DATABASE=BELL ATLANTIC + +OUI:00801B* + ID_OUI_FROM_DATABASE=KODIAK TECHNOLOGY + +OUI:00801C* + ID_OUI_FROM_DATABASE=NEWPORT SYSTEMS SOLUTIONS + +OUI:00801D* + ID_OUI_FROM_DATABASE=INTEGRATED INFERENCE MACHINES + +OUI:00801E* + ID_OUI_FROM_DATABASE=XINETRON, INC. + +OUI:00801F* + ID_OUI_FROM_DATABASE=KRUPP ATLAS ELECTRONIK GMBH + +OUI:008020* + ID_OUI_FROM_DATABASE=NETWORK PRODUCTS + +OUI:008021* + ID_OUI_FROM_DATABASE=Alcatel Canada Inc. + +OUI:008022* + ID_OUI_FROM_DATABASE=SCAN-OPTICS + +OUI:008023* + ID_OUI_FROM_DATABASE=INTEGRATED BUSINESS NETWORKS + +OUI:008024* + ID_OUI_FROM_DATABASE=KALPANA, INC. + +OUI:008025* + ID_OUI_FROM_DATABASE=STOLLMANN GMBH + +OUI:008026* + ID_OUI_FROM_DATABASE=NETWORK PRODUCTS CORPORATION + +OUI:008027* + ID_OUI_FROM_DATABASE=ADAPTIVE SYSTEMS, INC. + +OUI:008028* + ID_OUI_FROM_DATABASE=TRADPOST (HK) LTD + +OUI:008029* + ID_OUI_FROM_DATABASE=EAGLE TECHNOLOGY, INC. + +OUI:00802A* + ID_OUI_FROM_DATABASE=TEST SYSTEMS & SIMULATIONS INC + +OUI:00802B* + ID_OUI_FROM_DATABASE=INTEGRATED MARKETING CO + +OUI:00802C* + ID_OUI_FROM_DATABASE=THE SAGE GROUP PLC + +OUI:00802D* + ID_OUI_FROM_DATABASE=XYLOGICS INC + +OUI:00802E* + ID_OUI_FROM_DATABASE=CASTLE ROCK COMPUTING + +OUI:00802F* + ID_OUI_FROM_DATABASE=NATIONAL INSTRUMENTS CORP. + +OUI:008030* + ID_OUI_FROM_DATABASE=NEXUS ELECTRONICS + +OUI:008031* + ID_OUI_FROM_DATABASE=BASYS, CORP. + +OUI:008032* + ID_OUI_FROM_DATABASE=ACCESS CO., LTD. + +OUI:008033* + ID_OUI_FROM_DATABASE=EMS Aviation, Inc. + +OUI:008034* + ID_OUI_FROM_DATABASE=SMT GOUPIL + +OUI:008035* + ID_OUI_FROM_DATABASE=TECHNOLOGY WORKS, INC. + +OUI:008036* + ID_OUI_FROM_DATABASE=REFLEX MANUFACTURING SYSTEMS + +OUI:008037* + ID_OUI_FROM_DATABASE=Ericsson Group + +OUI:008038* + ID_OUI_FROM_DATABASE=DATA RESEARCH & APPLICATIONS + +OUI:008039* + ID_OUI_FROM_DATABASE=ALCATEL STC AUSTRALIA + +OUI:00803A* + ID_OUI_FROM_DATABASE=VARITYPER, INC. + +OUI:00803B* + ID_OUI_FROM_DATABASE=APT COMMUNICATIONS, INC. + +OUI:00803C* + ID_OUI_FROM_DATABASE=TVS ELECTRONICS LTD + +OUI:00803D* + ID_OUI_FROM_DATABASE=SURIGIKEN CO., LTD. + +OUI:00803E* + ID_OUI_FROM_DATABASE=SYNERNETICS + +OUI:00803F* + ID_OUI_FROM_DATABASE=TATUNG COMPANY + +OUI:008040* + ID_OUI_FROM_DATABASE=JOHN FLUKE MANUFACTURING CO. + +OUI:008041* + ID_OUI_FROM_DATABASE=VEB KOMBINAT ROBOTRON + +OUI:008042* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:008043* + ID_OUI_FROM_DATABASE=NETWORLD, INC. + +OUI:008044* + ID_OUI_FROM_DATABASE=SYSTECH COMPUTER CORP. + +OUI:008045* + ID_OUI_FROM_DATABASE=MATSUSHITA ELECTRIC IND. CO + +OUI:008046* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:008047* + ID_OUI_FROM_DATABASE=IN-NET CORP. + +OUI:008048* + ID_OUI_FROM_DATABASE=COMPEX INCORPORATED + +OUI:008049* + ID_OUI_FROM_DATABASE=NISSIN ELECTRIC CO., LTD. + +OUI:00804A* + ID_OUI_FROM_DATABASE=PRO-LOG + +OUI:00804B* + ID_OUI_FROM_DATABASE=EAGLE TECHNOLOGIES PTY.LTD. + +OUI:00804C* + ID_OUI_FROM_DATABASE=CONTEC CO., LTD. + +OUI:00804D* + ID_OUI_FROM_DATABASE=CYCLONE MICROSYSTEMS, INC. + +OUI:00804E* + ID_OUI_FROM_DATABASE=APEX COMPUTER COMPANY + +OUI:00804F* + ID_OUI_FROM_DATABASE=DAIKIN INDUSTRIES, LTD. + +OUI:008050* + ID_OUI_FROM_DATABASE=ZIATECH CORPORATION + +OUI:008051* + ID_OUI_FROM_DATABASE=FIBERMUX + +OUI:008052* + ID_OUI_FROM_DATABASE=TECHNICALLY ELITE CONCEPTS + +OUI:008053* + ID_OUI_FROM_DATABASE=INTELLICOM, INC. + +OUI:008054* + ID_OUI_FROM_DATABASE=FRONTIER TECHNOLOGIES CORP. + +OUI:008055* + ID_OUI_FROM_DATABASE=FERMILAB + +OUI:008056* + ID_OUI_FROM_DATABASE=SPHINX ELEKTRONIK GMBH + +OUI:008057* + ID_OUI_FROM_DATABASE=ADSOFT, LTD. + +OUI:008058* + ID_OUI_FROM_DATABASE=PRINTER SYSTEMS CORPORATION + +OUI:008059* + ID_OUI_FROM_DATABASE=STANLEY ELECTRIC CO., LTD + +OUI:00805A* + ID_OUI_FROM_DATABASE=TULIP COMPUTERS INTERNAT'L B.V + +OUI:00805B* + ID_OUI_FROM_DATABASE=CONDOR SYSTEMS, INC. + +OUI:00805C* + ID_OUI_FROM_DATABASE=AGILIS CORPORATION + +OUI:00805D* + ID_OUI_FROM_DATABASE=CANSTAR + +OUI:00805E* + ID_OUI_FROM_DATABASE=LSI LOGIC CORPORATION + +OUI:00805F* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:008060* + ID_OUI_FROM_DATABASE=NETWORK INTERFACE CORPORATION + +OUI:008061* + ID_OUI_FROM_DATABASE=LITTON SYSTEMS, INC. + +OUI:008062* + ID_OUI_FROM_DATABASE=INTERFACE CO. + +OUI:008063* + ID_OUI_FROM_DATABASE=Hirschmann Automation and Control GmbH + +OUI:008064* + ID_OUI_FROM_DATABASE=WYSE TECHNOLOGY LLC + +OUI:008065* + ID_OUI_FROM_DATABASE=CYBERGRAPHIC SYSTEMS PTY LTD. + +OUI:008066* + ID_OUI_FROM_DATABASE=ARCOM CONTROL SYSTEMS, LTD. + +OUI:008067* + ID_OUI_FROM_DATABASE=SQUARE D COMPANY + +OUI:008068* + ID_OUI_FROM_DATABASE=YAMATECH SCIENTIFIC LTD. + +OUI:008069* + ID_OUI_FROM_DATABASE=COMPUTONE SYSTEMS + +OUI:00806A* + ID_OUI_FROM_DATABASE=ERI (EMPAC RESEARCH INC.) + +OUI:00806B* + ID_OUI_FROM_DATABASE=SCHMID TELECOMMUNICATION + +OUI:00806C* + ID_OUI_FROM_DATABASE=CEGELEC PROJECTS LTD + +OUI:00806D* + ID_OUI_FROM_DATABASE=CENTURY SYSTEMS CORP. + +OUI:00806E* + ID_OUI_FROM_DATABASE=NIPPON STEEL CORPORATION + +OUI:00806F* + ID_OUI_FROM_DATABASE=ONELAN LTD. + +OUI:008070* + ID_OUI_FROM_DATABASE=COMPUTADORAS MICRON + +OUI:008071* + ID_OUI_FROM_DATABASE=SAI TECHNOLOGY + +OUI:008072* + ID_OUI_FROM_DATABASE=MICROPLEX SYSTEMS LTD. + +OUI:008073* + ID_OUI_FROM_DATABASE=DWB ASSOCIATES + +OUI:008074* + ID_OUI_FROM_DATABASE=FISHER CONTROLS + +OUI:008075* + ID_OUI_FROM_DATABASE=PARSYTEC GMBH + +OUI:008076* + ID_OUI_FROM_DATABASE=MCNC + +OUI:008077* + ID_OUI_FROM_DATABASE=BROTHER INDUSTRIES, LTD. + +OUI:008078* + ID_OUI_FROM_DATABASE=PRACTICAL PERIPHERALS, INC. + +OUI:008079* + ID_OUI_FROM_DATABASE=MICROBUS DESIGNS LTD. + +OUI:00807A* + ID_OUI_FROM_DATABASE=AITECH SYSTEMS LTD. + +OUI:00807B* + ID_OUI_FROM_DATABASE=ARTEL COMMUNICATIONS CORP. + +OUI:00807C* + ID_OUI_FROM_DATABASE=FIBERCOM, INC. + +OUI:00807D* + ID_OUI_FROM_DATABASE=EQUINOX SYSTEMS INC. + +OUI:00807E* + ID_OUI_FROM_DATABASE=SOUTHERN PACIFIC LTD. + +OUI:00807F* + ID_OUI_FROM_DATABASE=DY-4 INCORPORATED + +OUI:008080* + ID_OUI_FROM_DATABASE=DATAMEDIA CORPORATION + +OUI:008081* + ID_OUI_FROM_DATABASE=KENDALL SQUARE RESEARCH CORP. + +OUI:008082* + ID_OUI_FROM_DATABASE=PEP MODULAR COMPUTERS GMBH + +OUI:008083* + ID_OUI_FROM_DATABASE=AMDAHL + +OUI:008084* + ID_OUI_FROM_DATABASE=THE CLOUD INC. + +OUI:008085* + ID_OUI_FROM_DATABASE=H-THREE SYSTEMS CORPORATION + +OUI:008086* + ID_OUI_FROM_DATABASE=COMPUTER GENERATION INC. + +OUI:008087* + ID_OUI_FROM_DATABASE=OKI ELECTRIC INDUSTRY CO., LTD + +OUI:008088* + ID_OUI_FROM_DATABASE=VICTOR COMPANY OF JAPAN, LTD. + +OUI:008089* + ID_OUI_FROM_DATABASE=TECNETICS (PTY) LTD. + +OUI:00808A* + ID_OUI_FROM_DATABASE=SUMMIT MICROSYSTEMS CORP. + +OUI:00808B* + ID_OUI_FROM_DATABASE=DACOLL LIMITED + +OUI:00808C* + ID_OUI_FROM_DATABASE=NetScout Systems, Inc. + +OUI:00808D* + ID_OUI_FROM_DATABASE=WESTCOAST TECHNOLOGY B.V. + +OUI:00808E* + ID_OUI_FROM_DATABASE=RADSTONE TECHNOLOGY + +OUI:00808F* + ID_OUI_FROM_DATABASE=C. ITOH ELECTRONICS, INC. + +OUI:008090* + ID_OUI_FROM_DATABASE=MICROTEK INTERNATIONAL, INC. + +OUI:008091* + ID_OUI_FROM_DATABASE=TOKYO ELECTRIC CO.,LTD + +OUI:008092* + ID_OUI_FROM_DATABASE=Silex Technology, Inc. + +OUI:008093* + ID_OUI_FROM_DATABASE=XYRON CORPORATION + +OUI:008094* + ID_OUI_FROM_DATABASE=ALFA LAVAL AUTOMATION AB + +OUI:008095* + ID_OUI_FROM_DATABASE=BASIC MERTON HANDELSGES.M.B.H. + +OUI:008096* + ID_OUI_FROM_DATABASE=HUMAN DESIGNED SYSTEMS, INC. + +OUI:008097* + ID_OUI_FROM_DATABASE=CENTRALP AUTOMATISMES + +OUI:008098* + ID_OUI_FROM_DATABASE=TDK CORPORATION + +OUI:008099* + ID_OUI_FROM_DATABASE=Eaton Industries GmbH + +OUI:00809A* + ID_OUI_FROM_DATABASE=NOVUS NETWORKS LTD + +OUI:00809B* + ID_OUI_FROM_DATABASE=JUSTSYSTEM CORPORATION + +OUI:00809C* + ID_OUI_FROM_DATABASE=LUXCOM, INC. + +OUI:00809D* + ID_OUI_FROM_DATABASE=Commscraft Ltd. + +OUI:00809E* + ID_OUI_FROM_DATABASE=DATUS GMBH + +OUI:00809F* + ID_OUI_FROM_DATABASE=ALCATEL BUSINESS SYSTEMS + +OUI:0080A0* + ID_OUI_FROM_DATABASE=EDISA HEWLETT PACKARD S/A + +OUI:0080A1* + ID_OUI_FROM_DATABASE=MICROTEST, INC. + +OUI:0080A2* + ID_OUI_FROM_DATABASE=CREATIVE ELECTRONIC SYSTEMS + +OUI:0080A3* + ID_OUI_FROM_DATABASE=Lantronix + +OUI:0080A4* + ID_OUI_FROM_DATABASE=LIBERTY ELECTRONICS + +OUI:0080A5* + ID_OUI_FROM_DATABASE=SPEED INTERNATIONAL + +OUI:0080A6* + ID_OUI_FROM_DATABASE=REPUBLIC TECHNOLOGY, INC. + +OUI:0080A7* + ID_OUI_FROM_DATABASE=Honeywell International Inc + +OUI:0080A8* + ID_OUI_FROM_DATABASE=VITACOM CORPORATION + +OUI:0080A9* + ID_OUI_FROM_DATABASE=CLEARPOINT RESEARCH + +OUI:0080AA* + ID_OUI_FROM_DATABASE=MAXPEED + +OUI:0080AB* + ID_OUI_FROM_DATABASE=DUKANE NETWORK INTEGRATION + +OUI:0080AC* + ID_OUI_FROM_DATABASE=IMLOGIX, DIVISION OF GENESYS + +OUI:0080AD* + ID_OUI_FROM_DATABASE=CNET TECHNOLOGY, INC. + +OUI:0080AE* + ID_OUI_FROM_DATABASE=HUGHES NETWORK SYSTEMS + +OUI:0080AF* + ID_OUI_FROM_DATABASE=ALLUMER CO., LTD. + +OUI:0080B0* + ID_OUI_FROM_DATABASE=ADVANCED INFORMATION + +OUI:0080B1* + ID_OUI_FROM_DATABASE=SOFTCOM A/S + +OUI:0080B2* + ID_OUI_FROM_DATABASE=NETWORK EQUIPMENT TECHNOLOGIES + +OUI:0080B3* + ID_OUI_FROM_DATABASE=AVAL DATA CORPORATION + +OUI:0080B4* + ID_OUI_FROM_DATABASE=SOPHIA SYSTEMS + +OUI:0080B5* + ID_OUI_FROM_DATABASE=UNITED NETWORKS INC. + +OUI:0080B6* + ID_OUI_FROM_DATABASE=THEMIS COMPUTER + +OUI:0080B7* + ID_OUI_FROM_DATABASE=STELLAR COMPUTER + +OUI:0080B8* + ID_OUI_FROM_DATABASE=B.U.G. MORISEIKI, INCORPORATED + +OUI:0080B9* + ID_OUI_FROM_DATABASE=ARCHE TECHNOLIGIES INC. + +OUI:0080BA* + ID_OUI_FROM_DATABASE=SPECIALIX (ASIA) PTE, LTD + +OUI:0080BB* + ID_OUI_FROM_DATABASE=HUGHES LAN SYSTEMS + +OUI:0080BC* + ID_OUI_FROM_DATABASE=HITACHI ENGINEERING CO., LTD + +OUI:0080BD* + ID_OUI_FROM_DATABASE=THE FURUKAWA ELECTRIC CO., LTD + +OUI:0080BE* + ID_OUI_FROM_DATABASE=ARIES RESEARCH + +OUI:0080BF* + ID_OUI_FROM_DATABASE=TAKAOKA ELECTRIC MFG. CO. LTD. + +OUI:0080C0* + ID_OUI_FROM_DATABASE=PENRIL DATACOMM + +OUI:0080C1* + ID_OUI_FROM_DATABASE=LANEX CORPORATION + +OUI:0080C2* + ID_OUI_FROM_DATABASE=IEEE 802.1 COMMITTEE + +OUI:0080C3* + ID_OUI_FROM_DATABASE=BICC INFORMATION SYSTEMS & SVC + +OUI:0080C4* + ID_OUI_FROM_DATABASE=DOCUMENT TECHNOLOGIES, INC. + +OUI:0080C5* + ID_OUI_FROM_DATABASE=NOVELLCO DE MEXICO + +OUI:0080C6* + ID_OUI_FROM_DATABASE=NATIONAL DATACOMM CORPORATION + +OUI:0080C7* + ID_OUI_FROM_DATABASE=XIRCOM + +OUI:0080C8* + ID_OUI_FROM_DATABASE=D-LINK SYSTEMS, INC. + +OUI:0080C9* + ID_OUI_FROM_DATABASE=ALBERTA MICROELECTRONIC CENTRE + +OUI:0080CA* + ID_OUI_FROM_DATABASE=NETCOM RESEARCH INCORPORATED + +OUI:0080CB* + ID_OUI_FROM_DATABASE=FALCO DATA PRODUCTS + +OUI:0080CC* + ID_OUI_FROM_DATABASE=MICROWAVE BYPASS SYSTEMS + +OUI:0080CD* + ID_OUI_FROM_DATABASE=MICRONICS COMPUTER, INC. + +OUI:0080CE* + ID_OUI_FROM_DATABASE=BROADCAST TELEVISION SYSTEMS + +OUI:0080CF* + ID_OUI_FROM_DATABASE=EMBEDDED PERFORMANCE INC. + +OUI:0080D0* + ID_OUI_FROM_DATABASE=COMPUTER PERIPHERALS, INC. + +OUI:0080D1* + ID_OUI_FROM_DATABASE=KIMTRON CORPORATION + +OUI:0080D2* + ID_OUI_FROM_DATABASE=SHINNIHONDENKO CO., LTD. + +OUI:0080D3* + ID_OUI_FROM_DATABASE=SHIVA CORP. + +OUI:0080D4* + ID_OUI_FROM_DATABASE=CHASE RESEARCH LTD. + +OUI:0080D5* + ID_OUI_FROM_DATABASE=CADRE TECHNOLOGIES + +OUI:0080D6* + ID_OUI_FROM_DATABASE=NUVOTECH, INC. + +OUI:0080D7* + ID_OUI_FROM_DATABASE=Fantum Engineering + +OUI:0080D8* + ID_OUI_FROM_DATABASE=NETWORK PERIPHERALS INC. + +OUI:0080D9* + ID_OUI_FROM_DATABASE=EMK Elektronik GmbH & Co. KG + +OUI:0080DA* + ID_OUI_FROM_DATABASE=Bruel & Kjaer Sound & Vibration Measurement A/S + +OUI:0080DB* + ID_OUI_FROM_DATABASE=GRAPHON CORPORATION + +OUI:0080DC* + ID_OUI_FROM_DATABASE=PICKER INTERNATIONAL + +OUI:0080DD* + ID_OUI_FROM_DATABASE=GMX INC/GIMIX + +OUI:0080DE* + ID_OUI_FROM_DATABASE=GIPSI S.A. + +OUI:0080DF* + ID_OUI_FROM_DATABASE=ADC CODENOLL TECHNOLOGY CORP. + +OUI:0080E0* + ID_OUI_FROM_DATABASE=XTP SYSTEMS, INC. + +OUI:0080E1* + ID_OUI_FROM_DATABASE=STMICROELECTRONICS + +OUI:0080E2* + ID_OUI_FROM_DATABASE=T.D.I. CO., LTD. + +OUI:0080E3* + ID_OUI_FROM_DATABASE=CORAL NETWORK CORPORATION + +OUI:0080E4* + ID_OUI_FROM_DATABASE=NORTHWEST DIGITAL SYSTEMS, INC + +OUI:0080E5* + ID_OUI_FROM_DATABASE=NetApp, Inc + +OUI:0080E6* + ID_OUI_FROM_DATABASE=PEER NETWORKS, INC. + +OUI:0080E7* + ID_OUI_FROM_DATABASE=LYNWOOD SCIENTIFIC DEV. LTD. + +OUI:0080E8* + ID_OUI_FROM_DATABASE=CUMULUS CORPORATIION + +OUI:0080E9* + ID_OUI_FROM_DATABASE=Madge Ltd. + +OUI:0080EA* + ID_OUI_FROM_DATABASE=ADVA Optical Networking Ltd. + +OUI:0080EB* + ID_OUI_FROM_DATABASE=COMPCONTROL B.V. + +OUI:0080EC* + ID_OUI_FROM_DATABASE=SUPERCOMPUTING SOLUTIONS, INC. + +OUI:0080ED* + ID_OUI_FROM_DATABASE=IQ TECHNOLOGIES, INC. + +OUI:0080EE* + ID_OUI_FROM_DATABASE=THOMSON CSF + +OUI:0080EF* + ID_OUI_FROM_DATABASE=RATIONAL + +OUI:0080F0* + ID_OUI_FROM_DATABASE=Panasonic Communications Co., Ltd. + +OUI:0080F1* + ID_OUI_FROM_DATABASE=OPUS SYSTEMS + +OUI:0080F2* + ID_OUI_FROM_DATABASE=RAYCOM SYSTEMS INC + +OUI:0080F3* + ID_OUI_FROM_DATABASE=SUN ELECTRONICS CORP. + +OUI:0080F4* + ID_OUI_FROM_DATABASE=TELEMECANIQUE ELECTRIQUE + +OUI:0080F5* + ID_OUI_FROM_DATABASE=Quantel Ltd + +OUI:0080F6* + ID_OUI_FROM_DATABASE=SYNERGY MICROSYSTEMS + +OUI:0080F7* + ID_OUI_FROM_DATABASE=ZENITH ELECTRONICS + +OUI:0080F8* + ID_OUI_FROM_DATABASE=MIZAR, INC. + +OUI:0080F9* + ID_OUI_FROM_DATABASE=HEURIKON CORPORATION + +OUI:0080FA* + ID_OUI_FROM_DATABASE=RWT GMBH + +OUI:0080FB* + ID_OUI_FROM_DATABASE=BVM LIMITED + +OUI:0080FC* + ID_OUI_FROM_DATABASE=AVATAR CORPORATION + +OUI:0080FD* + ID_OUI_FROM_DATABASE=EXSCEED CORPRATION + +OUI:0080FE* + ID_OUI_FROM_DATABASE=AZURE TECHNOLOGIES, INC. + +OUI:0080FF* + ID_OUI_FROM_DATABASE=SOC. DE TELEINFORMATIQUE RTC + +OUI:008865* + ID_OUI_FROM_DATABASE=Apple + +OUI:008B43* + ID_OUI_FROM_DATABASE=RFTECH + +OUI:008C10* + ID_OUI_FROM_DATABASE=Black Box Corp. + +OUI:008C54* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:008CFA* + ID_OUI_FROM_DATABASE=Inventec Corporation + +OUI:008D4E* + ID_OUI_FROM_DATABASE=CJSC NII STT + +OUI:008DDA* + ID_OUI_FROM_DATABASE=Link One Co., Ltd. + +OUI:008EF2* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:009000* + ID_OUI_FROM_DATABASE=DIAMOND MULTIMEDIA + +OUI:009001* + ID_OUI_FROM_DATABASE=NISHIMU ELECTRONICS INDUSTRIES CO., LTD. + +OUI:009002* + ID_OUI_FROM_DATABASE=ALLGON AB + +OUI:009003* + ID_OUI_FROM_DATABASE=APLIO + +OUI:009004* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD. + +OUI:009005* + ID_OUI_FROM_DATABASE=PROTECH SYSTEMS CO., LTD. + +OUI:009006* + ID_OUI_FROM_DATABASE=HAMAMATSU PHOTONICS K.K. + +OUI:009007* + ID_OUI_FROM_DATABASE=DOMEX TECHNOLOGY CORP. + +OUI:009008* + ID_OUI_FROM_DATABASE=HanA Systems Inc. + +OUI:009009* + ID_OUI_FROM_DATABASE=I Controls, Inc. + +OUI:00900A* + ID_OUI_FROM_DATABASE=PROTON ELECTRONIC INDUSTRIAL CO., LTD. + +OUI:00900B* + ID_OUI_FROM_DATABASE=LANNER ELECTRONICS, INC. + +OUI:00900C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00900D* + ID_OUI_FROM_DATABASE=Overland Storage Inc. + +OUI:00900E* + ID_OUI_FROM_DATABASE=HANDLINK TECHNOLOGIES, INC. + +OUI:00900F* + ID_OUI_FROM_DATABASE=KAWASAKI HEAVY INDUSTRIES, LTD + +OUI:009010* + ID_OUI_FROM_DATABASE=SIMULATION LABORATORIES, INC. + +OUI:009011* + ID_OUI_FROM_DATABASE=WAVTrace, Inc. + +OUI:009012* + ID_OUI_FROM_DATABASE=GLOBESPAN SEMICONDUCTOR, INC. + +OUI:009013* + ID_OUI_FROM_DATABASE=SAMSAN CORP. + +OUI:009014* + ID_OUI_FROM_DATABASE=ROTORK INSTRUMENTS, LTD. + +OUI:009015* + ID_OUI_FROM_DATABASE=CENTIGRAM COMMUNICATIONS CORP. + +OUI:009016* + ID_OUI_FROM_DATABASE=ZAC + +OUI:009017* + ID_OUI_FROM_DATABASE=Zypcom, Inc + +OUI:009018* + ID_OUI_FROM_DATABASE=ITO ELECTRIC INDUSTRY CO, LTD. + +OUI:009019* + ID_OUI_FROM_DATABASE=HERMES ELECTRONICS CO., LTD. + +OUI:00901A* + ID_OUI_FROM_DATABASE=UNISPHERE SOLUTIONS + +OUI:00901B* + ID_OUI_FROM_DATABASE=DIGITAL CONTROLS + +OUI:00901C* + ID_OUI_FROM_DATABASE=mps Software Gmbh + +OUI:00901D* + ID_OUI_FROM_DATABASE=PEC (NZ) LTD. + +OUI:00901E* + ID_OUI_FROM_DATABASE=Selesta Ingegneria S.p.A. + +OUI:00901F* + ID_OUI_FROM_DATABASE=ADTEC PRODUCTIONS, INC. + +OUI:009020* + ID_OUI_FROM_DATABASE=PHILIPS ANALYTICAL X-RAY B.V. + +OUI:009021* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:009022* + ID_OUI_FROM_DATABASE=IVEX + +OUI:009023* + ID_OUI_FROM_DATABASE=ZILOG INC. + +OUI:009024* + ID_OUI_FROM_DATABASE=PIPELINKS, INC. + +OUI:009025* + ID_OUI_FROM_DATABASE=BAE Systems Australia (Electronic Systems) Pty Ltd + +OUI:009026* + ID_OUI_FROM_DATABASE=ADVANCED SWITCHING COMMUNICATIONS, INC. + +OUI:009027* + ID_OUI_FROM_DATABASE=INTEL CORPORATION + +OUI:009028* + ID_OUI_FROM_DATABASE=NIPPON SIGNAL CO., LTD. + +OUI:009029* + ID_OUI_FROM_DATABASE=CRYPTO AG + +OUI:00902A* + ID_OUI_FROM_DATABASE=COMMUNICATION DEVICES, INC. + +OUI:00902B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00902C* + ID_OUI_FROM_DATABASE=DATA & CONTROL EQUIPMENT LTD. + +OUI:00902D* + ID_OUI_FROM_DATABASE=DATA ELECTRONICS (AUST.) PTY, LTD. + +OUI:00902E* + ID_OUI_FROM_DATABASE=NAMCO LIMITED + +OUI:00902F* + ID_OUI_FROM_DATABASE=NETCORE SYSTEMS, INC. + +OUI:009030* + ID_OUI_FROM_DATABASE=HONEYWELL-DATING + +OUI:009031* + ID_OUI_FROM_DATABASE=MYSTICOM, LTD. + +OUI:009032* + ID_OUI_FROM_DATABASE=PELCOMBE GROUP LTD. + +OUI:009033* + ID_OUI_FROM_DATABASE=INNOVAPHONE AG + +OUI:009034* + ID_OUI_FROM_DATABASE=IMAGIC, INC. + +OUI:009035* + ID_OUI_FROM_DATABASE=ALPHA TELECOM, INC. + +OUI:009036* + ID_OUI_FROM_DATABASE=ens, inc. + +OUI:009037* + ID_OUI_FROM_DATABASE=ACUCOMM, INC. + +OUI:009038* + ID_OUI_FROM_DATABASE=FOUNTAIN TECHNOLOGIES, INC. + +OUI:009039* + ID_OUI_FROM_DATABASE=SHASTA NETWORKS + +OUI:00903A* + ID_OUI_FROM_DATABASE=NIHON MEDIA TOOL INC. + +OUI:00903B* + ID_OUI_FROM_DATABASE=TriEMS Research Lab, Inc. + +OUI:00903C* + ID_OUI_FROM_DATABASE=ATLANTIC NETWORK SYSTEMS + +OUI:00903D* + ID_OUI_FROM_DATABASE=BIOPAC SYSTEMS, INC. + +OUI:00903E* + ID_OUI_FROM_DATABASE=N.V. PHILIPS INDUSTRIAL ACTIVITIES + +OUI:00903F* + ID_OUI_FROM_DATABASE=AZTEC RADIOMEDIA + +OUI:009040* + ID_OUI_FROM_DATABASE=Siemens Network Convergence LLC + +OUI:009041* + ID_OUI_FROM_DATABASE=APPLIED DIGITAL ACCESS + +OUI:009042* + ID_OUI_FROM_DATABASE=ECCS, Inc. + +OUI:009043* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:009044* + ID_OUI_FROM_DATABASE=ASSURED DIGITAL, INC. + +OUI:009045* + ID_OUI_FROM_DATABASE=Marconi Communications + +OUI:009046* + ID_OUI_FROM_DATABASE=DEXDYNE, LTD. + +OUI:009047* + ID_OUI_FROM_DATABASE=GIGA FAST E. LTD. + +OUI:009048* + ID_OUI_FROM_DATABASE=ZEAL CORPORATION + +OUI:009049* + ID_OUI_FROM_DATABASE=ENTRIDIA CORPORATION + +OUI:00904A* + ID_OUI_FROM_DATABASE=CONCUR SYSTEM TECHNOLOGIES + +OUI:00904B* + ID_OUI_FROM_DATABASE=GemTek Technology Co., Ltd. + +OUI:00904C* + ID_OUI_FROM_DATABASE=EPIGRAM, INC. + +OUI:00904D* + ID_OUI_FROM_DATABASE=SPEC S.A. + +OUI:00904E* + ID_OUI_FROM_DATABASE=DELEM BV + +OUI:00904F* + ID_OUI_FROM_DATABASE=ABB POWER T&D COMPANY, INC. + +OUI:009050* + ID_OUI_FROM_DATABASE=TELESTE OY + +OUI:009051* + ID_OUI_FROM_DATABASE=ULTIMATE TECHNOLOGY CORP. + +OUI:009052* + ID_OUI_FROM_DATABASE=SELCOM ELETTRONICA S.R.L. + +OUI:009053* + ID_OUI_FROM_DATABASE=DAEWOO ELECTRONICS CO., LTD. + +OUI:009054* + ID_OUI_FROM_DATABASE=INNOVATIVE SEMICONDUCTORS, INC + +OUI:009055* + ID_OUI_FROM_DATABASE=PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION + +OUI:009056* + ID_OUI_FROM_DATABASE=TELESTREAM, INC. + +OUI:009057* + ID_OUI_FROM_DATABASE=AANetcom, Inc. + +OUI:009058* + ID_OUI_FROM_DATABASE=Ultra Electronics Ltd., Command and Control Systems + +OUI:009059* + ID_OUI_FROM_DATABASE=TELECOM DEVICE K.K. + +OUI:00905A* + ID_OUI_FROM_DATABASE=DEARBORN GROUP, INC. + +OUI:00905B* + ID_OUI_FROM_DATABASE=RAYMOND AND LAE ENGINEERING + +OUI:00905C* + ID_OUI_FROM_DATABASE=EDMI + +OUI:00905D* + ID_OUI_FROM_DATABASE=NETCOM SICHERHEITSTECHNIK GmbH + +OUI:00905E* + ID_OUI_FROM_DATABASE=RAULAND-BORG CORPORATION + +OUI:00905F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:009060* + ID_OUI_FROM_DATABASE=SYSTEM CREATE CORP. + +OUI:009061* + ID_OUI_FROM_DATABASE=PACIFIC RESEARCH & ENGINEERING CORPORATION + +OUI:009062* + ID_OUI_FROM_DATABASE=ICP VORTEX COMPUTERSYSTEME GmbH + +OUI:009063* + ID_OUI_FROM_DATABASE=COHERENT COMMUNICATIONS SYSTEMS CORPORATION + +OUI:009064* + ID_OUI_FROM_DATABASE=Thomson Inc. + +OUI:009065* + ID_OUI_FROM_DATABASE=FINISAR CORPORATION + +OUI:009066* + ID_OUI_FROM_DATABASE=Troika Networks, Inc. + +OUI:009067* + ID_OUI_FROM_DATABASE=WalkAbout Computers, Inc. + +OUI:009068* + ID_OUI_FROM_DATABASE=DVT CORP. + +OUI:009069* + ID_OUI_FROM_DATABASE=JUNIPER NETWORKS, INC. + +OUI:00906A* + ID_OUI_FROM_DATABASE=TURNSTONE SYSTEMS, INC. + +OUI:00906B* + ID_OUI_FROM_DATABASE=APPLIED RESOURCES, INC. + +OUI:00906C* + ID_OUI_FROM_DATABASE=Sartorius Hamburg GmbH + +OUI:00906D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00906E* + ID_OUI_FROM_DATABASE=PRAXON, INC. + +OUI:00906F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:009070* + ID_OUI_FROM_DATABASE=NEO NETWORKS, INC. + +OUI:009071* + ID_OUI_FROM_DATABASE=Applied Innovation Inc. + +OUI:009072* + ID_OUI_FROM_DATABASE=SIMRAD AS + +OUI:009073* + ID_OUI_FROM_DATABASE=GAIO TECHNOLOGY + +OUI:009074* + ID_OUI_FROM_DATABASE=ARGON NETWORKS, INC. + +OUI:009075* + ID_OUI_FROM_DATABASE=NEC DO BRASIL S.A. + +OUI:009076* + ID_OUI_FROM_DATABASE=FMT AIRCRAFT GATE SUPPORT SYSTEMS AB + +OUI:009077* + ID_OUI_FROM_DATABASE=ADVANCED FIBRE COMMUNICATIONS + +OUI:009078* + ID_OUI_FROM_DATABASE=MER TELEMANAGEMENT SOLUTIONS, LTD. + +OUI:009079* + ID_OUI_FROM_DATABASE=ClearOne, Inc. + +OUI:00907A* + ID_OUI_FROM_DATABASE=Spectralink, Inc + +OUI:00907B* + ID_OUI_FROM_DATABASE=E-TECH, INC. + +OUI:00907C* + ID_OUI_FROM_DATABASE=DIGITALCAST, INC. + +OUI:00907D* + ID_OUI_FROM_DATABASE=Lake Communications + +OUI:00907E* + ID_OUI_FROM_DATABASE=VETRONIX CORP. + +OUI:00907F* + ID_OUI_FROM_DATABASE=WatchGuard Technologies, Inc. + +OUI:009080* + ID_OUI_FROM_DATABASE=NOT LIMITED, INC. + +OUI:009081* + ID_OUI_FROM_DATABASE=ALOHA NETWORKS, INC. + +OUI:009082* + ID_OUI_FROM_DATABASE=FORCE INSTITUTE + +OUI:009083* + ID_OUI_FROM_DATABASE=TURBO COMMUNICATION, INC. + +OUI:009084* + ID_OUI_FROM_DATABASE=ATECH SYSTEM + +OUI:009085* + ID_OUI_FROM_DATABASE=GOLDEN ENTERPRISES, INC. + +OUI:009086* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:009087* + ID_OUI_FROM_DATABASE=ITIS + +OUI:009088* + ID_OUI_FROM_DATABASE=BAXALL SECURITY LTD. + +OUI:009089* + ID_OUI_FROM_DATABASE=SOFTCOM MICROSYSTEMS, INC. + +OUI:00908A* + ID_OUI_FROM_DATABASE=BAYLY COMMUNICATIONS, INC. + +OUI:00908B* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:00908C* + ID_OUI_FROM_DATABASE=ETREND ELECTRONICS, INC. + +OUI:00908D* + ID_OUI_FROM_DATABASE=VICKERS ELECTRONICS SYSTEMS + +OUI:00908E* + ID_OUI_FROM_DATABASE=Nortel Networks Broadband Access + +OUI:00908F* + ID_OUI_FROM_DATABASE=AUDIO CODES LTD. + +OUI:009090* + ID_OUI_FROM_DATABASE=I-BUS + +OUI:009091* + ID_OUI_FROM_DATABASE=DigitalScape, Inc. + +OUI:009092* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:009093* + ID_OUI_FROM_DATABASE=NANAO CORPORATION + +OUI:009094* + ID_OUI_FROM_DATABASE=OSPREY TECHNOLOGIES, INC. + +OUI:009095* + ID_OUI_FROM_DATABASE=UNIVERSAL AVIONICS + +OUI:009096* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP. + +OUI:009097* + ID_OUI_FROM_DATABASE=Sycamore Networks + +OUI:009098* + ID_OUI_FROM_DATABASE=SBC DESIGNS, INC. + +OUI:009099* + ID_OUI_FROM_DATABASE=ALLIED TELESIS, K.K. + +OUI:00909A* + ID_OUI_FROM_DATABASE=ONE WORLD SYSTEMS, INC. + +OUI:00909B* + ID_OUI_FROM_DATABASE=MARKEM-IMAJE + +OUI:00909C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00909D* + ID_OUI_FROM_DATABASE=NovaTech Process Solutions, LLC + +OUI:00909E* + ID_OUI_FROM_DATABASE=Critical IO, LLC + +OUI:00909F* + ID_OUI_FROM_DATABASE=DIGI-DATA CORPORATION + +OUI:0090A0* + ID_OUI_FROM_DATABASE=8X8 INC. + +OUI:0090A1* + ID_OUI_FROM_DATABASE=Flying Pig Systems/High End Systems Inc. + +OUI:0090A2* + ID_OUI_FROM_DATABASE=CYBERTAN TECHNOLOGY, INC. + +OUI:0090A3* + ID_OUI_FROM_DATABASE=Corecess Inc. + +OUI:0090A4* + ID_OUI_FROM_DATABASE=ALTIGA NETWORKS + +OUI:0090A5* + ID_OUI_FROM_DATABASE=SPECTRA LOGIC + +OUI:0090A6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090A7* + ID_OUI_FROM_DATABASE=CLIENTEC CORPORATION + +OUI:0090A8* + ID_OUI_FROM_DATABASE=NineTiles Networks, Ltd. + +OUI:0090A9* + ID_OUI_FROM_DATABASE=WESTERN DIGITAL + +OUI:0090AA* + ID_OUI_FROM_DATABASE=INDIGO ACTIVE VISION SYSTEMS LIMITED + +OUI:0090AB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090AC* + ID_OUI_FROM_DATABASE=OPTIVISION, INC. + +OUI:0090AD* + ID_OUI_FROM_DATABASE=ASPECT ELECTRONICS, INC. + +OUI:0090AE* + ID_OUI_FROM_DATABASE=ITALTEL S.p.A. + +OUI:0090AF* + ID_OUI_FROM_DATABASE=J. MORITA MFG. CORP. + +OUI:0090B0* + ID_OUI_FROM_DATABASE=VADEM + +OUI:0090B1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090B2* + ID_OUI_FROM_DATABASE=AVICI SYSTEMS INC. + +OUI:0090B3* + ID_OUI_FROM_DATABASE=AGRANAT SYSTEMS + +OUI:0090B4* + ID_OUI_FROM_DATABASE=WILLOWBROOK TECHNOLOGIES + +OUI:0090B5* + ID_OUI_FROM_DATABASE=NIKON CORPORATION + +OUI:0090B6* + ID_OUI_FROM_DATABASE=FIBEX SYSTEMS + +OUI:0090B7* + ID_OUI_FROM_DATABASE=DIGITAL LIGHTWAVE, INC. + +OUI:0090B8* + ID_OUI_FROM_DATABASE=ROHDE & SCHWARZ GMBH & CO. KG + +OUI:0090B9* + ID_OUI_FROM_DATABASE=BERAN INSTRUMENTS LTD. + +OUI:0090BA* + ID_OUI_FROM_DATABASE=VALID NETWORKS, INC. + +OUI:0090BB* + ID_OUI_FROM_DATABASE=TAINET COMMUNICATION SYSTEM Corp. + +OUI:0090BC* + ID_OUI_FROM_DATABASE=TELEMANN CO., LTD. + +OUI:0090BD* + ID_OUI_FROM_DATABASE=OMNIA COMMUNICATIONS, INC. + +OUI:0090BE* + ID_OUI_FROM_DATABASE=IBC/INTEGRATED BUSINESS COMPUTERS + +OUI:0090BF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090C0* + ID_OUI_FROM_DATABASE=K.J. LAW ENGINEERS, INC. + +OUI:0090C1* + ID_OUI_FROM_DATABASE=Peco II, Inc. + +OUI:0090C2* + ID_OUI_FROM_DATABASE=JK microsystems, Inc. + +OUI:0090C3* + ID_OUI_FROM_DATABASE=TOPIC SEMICONDUCTOR CORP. + +OUI:0090C4* + ID_OUI_FROM_DATABASE=JAVELIN SYSTEMS, INC. + +OUI:0090C5* + ID_OUI_FROM_DATABASE=INTERNET MAGIC, INC. + +OUI:0090C6* + ID_OUI_FROM_DATABASE=OPTIM SYSTEMS, INC. + +OUI:0090C7* + ID_OUI_FROM_DATABASE=ICOM INC. + +OUI:0090C8* + ID_OUI_FROM_DATABASE=WAVERIDER COMMUNICATIONS (CANADA) INC. + +OUI:0090C9* + ID_OUI_FROM_DATABASE=DPAC Technologies + +OUI:0090CA* + ID_OUI_FROM_DATABASE=ACCORD VIDEO TELECOMMUNICATIONS, LTD. + +OUI:0090CB* + ID_OUI_FROM_DATABASE=Wireless OnLine, Inc. + +OUI:0090CC* + ID_OUI_FROM_DATABASE=Planex Communications + +OUI:0090CD* + ID_OUI_FROM_DATABASE=ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A. + +OUI:0090CE* + ID_OUI_FROM_DATABASE=TETRA GmbH + +OUI:0090CF* + ID_OUI_FROM_DATABASE=NORTEL + +OUI:0090D0* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:0090D1* + ID_OUI_FROM_DATABASE=LEICHU ENTERPRISE CO., LTD. + +OUI:0090D2* + ID_OUI_FROM_DATABASE=ARTEL VIDEO SYSTEMS + +OUI:0090D3* + ID_OUI_FROM_DATABASE=GIESECKE & DEVRIENT GmbH + +OUI:0090D4* + ID_OUI_FROM_DATABASE=BindView Development Corp. + +OUI:0090D5* + ID_OUI_FROM_DATABASE=EUPHONIX, INC. + +OUI:0090D6* + ID_OUI_FROM_DATABASE=CRYSTAL GROUP + +OUI:0090D7* + ID_OUI_FROM_DATABASE=NetBoost Corp. + +OUI:0090D8* + ID_OUI_FROM_DATABASE=WHITECROSS SYSTEMS + +OUI:0090D9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090DA* + ID_OUI_FROM_DATABASE=DYNARC, INC. + +OUI:0090DB* + ID_OUI_FROM_DATABASE=NEXT LEVEL COMMUNICATIONS + +OUI:0090DC* + ID_OUI_FROM_DATABASE=TECO INFORMATION SYSTEMS + +OUI:0090DD* + ID_OUI_FROM_DATABASE=MIHARU COMMUNICATIONS Inc + +OUI:0090DE* + ID_OUI_FROM_DATABASE=CARDKEY SYSTEMS, INC. + +OUI:0090DF* + ID_OUI_FROM_DATABASE=MITSUBISHI CHEMICAL AMERICA, INC. + +OUI:0090E0* + ID_OUI_FROM_DATABASE=SYSTRAN CORP. + +OUI:0090E1* + ID_OUI_FROM_DATABASE=TELENA S.P.A. + +OUI:0090E2* + ID_OUI_FROM_DATABASE=DISTRIBUTED PROCESSING TECHNOLOGY + +OUI:0090E3* + ID_OUI_FROM_DATABASE=AVEX ELECTRONICS INC. + +OUI:0090E4* + ID_OUI_FROM_DATABASE=NEC AMERICA, INC. + +OUI:0090E5* + ID_OUI_FROM_DATABASE=TEKNEMA, INC. + +OUI:0090E6* + ID_OUI_FROM_DATABASE=ALi Corporation + +OUI:0090E7* + ID_OUI_FROM_DATABASE=HORSCH ELEKTRONIK AG + +OUI:0090E8* + ID_OUI_FROM_DATABASE=MOXA TECHNOLOGIES CORP., LTD. + +OUI:0090E9* + ID_OUI_FROM_DATABASE=JANZ COMPUTER AG + +OUI:0090EA* + ID_OUI_FROM_DATABASE=ALPHA TECHNOLOGIES, INC. + +OUI:0090EB* + ID_OUI_FROM_DATABASE=SENTRY TELECOM SYSTEMS + +OUI:0090EC* + ID_OUI_FROM_DATABASE=PYRESCOM + +OUI:0090ED* + ID_OUI_FROM_DATABASE=CENTRAL SYSTEM RESEARCH CO., LTD. + +OUI:0090EE* + ID_OUI_FROM_DATABASE=PERSONAL COMMUNICATIONS TECHNOLOGIES + +OUI:0090EF* + ID_OUI_FROM_DATABASE=INTEGRIX, INC. + +OUI:0090F0* + ID_OUI_FROM_DATABASE=Harmonic Video Systems Ltd. + +OUI:0090F1* + ID_OUI_FROM_DATABASE=DOT HILL SYSTEMS CORPORATION + +OUI:0090F2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0090F3* + ID_OUI_FROM_DATABASE=ASPECT COMMUNICATIONS + +OUI:0090F4* + ID_OUI_FROM_DATABASE=LIGHTNING INSTRUMENTATION + +OUI:0090F5* + ID_OUI_FROM_DATABASE=CLEVO CO. + +OUI:0090F6* + ID_OUI_FROM_DATABASE=ESCALATE NETWORKS, INC. + +OUI:0090F7* + ID_OUI_FROM_DATABASE=NBASE COMMUNICATIONS LTD. + +OUI:0090F8* + ID_OUI_FROM_DATABASE=MEDIATRIX TELECOM + +OUI:0090F9* + ID_OUI_FROM_DATABASE=LEITCH + +OUI:0090FA* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:0090FB* + ID_OUI_FROM_DATABASE=PORTWELL, INC. + +OUI:0090FC* + ID_OUI_FROM_DATABASE=NETWORK COMPUTING DEVICES + +OUI:0090FD* + ID_OUI_FROM_DATABASE=CopperCom, Inc. + +OUI:0090FE* + ID_OUI_FROM_DATABASE=ELECOM CO., LTD. (LANEED DIV.) + +OUI:0090FF* + ID_OUI_FROM_DATABASE=TELLUS TECHNOLOGY INC. + +OUI:0091D6* + ID_OUI_FROM_DATABASE=Crystal Group, Inc. + +OUI:0091FA* + ID_OUI_FROM_DATABASE=Synapse Product Development + +OUI:0092FA* + ID_OUI_FROM_DATABASE=SHENZHEN WISKY TECHNOLOGY CO.,LTD + +OUI:009363* + ID_OUI_FROM_DATABASE=Uni-Link Technology Co., Ltd. + +OUI:009569* + ID_OUI_FROM_DATABASE=LSD Science and Technology Co.,Ltd. + +OUI:0097FF* + ID_OUI_FROM_DATABASE=Heimann Sensor GmbH + +OUI:009C02* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:009D8E* + ID_OUI_FROM_DATABASE=CARDIAC RECORDERS, INC. + +OUI:00A000* + ID_OUI_FROM_DATABASE=CENTILLION NETWORKS, INC. + +OUI:00A001* + ID_OUI_FROM_DATABASE=DRS Signal Solutions + +OUI:00A002* + ID_OUI_FROM_DATABASE=LEEDS & NORTHRUP AUSTRALIA PTY LTD + +OUI:00A003* + ID_OUI_FROM_DATABASE=Siemens Switzerland Ltd., I B T HVP + +OUI:00A004* + ID_OUI_FROM_DATABASE=NETPOWER, INC. + +OUI:00A005* + ID_OUI_FROM_DATABASE=DANIEL INSTRUMENTS, LTD. + +OUI:00A006* + ID_OUI_FROM_DATABASE=IMAGE DATA PROCESSING SYSTEM GROUP + +OUI:00A007* + ID_OUI_FROM_DATABASE=APEXX TECHNOLOGY, INC. + +OUI:00A008* + ID_OUI_FROM_DATABASE=NETCORP + +OUI:00A009* + ID_OUI_FROM_DATABASE=WHITETREE NETWORK + +OUI:00A00A* + ID_OUI_FROM_DATABASE=Airspan + +OUI:00A00B* + ID_OUI_FROM_DATABASE=COMPUTEX CO., LTD. + +OUI:00A00C* + ID_OUI_FROM_DATABASE=KINGMAX TECHNOLOGY, INC. + +OUI:00A00D* + ID_OUI_FROM_DATABASE=THE PANDA PROJECT + +OUI:00A00E* + ID_OUI_FROM_DATABASE=VISUAL NETWORKS, INC. + +OUI:00A00F* + ID_OUI_FROM_DATABASE=Broadband Technologies + +OUI:00A010* + ID_OUI_FROM_DATABASE=SYSLOGIC DATENTECHNIK AG + +OUI:00A011* + ID_OUI_FROM_DATABASE=MUTOH INDUSTRIES LTD. + +OUI:00A012* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:00A013* + ID_OUI_FROM_DATABASE=TELTREND LTD. + +OUI:00A014* + ID_OUI_FROM_DATABASE=CSIR + +OUI:00A015* + ID_OUI_FROM_DATABASE=WYLE + +OUI:00A016* + ID_OUI_FROM_DATABASE=MICROPOLIS CORP. + +OUI:00A017* + ID_OUI_FROM_DATABASE=J B M CORPORATION + +OUI:00A018* + ID_OUI_FROM_DATABASE=CREATIVE CONTROLLERS, INC. + +OUI:00A019* + ID_OUI_FROM_DATABASE=NEBULA CONSULTANTS, INC. + +OUI:00A01A* + ID_OUI_FROM_DATABASE=BINAR ELEKTRONIK AB + +OUI:00A01B* + ID_OUI_FROM_DATABASE=PREMISYS COMMUNICATIONS, INC. + +OUI:00A01C* + ID_OUI_FROM_DATABASE=NASCENT NETWORKS CORPORATION + +OUI:00A01D* + ID_OUI_FROM_DATABASE=SIXNET + +OUI:00A01E* + ID_OUI_FROM_DATABASE=EST CORPORATION + +OUI:00A01F* + ID_OUI_FROM_DATABASE=TRICORD SYSTEMS, INC. + +OUI:00A020* + ID_OUI_FROM_DATABASE=CITICORP/TTI + +OUI:00A021* + ID_OUI_FROM_DATABASE=General Dynamics + +OUI:00A022* + ID_OUI_FROM_DATABASE=CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING + +OUI:00A023* + ID_OUI_FROM_DATABASE=APPLIED CREATIVE TECHNOLOGY, INC. + +OUI:00A024* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:00A025* + ID_OUI_FROM_DATABASE=REDCOM LABS INC. + +OUI:00A026* + ID_OUI_FROM_DATABASE=TELDAT, S.A. + +OUI:00A027* + ID_OUI_FROM_DATABASE=FIREPOWER SYSTEMS, INC. + +OUI:00A028* + ID_OUI_FROM_DATABASE=CONNER PERIPHERALS + +OUI:00A029* + ID_OUI_FROM_DATABASE=COULTER CORPORATION + +OUI:00A02A* + ID_OUI_FROM_DATABASE=TRANCELL SYSTEMS + +OUI:00A02B* + ID_OUI_FROM_DATABASE=TRANSITIONS RESEARCH CORP. + +OUI:00A02C* + ID_OUI_FROM_DATABASE=interWAVE Communications + +OUI:00A02D* + ID_OUI_FROM_DATABASE=1394 Trade Association + +OUI:00A02E* + ID_OUI_FROM_DATABASE=BRAND COMMUNICATIONS, LTD. + +OUI:00A02F* + ID_OUI_FROM_DATABASE=PIRELLI CAVI + +OUI:00A030* + ID_OUI_FROM_DATABASE=CAPTOR NV/SA + +OUI:00A031* + ID_OUI_FROM_DATABASE=HAZELTINE CORPORATION, MS 1-17 + +OUI:00A032* + ID_OUI_FROM_DATABASE=GES SINGAPORE PTE. LTD. + +OUI:00A033* + ID_OUI_FROM_DATABASE=imc MeBsysteme GmbH + +OUI:00A034* + ID_OUI_FROM_DATABASE=AXEL + +OUI:00A035* + ID_OUI_FROM_DATABASE=CYLINK CORPORATION + +OUI:00A036* + ID_OUI_FROM_DATABASE=APPLIED NETWORK TECHNOLOGY + +OUI:00A037* + ID_OUI_FROM_DATABASE=Mindray DS USA, Inc. + +OUI:00A038* + ID_OUI_FROM_DATABASE=EMAIL ELECTRONICS + +OUI:00A039* + ID_OUI_FROM_DATABASE=ROSS TECHNOLOGY, INC. + +OUI:00A03A* + ID_OUI_FROM_DATABASE=KUBOTEK CORPORATION + +OUI:00A03B* + ID_OUI_FROM_DATABASE=TOSHIN ELECTRIC CO., LTD. + +OUI:00A03C* + ID_OUI_FROM_DATABASE=EG&G NUCLEAR INSTRUMENTS + +OUI:00A03D* + ID_OUI_FROM_DATABASE=OPTO-22 + +OUI:00A03E* + ID_OUI_FROM_DATABASE=ATM FORUM + +OUI:00A03F* + ID_OUI_FROM_DATABASE=COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C + +OUI:00A040* + ID_OUI_FROM_DATABASE=Apple + +OUI:00A041* + ID_OUI_FROM_DATABASE=INFICON + +OUI:00A042* + ID_OUI_FROM_DATABASE=SPUR PRODUCTS CORP. + +OUI:00A043* + ID_OUI_FROM_DATABASE=AMERICAN TECHNOLOGY LABS, INC. + +OUI:00A044* + ID_OUI_FROM_DATABASE=NTT IT CO., LTD. + +OUI:00A045* + ID_OUI_FROM_DATABASE=PHOENIX CONTACT GMBH & CO. + +OUI:00A046* + ID_OUI_FROM_DATABASE=SCITEX CORP. LTD. + +OUI:00A047* + ID_OUI_FROM_DATABASE=INTEGRATED FITNESS CORP. + +OUI:00A048* + ID_OUI_FROM_DATABASE=QUESTECH, LTD. + +OUI:00A049* + ID_OUI_FROM_DATABASE=DIGITECH INDUSTRIES, INC. + +OUI:00A04A* + ID_OUI_FROM_DATABASE=NISSHIN ELECTRIC CO., LTD. + +OUI:00A04B* + ID_OUI_FROM_DATABASE=TFL LAN INC. + +OUI:00A04C* + ID_OUI_FROM_DATABASE=INNOVATIVE SYSTEMS & TECHNOLOGIES, INC. + +OUI:00A04D* + ID_OUI_FROM_DATABASE=EDA INSTRUMENTS, INC. + +OUI:00A04E* + ID_OUI_FROM_DATABASE=VOELKER TECHNOLOGIES, INC. + +OUI:00A04F* + ID_OUI_FROM_DATABASE=AMERITEC CORP. + +OUI:00A050* + ID_OUI_FROM_DATABASE=CYPRESS SEMICONDUCTOR + +OUI:00A051* + ID_OUI_FROM_DATABASE=ANGIA COMMUNICATIONS. INC. + +OUI:00A052* + ID_OUI_FROM_DATABASE=STANILITE ELECTRONICS PTY. LTD + +OUI:00A053* + ID_OUI_FROM_DATABASE=COMPACT DEVICES, INC. + +OUI:00A055* + ID_OUI_FROM_DATABASE=Data Device Corporation + +OUI:00A056* + ID_OUI_FROM_DATABASE=MICROPROSS + +OUI:00A057* + ID_OUI_FROM_DATABASE=LANCOM Systems GmbH + +OUI:00A058* + ID_OUI_FROM_DATABASE=GLORY, LTD. + +OUI:00A059* + ID_OUI_FROM_DATABASE=HAMILTON HALLMARK + +OUI:00A05A* + ID_OUI_FROM_DATABASE=KOFAX IMAGE PRODUCTS + +OUI:00A05B* + ID_OUI_FROM_DATABASE=MARQUIP, INC. + +OUI:00A05C* + ID_OUI_FROM_DATABASE=INVENTORY CONVERSION, INC./ + +OUI:00A05D* + ID_OUI_FROM_DATABASE=CS COMPUTER SYSTEME GmbH + +OUI:00A05E* + ID_OUI_FROM_DATABASE=MYRIAD LOGIC INC. + +OUI:00A05F* + ID_OUI_FROM_DATABASE=BTG Electronics Design BV + +OUI:00A060* + ID_OUI_FROM_DATABASE=ACER PERIPHERALS, INC. + +OUI:00A061* + ID_OUI_FROM_DATABASE=PURITAN BENNETT + +OUI:00A062* + ID_OUI_FROM_DATABASE=AES PRODATA + +OUI:00A063* + ID_OUI_FROM_DATABASE=JRL SYSTEMS, INC. + +OUI:00A064* + ID_OUI_FROM_DATABASE=KVB/ANALECT + +OUI:00A065* + ID_OUI_FROM_DATABASE=Symantec Corporation + +OUI:00A066* + ID_OUI_FROM_DATABASE=ISA CO., LTD. + +OUI:00A067* + ID_OUI_FROM_DATABASE=NETWORK SERVICES GROUP + +OUI:00A068* + ID_OUI_FROM_DATABASE=BHP LIMITED + +OUI:00A069* + ID_OUI_FROM_DATABASE=Symmetricom, Inc. + +OUI:00A06A* + ID_OUI_FROM_DATABASE=Verilink Corporation + +OUI:00A06B* + ID_OUI_FROM_DATABASE=DMS DORSCH MIKROSYSTEM GMBH + +OUI:00A06C* + ID_OUI_FROM_DATABASE=SHINDENGEN ELECTRIC MFG. CO., LTD. + +OUI:00A06D* + ID_OUI_FROM_DATABASE=MANNESMANN TALLY CORPORATION + +OUI:00A06E* + ID_OUI_FROM_DATABASE=AUSTRON, INC. + +OUI:00A06F* + ID_OUI_FROM_DATABASE=THE APPCON GROUP, INC. + +OUI:00A070* + ID_OUI_FROM_DATABASE=COASTCOM + +OUI:00A071* + ID_OUI_FROM_DATABASE=VIDEO LOTTERY TECHNOLOGIES,INC + +OUI:00A072* + ID_OUI_FROM_DATABASE=OVATION SYSTEMS LTD. + +OUI:00A073* + ID_OUI_FROM_DATABASE=COM21, INC. + +OUI:00A074* + ID_OUI_FROM_DATABASE=PERCEPTION TECHNOLOGY + +OUI:00A075* + ID_OUI_FROM_DATABASE=MICRON TECHNOLOGY, INC. + +OUI:00A076* + ID_OUI_FROM_DATABASE=CARDWARE LAB, INC. + +OUI:00A077* + ID_OUI_FROM_DATABASE=FUJITSU NEXION, INC. + +OUI:00A078* + ID_OUI_FROM_DATABASE=Marconi Communications + +OUI:00A079* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC (USA), INC. + +OUI:00A07A* + ID_OUI_FROM_DATABASE=ADVANCED PERIPHERALS TECHNOLOGIES, INC. + +OUI:00A07B* + ID_OUI_FROM_DATABASE=DAWN COMPUTER INCORPORATION + +OUI:00A07C* + ID_OUI_FROM_DATABASE=TONYANG NYLON CO., LTD. + +OUI:00A07D* + ID_OUI_FROM_DATABASE=SEEQ TECHNOLOGY, INC. + +OUI:00A07E* + ID_OUI_FROM_DATABASE=AVID TECHNOLOGY, INC. + +OUI:00A07F* + ID_OUI_FROM_DATABASE=GSM-SYNTEL, LTD. + +OUI:00A080* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:00A081* + ID_OUI_FROM_DATABASE=ALCATEL DATA NETWORKS + +OUI:00A082* + ID_OUI_FROM_DATABASE=NKT ELEKTRONIK A/S + +OUI:00A083* + ID_OUI_FROM_DATABASE=ASIMMPHONY TURKEY + +OUI:00A084* + ID_OUI_FROM_DATABASE=Dataplex Pty Ltd + +OUI:00A086* + ID_OUI_FROM_DATABASE=AMBER WAVE SYSTEMS, INC. + +OUI:00A087* + ID_OUI_FROM_DATABASE=Zarlink Semiconductor Ltd. + +OUI:00A088* + ID_OUI_FROM_DATABASE=ESSENTIAL COMMUNICATIONS + +OUI:00A089* + ID_OUI_FROM_DATABASE=XPOINT TECHNOLOGIES, INC. + +OUI:00A08A* + ID_OUI_FROM_DATABASE=BROOKTROUT TECHNOLOGY, INC. + +OUI:00A08B* + ID_OUI_FROM_DATABASE=ASTON ELECTRONIC DESIGNS LTD. + +OUI:00A08C* + ID_OUI_FROM_DATABASE=MultiMedia LANs, Inc. + +OUI:00A08D* + ID_OUI_FROM_DATABASE=JACOMO CORPORATION + +OUI:00A08E* + ID_OUI_FROM_DATABASE=Check Point Software Technologies + +OUI:00A08F* + ID_OUI_FROM_DATABASE=DESKNET SYSTEMS, INC. + +OUI:00A090* + ID_OUI_FROM_DATABASE=TimeStep Corporation + +OUI:00A091* + ID_OUI_FROM_DATABASE=APPLICOM INTERNATIONAL + +OUI:00A092* + ID_OUI_FROM_DATABASE=H. BOLLMANN MANUFACTURERS, LTD + +OUI:00A093* + ID_OUI_FROM_DATABASE=B/E AEROSPACE, Inc. + +OUI:00A094* + ID_OUI_FROM_DATABASE=COMSAT CORPORATION + +OUI:00A095* + ID_OUI_FROM_DATABASE=ACACIA NETWORKS, INC. + +OUI:00A096* + ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO., LTD. + +OUI:00A097* + ID_OUI_FROM_DATABASE=JC INFORMATION SYSTEMS + +OUI:00A098* + ID_OUI_FROM_DATABASE=NetApp + +OUI:00A099* + ID_OUI_FROM_DATABASE=K-NET LTD. + +OUI:00A09A* + ID_OUI_FROM_DATABASE=NIHON KOHDEN AMERICA + +OUI:00A09B* + ID_OUI_FROM_DATABASE=QPSX COMMUNICATIONS, LTD. + +OUI:00A09C* + ID_OUI_FROM_DATABASE=Xyplex, Inc. + +OUI:00A09D* + ID_OUI_FROM_DATABASE=JOHNATHON FREEMAN TECHNOLOGIES + +OUI:00A09E* + ID_OUI_FROM_DATABASE=ICTV + +OUI:00A09F* + ID_OUI_FROM_DATABASE=COMMVISION CORP. + +OUI:00A0A0* + ID_OUI_FROM_DATABASE=COMPACT DATA, LTD. + +OUI:00A0A1* + ID_OUI_FROM_DATABASE=EPIC DATA INC. + +OUI:00A0A2* + ID_OUI_FROM_DATABASE=DIGICOM S.P.A. + +OUI:00A0A3* + ID_OUI_FROM_DATABASE=RELIABLE POWER METERS + +OUI:00A0A4* + ID_OUI_FROM_DATABASE=MICROS SYSTEMS, INC. + +OUI:00A0A5* + ID_OUI_FROM_DATABASE=TEKNOR MICROSYSTEME, INC. + +OUI:00A0A6* + ID_OUI_FROM_DATABASE=M.I. SYSTEMS, K.K. + +OUI:00A0A7* + ID_OUI_FROM_DATABASE=VORAX CORPORATION + +OUI:00A0A8* + ID_OUI_FROM_DATABASE=RENEX CORPORATION + +OUI:00A0A9* + ID_OUI_FROM_DATABASE=NAVTEL COMMUNICATIONS INC. + +OUI:00A0AA* + ID_OUI_FROM_DATABASE=SPACELABS MEDICAL + +OUI:00A0AB* + ID_OUI_FROM_DATABASE=NETCS INFORMATIONSTECHNIK GMBH + +OUI:00A0AC* + ID_OUI_FROM_DATABASE=GILAT SATELLITE NETWORKS, LTD. + +OUI:00A0AD* + ID_OUI_FROM_DATABASE=MARCONI SPA + +OUI:00A0AE* + ID_OUI_FROM_DATABASE=NUCOM SYSTEMS, INC. + +OUI:00A0AF* + ID_OUI_FROM_DATABASE=WMS INDUSTRIES + +OUI:00A0B0* + ID_OUI_FROM_DATABASE=I-O DATA DEVICE, INC. + +OUI:00A0B1* + ID_OUI_FROM_DATABASE=FIRST VIRTUAL CORPORATION + +OUI:00A0B2* + ID_OUI_FROM_DATABASE=SHIMA SEIKI + +OUI:00A0B3* + ID_OUI_FROM_DATABASE=ZYKRONIX + +OUI:00A0B4* + ID_OUI_FROM_DATABASE=TEXAS MICROSYSTEMS, INC. + +OUI:00A0B5* + ID_OUI_FROM_DATABASE=3H TECHNOLOGY + +OUI:00A0B6* + ID_OUI_FROM_DATABASE=SANRITZ AUTOMATION CO., LTD. + +OUI:00A0B7* + ID_OUI_FROM_DATABASE=CORDANT, INC. + +OUI:00A0B8* + ID_OUI_FROM_DATABASE=SYMBIOS LOGIC INC. + +OUI:00A0B9* + ID_OUI_FROM_DATABASE=EAGLE TECHNOLOGY, INC. + +OUI:00A0BA* + ID_OUI_FROM_DATABASE=PATTON ELECTRONICS CO. + +OUI:00A0BB* + ID_OUI_FROM_DATABASE=HILAN GMBH + +OUI:00A0BC* + ID_OUI_FROM_DATABASE=VIASAT, INCORPORATED + +OUI:00A0BD* + ID_OUI_FROM_DATABASE=I-TECH CORP. + +OUI:00A0BE* + ID_OUI_FROM_DATABASE=INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP + +OUI:00A0BF* + ID_OUI_FROM_DATABASE=WIRELESS DATA GROUP MOTOROLA + +OUI:00A0C0* + ID_OUI_FROM_DATABASE=DIGITAL LINK CORP. + +OUI:00A0C1* + ID_OUI_FROM_DATABASE=ORTIVUS MEDICAL AB + +OUI:00A0C2* + ID_OUI_FROM_DATABASE=R.A. SYSTEMS CO., LTD. + +OUI:00A0C3* + ID_OUI_FROM_DATABASE=UNICOMPUTER GMBH + +OUI:00A0C4* + ID_OUI_FROM_DATABASE=CRISTIE ELECTRONICS LTD. + +OUI:00A0C5* + ID_OUI_FROM_DATABASE=ZYXEL COMMUNICATION + +OUI:00A0C6* + ID_OUI_FROM_DATABASE=QUALCOMM INCORPORATED + +OUI:00A0C7* + ID_OUI_FROM_DATABASE=TADIRAN TELECOMMUNICATIONS + +OUI:00A0C8* + ID_OUI_FROM_DATABASE=ADTRAN INC. + +OUI:00A0C9* + ID_OUI_FROM_DATABASE=INTEL CORPORATION - HF1-06 + +OUI:00A0CA* + ID_OUI_FROM_DATABASE=FUJITSU DENSO LTD. + +OUI:00A0CB* + ID_OUI_FROM_DATABASE=ARK TELECOMMUNICATIONS, INC. + +OUI:00A0CC* + ID_OUI_FROM_DATABASE=LITE-ON COMMUNICATIONS, INC. + +OUI:00A0CD* + ID_OUI_FROM_DATABASE=DR. JOHANNES HEIDENHAIN GmbH + +OUI:00A0CE* + ID_OUI_FROM_DATABASE=Ecessa + +OUI:00A0CF* + ID_OUI_FROM_DATABASE=SOTAS, INC. + +OUI:00A0D0* + ID_OUI_FROM_DATABASE=TEN X TECHNOLOGY, INC. + +OUI:00A0D1* + ID_OUI_FROM_DATABASE=INVENTEC CORPORATION + +OUI:00A0D2* + ID_OUI_FROM_DATABASE=ALLIED TELESIS INTERNATIONAL CORPORATION + +OUI:00A0D3* + ID_OUI_FROM_DATABASE=INSTEM COMPUTER SYSTEMS, LTD. + +OUI:00A0D4* + ID_OUI_FROM_DATABASE=RADIOLAN, INC. + +OUI:00A0D5* + ID_OUI_FROM_DATABASE=SIERRA WIRELESS INC. + +OUI:00A0D6* + ID_OUI_FROM_DATABASE=SBE, INC. + +OUI:00A0D7* + ID_OUI_FROM_DATABASE=KASTEN CHASE APPLIED RESEARCH + +OUI:00A0D8* + ID_OUI_FROM_DATABASE=SPECTRA - TEK + +OUI:00A0D9* + ID_OUI_FROM_DATABASE=CONVEX COMPUTER CORPORATION + +OUI:00A0DA* + ID_OUI_FROM_DATABASE=INTEGRATED SYSTEMS Technology, Inc. + +OUI:00A0DB* + ID_OUI_FROM_DATABASE=FISHER & PAYKEL PRODUCTION + +OUI:00A0DC* + ID_OUI_FROM_DATABASE=O.N. ELECTRONIC CO., LTD. + +OUI:00A0DD* + ID_OUI_FROM_DATABASE=AZONIX CORPORATION + +OUI:00A0DE* + ID_OUI_FROM_DATABASE=YAMAHA CORPORATION + +OUI:00A0DF* + ID_OUI_FROM_DATABASE=STS TECHNOLOGIES, INC. + +OUI:00A0E0* + ID_OUI_FROM_DATABASE=TENNYSON TECHNOLOGIES PTY LTD + +OUI:00A0E1* + ID_OUI_FROM_DATABASE=WESTPORT RESEARCH ASSOCIATES, INC. + +OUI:00A0E2* + ID_OUI_FROM_DATABASE=Keisokugiken Corporation + +OUI:00A0E3* + ID_OUI_FROM_DATABASE=XKL SYSTEMS CORP. + +OUI:00A0E4* + ID_OUI_FROM_DATABASE=OPTIQUEST + +OUI:00A0E5* + ID_OUI_FROM_DATABASE=NHC COMMUNICATIONS + +OUI:00A0E6* + ID_OUI_FROM_DATABASE=DIALOGIC CORPORATION + +OUI:00A0E7* + ID_OUI_FROM_DATABASE=CENTRAL DATA CORPORATION + +OUI:00A0E8* + ID_OUI_FROM_DATABASE=REUTERS HOLDINGS PLC + +OUI:00A0E9* + ID_OUI_FROM_DATABASE=ELECTRONIC RETAILING SYSTEMS INTERNATIONAL + +OUI:00A0EA* + ID_OUI_FROM_DATABASE=ETHERCOM CORP. + +OUI:00A0EB* + ID_OUI_FROM_DATABASE=Encore Networks, Inc. + +OUI:00A0EC* + ID_OUI_FROM_DATABASE=TRANSMITTON LTD. + +OUI:00A0ED* + ID_OUI_FROM_DATABASE=Brooks Automation, Inc. + +OUI:00A0EE* + ID_OUI_FROM_DATABASE=NASHOBA NETWORKS + +OUI:00A0EF* + ID_OUI_FROM_DATABASE=LUCIDATA LTD. + +OUI:00A0F0* + ID_OUI_FROM_DATABASE=TORONTO MICROELECTRONICS INC. + +OUI:00A0F1* + ID_OUI_FROM_DATABASE=MTI + +OUI:00A0F2* + ID_OUI_FROM_DATABASE=INFOTEK COMMUNICATIONS, INC. + +OUI:00A0F3* + ID_OUI_FROM_DATABASE=STAUBLI + +OUI:00A0F4* + ID_OUI_FROM_DATABASE=GE + +OUI:00A0F5* + ID_OUI_FROM_DATABASE=RADGUARD LTD. + +OUI:00A0F6* + ID_OUI_FROM_DATABASE=AutoGas Systems Inc. + +OUI:00A0F7* + ID_OUI_FROM_DATABASE=V.I COMPUTER CORP. + +OUI:00A0F8* + ID_OUI_FROM_DATABASE=SYMBOL TECHNOLOGIES, INC. + +OUI:00A0F9* + ID_OUI_FROM_DATABASE=BINTEC COMMUNICATIONS GMBH + +OUI:00A0FA* + ID_OUI_FROM_DATABASE=Marconi Communication GmbH + +OUI:00A0FB* + ID_OUI_FROM_DATABASE=TORAY ENGINEERING CO., LTD. + +OUI:00A0FC* + ID_OUI_FROM_DATABASE=IMAGE SCIENCES, INC. + +OUI:00A0FD* + ID_OUI_FROM_DATABASE=SCITEX DIGITAL PRINTING, INC. + +OUI:00A0FE* + ID_OUI_FROM_DATABASE=BOSTON TECHNOLOGY, INC. + +OUI:00A0FF* + ID_OUI_FROM_DATABASE=TELLABS OPERATIONS, INC. + +OUI:00A1DE* + ID_OUI_FROM_DATABASE=ShenZhen ShiHua Technology CO.,LTD + +OUI:00A2DA* + ID_OUI_FROM_DATABASE=INAT GmbH + +OUI:00A2FF* + ID_OUI_FROM_DATABASE=abatec group AG + +OUI:00AA00* + ID_OUI_FROM_DATABASE=INTEL CORPORATION + +OUI:00AA01* + ID_OUI_FROM_DATABASE=INTEL CORPORATION + +OUI:00AA02* + ID_OUI_FROM_DATABASE=INTEL CORPORATION + +OUI:00AA3C* + ID_OUI_FROM_DATABASE=OLIVETTI TELECOM SPA (OLTECO) + +OUI:00AA70* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:00B009* + ID_OUI_FROM_DATABASE=Grass Valley Group + +OUI:00B017* + ID_OUI_FROM_DATABASE=InfoGear Technology Corp. + +OUI:00B019* + ID_OUI_FROM_DATABASE=UTC CCS + +OUI:00B01C* + ID_OUI_FROM_DATABASE=Westport Technologies + +OUI:00B01E* + ID_OUI_FROM_DATABASE=Rantic Labs, Inc. + +OUI:00B02A* + ID_OUI_FROM_DATABASE=ORSYS GmbH + +OUI:00B02D* + ID_OUI_FROM_DATABASE=ViaGate Technologies, Inc. + +OUI:00B033* + ID_OUI_FROM_DATABASE=OAO "Izhevskiy radiozavod" + +OUI:00B03B* + ID_OUI_FROM_DATABASE=HiQ Networks + +OUI:00B048* + ID_OUI_FROM_DATABASE=Marconi Communications Inc. + +OUI:00B04A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00B052* + ID_OUI_FROM_DATABASE=Atheros Communications + +OUI:00B064* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00B069* + ID_OUI_FROM_DATABASE=Honewell Oy + +OUI:00B06D* + ID_OUI_FROM_DATABASE=Jones Futurex Inc. + +OUI:00B080* + ID_OUI_FROM_DATABASE=Mannesmann Ipulsys B.V. + +OUI:00B086* + ID_OUI_FROM_DATABASE=LocSoft Limited + +OUI:00B08E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00B091* + ID_OUI_FROM_DATABASE=Transmeta Corp. + +OUI:00B094* + ID_OUI_FROM_DATABASE=Alaris, Inc. + +OUI:00B09A* + ID_OUI_FROM_DATABASE=Morrow Technologies Corp. + +OUI:00B09D* + ID_OUI_FROM_DATABASE=Point Grey Research Inc. + +OUI:00B0AC* + ID_OUI_FROM_DATABASE=SIAE-Microelettronica S.p.A. + +OUI:00B0AE* + ID_OUI_FROM_DATABASE=Symmetricom + +OUI:00B0B3* + ID_OUI_FROM_DATABASE=Xstreamis PLC + +OUI:00B0C2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00B0C7* + ID_OUI_FROM_DATABASE=Tellabs Operations, Inc. + +OUI:00B0CE* + ID_OUI_FROM_DATABASE=TECHNOLOGY RESCUE + +OUI:00B0D0* + ID_OUI_FROM_DATABASE=Dell Computer Corp. + +OUI:00B0DB* + ID_OUI_FROM_DATABASE=Nextcell, Inc. + +OUI:00B0DF* + ID_OUI_FROM_DATABASE=Starboard Storage Systems + +OUI:00B0E7* + ID_OUI_FROM_DATABASE=British Federal Ltd. + +OUI:00B0EC* + ID_OUI_FROM_DATABASE=EACEM + +OUI:00B0EE* + ID_OUI_FROM_DATABASE=Ajile Systems, Inc. + +OUI:00B0F0* + ID_OUI_FROM_DATABASE=CALY NETWORKS + +OUI:00B0F5* + ID_OUI_FROM_DATABASE=NetWorth Technologies, Inc. + +OUI:00B338* + ID_OUI_FROM_DATABASE=Kontron Design Manufacturing Services (M) Sdn. Bhd + +OUI:00B342* + ID_OUI_FROM_DATABASE=MacroSAN Technologies Co., Ltd. + +OUI:00B56D* + ID_OUI_FROM_DATABASE=David Electronics Co., LTD. + +OUI:00B5D6* + ID_OUI_FROM_DATABASE=Omnibit Inc. + +OUI:00B78D* + ID_OUI_FROM_DATABASE=Nanjing Shining Electric Automation Co., Ltd + +OUI:00B9F6* + ID_OUI_FROM_DATABASE=Shenzhen Super Rich Electronics Co.,Ltd + +OUI:00BAC0* + ID_OUI_FROM_DATABASE=Biometric Access Company + +OUI:00BB01* + ID_OUI_FROM_DATABASE=OCTOTHORPE CORP. + +OUI:00BB8E* + ID_OUI_FROM_DATABASE=HME Co., Ltd. + +OUI:00BBF0* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00BD27* + ID_OUI_FROM_DATABASE=Exar Corp. + +OUI:00BD3A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:00BF15* + ID_OUI_FROM_DATABASE=Genetec Inc. + +OUI:00C000* + ID_OUI_FROM_DATABASE=LANOPTICS, LTD. + +OUI:00C001* + ID_OUI_FROM_DATABASE=DIATEK PATIENT MANAGMENT + +OUI:00C002* + ID_OUI_FROM_DATABASE=SERCOMM CORPORATION + +OUI:00C003* + ID_OUI_FROM_DATABASE=GLOBALNET COMMUNICATIONS + +OUI:00C004* + ID_OUI_FROM_DATABASE=JAPAN BUSINESS COMPUTER CO.LTD + +OUI:00C005* + ID_OUI_FROM_DATABASE=LIVINGSTON ENTERPRISES, INC. + +OUI:00C006* + ID_OUI_FROM_DATABASE=NIPPON AVIONICS CO., LTD. + +OUI:00C007* + ID_OUI_FROM_DATABASE=PINNACLE DATA SYSTEMS, INC. + +OUI:00C008* + ID_OUI_FROM_DATABASE=SECO SRL + +OUI:00C009* + ID_OUI_FROM_DATABASE=KT TECHNOLOGY (S) PTE LTD + +OUI:00C00A* + ID_OUI_FROM_DATABASE=MICRO CRAFT + +OUI:00C00B* + ID_OUI_FROM_DATABASE=NORCONTROL A.S. + +OUI:00C00C* + ID_OUI_FROM_DATABASE=RELIA TECHNOLGIES + +OUI:00C00D* + ID_OUI_FROM_DATABASE=ADVANCED LOGIC RESEARCH, INC. + +OUI:00C00E* + ID_OUI_FROM_DATABASE=PSITECH, INC. + +OUI:00C00F* + ID_OUI_FROM_DATABASE=QUANTUM SOFTWARE SYSTEMS LTD. + +OUI:00C010* + ID_OUI_FROM_DATABASE=HIRAKAWA HEWTECH CORP. + +OUI:00C011* + ID_OUI_FROM_DATABASE=INTERACTIVE COMPUTING DEVICES + +OUI:00C012* + ID_OUI_FROM_DATABASE=NETSPAN CORPORATION + +OUI:00C013* + ID_OUI_FROM_DATABASE=NETRIX + +OUI:00C014* + ID_OUI_FROM_DATABASE=TELEMATICS CALABASAS INT'L,INC + +OUI:00C015* + ID_OUI_FROM_DATABASE=NEW MEDIA CORPORATION + +OUI:00C016* + ID_OUI_FROM_DATABASE=ELECTRONIC THEATRE CONTROLS + +OUI:00C017* + ID_OUI_FROM_DATABASE=Fluke Corporation + +OUI:00C018* + ID_OUI_FROM_DATABASE=LANART CORPORATION + +OUI:00C019* + ID_OUI_FROM_DATABASE=LEAP TECHNOLOGY, INC. + +OUI:00C01A* + ID_OUI_FROM_DATABASE=COROMETRICS MEDICAL SYSTEMS + +OUI:00C01B* + ID_OUI_FROM_DATABASE=SOCKET COMMUNICATIONS, INC. + +OUI:00C01C* + ID_OUI_FROM_DATABASE=INTERLINK COMMUNICATIONS LTD. + +OUI:00C01D* + ID_OUI_FROM_DATABASE=GRAND JUNCTION NETWORKS, INC. + +OUI:00C01E* + ID_OUI_FROM_DATABASE=LA FRANCAISE DES JEUX + +OUI:00C01F* + ID_OUI_FROM_DATABASE=S.E.R.C.E.L. + +OUI:00C020* + ID_OUI_FROM_DATABASE=ARCO ELECTRONIC, CONTROL LTD. + +OUI:00C021* + ID_OUI_FROM_DATABASE=NETEXPRESS + +OUI:00C022* + ID_OUI_FROM_DATABASE=LASERMASTER TECHNOLOGIES, INC. + +OUI:00C023* + ID_OUI_FROM_DATABASE=TUTANKHAMON ELECTRONICS + +OUI:00C024* + ID_OUI_FROM_DATABASE=EDEN SISTEMAS DE COMPUTACAO SA + +OUI:00C025* + ID_OUI_FROM_DATABASE=DATAPRODUCTS CORPORATION + +OUI:00C026* + ID_OUI_FROM_DATABASE=LANS TECHNOLOGY CO., LTD. + +OUI:00C027* + ID_OUI_FROM_DATABASE=CIPHER SYSTEMS, INC. + +OUI:00C028* + ID_OUI_FROM_DATABASE=JASCO CORPORATION + +OUI:00C029* + ID_OUI_FROM_DATABASE=Nexans Deutschland GmbH - ANS + +OUI:00C02A* + ID_OUI_FROM_DATABASE=OHKURA ELECTRIC CO., LTD. + +OUI:00C02B* + ID_OUI_FROM_DATABASE=GERLOFF GESELLSCHAFT FUR + +OUI:00C02C* + ID_OUI_FROM_DATABASE=CENTRUM COMMUNICATIONS, INC. + +OUI:00C02D* + ID_OUI_FROM_DATABASE=FUJI PHOTO FILM CO., LTD. + +OUI:00C02E* + ID_OUI_FROM_DATABASE=NETWIZ + +OUI:00C02F* + ID_OUI_FROM_DATABASE=OKUMA CORPORATION + +OUI:00C030* + ID_OUI_FROM_DATABASE=INTEGRATED ENGINEERING B. V. + +OUI:00C031* + ID_OUI_FROM_DATABASE=DESIGN RESEARCH SYSTEMS, INC. + +OUI:00C032* + ID_OUI_FROM_DATABASE=I-CUBED LIMITED + +OUI:00C033* + ID_OUI_FROM_DATABASE=TELEBIT COMMUNICATIONS APS + +OUI:00C034* + ID_OUI_FROM_DATABASE=TRANSACTION NETWORK + +OUI:00C035* + ID_OUI_FROM_DATABASE=QUINTAR COMPANY + +OUI:00C036* + ID_OUI_FROM_DATABASE=RAYTECH ELECTRONIC CORP. + +OUI:00C037* + ID_OUI_FROM_DATABASE=DYNATEM + +OUI:00C038* + ID_OUI_FROM_DATABASE=RASTER IMAGE PROCESSING SYSTEM + +OUI:00C039* + ID_OUI_FROM_DATABASE=Teridian Semiconductor Corporation + +OUI:00C03A* + ID_OUI_FROM_DATABASE=MEN-MIKRO ELEKTRONIK GMBH + +OUI:00C03B* + ID_OUI_FROM_DATABASE=MULTIACCESS COMPUTING CORP. + +OUI:00C03C* + ID_OUI_FROM_DATABASE=TOWER TECH S.R.L. + +OUI:00C03D* + ID_OUI_FROM_DATABASE=WIESEMANN & THEIS GMBH + +OUI:00C03E* + ID_OUI_FROM_DATABASE=FA. GEBR. HELLER GMBH + +OUI:00C03F* + ID_OUI_FROM_DATABASE=STORES AUTOMATED SYSTEMS, INC. + +OUI:00C040* + ID_OUI_FROM_DATABASE=ECCI + +OUI:00C041* + ID_OUI_FROM_DATABASE=DIGITAL TRANSMISSION SYSTEMS + +OUI:00C042* + ID_OUI_FROM_DATABASE=DATALUX CORP. + +OUI:00C043* + ID_OUI_FROM_DATABASE=STRATACOM + +OUI:00C044* + ID_OUI_FROM_DATABASE=EMCOM CORPORATION + +OUI:00C045* + ID_OUI_FROM_DATABASE=ISOLATION SYSTEMS, LTD. + +OUI:00C046* + ID_OUI_FROM_DATABASE=Blue Chip Technology Ltd + +OUI:00C047* + ID_OUI_FROM_DATABASE=UNIMICRO SYSTEMS, INC. + +OUI:00C048* + ID_OUI_FROM_DATABASE=BAY TECHNICAL ASSOCIATES + +OUI:00C049* + ID_OUI_FROM_DATABASE=U.S. ROBOTICS, INC. + +OUI:00C04A* + ID_OUI_FROM_DATABASE=GROUP 2000 AG + +OUI:00C04B* + ID_OUI_FROM_DATABASE=CREATIVE MICROSYSTEMS + +OUI:00C04C* + ID_OUI_FROM_DATABASE=DEPARTMENT OF FOREIGN AFFAIRS + +OUI:00C04D* + ID_OUI_FROM_DATABASE=MITEC, INC. + +OUI:00C04E* + ID_OUI_FROM_DATABASE=COMTROL CORPORATION + +OUI:00C04F* + ID_OUI_FROM_DATABASE=DELL COMPUTER CORPORATION + +OUI:00C050* + ID_OUI_FROM_DATABASE=TOYO DENKI SEIZO K.K. + +OUI:00C051* + ID_OUI_FROM_DATABASE=ADVANCED INTEGRATION RESEARCH + +OUI:00C052* + ID_OUI_FROM_DATABASE=BURR-BROWN + +OUI:00C053* + ID_OUI_FROM_DATABASE=Aspect Software Inc. + +OUI:00C054* + ID_OUI_FROM_DATABASE=NETWORK PERIPHERALS, LTD. + +OUI:00C055* + ID_OUI_FROM_DATABASE=MODULAR COMPUTING TECHNOLOGIES + +OUI:00C056* + ID_OUI_FROM_DATABASE=SOMELEC + +OUI:00C057* + ID_OUI_FROM_DATABASE=MYCO ELECTRONICS + +OUI:00C058* + ID_OUI_FROM_DATABASE=DATAEXPERT CORP. + +OUI:00C059* + ID_OUI_FROM_DATABASE=DENSO CORPORATION + +OUI:00C05A* + ID_OUI_FROM_DATABASE=SEMAPHORE COMMUNICATIONS CORP. + +OUI:00C05B* + ID_OUI_FROM_DATABASE=NETWORKS NORTHWEST, INC. + +OUI:00C05C* + ID_OUI_FROM_DATABASE=ELONEX PLC + +OUI:00C05D* + ID_OUI_FROM_DATABASE=L&N TECHNOLOGIES + +OUI:00C05E* + ID_OUI_FROM_DATABASE=VARI-LITE, INC. + +OUI:00C05F* + ID_OUI_FROM_DATABASE=FINE-PAL COMPANY LIMITED + +OUI:00C060* + ID_OUI_FROM_DATABASE=ID SCANDINAVIA AS + +OUI:00C061* + ID_OUI_FROM_DATABASE=SOLECTEK CORPORATION + +OUI:00C062* + ID_OUI_FROM_DATABASE=IMPULSE TECHNOLOGY + +OUI:00C063* + ID_OUI_FROM_DATABASE=MORNING STAR TECHNOLOGIES, INC + +OUI:00C064* + ID_OUI_FROM_DATABASE=GENERAL DATACOMM IND. INC. + +OUI:00C065* + ID_OUI_FROM_DATABASE=SCOPE COMMUNICATIONS, INC. + +OUI:00C066* + ID_OUI_FROM_DATABASE=DOCUPOINT, INC. + +OUI:00C067* + ID_OUI_FROM_DATABASE=UNITED BARCODE INDUSTRIES + +OUI:00C068* + ID_OUI_FROM_DATABASE=HME Clear-Com LTD. + +OUI:00C069* + ID_OUI_FROM_DATABASE=Axxcelera Broadband Wireless + +OUI:00C06A* + ID_OUI_FROM_DATABASE=ZAHNER-ELEKTRIK GMBH & CO. KG + +OUI:00C06B* + ID_OUI_FROM_DATABASE=OSI PLUS CORPORATION + +OUI:00C06C* + ID_OUI_FROM_DATABASE=SVEC COMPUTER CORP. + +OUI:00C06D* + ID_OUI_FROM_DATABASE=BOCA RESEARCH, INC. + +OUI:00C06E* + ID_OUI_FROM_DATABASE=HAFT TECHNOLOGY, INC. + +OUI:00C06F* + ID_OUI_FROM_DATABASE=KOMATSU LTD. + +OUI:00C070* + ID_OUI_FROM_DATABASE=SECTRA SECURE-TRANSMISSION AB + +OUI:00C071* + ID_OUI_FROM_DATABASE=AREANEX COMMUNICATIONS, INC. + +OUI:00C072* + ID_OUI_FROM_DATABASE=KNX LTD. + +OUI:00C073* + ID_OUI_FROM_DATABASE=XEDIA CORPORATION + +OUI:00C074* + ID_OUI_FROM_DATABASE=TOYODA AUTOMATIC LOOM + +OUI:00C075* + ID_OUI_FROM_DATABASE=XANTE CORPORATION + +OUI:00C076* + ID_OUI_FROM_DATABASE=I-DATA INTERNATIONAL A-S + +OUI:00C077* + ID_OUI_FROM_DATABASE=DAEWOO TELECOM LTD. + +OUI:00C078* + ID_OUI_FROM_DATABASE=COMPUTER SYSTEMS ENGINEERING + +OUI:00C079* + ID_OUI_FROM_DATABASE=FONSYS CO.,LTD. + +OUI:00C07A* + ID_OUI_FROM_DATABASE=PRIVA B.V. + +OUI:00C07B* + ID_OUI_FROM_DATABASE=ASCEND COMMUNICATIONS, INC. + +OUI:00C07C* + ID_OUI_FROM_DATABASE=HIGHTECH INFORMATION + +OUI:00C07D* + ID_OUI_FROM_DATABASE=RISC DEVELOPMENTS LTD. + +OUI:00C07E* + ID_OUI_FROM_DATABASE=KUBOTA CORPORATION ELECTRONIC + +OUI:00C07F* + ID_OUI_FROM_DATABASE=NUPON COMPUTING CORP. + +OUI:00C080* + ID_OUI_FROM_DATABASE=NETSTAR, INC. + +OUI:00C081* + ID_OUI_FROM_DATABASE=METRODATA LTD. + +OUI:00C082* + ID_OUI_FROM_DATABASE=MOORE PRODUCTS CO. + +OUI:00C083* + ID_OUI_FROM_DATABASE=TRACE MOUNTAIN PRODUCTS, INC. + +OUI:00C084* + ID_OUI_FROM_DATABASE=DATA LINK CORP. LTD. + +OUI:00C085* + ID_OUI_FROM_DATABASE=ELECTRONICS FOR IMAGING, INC. + +OUI:00C086* + ID_OUI_FROM_DATABASE=THE LYNK CORPORATION + +OUI:00C087* + ID_OUI_FROM_DATABASE=UUNET TECHNOLOGIES, INC. + +OUI:00C088* + ID_OUI_FROM_DATABASE=EKF ELEKTRONIK GMBH + +OUI:00C089* + ID_OUI_FROM_DATABASE=TELINDUS DISTRIBUTION + +OUI:00C08A* + ID_OUI_FROM_DATABASE=Lauterbach GmbH + +OUI:00C08B* + ID_OUI_FROM_DATABASE=RISQ MODULAR SYSTEMS, INC. + +OUI:00C08C* + ID_OUI_FROM_DATABASE=PERFORMANCE TECHNOLOGIES, INC. + +OUI:00C08D* + ID_OUI_FROM_DATABASE=TRONIX PRODUCT DEVELOPMENT + +OUI:00C08E* + ID_OUI_FROM_DATABASE=NETWORK INFORMATION TECHNOLOGY + +OUI:00C08F* + ID_OUI_FROM_DATABASE=Panasonic Electric Works Co., Ltd. + +OUI:00C090* + ID_OUI_FROM_DATABASE=PRAIM S.R.L. + +OUI:00C091* + ID_OUI_FROM_DATABASE=JABIL CIRCUIT, INC. + +OUI:00C092* + ID_OUI_FROM_DATABASE=MENNEN MEDICAL INC. + +OUI:00C093* + ID_OUI_FROM_DATABASE=ALTA RESEARCH CORP. + +OUI:00C094* + ID_OUI_FROM_DATABASE=VMX INC. + +OUI:00C095* + ID_OUI_FROM_DATABASE=ZNYX + +OUI:00C096* + ID_OUI_FROM_DATABASE=TAMURA CORPORATION + +OUI:00C097* + ID_OUI_FROM_DATABASE=ARCHIPEL SA + +OUI:00C098* + ID_OUI_FROM_DATABASE=CHUNTEX ELECTRONIC CO., LTD. + +OUI:00C099* + ID_OUI_FROM_DATABASE=YOSHIKI INDUSTRIAL CO.,LTD. + +OUI:00C09A* + ID_OUI_FROM_DATABASE=PHOTONICS CORPORATION + +OUI:00C09B* + ID_OUI_FROM_DATABASE=RELIANCE COMM/TEC, R-TEC + +OUI:00C09C* + ID_OUI_FROM_DATABASE=HIOKI E.E. CORPORATION + +OUI:00C09D* + ID_OUI_FROM_DATABASE=DISTRIBUTED SYSTEMS INT'L, INC + +OUI:00C09E* + ID_OUI_FROM_DATABASE=CACHE COMPUTERS, INC. + +OUI:00C09F* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER, INC. + +OUI:00C0A0* + ID_OUI_FROM_DATABASE=ADVANCE MICRO RESEARCH, INC. + +OUI:00C0A1* + ID_OUI_FROM_DATABASE=TOKYO DENSHI SEKEI CO. + +OUI:00C0A2* + ID_OUI_FROM_DATABASE=INTERMEDIUM A/S + +OUI:00C0A3* + ID_OUI_FROM_DATABASE=DUAL ENTERPRISES CORPORATION + +OUI:00C0A4* + ID_OUI_FROM_DATABASE=UNIGRAF OY + +OUI:00C0A5* + ID_OUI_FROM_DATABASE=DICKENS DATA SYSTEMS + +OUI:00C0A6* + ID_OUI_FROM_DATABASE=EXICOM AUSTRALIA PTY. LTD + +OUI:00C0A7* + ID_OUI_FROM_DATABASE=SEEL LTD. + +OUI:00C0A8* + ID_OUI_FROM_DATABASE=GVC CORPORATION + +OUI:00C0A9* + ID_OUI_FROM_DATABASE=BARRON MCCANN LTD. + +OUI:00C0AA* + ID_OUI_FROM_DATABASE=SILICON VALLEY COMPUTER + +OUI:00C0AB* + ID_OUI_FROM_DATABASE=Telco Systems, Inc. + +OUI:00C0AC* + ID_OUI_FROM_DATABASE=GAMBIT COMPUTER COMMUNICATIONS + +OUI:00C0AD* + ID_OUI_FROM_DATABASE=MARBEN COMMUNICATION SYSTEMS + +OUI:00C0AE* + ID_OUI_FROM_DATABASE=TOWERCOM CO. INC. DBA PC HOUSE + +OUI:00C0AF* + ID_OUI_FROM_DATABASE=TEKLOGIX INC. + +OUI:00C0B0* + ID_OUI_FROM_DATABASE=GCC TECHNOLOGIES,INC. + +OUI:00C0B1* + ID_OUI_FROM_DATABASE=GENIUS NET CO. + +OUI:00C0B2* + ID_OUI_FROM_DATABASE=NORAND CORPORATION + +OUI:00C0B3* + ID_OUI_FROM_DATABASE=COMSTAT DATACOMM CORPORATION + +OUI:00C0B4* + ID_OUI_FROM_DATABASE=MYSON TECHNOLOGY, INC. + +OUI:00C0B5* + ID_OUI_FROM_DATABASE=CORPORATE NETWORK SYSTEMS,INC. + +OUI:00C0B6* + ID_OUI_FROM_DATABASE=Overland Storage, Inc. + +OUI:00C0B7* + ID_OUI_FROM_DATABASE=AMERICAN POWER CONVERSION CORP + +OUI:00C0B8* + ID_OUI_FROM_DATABASE=FRASER'S HILL LTD. + +OUI:00C0B9* + ID_OUI_FROM_DATABASE=FUNK SOFTWARE, INC. + +OUI:00C0BA* + ID_OUI_FROM_DATABASE=NETVANTAGE + +OUI:00C0BB* + ID_OUI_FROM_DATABASE=FORVAL CREATIVE, INC. + +OUI:00C0BC* + ID_OUI_FROM_DATABASE=TELECOM AUSTRALIA/CSSC + +OUI:00C0BD* + ID_OUI_FROM_DATABASE=INEX TECHNOLOGIES, INC. + +OUI:00C0BE* + ID_OUI_FROM_DATABASE=ALCATEL - SEL + +OUI:00C0BF* + ID_OUI_FROM_DATABASE=TECHNOLOGY CONCEPTS, LTD. + +OUI:00C0C0* + ID_OUI_FROM_DATABASE=SHORE MICROSYSTEMS, INC. + +OUI:00C0C1* + ID_OUI_FROM_DATABASE=QUAD/GRAPHICS, INC. + +OUI:00C0C2* + ID_OUI_FROM_DATABASE=INFINITE NETWORKS LTD. + +OUI:00C0C3* + ID_OUI_FROM_DATABASE=ACUSON COMPUTED SONOGRAPHY + +OUI:00C0C4* + ID_OUI_FROM_DATABASE=COMPUTER OPERATIONAL + +OUI:00C0C5* + ID_OUI_FROM_DATABASE=SID INFORMATICA + +OUI:00C0C6* + ID_OUI_FROM_DATABASE=PERSONAL MEDIA CORP. + +OUI:00C0C7* + ID_OUI_FROM_DATABASE=SPARKTRUM MICROSYSTEMS, INC. + +OUI:00C0C8* + ID_OUI_FROM_DATABASE=MICRO BYTE PTY. LTD. + +OUI:00C0C9* + ID_OUI_FROM_DATABASE=ELSAG BAILEY PROCESS + +OUI:00C0CA* + ID_OUI_FROM_DATABASE=ALFA, INC. + +OUI:00C0CB* + ID_OUI_FROM_DATABASE=CONTROL TECHNOLOGY CORPORATION + +OUI:00C0CC* + ID_OUI_FROM_DATABASE=TELESCIENCES CO SYSTEMS, INC. + +OUI:00C0CD* + ID_OUI_FROM_DATABASE=COMELTA, S.A. + +OUI:00C0CE* + ID_OUI_FROM_DATABASE=CEI SYSTEMS & ENGINEERING PTE + +OUI:00C0CF* + ID_OUI_FROM_DATABASE=IMATRAN VOIMA OY + +OUI:00C0D0* + ID_OUI_FROM_DATABASE=RATOC SYSTEM INC. + +OUI:00C0D1* + ID_OUI_FROM_DATABASE=COMTREE TECHNOLOGY CORPORATION + +OUI:00C0D2* + ID_OUI_FROM_DATABASE=SYNTELLECT, INC. + +OUI:00C0D3* + ID_OUI_FROM_DATABASE=OLYMPUS IMAGE SYSTEMS, INC. + +OUI:00C0D4* + ID_OUI_FROM_DATABASE=AXON NETWORKS, INC. + +OUI:00C0D5* + ID_OUI_FROM_DATABASE=Werbeagentur Jürgen Siebert + +OUI:00C0D6* + ID_OUI_FROM_DATABASE=J1 SYSTEMS, INC. + +OUI:00C0D7* + ID_OUI_FROM_DATABASE=TAIWAN TRADING CENTER DBA + +OUI:00C0D8* + ID_OUI_FROM_DATABASE=UNIVERSAL DATA SYSTEMS + +OUI:00C0D9* + ID_OUI_FROM_DATABASE=QUINTE NETWORK CONFIDENTIALITY + +OUI:00C0DA* + ID_OUI_FROM_DATABASE=NICE SYSTEMS LTD. + +OUI:00C0DB* + ID_OUI_FROM_DATABASE=IPC CORPORATION (PTE) LTD. + +OUI:00C0DC* + ID_OUI_FROM_DATABASE=EOS TECHNOLOGIES, INC. + +OUI:00C0DD* + ID_OUI_FROM_DATABASE=QLogic Corporation + +OUI:00C0DE* + ID_OUI_FROM_DATABASE=ZCOMM, INC. + +OUI:00C0DF* + ID_OUI_FROM_DATABASE=KYE Systems Corp. + +OUI:00C0E0* + ID_OUI_FROM_DATABASE=DSC COMMUNICATION CORP. + +OUI:00C0E1* + ID_OUI_FROM_DATABASE=SONIC SOLUTIONS + +OUI:00C0E2* + ID_OUI_FROM_DATABASE=CALCOMP, INC. + +OUI:00C0E3* + ID_OUI_FROM_DATABASE=OSITECH COMMUNICATIONS, INC. + +OUI:00C0E4* + ID_OUI_FROM_DATABASE=SIEMENS BUILDING + +OUI:00C0E5* + ID_OUI_FROM_DATABASE=GESPAC, S.A. + +OUI:00C0E6* + ID_OUI_FROM_DATABASE=Verilink Corporation + +OUI:00C0E7* + ID_OUI_FROM_DATABASE=FIBERDATA AB + +OUI:00C0E8* + ID_OUI_FROM_DATABASE=PLEXCOM, INC. + +OUI:00C0E9* + ID_OUI_FROM_DATABASE=OAK SOLUTIONS, LTD. + +OUI:00C0EA* + ID_OUI_FROM_DATABASE=ARRAY TECHNOLOGY LTD. + +OUI:00C0EB* + ID_OUI_FROM_DATABASE=SEH COMPUTERTECHNIK GMBH + +OUI:00C0EC* + ID_OUI_FROM_DATABASE=DAUPHIN TECHNOLOGY + +OUI:00C0ED* + ID_OUI_FROM_DATABASE=US ARMY ELECTRONIC + +OUI:00C0EE* + ID_OUI_FROM_DATABASE=KYOCERA CORPORATION + +OUI:00C0EF* + ID_OUI_FROM_DATABASE=ABIT CORPORATION + +OUI:00C0F0* + ID_OUI_FROM_DATABASE=KINGSTON TECHNOLOGY CORP. + +OUI:00C0F1* + ID_OUI_FROM_DATABASE=SHINKO ELECTRIC CO., LTD. + +OUI:00C0F2* + ID_OUI_FROM_DATABASE=TRANSITION NETWORKS + +OUI:00C0F3* + ID_OUI_FROM_DATABASE=NETWORK COMMUNICATIONS CORP. + +OUI:00C0F4* + ID_OUI_FROM_DATABASE=INTERLINK SYSTEM CO., LTD. + +OUI:00C0F5* + ID_OUI_FROM_DATABASE=METACOMP, INC. + +OUI:00C0F6* + ID_OUI_FROM_DATABASE=CELAN TECHNOLOGY INC. + +OUI:00C0F7* + ID_OUI_FROM_DATABASE=ENGAGE COMMUNICATION, INC. + +OUI:00C0F8* + ID_OUI_FROM_DATABASE=ABOUT COMPUTING INC. + +OUI:00C0F9* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:00C0FA* + ID_OUI_FROM_DATABASE=CANARY COMMUNICATIONS, INC. + +OUI:00C0FB* + ID_OUI_FROM_DATABASE=ADVANCED TECHNOLOGY LABS + +OUI:00C0FC* + ID_OUI_FROM_DATABASE=ELASTIC REALITY, INC. + +OUI:00C0FD* + ID_OUI_FROM_DATABASE=PROSUM + +OUI:00C0FE* + ID_OUI_FROM_DATABASE=APTEC COMPUTER SYSTEMS, INC. + +OUI:00C0FF* + ID_OUI_FROM_DATABASE=DOT HILL SYSTEMS CORPORATION + +OUI:00C14F* + ID_OUI_FROM_DATABASE=DDL Co,.ltd. + +OUI:00C2C6* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00C5DB* + ID_OUI_FROM_DATABASE=Datatech Sistemas Digitales Avanzados SL + +OUI:00C610* + ID_OUI_FROM_DATABASE=Apple + +OUI:00CBBD* + ID_OUI_FROM_DATABASE=Cambridge Broadband Networks Ltd. + +OUI:00CD90* + ID_OUI_FROM_DATABASE=MAS Elektronik AG + +OUI:00CF1C* + ID_OUI_FROM_DATABASE=COMMUNICATION MACHINERY CORP. + +OUI:00D000* + ID_OUI_FROM_DATABASE=FERRAN SCIENTIFIC, INC. + +OUI:00D001* + ID_OUI_FROM_DATABASE=VST TECHNOLOGIES, INC. + +OUI:00D002* + ID_OUI_FROM_DATABASE=DITECH CORPORATION + +OUI:00D003* + ID_OUI_FROM_DATABASE=COMDA ENTERPRISES CORP. + +OUI:00D004* + ID_OUI_FROM_DATABASE=PENTACOM LTD. + +OUI:00D005* + ID_OUI_FROM_DATABASE=ZHS ZEITMANAGEMENTSYSTEME + +OUI:00D006* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D007* + ID_OUI_FROM_DATABASE=MIC ASSOCIATES, INC. + +OUI:00D008* + ID_OUI_FROM_DATABASE=MACTELL CORPORATION + +OUI:00D009* + ID_OUI_FROM_DATABASE=HSING TECH. ENTERPRISE CO. LTD + +OUI:00D00A* + ID_OUI_FROM_DATABASE=LANACCESS TELECOM S.A. + +OUI:00D00B* + ID_OUI_FROM_DATABASE=RHK TECHNOLOGY, INC. + +OUI:00D00C* + ID_OUI_FROM_DATABASE=SNIJDER MICRO SYSTEMS + +OUI:00D00D* + ID_OUI_FROM_DATABASE=MICROMERITICS INSTRUMENT + +OUI:00D00E* + ID_OUI_FROM_DATABASE=PLURIS, INC. + +OUI:00D00F* + ID_OUI_FROM_DATABASE=SPEECH DESIGN GMBH + +OUI:00D010* + ID_OUI_FROM_DATABASE=CONVERGENT NETWORKS, INC. + +OUI:00D011* + ID_OUI_FROM_DATABASE=PRISM VIDEO, INC. + +OUI:00D012* + ID_OUI_FROM_DATABASE=GATEWORKS CORP. + +OUI:00D013* + ID_OUI_FROM_DATABASE=PRIMEX AEROSPACE COMPANY + +OUI:00D014* + ID_OUI_FROM_DATABASE=ROOT, INC. + +OUI:00D015* + ID_OUI_FROM_DATABASE=UNIVEX MICROTECHNOLOGY CORP. + +OUI:00D016* + ID_OUI_FROM_DATABASE=SCM MICROSYSTEMS, INC. + +OUI:00D017* + ID_OUI_FROM_DATABASE=SYNTECH INFORMATION CO., LTD. + +OUI:00D018* + ID_OUI_FROM_DATABASE=QWES. COM, INC. + +OUI:00D019* + ID_OUI_FROM_DATABASE=DAINIPPON SCREEN CORPORATE + +OUI:00D01A* + ID_OUI_FROM_DATABASE=URMET TLC S.P.A. + +OUI:00D01B* + ID_OUI_FROM_DATABASE=MIMAKI ENGINEERING CO., LTD. + +OUI:00D01C* + ID_OUI_FROM_DATABASE=SBS TECHNOLOGIES, + +OUI:00D01D* + ID_OUI_FROM_DATABASE=FURUNO ELECTRIC CO., LTD. + +OUI:00D01E* + ID_OUI_FROM_DATABASE=PINGTEL CORP. + +OUI:00D01F* + ID_OUI_FROM_DATABASE=CTAM PTY. LTD. + +OUI:00D020* + ID_OUI_FROM_DATABASE=AIM SYSTEM, INC. + +OUI:00D021* + ID_OUI_FROM_DATABASE=REGENT ELECTRONICS CORP. + +OUI:00D022* + ID_OUI_FROM_DATABASE=INCREDIBLE TECHNOLOGIES, INC. + +OUI:00D023* + ID_OUI_FROM_DATABASE=INFORTREND TECHNOLOGY, INC. + +OUI:00D024* + ID_OUI_FROM_DATABASE=Cognex Corporation + +OUI:00D025* + ID_OUI_FROM_DATABASE=XROSSTECH, INC. + +OUI:00D026* + ID_OUI_FROM_DATABASE=HIRSCHMANN AUSTRIA GMBH + +OUI:00D027* + ID_OUI_FROM_DATABASE=APPLIED AUTOMATION, INC. + +OUI:00D028* + ID_OUI_FROM_DATABASE=Harmonic, Inc + +OUI:00D029* + ID_OUI_FROM_DATABASE=WAKEFERN FOOD CORPORATION + +OUI:00D02A* + ID_OUI_FROM_DATABASE=Voxent Systems Ltd. + +OUI:00D02B* + ID_OUI_FROM_DATABASE=JETCELL, INC. + +OUI:00D02C* + ID_OUI_FROM_DATABASE=CAMPBELL SCIENTIFIC, INC. + +OUI:00D02D* + ID_OUI_FROM_DATABASE=ADEMCO + +OUI:00D02E* + ID_OUI_FROM_DATABASE=COMMUNICATION AUTOMATION CORP. + +OUI:00D02F* + ID_OUI_FROM_DATABASE=VLSI TECHNOLOGY INC. + +OUI:00D030* + ID_OUI_FROM_DATABASE=Safetran Systems Corp + +OUI:00D031* + ID_OUI_FROM_DATABASE=INDUSTRIAL LOGIC CORPORATION + +OUI:00D032* + ID_OUI_FROM_DATABASE=YANO ELECTRIC CO., LTD. + +OUI:00D033* + ID_OUI_FROM_DATABASE=DALIAN DAXIAN NETWORK + +OUI:00D034* + ID_OUI_FROM_DATABASE=ORMEC SYSTEMS CORP. + +OUI:00D035* + ID_OUI_FROM_DATABASE=BEHAVIOR TECH. COMPUTER CORP. + +OUI:00D036* + ID_OUI_FROM_DATABASE=TECHNOLOGY ATLANTA CORP. + +OUI:00D037* + ID_OUI_FROM_DATABASE=Pace France + +OUI:00D038* + ID_OUI_FROM_DATABASE=FIVEMERE, LTD. + +OUI:00D039* + ID_OUI_FROM_DATABASE=UTILICOM, INC. + +OUI:00D03A* + ID_OUI_FROM_DATABASE=ZONEWORX, INC. + +OUI:00D03B* + ID_OUI_FROM_DATABASE=VISION PRODUCTS PTY. LTD. + +OUI:00D03C* + ID_OUI_FROM_DATABASE=Vieo, Inc. + +OUI:00D03D* + ID_OUI_FROM_DATABASE=GALILEO TECHNOLOGY, LTD. + +OUI:00D03E* + ID_OUI_FROM_DATABASE=ROCKETCHIPS, INC. + +OUI:00D03F* + ID_OUI_FROM_DATABASE=AMERICAN COMMUNICATION + +OUI:00D040* + ID_OUI_FROM_DATABASE=SYSMATE CO., LTD. + +OUI:00D041* + ID_OUI_FROM_DATABASE=AMIGO TECHNOLOGY CO., LTD. + +OUI:00D042* + ID_OUI_FROM_DATABASE=MAHLO GMBH & CO. UG + +OUI:00D043* + ID_OUI_FROM_DATABASE=ZONAL RETAIL DATA SYSTEMS + +OUI:00D044* + ID_OUI_FROM_DATABASE=ALIDIAN NETWORKS, INC. + +OUI:00D045* + ID_OUI_FROM_DATABASE=KVASER AB + +OUI:00D046* + ID_OUI_FROM_DATABASE=DOLBY LABORATORIES, INC. + +OUI:00D047* + ID_OUI_FROM_DATABASE=XN TECHNOLOGIES + +OUI:00D048* + ID_OUI_FROM_DATABASE=ECTON, INC. + +OUI:00D049* + ID_OUI_FROM_DATABASE=IMPRESSTEK CO., LTD. + +OUI:00D04A* + ID_OUI_FROM_DATABASE=PRESENCE TECHNOLOGY GMBH + +OUI:00D04B* + ID_OUI_FROM_DATABASE=LA CIE GROUP S.A. + +OUI:00D04C* + ID_OUI_FROM_DATABASE=EUROTEL TELECOM LTD. + +OUI:00D04D* + ID_OUI_FROM_DATABASE=DIV OF RESEARCH & STATISTICS + +OUI:00D04E* + ID_OUI_FROM_DATABASE=LOGIBAG + +OUI:00D04F* + ID_OUI_FROM_DATABASE=BITRONICS, INC. + +OUI:00D050* + ID_OUI_FROM_DATABASE=ISKRATEL + +OUI:00D051* + ID_OUI_FROM_DATABASE=O2 MICRO, INC. + +OUI:00D052* + ID_OUI_FROM_DATABASE=ASCEND COMMUNICATIONS, INC. + +OUI:00D053* + ID_OUI_FROM_DATABASE=CONNECTED SYSTEMS + +OUI:00D054* + ID_OUI_FROM_DATABASE=SAS INSTITUTE INC. + +OUI:00D055* + ID_OUI_FROM_DATABASE=KATHREIN-WERKE KG + +OUI:00D056* + ID_OUI_FROM_DATABASE=SOMAT CORPORATION + +OUI:00D057* + ID_OUI_FROM_DATABASE=ULTRAK, INC. + +OUI:00D058* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D059* + ID_OUI_FROM_DATABASE=AMBIT MICROSYSTEMS CORP. + +OUI:00D05A* + ID_OUI_FROM_DATABASE=SYMBIONICS, LTD. + +OUI:00D05B* + ID_OUI_FROM_DATABASE=ACROLOOP MOTION CONTROL + +OUI:00D05C* + ID_OUI_FROM_DATABASE=TECHNOTREND SYSTEMTECHNIK GMBH + +OUI:00D05D* + ID_OUI_FROM_DATABASE=INTELLIWORXX, INC. + +OUI:00D05E* + ID_OUI_FROM_DATABASE=STRATABEAM TECHNOLOGY, INC. + +OUI:00D05F* + ID_OUI_FROM_DATABASE=VALCOM, INC. + +OUI:00D060* + ID_OUI_FROM_DATABASE=Panasonic Europe Ltd. + +OUI:00D061* + ID_OUI_FROM_DATABASE=TREMON ENTERPRISES CO., LTD. + +OUI:00D062* + ID_OUI_FROM_DATABASE=DIGIGRAM + +OUI:00D063* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D064* + ID_OUI_FROM_DATABASE=MULTITEL + +OUI:00D065* + ID_OUI_FROM_DATABASE=TOKO ELECTRIC + +OUI:00D066* + ID_OUI_FROM_DATABASE=WINTRISS ENGINEERING CORP. + +OUI:00D067* + ID_OUI_FROM_DATABASE=CAMPIO COMMUNICATIONS + +OUI:00D068* + ID_OUI_FROM_DATABASE=IWILL CORPORATION + +OUI:00D069* + ID_OUI_FROM_DATABASE=TECHNOLOGIC SYSTEMS + +OUI:00D06A* + ID_OUI_FROM_DATABASE=LINKUP SYSTEMS CORPORATION + +OUI:00D06B* + ID_OUI_FROM_DATABASE=SR TELECOM INC. + +OUI:00D06C* + ID_OUI_FROM_DATABASE=SHAREWAVE, INC. + +OUI:00D06D* + ID_OUI_FROM_DATABASE=ACRISON, INC. + +OUI:00D06E* + ID_OUI_FROM_DATABASE=TRENDVIEW RECORDERS LTD. + +OUI:00D06F* + ID_OUI_FROM_DATABASE=KMC CONTROLS + +OUI:00D070* + ID_OUI_FROM_DATABASE=LONG WELL ELECTRONICS CORP. + +OUI:00D071* + ID_OUI_FROM_DATABASE=ECHELON CORP. + +OUI:00D072* + ID_OUI_FROM_DATABASE=BROADLOGIC + +OUI:00D073* + ID_OUI_FROM_DATABASE=ACN ADVANCED COMMUNICATIONS + +OUI:00D074* + ID_OUI_FROM_DATABASE=TAQUA SYSTEMS, INC. + +OUI:00D075* + ID_OUI_FROM_DATABASE=ALARIS MEDICAL SYSTEMS, INC. + +OUI:00D076* + ID_OUI_FROM_DATABASE=Bank of America + +OUI:00D077* + ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES + +OUI:00D078* + ID_OUI_FROM_DATABASE=Eltex of Sweden AB + +OUI:00D079* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D07A* + ID_OUI_FROM_DATABASE=AMAQUEST COMPUTER CORP. + +OUI:00D07B* + ID_OUI_FROM_DATABASE=COMCAM INTERNATIONAL INC + +OUI:00D07C* + ID_OUI_FROM_DATABASE=KOYO ELECTRONICS INC. CO.,LTD. + +OUI:00D07D* + ID_OUI_FROM_DATABASE=COSINE COMMUNICATIONS + +OUI:00D07E* + ID_OUI_FROM_DATABASE=KEYCORP LTD. + +OUI:00D07F* + ID_OUI_FROM_DATABASE=STRATEGY & TECHNOLOGY, LIMITED + +OUI:00D080* + ID_OUI_FROM_DATABASE=EXABYTE CORPORATION + +OUI:00D081* + ID_OUI_FROM_DATABASE=RTD Embedded Technologies, Inc. + +OUI:00D082* + ID_OUI_FROM_DATABASE=IOWAVE INC. + +OUI:00D083* + ID_OUI_FROM_DATABASE=INVERTEX, INC. + +OUI:00D084* + ID_OUI_FROM_DATABASE=NEXCOMM SYSTEMS, INC. + +OUI:00D085* + ID_OUI_FROM_DATABASE=OTIS ELEVATOR COMPANY + +OUI:00D086* + ID_OUI_FROM_DATABASE=FOVEON, INC. + +OUI:00D087* + ID_OUI_FROM_DATABASE=MICROFIRST INC. + +OUI:00D088* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00D089* + ID_OUI_FROM_DATABASE=DYNACOLOR, INC. + +OUI:00D08A* + ID_OUI_FROM_DATABASE=PHOTRON USA + +OUI:00D08B* + ID_OUI_FROM_DATABASE=ADVA Optical Networking Ltd. + +OUI:00D08C* + ID_OUI_FROM_DATABASE=GENOA TECHNOLOGY, INC. + +OUI:00D08D* + ID_OUI_FROM_DATABASE=PHOENIX GROUP, INC. + +OUI:00D08E* + ID_OUI_FROM_DATABASE=NVISION INC. + +OUI:00D08F* + ID_OUI_FROM_DATABASE=ARDENT TECHNOLOGIES, INC. + +OUI:00D090* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D091* + ID_OUI_FROM_DATABASE=SMARTSAN SYSTEMS, INC. + +OUI:00D092* + ID_OUI_FROM_DATABASE=GLENAYRE WESTERN MULTIPLEX + +OUI:00D093* + ID_OUI_FROM_DATABASE=TQ - COMPONENTS GMBH + +OUI:00D094* + ID_OUI_FROM_DATABASE=TIMELINE VISTA, INC. + +OUI:00D095* + ID_OUI_FROM_DATABASE=Alcatel-Lucent, Enterprise Business Group + +OUI:00D096* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD. + +OUI:00D097* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D098* + ID_OUI_FROM_DATABASE=Photon Dynamics Canada Inc. + +OUI:00D099* + ID_OUI_FROM_DATABASE=Elcard Wireless Systems Oy + +OUI:00D09A* + ID_OUI_FROM_DATABASE=FILANET CORPORATION + +OUI:00D09B* + ID_OUI_FROM_DATABASE=SPECTEL LTD. + +OUI:00D09C* + ID_OUI_FROM_DATABASE=KAPADIA COMMUNICATIONS + +OUI:00D09D* + ID_OUI_FROM_DATABASE=VERIS INDUSTRIES + +OUI:00D09E* + ID_OUI_FROM_DATABASE=2WIRE, INC. + +OUI:00D09F* + ID_OUI_FROM_DATABASE=NOVTEK TEST SYSTEMS + +OUI:00D0A0* + ID_OUI_FROM_DATABASE=MIPS DENMARK + +OUI:00D0A1* + ID_OUI_FROM_DATABASE=OSKAR VIERLING GMBH + CO. KG + +OUI:00D0A2* + ID_OUI_FROM_DATABASE=INTEGRATED DEVICE + +OUI:00D0A3* + ID_OUI_FROM_DATABASE=VOCAL DATA, INC. + +OUI:00D0A4* + ID_OUI_FROM_DATABASE=ALANTRO COMMUNICATIONS + +OUI:00D0A5* + ID_OUI_FROM_DATABASE=AMERICAN ARIUM + +OUI:00D0A6* + ID_OUI_FROM_DATABASE=LANBIRD TECHNOLOGY CO., LTD. + +OUI:00D0A7* + ID_OUI_FROM_DATABASE=TOKYO SOKKI KENKYUJO CO., LTD. + +OUI:00D0A8* + ID_OUI_FROM_DATABASE=NETWORK ENGINES, INC. + +OUI:00D0A9* + ID_OUI_FROM_DATABASE=SHINANO KENSHI CO., LTD. + +OUI:00D0AA* + ID_OUI_FROM_DATABASE=CHASE COMMUNICATIONS + +OUI:00D0AB* + ID_OUI_FROM_DATABASE=DELTAKABEL TELECOM CV + +OUI:00D0AC* + ID_OUI_FROM_DATABASE=GRAYSON WIRELESS + +OUI:00D0AD* + ID_OUI_FROM_DATABASE=TL INDUSTRIES + +OUI:00D0AE* + ID_OUI_FROM_DATABASE=ORESIS COMMUNICATIONS, INC. + +OUI:00D0AF* + ID_OUI_FROM_DATABASE=CUTLER-HAMMER, INC. + +OUI:00D0B0* + ID_OUI_FROM_DATABASE=BITSWITCH LTD. + +OUI:00D0B1* + ID_OUI_FROM_DATABASE=OMEGA ELECTRONICS SA + +OUI:00D0B2* + ID_OUI_FROM_DATABASE=XIOTECH CORPORATION + +OUI:00D0B3* + ID_OUI_FROM_DATABASE=DRS Technologies Canada Ltd + +OUI:00D0B4* + ID_OUI_FROM_DATABASE=KATSUJIMA CO., LTD. + +OUI:00D0B5* + ID_OUI_FROM_DATABASE=IPricot formerly DotCom + +OUI:00D0B6* + ID_OUI_FROM_DATABASE=CRESCENT NETWORKS, INC. + +OUI:00D0B7* + ID_OUI_FROM_DATABASE=INTEL CORPORATION + +OUI:00D0B8* + ID_OUI_FROM_DATABASE=Iomega Corporation + +OUI:00D0B9* + ID_OUI_FROM_DATABASE=MICROTEK INTERNATIONAL, INC. + +OUI:00D0BA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0BB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0BC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0BD* + ID_OUI_FROM_DATABASE=Silicon Image GmbH + +OUI:00D0BE* + ID_OUI_FROM_DATABASE=EMUTEC INC. + +OUI:00D0BF* + ID_OUI_FROM_DATABASE=PIVOTAL TECHNOLOGIES + +OUI:00D0C0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0C1* + ID_OUI_FROM_DATABASE=HARMONIC DATA SYSTEMS, LTD. + +OUI:00D0C2* + ID_OUI_FROM_DATABASE=BALTHAZAR TECHNOLOGY AB + +OUI:00D0C3* + ID_OUI_FROM_DATABASE=VIVID TECHNOLOGY PTE, LTD. + +OUI:00D0C4* + ID_OUI_FROM_DATABASE=TERATECH CORPORATION + +OUI:00D0C5* + ID_OUI_FROM_DATABASE=COMPUTATIONAL SYSTEMS, INC. + +OUI:00D0C6* + ID_OUI_FROM_DATABASE=THOMAS & BETTS CORP. + +OUI:00D0C7* + ID_OUI_FROM_DATABASE=PATHWAY, INC. + +OUI:00D0C8* + ID_OUI_FROM_DATABASE=Prevas A/S + +OUI:00D0C9* + ID_OUI_FROM_DATABASE=ADVANTECH CO., LTD. + +OUI:00D0CA* + ID_OUI_FROM_DATABASE=Intrinsyc Software International Inc. + +OUI:00D0CB* + ID_OUI_FROM_DATABASE=DASAN CO., LTD. + +OUI:00D0CC* + ID_OUI_FROM_DATABASE=TECHNOLOGIES LYRE INC. + +OUI:00D0CD* + ID_OUI_FROM_DATABASE=ATAN TECHNOLOGY INC. + +OUI:00D0CE* + ID_OUI_FROM_DATABASE=ASYST ELECTRONIC + +OUI:00D0CF* + ID_OUI_FROM_DATABASE=MORETON BAY + +OUI:00D0D0* + ID_OUI_FROM_DATABASE=ZHONGXING TELECOM LTD. + +OUI:00D0D1* + ID_OUI_FROM_DATABASE=Sycamore Networks + +OUI:00D0D2* + ID_OUI_FROM_DATABASE=EPILOG CORPORATION + +OUI:00D0D3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0D4* + ID_OUI_FROM_DATABASE=V-BITS, INC. + +OUI:00D0D5* + ID_OUI_FROM_DATABASE=GRUNDIG AG + +OUI:00D0D6* + ID_OUI_FROM_DATABASE=AETHRA TELECOMUNICAZIONI + +OUI:00D0D7* + ID_OUI_FROM_DATABASE=B2C2, INC. + +OUI:00D0D8* + ID_OUI_FROM_DATABASE=3Com Corporation + +OUI:00D0D9* + ID_OUI_FROM_DATABASE=DEDICATED MICROCOMPUTERS + +OUI:00D0DA* + ID_OUI_FROM_DATABASE=TAICOM DATA SYSTEMS CO., LTD. + +OUI:00D0DB* + ID_OUI_FROM_DATABASE=MCQUAY INTERNATIONAL + +OUI:00D0DC* + ID_OUI_FROM_DATABASE=MODULAR MINING SYSTEMS, INC. + +OUI:00D0DD* + ID_OUI_FROM_DATABASE=SUNRISE TELECOM, INC. + +OUI:00D0DE* + ID_OUI_FROM_DATABASE=PHILIPS MULTIMEDIA NETWORK + +OUI:00D0DF* + ID_OUI_FROM_DATABASE=KUZUMI ELECTRONICS, INC. + +OUI:00D0E0* + ID_OUI_FROM_DATABASE=DOOIN ELECTRONICS CO. + +OUI:00D0E1* + ID_OUI_FROM_DATABASE=AVIONITEK ISRAEL INC. + +OUI:00D0E2* + ID_OUI_FROM_DATABASE=MRT MICRO, INC. + +OUI:00D0E3* + ID_OUI_FROM_DATABASE=ELE-CHEM ENGINEERING CO., LTD. + +OUI:00D0E4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D0E5* + ID_OUI_FROM_DATABASE=SOLIDUM SYSTEMS CORP. + +OUI:00D0E6* + ID_OUI_FROM_DATABASE=IBOND INC. + +OUI:00D0E7* + ID_OUI_FROM_DATABASE=VCON TELECOMMUNICATION LTD. + +OUI:00D0E8* + ID_OUI_FROM_DATABASE=MAC SYSTEM CO., LTD. + +OUI:00D0E9* + ID_OUI_FROM_DATABASE=Advantage Century Telecommunication Corp. + +OUI:00D0EA* + ID_OUI_FROM_DATABASE=NEXTONE COMMUNICATIONS, INC. + +OUI:00D0EB* + ID_OUI_FROM_DATABASE=LIGHTERA NETWORKS, INC. + +OUI:00D0EC* + ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS, INC + +OUI:00D0ED* + ID_OUI_FROM_DATABASE=XIOX + +OUI:00D0EE* + ID_OUI_FROM_DATABASE=DICTAPHONE CORPORATION + +OUI:00D0EF* + ID_OUI_FROM_DATABASE=IGT + +OUI:00D0F0* + ID_OUI_FROM_DATABASE=CONVISION TECHNOLOGY GMBH + +OUI:00D0F1* + ID_OUI_FROM_DATABASE=SEGA ENTERPRISES, LTD. + +OUI:00D0F2* + ID_OUI_FROM_DATABASE=MONTEREY NETWORKS + +OUI:00D0F3* + ID_OUI_FROM_DATABASE=SOLARI DI UDINE SPA + +OUI:00D0F4* + ID_OUI_FROM_DATABASE=CARINTHIAN TECH INSTITUTE + +OUI:00D0F5* + ID_OUI_FROM_DATABASE=ORANGE MICRO, INC. + +OUI:00D0F6* + ID_OUI_FROM_DATABASE=Alcatel Canada + +OUI:00D0F7* + ID_OUI_FROM_DATABASE=NEXT NETS CORPORATION + +OUI:00D0F8* + ID_OUI_FROM_DATABASE=FUJIAN STAR TERMINAL + +OUI:00D0F9* + ID_OUI_FROM_DATABASE=ACUTE COMMUNICATIONS CORP. + +OUI:00D0FA* + ID_OUI_FROM_DATABASE=Thales e-Security Ltd. + +OUI:00D0FB* + ID_OUI_FROM_DATABASE=TEK MICROSYSTEMS, INCORPORATED + +OUI:00D0FC* + ID_OUI_FROM_DATABASE=GRANITE MICROSYSTEMS + +OUI:00D0FD* + ID_OUI_FROM_DATABASE=OPTIMA TELE.COM, INC. + +OUI:00D0FE* + ID_OUI_FROM_DATABASE=ASTRAL POINT + +OUI:00D0FF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00D11C* + ID_OUI_FROM_DATABASE=ACETEL + +OUI:00D38D* + ID_OUI_FROM_DATABASE=Hotel Technology Next Generation + +OUI:00D632* + ID_OUI_FROM_DATABASE=GE Energy + +OUI:00DB1E* + ID_OUI_FROM_DATABASE=Albedo Telecom SL + +OUI:00DB45* + ID_OUI_FROM_DATABASE=THAMWAY CO.,LTD. + +OUI:00DBDF* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00DD00* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD01* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD02* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD03* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD04* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD05* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD06* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD07* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD08* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD09* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0A* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0B* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0C* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0D* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0E* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DD0F* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:00DEFB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E000* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:00E001* + ID_OUI_FROM_DATABASE=STRAND LIGHTING LIMITED + +OUI:00E002* + ID_OUI_FROM_DATABASE=CROSSROADS SYSTEMS, INC. + +OUI:00E003* + ID_OUI_FROM_DATABASE=NOKIA WIRELESS BUSINESS COMMUN + +OUI:00E004* + ID_OUI_FROM_DATABASE=PMC-SIERRA, INC. + +OUI:00E005* + ID_OUI_FROM_DATABASE=TECHNICAL CORP. + +OUI:00E006* + ID_OUI_FROM_DATABASE=SILICON INTEGRATED SYS. CORP. + +OUI:00E007* + ID_OUI_FROM_DATABASE=Avaya ECS Ltd + +OUI:00E008* + ID_OUI_FROM_DATABASE=AMAZING CONTROLS! INC. + +OUI:00E009* + ID_OUI_FROM_DATABASE=MARATHON TECHNOLOGIES CORP. + +OUI:00E00A* + ID_OUI_FROM_DATABASE=DIBA, INC. + +OUI:00E00B* + ID_OUI_FROM_DATABASE=ROOFTOP COMMUNICATIONS CORP. + +OUI:00E00C* + ID_OUI_FROM_DATABASE=MOTOROLA + +OUI:00E00D* + ID_OUI_FROM_DATABASE=RADIANT SYSTEMS + +OUI:00E00E* + ID_OUI_FROM_DATABASE=AVALON IMAGING SYSTEMS, INC. + +OUI:00E00F* + ID_OUI_FROM_DATABASE=SHANGHAI BAUD DATA + +OUI:00E010* + ID_OUI_FROM_DATABASE=HESS SB-AUTOMATENBAU GmbH + +OUI:00E011* + ID_OUI_FROM_DATABASE=Uniden Corporation + +OUI:00E012* + ID_OUI_FROM_DATABASE=PLUTO TECHNOLOGIES INTERNATIONAL INC. + +OUI:00E013* + ID_OUI_FROM_DATABASE=EASTERN ELECTRONIC CO., LTD. + +OUI:00E014* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E015* + ID_OUI_FROM_DATABASE=HEIWA CORPORATION + +OUI:00E016* + ID_OUI_FROM_DATABASE=RAPID CITY COMMUNICATIONS + +OUI:00E017* + ID_OUI_FROM_DATABASE=EXXACT GmbH + +OUI:00E018* + ID_OUI_FROM_DATABASE=ASUSTEK COMPUTER INC. + +OUI:00E019* + ID_OUI_FROM_DATABASE=ING. GIORDANO ELETTRONICA + +OUI:00E01A* + ID_OUI_FROM_DATABASE=COMTEC SYSTEMS. CO., LTD. + +OUI:00E01B* + ID_OUI_FROM_DATABASE=SPHERE COMMUNICATIONS, INC. + +OUI:00E01C* + ID_OUI_FROM_DATABASE=Cradlepoint, Inc + +OUI:00E01D* + ID_OUI_FROM_DATABASE=WebTV NETWORKS, INC. + +OUI:00E01E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E01F* + ID_OUI_FROM_DATABASE=AVIDIA Systems, Inc. + +OUI:00E020* + ID_OUI_FROM_DATABASE=TECNOMEN OY + +OUI:00E021* + ID_OUI_FROM_DATABASE=FREEGATE CORP. + +OUI:00E022* + ID_OUI_FROM_DATABASE=Analog Devices Inc. + +OUI:00E023* + ID_OUI_FROM_DATABASE=TELRAD + +OUI:00E024* + ID_OUI_FROM_DATABASE=GADZOOX NETWORKS + +OUI:00E025* + ID_OUI_FROM_DATABASE=dit Co., Ltd. + +OUI:00E026* + ID_OUI_FROM_DATABASE=Redlake MASD LLC + +OUI:00E027* + ID_OUI_FROM_DATABASE=DUX, INC. + +OUI:00E028* + ID_OUI_FROM_DATABASE=APTIX CORPORATION + +OUI:00E029* + ID_OUI_FROM_DATABASE=STANDARD MICROSYSTEMS CORP. + +OUI:00E02A* + ID_OUI_FROM_DATABASE=TANDBERG TELEVISION AS + +OUI:00E02B* + ID_OUI_FROM_DATABASE=EXTREME NETWORKS + +OUI:00E02C* + ID_OUI_FROM_DATABASE=AST COMPUTER + +OUI:00E02D* + ID_OUI_FROM_DATABASE=InnoMediaLogic, Inc. + +OUI:00E02E* + ID_OUI_FROM_DATABASE=SPC ELECTRONICS CORPORATION + +OUI:00E02F* + ID_OUI_FROM_DATABASE=MCNS HOLDINGS, L.P. + +OUI:00E030* + ID_OUI_FROM_DATABASE=MELITA INTERNATIONAL CORP. + +OUI:00E031* + ID_OUI_FROM_DATABASE=HAGIWARA ELECTRIC CO., LTD. + +OUI:00E032* + ID_OUI_FROM_DATABASE=MISYS FINANCIAL SYSTEMS, LTD. + +OUI:00E033* + ID_OUI_FROM_DATABASE=E.E.P.D. GmbH + +OUI:00E034* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E035* + ID_OUI_FROM_DATABASE=Emerson Network Power + +OUI:00E036* + ID_OUI_FROM_DATABASE=PIONEER CORPORATION + +OUI:00E037* + ID_OUI_FROM_DATABASE=CENTURY CORPORATION + +OUI:00E038* + ID_OUI_FROM_DATABASE=PROXIMA CORPORATION + +OUI:00E039* + ID_OUI_FROM_DATABASE=PARADYNE CORP. + +OUI:00E03A* + ID_OUI_FROM_DATABASE=CABLETRON SYSTEMS, INC. + +OUI:00E03B* + ID_OUI_FROM_DATABASE=PROMINET CORPORATION + +OUI:00E03C* + ID_OUI_FROM_DATABASE=AdvanSys + +OUI:00E03D* + ID_OUI_FROM_DATABASE=FOCON ELECTRONIC SYSTEMS A/S + +OUI:00E03E* + ID_OUI_FROM_DATABASE=ALFATECH, INC. + +OUI:00E03F* + ID_OUI_FROM_DATABASE=JATON CORPORATION + +OUI:00E040* + ID_OUI_FROM_DATABASE=DeskStation Technology, Inc. + +OUI:00E041* + ID_OUI_FROM_DATABASE=CSPI + +OUI:00E042* + ID_OUI_FROM_DATABASE=Pacom Systems Ltd. + +OUI:00E043* + ID_OUI_FROM_DATABASE=VitalCom + +OUI:00E044* + ID_OUI_FROM_DATABASE=LSICS CORPORATION + +OUI:00E045* + ID_OUI_FROM_DATABASE=TOUCHWAVE, INC. + +OUI:00E046* + ID_OUI_FROM_DATABASE=BENTLY NEVADA CORP. + +OUI:00E047* + ID_OUI_FROM_DATABASE=InFocus Corporation + +OUI:00E048* + ID_OUI_FROM_DATABASE=SDL COMMUNICATIONS, INC. + +OUI:00E049* + ID_OUI_FROM_DATABASE=MICROWI ELECTRONIC GmbH + +OUI:00E04A* + ID_OUI_FROM_DATABASE=ENHANCED MESSAGING SYSTEMS, INC + +OUI:00E04B* + ID_OUI_FROM_DATABASE=JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH + +OUI:00E04C* + ID_OUI_FROM_DATABASE=REALTEK SEMICONDUCTOR CORP. + +OUI:00E04D* + ID_OUI_FROM_DATABASE=INTERNET INITIATIVE JAPAN, INC + +OUI:00E04E* + ID_OUI_FROM_DATABASE=SANYO DENKI CO., LTD. + +OUI:00E04F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E050* + ID_OUI_FROM_DATABASE=EXECUTONE INFORMATION SYSTEMS, INC. + +OUI:00E051* + ID_OUI_FROM_DATABASE=TALX CORPORATION + +OUI:00E052* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc + +OUI:00E053* + ID_OUI_FROM_DATABASE=CELLPORT LABS, INC. + +OUI:00E054* + ID_OUI_FROM_DATABASE=KODAI HITEC CO., LTD. + +OUI:00E055* + ID_OUI_FROM_DATABASE=INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A. + +OUI:00E056* + ID_OUI_FROM_DATABASE=HOLONTECH CORPORATION + +OUI:00E057* + ID_OUI_FROM_DATABASE=HAN MICROTELECOM. CO., LTD. + +OUI:00E058* + ID_OUI_FROM_DATABASE=PHASE ONE DENMARK A/S + +OUI:00E059* + ID_OUI_FROM_DATABASE=CONTROLLED ENVIRONMENTS, LTD. + +OUI:00E05A* + ID_OUI_FROM_DATABASE=GALEA NETWORK SECURITY + +OUI:00E05B* + ID_OUI_FROM_DATABASE=WEST END SYSTEMS CORP. + +OUI:00E05C* + ID_OUI_FROM_DATABASE=MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD. + +OUI:00E05D* + ID_OUI_FROM_DATABASE=UNITEC CO., LTD. + +OUI:00E05E* + ID_OUI_FROM_DATABASE=JAPAN AVIATION ELECTRONICS INDUSTRY, LTD. + +OUI:00E05F* + ID_OUI_FROM_DATABASE=e-Net, Inc. + +OUI:00E060* + ID_OUI_FROM_DATABASE=SHERWOOD + +OUI:00E061* + ID_OUI_FROM_DATABASE=EdgePoint Networks, Inc. + +OUI:00E062* + ID_OUI_FROM_DATABASE=HOST ENGINEERING + +OUI:00E063* + ID_OUI_FROM_DATABASE=CABLETRON - YAGO SYSTEMS, INC. + +OUI:00E064* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS + +OUI:00E065* + ID_OUI_FROM_DATABASE=OPTICAL ACCESS INTERNATIONAL + +OUI:00E066* + ID_OUI_FROM_DATABASE=ProMax Systems, Inc. + +OUI:00E067* + ID_OUI_FROM_DATABASE=eac AUTOMATION-CONSULTING GmbH + +OUI:00E068* + ID_OUI_FROM_DATABASE=MERRIMAC SYSTEMS INC. + +OUI:00E069* + ID_OUI_FROM_DATABASE=JAYCOR + +OUI:00E06A* + ID_OUI_FROM_DATABASE=KAPSCH AG + +OUI:00E06B* + ID_OUI_FROM_DATABASE=W&G SPECIAL PRODUCTS + +OUI:00E06C* + ID_OUI_FROM_DATABASE=Ultra Electronics Limited (AEP Networks) + +OUI:00E06D* + ID_OUI_FROM_DATABASE=COMPUWARE CORPORATION + +OUI:00E06E* + ID_OUI_FROM_DATABASE=FAR SYSTEMS S.p.A. + +OUI:00E06F* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:00E070* + ID_OUI_FROM_DATABASE=DH TECHNOLOGY + +OUI:00E071* + ID_OUI_FROM_DATABASE=EPIS MICROCOMPUTER + +OUI:00E072* + ID_OUI_FROM_DATABASE=LYNK + +OUI:00E073* + ID_OUI_FROM_DATABASE=NATIONAL AMUSEMENT NETWORK, INC. + +OUI:00E074* + ID_OUI_FROM_DATABASE=TIERNAN COMMUNICATIONS, INC. + +OUI:00E075* + ID_OUI_FROM_DATABASE=Verilink Corporation + +OUI:00E076* + ID_OUI_FROM_DATABASE=DEVELOPMENT CONCEPTS, INC. + +OUI:00E077* + ID_OUI_FROM_DATABASE=WEBGEAR, INC. + +OUI:00E078* + ID_OUI_FROM_DATABASE=BERKELEY NETWORKS + +OUI:00E079* + ID_OUI_FROM_DATABASE=A.T.N.R. + +OUI:00E07A* + ID_OUI_FROM_DATABASE=MIKRODIDAKT AB + +OUI:00E07B* + ID_OUI_FROM_DATABASE=BAY NETWORKS + +OUI:00E07C* + ID_OUI_FROM_DATABASE=METTLER-TOLEDO, INC. + +OUI:00E07D* + ID_OUI_FROM_DATABASE=NETRONIX, INC. + +OUI:00E07E* + ID_OUI_FROM_DATABASE=WALT DISNEY IMAGINEERING + +OUI:00E07F* + ID_OUI_FROM_DATABASE=LOGISTISTEM s.r.l. + +OUI:00E080* + ID_OUI_FROM_DATABASE=CONTROL RESOURCES CORPORATION + +OUI:00E081* + ID_OUI_FROM_DATABASE=TYAN COMPUTER CORP. + +OUI:00E082* + ID_OUI_FROM_DATABASE=ANERMA + +OUI:00E083* + ID_OUI_FROM_DATABASE=JATO TECHNOLOGIES, INC. + +OUI:00E084* + ID_OUI_FROM_DATABASE=COMPULITE R&D + +OUI:00E085* + ID_OUI_FROM_DATABASE=GLOBAL MAINTECH, INC. + +OUI:00E086* + ID_OUI_FROM_DATABASE=Emerson Network Power, Avocent Division + +OUI:00E087* + ID_OUI_FROM_DATABASE=LeCroy - Networking Productions Division + +OUI:00E088* + ID_OUI_FROM_DATABASE=LTX-Credence CORPORATION + +OUI:00E089* + ID_OUI_FROM_DATABASE=ION Networks, Inc. + +OUI:00E08A* + ID_OUI_FROM_DATABASE=GEC AVERY, LTD. + +OUI:00E08B* + ID_OUI_FROM_DATABASE=QLogic Corp. + +OUI:00E08C* + ID_OUI_FROM_DATABASE=NEOPARADIGM LABS, INC. + +OUI:00E08D* + ID_OUI_FROM_DATABASE=PRESSURE SYSTEMS, INC. + +OUI:00E08E* + ID_OUI_FROM_DATABASE=UTSTARCOM + +OUI:00E08F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E090* + ID_OUI_FROM_DATABASE=BECKMAN LAB. AUTOMATION DIV. + +OUI:00E091* + ID_OUI_FROM_DATABASE=LG ELECTRONICS, INC. + +OUI:00E092* + ID_OUI_FROM_DATABASE=ADMTEK INCORPORATED + +OUI:00E093* + ID_OUI_FROM_DATABASE=ACKFIN NETWORKS + +OUI:00E094* + ID_OUI_FROM_DATABASE=OSAI SRL + +OUI:00E095* + ID_OUI_FROM_DATABASE=ADVANCED-VISION TECHNOLGIES CORP. + +OUI:00E096* + ID_OUI_FROM_DATABASE=SHIMADZU CORPORATION + +OUI:00E097* + ID_OUI_FROM_DATABASE=CARRIER ACCESS CORPORATION + +OUI:00E098* + ID_OUI_FROM_DATABASE=AboCom Systems, Inc. + +OUI:00E099* + ID_OUI_FROM_DATABASE=SAMSON AG + +OUI:00E09A* + ID_OUI_FROM_DATABASE=Positron Inc. + +OUI:00E09B* + ID_OUI_FROM_DATABASE=ENGAGE NETWORKS, INC. + +OUI:00E09C* + ID_OUI_FROM_DATABASE=MII + +OUI:00E09D* + ID_OUI_FROM_DATABASE=SARNOFF CORPORATION + +OUI:00E09E* + ID_OUI_FROM_DATABASE=QUANTUM CORPORATION + +OUI:00E09F* + ID_OUI_FROM_DATABASE=PIXEL VISION + +OUI:00E0A0* + ID_OUI_FROM_DATABASE=WILTRON CO. + +OUI:00E0A1* + ID_OUI_FROM_DATABASE=HIMA PAUL HILDEBRANDT GmbH Co. KG + +OUI:00E0A2* + ID_OUI_FROM_DATABASE=MICROSLATE INC. + +OUI:00E0A3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E0A4* + ID_OUI_FROM_DATABASE=ESAOTE S.p.A. + +OUI:00E0A5* + ID_OUI_FROM_DATABASE=ComCore Semiconductor, Inc. + +OUI:00E0A6* + ID_OUI_FROM_DATABASE=TELOGY NETWORKS, INC. + +OUI:00E0A7* + ID_OUI_FROM_DATABASE=IPC INFORMATION SYSTEMS, INC. + +OUI:00E0A8* + ID_OUI_FROM_DATABASE=SAT GmbH & Co. + +OUI:00E0A9* + ID_OUI_FROM_DATABASE=FUNAI ELECTRIC CO., LTD. + +OUI:00E0AA* + ID_OUI_FROM_DATABASE=ELECTROSONIC LTD. + +OUI:00E0AB* + ID_OUI_FROM_DATABASE=DIMAT S.A. + +OUI:00E0AC* + ID_OUI_FROM_DATABASE=MIDSCO, INC. + +OUI:00E0AD* + ID_OUI_FROM_DATABASE=EES TECHNOLOGY, LTD. + +OUI:00E0AE* + ID_OUI_FROM_DATABASE=XAQTI CORPORATION + +OUI:00E0AF* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS INFORMATION SYSTEMS + +OUI:00E0B0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E0B1* + ID_OUI_FROM_DATABASE=Alcatel-Lucent, Enterprise Business Group + +OUI:00E0B2* + ID_OUI_FROM_DATABASE=TELMAX COMMUNICATIONS CORP. + +OUI:00E0B3* + ID_OUI_FROM_DATABASE=EtherWAN Systems, Inc. + +OUI:00E0B4* + ID_OUI_FROM_DATABASE=TECHNO SCOPE CO., LTD. + +OUI:00E0B5* + ID_OUI_FROM_DATABASE=ARDENT COMMUNICATIONS CORP. + +OUI:00E0B6* + ID_OUI_FROM_DATABASE=Entrada Networks + +OUI:00E0B7* + ID_OUI_FROM_DATABASE=PI GROUP, LTD. + +OUI:00E0B8* + ID_OUI_FROM_DATABASE=GATEWAY 2000 + +OUI:00E0B9* + ID_OUI_FROM_DATABASE=BYAS SYSTEMS + +OUI:00E0BA* + ID_OUI_FROM_DATABASE=BERGHOF AUTOMATIONSTECHNIK GmbH + +OUI:00E0BB* + ID_OUI_FROM_DATABASE=NBX CORPORATION + +OUI:00E0BC* + ID_OUI_FROM_DATABASE=SYMON COMMUNICATIONS, INC. + +OUI:00E0BD* + ID_OUI_FROM_DATABASE=INTERFACE SYSTEMS, INC. + +OUI:00E0BE* + ID_OUI_FROM_DATABASE=GENROCO INTERNATIONAL, INC. + +OUI:00E0BF* + ID_OUI_FROM_DATABASE=TORRENT NETWORKING TECHNOLOGIES CORP. + +OUI:00E0C0* + ID_OUI_FROM_DATABASE=SEIWA ELECTRIC MFG. CO., LTD. + +OUI:00E0C1* + ID_OUI_FROM_DATABASE=MEMOREX TELEX JAPAN, LTD. + +OUI:00E0C2* + ID_OUI_FROM_DATABASE=NECSY S.p.A. + +OUI:00E0C3* + ID_OUI_FROM_DATABASE=SAKAI SYSTEM DEVELOPMENT CORP. + +OUI:00E0C4* + ID_OUI_FROM_DATABASE=HORNER ELECTRIC, INC. + +OUI:00E0C5* + ID_OUI_FROM_DATABASE=BCOM ELECTRONICS INC. + +OUI:00E0C6* + ID_OUI_FROM_DATABASE=LINK2IT, L.L.C. + +OUI:00E0C7* + ID_OUI_FROM_DATABASE=EUROTECH SRL + +OUI:00E0C8* + ID_OUI_FROM_DATABASE=VIRTUAL ACCESS, LTD. + +OUI:00E0C9* + ID_OUI_FROM_DATABASE=AutomatedLogic Corporation + +OUI:00E0CA* + ID_OUI_FROM_DATABASE=BEST DATA PRODUCTS + +OUI:00E0CB* + ID_OUI_FROM_DATABASE=RESON, INC. + +OUI:00E0CC* + ID_OUI_FROM_DATABASE=HERO SYSTEMS, LTD. + +OUI:00E0CD* + ID_OUI_FROM_DATABASE=SAAB SENSIS CORPORATION + +OUI:00E0CE* + ID_OUI_FROM_DATABASE=ARN + +OUI:00E0CF* + ID_OUI_FROM_DATABASE=INTEGRATED DEVICE TECHNOLOGY, INC. + +OUI:00E0D0* + ID_OUI_FROM_DATABASE=NETSPEED, INC. + +OUI:00E0D1* + ID_OUI_FROM_DATABASE=TELSIS LIMITED + +OUI:00E0D2* + ID_OUI_FROM_DATABASE=VERSANET COMMUNICATIONS, INC. + +OUI:00E0D3* + ID_OUI_FROM_DATABASE=DATENTECHNIK GmbH + +OUI:00E0D4* + ID_OUI_FROM_DATABASE=EXCELLENT COMPUTER + +OUI:00E0D5* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:00E0D6* + ID_OUI_FROM_DATABASE=COMPUTER & COMMUNICATION RESEARCH LAB. + +OUI:00E0D7* + ID_OUI_FROM_DATABASE=SUNSHINE ELECTRONICS, INC. + +OUI:00E0D8* + ID_OUI_FROM_DATABASE=LANBit Computer, Inc. + +OUI:00E0D9* + ID_OUI_FROM_DATABASE=TAZMO CO., LTD. + +OUI:00E0DA* + ID_OUI_FROM_DATABASE=Alcatel North America ESD + +OUI:00E0DB* + ID_OUI_FROM_DATABASE=ViaVideo Communications, Inc. + +OUI:00E0DC* + ID_OUI_FROM_DATABASE=NEXWARE CORP. + +OUI:00E0DD* + ID_OUI_FROM_DATABASE=ZENITH ELECTRONICS CORPORATION + +OUI:00E0DE* + ID_OUI_FROM_DATABASE=DATAX NV + +OUI:00E0DF* + ID_OUI_FROM_DATABASE=KEYMILE GmbH + +OUI:00E0E0* + ID_OUI_FROM_DATABASE=SI ELECTRONICS, LTD. + +OUI:00E0E1* + ID_OUI_FROM_DATABASE=G2 NETWORKS, INC. + +OUI:00E0E2* + ID_OUI_FROM_DATABASE=INNOVA CORP. + +OUI:00E0E3* + ID_OUI_FROM_DATABASE=SK-ELEKTRONIK GmbH + +OUI:00E0E4* + ID_OUI_FROM_DATABASE=FANUC ROBOTICS NORTH AMERICA, Inc. + +OUI:00E0E5* + ID_OUI_FROM_DATABASE=CINCO NETWORKS, INC. + +OUI:00E0E6* + ID_OUI_FROM_DATABASE=INCAA DATACOM B.V. + +OUI:00E0E7* + ID_OUI_FROM_DATABASE=RAYTHEON E-SYSTEMS, INC. + +OUI:00E0E8* + ID_OUI_FROM_DATABASE=GRETACODER Data Systems AG + +OUI:00E0E9* + ID_OUI_FROM_DATABASE=DATA LABS, INC. + +OUI:00E0EA* + ID_OUI_FROM_DATABASE=INNOVAT COMMUNICATIONS, INC. + +OUI:00E0EB* + ID_OUI_FROM_DATABASE=DIGICOM SYSTEMS, INCORPORATED + +OUI:00E0EC* + ID_OUI_FROM_DATABASE=CELESTICA INC. + +OUI:00E0ED* + ID_OUI_FROM_DATABASE=SILICOM, LTD. + +OUI:00E0EE* + ID_OUI_FROM_DATABASE=MAREL HF + +OUI:00E0EF* + ID_OUI_FROM_DATABASE=DIONEX + +OUI:00E0F0* + ID_OUI_FROM_DATABASE=ABLER TECHNOLOGY, INC. + +OUI:00E0F1* + ID_OUI_FROM_DATABASE=THAT CORPORATION + +OUI:00E0F2* + ID_OUI_FROM_DATABASE=ARLOTTO COMNET, INC. + +OUI:00E0F3* + ID_OUI_FROM_DATABASE=WebSprint Communications, Inc. + +OUI:00E0F4* + ID_OUI_FROM_DATABASE=INSIDE Technology A/S + +OUI:00E0F5* + ID_OUI_FROM_DATABASE=TELES AG + +OUI:00E0F6* + ID_OUI_FROM_DATABASE=DECISION EUROPE + +OUI:00E0F7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E0F8* + ID_OUI_FROM_DATABASE=DICNA CONTROL AB + +OUI:00E0F9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E0FA* + ID_OUI_FROM_DATABASE=TRL TECHNOLOGY, LTD. + +OUI:00E0FB* + ID_OUI_FROM_DATABASE=LEIGHTRONIX, INC. + +OUI:00E0FC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO., LTD. + +OUI:00E0FD* + ID_OUI_FROM_DATABASE=A-TREND TECHNOLOGY CO., LTD. + +OUI:00E0FE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:00E0FF* + ID_OUI_FROM_DATABASE=SECURITY DYNAMICS TECHNOLOGIES, Inc. + +OUI:00E175* + ID_OUI_FROM_DATABASE=AK-Systems Ltd + +OUI:00E3B2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:00E666* + ID_OUI_FROM_DATABASE=ARIMA Communications Corp. + +OUI:00E6D3* + ID_OUI_FROM_DATABASE=NIXDORF COMPUTER CORP. + +OUI:00E8AB* + ID_OUI_FROM_DATABASE=Meggitt Training Systems, Inc. + +OUI:00EB2D* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:00EEBD* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:00F051* + ID_OUI_FROM_DATABASE=KWB Gmbh + +OUI:00F403* + ID_OUI_FROM_DATABASE=Orbis Systems Oy + +OUI:00F4B9* + ID_OUI_FROM_DATABASE=Apple + +OUI:00F860* + ID_OUI_FROM_DATABASE=PT. Panggung Electric Citrabuana + +OUI:00FA3B* + ID_OUI_FROM_DATABASE=CLOOS ELECTRONIC GMBH + +OUI:00FC58* + ID_OUI_FROM_DATABASE=WebSilicon Ltd. + +OUI:00FC70* + ID_OUI_FROM_DATABASE=Intrepid Control Systems, Inc. + +OUI:00FD4C* + ID_OUI_FROM_DATABASE=NEVATEC + +OUI:020701* + ID_OUI_FROM_DATABASE=RACAL-DATACOM + +OUI:021C7C* + ID_OUI_FROM_DATABASE=PERQ SYSTEMS CORPORATION + +OUI:026086* + ID_OUI_FROM_DATABASE=LOGIC REPLACEMENT TECH. LTD. + +OUI:02608C* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:027001* + ID_OUI_FROM_DATABASE=RACAL-DATACOM + +OUI:0270B0* + ID_OUI_FROM_DATABASE=M/A-COM INC. COMPANIES + +OUI:0270B3* + ID_OUI_FROM_DATABASE=DATA RECALL LTD + +OUI:029D8E* + ID_OUI_FROM_DATABASE=CARDIAC RECORDERS INC. + +OUI:02AA3C* + ID_OUI_FROM_DATABASE=OLIVETTI TELECOMM SPA (OLTECO) + +OUI:02BB01* + ID_OUI_FROM_DATABASE=OCTOTHORPE CORP. + +OUI:02C08C* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:02CF1C* + ID_OUI_FROM_DATABASE=COMMUNICATION MACHINERY CORP. + +OUI:02E6D3* + ID_OUI_FROM_DATABASE=NIXDORF COMPUTER CORPORATION + +OUI:040A83* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:040AE0* + ID_OUI_FROM_DATABASE=XMIT AG COMPUTER NETWORKS + +OUI:040CCE* + ID_OUI_FROM_DATABASE=Apple + +OUI:040EC2* + ID_OUI_FROM_DATABASE=ViewSonic Mobile China Limited + +OUI:041552* + ID_OUI_FROM_DATABASE=Apple + +OUI:04180F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0418D6* + ID_OUI_FROM_DATABASE=Ubiquiti Networks + +OUI:041A04* + ID_OUI_FROM_DATABASE=WaveIP + +OUI:041B94* + ID_OUI_FROM_DATABASE=Host Mobility AB + +OUI:041BBA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:041D10* + ID_OUI_FROM_DATABASE=Dream Ware Inc. + +OUI:041E64* + ID_OUI_FROM_DATABASE=Apple + +OUI:04209A* + ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company + +OUI:042234* + ID_OUI_FROM_DATABASE=Wireless Standard Extensions + +OUI:042605* + ID_OUI_FROM_DATABASE=GFR Gesellschaft für Regelungstechnik und Energieeinsparung mbH + +OUI:042665* + ID_OUI_FROM_DATABASE=Apple + +OUI:042BBB* + ID_OUI_FROM_DATABASE=PicoCELA, Inc. + +OUI:042F56* + ID_OUI_FROM_DATABASE=ATOCS (Shenzhen) LTD + +OUI:0432F4* + ID_OUI_FROM_DATABASE=Partron + +OUI:043604* + ID_OUI_FROM_DATABASE=Gyeyoung I&T + +OUI:043D98* + ID_OUI_FROM_DATABASE=ChongQing QingJia Electronics CO.,LTD + +OUI:0444A1* + ID_OUI_FROM_DATABASE=TELECON GALICIA,S.A. + +OUI:044665* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:044A50* + ID_OUI_FROM_DATABASE=Ramaxel Technology (Shenzhen) limited company + +OUI:044BFF* + ID_OUI_FROM_DATABASE=GuangZhou Hedy Digital Technology Co., Ltd + +OUI:044CEF* + ID_OUI_FROM_DATABASE=Fujian Sanao Technology Co.,Ltd + +OUI:044E06* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:044F8B* + ID_OUI_FROM_DATABASE=Adapteva, Inc. + +OUI:044FAA* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:045453* + ID_OUI_FROM_DATABASE=Apple + +OUI:0455CA* + ID_OUI_FROM_DATABASE=BriView (Xiamen) Corp. + +OUI:04586F* + ID_OUI_FROM_DATABASE=Sichuan Whayer information industry Co.,LTD + +OUI:045A95* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:045C06* + ID_OUI_FROM_DATABASE=Zmodo Technology Corporation + +OUI:045D56* + ID_OUI_FROM_DATABASE=camtron industrial inc. + +OUI:045FA7* + ID_OUI_FROM_DATABASE=Shenzhen Yichen Technology Development Co.,LTD + +OUI:0462D7* + ID_OUI_FROM_DATABASE=ALSTOM HYDRO FRANCE + +OUI:0463E0* + ID_OUI_FROM_DATABASE=Nome Oy + +OUI:046D42* + ID_OUI_FROM_DATABASE=Bryston Ltd. + +OUI:046E49* + ID_OUI_FROM_DATABASE=TaiYear Electronic Technology (Suzhou) Co., Ltd + +OUI:0470BC* + ID_OUI_FROM_DATABASE=Globalstar Inc. + +OUI:0474A1* + ID_OUI_FROM_DATABASE=Aligera Equipamentos Digitais Ltda + +OUI:0475F5* + ID_OUI_FROM_DATABASE=CSST + +OUI:04766E* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:047D7B* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:0481AE* + ID_OUI_FROM_DATABASE=Clack Corporation + +OUI:04848A* + ID_OUI_FROM_DATABASE=7INOVA TECHNOLOGY LIMITED + +OUI:04888C* + ID_OUI_FROM_DATABASE=Eifelwerk Butler Systeme GmbH + +OUI:0488E2* + ID_OUI_FROM_DATABASE=Beats Electronics LLC + +OUI:048A15* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:048B42* + ID_OUI_FROM_DATABASE=Skspruce Technology Limited + +OUI:048C03* + ID_OUI_FROM_DATABASE=ThinPAD Technology (Shenzhen)CO.,LTD + +OUI:048D38* + ID_OUI_FROM_DATABASE=Netcore Technology Inc. + +OUI:0494A1* + ID_OUI_FROM_DATABASE=CATCH THE WIND INC + +OUI:0498F3* + ID_OUI_FROM_DATABASE=ALPS Electric Co,. Ltd. + +OUI:049C62* + ID_OUI_FROM_DATABASE=BMT Medical Technology s.r.o. + +OUI:049F06* + ID_OUI_FROM_DATABASE=Smobile Co., Ltd. + +OUI:049F81* + ID_OUI_FROM_DATABASE=Netscout Systems, Inc. + +OUI:04A151* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:04A3F3* + ID_OUI_FROM_DATABASE=Emicon + +OUI:04A82A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:04B3B6* + ID_OUI_FROM_DATABASE=Seamap (UK) Ltd + +OUI:04B466* + ID_OUI_FROM_DATABASE=BSP Co., Ltd. + +OUI:04BFA8* + ID_OUI_FROM_DATABASE=ISB Corporation + +OUI:04C05B* + ID_OUI_FROM_DATABASE=Tigo Energy + +OUI:04C06F* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:04C1B9* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:04C5A4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:04C880* + ID_OUI_FROM_DATABASE=Samtec Inc + +OUI:04CB1D* + ID_OUI_FROM_DATABASE=Traka plc + +OUI:04CE14* + ID_OUI_FROM_DATABASE=Wilocity LTD. + +OUI:04CF25* + ID_OUI_FROM_DATABASE=MANYCOLORS, INC. + +OUI:04D437* + ID_OUI_FROM_DATABASE=ZNV + +OUI:04D783* + ID_OUI_FROM_DATABASE=Y&H E&C Co.,LTD. + +OUI:04DAD2* + ID_OUI_FROM_DATABASE=Cisco + +OUI:04DB56* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:04DB8A* + ID_OUI_FROM_DATABASE=Suntech International Ltd. + +OUI:04DD4C* + ID_OUI_FROM_DATABASE=Velocytech + +OUI:04DF69* + ID_OUI_FROM_DATABASE=Car Connectivity Consortium + +OUI:04E0C4* + ID_OUI_FROM_DATABASE=TRIUMPH-ADLER AG + +OUI:04E1C8* + ID_OUI_FROM_DATABASE=IMS Soluções em Energia Ltda. + +OUI:04E2F8* + ID_OUI_FROM_DATABASE=AEP Ticketing solutions srl + +OUI:04E451* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:04E536* + ID_OUI_FROM_DATABASE=Apple + +OUI:04E548* + ID_OUI_FROM_DATABASE=Cohda Wireless Pty Ltd + +OUI:04E662* + ID_OUI_FROM_DATABASE=Acroname Inc. + +OUI:04E9E5* + ID_OUI_FROM_DATABASE=PJRC.COM, LLC + +OUI:04EE91* + ID_OUI_FROM_DATABASE=x-fabric GmbH + +OUI:04F021* + ID_OUI_FROM_DATABASE=Compex Systems Pte Ltd + +OUI:04F13E* + ID_OUI_FROM_DATABASE=Apple + +OUI:04F17D* + ID_OUI_FROM_DATABASE=Tarana Wireless + +OUI:04F4BC* + ID_OUI_FROM_DATABASE=Xena Networks + +OUI:04F7E4* + ID_OUI_FROM_DATABASE=Apple + +OUI:04F8C2* + ID_OUI_FROM_DATABASE=Flaircomm Microelectronics, Inc. + +OUI:04F938* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:04FE31* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:04FE7F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:04FF51* + ID_OUI_FROM_DATABASE=NOVAMEDIA INNOVISION SP. Z O.O. + +OUI:080001* + ID_OUI_FROM_DATABASE=COMPUTERVISION CORPORATION + +OUI:080002* + ID_OUI_FROM_DATABASE=BRIDGE COMMUNICATIONS INC. + +OUI:080003* + ID_OUI_FROM_DATABASE=ADVANCED COMPUTER COMM. + +OUI:080004* + ID_OUI_FROM_DATABASE=CROMEMCO INCORPORATED + +OUI:080005* + ID_OUI_FROM_DATABASE=SYMBOLICS INC. + +OUI:080006* + ID_OUI_FROM_DATABASE=SIEMENS AG + +OUI:080007* + ID_OUI_FROM_DATABASE=Apple + +OUI:080008* + ID_OUI_FROM_DATABASE=BOLT BERANEK AND NEWMAN INC. + +OUI:080009* + ID_OUI_FROM_DATABASE=HEWLETT PACKARD + +OUI:08000A* + ID_OUI_FROM_DATABASE=NESTAR SYSTEMS INCORPORATED + +OUI:08000B* + ID_OUI_FROM_DATABASE=UNISYS CORPORATION + +OUI:08000C* + ID_OUI_FROM_DATABASE=MIKLYN DEVELOPMENT CO. + +OUI:08000D* + ID_OUI_FROM_DATABASE=INTERNATIONAL COMPUTERS LTD. + +OUI:08000E* + ID_OUI_FROM_DATABASE=NCR CORPORATION + +OUI:08000F* + ID_OUI_FROM_DATABASE=MITEL CORPORATION + +OUI:080011* + ID_OUI_FROM_DATABASE=TEKTRONIX INC. + +OUI:080012* + ID_OUI_FROM_DATABASE=BELL ATLANTIC INTEGRATED SYST. + +OUI:080013* + ID_OUI_FROM_DATABASE=EXXON + +OUI:080014* + ID_OUI_FROM_DATABASE=EXCELAN + +OUI:080015* + ID_OUI_FROM_DATABASE=STC BUSINESS SYSTEMS + +OUI:080016* + ID_OUI_FROM_DATABASE=BARRISTER INFO SYS CORP + +OUI:080017* + ID_OUI_FROM_DATABASE=NATIONAL SEMICONDUCTOR + +OUI:080018* + ID_OUI_FROM_DATABASE=PIRELLI FOCOM NETWORKS + +OUI:080019* + ID_OUI_FROM_DATABASE=GENERAL ELECTRIC CORPORATION + +OUI:08001A* + ID_OUI_FROM_DATABASE=TIARA/ 10NET + +OUI:08001B* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:08001C* + ID_OUI_FROM_DATABASE=KDD-KOKUSAI DEBNSIN DENWA CO. + +OUI:08001D* + ID_OUI_FROM_DATABASE=ABLE COMMUNICATIONS INC. + +OUI:08001E* + ID_OUI_FROM_DATABASE=APOLLO COMPUTER INC. + +OUI:08001F* + ID_OUI_FROM_DATABASE=SHARP CORPORATION + +OUI:080020* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:080021* + ID_OUI_FROM_DATABASE=3M COMPANY + +OUI:080022* + ID_OUI_FROM_DATABASE=NBI INC. + +OUI:080023* + ID_OUI_FROM_DATABASE=Panasonic Communications Co., Ltd. + +OUI:080024* + ID_OUI_FROM_DATABASE=10NET COMMUNICATIONS/DCA + +OUI:080025* + ID_OUI_FROM_DATABASE=CONTROL DATA + +OUI:080026* + ID_OUI_FROM_DATABASE=NORSK DATA A.S. + +OUI:080027* + ID_OUI_FROM_DATABASE=CADMUS COMPUTER SYSTEMS + +OUI:080028* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:080029* + ID_OUI_FROM_DATABASE=MEGATEK CORPORATION + +OUI:08002A* + ID_OUI_FROM_DATABASE=MOSAIC TECHNOLOGIES INC. + +OUI:08002B* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:08002C* + ID_OUI_FROM_DATABASE=BRITTON LEE INC. + +OUI:08002D* + ID_OUI_FROM_DATABASE=LAN-TEC INC. + +OUI:08002E* + ID_OUI_FROM_DATABASE=METAPHOR COMPUTER SYSTEMS + +OUI:08002F* + ID_OUI_FROM_DATABASE=PRIME COMPUTER INC. + +OUI:080030* + ID_OUI_FROM_DATABASE=NETWORK RESEARCH CORPORATION + +OUI:080030* + ID_OUI_FROM_DATABASE=CERN + +OUI:080030* + ID_OUI_FROM_DATABASE=ROYAL MELBOURNE INST OF TECH + +OUI:080031* + ID_OUI_FROM_DATABASE=LITTLE MACHINES INC. + +OUI:080032* + ID_OUI_FROM_DATABASE=TIGAN INCORPORATED + +OUI:080033* + ID_OUI_FROM_DATABASE=BAUSCH & LOMB + +OUI:080034* + ID_OUI_FROM_DATABASE=FILENET CORPORATION + +OUI:080035* + ID_OUI_FROM_DATABASE=MICROFIVE CORPORATION + +OUI:080036* + ID_OUI_FROM_DATABASE=INTERGRAPH CORPORATION + +OUI:080037* + ID_OUI_FROM_DATABASE=FUJI-XEROX CO. LTD. + +OUI:080038* + ID_OUI_FROM_DATABASE=BULL S.A.S. + +OUI:080039* + ID_OUI_FROM_DATABASE=SPIDER SYSTEMS LIMITED + +OUI:08003A* + ID_OUI_FROM_DATABASE=ORCATECH INC. + +OUI:08003B* + ID_OUI_FROM_DATABASE=TORUS SYSTEMS LIMITED + +OUI:08003C* + ID_OUI_FROM_DATABASE=SCHLUMBERGER WELL SERVICES + +OUI:08003D* + ID_OUI_FROM_DATABASE=CADNETIX CORPORATIONS + +OUI:08003E* + ID_OUI_FROM_DATABASE=CODEX CORPORATION + +OUI:08003F* + ID_OUI_FROM_DATABASE=FRED KOSCHARA ENTERPRISES + +OUI:080040* + ID_OUI_FROM_DATABASE=FERRANTI COMPUTER SYS. LIMITED + +OUI:080041* + ID_OUI_FROM_DATABASE=RACAL-MILGO INFORMATION SYS.. + +OUI:080042* + ID_OUI_FROM_DATABASE=JAPAN MACNICS CORP. + +OUI:080043* + ID_OUI_FROM_DATABASE=PIXEL COMPUTER INC. + +OUI:080044* + ID_OUI_FROM_DATABASE=DAVID SYSTEMS INC. + +OUI:080045* + ID_OUI_FROM_DATABASE=CONCURRENT COMPUTER CORP. + +OUI:080046* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:080047* + ID_OUI_FROM_DATABASE=SEQUENT COMPUTER SYSTEMS INC. + +OUI:080048* + ID_OUI_FROM_DATABASE=EUROTHERM GAUGING SYSTEMS + +OUI:080049* + ID_OUI_FROM_DATABASE=UNIVATION + +OUI:08004A* + ID_OUI_FROM_DATABASE=BANYAN SYSTEMS INC. + +OUI:08004B* + ID_OUI_FROM_DATABASE=PLANNING RESEARCH CORP. + +OUI:08004C* + ID_OUI_FROM_DATABASE=HYDRA COMPUTER SYSTEMS INC. + +OUI:08004D* + ID_OUI_FROM_DATABASE=CORVUS SYSTEMS INC. + +OUI:08004E* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD. + +OUI:08004F* + ID_OUI_FROM_DATABASE=CYGNET SYSTEMS + +OUI:080050* + ID_OUI_FROM_DATABASE=DAISY SYSTEMS CORP. + +OUI:080051* + ID_OUI_FROM_DATABASE=EXPERDATA + +OUI:080052* + ID_OUI_FROM_DATABASE=INSYSTEC + +OUI:080053* + ID_OUI_FROM_DATABASE=MIDDLE EAST TECH. UNIVERSITY + +OUI:080055* + ID_OUI_FROM_DATABASE=STANFORD TELECOMM. INC. + +OUI:080056* + ID_OUI_FROM_DATABASE=STANFORD LINEAR ACCEL. CENTER + +OUI:080057* + ID_OUI_FROM_DATABASE=EVANS & SUTHERLAND + +OUI:080058* + ID_OUI_FROM_DATABASE=SYSTEMS CONCEPTS + +OUI:080059* + ID_OUI_FROM_DATABASE=A/S MYCRON + +OUI:08005A* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:08005B* + ID_OUI_FROM_DATABASE=VTA TECHNOLOGIES INC. + +OUI:08005C* + ID_OUI_FROM_DATABASE=FOUR PHASE SYSTEMS + +OUI:08005D* + ID_OUI_FROM_DATABASE=GOULD INC. + +OUI:08005E* + ID_OUI_FROM_DATABASE=COUNTERPOINT COMPUTER INC. + +OUI:08005F* + ID_OUI_FROM_DATABASE=SABER TECHNOLOGY CORP. + +OUI:080060* + ID_OUI_FROM_DATABASE=INDUSTRIAL NETWORKING INC. + +OUI:080061* + ID_OUI_FROM_DATABASE=JAROGATE LTD. + +OUI:080062* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS + +OUI:080063* + ID_OUI_FROM_DATABASE=PLESSEY + +OUI:080064* + ID_OUI_FROM_DATABASE=Sitasys AG + +OUI:080065* + ID_OUI_FROM_DATABASE=GENRAD INC. + +OUI:080066* + ID_OUI_FROM_DATABASE=AGFA CORPORATION + +OUI:080067* + ID_OUI_FROM_DATABASE=COMDESIGN + +OUI:080068* + ID_OUI_FROM_DATABASE=RIDGE COMPUTERS + +OUI:080069* + ID_OUI_FROM_DATABASE=SILICON GRAPHICS INC. + +OUI:08006A* + ID_OUI_FROM_DATABASE=ATT BELL LABORATORIES + +OUI:08006B* + ID_OUI_FROM_DATABASE=ACCEL TECHNOLOGIES INC. + +OUI:08006C* + ID_OUI_FROM_DATABASE=SUNTEK TECHNOLOGY INT'L + +OUI:08006D* + ID_OUI_FROM_DATABASE=WHITECHAPEL COMPUTER WORKS + +OUI:08006E* + ID_OUI_FROM_DATABASE=MASSCOMP + +OUI:08006F* + ID_OUI_FROM_DATABASE=PHILIPS APELDOORN B.V. + +OUI:080070* + ID_OUI_FROM_DATABASE=MITSUBISHI ELECTRIC CORP. + +OUI:080071* + ID_OUI_FROM_DATABASE=MATRA (DSIE) + +OUI:080072* + ID_OUI_FROM_DATABASE=XEROX CORP UNIV GRANT PROGRAM + +OUI:080073* + ID_OUI_FROM_DATABASE=TECMAR INC. + +OUI:080074* + ID_OUI_FROM_DATABASE=CASIO COMPUTER CO. LTD. + +OUI:080075* + ID_OUI_FROM_DATABASE=DANSK DATA ELECTRONIK + +OUI:080076* + ID_OUI_FROM_DATABASE=PC LAN TECHNOLOGIES + +OUI:080077* + ID_OUI_FROM_DATABASE=TSL COMMUNICATIONS LTD. + +OUI:080078* + ID_OUI_FROM_DATABASE=ACCELL CORPORATION + +OUI:080079* + ID_OUI_FROM_DATABASE=THE DROID WORKS + +OUI:08007A* + ID_OUI_FROM_DATABASE=INDATA + +OUI:08007B* + ID_OUI_FROM_DATABASE=SANYO ELECTRIC CO. LTD. + +OUI:08007C* + ID_OUI_FROM_DATABASE=VITALINK COMMUNICATIONS CORP. + +OUI:08007E* + ID_OUI_FROM_DATABASE=AMALGAMATED WIRELESS(AUS) LTD + +OUI:08007F* + ID_OUI_FROM_DATABASE=CARNEGIE-MELLON UNIVERSITY + +OUI:080080* + ID_OUI_FROM_DATABASE=AES DATA INC. + +OUI:080081* + ID_OUI_FROM_DATABASE=ASTECH INC. + +OUI:080082* + ID_OUI_FROM_DATABASE=VERITAS SOFTWARE + +OUI:080083* + ID_OUI_FROM_DATABASE=Seiko Instruments Inc. + +OUI:080084* + ID_OUI_FROM_DATABASE=TOMEN ELECTRONICS CORP. + +OUI:080085* + ID_OUI_FROM_DATABASE=ELXSI + +OUI:080086* + ID_OUI_FROM_DATABASE=KONICA MINOLTA HOLDINGS, INC. + +OUI:080087* + ID_OUI_FROM_DATABASE=XYPLEX + +OUI:080088* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:080089* + ID_OUI_FROM_DATABASE=KINETICS + +OUI:08008A* + ID_OUI_FROM_DATABASE=PerfTech, Inc. + +OUI:08008B* + ID_OUI_FROM_DATABASE=PYRAMID TECHNOLOGY CORP. + +OUI:08008C* + ID_OUI_FROM_DATABASE=NETWORK RESEARCH CORPORATION + +OUI:08008D* + ID_OUI_FROM_DATABASE=XYVISION INC. + +OUI:08008E* + ID_OUI_FROM_DATABASE=TANDEM COMPUTERS + +OUI:08008F* + ID_OUI_FROM_DATABASE=CHIPCOM CORPORATION + +OUI:080090* + ID_OUI_FROM_DATABASE=SONOMA SYSTEMS + +OUI:080371* + ID_OUI_FROM_DATABASE=KRG CORPORATE + +OUI:0805CD* + ID_OUI_FROM_DATABASE=DongGuang EnMai Electronic Product Co.Ltd. + +OUI:0808C2* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:0808EA* + ID_OUI_FROM_DATABASE=AMSC + +OUI:080C0B* + ID_OUI_FROM_DATABASE=SysMik GmbH Dresden + +OUI:080CC9* + ID_OUI_FROM_DATABASE=Mission Technology Group, dba Magma + +OUI:080D84* + ID_OUI_FROM_DATABASE=GECO, Inc. + +OUI:080EA8* + ID_OUI_FROM_DATABASE=Velex s.r.l. + +OUI:080FFA* + ID_OUI_FROM_DATABASE=KSP INC. + +OUI:081196* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:081443* + ID_OUI_FROM_DATABASE=UNIBRAIN S.A. + +OUI:081651* + ID_OUI_FROM_DATABASE=Shenzhen Sea Star Technology Co.,Ltd + +OUI:081735* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0817F4* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:08181A* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:08184C* + ID_OUI_FROM_DATABASE=A. S. Thomas, Inc. + +OUI:0819A6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:081DFB* + ID_OUI_FROM_DATABASE=Shanghai Mexon Communication Technology Co.,Ltd + +OUI:081F3F* + ID_OUI_FROM_DATABASE=WondaLink Inc. + +OUI:081FF3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:082522* + ID_OUI_FROM_DATABASE=ADVANSEE + +OUI:082719* + ID_OUI_FROM_DATABASE=APS systems/electronic AG + +OUI:082AD0* + ID_OUI_FROM_DATABASE=SRD Innovations Inc. + +OUI:082E5F* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:083571* + ID_OUI_FROM_DATABASE=CASwell INC. + +OUI:08373D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:08379C* + ID_OUI_FROM_DATABASE=Topaz Co. LTD. + +OUI:0838A5* + ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH + +OUI:083AB8* + ID_OUI_FROM_DATABASE=Shinoda Plasma Co., Ltd. + +OUI:083E0C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:083E8E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:083F3E* + ID_OUI_FROM_DATABASE=WSH GmbH + +OUI:083F76* + ID_OUI_FROM_DATABASE=Intellian Technologies, Inc. + +OUI:084027* + ID_OUI_FROM_DATABASE=Gridstore Inc. + +OUI:08482C* + ID_OUI_FROM_DATABASE=Raycore Taiwan Co., LTD. + +OUI:084929* + ID_OUI_FROM_DATABASE=CYBATI + +OUI:084E1C* + ID_OUI_FROM_DATABASE=H2A Systems, LLC + +OUI:084EBF* + ID_OUI_FROM_DATABASE=Broad Net Mux Corporation + +OUI:08512E* + ID_OUI_FROM_DATABASE=Orion Diagnostica Oy + +OUI:085240* + ID_OUI_FROM_DATABASE=EbV Elektronikbau- und Vertriebs GmbH + +OUI:085700* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:085AE0* + ID_OUI_FROM_DATABASE=Recovision Technology Co., Ltd. + +OUI:085B0E* + ID_OUI_FROM_DATABASE=Fortinet, Inc. + +OUI:08606E* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:086361* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:0868D0* + ID_OUI_FROM_DATABASE=Japan System Design + +OUI:0868EA* + ID_OUI_FROM_DATABASE=EITO ELECTRONICS CO., LTD. + +OUI:086DF2* + ID_OUI_FROM_DATABASE=Shenzhen MIMOWAVE Technology Co.,Ltd + +OUI:087045* + ID_OUI_FROM_DATABASE=Apple + +OUI:087572* + ID_OUI_FROM_DATABASE=Obelux Oy + +OUI:087618* + ID_OUI_FROM_DATABASE=ViE Technologies Sdn. Bhd. + +OUI:087695* + ID_OUI_FROM_DATABASE=Auto Industrial Co., Ltd. + +OUI:0876FF* + ID_OUI_FROM_DATABASE=Thomson Telecom Belgium + +OUI:087999* + ID_OUI_FROM_DATABASE=AIM GmbH + +OUI:087A4C* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:087BAA* + ID_OUI_FROM_DATABASE=SVYAZKOMPLEKTSERVICE, LLC + +OUI:087CBE* + ID_OUI_FROM_DATABASE=Quintic Corp. + +OUI:087D21* + ID_OUI_FROM_DATABASE=Altasec technology corporation + +OUI:088039* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:0881F4* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:08863B* + ID_OUI_FROM_DATABASE=Belkin International, Inc. + +OUI:088DC8* + ID_OUI_FROM_DATABASE=Ryowa Electronics Co.,Ltd + +OUI:088E4F* + ID_OUI_FROM_DATABASE=SF Software Solutions + +OUI:088F2C* + ID_OUI_FROM_DATABASE=Hills Sound Vision & Lighting + +OUI:0896D7* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:089758* + ID_OUI_FROM_DATABASE=Shenzhen Strong Rising Electronics Co.,Ltd DongGuan Subsidiary + +OUI:089E01* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. + +OUI:089F97* + ID_OUI_FROM_DATABASE=LEROY AUTOMATION + +OUI:08A12B* + ID_OUI_FROM_DATABASE=ShenZhen EZL Technology Co., Ltd + +OUI:08A95A* + ID_OUI_FROM_DATABASE=Azurewave + +OUI:08ACA5* + ID_OUI_FROM_DATABASE=Benu Video, Inc. + +OUI:08AF78* + ID_OUI_FROM_DATABASE=Totus Solutions, Inc. + +OUI:08B4CF* + ID_OUI_FROM_DATABASE=Abicom International + +OUI:08B738* + ID_OUI_FROM_DATABASE=Lite-On Technogy Corp. + +OUI:08B7EC* + ID_OUI_FROM_DATABASE=Wireless Seismic + +OUI:08BBCC* + ID_OUI_FROM_DATABASE=AK-NORD EDV VERTRIEBSGES. mbH + +OUI:08BD43* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:08BE09* + ID_OUI_FROM_DATABASE=Astrol Electronic AG + +OUI:08CA45* + ID_OUI_FROM_DATABASE=Toyou Feiji Electronics Co., Ltd. + +OUI:08CC68* + ID_OUI_FROM_DATABASE=Cisco + +OUI:08D09F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:08D29A* + ID_OUI_FROM_DATABASE=Proformatique + +OUI:08D40C* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:08D42B* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:08D5C0* + ID_OUI_FROM_DATABASE=Seers Technology Co., Ltd + +OUI:08D833* + ID_OUI_FROM_DATABASE=Shenzhen RF Technology Co,.Ltd + +OUI:08E5DA* + ID_OUI_FROM_DATABASE=NANJING FUJITSU COMPUTER PRODUCTS CO.,LTD. + +OUI:08E672* + ID_OUI_FROM_DATABASE=JEBSEE ELECTRONICS CO.,LTD. + +OUI:08EA44* + ID_OUI_FROM_DATABASE=Aerohive Networks, Inc. + +OUI:08EB74* + ID_OUI_FROM_DATABASE=Humax + +OUI:08EBED* + ID_OUI_FROM_DATABASE=World Elite Technology Co.,LTD + +OUI:08EDB9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:08EF3B* + ID_OUI_FROM_DATABASE=MCS Logic Inc. + +OUI:08F1B7* + ID_OUI_FROM_DATABASE=Towerstream Corpration + +OUI:08F2F4* + ID_OUI_FROM_DATABASE=Net One Partners Co.,Ltd. + +OUI:08F6F8* + ID_OUI_FROM_DATABASE=GET Engineering + +OUI:08FAE0* + ID_OUI_FROM_DATABASE=Fohhn Audio AG + +OUI:08FC52* + ID_OUI_FROM_DATABASE=OpenXS BV + +OUI:08FC88* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:08FD0E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0C0400* + ID_OUI_FROM_DATABASE=Jantar d.o.o. + +OUI:0C0535* + ID_OUI_FROM_DATABASE=Juniper Systems + +OUI:0C1105* + ID_OUI_FROM_DATABASE=Ringslink (Xiamen) Network Communication Technologies Co., Ltd + +OUI:0C1262* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:0C130B* + ID_OUI_FROM_DATABASE=Uniqoteq Ltd. + +OUI:0C1420* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0C15C5* + ID_OUI_FROM_DATABASE=SDTEC Co., Ltd. + +OUI:0C17F1* + ID_OUI_FROM_DATABASE=TELECSYS + +OUI:0C191F* + ID_OUI_FROM_DATABASE=Inform Electronik + +OUI:0C1DC2* + ID_OUI_FROM_DATABASE=SeAH Networks + +OUI:0C2724* + ID_OUI_FROM_DATABASE=Cisco + +OUI:0C2755* + ID_OUI_FROM_DATABASE=Valuable Techologies Limited + +OUI:0C2A69* + ID_OUI_FROM_DATABASE=electric imp, incorporated + +OUI:0C2AE7* + ID_OUI_FROM_DATABASE=Beijing General Research Institute of Mining and Metallurgy + +OUI:0C2D89* + ID_OUI_FROM_DATABASE=QiiQ Communications Inc. + +OUI:0C3021* + ID_OUI_FROM_DATABASE=Apple + +OUI:0C37DC* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:0C3956* + ID_OUI_FROM_DATABASE=Observator instruments + +OUI:0C3C65* + ID_OUI_FROM_DATABASE=Dome Imaging Inc + +OUI:0C3E9F* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:0C469D* + ID_OUI_FROM_DATABASE=MS Sedco + +OUI:0C473D* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:0C4C39* + ID_OUI_FROM_DATABASE=Mitrastar Technology + +OUI:0C4DE9* + ID_OUI_FROM_DATABASE=Apple + +OUI:0C4F5A* + ID_OUI_FROM_DATABASE=ASA-RT s.r.l. + +OUI:0C51F7* + ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX + +OUI:0C54A5* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:0C5521* + ID_OUI_FROM_DATABASE=Axiros GmbH + +OUI:0C565C* + ID_OUI_FROM_DATABASE=HyBroad Vision (Hong Kong) Technology Co Ltd + +OUI:0C57EB* + ID_OUI_FROM_DATABASE=Mueller Systems + +OUI:0C5A19* + ID_OUI_FROM_DATABASE=Axtion Sdn Bhd + +OUI:0C5CD8* + ID_OUI_FROM_DATABASE=DOLI Elektronik GmbH + +OUI:0C6076* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:0C6803* + ID_OUI_FROM_DATABASE=Cisco + +OUI:0C6E4F* + ID_OUI_FROM_DATABASE=PrimeVOLT Co., Ltd. + +OUI:0C715D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0C722C* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:0C74C2* + ID_OUI_FROM_DATABASE=Apple + +OUI:0C7523* + ID_OUI_FROM_DATABASE=BEIJING GEHUA CATV NETWORK CO.,LTD + +OUI:0C771A* + ID_OUI_FROM_DATABASE=Apple + +OUI:0C7D7C* + ID_OUI_FROM_DATABASE=Kexiang Information Technology Co, Ltd. + +OUI:0C8230* + ID_OUI_FROM_DATABASE=SHENZHEN MAGNUS TECHNOLOGIES CO.,LTD + +OUI:0C8268* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:0C826A* + ID_OUI_FROM_DATABASE=Wuhan Huagong Genuine Optics Technology Co., Ltd + +OUI:0C8411* + ID_OUI_FROM_DATABASE=A.O. Smith Water Products + +OUI:0C8484* + ID_OUI_FROM_DATABASE=Zenovia Electronics Inc. + +OUI:0C84DC* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:0C8525* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0C8910* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:0C8BFD* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0C8CDC* + ID_OUI_FROM_DATABASE=Suunto Oy + +OUI:0C8D98* + ID_OUI_FROM_DATABASE=TOP EIGHT IND CORP + +OUI:0C924E* + ID_OUI_FROM_DATABASE=Rice Lake Weighing Systems + +OUI:0C9301* + ID_OUI_FROM_DATABASE=PT. Prasimax Inovasi Teknologi + +OUI:0C93FB* + ID_OUI_FROM_DATABASE=BNS Solutions + +OUI:0C96BF* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:0C9B13* + ID_OUI_FROM_DATABASE=Shanghai Magic Mobile Telecommunication Co.Ltd. + +OUI:0C9D56* + ID_OUI_FROM_DATABASE=Consort Controls Ltd + +OUI:0C9E91* + ID_OUI_FROM_DATABASE=Sankosha Corporation + +OUI:0CA138* + ID_OUI_FROM_DATABASE=Blinq Wireless Inc. + +OUI:0CA2F4* + ID_OUI_FROM_DATABASE=Chameleon Technology (UK) Limited + +OUI:0CA402* + ID_OUI_FROM_DATABASE=Alcatel Lucent IPD + +OUI:0CA42A* + ID_OUI_FROM_DATABASE=OB Telecom Electronic Technology Co., Ltd + +OUI:0CA694* + ID_OUI_FROM_DATABASE=Sunitec Enterprise Co.,Ltd + +OUI:0CAF5A* + ID_OUI_FROM_DATABASE=GENUS POWER INFRASTRUCTURES LIMITED + +OUI:0CB4EF* + ID_OUI_FROM_DATABASE=Digience Co.,Ltd. + +OUI:0CBD51* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:0CBF15* + ID_OUI_FROM_DATABASE=Genetec + +OUI:0CC0C0* + ID_OUI_FROM_DATABASE=MAGNETI MARELLI SISTEMAS ELECTRONICOS MEXICO + +OUI:0CC3A7* + ID_OUI_FROM_DATABASE=Meritec + +OUI:0CC47A* + ID_OUI_FROM_DATABASE=Super Micro Computer, Inc. + +OUI:0CC47E* + ID_OUI_FROM_DATABASE=EUCAST Co., Ltd. + +OUI:0CC655* + ID_OUI_FROM_DATABASE=Wuxi YSTen Technology Co.,Ltd. + +OUI:0CC66A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:0CC6AC* + ID_OUI_FROM_DATABASE=DAGS + +OUI:0CC81F* + ID_OUI_FROM_DATABASE=Summer Infant, Inc. + +OUI:0CC9C6* + ID_OUI_FROM_DATABASE=Samwin Hong Kong Limited + +OUI:0CCB8D* + ID_OUI_FROM_DATABASE=ASCO Numatics GmbH + +OUI:0CCDD3* + ID_OUI_FROM_DATABASE=EASTRIVER TECHNOLOGY CO., LTD. + +OUI:0CCDFB* + ID_OUI_FROM_DATABASE=EDIC Systems Inc. + +OUI:0CD292* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0CD2B5* + ID_OUI_FROM_DATABASE=Binatone Telecommunication Pvt. Ltd + +OUI:0CD502* + ID_OUI_FROM_DATABASE=Westell + +OUI:0CD696* + ID_OUI_FROM_DATABASE=Amimon Ltd + +OUI:0CD7C2* + ID_OUI_FROM_DATABASE=Axium Technologies, Inc. + +OUI:0CD996* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:0CD9C1* + ID_OUI_FROM_DATABASE=Johnson Controls-ASG + +OUI:0CDA41* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:0CDCCC* + ID_OUI_FROM_DATABASE=Inala Technologies + +OUI:0CDDEF* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:0CDFA4* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0CE0E4* + ID_OUI_FROM_DATABASE=Plantronics, Inc + +OUI:0CE5D3* + ID_OUI_FROM_DATABASE=DH electronics GmbH + +OUI:0CE709* + ID_OUI_FROM_DATABASE=Fox Crypto B.V. + +OUI:0CE82F* + ID_OUI_FROM_DATABASE=Bonfiglioli Vectron GmbH + +OUI:0CE936* + ID_OUI_FROM_DATABASE=ELIMOS srl + +OUI:0CEEE6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:0CEF7C* + ID_OUI_FROM_DATABASE=AnaCom Inc + +OUI:0CF019* + ID_OUI_FROM_DATABASE=Malgn Technology Co., Ltd. + +OUI:0CF0B4* + ID_OUI_FROM_DATABASE=Globalsat International Technology Ltd + +OUI:0CF361* + ID_OUI_FROM_DATABASE=Java Information + +OUI:0CF3EE* + ID_OUI_FROM_DATABASE=EM Microelectronic + +OUI:0CF405* + ID_OUI_FROM_DATABASE=Beijing Signalway Technologies Co.,Ltd + +OUI:0CF893* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:0CFC83* + ID_OUI_FROM_DATABASE=Airoha Technology Corp., + +OUI:10005A* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:1000E8* + ID_OUI_FROM_DATABASE=NATIONAL SEMICONDUCTOR + +OUI:1000FD* + ID_OUI_FROM_DATABASE=LaonPeople + +OUI:1001CA* + ID_OUI_FROM_DATABASE=Ashley Butterworth + +OUI:10090C* + ID_OUI_FROM_DATABASE=Janome Sewing Machine Co., Ltd. + +OUI:100BA9* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:100C24* + ID_OUI_FROM_DATABASE=pomdevices, LLC + +OUI:100D2F* + ID_OUI_FROM_DATABASE=Online Security Pty. Ltd. + +OUI:100D32* + ID_OUI_FROM_DATABASE=Embedian, Inc. + +OUI:100D7F* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:100E2B* + ID_OUI_FROM_DATABASE=NEC CASIO Mobile Communications + +OUI:100E7E* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:1010B6* + ID_OUI_FROM_DATABASE=McCain Inc + +OUI:101212* + ID_OUI_FROM_DATABASE=Vivo International Corporation Pty Ltd + +OUI:101248* + ID_OUI_FROM_DATABASE=ITG, Inc. + +OUI:1013EE* + ID_OUI_FROM_DATABASE=Justec International Technology INC. + +OUI:10189E* + ID_OUI_FROM_DATABASE=Elmo Motion Control + +OUI:101B54* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:101C0C* + ID_OUI_FROM_DATABASE=Apple + +OUI:101D51* + ID_OUI_FROM_DATABASE=ON-Q LLC dba ON-Q Mesh Networks + +OUI:101DC0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:101F74* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:102279* + ID_OUI_FROM_DATABASE=ZeroDesktop, Inc. + +OUI:1027BE* + ID_OUI_FROM_DATABASE=TVIP + +OUI:102831* + ID_OUI_FROM_DATABASE=Morion Inc. + +OUI:102D96* + ID_OUI_FROM_DATABASE=Looxcie Inc. + +OUI:102EAF* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:103378* + ID_OUI_FROM_DATABASE=FLECTRON Co., LTD + +OUI:103711* + ID_OUI_FROM_DATABASE=Simlink AS + +OUI:103B59* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:103DEA* + ID_OUI_FROM_DATABASE=HFC Technology (Beijing) Ltd. Co. + +OUI:1040F3* + ID_OUI_FROM_DATABASE=Apple + +OUI:104369* + ID_OUI_FROM_DATABASE=Soundmax Electronic Limited + +OUI:10445A* + ID_OUI_FROM_DATABASE=Shaanxi Hitech Electronic Co., LTD + +OUI:1045BE* + ID_OUI_FROM_DATABASE=Norphonic AS + +OUI:1045F8* + ID_OUI_FROM_DATABASE=LNT-Automation GmbH + +OUI:104780* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:1048B1* + ID_OUI_FROM_DATABASE=Beijing Duokan Technology Limited + +OUI:104D77* + ID_OUI_FROM_DATABASE=Innovative Computer Engineering + +OUI:1056CA* + ID_OUI_FROM_DATABASE=Peplink International Ltd. + +OUI:105C3B* + ID_OUI_FROM_DATABASE=Perma-Pipe, Inc. + +OUI:105CBF* + ID_OUI_FROM_DATABASE=DuroByte Inc + +OUI:105F06* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:105F49* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:10604B* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:1062C9* + ID_OUI_FROM_DATABASE=Adatis GmbH & Co. KG + +OUI:1064E2* + ID_OUI_FROM_DATABASE=ADFweb.com s.r.l. + +OUI:1065A3* + ID_OUI_FROM_DATABASE=Core Brands LLC + +OUI:1065CF* + ID_OUI_FROM_DATABASE=IQSIM + +OUI:106682* + ID_OUI_FROM_DATABASE=NEC AccessTechnica, Ltd. + +OUI:10683F* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:106F3F* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:106FEF* + ID_OUI_FROM_DATABASE=Ad-Sol Nissin Corp + +OUI:1071F9* + ID_OUI_FROM_DATABASE=Cloud Telecomputers, LLC + +OUI:10768A* + ID_OUI_FROM_DATABASE=EoCell + +OUI:1077B1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:1078CE* + ID_OUI_FROM_DATABASE=Hanvit SI, Inc. + +OUI:1078D2* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. + +OUI:107A86* + ID_OUI_FROM_DATABASE=U&U ENGINEERING INC. + +OUI:107BEF* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corp + +OUI:1083D2* + ID_OUI_FROM_DATABASE=Microseven Systems, LLC + +OUI:10880F* + ID_OUI_FROM_DATABASE=Daruma Telecomunicações e Informática S.A. + +OUI:108CCF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:1093E9* + ID_OUI_FROM_DATABASE=Apple + +OUI:109AB9* + ID_OUI_FROM_DATABASE=Tosibox Oy + +OUI:109ADD* + ID_OUI_FROM_DATABASE=Apple + +OUI:109FA9* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:10A13B* + ID_OUI_FROM_DATABASE=FUJIKURA RUBBER LTD. + +OUI:10A5D0* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co.,Ltd. + +OUI:10A743* + ID_OUI_FROM_DATABASE=SK Mtek Limited + +OUI:10A932* + ID_OUI_FROM_DATABASE=Beijing Cyber Cloud Technology Co. ,Ltd. + +OUI:10B26B* + ID_OUI_FROM_DATABASE=base Co.,Ltd. + +OUI:10B7F6* + ID_OUI_FROM_DATABASE=Plastoform Industries Ltd. + +OUI:10B9FE* + ID_OUI_FROM_DATABASE=Lika srl + +OUI:10BAA5* + ID_OUI_FROM_DATABASE=GANA I&C CO., LTD + +OUI:10BD18* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:10BF48* + ID_OUI_FROM_DATABASE=ASUSTEK COMPUTER INC. + +OUI:10C2BA* + ID_OUI_FROM_DATABASE=UTT Co., Ltd. + +OUI:10C586* + ID_OUI_FROM_DATABASE=BIO SOUND LAB CO., LTD. + +OUI:10C61F* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:10C6FC* + ID_OUI_FROM_DATABASE=Garmin International + +OUI:10C73F* + ID_OUI_FROM_DATABASE=Midas Klark Teknik Ltd + +OUI:10CA81* + ID_OUI_FROM_DATABASE=PRECIA + +OUI:10CCDB* + ID_OUI_FROM_DATABASE=AXIMUM PRODUITS ELECTRONIQUES + +OUI:10D1DC* + ID_OUI_FROM_DATABASE=INSTAR Deutschland GmbH + +OUI:10D542* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:10DDB1* + ID_OUI_FROM_DATABASE=Apple + +OUI:10DDF4* + ID_OUI_FROM_DATABASE=Maxway Electronics CO.,LTD + +OUI:10DEE4* + ID_OUI_FROM_DATABASE=automationNEXT GmbH + +OUI:10E2D5* + ID_OUI_FROM_DATABASE=Qi Hardware Inc. + +OUI:10E3C7* + ID_OUI_FROM_DATABASE=Seohwa Telecom + +OUI:10E4AF* + ID_OUI_FROM_DATABASE=APR, LLC + +OUI:10E6AE* + ID_OUI_FROM_DATABASE=Source Technologies, LLC + +OUI:10E8EE* + ID_OUI_FROM_DATABASE=PhaseSpace + +OUI:10EA59* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:10EED9* + ID_OUI_FROM_DATABASE=Canoga Perkins Corporation + +OUI:10F311* + ID_OUI_FROM_DATABASE=Cisco + +OUI:10F3DB* + ID_OUI_FROM_DATABASE=Gridco Systems, Inc. + +OUI:10F49A* + ID_OUI_FROM_DATABASE=T3 Innovation + +OUI:10F96F* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:10F9EE* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:10FBF0* + ID_OUI_FROM_DATABASE=KangSheng LTD. + +OUI:10FC54* + ID_OUI_FROM_DATABASE=Shany Electronic Co., Ltd. + +OUI:10FEED* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:1407E0* + ID_OUI_FROM_DATABASE=Abrantix AG + +OUI:140C76* + ID_OUI_FROM_DATABASE=FREEBOX SAS + +OUI:140D4F* + ID_OUI_FROM_DATABASE=Flextronics International + +OUI:14109F* + ID_OUI_FROM_DATABASE=Apple + +OUI:141330* + ID_OUI_FROM_DATABASE=Anakreon UK LLP + +OUI:14144B* + ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD + +OUI:141A51* + ID_OUI_FROM_DATABASE=Treetech Sistemas Digitais + +OUI:141BBD* + ID_OUI_FROM_DATABASE=Volex Inc. + +OUI:141BF0* + ID_OUI_FROM_DATABASE=Intellimedia Systems Ltd + +OUI:1423D7* + ID_OUI_FROM_DATABASE=EUTRONIX CO., LTD. + +OUI:142BD2* + ID_OUI_FROM_DATABASE=Armtel Ltd. + +OUI:142D27* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:142D8B* + ID_OUI_FROM_DATABASE=Incipio Technologies, Inc + +OUI:142DF5* + ID_OUI_FROM_DATABASE=Amphitech + +OUI:14307A* + ID_OUI_FROM_DATABASE=Avermetrics + +OUI:14358B* + ID_OUI_FROM_DATABASE=Mediabridge Products, LLC. + +OUI:1435B3* + ID_OUI_FROM_DATABASE=Future Designs, Inc. + +OUI:143605* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:14373B* + ID_OUI_FROM_DATABASE=PROCOM Systems + +OUI:143AEA* + ID_OUI_FROM_DATABASE=Dynapower Company LLC + +OUI:143E60* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:1441E2* + ID_OUI_FROM_DATABASE=Monaco Enterprises, Inc. + +OUI:144319* + ID_OUI_FROM_DATABASE=Creative&Link Technology Limited + +OUI:1446E4* + ID_OUI_FROM_DATABASE=AVISTEL + +OUI:144978* + ID_OUI_FROM_DATABASE=Digital Control Incorporated + +OUI:1449E0* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:144C1A* + ID_OUI_FROM_DATABASE=Max Communication GmbH + +OUI:145412* + ID_OUI_FROM_DATABASE=Entis Co., Ltd. + +OUI:145A05* + ID_OUI_FROM_DATABASE=Apple + +OUI:145BD1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:146080* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:146308* + ID_OUI_FROM_DATABASE=JABIL CIRCUIT (SHANGHAI) LTD. + +OUI:146A0B* + ID_OUI_FROM_DATABASE=Cypress Electronics Limited + +OUI:147373* + ID_OUI_FROM_DATABASE=TUBITAK UEKAE + +OUI:147411* + ID_OUI_FROM_DATABASE=RIM + +OUI:147DB3* + ID_OUI_FROM_DATABASE=JOA TELECOM.CO.,LTD + +OUI:147DC5* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:14825B* + ID_OUI_FROM_DATABASE=Hefei Radio Communication Technology Co., Ltd + +OUI:148692* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:1489FD* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:148A70* + ID_OUI_FROM_DATABASE=ADS GmbH + +OUI:148FC6* + ID_OUI_FROM_DATABASE=Apple + +OUI:149090* + ID_OUI_FROM_DATABASE=KongTop industrial(shen zhen)CO.,LTD + +OUI:149448* + ID_OUI_FROM_DATABASE=BLU CASTLE S.A. + +OUI:1499E2* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:149FE8* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:14A62C* + ID_OUI_FROM_DATABASE=S.M. Dezac S.A. + +OUI:14A86B* + ID_OUI_FROM_DATABASE=ShenZhen Telacom Science&Technology Co., Ltd + +OUI:14A9E3* + ID_OUI_FROM_DATABASE=MST CORPORATION + +OUI:14ABF0* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:14B126* + ID_OUI_FROM_DATABASE=Industrial Software Co + +OUI:14B1C8* + ID_OUI_FROM_DATABASE=InfiniWing, Inc. + +OUI:14B73D* + ID_OUI_FROM_DATABASE=ARCHEAN Technologies + +OUI:14B968* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:14C089* + ID_OUI_FROM_DATABASE=DUNE HD LTD + +OUI:14C21D* + ID_OUI_FROM_DATABASE=Sabtech Industries + +OUI:14CC20* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD + +OUI:14CF8D* + ID_OUI_FROM_DATABASE=OHSUNG ELECTRONICS CO., LTD. + +OUI:14CF92* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:14CFE2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:14D4FE* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:14D64D* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:14D76E* + ID_OUI_FROM_DATABASE=CONCH ELECTRONIC Co.,Ltd + +OUI:14DAE9* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:14DB85* + ID_OUI_FROM_DATABASE=S NET MEDIA + +OUI:14E4EC* + ID_OUI_FROM_DATABASE=mLogic LLC + +OUI:14E6E4* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:14EB33* + ID_OUI_FROM_DATABASE=BSMediasoft Co., Ltd. + +OUI:14EDA5* + ID_OUI_FROM_DATABASE=Wächter GmbH Sicherheitssysteme + +OUI:14EE9D* + ID_OUI_FROM_DATABASE=AirNav Systems LLC + +OUI:14F0C5* + ID_OUI_FROM_DATABASE=Xtremio Ltd. + +OUI:14F28E* + ID_OUI_FROM_DATABASE=ShenYang ZhongKe-Allwin Technology Co.LTD + +OUI:14F42A* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:14FEAF* + ID_OUI_FROM_DATABASE=SAGITTAR LIMITED + +OUI:14FEB5* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:18002D* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:1800DB* + ID_OUI_FROM_DATABASE=Fitbit Inc. + +OUI:1801E3* + ID_OUI_FROM_DATABASE=Elektrobit Wireless Communications Ltd + +OUI:180373* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:1803FA* + ID_OUI_FROM_DATABASE=IBT Interfaces + +OUI:180675* + ID_OUI_FROM_DATABASE=DILAX Intelcom GmbH + +OUI:180B52* + ID_OUI_FROM_DATABASE=Nanotron Technologies GmbH + +OUI:180C14* + ID_OUI_FROM_DATABASE=iSonea Limited + +OUI:180C77* + ID_OUI_FROM_DATABASE=Westinghouse Electric Company, LLC + +OUI:180CAC* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:18104E* + ID_OUI_FROM_DATABASE=CEDINT-UPM + +OUI:181420* + ID_OUI_FROM_DATABASE=TEB SAS + +OUI:181456* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:181714* + ID_OUI_FROM_DATABASE=DAEWOOIS + +OUI:181725* + ID_OUI_FROM_DATABASE=Cameo Communications, Inc. + +OUI:18193F* + ID_OUI_FROM_DATABASE=Tamtron Oy + +OUI:181BEB* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:181EB0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:182012* + ID_OUI_FROM_DATABASE=Aztech Associates Inc. + +OUI:182032* + ID_OUI_FROM_DATABASE=Apple + +OUI:1820A6* + ID_OUI_FROM_DATABASE=Sage Co., Ltd. + +OUI:182666* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:182861* + ID_OUI_FROM_DATABASE=AirTies Wireless Networks + +OUI:182A7B* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:182B05* + ID_OUI_FROM_DATABASE=8D Technologies + +OUI:182C91* + ID_OUI_FROM_DATABASE=Concept Development, Inc. + +OUI:1832A2* + ID_OUI_FROM_DATABASE=LAON TECHNOLOGY CO., LTD. + +OUI:18339D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:183451* + ID_OUI_FROM_DATABASE=Apple + +OUI:1836FC* + ID_OUI_FROM_DATABASE=Elecsys International Corporation + +OUI:183825* + ID_OUI_FROM_DATABASE=Wuhan Lingjiu High-tech Co.,Ltd. + +OUI:183919* + ID_OUI_FROM_DATABASE=Unicoi Systems + +OUI:183BD2* + ID_OUI_FROM_DATABASE=BYD Precision Manufacture Company Ltd. + +OUI:183DA2* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:183F47* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:18422F* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:184462* + ID_OUI_FROM_DATABASE=Riava Networks, Inc. + +OUI:184617* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:1848D8* + ID_OUI_FROM_DATABASE=Fastback Networks + +OUI:184E94* + ID_OUI_FROM_DATABASE=MESSOA TECHNOLOGIES INC. + +OUI:185253* + ID_OUI_FROM_DATABASE=Pixord Corporation + +OUI:1853E0* + ID_OUI_FROM_DATABASE=Hanyang Digitech Co.Ltd + +OUI:18550F* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:185933* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:185AE8* + ID_OUI_FROM_DATABASE=Zenotech.Co.,Ltd + +OUI:18622C* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:186472* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:1866E3* + ID_OUI_FROM_DATABASE=Veros Systems, Inc. + +OUI:18673F* + ID_OUI_FROM_DATABASE=Hanover Displays Limited + +OUI:186751* + ID_OUI_FROM_DATABASE=KOMEG Industrielle Messtechnik GmbH + +OUI:1867B0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:186D99* + ID_OUI_FROM_DATABASE=Adanis Inc. + +OUI:1879A2* + ID_OUI_FROM_DATABASE=GMJ ELECTRIC LIMITED + +OUI:187A93* + ID_OUI_FROM_DATABASE=AMICCOM Electronics Corporation + +OUI:187C81* + ID_OUI_FROM_DATABASE=Valeo Vision Systems + +OUI:187ED5* + ID_OUI_FROM_DATABASE=shenzhen kaism technology Co. Ltd + +OUI:1880CE* + ID_OUI_FROM_DATABASE=Barberry Solutions Ltd + +OUI:1880F5* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:188331* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:188410* + ID_OUI_FROM_DATABASE=CoreTrust Inc. + +OUI:18863A* + ID_OUI_FROM_DATABASE=DIGITAL ART SYSTEM + +OUI:1886AC* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:188796* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:188857* + ID_OUI_FROM_DATABASE=Beijing Jinhong Xi-Dian Information Technology Corp. + +OUI:1889DF* + ID_OUI_FROM_DATABASE=CerebrEX Inc. + +OUI:188ED5* + ID_OUI_FROM_DATABASE=TP Vision Belgium N.V. - innovation site Brugge + +OUI:18922C* + ID_OUI_FROM_DATABASE=Virtual Instruments + +OUI:1897FF* + ID_OUI_FROM_DATABASE=TechFaith Wireless Technology Limited + +OUI:189A67* + ID_OUI_FROM_DATABASE=CSE-Servelec Limited + +OUI:189C5D* + ID_OUI_FROM_DATABASE=Cisco + +OUI:189EFC* + ID_OUI_FROM_DATABASE=Apple + +OUI:18A905* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:18A99B* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:18AA45* + ID_OUI_FROM_DATABASE=Fon Technology + +OUI:18ABF5* + ID_OUI_FROM_DATABASE=Ultra Electronics - Electrics + +OUI:18AD4D* + ID_OUI_FROM_DATABASE=Polostar Technology Corporation + +OUI:18AEBB* + ID_OUI_FROM_DATABASE=Siemens Convergence Creators GmbH&Co.KG + +OUI:18AF61* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:18AF8F* + ID_OUI_FROM_DATABASE=Apple + +OUI:18AF9F* + ID_OUI_FROM_DATABASE=DIGITRONIC Automationsanlagen GmbH + +OUI:18B209* + ID_OUI_FROM_DATABASE=Torrey Pines Logic, Inc + +OUI:18B3BA* + ID_OUI_FROM_DATABASE=Netlogic AB + +OUI:18B430* + ID_OUI_FROM_DATABASE=Nest Labs Inc. + +OUI:18B591* + ID_OUI_FROM_DATABASE=I-Storm + +OUI:18B79E* + ID_OUI_FROM_DATABASE=Invoxia + +OUI:18C086* + ID_OUI_FROM_DATABASE=Broadcom Corporation + +OUI:18C451* + ID_OUI_FROM_DATABASE=Tucson Embedded Systems + +OUI:18C8E7* + ID_OUI_FROM_DATABASE=Shenzhen Hualistone Technology Co.,Ltd + +OUI:18CC23* + ID_OUI_FROM_DATABASE=Philio Technology Corporation + +OUI:18D071* + ID_OUI_FROM_DATABASE=DASAN SMC, Inc. + +OUI:18D66A* + ID_OUI_FROM_DATABASE=Inmarsat + +OUI:18D6CF* + ID_OUI_FROM_DATABASE=Kurth Electronic GmbH + +OUI:18D949* + ID_OUI_FROM_DATABASE=Qvis Labs, LLC + +OUI:18DC56* + ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific(shenzhen)Co.,Lt + +OUI:18E288* + ID_OUI_FROM_DATABASE=STT Condigi + +OUI:18E2C2* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:18E728* + ID_OUI_FROM_DATABASE=Cisco + +OUI:18E7F4* + ID_OUI_FROM_DATABASE=Apple + +OUI:18E80F* + ID_OUI_FROM_DATABASE=Viking Electronics Inc. + +OUI:18E8DD* + ID_OUI_FROM_DATABASE=MODULETEK + +OUI:18EF63* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:18F46A* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:18F650* + ID_OUI_FROM_DATABASE=Multimedia Pacific Limited + +OUI:18F87A* + ID_OUI_FROM_DATABASE=i3 International Inc. + +OUI:18FA6F* + ID_OUI_FROM_DATABASE=ISC applied systems corp + +OUI:18FC9F* + ID_OUI_FROM_DATABASE=Changhe Electronics Co., Ltd. + +OUI:18FE34* + ID_OUI_FROM_DATABASE=Espressif Inc. + +OUI:18FF2E* + ID_OUI_FROM_DATABASE=Shenzhen Rui Ying Da Technology Co., Ltd + +OUI:1C0656* + ID_OUI_FROM_DATABASE=IDY Corporation + +OUI:1C08C1* + ID_OUI_FROM_DATABASE=Lg Innotek + +OUI:1C0B52* + ID_OUI_FROM_DATABASE=EPICOM S.A + +OUI:1C0FCF* + ID_OUI_FROM_DATABASE=Sypro Optics GmbH + +OUI:1C11E1* + ID_OUI_FROM_DATABASE=Wartsila Finland Oy + +OUI:1C129D* + ID_OUI_FROM_DATABASE=IEEE PES PSRC/SUB + +OUI:1C1448* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:1C17D3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:1C184A* + ID_OUI_FROM_DATABASE=ShenZhen RicherLink Technologies Co.,LTD + +OUI:1C19DE* + ID_OUI_FROM_DATABASE=eyevis GmbH + +OUI:1C1B68* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:1C1D67* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:1C1D86* + ID_OUI_FROM_DATABASE=Cisco + +OUI:1C334D* + ID_OUI_FROM_DATABASE=ITS Telecom + +OUI:1C3477* + ID_OUI_FROM_DATABASE=Innovation Wireless + +OUI:1C35F1* + ID_OUI_FROM_DATABASE=NEW Lift Neue Elektronische Wege Steuerungsbau GmbH + +OUI:1C37BF* + ID_OUI_FROM_DATABASE=Cloudium Systems Ltd. + +OUI:1C3A4F* + ID_OUI_FROM_DATABASE=AccuSpec Electronics, LLC + +OUI:1C3DE7* + ID_OUI_FROM_DATABASE=Sigma Koki Co.,Ltd. + +OUI:1C3E84* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:1C4158* + ID_OUI_FROM_DATABASE=Gemalto M2M GmbH + +OUI:1C43EC* + ID_OUI_FROM_DATABASE=JAPAN CIRCUIT CO.,LTD + +OUI:1C4593* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:1C48F9* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:1C4AF7* + ID_OUI_FROM_DATABASE=AMON INC + +OUI:1C4BB9* + ID_OUI_FROM_DATABASE=SMG ENTERPRISE, LLC + +OUI:1C4BD6* + ID_OUI_FROM_DATABASE=AzureWave + +OUI:1C51B5* + ID_OUI_FROM_DATABASE=Techaya LTD + +OUI:1C52D6* + ID_OUI_FROM_DATABASE=FLAT DISPLAY TECHNOLOGY CORPORATION + +OUI:1C5A3E* + ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd (Visual Display Divison) + +OUI:1C5A6B* + ID_OUI_FROM_DATABASE=Philips Electronics Nederland BV + +OUI:1C5C55* + ID_OUI_FROM_DATABASE=PRIMA Cinema, Inc + +OUI:1C5C60* + ID_OUI_FROM_DATABASE=Shenzhen Belzon Technology Co.,LTD. + +OUI:1C5FFF* + ID_OUI_FROM_DATABASE=Beijing Ereneben Information Technology Co.,Ltd Shenzhen Branch + +OUI:1C62B8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1C63B7* + ID_OUI_FROM_DATABASE=OpenProducts 237 AB + +OUI:1C659D* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:1C666D* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:1C66AA* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:1C69A5* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:1C6BCA* + ID_OUI_FROM_DATABASE=Mitsunami Co., Ltd. + +OUI:1C6F65* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:1C7508* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:1C76CA* + ID_OUI_FROM_DATABASE=Terasic Technologies Inc. + +OUI:1C7839* + ID_OUI_FROM_DATABASE=Shenzhen Tencent Computer System Co., Ltd. + +OUI:1C7B21* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:1C7C11* + ID_OUI_FROM_DATABASE=EID + +OUI:1C7C45* + ID_OUI_FROM_DATABASE=Vitek Industrial Video Products, Inc. + +OUI:1C7CC7* + ID_OUI_FROM_DATABASE=Coriant GmbH + +OUI:1C7EE5* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:1C83B0* + ID_OUI_FROM_DATABASE=Linked IP GmbH + +OUI:1C8464* + ID_OUI_FROM_DATABASE=FORMOSA WIRELESS COMMUNICATION CORP. + +OUI:1C86AD* + ID_OUI_FROM_DATABASE=MCT CO., LTD. + +OUI:1C8E8E* + ID_OUI_FROM_DATABASE=DB Communication & Systems Co., ltd. + +OUI:1C8F8A* + ID_OUI_FROM_DATABASE=Phase Motion Control SpA + +OUI:1C9179* + ID_OUI_FROM_DATABASE=Integrated System Technologies Ltd + +OUI:1C9492* + ID_OUI_FROM_DATABASE=RUAG Schweiz AG + +OUI:1C955D* + ID_OUI_FROM_DATABASE=I-LAX ELECTRONICS INC. + +OUI:1C959F* + ID_OUI_FROM_DATABASE=Veethree Electronics And Marine LLC + +OUI:1C973D* + ID_OUI_FROM_DATABASE=PRICOM Design + +OUI:1C994C* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:1CA770* + ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LT + +OUI:1CAA07* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:1CAB01* + ID_OUI_FROM_DATABASE=Innovolt + +OUI:1CABA7* + ID_OUI_FROM_DATABASE=Apple + +OUI:1CAF05* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1CAFF7* + ID_OUI_FROM_DATABASE=D-LINK INTERNATIONAL PTE LIMITED + +OUI:1CB094* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:1CB17F* + ID_OUI_FROM_DATABASE=NEC AccessTechnica, Ltd. + +OUI:1CB243* + ID_OUI_FROM_DATABASE=TDC A/S + +OUI:1CBA8C* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:1CBBA8* + ID_OUI_FROM_DATABASE=OJSC "Ufimskiy Zavod "Promsvyaz" + +OUI:1CBD0E* + ID_OUI_FROM_DATABASE=Amplified Engineering Pty Ltd + +OUI:1CBDB9* + ID_OUI_FROM_DATABASE=D-LINK INTERNATIONAL PTE LIMITED + +OUI:1CC11A* + ID_OUI_FROM_DATABASE=Wavetronix + +OUI:1CC1DE* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:1CC316* + ID_OUI_FROM_DATABASE=MileSight Technology Co., Ltd. + +OUI:1CC63C* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:1CD40C* + ID_OUI_FROM_DATABASE=Kriwan Industrie-Elektronik GmbH + +OUI:1CDF0F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:1CE165* + ID_OUI_FROM_DATABASE=Marshal Corporation + +OUI:1CE192* + ID_OUI_FROM_DATABASE=Qisda Corporation + +OUI:1CE2CC* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:1CE62B* + ID_OUI_FROM_DATABASE=Apple + +OUI:1CE6C7* + ID_OUI_FROM_DATABASE=Cisco + +OUI:1CEEE8* + ID_OUI_FROM_DATABASE=Ilshin Elecom + +OUI:1CF061* + ID_OUI_FROM_DATABASE=SCAPS GmbH + +OUI:1CF5E7* + ID_OUI_FROM_DATABASE=Turtle Industry Co., Ltd. + +OUI:1CFA68* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:1CFCBB* + ID_OUI_FROM_DATABASE=Realfiction ApS + +OUI:1CFEA7* + ID_OUI_FROM_DATABASE=IDentytech Solutins Ltd. + +OUI:20014F* + ID_OUI_FROM_DATABASE=Linea Research Ltd + +OUI:2002AF* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:200505* + ID_OUI_FROM_DATABASE=RADMAX COMMUNICATION PRIVATE LIMITED + +OUI:2005E8* + ID_OUI_FROM_DATABASE=OOO InProMedia + +OUI:2008ED* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:200A5E* + ID_OUI_FROM_DATABASE=Xiangshan Giant Eagle Technology Developing co.,LTD + +OUI:200BC7* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:200CC8* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:200E95* + ID_OUI_FROM_DATABASE=IEC – TC9 WG43 + +OUI:20107A* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:201257* + ID_OUI_FROM_DATABASE=Most Lucky Trading Ltd + +OUI:2013E0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:2016D8* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:20180E* + ID_OUI_FROM_DATABASE=Shenzhen Sunchip Technology Co., Ltd + +OUI:201A06* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:201D03* + ID_OUI_FROM_DATABASE=Elatec GmbH + +OUI:2021A5* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:202598* + ID_OUI_FROM_DATABASE=Teleview + +OUI:202BC1* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:202CB7* + ID_OUI_FROM_DATABASE=Kong Yue Electronics & Information Industry (Xinhui) Ltd. + +OUI:203706* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:2037BC* + ID_OUI_FROM_DATABASE=Kuipers Electronic Engineering BV + +OUI:203A07* + ID_OUI_FROM_DATABASE=Cisco + +OUI:204005* + ID_OUI_FROM_DATABASE=feno GmbH + +OUI:20415A* + ID_OUI_FROM_DATABASE=Smarteh d.o.o. + +OUI:20443A* + ID_OUI_FROM_DATABASE=Schneider Electric Asia Pacific Ltd + +OUI:2046A1* + ID_OUI_FROM_DATABASE=VECOW Co., Ltd + +OUI:2046F9* + ID_OUI_FROM_DATABASE=Advanced Network Devices (dba:AND) + +OUI:204AAA* + ID_OUI_FROM_DATABASE=Hanscan Spain S.A. + +OUI:204C6D* + ID_OUI_FROM_DATABASE=Hugo Brennenstuhl Gmbh & Co. KG. + +OUI:204E6B* + ID_OUI_FROM_DATABASE=Axxana(israel) ltd + +OUI:204E7F* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:205476* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:205721* + ID_OUI_FROM_DATABASE=Salix Technology CO., Ltd. + +OUI:2059A0* + ID_OUI_FROM_DATABASE=Paragon Technologies Inc. + +OUI:205B5E* + ID_OUI_FROM_DATABASE=Shenzhen Wonhe Technology Co., Ltd + +OUI:206432* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO.,LTD. + +OUI:2067B1* + ID_OUI_FROM_DATABASE=Pluto inc. + +OUI:20689D* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:206A8A* + ID_OUI_FROM_DATABASE=Wistron InfoComm Manufacturing(Kunshan)Co.,Ltd. + +OUI:206AFF* + ID_OUI_FROM_DATABASE=Atlas Elektronik UK Limited + +OUI:206FEC* + ID_OUI_FROM_DATABASE=Braemac CA LLC + +OUI:207355* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:2074CF* + ID_OUI_FROM_DATABASE=Shenzhen Voxtech Co.,Ltd + +OUI:207600* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:207C8F* + ID_OUI_FROM_DATABASE=Quanta Microsystems,Inc. + +OUI:207D74* + ID_OUI_FROM_DATABASE=Apple + +OUI:20858C* + ID_OUI_FROM_DATABASE=Assa + +OUI:2087AC* + ID_OUI_FROM_DATABASE=AES motomation + +OUI:208984* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD + +OUI:208986* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:20918A* + ID_OUI_FROM_DATABASE=PROFALUX + +OUI:2091D9* + ID_OUI_FROM_DATABASE=I'M SPA + +OUI:209BA5* + ID_OUI_FROM_DATABASE=JIAXING GLEAD Electronics Co.,Ltd + +OUI:20A2E7* + ID_OUI_FROM_DATABASE=Lee-Dickens Ltd + +OUI:20AA25* + ID_OUI_FROM_DATABASE=IP-NET LLC + +OUI:20AA4B* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:20B0F7* + ID_OUI_FROM_DATABASE=Enclustra GmbH + +OUI:20B399* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:20B5C6* + ID_OUI_FROM_DATABASE=Mimosa Networks + +OUI:20B7C0* + ID_OUI_FROM_DATABASE=Omicron electronics GmbH + +OUI:20BBC0* + ID_OUI_FROM_DATABASE=Cisco + +OUI:20BBC6* + ID_OUI_FROM_DATABASE=Jabil Circuit Hungary Ltd. + +OUI:20BFDB* + ID_OUI_FROM_DATABASE=DVL + +OUI:20C1AF* + ID_OUI_FROM_DATABASE=i Wit Digital Co., Limited + +OUI:20C60D* + ID_OUI_FROM_DATABASE=Shanghai annijie Information technology Co.,LTD + +OUI:20C6EB* + ID_OUI_FROM_DATABASE=Panasonic Corporation AVC Networks Company + +OUI:20C8B3* + ID_OUI_FROM_DATABASE=SHENZHEN BUL-TECH CO.,LTD. + +OUI:20C9D0* + ID_OUI_FROM_DATABASE=Apple + +OUI:20CD39* + ID_OUI_FROM_DATABASE=Texas Instruments, Inc + +OUI:20CEC4* + ID_OUI_FROM_DATABASE=Peraso Technologies + +OUI:20CF30* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:20D21F* + ID_OUI_FROM_DATABASE=Wincal Technology Corp. + +OUI:20D390* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:20D5AB* + ID_OUI_FROM_DATABASE=Korea Infocom Co.,Ltd. + +OUI:20D5BF* + ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd + +OUI:20D607* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:20D906* + ID_OUI_FROM_DATABASE=Iota, Inc. + +OUI:20DC93* + ID_OUI_FROM_DATABASE=Cheetah Hi-Tech, Inc. + +OUI:20DCE6* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:20DF3F* + ID_OUI_FROM_DATABASE=Nanjing SAC Power Grid Automation Co., Ltd. + +OUI:20E52A* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:20E564* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:20E791* + ID_OUI_FROM_DATABASE=Siemens Healthcare Diagnostics, Inc + +OUI:20EAC7* + ID_OUI_FROM_DATABASE=SHENZHEN RIOPINE ELECTRONICS CO., LTD + +OUI:20EEC6* + ID_OUI_FROM_DATABASE=Elefirst Science & Tech Co ., ltd + +OUI:20F002* + ID_OUI_FROM_DATABASE=MTData Developments Pty. Ltd. + +OUI:20F3A3* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:20F85E* + ID_OUI_FROM_DATABASE=Delta Electronics + +OUI:20FABB* + ID_OUI_FROM_DATABASE=Cambridge Executive Limited + +OUI:20FDF1* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD + +OUI:20FECD* + ID_OUI_FROM_DATABASE=System In Frontier Inc. + +OUI:20FEDB* + ID_OUI_FROM_DATABASE=M2M Solution S.A.S. + +OUI:2401C7* + ID_OUI_FROM_DATABASE=Cisco + +OUI:24050F* + ID_OUI_FROM_DATABASE=MTN Electronic Co. Ltd + +OUI:240917* + ID_OUI_FROM_DATABASE=Devlin Electronics Limited + +OUI:240A64* + ID_OUI_FROM_DATABASE=AzureWaveTechnologies,Inc + +OUI:240B2A* + ID_OUI_FROM_DATABASE=Viettel Group + +OUI:240BB1* + ID_OUI_FROM_DATABASE=KOSTAL Industrie Elektrik GmbH + +OUI:241064* + ID_OUI_FROM_DATABASE=Shenzhen Ecsino Tecnical Co. Ltd + +OUI:241125* + ID_OUI_FROM_DATABASE=Hutek Co., Ltd. + +OUI:241148* + ID_OUI_FROM_DATABASE=Entropix, LLC + +OUI:2411D0* + ID_OUI_FROM_DATABASE=Chongqing Ehs Science and Technology Development Co.,Ltd. + +OUI:241A8C* + ID_OUI_FROM_DATABASE=Squarehead Technology AS + +OUI:241B13* + ID_OUI_FROM_DATABASE=Shanghai Nutshell Electronic Co., Ltd. + +OUI:241F2C* + ID_OUI_FROM_DATABASE=Calsys, Inc. + +OUI:2421AB* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications + +OUI:242642* + ID_OUI_FROM_DATABASE=SHARP Corporation. + +OUI:242FFA* + ID_OUI_FROM_DATABASE=Toshiba Global Commerce Solutions + +OUI:24374C* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:2437EF* + ID_OUI_FROM_DATABASE=EMC Electronic Media Communication SA + +OUI:243C20* + ID_OUI_FROM_DATABASE=Dynamode Group + +OUI:244597* + ID_OUI_FROM_DATABASE=GEMUE Gebr. Mueller Apparatebau + +OUI:24470E* + ID_OUI_FROM_DATABASE=PentronicAB + +OUI:24497B* + ID_OUI_FROM_DATABASE=Innovative Converged Devices Inc + +OUI:245FDF* + ID_OUI_FROM_DATABASE=KYOCERA Corporation + +OUI:246278* + ID_OUI_FROM_DATABASE=sysmocom - systems for mobile communications GmbH + +OUI:2464EF* + ID_OUI_FROM_DATABASE=CYG SUNRI CO.,LTD. + +OUI:246511* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:24694A* + ID_OUI_FROM_DATABASE=Jasmine Systems Inc. + +OUI:2469A5* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:246AAB* + ID_OUI_FROM_DATABASE=IT-IS International + +OUI:24767D* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:247703* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:248000* + ID_OUI_FROM_DATABASE=Westcontrol AS + +OUI:2481AA* + ID_OUI_FROM_DATABASE=KSH International Co., Ltd. + +OUI:24828A* + ID_OUI_FROM_DATABASE=Prowave Technologies Ltd. + +OUI:2486F4* + ID_OUI_FROM_DATABASE=Ctek, Inc. + +OUI:248707* + ID_OUI_FROM_DATABASE=SEnergy Corporation + +OUI:2493CA* + ID_OUI_FROM_DATABASE=Voxtronic Technology Computer-Systeme GmbH + +OUI:249442* + ID_OUI_FROM_DATABASE=OPEN ROAD SOLUTIONS , INC. + +OUI:249504* + ID_OUI_FROM_DATABASE=SFR + +OUI:24A2E1* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:24A42C* + ID_OUI_FROM_DATABASE=KOUKAAM a.s. + +OUI:24A43C* + ID_OUI_FROM_DATABASE=Ubiquiti Networks, INC + +OUI:24A495* + ID_OUI_FROM_DATABASE=Thales Canada Inc. + +OUI:24A87D* + ID_OUI_FROM_DATABASE=Panasonic Automotive Systems Asia Pacific(Thailand)Co.,Ltd. + +OUI:24A937* + ID_OUI_FROM_DATABASE=PURE Storage + +OUI:24AB81* + ID_OUI_FROM_DATABASE=Apple + +OUI:24AF4A* + ID_OUI_FROM_DATABASE=Alcatel-Lucent-IPD + +OUI:24AF54* + ID_OUI_FROM_DATABASE=NEXGEN Mediatech Inc. + +OUI:24B657* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:24B6B8* + ID_OUI_FROM_DATABASE=FRIEM SPA + +OUI:24B6FD* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:24B88C* + ID_OUI_FROM_DATABASE=Crenus Co.,Ltd. + +OUI:24B8D2* + ID_OUI_FROM_DATABASE=Opzoon Technology Co.,Ltd. + +OUI:24BA30* + ID_OUI_FROM_DATABASE=Technical Consumer Products, Inc. + +OUI:24BBC1* + ID_OUI_FROM_DATABASE=Absolute Analysis + +OUI:24BC82* + ID_OUI_FROM_DATABASE=Dali Wireless, Inc. + +OUI:24BE05* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:24C0B3* + ID_OUI_FROM_DATABASE=RSF + +OUI:24C696* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:24C848* + ID_OUI_FROM_DATABASE=mywerk system GmbH + +OUI:24C86E* + ID_OUI_FROM_DATABASE=Chaney Instrument Co. + +OUI:24C9A1* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:24C9DE* + ID_OUI_FROM_DATABASE=Genoray + +OUI:24CBE7* + ID_OUI_FROM_DATABASE=MYK, Inc. + +OUI:24CF21* + ID_OUI_FROM_DATABASE=Shenzhen State Micro Technology Co., Ltd + +OUI:24D2CC* + ID_OUI_FROM_DATABASE=SmartDrive Systems Inc. + +OUI:24D921* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:24DAB6* + ID_OUI_FROM_DATABASE=Sistemas de Gestión Energética S.A. de C.V + +OUI:24DBAC* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:24DBAD* + ID_OUI_FROM_DATABASE=ShopperTrak RCT Corporation + +OUI:24DBED* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:24DEC6* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:24E271* + ID_OUI_FROM_DATABASE=Qingdao Hisense Communications Co.,Ltd + +OUI:24E6BA* + ID_OUI_FROM_DATABASE=JSC Zavod im. Kozitsky + +OUI:24E9B3* + ID_OUI_FROM_DATABASE=Cisco + +OUI:24EA40* + ID_OUI_FROM_DATABASE=Systeme Helmholz GmbH + +OUI:24EB65* + ID_OUI_FROM_DATABASE=SAET I.S. S.r.l. + +OUI:24EC99* + ID_OUI_FROM_DATABASE=Askey Computer Corp + +OUI:24ECD6* + ID_OUI_FROM_DATABASE=CSG Science & Technology Co.,Ltd.Hefei + +OUI:24EE3A* + ID_OUI_FROM_DATABASE=Chengdu Yingji Electronic Hi-tech Co Ltd + +OUI:24F0FF* + ID_OUI_FROM_DATABASE=GHT Co., Ltd. + +OUI:24F2DD* + ID_OUI_FROM_DATABASE=Radiant Zemax LLC + +OUI:24F5AA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:24FD52* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:2804E0* + ID_OUI_FROM_DATABASE=FERMAX ELECTRONICA S.A.U. + +OUI:28061E* + ID_OUI_FROM_DATABASE=NINGBO GLOBAL USEFUL ELECTRIC CO.,LTD + +OUI:28068D* + ID_OUI_FROM_DATABASE=ITL, LLC + +OUI:280B5C* + ID_OUI_FROM_DATABASE=Apple + +OUI:280CB8* + ID_OUI_FROM_DATABASE=Mikrosay Yazilim ve Elektronik A.S. + +OUI:280DFC* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:28107B* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:281471* + ID_OUI_FROM_DATABASE=Lantis co., LTD. + +OUI:28162E* + ID_OUI_FROM_DATABASE=2Wire + +OUI:2817CE* + ID_OUI_FROM_DATABASE=Omnisense Ltd + +OUI:281878* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:2818FD* + ID_OUI_FROM_DATABASE=Aditya Infotech Ltd. + +OUI:282246* + ID_OUI_FROM_DATABASE=Beijing Sinoix Communication Co., LTD + +OUI:2826A6* + ID_OUI_FROM_DATABASE=PBR electronics GmbH + +OUI:28285D* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:2829D9* + ID_OUI_FROM_DATABASE=GlobalBeiMing technology (Beijing)Co. Ltd + +OUI:282CB2* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:283152* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:283410* + ID_OUI_FROM_DATABASE=Enigma Diagnostics Limited + +OUI:283737* + ID_OUI_FROM_DATABASE=Apple + +OUI:2838CF* + ID_OUI_FROM_DATABASE=Gen2wave + +OUI:2839E7* + ID_OUI_FROM_DATABASE=Preceno Technology Pte.Ltd. + +OUI:283B96* + ID_OUI_FROM_DATABASE=Cool Control LTD + +OUI:283CE4* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:28401A* + ID_OUI_FROM_DATABASE=C8 MediSensors, Inc. + +OUI:284121* + ID_OUI_FROM_DATABASE=OptiSense Network, LLC + +OUI:284430* + ID_OUI_FROM_DATABASE=GenesisTechnical Systems (UK) Ltd + +OUI:2847AA* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:284846* + ID_OUI_FROM_DATABASE=GridCentric Inc. + +OUI:284C53* + ID_OUI_FROM_DATABASE=Intune Networks + +OUI:284D92* + ID_OUI_FROM_DATABASE=Luminator + +OUI:284FCE* + ID_OUI_FROM_DATABASE=Liaoning Wontel Science and Technology Development Co.,Ltd. + +OUI:285132* + ID_OUI_FROM_DATABASE=Shenzhen Prayfly Technology Co.,Ltd + +OUI:285767* + ID_OUI_FROM_DATABASE=Echostar Technologies Corp + +OUI:285FDB* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:286046* + ID_OUI_FROM_DATABASE=Lantech Communications Global, Inc. + +OUI:286094* + ID_OUI_FROM_DATABASE=CAPELEC + +OUI:286336* + ID_OUI_FROM_DATABASE=Siemens AG - Industrial Automation - EWA + +OUI:28656B* + ID_OUI_FROM_DATABASE=Keystone Microtech Corporation + +OUI:286AB8* + ID_OUI_FROM_DATABASE=Apple + +OUI:286ABA* + ID_OUI_FROM_DATABASE=Apple + +OUI:286D97* + ID_OUI_FROM_DATABASE=SAMJIN Co., Ltd. + +OUI:286ED4* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:287184* + ID_OUI_FROM_DATABASE=Spire Payments + +OUI:2872C5* + ID_OUI_FROM_DATABASE=Smartmatic Corp + +OUI:2872F0* + ID_OUI_FROM_DATABASE=ATHENA + +OUI:287994* + ID_OUI_FROM_DATABASE=Realplay Digital Technology(Shenzhen) Co.,Ltd + +OUI:28852D* + ID_OUI_FROM_DATABASE=Touch Networks + +OUI:288915* + ID_OUI_FROM_DATABASE=CashGuard Sverige AB + +OUI:288A1C* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:2891D0* + ID_OUI_FROM_DATABASE=Stage Tec Entwicklungsgesellschaft für professionelle Audiotechnik mbH + +OUI:28924A* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:2893FE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:28940F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:2894AF* + ID_OUI_FROM_DATABASE=Samhwa Telecom + +OUI:28987B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:289A4B* + ID_OUI_FROM_DATABASE=SteelSeries ApS + +OUI:289AFA* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:289EDF* + ID_OUI_FROM_DATABASE=Danfoss Turbocor Compressors, Inc + +OUI:28A186* + ID_OUI_FROM_DATABASE=enblink + +OUI:28A192* + ID_OUI_FROM_DATABASE=GERP Solution + +OUI:28A1EB* + ID_OUI_FROM_DATABASE=ETEK TECHNOLOGY (SHENZHEN) CO.,LTD + +OUI:28A241* + ID_OUI_FROM_DATABASE=exlar corp + +OUI:28A574* + ID_OUI_FROM_DATABASE=Miller Electric Mfg. Co. + +OUI:28AF0A* + ID_OUI_FROM_DATABASE=Sirius XM Radio Inc + +OUI:28B0CC* + ID_OUI_FROM_DATABASE=Xenya d.o.o. + +OUI:28B2BD* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:28B3AB* + ID_OUI_FROM_DATABASE=Genmark Automation + +OUI:28BA18* + ID_OUI_FROM_DATABASE=NextNav, LLC + +OUI:28BAB5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:28BB59* + ID_OUI_FROM_DATABASE=RNET Technologies, Inc. + +OUI:28BE9B* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:28C0DA* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:28C671* + ID_OUI_FROM_DATABASE=Yota Devices OY + +OUI:28C68E* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:28C718* + ID_OUI_FROM_DATABASE=Altierre + +OUI:28C825* + ID_OUI_FROM_DATABASE=DellKing Industrial Co., Ltd + +OUI:28C914* + ID_OUI_FROM_DATABASE=Taimag Corporation + +OUI:28CBEB* + ID_OUI_FROM_DATABASE=One + +OUI:28CC01* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:28CCFF* + ID_OUI_FROM_DATABASE=Corporacion Empresarial Altra SL + +OUI:28CD1C* + ID_OUI_FROM_DATABASE=Espotel Oy + +OUI:28CD4C* + ID_OUI_FROM_DATABASE=Individual Computers GmbH + +OUI:28CD9C* + ID_OUI_FROM_DATABASE=Shenzhen Dynamax Software Development Co.,Ltd. + +OUI:28CFDA* + ID_OUI_FROM_DATABASE=Apple + +OUI:28CFE9* + ID_OUI_FROM_DATABASE=Apple + +OUI:28D1AF* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:28D244* + ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology Co., Ltd. + +OUI:28D576* + ID_OUI_FROM_DATABASE=Premier Wireless, Inc. + +OUI:28D93E* + ID_OUI_FROM_DATABASE=Telecor Inc. + +OUI:28D997* + ID_OUI_FROM_DATABASE=Yuduan Mobile Co., Ltd. + +OUI:28DB81* + ID_OUI_FROM_DATABASE=Shanghai Guao Electronic Technology Co., Ltd + +OUI:28DEF6* + ID_OUI_FROM_DATABASE=bioMerieux Inc. + +OUI:28E02C* + ID_OUI_FROM_DATABASE=Apple + +OUI:28E14C* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:28E297* + ID_OUI_FROM_DATABASE=Shanghai InfoTM Microelectronics Co.,Ltd. + +OUI:28E347* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:28E608* + ID_OUI_FROM_DATABASE=Tokheim + +OUI:28E794* + ID_OUI_FROM_DATABASE=Microtime Computer Inc. + +OUI:28E7CF* + ID_OUI_FROM_DATABASE=Apple + +OUI:28ED58* + ID_OUI_FROM_DATABASE=JAG Jakob AG + +OUI:28EE2C* + ID_OUI_FROM_DATABASE=Frontline Test Equipment + +OUI:28F358* + ID_OUI_FROM_DATABASE=2C - Trifonov & Co + +OUI:28F532* + ID_OUI_FROM_DATABASE=ADD-Engineering BV + +OUI:28F606* + ID_OUI_FROM_DATABASE=Syes srl + +OUI:28FBD3* + ID_OUI_FROM_DATABASE=Ragentek Technology Group + +OUI:28FC51* + ID_OUI_FROM_DATABASE=The Electric Controller and Manufacturing Co., LLC + +OUI:2C002C* + ID_OUI_FROM_DATABASE=UNOWHY + +OUI:2C0033* + ID_OUI_FROM_DATABASE=EControls, LLC + +OUI:2C00F7* + ID_OUI_FROM_DATABASE=XOS + +OUI:2C0623* + ID_OUI_FROM_DATABASE=Win Leader Inc. + +OUI:2C073C* + ID_OUI_FROM_DATABASE=DEVLINE LIMITED + +OUI:2C10C1* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:2C18AE* + ID_OUI_FROM_DATABASE=Trend Electronics Co., Ltd. + +OUI:2C1984* + ID_OUI_FROM_DATABASE=IDN Telecom, Inc. + +OUI:2C1EEA* + ID_OUI_FROM_DATABASE=AERODEV + +OUI:2C2172* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:2C245F* + ID_OUI_FROM_DATABASE=Babolat VS + +OUI:2C26C5* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:2C27D7* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:2C282D* + ID_OUI_FROM_DATABASE=BBK COMMUNICATIAO TECHNOLOGY CO.,LTD. + +OUI:2C2D48* + ID_OUI_FROM_DATABASE=bct electronic GesmbH + +OUI:2C3068* + ID_OUI_FROM_DATABASE=Pantech Co.,Ltd + +OUI:2C3427* + ID_OUI_FROM_DATABASE=ERCO & GENER + +OUI:2C3557* + ID_OUI_FROM_DATABASE=ELLIY Power CO..Ltd + +OUI:2C36A0* + ID_OUI_FROM_DATABASE=Capisco Limited + +OUI:2C36F8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:2C3731* + ID_OUI_FROM_DATABASE=ShenZhen Yifang Digital Technology Co.,LTD + +OUI:2C3996* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:2C3A28* + ID_OUI_FROM_DATABASE=Fagor Electrónica + +OUI:2C3BFD* + ID_OUI_FROM_DATABASE=Netstor Technology Co., Ltd. + +OUI:2C3ECF* + ID_OUI_FROM_DATABASE=Cisco + +OUI:2C3F38* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:2C3F3E* + ID_OUI_FROM_DATABASE=Alge-Timing GmbH + +OUI:2C4138* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:2C4401* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:2C441B* + ID_OUI_FROM_DATABASE=Spectrum Medical Limited + +OUI:2C44FD* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:2C534A* + ID_OUI_FROM_DATABASE=Shenzhen Winyao Electronic Limited + +OUI:2C542D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:2C553C* + ID_OUI_FROM_DATABASE=Gainspeed, Inc. + +OUI:2C59E5* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:2C5A05* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:2C5AA3* + ID_OUI_FROM_DATABASE=PROMATE ELECTRONIC CO.LTD + +OUI:2C5D93* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:2C5FF3* + ID_OUI_FROM_DATABASE=Pertronic Industries + +OUI:2C625A* + ID_OUI_FROM_DATABASE=Finest Security Systems Co., Ltd + +OUI:2C6289* + ID_OUI_FROM_DATABASE=Regenersis (Glenrothes) Ltd + +OUI:2C67FB* + ID_OUI_FROM_DATABASE=ShenZhen Zhengjili Electronics Co., LTD + +OUI:2C69BA* + ID_OUI_FROM_DATABASE=RF Controls, LLC + +OUI:2C6BF5* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:2C7155* + ID_OUI_FROM_DATABASE=HiveMotion + +OUI:2C72C3* + ID_OUI_FROM_DATABASE=Soundmatters + +OUI:2C750F* + ID_OUI_FROM_DATABASE=Shanghai Dongzhou-Lawton Communication Technology Co. Ltd. + +OUI:2C768A* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:2C7B5A* + ID_OUI_FROM_DATABASE=Milper Ltd + +OUI:2C7B84* + ID_OUI_FROM_DATABASE=OOO Petr Telegin + +OUI:2C7ECF* + ID_OUI_FROM_DATABASE=Onzo Ltd + +OUI:2C8065* + ID_OUI_FROM_DATABASE=HARTING Inc. of North America + +OUI:2C8158* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd + +OUI:2C8BF2* + ID_OUI_FROM_DATABASE=Hitachi Metals America Ltd + +OUI:2C9127* + ID_OUI_FROM_DATABASE=Eintechno Corporation + +OUI:2C922C* + ID_OUI_FROM_DATABASE=Kishu Giken Kogyou Company Ltd,. + +OUI:2C9464* + ID_OUI_FROM_DATABASE=Cincoze Co., Ltd. + +OUI:2C957F* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:2C9717* + ID_OUI_FROM_DATABASE=I.C.Y. B.V. + +OUI:2C9E5F* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:2C9EFC* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:2CA157* + ID_OUI_FROM_DATABASE=acromate, Inc. + +OUI:2CA780* + ID_OUI_FROM_DATABASE=True Technologies Inc. + +OUI:2CA835* + ID_OUI_FROM_DATABASE=RIM + +OUI:2CAB25* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:2CB05D* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:2CB0DF* + ID_OUI_FROM_DATABASE=Soliton Technologies Pvt Ltd + +OUI:2CB43A* + ID_OUI_FROM_DATABASE=Apple + +OUI:2CB693* + ID_OUI_FROM_DATABASE=Radware + +OUI:2CB69D* + ID_OUI_FROM_DATABASE=RED Digital Cinema + +OUI:2CBE97* + ID_OUI_FROM_DATABASE=Ingenieurbuero Bickele und Buehler GmbH + +OUI:2CC260* + ID_OUI_FROM_DATABASE=Ravello Systems + +OUI:2CCC15* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:2CCD27* + ID_OUI_FROM_DATABASE=Precor Inc + +OUI:2CCD43* + ID_OUI_FROM_DATABASE=Summit Technology Group + +OUI:2CCD69* + ID_OUI_FROM_DATABASE=Aqavi.com + +OUI:2CD05A* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:2CD1DA* + ID_OUI_FROM_DATABASE=Sanjole, Inc. + +OUI:2CD2E7* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:2CD444* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:2CDD0C* + ID_OUI_FROM_DATABASE=Discovergy GmbH + +OUI:2CE2A8* + ID_OUI_FROM_DATABASE=DeviceDesign + +OUI:2CE412* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:2CE6CC* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:2CE871* + ID_OUI_FROM_DATABASE=Alert Metalguard ApS + +OUI:2CEDEB* + ID_OUI_FROM_DATABASE=Alpheus Digital Company Limited + +OUI:2CEE26* + ID_OUI_FROM_DATABASE=Petroleum Geo-Services + +OUI:2CF203* + ID_OUI_FROM_DATABASE=EMKO ELEKTRONIK SAN VE TIC AS + +OUI:2CF4C5* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:30055C* + ID_OUI_FROM_DATABASE=Brother industries, LTD. + +OUI:300B9C* + ID_OUI_FROM_DATABASE=Delta Mobile Systems, Inc. + +OUI:300ED5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:3010E4* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:30142D* + ID_OUI_FROM_DATABASE=Piciorgros GmbH + +OUI:30144A* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:301518* + ID_OUI_FROM_DATABASE=Ubiquitous Communication Co. ltd. + +OUI:30168D* + ID_OUI_FROM_DATABASE=ProLon + +OUI:3017C8* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:3018CF* + ID_OUI_FROM_DATABASE=DEOS control systems GmbH + +OUI:301966* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:301A28* + ID_OUI_FROM_DATABASE=Mako Networks Ltd + +OUI:30215B* + ID_OUI_FROM_DATABASE=Shenzhen Ostar Display Electronic Co.,Ltd + +OUI:302DE8* + ID_OUI_FROM_DATABASE=JDA, LLC (JDA Systems) + +OUI:303294* + ID_OUI_FROM_DATABASE=W-IE-NE-R Plein & Baus GmbH + +OUI:3032D4* + ID_OUI_FROM_DATABASE=Hanilstm Co., Ltd. + +OUI:3037A6* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:303855* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:303926* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:303955* + ID_OUI_FROM_DATABASE=Shenzhen Jinhengjia Electronic Co., Ltd. + +OUI:3039F2* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:303A64* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:303D08* + ID_OUI_FROM_DATABASE=GLINTT TES S.A. + +OUI:303EAD* + ID_OUI_FROM_DATABASE=Sonavox Canada Inc + +OUI:304174* + ID_OUI_FROM_DATABASE=ALTEC LANSING LLC + +OUI:304449* + ID_OUI_FROM_DATABASE=PLATH GmbH + +OUI:30469A* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:30493B* + ID_OUI_FROM_DATABASE=Nanjing Z-Com Wireless Co.,Ltd + +OUI:304C7E* + ID_OUI_FROM_DATABASE=Panasonic Electric Works Automation Controls Techno Co.,Ltd. + +OUI:304EC3* + ID_OUI_FROM_DATABASE=Tianjin Techua Technology Co., Ltd. + +OUI:3051F8* + ID_OUI_FROM_DATABASE=BYK-Gardner GmbH + +OUI:30525A* + ID_OUI_FROM_DATABASE=NST Co., LTD + +OUI:3055ED* + ID_OUI_FROM_DATABASE=Trex Network LLC + +OUI:3057AC* + ID_OUI_FROM_DATABASE=IRLAB LTD. + +OUI:305D38* + ID_OUI_FROM_DATABASE=Beissbarth + +OUI:306023* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:306112* + ID_OUI_FROM_DATABASE=PAV GmbH + +OUI:306118* + ID_OUI_FROM_DATABASE=Paradom Inc. + +OUI:3065EC* + ID_OUI_FROM_DATABASE=Wistron (ChongQing) + +OUI:30688C* + ID_OUI_FROM_DATABASE=Reach Technology Inc. + +OUI:30694B* + ID_OUI_FROM_DATABASE=RIM + +OUI:306CBE* + ID_OUI_FROM_DATABASE=Skymotion Technology (HK) Limited + +OUI:306E5C* + ID_OUI_FROM_DATABASE=Validus Technologies + +OUI:3071B2* + ID_OUI_FROM_DATABASE=Hangzhou Prevail Optoelectronic Equipment Co.,LTD. + +OUI:30766F* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:30786B* + ID_OUI_FROM_DATABASE=TIANJIN Golden Pentagon Electronics Co., Ltd. + +OUI:3078C2* + ID_OUI_FROM_DATABASE=Innowireless, Co. Ltd. + +OUI:307C30* + ID_OUI_FROM_DATABASE=RIM + +OUI:307ECB* + ID_OUI_FROM_DATABASE=SFR + +OUI:3085A9* + ID_OUI_FROM_DATABASE=Asustek Computer Inc + +OUI:308730* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:308999* + ID_OUI_FROM_DATABASE=Guangdong East Power Co., + +OUI:308CFB* + ID_OUI_FROM_DATABASE=Dropcam + +OUI:3090AB* + ID_OUI_FROM_DATABASE=Apple + +OUI:3092F6* + ID_OUI_FROM_DATABASE=SHANGHAI SUNMON COMMUNICATION TECHNOGY CO.,LTD + +OUI:309BAD* + ID_OUI_FROM_DATABASE=BBK Electronics Corp., Ltd., + +OUI:30A8DB* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:30AABD* + ID_OUI_FROM_DATABASE=Shanghai Reallytek Information Technology Co.,Ltd + +OUI:30AE7B* + ID_OUI_FROM_DATABASE=Deqing Dusun Electron CO., LTD + +OUI:30AEF6* + ID_OUI_FROM_DATABASE=Radio Mobile Access + +OUI:30B216* + ID_OUI_FROM_DATABASE=Hytec Geraetebau GmbH + +OUI:30B3A2* + ID_OUI_FROM_DATABASE=Shenzhen Heguang Measurement & Control Technology Co.,Ltd + +OUI:30B5C2* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:30C750* + ID_OUI_FROM_DATABASE=MIC Technology Group + +OUI:30C82A* + ID_OUI_FROM_DATABASE=Wi-Next s.r.l. + +OUI:30CDA7* + ID_OUI_FROM_DATABASE=Samsung Electronics ITS, Printer division + +OUI:30D357* + ID_OUI_FROM_DATABASE=Logosol, Inc. + +OUI:30D46A* + ID_OUI_FROM_DATABASE=Autosales Incorporated + +OUI:30D6C9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:30DE86* + ID_OUI_FROM_DATABASE=Cedac Software S.r.l. + +OUI:30E48E* + ID_OUI_FROM_DATABASE=Vodafone UK + +OUI:30E4DB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:30EB25* + ID_OUI_FROM_DATABASE=INTEK DIGITAL + +OUI:30EFD1* + ID_OUI_FROM_DATABASE=Alstom Strongwish (Shenzhen) Co., Ltd. + +OUI:30F31D* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:30F33A* + ID_OUI_FROM_DATABASE=+plugg srl + +OUI:30F42F* + ID_OUI_FROM_DATABASE=ESP + +OUI:30F70D* + ID_OUI_FROM_DATABASE=Cisco Systems + +OUI:30F7C5* + ID_OUI_FROM_DATABASE=Apple + +OUI:30F9ED* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:30FD11* + ID_OUI_FROM_DATABASE=MACROTECH (USA) INC. + +OUI:3407FB* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:340804* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:3413A8* + ID_OUI_FROM_DATABASE=Mediplan Limited + +OUI:3413E8* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:34159E* + ID_OUI_FROM_DATABASE=Apple + +OUI:3417EB* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:341A4C* + ID_OUI_FROM_DATABASE=SHENZHEN WEIBU ELECTRONICS CO.,LTD. + +OUI:341B22* + ID_OUI_FROM_DATABASE=Grandbeing Technology Co., Ltd + +OUI:342109* + ID_OUI_FROM_DATABASE=Jensen Scandinavia AS + +OUI:342387* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:3423BA* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:34255D* + ID_OUI_FROM_DATABASE=Shenzhen Loadcom Technology Co.,Ltd + +OUI:3429EA* + ID_OUI_FROM_DATABASE=MCD ELECTRONICS SP. Z O.O. + +OUI:342F6E* + ID_OUI_FROM_DATABASE=Anywire corporation + +OUI:343111* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:3440B5* + ID_OUI_FROM_DATABASE=IBM + +OUI:34466F* + ID_OUI_FROM_DATABASE=HiTEM Engineering + +OUI:344B3D* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:344B50* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:344F3F* + ID_OUI_FROM_DATABASE=IO-Power Technology Co., Ltd. + +OUI:344F5C* + ID_OUI_FROM_DATABASE=R&M AG + +OUI:344F69* + ID_OUI_FROM_DATABASE=EKINOPS SAS + +OUI:3451C9* + ID_OUI_FROM_DATABASE=Apple + +OUI:345B11* + ID_OUI_FROM_DATABASE=EVI HEAT AB + +OUI:345C40* + ID_OUI_FROM_DATABASE=Cargt Holdings LLC + +OUI:346178* + ID_OUI_FROM_DATABASE=The Boeing Company + +OUI:34684A* + ID_OUI_FROM_DATABASE=Teraworks Co., Ltd. + +OUI:346BD3* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:346E8A* + ID_OUI_FROM_DATABASE=Ecosense + +OUI:346F92* + ID_OUI_FROM_DATABASE=White Rodgers Division + +OUI:3475C7* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:3476C5* + ID_OUI_FROM_DATABASE=I-O DATA DEVICE, INC. + +OUI:347877* + ID_OUI_FROM_DATABASE=O-NET Communications(Shenzhen) Limited + +OUI:347E39* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:348137* + ID_OUI_FROM_DATABASE=UNICARD SA + +OUI:3482DE* + ID_OUI_FROM_DATABASE=Kayo Technology, Inc. + +OUI:348302* + ID_OUI_FROM_DATABASE=iFORCOM Co., Ltd + +OUI:348446* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:34862A* + ID_OUI_FROM_DATABASE=Heinz Lackmann GmbH & Co KG + +OUI:34885D* + ID_OUI_FROM_DATABASE=Logitech Far East + +OUI:348AAE* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:3495DB* + ID_OUI_FROM_DATABASE=Logitec Corporation + +OUI:3497FB* + ID_OUI_FROM_DATABASE=ADVANCED RF TECHNOLOGIES INC + +OUI:34996F* + ID_OUI_FROM_DATABASE=VPI Engineering + +OUI:3499D7* + ID_OUI_FROM_DATABASE=Universal Flow Monitors, Inc. + +OUI:349A0D* + ID_OUI_FROM_DATABASE=ZBD Displays Ltd + +OUI:349D90* + ID_OUI_FROM_DATABASE=Heinzmann GmbH & CO. KG + +OUI:34A183* + ID_OUI_FROM_DATABASE=AWare, Inc + +OUI:34A3BF* + ID_OUI_FROM_DATABASE=Terewave. Inc. + +OUI:34A55D* + ID_OUI_FROM_DATABASE=TECHNOSOFT INTERNATIONAL SRL + +OUI:34A5E1* + ID_OUI_FROM_DATABASE=Sensorist ApS + +OUI:34A68C* + ID_OUI_FROM_DATABASE=Shine Profit Development Limited + +OUI:34A709* + ID_OUI_FROM_DATABASE=Trevil srl + +OUI:34A7BA* + ID_OUI_FROM_DATABASE=Fischer International Systems Corporation + +OUI:34A843* + ID_OUI_FROM_DATABASE=KYOCERA Display Corporation + +OUI:34A84E* + ID_OUI_FROM_DATABASE=Cisco + +OUI:34AA8B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:34AA99* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:34AAEE* + ID_OUI_FROM_DATABASE=Mikrovisatos Servisas UAB + +OUI:34ADE4* + ID_OUI_FROM_DATABASE=Shanghai Chint Power Systems Co., Ltd. + +OUI:34AF2C* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:34B1F7* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:34B571* + ID_OUI_FROM_DATABASE=PLDS + +OUI:34BA51* + ID_OUI_FROM_DATABASE=Se-Kure Controls, Inc. + +OUI:34BA9A* + ID_OUI_FROM_DATABASE=Asiatelco Technologies Co. + +OUI:34BB1F* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:34BCA6* + ID_OUI_FROM_DATABASE=Beijing Ding Qing Technology, Ltd. + +OUI:34BDC8* + ID_OUI_FROM_DATABASE=Cisco Systems + +OUI:34BDF9* + ID_OUI_FROM_DATABASE=Shanghai WDK Industrial Co.,Ltd. + +OUI:34BDFA* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:34BE00* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:34BF90* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:34C059* + ID_OUI_FROM_DATABASE=Apple + +OUI:34C3AC* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:34C69A* + ID_OUI_FROM_DATABASE=Enecsys Ltd + +OUI:34C731* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:34C803* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:34C99D* + ID_OUI_FROM_DATABASE=EIDOLON COMMUNICATIONS TECHNOLOGY CO. LTD. + +OUI:34CD6D* + ID_OUI_FROM_DATABASE=CommSky Technologies + +OUI:34CDBE* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:34CE94* + ID_OUI_FROM_DATABASE=Parsec (Pty) Ltd + +OUI:34D09B* + ID_OUI_FROM_DATABASE=MobilMAX Technology Inc. + +OUI:34D2C4* + ID_OUI_FROM_DATABASE=RENA GmbH Print Systeme + +OUI:34D7B4* + ID_OUI_FROM_DATABASE=Tributary Systems, Inc. + +OUI:34DBFD* + ID_OUI_FROM_DATABASE=Cisco + +OUI:34DE1A* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:34DE34* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:34DF2A* + ID_OUI_FROM_DATABASE=Fujikon Industrial Co.,Limited + +OUI:34E0CF* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:34E0D7* + ID_OUI_FROM_DATABASE=DONGGUAN QISHENG ELECTRONICS INDUSTRIAL CO., LTD + +OUI:34E2FD* + ID_OUI_FROM_DATABASE=Apple + +OUI:34EF44* + ID_OUI_FROM_DATABASE=2Wire + +OUI:34EF8B* + ID_OUI_FROM_DATABASE=NTT Communications Corporation + +OUI:34F39B* + ID_OUI_FROM_DATABASE=WizLAN Ltd. + +OUI:34F62D* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:34F968* + ID_OUI_FROM_DATABASE=ATEK Products, LLC + +OUI:34FA40* + ID_OUI_FROM_DATABASE=Guangzhou Robustel Technologies Co., Limited + +OUI:34FC6F* + ID_OUI_FROM_DATABASE=ALCEA + +OUI:380197* + ID_OUI_FROM_DATABASE=Toshiba Samsung Storage Technolgoy Korea Corporation + +OUI:3806B4* + ID_OUI_FROM_DATABASE=A.D.C. GmbH + +OUI:380A0A* + ID_OUI_FROM_DATABASE=Sky-City Communication and Electronics Limited Company + +OUI:380A94* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:380B40* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:380DD4* + ID_OUI_FROM_DATABASE=Primax Electronics LTD. + +OUI:380F4A* + ID_OUI_FROM_DATABASE=Apple + +OUI:380FE4* + ID_OUI_FROM_DATABASE=Dedicated Network Partners Oy + +OUI:3816D1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:381766* + ID_OUI_FROM_DATABASE=PROMZAKAZ LTD. + +OUI:38192F* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:381C4A* + ID_OUI_FROM_DATABASE=SIMCom Wireless Solutions Co.,Ltd. + +OUI:38229D* + ID_OUI_FROM_DATABASE=Pirelli Tyre S.p.A. + +OUI:3822D6* + ID_OUI_FROM_DATABASE=H3C Technologies Co., Limited + +OUI:3826CD* + ID_OUI_FROM_DATABASE=ANDTEK + +OUI:3828EA* + ID_OUI_FROM_DATABASE=Fujian Netcom Technology Co., LTD + +OUI:3831AC* + ID_OUI_FROM_DATABASE=WEG + +OUI:383F10* + ID_OUI_FROM_DATABASE=DBL Technology Ltd. + +OUI:384233* + ID_OUI_FROM_DATABASE=Wildeboer Bauteile GmbH + +OUI:3842A6* + ID_OUI_FROM_DATABASE=Ingenieurbuero Stahlkopf + +OUI:384369* + ID_OUI_FROM_DATABASE=Patrol Products Consortium LLC + +OUI:38458C* + ID_OUI_FROM_DATABASE=MyCloud Technology corporation + +OUI:384608* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:38484C* + ID_OUI_FROM_DATABASE=Apple + +OUI:384FF0* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:38521A* + ID_OUI_FROM_DATABASE=Alcatel-Lucent 7705 + +OUI:38580C* + ID_OUI_FROM_DATABASE=Panaccess Systems GmbH + +OUI:3859F8* + ID_OUI_FROM_DATABASE=MindMade sp. z o.o. + +OUI:3859F9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:385AA8* + ID_OUI_FROM_DATABASE=Beijing Zhongdun Security Technology Development Co. + +OUI:385FC3* + ID_OUI_FROM_DATABASE=Yu Jeong System, Co.Ltd + +OUI:386077* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:3863F6* + ID_OUI_FROM_DATABASE=3NOD MULTIMEDIA(SHENZHEN)CO.,LTD + +OUI:386645* + ID_OUI_FROM_DATABASE=OOSIC Technology CO.,Ltd + +OUI:386793* + ID_OUI_FROM_DATABASE=Asia Optical Co., Inc. + +OUI:386BBB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:386C9B* + ID_OUI_FROM_DATABASE=Ivy Biomedical + +OUI:386E21* + ID_OUI_FROM_DATABASE=Wasion Group Ltd. + +OUI:3872C0* + ID_OUI_FROM_DATABASE=COMTREND + +OUI:387B47* + ID_OUI_FROM_DATABASE=AKELA, Inc. + +OUI:388345* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:3889DC* + ID_OUI_FROM_DATABASE=Opticon Sensors Europe B.V. + +OUI:388AB7* + ID_OUI_FROM_DATABASE=ITC Networks + +OUI:388EE7* + ID_OUI_FROM_DATABASE=Fanhattan LLC + +OUI:3891FB* + ID_OUI_FROM_DATABASE=Xenox Holding BV + +OUI:389592* + ID_OUI_FROM_DATABASE=Beijing Tendyron Corporation + +OUI:389F83* + ID_OUI_FROM_DATABASE=OTN Systems N.V. + +OUI:38A53C* + ID_OUI_FROM_DATABASE=Veenstra Instruments + +OUI:38A5B6* + ID_OUI_FROM_DATABASE=SHENZHEN MEGMEET ELECTRICAL CO.,LTD + +OUI:38A851* + ID_OUI_FROM_DATABASE=Moog, Ing + +OUI:38A86B* + ID_OUI_FROM_DATABASE=Orga BV + +OUI:38A95F* + ID_OUI_FROM_DATABASE=Actifio Inc + +OUI:38AA3C* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS + +OUI:38B12D* + ID_OUI_FROM_DATABASE=Sonotronic Nagel GmbH + +OUI:38B5BD* + ID_OUI_FROM_DATABASE=E.G.O. Elektro-Ger + +OUI:38B74D* + ID_OUI_FROM_DATABASE=Fijowave Limited + +OUI:38BB23* + ID_OUI_FROM_DATABASE=OzVision America LLC + +OUI:38BC1A* + ID_OUI_FROM_DATABASE=Meizu technology co.,ltd + +OUI:38BF2F* + ID_OUI_FROM_DATABASE=Espec Corp. + +OUI:38BF33* + ID_OUI_FROM_DATABASE=NEC CASIO Mobile Communications + +OUI:38C096* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:38C7BA* + ID_OUI_FROM_DATABASE=CS Services Co.,Ltd. + +OUI:38C85C* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:38C9A9* + ID_OUI_FROM_DATABASE=SMART High Reliability Solutions, Inc. + +OUI:38CA97* + ID_OUI_FROM_DATABASE=Contour Design LLC + +OUI:38D135* + ID_OUI_FROM_DATABASE=EasyIO Corporation Sdn. Bhd. + +OUI:38DBBB* + ID_OUI_FROM_DATABASE=Sunbow Telecom Co., Ltd. + +OUI:38DE60* + ID_OUI_FROM_DATABASE=Mohlenhoff GmbH + +OUI:38E08E* + ID_OUI_FROM_DATABASE=Mitsubishi Electric Corporation + +OUI:38E595* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:38E7D8* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:38E8DF* + ID_OUI_FROM_DATABASE=b gmbh medien + datenbanken + +OUI:38E98C* + ID_OUI_FROM_DATABASE=Reco S.p.A. + +OUI:38EAA7* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:38EC11* + ID_OUI_FROM_DATABASE=Novatek Microelectronics Corp. + +OUI:38ECE4* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:38EE9D* + ID_OUI_FROM_DATABASE=Anedo Ltd. + +OUI:38F098* + ID_OUI_FROM_DATABASE=Vapor Stone Rail Systems + +OUI:38F597* + ID_OUI_FROM_DATABASE=home2net GmbH + +OUI:38F708* + ID_OUI_FROM_DATABASE=National Resource Management, Inc. + +OUI:38F8B7* + ID_OUI_FROM_DATABASE=V2COM PARTICIPACOES S.A. + +OUI:38FEC5* + ID_OUI_FROM_DATABASE=Ellips B.V. + +OUI:3C02B1* + ID_OUI_FROM_DATABASE=Creation Technologies LP + +OUI:3C04BF* + ID_OUI_FROM_DATABASE=PRAVIS SYSTEMS Co.Ltd., + +OUI:3C05AB* + ID_OUI_FROM_DATABASE=Product Creation Studio + +OUI:3C0754* + ID_OUI_FROM_DATABASE=Apple + +OUI:3C0771* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:3C081E* + ID_OUI_FROM_DATABASE=Beijing Yupont Electric Power Technology Co.,Ltd + +OUI:3C08F6* + ID_OUI_FROM_DATABASE=Cisco + +OUI:3C096D* + ID_OUI_FROM_DATABASE=Powerhouse Dynamics + +OUI:3C0C48* + ID_OUI_FROM_DATABASE=Servergy, Inc. + +OUI:3C0E23* + ID_OUI_FROM_DATABASE=Cisco + +OUI:3C0FC1* + ID_OUI_FROM_DATABASE=KBC Networks + +OUI:3C1040* + ID_OUI_FROM_DATABASE=daesung network + +OUI:3C106F* + ID_OUI_FROM_DATABASE=ALBAHITH TECHNOLOGIES + +OUI:3C15C2* + ID_OUI_FROM_DATABASE=Apple + +OUI:3C15EA* + ID_OUI_FROM_DATABASE=TESCOM CO., LTD. + +OUI:3C18A0* + ID_OUI_FROM_DATABASE=Luxshare Precision Industry Co.,Ltd. + +OUI:3C1915* + ID_OUI_FROM_DATABASE=GFI Chrono Time + +OUI:3C197D* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:3C1A57* + ID_OUI_FROM_DATABASE=Cardiopulmonary Corp + +OUI:3C1A79* + ID_OUI_FROM_DATABASE=Huayuan Technology CO.,LTD + +OUI:3C1CBE* + ID_OUI_FROM_DATABASE=JADAK LLC + +OUI:3C25D7* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:3C26D5* + ID_OUI_FROM_DATABASE=Sotera Wireless + +OUI:3C2763* + ID_OUI_FROM_DATABASE=SLE quality engineering GmbH & Co. KG + +OUI:3C2DB7* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:3C2F3A* + ID_OUI_FROM_DATABASE=SFORZATO Corp. + +OUI:3C300C* + ID_OUI_FROM_DATABASE=Dewar Electronics Pty Ltd + +OUI:3C363D* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:3C36E4* + ID_OUI_FROM_DATABASE=Arris Group, Inc. + +OUI:3C3888* + ID_OUI_FROM_DATABASE=ConnectQuest, llc + +OUI:3C39C3* + ID_OUI_FROM_DATABASE=JW Electronics Co., Ltd. + +OUI:3C3A73* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:3C404F* + ID_OUI_FROM_DATABASE=Guangdong Pisen Electronics Co. Ltd. + +OUI:3C438E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:3C4A92* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:3C4C69* + ID_OUI_FROM_DATABASE=Infinity System S.L. + +OUI:3C4E47* + ID_OUI_FROM_DATABASE=Etronic A/S + +OUI:3C57BD* + ID_OUI_FROM_DATABASE=Kessler Crane Inc. + +OUI:3C57D5* + ID_OUI_FROM_DATABASE=FiveCo + +OUI:3C5A37* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:3C5F01* + ID_OUI_FROM_DATABASE=Synerchip Co., Ltd. + +OUI:3C6104* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C6200* + ID_OUI_FROM_DATABASE=Samsung electronics CO., LTD + +OUI:3C6278* + ID_OUI_FROM_DATABASE=SHENZHEN JETNET TECHNOLOGY CO.,LTD. + +OUI:3C672C* + ID_OUI_FROM_DATABASE=Sciovid Inc. + +OUI:3C6A7D* + ID_OUI_FROM_DATABASE=Niigata Power Systems Co., Ltd. + +OUI:3C6E63* + ID_OUI_FROM_DATABASE=Mitron OY + +OUI:3C6F45* + ID_OUI_FROM_DATABASE=Fiberpro Inc. + +OUI:3C6FF7* + ID_OUI_FROM_DATABASE=EnTek Systems, Inc. + +OUI:3C7059* + ID_OUI_FROM_DATABASE=MakerBot Industries + +OUI:3C7437* + ID_OUI_FROM_DATABASE=RIM + +OUI:3C754A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:3C77E6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:3C7DB1* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:3C81D8* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:3C83B5* + ID_OUI_FROM_DATABASE=Advance Vision Electronics Co. Ltd. + +OUI:3C86A8* + ID_OUI_FROM_DATABASE=Sangshin elecom .co,, LTD + +OUI:3C89A6* + ID_OUI_FROM_DATABASE=KAPELSE + +OUI:3C8AB0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C8AE5* + ID_OUI_FROM_DATABASE=Tensun Information Technology(Hangzhou) Co.,LTD + +OUI:3C8BFE* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:3C9157* + ID_OUI_FROM_DATABASE=Hangzhou Yulong Conmunication Co.,Ltd + +OUI:3C9174* + ID_OUI_FROM_DATABASE=ALONG COMMUNICATION TECHNOLOGY + +OUI:3C94D5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C970E* + ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. + +OUI:3C977E* + ID_OUI_FROM_DATABASE=IPS Technology Limited + +OUI:3C98BF* + ID_OUI_FROM_DATABASE=Quest Controls, Inc. + +OUI:3C99F7* + ID_OUI_FROM_DATABASE=Lansentechnology AB + +OUI:3C9F81* + ID_OUI_FROM_DATABASE=Shenzhen CATIC Bit Communications Technology Co.,Ltd + +OUI:3CA315* + ID_OUI_FROM_DATABASE=Bless Information & Communications Co., Ltd + +OUI:3CA72B* + ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD + +OUI:3CA9F4* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:3CB15B* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:3CB17F* + ID_OUI_FROM_DATABASE=Wattwatchers Pty Ld + +OUI:3CB9A6* + ID_OUI_FROM_DATABASE=Belden Deutschland GmbH + +OUI:3CBDD8* + ID_OUI_FROM_DATABASE=LG ELECTRONICS INC + +OUI:3CC0C6* + ID_OUI_FROM_DATABASE=d&b audiotechnik GmbH + +OUI:3CC12C* + ID_OUI_FROM_DATABASE=AES Corporation + +OUI:3CC1F6* + ID_OUI_FROM_DATABASE=Melange Systems Pvt. Ltd. + +OUI:3CC243* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:3CC99E* + ID_OUI_FROM_DATABASE=Huiyang Technology Co., Ltd + +OUI:3CCA87* + ID_OUI_FROM_DATABASE=Iders Incorporated + +OUI:3CCD93* + ID_OUI_FROM_DATABASE=LG ELECTRONICS INC + +OUI:3CCE73* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:3CD0F8* + ID_OUI_FROM_DATABASE=Apple + +OUI:3CD16E* + ID_OUI_FROM_DATABASE=Telepower Communication Co., Ltd + +OUI:3CD4D6* + ID_OUI_FROM_DATABASE=WirelessWERX, Inc + +OUI:3CD7DA* + ID_OUI_FROM_DATABASE=SK Mtek microelectronics(shenzhen)limited + +OUI:3CD92B* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:3CDF1E* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:3CDFBD* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:3CE072* + ID_OUI_FROM_DATABASE=Apple + +OUI:3CE5A6* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Ltd. + +OUI:3CE5B4* + ID_OUI_FROM_DATABASE=KIDASEN INDUSTRIA E COMERCIO DE ANTENAS LTDA + +OUI:3CE624* + ID_OUI_FROM_DATABASE=LG Display + +OUI:3CEA4F* + ID_OUI_FROM_DATABASE=2Wire + +OUI:3CEAFB* + ID_OUI_FROM_DATABASE=NSE AG + +OUI:3CF392* + ID_OUI_FROM_DATABASE=Virtualtek. Co. Ltd + +OUI:3CF52C* + ID_OUI_FROM_DATABASE=DSPECIALISTS GmbH + +OUI:3CF72A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:3CF748* + ID_OUI_FROM_DATABASE=Shenzhen Linsn Technology Development Co.,Ltd + +OUI:3CFB96* + ID_OUI_FROM_DATABASE=Emcraft Systems LLC + +OUI:400107* + ID_OUI_FROM_DATABASE=Arista Corp + +OUI:4001C6* + ID_OUI_FROM_DATABASE=3COM EUROPE LTD + +OUI:40040C* + ID_OUI_FROM_DATABASE=A&T + +OUI:4007C0* + ID_OUI_FROM_DATABASE=Railtec Systems GmbH + +OUI:400E67* + ID_OUI_FROM_DATABASE=Tremol Ltd. + +OUI:400E85* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:4012E4* + ID_OUI_FROM_DATABASE=Compass-EOS + +OUI:4013D9* + ID_OUI_FROM_DATABASE=Global ES + +OUI:401597* + ID_OUI_FROM_DATABASE=Protect America, Inc. + +OUI:40169F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:4016FA* + ID_OUI_FROM_DATABASE=EKM Metering + +OUI:4018B1* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc. + +OUI:4018D7* + ID_OUI_FROM_DATABASE=Wyle Telemetry and Data Systems + +OUI:401D59* + ID_OUI_FROM_DATABASE=Biometric Associates, LP + +OUI:4022ED* + ID_OUI_FROM_DATABASE=Digital Projection Ltd + +OUI:4025C2* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:40270B* + ID_OUI_FROM_DATABASE=Mobileeco Co., Ltd + +OUI:402BA1* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:402CF4* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:403004* + ID_OUI_FROM_DATABASE=Apple + +OUI:403067* + ID_OUI_FROM_DATABASE=Conlog (Pty) Ltd + +OUI:40336C* + ID_OUI_FROM_DATABASE=Godrej & Boyce Mfg. co. ltd + +OUI:4037AD* + ID_OUI_FROM_DATABASE=Macro Image Technology, Inc. + +OUI:403CFC* + ID_OUI_FROM_DATABASE=Apple + +OUI:404022* + ID_OUI_FROM_DATABASE=ZIV + +OUI:40406B* + ID_OUI_FROM_DATABASE=Icomera + +OUI:404A03* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:404A18* + ID_OUI_FROM_DATABASE=Addrek Smart Solutions + +OUI:404D8E* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:4050E0* + ID_OUI_FROM_DATABASE=Milton Security Group LLC + +OUI:40516C* + ID_OUI_FROM_DATABASE=Grandex International Corporation + +OUI:40520D* + ID_OUI_FROM_DATABASE=Pico Technology + +OUI:405539* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:40560C* + ID_OUI_FROM_DATABASE=In Home Displays Ltd + +OUI:405A9B* + ID_OUI_FROM_DATABASE=ANOVO + +OUI:405FBE* + ID_OUI_FROM_DATABASE=RIM + +OUI:405FC2* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:40605A* + ID_OUI_FROM_DATABASE=Hawkeye Tech Co. Ltd + +OUI:406186* + ID_OUI_FROM_DATABASE=MICRO-STAR INT'L CO.,LTD + +OUI:40618E* + ID_OUI_FROM_DATABASE=Stella-Green Co + +OUI:40667A* + ID_OUI_FROM_DATABASE=mediola - connected living AG + +OUI:406826* + ID_OUI_FROM_DATABASE=Thales UK Limited + +OUI:406AAB* + ID_OUI_FROM_DATABASE=RIM + +OUI:406C8F* + ID_OUI_FROM_DATABASE=Apple + +OUI:406F2A* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:407009* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:40704A* + ID_OUI_FROM_DATABASE=Power Idea Technology Limited + +OUI:407074* + ID_OUI_FROM_DATABASE=Life Technology (China) Co., Ltd + +OUI:407496* + ID_OUI_FROM_DATABASE=aFUN TECHNOLOGY INC. + +OUI:407875* + ID_OUI_FROM_DATABASE=IMBEL - Industria de Material Belico do Brasil + +OUI:407A80* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:407B1B* + ID_OUI_FROM_DATABASE=Mettle Networks Inc. + +OUI:4083DE* + ID_OUI_FROM_DATABASE=Motorola + +OUI:408493* + ID_OUI_FROM_DATABASE=Clavister AB + +OUI:4088E0* + ID_OUI_FROM_DATABASE=Beijing Ereneben Information Technology Limited Shenzhen Branch + +OUI:408A9A* + ID_OUI_FROM_DATABASE=TITENG CO., Ltd. + +OUI:408B07* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:408BF6* + ID_OUI_FROM_DATABASE=Shenzhen TCL New Technology Co; Ltd. + +OUI:409558* + ID_OUI_FROM_DATABASE=Aisino Corporation + +OUI:4097D1* + ID_OUI_FROM_DATABASE=BK Electronics cc + +OUI:40984C* + ID_OUI_FROM_DATABASE=Casacom Solutions AG + +OUI:40984E* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:40987B* + ID_OUI_FROM_DATABASE=Aisino Corporation + +OUI:409FC7* + ID_OUI_FROM_DATABASE=BAEKCHUN I&C Co., Ltd. + +OUI:40A6A4* + ID_OUI_FROM_DATABASE=PassivSystems Ltd + +OUI:40A6D9* + ID_OUI_FROM_DATABASE=Apple + +OUI:40A8F0* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:40AC8D* + ID_OUI_FROM_DATABASE=Data Management, Inc. + +OUI:40B0FA* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:40B2C8* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:40B395* + ID_OUI_FROM_DATABASE=Apple + +OUI:40B3FC* + ID_OUI_FROM_DATABASE=Logital Co. Limited + +OUI:40B4F0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:40B6B1* + ID_OUI_FROM_DATABASE=SUNGSAM CO,.Ltd + +OUI:40B7F3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:40BA61* + ID_OUI_FROM_DATABASE=Arima Communications Corp. + +OUI:40BC73* + ID_OUI_FROM_DATABASE=Cronoplast S.L. + +OUI:40BC8B* + ID_OUI_FROM_DATABASE=itelio GmbH + +OUI:40BD9E* + ID_OUI_FROM_DATABASE=Physio-Control, Inc + +OUI:40BF17* + ID_OUI_FROM_DATABASE=Digistar Telecom. SA + +OUI:40C245* + ID_OUI_FROM_DATABASE=Shenzhen Hexicom Technology Co., Ltd. + +OUI:40C4D6* + ID_OUI_FROM_DATABASE=ChongQing Camyu Technology Development Co.,Ltd. + +OUI:40C7C9* + ID_OUI_FROM_DATABASE=Naviit Inc. + +OUI:40CBA8* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:40CD3A* + ID_OUI_FROM_DATABASE=Z3 Technology + +OUI:40D32D* + ID_OUI_FROM_DATABASE=Apple + +OUI:40D40E* + ID_OUI_FROM_DATABASE=Biodata Ltd + +OUI:40D559* + ID_OUI_FROM_DATABASE=MICRO S.E.R.I. + +OUI:40E730* + ID_OUI_FROM_DATABASE=DEY Storage Systems, Inc. + +OUI:40E793* + ID_OUI_FROM_DATABASE=Shenzhen Siviton Technology Co.,Ltd + +OUI:40ECF8* + ID_OUI_FROM_DATABASE=Siemens AG + +OUI:40EF4C* + ID_OUI_FROM_DATABASE=Fihonest communication co.,Ltd + +OUI:40F02F* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:40F14C* + ID_OUI_FROM_DATABASE=ISE Europe SPRL + +OUI:40F2E9* + ID_OUI_FROM_DATABASE=IBM + +OUI:40F308* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:40F407* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:40F4EC* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:40F52E* + ID_OUI_FROM_DATABASE=Leica Microsystems (Schweiz) AG + +OUI:40FC89* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:4403A7* + ID_OUI_FROM_DATABASE=Cisco + +OUI:440CFD* + ID_OUI_FROM_DATABASE=NetMan Co., Ltd. + +OUI:4411C2* + ID_OUI_FROM_DATABASE=Telegartner Karl Gartner GmbH + +OUI:441319* + ID_OUI_FROM_DATABASE=WKK TECHNOLOGY LTD. + +OUI:44184F* + ID_OUI_FROM_DATABASE=Fitview + +OUI:4419B6* + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. + +OUI:441EA1* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:4423AA* + ID_OUI_FROM_DATABASE=Farmage Co., Ltd. + +OUI:4425BB* + ID_OUI_FROM_DATABASE=Bamboo Entertainment Corporation + +OUI:442938* + ID_OUI_FROM_DATABASE=NietZsche enterprise Co.Ltd. + +OUI:442A60* + ID_OUI_FROM_DATABASE=Apple + +OUI:442AFF* + ID_OUI_FROM_DATABASE=E3 Technology, Inc. + +OUI:442B03* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:443192* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:44322A* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:4432C8* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:44334C* + ID_OUI_FROM_DATABASE=Shenzhen Bilian electronic CO.,LTD + +OUI:44348F* + ID_OUI_FROM_DATABASE=MXT INDUSTRIAL LTDA + +OUI:443719* + ID_OUI_FROM_DATABASE=2 Save Energy Ltd + +OUI:44376F* + ID_OUI_FROM_DATABASE=Young Electric Sign Co + +OUI:4437E6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:443839* + ID_OUI_FROM_DATABASE=Cumulus Networks, inc + +OUI:4439C4* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co.,Ltd + +OUI:443C9C* + ID_OUI_FROM_DATABASE=Pintsch Tiefenbach GmbH + +OUI:443D21* + ID_OUI_FROM_DATABASE=Nuvolt + +OUI:443EB2* + ID_OUI_FROM_DATABASE=DEOTRON Co., LTD. + +OUI:444891* + ID_OUI_FROM_DATABASE=HDMI Licensing, LLC + +OUI:444A65* + ID_OUI_FROM_DATABASE=Silverflare Ltd. + +OUI:444C0C* + ID_OUI_FROM_DATABASE=Apple + +OUI:444E1A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:444F5E* + ID_OUI_FROM_DATABASE=Pan Studios Co.,Ltd. + +OUI:4451DB* + ID_OUI_FROM_DATABASE=Raytheon BBN Technologies + +OUI:4454C0* + ID_OUI_FROM_DATABASE=Thompson Aerospace + +OUI:44568D* + ID_OUI_FROM_DATABASE=PNC Technologies Co., Ltd. + +OUI:4456B7* + ID_OUI_FROM_DATABASE=Spawn Labs, Inc + +OUI:445829* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:44599F* + ID_OUI_FROM_DATABASE=Criticare Systems, Inc + +OUI:445EF3* + ID_OUI_FROM_DATABASE=Tonalite Holding B.V. + +OUI:445F7A* + ID_OUI_FROM_DATABASE=Shihlin Electric & Engineering Corp. + +OUI:446132* + ID_OUI_FROM_DATABASE=ecobee inc + +OUI:44619C* + ID_OUI_FROM_DATABASE=FONsystem co. ltd. + +OUI:446755* + ID_OUI_FROM_DATABASE=Orbit Irrigation + +OUI:4468AB* + ID_OUI_FROM_DATABASE=JUIN COMPANY, LIMITED + +OUI:446C24* + ID_OUI_FROM_DATABASE=Reallin Electronic Co.,Ltd + +OUI:446D57* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:44700B* + ID_OUI_FROM_DATABASE=IFFU + +OUI:447098* + ID_OUI_FROM_DATABASE=MING HONG TECHNOLOGY (SHEN ZHEN) LIMITED + +OUI:447BC4* + ID_OUI_FROM_DATABASE=DualShine Technology(SZ)Co.,Ltd + +OUI:447C7F* + ID_OUI_FROM_DATABASE=Innolight Technology Corporation + +OUI:447DA5* + ID_OUI_FROM_DATABASE=VTION INFORMATION TECHNOLOGY (FUJIAN) CO.,LTD + +OUI:447E76* + ID_OUI_FROM_DATABASE=Trek Technology (S) Pte Ltd + +OUI:447E95* + ID_OUI_FROM_DATABASE=Alpha and Omega, Inc + +OUI:448312* + ID_OUI_FROM_DATABASE=Star-Net + +OUI:448500* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:4487FC* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. + +OUI:448A5B* + ID_OUI_FROM_DATABASE=Micro-Star INT'L CO., LTD. + +OUI:448C52* + ID_OUI_FROM_DATABASE=KTIS CO., Ltd + +OUI:448E12* + ID_OUI_FROM_DATABASE=DT Research, Inc. + +OUI:448E81* + ID_OUI_FROM_DATABASE=VIG + +OUI:4491DB* + ID_OUI_FROM_DATABASE=Shanghai Huaqin Telecom Technology Co.,Ltd + +OUI:4494FC* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:4495FA* + ID_OUI_FROM_DATABASE=Qingdao Santong Digital Technology Co.Ltd + +OUI:449B78* + ID_OUI_FROM_DATABASE=The Now Factory + +OUI:449CB5* + ID_OUI_FROM_DATABASE=Alcomp, Inc + +OUI:44A42D* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:44A689* + ID_OUI_FROM_DATABASE=PROMAX ELECTRONICA SA + +OUI:44A7CF* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:44A8C2* + ID_OUI_FROM_DATABASE=SEWOO TECH CO., LTD + +OUI:44AA27* + ID_OUI_FROM_DATABASE=udworks Co., Ltd. + +OUI:44AAE8* + ID_OUI_FROM_DATABASE=Nanotec Electronic GmbH & Co. KG + +OUI:44ADD9* + ID_OUI_FROM_DATABASE=Cisco + +OUI:44B382* + ID_OUI_FROM_DATABASE=Kuang-chi Institute of Advanced Technology + +OUI:44C15C* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:44C233* + ID_OUI_FROM_DATABASE=Guangzhou Comet Technology Development Co.Ltd + +OUI:44C306* + ID_OUI_FROM_DATABASE=SIFROM Inc. + +OUI:44C39B* + ID_OUI_FROM_DATABASE=OOO RUBEZH NPO + +OUI:44C4A9* + ID_OUI_FROM_DATABASE=Opticom Communication, LLC + +OUI:44C56F* + ID_OUI_FROM_DATABASE=NGN Easy Satfinder (Tianjin) Electronic Co., Ltd + +OUI:44C9A2* + ID_OUI_FROM_DATABASE=Greenwald Industries + +OUI:44D15E* + ID_OUI_FROM_DATABASE=Shanghai Kingto Information Technology Ltd + +OUI:44D2CA* + ID_OUI_FROM_DATABASE=Anvia TV Oy + +OUI:44D3CA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:44D63D* + ID_OUI_FROM_DATABASE=Talari Networks + +OUI:44D832* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:44D884* + ID_OUI_FROM_DATABASE=Apple + +OUI:44DC91* + ID_OUI_FROM_DATABASE=PLANEX COMMUNICATIONS INC. + +OUI:44DCCB* + ID_OUI_FROM_DATABASE=SEMINDIA SYSTEMS PVT LTD + +OUI:44E08E* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:44E49A* + ID_OUI_FROM_DATABASE=OMNITRONICS PTY LTD + +OUI:44E4D9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:44E8A5* + ID_OUI_FROM_DATABASE=Myreka Technologies Sdn. Bhd. + +OUI:44ED57* + ID_OUI_FROM_DATABASE=Longicorn, inc. + +OUI:44EE30* + ID_OUI_FROM_DATABASE=Budelmann Elektronik GmbH + +OUI:44F459* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:44F849* + ID_OUI_FROM_DATABASE=Union Pacific Railroad + +OUI:44FB42* + ID_OUI_FROM_DATABASE=Apple + +OUI:48022A* + ID_OUI_FROM_DATABASE=B-Link Electronic Limited + +OUI:480362* + ID_OUI_FROM_DATABASE=DESAY ELECTRONICS(HUIZHOU)CO.,LTD + +OUI:481249* + ID_OUI_FROM_DATABASE=Luxcom Technologies Inc. + +OUI:4813F3* + ID_OUI_FROM_DATABASE=BBK Electronics Corp., Ltd. + +OUI:48174C* + ID_OUI_FROM_DATABASE=MicroPower technologies + +OUI:481842* + ID_OUI_FROM_DATABASE=Shanghai Winaas Co. Equipment Co. Ltd. + +OUI:481BD2* + ID_OUI_FROM_DATABASE=Intron Scientific co., ltd. + +OUI:48282F* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:482CEA* + ID_OUI_FROM_DATABASE=Motorola Inc Business Light Radios + +OUI:4833DD* + ID_OUI_FROM_DATABASE=ZENNIO AVANCE Y TECNOLOGIA, S.L. + +OUI:48343D* + ID_OUI_FROM_DATABASE=IEP GmbH + +OUI:483D32* + ID_OUI_FROM_DATABASE=Syscor Controls & Automation + +OUI:484487* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:4844F7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:4846F1* + ID_OUI_FROM_DATABASE=Uros Oy + +OUI:4846FB* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:485261* + ID_OUI_FROM_DATABASE=SOREEL + +OUI:485A3F* + ID_OUI_FROM_DATABASE=WISOL + +OUI:485AB6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:485B39* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:485D60* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:4860BC* + ID_OUI_FROM_DATABASE=Apple + +OUI:4861A3* + ID_OUI_FROM_DATABASE=Concern "Axion" JSC + +OUI:486B91* + ID_OUI_FROM_DATABASE=Fleetwood Group Inc. + +OUI:486E73* + ID_OUI_FROM_DATABASE=Pica8, Inc. + +OUI:486FD2* + ID_OUI_FROM_DATABASE=StorSimple Inc + +OUI:487119* + ID_OUI_FROM_DATABASE=SGB GROUP LTD. + +OUI:48746E* + ID_OUI_FROM_DATABASE=Apple + +OUI:488E42* + ID_OUI_FROM_DATABASE=DIGALOG GmbH + +OUI:489153* + ID_OUI_FROM_DATABASE=Weinmann Geräte für Medizin GmbH + Co. KG + +OUI:4891F6* + ID_OUI_FROM_DATABASE=Shenzhen Reach software technology CO.,LTD + +OUI:489BE2* + ID_OUI_FROM_DATABASE=SCI Innovations Ltd + +OUI:489D24* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:48A22D* + ID_OUI_FROM_DATABASE=Shenzhen Huaxuchang Telecom Technology Co.,Ltd + +OUI:48A2B7* + ID_OUI_FROM_DATABASE=Kodofon JSC + +OUI:48A6D2* + ID_OUI_FROM_DATABASE=GJsun Optical Science and Tech Co.,Ltd. + +OUI:48AA5D* + ID_OUI_FROM_DATABASE=Store Electronic Systems + +OUI:48B253* + ID_OUI_FROM_DATABASE=Marketaxess Corporation + +OUI:48B5A7* + ID_OUI_FROM_DATABASE=Glory Horse Industries Ltd. + +OUI:48B8DE* + ID_OUI_FROM_DATABASE=HOMEWINS TECHNOLOGY CO.,LTD. + +OUI:48B977* + ID_OUI_FROM_DATABASE=PulseOn Oy + +OUI:48B9C2* + ID_OUI_FROM_DATABASE=Teletics Inc. + +OUI:48BE2D* + ID_OUI_FROM_DATABASE=Symanitron + +OUI:48C1AC* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:48C862* + ID_OUI_FROM_DATABASE=Simo Wireless,Inc. + +OUI:48C8B6* + ID_OUI_FROM_DATABASE=SysTec GmbH + +OUI:48CB6E* + ID_OUI_FROM_DATABASE=Cello Electronics (UK) Ltd + +OUI:48D0CF* + ID_OUI_FROM_DATABASE=Universal Electronics, Inc. + +OUI:48D224* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:48D54C* + ID_OUI_FROM_DATABASE=Jeda Networks + +OUI:48D7FF* + ID_OUI_FROM_DATABASE=BLANKOM Antennentechnik GmbH + +OUI:48D8FE* + ID_OUI_FROM_DATABASE=ClarIDy Solutions, Inc. + +OUI:48DCFB* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:48DF1C* + ID_OUI_FROM_DATABASE=Wuhan NEC Fibre Optic Communications industry Co. Ltd + +OUI:48E1AF* + ID_OUI_FROM_DATABASE=Vity + +OUI:48EA63* + ID_OUI_FROM_DATABASE=Zhejiang Uniview Technologies Co., Ltd. + +OUI:48EB30* + ID_OUI_FROM_DATABASE=ETERNA TECHNOLOGY, INC. + +OUI:48ED80* + ID_OUI_FROM_DATABASE=daesung eltec + +OUI:48EE07* + ID_OUI_FROM_DATABASE=Silver Palm Technologies LLC + +OUI:48EE86* + ID_OUI_FROM_DATABASE=UTStarcom (China) Co.,Ltd + +OUI:48F230* + ID_OUI_FROM_DATABASE=Ubizcore Co.,LTD + +OUI:48F47D* + ID_OUI_FROM_DATABASE=TechVision Holding Internation Limited + +OUI:48F7F1* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:48F8B3* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:48F8E1* + ID_OUI_FROM_DATABASE=Alcatel Lucent WT + +OUI:48F925* + ID_OUI_FROM_DATABASE=Maestronic + +OUI:48FCB8* + ID_OUI_FROM_DATABASE=Woodstream Corporation + +OUI:48FEEA* + ID_OUI_FROM_DATABASE=HOMA B.V. + +OUI:4C0082* + ID_OUI_FROM_DATABASE=Cisco + +OUI:4C022E* + ID_OUI_FROM_DATABASE=CMR KOREA CO., LTD + +OUI:4C0289* + ID_OUI_FROM_DATABASE=LEX COMPUTECH CO., LTD + +OUI:4C068A* + ID_OUI_FROM_DATABASE=Basler Electric Company + +OUI:4C07C9* + ID_OUI_FROM_DATABASE=COMPUTER OFFICE Co.,Ltd. + +OUI:4C09B4* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:4C0B3A* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:4C0DEE* + ID_OUI_FROM_DATABASE=JABIL CIRCUIT (SHANGHAI) LTD. + +OUI:4C0F6E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:4C0FC7* + ID_OUI_FROM_DATABASE=Earda Electronics Co.,Ltd + +OUI:4C1480* + ID_OUI_FROM_DATABASE=NOREGON SYSTEMS, INC + +OUI:4C14A3* + ID_OUI_FROM_DATABASE=TCL Technoly Electronics (Huizhou) Co., Ltd. + +OUI:4C17EB* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:4C1A3A* + ID_OUI_FROM_DATABASE=PRIMA Research And Production Enterprise Ltd. + +OUI:4C1A95* + ID_OUI_FROM_DATABASE=Novakon Co., Ltd. + +OUI:4C1FCC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:4C21D0* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:4C2258* + ID_OUI_FROM_DATABASE=cozybit, Inc. + +OUI:4C2578* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:4C2C80* + ID_OUI_FROM_DATABASE=Beijing Skyway Technologies Co.,Ltd + +OUI:4C2F9D* + ID_OUI_FROM_DATABASE=ICM Controls + +OUI:4C3089* + ID_OUI_FROM_DATABASE=Thales Transportation Systems GmbH + +OUI:4C322D* + ID_OUI_FROM_DATABASE=TELEDATA NETWORKS + +OUI:4C32D9* + ID_OUI_FROM_DATABASE=M Rutty Holdings Pty. Ltd. + +OUI:4C3910* + ID_OUI_FROM_DATABASE=Newtek Electronics co., Ltd. + +OUI:4C3B74* + ID_OUI_FROM_DATABASE=VOGTEC(H.K.) Co., Ltd + +OUI:4C3C16* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:4C4B68* + ID_OUI_FROM_DATABASE=Mobile Device, Inc. + +OUI:4C4E35* + ID_OUI_FROM_DATABASE=Cisco + +OUI:4C5427* + ID_OUI_FROM_DATABASE=Linepro Sp. z o.o. + +OUI:4C5499* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:4C5585* + ID_OUI_FROM_DATABASE=Hamilton Systems + +OUI:4C55B8* + ID_OUI_FROM_DATABASE=Turkcell Teknoloji + +OUI:4C55CC* + ID_OUI_FROM_DATABASE=ACKme Networks Pty Ltd + +OUI:4C5DCD* + ID_OUI_FROM_DATABASE=Oy Finnish Electric Vehicle Technologies Ltd + +OUI:4C5E0C* + ID_OUI_FROM_DATABASE=Routerboard.com + +OUI:4C5FD2* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:4C60D5* + ID_OUI_FROM_DATABASE=airPointe of New Hampshire + +OUI:4C60DE* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:4C6255* + ID_OUI_FROM_DATABASE=SANMINA-SCI SYSTEM DE MEXICO S.A. DE C.V. + +OUI:4C63EB* + ID_OUI_FROM_DATABASE=Application Solutions (Electronics and Vision) Ltd + +OUI:4C64D9* + ID_OUI_FROM_DATABASE=Guangdong Leawin Group Co., Ltd + +OUI:4C72B9* + ID_OUI_FROM_DATABASE=Pegatron Corporation + +OUI:4C7367* + ID_OUI_FROM_DATABASE=Genius Bytes Software Solutions GmbH + +OUI:4C73A5* + ID_OUI_FROM_DATABASE=KOVE + +OUI:4C774F* + ID_OUI_FROM_DATABASE=Embedded Wireless Labs + +OUI:4C7897* + ID_OUI_FROM_DATABASE=Arrowhead Alarm Products Ltd + +OUI:4C79BA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:4C7F62* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:4C804F* + ID_OUI_FROM_DATABASE=Armstrong Monitoring Corp + +OUI:4C8093* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:4C82CF* + ID_OUI_FROM_DATABASE=Echostar Technologies + +OUI:4C8B30* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:4C8B55* + ID_OUI_FROM_DATABASE=Grupo Digicon + +OUI:4C8BEF* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:4C8D79* + ID_OUI_FROM_DATABASE=Apple + +OUI:4C8FA5* + ID_OUI_FROM_DATABASE=Jastec + +OUI:4C9614* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:4C98EF* + ID_OUI_FROM_DATABASE=Zeo + +OUI:4C9E80* + ID_OUI_FROM_DATABASE=KYOKKO ELECTRIC Co., Ltd. + +OUI:4C9EE4* + ID_OUI_FROM_DATABASE=Hanyang Navicom Co.,Ltd. + +OUI:4CA56D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:4CA74B* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:4CAA16* + ID_OUI_FROM_DATABASE=AzureWave Technologies (Shanghai) Inc. + +OUI:4CAB33* + ID_OUI_FROM_DATABASE=KST technology + +OUI:4CAC0A* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:4CB16C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:4CB199* + ID_OUI_FROM_DATABASE=Apple + +OUI:4CB4EA* + ID_OUI_FROM_DATABASE=HRD (S) PTE., LTD. + +OUI:4CB81C* + ID_OUI_FROM_DATABASE=SAM Electronics GmbH + +OUI:4CB9C8* + ID_OUI_FROM_DATABASE=CONET CO., LTD. + +OUI:4CBAA3* + ID_OUI_FROM_DATABASE=Bison Electronics Inc. + +OUI:4CBCA5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:4CC452* + ID_OUI_FROM_DATABASE=Shang Hai Tyd. Electon Technology Ltd. + +OUI:4CC602* + ID_OUI_FROM_DATABASE=Radios, Inc. + +OUI:4CC94F* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:4CCA53* + ID_OUI_FROM_DATABASE=Skyera, Inc. + +OUI:4CCBF5* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:4CCC34* + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. + +OUI:4CD637* + ID_OUI_FROM_DATABASE=Qsono Electronics Co., Ltd + +OUI:4CD7B6* + ID_OUI_FROM_DATABASE=Helmer Scientific + +OUI:4CD9C4* + ID_OUI_FROM_DATABASE=Magneti Marelli Automotive Electronics (Guangzhou) Co. Ltd + +OUI:4CDF3D* + ID_OUI_FROM_DATABASE=TEAM ENGINEERS ADVANCE TECHNOLOGIES INDIA PVT LTD + +OUI:4CE1BB* + ID_OUI_FROM_DATABASE=Zhuhai HiFocus Technology Co., Ltd. + +OUI:4CE676* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:4CEB42* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:4CEDDE* + ID_OUI_FROM_DATABASE=Askey Computer Corp + +OUI:4CF02E* + ID_OUI_FROM_DATABASE=Vifa Denmark A/S + +OUI:4CF45B* + ID_OUI_FROM_DATABASE=Blue Clover Devices + +OUI:4CF737* + ID_OUI_FROM_DATABASE=SamJi Electronics Co., Ltd + +OUI:50008C* + ID_OUI_FROM_DATABASE=Hong Kong Telecommunications (HKT) Limited + +OUI:5001BB* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:50053D* + ID_OUI_FROM_DATABASE=CyWee Group Ltd + +OUI:500604* + ID_OUI_FROM_DATABASE=Cisco + +OUI:500B32* + ID_OUI_FROM_DATABASE=Foxda Technology Industrial(ShenZhen)Co.,LTD + +OUI:500E6D* + ID_OUI_FROM_DATABASE=TrafficCast International + +OUI:5011EB* + ID_OUI_FROM_DATABASE=SilverNet Ltd + +OUI:5017FF* + ID_OUI_FROM_DATABASE=Cisco + +OUI:501AC5* + ID_OUI_FROM_DATABASE=Microsoft + +OUI:501CBF* + ID_OUI_FROM_DATABASE=Cisco + +OUI:50206B* + ID_OUI_FROM_DATABASE=Emerson Climate Technologies Transportation Solutions + +OUI:502267* + ID_OUI_FROM_DATABASE=PixeLINK + +OUI:50252B* + ID_OUI_FROM_DATABASE=Nethra Imaging Incorporated + +OUI:502690* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:5027C7* + ID_OUI_FROM_DATABASE=TECHNART Co.,Ltd + +OUI:502A7E* + ID_OUI_FROM_DATABASE=Smart electronic GmbH + +OUI:502A8B* + ID_OUI_FROM_DATABASE=Telekom Research and Development Sdn Bhd + +OUI:502D1D* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:502DA2* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:502DF4* + ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH + +OUI:502E5C* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:502ECE* + ID_OUI_FROM_DATABASE=Asahi Electronics Co.,Ltd + +OUI:503275* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:503955* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:503CC4* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:503DE5* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:503F56* + ID_OUI_FROM_DATABASE=Syncmold Enterprise Corp + +OUI:50465D* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:5048EB* + ID_OUI_FROM_DATABASE=BEIJING HAIHEJINSHENG NETWORK TECHNOLOGY CO. LTD. + +OUI:504A5E* + ID_OUI_FROM_DATABASE=Masimo Corporation + +OUI:504A6E* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:504F94* + ID_OUI_FROM_DATABASE=Loxone Electronics GmbH + +OUI:505663* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:5056A8* + ID_OUI_FROM_DATABASE=Jolla Ltd + +OUI:5057A8* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:505AC6* + ID_OUI_FROM_DATABASE=GUANGDONG SUPER TELECOM CO.,LTD. + +OUI:506028* + ID_OUI_FROM_DATABASE=Xirrus Inc. + +OUI:506184* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:5061D6* + ID_OUI_FROM_DATABASE=Indu-Sol GmbH + +OUI:506313* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:506441* + ID_OUI_FROM_DATABASE=Greenlee + +OUI:5067F0* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:506F9A* + ID_OUI_FROM_DATABASE=Wi-Fi Alliance + +OUI:5070E5* + ID_OUI_FROM_DATABASE=He Shan World Fair Electronics Technology Limited + +OUI:50724D* + ID_OUI_FROM_DATABASE=BEG Brueck Electronic GmbH + +OUI:507691* + ID_OUI_FROM_DATABASE=Tekpea, Inc. + +OUI:5076A6* + ID_OUI_FROM_DATABASE=Ecil Informatica Ind. Com. Ltda + +OUI:50795B* + ID_OUI_FROM_DATABASE=Interexport Telecomunicaciones S.A. + +OUI:507D02* + ID_OUI_FROM_DATABASE=BIODIT + +OUI:507E5D* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:508569* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:5087B8* + ID_OUI_FROM_DATABASE=Nuvyyo Inc + +OUI:508A42* + ID_OUI_FROM_DATABASE=Uptmate Technology Co., LTD + +OUI:508ACB* + ID_OUI_FROM_DATABASE=SHENZHEN MAXMADE TECHNOLOGY CO., LTD. + +OUI:508C77* + ID_OUI_FROM_DATABASE=DIRMEIER Schanktechnik GmbH &Co KG + +OUI:508D6F* + ID_OUI_FROM_DATABASE=CHAHOO Limited + +OUI:50934F* + ID_OUI_FROM_DATABASE=Gradual Tecnologia Ltda. + +OUI:509772* + ID_OUI_FROM_DATABASE=Westinghouse Digital + +OUI:509871* + ID_OUI_FROM_DATABASE=Inventum Technologies Private Limited + +OUI:509F27* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:50A054* + ID_OUI_FROM_DATABASE=Actineon + +OUI:50A0BF* + ID_OUI_FROM_DATABASE=Alba Fiber Systems Inc. + +OUI:50A4C8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:50A6E3* + ID_OUI_FROM_DATABASE=David Clark Company + +OUI:50A715* + ID_OUI_FROM_DATABASE=Aboundi, Inc. + +OUI:50A733* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:50ABBF* + ID_OUI_FROM_DATABASE=Hoseo Telecom + +OUI:50AF73* + ID_OUI_FROM_DATABASE=Shenzhen Bitland Information Technology Co., Ltd. + +OUI:50B695* + ID_OUI_FROM_DATABASE=Micropoint Biotechnologies,Inc. + +OUI:50B7C3* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:50B888* + ID_OUI_FROM_DATABASE=wi2be Tecnologia S/A + +OUI:50B8A2* + ID_OUI_FROM_DATABASE=ImTech Technologies LLC, + +OUI:50C006* + ID_OUI_FROM_DATABASE=Carmanah Signs + +OUI:50C271* + ID_OUI_FROM_DATABASE=SECURETECH INC + +OUI:50C58D* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:50C971* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:50C9A0* + ID_OUI_FROM_DATABASE=SKIPPER Electronics AS + +OUI:50CCF8* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics + +OUI:50CD32* + ID_OUI_FROM_DATABASE=NanJing Chaoran Science & Technology Co.,Ltd. + +OUI:50CE75* + ID_OUI_FROM_DATABASE=Measy Electronics Ltd + +OUI:50D274* + ID_OUI_FROM_DATABASE=Steffes Corporation + +OUI:50D6D7* + ID_OUI_FROM_DATABASE=Takahata Precision + +OUI:50E0C7* + ID_OUI_FROM_DATABASE=TurControlSystme AG + +OUI:50E549* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:50EAD6* + ID_OUI_FROM_DATABASE=Apple + +OUI:50EB1A* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:50ED78* + ID_OUI_FROM_DATABASE=Changzhou Yongse Infotech Co.,Ltd + +OUI:50ED94* + ID_OUI_FROM_DATABASE=Egatel SL + +OUI:50F003* + ID_OUI_FROM_DATABASE=Open Stack, Inc. + +OUI:50F520* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:50F61A* + ID_OUI_FROM_DATABASE=Kunshan JADE Technologies co., Ltd. + +OUI:50FAAB* + ID_OUI_FROM_DATABASE=L-tek d.o.o. + +OUI:50FC30* + ID_OUI_FROM_DATABASE=Treehouse Labs + +OUI:50FC9F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:5403F5* + ID_OUI_FROM_DATABASE=EBN Technology Corp. + +OUI:540496* + ID_OUI_FROM_DATABASE=Gigawave LTD + +OUI:5404A6* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:540536* + ID_OUI_FROM_DATABASE=Vivago Oy + +OUI:54055F* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:54112F* + ID_OUI_FROM_DATABASE=Sulzer Pump Solutions Finland Oy + +OUI:54115F* + ID_OUI_FROM_DATABASE=Atamo Pty Ltd + +OUI:541B5D* + ID_OUI_FROM_DATABASE=Techno-Innov + +OUI:541DFB* + ID_OUI_FROM_DATABASE=Freestyle Energy Ltd + +OUI:541FD5* + ID_OUI_FROM_DATABASE=Advantage Electronics + +OUI:542018* + ID_OUI_FROM_DATABASE=Tely Labs + +OUI:542160* + ID_OUI_FROM_DATABASE=Resolution Products + +OUI:5422F8* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:542696* + ID_OUI_FROM_DATABASE=Apple + +OUI:54271E* + ID_OUI_FROM_DATABASE=AzureWave Technonloies, Inc. + +OUI:542A9C* + ID_OUI_FROM_DATABASE=LSY Defense, LLC. + +OUI:542CEA* + ID_OUI_FROM_DATABASE=PROTECTRON + +OUI:542F89* + ID_OUI_FROM_DATABASE=Euclid Laboratories, Inc. + +OUI:543131* + ID_OUI_FROM_DATABASE=Raster Vision Ltd + +OUI:543530* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:5435DF* + ID_OUI_FROM_DATABASE=Symeo GmbH + +OUI:543968* + ID_OUI_FROM_DATABASE=Edgewater Networks Inc + +OUI:5439DF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:543D37* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:544249* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:544408* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:54466B* + ID_OUI_FROM_DATABASE=Shenzhen CZTIC Electronic Technology Co., Ltd + +OUI:544A05* + ID_OUI_FROM_DATABASE=wenglor sensoric gmbh + +OUI:5453ED* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:545414* + ID_OUI_FROM_DATABASE=Digital RF Corea, Inc + +OUI:545EBD* + ID_OUI_FROM_DATABASE=NL Technologies + +OUI:545FA9* + ID_OUI_FROM_DATABASE=Teracom Limited + +OUI:5461EA* + ID_OUI_FROM_DATABASE=Zaplox AB + +OUI:54724F* + ID_OUI_FROM_DATABASE=Apple + +OUI:547398* + ID_OUI_FROM_DATABASE=Toyo Electronics Corporation + +OUI:5474E6* + ID_OUI_FROM_DATABASE=Webtech Wireless + +OUI:5475D0* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:54781A* + ID_OUI_FROM_DATABASE=Cisco + +OUI:547975* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:547F54* + ID_OUI_FROM_DATABASE=INGENICO + +OUI:547FA8* + ID_OUI_FROM_DATABASE=TELCO systems, s.r.o. + +OUI:547FEE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:5481AD* + ID_OUI_FROM_DATABASE=Eagle Research Corporation + +OUI:54847B* + ID_OUI_FROM_DATABASE=Digital Devices GmbH + +OUI:54880E* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. + +OUI:548922* + ID_OUI_FROM_DATABASE=Zelfy Inc + +OUI:548998* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:5492BE* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:549359* + ID_OUI_FROM_DATABASE=SHENZHEN TWOWING TECHNOLOGIES CO.,LTD. + +OUI:549478* + ID_OUI_FROM_DATABASE=Silvershore Technology Partners + +OUI:549A16* + ID_OUI_FROM_DATABASE=Uzushio Electric Co.,Ltd. + +OUI:549B12* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:549D85* + ID_OUI_FROM_DATABASE=EnerAccess inc + +OUI:54A04F* + ID_OUI_FROM_DATABASE=t-mac Technologies Ltd + +OUI:54A31B* + ID_OUI_FROM_DATABASE=Shenzhen Linkworld Technology Co,.LTD + +OUI:54A51B* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:54A54B* + ID_OUI_FROM_DATABASE=NSC Communications Siberia Ltd + +OUI:54A619* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:54A9D4* + ID_OUI_FROM_DATABASE=Minibar Systems + +OUI:54AE27* + ID_OUI_FROM_DATABASE=Apple + +OUI:54B620* + ID_OUI_FROM_DATABASE=SUHDOL E&C Co.Ltd. + +OUI:54BEF7* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:54CDA7* + ID_OUI_FROM_DATABASE=Fujian Shenzhou Electronic Co.,Ltd + +OUI:54CDEE* + ID_OUI_FROM_DATABASE=ShenZhen Apexis Electronic Co.,Ltd + +OUI:54D0ED* + ID_OUI_FROM_DATABASE=AXIM Communications + +OUI:54D163* + ID_OUI_FROM_DATABASE=MAX-TECH,INC + +OUI:54D1B0* + ID_OUI_FROM_DATABASE=Universal Laser Systems, Inc + +OUI:54D46F* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:54DF63* + ID_OUI_FROM_DATABASE=Intrakey technologies GmbH + +OUI:54E032* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:54E2E0* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:54E3B0* + ID_OUI_FROM_DATABASE=JVL Industri Elektronik + +OUI:54E43A* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:54E63F* + ID_OUI_FROM_DATABASE=ShenZhen LingKeWeiEr Technology Co., Ltd. + +OUI:54E6FC* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:54EAA8* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:54F5B6* + ID_OUI_FROM_DATABASE=ORIENTAL PACIFIC INTERNATIONAL LIMITED + +OUI:54F666* + ID_OUI_FROM_DATABASE=Berthold Technologies GmbH and Co.KG + +OUI:54FB58* + ID_OUI_FROM_DATABASE=WISEWARE, Lda + +OUI:54FDBF* + ID_OUI_FROM_DATABASE=Scheidt & Bachmann GmbH + +OUI:580528* + ID_OUI_FROM_DATABASE=LABRIS NETWORKS + +OUI:580556* + ID_OUI_FROM_DATABASE=Elettronica GF S.r.L. + +OUI:5808FA* + ID_OUI_FROM_DATABASE=Fiber Optic & telecommunication INC. + +OUI:5809E5* + ID_OUI_FROM_DATABASE=Kivic Inc. + +OUI:580A20* + ID_OUI_FROM_DATABASE=Cisco + +OUI:581243* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:581626* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:58170C* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:581CBD* + ID_OUI_FROM_DATABASE=Affinegy + +OUI:581D91* + ID_OUI_FROM_DATABASE=Advanced Mobile Telecom co.,ltd. + +OUI:581FAA* + ID_OUI_FROM_DATABASE=Apple + +OUI:581FEF* + ID_OUI_FROM_DATABASE=Tuttnaer LTD + +OUI:582EFE* + ID_OUI_FROM_DATABASE=Lighting Science Group + +OUI:582F42* + ID_OUI_FROM_DATABASE=Universal Electric Corporation + +OUI:58343B* + ID_OUI_FROM_DATABASE=Glovast Technology Ltd. + +OUI:5835D9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:583CC6* + ID_OUI_FROM_DATABASE=Omneality Ltd. + +OUI:5842E4* + ID_OUI_FROM_DATABASE=Sigma International General Medical Apparatus, LLC. + +OUI:58468F* + ID_OUI_FROM_DATABASE=Koncar Electronics and Informatics + +OUI:5846E1* + ID_OUI_FROM_DATABASE=Baxter Healthcare + +OUI:5848C0* + ID_OUI_FROM_DATABASE=COFLEC + +OUI:58493B* + ID_OUI_FROM_DATABASE=Palo Alto Networks + +OUI:5849BA* + ID_OUI_FROM_DATABASE=Chitai Electronic Corp. + +OUI:584C19* + ID_OUI_FROM_DATABASE=Chongqing Guohong Technology Development Company Limited + +OUI:584CEE* + ID_OUI_FROM_DATABASE=Digital One Technologies, Limited + +OUI:585076* + ID_OUI_FROM_DATABASE=Linear Equipamentos Eletronicos SA + +OUI:5850AB* + ID_OUI_FROM_DATABASE=TLS Corporation + +OUI:5850E6* + ID_OUI_FROM_DATABASE=Best Buy Corporation + +OUI:5855CA* + ID_OUI_FROM_DATABASE=Apple + +OUI:5856E8* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:58570D* + ID_OUI_FROM_DATABASE=Danfoss Solar Inverters + +OUI:58639A* + ID_OUI_FROM_DATABASE=TPL SYSTEMES + +OUI:5865E6* + ID_OUI_FROM_DATABASE=INFOMARK CO., LTD. + +OUI:5866BA* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:58671A* + ID_OUI_FROM_DATABASE=BARNES&NOBLE.COM + +OUI:58677F* + ID_OUI_FROM_DATABASE=Clare Controls Inc. + +OUI:58696C* + ID_OUI_FROM_DATABASE=Fujian Ruijie Networks co, ltd + +OUI:5869F9* + ID_OUI_FROM_DATABASE=Fusion Transactive Ltd. + +OUI:586D8F* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:587521* + ID_OUI_FROM_DATABASE=CJSC RTSoft + +OUI:587675* + ID_OUI_FROM_DATABASE=Beijing ECHO Technologies Co.,Ltd + +OUI:587A4D* + ID_OUI_FROM_DATABASE=Stonesoft Corporation + +OUI:587E61* + ID_OUI_FROM_DATABASE=Hisense Electric Co., Ltd + +OUI:587FC8* + ID_OUI_FROM_DATABASE=S2M + +OUI:5884E4* + ID_OUI_FROM_DATABASE=IP500 Alliance e.V. + +OUI:58874C* + ID_OUI_FROM_DATABASE=LITE-ON CLEAN ENERGY TECHNOLOGY CORP. + +OUI:5887E2* + ID_OUI_FROM_DATABASE=Shenzhen Coship Electronics Co., Ltd. + +OUI:588D09* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:5891CF* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:58920D* + ID_OUI_FROM_DATABASE=Kinetic Avionics Limited + +OUI:589396* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:58946B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:5894CF* + ID_OUI_FROM_DATABASE=Vertex Standard LMR, Inc. + +OUI:58971E* + ID_OUI_FROM_DATABASE=Cisco + +OUI:589835* + ID_OUI_FROM_DATABASE=Technicolor + +OUI:58986F* + ID_OUI_FROM_DATABASE=Revolution Display + +OUI:589CFC* + ID_OUI_FROM_DATABASE=FreeBSD Foundation + +OUI:58A2B5* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:58A76F* + ID_OUI_FROM_DATABASE=iD corporation + +OUI:58B035* + ID_OUI_FROM_DATABASE=Apple + +OUI:58B0D4* + ID_OUI_FROM_DATABASE=ZuniData Systems Inc. + +OUI:58B961* + ID_OUI_FROM_DATABASE=SOLEM Electronique + +OUI:58B9E1* + ID_OUI_FROM_DATABASE=Crystalfontz America, Inc. + +OUI:58BC27* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:58BDA3* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:58BDF9* + ID_OUI_FROM_DATABASE=Sigrand + +OUI:58BFEA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:58C232* + ID_OUI_FROM_DATABASE=NEC Corporation + +OUI:58C38B* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:58CF4B* + ID_OUI_FROM_DATABASE=Lufkin Industries + +OUI:58D071* + ID_OUI_FROM_DATABASE=BW Broadcast + +OUI:58D08F* + ID_OUI_FROM_DATABASE=IEEE 1904.1 Working Group + +OUI:58D6D3* + ID_OUI_FROM_DATABASE=Dairy Cheq Inc + +OUI:58DB8D* + ID_OUI_FROM_DATABASE=Fast Co., Ltd. + +OUI:58E02C* + ID_OUI_FROM_DATABASE=Micro Technic A/S + +OUI:58E476* + ID_OUI_FROM_DATABASE=CENTRON COMMUNICATIONS TECHNOLOGIES FUJIAN CO.,LTD + +OUI:58E636* + ID_OUI_FROM_DATABASE=EVRsafe Technologies + +OUI:58E747* + ID_OUI_FROM_DATABASE=Deltanet AG + +OUI:58E808* + ID_OUI_FROM_DATABASE=AUTONICS CORPORATION + +OUI:58EB14* + ID_OUI_FROM_DATABASE=Proteus Digital Health + +OUI:58ECE1* + ID_OUI_FROM_DATABASE=Newport Corporation + +OUI:58EECE* + ID_OUI_FROM_DATABASE=Icon Time Systems + +OUI:58F387* + ID_OUI_FROM_DATABASE=HCCP + +OUI:58F67B* + ID_OUI_FROM_DATABASE=Xia Men UnionCore Technology LTD. + +OUI:58F6BF* + ID_OUI_FROM_DATABASE=Kyoto University + +OUI:58F98E* + ID_OUI_FROM_DATABASE=SECUDOS GmbH + +OUI:58FD20* + ID_OUI_FROM_DATABASE=Bravida Sakerhet AB + +OUI:5C026A* + ID_OUI_FROM_DATABASE=Applied Vision Corporation + +OUI:5C076F* + ID_OUI_FROM_DATABASE=Thought Creator + +OUI:5C0A5B* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD. + +OUI:5C0CBB* + ID_OUI_FROM_DATABASE=CELIZION Inc. + +OUI:5C0E8B* + ID_OUI_FROM_DATABASE=Motorola + +OUI:5C1193* + ID_OUI_FROM_DATABASE=Seal One AG + +OUI:5C1437* + ID_OUI_FROM_DATABASE=Thyssenkrupp Aufzugswerke GmbH + +OUI:5C15E1* + ID_OUI_FROM_DATABASE=AIDC TECHNOLOGY (S) PTE LTD + +OUI:5C16C7* + ID_OUI_FROM_DATABASE=Big Switch Networks + +OUI:5C1737* + ID_OUI_FROM_DATABASE=I-View Now, LLC. + +OUI:5C17D3* + ID_OUI_FROM_DATABASE=LGE + +OUI:5C18B5* + ID_OUI_FROM_DATABASE=Talon Communications + +OUI:5C20D0* + ID_OUI_FROM_DATABASE=Asoni Communication Co., Ltd. + +OUI:5C22C4* + ID_OUI_FROM_DATABASE=DAE EUN ELETRONICS CO., LTD + +OUI:5C2479* + ID_OUI_FROM_DATABASE=Baltech AG + +OUI:5C254C* + ID_OUI_FROM_DATABASE=Avire Global Pte Ltd + +OUI:5C260A* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:5C2AEF* + ID_OUI_FROM_DATABASE=Open Access Pty Ltd + +OUI:5C3327* + ID_OUI_FROM_DATABASE=Spazio Italia srl + +OUI:5C335C* + ID_OUI_FROM_DATABASE=Swissphone Telecom AG + +OUI:5C338E* + ID_OUI_FROM_DATABASE=Alpha Networkc Inc. + +OUI:5C353B* + ID_OUI_FROM_DATABASE=Compal Broadband Networks Inc. + +OUI:5C35DA* + ID_OUI_FROM_DATABASE=There Corporation Oy + +OUI:5C36B8* + ID_OUI_FROM_DATABASE=TCL King Electrical Appliances (Huizhou) Ltd. + +OUI:5C38E0* + ID_OUI_FROM_DATABASE=Shanghai Super Electronics Technology Co.,LTD + +OUI:5C3C27* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:5C4058* + ID_OUI_FROM_DATABASE=Jefferson Audio Video Systems, Inc. + +OUI:5C43D2* + ID_OUI_FROM_DATABASE=HAZEMEYER + +OUI:5C4A26* + ID_OUI_FROM_DATABASE=Enguity Technology Corp + +OUI:5C4CA9* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:5C5015* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:5C514F* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:5C56ED* + ID_OUI_FROM_DATABASE=3pleplay Electronics Private Limited + +OUI:5C571A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:5C57C8* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:5C5948* + ID_OUI_FROM_DATABASE=Apple + +OUI:5C5EAB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:5C63BF* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:5C6984* + ID_OUI_FROM_DATABASE=NUVICO + +OUI:5C6A7D* + ID_OUI_FROM_DATABASE=KENTKART EGE ELEKTRONIK SAN. VE TIC. LTD. STI. + +OUI:5C6B32* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:5C6D20* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:5C6F4F* + ID_OUI_FROM_DATABASE=S.A. SISTEL + +OUI:5C7757* + ID_OUI_FROM_DATABASE=Haivision Network Video + +OUI:5C7D5E* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:5C8486* + ID_OUI_FROM_DATABASE=Brightsource Industries Israel LTD + +OUI:5C864A* + ID_OUI_FROM_DATABASE=Secret Labs LLC + +OUI:5C8778* + ID_OUI_FROM_DATABASE=Cybertelbridge co.,ltd + +OUI:5C89D4* + ID_OUI_FROM_DATABASE=Beijing Banner Electric Co.,Ltd + +OUI:5C95AE* + ID_OUI_FROM_DATABASE=Apple + +OUI:5C969D* + ID_OUI_FROM_DATABASE=Apple + +OUI:5C9AD8* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:5CA39D* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD. + +OUI:5CA3EB* + ID_OUI_FROM_DATABASE=Lokel s.r.o. + +OUI:5CA48A* + ID_OUI_FROM_DATABASE=Cisco + +OUI:5CAC4C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:5CB524* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:5CBD9E* + ID_OUI_FROM_DATABASE=HONGKONG MIRACLE EAGLE TECHNOLOGY(GROUP) LIMITED + +OUI:5CC213* + ID_OUI_FROM_DATABASE=Fr. Sauter AG + +OUI:5CC5D4* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:5CC6D0* + ID_OUI_FROM_DATABASE=Skyworth Digital technology(shenzhen)co.ltd. + +OUI:5CC9D3* + ID_OUI_FROM_DATABASE=PALLADIUM ENERGY ELETRONICA DA AMAZONIA LTDA + +OUI:5CCA32* + ID_OUI_FROM_DATABASE=Theben AG + +OUI:5CCEAD* + ID_OUI_FROM_DATABASE=CDYNE Corporation + +OUI:5CD135* + ID_OUI_FROM_DATABASE=Xtreme Power Systems + +OUI:5CD2E4* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:5CD41B* + ID_OUI_FROM_DATABASE=UCZOON Technology Co., LTD + +OUI:5CD4AB* + ID_OUI_FROM_DATABASE=Zektor + +OUI:5CD61F* + ID_OUI_FROM_DATABASE=Qardio, Inc + +OUI:5CD998* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:5CDAD4* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + +OUI:5CDD70* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:5CE0CA* + ID_OUI_FROM_DATABASE=FeiTian United (Beijing) System Technology Co., Ltd. + +OUI:5CE0F6* + ID_OUI_FROM_DATABASE=NIC.br- Nucleo de Informacao e Coordenacao do Ponto BR + +OUI:5CE223* + ID_OUI_FROM_DATABASE=Delphin Technology AG + +OUI:5CE286* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:5CE2F4* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:5CE7BF* + ID_OUI_FROM_DATABASE=New Singularity International Technical Development Co.,Ltd + +OUI:5CE8EB* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:5CEB4E* + ID_OUI_FROM_DATABASE=R. STAHL HMI Systems GmbH + +OUI:5CEE79* + ID_OUI_FROM_DATABASE=Global Digitech Co LTD + +OUI:5CF207* + ID_OUI_FROM_DATABASE=Speco Technologies + +OUI:5CF370* + ID_OUI_FROM_DATABASE=CC&C Technologies, Inc + +OUI:5CF3FC* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:5CF50D* + ID_OUI_FROM_DATABASE=Institute of microelectronic applications + +OUI:5CF6DC* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:5CF8A1* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:5CF938* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:5CF9DD* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:5CFF35* + ID_OUI_FROM_DATABASE=Wistron Corporation + +OUI:5CFFFF* + ID_OUI_FROM_DATABASE=Shenzhen Kezhonglong Optoelectronic Technology Co., Ltd + +OUI:6002B4* + ID_OUI_FROM_DATABASE=Wistron NeWeb Corp. + +OUI:600308* + ID_OUI_FROM_DATABASE=Apple + +OUI:600347* + ID_OUI_FROM_DATABASE=Billion Electric Co. Ltd. + +OUI:600F77* + ID_OUI_FROM_DATABASE=SilverPlus, Inc + +OUI:601199* + ID_OUI_FROM_DATABASE=Siama Systems Inc + +OUI:601283* + ID_OUI_FROM_DATABASE=Soluciones Tecnologicas para la Salud y el Bienestar SA + +OUI:6015C7* + ID_OUI_FROM_DATABASE=IdaTech + +OUI:60190C* + ID_OUI_FROM_DATABASE=RRAMAC + +OUI:601929* + ID_OUI_FROM_DATABASE=VOLTRONIC POWER TECHNOLOGY(SHENZHEN) CORP. + +OUI:601D0F* + ID_OUI_FROM_DATABASE=Midnite Solar + +OUI:601E02* + ID_OUI_FROM_DATABASE=EltexAlatau + +OUI:602103* + ID_OUI_FROM_DATABASE=STCUBE.INC + +OUI:6021C0* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:6024C1* + ID_OUI_FROM_DATABASE=Jiangsu Zhongxun Electronic Technology Co., Ltd + +OUI:602A54* + ID_OUI_FROM_DATABASE=CardioTek B.V. + +OUI:602AD0* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:6032F0* + ID_OUI_FROM_DATABASE=Mplus technology + +OUI:60334B* + ID_OUI_FROM_DATABASE=Apple + +OUI:603553* + ID_OUI_FROM_DATABASE=Buwon Technology + +OUI:6036DD* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:60380E* + ID_OUI_FROM_DATABASE=Alps Electric Co., + +OUI:60391F* + ID_OUI_FROM_DATABASE=ABB Ltd + +OUI:603FC5* + ID_OUI_FROM_DATABASE=COX CO., LTD + +OUI:6044F5* + ID_OUI_FROM_DATABASE=Easy Digital Ltd. + +OUI:60455E* + ID_OUI_FROM_DATABASE=Liptel s.r.o. + +OUI:6045BD* + ID_OUI_FROM_DATABASE=Microsoft + +OUI:604616* + ID_OUI_FROM_DATABASE=XIAMEN VANN INTELLIGENT CO., LTD + +OUI:6047D4* + ID_OUI_FROM_DATABASE=FORICS Electronic Technology Co., Ltd. + +OUI:604A1C* + ID_OUI_FROM_DATABASE=SUYIN Corporation + +OUI:6052D0* + ID_OUI_FROM_DATABASE=FACTS Engineering + +OUI:605464* + ID_OUI_FROM_DATABASE=Eyedro Green Solutions Inc. + +OUI:605718* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:60601F* + ID_OUI_FROM_DATABASE=SZ DJI TECHNOLOGY CO.,LTD + +OUI:6063FD* + ID_OUI_FROM_DATABASE=Transcend Communication Beijing Co.,Ltd. + +OUI:6064A1* + ID_OUI_FROM_DATABASE=RADiflow Ltd. + +OUI:606720* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:606944* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:60699B* + ID_OUI_FROM_DATABASE=isepos GmbH + +OUI:606BBD* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:606C66* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:60735C* + ID_OUI_FROM_DATABASE=Cisco + +OUI:60748D* + ID_OUI_FROM_DATABASE=Atmaca Elektronik + +OUI:607688* + ID_OUI_FROM_DATABASE=Velodyne + +OUI:6083B2* + ID_OUI_FROM_DATABASE=GkWare e.K. + +OUI:60843B* + ID_OUI_FROM_DATABASE=Soladigm, Inc. + +OUI:608645* + ID_OUI_FROM_DATABASE=Avery Weigh-Tronix, LLC + +OUI:60893C* + ID_OUI_FROM_DATABASE=Thermo Fisher Scientific P.O.A. + +OUI:6089B1* + ID_OUI_FROM_DATABASE=Key Digital Systems + +OUI:6089B7* + ID_OUI_FROM_DATABASE=KAEL MÜHENDİSLİK ELEKTRONİK TİCARET SANAYİ LİMİTED ŞİRKETİ + +OUI:608C2B* + ID_OUI_FROM_DATABASE=Hanson Technology + +OUI:608D17* + ID_OUI_FROM_DATABASE=Sentrus Government Systems Division, Inc + +OUI:609084* + ID_OUI_FROM_DATABASE=DSSD Inc + +OUI:609AA4* + ID_OUI_FROM_DATABASE=GVI SECURITY INC. + +OUI:609E64* + ID_OUI_FROM_DATABASE=Vivonic GmbH + +OUI:609F9D* + ID_OUI_FROM_DATABASE=CloudSwitch + +OUI:60A10A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:60A44C* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:60A9B0* + ID_OUI_FROM_DATABASE=Merchandising Technologies, Inc + +OUI:60B185* + ID_OUI_FROM_DATABASE=ATH system + +OUI:60B3C4* + ID_OUI_FROM_DATABASE=Elber Srl + +OUI:60B606* + ID_OUI_FROM_DATABASE=Phorus + +OUI:60B933* + ID_OUI_FROM_DATABASE=Deutron Electronics Corp. + +OUI:60B982* + ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A. + +OUI:60BB0C* + ID_OUI_FROM_DATABASE=Beijing HuaqinWorld Technology Co,Ltd + +OUI:60BC4C* + ID_OUI_FROM_DATABASE=EWM Hightec Welding GmbH + +OUI:60BD91* + ID_OUI_FROM_DATABASE=Move Innovation + +OUI:60BEB5* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + +OUI:60C397* + ID_OUI_FROM_DATABASE=2Wire Inc + +OUI:60C547* + ID_OUI_FROM_DATABASE=Apple + +OUI:60C5A8* + ID_OUI_FROM_DATABASE=Beijing LT Honway Technology Co.,Ltd + +OUI:60C980* + ID_OUI_FROM_DATABASE=Trymus + +OUI:60CBFB* + ID_OUI_FROM_DATABASE=AirScape Inc. + +OUI:60CDC5* + ID_OUI_FROM_DATABASE=Taiwan Carol Electronics., Ltd + +OUI:60D0A9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:60D1AA* + ID_OUI_FROM_DATABASE=Vishal Telecommunications Pvt Ltd + +OUI:60D2B9* + ID_OUI_FROM_DATABASE=REALAND BIO CO., LTD. + +OUI:60D30A* + ID_OUI_FROM_DATABASE=Quatius Limited + +OUI:60D819* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:60D9C7* + ID_OUI_FROM_DATABASE=Apple + +OUI:60DA23* + ID_OUI_FROM_DATABASE=Estech Co.,Ltd + +OUI:60DB2A* + ID_OUI_FROM_DATABASE=HNS + +OUI:60DE44* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:60E00E* + ID_OUI_FROM_DATABASE=SHINSEI ELECTRONICS CO LTD + +OUI:60E956* + ID_OUI_FROM_DATABASE=Ayla Networks, Inc + +OUI:60EB69* + ID_OUI_FROM_DATABASE=Quanta computer Inc. + +OUI:60F13D* + ID_OUI_FROM_DATABASE=JABLOCOM s.r.o. + +OUI:60F281* + ID_OUI_FROM_DATABASE=TRANWO TECHNOLOGY CO., LTD. + +OUI:60F2EF* + ID_OUI_FROM_DATABASE=VisionVera International Co., Ltd. + +OUI:60F3DA* + ID_OUI_FROM_DATABASE=Logic Way GmbH + +OUI:60F494* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:60F59C* + ID_OUI_FROM_DATABASE=CRU-Dataport + +OUI:60F673* + ID_OUI_FROM_DATABASE=TERUMO CORPORATION + +OUI:60FACD* + ID_OUI_FROM_DATABASE=Apple + +OUI:60FB42* + ID_OUI_FROM_DATABASE=Apple + +OUI:60FE1E* + ID_OUI_FROM_DATABASE=China Palms Telecom.Ltd + +OUI:60FE20* + ID_OUI_FROM_DATABASE=2 Wire + +OUI:60FEC5* + ID_OUI_FROM_DATABASE=Apple + +OUI:60FEF9* + ID_OUI_FROM_DATABASE=Thomas & Betts + +OUI:60FFDD* + ID_OUI_FROM_DATABASE=C.E. ELECTRONICS, INC + +OUI:6400F1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:6405BE* + ID_OUI_FROM_DATABASE=NEW LIGHT LED + +OUI:64094C* + ID_OUI_FROM_DATABASE=Beijing Superbee Wireless Technology Co.,Ltd + +OUI:640B4A* + ID_OUI_FROM_DATABASE=Digital Telecom Technology Limited + +OUI:640E36* + ID_OUI_FROM_DATABASE=TAZTAG + +OUI:640E94* + ID_OUI_FROM_DATABASE=Pluribus Networks, Inc. + +OUI:640F28* + ID_OUI_FROM_DATABASE=2wire + +OUI:641084* + ID_OUI_FROM_DATABASE=HEXIUM Technical Development Co., Ltd. + +OUI:64168D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:6416F0* + ID_OUI_FROM_DATABASE=Shehzhen Huawei Communication Technologies Co., Ltd. + +OUI:641A22* + ID_OUI_FROM_DATABASE=Heliospectra/Woodhill Investments + +OUI:641C67* + ID_OUI_FROM_DATABASE=DIGIBRAS INDUSTRIA DO BRASILS/A + +OUI:641E81* + ID_OUI_FROM_DATABASE=Dowslake Microsystems + +OUI:64200C* + ID_OUI_FROM_DATABASE=Apple + +OUI:642184* + ID_OUI_FROM_DATABASE=Nippon Denki Kagaku Co.,LTD + +OUI:642216* + ID_OUI_FROM_DATABASE=Shandong Taixin Electronic co.,Ltd + +OUI:642400* + ID_OUI_FROM_DATABASE=Xorcom Ltd. + +OUI:642737* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:642DB7* + ID_OUI_FROM_DATABASE=SEUNGIL ELECTRONICS + +OUI:643150* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:64317E* + ID_OUI_FROM_DATABASE=Dexin Corporation + +OUI:643409* + ID_OUI_FROM_DATABASE=BITwave Pte Ltd + +OUI:643F5F* + ID_OUI_FROM_DATABASE=Exablaze + +OUI:644214* + ID_OUI_FROM_DATABASE=Swisscom Energy Solutions AG + +OUI:644346* + ID_OUI_FROM_DATABASE=GuangDong Quick Network Computer CO.,LTD + +OUI:644BC3* + ID_OUI_FROM_DATABASE=Shanghai WOASiS Telecommunications Ltd., Co. + +OUI:644BF0* + ID_OUI_FROM_DATABASE=CalDigit, Inc + +OUI:644D70* + ID_OUI_FROM_DATABASE=dSPACE GmbH + +OUI:644F74* + ID_OUI_FROM_DATABASE=LENUS Co., Ltd. + +OUI:64517E* + ID_OUI_FROM_DATABASE=LONG BEN (DONGGUAN) ELECTRONIC TECHNOLOGY CO.,LTD. + +OUI:645299* + ID_OUI_FROM_DATABASE=The Chamberlain Group, Inc + +OUI:64535D* + ID_OUI_FROM_DATABASE=Frauscher Sensortechnik + +OUI:645422* + ID_OUI_FROM_DATABASE=Equinox Payments + +OUI:645563* + ID_OUI_FROM_DATABASE=Intelight Inc. + +OUI:64557F* + ID_OUI_FROM_DATABASE=NSFOCUS Information Technology Co., Ltd. + +OUI:6455B1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:645601* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD + +OUI:645A04* + ID_OUI_FROM_DATABASE=Chicony Electronics Co., Ltd. + +OUI:645DD7* + ID_OUI_FROM_DATABASE=Shenzhen Lifesense Medical Electronics Co., Ltd. + +OUI:645EBE* + ID_OUI_FROM_DATABASE=Yahoo! JAPAN + +OUI:645FFF* + ID_OUI_FROM_DATABASE=Nicolet Neuro + +OUI:646223* + ID_OUI_FROM_DATABASE=Cellient Co., Ltd. + +OUI:6465C0* + ID_OUI_FROM_DATABASE=Nuvon, Inc + +OUI:6466B3* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:646707* + ID_OUI_FROM_DATABASE=Beijing Omnific Technology, Ltd. + +OUI:64680C* + ID_OUI_FROM_DATABASE=COMTREND + +OUI:6469BC* + ID_OUI_FROM_DATABASE=Hytera Communications Co .,ltd + +OUI:646E6C* + ID_OUI_FROM_DATABASE=Radio Datacom LLC + +OUI:646EEA* + ID_OUI_FROM_DATABASE=Iskratel d.o.o. + +OUI:647002* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:6472D8* + ID_OUI_FROM_DATABASE=GooWi Technology Co.,Limited + +OUI:6473E2* + ID_OUI_FROM_DATABASE=Arbiter Systems, Inc. + +OUI:647657* + ID_OUI_FROM_DATABASE=Innovative Security Designs + +OUI:6476BA* + ID_OUI_FROM_DATABASE=Apple + +OUI:647791* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:647BD4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:647C34* + ID_OUI_FROM_DATABASE=Ubee Interactive Corp. + +OUI:647D81* + ID_OUI_FROM_DATABASE=YOKOTA INDUSTRIAL CO,.LTD + +OUI:647FDA* + ID_OUI_FROM_DATABASE=TEKTELIC Communications Inc. + +OUI:64808B* + ID_OUI_FROM_DATABASE=VG Controls, Inc. + +OUI:648099* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:648125* + ID_OUI_FROM_DATABASE=Alphatron Marine BV + +OUI:648788* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:6487D7* + ID_OUI_FROM_DATABASE=Pirelli Tyre S.p.A. + +OUI:6488FF* + ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. + +OUI:648D9E* + ID_OUI_FROM_DATABASE=IVT Electronic Co.,Ltd + +OUI:64995D* + ID_OUI_FROM_DATABASE=LGE + +OUI:649968* + ID_OUI_FROM_DATABASE=Elentec + +OUI:6499A0* + ID_OUI_FROM_DATABASE=AG Elektronik AB + +OUI:649B24* + ID_OUI_FROM_DATABASE=V Technology Co., Ltd. + +OUI:649C81* + ID_OUI_FROM_DATABASE=Qualcomm iSkoot, Inc. + +OUI:649C8E* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:649EF3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:649FF7* + ID_OUI_FROM_DATABASE=Kone OYj + +OUI:64A0E7* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:64A232* + ID_OUI_FROM_DATABASE=OOO Samlight + +OUI:64A341* + ID_OUI_FROM_DATABASE=Wonderlan (Beijing) Technology Co., Ltd. + +OUI:64A3CB* + ID_OUI_FROM_DATABASE=Apple + +OUI:64A769* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:64A837* + ID_OUI_FROM_DATABASE=Juni Korea Co., Ltd + +OUI:64AE0C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:64AE88* + ID_OUI_FROM_DATABASE=Polytec GmbH + +OUI:64B310* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:64B370* + ID_OUI_FROM_DATABASE=PowerComm Solutons LLC + +OUI:64B64A* + ID_OUI_FROM_DATABASE=ViVOtech, Inc. + +OUI:64B9E8* + ID_OUI_FROM_DATABASE=Apple + +OUI:64BABD* + ID_OUI_FROM_DATABASE=SDJ Technologies, Inc. + +OUI:64BC11* + ID_OUI_FROM_DATABASE=CombiQ AB + +OUI:64C5AA* + ID_OUI_FROM_DATABASE=South African Broadcasting Corporation + +OUI:64C667* + ID_OUI_FROM_DATABASE=Barnes&Noble + +OUI:64C6AF* + ID_OUI_FROM_DATABASE=AXERRA Networks Ltd + +OUI:64C944* + ID_OUI_FROM_DATABASE=LARK Technologies, Inc + +OUI:64D02D* + ID_OUI_FROM_DATABASE=Next Generation Integration (NGI) + +OUI:64D1A3* + ID_OUI_FROM_DATABASE=Sitecom Europe BV + +OUI:64D241* + ID_OUI_FROM_DATABASE=Keith & Koep GmbH + +OUI:64D4BD* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:64D4DA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:64D814* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:64D912* + ID_OUI_FROM_DATABASE=Solidica, Inc. + +OUI:64D989* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:64DB18* + ID_OUI_FROM_DATABASE=OpenPattern + +OUI:64DC01* + ID_OUI_FROM_DATABASE=Static Systems Group PLC + +OUI:64DE1C* + ID_OUI_FROM_DATABASE=Kingnetic Pte Ltd + +OUI:64E161* + ID_OUI_FROM_DATABASE=DEP Corp. + +OUI:64E599* + ID_OUI_FROM_DATABASE=EFM Networks + +OUI:64E625* + ID_OUI_FROM_DATABASE=Woxu Wireless Co., Ltd + +OUI:64E682* + ID_OUI_FROM_DATABASE=Apple + +OUI:64E84F* + ID_OUI_FROM_DATABASE=Serialway Communication Technology Co. Ltd + +OUI:64E892* + ID_OUI_FROM_DATABASE=Morio Denki Co., Ltd. + +OUI:64E8E6* + ID_OUI_FROM_DATABASE=global moisture management system + +OUI:64E950* + ID_OUI_FROM_DATABASE=Cisco + +OUI:64EB8C* + ID_OUI_FROM_DATABASE=Seiko Epson Corporation + +OUI:64ED57* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:64ED62* + ID_OUI_FROM_DATABASE=WOORI SYSTEMS Co., Ltd + +OUI:64F242* + ID_OUI_FROM_DATABASE=Gerdes Aktiengesellschaft + +OUI:64F50E* + ID_OUI_FROM_DATABASE=Kinion Technology Company Limited + +OUI:64F970* + ID_OUI_FROM_DATABASE=Kenade Electronics Technology Co.,LTD. + +OUI:64F987* + ID_OUI_FROM_DATABASE=Avvasi Inc. + +OUI:64FC8C* + ID_OUI_FROM_DATABASE=Zonar Systems + +OUI:6805CA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:680927* + ID_OUI_FROM_DATABASE=Apple + +OUI:680AD7* + ID_OUI_FROM_DATABASE=Yancheng Kecheng Optoelectronic Technology Co., Ltd + +OUI:68122D* + ID_OUI_FROM_DATABASE=Special Instrument Development Co., Ltd. + +OUI:681590* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:6815D3* + ID_OUI_FROM_DATABASE=Zaklady Elektroniki i Mechaniki Precyzyjnej R&G S.A. + +OUI:681605* + ID_OUI_FROM_DATABASE=Systems And Electronic Development FZCO + +OUI:681729* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:68193F* + ID_OUI_FROM_DATABASE=Digital Airways + +OUI:681AB2* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:681CA2* + ID_OUI_FROM_DATABASE=Rosewill Inc. + +OUI:681D64* + ID_OUI_FROM_DATABASE=Sunwave Communications Co., Ltd + +OUI:681E8B* + ID_OUI_FROM_DATABASE=InfoSight Corporation + +OUI:681FD8* + ID_OUI_FROM_DATABASE=Advanced Telemetry + +OUI:68234B* + ID_OUI_FROM_DATABASE=Nihon Dengyo Kousaku + +OUI:682DDC* + ID_OUI_FROM_DATABASE=Wuhan Changjiang Electro-Communication Equipment CO.,LTD + +OUI:683B1E* + ID_OUI_FROM_DATABASE=Countwise LTD + +OUI:683EEC* + ID_OUI_FROM_DATABASE=ERECA + +OUI:684352* + ID_OUI_FROM_DATABASE=Bhuu Limited + +OUI:684898* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:684B88* + ID_OUI_FROM_DATABASE=Galtronics Telemetry Inc. + +OUI:684CA8* + ID_OUI_FROM_DATABASE=Shenzhen Herotel Tech. Co., Ltd. + +OUI:6851B7* + ID_OUI_FROM_DATABASE=PowerCloud Systems, Inc. + +OUI:6854ED* + ID_OUI_FROM_DATABASE=Alcatel-Lucent - Nuage + +OUI:6854F5* + ID_OUI_FROM_DATABASE=enLighted Inc + +OUI:68597F* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:685B35* + ID_OUI_FROM_DATABASE=Apple + +OUI:685B36* + ID_OUI_FROM_DATABASE=POWERTECH INDUSTRIAL CO., LTD. + +OUI:685D43* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:685E6B* + ID_OUI_FROM_DATABASE=PowerRay Co., Ltd. + +OUI:686359* + ID_OUI_FROM_DATABASE=Advanced Digital Broadcast SA + +OUI:68692E* + ID_OUI_FROM_DATABASE=Zycoo Co.,Ltd + +OUI:6869F2* + ID_OUI_FROM_DATABASE=ComAp s.r.o. + +OUI:686E23* + ID_OUI_FROM_DATABASE=Wi3 Inc. + +OUI:687251* + ID_OUI_FROM_DATABASE=Ubiquiti Networks + +OUI:68764F* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:687848* + ID_OUI_FROM_DATABASE=Westunitis Co., Ltd. + +OUI:68784C* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:687924* + ID_OUI_FROM_DATABASE=ELS-GmbH & Co. KG + +OUI:6879ED* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:687CC8* + ID_OUI_FROM_DATABASE=Measurement Systems S. de R.L. + +OUI:687CD5* + ID_OUI_FROM_DATABASE=Y Soft Corporation, a.s. + +OUI:687F74* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:68831A* + ID_OUI_FROM_DATABASE=Pandora Mobility Corporation + +OUI:688470* + ID_OUI_FROM_DATABASE=eSSys Co.,Ltd + +OUI:688540* + ID_OUI_FROM_DATABASE=IGI Mobile, Inc. + +OUI:68856A* + ID_OUI_FROM_DATABASE=OuterLink Corporation + +OUI:6886A7* + ID_OUI_FROM_DATABASE=Cisco + +OUI:6886E7* + ID_OUI_FROM_DATABASE=Orbotix, Inc. + +OUI:68876B* + ID_OUI_FROM_DATABASE=INQ Mobile Limited + +OUI:688AB5* + ID_OUI_FROM_DATABASE=EDP Servicos + +OUI:689234* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:689423* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:68967B* + ID_OUI_FROM_DATABASE=Apple + +OUI:68974B* + ID_OUI_FROM_DATABASE=Shenzhen Costar Electronics Co. Ltd. + +OUI:6897E8* + ID_OUI_FROM_DATABASE=Society of Motion Picture & Television Engineers + +OUI:689C5E* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:689C70* + ID_OUI_FROM_DATABASE=Apple + +OUI:68A1B7* + ID_OUI_FROM_DATABASE=Honghao Mingchuan Technology (Beijing) CO.,Ltd. + +OUI:68A3C4* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:68A40E* + ID_OUI_FROM_DATABASE=BSH Bosch and Siemens Home Appliances GmbH + +OUI:68A86D* + ID_OUI_FROM_DATABASE=Apple + +OUI:68AAD2* + ID_OUI_FROM_DATABASE=DATECS LTD., + +OUI:68AB8A* + ID_OUI_FROM_DATABASE=RF IDeas + +OUI:68AF13* + ID_OUI_FROM_DATABASE=Futura Mobility + +OUI:68B094* + ID_OUI_FROM_DATABASE=INESA ELECTRON CO.,LTD + +OUI:68B43A* + ID_OUI_FROM_DATABASE=WaterFurnace International, Inc. + +OUI:68B599* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:68B6FC* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:68B8D9* + ID_OUI_FROM_DATABASE=Act KDE, Inc. + +OUI:68BC0C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:68BDAB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:68CA00* + ID_OUI_FROM_DATABASE=Octopus Systems Limited + +OUI:68CC9C* + ID_OUI_FROM_DATABASE=Mine Site Technologies + +OUI:68CD0F* + ID_OUI_FROM_DATABASE=U Tek Company Limited + +OUI:68CE4E* + ID_OUI_FROM_DATABASE=L-3 Communications Infrared Products + +OUI:68D1FD* + ID_OUI_FROM_DATABASE=Shenzhen Trimax Technology Co.,Ltd + +OUI:68D247* + ID_OUI_FROM_DATABASE=Portalis LC + +OUI:68D925* + ID_OUI_FROM_DATABASE=ProSys Development Services + +OUI:68DB67* + ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd + +OUI:68DB96* + ID_OUI_FROM_DATABASE=OPWILL Technologies CO .,LTD + +OUI:68DCE8* + ID_OUI_FROM_DATABASE=PacketStorm Communications + +OUI:68E41F* + ID_OUI_FROM_DATABASE=Unglaube Identech GmbH + +OUI:68EBAE* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:68EBC5* + ID_OUI_FROM_DATABASE=Angstrem Telecom + +OUI:68EC62* + ID_OUI_FROM_DATABASE=YODO Technology Corp. Ltd. + +OUI:68ED43* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:68EE96* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:68EFBD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:68F125* + ID_OUI_FROM_DATABASE=Data Controls Inc. + +OUI:68F895* + ID_OUI_FROM_DATABASE=Redflow Limited + +OUI:68FB95* + ID_OUI_FROM_DATABASE=Generalplus Technology Inc. + +OUI:68FCB3* + ID_OUI_FROM_DATABASE=Next Level Security Systems, Inc. + +OUI:6C0460* + ID_OUI_FROM_DATABASE=RBH Access Technologies Inc. + +OUI:6C09D6* + ID_OUI_FROM_DATABASE=Digiquest Electronics LTD + +OUI:6C0E0D* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:6C0F6A* + ID_OUI_FROM_DATABASE=JDC Tech Co., Ltd. + +OUI:6C15F9* + ID_OUI_FROM_DATABASE=Nautronix Limited + +OUI:6C1811* + ID_OUI_FROM_DATABASE=Decatur Electronics + +OUI:6C2056* + ID_OUI_FROM_DATABASE=Cisco + +OUI:6C22AB* + ID_OUI_FROM_DATABASE=Ainsworth Game Technology + +OUI:6C23B9* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:6C2995* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:6C2E33* + ID_OUI_FROM_DATABASE=Accelink Technologies Co.,Ltd. + +OUI:6C2E85* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:6C32DE* + ID_OUI_FROM_DATABASE=Indieon Technologies Pvt. Ltd. + +OUI:6C33A9* + ID_OUI_FROM_DATABASE=Magicjack LP + +OUI:6C391D* + ID_OUI_FROM_DATABASE=Beijing ZhongHuaHun Network Information center + +OUI:6C3A84* + ID_OUI_FROM_DATABASE=Shenzhen Aero-Startech. Co.Ltd + +OUI:6C3BE5* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:6C3C53* + ID_OUI_FROM_DATABASE=SoundHawk Corp + +OUI:6C3E6D* + ID_OUI_FROM_DATABASE=Apple + +OUI:6C3E9C* + ID_OUI_FROM_DATABASE=KE Knestel Elektronik GmbH + +OUI:6C40C6* + ID_OUI_FROM_DATABASE=Nimbus Data Systems, Inc. + +OUI:6C416A* + ID_OUI_FROM_DATABASE=Cisco + +OUI:6C4B7F* + ID_OUI_FROM_DATABASE=Vossloh-Schwabe Deutschland GmbH + +OUI:6C504D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:6C5779* + ID_OUI_FROM_DATABASE=Aclima, Inc. + +OUI:6C5A34* + ID_OUI_FROM_DATABASE=Shenzhen Haitianxiong Electronic Co., Ltd. + +OUI:6C5AB5* + ID_OUI_FROM_DATABASE=TCL Technoly Electronics (Huizhou) Co., Ltd. + +OUI:6C5CDE* + ID_OUI_FROM_DATABASE=SunReports, Inc. + +OUI:6C5D63* + ID_OUI_FROM_DATABASE=ShenZhen Rapoo Technology Co., Ltd. + +OUI:6C5E7A* + ID_OUI_FROM_DATABASE=Ubiquitous Internet Telecom Co., Ltd + +OUI:6C5F1C* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:6C6126* + ID_OUI_FROM_DATABASE=Rinicom Holdings + +OUI:6C626D* + ID_OUI_FROM_DATABASE=Micro-Star INT'L CO., LTD + +OUI:6C641A* + ID_OUI_FROM_DATABASE=Penguin Computing + +OUI:6C6F18* + ID_OUI_FROM_DATABASE=Stereotaxis, Inc. + +OUI:6C7039* + ID_OUI_FROM_DATABASE=Novar GmbH + +OUI:6C709F* + ID_OUI_FROM_DATABASE=Apple + +OUI:6C71D9* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc + +OUI:6C81FE* + ID_OUI_FROM_DATABASE=Mitsuba Corporation + +OUI:6C8336* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:6C8366* + ID_OUI_FROM_DATABASE=Nanjing SAC Power Grid Automation Co., Ltd. + +OUI:6C8686* + ID_OUI_FROM_DATABASE=Technonia + +OUI:6C8814* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:6C8B2F* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:6C8CDB* + ID_OUI_FROM_DATABASE=Otus Technologies Ltd + +OUI:6C8D65* + ID_OUI_FROM_DATABASE=Wireless Glue Networks, Inc. + +OUI:6C90B1* + ID_OUI_FROM_DATABASE=SanLogic Inc + +OUI:6C92BF* + ID_OUI_FROM_DATABASE=Inspur Electronic Information Industry Co.,Ltd. + +OUI:6C98EB* + ID_OUI_FROM_DATABASE=Xyne GmbH + +OUI:6C9989* + ID_OUI_FROM_DATABASE=Cisco + +OUI:6C9AC9* + ID_OUI_FROM_DATABASE=Valentine Research, Inc. + +OUI:6C9B02* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:6C9CE9* + ID_OUI_FROM_DATABASE=Nimble Storage + +OUI:6C9CED* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:6CA682* + ID_OUI_FROM_DATABASE=EDAM information & communications + +OUI:6CA780* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:6CA906* + ID_OUI_FROM_DATABASE=Telefield Ltd + +OUI:6CA96F* + ID_OUI_FROM_DATABASE=TransPacket AS + +OUI:6CAB4D* + ID_OUI_FROM_DATABASE=Digital Payment Technologies + +OUI:6CAC60* + ID_OUI_FROM_DATABASE=Venetex Corp + +OUI:6CAD3F* + ID_OUI_FROM_DATABASE=Hubbell Building Automation, Inc. + +OUI:6CADEF* + ID_OUI_FROM_DATABASE=KZ Broadband Technologies, Ltd. + +OUI:6CADF8* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:6CAE8B* + ID_OUI_FROM_DATABASE=IBM Corporation + +OUI:6CB311* + ID_OUI_FROM_DATABASE=Shenzhen Lianrui Electronics Co.,Ltd + +OUI:6CB350* + ID_OUI_FROM_DATABASE=Anhui comhigher tech co.,ltd + +OUI:6CB7F4* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:6CBEE9* + ID_OUI_FROM_DATABASE=Alcatel-Lucent-IPD + +OUI:6CC1D2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:6CC26B* + ID_OUI_FROM_DATABASE=Apple + +OUI:6CD032* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:6CD146* + ID_OUI_FROM_DATABASE=Smartek d.o.o. + +OUI:6CD1B0* + ID_OUI_FROM_DATABASE=WING SING ELECTRONICS HONG KONG LIMITED + +OUI:6CD68A* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:6CDC6A* + ID_OUI_FROM_DATABASE=Promethean Limited + +OUI:6CE0B0* + ID_OUI_FROM_DATABASE=SOUND4 + +OUI:6CE4CE* + ID_OUI_FROM_DATABASE=Villiger Security Solutions AG + +OUI:6CE873* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:6CE907* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:6CE983* + ID_OUI_FROM_DATABASE=Gastron Co., LTD. + +OUI:6CECA1* + ID_OUI_FROM_DATABASE=SHENZHEN CLOU ELECTRONICS CO. LTD. + +OUI:6CF049* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:6CF373* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:6CF37F* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:6CF97C* + ID_OUI_FROM_DATABASE=Nanoptix Inc. + +OUI:6CFA58* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:6CFDB9* + ID_OUI_FROM_DATABASE=Proware Technologies Co Ltd. + +OUI:6CFFBE* + ID_OUI_FROM_DATABASE=MPB Communications Inc. + +OUI:700258* + ID_OUI_FROM_DATABASE=01DB-METRAVIB + +OUI:700514* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:700BC0* + ID_OUI_FROM_DATABASE=Dewav Technology Company + +OUI:700FEC* + ID_OUI_FROM_DATABASE=Poindus Systems Corp. + +OUI:70105C* + ID_OUI_FROM_DATABASE=Cisco + +OUI:701124* + ID_OUI_FROM_DATABASE=Apple + +OUI:701404* + ID_OUI_FROM_DATABASE=Limited Liability Company + +OUI:70188B* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:701A04* + ID_OUI_FROM_DATABASE=Liteon Tech Corp. + +OUI:701AED* + ID_OUI_FROM_DATABASE=ADVAS CO., LTD. + +OUI:701D7F* + ID_OUI_FROM_DATABASE=Comtech Technology Co., Ltd. + +OUI:702393* + ID_OUI_FROM_DATABASE=fos4X GmbH + +OUI:702526* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:702559* + ID_OUI_FROM_DATABASE=CyberTAN Technology, Inc. + +OUI:702B1D* + ID_OUI_FROM_DATABASE=E-Domus International Limited + +OUI:702C1F* + ID_OUI_FROM_DATABASE=Wisol + +OUI:702F4B* + ID_OUI_FROM_DATABASE=PolyVision Inc. + +OUI:702F97* + ID_OUI_FROM_DATABASE=Aava Mobile Oy + +OUI:703018* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:70305E* + ID_OUI_FROM_DATABASE=Nanjing Zhongke Menglian Information Technology Co.,LTD + +OUI:703187* + ID_OUI_FROM_DATABASE=ACX GmbH + +OUI:7032D5* + ID_OUI_FROM_DATABASE=Athena Wireless Communications Inc + +OUI:703811* + ID_OUI_FROM_DATABASE=Invensys Rail + +OUI:7038B4* + ID_OUI_FROM_DATABASE=Low Tech Solutions + +OUI:7038EE* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:703AD8* + ID_OUI_FROM_DATABASE=Shenzhen Afoundry Electronic Co., Ltd + +OUI:703C39* + ID_OUI_FROM_DATABASE=SEAWING Kft + +OUI:7041B7* + ID_OUI_FROM_DATABASE=Edwards Lifesciences LLC + +OUI:704642* + ID_OUI_FROM_DATABASE=CHYNG HONG ELECTRONIC CO., LTD. + +OUI:704AAE* + ID_OUI_FROM_DATABASE=Xstream Flow (Pty) Ltd + +OUI:704AE4* + ID_OUI_FROM_DATABASE=Rinstrum Pty Ltd + +OUI:704CED* + ID_OUI_FROM_DATABASE=TMRG, Inc. + +OUI:704E01* + ID_OUI_FROM_DATABASE=KWANGWON TECH CO., LTD. + +OUI:7052C5* + ID_OUI_FROM_DATABASE=Avaya, Inc. + +OUI:70533F* + ID_OUI_FROM_DATABASE=Alfa Instrumentos Eletronicos Ltda. + +OUI:7054D2* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:7054F5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:705681* + ID_OUI_FROM_DATABASE=Apple + +OUI:705812* + ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company + +OUI:705957* + ID_OUI_FROM_DATABASE=Medallion Instrumentation Systems + +OUI:705986* + ID_OUI_FROM_DATABASE=OOO TTV + +OUI:705AB6* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:705CAD* + ID_OUI_FROM_DATABASE=Konami Gaming Inc + +OUI:705EAA* + ID_OUI_FROM_DATABASE=Action Target, Inc. + +OUI:7060DE* + ID_OUI_FROM_DATABASE=LaVision GmbH + +OUI:706173* + ID_OUI_FROM_DATABASE=Calantec GmbH + +OUI:706417* + ID_OUI_FROM_DATABASE=ORBIS TECNOLOGIA ELECTRICA S.A. + +OUI:706582* + ID_OUI_FROM_DATABASE=Suzhou Hanming Technologies Co., Ltd. + +OUI:70704C* + ID_OUI_FROM_DATABASE=Purple Communications, Inc + +OUI:7071B3* + ID_OUI_FROM_DATABASE=Brain Corporation + +OUI:7071BC* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:70723C* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:7072CF* + ID_OUI_FROM_DATABASE=EdgeCore Networks + +OUI:7073CB* + ID_OUI_FROM_DATABASE=Apple + +OUI:707630* + ID_OUI_FROM_DATABASE=Pace plc. + +OUI:7076DD* + ID_OUI_FROM_DATABASE=Oxyguard International A/S + +OUI:7076F0* + ID_OUI_FROM_DATABASE=LevelOne Communications (India) Private Limited + +OUI:707BE8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:707C18* + ID_OUI_FROM_DATABASE=ADATA Technology Co., Ltd + +OUI:707E43* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:707EDE* + ID_OUI_FROM_DATABASE=NASTEC LTD. + +OUI:708105* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:70820E* + ID_OUI_FROM_DATABASE=as electronics GmbH + +OUI:70828E* + ID_OUI_FROM_DATABASE=OleumTech Corporation + +OUI:7085C6* + ID_OUI_FROM_DATABASE=Pace plc. + +OUI:708B78* + ID_OUI_FROM_DATABASE=citygrow technology co., ltd + +OUI:708D09* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:709383* + ID_OUI_FROM_DATABASE=Intelligent Optical Network High Tech CO.,LTD. + +OUI:7093F8* + ID_OUI_FROM_DATABASE=Space Monkey, Inc. + +OUI:709756* + ID_OUI_FROM_DATABASE=Happyelectronics Co.,Ltd + +OUI:709A0B* + ID_OUI_FROM_DATABASE=Italian Institute of Technology + +OUI:709BA5* + ID_OUI_FROM_DATABASE=Shenzhen Y&D Electronics Co.,LTD. + +OUI:709BFC* + ID_OUI_FROM_DATABASE=Bryton Inc. + +OUI:709E29* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:709E86* + ID_OUI_FROM_DATABASE=X6D Limited + +OUI:70A191* + ID_OUI_FROM_DATABASE=Trendsetter Medical, LLC + +OUI:70A41C* + ID_OUI_FROM_DATABASE=Advanced Wireless Dynamics S.L. + +OUI:70A66A* + ID_OUI_FROM_DATABASE=Prox Dynamics AS + +OUI:70A8E3* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:70AAB2* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:70B035* + ID_OUI_FROM_DATABASE=Shenzhen Zowee Technology Co., Ltd + +OUI:70B08C* + ID_OUI_FROM_DATABASE=Shenou Communication Equipment Co.,Ltd + +OUI:70B14E* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:70B265* + ID_OUI_FROM_DATABASE=Hiltron s.r.l. + +OUI:70B599* + ID_OUI_FROM_DATABASE=Embedded Technologies s.r.o. + +OUI:70B921* + ID_OUI_FROM_DATABASE=FiberHome Telecommunication Technologies CO.,LTD + +OUI:70C6AC* + ID_OUI_FROM_DATABASE=Bosch Automotive Aftermarket + +OUI:70CA9B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:70CD60* + ID_OUI_FROM_DATABASE=Apple + +OUI:70D4F2* + ID_OUI_FROM_DATABASE=RIM + +OUI:70D57E* + ID_OUI_FROM_DATABASE=Scalar Corporation + +OUI:70D5E7* + ID_OUI_FROM_DATABASE=Wellcore Corporation + +OUI:70D6B6* + ID_OUI_FROM_DATABASE=Metrum Technologies + +OUI:70D880* + ID_OUI_FROM_DATABASE=Upos System sp. z o.o. + +OUI:70DDA1* + ID_OUI_FROM_DATABASE=Tellabs + +OUI:70DEE2* + ID_OUI_FROM_DATABASE=Apple + +OUI:70E027* + ID_OUI_FROM_DATABASE=HONGYU COMMUNICATION TECHNOLOGY LIMITED + +OUI:70E139* + ID_OUI_FROM_DATABASE=3view Ltd + +OUI:70E24C* + ID_OUI_FROM_DATABASE=SAE IT-systems GmbH & Co. KG + +OUI:70E284* + ID_OUI_FROM_DATABASE=Wistron InfoComm(Zhongshan) Corporation + +OUI:70E843* + ID_OUI_FROM_DATABASE=Beijing C&W Optical Communication Technology Co.,Ltd. + +OUI:70EE50* + ID_OUI_FROM_DATABASE=Netatmo + +OUI:70F176* + ID_OUI_FROM_DATABASE=Data Modul AG + +OUI:70F1A1* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:70F1E5* + ID_OUI_FROM_DATABASE=Xetawave LLC + +OUI:70F395* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:70F927* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:70FF76* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:740ABC* + ID_OUI_FROM_DATABASE=JSJS Designs (Europe) Limited + +OUI:740EDB* + ID_OUI_FROM_DATABASE=Optowiz Co., Ltd + +OUI:741489* + ID_OUI_FROM_DATABASE=SRT Wireless + +OUI:7415E2* + ID_OUI_FROM_DATABASE=Tri-Sen Systems Corporation + +OUI:741E93* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:74258A* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:74273C* + ID_OUI_FROM_DATABASE=ChangYang Technology (Nanjing) Co., LTD + +OUI:7427EA* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. + +OUI:742B0F* + ID_OUI_FROM_DATABASE=Infinidat Ltd. + +OUI:742B62* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:742D0A* + ID_OUI_FROM_DATABASE=Norfolk Elektronik AG + +OUI:742F68* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:743170* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:743256* + ID_OUI_FROM_DATABASE=NT-ware Systemprg GmbH + +OUI:74372F* + ID_OUI_FROM_DATABASE=Tongfang Shenzhen Cloudcomputing Technology Co.,Ltd + +OUI:743889* + ID_OUI_FROM_DATABASE=ANNAX Anzeigesysteme GmbH + +OUI:743ECB* + ID_OUI_FROM_DATABASE=Gentrice tech + +OUI:744401* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:74458A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:7446A0* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:744BE9* + ID_OUI_FROM_DATABASE=EXPLORER HYPERTECH CO.,LTD + +OUI:744D79* + ID_OUI_FROM_DATABASE=Arrive Systems Inc. + +OUI:745327* + ID_OUI_FROM_DATABASE=COMMSEN CO., LIMITED + +OUI:745612* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:745798* + ID_OUI_FROM_DATABASE=TRUMPF Laser GmbH + Co. KG + +OUI:745E1C* + ID_OUI_FROM_DATABASE=PIONEER CORPORATION + +OUI:745F00* + ID_OUI_FROM_DATABASE=Samsung Semiconductor Inc. + +OUI:745FAE* + ID_OUI_FROM_DATABASE=TSL PPL + +OUI:7463DF* + ID_OUI_FROM_DATABASE=VTS GmbH + +OUI:7465D1* + ID_OUI_FROM_DATABASE=Atlinks + +OUI:746630* + ID_OUI_FROM_DATABASE=T:mi Ytti + +OUI:746A89* + ID_OUI_FROM_DATABASE=Rezolt Corporation + +OUI:746A8F* + ID_OUI_FROM_DATABASE=VS Vision Systems GmbH + +OUI:746B82* + ID_OUI_FROM_DATABASE=MOVEK + +OUI:746F3D* + ID_OUI_FROM_DATABASE=Contec GmbH + +OUI:7472F2* + ID_OUI_FROM_DATABASE=Chipsip Technology Co., Ltd. + +OUI:747818* + ID_OUI_FROM_DATABASE=ServiceAssure + +OUI:747B7A* + ID_OUI_FROM_DATABASE=ETH Inc. + +OUI:747DB6* + ID_OUI_FROM_DATABASE=Aliwei Communications, Inc + +OUI:747E1A* + ID_OUI_FROM_DATABASE=Red Embedded Design Limited + +OUI:747E2D* + ID_OUI_FROM_DATABASE=Beijing Thomson CITIC Digital Technology Co. LTD. + +OUI:74867A* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:74882A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:74888B* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:748E08* + ID_OUI_FROM_DATABASE=Bestek Corp. + +OUI:748EF8* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:748F1B* + ID_OUI_FROM_DATABASE=MasterImage 3D + +OUI:749050* + ID_OUI_FROM_DATABASE=Renesas Electronics Corporation + +OUI:74911A* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:7493A4* + ID_OUI_FROM_DATABASE=Zebra Technologies Corp. + +OUI:74943D* + ID_OUI_FROM_DATABASE=AgJunction + +OUI:749975* + ID_OUI_FROM_DATABASE=IBM Corporation + +OUI:749C52* + ID_OUI_FROM_DATABASE=Huizhou Desay SV Automotive Co., Ltd. + +OUI:749DDC* + ID_OUI_FROM_DATABASE=2Wire + +OUI:74A4A7* + ID_OUI_FROM_DATABASE=QRS Music Technologies, Inc. + +OUI:74A4B5* + ID_OUI_FROM_DATABASE=Powerleader Science and Technology Co. Ltd. + +OUI:74A722* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:74ADB7* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + +OUI:74AE76* + ID_OUI_FROM_DATABASE=iNovo Broadband, Inc. + +OUI:74B00C* + ID_OUI_FROM_DATABASE=Network Video Technologies, Inc + +OUI:74B9EB* + ID_OUI_FROM_DATABASE=Fujian JinQianMao Electronic Technology Co.,Ltd + +OUI:74BE08* + ID_OUI_FROM_DATABASE=ATEK Products, LLC + +OUI:74BFA1* + ID_OUI_FROM_DATABASE=HYUNTECK + +OUI:74C621* + ID_OUI_FROM_DATABASE=Zhejiang Hite Renewable Energy Co.,LTD + +OUI:74C99A* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:74CA25* + ID_OUI_FROM_DATABASE=Calxeda, Inc. + +OUI:74CD0C* + ID_OUI_FROM_DATABASE=Smith Myers Communications Ltd. + +OUI:74CE56* + ID_OUI_FROM_DATABASE=Packet Force Technology Limited Company + +OUI:74D02B* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:74D0DC* + ID_OUI_FROM_DATABASE=ERICSSON AB + +OUI:74D435* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:74D675* + ID_OUI_FROM_DATABASE=WYMA Tecnologia + +OUI:74D850* + ID_OUI_FROM_DATABASE=Evrisko Systems + +OUI:74DE2B* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:74E06E* + ID_OUI_FROM_DATABASE=Ergophone GmbH + +OUI:74E1B6* + ID_OUI_FROM_DATABASE=Apple + +OUI:74E2F5* + ID_OUI_FROM_DATABASE=Apple + +OUI:74E424* + ID_OUI_FROM_DATABASE=APISTE CORPORATION + +OUI:74E50B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:74E537* + ID_OUI_FROM_DATABASE=RADSPIN + +OUI:74E543* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:74E7C6* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:74EA3A* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co.,Ltd. + +OUI:74ECF1* + ID_OUI_FROM_DATABASE=Acumen + +OUI:74F06D* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc. + +OUI:74F07D* + ID_OUI_FROM_DATABASE=BnCOM Co.,Ltd + +OUI:74F102* + ID_OUI_FROM_DATABASE=Beijing HCHCOM Technology Co., Ltd + +OUI:74F612* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:74F726* + ID_OUI_FROM_DATABASE=Neuron Robotics + +OUI:74F85D* + ID_OUI_FROM_DATABASE=Berkeley Nucleonics Corp + +OUI:74FDA0* + ID_OUI_FROM_DATABASE=Compupal (Group) Corporation + +OUI:74FE48* + ID_OUI_FROM_DATABASE=ADVANTECH CO., LTD. + +OUI:74FF7D* + ID_OUI_FROM_DATABASE=Wren Sound Systems, LLC + +OUI:78028F* + ID_OUI_FROM_DATABASE=Adaptive Spectrum and Signal Alignment (ASSIA), Inc. + +OUI:780738* + ID_OUI_FROM_DATABASE=Z.U.K. Elzab S.A. + +OUI:781185* + ID_OUI_FROM_DATABASE=NBS Payment Solutions Inc. + +OUI:7812B8* + ID_OUI_FROM_DATABASE=ORANTEK LIMITED + +OUI:781881* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc. + +OUI:78192E* + ID_OUI_FROM_DATABASE=NASCENT Technology + +OUI:7819F7* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:781C5A* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:781DBA* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:781DFD* + ID_OUI_FROM_DATABASE=Jabil Inc + +OUI:781FDB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:78223D* + ID_OUI_FROM_DATABASE=Affirmed Networks + +OUI:782544* + ID_OUI_FROM_DATABASE=Omnima Limited + +OUI:7825AD* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. + +OUI:782BCB* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:782EEF* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:78303B* + ID_OUI_FROM_DATABASE=Stephen Technologies Co.,Limited + +OUI:7830E1* + ID_OUI_FROM_DATABASE=UltraClenz, LLC + +OUI:7831C1* + ID_OUI_FROM_DATABASE=Apple + +OUI:78324F* + ID_OUI_FROM_DATABASE=Millennium Group, Inc. + +OUI:783CE3* + ID_OUI_FROM_DATABASE=Kai-EE + +OUI:783D5B* + ID_OUI_FROM_DATABASE=TELNET Redes Inteligentes S.A. + +OUI:783E53* + ID_OUI_FROM_DATABASE=BSkyB Ltd + +OUI:783F15* + ID_OUI_FROM_DATABASE=EasySYNC Ltd. + +OUI:784405* + ID_OUI_FROM_DATABASE=FUJITU(HONG KONG) ELECTRONIC Co.,LTD. + +OUI:784476* + ID_OUI_FROM_DATABASE=Zioncom technology co.,ltd + +OUI:7845C4* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:7846C4* + ID_OUI_FROM_DATABASE=DAEHAP HYPER-TECH + +OUI:78471D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:78491D* + ID_OUI_FROM_DATABASE=The Will-Burt Company + +OUI:784B08* + ID_OUI_FROM_DATABASE=f.robotics acquisitions ltd + +OUI:784B87* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co.,Ltd. + +OUI:78510C* + ID_OUI_FROM_DATABASE=LiveU Ltd. + +OUI:78521A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:785262* + ID_OUI_FROM_DATABASE=Shenzhen Hojy Software Co., Ltd. + +OUI:78542E* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:785517* + ID_OUI_FROM_DATABASE=SankyuElectronics + +OUI:785712* + ID_OUI_FROM_DATABASE=Mobile Integration Workgroup + +OUI:78593E* + ID_OUI_FROM_DATABASE=RAFI GmbH & Co.KG + +OUI:78595E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:785968* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.,Ltd. + +OUI:785C72* + ID_OUI_FROM_DATABASE=Hioso Technology Co., Ltd. + +OUI:78617C* + ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO.,LTD + +OUI:7866AE* + ID_OUI_FROM_DATABASE=ZTEC Instruments, Inc. + +OUI:786A89* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:786C1C* + ID_OUI_FROM_DATABASE=Apple + +OUI:787F62* + ID_OUI_FROM_DATABASE=GiK mbH + +OUI:78818F* + ID_OUI_FROM_DATABASE=Server Racks Australia Pty Ltd + +OUI:78843C* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:7884EE* + ID_OUI_FROM_DATABASE=INDRA ESPACIO S.A. + +OUI:788973* + ID_OUI_FROM_DATABASE=CMC + +OUI:788C54* + ID_OUI_FROM_DATABASE=Eltek Technologies LTD + +OUI:788DF7* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:78929C* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:7898FD* + ID_OUI_FROM_DATABASE=Q9 Networks Inc. + +OUI:78995C* + ID_OUI_FROM_DATABASE=Nationz Technologies Inc + +OUI:789966* + ID_OUI_FROM_DATABASE=Musilab Electronics (DongGuan)Co.,Ltd. + +OUI:78998F* + ID_OUI_FROM_DATABASE=MEDILINE ITALIA SRL + +OUI:789ED0* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:789F4C* + ID_OUI_FROM_DATABASE=HOERBIGER Elektronik GmbH + +OUI:789F87* + ID_OUI_FROM_DATABASE=Siemens AG I IA PP PRM + +OUI:78A051* + ID_OUI_FROM_DATABASE=iiNet Labs Pty Ltd + +OUI:78A106* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:78A183* + ID_OUI_FROM_DATABASE=Advidia + +OUI:78A2A0* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:78A3E4* + ID_OUI_FROM_DATABASE=Apple + +OUI:78A504* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:78A5DD* + ID_OUI_FROM_DATABASE=Shenzhen Smarteye Digital Electronics Co., Ltd + +OUI:78A683* + ID_OUI_FROM_DATABASE=Precidata + +OUI:78A6BD* + ID_OUI_FROM_DATABASE=DAEYEON Control&Instrument Co,.Ltd + +OUI:78A714* + ID_OUI_FROM_DATABASE=Amphenol + +OUI:78A873* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:78AB60* + ID_OUI_FROM_DATABASE=ABB Australia + +OUI:78ABBB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:78ACC0* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:78AE0C* + ID_OUI_FROM_DATABASE=Far South Networks + +OUI:78B3CE* + ID_OUI_FROM_DATABASE=Elo touch solutions + +OUI:78B5D2* + ID_OUI_FROM_DATABASE=Ever Treasure Industrial Limited + +OUI:78B6C1* + ID_OUI_FROM_DATABASE=AOBO Telecom Co.,Ltd + +OUI:78B81A* + ID_OUI_FROM_DATABASE=INTER SALES A/S + +OUI:78BAD0* + ID_OUI_FROM_DATABASE=Shinybow Technology Co. Ltd. + +OUI:78BEB6* + ID_OUI_FROM_DATABASE=Enhanced Vision + +OUI:78BEBD* + ID_OUI_FROM_DATABASE=STULZ GmbH + +OUI:78C40E* + ID_OUI_FROM_DATABASE=H&D Wireless + +OUI:78C4AB* + ID_OUI_FROM_DATABASE=Shenzhen Runsil Technology Co.,Ltd + +OUI:78C5E5* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:78C6BB* + ID_OUI_FROM_DATABASE=Innovasic, Inc. + +OUI:78CA04* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:78CA39* + ID_OUI_FROM_DATABASE=Apple + +OUI:78CA5E* + ID_OUI_FROM_DATABASE=ELNO + +OUI:78CB33* + ID_OUI_FROM_DATABASE=DHC Software Co.,Ltd + +OUI:78CD8E* + ID_OUI_FROM_DATABASE=SMC Networks Inc + +OUI:78D004* + ID_OUI_FROM_DATABASE=Neousys Technology Inc. + +OUI:78D129* + ID_OUI_FROM_DATABASE=Vicos + +OUI:78D34F* + ID_OUI_FROM_DATABASE=Pace-O-Matic, Inc. + +OUI:78D38D* + ID_OUI_FROM_DATABASE=HONGKONG YUNLINK TECHNOLOGY LIMITED + +OUI:78D5B5* + ID_OUI_FROM_DATABASE=NAVIELEKTRO KY + +OUI:78D6F0* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics + +OUI:78D752* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:78D99F* + ID_OUI_FROM_DATABASE=NuCom HK Ltd. + +OUI:78DA6E* + ID_OUI_FROM_DATABASE=Cisco + +OUI:78DAB3* + ID_OUI_FROM_DATABASE=GBO Technology + +OUI:78DD08* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:78DDD6* + ID_OUI_FROM_DATABASE=c-scape + +OUI:78DEE4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:78E3B5* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:78E400* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:78E7D1* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:78E8B6* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:78EC22* + ID_OUI_FROM_DATABASE=Shanghai Qihui Telecom Technology Co., LTD + +OUI:78EC74* + ID_OUI_FROM_DATABASE=Kyland-USA + +OUI:78EF4C* + ID_OUI_FROM_DATABASE=Unetconvergence Co., Ltd. + +OUI:78F5E5* + ID_OUI_FROM_DATABASE=BEGA Gantenbrink-Leuchten KG + +OUI:78F5FD* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:78F7BE* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:78F7D0* + ID_OUI_FROM_DATABASE=Silverbrook Research + +OUI:78FE3D* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:78FE41* + ID_OUI_FROM_DATABASE=Socus networks + +OUI:78FEE2* + ID_OUI_FROM_DATABASE=Shanghai Diveo Technology Co., Ltd + +OUI:78FF57* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:7C0187* + ID_OUI_FROM_DATABASE=Curtis Instruments, Inc. + +OUI:7C02BC* + ID_OUI_FROM_DATABASE=Hansung Electronics Co. LTD + +OUI:7C034C* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:7C03D8* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:7C0507* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:7C051E* + ID_OUI_FROM_DATABASE=RAFAEL LTD. + +OUI:7C0623* + ID_OUI_FROM_DATABASE=Ultra Electronics, CIS + +OUI:7C08D9* + ID_OUI_FROM_DATABASE=Shanghai B-Star Technology Co + +OUI:7C092B* + ID_OUI_FROM_DATABASE=Bekey A/S + +OUI:7C0A50* + ID_OUI_FROM_DATABASE=J-MEX Inc. + +OUI:7C11BE* + ID_OUI_FROM_DATABASE=Apple + +OUI:7C1476* + ID_OUI_FROM_DATABASE=Damall Technologies SAS + +OUI:7C160D* + ID_OUI_FROM_DATABASE=Saia-Burgess Controls AG + +OUI:7C1A03* + ID_OUI_FROM_DATABASE=8Locations Co., Ltd. + +OUI:7C1AFC* + ID_OUI_FROM_DATABASE=Dalian Co-Edifice Video Technology Co., Ltd + +OUI:7C1E52* + ID_OUI_FROM_DATABASE=Microsoft + +OUI:7C1EB3* + ID_OUI_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +OUI:7C2048* + ID_OUI_FROM_DATABASE=KoamTac + +OUI:7C2064* + ID_OUI_FROM_DATABASE=Alcatel Lucent IPD + +OUI:7C2CF3* + ID_OUI_FROM_DATABASE=Secure Electrans Ltd + +OUI:7C2E0D* + ID_OUI_FROM_DATABASE=Blackmagic Design + +OUI:7C2F80* + ID_OUI_FROM_DATABASE=Gigaset Communications GmbH + +OUI:7C336E* + ID_OUI_FROM_DATABASE=MEG Electronics Inc. + +OUI:7C386C* + ID_OUI_FROM_DATABASE=Real Time Logic + +OUI:7C3920* + ID_OUI_FROM_DATABASE=SSOMA SECURITY + +OUI:7C3BD5* + ID_OUI_FROM_DATABASE=Imago Group + +OUI:7C3E9D* + ID_OUI_FROM_DATABASE=PATECH + +OUI:7C438F* + ID_OUI_FROM_DATABASE=E-Band Communications Corp. + +OUI:7C444C* + ID_OUI_FROM_DATABASE=Entertainment Solutions, S.L. + +OUI:7C49B9* + ID_OUI_FROM_DATABASE=Plexus Manufacturing Sdn Bhd + +OUI:7C4A82* + ID_OUI_FROM_DATABASE=Portsmith LLC + +OUI:7C4AA8* + ID_OUI_FROM_DATABASE=MindTree Wireless PVT Ltd + +OUI:7C4B78* + ID_OUI_FROM_DATABASE=Red Sun Synthesis Pte Ltd + +OUI:7C4C58* + ID_OUI_FROM_DATABASE=Scale Computing, Inc. + +OUI:7C4CA5* + ID_OUI_FROM_DATABASE=BSkyB Ltd + +OUI:7C4FB5* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:7C55E7* + ID_OUI_FROM_DATABASE=YSI, Inc. + +OUI:7C6097* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:7C6193* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:7C669D* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:7C69F6* + ID_OUI_FROM_DATABASE=Cisco + +OUI:7C6AB3* + ID_OUI_FROM_DATABASE=IBC TECHNOLOGIES INC. + +OUI:7C6ADB* + ID_OUI_FROM_DATABASE=SafeTone Technology Co.,Ltd + +OUI:7C6B33* + ID_OUI_FROM_DATABASE=Tenyu Tech Co. Ltd. + +OUI:7C6B52* + ID_OUI_FROM_DATABASE=Tigaro Wireless + +OUI:7C6C39* + ID_OUI_FROM_DATABASE=PIXSYS SRL + +OUI:7C6C8F* + ID_OUI_FROM_DATABASE=AMS NEVE LTD + +OUI:7C6D62* + ID_OUI_FROM_DATABASE=Apple + +OUI:7C6F06* + ID_OUI_FROM_DATABASE=Caterpillar Trimble Control Technologies + +OUI:7C6FF8* + ID_OUI_FROM_DATABASE=ShenZhen ACTO Digital Video Technology Co.,Ltd. + +OUI:7C72E4* + ID_OUI_FROM_DATABASE=Unikey Technologies + +OUI:7C7673* + ID_OUI_FROM_DATABASE=ENMAS GmbH + +OUI:7C7A91* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:7C7BE4* + ID_OUI_FROM_DATABASE=Z'SEDAI KENKYUSHO CORPORATION + +OUI:7C7D41* + ID_OUI_FROM_DATABASE=Jinmuyu Electronics Co., Ltd. + +OUI:7C822D* + ID_OUI_FROM_DATABASE=Nortec + +OUI:7C8306* + ID_OUI_FROM_DATABASE=Glen Dimplex Nordic as + +OUI:7C8D91* + ID_OUI_FROM_DATABASE=Shanghai Hongzhuo Information Technology co.,LTD + +OUI:7C8EE4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:7C94B2* + ID_OUI_FROM_DATABASE=Philips Healthcare PCCI + +OUI:7C95F3* + ID_OUI_FROM_DATABASE=Cisco + +OUI:7C9763* + ID_OUI_FROM_DATABASE=Openmatics s.r.o. + +OUI:7C9A9B* + ID_OUI_FROM_DATABASE=VSE valencia smart energy + +OUI:7CA15D* + ID_OUI_FROM_DATABASE=GN ReSound A/S + +OUI:7CA29B* + ID_OUI_FROM_DATABASE=D.SignT GmbH & Co. KG + +OUI:7CA61D* + ID_OUI_FROM_DATABASE=MHL, LLC + +OUI:7CACB2* + ID_OUI_FROM_DATABASE=Bosch Software Innovations GmbH + +OUI:7CAD74* + ID_OUI_FROM_DATABASE=Cisco + +OUI:7CB03E* + ID_OUI_FROM_DATABASE=OSRAM GmbH + +OUI:7CB21B* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:7CB232* + ID_OUI_FROM_DATABASE=TCL King High Frequency EI,Co.,LTD + +OUI:7CB542* + ID_OUI_FROM_DATABASE=ACES Technology + +OUI:7CB733* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP + +OUI:7CB77B* + ID_OUI_FROM_DATABASE=Paradigm Electronics Inc + +OUI:7CBB6F* + ID_OUI_FROM_DATABASE=Cosco Electronics Co., Ltd. + +OUI:7CBD06* + ID_OUI_FROM_DATABASE=AE REFUsol + +OUI:7CBF88* + ID_OUI_FROM_DATABASE=Mobilicom LTD + +OUI:7CBFB1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:7CC3A1* + ID_OUI_FROM_DATABASE=Apple + +OUI:7CC537* + ID_OUI_FROM_DATABASE=Apple + +OUI:7CC8AB* + ID_OUI_FROM_DATABASE=Acro Associates, Inc. + +OUI:7CC8D0* + ID_OUI_FROM_DATABASE=TIANJIN YAAN TECHNOLOGY CO., LTD. + +OUI:7CC8D7* + ID_OUI_FROM_DATABASE=Damalisk + +OUI:7CCB0D* + ID_OUI_FROM_DATABASE=Antaira Technologies, LLC + +OUI:7CCD11* + ID_OUI_FROM_DATABASE=MS-Magnet + +OUI:7CCD3C* + ID_OUI_FROM_DATABASE=Guangzhou Juzing Technology Co., Ltd + +OUI:7CCFCF* + ID_OUI_FROM_DATABASE=Shanghai SEARI Intelligent System Co., Ltd + +OUI:7CD1C3* + ID_OUI_FROM_DATABASE=Apple + +OUI:7CD762* + ID_OUI_FROM_DATABASE=Freestyle Technology Pty Ltd + +OUI:7CD844* + ID_OUI_FROM_DATABASE=Enmotus Inc + +OUI:7CD9FE* + ID_OUI_FROM_DATABASE=New Cosmos Electric Co., Ltd. + +OUI:7CDA84* + ID_OUI_FROM_DATABASE=Dongnian Networks Inc. + +OUI:7CDD11* + ID_OUI_FROM_DATABASE=Chongqing MAS SCI&TECH.Co.,Ltd + +OUI:7CDD20* + ID_OUI_FROM_DATABASE=IOXOS Technologies S.A. + +OUI:7CDD90* + ID_OUI_FROM_DATABASE=Shenzhen Ogemray Technology Co., Ltd. + +OUI:7CE044* + ID_OUI_FROM_DATABASE=NEON Inc + +OUI:7CE1FF* + ID_OUI_FROM_DATABASE=Computer Performance, Inc. DBA Digital Loggers, Inc. + +OUI:7CE56B* + ID_OUI_FROM_DATABASE=ESEN Optoelectronics Technology Co.,Ltd. + +OUI:7CE9D3* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:7CEBEA* + ID_OUI_FROM_DATABASE=ASCT + +OUI:7CED8D* + ID_OUI_FROM_DATABASE=MICROSOFT + +OUI:7CEF18* + ID_OUI_FROM_DATABASE=Creative Product Design Pty. Ltd. + +OUI:7CEF8A* + ID_OUI_FROM_DATABASE=Inhon International Ltd. + +OUI:7CF05F* + ID_OUI_FROM_DATABASE=Apple + +OUI:7CF098* + ID_OUI_FROM_DATABASE=Bee Beans Technologies, Inc. + +OUI:7CF0BA* + ID_OUI_FROM_DATABASE=Linkwell Telesystems Pvt Ltd + +OUI:7CF429* + ID_OUI_FROM_DATABASE=NUUO Inc. + +OUI:7CFADF* + ID_OUI_FROM_DATABASE=Apple + +OUI:7CFE28* + ID_OUI_FROM_DATABASE=Salutron Inc. + +OUI:7CFF62* + ID_OUI_FROM_DATABASE=Huizhou Super Electron Technology Co.,Ltd. + +OUI:80000B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:800010* + ID_OUI_FROM_DATABASE=ATT BELL LABORATORIES + +OUI:80006E* + ID_OUI_FROM_DATABASE=Apple + +OUI:8005DF* + ID_OUI_FROM_DATABASE=Montage Technology Group Limited + +OUI:8007A2* + ID_OUI_FROM_DATABASE=Esson Technology Inc. + +OUI:800A06* + ID_OUI_FROM_DATABASE=COMTEC co.,ltd + +OUI:801440* + ID_OUI_FROM_DATABASE=Sunlit System Technology Corp + +OUI:8016B7* + ID_OUI_FROM_DATABASE=Brunel University + +OUI:80177D* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:8018A7* + ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd + +OUI:801DAA* + ID_OUI_FROM_DATABASE=Avaya Inc + +OUI:801F02* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:8020AF* + ID_OUI_FROM_DATABASE=Trade FIDES, a.s. + +OUI:802275* + ID_OUI_FROM_DATABASE=Beijing Beny Wave Technology Co Ltd + +OUI:802AFA* + ID_OUI_FROM_DATABASE=Germaneers GmbH + +OUI:802DE1* + ID_OUI_FROM_DATABASE=Solarbridge Technologies + +OUI:802E14* + ID_OUI_FROM_DATABASE=azeti Networks AG + +OUI:802FDE* + ID_OUI_FROM_DATABASE=Zurich Instruments AG + +OUI:803457* + ID_OUI_FROM_DATABASE=OT Systems Limited + +OUI:8038FD* + ID_OUI_FROM_DATABASE=LeapFrog Enterprises, Inc. + +OUI:8039E5* + ID_OUI_FROM_DATABASE=PATLITE CORPORATION + +OUI:803B9A* + ID_OUI_FROM_DATABASE=ghe-ces electronic ag + +OUI:803F5D* + ID_OUI_FROM_DATABASE=Winstars Technology Ltd + +OUI:803FD6* + ID_OUI_FROM_DATABASE=bytes at work AG + +OUI:80427C* + ID_OUI_FROM_DATABASE=Adolf Tedsen GmbH & Co. KG + +OUI:804731* + ID_OUI_FROM_DATABASE=Packet Design, Inc. + +OUI:8048A5* + ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + +OUI:804971* + ID_OUI_FROM_DATABASE=Apple + +OUI:804B20* + ID_OUI_FROM_DATABASE=Ventilation Control + +OUI:804F58* + ID_OUI_FROM_DATABASE=ThinkEco, Inc. + +OUI:80501B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:8056F2* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:805719* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:8058C5* + ID_OUI_FROM_DATABASE=NovaTec Kommunikationstechnik GmbH + +OUI:8059FD* + ID_OUI_FROM_DATABASE=Noviga + +OUI:806007* + ID_OUI_FROM_DATABASE=RIM + +OUI:80618F* + ID_OUI_FROM_DATABASE=Shenzhen sangfei consumer communications co.,ltd + +OUI:806459* + ID_OUI_FROM_DATABASE=Nimbus Inc. + +OUI:8065E9* + ID_OUI_FROM_DATABASE=BenQ Corporation + +OUI:806629* + ID_OUI_FROM_DATABASE=Prescope Technologies CO.,LTD. + +OUI:806C8B* + ID_OUI_FROM_DATABASE=KAESER KOMPRESSOREN AG + +OUI:806CBC* + ID_OUI_FROM_DATABASE=NET New Electronic Technology GmbH + +OUI:80711F* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:807693* + ID_OUI_FROM_DATABASE=Newag SA + +OUI:8079AE* + ID_OUI_FROM_DATABASE=ShanDong Tecsunrise Co.,Ltd + +OUI:807A7F* + ID_OUI_FROM_DATABASE=ABB Genway Xiamen Electrical Equipment CO., LTD + +OUI:807B1E* + ID_OUI_FROM_DATABASE=Corsair Components + +OUI:807D1B* + ID_OUI_FROM_DATABASE=Neosystem Co. Ltd. + +OUI:807DE3* + ID_OUI_FROM_DATABASE=Chongqing Sichuan Instrument Microcircuit Co.LTD. + +OUI:8081A5* + ID_OUI_FROM_DATABASE=TONGQING COMMUNICATION EQUIPMENT (SHENZHEN) Co.,Ltd + +OUI:808287* + ID_OUI_FROM_DATABASE=ATCOM Technology Co.Ltd. + +OUI:808698* + ID_OUI_FROM_DATABASE=Netronics Technologies Inc. + +OUI:8086F2* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:808B5C* + ID_OUI_FROM_DATABASE=Shenzhen Runhuicheng Technology Co., Ltd + +OUI:80912A* + ID_OUI_FROM_DATABASE=Lih Rong electronic Enterprise Co., Ltd. + +OUI:8091C0* + ID_OUI_FROM_DATABASE=AgileMesh, Inc. + +OUI:80929F* + ID_OUI_FROM_DATABASE=Apple + +OUI:809393* + ID_OUI_FROM_DATABASE=Xapt GmbH + +OUI:80946C* + ID_OUI_FROM_DATABASE=TOKYO RADAR CORPORATION + +OUI:8096B1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:80971B* + ID_OUI_FROM_DATABASE=Altenergy Power System,Inc. + +OUI:809B20* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:80A1D7* + ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co.,Ltd + +OUI:80AAA4* + ID_OUI_FROM_DATABASE=USAG + +OUI:80B219* + ID_OUI_FROM_DATABASE=ELEKTRON TECHNOLOGY UK LIMITED + +OUI:80B289* + ID_OUI_FROM_DATABASE=Forworld Electronics Ltd. + +OUI:80B32A* + ID_OUI_FROM_DATABASE=Alstom Grid + +OUI:80B686* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:80B95C* + ID_OUI_FROM_DATABASE=ELFTECH Co., Ltd. + +OUI:80BAAC* + ID_OUI_FROM_DATABASE=TeleAdapt Ltd + +OUI:80BAE6* + ID_OUI_FROM_DATABASE=Neets + +OUI:80BBEB* + ID_OUI_FROM_DATABASE=Satmap Systems Ltd + +OUI:80C16E* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:80C63F* + ID_OUI_FROM_DATABASE=Remec Broadband Wireless , LLC + +OUI:80C6AB* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:80C6CA* + ID_OUI_FROM_DATABASE=Endian s.r.l. + +OUI:80C862* + ID_OUI_FROM_DATABASE=Openpeak, Inc + +OUI:80CEB1* + ID_OUI_FROM_DATABASE=Theissen Training Systems GmbH + +OUI:80CF41* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:80D019* + ID_OUI_FROM_DATABASE=Embed, Inc + +OUI:80D18B* + ID_OUI_FROM_DATABASE=Hangzhou I'converge Technology Co.,Ltd + +OUI:80D433* + ID_OUI_FROM_DATABASE=LzLabs GmbH + +OUI:80D733* + ID_OUI_FROM_DATABASE=QSR Automations, Inc. + +OUI:80DB31* + ID_OUI_FROM_DATABASE=Power Quotient International Co., Ltd. + +OUI:80EA96* + ID_OUI_FROM_DATABASE=Apple + +OUI:80EE73* + ID_OUI_FROM_DATABASE=Shuttle Inc. + +OUI:80F25E* + ID_OUI_FROM_DATABASE=Kyynel + +OUI:80F593* + ID_OUI_FROM_DATABASE=IRCO Sistemas de Telecomunicación S.A. + +OUI:80F62E* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:80FA5B* + ID_OUI_FROM_DATABASE=CLEVO CO. + +OUI:80FB06* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:80FFA8* + ID_OUI_FROM_DATABASE=UNIDIS + +OUI:8400D2* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:840B2D* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD + +OUI:840F45* + ID_OUI_FROM_DATABASE=Shanghai GMT Digital Technologies Co., Ltd + +OUI:841715* + ID_OUI_FROM_DATABASE=GP Electronics (HK) Ltd. + +OUI:841766* + ID_OUI_FROM_DATABASE=Weifang GoerTek Electronics Co., Ltd + +OUI:841888* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:841B38* + ID_OUI_FROM_DATABASE=Shenzhen Excelsecu Data Technology Co.,Ltd + +OUI:841B5E* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:841E26* + ID_OUI_FROM_DATABASE=KERNEL-I Co.,LTD + +OUI:842141* + ID_OUI_FROM_DATABASE=Shenzhen Ginwave Technologies Ltd. + +OUI:84248D* + ID_OUI_FROM_DATABASE=Motorola Solutions Inc + +OUI:84253F* + ID_OUI_FROM_DATABASE=Silex Technology, Inc + +OUI:8425A4* + ID_OUI_FROM_DATABASE=Tariox Limited + +OUI:8425DB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:842615* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:84262B* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:8427CE* + ID_OUI_FROM_DATABASE=Corporation of the Presiding Bishop of The Church of Jesus Christ of Latter-day Saints + +OUI:842914* + ID_OUI_FROM_DATABASE=EMPORIA TELECOM Produktions- und VertriebsgesmbH & Co KG + +OUI:842999* + ID_OUI_FROM_DATABASE=Apple + +OUI:842B2B* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:842B50* + ID_OUI_FROM_DATABASE=Huria Co.,Ltd. + +OUI:842BBC* + ID_OUI_FROM_DATABASE=Modelleisenbahn GmbH + +OUI:842F75* + ID_OUI_FROM_DATABASE=Innokas Group + +OUI:8430E5* + ID_OUI_FROM_DATABASE=SkyHawke Technologies, LLC + +OUI:843497* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:843611* + ID_OUI_FROM_DATABASE=hyungseul publishing networks + +OUI:843835* + ID_OUI_FROM_DATABASE=Apple + +OUI:843A4B* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:843F4E* + ID_OUI_FROM_DATABASE=Tri-Tech Manufacturing, Inc. + +OUI:844823* + ID_OUI_FROM_DATABASE=WOXTER TECHNOLOGY Co. Ltd + +OUI:844915* + ID_OUI_FROM_DATABASE=vArmour Networks, Inc. + +OUI:844BF5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:844F03* + ID_OUI_FROM_DATABASE=Ablelink Electronics Ltd + +OUI:845181* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:84569C* + ID_OUI_FROM_DATABASE=Coho Data, Inc., + +OUI:845787* + ID_OUI_FROM_DATABASE=DVR C&C Co., Ltd. + +OUI:845C93* + ID_OUI_FROM_DATABASE=Chabrier Services + +OUI:845DD7* + ID_OUI_FROM_DATABASE=Shenzhen Netcom Electronics Co.,Ltd + +OUI:846223* + ID_OUI_FROM_DATABASE=Shenzhen Coship Electronics Co., Ltd. + +OUI:8462A6* + ID_OUI_FROM_DATABASE=EuroCB (Phils), Inc. + +OUI:846AED* + ID_OUI_FROM_DATABASE=Wireless Tsukamoto.,co.LTD + +OUI:846EB1* + ID_OUI_FROM_DATABASE=Park Assist LLC + +OUI:847207* + ID_OUI_FROM_DATABASE=I&C Technology + +OUI:84742A* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:847616* + ID_OUI_FROM_DATABASE=Addat S.r.o. + +OUI:8478AC* + ID_OUI_FROM_DATABASE=Cisco + +OUI:847A88* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:847E40* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:8482F4* + ID_OUI_FROM_DATABASE=Beijing Huasun Unicreate Technology Co., Ltd + +OUI:848336* + ID_OUI_FROM_DATABASE=Newrun + +OUI:848371* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:848433* + ID_OUI_FROM_DATABASE=Paradox Engineering SA + +OUI:848506* + ID_OUI_FROM_DATABASE=Apple + +OUI:848D84* + ID_OUI_FROM_DATABASE=Rajant Corporation + +OUI:848E0C* + ID_OUI_FROM_DATABASE=Apple + +OUI:848E96* + ID_OUI_FROM_DATABASE=Embertec Pty Ltd + +OUI:848F69* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:849000* + ID_OUI_FROM_DATABASE=Arnold & Richter Cine Technik + +OUI:8497B8* + ID_OUI_FROM_DATABASE=Memjet Inc. + +OUI:849CA6* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:849DC5* + ID_OUI_FROM_DATABASE=Centera Photonics Inc. + +OUI:84A6C8* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:84A783* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:84A8E4* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:84A991* + ID_OUI_FROM_DATABASE=Cyber Trans Japan Co.,Ltd. + +OUI:84ACA4* + ID_OUI_FROM_DATABASE=Beijing Novel Super Digital TV Technology Co., Ltd + +OUI:84AF1F* + ID_OUI_FROM_DATABASE=Beat System Service Co,. Ltd. + +OUI:84B59C* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:84C2E4* + ID_OUI_FROM_DATABASE=Jiangsu Qinheng Co., Ltd. + +OUI:84C727* + ID_OUI_FROM_DATABASE=Gnodal Ltd + +OUI:84C7A9* + ID_OUI_FROM_DATABASE=C3PO S.A. + +OUI:84C8B1* + ID_OUI_FROM_DATABASE=Incognito Software Inc. + +OUI:84C9B2* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:84D32A* + ID_OUI_FROM_DATABASE=IEEE 1905.1 + +OUI:84D9C8* + ID_OUI_FROM_DATABASE=Unipattern Co., + +OUI:84DB2F* + ID_OUI_FROM_DATABASE=Sierra Wireless Inc + +OUI:84DD20* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:84DE3D* + ID_OUI_FROM_DATABASE=Crystal Vision Ltd + +OUI:84DF0C* + ID_OUI_FROM_DATABASE=NET2GRID BV + +OUI:84E4D9* + ID_OUI_FROM_DATABASE=Shenzhen NEED technology Ltd. + +OUI:84E629* + ID_OUI_FROM_DATABASE=Bluwan SA + +OUI:84E714* + ID_OUI_FROM_DATABASE=Liang Herng Enterprise,Co.Ltd. + +OUI:84EA99* + ID_OUI_FROM_DATABASE=Vieworks + +OUI:84ED33* + ID_OUI_FROM_DATABASE=BBMC Co.,Ltd + +OUI:84F493* + ID_OUI_FROM_DATABASE=OMS spol. s.r.o. + +OUI:84F64C* + ID_OUI_FROM_DATABASE=Cross Point BV + +OUI:84FCFE* + ID_OUI_FROM_DATABASE=Apple + +OUI:84FE9E* + ID_OUI_FROM_DATABASE=RTC Industries, Inc. + +OUI:880355* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corp. + +OUI:880905* + ID_OUI_FROM_DATABASE=MTMCommunications + +OUI:880FB6* + ID_OUI_FROM_DATABASE=Jabil Circuits India Pvt Ltd,-EHTP unit + +OUI:881036* + ID_OUI_FROM_DATABASE=Panodic(ShenZhen) Electronics Limted + +OUI:88124E* + ID_OUI_FROM_DATABASE=Qualcomm Atheros + +OUI:88142B* + ID_OUI_FROM_DATABASE=Protonic Holland + +OUI:881544* + ID_OUI_FROM_DATABASE=Meraki, Inc. + +OUI:8818AE* + ID_OUI_FROM_DATABASE=Tamron Co., Ltd + +OUI:881FA1* + ID_OUI_FROM_DATABASE=Apple + +OUI:882012* + ID_OUI_FROM_DATABASE=LMI Technologies + +OUI:8821E3* + ID_OUI_FROM_DATABASE=Nebusens, S.L. + +OUI:882364* + ID_OUI_FROM_DATABASE=Watchnet DVR Inc + +OUI:8823FE* + ID_OUI_FROM_DATABASE=TTTech Computertechnik AG + +OUI:88252C* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:882E5A* + ID_OUI_FROM_DATABASE=storONE + +OUI:88308A* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:88329B* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:883314* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:88354C* + ID_OUI_FROM_DATABASE=Transics + +OUI:883612* + ID_OUI_FROM_DATABASE=SRC Computers, LLC + +OUI:8841C1* + ID_OUI_FROM_DATABASE=ORBISAT DA AMAZONIA IND E AEROL SA + +OUI:8841FC* + ID_OUI_FROM_DATABASE=AirTies Wireless Netowrks + +OUI:8843E1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:8844F6* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:88462A* + ID_OUI_FROM_DATABASE=Telechips Inc. + +OUI:884B39* + ID_OUI_FROM_DATABASE=Siemens AG, Healthcare Sector + +OUI:8851FB* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:88532E* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:885395* + ID_OUI_FROM_DATABASE=Apple + +OUI:8853D4* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:88576D* + ID_OUI_FROM_DATABASE=XTA Electronics Ltd + +OUI:885A92* + ID_OUI_FROM_DATABASE=Cisco + +OUI:885C4F* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:88615A* + ID_OUI_FROM_DATABASE=Siano Mobile Silicon Ltd. + +OUI:88685C* + ID_OUI_FROM_DATABASE=Shenzhen ChuangDao & Perpetual Eternal Technology Co.,Ltd + +OUI:886B76* + ID_OUI_FROM_DATABASE=CHINA HOPEFUL GROUP HOPEFUL ELECTRIC CO.,LTD + +OUI:887398* + ID_OUI_FROM_DATABASE=K2E Tekpoint + +OUI:887556* + ID_OUI_FROM_DATABASE=Cisco + +OUI:88789C* + ID_OUI_FROM_DATABASE=Game Technologies SA + +OUI:888603* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:8886A0* + ID_OUI_FROM_DATABASE=Simton Technologies, Ltd. + +OUI:888717* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:8887DD* + ID_OUI_FROM_DATABASE=DarbeeVision Inc. + +OUI:888914* + ID_OUI_FROM_DATABASE=All Components Incorporated + +OUI:888964* + ID_OUI_FROM_DATABASE=GSI Electronics Inc. + +OUI:888B5D* + ID_OUI_FROM_DATABASE=Storage Appliance Corporation + +OUI:888C19* + ID_OUI_FROM_DATABASE=Brady Corp Asia Pacific Ltd + +OUI:889166* + ID_OUI_FROM_DATABASE=Viewcooper Corp. + +OUI:8891DD* + ID_OUI_FROM_DATABASE=Racktivity + +OUI:889471* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:8894F9* + ID_OUI_FROM_DATABASE=Gemicom Technology, Inc. + +OUI:8895B9* + ID_OUI_FROM_DATABASE=Unified Packet Systems Crop + +OUI:889676* + ID_OUI_FROM_DATABASE=TTC MARCONI s.r.o. + +OUI:8897DF* + ID_OUI_FROM_DATABASE=Entrypass Corporation Sdn. Bhd. + +OUI:889821* + ID_OUI_FROM_DATABASE=TERAON + +OUI:889B39* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:889CA6* + ID_OUI_FROM_DATABASE=BTB Korea INC + +OUI:889FFA* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:88A3CC* + ID_OUI_FROM_DATABASE=Amatis Controls + +OUI:88A5BD* + ID_OUI_FROM_DATABASE=QPCOM INC. + +OUI:88A73C* + ID_OUI_FROM_DATABASE=Ragentek Technology Group + +OUI:88ACC1* + ID_OUI_FROM_DATABASE=Generiton Co., Ltd. + +OUI:88AE1D* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION(KUNSHAN)CO.,LTD + +OUI:88B168* + ID_OUI_FROM_DATABASE=Delta Control GmbH + +OUI:88B627* + ID_OUI_FROM_DATABASE=Gembird Europe BV + +OUI:88BA7F* + ID_OUI_FROM_DATABASE=Qfiednet Co., Ltd. + +OUI:88BFD5* + ID_OUI_FROM_DATABASE=Simple Audio Ltd + +OUI:88C36E* + ID_OUI_FROM_DATABASE=Beijing Ereneben lnformation Technology Limited + +OUI:88C626* + ID_OUI_FROM_DATABASE=Logitech - Ultimate Ears + +OUI:88C663* + ID_OUI_FROM_DATABASE=Apple + +OUI:88CB87* + ID_OUI_FROM_DATABASE=Apple + +OUI:88D7BC* + ID_OUI_FROM_DATABASE=DEP Company + +OUI:88D962* + ID_OUI_FROM_DATABASE=Canopus Systems US LLC + +OUI:88DC96* + ID_OUI_FROM_DATABASE=SENAO Networks, Inc. + +OUI:88DD79* + ID_OUI_FROM_DATABASE=Voltaire + +OUI:88E0A0* + ID_OUI_FROM_DATABASE=Shenzhen VisionSTOR Technologies Co., Ltd + +OUI:88E0F3* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:88E3AB* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:88E712* + ID_OUI_FROM_DATABASE=Whirlpool Corporation + +OUI:88E7A6* + ID_OUI_FROM_DATABASE=iKnowledge Integration Corp. + +OUI:88E8F8* + ID_OUI_FROM_DATABASE=YONG TAI ELECTRONIC (DONGGUAN) LTD. + +OUI:88E917* + ID_OUI_FROM_DATABASE=Tamaggo + +OUI:88ED1C* + ID_OUI_FROM_DATABASE=Cudo Communication Co., Ltd. + +OUI:88F077* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:88F488* + ID_OUI_FROM_DATABASE=cellon communications technology(shenzhen)Co.,Ltd. + +OUI:88F490* + ID_OUI_FROM_DATABASE=Jetmobile Pte Ltd + +OUI:88F7C7* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:88FD15* + ID_OUI_FROM_DATABASE=LINEEYE CO., LTD + +OUI:88FED6* + ID_OUI_FROM_DATABASE=ShangHai WangYong Software Co., Ltd. + +OUI:8C006D* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C04FF* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:8C078C* + ID_OUI_FROM_DATABASE=FLOW DATA INC + +OUI:8C088B* + ID_OUI_FROM_DATABASE=Remote Solution + +OUI:8C09F4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:8C0C90* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:8C0CA3* + ID_OUI_FROM_DATABASE=Amper + +OUI:8C0EE3* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD. + +OUI:8C11CB* + ID_OUI_FROM_DATABASE=ABUS Security-Center GmbH & Co. KG + +OUI:8C1F94* + ID_OUI_FROM_DATABASE=RF Surgical System Inc. + +OUI:8C210A* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:8C271D* + ID_OUI_FROM_DATABASE=QuantHouse + +OUI:8C278A* + ID_OUI_FROM_DATABASE=Vocollect Inc + +OUI:8C2937* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C2DAA* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C2F39* + ID_OUI_FROM_DATABASE=IBA Dosimetry GmbH + +OUI:8C3330* + ID_OUI_FROM_DATABASE=EmFirst Co., Ltd. + +OUI:8C3AE3* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:8C3C07* + ID_OUI_FROM_DATABASE=Skiva Technologies, Inc. + +OUI:8C3C4A* + ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC. + +OUI:8C41F2* + ID_OUI_FROM_DATABASE=RDA Technologies Ltd. + +OUI:8C4435* + ID_OUI_FROM_DATABASE=Shanghai BroadMobi Communication Technology Co., Ltd. + +OUI:8C4AEE* + ID_OUI_FROM_DATABASE=GIGA TMS INC + +OUI:8C4B59* + ID_OUI_FROM_DATABASE=3D Imaging & Simulations Corp + +OUI:8C4CDC* + ID_OUI_FROM_DATABASE=PLANEX COMMUNICATIONS INC. + +OUI:8C4DB9* + ID_OUI_FROM_DATABASE=Unmonday Ltd + +OUI:8C4DEA* + ID_OUI_FROM_DATABASE=Cerio Corporation + +OUI:8C5105* + ID_OUI_FROM_DATABASE=Shenzhen ireadygo Information Technology CO.,LTD. + +OUI:8C53F7* + ID_OUI_FROM_DATABASE=A&D ENGINEERING CO., LTD. + +OUI:8C541D* + ID_OUI_FROM_DATABASE=LGE + +OUI:8C569D* + ID_OUI_FROM_DATABASE=Imaging Solutions Group + +OUI:8C56C5* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:8C57FD* + ID_OUI_FROM_DATABASE=LVX Western + +OUI:8C5877* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C598B* + ID_OUI_FROM_DATABASE=C Technologies AB + +OUI:8C5AF0* + ID_OUI_FROM_DATABASE=Exeltech Solar Products + +OUI:8C5CA1* + ID_OUI_FROM_DATABASE=d-broad,INC + +OUI:8C5FDF* + ID_OUI_FROM_DATABASE=Beijing Railway Signal Factory + +OUI:8C604F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:8C640B* + ID_OUI_FROM_DATABASE=Beyond Devices d.o.o. + +OUI:8C6422* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:8C6878* + ID_OUI_FROM_DATABASE=Nortek-AS + +OUI:8C6AE4* + ID_OUI_FROM_DATABASE=Viogem Limited + +OUI:8C705A* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:8C71F8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:8C736E* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:8C76C1* + ID_OUI_FROM_DATABASE=Goden Tech Limited + +OUI:8C7712* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:8C7716* + ID_OUI_FROM_DATABASE=LONGCHEER TELECOMMUNICATION LIMITED + +OUI:8C7B9D* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C7C92* + ID_OUI_FROM_DATABASE=Apple + +OUI:8C7CB5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:8C7CFF* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:8C7EB3* + ID_OUI_FROM_DATABASE=Lytro, Inc. + +OUI:8C82A8* + ID_OUI_FROM_DATABASE=Insigma Technology Co.,Ltd + +OUI:8C89A5* + ID_OUI_FROM_DATABASE=Micro-Star INT'L CO., LTD + +OUI:8C8A6E* + ID_OUI_FROM_DATABASE=ESTUN AUTOMATION TECHNOLOY CO., LTD + +OUI:8C8E76* + ID_OUI_FROM_DATABASE=taskit GmbH + +OUI:8C90D3* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:8C9236* + ID_OUI_FROM_DATABASE=Aus.Linx Technology Co., Ltd. + +OUI:8C94CF* + ID_OUI_FROM_DATABASE=Encell Technology, Inc. + +OUI:8CA048* + ID_OUI_FROM_DATABASE=Beijing NeTopChip Technology Co.,LTD + +OUI:8CA982* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:8CAE4C* + ID_OUI_FROM_DATABASE=Plugable Technologies + +OUI:8CAE89* + ID_OUI_FROM_DATABASE=Y-cam Solutions Ltd + +OUI:8CB64F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:8CB7F7* + ID_OUI_FROM_DATABASE=Shenzhen UniStrong Science & Technology Co., Ltd + +OUI:8CB82C* + ID_OUI_FROM_DATABASE=IPitomy Communications + +OUI:8CB864* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:8CBEBE* + ID_OUI_FROM_DATABASE=Xiaomi Technology Co.,Ltd + +OUI:8CC121* + ID_OUI_FROM_DATABASE=Panasonic Corporation AVC Networks Company + +OUI:8CC5E1* + ID_OUI_FROM_DATABASE=ShenZhen Konka Telecommunication Technology Co.,Ltd + +OUI:8CC7AA* + ID_OUI_FROM_DATABASE=Radinet Communications Inc. + +OUI:8CC7D0* + ID_OUI_FROM_DATABASE=zhejiang ebang communication co.,ltd + +OUI:8CC8CD* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:8CCDA2* + ID_OUI_FROM_DATABASE=ACTP, Inc. + +OUI:8CCDE8* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:8CCF5C* + ID_OUI_FROM_DATABASE=BEFEGA GmbH + +OUI:8CD17B* + ID_OUI_FROM_DATABASE=CG Mobile + +OUI:8CD3A2* + ID_OUI_FROM_DATABASE=VisSim AS + +OUI:8CD628* + ID_OUI_FROM_DATABASE=Ikor Metering + +OUI:8CDB25* + ID_OUI_FROM_DATABASE=ESG Solutions + +OUI:8CDD8D* + ID_OUI_FROM_DATABASE=Wifly-City System Inc. + +OUI:8CDE52* + ID_OUI_FROM_DATABASE=ISSC Technologies Corp. + +OUI:8CDE99* + ID_OUI_FROM_DATABASE=Comlab Inc. + +OUI:8CE081* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:8CE7B3* + ID_OUI_FROM_DATABASE=Sonardyne International Ltd + +OUI:8CEEC6* + ID_OUI_FROM_DATABASE=Precepscion Pty. Ltd. + +OUI:8CF945* + ID_OUI_FROM_DATABASE=Power Automation pte Ltd + +OUI:8CF9C9* + ID_OUI_FROM_DATABASE=MESADA Technology Co.,Ltd. + +OUI:8CFABA* + ID_OUI_FROM_DATABASE=Apple + +OUI:8CFDF0* + ID_OUI_FROM_DATABASE=QUALCOMM Incorporated + +OUI:90004E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:90013B* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:90028A* + ID_OUI_FROM_DATABASE=Shenzhen Shidean Legrand Electronic Products Co.,Ltd + +OUI:9002A9* + ID_OUI_FROM_DATABASE=ZHEJIANG DAHUA TECHNOLOGY CO.,LTD + +OUI:9003B7* + ID_OUI_FROM_DATABASE=PARROT + +OUI:900917* + ID_OUI_FROM_DATABASE=Far-sighted mobile + +OUI:900A3A* + ID_OUI_FROM_DATABASE=PSG Plastic Service GmbH + +OUI:900D66* + ID_OUI_FROM_DATABASE=Digimore Electronics Co., Ltd + +OUI:900DCB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:90185E* + ID_OUI_FROM_DATABASE=Apex Tool Group GmbH & Co OHG + +OUI:90187C* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. + +OUI:9018AE* + ID_OUI_FROM_DATABASE=Shanghai Meridian Technologies, Co. Ltd. + +OUI:901900* + ID_OUI_FROM_DATABASE=SCS SA + +OUI:901ACA* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:901B0E* + ID_OUI_FROM_DATABASE=Fujitsu Technology Solutions GmbH + +OUI:901D27* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:901EDD* + ID_OUI_FROM_DATABASE=GREAT COMPUTER CORPORATION + +OUI:902083* + ID_OUI_FROM_DATABASE=General Engine Management Systems Ltd. + +OUI:902155* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:9027E4* + ID_OUI_FROM_DATABASE=Apple + +OUI:902B34* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:902E87* + ID_OUI_FROM_DATABASE=LabJack + +OUI:9031CD* + ID_OUI_FROM_DATABASE=Onyx Healthcare Inc. + +OUI:90342B* + ID_OUI_FROM_DATABASE=Gatekeeper Systems, Inc. + +OUI:9034FC* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:90356E* + ID_OUI_FROM_DATABASE=Vodafone Omnitel N.V. + +OUI:9038DF* + ID_OUI_FROM_DATABASE=Changzhou Tiannengbo System Co. Ltd. + +OUI:903AA0* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:903CAE* + ID_OUI_FROM_DATABASE=Yunnan KSEC Digital Technology Co.,Ltd. + +OUI:903D5A* + ID_OUI_FROM_DATABASE=Shenzhen Wision Technology Holding Limited + +OUI:903D6B* + ID_OUI_FROM_DATABASE=Zicon Technology Corp. + +OUI:903EAB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:9046B7* + ID_OUI_FROM_DATABASE=Vadaro Pte Ltd + +OUI:904716* + ID_OUI_FROM_DATABASE=RORZE CORPORATION + +OUI:9049FA* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:904CE5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:904E2B* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:90507B* + ID_OUI_FROM_DATABASE=Advanced PANMOBIL Systems GmbH & Co. KG + +OUI:90513F* + ID_OUI_FROM_DATABASE=Elettronica Santerno + +OUI:905446* + ID_OUI_FROM_DATABASE=TES ELECTRONIC SOLUTIONS + +OUI:9055AE* + ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K + +OUI:905682* + ID_OUI_FROM_DATABASE=Lenbrook Industries Limited + +OUI:905692* + ID_OUI_FROM_DATABASE=Autotalks Ltd. + +OUI:9059AF* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:905F2E* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:905F8D* + ID_OUI_FROM_DATABASE=modas GmbH + +OUI:90610C* + ID_OUI_FROM_DATABASE=Fida International (S) Pte Ltd + +OUI:906717* + ID_OUI_FROM_DATABASE=Alphion India Private Limited + +OUI:9067B5* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:9067F3* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:906DC8* + ID_OUI_FROM_DATABASE=DLG Automação Industrial Ltda + +OUI:906EBB* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:907025* + ID_OUI_FROM_DATABASE=Garea Microsys Co.,Ltd. + +OUI:907240* + ID_OUI_FROM_DATABASE=Apple + +OUI:907990* + ID_OUI_FROM_DATABASE=Benchmark Electronics Romania SRL + +OUI:907A0A* + ID_OUI_FROM_DATABASE=Gebr. Bode GmbH & Co KG + +OUI:907A28* + ID_OUI_FROM_DATABASE=Beijing Morncloud Information And Technology Co. Ltd. + +OUI:907AF1* + ID_OUI_FROM_DATABASE=SNUPI Technologies + +OUI:907F61* + ID_OUI_FROM_DATABASE=Chicony Electronics Co., Ltd. + +OUI:908260* + ID_OUI_FROM_DATABASE=IEEE 1904.1 Working Group + +OUI:90837A* + ID_OUI_FROM_DATABASE=General Electric Water & Process Technologies + +OUI:90840D* + ID_OUI_FROM_DATABASE=Apple + +OUI:9088A2* + ID_OUI_FROM_DATABASE=IONICS TECHNOLOGY ME LTDA + +OUI:908C44* + ID_OUI_FROM_DATABASE=H.K ZONGMU TECHNOLOGY CO., LTD. + +OUI:908D1D* + ID_OUI_FROM_DATABASE=GH Technologies + +OUI:908F93* + ID_OUI_FROM_DATABASE=MakerBot Industries + +OUI:908FCF* + ID_OUI_FROM_DATABASE=UNO System Co., Ltd + +OUI:90903C* + ID_OUI_FROM_DATABASE=TRISON TECHNOLOGY CORPORATION + +OUI:909060* + ID_OUI_FROM_DATABASE=RSI VIDEO TECHNOLOGIES + +OUI:9092B4* + ID_OUI_FROM_DATABASE=Diehl BGT Defence GmbH & Co. KG + +OUI:9094E4* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:909864* + ID_OUI_FROM_DATABASE=Impex-Sat GmbH&Co KG + +OUI:909916* + ID_OUI_FROM_DATABASE=ELVEES NeoTek OJSC + +OUI:909DE0* + ID_OUI_FROM_DATABASE=Newland Design + Assoc. Inc. + +OUI:909F43* + ID_OUI_FROM_DATABASE=Accutron Instruments Inc. + +OUI:90A2DA* + ID_OUI_FROM_DATABASE=GHEO SA + +OUI:90A4DE* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:90A783* + ID_OUI_FROM_DATABASE=JSW PACIFIC CORPORATION + +OUI:90A7C1* + ID_OUI_FROM_DATABASE=Pakedge Device and Software Inc. + +OUI:90AC3F* + ID_OUI_FROM_DATABASE=BrightSign LLC + +OUI:90B11C* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:90B134* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:90B21F* + ID_OUI_FROM_DATABASE=Apple + +OUI:90B8D0* + ID_OUI_FROM_DATABASE=Joyent, Inc. + +OUI:90B931* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:90B97D* + ID_OUI_FROM_DATABASE=Johnson Outdoors Marine Electronics d/b/a Minnkota + +OUI:90C115* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:90CC24* + ID_OUI_FROM_DATABASE=Synaptics, Inc + +OUI:90CF15* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:90CF6F* + ID_OUI_FROM_DATABASE=Dlogixs Co Ltd + +OUI:90CF7D* + ID_OUI_FROM_DATABASE=Qingdao Hisense Electric Co.,Ltd. + +OUI:90D11B* + ID_OUI_FROM_DATABASE=Palomar Medical Technologies + +OUI:90D74F* + ID_OUI_FROM_DATABASE=Bookeen + +OUI:90D7EB* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:90D852* + ID_OUI_FROM_DATABASE=Comtec Co., Ltd. + +OUI:90D92C* + ID_OUI_FROM_DATABASE=HUG-WITSCHI AG + +OUI:90DA4E* + ID_OUI_FROM_DATABASE=AVANU + +OUI:90DB46* + ID_OUI_FROM_DATABASE=E-LEAD ELECTRONIC CO., LTD + +OUI:90DFB7* + ID_OUI_FROM_DATABASE=s.m.s smart microwave sensors GmbH + +OUI:90E0F0* + ID_OUI_FROM_DATABASE=Harman International + +OUI:90E2BA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:90E6BA* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:90EA60* + ID_OUI_FROM_DATABASE=SPI Lasers Ltd + +OUI:90F1AA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD + +OUI:90F1B0* + ID_OUI_FROM_DATABASE=Hangzhou Anheng Info&Tech CO.,LTD + +OUI:90F278* + ID_OUI_FROM_DATABASE=Radius Gateway + +OUI:90F3B7* + ID_OUI_FROM_DATABASE=Kirisun Communications Co., Ltd. + +OUI:90F4C1* + ID_OUI_FROM_DATABASE=Rand McNally + +OUI:90F652* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:90F72F* + ID_OUI_FROM_DATABASE=Phillips Machine & Welding Co., Inc. + +OUI:90FB5B* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:90FBA6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:90FF79* + ID_OUI_FROM_DATABASE=Metro Ethernet Forum + +OUI:940070* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:940149* + ID_OUI_FROM_DATABASE=AutoHotBox + +OUI:9401C2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:940B2D* + ID_OUI_FROM_DATABASE=NetView Technologies(Shenzhen) Co., Ltd + +OUI:940BD5* + ID_OUI_FROM_DATABASE=Himax Technologies, Inc + +OUI:940C6D* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co.,Ltd. + +OUI:94103E* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:9411DA* + ID_OUI_FROM_DATABASE=ITF Fröschl GmbH + +OUI:941673* + ID_OUI_FROM_DATABASE=Point Core SARL + +OUI:941D1C* + ID_OUI_FROM_DATABASE=TLab West Systems AB + +OUI:942053* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:942197* + ID_OUI_FROM_DATABASE=Stalmart Technology Limited + +OUI:94236E* + ID_OUI_FROM_DATABASE=Shenzhen Junlan Electronic Ltd + +OUI:942E17* + ID_OUI_FROM_DATABASE=Schneider Electric Canada Inc + +OUI:942E63* + ID_OUI_FROM_DATABASE=Finsécur + +OUI:94319B* + ID_OUI_FROM_DATABASE=Alphatronics BV + +OUI:9433DD* + ID_OUI_FROM_DATABASE=Taco Electronic Solutions, Inc. + +OUI:94350A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9436E0* + ID_OUI_FROM_DATABASE=Sichuan Bihong Broadcast & Television New Technologies Co.,Ltd + +OUI:9439E5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:943AF0* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:943BB1* + ID_OUI_FROM_DATABASE=KAONMEDIA + +OUI:9440A2* + ID_OUI_FROM_DATABASE=Anywave Communication Technologies, Inc. + +OUI:944444* + ID_OUI_FROM_DATABASE=LG Innotek + +OUI:944452* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:944696* + ID_OUI_FROM_DATABASE=BaudTec Corporation + +OUI:944A09* + ID_OUI_FROM_DATABASE=BitWise Controls + +OUI:945047* + ID_OUI_FROM_DATABASE=Rechnerbetriebsgruppe + +OUI:945103* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:9451BF* + ID_OUI_FROM_DATABASE=Hyundai ESG + +OUI:94592D* + ID_OUI_FROM_DATABASE=EKE Building Technology Systems Ltd + +OUI:945B7E* + ID_OUI_FROM_DATABASE=TRILOBIT LTDA. + +OUI:946124* + ID_OUI_FROM_DATABASE=Pason Systems + +OUI:9463D1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9471AC* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:94756E* + ID_OUI_FROM_DATABASE=QinetiQ North America + +OUI:947C3E* + ID_OUI_FROM_DATABASE=Polewall Norge AS + +OUI:9481A4* + ID_OUI_FROM_DATABASE=Azuray Technologies + +OUI:94857A* + ID_OUI_FROM_DATABASE=Evantage Industries Corp + +OUI:9486D4* + ID_OUI_FROM_DATABASE=Surveillance Pro Corporation + +OUI:94877C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:948854* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:948B03* + ID_OUI_FROM_DATABASE=EAGET Innovation and Technology Co., Ltd. + +OUI:948D50* + ID_OUI_FROM_DATABASE=Beamex Oy Ab + +OUI:948FEE* + ID_OUI_FROM_DATABASE=Hughes Telematics, Inc. + +OUI:949426* + ID_OUI_FROM_DATABASE=Apple + +OUI:9498A2* + ID_OUI_FROM_DATABASE=Shanghai LISTEN TECH.LTD + +OUI:949BFD* + ID_OUI_FROM_DATABASE=Trans New Technology, Inc. + +OUI:949C55* + ID_OUI_FROM_DATABASE=Alta Data Technologies + +OUI:949F3F* + ID_OUI_FROM_DATABASE=Optek Digital Technology company limited + +OUI:949FB4* + ID_OUI_FROM_DATABASE=ChengDu JiaFaAnTai Technology Co.,Ltd + +OUI:94A7BC* + ID_OUI_FROM_DATABASE=BodyMedia, Inc. + +OUI:94AAB8* + ID_OUI_FROM_DATABASE=Joview(Beijing) Technology Co. Ltd. + +OUI:94ACCA* + ID_OUI_FROM_DATABASE=trivum technologies GmbH + +OUI:94AE61* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:94B8C5* + ID_OUI_FROM_DATABASE=RuggedCom Inc. + +OUI:94B9B4* + ID_OUI_FROM_DATABASE=Aptos Technology + +OUI:94BA31* + ID_OUI_FROM_DATABASE=Visiontec da Amazônia Ltda. + +OUI:94BA56* + ID_OUI_FROM_DATABASE=Shenzhen Coship Electronics Co., Ltd. + +OUI:94BF1E* + ID_OUI_FROM_DATABASE=eflow Inc. / Smart Device Planning and Development Division + +OUI:94C014* + ID_OUI_FROM_DATABASE=Sorter Sp. j. Konrad Grzeszczyk MichaA, Ziomek + +OUI:94C150* + ID_OUI_FROM_DATABASE=2Wire Inc + +OUI:94C3E4* + ID_OUI_FROM_DATABASE=SCA Schucker Gmbh & Co KG + +OUI:94C4E9* + ID_OUI_FROM_DATABASE=PowerLayer Microsystems HongKong Limited + +OUI:94C6EB* + ID_OUI_FROM_DATABASE=NOVA electronics, Inc. + +OUI:94C7AF* + ID_OUI_FROM_DATABASE=Raylios Technology + +OUI:94C962* + ID_OUI_FROM_DATABASE=Teseq AG + +OUI:94CA0F* + ID_OUI_FROM_DATABASE=Honeywell Analytics + +OUI:94CCB9* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:94CDAC* + ID_OUI_FROM_DATABASE=Creowave Oy + +OUI:94CE2C* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:94D019* + ID_OUI_FROM_DATABASE=Cydle Corp. + +OUI:94D723* + ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co., Ltd + +OUI:94D771* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:94D93C* + ID_OUI_FROM_DATABASE=ENELPS + +OUI:94DB49* + ID_OUI_FROM_DATABASE=SITCORP + +OUI:94DBC9* + ID_OUI_FROM_DATABASE=Azurewave + +OUI:94DD3F* + ID_OUI_FROM_DATABASE=A+V Link Technologies, Corp. + +OUI:94DE0E* + ID_OUI_FROM_DATABASE=SmartOptics AS + +OUI:94DE80* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:94DF4E* + ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. + +OUI:94DF58* + ID_OUI_FROM_DATABASE=IJ Electron CO.,Ltd. + +OUI:94E0D0* + ID_OUI_FROM_DATABASE=HealthStream Taiwan Inc. + +OUI:94E226* + ID_OUI_FROM_DATABASE=D. ORtiz Consulting, LLC + +OUI:94E711* + ID_OUI_FROM_DATABASE=Xirka Dama Persada PT + +OUI:94E848* + ID_OUI_FROM_DATABASE=FYLDE MICRO LTD + +OUI:94E98C* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:94EB2C* + ID_OUI_FROM_DATABASE=Google Inc. + +OUI:94EBCD* + ID_OUI_FROM_DATABASE=Research In Motion Limited + +OUI:94F692* + ID_OUI_FROM_DATABASE=Geminico co.,Ltd. + +OUI:94F720* + ID_OUI_FROM_DATABASE=Tianjin Deviser Electronics Instrument Co., Ltd + +OUI:94FAE8* + ID_OUI_FROM_DATABASE=Shenzhen Eycom Technology Co., Ltd + +OUI:94FBB2* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:94FD1D* + ID_OUI_FROM_DATABASE=WhereWhen Corp + +OUI:94FD2E* + ID_OUI_FROM_DATABASE=Shanghai Uniscope Technologies Co.,Ltd + +OUI:94FEF4* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:980284* + ID_OUI_FROM_DATABASE=Theobroma Systems GmbH + +OUI:9803A0* + ID_OUI_FROM_DATABASE=ABB n.v. Power Quality Products + +OUI:9803D8* + ID_OUI_FROM_DATABASE=Apple + +OUI:980C82* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics + +OUI:980D2E* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:981094* + ID_OUI_FROM_DATABASE=Shenzhen Vsun communication technology Co.,ltd + +OUI:98208E* + ID_OUI_FROM_DATABASE=Definium Technologies + +OUI:98262A* + ID_OUI_FROM_DATABASE=Applied Research Associates, Inc + +OUI:98291D* + ID_OUI_FROM_DATABASE=Jaguar de Mexico, SA de CV + +OUI:98293F* + ID_OUI_FROM_DATABASE=Fujian Start Computer Equipment Co.,Ltd + +OUI:982CBE* + ID_OUI_FROM_DATABASE=2Wire + +OUI:982D56* + ID_OUI_FROM_DATABASE=Resolution Audio + +OUI:983000* + ID_OUI_FROM_DATABASE=Beijing KEMACOM Technologies Co., Ltd. + +OUI:983071* + ID_OUI_FROM_DATABASE=DAIKYUNG VASCOM + +OUI:98349D* + ID_OUI_FROM_DATABASE=Krauss Maffei Technologies GmbH + +OUI:983571* + ID_OUI_FROM_DATABASE=Sub10 Systems Ltd + +OUI:9835B8* + ID_OUI_FROM_DATABASE=Assembled Products Corporation + +OUI:983B16* + ID_OUI_FROM_DATABASE=AMPAK Technology Inc + +OUI:983F9F* + ID_OUI_FROM_DATABASE=China SSJ (Suzhou) Network Technology Inc. + +OUI:984246* + ID_OUI_FROM_DATABASE=SOL INDUSTRY PTE., LTD + +OUI:9843DA* + ID_OUI_FROM_DATABASE=INTERTECH + +OUI:98473C* + ID_OUI_FROM_DATABASE=SHANGHAI SUNMON COMMUNICATION TECHNOGY CO.,LTD + +OUI:984A47* + ID_OUI_FROM_DATABASE=CHG Hospital Beds + +OUI:984B4A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:984BE1* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:984C04* + ID_OUI_FROM_DATABASE=Zhangzhou Keneng Electrical Equipment Co Ltd + +OUI:984CD3* + ID_OUI_FROM_DATABASE=Mantis Deposition + +OUI:984E97* + ID_OUI_FROM_DATABASE=Starlight Marketing (H. K.) Ltd. + +OUI:984FEE* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:9852B1* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:9857D3* + ID_OUI_FROM_DATABASE=HON HAI-CCPBG PRECISION IND.CO.,LTD. + +OUI:98588A* + ID_OUI_FROM_DATABASE=SYSGRATION Ltd. + +OUI:985945* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:985C93* + ID_OUI_FROM_DATABASE=SBG Systems SAS + +OUI:985D46* + ID_OUI_FROM_DATABASE=PeopleNet Communication + +OUI:985E1B* + ID_OUI_FROM_DATABASE=ConversDigital Co., Ltd. + +OUI:986022* + ID_OUI_FROM_DATABASE=EMW Co., Ltd. + +OUI:9866EA* + ID_OUI_FROM_DATABASE=Industrial Control Communications, Inc. + +OUI:986CF5* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:986DC8* + ID_OUI_FROM_DATABASE=TOSHIBA MITSUBISHI-ELECTRIC INDUSTRIAL SYSTEMS CORPORATION + +OUI:9873C4* + ID_OUI_FROM_DATABASE=Sage Electronic Engineering LLC + +OUI:9876B6* + ID_OUI_FROM_DATABASE=Adafruit + +OUI:987770* + ID_OUI_FROM_DATABASE=Pep Digital Technology (Guangzhou) Co., Ltd + +OUI:988217* + ID_OUI_FROM_DATABASE=Disruptive Ltd + +OUI:9886B1* + ID_OUI_FROM_DATABASE=Flyaudio corporation (China) + +OUI:9889ED* + ID_OUI_FROM_DATABASE=Anadem Information Inc. + +OUI:988B5D* + ID_OUI_FROM_DATABASE=SAGEM COMMUNICATION + +OUI:988BAD* + ID_OUI_FROM_DATABASE=Corintech Ltd. + +OUI:988E34* + ID_OUI_FROM_DATABASE=ZHEJIANG BOXSAM ELECTRONIC CO.,LTD + +OUI:988E4A* + ID_OUI_FROM_DATABASE=NOXUS(BEIJING) TECHNOLOGY CO.,LTD + +OUI:988EDD* + ID_OUI_FROM_DATABASE=TE Connectivity Limerick + +OUI:989080* + ID_OUI_FROM_DATABASE=Linkpower Network System Inc Ltd. + +OUI:9893CC* + ID_OUI_FROM_DATABASE=LG Electronics Inc. + +OUI:989449* + ID_OUI_FROM_DATABASE=Skyworth Wireless Technology Ltd. + +OUI:98A7B0* + ID_OUI_FROM_DATABASE=MCST ZAO + +OUI:98AAD7* + ID_OUI_FROM_DATABASE=BLUE WAVE NETWORKING CO LTD + +OUI:98B039* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:98B8E3* + ID_OUI_FROM_DATABASE=Apple + +OUI:98BC57* + ID_OUI_FROM_DATABASE=SVA TECHNOLOGIES CO.LTD + +OUI:98BC99* + ID_OUI_FROM_DATABASE=Edeltech Co.,Ltd. + +OUI:98C0EB* + ID_OUI_FROM_DATABASE=Global Regency Ltd + +OUI:98C845* + ID_OUI_FROM_DATABASE=PacketAccess + +OUI:98CDB4* + ID_OUI_FROM_DATABASE=Virident Systems, Inc. + +OUI:98D331* + ID_OUI_FROM_DATABASE=Shenzhen Bolutek Technology Co.,Ltd. + +OUI:98D686* + ID_OUI_FROM_DATABASE=Chyi Lee industry Co., ltd. + +OUI:98D6BB* + ID_OUI_FROM_DATABASE=Apple + +OUI:98D6F7* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:98D88C* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:98DA92* + ID_OUI_FROM_DATABASE=Vuzix Corporation + +OUI:98DCD9* + ID_OUI_FROM_DATABASE=UNITEC Co., Ltd. + +OUI:98E165* + ID_OUI_FROM_DATABASE=Accutome + +OUI:98E79A* + ID_OUI_FROM_DATABASE=Foxconn(NanJing) Communication Co.,Ltd. + +OUI:98EC65* + ID_OUI_FROM_DATABASE=Cosesy ApS + +OUI:98F0AB* + ID_OUI_FROM_DATABASE=Apple + +OUI:98F537* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:98F8C1* + ID_OUI_FROM_DATABASE=IDT Technology Limited + +OUI:98F8DB* + ID_OUI_FROM_DATABASE=Marini Impianti Industriali s.r.l. + +OUI:98FB12* + ID_OUI_FROM_DATABASE=Grand Electronics (HK) Ltd + +OUI:98FC11* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:98FE03* + ID_OUI_FROM_DATABASE=Ericsson - North America + +OUI:98FE94* + ID_OUI_FROM_DATABASE=Apple + +OUI:98FF6A* + ID_OUI_FROM_DATABASE=OTEC(Shanghai)Technology Co.,Ltd. + +OUI:98FFD0* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:9C0111* + ID_OUI_FROM_DATABASE=Shenzhen Newabel Electronic Co., Ltd. + +OUI:9C0298* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9C039E* + ID_OUI_FROM_DATABASE=Beijing Winchannel Software Technology Co., Ltd + +OUI:9C0473* + ID_OUI_FROM_DATABASE=Tecmobile (International) Ltd. + +OUI:9C04EB* + ID_OUI_FROM_DATABASE=Apple + +OUI:9C066E* + ID_OUI_FROM_DATABASE=Hytera Communications Corporation Limited + +OUI:9C0DAC* + ID_OUI_FROM_DATABASE=Tymphany HK Limited + +OUI:9C1465* + ID_OUI_FROM_DATABASE=Edata Elektronik San. ve Tic. A.Ş. + +OUI:9C1874* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:9C1C12* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:9C1FDD* + ID_OUI_FROM_DATABASE=Accupix Inc. + +OUI:9C207B* + ID_OUI_FROM_DATABASE=Apple + +OUI:9C216A* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:9C220E* + ID_OUI_FROM_DATABASE=TASCAN Service GmbH + +OUI:9C2840* + ID_OUI_FROM_DATABASE=Discovery Technology,LTD.. + +OUI:9C28BF* + ID_OUI_FROM_DATABASE=Continental Automotive Czech Republic s.r.o. + +OUI:9C2A70* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:9C3178* + ID_OUI_FROM_DATABASE=Foshan Huadian Intelligent Communications Teachnologies Co.,Ltd + +OUI:9C31B6* + ID_OUI_FROM_DATABASE=Kulite Semiconductor Products Inc + +OUI:9C3AAF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9C3EAA* + ID_OUI_FROM_DATABASE=EnvyLogic Co.,Ltd. + +OUI:9C417C* + ID_OUI_FROM_DATABASE=Hame Technology Co., Limited + +OUI:9C443D* + ID_OUI_FROM_DATABASE=CHENGDU XUGUANG TECHNOLOGY CO, LTD + +OUI:9C44A6* + ID_OUI_FROM_DATABASE=SwiftTest, Inc. + +OUI:9C4563* + ID_OUI_FROM_DATABASE=DIMEP Sistemas + +OUI:9C4A7B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:9C4CAE* + ID_OUI_FROM_DATABASE=Mesa Labs + +OUI:9C4E20* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:9C4E36* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:9C4E8E* + ID_OUI_FROM_DATABASE=ALT Systems Ltd + +OUI:9C4EBF* + ID_OUI_FROM_DATABASE=BoxCast + +OUI:9C53CD* + ID_OUI_FROM_DATABASE=ENGICAM s.r.l. + +OUI:9C541C* + ID_OUI_FROM_DATABASE=Shenzhen My-power Technology Co.,Ltd + +OUI:9C54CA* + ID_OUI_FROM_DATABASE=Zhengzhou VCOM Science and Technology Co.,Ltd + +OUI:9C55B4* + ID_OUI_FROM_DATABASE=I.S.E. S.r.l. + +OUI:9C5711* + ID_OUI_FROM_DATABASE=Feitian Xunda(Beijing) Aeronautical Information Technology Co., Ltd. + +OUI:9C5B96* + ID_OUI_FROM_DATABASE=NMR Corporation + +OUI:9C5C8D* + ID_OUI_FROM_DATABASE=FIREMAX INDÚSTRIA E COMÉRCIO DE PRODUTOS ELETRÔNICOS LTDA + +OUI:9C5D12* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc + +OUI:9C5D95* + ID_OUI_FROM_DATABASE=VTC Electronics Corp. + +OUI:9C5E73* + ID_OUI_FROM_DATABASE=Calibre UK Ltd + +OUI:9C611D* + ID_OUI_FROM_DATABASE=Omni-ID USA, Inc. + +OUI:9C645E* + ID_OUI_FROM_DATABASE=Harman Consumer Group + +OUI:9C65B0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9C65F9* + ID_OUI_FROM_DATABASE=AcSiP Technology Corp. + +OUI:9C6650* + ID_OUI_FROM_DATABASE=Glodio Technolies Co.,Ltd Tianjin Branch + +OUI:9C6ABE* + ID_OUI_FROM_DATABASE=QEES ApS. + +OUI:9C7514* + ID_OUI_FROM_DATABASE=Wildix srl + +OUI:9C77AA* + ID_OUI_FROM_DATABASE=NADASNV + +OUI:9C79AC* + ID_OUI_FROM_DATABASE=Suntec Software(Shanghai) Co., Ltd. + +OUI:9C7BD2* + ID_OUI_FROM_DATABASE=NEOLAB Convergence + +OUI:9C807D* + ID_OUI_FROM_DATABASE=SYSCABLE Korea Inc. + +OUI:9C80DF* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:9C86DA* + ID_OUI_FROM_DATABASE=Phoenix Geophysics Ltd. + +OUI:9C8888* + ID_OUI_FROM_DATABASE=Simac Techniek NV + +OUI:9C8BF1* + ID_OUI_FROM_DATABASE=The Warehouse Limited + +OUI:9C8D1A* + ID_OUI_FROM_DATABASE=INTEG process group inc + +OUI:9C8E99* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:9C8EDC* + ID_OUI_FROM_DATABASE=Teracom Limited + +OUI:9C934E* + ID_OUI_FROM_DATABASE=Xerox Corporation + +OUI:9C95F8* + ID_OUI_FROM_DATABASE=SmartDoor Systems, LLC + +OUI:9C9726* + ID_OUI_FROM_DATABASE=Technicolor + +OUI:9C9811* + ID_OUI_FROM_DATABASE=Guangzhou Sunrise Electronics Development Co., Ltd + +OUI:9C9C1D* + ID_OUI_FROM_DATABASE=Starkey Labs Inc. + +OUI:9CA10A* + ID_OUI_FROM_DATABASE=SCLE SFE + +OUI:9CA134* + ID_OUI_FROM_DATABASE=Nike, Inc. + +OUI:9CA3BA* + ID_OUI_FROM_DATABASE=SAKURA Internet Inc. + +OUI:9CA577* + ID_OUI_FROM_DATABASE=Osorno Enterprises Inc. + +OUI:9CA9E4* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:9CADEF* + ID_OUI_FROM_DATABASE=Obihai Technology, Inc. + +OUI:9CAFCA* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:9CB008* + ID_OUI_FROM_DATABASE=Ubiquitous Computing Technology Corporation + +OUI:9CB206* + ID_OUI_FROM_DATABASE=PROCENTEC + +OUI:9CB654* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:9CB70D* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:9CB793* + ID_OUI_FROM_DATABASE=Creatcomm Technology Inc. + +OUI:9CBB98* + ID_OUI_FROM_DATABASE=Shen Zhen RND Electronic Co.,LTD + +OUI:9CBD9D* + ID_OUI_FROM_DATABASE=SkyDisk, Inc. + +OUI:9CC077* + ID_OUI_FROM_DATABASE=PrintCounts, LLC + +OUI:9CC0D2* + ID_OUI_FROM_DATABASE=Conductix-Wampfler AG + +OUI:9CC7A6* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:9CC7D1* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:9CCAD9* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:9CCD82* + ID_OUI_FROM_DATABASE=CHENG UEI PRECISION INDUSTRY CO.,LTD + +OUI:9CD21E* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:9CD24B* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:9CD36D* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:9CD643* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:9CDF03* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +OUI:9CE10E* + ID_OUI_FROM_DATABASE=NCTech Ltd + +OUI:9CE1D6* + ID_OUI_FROM_DATABASE=Junger Audio-Studiotechnik GmbH + +OUI:9CE635* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:9CE6E7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9CE7BD* + ID_OUI_FROM_DATABASE=Winduskorea co., Ltd + +OUI:9CEBE8* + ID_OUI_FROM_DATABASE=BizLink (Kunshan) Co.,Ltd + +OUI:9CF61A* + ID_OUI_FROM_DATABASE=UTC Fire and Security + +OUI:9CF67D* + ID_OUI_FROM_DATABASE=Ricardo Prague, s.r.o. + +OUI:9CF8DB* + ID_OUI_FROM_DATABASE=shenzhen eyunmei technology co,.ltd + +OUI:9CF938* + ID_OUI_FROM_DATABASE=AREVA NP GmbH + +OUI:9CFBF1* + ID_OUI_FROM_DATABASE=MESOMATIC GmbH & Co.KG + +OUI:9CFFBE* + ID_OUI_FROM_DATABASE=OTSL Inc. + +OUI:A00363* + ID_OUI_FROM_DATABASE=Robert Bosch Healthcare GmbH + +OUI:A00798* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:A007B6* + ID_OUI_FROM_DATABASE=Advanced Technical Support, Inc. + +OUI:A00ABF* + ID_OUI_FROM_DATABASE=Wieson Technologies Co., Ltd. + +OUI:A00BBA* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS + +OUI:A00CA1* + ID_OUI_FROM_DATABASE=SKTB SKiT + +OUI:A01290* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:A0133B* + ID_OUI_FROM_DATABASE=Copyright © HiTi Digital, Inc. + +OUI:A0143D* + ID_OUI_FROM_DATABASE=PARROT SA + +OUI:A0165C* + ID_OUI_FROM_DATABASE=Triteka LTD + +OUI:A01859* + ID_OUI_FROM_DATABASE=Shenzhen Yidashi Electronics Co Ltd + +OUI:A01917* + ID_OUI_FROM_DATABASE=Bertel S.p.a. + +OUI:A01C05* + ID_OUI_FROM_DATABASE=NIMAX TELECOM CO.,LTD. + +OUI:A01D48* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A02195* + ID_OUI_FROM_DATABASE=Samsung Electronics Digital Imaging + +OUI:A021B7* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:A0231B* + ID_OUI_FROM_DATABASE=TeleComp R&D Corp. + +OUI:A02EF3* + ID_OUI_FROM_DATABASE=United Integrated Services Co., Led. + +OUI:A0369F* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A036F0* + ID_OUI_FROM_DATABASE=Comprehensive Power + +OUI:A036FA* + ID_OUI_FROM_DATABASE=Ettus Research LLC + +OUI:A03A75* + ID_OUI_FROM_DATABASE=PSS Belgium N.V. + +OUI:A03B1B* + ID_OUI_FROM_DATABASE=Inspire Tech + +OUI:A04025* + ID_OUI_FROM_DATABASE=Actioncable, Inc. + +OUI:A04041* + ID_OUI_FROM_DATABASE=SAMWONFA Co.,Ltd. + +OUI:A041A7* + ID_OUI_FROM_DATABASE=NL Ministry of Defense + +OUI:A0423F* + ID_OUI_FROM_DATABASE=Tyan Computer Corp + +OUI:A0481C* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A04CC1* + ID_OUI_FROM_DATABASE=Helixtech Corp. + +OUI:A04E04* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A051C6* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:A055DE* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:A0593A* + ID_OUI_FROM_DATABASE=V.D.S. Video Display Systems srl + +OUI:A05AA4* + ID_OUI_FROM_DATABASE=Grand Products Nevada, Inc. + +OUI:A05B21* + ID_OUI_FROM_DATABASE=ENVINET GmbH + +OUI:A05DC1* + ID_OUI_FROM_DATABASE=TMCT Co., LTD. + +OUI:A05DE7* + ID_OUI_FROM_DATABASE=DIRECTV, Inc. + +OUI:A05E6B* + ID_OUI_FROM_DATABASE=MELPER Co., Ltd. + +OUI:A06518* + ID_OUI_FROM_DATABASE=VNPT TECHNOLOGY + +OUI:A067BE* + ID_OUI_FROM_DATABASE=Sicon s.r.l. + +OUI:A06986* + ID_OUI_FROM_DATABASE=Wellav Technologies Ltd + +OUI:A06A00* + ID_OUI_FROM_DATABASE=Verilink Corporation + +OUI:A06CEC* + ID_OUI_FROM_DATABASE=RIM + +OUI:A06D09* + ID_OUI_FROM_DATABASE=Intelcan Technosystems Inc. + +OUI:A06E50* + ID_OUI_FROM_DATABASE=Nanotek Elektronik Sistemler Ltd. Sti. + +OUI:A071A9* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A07332* + ID_OUI_FROM_DATABASE=Cashmaster International Limited + +OUI:A073FC* + ID_OUI_FROM_DATABASE=Rancore Technologies Private Limited + +OUI:A07591* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A07771* + ID_OUI_FROM_DATABASE=Vialis BV + +OUI:A078BA* + ID_OUI_FROM_DATABASE=Pantech Co., Ltd. + +OUI:A0821F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A082C7* + ID_OUI_FROM_DATABASE=P.T.I Co.,LTD + +OUI:A0861D* + ID_OUI_FROM_DATABASE=Chengdu Fuhuaxin Technology co.,Ltd + +OUI:A086EC* + ID_OUI_FROM_DATABASE=SAEHAN HITEC Co., Ltd + +OUI:A08869* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A088B4* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A089E4* + ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd + +OUI:A08A87* + ID_OUI_FROM_DATABASE=HuiZhou KaiYue Electronic Co.,Ltd + +OUI:A08C15* + ID_OUI_FROM_DATABASE=Gerhard D. Wempe KG + +OUI:A08C9B* + ID_OUI_FROM_DATABASE=Xtreme Technologies Corp + +OUI:A090DE* + ID_OUI_FROM_DATABASE=VEEDIMS,LLC + +OUI:A09805* + ID_OUI_FROM_DATABASE=OpenVox Communication Co Ltd + +OUI:A098ED* + ID_OUI_FROM_DATABASE=Shandong Intelligent Optical Communication Development Co., Ltd. + +OUI:A09A5A* + ID_OUI_FROM_DATABASE=Time Domain + +OUI:A09BBD* + ID_OUI_FROM_DATABASE=Total Aviation Solutions Pty Ltd + +OUI:A0A130* + ID_OUI_FROM_DATABASE=DLI Taiwan Branch office + +OUI:A0A23C* + ID_OUI_FROM_DATABASE=GPMS + +OUI:A0A763* + ID_OUI_FROM_DATABASE=Polytron Vertrieb GmbH + +OUI:A0A8CD* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A0AAFD* + ID_OUI_FROM_DATABASE=EraThink Technologies Corp. + +OUI:A0B100* + ID_OUI_FROM_DATABASE=ShenZhen Cando Electronics Co.,Ltd + +OUI:A0B3CC* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A0B5DA* + ID_OUI_FROM_DATABASE=HongKong THTF Co., Ltd + +OUI:A0B662* + ID_OUI_FROM_DATABASE=Acutvista Innovation Co., Ltd. + +OUI:A0B9ED* + ID_OUI_FROM_DATABASE=Skytap + +OUI:A0BAB8* + ID_OUI_FROM_DATABASE=Pixon Imaging + +OUI:A0BF50* + ID_OUI_FROM_DATABASE=S.C. ADD-PRODUCTION S.R.L. + +OUI:A0BFA5* + ID_OUI_FROM_DATABASE=CORESYS + +OUI:A0C3DE* + ID_OUI_FROM_DATABASE=Triton Electronic Systems Ltd. + +OUI:A0C6EC* + ID_OUI_FROM_DATABASE=ShenZhen ANYK Technology Co.,LTD + +OUI:A0CEC8* + ID_OUI_FROM_DATABASE=CE LINK LIMITED + +OUI:A0CF5B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A0D12A* + ID_OUI_FROM_DATABASE=AXPRO Technology Inc. + +OUI:A0D3C1* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A0DC04* + ID_OUI_FROM_DATABASE=Becker-Antriebe GmbH + +OUI:A0DD97* + ID_OUI_FROM_DATABASE=PolarLink Technologies, Ltd + +OUI:A0DDE5* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:A0DE05* + ID_OUI_FROM_DATABASE=JSC "Irbis-T" + +OUI:A0E201* + ID_OUI_FROM_DATABASE=AVTrace Ltd.(China) + +OUI:A0E25A* + ID_OUI_FROM_DATABASE=Amicus SK, s.r.o. + +OUI:A0E295* + ID_OUI_FROM_DATABASE=DAT System Co.,Ltd + +OUI:A0E453* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:A0E534* + ID_OUI_FROM_DATABASE=Stratec Biomedical AG + +OUI:A0E5E9* + ID_OUI_FROM_DATABASE=enimai Inc + +OUI:A0E9DB* + ID_OUI_FROM_DATABASE=Ningbo FreeWings Technologies Co.,Ltd + +OUI:A0EB76* + ID_OUI_FROM_DATABASE=AirCUVE Inc. + +OUI:A0EC80* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:A0EDCD* + ID_OUI_FROM_DATABASE=Apple + +OUI:A0EF84* + ID_OUI_FROM_DATABASE=Seine Image Int'l Co., Ltd + +OUI:A0F217* + ID_OUI_FROM_DATABASE=GE Medical System(China) Co., Ltd. + +OUI:A0F3C1* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:A0F3E4* + ID_OUI_FROM_DATABASE=Alcatel Lucent IPD + +OUI:A0F419* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A0F450* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:A0F459* + ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED + +OUI:A0FE91* + ID_OUI_FROM_DATABASE=AVAT Automation GmbH + +OUI:A40130* + ID_OUI_FROM_DATABASE=ABIsystems Co., LTD + +OUI:A4059E* + ID_OUI_FROM_DATABASE=STA Infinity LLP + +OUI:A409CB* + ID_OUI_FROM_DATABASE=Alfred Kaercher GmbH & Co KG + +OUI:A40BED* + ID_OUI_FROM_DATABASE=Carry Technology Co.,Ltd + +OUI:A40CC3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A4134E* + ID_OUI_FROM_DATABASE=Luxul + +OUI:A41566* + ID_OUI_FROM_DATABASE=Wei Fang Goertek Electronics Co.,Ltd + +OUI:A41731* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:A41875* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A41BC0* + ID_OUI_FROM_DATABASE=Fastec Imaging Corporation + +OUI:A41F72* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:A4218A* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:A42305* + ID_OUI_FROM_DATABASE=Open Networking Laboratory + +OUI:A424B3* + ID_OUI_FROM_DATABASE=FlatFrog Laboratories AB + +OUI:A42940* + ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd + +OUI:A429B7* + ID_OUI_FROM_DATABASE=bluesky + +OUI:A42C08* + ID_OUI_FROM_DATABASE=Masterwork Automodules + +OUI:A433D1* + ID_OUI_FROM_DATABASE=Fibrlink Communications Co.,Ltd. + +OUI:A438FC* + ID_OUI_FROM_DATABASE=Plastic Logic + +OUI:A43A69* + ID_OUI_FROM_DATABASE=Vers Inc + +OUI:A4466B* + ID_OUI_FROM_DATABASE=EOC Technology + +OUI:A446FA* + ID_OUI_FROM_DATABASE=AmTRAN Video Corporation + +OUI:A44B15* + ID_OUI_FROM_DATABASE=Sun Cupid Technology (HK) LTD + +OUI:A44C11* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A44E2D* + ID_OUI_FROM_DATABASE=Adaptive Wireless Solutions, LLC + +OUI:A44E31* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A45055* + ID_OUI_FROM_DATABASE=busware.de + +OUI:A4526F* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:A4561B* + ID_OUI_FROM_DATABASE=MCOT Corporation + +OUI:A45630* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A45A1C* + ID_OUI_FROM_DATABASE=smart-electronic GmbH + +OUI:A45C27* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:A45D36* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A46706* + ID_OUI_FROM_DATABASE=Apple + +OUI:A46CC1* + ID_OUI_FROM_DATABASE=LTi REEnergy GmbH + +OUI:A46E79* + ID_OUI_FROM_DATABASE=DFT System Co.Ltd + +OUI:A47733* + ID_OUI_FROM_DATABASE=Google + +OUI:A47760* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A479E4* + ID_OUI_FROM_DATABASE=KLINFO Corp + +OUI:A47AA4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:A47ACF* + ID_OUI_FROM_DATABASE=VIBICOM COMMUNICATIONS INC. + +OUI:A47C14* + ID_OUI_FROM_DATABASE=ChargeStorm AB + +OUI:A47C1F* + ID_OUI_FROM_DATABASE=Global Microwave Systems Inc. + +OUI:A4856B* + ID_OUI_FROM_DATABASE=Q Electronics Ltd + +OUI:A4895B* + ID_OUI_FROM_DATABASE=ARK INFOSOLUTIONS PVT LTD + +OUI:A49005* + ID_OUI_FROM_DATABASE=CHINA GREATWALL COMPUTER SHENZHEN CO.,LTD + +OUI:A4934C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A497BB* + ID_OUI_FROM_DATABASE=Hitachi Industrial Equipment Systems Co.,Ltd + +OUI:A49947* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:A49981* + ID_OUI_FROM_DATABASE=FuJian Elite Power Tech CO.,LTD. + +OUI:A49A58* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A49B13* + ID_OUI_FROM_DATABASE=Burroughs Payment Systems, Inc. + +OUI:A49EDB* + ID_OUI_FROM_DATABASE=AutoCrib, Inc. + +OUI:A49F89* + ID_OUI_FROM_DATABASE=Shanghai Rui Rui Communication Technology Co.Ltd. + +OUI:A4A24A* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:A4A80F* + ID_OUI_FROM_DATABASE=Shenzhen Coship Electronics Co., Ltd. + +OUI:A4AD00* + ID_OUI_FROM_DATABASE=Ragsdale Technology + +OUI:A4ADB8* + ID_OUI_FROM_DATABASE=Vitec Group, Camera Dynamics Ltd + +OUI:A4AE9A* + ID_OUI_FROM_DATABASE=Maestro Wireless Solutions ltd. + +OUI:A4B121* + ID_OUI_FROM_DATABASE=Arantia 2010 S.L. + +OUI:A4B197* + ID_OUI_FROM_DATABASE=Apple + +OUI:A4B1E9* + ID_OUI_FROM_DATABASE=Technicolor + +OUI:A4B1EE* + ID_OUI_FROM_DATABASE=H. ZANDER GmbH & Co. KG + +OUI:A4B2A7* + ID_OUI_FROM_DATABASE=Adaxys Solutions AG + +OUI:A4B36A* + ID_OUI_FROM_DATABASE=JSC SDO Chromatec + +OUI:A4B818* + ID_OUI_FROM_DATABASE=PENTA Gesellschaft für elektronische Industriedatenverarbeitung mbH + +OUI:A4B980* + ID_OUI_FROM_DATABASE=Parking BOXX Inc. + +OUI:A4BADB* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:A4BBAF* + ID_OUI_FROM_DATABASE=Lime Instruments + +OUI:A4BE61* + ID_OUI_FROM_DATABASE=EutroVision System, Inc. + +OUI:A4C0C7* + ID_OUI_FROM_DATABASE=ShenZhen Hitom Communication Technology Co..LTD + +OUI:A4C0E1* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:A4C2AB* + ID_OUI_FROM_DATABASE=Hangzhou LEAD-IT Information & Technology Co.,Ltd + +OUI:A4C361* + ID_OUI_FROM_DATABASE=Apple + +OUI:A4C7DE* + ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. + +OUI:A4D094* + ID_OUI_FROM_DATABASE=Erwin Peters Systemtechnik GmbH + +OUI:A4D18F* + ID_OUI_FROM_DATABASE=Shenzhen Skyee Optical Fiber Communication Technology Ltd. + +OUI:A4D1D1* + ID_OUI_FROM_DATABASE=ECOtality North America + +OUI:A4D1D2* + ID_OUI_FROM_DATABASE=Apple + +OUI:A4D3B5* + ID_OUI_FROM_DATABASE=GLITEL Stropkov, s.r.o. + +OUI:A4D856* + ID_OUI_FROM_DATABASE=Qualcomm Labs Inc. + +OUI:A4DA3F* + ID_OUI_FROM_DATABASE=Bionics Corp. + +OUI:A4DB2E* + ID_OUI_FROM_DATABASE=Kingspan Environmental Ltd + +OUI:A4DB30* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:A4DE50* + ID_OUI_FROM_DATABASE=Total Walther GmbH + +OUI:A4E0E6* + ID_OUI_FROM_DATABASE=FILIZOLA S.A. PESAGEM E AUTOMACAO + +OUI:A4E32E* + ID_OUI_FROM_DATABASE=Silicon & Software Systems Ltd. + +OUI:A4E391* + ID_OUI_FROM_DATABASE=DENY FONTAINE + +OUI:A4E4B8* + ID_OUI_FROM_DATABASE=BlackBerry Limited + +OUI:A4E731* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A4E7E4* + ID_OUI_FROM_DATABASE=Connex GmbH + +OUI:A4E991* + ID_OUI_FROM_DATABASE=SISTEMAS AUDIOVISUALES ITELSIS S.L. + +OUI:A4E9A3* + ID_OUI_FROM_DATABASE=Honest Technology Co., Ltd + +OUI:A4EBD3* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A4ED4E* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:A4EE57* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:A4EF52* + ID_OUI_FROM_DATABASE=Telewave Co., Ltd. + +OUI:A4F3C1* + ID_OUI_FROM_DATABASE=Open Source Robotics Foundation, Inc. + +OUI:A4F522* + ID_OUI_FROM_DATABASE=CHOFU SEISAKUSHO CO.,LTD + +OUI:A4F7D0* + ID_OUI_FROM_DATABASE=LAN Accessories Co., Ltd. + +OUI:A4FB8D* + ID_OUI_FROM_DATABASE=Hangzhou Dunchong Technology Co.Ltd + +OUI:A4FCCE* + ID_OUI_FROM_DATABASE=Security Expert Ltd. + +OUI:A80180* + ID_OUI_FROM_DATABASE=IMAGO Technologies GmbH + +OUI:A80600* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A80C0D* + ID_OUI_FROM_DATABASE=Cisco + +OUI:A8154D* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:A816B2* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:A81758* + ID_OUI_FROM_DATABASE=Elektronik System i Umeå AB + +OUI:A81B18* + ID_OUI_FROM_DATABASE=XTS CORP + +OUI:A81FAF* + ID_OUI_FROM_DATABASE=KRYPTON POLSKA + +OUI:A82066* + ID_OUI_FROM_DATABASE=Apple + +OUI:A824EB* + ID_OUI_FROM_DATABASE=ZAO NPO Introtest + +OUI:A826D9* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:A8294C* + ID_OUI_FROM_DATABASE=Precision Optical Transceivers, Inc. + +OUI:A82BD6* + ID_OUI_FROM_DATABASE=Shina System Co., Ltd + +OUI:A830AD* + ID_OUI_FROM_DATABASE=Wei Fang Goertek Electronics Co.,Ltd + +OUI:A83944* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:A84041* + ID_OUI_FROM_DATABASE=Dragino Technology Co., Limited + +OUI:A84481* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A845E9* + ID_OUI_FROM_DATABASE=Firich Enterprises CO., LTD. + +OUI:A849A5* + ID_OUI_FROM_DATABASE=Lisantech Co., Ltd. + +OUI:A854B2* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:A8556A* + ID_OUI_FROM_DATABASE=Pocketnet Technology Inc. + +OUI:A8574E* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:A85BB0* + ID_OUI_FROM_DATABASE=Shenzhen Dehoo Technology Co.,Ltd + +OUI:A85BF3* + ID_OUI_FROM_DATABASE=Audivo GmbH + +OUI:A861AA* + ID_OUI_FROM_DATABASE=Cloudview Limited + +OUI:A862A2* + ID_OUI_FROM_DATABASE=JIWUMEDIA CO., LTD. + +OUI:A863DF* + ID_OUI_FROM_DATABASE=DISPLAIRE CORPORATION + +OUI:A863F2* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:A865B2* + ID_OUI_FROM_DATABASE=DONGGUAN YISHANG ELECTRONIC TECHNOLOGY CO., LIMITED + +OUI:A86A6F* + ID_OUI_FROM_DATABASE=RIM + +OUI:A870A5* + ID_OUI_FROM_DATABASE=UniComm Inc. + +OUI:A875D6* + ID_OUI_FROM_DATABASE=FreeTek International Co., Ltd. + +OUI:A875E2* + ID_OUI_FROM_DATABASE=Aventura Technologies, Inc. + +OUI:A8776F* + ID_OUI_FROM_DATABASE=Zonoff + +OUI:A87B39* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A87E33* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:A881F1* + ID_OUI_FROM_DATABASE=BMEYE B.V. + +OUI:A886DD* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:A88792* + ID_OUI_FROM_DATABASE=Broadband Antenna Tracking Systems + +OUI:A887ED* + ID_OUI_FROM_DATABASE=ARC Wireless LLC + +OUI:A88808* + ID_OUI_FROM_DATABASE=Apple + +OUI:A88CEE* + ID_OUI_FROM_DATABASE=MicroMade Galka i Drozdz sp.j. + +OUI:A88D7B* + ID_OUI_FROM_DATABASE=SunDroid Global limited. + +OUI:A8922C* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:A893E6* + ID_OUI_FROM_DATABASE=JIANGXI JINGGANGSHAN CKING COMMUNICATION TECHNOLOGY CO.,LTD + +OUI:A895B0* + ID_OUI_FROM_DATABASE=Aker Subsea Ltd + +OUI:A8968A* + ID_OUI_FROM_DATABASE=Apple + +OUI:A897DC* + ID_OUI_FROM_DATABASE=IBM + +OUI:A898C6* + ID_OUI_FROM_DATABASE=Shinbo Co., Ltd. + +OUI:A8995C* + ID_OUI_FROM_DATABASE=aizo ag + +OUI:A89B10* + ID_OUI_FROM_DATABASE=inMotion Ltd. + +OUI:A8AD3D* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:A8B0AE* + ID_OUI_FROM_DATABASE=LEONI + +OUI:A8B1D4* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:A8B9B3* + ID_OUI_FROM_DATABASE=ESSYS + +OUI:A8BBCF* + ID_OUI_FROM_DATABASE=Apple + +OUI:A8BD1A* + ID_OUI_FROM_DATABASE=Honey Bee (Hong Kong) Limited + +OUI:A8BD3A* + ID_OUI_FROM_DATABASE=UNIONMAN TECHNOLOGY CO.,LTD + +OUI:A8C222* + ID_OUI_FROM_DATABASE=TM-Research Inc. + +OUI:A8CB95* + ID_OUI_FROM_DATABASE=EAST BEST CO., LTD. + +OUI:A8CCC5* + ID_OUI_FROM_DATABASE=Saab AB (publ) + +OUI:A8CE90* + ID_OUI_FROM_DATABASE=CVC + +OUI:A8D0E5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:A8D236* + ID_OUI_FROM_DATABASE=Lightware Visual Engineering + +OUI:A8D3C8* + ID_OUI_FROM_DATABASE=Wachendorff Elektronik GmbH & Co. KG + +OUI:A8E018* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:A8E3EE* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:A8EF26* + ID_OUI_FROM_DATABASE=Tritonwave + +OUI:A8F274* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:A8F470* + ID_OUI_FROM_DATABASE=Fujian Newland Communication Science Technologies Co.,Ltd. + +OUI:A8F94B* + ID_OUI_FROM_DATABASE=Eltex Enterprise Ltd. + +OUI:A8FAD8* + ID_OUI_FROM_DATABASE=Apple + +OUI:A8FB70* + ID_OUI_FROM_DATABASE=WiseSec L.t.d + +OUI:A8FCB7* + ID_OUI_FROM_DATABASE=Consolidated Resource Imaging + +OUI:AA0000* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:AA0001* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:AA0002* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:AA0003* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:AA0004* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:AC0142* + ID_OUI_FROM_DATABASE=Uriel Technologies SIA + +OUI:AC02CA* + ID_OUI_FROM_DATABASE=HI Solutions, Inc. + +OUI:AC02CF* + ID_OUI_FROM_DATABASE=RW Tecnologia Industria e Comercio Ltda + +OUI:AC02EF* + ID_OUI_FROM_DATABASE=Comsis + +OUI:AC0613* + ID_OUI_FROM_DATABASE=Senselogix Ltd + +OUI:AC0A61* + ID_OUI_FROM_DATABASE=Labor S.r.L. + +OUI:AC0DFE* + ID_OUI_FROM_DATABASE=Ekon GmbH - myGEKKO + +OUI:AC1461* + ID_OUI_FROM_DATABASE=ATAW Co., Ltd. + +OUI:AC14D2* + ID_OUI_FROM_DATABASE=wi-daq, inc. + +OUI:AC162D* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:AC1702* + ID_OUI_FROM_DATABASE=Fibar Group sp. z o.o. + +OUI:AC1826* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:AC199F* + ID_OUI_FROM_DATABASE=SUNGROW POWER SUPPLY CO.,LTD. + +OUI:AC20AA* + ID_OUI_FROM_DATABASE=DMATEK Co., Ltd. + +OUI:AC220B* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:AC2DA3* + ID_OUI_FROM_DATABASE=TXTR GmbH + +OUI:AC2FA8* + ID_OUI_FROM_DATABASE=Humannix Co.,Ltd. + +OUI:AC319D* + ID_OUI_FROM_DATABASE=Shenzhen TG-NET Botone Technology Co.,Ltd. + +OUI:AC34CB* + ID_OUI_FROM_DATABASE=Shanhai GBCOM Communication Technology Co. Ltd + +OUI:AC3613* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:AC3C0B* + ID_OUI_FROM_DATABASE=Apple + +OUI:AC3CB4* + ID_OUI_FROM_DATABASE=Nilan A/S + +OUI:AC3D05* + ID_OUI_FROM_DATABASE=Instorescreen Aisa + +OUI:AC3D75* + ID_OUI_FROM_DATABASE=HANGZHOU ZHIWAY TECHNOLOGIES CO.,LTD. + +OUI:AC3FA4* + ID_OUI_FROM_DATABASE=TAIYO YUDEN CO.,LTD + +OUI:AC40EA* + ID_OUI_FROM_DATABASE=C&T Solution Inc. + +OUI:AC4122* + ID_OUI_FROM_DATABASE=Eclipse Electronic Systems Inc. + +OUI:AC44F2* + ID_OUI_FROM_DATABASE=Revolabs Inc + +OUI:AC4723* + ID_OUI_FROM_DATABASE=Genelec + +OUI:AC4AFE* + ID_OUI_FROM_DATABASE=Hisense Broadband Multimedia Technology Co.,Ltd. + +OUI:AC4BC8* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:AC4E91* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:AC4FFC* + ID_OUI_FROM_DATABASE=SVS-VISTEK GmbH + +OUI:AC5036* + ID_OUI_FROM_DATABASE=Pi-Coral Inc + +OUI:AC5135* + ID_OUI_FROM_DATABASE=MPI TECH + +OUI:AC51EE* + ID_OUI_FROM_DATABASE=Cambridge Communication Systems Ltd + +OUI:AC54EC* + ID_OUI_FROM_DATABASE=IEEE P1823 Standards Working Group + +OUI:AC583B* + ID_OUI_FROM_DATABASE=Human Assembler, Inc. + +OUI:AC5D10* + ID_OUI_FROM_DATABASE=Pace Americas + +OUI:AC5E8C* + ID_OUI_FROM_DATABASE=Utillink + +OUI:AC6123* + ID_OUI_FROM_DATABASE=Drivven, Inc. + +OUI:AC6706* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:AC6BAC* + ID_OUI_FROM_DATABASE=Jenny Science AG + +OUI:AC6E1A* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:AC6F4F* + ID_OUI_FROM_DATABASE=Enspert Inc + +OUI:AC6FBB* + ID_OUI_FROM_DATABASE=TATUNG Technology Inc. + +OUI:AC6FD9* + ID_OUI_FROM_DATABASE=Valueplus Inc. + +OUI:AC7236* + ID_OUI_FROM_DATABASE=Lexking Technology Co., Ltd. + +OUI:AC7289* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:AC7A42* + ID_OUI_FROM_DATABASE=iConnectivity + +OUI:AC7BA1* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:AC7F3E* + ID_OUI_FROM_DATABASE=Apple + +OUI:AC80D6* + ID_OUI_FROM_DATABASE=Hexatronic AB + +OUI:AC8112* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:AC81F3* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:AC8317* + ID_OUI_FROM_DATABASE=Shenzhen Furtunetel Communication Co., Ltd + +OUI:AC83F0* + ID_OUI_FROM_DATABASE=ImmediaTV Corporation + +OUI:AC853D* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:AC8674* + ID_OUI_FROM_DATABASE=Open Mesh, Inc. + +OUI:AC867E* + ID_OUI_FROM_DATABASE=Create New Technology (HK) Limited Company + +OUI:AC8ACD* + ID_OUI_FROM_DATABASE=ROGER D.Wensker, G.Wensker sp.j. + +OUI:AC8D14* + ID_OUI_FROM_DATABASE=Smartrove Inc + +OUI:AC932F* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:AC9403* + ID_OUI_FROM_DATABASE=Envision Peripherals Inc + +OUI:AC9A96* + ID_OUI_FROM_DATABASE=Lantiq Deutschland GmbH + +OUI:AC9B84* + ID_OUI_FROM_DATABASE=Smak Tecnologia e Automacao + +OUI:AC9CE4* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:ACA016* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:ACA22C* + ID_OUI_FROM_DATABASE=Baycity Technologies Ltd + +OUI:ACA430* + ID_OUI_FROM_DATABASE=Peerless AV + +OUI:ACAB8D* + ID_OUI_FROM_DATABASE=Lyngso Marine A/S + +OUI:ACB313* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:ACBD0B* + ID_OUI_FROM_DATABASE=IMAC CO.,LTD + +OUI:ACBE75* + ID_OUI_FROM_DATABASE=Ufine Technologies Co.,Ltd. + +OUI:ACBEB6* + ID_OUI_FROM_DATABASE=Visualedge Technology Co., Ltd. + +OUI:ACC2EC* + ID_OUI_FROM_DATABASE=CLT INT'L IND. CORP. + +OUI:ACC595* + ID_OUI_FROM_DATABASE=Graphite Systems + +OUI:ACC698* + ID_OUI_FROM_DATABASE=Kohzu Precision Co., Ltd. + +OUI:ACC935* + ID_OUI_FROM_DATABASE=Ness Corporation + +OUI:ACCA54* + ID_OUI_FROM_DATABASE=Telldus Technologies AB + +OUI:ACCA8E* + ID_OUI_FROM_DATABASE=ODA Technologies + +OUI:ACCABA* + ID_OUI_FROM_DATABASE=Midokura Co., Ltd. + +OUI:ACCB09* + ID_OUI_FROM_DATABASE=Hefcom Metering (Pty) Ltd + +OUI:ACCC8E* + ID_OUI_FROM_DATABASE=Axis Communications AB + +OUI:ACCE8F* + ID_OUI_FROM_DATABASE=HWA YAO TECHNOLOGIES CO., LTD + +OUI:ACCF23* + ID_OUI_FROM_DATABASE=Hi-flying electronics technology Co.,Ltd + +OUI:ACCF5C* + ID_OUI_FROM_DATABASE=Apple + +OUI:ACD180* + ID_OUI_FROM_DATABASE=Crexendo Business Solutions, Inc. + +OUI:ACD364* + ID_OUI_FROM_DATABASE=ABB SPA, ABB SACE DIV. + +OUI:ACD657* + ID_OUI_FROM_DATABASE=Shaanxi Guolian Digital TV Technology Co., Ltd. + +OUI:ACD9D6* + ID_OUI_FROM_DATABASE=tci GmbH + +OUI:ACDBDA* + ID_OUI_FROM_DATABASE=Shenzhen Geniatech Inc, Ltd + +OUI:ACE069* + ID_OUI_FROM_DATABASE=ISAAC Instruments + +OUI:ACE215* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:ACE348* + ID_OUI_FROM_DATABASE=MadgeTech, Inc + +OUI:ACE42E* + ID_OUI_FROM_DATABASE=SK hynix + +OUI:ACE64B* + ID_OUI_FROM_DATABASE=Shenzhen Baojia Battery Technology Co., Ltd. + +OUI:ACE87B* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:ACE87E* + ID_OUI_FROM_DATABASE=Bytemark Computer Consulting Ltd + +OUI:ACE97F* + ID_OUI_FROM_DATABASE=IoT Tech Limited + +OUI:ACE9AA* + ID_OUI_FROM_DATABASE=Hay Systems Ltd + +OUI:ACEA6A* + ID_OUI_FROM_DATABASE=GENIX INFOCOMM CO., LTD. + +OUI:ACEE3B* + ID_OUI_FROM_DATABASE=6harmonics Inc + +OUI:ACF0B2* + ID_OUI_FROM_DATABASE=Becker Electronics Taiwan Ltd. + +OUI:ACF1DF* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:ACF2C5* + ID_OUI_FROM_DATABASE=Cisco + +OUI:ACF7F3* + ID_OUI_FROM_DATABASE=XIAOMI CORPORATION + +OUI:ACF97E* + ID_OUI_FROM_DATABASE=ELESYS INC. + +OUI:ACFDEC* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:B00594* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:B01203* + ID_OUI_FROM_DATABASE=Dynamics Hong Kong Limited + +OUI:B01266* + ID_OUI_FROM_DATABASE=Futaba-Kikaku + +OUI:B01408* + ID_OUI_FROM_DATABASE=LIGHTSPEED INTERNATIONAL CO. + +OUI:B01743* + ID_OUI_FROM_DATABASE=EDISON GLOBAL CIRCUITS LLC + +OUI:B01B7C* + ID_OUI_FROM_DATABASE=Ontrol A.S. + +OUI:B01C91* + ID_OUI_FROM_DATABASE=Elim Co + +OUI:B024F3* + ID_OUI_FROM_DATABASE=Progeny Systems + +OUI:B03495* + ID_OUI_FROM_DATABASE=Apple + +OUI:B0358D* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:B03829* + ID_OUI_FROM_DATABASE=Siliconware Precision Industries Co., Ltd. + +OUI:B03850* + ID_OUI_FROM_DATABASE=Nanjing CAS-ZDC IOT SYSTEM CO.,LTD + +OUI:B0435D* + ID_OUI_FROM_DATABASE=NuLEDs, Inc. + +OUI:B04545* + ID_OUI_FROM_DATABASE=YACOUB Automation GmbH + +OUI:B046FC* + ID_OUI_FROM_DATABASE=MitraStar Technology Corp. + +OUI:B0487A* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:B04C05* + ID_OUI_FROM_DATABASE=Fresenius Medical Care Deutschland GmbH + +OUI:B050BC* + ID_OUI_FROM_DATABASE=SHENZHEN BASICOM ELECTRONIC CO.,LTD. + +OUI:B0518E* + ID_OUI_FROM_DATABASE=Holl technology CO.Ltd. + +OUI:B05706* + ID_OUI_FROM_DATABASE=Vallox Oy + +OUI:B058C4* + ID_OUI_FROM_DATABASE=Broadcast Microwave Services, Inc + +OUI:B05B1F* + ID_OUI_FROM_DATABASE=THERMO FISHER SCIENTIFIC S.P.A. + +OUI:B05CE5* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:B061C7* + ID_OUI_FROM_DATABASE=Ericsson-LG Enterprise + +OUI:B06563* + ID_OUI_FROM_DATABASE=Shanghai Railway Communication Factory + +OUI:B065BD* + ID_OUI_FROM_DATABASE=Apple + +OUI:B068B6* + ID_OUI_FROM_DATABASE=Hangzhou OYE Technology Co. Ltd + +OUI:B06971* + ID_OUI_FROM_DATABASE=DEI Sales, Inc. + +OUI:B06CBF* + ID_OUI_FROM_DATABASE=3ality Digital Systems GmbH + +OUI:B0750C* + ID_OUI_FROM_DATABASE=QA Cafe + +OUI:B075D5* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:B077AC* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:B07908* + ID_OUI_FROM_DATABASE=Cummings Engineering + +OUI:B0793C* + ID_OUI_FROM_DATABASE=Revolv Inc + +OUI:B07994* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + +OUI:B07D62* + ID_OUI_FROM_DATABASE=Dipl.-Ing. H. Horstmann GmbH + +OUI:B0808C* + ID_OUI_FROM_DATABASE=Laser Light Engines + +OUI:B081D8* + ID_OUI_FROM_DATABASE=I-sys Corp + +OUI:B0869E* + ID_OUI_FROM_DATABASE=Chloride S.r.L + +OUI:B08807* + ID_OUI_FROM_DATABASE=Strata Worldwide + +OUI:B08991* + ID_OUI_FROM_DATABASE=LGE + +OUI:B08E1A* + ID_OUI_FROM_DATABASE=URadio Systems Co., Ltd + +OUI:B09074* + ID_OUI_FROM_DATABASE=Fulan Electronics Limited + +OUI:B09134* + ID_OUI_FROM_DATABASE=Taleo + +OUI:B0973A* + ID_OUI_FROM_DATABASE=E-Fuel Corporation + +OUI:B0989F* + ID_OUI_FROM_DATABASE=LG CNS + +OUI:B09928* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:B09AE2* + ID_OUI_FROM_DATABASE=STEMMER IMAGING GmbH + +OUI:B09BD4* + ID_OUI_FROM_DATABASE=GNH Software India Private Limited + +OUI:B09FBA* + ID_OUI_FROM_DATABASE=Apple + +OUI:B0A10A* + ID_OUI_FROM_DATABASE=Pivotal Systems Corporation + +OUI:B0A72A* + ID_OUI_FROM_DATABASE=Ensemble Designs, Inc. + +OUI:B0A86E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:B0AA36* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD. + +OUI:B0ACFA* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:B0ADAA* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:B0B2DC* + ID_OUI_FROM_DATABASE=Zyxel Communications Corporation + +OUI:B0B32B* + ID_OUI_FROM_DATABASE=Slican Sp. z o.o. + +OUI:B0B448* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:B0B8D5* + ID_OUI_FROM_DATABASE=Nanjing Nengrui Auto Equipment CO.,Ltd + +OUI:B0BD6D* + ID_OUI_FROM_DATABASE=Echostreams Innovative Solutions + +OUI:B0BDA1* + ID_OUI_FROM_DATABASE=ZAKLAD ELEKTRONICZNY SIMS + +OUI:B0BF99* + ID_OUI_FROM_DATABASE=WIZITDONGDO + +OUI:B0C4E7* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:B0C554* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:B0C69A* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:B0C745* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:B0C83F* + ID_OUI_FROM_DATABASE=Jiangsu Cynray IOT Co., Ltd. + +OUI:B0C8AD* + ID_OUI_FROM_DATABASE=People Power Company + +OUI:B0C95B* + ID_OUI_FROM_DATABASE=Beijing Symtech CO.,LTD + +OUI:B0CE18* + ID_OUI_FROM_DATABASE=Zhejiang shenghui lighting co.,Ltd + +OUI:B0CF4D* + ID_OUI_FROM_DATABASE=MI-Zone Technology Ireland + +OUI:B0D09C* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B0D2F5* + ID_OUI_FROM_DATABASE=Vello Systems, Inc. + +OUI:B0D7C5* + ID_OUI_FROM_DATABASE=STP KFT + +OUI:B0DA00* + ID_OUI_FROM_DATABASE=CERA ELECTRONIQUE + +OUI:B0DF3A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B0E39D* + ID_OUI_FROM_DATABASE=CAT SYSTEM CO.,LTD. + +OUI:B0E50E* + ID_OUI_FROM_DATABASE=NRG SYSTEMS INC + +OUI:B0E754* + ID_OUI_FROM_DATABASE=2Wire + +OUI:B0E892* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:B0E97E* + ID_OUI_FROM_DATABASE=Advanced Micro Peripherals + +OUI:B0EC71* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B0EC8F* + ID_OUI_FROM_DATABASE=GMX SAS + +OUI:B0EE45* + ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc. + +OUI:B0F1BC* + ID_OUI_FROM_DATABASE=Dhemax Ingenieros Ltda + +OUI:B0FAEB* + ID_OUI_FROM_DATABASE=Cisco + +OUI:B4009C* + ID_OUI_FROM_DATABASE=CableWorld Ltd. + +OUI:B40142* + ID_OUI_FROM_DATABASE=GCI Science & Technology Co.,LTD + +OUI:B40418* + ID_OUI_FROM_DATABASE=Smartchip Integrated Inc. + +OUI:B407F9* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS + +OUI:B40832* + ID_OUI_FROM_DATABASE=TC Communications + +OUI:B40B7A* + ID_OUI_FROM_DATABASE=Brusa Elektronik AG + +OUI:B40C25* + ID_OUI_FROM_DATABASE=Palo Alto Networks + +OUI:B40E96* + ID_OUI_FROM_DATABASE=HERAN + +OUI:B40EDC* + ID_OUI_FROM_DATABASE=LG-Ericsson Co.,Ltd. + +OUI:B41489* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:B41513* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:B418D1* + ID_OUI_FROM_DATABASE=Apple + +OUI:B41DEF* + ID_OUI_FROM_DATABASE=Internet Laboratories, Inc. + +OUI:B4211D* + ID_OUI_FROM_DATABASE=Beijing GuangXin Technology Co., Ltd + +OUI:B4218A* + ID_OUI_FROM_DATABASE=Dog Hunter LLC + +OUI:B424E7* + ID_OUI_FROM_DATABASE=Codetek Technology Co.,Ltd + +OUI:B428F1* + ID_OUI_FROM_DATABASE=E-Prime Co., Ltd. + +OUI:B42A39* + ID_OUI_FROM_DATABASE=ORBIT MERRET, spol. s r. o. + +OUI:B42C92* + ID_OUI_FROM_DATABASE=Zhejiang Weirong Electronic Co., Ltd + +OUI:B42CBE* + ID_OUI_FROM_DATABASE=Direct Payment Solutions Limited + +OUI:B431B8* + ID_OUI_FROM_DATABASE=Aviwest + +OUI:B4346C* + ID_OUI_FROM_DATABASE=MATSUNICHI DIGITAL TECHNOLOGY (HONG KONG) LIMITED + +OUI:B43564* + ID_OUI_FROM_DATABASE=Fujian Tian Cheng Electron Science & Technical Development Co.,Ltd. + +OUI:B435F7* + ID_OUI_FROM_DATABASE=Zhejiang Pearmain Electronics Co.ltd. + +OUI:B43741* + ID_OUI_FROM_DATABASE=Consert, Inc. + +OUI:B439D6* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:B43A28* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B43DB2* + ID_OUI_FROM_DATABASE=Degreane Horizon + +OUI:B43E3B* + ID_OUI_FROM_DATABASE=Viableware, Inc + +OUI:B4417A* + ID_OUI_FROM_DATABASE=ShenZhen Gongjin Electronics Co.,Ltd + +OUI:B4430D* + ID_OUI_FROM_DATABASE=Broadlink Pty Ltd + +OUI:B44CC2* + ID_OUI_FROM_DATABASE=NR ELECTRIC CO., LTD + +OUI:B451F9* + ID_OUI_FROM_DATABASE=NB Software + +OUI:B45253* + ID_OUI_FROM_DATABASE=Seagate Technology + +OUI:B4527D* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:B4527E* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:B45570* + ID_OUI_FROM_DATABASE=Borea + +OUI:B45861* + ID_OUI_FROM_DATABASE=CRemote, LLC + +OUI:B45CA4* + ID_OUI_FROM_DATABASE=Thing-talk Wireless Communication Technologies Corporation Limited + +OUI:B461FF* + ID_OUI_FROM_DATABASE=Lumigon A/S + +OUI:B46238* + ID_OUI_FROM_DATABASE=Exablox + +OUI:B46293* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B462AD* + ID_OUI_FROM_DATABASE=raytest GmbH + +OUI:B46698* + ID_OUI_FROM_DATABASE=Zealabs srl + +OUI:B467E9* + ID_OUI_FROM_DATABASE=Qingdao GoerTek Technology Co., Ltd. + +OUI:B4749F* + ID_OUI_FROM_DATABASE=askey computer corp + +OUI:B4750E* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:B47F5E* + ID_OUI_FROM_DATABASE=Foresight Manufacture (S) Pte Ltd + +OUI:B48255* + ID_OUI_FROM_DATABASE=Research Products Corporation + +OUI:B4827B* + ID_OUI_FROM_DATABASE=AKG Acoustics GmbH + +OUI:B482C5* + ID_OUI_FROM_DATABASE=Relay2, Inc. + +OUI:B482FE* + ID_OUI_FROM_DATABASE=Askey Computer Corp + +OUI:B48547* + ID_OUI_FROM_DATABASE=Amptown System Company GmbH + +OUI:B48910* + ID_OUI_FROM_DATABASE=Coster T.E. S.P.A. + +OUI:B4944E* + ID_OUI_FROM_DATABASE=WeTelecom Co., Ltd. + +OUI:B49842* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:B4994C* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:B499BA* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:B49DB4* + ID_OUI_FROM_DATABASE=Axion Technologies Inc. + +OUI:B49EE6* + ID_OUI_FROM_DATABASE=SHENZHEN TECHNOLOGY CO LTD + +OUI:B4A4B5* + ID_OUI_FROM_DATABASE=Zen Eye Co.,Ltd + +OUI:B4A4E3* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:B4A5A9* + ID_OUI_FROM_DATABASE=MODI GmbH + +OUI:B4A82B* + ID_OUI_FROM_DATABASE=Histar Digital Electronics Co., Ltd. + +OUI:B4A95A* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:B4AA4D* + ID_OUI_FROM_DATABASE=Ensequence, Inc. + +OUI:B4AB2C* + ID_OUI_FROM_DATABASE=MtM Technology Corporation + +OUI:B4B017* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:B4B362* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:B4B52F* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:B4B542* + ID_OUI_FROM_DATABASE=Hubbell Power Systems, Inc. + +OUI:B4B5AF* + ID_OUI_FROM_DATABASE=Minsung Electronics + +OUI:B4B676* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:B4B88D* + ID_OUI_FROM_DATABASE=Thuh Company + +OUI:B4C44E* + ID_OUI_FROM_DATABASE=VXL eTech Pvt Ltd + +OUI:B4C799* + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. + +OUI:B4C810* + ID_OUI_FROM_DATABASE=UMPI Elettronica + +OUI:B4CCE9* + ID_OUI_FROM_DATABASE=PROSYST + +OUI:B4CFDB* + ID_OUI_FROM_DATABASE=Shenzhen Jiuzhou Electric Co.,LTD + +OUI:B4D8A9* + ID_OUI_FROM_DATABASE=BetterBots + +OUI:B4D8DE* + ID_OUI_FROM_DATABASE=iota Computing, Inc. + +OUI:B4DD15* + ID_OUI_FROM_DATABASE=ControlThings Oy Ab + +OUI:B4DF3B* + ID_OUI_FROM_DATABASE=Chromlech + +OUI:B4DFFA* + ID_OUI_FROM_DATABASE=Litemax Electronics Inc. + +OUI:B4E0CD* + ID_OUI_FROM_DATABASE=Fusion-io, Inc + +OUI:B4E9B0* + ID_OUI_FROM_DATABASE=Cisco + +OUI:B4ED19* + ID_OUI_FROM_DATABASE=Pie Digital, Inc. + +OUI:B4ED54* + ID_OUI_FROM_DATABASE=Wohler Technologies + +OUI:B4EED4* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:B4F0AB* + ID_OUI_FROM_DATABASE=Apple + +OUI:B4F2E8* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:B4F323* + ID_OUI_FROM_DATABASE=PETATEL INC. + +OUI:B4FC75* + ID_OUI_FROM_DATABASE=SEMA Electronics(HK) CO.,LTD + +OUI:B4FE8C* + ID_OUI_FROM_DATABASE=Centro Sicurezza Italia SpA + +OUI:B80305* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:B80415* + ID_OUI_FROM_DATABASE=Bayan Audio + +OUI:B80B9D* + ID_OUI_FROM_DATABASE=ROPEX Industrie-Elektronik GmbH + +OUI:B81413* + ID_OUI_FROM_DATABASE=Keen High Holding(HK) Ltd. + +OUI:B81619* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:B817C2* + ID_OUI_FROM_DATABASE=Apple + +OUI:B81999* + ID_OUI_FROM_DATABASE=Nesys + +OUI:B820E7* + ID_OUI_FROM_DATABASE=Guangzhou Horizontal Information & Network Integration Co. Ltd + +OUI:B82410* + ID_OUI_FROM_DATABASE=Magneti Marelli Slovakia s.r.o. + +OUI:B8241A* + ID_OUI_FROM_DATABASE=SWEDA INFORMATICA LTDA + +OUI:B8266C* + ID_OUI_FROM_DATABASE=ANOV France + +OUI:B826D4* + ID_OUI_FROM_DATABASE=Furukawa Industrial S.A. Produtos Elétricos + +OUI:B827EB* + ID_OUI_FROM_DATABASE=Raspberry Pi Foundation + +OUI:B8288B* + ID_OUI_FROM_DATABASE=Parker Hannifin + +OUI:B829F7* + ID_OUI_FROM_DATABASE=Blaster Tech + +OUI:B82ADC* + ID_OUI_FROM_DATABASE=EFR Europäische Funk-Rundsteuerung GmbH + +OUI:B82CA0* + ID_OUI_FROM_DATABASE=Honeywell HomMed + +OUI:B830A8* + ID_OUI_FROM_DATABASE=Road-Track Telematics Development + +OUI:B836D8* + ID_OUI_FROM_DATABASE=Videoswitch + +OUI:B83861* + ID_OUI_FROM_DATABASE=Cisco + +OUI:B838CA* + ID_OUI_FROM_DATABASE=Kyokko Tsushin System CO.,LTD + +OUI:B83A7B* + ID_OUI_FROM_DATABASE=Worldplay (Canada) Inc. + +OUI:B83D4E* + ID_OUI_FROM_DATABASE=Shenzhen Cultraview Digital Technology Co.,Ltd Shanghai Branch + +OUI:B83E59* + ID_OUI_FROM_DATABASE=Roku, Inc + +OUI:B8415F* + ID_OUI_FROM_DATABASE=ASP AG + +OUI:B843E4* + ID_OUI_FROM_DATABASE=Vlatacom + +OUI:B847C6* + ID_OUI_FROM_DATABASE=SanJet Technology Corp. + +OUI:B85510* + ID_OUI_FROM_DATABASE=Zioncom Electronics (Shenzhen) Ltd. + +OUI:B85810* + ID_OUI_FROM_DATABASE=NUMERA, INC. + +OUI:B85AF7* + ID_OUI_FROM_DATABASE=Ouya, Inc + +OUI:B85AFE* + ID_OUI_FROM_DATABASE=Handaer Communication Technology (Beijing) Co., Ltd + +OUI:B85E7B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B86091* + ID_OUI_FROM_DATABASE=Onnet Technologies and Innovations LLC + +OUI:B8616F* + ID_OUI_FROM_DATABASE=Accton Wireless Broadband(AWB), Corp. + +OUI:B8621F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:B863BC* + ID_OUI_FROM_DATABASE=ROBOTIS, Co, Ltd + +OUI:B86491* + ID_OUI_FROM_DATABASE=CK Telecom Ltd + +OUI:B8653B* + ID_OUI_FROM_DATABASE=Bolymin, Inc. + +OUI:B86B23* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:B86CE8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B870F4* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:B87424* + ID_OUI_FROM_DATABASE=Viessmann Elektronik GmbH + +OUI:B87447* + ID_OUI_FROM_DATABASE=Convergence Technologies + +OUI:B8763F* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:B877C3* + ID_OUI_FROM_DATABASE=Decagon Devices, Inc. + +OUI:B8782E* + ID_OUI_FROM_DATABASE=Apple + +OUI:B8797E* + ID_OUI_FROM_DATABASE=Secure Meters (UK) Limited + +OUI:B87AC9* + ID_OUI_FROM_DATABASE=Siemens Ltd. + +OUI:B8871E* + ID_OUI_FROM_DATABASE=Good Mind Industries Co., Ltd. + +OUI:B887A8* + ID_OUI_FROM_DATABASE=Step Ahead Innovations Inc. + +OUI:B888E3* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD + +OUI:B889CA* + ID_OUI_FROM_DATABASE=ILJIN ELECTRIC Co., Ltd. + +OUI:B88A60* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:B88D12* + ID_OUI_FROM_DATABASE=Apple + +OUI:B88E3A* + ID_OUI_FROM_DATABASE=Infinite Technologies JLT + +OUI:B88F14* + ID_OUI_FROM_DATABASE=Analytica GmbH + +OUI:B8921D* + ID_OUI_FROM_DATABASE=BG T&A + +OUI:B894D2* + ID_OUI_FROM_DATABASE=Retail Innovation HTT AB + +OUI:B89674* + ID_OUI_FROM_DATABASE=AllDSP GmbH & Co. KG + +OUI:B8975A* + ID_OUI_FROM_DATABASE=BIOSTAR Microtech Int'l Corp. + +OUI:B898B0* + ID_OUI_FROM_DATABASE=Atlona Inc. + +OUI:B898F7* + ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen + +OUI:B89AED* + ID_OUI_FROM_DATABASE=OceanServer Technology, Inc + +OUI:B89BC9* + ID_OUI_FROM_DATABASE=SMC Networks Inc + +OUI:B8A386* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:B8A3E0* + ID_OUI_FROM_DATABASE=BenRui Technology Co.,Ltd + +OUI:B8A8AF* + ID_OUI_FROM_DATABASE=Logic S.p.A. + +OUI:B8AC6F* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:B8AE6E* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:B8AF67* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:B8B1C7* + ID_OUI_FROM_DATABASE=BT&COM CO.,LTD + +OUI:B8B42E* + ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen + +OUI:B8B7D7* + ID_OUI_FROM_DATABASE=2GIG Technologies + +OUI:B8B94E* + ID_OUI_FROM_DATABASE=Shenzhen iBaby Labs, Inc. + +OUI:B8BA68* + ID_OUI_FROM_DATABASE=Xi'an Jizhong Digital Communication Co.,Ltd + +OUI:B8BA72* + ID_OUI_FROM_DATABASE=Cynove + +OUI:B8BB6D* + ID_OUI_FROM_DATABASE=ENERES Co.,Ltd. + +OUI:B8BEBF* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:B8C1A2* + ID_OUI_FROM_DATABASE=Dragon Path Technologies Co., Limited + +OUI:B8C46F* + ID_OUI_FROM_DATABASE=PRIMMCON INDUSTRIES INC + +OUI:B8C68E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B8C716* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:B8C75D* + ID_OUI_FROM_DATABASE=Apple + +OUI:B8C855* + ID_OUI_FROM_DATABASE=Shanghai GBCOM Communication Technology Co.,Ltd. + +OUI:B8CA3A* + ID_OUI_FROM_DATABASE=Dell PCBA Test + +OUI:B8CD93* + ID_OUI_FROM_DATABASE=Penetek, Inc + +OUI:B8CDA7* + ID_OUI_FROM_DATABASE=Maxeler Technologies Ltd. + +OUI:B8D06F* + ID_OUI_FROM_DATABASE=GUANGZHOU HKUST FOK YING TUNG RESEARCH INSTITUTE + +OUI:B8D49D* + ID_OUI_FROM_DATABASE=M Seven System Ltd. + +OUI:B8D9CE* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:B8DAF1* + ID_OUI_FROM_DATABASE=Strahlenschutz- Entwicklungs- und Ausruestungsgesellschaft mbH + +OUI:B8DAF7* + ID_OUI_FROM_DATABASE=Advanced Photonics, Inc. + +OUI:B8DC87* + ID_OUI_FROM_DATABASE=IAI Corporation + +OUI:B8DF6B* + ID_OUI_FROM_DATABASE=SpotCam Co., Ltd. + +OUI:B8E589* + ID_OUI_FROM_DATABASE=Payter BV + +OUI:B8E625* + ID_OUI_FROM_DATABASE=2Wire + +OUI:B8E779* + ID_OUI_FROM_DATABASE=9Solutions Oy + +OUI:B8E856* + ID_OUI_FROM_DATABASE=Apple + +OUI:B8E937* + ID_OUI_FROM_DATABASE=Sonos, Inc. + +OUI:B8EE79* + ID_OUI_FROM_DATABASE=YWire Technologies, Inc. + +OUI:B8F4D0* + ID_OUI_FROM_DATABASE=Herrmann Ultraschalltechnik GmbH & Co. Kg + +OUI:B8F5E7* + ID_OUI_FROM_DATABASE=WayTools, LLC + +OUI:B8F6B1* + ID_OUI_FROM_DATABASE=Apple + +OUI:B8F732* + ID_OUI_FROM_DATABASE=Aryaka Networks Inc + +OUI:B8F828* + ID_OUI_FROM_DATABASE=Changshu Gaoshida Optoelectronic Technology Co. Ltd. + +OUI:B8F934* + ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +OUI:B8FD32* + ID_OUI_FROM_DATABASE=Zhejiang ROICX Microelectronics + +OUI:B8FF61* + ID_OUI_FROM_DATABASE=Apple + +OUI:B8FF6F* + ID_OUI_FROM_DATABASE=Shanghai Typrotech Technology Co.Ltd + +OUI:B8FFFE* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:BC0200* + ID_OUI_FROM_DATABASE=Stewart Audio + +OUI:BC0543* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:BC0DA5* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:BC0F2B* + ID_OUI_FROM_DATABASE=FORTUNE TECHGROUP CO.,LTD + +OUI:BC125E* + ID_OUI_FROM_DATABASE=Beijing WisVideo INC. + +OUI:BC1401* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:BC14EF* + ID_OUI_FROM_DATABASE=ITON Technology Limited + +OUI:BC15A6* + ID_OUI_FROM_DATABASE=Taiwan Jantek Electronics,Ltd. + +OUI:BC1665* + ID_OUI_FROM_DATABASE=Cisco + +OUI:BC1A67* + ID_OUI_FROM_DATABASE=YF Technology Co., Ltd + +OUI:BC20A4* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:BC20BA* + ID_OUI_FROM_DATABASE=Inspur (Shandong) Electronic Information Co., Ltd + +OUI:BC261D* + ID_OUI_FROM_DATABASE=HONG KONG TECON TECHNOLOGY + +OUI:BC2846* + ID_OUI_FROM_DATABASE=NextBIT Computing Pvt. Ltd. + +OUI:BC28D6* + ID_OUI_FROM_DATABASE=Rowley Associates Limited + +OUI:BC2B6B* + ID_OUI_FROM_DATABASE=Beijing Haier IC Design Co.,Ltd + +OUI:BC2BD7* + ID_OUI_FROM_DATABASE=Revogi Innovation Co., Ltd. + +OUI:BC2C55* + ID_OUI_FROM_DATABASE=Bear Flag Design, Inc. + +OUI:BC2D98* + ID_OUI_FROM_DATABASE=ThinGlobal LLC + +OUI:BC305B* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:BC307D* + ID_OUI_FROM_DATABASE=Wistron Neweb Corp. + +OUI:BC35E5* + ID_OUI_FROM_DATABASE=Hydro Systems Company + +OUI:BC38D2* + ID_OUI_FROM_DATABASE=Pandachip Limited + +OUI:BC39A6* + ID_OUI_FROM_DATABASE=CSUN System Technology Co.,LTD + +OUI:BC3BAF* + ID_OUI_FROM_DATABASE=Apple + +OUI:BC3E13* + ID_OUI_FROM_DATABASE=Accordance Systems Inc. + +OUI:BC4100* + ID_OUI_FROM_DATABASE=Codaco Electronic s.r.o. + +OUI:BC4377* + ID_OUI_FROM_DATABASE=Hang Zhou Huite Technology Co.,ltd. + +OUI:BC4486* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:BC4760* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:BC4B79* + ID_OUI_FROM_DATABASE=SensingTek + +OUI:BC4E3C* + ID_OUI_FROM_DATABASE=CORE STAFF CO., LTD. + +OUI:BC51FE* + ID_OUI_FROM_DATABASE=Swann Communications Pty Ltd + +OUI:BC52B7* + ID_OUI_FROM_DATABASE=Apple + +OUI:BC5FF4* + ID_OUI_FROM_DATABASE=ASRock Incorporation + +OUI:BC629F* + ID_OUI_FROM_DATABASE=Telenet Systems P. Ltd. + +OUI:BC6778* + ID_OUI_FROM_DATABASE=Apple + +OUI:BC6784* + ID_OUI_FROM_DATABASE=Environics Oy + +OUI:BC6A16* + ID_OUI_FROM_DATABASE=tdvine + +OUI:BC6A29* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:BC6E76* + ID_OUI_FROM_DATABASE=Green Energy Options Ltd + +OUI:BC71C1* + ID_OUI_FROM_DATABASE=XTrillion, Inc. + +OUI:BC72B1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:BC764E* + ID_OUI_FROM_DATABASE=Rackspace US, Inc. + +OUI:BC7670* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:BC7737* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:BC779F* + ID_OUI_FROM_DATABASE=SBM Co., Ltd. + +OUI:BC79AD* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:BC7DD1* + ID_OUI_FROM_DATABASE=Radio Data Comms + +OUI:BC811F* + ID_OUI_FROM_DATABASE=Ingate Systems + +OUI:BC8199* + ID_OUI_FROM_DATABASE=BASIC Co.,Ltd. + +OUI:BC83A7* + ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LT + +OUI:BC851F* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:BC8556* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:BC8893* + ID_OUI_FROM_DATABASE=VILLBAU Ltd. + +OUI:BC8B55* + ID_OUI_FROM_DATABASE=NPP ELIKS America Inc. DBA T&M Atlantic + +OUI:BC8CCD* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:BC926B* + ID_OUI_FROM_DATABASE=Apple + +OUI:BC9680* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:BC9889* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:BC99BC* + ID_OUI_FROM_DATABASE=FonSee Technology Inc. + +OUI:BC9DA5* + ID_OUI_FROM_DATABASE=DASCOM Europe GmbH + +OUI:BCA4E1* + ID_OUI_FROM_DATABASE=Nabto + +OUI:BCA9D6* + ID_OUI_FROM_DATABASE=Cyber-Rain, Inc. + +OUI:BCAEC5* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:BCB181* + ID_OUI_FROM_DATABASE=SHARP CORPORATION + +OUI:BCB1F3* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:BCB852* + ID_OUI_FROM_DATABASE=Cybera, Inc. + +OUI:BCBAE1* + ID_OUI_FROM_DATABASE=AREC Inc. + +OUI:BCBBC9* + ID_OUI_FROM_DATABASE=Kellendonk Elektronik GmbH + +OUI:BCC168* + ID_OUI_FROM_DATABASE=DinBox Sverige AB + +OUI:BCC23A* + ID_OUI_FROM_DATABASE=Thomson Video Networks + +OUI:BCC61A* + ID_OUI_FROM_DATABASE=SPECTRA EMBEDDED SYSTEMS + +OUI:BCC6DB* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:BCC810* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:BCCD45* + ID_OUI_FROM_DATABASE=VOISMART + +OUI:BCCFCC* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:BCD177* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:BCD5B6* + ID_OUI_FROM_DATABASE=d2d technologies + +OUI:BCD940* + ID_OUI_FROM_DATABASE=ASR Co,.Ltd. + +OUI:BCE09D* + ID_OUI_FROM_DATABASE=Eoslink + +OUI:BCE59F* + ID_OUI_FROM_DATABASE=WATERWORLD Technology Co.,LTD + +OUI:BCEA2B* + ID_OUI_FROM_DATABASE=CityCom GmbH + +OUI:BCEE7B* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:BCF2AF* + ID_OUI_FROM_DATABASE=devolo AG + +OUI:BCF5AC* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:BCF61C* + ID_OUI_FROM_DATABASE=Geomodeling Wuxi Technology Co. Ltd. + +OUI:BCF685* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:BCFE8C* + ID_OUI_FROM_DATABASE=Altronic, LLC + +OUI:BCFFAC* + ID_OUI_FROM_DATABASE=TOPCON CORPORATION + +OUI:C00D7E* + ID_OUI_FROM_DATABASE=Additech, Inc. + +OUI:C011A6* + ID_OUI_FROM_DATABASE=Fort-Telecom ltd. + +OUI:C01242* + ID_OUI_FROM_DATABASE=Alpha Security Products + +OUI:C0143D* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C01885* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C01E9B* + ID_OUI_FROM_DATABASE=Pixavi AS + +OUI:C02506* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:C0255C* + ID_OUI_FROM_DATABASE=Cisco + +OUI:C027B9* + ID_OUI_FROM_DATABASE=Beijing National Railway Research & Design Institute of Signal & Communication Co., Ltd. + +OUI:C02973* + ID_OUI_FROM_DATABASE=Audyssey Laboratories Inc. + +OUI:C029F3* + ID_OUI_FROM_DATABASE=XySystem + +OUI:C02BFC* + ID_OUI_FROM_DATABASE=iNES. applied informatics GmbH + +OUI:C02C7A* + ID_OUI_FROM_DATABASE=Shen Zhen Horn audio Co., Ltd. + +OUI:C034B4* + ID_OUI_FROM_DATABASE=Gigastone Corporation + +OUI:C03580* + ID_OUI_FROM_DATABASE=A&R TECH + +OUI:C035BD* + ID_OUI_FROM_DATABASE=Velocytech Aps + +OUI:C038F9* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:C03B8F* + ID_OUI_FROM_DATABASE=Minicom Digital Signage + +OUI:C03E0F* + ID_OUI_FROM_DATABASE=BSkyB Ltd + +OUI:C03F0E* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:C03F2A* + ID_OUI_FROM_DATABASE=Biscotti, Inc. + +OUI:C03FD5* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., LTD + +OUI:C041F6* + ID_OUI_FROM_DATABASE=LG Electronics Inc + +OUI:C04301* + ID_OUI_FROM_DATABASE=Epec Oy + +OUI:C044E3* + ID_OUI_FROM_DATABASE=Shenzhen Sinkna Electronics Co., LTD + +OUI:C0493D* + ID_OUI_FROM_DATABASE=MAITRISE TECHNOLOGIQUE + +OUI:C04A00* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:C04DF7* + ID_OUI_FROM_DATABASE=SERELEC + +OUI:C057BC* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:C058A7* + ID_OUI_FROM_DATABASE=Pico Systems Co., Ltd. + +OUI:C05E6F* + ID_OUI_FROM_DATABASE=V. Stonkaus firma "Kodinis Raktas" + +OUI:C05E79* + ID_OUI_FROM_DATABASE=SHENZHEN HUAXUN ARK TECHNOLOGIES CO.,LTD + +OUI:C0626B* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C06394* + ID_OUI_FROM_DATABASE=Apple + +OUI:C064C6* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:C06599* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C067AF* + ID_OUI_FROM_DATABASE=Cisco + +OUI:C06C0F* + ID_OUI_FROM_DATABASE=Dobbs Stanford + +OUI:C06C6D* + ID_OUI_FROM_DATABASE=MagneMotion, Inc. + +OUI:C07BBC* + ID_OUI_FROM_DATABASE=Cisco + +OUI:C07E40* + ID_OUI_FROM_DATABASE=SHENZHEN XDK COMMUNICATION EQUIPMENT CO.,LTD + +OUI:C08170* + ID_OUI_FROM_DATABASE=Effigis GeoSolutions + +OUI:C0830A* + ID_OUI_FROM_DATABASE=2Wire + +OUI:C0847A* + ID_OUI_FROM_DATABASE=Apple + +OUI:C0885B* + ID_OUI_FROM_DATABASE=SnD Tech Co., Ltd. + +OUI:C08ADE* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:C08B6F* + ID_OUI_FROM_DATABASE=S I Sistemas Inteligentes Eletrônicos Ltda + +OUI:C08C60* + ID_OUI_FROM_DATABASE=Cisco + +OUI:C09132* + ID_OUI_FROM_DATABASE=Patriot Memory + +OUI:C09134* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:C098E5* + ID_OUI_FROM_DATABASE=University of Michigan + +OUI:C09C92* + ID_OUI_FROM_DATABASE=COBY + +OUI:C09D26* + ID_OUI_FROM_DATABASE=Topicon HK Lmd. + +OUI:C09F42* + ID_OUI_FROM_DATABASE=Apple + +OUI:C0A0BB* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:C0A0C7* + ID_OUI_FROM_DATABASE=FAIRFIELD INDUSTRIES + +OUI:C0A0DE* + ID_OUI_FROM_DATABASE=Multi Touch Oy + +OUI:C0A0E2* + ID_OUI_FROM_DATABASE=Eden Innovations + +OUI:C0A26D* + ID_OUI_FROM_DATABASE=Abbott Point of Care + +OUI:C0A364* + ID_OUI_FROM_DATABASE=3D Systems Massachusetts + +OUI:C0A39E* + ID_OUI_FROM_DATABASE=EarthCam, Inc. + +OUI:C0AA68* + ID_OUI_FROM_DATABASE=OSASI Technos Inc. + +OUI:C0AC54* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:C0B339* + ID_OUI_FROM_DATABASE=Comigo Ltd. + +OUI:C0B357* + ID_OUI_FROM_DATABASE=Yoshiki Electronics Industry Ltd. + +OUI:C0B8B1* + ID_OUI_FROM_DATABASE=BitBox Ltd + +OUI:C0BAE6* + ID_OUI_FROM_DATABASE=Application Solutions (Electronics and Vision) Ltd + +OUI:C0BD42* + ID_OUI_FROM_DATABASE=ZPA Smart Energy a.s. + +OUI:C0C1C0* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:C0C3B6* + ID_OUI_FROM_DATABASE=Automatic Systems + +OUI:C0C520* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:C0C569* + ID_OUI_FROM_DATABASE=SHANGHAI LYNUC CNC TECHNOLOGY CO.,LTD + +OUI:C0C687* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:C0C946* + ID_OUI_FROM_DATABASE=MITSUYA LABORATORIES INC. + +OUI:C0CB38* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C0CFA3* + ID_OUI_FROM_DATABASE=Creative Electronics & Software, Inc. + +OUI:C0D044* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:C0D962* + ID_OUI_FROM_DATABASE=Askey Computer Corp. + +OUI:C0DA74* + ID_OUI_FROM_DATABASE=Hangzhou Sunyard Technology Co., Ltd. + +OUI:C0DF77* + ID_OUI_FROM_DATABASE=Conrad Electronic SE + +OUI:C0E422* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:C0E54E* + ID_OUI_FROM_DATABASE=DENX Computer Systems GmbH + +OUI:C0EAE4* + ID_OUI_FROM_DATABASE=Sonicwall + +OUI:C0F1C4* + ID_OUI_FROM_DATABASE=Pacidal Corporation Ltd. + +OUI:C0F79D* + ID_OUI_FROM_DATABASE=Powercode + +OUI:C0F8DA* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C0F991* + ID_OUI_FROM_DATABASE=GME Standard Communications P/L + +OUI:C40142* + ID_OUI_FROM_DATABASE=MaxMedia Technology Limited + +OUI:C4017C* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:C401B1* + ID_OUI_FROM_DATABASE=SeekTech INC + +OUI:C40415* + ID_OUI_FROM_DATABASE=NETGEAR INC., + +OUI:C40528* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:C40938* + ID_OUI_FROM_DATABASE=Fujian Star-net Communication Co., Ltd + +OUI:C40ACB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C40E45* + ID_OUI_FROM_DATABASE=ACK Networks,Inc. + +OUI:C40F09* + ID_OUI_FROM_DATABASE=Hermes electronic GmbH + +OUI:C4108A* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:C4143C* + ID_OUI_FROM_DATABASE=Cisco + +OUI:C416FA* + ID_OUI_FROM_DATABASE=Prysm Inc + +OUI:C417FE* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C4198B* + ID_OUI_FROM_DATABASE=Dominion Voting Systems Corporation + +OUI:C419EC* + ID_OUI_FROM_DATABASE=Qualisys AB + +OUI:C41ECE* + ID_OUI_FROM_DATABASE=HMI Sources Ltd. + +OUI:C421C8* + ID_OUI_FROM_DATABASE=KYOCERA Corporation + +OUI:C4237A* + ID_OUI_FROM_DATABASE=WhizNets Inc. + +OUI:C4242E* + ID_OUI_FROM_DATABASE=Galvanic Applied Sciences Inc + +OUI:C42628* + ID_OUI_FROM_DATABASE=Airo Wireless + +OUI:C42795* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:C4291D* + ID_OUI_FROM_DATABASE=KLEMSAN ELEKTRIK ELEKTRONIK SAN.VE TIC.AS. + +OUI:C42C03* + ID_OUI_FROM_DATABASE=Apple + +OUI:C436DA* + ID_OUI_FROM_DATABASE=Rusteletech Ltd. + +OUI:C438D3* + ID_OUI_FROM_DATABASE=TAGATEC CO.,LTD + +OUI:C4393A* + ID_OUI_FROM_DATABASE=SMC Networks Inc + +OUI:C43A9F* + ID_OUI_FROM_DATABASE=Siconix Inc. + +OUI:C43C3C* + ID_OUI_FROM_DATABASE=CYBELEC SA + +OUI:C43DC7* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:C4438F* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:C44567* + ID_OUI_FROM_DATABASE=SAMBON PRECISON and ELECTRONICS + +OUI:C445EC* + ID_OUI_FROM_DATABASE=Shanghai Yali Electron Co.,LTD + +OUI:C44619* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:C44838* + ID_OUI_FROM_DATABASE=Satcom Direct, Inc. + +OUI:C44AD0* + ID_OUI_FROM_DATABASE=FIREFLIES SYSTEMS + +OUI:C44B44* + ID_OUI_FROM_DATABASE=Omniprint Inc. + +OUI:C44E1F* + ID_OUI_FROM_DATABASE=BlueN + +OUI:C44EAC* + ID_OUI_FROM_DATABASE=Shenzhen Shiningworth Technology Co., Ltd. + +OUI:C45006* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C45444* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. + +OUI:C455A6* + ID_OUI_FROM_DATABASE=Cadac Holdings Ltd + +OUI:C455C2* + ID_OUI_FROM_DATABASE=Bach-Simpson + +OUI:C45600* + ID_OUI_FROM_DATABASE=Galleon Embedded Computing + +OUI:C458C2* + ID_OUI_FROM_DATABASE=Shenzhen TATFOOK Technology Co., Ltd. + +OUI:C45976* + ID_OUI_FROM_DATABASE=Fugoo Coorporation + +OUI:C45DD8* + ID_OUI_FROM_DATABASE=HDMI Forum + +OUI:C46044* + ID_OUI_FROM_DATABASE=Everex Electronics Limited + +OUI:C4626B* + ID_OUI_FROM_DATABASE=ZPT Vigantice + +OUI:C462EA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C46354* + ID_OUI_FROM_DATABASE=U-Raku, Inc. + +OUI:C46413* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C467B5* + ID_OUI_FROM_DATABASE=Libratone A/S + +OUI:C46AB7* + ID_OUI_FROM_DATABASE=Xiaomi Technology,Inc. + +OUI:C46DF1* + ID_OUI_FROM_DATABASE=DataGravity + +OUI:C46E1F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD + +OUI:C47130* + ID_OUI_FROM_DATABASE=Fon Technology S.L. + +OUI:C471FE* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C4731E* + ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd + +OUI:C47B2F* + ID_OUI_FROM_DATABASE=Beijing JoinHope Image Technology Ltd. + +OUI:C47BA3* + ID_OUI_FROM_DATABASE=NAVIS Inc. + +OUI:C47D4F* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C47DCC* + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. + +OUI:C47DFE* + ID_OUI_FROM_DATABASE=A.N. Solutions GmbH + +OUI:C47F51* + ID_OUI_FROM_DATABASE=Inventek Systems + +OUI:C4823F* + ID_OUI_FROM_DATABASE=Fujian Newland Auto-ID Tech. Co,.Ltd. + +OUI:C4824E* + ID_OUI_FROM_DATABASE=Changzhou Uchip Electronics Co., LTD. + +OUI:C48508* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:C488E5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C49300* + ID_OUI_FROM_DATABASE=8Devices + +OUI:C49313* + ID_OUI_FROM_DATABASE=100fio networks technology llc + +OUI:C49380* + ID_OUI_FROM_DATABASE=Speedytel technology + +OUI:C495A2* + ID_OUI_FROM_DATABASE=SHENZHEN WEIJIU INDUSTRY AND TRADE DEVELOPMENT CO., LTD + +OUI:C49805* + ID_OUI_FROM_DATABASE=Minieum Networks, Inc + +OUI:C4A81D* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:C4AAA1* + ID_OUI_FROM_DATABASE=SUMMIT DEVELOPMENT, spol.s r.o. + +OUI:C4AD21* + ID_OUI_FROM_DATABASE=MEDIAEDGE Corporation + +OUI:C4B512* + ID_OUI_FROM_DATABASE=General Electric Digital Energy + +OUI:C4BA99* + ID_OUI_FROM_DATABASE=I+ME Actia Informatik und Mikro-Elektronik GmbH + +OUI:C4C0AE* + ID_OUI_FROM_DATABASE=MIDORI ELECTRONIC CO., LTD. + +OUI:C4C19F* + ID_OUI_FROM_DATABASE=National Oilwell Varco Instrumentation, Monitoring, and Optimization (NOV IMO) + +OUI:C4C755* + ID_OUI_FROM_DATABASE=Beijing HuaqinWorld Technology Co.,Ltd + +OUI:C4C919* + ID_OUI_FROM_DATABASE=Energy Imports Ltd + +OUI:C4CAD9* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:C4CD45* + ID_OUI_FROM_DATABASE=Beijing Boomsense Technology CO.,LTD. + +OUI:C4D489* + ID_OUI_FROM_DATABASE=JiangSu Joyque Information Industry Co.,Ltd + +OUI:C4D655* + ID_OUI_FROM_DATABASE=Tercel technology co.,ltd + +OUI:C4D987* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:C4DA26* + ID_OUI_FROM_DATABASE=NOBLEX SA + +OUI:C4E032* + ID_OUI_FROM_DATABASE=IEEE 1904.1 Working Group + +OUI:C4E17C* + ID_OUI_FROM_DATABASE=U2S co. + +OUI:C4E7BE* + ID_OUI_FROM_DATABASE=SCSpro Co.,Ltd + +OUI:C4E92F* + ID_OUI_FROM_DATABASE=AB Sciex + +OUI:C4E984* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:C4EBE3* + ID_OUI_FROM_DATABASE=RRCN SAS + +OUI:C4EDBA* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:C4EEAE* + ID_OUI_FROM_DATABASE=VSS Monitoring + +OUI:C4EEF5* + ID_OUI_FROM_DATABASE=Oclaro, Inc. + +OUI:C4F464* + ID_OUI_FROM_DATABASE=Spica international + +OUI:C4F57C* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:C4FCE4* + ID_OUI_FROM_DATABASE=DishTV NZ Ltd + +OUI:C80258* + ID_OUI_FROM_DATABASE=ITW GSE ApS + +OUI:C802A6* + ID_OUI_FROM_DATABASE=Beijing Newmine Technology + +OUI:C80718* + ID_OUI_FROM_DATABASE=TDSi + +OUI:C80AA9* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:C80E77* + ID_OUI_FROM_DATABASE=Le Shi Zhi Xin Electronic Technology (Tianjin) Co.,Ltd + +OUI:C80E95* + ID_OUI_FROM_DATABASE=OmniLync Inc. + +OUI:C81479* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C816BD* + ID_OUI_FROM_DATABASE=HISENSE ELECTRIC CO.,LTD. + +OUI:C819F7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C81AFE* + ID_OUI_FROM_DATABASE=DLOGIC GmbH + +OUI:C81E8E* + ID_OUI_FROM_DATABASE=ADV Security (S) Pte Ltd + +OUI:C81F66* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:C8208E* + ID_OUI_FROM_DATABASE=Storagedata + +OUI:C8292A* + ID_OUI_FROM_DATABASE=Barun Electronics + +OUI:C82A14* + ID_OUI_FROM_DATABASE=Apple + +OUI:C82E94* + ID_OUI_FROM_DATABASE=Halfa Enterprise Co., Ltd. + +OUI:C83232* + ID_OUI_FROM_DATABASE=Hunting Innova + +OUI:C8334B* + ID_OUI_FROM_DATABASE=Apple + +OUI:C835B8* + ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K + +OUI:C83A35* + ID_OUI_FROM_DATABASE=Tenda Technology Co., Ltd. + +OUI:C83B45* + ID_OUI_FROM_DATABASE=JRI-Maxant + +OUI:C83D97* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:C83E99* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:C83EA7* + ID_OUI_FROM_DATABASE=KUNBUS GmbH + +OUI:C84529* + ID_OUI_FROM_DATABASE=IMK Networks Co.,Ltd + +OUI:C84544* + ID_OUI_FROM_DATABASE=Shanghai Enlogic Electric Technology Co., Ltd. + +OUI:C848F5* + ID_OUI_FROM_DATABASE=MEDISON Xray Co., Ltd + +OUI:C84C75* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C85645* + ID_OUI_FROM_DATABASE=Intermas France + +OUI:C85663* + ID_OUI_FROM_DATABASE=Sunflex Europe GmbH + +OUI:C86000* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:C864C7* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:C86C1E* + ID_OUI_FROM_DATABASE=Display Systems Ltd + +OUI:C86C87* + ID_OUI_FROM_DATABASE=Zyxel Communications Corp + +OUI:C86CB6* + ID_OUI_FROM_DATABASE=Optcom Co., Ltd. + +OUI:C86F1D* + ID_OUI_FROM_DATABASE=Apple + +OUI:C87248* + ID_OUI_FROM_DATABASE=Aplicom Oy + +OUI:C87B5B* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:C87CBC* + ID_OUI_FROM_DATABASE=Valink Co., Ltd. + +OUI:C87D77* + ID_OUI_FROM_DATABASE=Shenzhen Kingtech Communication Equipment Co.,Ltd + +OUI:C87E75* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:C88439* + ID_OUI_FROM_DATABASE=Sunrise Technologies + +OUI:C88447* + ID_OUI_FROM_DATABASE=Beautiful Enterprise Co., Ltd + +OUI:C8873B* + ID_OUI_FROM_DATABASE=Net Optics + +OUI:C88A83* + ID_OUI_FROM_DATABASE=Dongguan HuaHong Electronics Co.,Ltd + +OUI:C88B47* + ID_OUI_FROM_DATABASE=Nolangroup S.P.A con Socio Unico + +OUI:C8903E* + ID_OUI_FROM_DATABASE=Pakton Technologies + +OUI:C89346* + ID_OUI_FROM_DATABASE=MXCHIP Company Limited + +OUI:C89383* + ID_OUI_FROM_DATABASE=Embedded Automation, Inc. + +OUI:C894D2* + ID_OUI_FROM_DATABASE=Jiangsu Datang Electronic Products Co., Ltd + +OUI:C8979F* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:C89C1D* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C89CDC* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. + +OUI:C89F42* + ID_OUI_FROM_DATABASE=VDII Innovation AB + +OUI:C8A030* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:C8A1B6* + ID_OUI_FROM_DATABASE=Shenzhen Longway Technologies Co., Ltd + +OUI:C8A1BA* + ID_OUI_FROM_DATABASE=Neul Ltd + +OUI:C8A620* + ID_OUI_FROM_DATABASE=Nebula, Inc + +OUI:C8A70A* + ID_OUI_FROM_DATABASE=Verizon Business + +OUI:C8A729* + ID_OUI_FROM_DATABASE=SYStronics Co., Ltd. + +OUI:C8AA21* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:C8AE9C* + ID_OUI_FROM_DATABASE=Shanghai TYD Elecronic Technology Co. Ltd + +OUI:C8AF40* + ID_OUI_FROM_DATABASE=marco Systemanalyse und Entwicklung GmbH + +OUI:C8B373* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:C8B5B7* + ID_OUI_FROM_DATABASE=Apple + +OUI:C8BBD3* + ID_OUI_FROM_DATABASE=Embrane + +OUI:C8BCC8* + ID_OUI_FROM_DATABASE=Apple + +OUI:C8BE19* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:C8C126* + ID_OUI_FROM_DATABASE=ZPM Industria e Comercio Ltda + +OUI:C8C13C* + ID_OUI_FROM_DATABASE=RuggedTek Hangzhou Co., Ltd + +OUI:C8C791* + ID_OUI_FROM_DATABASE=Zero1.tv GmbH + +OUI:C8CBB8* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:C8CD72* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:C8D10B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:C8D15E* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:C8D1D1* + ID_OUI_FROM_DATABASE=AGAiT Technology Corporation + +OUI:C8D2C1* + ID_OUI_FROM_DATABASE=Jetlun (Shenzhen) Corporation + +OUI:C8D3A3* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:C8D429* + ID_OUI_FROM_DATABASE=Muehlbauer AG + +OUI:C8D5FE* + ID_OUI_FROM_DATABASE=Shenzhen Zowee Technology Co., Ltd + +OUI:C8D719* + ID_OUI_FROM_DATABASE=Cisco Consumer Products, LLC + +OUI:C8DDC9* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:C8DE51* + ID_OUI_FROM_DATABASE=Integra Networks, Inc. + +OUI:C8DF7C* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:C8E0EB* + ID_OUI_FROM_DATABASE=Apple + +OUI:C8E1A7* + ID_OUI_FROM_DATABASE=Vertu Corporation Limited + +OUI:C8EE08* + ID_OUI_FROM_DATABASE=TANGTOP TECHNOLOGY CO.,LTD + +OUI:C8EE75* + ID_OUI_FROM_DATABASE=Pishion International Co. Ltd + +OUI:C8EEA6* + ID_OUI_FROM_DATABASE=Shenzhen SHX Technology Co., Ltd + +OUI:C8EF2E* + ID_OUI_FROM_DATABASE=Beijing Gefei Tech. Co., Ltd + +OUI:C8F36B* + ID_OUI_FROM_DATABASE=Yamato Scale Co.,Ltd. + +OUI:C8F386* + ID_OUI_FROM_DATABASE=Shenzhen Xiaoniao Technology Co.,Ltd + +OUI:C8F406* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:C8F68D* + ID_OUI_FROM_DATABASE=S.E.TECHNOLOGIES LIMITED + +OUI:C8F704* + ID_OUI_FROM_DATABASE=Building Block Video + +OUI:C8F733* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:C8F981* + ID_OUI_FROM_DATABASE=Seneca s.r.l. + +OUI:C8F9F9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:C8FB26* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:C8FE30* + ID_OUI_FROM_DATABASE=Bejing DAYO Mobile Communication Technology Ltd. + +OUI:CC0080* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:CC047C* + ID_OUI_FROM_DATABASE=G-WAY Microwave + +OUI:CC04B4* + ID_OUI_FROM_DATABASE=Select Comfort + +OUI:CC051B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:CC07AB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:CC08E0* + ID_OUI_FROM_DATABASE=Apple + +OUI:CC09C8* + ID_OUI_FROM_DATABASE=IMAQLIQ LTD + +OUI:CC0CDA* + ID_OUI_FROM_DATABASE=Miljovakt AS + +OUI:CC0DEC* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:CC14A6* + ID_OUI_FROM_DATABASE=Yichun MyEnergy Domain, Inc + +OUI:CC187B* + ID_OUI_FROM_DATABASE=Manzanita Systems, Inc. + +OUI:CC1AFA* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:CC1EFF* + ID_OUI_FROM_DATABASE=Metrological Group BV + +OUI:CC2218* + ID_OUI_FROM_DATABASE=InnoDigital Co., Ltd. + +OUI:CC262D* + ID_OUI_FROM_DATABASE=Verifi, LLC + +OUI:CC2A80* + ID_OUI_FROM_DATABASE=Micro-Biz intelligence solutions Co.,Ltd + +OUI:CC2D8C* + ID_OUI_FROM_DATABASE=LG ELECTRONICS INC + +OUI:CC33BB* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:CC3429* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:CC34D7* + ID_OUI_FROM_DATABASE=GEWISS S.P.A. + +OUI:CC3540* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:CC398C* + ID_OUI_FROM_DATABASE=Shiningtek + +OUI:CC3A61* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO., LTD. + +OUI:CC3C3F* + ID_OUI_FROM_DATABASE=SA.S.S. Datentechnik AG + +OUI:CC3E5F* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:CC43E3* + ID_OUI_FROM_DATABASE=Trump s.a. + +OUI:CC4703* + ID_OUI_FROM_DATABASE=Intercon Systems Co., Ltd. + +OUI:CC4AE1* + ID_OUI_FROM_DATABASE=Fourtec -Fourier Technologies + +OUI:CC4BFB* + ID_OUI_FROM_DATABASE=Hellberg Safety AB + +OUI:CC4E24* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:CC501C* + ID_OUI_FROM_DATABASE=KVH Industries, Inc. + +OUI:CC5076* + ID_OUI_FROM_DATABASE=Ocom Communications, Inc. + +OUI:CC52AF* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:CC53B5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:CC5459* + ID_OUI_FROM_DATABASE=OnTime Networks AS + +OUI:CC55AD* + ID_OUI_FROM_DATABASE=RIM + +OUI:CC593E* + ID_OUI_FROM_DATABASE=TOUMAZ LTD + +OUI:CC5C75* + ID_OUI_FROM_DATABASE=Weightech Com. Imp. Exp. Equip. Pesagem Ltda + +OUI:CC5D4E* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:CC5D57* + ID_OUI_FROM_DATABASE=Information System Research Institute,Inc. + +OUI:CC60BB* + ID_OUI_FROM_DATABASE=Empower RF Systems + +OUI:CC65AD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:CC69B0* + ID_OUI_FROM_DATABASE=Global Traffic Technologies, LLC + +OUI:CC6B98* + ID_OUI_FROM_DATABASE=Minetec Wireless Technologies + +OUI:CC6BF1* + ID_OUI_FROM_DATABASE=Sound Masking Inc. + +OUI:CC6DA0* + ID_OUI_FROM_DATABASE=Roku, Inc. + +OUI:CC6DEF* + ID_OUI_FROM_DATABASE=TJK Tietolaite Oy + +OUI:CC720F* + ID_OUI_FROM_DATABASE=Viscount Systems Inc. + +OUI:CC7498* + ID_OUI_FROM_DATABASE=Filmetrics Inc. + +OUI:CC7669* + ID_OUI_FROM_DATABASE=SEETECH + +OUI:CC785F* + ID_OUI_FROM_DATABASE=Apple + +OUI:CC7A30* + ID_OUI_FROM_DATABASE=CMAX Wireless Co., Ltd. + +OUI:CC7B35* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:CC7D37* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:CC7EE7* + ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company + +OUI:CC856C* + ID_OUI_FROM_DATABASE=SHENZHEN MDK DIGITAL TECHNOLOGY CO.,LTD + +OUI:CC89FD* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:CC8CE3* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:CC9093* + ID_OUI_FROM_DATABASE=Hansong Tehnologies + +OUI:CC912B* + ID_OUI_FROM_DATABASE=TE Connectivity Touch Solutions + +OUI:CC944A* + ID_OUI_FROM_DATABASE=Pfeiffer Vacuum GmbH + +OUI:CC95D7* + ID_OUI_FROM_DATABASE=VIZIO, Inc + +OUI:CC96A0* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:CC9E00* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:CC9F35* + ID_OUI_FROM_DATABASE=Transbit Sp. z o.o. + +OUI:CCA374* + ID_OUI_FROM_DATABASE=Guangdong Guanglian Electronic Technology Co.Ltd + +OUI:CCA462* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:CCA614* + ID_OUI_FROM_DATABASE=AIFA TECHNOLOGY CORP. + +OUI:CCAF78* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:CCB255* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:CCB3F8* + ID_OUI_FROM_DATABASE=FUJITSU ISOTEC LIMITED + +OUI:CCB55A* + ID_OUI_FROM_DATABASE=Fraunhofer ITWM + +OUI:CCB888* + ID_OUI_FROM_DATABASE=AnB Securite s.a. + +OUI:CCB8F1* + ID_OUI_FROM_DATABASE=EAGLE KINGDOM TECHNOLOGIES LIMITED + +OUI:CCBD35* + ID_OUI_FROM_DATABASE=Steinel GmbH + +OUI:CCBE71* + ID_OUI_FROM_DATABASE=OptiLogix BV + +OUI:CCC104* + ID_OUI_FROM_DATABASE=Applied Technical Systems + +OUI:CCC50A* + ID_OUI_FROM_DATABASE=SHENZHEN DAJIAHAO TECHNOLOGY CO.,LTD + +OUI:CCC62B* + ID_OUI_FROM_DATABASE=Tri-Systems Corporation + +OUI:CCC8D7* + ID_OUI_FROM_DATABASE=CIAS Elettronica srl + +OUI:CCCC4E* + ID_OUI_FROM_DATABASE=Sun Fountainhead USA. Corp + +OUI:CCCC81* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:CCCD64* + ID_OUI_FROM_DATABASE=SM-Electronic GmbH + +OUI:CCCE40* + ID_OUI_FROM_DATABASE=Janteq Corp + +OUI:CCD29B* + ID_OUI_FROM_DATABASE=Shenzhen Bopengfa Elec&Technology CO.,Ltd + +OUI:CCD539* + ID_OUI_FROM_DATABASE=Cisco + +OUI:CCD811* + ID_OUI_FROM_DATABASE=Aiconn Technology Corporation + +OUI:CCD9E9* + ID_OUI_FROM_DATABASE=SCR Engineers Ltd. + +OUI:CCE798* + ID_OUI_FROM_DATABASE=My Social Stuff + +OUI:CCE7DF* + ID_OUI_FROM_DATABASE=American Magnetics, Inc. + +OUI:CCE8AC* + ID_OUI_FROM_DATABASE=SOYEA Technology Co.,Ltd. + +OUI:CCEA1C* + ID_OUI_FROM_DATABASE=DCONWORKS Co., Ltd + +OUI:CCEED9* + ID_OUI_FROM_DATABASE=Deto Mechatronic GmbH + +OUI:CCEF48* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:CCF3A5* + ID_OUI_FROM_DATABASE=Chi Mei Communication Systems, Inc + +OUI:CCF407* + ID_OUI_FROM_DATABASE=EUKREA ELECTROMATIQUE SARL + +OUI:CCF67A* + ID_OUI_FROM_DATABASE=Ayecka Communication Systems LTD + +OUI:CCF841* + ID_OUI_FROM_DATABASE=Lumewave + +OUI:CCF8F0* + ID_OUI_FROM_DATABASE=Xi'an HISU Multimedia Technology Co.,Ltd. + +OUI:CCF954* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:CCF9E8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:CCFA00* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:CCFB65* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:CCFC6D* + ID_OUI_FROM_DATABASE=RIZ TRANSMITTERS + +OUI:CCFCB1* + ID_OUI_FROM_DATABASE=Wireless Technology, Inc. + +OUI:CCFE3C* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:D00790* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D00EA4* + ID_OUI_FROM_DATABASE=Porsche Cars North America + +OUI:D0131E* + ID_OUI_FROM_DATABASE=Sunrex Technology Corp + +OUI:D0154A* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:D0176A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D01AA7* + ID_OUI_FROM_DATABASE=UniPrint + +OUI:D01CBB* + ID_OUI_FROM_DATABASE=Beijing Ctimes Digital Technology Co., Ltd. + +OUI:D022BE* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co.,LTD. + +OUI:D023DB* + ID_OUI_FROM_DATABASE=Apple + +OUI:D02788* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd + +OUI:D02C45* + ID_OUI_FROM_DATABASE=littleBits Electronics, Inc. + +OUI:D02DB3* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:D03110* + ID_OUI_FROM_DATABASE=Ingenic Semiconductor Co.,Ltd + +OUI:D03761* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D03972* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D046DC* + ID_OUI_FROM_DATABASE=Southwest Research Institute + +OUI:D04CC1* + ID_OUI_FROM_DATABASE=SINTRONES Technology Corp. + +OUI:D05099* + ID_OUI_FROM_DATABASE=ASRock Incorporation + +OUI:D05162* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:D052A8* + ID_OUI_FROM_DATABASE=Physical Graph Corporation + +OUI:D0542D* + ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. + +OUI:D0574C* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D05785* + ID_OUI_FROM_DATABASE=Pantech Co., Ltd. + +OUI:D057A1* + ID_OUI_FROM_DATABASE=Werma Signaltechnik GmbH & Co. KG + +OUI:D05875* + ID_OUI_FROM_DATABASE=Active Control Technology Inc. + +OUI:D059C3* + ID_OUI_FROM_DATABASE=CeraMicro Technology Corporation + +OUI:D05A0F* + ID_OUI_FROM_DATABASE=I-BT DIGITAL CO.,LTD + +OUI:D05FCE* + ID_OUI_FROM_DATABASE=Hitachi Data Systems + +OUI:D0634D* + ID_OUI_FROM_DATABASE=Meiko Maschinenbau GmbH & Co. KG + +OUI:D063B4* + ID_OUI_FROM_DATABASE=SolidRun Ltd. + +OUI:D0667B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:D067E5* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:D0699E* + ID_OUI_FROM_DATABASE=LUMINEX Lighting Control Equipment + +OUI:D069D0* + ID_OUI_FROM_DATABASE=Verto Medical Solutions, LLC + +OUI:D0737F* + ID_OUI_FROM_DATABASE=Mini-Circuits + +OUI:D0738E* + ID_OUI_FROM_DATABASE=DONG OH PRECISION CO., LTD. + +OUI:D073D5* + ID_OUI_FROM_DATABASE=LIFI LABS MANAGEMENT PTY LTD + +OUI:D075BE* + ID_OUI_FROM_DATABASE=Reno A&E + +OUI:D07AB5* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:D07DE5* + ID_OUI_FROM_DATABASE=Forward Pay Systems, Inc. + +OUI:D07E28* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:D07E35* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:D08999* + ID_OUI_FROM_DATABASE=APCON, Inc. + +OUI:D08A55* + ID_OUI_FROM_DATABASE=Skullcandy + +OUI:D08B7E* + ID_OUI_FROM_DATABASE=Passif Semiconductor + +OUI:D08CB5* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D08CFF* + ID_OUI_FROM_DATABASE=UPWIS AB + +OUI:D093F8* + ID_OUI_FROM_DATABASE=Stonestreet One LLC + +OUI:D095C7* + ID_OUI_FROM_DATABASE=Pantech Co., Ltd. + +OUI:D09B05* + ID_OUI_FROM_DATABASE=Emtronix + +OUI:D09C30* + ID_OUI_FROM_DATABASE=Foster Electric Company, Limited + +OUI:D09D0A* + ID_OUI_FROM_DATABASE=LINKCOM + +OUI:D0A311* + ID_OUI_FROM_DATABASE=Neuberger Gebäudeautomation GmbH + +OUI:D0AEEC* + ID_OUI_FROM_DATABASE=Alpha Networks Inc. + +OUI:D0AFB6* + ID_OUI_FROM_DATABASE=Linktop Technology Co., LTD + +OUI:D0B33F* + ID_OUI_FROM_DATABASE=SHENZHEN TINNO MOBILE TECHNOLOGY CO.,LTD. + +OUI:D0B498* + ID_OUI_FROM_DATABASE=Robert Bosch LLC Automotive Electronics + +OUI:D0B523* + ID_OUI_FROM_DATABASE=Bestcare Cloucal Corp. + +OUI:D0B53D* + ID_OUI_FROM_DATABASE=SEPRO ROBOTIQUE + +OUI:D0BB80* + ID_OUI_FROM_DATABASE=SHL Telemedicine International Ltd. + +OUI:D0BD01* + ID_OUI_FROM_DATABASE=DS International + +OUI:D0BE2C* + ID_OUI_FROM_DATABASE=CNSLink Co., Ltd. + +OUI:D0C1B1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D0C282* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D0C42F* + ID_OUI_FROM_DATABASE=Tamagawa Seiki Co.,Ltd. + +OUI:D0C789* + ID_OUI_FROM_DATABASE=Cisco + +OUI:D0CDE1* + ID_OUI_FROM_DATABASE=Scientech Electronics + +OUI:D0CF5E* + ID_OUI_FROM_DATABASE=Energy Micro AS + +OUI:D0D0FD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D0D212* + ID_OUI_FROM_DATABASE=K2NET Co.,Ltd. + +OUI:D0D286* + ID_OUI_FROM_DATABASE=Beckman Coulter K.K. + +OUI:D0D3FC* + ID_OUI_FROM_DATABASE=Mios, Ltd. + +OUI:D0D412* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:D0D471* + ID_OUI_FROM_DATABASE=MVTECH co., Ltd + +OUI:D0D6CC* + ID_OUI_FROM_DATABASE=Wintop + +OUI:D0DB32* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D0DF9A* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:D0DFB2* + ID_OUI_FROM_DATABASE=Genie Networks Limited + +OUI:D0DFC7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D0E140* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:D0E347* + ID_OUI_FROM_DATABASE=Yoga + +OUI:D0E40B* + ID_OUI_FROM_DATABASE=Wearable Inc. + +OUI:D0E54D* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:D0E782* + ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc. + +OUI:D0EB03* + ID_OUI_FROM_DATABASE=Zhehua technology limited + +OUI:D0EB9E* + ID_OUI_FROM_DATABASE=Seowoo Inc. + +OUI:D0F0DB* + ID_OUI_FROM_DATABASE=Ericsson + +OUI:D0F27F* + ID_OUI_FROM_DATABASE=SteadyServ Technoligies, LLC + +OUI:D0F73B* + ID_OUI_FROM_DATABASE=Helmut Mauell GmbH + +OUI:D0FF50* + ID_OUI_FROM_DATABASE=Texas Instruments, Inc + +OUI:D4000D* + ID_OUI_FROM_DATABASE=Phoenix Broadband Technologies, LLC. + +OUI:D40057* + ID_OUI_FROM_DATABASE=MC Technologies GmbH + +OUI:D40129* + ID_OUI_FROM_DATABASE=Broadcom Corporation + +OUI:D4016D* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:D4024A* + ID_OUI_FROM_DATABASE=Delphian Systems LLC + +OUI:D40BB9* + ID_OUI_FROM_DATABASE=Solid Semecs bv. + +OUI:D40FB2* + ID_OUI_FROM_DATABASE=Applied Micro Electronics AME bv + +OUI:D41090* + ID_OUI_FROM_DATABASE=iNFORM Systems AG + +OUI:D410CF* + ID_OUI_FROM_DATABASE=Huanshun Network Science and Technology Co., Ltd. + +OUI:D411D6* + ID_OUI_FROM_DATABASE=ShotSpotter, Inc. + +OUI:D41296* + ID_OUI_FROM_DATABASE=Anobit Technologies Ltd. + +OUI:D412BB* + ID_OUI_FROM_DATABASE=Quadrant Components Inc. Ltd + +OUI:D4136F* + ID_OUI_FROM_DATABASE=Asia Pacific Brands + +OUI:D41C1C* + ID_OUI_FROM_DATABASE=RCF S.P.A. + +OUI:D41E35* + ID_OUI_FROM_DATABASE=TOHO Electronics INC. + +OUI:D41F0C* + ID_OUI_FROM_DATABASE=TVI Vision Oy + +OUI:D4206D* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:D4223F* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:D4224E* + ID_OUI_FROM_DATABASE=Alcatel Lucent + +OUI:D42751* + ID_OUI_FROM_DATABASE=Infopia Co., Ltd + +OUI:D428B2* + ID_OUI_FROM_DATABASE=ioBridge, Inc. + +OUI:D429EA* + ID_OUI_FROM_DATABASE=Zimory GmbH + +OUI:D42C3D* + ID_OUI_FROM_DATABASE=Sky Light Digital Limited + +OUI:D42F23* + ID_OUI_FROM_DATABASE=Akenori PTE Ltd + +OUI:D4319D* + ID_OUI_FROM_DATABASE=Sinwatec + +OUI:D43A65* + ID_OUI_FROM_DATABASE=IGRS Engineering Lab Ltd. + +OUI:D43AE9* + ID_OUI_FROM_DATABASE=DONGGUAN ipt INDUSTRIAL CO., LTD + +OUI:D43D67* + ID_OUI_FROM_DATABASE=Carma Industries Inc. + +OUI:D43D7E* + ID_OUI_FROM_DATABASE=Micro-Star Int'l Co, Ltd + +OUI:D443A8* + ID_OUI_FROM_DATABASE=Changzhou Haojie Electric Co., Ltd. + +OUI:D44B5E* + ID_OUI_FROM_DATABASE=TAIYO YUDEN CO., LTD. + +OUI:D44C24* + ID_OUI_FROM_DATABASE=Vuppalamritha Magnetic Components LTD + +OUI:D44C9C* + ID_OUI_FROM_DATABASE=Shenzhen YOOBAO Technology Co.Ltd + +OUI:D44CA7* + ID_OUI_FROM_DATABASE=Informtekhnika & Communication, LLC + +OUI:D44F80* + ID_OUI_FROM_DATABASE=Kemper Digital GmbH + +OUI:D4507A* + ID_OUI_FROM_DATABASE=CEIVA Logic, Inc + +OUI:D45251* + ID_OUI_FROM_DATABASE=IBT Ingenieurbureau Broennimann Thun + +OUI:D45297* + ID_OUI_FROM_DATABASE=nSTREAMS Technologies, Inc. + +OUI:D453AF* + ID_OUI_FROM_DATABASE=VIGO System S.A. + +OUI:D45AB2* + ID_OUI_FROM_DATABASE=Galleon Systems + +OUI:D45C70* + ID_OUI_FROM_DATABASE=Wireless Gigabit Alliance + +OUI:D45D42* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D464F7* + ID_OUI_FROM_DATABASE=CHENGDU USEE DIGITAL TECHNOLOGY CO., LTD + +OUI:D466A8* + ID_OUI_FROM_DATABASE=Riedo Networks GmbH + +OUI:D467E7* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:D46867* + ID_OUI_FROM_DATABASE=Neoventus Design Group + +OUI:D46A91* + ID_OUI_FROM_DATABASE=Snap AV + +OUI:D46AA8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:D46CBF* + ID_OUI_FROM_DATABASE=Goodrich ISR + +OUI:D46CDA* + ID_OUI_FROM_DATABASE=CSM GmbH + +OUI:D46E5C* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:D46F42* + ID_OUI_FROM_DATABASE=WAXESS USA Inc + +OUI:D479C3* + ID_OUI_FROM_DATABASE=Cameronet GmbH & Co. KG + +OUI:D47B75* + ID_OUI_FROM_DATABASE=HARTING Electronics GmbH + +OUI:D481CA* + ID_OUI_FROM_DATABASE=iDevices, LLC + +OUI:D4823E* + ID_OUI_FROM_DATABASE=Argosy Technologies, Ltd. + +OUI:D48564* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:D487D8* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:D48890* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D48CB5* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D48FAA* + ID_OUI_FROM_DATABASE=Sogecam Industrial, S.A. + +OUI:D491AF* + ID_OUI_FROM_DATABASE=Electroacustica General Iberica, S.A. + +OUI:D493A0* + ID_OUI_FROM_DATABASE=Fidelix Oy + +OUI:D4945A* + ID_OUI_FROM_DATABASE=COSMO CO., LTD + +OUI:D494A1* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D49524* + ID_OUI_FROM_DATABASE=Clover Network, Inc. + +OUI:D496DF* + ID_OUI_FROM_DATABASE=SUNGJIN C&T CO.,LTD + +OUI:D49A20* + ID_OUI_FROM_DATABASE=Apple + +OUI:D49C28* + ID_OUI_FROM_DATABASE=JayBird Gear LLC + +OUI:D49C8E* + ID_OUI_FROM_DATABASE=University of FUKUI + +OUI:D49E6D* + ID_OUI_FROM_DATABASE=Wuhan Zhongyuan Huadian Science & Technology Co., + +OUI:D4A02A* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D4A425* + ID_OUI_FROM_DATABASE=SMAX Technology Co., Ltd. + +OUI:D4A499* + ID_OUI_FROM_DATABASE=InView Technology Corporation + +OUI:D4A928* + ID_OUI_FROM_DATABASE=GreenWave Reality Inc + +OUI:D4AAFF* + ID_OUI_FROM_DATABASE=MICRO WORLD + +OUI:D4AC4E* + ID_OUI_FROM_DATABASE=BODi rS, LLC + +OUI:D4AD2D* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:D4AE52* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:D4B110* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:D4BED9* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:D4BF2D* + ID_OUI_FROM_DATABASE=SE Controls Asia Pacific Ltd + +OUI:D4BF7F* + ID_OUI_FROM_DATABASE=UPVEL + +OUI:D4C1FC* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D4C766* + ID_OUI_FROM_DATABASE=Acentic GmbH + +OUI:D4C9EF* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:D4CA6D* + ID_OUI_FROM_DATABASE=Routerboard.com + +OUI:D4CA6E* + ID_OUI_FROM_DATABASE=u-blox AG + +OUI:D4CBAF* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D4CEB8* + ID_OUI_FROM_DATABASE=Enatel LTD + +OUI:D4D184* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:D4D249* + ID_OUI_FROM_DATABASE=Power Ethernet + +OUI:D4D50D* + ID_OUI_FROM_DATABASE=Southwest Microwave, Inc + +OUI:D4D748* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D4D898* + ID_OUI_FROM_DATABASE=Korea CNO Tech Co., Ltd + +OUI:D4D919* + ID_OUI_FROM_DATABASE=GoPro + +OUI:D4DF57* + ID_OUI_FROM_DATABASE=Alpinion Medical Systems + +OUI:D4E32C* + ID_OUI_FROM_DATABASE=S. Siedle & Sohne + +OUI:D4E33F* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:D4E8B2* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:D4EA0E* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:D4EC0C* + ID_OUI_FROM_DATABASE=Harley-Davidson Motor Company + +OUI:D4EE07* + ID_OUI_FROM_DATABASE=HIWIFI Co., Ltd. + +OUI:D4F027* + ID_OUI_FROM_DATABASE=Navetas Energy Management + +OUI:D4F0B4* + ID_OUI_FROM_DATABASE=Napco Security Technologies + +OUI:D4F143* + ID_OUI_FROM_DATABASE=IPROAD.,Inc + +OUI:D4F63F* + ID_OUI_FROM_DATABASE=IEA S.R.L. + +OUI:D8004D* + ID_OUI_FROM_DATABASE=Apple + +OUI:D8052E* + ID_OUI_FROM_DATABASE=Skyviia Corporation + +OUI:D806D1* + ID_OUI_FROM_DATABASE=Honeywell Fire System (Shanghai) Co,. Ltd. + +OUI:D808F5* + ID_OUI_FROM_DATABASE=Arcadia Networks Co. Ltd. + +OUI:D809C3* + ID_OUI_FROM_DATABASE=Cercacor Labs + +OUI:D80DE3* + ID_OUI_FROM_DATABASE=FXI TECHNOLOGIES AS + +OUI:D8150D* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:D8160A* + ID_OUI_FROM_DATABASE=Nippon Electro-Sensory Devices + +OUI:D8182B* + ID_OUI_FROM_DATABASE=Conti Temic Microelectronic GmbH + +OUI:D819CE* + ID_OUI_FROM_DATABASE=Telesquare + +OUI:D81BFE* + ID_OUI_FROM_DATABASE=TWINLINX CORPORATION + +OUI:D81C14* + ID_OUI_FROM_DATABASE=Compacta International, Ltd. + +OUI:D81EDE* + ID_OUI_FROM_DATABASE=B&W Group Ltd + +OUI:D824BD* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D826B9* + ID_OUI_FROM_DATABASE=Guangdong Coagent Electronics S &T Co., Ltd. + +OUI:D8270C* + ID_OUI_FROM_DATABASE=MaxTronic International Co., Ltd. + +OUI:D828C9* + ID_OUI_FROM_DATABASE=General Electric Consumer and Industrial + +OUI:D82916* + ID_OUI_FROM_DATABASE=Ascent Communication Technology + +OUI:D82986* + ID_OUI_FROM_DATABASE=Best Wish Technology LTD + +OUI:D82A15* + ID_OUI_FROM_DATABASE=Leitner SpA + +OUI:D82A7E* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D82D9B* + ID_OUI_FROM_DATABASE=Shenzhen G.Credit Communication Technology Co., Ltd + +OUI:D82DE1* + ID_OUI_FROM_DATABASE=Tricascade Inc. + +OUI:D83062* + ID_OUI_FROM_DATABASE=Apple + +OUI:D831CF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D8337F* + ID_OUI_FROM_DATABASE=Office FA.com Co.,Ltd. + +OUI:D842AC* + ID_OUI_FROM_DATABASE=Shanghai Feixun Communication Co.,Ltd. + +OUI:D84606* + ID_OUI_FROM_DATABASE=Silicon Valley Global Marketing + +OUI:D8490B* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:D84B2A* + ID_OUI_FROM_DATABASE=Cognitas Technologies, Inc. + +OUI:D850E6* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:D8543A* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D857EF* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:D858D7* + ID_OUI_FROM_DATABASE=CZ.NIC, z.s.p.o. + +OUI:D85D4C* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co.,Ltd. + +OUI:D85D84* + ID_OUI_FROM_DATABASE=CAx soft GmbH + +OUI:D86194* + ID_OUI_FROM_DATABASE=Objetivos y Sevicios de Valor Añadido + +OUI:D862DB* + ID_OUI_FROM_DATABASE=Eno Inc. + +OUI:D86595* + ID_OUI_FROM_DATABASE=Toy's Myth Inc. + +OUI:D866C6* + ID_OUI_FROM_DATABASE=Shenzhen Daystar Technology Co.,ltd + +OUI:D867D9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:D86960* + ID_OUI_FROM_DATABASE=Steinsvik + +OUI:D86BF7* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:D86CE9* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:D87157* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:D87533* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:D8760A* + ID_OUI_FROM_DATABASE=Escort, Inc. + +OUI:D878E5* + ID_OUI_FROM_DATABASE=KUHN SA + +OUI:D87988* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + +OUI:D87CDD* + ID_OUI_FROM_DATABASE=SANIX INCORPORATED + +OUI:D881CE* + ID_OUI_FROM_DATABASE=AHN INC. + +OUI:D88A3B* + ID_OUI_FROM_DATABASE=UNIT-EM + +OUI:D890E8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:D8952F* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D89685* + ID_OUI_FROM_DATABASE=GoPro + +OUI:D89695* + ID_OUI_FROM_DATABASE=Apple + +OUI:D8973B* + ID_OUI_FROM_DATABASE=Emerson Network Power Embedded Power + +OUI:D89760* + ID_OUI_FROM_DATABASE=C2 Development, Inc. + +OUI:D89D67* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:D89DB9* + ID_OUI_FROM_DATABASE=eMegatech International Corp. + +OUI:D89E3F* + ID_OUI_FROM_DATABASE=Apple + +OUI:D8A25E* + ID_OUI_FROM_DATABASE=Apple + +OUI:D8AE90* + ID_OUI_FROM_DATABASE=Itibia Technologies + +OUI:D8AF3B* + ID_OUI_FROM_DATABASE=Hangzhou Bigbright Integrated communications system Co.,Ltd + +OUI:D8AFF1* + ID_OUI_FROM_DATABASE=Panasonic Appliances Company + +OUI:D8B02E* + ID_OUI_FROM_DATABASE=Guangzhou Zonerich Business Machine Co., Ltd + +OUI:D8B04C* + ID_OUI_FROM_DATABASE=Jinan USR IOT Technology Co., Ltd. + +OUI:D8B12A* + ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co., Ltd. + +OUI:D8B377* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:D8B6C1* + ID_OUI_FROM_DATABASE=NetworkAccountant, Inc. + +OUI:D8B6D6* + ID_OUI_FROM_DATABASE=Blu Tether Limited + +OUI:D8B8F6* + ID_OUI_FROM_DATABASE=Nantworks + +OUI:D8B90E* + ID_OUI_FROM_DATABASE=Triple Domain Vision Co.,Ltd. + +OUI:D8BF4C* + ID_OUI_FROM_DATABASE=Victory Concept Electronics Limited + +OUI:D8C068* + ID_OUI_FROM_DATABASE=Netgenetech.co.,ltd. + +OUI:D8C3FB* + ID_OUI_FROM_DATABASE=DETRACOM + +OUI:D8C691* + ID_OUI_FROM_DATABASE=Hichan Technology Corp. + +OUI:D8C7C8* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:D8C99D* + ID_OUI_FROM_DATABASE=EA DISPLAY LIMITED + +OUI:D8D1CB* + ID_OUI_FROM_DATABASE=Apple + +OUI:D8D27C* + ID_OUI_FROM_DATABASE=JEMA ENERGY, SA + +OUI:D8D385* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:D8D43C* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:D8D5B9* + ID_OUI_FROM_DATABASE=Rainforest Automation, Inc. + +OUI:D8D67E* + ID_OUI_FROM_DATABASE=GSK CNC EQUIPMENT CO.,LTD + +OUI:D8DA52* + ID_OUI_FROM_DATABASE=APATOR S.A. + +OUI:D8DCE9* + ID_OUI_FROM_DATABASE=Kunshan Erlab ductless filtration system Co.,Ltd + +OUI:D8DD5F* + ID_OUI_FROM_DATABASE=BALMUDA Inc. + +OUI:D8DDFD* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:D8DF0D* + ID_OUI_FROM_DATABASE=beroNet GmbH + +OUI:D8E3AE* + ID_OUI_FROM_DATABASE=CIRTEC MEDICAL SYSTEMS + +OUI:D8E72B* + ID_OUI_FROM_DATABASE=OnPATH Technologies + +OUI:D8E743* + ID_OUI_FROM_DATABASE=Wush, Inc + +OUI:D8E952* + ID_OUI_FROM_DATABASE=KEOPSYS + +OUI:D8EB97* + ID_OUI_FROM_DATABASE=TRENDnet, Inc. + +OUI:D8EE78* + ID_OUI_FROM_DATABASE=Moog Protokraft + +OUI:D8F0F2* + ID_OUI_FROM_DATABASE=Zeebo Inc + +OUI:D8FC93* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:D8FE8F* + ID_OUI_FROM_DATABASE=IDFone Co., Ltd. + +OUI:D8FEE3* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:DC0265* + ID_OUI_FROM_DATABASE=Meditech Kft + +OUI:DC028E* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:DC052F* + ID_OUI_FROM_DATABASE=National Products Inc. + +OUI:DC0575* + ID_OUI_FROM_DATABASE=SIEMENS ENERGY AUTOMATION + +OUI:DC05ED* + ID_OUI_FROM_DATABASE=Nabtesco Corporation + +OUI:DC07C1* + ID_OUI_FROM_DATABASE=HangZhou QiYang Technology Co.,Ltd. + +OUI:DC0B1A* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:DC0EA1* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD + +OUI:DC16A2* + ID_OUI_FROM_DATABASE=Medtronic Diabetes + +OUI:DC175A* + ID_OUI_FROM_DATABASE=Hitachi High-Technologies Corporation + +OUI:DC1792* + ID_OUI_FROM_DATABASE=Captivate Network + +OUI:DC1D9F* + ID_OUI_FROM_DATABASE=U & B tech + +OUI:DC1DD4* + ID_OUI_FROM_DATABASE=Microstep-MIS spol. s r.o. + +OUI:DC1EA3* + ID_OUI_FROM_DATABASE=Accensus LLC + +OUI:DC2008* + ID_OUI_FROM_DATABASE=ASD Electronics Ltd + +OUI:DC2A14* + ID_OUI_FROM_DATABASE=Shanghai Longjing Technology Co. + +OUI:DC2B61* + ID_OUI_FROM_DATABASE=Apple + +OUI:DC2B66* + ID_OUI_FROM_DATABASE=InfoBLOCK S.A. de C.V. + +OUI:DC2BCA* + ID_OUI_FROM_DATABASE=Zera GmbH + +OUI:DC2C26* + ID_OUI_FROM_DATABASE=Iton Technology Limited + +OUI:DC2E6A* + ID_OUI_FROM_DATABASE=HCT. Co., Ltd. + +OUI:DC309C* + ID_OUI_FROM_DATABASE=Heyrex Limited + +OUI:DC3350* + ID_OUI_FROM_DATABASE=TechSAT GmbH + +OUI:DC37D2* + ID_OUI_FROM_DATABASE=Hunan HKT Electronic Technology Co., Ltd + +OUI:DC3A5E* + ID_OUI_FROM_DATABASE=Roku, Inc + +OUI:DC3C2E* + ID_OUI_FROM_DATABASE=Manufacturing System Insights, Inc. + +OUI:DC3C84* + ID_OUI_FROM_DATABASE=Ticom Geomatics, Inc. + +OUI:DC3E51* + ID_OUI_FROM_DATABASE=Solberg & Andersen AS + +OUI:DC3EF8* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:DC4517* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:DC49C9* + ID_OUI_FROM_DATABASE=CASCO SIGNAL LTD + +OUI:DC4EDE* + ID_OUI_FROM_DATABASE=SHINYEI TECHNOLOGY CO., LTD. + +OUI:DC5726* + ID_OUI_FROM_DATABASE=Power-One + +OUI:DC5E36* + ID_OUI_FROM_DATABASE=Paterson Technology + +OUI:DC647C* + ID_OUI_FROM_DATABASE=C.R.S. iiMotion GmbH + +OUI:DC6F00* + ID_OUI_FROM_DATABASE=Livescribe, Inc. + +OUI:DC6F08* + ID_OUI_FROM_DATABASE=Bay Storage Technology + +OUI:DC7144* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics + +OUI:DC7B94* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:DC825B* + ID_OUI_FROM_DATABASE=JANUS, spol. s r.o. + +OUI:DC85DE* + ID_OUI_FROM_DATABASE=Azurewave Technologies., inc. + +OUI:DC86D8* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:DC9B1E* + ID_OUI_FROM_DATABASE=Intercom, Inc. + +OUI:DC9B9C* + ID_OUI_FROM_DATABASE=Apple + +OUI:DC9C52* + ID_OUI_FROM_DATABASE=Sapphire Technology Limited. + +OUI:DC9FA4* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:DC9FDB* + ID_OUI_FROM_DATABASE=Ubiquiti Networks, Inc. + +OUI:DCA5F4* + ID_OUI_FROM_DATABASE=Cisco + +OUI:DCA6BD* + ID_OUI_FROM_DATABASE=Beijing Lanbo Technology Co., Ltd. + +OUI:DCA7D9* + ID_OUI_FROM_DATABASE=Compressor Controls Corp + +OUI:DCA8CF* + ID_OUI_FROM_DATABASE=New Spin Golf, LLC. + +OUI:DCA971* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:DCA989* + ID_OUI_FROM_DATABASE=MACANDC + +OUI:DCAD9E* + ID_OUI_FROM_DATABASE=GreenPriz + +OUI:DCAE04* + ID_OUI_FROM_DATABASE=CELOXICA Ltd + +OUI:DCB058* + ID_OUI_FROM_DATABASE=Burkert Werke GmbH + +OUI:DCB4C4* + ID_OUI_FROM_DATABASE=Microsoft XCG + +OUI:DCBF90* + ID_OUI_FROM_DATABASE=HUIZHOU QIAOXING TELECOMMUNICATION INDUSTRY CO.,LTD. + +OUI:DCC0DB* + ID_OUI_FROM_DATABASE=Shenzhen Kaiboer Technology Co., Ltd. + +OUI:DCC101* + ID_OUI_FROM_DATABASE=SOLiD Technologies, Inc. + +OUI:DCC422* + ID_OUI_FROM_DATABASE=Systembase Limited + +OUI:DCC793* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:DCCBA8* + ID_OUI_FROM_DATABASE=Explora Technologies Inc + +OUI:DCCE41* + ID_OUI_FROM_DATABASE=FE GLOBAL HONG KONG LIMITED + +OUI:DCCEBC* + ID_OUI_FROM_DATABASE=Shenzhen JSR Technology Co.,Ltd. + +OUI:DCCF94* + ID_OUI_FROM_DATABASE=Beijing Rongcheng Hutong Technology Co., Ltd. + +OUI:DCD0F7* + ID_OUI_FROM_DATABASE=Bentek Systems Ltd. + +OUI:DCD2FC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:DCD321* + ID_OUI_FROM_DATABASE=HUMAX co.,tld + +OUI:DCD52A* + ID_OUI_FROM_DATABASE=Sunny Heart Limited + +OUI:DCD87F* + ID_OUI_FROM_DATABASE=Shenzhen JoinCyber Telecom Equipment Ltd + +OUI:DCDECA* + ID_OUI_FROM_DATABASE=Akyllor + +OUI:DCE2AC* + ID_OUI_FROM_DATABASE=Lumens Digital Optics Inc. + +OUI:DCE578* + ID_OUI_FROM_DATABASE=Experimental Factory of Scientific Engineering and Special Design Department + +OUI:DCE71C* + ID_OUI_FROM_DATABASE=AUG Elektronik GmbH + +OUI:DCF05D* + ID_OUI_FROM_DATABASE=Letta Teknoloji + +OUI:DCF755* + ID_OUI_FROM_DATABASE=SITRONIK + +OUI:DCF858* + ID_OUI_FROM_DATABASE=Lorent Networks, Inc. + +OUI:DCFAD5* + ID_OUI_FROM_DATABASE=STRONG Ges.m.b.H. + +OUI:DCFB02* + ID_OUI_FROM_DATABASE=Buffalo Inc. + +OUI:E005C5* + ID_OUI_FROM_DATABASE=TP-LINK Technologies Co.,Ltd. + +OUI:E006E6* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:E00B28* + ID_OUI_FROM_DATABASE=Inovonics + +OUI:E00C7F* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:E0143E* + ID_OUI_FROM_DATABASE=Modoosis Inc. + +OUI:E01877* + ID_OUI_FROM_DATABASE=Fujitsu Limited + +OUI:E01C41* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc. + +OUI:E01CEE* + ID_OUI_FROM_DATABASE=Bravo Tech, Inc. + +OUI:E01D3B* + ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd + +OUI:E01E07* + ID_OUI_FROM_DATABASE=Anite Telecoms US. Inc + +OUI:E01F0A* + ID_OUI_FROM_DATABASE=Xslent Energy Technologies. LLC + +OUI:E0247F* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:E02538* + ID_OUI_FROM_DATABASE=Titan Pet Products + +OUI:E02630* + ID_OUI_FROM_DATABASE=Intrigue Technologies, Inc. + +OUI:E02636* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:E0271A* + ID_OUI_FROM_DATABASE=TTC Next-generation Home Network System WG + +OUI:E02A82* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:E02F6D* + ID_OUI_FROM_DATABASE=Cisco + +OUI:E03005* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:E031D0* + ID_OUI_FROM_DATABASE=SZ Telstar CO., LTD + +OUI:E036E3* + ID_OUI_FROM_DATABASE=Stage One International Co., Ltd. + +OUI:E039D7* + ID_OUI_FROM_DATABASE=Plexxi, Inc. + +OUI:E03C5B* + ID_OUI_FROM_DATABASE=SHENZHEN JIAXINJIE ELECTRON CO.,LTD + +OUI:E03E4A* + ID_OUI_FROM_DATABASE=Cavanagh Group International + +OUI:E03E7D* + ID_OUI_FROM_DATABASE=data-complex GmbH + +OUI:E03F49* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:E0469A* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:E05597* + ID_OUI_FROM_DATABASE=Emergent Vision Technologies Inc. + +OUI:E056F4* + ID_OUI_FROM_DATABASE=AxesNetwork Solutions inc. + +OUI:E0589E* + ID_OUI_FROM_DATABASE=Laerdal Medical + +OUI:E05B70* + ID_OUI_FROM_DATABASE=Innovid, Co., Ltd. + +OUI:E05DA6* + ID_OUI_FROM_DATABASE=Detlef Fink Elektronik & Softwareentwicklung + +OUI:E05FB9* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:E061B2* + ID_OUI_FROM_DATABASE=HANGZHOU ZENOINTEL TECHNOLOGY CO., LTD + +OUI:E06290* + ID_OUI_FROM_DATABASE=Jinan Jovision Science & Technology Co., Ltd. + +OUI:E063E5* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:E064BB* + ID_OUI_FROM_DATABASE=DigiView S.r.l. + +OUI:E067B3* + ID_OUI_FROM_DATABASE=C-Data Technology Co., Ltd + +OUI:E06995* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:E0750A* + ID_OUI_FROM_DATABASE=ALPS ERECTORIC CO.,LTD. + +OUI:E0757D* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + +OUI:E07C62* + ID_OUI_FROM_DATABASE=Whistle Labs, Inc. + +OUI:E07F53* + ID_OUI_FROM_DATABASE=TECHBOARD SRL + +OUI:E07F88* + ID_OUI_FROM_DATABASE=EVIDENCE Network SIA + +OUI:E08177* + ID_OUI_FROM_DATABASE=GreenBytes, Inc. + +OUI:E087B1* + ID_OUI_FROM_DATABASE=Nata-Info Ltd. + +OUI:E08A7E* + ID_OUI_FROM_DATABASE=Exponent + +OUI:E08FEC* + ID_OUI_FROM_DATABASE=REPOTEC CO., LTD. + +OUI:E09153* + ID_OUI_FROM_DATABASE=XAVi Technologies Corp. + +OUI:E091F5* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:E09467* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:E09579* + ID_OUI_FROM_DATABASE=ORTHOsoft inc, d/b/a Zimmer CAS + +OUI:E097F2* + ID_OUI_FROM_DATABASE=Atomax Inc. + +OUI:E09D31* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:E09DB8* + ID_OUI_FROM_DATABASE=PLANEX COMMUNICATIONS INC. + +OUI:E0A198* + ID_OUI_FROM_DATABASE=NOJA Power Switchgear Pty Ltd + +OUI:E0A1D7* + ID_OUI_FROM_DATABASE=SFR + +OUI:E0A30F* + ID_OUI_FROM_DATABASE=Pevco + +OUI:E0A670* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:E0AAB0* + ID_OUI_FROM_DATABASE=GENERAL VISION ELECTRONICS CO. LTD. + +OUI:E0ABFE* + ID_OUI_FROM_DATABASE=Orb Networks, Inc. + +OUI:E0AE5E* + ID_OUI_FROM_DATABASE=ALPS Co,. Ltd. + +OUI:E0AEB2* + ID_OUI_FROM_DATABASE=Bender GmbH & Co.KG + +OUI:E0AEED* + ID_OUI_FROM_DATABASE=LOENK + +OUI:E0AF4B* + ID_OUI_FROM_DATABASE=Pluribus Networks, Inc. + +OUI:E0B2F1* + ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED + +OUI:E0B7B1* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:E0B9A5* + ID_OUI_FROM_DATABASE=Azurewave + +OUI:E0B9BA* + ID_OUI_FROM_DATABASE=Apple + +OUI:E0BC43* + ID_OUI_FROM_DATABASE=C2 Microsystems, Inc. + +OUI:E0C286* + ID_OUI_FROM_DATABASE=Aisai Communication Technology Co., Ltd. + +OUI:E0C2B7* + ID_OUI_FROM_DATABASE=Masimo Corporation + +OUI:E0C3F3* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:E0C6B3* + ID_OUI_FROM_DATABASE=MilDef AB + +OUI:E0C79D* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:E0C86A* + ID_OUI_FROM_DATABASE=SHENZHEN TW-SCIE Co., Ltd + +OUI:E0C922* + ID_OUI_FROM_DATABASE=Jireh Energy Tech., Ltd. + +OUI:E0C97A* + ID_OUI_FROM_DATABASE=Apple + +OUI:E0CA4D* + ID_OUI_FROM_DATABASE=Shenzhen Unistar Communication Co.,LTD + +OUI:E0CA94* + ID_OUI_FROM_DATABASE=Askey Computer + +OUI:E0CB4E* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:E0CEC3* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP + +OUI:E0CF2D* + ID_OUI_FROM_DATABASE=Gemintek Corporation + +OUI:E0D10A* + ID_OUI_FROM_DATABASE=Katoudenkikougyousyo co ltd + +OUI:E0D1E6* + ID_OUI_FROM_DATABASE=Aliph dba Jawbone + +OUI:E0D31A* + ID_OUI_FROM_DATABASE=EQUES Technology Co., Limited + +OUI:E0D7BA* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:E0D9A2* + ID_OUI_FROM_DATABASE=Hippih aps + +OUI:E0DADC* + ID_OUI_FROM_DATABASE=JVC KENWOOD Corporation + +OUI:E0DB55* + ID_OUI_FROM_DATABASE=Dell Inc + +OUI:E0DB88* + ID_OUI_FROM_DATABASE=Open Standard Digital-IF Interface for SATCOM Systems + +OUI:E0DCA0* + ID_OUI_FROM_DATABASE=Siemens Electrical Apparatus Ltd., Suzhou Chengdu Branch + +OUI:E0E631* + ID_OUI_FROM_DATABASE=SNB TECHNOLOGIES LIMITED + +OUI:E0E751* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:E0E8E8* + ID_OUI_FROM_DATABASE=Olive Telecommunication Pvt. Ltd + +OUI:E0ED1A* + ID_OUI_FROM_DATABASE=vastriver Technology Co., Ltd + +OUI:E0EDC7* + ID_OUI_FROM_DATABASE=Shenzhen Friendcom Technology Development Co., Ltd + +OUI:E0EE1B* + ID_OUI_FROM_DATABASE=Panasonic Automotive Systems Company of America + +OUI:E0EF25* + ID_OUI_FROM_DATABASE=Lintes Technology Co., Ltd. + +OUI:E0F211* + ID_OUI_FROM_DATABASE=Digitalwatt + +OUI:E0F379* + ID_OUI_FROM_DATABASE=Vaddio + +OUI:E0F5C6* + ID_OUI_FROM_DATABASE=Apple + +OUI:E0F5CA* + ID_OUI_FROM_DATABASE=CHENG UEI PRECISION INDUSTRY CO.,LTD. + +OUI:E0F847* + ID_OUI_FROM_DATABASE=Apple + +OUI:E0F9BE* + ID_OUI_FROM_DATABASE=Cloudena Corp. + +OUI:E0FAEC* + ID_OUI_FROM_DATABASE=Platan sp. z o.o. sp. k. + +OUI:E40439* + ID_OUI_FROM_DATABASE=TomTom Software Ltd + +OUI:E4115B* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:E4121D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E41289* + ID_OUI_FROM_DATABASE=topsystem Systemhaus GmbH + +OUI:E41C4B* + ID_OUI_FROM_DATABASE=V2 TECHNOLOGY, INC. + +OUI:E41F13* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:E425E7* + ID_OUI_FROM_DATABASE=Apple + +OUI:E425E9* + ID_OUI_FROM_DATABASE=Color-Chip + +OUI:E42771* + ID_OUI_FROM_DATABASE=Smartlabs + +OUI:E42AD3* + ID_OUI_FROM_DATABASE=Magneti Marelli S.p.A. Powertrain + +OUI:E42C56* + ID_OUI_FROM_DATABASE=Lilee Systems, Ltd. + +OUI:E42D02* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:E42F26* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. + +OUI:E42FF6* + ID_OUI_FROM_DATABASE=Unicore communication Inc. + +OUI:E432CB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E43593* + ID_OUI_FROM_DATABASE=Hangzhou GoTo technology Co.Ltd + +OUI:E435FB* + ID_OUI_FROM_DATABASE=Sabre Technology (Hull) Ltd + +OUI:E437D7* + ID_OUI_FROM_DATABASE=HENRI DEPAEPE S.A.S. + +OUI:E438F2* + ID_OUI_FROM_DATABASE=Advantage Controls + +OUI:E43FA2* + ID_OUI_FROM_DATABASE=Wuxi DSP Technologies Inc. + +OUI:E440E2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E441E6* + ID_OUI_FROM_DATABASE=Ottec Technology GmbH + +OUI:E446BD* + ID_OUI_FROM_DATABASE=C&C TECHNIC TAIWAN CO., LTD. + +OUI:E448C7* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:E44C6C* + ID_OUI_FROM_DATABASE=Shenzhen Guo Wei Electronic Co,. Ltd. + +OUI:E44E18* + ID_OUI_FROM_DATABASE=Gardasoft VisionLimited + +OUI:E44F29* + ID_OUI_FROM_DATABASE=MA Lighting Technology GmbH + +OUI:E44F5F* + ID_OUI_FROM_DATABASE=EDS Elektronik Destek San.Tic.Ltd.Sti + +OUI:E455EA* + ID_OUI_FROM_DATABASE=Dedicated Computing + +OUI:E45614* + ID_OUI_FROM_DATABASE=Suttle Apparatus + +OUI:E457A8* + ID_OUI_FROM_DATABASE=Stuart Manufacturing, Inc. + +OUI:E46449* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E467BA* + ID_OUI_FROM_DATABASE=Danish Interpretation Systems A/S + +OUI:E468A3* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:E46C21* + ID_OUI_FROM_DATABASE=messMa GmbH + +OUI:E47185* + ID_OUI_FROM_DATABASE=Securifi Ltd + +OUI:E4751E* + ID_OUI_FROM_DATABASE=Getinge Sterilization AB + +OUI:E47723* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:E4776B* + ID_OUI_FROM_DATABASE=AARTESYS AG + +OUI:E477D4* + ID_OUI_FROM_DATABASE=Minrray Industry Co.,Ltd + +OUI:E47CF9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:E47D5A* + ID_OUI_FROM_DATABASE=Beijing Hanbang Technology Corp. + +OUI:E48184* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:E481B3* + ID_OUI_FROM_DATABASE=Shenzhen ACT Industrial Co.,Ltd. + +OUI:E48399* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E48AD5* + ID_OUI_FROM_DATABASE=RF WINDOW CO., LTD. + +OUI:E48B7F* + ID_OUI_FROM_DATABASE=Apple + +OUI:E49069* + ID_OUI_FROM_DATABASE=Rockwell Automation + +OUI:E492E7* + ID_OUI_FROM_DATABASE=Gridlink Tech. Co.,Ltd. + +OUI:E492FB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E496AE* + ID_OUI_FROM_DATABASE=ALTOGRAPHICS Inc. + +OUI:E497F0* + ID_OUI_FROM_DATABASE=Shanghai VLC Technologies Ltd. Co. + +OUI:E498D6* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:E4A5EF* + ID_OUI_FROM_DATABASE=TRON LINK ELECTRONICS CO., LTD. + +OUI:E4A7FD* + ID_OUI_FROM_DATABASE=Cellco Partnership + +OUI:E4AB46* + ID_OUI_FROM_DATABASE=UAB Selteka + +OUI:E4AD7D* + ID_OUI_FROM_DATABASE=SCL Elements + +OUI:E4AFA1* + ID_OUI_FROM_DATABASE=HES-SO + +OUI:E4B021* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E4C146* + ID_OUI_FROM_DATABASE=Objetivos y Servicios de Valor A + +OUI:E4C63D* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:E4C6E6* + ID_OUI_FROM_DATABASE=Mophie, LLC + +OUI:E4C722* + ID_OUI_FROM_DATABASE=Cisco + +OUI:E4C806* + ID_OUI_FROM_DATABASE=Ceiec Electric Technology Inc. + +OUI:E4CE8F* + ID_OUI_FROM_DATABASE=Apple + +OUI:E4D3F1* + ID_OUI_FROM_DATABASE=Cisco + +OUI:E4D53D* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:E4D71D* + ID_OUI_FROM_DATABASE=Oraya Therapeutics + +OUI:E4DD79* + ID_OUI_FROM_DATABASE=En-Vision America, Inc. + +OUI:E4E0C5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:E4E409* + ID_OUI_FROM_DATABASE=LEIFHEIT AG + +OUI:E4EC10* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:E4EEFD* + ID_OUI_FROM_DATABASE=MR&D Manufacturing + +OUI:E4F365* + ID_OUI_FROM_DATABASE=Time-O-Matic, Inc. + +OUI:E4F3E3* + ID_OUI_FROM_DATABASE=Shanghai iComhome Co.,Ltd. + +OUI:E4F7A1* + ID_OUI_FROM_DATABASE=Datafox GmbH + +OUI:E4FA1D* + ID_OUI_FROM_DATABASE=PAD Peripheral Advanced Design Inc. + +OUI:E4FFDD* + ID_OUI_FROM_DATABASE=ELECTRON INDIA + +OUI:E8039A* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:E8040B* + ID_OUI_FROM_DATABASE=Apple + +OUI:E80462* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:E804F3* + ID_OUI_FROM_DATABASE=Throughtek Co., Ltd. + +OUI:E8056D* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:E80688* + ID_OUI_FROM_DATABASE=Apple + +OUI:E8088B* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:E80B13* + ID_OUI_FROM_DATABASE=Akib Systems Taiwan, INC + +OUI:E80C38* + ID_OUI_FROM_DATABASE=DAEYOUNG INFORMATION SYSTEM CO., LTD + +OUI:E80C75* + ID_OUI_FROM_DATABASE=Syncbak, Inc. + +OUI:E8102E* + ID_OUI_FROM_DATABASE=Really Simple Software, Inc + +OUI:E81132* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:E81324* + ID_OUI_FROM_DATABASE=GuangZhou Bonsoninfo System CO.,LTD + +OUI:E817FC* + ID_OUI_FROM_DATABASE=NIFTY Corporation + +OUI:E82877* + ID_OUI_FROM_DATABASE=TMY Co., Ltd. + +OUI:E828D5* + ID_OUI_FROM_DATABASE=Cots Technology + +OUI:E82AEA* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:E82E24* + ID_OUI_FROM_DATABASE=Out of the Fog Research LLC + +OUI:E83935* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:E839DF* + ID_OUI_FROM_DATABASE=Askey Computer + +OUI:E83A97* + ID_OUI_FROM_DATABASE=OCZ Technology Group + +OUI:E83EB6* + ID_OUI_FROM_DATABASE=RIM + +OUI:E83EFB* + ID_OUI_FROM_DATABASE=GEODESIC LTD. + +OUI:E83EFC* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E84040* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:E840F2* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:E843B6* + ID_OUI_FROM_DATABASE=QNAP Systems, Inc. + +OUI:E8481F* + ID_OUI_FROM_DATABASE=Advanced Automotive Antennas + +OUI:E84E06* + ID_OUI_FROM_DATABASE=EDUP INTERNATIONAL (HK) CO., LTD + +OUI:E84E84* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E84ECE* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:E8516E* + ID_OUI_FROM_DATABASE=TSMART Inc. + +OUI:E8519D* + ID_OUI_FROM_DATABASE=Yeonhab Precision Co.,LTD + +OUI:E85484* + ID_OUI_FROM_DATABASE=NEO INFORMATION SYSTEMS CO., LTD. + +OUI:E856D6* + ID_OUI_FROM_DATABASE=NCTech Ltd + +OUI:E85AA7* + ID_OUI_FROM_DATABASE=LLC Emzior + +OUI:E85B5B* + ID_OUI_FROM_DATABASE=LG ELECTRONICS INC + +OUI:E85BF0* + ID_OUI_FROM_DATABASE=Imaging Diagnostics + +OUI:E85E53* + ID_OUI_FROM_DATABASE=Infratec Datentechnik GmbH + +OUI:E8611F* + ID_OUI_FROM_DATABASE=Dawning Information Industry Co.,Ltd + +OUI:E8617E* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:E86183* + ID_OUI_FROM_DATABASE=Black Diamond Advanced Technology, LLC + +OUI:E86CDA* + ID_OUI_FROM_DATABASE=Supercomputers and Neurocomputers Research Center + +OUI:E86D52* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E86D54* + ID_OUI_FROM_DATABASE=Digit Mobile Inc + +OUI:E86D6E* + ID_OUI_FROM_DATABASE=Control & Display Systems Ltd t/a CDSRail + +OUI:E8718D* + ID_OUI_FROM_DATABASE=Elsys Equipamentos Eletronicos Ltda + +OUI:E8757F* + ID_OUI_FROM_DATABASE=FIRS Technologies(Shenzhen) Co., Ltd + +OUI:E878A1* + ID_OUI_FROM_DATABASE=BEOVIEW INTERCOM DOO + +OUI:E87AF3* + ID_OUI_FROM_DATABASE=S5 Tech S.r.l. + +OUI:E880D8* + ID_OUI_FROM_DATABASE=GNTEK Electronics Co.,Ltd. + +OUI:E8892C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E88D28* + ID_OUI_FROM_DATABASE=Apple + +OUI:E88DF5* + ID_OUI_FROM_DATABASE=ZNYX Networks, Inc. + +OUI:E89218* + ID_OUI_FROM_DATABASE=Arcontia International AB + +OUI:E892A4* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:E8944C* + ID_OUI_FROM_DATABASE=Cogent Healthcare Systems Ltd + +OUI:E894F6* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:E8995A* + ID_OUI_FROM_DATABASE=PiiGAB, Processinformation i Goteborg AB + +OUI:E899C4* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:E89A8F* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. + +OUI:E89AFF* + ID_OUI_FROM_DATABASE=Fujian Landi Commercial Equipment Co.,Ltd + +OUI:E89D87* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:E8A364* + ID_OUI_FROM_DATABASE=Signal Path International / Peachtree Audio + +OUI:E8A4C1* + ID_OUI_FROM_DATABASE=Deep Sea Electronics PLC + +OUI:E8ABFA* + ID_OUI_FROM_DATABASE=Shenzhen Reecam Tech.Ltd. + +OUI:E8B1FC* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:E8B4AE* + ID_OUI_FROM_DATABASE=Shenzhen C&D Electronics Co.,Ltd + +OUI:E8B748* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:E8BA70* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:E8BB3D* + ID_OUI_FROM_DATABASE=Sino Prime-Tech Limited + +OUI:E8BBA8* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD. + +OUI:E8BE81* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:E8C229* + ID_OUI_FROM_DATABASE=H-Displays (MSC) Bhd + +OUI:E8C320* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd + +OUI:E8CBA1* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:E8CC32* + ID_OUI_FROM_DATABASE=Micronet LTD + +OUI:E8CD2D* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:E8CE06* + ID_OUI_FROM_DATABASE=SkyHawke Technologies, LLC. + +OUI:E8D0FA* + ID_OUI_FROM_DATABASE=MKS Instruments Deutschland GmbH + +OUI:E8D483* + ID_OUI_FROM_DATABASE=ULTIMATE Europe Transportation Equipment GmbH + +OUI:E8D4E0* + ID_OUI_FROM_DATABASE=Beijing BenyWave Technology Co., Ltd. + +OUI:E8DA96* + ID_OUI_FROM_DATABASE=Zhuhai Tianrui Electrical Power Tech. Co., Ltd. + +OUI:E8DAAA* + ID_OUI_FROM_DATABASE=VideoHome Technology Corp. + +OUI:E8DE27* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:E8DFF2* + ID_OUI_FROM_DATABASE=PRF Co., Ltd. + +OUI:E8E08F* + ID_OUI_FROM_DATABASE=GRAVOTECH MARKING SAS + +OUI:E8E0B7* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:E8E1E2* + ID_OUI_FROM_DATABASE=Energotest + +OUI:E8E5D6* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E8E732* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:E8E770* + ID_OUI_FROM_DATABASE=Warp9 Tech Design, Inc. + +OUI:E8E776* + ID_OUI_FROM_DATABASE=Shenzhen Kootion Technology Co., Ltd + +OUI:E8E875* + ID_OUI_FROM_DATABASE=iS5 Communications Inc. + +OUI:E8EA6A* + ID_OUI_FROM_DATABASE=StarTech.com + +OUI:E8EADA* + ID_OUI_FROM_DATABASE=Denkovi Assembly Electroncs LTD + +OUI:E8EDF3* + ID_OUI_FROM_DATABASE=Cisco + +OUI:E8F1B0* + ID_OUI_FROM_DATABASE=SAGEMCOM SAS + +OUI:E8F226* + ID_OUI_FROM_DATABASE=MILLSON CUSTOM SOLUTIONS INC. + +OUI:E8F928* + ID_OUI_FROM_DATABASE=RFTECH SRL + +OUI:E8FC60* + ID_OUI_FROM_DATABASE=ELCOM Innovations Private Limited + +OUI:EC0ED6* + ID_OUI_FROM_DATABASE=ITECH INSTRUMENTS SAS + +OUI:EC1120* + ID_OUI_FROM_DATABASE=FloDesign Wind Turbine Corporation + +OUI:EC14F6* + ID_OUI_FROM_DATABASE=BioControl AS + +OUI:EC172F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:EC1766* + ID_OUI_FROM_DATABASE=Research Centre Module + +OUI:EC1A59* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:EC219F* + ID_OUI_FROM_DATABASE=VidaBox LLC + +OUI:EC2257* + ID_OUI_FROM_DATABASE=JiangSu NanJing University Electronic Information Technology Co.,Ltd + +OUI:EC233D* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:EC2368* + ID_OUI_FROM_DATABASE=IntelliVoice Co.,Ltd. + +OUI:EC2AF0* + ID_OUI_FROM_DATABASE=Ypsomed AG + +OUI:EC2C49* + ID_OUI_FROM_DATABASE=University of Tokyo + +OUI:EC3091* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:EC3586* + ID_OUI_FROM_DATABASE=Apple + +OUI:EC3BF0* + ID_OUI_FROM_DATABASE=NovelSat + +OUI:EC3E09* + ID_OUI_FROM_DATABASE=PERFORMANCE DESIGNED PRODUCTS, LLC + +OUI:EC3F05* + ID_OUI_FROM_DATABASE=Institute 706, The Second Academy China Aerospace Science & Industry Corp + +OUI:EC42F0* + ID_OUI_FROM_DATABASE=ADL Embedded Solutions, Inc. + +OUI:EC43E6* + ID_OUI_FROM_DATABASE=AWCER Ltd. + +OUI:EC43F6* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:EC4476* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:EC4644* + ID_OUI_FROM_DATABASE=TTK SAS + +OUI:EC4670* + ID_OUI_FROM_DATABASE=Meinberg Funkuhren GmbH & Co. KG + +OUI:EC473C* + ID_OUI_FROM_DATABASE=Redwire, LLC + +OUI:EC4993* + ID_OUI_FROM_DATABASE=Qihan Technology Co., Ltd + +OUI:EC4C4D* + ID_OUI_FROM_DATABASE=ZAO NPK RoTeK + +OUI:EC542E* + ID_OUI_FROM_DATABASE=Shanghai XiMei Electronic Technology Co. Ltd + +OUI:EC55F9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:EC5C69* + ID_OUI_FROM_DATABASE=MITSUBISHI HEAVY INDUSTRIES MECHATRONICS SYSTEMS,LTD. + +OUI:EC6264* + ID_OUI_FROM_DATABASE=Global411 Internet Services, LLC + +OUI:EC63E5* + ID_OUI_FROM_DATABASE=ePBoard Design LLC + +OUI:EC66D1* + ID_OUI_FROM_DATABASE=B&W Group LTD + +OUI:EC6C9F* + ID_OUI_FROM_DATABASE=Chengdu Volans Technology CO.,LTD + +OUI:EC71DB* + ID_OUI_FROM_DATABASE=Shenzhen Baichuan Digital Technology Co., Ltd. + +OUI:EC7C74* + ID_OUI_FROM_DATABASE=Justone Technologies Co., Ltd. + +OUI:EC7D9D* + ID_OUI_FROM_DATABASE=MEI + +OUI:EC836C* + ID_OUI_FROM_DATABASE=RM Tech Co., Ltd. + +OUI:EC852F* + ID_OUI_FROM_DATABASE=Apple + +OUI:EC888F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:EC89F5* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:EC8EAD* + ID_OUI_FROM_DATABASE=DLX + +OUI:EC9233* + ID_OUI_FROM_DATABASE=Eddyfi NDT Inc + +OUI:EC9327* + ID_OUI_FROM_DATABASE=MEMMERT GmbH + Co. KG + +OUI:EC9681* + ID_OUI_FROM_DATABASE=2276427 Ontario Inc + +OUI:EC986C* + ID_OUI_FROM_DATABASE=Lufft Mess- und Regeltechnik GmbH + +OUI:EC98C1* + ID_OUI_FROM_DATABASE=Beijing Risbo Network Technology Co.,Ltd + +OUI:EC9A74* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:EC9B5B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:EC9ECD* + ID_OUI_FROM_DATABASE=Emerson Network Power and Embedded Computing + +OUI:ECA29B* + ID_OUI_FROM_DATABASE=Kemppi Oy + +OUI:ECA86B* + ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEMS CO., LTD. + +OUI:ECB106* + ID_OUI_FROM_DATABASE=Acuro Networks, Inc + +OUI:ECB541* + ID_OUI_FROM_DATABASE=SHINANO E and E Co.Ltd. + +OUI:ECBBAE* + ID_OUI_FROM_DATABASE=Digivoice Tecnologia em Eletronica Ltda + +OUI:ECBD09* + ID_OUI_FROM_DATABASE=FUSION Electronics Ltd + +OUI:ECC38A* + ID_OUI_FROM_DATABASE=Accuenergy (CANADA) Inc + +OUI:ECC882* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:ECCD6D* + ID_OUI_FROM_DATABASE=Allied Telesis, Inc. + +OUI:ECD00E* + ID_OUI_FROM_DATABASE=MiraeRecognition Co., Ltd. + +OUI:ECD040* + ID_OUI_FROM_DATABASE=GEA Farm Technologies GmbH + +OUI:ECD19A* + ID_OUI_FROM_DATABASE=Zhuhai Liming Industries Co., Ltd + +OUI:ECD925* + ID_OUI_FROM_DATABASE=RAMI + +OUI:ECD950* + ID_OUI_FROM_DATABASE=IRT SA + +OUI:ECDE3D* + ID_OUI_FROM_DATABASE=Lamprey Networks, Inc. + +OUI:ECE09B* + ID_OUI_FROM_DATABASE=Samsung electronics CO., LTD + +OUI:ECE1A9* + ID_OUI_FROM_DATABASE=Cisco + +OUI:ECE555* + ID_OUI_FROM_DATABASE=Hirschmann Automation + +OUI:ECE744* + ID_OUI_FROM_DATABASE=Omntec mfg. inc + +OUI:ECE90B* + ID_OUI_FROM_DATABASE=SISTEMA SOLUCOES ELETRONICAS LTDA - EASYTECH + +OUI:ECE915* + ID_OUI_FROM_DATABASE=STI Ltd + +OUI:ECE9F8* + ID_OUI_FROM_DATABASE=Guang Zhou TRI-SUN Electronics Technology Co., Ltd + +OUI:ECEA03* + ID_OUI_FROM_DATABASE=DARFON LIGHTING CORP + +OUI:ECF00E* + ID_OUI_FROM_DATABASE=Abocom + +OUI:ECF236* + ID_OUI_FROM_DATABASE=NEOMONTANA ELECTRONICS + +OUI:ECF35B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:ECF4BB* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:ECF72B* + ID_OUI_FROM_DATABASE=HD DIGITAL TECH CO., LTD. + +OUI:ECFAAA* + ID_OUI_FROM_DATABASE=The IMS Company + +OUI:ECFC55* + ID_OUI_FROM_DATABASE=A. Eberle GmbH & Co. KG + +OUI:ECFE7E* + ID_OUI_FROM_DATABASE=BlueRadios, Inc. + +OUI:F0007F* + ID_OUI_FROM_DATABASE=Janz - Contadores de Energia, SA + +OUI:F0022B* + ID_OUI_FROM_DATABASE=Chrontel + +OUI:F00248* + ID_OUI_FROM_DATABASE=SmarteBuilding + +OUI:F00786* + ID_OUI_FROM_DATABASE=Shandong Bittel Electronics Co., Ltd + +OUI:F008F1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F013C3* + ID_OUI_FROM_DATABASE=SHENZHEN FENDA TECHNOLOGY CO., LTD + +OUI:F015A0* + ID_OUI_FROM_DATABASE=KyungDong One Co., Ltd. + +OUI:F01C13* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:F01FAF* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:F0219D* + ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Company Ltd. + +OUI:F02329* + ID_OUI_FROM_DATABASE=SHOWA DENKI CO.,LTD. + +OUI:F02405* + ID_OUI_FROM_DATABASE=OPUS High Technology Corporation + +OUI:F02408* + ID_OUI_FROM_DATABASE=Talaris (Sweden) AB + +OUI:F02572* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F025B7* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. + +OUI:F0264C* + ID_OUI_FROM_DATABASE=Dr. Sigrist AG + +OUI:F02765* + ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd. + +OUI:F02929* + ID_OUI_FROM_DATABASE=Cisco + +OUI:F02A61* + ID_OUI_FROM_DATABASE=Waldo Networks, Inc. + +OUI:F02FD8* + ID_OUI_FROM_DATABASE=Bi2-Vision + +OUI:F0321A* + ID_OUI_FROM_DATABASE=Mita-Teknik A/S + +OUI:F037A1* + ID_OUI_FROM_DATABASE=Huike Electronics (SHENZHEN) CO., LTD. + +OUI:F03A4B* + ID_OUI_FROM_DATABASE=Bloombase, Inc. + +OUI:F03A55* + ID_OUI_FROM_DATABASE=Omega Elektronik AS + +OUI:F03FF8* + ID_OUI_FROM_DATABASE=R L Drake + +OUI:F04335* + ID_OUI_FROM_DATABASE=DVN(Shanghai)Ltd. + +OUI:F04A2B* + ID_OUI_FROM_DATABASE=PYRAMID Computer GmbH + +OUI:F04B6A* + ID_OUI_FROM_DATABASE=Scientific Production Association Siberian Arsenal, Ltd. + +OUI:F04BF2* + ID_OUI_FROM_DATABASE=JTECH Communications, Inc. + +OUI:F04DA2* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:F05849* + ID_OUI_FROM_DATABASE=CareView Communications + +OUI:F05A09* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F05D89* + ID_OUI_FROM_DATABASE=Dycon Limited + +OUI:F05DC8* + ID_OUI_FROM_DATABASE=Duracell Powermat + +OUI:F05F5A* + ID_OUI_FROM_DATABASE=Getriebebau NORD GmbH and Co. KG + +OUI:F06130* + ID_OUI_FROM_DATABASE=Advantage Pharmacy Services, LLC + +OUI:F0620D* + ID_OUI_FROM_DATABASE=Shenzhen Egreat Tech Corp.,Ltd + +OUI:F06281* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:F065DD* + ID_OUI_FROM_DATABASE=Primax Electronics Ltd. + +OUI:F06853* + ID_OUI_FROM_DATABASE=Integrated Corporation + +OUI:F06BCA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F0728C* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F073AE* + ID_OUI_FROM_DATABASE=PEAK-System Technik + +OUI:F07765* + ID_OUI_FROM_DATABASE=Sourcefire, Inc + +OUI:F077D0* + ID_OUI_FROM_DATABASE=Xcellen + +OUI:F07BCB* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:F07D68* + ID_OUI_FROM_DATABASE=D-Link Corporation + +OUI:F07F0C* + ID_OUI_FROM_DATABASE=Leopold Kostal GmbH &Co. KG + +OUI:F081AF* + ID_OUI_FROM_DATABASE=IRZ AUTOMATION TECHNOLOGIES LTD + +OUI:F08261* + ID_OUI_FROM_DATABASE=SAGEMCOM + +OUI:F0842F* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:F084C9* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:F08A28* + ID_OUI_FROM_DATABASE=JIANGSU HENGSION ELECTRONIC S and T CO.,LTD + +OUI:F08BFE* + ID_OUI_FROM_DATABASE=COSTEL.,CO.LTD + +OUI:F08EDB* + ID_OUI_FROM_DATABASE=VeloCloud Networks + +OUI:F0921C* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:F0933A* + ID_OUI_FROM_DATABASE=NxtConect + +OUI:F093C5* + ID_OUI_FROM_DATABASE=Garland Technology + +OUI:F09CBB* + ID_OUI_FROM_DATABASE=RaonThink Inc. + +OUI:F09CE9* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc + +OUI:F0A764* + ID_OUI_FROM_DATABASE=GST Co., Ltd. + +OUI:F0ACA4* + ID_OUI_FROM_DATABASE=HBC-radiomatic + +OUI:F0AD4E* + ID_OUI_FROM_DATABASE=Globalscale Technologies, Inc. + +OUI:F0AE51* + ID_OUI_FROM_DATABASE=Xi3 Corp + +OUI:F0B479* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0B6EB* + ID_OUI_FROM_DATABASE=Poslab Technology Co., Ltd. + +OUI:F0BCC8* + ID_OUI_FROM_DATABASE=MaxID (Pty) Ltd + +OUI:F0BDF1* + ID_OUI_FROM_DATABASE=Sipod Inc. + +OUI:F0BF97* + ID_OUI_FROM_DATABASE=Sony Corporation + +OUI:F0C1F1* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:F0C24C* + ID_OUI_FROM_DATABASE=Zhejiang FeiYue Digital Technology Co., Ltd + +OUI:F0C27C* + ID_OUI_FROM_DATABASE=Mianyang Netop Telecom Equipment Co.,Ltd. + +OUI:F0C88C* + ID_OUI_FROM_DATABASE=LeddarTech Inc. + +OUI:F0CBA1* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0D14F* + ID_OUI_FROM_DATABASE=LINEAR LLC + +OUI:F0D1A9* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0D3A7* + ID_OUI_FROM_DATABASE=CobaltRay Co., Ltd + +OUI:F0D3E7* + ID_OUI_FROM_DATABASE=Sensometrix SA + +OUI:F0D767* + ID_OUI_FROM_DATABASE=Axema Passagekontroll AB + +OUI:F0DA7C* + ID_OUI_FROM_DATABASE=RLH INDUSTRIES,INC. + +OUI:F0DB30* + ID_OUI_FROM_DATABASE=Yottabyte + +OUI:F0DBF8* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0DCE2* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0DE71* + ID_OUI_FROM_DATABASE=Shanghai EDO Technologies Co.,Ltd. + +OUI:F0DEB9* + ID_OUI_FROM_DATABASE=ShangHai Y&Y Electronics Co., Ltd + +OUI:F0DEF1* + ID_OUI_FROM_DATABASE=Wistron InfoComm (Kunshan)Co + +OUI:F0E5C3* + ID_OUI_FROM_DATABASE=Drägerwerk AG & Co. KG aA + +OUI:F0E77E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F0EBD0* + ID_OUI_FROM_DATABASE=Shanghai Feixun Communication Co.,Ltd. + +OUI:F0EC39* + ID_OUI_FROM_DATABASE=Essec + +OUI:F0ED1E* + ID_OUI_FROM_DATABASE=Bilkon Bilgisayar Kontrollu Cih. Im.Ltd. + +OUI:F0EEBB* + ID_OUI_FROM_DATABASE=VIPAR GmbH + +OUI:F0F002* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:F0F260* + ID_OUI_FROM_DATABASE=Mobitec AB + +OUI:F0F5AE* + ID_OUI_FROM_DATABASE=Adaptrum Inc. + +OUI:F0F61C* + ID_OUI_FROM_DATABASE=Apple + +OUI:F0F644* + ID_OUI_FROM_DATABASE=Whitesky Science & Technology Co.,Ltd. + +OUI:F0F669* + ID_OUI_FROM_DATABASE=Motion Analysis Corporation + +OUI:F0F755* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F0F7B3* + ID_OUI_FROM_DATABASE=Phorm + +OUI:F0F842* + ID_OUI_FROM_DATABASE=KEEBOX, Inc. + +OUI:F0F9F7* + ID_OUI_FROM_DATABASE=IES GmbH & Co. KG + +OUI:F0FDA0* + ID_OUI_FROM_DATABASE=Acurix Networks LP + +OUI:F40321* + ID_OUI_FROM_DATABASE=BeNeXt B.V. + +OUI:F4044C* + ID_OUI_FROM_DATABASE=ValenceTech Limited + +OUI:F4068D* + ID_OUI_FROM_DATABASE=devolo AG + +OUI:F40B93* + ID_OUI_FROM_DATABASE=Research In Motion + +OUI:F40F9B* + ID_OUI_FROM_DATABASE=WAVELINK + +OUI:F415FD* + ID_OUI_FROM_DATABASE=Shanghai Pateo Electronic Equipment Manufacturing Co., Ltd. + +OUI:F41BA1* + ID_OUI_FROM_DATABASE=Apple + +OUI:F41E26* + ID_OUI_FROM_DATABASE=Simon-Kaloi Engineering + +OUI:F41F0B* + ID_OUI_FROM_DATABASE=YAMABISHI Corporation + +OUI:F41FC2* + ID_OUI_FROM_DATABASE=Cisco + +OUI:F42012* + ID_OUI_FROM_DATABASE=Cuciniale GmbH + +OUI:F42896* + ID_OUI_FROM_DATABASE=SPECTO PAINEIS ELETRONICOS LTDA + +OUI:F436E1* + ID_OUI_FROM_DATABASE=Abilis Systems SARL + +OUI:F437B7* + ID_OUI_FROM_DATABASE=Apple + +OUI:F43814* + ID_OUI_FROM_DATABASE=Shanghai Howell Electronic Co.,Ltd + +OUI:F43D80* + ID_OUI_FROM_DATABASE=FAG Industrial Services GmbH + +OUI:F43E61* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co., Ltd + +OUI:F43E9D* + ID_OUI_FROM_DATABASE=Benu Networks, Inc. + +OUI:F44227* + ID_OUI_FROM_DATABASE=S & S Research Inc. + +OUI:F44450* + ID_OUI_FROM_DATABASE=BND Co., Ltd. + +OUI:F445ED* + ID_OUI_FROM_DATABASE=Portable Innovation Technology Ltd. + +OUI:F4472A* + ID_OUI_FROM_DATABASE=Nanjing Rousing Sci. and Tech. Industrial Co., Ltd + +OUI:F44848* + ID_OUI_FROM_DATABASE=Amscreen Group Ltd + +OUI:F44EFD* + ID_OUI_FROM_DATABASE=Actions Semiconductor Co.,Ltd.(Cayman Islands) + +OUI:F450EB* + ID_OUI_FROM_DATABASE=Telechips Inc + +OUI:F45214* + ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc. + +OUI:F45433* + ID_OUI_FROM_DATABASE=Rockwell Automation + +OUI:F45595* + ID_OUI_FROM_DATABASE=HENGBAO Corporation LTD. + +OUI:F4559C* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:F455E0* + ID_OUI_FROM_DATABASE=Niceway CNC Technology Co.,Ltd.Hunan Province + +OUI:F45842* + ID_OUI_FROM_DATABASE=Boxx TV Ltd + +OUI:F45F69* + ID_OUI_FROM_DATABASE=Matsufu Electronics distribution Company + +OUI:F45FD4* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:F45FF7* + ID_OUI_FROM_DATABASE=DQ Technology Inc. + +OUI:F4600D* + ID_OUI_FROM_DATABASE=Panoptic Technology, Inc + +OUI:F46349* + ID_OUI_FROM_DATABASE=Diffon Corporation + +OUI:F46ABC* + ID_OUI_FROM_DATABASE=Adonit Corp. Ltd. + +OUI:F46D04* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:F46DE2* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:F473CA* + ID_OUI_FROM_DATABASE=Conversion Sound Inc. + +OUI:F47626* + ID_OUI_FROM_DATABASE=Viltechmeda UAB + +OUI:F47A4E* + ID_OUI_FROM_DATABASE=Woojeon&Handan + +OUI:F47ACC* + ID_OUI_FROM_DATABASE=SolidFire, Inc. + +OUI:F47B5E* + ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd + +OUI:F47F35* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F48139* + ID_OUI_FROM_DATABASE=CANON INC. + +OUI:F48771* + ID_OUI_FROM_DATABASE=Infoblox + +OUI:F48E09* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:F490CA* + ID_OUI_FROM_DATABASE=Tensorcom + +OUI:F490EA* + ID_OUI_FROM_DATABASE=Deciso B.V. + +OUI:F49461* + ID_OUI_FROM_DATABASE=NexGen Storage + +OUI:F49466* + ID_OUI_FROM_DATABASE=CountMax, ltd + +OUI:F499AC* + ID_OUI_FROM_DATABASE=WEBER Schraubautomaten GmbH + +OUI:F49F54* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:F4A294* + ID_OUI_FROM_DATABASE=EAGLE WORLD DEVELOPMENT CO., LIMITED + +OUI:F4A52A* + ID_OUI_FROM_DATABASE=Hawa Technologies Inc + +OUI:F4ACC1* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F4B164* + ID_OUI_FROM_DATABASE=Lightning Telecommunications Technology Co. Ltd + +OUI:F4B381* + ID_OUI_FROM_DATABASE=WindowMaster A/S + +OUI:F4B52F* + ID_OUI_FROM_DATABASE=Juniper networks + +OUI:F4B549* + ID_OUI_FROM_DATABASE=Yeastar Technology Co., Ltd. + +OUI:F4B6E5* + ID_OUI_FROM_DATABASE=TerraSem Co.,Ltd + +OUI:F4B72A* + ID_OUI_FROM_DATABASE=TIME INTERCONNECT LTD + +OUI:F4B7E2* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:F4BD7C* + ID_OUI_FROM_DATABASE=Chengdu jinshi communication Co., LTD + +OUI:F4C6D7* + ID_OUI_FROM_DATABASE=blackned GmbH + +OUI:F4C714* + ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd + +OUI:F4C795* + ID_OUI_FROM_DATABASE=WEY Elektronik AG + +OUI:F4CAE5* + ID_OUI_FROM_DATABASE=FREEBOX SA + +OUI:F4CD90* + ID_OUI_FROM_DATABASE=Vispiron Rotec GmbH + +OUI:F4CE46* + ID_OUI_FROM_DATABASE=Hewlett-Packard Company + +OUI:F4CFE2* + ID_OUI_FROM_DATABASE=Cisco + +OUI:F4D9FB* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:F4DC4D* + ID_OUI_FROM_DATABASE=Beijing CCD Digital Technology Co., Ltd + +OUI:F4DCDA* + ID_OUI_FROM_DATABASE=Zhuhai Jiahe Communication Technology Co., limited + +OUI:F4DCF9* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:F4E142* + ID_OUI_FROM_DATABASE=Delta Elektronika BV + +OUI:F4E6D7* + ID_OUI_FROM_DATABASE=Solar Power Technologies, Inc. + +OUI:F4EA67* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F4EC38* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:F4F15A* + ID_OUI_FROM_DATABASE=Apple + +OUI:F4F5A5* + ID_OUI_FROM_DATABASE=Nokia corporation + +OUI:F4F951* + ID_OUI_FROM_DATABASE=Apple + +OUI:F4FC32* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:F80113* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:F80332* + ID_OUI_FROM_DATABASE=Khomp + +OUI:F8051C* + ID_OUI_FROM_DATABASE=DRS Imaging and Targeting Solutions + +OUI:F80BBE* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:F80BD0* + ID_OUI_FROM_DATABASE=Datang Telecom communication terminal (Tianjin) Co., Ltd. + +OUI:F80CF3* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:F80DEA* + ID_OUI_FROM_DATABASE=ZyCast Technology Inc. + +OUI:F80F41* + ID_OUI_FROM_DATABASE=Wistron InfoComm(ZhongShan) Corporation + +OUI:F80F84* + ID_OUI_FROM_DATABASE=Natural Security SAS + +OUI:F81037* + ID_OUI_FROM_DATABASE=Atopia Systems, LP + +OUI:F81547* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:F81654* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:F81A67* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:F81CE5* + ID_OUI_FROM_DATABASE=Telefonbau Behnke GmbH + +OUI:F81D93* + ID_OUI_FROM_DATABASE=Longdhua(Beijing) Controls Technology Co.,Ltd + +OUI:F81EDF* + ID_OUI_FROM_DATABASE=Apple + +OUI:F82285* + ID_OUI_FROM_DATABASE=Cypress Technology CO., LTD. + +OUI:F82793* + ID_OUI_FROM_DATABASE=Apple, Inc + +OUI:F82BC8* + ID_OUI_FROM_DATABASE=Jiangsu Switter Co., Ltd + +OUI:F82EDB* + ID_OUI_FROM_DATABASE=RTW GmbH & Co. KG + +OUI:F82F5B* + ID_OUI_FROM_DATABASE=eGauge Systems LLC + +OUI:F82FA8* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:F83094* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Telecom Limited + +OUI:F8313E* + ID_OUI_FROM_DATABASE=endeavour GmbH + +OUI:F83376* + ID_OUI_FROM_DATABASE=Good Mind Innovation Co., Ltd. + +OUI:F83553* + ID_OUI_FROM_DATABASE=Magenta Research Ltd. + +OUI:F835DD* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + +OUI:F83D4E* + ID_OUI_FROM_DATABASE=Softlink Automation System Co., Ltd + +OUI:F83DFF* + ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd + +OUI:F842FB* + ID_OUI_FROM_DATABASE=Yasuda Joho Co.,ltd. + +OUI:F845AD* + ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. + +OUI:F8462D* + ID_OUI_FROM_DATABASE=SYNTEC Incorporation + +OUI:F8472D* + ID_OUI_FROM_DATABASE=X2gen Digital Corp. Ltd + +OUI:F84897* + ID_OUI_FROM_DATABASE=Hitachi, Ltd. + +OUI:F84A7F* + ID_OUI_FROM_DATABASE=Innometriks Inc + +OUI:F84ABF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:F84F57* + ID_OUI_FROM_DATABASE=Cisco + +OUI:F85063* + ID_OUI_FROM_DATABASE=Verathon + +OUI:F8516D* + ID_OUI_FROM_DATABASE=Denwa Technology Corp. + +OUI:F852DF* + ID_OUI_FROM_DATABASE=VNL Europe AB + +OUI:F854AF* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:F8572E* + ID_OUI_FROM_DATABASE=Core Brands, LLC + +OUI:F85BC9* + ID_OUI_FROM_DATABASE=M-Cube Spa + +OUI:F85C45* + ID_OUI_FROM_DATABASE=IC Nexus Co. Ltd. + +OUI:F85F2A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:F862AA* + ID_OUI_FROM_DATABASE=xn systems + +OUI:F866F2* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:F86971* + ID_OUI_FROM_DATABASE=Seibu Electric Co., + +OUI:F86ECF* + ID_OUI_FROM_DATABASE=Arcx Inc + +OUI:F871FE* + ID_OUI_FROM_DATABASE=The Goldman Sachs Group, Inc. + +OUI:F872EA* + ID_OUI_FROM_DATABASE=Cisco + +OUI:F8769B* + ID_OUI_FROM_DATABASE=Neopis Co., Ltd. + +OUI:F87B62* + ID_OUI_FROM_DATABASE=FASTWEL INTERNATIONAL CO., LTD. Taiwan Branch + +OUI:F87B7A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:F87B8C* + ID_OUI_FROM_DATABASE=Amped Wireless + +OUI:F8811A* + ID_OUI_FROM_DATABASE=OVERKIZ + +OUI:F88C1C* + ID_OUI_FROM_DATABASE=KAISHUN ELECTRONIC TECHNOLOGY CO., LTD. BEIJING + +OUI:F88DEF* + ID_OUI_FROM_DATABASE=Tenebraex + +OUI:F88E85* + ID_OUI_FROM_DATABASE=COMTREND CORPORATION + +OUI:F88FCA* + ID_OUI_FROM_DATABASE=Google Fiber, Inc + +OUI:F8912A* + ID_OUI_FROM_DATABASE=GLP German Light Products GmbH + +OUI:F893F3* + ID_OUI_FROM_DATABASE=VOLANS + +OUI:F89550* + ID_OUI_FROM_DATABASE=Proton Products Chengdu Ltd + +OUI:F897CF* + ID_OUI_FROM_DATABASE=DAESHIN-INFORMATION TECHNOLOGY CO., LTD. + +OUI:F89955* + ID_OUI_FROM_DATABASE=Fortress Technology Inc + +OUI:F89D0D* + ID_OUI_FROM_DATABASE=Control Technology Inc. + +OUI:F89FB8* + ID_OUI_FROM_DATABASE=YAZAKI Energy System Corporation + +OUI:F8A03D* + ID_OUI_FROM_DATABASE=Dinstar Technologies Co., Ltd. + +OUI:F8A2B4* + ID_OUI_FROM_DATABASE=RHEWA-WAAGENFABRIK August Freudewald GmbH &Co. KG + +OUI:F8A45F* + ID_OUI_FROM_DATABASE=Beijing Xiaomi communications co.,ltd + +OUI:F8A963* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + +OUI:F8A9D0* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:F8A9DE* + ID_OUI_FROM_DATABASE=PUISSANCE PLUS + +OUI:F8AA8A* + ID_OUI_FROM_DATABASE=Axview Technology (Shenzhen) Co.,Ltd + +OUI:F8AC6D* + ID_OUI_FROM_DATABASE=Deltenna Ltd + +OUI:F8B156* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:F8B599* + ID_OUI_FROM_DATABASE=Guangzhou CHNAVS Digital Technology Co.,Ltd + +OUI:F8BC12* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:F8C001* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F8C091* + ID_OUI_FROM_DATABASE=Highgates Technology + +OUI:F8C678* + ID_OUI_FROM_DATABASE=Carefusion + +OUI:F8D0AC* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:F8D0BD* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F8D111* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD. + +OUI:F8D3A9* + ID_OUI_FROM_DATABASE=AXAN Networks + +OUI:F8D462* + ID_OUI_FROM_DATABASE=Pumatronix Equipamentos Eletronicos Ltda. + +OUI:F8D756* + ID_OUI_FROM_DATABASE=Simm Tronic Limited + +OUI:F8D7BF* + ID_OUI_FROM_DATABASE=REV Ritter GmbH + +OUI:F8DADF* + ID_OUI_FROM_DATABASE=EcoTech, Inc. + +OUI:F8DAE2* + ID_OUI_FROM_DATABASE=Beta LaserMike + +OUI:F8DAF4* + ID_OUI_FROM_DATABASE=Taishan Online Technology Co., Ltd. + +OUI:F8DB4C* + ID_OUI_FROM_DATABASE=PNY Technologies, INC. + +OUI:F8DB7F* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:F8DB88* + ID_OUI_FROM_DATABASE=Dell Inc PCBA Test + +OUI:F8DC7A* + ID_OUI_FROM_DATABASE=Variscite LTD + +OUI:F8DFA8* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:F8E079* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + +OUI:F8E4FB* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:F8E7B5* + ID_OUI_FROM_DATABASE=µTech Tecnologia LTDA + +OUI:F8E968* + ID_OUI_FROM_DATABASE=Egker Kft. + +OUI:F8EA0A* + ID_OUI_FROM_DATABASE=Dipl.-Math. Michael Rauch + +OUI:F8EDA5* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:F8F005* + ID_OUI_FROM_DATABASE=Newport Media Inc. + +OUI:F8F014* + ID_OUI_FROM_DATABASE=RackWare Inc. + +OUI:F8F082* + ID_OUI_FROM_DATABASE=Orion Networks International, Inc + +OUI:F8F1B6* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC + +OUI:F8F25A* + ID_OUI_FROM_DATABASE=G-Lab GmbH + +OUI:F8F7D3* + ID_OUI_FROM_DATABASE=International Communications Corporation + +OUI:F8F7FF* + ID_OUI_FROM_DATABASE=SYN-TECH SYSTEMS INC + +OUI:F8FB2F* + ID_OUI_FROM_DATABASE=Santur Corporation + +OUI:F8FE5C* + ID_OUI_FROM_DATABASE=Reciprocal Labs Corp + +OUI:F8FEA8* + ID_OUI_FROM_DATABASE=Technico Japan Corporation + +OUI:F8FF5F* + ID_OUI_FROM_DATABASE=Shenzhen Communication Technology Co.,Ltd + +OUI:FC0012* + ID_OUI_FROM_DATABASE=Toshiba Samsung Storage Technolgoy Korea Corporation + +OUI:FC019E* + ID_OUI_FROM_DATABASE=VIEVU + +OUI:FC01CD* + ID_OUI_FROM_DATABASE=FUNDACION TEKNIKER + +OUI:FC0647* + ID_OUI_FROM_DATABASE=Cortland Research, LLC + +OUI:FC07A0* + ID_OUI_FROM_DATABASE=LRE Medical GmbH + +OUI:FC0877* + ID_OUI_FROM_DATABASE=Prentke Romich Company + +OUI:FC09D8* + ID_OUI_FROM_DATABASE=ACTEON Group + +OUI:FC09F6* + ID_OUI_FROM_DATABASE=GUANGDONG TONZE ELECTRIC CO.,LTD + +OUI:FC0A81* + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. + +OUI:FC0FE6* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:FC10BD* + ID_OUI_FROM_DATABASE=Control Sistematizado S.A. + +OUI:FC1186* + ID_OUI_FROM_DATABASE=Logic3 plc + +OUI:FC1349* + ID_OUI_FROM_DATABASE=Global Apps Corp. + +OUI:FC15B4* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:FC1607* + ID_OUI_FROM_DATABASE=Taian Technology(Wuxi) Co.,Ltd. + +OUI:FC1794* + ID_OUI_FROM_DATABASE=InterCreative Co., Ltd + +OUI:FC19D0* + ID_OUI_FROM_DATABASE=Cloud Vision Networks Technology Co.,Ltd. + +OUI:FC1BFF* + ID_OUI_FROM_DATABASE=V-ZUG AG + +OUI:FC1D59* + ID_OUI_FROM_DATABASE=I Smart Cities HK Ltd + +OUI:FC1E16* + ID_OUI_FROM_DATABASE=IPEVO corp + +OUI:FC1F19* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD. + +OUI:FC1FC0* + ID_OUI_FROM_DATABASE=EURECAM + +OUI:FC229C* + ID_OUI_FROM_DATABASE=Han Kyung I Net Co.,Ltd. + +OUI:FC253F* + ID_OUI_FROM_DATABASE=Apple + +OUI:FC27A2* + ID_OUI_FROM_DATABASE=TRANS ELECTRIC CO., LTD. + +OUI:FC2A54* + ID_OUI_FROM_DATABASE=Connected Data, Inc. + +OUI:FC2E2D* + ID_OUI_FROM_DATABASE=Lorom Industrial Co.LTD. + +OUI:FC2F40* + ID_OUI_FROM_DATABASE=Calxeda, Inc. + +OUI:FC3598* + ID_OUI_FROM_DATABASE=Favite Inc. + +OUI:FC35E6* + ID_OUI_FROM_DATABASE=Visteon corp + +OUI:FC3FAB* + ID_OUI_FROM_DATABASE=Henan Lanxin Technology Co., Ltd + +OUI:FC4463* + ID_OUI_FROM_DATABASE=Universal Audio + +OUI:FC4499* + ID_OUI_FROM_DATABASE=Swarco LEA d.o.o. + +OUI:FC455F* + ID_OUI_FROM_DATABASE=JIANGXI SHANSHUI OPTOELECTRONIC TECHNOLOGY CO.,LTD + +OUI:FC48EF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:FC4B1C* + ID_OUI_FROM_DATABASE=INTERSENSOR S.R.L. + +OUI:FC4BBC* + ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd. + +OUI:FC4DD4* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + +OUI:FC5090* + ID_OUI_FROM_DATABASE=SIMEX Sp. z o.o. + +OUI:FC52CE* + ID_OUI_FROM_DATABASE=Control iD + +OUI:FC58FA* + ID_OUI_FROM_DATABASE=Shen Zhen Shi Xin Zhong Xin Technology Co.,Ltd. + +OUI:FC5B24* + ID_OUI_FROM_DATABASE=Weibel Scientific A/S + +OUI:FC5B26* + ID_OUI_FROM_DATABASE=MikroBits + +OUI:FC6018* + ID_OUI_FROM_DATABASE=Zhejiang Kangtai Electric Co., Ltd. + +OUI:FC6198* + ID_OUI_FROM_DATABASE=NEC Personal Products, Ltd + +OUI:FC626E* + ID_OUI_FROM_DATABASE=Beijing MDC Telecom + +OUI:FC683E* + ID_OUI_FROM_DATABASE=Directed Perception, Inc + +OUI:FC6C31* + ID_OUI_FROM_DATABASE=LXinstruments GmbH + +OUI:FC7516* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:FC75E6* + ID_OUI_FROM_DATABASE=Handreamnet + +OUI:FC7CE7* + ID_OUI_FROM_DATABASE=FCI USA LLC + +OUI:FC8329* + ID_OUI_FROM_DATABASE=Trei technics + +OUI:FC8399* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:FC8B97* + ID_OUI_FROM_DATABASE=Shenzhen Gongjin Electronics Co.,Ltd + +OUI:FC8E7E* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:FC8FC4* + ID_OUI_FROM_DATABASE=Intelligent Technology Inc. + +OUI:FC923B* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:FC946C* + ID_OUI_FROM_DATABASE=UBIVELOX + +OUI:FC94E3* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:FC9947* + ID_OUI_FROM_DATABASE=Cisco + +OUI:FC9FAE* + ID_OUI_FROM_DATABASE=Fidus Systems Inc + +OUI:FCA13E* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:FCA841* + ID_OUI_FROM_DATABASE=Avaya, Inc + +OUI:FCA9B0* + ID_OUI_FROM_DATABASE=MIARTECH (SHANGHAI),INC. + +OUI:FCAD0F* + ID_OUI_FROM_DATABASE=QTS NETWORKS + +OUI:FCAF6A* + ID_OUI_FROM_DATABASE=Conemtech AB + +OUI:FCB0C4* + ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co., Ltd + +OUI:FCBBA1* + ID_OUI_FROM_DATABASE=Shenzhen Minicreate Technology Co.,Ltd + +OUI:FCC23D* + ID_OUI_FROM_DATABASE=Atmel Corporation + +OUI:FCC734* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:FCC897* + ID_OUI_FROM_DATABASE=ZTE Corporation + +OUI:FCCCE4* + ID_OUI_FROM_DATABASE=Ascon Ltd. + +OUI:FCCF62* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:FCD4F2* + ID_OUI_FROM_DATABASE=The Coca Cola Company + +OUI:FCD4F6* + ID_OUI_FROM_DATABASE=Messana Air.Ray Conditioning s.r.l. + +OUI:FCD6BD* + ID_OUI_FROM_DATABASE=Robert Bosch GmbH + +OUI:FCD817* + ID_OUI_FROM_DATABASE=Beijing Hesun Technologies Co.Ltd. + +OUI:FCDB96* + ID_OUI_FROM_DATABASE=ENERVALLEY CO., LTD + +OUI:FCDD55* + ID_OUI_FROM_DATABASE=Shenzhen WeWins wireless Co.,Ltd + +OUI:FCE192* + ID_OUI_FROM_DATABASE=Sichuan Jinwangtong Electronic Science&Technology Co,.Ltd + +OUI:FCE1D9* + ID_OUI_FROM_DATABASE=Stable Imaging Solutions LLC + +OUI:FCE23F* + ID_OUI_FROM_DATABASE=CLAY PAKY SPA + +OUI:FCE557* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:FCE892* + ID_OUI_FROM_DATABASE=Hangzhou Lancable Technology Co.,Ltd + +OUI:FCEDB9* + ID_OUI_FROM_DATABASE=Arrayent + +OUI:FCF1CD* + ID_OUI_FROM_DATABASE=OPTEX-FA CO.,LTD. + +OUI:FCF528* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:FCF8AE* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:FCF8B7* + ID_OUI_FROM_DATABASE=TRONTEQ Electronic + +OUI:FCFAF7* + ID_OUI_FROM_DATABASE=Shanghai Baud Data Communication Co.,Ltd. + +OUI:FCFBFB* + ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC. + +OUI:FCFE77* + ID_OUI_FROM_DATABASE=Hitachi Reftechno, Inc. diff --git a/hwdb/20-acpi-vendor.hwdb b/hwdb/20-acpi-vendor.hwdb new file mode 100644 index 0000000..9b3b009 --- /dev/null +++ b/hwdb/20-acpi-vendor.hwdb @@ -0,0 +1,6593 @@ +# This file is part of systemd. +# +# Data imported from: +# http://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/ISA_PNPID_List.xlsx +# Non-unique, duplicate assignements manually removed. + +acpi:AAA*: + ID_VENDOR_FROM_DATABASE=Avolites Ltd + +acpi:AAE*: + ID_VENDOR_FROM_DATABASE=Anatek Electronics Inc. + +acpi:AAT*: + ID_VENDOR_FROM_DATABASE=Ann Arbor Technologies + +acpi:ABA*: + ID_VENDOR_FROM_DATABASE=ABBAHOME INC. + +acpi:ABC*: + ID_VENDOR_FROM_DATABASE=AboCom System Inc + +acpi:ABD*: + ID_VENDOR_FROM_DATABASE=Allen Bradley Company + +acpi:ABE*: + ID_VENDOR_FROM_DATABASE=Alcatel Bell + +acpi:ABO*: + ID_VENDOR_FROM_DATABASE=D-Link Systems Inc + +acpi:ABT*: + ID_VENDOR_FROM_DATABASE=Anchor Bay Technologies, Inc. + +acpi:ABV*: + ID_VENDOR_FROM_DATABASE=Advanced Research Technology + +acpi:ACA*: + ID_VENDOR_FROM_DATABASE=Ariel Corporation + +acpi:ACB*: + ID_VENDOR_FROM_DATABASE=Aculab Ltd + +acpi:ACC*: + ID_VENDOR_FROM_DATABASE=Accton Technology Corporation + +acpi:ACD*: + ID_VENDOR_FROM_DATABASE=AWETA BV + +acpi:ACE*: + ID_VENDOR_FROM_DATABASE=Actek Engineering Pty Ltd + +acpi:ACG*: + ID_VENDOR_FROM_DATABASE=A&R Cambridge Ltd + +acpi:ACH*: + ID_VENDOR_FROM_DATABASE=Archtek Telecom Corporation + +acpi:ACI*: + ID_VENDOR_FROM_DATABASE=Ancor Communications Inc + +acpi:ACK*: + ID_VENDOR_FROM_DATABASE=Acksys + +acpi:ACL*: + ID_VENDOR_FROM_DATABASE=Apricot Computers + +acpi:ACM*: + ID_VENDOR_FROM_DATABASE=Acroloop Motion Control Systems Inc + +acpi:ACO*: + ID_VENDOR_FROM_DATABASE=Allion Computer Inc. + +acpi:ACP[0-9A-F]*: + ID_VENDOR_FROM_DATABASE=Aspen Tech Inc + +acpi:ACR*: + ID_VENDOR_FROM_DATABASE=Acer Technologies + +acpi:ACS*: + ID_VENDOR_FROM_DATABASE=Altos Computer Systems + +acpi:ACT*: + ID_VENDOR_FROM_DATABASE=Applied Creative Technology + +acpi:ACU*: + ID_VENDOR_FROM_DATABASE=Acculogic + +acpi:ACV*: + ID_VENDOR_FROM_DATABASE=ActivCard S.A + +acpi:ADA*: + ID_VENDOR_FROM_DATABASE=Addi-Data GmbH + +acpi:ADB*: + ID_VENDOR_FROM_DATABASE=Aldebbaron + +acpi:ADC*: + ID_VENDOR_FROM_DATABASE=Acnhor Datacomm + +acpi:ADD*: + ID_VENDOR_FROM_DATABASE=Advanced Peripheral Devices Inc + +acpi:ADE*: + ID_VENDOR_FROM_DATABASE=Arithmos, Inc. + +acpi:ADH*: + ID_VENDOR_FROM_DATABASE=Aerodata Holdings Ltd + +acpi:ADI*: + ID_VENDOR_FROM_DATABASE=ADI Systems Inc + +acpi:ADK*: + ID_VENDOR_FROM_DATABASE=Adtek System Science Company Ltd + +acpi:ADL*: + ID_VENDOR_FROM_DATABASE=ASTRA Security Products Ltd + +acpi:ADM*: + ID_VENDOR_FROM_DATABASE=Ad Lib MultiMedia Inc + +acpi:ADN*: + ID_VENDOR_FROM_DATABASE=Analog & Digital Devices Tel. Inc + +acpi:ADP*: + ID_VENDOR_FROM_DATABASE=Adaptec Inc + +acpi:ADR*: + ID_VENDOR_FROM_DATABASE=Nasa Ames Research Center + +acpi:ADS*: + ID_VENDOR_FROM_DATABASE=Analog Devices Inc + +acpi:ADT*: + ID_VENDOR_FROM_DATABASE=Aved Display Technologies + +acpi:ADV*: + ID_VENDOR_FROM_DATABASE=Advanced Micro Devices Inc + +acpi:ADX*: + ID_VENDOR_FROM_DATABASE=Adax Inc + +acpi:AEC*: + ID_VENDOR_FROM_DATABASE=Antex Electronics Corporation + +acpi:AED*: + ID_VENDOR_FROM_DATABASE=Advanced Electronic Designs, Inc. + +acpi:AEI*: + ID_VENDOR_FROM_DATABASE=Actiontec Electric Inc + +acpi:AEJ*: + ID_VENDOR_FROM_DATABASE=Alpha Electronics Company + +acpi:AEM*: + ID_VENDOR_FROM_DATABASE=ASEM S.p.A. + +acpi:AEN*: + ID_VENDOR_FROM_DATABASE=Avencall + +acpi:AEP*: + ID_VENDOR_FROM_DATABASE=Aetas Peripheral International + +acpi:AET*: + ID_VENDOR_FROM_DATABASE=Aethra Telecomunicazioni S.r.l. + +acpi:AFA*: + ID_VENDOR_FROM_DATABASE=Alfa Inc + +acpi:AGC*: + ID_VENDOR_FROM_DATABASE=Beijing Aerospace Golden Card Electronic Engineering Co.,Ltd. + +acpi:AGI*: + ID_VENDOR_FROM_DATABASE=Artish Graphics Inc + +acpi:AGL*: + ID_VENDOR_FROM_DATABASE=Argolis + +acpi:AGM*: + ID_VENDOR_FROM_DATABASE=Advan Int'l Corporation + +acpi:AGT*: + ID_VENDOR_FROM_DATABASE=Agilent Technologies + +acpi:AHC*: + ID_VENDOR_FROM_DATABASE=Advantech Co., Ltd. + +acpi:AIC*: + ID_VENDOR_FROM_DATABASE=Arnos Insturments & Computer Systems + +acpi:AIE*: + ID_VENDOR_FROM_DATABASE=Altmann Industrieelektronik + +acpi:AII*: + ID_VENDOR_FROM_DATABASE=Amptron International Inc. + +acpi:AIL*: + ID_VENDOR_FROM_DATABASE=Altos India Ltd + +acpi:AIM*: + ID_VENDOR_FROM_DATABASE=AIMS Lab Inc + +acpi:AIR*: + ID_VENDOR_FROM_DATABASE=Advanced Integ. Research Inc + +acpi:AIS*: + ID_VENDOR_FROM_DATABASE=Alien Internet Services + +acpi:AIW*: + ID_VENDOR_FROM_DATABASE=Aiwa Company Ltd + +acpi:AIX*: + ID_VENDOR_FROM_DATABASE=ALTINEX, INC. + +acpi:AJA*: + ID_VENDOR_FROM_DATABASE=AJA Video Systems, Inc. + +acpi:AKB*: + ID_VENDOR_FROM_DATABASE=Akebia Ltd + +acpi:AKE*: + ID_VENDOR_FROM_DATABASE=AKAMI Electric Co.,Ltd + +acpi:AKI*: + ID_VENDOR_FROM_DATABASE=AKIA Corporation + +acpi:AKL*: + ID_VENDOR_FROM_DATABASE=AMiT Ltd + +acpi:AKM*: + ID_VENDOR_FROM_DATABASE=Asahi Kasei Microsystems Company Ltd + +acpi:AKP*: + ID_VENDOR_FROM_DATABASE=Atom Komplex Prylad + +acpi:AKY*: + ID_VENDOR_FROM_DATABASE=Askey Computer Corporation + +acpi:ALA*: + ID_VENDOR_FROM_DATABASE=Alacron Inc + +acpi:ALC*: + ID_VENDOR_FROM_DATABASE=Altec Corporation + +acpi:ALD*: + ID_VENDOR_FROM_DATABASE=In4S Inc + +acpi:ALG*: + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Corp. + +acpi:ALH*: + ID_VENDOR_FROM_DATABASE=AL Systems + +acpi:ALI*: + ID_VENDOR_FROM_DATABASE=Acer Labs + +acpi:ALJ*: + ID_VENDOR_FROM_DATABASE=Altec Lansing + +acpi:ALK*: + ID_VENDOR_FROM_DATABASE=Acrolink Inc + +acpi:ALL*: + ID_VENDOR_FROM_DATABASE=Alliance Semiconductor Corporation + +acpi:ALM*: + ID_VENDOR_FROM_DATABASE=Acutec Ltd. + +acpi:ALN*: + ID_VENDOR_FROM_DATABASE=Alana Technologies + +acpi:ALO*: + ID_VENDOR_FROM_DATABASE=Algolith Inc. + +acpi:ALP*: + ID_VENDOR_FROM_DATABASE=Alps Electric Company Ltd + +acpi:ALR*: + ID_VENDOR_FROM_DATABASE=Advanced Logic + +acpi:ALS*: + ID_VENDOR_FROM_DATABASE=Avance Logic Inc + +acpi:ALT*: + ID_VENDOR_FROM_DATABASE=Altra + +acpi:ALV*: + ID_VENDOR_FROM_DATABASE=AlphaView LCD + +acpi:ALX*: + ID_VENDOR_FROM_DATABASE=ALEXON Co.,Ltd. + +acpi:AMA*: + ID_VENDOR_FROM_DATABASE=Asia Microelectronic Development Inc + +acpi:AMB*: + ID_VENDOR_FROM_DATABASE=Ambient Technologies, Inc. + +acpi:AMC*: + ID_VENDOR_FROM_DATABASE=Attachmate Corporation + +acpi:AMD*: + ID_VENDOR_FROM_DATABASE=Amdek Corporation + +acpi:AMI*: + ID_VENDOR_FROM_DATABASE=American Megatrends Inc + +acpi:AML*: + ID_VENDOR_FROM_DATABASE=Anderson Multimedia Communications (HK) Limited + +acpi:AMN*: + ID_VENDOR_FROM_DATABASE=Amimon LTD. + +acpi:AMO*: + ID_VENDOR_FROM_DATABASE=Amino Technologies PLC and Amino Communications Limited + +acpi:AMP*: + ID_VENDOR_FROM_DATABASE=AMP Inc + +acpi:AMS *: + ID_VENDOR_FROM_DATABASE=ARMSTEL, Inc. + +acpi:AMT*: + ID_VENDOR_FROM_DATABASE=AMT International Industry + +acpi:AMX*: + ID_VENDOR_FROM_DATABASE=AMX LLC + +acpi:ANA*: + ID_VENDOR_FROM_DATABASE=Anakron + +acpi:ANC*: + ID_VENDOR_FROM_DATABASE=Ancot + +acpi:AND*: + ID_VENDOR_FROM_DATABASE=Adtran Inc + +acpi:ANI*: + ID_VENDOR_FROM_DATABASE=Anigma Inc + +acpi:ANK*: + ID_VENDOR_FROM_DATABASE=Anko Electronic Company Ltd + +acpi:ANL*: + ID_VENDOR_FROM_DATABASE=Analogix Semiconductor, Inc + +acpi:ANO*: + ID_VENDOR_FROM_DATABASE=Anorad Corporation + +acpi:ANP*: + ID_VENDOR_FROM_DATABASE=Andrew Network Production + +acpi:ANR*: + ID_VENDOR_FROM_DATABASE=ANR Ltd + +acpi:ANS*: + ID_VENDOR_FROM_DATABASE=Ansel Communication Company + +acpi:ANT*: + ID_VENDOR_FROM_DATABASE=Ace CAD Enterprise Company Ltd + +acpi:ANX*: + ID_VENDOR_FROM_DATABASE=Acer Netxus Inc + +acpi:AOA*: + ID_VENDOR_FROM_DATABASE=AOpen Inc. + +acpi:AOE*: + ID_VENDOR_FROM_DATABASE=Advanced Optics Electronics, Inc. + +acpi:AOL*: + ID_VENDOR_FROM_DATABASE=America OnLine + +acpi:AOT*: + ID_VENDOR_FROM_DATABASE=Alcatel + +acpi:APC*: + ID_VENDOR_FROM_DATABASE=American Power Conversion + +acpi:APD*: + ID_VENDOR_FROM_DATABASE=AppliAdata + +acpi:APG*: + ID_VENDOR_FROM_DATABASE=Horner Electric Inc + +acpi:API*: + ID_VENDOR_FROM_DATABASE=A Plus Info Corporation + +acpi:APL*: + ID_VENDOR_FROM_DATABASE=Aplicom Oy + +acpi:APM*: + ID_VENDOR_FROM_DATABASE=Applied Memory Tech + +acpi:APN*: + ID_VENDOR_FROM_DATABASE=Appian Tech Inc + +acpi:APP*: + ID_VENDOR_FROM_DATABASE=Apple Computer Inc + +acpi:APR*: + ID_VENDOR_FROM_DATABASE=Aprilia s.p.a. + +acpi:APS*: + ID_VENDOR_FROM_DATABASE=Autologic Inc + +acpi:APT*: + ID_VENDOR_FROM_DATABASE=Audio Processing Technology Ltd + +acpi:APV*: + ID_VENDOR_FROM_DATABASE=A+V Link + +acpi:APX*: + ID_VENDOR_FROM_DATABASE=AP Designs Ltd + +acpi:ARC*: + ID_VENDOR_FROM_DATABASE=Alta Research Corporation + +acpi:ARE*: + ID_VENDOR_FROM_DATABASE=ICET S.p.A. + +acpi:ARG*: + ID_VENDOR_FROM_DATABASE=Argus Electronics Co., LTD + +acpi:ARI*: + ID_VENDOR_FROM_DATABASE=Argosy Research Inc + +acpi:ARK*: + ID_VENDOR_FROM_DATABASE=Ark Logic Inc + +acpi:ARL*: + ID_VENDOR_FROM_DATABASE=Arlotto Comnet Inc + +acpi:ARM*: + ID_VENDOR_FROM_DATABASE=Arima + +acpi:ARO*: + ID_VENDOR_FROM_DATABASE=Poso International B.V. + +acpi:ARS*: + ID_VENDOR_FROM_DATABASE=Arescom Inc + +acpi:ART*: + ID_VENDOR_FROM_DATABASE=Corion Industrial Corporation + +acpi:ASC*: + ID_VENDOR_FROM_DATABASE=Ascom Strategic Technology Unit + +acpi:ASD*: + ID_VENDOR_FROM_DATABASE=USC Information Sciences Institute + +acpi:ASE*: + ID_VENDOR_FROM_DATABASE=AseV Display Labs + +acpi:ASI*: + ID_VENDOR_FROM_DATABASE=Ahead Systems + +acpi:ASK*: + ID_VENDOR_FROM_DATABASE=Ask A/S + +acpi:ASL*: + ID_VENDOR_FROM_DATABASE=AccuScene Corporation Ltd + +acpi:ASM*: + ID_VENDOR_FROM_DATABASE=ASEM S.p.A. + +acpi:ASN*: + ID_VENDOR_FROM_DATABASE=Asante Tech Inc + +acpi:ASP*: + ID_VENDOR_FROM_DATABASE=ASP Microelectronics Ltd + +acpi:AST*: + ID_VENDOR_FROM_DATABASE=AST Research Inc + +acpi:ASU*: + ID_VENDOR_FROM_DATABASE=Asuscom Network Inc + +acpi:ASX*: + ID_VENDOR_FROM_DATABASE=AudioScience + +acpi:ASY*: + ID_VENDOR_FROM_DATABASE=Rockwell Collins / Airshow Systems + +acpi:ATA*: + ID_VENDOR_FROM_DATABASE=Allied Telesyn International (Asia) Pte Ltd + +acpi:ATC*: + ID_VENDOR_FROM_DATABASE=Ably-Tech Corporation + +acpi:ATD*: + ID_VENDOR_FROM_DATABASE=Alpha Telecom Inc + +acpi:ATE*: + ID_VENDOR_FROM_DATABASE=Innovate Ltd + +acpi:ATH*: + ID_VENDOR_FROM_DATABASE=Athena Informatica S.R.L. + +acpi:ATI*: + ID_VENDOR_FROM_DATABASE=Allied Telesis KK + +acpi:ATK*: + ID_VENDOR_FROM_DATABASE=Allied Telesyn Int'l + +acpi:ATL*: + ID_VENDOR_FROM_DATABASE=Arcus Technology Ltd + +acpi:ATM*: + ID_VENDOR_FROM_DATABASE=ATM Ltd + +acpi:ATN*: + ID_VENDOR_FROM_DATABASE=Athena Smartcard Solutions Ltd. + +acpi:ATO*: + ID_VENDOR_FROM_DATABASE=ASTRO DESIGN, INC. + +acpi:ATP*: + ID_VENDOR_FROM_DATABASE=Alpha-Top Corporation + +acpi:ATT*: + ID_VENDOR_FROM_DATABASE=AT&T + +acpi:ATV*: + ID_VENDOR_FROM_DATABASE=Office Depot, Inc. + +acpi:ATX*: + ID_VENDOR_FROM_DATABASE=Athenix Corporation + +acpi:AUI*: + ID_VENDOR_FROM_DATABASE=Alps Electric Inc + +acpi:AUR*: + ID_VENDOR_FROM_DATABASE=Aureal Semiconductor + +acpi:AUT*: + ID_VENDOR_FROM_DATABASE=Autotime Corporation + +acpi:AVA*: + ID_VENDOR_FROM_DATABASE=Avaya Communication + +acpi:AVC*: + ID_VENDOR_FROM_DATABASE=Auravision Corporation + +acpi:AVD*: + ID_VENDOR_FROM_DATABASE=Avid Electronics Corporation + +acpi:AVE*: + ID_VENDOR_FROM_DATABASE=Add Value Enterpises (Asia) Pte Ltd + +acpi:AVI*: + ID_VENDOR_FROM_DATABASE=Nippon Avionics Co.,Ltd + +acpi:AVL*: + ID_VENDOR_FROM_DATABASE=Avalue Technology Inc. + +acpi:AVM*: + ID_VENDOR_FROM_DATABASE=AVM GmbH + +acpi:AVN *: + ID_VENDOR_FROM_DATABASE=Advance Computer Corporation + +acpi:AVO*: + ID_VENDOR_FROM_DATABASE=Avocent Corporation + +acpi:AVR*: + ID_VENDOR_FROM_DATABASE=AVer Information Inc. + +acpi:AVT*: + ID_VENDOR_FROM_DATABASE=Avtek (Electronics) Pty Ltd + +acpi:AVV*: + ID_VENDOR_FROM_DATABASE=SBS Technologies (Canada), Inc. (was Avvida Systems, Inc.) + +acpi:AWC*: + ID_VENDOR_FROM_DATABASE=Access Works Comm Inc + +acpi:AWL*: + ID_VENDOR_FROM_DATABASE=Aironet Wireless Communications, Inc + +acpi:AWS*: + ID_VENDOR_FROM_DATABASE=Wave Systems + +acpi:AXB*: + ID_VENDOR_FROM_DATABASE=Adrienne Electronics Corporation + +acpi:AXC*: + ID_VENDOR_FROM_DATABASE=AXIOMTEK CO., LTD. + +acpi:AXE*: + ID_VENDOR_FROM_DATABASE=D-Link Systems Inc (used as 2nd pnpid) + +acpi:AXI*: + ID_VENDOR_FROM_DATABASE=American Magnetics + +acpi:AXL*: + ID_VENDOR_FROM_DATABASE=Axel + +acpi:AXO*: + ID_VENDOR_FROM_DATABASE=Axonic Labs LLC + +acpi:AXP*: + ID_VENDOR_FROM_DATABASE=American Express + +acpi:AXT*: + ID_VENDOR_FROM_DATABASE=Axtend Technologies Inc + +acpi:AXX*: + ID_VENDOR_FROM_DATABASE=Axxon Computer Corporation + +acpi:AXY*: + ID_VENDOR_FROM_DATABASE=AXYZ Automation Services, Inc + +acpi:AYD*: + ID_VENDOR_FROM_DATABASE=Aydin Displays + +acpi:AYR*: + ID_VENDOR_FROM_DATABASE=Airlib, Inc + +acpi:AZM*: + ID_VENDOR_FROM_DATABASE=AZ Middelheim - Radiotherapy + +acpi:AZT*: + ID_VENDOR_FROM_DATABASE=Aztech Systems Ltd + +acpi:BAC*: + ID_VENDOR_FROM_DATABASE=Biometric Access Corporation + +acpi:BAN*: + ID_VENDOR_FROM_DATABASE=Banyan + +acpi:BBB*: + ID_VENDOR_FROM_DATABASE=an-najah university + +acpi:BBH*: + ID_VENDOR_FROM_DATABASE=B&Bh + +acpi:BBL*: + ID_VENDOR_FROM_DATABASE=Brain Boxes Limited + +acpi:BCC*: + ID_VENDOR_FROM_DATABASE=Beaver Computer Corporaton + +acpi:BCD*: + ID_VENDOR_FROM_DATABASE=Barco GmbH + +acpi:BCM*: + ID_VENDOR_FROM_DATABASE=Broadcom + +acpi:BCQ*: + ID_VENDOR_FROM_DATABASE=Deutsche Telekom Berkom GmbH + +acpi:BCS*: + ID_VENDOR_FROM_DATABASE=Booria CAD/CAM systems + +acpi:BDO*: + ID_VENDOR_FROM_DATABASE=Brahler ICS + +acpi:BDR*: + ID_VENDOR_FROM_DATABASE=Blonder Tongue Labs, Inc. + +acpi:BDS*: + ID_VENDOR_FROM_DATABASE=Barco Display Systems + +acpi:BEC*: + ID_VENDOR_FROM_DATABASE=Elektro Beckhoff GmbH + +acpi:BEI*: + ID_VENDOR_FROM_DATABASE=Beckworth Enterprises Inc + +acpi:BEK*: + ID_VENDOR_FROM_DATABASE=Beko Elektronik A.S. + +acpi:BEL*: + ID_VENDOR_FROM_DATABASE=Beltronic Industrieelektronik GmbH + +acpi:BEO*: + ID_VENDOR_FROM_DATABASE=Baug & Olufsen + +acpi:BFE*: + ID_VENDOR_FROM_DATABASE=B.F. Engineering Corporation + +acpi:BGB*: + ID_VENDOR_FROM_DATABASE=Barco Graphics N.V + +acpi:BGT*: + ID_VENDOR_FROM_DATABASE=Budzetron Inc + +acpi:BHZ*: + ID_VENDOR_FROM_DATABASE=BitHeadz, Inc. + +acpi:BIC*: + ID_VENDOR_FROM_DATABASE=Big Island Communications + +acpi:BII*: + ID_VENDOR_FROM_DATABASE=Boeckeler Instruments Inc + +acpi:BIL*: + ID_VENDOR_FROM_DATABASE=Billion Electric Company Ltd + +acpi:BIO*: + ID_VENDOR_FROM_DATABASE=BioLink Technologies International, Inc. + +acpi:BIT*: + ID_VENDOR_FROM_DATABASE=Bit 3 Computer + +acpi:BLI*: + ID_VENDOR_FROM_DATABASE=Busicom + +acpi:BLN*: + ID_VENDOR_FROM_DATABASE=BioLink Technologies + +acpi:BLP*: + ID_VENDOR_FROM_DATABASE=Bloomberg L.P. + +acpi:BMI*: + ID_VENDOR_FROM_DATABASE=Benson Medical Instruments Company + +acpi:BML*: + ID_VENDOR_FROM_DATABASE=BIOMED Lab + +acpi:BMS*: + ID_VENDOR_FROM_DATABASE=BIOMEDISYS + +acpi:BNE*: + ID_VENDOR_FROM_DATABASE=Bull AB + +acpi:BNK*: + ID_VENDOR_FROM_DATABASE=Banksia Tech Pty Ltd + +acpi:BNO*: + ID_VENDOR_FROM_DATABASE=Bang & Olufsen + +acpi:BNS*: + ID_VENDOR_FROM_DATABASE=Boulder Nonlinear Systems + +acpi:BOB*: + ID_VENDOR_FROM_DATABASE=Rainy Orchard + +acpi:BOE*: + ID_VENDOR_FROM_DATABASE=BOE + +acpi:BOI*: + ID_VENDOR_FROM_DATABASE=NINGBO BOIGLE DIGITAL TECHNOLOGY CO.,LTD + +acpi:BOS*: + ID_VENDOR_FROM_DATABASE=BOS + +acpi:BPD*: + ID_VENDOR_FROM_DATABASE=Micro Solutions, Inc. + +acpi:BPU*: + ID_VENDOR_FROM_DATABASE=Best Power + +acpi:BRA*: + ID_VENDOR_FROM_DATABASE=Braemac Pty Ltd + +acpi:BRC*: + ID_VENDOR_FROM_DATABASE=BARC + +acpi:BRG*: + ID_VENDOR_FROM_DATABASE=Bridge Information Co., Ltd + +acpi:BRI*: + ID_VENDOR_FROM_DATABASE=Boca Research Inc + +acpi:BRM*: + ID_VENDOR_FROM_DATABASE=Braemar Inc + +acpi:BRO*: + ID_VENDOR_FROM_DATABASE=BROTHER INDUSTRIES,LTD. + +acpi:BSE*: + ID_VENDOR_FROM_DATABASE=Bose Corporation + +acpi:BSL*: + ID_VENDOR_FROM_DATABASE=Biomedical Systems Laboratory + +acpi:BSN*: + ID_VENDOR_FROM_DATABASE=BRIGHTSIGN, LLC + +acpi:BST*: + ID_VENDOR_FROM_DATABASE=BodySound Technologies, Inc. + +acpi:BTC*: + ID_VENDOR_FROM_DATABASE=Bit 3 Computer + +acpi:BTE*: + ID_VENDOR_FROM_DATABASE=Brilliant Technology + +acpi:BTF*: + ID_VENDOR_FROM_DATABASE=Bitfield Oy + +acpi:BTI*: + ID_VENDOR_FROM_DATABASE=BusTech Inc + +acpi:BTO*: + ID_VENDOR_FROM_DATABASE=BioTao Ltd + +acpi:BUF*: + ID_VENDOR_FROM_DATABASE=Yasuhiko Shirai Melco Inc + +acpi:BUG*: + ID_VENDOR_FROM_DATABASE=B.U.G., Inc. + +acpi:BUJ*: + ID_VENDOR_FROM_DATABASE=ATI Tech Inc + +acpi:BUL*: + ID_VENDOR_FROM_DATABASE=Bull + +acpi:BUR*: + ID_VENDOR_FROM_DATABASE=Bernecker & Rainer Ind-Eletronik GmbH + +acpi:BUS*: + ID_VENDOR_FROM_DATABASE=BusTek + +acpi:BUT*: + ID_VENDOR_FROM_DATABASE=21ST CENTURY ENTERTAINMENT + +acpi:BWK*: + ID_VENDOR_FROM_DATABASE=Bitworks Inc. + +acpi:BXE*: + ID_VENDOR_FROM_DATABASE=Buxco Electronics + +acpi:BYD*: + ID_VENDOR_FROM_DATABASE=byd:sign corporation + +acpi:CAA*: + ID_VENDOR_FROM_DATABASE=Castles Automation Co., Ltd + +acpi:CAC*: + ID_VENDOR_FROM_DATABASE=CA & F Elettronica + +acpi:CAG*: + ID_VENDOR_FROM_DATABASE=CalComp + +acpi:CAI*: + ID_VENDOR_FROM_DATABASE=Canon Inc. + +acpi:CAL*: + ID_VENDOR_FROM_DATABASE=Acon + +acpi:CAM*: + ID_VENDOR_FROM_DATABASE=Cambridge Audio + +acpi:CAN*: + ID_VENDOR_FROM_DATABASE=Canopus Company Ltd + +acpi:CAR*: + ID_VENDOR_FROM_DATABASE=Cardinal Company Ltd + +acpi:CAS*: + ID_VENDOR_FROM_DATABASE=CASIO COMPUTER CO.,LTD + +acpi:CAT*: + ID_VENDOR_FROM_DATABASE=Consultancy in Advanced Technology + +acpi:CAV*: + ID_VENDOR_FROM_DATABASE=Cavium Networks, Inc + +acpi:CBI*: + ID_VENDOR_FROM_DATABASE=ComputerBoards Inc + +acpi:CBR*: + ID_VENDOR_FROM_DATABASE=Cebra Tech A/S + +acpi:CBT*: + ID_VENDOR_FROM_DATABASE=Cabletime Ltd + +acpi:CBX*: + ID_VENDOR_FROM_DATABASE=Cybex Computer Products Corporation + +acpi:CCC*: + ID_VENDOR_FROM_DATABASE=C-Cube Microsystems + +acpi:CCI*: + ID_VENDOR_FROM_DATABASE=Cache + +acpi:CCJ*: + ID_VENDOR_FROM_DATABASE=CONTEC CO.,LTD. + +acpi:CCL*: + ID_VENDOR_FROM_DATABASE=CCL/ITRI + +acpi:CCP*: + ID_VENDOR_FROM_DATABASE=Capetronic USA Inc + +acpi:CDC*: + ID_VENDOR_FROM_DATABASE=Core Dynamics Corporation + +acpi:CDD*: + ID_VENDOR_FROM_DATABASE=Convergent Data Devices + +acpi:CDE*: + ID_VENDOR_FROM_DATABASE=Colin.de + +acpi:CDG*: + ID_VENDOR_FROM_DATABASE=Christie Digital Systems Inc + +acpi:CDI*: + ID_VENDOR_FROM_DATABASE=Concept Development Inc + +acpi:CDK*: + ID_VENDOR_FROM_DATABASE=Cray Communications + +acpi:CDN*: + ID_VENDOR_FROM_DATABASE=Codenoll Technical Corporation + +acpi:CDP*: + ID_VENDOR_FROM_DATABASE=CalComp + +acpi:CDS*: + ID_VENDOR_FROM_DATABASE=Computer Diagnostic Systems + +acpi:CDT*: + ID_VENDOR_FROM_DATABASE=IBM Corporation + +acpi:CDV*: + ID_VENDOR_FROM_DATABASE=Convergent Design Inc. + +acpi:CEA*: + ID_VENDOR_FROM_DATABASE=Consumer Electronics Association + +acpi:CEC*: + ID_VENDOR_FROM_DATABASE=Chicony Electronics Company Ltd + +acpi:CED*: + ID_VENDOR_FROM_DATABASE=Cambridge Electronic Design Ltd + +acpi:CEF*: + ID_VENDOR_FROM_DATABASE=Cefar Digital Vision + +acpi:CEI*: + ID_VENDOR_FROM_DATABASE=Crestron Electronics, Inc. + +acpi:CEM*: + ID_VENDOR_FROM_DATABASE=MEC Electronics GmbH + +acpi:CEN*: + ID_VENDOR_FROM_DATABASE=Centurion Technologies P/L + +acpi:CEP*: + ID_VENDOR_FROM_DATABASE=C-DAC + +acpi:CER*: + ID_VENDOR_FROM_DATABASE=Ceronix + +acpi:CET*: + ID_VENDOR_FROM_DATABASE=TEC CORPORATION + +acpi:CFG*: + ID_VENDOR_FROM_DATABASE=Atlantis + +acpi:CGA*: + ID_VENDOR_FROM_DATABASE=Chunghwa Picture Tubes, LTD + +acpi:CGS*: + ID_VENDOR_FROM_DATABASE=Chyron Corp + +acpi:CGT*: + ID_VENDOR_FROM_DATABASE=congatec AG + +acpi:CHA*: + ID_VENDOR_FROM_DATABASE=Chase Research PLC + +acpi:CHC*: + ID_VENDOR_FROM_DATABASE=Chic Technology Corp. + +acpi:CHD*: + ID_VENDOR_FROM_DATABASE=ChangHong Electric Co.,Ltd + +acpi:CHE*: + ID_VENDOR_FROM_DATABASE=Acer Inc + +acpi:CHG*: + ID_VENDOR_FROM_DATABASE=Sichuan Changhong Electric CO, LTD. + +acpi:CHI*: + ID_VENDOR_FROM_DATABASE=Chrontel Inc + +acpi:CHL*: + ID_VENDOR_FROM_DATABASE=Chloride-R&D + +acpi:CHM*: + ID_VENDOR_FROM_DATABASE=CHIC TECHNOLOGY CORP. + +acpi:CHO*: + ID_VENDOR_FROM_DATABASE=Sichuang Changhong Corporation + +acpi:CHP*: + ID_VENDOR_FROM_DATABASE=CH Products + +acpi:CHS*: + ID_VENDOR_FROM_DATABASE=Agentur Chairos + +acpi:CHT*: + ID_VENDOR_FROM_DATABASE=Chunghwa Picture Tubes,LTD. + +acpi:CHY*: + ID_VENDOR_FROM_DATABASE=Cherry GmbH + +acpi:CIC*: + ID_VENDOR_FROM_DATABASE=Comm. Intelligence Corporation + +acpi:CII*: + ID_VENDOR_FROM_DATABASE=Cromack Industries Inc + +acpi:CIL*: + ID_VENDOR_FROM_DATABASE=Citicom Infotech Private Limited + +acpi:CIN*: + ID_VENDOR_FROM_DATABASE=Citron GmbH + +acpi:CIP*: + ID_VENDOR_FROM_DATABASE=Ciprico Inc + +acpi:CIR*: + ID_VENDOR_FROM_DATABASE=Cirrus Logic Inc + +acpi:CIS*: + ID_VENDOR_FROM_DATABASE=Cisco Systems Inc + +acpi:CIT*: + ID_VENDOR_FROM_DATABASE=Citifax Limited + +acpi:CKC*: + ID_VENDOR_FROM_DATABASE=The Concept Keyboard Company Ltd + +acpi:CKJ*: + ID_VENDOR_FROM_DATABASE=Carina System Co., Ltd. + +acpi:CLA*: + ID_VENDOR_FROM_DATABASE=Clarion Company Ltd + +acpi:CLD*: + ID_VENDOR_FROM_DATABASE=COMMAT L.t.d. + +acpi:CLE*: + ID_VENDOR_FROM_DATABASE=Classe Audio + +acpi:CLG*: + ID_VENDOR_FROM_DATABASE=CoreLogic + +acpi:CLI*: + ID_VENDOR_FROM_DATABASE=Cirrus Logic Inc + +acpi:CLM*: + ID_VENDOR_FROM_DATABASE=CrystaLake Multimedia + +acpi:CLO*: + ID_VENDOR_FROM_DATABASE=Clone Computers + +acpi:CLT*: + ID_VENDOR_FROM_DATABASE=automated computer control systems + +acpi:CLV*: + ID_VENDOR_FROM_DATABASE=Clevo Company + +acpi:CLX*: + ID_VENDOR_FROM_DATABASE=CardLogix + +acpi:CMC*: + ID_VENDOR_FROM_DATABASE=CMC Ltd + +acpi:CMD*: + ID_VENDOR_FROM_DATABASE=Colorado MicroDisplay, Inc. + +acpi:CMG*: + ID_VENDOR_FROM_DATABASE=Chenming Mold Ind. Corp. + +acpi:CMI*: + ID_VENDOR_FROM_DATABASE=C-Media Electronics + +acpi:CMM*: + ID_VENDOR_FROM_DATABASE=Comtime GmbH + +acpi:CMN*: + ID_VENDOR_FROM_DATABASE=Chimei Innolux Corporation + +acpi:CMO*: + ID_VENDOR_FROM_DATABASE=Chi Mei Optoelectronics corp. + +acpi:CMR*: + ID_VENDOR_FROM_DATABASE=Cambridge Research Systems Ltd + +acpi:CMS*: + ID_VENDOR_FROM_DATABASE=CompuMaster Srl + +acpi:CMX*: + ID_VENDOR_FROM_DATABASE=Comex Electronics AB + +acpi:CNB*: + ID_VENDOR_FROM_DATABASE=American Power Conversion + +acpi:CNC*: + ID_VENDOR_FROM_DATABASE=Alvedon Computers Ltd + +acpi:CNE*: + ID_VENDOR_FROM_DATABASE=Cine-tal + +acpi:CNI*: + ID_VENDOR_FROM_DATABASE=Connect Int'l A/S + +acpi:CNN*: + ID_VENDOR_FROM_DATABASE=Canon Inc + +acpi:CNT*: + ID_VENDOR_FROM_DATABASE=COINT Multimedia Systems + +acpi:COB*: + ID_VENDOR_FROM_DATABASE=COBY Electronics Co., Ltd + +acpi:COD*: + ID_VENDOR_FROM_DATABASE=CODAN Pty. Ltd. + +acpi:COI*: + ID_VENDOR_FROM_DATABASE=Codec Inc. + +acpi:COL*: + ID_VENDOR_FROM_DATABASE=Rockwell Collins, Inc. + +acpi:COM*: + ID_VENDOR_FROM_DATABASE=Comtrol Corporation + +acpi:CON*: + ID_VENDOR_FROM_DATABASE=Contec Company Ltd + +acpi:COO*: + ID_VENDOR_FROM_DATABASE=coolux GmbH + +acpi:COR*: + ID_VENDOR_FROM_DATABASE=Corollary Inc + +acpi:COS*: + ID_VENDOR_FROM_DATABASE=CoStar Corporation + +acpi:COT*: + ID_VENDOR_FROM_DATABASE=Core Technology Inc + +acpi:COW*: + ID_VENDOR_FROM_DATABASE=Polycow Productions + +acpi:COX*: + ID_VENDOR_FROM_DATABASE=Comrex + +acpi:CPC*: + ID_VENDOR_FROM_DATABASE=Ciprico Inc + +acpi:CPD*: + ID_VENDOR_FROM_DATABASE=CompuAdd + +acpi:CPI*: + ID_VENDOR_FROM_DATABASE=Computer Peripherals Inc + +acpi:CPL*: + ID_VENDOR_FROM_DATABASE=Compal Electronics Inc + +acpi:CPM*: + ID_VENDOR_FROM_DATABASE=Capella Microsystems Inc. + +acpi:CPQ*: + ID_VENDOR_FROM_DATABASE=Compaq Computer Company + +acpi:CPT*: + ID_VENDOR_FROM_DATABASE=cPATH + +acpi:CPX*: + ID_VENDOR_FROM_DATABASE=Powermatic Data Systems + +acpi:CRC*: + ID_VENDOR_FROM_DATABASE=CONRAC GmbH + +acpi:CRD*: + ID_VENDOR_FROM_DATABASE=Cardinal Technical Inc + +acpi:CRE*: + ID_VENDOR_FROM_DATABASE=Creative Labs Inc + +acpi:CRI*: + ID_VENDOR_FROM_DATABASE=Crio Inc. + +acpi:CRL*: + ID_VENDOR_FROM_DATABASE=Creative Logic   + +acpi:CRN*: + ID_VENDOR_FROM_DATABASE=Cornerstone Imaging + +acpi:CRO*: + ID_VENDOR_FROM_DATABASE=Extraordinary Technologies PTY Limited + +acpi:CRQ*: + ID_VENDOR_FROM_DATABASE=Cirque Corporation + +acpi:CRS*: + ID_VENDOR_FROM_DATABASE=Crescendo Communication Inc + +acpi:CRV*: + ID_VENDOR_FROM_DATABASE=Cerevo Inc. + +acpi:CRX*: + ID_VENDOR_FROM_DATABASE=Cyrix Corporation + +acpi:CSB*: + ID_VENDOR_FROM_DATABASE=Transtex SA + +acpi:CSC*: + ID_VENDOR_FROM_DATABASE=Crystal Semiconductor + +acpi:CSD*: + ID_VENDOR_FROM_DATABASE=Cresta Systems Inc + +acpi:CSE*: + ID_VENDOR_FROM_DATABASE=Concept Solutions & Engineering + +acpi:CSI*: + ID_VENDOR_FROM_DATABASE=Cabletron System Inc + +acpi:CSM*: + ID_VENDOR_FROM_DATABASE=Cosmic Engineering Inc. + +acpi:CSO*: + ID_VENDOR_FROM_DATABASE=California Institute of Technology + +acpi:CSS*: + ID_VENDOR_FROM_DATABASE=CSS Laboratories + +acpi:CST*: + ID_VENDOR_FROM_DATABASE=CSTI Inc + +acpi:CTA*: + ID_VENDOR_FROM_DATABASE=CoSystems Inc + +acpi:CTC*: + ID_VENDOR_FROM_DATABASE=CTC Communication Development Company Ltd + +acpi:CTE*: + ID_VENDOR_FROM_DATABASE=Chunghwa Telecom Co., Ltd. + +acpi:CTL*: + ID_VENDOR_FROM_DATABASE=Creative Technology Ltd + +acpi:CTM*: + ID_VENDOR_FROM_DATABASE=Computerm Corporation + +acpi:CTN*: + ID_VENDOR_FROM_DATABASE=Computone Products + +acpi:CTP*: + ID_VENDOR_FROM_DATABASE=Computer Technology Corporation + +acpi:CTS*: + ID_VENDOR_FROM_DATABASE=Comtec Systems Co., Ltd. + +acpi:CTX*: + ID_VENDOR_FROM_DATABASE=Creatix Polymedia GmbH + +acpi:CUB*: + ID_VENDOR_FROM_DATABASE=Cubix Corporation + +acpi:CUK*: + ID_VENDOR_FROM_DATABASE=Calibre UK Ltd + +acpi:CVA*: + ID_VENDOR_FROM_DATABASE=Covia Inc. + +acpi:CVS*: + ID_VENDOR_FROM_DATABASE=Clarity Visual Systems + +acpi:CWR*: + ID_VENDOR_FROM_DATABASE=Connectware Inc + +acpi:CXT*: + ID_VENDOR_FROM_DATABASE=Conexant Systems + +acpi:CYB*: + ID_VENDOR_FROM_DATABASE=CyberVision + +acpi:CYC*: + ID_VENDOR_FROM_DATABASE=Cylink Corporation + +acpi:CYD*: + ID_VENDOR_FROM_DATABASE=Cyclades Corporation + +acpi:CYL*: + ID_VENDOR_FROM_DATABASE=Cyberlabs + +acpi:CYT*: + ID_VENDOR_FROM_DATABASE=Cytechinfo Inc + +acpi:CYV*: + ID_VENDOR_FROM_DATABASE=Cyviz AS + +acpi:CYW*: + ID_VENDOR_FROM_DATABASE=Cyberware + +acpi:CYX*: + ID_VENDOR_FROM_DATABASE=Cyrix Corporation + +acpi:CZE*: + ID_VENDOR_FROM_DATABASE=Carl Zeiss AG + +acpi:DAC*: + ID_VENDOR_FROM_DATABASE=Digital Acoustics Corporation + +acpi:DAE*: + ID_VENDOR_FROM_DATABASE=Digatron Industrie Elektronik GmbH + +acpi:DAI*: + ID_VENDOR_FROM_DATABASE=DAIS SET Ltd. + +acpi:DAK*: + ID_VENDOR_FROM_DATABASE=Daktronics + +acpi:DAL*: + ID_VENDOR_FROM_DATABASE=Digital Audio Labs Inc + +acpi:DAN*: + ID_VENDOR_FROM_DATABASE=Danelec Marine A/S + +acpi:DAS*: + ID_VENDOR_FROM_DATABASE=DAVIS AS + +acpi:DAT*: + ID_VENDOR_FROM_DATABASE=Datel Inc + +acpi:DAU*: + ID_VENDOR_FROM_DATABASE=Daou Tech Inc + +acpi:DAV*: + ID_VENDOR_FROM_DATABASE=Davicom Semiconductor Inc + +acpi:DAW*: + ID_VENDOR_FROM_DATABASE=DA2 Technologies Inc + +acpi:DAX*: + ID_VENDOR_FROM_DATABASE=Data Apex Ltd + +acpi:DBD*: + ID_VENDOR_FROM_DATABASE=Diebold Inc. + +acpi:DBI*: + ID_VENDOR_FROM_DATABASE=DigiBoard Inc + +acpi:DBK*: + ID_VENDOR_FROM_DATABASE=Databook Inc + +acpi:DBL*: + ID_VENDOR_FROM_DATABASE=Doble Engineering Company + +acpi:DBN*: + ID_VENDOR_FROM_DATABASE=DB Networks Inc + +acpi:DCA*: + ID_VENDOR_FROM_DATABASE=Digital Communications Association + +acpi:DCC*: + ID_VENDOR_FROM_DATABASE=Dale Computer Corporation + +acpi:DCD*: + ID_VENDOR_FROM_DATABASE=Datacast LLC + +acpi:DCE*: + ID_VENDOR_FROM_DATABASE=dSPACE GmbH + +acpi:DCI*: + ID_VENDOR_FROM_DATABASE=Concepts Inc + +acpi:DCL*: + ID_VENDOR_FROM_DATABASE=Dynamic Controls Ltd + +acpi:DCM*: + ID_VENDOR_FROM_DATABASE=DCM Data Products + +acpi:DCO*: + ID_VENDOR_FROM_DATABASE=Dialogue Technology Corporation + +acpi:DCR*: + ID_VENDOR_FROM_DATABASE=Decros Ltd + +acpi:DCS*: + ID_VENDOR_FROM_DATABASE=Diamond Computer Systems Inc + +acpi:DCT*: + ID_VENDOR_FROM_DATABASE=Dancall Telecom A/S + +acpi:DCV*: + ID_VENDOR_FROM_DATABASE=Datatronics Technology Inc + +acpi:DDA*: + ID_VENDOR_FROM_DATABASE=DA2 Technologies Corporation + +acpi:DDD*: + ID_VENDOR_FROM_DATABASE=Danka Data Devices + +acpi:DDE*: + ID_VENDOR_FROM_DATABASE=Datasat Digital Entertainment + +acpi:DDI*: + ID_VENDOR_FROM_DATABASE=Data Display AG + +acpi:DDS*: + ID_VENDOR_FROM_DATABASE=Barco, n.v. + +acpi:DDT*: + ID_VENDOR_FROM_DATABASE=Datadesk Technologies Inc + +acpi:DDV*: + ID_VENDOR_FROM_DATABASE=Delta Information Systems, Inc + +acpi:DEC*: + ID_VENDOR_FROM_DATABASE=Digital Equipment Corporation + +acpi:DEI*: + ID_VENDOR_FROM_DATABASE=Deico Electronics + +acpi:DEL*: + ID_VENDOR_FROM_DATABASE=Dell Inc. + +acpi:DEN*: + ID_VENDOR_FROM_DATABASE=Densitron Computers Ltd + +acpi:DEX*: + ID_VENDOR_FROM_DATABASE=idex displays + +acpi:DFI*: + ID_VENDOR_FROM_DATABASE=DFI + +acpi:DFK*: + ID_VENDOR_FROM_DATABASE=SharkTec A/S + +acpi:DFT*: + ID_VENDOR_FROM_DATABASE=DEI Holdings dba Definitive Technology + +acpi:DGA*: + ID_VENDOR_FROM_DATABASE=Digiital Arts Inc + +acpi:DGC*: + ID_VENDOR_FROM_DATABASE=Data General Corporation + +acpi:DGI*: + ID_VENDOR_FROM_DATABASE=DIGI International + +acpi:DGK*: + ID_VENDOR_FROM_DATABASE=DugoTech Co., LTD + +acpi:DGP*: + ID_VENDOR_FROM_DATABASE=Digicorp European sales S.A. + +acpi:DGS*: + ID_VENDOR_FROM_DATABASE=Diagsoft Inc + +acpi:DGT*: + ID_VENDOR_FROM_DATABASE=The Dearborn Group + +acpi:DHP*: + ID_VENDOR_FROM_DATABASE=DH Print + +acpi:DHQ*: + ID_VENDOR_FROM_DATABASE=Quadram + +acpi:DHT*: + ID_VENDOR_FROM_DATABASE=Projectavision Inc + +acpi:DIA*: + ID_VENDOR_FROM_DATABASE=Diadem + +acpi:DIG*: + ID_VENDOR_FROM_DATABASE=Digicom S.p.A. + +acpi:DII*: + ID_VENDOR_FROM_DATABASE=Dataq Instruments Inc + +acpi:DIM*: + ID_VENDOR_FROM_DATABASE=dPict Imaging, Inc. + +acpi:DIN*: + ID_VENDOR_FROM_DATABASE=Daintelecom Co., Ltd + +acpi:DIS*: + ID_VENDOR_FROM_DATABASE=Diseda S.A. + +acpi:DIT*: + ID_VENDOR_FROM_DATABASE=Dragon Information Technology + +acpi:DJE*: + ID_VENDOR_FROM_DATABASE=Capstone Visual Product Development + +acpi:DJP*: + ID_VENDOR_FROM_DATABASE=Maygay Machines, Ltd + +acpi:DKY*: + ID_VENDOR_FROM_DATABASE=Datakey Inc + +acpi:DLB*: + ID_VENDOR_FROM_DATABASE=Dolby Laboratories Inc. + +acpi:DLC*: + ID_VENDOR_FROM_DATABASE=Diamond Lane Comm. Corporation + +acpi:DLG*: + ID_VENDOR_FROM_DATABASE=Digital-Logic GmbH + +acpi:DLK*: + ID_VENDOR_FROM_DATABASE=D-Link Systems Inc + +acpi:DLL*: + ID_VENDOR_FROM_DATABASE=Dell Inc + +acpi:DLT*: + ID_VENDOR_FROM_DATABASE=Digitelec Informatique Park Cadera + +acpi:DMB*: + ID_VENDOR_FROM_DATABASE=Digicom Systems Inc + +acpi:DMC*: + ID_VENDOR_FROM_DATABASE=Dune Microsystems Corporation + +acpi:DMM*: + ID_VENDOR_FROM_DATABASE=Dimond Multimedia Systems Inc + +acpi:DMP*: + ID_VENDOR_FROM_DATABASE=D&M Holdings Inc, Professional Business Company + +acpi:DMS*: + ID_VENDOR_FROM_DATABASE=DOME imaging systems + +acpi:DMT*: + ID_VENDOR_FROM_DATABASE=Distributed Management Task Force, Inc. (DMTF) + +acpi:DMV*: + ID_VENDOR_FROM_DATABASE=NDS Ltd + +acpi:DNA*: + ID_VENDOR_FROM_DATABASE=DNA Enterprises, Inc. + +acpi:DNG*: + ID_VENDOR_FROM_DATABASE=Apache Micro Peripherals Inc + +acpi:DNI*: + ID_VENDOR_FROM_DATABASE=Deterministic Networks Inc. + +acpi:DNT*: + ID_VENDOR_FROM_DATABASE=Dr. Neuhous Telekommunikation GmbH + +acpi:DNV*: + ID_VENDOR_FROM_DATABASE=DiCon + +acpi:DOL*: + ID_VENDOR_FROM_DATABASE=Dolman Technologies Group Inc + +acpi:DOM*: + ID_VENDOR_FROM_DATABASE=Dome Imaging Systems + +acpi:DON*: + ID_VENDOR_FROM_DATABASE=DENON, Ltd. + +acpi:DOT*: + ID_VENDOR_FROM_DATABASE=Dotronic Mikroelektronik GmbH + +acpi:DPA*: + ID_VENDOR_FROM_DATABASE=DigiTalk Pro AV + +acpi:DPC*: + ID_VENDOR_FROM_DATABASE=Delta Electronics Inc + +acpi:DPI*: + ID_VENDOR_FROM_DATABASE=DocuPoint + +acpi:DPL*: + ID_VENDOR_FROM_DATABASE=Digital Projection Limited + +acpi:DPM*: + ID_VENDOR_FROM_DATABASE=ADPM Synthesis sas + +acpi:DPS*: + ID_VENDOR_FROM_DATABASE=Digital Processing Systems + +acpi:DPT*: + ID_VENDOR_FROM_DATABASE=DPT + +acpi:DPX*: + ID_VENDOR_FROM_DATABASE=DpiX, Inc. + +acpi:DQB*: + ID_VENDOR_FROM_DATABASE=Datacube Inc + +acpi:DRB*: + ID_VENDOR_FROM_DATABASE=Dr. Bott KG + +acpi:DRC*: + ID_VENDOR_FROM_DATABASE=Data Ray Corp. + +acpi:DRD*: + ID_VENDOR_FROM_DATABASE=DIGITAL REFLECTION INC. + +acpi:DRI*: + ID_VENDOR_FROM_DATABASE=Data Race Inc + +acpi:DRS*: + ID_VENDOR_FROM_DATABASE=DRS Defense Solutions, LLC + +acpi:DSD*: + ID_VENDOR_FROM_DATABASE=DS Multimedia Pte Ltd + +acpi:DSI*: + ID_VENDOR_FROM_DATABASE=Digitan Systems Inc + +acpi:DSM*: + ID_VENDOR_FROM_DATABASE=DSM Digital Services GmbH + +acpi:DSP*: + ID_VENDOR_FROM_DATABASE=Domain Technology Inc + +acpi:DTA*: + ID_VENDOR_FROM_DATABASE=DELTATEC + +acpi:DTC*: + ID_VENDOR_FROM_DATABASE=DTC Tech Corporation + +acpi:DTE*: + ID_VENDOR_FROM_DATABASE=Dimension Technologies, Inc. + +acpi:DTI*: + ID_VENDOR_FROM_DATABASE=Diversified Technology, Inc. + +acpi:DTK*: + ID_VENDOR_FROM_DATABASE=Dynax Electronics (HK) Ltd + +acpi:DTL*: + ID_VENDOR_FROM_DATABASE=e-Net Inc + +acpi:DTN*: + ID_VENDOR_FROM_DATABASE=Datang Telephone Co + +acpi:DTO*: + ID_VENDOR_FROM_DATABASE=Deutsche Thomson OHG + +acpi:DTT*: + ID_VENDOR_FROM_DATABASE=Design & Test Technology, Inc. + +acpi:DTX*: + ID_VENDOR_FROM_DATABASE=Data Translation + +acpi:DUA*: + ID_VENDOR_FROM_DATABASE=Dosch & Amand GmbH & Company KG + +acpi:DUN*: + ID_VENDOR_FROM_DATABASE=NCR Corporation + +acpi:DVD*: + ID_VENDOR_FROM_DATABASE=Dictaphone Corporation + +acpi:DVL*: + ID_VENDOR_FROM_DATABASE=Devolo AG + +acpi:DVS*: + ID_VENDOR_FROM_DATABASE=Digital Video System + +acpi:DVT*: + ID_VENDOR_FROM_DATABASE=Data Video + +acpi:DWE*: + ID_VENDOR_FROM_DATABASE=Daewoo Electronics Company Ltd + +acpi:DXC*: + ID_VENDOR_FROM_DATABASE=Digipronix Control Systems + +acpi:DXD*: + ID_VENDOR_FROM_DATABASE=DECIMATOR DESIGN PTY LTD + +acpi:DXL*: + ID_VENDOR_FROM_DATABASE=Dextera Labs Inc + +acpi:DXP*: + ID_VENDOR_FROM_DATABASE=Data Expert Corporation + +acpi:DXS*: + ID_VENDOR_FROM_DATABASE=Signet + +acpi:DYC*: + ID_VENDOR_FROM_DATABASE=Dycam Inc + +acpi:DYM*: + ID_VENDOR_FROM_DATABASE=Dymo-CoStar Corporation + +acpi:DYN*: + ID_VENDOR_FROM_DATABASE=Askey Computer Corporation + +acpi:DYX*: + ID_VENDOR_FROM_DATABASE=Dynax Electronics (HK) Ltd + +acpi:EAS*: + ID_VENDOR_FROM_DATABASE=Evans and Sutherland Computer + +acpi:EBH*: + ID_VENDOR_FROM_DATABASE=Data Price Informatica + +acpi:EBT*: + ID_VENDOR_FROM_DATABASE=HUALONG TECHNOLOGY CO., LTD + +acpi:ECA*: + ID_VENDOR_FROM_DATABASE=Electro Cam Corp. + +acpi:ECC*: + ID_VENDOR_FROM_DATABASE=ESSential Comm. Corporation + +acpi:ECI*: + ID_VENDOR_FROM_DATABASE=Enciris Technologies + +acpi:ECK*: + ID_VENDOR_FROM_DATABASE=Eugene Chukhlomin Sole Proprietorship, d.b.a. + +acpi:ECL*: + ID_VENDOR_FROM_DATABASE=Excel Company Ltd + +acpi:ECM*: + ID_VENDOR_FROM_DATABASE=E-Cmos Tech Corporation + +acpi:ECO*: + ID_VENDOR_FROM_DATABASE=Echo Speech Corporation + +acpi:ECP*: + ID_VENDOR_FROM_DATABASE=Elecom Company Ltd + +acpi:ECS*: + ID_VENDOR_FROM_DATABASE=Elitegroup Computer Systems Company Ltd + +acpi:ECT*: + ID_VENDOR_FROM_DATABASE=Enciris Technologies + +acpi:EDC*: + ID_VENDOR_FROM_DATABASE=e.Digital Corporation + +acpi:EDG*: + ID_VENDOR_FROM_DATABASE=Electronic-Design GmbH + +acpi:EDI*: + ID_VENDOR_FROM_DATABASE=Edimax Tech. Company Ltd + +acpi:EDM*: + ID_VENDOR_FROM_DATABASE=EDMI + +acpi:EDT*: + ID_VENDOR_FROM_DATABASE=Emerging Display Technologies Corp + +acpi:EEE*: + ID_VENDOR_FROM_DATABASE=ET&T Technology Company Ltd + +acpi:EEH*: + ID_VENDOR_FROM_DATABASE=EEH Datalink GmbH + +acpi:EEP*: + ID_VENDOR_FROM_DATABASE=E.E.P.D. GmbH + +acpi:EES*: + ID_VENDOR_FROM_DATABASE=EE Solutions, Inc. + +acpi:EGA*: + ID_VENDOR_FROM_DATABASE=Elgato Systems LLC + +acpi:EGD*: + ID_VENDOR_FROM_DATABASE=EIZO GmbH Display Technologies + +acpi:EGL*: + ID_VENDOR_FROM_DATABASE=Eagle Technology + +acpi:EGN*: + ID_VENDOR_FROM_DATABASE=Egenera, Inc. + +acpi:EGO*: + ID_VENDOR_FROM_DATABASE=Ergo Electronics + +acpi:EHJ*: + ID_VENDOR_FROM_DATABASE=Epson Research + +acpi:EHN*: + ID_VENDOR_FROM_DATABASE=Enhansoft + +acpi:EIC*: + ID_VENDOR_FROM_DATABASE=Eicon Technology Corporation + +acpi:EKA*: + ID_VENDOR_FROM_DATABASE=MagTek Inc. + +acpi:EKC*: + ID_VENDOR_FROM_DATABASE=Eastman Kodak Company + +acpi:EKS*: + ID_VENDOR_FROM_DATABASE=EKSEN YAZILIM + +acpi:ELA*: + ID_VENDOR_FROM_DATABASE=ELAD srl + +acpi:ELC*: + ID_VENDOR_FROM_DATABASE=Electro Scientific Ind + +acpi:ELE*: + ID_VENDOR_FROM_DATABASE=Elecom Company Ltd + +acpi:ELG*: + ID_VENDOR_FROM_DATABASE=Elmeg GmbH Kommunikationstechnik + +acpi:ELI*: + ID_VENDOR_FROM_DATABASE=Edsun Laboratories + +acpi:ELL*: + ID_VENDOR_FROM_DATABASE=Electrosonic Ltd + +acpi:ELM*: + ID_VENDOR_FROM_DATABASE=Elmic Systems Inc + +acpi:ELO*: + ID_VENDOR_FROM_DATABASE=Elo TouchSystems Inc + +acpi:ELS*: + ID_VENDOR_FROM_DATABASE=ELSA GmbH + +acpi:ELT*: + ID_VENDOR_FROM_DATABASE=Element Labs, Inc. + +acpi:ELX*: + ID_VENDOR_FROM_DATABASE=Elonex PLC + +acpi:EMB*: + ID_VENDOR_FROM_DATABASE=Embedded computing inc ltd + +acpi:EMC*: + ID_VENDOR_FROM_DATABASE=eMicro Corporation + +acpi:EME*: + ID_VENDOR_FROM_DATABASE=EMiNE TECHNOLOGY COMPANY, LTD. + +acpi:EMG*: + ID_VENDOR_FROM_DATABASE=EMG Consultants Inc + +acpi:EMI*: + ID_VENDOR_FROM_DATABASE=Ex Machina Inc + +acpi:EMK*: + ID_VENDOR_FROM_DATABASE=Emcore Corporation + +acpi:EMO*: + ID_VENDOR_FROM_DATABASE=ELMO COMPANY, LIMITED + +acpi:EMU*: + ID_VENDOR_FROM_DATABASE=Emulex Corporation + +acpi:ENC*: + ID_VENDOR_FROM_DATABASE=Eizo Nanao Corporation + +acpi:END*: + ID_VENDOR_FROM_DATABASE=ENIDAN Technologies Ltd + +acpi:ENE*: + ID_VENDOR_FROM_DATABASE=ENE Technology Inc. + +acpi:ENI*: + ID_VENDOR_FROM_DATABASE=Efficient Networks + +acpi:ENS*: + ID_VENDOR_FROM_DATABASE=Ensoniq Corporation + +acpi:ENT*: + ID_VENDOR_FROM_DATABASE=Enterprise Comm. & Computing Inc + +acpi:EPC*: + ID_VENDOR_FROM_DATABASE=Empac + +acpi:EPH *: + ID_VENDOR_FROM_DATABASE=Epiphan Systems Inc.  + +acpi:EPI*: + ID_VENDOR_FROM_DATABASE=Envision Peripherals, Inc + +acpi:EPN*: + ID_VENDOR_FROM_DATABASE=EPiCON Inc. + +acpi:EPS*: + ID_VENDOR_FROM_DATABASE=KEPS + +acpi:EQP*: + ID_VENDOR_FROM_DATABASE=Equipe Electronics Ltd. + +acpi:EQX*: + ID_VENDOR_FROM_DATABASE=Equinox Systems Inc + +acpi:ERG*: + ID_VENDOR_FROM_DATABASE=Ergo System + +acpi:ERI*: + ID_VENDOR_FROM_DATABASE=Ericsson Mobile Communications AB + +acpi:ERN*: + ID_VENDOR_FROM_DATABASE=Ericsson, Inc. + +acpi:ERP*: + ID_VENDOR_FROM_DATABASE=Euraplan GmbH + +acpi:ERT*: + ID_VENDOR_FROM_DATABASE=Escort Insturments Corporation + +acpi:ESA*: + ID_VENDOR_FROM_DATABASE=Elbit Systems of America + +acpi:ESC*: + ID_VENDOR_FROM_DATABASE=Eden Sistemas de Computacao S/A + +acpi:ESD*: + ID_VENDOR_FROM_DATABASE=Ensemble Designs, Inc + +acpi:ESG*: + ID_VENDOR_FROM_DATABASE=ELCON Systemtechnik GmbH + +acpi:ESI*: + ID_VENDOR_FROM_DATABASE=Extended Systems, Inc. + +acpi:ESK*: + ID_VENDOR_FROM_DATABASE=ES&S + +acpi:ESL*: + ID_VENDOR_FROM_DATABASE=Esterline Technologies + +acpi:ESN*: + ID_VENDOR_FROM_DATABASE=eSATURNUS + +acpi:ESS*: + ID_VENDOR_FROM_DATABASE=ESS Technology Inc + +acpi:EST*: + ID_VENDOR_FROM_DATABASE=Embedded Solution Technology + +acpi:ESY*: + ID_VENDOR_FROM_DATABASE=E-Systems Inc + +acpi:ETC*: + ID_VENDOR_FROM_DATABASE=Everton Technology Company Ltd + +acpi:ETD*: + ID_VENDOR_FROM_DATABASE=ELAN MICROELECTRONICS CORPORATION + +acpi:ETH*: + ID_VENDOR_FROM_DATABASE=Etherboot Project + +acpi:ETI*: + ID_VENDOR_FROM_DATABASE=Eclipse Tech Inc + +acpi:ETK*: + ID_VENDOR_FROM_DATABASE=eTEK Labs Inc. + +acpi:ETL*: + ID_VENDOR_FROM_DATABASE=Evertz Microsystems Ltd. + +acpi:ETS*: + ID_VENDOR_FROM_DATABASE=Electronic Trade Solutions Ltd + +acpi:ETT*: + ID_VENDOR_FROM_DATABASE=E-Tech Inc + +acpi:EUT*: + ID_VENDOR_FROM_DATABASE=Ericsson Mobile Networks B.V. + +acpi:EVE*: + ID_VENDOR_FROM_DATABASE=Advanced Micro Peripherals Ltd + +acpi:EVI*: + ID_VENDOR_FROM_DATABASE=eviateg GmbH + +acpi:EVX*: + ID_VENDOR_FROM_DATABASE=Everex + +acpi:EXA*: + ID_VENDOR_FROM_DATABASE=Exabyte + +acpi:EXC*: + ID_VENDOR_FROM_DATABASE=Excession Audio + +acpi:EXI*: + ID_VENDOR_FROM_DATABASE=Exide Electronics + +acpi:EXN*: + ID_VENDOR_FROM_DATABASE=RGB Systems, Inc. dba Extron Electronics + +acpi:EXP*: + ID_VENDOR_FROM_DATABASE=Data Export Corporation + +acpi:EXT*: + ID_VENDOR_FROM_DATABASE=Exatech Computadores & Servicos Ltda + +acpi:EXX*: + ID_VENDOR_FROM_DATABASE=Exxact GmbH + +acpi:EXY*: + ID_VENDOR_FROM_DATABASE=Exterity Ltd + +acpi:EYE*: + ID_VENDOR_FROM_DATABASE=eyevis GmbH + +acpi:EZE*: + ID_VENDOR_FROM_DATABASE=EzE Technologies + +acpi:EZP*: + ID_VENDOR_FROM_DATABASE=Storm Technology + +acpi:FAR*: + ID_VENDOR_FROM_DATABASE=Farallon Computing + +acpi:FBI*: + ID_VENDOR_FROM_DATABASE=Interface Corporation + +acpi:FCB*: + ID_VENDOR_FROM_DATABASE=Furukawa Electric Company Ltd + +acpi:FCG*: + ID_VENDOR_FROM_DATABASE=First International Computer Ltd + +acpi:FCS*: + ID_VENDOR_FROM_DATABASE=Focus Enhancements, Inc. + +acpi:FDC*: + ID_VENDOR_FROM_DATABASE=Future Domain + +acpi:FDT*: + ID_VENDOR_FROM_DATABASE=Fujitsu Display Technologies Corp. + +acpi:FEC*: + ID_VENDOR_FROM_DATABASE=FURUNO ELECTRIC CO., LTD. + +acpi:FEL*: + ID_VENDOR_FROM_DATABASE=Fellowes & Questec + +acpi:FEN*: + ID_VENDOR_FROM_DATABASE=Fen Systems Ltd. + +acpi:FER*: + ID_VENDOR_FROM_DATABASE=Ferranti Int'L + +acpi:FFC*: + ID_VENDOR_FROM_DATABASE=FUJIFILM Corporation + +acpi:FFI*: + ID_VENDOR_FROM_DATABASE=Fairfield Industries + +acpi:FGD*: + ID_VENDOR_FROM_DATABASE=Lisa Draexlmaier GmbH + +acpi:FGL*: + ID_VENDOR_FROM_DATABASE=Fujitsu General Limited. + +acpi:FHL*: + ID_VENDOR_FROM_DATABASE=FHLP + +acpi:FIC*: + ID_VENDOR_FROM_DATABASE=Formosa Industrial Computing Inc + +acpi:FIL*: + ID_VENDOR_FROM_DATABASE=Forefront Int'l Ltd + +acpi:FIN*: + ID_VENDOR_FROM_DATABASE=Finecom Co., Ltd. + +acpi:FIR*: + ID_VENDOR_FROM_DATABASE=Chaplet Systems Inc + +acpi:FIS*: + ID_VENDOR_FROM_DATABASE=FLY-IT Simulators + +acpi:FIT*: + ID_VENDOR_FROM_DATABASE=Feature Integration Technology Inc. + +acpi:FJC*: + ID_VENDOR_FROM_DATABASE=Fujitsu Takamisawa Component Limited + +acpi:FJS*: + ID_VENDOR_FROM_DATABASE=Fujitsu Spain + +acpi:FJT*: + ID_VENDOR_FROM_DATABASE=F.J. Tieman BV + +acpi:FLE*: + ID_VENDOR_FROM_DATABASE=ADTI Media, Inc + +acpi:FLI*: + ID_VENDOR_FROM_DATABASE=Faroudja Laboratories + +acpi:FLY*: + ID_VENDOR_FROM_DATABASE=Butterfly Communications + +acpi:FMA*: + ID_VENDOR_FROM_DATABASE=Fast Multimedia AG + +acpi:FMC*: + ID_VENDOR_FROM_DATABASE=Ford Microelectronics Inc + +acpi:FMI*: + ID_VENDOR_FROM_DATABASE=Fujitsu Microelect Inc + +acpi:FML*: + ID_VENDOR_FROM_DATABASE=Fujitsu Microelect Ltd + +acpi:FMZ*: + ID_VENDOR_FROM_DATABASE=Formoza-Altair + +acpi:FNC*: + ID_VENDOR_FROM_DATABASE=Fanuc LTD + +acpi:FNI*: + ID_VENDOR_FROM_DATABASE=Funai Electric Co., Ltd. + +acpi:FOA*: + ID_VENDOR_FROM_DATABASE=FOR-A Company Limited + +acpi:FOS*: + ID_VENDOR_FROM_DATABASE=Foss Tecator + +acpi:FOX*: + ID_VENDOR_FROM_DATABASE=HON HAI PRECISON IND.CO.,LTD. + +acpi:FPE*: + ID_VENDOR_FROM_DATABASE=Fujitsu Peripherals Ltd + +acpi:FPS*: + ID_VENDOR_FROM_DATABASE=Deltec Corporation + +acpi:FPX*: + ID_VENDOR_FROM_DATABASE=Cirel Systemes + +acpi:FRC*: + ID_VENDOR_FROM_DATABASE=Force Computers + +acpi:FRD*: + ID_VENDOR_FROM_DATABASE=Freedom Scientific BLV + +acpi:FRE*: + ID_VENDOR_FROM_DATABASE=Forvus Research Inc + +acpi:FRI*: + ID_VENDOR_FROM_DATABASE=Fibernet Research Inc + +acpi:FRS*: + ID_VENDOR_FROM_DATABASE=South Mountain Technologies, LTD + +acpi:FSC*: + ID_VENDOR_FROM_DATABASE=Future Systems Consulting KK + +acpi:FSI*: + ID_VENDOR_FROM_DATABASE=Fore Systems Inc + +acpi:FST*: + ID_VENDOR_FROM_DATABASE=Modesto PC Inc + +acpi:FTC*: + ID_VENDOR_FROM_DATABASE=Futuretouch Corporation + +acpi:FTE*: + ID_VENDOR_FROM_DATABASE=Frontline Test Equipment Inc. + +acpi:FTG*: + ID_VENDOR_FROM_DATABASE=FTG Data Systems + +acpi:FTI*: + ID_VENDOR_FROM_DATABASE=FastPoint Technologies, Inc. + +acpi:FTL*: + ID_VENDOR_FROM_DATABASE=FUJITSU TEN LIMITED + +acpi:FTN*: + ID_VENDOR_FROM_DATABASE=Fountain Technologies Inc + +acpi:FTR*: + ID_VENDOR_FROM_DATABASE=Mediasonic + +acpi:FTW*: + ID_VENDOR_FROM_DATABASE=MindTribe Product Engineering, Inc. + +acpi:FUJ*: + ID_VENDOR_FROM_DATABASE=Fujitsu Ltd + +acpi:FUN*: + ID_VENDOR_FROM_DATABASE=sisel muhendislik + +acpi:FUS*: + ID_VENDOR_FROM_DATABASE=Fujitsu Siemens Computers GmbH + +acpi:FVC*: + ID_VENDOR_FROM_DATABASE=First Virtual Corporation + +acpi:FVX*: + ID_VENDOR_FROM_DATABASE=C-C-C Group Plc + +acpi:FWA*: + ID_VENDOR_FROM_DATABASE=Attero Tech, LLC + +acpi:FWR*: + ID_VENDOR_FROM_DATABASE=Flat Connections Inc + +acpi:FXX*: + ID_VENDOR_FROM_DATABASE=Fuji Xerox + +acpi:FZC*: + ID_VENDOR_FROM_DATABASE=Founder Group Shenzhen Co. + +acpi:FZI*: + ID_VENDOR_FROM_DATABASE=FZI Forschungszentrum Informatik + +acpi:GAG*: + ID_VENDOR_FROM_DATABASE=Gage Applied Sciences Inc + +acpi:GAL*: + ID_VENDOR_FROM_DATABASE=Galil Motion Control + +acpi:GAU*: + ID_VENDOR_FROM_DATABASE=Gaudi Co., Ltd. + +acpi:GCC*: + ID_VENDOR_FROM_DATABASE=GCC Technologies Inc + +acpi:GCI*: + ID_VENDOR_FROM_DATABASE=Gateway Comm. Inc + +acpi:GCS*: + ID_VENDOR_FROM_DATABASE=Grey Cell Systems Ltd + +acpi:GDC*: + ID_VENDOR_FROM_DATABASE=General Datacom + +acpi:GDI*: + ID_VENDOR_FROM_DATABASE=G. Diehl ISDN GmbH + +acpi:GDS*: + ID_VENDOR_FROM_DATABASE=GDS + +acpi:GDT*: + ID_VENDOR_FROM_DATABASE=Vortex Computersysteme GmbH + +acpi:GEF*: + ID_VENDOR_FROM_DATABASE=GE Fanuc Embedded Systems + +acpi:GEH*: + ID_VENDOR_FROM_DATABASE=GE Intelligent Platforms - Huntsville + +acpi:GEM*: + ID_VENDOR_FROM_DATABASE=Gem Plus + +acpi:GEN*: + ID_VENDOR_FROM_DATABASE=Genesys ATE Inc + +acpi:GEO*: + ID_VENDOR_FROM_DATABASE=GEO Sense + +acpi:GER*: + ID_VENDOR_FROM_DATABASE=GERMANEERS GmbH + +acpi:GES*: + ID_VENDOR_FROM_DATABASE=GES Singapore Pte Ltd + +acpi:GET*: + ID_VENDOR_FROM_DATABASE=Getac Technology Corporation + +acpi:GFM*: + ID_VENDOR_FROM_DATABASE=GFMesstechnik GmbH + +acpi:GFN*: + ID_VENDOR_FROM_DATABASE=Gefen Inc. + +acpi:GGL*: + ID_VENDOR_FROM_DATABASE=Google Inc. + +acpi:GIC*: + ID_VENDOR_FROM_DATABASE=General Inst. Corporation + +acpi:GIM*: + ID_VENDOR_FROM_DATABASE=Guillemont International + +acpi:GIP*: + ID_VENDOR_FROM_DATABASE=GI Provision Ltd + +acpi:GIS*: + ID_VENDOR_FROM_DATABASE=AT&T Global Info Solutions + +acpi:GJN*: + ID_VENDOR_FROM_DATABASE=Grand Junction Networks + +acpi:GLD*: + ID_VENDOR_FROM_DATABASE=Goldmund - Digital Audio SA + +acpi:GLE*: + ID_VENDOR_FROM_DATABASE=AD electronics + +acpi:GLM*: + ID_VENDOR_FROM_DATABASE=Genesys Logic + +acpi:GLS*: + ID_VENDOR_FROM_DATABASE=Gadget Labs LLC + +acpi:GMK*: + ID_VENDOR_FROM_DATABASE=GMK Electronic Design GmbH + +acpi:GML*: + ID_VENDOR_FROM_DATABASE=General Information Systems + +acpi:GMM*: + ID_VENDOR_FROM_DATABASE=GMM Research Inc + +acpi:GMN*: + ID_VENDOR_FROM_DATABASE=GEMINI 2000 Ltd + +acpi:GMX*: + ID_VENDOR_FROM_DATABASE=GMX Inc + +acpi:GND*: + ID_VENDOR_FROM_DATABASE=Gennum Corporation + +acpi:GNN*: + ID_VENDOR_FROM_DATABASE=GN Nettest Inc + +acpi:GNZ*: + ID_VENDOR_FROM_DATABASE=Gunze Ltd + +acpi:GRA*: + ID_VENDOR_FROM_DATABASE=Graphica Computer + +acpi:GRE*: + ID_VENDOR_FROM_DATABASE=GOLD RAIN ENTERPRISES CORP. + +acpi:GRH*: + ID_VENDOR_FROM_DATABASE=Granch Ltd + +acpi:GRM*: + ID_VENDOR_FROM_DATABASE=Garmin International + +acpi:GRV*: + ID_VENDOR_FROM_DATABASE=Advanced Gravis + +acpi:GRY*: + ID_VENDOR_FROM_DATABASE=Robert Gray Company + +acpi:GSB*: + ID_VENDOR_FROM_DATABASE=NIPPONDENCHI CO,.LTD + +acpi:GSC*: + ID_VENDOR_FROM_DATABASE=General Standards Corporation + +acpi:GSM*: + ID_VENDOR_FROM_DATABASE=Goldstar Company Ltd + +acpi:GST*: + ID_VENDOR_FROM_DATABASE=Graphic SystemTechnology + +acpi:GSY*: + ID_VENDOR_FROM_DATABASE=Grossenbacher Systeme AG + +acpi:GTC*: + ID_VENDOR_FROM_DATABASE=Graphtec Corporation + +acpi:GTI*: + ID_VENDOR_FROM_DATABASE=Goldtouch + +acpi:GTK*: + ID_VENDOR_FROM_DATABASE=G-Tech Corporation + +acpi:GTM*: + ID_VENDOR_FROM_DATABASE=Garnet System Company Ltd + +acpi:GTS*: + ID_VENDOR_FROM_DATABASE=Geotest Marvin Test Systems Inc + +acpi:GTT*: + ID_VENDOR_FROM_DATABASE=General Touch Technology Co., Ltd. + +acpi:GUD*: + ID_VENDOR_FROM_DATABASE=Guntermann & Drunck GmbH + +acpi:GUZ*: + ID_VENDOR_FROM_DATABASE=Guzik Technical Enterprises + +acpi:GVC*: + ID_VENDOR_FROM_DATABASE=GVC Corporation + +acpi:GVL*: + ID_VENDOR_FROM_DATABASE=Global Village Communication + +acpi:GWI*: + ID_VENDOR_FROM_DATABASE=GW Instruments + +acpi:GWY*: + ID_VENDOR_FROM_DATABASE=Gateway 2000 + +acpi:GZE*: + ID_VENDOR_FROM_DATABASE=GUNZE Limited + +acpi:HAE*: + ID_VENDOR_FROM_DATABASE=Haider electronics + +acpi:HAI*: + ID_VENDOR_FROM_DATABASE=Haivision Systems Inc. + +acpi:HAL*: + ID_VENDOR_FROM_DATABASE=Halberthal + +acpi:HAN*: + ID_VENDOR_FROM_DATABASE=Hanchang System Corporation + +acpi:HAR*: + ID_VENDOR_FROM_DATABASE=Harris Corporation + +acpi:HAY*: + ID_VENDOR_FROM_DATABASE=Hayes Microcomputer Products Inc + +acpi:HCA*: + ID_VENDOR_FROM_DATABASE=DAT + +acpi:HCE*: + ID_VENDOR_FROM_DATABASE=Hitachi Consumer Electronics Co., Ltd + +acpi:HCL*: + ID_VENDOR_FROM_DATABASE=HCL America Inc + +acpi:HCM*: + ID_VENDOR_FROM_DATABASE=HCL Peripherals + +acpi:HCP*: + ID_VENDOR_FROM_DATABASE=Hitachi Computer Products Inc + +acpi:HCW*: + ID_VENDOR_FROM_DATABASE=Hauppauge Computer Works Inc + +acpi:HDC*: + ID_VENDOR_FROM_DATABASE=HardCom Elektronik & Datateknik + +acpi:HDI*: + ID_VENDOR_FROM_DATABASE=HD-INFO d.o.o. + +acpi:HDV*: + ID_VENDOR_FROM_DATABASE=Holografika kft. + +acpi:HEC*: + ID_VENDOR_FROM_DATABASE=Hisense Electric Co., Ltd. + +acpi:HEL*: + ID_VENDOR_FROM_DATABASE=Hitachi Micro Systems Europe Ltd + +acpi:HER*: + ID_VENDOR_FROM_DATABASE=Ascom Business Systems + +acpi:HET*: + ID_VENDOR_FROM_DATABASE=HETEC Datensysteme GmbH + +acpi:HHC*: + ID_VENDOR_FROM_DATABASE=HIRAKAWA HEWTECH CORP. + +acpi:HHI*: + ID_VENDOR_FROM_DATABASE=Fraunhofer Heinrich-Hertz-Institute + +acpi:HIB*: + ID_VENDOR_FROM_DATABASE=Hibino Corporation + +acpi:HIC*: + ID_VENDOR_FROM_DATABASE=Hitachi Information Technology Co., Ltd. + +acpi:HIK*: + ID_VENDOR_FROM_DATABASE=Hikom Co., Ltd. + +acpi:HIL*: + ID_VENDOR_FROM_DATABASE=Hilevel Technology + +acpi:HIQ*: + ID_VENDOR_FROM_DATABASE=Kaohsiung Opto Electronics Americas, Inc. + +acpi:HIT*: + ID_VENDOR_FROM_DATABASE=Hitachi America Ltd + +acpi:HJI*: + ID_VENDOR_FROM_DATABASE=Harris & Jeffries Inc + +acpi:HKA*: + ID_VENDOR_FROM_DATABASE=HONKO MFG. CO., LTD. + +acpi:HKG*: + ID_VENDOR_FROM_DATABASE=Josef Heim KG + +acpi:HMC*: + ID_VENDOR_FROM_DATABASE=Hualon Microelectric Corporation + +acpi:HMK*: + ID_VENDOR_FROM_DATABASE=hmk Daten-System-Technik BmbH + +acpi:HMX*: + ID_VENDOR_FROM_DATABASE=HUMAX Co., Ltd. + +acpi:HNS*: + ID_VENDOR_FROM_DATABASE=Hughes Network Systems + +acpi:HOB*: + ID_VENDOR_FROM_DATABASE=HOB Electronic GmbH + +acpi:HOE*: + ID_VENDOR_FROM_DATABASE=Hosiden Corporation + +acpi:HOL*: + ID_VENDOR_FROM_DATABASE=Holoeye Photonics AG + +acpi:HON*: + ID_VENDOR_FROM_DATABASE=Sonitronix + +acpi:HPA*: + ID_VENDOR_FROM_DATABASE=Zytor Communications + +acpi:HPC*: + ID_VENDOR_FROM_DATABASE=Hewlett Packard Co. + +acpi:HPD*: + ID_VENDOR_FROM_DATABASE=Hewlett Packard + +acpi:HPI*: + ID_VENDOR_FROM_DATABASE=Headplay, Inc. + +acpi:HPK*: + ID_VENDOR_FROM_DATABASE=HAMAMATSU PHOTONICS K.K. + +acpi:HPQ*: + ID_VENDOR_FROM_DATABASE=HP + +acpi:HPR*: + ID_VENDOR_FROM_DATABASE=H.P.R. Electronics GmbH + +acpi:HRC*: + ID_VENDOR_FROM_DATABASE=Hercules + +acpi:HRE*: + ID_VENDOR_FROM_DATABASE=Qingdao Haier Electronics Co., Ltd. + +acpi:HRI*: + ID_VENDOR_FROM_DATABASE=Hall Research + +acpi:HRL*: + ID_VENDOR_FROM_DATABASE=Herolab GmbH + +acpi:HRS*: + ID_VENDOR_FROM_DATABASE=Harris Semiconductor + +acpi:HRT*: + ID_VENDOR_FROM_DATABASE=HERCULES + +acpi:HSC*: + ID_VENDOR_FROM_DATABASE=Hagiwara Sys-Com Company Ltd + +acpi:HSD*: + ID_VENDOR_FROM_DATABASE=HannStar Display Corp + +acpi:HSM*: + ID_VENDOR_FROM_DATABASE=AT&T Microelectronics + +acpi:HSP*: + ID_VENDOR_FROM_DATABASE=HannStar Display Corp + +acpi:HTC*: + ID_VENDOR_FROM_DATABASE=Hitachi Ltd + +acpi:HTI*: + ID_VENDOR_FROM_DATABASE=Hampshire Company, Inc. + +acpi:HTK*: + ID_VENDOR_FROM_DATABASE=Holtek Microelectronics Inc + +acpi:HTX*: + ID_VENDOR_FROM_DATABASE=Hitex Systementwicklung GmbH + +acpi:HUB*: + ID_VENDOR_FROM_DATABASE=GAI-Tronics, A Hubbell Company + +acpi:HUM*: + ID_VENDOR_FROM_DATABASE=IMP Electronics Ltd. + +acpi:HWA*: + ID_VENDOR_FROM_DATABASE=Harris Canada Inc + +acpi:HWC*: + ID_VENDOR_FROM_DATABASE=DBA Hans Wedemeyer + +acpi:HWD*: + ID_VENDOR_FROM_DATABASE=Highwater Designs Ltd + +acpi:HWP*: + ID_VENDOR_FROM_DATABASE=Hewlett Packard + +acpi:HXM*: + ID_VENDOR_FROM_DATABASE=Hexium Ltd. + +acpi:HYC*: + ID_VENDOR_FROM_DATABASE=Hypercope Gmbh Aachen + +acpi:HYD*: + ID_VENDOR_FROM_DATABASE=Hydis Technologies.Co.,LTD + +acpi:HYO*: + ID_VENDOR_FROM_DATABASE=HYC CO., LTD. + +acpi:HYP*: + ID_VENDOR_FROM_DATABASE=Hyphen Ltd + +acpi:HYR*: + ID_VENDOR_FROM_DATABASE=Hypertec Pty Ltd + +acpi:HYT*: + ID_VENDOR_FROM_DATABASE=Heng Yu Technology (HK) Limited + +acpi:HYV*: + ID_VENDOR_FROM_DATABASE=Hynix Semiconductor + +acpi:IAF*: + ID_VENDOR_FROM_DATABASE=Institut f r angewandte Funksystemtechnik GmbH + +acpi:IAI*: + ID_VENDOR_FROM_DATABASE=Integration Associates, Inc. + +acpi:IAT*: + ID_VENDOR_FROM_DATABASE=IAT Germany GmbH + +acpi:IBC*: + ID_VENDOR_FROM_DATABASE=Integrated Business Systems + +acpi:IBI*: + ID_VENDOR_FROM_DATABASE=INBINE.CO.LTD + +acpi:IBM*: + ID_VENDOR_FROM_DATABASE=IBM + +acpi:IBP*: + ID_VENDOR_FROM_DATABASE=IBP Instruments GmbH + +acpi:IBR*: + ID_VENDOR_FROM_DATABASE=IBR GmbH + +acpi:ICA*: + ID_VENDOR_FROM_DATABASE=ICA Inc + +acpi:ICC*: + ID_VENDOR_FROM_DATABASE=BICC Data Networks Ltd + +acpi:ICD*: + ID_VENDOR_FROM_DATABASE=ICD Inc + +acpi:ICE*: + ID_VENDOR_FROM_DATABASE=IC Ensemble + +acpi:ICI*: + ID_VENDOR_FROM_DATABASE=Infotek Communication Inc + +acpi:ICM*: + ID_VENDOR_FROM_DATABASE=Intracom SA + +acpi:ICN*: + ID_VENDOR_FROM_DATABASE=Sanyo Icon + +acpi:ICO*: + ID_VENDOR_FROM_DATABASE=Intel Corp + +acpi:ICS*: + ID_VENDOR_FROM_DATABASE=Integrated Circuit Systems + +acpi:ICV*: + ID_VENDOR_FROM_DATABASE=Inside Contactless + +acpi:ICX*: + ID_VENDOR_FROM_DATABASE=ICCC A/S + +acpi:IDC*: + ID_VENDOR_FROM_DATABASE=International Datacasting Corporation + +acpi:IDE*: + ID_VENDOR_FROM_DATABASE=IDE Associates + +acpi:IDK*: + ID_VENDOR_FROM_DATABASE=IDK Corporation + +acpi:IDN*: + ID_VENDOR_FROM_DATABASE=Idneo Technologies + +acpi:IDO*: + ID_VENDOR_FROM_DATABASE=IDEO Product Development + +acpi:IDP*: + ID_VENDOR_FROM_DATABASE=Integrated Device Technology, Inc. + +acpi:IDS*: + ID_VENDOR_FROM_DATABASE=Interdigital Sistemas de Informacao + +acpi:IDT*: + ID_VENDOR_FROM_DATABASE=International Display Technology + +acpi:IDX*: + ID_VENDOR_FROM_DATABASE=IDEXX Labs + +acpi:IEC*: + ID_VENDOR_FROM_DATABASE=Interlace Engineering Corporation + +acpi:IEE*: + ID_VENDOR_FROM_DATABASE=IEE + +acpi:IEI*: + ID_VENDOR_FROM_DATABASE=Interlink Electronics + +acpi:IFS*: + ID_VENDOR_FROM_DATABASE=In Focus Systems Inc + +acpi:IFT*: + ID_VENDOR_FROM_DATABASE=Informtech + +acpi:IFX*: + ID_VENDOR_FROM_DATABASE=Infineon Technologies AG + +acpi:IFZ*: + ID_VENDOR_FROM_DATABASE=Infinite Z + +acpi:IGC*: + ID_VENDOR_FROM_DATABASE=Intergate Pty Ltd + +acpi:IGM*: + ID_VENDOR_FROM_DATABASE=IGM Communi + +acpi:IHE*: + ID_VENDOR_FROM_DATABASE=InHand Electronics + +acpi:IIC*: + ID_VENDOR_FROM_DATABASE=ISIC Innoscan Industrial Computers A/S + +acpi:III*: + ID_VENDOR_FROM_DATABASE=Intelligent Instrumentation + +acpi:IIN*: + ID_VENDOR_FROM_DATABASE=IINFRA Co., Ltd + +acpi:IKS*: + ID_VENDOR_FROM_DATABASE=Ikos Systems Inc + +acpi:ILC*: + ID_VENDOR_FROM_DATABASE=Image Logic Corporation + +acpi:ILS*: + ID_VENDOR_FROM_DATABASE=Innotech Corporation + +acpi:IMA*: + ID_VENDOR_FROM_DATABASE=Imagraph + +acpi:IMB*: + ID_VENDOR_FROM_DATABASE=ART s.r.l. + +acpi:IMC*: + ID_VENDOR_FROM_DATABASE=IMC Networks + +acpi:IMD*: + ID_VENDOR_FROM_DATABASE=ImasDe Canarias S.A. + +acpi:IME*: + ID_VENDOR_FROM_DATABASE=Imagraph + +acpi:IMG*: + ID_VENDOR_FROM_DATABASE=IMAGENICS Co., Ltd. + +acpi:IMI*: + ID_VENDOR_FROM_DATABASE=International Microsystems Inc + +acpi:IMM*: + ID_VENDOR_FROM_DATABASE=Immersion Corporation + +acpi:IMN*: + ID_VENDOR_FROM_DATABASE=Impossible Production + +acpi:IMP*: + ID_VENDOR_FROM_DATABASE=Impression Products Incorporated + +acpi:IMT*: + ID_VENDOR_FROM_DATABASE=Inmax Technology Corporation + +acpi:INC*: + ID_VENDOR_FROM_DATABASE=Home Row Inc + +acpi:IND*: + ID_VENDOR_FROM_DATABASE=ILC + +acpi:INE*: + ID_VENDOR_FROM_DATABASE=Inventec Electronics (M) Sdn. Bhd. + +acpi:INF*: + ID_VENDOR_FROM_DATABASE=Inframetrics Inc + +acpi:ING*: + ID_VENDOR_FROM_DATABASE=Integraph Corporation + +acpi:INI*: + ID_VENDOR_FROM_DATABASE=Initio Corporation + +acpi:INK*: + ID_VENDOR_FROM_DATABASE=Indtek Co., Ltd. + +acpi:INL*: + ID_VENDOR_FROM_DATABASE=InnoLux Display Corporation + +acpi:INM*: + ID_VENDOR_FROM_DATABASE=InnoMedia Inc + +acpi:INN*: + ID_VENDOR_FROM_DATABASE=Innovent Systems, Inc. + +acpi:INO*: + ID_VENDOR_FROM_DATABASE=Innolab Pte Ltd + +acpi:INP*: + ID_VENDOR_FROM_DATABASE=Interphase Corporation + +acpi:INS*: + ID_VENDOR_FROM_DATABASE=Ines GmbH + +acpi:INT*: + ID_VENDOR_FROM_DATABASE=Interphase Corporation + +acpi:inu*: + ID_VENDOR_FROM_DATABASE=Inovatec S.p.A. + +acpi:INV*: + ID_VENDOR_FROM_DATABASE=Inviso, Inc. + +acpi:INZ*: + ID_VENDOR_FROM_DATABASE=Best Buy + +acpi:IOA*: + ID_VENDOR_FROM_DATABASE=CRE Technology Corporation + +acpi:IOD*: + ID_VENDOR_FROM_DATABASE=I-O Data Device Inc + +acpi:IOM*: + ID_VENDOR_FROM_DATABASE=Iomega + +acpi:ION*: + ID_VENDOR_FROM_DATABASE=Inside Out Networks + +acpi:IOS*: + ID_VENDOR_FROM_DATABASE=i-O Display System + +acpi:IOT*: + ID_VENDOR_FROM_DATABASE=I/OTech Inc + +acpi:IPC*: + ID_VENDOR_FROM_DATABASE=IPC Corporation + +acpi:IPD*: + ID_VENDOR_FROM_DATABASE=Industrial Products Design, Inc. + +acpi:IPI*: + ID_VENDOR_FROM_DATABASE=Intelligent Platform Management Interface (IPMI) forum (Intel, HP, NEC, Dell) + +acpi:IPM*: + ID_VENDOR_FROM_DATABASE=IPM Industria Politecnica Meridionale SpA + +acpi:IPN*: + ID_VENDOR_FROM_DATABASE=Performance Technologies + +acpi:IPP*: + ID_VENDOR_FROM_DATABASE=IP Power Technologies GmbH + +acpi:IPR*: + ID_VENDOR_FROM_DATABASE=Ithaca Peripherals + +acpi:IPS*: + ID_VENDOR_FROM_DATABASE=IPS, Inc. (Intellectual Property Solutions, Inc.) + +acpi:IPT*: + ID_VENDOR_FROM_DATABASE=International Power Technologies + +acpi:IPW*: + ID_VENDOR_FROM_DATABASE=IPWireless, Inc + +acpi:IQI*: + ID_VENDOR_FROM_DATABASE=IneoQuest Technologies, Inc + +acpi:IQT*: + ID_VENDOR_FROM_DATABASE=IMAGEQUEST Co., Ltd + +acpi:IRD*: + ID_VENDOR_FROM_DATABASE=IRdata + +acpi:ISA*: + ID_VENDOR_FROM_DATABASE=Symbol Technologies + +acpi:ISC*: + ID_VENDOR_FROM_DATABASE=Id3 Semiconductors + +acpi:ISG*: + ID_VENDOR_FROM_DATABASE=Insignia Solutions Inc + +acpi:ISI*: + ID_VENDOR_FROM_DATABASE=Interface Solutions + +acpi:ISL*: + ID_VENDOR_FROM_DATABASE=Isolation Systems + +acpi:ISM*: + ID_VENDOR_FROM_DATABASE=Image Stream Medical + +acpi:ISP*: + ID_VENDOR_FROM_DATABASE=IntreSource Systems Pte Ltd + +acpi:ISR*: + ID_VENDOR_FROM_DATABASE=INSIS Co., LTD. + +acpi:ISS*: + ID_VENDOR_FROM_DATABASE=ISS Inc + +acpi:IST*: + ID_VENDOR_FROM_DATABASE=Intersolve Technologies + +acpi:ISY*: + ID_VENDOR_FROM_DATABASE=International Integrated Systems,Inc.(IISI) + +acpi:ITA*: + ID_VENDOR_FROM_DATABASE=Itausa Export North America + +acpi:ITC*: + ID_VENDOR_FROM_DATABASE=Intercom Inc + +acpi:ITD*: + ID_VENDOR_FROM_DATABASE=Internet Technology Corporation + +acpi:ITE*: + ID_VENDOR_FROM_DATABASE=Integrated Tech Express Inc + +acpi:ITK*: + ID_VENDOR_FROM_DATABASE=ITK Telekommunikation AG + +acpi:ITL*: + ID_VENDOR_FROM_DATABASE=Inter-Tel + +acpi:ITM*: + ID_VENDOR_FROM_DATABASE=ITM inc. + +acpi:ITN*: + ID_VENDOR_FROM_DATABASE=The NTI Group + +acpi:ITP*: + ID_VENDOR_FROM_DATABASE=IT-PRO Consulting und Systemhaus GmbH + +acpi:ITR*: + ID_VENDOR_FROM_DATABASE=Infotronic America, Inc. + +acpi:ITS*: + ID_VENDOR_FROM_DATABASE=IDTECH + +acpi:ITT*: + ID_VENDOR_FROM_DATABASE=I&T Telecom. + +acpi:ITX*: + ID_VENDOR_FROM_DATABASE=integrated Technology Express Inc + +acpi:IUC*: + ID_VENDOR_FROM_DATABASE=ICSL + +acpi:IVI*: + ID_VENDOR_FROM_DATABASE=Intervoice Inc + +acpi:IVM*: + ID_VENDOR_FROM_DATABASE=Iiyama North America + +acpi:IVS*: + ID_VENDOR_FROM_DATABASE=Intevac Photonics Inc. + +acpi:IWR*: + ID_VENDOR_FROM_DATABASE=Icuiti Corporation + +acpi:IWX*: + ID_VENDOR_FROM_DATABASE=Intelliworxx, Inc. + +acpi:IXD*: + ID_VENDOR_FROM_DATABASE=Intertex Data AB + +acpi:JAC*: + ID_VENDOR_FROM_DATABASE=Astec Inc + +acpi:JAE*: + ID_VENDOR_FROM_DATABASE=Japan Aviation Electronics Industry, Limited + +acpi:JAS*: + ID_VENDOR_FROM_DATABASE=Janz Automationssysteme AG + +acpi:JAT*: + ID_VENDOR_FROM_DATABASE=Jaton Corporation + +acpi:JAZ*: + ID_VENDOR_FROM_DATABASE=Carrera Computer Inc + +acpi:JCE*: + ID_VENDOR_FROM_DATABASE=Jace Tech Inc + +acpi:JDL*: + ID_VENDOR_FROM_DATABASE=Japan Digital Laboratory Co.,Ltd. + +acpi:JEN*: + ID_VENDOR_FROM_DATABASE=N-Vision + +acpi:JET*: + ID_VENDOR_FROM_DATABASE=JET POWER TECHNOLOGY CO., LTD. + +acpi:JFX*: + ID_VENDOR_FROM_DATABASE=Jones Futurex Inc + +acpi:JGD*: + ID_VENDOR_FROM_DATABASE=University College + +acpi:JIC*: + ID_VENDOR_FROM_DATABASE=Jaeik Information & Communication Co., Ltd. + +acpi:JKC*: + ID_VENDOR_FROM_DATABASE=JVC KENWOOD Corporation + +acpi:JMT*: + ID_VENDOR_FROM_DATABASE=Micro Technical Company Ltd + +acpi:JPC*: + ID_VENDOR_FROM_DATABASE=JPC Technology Limited + +acpi:JPW*: + ID_VENDOR_FROM_DATABASE=Wallis Hamilton Industries + +acpi:JQE*: + ID_VENDOR_FROM_DATABASE=CNet Technical Inc + +acpi:JSD*: + ID_VENDOR_FROM_DATABASE=JS DigiTech, Inc + +acpi:JSI*: + ID_VENDOR_FROM_DATABASE=Jupiter Systems, Inc. + +acpi:JSK*: + ID_VENDOR_FROM_DATABASE=SANKEN ELECTRIC CO., LTD + +acpi:JTS*: + ID_VENDOR_FROM_DATABASE=JS Motorsports + +acpi:JTY*: + ID_VENDOR_FROM_DATABASE=jetway security micro,inc + +acpi:JUK*: + ID_VENDOR_FROM_DATABASE=Janich & Klass Computertechnik GmbH + +acpi:JUP*: + ID_VENDOR_FROM_DATABASE=Jupiter Systems + +acpi:JVC*: + ID_VENDOR_FROM_DATABASE=JVC + +acpi:JWD*: + ID_VENDOR_FROM_DATABASE=Video International Inc. + +acpi:JWL*: + ID_VENDOR_FROM_DATABASE=Jewell Instruments, LLC + +acpi:JWS*: + ID_VENDOR_FROM_DATABASE=JWSpencer & Co. + +acpi:JWY*: + ID_VENDOR_FROM_DATABASE=Jetway Information Co., Ltd + +acpi:KAR*: + ID_VENDOR_FROM_DATABASE=Karna + +acpi:KBI*: + ID_VENDOR_FROM_DATABASE=Kidboard Inc + +acpi:KBL*: + ID_VENDOR_FROM_DATABASE=Kobil Systems GmbH + +acpi:KCD*: + ID_VENDOR_FROM_DATABASE=Chunichi Denshi Co.,LTD. + +acpi:KCL*: + ID_VENDOR_FROM_DATABASE=Keycorp Ltd + +acpi:KDE*: + ID_VENDOR_FROM_DATABASE=KDE + +acpi:KDK*: + ID_VENDOR_FROM_DATABASE=Kodiak Tech + +acpi:KDM*: + ID_VENDOR_FROM_DATABASE=Korea Data Systems Co., Ltd. + +acpi:KDS*: + ID_VENDOR_FROM_DATABASE=KDS USA + +acpi:KDT*: + ID_VENDOR_FROM_DATABASE=KDDI Technology Corporation + +acpi:KEC*: + ID_VENDOR_FROM_DATABASE=Kyushu Electronics Systems Inc + +acpi:KEM*: + ID_VENDOR_FROM_DATABASE=Kontron Embedded Modules GmbH + +acpi:KES*: + ID_VENDOR_FROM_DATABASE=Kesa Corporation + +acpi:KEY*: + ID_VENDOR_FROM_DATABASE=Key Tech Inc + +acpi:KFC*: + ID_VENDOR_FROM_DATABASE=SCD Tech + +acpi:KFE*: + ID_VENDOR_FROM_DATABASE=Komatsu Forest + +acpi:KFX*: + ID_VENDOR_FROM_DATABASE=Kofax Image Products + +acpi:KGL*: + ID_VENDOR_FROM_DATABASE=KEISOKU GIKEN Co.,Ltd. + +acpi:KIS*: + ID_VENDOR_FROM_DATABASE=KiSS Technology A/S + +acpi:KMC*: + ID_VENDOR_FROM_DATABASE=Mitsumi Company Ltd + +acpi:KME*: + ID_VENDOR_FROM_DATABASE=KIMIN Electronics Co., Ltd. + +acpi:KML*: + ID_VENDOR_FROM_DATABASE=Kensington Microware Ltd + +acpi:KNC*: + ID_VENDOR_FROM_DATABASE=Konica corporation + +acpi:KNX*: + ID_VENDOR_FROM_DATABASE=Nutech Marketing PTL + +acpi:KOB*: + ID_VENDOR_FROM_DATABASE=Kobil Systems GmbH + +acpi:KOD*: + ID_VENDOR_FROM_DATABASE=Eastman Kodak Company + +acpi:KOE*: + ID_VENDOR_FROM_DATABASE=KOLTER ELECTRONIC + +acpi:KOL*: + ID_VENDOR_FROM_DATABASE=Kollmorgen Motion Technologies Group + +acpi:KOU*: + ID_VENDOR_FROM_DATABASE=KOUZIRO Co.,Ltd. + +acpi:KOW*: + ID_VENDOR_FROM_DATABASE=KOWA Company,LTD. + +acpi:KPC*: + ID_VENDOR_FROM_DATABASE=King Phoenix Company + +acpi:KRL*: + ID_VENDOR_FROM_DATABASE=Krell Industries Inc. + +acpi:KRM*: + ID_VENDOR_FROM_DATABASE=Kroma Telecom + +acpi:KRY*: + ID_VENDOR_FROM_DATABASE=Kroy LLC + +acpi:KSC*: + ID_VENDOR_FROM_DATABASE=Kinetic Systems Corporation + +acpi:KSL*: + ID_VENDOR_FROM_DATABASE=Karn Solutions Ltd. + +acpi:KSX*: + ID_VENDOR_FROM_DATABASE=King Tester Corporation + +acpi:KTC*: + ID_VENDOR_FROM_DATABASE=Kingston Tech Corporation + +acpi:KTD*: + ID_VENDOR_FROM_DATABASE=Takahata Electronics Co.,Ltd. + +acpi:KTE*: + ID_VENDOR_FROM_DATABASE=K-Tech + +acpi:KTG*: + ID_VENDOR_FROM_DATABASE=Kayser-Threde GmbH + +acpi:KTI*: + ID_VENDOR_FROM_DATABASE=Konica Technical Inc + +acpi:KTK*: + ID_VENDOR_FROM_DATABASE=Key Tronic Corporation + +acpi:KTN*: + ID_VENDOR_FROM_DATABASE=Katron Tech Inc + +acpi:KUR*: + ID_VENDOR_FROM_DATABASE=Kurta Corporation + +acpi:KVA*: + ID_VENDOR_FROM_DATABASE=Kvaser AB + +acpi:KVX*: + ID_VENDOR_FROM_DATABASE=KeyView + +acpi:KWD*: + ID_VENDOR_FROM_DATABASE=Kenwood Corporation + +acpi:KYC*: + ID_VENDOR_FROM_DATABASE=Kyocera Corporation + +acpi:KYE*: + ID_VENDOR_FROM_DATABASE=KYE Syst Corporation + +acpi:KYK*: + ID_VENDOR_FROM_DATABASE=Samsung Electronics America Inc + +acpi:KZI*: + ID_VENDOR_FROM_DATABASE=K-Zone International co. Ltd. + +acpi:KZN*: + ID_VENDOR_FROM_DATABASE=K-Zone International + +acpi:LAB*: + ID_VENDOR_FROM_DATABASE=ACT Labs Ltd + +acpi:LAC*: + ID_VENDOR_FROM_DATABASE=LaCie + +acpi:LAF*: + ID_VENDOR_FROM_DATABASE=Microline + +acpi:LAG*: + ID_VENDOR_FROM_DATABASE=Laguna Systems + +acpi:LAN*: + ID_VENDOR_FROM_DATABASE=Sodeman Lancom Inc + +acpi:LAS*: + ID_VENDOR_FROM_DATABASE=LASAT Comm. A/S + +acpi:LAV*: + ID_VENDOR_FROM_DATABASE=Lava Computer MFG Inc + +acpi:LBO*: + ID_VENDOR_FROM_DATABASE=Lubosoft + +acpi:LCC*: + ID_VENDOR_FROM_DATABASE=LCI + +acpi:LCD*: + ID_VENDOR_FROM_DATABASE=Toshiba Matsushita Display Technology Co., Ltd + +acpi:LCE*: + ID_VENDOR_FROM_DATABASE=La Commande Electronique + +acpi:LCI*: + ID_VENDOR_FROM_DATABASE=Lite-On Communication Inc + +acpi:LCM*: + ID_VENDOR_FROM_DATABASE=Latitude Comm. + +acpi:LCN*: + ID_VENDOR_FROM_DATABASE=LEXICON + +acpi:LCS*: + ID_VENDOR_FROM_DATABASE=Longshine Electronics Company + +acpi:LCT*: + ID_VENDOR_FROM_DATABASE=Labcal Technologies + +acpi:LDT*: + ID_VENDOR_FROM_DATABASE=LogiDataTech Electronic GmbH + +acpi:LEC*: + ID_VENDOR_FROM_DATABASE=Lectron Company Ltd + +acpi:LED*: + ID_VENDOR_FROM_DATABASE=Long Engineering Design Inc + +acpi:LEG*: + ID_VENDOR_FROM_DATABASE=Legerity, Inc + +acpi:LEN*: + ID_VENDOR_FROM_DATABASE=Lenovo Group Limited + +acpi:LEO*: + ID_VENDOR_FROM_DATABASE=First International Computer Inc + +acpi:LEX*: + ID_VENDOR_FROM_DATABASE=Lexical Ltd + +acpi:LGC*: + ID_VENDOR_FROM_DATABASE=Logic Ltd + +acpi:LGI*: + ID_VENDOR_FROM_DATABASE=Logitech Inc + +acpi:LGS*: + ID_VENDOR_FROM_DATABASE=LG Semicom Company Ltd + +acpi:LGX*: + ID_VENDOR_FROM_DATABASE=Lasergraphics, Inc. + +acpi:LHA*: + ID_VENDOR_FROM_DATABASE=Lars Haagh ApS + +acpi:LHE*: + ID_VENDOR_FROM_DATABASE=Lung Hwa Electronics Company Ltd + +acpi:LHT*: + ID_VENDOR_FROM_DATABASE=Lighthouse Technologies Limited + +acpi:LIN*: + ID_VENDOR_FROM_DATABASE=Lenovo Beijing Co. Ltd. + +acpi:LIP*: + ID_VENDOR_FROM_DATABASE=Linked IP GmbH + +acpi:LIT*: + ID_VENDOR_FROM_DATABASE=Lithics Silicon Technology + +acpi:LJX*: + ID_VENDOR_FROM_DATABASE=Datalogic Corporation + +acpi:LKM*: + ID_VENDOR_FROM_DATABASE=Likom Technology Sdn. Bhd. + +acpi:LLL*: + ID_VENDOR_FROM_DATABASE=L-3 Communications + +acpi:LMG*: + ID_VENDOR_FROM_DATABASE=Lucent Technologies + +acpi:LMI*: + ID_VENDOR_FROM_DATABASE=Lexmark Int'l Inc + +acpi:LMP*: + ID_VENDOR_FROM_DATABASE=Leda Media Products + +acpi:LMT*: + ID_VENDOR_FROM_DATABASE=Laser Master + +acpi:LND*: + ID_VENDOR_FROM_DATABASE=Land Computer Company Ltd + +acpi:LNK*: + ID_VENDOR_FROM_DATABASE=Link Tech Inc + +acpi:LNR*: + ID_VENDOR_FROM_DATABASE=Linear Systems Ltd. + +acpi:LNT*: + ID_VENDOR_FROM_DATABASE=LANETCO International + +acpi:LNV*: + ID_VENDOR_FROM_DATABASE=Lenovo + +acpi:LOC*: + ID_VENDOR_FROM_DATABASE=Locamation B.V. + +acpi:LOE*: + ID_VENDOR_FROM_DATABASE=Loewe Opta GmbH + +acpi:LOG*: + ID_VENDOR_FROM_DATABASE=Logicode Technology Inc + +acpi:LOL*: + ID_VENDOR_FROM_DATABASE=Litelogic Operations Ltd + +acpi:LPE*: + ID_VENDOR_FROM_DATABASE=El-PUSK Co., Ltd. + +acpi:LPI*: + ID_VENDOR_FROM_DATABASE=Design Technology + +acpi:LSC*: + ID_VENDOR_FROM_DATABASE=LifeSize Communications + +acpi:LSD*: + ID_VENDOR_FROM_DATABASE=Intersil Corporation + +acpi:LSI*: + ID_VENDOR_FROM_DATABASE=Loughborough Sound Images + +acpi:LSJ*: + ID_VENDOR_FROM_DATABASE=LSI Japan Company Ltd + +acpi:LSL*: + ID_VENDOR_FROM_DATABASE=Logical Solutions + +acpi:LSY*: + ID_VENDOR_FROM_DATABASE=LSI Systems Inc + +acpi:LTC*: + ID_VENDOR_FROM_DATABASE=Labtec Inc + +acpi:LTI*: + ID_VENDOR_FROM_DATABASE=Jongshine Tech Inc + +acpi:LTK*: + ID_VENDOR_FROM_DATABASE=Lucidity Technology Company Ltd + +acpi:LTN*: + ID_VENDOR_FROM_DATABASE=Litronic Inc + +acpi:LTS*: + ID_VENDOR_FROM_DATABASE=LTS Scale LLC + +acpi:LTV*: + ID_VENDOR_FROM_DATABASE=Leitch Technology International Inc. + +acpi:LTW*: + ID_VENDOR_FROM_DATABASE=Lightware, Inc + +acpi:LUC*: + ID_VENDOR_FROM_DATABASE=Lucent Technologies + +acpi:LUM*: + ID_VENDOR_FROM_DATABASE=Lumagen, Inc. + +acpi:LUX*: + ID_VENDOR_FROM_DATABASE=Luxxell Research Inc + +acpi:LVI*: + ID_VENDOR_FROM_DATABASE=LVI Low Vision International AB + +acpi:LWC*: + ID_VENDOR_FROM_DATABASE=Labway Corporation + +acpi:LWR*: + ID_VENDOR_FROM_DATABASE=Lightware Visual Engineering + +acpi:LWW*: + ID_VENDOR_FROM_DATABASE=Lanier Worldwide + +acpi:LXC*: + ID_VENDOR_FROM_DATABASE=LXCO Technologies AG + +acpi:LXN*: + ID_VENDOR_FROM_DATABASE=Luxeon + +acpi:LXS*: + ID_VENDOR_FROM_DATABASE=ELEA CardWare + +acpi:LZX*: + ID_VENDOR_FROM_DATABASE=Lightwell Company Ltd + +acpi:MAC*: + ID_VENDOR_FROM_DATABASE=MAC System Company Ltd + +acpi:MAD*: + ID_VENDOR_FROM_DATABASE=Xedia Corporation + +acpi:MAE*: + ID_VENDOR_FROM_DATABASE=Maestro Pty Ltd + +acpi:MAG*: + ID_VENDOR_FROM_DATABASE=MAG InnoVision + +acpi:MAI*: + ID_VENDOR_FROM_DATABASE=Mutoh America Inc + +acpi:MAL*: + ID_VENDOR_FROM_DATABASE=Meridian Audio Ltd + +acpi:MAN*: + ID_VENDOR_FROM_DATABASE=LGIC + +acpi:MAS*: + ID_VENDOR_FROM_DATABASE=Mass Inc. + +acpi:MAT*: + ID_VENDOR_FROM_DATABASE=Matsushita Electric Ind. Company Ltd + +acpi:MAX*: + ID_VENDOR_FROM_DATABASE=Rogen Tech Distribution Inc + +acpi:MAY*: + ID_VENDOR_FROM_DATABASE=Maynard Electronics + +acpi:MAZ*: + ID_VENDOR_FROM_DATABASE=MAZeT GmbH + +acpi:MBC*: + ID_VENDOR_FROM_DATABASE=MBC + +acpi:MBD*: + ID_VENDOR_FROM_DATABASE=Microbus PLC + +acpi:MBM*: + ID_VENDOR_FROM_DATABASE=Marshall Electronics + +acpi:MBV*: + ID_VENDOR_FROM_DATABASE=Moreton Bay + +acpi:MCA*: + ID_VENDOR_FROM_DATABASE=American Nuclear Systems Inc + +acpi:MCC*: + ID_VENDOR_FROM_DATABASE=Micro Industries + +acpi:MCD*: + ID_VENDOR_FROM_DATABASE=McDATA Corporation + +acpi:MCE*: + ID_VENDOR_FROM_DATABASE=Metz-Werke GmbH & Co KG + +acpi:MCG*: + ID_VENDOR_FROM_DATABASE=Motorola Computer Group + +acpi:MCI*: + ID_VENDOR_FROM_DATABASE=Micronics Computers + +acpi:MCL*: + ID_VENDOR_FROM_DATABASE=Motorola Communications Israel + +acpi:MCM*: + ID_VENDOR_FROM_DATABASE=Metricom Inc + +acpi:MCN*: + ID_VENDOR_FROM_DATABASE=Micron Electronics Inc + +acpi:MCO*: + ID_VENDOR_FROM_DATABASE=Motion Computing Inc. + +acpi:MCP*: + ID_VENDOR_FROM_DATABASE=Magni Systems Inc + +acpi:MCQ*: + ID_VENDOR_FROM_DATABASE=Mat's Computers + +acpi:MCR*: + ID_VENDOR_FROM_DATABASE=Marina Communicaitons + +acpi:MCS*: + ID_VENDOR_FROM_DATABASE=Micro Computer Systems + +acpi:MCT*: + ID_VENDOR_FROM_DATABASE=Microtec + +acpi:MDA*: + ID_VENDOR_FROM_DATABASE=Media4 Inc + +acpi:MDC*: + ID_VENDOR_FROM_DATABASE=Midori Electronics + +acpi:MDD*: + ID_VENDOR_FROM_DATABASE=MODIS + +acpi:MDG*: + ID_VENDOR_FROM_DATABASE=Madge Networks + +acpi:MDI*: + ID_VENDOR_FROM_DATABASE=Micro Design Inc + +acpi:MDK*: + ID_VENDOR_FROM_DATABASE=Mediatek Corporation + +acpi:MDO*: + ID_VENDOR_FROM_DATABASE=Panasonic + +acpi:MDR*: + ID_VENDOR_FROM_DATABASE=Medar Inc + +acpi:MDS*: + ID_VENDOR_FROM_DATABASE=Micro Display Systems Inc + +acpi:MDT*: + ID_VENDOR_FROM_DATABASE=Magus Data Tech + +acpi:MDV*: + ID_VENDOR_FROM_DATABASE=MET Development Inc + +acpi:MDX*: + ID_VENDOR_FROM_DATABASE=MicroDatec GmbH + +acpi:MDY*: + ID_VENDOR_FROM_DATABASE=Microdyne Inc + +acpi:MEC*: + ID_VENDOR_FROM_DATABASE=Mega System Technologies Inc + +acpi:MED*: + ID_VENDOR_FROM_DATABASE=Messeltronik Dresden GmbH + +acpi:MEE*: + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Engineering Co., Ltd. + +acpi:MEG*: + ID_VENDOR_FROM_DATABASE=Abeam Tech Ltd + +acpi:MEI*: + ID_VENDOR_FROM_DATABASE=Panasonic Industry Company + +acpi:MEJ*: + ID_VENDOR_FROM_DATABASE=Mac-Eight Co., LTD. + +acpi:MEL*: + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Corporation + +acpi:MEN*: + ID_VENDOR_FROM_DATABASE=MEN Mikroelectronik Nueruberg GmbH + +acpi:MEQ*: + ID_VENDOR_FROM_DATABASE=Matelect Ltd. + +acpi:MET*: + ID_VENDOR_FROM_DATABASE=Metheus Corporation + +acpi:MEX*: + ID_VENDOR_FROM_DATABASE=MSC Vertriebs GmbH + +acpi:MFG*: + ID_VENDOR_FROM_DATABASE=MicroField Graphics Inc + +acpi:MFI*: + ID_VENDOR_FROM_DATABASE=Micro Firmware + +acpi:MFR*: + ID_VENDOR_FROM_DATABASE=MediaFire Corp. + +acpi:MGA*: + ID_VENDOR_FROM_DATABASE=Mega System Technologies, Inc. + +acpi:MGC*: + ID_VENDOR_FROM_DATABASE=Mentor Graphics Corporation + +acpi:MGE*: + ID_VENDOR_FROM_DATABASE=Schneider Electric S.A. + +acpi:MGL*: + ID_VENDOR_FROM_DATABASE=M-G Technology Ltd + +acpi:MGT*: + ID_VENDOR_FROM_DATABASE=Megatech R & D Company + +acpi:MIC*: + ID_VENDOR_FROM_DATABASE=Micom Communications Inc + +acpi:MID*: + ID_VENDOR_FROM_DATABASE=miro Displays + +acpi:MII*: + ID_VENDOR_FROM_DATABASE=Mitec Inc + +acpi:MIL*: + ID_VENDOR_FROM_DATABASE=Marconi Instruments Ltd + +acpi:MIM*: + ID_VENDOR_FROM_DATABASE=Mimio – A Newell Rubbermaid Company + +acpi:MIN*: + ID_VENDOR_FROM_DATABASE=Minicom Digital Signage + +acpi:MIP*: + ID_VENDOR_FROM_DATABASE=micronpc.com + +acpi:MIR*: + ID_VENDOR_FROM_DATABASE=Miro Computer Prod. + +acpi:MIS*: + ID_VENDOR_FROM_DATABASE=Modular Industrial Solutions Inc + +acpi:MIT*: + ID_VENDOR_FROM_DATABASE=MCM Industrial Technology GmbH + +acpi:MJI*: + ID_VENDOR_FROM_DATABASE=MARANTZ JAPAN, INC. + +acpi:MJS*: + ID_VENDOR_FROM_DATABASE=MJS Designs + +acpi:MKC*: + ID_VENDOR_FROM_DATABASE=Media Tek Inc. + +acpi:MKT*: + ID_VENDOR_FROM_DATABASE=MICROTEK Inc. + +acpi:MKV*: + ID_VENDOR_FROM_DATABASE=Trtheim Technology + +acpi:MLD*: + ID_VENDOR_FROM_DATABASE=Deep Video Imaging Ltd + +acpi:MLG*: + ID_VENDOR_FROM_DATABASE=Micrologica AG + +acpi:MLI*: + ID_VENDOR_FROM_DATABASE=McIntosh Laboratory Inc. + +acpi:MLM*: + ID_VENDOR_FROM_DATABASE=Millennium Engineering Inc + +acpi:MLN*: + ID_VENDOR_FROM_DATABASE=Mark Levinson + +acpi:MLS*: + ID_VENDOR_FROM_DATABASE=Milestone EPE + +acpi:MLX*: + ID_VENDOR_FROM_DATABASE=Mylex Corporation + +acpi:MMA*: + ID_VENDOR_FROM_DATABASE=Micromedia AG + +acpi:MMD*: + ID_VENDOR_FROM_DATABASE=Micromed Biotecnologia Ltd + +acpi:MMF*: + ID_VENDOR_FROM_DATABASE=Minnesota Mining and Manufacturing + +acpi:MMI*: + ID_VENDOR_FROM_DATABASE=Multimax + +acpi:MMM*: + ID_VENDOR_FROM_DATABASE=Electronic Measurements + +acpi:MMN*: + ID_VENDOR_FROM_DATABASE=MiniMan Inc + +acpi:MMS*: + ID_VENDOR_FROM_DATABASE=MMS Electronics + +acpi:MNC*: + ID_VENDOR_FROM_DATABASE=Mini Micro Methods Ltd + +acpi:MNL*: + ID_VENDOR_FROM_DATABASE=Monorail Inc + +acpi:MNP*: + ID_VENDOR_FROM_DATABASE=Microcom + +acpi:MOD*: + ID_VENDOR_FROM_DATABASE=Modular Technology + +acpi:MOM*: + ID_VENDOR_FROM_DATABASE=Momentum Data Systems + +acpi:MOS*: + ID_VENDOR_FROM_DATABASE=Moses Corporation + +acpi:MOT*: + ID_VENDOR_FROM_DATABASE=Motorola UDS + +acpi:MPC*: + ID_VENDOR_FROM_DATABASE=M-Pact Inc + +acpi:MPI*: + ID_VENDOR_FROM_DATABASE=Mediatrix Peripherals Inc + +acpi:MPJ*: + ID_VENDOR_FROM_DATABASE=Microlab + +acpi:MPL*: + ID_VENDOR_FROM_DATABASE=Maple Research Inst. Company Ltd + +acpi:MPN*: + ID_VENDOR_FROM_DATABASE=Mainpine Limited + +acpi:MPS*: + ID_VENDOR_FROM_DATABASE=mps Software GmbH + +acpi:MPX*: + ID_VENDOR_FROM_DATABASE=Micropix Technologies, Ltd. + +acpi:MQP*: + ID_VENDOR_FROM_DATABASE=MultiQ Products AB + +acpi:MRA*: + ID_VENDOR_FROM_DATABASE=Miranda Technologies Inc + +acpi:MRC*: + ID_VENDOR_FROM_DATABASE=Marconi Simulation & Ty-Coch Way Training + +acpi:MRD*: + ID_VENDOR_FROM_DATABASE=MicroDisplay Corporation + +acpi:MRK*: + ID_VENDOR_FROM_DATABASE=Maruko & Company Ltd + +acpi:MRL*: + ID_VENDOR_FROM_DATABASE=Miratel + +acpi:MRO*: + ID_VENDOR_FROM_DATABASE=Medikro Oy + +acpi:MRT*: + ID_VENDOR_FROM_DATABASE=Merging Technologies + +acpi:MSA*: + ID_VENDOR_FROM_DATABASE=Micro Systemation AB + +acpi:MSC*: + ID_VENDOR_FROM_DATABASE=Mouse Systems Corporation + +acpi:MSD*: + ID_VENDOR_FROM_DATABASE=Datenerfassungs- und Informationssysteme + +acpi:MSF*: + ID_VENDOR_FROM_DATABASE=M-Systems Flash Disk Pioneers + +acpi:MSG*: + ID_VENDOR_FROM_DATABASE=MSI GmbH + +acpi:MSH*: + ID_VENDOR_FROM_DATABASE=Microsoft + +acpi:MSI*: + ID_VENDOR_FROM_DATABASE=Microstep + +acpi:MSK*: + ID_VENDOR_FROM_DATABASE=Megasoft Inc + +acpi:MSL*: + ID_VENDOR_FROM_DATABASE=MicroSlate Inc. + +acpi:MSM*: + ID_VENDOR_FROM_DATABASE=Advanced Digital Systems + +acpi:MSP*: + ID_VENDOR_FROM_DATABASE=Mistral Solutions [P] Ltd. + +acpi:MST*: + ID_VENDOR_FROM_DATABASE=MS Telematica + +acpi:MSU*: + ID_VENDOR_FROM_DATABASE=motorola + +acpi:MSV*: + ID_VENDOR_FROM_DATABASE=Mosgi Corporation + +acpi:MSX*: + ID_VENDOR_FROM_DATABASE=Micomsoft Co., Ltd. + +acpi:MSY*: + ID_VENDOR_FROM_DATABASE=MicroTouch Systems Inc + +acpi:MTB*: + ID_VENDOR_FROM_DATABASE=Media Technologies Ltd. + +acpi:MTC*: + ID_VENDOR_FROM_DATABASE=Mars-Tech Corporation + +acpi:MTD*: + ID_VENDOR_FROM_DATABASE=MindTech Display Co. Ltd + +acpi:MTE*: + ID_VENDOR_FROM_DATABASE=MediaTec GmbH + +acpi:MTH*: + ID_VENDOR_FROM_DATABASE=Micro-Tech Hearing Instruments + +acpi:MTI*: + ID_VENDOR_FROM_DATABASE=MaxCom Technical Inc + +acpi:MTK*: + ID_VENDOR_FROM_DATABASE=Microtek International Inc. + +acpi:MTL*: + ID_VENDOR_FROM_DATABASE=Mitel Corporation + +acpi:MTM*: + ID_VENDOR_FROM_DATABASE=Motium + +acpi:MTN*: + ID_VENDOR_FROM_DATABASE=Mtron Storage Technology Co., Ltd. + +acpi:MTR*: + ID_VENDOR_FROM_DATABASE=Mitron computer Inc + +acpi:MTS*: + ID_VENDOR_FROM_DATABASE=Multi-Tech Systems + +acpi:MTU*: + ID_VENDOR_FROM_DATABASE=Mark of the Unicorn Inc + +acpi:MTX*: + ID_VENDOR_FROM_DATABASE=Matrox + +acpi:MUD*: + ID_VENDOR_FROM_DATABASE=Multi-Dimension Institute + +acpi:MUK*: + ID_VENDOR_FROM_DATABASE=mainpine limited + +acpi:MVD*: + ID_VENDOR_FROM_DATABASE=Microvitec PLC + +acpi:MVI*: + ID_VENDOR_FROM_DATABASE=Media Vision Inc + +acpi:MVM*: + ID_VENDOR_FROM_DATABASE=SOBO VISION + +acpi:MVS*: + ID_VENDOR_FROM_DATABASE=Microvision + +acpi:MVX*: + ID_VENDOR_FROM_DATABASE=COM 1 + +acpi:MWI*: + ID_VENDOR_FROM_DATABASE=Multiwave Innovation Pte Ltd + +acpi:MWR*: + ID_VENDOR_FROM_DATABASE=mware + +acpi:MWY*: + ID_VENDOR_FROM_DATABASE=Microway Inc + +acpi:MXD*: + ID_VENDOR_FROM_DATABASE=MaxData Computer GmbH & Co.KG + +acpi:MXI*: + ID_VENDOR_FROM_DATABASE=Macronix Inc + +acpi:MXL*: + ID_VENDOR_FROM_DATABASE=Hitachi Maxell, Ltd. + +acpi:MXP*: + ID_VENDOR_FROM_DATABASE=Maxpeed Corporation + +acpi:MXT*: + ID_VENDOR_FROM_DATABASE=Maxtech Corporation + +acpi:MXV*: + ID_VENDOR_FROM_DATABASE=MaxVision Corporation + +acpi:MYA*: + ID_VENDOR_FROM_DATABASE=Monydata + +acpi:MYR*: + ID_VENDOR_FROM_DATABASE=Myriad Solutions Ltd + +acpi:MYX*: + ID_VENDOR_FROM_DATABASE=Micronyx Inc + +acpi:NAC*: + ID_VENDOR_FROM_DATABASE=Ncast Corporation + +acpi:NAD*: + ID_VENDOR_FROM_DATABASE=NAD Electronics + +acpi:NAK*: + ID_VENDOR_FROM_DATABASE=Nakano Engineering Co.,Ltd. + +acpi:NAL*: + ID_VENDOR_FROM_DATABASE=Network Alchemy + +acpi:NAT*: + ID_VENDOR_FROM_DATABASE=NaturalPoint Inc. + +acpi:NAV*: + ID_VENDOR_FROM_DATABASE=Navigation Corporation + +acpi:NAX*: + ID_VENDOR_FROM_DATABASE=Naxos Tecnologia + +acpi:NBL*: + ID_VENDOR_FROM_DATABASE=N*Able Technologies Inc + +acpi:NBS*: + ID_VENDOR_FROM_DATABASE=National Key Lab. on ISN + +acpi:NBT*: + ID_VENDOR_FROM_DATABASE=NingBo Bestwinning Technology CO., Ltd + +acpi:NCA*: + ID_VENDOR_FROM_DATABASE=Nixdorf Company + +acpi:NCC*: + ID_VENDOR_FROM_DATABASE=NCR Corporation + +acpi:NCE*: + ID_VENDOR_FROM_DATABASE=Norcent Technology, Inc. + +acpi:NCI*: + ID_VENDOR_FROM_DATABASE=NewCom Inc + +acpi:NCL*: + ID_VENDOR_FROM_DATABASE=NetComm Ltd + +acpi:NCR*: + ID_VENDOR_FROM_DATABASE=NCR Electronics + +acpi:NCS*: + ID_VENDOR_FROM_DATABASE=Northgate Computer Systems + +acpi:NCT*: + ID_VENDOR_FROM_DATABASE=NEC CustomTechnica, Ltd. + +acpi:NDC*: + ID_VENDOR_FROM_DATABASE=National DataComm Corporaiton + +acpi:NDI*: + ID_VENDOR_FROM_DATABASE=National Display Systems + +acpi:NDK*: + ID_VENDOR_FROM_DATABASE=Naitoh Densei CO., LTD. + +acpi:NDL*: + ID_VENDOR_FROM_DATABASE=Network Designers + +acpi:NDS*: + ID_VENDOR_FROM_DATABASE=Nokia Data + +acpi:NEC*: + ID_VENDOR_FROM_DATABASE=NEC Corporation + +acpi:NEO*: + ID_VENDOR_FROM_DATABASE=NEO TELECOM CO.,LTD. + +acpi:NET*: + ID_VENDOR_FROM_DATABASE=Mettler Toledo + +acpi:NEU*: + ID_VENDOR_FROM_DATABASE=NEUROTEC - EMPRESA DE PESQUISA E DESENVOLVIMENTO EM BIOMEDICINA + +acpi:NEX*: + ID_VENDOR_FROM_DATABASE=Nexgen Mediatech Inc., + +acpi:NFC*: + ID_VENDOR_FROM_DATABASE=BTC Korea Co., Ltd + +acpi:NFS*: + ID_VENDOR_FROM_DATABASE=Number Five Software + +acpi:NGC*: + ID_VENDOR_FROM_DATABASE=Network General + +acpi:NGS*: + ID_VENDOR_FROM_DATABASE=A D S Exports + +acpi:NHT*: + ID_VENDOR_FROM_DATABASE=Vinci Labs + +acpi:NIC*: + ID_VENDOR_FROM_DATABASE=National Instruments Corporation + +acpi:NIS*: + ID_VENDOR_FROM_DATABASE=Nissei Electric Company + +acpi:NIT*: + ID_VENDOR_FROM_DATABASE=Network Info Technology + +acpi:NIX*: + ID_VENDOR_FROM_DATABASE=Seanix Technology Inc + +acpi:NLC*: + ID_VENDOR_FROM_DATABASE=Next Level Communications + +acpi:NMP*: + ID_VENDOR_FROM_DATABASE=Nokia Mobile Phones + +acpi:NMS*: + ID_VENDOR_FROM_DATABASE=Natural Micro System + +acpi:NMV*: + ID_VENDOR_FROM_DATABASE=NEC-Mitsubishi Electric Visual Systems Corporation + +acpi:NMX*: + ID_VENDOR_FROM_DATABASE=Neomagic + +acpi:NNC*: + ID_VENDOR_FROM_DATABASE=NNC + +acpi:NOE*: + ID_VENDOR_FROM_DATABASE=NordicEye AB + +acpi:NOI*: + ID_VENDOR_FROM_DATABASE=North Invent A/S + +acpi:NOK*: + ID_VENDOR_FROM_DATABASE=Nokia Display Products + +acpi:NOR*: + ID_VENDOR_FROM_DATABASE=Norand Corporation + +acpi:NOT*: + ID_VENDOR_FROM_DATABASE=Not Limited Inc + +acpi:NPI*: + ID_VENDOR_FROM_DATABASE=Network Peripherals Inc + +acpi:NRL*: + ID_VENDOR_FROM_DATABASE=U.S. Naval Research Lab + +acpi:NRT*: + ID_VENDOR_FROM_DATABASE=Beijing Northern Radiantelecom Co. + +acpi:NRV*: + ID_VENDOR_FROM_DATABASE=Taugagreining hf + +acpi:NSC*: + ID_VENDOR_FROM_DATABASE=National Semiconductor Corporation + +acpi:NSI*: + ID_VENDOR_FROM_DATABASE=NISSEI ELECTRIC CO.,LTD + +acpi:NSP*: + ID_VENDOR_FROM_DATABASE=Nspire System Inc. + +acpi:NSS*: + ID_VENDOR_FROM_DATABASE=Newport Systems Solutions + +acpi:NST*: + ID_VENDOR_FROM_DATABASE=Network Security Technology Co + +acpi:NTC*: + ID_VENDOR_FROM_DATABASE=NeoTech S.R.L + +acpi:NTI*: + ID_VENDOR_FROM_DATABASE=New Tech Int'l Company + +acpi:NTL*: + ID_VENDOR_FROM_DATABASE=National Transcomm. Ltd + +acpi:NTN*: + ID_VENDOR_FROM_DATABASE=Nuvoton Technology Corporation + +acpi:NTR*: + ID_VENDOR_FROM_DATABASE=N-trig Innovative Technologies, Inc. + +acpi:NTS*: + ID_VENDOR_FROM_DATABASE=Nits Technology Inc. + +acpi:NTT*: + ID_VENDOR_FROM_DATABASE=NTT Advanced Technology Corporation + +acpi:NTW*: + ID_VENDOR_FROM_DATABASE=Networth Inc + +acpi:NTX*: + ID_VENDOR_FROM_DATABASE=Netaccess Inc + +acpi:NUG*: + ID_VENDOR_FROM_DATABASE=NU Technology, Inc. + +acpi:NUI*: + ID_VENDOR_FROM_DATABASE=NU Inc. + +acpi:NVC*: + ID_VENDOR_FROM_DATABASE=NetVision Corporation + +acpi:NVD*: + ID_VENDOR_FROM_DATABASE=Nvidia + +acpi:NVI*: + ID_VENDOR_FROM_DATABASE=NuVision US, Inc. + +acpi:NVL*: + ID_VENDOR_FROM_DATABASE=Novell Inc + +acpi:NVT*: + ID_VENDOR_FROM_DATABASE=Navatek Engineering Corporation + +acpi:NWC*: + ID_VENDOR_FROM_DATABASE=NW Computer Engineering + +acpi:NWP*: + ID_VENDOR_FROM_DATABASE=NovaWeb Technologies Inc + +acpi:NWS*: + ID_VENDOR_FROM_DATABASE=Newisys, Inc. + +acpi:NXC*: + ID_VENDOR_FROM_DATABASE=NextCom K.K. + +acpi:NXG*: + ID_VENDOR_FROM_DATABASE=Nexgen + +acpi:NXP*: + ID_VENDOR_FROM_DATABASE=NXP Semiconductors bv. + +acpi:NXQ*: + ID_VENDOR_FROM_DATABASE=Nexiq Technologies, Inc. + +acpi:NXS*: + ID_VENDOR_FROM_DATABASE=Technology Nexus Secure Open Systems AB + +acpi:NYC*: + ID_VENDOR_FROM_DATABASE=nakayo telecommunications,inc. + +acpi:OAK*: + ID_VENDOR_FROM_DATABASE=Oak Tech Inc + +acpi:OAS*: + ID_VENDOR_FROM_DATABASE=Oasys Technology Company + +acpi:OBS*: + ID_VENDOR_FROM_DATABASE=Optibase Technologies + +acpi:OCD*: + ID_VENDOR_FROM_DATABASE=Macraigor Systems Inc + +acpi:OCN*: + ID_VENDOR_FROM_DATABASE=Olfan + +acpi:OCS*: + ID_VENDOR_FROM_DATABASE=Open Connect Solutions + +acpi:ODM*: + ID_VENDOR_FROM_DATABASE=ODME Inc. + +acpi:ODR*: + ID_VENDOR_FROM_DATABASE=Odrac + +acpi:OEC*: + ID_VENDOR_FROM_DATABASE=ORION ELECTRIC CO.,LTD + +acpi:OEI*: + ID_VENDOR_FROM_DATABASE=Optum Engineering Inc. + +acpi:OIC*: + ID_VENDOR_FROM_DATABASE=Option Industrial Computers + +acpi:OIM*: + ID_VENDOR_FROM_DATABASE=Option International + +acpi:OIN*: + ID_VENDOR_FROM_DATABASE=Option International + +acpi:OKI*: + ID_VENDOR_FROM_DATABASE=OKI Electric Industrial Company Ltd + +acpi:OLC*: + ID_VENDOR_FROM_DATABASE=Olicom A/S + +acpi:OLD*: + ID_VENDOR_FROM_DATABASE=Olidata S.p.A. + +acpi:OLI*: + ID_VENDOR_FROM_DATABASE=Olivetti + +acpi:OLT*: + ID_VENDOR_FROM_DATABASE=Olitec S.A. + +acpi:OLV*: + ID_VENDOR_FROM_DATABASE=Olitec S.A. + +acpi:OLY*: + ID_VENDOR_FROM_DATABASE=OLYMPUS CORPORATION + +acpi:OMC*: + ID_VENDOR_FROM_DATABASE=OBJIX Multimedia Corporation + +acpi:OMN*: + ID_VENDOR_FROM_DATABASE=Omnitel + +acpi:OMR*: + ID_VENDOR_FROM_DATABASE=Omron Corporation + +acpi:ONE*: + ID_VENDOR_FROM_DATABASE=Oneac Corporation + +acpi:ONK*: + ID_VENDOR_FROM_DATABASE=ONKYO Corporation + +acpi:ONL*: + ID_VENDOR_FROM_DATABASE=OnLive, Inc + +acpi:ONS*: + ID_VENDOR_FROM_DATABASE=On Systems Inc + +acpi:ONW*: + ID_VENDOR_FROM_DATABASE=OPEN Networks Ltd + +acpi:ONX*: + ID_VENDOR_FROM_DATABASE=SOMELEC Z.I. Du Vert Galanta + +acpi:OOS*: + ID_VENDOR_FROM_DATABASE=OSRAM + +acpi:OPC*: + ID_VENDOR_FROM_DATABASE=Opcode Inc + +acpi:OPI*: + ID_VENDOR_FROM_DATABASE=D.N.S. Corporation + +acpi:OPP*: + ID_VENDOR_FROM_DATABASE=OPPO Digital, Inc. + +acpi:OPT*: + ID_VENDOR_FROM_DATABASE=OPTi Inc + +acpi:OPV*: + ID_VENDOR_FROM_DATABASE=Optivision Inc + +acpi:OQI*: + ID_VENDOR_FROM_DATABASE=Oksori Company Ltd + +acpi:ORG*: + ID_VENDOR_FROM_DATABASE=ORGA Kartensysteme GmbH + +acpi:ORI*: + ID_VENDOR_FROM_DATABASE=OSR Open Systems Resources, Inc. + +acpi:ORN*: + ID_VENDOR_FROM_DATABASE=ORION ELECTRIC CO., LTD. + +acpi:OSA*: + ID_VENDOR_FROM_DATABASE=OSAKA Micro Computer, Inc. + +acpi:OSP*: + ID_VENDOR_FROM_DATABASE=OPTI-UPS Corporation + +acpi:OSR*: + ID_VENDOR_FROM_DATABASE=Oksori Company Ltd + +acpi:OTB*: + ID_VENDOR_FROM_DATABASE=outsidetheboxstuff.com + +acpi:OTI*: + ID_VENDOR_FROM_DATABASE=Orchid Technology + +acpi:OTM*: + ID_VENDOR_FROM_DATABASE=Optoma Corporation           + +acpi:OTT*: + ID_VENDOR_FROM_DATABASE=OPTO22, Inc. + +acpi:OUK*: + ID_VENDOR_FROM_DATABASE=OUK Company Ltd + +acpi:OWL*: + ID_VENDOR_FROM_DATABASE=Mediacom Technologies Pte Ltd + +acpi:OXU*: + ID_VENDOR_FROM_DATABASE=Oxus Research S.A. + +acpi:OYO*: + ID_VENDOR_FROM_DATABASE=Shadow Systems + +acpi:OZC*: + ID_VENDOR_FROM_DATABASE=OZ Corporation + +acpi:OZO*: + ID_VENDOR_FROM_DATABASE=Tribe Computer Works Inc + +acpi:PAC*: + ID_VENDOR_FROM_DATABASE=Pacific Avionics Corporation + +acpi:PAD*: + ID_VENDOR_FROM_DATABASE=Promotion and Display Technology Ltd. + +acpi:PAK*: + ID_VENDOR_FROM_DATABASE=Many CNC System Co., Ltd. + +acpi:PAM*: + ID_VENDOR_FROM_DATABASE=Peter Antesberger Messtechnik + +acpi:PAN*: + ID_VENDOR_FROM_DATABASE=The Panda Project + +acpi:PAR*: + ID_VENDOR_FROM_DATABASE=Parallan Comp Inc + +acpi:PBI*: + ID_VENDOR_FROM_DATABASE=Pitney Bowes + +acpi:PBL*: + ID_VENDOR_FROM_DATABASE=Packard Bell Electronics + +acpi:PBN*: + ID_VENDOR_FROM_DATABASE=Packard Bell NEC + +acpi:PBV*: + ID_VENDOR_FROM_DATABASE=Pitney Bowes + +acpi:PCA*: + ID_VENDOR_FROM_DATABASE=Philips BU Add On Card + +acpi:PCB*: + ID_VENDOR_FROM_DATABASE=OCTAL S.A. + +acpi:PCC*: + ID_VENDOR_FROM_DATABASE=PowerCom Technology Company Ltd + +acpi:PCG*: + ID_VENDOR_FROM_DATABASE=First Industrial Computer Inc + +acpi:PCI*: + ID_VENDOR_FROM_DATABASE=Pioneer Computer Inc + +acpi:PCK*: + ID_VENDOR_FROM_DATABASE=PCBANK21 + +acpi:PCL*: + ID_VENDOR_FROM_DATABASE=pentel.co.,ltd + +acpi:PCM*: + ID_VENDOR_FROM_DATABASE=PCM Systems Corporation + +acpi:PCO*: + ID_VENDOR_FROM_DATABASE=Performance Concepts Inc., + +acpi:PCP*: + ID_VENDOR_FROM_DATABASE=Procomp USA Inc + +acpi:PCS*: + ID_VENDOR_FROM_DATABASE=TOSHIBA PERSONAL COMPUTER SYSTEM CORPRATION + +acpi:PCT*: + ID_VENDOR_FROM_DATABASE=PC-Tel Inc + +acpi:PCW*: + ID_VENDOR_FROM_DATABASE=Pacific CommWare Inc + +acpi:PCX*: + ID_VENDOR_FROM_DATABASE=PC Xperten + +acpi:PDM*: + ID_VENDOR_FROM_DATABASE=Psion Dacom Plc. + +acpi:PDN*: + ID_VENDOR_FROM_DATABASE=AT&T Paradyne + +acpi:PDR*: + ID_VENDOR_FROM_DATABASE=Pure Data Inc + +acpi:PDS*: + ID_VENDOR_FROM_DATABASE=PD Systems International Ltd + +acpi:PDT*: + ID_VENDOR_FROM_DATABASE=PDTS - Prozessdatentechnik und Systeme + +acpi:PDV*: + ID_VENDOR_FROM_DATABASE=Prodrive B.V. + +acpi:PEC*: + ID_VENDOR_FROM_DATABASE=POTRANS Electrical Corp. + +acpi:PEI*: + ID_VENDOR_FROM_DATABASE=PEI Electronics Inc + +acpi:PEL*: + ID_VENDOR_FROM_DATABASE=Primax Electric Ltd + +acpi:PEN*: + ID_VENDOR_FROM_DATABASE=Interactive Computer Products Inc + +acpi:PEP*: + ID_VENDOR_FROM_DATABASE=Peppercon AG + +acpi:PER*: + ID_VENDOR_FROM_DATABASE=Perceptive Signal Technologies + +acpi:PET*: + ID_VENDOR_FROM_DATABASE=Practical Electronic Tools + +acpi:PFT*: + ID_VENDOR_FROM_DATABASE=Telia ProSoft AB + +acpi:PGI*: + ID_VENDOR_FROM_DATABASE=PACSGEAR, Inc. + +acpi:PGM*: + ID_VENDOR_FROM_DATABASE=Paradigm Advanced Research Centre + +acpi:PGP*: + ID_VENDOR_FROM_DATABASE=propagamma kommunikation + +acpi:PGS*: + ID_VENDOR_FROM_DATABASE=Princeton Graphic Systems + +acpi:PHC*: + ID_VENDOR_FROM_DATABASE=Pijnenburg Beheer N.V. + +acpi:PHE*: + ID_VENDOR_FROM_DATABASE=Philips Medical Systems Boeblingen GmbH + +acpi:PHL*: + ID_VENDOR_FROM_DATABASE=Philips Consumer Electronics Company + +acpi:PHO*: + ID_VENDOR_FROM_DATABASE=Photonics Systems Inc. + +acpi:PHS*: + ID_VENDOR_FROM_DATABASE=Philips Communication Systems + +acpi:PHY*: + ID_VENDOR_FROM_DATABASE=Phylon Communications + +acpi:PIE*: + ID_VENDOR_FROM_DATABASE=Pacific Image Electronics Company Ltd + +acpi:PIM*: + ID_VENDOR_FROM_DATABASE=Prism, LLC + +acpi:PIO*: + ID_VENDOR_FROM_DATABASE=Pioneer Electronic Corporation + +acpi:PIX*: + ID_VENDOR_FROM_DATABASE=Pixie Tech Inc + +acpi:PJA*: + ID_VENDOR_FROM_DATABASE=Projecta + +acpi:PJD*: + ID_VENDOR_FROM_DATABASE=Projectiondesign AS + +acpi:PJT*: + ID_VENDOR_FROM_DATABASE=Pan Jit International Inc. + +acpi:PKA*: + ID_VENDOR_FROM_DATABASE=Acco UK ltd. + +acpi:PLC*: + ID_VENDOR_FROM_DATABASE=Pro-Log Corporation + +acpi:PLF*: + ID_VENDOR_FROM_DATABASE=Panasonic Avionics Corporation + +acpi:PLM*: + ID_VENDOR_FROM_DATABASE=PROLINK Microsystems Corp. + +acpi:PLT*: + ID_VENDOR_FROM_DATABASE=PT Hartono Istana Teknologi + +acpi:PLV*: + ID_VENDOR_FROM_DATABASE=PLUS Vision Corp. + +acpi:PLX*: + ID_VENDOR_FROM_DATABASE=Parallax Graphics + +acpi:PLY*: + ID_VENDOR_FROM_DATABASE=Polycom Inc. + +acpi:PMC*: + ID_VENDOR_FROM_DATABASE=PMC Consumer Electronics Ltd + +acpi:PMD*: + ID_VENDOR_FROM_DATABASE=TDK USA Corporation + +acpi:PMM*: + ID_VENDOR_FROM_DATABASE=Point Multimedia System + +acpi:PMT*: + ID_VENDOR_FROM_DATABASE=Promate Electronic Co., Ltd. + +acpi:PMX*: + ID_VENDOR_FROM_DATABASE=Photomatrix + +acpi:PNG*: + ID_VENDOR_FROM_DATABASE=Microsoft + +acpi:PNL*: + ID_VENDOR_FROM_DATABASE=Panelview, Inc. + +acpi:PNR*: + ID_VENDOR_FROM_DATABASE=Planar Systems, Inc. + +acpi:PNS*: + ID_VENDOR_FROM_DATABASE=PanaScope + +acpi:PNX*: + ID_VENDOR_FROM_DATABASE=Phoenix Technologies, Ltd. + +acpi:POL*: + ID_VENDOR_FROM_DATABASE=PolyComp (PTY) Ltd. + +acpi:PON*: + ID_VENDOR_FROM_DATABASE=Perpetual Technologies, LLC + +acpi:POR*: + ID_VENDOR_FROM_DATABASE=Portalis LC + +acpi:PPC*: + ID_VENDOR_FROM_DATABASE=Phoenixtec Power Company Ltd + +acpi:PPD*: + ID_VENDOR_FROM_DATABASE=MEPhI + +acpi:PPI*: + ID_VENDOR_FROM_DATABASE=Practical Peripherals + +acpi:PPM*: + ID_VENDOR_FROM_DATABASE=Clinton Electronics Corp. + +acpi:PPP*: + ID_VENDOR_FROM_DATABASE=Purup Prepress AS + +acpi:PPR*: + ID_VENDOR_FROM_DATABASE=PicPro + +acpi:PPX*: + ID_VENDOR_FROM_DATABASE=Perceptive Pixel Inc. + +acpi:PQI*: + ID_VENDOR_FROM_DATABASE=Pixel Qi + +acpi:PRA*: + ID_VENDOR_FROM_DATABASE=PRO/AUTOMATION + +acpi:PRC*: + ID_VENDOR_FROM_DATABASE=PerComm + +acpi:PRD*: + ID_VENDOR_FROM_DATABASE=Praim S.R.L. + +acpi:PRF*: + ID_VENDOR_FROM_DATABASE=Digital Electronics Corporation + +acpi:PRG*: + ID_VENDOR_FROM_DATABASE=The Phoenix Research Group Inc + +acpi:PRI*: + ID_VENDOR_FROM_DATABASE=Priva Hortimation BV + +acpi:PRM*: + ID_VENDOR_FROM_DATABASE=Prometheus + +acpi:PRO*: + ID_VENDOR_FROM_DATABASE=Proteon + +acpi:PRS*: + ID_VENDOR_FROM_DATABASE=Leutron Vision + +acpi:PRT*: + ID_VENDOR_FROM_DATABASE=Parade Technologies, Ltd. + +acpi:PRX*: + ID_VENDOR_FROM_DATABASE=Proxima Corporation + +acpi:PSA*: + ID_VENDOR_FROM_DATABASE=Advanced Signal Processing Technologies + +acpi:PSC*: + ID_VENDOR_FROM_DATABASE=Philips Semiconductors + +acpi:PSD*: + ID_VENDOR_FROM_DATABASE=Peus-Systems GmbH + +acpi:PSE*: + ID_VENDOR_FROM_DATABASE=Practical Solutions Pte., Ltd. + +acpi:PSI*: + ID_VENDOR_FROM_DATABASE=PSI-Perceptive Solutions Inc + +acpi:PSL*: + ID_VENDOR_FROM_DATABASE=Perle Systems Limited + +acpi:PSM*: + ID_VENDOR_FROM_DATABASE=Prosum + +acpi:PST*: + ID_VENDOR_FROM_DATABASE=Global Data SA + +acpi:PTA*: + ID_VENDOR_FROM_DATABASE=PAR Tech Inc. + +acpi:PTC*: + ID_VENDOR_FROM_DATABASE=PS Technology Corporation + +acpi:PTG*: + ID_VENDOR_FROM_DATABASE=Cipher Systems Inc + +acpi:PTH*: + ID_VENDOR_FROM_DATABASE=Pathlight Technology Inc + +acpi:PTI*: + ID_VENDOR_FROM_DATABASE=Promise Technology Inc + +acpi:PTL*: + ID_VENDOR_FROM_DATABASE=Pantel Inc + +acpi:PTS*: + ID_VENDOR_FROM_DATABASE=Plain Tree Systems Inc + +acpi:PVG*: + ID_VENDOR_FROM_DATABASE=Proview Global Co., Ltd + +acpi:PVI*: + ID_VENDOR_FROM_DATABASE=Prime view international Co., Ltd + +acpi:PVM*: + ID_VENDOR_FROM_DATABASE=Penta Studiotechnik GmbH + +acpi:PVN*: + ID_VENDOR_FROM_DATABASE=Pixel Vision + +acpi:PVP*: + ID_VENDOR_FROM_DATABASE=Klos Technologies, Inc. + +acpi:PXC*: + ID_VENDOR_FROM_DATABASE=Phoenix Contact + +acpi:PXE*: + ID_VENDOR_FROM_DATABASE=PIXELA CORPORATION + +acpi:PXL*: + ID_VENDOR_FROM_DATABASE=The Moving Pixel Company + +acpi:PXM*: + ID_VENDOR_FROM_DATABASE=Proxim Inc + +acpi:QCC*: + ID_VENDOR_FROM_DATABASE=QuakeCom Company Ltd + +acpi:QCH*: + ID_VENDOR_FROM_DATABASE=Metronics Inc + +acpi:QCI*: + ID_VENDOR_FROM_DATABASE=Quanta Computer Inc + +acpi:QCK*: + ID_VENDOR_FROM_DATABASE=Quick Corporation + +acpi:QCL*: + ID_VENDOR_FROM_DATABASE=Quadrant Components Inc + +acpi:QCP*: + ID_VENDOR_FROM_DATABASE=Qualcomm Inc + +acpi:QDI*: + ID_VENDOR_FROM_DATABASE=Quantum Data Incorporated + +acpi:QDM*: + ID_VENDOR_FROM_DATABASE=Quadram + +acpi:QDS*: + ID_VENDOR_FROM_DATABASE=Quanta Display Inc. + +acpi:QFF*: + ID_VENDOR_FROM_DATABASE=Padix Co., Inc. + +acpi:QFI*: + ID_VENDOR_FROM_DATABASE=Quickflex, Inc + +acpi:QLC*: + ID_VENDOR_FROM_DATABASE=Q-Logic + +acpi:QQQ*: + ID_VENDOR_FROM_DATABASE=Chuomusen Co., Ltd. + +acpi:QSI*: + ID_VENDOR_FROM_DATABASE=Quantum Solutions, Inc. + +acpi:QTD*: + ID_VENDOR_FROM_DATABASE=Quantum 3D Inc + +acpi:QTH*: + ID_VENDOR_FROM_DATABASE=Questech Ltd + +acpi:QTI*: + ID_VENDOR_FROM_DATABASE=Quicknet Technologies Inc + +acpi:QTM*: + ID_VENDOR_FROM_DATABASE=Quantum + +acpi:QTR*: + ID_VENDOR_FROM_DATABASE=Qtronix Corporation + +acpi:QUA*: + ID_VENDOR_FROM_DATABASE=Quatographic AG + +acpi:QUE*: + ID_VENDOR_FROM_DATABASE=Questra Consulting + +acpi:QVU*: + ID_VENDOR_FROM_DATABASE=Quartics + +acpi:RAC*: + ID_VENDOR_FROM_DATABASE=Racore Computer Products Inc + +acpi:RAD*: + ID_VENDOR_FROM_DATABASE=Radisys Corporation + +acpi:RAI*: + ID_VENDOR_FROM_DATABASE=Rockwell Automation/Intecolor + +acpi:RAN*: + ID_VENDOR_FROM_DATABASE=Rancho Tech Inc + +acpi:RAR*: + ID_VENDOR_FROM_DATABASE=Raritan, Inc. + +acpi:RAS*: + ID_VENDOR_FROM_DATABASE=RAScom Inc + +acpi:RAT*: + ID_VENDOR_FROM_DATABASE=Rent-A-Tech + +acpi:RAY*: + ID_VENDOR_FROM_DATABASE=Raylar Design, Inc. + +acpi:RCE*: + ID_VENDOR_FROM_DATABASE=Parc d'Activite des Bellevues + +acpi:RCH*: + ID_VENDOR_FROM_DATABASE=Reach Technology Inc + +acpi:RCI*: + ID_VENDOR_FROM_DATABASE=RC International + +acpi:RCN*: + ID_VENDOR_FROM_DATABASE=Radio Consult SRL + +acpi:RCO*: + ID_VENDOR_FROM_DATABASE=Rockwell Collins + +acpi:RDI*: + ID_VENDOR_FROM_DATABASE=Rainbow Displays, Inc. + +acpi:RDM*: + ID_VENDOR_FROM_DATABASE=Tremon Enterprises Company Ltd + +acpi:RDN*: + ID_VENDOR_FROM_DATABASE=RADIODATA GmbH + +acpi:RDS*: + ID_VENDOR_FROM_DATABASE=Radius Inc + +acpi:REA*: + ID_VENDOR_FROM_DATABASE=Real D + +acpi:REC*: + ID_VENDOR_FROM_DATABASE=ReCom + +acpi:RED*: + ID_VENDOR_FROM_DATABASE=Research Electronics Development Inc + +acpi:REF*: + ID_VENDOR_FROM_DATABASE=Reflectivity, Inc. + +acpi:REH*: + ID_VENDOR_FROM_DATABASE=Rehan Electronics Ltd. + +acpi:REL*: + ID_VENDOR_FROM_DATABASE=Reliance Electric Ind Corporation + +acpi:REM*: + ID_VENDOR_FROM_DATABASE=SCI Systems Inc. + +acpi:REN*: + ID_VENDOR_FROM_DATABASE=Renesas Technology Corp. + +acpi:RES*: + ID_VENDOR_FROM_DATABASE=ResMed Pty Ltd + +acpi:RET*: + ID_VENDOR_FROM_DATABASE=Resonance Technology, Inc. + +acpi:REX*: + ID_VENDOR_FROM_DATABASE=RATOC Systems, Inc. + +acpi:RGL*: + ID_VENDOR_FROM_DATABASE=Robertson Geologging Ltd + +acpi:RHD*: + ID_VENDOR_FROM_DATABASE=RightHand Technologies + +acpi:RHM*: + ID_VENDOR_FROM_DATABASE=Rohm Company Ltd + +acpi:RHT*: + ID_VENDOR_FROM_DATABASE=Red Hat, Inc. + +acpi:RIC*: + ID_VENDOR_FROM_DATABASE=RICOH COMPANY, LTD. + +acpi:RII*: + ID_VENDOR_FROM_DATABASE=Racal Interlan Inc + +acpi:RIO*: + ID_VENDOR_FROM_DATABASE=Rios Systems Company Ltd + +acpi:RIT*: + ID_VENDOR_FROM_DATABASE=Ritech Inc + +acpi:RIV*: + ID_VENDOR_FROM_DATABASE=Rivulet Communications + +acpi:RJA*: + ID_VENDOR_FROM_DATABASE=Roland Corporation + +acpi:RJS*: + ID_VENDOR_FROM_DATABASE=Advanced Engineering + +acpi:RKC*: + ID_VENDOR_FROM_DATABASE=Reakin Technolohy Corporation + +acpi:RLD*: + ID_VENDOR_FROM_DATABASE=MEPCO + +acpi:RLN*: + ID_VENDOR_FROM_DATABASE=RadioLAN Inc + +acpi:RMC*: + ID_VENDOR_FROM_DATABASE=Raritan Computer, Inc + +acpi:RMP*: + ID_VENDOR_FROM_DATABASE=Research Machines + +acpi:RMT*: + ID_VENDOR_FROM_DATABASE=Roper Mobile + +acpi:RNB*: + ID_VENDOR_FROM_DATABASE=Rainbow Technologies + +acpi:ROB*: + ID_VENDOR_FROM_DATABASE=Robust Electronics GmbH + +acpi:ROH*: + ID_VENDOR_FROM_DATABASE=Rohm Co., Ltd. + +acpi:ROK*: + ID_VENDOR_FROM_DATABASE=Rockwell International + +acpi:ROP*: + ID_VENDOR_FROM_DATABASE=Roper International Ltd + +acpi:ROS*: + ID_VENDOR_FROM_DATABASE=Rohde & Schwarz + +acpi:RPI*: + ID_VENDOR_FROM_DATABASE=RoomPro Technologies + +acpi:RPT*: + ID_VENDOR_FROM_DATABASE=R.P.T.Intergroups + +acpi:RRI*: + ID_VENDOR_FROM_DATABASE=Radicom Research Inc + +acpi:RSC*: + ID_VENDOR_FROM_DATABASE=PhotoTelesis + +acpi:RSH*: + ID_VENDOR_FROM_DATABASE=ADC-Centre + +acpi:RSI*: + ID_VENDOR_FROM_DATABASE=Rampage Systems Inc + +acpi:RSN*: + ID_VENDOR_FROM_DATABASE=Radiospire Networks, Inc. + +acpi:RSQ*: + ID_VENDOR_FROM_DATABASE=R Squared + +acpi:RSS*: + ID_VENDOR_FROM_DATABASE=Rockwell Semiconductor Systems + +acpi:RSV*: + ID_VENDOR_FROM_DATABASE=Ross Video Ltd + +acpi:RSX*: + ID_VENDOR_FROM_DATABASE=Rapid Tech Corporation + +acpi:RTC*: + ID_VENDOR_FROM_DATABASE=Relia Technologies + +acpi:RTI*: + ID_VENDOR_FROM_DATABASE=Rancho Tech Inc + +acpi:RTL*: + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Company Ltd + +acpi:RTS*: + ID_VENDOR_FROM_DATABASE=Raintree Systems + +acpi:RUN*: + ID_VENDOR_FROM_DATABASE=RUNCO International + +acpi:RUP*: + ID_VENDOR_FROM_DATABASE=Ups Manufactoring s.r.l. + +acpi:RVC*: + ID_VENDOR_FROM_DATABASE=RSI Systems Inc + +acpi:RVI*: + ID_VENDOR_FROM_DATABASE=Realvision Inc + +acpi:RVL*: + ID_VENDOR_FROM_DATABASE=Reveal Computer Prod + +acpi:RWC*: + ID_VENDOR_FROM_DATABASE=Red Wing Corporation + +acpi:RXT*: + ID_VENDOR_FROM_DATABASE=Tectona SoftSolutions (P) Ltd., + +acpi:SAA*: + ID_VENDOR_FROM_DATABASE=Sanritz Automation Co.,Ltd. + +acpi:SAE*: + ID_VENDOR_FROM_DATABASE=Saab Aerotech + +acpi:SAG*: + ID_VENDOR_FROM_DATABASE=Sedlbauer + +acpi:SAI*: + ID_VENDOR_FROM_DATABASE=Sage Inc + +acpi:SAK*: + ID_VENDOR_FROM_DATABASE=Saitek Ltd + +acpi:SAM*: + ID_VENDOR_FROM_DATABASE=Samsung Electric Company + +acpi:SAN*: + ID_VENDOR_FROM_DATABASE=Sanyo Electric Co.,Ltd. + +acpi:SAS*: + ID_VENDOR_FROM_DATABASE=Stores Automated Systems Inc + +acpi:SAT*: + ID_VENDOR_FROM_DATABASE=Shuttle Tech + +acpi:SBC*: + ID_VENDOR_FROM_DATABASE=Shanghai Bell Telephone Equip Mfg Co + +acpi:SBD*: + ID_VENDOR_FROM_DATABASE=Softbed - Consulting & Development Ltd + +acpi:SBI*: + ID_VENDOR_FROM_DATABASE=SMART Technologies Inc. + +acpi:SBS*: + ID_VENDOR_FROM_DATABASE=SBS-or Industrial Computers GmbH + +acpi:SBT*: + ID_VENDOR_FROM_DATABASE=Senseboard Technologies AB + +acpi:SCC*: + ID_VENDOR_FROM_DATABASE=SORD Computer Corporation + +acpi:SCD*: + ID_VENDOR_FROM_DATABASE=Sanyo Electric Company Ltd + +acpi:SCE*: + ID_VENDOR_FROM_DATABASE=Sun Corporation + +acpi:SCH*: + ID_VENDOR_FROM_DATABASE=Schlumberger Cards + +acpi:SCI*: + ID_VENDOR_FROM_DATABASE=System Craft + +acpi:SCL*: + ID_VENDOR_FROM_DATABASE=Sigmacom Co., Ltd. + +acpi:SCM*: + ID_VENDOR_FROM_DATABASE=SCM Microsystems Inc + +acpi:SCN*: + ID_VENDOR_FROM_DATABASE=Scanport, Inc. + +acpi:SCO*: + ID_VENDOR_FROM_DATABASE=SORCUS Computer GmbH + +acpi:SCP*: + ID_VENDOR_FROM_DATABASE=Scriptel Corporation + +acpi:SCR*: + ID_VENDOR_FROM_DATABASE=Systran Corporation + +acpi:SCS*: + ID_VENDOR_FROM_DATABASE=Nanomach Anstalt + +acpi:SCT*: + ID_VENDOR_FROM_DATABASE=Smart Card Technology + +acpi:SDA*: + ID_VENDOR_FROM_DATABASE=SAT (Societe Anonyme) + +acpi:SDD*: + ID_VENDOR_FROM_DATABASE=Intrada-SDD Ltd + +acpi:SDE*: + ID_VENDOR_FROM_DATABASE=Sherwood Digital Electronics Corporation + +acpi:SDF*: + ID_VENDOR_FROM_DATABASE=SODIFF E&T CO., Ltd. + +acpi:SDH*: + ID_VENDOR_FROM_DATABASE=Communications Specialies, Inc. + +acpi:SDI*: + ID_VENDOR_FROM_DATABASE=Samtron Displays Inc + +acpi:SDK*: + ID_VENDOR_FROM_DATABASE=SAIT-Devlonics + +acpi:SDR*: + ID_VENDOR_FROM_DATABASE=SDR Systems + +acpi:SDS*: + ID_VENDOR_FROM_DATABASE=SunRiver Data System + +acpi:SDT*: + ID_VENDOR_FROM_DATABASE=Siemens AG + +acpi:SDX*: + ID_VENDOR_FROM_DATABASE=SDX Business Systems Ltd + +acpi:SEA*: + ID_VENDOR_FROM_DATABASE=Seanix Technology Inc. + +acpi:SEB*: + ID_VENDOR_FROM_DATABASE=system elektronik GmbH + +acpi:SEC*: + ID_VENDOR_FROM_DATABASE=Seiko Epson Corporation + +acpi:SEE*: + ID_VENDOR_FROM_DATABASE=SeeColor Corporation + +acpi:SEI*: + ID_VENDOR_FROM_DATABASE=Seitz & Associates Inc + +acpi:SEL*: + ID_VENDOR_FROM_DATABASE=Way2Call Communications + +acpi:SEM*: + ID_VENDOR_FROM_DATABASE=Samsung Electronics Company Ltd + +acpi:SEN*: + ID_VENDOR_FROM_DATABASE=Sencore + +acpi:SEO*: + ID_VENDOR_FROM_DATABASE=SEOS Ltd + +acpi:SEP*: + ID_VENDOR_FROM_DATABASE=SEP Eletronica Ltda. + +acpi:SER*: + ID_VENDOR_FROM_DATABASE=Sony Ericsson Mobile Communications Inc. + +acpi:SES*: + ID_VENDOR_FROM_DATABASE=Session Control LLC + +acpi:SET*: + ID_VENDOR_FROM_DATABASE=SendTek Corporation + +acpi:SFM*: + ID_VENDOR_FROM_DATABASE=TORNADO Company + +acpi:SFT*: + ID_VENDOR_FROM_DATABASE=Mikroforum Ring 3 + +acpi:SGC*: + ID_VENDOR_FROM_DATABASE=Spectragraphics Corporation + +acpi:SGD*: + ID_VENDOR_FROM_DATABASE=Sigma Designs, Inc. + +acpi:SGE*: + ID_VENDOR_FROM_DATABASE=Kansai Electric Company Ltd + +acpi:SGI*: + ID_VENDOR_FROM_DATABASE=Scan Group Ltd + +acpi:SGL*: + ID_VENDOR_FROM_DATABASE=Super Gate Technology Company Ltd + +acpi:SGM*: + ID_VENDOR_FROM_DATABASE=SAGEM + +acpi:SGO*: + ID_VENDOR_FROM_DATABASE=Logos Design A/S + +acpi:SGT*: + ID_VENDOR_FROM_DATABASE=Stargate Technology + +acpi:SGW*: + ID_VENDOR_FROM_DATABASE=Shanghai Guowei Science and Technology Co., Ltd. + +acpi:SGX*: + ID_VENDOR_FROM_DATABASE=Silicon Graphics Inc + +acpi:SGZ*: + ID_VENDOR_FROM_DATABASE=Systec Computer GmbH + +acpi:SHC*: + ID_VENDOR_FROM_DATABASE=ShibaSoku Co., Ltd. + +acpi:SHG*: + ID_VENDOR_FROM_DATABASE=Soft & Hardware development Goldammer GmbH + +acpi:SHI*: + ID_VENDOR_FROM_DATABASE=Jiangsu Shinco Electronic Group Co., Ltd + +acpi:SHP*: + ID_VENDOR_FROM_DATABASE=Sharp Corporation + +acpi:SHR*: + ID_VENDOR_FROM_DATABASE=Digital Discovery + +acpi:SHT*: + ID_VENDOR_FROM_DATABASE=Shin Ho Tech + +acpi:SIA*: + ID_VENDOR_FROM_DATABASE=SIEMENS AG + +acpi:SIB*: + ID_VENDOR_FROM_DATABASE=Sanyo Electric Company Ltd + +acpi:SIC*: + ID_VENDOR_FROM_DATABASE=Sysmate Corporation + +acpi:SID*: + ID_VENDOR_FROM_DATABASE=Seiko Instruments Information Devices Inc + +acpi:SIE*: + ID_VENDOR_FROM_DATABASE=Siemens + +acpi:SIG*: + ID_VENDOR_FROM_DATABASE=Sigma Designs Inc + +acpi:SII*: + ID_VENDOR_FROM_DATABASE=Silicon Image, Inc. + +acpi:SIL*: + ID_VENDOR_FROM_DATABASE=Silicon Laboratories, Inc + +acpi:SIM*: + ID_VENDOR_FROM_DATABASE=S3 Inc + +acpi:SIN*: + ID_VENDOR_FROM_DATABASE=Singular Technology Co., Ltd. + +acpi:SIR*: + ID_VENDOR_FROM_DATABASE=Sirius Technologies Pty Ltd + +acpi:SIS*: + ID_VENDOR_FROM_DATABASE=Silicon Integrated Systems Corporation + +acpi:SIT*: + ID_VENDOR_FROM_DATABASE=Sitintel + +acpi:SIU*: + ID_VENDOR_FROM_DATABASE=Seiko Instruments USA Inc + +acpi:SIX*: + ID_VENDOR_FROM_DATABASE=Zuniq Data Corporation + +acpi:SJE*: + ID_VENDOR_FROM_DATABASE=Sejin Electron Inc + +acpi:SKD*: + ID_VENDOR_FROM_DATABASE=Schneider & Koch + +acpi:SKT*: + ID_VENDOR_FROM_DATABASE=Samsung Electro-Mechanics Company Ltd + +acpi:SKY*: + ID_VENDOR_FROM_DATABASE=SKYDATA S.P.A. + +acpi:SLA*: + ID_VENDOR_FROM_DATABASE=Systeme Lauer GmbH&Co KG + +acpi:SLB*: + ID_VENDOR_FROM_DATABASE=Shlumberger Ltd + +acpi:SLC*: + ID_VENDOR_FROM_DATABASE=Syslogic Datentechnik AG + +acpi:SLF*: + ID_VENDOR_FROM_DATABASE=StarLeaf + +acpi:SLH*: + ID_VENDOR_FROM_DATABASE=Silicon Library Inc. + +acpi:SLI*: + ID_VENDOR_FROM_DATABASE=Symbios Logic Inc + +acpi:SLK*: + ID_VENDOR_FROM_DATABASE=Silitek Corporation + +acpi:SLM*: + ID_VENDOR_FROM_DATABASE=Solomon Technology Corporation + +acpi:SLR*: + ID_VENDOR_FROM_DATABASE=Schlumberger Technology Corporate + +acpi:SLS*: + ID_VENDOR_FROM_DATABASE=Schnick-Schnack-Systems GmbH + +acpi:SLT*: + ID_VENDOR_FROM_DATABASE=Salt Internatioinal Corp. + +acpi:SLX*: + ID_VENDOR_FROM_DATABASE=Specialix + +acpi:SMA*: + ID_VENDOR_FROM_DATABASE=SMART Modular Technologies + +acpi:SMB*: + ID_VENDOR_FROM_DATABASE=Schlumberger + +acpi:SMC*: + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corporation + +acpi:SME*: + ID_VENDOR_FROM_DATABASE=Sysmate Company + +acpi:SMI*: + ID_VENDOR_FROM_DATABASE=SpaceLabs Medical Inc + +acpi:SMK*: + ID_VENDOR_FROM_DATABASE=SMK CORPORATION + +acpi:SML*: + ID_VENDOR_FROM_DATABASE=Sumitomo Metal Industries, Ltd. + +acpi:SMM*: + ID_VENDOR_FROM_DATABASE=Shark Multimedia Inc + +acpi:SMO*: + ID_VENDOR_FROM_DATABASE=STMicroelectronics + +acpi:SMP*: + ID_VENDOR_FROM_DATABASE=Simple Computing + +acpi:SMR*: + ID_VENDOR_FROM_DATABASE=B.& V. s.r.l. + +acpi:SMS*: + ID_VENDOR_FROM_DATABASE=Silicom Multimedia Systems Inc + +acpi:SMT*: + ID_VENDOR_FROM_DATABASE=Silcom Manufacturing Tech Inc + +acpi:SNC*: + ID_VENDOR_FROM_DATABASE=Sentronic International Corp. + +acpi:SNI*: + ID_VENDOR_FROM_DATABASE=Siemens Microdesign GmbH + +acpi:SNK*: + ID_VENDOR_FROM_DATABASE=S&K Electronics + +acpi:SNO*: + ID_VENDOR_FROM_DATABASE=SINOSUN TECHNOLOGY CO., LTD + +acpi:SNP*: + ID_VENDOR_FROM_DATABASE=Siemens Nixdorf Info Systems + +acpi:SNS*: + ID_VENDOR_FROM_DATABASE=Cirtech (UK) Ltd + +acpi:SNT*: + ID_VENDOR_FROM_DATABASE=SuperNet Inc + +acpi:SNW*: + ID_VENDOR_FROM_DATABASE=Snell & Wilcox + +acpi:SNX*: + ID_VENDOR_FROM_DATABASE=Sonix Comm. Ltd + +acpi:SNY*: + ID_VENDOR_FROM_DATABASE=Sony + +acpi:SOI*: + ID_VENDOR_FROM_DATABASE=Silicon Optix Corporation + +acpi:SOL*: + ID_VENDOR_FROM_DATABASE=Solitron Technologies Inc + +acpi:SON*: + ID_VENDOR_FROM_DATABASE=Sony + +acpi:SOR*: + ID_VENDOR_FROM_DATABASE=Sorcus Computer GmbH + +acpi:SOT*: + ID_VENDOR_FROM_DATABASE=Sotec Company Ltd + +acpi:SOY*: + ID_VENDOR_FROM_DATABASE=SOYO Group, Inc + +acpi:SPC*: + ID_VENDOR_FROM_DATABASE=SpinCore Technologies, Inc + +acpi:SPE*: + ID_VENDOR_FROM_DATABASE=SPEA Software AG + +acpi:SPH*: + ID_VENDOR_FROM_DATABASE=G&W Instruments GmbH + +acpi:SPI*: + ID_VENDOR_FROM_DATABASE=SPACE-I Co., Ltd. + +acpi:SPK*: + ID_VENDOR_FROM_DATABASE=SpeakerCraft + +acpi:SPL*: + ID_VENDOR_FROM_DATABASE=Smart Silicon Systems Pty Ltd + +acpi:SPN*: + ID_VENDOR_FROM_DATABASE=Sapience Corporation + +acpi:SPR*: + ID_VENDOR_FROM_DATABASE=pmns GmbH + +acpi:SPS*: + ID_VENDOR_FROM_DATABASE=Synopsys Inc + +acpi:SPT*: + ID_VENDOR_FROM_DATABASE=Sceptre Tech Inc + +acpi:SPU*: + ID_VENDOR_FROM_DATABASE=SIM2 Multimedia S.P.A. + +acpi:SPX*: + ID_VENDOR_FROM_DATABASE=Simplex Time Recorder Co. + +acpi:SQT*: + ID_VENDOR_FROM_DATABASE=Sequent Computer Systems Inc + +acpi:SRC*: + ID_VENDOR_FROM_DATABASE=Integrated Tech Express Inc + +acpi:SRD*: + ID_VENDOR_FROM_DATABASE=Setred + +acpi:SRF*: + ID_VENDOR_FROM_DATABASE=Surf Communication Solutions Ltd + +acpi:SRG*: + ID_VENDOR_FROM_DATABASE=Intuitive Surgical, Inc. + +acpi:SRT*: + ID_VENDOR_FROM_DATABASE=SeeReal Technologies GmbH + +acpi:SSC*: + ID_VENDOR_FROM_DATABASE=Sierra Semiconductor Inc + +acpi:SSD*: + ID_VENDOR_FROM_DATABASE=FlightSafety International + +acpi:SSE*: + ID_VENDOR_FROM_DATABASE=Samsung Electronic Co. + +acpi:SSI*: + ID_VENDOR_FROM_DATABASE=S-S Technology Inc + +acpi:SSJ*: + ID_VENDOR_FROM_DATABASE=Sankyo Seiki Mfg.co., Ltd + +acpi:SSP*: + ID_VENDOR_FROM_DATABASE=Spectrum Signal Proecessing Inc + +acpi:SSS*: + ID_VENDOR_FROM_DATABASE=S3 Inc + +acpi:SST*: + ID_VENDOR_FROM_DATABASE=SystemSoft Corporation + +acpi:STA*: + ID_VENDOR_FROM_DATABASE=ST Electronics Systems Assembly Pte Ltd + +acpi:STB*: + ID_VENDOR_FROM_DATABASE=STB Systems Inc + +acpi:STC*: + ID_VENDOR_FROM_DATABASE=STAC Electronics + +acpi:STD*: + ID_VENDOR_FROM_DATABASE=STD Computer Inc + +acpi:STE*: + ID_VENDOR_FROM_DATABASE=SII Ido-Tsushin Inc + +acpi:STF*: + ID_VENDOR_FROM_DATABASE=Starflight Electronics + +acpi:STG*: + ID_VENDOR_FROM_DATABASE=StereoGraphics Corp. + +acpi:STH*: + ID_VENDOR_FROM_DATABASE=Semtech Corporation + +acpi:STI*: + ID_VENDOR_FROM_DATABASE=Smart Tech Inc + +acpi:STK*: + ID_VENDOR_FROM_DATABASE=SANTAK CORP. + +acpi:STL*: + ID_VENDOR_FROM_DATABASE=SigmaTel Inc + +acpi:STM*: + ID_VENDOR_FROM_DATABASE=SGS Thomson Microelectronics + +acpi:STN*: + ID_VENDOR_FROM_DATABASE=Samsung Electronics America + +acpi:STO*: + ID_VENDOR_FROM_DATABASE=Stollmann E+V GmbH + +acpi:STP*: + ID_VENDOR_FROM_DATABASE=StreamPlay Ltd + +acpi:STR*: + ID_VENDOR_FROM_DATABASE=Starlight Networks Inc + +acpi:STS*: + ID_VENDOR_FROM_DATABASE=SITECSYSTEM CO., LTD. + +acpi:STT*: + ID_VENDOR_FROM_DATABASE=Star Paging Telecom Tech (Shenzhen) Co. Ltd. + +acpi:STU*: + ID_VENDOR_FROM_DATABASE=Sentelic Corporation + +acpi:STW*: + ID_VENDOR_FROM_DATABASE=Starwin Inc. + +acpi:STX*: + ID_VENDOR_FROM_DATABASE=ST-Ericsson + +acpi:STY*: + ID_VENDOR_FROM_DATABASE=SDS Technologies + +acpi:SUB*: + ID_VENDOR_FROM_DATABASE=Subspace Comm. Inc + +acpi:SUM*: + ID_VENDOR_FROM_DATABASE=Summagraphics Corporation + +acpi:SUN*: + ID_VENDOR_FROM_DATABASE=Sun Electronics Corporation + +acpi:SUP*: + ID_VENDOR_FROM_DATABASE=Supra Corporation + +acpi:SUR*: + ID_VENDOR_FROM_DATABASE=Surenam Computer Corporation + +acpi:SVA*: + ID_VENDOR_FROM_DATABASE=SGEG + +acpi:SVC*: + ID_VENDOR_FROM_DATABASE=Intellix Corp. + +acpi:SVD*: + ID_VENDOR_FROM_DATABASE=SVD Computer + +acpi:SVI*: + ID_VENDOR_FROM_DATABASE=Sun Microsystems + +acpi:SVS*: + ID_VENDOR_FROM_DATABASE=SVSI + +acpi:SVT*: + ID_VENDOR_FROM_DATABASE=SEVIT Co., Ltd. + +acpi:SWC*: + ID_VENDOR_FROM_DATABASE=Software Café + +acpi:SWI*: + ID_VENDOR_FROM_DATABASE=Sierra Wireless Inc. + +acpi:SWL*: + ID_VENDOR_FROM_DATABASE=Sharedware Ltd + +acpi:SWS*: + ID_VENDOR_FROM_DATABASE=Static + +acpi:SWT*: + ID_VENDOR_FROM_DATABASE=Software Technologies Group,Inc. + +acpi:SXB*: + ID_VENDOR_FROM_DATABASE=Syntax-Brillian + +acpi:SXD*: + ID_VENDOR_FROM_DATABASE=Silex technology, Inc. + +acpi:SXL*: + ID_VENDOR_FROM_DATABASE=SolutionInside + +acpi:SXT*: + ID_VENDOR_FROM_DATABASE=SHARP TAKAYA ELECTRONIC INDUSTRY CO.,LTD. + +acpi:SYC*: + ID_VENDOR_FROM_DATABASE=Sysmic + +acpi:SYE*: + ID_VENDOR_FROM_DATABASE=SY Electronics Ltd + +acpi:SYK*: + ID_VENDOR_FROM_DATABASE=Stryker Communications + +acpi:SYL*: + ID_VENDOR_FROM_DATABASE=Sylvania Computer Products + +acpi:SYM*: + ID_VENDOR_FROM_DATABASE=Symicron Computer Communications Ltd. + +acpi:SYN*: + ID_VENDOR_FROM_DATABASE=Synaptics Inc + +acpi:SYP*: + ID_VENDOR_FROM_DATABASE=SYPRO Co Ltd + +acpi:SYS*: + ID_VENDOR_FROM_DATABASE=Sysgration Ltd + +acpi:SYT*: + ID_VENDOR_FROM_DATABASE=Seyeon Tech Company Ltd + +acpi:SYV*: + ID_VENDOR_FROM_DATABASE=SYVAX Inc + +acpi:SYX*: + ID_VENDOR_FROM_DATABASE=Prime Systems, Inc. + +acpi:TAA*: + ID_VENDOR_FROM_DATABASE=Tandberg + +acpi:TAB*: + ID_VENDOR_FROM_DATABASE=Todos Data System AB + +acpi:TAG*: + ID_VENDOR_FROM_DATABASE=Teles AG + +acpi:TAI*: + ID_VENDOR_FROM_DATABASE=Toshiba America Info Systems Inc + +acpi:TAM*: + ID_VENDOR_FROM_DATABASE=Tamura Seisakusyo Ltd + +acpi:TAS*: + ID_VENDOR_FROM_DATABASE=Taskit Rechnertechnik GmbH + +acpi:TAT*: + ID_VENDOR_FROM_DATABASE=Teleliaison Inc + +acpi:TAX*: + ID_VENDOR_FROM_DATABASE=Taxan (Europe) Ltd + +acpi:TBB*: + ID_VENDOR_FROM_DATABASE=Triple S Engineering Inc + +acpi:TBC*: + ID_VENDOR_FROM_DATABASE=Turbo Communication, Inc + +acpi:TBS*: + ID_VENDOR_FROM_DATABASE=Turtle Beach System + +acpi:TCC*: + ID_VENDOR_FROM_DATABASE=Tandon Corporation + +acpi:TCD*: + ID_VENDOR_FROM_DATABASE=Taicom Data Systems Co., Ltd. + +acpi:TCE*: + ID_VENDOR_FROM_DATABASE=Century Corporation + +acpi:TCH*: + ID_VENDOR_FROM_DATABASE=Interaction Systems, Inc + +acpi:TCI*: + ID_VENDOR_FROM_DATABASE=Tulip Computers Int'l B.V. + +acpi:TCJ*: + ID_VENDOR_FROM_DATABASE=TEAC America Inc + +acpi:TCL*: + ID_VENDOR_FROM_DATABASE=Technical Concepts Ltd + +acpi:TCM*: + ID_VENDOR_FROM_DATABASE=3Com Corporation + +acpi:TCN*: + ID_VENDOR_FROM_DATABASE=Tecnetics (PTY) Ltd + +acpi:TCO*: + ID_VENDOR_FROM_DATABASE=Thomas-Conrad Corporation + +acpi:TCR*: + ID_VENDOR_FROM_DATABASE=Thomson Consumer Electronics + +acpi:TCS*: + ID_VENDOR_FROM_DATABASE=Tatung Company of America Inc + +acpi:TCT*: + ID_VENDOR_FROM_DATABASE=Telecom Technology Centre Co. Ltd. + +acpi:TCX*: + ID_VENDOR_FROM_DATABASE=FREEMARS Heavy Industries + +acpi:TDC*: + ID_VENDOR_FROM_DATABASE=Teradici + +acpi:TDD*: + ID_VENDOR_FROM_DATABASE=Tandberg Data Display AS + +acpi:TDK*: + ID_VENDOR_FROM_DATABASE=TDK USA Corporation + +acpi:TDM*: + ID_VENDOR_FROM_DATABASE=Tandem Computer Europe Inc + +acpi:TDP*: + ID_VENDOR_FROM_DATABASE=3D Perception + +acpi:TDS*: + ID_VENDOR_FROM_DATABASE=Tri-Data Systems Inc + +acpi:TDT*: + ID_VENDOR_FROM_DATABASE=TDT + +acpi:TDV*: + ID_VENDOR_FROM_DATABASE=TDVision Systems, Inc. + +acpi:TDY*: + ID_VENDOR_FROM_DATABASE=Tandy Electronics + +acpi:TEA*: + ID_VENDOR_FROM_DATABASE=TEAC System Corporation + +acpi:TEC*: + ID_VENDOR_FROM_DATABASE=Tecmar Inc + +acpi:TEK*: + ID_VENDOR_FROM_DATABASE=Tektronix Inc + +acpi:TEL*: + ID_VENDOR_FROM_DATABASE=Promotion and Display Technology Ltd. + +acpi:TER*: + ID_VENDOR_FROM_DATABASE=TerraTec Electronic GmbH + +acpi:TGC*: + ID_VENDOR_FROM_DATABASE=Toshiba Global Commerce Solutions, Inc. + +acpi:TGI*: + ID_VENDOR_FROM_DATABASE=TriGem Computer Inc + +acpi:TGM*: + ID_VENDOR_FROM_DATABASE=TriGem Computer,Inc. + +acpi:TGS*: + ID_VENDOR_FROM_DATABASE=Torus Systems Ltd + +acpi:TGV*: + ID_VENDOR_FROM_DATABASE=Grass Valley Germany GmbH + +acpi:THN*: + ID_VENDOR_FROM_DATABASE=Thundercom Holdings Sdn. Bhd. + +acpi:TIC*: + ID_VENDOR_FROM_DATABASE=Trigem KinfoComm + +acpi:TIP*: + ID_VENDOR_FROM_DATABASE=TIPTEL AG + +acpi:TIV*: + ID_VENDOR_FROM_DATABASE=OOO Technoinvest + +acpi:TIX*: + ID_VENDOR_FROM_DATABASE=Tixi.Com GmbH + +acpi:TKC*: + ID_VENDOR_FROM_DATABASE=Taiko Electric Works.LTD + +acpi:TKN*: + ID_VENDOR_FROM_DATABASE=Teknor Microsystem Inc + +acpi:TKO*: + ID_VENDOR_FROM_DATABASE=TouchKo, Inc. + +acpi:TKS*: + ID_VENDOR_FROM_DATABASE=TimeKeeping Systems, Inc. + +acpi:TLA*: + ID_VENDOR_FROM_DATABASE=Ferrari Electronic GmbH + +acpi:TLD*: + ID_VENDOR_FROM_DATABASE=Telindus + +acpi:TLI*: + ID_VENDOR_FROM_DATABASE=TOSHIBA TELI CORPORATION + +acpi:TLK*: + ID_VENDOR_FROM_DATABASE=Telelink AG + +acpi:TLS*: + ID_VENDOR_FROM_DATABASE=Teleste Educational OY + +acpi:TLT*: + ID_VENDOR_FROM_DATABASE=Dai Telecom S.p.A. + +acpi:TLV*: + ID_VENDOR_FROM_DATABASE=S3 Inc + +acpi:TLX*: + ID_VENDOR_FROM_DATABASE=Telxon Corporation + +acpi:TMC*: + ID_VENDOR_FROM_DATABASE=Techmedia Computer Systems Corporation + +acpi:TME*: + ID_VENDOR_FROM_DATABASE=AT&T Microelectronics + +acpi:TMI*: + ID_VENDOR_FROM_DATABASE=Texas Microsystem + +acpi:TMM*: + ID_VENDOR_FROM_DATABASE=Time Management, Inc. + +acpi:TMR*: + ID_VENDOR_FROM_DATABASE=Taicom International Inc + +acpi:TMS*: + ID_VENDOR_FROM_DATABASE=Trident Microsystems Ltd + +acpi:TMT*: + ID_VENDOR_FROM_DATABASE=T-Metrics Inc. + +acpi:TMX*: + ID_VENDOR_FROM_DATABASE=Thermotrex Corporation + +acpi:TNC*: + ID_VENDOR_FROM_DATABASE=TNC Industrial Company Ltd + +acpi:TNM*: + ID_VENDOR_FROM_DATABASE=TECNIMAGEN SA + +acpi:TNY*: + ID_VENDOR_FROM_DATABASE=Tennyson Tech Pty Ltd + +acpi:TOE*: + ID_VENDOR_FROM_DATABASE=TOEI Electronics Co., Ltd. + +acpi:TOG*: + ID_VENDOR_FROM_DATABASE=The OPEN Group + +acpi:TON*: + ID_VENDOR_FROM_DATABASE=TONNA + +acpi:TOP*: + ID_VENDOR_FROM_DATABASE=Orion Communications Co., Ltd. + +acpi:TOS*: + ID_VENDOR_FROM_DATABASE=Toshiba Corporation + +acpi:TOU*: + ID_VENDOR_FROM_DATABASE=Touchstone Technology + +acpi:TPC*: + ID_VENDOR_FROM_DATABASE=Touch Panel Systems Corporation + +acpi:TPE*: + ID_VENDOR_FROM_DATABASE=Technology Power Enterprises Inc + +acpi:TPJ*: + ID_VENDOR_FROM_DATABASE=Junnila + +acpi:TPK*: + ID_VENDOR_FROM_DATABASE=TOPRE CORPORATION + +acpi:TPR*: + ID_VENDOR_FROM_DATABASE=Topro Technology Inc + +acpi:TPS*: + ID_VENDOR_FROM_DATABASE=Teleprocessing Systeme GmbH + +acpi:TPT*: + ID_VENDOR_FROM_DATABASE=Thruput Ltd + +acpi:TPV*: + ID_VENDOR_FROM_DATABASE=Top Victory Electronics ( Fujian ) Company Ltd + +acpi:TPZ*: + ID_VENDOR_FROM_DATABASE=Ypoaz Systems Inc + +acpi:TRA*: + ID_VENDOR_FROM_DATABASE=TriTech Microelectronics International + +acpi:TRC*: + ID_VENDOR_FROM_DATABASE=Trioc AB + +acpi:TRD*: + ID_VENDOR_FROM_DATABASE=Trident Microsystem Inc + +acpi:TRE*: + ID_VENDOR_FROM_DATABASE=Tremetrics + +acpi:TRI*: + ID_VENDOR_FROM_DATABASE=Tricord Systems + +acpi:TRL*: + ID_VENDOR_FROM_DATABASE=Royal Information + +acpi:TRM*: + ID_VENDOR_FROM_DATABASE=Tekram Technology Company Ltd + +acpi:TRN*: + ID_VENDOR_FROM_DATABASE=Datacommunicatie Tron B.V. + +acpi:TRS*: + ID_VENDOR_FROM_DATABASE=Torus Systems Ltd + +acpi:TRT*: + ID_VENDOR_FROM_DATABASE=Tritec Electronic AG + +acpi:TRU*: + ID_VENDOR_FROM_DATABASE=Aashima Technology B.V. + +acpi:TRV*: + ID_VENDOR_FROM_DATABASE=Trivisio Prototyping GmbH + +acpi:TRX*: + ID_VENDOR_FROM_DATABASE=Trex Enterprises + +acpi:TSB*: + ID_VENDOR_FROM_DATABASE=Toshiba America Info Systems Inc + +acpi:TSC*: + ID_VENDOR_FROM_DATABASE=Sanyo Electric Company Ltd + +acpi:TSD*: + ID_VENDOR_FROM_DATABASE=TechniSat Digital GmbH + +acpi:TSE*: + ID_VENDOR_FROM_DATABASE=Tottori Sanyo Electric + +acpi:TSF*: + ID_VENDOR_FROM_DATABASE=Racal-Airtech Software Forge Ltd + +acpi:TSG*: + ID_VENDOR_FROM_DATABASE=The Software Group Ltd + +acpi:TSI*: + ID_VENDOR_FROM_DATABASE=TeleVideo Systems + +acpi:TSL*: + ID_VENDOR_FROM_DATABASE=Tottori SANYO Electric Co., Ltd. + +acpi:TSP*: + ID_VENDOR_FROM_DATABASE=U.S. Navy + +acpi:TST*: + ID_VENDOR_FROM_DATABASE=Transtream Inc + +acpi:TSV*: + ID_VENDOR_FROM_DATABASE=TRANSVIDEO + +acpi:TSY*: + ID_VENDOR_FROM_DATABASE=TouchSystems + +acpi:TTA*: + ID_VENDOR_FROM_DATABASE=Topson Technology Co., Ltd. + +acpi:TTB*: + ID_VENDOR_FROM_DATABASE=National Semiconductor Japan Ltd + +acpi:TTC*: + ID_VENDOR_FROM_DATABASE=Telecommunications Techniques Corporation + +acpi:TTE*: + ID_VENDOR_FROM_DATABASE=TTE, Inc. + +acpi:TTI*: + ID_VENDOR_FROM_DATABASE=Trenton Terminals Inc + +acpi:TTK*: + ID_VENDOR_FROM_DATABASE=Totoku Electric Company Ltd + +acpi:TTL*: + ID_VENDOR_FROM_DATABASE=2-Tel B.V. + +acpi:TTS*: + ID_VENDOR_FROM_DATABASE=TechnoTrend Systemtechnik GmbH + +acpi:TTY*: + ID_VENDOR_FROM_DATABASE=TRIDELITY Display Solutions GmbH + +acpi:TUA*: + ID_VENDOR_FROM_DATABASE=T+A elektroakustik GmbH + +acpi:TUT*: + ID_VENDOR_FROM_DATABASE=Tut Systems + +acpi:TVD*: + ID_VENDOR_FROM_DATABASE=Tecnovision + +acpi:TVI*: + ID_VENDOR_FROM_DATABASE=Truevision + +acpi:TVM*: + ID_VENDOR_FROM_DATABASE=Taiwan Video & Monitor Corporation + +acpi:TVO*: + ID_VENDOR_FROM_DATABASE=TV One Ltd + +acpi:TVR*: + ID_VENDOR_FROM_DATABASE=TV Interactive Corporation + +acpi:TVS*: + ID_VENDOR_FROM_DATABASE=TVS Electronics Limited + +acpi:TVV*: + ID_VENDOR_FROM_DATABASE=TV1 GmbH + +acpi:TWA*: + ID_VENDOR_FROM_DATABASE=Tidewater Association + +acpi:TWE*: + ID_VENDOR_FROM_DATABASE=Kontron Electronik + +acpi:TWH*: + ID_VENDOR_FROM_DATABASE=Twinhead International Corporation + +acpi:TWI*: + ID_VENDOR_FROM_DATABASE=Easytel oy + +acpi:TWK*: + ID_VENDOR_FROM_DATABASE=TOWITOKO electronics GmbH + +acpi:TWX*: + ID_VENDOR_FROM_DATABASE=TEKWorx Limited + +acpi:TXL*: + ID_VENDOR_FROM_DATABASE=Trixel Ltd + +acpi:TXN*: + ID_VENDOR_FROM_DATABASE=Texas Insturments + +acpi:TXT*: + ID_VENDOR_FROM_DATABASE=Textron Defense System + +acpi:TYN*: + ID_VENDOR_FROM_DATABASE=Tyan Computer Corporation + +acpi:UAS*: + ID_VENDOR_FROM_DATABASE=Ultima Associates Pte Ltd + +acpi:UBI*: + ID_VENDOR_FROM_DATABASE=Ungermann-Bass Inc + +acpi:UBL*: + ID_VENDOR_FROM_DATABASE=Ubinetics Ltd. + +acpi:UDN*: + ID_VENDOR_FROM_DATABASE=Uniden Corporation + +acpi:UEC*: + ID_VENDOR_FROM_DATABASE=Ultima Electronics Corporation + +acpi:UEG*: + ID_VENDOR_FROM_DATABASE=Elitegroup Computer Systems Company Ltd + +acpi:UEI*: + ID_VENDOR_FROM_DATABASE=Universal Electronics Inc + +acpi:UET*: + ID_VENDOR_FROM_DATABASE=Universal Empowering Technologies + +acpi:UFG*: + ID_VENDOR_FROM_DATABASE=UNIGRAF-USA + +acpi:UFO*: + ID_VENDOR_FROM_DATABASE=UFO Systems Inc + +acpi:UHB*: + ID_VENDOR_FROM_DATABASE=XOCECO + +acpi:UIC*: + ID_VENDOR_FROM_DATABASE=Uniform Industrial Corporation + +acpi:UJR*: + ID_VENDOR_FROM_DATABASE=Ueda Japan Radio Co., Ltd. + +acpi:ULT*: + ID_VENDOR_FROM_DATABASE=Ultra Network Tech + +acpi:UMC*: + ID_VENDOR_FROM_DATABASE=United Microelectr Corporation + +acpi:UMG*: + ID_VENDOR_FROM_DATABASE=Umezawa Giken Co.,Ltd + +acpi:UMM*: + ID_VENDOR_FROM_DATABASE=Universal Multimedia + +acpi:UNA*: + ID_VENDOR_FROM_DATABASE=Unisys DSD + +acpi:UNB*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNC*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNI*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNM*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNO*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNP*: + ID_VENDOR_FROM_DATABASE=Unitop + +acpi:UNS*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNT*: + ID_VENDOR_FROM_DATABASE=Unisys Corporation + +acpi:UNY*: + ID_VENDOR_FROM_DATABASE=Unicate + +acpi:UPP*: + ID_VENDOR_FROM_DATABASE=UPPI + +acpi:UPS*: + ID_VENDOR_FROM_DATABASE=Systems Enhancement + +acpi:URD*: + ID_VENDOR_FROM_DATABASE=Video Computer S.p.A. + +acpi:USA*: + ID_VENDOR_FROM_DATABASE=Utimaco Safeware AG + +acpi:USD*: + ID_VENDOR_FROM_DATABASE=U.S. Digital Corporation + +acpi:USI*: + ID_VENDOR_FROM_DATABASE=Universal Scientific Industrial Co., Ltd. + +acpi:USR*: + ID_VENDOR_FROM_DATABASE=U.S. Robotics Inc + +acpi:UTD*: + ID_VENDOR_FROM_DATABASE=Up to Date Tech + +acpi:UWC*: + ID_VENDOR_FROM_DATABASE=Uniwill Computer Corp. + +acpi:VAL*: + ID_VENDOR_FROM_DATABASE=Valence Computing Corporation + +acpi:VAR*: + ID_VENDOR_FROM_DATABASE=Varian Australia Pty Ltd + +acpi:VBR*: + ID_VENDOR_FROM_DATABASE=VBrick Systems Inc. + +acpi:VBT*: + ID_VENDOR_FROM_DATABASE=Valley Board Ltda + +acpi:VCC*: + ID_VENDOR_FROM_DATABASE=Virtual Computer Corporation + +acpi:VCI*: + ID_VENDOR_FROM_DATABASE=VistaCom Inc + +acpi:VCJ*: + ID_VENDOR_FROM_DATABASE=Victor Company of Japan, Limited + +acpi:VCM*: + ID_VENDOR_FROM_DATABASE=Vector Magnetics, LLC + +acpi:VCX*: + ID_VENDOR_FROM_DATABASE=VCONEX + +acpi:VDA*: + ID_VENDOR_FROM_DATABASE=Victor Data Systems + +acpi:VDC*: + ID_VENDOR_FROM_DATABASE=VDC Display Systems + +acpi:VDM*: + ID_VENDOR_FROM_DATABASE=Vadem + +acpi:VDO*: + ID_VENDOR_FROM_DATABASE=Video & Display Oriented Corporation + +acpi:VDS*: + ID_VENDOR_FROM_DATABASE=Vidisys GmbH & Company + +acpi:VDT*: + ID_VENDOR_FROM_DATABASE=Viditec, Inc. + +acpi:VEC*: + ID_VENDOR_FROM_DATABASE=Vector Informatik GmbH + +acpi:VEK*: + ID_VENDOR_FROM_DATABASE=Vektrex + +acpi:VES*: + ID_VENDOR_FROM_DATABASE=Vestel Elektronik Sanayi ve Ticaret A. S. + +acpi:VFI*: + ID_VENDOR_FROM_DATABASE=VeriFone Inc + +acpi:VHI*: + ID_VENDOR_FROM_DATABASE=Macrocad Development Inc. + +acpi:VIA*: + ID_VENDOR_FROM_DATABASE=VIA Tech Inc + +acpi:VIB*: + ID_VENDOR_FROM_DATABASE=Tatung UK Ltd + +acpi:VIC*: + ID_VENDOR_FROM_DATABASE=Victron B.V. + +acpi:VID*: + ID_VENDOR_FROM_DATABASE=Ingram Macrotron Germany + +acpi:VIK*: + ID_VENDOR_FROM_DATABASE=Viking Connectors + +acpi:VIN*: + ID_VENDOR_FROM_DATABASE=Vine Micros Ltd + +acpi:VIR*: + ID_VENDOR_FROM_DATABASE=Visual Interface, Inc + +acpi:VIS*: + ID_VENDOR_FROM_DATABASE=Visioneer + +acpi:VIT*: + ID_VENDOR_FROM_DATABASE=Visitech AS + +acpi:VIZ*: + ID_VENDOR_FROM_DATABASE=VIZIO, Inc + +acpi:VLB*: + ID_VENDOR_FROM_DATABASE=ValleyBoard Ltda. + +acpi:VLT*: + ID_VENDOR_FROM_DATABASE=VideoLan Technologies + +acpi:VMI*: + ID_VENDOR_FROM_DATABASE=Vermont Microsystems + +acpi:VML*: + ID_VENDOR_FROM_DATABASE=Vine Micros Limited + +acpi:VMW*: + ID_VENDOR_FROM_DATABASE=VMware Inc., + +acpi:VNC*: + ID_VENDOR_FROM_DATABASE=Vinca Corporation + +acpi:VOB*: + ID_VENDOR_FROM_DATABASE=MaxData Computer AG + +acpi:VPI*: + ID_VENDOR_FROM_DATABASE=Video Products Inc + +acpi:VPR*: + ID_VENDOR_FROM_DATABASE=Best Buy + +acpi:VQ@*: + ID_VENDOR_FROM_DATABASE=Vision Quest + +acpi:VRC*: + ID_VENDOR_FROM_DATABASE=Virtual Resources Corporation + +acpi:VSC*: + ID_VENDOR_FROM_DATABASE=ViewSonic Corporation + +acpi:VSD*: + ID_VENDOR_FROM_DATABASE=3M + +acpi:VSI*: + ID_VENDOR_FROM_DATABASE=VideoServer + +acpi:VSN*: + ID_VENDOR_FROM_DATABASE=Ingram Macrotron + +acpi:VSP*: + ID_VENDOR_FROM_DATABASE=Vision Systems GmbH + +acpi:VSR*: + ID_VENDOR_FROM_DATABASE=V-Star Electronics Inc. + +acpi:VTC*: + ID_VENDOR_FROM_DATABASE=VTel Corporation + +acpi:VTG*: + ID_VENDOR_FROM_DATABASE=Voice Technologies Group Inc + +acpi:VTI*: + ID_VENDOR_FROM_DATABASE=VLSI Tech Inc + +acpi:VTK*: + ID_VENDOR_FROM_DATABASE=Viewteck Co., Ltd. + +acpi:VTL*: + ID_VENDOR_FROM_DATABASE=Vivid Technology Pte Ltd + +acpi:VTM*: + ID_VENDOR_FROM_DATABASE=Miltope Corporation + +acpi:VTN*: + ID_VENDOR_FROM_DATABASE=VIDEOTRON CORP. + +acpi:VTS*: + ID_VENDOR_FROM_DATABASE=VTech Computers Ltd + +acpi:VTV*: + ID_VENDOR_FROM_DATABASE=VATIV Technologies + +acpi:VTX*: + ID_VENDOR_FROM_DATABASE=Vestax Corporation + +acpi:VUT*: + ID_VENDOR_FROM_DATABASE=Vutrix (UK) Ltd + +acpi:VWB*: + ID_VENDOR_FROM_DATABASE=Vweb Corp. + +acpi:WAC*: + ID_VENDOR_FROM_DATABASE=Wacom Tech + +acpi:WAL*: + ID_VENDOR_FROM_DATABASE=Wave Access + +acpi:WAV*: + ID_VENDOR_FROM_DATABASE=Wavephore + +acpi:WBN*: + ID_VENDOR_FROM_DATABASE=MicroSoftWare + +acpi:WBS*: + ID_VENDOR_FROM_DATABASE=WB Systemtechnik GmbH + +acpi:WCI*: + ID_VENDOR_FROM_DATABASE=Wisecom Inc + +acpi:WCS*: + ID_VENDOR_FROM_DATABASE=Woodwind Communications Systems Inc + +acpi:WDC*: + ID_VENDOR_FROM_DATABASE=Western Digital + +acpi:WDE*: + ID_VENDOR_FROM_DATABASE=Westinghouse Digital Electronics + +acpi:WEB*: + ID_VENDOR_FROM_DATABASE=WebGear Inc + +acpi:WEC*: + ID_VENDOR_FROM_DATABASE=Winbond Electronics Corporation + +acpi:WEL *: + ID_VENDOR_FROM_DATABASE=W-DEV + +acpi:WEY*: + ID_VENDOR_FROM_DATABASE=WEY Design AG + +acpi:WHI*: + ID_VENDOR_FROM_DATABASE=Whistle Communications + +acpi:WII*: + ID_VENDOR_FROM_DATABASE=Innoware Inc + +acpi:WIL*: + ID_VENDOR_FROM_DATABASE=WIPRO Information Technology Ltd + +acpi:WIN*: + ID_VENDOR_FROM_DATABASE=Wintop Technology Inc + +acpi:WIP*: + ID_VENDOR_FROM_DATABASE=Wipro Infotech + +acpi:WKH*: + ID_VENDOR_FROM_DATABASE=Uni-Take Int'l Inc. + +acpi:WLD*: + ID_VENDOR_FROM_DATABASE=Wildfire Communications Inc + +acpi:WML*: + ID_VENDOR_FROM_DATABASE=Wolfson Microelectronics Ltd + +acpi:WMO*: + ID_VENDOR_FROM_DATABASE=Westermo Teleindustri AB + +acpi:WMT*: + ID_VENDOR_FROM_DATABASE=Winmate Communication Inc + +acpi:WNI*: + ID_VENDOR_FROM_DATABASE=WillNet Inc. + +acpi:WNV*: + ID_VENDOR_FROM_DATABASE=Winnov L.P. + +acpi:WNX*: + ID_VENDOR_FROM_DATABASE=Wincor Nixdorf International GmbH + +acpi:WPA*: + ID_VENDOR_FROM_DATABASE=Matsushita Communication Industrial Co., Ltd. + +acpi:WPI*: + ID_VENDOR_FROM_DATABASE=Wearnes Peripherals International (Pte) Ltd + +acpi:WRC*: + ID_VENDOR_FROM_DATABASE=WiNRADiO Communications + +acpi:WSC*: + ID_VENDOR_FROM_DATABASE=CIS Technology Inc + +acpi:WSP*: + ID_VENDOR_FROM_DATABASE=Wireless And Smart Products Inc. + +acpi:WST*: + ID_VENDOR_FROM_DATABASE=Wistron Corporation + +acpi:WTC*: + ID_VENDOR_FROM_DATABASE=ACC Microelectronics + +acpi:WTI*: + ID_VENDOR_FROM_DATABASE=WorkStation Tech + +acpi:WTK*: + ID_VENDOR_FROM_DATABASE=Wearnes Thakral Pte + +acpi:WTS*: + ID_VENDOR_FROM_DATABASE=Restek Electric Company Ltd + +acpi:WVM*: + ID_VENDOR_FROM_DATABASE=Wave Systems Corporation + +acpi:WWV*: + ID_VENDOR_FROM_DATABASE=World Wide Video, Inc. + +acpi:WXT*: + ID_VENDOR_FROM_DATABASE=Woxter Technology Co. Ltd + +acpi:WYS*: + ID_VENDOR_FROM_DATABASE=Myse Technology + +acpi:WYT*: + ID_VENDOR_FROM_DATABASE=Wooyoung Image & Information Co.,Ltd. + +acpi:XAC*: + ID_VENDOR_FROM_DATABASE=XAC Automation Corp + +acpi:XAD*: + ID_VENDOR_FROM_DATABASE=Alpha Data + +acpi:XDM*: + ID_VENDOR_FROM_DATABASE=XDM Ltd. + +acpi:XFG*: + ID_VENDOR_FROM_DATABASE=Jan Strapko - FOTO + +acpi:XFO*: + ID_VENDOR_FROM_DATABASE=EXFO Electro Optical Engineering + +acpi:XIN*: + ID_VENDOR_FROM_DATABASE=Xinex Networks Inc + +acpi:XIO*: + ID_VENDOR_FROM_DATABASE=Xiotech Corporation + +acpi:XIR*: + ID_VENDOR_FROM_DATABASE=Xirocm Inc + +acpi:XIT*: + ID_VENDOR_FROM_DATABASE=Xitel Pty ltd + +acpi:XLX*: + ID_VENDOR_FROM_DATABASE=Xilinx, Inc. + +acpi:XMM*: + ID_VENDOR_FROM_DATABASE=C3PO S.L. + +acpi:XNT*: + ID_VENDOR_FROM_DATABASE=XN Technologies, Inc. + +acpi:XQU*: + ID_VENDOR_FROM_DATABASE=SHANGHAI SVA-DAV ELECTRONICS CO., LTD + +acpi:XRC*: + ID_VENDOR_FROM_DATABASE=Xircom Inc + +acpi:XRO*: + ID_VENDOR_FROM_DATABASE=XORO ELECTRONICS (CHENGDU) LIMITED + +acpi:XSN*: + ID_VENDOR_FROM_DATABASE=Xscreen AS + +acpi:XST*: + ID_VENDOR_FROM_DATABASE=XS Technologies Inc + +acpi:XSY*: + ID_VENDOR_FROM_DATABASE=XSYS + +acpi:XTD*: + ID_VENDOR_FROM_DATABASE=Icuiti Corporation + +acpi:XTE*: + ID_VENDOR_FROM_DATABASE=X2E GmbH + +acpi:XTL*: + ID_VENDOR_FROM_DATABASE=Crystal Computer + +acpi:XTN*: + ID_VENDOR_FROM_DATABASE=X-10 (USA) Inc + +acpi:XYC*: + ID_VENDOR_FROM_DATABASE=Xycotec Computer GmbH + +acpi:YED*: + ID_VENDOR_FROM_DATABASE=Y-E Data Inc + +acpi:YHQ*: + ID_VENDOR_FROM_DATABASE=Yokogawa Electric Corporation + +acpi:YHW*: + ID_VENDOR_FROM_DATABASE=Exacom SA + +acpi:YMH*: + ID_VENDOR_FROM_DATABASE=Yamaha Corporation + +acpi:YOW*: + ID_VENDOR_FROM_DATABASE=American Biometric Company + +acpi:ZAN*: + ID_VENDOR_FROM_DATABASE=Zandar Technologies plc + +acpi:ZAX*: + ID_VENDOR_FROM_DATABASE=Zefiro Acoustics + +acpi:ZAZ*: + ID_VENDOR_FROM_DATABASE=Zazzle Technologies + +acpi:ZBR*: + ID_VENDOR_FROM_DATABASE=Zebra Technologies International, LLC + +acpi:ZCT*: + ID_VENDOR_FROM_DATABASE=ZeitControl cardsystems GmbH + +acpi:ZDS*: + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +acpi:ZGT*: + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +acpi:ZIC*: + ID_VENDOR_FROM_DATABASE=Nationz Technologies Inc. + +acpi:ZMT*: + ID_VENDOR_FROM_DATABASE=Zalman Tech Co., Ltd. + +acpi:ZMZ*: + ID_VENDOR_FROM_DATABASE=Z Microsystems + +acpi:ZNI*: + ID_VENDOR_FROM_DATABASE=Zetinet Inc + +acpi:ZNX*: + ID_VENDOR_FROM_DATABASE=Znyx Adv. Systems + +acpi:ZOW*: + ID_VENDOR_FROM_DATABASE=Zowie Intertainment, Inc + +acpi:ZRN*: + ID_VENDOR_FROM_DATABASE=Zoran Corporation + +acpi:ZSE*: + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +acpi:ZTC*: + ID_VENDOR_FROM_DATABASE=ZyDAS Technology Corporation + +acpi:ZTE*: + ID_VENDOR_FROM_DATABASE=ZTE Corporation + +acpi:ZTI*: + ID_VENDOR_FROM_DATABASE=Zoom Telephonics Inc + +acpi:ZTM*: + ID_VENDOR_FROM_DATABASE=ZT Group Int'l Inc. + +acpi:ZTT*: + ID_VENDOR_FROM_DATABASE=Z3 Technology + +acpi:ZYD*: + ID_VENDOR_FROM_DATABASE=Zydacron Inc + +acpi:ZYP*: + ID_VENDOR_FROM_DATABASE=Zypcom Inc + +acpi:ZYT*: + ID_VENDOR_FROM_DATABASE=Zytex Computers + +acpi:ZYX*: + ID_VENDOR_FROM_DATABASE=Zyxel + +acpi:ZZZ*: + ID_VENDOR_FROM_DATABASE=Boca Research Inc diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb new file mode 100644 index 0000000..db3bc24 --- /dev/null +++ b/hwdb/20-bluetooth-vendor-product.hwdb @@ -0,0 +1,904 @@ +# This file is part of systemd. +# +# Data imported from: +# http://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm + +bluetooth:v0000* + ID_VENDOR_FROM_DATABASE=Ericsson Technology Licensing + +bluetooth:v0001* + ID_VENDOR_FROM_DATABASE=Nokia Mobile Phones + +bluetooth:v0002* + ID_VENDOR_FROM_DATABASE=Intel Corp. + +bluetooth:v0003* + ID_VENDOR_FROM_DATABASE=IBM Corp. + +bluetooth:v0004* + ID_VENDOR_FROM_DATABASE=Toshiba Corp. + +bluetooth:v0005* + ID_VENDOR_FROM_DATABASE=3Com + +bluetooth:v0006* + ID_VENDOR_FROM_DATABASE=Microsoft + +bluetooth:v0007* + ID_VENDOR_FROM_DATABASE=Lucent + +bluetooth:v0008* + ID_VENDOR_FROM_DATABASE=Motorola + +bluetooth:v0009* + ID_VENDOR_FROM_DATABASE=Infineon Technologies AG + +bluetooth:v000A* + ID_VENDOR_FROM_DATABASE=Cambridge Silicon Radio + +bluetooth:v000B* + ID_VENDOR_FROM_DATABASE=Silicon Wave + +bluetooth:v000C* + ID_VENDOR_FROM_DATABASE=Digianswer A/S + +bluetooth:v000D* + ID_VENDOR_FROM_DATABASE=Texas Instruments Inc. + +bluetooth:v000E* + ID_VENDOR_FROM_DATABASE=Ceva, Inc. (formerly Parthus Technologies, Inc.) + +bluetooth:v000F* + ID_VENDOR_FROM_DATABASE=Broadcom Corporation + +bluetooth:v0010* + ID_VENDOR_FROM_DATABASE=Mitel Semiconductor + +bluetooth:v0011* + ID_VENDOR_FROM_DATABASE=Widcomm, Inc + +bluetooth:v0012* + ID_VENDOR_FROM_DATABASE=Zeevo, Inc. + +bluetooth:v0013* + ID_VENDOR_FROM_DATABASE=Atmel Corporation + +bluetooth:v0014* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Corporation + +bluetooth:v0015* + ID_VENDOR_FROM_DATABASE=RTX Telecom A/S + +bluetooth:v0016* + ID_VENDOR_FROM_DATABASE=KC Technology Inc. + +bluetooth:v0017* + ID_VENDOR_FROM_DATABASE=NewLogic + +bluetooth:v0018* + ID_VENDOR_FROM_DATABASE=Transilica, Inc. + +bluetooth:v0019* + ID_VENDOR_FROM_DATABASE=Rohde & Schwarz GmbH & Co. KG + +bluetooth:v001A* + ID_VENDOR_FROM_DATABASE=TTPCom Limited + +bluetooth:v001B* + ID_VENDOR_FROM_DATABASE=Signia Technologies, Inc. + +bluetooth:v001C* + ID_VENDOR_FROM_DATABASE=Conexant Systems Inc. + +bluetooth:v001D* + ID_VENDOR_FROM_DATABASE=Qualcomm + +bluetooth:v001E* + ID_VENDOR_FROM_DATABASE=Inventel + +bluetooth:v001F* + ID_VENDOR_FROM_DATABASE=AVM Berlin + +bluetooth:v0020* + ID_VENDOR_FROM_DATABASE=BandSpeed, Inc. + +bluetooth:v0021* + ID_VENDOR_FROM_DATABASE=Mansella Ltd + +bluetooth:v0022* + ID_VENDOR_FROM_DATABASE=NEC Corporation + +bluetooth:v0023* + ID_VENDOR_FROM_DATABASE=WavePlus Technology Co., Ltd. + +bluetooth:v0024* + ID_VENDOR_FROM_DATABASE=Alcatel + +bluetooth:v0025* + ID_VENDOR_FROM_DATABASE=Philips Semiconductors + +bluetooth:v0026* + ID_VENDOR_FROM_DATABASE=C Technologies + +bluetooth:v0027* + ID_VENDOR_FROM_DATABASE=Open Interface + +bluetooth:v0028* + ID_VENDOR_FROM_DATABASE=R F Micro Devices + +bluetooth:v0029* + ID_VENDOR_FROM_DATABASE=Hitachi Ltd + +bluetooth:v002A* + ID_VENDOR_FROM_DATABASE=Symbol Technologies, Inc. + +bluetooth:v002B* + ID_VENDOR_FROM_DATABASE=Tenovis + +bluetooth:v002C* + ID_VENDOR_FROM_DATABASE=Macronix International Co. Ltd. + +bluetooth:v002D* + ID_VENDOR_FROM_DATABASE=GCT Semiconductor + +bluetooth:v002E* + ID_VENDOR_FROM_DATABASE=Norwood Systems + +bluetooth:v002F* + ID_VENDOR_FROM_DATABASE=MewTel Technology Inc. + +bluetooth:v0030* + ID_VENDOR_FROM_DATABASE=ST Microelectronics + +bluetooth:v0031* + ID_VENDOR_FROM_DATABASE=Synopsis + +bluetooth:v0032* + ID_VENDOR_FROM_DATABASE=Red-M (Communications) Ltd + +bluetooth:v0033* + ID_VENDOR_FROM_DATABASE=Commil Ltd + +bluetooth:v0034* + ID_VENDOR_FROM_DATABASE=Computer Access Technology Corporation (CATC) + +bluetooth:v0035* + ID_VENDOR_FROM_DATABASE=Eclipse (HQ Espana) S.L. + +bluetooth:v0036* + ID_VENDOR_FROM_DATABASE=Renesas Technology Corp. + +bluetooth:v0037* + ID_VENDOR_FROM_DATABASE=Mobilian Corporation + +bluetooth:v0038* + ID_VENDOR_FROM_DATABASE=Terax + +bluetooth:v0039* + ID_VENDOR_FROM_DATABASE=Integrated System Solution Corp. + +bluetooth:v003A* + ID_VENDOR_FROM_DATABASE=Matsushita Electric Industrial Co., Ltd. + +bluetooth:v003B* + ID_VENDOR_FROM_DATABASE=Gennum Corporation + +bluetooth:v003C* + ID_VENDOR_FROM_DATABASE=Research In Motion + +bluetooth:v003D* + ID_VENDOR_FROM_DATABASE=IPextreme, Inc. + +bluetooth:v003E* + ID_VENDOR_FROM_DATABASE=Systems and Chips, Inc. + +bluetooth:v003F* + ID_VENDOR_FROM_DATABASE=Bluetooth SIG, Inc. + +bluetooth:v0040* + ID_VENDOR_FROM_DATABASE=Seiko Epson Corporation + +bluetooth:v0041* + ID_VENDOR_FROM_DATABASE=Integrated Silicon Solution Taiwan, Inc. + +bluetooth:v0042* + ID_VENDOR_FROM_DATABASE=CONWISE Technology Corporation Ltd + +bluetooth:v0043* + ID_VENDOR_FROM_DATABASE=PARROT SA + +bluetooth:v0044* + ID_VENDOR_FROM_DATABASE=Socket Mobile + +bluetooth:v0045* + ID_VENDOR_FROM_DATABASE=Atheros Communications, Inc. + +bluetooth:v0046* + ID_VENDOR_FROM_DATABASE=MediaTek, Inc. + +bluetooth:v0047* + ID_VENDOR_FROM_DATABASE=Bluegiga + +bluetooth:v0048* + ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. + +bluetooth:v0049* + ID_VENDOR_FROM_DATABASE=3DSP Corporation + +bluetooth:v004A* + ID_VENDOR_FROM_DATABASE=Accel Semiconductor Ltd. + +bluetooth:v004B* + ID_VENDOR_FROM_DATABASE=Continental Automotive Systems + +bluetooth:v004C* + ID_VENDOR_FROM_DATABASE=Apple, Inc. + +bluetooth:v004D* + ID_VENDOR_FROM_DATABASE=Staccato Communications, Inc. + +bluetooth:v004E* + ID_VENDOR_FROM_DATABASE=Avago Technologies + +bluetooth:v004F* + ID_VENDOR_FROM_DATABASE=APT Licensing Ltd. + +bluetooth:v0050* + ID_VENDOR_FROM_DATABASE=SiRF Technology + +bluetooth:v0051* + ID_VENDOR_FROM_DATABASE=Tzero Technologies, Inc. + +bluetooth:v0052* + ID_VENDOR_FROM_DATABASE=J&M Corporation + +bluetooth:v0053* + ID_VENDOR_FROM_DATABASE=Free2move AB + +bluetooth:v0054* + ID_VENDOR_FROM_DATABASE=3DiJoy Corporation + +bluetooth:v0055* + ID_VENDOR_FROM_DATABASE=Plantronics, Inc. + +bluetooth:v0056* + ID_VENDOR_FROM_DATABASE=Sony Ericsson Mobile Communications + +bluetooth:v0057* + ID_VENDOR_FROM_DATABASE=Harman International Industries, Inc. + +bluetooth:v0058* + ID_VENDOR_FROM_DATABASE=Vizio, Inc. + +bluetooth:v0059* + ID_VENDOR_FROM_DATABASE=Nordic Semiconductor ASA + +bluetooth:v005A* + ID_VENDOR_FROM_DATABASE=EM Microelectronic-Marin SA + +bluetooth:v005B* + ID_VENDOR_FROM_DATABASE=Ralink Technology Corporation + +bluetooth:v005C* + ID_VENDOR_FROM_DATABASE=Belkin International, Inc. + +bluetooth:v005D* + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Corporation + +bluetooth:v005E* + ID_VENDOR_FROM_DATABASE=Stonestreet One, LLC + +bluetooth:v005F* + ID_VENDOR_FROM_DATABASE=Wicentric, Inc. + +bluetooth:v0060* + ID_VENDOR_FROM_DATABASE=RivieraWaves S.A.S + +bluetooth:v0061* + ID_VENDOR_FROM_DATABASE=RDA Microelectronics + +bluetooth:v0062* + ID_VENDOR_FROM_DATABASE=Gibson Guitars + +bluetooth:v0063* + ID_VENDOR_FROM_DATABASE=MiCommand Inc. + +bluetooth:v0064* + ID_VENDOR_FROM_DATABASE=Band XI International, LLC + +bluetooth:v0065* + ID_VENDOR_FROM_DATABASE=Hewlett-Packard Company + +bluetooth:v0066* + ID_VENDOR_FROM_DATABASE=9Solutions Oy + +bluetooth:v0067* + ID_VENDOR_FROM_DATABASE=GN Netcom A/S + +bluetooth:v0068* + ID_VENDOR_FROM_DATABASE=General Motors + +bluetooth:v0069* + ID_VENDOR_FROM_DATABASE=A&D Engineering, Inc. + +bluetooth:v006A* + ID_VENDOR_FROM_DATABASE=MindTree Ltd. + +bluetooth:v006B* + ID_VENDOR_FROM_DATABASE=Polar Electro OY + +bluetooth:v006C* + ID_VENDOR_FROM_DATABASE=Beautiful Enterprise Co., Ltd. + +bluetooth:v006D* + ID_VENDOR_FROM_DATABASE=BriarTek, Inc. + +bluetooth:v006E* + ID_VENDOR_FROM_DATABASE=Summit Data Communications, Inc. + +bluetooth:v006F* + ID_VENDOR_FROM_DATABASE=Sound ID + +bluetooth:v0070* + ID_VENDOR_FROM_DATABASE=Monster, LLC + +bluetooth:v0071* + ID_VENDOR_FROM_DATABASE=connectBlue AB + +bluetooth:v0072* + ID_VENDOR_FROM_DATABASE=ShangHai Super Smart Electronics Co. Ltd. + +bluetooth:v0073* + ID_VENDOR_FROM_DATABASE=Group Sense Ltd. + +bluetooth:v0074* + ID_VENDOR_FROM_DATABASE=Zomm, LLC + +bluetooth:v0075* + ID_VENDOR_FROM_DATABASE=Samsung Electronics Co. Ltd. + +bluetooth:v0076* + ID_VENDOR_FROM_DATABASE=Creative Technology Ltd. + +bluetooth:v0077* + ID_VENDOR_FROM_DATABASE=Laird Technologies + +bluetooth:v0078* + ID_VENDOR_FROM_DATABASE=Nike, Inc. + +bluetooth:v0078p0001* + ID_PRODUCT_FROM_DATABASE=Nike+ FuelBand + +bluetooth:v0079* + ID_VENDOR_FROM_DATABASE=lesswire AG + +bluetooth:v007A* + ID_VENDOR_FROM_DATABASE=MStar Semiconductor, Inc. + +bluetooth:v007B* + ID_VENDOR_FROM_DATABASE=Hanlynn Technologies + +bluetooth:v007C* + ID_VENDOR_FROM_DATABASE=A & R Cambridge + +bluetooth:v007D* + ID_VENDOR_FROM_DATABASE=Seers Technology Co. Ltd + +bluetooth:v007E* + ID_VENDOR_FROM_DATABASE=Sports Tracking Technologies Ltd. + +bluetooth:v007F* + ID_VENDOR_FROM_DATABASE=Autonet Mobile + +bluetooth:v0080* + ID_VENDOR_FROM_DATABASE=DeLorme Publishing Company, Inc. + +bluetooth:v0081* + ID_VENDOR_FROM_DATABASE=WuXi Vimicro + +bluetooth:v0082* + ID_VENDOR_FROM_DATABASE=Sennheiser Communications A/S + +bluetooth:v0083* + ID_VENDOR_FROM_DATABASE=TimeKeeping Systems, Inc. + +bluetooth:v0084* + ID_VENDOR_FROM_DATABASE=Ludus Helsinki Ltd. + +bluetooth:v0085* + ID_VENDOR_FROM_DATABASE=BlueRadios, Inc. + +bluetooth:v0086* + ID_VENDOR_FROM_DATABASE=equinox AG + +bluetooth:v0087* + ID_VENDOR_FROM_DATABASE=Garmin International, Inc. + +bluetooth:v0088* + ID_VENDOR_FROM_DATABASE=Ecotest + +bluetooth:v0089* + ID_VENDOR_FROM_DATABASE=GN ReSound A/S + +bluetooth:v008A* + ID_VENDOR_FROM_DATABASE=Jawbone + +bluetooth:v008B* + ID_VENDOR_FROM_DATABASE=Topcorn Positioning Systems, LLC + +bluetooth:v008C* + ID_VENDOR_FROM_DATABASE=Qualcomm Retail Solutions, Inc. (formerly Qualcomm Labs, Inc.) + +bluetooth:v008D* + ID_VENDOR_FROM_DATABASE=Zscan Software + +bluetooth:v008E* + ID_VENDOR_FROM_DATABASE=Quintic Corp. + +bluetooth:v008F* + ID_VENDOR_FROM_DATABASE=Stollman E+V GmbH + +bluetooth:v0090* + ID_VENDOR_FROM_DATABASE=Funai Electric Co., Ltd. + +bluetooth:v0091* + ID_VENDOR_FROM_DATABASE=Advanced PANMOBIL Systems GmbH & Co. KG + +bluetooth:v0092* + ID_VENDOR_FROM_DATABASE=ThinkOptics, Inc. + +bluetooth:v0093* + ID_VENDOR_FROM_DATABASE=Universal Electronics, Inc. + +bluetooth:v0094* + ID_VENDOR_FROM_DATABASE=Airoha Technology Corp. + +bluetooth:v0095* + ID_VENDOR_FROM_DATABASE=NEC Lighting, Ltd. + +bluetooth:v0096* + ID_VENDOR_FROM_DATABASE=ODM Technology, Inc. + +bluetooth:v0097* + ID_VENDOR_FROM_DATABASE=ConnecteDevice Ltd. + +bluetooth:v0098* + ID_VENDOR_FROM_DATABASE=zer01.tv GmbH + +bluetooth:v0099* + ID_VENDOR_FROM_DATABASE=i.Tech Dynamic Global Distribution Ltd. + +bluetooth:v009A* + ID_VENDOR_FROM_DATABASE=Alpwise + +bluetooth:v009B* + ID_VENDOR_FROM_DATABASE=Jiangsu Toppower Automotive Electronics Co., Ltd. + +bluetooth:v009C* + ID_VENDOR_FROM_DATABASE=Colorfy, Inc. + +bluetooth:v009D* + ID_VENDOR_FROM_DATABASE=Geoforce Inc. + +bluetooth:v009E* + ID_VENDOR_FROM_DATABASE=Bose Corporation + +bluetooth:v009F* + ID_VENDOR_FROM_DATABASE=Suunto Oy + +bluetooth:v00A0* + ID_VENDOR_FROM_DATABASE=Kensington Computer Products Group + +bluetooth:v00A1* + ID_VENDOR_FROM_DATABASE=SR-Medizinelektronik + +bluetooth:v00A2* + ID_VENDOR_FROM_DATABASE=Vertu Corporation Limited + +bluetooth:v00A3* + ID_VENDOR_FROM_DATABASE=Meta Watch Ltd. + +bluetooth:v00A4* + ID_VENDOR_FROM_DATABASE=LINAK A/S + +bluetooth:v00A5* + ID_VENDOR_FROM_DATABASE=OTL Dynamics LLC + +bluetooth:v00A6* + ID_VENDOR_FROM_DATABASE=Panda Ocean Inc. + +bluetooth:v00A7* + ID_VENDOR_FROM_DATABASE=Visteon Corporation + +bluetooth:v00A8* + ID_VENDOR_FROM_DATABASE=ARP Devices Limited + +bluetooth:v00A9* + ID_VENDOR_FROM_DATABASE=Magneti Marelli S.p.A + +bluetooth:v00AA* + ID_VENDOR_FROM_DATABASE=CAEN RFID srl + +bluetooth:v00AB* + ID_VENDOR_FROM_DATABASE=Ingenieur-Systemgruppe Zahn GmbH + +bluetooth:v00AC* + ID_VENDOR_FROM_DATABASE=Green Throttle Games + +bluetooth:v00AD* + ID_VENDOR_FROM_DATABASE=Peter Systemtechnik GmbH + +bluetooth:v00AE* + ID_VENDOR_FROM_DATABASE=Omegawave Oy + +bluetooth:v00AF* + ID_VENDOR_FROM_DATABASE=Cinetix + +bluetooth:v00B0* + ID_VENDOR_FROM_DATABASE=Passif Semiconductor Corp + +bluetooth:v00B1* + ID_VENDOR_FROM_DATABASE=Saris Cycling Group, Inc + +bluetooth:v00B2* + ID_VENDOR_FROM_DATABASE=Bekey A/S + +bluetooth:v00B3* + ID_VENDOR_FROM_DATABASE=Clarinox Technologies Pty. Ltd. + +bluetooth:v00B4* + ID_VENDOR_FROM_DATABASE=BDE Technology Co., Ltd. + +bluetooth:v00B5* + ID_VENDOR_FROM_DATABASE=Swirl Networks + +bluetooth:v00B6* + ID_VENDOR_FROM_DATABASE=Meso international + +bluetooth:v00B7* + ID_VENDOR_FROM_DATABASE=TreLab Ltd + +bluetooth:v00B8* + ID_VENDOR_FROM_DATABASE=Qualcomm Innovation Center, Inc. (QuIC) + +bluetooth:v00B9* + ID_VENDOR_FROM_DATABASE=Johnson Controls, Inc. + +bluetooth:v00BA* + ID_VENDOR_FROM_DATABASE=Starkey Laboratories Inc. + +bluetooth:v00BB* + ID_VENDOR_FROM_DATABASE=S-Power Electronics Limited + +bluetooth:v00BC* + ID_VENDOR_FROM_DATABASE=Ace Sensor Inc + +bluetooth:v00BD* + ID_VENDOR_FROM_DATABASE=Aplix Corporation + +bluetooth:v00BE* + ID_VENDOR_FROM_DATABASE=AAMP of America + +bluetooth:v00BF* + ID_VENDOR_FROM_DATABASE=Stalmart Technology Limited + +bluetooth:v00C0* + ID_VENDOR_FROM_DATABASE=AMICCOM Electronics Corporation + +bluetooth:v00C1* + ID_VENDOR_FROM_DATABASE=Shenzhen Excelsecu Data Technology Co.,Ltd + +bluetooth:v00C2* + ID_VENDOR_FROM_DATABASE=Geneq Inc. + +bluetooth:v00C3* + ID_VENDOR_FROM_DATABASE=adidas AG + +bluetooth:v00C4* + ID_VENDOR_FROM_DATABASE=LG Electronics + +bluetooth:v00C5* + ID_VENDOR_FROM_DATABASE=Onset Computer Corporation + +bluetooth:v00C6* + ID_VENDOR_FROM_DATABASE=Selfly BV + +bluetooth:v00C7* + ID_VENDOR_FROM_DATABASE=Quuppa Oy. + +bluetooth:v00C8* + ID_VENDOR_FROM_DATABASE=GeLo Inc + +bluetooth:v00C9* + ID_VENDOR_FROM_DATABASE=Evluma + +bluetooth:v00CA* + ID_VENDOR_FROM_DATABASE=MC10 + +bluetooth:v00CB* + ID_VENDOR_FROM_DATABASE=Binauric SE + +bluetooth:v00CC* + ID_VENDOR_FROM_DATABASE=Beats Electronics + +bluetooth:v00CD* + ID_VENDOR_FROM_DATABASE=Microchip Technology Inc. + +bluetooth:v00CE* + ID_VENDOR_FROM_DATABASE=Elgato Systems GmbH + +bluetooth:v00CF* + ID_VENDOR_FROM_DATABASE=ARCHOS SA + +bluetooth:v00D0* + ID_VENDOR_FROM_DATABASE=Dexcom, Inc. + +bluetooth:v00D1* + ID_VENDOR_FROM_DATABASE=Polar Electro Europe B.V. + +bluetooth:v00D2* + ID_VENDOR_FROM_DATABASE=Dialog Semiconductor B.V. + +bluetooth:v00D3* + ID_VENDOR_FROM_DATABASE=Taixingbang Technology (HK) Co,. LTD. + +bluetooth:v00D4* + ID_VENDOR_FROM_DATABASE=Kawantech + +bluetooth:v00D5* + ID_VENDOR_FROM_DATABASE=Austco Communication Systems + +bluetooth:v00D6* + ID_VENDOR_FROM_DATABASE=Timex Group USA, Inc. + +bluetooth:v00D7* + ID_VENDOR_FROM_DATABASE=Qualcomm Technologies, Inc. + +bluetooth:v00D8* + ID_VENDOR_FROM_DATABASE=Qualcomm Connected Experiences, Inc. + +bluetooth:v00D9* + ID_VENDOR_FROM_DATABASE=Voyetra Turtle Beach + +bluetooth:v00DA* + ID_VENDOR_FROM_DATABASE=txtr GmbH + +bluetooth:v00DB* + ID_VENDOR_FROM_DATABASE=Biosentronics + +bluetooth:v00DC* + ID_VENDOR_FROM_DATABASE=Procter & Gamble + +bluetooth:v00DD* + ID_VENDOR_FROM_DATABASE=Hosiden Corporation + +bluetooth:v00DE* + ID_VENDOR_FROM_DATABASE=Muzik LLC + +bluetooth:v00DF* + ID_VENDOR_FROM_DATABASE=Misfit Wearables Corp + +bluetooth:v00E0* + ID_VENDOR_FROM_DATABASE=Google + +bluetooth:v00E1* + ID_VENDOR_FROM_DATABASE=Danlers Ltd + +bluetooth:v00E2* + ID_VENDOR_FROM_DATABASE=Semilink Inc + +bluetooth:v00E3* + ID_VENDOR_FROM_DATABASE=inMusic Brands, Inc + +bluetooth:v00E4* + ID_VENDOR_FROM_DATABASE=L.S. Research Inc. + +bluetooth:v00E5* + ID_VENDOR_FROM_DATABASE=Eden Software Consultants Ltd. + +bluetooth:v00E6* + ID_VENDOR_FROM_DATABASE=Freshtemp + +bluetooth:v00E7* + ID_VENDOR_FROM_DATABASE=KS Technologies + +bluetooth:v00E8* + ID_VENDOR_FROM_DATABASE=ACTS Technologies + +bluetooth:v00E9* + ID_VENDOR_FROM_DATABASE=Vtrack Systems + +bluetooth:v00EA* + ID_VENDOR_FROM_DATABASE=Nielsen-Kellerman Company + +bluetooth:v00EB* + ID_VENDOR_FROM_DATABASE=Server Technology, Inc. + +bluetooth:v00EC* + ID_VENDOR_FROM_DATABASE=BioResearch Associates + +bluetooth:v00ED* + ID_VENDOR_FROM_DATABASE=Jolly Logic, LLC + +bluetooth:v00EE* + ID_VENDOR_FROM_DATABASE=Above Average Outcomes, Inc. + +bluetooth:v00EF* + ID_VENDOR_FROM_DATABASE=Bitsplitters GmbH + +bluetooth:v00F0* + ID_VENDOR_FROM_DATABASE=PayPal, Inc. + +bluetooth:v00F1* + ID_VENDOR_FROM_DATABASE=Witron Technology Limited + +bluetooth:v00F2* + ID_VENDOR_FROM_DATABASE=Morse Project Inc. + +bluetooth:v00F3* + ID_VENDOR_FROM_DATABASE=Kent Displays Inc. + +bluetooth:v00F4* + ID_VENDOR_FROM_DATABASE=Nautilus Inc. + +bluetooth:v00F5* + ID_VENDOR_FROM_DATABASE=Smartifier Oy + +bluetooth:v00F6* + ID_VENDOR_FROM_DATABASE=Elcometer Limited + +bluetooth:v00F7* + ID_VENDOR_FROM_DATABASE=VSN Technologies Inc. + +bluetooth:v00F8* + ID_VENDOR_FROM_DATABASE=AceUni Corp., Ltd. + +bluetooth:v00F9* + ID_VENDOR_FROM_DATABASE=StickNFind + +bluetooth:v00FA* + ID_VENDOR_FROM_DATABASE=Crystal Code AB + +bluetooth:v00FB* + ID_VENDOR_FROM_DATABASE=KOUKAAM a.s. + +bluetooth:v00FC* + ID_VENDOR_FROM_DATABASE=Delphi Corporation + +bluetooth:v00FD* + ID_VENDOR_FROM_DATABASE=ValenceTech Limited + +bluetooth:v00FE* + ID_VENDOR_FROM_DATABASE=Reserved + +bluetooth:v00FF* + ID_VENDOR_FROM_DATABASE=Typo Products, LLC + +bluetooth:v0100* + ID_VENDOR_FROM_DATABASE=TomTom International BV + +bluetooth:v0101* + ID_VENDOR_FROM_DATABASE=Fugoo, Inc + +bluetooth:v0102* + ID_VENDOR_FROM_DATABASE=Keiser Corporation + +bluetooth:v0103* + ID_VENDOR_FROM_DATABASE=Bang & Olufsen A/S + +bluetooth:v0104* + ID_VENDOR_FROM_DATABASE=PLUS Locations Systems Pty Ltd + +bluetooth:v0105* + ID_VENDOR_FROM_DATABASE=Ubiquitous Computing Technology Corporation + +bluetooth:v0106* + ID_VENDOR_FROM_DATABASE=Innovative Yachtter Solutions + +bluetooth:v0107* + ID_VENDOR_FROM_DATABASE=William Demant Holding A/S + +bluetooth:v0108* + ID_VENDOR_FROM_DATABASE=Chicony Electronics Co., Ltd. + +bluetooth:v0109* + ID_VENDOR_FROM_DATABASE=Atus BV + +bluetooth:v010A* + ID_VENDOR_FROM_DATABASE=Codegate Ltd. + +bluetooth:v010B* + ID_VENDOR_FROM_DATABASE=ERi, Inc. + +bluetooth:v010C* + ID_VENDOR_FROM_DATABASE=Transducers Direct, LLC + +bluetooth:v010D* + ID_VENDOR_FROM_DATABASE=Fujitsu Ten Limited + +bluetooth:v010E* + ID_VENDOR_FROM_DATABASE=Audi AG + +bluetooth:v010F* + ID_VENDOR_FROM_DATABASE=HiSilicon Technologies Co., Ltd. + +bluetooth:v0110* + ID_VENDOR_FROM_DATABASE=Nippon Seiki Co., Ltd. + +bluetooth:v0111* + ID_VENDOR_FROM_DATABASE=Steelseries ApS + +bluetooth:v0112* + ID_VENDOR_FROM_DATABASE=vyzybl Inc. + +bluetooth:v0113* + ID_VENDOR_FROM_DATABASE=Openbrain Technologies, Co., Ltd. + +bluetooth:v0114* + ID_VENDOR_FROM_DATABASE=Xensr + +bluetooth:v0115* + ID_VENDOR_FROM_DATABASE=e.solutions + +bluetooth:v0116* + ID_VENDOR_FROM_DATABASE=1OAK Technologies + +bluetooth:v0117* + ID_VENDOR_FROM_DATABASE=Wimoto Technologies Inc + +bluetooth:v0118* + ID_VENDOR_FROM_DATABASE=Radius Networks, Inc. + +bluetooth:v0119* + ID_VENDOR_FROM_DATABASE=Wize Technology Co., Ltd. + +bluetooth:v011A* + ID_VENDOR_FROM_DATABASE=Qualcomm Labs, Inc. + +bluetooth:v011B* + ID_VENDOR_FROM_DATABASE=Aruba Networks + +bluetooth:v011C* + ID_VENDOR_FROM_DATABASE=Baidu + +bluetooth:v011D* + ID_VENDOR_FROM_DATABASE=Arendi AG + +bluetooth:v011E* + ID_VENDOR_FROM_DATABASE=Skoda Auto a.s. + +bluetooth:v011F* + ID_VENDOR_FROM_DATABASE=Volkswagon AG + +bluetooth:v0120* + ID_VENDOR_FROM_DATABASE=Porsche AG + +bluetooth:v0121* + ID_VENDOR_FROM_DATABASE=Sino Wealth Electronic Ltd. + +bluetooth:v0122* + ID_VENDOR_FROM_DATABASE=AirTurn, Inc. + +bluetooth:v0123* + ID_VENDOR_FROM_DATABASE=Kinsa, Inc. + +bluetooth:v0124* + ID_VENDOR_FROM_DATABASE=HID Global + +bluetooth:v0125* + ID_VENDOR_FROM_DATABASE=SEAT es + +bluetooth:v0126* + ID_VENDOR_FROM_DATABASE=Promethean Ltd. + +bluetooth:v0127* + ID_VENDOR_FROM_DATABASE=Salutica Allied Solutions + +bluetooth:v0128* + ID_VENDOR_FROM_DATABASE=GPSI Group Pty Ltd + +bluetooth:v0129* + ID_VENDOR_FROM_DATABASE=Nimble Devices Oy + +bluetooth:v012A* + ID_VENDOR_FROM_DATABASE=Changzhou Yongse Infotech Co., Ltd diff --git a/hwdb/20-net-ifname.hwdb b/hwdb/20-net-ifname.hwdb new file mode 100644 index 0000000..29d2633 --- /dev/null +++ b/hwdb/20-net-ifname.hwdb @@ -0,0 +1,5 @@ +# This file is part of systemd. + +# Dell iDRAC Virtual USB NIC +usb:v413CpA102* + ID_NET_NAME_FROM_DATABASE=irdac diff --git a/hwdb/20-pci-classes.hwdb b/hwdb/20-pci-classes.hwdb new file mode 100644 index 0000000..fd1d5d0 --- /dev/null +++ b/hwdb/20-pci-classes.hwdb @@ -0,0 +1,531 @@ +# This file is part of systemd. +# +# Data imported from: http://pci-ids.ucw.cz/v2.2/pci.ids + +pci:v*d*sv*sd*bc00* + ID_PCI_CLASS_FROM_DATABASE=Unclassified device + +pci:v*d*sv*sd*bc00sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Non-VGA unclassified device + +pci:v*d*sv*sd*bc00sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible unclassified device + +pci:v*d*sv*sd*bc01* + ID_PCI_CLASS_FROM_DATABASE=Mass storage controller + +pci:v*d*sv*sd*bc01sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=SCSI storage controller + +pci:v*d*sv*sd*bc01sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=IDE interface + +pci:v*d*sv*sd*bc01sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Floppy disk controller + +pci:v*d*sv*sd*bc01sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=IPI bus controller + +pci:v*d*sv*sd*bc01sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=RAID bus controller + +pci:v*d*sv*sd*bc01sc05* + ID_PCI_SUBCLASS_FROM_DATABASE=ATA controller + +pci:v*d*sv*sd*bc01sc05i20* + ID_PCI_INTERFACE_FROM_DATABASE=ADMA single stepping + +pci:v*d*sv*sd*bc01sc05i30* + ID_PCI_INTERFACE_FROM_DATABASE=ADMA continuous operation + +pci:v*d*sv*sd*bc01sc06* + ID_PCI_SUBCLASS_FROM_DATABASE=SATA controller + +pci:v*d*sv*sd*bc01sc06i00* + ID_PCI_INTERFACE_FROM_DATABASE=Vendor specific + +pci:v*d*sv*sd*bc01sc06i01* + ID_PCI_INTERFACE_FROM_DATABASE=AHCI 1.0 + +pci:v*d*sv*sd*bc01sc07* + ID_PCI_SUBCLASS_FROM_DATABASE=Serial Attached SCSI controller + +pci:v*d*sv*sd*bc01sc08* + ID_PCI_SUBCLASS_FROM_DATABASE=Non-Volatile memory controller + +pci:v*d*sv*sd*bc01sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Mass storage controller + +pci:v*d*sv*sd*bc02* + ID_PCI_CLASS_FROM_DATABASE=Network controller + +pci:v*d*sv*sd*bc02sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Ethernet controller + +pci:v*d*sv*sd*bc02sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Token ring network controller + +pci:v*d*sv*sd*bc02sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=FDDI network controller + +pci:v*d*sv*sd*bc02sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=ATM network controller + +pci:v*d*sv*sd*bc02sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=ISDN controller + +pci:v*d*sv*sd*bc02sc05* + ID_PCI_SUBCLASS_FROM_DATABASE=WorldFip controller + +pci:v*d*sv*sd*bc02sc06* + ID_PCI_SUBCLASS_FROM_DATABASE=PICMG controller + +pci:v*d*sv*sd*bc02sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Network controller + +pci:v*d*sv*sd*bc03* + ID_PCI_CLASS_FROM_DATABASE=Display controller + +pci:v*d*sv*sd*bc03sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible controller + +pci:v*d*sv*sd*bc03sc00i00* + ID_PCI_INTERFACE_FROM_DATABASE=VGA controller + +pci:v*d*sv*sd*bc03sc00i01* + ID_PCI_INTERFACE_FROM_DATABASE=8514 controller + +pci:v*d*sv*sd*bc03sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=XGA compatible controller + +pci:v*d*sv*sd*bc03sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=3D controller + +pci:v*d*sv*sd*bc03sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Display controller + +pci:v*d*sv*sd*bc04* + ID_PCI_CLASS_FROM_DATABASE=Multimedia controller + +pci:v*d*sv*sd*bc04sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Multimedia video controller + +pci:v*d*sv*sd*bc04sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Multimedia audio controller + +pci:v*d*sv*sd*bc04sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Computer telephony device + +pci:v*d*sv*sd*bc04sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=Audio device + +pci:v*d*sv*sd*bc04sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Multimedia controller + +pci:v*d*sv*sd*bc05* + ID_PCI_CLASS_FROM_DATABASE=Memory controller + +pci:v*d*sv*sd*bc05sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=RAM memory + +pci:v*d*sv*sd*bc05sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=FLASH memory + +pci:v*d*sv*sd*bc05sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Memory controller + +pci:v*d*sv*sd*bc06* + ID_PCI_CLASS_FROM_DATABASE=Bridge + +pci:v*d*sv*sd*bc06sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Host bridge + +pci:v*d*sv*sd*bc06sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=ISA bridge + +pci:v*d*sv*sd*bc06sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=EISA bridge + +pci:v*d*sv*sd*bc06sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=MicroChannel bridge + +pci:v*d*sv*sd*bc06sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge + +pci:v*d*sv*sd*bc06sc04i00* + ID_PCI_INTERFACE_FROM_DATABASE=Normal decode + +pci:v*d*sv*sd*bc06sc04i01* + ID_PCI_INTERFACE_FROM_DATABASE=Subtractive decode + +pci:v*d*sv*sd*bc06sc05* + ID_PCI_SUBCLASS_FROM_DATABASE=PCMCIA bridge + +pci:v*d*sv*sd*bc06sc06* + ID_PCI_SUBCLASS_FROM_DATABASE=NuBus bridge + +pci:v*d*sv*sd*bc06sc07* + ID_PCI_SUBCLASS_FROM_DATABASE=CardBus bridge + +pci:v*d*sv*sd*bc06sc08* + ID_PCI_SUBCLASS_FROM_DATABASE=RACEway bridge + +pci:v*d*sv*sd*bc06sc08i00* + ID_PCI_INTERFACE_FROM_DATABASE=Transparent mode + +pci:v*d*sv*sd*bc06sc08i01* + ID_PCI_INTERFACE_FROM_DATABASE=Endpoint mode + +pci:v*d*sv*sd*bc06sc09* + ID_PCI_SUBCLASS_FROM_DATABASE=Semi-transparent PCI-to-PCI bridge + +pci:v*d*sv*sd*bc06sc09i40* + ID_PCI_INTERFACE_FROM_DATABASE=Primary bus towards host CPU + +pci:v*d*sv*sd*bc06sc09i80* + ID_PCI_INTERFACE_FROM_DATABASE=Secondary bus towards host CPU + +pci:v*d*sv*sd*bc06sc0A* + ID_PCI_SUBCLASS_FROM_DATABASE=InfiniBand to PCI host bridge + +pci:v*d*sv*sd*bc06sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Bridge + +pci:v*d*sv*sd*bc07* + ID_PCI_CLASS_FROM_DATABASE=Communication controller + +pci:v*d*sv*sd*bc07sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Serial controller + +pci:v*d*sv*sd*bc07sc00i00* + ID_PCI_INTERFACE_FROM_DATABASE=8250 + +pci:v*d*sv*sd*bc07sc00i01* + ID_PCI_INTERFACE_FROM_DATABASE=16450 + +pci:v*d*sv*sd*bc07sc00i02* + ID_PCI_INTERFACE_FROM_DATABASE=16550 + +pci:v*d*sv*sd*bc07sc00i03* + ID_PCI_INTERFACE_FROM_DATABASE=16650 + +pci:v*d*sv*sd*bc07sc00i04* + ID_PCI_INTERFACE_FROM_DATABASE=16750 + +pci:v*d*sv*sd*bc07sc00i05* + ID_PCI_INTERFACE_FROM_DATABASE=16850 + +pci:v*d*sv*sd*bc07sc00i06* + ID_PCI_INTERFACE_FROM_DATABASE=16950 + +pci:v*d*sv*sd*bc07sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Parallel controller + +pci:v*d*sv*sd*bc07sc01i00* + ID_PCI_INTERFACE_FROM_DATABASE=SPP + +pci:v*d*sv*sd*bc07sc01i01* + ID_PCI_INTERFACE_FROM_DATABASE=BiDir + +pci:v*d*sv*sd*bc07sc01i02* + ID_PCI_INTERFACE_FROM_DATABASE=ECP + +pci:v*d*sv*sd*bc07sc01i03* + ID_PCI_INTERFACE_FROM_DATABASE=IEEE1284 + +pci:v*d*sv*sd*bc07sc01iFE* + ID_PCI_INTERFACE_FROM_DATABASE=IEEE1284 Target + +pci:v*d*sv*sd*bc07sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Multiport serial controller + +pci:v*d*sv*sd*bc07sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=Modem + +pci:v*d*sv*sd*bc07sc03i00* + ID_PCI_INTERFACE_FROM_DATABASE=Generic + +pci:v*d*sv*sd*bc07sc03i01* + ID_PCI_INTERFACE_FROM_DATABASE=Hayes/16450 + +pci:v*d*sv*sd*bc07sc03i02* + ID_PCI_INTERFACE_FROM_DATABASE=Hayes/16550 + +pci:v*d*sv*sd*bc07sc03i03* + ID_PCI_INTERFACE_FROM_DATABASE=Hayes/16650 + +pci:v*d*sv*sd*bc07sc03i04* + ID_PCI_INTERFACE_FROM_DATABASE=Hayes/16750 + +pci:v*d*sv*sd*bc07sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=GPIB controller + +pci:v*d*sv*sd*bc07sc05* + ID_PCI_SUBCLASS_FROM_DATABASE=Smard Card controller + +pci:v*d*sv*sd*bc07sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Communication controller + +pci:v*d*sv*sd*bc08* + ID_PCI_CLASS_FROM_DATABASE=Generic system peripheral + +pci:v*d*sv*sd*bc08sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=PIC + +pci:v*d*sv*sd*bc08sc00i00* + ID_PCI_INTERFACE_FROM_DATABASE=8259 + +pci:v*d*sv*sd*bc08sc00i01* + ID_PCI_INTERFACE_FROM_DATABASE=ISA PIC + +pci:v*d*sv*sd*bc08sc00i02* + ID_PCI_INTERFACE_FROM_DATABASE=EISA PIC + +pci:v*d*sv*sd*bc08sc00i10* + ID_PCI_INTERFACE_FROM_DATABASE=IO-APIC + +pci:v*d*sv*sd*bc08sc00i20* + ID_PCI_INTERFACE_FROM_DATABASE=IO(X)-APIC + +pci:v*d*sv*sd*bc08sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=DMA controller + +pci:v*d*sv*sd*bc08sc01i00* + ID_PCI_INTERFACE_FROM_DATABASE=8237 + +pci:v*d*sv*sd*bc08sc01i01* + ID_PCI_INTERFACE_FROM_DATABASE=ISA DMA + +pci:v*d*sv*sd*bc08sc01i02* + ID_PCI_INTERFACE_FROM_DATABASE=EISA DMA + +pci:v*d*sv*sd*bc08sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Timer + +pci:v*d*sv*sd*bc08sc02i00* + ID_PCI_INTERFACE_FROM_DATABASE=8254 + +pci:v*d*sv*sd*bc08sc02i01* + ID_PCI_INTERFACE_FROM_DATABASE=ISA Timer + +pci:v*d*sv*sd*bc08sc02i02* + ID_PCI_INTERFACE_FROM_DATABASE=EISA Timers + +pci:v*d*sv*sd*bc08sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=RTC + +pci:v*d*sv*sd*bc08sc03i00* + ID_PCI_INTERFACE_FROM_DATABASE=Generic + +pci:v*d*sv*sd*bc08sc03i01* + ID_PCI_INTERFACE_FROM_DATABASE=ISA RTC + +pci:v*d*sv*sd*bc08sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=PCI Hot-plug controller + +pci:v*d*sv*sd*bc08sc05* + ID_PCI_SUBCLASS_FROM_DATABASE=SD Host controller + +pci:v*d*sv*sd*bc08sc06* + ID_PCI_SUBCLASS_FROM_DATABASE=IOMMU + +pci:v*d*sv*sd*bc08sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=System peripheral + +pci:v*d*sv*sd*bc09* + ID_PCI_CLASS_FROM_DATABASE=Input device controller + +pci:v*d*sv*sd*bc09sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Keyboard controller + +pci:v*d*sv*sd*bc09sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Digitizer Pen + +pci:v*d*sv*sd*bc09sc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Mouse controller + +pci:v*d*sv*sd*bc09sc03* + ID_PCI_SUBCLASS_FROM_DATABASE=Scanner controller + +pci:v*d*sv*sd*bc09sc04* + ID_PCI_SUBCLASS_FROM_DATABASE=Gameport controller + +pci:v*d*sv*sd*bc09sc04i00* + ID_PCI_INTERFACE_FROM_DATABASE=Generic + +pci:v*d*sv*sd*bc09sc04i10* + ID_PCI_INTERFACE_FROM_DATABASE=Extended + +pci:v*d*sv*sd*bc09sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Input device controller + +pci:v*d*sv*sd*bc0A* + ID_PCI_CLASS_FROM_DATABASE=Docking station + +pci:v*d*sv*sd*bc0Asc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Generic Docking Station + +pci:v*d*sv*sd*bc0Asc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Docking Station + +pci:v*d*sv*sd*bc0B* + ID_PCI_CLASS_FROM_DATABASE=Processor + +pci:v*d*sv*sd*bc0Bsc00* + ID_PCI_SUBCLASS_FROM_DATABASE=386 + +pci:v*d*sv*sd*bc0Bsc01* + ID_PCI_SUBCLASS_FROM_DATABASE=486 + +pci:v*d*sv*sd*bc0Bsc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Pentium + +pci:v*d*sv*sd*bc0Bsc10* + ID_PCI_SUBCLASS_FROM_DATABASE=Alpha + +pci:v*d*sv*sd*bc0Bsc20* + ID_PCI_SUBCLASS_FROM_DATABASE=Power PC + +pci:v*d*sv*sd*bc0Bsc30* + ID_PCI_SUBCLASS_FROM_DATABASE=MIPS + +pci:v*d*sv*sd*bc0Bsc40* + ID_PCI_SUBCLASS_FROM_DATABASE=Co-processor + +pci:v*d*sv*sd*bc0C* + ID_PCI_CLASS_FROM_DATABASE=Serial bus controller + +pci:v*d*sv*sd*bc0Csc00* + ID_PCI_SUBCLASS_FROM_DATABASE=FireWire (IEEE 1394) + +pci:v*d*sv*sd*bc0Csc00i00* + ID_PCI_INTERFACE_FROM_DATABASE=Generic + +pci:v*d*sv*sd*bc0Csc00i10* + ID_PCI_INTERFACE_FROM_DATABASE=OHCI + +pci:v*d*sv*sd*bc0Csc01* + ID_PCI_SUBCLASS_FROM_DATABASE=ACCESS Bus + +pci:v*d*sv*sd*bc0Csc02* + ID_PCI_SUBCLASS_FROM_DATABASE=SSA + +pci:v*d*sv*sd*bc0Csc03* + ID_PCI_SUBCLASS_FROM_DATABASE=USB controller + +pci:v*d*sv*sd*bc0Csc03i00* + ID_PCI_INTERFACE_FROM_DATABASE=UHCI + +pci:v*d*sv*sd*bc0Csc03i10* + ID_PCI_INTERFACE_FROM_DATABASE=OHCI + +pci:v*d*sv*sd*bc0Csc03i20* + ID_PCI_INTERFACE_FROM_DATABASE=EHCI + +pci:v*d*sv*sd*bc0Csc03i30* + ID_PCI_INTERFACE_FROM_DATABASE=XHCI + +pci:v*d*sv*sd*bc0Csc03i80* + ID_PCI_INTERFACE_FROM_DATABASE=Unspecified + +pci:v*d*sv*sd*bc0Csc03iFE* + ID_PCI_INTERFACE_FROM_DATABASE=USB Device + +pci:v*d*sv*sd*bc0Csc04* + ID_PCI_SUBCLASS_FROM_DATABASE=Fibre Channel + +pci:v*d*sv*sd*bc0Csc05* + ID_PCI_SUBCLASS_FROM_DATABASE=SMBus + +pci:v*d*sv*sd*bc0Csc06* + ID_PCI_SUBCLASS_FROM_DATABASE=InfiniBand + +pci:v*d*sv*sd*bc0Csc07* + ID_PCI_SUBCLASS_FROM_DATABASE=IPMI SMIC interface + +pci:v*d*sv*sd*bc0Csc08* + ID_PCI_SUBCLASS_FROM_DATABASE=SERCOS interface + +pci:v*d*sv*sd*bc0Csc09* + ID_PCI_SUBCLASS_FROM_DATABASE=CANBUS + +pci:v*d*sv*sd*bc0D* + ID_PCI_CLASS_FROM_DATABASE=Wireless controller + +pci:v*d*sv*sd*bc0Dsc00* + ID_PCI_SUBCLASS_FROM_DATABASE=IRDA controller + +pci:v*d*sv*sd*bc0Dsc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Consumer IR controller + +pci:v*d*sv*sd*bc0Dsc10* + ID_PCI_SUBCLASS_FROM_DATABASE=RF controller + +pci:v*d*sv*sd*bc0Dsc11* + ID_PCI_SUBCLASS_FROM_DATABASE=Bluetooth + +pci:v*d*sv*sd*bc0Dsc12* + ID_PCI_SUBCLASS_FROM_DATABASE=Broadband + +pci:v*d*sv*sd*bc0Dsc20* + ID_PCI_SUBCLASS_FROM_DATABASE=802.1a controller + +pci:v*d*sv*sd*bc0Dsc21* + ID_PCI_SUBCLASS_FROM_DATABASE=802.1b controller + +pci:v*d*sv*sd*bc0Dsc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Wireless controller + +pci:v*d*sv*sd*bc0E* + ID_PCI_CLASS_FROM_DATABASE=Intelligent controller + +pci:v*d*sv*sd*bc0Esc00* + ID_PCI_SUBCLASS_FROM_DATABASE=I2O + +pci:v*d*sv*sd*bc0F* + ID_PCI_CLASS_FROM_DATABASE=Satellite communications controller + +pci:v*d*sv*sd*bc0Fsc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Satellite TV controller + +pci:v*d*sv*sd*bc0Fsc02* + ID_PCI_SUBCLASS_FROM_DATABASE=Satellite audio communication controller + +pci:v*d*sv*sd*bc0Fsc03* + ID_PCI_SUBCLASS_FROM_DATABASE=Satellite voice communication controller + +pci:v*d*sv*sd*bc0Fsc04* + ID_PCI_SUBCLASS_FROM_DATABASE=Satellite data communication controller + +pci:v*d*sv*sd*bc10* + ID_PCI_CLASS_FROM_DATABASE=Encryption controller + +pci:v*d*sv*sd*bc10sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=Network and computing encryption device + +pci:v*d*sv*sd*bc10sc10* + ID_PCI_SUBCLASS_FROM_DATABASE=Entertainment encryption device + +pci:v*d*sv*sd*bc10sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Encryption controller + +pci:v*d*sv*sd*bc11* + ID_PCI_CLASS_FROM_DATABASE=Signal processing controller + +pci:v*d*sv*sd*bc11sc00* + ID_PCI_SUBCLASS_FROM_DATABASE=DPIO module + +pci:v*d*sv*sd*bc11sc01* + ID_PCI_SUBCLASS_FROM_DATABASE=Performance counters + +pci:v*d*sv*sd*bc11sc10* + ID_PCI_SUBCLASS_FROM_DATABASE=Communication synchronizer + +pci:v*d*sv*sd*bc11sc20* + ID_PCI_SUBCLASS_FROM_DATABASE=Signal processing management + +pci:v*d*sv*sd*bc11sc80* + ID_PCI_SUBCLASS_FROM_DATABASE=Signal processing controller + +pci:v*d*sv*sd*bcFF* + ID_PCI_CLASS_FROM_DATABASE=Unassigned class diff --git a/hwdb/20-pci-vendor-model.hwdb b/hwdb/20-pci-vendor-model.hwdb new file mode 100644 index 0000000..7f833e3 --- /dev/null +++ b/hwdb/20-pci-vendor-model.hwdb @@ -0,0 +1,72036 @@ +# This file is part of systemd. +# +# Data imported from: http://pci-ids.ucw.cz/v2.2/pci.ids + +pci:v00000010* + ID_VENDOR_FROM_DATABASE=Allied Telesis, Inc (Wrong ID) + +pci:v00000010d00008139* + ID_MODEL_FROM_DATABASE=AT-2500TX V3 Ethernet + +pci:v0000001C* + ID_VENDOR_FROM_DATABASE=PEAK-System Technik GmbH + +pci:v0000001Cd00000001* + ID_MODEL_FROM_DATABASE=PCAN-PCI CAN-Bus controller + +pci:v0000001Cd00000001sv0000001Csd00000004* + ID_MODEL_FROM_DATABASE=2 Channel CAN Bus SJC1000 + +pci:v0000001Cd00000001sv0000001Csd00000005* + ID_MODEL_FROM_DATABASE=2 Channel CAN Bus SJC1000 (Optically Isolated) + +pci:v0000003D* + ID_VENDOR_FROM_DATABASE=Lockheed Martin-Marietta Corp + +pci:v00000059* + ID_VENDOR_FROM_DATABASE=Tiger Jet Network Inc. (Wrong ID) + +pci:v00000070* + ID_VENDOR_FROM_DATABASE=Hauppauge computer works Inc. + +pci:v00000070d00007801* + ID_MODEL_FROM_DATABASE=WinTV HVR-1800 MCE + +pci:v00000071* + ID_VENDOR_FROM_DATABASE=Nebula Electronics Ltd. + +pci:v00000095* + ID_VENDOR_FROM_DATABASE=Silicon Image, Inc. (Wrong ID) + +pci:v00000095d00000680* + ID_MODEL_FROM_DATABASE=Ultra ATA/133 IDE RAID CONTROLLER CARD + +pci:v000000A7* + ID_VENDOR_FROM_DATABASE=Teles AG (Wrong ID) + +pci:v00000100* + ID_VENDOR_FROM_DATABASE=Ncipher Corp Ltd + +pci:v00000123* + ID_VENDOR_FROM_DATABASE=General Dynamics + +pci:v0000018A* + ID_VENDOR_FROM_DATABASE=LevelOne + +pci:v0000018Ad00000106* + ID_MODEL_FROM_DATABASE=FPC-0106TX misprogrammed [RTL81xx] + +pci:v0000021B* + ID_VENDOR_FROM_DATABASE=Compaq Computer Corporation + +pci:v0000021Bd00008139* + ID_MODEL_FROM_DATABASE=HNE-300 (RealTek RTL8139c) [iPaq Networking] + +pci:v00000270* + ID_VENDOR_FROM_DATABASE=Hauppauge computer works Inc. (Wrong ID) + +pci:v000002AC* + ID_VENDOR_FROM_DATABASE=SpeedStream + +pci:v000002ACd00001012* + ID_MODEL_FROM_DATABASE=1012 PCMCIA 10/100 Ethernet Card [RTL81xx] + +pci:v00000303* + ID_VENDOR_FROM_DATABASE=Hewlett-Packard Company (Wrong ID) + +pci:v00000308* + ID_VENDOR_FROM_DATABASE=ZyXEL Communications Corporation (Wrong ID) + +pci:v00000315* + ID_VENDOR_FROM_DATABASE=SK-Electronics Co., Ltd. + +pci:v00000357* + ID_VENDOR_FROM_DATABASE=TTTech Computertechnik AG (Wrong ID) + +pci:v00000357d0000000A* + ID_MODEL_FROM_DATABASE=TTP-Monitoring Card V2.0 + +pci:v00000432* + ID_VENDOR_FROM_DATABASE=SCM Microsystems, Inc. + +pci:v00000432d00000001* + ID_MODEL_FROM_DATABASE=Pluto2 DVB-T Receiver for PCMCIA [EasyWatch MobilSet] + +pci:v00000675* + ID_VENDOR_FROM_DATABASE=Dynalink + +pci:v00000675d00001700* + ID_MODEL_FROM_DATABASE=IS64PH ISDN Adapter + +pci:v00000675d00001702* + ID_MODEL_FROM_DATABASE=IS64PH ISDN Adapter + +pci:v00000675d00001703* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00000675d00001704* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, C) + +pci:v00000721* + ID_VENDOR_FROM_DATABASE=Sapphire, Inc. + +pci:v00000777* + ID_VENDOR_FROM_DATABASE=Ubiquiti Networks, Inc. + +pci:v00000795* + ID_VENDOR_FROM_DATABASE=Wired Inc. + +pci:v00000795d00006663* + ID_MODEL_FROM_DATABASE=Butane II (MPEG2 encoder board) + +pci:v00000795d00006666* + ID_MODEL_FROM_DATABASE=MediaPress (MPEG2 encoder board) + +pci:v000007D1* + ID_VENDOR_FROM_DATABASE=D-Link System Inc + +pci:v00000925* + ID_VENDOR_FROM_DATABASE=VIA Technologies, Inc. (Wrong ID) + +pci:v00000A89* + ID_VENDOR_FROM_DATABASE=BREA Technologies Inc + +pci:v00000B0B* + ID_VENDOR_FROM_DATABASE=Rhino Equipment Corp. + +pci:v00000B0Bd00000105* + ID_MODEL_FROM_DATABASE=Rhino R1T1 + +pci:v00000B0Bd00000205* + ID_MODEL_FROM_DATABASE=Rhino R4FXO + +pci:v00000B0Bd00000206* + ID_MODEL_FROM_DATABASE=RCB4FXO 4-channel FXO analog telphony card + +pci:v00000B0Bd00000305* + ID_MODEL_FROM_DATABASE=Rhino R4T1 + +pci:v00000B0Bd00000405* + ID_MODEL_FROM_DATABASE=Rhino R8FXX + +pci:v00000B0Bd00000406* + ID_MODEL_FROM_DATABASE=RCB8FXX 8-channel modular analog telphony card + +pci:v00000B0Bd00000505* + ID_MODEL_FROM_DATABASE=Rhino R24FXX + +pci:v00000B0Bd00000506* + ID_MODEL_FROM_DATABASE=RCB24FXS 24-Channel FXS analog telphony card + +pci:v00000B0Bd00000605* + ID_MODEL_FROM_DATABASE=Rhino R2T1 + +pci:v00000B0Bd00000705* + ID_MODEL_FROM_DATABASE=Rhino R24FXS + +pci:v00000B0Bd00000706* + ID_MODEL_FROM_DATABASE=RCB24FXO 24-Channel FXO analog telphony card + +pci:v00000B0Bd00000905* + ID_MODEL_FROM_DATABASE=R1T3 Single T3 Digital Telephony Card + +pci:v00000B0Bd00000906* + ID_MODEL_FROM_DATABASE=RCB24FXX 24-channel modular analog telphony card + +pci:v00000B0Bd00000A06* + ID_MODEL_FROM_DATABASE=RCB672FXX 672-channel modular analog telphony card + +pci:v00000E11* + ID_VENDOR_FROM_DATABASE=Compaq Computer Corporation + +pci:v00000E11d00000001* + ID_MODEL_FROM_DATABASE=PCI to EISA Bridge + +pci:v00000E11d00000002* + ID_MODEL_FROM_DATABASE=PCI to ISA Bridge + +pci:v00000E11d00000046* + ID_MODEL_FROM_DATABASE=Smart Array 64xx + +pci:v00000E11d00000046sv00000E11sd00004091* + ID_MODEL_FROM_DATABASE=Smart Array 6i + +pci:v00000E11d00000046sv00000E11sd0000409A* + ID_MODEL_FROM_DATABASE=Smart Array 641 + +pci:v00000E11d00000046sv00000E11sd0000409B* + ID_MODEL_FROM_DATABASE=Smart Array 642 + +pci:v00000E11d00000046sv00000E11sd0000409C* + ID_MODEL_FROM_DATABASE=Smart Array 6400 + +pci:v00000E11d00000046sv00000E11sd0000409D* + ID_MODEL_FROM_DATABASE=Smart Array 6400 EM + +pci:v00000E11d00000049* + ID_MODEL_FROM_DATABASE=NC7132 Gigabit Upgrade Module + +pci:v00000E11d0000004A* + ID_MODEL_FROM_DATABASE=NC6136 Gigabit Server Adapter + +pci:v00000E11d0000005A* + ID_MODEL_FROM_DATABASE=Remote Insight II board - Lights-Out + +pci:v00000E11d0000007C* + ID_MODEL_FROM_DATABASE=NC7770 1000BaseTX + +pci:v00000E11d0000007D* + ID_MODEL_FROM_DATABASE=NC6770 1000BaseTX + +pci:v00000E11d00000085* + ID_MODEL_FROM_DATABASE=NC7780 1000BaseTX + +pci:v00000E11d000000B1* + ID_MODEL_FROM_DATABASE=Remote Insight II board - PCI device + +pci:v00000E11d000000BB* + ID_MODEL_FROM_DATABASE=NC7760 + +pci:v00000E11d000000CA* + ID_MODEL_FROM_DATABASE=NC7771 + +pci:v00000E11d000000CB* + ID_MODEL_FROM_DATABASE=NC7781 + +pci:v00000E11d000000CF* + ID_MODEL_FROM_DATABASE=NC7772 + +pci:v00000E11d000000D0* + ID_MODEL_FROM_DATABASE=NC7782 + +pci:v00000E11d000000D1* + ID_MODEL_FROM_DATABASE=NC7783 + +pci:v00000E11d000000E3* + ID_MODEL_FROM_DATABASE=NC7761 + +pci:v00000E11d00000508* + ID_MODEL_FROM_DATABASE=Netelligent 4/16 Token Ring + +pci:v00000E11d00001000* + ID_MODEL_FROM_DATABASE=Triflex/Pentium Bridge, Model 1000 + +pci:v00000E11d00002000* + ID_MODEL_FROM_DATABASE=Triflex/Pentium Bridge, Model 2000 + +pci:v00000E11d00003032* + ID_MODEL_FROM_DATABASE=QVision 1280/p + +pci:v00000E11d00003033* + ID_MODEL_FROM_DATABASE=QVision 1280/p + +pci:v00000E11d00003034* + ID_MODEL_FROM_DATABASE=QVision 1280/p + +pci:v00000E11d00004000* + ID_MODEL_FROM_DATABASE=4000 [Triflex] + +pci:v00000E11d00004040* + ID_MODEL_FROM_DATABASE=Integrated Array + +pci:v00000E11d00004048* + ID_MODEL_FROM_DATABASE=Compaq Raid LC2 + +pci:v00000E11d00004050* + ID_MODEL_FROM_DATABASE=Smart Array 4200 + +pci:v00000E11d00004051* + ID_MODEL_FROM_DATABASE=Smart Array 4250ES + +pci:v00000E11d00004058* + ID_MODEL_FROM_DATABASE=Smart Array 431 + +pci:v00000E11d00004070* + ID_MODEL_FROM_DATABASE=Smart Array 5300 + +pci:v00000E11d00004080* + ID_MODEL_FROM_DATABASE=Smart Array 5i + +pci:v00000E11d00004082* + ID_MODEL_FROM_DATABASE=Smart Array 532 + +pci:v00000E11d00004083* + ID_MODEL_FROM_DATABASE=Smart Array 5312 + +pci:v00000E11d00004091* + ID_MODEL_FROM_DATABASE=Smart Array 6i + +pci:v00000E11d0000409A* + ID_MODEL_FROM_DATABASE=Smart Array 641 + +pci:v00000E11d0000409B* + ID_MODEL_FROM_DATABASE=Smart Array 642 + +pci:v00000E11d0000409C* + ID_MODEL_FROM_DATABASE=Smart Array 6400 + +pci:v00000E11d0000409D* + ID_MODEL_FROM_DATABASE=Smart Array 6400 EM + +pci:v00000E11d00006010* + ID_MODEL_FROM_DATABASE=HotPlug PCI Bridge 6010 + +pci:v00000E11d00007020* + ID_MODEL_FROM_DATABASE=USB Controller + +pci:v00000E11d0000A0EC* + ID_MODEL_FROM_DATABASE=Fibre Channel Host Controller + +pci:v00000E11d0000A0F0* + ID_MODEL_FROM_DATABASE=Advanced System Management Controller + +pci:v00000E11d0000A0F0sv00000E11sd0000B0F3* + ID_MODEL_FROM_DATABASE=ProLiant DL360 + +pci:v00000E11d0000A0F3* + ID_MODEL_FROM_DATABASE=Triflex PCI to ISA Bridge + +pci:v00000E11d0000A0F7* + ID_MODEL_FROM_DATABASE=PCI Hotplug Controller + +pci:v00000E11d0000A0F7sv00008086sd0000002A* + ID_MODEL_FROM_DATABASE=PCI Hotplug Controller A + +pci:v00000E11d0000A0F7sv00008086sd0000002B* + ID_MODEL_FROM_DATABASE=PCI Hotplug Controller B + +pci:v00000E11d0000A0F8* + ID_MODEL_FROM_DATABASE=ZFMicro Chipset USB + +pci:v00000E11d0000A0FC* + ID_MODEL_FROM_DATABASE=FibreChannel HBA Tachyon + +pci:v00000E11d0000AE10* + ID_MODEL_FROM_DATABASE=Smart-2/P RAID Controller + +pci:v00000E11d0000AE10sv00000E11sd00004030* + ID_MODEL_FROM_DATABASE=Smart-2/P Array Controller + +pci:v00000E11d0000AE10sv00000E11sd00004031* + ID_MODEL_FROM_DATABASE=Smart-2SL Array Controller + +pci:v00000E11d0000AE10sv00000E11sd00004032* + ID_MODEL_FROM_DATABASE=Smart Array 3200 Controller + +pci:v00000E11d0000AE10sv00000E11sd00004033* + ID_MODEL_FROM_DATABASE=Smart Array 3100ES Controller + +pci:v00000E11d0000AE10sv00000E11sd00004034* + ID_MODEL_FROM_DATABASE=Smart Array 221 Controller + +pci:v00000E11d0000AE29* + ID_MODEL_FROM_DATABASE=MIS-L + +pci:v00000E11d0000AE2A* + ID_MODEL_FROM_DATABASE=MPC + +pci:v00000E11d0000AE2B* + ID_MODEL_FROM_DATABASE=MIS-E + +pci:v00000E11d0000AE31* + ID_MODEL_FROM_DATABASE=System Management Controller + +pci:v00000E11d0000AE32* + ID_MODEL_FROM_DATABASE=Netelligent 10/100 TX PCI UTP + +pci:v00000E11d0000AE33* + ID_MODEL_FROM_DATABASE=Triflex Dual EIDE Controller + +pci:v00000E11d0000AE34* + ID_MODEL_FROM_DATABASE=Netelligent 10 T PCI UTP + +pci:v00000E11d0000AE35* + ID_MODEL_FROM_DATABASE=Integrated NetFlex-3/P + +pci:v00000E11d0000AE40* + ID_MODEL_FROM_DATABASE=Netelligent Dual 10/100 TX PCI UTP + +pci:v00000E11d0000AE43* + ID_MODEL_FROM_DATABASE=Netelligent Integrated 10/100 TX UTP + +pci:v00000E11d0000AE69* + ID_MODEL_FROM_DATABASE=CETUS-L + +pci:v00000E11d0000AE6C* + ID_MODEL_FROM_DATABASE=Northstar + +pci:v00000E11d0000AE6D* + ID_MODEL_FROM_DATABASE=NorthStar CPU to PCI Bridge + +pci:v00000E11d0000B011* + ID_MODEL_FROM_DATABASE=Netelligent 10/100 TX Embedded UTP + +pci:v00000E11d0000B012* + ID_MODEL_FROM_DATABASE=Netelligent 10 T/2 PCI UTP/Coax + +pci:v00000E11d0000B01E* + ID_MODEL_FROM_DATABASE=NC3120 Fast Ethernet NIC + +pci:v00000E11d0000B01F* + ID_MODEL_FROM_DATABASE=NC3122 Fast Ethernet NIC + +pci:v00000E11d0000B02F* + ID_MODEL_FROM_DATABASE=NC1120 Ethernet NIC + +pci:v00000E11d0000B030* + ID_MODEL_FROM_DATABASE=Netelligent 10/100 TX UTP + +pci:v00000E11d0000B04A* + ID_MODEL_FROM_DATABASE=10/100 TX PCI Intel WOL UTP Controller + +pci:v00000E11d0000B060* + ID_MODEL_FROM_DATABASE=Smart Array 5300 Controller + +pci:v00000E11d0000B0C6* + ID_MODEL_FROM_DATABASE=NC3161 Fast Ethernet NIC + +pci:v00000E11d0000B0C7* + ID_MODEL_FROM_DATABASE=NC3160 Fast Ethernet NIC + +pci:v00000E11d0000B0D7* + ID_MODEL_FROM_DATABASE=NC3121 Fast Ethernet NIC + +pci:v00000E11d0000B0DD* + ID_MODEL_FROM_DATABASE=NC3131 Fast Ethernet NIC + +pci:v00000E11d0000B0DE* + ID_MODEL_FROM_DATABASE=NC3132 Fast Ethernet Module + +pci:v00000E11d0000B0DF* + ID_MODEL_FROM_DATABASE=NC6132 Gigabit Module + +pci:v00000E11d0000B0E0* + ID_MODEL_FROM_DATABASE=NC6133 Gigabit Module + +pci:v00000E11d0000B0E1* + ID_MODEL_FROM_DATABASE=NC3133 Fast Ethernet Module + +pci:v00000E11d0000B123* + ID_MODEL_FROM_DATABASE=NC6134 Gigabit NIC + +pci:v00000E11d0000B134* + ID_MODEL_FROM_DATABASE=NC3163 Fast Ethernet NIC + +pci:v00000E11d0000B13C* + ID_MODEL_FROM_DATABASE=NC3162 Fast Ethernet NIC + +pci:v00000E11d0000B144* + ID_MODEL_FROM_DATABASE=NC3123 Fast Ethernet NIC + +pci:v00000E11d0000B163* + ID_MODEL_FROM_DATABASE=NC3134 Fast Ethernet NIC + +pci:v00000E11d0000B164* + ID_MODEL_FROM_DATABASE=NC3165 Fast Ethernet Upgrade Module + +pci:v00000E11d0000B178* + ID_MODEL_FROM_DATABASE=Smart Array 5i/532 + +pci:v00000E11d0000B178sv00000E11sd00004080* + ID_MODEL_FROM_DATABASE=Smart Array 5i + +pci:v00000E11d0000B178sv00000E11sd00004082* + ID_MODEL_FROM_DATABASE=Smart Array 532 + +pci:v00000E11d0000B178sv00000E11sd00004083* + ID_MODEL_FROM_DATABASE=Smart Array 5312 + +pci:v00000E11d0000B1A4* + ID_MODEL_FROM_DATABASE=NC7131 Gigabit Server Adapter + +pci:v00000E11d0000B200* + ID_MODEL_FROM_DATABASE=Memory Hot-Plug Controller + +pci:v00000E11d0000B203* + ID_MODEL_FROM_DATABASE=Integrated Lights Out Controller + +pci:v00000E11d0000B204* + ID_MODEL_FROM_DATABASE=Integrated Lights Out Processor + +pci:v00000E11d0000C000* + ID_MODEL_FROM_DATABASE=Remote Insight Lights-Out Edition + +pci:v00000E11d0000F130* + ID_MODEL_FROM_DATABASE=NetFlex-3/P ThunderLAN 1.0 + +pci:v00000E11d0000F150* + ID_MODEL_FROM_DATABASE=NetFlex-3/P ThunderLAN 2.3 + +pci:v00000EAC* + ID_VENDOR_FROM_DATABASE=SHF Communication Technologies AG + +pci:v00000EACd00000008* + ID_MODEL_FROM_DATABASE=Ethernet Powerlink Managing Node 01 + +pci:v00000F62* + ID_VENDOR_FROM_DATABASE=Acrox Technologies Co., Ltd. + +pci:v00001000* + ID_VENDOR_FROM_DATABASE=LSI Logic / Symbios Logic + +pci:v00001000d00000001* + ID_MODEL_FROM_DATABASE=53c810 + +pci:v00001000d00000001sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C810AE PCI to SCSI I/O Processor + +pci:v00001000d00000002* + ID_MODEL_FROM_DATABASE=53c820 + +pci:v00001000d00000003* + ID_MODEL_FROM_DATABASE=53c825 + +pci:v00001000d00000003sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C825AE PCI to SCSI I/O Processor (Ultra Wide) + +pci:v00001000d00000004* + ID_MODEL_FROM_DATABASE=53c815 + +pci:v00001000d00000005* + ID_MODEL_FROM_DATABASE=53c810AP + +pci:v00001000d00000006* + ID_MODEL_FROM_DATABASE=53c860 + +pci:v00001000d00000006sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C860E PCI to Ultra SCSI I/O Processor + +pci:v00001000d0000000A* + ID_MODEL_FROM_DATABASE=53c1510 + +pci:v00001000d0000000Asv00000E11sd0000B143* + ID_MODEL_FROM_DATABASE=Integrated Dual Channel Wide Ultra2 SCSI Controller + +pci:v00001000d0000000Asv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode) + +pci:v00001000d0000000B* + ID_MODEL_FROM_DATABASE=53C896/897 + +pci:v00001000d0000000Bsv00000E11sd00006004* + ID_MODEL_FROM_DATABASE=EOB003 Series SCSI host adapter + +pci:v00001000d0000000Bsv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller + +pci:v00001000d0000000Bsv00001000sd00001010* + ID_MODEL_FROM_DATABASE=LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter + +pci:v00001000d0000000Bsv00001000sd00001020* + ID_MODEL_FROM_DATABASE=LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter + +pci:v00001000d0000000Bsv000013E9sd00001000* + ID_MODEL_FROM_DATABASE=6221L-4U (Dual U2W SCSI, dual 10/100TX, graphics) + +pci:v00001000d0000000C* + ID_MODEL_FROM_DATABASE=53c895 + +pci:v00001000d0000000Csv00001000sd00001010* + ID_MODEL_FROM_DATABASE=LSI8951U PCI to Ultra2 SCSI host adapter + +pci:v00001000d0000000Csv00001000sd00001020* + ID_MODEL_FROM_DATABASE=LSI8952U PCI to Ultra2 SCSI host adapter + +pci:v00001000d0000000Csv00001DE1sd00003906* + ID_MODEL_FROM_DATABASE=DC-390U2B SCSI adapter + +pci:v00001000d0000000Csv00001DE1sd00003907* + ID_MODEL_FROM_DATABASE=DC-390U2W + +pci:v00001000d0000000D* + ID_MODEL_FROM_DATABASE=53c885 + +pci:v00001000d0000000F* + ID_MODEL_FROM_DATABASE=53c875 + +pci:v00001000d0000000Fsv00000E11sd00007004* + ID_MODEL_FROM_DATABASE=Embedded Ultra Wide SCSI Controller + +pci:v00001000d0000000Fsv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C876/E PCI to Dual Channel SCSI Controller + +pci:v00001000d0000000Fsv00001000sd00001010* + ID_MODEL_FROM_DATABASE=LSI22801 PCI to Dual Channel Ultra SCSI host adapter + +pci:v00001000d0000000Fsv00001000sd00001020* + ID_MODEL_FROM_DATABASE=LSI22802 PCI to Dual Channel Ultra SCSI host adapter + +pci:v00001000d0000000Fsv00001092sd00008760* + ID_MODEL_FROM_DATABASE=FirePort 40 Dual SCSI Controller + +pci:v00001000d0000000Fsv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer Wide Ultra SCSI + +pci:v00001000d0000000Fsv00001775sd000010D1* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer Ultra SCSI + +pci:v00001000d0000000Fsv00001DE1sd00003904* + ID_MODEL_FROM_DATABASE=DC390F/U Ultra Wide SCSI Adapter + +pci:v00001000d0000000Fsv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v00001000d0000000Fsv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00001000d00000010* + ID_MODEL_FROM_DATABASE=53C1510 + +pci:v00001000d00000010sv00000E11sd00004040* + ID_MODEL_FROM_DATABASE=Integrated Smart Array Controller + +pci:v00001000d00000010sv00000E11sd00004048* + ID_MODEL_FROM_DATABASE=RAID LC2 Controller + +pci:v00001000d00000010sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode) + +pci:v00001000d00000012* + ID_MODEL_FROM_DATABASE=53c895a + +pci:v00001000d00000012sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C895A PCI to Ultra2 SCSI Controller + +pci:v00001000d00000013* + ID_MODEL_FROM_DATABASE=53c875a + +pci:v00001000d00000013sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C875A PCI to Ultra SCSI Controller + +pci:v00001000d00000020* + ID_MODEL_FROM_DATABASE=53c1010 Ultra3 SCSI Adapter + +pci:v00001000d00000020sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C1010-33 PCI to Dual Channel Ultra160 SCSI Controller + +pci:v00001000d00000020sv0000107Bsd00001040* + ID_MODEL_FROM_DATABASE=Server Onboard 53C1010-33 + +pci:v00001000d00000020sv00001DE1sd00001020* + ID_MODEL_FROM_DATABASE=DC-390U3W + +pci:v00001000d00000021* + ID_MODEL_FROM_DATABASE=53c1010 66MHz Ultra3 SCSI Adapter + +pci:v00001000d00000021sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller + +pci:v00001000d00000021sv00001000sd00001010* + ID_MODEL_FROM_DATABASE=Asus TR-DLS onboard 53C1010-66 + +pci:v00001000d00000021sv0000103Csd00001300* + ID_MODEL_FROM_DATABASE=Ultra160 SCSI [AB306A] + +pci:v00001000d00000021sv0000103Csd00001310* + ID_MODEL_FROM_DATABASE=Ultra160 SCSI [A9918A] + +pci:v00001000d00000021sv0000103Csd00001330* + ID_MODEL_FROM_DATABASE=Ultra160 SCSI [A7059A] + +pci:v00001000d00000021sv0000103Csd00001340* + ID_MODEL_FROM_DATABASE=Ultra160 SCSI [A7060A] + +pci:v00001000d00000021sv0000124Bsd00001070* + ID_MODEL_FROM_DATABASE=PMC-USCSI3 + +pci:v00001000d00000021sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00001000d00000021sv00004C53sd00001300* + ID_MODEL_FROM_DATABASE=P017 mezzanine (32-bit PMC) + +pci:v00001000d00000021sv00004C53sd00001310* + ID_MODEL_FROM_DATABASE=P017 mezzanine (64-bit PMC) + +pci:v00001000d0000002F* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 IOV [Thunderbolt] + +pci:v00001000d0000002Fsv00001028sd00001F3E* + ID_MODEL_FROM_DATABASE=SPERC 8 + +pci:v00001000d00000030* + ID_MODEL_FROM_DATABASE=53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000030sv00000E11sd000000DA* + ID_MODEL_FROM_DATABASE=ProLiant ML 350 + +pci:v00001000d00000030sv00001028sd00000123* + ID_MODEL_FROM_DATABASE=LSI Logic 1020/1030 + +pci:v00001000d00000030sv00001028sd0000014A* + ID_MODEL_FROM_DATABASE=LSI Logic 1020/1030 + +pci:v00001000d00000030sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 MPT Fusion SCSI/RAID (Perc 4) + +pci:v00001000d00000030sv00001028sd00000183* + ID_MODEL_FROM_DATABASE=LSI Logic 1020/1030 + +pci:v00001000d00000030sv00001028sd0000018A* + ID_MODEL_FROM_DATABASE=PERC 4/IM + +pci:v00001000d00000030sv00001028sd00001010* + ID_MODEL_FROM_DATABASE=LSI U320 SCSI Controller + +pci:v00001000d00000030sv0000103Csd000012C5* + ID_MODEL_FROM_DATABASE=Ultra320 SCSI [A7173A] + +pci:v00001000d00000030sv0000103Csd00001323* + ID_MODEL_FROM_DATABASE=Core I/O LAN/SCSI Combo [AB314A] + +pci:v00001000d00000030sv0000103Csd00003108* + ID_MODEL_FROM_DATABASE=Single Channel Ultra320 SCSI HBA G2 + +pci:v00001000d00000030sv0000124Bsd00001170* + ID_MODEL_FROM_DATABASE=PMC-USCSI320 + +pci:v00001000d00000030sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=LSI Logic Parallel SCSI Controller + +pci:v00001000d00000030sv00001734sd00001052* + ID_MODEL_FROM_DATABASE=PRIMERGY BX/RX/TX S2 series onboard SCSI(IME) + +pci:v00001000d00000031* + ID_MODEL_FROM_DATABASE=53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000032* + ID_MODEL_FROM_DATABASE=53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000032sv00001000sd00001000* + ID_MODEL_FROM_DATABASE=LSI53C1020/1030 PCI-X to Ultra320 SCSI Controller + +pci:v00001000d00000033* + ID_MODEL_FROM_DATABASE=1030ZC_53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000040* + ID_MODEL_FROM_DATABASE=53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000040sv00001000sd00000033* + ID_MODEL_FROM_DATABASE=MegaRAID SCSI 320-2XR + +pci:v00001000d00000040sv00001000sd00000066* + ID_MODEL_FROM_DATABASE=MegaRAID SCSI 320-2XRWS + +pci:v00001000d00000041* + ID_MODEL_FROM_DATABASE=53C1035ZC PCI-X Fusion-MPT Dual Ultra320 SCSI + +pci:v00001000d00000050* + ID_MODEL_FROM_DATABASE=SAS1064 PCI-X Fusion-MPT SAS + +pci:v00001000d00000050sv00001028sd00001F04* + ID_MODEL_FROM_DATABASE=SAS 5/E + +pci:v00001000d00000050sv00001028sd00001F09* + ID_MODEL_FROM_DATABASE=SAS 5i/R + +pci:v00001000d00000054* + ID_MODEL_FROM_DATABASE=SAS1068 PCI-X Fusion-MPT SAS + +pci:v00001000d00000054sv00001028sd00001F04* + ID_MODEL_FROM_DATABASE=SAS 5/E Adapter Controller + +pci:v00001000d00000054sv00001028sd00001F05* + ID_MODEL_FROM_DATABASE=SAS 5/i Adapter Controller + +pci:v00001000d00000054sv00001028sd00001F06* + ID_MODEL_FROM_DATABASE=SAS 5/i Integrated Controller + +pci:v00001000d00000054sv00001028sd00001F07* + ID_MODEL_FROM_DATABASE=SAS 5/iR Integrated RAID Controller + +pci:v00001000d00000054sv00001028sd00001F08* + ID_MODEL_FROM_DATABASE=SAS 5/iR Integrated RAID Controller + +pci:v00001000d00000054sv00001028sd00001F09* + ID_MODEL_FROM_DATABASE=SAS 5/iR Adapter RAID Controller + +pci:v00001000d00000054sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=SAS Controller + +pci:v00001000d00000055* + ID_MODEL_FROM_DATABASE=SAS1068 PCI-X Fusion-MPT SAS + +pci:v00001000d00000055sv00001033sd00008336* + ID_MODEL_FROM_DATABASE=SAS1068 + +pci:v00001000d00000056* + ID_MODEL_FROM_DATABASE=SAS1064ET PCI-Express Fusion-MPT SAS + +pci:v00001000d00000056sv00001014sd000003BB* + ID_MODEL_FROM_DATABASE=ServeRAID BR10il SAS/SATA Controller v2 + +pci:v00001000d00000057* + ID_MODEL_FROM_DATABASE=M1064E MegaRAID SAS + +pci:v00001000d00000057sv00008086sd0000346C* + ID_MODEL_FROM_DATABASE=Embedded Software RAID Technology II (ESTRII) + +pci:v00001000d00000058* + ID_MODEL_FROM_DATABASE=SAS1068E PCI-Express Fusion-MPT SAS + +pci:v00001000d00000058sv00001000sd00003140* + ID_MODEL_FROM_DATABASE=SAS3081E-R 8-Port SAS/SATA Host Bus Adapter + +pci:v00001000d00000058sv00001028sd0000021D* + ID_MODEL_FROM_DATABASE=SAS 6/iR Integrated Workstations RAID Controller + +pci:v00001000d00000058sv00001028sd00001F0E* + ID_MODEL_FROM_DATABASE=SAS 6/iR Adapter RAID Controller + +pci:v00001000d00000058sv00001028sd00001F0F* + ID_MODEL_FROM_DATABASE=SAS 6/iR Integrated Blades RAID Controller + +pci:v00001000d00000058sv00001028sd00001F10* + ID_MODEL_FROM_DATABASE=SAS 6/iR Integrated RAID Controller + +pci:v00001000d00000058sv0000103Csd00003229* + ID_MODEL_FROM_DATABASE=SC44Ge Host Bus Adapter + +pci:v00001000d00000059* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8208ELP/8208ELP + +pci:v00001000d0000005A* + ID_MODEL_FROM_DATABASE=SAS1066E PCI-Express Fusion-MPT SAS + +pci:v00001000d0000005B* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 [Thunderbolt] + +pci:v00001000d0000005Bsv00001000sd00009265* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9265-8i + +pci:v00001000d0000005Bsv00001000sd00009266* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9266-8i + +pci:v00001000d0000005Bsv00001000sd00009267* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9267-8i + +pci:v00001000d0000005Bsv00001000sd00009268* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9265CV-8i / 9270CV-8i + +pci:v00001000d0000005Bsv00001000sd00009269* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9266-4i + +pci:v00001000d0000005Bsv00001000sd00009270* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9270-8i + +pci:v00001000d0000005Bsv00001000sd00009271* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9271-8i + +pci:v00001000d0000005Bsv00001000sd00009272* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9272-8i + +pci:v00001000d0000005Bsv00001000sd00009273* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9270CV-8i + +pci:v00001000d0000005Bsv00001000sd00009274* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9270-4i + +pci:v00001000d0000005Bsv00001000sd00009275* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9271-8iCC + +pci:v00001000d0000005Bsv00001000sd00009276* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9271-4i + +pci:v00001000d0000005Bsv00001000sd00009285* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9285-8e + +pci:v00001000d0000005Bsv00001000sd00009288* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9285CV-8e + +pci:v00001000d0000005Bsv00001000sd00009290* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9286-8e + +pci:v00001000d0000005Bsv00001000sd00009291* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9286CV-8e + +pci:v00001000d0000005Bsv00001000sd00009295* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9286CV-8eCC + +pci:v00001000d0000005Bsv00001014sd0000040B* + ID_MODEL_FROM_DATABASE=ServeRAID M5110 SAS/SATA Controller + +pci:v00001000d0000005Bsv00001014sd00000412* + ID_MODEL_FROM_DATABASE=ServeRAID M5110e SAS/SATA Controller + +pci:v00001000d0000005Bsv00001028sd00001F2D* + ID_MODEL_FROM_DATABASE=PERC H810 Adapter + +pci:v00001000d0000005Bsv00001028sd00001F30* + ID_MODEL_FROM_DATABASE=PERC H710 Embedded + +pci:v00001000d0000005Bsv00001028sd00001F31* + ID_MODEL_FROM_DATABASE=PERC H710P Adapter + +pci:v00001000d0000005Bsv00001028sd00001F33* + ID_MODEL_FROM_DATABASE=PERC H710P Mini (for blades) + +pci:v00001000d0000005Bsv00001028sd00001F34* + ID_MODEL_FROM_DATABASE=PERC H710P Mini (for monolithics) + +pci:v00001000d0000005Bsv00001028sd00001F35* + ID_MODEL_FROM_DATABASE=PERC H710 Adapter + +pci:v00001000d0000005Bsv00001028sd00001F37* + ID_MODEL_FROM_DATABASE=PERC H710 Mini (for blades) + +pci:v00001000d0000005Bsv00001028sd00001F38* + ID_MODEL_FROM_DATABASE=PERC H710 Mini (for monolithics) + +pci:v00001000d0000005Bsv00008086sd00003510* + ID_MODEL_FROM_DATABASE=RMS25PB080 RAID Controller + +pci:v00001000d0000005Bsv00008086sd00003513* + ID_MODEL_FROM_DATABASE=RMS25CB080 RAID Controller + +pci:v00001000d0000005C* + ID_MODEL_FROM_DATABASE=SAS1064A PCI-X Fusion-MPT SAS + +pci:v00001000d0000005D* + ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] + +pci:v00001000d0000005Dsv00001028sd00001F41* + ID_MODEL_FROM_DATABASE=PERC H830 Adapter + +pci:v00001000d0000005Dsv00001028sd00001F42* + ID_MODEL_FROM_DATABASE=PERC H730P Adapter + +pci:v00001000d0000005Dsv00001028sd00001F43* + ID_MODEL_FROM_DATABASE=PERC H730 Adapter + +pci:v00001000d0000005Dsv00001028sd00001F47* + ID_MODEL_FROM_DATABASE=PERC H730P Mini + +pci:v00001000d0000005Dsv00001028sd00001F48* + ID_MODEL_FROM_DATABASE=PERC H730P Mini (for blades) + +pci:v00001000d0000005Dsv00001028sd00001F49* + ID_MODEL_FROM_DATABASE=PERC H730 Mini + +pci:v00001000d0000005Dsv00001028sd00001F4A* + ID_MODEL_FROM_DATABASE=PERC H730 Mini (for blades) + +pci:v00001000d0000005E* + ID_MODEL_FROM_DATABASE=SAS1066 PCI-X Fusion-MPT SAS + +pci:v00001000d0000005F* + ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3008 [Fury] + +pci:v00001000d0000005Fsv00001028sd00001F44* + ID_MODEL_FROM_DATABASE=PERC H330 Adapter + +pci:v00001000d0000005Fsv00001028sd00001F4B* + ID_MODEL_FROM_DATABASE=PERC H330 Mini + +pci:v00001000d0000005Fsv00001028sd00001F4C* + ID_MODEL_FROM_DATABASE=PERC H330 Mini (for blades) + +pci:v00001000d0000005Fsv00001028sd00001F4D* + ID_MODEL_FROM_DATABASE=PERC H330 Embedded (for monolithic) + +pci:v00001000d00000060* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 1078 + +pci:v00001000d00000060sv00001000sd00001006* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8888ELP + +pci:v00001000d00000060sv00001000sd0000100A* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8708ELP + +pci:v00001000d00000060sv00001000sd0000100E* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8884E + +pci:v00001000d00000060sv00001000sd0000100F* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8708E + +pci:v00001000d00000060sv00001000sd00001010* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 350-8ELP + +pci:v00001000d00000060sv00001000sd00001011* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 350-4ELP + +pci:v00001000d00000060sv00001000sd00001012* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8704ELP + +pci:v00001000d00000060sv00001000sd00001016* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8880EM2 + +pci:v00001000d00000060sv00001014sd00000363* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv00001014sd00000364* + ID_MODEL_FROM_DATABASE=SystemX MegaRAID SAS 8808E + +pci:v00001000d00000060sv00001014sd00000365* + ID_MODEL_FROM_DATABASE=SystemX MegaRAID SAS 8884E + +pci:v00001000d00000060sv00001014sd00000379* + ID_MODEL_FROM_DATABASE=SystemX MegaRAID SAS 8880EM2 + +pci:v00001000d00000060sv00001028sd00001F0A* + ID_MODEL_FROM_DATABASE=PERC 6/E Adapter RAID Controller + +pci:v00001000d00000060sv00001028sd00001F0B* + ID_MODEL_FROM_DATABASE=PERC 6/i Adapter RAID Controller + +pci:v00001000d00000060sv00001028sd00001F0C* + ID_MODEL_FROM_DATABASE=PERC 6/i Integrated RAID Controller + +pci:v00001000d00000060sv00001028sd00001F0D* + ID_MODEL_FROM_DATABASE=PERC 6/i Integrated RAID Controller + +pci:v00001000d00000060sv00001028sd00001F11* + ID_MODEL_FROM_DATABASE=CERC 6/i Integrated RAID Controller + +pci:v00001000d00000060sv00001033sd0000835A* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv00001043sd0000824D* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv00001170sd0000002F* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv00001170sd00000036* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv000015D9sd0000C080* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv000017AAsd00006B7C* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv000018A1sd00000003* + ID_MODEL_FROM_DATABASE=LSI MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000060sv00008086sd00001006* + ID_MODEL_FROM_DATABASE=RAID Controller SRCSAS28EP + +pci:v00001000d00000060sv00008086sd0000100A* + ID_MODEL_FROM_DATABASE=RAID Controller SRCSAS28EV + +pci:v00001000d00000060sv00008086sd00001010* + ID_MODEL_FROM_DATABASE=RAID Controller SRCSATA28E + +pci:v00001000d00000060sv00008086sd000034CC* + ID_MODEL_FROM_DATABASE=Integrated RAID Controller SROMBSAS28E + +pci:v00001000d00000060sv00008086sd000034CD* + ID_MODEL_FROM_DATABASE=Integrated RAID Controller SROMBSAS28E + +pci:v00001000d00000060sv00008086sd00003505* + ID_MODEL_FROM_DATABASE=Integrated RAID Controller SROMBSASMP2 + +pci:v00001000d00000062* + ID_MODEL_FROM_DATABASE=SAS1078 PCI-Express Fusion-MPT SAS + +pci:v00001000d00000062sv00001000sd00000062* + ID_MODEL_FROM_DATABASE=SAS1078 PCI-Express Fusion-MPT SAS + +pci:v00001000d00000064* + ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor] + +pci:v00001000d00000065* + ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor] + +pci:v00001000d0000006E* + ID_MODEL_FROM_DATABASE=SAS2308 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000070* + ID_MODEL_FROM_DATABASE=SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire] + +pci:v00001000d00000071* + ID_MODEL_FROM_DATABASE=MR SAS HBA 2004 + +pci:v00001000d00000072* + ID_MODEL_FROM_DATABASE=SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon] + +pci:v00001000d00000072sv00001028sd00001F1C* + ID_MODEL_FROM_DATABASE=6Gbps SAS HBA Adapter + +pci:v00001000d00000072sv00001028sd00001F1D* + ID_MODEL_FROM_DATABASE=PERC H200 Adapter + +pci:v00001000d00000072sv00001028sd00001F1E* + ID_MODEL_FROM_DATABASE=PERC H200 Integrated + +pci:v00001000d00000072sv00001028sd00001F1F* + ID_MODEL_FROM_DATABASE=PERC H200 Modular + +pci:v00001000d00000072sv00001028sd00001F20* + ID_MODEL_FROM_DATABASE=PERC H200 Embedded + +pci:v00001000d00000072sv00001028sd00001F22* + ID_MODEL_FROM_DATABASE=Internal Tape Adapter + +pci:v00001000d00000072sv00008086sd0000350F* + ID_MODEL_FROM_DATABASE=RMS2LL040 RAID Controller + +pci:v00001000d00000073* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 2008 [Falcon] + +pci:v00001000d00000073sv00001000sd00009240* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9240-8i + +pci:v00001000d00000073sv00001000sd00009241* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9240-4i + +pci:v00001000d00000073sv00001000sd000092A0* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9220-8i + +pci:v00001000d00000073sv00001014sd000003B1* + ID_MODEL_FROM_DATABASE=ServeRAID M1015 SAS/SATA Controller + +pci:v00001000d00000073sv00001028sd00001F4E* + ID_MODEL_FROM_DATABASE=PERC H310 Adapter + +pci:v00001000d00000073sv00001028sd00001F4F* + ID_MODEL_FROM_DATABASE=PERC H310 Integrated + +pci:v00001000d00000073sv00001028sd00001F50* + ID_MODEL_FROM_DATABASE=PERC H310 Mini Blades + +pci:v00001000d00000073sv00001028sd00001F51* + ID_MODEL_FROM_DATABASE=PERC H310 Mini Monolithics + +pci:v00001000d00000073sv00001028sd00001F52* + ID_MODEL_FROM_DATABASE=PERC H310 Embedded1 + +pci:v00001000d00000073sv00001028sd00001F53* + ID_MODEL_FROM_DATABASE=PERC H310 Embedded2 + +pci:v00001000d00000073sv00001028sd00001F54* + ID_MODEL_FROM_DATABASE=PERC H310 Reserved + +pci:v00001000d00000073sv00001054sd00003035* + ID_MODEL_FROM_DATABASE=LSI MegaRAID SAS 9240-8i + +pci:v00001000d00000073sv00001137sd00000072* + ID_MODEL_FROM_DATABASE=2004 iMR ROMB + +pci:v00001000d00000073sv00001137sd00000073* + ID_MODEL_FROM_DATABASE=2008 ROMB + +pci:v00001000d00000073sv00001137sd000000B0* + ID_MODEL_FROM_DATABASE=UCSC RAID SAS 2008M-8i + +pci:v00001000d00000073sv00001137sd000000B1* + ID_MODEL_FROM_DATABASE=UCSC RAID SAS 2008M-8i + +pci:v00001000d00000073sv000015D9sd00000400* + ID_MODEL_FROM_DATABASE=Supermicro SMC2008-iMR + +pci:v00001000d00000073sv00001734sd00001177* + ID_MODEL_FROM_DATABASE=RAID Ctrl SAS 6G 0/1 (D2607) + +pci:v00001000d00000073sv00008086sd0000350D* + ID_MODEL_FROM_DATABASE=RMS2AF040 RAID Controller + +pci:v00001000d00000073sv00008086sd00009240* + ID_MODEL_FROM_DATABASE=RAID Controller RS2WC080 + +pci:v00001000d00000073sv00008086sd00009241* + ID_MODEL_FROM_DATABASE=RAID Controller RS2WC040 + +pci:v00001000d00000074* + ID_MODEL_FROM_DATABASE=SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator] + +pci:v00001000d00000076* + ID_MODEL_FROM_DATABASE=SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator] + +pci:v00001000d00000077* + ID_MODEL_FROM_DATABASE=SAS2108 PCI-Express Fusion-MPT SAS-2 [Liberator] + +pci:v00001000d00000079* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 2108 [Liberator] + +pci:v00001000d00000079sv00001000sd00009251* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260-4ix + +pci:v00001000d00000079sv00001000sd00009256* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260-8ix + +pci:v00001000d00000079sv00001000sd00009260* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260-4i + +pci:v00001000d00000079sv00001000sd00009261* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260-8i + +pci:v00001000d00000079sv00001000sd00009262* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9262-8i + +pci:v00001000d00000079sv00001000sd00009263* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9261-8i + +pci:v00001000d00000079sv00001000sd00009264* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9264-8i + +pci:v00001000d00000079sv00001000sd00009267* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260CV-4i + +pci:v00001000d00000079sv00001000sd00009268* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260CV-8i + +pci:v00001000d00000079sv00001000sd00009275* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9280-8ex + +pci:v00001000d00000079sv00001000sd00009276* + ID_MODEL_FROM_DATABASE=MR9260-16i + +pci:v00001000d00000079sv00001000sd00009280* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9280-8e + +pci:v00001000d00000079sv00001000sd00009281* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9281-8E + +pci:v00001000d00000079sv00001000sd00009282* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9280-4i4e + +pci:v00001000d00000079sv00001000sd00009290* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9280DE-24i4e + +pci:v00001000d00000079sv00001014sd000003B2* + ID_MODEL_FROM_DATABASE=ServeRAID M5015 SAS/SATA Controller + +pci:v00001000d00000079sv00001014sd000003B3* + ID_MODEL_FROM_DATABASE=ServeRAID M5025 SAS/SATA Controller + +pci:v00001000d00000079sv00001028sd00001F15* + ID_MODEL_FROM_DATABASE=PERC H800 Adapter + +pci:v00001000d00000079sv00001028sd00001F16* + ID_MODEL_FROM_DATABASE=PERC H700 Adapter + +pci:v00001000d00000079sv00001028sd00001F17* + ID_MODEL_FROM_DATABASE=PERC H700 Integrated + +pci:v00001000d00000079sv00001028sd00001F18* + ID_MODEL_FROM_DATABASE=PERC H700 Modular + +pci:v00001000d00000079sv00001028sd00001F1A* + ID_MODEL_FROM_DATABASE=PERC H800 Proto Adapter + +pci:v00001000d00000079sv00001028sd00001F1B* + ID_MODEL_FROM_DATABASE=PERC H700 Integrated + +pci:v00001000d00000079sv00001043sd00008480* + ID_MODEL_FROM_DATABASE=PIKE-2108 16PD + +pci:v00001000d00000079sv00001734sd00001176* + ID_MODEL_FROM_DATABASE=RAID Ctrl SAS 6G 5/6 512MB (D2616) + +pci:v00001000d00000079sv00001734sd00001177* + ID_MODEL_FROM_DATABASE=RAID Ctrl SAS 6G 0/1 (D2607) + +pci:v00001000d00000079sv00008086sd00009256* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 9260DE-8i + +pci:v00001000d00000079sv00008086sd00009260* + ID_MODEL_FROM_DATABASE=RAID Controller RS2BL040 + +pci:v00001000d00000079sv00008086sd00009261* + ID_MODEL_FROM_DATABASE=RAID Controller RS2BL080 + +pci:v00001000d00000079sv00008086sd00009264* + ID_MODEL_FROM_DATABASE=Warm Beach (Caster Lite) + +pci:v00001000d00000079sv00008086sd00009267* + ID_MODEL_FROM_DATABASE=RAID Controller RS2VB040 + +pci:v00001000d00000079sv00008086sd00009268* + ID_MODEL_FROM_DATABASE=RAID Controller RS2VB080 + +pci:v00001000d0000007C* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 1078DE + +pci:v00001000d0000007Csv00001014sd00000395* + ID_MODEL_FROM_DATABASE=ServeRAID-AR10is SAS/SATA Controller + +pci:v00001000d0000007E* + ID_MODEL_FROM_DATABASE=SSS6200 PCI-Express Flash SSD + +pci:v00001000d00000080* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000081* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000082* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000083* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000084* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000085* + ID_MODEL_FROM_DATABASE=SAS2208 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000086* + ID_MODEL_FROM_DATABASE=SAS2308 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000087* + ID_MODEL_FROM_DATABASE=SAS2308 PCI-Express Fusion-MPT SAS-2 + +pci:v00001000d00000087sv00001590sd00000044* + ID_MODEL_FROM_DATABASE=H220i + +pci:v00001000d0000008F* + ID_MODEL_FROM_DATABASE=53c875J + +pci:v00001000d0000008Fsv00001092sd00008000* + ID_MODEL_FROM_DATABASE=FirePort 40 SCSI Controller + +pci:v00001000d0000008Fsv00001092sd00008760* + ID_MODEL_FROM_DATABASE=FirePort 40 Dual SCSI Host Adapter + +pci:v00001000d00000090* + ID_MODEL_FROM_DATABASE=SAS3108 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000091* + ID_MODEL_FROM_DATABASE=SAS3108 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000094* + ID_MODEL_FROM_DATABASE=SAS3108 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000095* + ID_MODEL_FROM_DATABASE=SAS3108 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000096* + ID_MODEL_FROM_DATABASE=SAS3004 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000097* + ID_MODEL_FROM_DATABASE=SAS3008 PCI-Express Fusion-MPT SAS-3 + +pci:v00001000d00000097sv00001028sd00001F45* + ID_MODEL_FROM_DATABASE=12GB/s HBA internal + +pci:v00001000d00000097sv00001028sd00001F46* + ID_MODEL_FROM_DATABASE=12GB/s HBA external + +pci:v00001000d00000407* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00001000d00000407sv00001000sd00000530* + ID_MODEL_FROM_DATABASE=MegaRAID 530 SCSI 320-0X RAID Controller + +pci:v00001000d00000407sv00001000sd00000531* + ID_MODEL_FROM_DATABASE=MegaRAID 531 SCSI 320-4X RAID Controller + +pci:v00001000d00000407sv00001000sd00000532* + ID_MODEL_FROM_DATABASE=MegaRAID 532 SCSI 320-2X RAID Controller + +pci:v00001000d00000407sv00001028sd00000531* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4/QC + +pci:v00001000d00000407sv00001028sd00000533* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4/QC + +pci:v00001000d00000407sv00008086sd00000530* + ID_MODEL_FROM_DATABASE=MegaRAID Intel RAID Controller SRCZCRX + +pci:v00001000d00000407sv00008086sd00000532* + ID_MODEL_FROM_DATABASE=MegaRAID Intel RAID Controller SRCU42X + +pci:v00001000d00000408* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00001000d00000408sv00001000sd00000001* + ID_MODEL_FROM_DATABASE=MegaRAID SCSI 320-1E RAID Controller + +pci:v00001000d00000408sv00001000sd00000002* + ID_MODEL_FROM_DATABASE=MegaRAID SCSI 320-2E RAID Controller + +pci:v00001000d00000408sv00001025sd0000004D* + ID_MODEL_FROM_DATABASE=MegaRAID ACER ROMB-2E RAID Controller + +pci:v00001000d00000408sv00001028sd00000001* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller PERC4e/SC + +pci:v00001000d00000408sv00001028sd00000002* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller PERC4e/DC + +pci:v00001000d00000408sv00001028sd00000012* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller RAC4 + +pci:v00001000d00000408sv00001028sd00000015* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller PERC5 + +pci:v00001000d00000408sv00001028sd00001F03* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller PERC5 + +pci:v00001000d00000408sv00001734sd00001065* + ID_MODEL_FROM_DATABASE=FSC MegaRAID PCI Express ROMB + +pci:v00001000d00000408sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=MegaRAID Intel RAID Controller SRCU42E + +pci:v00001000d00000408sv00008086sd00003449* + ID_MODEL_FROM_DATABASE=MegaRAID Intel RAID Controller SROMBU + +pci:v00001000d00000409* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00001000d00000409sv00001000sd00003004* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-4X RAID Controller + +pci:v00001000d00000409sv00001000sd00003008* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-8X RAID Controller + +pci:v00001000d00000409sv00008086sd00003008* + ID_MODEL_FROM_DATABASE=MegaRAID RAID Controller SRCS28X + +pci:v00001000d00000409sv00008086sd00003431* + ID_MODEL_FROM_DATABASE=MegaRAID RAID Controller Alief SROMBU42E + +pci:v00001000d00000409sv00008086sd00003499* + ID_MODEL_FROM_DATABASE=MegaRAID RAID Controller Harwich SROMBU42E + +pci:v00001000d00000411* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 1068 + +pci:v00001000d00000411sv00001000sd00001001* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8408E + +pci:v00001000d00000411sv00001000sd00001002* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8480E + +pci:v00001000d00000411sv00001000sd00001003* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8344ELP + +pci:v00001000d00000411sv00001000sd00001004* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8308ELP + +pci:v00001000d00000411sv00001000sd00001008* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 84016E + +pci:v00001000d00000411sv00001000sd0000100C* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-12E + +pci:v00001000d00000411sv00001000sd0000100D* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-16E + +pci:v00001000d00000411sv00001000sd00002004* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-8ELP + +pci:v00001000d00000411sv00001000sd00002005* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 300-4ELP + +pci:v00001000d00000411sv00001033sd00008287* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000411sv00001054sd00003016* + ID_MODEL_FROM_DATABASE=MegaRAID SAS RoMB Server + +pci:v00001000d00000411sv00001734sd00001081* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000411sv00001734sd000010A3* + ID_MODEL_FROM_DATABASE=MegaRAID SAS PCI Express ROMB + +pci:v00001000d00000411sv00008086sd00001001* + ID_MODEL_FROM_DATABASE=RAID Controller SRCSAS18E + +pci:v00001000d00000411sv00008086sd00001003* + ID_MODEL_FROM_DATABASE=RAID Controller SRCSAS144E + +pci:v00001000d00000411sv00008086sd00003500* + ID_MODEL_FROM_DATABASE=SROMBSAS18E RAID Controller + +pci:v00001000d00000411sv00008086sd00003501* + ID_MODEL_FROM_DATABASE=SROMBSAS18E RAID Controller + +pci:v00001000d00000411sv00008086sd00003504* + ID_MODEL_FROM_DATABASE=SROMBSAS18E RAID Controller + +pci:v00001000d00000413* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 1068 [Verde ZCR] + +pci:v00001000d00000413sv00001000sd00001005* + ID_MODEL_FROM_DATABASE=MegaRAID SAS 8300XLP + +pci:v00001000d00000621* + ID_MODEL_FROM_DATABASE=FC909 Fibre Channel Adapter + +pci:v00001000d00000622* + ID_MODEL_FROM_DATABASE=FC929 Fibre Channel Adapter + +pci:v00001000d00000622sv00001000sd00001020* + ID_MODEL_FROM_DATABASE=44929 O Dual Fibre Channel card + +pci:v00001000d00000623* + ID_MODEL_FROM_DATABASE=FC929 LAN + +pci:v00001000d00000624* + ID_MODEL_FROM_DATABASE=FC919 Fibre Channel Adapter + +pci:v00001000d00000625* + ID_MODEL_FROM_DATABASE=FC919 LAN + +pci:v00001000d00000626* + ID_MODEL_FROM_DATABASE=FC929X Fibre Channel Adapter + +pci:v00001000d00000626sv00001000sd00001010* + ID_MODEL_FROM_DATABASE=7202-XP-LC Dual Fibre Channel card + +pci:v00001000d00000627* + ID_MODEL_FROM_DATABASE=FC929X LAN + +pci:v00001000d00000628* + ID_MODEL_FROM_DATABASE=FC919X Fibre Channel Adapter + +pci:v00001000d00000629* + ID_MODEL_FROM_DATABASE=FC919X LAN + +pci:v00001000d00000640* + ID_MODEL_FROM_DATABASE=FC949X Fibre Channel Adapter + +pci:v00001000d00000642* + ID_MODEL_FROM_DATABASE=FC939X Fibre Channel Adapter + +pci:v00001000d00000646* + ID_MODEL_FROM_DATABASE=FC949ES Fibre Channel Adapter + +pci:v00001000d00000701* + ID_MODEL_FROM_DATABASE=83C885 NT50 DigitalScape Fast Ethernet + +pci:v00001000d00000702* + ID_MODEL_FROM_DATABASE=Yellowfin G-NIC gigabit ethernet + +pci:v00001000d00000702sv00001318sd00000000* + ID_MODEL_FROM_DATABASE=PEI100X + +pci:v00001000d00000804* + ID_MODEL_FROM_DATABASE=SA2010 + +pci:v00001000d00000805* + ID_MODEL_FROM_DATABASE=SA2010ZC + +pci:v00001000d00000806* + ID_MODEL_FROM_DATABASE=SA2020 + +pci:v00001000d00000807* + ID_MODEL_FROM_DATABASE=SA2020ZC + +pci:v00001000d00000901* + ID_MODEL_FROM_DATABASE=61C102 + +pci:v00001000d00001000* + ID_MODEL_FROM_DATABASE=63C815 + +pci:v00001000d00001960* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00001000d00001960sv00001000sd00000518* + ID_MODEL_FROM_DATABASE=MegaRAID 518 SCSI 320-2 Controller + +pci:v00001000d00001960sv00001000sd00000520* + ID_MODEL_FROM_DATABASE=MegaRAID 520 SCSI 320-1 Controller + +pci:v00001000d00001960sv00001000sd00000522* + ID_MODEL_FROM_DATABASE=MegaRAID 522 i4 133 RAID Controller + +pci:v00001000d00001960sv00001000sd00000523* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 150-6 RAID Controller + +pci:v00001000d00001960sv00001000sd00004523* + ID_MODEL_FROM_DATABASE=MegaRAID SATA 150-4 RAID Controller + +pci:v00001000d00001960sv00001000sd0000A520* + ID_MODEL_FROM_DATABASE=MegaRAID ZCR SCSI 320-0 Controller + +pci:v00001000d00001960sv00001028sd00000518* + ID_MODEL_FROM_DATABASE=MegaRAID 518 DELL PERC 4/DC RAID Controller + +pci:v00001000d00001960sv00001028sd00000520* + ID_MODEL_FROM_DATABASE=MegaRAID 520 DELL PERC 4/SC RAID Controller + +pci:v00001000d00001960sv00001028sd00000531* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4/QC + +pci:v00001000d00001960sv00001028sd00000533* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4/QC + +pci:v00001000d00001960sv00008086sd00000520* + ID_MODEL_FROM_DATABASE=MegaRAID RAID Controller SRCU41L + +pci:v00001000d00001960sv00008086sd00000523* + ID_MODEL_FROM_DATABASE=MegaRAID RAID Controller SRCS16 + +pci:v00001000d00006001* + ID_MODEL_FROM_DATABASE=DX1 Multiformat Broadcast HD/SD Encoder/Decoder + +pci:v00001001* + ID_VENDOR_FROM_DATABASE=Kolter Electronic + +pci:v00001001d00000010* + ID_MODEL_FROM_DATABASE=PCI 1616 Measurement card with 32 digital I/O lines + +pci:v00001001d00000011* + ID_MODEL_FROM_DATABASE=OPTO-PCI Opto-Isolated digital I/O board + +pci:v00001001d00000012* + ID_MODEL_FROM_DATABASE=PCI-AD/DA Analogue I/O board + +pci:v00001001d00000013* + ID_MODEL_FROM_DATABASE=PCI-OPTO-RELAIS Digital I/O board with relay outputs + +pci:v00001001d00000014* + ID_MODEL_FROM_DATABASE=PCI-Counter/Timer Counter Timer board + +pci:v00001001d00000015* + ID_MODEL_FROM_DATABASE=PCI-DAC416 Analogue output board + +pci:v00001001d00000016* + ID_MODEL_FROM_DATABASE=PCI-MFB Analogue I/O board + +pci:v00001001d00000017* + ID_MODEL_FROM_DATABASE=PROTO-3 PCI Prototyping board + +pci:v00001001d00009100* + ID_MODEL_FROM_DATABASE=INI-9100/9100W SCSI Host + +pci:v00001002* + ID_VENDOR_FROM_DATABASE=Advanced Micro Devices, Inc. [AMD/ATI] + +pci:v00001002d00001304* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001305* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001306* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001307* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001309* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130A* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130B* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130C* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130D* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130E* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000130F* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001310* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001311* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001313* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001314* + ID_MODEL_FROM_DATABASE=Wrestler HDMI Audio + +pci:v00001002d00001314sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00001315* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001316* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000131B* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d0000131C* + ID_MODEL_FROM_DATABASE=Kaveri + +pci:v00001002d00001714* + ID_MODEL_FROM_DATABASE=BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series] + +pci:v00001002d00001714sv0000103Csd0000168B* + ID_MODEL_FROM_DATABASE=ProBook 4535s + +pci:v00001002d00003150* + ID_MODEL_FROM_DATABASE=RV380/M24 [Mobility Radeon X600] + +pci:v00001002d00003150sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=nx8220 + +pci:v00001002d00003151* + ID_MODEL_FROM_DATABASE=RV380 GL [FireMV 2400] + +pci:v00001002d00003152* + ID_MODEL_FROM_DATABASE=RV370/M22 [Mobility Radeon X300] + +pci:v00001002d00003154* + ID_MODEL_FROM_DATABASE=RV380/M24 GL [Mobility FireGL V3200] + +pci:v00001002d00003155* + ID_MODEL_FROM_DATABASE=RV380 GL [FireMV 2400] + +pci:v00001002d00003171* + ID_MODEL_FROM_DATABASE=RV380 GL [FireMV 2400] (Secondary) + +pci:v00001002d00003E50* + ID_MODEL_FROM_DATABASE=RV380 [Radeon X600] + +pci:v00001002d00003E54* + ID_MODEL_FROM_DATABASE=RV380 GL [FireGL V3200] + +pci:v00001002d00003E70* + ID_MODEL_FROM_DATABASE=RV380 [Radeon X600] (Secondary) + +pci:v00001002d00004136* + ID_MODEL_FROM_DATABASE=RS100 [Mobility IGP 320M] + +pci:v00001002d00004137* + ID_MODEL_FROM_DATABASE=RS200 [Radeon IGP 340] + +pci:v00001002d00004144* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9500] + +pci:v00001002d00004146* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9700 PRO] + +pci:v00001002d00004147* + ID_MODEL_FROM_DATABASE=R300 GL [FireGL Z1] + +pci:v00001002d00004148* + ID_MODEL_FROM_DATABASE=R350 [Radeon 9800/9800 SE] + +pci:v00001002d00004150* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550/9600/X1050 Series] + +pci:v00001002d00004150sv00001002sd00000002* + ID_MODEL_FROM_DATABASE=R9600 Pro primary (Asus OEM for HP) + +pci:v00001002d00004150sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=R9600 Pro secondary (Asus OEM for HP) + +pci:v00001002d00004150sv00001002sd00004722* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 AGP Edition + +pci:v00001002d00004150sv00001458sd00004024* + ID_MODEL_FROM_DATABASE=GV-R96128D + +pci:v00001002d00004150sv0000148Csd00002064* + ID_MODEL_FROM_DATABASE=R96A-C3N + +pci:v00001002d00004150sv0000148Csd00002066* + ID_MODEL_FROM_DATABASE=R96A-C3N + +pci:v00001002d00004150sv0000174Bsd00007C19* + ID_MODEL_FROM_DATABASE=Atlantis Radeon 9600 Pro + +pci:v00001002d00004150sv0000174Bsd00007C29* + ID_MODEL_FROM_DATABASE=GC-R9600PRO + +pci:v00001002d00004150sv000017EEsd00002002* + ID_MODEL_FROM_DATABASE=Radeon 9600 256Mb Primary + +pci:v00001002d00004150sv000018BCsd00000101* + ID_MODEL_FROM_DATABASE=GC-R9600PRO (Primary) + +pci:v00001002d00004151* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9600 Series] + +pci:v00001002d00004151sv00001043sd0000C004* + ID_MODEL_FROM_DATABASE=A9600SE + +pci:v00001002d00004152* + ID_MODEL_FROM_DATABASE=RV360 [Radeon 9600/X1050 Series] + +pci:v00001002d00004152sv00001002sd00000002* + ID_MODEL_FROM_DATABASE=Radeon 9600XT + +pci:v00001002d00004152sv00001002sd00004772* + ID_MODEL_FROM_DATABASE=All-in-Wonder 9600 XT + +pci:v00001002d00004152sv00001043sd0000C002* + ID_MODEL_FROM_DATABASE=Radeon 9600 XT TVD + +pci:v00001002d00004152sv00001043sd0000C01A* + ID_MODEL_FROM_DATABASE=A9600XT/TD + +pci:v00001002d00004152sv00001462sd00009510* + ID_MODEL_FROM_DATABASE=RX9600XT (MS-8951) + +pci:v00001002d00004152sv0000174Bsd00007C29* + ID_MODEL_FROM_DATABASE=Radeon 9600XT + +pci:v00001002d00004152sv00001787sd00004002* + ID_MODEL_FROM_DATABASE=Radeon 9600 XT + +pci:v00001002d00004153* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550] + +pci:v00001002d00004153sv00001043sd0000010C* + ID_MODEL_FROM_DATABASE=A9550GE/TD + +pci:v00001002d00004153sv00001462sd0000932C* + ID_MODEL_FROM_DATABASE=RX9550SE-TD128 (MS-8932) + +pci:v00001002d00004154* + ID_MODEL_FROM_DATABASE=RV350 GL [FireGL T2] + +pci:v00001002d00004155* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9600] + +pci:v00001002d00004157* + ID_MODEL_FROM_DATABASE=RV350 GL [FireGL T2] + +pci:v00001002d00004158* + ID_MODEL_FROM_DATABASE=68800AX [Graphics Ultra Pro PCI] + +pci:v00001002d00004164* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9500 PRO] (Secondary) + +pci:v00001002d00004165* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9700 PRO] (Secondary) + +pci:v00001002d00004166* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9700 PRO] (Secondary) + +pci:v00001002d00004168* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9800 SE] (Secondary) + +pci:v00001002d00004170* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550/9600/X1050 Series] (Secondary) + +pci:v00001002d00004170sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=R9600 Pro secondary (Asus OEM for HP) + +pci:v00001002d00004170sv00001002sd00004723* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 AGP Edition (Secondary) + +pci:v00001002d00004170sv00001458sd00004025* + ID_MODEL_FROM_DATABASE=GV-R96128D (Secondary) + +pci:v00001002d00004170sv0000148Csd00002067* + ID_MODEL_FROM_DATABASE=R96A-C3N (Secondary) + +pci:v00001002d00004170sv0000174Bsd00007C28* + ID_MODEL_FROM_DATABASE=GC-R9600PRO (Secondary) + +pci:v00001002d00004170sv000017EEsd00002003* + ID_MODEL_FROM_DATABASE=Radeon 9600 256Mb (Secondary) + +pci:v00001002d00004170sv000018BCsd00000100* + ID_MODEL_FROM_DATABASE=GC-R9600PRO (Secondary) + +pci:v00001002d00004171* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9600] (Secondary) + +pci:v00001002d00004171sv00001043sd0000C005* + ID_MODEL_FROM_DATABASE=A9600SE (Secondary) + +pci:v00001002d00004172* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9600/X1050 Series] (Secondary) + +pci:v00001002d00004172sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=Radeon 9600XT (Secondary) + +pci:v00001002d00004172sv00001002sd00004773* + ID_MODEL_FROM_DATABASE=All-in-Wonder 9600 XT (Secondary) + +pci:v00001002d00004172sv00001043sd0000C003* + ID_MODEL_FROM_DATABASE=A9600XT (Secondary) + +pci:v00001002d00004172sv00001043sd0000C01B* + ID_MODEL_FROM_DATABASE=A9600XT/TD (Secondary) + +pci:v00001002d00004172sv0000174Bsd00007C28* + ID_MODEL_FROM_DATABASE=Radeon 9600XT (Secondary) + +pci:v00001002d00004172sv00001787sd00004003* + ID_MODEL_FROM_DATABASE=Radeon 9600 XT (Secondary) + +pci:v00001002d00004173* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550] (Secondary) + +pci:v00001002d00004173sv00001043sd0000010D* + ID_MODEL_FROM_DATABASE=A9550GE/TD (Secondary) + +pci:v00001002d00004242* + ID_MODEL_FROM_DATABASE=R200 [All-In-Wonder Radeon 8500 DV] + +pci:v00001002d00004242sv00001002sd000002AA* + ID_MODEL_FROM_DATABASE=Radeon 8500 AIW DV Edition + +pci:v00001002d00004243* + ID_MODEL_FROM_DATABASE=R200 PCI Bridge [All-in-Wonder Radeon 8500DV] + +pci:v00001002d00004336* + ID_MODEL_FROM_DATABASE=RS100 [Radeon IGP 320M] + +pci:v00001002d00004336sv00001002sd00004336* + ID_MODEL_FROM_DATABASE=Pavilion ze4300 ATI Radeon Mobility U1 (IGP 320 M) + +pci:v00001002d00004336sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin Video + +pci:v00001002d00004336sv0000161Fsd00002029* + ID_MODEL_FROM_DATABASE=eMachines M5312 builtin Video + +pci:v00001002d00004337* + ID_MODEL_FROM_DATABASE=RS200M [Radeon IGP 330M/340M/345M/350M] + +pci:v00001002d00004337sv00001014sd0000053A* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v00001002d00004337sv0000103Csd00000850* + ID_MODEL_FROM_DATABASE=Radeon IGP 345M + +pci:v00001002d00004341* + ID_MODEL_FROM_DATABASE=IXP150 AC'97 Audio Controller + +pci:v00001002d00004342* + ID_MODEL_FROM_DATABASE=IXP200 3COM 3C920B Ethernet Controller + +pci:v00001002d00004345* + ID_MODEL_FROM_DATABASE=EHCI USB Controller + +pci:v00001002d00004347* + ID_MODEL_FROM_DATABASE=OHCI USB Controller #1 + +pci:v00001002d00004348* + ID_MODEL_FROM_DATABASE=OHCI USB Controller #2 + +pci:v00001002d00004349* + ID_MODEL_FROM_DATABASE=Dual Channel Bus Master PCI IDE Controller + +pci:v00001002d0000434D* + ID_MODEL_FROM_DATABASE=IXP AC'97 Modem + +pci:v00001002d00004353* + ID_MODEL_FROM_DATABASE=SMBus + +pci:v00001002d00004354* + ID_MODEL_FROM_DATABASE=215CT [Mach64 CT PCI] + +pci:v00001002d00004358* + ID_MODEL_FROM_DATABASE=210888CX [Mach64 CX] + +pci:v00001002d00004361* + ID_MODEL_FROM_DATABASE=IXP SB300 AC'97 Audio Controller + +pci:v00001002d00004363* + ID_MODEL_FROM_DATABASE=SMBus + +pci:v00001002d0000436E* + ID_MODEL_FROM_DATABASE=436E Serial ATA Controller + +pci:v00001002d00004370* + ID_MODEL_FROM_DATABASE=IXP SB400 AC'97 Audio Controller + +pci:v00001002d00004370sv00001025sd00000079* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004370sv00001025sd00000091* + ID_MODEL_FROM_DATABASE=Aspire 5032WXMi + +pci:v00001002d00004370sv0000103Csd00002A05* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004370sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004370sv0000105Bsd00000C81* + ID_MODEL_FROM_DATABASE=Realtek ALC 653 + +pci:v00001002d00004370sv0000107Bsd00000300* + ID_MODEL_FROM_DATABASE=MX6421 + +pci:v00001002d00004370sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00004371* + ID_MODEL_FROM_DATABASE=IXP SB4x0 PCI-PCI Bridge + +pci:v00001002d00004371sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004371sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004372* + ID_MODEL_FROM_DATABASE=IXP SB4x0 SMBus Controller + +pci:v00001002d00004372sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004372sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004372sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004372sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00004372sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004373* + ID_MODEL_FROM_DATABASE=IXP SB4x0 USB2 Host Controller + +pci:v00001002d00004373sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004373sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004373sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004373sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004374* + ID_MODEL_FROM_DATABASE=IXP SB4x0 USB Host Controller + +pci:v00001002d00004374sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004374sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004374sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004375* + ID_MODEL_FROM_DATABASE=IXP SB4x0 USB Host Controller + +pci:v00001002d00004375sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004375sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004375sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004375sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004376* + ID_MODEL_FROM_DATABASE=IXP SB4x0 IDE Controller + +pci:v00001002d00004376sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004376sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004376sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004376sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00004376sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004377* + ID_MODEL_FROM_DATABASE=IXP SB4x0 PCI-ISA Bridge + +pci:v00001002d00004377sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v00001002d00004377sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00004377sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004377sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00004378* + ID_MODEL_FROM_DATABASE=IXP SB400 AC'97 Modem Controller + +pci:v00001002d00004378sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00004378sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00004378sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00004379* + ID_MODEL_FROM_DATABASE=IXP SB4x0 Serial ATA Controller + +pci:v00001002d00004379sv00001462sd00007141* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d0000437A* + ID_MODEL_FROM_DATABASE=IXP SB400 Serial ATA Controller + +pci:v00001002d0000437Asv00001002sd00004379* + ID_MODEL_FROM_DATABASE=4379 Serial ATA Controller + +pci:v00001002d0000437Asv00001002sd0000437A* + ID_MODEL_FROM_DATABASE=437A Serial ATA Controller + +pci:v00001002d0000437Asv00001462sd00007141* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d0000437Asv000014F1sd00008800* + ID_MODEL_FROM_DATABASE=Leadtek WinFast TV2000XP Expert + +pci:v00001002d0000437B* + ID_MODEL_FROM_DATABASE=IXP SB4x0 High Definition Audio Controller + +pci:v00001002d0000437Bsv00001002sd0000437B* + ID_MODEL_FROM_DATABASE=IXP SB4x0 High Definition Audio Controller + +pci:v00001002d0000437Bsv000010CFsd00001326* + ID_MODEL_FROM_DATABASE=Fujitsu Lifebook A3040 + +pci:v00001002d0000437Bsv00001734sd000010B8* + ID_MODEL_FROM_DATABASE=Realtek High Definition Audio + +pci:v00001002d00004380* + ID_MODEL_FROM_DATABASE=SB600 Non-Raid-5 SATA + +pci:v00001002d00004380sv0000103Csd00002813* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004380sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004380sv00001458sd0000B003* + ID_MODEL_FROM_DATABASE=GA-MA790FX-DS5 (rev. 1.0) + +pci:v00001002d00004380sv00001458sd0000B005* + ID_MODEL_FROM_DATABASE=Gigabyte GA-MA69G-S3H Motherboard + +pci:v00001002d00004380sv00001462sd00007327* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004380sv000017F2sd00005999* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004381* + ID_MODEL_FROM_DATABASE=SB600 SATA Controller (RAID 5 mode) + +pci:v00001002d00004382* + ID_MODEL_FROM_DATABASE=SB600 AC97 Audio + +pci:v00001002d00004383* + ID_MODEL_FROM_DATABASE=SBx00 Azalia (Intel HDA) + +pci:v00001002d00004383sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004383sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d00004383sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004383sv00001043sd00008230* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004383sv00001043sd0000836C* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001002d00004383sv00001043sd00008410* + ID_MODEL_FROM_DATABASE=M4A89GTD PRO/USB3 Motherboard + +pci:v00001002d00004383sv00001043sd0000841B* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00004383sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004383sv00001458sd0000A022* + ID_MODEL_FROM_DATABASE=GA-MA770-DS3rev2.0 Motherboard + +pci:v00001002d00004383sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004384* + ID_MODEL_FROM_DATABASE=SBx00 PCI to PCI Bridge + +pci:v00001002d00004385* + ID_MODEL_FROM_DATABASE=SBx00 SMBus Controller + +pci:v00001002d00004385sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004385sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d00004385sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004385sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004385sv00001043sd00008389* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001002d00004385sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004385sv00001458sd00004385* + ID_MODEL_FROM_DATABASE=GA-MA770-DS3rev2.0 Motherboard + +pci:v00001002d00004385sv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004385sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00004385sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00004385sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004386* + ID_MODEL_FROM_DATABASE=SB600 USB Controller (EHCI) + +pci:v00001002d00004386sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004386sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004386sv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004386sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004387* + ID_MODEL_FROM_DATABASE=SB600 USB (OHCI0) + +pci:v00001002d00004387sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004387sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004387sv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004387sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004388* + ID_MODEL_FROM_DATABASE=SB600 USB (OHCI1) + +pci:v00001002d00004388sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004388sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004388sv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004388sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00004389* + ID_MODEL_FROM_DATABASE=SB600 USB (OHCI2) + +pci:v00001002d00004389sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00004389sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00004389sv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d00004389sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000438A* + ID_MODEL_FROM_DATABASE=SB600 USB (OHCI3) + +pci:v00001002d0000438Asv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d0000438Asv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d0000438Asv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d0000438Asv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000438B* + ID_MODEL_FROM_DATABASE=SB600 USB (OHCI4) + +pci:v00001002d0000438Bsv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d0000438Bsv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d0000438Bsv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d0000438Bsv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000438C* + ID_MODEL_FROM_DATABASE=SB600 IDE + +pci:v00001002d0000438Csv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d0000438Csv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d0000438Csv00001458sd00005002* + ID_MODEL_FROM_DATABASE=Gigabyte GA-MA69G-S3H Motherboard + +pci:v00001002d0000438Csv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d0000438Csv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000438D* + ID_MODEL_FROM_DATABASE=SB600 PCI to LPC Bridge + +pci:v00001002d0000438Dsv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d0000438Dsv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d0000438Dsv00001462sd00007368* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d0000438Dsv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000438E* + ID_MODEL_FROM_DATABASE=SB600 AC97 Modem + +pci:v00001002d00004390* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode] + +pci:v00001002d00004390sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004390sv00001043sd00008389* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001002d00004390sv00001458sd0000B002* + ID_MODEL_FROM_DATABASE=GA-MA770-DS3rev2.0 Motherboard + +pci:v00001002d00004390sv00001849sd00004390* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v00001002d00004391* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode] + +pci:v00001002d00004391sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d00004391sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004391sv00001043sd00008443* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00004391sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00004392* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [Non-RAID5 mode] + +pci:v00001002d00004393* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [RAID5 mode] + +pci:v00001002d00004394* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode] + +pci:v00001002d00004395* + ID_MODEL_FROM_DATABASE=SB8x0/SB9x0 SATA Controller [Storage mode] + +pci:v00001002d00004396* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB EHCI Controller + +pci:v00001002d00004396sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004396sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d00004396sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004396sv00001043sd00008443* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00004396sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00004396sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00004397* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI0 Controller + +pci:v00001002d00004397sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004397sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d00004397sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004397sv00001043sd00008443* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00004397sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00004397sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00004398* + ID_MODEL_FROM_DATABASE=SB7x0 USB OHCI1 Controller + +pci:v00001002d00004398sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004398sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004398sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00004399* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI2 Controller + +pci:v00001002d00004399sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00004399sv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d00004399sv00001043sd00008443* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00004399sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d0000439C* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 IDE Controller + +pci:v00001002d0000439Csv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d0000439Csv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d0000439D* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 LPC host controller + +pci:v00001002d0000439Dsv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d0000439Dsv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v00001002d0000439Dsv00001043sd000082EF* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001002d0000439Dsv00001043sd00008443* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d0000439Dsv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d000043A0* + ID_MODEL_FROM_DATABASE=SB700/SB800/SB900 PCI to PCI bridge (PCIE port 0) + +pci:v00001002d000043A1* + ID_MODEL_FROM_DATABASE=SB700/SB800/SB900 PCI to PCI bridge (PCIE port 1) + +pci:v00001002d000043A2* + ID_MODEL_FROM_DATABASE=SB900 PCI to PCI bridge (PCIE port 2) + +pci:v00001002d000043A3* + ID_MODEL_FROM_DATABASE=SB900 PCI to PCI bridge (PCIE port 3) + +pci:v00001002d00004437* + ID_MODEL_FROM_DATABASE=RS250 [Mobility Radeon 7000 IGP] + +pci:v00001002d00004554* + ID_MODEL_FROM_DATABASE=210888ET [Mach64 ET] + +pci:v00001002d00004654* + ID_MODEL_FROM_DATABASE=Mach64 VT + +pci:v00001002d00004742* + ID_MODEL_FROM_DATABASE=3D Rage PRO AGP 2X + +pci:v00001002d00004742sv00001002sd00000040* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001002sd00000044* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001002sd00000061* + ID_MODEL_FROM_DATABASE=Rage Pro AIW AGP 2X + +pci:v00001002d00004742sv00001002sd00000062* + ID_MODEL_FROM_DATABASE=Rage Pro AIW AGP 2X + +pci:v00001002d00004742sv00001002sd00000063* + ID_MODEL_FROM_DATABASE=Rage Pro AIW AGP 2X + +pci:v00001002d00004742sv00001002sd00000080* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001002sd00000084* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001002sd00004742* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001002sd00008001* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001028sd00000082* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001028sd00004082* + ID_MODEL_FROM_DATABASE=Optiplex GX1 Onboard Display Adapter + +pci:v00001002d00004742sv00001028sd00008082* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00001028sd0000C082* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004742sv00008086sd00004152* + ID_MODEL_FROM_DATABASE=Xpert 98D AGP 2X + +pci:v00001002d00004742sv00008086sd0000464A* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP 2X + +pci:v00001002d00004744* + ID_MODEL_FROM_DATABASE=3D Rage PRO AGP 1X + +pci:v00001002d00004744sv00001002sd00004744* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo AGP + +pci:v00001002d00004744sv00008086sd00004D55* + ID_MODEL_FROM_DATABASE=Rage 3D Pro AGP 1X [Intel MU440EX] + +pci:v00001002d00004749* + ID_MODEL_FROM_DATABASE=3D Rage PRO PCI + +pci:v00001002d00004749sv00001002sd00000061* + ID_MODEL_FROM_DATABASE=Rage Pro AIW + +pci:v00001002d00004749sv00001002sd00000062* + ID_MODEL_FROM_DATABASE=Rage Pro AIW + +pci:v00001002d0000474D* + ID_MODEL_FROM_DATABASE=Rage XL AGP 2X + +pci:v00001002d0000474Dsv00001002sd00000004* + ID_MODEL_FROM_DATABASE=Xpert 98 RXL AGP 2X + +pci:v00001002d0000474Dsv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Xpert 98 RXL AGP 2X + +pci:v00001002d0000474Dsv00001002sd00000080* + ID_MODEL_FROM_DATABASE=Rage XL AGP 2X + +pci:v00001002d0000474Dsv00001002sd00000084* + ID_MODEL_FROM_DATABASE=Xpert 98 AGP 2X + +pci:v00001002d0000474Dsv00001002sd0000474D* + ID_MODEL_FROM_DATABASE=Rage XL AGP + +pci:v00001002d0000474Dsv00001033sd0000806A* + ID_MODEL_FROM_DATABASE=Rage XL AGP + +pci:v00001002d0000474E* + ID_MODEL_FROM_DATABASE=Rage XC AGP + +pci:v00001002d0000474Esv00001002sd0000474E* + ID_MODEL_FROM_DATABASE=Rage XC AGP + +pci:v00001002d0000474F* + ID_MODEL_FROM_DATABASE=Rage XL + +pci:v00001002d0000474Fsv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Rage XL + +pci:v00001002d0000474Fsv00001002sd0000474F* + ID_MODEL_FROM_DATABASE=Rage XL + +pci:v00001002d00004750* + ID_MODEL_FROM_DATABASE=3D Rage Pro PCI + +pci:v00001002d00004750sv00001002sd00000040* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo + +pci:v00001002d00004750sv00001002sd00000044* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo + +pci:v00001002d00004750sv00001002sd00000080* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo + +pci:v00001002d00004750sv00001002sd00000084* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo + +pci:v00001002d00004750sv00001002sd00004750* + ID_MODEL_FROM_DATABASE=Rage Pro Turbo + +pci:v00001002d00004752* + ID_MODEL_FROM_DATABASE=Rage XL PCI + +pci:v00001002d00004752sv00000E11sd0000001E* + ID_MODEL_FROM_DATABASE=Proliant Rage XL + +pci:v00001002d00004752sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Rage XL + +pci:v00001002d00004752sv00001002sd00004752* + ID_MODEL_FROM_DATABASE=Proliant Rage XL + +pci:v00001002d00004752sv00001002sd00008008* + ID_MODEL_FROM_DATABASE=Rage XL + +pci:v00001002d00004752sv00001014sd00000240* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00001002d00004752sv00001028sd000000CE* + ID_MODEL_FROM_DATABASE=PowerEdge 1400 + +pci:v00001002d00004752sv00001028sd000000D1* + ID_MODEL_FROM_DATABASE=PowerEdge 2550 + +pci:v00001002d00004752sv00001028sd000000D9* + ID_MODEL_FROM_DATABASE=PowerEdge 2500 + +pci:v00001002d00004752sv00001028sd00000134* + ID_MODEL_FROM_DATABASE=PowerEdge 600SC + +pci:v00001002d00004752sv00001028sd0000014A* + ID_MODEL_FROM_DATABASE=PowerEdge 1750 + +pci:v00001002d00004752sv00001028sd00000165* + ID_MODEL_FROM_DATABASE=PowerEdge 750 + +pci:v00001002d00004752sv0000103Csd000010E1* + ID_MODEL_FROM_DATABASE=NetServer Rage XL + +pci:v00001002d00004752sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00001002d00004752sv0000107Bsd00006400* + ID_MODEL_FROM_DATABASE=6400 Server + +pci:v00001002d00004752sv00001734sd0000007A* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series onboard VGA + +pci:v00001002d00004752sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00001002d00004752sv00008086sd00003411* + ID_MODEL_FROM_DATABASE=SDS2 Mainboard + +pci:v00001002d00004752sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00001002d00004752sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00001002d00004753* + ID_MODEL_FROM_DATABASE=Rage XC + +pci:v00001002d00004753sv00001002sd00004753* + ID_MODEL_FROM_DATABASE=Rage XC + +pci:v00001002d00004754* + ID_MODEL_FROM_DATABASE=3D Rage II/II+ PCI [Mach64 GT] + +pci:v00001002d00004755* + ID_MODEL_FROM_DATABASE=Mach64 GTB [3D Rage II+ DVD] + +pci:v00001002d00004756* + ID_MODEL_FROM_DATABASE=3D Rage IIC PCI [Mach64 GT IIC] + +pci:v00001002d00004756sv00001002sd00004756* + ID_MODEL_FROM_DATABASE=Rage IIC + +pci:v00001002d00004757* + ID_MODEL_FROM_DATABASE=3D Rage IIC AGP + +pci:v00001002d00004757sv00001002sd00004757* + ID_MODEL_FROM_DATABASE=Rage IIC AGP + +pci:v00001002d00004757sv00001028sd00000089* + ID_MODEL_FROM_DATABASE=Rage 3D IIC + +pci:v00001002d00004757sv00001028sd0000008E* + ID_MODEL_FROM_DATABASE=PowerEdge 1300 onboard video + +pci:v00001002d00004757sv00001028sd00004082* + ID_MODEL_FROM_DATABASE=Rage 3D IIC + +pci:v00001002d00004757sv00001028sd00008082* + ID_MODEL_FROM_DATABASE=Rage 3D IIC + +pci:v00001002d00004757sv00001028sd0000C082* + ID_MODEL_FROM_DATABASE=Rage 3D IIC + +pci:v00001002d00004758* + ID_MODEL_FROM_DATABASE=210888GX [Mach64 GX PCI] + +pci:v00001002d00004759* + ID_MODEL_FROM_DATABASE=3D Rage IIC PCI + +pci:v00001002d0000475A* + ID_MODEL_FROM_DATABASE=3D Rage IIC AGP + +pci:v00001002d0000475Asv00001002sd00000084* + ID_MODEL_FROM_DATABASE=Rage 3D Pro AGP 2x XPERT 98 + +pci:v00001002d0000475Asv00001002sd00000087* + ID_MODEL_FROM_DATABASE=Rage 3D IIC + +pci:v00001002d0000475Asv00001002sd0000475A* + ID_MODEL_FROM_DATABASE=Rage IIC AGP + +pci:v00001002d00004966* + ID_MODEL_FROM_DATABASE=RV250 [Radeon 9000 Series] + +pci:v00001002d00004966sv000010F1sd00000002* + ID_MODEL_FROM_DATABASE=RV250 If [Tachyon G9000 PRO] + +pci:v00001002d00004966sv0000148Csd00002039* + ID_MODEL_FROM_DATABASE=RV250 If [Radeon 9000 Pro "Evil Commando"] + +pci:v00001002d00004966sv00001509sd00009A00* + ID_MODEL_FROM_DATABASE=RV250 If [Radeon 9000 "AT009"] + +pci:v00001002d00004966sv00001681sd00000040* + ID_MODEL_FROM_DATABASE=RV250 If [3D prophet 9000] + +pci:v00001002d00004966sv0000174Bsd00007176* + ID_MODEL_FROM_DATABASE=Radeon 9000 Pro + +pci:v00001002d00004966sv0000174Bsd00007192* + ID_MODEL_FROM_DATABASE=RV250 If [Radeon 9000 "Atlantis"] + +pci:v00001002d00004966sv000017AFsd00002005* + ID_MODEL_FROM_DATABASE=RV250 If [Excalibur Radeon 9000 Pro] + +pci:v00001002d00004966sv000017AFsd00002006* + ID_MODEL_FROM_DATABASE=RV250 If [Excalibur Radeon 9000] + +pci:v00001002d0000496E* + ID_MODEL_FROM_DATABASE=RV250 [Radeon 9000] (Secondary) + +pci:v00001002d00004A49* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 PRO/GTO AGP] + +pci:v00001002d00004A49sv0000174Bsd00002620* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 GTO AGP] + +pci:v00001002d00004A4A* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 GT AGP] + +pci:v00001002d00004A4B* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 AGP Series] + +pci:v00001002d00004A4D* + ID_MODEL_FROM_DATABASE=R420 GL [FireGL X3-256] + +pci:v00001002d00004A4E* + ID_MODEL_FROM_DATABASE=RV420/M18 [Mobility Radeon 9800] + +pci:v00001002d00004A4F* + ID_MODEL_FROM_DATABASE=R420 [Radeon X850 AGP] + +pci:v00001002d00004A50* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 XT Platinum Edition AGP] + +pci:v00001002d00004A54* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 VE AGP] + +pci:v00001002d00004A54sv00001002sd00004422* + ID_MODEL_FROM_DATABASE=All-In-Wonder X800 VE AGP + +pci:v00001002d00004A69* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 PRO/GTO] (Secondary) + +pci:v00001002d00004A6A* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800] (Secondary) + +pci:v00001002d00004A6B* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 XT AGP] (Secondary) + +pci:v00001002d00004A70* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 XT Platinum Edition AGP] (Secondary) + +pci:v00001002d00004A74* + ID_MODEL_FROM_DATABASE=R420 [Radeon X800 VE] (Secondary) + +pci:v00001002d00004B49* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 XT AGP] + +pci:v00001002d00004B4B* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 PRO AGP] + +pci:v00001002d00004B4C* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 XT Platinum Edition AGP] + +pci:v00001002d00004B69* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 XT AGP] (Secondary) + +pci:v00001002d00004B6B* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 PRO AGP] (Secondary) + +pci:v00001002d00004B6C* + ID_MODEL_FROM_DATABASE=R481 [Radeon X850 XT Platinum Edition AGP] (Secondary) + +pci:v00001002d00004C42* + ID_MODEL_FROM_DATABASE=3D Rage LT PRO AGP 2X + +pci:v00001002d00004C42sv00000E11sd0000B0E7* + ID_MODEL_FROM_DATABASE=Rage LT Pro (Compaq Presario 5240) + +pci:v00001002d00004C42sv00000E11sd0000B0E8* + ID_MODEL_FROM_DATABASE=Rage 3D LT Pro + +pci:v00001002d00004C42sv00000E11sd0000B10E* + ID_MODEL_FROM_DATABASE=3D Rage LT Pro (Compaq Armada 1750) + +pci:v00001002d00004C42sv00001002sd00000040* + ID_MODEL_FROM_DATABASE=Rage LT Pro AGP 2X + +pci:v00001002d00004C42sv00001002sd00000044* + ID_MODEL_FROM_DATABASE=Rage LT Pro AGP 2X + +pci:v00001002d00004C42sv00001002sd00004C42* + ID_MODEL_FROM_DATABASE=Rage LT Pro AGP 2X + +pci:v00001002d00004C42sv00001002sd00008001* + ID_MODEL_FROM_DATABASE=Rage LT Pro AGP 2X + +pci:v00001002d00004C42sv00001028sd00000085* + ID_MODEL_FROM_DATABASE=Rage 3D LT Pro + +pci:v00001002d00004C46* + ID_MODEL_FROM_DATABASE=Rage Mobility 128 AGP 2X/Mobility M3 + +pci:v00001002d00004C46sv00001002sd00000155* + ID_MODEL_FROM_DATABASE=IBM Thinkpad A22p + +pci:v00001002d00004C46sv00001014sd00000155* + ID_MODEL_FROM_DATABASE=IBM Thinkpad A22p + +pci:v00001002d00004C46sv00001028sd000000B1* + ID_MODEL_FROM_DATABASE=Latitude C600 + +pci:v00001002d00004C47* + ID_MODEL_FROM_DATABASE=3D Rage IIC PCI / Mobility Radeon 7500/7500C + +pci:v00001002d00004C49* + ID_MODEL_FROM_DATABASE=3D Rage LT PRO PCI + +pci:v00001002d00004C49sv00001002sd00000004* + ID_MODEL_FROM_DATABASE=Rage LT Pro + +pci:v00001002d00004C49sv00001002sd00000040* + ID_MODEL_FROM_DATABASE=Rage LT Pro + +pci:v00001002d00004C49sv00001002sd00000044* + ID_MODEL_FROM_DATABASE=Rage LT Pro + +pci:v00001002d00004C49sv00001002sd00004C49* + ID_MODEL_FROM_DATABASE=Rage LT Pro + +pci:v00001002d00004C4D* + ID_MODEL_FROM_DATABASE=Rage Mobility AGP 2x Series + +pci:v00001002d00004C4Dsv00000E11sd0000B111* + ID_MODEL_FROM_DATABASE=Armada M700 + +pci:v00001002d00004C4Dsv00000E11sd0000B160* + ID_MODEL_FROM_DATABASE=Armada E500 + +pci:v00001002d00004C4Dsv00001002sd00000084* + ID_MODEL_FROM_DATABASE=Xpert 98 AGP 2X (Mobility) + +pci:v00001002d00004C4Dsv00001014sd00000154* + ID_MODEL_FROM_DATABASE=ThinkPad A20m/A21m + +pci:v00001002d00004C4Dsv00001028sd000000AA* + ID_MODEL_FROM_DATABASE=Latitude CPt + +pci:v00001002d00004C4Dsv00001028sd000000BB* + ID_MODEL_FROM_DATABASE=Latitude CPx + +pci:v00001002d00004C4Dsv00001179sd0000FF00* + ID_MODEL_FROM_DATABASE=Satellite 1715XCDS laptop + +pci:v00001002d00004C4Dsv000013BDsd00001019* + ID_MODEL_FROM_DATABASE=PC-AR10 + +pci:v00001002d00004C50* + ID_MODEL_FROM_DATABASE=3D Rage LT PRO PCI + +pci:v00001002d00004C50sv00001002sd00004C50* + ID_MODEL_FROM_DATABASE=Rage LT Pro + +pci:v00001002d00004C52* + ID_MODEL_FROM_DATABASE=Rage Mobility-M1 PCI + +pci:v00001002d00004C52sv00001033sd00008112* + ID_MODEL_FROM_DATABASE=Versa Note VXi + +pci:v00001002d00004C54* + ID_MODEL_FROM_DATABASE=264LT [Mach64 LT] + +pci:v00001002d00004C57* + ID_MODEL_FROM_DATABASE=RV200/M7 [Mobility Radeon 7500] + +pci:v00001002d00004C57sv00001014sd00000517* + ID_MODEL_FROM_DATABASE=ThinkPad T30 + +pci:v00001002d00004C57sv00001014sd00000530* + ID_MODEL_FROM_DATABASE=ThinkPad T42 2373-4WU + +pci:v00001002d00004C57sv00001028sd000000E6* + ID_MODEL_FROM_DATABASE=Radeon Mobility M7 LW (Dell Inspiron 8100) + +pci:v00001002d00004C57sv00001028sd0000012A* + ID_MODEL_FROM_DATABASE=Latitude C640 + +pci:v00001002d00004C57sv00001043sd00001622* + ID_MODEL_FROM_DATABASE=Mobility Radeon M7 (L3C/S) + +pci:v00001002d00004C57sv0000144Dsd0000C006* + ID_MODEL_FROM_DATABASE=Radeon Mobility M7 LW in vpr Matrix 170B4 + +pci:v00001002d00004C58* + ID_MODEL_FROM_DATABASE=RV200/M7 GL [Mobility FireGL 7800] + +pci:v00001002d00004C59* + ID_MODEL_FROM_DATABASE=RV100/M6 [Rage/Radeon Mobility Series] + +pci:v00001002d00004C59sv00000E11sd0000B111* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00001002d00004C59sv00001014sd00000235* + ID_MODEL_FROM_DATABASE=ThinkPad A30/A30p (2652/2653) + +pci:v00001002d00004C59sv00001014sd00000239* + ID_MODEL_FROM_DATABASE=ThinkPad X22/X23/X24 + +pci:v00001002d00004C59sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v00001002d00004C59sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00001002d00004C59sv0000104Dsd00008140* + ID_MODEL_FROM_DATABASE=PCG-Z1SP laptop + +pci:v00001002d00004C59sv00001509sd00001930* + ID_MODEL_FROM_DATABASE=Medion MD9703 + +pci:v00001002d00004C66* + ID_MODEL_FROM_DATABASE=RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] + +pci:v00001002d00004C66sv00001014sd0000054D* + ID_MODEL_FROM_DATABASE=ThinkPad T41 + +pci:v00001002d00004C6E* + ID_MODEL_FROM_DATABASE=RV250/M9 [Mobility Radeon 9000] (Secondary) + +pci:v00001002d00004D46* + ID_MODEL_FROM_DATABASE=Rage Mobility 128 AGP 4X/Mobility M4 + +pci:v00001002d00004D52* + ID_MODEL_FROM_DATABASE=Theater 550 PRO PCI [ATI TV Wonder 550] + +pci:v00001002d00004D53* + ID_MODEL_FROM_DATABASE=Theater 550 PRO PCIe + +pci:v00001002d00004E44* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9700/9700 PRO] + +pci:v00001002d00004E44sv00001002sd0000515E* + ID_MODEL_FROM_DATABASE=Radeon ES1000 + +pci:v00001002d00004E44sv00001002sd00005965* + ID_MODEL_FROM_DATABASE=Radeon ES1000 + +pci:v00001002d00004E45* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9500 PRO/9700] + +pci:v00001002d00004E45sv00001002sd00000002* + ID_MODEL_FROM_DATABASE=Radeon R300 NE [Radeon 9500 Pro] + +pci:v00001002d00004E45sv00001681sd00000002* + ID_MODEL_FROM_DATABASE=Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] + +pci:v00001002d00004E46* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9600 TX] + +pci:v00001002d00004E47* + ID_MODEL_FROM_DATABASE=R300 GL [FireGL X1] + +pci:v00001002d00004E48* + ID_MODEL_FROM_DATABASE=R350 [Radeon 9800 Series] + +pci:v00001002d00004E49* + ID_MODEL_FROM_DATABASE=R350 [Radeon 9800] + +pci:v00001002d00004E4A* + ID_MODEL_FROM_DATABASE=R360 [Radeon 9800 XXL/XT] + +pci:v00001002d00004E4Asv00001002sd00004E4A* + ID_MODEL_FROM_DATABASE=R360 [Radeon 9800 XT] + +pci:v00001002d00004E4B* + ID_MODEL_FROM_DATABASE=R350 GL [FireGL X2 AGP Pro] + +pci:v00001002d00004E50* + ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] + +pci:v00001002d00004E50sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00001002d00004E50sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00001002d00004E50sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00001002d00004E50sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P35 notebook + +pci:v00001002d00004E50sv00001462sd00000311* + ID_MODEL_FROM_DATABASE=MSI M510A + +pci:v00001002d00004E50sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420W + +pci:v00001002d00004E51* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550/9600/X1050 Series] + +pci:v00001002d00004E52* + ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9500/9700 SE] + +pci:v00001002d00004E52sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P35 notebook + +pci:v00001002d00004E54* + ID_MODEL_FROM_DATABASE=RV350/M10 GL [Mobility FireGL T2] + +pci:v00001002d00004E56* + ID_MODEL_FROM_DATABASE=RV360/M12 [Mobility Radeon 9550] + +pci:v00001002d00004E64* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9700 PRO] (Secondary) + +pci:v00001002d00004E65* + ID_MODEL_FROM_DATABASE=R300 [Radeon 9500 PRO] (Secondary) + +pci:v00001002d00004E65sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=Radeon R300 NE [Radeon 9500 Pro] + +pci:v00001002d00004E65sv00001681sd00000003* + ID_MODEL_FROM_DATABASE=Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] (Secondary) + +pci:v00001002d00004E66* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9600] (Secondary) + +pci:v00001002d00004E67* + ID_MODEL_FROM_DATABASE=R300 GL [FireGL X1] (Secondary) + +pci:v00001002d00004E68* + ID_MODEL_FROM_DATABASE=R350 [Radeon 9800 PRO] (Secondary) + +pci:v00001002d00004E69* + ID_MODEL_FROM_DATABASE=R350 [Radeon 9800] (Secondary) + +pci:v00001002d00004E6A* + ID_MODEL_FROM_DATABASE=RV350 [Radeon 9800 XT] (Secondary) + +pci:v00001002d00004E6Asv00001002sd00004E6A* + ID_MODEL_FROM_DATABASE=R360 [Radeon 9800 XT] (Secondary) + +pci:v00001002d00004E6Asv00001002sd00004E71* + ID_MODEL_FROM_DATABASE=M10 NQ [Radeon Mobility 9600] + +pci:v00001002d00004E71* + ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600] (Secondary) + +pci:v00001002d00004F72* + ID_MODEL_FROM_DATABASE=RV250 [Radeon 9000 Series] + +pci:v00001002d00004F73* + ID_MODEL_FROM_DATABASE=RV250 [Radeon 9000 Series] (Secondary) + +pci:v00001002d00005044* + ID_MODEL_FROM_DATABASE=All-In-Wonder 128 PCI + +pci:v00001002d00005044sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005044sv00001002sd00000029* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005046* + ID_MODEL_FROM_DATABASE=Rage 128 PRO AGP 4x TMDS + +pci:v00001002d00005046sv00001002sd00000004* + ID_MODEL_FROM_DATABASE=Rage Fury Pro + +pci:v00001002d00005046sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Rage Fury Pro/Xpert 2000 Pro + +pci:v00001002d00005046sv00001002sd00000014* + ID_MODEL_FROM_DATABASE=Rage Fury Pro + +pci:v00001002d00005046sv00001002sd00000018* + ID_MODEL_FROM_DATABASE=Rage Fury Pro/Xpert 2000 Pro + +pci:v00001002d00005046sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Rage 128 Pro AIW AGP + +pci:v00001002d00005046sv00001002sd0000002A* + ID_MODEL_FROM_DATABASE=Rage 128 Pro AIW AGP + +pci:v00001002d00005046sv00001002sd00000048* + ID_MODEL_FROM_DATABASE=Rage Fury Pro + +pci:v00001002d00005046sv00001002sd00002000* + ID_MODEL_FROM_DATABASE=Rage Fury MAXX AGP 4x (TMDS) (VGA device) + +pci:v00001002d00005046sv00001002sd00002001* + ID_MODEL_FROM_DATABASE=Rage Fury MAXX AGP 4x (TMDS) (Extra device?!) + +pci:v00001002d00005050* + ID_MODEL_FROM_DATABASE=Rage128 [Xpert 128 PCI] + +pci:v00001002d00005050sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Xpert 128 + +pci:v00001002d00005052* + ID_MODEL_FROM_DATABASE=Rage 128 PRO AGP 4X TMDS + +pci:v00001002d00005144* + ID_MODEL_FROM_DATABASE=R100 [Radeon 7200 / All-In-Wonder Radeon] + +pci:v00001002d00005144sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005144sv00001002sd00000009* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd0000000A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd0000001A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd00000029* + ID_MODEL_FROM_DATABASE=Radeon AIW + +pci:v00001002d00005144sv00001002sd00000038* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd00000039* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd0000008A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd000000BA* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd00000139* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd0000028A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005144sv00001002sd000002AA* + ID_MODEL_FROM_DATABASE=Radeon AIW + +pci:v00001002d00005144sv00001002sd0000053A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon + +pci:v00001002d00005148* + ID_MODEL_FROM_DATABASE=R200 GL [FireGL 8800] + +pci:v00001002d00005148sv00001002sd0000010A* + ID_MODEL_FROM_DATABASE=FireGL 8800 64Mb + +pci:v00001002d00005148sv00001002sd00000152* + ID_MODEL_FROM_DATABASE=FireGL 8800 128Mb + +pci:v00001002d00005148sv00001002sd00000162* + ID_MODEL_FROM_DATABASE=FireGL 8700 32Mb + +pci:v00001002d00005148sv00001002sd00000172* + ID_MODEL_FROM_DATABASE=FireGL 8700 64Mb + +pci:v00001002d0000514C* + ID_MODEL_FROM_DATABASE=R200 [Radeon 8500/8500 LE] + +pci:v00001002d0000514Csv00001002sd0000003A* + ID_MODEL_FROM_DATABASE=Radeon R200 QL [Radeon 8500 LE] + +pci:v00001002d0000514Csv00001002sd0000013A* + ID_MODEL_FROM_DATABASE=Radeon 8500 + +pci:v00001002d0000514Csv0000148Csd00002026* + ID_MODEL_FROM_DATABASE=R200 QL [Radeon 8500 Evil Master II Multi Display Edition] + +pci:v00001002d0000514Csv00001681sd00000010* + ID_MODEL_FROM_DATABASE=Radeon 8500 [3D Prophet 8500 128Mb] + +pci:v00001002d0000514Csv0000174Bsd00007149* + ID_MODEL_FROM_DATABASE=Radeon 8500 LE + +pci:v00001002d0000514Csv00001787sd00000F08* + ID_MODEL_FROM_DATABASE=Radeon R200 QL [PowerMagic Radeon 8500] + +pci:v00001002d0000514D* + ID_MODEL_FROM_DATABASE=R200 [Radeon 9100] + +pci:v00001002d00005157* + ID_MODEL_FROM_DATABASE=RV200 [Radeon 7500/7500 LE] + +pci:v00001002d00005157sv00001002sd0000013A* + ID_MODEL_FROM_DATABASE=Radeon 7500 + +pci:v00001002d00005157sv00001002sd00000F2B* + ID_MODEL_FROM_DATABASE=ALL-IN-WONDER VE PCI + +pci:v00001002d00005157sv00001002sd0000103A* + ID_MODEL_FROM_DATABASE=Dell Optiplex GX260 + +pci:v00001002d00005157sv00001458sd00004000* + ID_MODEL_FROM_DATABASE=RV200 QW [RADEON 7500 PRO MAYA AR] + +pci:v00001002d00005157sv0000148Csd00002024* + ID_MODEL_FROM_DATABASE=RV200 QW [Radeon 7500LE Dual Display] + +pci:v00001002d00005157sv0000148Csd00002025* + ID_MODEL_FROM_DATABASE=RV200 QW [Radeon 7500 Evil Master Multi Display Edition] + +pci:v00001002d00005157sv0000148Csd00002036* + ID_MODEL_FROM_DATABASE=RV200 QW [Radeon 7500 PCI Dual Display] + +pci:v00001002d00005157sv0000174Bsd00007146* + ID_MODEL_FROM_DATABASE=RV200 QW [Radeon 7500 LE] + +pci:v00001002d00005157sv0000174Bsd00007147* + ID_MODEL_FROM_DATABASE=Radeon 7500 LE + +pci:v00001002d00005157sv0000174Bsd00007161* + ID_MODEL_FROM_DATABASE=Radeon RV200 QW [Radeon 7500 LE] + +pci:v00001002d00005157sv000017AFsd00000202* + ID_MODEL_FROM_DATABASE=RV200 QW [Excalibur Radeon 7500LE] + +pci:v00001002d00005159* + ID_MODEL_FROM_DATABASE=RV100 [Radeon 7000 / Radeon VE] + +pci:v00001002d00005159sv00001002sd0000000A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005159sv00001002sd0000000B* + ID_MODEL_FROM_DATABASE=Radeon 7000 + +pci:v00001002d00005159sv00001002sd00000038* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005159sv00001002sd0000003A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005159sv00001002sd000000BA* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005159sv00001002sd0000013A* + ID_MODEL_FROM_DATABASE=Radeon 7000/Radeon VE + +pci:v00001002d00005159sv00001002sd00000908* + ID_MODEL_FROM_DATABASE=XVR-100 (supplied by Sun) + +pci:v00001002d00005159sv00001014sd0000029A* + ID_MODEL_FROM_DATABASE=Remote Supervisor Adapter II (RSA2) + +pci:v00001002d00005159sv00001014sd000002C8* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00001002d00005159sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 Embedded Radeon 7000/VE + +pci:v00001002d00005159sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 Embedded Radeon 7000-M + +pci:v00001002d00005159sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Embedded Radeon 7000/VE + +pci:v00001002d00005159sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00001002d00005159sv0000103Csd00001292* + ID_MODEL_FROM_DATABASE=Radeon 7000 + +pci:v00001002d00005159sv00001043sd0000C00A* + ID_MODEL_FROM_DATABASE=A7000/T/64M + +pci:v00001002d00005159sv00001458sd00004002* + ID_MODEL_FROM_DATABASE=RV100 QY [RADEON 7000 PRO MAYA AV Series] + +pci:v00001002d00005159sv0000148Csd00002003* + ID_MODEL_FROM_DATABASE=RV100 QY [Radeon 7000 Multi-Display Edition] + +pci:v00001002d00005159sv0000148Csd00002023* + ID_MODEL_FROM_DATABASE=RV100 QY [Radeon 7000 Evil Master Multi-Display] + +pci:v00001002d00005159sv0000174Bsd00000280* + ID_MODEL_FROM_DATABASE=Radeon RV100 QY [Radeon 7000/VE] + +pci:v00001002d00005159sv0000174Bsd00007112* + ID_MODEL_FROM_DATABASE=Radeon VE 7000 + +pci:v00001002d00005159sv0000174Bsd00007C28* + ID_MODEL_FROM_DATABASE=Radeon VE 7000 DDR + +pci:v00001002d00005159sv00001787sd00000202* + ID_MODEL_FROM_DATABASE=RV100 QY [Excalibur Radeon 7000] + +pci:v00001002d00005159sv000017EEsd00001001* + ID_MODEL_FROM_DATABASE=Radeon 7000 64MB DDR + DVI + +pci:v00001002d0000515E* + ID_MODEL_FROM_DATABASE=ES1000 + +pci:v00001002d0000515Esv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00001002d0000515Esv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00001002d0000515Esv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd0000020B* + ID_MODEL_FROM_DATABASE=PowerEdge T605 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd00000223* + ID_MODEL_FROM_DATABASE=PowerEdge R905 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 Embedded ATI ES1000 + +pci:v00001002d0000515Esv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 Embedded ATI ES1000 + +pci:v00001002d0000515Esv0000103Csd00001304* + ID_MODEL_FROM_DATABASE=Integrity iLO2 Advanced KVM VGA [AD307A] + +pci:v00001002d0000515Esv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00001002d0000515Esv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00001002d0000515Esv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00001002d00005245* + ID_MODEL_FROM_DATABASE=Rage 128 GL PCI + +pci:v00001002d00005245sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Xpert 128 + +pci:v00001002d00005245sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005245sv00001002sd00000029* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005245sv00001002sd00000068* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005246* + ID_MODEL_FROM_DATABASE=Rage Fury/Xpert 128/Xpert 2000 AGP 2x + +pci:v00001002d00005246sv00001002sd00000004* + ID_MODEL_FROM_DATABASE=Magnum/Xpert 128/Xpert 99 + +pci:v00001002d00005246sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Magnum/Xpert128/X99/Xpert2000 + +pci:v00001002d00005246sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Rage 128 AIW AGP + +pci:v00001002d00005246sv00001002sd00000044* + ID_MODEL_FROM_DATABASE=Rage Fury/Xpert 128/Xpert 2000 + +pci:v00001002d00005246sv00001002sd00000068* + ID_MODEL_FROM_DATABASE=Rage 128 AIW AGP + +pci:v00001002d00005246sv00001002sd00000448* + ID_MODEL_FROM_DATABASE=Rage Fury + +pci:v00001002d0000524B* + ID_MODEL_FROM_DATABASE=Rage 128 VR PCI + +pci:v00001002d0000524C* + ID_MODEL_FROM_DATABASE=Rage 128 VR AGP + +pci:v00001002d0000524Csv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Xpert 99/Xpert 2000 + +pci:v00001002d0000524Csv00001002sd00000088* + ID_MODEL_FROM_DATABASE=Xpert 99 + +pci:v00001002d00005346* + ID_MODEL_FROM_DATABASE=Rage 128 SF/4x AGP 2x + +pci:v00001002d00005346sv00001002sd00000048* + ID_MODEL_FROM_DATABASE=RAGE 128 16MB VGA TVOUT AMC PAL + +pci:v00001002d0000534D* + ID_MODEL_FROM_DATABASE=Rage 128 4X AGP 4x + +pci:v00001002d0000534Dsv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Xpert 99/Xpert 2000 + +pci:v00001002d0000534Dsv00001002sd00000018* + ID_MODEL_FROM_DATABASE=Xpert 2000 + +pci:v00001002d00005354* + ID_MODEL_FROM_DATABASE=Mach 64 VT + +pci:v00001002d00005354sv00001002sd00005654* + ID_MODEL_FROM_DATABASE=Mach 64 reference + +pci:v00001002d00005446* + ID_MODEL_FROM_DATABASE=Rage 128 PRO Ultra AGP 4x + +pci:v00001002d00005446sv00001002sd00000004* + ID_MODEL_FROM_DATABASE=Rage Fury Pro + +pci:v00001002d00005446sv00001002sd00000008* + ID_MODEL_FROM_DATABASE=Rage Fury Pro/Xpert 2000 Pro + +pci:v00001002d00005446sv00001002sd00000018* + ID_MODEL_FROM_DATABASE=Rage Fury Pro/Xpert 2000 Pro + +pci:v00001002d00005446sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Rage 128 AIW Pro AGP + +pci:v00001002d00005446sv00001002sd00000029* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005446sv00001002sd0000002A* + ID_MODEL_FROM_DATABASE=Rage 128 AIW Pro AGP + +pci:v00001002d00005446sv00001002sd0000002B* + ID_MODEL_FROM_DATABASE=Rage 128 AIW + +pci:v00001002d00005446sv00001002sd00000048* + ID_MODEL_FROM_DATABASE=Xpert 2000 Pro + +pci:v00001002d00005452* + ID_MODEL_FROM_DATABASE=Rage 128 PRO Ultra4XL VR-R AGP + +pci:v00001002d00005452sv00001002sd0000001C* + ID_MODEL_FROM_DATABASE=Rage 128 Pro 4XL + +pci:v00001002d00005452sv0000103Csd00001279* + ID_MODEL_FROM_DATABASE=Rage 128 Pro 4XL + +pci:v00001002d00005460* + ID_MODEL_FROM_DATABASE=RV370/M22 [Mobility Radeon X300] + +pci:v00001002d00005460sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00001002d00005461* + ID_MODEL_FROM_DATABASE=RV370/M22 [Mobility Radeon X300] + +pci:v00001002d00005462* + ID_MODEL_FROM_DATABASE=RV380/M24C [Mobility Radeon X600 SE] + +pci:v00001002d00005464* + ID_MODEL_FROM_DATABASE=RV370/M22 GL [Mobility FireGL V3100] + +pci:v00001002d00005549* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 GTO] + +pci:v00001002d0000554A* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 XT Platinum Edition] + +pci:v00001002d0000554B* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 GT/SE] + +pci:v00001002d0000554Bsv00001002sd00000302* + ID_MODEL_FROM_DATABASE=Radeon X800 SE + +pci:v00001002d0000554D* + ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] + +pci:v00001002d0000554Dsv00001002sd00000322* + ID_MODEL_FROM_DATABASE=All-In-Wonder X800 XL + +pci:v00001002d0000554Dsv00001458sd00002124* + ID_MODEL_FROM_DATABASE=GV-R80L256V-B (AGP) + +pci:v00001002d0000554E* + ID_MODEL_FROM_DATABASE=R430 [All-In-Wonder X800 GT] + +pci:v00001002d0000554F* + ID_MODEL_FROM_DATABASE=R430 [Radeon X800] + +pci:v00001002d00005550* + ID_MODEL_FROM_DATABASE=R423 GL [FireGL V7100] + +pci:v00001002d00005551* + ID_MODEL_FROM_DATABASE=R423 GL [FireGL V5100] + +pci:v00001002d00005569* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 PRO] (Secondary) + +pci:v00001002d0000556B* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 GT] (Secondary) + +pci:v00001002d0000556D* + ID_MODEL_FROM_DATABASE=R430 [Radeon X800 XL] (Secondary) + +pci:v00001002d0000556Dsv00001458sd00002125* + ID_MODEL_FROM_DATABASE=GV-R80L256V-B (AGP) + +pci:v00001002d0000556F* + ID_MODEL_FROM_DATABASE=R430 [Radeon X800] (Secondary) + +pci:v00001002d00005571* + ID_MODEL_FROM_DATABASE=R423 GL [FireGL V5100] (Secondary) + +pci:v00001002d0000564B* + ID_MODEL_FROM_DATABASE=RV410/M26 GL [Mobility FireGL V5000] + +pci:v00001002d0000564F* + ID_MODEL_FROM_DATABASE=RV410/M26 [Mobility Radeon X700 XL] + +pci:v00001002d00005652* + ID_MODEL_FROM_DATABASE=RV410/M26 [Mobility Radeon X700] + +pci:v00001002d00005653* + ID_MODEL_FROM_DATABASE=RV410/M26 [Mobility Radeon X700] + +pci:v00001002d00005653sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v00001002d00005653sv0000103Csd00000940* + ID_MODEL_FROM_DATABASE=HP Compaq NW8240 Mobile Workstation + +pci:v00001002d00005654* + ID_MODEL_FROM_DATABASE=264VT [Mach64 VT] + +pci:v00001002d00005654sv00001002sd00005654* + ID_MODEL_FROM_DATABASE=Mach64VT Reference + +pci:v00001002d00005655* + ID_MODEL_FROM_DATABASE=264VT3 [Mach64 VT3] + +pci:v00001002d00005656* + ID_MODEL_FROM_DATABASE=264VT4 [Mach64 VT4] + +pci:v00001002d00005657* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X550 XTX / X700] + +pci:v00001002d00005830* + ID_MODEL_FROM_DATABASE=RS300 Host Bridge + +pci:v00001002d00005831* + ID_MODEL_FROM_DATABASE=RS300 Host Bridge + +pci:v00001002d00005832* + ID_MODEL_FROM_DATABASE=RS300 Host Bridge + +pci:v00001002d00005833* + ID_MODEL_FROM_DATABASE=RS300 Host Bridge + +pci:v00001002d00005834* + ID_MODEL_FROM_DATABASE=RS300 [Radeon 9100 IGP] + +pci:v00001002d00005835* + ID_MODEL_FROM_DATABASE=RS300M [Mobility Radeon 9100 IGP] + +pci:v00001002d00005838* + ID_MODEL_FROM_DATABASE=RS300 AGP Bridge + +pci:v00001002d00005854* + ID_MODEL_FROM_DATABASE=RS480 [Radeon Xpress 200 Series] (Secondary) + +pci:v00001002d00005874* + ID_MODEL_FROM_DATABASE=RS480 [Radeon Xpress 1150] (Secondary) + +pci:v00001002d00005940* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO] (Secondary) + +pci:v00001002d00005940sv000017AFsd00002021* + ID_MODEL_FROM_DATABASE=Excalibur Radeon 9250 (Secondary) + +pci:v00001002d00005941* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200] (Secondary) + +pci:v00001002d00005941sv00001458sd00004019* + ID_MODEL_FROM_DATABASE=Radeon 9200 + +pci:v00001002d00005941sv0000174Bsd00007C12* + ID_MODEL_FROM_DATABASE=Radeon 9200 + +pci:v00001002d00005941sv000017AFsd0000200D* + ID_MODEL_FROM_DATABASE=Excalibur Radeon 9200 + +pci:v00001002d00005941sv000018BCsd00000050* + ID_MODEL_FROM_DATABASE=GC-R9200-C3 (Secondary) + +pci:v00001002d00005944* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE PCI] + +pci:v00001002d00005950* + ID_MODEL_FROM_DATABASE=RS480/RS482/RS485 Host Bridge + +pci:v00001002d00005950sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMMi + +pci:v00001002d00005950sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00005950sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001002d00005950sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00005950sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00005950sv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00005951* + ID_MODEL_FROM_DATABASE=RX480/RX482 Host Bridge + +pci:v00001002d00005952* + ID_MODEL_FROM_DATABASE=RD580 Host Bridge + +pci:v00001002d00005954* + ID_MODEL_FROM_DATABASE=RS480 [Radeon Xpress 200 Series] + +pci:v00001002d00005954sv00001002sd00005954* + ID_MODEL_FROM_DATABASE=RV370 [Radeon Xpress 200G Series] + +pci:v00001002d00005955* + ID_MODEL_FROM_DATABASE=RS480M [Mobility Radeon Xpress 200] + +pci:v00001002d00005955sv00001002sd00005955* + ID_MODEL_FROM_DATABASE=RS480 0x5955 [Radeon XPRESS 200M 5955 (PCIE)] + +pci:v00001002d00005955sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v00001002d00005955sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v00001002d00005956* + ID_MODEL_FROM_DATABASE=RD790 Host Bridge + +pci:v00001002d00005957* + ID_MODEL_FROM_DATABASE=RX780/RX790 Host Bridge + +pci:v00001002d00005957sv00001849sd00005957* + ID_MODEL_FROM_DATABASE=A770CrossFire Motherboard + +pci:v00001002d00005958* + ID_MODEL_FROM_DATABASE=RD780 Host Bridge + +pci:v00001002d00005960* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 PRO] + +pci:v00001002d00005960sv000017AFsd00002020* + ID_MODEL_FROM_DATABASE=Excalibur Radeon 9250 + +pci:v00001002d00005961* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200] + +pci:v00001002d00005961sv00001002sd00002F72* + ID_MODEL_FROM_DATABASE=All-in-Wonder 9200 Series + +pci:v00001002d00005961sv00001019sd00004C30* + ID_MODEL_FROM_DATABASE=Radeon 9200 VIVO + +pci:v00001002d00005961sv000012ABsd00005961* + ID_MODEL_FROM_DATABASE=YUAN SMARTVGA Radeon 9200 + +pci:v00001002d00005961sv00001458sd00004018* + ID_MODEL_FROM_DATABASE=Radeon 9200 + +pci:v00001002d00005961sv0000174Bsd00007C13* + ID_MODEL_FROM_DATABASE=Radeon 9200 + +pci:v00001002d00005961sv000017AFsd0000200C* + ID_MODEL_FROM_DATABASE=Excalibur Radeon 9200 + +pci:v00001002d00005961sv000018BCsd00000050* + ID_MODEL_FROM_DATABASE=Radeon 9200 Game Buster + +pci:v00001002d00005961sv000018BCsd00000051* + ID_MODEL_FROM_DATABASE=GC-R9200-C3 + +pci:v00001002d00005961sv000018BCsd00000053* + ID_MODEL_FROM_DATABASE=Radeon 9200 Game Buster VIVO + +pci:v00001002d00005962* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200] + +pci:v00001002d00005964* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] + +pci:v00001002d00005964sv00001002sd00005964* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE, 64-bit 128MB DDR, 200/166MHz + +pci:v00001002d00005964sv00001043sd0000C006* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE / TD / 128M + +pci:v00001002d00005964sv00001458sd00004018* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE + +pci:v00001002d00005964sv00001458sd00004032* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE 128MB + +pci:v00001002d00005964sv0000147Bsd00006191* + ID_MODEL_FROM_DATABASE=R9200SE-DT + +pci:v00001002d00005964sv0000148Csd00002073* + ID_MODEL_FROM_DATABASE=CN-AG92E + +pci:v00001002d00005964sv0000174Bsd00007C13* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE + +pci:v00001002d00005964sv00001787sd00005964* + ID_MODEL_FROM_DATABASE=Excalibur 9200SE VIVO 128M + +pci:v00001002d00005964sv000017AFsd00002012* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE Excalibur + +pci:v00001002d00005964sv000018BCsd00000170* + ID_MODEL_FROM_DATABASE=Sapphire Radeon 9200 SE 128MB Game Buster + +pci:v00001002d00005964sv000018BCsd00000173* + ID_MODEL_FROM_DATABASE=GC-R9200L(SE)-C3H [Radeon 9200 Game Buster] + +pci:v00001002d00005965* + ID_MODEL_FROM_DATABASE=RV280 GL [FireMV 2200 PCI] + +pci:v00001002d00005974* + ID_MODEL_FROM_DATABASE=RS482/RS485 [Radeon Xpress 1100/1150] + +pci:v00001002d00005974sv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v00001002d00005974sv00001462sd00007141* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00005975* + ID_MODEL_FROM_DATABASE=RS482M [Mobility Radeon Xpress 200] + +pci:v00001002d00005978* + ID_MODEL_FROM_DATABASE=RX780/RD790 PCI to PCI bridge (external gfx0 port A) + +pci:v00001002d00005978sv00001849sd00005957* + ID_MODEL_FROM_DATABASE=A770CrossFire Motherboard + +pci:v00001002d00005979* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (external gfx0 port B) + +pci:v00001002d0000597A* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (PCI express gpp port A) + +pci:v00001002d0000597B* + ID_MODEL_FROM_DATABASE=RX780/RD790 PCI to PCI bridge (PCI express gpp port B) + +pci:v00001002d0000597C* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (PCI express gpp port C) + +pci:v00001002d0000597D* + ID_MODEL_FROM_DATABASE=RX780/RD790 PCI to PCI bridge (PCI express gpp port D) + +pci:v00001002d0000597E* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (PCI express gpp port E) + +pci:v00001002d0000597Esv00001849sd00005957* + ID_MODEL_FROM_DATABASE=A770CrossFire Motherboard + +pci:v00001002d0000597F* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (PCI express gpp port F) + +pci:v00001002d0000597Fsv00001849sd00005957* + ID_MODEL_FROM_DATABASE=A770CrossFire Motherboard + +pci:v00001002d00005980* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (external gfx1 port A) + +pci:v00001002d00005981* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (external gfx1 port B) + +pci:v00001002d00005982* + ID_MODEL_FROM_DATABASE=RD790 PCI to PCI bridge (NB-SB link) + +pci:v00001002d00005A10* + ID_MODEL_FROM_DATABASE=RD890 Northbridge only dual slot (2x16) PCI-e GFX Hydra part + +pci:v00001002d00005A11* + ID_MODEL_FROM_DATABASE=RD890 Northbridge only single slot PCI-e GFX Hydra part + +pci:v00001002d00005A12* + ID_MODEL_FROM_DATABASE=RD890 Northbridge only dual slot (2x8) PCI-e GFX Hydra part + +pci:v00001002d00005A12sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00005A13* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (external gfx0 port A) + +pci:v00001002d00005A14* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (external gfx0 port B) + +pci:v00001002d00005A15* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port A) + +pci:v00001002d00005A16* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port B) + +pci:v00001002d00005A17* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port C) + +pci:v00001002d00005A18* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port D) + +pci:v00001002d00005A18sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00005A19* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port E) + +pci:v00001002d00005A1A* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port F) + +pci:v00001002d00005A1B* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port G) + +pci:v00001002d00005A1C* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (PCI express gpp port H) + +pci:v00001002d00005A1D* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (external gfx1 port A) + +pci:v00001002d00005A1E* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (external gfx1 port B) + +pci:v00001002d00005A1F* + ID_MODEL_FROM_DATABASE=RD890 PCI to PCI bridge (NB-SB link) + +pci:v00001002d00005A1Fsv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00001002d00005A20* + ID_MODEL_FROM_DATABASE=RD890S PCI Express bridge for GPP2 port 1 + +pci:v00001002d00005A23* + ID_MODEL_FROM_DATABASE=RD990 I/O Memory Management Unit (IOMMU) + +pci:v00001002d00005A31* + ID_MODEL_FROM_DATABASE=RC410 Host Bridge + +pci:v00001002d00005A33* + ID_MODEL_FROM_DATABASE=RS400 Host Bridge + +pci:v00001002d00005A34* + ID_MODEL_FROM_DATABASE=RS4xx PCI Express Port [ext gfx] + +pci:v00001002d00005A36* + ID_MODEL_FROM_DATABASE=RC4xx/RS4xx PCI Express Port 1 + +pci:v00001002d00005A37* + ID_MODEL_FROM_DATABASE=RC4xx/RS4xx PCI Express Port 2 + +pci:v00001002d00005A38* + ID_MODEL_FROM_DATABASE=RC4xx/RS4xx PCI Express Port 3 + +pci:v00001002d00005A39* + ID_MODEL_FROM_DATABASE=RC4xx/RS4xx PCI Express Port 4 + +pci:v00001002d00005A3F* + ID_MODEL_FROM_DATABASE=RC4xx/RS4xx PCI Bridge [int gfx] + +pci:v00001002d00005A3Fsv00001462sd00007217* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001002d00005A41* + ID_MODEL_FROM_DATABASE=RS400 [Radeon Xpress 200] + +pci:v00001002d00005A42* + ID_MODEL_FROM_DATABASE=RS400M [Radeon Xpress 200M] + +pci:v00001002d00005A61* + ID_MODEL_FROM_DATABASE=RC410 [Radeon Xpress 200/1100] + +pci:v00001002d00005A62* + ID_MODEL_FROM_DATABASE=RC410M [Mobility Radeon Xpress 200M] + +pci:v00001002d00005B60* + ID_MODEL_FROM_DATABASE=RV370 [Radeon X300] + +pci:v00001002d00005B60sv00001043sd0000002A* + ID_MODEL_FROM_DATABASE=Extreme AX300SE-X + +pci:v00001002d00005B60sv00001043sd0000032E* + ID_MODEL_FROM_DATABASE=Extreme AX300/TD + +pci:v00001002d00005B60sv00001458sd00002102* + ID_MODEL_FROM_DATABASE=GV-RX30S128D (X300SE) + +pci:v00001002d00005B60sv00001462sd00000400* + ID_MODEL_FROM_DATABASE=RX300SE-TD128E (MS-8940 REV:200) + +pci:v00001002d00005B60sv00001462sd00000402* + ID_MODEL_FROM_DATABASE=RX300SE-TD128E (MS-8940) + +pci:v00001002d00005B60sv0000174Bsd00000500* + ID_MODEL_FROM_DATABASE=Radeon X300 (PCIE) + +pci:v00001002d00005B60sv0000196Dsd00001086* + ID_MODEL_FROM_DATABASE=X300SE HM + +pci:v00001002d00005B62* + ID_MODEL_FROM_DATABASE=RV370 [Radeon X600/X600 SE] + +pci:v00001002d00005B63* + ID_MODEL_FROM_DATABASE=RV370 [Radeon X300/X550/X1050 Series] + +pci:v00001002d00005B64* + ID_MODEL_FROM_DATABASE=RV370 GL [FireGL V3100] + +pci:v00001002d00005B65* + ID_MODEL_FROM_DATABASE=RV370 GL [FireMV 2200] + +pci:v00001002d00005B66* + ID_MODEL_FROM_DATABASE=RV370X + +pci:v00001002d00005B70* + ID_MODEL_FROM_DATABASE=RV370 [Radeon X300 SE] + +pci:v00001002d00005B70sv00001462sd00000403* + ID_MODEL_FROM_DATABASE=Radeon X300 SE 128MB DDR + +pci:v00001002d00005B70sv0000174Bsd00000501* + ID_MODEL_FROM_DATABASE=Radeon X300 SE + +pci:v00001002d00005B70sv0000196Dsd00001087* + ID_MODEL_FROM_DATABASE=Radeon X300 SE HyperMemory + +pci:v00001002d00005B72* + ID_MODEL_FROM_DATABASE=RV380 [Radeon X300/X550/X1050 Series] (Secondary) + +pci:v00001002d00005B73* + ID_MODEL_FROM_DATABASE=RV370 [Radeon X300/X550/X1050 Series] (Secondary) + +pci:v00001002d00005B74* + ID_MODEL_FROM_DATABASE=RV370 GL [FireGL V3100] (Secondary) + +pci:v00001002d00005B75* + ID_MODEL_FROM_DATABASE=RV370 GL [FireMV 2200] (Secondary) + +pci:v00001002d00005C61* + ID_MODEL_FROM_DATABASE=RV280/M9+ [Mobility Radeon 9200 AGP] + +pci:v00001002d00005C63* + ID_MODEL_FROM_DATABASE=RV280/M9+ [Mobility Radeon 9200 AGP] + +pci:v00001002d00005C63sv00001002sd00005C63* + ID_MODEL_FROM_DATABASE=Apple iBook G4 2004 + +pci:v00001002d00005C63sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30 notebook + +pci:v00001002d00005D44* + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Secondary) + +pci:v00001002d00005D44sv00001458sd00004019* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE (Secondary) + +pci:v00001002d00005D44sv00001458sd00004032* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE 128MB + +pci:v00001002d00005D44sv0000147Bsd00006190* + ID_MODEL_FROM_DATABASE=R9200SE-DT (Secondary) + +pci:v00001002d00005D44sv0000174Bsd00007C12* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE (Secondary) + +pci:v00001002d00005D44sv00001787sd00005965* + ID_MODEL_FROM_DATABASE=Excalibur 9200SE VIVO 128M (Secondary) + +pci:v00001002d00005D44sv000017AFsd00002013* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE Excalibur (Secondary) + +pci:v00001002d00005D44sv000018BCsd00000171* + ID_MODEL_FROM_DATABASE=Radeon 9200 SE 128MB Game Buster (Secondary) + +pci:v00001002d00005D44sv000018BCsd00000172* + ID_MODEL_FROM_DATABASE=GC-R9200L(SE)-C3H [Radeon 9200 Game Buster] + +pci:v00001002d00005D45* + ID_MODEL_FROM_DATABASE=RV280 GL [FireMV 2200 PCI] (Secondary) + +pci:v00001002d00005D48* + ID_MODEL_FROM_DATABASE=R423/M28 [Mobility Radeon X800 XT] + +pci:v00001002d00005D49* + ID_MODEL_FROM_DATABASE=R423/M28 GL [Mobility FireGL V5100] + +pci:v00001002d00005D4A* + ID_MODEL_FROM_DATABASE=R423/M28 [Mobility Radeon X800] + +pci:v00001002d00005D4D* + ID_MODEL_FROM_DATABASE=R480 [Radeon X850 XT Platinum Edition] + +pci:v00001002d00005D4E* + ID_MODEL_FROM_DATABASE=R480 [Radeon X850 SE] + +pci:v00001002d00005D4F* + ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO] + +pci:v00001002d00005D50* + ID_MODEL_FROM_DATABASE=R480 GL [FireGL V7200] + +pci:v00001002d00005D52* + ID_MODEL_FROM_DATABASE=R480 [Radeon X850 XT] + +pci:v00001002d00005D52sv00001002sd00000B12* + ID_MODEL_FROM_DATABASE=PowerColor X850XT PCIe (Primary) + +pci:v00001002d00005D57* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 XT] + +pci:v00001002d00005D6D* + ID_MODEL_FROM_DATABASE=R480 [Radeon X850 XT Platinum Edition] (Secondary) + +pci:v00001002d00005D6F* + ID_MODEL_FROM_DATABASE=R480 [Radeon X800 GTO] (Secondary) + +pci:v00001002d00005D72* + ID_MODEL_FROM_DATABASE=R480 [Radeon X850 XT] (Secondary) + +pci:v00001002d00005D72sv00001002sd00000B13* + ID_MODEL_FROM_DATABASE=PowerColor X850XT PCIe (Secondary) + +pci:v00001002d00005D77* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 XT] (Secondary) + +pci:v00001002d00005E48* + ID_MODEL_FROM_DATABASE=RV410 GL [FireGL V5000] + +pci:v00001002d00005E49* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700 Series] + +pci:v00001002d00005E4A* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700 XT] + +pci:v00001002d00005E4B* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700 PRO] + +pci:v00001002d00005E4C* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700 SE] + +pci:v00001002d00005E4D* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700] + +pci:v00001002d00005E4Dsv0000148Csd00002116* + ID_MODEL_FROM_DATABASE=Bravo X700 + +pci:v00001002d00005E4F* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700] + +pci:v00001002d00005E4Fsv00001569sd00001E4F* + ID_MODEL_FROM_DATABASE=Radeon X550 XT + +pci:v00001002d00005E6B* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700 PRO] (Secondary) + +pci:v00001002d00005E6D* + ID_MODEL_FROM_DATABASE=RV410 [Radeon X700] (Secondary) + +pci:v00001002d00005E6Dsv0000148Csd00002117* + ID_MODEL_FROM_DATABASE=Bravo X700 (Secondary) + +pci:v00001002d00005F57* + ID_MODEL_FROM_DATABASE=R423 [Radeon X800 XT] + +pci:v00001002d00006600* + ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8670A/8670M/8750M] + +pci:v00001002d00006601* + ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8730M] + +pci:v00001002d00006601sv0000103Csd00002100* + ID_MODEL_FROM_DATABASE=FirePro M4100 + +pci:v00001002d00006602* + ID_MODEL_FROM_DATABASE=Mars + +pci:v00001002d00006603* + ID_MODEL_FROM_DATABASE=Mars + +pci:v00001002d00006604* + ID_MODEL_FROM_DATABASE=Mars [Radeon R7 M265] + +pci:v00001002d00006605* + ID_MODEL_FROM_DATABASE=Mars [Radeon R7 M260] + +pci:v00001002d00006606* + ID_MODEL_FROM_DATABASE=Mars XTX [Radeon HD 8790M] + +pci:v00001002d00006607* + ID_MODEL_FROM_DATABASE=Mars LE [Radeon HD 8530M] + +pci:v00001002d00006610* + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] + +pci:v00001002d00006611* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM] + +pci:v00001002d00006611sv00001028sd0000210B* + ID_MODEL_FROM_DATABASE=Radeon R5 240 OEM + +pci:v00001002d00006611sv0000174Bsd00004248* + ID_MODEL_FROM_DATABASE=Radeon R7 240 OEM + +pci:v00001002d00006611sv0000174Bsd0000A240* + ID_MODEL_FROM_DATABASE=Radeon R7 240 OEM + +pci:v00001002d00006611sv00001B0Asd000090D3* + ID_MODEL_FROM_DATABASE=Radeon R7 240 OEM + +pci:v00001002d00006613* + ID_MODEL_FROM_DATABASE=Oland PRO [Radeon R7 240] + +pci:v00001002d00006620* + ID_MODEL_FROM_DATABASE=Mars + +pci:v00001002d00006621* + ID_MODEL_FROM_DATABASE=Mars PRO + +pci:v00001002d00006623* + ID_MODEL_FROM_DATABASE=Mars + +pci:v00001002d00006631* + ID_MODEL_FROM_DATABASE=Oland + +pci:v00001002d00006640* + ID_MODEL_FROM_DATABASE=Saturn XT [FirePro M6100] + +pci:v00001002d00006641* + ID_MODEL_FROM_DATABASE=Saturn PRO [Radeon HD 8930M] + +pci:v00001002d00006649* + ID_MODEL_FROM_DATABASE=Bonaire + +pci:v00001002d00006650* + ID_MODEL_FROM_DATABASE=Bonaire + +pci:v00001002d00006651* + ID_MODEL_FROM_DATABASE=Bonaire + +pci:v00001002d00006658* + ID_MODEL_FROM_DATABASE=Bonaire XTX [Radeon R7 260X] + +pci:v00001002d0000665C* + ID_MODEL_FROM_DATABASE=Bonaire XT [Radeon HD 7790/8770 / R9 260 OEM] + +pci:v00001002d0000665Csv00001043sd00000452* + ID_MODEL_FROM_DATABASE=Radeon HD 7790 DirectCU II OC + +pci:v00001002d0000665Csv00001462sd00002930* + ID_MODEL_FROM_DATABASE=Radeon HD 7790 OC + +pci:v00001002d0000665Csv00001462sd00002932* + ID_MODEL_FROM_DATABASE=Radeon HD 8770 + +pci:v00001002d0000665Csv00001462sd00002934* + ID_MODEL_FROM_DATABASE=Radeon R9 260 OEM + +pci:v00001002d0000665Csv0000148Csd00009260* + ID_MODEL_FROM_DATABASE=Radeon R9 260 OEM + +pci:v00001002d0000665Csv00001682sd00003310* + ID_MODEL_FROM_DATABASE=Radeon HD 7790 Black Edition 2 GB + +pci:v00001002d0000665Csv0000174Bsd0000E253* + ID_MODEL_FROM_DATABASE=Radeon HD 7790 Dual-X OC + +pci:v00001002d0000665Csv00001787sd00002329* + ID_MODEL_FROM_DATABASE=Radeon HD 7790 TurboDuo + +pci:v00001002d0000665D* + ID_MODEL_FROM_DATABASE=Bonaire [Radeon R7 200 Series] + +pci:v00001002d00006660* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M] + +pci:v00001002d00006663* + ID_MODEL_FROM_DATABASE=Sun PRO [Radeon HD 8570A/8570M] + +pci:v00001002d00006663sv00001025sd00000846* + ID_MODEL_FROM_DATABASE=Radeon HD 8570A + +pci:v00001002d00006664* + ID_MODEL_FROM_DATABASE=Jet XT [Radeon R5 M200 Series] + +pci:v00001002d00006665* + ID_MODEL_FROM_DATABASE=Jet PRO [Radeon R5 M200 Series] + +pci:v00001002d00006667* + ID_MODEL_FROM_DATABASE=Jet ULT [Radeon R5 M200 Series] + +pci:v00001002d0000666F* + ID_MODEL_FROM_DATABASE=Sun LE [Radeon HD 8550M] + +pci:v00001002d00006670* + ID_MODEL_FROM_DATABASE=Hainan + +pci:v00001002d00006704* + ID_MODEL_FROM_DATABASE=Cayman PRO GL [FirePro V7900] + +pci:v00001002d00006707* + ID_MODEL_FROM_DATABASE=Cayman LE GL [FirePro V5900] + +pci:v00001002d00006718* + ID_MODEL_FROM_DATABASE=Cayman XT [Radeon HD 6970] + +pci:v00001002d00006719* + ID_MODEL_FROM_DATABASE=Cayman PRO [Radeon HD 6950] + +pci:v00001002d0000671C* + ID_MODEL_FROM_DATABASE=Antilles [Radeon HD 6990] + +pci:v00001002d0000671D* + ID_MODEL_FROM_DATABASE=Antilles [Radeon HD 6990] + +pci:v00001002d0000671F* + ID_MODEL_FROM_DATABASE=Cayman CE [Radeon HD 6930] + +pci:v00001002d00006720* + ID_MODEL_FROM_DATABASE=Blackcomb [Radeon HD 6970M/6990M] + +pci:v00001002d00006720sv00001028sd0000048F* + ID_MODEL_FROM_DATABASE=Radeon HD 6990M + +pci:v00001002d00006720sv00001028sd00000490* + ID_MODEL_FROM_DATABASE=Alienware M17x R3 Radeon HD 6970M + +pci:v00001002d00006720sv00001028sd000004A4* + ID_MODEL_FROM_DATABASE=FirePro M8900 + +pci:v00001002d00006720sv00001028sd000004BA* + ID_MODEL_FROM_DATABASE=Radeon HD 6990M + +pci:v00001002d00006720sv00001028sd0000053F* + ID_MODEL_FROM_DATABASE=FirePro M8900 + +pci:v00001002d00006720sv0000106Bsd00000B00* + ID_MODEL_FROM_DATABASE=Radeon HD 6970M + +pci:v00001002d00006720sv00001558sd00005102* + ID_MODEL_FROM_DATABASE=Radeon HD 6970M + +pci:v00001002d00006720sv00001558sd00005104* + ID_MODEL_FROM_DATABASE=Radeon HD 6990M + +pci:v00001002d00006720sv00001558sd00007201* + ID_MODEL_FROM_DATABASE=Radeon HD 6990M + +pci:v00001002d00006720sv0000174Bsd0000E188* + ID_MODEL_FROM_DATABASE=Radeon HD 6970M + +pci:v00001002d00006724* + ID_MODEL_FROM_DATABASE=Blackcomb [Mobility Radeon HD 6000 series] + +pci:v00001002d00006725* + ID_MODEL_FROM_DATABASE=Blackcomb [Radeon HD 6900M Series] + +pci:v00001002d00006738* + ID_MODEL_FROM_DATABASE=Barts XT [Radeon HD 6870] + +pci:v00001002d00006738sv00001682sd00003103* + ID_MODEL_FROM_DATABASE=Radeon HD 8670 + +pci:v00001002d00006738sv00001787sd0000201A* + ID_MODEL_FROM_DATABASE=Barts XT [Radeon HD 6870 X2] + +pci:v00001002d00006738sv00001787sd0000201B* + ID_MODEL_FROM_DATABASE=Barts XT [Radeon HD 6870 X2] + +pci:v00001002d00006739* + ID_MODEL_FROM_DATABASE=Barts PRO [Radeon HD 6850] + +pci:v00001002d00006739sv00001043sd000003B4* + ID_MODEL_FROM_DATABASE=EAH6850 [Radeon HD 6850] + +pci:v00001002d0000673E* + ID_MODEL_FROM_DATABASE=Barts LE [Radeon HD 6790] + +pci:v00001002d0000673Esv0000148Csd00007720* + ID_MODEL_FROM_DATABASE=Radeon HD 7720 OEM + +pci:v00001002d00006740* + ID_MODEL_FROM_DATABASE=Whistler [Radeon HD 6730M/6770M/7690M XT] + +pci:v00001002d00006740sv00001019sd0000238C* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv00001019sd0000238E* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv00001019sd00002391* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv00001019sd00002392* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001002d00006740sv00001028sd0000053E* + ID_MODEL_FROM_DATABASE=FirePro M5950 + +pci:v00001002d00006740sv0000103Csd00001630* + ID_MODEL_FROM_DATABASE=FirePro M5950 + +pci:v00001002d00006740sv0000103Csd00001631* + ID_MODEL_FROM_DATABASE=FirePro M5950 + +pci:v00001002d00006740sv0000103Csd0000164B* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000103Csd0000164E* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000103Csd00001657* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd00001658* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd0000165A* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd0000165B* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd00001688* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd00001689* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd0000168A* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd0000185E* + ID_MODEL_FROM_DATABASE=Radeon HD 7690M XT + +pci:v00001002d00006740sv0000103Csd00003388* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd00003389* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd00003582* + ID_MODEL_FROM_DATABASE=Radeon HD 6770M + +pci:v00001002d00006740sv0000103Csd0000366C* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv00001043sd00001D02* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv00001043sd00001D12* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000104Dsd00009084* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000104Dsd00009085* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000144Dsd0000B074* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000144Dsd0000B077* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000144Dsd0000B084* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv0000144Dsd0000B088* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006740sv000017AAsd00003982* + ID_MODEL_FROM_DATABASE=Radeon HD 6730M + +pci:v00001002d00006741* + ID_MODEL_FROM_DATABASE=Whistler [Radeon HD 6630M/6650M/6750M/7670M/7690M] + +pci:v00001002d00006741sv00001019sd0000238E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001019sd0000238F* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000379* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000037B* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000037E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000382* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000384* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000385* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000386* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000387* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000388* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000442* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000451* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000489* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000048B* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000048C* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000050A* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000050B* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000050C* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000050E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000050F* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000513* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000514* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000515* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000516* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000051E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000051F* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000520* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000521* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000052A* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000555* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000556* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000055D* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000055E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000056D* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000059A* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000059B* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000059E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd0000059F* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000600* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000605* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000606* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001025sd00000619* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001028sd000004C1* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001028sd000004C5* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001028sd000004CD* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001028sd000004D7* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001028sd000004D9* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001028sd0000052D* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000103Csd00001617* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000103Csd00001646* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd00001647* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000103Csd0000164B* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000103Csd0000164E* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000103Csd00001688* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd00001689* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd0000168A* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd00001860* + ID_MODEL_FROM_DATABASE=Radeon HD 7690M + +pci:v00001002d00006741sv0000103Csd00003385* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000103Csd00003560* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd0000358D* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd00003590* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd00003593* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000103Csd0000366C* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001043sd00001CD2* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001043sd00002121* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001043sd00002122* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001043sd00002123* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001043sd00002125* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006741sv00001043sd00002127* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006741sv0000104Dsd0000907B* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000104Dsd00009080* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000104Dsd00009081* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000106Bsd000000E2* + ID_MODEL_FROM_DATABASE=MacBookPro8,2 [Core i7, 15", Late 2011] + +pci:v00001002d00006741sv00001179sd0000FD63* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv00001179sd0000FD65* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000144Dsd0000C093* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000144Dsd0000C0AC* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv0000144Dsd0000C0B3* + ID_MODEL_FROM_DATABASE=Radeon HD 6750M + +pci:v00001002d00006741sv0000144Dsd0000C539* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000144Dsd0000C609* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv0000152Dsd00000914* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv000017AAsd000021E1* + ID_MODEL_FROM_DATABASE=Radeon HD 6630M + +pci:v00001002d00006741sv000017AAsd00003970* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv000017AAsd00003976* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006741sv00001854sd00000907* + ID_MODEL_FROM_DATABASE=Radeon HD 6650M + +pci:v00001002d00006742* + ID_MODEL_FROM_DATABASE=Whistler LE [Radeon HD 6610M/7610M] + +pci:v00001002d00006742sv00001002sd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv00001019sd00002393* + ID_MODEL_FROM_DATABASE=Radeon HD 6610M + +pci:v00001002d00006742sv00001043sd00001D82* + ID_MODEL_FROM_DATABASE=K53SK Laptop Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB22* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB23* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB27* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB2A* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB2C* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB30* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB31* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB32* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB38* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB39* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB3A* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB3B* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB40* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB41* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB47* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB48* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB49* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB51* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB52* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB53* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB56* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB81* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB82* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FB83* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FC56* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FCD4* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001179sd0000FCEE* + ID_MODEL_FROM_DATABASE=Radeon HD 7610M + +pci:v00001002d00006742sv00001458sd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv00001462sd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv0000148Csd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv00001682sd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv0000174Bsd00005570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 5570] + +pci:v00001002d00006742sv0000174Bsd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv0000174Bsd00007570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 7570] + +pci:v00001002d00006742sv0000174Bsd00008510* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 8510] + +pci:v00001002d00006742sv0000174Bsd00008570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 8570] + +pci:v00001002d00006742sv00001787sd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv000017AFsd00006570* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 6570] + +pci:v00001002d00006742sv00008086sd00002111* + ID_MODEL_FROM_DATABASE=Radeon HD 6625M + +pci:v00001002d00006743* + ID_MODEL_FROM_DATABASE=Whistler [Radeon E6760] + +pci:v00001002d00006749* + ID_MODEL_FROM_DATABASE=Turks GL [FirePro V4900] + +pci:v00001002d0000674A* + ID_MODEL_FROM_DATABASE=Turks GL [FirePro V3900] + +pci:v00001002d00006750* + ID_MODEL_FROM_DATABASE=Onega [Radeon HD 6650A/7650A] + +pci:v00001002d00006750sv00001462sd00002670* + ID_MODEL_FROM_DATABASE=Radeon HD 6670A + +pci:v00001002d00006750sv000017AAsd00003079* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006750sv000017AAsd0000307A* + ID_MODEL_FROM_DATABASE=Radeon HD 6650A + +pci:v00001002d00006750sv000017AAsd00003087* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006750sv000017AAsd00003618* + ID_MODEL_FROM_DATABASE=Radeon HD 6650A + +pci:v00001002d00006750sv000017AAsd00003623* + ID_MODEL_FROM_DATABASE=Radeon HD 6650A + +pci:v00001002d00006750sv000017AAsd00003627* + ID_MODEL_FROM_DATABASE=Radeon HD 6650A + +pci:v00001002d00006751* + ID_MODEL_FROM_DATABASE=Turks [Radeon HD 7650A/7670A] + +pci:v00001002d00006751sv00001028sd00000548* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006751sv00001462sd00002671* + ID_MODEL_FROM_DATABASE=Radeon HD 7670A + +pci:v00001002d00006751sv00001462sd00002672* + ID_MODEL_FROM_DATABASE=Radeon HD 7670A + +pci:v00001002d00006751sv00001462sd00002680* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006751sv00001462sd00002681* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006751sv000017AAsd00003087* + ID_MODEL_FROM_DATABASE=Radeon HD 7650A + +pci:v00001002d00006758* + ID_MODEL_FROM_DATABASE=Turks XT [Radeon HD 6670/7670] + +pci:v00001002d00006758sv00001028sd00000B0E* + ID_MODEL_FROM_DATABASE=Radeon HD 6670 + +pci:v00001002d00006758sv0000103Csd00006882* + ID_MODEL_FROM_DATABASE=Radeon HD 6670 + +pci:v00001002d00006758sv00001462sd0000250A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670 + +pci:v00001002d00006758sv0000148Csd00007670* + ID_MODEL_FROM_DATABASE=Radeon HD 7670 + +pci:v00001002d00006758sv00001545sd00007670* + ID_MODEL_FROM_DATABASE=Radeon HD 7670 + +pci:v00001002d00006758sv00001682sd00003300* + ID_MODEL_FROM_DATABASE=Radeon HD 7670 + +pci:v00001002d00006758sv0000174Bsd00007670* + ID_MODEL_FROM_DATABASE=Radeon HD 7670 + +pci:v00001002d00006758sv0000174Bsd0000E181* + ID_MODEL_FROM_DATABASE=Radeon HD 6670 + +pci:v00001002d00006758sv00001787sd00002309* + ID_MODEL_FROM_DATABASE=Radeon HD 6670 + +pci:v00001002d00006759* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] + +pci:v00001002d00006759sv0000103Csd00003130* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001043sd00000403* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001462sd00002500* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001462sd00002509* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d00006759sv0000148Csd00007570* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d00006759sv00001642sd00003A67* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001682sd00003280* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d00006759sv00001682sd00003530* + ID_MODEL_FROM_DATABASE=Radeon HD 8550 + +pci:v00001002d00006759sv0000174Bsd00007570* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d00006759sv0000174Bsd0000E142* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv0000174Bsd0000E181* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd0000908F* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd00009090* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd00009091* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd00009092* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd0000909E* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006759sv00001B0Asd000090B5* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d00006759sv00001B0Asd000090B6* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d0000675D* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 7570] + +pci:v00001002d0000675F* + ID_MODEL_FROM_DATABASE=Turks LE [Radeon HD 5570/6510/7510/8510] + +pci:v00001002d0000675Fsv0000148Csd00006510* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d0000675Fsv0000148Csd00006530* + ID_MODEL_FROM_DATABASE=Radeon HD 6530 + +pci:v00001002d0000675Fsv0000148Csd00007510* + ID_MODEL_FROM_DATABASE=Radeon HD 7510 + +pci:v00001002d0000675Fsv00001545sd00007570* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d0000675Fsv0000174Bsd00006510* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d0000675Fsv0000174Bsd00007510* + ID_MODEL_FROM_DATABASE=Radeon HD 7510 + +pci:v00001002d0000675Fsv0000174Bsd00008510* + ID_MODEL_FROM_DATABASE=Radeon HD 8510 + +pci:v00001002d0000675Fsv00001787sd00002012* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 2GB GDDR3 + +pci:v00001002d0000675Fsv00001787sd00002314* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 1GB DDR2/GDDR3 + +pci:v00001002d00006760* + ID_MODEL_FROM_DATABASE=Seymour [Radeon HD 6400M/7400M Series] + +pci:v00001002d00006760sv00001002sd00000124* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001002sd00000134* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001019sd0000238B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001019sd0000238E* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001019sd00002390* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001019sd00009985* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004C1* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004C3* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004CA* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004CB* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004CC* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00001002d00006760sv00001028sd000004D1* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004D3* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd000004D7* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd00000502* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd00000503* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd00000506* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd00000507* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd00000514* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001028sd0000051C* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv00001028sd0000051D* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv0000103Csd0000161A* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000161B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000161E* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000161F* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001622* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv0000103Csd00001623* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv0000103Csd0000164A* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000164D* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001651* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001656* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00001658* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00001659* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000165B* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000165D* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000165F* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001661* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001663* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001665* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001667* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001669* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000166B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000166C* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000166E* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001670* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001672* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000167A* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000167B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000167D* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000167F* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000168C* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000168F* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001694* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001696* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00001698* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000169A* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000169C* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00001855* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv0000103Csd00001859* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv0000103Csd0000185C* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv0000103Csd0000185D* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000103Csd0000185F* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000103Csd00001863* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv0000103Csd0000355C* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000355F* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00003563* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00003565* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00003567* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00003569* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00003581* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00003584* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd0000358C* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000358F* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00003592* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd00003596* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000103Csd0000366B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000103Csd00003671* + ID_MODEL_FROM_DATABASE=FirePro M3900 + +pci:v00001002d00006760sv0000103Csd00003673* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd0000100A* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000100C* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd0000101B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd0000101C* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd0000102A* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv00001043sd0000102C* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd0000104B* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000105D* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000106B* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000106D* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000107D* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd00001CB2* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd00001D22* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd00001D32* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd00002001* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd00002002* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd00002107* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd00002108* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd00002109* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd000084A0* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd000084E9* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001043sd00008515* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd00008517* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001043sd0000855A* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000104Dsd0000907B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000104Dsd00009081* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000104Dsd00009084* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000104Dsd00009085* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv00001179sd00000003* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv00001179sd00000004* + ID_MODEL_FROM_DATABASE=Radeon HD 6450M + +pci:v00001002d00006760sv00001179sd0000FB22* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB23* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB2C* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB31* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB32* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB33* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB38* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB39* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB3A* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB40* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB41* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB42* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB47* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB48* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB51* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB52* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB53* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB81* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB82* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FB83* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FC51* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001179sd0000FC52* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FC56* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FCD3* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FCD4* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FCEE* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv00001179sd0000FDEE* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000144Dsd0000B074* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000B084* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000C095* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000C0B3* + ID_MODEL_FROM_DATABASE=Radeon HD 6490M + +pci:v00001002d00006760sv0000144Dsd0000C538* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000C581* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000C589* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000144Dsd0000C609* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000144Dsd0000C625* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv0000144Dsd0000C636* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv00001462sd000010AC* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv0000152Dsd00000916* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd000021E5* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd00003900* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv000017AAsd00003902* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv000017AAsd00003969* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd00003970* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv000017AAsd00003976* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd0000397B* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd0000397D* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv000017AAsd00005101* + ID_MODEL_FROM_DATABASE=Radeon HD 7470M + +pci:v00001002d00006760sv000017AAsd00005102* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv000017AAsd00005103* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv000017AAsd00005106* + ID_MODEL_FROM_DATABASE=Radeon HD 7450M + +pci:v00001002d00006760sv00001854sd00000897* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001854sd00000900* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001854sd00000908* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006760sv00001854sd00002015* + ID_MODEL_FROM_DATABASE=Radeon HD 6470M + +pci:v00001002d00006761* + ID_MODEL_FROM_DATABASE=Seymour LP [Radeon HD 6430M] + +pci:v00001002d00006763* + ID_MODEL_FROM_DATABASE=Seymour [Radeon E6460] + +pci:v00001002d00006764* + ID_MODEL_FROM_DATABASE=Seymour [Radeon HD 6400M Series] + +pci:v00001002d00006765* + ID_MODEL_FROM_DATABASE=Seymour [Radeon HD 6400M Series] + +pci:v00001002d00006766* + ID_MODEL_FROM_DATABASE=Caicos + +pci:v00001002d00006767* + ID_MODEL_FROM_DATABASE=Caicos + +pci:v00001002d00006768* + ID_MODEL_FROM_DATABASE=Caicos + +pci:v00001002d00006770* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6450A/7450A] + +pci:v00001002d00006770sv000017AAsd0000308D* + ID_MODEL_FROM_DATABASE=Radeon HD 7450A + +pci:v00001002d00006770sv000017AAsd00003623* + ID_MODEL_FROM_DATABASE=Radeon HD 6450A + +pci:v00001002d00006770sv000017AAsd00003627* + ID_MODEL_FROM_DATABASE=Radeon HD 6450A + +pci:v00001002d00006770sv000017AAsd00003629* + ID_MODEL_FROM_DATABASE=Radeon HD 6450A + +pci:v00001002d00006770sv000017AAsd0000363C* + ID_MODEL_FROM_DATABASE=Radeon HD 6450A + +pci:v00001002d00006770sv000017AAsd00003658* + ID_MODEL_FROM_DATABASE=Radeon HD 7470A + +pci:v00001002d00006771* + ID_MODEL_FROM_DATABASE=Caicos XTX [Radeon HD 8490 / R5 235X OEM] + +pci:v00001002d00006772* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7450A] + +pci:v00001002d00006778* + ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] + +pci:v00001002d00006778sv00001019sd00000024* + ID_MODEL_FROM_DATABASE=Radeon HD 7470 + +pci:v00001002d00006778sv00001019sd00000027* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv00001028sd00002120* + ID_MODEL_FROM_DATABASE=Radeon HD 7470 + +pci:v00001002d00006778sv00001462sd0000B491* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv00001462sd0000B492* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv00001462sd0000B493* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 OEM + +pci:v00001002d00006778sv00001642sd00003C65* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv00001642sd00003C75* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv0000174Bsd00008145* + ID_MODEL_FROM_DATABASE=Radeon HD 8470 + +pci:v00001002d00006778sv0000174Bsd0000E145* + ID_MODEL_FROM_DATABASE=Radeon HD 7470 + +pci:v00001002d00006779* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6450/7450/8450 / R5 230 OEM] + +pci:v00001002d00006779sv00001019sd00000016* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001019sd00000017* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001019sd00000018* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001028sd00002120* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv0000103Csd00002128* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv0000103Csd00002AEE* + ID_MODEL_FROM_DATABASE=Radeon HD 7450A + +pci:v00001002d00006779sv00001462sd00002125* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001462sd00002346* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv00001462sd00002490* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001462sd00002494* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001462sd00002496* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv0000148Csd00007450* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv0000148Csd00008450* + ID_MODEL_FROM_DATABASE=Radeon HD 8450 OEM + +pci:v00001002d00006779sv00001545sd00007470* + ID_MODEL_FROM_DATABASE=Radeon HD 7470 + +pci:v00001002d00006779sv00001642sd00003A65* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001642sd00003A66* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv00001642sd00003A75* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001642sd00003A76* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv00001682sd00003200* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv0000174Bsd00007450* + ID_MODEL_FROM_DATABASE=Radeon HD 7450 + +pci:v00001002d00006779sv0000174Bsd0000E127* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv0000174Bsd0000E153* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv0000174Bsd0000E164* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 1 GB DDR3 + +pci:v00001002d00006779sv0000174Bsd0000E180* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv0000174Bsd0000E201* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv000017AFsd00008450* + ID_MODEL_FROM_DATABASE=Radeon HD 8450 OEM + +pci:v00001002d00006779sv00001B0Asd00009096* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001B0Asd00009097* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001B0Asd000090A8* + ID_MODEL_FROM_DATABASE=Radeon HD 6450A + +pci:v00001002d00006779sv00001B0Asd000090B1* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 + +pci:v00001002d00006779sv00001B0Asd000090B3* + ID_MODEL_FROM_DATABASE=Radeon HD 7450A + +pci:v00001002d00006779sv00001B0Asd000090BB* + ID_MODEL_FROM_DATABASE=Radeon HD 7450A + +pci:v00001002d0000677B* + ID_MODEL_FROM_DATABASE=Caicos PRO [Radeon HD 7450] + +pci:v00001002d00006780* + ID_MODEL_FROM_DATABASE=Tahiti XT GL [FirePro W9000] + +pci:v00001002d00006784* + ID_MODEL_FROM_DATABASE=Tahiti [ATI FirePro V (FireGL V) Graphics Adapter] + +pci:v00001002d00006788* + ID_MODEL_FROM_DATABASE=Tahiti [ATI FirePro V (FireGL V) Graphics Adapter] + +pci:v00001002d0000678A* + ID_MODEL_FROM_DATABASE=Tahiti PRO GL [FirePro Series] + +pci:v00001002d0000678Asv00001002sd0000030C* + ID_MODEL_FROM_DATABASE=FirePro W8000 + +pci:v00001002d0000678Asv00001002sd00000310* + ID_MODEL_FROM_DATABASE=FirePro S9000 + +pci:v00001002d0000678Asv00001002sd00000420* + ID_MODEL_FROM_DATABASE=Radeon Sky 700 + +pci:v00001002d0000678Asv00001002sd00000422* + ID_MODEL_FROM_DATABASE=Radeon Sky 900 + +pci:v00001002d0000678Asv00001002sd00000B0E* + ID_MODEL_FROM_DATABASE=FirePro S10000 Passive + +pci:v00001002d0000678Asv00001002sd00000B2A* + ID_MODEL_FROM_DATABASE=FirePro S10000 + +pci:v00001002d0000678Asv00001028sd0000030C* + ID_MODEL_FROM_DATABASE=FirePro W8000 + +pci:v00001002d00006790* + ID_MODEL_FROM_DATABASE=Tahiti + +pci:v00001002d00006791* + ID_MODEL_FROM_DATABASE=Tahiti + +pci:v00001002d00006792* + ID_MODEL_FROM_DATABASE=Tahiti + +pci:v00001002d00006798* + ID_MODEL_FROM_DATABASE=Tahiti XT [Radeon HD 7970/R9 280X] + +pci:v00001002d00006798sv00001002sd00003000* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Radeon HD 7970 GHz Edition] + +pci:v00001002d00006798sv00001002sd00003001* + ID_MODEL_FROM_DATABASE=Tahiti XTL [Radeon R9 280X] + +pci:v00001002d00006798sv00001002sd00004000* + ID_MODEL_FROM_DATABASE=Radeon HD 8970 OEM + +pci:v00001002d00006798sv00001043sd0000041C* + ID_MODEL_FROM_DATABASE=HD 7970 DirectCU II + +pci:v00001002d00006798sv00001043sd00000420* + ID_MODEL_FROM_DATABASE=HD 7970 DirectCU II TOP + +pci:v00001002d00006798sv00001043sd00000444* + ID_MODEL_FROM_DATABASE=HD 7970 DirectCU II TOP + +pci:v00001002d00006798sv00001043sd00000448* + ID_MODEL_FROM_DATABASE=HD 7970 DirectCU II TOP + +pci:v00001002d00006798sv00001043sd0000044A* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Matrix HD 7970] + +pci:v00001002d00006798sv00001043sd0000044C* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Matrix HD 7970 Platinum] + +pci:v00001002d00006798sv00001043sd00003001* + ID_MODEL_FROM_DATABASE=Tahiti XTL [ROG Matrix R9 280X] + +pci:v00001002d00006798sv00001043sd00003006* + ID_MODEL_FROM_DATABASE=Tahiti XTL [Radeon R9 280X DirectCU II TOP] + +pci:v00001002d00006798sv00001043sd00009999* + ID_MODEL_FROM_DATABASE=ARES II + +pci:v00001002d00006798sv00001092sd00003000* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Radeon HD 7970 GHz Edition] + +pci:v00001002d00006798sv00001458sd00002261* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Radeon HD 7970 GHz Edition OC] + +pci:v00001002d00006798sv00001682sd00003211* + ID_MODEL_FROM_DATABASE=Double D HD 7970 Black Edition + +pci:v00001002d00006798sv00001682sd00003213* + ID_MODEL_FROM_DATABASE=HD 7970 Black Edition + +pci:v00001002d00006798sv00001682sd00003214* + ID_MODEL_FROM_DATABASE=Double D HD 7970 + +pci:v00001002d00006798sv00001787sd0000201C* + ID_MODEL_FROM_DATABASE=HD 7970 IceQ X² + +pci:v00001002d00006798sv00001787sd00002317* + ID_MODEL_FROM_DATABASE=Radeon HD 7990 + +pci:v00001002d00006798sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Tahiti XT2 [Radeon HD 7970 GHz Edition] + +pci:v00001002d00006799* + ID_MODEL_FROM_DATABASE=New Zealand [Radeon HD 7900 Series] + +pci:v00001002d0000679A* + ID_MODEL_FROM_DATABASE=Tahiti PRO [Radeon HD 7950] + +pci:v00001002d0000679Asv00001002sd00000B01* + ID_MODEL_FROM_DATABASE=Radeon HD 8950 OEM + +pci:v00001002d0000679Asv00001002sd00003000* + ID_MODEL_FROM_DATABASE=Tahiti PRO2 [Radeon HD 7950 Boost] + +pci:v00001002d0000679Asv00001462sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 8950 OEM + +pci:v00001002d0000679B* + ID_MODEL_FROM_DATABASE=Malta [Radeon HD 7990] + +pci:v00001002d0000679Bsv00001002sd00000B28* + ID_MODEL_FROM_DATABASE=Radeon HD 8990 OEM + +pci:v00001002d0000679Bsv00001002sd00000B2A* + ID_MODEL_FROM_DATABASE=Radeon HD 7990 + +pci:v00001002d0000679Bsv00001462sd00008036* + ID_MODEL_FROM_DATABASE=Radeon HD 8990 OEM + +pci:v00001002d0000679Bsv0000148Csd00008990* + ID_MODEL_FROM_DATABASE=Radeon HD 8990 OEM + +pci:v00001002d0000679E* + ID_MODEL_FROM_DATABASE=Tahiti LE [Radeon HD 7870 XT] + +pci:v00001002d0000679F* + ID_MODEL_FROM_DATABASE=Tahiti + +pci:v00001002d000067A0* + ID_MODEL_FROM_DATABASE=Hawaii XT GL + +pci:v00001002d000067A1* + ID_MODEL_FROM_DATABASE=Hawaii GL + +pci:v00001002d000067A2* + ID_MODEL_FROM_DATABASE=Hawaii GL + +pci:v00001002d000067A8* + ID_MODEL_FROM_DATABASE=Hawaii + +pci:v00001002d000067A9* + ID_MODEL_FROM_DATABASE=Hawaii + +pci:v00001002d000067AA* + ID_MODEL_FROM_DATABASE=Hawaii + +pci:v00001002d000067B0* + ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] + +pci:v00001002d000067B1* + ID_MODEL_FROM_DATABASE=Hawaii PRO [Radeon R9 290] + +pci:v00001002d000067B9* + ID_MODEL_FROM_DATABASE=Vesuvius + +pci:v00001002d000067BE* + ID_MODEL_FROM_DATABASE=Hawaii LE + +pci:v00001002d00006800* + ID_MODEL_FROM_DATABASE=Wimbledon XT [Radeon HD 7970M] + +pci:v00001002d00006800sv00001002sd00000124* + ID_MODEL_FROM_DATABASE=Radeon HD 7970M + +pci:v00001002d00006800sv00008086sd00002110* + ID_MODEL_FROM_DATABASE=Radeon HD 7970M + +pci:v00001002d00006800sv00008086sd00002111* + ID_MODEL_FROM_DATABASE=Radeon HD 7970M + +pci:v00001002d00006801* + ID_MODEL_FROM_DATABASE=Neptune [Radeon HD 8970M] + +pci:v00001002d00006801sv00001002sd00000124* + ID_MODEL_FROM_DATABASE=Radeon HD 8970M + +pci:v00001002d00006801sv00008086sd00002110* + ID_MODEL_FROM_DATABASE=Radeon HD 8970M + +pci:v00001002d00006801sv00008086sd00002111* + ID_MODEL_FROM_DATABASE=Radeon HD 8970M + +pci:v00001002d00006802* + ID_MODEL_FROM_DATABASE=Wimbledon + +pci:v00001002d00006806* + ID_MODEL_FROM_DATABASE=Neptune + +pci:v00001002d00006808* + ID_MODEL_FROM_DATABASE=Pitcairn XT GL [FirePro W7000] + +pci:v00001002d00006808sv00001002sd00000310* + ID_MODEL_FROM_DATABASE=FirePro S7000 + +pci:v00001002d00006808sv00001002sd00000420* + ID_MODEL_FROM_DATABASE=Radeon Sky 500 + +pci:v00001002d00006809* + ID_MODEL_FROM_DATABASE=Pitcairn LE GL [FirePro W5000] + +pci:v00001002d00006810* + ID_MODEL_FROM_DATABASE=Curacao XT [Radeon R9 270X] + +pci:v00001002d00006811* + ID_MODEL_FROM_DATABASE=Curacao PRO [Radeon R9 270] + +pci:v00001002d00006816* + ID_MODEL_FROM_DATABASE=Pitcairn + +pci:v00001002d00006817* + ID_MODEL_FROM_DATABASE=Pitcairn + +pci:v00001002d00006818* + ID_MODEL_FROM_DATABASE=Pitcairn XT [Radeon HD 7870 GHz Edition] + +pci:v00001002d00006818sv00001002sd00000B05* + ID_MODEL_FROM_DATABASE=Radeon HD 8870 OEM + +pci:v00001002d00006818sv0000174Bsd00008B04* + ID_MODEL_FROM_DATABASE=Radeon HD 8860 + +pci:v00001002d00006819* + ID_MODEL_FROM_DATABASE=Pitcairn PRO [Radeon HD 7850] + +pci:v00001002d00006819sv0000174Bsd0000E221* + ID_MODEL_FROM_DATABASE=Radeon HD 7850 2GB GDDR5 DVI-I/DVI-D/HDMI/DP + +pci:v00001002d00006820* + ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M] + +pci:v00001002d00006820sv0000103Csd00001851* + ID_MODEL_FROM_DATABASE=Radeon HD 7750M + +pci:v00001002d00006821* + ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M] + +pci:v00001002d00006821sv00001002sd0000031E* + ID_MODEL_FROM_DATABASE=FirePro SX4000 + +pci:v00001002d00006822* + ID_MODEL_FROM_DATABASE=Venus PRO [Radeon E8860] + +pci:v00001002d00006823* + ID_MODEL_FROM_DATABASE=Venus PRO [Radeon HD 8850M] + +pci:v00001002d00006825* + ID_MODEL_FROM_DATABASE=Heathrow XT [Radeon HD 7870M] + +pci:v00001002d00006825sv00008086sd00002111* + ID_MODEL_FROM_DATABASE=Chelsea PRO + +pci:v00001002d00006826* + ID_MODEL_FROM_DATABASE=Chelsea LP [Radeon HD 7700M Series] + +pci:v00001002d00006827* + ID_MODEL_FROM_DATABASE=Heathrow PRO [Radeon HD 7850M/8850M] + +pci:v00001002d00006828* + ID_MODEL_FROM_DATABASE=Cape Verde PRO [FirePro W600] + +pci:v00001002d00006829* + ID_MODEL_FROM_DATABASE=Cape Verde + +pci:v00001002d0000682A* + ID_MODEL_FROM_DATABASE=Venus PRO + +pci:v00001002d0000682B* + ID_MODEL_FROM_DATABASE=Venus LE [Radeon HD 8830M] + +pci:v00001002d0000682D* + ID_MODEL_FROM_DATABASE=Chelsea XT GL [FirePro M4000] + +pci:v00001002d0000682F* + ID_MODEL_FROM_DATABASE=Chelsea LP [Radeon HD 7730M] + +pci:v00001002d0000682Fsv0000103Csd00001851* + ID_MODEL_FROM_DATABASE=Radeon HD 7750M + +pci:v00001002d00006830* + ID_MODEL_FROM_DATABASE=Cape Verde [Radeon HD 7800M Series] + +pci:v00001002d00006831* + ID_MODEL_FROM_DATABASE=Cape Verde [AMD Radeon HD 7700M Series] + +pci:v00001002d00006835* + ID_MODEL_FROM_DATABASE=Cape Verde PRX [Radeon R9 255 OEM] + +pci:v00001002d00006837* + ID_MODEL_FROM_DATABASE=Cape Verde LE [Radeon HD 7730/8730] + +pci:v00001002d00006837sv00001462sd00002796* + ID_MODEL_FROM_DATABASE=Radeon HD 8730 + +pci:v00001002d00006837sv00001462sd00008092* + ID_MODEL_FROM_DATABASE=Radeon HD 8730 + +pci:v00001002d00006837sv0000148Csd00008730* + ID_MODEL_FROM_DATABASE=Radeon HD 8730 + +pci:v00001002d00006837sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6570 + +pci:v00001002d00006838* + ID_MODEL_FROM_DATABASE=Cape Verde + +pci:v00001002d00006839* + ID_MODEL_FROM_DATABASE=Cape Verde + +pci:v00001002d0000683B* + ID_MODEL_FROM_DATABASE=Cape Verde [Radeon HD 7700 Series] + +pci:v00001002d0000683D* + ID_MODEL_FROM_DATABASE=Cape Verde XT [Radeon HD 7770 GHz Edition] + +pci:v00001002d0000683Dsv00001002sd00000030* + ID_MODEL_FROM_DATABASE=Radeon HD 8760 OEM + +pci:v00001002d0000683Dsv00001019sd00000030* + ID_MODEL_FROM_DATABASE=Radeon HD 8760 OEM + +pci:v00001002d0000683Dsv0000103Csd00006890* + ID_MODEL_FROM_DATABASE=Radeon HD 8760 OEM + +pci:v00001002d0000683F* + ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750] + +pci:v00001002d00006840* + ID_MODEL_FROM_DATABASE=Thames [Radeon HD 7500M/7600M Series] + +pci:v00001002d00006840sv00001025sd0000050E* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd0000050F* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd00000513* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd00000514* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd0000056D* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd0000059A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd0000059B* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd0000059E* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd00000600* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd00000606* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001025sd00000696* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006840sv00001025sd00000697* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006840sv00001025sd00000698* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006840sv00001025sd00000699* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006840sv00001025sd00000757* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd0000056A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd0000056E* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd00000598* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd0000059D* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd000005A3* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd000005B9* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001028sd000005BB* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd000017F1* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006840sv0000103Csd000017F4* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006840sv0000103Csd00001813* + ID_MODEL_FROM_DATABASE=Radeon HD 7590M + +pci:v00001002d00006840sv0000103Csd0000182F* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001830* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001835* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd0000183A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd0000183C* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd0000183E* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001840* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001842* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001844* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001848* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd0000184A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd0000184C* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001895* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd00001897* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd000018A5* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd000018A7* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000103Csd000018F4* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd0000100A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd0000104B* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd000010DC* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd00002121* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd00002122* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd00002123* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd00002125* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001043sd00002127* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB11* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB22* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB23* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB2C* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB31* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB32* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB38* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB39* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB3A* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB40* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB41* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB47* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB48* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB51* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB52* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB53* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB81* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB82* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FB83* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FC56* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FCD4* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv00001179sd0000FCEE* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000144Dsd0000C0C5* + ID_MODEL_FROM_DATABASE=Radeon HD 7690M + +pci:v00001002d00006840sv0000144Dsd0000C0CE* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv0000144Dsd0000C0DA* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv000017AAsd00003970* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv000017AAsd0000397B* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv000017AAsd00005101* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv000017AAsd00005102* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006840sv000017AAsd00005103* + ID_MODEL_FROM_DATABASE=Radeon HD 7670M + +pci:v00001002d00006841* + ID_MODEL_FROM_DATABASE=Thames [Radeon HD 7550M/7570M/7650M] + +pci:v00001002d00006841sv00001028sd00000561* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001028sd0000056C* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001028sd0000057F* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006841sv0000103Csd000017F1* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006841sv0000103Csd000017F4* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd00001813* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006841sv0000103Csd0000183A* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd0000183C* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd0000183E* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd00001840* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd00001842* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv0000103Csd00001844* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001043sd0000100A* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001043sd0000104B* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001043sd000010DC* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001043sd00002134* + ID_MODEL_FROM_DATABASE=Radeon HD 7650M + +pci:v00001002d00006841sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006841sv00001179sd00000002* + ID_MODEL_FROM_DATABASE=Radeon HD 7570M + +pci:v00001002d00006841sv00001179sd0000FB43* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv00001179sd0000FB91* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv00001179sd0000FB92* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv00001179sd0000FB93* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv00001179sd0000FBA2* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv00001179sd0000FBA3* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006841sv0000144Dsd0000C0C7* + ID_MODEL_FROM_DATABASE=Radeon HD 7550M + +pci:v00001002d00006842* + ID_MODEL_FROM_DATABASE=Thames LE [Radeon HD 7000M Series] + +pci:v00001002d00006843* + ID_MODEL_FROM_DATABASE=Thames [Radeon HD 7670M] + +pci:v00001002d00006888* + ID_MODEL_FROM_DATABASE=Cypress XT [FirePro V8800] + +pci:v00001002d00006889* + ID_MODEL_FROM_DATABASE=Cypress PRO [FirePro V7800] + +pci:v00001002d00006889sv00001002sd00000301* + ID_MODEL_FROM_DATABASE=FirePro V7800P + +pci:v00001002d0000688A* + ID_MODEL_FROM_DATABASE=Cypress XT [FirePro V9800] + +pci:v00001002d0000688Asv00001002sd0000030C* + ID_MODEL_FROM_DATABASE=FirePro V9800P + +pci:v00001002d0000688C* + ID_MODEL_FROM_DATABASE=Cypress XT GL [FireStream 9370] + +pci:v00001002d0000688D* + ID_MODEL_FROM_DATABASE=Cypress PRO GL [FireStream 9350] + +pci:v00001002d00006898* + ID_MODEL_FROM_DATABASE=Cypress XT [Radeon HD 5870] + +pci:v00001002d00006898sv00001002sd00000B00* + ID_MODEL_FROM_DATABASE=Radeon HD 5870 Eyefinity⁶ Edition + +pci:v00001002d00006898sv0000106Bsd000000D0* + ID_MODEL_FROM_DATABASE=Radeon HD 5870 Mac Edition + +pci:v00001002d00006898sv00001462sd00008032* + ID_MODEL_FROM_DATABASE=Radeon HD 5870 1 GB GDDR5 + +pci:v00001002d00006898sv0000174Bsd00006870* + ID_MODEL_FROM_DATABASE=Radeon HD 6870 1600SP Edition + +pci:v00001002d00006899* + ID_MODEL_FROM_DATABASE=Cypress PRO [Radeon HD 5850] + +pci:v00001002d00006899sv00001043sd00000330* + ID_MODEL_FROM_DATABASE=Radeon HD 5850 + +pci:v00001002d00006899sv0000174Bsd0000237B* + ID_MODEL_FROM_DATABASE=Radeon HD 5850 X2 + +pci:v00001002d00006899sv0000174Bsd00006850* + ID_MODEL_FROM_DATABASE=Radeon HD 6850 1440SP Edition + +pci:v00001002d0000689B* + ID_MODEL_FROM_DATABASE=Cypress PRO [Radeon HD 6800 Series] + +pci:v00001002d0000689C* + ID_MODEL_FROM_DATABASE=Hemlock [Radeon HD 5970] + +pci:v00001002d0000689Csv00001043sd00000352* + ID_MODEL_FROM_DATABASE=ARES + +pci:v00001002d0000689D* + ID_MODEL_FROM_DATABASE=Hemlock [Radeon HD 5970] + +pci:v00001002d0000689E* + ID_MODEL_FROM_DATABASE=Cypress LE [Radeon HD 5830] + +pci:v00001002d000068A0* + ID_MODEL_FROM_DATABASE=Broadway XT [Mobility Radeon HD 5870] + +pci:v00001002d000068A0sv00001028sd000012EF* + ID_MODEL_FROM_DATABASE=FirePro M7820 + +pci:v00001002d000068A0sv0000103Csd00001520* + ID_MODEL_FROM_DATABASE=FirePro M7820 + +pci:v00001002d000068A1* + ID_MODEL_FROM_DATABASE=Broadway PRO [Mobility Radeon HD 5850] + +pci:v00001002d000068A1sv0000106Bsd000000CC* + ID_MODEL_FROM_DATABASE=iMac MC511 Mobility Radeon HD 5850 MXM Module + +pci:v00001002d000068A8* + ID_MODEL_FROM_DATABASE=Granville [Radeon HD 6850M/6870M] + +pci:v00001002d000068A8sv00001025sd00000442* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000451* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000050A* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000050B* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000050C* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000050E* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000050F* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000513* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000514* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000515* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000516* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000525* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd00000526* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001025sd0000056D* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv00001028sd0000048F* + ID_MODEL_FROM_DATABASE=Radeon HD 6870M + +pci:v00001002d000068A8sv00001028sd00000490* + ID_MODEL_FROM_DATABASE=Radeon HD 6870M + +pci:v00001002d000068A8sv00001028sd000004B9* + ID_MODEL_FROM_DATABASE=Radeon HD 6870M + +pci:v00001002d000068A8sv00001028sd000004BA* + ID_MODEL_FROM_DATABASE=Radeon HD 6870M + +pci:v00001002d000068A8sv0000103Csd0000159B* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A8sv0000144Dsd0000C0AD* + ID_MODEL_FROM_DATABASE=Radeon HD 6850M + +pci:v00001002d000068A9* + ID_MODEL_FROM_DATABASE=Juniper XT [FirePro V5800] + +pci:v00001002d000068B8* + ID_MODEL_FROM_DATABASE=Juniper XT [Radeon HD 5770] + +pci:v00001002d000068B8sv0000106Bsd000000CF* + ID_MODEL_FROM_DATABASE=MacPro5,1 [Mac Pro 2.8GHz DDR3] + +pci:v00001002d000068B9* + ID_MODEL_FROM_DATABASE=Juniper LE [Radeon HD 5670 640SP Edition] + +pci:v00001002d000068BA* + ID_MODEL_FROM_DATABASE=Juniper XT [Radeon HD 6770] + +pci:v00001002d000068BE* + ID_MODEL_FROM_DATABASE=Juniper PRO [Radeon HD 5750] + +pci:v00001002d000068BEsv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6750 + +pci:v00001002d000068BF* + ID_MODEL_FROM_DATABASE=Juniper PRO [Radeon HD 6750] + +pci:v00001002d000068BFsv0000174Bsd00006750* + ID_MODEL_FROM_DATABASE=Radeon HD 6750 + +pci:v00001002d000068C0* + ID_MODEL_FROM_DATABASE=Madison [Mobility Radeon HD 5730 / 6570M] + +pci:v00001002d000068C0sv00001019sd00002383* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv00001028sd000002A2* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv00001028sd000002FE* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv00001028sd00000419* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv0000103Csd0000147D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv0000103Csd00001521* + ID_MODEL_FROM_DATABASE=Madison XT [FirePro M5800] + +pci:v00001002d000068C0sv0000103Csd00001593* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 6570 + +pci:v00001002d000068C0sv0000103Csd00001596* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 6570 + +pci:v00001002d000068C0sv0000103Csd00001599* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 6570 + +pci:v00001002d000068C0sv00001043sd00001C22* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv000017AAsd00003927* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv000017AAsd00003952* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5730 + +pci:v00001002d000068C0sv000017AAsd00003978* + ID_MODEL_FROM_DATABASE=Radeon HD 6570M + +pci:v00001002d000068C1* + ID_MODEL_FROM_DATABASE=Madison [Mobility Radeon HD 5650/5750 / 6530M/6550M] + +pci:v00001002d000068C1sv00001025sd00000205* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000293* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000294* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000296* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000308* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000030A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000311* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000312* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000031C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000031D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000033D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000033E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000033F* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000346* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00001002d000068C1sv00001025sd00000348* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000356* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000357* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000358* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000359* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000035A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000035B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000035C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000035D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000035E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000360* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000362* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000364* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000365* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000366* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000367* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000368* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000036C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000036D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000036E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000036F* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000372* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000373* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000377* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000378* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000379* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000037A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000037B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000037E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000037F* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000382* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000383* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000384* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000385* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000386* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000387* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000388* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000038B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000038C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000039A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000411* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000412* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000418* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000419* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000420* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000421* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000425* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000042A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000042E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000042F* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000432* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000433* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000442* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000044C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd0000044E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000451* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000454* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000455* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000475* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000476* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000487* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000489* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000498* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001025sd00000517* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000051A* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000051B* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000051C* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000051D* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd00000525* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd00000526* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000052B* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000052C* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000053C* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000053D* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000053E* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd0000053F* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001025sd00000607* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C1sv00001028sd0000041B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001028sd00000447* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001028sd00000448* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001028sd00000456* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001028sd00000457* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001436* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001437* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001440* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001448* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001449* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd0000144A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd0000144B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd0000147B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd0000149C* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd0000149E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000103Csd00001521* + ID_MODEL_FROM_DATABASE=Madison Pro [FirePro M5800] + +pci:v00001002d000068C1sv00001043sd00001BC2* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000104Dsd00009071* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000104Dsd00009077* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000104Dsd00009081* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD00* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD12* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD1A* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD30* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD31* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD50* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FD52* + ID_MODEL_FROM_DATABASE=Radeon HD 6530M + +pci:v00001002d000068C1sv00001179sd0000FD63* + ID_MODEL_FROM_DATABASE=Radeon HD 6530M + +pci:v00001002d000068C1sv00001179sd0000FD65* + ID_MODEL_FROM_DATABASE=Radeon HD 6530M + +pci:v00001002d000068C1sv00001179sd0000FDD0* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv00001179sd0000FDD2* + ID_MODEL_FROM_DATABASE=Radeon HD 6530M + +pci:v00001002d000068C1sv0000144Dsd0000C07E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv0000144Dsd0000C085* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv000014C0sd00000043* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv000014C0sd0000004D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv000017AAsd00003928* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv000017AAsd00003951* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d000068C1sv000017AAsd00003977* + ID_MODEL_FROM_DATABASE=Radeon HD 6550M + +pci:v00001002d000068C7* + ID_MODEL_FROM_DATABASE=Madison [Mobility Radeon HD 5570/6550A] + +pci:v00001002d000068C7sv00001462sd00002241* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5570 + +pci:v00001002d000068C7sv00001462sd00002243* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5570 + +pci:v00001002d000068C7sv00001462sd00002244* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5570 + +pci:v00001002d000068C7sv00001462sd00002245* + ID_MODEL_FROM_DATABASE=Radeon HD 6550A + +pci:v00001002d000068C7sv00001462sd00002246* + ID_MODEL_FROM_DATABASE=Radeon HD 6550A + +pci:v00001002d000068C8* + ID_MODEL_FROM_DATABASE=Redwood XT GL [FirePro V4800] + +pci:v00001002d000068C9* + ID_MODEL_FROM_DATABASE=Redwood PRO GL [FirePro V3800] + +pci:v00001002d000068D8* + ID_MODEL_FROM_DATABASE=Redwood XT [Radeon HD 5670/5690/5730] + +pci:v00001002d000068D8sv00001028sd000068E0* + ID_MODEL_FROM_DATABASE=Radeon HD 5670 + +pci:v00001002d000068D8sv0000174Bsd00005690* + ID_MODEL_FROM_DATABASE=Radeon HD 5690 + +pci:v00001002d000068D8sv0000174Bsd00005730* + ID_MODEL_FROM_DATABASE=Radeon HD 5730 + +pci:v00001002d000068D8sv0000174Bsd0000E151* + ID_MODEL_FROM_DATABASE=Radeon HD 5670 + +pci:v00001002d000068D8sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 5730 + +pci:v00001002d000068D8sv000017AFsd00003010* + ID_MODEL_FROM_DATABASE=Radeon HD 5730 + +pci:v00001002d000068D8sv000017AFsd00003011* + ID_MODEL_FROM_DATABASE=Radeon HD 5690 + +pci:v00001002d000068D9* + ID_MODEL_FROM_DATABASE=Redwood PRO [Radeon HD 5550/5570/5630/6510/6610/7570] + +pci:v00001002d000068D9sv0000103Csd00006870* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv0000103Csd00006872* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv00001043sd000003CE* + ID_MODEL_FROM_DATABASE=Radeon HD 5550 + +pci:v00001002d000068D9sv00001462sd00002151* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv00001462sd00002240* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d000068D9sv0000148Csd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 6610 + +pci:v00001002d000068D9sv00001545sd00005550* + ID_MODEL_FROM_DATABASE=Radeon HD 5550 + +pci:v00001002d000068D9sv00001545sd00007570* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d000068D9sv00001642sd00003985* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv00001642sd00003996* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d000068D9sv0000174Bsd00006510* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d000068D9sv0000174Bsd00006610* + ID_MODEL_FROM_DATABASE=Radeon HD 6610 + +pci:v00001002d000068D9sv0000174Bsd0000E142* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068D9sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d000068D9sv000017AFsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6510 + +pci:v00001002d000068D9sv000017AFsd00003010* + ID_MODEL_FROM_DATABASE=Radeon HD 5630 + +pci:v00001002d000068DA* + ID_MODEL_FROM_DATABASE=Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570] + +pci:v00001002d000068DAsv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6390 + +pci:v00001002d000068DAsv0000148Csd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 6490 + +pci:v00001002d000068DAsv00001545sd00007570* + ID_MODEL_FROM_DATABASE=Radeon HD 7570 + +pci:v00001002d000068DAsv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6390 + +pci:v00001002d000068DAsv0000174Bsd00005570* + ID_MODEL_FROM_DATABASE=Radeon HD 5570 + +pci:v00001002d000068DAsv0000174Bsd00005630* + ID_MODEL_FROM_DATABASE=Radeon HD 5630 + +pci:v00001002d000068DAsv0000174Bsd00006490* + ID_MODEL_FROM_DATABASE=Radeon HD 6490 + +pci:v00001002d000068DAsv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 5630 + +pci:v00001002d000068DAsv000017AFsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6390 + +pci:v00001002d000068DAsv000017AFsd00003010* + ID_MODEL_FROM_DATABASE=Radeon HD 5630 + +pci:v00001002d000068DE* + ID_MODEL_FROM_DATABASE=Redwood + +pci:v00001002d000068E0* + ID_MODEL_FROM_DATABASE=Park [Mobility Radeon HD 5430/5450/5470] + +pci:v00001002d000068E0sv00001028sd00000404* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv00001028sd00000414* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv00001028sd00000434* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd00001433* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd00001434* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd00001469* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd0000146B* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd00001486* + ID_MODEL_FROM_DATABASE=TouchSmart tm2-2050er discrete GPU (Mobility Radeon HD 5450) + +pci:v00001002d000068E0sv0000103Csd00001622* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd00001623* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000103Csd0000EEEE* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv0000104Dsd00009076* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5450 + +pci:v00001002d000068E0sv00001682sd0000304E* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E0sv00001682sd00006000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E0sv000017AAsd00009E52* + ID_MODEL_FROM_DATABASE=FirePro M3800 + +pci:v00001002d000068E0sv000017AAsd00009E53* + ID_MODEL_FROM_DATABASE=FirePro M3800 + +pci:v00001002d000068E1* + ID_MODEL_FROM_DATABASE=Park [Mobility Radeon HD 5430] + +pci:v00001002d000068E1sv00001043sd0000041F* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv00001043sd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv0000148Csd00003001* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6230] + +pci:v00001002d000068E1sv0000148Csd00003002* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6250] + +pci:v00001002d000068E1sv0000148Csd00003003* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6350] + +pci:v00001002d000068E1sv0000148Csd00007350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv0000148Csd00008350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 8350] + +pci:v00001002d000068E1sv00001545sd00005450* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv00001545sd00007350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv00001682sd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv00001682sd00006000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv00001682sd00007350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv0000174Bsd00005470* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5470] + +pci:v00001002d000068E1sv0000174Bsd00006000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv0000174Bsd00006230* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6230] + +pci:v00001002d000068E1sv0000174Bsd00006350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6350] + +pci:v00001002d000068E1sv0000174Bsd00007350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv000017AFsd00003000* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 5450] + +pci:v00001002d000068E1sv000017AFsd00003001* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6230] + +pci:v00001002d000068E1sv000017AFsd00003014* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6350] + +pci:v00001002d000068E1sv000017AFsd00003015* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7350] + +pci:v00001002d000068E1sv000017AFsd00008350* + ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 8350 OEM] + +pci:v00001002d000068E4* + ID_MODEL_FROM_DATABASE=Robson CE [Radeon HD 6370M/7370M] + +pci:v00001002d000068E4sv00001019sd00002386* + ID_MODEL_FROM_DATABASE=Radeon HD 6350M + +pci:v00001002d000068E4sv00001019sd00002387* + ID_MODEL_FROM_DATABASE=Radeon HD 6350M + +pci:v00001002d000068E4sv00001019sd0000238D* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001019sd0000238E* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001025sd00000382* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001025sd00000489* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001025sd0000048A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001025sd0000048B* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001025sd0000048C* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001028sd000004C1* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001028sd000004CA* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001028sd000004CC* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001028sd000004CD* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001028sd000004D7* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001411* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001421* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001426* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001428* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000142A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000142B* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000143A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000143C* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001445* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000162C* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000162D* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000162E* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000162F* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001639* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163B* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163C* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163D* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163E* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000163F* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001641* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00001643* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00003578* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd0000357A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00003673* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000103Csd00003675* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001043sd00001C92* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001043sd000084A1* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001043sd000084AD* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000104Dsd00009081* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001545sd00007350* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 7350] + +pci:v00001002d000068E4sv00001558sd00004510* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv00001558sd00005505* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv0000174Bsd00005450* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 5450] + +pci:v00001002d000068E4sv000017AAsd000021DD* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv000017AAsd000021E9* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv000017AAsd00003971* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M + +pci:v00001002d000068E4sv000017AAsd00003972* + ID_MODEL_FROM_DATABASE=Radeon HD 7370M + +pci:v00001002d000068E4sv000017AAsd0000397A* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M/7370M + +pci:v00001002d000068E4sv000017AAsd0000397B* + ID_MODEL_FROM_DATABASE=Radeon HD 6370M/7370M + +pci:v00001002d000068E4sv000017AAsd0000397F* + ID_MODEL_FROM_DATABASE=Radeon HD 7370M + +pci:v00001002d000068E5* + ID_MODEL_FROM_DATABASE=Robson LE [Radeon HD 6330M] + +pci:v00001002d000068E5sv00001179sd0000FD3C* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD50* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD52* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD63* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD65* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD73* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FD75* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FDD0* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FDD2* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FDEA* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv00001179sd0000FDF8* + ID_MODEL_FROM_DATABASE=Radeon HD 6330M + +pci:v00001002d000068E5sv0000148Csd00005450* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 5450] + +pci:v00001002d000068E5sv0000148Csd00006350* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 6350] + +pci:v00001002d000068E5sv0000148Csd00007350* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 7350] + +pci:v00001002d000068E5sv0000148Csd00008350* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 8350] + +pci:v00001002d000068E5sv00001545sd00007350* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 7350] + +pci:v00001002d000068E8* + ID_MODEL_FROM_DATABASE=Cedar + +pci:v00001002d000068E9* + ID_MODEL_FROM_DATABASE=Cedar [ATI FirePro (FireGL) Graphics Adapter] + +pci:v00001002d000068F1* + ID_MODEL_FROM_DATABASE=Cedar GL [FirePro 2460] + +pci:v00001002d000068F2* + ID_MODEL_FROM_DATABASE=Cedar GL [FirePro 2270] + +pci:v00001002d000068F8* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 7300 Series] + +pci:v00001002d000068F9* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 5000/6000/7350/8350 Series] + +pci:v00001002d000068F9sv00001019sd00000001* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001019sd00000002* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001019sd00000019* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001025sd00000518* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001025sd00000519* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00001002d000068F9sv00001028sd00002126* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000103Csd00002126* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000103Csd00002AAC* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv0000103Csd00002AAE* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv0000103Csd00003580* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001043sd00000386* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001043sd000003C2* + ID_MODEL_FROM_DATABASE=EAH5450 SILENT/DI/512MD2 (LP) + +pci:v00001002d000068F9sv00001462sd00002130* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002131* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002133* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001462sd00002180* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002181* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002182* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001462sd00002183* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001462sd00002230* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002231* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001462sd00002495* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000148Csd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 5530/6250 + +pci:v00001002d000068F9sv0000148Csd00003002* + ID_MODEL_FROM_DATABASE=Radeon HD 6290 + +pci:v00001002d000068F9sv0000148Csd00003003* + ID_MODEL_FROM_DATABASE=Radeon HD 6230 + +pci:v00001002d000068F9sv0000148Csd00003004* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000148Csd00007350* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068F9sv0000148Csd00008350* + ID_MODEL_FROM_DATABASE=Radeon HD 8350 + +pci:v00001002d000068F9sv00001545sd00007350* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068F9sv00001642sd00003983* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001642sd00003984* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001642sd00003987* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv00001642sd00003997* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001642sd00003A05* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001642sd00003B31* + ID_MODEL_FROM_DATABASE=Radeon HD 6350A + +pci:v00001002d000068F9sv00001682sd00003270* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068F9sv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6230 + +pci:v00001002d000068F9sv0000174Bsd00003987* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000174Bsd00005470* + ID_MODEL_FROM_DATABASE=Radeon HD 5470 + +pci:v00001002d000068F9sv0000174Bsd00005490* + ID_MODEL_FROM_DATABASE=Radeon HD 5490 + +pci:v00001002d000068F9sv0000174Bsd00005530* + ID_MODEL_FROM_DATABASE=Radeon HD 5530 + +pci:v00001002d000068F9sv0000174Bsd00006230* + ID_MODEL_FROM_DATABASE=Radeon HD 6230 + +pci:v00001002d000068F9sv0000174Bsd00006250* + ID_MODEL_FROM_DATABASE=Radeon HD 6250 + +pci:v00001002d000068F9sv0000174Bsd00006290* + ID_MODEL_FROM_DATABASE=Radeon HD 6290 + +pci:v00001002d000068F9sv0000174Bsd00006350* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068F9sv0000174Bsd00007350* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068F9sv0000174Bsd00008350* + ID_MODEL_FROM_DATABASE=Radeon HD 8350 + +pci:v00001002d000068F9sv0000174Bsd0000E127* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv0000174Bsd0000E145* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv0000174Bsd0000E153* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 5470 + +pci:v00001002d000068F9sv00001787sd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 5530 + +pci:v00001002d000068F9sv00001787sd00003002* + ID_MODEL_FROM_DATABASE=Radeon HD 5490 + +pci:v00001002d000068F9sv000017AAsd00003602* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv000017AAsd00003603* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv000017AAsd0000360F* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv000017AAsd00003619* + ID_MODEL_FROM_DATABASE=Radeon HD 5450 + +pci:v00001002d000068F9sv000017AFsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 6250 + +pci:v00001002d000068F9sv000017AFsd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 6230 + +pci:v00001002d000068F9sv000017AFsd00003002* + ID_MODEL_FROM_DATABASE=Radeon HD 6290 + +pci:v00001002d000068F9sv000017AFsd00003011* + ID_MODEL_FROM_DATABASE=Radeon HD 5470 + +pci:v00001002d000068F9sv000017AFsd00003012* + ID_MODEL_FROM_DATABASE=Radeon HD 5490 + +pci:v00001002d000068F9sv000017AFsd00003013* + ID_MODEL_FROM_DATABASE=Radeon HD 5470 + +pci:v00001002d000068F9sv000017AFsd00003014* + ID_MODEL_FROM_DATABASE=Radeon HD 6350 + +pci:v00001002d000068FA* + ID_MODEL_FROM_DATABASE=Cedar [Radeon HD 7350/8350] + +pci:v00001002d000068FAsv00001019sd00000019* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001019sd00000021* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001019sd00000022* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001019sd00000026* + ID_MODEL_FROM_DATABASE=Radeon HD 8350 + +pci:v00001002d000068FAsv0000103Csd00002ADF* + ID_MODEL_FROM_DATABASE=Radeon HD 7350A + +pci:v00001002d000068FAsv0000103Csd00002AE8* + ID_MODEL_FROM_DATABASE=Radeon HD 7350A + +pci:v00001002d000068FAsv00001043sd00008350* + ID_MODEL_FROM_DATABASE=Radeon HD 8350 + +pci:v00001002d000068FAsv00001462sd00002128* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001462sd00002184* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001462sd00002186* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001462sd00002495* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001462sd0000B490* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv00001642sd00003985* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv0000174Bsd00007350* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv0000174Bsd00008153* + ID_MODEL_FROM_DATABASE=Radeon HD 8350 + +pci:v00001002d000068FAsv0000174Bsd0000E127* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv0000174Bsd0000E153* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv0000174Bsd0000E180* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FAsv000017AFsd00003015* + ID_MODEL_FROM_DATABASE=Radeon HD 7350 + +pci:v00001002d000068FE* + ID_MODEL_FROM_DATABASE=Cedar LE + +pci:v00001002d00006920* + ID_MODEL_FROM_DATABASE=Tonga + +pci:v00001002d0000700F* + ID_MODEL_FROM_DATABASE=RS100 AGP Bridge + +pci:v00001002d00007010* + ID_MODEL_FROM_DATABASE=RS200/RS250 AGP Bridge + +pci:v00001002d00007100* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800 XT] + +pci:v00001002d00007101* + ID_MODEL_FROM_DATABASE=R520/M58 [Mobility Radeon X1800 XT] + +pci:v00001002d00007102* + ID_MODEL_FROM_DATABASE=R520/M58 [Mobility Radeon X1800] + +pci:v00001002d00007104* + ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200] + +pci:v00001002d00007109* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800 XL] + +pci:v00001002d00007109sv00001002sd00000322* + ID_MODEL_FROM_DATABASE=All-in-Wonder X1800XL + +pci:v00001002d00007109sv00001002sd00000D02* + ID_MODEL_FROM_DATABASE=Radeon X1800 CrossFire Edition + +pci:v00001002d0000710A* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800 GTO] + +pci:v00001002d0000710Asv00001002sd00000B12* + ID_MODEL_FROM_DATABASE=Radeon X1800 GTO² + +pci:v00001002d0000710B* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800 GTO] + +pci:v00001002d00007120* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800] (Secondary) + +pci:v00001002d00007124* + ID_MODEL_FROM_DATABASE=R520 GL [FireGL V7200] (Secondary) + +pci:v00001002d00007129* + ID_MODEL_FROM_DATABASE=R520 [Radeon X1800] (Secondary) + +pci:v00001002d00007129sv00001002sd00000323* + ID_MODEL_FROM_DATABASE=All-In-Wonder X1800 XL (Secondary) + +pci:v00001002d00007129sv00001002sd00000D03* + ID_MODEL_FROM_DATABASE=Radeon X1800 CrossFire Edition (Secondary) + +pci:v00001002d00007140* + ID_MODEL_FROM_DATABASE=RV515 [Radeon X1300/X1550/X1600 Series] + +pci:v00001002d00007142* + ID_MODEL_FROM_DATABASE=RV515 PRO [Radeon X1300/X1550 Series] + +pci:v00001002d00007142sv00001002sd00000322* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 PCI-E Edition + +pci:v00001002d00007142sv00001043sd00000142* + ID_MODEL_FROM_DATABASE=EAX1300PRO/TD/256M + +pci:v00001002d00007143* + ID_MODEL_FROM_DATABASE=RV505 [Radeon X1300/X1550 Series] + +pci:v00001002d00007145* + ID_MODEL_FROM_DATABASE=RV515/M54 [Mobility Radeon X1400] + +pci:v00001002d00007145sv000017AAsd00002006* + ID_MODEL_FROM_DATABASE=Thinkpad T60 model 2007 + +pci:v00001002d00007146* + ID_MODEL_FROM_DATABASE=RV515 [Radeon X1300/X1550] + +pci:v00001002d00007146sv00001002sd00000322* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 PCI-E Edition + +pci:v00001002d00007146sv00001545sd00001996* + ID_MODEL_FROM_DATABASE=Radeon X1300 512MB PCI-e + +pci:v00001002d00007147* + ID_MODEL_FROM_DATABASE=RV505 [Radeon X1550 64-bit] + +pci:v00001002d00007149* + ID_MODEL_FROM_DATABASE=RV515/M52 [Mobility Radeon X1300] + +pci:v00001002d0000714A* + ID_MODEL_FROM_DATABASE=RV515/M52 [Mobility Radeon X1300] + +pci:v00001002d00007152* + ID_MODEL_FROM_DATABASE=RV515 GL [FireGL V3300] + +pci:v00001002d00007153* + ID_MODEL_FROM_DATABASE=RV515 GL [FireGL V3350] + +pci:v00001002d0000715F* + ID_MODEL_FROM_DATABASE=RV505 CE [Radeon X1550 64-bit] + +pci:v00001002d00007162* + ID_MODEL_FROM_DATABASE=RV515 PRO [Radeon X1300/X1550 Series] (Secondary) + +pci:v00001002d00007162sv00001002sd00000323* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 PCI-E Edition (Secondary) + +pci:v00001002d00007163* + ID_MODEL_FROM_DATABASE=RV505 [Radeon X1550 Series] (Secondary) + +pci:v00001002d00007166* + ID_MODEL_FROM_DATABASE=RV515 [Radeon X1300/X1550 Series] (Secondary) + +pci:v00001002d00007166sv00001002sd00000323* + ID_MODEL_FROM_DATABASE=All-in-Wonder 2006 PCI-E Edition (Secondary) + +pci:v00001002d00007166sv00001545sd00001997* + ID_MODEL_FROM_DATABASE=Radeon X1300 512MB PCI-e (Secondary) + +pci:v00001002d00007167* + ID_MODEL_FROM_DATABASE=RV515 [Radeon X1550 64-bit] (Secondary) + +pci:v00001002d00007172* + ID_MODEL_FROM_DATABASE=RV515 GL [FireGL V3300] (Secondary) + +pci:v00001002d00007173* + ID_MODEL_FROM_DATABASE=RV515 GL [FireGL V3350] (Secondary) + +pci:v00001002d00007181* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1600/X1650 Series] + +pci:v00001002d00007183* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1300/X1550 Series] + +pci:v00001002d00007186* + ID_MODEL_FROM_DATABASE=RV516/M64 [Mobility Radeon X1450] + +pci:v00001002d00007187* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1300/X1550 Series] + +pci:v00001002d00007188* + ID_MODEL_FROM_DATABASE=RV516/M64-S [Mobility Radeon X2300] + +pci:v00001002d00007188sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=6910p + +pci:v00001002d0000718A* + ID_MODEL_FROM_DATABASE=RV516/M64 [Mobility Radeon X2300] + +pci:v00001002d0000718B* + ID_MODEL_FROM_DATABASE=RV516/M62 [Mobility Radeon X1350] + +pci:v00001002d0000718C* + ID_MODEL_FROM_DATABASE=RV516/M62-CSP64 [Mobility Radeon X1350] + +pci:v00001002d0000718D* + ID_MODEL_FROM_DATABASE=RV516/M64-CSP128 [Mobility Radeon X1450] + +pci:v00001002d00007193* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1550 Series] + +pci:v00001002d00007196* + ID_MODEL_FROM_DATABASE=RV516/M62-S [Mobility Radeon X1350] + +pci:v00001002d0000719B* + ID_MODEL_FROM_DATABASE=RV516 GL [FireMV 2250] + +pci:v00001002d0000719F* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1550 Series] + +pci:v00001002d000071A0* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1300/X1550 Series] (Secondary) + +pci:v00001002d000071A1* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1600/X1650 Series] (Secondary) + +pci:v00001002d000071A3* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1300/X1550 Series] (Secondary) + +pci:v00001002d000071A7* + ID_MODEL_FROM_DATABASE=RV516 [Radeon X1300/X1550 Series] (Secondary) + +pci:v00001002d000071BB* + ID_MODEL_FROM_DATABASE=RV516 GL [FireMV 2250] (Secondary) + +pci:v00001002d000071C0* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1600 XT/X1650 GTO] + +pci:v00001002d000071C0sv00001002sd0000E160* + ID_MODEL_FROM_DATABASE=Radeon X1650 GTO + +pci:v00001002d000071C0sv0000174Bsd0000E160* + ID_MODEL_FROM_DATABASE=Radeon X1650 GTO + +pci:v00001002d000071C1* + ID_MODEL_FROM_DATABASE=RV535 [Radeon X1650 PRO] + +pci:v00001002d000071C1sv0000174Bsd00000880* + ID_MODEL_FROM_DATABASE=Radeon X1700 FSC + +pci:v00001002d000071C2* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1600 PRO] + +pci:v00001002d000071C4* + ID_MODEL_FROM_DATABASE=RV530/M56 GL [Mobility FireGL V5200] + +pci:v00001002d000071C4sv000017AAsd00002007* + ID_MODEL_FROM_DATABASE=ThinkPad T60p + +pci:v00001002d000071C5* + ID_MODEL_FROM_DATABASE=RV530/M56-P [Mobility Radeon X1600] + +pci:v00001002d000071C5sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00001002d000071C5sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq NW8440 + +pci:v00001002d000071C5sv00001043sd000010B2* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00001002d000071C5sv0000106Bsd00000080* + ID_MODEL_FROM_DATABASE=MacBook Pro + +pci:v00001002d000071C6* + ID_MODEL_FROM_DATABASE=RV530LE [Radeon X1600/X1650 PRO] + +pci:v00001002d000071C7* + ID_MODEL_FROM_DATABASE=RV535 [Radeon X1650 PRO] + +pci:v00001002d000071C7sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=PowerColor X1650 PRO AGP + +pci:v00001002d000071CE* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1300 XT/X1600 PRO] + +pci:v00001002d000071D2* + ID_MODEL_FROM_DATABASE=RV530 GL [FireGL V3400] + +pci:v00001002d000071D4* + ID_MODEL_FROM_DATABASE=RV530/M66 GL [Mobility FireGL V5250] + +pci:v00001002d000071D5* + ID_MODEL_FROM_DATABASE=RV530/M66-P [Mobility Radeon X1700] + +pci:v00001002d000071D6* + ID_MODEL_FROM_DATABASE=RV530/M66-XT [Mobility Radeon X1700] + +pci:v00001002d000071DE* + ID_MODEL_FROM_DATABASE=RV530/M66 [Mobility Radeon X1700/X2500] + +pci:v00001002d000071E0* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1600] (Secondary) + +pci:v00001002d000071E0sv0000174Bsd0000E161* + ID_MODEL_FROM_DATABASE=Radeon X1600 GTO (Secondary) + +pci:v00001002d000071E1* + ID_MODEL_FROM_DATABASE=RV535 [Radeon X1650 PRO] (Secondary) + +pci:v00001002d000071E1sv0000174Bsd00000881* + ID_MODEL_FROM_DATABASE=Radeon X1700 FSC (Secondary) + +pci:v00001002d000071E2* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1600] (Secondary) + +pci:v00001002d000071E6* + ID_MODEL_FROM_DATABASE=RV530 [Radeon X1650] (Secondary) + +pci:v00001002d000071E7* + ID_MODEL_FROM_DATABASE=RV535 [Radeon X1650 PRO] (Secondary) + +pci:v00001002d000071E7sv00001787sd00003001* + ID_MODEL_FROM_DATABASE=Radeon X1650 PRO AGP + +pci:v00001002d000071F2* + ID_MODEL_FROM_DATABASE=RV530 GL [FireGL V3400] (Secondary) + +pci:v00001002d00007210* + ID_MODEL_FROM_DATABASE=RV550/M71 [Mobility Radeon HD 2300] + +pci:v00001002d00007211* + ID_MODEL_FROM_DATABASE=RV550/M71 [Mobility Radeon X2300 HD] + +pci:v00001002d00007240* + ID_MODEL_FROM_DATABASE=R580+ [Radeon X1950 XTX] + +pci:v00001002d00007240sv00001002sd00000D02* + ID_MODEL_FROM_DATABASE=Radeon X1950 CrossFire Edition + +pci:v00001002d00007244* + ID_MODEL_FROM_DATABASE=R580+ [Radeon X1950 XT] + +pci:v00001002d00007248* + ID_MODEL_FROM_DATABASE=R580 [Radeon X1950] + +pci:v00001002d00007249* + ID_MODEL_FROM_DATABASE=R580 [Radeon X1900 XT] + +pci:v00001002d00007249sv00001002sd00000412* + ID_MODEL_FROM_DATABASE=All-In-Wonder X1900 + +pci:v00001002d00007249sv00001002sd00000B12* + ID_MODEL_FROM_DATABASE=Radeon X1900 XT/XTX + +pci:v00001002d00007249sv00001002sd00000D02* + ID_MODEL_FROM_DATABASE=Radeon X1900 CrossFire Edition + +pci:v00001002d00007249sv00001043sd00000160* + ID_MODEL_FROM_DATABASE=Radeon X1900 XTX 512 MB GDDR3 + +pci:v00001002d0000724B* + ID_MODEL_FROM_DATABASE=R580 [Radeon X1900 GT] + +pci:v00001002d0000724Bsv00001002sd00000B12* + ID_MODEL_FROM_DATABASE=Radeon X1900 (Primary) + +pci:v00001002d0000724Bsv00001002sd00000B13* + ID_MODEL_FROM_DATABASE=Radeon X1900 (Secondary) + +pci:v00001002d0000724E* + ID_MODEL_FROM_DATABASE=R580 GL [FireGL V7350] + +pci:v00001002d00007269* + ID_MODEL_FROM_DATABASE=R580 [Radeon X1900 XT] (Secondary) + +pci:v00001002d0000726B* + ID_MODEL_FROM_DATABASE=R580 [Radeon X1900 GT] (Secondary) + +pci:v00001002d0000726E* + ID_MODEL_FROM_DATABASE=R580 [AMD Stream Processor] (Secondary) + +pci:v00001002d00007280* + ID_MODEL_FROM_DATABASE=RV570 [Radeon X1950 PRO] + +pci:v00001002d00007288* + ID_MODEL_FROM_DATABASE=RV570 [Radeon X1950 GT] + +pci:v00001002d00007291* + ID_MODEL_FROM_DATABASE=RV560 [Radeon X1650 XT] + +pci:v00001002d00007291sv00001462sd00000810* + ID_MODEL_FROM_DATABASE=Radeon X1700 SE + +pci:v00001002d00007293* + ID_MODEL_FROM_DATABASE=RV560 [Radeon X1650 GT] + +pci:v00001002d000072A0* + ID_MODEL_FROM_DATABASE=RV570 [Radeon X1950 PRO] (Secondary) + +pci:v00001002d000072A8* + ID_MODEL_FROM_DATABASE=RV570 [Radeon X1950 GT] (Secondary) + +pci:v00001002d000072B1* + ID_MODEL_FROM_DATABASE=RV560 [Radeon X1650 XT] (Secondary) + +pci:v00001002d000072B3* + ID_MODEL_FROM_DATABASE=RV560 [Radeon X1650 GT] (Secondary) + +pci:v00001002d00007833* + ID_MODEL_FROM_DATABASE=RS350 Host Bridge + +pci:v00001002d00007834* + ID_MODEL_FROM_DATABASE=RS350 [Radeon 9100 PRO/XT IGP] + +pci:v00001002d00007835* + ID_MODEL_FROM_DATABASE=RS350M [Mobility Radeon 9000 IGP] + +pci:v00001002d00007838* + ID_MODEL_FROM_DATABASE=RS350 AGP Bridge + +pci:v00001002d00007910* + ID_MODEL_FROM_DATABASE=RS690 Host Bridge + +pci:v00001002d00007910sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00007910sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d00007911* + ID_MODEL_FROM_DATABASE=RS690 Host Bridge + +pci:v00001002d00007912* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (Internal gfx) + +pci:v00001002d00007913* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (PCI Express Graphics Port 0) + +pci:v00001002d00007915* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (PCI Express Port 1) + +pci:v00001002d00007916* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (PCI Express Port 2) + +pci:v00001002d00007917* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (PCI Express Port 3) + +pci:v00001002d00007917sv00001002sd00007910* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge + +pci:v00001002d00007919* + ID_MODEL_FROM_DATABASE=RS690 HDMI Audio [Radeon Xpress 1200 Series] + +pci:v00001002d00007919sv00001179sd00007919* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00007919sv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000791E* + ID_MODEL_FROM_DATABASE=RS690 [Radeon X1200] + +pci:v00001002d0000791Esv00001462sd00007327* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v00001002d0000791Esv000017F2sd00005000* + ID_MODEL_FROM_DATABASE=KI690-AM2 Motherboard + +pci:v00001002d0000791F* + ID_MODEL_FROM_DATABASE=RS690M [Radeon Xpress 1200/1250/1270] + +pci:v00001002d0000791Fsv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001002d00007930* + ID_MODEL_FROM_DATABASE=RS600 Host Bridge + +pci:v00001002d00007932* + ID_MODEL_FROM_DATABASE=RS600 PCI to PCI Bridge (Internal gfx) + +pci:v00001002d00007933* + ID_MODEL_FROM_DATABASE=RS600 PCI to PCI Bridge (PCI Express Graphics Port 0) + +pci:v00001002d00007935* + ID_MODEL_FROM_DATABASE=RS600 PCI to PCI Bridge (PCI Express Port 1) + +pci:v00001002d00007936* + ID_MODEL_FROM_DATABASE=RS600 PCI to PCI Bridge (PCI Express Port 2) + +pci:v00001002d00007937* + ID_MODEL_FROM_DATABASE=RS690 PCI to PCI Bridge (PCI Express Port 3) + +pci:v00001002d0000793B* + ID_MODEL_FROM_DATABASE=RS600 HDMI Audio [Radeon Xpress 1250] + +pci:v00001002d0000793F* + ID_MODEL_FROM_DATABASE=RS690M [Radeon Xpress 1200/1250/1270] (Secondary) + +pci:v00001002d00007941* + ID_MODEL_FROM_DATABASE=RS600 [Radeon Xpress 1250] + +pci:v00001002d00007942* + ID_MODEL_FROM_DATABASE=RS600M [Radeon Xpress 1250] + +pci:v00001002d0000796E* + ID_MODEL_FROM_DATABASE=RS740 [Radeon 2100] + +pci:v00001002d00009400* + ID_MODEL_FROM_DATABASE=R600 [Radeon HD 2900 PRO/XT] + +pci:v00001002d00009400sv00001002sd00002552* + ID_MODEL_FROM_DATABASE=Radeon HD 2900 XT + +pci:v00001002d00009400sv00001002sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 2900 PRO + +pci:v00001002d00009400sv00001002sd00003142* + ID_MODEL_FROM_DATABASE=HIS Radeon HD 2900XT 512MB GDDR3 VIVO PCIe + +pci:v00001002d00009401* + ID_MODEL_FROM_DATABASE=R600 [Radeon HD 2900 XT] + +pci:v00001002d00009403* + ID_MODEL_FROM_DATABASE=R600 [Radeon HD 2900 PRO] + +pci:v00001002d00009405* + ID_MODEL_FROM_DATABASE=R600 [Radeon HD 2900 GT] + +pci:v00001002d0000940A* + ID_MODEL_FROM_DATABASE=R600 GL [FireGL V8650] + +pci:v00001002d0000940B* + ID_MODEL_FROM_DATABASE=R600 GL [FireGL V8600] + +pci:v00001002d0000940F* + ID_MODEL_FROM_DATABASE=R600 GL [FireGL V7600] + +pci:v00001002d00009440* + ID_MODEL_FROM_DATABASE=RV770 [Radeon HD 4870] + +pci:v00001002d00009441* + ID_MODEL_FROM_DATABASE=R700 [Radeon HD 4870 X2] + +pci:v00001002d00009442* + ID_MODEL_FROM_DATABASE=RV770 [Radeon HD 4850] + +pci:v00001002d00009442sv00001002sd00000502* + ID_MODEL_FROM_DATABASE=MSI Radeon HD 4850 512MB GDDR3 + +pci:v00001002d00009442sv0000174Bsd0000E810* + ID_MODEL_FROM_DATABASE=Radeon HD 4850 512MB GDDR3 + +pci:v00001002d00009443* + ID_MODEL_FROM_DATABASE=R700 [Radeon HD 4850 X2] + +pci:v00001002d00009444* + ID_MODEL_FROM_DATABASE=RV770 GL [FirePro V8750] + +pci:v00001002d00009446* + ID_MODEL_FROM_DATABASE=RV770 GL [FirePro V7760] + +pci:v00001002d0000944A* + ID_MODEL_FROM_DATABASE=RV770/M98L [Mobility Radeon HD 4850] + +pci:v00001002d0000944B* + ID_MODEL_FROM_DATABASE=RV770/M98 [Mobility Radeon HD 4850 X2] + +pci:v00001002d0000944C* + ID_MODEL_FROM_DATABASE=RV770 LE [Radeon HD 4830] + +pci:v00001002d0000944E* + ID_MODEL_FROM_DATABASE=RV770 CE [Radeon HD 4710] + +pci:v00001002d0000944Esv0000174Bsd00003261* + ID_MODEL_FROM_DATABASE=Radeon HD 4810 + +pci:v00001002d00009450* + ID_MODEL_FROM_DATABASE=RV770 GL [FireStream 9270] + +pci:v00001002d00009452* + ID_MODEL_FROM_DATABASE=RV770 GL [FireStream 9250] + +pci:v00001002d00009456* + ID_MODEL_FROM_DATABASE=RV770 GL [FirePro V8700] + +pci:v00001002d0000945A* + ID_MODEL_FROM_DATABASE=RV770/M98-XT [Mobility Radeon HD 4870] + +pci:v00001002d00009460* + ID_MODEL_FROM_DATABASE=RV790 [Radeon HD 4890] + +pci:v00001002d00009462* + ID_MODEL_FROM_DATABASE=RV790 [Radeon HD 4860] + +pci:v00001002d0000946A* + ID_MODEL_FROM_DATABASE=RV770 GL [FirePro M7750] + +pci:v00001002d00009480* + ID_MODEL_FROM_DATABASE=RV730/M96 [Mobility Radeon HD 4650/5165] + +pci:v00001002d00009480sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4650 [dv6-1190en] + +pci:v00001002d00009488* + ID_MODEL_FROM_DATABASE=RV730/M96-XT [Mobility Radeon HD 4670] + +pci:v00001002d00009489* + ID_MODEL_FROM_DATABASE=RV730/M96 GL [Mobility FireGL V5725] + +pci:v00001002d00009490* + ID_MODEL_FROM_DATABASE=RV730 XT [Radeon HD 4670] + +pci:v00001002d00009490sv0000174Bsd0000E880* + ID_MODEL_FROM_DATABASE=Radeon HD 4670 512MB GDDR3 Dual DVI-I/TVO + +pci:v00001002d00009491* + ID_MODEL_FROM_DATABASE=RV730/M96-CSP [Radeon E4690] + +pci:v00001002d00009495* + ID_MODEL_FROM_DATABASE=RV730 [Radeon HD 4600 AGP Series] + +pci:v00001002d00009495sv00001002sd00000028* + ID_MODEL_FROM_DATABASE=Radeon HD 4650/4670 AGP + +pci:v00001002d00009495sv00001092sd00000028* + ID_MODEL_FROM_DATABASE=Radeon HD 4670 AGP 512MB DDR2 + +pci:v00001002d00009495sv00001458sd00000028* + ID_MODEL_FROM_DATABASE=Radeon HD 4650 AGP + +pci:v00001002d00009495sv00001682sd00000028* + ID_MODEL_FROM_DATABASE=Radeon HD 4650 AGP + +pci:v00001002d00009495sv0000174Bsd00000028* + ID_MODEL_FROM_DATABASE=Radeon HD 4650 AGP DDR2 + +pci:v00001002d00009498* + ID_MODEL_FROM_DATABASE=RV730 PRO [Radeon HD 4650] + +pci:v00001002d0000949C* + ID_MODEL_FROM_DATABASE=RV730 GL [FirePro V7750] + +pci:v00001002d0000949E* + ID_MODEL_FROM_DATABASE=RV730 GL [FirePro V5700] + +pci:v00001002d0000949F* + ID_MODEL_FROM_DATABASE=RV730 GL [FirePro V3750] + +pci:v00001002d000094A0* + ID_MODEL_FROM_DATABASE=RV740/M97 [Mobility Radeon HD 4830] + +pci:v00001002d000094A1* + ID_MODEL_FROM_DATABASE=RV740/M97-XT [Mobility Radeon HD 4860] + +pci:v00001002d000094A3* + ID_MODEL_FROM_DATABASE=RV740/M97 GL [FirePro M7740] + +pci:v00001002d000094B3* + ID_MODEL_FROM_DATABASE=RV740 PRO [Radeon HD 4770] + +pci:v00001002d000094B4* + ID_MODEL_FROM_DATABASE=RV740 PRO [Radeon HD 4750] + +pci:v00001002d000094C1* + ID_MODEL_FROM_DATABASE=RV610 [Radeon HD 2400 PRO/XT] + +pci:v00001002d000094C1sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00001002d000094C1sv00001028sd00000D02* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00001002d000094C3* + ID_MODEL_FROM_DATABASE=RV610 [Radeon HD 2400 PRO] + +pci:v00001002d000094C3sv00001028sd00000302* + ID_MODEL_FROM_DATABASE=Radeon HD 2400 Pro + +pci:v00001002d000094C3sv0000174Bsd0000E400* + ID_MODEL_FROM_DATABASE=Radeon HD 2400 PRO + +pci:v00001002d000094C3sv000018BCsd00003550* + ID_MODEL_FROM_DATABASE=Radeon HD 2400 PRO + +pci:v00001002d000094C4* + ID_MODEL_FROM_DATABASE=RV610 LE [Radeon HD 2400 PRO AGP] + +pci:v00001002d000094C5* + ID_MODEL_FROM_DATABASE=RV610 [Radeon HD 2400 LE] + +pci:v00001002d000094C7* + ID_MODEL_FROM_DATABASE=RV610 [Radeon HD 2350] + +pci:v00001002d000094C8* + ID_MODEL_FROM_DATABASE=RV610/M74 [Mobility Radeon HD 2400 XT] + +pci:v00001002d000094C9* + ID_MODEL_FROM_DATABASE=RV610/M72-S [Mobility Radeon HD 2400] + +pci:v00001002d000094C9sv00001002sd000094C9* + ID_MODEL_FROM_DATABASE=Radeon HD2400 + +pci:v00001002d000094CB* + ID_MODEL_FROM_DATABASE=RV610 [Radeon E2400] + +pci:v00001002d000094CC* + ID_MODEL_FROM_DATABASE=RV610 LE [Radeon HD 2400 PRO PCI] + +pci:v00001002d00009500* + ID_MODEL_FROM_DATABASE=RV670 [Radeon HD 3850 X2] + +pci:v00001002d00009501* + ID_MODEL_FROM_DATABASE=RV670 [Radeon HD 3870] + +pci:v00001002d00009501sv0000174Bsd0000E620* + ID_MODEL_FROM_DATABASE=Radeon HD 3870 + +pci:v00001002d00009504* + ID_MODEL_FROM_DATABASE=RV670/M88 [Mobility Radeon HD 3850] + +pci:v00001002d00009505* + ID_MODEL_FROM_DATABASE=RV670 [Radeon HD 3690/3850] + +pci:v00001002d00009505sv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 3850 + +pci:v00001002d00009505sv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 3690/3850 + +pci:v00001002d00009505sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 3690 + +pci:v00001002d00009506* + ID_MODEL_FROM_DATABASE=RV670/M88 [Mobility Radeon HD 3850 X2] + +pci:v00001002d00009507* + ID_MODEL_FROM_DATABASE=RV670 [Radeon HD 3830] + +pci:v00001002d00009508* + ID_MODEL_FROM_DATABASE=RV670/M88-XT [Mobility Radeon HD 3870] + +pci:v00001002d00009509* + ID_MODEL_FROM_DATABASE=RV670/M88 [Mobility Radeon HD 3870 X2] + +pci:v00001002d0000950F* + ID_MODEL_FROM_DATABASE=R680 [Radeon HD 3870 X2] + +pci:v00001002d00009511* + ID_MODEL_FROM_DATABASE=RV670 GL [FireGL V7700] + +pci:v00001002d00009513* + ID_MODEL_FROM_DATABASE=RV670 [Radeon HD 3850 X2] + +pci:v00001002d00009515* + ID_MODEL_FROM_DATABASE=RV670 PRO [Radeon HD 3850 AGP] + +pci:v00001002d00009519* + ID_MODEL_FROM_DATABASE=RV670 GL [FireStream 9170] + +pci:v00001002d00009540* + ID_MODEL_FROM_DATABASE=RV710 [Radeon HD 4550] + +pci:v00001002d0000954F* + ID_MODEL_FROM_DATABASE=RV710 [Radeon HD 4350/4550] + +pci:v00001002d0000954Fsv00001462sd00001618* + ID_MODEL_FROM_DATABASE=R4350 MD512H (MS-V161) + +pci:v00001002d00009552* + ID_MODEL_FROM_DATABASE=RV710/M92 [Mobility Radeon HD 4330/4350/4550] + +pci:v00001002d00009552sv00001028sd00001103* + ID_MODEL_FROM_DATABASE=M92 [Mobility Radeon HD 4330] + +pci:v00001002d00009552sv00001458sd000021AC* + ID_MODEL_FROM_DATABASE=Radeon HD 4350 + +pci:v00001002d00009552sv00001458sd000021ED* + ID_MODEL_FROM_DATABASE=Radeon HD 4550 + +pci:v00001002d00009552sv0000148Csd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 4350 Go! Green 512MB GDDR3 + +pci:v00001002d00009552sv0000174Bsd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 4350/4550 HyperMemory DDR2 + +pci:v00001002d00009553* + ID_MODEL_FROM_DATABASE=RV710/M92 [Mobility Radeon HD 4530/4570/545v] + +pci:v00001002d00009553sv00001025sd0000015E* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001025sd0000017D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001025sd00000205* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001025sd00000206* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001025sd00000237* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001028sd000002BE* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001028sd000002E8* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4530 + +pci:v00001002d00009553sv0000103Csd00003624* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4530 + +pci:v00001002d00009553sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4530 + +pci:v00001002d00009553sv0000103Csd00003636* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4530 + +pci:v00001002d00009553sv00001043sd00001B32* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001043sd00001B42* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv0000104Dsd00009056* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 4570 + +pci:v00001002d00009553sv00001179sd0000FF82* + ID_MODEL_FROM_DATABASE=Satellite L505-13T GPU (Mobility Radeon HD 5145) + +pci:v00001002d00009555* + ID_MODEL_FROM_DATABASE=RV710/M92 [Mobility Radeon HD 4350/4550] + +pci:v00001002d00009555sv0000103Csd00001411* + ID_MODEL_FROM_DATABASE=ProBook 4720s GPU (Mobility Radeon HD 4350) + +pci:v00001002d00009557* + ID_MODEL_FROM_DATABASE=RV711 GL [FirePro RG220] + +pci:v00001002d0000955F* + ID_MODEL_FROM_DATABASE=RV710/M92 [Mobility Radeon HD 4330] + +pci:v00001002d00009580* + ID_MODEL_FROM_DATABASE=RV630 [Radeon HD 2600 PRO] + +pci:v00001002d00009581* + ID_MODEL_FROM_DATABASE=RV630/M76 [Mobility Radeon HD 2600] + +pci:v00001002d00009583* + ID_MODEL_FROM_DATABASE=RV630/M76 [Mobility Radeon HD 2600 XT/2700] + +pci:v00001002d00009583sv0000106Bsd00000083* + ID_MODEL_FROM_DATABASE=iMac 7,1 + +pci:v00001002d00009583sv00001734sd00001107* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 2700 + +pci:v00001002d00009586* + ID_MODEL_FROM_DATABASE=RV630 XT [Radeon HD 2600 XT AGP] + +pci:v00001002d00009587* + ID_MODEL_FROM_DATABASE=RV630 PRO [Radeon HD 2600 PRO AGP] + +pci:v00001002d00009588* + ID_MODEL_FROM_DATABASE=RV630 XT [Radeon HD 2600 XT] + +pci:v00001002d00009588sv00001458sd0000216C* + ID_MODEL_FROM_DATABASE=Radeon HD 2600 XT, 256MB GDDR3, 2x DVI, TV-out, PCIe (GV-RX26T256H) + +pci:v00001002d00009589* + ID_MODEL_FROM_DATABASE=RV630 PRO [Radeon HD 2600 PRO] + +pci:v00001002d00009589sv00001787sd00003000* + ID_MODEL_FROM_DATABASE=Radeon HD 3610 + +pci:v00001002d0000958A* + ID_MODEL_FROM_DATABASE=RV630 [Radeon HD 2600 X2] + +pci:v00001002d0000958B* + ID_MODEL_FROM_DATABASE=RV630/M76 [Mobility Radeon HD 2600 XT] + +pci:v00001002d0000958C* + ID_MODEL_FROM_DATABASE=RV630 GL [FireGL V5600] + +pci:v00001002d0000958D* + ID_MODEL_FROM_DATABASE=RV630 GL [FireGL V3600] + +pci:v00001002d00009591* + ID_MODEL_FROM_DATABASE=RV635/M86 [Mobility Radeon HD 3650] + +pci:v00001002d00009591sv00001002sd00009591* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 3650 + +pci:v00001002d00009593* + ID_MODEL_FROM_DATABASE=RV635/M86 [Mobility Radeon HD 3670] + +pci:v00001002d00009595* + ID_MODEL_FROM_DATABASE=RV635/M86 GL [Mobility FireGL V5700] + +pci:v00001002d00009596* + ID_MODEL_FROM_DATABASE=RV635 PRO [Radeon HD 3650 AGP] + +pci:v00001002d00009596sv00001043sd00000028* + ID_MODEL_FROM_DATABASE=EAH3650 SILENT/HTDI/512M/A + +pci:v00001002d00009597* + ID_MODEL_FROM_DATABASE=RV635 PRO [Radeon HD 3650 AGP] + +pci:v00001002d00009598* + ID_MODEL_FROM_DATABASE=RV635 [Radeon HD 3650/3750/4570/4580] + +pci:v00001002d00009598sv00001002sd00009598* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 3600 + +pci:v00001002d00009598sv00001043sd000001D6* + ID_MODEL_FROM_DATABASE=EAH3650 Silent + +pci:v00001002d00009598sv00001043sd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 4570 + +pci:v00001002d00009598sv0000174Bsd00003001* + ID_MODEL_FROM_DATABASE=Radeon HD 3750 + +pci:v00001002d00009598sv0000174Bsd00004580* + ID_MODEL_FROM_DATABASE=RV635 PRO [Radeon HD 4580] + +pci:v00001002d00009599* + ID_MODEL_FROM_DATABASE=RV635 PRO [Radeon HD 3650 AGP] + +pci:v00001002d000095C0* + ID_MODEL_FROM_DATABASE=RV620 PRO [Radeon HD 3470] + +pci:v00001002d000095C0sv00001002sd000095C0* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 3470 + +pci:v00001002d000095C2* + ID_MODEL_FROM_DATABASE=RV620/M82 [Mobility Radeon HD 3410/3430] + +pci:v00001002d000095C4* + ID_MODEL_FROM_DATABASE=RV620/M82 [Mobility Radeon HD 3450/3470] + +pci:v00001002d000095C4sv00001002sd000095C4* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 3400 + +pci:v00001002d000095C5* + ID_MODEL_FROM_DATABASE=RV620 LE [Radeon HD 3450] + +pci:v00001002d000095C5sv00001028sd00000342* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00001002d000095C6* + ID_MODEL_FROM_DATABASE=RV620 LE [Radeon HD 3450 AGP] + +pci:v00001002d000095C9* + ID_MODEL_FROM_DATABASE=RV620 LE [Radeon HD 3450 PCI] + +pci:v00001002d000095CC* + ID_MODEL_FROM_DATABASE=RV620 GL [FirePro V3700] + +pci:v00001002d000095CF* + ID_MODEL_FROM_DATABASE=RV620 GL [FirePro 2260] + +pci:v00001002d0000960F* + ID_MODEL_FROM_DATABASE=RS780 HDMI Audio [Radeon (HD) 3000 Series] + +pci:v00001002d00009610* + ID_MODEL_FROM_DATABASE=RS780 [Radeon HD 3200] + +pci:v00001002d00009610sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=GA-MA78GM-S2H Motherboard + +pci:v00001002d00009611* + ID_MODEL_FROM_DATABASE=RS780C [Radeon 3100] + +pci:v00001002d00009612* + ID_MODEL_FROM_DATABASE=RS780M [Mobility Radeon HD 3200] + +pci:v00001002d00009613* + ID_MODEL_FROM_DATABASE=RS780MC [Mobility Radeon HD 3100] + +pci:v00001002d00009614* + ID_MODEL_FROM_DATABASE=RS780D [Radeon HD 3300] + +pci:v00001002d00009616* + ID_MODEL_FROM_DATABASE=RS780L [Radeon 3000] + +pci:v00001002d00009640* + ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6550D] + +pci:v00001002d00009641* + ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6620G] + +pci:v00001002d00009642* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6370D] + +pci:v00001002d00009643* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6380G] + +pci:v00001002d00009644* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6410D] + +pci:v00001002d00009645* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6410D] + +pci:v00001002d00009647* + ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6520G] + +pci:v00001002d00009648* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6480G] + +pci:v00001002d00009649* + ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6480G] + +pci:v00001002d0000964A* + ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6530D] + +pci:v00001002d0000964B* + ID_MODEL_FROM_DATABASE=Sumo + +pci:v00001002d0000964C* + ID_MODEL_FROM_DATABASE=Sumo + +pci:v00001002d0000964E* + ID_MODEL_FROM_DATABASE=Sumo + +pci:v00001002d0000964F* + ID_MODEL_FROM_DATABASE=Sumo + +pci:v00001002d0000970F* + ID_MODEL_FROM_DATABASE=RS880 HDMI Audio [Radeon HD 4200 Series] + +pci:v00001002d0000970Fsv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d0000970Fsv00001043sd000083A2* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001002d0000970Fsv00001043sd0000843E* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00009710* + ID_MODEL_FROM_DATABASE=RS880 [Radeon HD 4200] + +pci:v00001002d00009710sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001002d00009710sv00001043sd000083A2* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001002d00009712* + ID_MODEL_FROM_DATABASE=RS880M [Mobility Radeon HD 4225/4250] + +pci:v00001002d00009713* + ID_MODEL_FROM_DATABASE=RS880M [Mobility Radeon HD 4100] + +pci:v00001002d00009714* + ID_MODEL_FROM_DATABASE=RS880 [Radeon HD 4290] + +pci:v00001002d00009715* + ID_MODEL_FROM_DATABASE=RS880 [Radeon HD 4250] + +pci:v00001002d00009715sv00001043sd0000843E* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001002d00009802* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6310] + +pci:v00001002d00009802sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001002d00009803* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6310] + +pci:v00001002d00009804* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6250] + +pci:v00001002d00009805* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6250] + +pci:v00001002d00009806* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6320] + +pci:v00001002d00009807* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 6290] + +pci:v00001002d00009808* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 7340] + +pci:v00001002d00009809* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 7310] + +pci:v00001002d0000980A* + ID_MODEL_FROM_DATABASE=Wrestler [Radeon HD 7290] + +pci:v00001002d00009830* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8400] + +pci:v00001002d00009831* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8400E] + +pci:v00001002d00009832* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8330] + +pci:v00001002d00009833* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8330E] + +pci:v00001002d00009834* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8210] + +pci:v00001002d00009835* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8310E] + +pci:v00001002d00009836* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8280] + +pci:v00001002d00009837* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8280E] + +pci:v00001002d00009838* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8240] + +pci:v00001002d00009839* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8180] + +pci:v00001002d0000983A* + ID_MODEL_FROM_DATABASE=Kabini + +pci:v00001002d0000983B* + ID_MODEL_FROM_DATABASE=Kabini + +pci:v00001002d0000983C* + ID_MODEL_FROM_DATABASE=Kabini + +pci:v00001002d0000983D* + ID_MODEL_FROM_DATABASE=Temash [Radeon HD 8250/8280G] + +pci:v00001002d0000983E* + ID_MODEL_FROM_DATABASE=Kabini + +pci:v00001002d0000983F* + ID_MODEL_FROM_DATABASE=Kabini + +pci:v00001002d00009850* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU A6-6200 with R3 Graphics] + +pci:v00001002d00009851* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU A4-6000 with R2 Graphics] + +pci:v00001002d00009852* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU A4-6000 with R2 Graphics] + +pci:v00001002d00009853* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU E2-4000 with R2 Graphics] + +pci:v00001002d00009854* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU E2-3700 with R2 Graphics] + +pci:v00001002d00009855* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU XX-2450M with R3 Graphics] + +pci:v00001002d00009856* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU XX-2200M with R2 Graphics] + +pci:v00001002d00009857* + ID_MODEL_FROM_DATABASE=Mullins [Radeon APU XX-2200M with R2 Graphics] + +pci:v00001002d00009858* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d00009859* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985A* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985B* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985C* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985D* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985E* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d0000985F* + ID_MODEL_FROM_DATABASE=Mullins + +pci:v00001002d00009901* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7660D] + +pci:v00001002d00009902* + ID_MODEL_FROM_DATABASE=Trinity HDMI Audio Controller + +pci:v00001002d00009902sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001002d00009903* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7640G] + +pci:v00001002d00009903sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001002d00009903sv0000103Csd00001952* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001002d00009904* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7560D] + +pci:v00001002d00009905* + ID_MODEL_FROM_DATABASE=Trinity [FirePro A300 Series Graphics] + +pci:v00001002d00009906* + ID_MODEL_FROM_DATABASE=Trinity [FirePro A300 Series Graphics] + +pci:v00001002d00009907* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7620G] + +pci:v00001002d00009908* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7600G] + +pci:v00001002d00009909* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7500G] + +pci:v00001002d0000990A* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7500G] + +pci:v00001002d0000990B* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8650G] + +pci:v00001002d0000990C* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8670D] + +pci:v00001002d0000990D* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8550G] + +pci:v00001002d0000990E* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8570D] + +pci:v00001002d0000990F* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8610G] + +pci:v00001002d00009910* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7660G] + +pci:v00001002d00009913* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7640G] + +pci:v00001002d00009917* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7620G] + +pci:v00001002d00009918* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7600G] + +pci:v00001002d00009919* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7500G] + +pci:v00001002d00009990* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7520G] + +pci:v00001002d00009991* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7540D] + +pci:v00001002d00009992* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7420G] + +pci:v00001002d00009993* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7480D] + +pci:v00001002d00009994* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7400G] + +pci:v00001002d00009995* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8450G] + +pci:v00001002d00009996* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8470D] + +pci:v00001002d00009997* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8350G] + +pci:v00001002d00009998* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8370D] + +pci:v00001002d00009999* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8510G] + +pci:v00001002d0000999A* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8410G] + +pci:v00001002d0000999B* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8310G] + +pci:v00001002d0000999C* + ID_MODEL_FROM_DATABASE=Richland + +pci:v00001002d0000999D* + ID_MODEL_FROM_DATABASE=Richland [Radeon HD 8550D] + +pci:v00001002d000099A0* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7520G] + +pci:v00001002d000099A2* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7420G] + +pci:v00001002d000099A4* + ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7400G] + +pci:v00001002d0000AA00* + ID_MODEL_FROM_DATABASE=R600 HDMI Audio [Radeon HD 2900 Series] + +pci:v00001002d0000AA08* + ID_MODEL_FROM_DATABASE=RV630 HDMI Audio [Radeon HD 2600 Series] + +pci:v00001002d0000AA10* + ID_MODEL_FROM_DATABASE=RV610 HDMI Audio [Radeon HD 2350/2400 Series] + +pci:v00001002d0000AA10sv0000174Bsd0000AA10* + ID_MODEL_FROM_DATABASE=Radeon HD 2400 PRO + +pci:v00001002d0000AA10sv000018BCsd0000AA10* + ID_MODEL_FROM_DATABASE=Radeon HD 2400 PRO + +pci:v00001002d0000AA18* + ID_MODEL_FROM_DATABASE=RV670/680 HDMI Audio [Radeon HD 3690/3800 Series] + +pci:v00001002d0000AA20* + ID_MODEL_FROM_DATABASE=RV635 HDMI Audio [Radeon HD 3600 Series] + +pci:v00001002d0000AA28* + ID_MODEL_FROM_DATABASE=RV620 HDMI Audio [Radeon HD 3400 Series] + +pci:v00001002d0000AA30* + ID_MODEL_FROM_DATABASE=RV770 HDMI Audio [Radeon HD 4850/4870] + +pci:v00001002d0000AA30sv0000174Bsd0000AA30* + ID_MODEL_FROM_DATABASE=Radeon HD 4850 512MB GDDR3 PCI-E Dual Slot Fansink + +pci:v00001002d0000AA38* + ID_MODEL_FROM_DATABASE=RV710/730 HDMI Audio [Radeon HD 4000 series] + +pci:v00001002d0000AA38sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=dv6-1190en + +pci:v00001002d0000AA50* + ID_MODEL_FROM_DATABASE=Cypress HDMI Audio [Radeon HD 5800 Series] + +pci:v00001002d0000AA58* + ID_MODEL_FROM_DATABASE=Juniper HDMI Audio [Radeon HD 5700 Series] + +pci:v00001002d0000AA60* + ID_MODEL_FROM_DATABASE=Redwood HDMI Audio [Radeon HD 5000 Series] + +pci:v00001002d0000AA60sv00001025sd0000033D* + ID_MODEL_FROM_DATABASE=Mobility Radeon HD 5650 + +pci:v00001002d0000AA60sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00001002d0000AA68* + ID_MODEL_FROM_DATABASE=Cedar HDMI Audio [Radeon HD 5400/6300 Series] + +pci:v00001002d0000AA68sv00001028sd0000AA68* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00001002d0000AA80* + ID_MODEL_FROM_DATABASE=Cayman/Antilles HDMI Audio [Radeon HD 6900 Series] + +pci:v00001002d0000AA88* + ID_MODEL_FROM_DATABASE=Barts HDMI Audio [Radeon HD 6800 Series] + +pci:v00001002d0000AA90* + ID_MODEL_FROM_DATABASE=Turks/Whistler HDMI Audio [Radeon HD 6000 Series] + +pci:v00001002d0000AA90sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001002d0000AA98* + ID_MODEL_FROM_DATABASE=Caicos HDMI Audio [Radeon HD 6400 Series] + +pci:v00001002d0000AA98sv0000174Bsd0000AA98* + ID_MODEL_FROM_DATABASE=Radeon HD 6450 1GB DDR3 + +pci:v00001002d0000AAA0* + ID_MODEL_FROM_DATABASE=Tahiti XT HDMI Audio [Radeon HD 7970 Series] + +pci:v00001002d0000AAB0* + ID_MODEL_FROM_DATABASE=Cape Verde/Pitcairn HDMI Audio [Radeon HD 7700/7800 Series] + +pci:v00001002d0000AC00* + ID_MODEL_FROM_DATABASE=Theater 600 Pro + +pci:v00001002d0000AC02* + ID_MODEL_FROM_DATABASE=TV Wonder HD 600 PCIe + +pci:v00001002d0000AC12* + ID_MODEL_FROM_DATABASE=Theater HD T507 (DVB-T) TV tuner/capture device + +pci:v00001002d0000CAB0* + ID_MODEL_FROM_DATABASE=RS100 Host Bridge + +pci:v00001002d0000CAB2* + ID_MODEL_FROM_DATABASE=RS200 Host Bridge + +pci:v00001002d0000CAB3* + ID_MODEL_FROM_DATABASE=RS250 Host Bridge + +pci:v00001002d0000CBB2* + ID_MODEL_FROM_DATABASE=RS200 Host Bridge + +pci:v00001003* + ID_VENDOR_FROM_DATABASE=ULSI Systems + +pci:v00001003d00000201* + ID_MODEL_FROM_DATABASE=US201 + +pci:v00001004* + ID_VENDOR_FROM_DATABASE=VLSI Technology Inc + +pci:v00001004d00000005* + ID_MODEL_FROM_DATABASE=82C592-FC1 + +pci:v00001004d00000006* + ID_MODEL_FROM_DATABASE=82C593-FC1 + +pci:v00001004d00000007* + ID_MODEL_FROM_DATABASE=82C594-AFC2 + +pci:v00001004d00000008* + ID_MODEL_FROM_DATABASE=82C596/7 [Wildcat] + +pci:v00001004d00000009* + ID_MODEL_FROM_DATABASE=82C597-AFC2 + +pci:v00001004d0000000C* + ID_MODEL_FROM_DATABASE=82C541 [Lynx] + +pci:v00001004d0000000D* + ID_MODEL_FROM_DATABASE=82C543 [Lynx] + +pci:v00001004d00000101* + ID_MODEL_FROM_DATABASE=82C532 + +pci:v00001004d00000102* + ID_MODEL_FROM_DATABASE=82C534 [Eagle] + +pci:v00001004d00000103* + ID_MODEL_FROM_DATABASE=82C538 + +pci:v00001004d00000104* + ID_MODEL_FROM_DATABASE=82C535 + +pci:v00001004d00000105* + ID_MODEL_FROM_DATABASE=82C147 + +pci:v00001004d00000200* + ID_MODEL_FROM_DATABASE=82C975 + +pci:v00001004d00000280* + ID_MODEL_FROM_DATABASE=82C925 + +pci:v00001004d00000304* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio + +pci:v00001004d00000304sv00001004sd00000304* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio + +pci:v00001004d00000304sv0000122Dsd00001206* + ID_MODEL_FROM_DATABASE=DSP368 Audio + +pci:v00001004d00000304sv00001483sd00005020* + ID_MODEL_FROM_DATABASE=XWave Thunder 3D Audio + +pci:v00001004d00000305* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio Gameport + +pci:v00001004d00000305sv00001004sd00000305* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio Gameport + +pci:v00001004d00000305sv0000122Dsd00001207* + ID_MODEL_FROM_DATABASE=DSP368 Audio Gameport + +pci:v00001004d00000305sv00001483sd00005021* + ID_MODEL_FROM_DATABASE=XWave Thunder 3D Audio Gameport + +pci:v00001004d00000306* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio Support Registers + +pci:v00001004d00000306sv00001004sd00000306* + ID_MODEL_FROM_DATABASE=QSound ThunderBird PCI Audio Support Registers + +pci:v00001004d00000306sv0000122Dsd00001208* + ID_MODEL_FROM_DATABASE=DSP368 Audio Support Registers + +pci:v00001004d00000306sv00001483sd00005022* + ID_MODEL_FROM_DATABASE=XWave Thunder 3D Audio Support Registers + +pci:v00001004d00000307* + ID_MODEL_FROM_DATABASE=SAA7785 ThunderBird PCI Audio + +pci:v00001004d00000307sv00001004sd00000703* + ID_MODEL_FROM_DATABASE=Philips Rhythmic Edge PSC703 + +pci:v00001004d00000307sv00001004sd00000705* + ID_MODEL_FROM_DATABASE=Philips Seismic Edge PSC705 + +pci:v00001004d00000307sv00001004sd00000706* + ID_MODEL_FROM_DATABASE=Philips Acoustic Edge PSC706 + +pci:v00001004d00000308* + ID_MODEL_FROM_DATABASE=SAA7785 ThunderBird PCI Audio Gameport + +pci:v00001004d00000702* + ID_MODEL_FROM_DATABASE=VAS96011 [Golden Gate II] + +pci:v00001004d00000703* + ID_MODEL_FROM_DATABASE=Tollgate + +pci:v00001005* + ID_VENDOR_FROM_DATABASE=Avance Logic Inc. [ALI] + +pci:v00001005d00002064* + ID_MODEL_FROM_DATABASE=ALG2032/2064 + +pci:v00001005d00002128* + ID_MODEL_FROM_DATABASE=ALG2364A + +pci:v00001005d00002301* + ID_MODEL_FROM_DATABASE=ALG2301 + +pci:v00001005d00002302* + ID_MODEL_FROM_DATABASE=ALG2302 + +pci:v00001005d00002364* + ID_MODEL_FROM_DATABASE=ALG2364 + +pci:v00001005d00002464* + ID_MODEL_FROM_DATABASE=ALG2364A + +pci:v00001005d00002501* + ID_MODEL_FROM_DATABASE=ALG2564A/25128A + +pci:v00001006* + ID_VENDOR_FROM_DATABASE=Reply Group + +pci:v00001007* + ID_VENDOR_FROM_DATABASE=NetFrame Systems Inc + +pci:v00001008* + ID_VENDOR_FROM_DATABASE=Epson + +pci:v0000100A* + ID_VENDOR_FROM_DATABASE=Phoenix Technologies + +pci:v0000100B* + ID_VENDOR_FROM_DATABASE=National Semiconductor Corporation + +pci:v0000100Bd00000001* + ID_MODEL_FROM_DATABASE=DP83810 + +pci:v0000100Bd00000002* + ID_MODEL_FROM_DATABASE=87415/87560 IDE + +pci:v0000100Bd0000000E* + ID_MODEL_FROM_DATABASE=87560 Legacy I/O + +pci:v0000100Bd0000000F* + ID_MODEL_FROM_DATABASE=FireWire Controller + +pci:v0000100Bd00000011* + ID_MODEL_FROM_DATABASE=NS87560 National PCI System I/O + +pci:v0000100Bd00000012* + ID_MODEL_FROM_DATABASE=USB Controller + +pci:v0000100Bd00000020* + ID_MODEL_FROM_DATABASE=DP83815 (MacPhyter) Ethernet Controller + +pci:v0000100Bd00000020sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin Network + +pci:v0000100Bd00000020sv000012D9sd0000000C* + ID_MODEL_FROM_DATABASE=Aculab E1/T1 PMXc cPCI carrier card + +pci:v0000100Bd00000020sv00001385sd0000F311* + ID_MODEL_FROM_DATABASE=FA311 / FA312 (FA311 with WoL HW) + +pci:v0000100Bd00000020sv00001385sd0000F312* + ID_MODEL_FROM_DATABASE=FA312 (rev. A1) Fast Ethernet PCI Adapter + +pci:v0000100Bd00000021* + ID_MODEL_FROM_DATABASE=PC87200 PCI to ISA Bridge + +pci:v0000100Bd00000022* + ID_MODEL_FROM_DATABASE=DP83820 10/100/1000 Ethernet Controller + +pci:v0000100Bd00000022sv00001186sd00004900* + ID_MODEL_FROM_DATABASE=DGE-500T + +pci:v0000100Bd00000022sv00001385sd0000621A* + ID_MODEL_FROM_DATABASE=GA621 + +pci:v0000100Bd00000022sv00001385sd0000622A* + ID_MODEL_FROM_DATABASE=GA622T + +pci:v0000100Bd00000028* + ID_MODEL_FROM_DATABASE=Geode GX2 Host Bridge + +pci:v0000100Bd0000002A* + ID_MODEL_FROM_DATABASE=CS5535 South Bridge + +pci:v0000100Bd0000002B* + ID_MODEL_FROM_DATABASE=CS5535 ISA bridge + +pci:v0000100Bd0000002D* + ID_MODEL_FROM_DATABASE=CS5535 IDE + +pci:v0000100Bd0000002E* + ID_MODEL_FROM_DATABASE=CS5535 Audio + +pci:v0000100Bd0000002F* + ID_MODEL_FROM_DATABASE=CS5535 USB + +pci:v0000100Bd00000030* + ID_MODEL_FROM_DATABASE=Geode GX2 Graphics Processor + +pci:v0000100Bd00000035* + ID_MODEL_FROM_DATABASE=DP83065 [Saturn] 10/100/1000 Ethernet Controller + +pci:v0000100Bd00000500* + ID_MODEL_FROM_DATABASE=SCx200 Bridge + +pci:v0000100Bd00000501* + ID_MODEL_FROM_DATABASE=SCx200 SMI + +pci:v0000100Bd00000502* + ID_MODEL_FROM_DATABASE=SCx200, SC1100 IDE controller + +pci:v0000100Bd00000502sv0000100Bsd00000502* + ID_MODEL_FROM_DATABASE=IDE Controller + +pci:v0000100Bd00000503* + ID_MODEL_FROM_DATABASE=SCx200, SC1100 Audio Controller + +pci:v0000100Bd00000503sv0000100Bsd00000503* + ID_MODEL_FROM_DATABASE=XpressAudio controller + +pci:v0000100Bd00000504* + ID_MODEL_FROM_DATABASE=SCx200 Video + +pci:v0000100Bd00000505* + ID_MODEL_FROM_DATABASE=SCx200 XBus + +pci:v0000100Bd00000510* + ID_MODEL_FROM_DATABASE=SC1100 Bridge + +pci:v0000100Bd00000510sv0000100Bsd00000500* + ID_MODEL_FROM_DATABASE=GPIO and LPC support bridge + +pci:v0000100Bd00000511* + ID_MODEL_FROM_DATABASE=SC1100 SMI & ACPI + +pci:v0000100Bd00000511sv0000100Bsd00000501* + ID_MODEL_FROM_DATABASE=SC1100 SMI & ACPI bridge + +pci:v0000100Bd00000515* + ID_MODEL_FROM_DATABASE=SC1100 XBus + +pci:v0000100Bd00000515sv0000100Bsd00000505* + ID_MODEL_FROM_DATABASE=SC1100 PCI to XBus bridge + +pci:v0000100Bd0000D001* + ID_MODEL_FROM_DATABASE=87410 IDE + +pci:v0000100C* + ID_VENDOR_FROM_DATABASE=Tseng Labs Inc + +pci:v0000100Cd00003202* + ID_MODEL_FROM_DATABASE=ET4000/W32p rev A + +pci:v0000100Cd00003205* + ID_MODEL_FROM_DATABASE=ET4000/W32p rev B + +pci:v0000100Cd00003206* + ID_MODEL_FROM_DATABASE=ET4000/W32p rev C + +pci:v0000100Cd00003207* + ID_MODEL_FROM_DATABASE=ET4000/W32p rev D + +pci:v0000100Cd00003208* + ID_MODEL_FROM_DATABASE=ET6000 + +pci:v0000100Cd00004702* + ID_MODEL_FROM_DATABASE=ET6300 + +pci:v0000100D* + ID_VENDOR_FROM_DATABASE=AST Research Inc + +pci:v0000100E* + ID_VENDOR_FROM_DATABASE=Weitek + +pci:v0000100Ed00009000* + ID_MODEL_FROM_DATABASE=P9000 Viper + +pci:v0000100Ed00009001* + ID_MODEL_FROM_DATABASE=P9000 Viper + +pci:v0000100Ed00009002* + ID_MODEL_FROM_DATABASE=P9000 Viper + +pci:v0000100Ed00009100* + ID_MODEL_FROM_DATABASE=P9100 Viper Pro/SE + +pci:v00001010* + ID_VENDOR_FROM_DATABASE=Video Logic, Ltd. + +pci:v00001011* + ID_VENDOR_FROM_DATABASE=Digital Equipment Corporation + +pci:v00001011d00000001* + ID_MODEL_FROM_DATABASE=DECchip 21050 + +pci:v00001011d00000002* + ID_MODEL_FROM_DATABASE=DECchip 21040 [Tulip] + +pci:v00001011d00000004* + ID_MODEL_FROM_DATABASE=DECchip 21030 [TGA] + +pci:v00001011d00000007* + ID_MODEL_FROM_DATABASE=NVRAM [Zephyr NVRAM] + +pci:v00001011d00000008* + ID_MODEL_FROM_DATABASE=KZPSA [KZPSA] + +pci:v00001011d00000009* + ID_MODEL_FROM_DATABASE=DECchip 21140 [FasterNet] + +pci:v00001011d00000009sv00001025sd00000310* + ID_MODEL_FROM_DATABASE=21140 Fast Ethernet + +pci:v00001011d00000009sv000010B8sd00002001* + ID_MODEL_FROM_DATABASE=SMC9332BDT EtherPower 10/100 + +pci:v00001011d00000009sv000010B8sd00002002* + ID_MODEL_FROM_DATABASE=SMC9332BVT EtherPower T4 10/100 + +pci:v00001011d00000009sv000010B8sd00002003* + ID_MODEL_FROM_DATABASE=SMC9334BDT EtherPower 10/100 (1-port) + +pci:v00001011d00000009sv00001109sd00002400* + ID_MODEL_FROM_DATABASE=ANA-6944A/TX Fast Ethernet + +pci:v00001011d00000009sv00001112sd00002300* + ID_MODEL_FROM_DATABASE=RNS2300 Fast Ethernet + +pci:v00001011d00000009sv00001112sd00002320* + ID_MODEL_FROM_DATABASE=RNS2320 Fast Ethernet + +pci:v00001011d00000009sv00001112sd00002340* + ID_MODEL_FROM_DATABASE=RNS2340 Fast Ethernet + +pci:v00001011d00000009sv00001113sd00001207* + ID_MODEL_FROM_DATABASE=EN-1207-TX Fast Ethernet + +pci:v00001011d00000009sv00001186sd00001100* + ID_MODEL_FROM_DATABASE=DFE-500TX Fast Ethernet + +pci:v00001011d00000009sv00001186sd00001112* + ID_MODEL_FROM_DATABASE=DFE-570TX Fast Ethernet + +pci:v00001011d00000009sv00001186sd00001140* + ID_MODEL_FROM_DATABASE=DFE-660 Cardbus Ethernet 10/100 + +pci:v00001011d00000009sv00001186sd00001142* + ID_MODEL_FROM_DATABASE=DFE-660 Cardbus Ethernet 10/100 + +pci:v00001011d00000009sv000011F6sd00000503* + ID_MODEL_FROM_DATABASE=Freedomline Fast Ethernet + +pci:v00001011d00000009sv00001282sd00009100* + ID_MODEL_FROM_DATABASE=AEF-380TXD Fast Ethernet + +pci:v00001011d00000009sv00001385sd00001100* + ID_MODEL_FROM_DATABASE=FA310TX Fast Ethernet + +pci:v00001011d00000009sv00002646sd00000001* + ID_MODEL_FROM_DATABASE=KNE100TX Fast Ethernet + +pci:v00001011d0000000A* + ID_MODEL_FROM_DATABASE=21230 Video Codec + +pci:v00001011d0000000D* + ID_MODEL_FROM_DATABASE=PBXGB [TGA2] + +pci:v00001011d0000000F* + ID_MODEL_FROM_DATABASE=PCI-to-PDQ Interface Chip [PFI] + +pci:v00001011d0000000Fsv00001011sd0000DEF1* + ID_MODEL_FROM_DATABASE=FDDI controller (DEFPA) + +pci:v00001011d0000000Fsv0000103Csd0000DEF1* + ID_MODEL_FROM_DATABASE=FDDI controller (3X-DEFPA) + +pci:v00001011d00000014* + ID_MODEL_FROM_DATABASE=DECchip 21041 [Tulip Pass 3] + +pci:v00001011d00000014sv00001186sd00000100* + ID_MODEL_FROM_DATABASE=DE-530+ + +pci:v00001011d00000016* + ID_MODEL_FROM_DATABASE=DGLPB [OPPO] + +pci:v00001011d00000017* + ID_MODEL_FROM_DATABASE=PV-PCI Graphics Controller (ZLXp-L) + +pci:v00001011d00000018* + ID_MODEL_FROM_DATABASE=Memory Channel interface + +pci:v00001011d00000019* + ID_MODEL_FROM_DATABASE=DECchip 21142/43 + +pci:v00001011d00000019sv00001011sd0000500A* + ID_MODEL_FROM_DATABASE=DE500A Fast Ethernet + +pci:v00001011d00000019sv00001011sd0000500B* + ID_MODEL_FROM_DATABASE=DE500B Fast Ethernet + +pci:v00001011d00000019sv00001014sd00000001* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus + +pci:v00001011d00000019sv00001025sd00000315* + ID_MODEL_FROM_DATABASE=ALN315 Fast Ethernet + +pci:v00001011d00000019sv00001033sd0000800C* + ID_MODEL_FROM_DATABASE=PC-9821-CS01 100BASE-TX Interface Card + +pci:v00001011d00000019sv00001033sd0000800D* + ID_MODEL_FROM_DATABASE=PC-9821NR-B06 100BASE-TX Interface Card + +pci:v00001011d00000019sv0000103Csd0000125A* + ID_MODEL_FROM_DATABASE=10/100Base-TX (PCI) [A5506B] + +pci:v00001011d00000019sv0000108Dsd00000016* + ID_MODEL_FROM_DATABASE=Rapidfire 2327 10/100 Ethernet + +pci:v00001011d00000019sv0000108Dsd00000017* + ID_MODEL_FROM_DATABASE=GoCard 2250 Ethernet 10/100 Cardbus + +pci:v00001011d00000019sv000010B8sd00002005* + ID_MODEL_FROM_DATABASE=SMC8032DT Extreme Ethernet 10/100 + +pci:v00001011d00000019sv000010B8sd00008034* + ID_MODEL_FROM_DATABASE=SMC8034 Extreme Ethernet 10/100 + +pci:v00001011d00000019sv000010EFsd00008169* + ID_MODEL_FROM_DATABASE=Cardbus Fast Ethernet + +pci:v00001011d00000019sv00001109sd00002A00* + ID_MODEL_FROM_DATABASE=ANA-6911A/TX Fast Ethernet + +pci:v00001011d00000019sv00001109sd00002B00* + ID_MODEL_FROM_DATABASE=ANA-6911A/TXC Fast Ethernet + +pci:v00001011d00000019sv00001109sd00003000* + ID_MODEL_FROM_DATABASE=ANA-6922/TX Fast Ethernet + +pci:v00001011d00000019sv00001113sd00001207* + ID_MODEL_FROM_DATABASE=Cheetah Fast Ethernet + +pci:v00001011d00000019sv00001113sd00002220* + ID_MODEL_FROM_DATABASE=Cardbus Fast Ethernet + +pci:v00001011d00000019sv0000115Dsd00000002* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v00001011d00000019sv00001179sd00000203* + ID_MODEL_FROM_DATABASE=Fast Ethernet + +pci:v00001011d00000019sv00001179sd00000204* + ID_MODEL_FROM_DATABASE=Cardbus Fast Ethernet + +pci:v00001011d00000019sv00001186sd00001100* + ID_MODEL_FROM_DATABASE=DFE-500TX Fast Ethernet + +pci:v00001011d00000019sv00001186sd00001101* + ID_MODEL_FROM_DATABASE=DFE-500TX Fast Ethernet + +pci:v00001011d00000019sv00001186sd00001102* + ID_MODEL_FROM_DATABASE=DFE-500TX Fast Ethernet + +pci:v00001011d00000019sv00001186sd00001112* + ID_MODEL_FROM_DATABASE=DFE-570TX Quad Fast Ethernet + +pci:v00001011d00000019sv00001259sd00002800* + ID_MODEL_FROM_DATABASE=AT-2800Tx Fast Ethernet + +pci:v00001011d00000019sv00001266sd00000004* + ID_MODEL_FROM_DATABASE=Eagle Fast EtherMAX + +pci:v00001011d00000019sv000012AFsd00000019* + ID_MODEL_FROM_DATABASE=NetFlyer Cardbus Fast Ethernet + +pci:v00001011d00000019sv00001374sd00000001* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet Card 10/100 + +pci:v00001011d00000019sv00001374sd00000002* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet Card 10/100 + +pci:v00001011d00000019sv00001374sd00000007* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet Card 10/100 + +pci:v00001011d00000019sv00001374sd00000008* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet Card 10/100 + +pci:v00001011d00000019sv00001385sd00002100* + ID_MODEL_FROM_DATABASE=FA510 + +pci:v00001011d00000019sv00001395sd00000001* + ID_MODEL_FROM_DATABASE=10/100 Ethernet CardBus PC Card + +pci:v00001011d00000019sv000013D1sd0000AB01* + ID_MODEL_FROM_DATABASE=EtherFast 10/100 Cardbus (PCMPC200) + +pci:v00001011d00000019sv00001498sd0000000A* + ID_MODEL_FROM_DATABASE=TPMC880-10 10/100Base-T and 10Base2 PMC Ethernet Adapter + +pci:v00001011d00000019sv00001498sd0000000B* + ID_MODEL_FROM_DATABASE=TPMC880-11 Single 10/100Base-T PMC Ethernet Adapter + +pci:v00001011d00000019sv00001498sd0000000C* + ID_MODEL_FROM_DATABASE=TPMC880-12 Single 10Base2 PMC Ethernet Adapter + +pci:v00001011d00000019sv000014CBsd00000100* + ID_MODEL_FROM_DATABASE=LNDL-100N 100Base-TX Ethernet PC Card + +pci:v00001011d00000019sv00001668sd00002000* + ID_MODEL_FROM_DATABASE=FastNet Pro (PE2000) + +pci:v00001011d00000019sv00002646sd00000001* + ID_MODEL_FROM_DATABASE=KNE100TX + +pci:v00001011d00000019sv00002646sd00000002* + ID_MODEL_FROM_DATABASE=KNE-CB4TX + +pci:v00001011d00000019sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Mobile CardBus 32 + +pci:v00001011d0000001A* + ID_MODEL_FROM_DATABASE=Farallon PN9000SX Gigabit Ethernet + +pci:v00001011d00000021* + ID_MODEL_FROM_DATABASE=DECchip 21052 + +pci:v00001011d00000022* + ID_MODEL_FROM_DATABASE=DECchip 21150 + +pci:v00001011d00000023* + ID_MODEL_FROM_DATABASE=DECchip 21150 + +pci:v00001011d00000024* + ID_MODEL_FROM_DATABASE=DECchip 21152 + +pci:v00001011d00000025* + ID_MODEL_FROM_DATABASE=DECchip 21153 + +pci:v00001011d00000026* + ID_MODEL_FROM_DATABASE=DECchip 21154 + +pci:v00001011d00000034* + ID_MODEL_FROM_DATABASE=56k Modem Cardbus + +pci:v00001011d00000034sv00001374sd00000003* + ID_MODEL_FROM_DATABASE=56k Modem Cardbus + +pci:v00001011d00000045* + ID_MODEL_FROM_DATABASE=DECchip 21553 + +pci:v00001011d00000046* + ID_MODEL_FROM_DATABASE=DECchip 21554 + +pci:v00001011d00000046sv00000E11sd00004050* + ID_MODEL_FROM_DATABASE=Smart Array 4200 Controller + +pci:v00001011d00000046sv00000E11sd00004051* + ID_MODEL_FROM_DATABASE=Smart Array 4250ES Controller + +pci:v00001011d00000046sv00000E11sd00004058* + ID_MODEL_FROM_DATABASE=Smart Array 431 Controller + +pci:v00001011d00000046sv0000103Csd000010C2* + ID_MODEL_FROM_DATABASE=NetRAID-4M + +pci:v00001011d00000046sv000012D9sd0000000A* + ID_MODEL_FROM_DATABASE=IP Telephony card + +pci:v00001011d00000046sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00001011d00000046sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v00001011d00000046sv00009005sd00000364* + ID_MODEL_FROM_DATABASE=5400S (Mustang) + +pci:v00001011d00000046sv00009005sd00000365* + ID_MODEL_FROM_DATABASE=5400S (Mustang) + +pci:v00001011d00000046sv00009005sd00001364* + ID_MODEL_FROM_DATABASE=Dell PowerEdge RAID Controller 2 + +pci:v00001011d00000046sv00009005sd00001365* + ID_MODEL_FROM_DATABASE=Dell PowerEdge RAID Controller 2 + +pci:v00001011d00000046sv0000E4BFsd00001000* + ID_MODEL_FROM_DATABASE=CC8-1-BLUES + +pci:v00001011d00001065* + ID_MODEL_FROM_DATABASE=StrongARM DC21285 + +pci:v00001011d00001065sv00001069sd00000020* + ID_MODEL_FROM_DATABASE=DAC960P / DAC1164P + +pci:v00001012* + ID_VENDOR_FROM_DATABASE=Micronics Computers Inc + +pci:v00001013* + ID_VENDOR_FROM_DATABASE=Cirrus Logic + +pci:v00001013d00000038* + ID_MODEL_FROM_DATABASE=GD 7548 + +pci:v00001013d00000040* + ID_MODEL_FROM_DATABASE=GD 7555 Flat Panel GUI Accelerator + +pci:v00001013d0000004C* + ID_MODEL_FROM_DATABASE=GD 7556 Video/Graphics LCD/CRT Ctrlr + +pci:v00001013d000000A0* + ID_MODEL_FROM_DATABASE=GD 5430/40 [Alpine] + +pci:v00001013d000000A2* + ID_MODEL_FROM_DATABASE=GD 5432 [Alpine] + +pci:v00001013d000000A4* + ID_MODEL_FROM_DATABASE=GD 5434-4 [Alpine] + +pci:v00001013d000000A8* + ID_MODEL_FROM_DATABASE=GD 5434-8 [Alpine] + +pci:v00001013d000000AC* + ID_MODEL_FROM_DATABASE=GD 5436 [Alpine] + +pci:v00001013d000000B0* + ID_MODEL_FROM_DATABASE=GD 5440 + +pci:v00001013d000000B8* + ID_MODEL_FROM_DATABASE=GD 5446 + +pci:v00001013d000000BC* + ID_MODEL_FROM_DATABASE=GD 5480 + +pci:v00001013d000000BCsv00001013sd000000BC* + ID_MODEL_FROM_DATABASE=CL-GD5480 + +pci:v00001013d000000D0* + ID_MODEL_FROM_DATABASE=GD 5462 + +pci:v00001013d000000D2* + ID_MODEL_FROM_DATABASE=GD 5462 [Laguna I] + +pci:v00001013d000000D4* + ID_MODEL_FROM_DATABASE=GD 5464 [Laguna] + +pci:v00001013d000000D5* + ID_MODEL_FROM_DATABASE=GD 5464 BD [Laguna] + +pci:v00001013d000000D6* + ID_MODEL_FROM_DATABASE=GD 5465 [Laguna] + +pci:v00001013d000000D6sv000013CEsd00008031* + ID_MODEL_FROM_DATABASE=Barco Metheus 2 Megapixel, Dual Head + +pci:v00001013d000000D6sv000013CFsd00008031* + ID_MODEL_FROM_DATABASE=Barco Metheus 2 Megapixel, Dual Head + +pci:v00001013d000000E8* + ID_MODEL_FROM_DATABASE=GD 5436U + +pci:v00001013d00001100* + ID_MODEL_FROM_DATABASE=CL 6729 + +pci:v00001013d00001110* + ID_MODEL_FROM_DATABASE=PD 6832 PCMCIA/CardBus Ctrlr + +pci:v00001013d00001112* + ID_MODEL_FROM_DATABASE=PD 6834 PCMCIA/CardBus Ctrlr + +pci:v00001013d00001113* + ID_MODEL_FROM_DATABASE=PD 6833 PCMCIA/CardBus Ctrlr + +pci:v00001013d00001200* + ID_MODEL_FROM_DATABASE=GD 7542 [Nordic] + +pci:v00001013d00001202* + ID_MODEL_FROM_DATABASE=GD 7543 [Viking] + +pci:v00001013d00001204* + ID_MODEL_FROM_DATABASE=GD 7541 [Nordic Light] + +pci:v00001013d00004000* + ID_MODEL_FROM_DATABASE=MD 5620 [CLM Data Fax Voice] + +pci:v00001013d00004400* + ID_MODEL_FROM_DATABASE=CD 4400 + +pci:v00001013d00006001* + ID_MODEL_FROM_DATABASE=CS 4610/11 [CrystalClear SoundFusion Audio Accelerator] + +pci:v00001013d00006001sv00001014sd00001010* + ID_MODEL_FROM_DATABASE=CS4610 SoundFusion Audio Accelerator + +pci:v00001013d00006003* + ID_MODEL_FROM_DATABASE=CS 4614/22/24/30 [CrystalClear SoundFusion Audio Accelerator] + +pci:v00001013d00006003sv00001013sd00004280* + ID_MODEL_FROM_DATABASE=Crystal SoundFusion PCI Audio Accelerator + +pci:v00001013d00006003sv00001014sd00000153* + ID_MODEL_FROM_DATABASE=ThinkPad 600X/A20m + +pci:v00001013d00006003sv0000153Bsd0000112E* + ID_MODEL_FROM_DATABASE=DMX XFire 1024 + +pci:v00001013d00006003sv0000153Bsd00001136* + ID_MODEL_FROM_DATABASE=SiXPack 5.1+ + +pci:v00001013d00006003sv00001681sd00000050* + ID_MODEL_FROM_DATABASE=Game Theater XP + +pci:v00001013d00006003sv00001681sd0000A010* + ID_MODEL_FROM_DATABASE=Gamesurround Fortissimo II + +pci:v00001013d00006003sv00001681sd0000A011* + ID_MODEL_FROM_DATABASE=Gamesurround Fortissimo III 7.1 + +pci:v00001013d00006003sv00005053sd00003357* + ID_MODEL_FROM_DATABASE=Santa Cruz + +pci:v00001013d00006004* + ID_MODEL_FROM_DATABASE=CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator] + +pci:v00001013d00006005* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv00001013sd00004281* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010A8* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010A9* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010AA* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010AB* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010AC* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010AD* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000010CFsd000010B4* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001013d00006005sv000014C0sd0000000C* + ID_MODEL_FROM_DATABASE=Crystal CS4281 PCI Audio + +pci:v00001014* + ID_VENDOR_FROM_DATABASE=IBM + +pci:v00001014d00000002* + ID_MODEL_FROM_DATABASE=PCI to MCA Bridge + +pci:v00001014d00000005* + ID_MODEL_FROM_DATABASE=Processor to I/O Controller [Alta Lite] + +pci:v00001014d00000007* + ID_MODEL_FROM_DATABASE=Processor to I/O Controller [Alta MP] + +pci:v00001014d0000000A* + ID_MODEL_FROM_DATABASE=PCI to ISA Bridge (IBM27-82376) [Fire Coral] + +pci:v00001014d00000017* + ID_MODEL_FROM_DATABASE=CPU to PCI Bridge + +pci:v00001014d00000018* + ID_MODEL_FROM_DATABASE=TR Auto LANstreamer + +pci:v00001014d0000001B* + ID_MODEL_FROM_DATABASE=GXT-150P + +pci:v00001014d0000001C* + ID_MODEL_FROM_DATABASE=Carrera + +pci:v00001014d0000001D* + ID_MODEL_FROM_DATABASE=SCSI-2 FAST PCI Adapter (82G2675) + +pci:v00001014d00000020* + ID_MODEL_FROM_DATABASE=GXT1000 Graphics Adapter + +pci:v00001014d00000022* + ID_MODEL_FROM_DATABASE=PCI to PCI Bridge (IBM27-82351) + +pci:v00001014d0000002D* + ID_MODEL_FROM_DATABASE=Processor to I/O Controller [Python] + +pci:v00001014d0000002E* + ID_MODEL_FROM_DATABASE=SCSI RAID Adapter [ServeRAID] + +pci:v00001014d0000002Esv00001014sd0000002E* + ID_MODEL_FROM_DATABASE=ServeRAID-3x + +pci:v00001014d0000002Esv00001014sd0000022E* + ID_MODEL_FROM_DATABASE=ServeRAID-4H + +pci:v00001014d00000031* + ID_MODEL_FROM_DATABASE=2 Port Serial Adapter + +pci:v00001014d00000031sv00001014sd00000031* + ID_MODEL_FROM_DATABASE=2721 WAN IOA - 2 Port Sync Serial Adapter + +pci:v00001014d00000036* + ID_MODEL_FROM_DATABASE=PCI to 32-bit LocalBus Bridge [Miami] + +pci:v00001014d00000037* + ID_MODEL_FROM_DATABASE=PowerPC to PCI Bridge (IBM27-82660) + +pci:v00001014d0000003A* + ID_MODEL_FROM_DATABASE=CPU to PCI Bridge + +pci:v00001014d0000003C* + ID_MODEL_FROM_DATABASE=GXT250P/GXT255P Graphics Adapter + +pci:v00001014d0000003E* + ID_MODEL_FROM_DATABASE=16/4 Token ring UTP/STP controller + +pci:v00001014d0000003Esv00001014sd0000003E* + ID_MODEL_FROM_DATABASE=Token-Ring Adapter + +pci:v00001014d0000003Esv00001014sd000000CD* + ID_MODEL_FROM_DATABASE=Token-Ring Adapter + Wake-On-LAN + +pci:v00001014d0000003Esv00001014sd000000CE* + ID_MODEL_FROM_DATABASE=16/4 Token-Ring Adapter 2 + +pci:v00001014d0000003Esv00001014sd000000CF* + ID_MODEL_FROM_DATABASE=16/4 Token-Ring Adapter Special + +pci:v00001014d0000003Esv00001014sd000000E4* + ID_MODEL_FROM_DATABASE=High-Speed 100/16/4 Token-Ring Adapter + +pci:v00001014d0000003Esv00001014sd000000E5* + ID_MODEL_FROM_DATABASE=16/4 Token-Ring Adapter 2 + Wake-On-LAN + +pci:v00001014d0000003Esv00001014sd0000016D* + ID_MODEL_FROM_DATABASE=iSeries 2744 Card + +pci:v00001014d00000045* + ID_MODEL_FROM_DATABASE=SSA Adapter + +pci:v00001014d00000046* + ID_MODEL_FROM_DATABASE=MPIC interrupt controller + +pci:v00001014d00000047* + ID_MODEL_FROM_DATABASE=PCI to PCI Bridge + +pci:v00001014d00000048* + ID_MODEL_FROM_DATABASE=PCI to PCI Bridge + +pci:v00001014d00000049* + ID_MODEL_FROM_DATABASE=Warhead SCSI Controller + +pci:v00001014d0000004E* + ID_MODEL_FROM_DATABASE=ATM Controller (14104e00) + +pci:v00001014d0000004F* + ID_MODEL_FROM_DATABASE=ATM Controller (14104f00) + +pci:v00001014d00000050* + ID_MODEL_FROM_DATABASE=ATM Controller (14105000) + +pci:v00001014d00000053* + ID_MODEL_FROM_DATABASE=25 MBit ATM Controller + +pci:v00001014d00000054* + ID_MODEL_FROM_DATABASE=GXT500P/GXT550P Graphics Adapter + +pci:v00001014d00000057* + ID_MODEL_FROM_DATABASE=MPEG PCI Bridge + +pci:v00001014d00000058* + ID_MODEL_FROM_DATABASE=SSA Adapter [Advanced SerialRAID/X] + +pci:v00001014d0000005E* + ID_MODEL_FROM_DATABASE=GXT800P Graphics Adapter + +pci:v00001014d0000007C* + ID_MODEL_FROM_DATABASE=ATM Controller (14107c00) + +pci:v00001014d0000007D* + ID_MODEL_FROM_DATABASE=3780IDSP [MWave] + +pci:v00001014d0000008B* + ID_MODEL_FROM_DATABASE=EADS PCI to PCI Bridge + +pci:v00001014d0000008E* + ID_MODEL_FROM_DATABASE=GXT3000P Graphics Adapter + +pci:v00001014d00000090* + ID_MODEL_FROM_DATABASE=GXT 3000P + +pci:v00001014d00000090sv00001014sd0000008E* + ID_MODEL_FROM_DATABASE=GXT-3000P + +pci:v00001014d00000091* + ID_MODEL_FROM_DATABASE=SSA Adapter + +pci:v00001014d00000095* + ID_MODEL_FROM_DATABASE=20H2999 PCI Docking Bridge + +pci:v00001014d00000096* + ID_MODEL_FROM_DATABASE=Chukar chipset SCSI controller + +pci:v00001014d00000096sv00001014sd00000097* + ID_MODEL_FROM_DATABASE=iSeries 2778 DASD IOA + +pci:v00001014d00000096sv00001014sd00000098* + ID_MODEL_FROM_DATABASE=iSeries 2763 DASD IOA + +pci:v00001014d00000096sv00001014sd00000099* + ID_MODEL_FROM_DATABASE=iSeries 2748 DASD IOA + +pci:v00001014d0000009F* + ID_MODEL_FROM_DATABASE=PCI 4758 Cryptographic Accelerator + +pci:v00001014d000000A5* + ID_MODEL_FROM_DATABASE=ATM Controller (1410a500) + +pci:v00001014d000000A6* + ID_MODEL_FROM_DATABASE=ATM 155MBPS MM Controller (1410a600) + +pci:v00001014d000000B7* + ID_MODEL_FROM_DATABASE=256-bit Graphics Rasterizer [FireGL1] + +pci:v00001014d000000B7sv00001092sd000000B8* + ID_MODEL_FROM_DATABASE=FireGL1 AGP 32Mb + +pci:v00001014d000000B8* + ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter + +pci:v00001014d000000BE* + ID_MODEL_FROM_DATABASE=ATM 622MBPS Controller (1410be00) + +pci:v00001014d000000DC* + ID_MODEL_FROM_DATABASE=Advanced Systems Management Adapter (ASMA) + +pci:v00001014d000000FC* + ID_MODEL_FROM_DATABASE=CPC710 Dual Bridge and Memory Controller (PCI-64) + +pci:v00001014d00000105* + ID_MODEL_FROM_DATABASE=CPC710 Dual Bridge and Memory Controller (PCI-32) + +pci:v00001014d0000010F* + ID_MODEL_FROM_DATABASE=Remote Supervisor Adapter (RSA) + +pci:v00001014d00000142* + ID_MODEL_FROM_DATABASE=Yotta Video Compositor Input + +pci:v00001014d00000142sv00001014sd00000143* + ID_MODEL_FROM_DATABASE=Yotta Input Controller (ytin) + +pci:v00001014d00000144* + ID_MODEL_FROM_DATABASE=Yotta Video Compositor Output + +pci:v00001014d00000144sv00001014sd00000145* + ID_MODEL_FROM_DATABASE=Yotta Output Controller (ytout) + +pci:v00001014d00000156* + ID_MODEL_FROM_DATABASE=405GP PLB to PCI Bridge + +pci:v00001014d0000015E* + ID_MODEL_FROM_DATABASE=622Mbps ATM PCI Adapter + +pci:v00001014d00000160* + ID_MODEL_FROM_DATABASE=64bit/66MHz PCI ATM 155 MMF + +pci:v00001014d0000016E* + ID_MODEL_FROM_DATABASE=GXT4000P Graphics Adapter + +pci:v00001014d00000170* + ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter + +pci:v00001014d0000017D* + ID_MODEL_FROM_DATABASE=GXT300P Graphics Adapter + +pci:v00001014d00000180* + ID_MODEL_FROM_DATABASE=Snipe chipset SCSI controller + +pci:v00001014d00000180sv00001014sd00000241* + ID_MODEL_FROM_DATABASE=iSeries 2757 DASD IOA + +pci:v00001014d00000180sv00001014sd00000264* + ID_MODEL_FROM_DATABASE=Quad Channel PCI-X U320 SCSI RAID Adapter (2780) + +pci:v00001014d00000188* + ID_MODEL_FROM_DATABASE=EADS-X PCI-X to PCI-X Bridge + +pci:v00001014d000001A7* + ID_MODEL_FROM_DATABASE=PCI-X to PCI-X Bridge + +pci:v00001014d000001BD* + ID_MODEL_FROM_DATABASE=ServeRAID Controller + +pci:v00001014d000001BDsv00001014sd000001BD* + ID_MODEL_FROM_DATABASE=ServeRAID 4Lx + +pci:v00001014d000001BDsv00001014sd000001BE* + ID_MODEL_FROM_DATABASE=ServeRAID-4M + +pci:v00001014d000001BDsv00001014sd000001BF* + ID_MODEL_FROM_DATABASE=ServeRAID-4L + +pci:v00001014d000001BDsv00001014sd00000208* + ID_MODEL_FROM_DATABASE=ServeRAID-4Mx + +pci:v00001014d000001BDsv00001014sd0000020E* + ID_MODEL_FROM_DATABASE=ServeRAID-4Lx + +pci:v00001014d000001BDsv00001014sd0000022E* + ID_MODEL_FROM_DATABASE=ServeRAID-4H + +pci:v00001014d000001BDsv00001014sd00000258* + ID_MODEL_FROM_DATABASE=ServeRAID-5i + +pci:v00001014d000001BDsv00001014sd00000259* + ID_MODEL_FROM_DATABASE=ServeRAID-5i + +pci:v00001014d000001C1* + ID_MODEL_FROM_DATABASE=64bit/66MHz PCI ATM 155 UTP + +pci:v00001014d000001E6* + ID_MODEL_FROM_DATABASE=Cryptographic Accelerator + +pci:v00001014d000001EF* + ID_MODEL_FROM_DATABASE=PowerPC 440GP PCI Bridge + +pci:v00001014d000001EFsv00001734sd0000102B* + ID_MODEL_FROM_DATABASE=PCEAS PCI-X Dual Port ESCON Adapter + +pci:v00001014d000001EFsv00001734sd000010F8* + ID_MODEL_FROM_DATABASE=PCEAT PCI-Express Dual Port ESCON Adapter + +pci:v00001014d000001FF* + ID_MODEL_FROM_DATABASE=10/100 Mbps Ethernet + +pci:v00001014d00000219* + ID_MODEL_FROM_DATABASE=Multiport Serial Adapter + +pci:v00001014d00000219sv00001014sd0000021A* + ID_MODEL_FROM_DATABASE=Dual RVX + +pci:v00001014d00000219sv00001014sd00000251* + ID_MODEL_FROM_DATABASE=Internal Modem/RVX + +pci:v00001014d00000219sv00001014sd00000252* + ID_MODEL_FROM_DATABASE=Quad Internal Modem + +pci:v00001014d0000021B* + ID_MODEL_FROM_DATABASE=GXT6500P Graphics Adapter + +pci:v00001014d0000021C* + ID_MODEL_FROM_DATABASE=GXT4500P Graphics Adapter + +pci:v00001014d00000233* + ID_MODEL_FROM_DATABASE=GXT135P Graphics Adapter + +pci:v00001014d0000028C* + ID_MODEL_FROM_DATABASE=Citrine chipset SCSI controller + +pci:v00001014d0000028Csv00001014sd0000028D* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X DDR SAS RAID Adapter (572E) + +pci:v00001014d0000028Csv00001014sd000002BE* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X DDR U320 SCSI RAID Adapter (571B) + +pci:v00001014d0000028Csv00001014sd000002C0* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X DDR U320 SCSI Adapter (571A) + +pci:v00001014d0000028Csv00001014sd0000030D* + ID_MODEL_FROM_DATABASE=PCI-X DDR Auxiliary Cache Adapter (575B) + +pci:v00001014d000002A1* + ID_MODEL_FROM_DATABASE=Calgary PCI-X Host Bridge + +pci:v00001014d000002BD* + ID_MODEL_FROM_DATABASE=Obsidian chipset SCSI controller + +pci:v00001014d000002BDsv00001014sd000002C1* + ID_MODEL_FROM_DATABASE=PCI-X DDR 3Gb SAS Adapter (572A/572C) + +pci:v00001014d000002BDsv00001014sd000002C2* + ID_MODEL_FROM_DATABASE=PCI-X DDR 3Gb SAS RAID Adapter (572B/571D) + +pci:v00001014d000002BDsv00001014sd00000338* + ID_MODEL_FROM_DATABASE=PCI-X DDR Auxiliary Cache Adapter (575C) + +pci:v00001014d00000302* + ID_MODEL_FROM_DATABASE=Winnipeg PCI-X Host Bridge + +pci:v00001014d00000308* + ID_MODEL_FROM_DATABASE=CalIOC2 PCI-E Root Port + +pci:v00001014d00000314* + ID_MODEL_FROM_DATABASE=ZISC 036 Neural accelerator card + +pci:v00001014d0000032D* + ID_MODEL_FROM_DATABASE=Axon - Cell Companion Chip + +pci:v00001014d0000032Dsv00001014sd000003A1* + ID_MODEL_FROM_DATABASE=PCIe PowerXCell 8i Cell Accelerator Board + +pci:v00001014d00000339* + ID_MODEL_FROM_DATABASE=Obsidian-E PCI-E SCSI controller + +pci:v00001014d00000339sv00001014sd0000030A* + ID_MODEL_FROM_DATABASE=PCIe 3Gb SAS RAID Adapter (574E) + +pci:v00001014d00000339sv00001014sd0000033A* + ID_MODEL_FROM_DATABASE=PCIe 3Gb SAS Adapter (57B3) + +pci:v00001014d00000339sv00001014sd0000035C* + ID_MODEL_FROM_DATABASE=PCIe x8 Internal 3Gb SAS adapter (57CC) + +pci:v00001014d00000339sv00001014sd00000360* + ID_MODEL_FROM_DATABASE=PCI-E Auxiliary Cache Adapter (57B7) + +pci:v00001014d0000033D* + ID_MODEL_FROM_DATABASE=PCI-E IPR SAS Adapter (FPGA) + +pci:v00001014d0000033Dsv00001014sd0000033C* + ID_MODEL_FROM_DATABASE=PCIe2 1.8GB Cache 6Gb SAS RAID Adapter Tri-port (57B5) + +pci:v00001014d0000033Dsv00001014sd00000353* + ID_MODEL_FROM_DATABASE=PCIe2 3.1GB Cache 6Gb SAS RAID Enclosure (57C3) + +pci:v00001014d0000033Dsv00001014sd00000354* + ID_MODEL_FROM_DATABASE=PCIe2 6Gb SAS Adapter Dual-port (57C4) + +pci:v00001014d0000033Dsv00001014sd00000356* + ID_MODEL_FROM_DATABASE=PCIe2 1.8GB Cache 6Gb SAS RAID & SSD Adapter (574D) + +pci:v00001014d0000033Dsv00001014sd0000035F* + ID_MODEL_FROM_DATABASE=PCIe2 6Gb SAS Adapter Quad-port (57B2) + +pci:v00001014d0000034A* + ID_MODEL_FROM_DATABASE=PCI-E IPR SAS Adapter (ASIC) + +pci:v00001014d0000034Asv00001014sd0000033B* + ID_MODEL_FROM_DATABASE=PCIe2 6Gb SAS RAID Adapter Quad-port (57B4) + +pci:v00001014d0000034Asv00001014sd00000355* + ID_MODEL_FROM_DATABASE=PCIe2 3.6GB Cache 6Gb SAS RAID Adapter Quad-port (57B1) + +pci:v00001014d0000034Asv00001014sd00000357* + ID_MODEL_FROM_DATABASE=PCIe2 6Gb SAS Adapter Quad-port (57C6) + +pci:v00001014d0000034Asv00001014sd0000035D* + ID_MODEL_FROM_DATABASE=PCIe3 1.8GB Cache RAID SAS Adapter Quad-port 6GB (57C8) + +pci:v00001014d0000034Asv00001014sd0000035E* + ID_MODEL_FROM_DATABASE=PCIe2 3.6GB Cache 6Gb SAS RAID Adapter Quad-port (57CE) + +pci:v00001014d0000034Asv00001014sd000003FB* + ID_MODEL_FROM_DATABASE=PCIe3 28GB Cache RAID SAS Enclosure 6Gb x 16 (57D5) + +pci:v00001014d0000034Asv00001014sd000003FE* + ID_MODEL_FROM_DATABASE=PCIe3 x8 Cache SAS RAID Internal Adapter 6Gb (57D8) + +pci:v00001014d0000034Asv00001014sd000003FF* + ID_MODEL_FROM_DATABASE=PCIe3 x8 SAS RAID Internal Adapter 6Gb (57D7) + +pci:v00001014d0000034Asv00001014sd00000474* + ID_MODEL_FROM_DATABASE=PCIe3 x16 Cache SAS RAID Internal Adapter 6Gb (57EB) + +pci:v00001014d0000034Asv00001014sd00000475* + ID_MODEL_FROM_DATABASE=PCIe3 x16 SAS RAID Internal Adapter 6Gb (57EC) + +pci:v00001014d0000034Asv00001014sd00000499* + ID_MODEL_FROM_DATABASE=PCIe3 x16 Cache SAS RAID Internal Adapter 6Gb (57ED) + +pci:v00001014d0000034Asv00001014sd0000049A* + ID_MODEL_FROM_DATABASE=PCIe3 x16 SAS RAID Internal Adapter 6Gb (57EE) + +pci:v00001014d000004AA* + ID_MODEL_FROM_DATABASE=Flash Adapter 90 (PCIe2 0.9TB) + +pci:v00001014d00003022* + ID_MODEL_FROM_DATABASE=QLA3022 Network Adapter + +pci:v00001014d00004022* + ID_MODEL_FROM_DATABASE=QLA3022 Network Adapter + +pci:v00001014d0000FFFF* + ID_MODEL_FROM_DATABASE=MPIC-2 interrupt controller + +pci:v00001015* + ID_VENDOR_FROM_DATABASE=LSI Logic Corp of Canada + +pci:v00001016* + ID_VENDOR_FROM_DATABASE=ICL Personal Systems + +pci:v00001017* + ID_VENDOR_FROM_DATABASE=SPEA Software AG + +pci:v00001017d00005343* + ID_MODEL_FROM_DATABASE=SPEA 3D Accelerator + +pci:v00001018* + ID_VENDOR_FROM_DATABASE=Unisys Systems + +pci:v00001019* + ID_VENDOR_FROM_DATABASE=Elitegroup Computer Systems + +pci:v0000101A* + ID_VENDOR_FROM_DATABASE=AT&T GIS (NCR) + +pci:v0000101Ad00000005* + ID_MODEL_FROM_DATABASE=100VG ethernet + +pci:v0000101Ad00000007* + ID_MODEL_FROM_DATABASE=BYNET BIC4G/2C/2G + +pci:v0000101Ad00000007sv0000101Asd00000019* + ID_MODEL_FROM_DATABASE=BYNET BIC2C + +pci:v0000101Ad00000007sv0000101Asd0000001C* + ID_MODEL_FROM_DATABASE=BYNET BIC2G + +pci:v0000101Ad00000007sv0000101Asd0000001F* + ID_MODEL_FROM_DATABASE=BYNET BIC4G + +pci:v0000101Ad00000009* + ID_MODEL_FROM_DATABASE=PQS Memory Controller + +pci:v0000101Ad0000000A* + ID_MODEL_FROM_DATABASE=BYNET BPCI Adapter + +pci:v0000101Ad0000000B* + ID_MODEL_FROM_DATABASE=BYNET 4 Port BYA Switch (BYA4P) + +pci:v0000101Ad0000000C* + ID_MODEL_FROM_DATABASE=BYNET 4 Port BYA Switch (BYA4G) + +pci:v0000101Ad00000010* + ID_MODEL_FROM_DATABASE=NCR AMC Memory Controller + +pci:v0000101Ad00001DC1* + ID_MODEL_FROM_DATABASE=BYNET BIC2M/BIC4M/BYA4M + +pci:v0000101Ad00001DC1sv0000101Asd00000019* + ID_MODEL_FROM_DATABASE=BIC2M + +pci:v0000101Ad00001DC1sv0000101Asd0000001F* + ID_MODEL_FROM_DATABASE=BIC4M + +pci:v0000101Ad00001DC1sv0000101Asd00000ECE* + ID_MODEL_FROM_DATABASE=BYA4M + +pci:v0000101Ad00001FA8* + ID_MODEL_FROM_DATABASE=BYNET Multi-port BIC Adapter (XBIC Based) + +pci:v0000101Ad00001FA8sv0000101Asd000000C3* + ID_MODEL_FROM_DATABASE=BYNET BIC2SE + +pci:v0000101B* + ID_VENDOR_FROM_DATABASE=Vitesse Semiconductor + +pci:v0000101Bd00000452* + ID_MODEL_FROM_DATABASE=VSC452 [SuperBMC] + +pci:v0000101C* + ID_VENDOR_FROM_DATABASE=Western Digital + +pci:v0000101Cd00000193* + ID_MODEL_FROM_DATABASE=33C193A + +pci:v0000101Cd00000196* + ID_MODEL_FROM_DATABASE=33C196A + +pci:v0000101Cd00000197* + ID_MODEL_FROM_DATABASE=33C197A + +pci:v0000101Cd00000296* + ID_MODEL_FROM_DATABASE=33C296A + +pci:v0000101Cd00003193* + ID_MODEL_FROM_DATABASE=7193 + +pci:v0000101Cd00003197* + ID_MODEL_FROM_DATABASE=7197 + +pci:v0000101Cd00003296* + ID_MODEL_FROM_DATABASE=33C296A + +pci:v0000101Cd00004296* + ID_MODEL_FROM_DATABASE=34C296 + +pci:v0000101Cd00009710* + ID_MODEL_FROM_DATABASE=Pipeline 9710 + +pci:v0000101Cd00009712* + ID_MODEL_FROM_DATABASE=Pipeline 9712 + +pci:v0000101Cd0000C24A* + ID_MODEL_FROM_DATABASE=90C + +pci:v0000101D* + ID_VENDOR_FROM_DATABASE=Maxim Integrated Products + +pci:v0000101E* + ID_VENDOR_FROM_DATABASE=American Megatrends Inc. + +pci:v0000101Ed00000009* + ID_MODEL_FROM_DATABASE=MegaRAID 428 Ultra RAID Controller (rev 03) + +pci:v0000101Ed00001960* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v0000101Ed00001960sv0000101Esd00000471* + ID_MODEL_FROM_DATABASE=MegaRAID 471 Enterprise 1600 RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000475* + ID_MODEL_FROM_DATABASE=MegaRAID 475 Express 500/500LC RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000477* + ID_MODEL_FROM_DATABASE=MegaRAID 477 Elite 3100 RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000493* + ID_MODEL_FROM_DATABASE=MegaRAID 493 Elite 1600 RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000494* + ID_MODEL_FROM_DATABASE=MegaRAID 494 Elite 1650 RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000503* + ID_MODEL_FROM_DATABASE=MegaRAID 503 Enterprise 1650 RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000511* + ID_MODEL_FROM_DATABASE=MegaRAID 511 i4 IDE RAID Controller + +pci:v0000101Ed00001960sv0000101Esd00000522* + ID_MODEL_FROM_DATABASE=MegaRAID 522 i4133 RAID Controller + +pci:v0000101Ed00001960sv00001028sd00000471* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller 3/QC + +pci:v0000101Ed00001960sv00001028sd00000475* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller 3/SC + +pci:v0000101Ed00001960sv00001028sd00000493* + ID_MODEL_FROM_DATABASE=PowerEdge RAID Controller 3/DC + +pci:v0000101Ed00001960sv00001028sd00000511* + ID_MODEL_FROM_DATABASE=PowerEdge Cost Effective RAID Controller ATA100/4Ch + +pci:v0000101Ed00001960sv0000103Csd000060E7* + ID_MODEL_FROM_DATABASE=NetRAID-1M + +pci:v0000101Ed00009010* + ID_MODEL_FROM_DATABASE=MegaRAID 428 Ultra RAID Controller + +pci:v0000101Ed00009030* + ID_MODEL_FROM_DATABASE=EIDE Controller + +pci:v0000101Ed00009031* + ID_MODEL_FROM_DATABASE=EIDE Controller + +pci:v0000101Ed00009032* + ID_MODEL_FROM_DATABASE=EIDE & SCSI Controller + +pci:v0000101Ed00009033* + ID_MODEL_FROM_DATABASE=SCSI Controller + +pci:v0000101Ed00009040* + ID_MODEL_FROM_DATABASE=Multimedia card + +pci:v0000101Ed00009060* + ID_MODEL_FROM_DATABASE=MegaRAID 434 Ultra GT RAID Controller + +pci:v0000101Ed00009063* + ID_MODEL_FROM_DATABASE=MegaRAC + +pci:v0000101Ed00009063sv0000101Esd00000767* + ID_MODEL_FROM_DATABASE=Dell Remote Assistant Card 2 + +pci:v0000101F* + ID_VENDOR_FROM_DATABASE=PictureTel + +pci:v00001020* + ID_VENDOR_FROM_DATABASE=Hitachi Computer Products + +pci:v00001021* + ID_VENDOR_FROM_DATABASE=OKI Electric Industry Co. Ltd. + +pci:v00001022* + ID_VENDOR_FROM_DATABASE=Advanced Micro Devices, Inc. [AMD] + +pci:v00001022d00001100* + ID_MODEL_FROM_DATABASE=K8 [Athlon64/Opteron] HyperTransport Technology Configuration + +pci:v00001022d00001101* + ID_MODEL_FROM_DATABASE=K8 [Athlon64/Opteron] Address Map + +pci:v00001022d00001102* + ID_MODEL_FROM_DATABASE=K8 [Athlon64/Opteron] DRAM Controller + +pci:v00001022d00001103* + ID_MODEL_FROM_DATABASE=K8 [Athlon64/Opteron] Miscellaneous Control + +pci:v00001022d00001200* + ID_MODEL_FROM_DATABASE=Family 10h Processor HyperTransport Configuration + +pci:v00001022d00001201* + ID_MODEL_FROM_DATABASE=Family 10h Processor Address Map + +pci:v00001022d00001202* + ID_MODEL_FROM_DATABASE=Family 10h Processor DRAM Controller + +pci:v00001022d00001203* + ID_MODEL_FROM_DATABASE=Family 10h Processor Miscellaneous Control + +pci:v00001022d00001204* + ID_MODEL_FROM_DATABASE=Family 10h Processor Link Control + +pci:v00001022d00001300* + ID_MODEL_FROM_DATABASE=Family 11h Processor HyperTransport Configuration + +pci:v00001022d00001301* + ID_MODEL_FROM_DATABASE=Family 11h Processor Address Map + +pci:v00001022d00001302* + ID_MODEL_FROM_DATABASE=Family 11h Processor DRAM Controller + +pci:v00001022d00001303* + ID_MODEL_FROM_DATABASE=Family 11h Processor Miscellaneous Control + +pci:v00001022d00001304* + ID_MODEL_FROM_DATABASE=Family 11h Processor Link Control + +pci:v00001022d00001400* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 0 + +pci:v00001022d00001401* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 1 + +pci:v00001022d00001402* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 2 + +pci:v00001022d00001403* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 3 + +pci:v00001022d00001404* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 4 + +pci:v00001022d00001405* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Function 5 + +pci:v00001022d00001410* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Complex + +pci:v00001022d00001412* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001413* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001414* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001415* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001416* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001417* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001418* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) Processor Root Port + +pci:v00001022d00001419* + ID_MODEL_FROM_DATABASE=Family 15h (Models 10h-1fh) I/O Memory Management Unit + +pci:v00001022d00001439* + ID_MODEL_FROM_DATABASE=Family 16h Processor Functions 5:1 + +pci:v00001022d00001510* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Complex + +pci:v00001022d00001510sv0000174Bsd00001001* + ID_MODEL_FROM_DATABASE=PURE Fusion Mini + +pci:v00001022d00001512* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Port + +pci:v00001022d00001513* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Port + +pci:v00001022d00001514* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Port + +pci:v00001022d00001515* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Port + +pci:v00001022d00001516* + ID_MODEL_FROM_DATABASE=Family 14h Processor Root Port + +pci:v00001022d00001530* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 0 + +pci:v00001022d00001531* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 1 + +pci:v00001022d00001532* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 2 + +pci:v00001022d00001533* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 3 + +pci:v00001022d00001534* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 4 + +pci:v00001022d00001535* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 5 + +pci:v00001022d00001536* + ID_MODEL_FROM_DATABASE=Family 16h Processor Root Complex + +pci:v00001022d00001538* + ID_MODEL_FROM_DATABASE=Family 16h Processor Function 0 + +pci:v00001022d00001600* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 0 + +pci:v00001022d00001601* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 1 + +pci:v00001022d00001602* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 2 + +pci:v00001022d00001603* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 3 + +pci:v00001022d00001604* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 4 + +pci:v00001022d00001605* + ID_MODEL_FROM_DATABASE=Family 15h Processor Function 5 + +pci:v00001022d00001700* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 0 + +pci:v00001022d00001701* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 1 + +pci:v00001022d00001702* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 2 + +pci:v00001022d00001703* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 3 + +pci:v00001022d00001704* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 4 + +pci:v00001022d00001705* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Complex + +pci:v00001022d00001707* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d00001708* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d00001709* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d0000170A* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d0000170B* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d0000170C* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d0000170D* + ID_MODEL_FROM_DATABASE=Family 12h Processor Root Port + +pci:v00001022d00001716* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 5 + +pci:v00001022d00001718* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 6 + +pci:v00001022d00001719* + ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 7 + +pci:v00001022d00002000* + ID_MODEL_FROM_DATABASE=79c970 [PCnet32 LANCE] + +pci:v00001022d00002000sv00001014sd00002000* + ID_MODEL_FROM_DATABASE=NetFinity 10/100 Fast Ethernet + +pci:v00001022d00002000sv00001022sd00002000* + ID_MODEL_FROM_DATABASE=PCnet - Fast 79C971 + +pci:v00001022d00002000sv0000103Csd0000104C* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv0000103Csd00001064* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv0000103Csd00001065* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv0000103Csd0000106C* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv0000103Csd0000106E* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv0000103Csd000010EA* + ID_MODEL_FROM_DATABASE=Ethernet with LAN remote power Adapter + +pci:v00001022d00002000sv00001113sd00001220* + ID_MODEL_FROM_DATABASE=EN1220 10/100 Fast Ethernet + +pci:v00001022d00002000sv00001259sd00002450* + ID_MODEL_FROM_DATABASE=AT-2450 10/100 Fast Ethernet + +pci:v00001022d00002000sv00001259sd00002454* + ID_MODEL_FROM_DATABASE=AT-2450v4 10Mb Ethernet Adapter + +pci:v00001022d00002000sv00001259sd00002700* + ID_MODEL_FROM_DATABASE=AT-2700TX 10/100 Fast Ethernet + +pci:v00001022d00002000sv00001259sd00002701* + ID_MODEL_FROM_DATABASE=AT-2700FX 100Mb Ethernet + +pci:v00001022d00002000sv00001259sd00002702* + ID_MODEL_FROM_DATABASE=AT-2700FTX 10/100 Mb Fiber/Copper Fast Ethernet + +pci:v00001022d00002000sv00001259sd00002703* + ID_MODEL_FROM_DATABASE=AT-2701FX + +pci:v00001022d00002000sv00001259sd00002704* + ID_MODEL_FROM_DATABASE=AT-2701FTX 10/100 Mb Fiber/Copper Fast Ethernet + +pci:v00001022d00002000sv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v00001022d00002000sv00004C53sd00001010* + ID_MODEL_FROM_DATABASE=CP5/CR6 mainboard + +pci:v00001022d00002000sv00004C53sd00001020* + ID_MODEL_FROM_DATABASE=VR6 mainboard + +pci:v00001022d00002000sv00004C53sd00001030* + ID_MODEL_FROM_DATABASE=PC5 mainboard + +pci:v00001022d00002000sv00004C53sd00001040* + ID_MODEL_FROM_DATABASE=CL7 mainboard + +pci:v00001022d00002000sv00004C53sd00001060* + ID_MODEL_FROM_DATABASE=PC7 mainboard + +pci:v00001022d00002001* + ID_MODEL_FROM_DATABASE=79c978 [HomePNA] + +pci:v00001022d00002001sv00001092sd00000A78* + ID_MODEL_FROM_DATABASE=Multimedia Home Network Adapter + +pci:v00001022d00002001sv00001668sd00000299* + ID_MODEL_FROM_DATABASE=ActionLink Home Network Adapter + +pci:v00001022d00002003* + ID_MODEL_FROM_DATABASE=Am 1771 MBW [Alchemy] + +pci:v00001022d00002020* + ID_MODEL_FROM_DATABASE=53c974 [PCscsi] + +pci:v00001022d00002040* + ID_MODEL_FROM_DATABASE=79c974 + +pci:v00001022d00002080* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] Host Bridge + +pci:v00001022d00002081* + ID_MODEL_FROM_DATABASE=Geode LX Video + +pci:v00001022d00002082* + ID_MODEL_FROM_DATABASE=Geode LX AES Security Block + +pci:v00001022d0000208F* + ID_MODEL_FROM_DATABASE=CS5536 GeodeLink PCI South Bridge + +pci:v00001022d00002090* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] ISA + +pci:v00001022d00002091* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] FLASH + +pci:v00001022d00002093* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] Audio + +pci:v00001022d00002094* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] OHC + +pci:v00001022d00002095* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] EHC + +pci:v00001022d00002096* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] UDC + +pci:v00001022d00002097* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] UOC + +pci:v00001022d0000209A* + ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] IDE + +pci:v00001022d00003000* + ID_MODEL_FROM_DATABASE=ELanSC520 Microcontroller + +pci:v00001022d000043A0* + ID_MODEL_FROM_DATABASE=Hudson PCI to PCI bridge (PCIE port 0) + +pci:v00001022d000043A1* + ID_MODEL_FROM_DATABASE=Hudson PCI to PCI bridge (PCIE port 1) + +pci:v00001022d000043A2* + ID_MODEL_FROM_DATABASE=Hudson PCI to PCI bridge (PCIE port 2) + +pci:v00001022d000043A3* + ID_MODEL_FROM_DATABASE=Hudson PCI to PCI bridge (PCIE port 3) + +pci:v00001022d00007006* + ID_MODEL_FROM_DATABASE=AMD-751 [Irongate] System Controller + +pci:v00001022d00007007* + ID_MODEL_FROM_DATABASE=AMD-751 [Irongate] AGP Bridge + +pci:v00001022d0000700A* + ID_MODEL_FROM_DATABASE=AMD-IGR4 AGP Host to PCI Bridge + +pci:v00001022d0000700B* + ID_MODEL_FROM_DATABASE=AMD-IGR4 PCI to PCI Bridge + +pci:v00001022d0000700C* + ID_MODEL_FROM_DATABASE=AMD-760 MP [IGD4-2P] System Controller + +pci:v00001022d0000700D* + ID_MODEL_FROM_DATABASE=AMD-760 MP [IGD4-2P] AGP Bridge + +pci:v00001022d0000700E* + ID_MODEL_FROM_DATABASE=AMD-760 [IGD4-1P] System Controller + +pci:v00001022d0000700F* + ID_MODEL_FROM_DATABASE=AMD-760 [IGD4-1P] AGP Bridge + +pci:v00001022d00007400* + ID_MODEL_FROM_DATABASE=AMD-755 [Cobra] ISA + +pci:v00001022d00007401* + ID_MODEL_FROM_DATABASE=AMD-755 [Cobra] IDE + +pci:v00001022d00007403* + ID_MODEL_FROM_DATABASE=AMD-755 [Cobra] ACPI + +pci:v00001022d00007404* + ID_MODEL_FROM_DATABASE=AMD-755 [Cobra] USB + +pci:v00001022d00007408* + ID_MODEL_FROM_DATABASE=AMD-756 [Viper] ISA + +pci:v00001022d00007409* + ID_MODEL_FROM_DATABASE=AMD-756 [Viper] IDE + +pci:v00001022d0000740B* + ID_MODEL_FROM_DATABASE=AMD-756 [Viper] ACPI + +pci:v00001022d0000740C* + ID_MODEL_FROM_DATABASE=AMD-756 [Viper] USB + +pci:v00001022d00007410* + ID_MODEL_FROM_DATABASE=AMD-766 [ViperPlus] ISA + +pci:v00001022d00007411* + ID_MODEL_FROM_DATABASE=AMD-766 [ViperPlus] IDE + +pci:v00001022d00007413* + ID_MODEL_FROM_DATABASE=AMD-766 [ViperPlus] ACPI + +pci:v00001022d00007414* + ID_MODEL_FROM_DATABASE=AMD-766 [ViperPlus] USB + +pci:v00001022d00007440* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] ISA + +pci:v00001022d00007440sv00001043sd00008044* + ID_MODEL_FROM_DATABASE=A7M-D Mainboard + +pci:v00001022d00007441* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] IDE + +pci:v00001022d00007443* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] ACPI + +pci:v00001022d00007443sv00001043sd00008044* + ID_MODEL_FROM_DATABASE=A7M-D Mainboard + +pci:v00001022d00007445* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] Audio + +pci:v00001022d00007446* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] MC97 Modem + +pci:v00001022d00007448* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] PCI + +pci:v00001022d00007449* + ID_MODEL_FROM_DATABASE=AMD-768 [Opus] USB + +pci:v00001022d00007450* + ID_MODEL_FROM_DATABASE=AMD-8131 PCI-X Bridge + +pci:v00001022d00007451* + ID_MODEL_FROM_DATABASE=AMD-8131 PCI-X IOAPIC + +pci:v00001022d00007454* + ID_MODEL_FROM_DATABASE=AMD-8151 System Controller + +pci:v00001022d00007455* + ID_MODEL_FROM_DATABASE=AMD-8151 AGP Bridge + +pci:v00001022d00007458* + ID_MODEL_FROM_DATABASE=AMD-8132 PCI-X Bridge + +pci:v00001022d00007459* + ID_MODEL_FROM_DATABASE=AMD-8132 PCI-X IOAPIC + +pci:v00001022d00007460* + ID_MODEL_FROM_DATABASE=AMD-8111 PCI + +pci:v00001022d00007460sv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d00007461* + ID_MODEL_FROM_DATABASE=AMD-8111 USB + +pci:v00001022d00007462* + ID_MODEL_FROM_DATABASE=AMD-8111 Ethernet + +pci:v00001022d00007463* + ID_MODEL_FROM_DATABASE=AMD-8111 USB EHCI + +pci:v00001022d00007464* + ID_MODEL_FROM_DATABASE=AMD-8111 USB OHCI + +pci:v00001022d00007464sv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d00007468* + ID_MODEL_FROM_DATABASE=AMD-8111 LPC + +pci:v00001022d00007468sv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d00007469* + ID_MODEL_FROM_DATABASE=AMD-8111 IDE + +pci:v00001022d00007469sv00001022sd00002B80* + ID_MODEL_FROM_DATABASE=AMD-8111 IDE [Quartet] + +pci:v00001022d00007469sv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d0000746A* + ID_MODEL_FROM_DATABASE=AMD-8111 SMBus 2.0 + +pci:v00001022d0000746B* + ID_MODEL_FROM_DATABASE=AMD-8111 ACPI + +pci:v00001022d0000746Bsv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d0000746D* + ID_MODEL_FROM_DATABASE=AMD-8111 AC97 Audio + +pci:v00001022d0000746Dsv0000161Fsd00003017* + ID_MODEL_FROM_DATABASE=HDAMB + +pci:v00001022d0000746E* + ID_MODEL_FROM_DATABASE=AMD-8111 MC97 Modem + +pci:v00001022d0000756B* + ID_MODEL_FROM_DATABASE=AMD-8111 ACPI + +pci:v00001022d00007800* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [IDE mode] + +pci:v00001022d00007801* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] + +pci:v00001022d00007801sv0000103Csd0000168B* + ID_MODEL_FROM_DATABASE=ProBook 4535s Notebook + +pci:v00001022d00007801sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d00007802* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] + +pci:v00001022d00007803* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] + +pci:v00001022d00007804* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] + +pci:v00001022d00007805* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] + +pci:v00001022d00007806* + ID_MODEL_FROM_DATABASE=FCH SD Flash Controller + +pci:v00001022d00007807* + ID_MODEL_FROM_DATABASE=FCH USB OHCI Controller + +pci:v00001022d00007807sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d00007808* + ID_MODEL_FROM_DATABASE=FCH USB EHCI Controller + +pci:v00001022d00007808sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d00007809* + ID_MODEL_FROM_DATABASE=FCH USB OHCI Controller + +pci:v00001022d00007809sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d0000780B* + ID_MODEL_FROM_DATABASE=FCH SMBus Controller + +pci:v00001022d0000780Bsv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d0000780C* + ID_MODEL_FROM_DATABASE=FCH IDE Controller + +pci:v00001022d0000780D* + ID_MODEL_FROM_DATABASE=FCH Azalia Controller + +pci:v00001022d0000780Dsv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d0000780Dsv00001043sd00008444* + ID_MODEL_FROM_DATABASE=F2A85-M Series + +pci:v00001022d0000780E* + ID_MODEL_FROM_DATABASE=FCH LPC Bridge + +pci:v00001022d0000780Esv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d0000780F* + ID_MODEL_FROM_DATABASE=FCH PCI Bridge + +pci:v00001022d00007812* + ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller + +pci:v00001022d00007813* + ID_MODEL_FROM_DATABASE=FCH SD Flash Controller + +pci:v00001022d00007814* + ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller + +pci:v00001022d00007814sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v00001022d00007900* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [IDE mode] + +pci:v00001022d00007901* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] + +pci:v00001022d00007902* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] + +pci:v00001022d00007903* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] + +pci:v00001022d00007904* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] + +pci:v00001022d00007906* + ID_MODEL_FROM_DATABASE=FCH SD Flash Controller + +pci:v00001022d00007908* + ID_MODEL_FROM_DATABASE=FCH USB EHCI Controller + +pci:v00001022d0000790B* + ID_MODEL_FROM_DATABASE=FCH SMBus Controller + +pci:v00001022d0000790E* + ID_MODEL_FROM_DATABASE=FCH LPC Bridge + +pci:v00001022d0000790F* + ID_MODEL_FROM_DATABASE=FCH PCI Bridge + +pci:v00001022d00007914* + ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller + +pci:v00001022d00009600* + ID_MODEL_FROM_DATABASE=RS780 Host Bridge + +pci:v00001022d00009600sv00001043sd000082F1* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v00001022d00009601* + ID_MODEL_FROM_DATABASE=RS880 Host Bridge + +pci:v00001022d00009601sv00001019sd00002120* + ID_MODEL_FROM_DATABASE=A785GM-M + +pci:v00001022d00009601sv00001043sd0000843E* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001022d00009602* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (int gfx) + +pci:v00001022d00009603* + ID_MODEL_FROM_DATABASE=RS780 PCI to PCI bridge (ext gfx port 0) + +pci:v00001022d00009604* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (PCIE port 0) + +pci:v00001022d00009605* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (PCIE port 1) + +pci:v00001022d00009606* + ID_MODEL_FROM_DATABASE=RS780 PCI to PCI bridge (PCIE port 2) + +pci:v00001022d00009607* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (PCIE port 3) + +pci:v00001022d00009608* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (PCIE port 4) + +pci:v00001022d00009609* + ID_MODEL_FROM_DATABASE=RS780/RS880 PCI to PCI bridge (PCIE port 5) + +pci:v00001022d0000960A* + ID_MODEL_FROM_DATABASE=RS780 PCI to PCI bridge (NB-SB link) + +pci:v00001022d0000960B* + ID_MODEL_FROM_DATABASE=RS780 PCI to PCI bridge (ext gfx port 1) + +pci:v00001023* + ID_VENDOR_FROM_DATABASE=Trident Microsystems + +pci:v00001023d00000194* + ID_MODEL_FROM_DATABASE=82C194 + +pci:v00001023d00002000* + ID_MODEL_FROM_DATABASE=4DWave DX + +pci:v00001023d00002001* + ID_MODEL_FROM_DATABASE=4DWave NX + +pci:v00001023d00002001sv0000122Dsd00001400* + ID_MODEL_FROM_DATABASE=Trident PCI288-Q3DII (NX) + +pci:v00001023d00002100* + ID_MODEL_FROM_DATABASE=CyberBlade XP4m32 + +pci:v00001023d00002200* + ID_MODEL_FROM_DATABASE=XGI Volari XP5 + +pci:v00001023d00008400* + ID_MODEL_FROM_DATABASE=CyberBlade/i7 + +pci:v00001023d00008400sv00001023sd00008400* + ID_MODEL_FROM_DATABASE=CyberBlade i7 AGP + +pci:v00001023d00008420* + ID_MODEL_FROM_DATABASE=CyberBlade/i7d + +pci:v00001023d00008420sv00000E11sd0000B15A* + ID_MODEL_FROM_DATABASE=CyberBlade i7 AGP + +pci:v00001023d00008500* + ID_MODEL_FROM_DATABASE=CyberBlade/i1 + +pci:v00001023d00008520* + ID_MODEL_FROM_DATABASE=CyberBlade i1 + +pci:v00001023d00008520sv00000E11sd0000B16E* + ID_MODEL_FROM_DATABASE=CyberBlade i1 AGP + +pci:v00001023d00008520sv00001023sd00008520* + ID_MODEL_FROM_DATABASE=CyberBlade i1 AGP + +pci:v00001023d00008620* + ID_MODEL_FROM_DATABASE=CyberBlade/i1 + +pci:v00001023d00008620sv00001014sd00000502* + ID_MODEL_FROM_DATABASE=ThinkPad R30/T30 + +pci:v00001023d00008620sv00001014sd00001025* + ID_MODEL_FROM_DATABASE=Travelmate 352TE + +pci:v00001023d00008820* + ID_MODEL_FROM_DATABASE=CyberBlade XPAi1 + +pci:v00001023d00009320* + ID_MODEL_FROM_DATABASE=TGUI 9320 + +pci:v00001023d00009350* + ID_MODEL_FROM_DATABASE=GUI Accelerator + +pci:v00001023d00009360* + ID_MODEL_FROM_DATABASE=Flat panel GUI Accelerator + +pci:v00001023d00009382* + ID_MODEL_FROM_DATABASE=Cyber 9382 [Reference design] + +pci:v00001023d00009383* + ID_MODEL_FROM_DATABASE=Cyber 9383 [Reference design] + +pci:v00001023d00009385* + ID_MODEL_FROM_DATABASE=Cyber 9385 [Reference design] + +pci:v00001023d00009386* + ID_MODEL_FROM_DATABASE=Cyber 9386 + +pci:v00001023d00009388* + ID_MODEL_FROM_DATABASE=Cyber 9388 + +pci:v00001023d00009397* + ID_MODEL_FROM_DATABASE=Cyber 9397 + +pci:v00001023d0000939A* + ID_MODEL_FROM_DATABASE=Cyber 9397DVD + +pci:v00001023d00009420* + ID_MODEL_FROM_DATABASE=TGUI 9420 + +pci:v00001023d00009430* + ID_MODEL_FROM_DATABASE=TGUI 9430 + +pci:v00001023d00009440* + ID_MODEL_FROM_DATABASE=TGUI 9440 + +pci:v00001023d00009460* + ID_MODEL_FROM_DATABASE=TGUI 9460 + +pci:v00001023d00009470* + ID_MODEL_FROM_DATABASE=TGUI 9470 + +pci:v00001023d00009520* + ID_MODEL_FROM_DATABASE=Cyber 9520 + +pci:v00001023d00009525* + ID_MODEL_FROM_DATABASE=Cyber 9525 + +pci:v00001023d00009540* + ID_MODEL_FROM_DATABASE=Cyber 9540 + +pci:v00001023d00009660* + ID_MODEL_FROM_DATABASE=TGUI 9660/938x/968x + +pci:v00001023d00009680* + ID_MODEL_FROM_DATABASE=TGUI 9680 + +pci:v00001023d00009682* + ID_MODEL_FROM_DATABASE=TGUI 9682 + +pci:v00001023d00009683* + ID_MODEL_FROM_DATABASE=TGUI 9683 + +pci:v00001023d00009685* + ID_MODEL_FROM_DATABASE=ProVIDIA 9685 + +pci:v00001023d00009750* + ID_MODEL_FROM_DATABASE=3DImage 9750 + +pci:v00001023d00009750sv00001014sd00009750* + ID_MODEL_FROM_DATABASE=3DImage 9750 + +pci:v00001023d00009750sv00001023sd00009750* + ID_MODEL_FROM_DATABASE=3DImage 9750 + +pci:v00001023d00009753* + ID_MODEL_FROM_DATABASE=TGUI 9753 + +pci:v00001023d00009754* + ID_MODEL_FROM_DATABASE=TGUI 9754 + +pci:v00001023d00009759* + ID_MODEL_FROM_DATABASE=TGUI 975 + +pci:v00001023d00009783* + ID_MODEL_FROM_DATABASE=TGUI 9783 + +pci:v00001023d00009785* + ID_MODEL_FROM_DATABASE=TGUI 9785 + +pci:v00001023d00009850* + ID_MODEL_FROM_DATABASE=3DImage 9850 + +pci:v00001023d00009880* + ID_MODEL_FROM_DATABASE=Blade 3D PCI/AGP + +pci:v00001023d00009880sv00001023sd00009880* + ID_MODEL_FROM_DATABASE=Blade 3D + +pci:v00001023d00009910* + ID_MODEL_FROM_DATABASE=CyberBlade/XP + +pci:v00001023d00009930* + ID_MODEL_FROM_DATABASE=CyberBlade/XPm + +pci:v00001023d00009960* + ID_MODEL_FROM_DATABASE=CyberBlade XP2 + +pci:v00001024* + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +pci:v00001025* + ID_VENDOR_FROM_DATABASE=Acer Incorporated [ALI] + +pci:v00001025d00001435* + ID_MODEL_FROM_DATABASE=M1435 + +pci:v00001025d00001445* + ID_MODEL_FROM_DATABASE=M1445 + +pci:v00001025d00001449* + ID_MODEL_FROM_DATABASE=M1449 + +pci:v00001025d00001451* + ID_MODEL_FROM_DATABASE=M1451 + +pci:v00001025d00001461* + ID_MODEL_FROM_DATABASE=M1461 + +pci:v00001025d00001489* + ID_MODEL_FROM_DATABASE=M1489 + +pci:v00001025d00001511* + ID_MODEL_FROM_DATABASE=M1511 + +pci:v00001025d00001512* + ID_MODEL_FROM_DATABASE=ALI M1512 Aladdin + +pci:v00001025d00001513* + ID_MODEL_FROM_DATABASE=M1513 + +pci:v00001025d00001521* + ID_MODEL_FROM_DATABASE=ALI M1521 Aladdin III CPU Bridge + +pci:v00001025d00001521sv000010B9sd00001521* + ID_MODEL_FROM_DATABASE=ALI M1521 Aladdin III CPU Bridge + +pci:v00001025d00001523* + ID_MODEL_FROM_DATABASE=ALI M1523 ISA Bridge + +pci:v00001025d00001523sv000010B9sd00001523* + ID_MODEL_FROM_DATABASE=ALI M1523 ISA Bridge + +pci:v00001025d00001531* + ID_MODEL_FROM_DATABASE=M1531 Northbridge [Aladdin IV/IV+] + +pci:v00001025d00001533* + ID_MODEL_FROM_DATABASE=M1533 PCI-to-ISA Bridge + +pci:v00001025d00001533sv000010B9sd00001533* + ID_MODEL_FROM_DATABASE=ALI M1533 Aladdin IV/V ISA South Bridge + +pci:v00001025d00001535* + ID_MODEL_FROM_DATABASE=M1535 PCI Bridge + Super I/O + FIR + +pci:v00001025d00001541* + ID_MODEL_FROM_DATABASE=M1541 Northbridge [Aladdin V] + +pci:v00001025d00001541sv000010B9sd00001541* + ID_MODEL_FROM_DATABASE=ALI M1541 Aladdin V/V+ AGP+PCI North Bridge + +pci:v00001025d00001542* + ID_MODEL_FROM_DATABASE=M1542 Northbridge [Aladdin V] + +pci:v00001025d00001543* + ID_MODEL_FROM_DATABASE=M1543 PCI-to-ISA Bridge + Super I/O + FIR + +pci:v00001025d00001561* + ID_MODEL_FROM_DATABASE=M1561 Northbridge [Aladdin 7] + +pci:v00001025d00001621* + ID_MODEL_FROM_DATABASE=M1621 Northbridge [Aladdin-Pro II] + +pci:v00001025d00001631* + ID_MODEL_FROM_DATABASE=M1631 Northbridge+3D Graphics [Aladdin TNT2] + +pci:v00001025d00001641* + ID_MODEL_FROM_DATABASE=M1641 Northbridge [Aladdin-Pro IV] + +pci:v00001025d00001647* + ID_MODEL_FROM_DATABASE=M1647 [MaGiK1] PCI North Bridge + +pci:v00001025d00001671* + ID_MODEL_FROM_DATABASE=M1671 Northbridge [ALADDiN-P4] + +pci:v00001025d00001672* + ID_MODEL_FROM_DATABASE=Northbridge [CyberALADDiN-P4] + +pci:v00001025d00003141* + ID_MODEL_FROM_DATABASE=M3141 + +pci:v00001025d00003143* + ID_MODEL_FROM_DATABASE=M3143 + +pci:v00001025d00003145* + ID_MODEL_FROM_DATABASE=M3145 + +pci:v00001025d00003147* + ID_MODEL_FROM_DATABASE=M3147 + +pci:v00001025d00003149* + ID_MODEL_FROM_DATABASE=M3149 + +pci:v00001025d00003151* + ID_MODEL_FROM_DATABASE=M3151 + +pci:v00001025d00003307* + ID_MODEL_FROM_DATABASE=M3307 MPEG-I Video Controller + +pci:v00001025d00003309* + ID_MODEL_FROM_DATABASE=M3309 MPEG-II Video w/ Software Audio Decoder + +pci:v00001025d00003321* + ID_MODEL_FROM_DATABASE=M3321 MPEG-II Audio/Video Decoder + +pci:v00001025d00005212* + ID_MODEL_FROM_DATABASE=M4803 + +pci:v00001025d00005215* + ID_MODEL_FROM_DATABASE=ALI PCI EIDE Controller + +pci:v00001025d00005217* + ID_MODEL_FROM_DATABASE=M5217H + +pci:v00001025d00005219* + ID_MODEL_FROM_DATABASE=M5219 + +pci:v00001025d00005225* + ID_MODEL_FROM_DATABASE=M5225 + +pci:v00001025d00005229* + ID_MODEL_FROM_DATABASE=M5229 + +pci:v00001025d00005235* + ID_MODEL_FROM_DATABASE=M5235 + +pci:v00001025d00005237* + ID_MODEL_FROM_DATABASE=M5237 PCI USB Host Controller + +pci:v00001025d00005240* + ID_MODEL_FROM_DATABASE=EIDE Controller + +pci:v00001025d00005241* + ID_MODEL_FROM_DATABASE=PCMCIA Bridge + +pci:v00001025d00005242* + ID_MODEL_FROM_DATABASE=General Purpose Controller + +pci:v00001025d00005243* + ID_MODEL_FROM_DATABASE=PCI to PCI Bridge Controller + +pci:v00001025d00005244* + ID_MODEL_FROM_DATABASE=Floppy Disk Controller + +pci:v00001025d00005247* + ID_MODEL_FROM_DATABASE=M1541 PCI to PCI Bridge + +pci:v00001025d00005251* + ID_MODEL_FROM_DATABASE=M5251 P1394 Controller + +pci:v00001025d00005427* + ID_MODEL_FROM_DATABASE=PCI to AGP Bridge + +pci:v00001025d00005451* + ID_MODEL_FROM_DATABASE=M5451 PCI AC-Link Controller Audio Device + +pci:v00001025d00005453* + ID_MODEL_FROM_DATABASE=M5453 PCI AC-Link Controller Modem Device + +pci:v00001025d00007101* + ID_MODEL_FROM_DATABASE=M7101 PCI PMU Power Management Controller + +pci:v00001025d00007101sv000010B9sd00007101* + ID_MODEL_FROM_DATABASE=M7101 PCI PMU Power Management Controller + +pci:v00001025d00009602* + ID_MODEL_FROM_DATABASE=AMD RS780/RS880 PCI to PCI bridge (int gfx) + +pci:v00001028* + ID_VENDOR_FROM_DATABASE=Dell + +pci:v00001028d00000001* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 2/Si + +pci:v00001028d00000001sv00001028sd00000001* + ID_MODEL_FROM_DATABASE=PowerEdge 2400 + +pci:v00001028d00000002* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 3/Di + +pci:v00001028d00000002sv00001028sd00000002* + ID_MODEL_FROM_DATABASE=PowerEdge 4400 + +pci:v00001028d00000002sv00001028sd000000D1* + ID_MODEL_FROM_DATABASE=PERC 3/DiV [Viper] + +pci:v00001028d00000002sv00001028sd000000D9* + ID_MODEL_FROM_DATABASE=PERC 3/DiL [Lexus] + +pci:v00001028d00000003* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 3/Si + +pci:v00001028d00000003sv00001028sd00000003* + ID_MODEL_FROM_DATABASE=PowerEdge 2450 + +pci:v00001028d00000004* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 3/Di [Iguana] + +pci:v00001028d00000004sv00001028sd00000004* + ID_MODEL_FROM_DATABASE=PERC 3/DiF [Iguana] + +pci:v00001028d00000006* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 3/Di + +pci:v00001028d00000007* + ID_MODEL_FROM_DATABASE=Remote Access Card III + +pci:v00001028d00000008* + ID_MODEL_FROM_DATABASE=Remote Access Card III + +pci:v00001028d00000009* + ID_MODEL_FROM_DATABASE=Remote Access Card III: BMC/SMIC device not present + +pci:v00001028d0000000A* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 3/Di + +pci:v00001028d0000000Asv00001028sd00000106* + ID_MODEL_FROM_DATABASE=PERC 3/DiJ [Jaguar] + +pci:v00001028d0000000Asv00001028sd0000011B* + ID_MODEL_FROM_DATABASE=PERC 3/DiD [Dagger] + +pci:v00001028d0000000Asv00001028sd00000121* + ID_MODEL_FROM_DATABASE=PERC 3/DiB [Boxster] + +pci:v00001028d0000000C* + ID_MODEL_FROM_DATABASE=Embedded Remote Access or ERA/O + +pci:v00001028d0000000D* + ID_MODEL_FROM_DATABASE=Embedded Remote Access: BMC/SMIC device + +pci:v00001028d0000000E* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID controller 4/Di + +pci:v00001028d0000000F* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID controller 4/Di + +pci:v00001028d0000000Fsv00001028sd0000014A* + ID_MODEL_FROM_DATABASE=PowerEdge 1750 + +pci:v00001028d00000010* + ID_MODEL_FROM_DATABASE=Remote Access Card 4 + +pci:v00001028d00000011* + ID_MODEL_FROM_DATABASE=Remote Access Card 4 Daughter Card + +pci:v00001028d00000012* + ID_MODEL_FROM_DATABASE=Remote Access Card 4 Daughter Card Virtual UART + +pci:v00001028d00000013* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID controller 4 + +pci:v00001028d00000013sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4e/Si + +pci:v00001028d00000013sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4e/Di + +pci:v00001028d00000013sv00001028sd0000016E* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4e/Di + +pci:v00001028d00000013sv00001028sd0000016F* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4e/Di + +pci:v00001028d00000013sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 4e/Di + +pci:v00001028d00000014* + ID_MODEL_FROM_DATABASE=Remote Access Card 4 Daughter Card SMIC interface + +pci:v00001028d00000015* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID controller 5 + +pci:v00001028d00000015sv00001028sd00001F01* + ID_MODEL_FROM_DATABASE=PERC 5/E Adapter RAID Controller + +pci:v00001028d00000015sv00001028sd00001F02* + ID_MODEL_FROM_DATABASE=PERC 5/i Adapter RAID Controller + +pci:v00001028d00000015sv00001028sd00001F03* + ID_MODEL_FROM_DATABASE=PERC 5/i Integrated RAID Controller + +pci:v00001028d00000016* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID controller S300 + +pci:v00001028d00000016sv00001028sd00001F24* + ID_MODEL_FROM_DATABASE=PERC S300 Controller + +pci:v00001029* + ID_VENDOR_FROM_DATABASE=Siemens Nixdorf IS + +pci:v0000102A* + ID_VENDOR_FROM_DATABASE=LSI Logic + +pci:v0000102Ad00000000* + ID_MODEL_FROM_DATABASE=HYDRA + +pci:v0000102Ad00000010* + ID_MODEL_FROM_DATABASE=ASPEN + +pci:v0000102Ad0000001F* + ID_MODEL_FROM_DATABASE=AHA-2940U2/U2W /7890/7891 SCSI Controllers + +pci:v0000102Ad0000001Fsv00009005sd0000000F* + ID_MODEL_FROM_DATABASE=2940U2W SCSI Controller + +pci:v0000102Ad0000001Fsv00009005sd00000106* + ID_MODEL_FROM_DATABASE=2940U2W SCSI Controller + +pci:v0000102Ad0000001Fsv00009005sd0000A180* + ID_MODEL_FROM_DATABASE=2940U2W SCSI Controller + +pci:v0000102Ad000000C5* + ID_MODEL_FROM_DATABASE=AIC-7899 U160/m SCSI Controller + +pci:v0000102Ad000000C5sv00001028sd000000C5* + ID_MODEL_FROM_DATABASE=PowerEdge 2550/2650/4600 + +pci:v0000102Ad000000CF* + ID_MODEL_FROM_DATABASE=AIC-7899P U160/m + +pci:v0000102Ad000000CFsv00001028sd00000106* + ID_MODEL_FROM_DATABASE=PowerEdge 4600 + +pci:v0000102Ad000000CFsv00001028sd00000121* + ID_MODEL_FROM_DATABASE=PowerEdge 2650 + +pci:v0000102B* + ID_VENDOR_FROM_DATABASE=Matrox Electronics Systems Ltd. + +pci:v0000102Bd00000010* + ID_MODEL_FROM_DATABASE=MGA-I [Impression?] + +pci:v0000102Bd00000100* + ID_MODEL_FROM_DATABASE=MGA 1064SG [Mystique] + +pci:v0000102Bd00000518* + ID_MODEL_FROM_DATABASE=MGA-II [Athena] + +pci:v0000102Bd00000519* + ID_MODEL_FROM_DATABASE=MGA 2064W [Millennium] + +pci:v0000102Bd0000051A* + ID_MODEL_FROM_DATABASE=MGA 1064SG [Mystique] + +pci:v0000102Bd0000051Asv0000102Bsd00000100* + ID_MODEL_FROM_DATABASE=MGA-1064SG Mystique + +pci:v0000102Bd0000051Asv0000102Bsd00001100* + ID_MODEL_FROM_DATABASE=MGA-1084SG Mystique + +pci:v0000102Bd0000051Asv0000102Bsd00001200* + ID_MODEL_FROM_DATABASE=MGA-1084SG Mystique + +pci:v0000102Bd0000051Asv00001100sd0000102B* + ID_MODEL_FROM_DATABASE=MGA-1084SG Mystique + +pci:v0000102Bd0000051Asv0000110Asd00000018* + ID_MODEL_FROM_DATABASE=Scenic Pro C5 (D1025) + +pci:v0000102Bd0000051B* + ID_MODEL_FROM_DATABASE=MGA 2164W [Millennium II] + +pci:v0000102Bd0000051Bsv0000102Bsd0000051B* + ID_MODEL_FROM_DATABASE=MGA-2164W Millennium II + +pci:v0000102Bd0000051Bsv0000102Bsd00001100* + ID_MODEL_FROM_DATABASE=MGA-2164W Millennium II + +pci:v0000102Bd0000051Bsv0000102Bsd00001200* + ID_MODEL_FROM_DATABASE=MGA-2164W Millennium II + +pci:v0000102Bd0000051Bsv0000102Bsd00002100* + ID_MODEL_FROM_DATABASE=MGA-2164W Millennium II + +pci:v0000102Bd0000051E* + ID_MODEL_FROM_DATABASE=MGA 1064SG [Mystique] AGP + +pci:v0000102Bd0000051F* + ID_MODEL_FROM_DATABASE=MGA 2164W [Millennium II] AGP + +pci:v0000102Bd00000520* + ID_MODEL_FROM_DATABASE=MGA G200 + +pci:v0000102Bd00000520sv0000102Bsd0000DBC2* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000520sv0000102Bsd0000DBC8* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000520sv0000102Bsd0000DBE2* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000520sv0000102Bsd0000DBE8* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000520sv0000102Bsd0000FF03* + ID_MODEL_FROM_DATABASE=Millennium G200 SD + +pci:v0000102Bd00000520sv0000102Bsd0000FF04* + ID_MODEL_FROM_DATABASE=Marvel G200 + +pci:v0000102Bd00000521* + ID_MODEL_FROM_DATABASE=MGA G200 AGP + +pci:v0000102Bd00000521sv00001014sd0000FF03* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd000048E9* + ID_MODEL_FROM_DATABASE=Mystique G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd000048F8* + ID_MODEL_FROM_DATABASE=Millennium G200 SD AGP + +pci:v0000102Bd00000521sv0000102Bsd00004A60* + ID_MODEL_FROM_DATABASE=Millennium G200 LE AGP + +pci:v0000102Bd00000521sv0000102Bsd00004A64* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000C93C* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000C9B0* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000C9BC* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000CA60* + ID_MODEL_FROM_DATABASE=Millennium G250 LE AGP + +pci:v0000102Bd00000521sv0000102Bsd0000CA6C* + ID_MODEL_FROM_DATABASE=Millennium G250 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000DBBC* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000DBC2* + ID_MODEL_FROM_DATABASE=Millennium G200 MMS (Dual G200) + +pci:v0000102Bd00000521sv0000102Bsd0000DBC3* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBC8* + ID_MODEL_FROM_DATABASE=Millennium G200 MMS (Dual G200) + +pci:v0000102Bd00000521sv0000102Bsd0000DBD2* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBD3* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBD4* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBD5* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBD8* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBD9* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBE2* + ID_MODEL_FROM_DATABASE=Millennium G200 MMS (Quad G200) + +pci:v0000102Bd00000521sv0000102Bsd0000DBE3* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBE8* + ID_MODEL_FROM_DATABASE=Millennium G200 MMS (Quad G200) + +pci:v0000102Bd00000521sv0000102Bsd0000DBF2* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBF3* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBF4* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBF5* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBF8* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000DBF9* + ID_MODEL_FROM_DATABASE=G200 Multi-Monitor + +pci:v0000102Bd00000521sv0000102Bsd0000F806* + ID_MODEL_FROM_DATABASE=Mystique G200 Video AGP + +pci:v0000102Bd00000521sv0000102Bsd0000FF00* + ID_MODEL_FROM_DATABASE=MGA-G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000FF02* + ID_MODEL_FROM_DATABASE=Mystique G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000FF03* + ID_MODEL_FROM_DATABASE=Millennium G200 AGP + +pci:v0000102Bd00000521sv0000102Bsd0000FF04* + ID_MODEL_FROM_DATABASE=Marvel G200 AGP + +pci:v0000102Bd00000521sv0000110Asd00000032* + ID_MODEL_FROM_DATABASE=MGA-G200 AGP + +pci:v0000102Bd00000522* + ID_MODEL_FROM_DATABASE=MGA G200e [Pilot] ServerEngines (SEP1) + +pci:v0000102Bd00000522sv0000103Csd000031FA* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v0000102Bd00000525* + ID_MODEL_FROM_DATABASE=MGA G400/G450 + +pci:v0000102Bd00000525sv00000E11sd0000B16F* + ID_MODEL_FROM_DATABASE=MGA-G400 AGP + +pci:v0000102Bd00000525sv0000102Bsd00000328* + ID_MODEL_FROM_DATABASE=Millennium G400 16Mb SDRAM + +pci:v0000102Bd00000525sv0000102Bsd00000338* + ID_MODEL_FROM_DATABASE=Millennium G400 16Mb SDRAM + +pci:v0000102Bd00000525sv0000102Bsd00000378* + ID_MODEL_FROM_DATABASE=Millennium G400 32Mb SDRAM + +pci:v0000102Bd00000525sv0000102Bsd00000541* + ID_MODEL_FROM_DATABASE=Millennium G450 Dual Head + +pci:v0000102Bd00000525sv0000102Bsd00000542* + ID_MODEL_FROM_DATABASE=Millennium G450 Dual Head LX + +pci:v0000102Bd00000525sv0000102Bsd00000543* + ID_MODEL_FROM_DATABASE=Millennium G450 Single Head LX + +pci:v0000102Bd00000525sv0000102Bsd00000641* + ID_MODEL_FROM_DATABASE=Millennium G450 32Mb SDRAM Dual Head + +pci:v0000102Bd00000525sv0000102Bsd00000642* + ID_MODEL_FROM_DATABASE=Millennium G450 32Mb SDRAM Dual Head LX + +pci:v0000102Bd00000525sv0000102Bsd00000643* + ID_MODEL_FROM_DATABASE=Millennium G450 32Mb SDRAM Single Head LX + +pci:v0000102Bd00000525sv0000102Bsd000007C0* + ID_MODEL_FROM_DATABASE=Millennium G450 Dual Head LE + +pci:v0000102Bd00000525sv0000102Bsd000007C1* + ID_MODEL_FROM_DATABASE=Millennium G450 SDR Dual Head LE + +pci:v0000102Bd00000525sv0000102Bsd00000D41* + ID_MODEL_FROM_DATABASE=Millennium G450 Dual Head PCI + +pci:v0000102Bd00000525sv0000102Bsd00000D42* + ID_MODEL_FROM_DATABASE=Millennium G450 Dual Head LX PCI + +pci:v0000102Bd00000525sv0000102Bsd00000D43* + ID_MODEL_FROM_DATABASE=Millennium G450 32Mb Dual Head PCI + +pci:v0000102Bd00000525sv0000102Bsd00000E00* + ID_MODEL_FROM_DATABASE=Marvel G450 eTV + +pci:v0000102Bd00000525sv0000102Bsd00000E01* + ID_MODEL_FROM_DATABASE=Marvel G450 eTV + +pci:v0000102Bd00000525sv0000102Bsd00000E02* + ID_MODEL_FROM_DATABASE=Marvel G450 eTV + +pci:v0000102Bd00000525sv0000102Bsd00000E03* + ID_MODEL_FROM_DATABASE=Marvel G450 eTV + +pci:v0000102Bd00000525sv0000102Bsd00000F80* + ID_MODEL_FROM_DATABASE=Millennium G450 Low Profile + +pci:v0000102Bd00000525sv0000102Bsd00000F81* + ID_MODEL_FROM_DATABASE=Millennium G450 Low Profile + +pci:v0000102Bd00000525sv0000102Bsd00000F82* + ID_MODEL_FROM_DATABASE=Millennium G450 Low Profile DVI + +pci:v0000102Bd00000525sv0000102Bsd00000F83* + ID_MODEL_FROM_DATABASE=Millennium G450 Low Profile DVI + +pci:v0000102Bd00000525sv0000102Bsd000019D8* + ID_MODEL_FROM_DATABASE=Millennium G400 16Mb SGRAM + +pci:v0000102Bd00000525sv0000102Bsd000019F8* + ID_MODEL_FROM_DATABASE=Millennium G400 32Mb SGRAM + +pci:v0000102Bd00000525sv0000102Bsd00002159* + ID_MODEL_FROM_DATABASE=Millennium G400 Dual Head 16Mb + +pci:v0000102Bd00000525sv0000102Bsd00002179* + ID_MODEL_FROM_DATABASE=Millennium G400 MAX/Dual Head 32Mb + +pci:v0000102Bd00000525sv0000102Bsd0000217D* + ID_MODEL_FROM_DATABASE=Millennium G400 Dual Head Max + +pci:v0000102Bd00000525sv0000102Bsd000023C0* + ID_MODEL_FROM_DATABASE=Millennium G450 + +pci:v0000102Bd00000525sv0000102Bsd000023C1* + ID_MODEL_FROM_DATABASE=Millennium G450 + +pci:v0000102Bd00000525sv0000102Bsd000023C2* + ID_MODEL_FROM_DATABASE=Millennium G450 DVI + +pci:v0000102Bd00000525sv0000102Bsd000023C3* + ID_MODEL_FROM_DATABASE=Millennium G450 DVI + +pci:v0000102Bd00000525sv0000102Bsd00002F58* + ID_MODEL_FROM_DATABASE=Millennium G400 + +pci:v0000102Bd00000525sv0000102Bsd00002F78* + ID_MODEL_FROM_DATABASE=Millennium G400 + +pci:v0000102Bd00000525sv0000102Bsd00003693* + ID_MODEL_FROM_DATABASE=Marvel G400 AGP + +pci:v0000102Bd00000525sv0000102Bsd00005DD0* + ID_MODEL_FROM_DATABASE=4Sight II + +pci:v0000102Bd00000525sv0000102Bsd00005F50* + ID_MODEL_FROM_DATABASE=4Sight II + +pci:v0000102Bd00000525sv0000102Bsd00005F51* + ID_MODEL_FROM_DATABASE=4Sight II + +pci:v0000102Bd00000525sv0000102Bsd00005F52* + ID_MODEL_FROM_DATABASE=4Sight II + +pci:v0000102Bd00000525sv0000102Bsd00009010* + ID_MODEL_FROM_DATABASE=Millennium G400 Dual Head + +pci:v0000102Bd00000525sv00001458sd00000400* + ID_MODEL_FROM_DATABASE=GA-G400 + +pci:v0000102Bd00000525sv00001705sd00000001* + ID_MODEL_FROM_DATABASE=Millennium G450 32MB SGRAM + +pci:v0000102Bd00000525sv00001705sd00000002* + ID_MODEL_FROM_DATABASE=Millennium G450 16MB SGRAM + +pci:v0000102Bd00000525sv00001705sd00000003* + ID_MODEL_FROM_DATABASE=Millennium G450 32MB + +pci:v0000102Bd00000525sv00001705sd00000004* + ID_MODEL_FROM_DATABASE=Millennium G450 16MB + +pci:v0000102Bd00000527* + ID_MODEL_FROM_DATABASE=Parhelia + +pci:v0000102Bd00000527sv0000102Bsd00000840* + ID_MODEL_FROM_DATABASE=Parhelia 128Mb + +pci:v0000102Bd00000527sv0000102Bsd00000850* + ID_MODEL_FROM_DATABASE=Parhelia 256MB + +pci:v0000102Bd00000527sv0000102Bsd00000870* + ID_MODEL_FROM_DATABASE=MED2mp-DVI + +pci:v0000102Bd00000527sv0000102Bsd00000880* + ID_MODEL_FROM_DATABASE=P-256 Edge Overlap Controller + +pci:v0000102Bd00000528* + ID_MODEL_FROM_DATABASE=Parhelia + +pci:v0000102Bd00000528sv0000102Bsd00001020* + ID_MODEL_FROM_DATABASE=Parhelia 128MB + +pci:v0000102Bd00000528sv0000102Bsd00001030* + ID_MODEL_FROM_DATABASE=Parhelia 256 MB Dual DVI + +pci:v0000102Bd00000528sv0000102Bsd00001040* + ID_MODEL_FROM_DATABASE=MED2mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001050* + ID_MODEL_FROM_DATABASE=Sono S20 + +pci:v0000102Bd00000528sv0000102Bsd00001060* + ID_MODEL_FROM_DATABASE=PJ-30L + +pci:v0000102Bd00000528sv0000102Bsd00001070* + ID_MODEL_FROM_DATABASE=PJ-40L + +pci:v0000102Bd00000528sv0000102Bsd00001421* + ID_MODEL_FROM_DATABASE=MED5mp + +pci:v0000102Bd00000528sv0000102Bsd00001431* + ID_MODEL_FROM_DATABASE=MED3mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001451* + ID_MODEL_FROM_DATABASE=MED5mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001491* + ID_MODEL_FROM_DATABASE=MED2mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd000014B1* + ID_MODEL_FROM_DATABASE=MED3mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd000014C1* + ID_MODEL_FROM_DATABASE=MED5mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd000014E1* + ID_MODEL_FROM_DATABASE=Parhelia PCI 256MB + +pci:v0000102Bd00000528sv0000102Bsd000014F1* + ID_MODEL_FROM_DATABASE=Parhelia Precision SGT + +pci:v0000102Bd00000528sv0000102Bsd00001501* + ID_MODEL_FROM_DATABASE=ATC-4MP + +pci:v0000102Bd00000528sv0000102Bsd00001511* + ID_MODEL_FROM_DATABASE=ATC-4MP + +pci:v0000102Bd00000528sv0000102Bsd00001521* + ID_MODEL_FROM_DATABASE=TheatreVUE T30 + +pci:v0000102Bd00000528sv0000102Bsd00001531* + ID_MODEL_FROM_DATABASE=TheatreVUE T20 + +pci:v0000102Bd00000528sv0000102Bsd00001541* + ID_MODEL_FROM_DATABASE=MED2mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001551* + ID_MODEL_FROM_DATABASE=MED3mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001561* + ID_MODEL_FROM_DATABASE=MED5mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00001571* + ID_MODEL_FROM_DATABASE=Parhelia DL256 PCI + +pci:v0000102Bd00000528sv0000102Bsd00001591* + ID_MODEL_FROM_DATABASE=Parhelia Precision SDT + +pci:v0000102Bd00000528sv0000102Bsd000015A1* + ID_MODEL_FROM_DATABASE=MED4mp-DVI + +pci:v0000102Bd00000528sv0000102Bsd00002011* + ID_MODEL_FROM_DATABASE=Parhelia HR256 + +pci:v0000102Bd00000528sv0000102Bsd00002021* + ID_MODEL_FROM_DATABASE=QID Pro + +pci:v0000102Bd00000528sv0000102Bsd00002061* + ID_MODEL_FROM_DATABASE=PJ-40LP + +pci:v0000102Bd00000528sv0000102Bsd00002081* + ID_MODEL_FROM_DATABASE=EWS Quad + +pci:v0000102Bd00000528sv0000102Bsd00002411* + ID_MODEL_FROM_DATABASE=PPX-OUT8 + +pci:v0000102Bd00000528sv0000102Bsd00002421* + ID_MODEL_FROM_DATABASE=VPX-OUT8 + +pci:v0000102Bd00000528sv0000102Bsd00002441* + ID_MODEL_FROM_DATABASE=PPX-OUT4 + +pci:v0000102Bd00000528sv0000102Bsd00002451* + ID_MODEL_FROM_DATABASE=VPX-OUT4 + +pci:v0000102Bd00000528sv0000102Bsd00002491* + ID_MODEL_FROM_DATABASE=LPX-OUT4 + +pci:v0000102Bd00000530* + ID_MODEL_FROM_DATABASE=MGA G200EV + +pci:v0000102Bd00000532* + ID_MODEL_FROM_DATABASE=MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv00001028sd000002A4* + ID_MODEL_FROM_DATABASE=PowerEdge T310 MGA G200eW WPCM450 + +pci:v0000102Bd00000532sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v0000102Bd00000533* + ID_MODEL_FROM_DATABASE=MGA G200EH + +pci:v0000102Bd00000533sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000102Bd00000534* + ID_MODEL_FROM_DATABASE=G200eR2 + +pci:v0000102Bd00000540* + ID_MODEL_FROM_DATABASE=M91XX + +pci:v0000102Bd00000540sv0000102Bsd00002080* + ID_MODEL_FROM_DATABASE=M9140 LP PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd000020C0* + ID_MODEL_FROM_DATABASE=Xenia + +pci:v0000102Bd00000540sv0000102Bsd000020C1* + ID_MODEL_FROM_DATABASE=Xenia Pro + +pci:v0000102Bd00000540sv0000102Bsd00002100* + ID_MODEL_FROM_DATABASE=M9120 PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd00002140* + ID_MODEL_FROM_DATABASE=M9125 PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd00002180* + ID_MODEL_FROM_DATABASE=M9120 Plus LP PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd000021C0* + ID_MODEL_FROM_DATABASE=M9120 Plus LP PCIe x1 + +pci:v0000102Bd00000540sv0000102Bsd00002200* + ID_MODEL_FROM_DATABASE=VDA1164 Output Board + +pci:v0000102Bd00000540sv0000102Bsd00002240* + ID_MODEL_FROM_DATABASE=M9148 LP PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd00002241* + ID_MODEL_FROM_DATABASE=M9138 LP PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd00002280* + ID_MODEL_FROM_DATABASE=M9188 ATX PCIe x16 + +pci:v0000102Bd00000540sv0000102Bsd000022C0* + ID_MODEL_FROM_DATABASE=M9128 LP PCIe x16 + +pci:v0000102Bd00000D10* + ID_MODEL_FROM_DATABASE=MGA Ultima/Impression + +pci:v0000102Bd00001000* + ID_MODEL_FROM_DATABASE=MGA G100 [Productiva] + +pci:v0000102Bd00001000sv0000102Bsd0000FF01* + ID_MODEL_FROM_DATABASE=Productiva G100 + +pci:v0000102Bd00001000sv0000102Bsd0000FF05* + ID_MODEL_FROM_DATABASE=Productiva G100 Multi-Monitor + +pci:v0000102Bd00001001* + ID_MODEL_FROM_DATABASE=MGA G100 [Productiva] AGP + +pci:v0000102Bd00001001sv0000102Bsd00001001* + ID_MODEL_FROM_DATABASE=MGA-G100 AGP + +pci:v0000102Bd00001001sv0000102Bsd0000FF00* + ID_MODEL_FROM_DATABASE=MGA-G100 AGP + +pci:v0000102Bd00001001sv0000102Bsd0000FF01* + ID_MODEL_FROM_DATABASE=MGA-G100 Productiva AGP + +pci:v0000102Bd00001001sv0000102Bsd0000FF03* + ID_MODEL_FROM_DATABASE=Millennium G100 AGP + +pci:v0000102Bd00001001sv0000102Bsd0000FF04* + ID_MODEL_FROM_DATABASE=MGA-G100 AGP + +pci:v0000102Bd00001001sv0000102Bsd0000FF05* + ID_MODEL_FROM_DATABASE=MGA-G100 Productiva AGP Multi-Monitor + +pci:v0000102Bd00001001sv0000110Asd0000001E* + ID_MODEL_FROM_DATABASE=MGA-G100 AGP + +pci:v0000102Bd00002007* + ID_MODEL_FROM_DATABASE=MGA Mistral + +pci:v0000102Bd00002527* + ID_MODEL_FROM_DATABASE=Millennium G550 + +pci:v0000102Bd00002527sv0000102Bsd00000F83* + ID_MODEL_FROM_DATABASE=Millennium G550 + +pci:v0000102Bd00002527sv0000102Bsd00000F84* + ID_MODEL_FROM_DATABASE=Millennium G550 Dual Head DDR 32Mb + +pci:v0000102Bd00002527sv0000102Bsd00001E41* + ID_MODEL_FROM_DATABASE=Millennium G550 + +pci:v0000102Bd00002527sv0000102Bsd00002300* + ID_MODEL_FROM_DATABASE=Millennium G550 LP PCIE + +pci:v0000102Bd00002537* + ID_MODEL_FROM_DATABASE=Millenium P650/P750 + +pci:v0000102Bd00002537sv0000102Bsd00001820* + ID_MODEL_FROM_DATABASE=Millennium P750 64MB + +pci:v0000102Bd00002537sv0000102Bsd00001830* + ID_MODEL_FROM_DATABASE=Millennium P650 64MB + +pci:v0000102Bd00002537sv0000102Bsd00001850* + ID_MODEL_FROM_DATABASE=RAD2mp + +pci:v0000102Bd00002537sv0000102Bsd00001860* + ID_MODEL_FROM_DATABASE=RAD3mp + +pci:v0000102Bd00002537sv0000102Bsd00001880* + ID_MODEL_FROM_DATABASE=Sono S10 + +pci:v0000102Bd00002537sv0000102Bsd00001C10* + ID_MODEL_FROM_DATABASE=QID 128MB + +pci:v0000102Bd00002537sv0000102Bsd00002811* + ID_MODEL_FROM_DATABASE=Millennium P650 Low-profile PCI 64MB + +pci:v0000102Bd00002537sv0000102Bsd00002821* + ID_MODEL_FROM_DATABASE=Millenium P650 Low-profile PCI + +pci:v0000102Bd00002537sv0000102Bsd00002841* + ID_MODEL_FROM_DATABASE=RAD PCI + +pci:v0000102Bd00002537sv0000102Bsd00002851* + ID_MODEL_FROM_DATABASE=Spectrum PCI + +pci:v0000102Bd00002537sv0000102Bsd00002871* + ID_MODEL_FROM_DATABASE=EpicA TC2 + +pci:v0000102Bd00002537sv0000102Bsd00002C11* + ID_MODEL_FROM_DATABASE=QID Low-profile PCI + +pci:v0000102Bd00002537sv0000102Bsd00002C21* + ID_MODEL_FROM_DATABASE=QID LP PCI LW + +pci:v0000102Bd00002537sv0000102Bsd00002C31* + ID_MODEL_FROM_DATABASE=QID LP PCI + +pci:v0000102Bd00002537sv0000102Bsd00002C41* + ID_MODEL_FROM_DATABASE=EpicA TC4 + +pci:v0000102Bd00002537sv0000102Bsd00003001* + ID_MODEL_FROM_DATABASE=Extio F1400 + +pci:v0000102Bd00002537sv0000102Bsd00003011* + ID_MODEL_FROM_DATABASE=Extio F1220 + +pci:v0000102Bd00002537sv0000102Bsd00003041* + ID_MODEL_FROM_DATABASE=RG-200DL + +pci:v0000102Bd00002537sv0000102Bsd00003051* + ID_MODEL_FROM_DATABASE=RG-400SL + +pci:v0000102Bd00002537sv0000102Bsd00003061* + ID_MODEL_FROM_DATABASE=Extio F1420 + +pci:v0000102Bd00002537sv0000102Bsd00003081* + ID_MODEL_FROM_DATABASE=Extio F1240 + +pci:v0000102Bd00002538* + ID_MODEL_FROM_DATABASE=Millenium P650 PCIe + +pci:v0000102Bd00002538sv0000102Bsd00000847* + ID_MODEL_FROM_DATABASE=RAD PCIe + +pci:v0000102Bd00002538sv0000102Bsd000008C7* + ID_MODEL_FROM_DATABASE=Millennium P650 PCIe 128MB + +pci:v0000102Bd00002538sv0000102Bsd00000907* + ID_MODEL_FROM_DATABASE=Millennium P650 PCIe 64MB + +pci:v0000102Bd00002538sv0000102Bsd00000947* + ID_MODEL_FROM_DATABASE=Parhelia APVe + +pci:v0000102Bd00002538sv0000102Bsd00000987* + ID_MODEL_FROM_DATABASE=ATC PCIe 4MP + +pci:v0000102Bd00002538sv0000102Bsd00001047* + ID_MODEL_FROM_DATABASE=Millennium P650 LP PCIe 128MB + +pci:v0000102Bd00002538sv0000102Bsd00001087* + ID_MODEL_FROM_DATABASE=Millennium P650 LP PCIe 64MB + +pci:v0000102Bd00002538sv0000102Bsd00001801* + ID_MODEL_FROM_DATABASE=Millenium P650 PCIe x1 + +pci:v0000102Bd00002538sv0000102Bsd00002538* + ID_MODEL_FROM_DATABASE=Parhelia APVe + +pci:v0000102Bd00002538sv0000102Bsd00003007* + ID_MODEL_FROM_DATABASE=QID Low-profile PCIe + +pci:v0000102Bd00002538sv0000102Bsd00003087* + ID_MODEL_FROM_DATABASE=Aurora VX3mp + +pci:v0000102Bd00002538sv0000102Bsd000030C7* + ID_MODEL_FROM_DATABASE=QID LP PCIe + +pci:v0000102Bd00002539* + ID_MODEL_FROM_DATABASE=Millennium P690 + +pci:v0000102Bd00002539sv0000102Bsd00000040* + ID_MODEL_FROM_DATABASE=Millenium P690 PCIe x16 + +pci:v0000102Bd00002539sv0000102Bsd00000042* + ID_MODEL_FROM_DATABASE=ONYX + +pci:v0000102Bd00002539sv0000102Bsd00000043* + ID_MODEL_FROM_DATABASE=SPECTRA + +pci:v0000102Bd00002539sv0000102Bsd00000080* + ID_MODEL_FROM_DATABASE=Millenium P690 Plus LP PCIe x16 + +pci:v0000102Bd00002539sv0000102Bsd00000081* + ID_MODEL_FROM_DATABASE=Millenium P690 LP PCIe x16 + +pci:v0000102Bd00002539sv0000102Bsd00000082* + ID_MODEL_FROM_DATABASE=RAD LPX PCIe x16 + +pci:v0000102Bd00002539sv0000102Bsd000000C0* + ID_MODEL_FROM_DATABASE=Millenium P690 Plus LP PCI + +pci:v0000102Bd00002539sv0000102Bsd000000C2* + ID_MODEL_FROM_DATABASE=Millenium P690 LP PCI + +pci:v0000102Bd00002539sv0000102Bsd000000C3* + ID_MODEL_FROM_DATABASE=RAD LPX PCI + +pci:v0000102Bd00002539sv0000102Bsd00000101* + ID_MODEL_FROM_DATABASE=Millenium P690 PCI + +pci:v0000102Bd00002539sv0000102Bsd00000140* + ID_MODEL_FROM_DATABASE=Millenium P690 LP PCIe x1 + +pci:v0000102Bd00002539sv0000102Bsd00000180* + ID_MODEL_FROM_DATABASE=Display Wall IP Decode 128 MB + +pci:v0000102Bd00004164* + ID_MODEL_FROM_DATABASE=Morphis QxT frame grabber + +pci:v0000102Bd000043B4* + ID_MODEL_FROM_DATABASE=Morphis Qxt encoding engine + +pci:v0000102Bd00004510* + ID_MODEL_FROM_DATABASE=Morphis COM port + +pci:v0000102Bd00004536* + ID_MODEL_FROM_DATABASE=VIA Framegrabber + +pci:v0000102Bd00004686* + ID_MODEL_FROM_DATABASE=Concord GX (customized Intel 82541) + +pci:v0000102Bd0000475B* + ID_MODEL_FROM_DATABASE=Solios eCL/XCL-B frame grabber + +pci:v0000102Bd0000475D* + ID_MODEL_FROM_DATABASE=Vio frame grabber family + +pci:v0000102Bd0000475Dsv0000102Bsd00004B90* + ID_MODEL_FROM_DATABASE=Vio Duo frame grabber (single channel) + +pci:v0000102Bd0000475Dsv0000102Bsd00004B91* + ID_MODEL_FROM_DATABASE=Vio Duo frame grabber + +pci:v0000102Bd0000475Dsv0000102Bsd00004B92* + ID_MODEL_FROM_DATABASE=Vio Analog frame grabber + +pci:v0000102Bd0000475Dsv0000102Bsd00004B93* + ID_MODEL_FROM_DATABASE=Vio SDI Frame Grabber + +pci:v0000102Bd0000475Dsv0000102Bsd00004B94* + ID_MODEL_FROM_DATABASE=Vio DVI-A frame grabber + +pci:v0000102Bd0000475F* + ID_MODEL_FROM_DATABASE=Solios (single-Full) CL frame grabber + +pci:v0000102Bd0000475Fsv0000102Bsd0000475F* + ID_MODEL_FROM_DATABASE=Solios eCL/XCL-F frame grabber + +pci:v0000102Bd0000475Fsv0000102Bsd00004D5F* + ID_MODEL_FROM_DATABASE=Solios eV-CL (single-Full) frame grabber + +pci:v0000102Bd0000475Fsv0000102Bsd00004E5F* + ID_MODEL_FROM_DATABASE=Solios eM-CL (single-Full) frame grabber + +pci:v0000102Bd000047A1* + ID_MODEL_FROM_DATABASE=Solios eA/XA frame grabber + +pci:v0000102Bd000047A1sv0000102Bsd00004BE0* + ID_MODEL_FROM_DATABASE=Solios eA/XA (single) frame grabber + +pci:v0000102Bd000047A1sv0000102Bsd00004BE1* + ID_MODEL_FROM_DATABASE=Solios eA/XA (dual) frame grabber + +pci:v0000102Bd000047A1sv0000102Bsd00004BE2* + ID_MODEL_FROM_DATABASE=Solios eA/XA (quad) frame grabber + +pci:v0000102Bd000047A2* + ID_MODEL_FROM_DATABASE=Solios COM port + +pci:v0000102Bd000047C1* + ID_MODEL_FROM_DATABASE=Solios (dual-Base/single-Medium) CL frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00000000* + ID_MODEL_FROM_DATABASE=Solios frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004B80* + ID_MODEL_FROM_DATABASE=Solios eCL/XCL (single-Medium) frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004B81* + ID_MODEL_FROM_DATABASE=Solios eCL/XCL (dual-Base) frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004D80* + ID_MODEL_FROM_DATABASE=Solios eV-CL (single-Medium) frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004D81* + ID_MODEL_FROM_DATABASE=Solios eV-CL (dual-Base) frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004E80* + ID_MODEL_FROM_DATABASE=Solios eM-CL (single-Medium) frame grabber + +pci:v0000102Bd000047C1sv0000102Bsd00004E81* + ID_MODEL_FROM_DATABASE=Solios eM-CL (dual-Base) frame grabber + +pci:v0000102Bd000047C2* + ID_MODEL_FROM_DATABASE=Solios COM port + +pci:v0000102Bd00004949* + ID_MODEL_FROM_DATABASE=Radient frame grabber family + +pci:v0000102Bd00004949sv0000102Bsd00000010* + ID_MODEL_FROM_DATABASE=Radient eCL (Single-full) frame grabber + +pci:v0000102Bd00004949sv0000102Bsd00000020* + ID_MODEL_FROM_DATABASE=Radient eCL (Dual-base) frame grabber + +pci:v0000102Bd00004949sv0000102Bsd00000030* + ID_MODEL_FROM_DATABASE=Radient eCL (Dual-full) frame grabber + +pci:v0000102Bd00004949sv0000102Bsd00000040* + ID_MODEL_FROM_DATABASE=Radient eCL (Quad-base) frame grabber + +pci:v0000102Bd00004949sv0000102Bsd00000050* + ID_MODEL_FROM_DATABASE=Radient eCL (Golden) frame grabber + +pci:v0000102Bd00004CDC* + ID_MODEL_FROM_DATABASE=Morphis JPEG2000 accelerator + +pci:v0000102Bd00004F54* + ID_MODEL_FROM_DATABASE=Morphis (e)Quad frame grabber + +pci:v0000102Bd00004FC5* + ID_MODEL_FROM_DATABASE=Morphis (e)Dual frame grabber + +pci:v0000102Bd00005E10* + ID_MODEL_FROM_DATABASE=Morphis aux I/O + +pci:v0000102Bd00006573* + ID_MODEL_FROM_DATABASE=Shark 10/100 Multiport SwitchNIC + +pci:v0000102C* + ID_VENDOR_FROM_DATABASE=Chips and Technologies + +pci:v0000102Cd000000B8* + ID_MODEL_FROM_DATABASE=F64310 + +pci:v0000102Cd000000C0* + ID_MODEL_FROM_DATABASE=F69000 HiQVideo + +pci:v0000102Cd000000C0sv0000102Csd000000C0* + ID_MODEL_FROM_DATABASE=F69000 HiQVideo + +pci:v0000102Cd000000C0sv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v0000102Cd000000C0sv00004C53sd00001010* + ID_MODEL_FROM_DATABASE=CP5/CR6 mainboard + +pci:v0000102Cd000000C0sv00004C53sd00001020* + ID_MODEL_FROM_DATABASE=VR6 mainboard + +pci:v0000102Cd000000C0sv00004C53sd00001030* + ID_MODEL_FROM_DATABASE=PC5 mainboard + +pci:v0000102Cd000000C0sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v0000102Cd000000C0sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v0000102Cd000000D0* + ID_MODEL_FROM_DATABASE=F65545 + +pci:v0000102Cd000000D8* + ID_MODEL_FROM_DATABASE=F65545 + +pci:v0000102Cd000000DC* + ID_MODEL_FROM_DATABASE=F65548 + +pci:v0000102Cd000000E0* + ID_MODEL_FROM_DATABASE=F65550 + +pci:v0000102Cd000000E4* + ID_MODEL_FROM_DATABASE=F65554 + +pci:v0000102Cd000000E5* + ID_MODEL_FROM_DATABASE=F65555 HiQVPro + +pci:v0000102Cd000000E5sv00000E11sd0000B049* + ID_MODEL_FROM_DATABASE=Armada 1700 Laptop Display Controller + +pci:v0000102Cd000000E5sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Satellite Pro/Satellite + +pci:v0000102Cd000000F0* + ID_MODEL_FROM_DATABASE=F68554 + +pci:v0000102Cd000000F4* + ID_MODEL_FROM_DATABASE=F68554 HiQVision + +pci:v0000102Cd000000F5* + ID_MODEL_FROM_DATABASE=F68555 + +pci:v0000102Cd00000C30* + ID_MODEL_FROM_DATABASE=F69030 + +pci:v0000102Cd00000C30sv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v0000102Cd00000C30sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v0000102Cd00000C30sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v0000102Cd00000C30sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v0000102D* + ID_VENDOR_FROM_DATABASE=Wyse Technology Inc. + +pci:v0000102Dd000050DC* + ID_MODEL_FROM_DATABASE=3328 Audio + +pci:v0000102E* + ID_VENDOR_FROM_DATABASE=Olivetti Advanced Technology + +pci:v0000102F* + ID_VENDOR_FROM_DATABASE=Toshiba America + +pci:v0000102Fd00000009* + ID_MODEL_FROM_DATABASE=r4x00 + +pci:v0000102Fd0000000A* + ID_MODEL_FROM_DATABASE=TX3927 MIPS RISC PCI Controller + +pci:v0000102Fd00000020* + ID_MODEL_FROM_DATABASE=ATM Meteor 155 + +pci:v0000102Fd00000020sv0000102Fsd000000F8* + ID_MODEL_FROM_DATABASE=ATM Meteor 155 + +pci:v0000102Fd00000030* + ID_MODEL_FROM_DATABASE=TC35815CF PCI 10/100 Mbit Ethernet Controller + +pci:v0000102Fd00000031* + ID_MODEL_FROM_DATABASE=TC35815CF PCI 10/100 Mbit Ethernet Controller with WOL + +pci:v0000102Fd00000032* + ID_MODEL_FROM_DATABASE=TC35815CF PCI 10/100 Mbit Ethernet Controller on TX4939 + +pci:v0000102Fd00000105* + ID_MODEL_FROM_DATABASE=TC86C001 [goku-s] IDE + +pci:v0000102Fd00000106* + ID_MODEL_FROM_DATABASE=TC86C001 [goku-s] USB 1.1 Host + +pci:v0000102Fd00000107* + ID_MODEL_FROM_DATABASE=TC86C001 [goku-s] USB Device Controller + +pci:v0000102Fd00000108* + ID_MODEL_FROM_DATABASE=TC86C001 [goku-s] I2C/SIO/GPIO Controller + +pci:v0000102Fd00000180* + ID_MODEL_FROM_DATABASE=TX4927/38 MIPS RISC PCI Controller + +pci:v0000102Fd00000181* + ID_MODEL_FROM_DATABASE=TX4925 MIPS RISC PCI Controller + +pci:v0000102Fd00000182* + ID_MODEL_FROM_DATABASE=TX4937 MIPS RISC PCI Controller + +pci:v0000102Fd000001B4* + ID_MODEL_FROM_DATABASE=Celleb platform IDE interface + +pci:v0000102Fd000001B5* + ID_MODEL_FROM_DATABASE=SCC USB 2.0 EHCI controller + +pci:v0000102Fd000001B6* + ID_MODEL_FROM_DATABASE=SCC USB 1.1 OHCI controller + +pci:v00001030* + ID_VENDOR_FROM_DATABASE=TMC Research + +pci:v00001031* + ID_VENDOR_FROM_DATABASE=Miro Computer Products AG + +pci:v00001031d00005601* + ID_MODEL_FROM_DATABASE=DC20 ASIC + +pci:v00001031d00005607* + ID_MODEL_FROM_DATABASE=Video I/O & motion JPEG compressor + +pci:v00001031d00005631* + ID_MODEL_FROM_DATABASE=Media 3D + +pci:v00001031d00006057* + ID_MODEL_FROM_DATABASE=MiroVideo DC10/DC30+ + +pci:v00001032* + ID_VENDOR_FROM_DATABASE=Compaq + +pci:v00001033* + ID_VENDOR_FROM_DATABASE=NEC Corporation + +pci:v00001033d00000000* + ID_MODEL_FROM_DATABASE=Vr4181A USB Host or Function Control Unit + +pci:v00001033d00000001* + ID_MODEL_FROM_DATABASE=PCI to 486-like bus Bridge + +pci:v00001033d00000002* + ID_MODEL_FROM_DATABASE=PCI to VL98 Bridge + +pci:v00001033d00000003* + ID_MODEL_FROM_DATABASE=ATM Controller + +pci:v00001033d00000004* + ID_MODEL_FROM_DATABASE=R4000 PCI Bridge + +pci:v00001033d00000005* + ID_MODEL_FROM_DATABASE=PCI to 486-like bus Bridge + +pci:v00001033d00000006* + ID_MODEL_FROM_DATABASE=PC-9800 Graphic Accelerator + +pci:v00001033d00000007* + ID_MODEL_FROM_DATABASE=PCI to UX-Bus Bridge + +pci:v00001033d00000008* + ID_MODEL_FROM_DATABASE=PC-9800 Graphic Accelerator + +pci:v00001033d00000009* + ID_MODEL_FROM_DATABASE=PCI to PC9800 Core-Graph Bridge + +pci:v00001033d00000016* + ID_MODEL_FROM_DATABASE=PCI to VL Bridge + +pci:v00001033d0000001A* + ID_MODEL_FROM_DATABASE=[Nile II] + +pci:v00001033d00000021* + ID_MODEL_FROM_DATABASE=Vrc4373 [Nile I] + +pci:v00001033d00000029* + ID_MODEL_FROM_DATABASE=PowerVR PCX1 + +pci:v00001033d0000002A* + ID_MODEL_FROM_DATABASE=PowerVR 3D + +pci:v00001033d0000002C* + ID_MODEL_FROM_DATABASE=Star Alpha 2 + +pci:v00001033d0000002D* + ID_MODEL_FROM_DATABASE=PCI to C-bus Bridge + +pci:v00001033d00000035* + ID_MODEL_FROM_DATABASE=OHCI USB Controller + +pci:v00001033d00000035sv00001033sd00000035* + ID_MODEL_FROM_DATABASE=USB Controller + +pci:v00001033d00000035sv0000103Csd00001293* + ID_MODEL_FROM_DATABASE=USB add-in card + +pci:v00001033d00000035sv0000103Csd00001294* + ID_MODEL_FROM_DATABASE=USB 2.0 add-in card + +pci:v00001033d00000035sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=USB + +pci:v00001033d00000035sv000012EEsd00007000* + ID_MODEL_FROM_DATABASE=Root Hub + +pci:v00001033d00000035sv000014C2sd00000105* + ID_MODEL_FROM_DATABASE=PTI-205N USB 2.0 Host Controller + +pci:v00001033d00000035sv00001799sd00000001* + ID_MODEL_FROM_DATABASE=Root Hub + +pci:v00001033d00000035sv00001931sd0000000A* + ID_MODEL_FROM_DATABASE=GlobeTrotter Fusion Quad Lite (PPP data) + +pci:v00001033d00000035sv00001931sd0000000B* + ID_MODEL_FROM_DATABASE=GlobeTrotter Fusion Quad Lite (GSM data) + +pci:v00001033d00000035sv0000807Dsd00000035* + ID_MODEL_FROM_DATABASE=PCI-USB2 (OHCI subsystem) + +pci:v00001033d0000003B* + ID_MODEL_FROM_DATABASE=PCI to C-bus Bridge + +pci:v00001033d0000003E* + ID_MODEL_FROM_DATABASE=NAPCCARD Cardbus Controller + +pci:v00001033d00000046* + ID_MODEL_FROM_DATABASE=PowerVR PCX2 [midas] + +pci:v00001033d0000005A* + ID_MODEL_FROM_DATABASE=Vrc5074 [Nile 4] + +pci:v00001033d00000063* + ID_MODEL_FROM_DATABASE=uPD72862 [Firewarden] IEEE1394 OHCI 1.0 Link Controller + +pci:v00001033d00000067* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 Chipset + +pci:v00001033d00000067sv00001010sd00000020* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 AGP 32Mb + +pci:v00001033d00000067sv00001010sd00000080* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 AGP 16Mb + +pci:v00001033d00000067sv00001010sd00000088* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 16Mb + +pci:v00001033d00000067sv00001010sd00000090* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 AGP 16Mb + +pci:v00001033d00000067sv00001010sd00000098* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 16Mb + +pci:v00001033d00000067sv00001010sd000000A0* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 AGP 32Mb + +pci:v00001033d00000067sv00001010sd000000A8* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 32Mb + +pci:v00001033d00000067sv00001010sd00000120* + ID_MODEL_FROM_DATABASE=PowerVR Neon 250 AGP 32Mb + +pci:v00001033d00000072* + ID_MODEL_FROM_DATABASE=uPD72874 IEEE1394 OHCI 1.1 3-port PHY-Link Ctrlr + +pci:v00001033d00000074* + ID_MODEL_FROM_DATABASE=56k Voice Modem + +pci:v00001033d00000074sv00001033sd00008014* + ID_MODEL_FROM_DATABASE=RCV56ACF 56k Voice Modem + +pci:v00001033d0000009B* + ID_MODEL_FROM_DATABASE=Vrc5476 + +pci:v00001033d000000A5* + ID_MODEL_FROM_DATABASE=VRC4173 + +pci:v00001033d000000A6* + ID_MODEL_FROM_DATABASE=VRC5477 AC97 + +pci:v00001033d000000CD* + ID_MODEL_FROM_DATABASE=uPD72870 [Firewarden] IEEE1394a OHCI 1.0 Link/3-port PHY Controller + +pci:v00001033d000000CDsv000012EEsd00008011* + ID_MODEL_FROM_DATABASE=Root hub + +pci:v00001033d000000CE* + ID_MODEL_FROM_DATABASE=uPD72871 [Firewarden] IEEE1394a OHCI 1.0 Link/1-port PHY Controller + +pci:v00001033d000000DF* + ID_MODEL_FROM_DATABASE=Vr4131 + +pci:v00001033d000000E0* + ID_MODEL_FROM_DATABASE=uPD72010x USB 2.0 Controller + +pci:v00001033d000000E0sv000012EEsd00007001* + ID_MODEL_FROM_DATABASE=Root hub + +pci:v00001033d000000E0sv000014C2sd00000205* + ID_MODEL_FROM_DATABASE=PTI-205N USB 2.0 Host Controller + +pci:v00001033d000000E0sv00001799sd00000002* + ID_MODEL_FROM_DATABASE=Root Hub + +pci:v00001033d000000E0sv0000807Dsd00001043* + ID_MODEL_FROM_DATABASE=PCI-USB2 (EHCI subsystem) + +pci:v00001033d000000E7* + ID_MODEL_FROM_DATABASE=uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller + +pci:v00001033d000000F2* + ID_MODEL_FROM_DATABASE=uPD72874 [Firewarden] IEEE1394a OHCI 1.1 Link/3-port PHY Controller + +pci:v00001033d000000F3* + ID_MODEL_FROM_DATABASE=uPD6113x Multimedia Decoder/Processor [EMMA2] + +pci:v00001033d0000010C* + ID_MODEL_FROM_DATABASE=VR7701 + +pci:v00001033d00000125* + ID_MODEL_FROM_DATABASE=uPD720400 PCI Express - PCI/PCI-X Bridge + +pci:v00001033d0000013A* + ID_MODEL_FROM_DATABASE=Dual Tuner/MPEG Encoder + +pci:v00001033d00000194* + ID_MODEL_FROM_DATABASE=uPD720200 USB 3.0 Host Controller + +pci:v00001033d00000194sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001033d00000194sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00001033d00000194sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00001033d00000194sv00001043sd00008413* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00001033d00000194sv00001B96sd00000001* + ID_MODEL_FROM_DATABASE=USB 3.0 PCIe Card + +pci:v00001033d000001E7* + ID_MODEL_FROM_DATABASE=uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller + +pci:v00001033d000001F2* + ID_MODEL_FROM_DATABASE=uPD72874 [Firewarden] IEEE1394a OHCI 1.1 Link/3-port PHY Controller + +pci:v00001034* + ID_VENDOR_FROM_DATABASE=Framatome Connectors USA Inc. + +pci:v00001035* + ID_VENDOR_FROM_DATABASE=Comp. & Comm. Research Lab + +pci:v00001036* + ID_VENDOR_FROM_DATABASE=Future Domain Corp. + +pci:v00001036d00000000* + ID_MODEL_FROM_DATABASE=TMC-18C30 [36C70] + +pci:v00001037* + ID_VENDOR_FROM_DATABASE=Hitachi Micro Systems + +pci:v00001038* + ID_VENDOR_FROM_DATABASE=AMP, Inc + +pci:v00001039* + ID_VENDOR_FROM_DATABASE=Silicon Integrated Systems [SiS] + +pci:v00001039d00000001* + ID_MODEL_FROM_DATABASE=AGP Port (virtual PCI-to-PCI bridge) + +pci:v00001039d00000002* + ID_MODEL_FROM_DATABASE=AGP Port (virtual PCI-to-PCI bridge) + +pci:v00001039d00000003* + ID_MODEL_FROM_DATABASE=AGP Port (virtual PCI-to-PCI bridge) + +pci:v00001039d00000004* + ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge + +pci:v00001039d00000006* + ID_MODEL_FROM_DATABASE=85C501/2/3 + +pci:v00001039d00000008* + ID_MODEL_FROM_DATABASE=SiS85C503/5513 (LPC Bridge) + +pci:v00001039d00000009* + ID_MODEL_FROM_DATABASE=5595 Power Management Controller + +pci:v00001039d0000000A* + ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge + +pci:v00001039d00000016* + ID_MODEL_FROM_DATABASE=SiS961/2/3 SMBus controller + +pci:v00001039d00000018* + ID_MODEL_FROM_DATABASE=SiS85C503/5513 (LPC Bridge) + +pci:v00001039d00000180* + ID_MODEL_FROM_DATABASE=RAID bus controller 180 SATA/PATA [SiS] + +pci:v00001039d00000181* + ID_MODEL_FROM_DATABASE=SATA + +pci:v00001039d00000182* + ID_MODEL_FROM_DATABASE=182 SATA/RAID Controller + +pci:v00001039d00000182sv00001734sd00001095* + ID_MODEL_FROM_DATABASE=D2030-A1 + +pci:v00001039d00000186* + ID_MODEL_FROM_DATABASE=AHCI Controller (0106) + +pci:v00001039d00000190* + ID_MODEL_FROM_DATABASE=190 Ethernet Adapter + +pci:v00001039d00000191* + ID_MODEL_FROM_DATABASE=191 Gigabit Ethernet Adapter + +pci:v00001039d00000200* + ID_MODEL_FROM_DATABASE=5597/5598/6326 VGA + +pci:v00001039d00000200sv00001039sd00000000* + ID_MODEL_FROM_DATABASE=SiS5597 SVGA (Shared RAM) + +pci:v00001039d00000204* + ID_MODEL_FROM_DATABASE=82C204 + +pci:v00001039d00000205* + ID_MODEL_FROM_DATABASE=SG86C205 + +pci:v00001039d00000300* + ID_MODEL_FROM_DATABASE=300/305 PCI/AGP VGA Display Adapter + +pci:v00001039d00000300sv0000107Dsd00002720* + ID_MODEL_FROM_DATABASE=Leadtek WinFast VR300 + +pci:v00001039d00000310* + ID_MODEL_FROM_DATABASE=315H PCI/AGP VGA Display Adapter + +pci:v00001039d00000315* + ID_MODEL_FROM_DATABASE=315 PCI/AGP VGA Display Adapter + +pci:v00001039d00000325* + ID_MODEL_FROM_DATABASE=315PRO PCI/AGP VGA Display Adapter + +pci:v00001039d00000330* + ID_MODEL_FROM_DATABASE=330 [Xabre] PCI/AGP VGA Display Adapter + +pci:v00001039d00000406* + ID_MODEL_FROM_DATABASE=85C501/2 + +pci:v00001039d00000496* + ID_MODEL_FROM_DATABASE=85C496 + +pci:v00001039d00000530* + ID_MODEL_FROM_DATABASE=530 Host + +pci:v00001039d00000540* + ID_MODEL_FROM_DATABASE=540 Host + +pci:v00001039d00000550* + ID_MODEL_FROM_DATABASE=550 Host + +pci:v00001039d00000597* + ID_MODEL_FROM_DATABASE=5513C + +pci:v00001039d00000601* + ID_MODEL_FROM_DATABASE=85C601 + +pci:v00001039d00000620* + ID_MODEL_FROM_DATABASE=620 Host + +pci:v00001039d00000630* + ID_MODEL_FROM_DATABASE=630 Host + +pci:v00001039d00000633* + ID_MODEL_FROM_DATABASE=633 Host + +pci:v00001039d00000635* + ID_MODEL_FROM_DATABASE=635 Host + +pci:v00001039d00000645* + ID_MODEL_FROM_DATABASE=SiS645 Host & Memory & AGP Controller + +pci:v00001039d00000646* + ID_MODEL_FROM_DATABASE=SiS645DX Host & Memory & AGP Controller + +pci:v00001039d00000648* + ID_MODEL_FROM_DATABASE=645xx + +pci:v00001039d00000649* + ID_MODEL_FROM_DATABASE=SiS649 Host + +pci:v00001039d00000650* + ID_MODEL_FROM_DATABASE=650/M650 Host + +pci:v00001039d00000651* + ID_MODEL_FROM_DATABASE=651 Host + +pci:v00001039d00000655* + ID_MODEL_FROM_DATABASE=655 Host + +pci:v00001039d00000660* + ID_MODEL_FROM_DATABASE=660 Host + +pci:v00001039d00000661* + ID_MODEL_FROM_DATABASE=661FX/M661FX/M661MX Host + +pci:v00001039d00000662* + ID_MODEL_FROM_DATABASE=662 Host + +pci:v00001039d00000671* + ID_MODEL_FROM_DATABASE=671MX + +pci:v00001039d00000730* + ID_MODEL_FROM_DATABASE=730 Host + +pci:v00001039d00000733* + ID_MODEL_FROM_DATABASE=733 Host + +pci:v00001039d00000735* + ID_MODEL_FROM_DATABASE=735 Host + +pci:v00001039d00000740* + ID_MODEL_FROM_DATABASE=740 Host + +pci:v00001039d00000741* + ID_MODEL_FROM_DATABASE=741/741GX/M741 Host + +pci:v00001039d00000741sv00001849sd00000741* + ID_MODEL_FROM_DATABASE=K7S41/K7S41GX motherboard + +pci:v00001039d00000745* + ID_MODEL_FROM_DATABASE=745 Host + +pci:v00001039d00000746* + ID_MODEL_FROM_DATABASE=746 Host + +pci:v00001039d00000755* + ID_MODEL_FROM_DATABASE=755 Host + +pci:v00001039d00000760* + ID_MODEL_FROM_DATABASE=760/M760 Host + +pci:v00001039d00000761* + ID_MODEL_FROM_DATABASE=761/M761 Host + +pci:v00001039d00000761sv00001734sd00001099* + ID_MODEL_FROM_DATABASE=D2030-A1 Motherboard + +pci:v00001039d00000900* + ID_MODEL_FROM_DATABASE=SiS900 PCI Fast Ethernet + +pci:v00001039d00000900sv00001019sd00000A14* + ID_MODEL_FROM_DATABASE=K7S5A motherboard + +pci:v00001039d00000900sv00001039sd00000900* + ID_MODEL_FROM_DATABASE=SiS900 10/100 Ethernet Adapter onboard [Asus P4SC-EA] + +pci:v00001039d00000900sv00001043sd00008035* + ID_MODEL_FROM_DATABASE=CUSI-FX motherboard + +pci:v00001039d00000900sv00001043sd000080A7* + ID_MODEL_FROM_DATABASE=Motherboard P4S800D-X + +pci:v00001039d00000900sv00001462sd00000900* + ID_MODEL_FROM_DATABASE=MS-6701 motherboard + +pci:v00001039d00000961* + ID_MODEL_FROM_DATABASE=SiS961 [MuTIOL Media IO] + +pci:v00001039d00000962* + ID_MODEL_FROM_DATABASE=SiS962 [MuTIOL Media IO] LPC Controller + +pci:v00001039d00000963* + ID_MODEL_FROM_DATABASE=SiS963 [MuTIOL Media IO] LPC Controller + +pci:v00001039d00000964* + ID_MODEL_FROM_DATABASE=SiS964 [MuTIOL Media IO] LPC Controller + +pci:v00001039d00000965* + ID_MODEL_FROM_DATABASE=SiS965 [MuTIOL Media IO] + +pci:v00001039d00000966* + ID_MODEL_FROM_DATABASE=SiS966 [MuTIOL Media IO] + +pci:v00001039d00000968* + ID_MODEL_FROM_DATABASE=SiS968 [MuTIOL Media IO] + +pci:v00001039d00001180* + ID_MODEL_FROM_DATABASE=SATA Controller / IDE mode + +pci:v00001039d00001182* + ID_MODEL_FROM_DATABASE=SATA Controller / RAID mode + +pci:v00001039d00001183* + ID_MODEL_FROM_DATABASE=SATA Controller / IDE mode + +pci:v00001039d00001184* + ID_MODEL_FROM_DATABASE=AHCI Controller / RAID mode + +pci:v00001039d00001185* + ID_MODEL_FROM_DATABASE=AHCI IDE Controller (0106) + +pci:v00001039d00003602* + ID_MODEL_FROM_DATABASE=83C602 + +pci:v00001039d00005107* + ID_MODEL_FROM_DATABASE=5107 + +pci:v00001039d00005300* + ID_MODEL_FROM_DATABASE=SiS540 PCI Display Adapter + +pci:v00001039d00005315* + ID_MODEL_FROM_DATABASE=550 PCI/AGP VGA Display Adapter + +pci:v00001039d00005401* + ID_MODEL_FROM_DATABASE=486 PCI Chipset + +pci:v00001039d00005511* + ID_MODEL_FROM_DATABASE=5511/5512 + +pci:v00001039d00005513* + ID_MODEL_FROM_DATABASE=5513 IDE Controller + +pci:v00001039d00005513sv00001019sd00000970* + ID_MODEL_FROM_DATABASE=P6STP-FL motherboard + +pci:v00001039d00005513sv00001039sd00005513* + ID_MODEL_FROM_DATABASE=SiS5513 EIDE Controller (A,B step) + +pci:v00001039d00005513sv00001043sd00008035* + ID_MODEL_FROM_DATABASE=CUSI-FX motherboard + +pci:v00001039d00005513sv00001462sd00007010* + ID_MODEL_FROM_DATABASE=MS-6701 motherboard + +pci:v00001039d00005513sv00001631sd00005513* + ID_MODEL_FROM_DATABASE=GA-8SIML Rev1.0 Motherboard + +pci:v00001039d00005513sv00001734sd00001095* + ID_MODEL_FROM_DATABASE=D2030-A1 Motherboard + +pci:v00001039d00005517* + ID_MODEL_FROM_DATABASE=5517 + +pci:v00001039d00005571* + ID_MODEL_FROM_DATABASE=5571 + +pci:v00001039d00005581* + ID_MODEL_FROM_DATABASE=5581 Pentium Chipset + +pci:v00001039d00005582* + ID_MODEL_FROM_DATABASE=5582 + +pci:v00001039d00005591* + ID_MODEL_FROM_DATABASE=5591/5592 Host + +pci:v00001039d00005596* + ID_MODEL_FROM_DATABASE=5596 Pentium Chipset + +pci:v00001039d00005597* + ID_MODEL_FROM_DATABASE=5597 [SiS5582] + +pci:v00001039d00005600* + ID_MODEL_FROM_DATABASE=5600 Host + +pci:v00001039d00006204* + ID_MODEL_FROM_DATABASE=Video decoder & MPEG interface + +pci:v00001039d00006205* + ID_MODEL_FROM_DATABASE=VGA Controller + +pci:v00001039d00006236* + ID_MODEL_FROM_DATABASE=6236 3D-AGP + +pci:v00001039d00006300* + ID_MODEL_FROM_DATABASE=630/730 PCI/AGP VGA Display Adapter + +pci:v00001039d00006300sv00001019sd00000970* + ID_MODEL_FROM_DATABASE=P6STP-FL motherboard + +pci:v00001039d00006300sv00001043sd00008035* + ID_MODEL_FROM_DATABASE=CUSI-FX motherboard + +pci:v00001039d00006300sv0000104Dsd000080E2* + ID_MODEL_FROM_DATABASE=VAIO PCV-J200 + +pci:v00001039d00006306* + ID_MODEL_FROM_DATABASE=530/620 PCI/AGP VGA Display Adapter + +pci:v00001039d00006325* + ID_MODEL_FROM_DATABASE=65x/M650/740 PCI/AGP VGA Display Adapter + +pci:v00001039d00006325sv00001039sd00006325* + ID_MODEL_FROM_DATABASE=SiS 651 onboard [Asus P4SC-EA] + +pci:v00001039d00006325sv00001631sd00001004* + ID_MODEL_FROM_DATABASE=SiS 651C onboard [Gigabyte GA-8SIML Rev1.0] + +pci:v00001039d00006326* + ID_MODEL_FROM_DATABASE=86C326 5598/6326 + +pci:v00001039d00006326sv00001039sd00006326* + ID_MODEL_FROM_DATABASE=SiS6326 GUI Accelerator + +pci:v00001039d00006326sv00001092sd00000A50* + ID_MODEL_FROM_DATABASE=SpeedStar A50 + +pci:v00001039d00006326sv00001092sd00000A70* + ID_MODEL_FROM_DATABASE=SpeedStar A70 + +pci:v00001039d00006326sv00001092sd00004910* + ID_MODEL_FROM_DATABASE=SpeedStar A70 + +pci:v00001039d00006326sv00001092sd00004920* + ID_MODEL_FROM_DATABASE=SpeedStar A70 + +pci:v00001039d00006326sv000010B0sd00006326* + ID_MODEL_FROM_DATABASE=S6110-B (AGP) + +pci:v00001039d00006326sv00001569sd00006326* + ID_MODEL_FROM_DATABASE=SiS6326 GUI Accelerator + +pci:v00001039d00006330* + ID_MODEL_FROM_DATABASE=661/741/760 PCI/AGP or 662/761Gx PCIE VGA Display Adapter + +pci:v00001039d00006330sv00001039sd00006330* + ID_MODEL_FROM_DATABASE=[M]661xX/[M]741[GX]/[M]760 PCI/AGP VGA Adapter + +pci:v00001039d00006330sv00001043sd00008113* + ID_MODEL_FROM_DATABASE=SiS Real 256E (ASUS P5S800-VM motherboard) + +pci:v00001039d00006330sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=SiS661FX GUI 2D/3D Accelerator + +pci:v00001039d00006330sv00001734sd00001099* + ID_MODEL_FROM_DATABASE=D2030-A1 + +pci:v00001039d00006350* + ID_MODEL_FROM_DATABASE=770/670 PCIE VGA Display Adapter + +pci:v00001039d00006351* + ID_MODEL_FROM_DATABASE=771/671 PCIE VGA Display Adapter + +pci:v00001039d00007001* + ID_MODEL_FROM_DATABASE=USB 1.1 Controller + +pci:v00001039d00007001sv00001019sd00000A14* + ID_MODEL_FROM_DATABASE=K7S5A motherboard + +pci:v00001039d00007001sv00001039sd00007000* + ID_MODEL_FROM_DATABASE=Onboard USB Controller + +pci:v00001039d00007001sv00001462sd00005470* + ID_MODEL_FROM_DATABASE=ECS K7SOM+ motherboard + +pci:v00001039d00007001sv00001462sd00007010* + ID_MODEL_FROM_DATABASE=MS-6701 motherboard + +pci:v00001039d00007001sv00001734sd00001095* + ID_MODEL_FROM_DATABASE=D2030-A1 Motherboard + +pci:v00001039d00007002* + ID_MODEL_FROM_DATABASE=USB 2.0 Controller + +pci:v00001039d00007002sv00001462sd00005470* + ID_MODEL_FROM_DATABASE=K7SOM+ 5.2C Motherboard + +pci:v00001039d00007002sv00001462sd00007010* + ID_MODEL_FROM_DATABASE=MS-6701 motherboard + +pci:v00001039d00007002sv00001509sd00007002* + ID_MODEL_FROM_DATABASE=Onboard USB Controller + +pci:v00001039d00007002sv00001734sd00001095* + ID_MODEL_FROM_DATABASE=D2030-A1 + +pci:v00001039d00007007* + ID_MODEL_FROM_DATABASE=FireWire Controller + +pci:v00001039d00007007sv00001462sd0000701D* + ID_MODEL_FROM_DATABASE=MS-6701 + +pci:v00001039d00007012* + ID_MODEL_FROM_DATABASE=SiS7012 AC'97 Sound Controller + +pci:v00001039d00007012sv00001019sd00000F05* + ID_MODEL_FROM_DATABASE=A928 (i-Buddie) + +pci:v00001039d00007012sv00001039sd00007012* + ID_MODEL_FROM_DATABASE=SiS 7012 onboard [Asus P4SC-EA] AC'97 Sound Controller + +pci:v00001039d00007012sv00001043sd0000818F* + ID_MODEL_FROM_DATABASE=A8S-X Motherboard + +pci:v00001039d00007012sv000013F6sd00000300* + ID_MODEL_FROM_DATABASE=CMI9739(A) on ECS K7SOM+ motherboard + +pci:v00001039d00007012sv00001462sd00005850* + ID_MODEL_FROM_DATABASE=MSI 648 Max (MS-6585) + +pci:v00001039d00007012sv00001462sd00007010* + ID_MODEL_FROM_DATABASE=MS-6701 motherboard + +pci:v00001039d00007012sv000015BDsd00001001* + ID_MODEL_FROM_DATABASE=DFI 661FX motherboard + +pci:v00001039d00007012sv00001734sd0000109F* + ID_MODEL_FROM_DATABASE=D2030-A1 Motherboard + +pci:v00001039d00007012sv00001849sd00007012* + ID_MODEL_FROM_DATABASE=K7S41GX motherboard + +pci:v00001039d00007013* + ID_MODEL_FROM_DATABASE=AC'97 Modem Controller + +pci:v00001039d00007016* + ID_MODEL_FROM_DATABASE=SiS7016 PCI Fast Ethernet Adapter + +pci:v00001039d00007016sv00001039sd00007016* + ID_MODEL_FROM_DATABASE=SiS7016 10/100 Ethernet Adapter + +pci:v00001039d00007018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001014sd000001B6* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001014sd000001B7* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001019sd00007018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001025sd0000000E* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001025sd00000018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001039sd00007018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001043sd00001453* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001043sd0000800B* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000104Dsd000080E2* + ID_MODEL_FROM_DATABASE=VAIO PCV-J200 + +pci:v00001039d00007018sv00001054sd00007018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000107Dsd00005330* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000107Dsd00005350* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001170sd00003209* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001462sd0000400A* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv000014A4sd00002089* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv000014CDsd00002194* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv000014FFsd00001100* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000152Dsd00008808* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001558sd00001103* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001558sd00002200* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv00001563sd00007018* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv000015C5sd00000111* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000270Fsd0000A171* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007018sv0000A0A0sd00000022* + ID_MODEL_FROM_DATABASE=SiS PCI Audio Accelerator + +pci:v00001039d00007019* + ID_MODEL_FROM_DATABASE=SiS7019 Audio Accelerator + +pci:v00001039d00007502* + ID_MODEL_FROM_DATABASE=Azalia Audio Controller + +pci:v0000103A* + ID_VENDOR_FROM_DATABASE=Seiko Epson Corporation + +pci:v0000103B* + ID_VENDOR_FROM_DATABASE=Tatung Corp. Of America + +pci:v0000103C* + ID_VENDOR_FROM_DATABASE=Hewlett-Packard Company + +pci:v0000103Cd00001005* + ID_MODEL_FROM_DATABASE=A4977A Visualize EG + +pci:v0000103Cd00001008* + ID_MODEL_FROM_DATABASE=Visualize FX + +pci:v0000103Cd00001028* + ID_MODEL_FROM_DATABASE=Tach TL Fibre Channel Host Adapter + +pci:v0000103Cd00001029* + ID_MODEL_FROM_DATABASE=Tach XL2 Fibre Channel Host Adapter + +pci:v0000103Cd00001029sv0000107Esd0000000F* + ID_MODEL_FROM_DATABASE=Interphase 5560 Fibre Channel Adapter + +pci:v0000103Cd00001029sv00009004sd00009210* + ID_MODEL_FROM_DATABASE=1Gb/2Gb Family Fibre Channel Controller + +pci:v0000103Cd00001029sv00009004sd00009211* + ID_MODEL_FROM_DATABASE=1Gb/2Gb Family Fibre Channel Controller + +pci:v0000103Cd0000102A* + ID_MODEL_FROM_DATABASE=Tach TS Fibre Channel Host Adapter + +pci:v0000103Cd0000102Asv0000107Esd0000000E* + ID_MODEL_FROM_DATABASE=Interphase 5540/5541 Fibre Channel Adapter + +pci:v0000103Cd0000102Asv00009004sd00009110* + ID_MODEL_FROM_DATABASE=1Gb/2Gb Family Fibre Channel Controller + +pci:v0000103Cd0000102Asv00009004sd00009111* + ID_MODEL_FROM_DATABASE=1Gb/2Gb Family Fibre Channel Controller + +pci:v0000103Cd00001030* + ID_MODEL_FROM_DATABASE=J2585A DeskDirect 10/100VG NIC + +pci:v0000103Cd00001031* + ID_MODEL_FROM_DATABASE=J2585B HP 10/100VG PCI LAN Adapter + +pci:v0000103Cd00001031sv0000103Csd00001040* + ID_MODEL_FROM_DATABASE=J2973A DeskDirect 10BaseT NIC + +pci:v0000103Cd00001031sv0000103Csd00001041* + ID_MODEL_FROM_DATABASE=J2585B DeskDirect 10/100VG NIC + +pci:v0000103Cd00001031sv0000103Csd00001042* + ID_MODEL_FROM_DATABASE=J2970A DeskDirect 10BaseT/2 NIC + +pci:v0000103Cd00001040* + ID_MODEL_FROM_DATABASE=J2973A DeskDirect 10BaseT NIC + +pci:v0000103Cd00001041* + ID_MODEL_FROM_DATABASE=J2585B DeskDirect 10/100 NIC + +pci:v0000103Cd00001042* + ID_MODEL_FROM_DATABASE=J2970A DeskDirect 10BaseT/2 NIC + +pci:v0000103Cd00001048* + ID_MODEL_FROM_DATABASE=Diva Serial [GSP] Multiport UART + +pci:v0000103Cd00001048sv0000103Csd00001049* + ID_MODEL_FROM_DATABASE=Tosca Console + +pci:v0000103Cd00001048sv0000103Csd0000104A* + ID_MODEL_FROM_DATABASE=Tosca Secondary + +pci:v0000103Cd00001048sv0000103Csd0000104B* + ID_MODEL_FROM_DATABASE=Maestro SP2 + +pci:v0000103Cd00001048sv0000103Csd00001223* + ID_MODEL_FROM_DATABASE=Superdome Console + +pci:v0000103Cd00001048sv0000103Csd00001226* + ID_MODEL_FROM_DATABASE=Keystone SP2 + +pci:v0000103Cd00001048sv0000103Csd00001227* + ID_MODEL_FROM_DATABASE=Powerbar SP2 + +pci:v0000103Cd00001048sv0000103Csd00001282* + ID_MODEL_FROM_DATABASE=Everest SP2 + +pci:v0000103Cd00001048sv0000103Csd00001301* + ID_MODEL_FROM_DATABASE=Diva RMP3 + +pci:v0000103Cd00001054* + ID_MODEL_FROM_DATABASE=PCI Local Bus Adapter + +pci:v0000103Cd00001064* + ID_MODEL_FROM_DATABASE=79C970 PCnet Ethernet Controller + +pci:v0000103Cd0000108B* + ID_MODEL_FROM_DATABASE=Visualize FXe + +pci:v0000103Cd000010C1* + ID_MODEL_FROM_DATABASE=NetServer Smart IRQ Router + +pci:v0000103Cd000010ED* + ID_MODEL_FROM_DATABASE=TopTools Remote Control + +pci:v0000103Cd000010F0* + ID_MODEL_FROM_DATABASE=rio System Bus Adapter + +pci:v0000103Cd000010F1* + ID_MODEL_FROM_DATABASE=rio I/O Controller + +pci:v0000103Cd00001219* + ID_MODEL_FROM_DATABASE=NetServer PCI Hot-Plug Controller + +pci:v0000103Cd0000121A* + ID_MODEL_FROM_DATABASE=NetServer SMIC Controller + +pci:v0000103Cd0000121B* + ID_MODEL_FROM_DATABASE=NetServer Legacy COM Port Decoder + +pci:v0000103Cd0000121C* + ID_MODEL_FROM_DATABASE=NetServer PCI COM Port Decoder + +pci:v0000103Cd00001229* + ID_MODEL_FROM_DATABASE=zx1 System Bus Adapter + +pci:v0000103Cd0000122A* + ID_MODEL_FROM_DATABASE=zx1 I/O Controller + +pci:v0000103Cd0000122E* + ID_MODEL_FROM_DATABASE=PCI-X Local Bus Adapter + +pci:v0000103Cd0000127B* + ID_MODEL_FROM_DATABASE=sx1000 System Bus Adapter + +pci:v0000103Cd0000127C* + ID_MODEL_FROM_DATABASE=sx1000 I/O Controller + +pci:v0000103Cd00001290* + ID_MODEL_FROM_DATABASE=Auxiliary Diva Serial Port + +pci:v0000103Cd00001290sv0000103Csd00001291* + ID_MODEL_FROM_DATABASE=Diva SP2 + +pci:v0000103Cd00001291* + ID_MODEL_FROM_DATABASE=Auxiliary Diva Serial Port + +pci:v0000103Cd000012B4* + ID_MODEL_FROM_DATABASE=zx1 QuickSilver AGP8x Local Bus Adapter + +pci:v0000103Cd000012EB* + ID_MODEL_FROM_DATABASE=sx2000 System Bus Adapter + +pci:v0000103Cd000012EC* + ID_MODEL_FROM_DATABASE=sx2000 I/O Controller + +pci:v0000103Cd000012EE* + ID_MODEL_FROM_DATABASE=PCI-X 2.0 Local Bus Adapter + +pci:v0000103Cd00001302* + ID_MODEL_FROM_DATABASE=RMP-3 Shared Memory Driver + +pci:v0000103Cd00001303* + ID_MODEL_FROM_DATABASE=RMP-3 (Remote Management Processor) + +pci:v0000103Cd00002910* + ID_MODEL_FROM_DATABASE=E2910A PCIBus Exerciser + +pci:v0000103Cd00002925* + ID_MODEL_FROM_DATABASE=E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer + +pci:v0000103Cd00003206* + ID_MODEL_FROM_DATABASE=Adaptec Embedded Serial ATA HostRAID + +pci:v0000103Cd00003220* + ID_MODEL_FROM_DATABASE=Smart Array P600 + +pci:v0000103Cd00003220sv0000103Csd00003225* + ID_MODEL_FROM_DATABASE=3 Gb/s SAS RAID + +pci:v0000103Cd00003230* + ID_MODEL_FROM_DATABASE=Smart Array Controller + +pci:v0000103Cd00003230sv0000103Csd00003223* + ID_MODEL_FROM_DATABASE=Smart Array P800 + +pci:v0000103Cd00003230sv0000103Csd00003234* + ID_MODEL_FROM_DATABASE=P400 SAS Controller + +pci:v0000103Cd00003230sv0000103Csd00003235* + ID_MODEL_FROM_DATABASE=P400i SAS Controller + +pci:v0000103Cd00003230sv0000103Csd00003237* + ID_MODEL_FROM_DATABASE=E500 SAS Controller + +pci:v0000103Cd00003230sv0000103Csd0000323D* + ID_MODEL_FROM_DATABASE=P700m SAS Controller + +pci:v0000103Cd00003238* + ID_MODEL_FROM_DATABASE=Smart Array E200i (SAS Controller) + +pci:v0000103Cd00003238sv0000103Csd00003211* + ID_MODEL_FROM_DATABASE=Smart Array E200i + +pci:v0000103Cd00003238sv0000103Csd00003212* + ID_MODEL_FROM_DATABASE=Smart Array E200 + +pci:v0000103Cd0000323A* + ID_MODEL_FROM_DATABASE=Smart Array G6 controllers + +pci:v0000103Cd0000323Asv0000103Csd00003241* + ID_MODEL_FROM_DATABASE=Smart Array P212 + +pci:v0000103Cd0000323Asv0000103Csd00003243* + ID_MODEL_FROM_DATABASE=Smart Array P410 + +pci:v0000103Cd0000323Asv0000103Csd00003245* + ID_MODEL_FROM_DATABASE=Smart Array P410i + +pci:v0000103Cd0000323Asv0000103Csd00003247* + ID_MODEL_FROM_DATABASE=Smart Array P411 + +pci:v0000103Cd0000323Asv0000103Csd00003249* + ID_MODEL_FROM_DATABASE=Smart Array P812 + +pci:v0000103Cd0000323Asv0000103Csd0000324A* + ID_MODEL_FROM_DATABASE=HP Smart Array 712m (Mezzanine RAID controller) + +pci:v0000103Cd0000323Asv0000103Csd0000324B* + ID_MODEL_FROM_DATABASE=Smart Array P711m (Mezzanine RAID controller) + +pci:v0000103Cd0000323B* + ID_MODEL_FROM_DATABASE=Smart Array Gen8 Controllers + +pci:v0000103Cd0000323Bsv0000103Csd00003350* + ID_MODEL_FROM_DATABASE=P222 + +pci:v0000103Cd0000323Bsv0000103Csd00003351* + ID_MODEL_FROM_DATABASE=P420 + +pci:v0000103Cd0000323Bsv0000103Csd00003352* + ID_MODEL_FROM_DATABASE=P421 + +pci:v0000103Cd0000323Bsv0000103Csd00003354* + ID_MODEL_FROM_DATABASE=P420i + +pci:v0000103Cd0000323Bsv0000103Csd00003355* + ID_MODEL_FROM_DATABASE=P220i + +pci:v0000103Cd0000323C* + ID_MODEL_FROM_DATABASE=Smart Array Gen8+ Controllers + +pci:v0000103Cd0000323Csv0000103Csd00001920* + ID_MODEL_FROM_DATABASE=P430i + +pci:v0000103Cd0000323Csv0000103Csd00001921* + ID_MODEL_FROM_DATABASE=P830i + +pci:v0000103Cd0000323Csv0000103Csd00001922* + ID_MODEL_FROM_DATABASE=P430 + +pci:v0000103Cd0000323Csv0000103Csd00001923* + ID_MODEL_FROM_DATABASE=P431 + +pci:v0000103Cd0000323Csv0000103Csd00001924* + ID_MODEL_FROM_DATABASE=P830 + +pci:v0000103Cd0000323Csv0000103Csd00001925* + ID_MODEL_FROM_DATABASE=Smart Array + +pci:v0000103Cd0000323Csv0000103Csd00001926* + ID_MODEL_FROM_DATABASE=P731m + +pci:v0000103Cd0000323Csv0000103Csd00001928* + ID_MODEL_FROM_DATABASE=P230i + +pci:v0000103Cd00003300* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard Virtual USB Controller + +pci:v0000103Cd00003300sv0000103Csd00003304* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003300sv0000103Csd00003305* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003300sv0000103Csd00003309* + ID_MODEL_FROM_DATABASE=iLO2 GXL/iLO3 GXE + +pci:v0000103Cd00003300sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003300sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd00003301* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard Serial Port + +pci:v0000103Cd00003301sv0000103Csd00003304* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003301sv0000103Csd00003305* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003301sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003301sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd00003302* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard KCS Interface + +pci:v0000103Cd00003302sv0000103Csd00003304* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003302sv0000103Csd00003305* + ID_MODEL_FROM_DATABASE=iLO2 + +pci:v0000103Cd00003302sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003302sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd00003305* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out (iLO2) Controller + +pci:v0000103Cd00003306* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard Slave Instrumentation & System Support + +pci:v0000103Cd00003306sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003306sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd00003307* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard Management Processor Support and Messaging + +pci:v0000103Cd00003307sv0000103Csd00003309* + ID_MODEL_FROM_DATABASE=iLO 2 + +pci:v0000103Cd00003307sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003307sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd00003308* + ID_MODEL_FROM_DATABASE=Integrated Lights-Out Standard MS Watchdog Timer + +pci:v0000103Cd00003308sv0000103Csd0000330E* + ID_MODEL_FROM_DATABASE=iLO3 + +pci:v0000103Cd00003308sv0000103Csd00003381* + ID_MODEL_FROM_DATABASE=iLO4 + +pci:v0000103Cd0000402F* + ID_MODEL_FROM_DATABASE=PCIe Root Port + +pci:v0000103Cd00004030* + ID_MODEL_FROM_DATABASE=zx2 System Bus Adapter + +pci:v0000103Cd00004031* + ID_MODEL_FROM_DATABASE=zx2 I/O Controller + +pci:v0000103Cd00004037* + ID_MODEL_FROM_DATABASE=PCIe Local Bus Adapter + +pci:v0000103Cd0000403B* + ID_MODEL_FROM_DATABASE=PCIe Root Port + +pci:v0000103Cd000060E8* + ID_MODEL_FROM_DATABASE=NetRAID-2M : ZX1/M (OEM AMI MegaRAID 493) + +pci:v0000103E* + ID_VENDOR_FROM_DATABASE=Solliday Engineering + +pci:v0000103F* + ID_VENDOR_FROM_DATABASE=Synopsys/Logic Modeling Group + +pci:v00001040* + ID_VENDOR_FROM_DATABASE=Accelgraphics Inc. + +pci:v00001041* + ID_VENDOR_FROM_DATABASE=Computrend + +pci:v00001042* + ID_VENDOR_FROM_DATABASE=Micron + +pci:v00001042d00001000* + ID_MODEL_FROM_DATABASE=PC Tech RZ1000 + +pci:v00001042d00001001* + ID_MODEL_FROM_DATABASE=PC Tech RZ1001 + +pci:v00001042d00003000* + ID_MODEL_FROM_DATABASE=Samurai_0 + +pci:v00001042d00003010* + ID_MODEL_FROM_DATABASE=Samurai_1 + +pci:v00001042d00003020* + ID_MODEL_FROM_DATABASE=Samurai_IDE + +pci:v00001043* + ID_VENDOR_FROM_DATABASE=ASUSTeK Computer Inc. + +pci:v00001043d00000675* + ID_MODEL_FROM_DATABASE=ISDNLink P-IN100-ST-D + +pci:v00001043d00000675sv00000675sd00001704* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, C) + +pci:v00001043d00000675sv00000675sd00001707* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001043d00000675sv000010CFsd0000105E* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001043d00009602* + ID_MODEL_FROM_DATABASE=AMD RS780/RS880 PCI to PCI bridge (int gfx) + +pci:v00001043d00009602sv00001043sd000083A2* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v00001044* + ID_VENDOR_FROM_DATABASE=Adaptec (formerly DPT) + +pci:v00001044d00001012* + ID_MODEL_FROM_DATABASE=Domino RAID Engine + +pci:v00001044d0000A400* + ID_MODEL_FROM_DATABASE=SmartCache/Raid I-IV Controller + +pci:v00001044d0000A500* + ID_MODEL_FROM_DATABASE=PCI Bridge + +pci:v00001044d0000A501* + ID_MODEL_FROM_DATABASE=SmartRAID V Controller + +pci:v00001044d0000A501sv00001044sd0000C001* + ID_MODEL_FROM_DATABASE=PM1554U2 Ultra2 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C002* + ID_MODEL_FROM_DATABASE=PM1654U2 Ultra2 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C003* + ID_MODEL_FROM_DATABASE=PM1564U3 Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C004* + ID_MODEL_FROM_DATABASE=PM1564U3 Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C005* + ID_MODEL_FROM_DATABASE=PM1554U2 Ultra2 Single Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C00A* + ID_MODEL_FROM_DATABASE=PM2554U2 Ultra2 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C00B* + ID_MODEL_FROM_DATABASE=PM2654U2 Ultra2 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C00C* + ID_MODEL_FROM_DATABASE=PM2664U3 Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C00D* + ID_MODEL_FROM_DATABASE=PM2664U3 Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C00E* + ID_MODEL_FROM_DATABASE=PM2554U2 Ultra2 Single Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C00F* + ID_MODEL_FROM_DATABASE=PM2654U2 Ultra2 Single Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C014* + ID_MODEL_FROM_DATABASE=PM3754U2 Ultra2 Single Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C015* + ID_MODEL_FROM_DATABASE=PM3755U2B Ultra2 Single Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C016* + ID_MODEL_FROM_DATABASE=PM3755F Fibre Channel (NON ACPI) + +pci:v00001044d0000A501sv00001044sd0000C01E* + ID_MODEL_FROM_DATABASE=PM3757U2 Ultra2 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C01F* + ID_MODEL_FROM_DATABASE=PM3757U2 Ultra2 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C020* + ID_MODEL_FROM_DATABASE=PM3767U3 Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C021* + ID_MODEL_FROM_DATABASE=PM3767U3 Ultra3 Quad Channel + +pci:v00001044d0000A501sv00001044sd0000C028* + ID_MODEL_FROM_DATABASE=PM2865U3 Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C029* + ID_MODEL_FROM_DATABASE=PM2865U3 Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C02A* + ID_MODEL_FROM_DATABASE=PM2865F Fibre Channel + +pci:v00001044d0000A501sv00001044sd0000C03C* + ID_MODEL_FROM_DATABASE=2000S Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C03D* + ID_MODEL_FROM_DATABASE=2000S Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C03E* + ID_MODEL_FROM_DATABASE=2000F Fibre Channel + +pci:v00001044d0000A501sv00001044sd0000C046* + ID_MODEL_FROM_DATABASE=3000S Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C047* + ID_MODEL_FROM_DATABASE=3000S Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C048* + ID_MODEL_FROM_DATABASE=3000F Fibre Channel + +pci:v00001044d0000A501sv00001044sd0000C050* + ID_MODEL_FROM_DATABASE=5000S Ultra3 Single Channel + +pci:v00001044d0000A501sv00001044sd0000C051* + ID_MODEL_FROM_DATABASE=5000S Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C052* + ID_MODEL_FROM_DATABASE=5000F Fibre Channel + +pci:v00001044d0000A501sv00001044sd0000C05A* + ID_MODEL_FROM_DATABASE=2400A UDMA Four Channel + +pci:v00001044d0000A501sv00001044sd0000C05B* + ID_MODEL_FROM_DATABASE=2400A UDMA Four Channel DAC + +pci:v00001044d0000A501sv00001044sd0000C064* + ID_MODEL_FROM_DATABASE=3010S Ultra3 Dual Channel + +pci:v00001044d0000A501sv00001044sd0000C065* + ID_MODEL_FROM_DATABASE=3410S Ultra160 Four Channel + +pci:v00001044d0000A501sv00001044sd0000C066* + ID_MODEL_FROM_DATABASE=3010S Fibre Channel + +pci:v00001044d0000A511* + ID_MODEL_FROM_DATABASE=SmartRAID V Controller + +pci:v00001044d0000A511sv00001044sd0000C032* + ID_MODEL_FROM_DATABASE=ASR-2005S I2O Zero Channel + +pci:v00001044d0000A511sv00001044sd0000C035* + ID_MODEL_FROM_DATABASE=ASR-2010S I2O Zero Channel + +pci:v00001044d0000C066* + ID_MODEL_FROM_DATABASE=3010S Ultra3 Dual Channel + +pci:v00001045* + ID_VENDOR_FROM_DATABASE=OPTi Inc. + +pci:v00001045d0000A0F8* + ID_MODEL_FROM_DATABASE=82C750 [Vendetta] USB Controller + +pci:v00001045d0000C101* + ID_MODEL_FROM_DATABASE=92C264 + +pci:v00001045d0000C178* + ID_MODEL_FROM_DATABASE=92C178 + +pci:v00001045d0000C556* + ID_MODEL_FROM_DATABASE=82X556 [Viper] + +pci:v00001045d0000C557* + ID_MODEL_FROM_DATABASE=82C557 [Viper-M] + +pci:v00001045d0000C558* + ID_MODEL_FROM_DATABASE=82C558 [Viper-M ISA+IDE] + +pci:v00001045d0000C567* + ID_MODEL_FROM_DATABASE=82C750 [Vendetta], device 0 + +pci:v00001045d0000C568* + ID_MODEL_FROM_DATABASE=82C750 [Vendetta], device 1 + +pci:v00001045d0000C569* + ID_MODEL_FROM_DATABASE=82C579 [Viper XPress+ Chipset] + +pci:v00001045d0000C621* + ID_MODEL_FROM_DATABASE=82C621 [Viper-M/N+] + +pci:v00001045d0000C700* + ID_MODEL_FROM_DATABASE=82C700 [FireStar] + +pci:v00001045d0000C701* + ID_MODEL_FROM_DATABASE=82C701 [FireStar Plus] + +pci:v00001045d0000C814* + ID_MODEL_FROM_DATABASE=82C814 [Firebridge 1] + +pci:v00001045d0000C822* + ID_MODEL_FROM_DATABASE=82C822 + +pci:v00001045d0000C824* + ID_MODEL_FROM_DATABASE=82C824 + +pci:v00001045d0000C825* + ID_MODEL_FROM_DATABASE=82C825 [Firebridge 2] + +pci:v00001045d0000C832* + ID_MODEL_FROM_DATABASE=82C832 + +pci:v00001045d0000C861* + ID_MODEL_FROM_DATABASE=82C861 + +pci:v00001045d0000C881* + ID_MODEL_FROM_DATABASE=82C881 [FireLink] 1394 OHCI Link Controller + +pci:v00001045d0000C895* + ID_MODEL_FROM_DATABASE=82C895 + +pci:v00001045d0000C935* + ID_MODEL_FROM_DATABASE=EV1935 ECTIVA MachOne PCIAudio + +pci:v00001045d0000D568* + ID_MODEL_FROM_DATABASE=82C825 [Firebridge 2] + +pci:v00001045d0000D721* + ID_MODEL_FROM_DATABASE=IDE [FireStar] + +pci:v00001046* + ID_VENDOR_FROM_DATABASE=IPC Corporation, Ltd. + +pci:v00001047* + ID_VENDOR_FROM_DATABASE=Genoa Systems Corp + +pci:v00001048* + ID_VENDOR_FROM_DATABASE=Elsa AG + +pci:v00001048d00000C60* + ID_MODEL_FROM_DATABASE=Gladiac MX + +pci:v00001048d00000D22* + ID_MODEL_FROM_DATABASE=Quadro4 900XGL [ELSA GLoria4 900XGL] + +pci:v00001048d00001000* + ID_MODEL_FROM_DATABASE=QuickStep 1000 + +pci:v00001048d00003000* + ID_MODEL_FROM_DATABASE=QuickStep 3000 + +pci:v00001048d00008901* + ID_MODEL_FROM_DATABASE=Gloria XL + +pci:v00001048d00008901sv00001048sd00000935* + ID_MODEL_FROM_DATABASE=GLoria XL (Virge) + +pci:v00001049* + ID_VENDOR_FROM_DATABASE=Fountain Technologies, Inc. + +pci:v0000104A* + ID_VENDOR_FROM_DATABASE=STMicroelectronics + +pci:v0000104Ad00000000* + ID_MODEL_FROM_DATABASE=STLS2F Host Bridge + +pci:v0000104Ad00000008* + ID_MODEL_FROM_DATABASE=STG 2000X + +pci:v0000104Ad00000009* + ID_MODEL_FROM_DATABASE=STG 1764X + +pci:v0000104Ad00000010* + ID_MODEL_FROM_DATABASE=STG4000 [3D Prophet Kyro Series] + +pci:v0000104Ad00000010sv0000104Asd00004018* + ID_MODEL_FROM_DATABASE=ST PowerVR Kyro (64MB AGP TVO) + +pci:v0000104Ad00000010sv00001681sd00000028* + ID_MODEL_FROM_DATABASE=3D Prophet 4000XT + +pci:v0000104Ad00000010sv00001681sd0000C010* + ID_MODEL_FROM_DATABASE=3D Prophet 4500 TV-Out + +pci:v0000104Ad00000010sv00001681sd0000C069* + ID_MODEL_FROM_DATABASE=3D Prophet 4000XT + +pci:v0000104Ad00000201* + ID_MODEL_FROM_DATABASE=STPC Vega Northbridge + +pci:v0000104Ad00000209* + ID_MODEL_FROM_DATABASE=STPC Consumer/Industrial North- and Southbridge + +pci:v0000104Ad0000020A* + ID_MODEL_FROM_DATABASE=STPC Atlas/ConsumerS/Consumer IIA Northbridge + +pci:v0000104Ad0000020B* + ID_MODEL_FROM_DATABASE=STPC Consumer II ISA Bridge + +pci:v0000104Ad00000210* + ID_MODEL_FROM_DATABASE=STPC Atlas ISA Bridge + +pci:v0000104Ad0000021A* + ID_MODEL_FROM_DATABASE=STPC Consumer S Southbridge + +pci:v0000104Ad0000021B* + ID_MODEL_FROM_DATABASE=STPC Consumer IIA Southbridge + +pci:v0000104Ad00000220* + ID_MODEL_FROM_DATABASE=STPC Industrial PCI to PCCard bridge + +pci:v0000104Ad00000228* + ID_MODEL_FROM_DATABASE=STPC Atlas IDE + +pci:v0000104Ad00000229* + ID_MODEL_FROM_DATABASE=STPC Vega IDE + +pci:v0000104Ad00000230* + ID_MODEL_FROM_DATABASE=STPC Atlas/Vega OHCI USB Controller + +pci:v0000104Ad00000238* + ID_MODEL_FROM_DATABASE=STPC Vega LAN + +pci:v0000104Ad00000500* + ID_MODEL_FROM_DATABASE=ST70137 [Unicorn] ADSL DMT Transceiver + +pci:v0000104Ad00000500sv0000104Asd00000500* + ID_MODEL_FROM_DATABASE=BeWAN ADSL PCI st + +pci:v0000104Ad00000564* + ID_MODEL_FROM_DATABASE=STPC Client Northbridge + +pci:v0000104Ad00000981* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v0000104Ad00001746* + ID_MODEL_FROM_DATABASE=STG 1764X + +pci:v0000104Ad00002774* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v0000104Ad00003520* + ID_MODEL_FROM_DATABASE=MPEG-II decoder card + +pci:v0000104Ad000055CC* + ID_MODEL_FROM_DATABASE=STPC Client Southbridge + +pci:v0000104B* + ID_VENDOR_FROM_DATABASE=BusLogic + +pci:v0000104Bd00000140* + ID_MODEL_FROM_DATABASE=BT-946C (old) [multimaster 01] + +pci:v0000104Bd00001040* + ID_MODEL_FROM_DATABASE=BT-946C (BA80C30) [MultiMaster 10] + +pci:v0000104Bd00008130* + ID_MODEL_FROM_DATABASE=Flashpoint LT + +pci:v0000104C* + ID_VENDOR_FROM_DATABASE=Texas Instruments + +pci:v0000104Cd00000500* + ID_MODEL_FROM_DATABASE=100 MBit LAN Controller + +pci:v0000104Cd00000508* + ID_MODEL_FROM_DATABASE=TMS380C2X Compressor Interface + +pci:v0000104Cd00001000* + ID_MODEL_FROM_DATABASE=Eagle i/f AS + +pci:v0000104Cd0000104C* + ID_MODEL_FROM_DATABASE=PCI1510 PC card Cardbus Controller + +pci:v0000104Cd00003D04* + ID_MODEL_FROM_DATABASE=TVP4010 [Permedia] + +pci:v0000104Cd00003D07* + ID_MODEL_FROM_DATABASE=TVP4020 [Permedia 2] + +pci:v0000104Cd00003D07sv00001011sd00004D10* + ID_MODEL_FROM_DATABASE=Comet + +pci:v0000104Cd00003D07sv00001040sd0000000F* + ID_MODEL_FROM_DATABASE=AccelStar II + +pci:v0000104Cd00003D07sv00001040sd00000011* + ID_MODEL_FROM_DATABASE=AccelStar II + +pci:v0000104Cd00003D07sv00001048sd00000A31* + ID_MODEL_FROM_DATABASE=WINNER 2000 + +pci:v0000104Cd00003D07sv00001048sd00000A32* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv00001048sd00000A34* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv00001048sd00000A35* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv00001048sd00000A36* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv00001048sd00000A43* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv00001048sd00000A44* + ID_MODEL_FROM_DATABASE=GLoria Synergy + +pci:v0000104Cd00003D07sv0000107Dsd00002633* + ID_MODEL_FROM_DATABASE=WinFast 3D L2300 + +pci:v0000104Cd00003D07sv00001092sd00000126* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000127* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000136* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000141* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000146* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000148* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000149* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000152* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000154* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000155* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000156* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001092sd00000157* + ID_MODEL_FROM_DATABASE=FIRE GL 1000 PRO + +pci:v0000104Cd00003D07sv00001097sd00003D01* + ID_MODEL_FROM_DATABASE=Jeronimo Pro + +pci:v0000104Cd00003D07sv00001102sd0000100F* + ID_MODEL_FROM_DATABASE=Graphics Blaster Extreme + +pci:v0000104Cd00003D07sv00003D3Dsd00000100* + ID_MODEL_FROM_DATABASE=Reference Permedia 2 3D + +pci:v0000104Cd00008000* + ID_MODEL_FROM_DATABASE=PCILynx/PCILynx2 IEEE 1394 Link Layer Controller + +pci:v0000104Cd00008000sv0000105Esd00008003* + ID_MODEL_FROM_DATABASE=FireBoard200 + +pci:v0000104Cd00008000sv00001443sd00008003* + ID_MODEL_FROM_DATABASE=FireBoard200 + +pci:v0000104Cd00008000sv00001443sd00008005* + ID_MODEL_FROM_DATABASE=FireBoard400 + +pci:v0000104Cd00008000sv00001443sd00008006* + ID_MODEL_FROM_DATABASE=FireBoard400 + +pci:v0000104Cd00008000sv0000E4BFsd00001010* + ID_MODEL_FROM_DATABASE=CF1-1-SNARE + +pci:v0000104Cd00008000sv0000E4BFsd00001020* + ID_MODEL_FROM_DATABASE=CF1-2-SNARE + +pci:v0000104Cd00008000sv0000E4BFsd00001040* + ID_MODEL_FROM_DATABASE=FireCompact400 + +pci:v0000104Cd00008009* + ID_MODEL_FROM_DATABASE=TSB12LV22 IEEE-1394 Controller + +pci:v0000104Cd00008009sv0000104Dsd00008032* + ID_MODEL_FROM_DATABASE=8032 OHCI i.LINK (IEEE 1394) Controller + +pci:v0000104Cd00008009sv00001443sd00008010* + ID_MODEL_FROM_DATABASE=FireBoard400-OHCI + +pci:v0000104Cd00008017* + ID_MODEL_FROM_DATABASE=PCI4410 FireWire Controller + +pci:v0000104Cd00008019* + ID_MODEL_FROM_DATABASE=TSB12LV23 IEEE-1394 Controller + +pci:v0000104Cd00008019sv000011BDsd0000000A* + ID_MODEL_FROM_DATABASE=Studio DV500-1394 + +pci:v0000104Cd00008019sv000011BDsd0000000E* + ID_MODEL_FROM_DATABASE=Studio DV + +pci:v0000104Cd00008019sv00001443sd00008010* + ID_MODEL_FROM_DATABASE=FireBoard400-OHCI + +pci:v0000104Cd00008019sv0000E4BFsd00001010* + ID_MODEL_FROM_DATABASE=CF2-1-CYMBAL + +pci:v0000104Cd00008020* + ID_MODEL_FROM_DATABASE=TSB12LV26 IEEE-1394 Controller (Link) + +pci:v0000104Cd00008020sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v0000104Cd00008020sv0000104Dsd000080E2* + ID_MODEL_FROM_DATABASE=VAIO PCV-J200 + +pci:v0000104Cd00008020sv000011BDsd0000000F* + ID_MODEL_FROM_DATABASE=Studio DV500-1394 + +pci:v0000104Cd00008020sv000011BDsd0000001C* + ID_MODEL_FROM_DATABASE=Excalibur 4.1 + +pci:v0000104Cd00008020sv00001443sd00008010* + ID_MODEL_FROM_DATABASE=FireBoard400-OHCI + +pci:v0000104Cd00008021* + ID_MODEL_FROM_DATABASE=TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated) + +pci:v0000104Cd00008021sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v0000104Cd00008021sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v0000104Cd00008022* + ID_MODEL_FROM_DATABASE=TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link) [iOHCI-Lynx] + +pci:v0000104Cd00008022sv0000104Csd00008023* + ID_MODEL_FROM_DATABASE=TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link) + +pci:v0000104Cd00008023* + ID_MODEL_FROM_DATABASE=TSB43AB22A IEEE-1394a-2000 Controller (PHY/Link) [iOHCI-Lynx] + +pci:v0000104Cd00008023sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v0000104Cd00008023sv00001043sd0000808B* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v0000104Cd00008023sv00001043sd0000815B* + ID_MODEL_FROM_DATABASE=P5W DH Deluxe Motherboard + +pci:v0000104Cd00008023sv00001443sd00008023* + ID_MODEL_FROM_DATABASE=FireCard400 + +pci:v0000104Cd00008023sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v0000104Cd00008024* + ID_MODEL_FROM_DATABASE=TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link) + +pci:v0000104Cd00008024sv0000107Dsd00006620* + ID_MODEL_FROM_DATABASE=Winfast DV2000 FireWire Controller + +pci:v0000104Cd00008024sv00001443sd00008024* + ID_MODEL_FROM_DATABASE=FireBoard Blue + +pci:v0000104Cd00008024sv00001458sd00001000* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v0000104Cd00008025* + ID_MODEL_FROM_DATABASE=TSB82AA2 IEEE-1394b Link Layer Controller + +pci:v0000104Cd00008025sv00001043sd0000813C* + ID_MODEL_FROM_DATABASE=P5P series mainboard + +pci:v0000104Cd00008025sv00001443sd00008025* + ID_MODEL_FROM_DATABASE=FireBoard800 + +pci:v0000104Cd00008025sv00001458sd00001000* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v0000104Cd00008025sv00001546sd00008025* + ID_MODEL_FROM_DATABASE=FWB-PCI01 + +pci:v0000104Cd00008025sv000017FCsd00008025* + ID_MODEL_FROM_DATABASE=GIC3800 + +pci:v0000104Cd00008026* + ID_MODEL_FROM_DATABASE=TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link) + +pci:v0000104Cd00008026sv00001025sd00000035* + ID_MODEL_FROM_DATABASE=TravelMate 660 + +pci:v0000104Cd00008026sv00001025sd0000003C* + ID_MODEL_FROM_DATABASE=Aspire 2001WLCi (Compaq CL50 motherboard) + +pci:v0000104Cd00008026sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v0000104Cd00008026sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v0000104Cd00008026sv00001043sd0000808D* + ID_MODEL_FROM_DATABASE=A7V333 mainboard. + +pci:v0000104Cd00008027* + ID_MODEL_FROM_DATABASE=PCI4451 IEEE-1394 Controller + +pci:v0000104Cd00008027sv00001028sd000000E5* + ID_MODEL_FROM_DATABASE=Latitude C810 + +pci:v0000104Cd00008027sv00001028sd000000E6* + ID_MODEL_FROM_DATABASE=PCI4451 IEEE-1394 Controller (Dell Inspiron 8100) + +pci:v0000104Cd00008029* + ID_MODEL_FROM_DATABASE=PCI4510 IEEE-1394 Controller + +pci:v0000104Cd00008029sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v0000104Cd00008029sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v0000104Cd00008029sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2900 + +pci:v0000104Cd0000802B* + ID_MODEL_FROM_DATABASE=PCI7410,7510,7610 OHCI-Lynx Controller + +pci:v0000104Cd0000802Bsv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v0000104Cd0000802Bsv00001028sd0000014E* + ID_MODEL_FROM_DATABASE=PCI7410,7510,7610 OHCI-Lynx Controller (Latitude D800) + +pci:v0000104Cd0000802E* + ID_MODEL_FROM_DATABASE=PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller + +pci:v0000104Cd0000802Esv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v0000104Cd00008031* + ID_MODEL_FROM_DATABASE=PCIxx21/x515 Cardbus Controller + +pci:v0000104Cd00008031sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v0000104Cd00008031sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v0000104Cd00008031sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v0000104Cd00008031sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v0000104Cd00008032* + ID_MODEL_FROM_DATABASE=OHCI Compliant IEEE 1394 Host Controller + +pci:v0000104Cd00008032sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v0000104Cd00008032sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v0000104Cd00008032sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v0000104Cd00008032sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v0000104Cd00008033* + ID_MODEL_FROM_DATABASE=PCIxx21 Integrated FlashMedia Controller + +pci:v0000104Cd00008033sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v0000104Cd00008033sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v0000104Cd00008033sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v0000104Cd00008033sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v0000104Cd00008034* + ID_MODEL_FROM_DATABASE=PCI6411/6421/6611/6621/7411/7421/7611/7621 Secure Digital Controller + +pci:v0000104Cd00008034sv00001025sd00000080* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v0000104Cd00008034sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v0000104Cd00008034sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v0000104Cd00008034sv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v0000104Cd00008035* + ID_MODEL_FROM_DATABASE=PCI6411/6421/6611/6621/7411/7421/7611/7621 Smart Card Controller + +pci:v0000104Cd00008035sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v0000104Cd00008035sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v0000104Cd00008036* + ID_MODEL_FROM_DATABASE=PCI6515 Cardbus Controller + +pci:v0000104Cd00008038* + ID_MODEL_FROM_DATABASE=PCI6515 SmartCard Controller + +pci:v0000104Cd00008039* + ID_MODEL_FROM_DATABASE=PCIxx12 Cardbus Controller + +pci:v0000104Cd00008039sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v0000104Cd00008039sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v0000104Cd00008039sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v0000104Cd00008039sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v0000104Cd0000803A* + ID_MODEL_FROM_DATABASE=PCIxx12 OHCI Compliant IEEE 1394 Host Controller + +pci:v0000104Cd0000803Asv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=nx9420 + +pci:v0000104Cd0000803Asv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v0000104Cd0000803Asv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v0000104Cd0000803Asv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v0000104Cd0000803B* + ID_MODEL_FROM_DATABASE=5-in-1 Multimedia Card Reader (SD/MMC/MS/MS PRO/xD) + +pci:v0000104Cd0000803Bsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=nx9420 + +pci:v0000104Cd0000803Bsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v0000104Cd0000803Bsv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v0000104Cd0000803C* + ID_MODEL_FROM_DATABASE=PCIxx12 SDA Standard Compliant SD Host Controller + +pci:v0000104Cd0000803Csv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=nx9420 + +pci:v0000104Cd0000803Csv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v0000104Cd0000803D* + ID_MODEL_FROM_DATABASE=PCIxx12 GemCore based SmartCard controller + +pci:v0000104Cd0000803Dsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v0000104Cd0000803Dsv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v0000104Cd0000803Dsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=nc8430 + +pci:v0000104Cd0000803Dsv0000103Csd000030AA* + ID_MODEL_FROM_DATABASE=nc6310 + +pci:v0000104Cd00008101* + ID_MODEL_FROM_DATABASE=TSB43DB42 IEEE-1394a-2000 Controller (PHY/Link) + +pci:v0000104Cd00008201* + ID_MODEL_FROM_DATABASE=PCI1620 Firmware Loading Function + +pci:v0000104Cd00008204* + ID_MODEL_FROM_DATABASE=PCI7410/7510/7610 PCI Firmware Loading Function + +pci:v0000104Cd00008204sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v0000104Cd00008204sv00001028sd0000014E* + ID_MODEL_FROM_DATABASE=Latitude D800 + +pci:v0000104Cd00008231* + ID_MODEL_FROM_DATABASE=XIO2000(A)/XIO2200A PCI Express-to-PCI Bridge + +pci:v0000104Cd00008231sv00005678sd00001234* + ID_MODEL_FROM_DATABASE=DC-1394 PCIe + +pci:v0000104Cd00008232* + ID_MODEL_FROM_DATABASE=XIO3130 PCI Express Switch (Upstream) + +pci:v0000104Cd00008233* + ID_MODEL_FROM_DATABASE=XIO3130 PCI Express Switch (Downstream) + +pci:v0000104Cd00008235* + ID_MODEL_FROM_DATABASE=XIO2200A IEEE-1394a-2000 Controller (PHY/Link) + +pci:v0000104Cd00008235sv00005678sd00001234* + ID_MODEL_FROM_DATABASE=DC-1394 PCIe + +pci:v0000104Cd0000823E* + ID_MODEL_FROM_DATABASE=XIO2213A/B/XIO2221 PCI Express to PCI Bridge [Cheetah Express] + +pci:v0000104Cd0000823F* + ID_MODEL_FROM_DATABASE=XIO2213A/B/XIO2221 IEEE-1394b OHCI Controller [Cheetah Express] + +pci:v0000104Cd0000823Fsv00001546sd0000803C* + ID_MODEL_FROM_DATABASE=FWB-PCIE1X11B + +pci:v0000104Cd00008240* + ID_MODEL_FROM_DATABASE=XIO2001 PCI Express-to-PCI Bridge + +pci:v0000104Cd00008241* + ID_MODEL_FROM_DATABASE=TUSB73x0 SuperSpeed USB 3.0 xHCI Host Controller + +pci:v0000104Cd00008400* + ID_MODEL_FROM_DATABASE=ACX 100 22Mbps Wireless Interface + +pci:v0000104Cd00008400sv00001186sd00003B00* + ID_MODEL_FROM_DATABASE=DWL-650+ PC Card cardbus 22Mbs Wireless Adapter [AirPlus] + +pci:v0000104Cd00008400sv00001186sd00003B01* + ID_MODEL_FROM_DATABASE=DWL-520+ 22Mbps PCI Wireless Adapter + +pci:v0000104Cd00008400sv00001395sd00002201* + ID_MODEL_FROM_DATABASE=WL22-PC + +pci:v0000104Cd00008400sv000016ABsd00008501* + ID_MODEL_FROM_DATABASE=WL-8305 IEEE802.11b+ Wireless LAN PCI Adapter + +pci:v0000104Cd00008401* + ID_MODEL_FROM_DATABASE=ACX 100 22Mbps Wireless Interface + +pci:v0000104Cd00009000* + ID_MODEL_FROM_DATABASE=Wireless Interface (of unknown type) + +pci:v0000104Cd00009065* + ID_MODEL_FROM_DATABASE=TMS320DM642 + +pci:v0000104Cd00009066* + ID_MODEL_FROM_DATABASE=ACX 111 54Mbps Wireless Interface + +pci:v0000104Cd00009066sv00000308sd00003404* + ID_MODEL_FROM_DATABASE=G-102 v1 802.11g Wireless Cardbus Adapter + +pci:v0000104Cd00009066sv00000308sd00003406* + ID_MODEL_FROM_DATABASE=G-162 v2 802.11g Wireless Cardbus Adapter + +pci:v0000104Cd00009066sv0000104Csd00009066* + ID_MODEL_FROM_DATABASE=WL212 Sitecom Wireless Network PCI-Card 100M (Version 1) + +pci:v0000104Cd00009066sv0000104Csd00009067* + ID_MODEL_FROM_DATABASE=TNETW1130GVF + +pci:v0000104Cd00009066sv0000104Csd00009096* + ID_MODEL_FROM_DATABASE=Trendnet TEW-412PC Wireless PCI Adapter (Version A) + +pci:v0000104Cd00009066sv00001186sd00003B04* + ID_MODEL_FROM_DATABASE=DWL-G520+ Wireless PCI Adapter + +pci:v0000104Cd00009066sv00001186sd00003B05* + ID_MODEL_FROM_DATABASE=DWL-G650+ AirPlusG+ CardBus Wireless LAN + +pci:v0000104Cd00009066sv00001186sd00003B08* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.B1) + +pci:v0000104Cd00009066sv00001385sd00004C00* + ID_MODEL_FROM_DATABASE=WG311v2 802.11g Wireless PCI Adapter + +pci:v0000104Cd00009066sv000013D1sd0000ABA0* + ID_MODEL_FROM_DATABASE=SWLMP-54108 108Mbps Wireless mini PCI card 802.11g+ + +pci:v0000104Cd00009066sv000014EAsd0000AB07* + ID_MODEL_FROM_DATABASE=GW-NS54GM Wireless Cardbus Adapter + +pci:v0000104Cd00009066sv000016ECsd0000010D* + ID_MODEL_FROM_DATABASE=USR5416 802.11g Wireless Turbo PCI Adapter + +pci:v0000104Cd00009066sv000016ECsd0000010E* + ID_MODEL_FROM_DATABASE=USR5410 802.11g Wireless Cardbus Adapter + +pci:v0000104Cd00009066sv00001737sd00000033* + ID_MODEL_FROM_DATABASE=WPC54G v2 802.11g Wireless-G Notebook Adapter + +pci:v0000104Cd00009066sv000017CFsd00000032* + ID_MODEL_FROM_DATABASE=G-162 v1 802.11g Wireless Cardbus Adapter + +pci:v0000104Cd00009066sv000017CFsd00000033* + ID_MODEL_FROM_DATABASE=Z-Com XG650 Wireless miniPCI 802.11b/g + +pci:v0000104Cd00009066sv0000187Esd0000340B* + ID_MODEL_FROM_DATABASE=G-302 v2 802.11g Wireless PCI Adapter + +pci:v0000104Cd00009066sv0000187Esd0000340C* + ID_MODEL_FROM_DATABASE=G-360 v2 802.11g Wireless PCI Adapter + +pci:v0000104Cd0000A001* + ID_MODEL_FROM_DATABASE=TDC1570 + +pci:v0000104Cd0000A100* + ID_MODEL_FROM_DATABASE=TDC1561 + +pci:v0000104Cd0000A102* + ID_MODEL_FROM_DATABASE=TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f + +pci:v0000104Cd0000A106* + ID_MODEL_FROM_DATABASE=TMS320C6414 TMS320C6415 TMS320C6416 + +pci:v0000104Cd0000A106sv0000175Csd00005000* + ID_MODEL_FROM_DATABASE=ASI50xx Audio Adapter + +pci:v0000104Cd0000A106sv0000175Csd00006400* + ID_MODEL_FROM_DATABASE=ASI6400 Cobranet series + +pci:v0000104Cd0000A106sv0000175Csd00008700* + ID_MODEL_FROM_DATABASE=ASI87xx Radio Tuner card + +pci:v0000104Cd0000AC10* + ID_MODEL_FROM_DATABASE=PCI1050 + +pci:v0000104Cd0000AC11* + ID_MODEL_FROM_DATABASE=PCI1053 + +pci:v0000104Cd0000AC12* + ID_MODEL_FROM_DATABASE=PCI1130 + +pci:v0000104Cd0000AC13* + ID_MODEL_FROM_DATABASE=PCI1031 + +pci:v0000104Cd0000AC15* + ID_MODEL_FROM_DATABASE=PCI1131 + +pci:v0000104Cd0000AC16* + ID_MODEL_FROM_DATABASE=PCI1250 + +pci:v0000104Cd0000AC16sv00001014sd00000092* + ID_MODEL_FROM_DATABASE=ThinkPad 600 + +pci:v0000104Cd0000AC17* + ID_MODEL_FROM_DATABASE=PCI1220 + +pci:v0000104Cd0000AC18* + ID_MODEL_FROM_DATABASE=PCI1260 + +pci:v0000104Cd0000AC19* + ID_MODEL_FROM_DATABASE=PCI1221 + +pci:v0000104Cd0000AC1A* + ID_MODEL_FROM_DATABASE=PCI1210 + +pci:v0000104Cd0000AC1B* + ID_MODEL_FROM_DATABASE=PCI1450 + +pci:v0000104Cd0000AC1Bsv00000E11sd0000B113* + ID_MODEL_FROM_DATABASE=Armada M700 + +pci:v0000104Cd0000AC1Bsv00001014sd00000130* + ID_MODEL_FROM_DATABASE=ThinkPad 600X/A21m/T20/T22 + +pci:v0000104Cd0000AC1C* + ID_MODEL_FROM_DATABASE=PCI1225 + +pci:v0000104Cd0000AC1Csv00000E11sd0000B121* + ID_MODEL_FROM_DATABASE=Armada E500 + +pci:v0000104Cd0000AC1Csv00001028sd00000088* + ID_MODEL_FROM_DATABASE=Latitude CPi A400XT + +pci:v0000104Cd0000AC1D* + ID_MODEL_FROM_DATABASE=PCI1251A + +pci:v0000104Cd0000AC1E* + ID_MODEL_FROM_DATABASE=PCI1211 + +pci:v0000104Cd0000AC1F* + ID_MODEL_FROM_DATABASE=PCI1251B + +pci:v0000104Cd0000AC20* + ID_MODEL_FROM_DATABASE=TI 2030 + +pci:v0000104Cd0000AC21* + ID_MODEL_FROM_DATABASE=PCI2031 + +pci:v0000104Cd0000AC22* + ID_MODEL_FROM_DATABASE=PCI2032 PCI Docking Bridge + +pci:v0000104Cd0000AC23* + ID_MODEL_FROM_DATABASE=PCI2250 PCI-to-PCI Bridge + +pci:v0000104Cd0000AC28* + ID_MODEL_FROM_DATABASE=PCI2050 PCI-to-PCI Bridge + +pci:v0000104Cd0000AC2C* + ID_MODEL_FROM_DATABASE=PCI2060 PCI-to-PCI Bridge + +pci:v0000104Cd0000AC30* + ID_MODEL_FROM_DATABASE=PCI1260 PC card Cardbus Controller + +pci:v0000104Cd0000AC40* + ID_MODEL_FROM_DATABASE=PCI4450 PC card Cardbus Controller + +pci:v0000104Cd0000AC41* + ID_MODEL_FROM_DATABASE=PCI4410 PC card Cardbus Controller + +pci:v0000104Cd0000AC42* + ID_MODEL_FROM_DATABASE=PCI4451 PC card Cardbus Controller + +pci:v0000104Cd0000AC42sv00001028sd000000E6* + ID_MODEL_FROM_DATABASE=PCI4451 PC card CardBus Controller (Inspiron 8100) + +pci:v0000104Cd0000AC44* + ID_MODEL_FROM_DATABASE=PCI4510 PC card Cardbus Controller + +pci:v0000104Cd0000AC44sv00001028sd00000149* + ID_MODEL_FROM_DATABASE=Inspiron 5100 + +pci:v0000104Cd0000AC44sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v0000104Cd0000AC44sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v0000104Cd0000AC44sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v0000104Cd0000AC46* + ID_MODEL_FROM_DATABASE=PCI4520 PC card Cardbus Controller + +pci:v0000104Cd0000AC46sv00001014sd00000552* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v0000104Cd0000AC47* + ID_MODEL_FROM_DATABASE=PCI7510 PC card Cardbus Controller + +pci:v0000104Cd0000AC47sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v0000104Cd0000AC47sv00001028sd0000013F* + ID_MODEL_FROM_DATABASE=Precision M60 + +pci:v0000104Cd0000AC47sv00001028sd0000014E* + ID_MODEL_FROM_DATABASE=Latitude D800 + +pci:v0000104Cd0000AC48* + ID_MODEL_FROM_DATABASE=PCI7610 PC Card Cardbus Controller + +pci:v0000104Cd0000AC49* + ID_MODEL_FROM_DATABASE=PCI7410 PC Card Cardbus Controller + +pci:v0000104Cd0000AC4A* + ID_MODEL_FROM_DATABASE=PCI7510/7610 CardBus Bridge + +pci:v0000104Cd0000AC4Asv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v0000104Cd0000AC4Asv00001028sd0000014E* + ID_MODEL_FROM_DATABASE=Latitude D800 + +pci:v0000104Cd0000AC4B* + ID_MODEL_FROM_DATABASE=PCI7610 SD/MMC controller + +pci:v0000104Cd0000AC4C* + ID_MODEL_FROM_DATABASE=PCI7610 Memory Stick controller + +pci:v0000104Cd0000AC50* + ID_MODEL_FROM_DATABASE=PCI1410 PC card Cardbus Controller + +pci:v0000104Cd0000AC51* + ID_MODEL_FROM_DATABASE=PCI1420 PC card Cardbus Controller + +pci:v0000104Cd0000AC51sv00000E11sd0000004E* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v0000104Cd0000AC51sv00001014sd00000148* + ID_MODEL_FROM_DATABASE=ThinkPad A20m + +pci:v0000104Cd0000AC51sv00001014sd0000023B* + ID_MODEL_FROM_DATABASE=ThinkPad T23 + +pci:v0000104Cd0000AC51sv00001028sd000000B1* + ID_MODEL_FROM_DATABASE=Latitude C600 + +pci:v0000104Cd0000AC51sv00001028sd0000012A* + ID_MODEL_FROM_DATABASE=Latitude C640 + +pci:v0000104Cd0000AC51sv00001033sd000080CD* + ID_MODEL_FROM_DATABASE=Versa Note VXi + +pci:v0000104Cd0000AC51sv000010CFsd00001095* + ID_MODEL_FROM_DATABASE=Lifebook S-4510/C6155 + +pci:v0000104Cd0000AC51sv0000E4BFsd00001000* + ID_MODEL_FROM_DATABASE=CP2-2-HIPHOP + +pci:v0000104Cd0000AC52* + ID_MODEL_FROM_DATABASE=PCI1451 PC card Cardbus Controller + +pci:v0000104Cd0000AC53* + ID_MODEL_FROM_DATABASE=PCI1421 PC card Cardbus Controller + +pci:v0000104Cd0000AC54* + ID_MODEL_FROM_DATABASE=PCI1620 PC Card Controller + +pci:v0000104Cd0000AC54sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v0000104Cd0000AC55* + ID_MODEL_FROM_DATABASE=PCI1520 PC card Cardbus Controller + +pci:v0000104Cd0000AC55sv00001014sd00000512* + ID_MODEL_FROM_DATABASE=ThinkPad T30/T40 + +pci:v0000104Cd0000AC55sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v0000104Cd0000AC56* + ID_MODEL_FROM_DATABASE=PCI1510 PC card Cardbus Controller + +pci:v0000104Cd0000AC56sv00001014sd00000512* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v0000104Cd0000AC56sv00001014sd00000528* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v0000104Cd0000AC56sv000017AAsd00002012* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v0000104Cd0000AC60* + ID_MODEL_FROM_DATABASE=PCI2040 PCI to DSP Bridge Controller + +pci:v0000104Cd0000AC60sv0000175Csd00005100* + ID_MODEL_FROM_DATABASE=ASI51xx Audio Adapter + +pci:v0000104Cd0000AC60sv0000175Csd00006100* + ID_MODEL_FROM_DATABASE=ASI61xx Audio Adapter + +pci:v0000104Cd0000AC60sv0000175Csd00006200* + ID_MODEL_FROM_DATABASE=ASI62xx Audio Adapter + +pci:v0000104Cd0000AC60sv0000175Csd00008800* + ID_MODEL_FROM_DATABASE=ASI88xx Audio Adapter + +pci:v0000104Cd0000AC60sv0000186Fsd00003001* + ID_MODEL_FROM_DATABASE=WR-G303 PCI radio receiver + +pci:v0000104Cd0000AC60sv0000186Fsd00003005* + ID_MODEL_FROM_DATABASE=WR-G305 PCI radio receiver + +pci:v0000104Cd0000AC60sv0000186Fsd00003101* + ID_MODEL_FROM_DATABASE=WR-G313 PCI radio receiver + +pci:v0000104Cd0000AC60sv0000186Fsd00003105* + ID_MODEL_FROM_DATABASE=WR-G315 PCI radio receiver + +pci:v0000104Cd0000AC8D* + ID_MODEL_FROM_DATABASE=PCI 7620 + +pci:v0000104Cd0000AC8E* + ID_MODEL_FROM_DATABASE=PCI7420 CardBus Controller + +pci:v0000104Cd0000AC8Esv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v0000104Cd0000AC8F* + ID_MODEL_FROM_DATABASE=PCI7420/7620 SD/MS-Pro Controller + +pci:v0000104Cd0000AC8Fsv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v0000104Cd0000B001* + ID_MODEL_FROM_DATABASE=TMS320C6424 + +pci:v0000104Cd0000FE00* + ID_MODEL_FROM_DATABASE=FireWire Host Controller + +pci:v0000104Cd0000FE03* + ID_MODEL_FROM_DATABASE=12C01A FireWire Host Controller + +pci:v0000104D* + ID_VENDOR_FROM_DATABASE=Sony Corporation + +pci:v0000104Dd00008004* + ID_MODEL_FROM_DATABASE=DTL-H2500 [Playstation development board] + +pci:v0000104Dd00008009* + ID_MODEL_FROM_DATABASE=CXD1947Q i.LINK Controller + +pci:v0000104Dd00008039* + ID_MODEL_FROM_DATABASE=CXD3222 i.LINK Controller + +pci:v0000104Dd00008056* + ID_MODEL_FROM_DATABASE=Rockwell HCF 56K modem + +pci:v0000104Dd0000808A* + ID_MODEL_FROM_DATABASE=Memory Stick Controller + +pci:v0000104Dd000081CE* + ID_MODEL_FROM_DATABASE=SxS Pro memory card + +pci:v0000104E* + ID_VENDOR_FROM_DATABASE=Oak Technology, Inc + +pci:v0000104Ed00000017* + ID_MODEL_FROM_DATABASE=OTI-64017 + +pci:v0000104Ed00000107* + ID_MODEL_FROM_DATABASE=OTI-107 [Spitfire] + +pci:v0000104Ed00000109* + ID_MODEL_FROM_DATABASE=Video Adapter + +pci:v0000104Ed00000111* + ID_MODEL_FROM_DATABASE=OTI-64111 [Spitfire] + +pci:v0000104Ed00000217* + ID_MODEL_FROM_DATABASE=OTI-64217 + +pci:v0000104Ed00000317* + ID_MODEL_FROM_DATABASE=OTI-64317 + +pci:v0000104F* + ID_VENDOR_FROM_DATABASE=Co-time Computer Ltd + +pci:v00001050* + ID_VENDOR_FROM_DATABASE=Winbond Electronics Corp + +pci:v00001050d00000000* + ID_MODEL_FROM_DATABASE=NE2000 + +pci:v00001050d00000001* + ID_MODEL_FROM_DATABASE=W83769F + +pci:v00001050d00000033* + ID_MODEL_FROM_DATABASE=W89C33D 802.11 a/b/g BB/MAC + +pci:v00001050d00000105* + ID_MODEL_FROM_DATABASE=W82C105 + +pci:v00001050d00000840* + ID_MODEL_FROM_DATABASE=W89C840 + +pci:v00001050d00000840sv00001050sd00000001* + ID_MODEL_FROM_DATABASE=W89C840 Ethernet Adapter + +pci:v00001050d00000840sv00001050sd00000840* + ID_MODEL_FROM_DATABASE=W89C840 Ethernet Adapter + +pci:v00001050d00000940* + ID_MODEL_FROM_DATABASE=W89C940 + +pci:v00001050d00005A5A* + ID_MODEL_FROM_DATABASE=W89C940F + +pci:v00001050d00006692* + ID_MODEL_FROM_DATABASE=W6692 + +pci:v00001050d00006692sv00001043sd00001702* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, W) + +pci:v00001050d00006692sv00001043sd00001703* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001050d00006692sv00001043sd00001707* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001050d00006692sv0000144Fsd00001702* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, W) + +pci:v00001050d00006692sv0000144Fsd00001703* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001050d00006692sv0000144Fsd00001707* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, DV, W) + +pci:v00001050d00009921* + ID_MODEL_FROM_DATABASE=W99200F MPEG-1 Video Encoder + +pci:v00001050d00009922* + ID_MODEL_FROM_DATABASE=W99200F/W9922PF MPEG-1/2 Video Encoder + +pci:v00001050d00009970* + ID_MODEL_FROM_DATABASE=W9970CF + +pci:v00001051* + ID_VENDOR_FROM_DATABASE=Anigma, Inc. + +pci:v00001052* + ID_VENDOR_FROM_DATABASE=?Young Micro Systems + +pci:v00001053* + ID_VENDOR_FROM_DATABASE=Young Micro Systems + +pci:v00001054* + ID_VENDOR_FROM_DATABASE=Hitachi, Ltd + +pci:v00001054d00003009* + ID_MODEL_FROM_DATABASE=2Gbps Fibre Channel to PCI HBA 3009 + +pci:v00001054d0000300A* + ID_MODEL_FROM_DATABASE=4Gbps Fibre Channel to PCI-X HBA 300a + +pci:v00001054d0000300B* + ID_MODEL_FROM_DATABASE=4Gbps Fibre Channel to PCI-X HBA 300b + +pci:v00001054d0000300F* + ID_MODEL_FROM_DATABASE=ColdFusion 3 Chipset Processor to I/O Controller + +pci:v00001054d00003010* + ID_MODEL_FROM_DATABASE=ColdFusion 3 Chipset Memory Controller Hub + +pci:v00001054d00003011* + ID_MODEL_FROM_DATABASE=ColdFusion 3e Chipset Processor to I/O Controller + +pci:v00001054d00003012* + ID_MODEL_FROM_DATABASE=ColdFusion 3e Chipset Memory Controller Hub + +pci:v00001054d00003017* + ID_MODEL_FROM_DATABASE=Unassigned Hitachi Shared FC Device 3017 + +pci:v00001054d0000301B* + ID_MODEL_FROM_DATABASE=Virtual VGA Device + +pci:v00001054d0000301D* + ID_MODEL_FROM_DATABASE=PCIe-to-PCIe Bridge with Virtualization IO Assist Feature + +pci:v00001054d00003020* + ID_MODEL_FROM_DATABASE=FIVE-EX based Fibre Channel to PCIe HBA + +pci:v00001054d0000302C* + ID_MODEL_FROM_DATABASE=M001 PCI Express Switch Upstream Port + +pci:v00001054d0000302D* + ID_MODEL_FROM_DATABASE=M001 PCI Express Switch Downstream Port + +pci:v00001054d00003505* + ID_MODEL_FROM_DATABASE=SH7751 PCI Controller (PCIC) + +pci:v00001054d0000350E* + ID_MODEL_FROM_DATABASE=SH7751R PCI Controller (PCIC) + +pci:v00001055* + ID_VENDOR_FROM_DATABASE=Efar Microsystems + +pci:v00001055d00009130* + ID_MODEL_FROM_DATABASE=SLC90E66 [Victory66] IDE + +pci:v00001055d00009460* + ID_MODEL_FROM_DATABASE=SLC90E66 [Victory66] ISA + +pci:v00001055d00009462* + ID_MODEL_FROM_DATABASE=SLC90E66 [Victory66] USB + +pci:v00001055d00009463* + ID_MODEL_FROM_DATABASE=SLC90E66 [Victory66] ACPI + +pci:v00001055d0000E420* + ID_MODEL_FROM_DATABASE=LAN9420/LAN9420i + +pci:v00001056* + ID_VENDOR_FROM_DATABASE=ICL + +pci:v00001057* + ID_VENDOR_FROM_DATABASE=Motorola + +pci:v00001057d00000001* + ID_MODEL_FROM_DATABASE=MPC105 [Eagle] + +pci:v00001057d00000002* + ID_MODEL_FROM_DATABASE=MPC106 [Grackle] + +pci:v00001057d00000003* + ID_MODEL_FROM_DATABASE=MPC8240 [Kahlua] + +pci:v00001057d00000004* + ID_MODEL_FROM_DATABASE=MPC107 + +pci:v00001057d00000006* + ID_MODEL_FROM_DATABASE=MPC8245 [Unity] + +pci:v00001057d00000008* + ID_MODEL_FROM_DATABASE=MPC8540 + +pci:v00001057d00000009* + ID_MODEL_FROM_DATABASE=MPC8560 + +pci:v00001057d00000012* + ID_MODEL_FROM_DATABASE=MPC8548 [PowerQUICC III] + +pci:v00001057d00000100* + ID_MODEL_FROM_DATABASE=MC145575 [HFC-PCI] + +pci:v00001057d00000431* + ID_MODEL_FROM_DATABASE=KTI829c 100VG + +pci:v00001057d00001073* + ID_MODEL_FROM_DATABASE=Nokia N770 + +pci:v00001057d00001219* + ID_MODEL_FROM_DATABASE=Nokia N800 + +pci:v00001057d00001801* + ID_MODEL_FROM_DATABASE=DSP56301 Digital Signal Processor + +pci:v00001057d00001801sv000014FBsd00000101* + ID_MODEL_FROM_DATABASE=Transas Radar Imitator Board [RIM] + +pci:v00001057d00001801sv000014FBsd00000102* + ID_MODEL_FROM_DATABASE=Transas Radar Imitator Board [RIM-2] + +pci:v00001057d00001801sv000014FBsd00000202* + ID_MODEL_FROM_DATABASE=Transas Radar Integrator Board [RIB-2] + +pci:v00001057d00001801sv000014FBsd00000611* + ID_MODEL_FROM_DATABASE=1 channel CAN bus Controller [CanPci-1] + +pci:v00001057d00001801sv000014FBsd00000612* + ID_MODEL_FROM_DATABASE=2 channels CAN bus Controller [CanPci-2] + +pci:v00001057d00001801sv000014FBsd00000613* + ID_MODEL_FROM_DATABASE=3 channels CAN bus Controller [CanPci-3] + +pci:v00001057d00001801sv000014FBsd00000614* + ID_MODEL_FROM_DATABASE=4 channels CAN bus Controller [CanPci-4] + +pci:v00001057d00001801sv000014FBsd00000621* + ID_MODEL_FROM_DATABASE=1 channel CAN bus Controller [CanPci2-1] + +pci:v00001057d00001801sv000014FBsd00000622* + ID_MODEL_FROM_DATABASE=2 channels CAN bus Controller [CanPci2-2] + +pci:v00001057d00001801sv000014FBsd00000810* + ID_MODEL_FROM_DATABASE=Transas VTS Radar Integrator Board [RIB-4] + +pci:v00001057d00001801sv0000175Csd00004200* + ID_MODEL_FROM_DATABASE=ASI4215 Audio Adapter + +pci:v00001057d00001801sv0000175Csd00004300* + ID_MODEL_FROM_DATABASE=ASI43xx Audio Adapter + +pci:v00001057d00001801sv0000175Csd00004400* + ID_MODEL_FROM_DATABASE=ASI4401 Audio Adapter + +pci:v00001057d00001801sv0000ECC0sd00000010* + ID_MODEL_FROM_DATABASE=Darla + +pci:v00001057d00001801sv0000ECC0sd00000020* + ID_MODEL_FROM_DATABASE=Gina + +pci:v00001057d00001801sv0000ECC0sd00000030* + ID_MODEL_FROM_DATABASE=Layla rev.0 + +pci:v00001057d00001801sv0000ECC0sd00000031* + ID_MODEL_FROM_DATABASE=Layla rev.1 + +pci:v00001057d00001801sv0000ECC0sd00000040* + ID_MODEL_FROM_DATABASE=Darla24 rev.0 + +pci:v00001057d00001801sv0000ECC0sd00000041* + ID_MODEL_FROM_DATABASE=Darla24 rev.1 + +pci:v00001057d00001801sv0000ECC0sd00000050* + ID_MODEL_FROM_DATABASE=Gina24 rev.0 + +pci:v00001057d00001801sv0000ECC0sd00000051* + ID_MODEL_FROM_DATABASE=Gina24 rev.1 + +pci:v00001057d00001801sv0000ECC0sd00000070* + ID_MODEL_FROM_DATABASE=Mona rev.0 + +pci:v00001057d00001801sv0000ECC0sd00000071* + ID_MODEL_FROM_DATABASE=Mona rev.1 + +pci:v00001057d00001801sv0000ECC0sd00000072* + ID_MODEL_FROM_DATABASE=Mona rev.2 + +pci:v00001057d000018C0* + ID_MODEL_FROM_DATABASE=MPC8265A/8266/8272 + +pci:v00001057d000018C1* + ID_MODEL_FROM_DATABASE=MPC8271/MPC8272 + +pci:v00001057d00003052* + ID_MODEL_FROM_DATABASE=SM56 Data Fax Modem + +pci:v00001057d00003410* + ID_MODEL_FROM_DATABASE=DSP56361 Digital Signal Processor + +pci:v00001057d00003410sv0000ECC0sd00000050* + ID_MODEL_FROM_DATABASE=Gina24 rev.0 + +pci:v00001057d00003410sv0000ECC0sd00000051* + ID_MODEL_FROM_DATABASE=Gina24 rev.1 + +pci:v00001057d00003410sv0000ECC0sd00000060* + ID_MODEL_FROM_DATABASE=Layla24 + +pci:v00001057d00003410sv0000ECC0sd00000070* + ID_MODEL_FROM_DATABASE=Mona rev.0 + +pci:v00001057d00003410sv0000ECC0sd00000071* + ID_MODEL_FROM_DATABASE=Mona rev.1 + +pci:v00001057d00003410sv0000ECC0sd00000072* + ID_MODEL_FROM_DATABASE=Mona rev.2 + +pci:v00001057d00003410sv0000ECC0sd00000080* + ID_MODEL_FROM_DATABASE=Mia rev.0 + +pci:v00001057d00003410sv0000ECC0sd00000081* + ID_MODEL_FROM_DATABASE=Mia rev.1 + +pci:v00001057d00003410sv0000ECC0sd00000090* + ID_MODEL_FROM_DATABASE=Indigo + +pci:v00001057d00003410sv0000ECC0sd000000A0* + ID_MODEL_FROM_DATABASE=Indigo IO + +pci:v00001057d00003410sv0000ECC0sd000000B0* + ID_MODEL_FROM_DATABASE=Indigo DJ + +pci:v00001057d00003410sv0000ECC0sd00000100* + ID_MODEL_FROM_DATABASE=3G + +pci:v00001057d00004801* + ID_MODEL_FROM_DATABASE=Raven + +pci:v00001057d00004802* + ID_MODEL_FROM_DATABASE=Falcon + +pci:v00001057d00004803* + ID_MODEL_FROM_DATABASE=Hawk + +pci:v00001057d00004806* + ID_MODEL_FROM_DATABASE=CPX8216 + +pci:v00001057d00004D68* + ID_MODEL_FROM_DATABASE=20268 + +pci:v00001057d00005600* + ID_MODEL_FROM_DATABASE=SM56 PCI Modem + +pci:v00001057d00005600sv00001057sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv00001057sd00000301* + ID_MODEL_FROM_DATABASE=SM56 PCI Voice Modem + +pci:v00001057d00005600sv00001057sd00000302* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005600sv00001057sd00005600* + ID_MODEL_FROM_DATABASE=SM56 PCI Voice modem + +pci:v00001057d00005600sv000013D2sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv000013D2sd00000301* + ID_MODEL_FROM_DATABASE=SM56 PCI Voice modem + +pci:v00001057d00005600sv000013D2sd00000302* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005600sv00001436sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv00001436sd00000301* + ID_MODEL_FROM_DATABASE=SM56 PCI Voice modem + +pci:v00001057d00005600sv00001436sd00000302* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005600sv0000144Fsd0000100C* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005600sv00001494sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv00001494sd00000301* + ID_MODEL_FROM_DATABASE=SM56 PCI Voice modem + +pci:v00001057d00005600sv000014C8sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv000014C8sd00000302* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005600sv00001668sd00000300* + ID_MODEL_FROM_DATABASE=SM56 PCI Speakerphone Modem + +pci:v00001057d00005600sv00001668sd00000302* + ID_MODEL_FROM_DATABASE=SM56 PCI Fax Modem + +pci:v00001057d00005608* + ID_MODEL_FROM_DATABASE=Wildcard X100P + +pci:v00001057d00005803* + ID_MODEL_FROM_DATABASE=MPC5200 + +pci:v00001057d00005806* + ID_MODEL_FROM_DATABASE=MCF54 Coldfire + +pci:v00001057d00005808* + ID_MODEL_FROM_DATABASE=MPC8220 + +pci:v00001057d00005809* + ID_MODEL_FROM_DATABASE=MPC5200B + +pci:v00001057d00006400* + ID_MODEL_FROM_DATABASE=MPC190 Security Processor (S1 family, encryption) + +pci:v00001057d00006405* + ID_MODEL_FROM_DATABASE=MPC184 Security Processor (S1 family) + +pci:v00001058* + ID_VENDOR_FROM_DATABASE=Electronics & Telecommunications RSH + +pci:v00001059* + ID_VENDOR_FROM_DATABASE=Kontron + +pci:v0000105A* + ID_VENDOR_FROM_DATABASE=Promise Technology, Inc. + +pci:v0000105Ad00000D30* + ID_MODEL_FROM_DATABASE=PDC20265 (FastTrak100 Lite/Ultra100) + +pci:v0000105Ad00000D30sv00001043sd00008042* + ID_MODEL_FROM_DATABASE=AV7266-E South Bridge Promise RAID + +pci:v0000105Ad00000D30sv0000105Asd00004D33* + ID_MODEL_FROM_DATABASE=Ultra100 + +pci:v0000105Ad00000D38* + ID_MODEL_FROM_DATABASE=20263 + +pci:v0000105Ad00000D38sv0000105Asd00004D39* + ID_MODEL_FROM_DATABASE=Fasttrak66 + +pci:v0000105Ad00001275* + ID_MODEL_FROM_DATABASE=20275 + +pci:v0000105Ad00003318* + ID_MODEL_FROM_DATABASE=PDC20318 (SATA150 TX4) + +pci:v0000105Ad00003319* + ID_MODEL_FROM_DATABASE=PDC20319 (FastTrak S150 TX4) + +pci:v0000105Ad00003319sv0000105Asd00003319* + ID_MODEL_FROM_DATABASE=FastTrak S150 TX4 4 port SATA PCI board + +pci:v0000105Ad00003319sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v0000105Ad00003371* + ID_MODEL_FROM_DATABASE=PDC20371 (FastTrak S150 TX2plus) + +pci:v0000105Ad00003373* + ID_MODEL_FROM_DATABASE=PDC20378 (FastTrak 378/SATA 378) + +pci:v0000105Ad00003373sv00001043sd000080F5* + ID_MODEL_FROM_DATABASE=K8V Deluxe/PC-DL Deluxe motherboard + +pci:v0000105Ad00003373sv00001462sd0000590D* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v0000105Ad00003373sv00001462sd0000702E* + ID_MODEL_FROM_DATABASE=K8T NEO FIS2R motherboard + +pci:v0000105Ad00003375* + ID_MODEL_FROM_DATABASE=PDC20375 (SATA150 TX2plus) + +pci:v0000105Ad00003376* + ID_MODEL_FROM_DATABASE=PDC20376 (FastTrak 376) + +pci:v0000105Ad00003376sv00001043sd0000809E* + ID_MODEL_FROM_DATABASE=A7V8X motherboard + +pci:v0000105Ad00003515* + ID_MODEL_FROM_DATABASE=PDC40719 [FastTrak TX4300/TX4310] + +pci:v0000105Ad00003519* + ID_MODEL_FROM_DATABASE=PDC40519 (FastTrak TX4200) + +pci:v0000105Ad00003570* + ID_MODEL_FROM_DATABASE=PDC20771 [FastTrak TX2300] + +pci:v0000105Ad00003571* + ID_MODEL_FROM_DATABASE=PDC20571 (FastTrak TX2200) + +pci:v0000105Ad00003574* + ID_MODEL_FROM_DATABASE=PDC20579 SATAII 150 IDE Controller + +pci:v0000105Ad00003577* + ID_MODEL_FROM_DATABASE=PDC40779 (SATA 300 779) + +pci:v0000105Ad00003D17* + ID_MODEL_FROM_DATABASE=PDC40718 (SATA 300 TX4) + +pci:v0000105Ad00003D18* + ID_MODEL_FROM_DATABASE=PDC20518/PDC40518 (SATAII 150 TX4) + +pci:v0000105Ad00003D73* + ID_MODEL_FROM_DATABASE=PDC40775 (SATA 300 TX2plus) + +pci:v0000105Ad00003D75* + ID_MODEL_FROM_DATABASE=PDC20575 (SATAII150 TX2plus) + +pci:v0000105Ad00003F20* + ID_MODEL_FROM_DATABASE=PDC42819 [FastTrak TX2650/TX4650] + +pci:v0000105Ad00004302* + ID_MODEL_FROM_DATABASE=80333 [SuperTrak EX4350] + +pci:v0000105Ad00004D30* + ID_MODEL_FROM_DATABASE=PDC20267 (FastTrak100/Ultra100) + +pci:v0000105Ad00004D30sv0000105Asd00004D33* + ID_MODEL_FROM_DATABASE=Ultra100 + +pci:v0000105Ad00004D30sv0000105Asd00004D39* + ID_MODEL_FROM_DATABASE=FastTrak100 + +pci:v0000105Ad00004D30sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v0000105Ad00004D33* + ID_MODEL_FROM_DATABASE=20246 + +pci:v0000105Ad00004D33sv0000105Asd00004D33* + ID_MODEL_FROM_DATABASE=20246 IDE Controller + +pci:v0000105Ad00004D38* + ID_MODEL_FROM_DATABASE=PDC20262 (FastTrak66/Ultra66) + +pci:v0000105Ad00004D38sv0000105Asd00004D30* + ID_MODEL_FROM_DATABASE=Ultra Device on SuperTrak + +pci:v0000105Ad00004D38sv0000105Asd00004D33* + ID_MODEL_FROM_DATABASE=Ultra66 + +pci:v0000105Ad00004D38sv0000105Asd00004D39* + ID_MODEL_FROM_DATABASE=FastTrak66 + +pci:v0000105Ad00004D68* + ID_MODEL_FROM_DATABASE=PDC20268 [Ultra100 TX2] + +pci:v0000105Ad00004D68sv0000105Asd00004D68* + ID_MODEL_FROM_DATABASE=Ultra100 TX2 + +pci:v0000105Ad00004D69* + ID_MODEL_FROM_DATABASE=20269 + +pci:v0000105Ad00004D69sv0000105Asd00004D68* + ID_MODEL_FROM_DATABASE=Ultra133TX2 + +pci:v0000105Ad00005275* + ID_MODEL_FROM_DATABASE=PDC20276 (MBFastTrak133 Lite) + +pci:v0000105Ad00005275sv00001043sd0000807E* + ID_MODEL_FROM_DATABASE=A7V333 motherboard. + +pci:v0000105Ad00005275sv0000105Asd00000275* + ID_MODEL_FROM_DATABASE=SuperTrak SX6000 IDE + +pci:v0000105Ad00005275sv0000105Asd00001275* + ID_MODEL_FROM_DATABASE=MBFastTrak133 Lite (tm) Controller (RAID mode) + +pci:v0000105Ad00005275sv00001458sd0000B001* + ID_MODEL_FROM_DATABASE=MBUltra 133 + +pci:v0000105Ad00005300* + ID_MODEL_FROM_DATABASE=DC5300 + +pci:v0000105Ad00006268* + ID_MODEL_FROM_DATABASE=PDC20270 (FastTrak100 LP/TX2/TX4) + +pci:v0000105Ad00006268sv0000105Asd00004D68* + ID_MODEL_FROM_DATABASE=FastTrak100 TX2 + +pci:v0000105Ad00006269* + ID_MODEL_FROM_DATABASE=PDC20271 (FastTrak TX2000) + +pci:v0000105Ad00006269sv0000105Asd00006269* + ID_MODEL_FROM_DATABASE=FastTrak TX2/TX2000 + +pci:v0000105Ad00006300* + ID_MODEL_FROM_DATABASE=PDC81731 [FastTrak SX8300] + +pci:v0000105Ad00006621* + ID_MODEL_FROM_DATABASE=PDC20621 (FastTrak S150 SX4/FastTrak SX4000 lite) + +pci:v0000105Ad00006622* + ID_MODEL_FROM_DATABASE=PDC20621 [SATA150 SX4] 4 Channel IDE RAID Controller + +pci:v0000105Ad00006624* + ID_MODEL_FROM_DATABASE=PDC20621 [FastTrak SX4100] + +pci:v0000105Ad00006626* + ID_MODEL_FROM_DATABASE=PDC20618 (Ultra 618) + +pci:v0000105Ad00006629* + ID_MODEL_FROM_DATABASE=PDC20619 (FastTrak TX4000) + +pci:v0000105Ad00007275* + ID_MODEL_FROM_DATABASE=PDC20277 (SBFastTrak133 Lite) + +pci:v0000105Ad00008002* + ID_MODEL_FROM_DATABASE=SATAII150 SX8 + +pci:v0000105Ad00008350* + ID_MODEL_FROM_DATABASE=80333 [SuperTrak EX8350/EX16350], 80331 [SuperTrak EX8300/EX16300] + +pci:v0000105Ad00008650* + ID_MODEL_FROM_DATABASE=81384 [SuperTrak EX SAS and SATA RAID Controller] + +pci:v0000105Ad00008650sv0000105Asd00004600* + ID_MODEL_FROM_DATABASE=SuperTrak EX4650A + +pci:v0000105Ad00008650sv0000105Asd00004601* + ID_MODEL_FROM_DATABASE=SuperTrak EX4650 + +pci:v0000105Ad00008650sv0000105Asd00004610* + ID_MODEL_FROM_DATABASE=SuperTrak EX4650EL + +pci:v0000105Ad00008650sv0000105Asd00008600* + ID_MODEL_FROM_DATABASE=SuperTrak EX8650EL + +pci:v0000105Ad00008650sv0000105Asd00008601* + ID_MODEL_FROM_DATABASE=SuperTrak EX8650A + +pci:v0000105Ad00008650sv0000105Asd00008602* + ID_MODEL_FROM_DATABASE=SuperTrak EX8654 + +pci:v0000105Ad00008650sv0000105Asd00008603* + ID_MODEL_FROM_DATABASE=SuperTrak EX8658 + +pci:v0000105Ad00008650sv0000105Asd00008604* + ID_MODEL_FROM_DATABASE=SuperTrak EX8650 + +pci:v0000105Ad00008650sv0000105Asd00008610* + ID_MODEL_FROM_DATABASE=SuperTrak EX8650M + +pci:v0000105Ad00008650sv0000105Asd0000A600* + ID_MODEL_FROM_DATABASE=SuperTrak EX12650 + +pci:v0000105Ad00008650sv0000105Asd0000B600* + ID_MODEL_FROM_DATABASE=SuperTrak EX16650 + +pci:v0000105Ad00008650sv0000105Asd0000B601* + ID_MODEL_FROM_DATABASE=SuperTrak EX16654 + +pci:v0000105Ad00008650sv0000105Asd0000B602* + ID_MODEL_FROM_DATABASE=SuperTrak EX16658 + +pci:v0000105Ad00008760* + ID_MODEL_FROM_DATABASE=PM8010 [SuperTrak EX SAS and SATA 6G RAID Controller] + +pci:v0000105Ad0000C350* + ID_MODEL_FROM_DATABASE=80333 [SuperTrak EX12350] + +pci:v0000105Ad0000E350* + ID_MODEL_FROM_DATABASE=80333 [SuperTrak EX24350] + +pci:v0000105B* + ID_VENDOR_FROM_DATABASE=Foxconn International, Inc. + +pci:v0000105C* + ID_VENDOR_FROM_DATABASE=Wipro Infotech Limited + +pci:v0000105D* + ID_VENDOR_FROM_DATABASE=Number 9 Computer Company + +pci:v0000105Dd00002309* + ID_MODEL_FROM_DATABASE=Imagine 128 + +pci:v0000105Dd00002339* + ID_MODEL_FROM_DATABASE=Imagine 128-II + +pci:v0000105Dd00002339sv0000105Dsd00000000* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000001* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000002* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000003* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000004* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000005* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000006* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000007* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 4Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd00000008* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2e 4Mb DRAM + +pci:v0000105Dd00002339sv0000105Dsd00000009* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2e 4Mb DRAM + +pci:v0000105Dd00002339sv0000105Dsd0000000A* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 8Mb VRAM + +pci:v0000105Dd00002339sv0000105Dsd0000000B* + ID_MODEL_FROM_DATABASE=Imagine 128 series 2 8Mb H-VRAM + +pci:v0000105Dd00002339sv000011A4sd0000000A* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000000* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000004* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000005* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000006* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000008* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd00000009* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd0000000A* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd00002339sv000013CCsd0000000C* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel + +pci:v0000105Dd0000493D* + ID_MODEL_FROM_DATABASE=Imagine 128 T2R [Ticket to Ride] + +pci:v0000105Dd0000493Dsv000011A4sd0000000A* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000011A4sd0000000B* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd00000002* + ID_MODEL_FROM_DATABASE=Barco Metheus 4 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd00000003* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd00000007* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd00000008* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd00000009* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd0000493Dsv000013CCsd0000000A* + ID_MODEL_FROM_DATABASE=Barco Metheus 5 Megapixel, Dual Head + +pci:v0000105Dd00005348* + ID_MODEL_FROM_DATABASE=Revolution 4 + +pci:v0000105Dd00005348sv0000105Dsd00000037* + ID_MODEL_FROM_DATABASE=Revolution IV-FP AGP (For SGI 1600SW) + +pci:v0000105Dd00005348sv000011A4sd00000028* + ID_MODEL_FROM_DATABASE=PVS5600M + +pci:v0000105Dd00005348sv000011A4sd00000038* + ID_MODEL_FROM_DATABASE=PVS5600D + +pci:v0000105E* + ID_VENDOR_FROM_DATABASE=Vtech Computers Ltd + +pci:v0000105F* + ID_VENDOR_FROM_DATABASE=Infotronic America Inc + +pci:v00001060* + ID_VENDOR_FROM_DATABASE=United Microelectronics [UMC] + +pci:v00001060d00000001* + ID_MODEL_FROM_DATABASE=UM82C881 + +pci:v00001060d00000002* + ID_MODEL_FROM_DATABASE=UM82C886 + +pci:v00001060d00000101* + ID_MODEL_FROM_DATABASE=UM8673F + +pci:v00001060d00000881* + ID_MODEL_FROM_DATABASE=UM8881 + +pci:v00001060d00000886* + ID_MODEL_FROM_DATABASE=UM8886F + +pci:v00001060d00000891* + ID_MODEL_FROM_DATABASE=UM8891A + +pci:v00001060d00001001* + ID_MODEL_FROM_DATABASE=UM886A + +pci:v00001060d0000673A* + ID_MODEL_FROM_DATABASE=UM8886BF + +pci:v00001060d0000673B* + ID_MODEL_FROM_DATABASE=EIDE Master/DMA + +pci:v00001060d00008710* + ID_MODEL_FROM_DATABASE=UM8710 + +pci:v00001060d0000886A* + ID_MODEL_FROM_DATABASE=UM8886A + +pci:v00001060d00008881* + ID_MODEL_FROM_DATABASE=UM8881F + +pci:v00001060d00008886* + ID_MODEL_FROM_DATABASE=UM8886F + +pci:v00001060d0000888A* + ID_MODEL_FROM_DATABASE=UM8886A + +pci:v00001060d00008891* + ID_MODEL_FROM_DATABASE=UM8891A + +pci:v00001060d00009017* + ID_MODEL_FROM_DATABASE=UM9017F + +pci:v00001060d00009018* + ID_MODEL_FROM_DATABASE=UM9018 + +pci:v00001060d00009026* + ID_MODEL_FROM_DATABASE=UM9026 + +pci:v00001060d0000E881* + ID_MODEL_FROM_DATABASE=UM8881N + +pci:v00001060d0000E886* + ID_MODEL_FROM_DATABASE=UM8886N + +pci:v00001060d0000E88A* + ID_MODEL_FROM_DATABASE=UM8886N + +pci:v00001060d0000E891* + ID_MODEL_FROM_DATABASE=UM8891N + +pci:v00001061* + ID_VENDOR_FROM_DATABASE=I.I.T. + +pci:v00001061d00000001* + ID_MODEL_FROM_DATABASE=AGX016 + +pci:v00001061d00000002* + ID_MODEL_FROM_DATABASE=IIT3204/3501 + +pci:v00001062* + ID_VENDOR_FROM_DATABASE=Maspar Computer Corp + +pci:v00001063* + ID_VENDOR_FROM_DATABASE=Ocean Office Automation + +pci:v00001064* + ID_VENDOR_FROM_DATABASE=Alcatel + +pci:v00001064d00001102* + ID_MODEL_FROM_DATABASE=Dynamite 2840 (ADSL PCI modem) + +pci:v00001065* + ID_VENDOR_FROM_DATABASE=Texas Microsystems + +pci:v00001066* + ID_VENDOR_FROM_DATABASE=PicoPower Technology + +pci:v00001066d00000000* + ID_MODEL_FROM_DATABASE=PT80C826 + +pci:v00001066d00000001* + ID_MODEL_FROM_DATABASE=PT86C521 [Vesuvius v1] Host Bridge + +pci:v00001066d00000002* + ID_MODEL_FROM_DATABASE=PT86C523 [Vesuvius v3] PCI-ISA Bridge Master + +pci:v00001066d00000003* + ID_MODEL_FROM_DATABASE=PT86C524 [Nile] PCI-to-PCI Bridge + +pci:v00001066d00000004* + ID_MODEL_FROM_DATABASE=PT86C525 [Nile-II] PCI-to-PCI Bridge + +pci:v00001066d00000005* + ID_MODEL_FROM_DATABASE=National PC87550 System Controller + +pci:v00001066d00008002* + ID_MODEL_FROM_DATABASE=PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave + +pci:v00001067* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric + +pci:v00001067d00000301* + ID_MODEL_FROM_DATABASE=AccelGraphics AccelECLIPSE + +pci:v00001067d00000304* + ID_MODEL_FROM_DATABASE=AccelGALAXY A2100 [OEM Evans & Sutherland] + +pci:v00001067d00000308* + ID_MODEL_FROM_DATABASE=Tornado 3000 [OEM Evans & Sutherland] + +pci:v00001067d00001002* + ID_MODEL_FROM_DATABASE=VG500 [VolumePro Volume Rendering Accelerator] + +pci:v00001068* + ID_VENDOR_FROM_DATABASE=Diversified Technology + +pci:v00001069* + ID_VENDOR_FROM_DATABASE=Mylex Corporation + +pci:v00001069d00000001* + ID_MODEL_FROM_DATABASE=DAC960P + +pci:v00001069d00000002* + ID_MODEL_FROM_DATABASE=DAC960PD + +pci:v00001069d00000010* + ID_MODEL_FROM_DATABASE=DAC960PG + +pci:v00001069d00000020* + ID_MODEL_FROM_DATABASE=DAC960LA + +pci:v00001069d00000050* + ID_MODEL_FROM_DATABASE=AcceleRAID 352/170/160 support Device + +pci:v00001069d00000050sv00001069sd00000050* + ID_MODEL_FROM_DATABASE=AcceleRAID 352 support Device + +pci:v00001069d00000050sv00001069sd00000052* + ID_MODEL_FROM_DATABASE=AcceleRAID 170 support Device + +pci:v00001069d00000050sv00001069sd00000054* + ID_MODEL_FROM_DATABASE=AcceleRAID 160 support Device + +pci:v00001069d0000B166* + ID_MODEL_FROM_DATABASE=AcceleRAID 600/500/400/Sapphire support Device + +pci:v00001069d0000B166sv00001014sd00000242* + ID_MODEL_FROM_DATABASE=iSeries 2872 DASD IOA + +pci:v00001069d0000B166sv00001014sd00000266* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X U320 SCSI Adapter + +pci:v00001069d0000B166sv00001014sd00000278* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X U320 SCSI RAID Adapter + +pci:v00001069d0000B166sv00001014sd000002D3* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X U320 SCSI Adapter + +pci:v00001069d0000B166sv00001014sd000002D4* + ID_MODEL_FROM_DATABASE=Dual Channel PCI-X U320 SCSI RAID Adapter + +pci:v00001069d0000B166sv00001069sd00000200* + ID_MODEL_FROM_DATABASE=AcceleRAID 400, Single Channel, PCI-X, U320, SCSI RAID + +pci:v00001069d0000B166sv00001069sd00000202* + ID_MODEL_FROM_DATABASE=AcceleRAID Sapphire, Dual Channel, PCI-X, U320, SCSI RAID + +pci:v00001069d0000B166sv00001069sd00000204* + ID_MODEL_FROM_DATABASE=AcceleRAID 500, Dual Channel, Low-Profile, PCI-X, U320, SCSI RAID + +pci:v00001069d0000B166sv00001069sd00000206* + ID_MODEL_FROM_DATABASE=AcceleRAID 600, Dual Channel, PCI-X, U320, SCSI RAID + +pci:v00001069d0000BA55* + ID_MODEL_FROM_DATABASE=eXtremeRAID 1100 support Device + +pci:v00001069d0000BA56* + ID_MODEL_FROM_DATABASE=eXtremeRAID 2000/3000 support Device + +pci:v00001069d0000BA56sv00001069sd00000030* + ID_MODEL_FROM_DATABASE=eXtremeRAID 3000 support Device + +pci:v00001069d0000BA56sv00001069sd00000040* + ID_MODEL_FROM_DATABASE=eXtremeRAID 2000 support Device + +pci:v00001069d0000BA57* + ID_MODEL_FROM_DATABASE=eXtremeRAID 4000/5000 support Device + +pci:v00001069d0000BA57sv00001069sd00000072* + ID_MODEL_FROM_DATABASE=eXtremeRAID 5000 support Device + +pci:v0000106A* + ID_VENDOR_FROM_DATABASE=Aten Research Inc + +pci:v0000106B* + ID_VENDOR_FROM_DATABASE=Apple Inc. + +pci:v0000106Bd00000001* + ID_MODEL_FROM_DATABASE=Bandit PowerPC host bridge + +pci:v0000106Bd00000002* + ID_MODEL_FROM_DATABASE=Grand Central I/O + +pci:v0000106Bd00000003* + ID_MODEL_FROM_DATABASE=Control Video + +pci:v0000106Bd00000004* + ID_MODEL_FROM_DATABASE=PlanB Video-In + +pci:v0000106Bd00000007* + ID_MODEL_FROM_DATABASE=O'Hare I/O + +pci:v0000106Bd0000000C* + ID_MODEL_FROM_DATABASE=DOS on Mac + +pci:v0000106Bd0000000E* + ID_MODEL_FROM_DATABASE=Hydra Mac I/O + +pci:v0000106Bd00000010* + ID_MODEL_FROM_DATABASE=Heathrow Mac I/O + +pci:v0000106Bd00000017* + ID_MODEL_FROM_DATABASE=Paddington Mac I/O + +pci:v0000106Bd00000018* + ID_MODEL_FROM_DATABASE=UniNorth FireWire + +pci:v0000106Bd00000019* + ID_MODEL_FROM_DATABASE=KeyLargo USB + +pci:v0000106Bd0000001E* + ID_MODEL_FROM_DATABASE=UniNorth Internal PCI + +pci:v0000106Bd0000001F* + ID_MODEL_FROM_DATABASE=UniNorth PCI + +pci:v0000106Bd00000020* + ID_MODEL_FROM_DATABASE=UniNorth AGP + +pci:v0000106Bd00000021* + ID_MODEL_FROM_DATABASE=UniNorth GMAC (Sun GEM) + +pci:v0000106Bd00000022* + ID_MODEL_FROM_DATABASE=KeyLargo Mac I/O + +pci:v0000106Bd00000024* + ID_MODEL_FROM_DATABASE=UniNorth/Pangea GMAC (Sun GEM) + +pci:v0000106Bd00000025* + ID_MODEL_FROM_DATABASE=KeyLargo/Pangea Mac I/O + +pci:v0000106Bd00000026* + ID_MODEL_FROM_DATABASE=KeyLargo/Pangea USB + +pci:v0000106Bd00000027* + ID_MODEL_FROM_DATABASE=UniNorth/Pangea AGP + +pci:v0000106Bd00000028* + ID_MODEL_FROM_DATABASE=UniNorth/Pangea PCI + +pci:v0000106Bd00000029* + ID_MODEL_FROM_DATABASE=UniNorth/Pangea Internal PCI + +pci:v0000106Bd0000002D* + ID_MODEL_FROM_DATABASE=UniNorth 1.5 AGP + +pci:v0000106Bd0000002E* + ID_MODEL_FROM_DATABASE=UniNorth 1.5 PCI + +pci:v0000106Bd0000002F* + ID_MODEL_FROM_DATABASE=UniNorth 1.5 Internal PCI + +pci:v0000106Bd00000030* + ID_MODEL_FROM_DATABASE=UniNorth/Pangea FireWire + +pci:v0000106Bd00000031* + ID_MODEL_FROM_DATABASE=UniNorth 2 FireWire + +pci:v0000106Bd00000031sv0000106Bsd00005811* + ID_MODEL_FROM_DATABASE=iBook G4 2004 + +pci:v0000106Bd00000032* + ID_MODEL_FROM_DATABASE=UniNorth 2 GMAC (Sun GEM) + +pci:v0000106Bd00000033* + ID_MODEL_FROM_DATABASE=UniNorth 2 ATA/100 + +pci:v0000106Bd00000034* + ID_MODEL_FROM_DATABASE=UniNorth 2 AGP + +pci:v0000106Bd00000035* + ID_MODEL_FROM_DATABASE=UniNorth 2 PCI + +pci:v0000106Bd00000036* + ID_MODEL_FROM_DATABASE=UniNorth 2 Internal PCI + +pci:v0000106Bd0000003B* + ID_MODEL_FROM_DATABASE=UniNorth/Intrepid ATA/100 + +pci:v0000106Bd0000003E* + ID_MODEL_FROM_DATABASE=KeyLargo/Intrepid Mac I/O + +pci:v0000106Bd0000003F* + ID_MODEL_FROM_DATABASE=KeyLargo/Intrepid USB + +pci:v0000106Bd00000040* + ID_MODEL_FROM_DATABASE=K2 KeyLargo USB + +pci:v0000106Bd00000041* + ID_MODEL_FROM_DATABASE=K2 KeyLargo Mac/IO + +pci:v0000106Bd00000042* + ID_MODEL_FROM_DATABASE=K2 FireWire + +pci:v0000106Bd00000043* + ID_MODEL_FROM_DATABASE=K2 ATA/100 + +pci:v0000106Bd00000045* + ID_MODEL_FROM_DATABASE=K2 HT-PCI Bridge + +pci:v0000106Bd00000046* + ID_MODEL_FROM_DATABASE=K2 HT-PCI Bridge + +pci:v0000106Bd00000047* + ID_MODEL_FROM_DATABASE=K2 HT-PCI Bridge + +pci:v0000106Bd00000048* + ID_MODEL_FROM_DATABASE=K2 HT-PCI Bridge + +pci:v0000106Bd00000049* + ID_MODEL_FROM_DATABASE=K2 HT-PCI Bridge + +pci:v0000106Bd0000004A* + ID_MODEL_FROM_DATABASE=CPC945 HT Bridge + +pci:v0000106Bd0000004B* + ID_MODEL_FROM_DATABASE=U3 AGP + +pci:v0000106Bd0000004C* + ID_MODEL_FROM_DATABASE=K2 GMAC (Sun GEM) + +pci:v0000106Bd0000004F* + ID_MODEL_FROM_DATABASE=Shasta Mac I/O + +pci:v0000106Bd00000050* + ID_MODEL_FROM_DATABASE=Shasta IDE + +pci:v0000106Bd00000051* + ID_MODEL_FROM_DATABASE=Shasta (Sun GEM) + +pci:v0000106Bd00000052* + ID_MODEL_FROM_DATABASE=Shasta Firewire + +pci:v0000106Bd00000053* + ID_MODEL_FROM_DATABASE=Shasta PCI Bridge + +pci:v0000106Bd00000054* + ID_MODEL_FROM_DATABASE=Shasta PCI Bridge + +pci:v0000106Bd00000055* + ID_MODEL_FROM_DATABASE=Shasta PCI Bridge + +pci:v0000106Bd00000056* + ID_MODEL_FROM_DATABASE=U4 PCIe + +pci:v0000106Bd00000057* + ID_MODEL_FROM_DATABASE=U3 HT Bridge + +pci:v0000106Bd00000058* + ID_MODEL_FROM_DATABASE=U3L AGP Bridge + +pci:v0000106Bd00000059* + ID_MODEL_FROM_DATABASE=U3H AGP Bridge + +pci:v0000106Bd0000005B* + ID_MODEL_FROM_DATABASE=CPC945 PCIe Bridge + +pci:v0000106Bd00000066* + ID_MODEL_FROM_DATABASE=Intrepid2 AGP Bridge + +pci:v0000106Bd00000067* + ID_MODEL_FROM_DATABASE=Intrepid2 PCI Bridge + +pci:v0000106Bd00000068* + ID_MODEL_FROM_DATABASE=Intrepid2 PCI Bridge + +pci:v0000106Bd00000069* + ID_MODEL_FROM_DATABASE=Intrepid2 ATA/100 + +pci:v0000106Bd0000006A* + ID_MODEL_FROM_DATABASE=Intrepid2 Firewire + +pci:v0000106Bd0000006B* + ID_MODEL_FROM_DATABASE=Intrepid2 GMAC (Sun GEM) + +pci:v0000106Bd00000074* + ID_MODEL_FROM_DATABASE=U4 HT Bridge + +pci:v0000106Bd00001645* + ID_MODEL_FROM_DATABASE=Broadcom NetXtreme BCM5701 Gigabit Ethernet + +pci:v0000106C* + ID_VENDOR_FROM_DATABASE=Hynix Semiconductor + +pci:v0000106Cd00008139* + ID_MODEL_FROM_DATABASE=8139c 100BaseTX Ethernet Controller + +pci:v0000106Cd00008801* + ID_MODEL_FROM_DATABASE=Dual Pentium ISA/PCI Motherboard + +pci:v0000106Cd00008802* + ID_MODEL_FROM_DATABASE=PowerPC ISA/PCI Motherboard + +pci:v0000106Cd00008803* + ID_MODEL_FROM_DATABASE=Dual Window Graphics Accelerator + +pci:v0000106Cd00008804* + ID_MODEL_FROM_DATABASE=LAN Controller + +pci:v0000106Cd00008805* + ID_MODEL_FROM_DATABASE=100-BaseT LAN + +pci:v0000106D* + ID_VENDOR_FROM_DATABASE=Sequent Computer Systems + +pci:v0000106E* + ID_VENDOR_FROM_DATABASE=DFI, Inc + +pci:v0000106F* + ID_VENDOR_FROM_DATABASE=City Gate Development Ltd + +pci:v00001070* + ID_VENDOR_FROM_DATABASE=Daewoo Telecom Ltd + +pci:v00001071* + ID_VENDOR_FROM_DATABASE=Mitac + +pci:v00001071d00008160* + ID_MODEL_FROM_DATABASE=Mitac 8060B Mobile Platform + +pci:v00001072* + ID_VENDOR_FROM_DATABASE=GIT Co Ltd + +pci:v00001073* + ID_VENDOR_FROM_DATABASE=Yamaha Corporation + +pci:v00001073d00000001* + ID_MODEL_FROM_DATABASE=3D GUI Accelerator + +pci:v00001073d00000002* + ID_MODEL_FROM_DATABASE=YGV615 [RPA3 3D-Graphics Controller] + +pci:v00001073d00000003* + ID_MODEL_FROM_DATABASE=YMF-740 + +pci:v00001073d00000004* + ID_MODEL_FROM_DATABASE=YMF-724 + +pci:v00001073d00000004sv00001073sd00000004* + ID_MODEL_FROM_DATABASE=YMF724-Based PCI Audio Adapter + +pci:v00001073d00000005* + ID_MODEL_FROM_DATABASE=DS1 Audio + +pci:v00001073d00000005sv00001073sd00000005* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d00000006* + ID_MODEL_FROM_DATABASE=DS1 Audio + +pci:v00001073d00000008* + ID_MODEL_FROM_DATABASE=DS1 Audio + +pci:v00001073d00000008sv00001073sd00000008* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d0000000A* + ID_MODEL_FROM_DATABASE=DS1L Audio + +pci:v00001073d0000000Asv00001073sd00000004* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d0000000Asv00001073sd0000000A* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d0000000Asv00008086sd00004D55* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC [Intel MU440EX] + +pci:v00001073d0000000C* + ID_MODEL_FROM_DATABASE=YMF-740C [DS-1L Audio Controller] + +pci:v00001073d0000000Csv0000107Asd0000000C* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d0000000D* + ID_MODEL_FROM_DATABASE=YMF-724F [DS-1 Audio Controller] + +pci:v00001073d0000000Dsv00001073sd0000000D* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d00000010* + ID_MODEL_FROM_DATABASE=YMF-744B [DS-1S Audio Controller] + +pci:v00001073d00000010sv00001073sd00000006* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d00000010sv00001073sd00000010* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio CODEC + +pci:v00001073d00000012* + ID_MODEL_FROM_DATABASE=YMF-754 [DS-1E Audio Controller] + +pci:v00001073d00000012sv00001073sd00000012* + ID_MODEL_FROM_DATABASE=DS-XG PCI Audio Codec + +pci:v00001073d00000020* + ID_MODEL_FROM_DATABASE=DS-1 Audio + +pci:v00001073d00001000* + ID_MODEL_FROM_DATABASE=SW1000XG [XG Factory] + +pci:v00001073d00002000* + ID_MODEL_FROM_DATABASE=DS2416 Digital Mixing Card + +pci:v00001073d00002000sv00001073sd00002000* + ID_MODEL_FROM_DATABASE=DS2416 Digital Mixing Card + +pci:v00001074* + ID_VENDOR_FROM_DATABASE=NexGen Microsystems + +pci:v00001074d00004E78* + ID_MODEL_FROM_DATABASE=82c500/1 + +pci:v00001075* + ID_VENDOR_FROM_DATABASE=Advanced Integrations Research + +pci:v00001076* + ID_VENDOR_FROM_DATABASE=Chaintech Computer Co. Ltd + +pci:v00001077* + ID_VENDOR_FROM_DATABASE=QLogic Corp. + +pci:v00001077d00001016* + ID_MODEL_FROM_DATABASE=ISP10160 Single Channel Ultra3 SCSI Processor + +pci:v00001077d00001020* + ID_MODEL_FROM_DATABASE=ISP1020 Fast-wide SCSI + +pci:v00001077d00001022* + ID_MODEL_FROM_DATABASE=ISP1022 Fast-wide SCSI + +pci:v00001077d00001080* + ID_MODEL_FROM_DATABASE=ISP1080 SCSI Host Adapter + +pci:v00001077d00001216* + ID_MODEL_FROM_DATABASE=ISP12160 Dual Channel Ultra3 SCSI Processor + +pci:v00001077d00001216sv0000101Esd00008471* + ID_MODEL_FROM_DATABASE=QLA12160 on AMI MegaRAID + +pci:v00001077d00001216sv0000101Esd00008493* + ID_MODEL_FROM_DATABASE=QLA12160 on AMI MegaRAID + +pci:v00001077d00001240* + ID_MODEL_FROM_DATABASE=ISP1240 SCSI Host Adapter + +pci:v00001077d00001280* + ID_MODEL_FROM_DATABASE=ISP1280 SCSI Host Adapter + +pci:v00001077d00002020* + ID_MODEL_FROM_DATABASE=ISP2020A Fast!SCSI Basic Adapter + +pci:v00001077d00002031* + ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter + +pci:v00001077d00002100* + ID_MODEL_FROM_DATABASE=QLA2100 64-bit Fibre Channel Adapter + +pci:v00001077d00002100sv00001077sd00000001* + ID_MODEL_FROM_DATABASE=QLA2100 64-bit Fibre Channel Adapter + +pci:v00001077d00002200* + ID_MODEL_FROM_DATABASE=QLA2200 64-bit Fibre Channel Adapter + +pci:v00001077d00002200sv00001077sd00000002* + ID_MODEL_FROM_DATABASE=QLA2200 + +pci:v00001077d00002300* + ID_MODEL_FROM_DATABASE=QLA2300 64-bit Fibre Channel Adapter + +pci:v00001077d00002312* + ID_MODEL_FROM_DATABASE=ISP2312-based 2Gb Fibre Channel to PCI-X HBA + +pci:v00001077d00002312sv0000103Csd00000131* + ID_MODEL_FROM_DATABASE=2Gb Fibre Channel - Single port [A7538A] + +pci:v00001077d00002312sv0000103Csd000012BA* + ID_MODEL_FROM_DATABASE=2Gb Fibre Channel - Dual port [A6826A] + +pci:v00001077d00002322* + ID_MODEL_FROM_DATABASE=ISP2322-based 2Gb Fibre Channel to PCI-X HBA + +pci:v00001077d00002422* + ID_MODEL_FROM_DATABASE=ISP2422-based 4Gb Fibre Channel to PCI-X HBA + +pci:v00001077d00002422sv0000103Csd000012D7* + ID_MODEL_FROM_DATABASE=4Gb Fibre Channel [AB379A] + +pci:v00001077d00002422sv0000103Csd000012DD* + ID_MODEL_FROM_DATABASE=4Gb Fibre Channel [AB429A] + +pci:v00001077d00002432* + ID_MODEL_FROM_DATABASE=ISP2432-based 4Gb Fibre Channel to PCI Express HBA + +pci:v00001077d00002532* + ID_MODEL_FROM_DATABASE=ISP2532-based 8Gb Fibre Channel to PCI Express HBA + +pci:v00001077d00002532sv0000103Csd00003262* + ID_MODEL_FROM_DATABASE=StorageWorks 81Q + +pci:v00001077d00002532sv00001077sd00000167* + ID_MODEL_FROM_DATABASE=QME2572 Dual Port FC8 HBA Mezzanine + +pci:v00001077d00003022* + ID_MODEL_FROM_DATABASE=ISP4022-based Ethernet NIC + +pci:v00001077d00003032* + ID_MODEL_FROM_DATABASE=ISP4032-based Ethernet IPv6 NIC + +pci:v00001077d00004010* + ID_MODEL_FROM_DATABASE=ISP4010-based iSCSI TOE HBA + +pci:v00001077d00004022* + ID_MODEL_FROM_DATABASE=ISP4022-based iSCSI TOE HBA + +pci:v00001077d00004032* + ID_MODEL_FROM_DATABASE=ISP4032-based iSCSI TOE IPv6 HBA + +pci:v00001077d00005432* + ID_MODEL_FROM_DATABASE=SP232-based 4Gb Fibre Channel to PCI Express HBA + +pci:v00001077d00006312* + ID_MODEL_FROM_DATABASE=SP202-based 2Gb Fibre Channel to PCI-X HBA + +pci:v00001077d00006322* + ID_MODEL_FROM_DATABASE=SP212-based 2Gb Fibre Channel to PCI-X HBA + +pci:v00001077d00007220* + ID_MODEL_FROM_DATABASE=IBA7220 InfiniBand HCA + +pci:v00001077d00007322* + ID_MODEL_FROM_DATABASE=IBA7322 QDR InfiniBand HCA + +pci:v00001077d00008000* + ID_MODEL_FROM_DATABASE=10GbE Converged Network Adapter (TCP/IP Networking) + +pci:v00001077d00008001* + ID_MODEL_FROM_DATABASE=10GbE Converged Network Adapter (FCoE) + +pci:v00001077d00008020* + ID_MODEL_FROM_DATABASE=cLOM8214 1/10GbE Controller + +pci:v00001077d00008020sv0000103Csd00003346* + ID_MODEL_FROM_DATABASE=CN1000Q Dual Port Converged Network Adapter + +pci:v00001077d00008020sv0000103Csd00003733* + ID_MODEL_FROM_DATABASE=NC523SFP 10Gb 2-port Server Adapter + +pci:v00001077d00008020sv00001077sd00000203* + ID_MODEL_FROM_DATABASE=8200 Series Single Port 10GbE Converged Network Adapter (TCP/IP Networking) + +pci:v00001077d00008020sv00001077sd00000207* + ID_MODEL_FROM_DATABASE=8200 Series Dual Port 10GbE Converged Network Adapter (TCP/IP Networking) + +pci:v00001077d00008020sv00001077sd0000020B* + ID_MODEL_FROM_DATABASE=3200 Series Dual Port 10Gb Intelligent Ethernet Adapter + +pci:v00001077d00008020sv00001077sd0000020C* + ID_MODEL_FROM_DATABASE=3200 Series Quad Port 1Gb Intelligent Ethernet Adapter + +pci:v00001077d00008020sv00001077sd0000020F* + ID_MODEL_FROM_DATABASE=3200 Series Single Port 10Gb Intelligent Ethernet Adapter + +pci:v00001077d00008020sv00001077sd00000210* + ID_MODEL_FROM_DATABASE=QME8242-k 10GbE Dual Port Mezzanine Card + +pci:v00001077d00008021* + ID_MODEL_FROM_DATABASE=8200 Series 10GbE Converged Network Adapter (FCoE) + +pci:v00001077d00008021sv0000103Csd00003348* + ID_MODEL_FROM_DATABASE=CN1000Q Dual Port Converged Network Adapter + +pci:v00001077d00008021sv00001077sd00000211* + ID_MODEL_FROM_DATABASE=QME8242-k 10GbE Dual Port Mezzanine Card, FCoE + +pci:v00001077d00008022* + ID_MODEL_FROM_DATABASE=8200 Series 10GbE Converged Network Adapter (iSCSI) + +pci:v00001077d00008022sv0000103Csd00003347* + ID_MODEL_FROM_DATABASE=CN1000Q Dual Port Converged Network Adapter + +pci:v00001077d00008022sv00001077sd00000212* + ID_MODEL_FROM_DATABASE=QME8242-k 10GbE Dual Port Mezzanine Card, iSCSI + +pci:v00001077d00008030* + ID_MODEL_FROM_DATABASE=ISP8324 1/10GbE Converged Network Controller + +pci:v00001077d00008030sv00001077sd00000243* + ID_MODEL_FROM_DATABASE=8300 Series Single Port 10GbE Converged Network Adapter (TCP/IP Networking) + +pci:v00001077d00008030sv00001077sd00000246* + ID_MODEL_FROM_DATABASE=8300 Series Dual Port 10GbE Converged Network Adapter (TCP/IP Networking) + +pci:v00001077d00008031* + ID_MODEL_FROM_DATABASE=8300 Series 10GbE Converged Network Adapter (FCoE) + +pci:v00001077d00008032* + ID_MODEL_FROM_DATABASE=8300 Series 10GbE Converged Network Adapter (iSCSI) + +pci:v00001077d00008430* + ID_MODEL_FROM_DATABASE=ISP8324 1/10GbE Converged Network Controller (NIC VF) + +pci:v00001077d00008431* + ID_MODEL_FROM_DATABASE=8300 Series 10GbE Converged Network Adapter (FCoE VF) + +pci:v00001077d00008432* + ID_MODEL_FROM_DATABASE=ISP2432M-based 10GbE Converged Network Adapter (CNA) + +pci:v00001078* + ID_VENDOR_FROM_DATABASE=Cyrix Corporation + +pci:v00001078d00000000* + ID_MODEL_FROM_DATABASE=5510 [Grappa] + +pci:v00001078d00000001* + ID_MODEL_FROM_DATABASE=PCI Master + +pci:v00001078d00000002* + ID_MODEL_FROM_DATABASE=5520 [Cognac] + +pci:v00001078d00000100* + ID_MODEL_FROM_DATABASE=5530 Legacy [Kahlua] + +pci:v00001078d00000101* + ID_MODEL_FROM_DATABASE=5530 SMI [Kahlua] + +pci:v00001078d00000102* + ID_MODEL_FROM_DATABASE=5530 IDE [Kahlua] + +pci:v00001078d00000103* + ID_MODEL_FROM_DATABASE=5530 Audio [Kahlua] + +pci:v00001078d00000104* + ID_MODEL_FROM_DATABASE=5530 Video [Kahlua] + +pci:v00001078d00000400* + ID_MODEL_FROM_DATABASE=ZFMicro PCI Bridge + +pci:v00001078d00000401* + ID_MODEL_FROM_DATABASE=ZFMicro Chipset SMI + +pci:v00001078d00000402* + ID_MODEL_FROM_DATABASE=ZFMicro Chipset IDE + +pci:v00001078d00000403* + ID_MODEL_FROM_DATABASE=ZFMicro Expansion Bus + +pci:v00001079* + ID_VENDOR_FROM_DATABASE=I-Bus + +pci:v0000107A* + ID_VENDOR_FROM_DATABASE=NetWorth + +pci:v0000107B* + ID_VENDOR_FROM_DATABASE=Gateway, Inc. + +pci:v0000107C* + ID_VENDOR_FROM_DATABASE=LG Electronics [Lucky Goldstar Co. Ltd] + +pci:v0000107D* + ID_VENDOR_FROM_DATABASE=LeadTek Research Inc. + +pci:v0000107Dd00000000* + ID_MODEL_FROM_DATABASE=P86C850 + +pci:v0000107E* + ID_VENDOR_FROM_DATABASE=Interphase Corporation + +pci:v0000107Ed00000001* + ID_MODEL_FROM_DATABASE=5515 ATM Adapter [Flipper] + +pci:v0000107Ed00000002* + ID_MODEL_FROM_DATABASE=100 VG AnyLan Controller + +pci:v0000107Ed00000004* + ID_MODEL_FROM_DATABASE=5526 Fibre Channel Host Adapter + +pci:v0000107Ed00000005* + ID_MODEL_FROM_DATABASE=x526 Fibre Channel Host Adapter + +pci:v0000107Ed00000008* + ID_MODEL_FROM_DATABASE=5525/5575 ATM Adapter (155 Mbit) [Atlantic] + +pci:v0000107Ed00009003* + ID_MODEL_FROM_DATABASE=5535-4P-BRI-ST + +pci:v0000107Ed00009007* + ID_MODEL_FROM_DATABASE=5535-4P-BRI-U + +pci:v0000107Ed00009008* + ID_MODEL_FROM_DATABASE=5535-1P-SR + +pci:v0000107Ed0000900C* + ID_MODEL_FROM_DATABASE=5535-1P-SR-ST + +pci:v0000107Ed0000900E* + ID_MODEL_FROM_DATABASE=5535-1P-SR-U + +pci:v0000107Ed00009011* + ID_MODEL_FROM_DATABASE=5535-1P-PRI + +pci:v0000107Ed00009013* + ID_MODEL_FROM_DATABASE=5535-2P-PRI + +pci:v0000107Ed00009023* + ID_MODEL_FROM_DATABASE=5536-4P-BRI-ST + +pci:v0000107Ed00009027* + ID_MODEL_FROM_DATABASE=5536-4P-BRI-U + +pci:v0000107Ed00009031* + ID_MODEL_FROM_DATABASE=5536-1P-PRI + +pci:v0000107Ed00009033* + ID_MODEL_FROM_DATABASE=5536-2P-PRI + +pci:v0000107F* + ID_VENDOR_FROM_DATABASE=Data Technology Corporation + +pci:v0000107Fd00000802* + ID_MODEL_FROM_DATABASE=SL82C105 + +pci:v00001080* + ID_VENDOR_FROM_DATABASE=Contaq Microsystems + +pci:v00001080d00000600* + ID_MODEL_FROM_DATABASE=82C599 + +pci:v00001080d0000C691* + ID_MODEL_FROM_DATABASE=Cypress CY82C691 + +pci:v00001080d0000C693* + ID_MODEL_FROM_DATABASE=82c693 + +pci:v00001081* + ID_VENDOR_FROM_DATABASE=Supermac Technology + +pci:v00001081d00000D47* + ID_MODEL_FROM_DATABASE=Radius PCI to NuBUS Bridge + +pci:v00001082* + ID_VENDOR_FROM_DATABASE=EFA Corporation of America + +pci:v00001083* + ID_VENDOR_FROM_DATABASE=Forex Computer Corporation + +pci:v00001083d00000001* + ID_MODEL_FROM_DATABASE=FR710 + +pci:v00001084* + ID_VENDOR_FROM_DATABASE=Parador + +pci:v00001086* + ID_VENDOR_FROM_DATABASE=J. Bond Computer Systems + +pci:v00001087* + ID_VENDOR_FROM_DATABASE=Cache Computer + +pci:v00001088* + ID_VENDOR_FROM_DATABASE=Microcomputer Systems (M) Son + +pci:v00001089* + ID_VENDOR_FROM_DATABASE=Data General Corporation + +pci:v0000108A* + ID_VENDOR_FROM_DATABASE=SBS Technologies + +pci:v0000108Ad00000001* + ID_MODEL_FROM_DATABASE=VME Bridge Model 617 + +pci:v0000108Ad00000010* + ID_MODEL_FROM_DATABASE=VME Bridge Model 618 + +pci:v0000108Ad00000040* + ID_MODEL_FROM_DATABASE=dataBLIZZARD + +pci:v0000108Ad00003000* + ID_MODEL_FROM_DATABASE=VME Bridge Model 2706 + +pci:v0000108C* + ID_VENDOR_FROM_DATABASE=Oakleigh Systems Inc. + +pci:v0000108D* + ID_VENDOR_FROM_DATABASE=Olicom + +pci:v0000108Dd00000001* + ID_MODEL_FROM_DATABASE=Token-Ring 16/4 PCI Adapter (3136/3137) + +pci:v0000108Dd00000002* + ID_MODEL_FROM_DATABASE=16/4 Token Ring + +pci:v0000108Dd00000004* + ID_MODEL_FROM_DATABASE=RapidFire 3139 Token-Ring 16/4 PCI Adapter + +pci:v0000108Dd00000004sv0000108Dsd00000004* + ID_MODEL_FROM_DATABASE=OC-3139/3140 RapidFire Token-Ring 16/4 Adapter + +pci:v0000108Dd00000005* + ID_MODEL_FROM_DATABASE=GoCard 3250 Token-Ring 16/4 CardBus PC Card + +pci:v0000108Dd00000006* + ID_MODEL_FROM_DATABASE=OC-3530 RapidFire Token-Ring 100 + +pci:v0000108Dd00000007* + ID_MODEL_FROM_DATABASE=RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter + +pci:v0000108Dd00000007sv0000108Dsd00000007* + ID_MODEL_FROM_DATABASE=OC-3141 RapidFire Token-Ring 16/4 Adapter + +pci:v0000108Dd00000008* + ID_MODEL_FROM_DATABASE=RapidFire 3540 HSTR 100/16/4 PCI Adapter + +pci:v0000108Dd00000008sv0000108Dsd00000008* + ID_MODEL_FROM_DATABASE=OC-3540 RapidFire HSTR 100/16/4 Adapter + +pci:v0000108Dd00000011* + ID_MODEL_FROM_DATABASE=OC-2315 + +pci:v0000108Dd00000012* + ID_MODEL_FROM_DATABASE=OC-2325 + +pci:v0000108Dd00000013* + ID_MODEL_FROM_DATABASE=OC-2183/2185 + +pci:v0000108Dd00000014* + ID_MODEL_FROM_DATABASE=OC-2326 + +pci:v0000108Dd00000019* + ID_MODEL_FROM_DATABASE=OC-2327/2250 10/100 Ethernet Adapter + +pci:v0000108Dd00000019sv0000108Dsd00000016* + ID_MODEL_FROM_DATABASE=OC-2327 Rapidfire 10/100 Ethernet Adapter + +pci:v0000108Dd00000019sv0000108Dsd00000017* + ID_MODEL_FROM_DATABASE=OC-2250 GoCard 10/100 Ethernet Adapter + +pci:v0000108Dd00000021* + ID_MODEL_FROM_DATABASE=OC-6151/6152 [RapidFire ATM 155] + +pci:v0000108Dd00000022* + ID_MODEL_FROM_DATABASE=ATM Adapter + +pci:v0000108E* + ID_VENDOR_FROM_DATABASE=Oracle/SUN + +pci:v0000108Ed00000001* + ID_MODEL_FROM_DATABASE=EBUS + +pci:v0000108Ed00001000* + ID_MODEL_FROM_DATABASE=EBUS + +pci:v0000108Ed00001001* + ID_MODEL_FROM_DATABASE=Happy Meal 10/100 Ethernet [hme] + +pci:v0000108Ed00001100* + ID_MODEL_FROM_DATABASE=RIO EBUS + +pci:v0000108Ed00001100sv0000108Esd00001100* + ID_MODEL_FROM_DATABASE=RIO EBUS on Blade 100 motherboard + +pci:v0000108Ed00001101* + ID_MODEL_FROM_DATABASE=RIO 10/100 Ethernet [eri] + +pci:v0000108Ed00001101sv0000108Esd00001101* + ID_MODEL_FROM_DATABASE=RIO GEM on Blade 100 motherboard + +pci:v0000108Ed00001102* + ID_MODEL_FROM_DATABASE=RIO 1394 + +pci:v0000108Ed00001102sv0000108Esd00001102* + ID_MODEL_FROM_DATABASE=RIO 1394 on Blade 100 motherboard + +pci:v0000108Ed00001103* + ID_MODEL_FROM_DATABASE=RIO USB + +pci:v0000108Ed00001103sv0000108Esd00001103* + ID_MODEL_FROM_DATABASE=RIO USB on Blade 100 motherboard + +pci:v0000108Ed00001647* + ID_MODEL_FROM_DATABASE=Broadcom 570x 10/100/1000 Ethernet [bge] + +pci:v0000108Ed00001648* + ID_MODEL_FROM_DATABASE=Broadcom 570x 10/100/1000 Ethernet [bge] + +pci:v0000108Ed000016A7* + ID_MODEL_FROM_DATABASE=Broadcom 570x 10/100/1000 Ethernet [bge] + +pci:v0000108Ed000016A8* + ID_MODEL_FROM_DATABASE=Broadcom 570x 10/100/1000 Ethernet [bge] + +pci:v0000108Ed00002BAD* + ID_MODEL_FROM_DATABASE=GEM 10/100/1000 Ethernet [ge] + +pci:v0000108Ed00005000* + ID_MODEL_FROM_DATABASE=Simba Advanced PCI Bridge + +pci:v0000108Ed00005000sv0000108Esd00005000* + ID_MODEL_FROM_DATABASE=Netra AX1105-500 + +pci:v0000108Ed00005043* + ID_MODEL_FROM_DATABASE=SunPCI Co-processor + +pci:v0000108Ed00005CA0* + ID_MODEL_FROM_DATABASE=Crypto Accelerator 6000 [mca] + +pci:v0000108Ed00006300* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006301* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006302* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006303* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006310* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006311* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006312* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006313* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006320* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006323* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006330* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006331* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006332* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006333* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006340* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006343* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006350* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006353* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed00006722* + ID_MODEL_FROM_DATABASE=Intel 21554 PCI-PCI bus bridge [db21554] + +pci:v0000108Ed0000676E* + ID_MODEL_FROM_DATABASE=SunPCiIII + +pci:v0000108Ed00007063* + ID_MODEL_FROM_DATABASE=SunPCiII / SunPCiIIpro + +pci:v0000108Ed00008000* + ID_MODEL_FROM_DATABASE=Psycho PCI Bus Module + +pci:v0000108Ed00008001* + ID_MODEL_FROM_DATABASE=Schizo PCI Bus Module + +pci:v0000108Ed00008002* + ID_MODEL_FROM_DATABASE=Schizo+ PCI Bus Module + +pci:v0000108Ed000080F0* + ID_MODEL_FROM_DATABASE=PCIe switch [px] + +pci:v0000108Ed000080F8* + ID_MODEL_FROM_DATABASE=PCIe switch [px] + +pci:v0000108Ed00009010* + ID_MODEL_FROM_DATABASE=PCIe/PCI bridge switch [pxb_plx] + +pci:v0000108Ed00009020* + ID_MODEL_FROM_DATABASE=PCIe/PCI bridge switch [pxb_plx] + +pci:v0000108Ed00009102* + ID_MODEL_FROM_DATABASE=Davicom Fast Ethernet driver for Davicom DM9102A [dmfe] + +pci:v0000108Ed0000A000* + ID_MODEL_FROM_DATABASE=Psycho UPA-PCI Bus Module [pcipsy] + +pci:v0000108Ed0000A001* + ID_MODEL_FROM_DATABASE=Psycho UPA-PCI Bus Module [pcipsy] + +pci:v0000108Ed0000A001sv0000108Esd0000A001* + ID_MODEL_FROM_DATABASE=Ultra IIe on Blade 100 motherboard + +pci:v0000108Ed0000A801* + ID_MODEL_FROM_DATABASE=Schizo Fireplane-PCI bus bridge module [pcisch] + +pci:v0000108Ed0000AAAA* + ID_MODEL_FROM_DATABASE=Multithreaded Shared 10GbE Ethernet Network Controller + +pci:v0000108Ed0000ABBA* + ID_MODEL_FROM_DATABASE=Cassini 10/100/1000 + +pci:v0000108Ed0000ABCD* + ID_MODEL_FROM_DATABASE=Multithreaded 10-Gigabit Ethernet Network Controller + +pci:v0000108Ed0000C416* + ID_MODEL_FROM_DATABASE=Sun Fire System/System Controller Interface chip [sbbc] + +pci:v0000108F* + ID_VENDOR_FROM_DATABASE=Systemsoft + +pci:v00001090* + ID_VENDOR_FROM_DATABASE=Compro Computer Services, Inc. + +pci:v00001090d00004610* + ID_MODEL_FROM_DATABASE=PCI RTOM + +pci:v00001090d00004620* + ID_MODEL_FROM_DATABASE=GPIO HSD + +pci:v00001091* + ID_VENDOR_FROM_DATABASE=Intergraph Corporation + +pci:v00001091d00000020* + ID_MODEL_FROM_DATABASE=3D graphics processor + +pci:v00001091d00000021* + ID_MODEL_FROM_DATABASE=3D graphics processor w/Texturing + +pci:v00001091d00000040* + ID_MODEL_FROM_DATABASE=3D graphics frame buffer + +pci:v00001091d00000041* + ID_MODEL_FROM_DATABASE=3D graphics frame buffer + +pci:v00001091d00000060* + ID_MODEL_FROM_DATABASE=Proprietary bus bridge + +pci:v00001091d000000E4* + ID_MODEL_FROM_DATABASE=Powerstorm 4D50T + +pci:v00001091d00000720* + ID_MODEL_FROM_DATABASE=Motion JPEG codec + +pci:v00001091d00000780* + ID_MODEL_FROM_DATABASE=Intense3D Wildcat 3410 (MSMT496) + +pci:v00001091d000007A0* + ID_MODEL_FROM_DATABASE=Sun Expert3D-Lite Graphics Accelerator + +pci:v00001091d00001091* + ID_MODEL_FROM_DATABASE=Sun Expert3D Graphics Accelerator + +pci:v00001092* + ID_VENDOR_FROM_DATABASE=Diamond Multimedia Systems + +pci:v00001092d00000028* + ID_MODEL_FROM_DATABASE=Viper V770 + +pci:v00001092d00000028sv00001092sd00004A00* + ID_MODEL_FROM_DATABASE=Viper V770 32MB + +pci:v00001092d000000A0* + ID_MODEL_FROM_DATABASE=Speedstar Pro SE + +pci:v00001092d000000A8* + ID_MODEL_FROM_DATABASE=Speedstar 64 + +pci:v00001092d00000550* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v00001092d000008D4* + ID_MODEL_FROM_DATABASE=Supra 2260 Modem + +pci:v00001092d0000094C* + ID_MODEL_FROM_DATABASE=SupraExpress 56i Pro + +pci:v00001092d00001001* + ID_MODEL_FROM_DATABASE=Video Crunch It 1001 capture card + +pci:v00001092d00001092* + ID_MODEL_FROM_DATABASE=Viper V330 + +pci:v00001092d00006120* + ID_MODEL_FROM_DATABASE=Maximum DVD + +pci:v00001092d00008810* + ID_MODEL_FROM_DATABASE=Stealth SE + +pci:v00001092d00008811* + ID_MODEL_FROM_DATABASE=Stealth 64/SE + +pci:v00001092d00008880* + ID_MODEL_FROM_DATABASE=Stealth + +pci:v00001092d00008881* + ID_MODEL_FROM_DATABASE=Stealth + +pci:v00001092d000088B0* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088B1* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088C0* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088C1* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088D0* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088D1* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088F0* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d000088F1* + ID_MODEL_FROM_DATABASE=Stealth 64 + +pci:v00001092d00009999* + ID_MODEL_FROM_DATABASE=DMD-I0928-1 "Monster sound" sound chip + +pci:v00001093* + ID_VENDOR_FROM_DATABASE=National Instruments + +pci:v00001093d00000160* + ID_MODEL_FROM_DATABASE=PCI-DIO-96 + +pci:v00001093d00000162* + ID_MODEL_FROM_DATABASE=PCI-MIO-16XE-50 + +pci:v00001093d00001150* + ID_MODEL_FROM_DATABASE=PCI-DIO-32HS High Speed Digital I/O Board + +pci:v00001093d00001170* + ID_MODEL_FROM_DATABASE=PCI-MIO-16XE-10 + +pci:v00001093d00001180* + ID_MODEL_FROM_DATABASE=PCI-MIO-16E-1 + +pci:v00001093d00001190* + ID_MODEL_FROM_DATABASE=PCI-MIO-16E-4 + +pci:v00001093d000011B0* + ID_MODEL_FROM_DATABASE=PXI-6070E + +pci:v00001093d000011C0* + ID_MODEL_FROM_DATABASE=PXI-6040e + +pci:v00001093d000011D0* + ID_MODEL_FROM_DATABASE=PXI-6030e + +pci:v00001093d00001270* + ID_MODEL_FROM_DATABASE=PCI-6032e + +pci:v00001093d00001310* + ID_MODEL_FROM_DATABASE=PCI-6602 + +pci:v00001093d00001330* + ID_MODEL_FROM_DATABASE=PCI-6031E + +pci:v00001093d00001340* + ID_MODEL_FROM_DATABASE=PCI-6033e + +pci:v00001093d00001350* + ID_MODEL_FROM_DATABASE=PCI-6071E + +pci:v00001093d00001360* + ID_MODEL_FROM_DATABASE=PXI-6602 + +pci:v00001093d000014E0* + ID_MODEL_FROM_DATABASE=PCI-6110 + +pci:v00001093d000014F0* + ID_MODEL_FROM_DATABASE=PCI-6111 + +pci:v00001093d00001580* + ID_MODEL_FROM_DATABASE=PXI-6031E + +pci:v00001093d000015B0* + ID_MODEL_FROM_DATABASE=PXI-6071E + +pci:v00001093d00001710* + ID_MODEL_FROM_DATABASE=PXI-6509 + +pci:v00001093d000017D0* + ID_MODEL_FROM_DATABASE=PCI-6503 + +pci:v00001093d00001870* + ID_MODEL_FROM_DATABASE=PCI-6713 + +pci:v00001093d00001880* + ID_MODEL_FROM_DATABASE=PCI-6711 + +pci:v00001093d000018B0* + ID_MODEL_FROM_DATABASE=PCI-6052E + +pci:v00001093d000018C0* + ID_MODEL_FROM_DATABASE=PXI-6052E + +pci:v00001093d00002410* + ID_MODEL_FROM_DATABASE=PCI-6733 + +pci:v00001093d00002420* + ID_MODEL_FROM_DATABASE=PXI-6733 + +pci:v00001093d00002430* + ID_MODEL_FROM_DATABASE=PCI-6731 + +pci:v00001093d00002880* + ID_MODEL_FROM_DATABASE=DAQCard-6601 + +pci:v00001093d00002890* + ID_MODEL_FROM_DATABASE=PCI-6036E + +pci:v00001093d000028C0* + ID_MODEL_FROM_DATABASE=PCI-6014 + +pci:v00001093d000028D0* + ID_MODEL_FROM_DATABASE=PCI-5122 + +pci:v00001093d000028E0* + ID_MODEL_FROM_DATABASE=PXI-5122 + +pci:v00001093d00002A60* + ID_MODEL_FROM_DATABASE=PCI-6023E + +pci:v00001093d00002A70* + ID_MODEL_FROM_DATABASE=PCI-6024E + +pci:v00001093d00002A80* + ID_MODEL_FROM_DATABASE=PCI-6025E + +pci:v00001093d00002AB0* + ID_MODEL_FROM_DATABASE=PXI-6025e + +pci:v00001093d00002B80* + ID_MODEL_FROM_DATABASE=PXI-6713 + +pci:v00001093d00002B90* + ID_MODEL_FROM_DATABASE=PXI-6711 + +pci:v00001093d00002C60* + ID_MODEL_FROM_DATABASE=PCI-6601 + +pci:v00001093d00002C70* + ID_MODEL_FROM_DATABASE=PXI-6601 + +pci:v00001093d00002C80* + ID_MODEL_FROM_DATABASE=PCI-6035E + +pci:v00001093d00002CA0* + ID_MODEL_FROM_DATABASE=PCI-6034E + +pci:v00001093d00002CC0* + ID_MODEL_FROM_DATABASE=PXI-6608 + +pci:v00001093d00002DB0* + ID_MODEL_FROM_DATABASE=PCI-6608 + +pci:v00001093d00007085* + ID_MODEL_FROM_DATABASE=PCI-6509 + +pci:v00001093d000070A9* + ID_MODEL_FROM_DATABASE=PCI-6528 (Digital I/O at 60V) + +pci:v00001093d000070AA* + ID_MODEL_FROM_DATABASE=PCI-6229 + +pci:v00001093d000070AB* + ID_MODEL_FROM_DATABASE=PCI-6259 + +pci:v00001093d000070AC* + ID_MODEL_FROM_DATABASE=PCI-6289 + +pci:v00001093d000070AE* + ID_MODEL_FROM_DATABASE=PXI-6220 + +pci:v00001093d000070AF* + ID_MODEL_FROM_DATABASE=PCI-6221 + +pci:v00001093d000070B0* + ID_MODEL_FROM_DATABASE=PCI-6220 + +pci:v00001093d000070B4* + ID_MODEL_FROM_DATABASE=PCI-6250 + +pci:v00001093d000070B6* + ID_MODEL_FROM_DATABASE=PCI-6280 + +pci:v00001093d000070B7* + ID_MODEL_FROM_DATABASE=PCI-6254 + +pci:v00001093d000070B8* + ID_MODEL_FROM_DATABASE=PCI-6251 [M Series - High Speed Multifunction DAQ] + +pci:v00001093d000070BC* + ID_MODEL_FROM_DATABASE=PCI-6284 + +pci:v00001093d000070BD* + ID_MODEL_FROM_DATABASE=PCI-6281 + +pci:v00001093d000070BF* + ID_MODEL_FROM_DATABASE=PXI-6281 + +pci:v00001093d000070C0* + ID_MODEL_FROM_DATABASE=PCI-6143 + +pci:v00001093d000070F0* + ID_MODEL_FROM_DATABASE=PXI-5922 + +pci:v00001093d000070F1* + ID_MODEL_FROM_DATABASE=PCI-5922 + +pci:v00001093d000070F2* + ID_MODEL_FROM_DATABASE=PCI-6224 + +pci:v00001093d00007121* + ID_MODEL_FROM_DATABASE=PXI-5122EX + +pci:v00001093d00007122* + ID_MODEL_FROM_DATABASE=PCI-5122EX + +pci:v00001093d00007144* + ID_MODEL_FROM_DATABASE=PXI-5124 (12-bit 200 MS/s Digitizer) + +pci:v00001093d00007145* + ID_MODEL_FROM_DATABASE=PCI-5124 + +pci:v00001093d0000714C* + ID_MODEL_FROM_DATABASE=PXI-5114 + +pci:v00001093d0000714D* + ID_MODEL_FROM_DATABASE=PCI-5114 + +pci:v00001093d0000716C* + ID_MODEL_FROM_DATABASE=PCI-6225 + +pci:v00001093d0000717D* + ID_MODEL_FROM_DATABASE=PCIE-6251 + +pci:v00001093d0000717F* + ID_MODEL_FROM_DATABASE=PCIe-6259 + +pci:v00001093d000071BC* + ID_MODEL_FROM_DATABASE=PCI-6221 (37pin) + +pci:v00001093d000071D0* + ID_MODEL_FROM_DATABASE=PXI-6143 + +pci:v00001093d00007260* + ID_MODEL_FROM_DATABASE=PXI-5142 + +pci:v00001093d00007261* + ID_MODEL_FROM_DATABASE=PCI-5142 + +pci:v00001093d000072A8* + ID_MODEL_FROM_DATABASE=PXI-5152 + +pci:v00001093d000072A9* + ID_MODEL_FROM_DATABASE=PCI-5152 + +pci:v00001093d000072AA* + ID_MODEL_FROM_DATABASE=PXI-5105 + +pci:v00001093d000072AB* + ID_MODEL_FROM_DATABASE=PCI-5105 + +pci:v00001093d0000730F* + ID_MODEL_FROM_DATABASE=PXI-5922EX + +pci:v00001093d00007310* + ID_MODEL_FROM_DATABASE=PCI-5922EX + +pci:v00001093d00007333* + ID_MODEL_FROM_DATABASE=PXI-5900 + +pci:v00001093d00007349* + ID_MODEL_FROM_DATABASE=PXI-5154 + +pci:v00001093d0000734A* + ID_MODEL_FROM_DATABASE=PCI-5154 + +pci:v00001093d0000737D* + ID_MODEL_FROM_DATABASE=PXI-5124EX + +pci:v00001093d000073F0* + ID_MODEL_FROM_DATABASE=PXI-5153 + +pci:v00001093d000073F1* + ID_MODEL_FROM_DATABASE=PCI-5153 + +pci:v00001093d0000745E* + ID_MODEL_FROM_DATABASE=PXI-5153EX + +pci:v00001093d0000745F* + ID_MODEL_FROM_DATABASE=PCI-5153EX + +pci:v00001093d00007460* + ID_MODEL_FROM_DATABASE=PXI-5154EX + +pci:v00001093d00007461* + ID_MODEL_FROM_DATABASE=PCI-5154EX + +pci:v00001093d0000B001* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1408 + +pci:v00001093d0000B011* + ID_MODEL_FROM_DATABASE=IMAQ-PXI-1408 + +pci:v00001093d0000B021* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1424 + +pci:v00001093d0000B031* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1413 + +pci:v00001093d0000B041* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1407 + +pci:v00001093d0000B051* + ID_MODEL_FROM_DATABASE=IMAQ-PXI-1407 + +pci:v00001093d0000B061* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1411 + +pci:v00001093d0000B071* + ID_MODEL_FROM_DATABASE=IMAQ-PCI-1422 + +pci:v00001093d0000B081* + ID_MODEL_FROM_DATABASE=IMAQ-PXI-1422 + +pci:v00001093d0000B091* + ID_MODEL_FROM_DATABASE=IMAQ-PXI-1411 + +pci:v00001093d0000C4C4* + ID_MODEL_FROM_DATABASE=PXIe-4353/5160 + +pci:v00001093d0000C4C4sv00001093sd000076D0* + ID_MODEL_FROM_DATABASE=PXIe-5160 + +pci:v00001093d0000C801* + ID_MODEL_FROM_DATABASE=PCI-GPIB + +pci:v00001093d0000C831* + ID_MODEL_FROM_DATABASE=PCI-GPIB bridge + +pci:v00001094* + ID_VENDOR_FROM_DATABASE=First International Computers [FIC] + +pci:v00001095* + ID_VENDOR_FROM_DATABASE=Silicon Image, Inc. + +pci:v00001095d00000240* + ID_MODEL_FROM_DATABASE=Adaptec AAR-1210SA SATA HostRAID Controller + +pci:v00001095d00000640* + ID_MODEL_FROM_DATABASE=PCI0640 + +pci:v00001095d00000643* + ID_MODEL_FROM_DATABASE=PCI0643 + +pci:v00001095d00000646* + ID_MODEL_FROM_DATABASE=PCI0646 + +pci:v00001095d00000647* + ID_MODEL_FROM_DATABASE=PCI0647 + +pci:v00001095d00000648* + ID_MODEL_FROM_DATABASE=PCI0648 + +pci:v00001095d00000648sv00001043sd00008025* + ID_MODEL_FROM_DATABASE=CUBX motherboard + +pci:v00001095d00000649* + ID_MODEL_FROM_DATABASE=SiI 0649 Ultra ATA/100 PCI to ATA Host Controller + +pci:v00001095d00000649sv00000E11sd0000005D* + ID_MODEL_FROM_DATABASE=Integrated Ultra ATA-100 Dual Channel Controller + +pci:v00001095d00000649sv00000E11sd0000007E* + ID_MODEL_FROM_DATABASE=Integrated Ultra ATA-100 IDE RAID Controller + +pci:v00001095d00000649sv0000101Esd00000649* + ID_MODEL_FROM_DATABASE=AMI MegaRAID IDE 100 Controller + +pci:v00001095d00000650* + ID_MODEL_FROM_DATABASE=PBC0650A + +pci:v00001095d00000670* + ID_MODEL_FROM_DATABASE=USB0670 + +pci:v00001095d00000670sv00001095sd00000670* + ID_MODEL_FROM_DATABASE=USB0670 + +pci:v00001095d00000673* + ID_MODEL_FROM_DATABASE=USB0673 + +pci:v00001095d00000680* + ID_MODEL_FROM_DATABASE=PCI0680 Ultra ATA-133 Host Controller + +pci:v00001095d00000680sv00001095sd00000680* + ID_MODEL_FROM_DATABASE=SiI 0680 ATA/133 Controller + +pci:v00001095d00000680sv00001095sd00003680* + ID_MODEL_FROM_DATABASE=Winic W-680 (Silicon Image 680 based) + +pci:v00001095d00003112* + ID_MODEL_FROM_DATABASE=SiI 3112 [SATALink/SATARaid] Serial ATA Controller + +pci:v00001095d00003112sv00001095sd00003112* + ID_MODEL_FROM_DATABASE=SiI 3112 SATALink Controller + +pci:v00001095d00003112sv00001095sd00006112* + ID_MODEL_FROM_DATABASE=SiI 3112 SATARaid Controller + +pci:v00001095d00003112sv00009005sd00000250* + ID_MODEL_FROM_DATABASE=SATAConnect 1205SA Host Controller + +pci:v00001095d00003114* + ID_MODEL_FROM_DATABASE=SiI 3114 [SATALink/SATARaid] Serial ATA Controller + +pci:v00001095d00003114sv00001043sd00008167* + ID_MODEL_FROM_DATABASE=A8N-SLI Deluxe/Premium Mainboard + +pci:v00001095d00003114sv00001095sd00003114* + ID_MODEL_FROM_DATABASE=SiI 3114 SATALink Controller + +pci:v00001095d00003114sv00001095sd00006114* + ID_MODEL_FROM_DATABASE=SiI 3114 SATARaid Controller + +pci:v00001095d00003124* + ID_MODEL_FROM_DATABASE=SiI 3124 PCI-X Serial ATA Controller + +pci:v00001095d00003124sv00001095sd00003124* + ID_MODEL_FROM_DATABASE=SiI 3124 PCI-X Serial ATA Controller + +pci:v00001095d00003132* + ID_MODEL_FROM_DATABASE=SiI 3132 Serial ATA Raid II Controller + +pci:v00001095d00003512* + ID_MODEL_FROM_DATABASE=SiI 3512 [SATALink/SATARaid] Serial ATA Controller + +pci:v00001095d00003512sv00001095sd00003512* + ID_MODEL_FROM_DATABASE=SiI 3512 SATALink Controller + +pci:v00001095d00003512sv00001095sd00006512* + ID_MODEL_FROM_DATABASE=SiI 3512 SATARaid Controller + +pci:v00001095d00003531* + ID_MODEL_FROM_DATABASE=SiI 3531 [SATALink/SATARaid] Serial ATA Controller + +pci:v00001096* + ID_VENDOR_FROM_DATABASE=Alacron + +pci:v00001097* + ID_VENDOR_FROM_DATABASE=Appian Technology + +pci:v00001098* + ID_VENDOR_FROM_DATABASE=Quantum Designs (H.K.) Ltd + +pci:v00001098d00000001* + ID_MODEL_FROM_DATABASE=QD-8500 + +pci:v00001098d00000002* + ID_MODEL_FROM_DATABASE=QD-8580 + +pci:v00001099* + ID_VENDOR_FROM_DATABASE=Samsung Electronics Co., Ltd + +pci:v0000109A* + ID_VENDOR_FROM_DATABASE=Packard Bell + +pci:v0000109B* + ID_VENDOR_FROM_DATABASE=Gemlight Computer Ltd. + +pci:v0000109C* + ID_VENDOR_FROM_DATABASE=Megachips Corporation + +pci:v0000109D* + ID_VENDOR_FROM_DATABASE=Zida Technologies Ltd. + +pci:v0000109E* + ID_VENDOR_FROM_DATABASE=Brooktree Corporation + +pci:v0000109Ed00000310* + ID_MODEL_FROM_DATABASE=Bt848 Video Capture + +pci:v0000109Ed0000032E* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture + +pci:v0000109Ed00000350* + ID_MODEL_FROM_DATABASE=Bt848 Video Capture + +pci:v0000109Ed00000351* + ID_MODEL_FROM_DATABASE=Bt849A Video capture + +pci:v0000109Ed00000369* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture + +pci:v0000109Ed00000369sv00001002sd00000001* + ID_MODEL_FROM_DATABASE=TV-Wonder + +pci:v0000109Ed00000369sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=TV-Wonder/VE + +pci:v0000109Ed0000036C* + ID_MODEL_FROM_DATABASE=Bt879(??) Video Capture + +pci:v0000109Ed0000036Csv000013E9sd00000070* + ID_MODEL_FROM_DATABASE=Win/TV (Video Section) + +pci:v0000109Ed0000036E* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture + +pci:v0000109Ed0000036Esv00000070sd000013EB* + ID_MODEL_FROM_DATABASE=WinTV Series + +pci:v0000109Ed0000036Esv00000070sd0000FF01* + ID_MODEL_FROM_DATABASE=Viewcast Osprey 200 + +pci:v0000109Ed0000036Esv00000071sd00000101* + ID_MODEL_FROM_DATABASE=DigiTV PCI + +pci:v0000109Ed0000036Esv0000107Dsd00006606* + ID_MODEL_FROM_DATABASE=WinFast TV 2000 + +pci:v0000109Ed0000036Esv000011BDsd00000012* + ID_MODEL_FROM_DATABASE=PCTV pro (TV + FM stereo receiver) + +pci:v0000109Ed0000036Esv000011BDsd0000001C* + ID_MODEL_FROM_DATABASE=PCTV Sat (DBC receiver) + +pci:v0000109Ed0000036Esv0000127Asd00000001* + ID_MODEL_FROM_DATABASE=Bt878 Mediastream Controller NTSC + +pci:v0000109Ed0000036Esv0000127Asd00000002* + ID_MODEL_FROM_DATABASE=Bt878 Mediastream Controller PAL BG + +pci:v0000109Ed0000036Esv0000127Asd00000003* + ID_MODEL_FROM_DATABASE=Bt878a Mediastream Controller PAL BG + +pci:v0000109Ed0000036Esv0000127Asd00000048* + ID_MODEL_FROM_DATABASE=Bt878/832 Mediastream Controller + +pci:v0000109Ed0000036Esv0000144Fsd00003000* + ID_MODEL_FROM_DATABASE=MagicTView CPH060 - Video + +pci:v0000109Ed0000036Esv00001461sd00000002* + ID_MODEL_FROM_DATABASE=TV98 Series (TV/No FM/Remote) + +pci:v0000109Ed0000036Esv00001461sd00000003* + ID_MODEL_FROM_DATABASE=AverMedia UltraTV PCI 350 + +pci:v0000109Ed0000036Esv00001461sd00000004* + ID_MODEL_FROM_DATABASE=AVerTV WDM Video Capture + +pci:v0000109Ed0000036Esv00001461sd00000761* + ID_MODEL_FROM_DATABASE=AverTV DVB-T + +pci:v0000109Ed0000036Esv00001461sd00000771* + ID_MODEL_FROM_DATABASE=AverMedia AVerTV DVB-T 771 + +pci:v0000109Ed0000036Esv00001464sd0000AA00* + ID_MODEL_FROM_DATABASE=iTuner Spectra8 + +pci:v0000109Ed0000036Esv000014F1sd00000001* + ID_MODEL_FROM_DATABASE=Bt878 Mediastream Controller NTSC + +pci:v0000109Ed0000036Esv000014F1sd00000002* + ID_MODEL_FROM_DATABASE=Bt878 Mediastream Controller PAL BG + +pci:v0000109Ed0000036Esv000014F1sd00000003* + ID_MODEL_FROM_DATABASE=Bt878a Mediastream Controller PAL BG + +pci:v0000109Ed0000036Esv000014F1sd00000048* + ID_MODEL_FROM_DATABASE=Bt878/832 Mediastream Controller + +pci:v0000109Ed0000036Esv00001822sd00000001* + ID_MODEL_FROM_DATABASE=VisionPlus DVB card + +pci:v0000109Ed0000036Esv00001851sd00001850* + ID_MODEL_FROM_DATABASE=FlyVideo'98 - Video + +pci:v0000109Ed0000036Esv00001851sd00001851* + ID_MODEL_FROM_DATABASE=FlyVideo II + +pci:v0000109Ed0000036Esv00001852sd00001852* + ID_MODEL_FROM_DATABASE=FlyVideo'98 - Video (with FM Tuner) + +pci:v0000109Ed0000036Esv000018ACsd0000D500* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV5 Lite + +pci:v0000109Ed0000036Esv0000270Fsd0000FC00* + ID_MODEL_FROM_DATABASE=Digitop DTT-1000 + +pci:v0000109Ed0000036Esv0000BD11sd00001200* + ID_MODEL_FROM_DATABASE=PCTV pro (TV + FM stereo receiver) + +pci:v0000109Ed0000036F* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture + +pci:v0000109Ed0000036Fsv0000127Asd00000044* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00000122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL I + +pci:v0000109Ed0000036Fsv0000127Asd00000144* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00000222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL BG + +pci:v0000109Ed0000036Fsv0000127Asd00000244* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00000322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00000422* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00001122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL I + +pci:v0000109Ed0000036Fsv0000127Asd00001222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL BG + +pci:v0000109Ed0000036Fsv0000127Asd00001322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv0000127Asd00001522* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture PAL I + +pci:v0000109Ed0000036Fsv0000127Asd00001622* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture PAL BG + +pci:v0000109Ed0000036Fsv0000127Asd00001722* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00000044* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00000122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL I + +pci:v0000109Ed0000036Fsv000014F1sd00000144* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00000222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL BG + +pci:v0000109Ed0000036Fsv000014F1sd00000244* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00000322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00000422* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00001122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL I + +pci:v0000109Ed0000036Fsv000014F1sd00001222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture PAL BG + +pci:v0000109Ed0000036Fsv000014F1sd00001322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture NTSC + +pci:v0000109Ed0000036Fsv000014F1sd00001522* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture PAL I + +pci:v0000109Ed0000036Fsv000014F1sd00001622* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture PAL BG + +pci:v0000109Ed0000036Fsv000014F1sd00001722* + ID_MODEL_FROM_DATABASE=Bt879a Video Capture NTSC + +pci:v0000109Ed0000036Fsv00001851sd00001850* + ID_MODEL_FROM_DATABASE=FlyVideo'98 - Video + +pci:v0000109Ed0000036Fsv00001851sd00001851* + ID_MODEL_FROM_DATABASE=FlyVideo II + +pci:v0000109Ed0000036Fsv00001852sd00001852* + ID_MODEL_FROM_DATABASE=FlyVideo'98 - Video (with FM Tuner) + +pci:v0000109Ed00000370* + ID_MODEL_FROM_DATABASE=Bt880 Video Capture + +pci:v0000109Ed00000370sv00001851sd00001850* + ID_MODEL_FROM_DATABASE=FlyVideo'98 + +pci:v0000109Ed00000370sv00001851sd00001851* + ID_MODEL_FROM_DATABASE=FlyVideo'98 EZ - video + +pci:v0000109Ed00000370sv00001852sd00001852* + ID_MODEL_FROM_DATABASE=FlyVideo'98 (with FM Tuner) + +pci:v0000109Ed00000878* + ID_MODEL_FROM_DATABASE=Bt878 Audio Capture + +pci:v0000109Ed00000878sv00000070sd000013EB* + ID_MODEL_FROM_DATABASE=WinTV Series + +pci:v0000109Ed00000878sv00000070sd0000FF01* + ID_MODEL_FROM_DATABASE=Viewcast Osprey 200 + +pci:v0000109Ed00000878sv00000071sd00000101* + ID_MODEL_FROM_DATABASE=DigiTV PCI + +pci:v0000109Ed00000878sv00001002sd00000001* + ID_MODEL_FROM_DATABASE=TV-Wonder + +pci:v0000109Ed00000878sv00001002sd00000003* + ID_MODEL_FROM_DATABASE=TV-Wonder/VE + +pci:v0000109Ed00000878sv000011BDsd00000012* + ID_MODEL_FROM_DATABASE=PCTV pro (TV + FM stereo receiver, audio section) + +pci:v0000109Ed00000878sv000011BDsd0000001C* + ID_MODEL_FROM_DATABASE=PCTV Sat (DBC receiver) + +pci:v0000109Ed00000878sv0000127Asd00000001* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv0000127Asd00000002* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv0000127Asd00000003* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv0000127Asd00000048* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv000013E9sd00000070* + ID_MODEL_FROM_DATABASE=Win/TV (Audio Section) + +pci:v0000109Ed00000878sv0000144Fsd00003000* + ID_MODEL_FROM_DATABASE=MagicTView CPH060 - Audio + +pci:v0000109Ed00000878sv00001461sd00000002* + ID_MODEL_FROM_DATABASE=Avermedia PCTV98 Audio Capture + +pci:v0000109Ed00000878sv00001461sd00000003* + ID_MODEL_FROM_DATABASE=UltraTV PCI 350 + +pci:v0000109Ed00000878sv00001461sd00000004* + ID_MODEL_FROM_DATABASE=AVerTV WDM Audio Capture + +pci:v0000109Ed00000878sv00001461sd00000761* + ID_MODEL_FROM_DATABASE=AVerTV DVB-T + +pci:v0000109Ed00000878sv00001461sd00000771* + ID_MODEL_FROM_DATABASE=AverMedia AVerTV DVB-T 771 + +pci:v0000109Ed00000878sv000014F1sd00000001* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv000014F1sd00000002* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv000014F1sd00000003* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv000014F1sd00000048* + ID_MODEL_FROM_DATABASE=Bt878 Video Capture (Audio Section) + +pci:v0000109Ed00000878sv00001822sd00000001* + ID_MODEL_FROM_DATABASE=VisionPlus DVB Card + +pci:v0000109Ed00000878sv000018ACsd0000D500* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV5 Lite + +pci:v0000109Ed00000878sv0000270Fsd0000FC00* + ID_MODEL_FROM_DATABASE=Digitop DTT-1000 + +pci:v0000109Ed00000878sv0000BD11sd00001200* + ID_MODEL_FROM_DATABASE=PCTV pro (TV + FM stereo receiver, audio section) + +pci:v0000109Ed00000879* + ID_MODEL_FROM_DATABASE=Bt879 Audio Capture + +pci:v0000109Ed00000879sv0000127Asd00000044* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000144* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000244* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00000422* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001522* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001622* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv0000127Asd00001722* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000044* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000144* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000244* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00000422* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001122* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001222* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001322* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001522* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001622* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000879sv000014F1sd00001722* + ID_MODEL_FROM_DATABASE=Bt879 Video Capture (Audio Section) + +pci:v0000109Ed00000880* + ID_MODEL_FROM_DATABASE=Bt880 Audio Capture + +pci:v0000109Ed00002115* + ID_MODEL_FROM_DATABASE=BtV 2115 Mediastream controller + +pci:v0000109Ed00002125* + ID_MODEL_FROM_DATABASE=BtV 2125 Mediastream controller + +pci:v0000109Ed00002164* + ID_MODEL_FROM_DATABASE=BtV 2164 + +pci:v0000109Ed00002165* + ID_MODEL_FROM_DATABASE=BtV 2165 + +pci:v0000109Ed00008230* + ID_MODEL_FROM_DATABASE=Bt8230 ATM Segment/Reassembly Ctrlr (SRC) + +pci:v0000109Ed00008472* + ID_MODEL_FROM_DATABASE=Bt8472 + +pci:v0000109Ed00008474* + ID_MODEL_FROM_DATABASE=Bt8474 + +pci:v0000109F* + ID_VENDOR_FROM_DATABASE=Trigem Computer Inc. + +pci:v000010A0* + ID_VENDOR_FROM_DATABASE=Meidensha Corporation + +pci:v000010A1* + ID_VENDOR_FROM_DATABASE=Juko Electronics Ind. Co. Ltd + +pci:v000010A2* + ID_VENDOR_FROM_DATABASE=Quantum Corporation + +pci:v000010A3* + ID_VENDOR_FROM_DATABASE=Everex Systems Inc + +pci:v000010A4* + ID_VENDOR_FROM_DATABASE=Globe Manufacturing Sales + +pci:v000010A5* + ID_VENDOR_FROM_DATABASE=Smart Link Ltd. + +pci:v000010A5d00003052* + ID_MODEL_FROM_DATABASE=SmartPCI562 56K Modem + +pci:v000010A5d00005449* + ID_MODEL_FROM_DATABASE=SmartPCI561 modem + +pci:v000010A6* + ID_VENDOR_FROM_DATABASE=Informtech Industrial Ltd. + +pci:v000010A7* + ID_VENDOR_FROM_DATABASE=Benchmarq Microelectronics + +pci:v000010A8* + ID_VENDOR_FROM_DATABASE=Sierra Semiconductor + +pci:v000010A8d00000000* + ID_MODEL_FROM_DATABASE=STB Horizon 64 + +pci:v000010A9* + ID_VENDOR_FROM_DATABASE=Silicon Graphics Intl. Corp. + +pci:v000010A9d00000001* + ID_MODEL_FROM_DATABASE=Crosstalk to PCI Bridge + +pci:v000010A9d00000002* + ID_MODEL_FROM_DATABASE=Linc I/O controller + +pci:v000010A9d00000003* + ID_MODEL_FROM_DATABASE=IOC3 I/O controller + +pci:v000010A9d00000004* + ID_MODEL_FROM_DATABASE=O2 MACE + +pci:v000010A9d00000005* + ID_MODEL_FROM_DATABASE=RAD Audio + +pci:v000010A9d00000006* + ID_MODEL_FROM_DATABASE=HPCEX + +pci:v000010A9d00000007* + ID_MODEL_FROM_DATABASE=RPCEX + +pci:v000010A9d00000008* + ID_MODEL_FROM_DATABASE=DiVO VIP + +pci:v000010A9d00000009* + ID_MODEL_FROM_DATABASE=AceNIC Gigabit Ethernet + +pci:v000010A9d00000009sv000010A9sd00008002* + ID_MODEL_FROM_DATABASE=AceNIC Gigabit Ethernet + +pci:v000010A9d00000010* + ID_MODEL_FROM_DATABASE=AMP Video I/O + +pci:v000010A9d00000011* + ID_MODEL_FROM_DATABASE=GRIP + +pci:v000010A9d00000012* + ID_MODEL_FROM_DATABASE=SGH PSHAC GSN + +pci:v000010A9d00000208* + ID_MODEL_FROM_DATABASE=SSIM1 SAS Adapter + +pci:v000010A9d00001001* + ID_MODEL_FROM_DATABASE=Magic Carpet + +pci:v000010A9d00001002* + ID_MODEL_FROM_DATABASE=Lithium + +pci:v000010A9d00001003* + ID_MODEL_FROM_DATABASE=Dual JPEG 1 + +pci:v000010A9d00001004* + ID_MODEL_FROM_DATABASE=Dual JPEG 2 + +pci:v000010A9d00001005* + ID_MODEL_FROM_DATABASE=Dual JPEG 3 + +pci:v000010A9d00001006* + ID_MODEL_FROM_DATABASE=Dual JPEG 4 + +pci:v000010A9d00001007* + ID_MODEL_FROM_DATABASE=Dual JPEG 5 + +pci:v000010A9d00001008* + ID_MODEL_FROM_DATABASE=Cesium + +pci:v000010A9d0000100A* + ID_MODEL_FROM_DATABASE=IOC4 I/O controller + +pci:v000010A9d00001504* + ID_MODEL_FROM_DATABASE=SSIM1 Fibre Channel Adapter + +pci:v000010A9d00002001* + ID_MODEL_FROM_DATABASE=Fibre Channel + +pci:v000010A9d00002002* + ID_MODEL_FROM_DATABASE=ASDE + +pci:v000010A9d00004001* + ID_MODEL_FROM_DATABASE=TIO-CE PCI Express Bridge + +pci:v000010A9d00004002* + ID_MODEL_FROM_DATABASE=TIO-CE PCI Express Port + +pci:v000010A9d00008001* + ID_MODEL_FROM_DATABASE=O2 1394 + +pci:v000010A9d00008002* + ID_MODEL_FROM_DATABASE=G-net NT + +pci:v000010AA* + ID_VENDOR_FROM_DATABASE=ACC Microelectronics + +pci:v000010AAd00000000* + ID_MODEL_FROM_DATABASE=ACCM 2188 + +pci:v000010AAd00002051* + ID_MODEL_FROM_DATABASE=2051 CPU bridge + +pci:v000010AAd00005842* + ID_MODEL_FROM_DATABASE=2051 ISA bridge + +pci:v000010AB* + ID_VENDOR_FROM_DATABASE=Digicom + +pci:v000010AC* + ID_VENDOR_FROM_DATABASE=Honeywell IAC + +pci:v000010AD* + ID_VENDOR_FROM_DATABASE=Symphony Labs + +pci:v000010ADd00000001* + ID_MODEL_FROM_DATABASE=W83769F + +pci:v000010ADd00000003* + ID_MODEL_FROM_DATABASE=SL82C103 + +pci:v000010ADd00000005* + ID_MODEL_FROM_DATABASE=SL82C105 + +pci:v000010ADd00000103* + ID_MODEL_FROM_DATABASE=SL82c103 + +pci:v000010ADd00000105* + ID_MODEL_FROM_DATABASE=SL82c105 + +pci:v000010ADd00000565* + ID_MODEL_FROM_DATABASE=W83C553F/W83C554F + +pci:v000010AE* + ID_VENDOR_FROM_DATABASE=Cornerstone Technology + +pci:v000010AF* + ID_VENDOR_FROM_DATABASE=Micro Computer Systems Inc + +pci:v000010B0* + ID_VENDOR_FROM_DATABASE=CardExpert Technology + +pci:v000010B1* + ID_VENDOR_FROM_DATABASE=Cabletron Systems Inc + +pci:v000010B2* + ID_VENDOR_FROM_DATABASE=Raytheon Company + +pci:v000010B3* + ID_VENDOR_FROM_DATABASE=Databook Inc + +pci:v000010B3d00003106* + ID_MODEL_FROM_DATABASE=DB87144 + +pci:v000010B3d0000B106* + ID_MODEL_FROM_DATABASE=DB87144 + +pci:v000010B4* + ID_VENDOR_FROM_DATABASE=STB Systems Inc + +pci:v000010B4d00001B1D* + ID_MODEL_FROM_DATABASE=Velocity 128 3D + +pci:v000010B4d00001B1Dsv000010B4sd0000237E* + ID_MODEL_FROM_DATABASE=Velocity 4400 + +pci:v000010B5* + ID_VENDOR_FROM_DATABASE=PLX Technology, Inc. + +pci:v000010B5d00000001* + ID_MODEL_FROM_DATABASE=i960 PCI bus interface + +pci:v000010B5d00000557* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00000557sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=Digium Tormenta 2 T400P-SS7 or E400P-SS7 Quad T1 or E1 PCI card + +pci:v000010B5d00001000* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00001000sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=ATCOM AT400P Quad T1 PCI card + +pci:v000010B5d00001024* + ID_MODEL_FROM_DATABASE=Acromag, Inc. IndustryPack Carrier Card + +pci:v000010B5d00001042* + ID_MODEL_FROM_DATABASE=Brandywine / jxi2, Inc. - PMC-SyncClock32, IRIG A & B, Nasa 36 + +pci:v000010B5d0000106A* + ID_MODEL_FROM_DATABASE=Dual OX16C952 4 port serial adapter [Megawolf Romulus/4] + +pci:v000010B5d00001076* + ID_MODEL_FROM_DATABASE=VScom 800 8 port serial adaptor + +pci:v000010B5d00001077* + ID_MODEL_FROM_DATABASE=VScom 400 4 port serial adaptor + +pci:v000010B5d00001078* + ID_MODEL_FROM_DATABASE=VScom 210 2 port serial and 1 port parallel adaptor + +pci:v000010B5d00001103* + ID_MODEL_FROM_DATABASE=VScom 200 2 port serial adaptor + +pci:v000010B5d00001146* + ID_MODEL_FROM_DATABASE=VScom 010 1 port parallel adaptor + +pci:v000010B5d00001147* + ID_MODEL_FROM_DATABASE=VScom 020 2 port parallel adaptor + +pci:v000010B5d00002000* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00002000sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=ATCOM AE400P Quad E1 PCI card + +pci:v000010B5d00002540* + ID_MODEL_FROM_DATABASE=IXXAT CAN-Interface PC-I 04/PCI + +pci:v000010B5d00002724* + ID_MODEL_FROM_DATABASE=Thales PCSM Security Card + +pci:v000010B5d00003376* + ID_MODEL_FROM_DATABASE=Cosateq 4 Port CAN Card + +pci:v000010B5d00004000* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00004000sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=Tormenta 3 Varion V400P/ATCOM TE400P Quad E1/T1/J1 PCI card + +pci:v000010B5d00004001* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00004001sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=ATCOM A400PE Quad E1 PCI card + +pci:v000010B5d00004002* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00004002sv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=ATCOM A400PT Quad T1 PCI card + +pci:v000010B5d00006140* + ID_MODEL_FROM_DATABASE=PCI6140 32-bit 33MHz PCI-to-PCI Bridge + +pci:v000010B5d00006150* + ID_MODEL_FROM_DATABASE=PCI6150 32-bit 33MHz PCI-to-PCI Bridge + +pci:v000010B5d00006152* + ID_MODEL_FROM_DATABASE=PCI6152 32-bit 66MHz PCI-to-PCI Bridge + +pci:v000010B5d00006154* + ID_MODEL_FROM_DATABASE=PCI6154 64-bit 66MHz PCI-to-PCI Bridge + +pci:v000010B5d00006254* + ID_MODEL_FROM_DATABASE=PCI6254 64-bit 66MHz PCI-to-PCI Bridge + +pci:v000010B5d00006466* + ID_MODEL_FROM_DATABASE=PCI6466 64-bit 66MHz PCI-to-PCI Bridge + +pci:v000010B5d00006520* + ID_MODEL_FROM_DATABASE=PCI6520 64-bit 133MHz PCI-X-to-PCI-X Bridge + +pci:v000010B5d00006540* + ID_MODEL_FROM_DATABASE=PCI6540 64-bit 133MHz PCI-X-to-PCI-X Bridge + +pci:v000010B5d00006540sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11 Single Board Computer + +pci:v000010B5d00006540sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v000010B5d00006541* + ID_MODEL_FROM_DATABASE=PCI6540/6466 PCI-PCI bridge (non-transparent mode, primary side) + +pci:v000010B5d00006541sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11 Single Board Computer + +pci:v000010B5d00006541sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v000010B5d00006542* + ID_MODEL_FROM_DATABASE=PCI6540/6466 PCI-PCI bridge (non-transparent mode, secondary side) + +pci:v000010B5d00006542sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11 Single Board Computer + +pci:v000010B5d00006542sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v000010B5d00008111* + ID_MODEL_FROM_DATABASE=PEX 8111 PCI Express-to-PCI Bridge + +pci:v000010B5d00008112* + ID_MODEL_FROM_DATABASE=PEX8112 x1 Lane PCI Express-to-PCI Bridge + +pci:v000010B5d00008114* + ID_MODEL_FROM_DATABASE=PEX 8114 PCI Express-to-PCI/PCI-X Bridge + +pci:v000010B5d00008311* + ID_MODEL_FROM_DATABASE=PEX8311 x1 Lane PCI Express-to-Generic Local Bus Bridge + +pci:v000010B5d00008505* + ID_MODEL_FROM_DATABASE=PEX 8505 5-lane, 5-port PCI Express Switch + +pci:v000010B5d00008508* + ID_MODEL_FROM_DATABASE=PEX 8508 8-lane, 5-port PCI Express Switch + +pci:v000010B5d00008509* + ID_MODEL_FROM_DATABASE=PEX 8509 8-lane, 8-port PCI Express Switch + +pci:v000010B5d00008512* + ID_MODEL_FROM_DATABASE=PEX 8512 12-lane, 5-port PCI Express Switch + +pci:v000010B5d00008516* + ID_MODEL_FROM_DATABASE=PEX 8516 Versatile PCI Express Switch + +pci:v000010B5d00008517* + ID_MODEL_FROM_DATABASE=PEX 8517 16-lane, 5-port PCI Express Switch + +pci:v000010B5d00008518* + ID_MODEL_FROM_DATABASE=PEX 8518 16-lane, 5-port PCI Express Switch + +pci:v000010B5d00008524* + ID_MODEL_FROM_DATABASE=PEX 8524 24-lane, 6-port PCI Express Switch + +pci:v000010B5d00008525* + ID_MODEL_FROM_DATABASE=PEX 8525 24-lane, 5-port PCI Express Switch + +pci:v000010B5d00008532* + ID_MODEL_FROM_DATABASE=PEX 8532 Versatile PCI Express Switch + +pci:v000010B5d00008533* + ID_MODEL_FROM_DATABASE=PEX 8533 32-lane, 6-port PCI Express Switch + +pci:v000010B5d00008547* + ID_MODEL_FROM_DATABASE=PEX 8547 48-lane, 3-port PCI Express Switch + +pci:v000010B5d00008548* + ID_MODEL_FROM_DATABASE=PEX 8548 48-lane, 9-port PCI Express Switch + +pci:v000010B5d00008604* + ID_MODEL_FROM_DATABASE=PEX 8604 4-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008605* + ID_MODEL_FROM_DATABASE=PEX 8605 PCI Express 4-port Gen2 Switch + +pci:v000010B5d00008606* + ID_MODEL_FROM_DATABASE=PEX 8606 6 Lane, 6 Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008608* + ID_MODEL_FROM_DATABASE=PEX 8608 8-lane, 8-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008609* + ID_MODEL_FROM_DATABASE=PEX 8609 8-lane, 8-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA + +pci:v000010B5d00008612* + ID_MODEL_FROM_DATABASE=PEX 8612 12-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008613* + ID_MODEL_FROM_DATABASE=PEX 8613 12-lane, 3-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008614* + ID_MODEL_FROM_DATABASE=PEX 8614 12-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008615* + ID_MODEL_FROM_DATABASE=PEX 8615 12-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA + +pci:v000010B5d00008616* + ID_MODEL_FROM_DATABASE=PEX 8616 16-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008617* + ID_MODEL_FROM_DATABASE=PEX 8617 16-lane, 4-Port PCI Express Gen 2 (5.0 GT/s) Switch with P2P + +pci:v000010B5d00008618* + ID_MODEL_FROM_DATABASE=PEX 8618 16-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008619* + ID_MODEL_FROM_DATABASE=PEX 8619 16-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch with DMA + +pci:v000010B5d00008624* + ID_MODEL_FROM_DATABASE=PEX 8624 24-lane, 6-Port PCI Express Gen 2 (5.0 GT/s) Switch [ExpressLane] + +pci:v000010B5d00008624sv000013A3sd00001845* + ID_MODEL_FROM_DATABASE=DX1845 Acceleration Card + +pci:v000010B5d00008625* + ID_MODEL_FROM_DATABASE=PEX 8625 24-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008632* + ID_MODEL_FROM_DATABASE=PEX 8632 32-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008636* + ID_MODEL_FROM_DATABASE=PEX 8636 36-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008647* + ID_MODEL_FROM_DATABASE=PEX 8647 48-Lane, 3-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008648* + ID_MODEL_FROM_DATABASE=PEX 8648 48-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008649* + ID_MODEL_FROM_DATABASE=PEX 8649 48-lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008664* + ID_MODEL_FROM_DATABASE=PEX 8664 64-lane, 16-Port PCI Express Gen 2 (5.0 GT/s) Switch + +pci:v000010B5d00008680* + ID_MODEL_FROM_DATABASE=PEX 8680 80-lane, 20-Port PCI Express Gen 2 (5.0 GT/s) Multi-Root Switch + +pci:v000010B5d00008696* + ID_MODEL_FROM_DATABASE=PEX 8696 96-lane, 24-Port PCI Express Gen 2 (5.0 GT/s) Multi-Root Switch + +pci:v000010B5d00008717* + ID_MODEL_FROM_DATABASE=PEX 8717 16-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch with DMA + +pci:v000010B5d00008718* + ID_MODEL_FROM_DATABASE=PEX 8718 16-Lane, 5-Port PCI Express Gen 3 (8.0 GT/s) Switch + +pci:v000010B5d00008732* + ID_MODEL_FROM_DATABASE=PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch + +pci:v000010B5d00008734* + ID_MODEL_FROM_DATABASE=PEX 8734 32-lane, 8-Port PCI Express Gen 3 (8.0GT/s) Switch + +pci:v000010B5d000087B0* + ID_MODEL_FROM_DATABASE=PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch + +pci:v000010B5d00009016* + ID_MODEL_FROM_DATABASE=PLX 9016 8-port serial controller + +pci:v000010B5d00009030* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00009030sv000010B5sd00002695* + ID_MODEL_FROM_DATABASE=Hilscher CIF50-PB/DPS Profibus + +pci:v000010B5d00009030sv000010B5sd00002862* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI LV (3V/5V): Timecode Reader Board + +pci:v000010B5d00009030sv000010B5sd00002906* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCI TS (3V/5V): Time Synchronisation Board + +pci:v000010B5d00009030sv000010B5sd00002940* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI D (3V/5V): Timecode Reader Board + +pci:v000010B5d00009030sv000010B5sd00002977* + ID_MODEL_FROM_DATABASE=IXXAT iPC-I XC16/PCI CAN Board + +pci:v000010B5d00009030sv000010B5sd00002978* + ID_MODEL_FROM_DATABASE=SH ARC-PCIu/SH ARC-PCI104/SH ARC-PCIe SOHARD ARCNET card + +pci:v000010B5d00009030sv000010B5sd00003025* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI L (3V/5V): Timecode Reader Board + +pci:v000010B5d00009030sv000010B5sd00003068* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI HD (3V/5V): Timecode Reader Board + +pci:v000010B5d00009030sv000010B5sd00003463* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI D (v2) (3V/5V): Timecode Reader Board + +pci:v000010B5d00009030sv000012FEsd00000111* + ID_MODEL_FROM_DATABASE=CPCI-ASIO4 (ESD 4-port Serial Interface Board) + +pci:v000010B5d00009030sv00001369sd00009C01* + ID_MODEL_FROM_DATABASE=VX222v2 + +pci:v000010B5d00009030sv00001369sd00009D01* + ID_MODEL_FROM_DATABASE=VX222-Mic + +pci:v000010B5d00009030sv00001369sd00009D02* + ID_MODEL_FROM_DATABASE=VX222-Mic + +pci:v000010B5d00009030sv00001369sd00009E01* + ID_MODEL_FROM_DATABASE=PCX924v2 + +pci:v000010B5d00009030sv00001369sd00009F01* + ID_MODEL_FROM_DATABASE=PCX924-Mic + +pci:v000010B5d00009030sv00001369sd00009F02* + ID_MODEL_FROM_DATABASE=PCX924-Mic + +pci:v000010B5d00009030sv00001369sd0000A001* + ID_MODEL_FROM_DATABASE=PCX22v2 + +pci:v000010B5d00009030sv00001369sd0000A701* + ID_MODEL_FROM_DATABASE=LCM220v2 + +pci:v000010B5d00009030sv00001369sd0000A801* + ID_MODEL_FROM_DATABASE=LCM200 + +pci:v000010B5d00009030sv00001397sd00003136* + ID_MODEL_FROM_DATABASE=4xS0-ISDN PCI Adapter + +pci:v000010B5d00009030sv00001397sd00003137* + ID_MODEL_FROM_DATABASE=S2M-E1-ISDN PCI Adapter + +pci:v000010B5d00009030sv00001518sd00000200* + ID_MODEL_FROM_DATABASE=Kontron ThinkIO-C + +pci:v000010B5d00009030sv000015EDsd00001002* + ID_MODEL_FROM_DATABASE=MCCS 8-port Serial Hot Swap + +pci:v000010B5d00009030sv000015EDsd00001003* + ID_MODEL_FROM_DATABASE=MCCS 16-port Serial Hot Swap + +pci:v000010B5d00009030sv0000E1C5sd00000001* + ID_MODEL_FROM_DATABASE=TE1-PCI + +pci:v000010B5d00009030sv0000E1C5sd00000005* + ID_MODEL_FROM_DATABASE=TA1-PCI + +pci:v000010B5d00009030sv0000E1C5sd00000006* + ID_MODEL_FROM_DATABASE=TA1-PCI4 + +pci:v000010B5d00009036* + ID_MODEL_FROM_DATABASE=9036 + +pci:v000010B5d00009050* + ID_MODEL_FROM_DATABASE=PCI <-> IOBus Bridge + +pci:v000010B5d00009050sv000010B5sd00001067* + ID_MODEL_FROM_DATABASE=IXXAT CAN i165 + +pci:v000010B5d00009050sv000010B5sd0000114E* + ID_MODEL_FROM_DATABASE=Wasco WITIO PCI168extended + +pci:v000010B5d00009050sv000010B5sd00001169* + ID_MODEL_FROM_DATABASE=Wasco OPTOIO32standard 32 digital in, 32 digital out + +pci:v000010B5d00009050sv000010B5sd00001172* + ID_MODEL_FROM_DATABASE=IK220 (Heidenhain) + +pci:v000010B5d00009050sv000010B5sd00002036* + ID_MODEL_FROM_DATABASE=SatPak GPS + +pci:v000010B5d00009050sv000010B5sd00002221* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI LV: Timecode Reader Board + +pci:v000010B5d00009050sv000010B5sd00002273* + ID_MODEL_FROM_DATABASE=SH ARC-PCI SOHARD ARCNET card + +pci:v000010B5d00009050sv000010B5sd00002431* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCI D: Timecode Reader Board + +pci:v000010B5d00009050sv000010B5sd00002905* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCI TS: Time Synchronisation Board + +pci:v000010B5d00009050sv000010B5sd00003196* + ID_MODEL_FROM_DATABASE=Goramo PLX200SYN sync serial card + +pci:v000010B5d00009050sv000010B5sd00009050* + ID_MODEL_FROM_DATABASE=PCI-I04 PCI Passive PC/CAN Interface + +pci:v000010B5d00009050sv00001369sd00008901* + ID_MODEL_FROM_DATABASE=PCX11+ PCI + +pci:v000010B5d00009050sv00001369sd00008F01* + ID_MODEL_FROM_DATABASE=VX222 + +pci:v000010B5d00009050sv00001369sd00009401* + ID_MODEL_FROM_DATABASE=PCX924 + +pci:v000010B5d00009050sv00001369sd00009501* + ID_MODEL_FROM_DATABASE=PCX22 + +pci:v000010B5d00009050sv00001498sd00000362* + ID_MODEL_FROM_DATABASE=TPMC866 8 Channel Serial Card + +pci:v000010B5d00009050sv00001522sd00000001* + ID_MODEL_FROM_DATABASE=RockForce 4 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv00001522sd00000002* + ID_MODEL_FROM_DATABASE=RockForce 2 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv00001522sd00000003* + ID_MODEL_FROM_DATABASE=RockForce 6 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv00001522sd00000004* + ID_MODEL_FROM_DATABASE=RockForce 8 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv00001522sd00000010* + ID_MODEL_FROM_DATABASE=RockForce2000 4 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv00001522sd00000020* + ID_MODEL_FROM_DATABASE=RockForce2000 2 Port V.90 Data/Fax/Voice Modem + +pci:v000010B5d00009050sv000015EDsd00001000* + ID_MODEL_FROM_DATABASE=Macrolink MCCS 8-port Serial + +pci:v000010B5d00009050sv000015EDsd00001001* + ID_MODEL_FROM_DATABASE=Macrolink MCCS 16-port Serial + +pci:v000010B5d00009050sv000015EDsd00001002* + ID_MODEL_FROM_DATABASE=Macrolink MCCS 8-port Serial Hot Swap + +pci:v000010B5d00009050sv000015EDsd00001003* + ID_MODEL_FROM_DATABASE=Macrolink MCCS 16-port Serial Hot Swap + +pci:v000010B5d00009050sv00005654sd00002036* + ID_MODEL_FROM_DATABASE=OpenSwitch 6 Telephony card + +pci:v000010B5d00009050sv00005654sd00003132* + ID_MODEL_FROM_DATABASE=OpenSwitch 12 Telephony card + +pci:v000010B5d00009050sv00005654sd00005634* + ID_MODEL_FROM_DATABASE=OpenLine4 Telephony Card + +pci:v000010B5d00009050sv0000D531sd0000C002* + ID_MODEL_FROM_DATABASE=PCIntelliCAN 2xSJA1000 CAN bus + +pci:v000010B5d00009050sv0000D84Dsd00004006* + ID_MODEL_FROM_DATABASE=EX-4006 1P + +pci:v000010B5d00009050sv0000D84Dsd00004008* + ID_MODEL_FROM_DATABASE=EX-4008 1P EPP/ECP + +pci:v000010B5d00009050sv0000D84Dsd00004014* + ID_MODEL_FROM_DATABASE=EX-4014 2P + +pci:v000010B5d00009050sv0000D84Dsd00004018* + ID_MODEL_FROM_DATABASE=EX-4018 3P EPP/ECP + +pci:v000010B5d00009050sv0000D84Dsd00004025* + ID_MODEL_FROM_DATABASE=EX-4025 1S(16C550) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004027* + ID_MODEL_FROM_DATABASE=EX-4027 1S(16C650) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004028* + ID_MODEL_FROM_DATABASE=EX-4028 1S(16C850) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004036* + ID_MODEL_FROM_DATABASE=EX-4036 2S(16C650) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004037* + ID_MODEL_FROM_DATABASE=EX-4037 2S(16C650) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004038* + ID_MODEL_FROM_DATABASE=EX-4038 2S(16C850) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004052* + ID_MODEL_FROM_DATABASE=EX-4052 1S(16C550) RS-422/485 + +pci:v000010B5d00009050sv0000D84Dsd00004053* + ID_MODEL_FROM_DATABASE=EX-4053 2S(16C550) RS-422/485 + +pci:v000010B5d00009050sv0000D84Dsd00004055* + ID_MODEL_FROM_DATABASE=EX-4055 4S(16C550) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004058* + ID_MODEL_FROM_DATABASE=EX-4055 4S(16C650) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004065* + ID_MODEL_FROM_DATABASE=EX-4065 8S(16C550) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004068* + ID_MODEL_FROM_DATABASE=EX-4068 8S(16C650) RS-232 + +pci:v000010B5d00009050sv0000D84Dsd00004078* + ID_MODEL_FROM_DATABASE=EX-4078 2S(16C552) RS-232+1P + +pci:v000010B5d00009052* + ID_MODEL_FROM_DATABASE=PCI9052 PCI <-> IOBus Bridge + +pci:v000010B5d00009054* + ID_MODEL_FROM_DATABASE=PCI9054 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00009054sv000010B5sd00002455* + ID_MODEL_FROM_DATABASE=Wessex Techology PHIL-PCI + +pci:v000010B5d00009054sv000010B5sd00002696* + ID_MODEL_FROM_DATABASE=Innes Corp AM Radcap card + +pci:v000010B5d00009054sv000010B5sd00002717* + ID_MODEL_FROM_DATABASE=Innes Corp Auricon card + +pci:v000010B5d00009054sv000010B5sd00002844* + ID_MODEL_FROM_DATABASE=Innes Corp TVS Encoder card + +pci:v000010B5d00009054sv000012C7sd00004001* + ID_MODEL_FROM_DATABASE=Intel Dialogic DM/V960-4T1 PCI + +pci:v000010B5d00009054sv000012D9sd00000002* + ID_MODEL_FROM_DATABASE=PCI Prosody Card rev 1.5 + +pci:v000010B5d00009054sv000014B4sd0000D100* + ID_MODEL_FROM_DATABASE=Dektec DTA-100 + +pci:v000010B5d00009054sv000014B4sd0000D114* + ID_MODEL_FROM_DATABASE=Dektec DTA-120 + +pci:v000010B5d00009054sv000016DFsd00000011* + ID_MODEL_FROM_DATABASE=PIKA PrimeNet MM PCI + +pci:v000010B5d00009054sv000016DFsd00000012* + ID_MODEL_FROM_DATABASE=PIKA PrimeNet MM cPCI 8 + +pci:v000010B5d00009054sv000016DFsd00000013* + ID_MODEL_FROM_DATABASE=PIKA PrimeNet MM cPCI 8 (without CAS Signaling) + +pci:v000010B5d00009054sv000016DFsd00000014* + ID_MODEL_FROM_DATABASE=PIKA PrimeNet MM cPCI 4 + +pci:v000010B5d00009054sv000016DFsd00000015* + ID_MODEL_FROM_DATABASE=PIKA Daytona MM + +pci:v000010B5d00009054sv000016DFsd00000016* + ID_MODEL_FROM_DATABASE=PIKA InLine MM + +pci:v000010B5d00009056* + ID_MODEL_FROM_DATABASE=PCI9056 32-bit 66MHz PCI <-> IOBus Bridge + +pci:v000010B5d00009056sv000010B5sd00002979* + ID_MODEL_FROM_DATABASE=CellinkBlade 11 - CPCI board VoATM AAL1 + +pci:v000010B5d00009056sv000010B5sd00003268* + ID_MODEL_FROM_DATABASE=IXXAT iPC-I XC16/PCIe CAN Board + +pci:v000010B5d00009056sv000010B5sd00003352* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCIe HD: Timecode Reader Board + +pci:v000010B5d00009056sv000010B5sd00003353* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCIe D: Timecode Reader Board + +pci:v000010B5d00009056sv000010B5sd00003354* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCIe LV: Timecode Reader Board + +pci:v000010B5d00009056sv000010B5sd00003355* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCIe L: Timecode Reader Board + +pci:v000010B5d00009056sv000010B5sd00003415* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCIe TS: Time Synchronisation Board + +pci:v000010B5d00009056sv000010B5sd00003493* + ID_MODEL_FROM_DATABASE=Alpermann+Velte PCL PCIe 3G: Timecode Reader Board + +pci:v000010B5d00009056sv00001369sd0000C001* + ID_MODEL_FROM_DATABASE=LX6464ES + +pci:v000010B5d00009056sv00001369sd0000C201* + ID_MODEL_FROM_DATABASE=LX1616ES + +pci:v000010B5d00009056sv000014B4sd0000D10A* + ID_MODEL_FROM_DATABASE=DekTec DTA-110T + +pci:v000010B5d00009056sv000014B4sd0000D140* + ID_MODEL_FROM_DATABASE=Dektec DTA-140 + +pci:v000010B5d00009056sv00001A0Esd0000006F* + ID_MODEL_FROM_DATABASE=Dektec DTA-111 + +pci:v000010B5d00009060* + ID_MODEL_FROM_DATABASE=PCI9060 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d0000906D* + ID_MODEL_FROM_DATABASE=9060SD + +pci:v000010B5d0000906Dsv0000125Csd00000640* + ID_MODEL_FROM_DATABASE=Aries 16000P + +pci:v000010B5d0000906E* + ID_MODEL_FROM_DATABASE=9060ES + +pci:v000010B5d00009080* + ID_MODEL_FROM_DATABASE=PCI9080 32-bit; 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d00009080sv0000103Csd000010EB* + ID_MODEL_FROM_DATABASE=(Agilent) E2777B 83K Series Optical Communication Interface + +pci:v000010B5d00009080sv0000103Csd000010EC* + ID_MODEL_FROM_DATABASE=(Agilent) E6978-66442 PCI CIC + +pci:v000010B5d00009080sv000010B5sd00001123* + ID_MODEL_FROM_DATABASE=Sectra KK631 encryption board + +pci:v000010B5d00009080sv000010B5sd00009080* + ID_MODEL_FROM_DATABASE=9080 [real subsystem ID not set] + +pci:v000010B5d00009080sv000012D9sd00000002* + ID_MODEL_FROM_DATABASE=PCI Prosody Card + +pci:v000010B5d00009080sv000012DFsd00004422* + ID_MODEL_FROM_DATABASE=4422PCI ["Do-All" Telemetry Data Aquisition System] + +pci:v000010B5d00009080sv00001369sd00009601* + ID_MODEL_FROM_DATABASE=PCX822np + +pci:v000010B5d00009080sv00001369sd0000A102* + ID_MODEL_FROM_DATABASE=PCX822v2 + +pci:v000010B5d00009080sv00001369sd0000A201* + ID_MODEL_FROM_DATABASE=PCX442 + +pci:v000010B5d00009080sv00001369sd0000A301* + ID_MODEL_FROM_DATABASE=LCM440v2 + +pci:v000010B5d00009080sv00001369sd0000A401* + ID_MODEL_FROM_DATABASE=VX822 + +pci:v000010B5d00009080sv00001369sd0000A402* + ID_MODEL_FROM_DATABASE=VX822v2 + +pci:v000010B5d00009080sv00001369sd0000A901* + ID_MODEL_FROM_DATABASE=LCM420 + +pci:v000010B5d00009080sv00001369sd0000AA01* + ID_MODEL_FROM_DATABASE=VX820v2 + +pci:v000010B5d00009080sv00001517sd0000000B* + ID_MODEL_FROM_DATABASE=ECSG-1R3ADC-PMC Clock synthesizer + +pci:v000010B5d00009656* + ID_MODEL_FROM_DATABASE=PCI9656 PCI <-> IOBus Bridge + +pci:v000010B5d00009656sv00001517sd0000000F* + ID_MODEL_FROM_DATABASE=ECDR-GC314-PMC Receiver + +pci:v000010B5d00009656sv00001885sd00000700* + ID_MODEL_FROM_DATABASE=Tsunami FPGA PMC with Altera Stratix S40 + +pci:v000010B5d00009656sv00001885sd00000701* + ID_MODEL_FROM_DATABASE=Tsunami FPGA PMC with Altera Stratix S30 + +pci:v000010B5d0000A100* + ID_MODEL_FROM_DATABASE=Blackmagic Design DeckLink + +pci:v000010B5d0000BB04* + ID_MODEL_FROM_DATABASE=B&B 3PCIOSD1A Isolated PCI Serial + +pci:v000010B5d0000C001* + ID_MODEL_FROM_DATABASE=CronyxOmega-PCI (8-port RS232) + +pci:v000010B5d0000D00D* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d0000D00Dsv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=Digium Tormenta 2 T400P or E400P Quad T1 or E1 PCI card + +pci:v000010B5d0000D33D* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d0000D33Dsv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=Tormenta 3 Varion V401PT Quad T1/J1 PCI card + +pci:v000010B5d0000D44D* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge + +pci:v000010B5d0000D44Dsv000010B5sd000017F6* + ID_MODEL_FROM_DATABASE=Allo CP100P/E 1-port E1/T1/J1 PCI/PCIe card + +pci:v000010B5d0000D44Dsv000010B5sd000017F7* + ID_MODEL_FROM_DATABASE=Allo CP400P/E 4-port E1/T1/J1 PCI/PCIe card + +pci:v000010B5d0000D44Dsv000010B5sd000017F8* + ID_MODEL_FROM_DATABASE=Allo CP200P/E 2-port E1/T1/J1 PCI/PCIe card + +pci:v000010B5d0000D44Dsv000010B5sd00009030* + ID_MODEL_FROM_DATABASE=Tormenta 3 Varion V401PE Quad E1 PCI card + +pci:v000010B6* + ID_VENDOR_FROM_DATABASE=Madge Networks + +pci:v000010B6d00000001* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode + +pci:v000010B6d00000002* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode Mk2 + +pci:v000010B6d00000002sv000010B6sd00000002* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode Mk2 + +pci:v000010B6d00000002sv000010B6sd00000006* + ID_MODEL_FROM_DATABASE=16/4 CardBus Adapter + +pci:v000010B6d00000003* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode Mk3 + +pci:v000010B6d00000003sv00000E11sd0000B0FD* + ID_MODEL_FROM_DATABASE=Compaq NC4621 PCI, 4/16, WOL + +pci:v000010B6d00000003sv000010B6sd00000003* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode Mk3 + +pci:v000010B6d00000003sv000010B6sd00000007* + ID_MODEL_FROM_DATABASE=Presto PCI Plus Adapter + +pci:v000010B6d00000004* + ID_MODEL_FROM_DATABASE=Smart 16/4 PCI Ringnode Mk1 + +pci:v000010B6d00000006* + ID_MODEL_FROM_DATABASE=16/4 Cardbus Adapter + +pci:v000010B6d00000006sv000010B6sd00000006* + ID_MODEL_FROM_DATABASE=16/4 CardBus Adapter + +pci:v000010B6d00000007* + ID_MODEL_FROM_DATABASE=Presto PCI Adapter + +pci:v000010B6d00000007sv000010B6sd00000007* + ID_MODEL_FROM_DATABASE=Presto PCI + +pci:v000010B6d00000009* + ID_MODEL_FROM_DATABASE=Smart 100/16/4 PCI-HS Ringnode + +pci:v000010B6d00000009sv000010B6sd00000009* + ID_MODEL_FROM_DATABASE=Smart 100/16/4 PCI-HS Ringnode + +pci:v000010B6d0000000A* + ID_MODEL_FROM_DATABASE=Smart 100/16/4 PCI Ringnode + +pci:v000010B6d0000000Asv000010B6sd0000000A* + ID_MODEL_FROM_DATABASE=Smart 100/16/4 PCI Ringnode + +pci:v000010B6d0000000B* + ID_MODEL_FROM_DATABASE=16/4 CardBus Adapter Mk2 + +pci:v000010B6d0000000Bsv000010B6sd00000008* + ID_MODEL_FROM_DATABASE=16/4 CardBus Adapter Mk2 + +pci:v000010B6d0000000Bsv000010B6sd0000000B* + ID_MODEL_FROM_DATABASE=16/4 Cardbus Adapter Mk2 + +pci:v000010B6d0000000C* + ID_MODEL_FROM_DATABASE=RapidFire 3140V2 16/4 TR Adapter + +pci:v000010B6d0000000Csv000010B6sd0000000C* + ID_MODEL_FROM_DATABASE=RapidFire 3140V2 16/4 TR Adapter + +pci:v000010B6d00001000* + ID_MODEL_FROM_DATABASE=Collage 25/155 ATM Client Adapter + +pci:v000010B6d00001001* + ID_MODEL_FROM_DATABASE=Collage 155 ATM Server Adapter + +pci:v000010B7* + ID_VENDOR_FROM_DATABASE=3Com Corporation + +pci:v000010B7d00000001* + ID_MODEL_FROM_DATABASE=3c985 1000BaseSX (SX/TX) + +pci:v000010B7d00000013* + ID_MODEL_FROM_DATABASE=AR5212 802.11abg NIC (3CRDAG675) + +pci:v000010B7d00000013sv000010B7sd00002031* + ID_MODEL_FROM_DATABASE=3CRDAG675 11a/b/g Wireless PCI Adapter + +pci:v000010B7d00000910* + ID_MODEL_FROM_DATABASE=3C910-A01 + +pci:v000010B7d00001006* + ID_MODEL_FROM_DATABASE=MINI PCI type 3B Data Fax Modem + +pci:v000010B7d00001007* + ID_MODEL_FROM_DATABASE=Mini PCI 56k Winmodem + +pci:v000010B7d00001007sv000010B7sd0000615B* + ID_MODEL_FROM_DATABASE=Mini PCI 56K Modem + +pci:v000010B7d00001007sv000010B7sd0000615C* + ID_MODEL_FROM_DATABASE=Mini PCI 56K Modem + +pci:v000010B7d00001201* + ID_MODEL_FROM_DATABASE=3c982-TXM 10/100baseTX Dual Port A [Hydra] + +pci:v000010B7d00001202* + ID_MODEL_FROM_DATABASE=3c982-TXM 10/100baseTX Dual Port B [Hydra] + +pci:v000010B7d00001700* + ID_MODEL_FROM_DATABASE=3c940 10/100/1000Base-T [Marvell] + +pci:v000010B7d00001700sv00001043sd000080EB* + ID_MODEL_FROM_DATABASE=A7V600/P4P800/K8V motherboard + +pci:v000010B7d00001700sv000010B7sd00000010* + ID_MODEL_FROM_DATABASE=3C940 Gigabit LOM Ethernet Adapter + +pci:v000010B7d00001700sv000010B7sd00000020* + ID_MODEL_FROM_DATABASE=3C941 Gigabit LOM Ethernet Adapter + +pci:v000010B7d00001700sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v000010B7d00003390* + ID_MODEL_FROM_DATABASE=3c339 TokenLink Velocity + +pci:v000010B7d00003590* + ID_MODEL_FROM_DATABASE=3c359 TokenLink Velocity XL + +pci:v000010B7d00003590sv000010B7sd00003590* + ID_MODEL_FROM_DATABASE=TokenLink Velocity XL Adapter (3C359/359B) + +pci:v000010B7d00004500* + ID_MODEL_FROM_DATABASE=3c450 HomePNA [Tornado] + +pci:v000010B7d00005055* + ID_MODEL_FROM_DATABASE=3c555 Laptop Hurricane + +pci:v000010B7d00005057* + ID_MODEL_FROM_DATABASE=3c575 Megahertz 10/100 LAN CardBus [Boomerang] + +pci:v000010B7d00005057sv000010B7sd00005A57* + ID_MODEL_FROM_DATABASE=3C575 Megahertz 10/100 LAN Cardbus PC Card + +pci:v000010B7d00005157* + ID_MODEL_FROM_DATABASE=3cCFE575BT Megahertz 10/100 LAN CardBus [Cyclone] + +pci:v000010B7d00005157sv000010B7sd00005B57* + ID_MODEL_FROM_DATABASE=3C575 Megahertz 10/100 LAN Cardbus PC Card + +pci:v000010B7d00005257* + ID_MODEL_FROM_DATABASE=3cCFE575CT CardBus [Cyclone] + +pci:v000010B7d00005257sv000010B7sd00005C57* + ID_MODEL_FROM_DATABASE=FE575C-3Com 10/100 LAN CardBus-Fast Ethernet + +pci:v000010B7d00005900* + ID_MODEL_FROM_DATABASE=3c590 10BaseT [Vortex] + +pci:v000010B7d00005920* + ID_MODEL_FROM_DATABASE=3c592 EISA 10mbps Demon/Vortex + +pci:v000010B7d00005950* + ID_MODEL_FROM_DATABASE=3c595 100BaseTX [Vortex] + +pci:v000010B7d00005951* + ID_MODEL_FROM_DATABASE=3c595 100BaseT4 [Vortex] + +pci:v000010B7d00005952* + ID_MODEL_FROM_DATABASE=3c595 100Base-MII [Vortex] + +pci:v000010B7d00005970* + ID_MODEL_FROM_DATABASE=3c597 EISA Fast Demon/Vortex + +pci:v000010B7d00005B57* + ID_MODEL_FROM_DATABASE=3c595 Megahertz 10/100 LAN CardBus [Boomerang] + +pci:v000010B7d00005B57sv000010B7sd00005B57* + ID_MODEL_FROM_DATABASE=3C575 Megahertz 10/100 LAN Cardbus PC Card + +pci:v000010B7d00006000* + ID_MODEL_FROM_DATABASE=3CRSHPW796 [OfficeConnect Wireless CardBus] + +pci:v000010B7d00006001* + ID_MODEL_FROM_DATABASE=3com 3CRWE154G72 [Office Connect Wireless LAN Adapter] + +pci:v000010B7d00006055* + ID_MODEL_FROM_DATABASE=3c556 Hurricane CardBus [Cyclone] + +pci:v000010B7d00006056* + ID_MODEL_FROM_DATABASE=3c556B CardBus [Tornado] + +pci:v000010B7d00006056sv000010B7sd00006556* + ID_MODEL_FROM_DATABASE=10/100 Mini PCI Ethernet Adapter + +pci:v000010B7d00006560* + ID_MODEL_FROM_DATABASE=3cCFE656 CardBus [Cyclone] + +pci:v000010B7d00006560sv000010B7sd0000656A* + ID_MODEL_FROM_DATABASE=3CCFEM656 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006561* + ID_MODEL_FROM_DATABASE=3cCFEM656 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006561sv000010B7sd0000656B* + ID_MODEL_FROM_DATABASE=3CCFEM656 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006562* + ID_MODEL_FROM_DATABASE=3cCFEM656B 10/100 LAN+Winmodem CardBus [Cyclone] + +pci:v000010B7d00006562sv000010B7sd0000656B* + ID_MODEL_FROM_DATABASE=3CCFEM656B 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006563* + ID_MODEL_FROM_DATABASE=3cCFEM656B 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006563sv000010B7sd0000656B* + ID_MODEL_FROM_DATABASE=3CCFEM656 10/100 LAN+56K Modem CardBus + +pci:v000010B7d00006564* + ID_MODEL_FROM_DATABASE=3cXFEM656C 10/100 LAN+Winmodem CardBus [Tornado] + +pci:v000010B7d00007646* + ID_MODEL_FROM_DATABASE=3cSOHO100-TX Hurricane + +pci:v000010B7d00007770* + ID_MODEL_FROM_DATABASE=3CRWE777 PCI Wireless Adapter [Airconnect] + +pci:v000010B7d00007940* + ID_MODEL_FROM_DATABASE=3c803 FDDILink UTP Controller + +pci:v000010B7d00007980* + ID_MODEL_FROM_DATABASE=3c804 FDDILink SAS Controller + +pci:v000010B7d00007990* + ID_MODEL_FROM_DATABASE=3c805 FDDILink DAS Controller + +pci:v000010B7d000080EB* + ID_MODEL_FROM_DATABASE=3c940B 10/100/1000Base-T + +pci:v000010B7d00008811* + ID_MODEL_FROM_DATABASE=Token ring + +pci:v000010B7d00009000* + ID_MODEL_FROM_DATABASE=3c900 10BaseT [Boomerang] + +pci:v000010B7d00009001* + ID_MODEL_FROM_DATABASE=3c900 10Mbps Combo [Boomerang] + +pci:v000010B7d00009004* + ID_MODEL_FROM_DATABASE=3c900B-TPO Etherlink XL [Cyclone] + +pci:v000010B7d00009004sv000010B7sd00009004* + ID_MODEL_FROM_DATABASE=3C900B-TPO Etherlink XL TPO 10Mb + +pci:v000010B7d00009005* + ID_MODEL_FROM_DATABASE=3c900B-Combo Etherlink XL [Cyclone] + +pci:v000010B7d00009005sv000010B7sd00009005* + ID_MODEL_FROM_DATABASE=3C900B-Combo Etherlink XL Combo + +pci:v000010B7d00009006* + ID_MODEL_FROM_DATABASE=3c900B-TPC Etherlink XL [Cyclone] + +pci:v000010B7d0000900A* + ID_MODEL_FROM_DATABASE=3c900B-FL 10base-FL [Cyclone] + +pci:v000010B7d00009050* + ID_MODEL_FROM_DATABASE=3c905 100BaseTX [Boomerang] + +pci:v000010B7d00009051* + ID_MODEL_FROM_DATABASE=3c905 100BaseT4 [Boomerang] + +pci:v000010B7d00009054* + ID_MODEL_FROM_DATABASE=3C905B-TX Fast Etherlink XL PCI + +pci:v000010B7d00009054sv000010B7sd00009054* + ID_MODEL_FROM_DATABASE=3C905B-TX Fast Etherlink XL PCI + +pci:v000010B7d00009055* + ID_MODEL_FROM_DATABASE=3c905B 100BaseTX [Cyclone] + +pci:v000010B7d00009055sv00001028sd00000080* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000081* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000082* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000083* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000084* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000085* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000086* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000087* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000088* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000089* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000090* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000091* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000092* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000093* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000094* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000095* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000096* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000097* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000098* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv00001028sd00000099* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009055sv000010B7sd00009055* + ID_MODEL_FROM_DATABASE=3C905B Fast Etherlink XL 10/100 + +pci:v000010B7d00009056* + ID_MODEL_FROM_DATABASE=3c905B-T4 Fast EtherLink XL [Cyclone] + +pci:v000010B7d00009058* + ID_MODEL_FROM_DATABASE=3c905B Deluxe Etherlink 10/100/BNC [Cyclone] + +pci:v000010B7d0000905A* + ID_MODEL_FROM_DATABASE=3c905B-FX Fast Etherlink XL FX 100baseFx [Cyclone] + +pci:v000010B7d00009200* + ID_MODEL_FROM_DATABASE=3c905C-TX/TX-M [Tornado] + +pci:v000010B7d00009200sv00001028sd00000095* + ID_MODEL_FROM_DATABASE=3C920 Integrated Fast Ethernet Controller + +pci:v000010B7d00009200sv00001028sd00000097* + ID_MODEL_FROM_DATABASE=3C920 Integrated Fast Ethernet Controller + +pci:v000010B7d00009200sv00001028sd000000B4* + ID_MODEL_FROM_DATABASE=OptiPlex GX110 + +pci:v000010B7d00009200sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v000010B7d00009200sv00001028sd000000FE* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v000010B7d00009200sv00001028sd0000012A* + ID_MODEL_FROM_DATABASE=3C920 Integrated Fast Ethernet Controller [Latitude C640] + +pci:v000010B7d00009200sv000010B7sd00001000* + ID_MODEL_FROM_DATABASE=3C905CX-TX/TX-M Fast Etherlink for PC Management NIC + +pci:v000010B7d00009200sv000010B7sd00007000* + ID_MODEL_FROM_DATABASE=10/100 Mini PCI Ethernet Adapter + +pci:v000010B7d00009200sv000010F1sd00002466* + ID_MODEL_FROM_DATABASE=Tiger MPX S2466 (3C920 Integrated Fast Ethernet Controller) + +pci:v000010B7d00009200sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v000010B7d00009201* + ID_MODEL_FROM_DATABASE=3C920B-EMB Integrated Fast Ethernet Controller [Tornado] + +pci:v000010B7d00009201sv00001043sd000080AB* + ID_MODEL_FROM_DATABASE=A7N8X Deluxe onboard 3C920B-EMB Integrated Fast Ethernet Controller + +pci:v000010B7d00009202* + ID_MODEL_FROM_DATABASE=3Com 3C920B-EMB-WNM Integrated Fast Ethernet Controller + +pci:v000010B7d00009210* + ID_MODEL_FROM_DATABASE=3C920B-EMB-WNM Integrated Fast Ethernet Controller + +pci:v000010B7d00009300* + ID_MODEL_FROM_DATABASE=3CSOHO100B-TX 910-A01 [tulip] + +pci:v000010B7d00009800* + ID_MODEL_FROM_DATABASE=3c980-TX Fast Etherlink XL Server Adapter [Cyclone] + +pci:v000010B7d00009800sv000010B7sd00009800* + ID_MODEL_FROM_DATABASE=3c980-TX Fast Etherlink XL Server Adapter + +pci:v000010B7d00009805* + ID_MODEL_FROM_DATABASE=3c980-C 10/100baseTX NIC [Python-T] + +pci:v000010B7d00009805sv000010B7sd00001201* + ID_MODEL_FROM_DATABASE=EtherLink Server 10/100 Dual Port A + +pci:v000010B7d00009805sv000010B7sd00001202* + ID_MODEL_FROM_DATABASE=EtherLink Server 10/100 Dual Port B + +pci:v000010B7d00009805sv000010B7sd00009805* + ID_MODEL_FROM_DATABASE=3c980 10/100baseTX NIC [Python-T] + +pci:v000010B7d00009805sv000010F1sd00002462* + ID_MODEL_FROM_DATABASE=Thunder K7 S2462 + +pci:v000010B7d00009900* + ID_MODEL_FROM_DATABASE=3C990-TX [Typhoon] + +pci:v000010B7d00009902* + ID_MODEL_FROM_DATABASE=3CR990-TX-95 [Typhoon 56-bit] + +pci:v000010B7d00009903* + ID_MODEL_FROM_DATABASE=3CR990-TX-97 [Typhoon 168-bit] + +pci:v000010B7d00009904* + ID_MODEL_FROM_DATABASE=3C990B-TX-M/3C990BSVR [Typhoon2] + +pci:v000010B7d00009904sv000010B7sd00001000* + ID_MODEL_FROM_DATABASE=3CR990B-TX-M [Typhoon2] + +pci:v000010B7d00009904sv000010B7sd00002000* + ID_MODEL_FROM_DATABASE=3CR990BSVR [Typhoon2 Server] + +pci:v000010B7d00009905* + ID_MODEL_FROM_DATABASE=3CR990-FX-95/97/95 [Typhon Fiber] + +pci:v000010B7d00009905sv000010B7sd00001101* + ID_MODEL_FROM_DATABASE=3CR990-FX-95 [Typhoon Fiber 56-bit] + +pci:v000010B7d00009905sv000010B7sd00001102* + ID_MODEL_FROM_DATABASE=3CR990-FX-97 [Typhoon Fiber 168-bit] + +pci:v000010B7d00009905sv000010B7sd00002101* + ID_MODEL_FROM_DATABASE=3CR990-FX-95 Server [Typhoon Fiber 56-bit] + +pci:v000010B7d00009905sv000010B7sd00002102* + ID_MODEL_FROM_DATABASE=3CR990-FX-97 Server [Typhoon Fiber 168-bit] + +pci:v000010B7d00009908* + ID_MODEL_FROM_DATABASE=3CR990SVR95 [Typhoon Server 56-bit] + +pci:v000010B7d00009909* + ID_MODEL_FROM_DATABASE=3CR990SVR97 [Typhoon Server 168-bit] + +pci:v000010B7d0000990A* + ID_MODEL_FROM_DATABASE=3C990SVR [Typhoon Server] + +pci:v000010B7d0000990B* + ID_MODEL_FROM_DATABASE=3C990SVR [Typhoon Server] + +pci:v000010B8* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp [SMC] + +pci:v000010B8d00000005* + ID_MODEL_FROM_DATABASE=83c170 EPIC/100 Fast Ethernet Adapter + +pci:v000010B8d00000005sv00001055sd0000E000* + ID_MODEL_FROM_DATABASE=LANEPIC 10/100 [EVB171Q-PCI] + +pci:v000010B8d00000005sv00001055sd0000E002* + ID_MODEL_FROM_DATABASE=LANEPIC 10/100 [EVB171G-PCI] + +pci:v000010B8d00000005sv000010B8sd0000A011* + ID_MODEL_FROM_DATABASE=EtherPower II 10/100 + +pci:v000010B8d00000005sv000010B8sd0000A014* + ID_MODEL_FROM_DATABASE=EtherPower II 10/100 + +pci:v000010B8d00000005sv000010B8sd0000A015* + ID_MODEL_FROM_DATABASE=EtherPower II 10/100 + +pci:v000010B8d00000005sv000010B8sd0000A016* + ID_MODEL_FROM_DATABASE=EtherPower II 10/100 + +pci:v000010B8d00000005sv000010B8sd0000A017* + ID_MODEL_FROM_DATABASE=EtherPower II 10/100 + +pci:v000010B8d00000006* + ID_MODEL_FROM_DATABASE=83c175 EPIC/100 Fast Ethernet Adapter + +pci:v000010B8d00000006sv00001055sd0000E100* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv00001055sd0000E102* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv00001055sd0000E300* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv00001055sd0000E302* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv000010B8sd0000A012* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv000013A2sd00008002* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00000006sv000013A2sd00008006* + ID_MODEL_FROM_DATABASE=LANEPIC Cardbus Fast Ethernet Adapter + +pci:v000010B8d00001000* + ID_MODEL_FROM_DATABASE=FDC 37c665 + +pci:v000010B8d00001001* + ID_MODEL_FROM_DATABASE=FDC 37C922 + +pci:v000010B8d0000A011* + ID_MODEL_FROM_DATABASE=83C170QF + +pci:v000010B8d0000B106* + ID_MODEL_FROM_DATABASE=SMC34C90 + +pci:v000010B9* + ID_VENDOR_FROM_DATABASE=ULi Electronics Inc. + +pci:v000010B9d00000101* + ID_MODEL_FROM_DATABASE=CMI8338/C3DX PCI Audio Device + +pci:v000010B9d00000111* + ID_MODEL_FROM_DATABASE=C-Media CMI8738/C3DX Audio Device (OEM) + +pci:v000010B9d00000111sv000010B9sd00000111* + ID_MODEL_FROM_DATABASE=C-Media CMI8738/C3DX Audio Device (OEM) + +pci:v000010B9d00000780* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v000010B9d00000782* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v000010B9d00001435* + ID_MODEL_FROM_DATABASE=M1435 + +pci:v000010B9d00001445* + ID_MODEL_FROM_DATABASE=M1445 + +pci:v000010B9d00001449* + ID_MODEL_FROM_DATABASE=M1449 + +pci:v000010B9d00001451* + ID_MODEL_FROM_DATABASE=M1451 + +pci:v000010B9d00001461* + ID_MODEL_FROM_DATABASE=M1461 + +pci:v000010B9d00001489* + ID_MODEL_FROM_DATABASE=M1489 + +pci:v000010B9d00001511* + ID_MODEL_FROM_DATABASE=M1511 [Aladdin] + +pci:v000010B9d00001512* + ID_MODEL_FROM_DATABASE=M1512 [Aladdin] + +pci:v000010B9d00001513* + ID_MODEL_FROM_DATABASE=M1513 [Aladdin] + +pci:v000010B9d00001521* + ID_MODEL_FROM_DATABASE=M1521 [Aladdin III] + +pci:v000010B9d00001521sv000010B9sd00001521* + ID_MODEL_FROM_DATABASE=ALI M1521 Aladdin III CPU Bridge + +pci:v000010B9d00001523* + ID_MODEL_FROM_DATABASE=M1523 + +pci:v000010B9d00001523sv000010B9sd00001523* + ID_MODEL_FROM_DATABASE=ALI M1523 ISA Bridge + +pci:v000010B9d00001531* + ID_MODEL_FROM_DATABASE=M1531 [Aladdin IV] + +pci:v000010B9d00001533* + ID_MODEL_FROM_DATABASE=M1533/M1535/M1543 PCI to ISA Bridge [Aladdin IV/V/V+] + +pci:v000010B9d00001533sv00001014sd0000053B* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00001533sv000010B9sd00001533* + ID_MODEL_FROM_DATABASE=ALi M1533 Aladdin IV/V ISA Bridge + +pci:v000010B9d00001541* + ID_MODEL_FROM_DATABASE=M1541 + +pci:v000010B9d00001541sv000010B9sd00001541* + ID_MODEL_FROM_DATABASE=ALI M1541 Aladdin V/V+ AGP System Controller + +pci:v000010B9d00001543* + ID_MODEL_FROM_DATABASE=M1543 + +pci:v000010B9d00001563* + ID_MODEL_FROM_DATABASE=M1563 HyperTransport South Bridge + +pci:v000010B9d00001563sv000010B9sd00001563* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00001563sv00001849sd00001563* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00001573* + ID_MODEL_FROM_DATABASE=PCI to LPC Controller + +pci:v000010B9d00001575* + ID_MODEL_FROM_DATABASE=M1575 South Bridge + +pci:v000010B9d00001621* + ID_MODEL_FROM_DATABASE=M1621 + +pci:v000010B9d00001631* + ID_MODEL_FROM_DATABASE=ALI M1631 PCI North Bridge Aladdin Pro III + +pci:v000010B9d00001632* + ID_MODEL_FROM_DATABASE=M1632M Northbridge+Trident + +pci:v000010B9d00001641* + ID_MODEL_FROM_DATABASE=ALI M1641 PCI North Bridge Aladdin Pro IV + +pci:v000010B9d00001644* + ID_MODEL_FROM_DATABASE=M1644/M1644T Northbridge+Trident + +pci:v000010B9d00001646* + ID_MODEL_FROM_DATABASE=M1646 Northbridge+Trident + +pci:v000010B9d00001647* + ID_MODEL_FROM_DATABASE=M1647 Northbridge [MAGiK 1 / MobileMAGiK 1] + +pci:v000010B9d00001651* + ID_MODEL_FROM_DATABASE=M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM] + +pci:v000010B9d00001671* + ID_MODEL_FROM_DATABASE=M1671 Super P4 Northbridge [AGP4X,PCI and SDR/DDR] + +pci:v000010B9d00001672* + ID_MODEL_FROM_DATABASE=M1672 Northbridge [CyberALADDiN-P4] + +pci:v000010B9d00001681* + ID_MODEL_FROM_DATABASE=M1681 P4 Northbridge [AGP8X,HyperTransport and SDR/DDR] + +pci:v000010B9d00001687* + ID_MODEL_FROM_DATABASE=M1687 K8 Northbridge [AGP8X and HyperTransport] + +pci:v000010B9d00001689* + ID_MODEL_FROM_DATABASE=M1689 K8 Northbridge [Super K8 Single Chip] + +pci:v000010B9d00001695* + ID_MODEL_FROM_DATABASE=M1695 Host Bridge + +pci:v000010B9d00001697* + ID_MODEL_FROM_DATABASE=M1697 HTT Host Bridge + +pci:v000010B9d00003141* + ID_MODEL_FROM_DATABASE=M3141 + +pci:v000010B9d00003143* + ID_MODEL_FROM_DATABASE=M3143 + +pci:v000010B9d00003145* + ID_MODEL_FROM_DATABASE=M3145 + +pci:v000010B9d00003147* + ID_MODEL_FROM_DATABASE=M3147 + +pci:v000010B9d00003149* + ID_MODEL_FROM_DATABASE=M3149 + +pci:v000010B9d00003151* + ID_MODEL_FROM_DATABASE=M3151 + +pci:v000010B9d00003307* + ID_MODEL_FROM_DATABASE=M3307 + +pci:v000010B9d00003309* + ID_MODEL_FROM_DATABASE=M3309 + +pci:v000010B9d00003323* + ID_MODEL_FROM_DATABASE=M3325 Video/Audio Decoder + +pci:v000010B9d00005212* + ID_MODEL_FROM_DATABASE=M4803 + +pci:v000010B9d00005215* + ID_MODEL_FROM_DATABASE=MS4803 + +pci:v000010B9d00005217* + ID_MODEL_FROM_DATABASE=M5217H + +pci:v000010B9d00005219* + ID_MODEL_FROM_DATABASE=M5219 + +pci:v000010B9d00005225* + ID_MODEL_FROM_DATABASE=M5225 + +pci:v000010B9d00005228* + ID_MODEL_FROM_DATABASE=M5228 ALi ATA/RAID Controller + +pci:v000010B9d00005229* + ID_MODEL_FROM_DATABASE=M5229 IDE + +pci:v000010B9d00005229sv00001014sd0000050F* + ID_MODEL_FROM_DATABASE=ThinkPad R30 + +pci:v000010B9d00005229sv00001014sd0000053D* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00005229sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin IDE + +pci:v000010B9d00005229sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v000010B9d00005229sv00001043sd00008053* + ID_MODEL_FROM_DATABASE=A7A266 Motherboard IDE + +pci:v000010B9d00005229sv00001849sd00005229* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard IDE (PATA) + +pci:v000010B9d00005235* + ID_MODEL_FROM_DATABASE=M5225 + +pci:v000010B9d00005237* + ID_MODEL_FROM_DATABASE=USB 1.1 Controller + +pci:v000010B9d00005237sv00001014sd00000540* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00005237sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin USB + +pci:v000010B9d00005237sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v000010B9d00005237sv0000104Dsd0000810F* + ID_MODEL_FROM_DATABASE=VAIO PCG-U1 USB/OHCI Revision 1.0 + +pci:v000010B9d00005237sv000010B9sd00005237* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005237sv00001849sd00005237* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005239* + ID_MODEL_FROM_DATABASE=USB 2.0 Controller + +pci:v000010B9d00005239sv000010B9sd00005239* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005239sv00001849sd00005239* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005243* + ID_MODEL_FROM_DATABASE=M1541 PCI to AGP Controller + +pci:v000010B9d00005246* + ID_MODEL_FROM_DATABASE=AGP8X Controller + +pci:v000010B9d00005247* + ID_MODEL_FROM_DATABASE=PCI to AGP Controller + +pci:v000010B9d00005249* + ID_MODEL_FROM_DATABASE=M5249 HTT to PCI Bridge + +pci:v000010B9d0000524B* + ID_MODEL_FROM_DATABASE=PCI Express Root Port + +pci:v000010B9d0000524C* + ID_MODEL_FROM_DATABASE=PCI Express Root Port + +pci:v000010B9d0000524D* + ID_MODEL_FROM_DATABASE=PCI Express Root Port + +pci:v000010B9d0000524E* + ID_MODEL_FROM_DATABASE=PCI Express Root Port + +pci:v000010B9d00005251* + ID_MODEL_FROM_DATABASE=M5251 P1394 OHCI 1.0 Controller + +pci:v000010B9d00005253* + ID_MODEL_FROM_DATABASE=M5253 P1394 OHCI 1.1 Controller + +pci:v000010B9d00005261* + ID_MODEL_FROM_DATABASE=M5261 Ethernet Controller + +pci:v000010B9d00005263* + ID_MODEL_FROM_DATABASE=ULi 1689,1573 integrated ethernet. + +pci:v000010B9d00005281* + ID_MODEL_FROM_DATABASE=ALi M5281 Serial ATA / RAID Host Controller + +pci:v000010B9d00005287* + ID_MODEL_FROM_DATABASE=ULi 5287 SATA + +pci:v000010B9d00005288* + ID_MODEL_FROM_DATABASE=ULi M5288 SATA + +pci:v000010B9d00005288sv00001043sd00008056* + ID_MODEL_FROM_DATABASE=A8R-MVP Mainboard + +pci:v000010B9d00005289* + ID_MODEL_FROM_DATABASE=ULi 5289 SATA + +pci:v000010B9d00005450* + ID_MODEL_FROM_DATABASE=Lucent Technologies Soft Modem AMR + +pci:v000010B9d00005451* + ID_MODEL_FROM_DATABASE=M5451 PCI AC-Link Controller Audio Device + +pci:v000010B9d00005451sv00001014sd00000506* + ID_MODEL_FROM_DATABASE=ThinkPad R30 + +pci:v000010B9d00005451sv00001014sd0000053E* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00005451sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin Audio + +pci:v000010B9d00005451sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v000010B9d00005453* + ID_MODEL_FROM_DATABASE=M5453 PCI AC-Link Controller Modem Device + +pci:v000010B9d00005455* + ID_MODEL_FROM_DATABASE=M5455 PCI AC-Link Controller Audio Device + +pci:v000010B9d00005455sv000010B9sd00005455* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005455sv00001849sd00000850* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010B9d00005457* + ID_MODEL_FROM_DATABASE=M5457 AC'97 Modem Controller + +pci:v000010B9d00005457sv00001014sd00000535* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00005457sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 builtin Modem Device + +pci:v000010B9d00005457sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v000010B9d00005459* + ID_MODEL_FROM_DATABASE=SmartLink SmartPCI561 56K Modem + +pci:v000010B9d0000545A* + ID_MODEL_FROM_DATABASE=SmartLink SmartPCI563 56K Modem + +pci:v000010B9d00005461* + ID_MODEL_FROM_DATABASE=HD Audio Controller + +pci:v000010B9d00005471* + ID_MODEL_FROM_DATABASE=M5471 Memory Stick Controller + +pci:v000010B9d00005473* + ID_MODEL_FROM_DATABASE=M5473 SD-MMC Controller + +pci:v000010B9d00007101* + ID_MODEL_FROM_DATABASE=M7101 Power Management Controller [PMU] + +pci:v000010B9d00007101sv00001014sd00000510* + ID_MODEL_FROM_DATABASE=ThinkPad R30 + +pci:v000010B9d00007101sv00001014sd0000053C* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000010B9d00007101sv0000103Csd00000024* + ID_MODEL_FROM_DATABASE=Pavilion ze4400 + +pci:v000010B9d00007101sv0000103Csd00000025* + ID_MODEL_FROM_DATABASE=XE4500 Notebook + +pci:v000010B9d00007101sv00001849sd00007101* + ID_MODEL_FROM_DATABASE=ASRock 939Dual-SATA2 Motherboard + +pci:v000010BA* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Corp. + +pci:v000010BAd00000301* + ID_MODEL_FROM_DATABASE=AccelGraphics AccelECLIPSE + +pci:v000010BAd00000304* + ID_MODEL_FROM_DATABASE=AccelGALAXY A2100 [OEM Evans & Sutherland] + +pci:v000010BAd00000308* + ID_MODEL_FROM_DATABASE=Tornado 3000 [OEM Evans & Sutherland] + +pci:v000010BAd00000308sv000010DDsd00000024* + ID_MODEL_FROM_DATABASE=Tornado 3000 + +pci:v000010BAd00001002* + ID_MODEL_FROM_DATABASE=VG500 [VolumePro Volume Rendering Accelerator] + +pci:v000010BB* + ID_VENDOR_FROM_DATABASE=Dapha Electronics Corporation + +pci:v000010BC* + ID_VENDOR_FROM_DATABASE=Advanced Logic Research + +pci:v000010BD* + ID_VENDOR_FROM_DATABASE=Surecom Technology + +pci:v000010BDd00000E34* + ID_MODEL_FROM_DATABASE=NE-34 + +pci:v000010BE* + ID_VENDOR_FROM_DATABASE=Tseng Labs International Co. + +pci:v000010BF* + ID_VENDOR_FROM_DATABASE=Most Inc + +pci:v000010C0* + ID_VENDOR_FROM_DATABASE=Boca Research Inc. + +pci:v000010C1* + ID_VENDOR_FROM_DATABASE=ICM Co., Ltd. + +pci:v000010C2* + ID_VENDOR_FROM_DATABASE=Auspex Systems Inc. + +pci:v000010C3* + ID_VENDOR_FROM_DATABASE=Samsung Semiconductors, Inc. + +pci:v000010C4* + ID_VENDOR_FROM_DATABASE=Award Software International Inc. + +pci:v000010C5* + ID_VENDOR_FROM_DATABASE=Xerox Corporation + +pci:v000010C6* + ID_VENDOR_FROM_DATABASE=Rambus Inc. + +pci:v000010C7* + ID_VENDOR_FROM_DATABASE=Media Vision + +pci:v000010C8* + ID_VENDOR_FROM_DATABASE=Neomagic Corporation + +pci:v000010C8d00000001* + ID_MODEL_FROM_DATABASE=NM2070 [MagicGraph 128] + +pci:v000010C8d00000002* + ID_MODEL_FROM_DATABASE=NM2090 [MagicGraph 128V] + +pci:v000010C8d00000003* + ID_MODEL_FROM_DATABASE=NM2093 [MagicGraph 128ZV] + +pci:v000010C8d00000004* + ID_MODEL_FROM_DATABASE=NM2160 [MagicGraph 128XD] + +pci:v000010C8d00000004sv00001014sd000000BA* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001025sd00001007* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001028sd00000074* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001028sd00000075* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001028sd0000007D* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001028sd0000007E* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv00001033sd0000802F* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv0000104Dsd0000801B* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv0000104Dsd0000802F* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv0000104Dsd0000830B* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010BAsd00000E00* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010C8sd00000004* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010CFsd00001029* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010F7sd00008308* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010F7sd00008309* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010F7sd0000830B* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010F7sd0000830D* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000004sv000010F7sd00008312* + ID_MODEL_FROM_DATABASE=MagicGraph 128XD + +pci:v000010C8d00000005* + ID_MODEL_FROM_DATABASE=NM2200 [MagicGraph 256AV] + +pci:v000010C8d00000005sv00001014sd000000DD* + ID_MODEL_FROM_DATABASE=ThinkPad 570 + +pci:v000010C8d00000005sv00001028sd00000088* + ID_MODEL_FROM_DATABASE=Latitude CPi A + +pci:v000010C8d00000006* + ID_MODEL_FROM_DATABASE=NM2360 [MagicMedia 256ZX] + +pci:v000010C8d00000006sv00001014sd00000152* + ID_MODEL_FROM_DATABASE=ThinkPad 600X + +pci:v000010C8d00000016* + ID_MODEL_FROM_DATABASE=NM2380 [MagicMedia 256XL+] + +pci:v000010C8d00000016sv000010C8sd00000016* + ID_MODEL_FROM_DATABASE=MagicMedia 256XL+ + +pci:v000010C8d00000025* + ID_MODEL_FROM_DATABASE=NM2230 [MagicGraph 256AV+] + +pci:v000010C8d00000083* + ID_MODEL_FROM_DATABASE=NM2093 [MagicGraph 128ZV+] + +pci:v000010C8d00008005* + ID_MODEL_FROM_DATABASE=NM2200 [MagicMedia 256AV Audio] + +pci:v000010C8d00008005sv00000E11sd0000B0D1* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Discovery + +pci:v000010C8d00008005sv00000E11sd0000B126* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Durango + +pci:v000010C8d00008005sv00001014sd000000DD* + ID_MODEL_FROM_DATABASE=ThinkPad 390/i1720/i1721 + +pci:v000010C8d00008005sv00001025sd00001003* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on TravelMate 720 + +pci:v000010C8d00008005sv00001028sd00000088* + ID_MODEL_FROM_DATABASE=Latitude CPi A + +pci:v000010C8d00008005sv00001028sd0000008F* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Colorado Inspiron + +pci:v000010C8d00008005sv0000103Csd00000007* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Voyager II + +pci:v000010C8d00008005sv0000103Csd00000008* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Voyager III + +pci:v000010C8d00008005sv0000103Csd0000000D* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on Omnibook 900 + +pci:v000010C8d00008005sv000010C8sd00008005* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device on FireAnt + +pci:v000010C8d00008005sv0000110Asd00008005* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device + +pci:v000010C8d00008005sv000014C0sd00000004* + ID_MODEL_FROM_DATABASE=MagicMedia 256AV Audio Device + +pci:v000010C8d00008006* + ID_MODEL_FROM_DATABASE=NM2360 [MagicMedia 256ZX Audio] + +pci:v000010C8d00008016* + ID_MODEL_FROM_DATABASE=NM2380 [MagicMedia 256XL+ Audio] + +pci:v000010C9* + ID_VENDOR_FROM_DATABASE=Dataexpert Corporation + +pci:v000010CA* + ID_VENDOR_FROM_DATABASE=Fujitsu Microelectr., Inc. + +pci:v000010CB* + ID_VENDOR_FROM_DATABASE=Omron Corporation + +pci:v000010CC* + ID_VENDOR_FROM_DATABASE=Mai Logic Incorporated + +pci:v000010CCd00000660* + ID_MODEL_FROM_DATABASE=Articia S Host Bridge + +pci:v000010CCd00000661* + ID_MODEL_FROM_DATABASE=Articia S PCI Bridge + +pci:v000010CD* + ID_VENDOR_FROM_DATABASE=Advanced System Products, Inc + +pci:v000010CDd00001100* + ID_MODEL_FROM_DATABASE=ASC1100 + +pci:v000010CDd00001200* + ID_MODEL_FROM_DATABASE=ASC1200 [(abp940) Fast SCSI-II] + +pci:v000010CDd00001300* + ID_MODEL_FROM_DATABASE=ABP940-U / ABP960-U + +pci:v000010CDd00001300sv000010CDsd00001310* + ID_MODEL_FROM_DATABASE=ASC1300 SCSI Adapter + +pci:v000010CDd00001300sv00001195sd00001320* + ID_MODEL_FROM_DATABASE=Ultra-SCSI CardBus PC Card REX CB31 + +pci:v000010CDd00002300* + ID_MODEL_FROM_DATABASE=ABP940-UW + +pci:v000010CDd00002500* + ID_MODEL_FROM_DATABASE=ABP940-U2W + +pci:v000010CDd00002700* + ID_MODEL_FROM_DATABASE=ABP3950-U3W + +pci:v000010CE* + ID_VENDOR_FROM_DATABASE=Radius + +pci:v000010CF* + ID_VENDOR_FROM_DATABASE=Fujitsu Limited. + +pci:v000010CFd000001EF* + ID_MODEL_FROM_DATABASE=PCEA4 PCI-Express Dual Port ESCON Adapter + +pci:v000010CFd00001414* + ID_MODEL_FROM_DATABASE=On-board USB 1.1 companion controller + +pci:v000010CFd00001415* + ID_MODEL_FROM_DATABASE=On-board USB 2.0 EHCI controller + +pci:v000010CFd00001422* + ID_MODEL_FROM_DATABASE=E8410 nVidia graphics adapter + +pci:v000010CFd0000142D* + ID_MODEL_FROM_DATABASE=HD audio (Realtek ALC262) + +pci:v000010CFd00001430* + ID_MODEL_FROM_DATABASE=82566MM Intel 1Gb copper LAN interface + +pci:v000010CFd00001623* + ID_MODEL_FROM_DATABASE=PCEA4 PCI-Express Dual Port ESCON Adapter + +pci:v000010CFd00002001* + ID_MODEL_FROM_DATABASE=mb86605 + +pci:v000010CFd0000200C* + ID_MODEL_FROM_DATABASE=MB86613L IEEE1394 OHCI 1.0 Controller + +pci:v000010CFd00002010* + ID_MODEL_FROM_DATABASE=MB86613S IEEE1394 OHCI 1.1 Controller + +pci:v000010CFd00002019* + ID_MODEL_FROM_DATABASE=MB86295S [CORAL P] + +pci:v000010CFd0000201E* + ID_MODEL_FROM_DATABASE=MB86296S [CORAL PA] + +pci:v000010CFd0000202B* + ID_MODEL_FROM_DATABASE=MB86297A [Carmine Graphics Controller] + +pci:v000010D1* + ID_VENDOR_FROM_DATABASE=FuturePlus Systems Corp. + +pci:v000010D2* + ID_VENDOR_FROM_DATABASE=Molex Incorporated + +pci:v000010D3* + ID_VENDOR_FROM_DATABASE=Jabil Circuit Inc + +pci:v000010D4* + ID_VENDOR_FROM_DATABASE=Hualon Microelectronics + +pci:v000010D5* + ID_VENDOR_FROM_DATABASE=Autologic Inc. + +pci:v000010D6* + ID_VENDOR_FROM_DATABASE=Cetia + +pci:v000010D7* + ID_VENDOR_FROM_DATABASE=BCM Advanced Research + +pci:v000010D8* + ID_VENDOR_FROM_DATABASE=Advanced Peripherals Labs + +pci:v000010D9* + ID_VENDOR_FROM_DATABASE=Macronix, Inc. [MXIC] + +pci:v000010D9d00000431* + ID_MODEL_FROM_DATABASE=MX98715 + +pci:v000010D9d00000512* + ID_MODEL_FROM_DATABASE=MX98713 + +pci:v000010D9d00000531* + ID_MODEL_FROM_DATABASE=MX987x5 + +pci:v000010D9d00000531sv00001186sd00001200* + ID_MODEL_FROM_DATABASE=DFE-540TX ProFAST 10/100 Adapter + +pci:v000010D9d00008625* + ID_MODEL_FROM_DATABASE=MX86250 + +pci:v000010D9d00008626* + ID_MODEL_FROM_DATABASE=Macronix MX86251 + 3Dfx Voodoo Rush + +pci:v000010D9d00008888* + ID_MODEL_FROM_DATABASE=MX86200 + +pci:v000010DA* + ID_VENDOR_FROM_DATABASE=Compaq IPG-Austin + +pci:v000010DAd00000508* + ID_MODEL_FROM_DATABASE=TC4048 Token Ring 4/16 + +pci:v000010DAd00003390* + ID_MODEL_FROM_DATABASE=Tl3c3x9 + +pci:v000010DB* + ID_VENDOR_FROM_DATABASE=Rohm LSI Systems, Inc. + +pci:v000010DC* + ID_VENDOR_FROM_DATABASE=CERN/ECP/EDU + +pci:v000010DCd00000001* + ID_MODEL_FROM_DATABASE=STAR/RD24 SCI-PCI (PMC) + +pci:v000010DCd00000002* + ID_MODEL_FROM_DATABASE=TAR/RD24 SCI-PCI (PMC) + +pci:v000010DCd00000021* + ID_MODEL_FROM_DATABASE=HIPPI destination + +pci:v000010DCd00000022* + ID_MODEL_FROM_DATABASE=HIPPI source + +pci:v000010DCd000010DC* + ID_MODEL_FROM_DATABASE=ATT2C15-3 FPGA + +pci:v000010DD* + ID_VENDOR_FROM_DATABASE=Evans & Sutherland + +pci:v000010DDd00000100* + ID_MODEL_FROM_DATABASE=Lightning 1200 + +pci:v000010DDd00000100sv000010DDsd00000023* + ID_MODEL_FROM_DATABASE=Lightning 1200 15+16M + +pci:v000010DE* + ID_VENDOR_FROM_DATABASE=NVIDIA Corporation + +pci:v000010DEd00000008* + ID_MODEL_FROM_DATABASE=NV1 [EDGE 3D] + +pci:v000010DEd00000009* + ID_MODEL_FROM_DATABASE=NV1 [EDGE 3D] + +pci:v000010DEd00000020* + ID_MODEL_FROM_DATABASE=NV4 [Riva TNT] + +pci:v000010DEd00000020sv00001043sd00000200* + ID_MODEL_FROM_DATABASE=V3400 TNT + +pci:v000010DEd00000020sv00001048sd00000C18* + ID_MODEL_FROM_DATABASE=Erazor II SGRAM + +pci:v000010DEd00000020sv00001048sd00000C19* + ID_MODEL_FROM_DATABASE=Erazor II + +pci:v000010DEd00000020sv00001048sd00000C1B* + ID_MODEL_FROM_DATABASE=Erazor II + +pci:v000010DEd00000020sv00001048sd00000C1C* + ID_MODEL_FROM_DATABASE=Erazor II + +pci:v000010DEd00000020sv00001092sd00000550* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00000552* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004804* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004808* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004810* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004812* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004815* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004820* + ID_MODEL_FROM_DATABASE=Viper V550 with TV out + +pci:v000010DEd00000020sv00001092sd00004822* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004904* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00004914* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv00001092sd00008225* + ID_MODEL_FROM_DATABASE=Viper V550 + +pci:v000010DEd00000020sv000010B4sd0000273D* + ID_MODEL_FROM_DATABASE=Velocity 4400 + +pci:v000010DEd00000020sv000010B4sd0000273E* + ID_MODEL_FROM_DATABASE=Velocity 4400 + +pci:v000010DEd00000020sv000010B4sd00002740* + ID_MODEL_FROM_DATABASE=Velocity 4400 + +pci:v000010DEd00000020sv000010DEsd00000020* + ID_MODEL_FROM_DATABASE=Riva TNT + +pci:v000010DEd00000020sv00001102sd00001015* + ID_MODEL_FROM_DATABASE=Graphics Blaster CT6710 + +pci:v000010DEd00000020sv00001102sd00001016* + ID_MODEL_FROM_DATABASE=Graphics Blaster RIVA TNT + +pci:v000010DEd00000028* + ID_MODEL_FROM_DATABASE=NV5 [Riva TNT2 / TNT2 Pro] + +pci:v000010DEd00000028sv00001043sd00000200* + ID_MODEL_FROM_DATABASE=AGP-V3800 SGRAM + +pci:v000010DEd00000028sv00001043sd00000201* + ID_MODEL_FROM_DATABASE=AGP-V3800 SDRAM + +pci:v000010DEd00000028sv00001043sd00000205* + ID_MODEL_FROM_DATABASE=PCI-V3800 + +pci:v000010DEd00000028sv00001043sd00004000* + ID_MODEL_FROM_DATABASE=AGP-V3800PRO + +pci:v000010DEd00000028sv00001048sd00000C21* + ID_MODEL_FROM_DATABASE=Synergy II + +pci:v000010DEd00000028sv00001048sd00000C28* + ID_MODEL_FROM_DATABASE=Erazor III + +pci:v000010DEd00000028sv00001048sd00000C29* + ID_MODEL_FROM_DATABASE=Erazor III + +pci:v000010DEd00000028sv00001048sd00000C2A* + ID_MODEL_FROM_DATABASE=Erazor III + +pci:v000010DEd00000028sv00001048sd00000C2B* + ID_MODEL_FROM_DATABASE=Erazor III + +pci:v000010DEd00000028sv00001048sd00000C31* + ID_MODEL_FROM_DATABASE=Erazor III Pro + +pci:v000010DEd00000028sv00001048sd00000C32* + ID_MODEL_FROM_DATABASE=Erazor III Pro + +pci:v000010DEd00000028sv00001048sd00000C33* + ID_MODEL_FROM_DATABASE=Erazor III Pro + +pci:v000010DEd00000028sv00001048sd00000C34* + ID_MODEL_FROM_DATABASE=Erazor III Pro + +pci:v000010DEd00000028sv0000107Dsd00002134* + ID_MODEL_FROM_DATABASE=WinFast 3D S320 II + TV-Out + +pci:v000010DEd00000028sv00001092sd00004804* + ID_MODEL_FROM_DATABASE=Viper V770 + +pci:v000010DEd00000028sv00001092sd00004A00* + ID_MODEL_FROM_DATABASE=Viper V770 + +pci:v000010DEd00000028sv00001092sd00004A02* + ID_MODEL_FROM_DATABASE=Viper V770 Ultra + +pci:v000010DEd00000028sv00001092sd00005A00* + ID_MODEL_FROM_DATABASE=RIVA TNT2/TNT2 Pro + +pci:v000010DEd00000028sv00001092sd00005A40* + ID_MODEL_FROM_DATABASE=Viper V770D AGP + +pci:v000010DEd00000028sv00001092sd00006A02* + ID_MODEL_FROM_DATABASE=Viper V770 Ultra + +pci:v000010DEd00000028sv00001092sd00007A02* + ID_MODEL_FROM_DATABASE=Viper V770 Ultra + +pci:v000010DEd00000028sv000010DEsd00000005* + ID_MODEL_FROM_DATABASE=RIVA TNT2 Pro + +pci:v000010DEd00000028sv000010DEsd0000000F* + ID_MODEL_FROM_DATABASE=Compaq NVIDIA TNT2 Pro + +pci:v000010DEd00000028sv00001102sd00001020* + ID_MODEL_FROM_DATABASE=3D Blaster RIVA TNT2 + +pci:v000010DEd00000028sv00001102sd00001026* + ID_MODEL_FROM_DATABASE=3D Blaster RIVA TNT2 Digital + +pci:v000010DEd00000028sv00001462sd00008806* + ID_MODEL_FROM_DATABASE=MS-8806 AGPhantom Graphics Card + +pci:v000010DEd00000028sv000014AFsd00005810* + ID_MODEL_FROM_DATABASE=Maxi Gamer Xentor + +pci:v000010DEd00000029* + ID_MODEL_FROM_DATABASE=NV5 [Riva TNT2 Ultra] + +pci:v000010DEd00000029sv00001043sd00000200* + ID_MODEL_FROM_DATABASE=AGP-V3800 Deluxe + +pci:v000010DEd00000029sv00001043sd00000201* + ID_MODEL_FROM_DATABASE=AGP-V3800 Ultra SDRAM + +pci:v000010DEd00000029sv00001043sd00000205* + ID_MODEL_FROM_DATABASE=PCI-V3800 Ultra + +pci:v000010DEd00000029sv00001048sd00000C2E* + ID_MODEL_FROM_DATABASE=Erazor III Ultra + +pci:v000010DEd00000029sv00001048sd00000C2F* + ID_MODEL_FROM_DATABASE=Erazor III Ultra + +pci:v000010DEd00000029sv00001048sd00000C30* + ID_MODEL_FROM_DATABASE=Erazor III Ultra + +pci:v000010DEd00000029sv00001102sd00001021* + ID_MODEL_FROM_DATABASE=3D Blaster RIVA TNT2 Ultra + +pci:v000010DEd00000029sv00001102sd00001029* + ID_MODEL_FROM_DATABASE=3D Blaster RIVA TNT2 Ultra + +pci:v000010DEd00000029sv00001102sd0000102F* + ID_MODEL_FROM_DATABASE=3D Blaster RIVA TNT2 Ultra + +pci:v000010DEd00000029sv000014AFsd00005820* + ID_MODEL_FROM_DATABASE=Maxi Gamer Xentor 32 + +pci:v000010DEd00000029sv00004843sd00004F34* + ID_MODEL_FROM_DATABASE=Dynamite + +pci:v000010DEd0000002A* + ID_MODEL_FROM_DATABASE=NV5 [Riva TNT2] + +pci:v000010DEd0000002B* + ID_MODEL_FROM_DATABASE=NV5 [Riva TNT2] + +pci:v000010DEd0000002C* + ID_MODEL_FROM_DATABASE=NV5 [Vanta / Vanta LT] + +pci:v000010DEd0000002Csv00001043sd00000200* + ID_MODEL_FROM_DATABASE=AGP-V3800 Combat SDRAM + +pci:v000010DEd0000002Csv00001043sd00000201* + ID_MODEL_FROM_DATABASE=AGP-V3800 Combat + +pci:v000010DEd0000002Csv00001048sd00000C20* + ID_MODEL_FROM_DATABASE=TNT2 Vanta + +pci:v000010DEd0000002Csv00001048sd00000C21* + ID_MODEL_FROM_DATABASE=TNT2 Vanta + +pci:v000010DEd0000002Csv00001048sd00000C25* + ID_MODEL_FROM_DATABASE=TNT2 Vanta 16MB + +pci:v000010DEd0000002Csv00001092sd00006820* + ID_MODEL_FROM_DATABASE=Viper V730 + +pci:v000010DEd0000002Csv00001102sd00001031* + ID_MODEL_FROM_DATABASE=CT6938 VANTA 8MB + +pci:v000010DEd0000002Csv00001102sd00001034* + ID_MODEL_FROM_DATABASE=CT6894 VANTA 16MB + +pci:v000010DEd0000002Csv000014AFsd00005008* + ID_MODEL_FROM_DATABASE=Maxi Gamer Phoenix 2 + +pci:v000010DEd0000002D* + ID_MODEL_FROM_DATABASE=NV5 [Riva TNT2 Model 64 / Model 64 Pro] + +pci:v000010DEd0000002Dsv00001043sd00000200* + ID_MODEL_FROM_DATABASE=AGP-V3800M + +pci:v000010DEd0000002Dsv00001043sd00000201* + ID_MODEL_FROM_DATABASE=AGP-V3800M + +pci:v000010DEd0000002Dsv00001048sd00000C3A* + ID_MODEL_FROM_DATABASE=Erazor III LT + +pci:v000010DEd0000002Dsv00001048sd00000C3B* + ID_MODEL_FROM_DATABASE=Erazor III LT + +pci:v000010DEd0000002Dsv0000107Dsd00002137* + ID_MODEL_FROM_DATABASE=WinFast 3D S325 + +pci:v000010DEd0000002Dsv000010DEsd00000006* + ID_MODEL_FROM_DATABASE=RIVA TNT2 Model 64/Model 64 Pro + +pci:v000010DEd0000002Dsv000010DEsd0000001E* + ID_MODEL_FROM_DATABASE=M64 AGP4x + +pci:v000010DEd0000002Dsv00001102sd00001023* + ID_MODEL_FROM_DATABASE=CT6892 RIVA TNT2 Value + +pci:v000010DEd0000002Dsv00001102sd00001024* + ID_MODEL_FROM_DATABASE=CT6932 RIVA TNT2 Value 32Mb + +pci:v000010DEd0000002Dsv00001102sd0000102C* + ID_MODEL_FROM_DATABASE=CT6931 RIVA TNT2 Value [Jumper] + +pci:v000010DEd0000002Dsv00001102sd00001030* + ID_MODEL_FROM_DATABASE=CT6931 RIVA TNT2 Value + +pci:v000010DEd0000002Dsv0000110Asd0000006F* + ID_MODEL_FROM_DATABASE=GM1000-16 + +pci:v000010DEd0000002Dsv0000110Asd00000081* + ID_MODEL_FROM_DATABASE=GM1000-16 + +pci:v000010DEd0000002Dsv00001462sd00008808* + ID_MODEL_FROM_DATABASE=MSI-8808 + +pci:v000010DEd0000002Dsv000014AFsd00005620* + ID_MODEL_FROM_DATABASE=Gamer Cougar Video Edition + +pci:v000010DEd0000002Dsv00001554sd00001041* + ID_MODEL_FROM_DATABASE=Pixelview RIVA TNT2 M64 + +pci:v000010DEd0000002Dsv00001569sd0000002D* + ID_MODEL_FROM_DATABASE=Palit Microsystems Daytona TNT2 M64 + +pci:v000010DEd00000034* + ID_MODEL_FROM_DATABASE=MCP04 SMBus + +pci:v000010DEd00000035* + ID_MODEL_FROM_DATABASE=MCP04 IDE + +pci:v000010DEd00000036* + ID_MODEL_FROM_DATABASE=MCP04 Serial ATA Controller + +pci:v000010DEd00000037* + ID_MODEL_FROM_DATABASE=MCP04 Ethernet Controller + +pci:v000010DEd00000038* + ID_MODEL_FROM_DATABASE=MCP04 Ethernet Controller + +pci:v000010DEd0000003A* + ID_MODEL_FROM_DATABASE=MCP04 AC'97 Audio Controller + +pci:v000010DEd0000003B* + ID_MODEL_FROM_DATABASE=MCP04 USB Controller + +pci:v000010DEd0000003C* + ID_MODEL_FROM_DATABASE=MCP04 USB Controller + +pci:v000010DEd0000003D* + ID_MODEL_FROM_DATABASE=MCP04 PCI Bridge + +pci:v000010DEd0000003E* + ID_MODEL_FROM_DATABASE=MCP04 Serial ATA Controller + +pci:v000010DEd00000040* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 Ultra] + +pci:v000010DEd00000041* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800] + +pci:v000010DEd00000041sv00001043sd0000817B* + ID_MODEL_FROM_DATABASE=V9999 Gamer Edition + +pci:v000010DEd00000041sv0000107Dsd00002992* + ID_MODEL_FROM_DATABASE=WinFast A400 + +pci:v000010DEd00000041sv00001458sd0000310F* + ID_MODEL_FROM_DATABASE=Geforce 6800 GV-N6812 + +pci:v000010DEd00000042* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 LE] + +pci:v000010DEd00000042sv0000107Dsd0000299B* + ID_MODEL_FROM_DATABASE=WinFast A400 LE + +pci:v000010DEd00000043* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 XE] + +pci:v000010DEd00000044* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 XT] + +pci:v000010DEd00000045* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 GT] + +pci:v000010DEd00000045sv00001043sd0000817D* + ID_MODEL_FROM_DATABASE=V9999GT + +pci:v000010DEd00000045sv00001458sd00003140* + ID_MODEL_FROM_DATABASE=GV-N68T256D + +pci:v000010DEd00000047* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 GS] + +pci:v000010DEd00000047sv00001682sd00002109* + ID_MODEL_FROM_DATABASE=GeForce 6800 GS + +pci:v000010DEd00000048* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 XT] + +pci:v000010DEd0000004E* + ID_MODEL_FROM_DATABASE=NV40GL [Quadro FX 4000] + +pci:v000010DEd00000050* + ID_MODEL_FROM_DATABASE=CK804 ISA Bridge + +pci:v000010DEd00000050sv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000050sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000050sv00001458sd00000C11* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000050sv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd00000050sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000050sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000050sv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000051* + ID_MODEL_FROM_DATABASE=CK804 ISA Bridge + +pci:v000010DEd00000051sv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 ISA Bridge + +pci:v000010DEd00000052* + ID_MODEL_FROM_DATABASE=CK804 SMBus + +pci:v000010DEd00000052sv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 SMBus + +pci:v000010DEd00000052sv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000052sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000052sv00001458sd00000C11* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000052sv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd00000052sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000052sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000052sv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000053* + ID_MODEL_FROM_DATABASE=CK804 IDE + +pci:v000010DEd00000053sv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000053sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000053sv00001458sd00005002* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000053sv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd00000053sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000053sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000053sv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000054* + ID_MODEL_FROM_DATABASE=CK804 Serial ATA Controller + +pci:v000010DEd00000054sv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 Serial ATA + +pci:v000010DEd00000054sv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=A8N Series Mainboard + +pci:v000010DEd00000054sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000054sv00001458sd0000B003* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000054sv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd00000054sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000054sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000054sv00001565sd00005401* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000055* + ID_MODEL_FROM_DATABASE=CK804 Serial ATA Controller + +pci:v000010DEd00000055sv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 Serial ATA + +pci:v000010DEd00000055sv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000055sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000055sv00001458sd0000B003* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000055sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000055sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000055sv00001565sd00005401* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000056* + ID_MODEL_FROM_DATABASE=CK804 Ethernet Controller + +pci:v000010DEd00000057* + ID_MODEL_FROM_DATABASE=CK804 Ethernet Controller + +pci:v000010DEd00000057sv00001043sd00008141* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000057sv000010DEsd0000CB84* + ID_MODEL_FROM_DATABASE=NF4 Lanparty + +pci:v000010DEd00000057sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000057sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd00000057sv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd00000057sv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000057sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000057sv00001565sd00002501* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd00000058* + ID_MODEL_FROM_DATABASE=CK804 AC'97 Modem + +pci:v000010DEd00000059* + ID_MODEL_FROM_DATABASE=CK804 AC'97 Audio Controller + +pci:v000010DEd00000059sv00001043sd0000812A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd00000059sv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd00000059sv00001462sd00007585* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd00000059sv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd00000059sv00001565sd00008211* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd0000005A* + ID_MODEL_FROM_DATABASE=CK804 USB Controller + +pci:v000010DEd0000005Asv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 onboard USB + +pci:v000010DEd0000005Asv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd0000005Asv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd0000005Asv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd0000005Asv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd0000005Asv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd0000005Asv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd0000005Asv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd0000005B* + ID_MODEL_FROM_DATABASE=CK804 USB Controller + +pci:v000010DEd0000005Bsv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 onboard USB + +pci:v000010DEd0000005Bsv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=K8N4/A8N Series Mainboard + +pci:v000010DEd0000005Bsv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd0000005Bsv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd0000005Bsv00001462sd00007100* + ID_MODEL_FROM_DATABASE=MSI K8N Diamond + +pci:v000010DEd0000005Bsv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F mainboard + +pci:v000010DEd0000005Bsv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd0000005Bsv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd0000005C* + ID_MODEL_FROM_DATABASE=CK804 PCI Bridge + +pci:v000010DEd0000005D* + ID_MODEL_FROM_DATABASE=CK804 PCIE Bridge + +pci:v000010DEd0000005E* + ID_MODEL_FROM_DATABASE=CK804 Memory Controller + +pci:v000010DEd0000005Esv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 Memory Controller + +pci:v000010DEd0000005Esv00001043sd0000815A* + ID_MODEL_FROM_DATABASE=A8N Series Mainboard + +pci:v000010DEd0000005Esv000010DEsd0000005E* + ID_MODEL_FROM_DATABASE=ECS Elitegroup NFORCE3-A939 motherboard. + +pci:v000010DEd0000005Esv000010F1sd00002865* + ID_MODEL_FROM_DATABASE=Tomcat K8E (S2865) + +pci:v000010DEd0000005Esv000010F1sd00002891* + ID_MODEL_FROM_DATABASE=Thunder K8SRE Mainboard + +pci:v000010DEd0000005Esv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-K8N Ultra-9 Mainboard + +pci:v000010DEd0000005Esv00001462sd00007100* + ID_MODEL_FROM_DATABASE=K8N Diamond Mainboard + +pci:v000010DEd0000005Esv00001462sd00007125* + ID_MODEL_FROM_DATABASE=K8N Neo4-F Mainboard + +pci:v000010DEd0000005Esv0000147Bsd00001C1A* + ID_MODEL_FROM_DATABASE=KN8-Ultra Mainboard + +pci:v000010DEd0000005Esv00001565sd00003402* + ID_MODEL_FROM_DATABASE=NF4 AM2L Mainboard + +pci:v000010DEd0000005F* + ID_MODEL_FROM_DATABASE=CK804 Memory Controller + +pci:v000010DEd00000060* + ID_MODEL_FROM_DATABASE=nForce2 ISA Bridge + +pci:v000010DEd00000060sv00001043sd000080AD* + ID_MODEL_FROM_DATABASE=A7N8X Mainboard + +pci:v000010DEd00000060sv0000147Bsd00001C02* + ID_MODEL_FROM_DATABASE=NF7-S/NF7 (nVidia-nForce2) 2.X + +pci:v000010DEd00000060sv0000A0A0sd000003BA* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000064* + ID_MODEL_FROM_DATABASE=nForce2 SMBus (MCP) + +pci:v000010DEd00000064sv0000147Bsd00001C02* + ID_MODEL_FROM_DATABASE=NF7-S/NF7 (nVidia-nForce2) 2.X + +pci:v000010DEd00000064sv0000A0A0sd000003BB* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000065* + ID_MODEL_FROM_DATABASE=nForce2 IDE + +pci:v000010DEd00000065sv000010DEsd00000C11* + ID_MODEL_FROM_DATABASE=nForce 2 EIDE Controller + +pci:v000010DEd00000065sv0000A0A0sd000003B2* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000066* + ID_MODEL_FROM_DATABASE=nForce2 Ethernet Controller + +pci:v000010DEd00000066sv00001043sd000080A7* + ID_MODEL_FROM_DATABASE=A7N8X Mainboard onboard nForce2 Ethernet + +pci:v000010DEd00000066sv000010DEsd00000C11* + ID_MODEL_FROM_DATABASE=nForce MCP-T Networking Adapter + +pci:v000010DEd00000066sv0000A0A0sd000003B3* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000067* + ID_MODEL_FROM_DATABASE=nForce2 USB Controller + +pci:v000010DEd00000067sv00001043sd00000C11* + ID_MODEL_FROM_DATABASE=A7N8X Mainboard + +pci:v000010DEd00000067sv0000A0A0sd000003B4* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000068* + ID_MODEL_FROM_DATABASE=nForce2 USB Controller + +pci:v000010DEd00000068sv00001043sd00000C11* + ID_MODEL_FROM_DATABASE=A7N8X Mainboard + +pci:v000010DEd00000068sv0000A0A0sd000003B4* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd0000006A* + ID_MODEL_FROM_DATABASE=nForce2 AC97 Audio Controler (MCP) + +pci:v000010DEd0000006Asv00001043sd00008095* + ID_MODEL_FROM_DATABASE=nForce2 AC97 Audio Controler (MCP) + +pci:v000010DEd0000006Asv0000A0A0sd00000304* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd0000006B* + ID_MODEL_FROM_DATABASE=nForce Audio Processing Unit + +pci:v000010DEd0000006Bsv000010DEsd0000006B* + ID_MODEL_FROM_DATABASE=nForce2 MCP Audio Processing Unit + +pci:v000010DEd0000006Bsv0000A0A0sd00000304* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd0000006C* + ID_MODEL_FROM_DATABASE=nForce2 External PCI Bridge + +pci:v000010DEd0000006D* + ID_MODEL_FROM_DATABASE=nForce2 PCI Bridge + +pci:v000010DEd0000006E* + ID_MODEL_FROM_DATABASE=nForce2 FireWire (IEEE 1394) Controller + +pci:v000010DEd0000006Esv0000A0A0sd00000306* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000080* + ID_MODEL_FROM_DATABASE=MCP2A ISA bridge + +pci:v000010DEd00000080sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd00000084* + ID_MODEL_FROM_DATABASE=MCP2A SMBus + +pci:v000010DEd00000084sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd00000085* + ID_MODEL_FROM_DATABASE=MCP2A IDE + +pci:v000010DEd00000085sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd00000086* + ID_MODEL_FROM_DATABASE=MCP2A Ethernet Controller + +pci:v000010DEd00000087* + ID_MODEL_FROM_DATABASE=MCP2A USB Controller + +pci:v000010DEd00000087sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd00000088* + ID_MODEL_FROM_DATABASE=MCP2A USB Controller + +pci:v000010DEd00000088sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd0000008A* + ID_MODEL_FROM_DATABASE=MCP2S AC'97 Audio Controller + +pci:v000010DEd0000008Asv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd0000008B* + ID_MODEL_FROM_DATABASE=MCP2A PCI Bridge + +pci:v000010DEd0000008C* + ID_MODEL_FROM_DATABASE=MCP2A Ethernet Controller + +pci:v000010DEd0000008E* + ID_MODEL_FROM_DATABASE=nForce2 Serial ATA Controller + +pci:v000010DEd00000090* + ID_MODEL_FROM_DATABASE=G70 [GeForce 7800 GTX] + +pci:v000010DEd00000091* + ID_MODEL_FROM_DATABASE=G70 [GeForce 7800 GTX] + +pci:v000010DEd00000092* + ID_MODEL_FROM_DATABASE=G70 [GeForce 7800 GT] + +pci:v000010DEd00000093* + ID_MODEL_FROM_DATABASE=G70 [GeForce 7800 GS] + +pci:v000010DEd00000095* + ID_MODEL_FROM_DATABASE=G70 [GeForce 7800 SLI] + +pci:v000010DEd00000097* + ID_MODEL_FROM_DATABASE=G70 [GeForce GTS 250] + +pci:v000010DEd00000098* + ID_MODEL_FROM_DATABASE=G70M [GeForce Go 7800] + +pci:v000010DEd00000099* + ID_MODEL_FROM_DATABASE=G70M [GeForce Go 7800 GTX] + +pci:v000010DEd0000009D* + ID_MODEL_FROM_DATABASE=G70GL [Quadro FX 4500] + +pci:v000010DEd000000A0* + ID_MODEL_FROM_DATABASE=NV5 [Aladdin TNT2] + +pci:v000010DEd000000A0sv000014AFsd00005810* + ID_MODEL_FROM_DATABASE=Maxi Gamer Xentor + +pci:v000010DEd000000C0* + ID_MODEL_FROM_DATABASE=NV41 [GeForce 6800 GS] + +pci:v000010DEd000000C1* + ID_MODEL_FROM_DATABASE=NV41 [GeForce 6800] + +pci:v000010DEd000000C2* + ID_MODEL_FROM_DATABASE=NV41 [GeForce 6800 LE] + +pci:v000010DEd000000C3* + ID_MODEL_FROM_DATABASE=NV41 [GeForce 6800 XT] + +pci:v000010DEd000000C5* + ID_MODEL_FROM_DATABASE=NV41 + +pci:v000010DEd000000C6* + ID_MODEL_FROM_DATABASE=NV41 + +pci:v000010DEd000000C7* + ID_MODEL_FROM_DATABASE=NV41 + +pci:v000010DEd000000C8* + ID_MODEL_FROM_DATABASE=NV41M [GeForce Go 6800] + +pci:v000010DEd000000C9* + ID_MODEL_FROM_DATABASE=NV41M [GeForce Go 6800 Ultra] + +pci:v000010DEd000000CC* + ID_MODEL_FROM_DATABASE=NV41GLM [Quadro FX Go1400] + +pci:v000010DEd000000CD* + ID_MODEL_FROM_DATABASE=NV41GL [Quadro FX 3450/4000 SDI] + +pci:v000010DEd000000CDsv000010DEsd0000029B* + ID_MODEL_FROM_DATABASE=wx4300 Workstation + +pci:v000010DEd000000CE* + ID_MODEL_FROM_DATABASE=NV41GL [Quadro FX 1400] + +pci:v000010DEd000000CF* + ID_MODEL_FROM_DATABASE=NV41 + +pci:v000010DEd000000D0* + ID_MODEL_FROM_DATABASE=nForce3 LPC Bridge + +pci:v000010DEd000000D1* + ID_MODEL_FROM_DATABASE=nForce3 Host Bridge + +pci:v000010DEd000000D2* + ID_MODEL_FROM_DATABASE=nForce3 AGP Bridge + +pci:v000010DEd000000D3* + ID_MODEL_FROM_DATABASE=CK804 Memory Controller + +pci:v000010DEd000000D4* + ID_MODEL_FROM_DATABASE=nForce3 SMBus + +pci:v000010DEd000000D5* + ID_MODEL_FROM_DATABASE=nForce3 IDE + +pci:v000010DEd000000D6* + ID_MODEL_FROM_DATABASE=nForce3 Ethernet + +pci:v000010DEd000000D7* + ID_MODEL_FROM_DATABASE=nForce3 USB 1.1 + +pci:v000010DEd000000D8* + ID_MODEL_FROM_DATABASE=nForce3 USB 2.0 + +pci:v000010DEd000000D9* + ID_MODEL_FROM_DATABASE=nForce3 Audio + +pci:v000010DEd000000DA* + ID_MODEL_FROM_DATABASE=nForce3 Audio + +pci:v000010DEd000000DD* + ID_MODEL_FROM_DATABASE=nForce3 PCI Bridge + +pci:v000010DEd000000DF* + ID_MODEL_FROM_DATABASE=CK8S Ethernet Controller + +pci:v000010DEd000000DFsv00001043sd000080A7* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000DFsv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000DFsv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E0* + ID_MODEL_FROM_DATABASE=nForce3 250Gb LPC Bridge + +pci:v000010DEd000000E0sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E0sv000010DEsd00000C11* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E0sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E0sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E0sv00001849sd000000E0* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E1* + ID_MODEL_FROM_DATABASE=nForce3 250Gb Host Bridge + +pci:v000010DEd000000E1sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E1sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E1sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E1sv00001849sd000000E1* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E2* + ID_MODEL_FROM_DATABASE=nForce3 250Gb AGP Host to PCI Bridge + +pci:v000010DEd000000E3* + ID_MODEL_FROM_DATABASE=nForce3 Serial ATA Controller + +pci:v000010DEd000000E3sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E3sv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E3sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E3sv00001849sd000000E3* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E4* + ID_MODEL_FROM_DATABASE=nForce 250Gb PCI System Management + +pci:v000010DEd000000E4sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E4sv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E4sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E4sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E4sv00001849sd000000E4* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E5* + ID_MODEL_FROM_DATABASE=CK8S Parallel ATA Controller (v2.5) + +pci:v000010DEd000000E5sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E5sv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E5sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E5sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E5sv00001849sd000000E5* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E5sv0000F849sd000000E5* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E6* + ID_MODEL_FROM_DATABASE=CK8S Ethernet Controller + +pci:v000010DEd000000E7* + ID_MODEL_FROM_DATABASE=CK8S USB Controller + +pci:v000010DEd000000E7sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E7sv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E7sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E7sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E7sv00001849sd000000E7* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000E8* + ID_MODEL_FROM_DATABASE=nForce3 EHCI USB 2.0 Controller + +pci:v000010DEd000000E8sv00001043sd0000813F* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000E8sv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000E8sv00001462sd00007030* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000E8sv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000E8sv00001849sd000000E8* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010DEd000000EA* + ID_MODEL_FROM_DATABASE=nForce3 250Gb AC'97 Audio Controller + +pci:v000010DEd000000EAsv00001043sd0000819D* + ID_MODEL_FROM_DATABASE=K8N-E + +pci:v000010DEd000000EAsv0000105Bsd00000C43* + ID_MODEL_FROM_DATABASE=Winfast NF3250K8AA + +pci:v000010DEd000000EAsv00001462sd0000B010* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 + +pci:v000010DEd000000EAsv0000147Bsd00001C0B* + ID_MODEL_FROM_DATABASE=NF8 Mainboard + +pci:v000010DEd000000ED* + ID_MODEL_FROM_DATABASE=nForce3 250Gb PCI-to-PCI Bridge + +pci:v000010DEd000000EE* + ID_MODEL_FROM_DATABASE=nForce3 Serial ATA Controller 2 + +pci:v000010DEd000000F1* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 GT] + +pci:v000010DEd000000F1sv00001043sd000081A6* + ID_MODEL_FROM_DATABASE=N6600GT TD 128M AGP + +pci:v000010DEd000000F1sv00001043sd000081C6* + ID_MODEL_FROM_DATABASE=N6600GT TD 128M AGP + +pci:v000010DEd000000F1sv00001458sd00003150* + ID_MODEL_FROM_DATABASE=GV-N66T128VP + +pci:v000010DEd000000F1sv00001554sd00001191* + ID_MODEL_FROM_DATABASE=PixelView PV-N43UA (128KD) + +pci:v000010DEd000000F1sv00001682sd00002119* + ID_MODEL_FROM_DATABASE=GeForce 6600 GT AGP + +pci:v000010DEd000000F2* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600] + +pci:v000010DEd000000F2sv00001554sd00001194* + ID_MODEL_FROM_DATABASE=PixelView PV-N43AT (256KD) + +pci:v000010DEd000000F2sv00001682sd0000211C* + ID_MODEL_FROM_DATABASE=GeForce 6600 256MB DDR DUAL DVI TV + +pci:v000010DEd000000F3* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6200] + +pci:v000010DEd000000F4* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 LE] + +pci:v000010DEd000000F5* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7800 GS] + +pci:v000010DEd000000F6* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6800 GS/XT] + +pci:v000010DEd000000F6sv00001682sd0000217E* + ID_MODEL_FROM_DATABASE=XFX GeForce 6800 XTreme 256MB DDR3 AGP + +pci:v000010DEd000000F8* + ID_MODEL_FROM_DATABASE=NV40GL [Quadro FX 3400/4400] + +pci:v000010DEd000000F9* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 GT/GTO/Ultra] + +pci:v000010DEd000000F9sv000010DEsd000000F9* + ID_MODEL_FROM_DATABASE=NV40 [GeForce 6800 GT] + +pci:v000010DEd000000F9sv00001682sd00002120* + ID_MODEL_FROM_DATABASE=GEFORCE 6800 GT PCI-E + +pci:v000010DEd000000FA* + ID_MODEL_FROM_DATABASE=NV36 [GeForce PCX 5750] + +pci:v000010DEd000000FB* + ID_MODEL_FROM_DATABASE=NV38 [GeForce PCX 5900] + +pci:v000010DEd000000FC* + ID_MODEL_FROM_DATABASE=NV37GL [Quadro FX 330/GeForce PCX 5300] + +pci:v000010DEd000000FD* + ID_MODEL_FROM_DATABASE=NV37GL [Quadro PCI-E Series] + +pci:v000010DEd000000FE* + ID_MODEL_FROM_DATABASE=NV38GL [Quadro FX 1300] + +pci:v000010DEd000000FF* + ID_MODEL_FROM_DATABASE=NV18 [GeForce PCX 4300] + +pci:v000010DEd00000100* + ID_MODEL_FROM_DATABASE=NV10 [GeForce 256 SDR] + +pci:v000010DEd00000100sv00001043sd00000200* + ID_MODEL_FROM_DATABASE=AGP-V6600 SGRAM + +pci:v000010DEd00000100sv00001043sd00000201* + ID_MODEL_FROM_DATABASE=AGP-V6600 SDRAM + +pci:v000010DEd00000100sv00001043sd00004008* + ID_MODEL_FROM_DATABASE=AGP-V6600 SGRAM + +pci:v000010DEd00000100sv00001043sd00004009* + ID_MODEL_FROM_DATABASE=AGP-V6600 SDRAM + +pci:v000010DEd00000100sv00001048sd00000C41* + ID_MODEL_FROM_DATABASE=Erazor X + +pci:v000010DEd00000100sv00001048sd00000C43* + ID_MODEL_FROM_DATABASE=ERAZOR X PCI + +pci:v000010DEd00000100sv00001048sd00000C48* + ID_MODEL_FROM_DATABASE=Synergy Force + +pci:v000010DEd00000100sv00001102sd0000102D* + ID_MODEL_FROM_DATABASE=CT6941 GeForce 256 + +pci:v000010DEd00000100sv000014AFsd00005022* + ID_MODEL_FROM_DATABASE=3D Prophet SE + +pci:v000010DEd00000101* + ID_MODEL_FROM_DATABASE=NV10 [GeForce 256 DDR] + +pci:v000010DEd00000101sv00001043sd00000202* + ID_MODEL_FROM_DATABASE=AGP-V6800 DDR + +pci:v000010DEd00000101sv00001043sd0000400A* + ID_MODEL_FROM_DATABASE=AGP-V6800 DDR SGRAM + +pci:v000010DEd00000101sv00001043sd0000400B* + ID_MODEL_FROM_DATABASE=AGP-V6800 DDR SDRAM + +pci:v000010DEd00000101sv00001048sd00000C42* + ID_MODEL_FROM_DATABASE=Erazor X + +pci:v000010DEd00000101sv0000107Dsd00002822* + ID_MODEL_FROM_DATABASE=WinFast GeForce 256 + +pci:v000010DEd00000101sv00001102sd0000102E* + ID_MODEL_FROM_DATABASE=CT6970/CT6971 + +pci:v000010DEd00000101sv000014AFsd00005021* + ID_MODEL_FROM_DATABASE=3D Prophet DDR-DVI + +pci:v000010DEd00000103* + ID_MODEL_FROM_DATABASE=NV10GL [Quadro] + +pci:v000010DEd00000103sv00001048sd00000C40* + ID_MODEL_FROM_DATABASE=GLoria II-64 + +pci:v000010DEd00000103sv00001048sd00000C44* + ID_MODEL_FROM_DATABASE=GLoria II + +pci:v000010DEd00000103sv00001048sd00000C45* + ID_MODEL_FROM_DATABASE=GLoria II + +pci:v000010DEd00000103sv00001048sd00000C4A* + ID_MODEL_FROM_DATABASE=GLoria II-64 Pro + +pci:v000010DEd00000103sv00001048sd00000C4B* + ID_MODEL_FROM_DATABASE=GLoria II-64 Pro DVII + +pci:v000010DEd00000110* + ID_MODEL_FROM_DATABASE=NV11 [GeForce2 MX/MX 400] + +pci:v000010DEd00000110sv00001043sd00004015* + ID_MODEL_FROM_DATABASE=AGP-V7100 Pro + +pci:v000010DEd00000110sv00001043sd00004021* + ID_MODEL_FROM_DATABASE=V7100 Deluxe Combo + +pci:v000010DEd00000110sv00001043sd00004031* + ID_MODEL_FROM_DATABASE=V7100 Pro with TV output + +pci:v000010DEd00000110sv00001048sd00000C60* + ID_MODEL_FROM_DATABASE=Gladiac MX + +pci:v000010DEd00000110sv00001048sd00000C61* + ID_MODEL_FROM_DATABASE=Gladiac 511PCI + +pci:v000010DEd00000110sv00001048sd00000C63* + ID_MODEL_FROM_DATABASE=Gladiac 511TV-OUT 32MB + +pci:v000010DEd00000110sv00001048sd00000C64* + ID_MODEL_FROM_DATABASE=Gladiac 511TV-OUT 64MB + +pci:v000010DEd00000110sv00001048sd00000C65* + ID_MODEL_FROM_DATABASE=Gladiac 511TWIN + +pci:v000010DEd00000110sv00001048sd00000C66* + ID_MODEL_FROM_DATABASE=Gladiac 311 + +pci:v000010DEd00000110sv000010B0sd00000001* + ID_MODEL_FROM_DATABASE=GeForce2 MX Jumbo TV + +pci:v000010DEd00000110sv000010DEsd00000091* + ID_MODEL_FROM_DATABASE=Dell OEM GeForce 2 MX 400 + +pci:v000010DEd00000110sv000010DEsd000000A1* + ID_MODEL_FROM_DATABASE=Apple OEM GeForce2 MX + +pci:v000010DEd00000110sv00001462sd00008523* + ID_MODEL_FROM_DATABASE=MS-8852 + +pci:v000010DEd00000110sv00001462sd00008817* + ID_MODEL_FROM_DATABASE=MSI GeForce2 MX400 Pro32S [MS-8817] + +pci:v000010DEd00000110sv000014AFsd00007102* + ID_MODEL_FROM_DATABASE=3D Prophet II MX + +pci:v000010DEd00000110sv000014AFsd00007103* + ID_MODEL_FROM_DATABASE=3D Prophet II MX Dual-Display + +pci:v000010DEd00000110sv00001545sd00000023* + ID_MODEL_FROM_DATABASE=Xtasy Rev. B2 + +pci:v000010DEd00000110sv00001554sd00001081* + ID_MODEL_FROM_DATABASE=MVGA-NVG11AM(400) + +pci:v000010DEd00000111* + ID_MODEL_FROM_DATABASE=NV11 [GeForce2 MX200] + +pci:v000010DEd00000112* + ID_MODEL_FROM_DATABASE=NV11M [GeForce2 Go] + +pci:v000010DEd00000113* + ID_MODEL_FROM_DATABASE=NV11GL [Quadro2 MXR/EX/Go] + +pci:v000010DEd00000140* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 GT] + +pci:v000010DEd00000140sv00001458sd00003125* + ID_MODEL_FROM_DATABASE=GV-NX66T128D + +pci:v000010DEd00000140sv00001458sd00003126* + ID_MODEL_FROM_DATABASE=GV-NX66T256DE + +pci:v000010DEd00000140sv00001462sd00008939* + ID_MODEL_FROM_DATABASE=MS-8983 + +pci:v000010DEd00000141* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600] + +pci:v000010DEd00000141sv00001043sd000081B0* + ID_MODEL_FROM_DATABASE=EN6600 Silencer + +pci:v000010DEd00000141sv0000107Dsd0000593A* + ID_MODEL_FROM_DATABASE=LR2A22 128MB TV OUT + +pci:v000010DEd00000141sv0000107Dsd0000597B* + ID_MODEL_FROM_DATABASE=WINFAST PX6600 + +pci:v000010DEd00000141sv00001458sd00003124* + ID_MODEL_FROM_DATABASE=GV-NX66128DP Turbo Force Edition + +pci:v000010DEd00000142* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 LE] + +pci:v000010DEd00000143* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 VE] + +pci:v000010DEd00000144* + ID_MODEL_FROM_DATABASE=NV43M [GeForce Go 6600] + +pci:v000010DEd00000145* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6610 XL] + +pci:v000010DEd00000146* + ID_MODEL_FROM_DATABASE=NV43M [GeForce Go6200 TE / 6600 TE] + +pci:v000010DEd00000147* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6700 XL] + +pci:v000010DEd00000148* + ID_MODEL_FROM_DATABASE=NV43M [GeForce Go 6600] + +pci:v000010DEd00000149* + ID_MODEL_FROM_DATABASE=NV43M [GeForce Go 6600 GT] + +pci:v000010DEd0000014A* + ID_MODEL_FROM_DATABASE=NV43 [Quadro NVS 440] + +pci:v000010DEd0000014B* + ID_MODEL_FROM_DATABASE=NV43 + +pci:v000010DEd0000014D* + ID_MODEL_FROM_DATABASE=NV43GL [Quadro FX 550] + +pci:v000010DEd0000014E* + ID_MODEL_FROM_DATABASE=NV43GL [Quadro FX 540] + +pci:v000010DEd0000014F* + ID_MODEL_FROM_DATABASE=NV43 [GeForce 6200] + +pci:v000010DEd00000150* + ID_MODEL_FROM_DATABASE=NV15 [GeForce2 GTS/Pro] + +pci:v000010DEd00000150sv00001043sd00004016* + ID_MODEL_FROM_DATABASE=V7700 AGP Video Card + +pci:v000010DEd00000150sv00001043sd0000402A* + ID_MODEL_FROM_DATABASE=AGP-V7700 + +pci:v000010DEd00000150sv00001048sd00000C50* + ID_MODEL_FROM_DATABASE=Gladiac + +pci:v000010DEd00000150sv00001048sd00000C52* + ID_MODEL_FROM_DATABASE=Gladiac-64 + +pci:v000010DEd00000150sv0000107Dsd00002840* + ID_MODEL_FROM_DATABASE=WinFast GeForce2 GTS with TV output + +pci:v000010DEd00000150sv0000107Dsd00002842* + ID_MODEL_FROM_DATABASE=WinFast GeForce 2 Pro + +pci:v000010DEd00000150sv000010DEsd0000002E* + ID_MODEL_FROM_DATABASE=GeForce2 GTS + +pci:v000010DEd00000150sv00001462sd0000815A* + ID_MODEL_FROM_DATABASE=MS-8815 + +pci:v000010DEd00000150sv00001462sd00008831* + ID_MODEL_FROM_DATABASE=Creative GeForce2 Pro + +pci:v000010DEd00000151* + ID_MODEL_FROM_DATABASE=NV15 [GeForce2 Ti] + +pci:v000010DEd00000151sv00001043sd0000405F* + ID_MODEL_FROM_DATABASE=V7700Ti + +pci:v000010DEd00000151sv00001462sd00005506* + ID_MODEL_FROM_DATABASE=Creative 3D Blaster GeForce2 Titanium + +pci:v000010DEd00000151sv00001462sd00008364* + ID_MODEL_FROM_DATABASE=MS-8836 + +pci:v000010DEd00000152* + ID_MODEL_FROM_DATABASE=NV15 [GeForce2 Ultra] + +pci:v000010DEd00000152sv00001048sd00000C56* + ID_MODEL_FROM_DATABASE=GLADIAC Ultra + +pci:v000010DEd00000153* + ID_MODEL_FROM_DATABASE=NV15GL [Quadro2 Pro] + +pci:v000010DEd00000160* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6500] + +pci:v000010DEd00000161* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6200 TurboCache] + +pci:v000010DEd00000162* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6200 SE TurboCache] + +pci:v000010DEd00000163* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6200 LE] + +pci:v000010DEd00000164* + ID_MODEL_FROM_DATABASE=NV44M [GeForce Go 6200] + +pci:v000010DEd00000165* + ID_MODEL_FROM_DATABASE=NV44 [Quadro NVS 285] + +pci:v000010DEd00000166* + ID_MODEL_FROM_DATABASE=NV44M [GeForce Go 6400] + +pci:v000010DEd00000167* + ID_MODEL_FROM_DATABASE=NV44M [GeForce Go 6200] + +pci:v000010DEd00000168* + ID_MODEL_FROM_DATABASE=NV44M [GeForce Go 6400] + +pci:v000010DEd00000169* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6250] + +pci:v000010DEd0000016A* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 7100 GS] + +pci:v000010DEd0000016D* + ID_MODEL_FROM_DATABASE=NV44 + +pci:v000010DEd0000016E* + ID_MODEL_FROM_DATABASE=NV44 + +pci:v000010DEd0000016F* + ID_MODEL_FROM_DATABASE=NV44 + +pci:v000010DEd00000170* + ID_MODEL_FROM_DATABASE=NV17 [GeForce4 MX 460] + +pci:v000010DEd00000170sv00001462sd00008630* + ID_MODEL_FROM_DATABASE=MS-8863 + +pci:v000010DEd00000171* + ID_MODEL_FROM_DATABASE=NV17 [GeForce4 MX 440] + +pci:v000010DEd00000171sv000010B0sd00000002* + ID_MODEL_FROM_DATABASE=Gainward Pro/600 TV + +pci:v000010DEd00000171sv000010DEsd00000008* + ID_MODEL_FROM_DATABASE=Apple OEM GeForce4 MX 440 + +pci:v000010DEd00000171sv00001462sd00008661* + ID_MODEL_FROM_DATABASE=G4MX440-VTP + +pci:v000010DEd00000171sv00001462sd00008730* + ID_MODEL_FROM_DATABASE=MX440SES-T (MS-8873) + +pci:v000010DEd00000171sv00001462sd00008743* + ID_MODEL_FROM_DATABASE=MS-8874 + +pci:v000010DEd00000171sv00001462sd00008852* + ID_MODEL_FROM_DATABASE=GeForce4 MX440 PCI + +pci:v000010DEd00000171sv0000147Bsd00008F00* + ID_MODEL_FROM_DATABASE=Abit Siluro GeForce4MX440 + +pci:v000010DEd00000172* + ID_MODEL_FROM_DATABASE=NV17 [GeForce4 MX 420] + +pci:v000010DEd00000172sv00001462sd00008730* + ID_MODEL_FROM_DATABASE=MS-8873 + +pci:v000010DEd00000172sv00001462sd00008784* + ID_MODEL_FROM_DATABASE=MS-8878 + +pci:v000010DEd00000173* + ID_MODEL_FROM_DATABASE=NV17 [GeForce4 MX 440-SE] + +pci:v000010DEd00000174* + ID_MODEL_FROM_DATABASE=NV17M [GeForce4 440 Go] + +pci:v000010DEd00000175* + ID_MODEL_FROM_DATABASE=NV17M [GeForce4 420 Go] + +pci:v000010DEd00000176* + ID_MODEL_FROM_DATABASE=NV17M [GeForce4 420 Go 32M] + +pci:v000010DEd00000176sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v000010DEd00000176sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v000010DEd00000176sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v000010DEd00000177* + ID_MODEL_FROM_DATABASE=NV17M [GeForce4 460 Go] + +pci:v000010DEd00000178* + ID_MODEL_FROM_DATABASE=NV17GL [Quadro4 550 XGL] + +pci:v000010DEd00000179* + ID_MODEL_FROM_DATABASE=NV17M [GeForce4 440 Go 64M] + +pci:v000010DEd00000179sv000010DEsd00000179* + ID_MODEL_FROM_DATABASE=GeForce4 MX (Mac) + +pci:v000010DEd0000017A* + ID_MODEL_FROM_DATABASE=NV17GL [Quadro NVS] + +pci:v000010DEd0000017B* + ID_MODEL_FROM_DATABASE=NV17GL [Quadro4 550 XGL] + +pci:v000010DEd0000017C* + ID_MODEL_FROM_DATABASE=NV17GL [Quadro4 500 GoGL] + +pci:v000010DEd0000017F* + ID_MODEL_FROM_DATABASE=NV17 + +pci:v000010DEd00000181* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX 440 AGP 8x] + +pci:v000010DEd00000181sv00001043sd00008063* + ID_MODEL_FROM_DATABASE=GeForce4 MX 440 AGP 8X + +pci:v000010DEd00000181sv00001043sd0000806F* + ID_MODEL_FROM_DATABASE=V9180 Magic + +pci:v000010DEd00000181sv00001462sd00008880* + ID_MODEL_FROM_DATABASE=MS-StarForce GeForce4 MX 440 with AGP8X + +pci:v000010DEd00000181sv00001462sd00008900* + ID_MODEL_FROM_DATABASE=MS-8890 GeForce 4 MX440 AGP8X + +pci:v000010DEd00000181sv00001462sd00009350* + ID_MODEL_FROM_DATABASE=MSI GeForce4 MX T8X with AGP8X + +pci:v000010DEd00000181sv0000147Bsd00008F0D* + ID_MODEL_FROM_DATABASE=Siluro GF4 MX-8X + +pci:v000010DEd00000181sv00001554sd00001111* + ID_MODEL_FROM_DATABASE=PixelView MVGA-NVG18A + +pci:v000010DEd00000182* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX 440SE AGP 8x] + +pci:v000010DEd00000183* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX 420 AGP 8x] + +pci:v000010DEd00000184* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX] + +pci:v000010DEd00000185* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX 4000] + +pci:v000010DEd00000186* + ID_MODEL_FROM_DATABASE=NV18M [GeForce4 448 Go] + +pci:v000010DEd00000187* + ID_MODEL_FROM_DATABASE=NV18M [GeForce4 488 Go] + +pci:v000010DEd00000188* + ID_MODEL_FROM_DATABASE=NV18GL [Quadro4 580 XGL] + +pci:v000010DEd00000189* + ID_MODEL_FROM_DATABASE=NV18 [GeForce4 MX with AGP8X (Mac)] + +pci:v000010DEd0000018A* + ID_MODEL_FROM_DATABASE=NV18GL [Quadro NVS 280 SD] + +pci:v000010DEd0000018B* + ID_MODEL_FROM_DATABASE=NV18GL [Quadro4 380 XGL] + +pci:v000010DEd0000018C* + ID_MODEL_FROM_DATABASE=NV18GL [Quadro NVS 50 PCI] + +pci:v000010DEd0000018D* + ID_MODEL_FROM_DATABASE=NV18M [GeForce4 448 Go] + +pci:v000010DEd0000018F* + ID_MODEL_FROM_DATABASE=NV18 + +pci:v000010DEd00000190* + ID_MODEL_FROM_DATABASE=G80 [GeForce 8800 GTS / 8800 GTX] + +pci:v000010DEd00000191* + ID_MODEL_FROM_DATABASE=G80 [GeForce 8800 GTX] + +pci:v000010DEd00000192* + ID_MODEL_FROM_DATABASE=G80 [GeForce 8800 GTS] + +pci:v000010DEd00000193* + ID_MODEL_FROM_DATABASE=G80 [GeForce 8800 GTS] + +pci:v000010DEd00000193sv0000107Dsd000020BD* + ID_MODEL_FROM_DATABASE=WinFast PX 8800 GTS TDH + +pci:v000010DEd00000194* + ID_MODEL_FROM_DATABASE=G80 [GeForce 8800 Ultra] + +pci:v000010DEd00000197* + ID_MODEL_FROM_DATABASE=G80GL [Tesla C870] + +pci:v000010DEd0000019D* + ID_MODEL_FROM_DATABASE=G80GL [Quadro FX 5600] + +pci:v000010DEd0000019E* + ID_MODEL_FROM_DATABASE=G80GL [Quadro FX 4600] + +pci:v000010DEd000001A0* + ID_MODEL_FROM_DATABASE=nForce 220/420 NV11 [GeForce2 MX] + +pci:v000010DEd000001A4* + ID_MODEL_FROM_DATABASE=nForce CPU bridge + +pci:v000010DEd000001AB* + ID_MODEL_FROM_DATABASE=nForce 420 Memory Controller (DDR) + +pci:v000010DEd000001AC* + ID_MODEL_FROM_DATABASE=nForce 220/420 Memory Controller + +pci:v000010DEd000001AD* + ID_MODEL_FROM_DATABASE=nForce 220/420 Memory Controller + +pci:v000010DEd000001B0* + ID_MODEL_FROM_DATABASE=nForce Audio Processing Unit + +pci:v000010DEd000001B1* + ID_MODEL_FROM_DATABASE=nForce AC'97 Audio Controller + +pci:v000010DEd000001B2* + ID_MODEL_FROM_DATABASE=nForce ISA Bridge + +pci:v000010DEd000001B4* + ID_MODEL_FROM_DATABASE=nForce PCI System Management + +pci:v000010DEd000001B7* + ID_MODEL_FROM_DATABASE=nForce AGP to PCI Bridge + +pci:v000010DEd000001B8* + ID_MODEL_FROM_DATABASE=nForce PCI-to-PCI bridge + +pci:v000010DEd000001BC* + ID_MODEL_FROM_DATABASE=nForce IDE + +pci:v000010DEd000001C1* + ID_MODEL_FROM_DATABASE=nForce AC'97 Modem Controller + +pci:v000010DEd000001C2* + ID_MODEL_FROM_DATABASE=nForce USB Controller + +pci:v000010DEd000001C3* + ID_MODEL_FROM_DATABASE=nForce Ethernet Controller + +pci:v000010DEd000001D0* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7350 LE] + +pci:v000010DEd000001D1* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7300 LE] + +pci:v000010DEd000001D1sv0000107Dsd00005EFA* + ID_MODEL_FROM_DATABASE=WinFast PX7300LE-TD128 + +pci:v000010DEd000001D1sv0000107Dsd00005EFB* + ID_MODEL_FROM_DATABASE=WinFast PX7300LE-TD256 + +pci:v000010DEd000001D1sv00001462sd00000345* + ID_MODEL_FROM_DATABASE=7300LE PCI Express Graphics Adapter + +pci:v000010DEd000001D2* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7550 LE] + +pci:v000010DEd000001D3* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7200 GS / 7300 SE] + +pci:v000010DEd000001D5* + ID_MODEL_FROM_DATABASE=G72 + +pci:v000010DEd000001D6* + ID_MODEL_FROM_DATABASE=G72M [GeForce Go 7200] + +pci:v000010DEd000001D7* + ID_MODEL_FROM_DATABASE=G72M [Quadro NVS 110M/GeForce Go 7300] + +pci:v000010DEd000001D8* + ID_MODEL_FROM_DATABASE=G72M [GeForce Go 7400] + +pci:v000010DEd000001D8sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v000010DEd000001D9* + ID_MODEL_FROM_DATABASE=G72M [GeForce Go 7450] + +pci:v000010DEd000001DA* + ID_MODEL_FROM_DATABASE=G72M [Quadro NVS 110M] + +pci:v000010DEd000001DB* + ID_MODEL_FROM_DATABASE=G72M [Quadro NVS 120M] + +pci:v000010DEd000001DC* + ID_MODEL_FROM_DATABASE=G72GLM [Quadro FX 350M] + +pci:v000010DEd000001DD* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7500 LE] + +pci:v000010DEd000001DE* + ID_MODEL_FROM_DATABASE=G72GL [Quadro FX 350] + +pci:v000010DEd000001DEsv000010DEsd000001DC* + ID_MODEL_FROM_DATABASE=Quadro FX Go350M + +pci:v000010DEd000001DF* + ID_MODEL_FROM_DATABASE=G72 [GeForce 7300 GS] + +pci:v000010DEd000001E0* + ID_MODEL_FROM_DATABASE=nForce2 IGP2 + +pci:v000010DEd000001E0sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v000010DEd000001E8* + ID_MODEL_FROM_DATABASE=nForce2 AGP + +pci:v000010DEd000001EA* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 0 + +pci:v000010DEd000001EAsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001EB* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 1 + +pci:v000010DEd000001EBsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001EC* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 2 + +pci:v000010DEd000001ECsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001ED* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 3 + +pci:v000010DEd000001EDsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001EE* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 4 + +pci:v000010DEd000001EEsv000010DEsd000001EE* + ID_MODEL_FROM_DATABASE=MSI Delta-L nForce2 memory controller + +pci:v000010DEd000001EEsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001EF* + ID_MODEL_FROM_DATABASE=nForce2 Memory Controller 5 + +pci:v000010DEd000001EFsv0000A0A0sd000003B9* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd000001F0* + ID_MODEL_FROM_DATABASE=C17 [GeForce4 MX IGP] + +pci:v000010DEd000001F0sv0000A0A0sd000003B5* + ID_MODEL_FROM_DATABASE=UK79G-1394 motherboard + +pci:v000010DEd00000200* + ID_MODEL_FROM_DATABASE=NV20 [GeForce3] + +pci:v000010DEd00000200sv00001043sd0000402F* + ID_MODEL_FROM_DATABASE=AGP-V8200 DDR + +pci:v000010DEd00000200sv00001048sd00000C70* + ID_MODEL_FROM_DATABASE=GLADIAC 920 + +pci:v000010DEd00000201* + ID_MODEL_FROM_DATABASE=NV20 [GeForce3 Ti 200] + +pci:v000010DEd00000202* + ID_MODEL_FROM_DATABASE=NV20 [GeForce3 Ti 500] + +pci:v000010DEd00000202sv00001043sd0000405B* + ID_MODEL_FROM_DATABASE=V8200 T5 + +pci:v000010DEd00000202sv00001545sd0000002F* + ID_MODEL_FROM_DATABASE=Xtasy 6964 + +pci:v000010DEd00000203* + ID_MODEL_FROM_DATABASE=NV20GL [Quadro DCC] + +pci:v000010DEd00000211* + ID_MODEL_FROM_DATABASE=NV48 [GeForce 6800] + +pci:v000010DEd00000212* + ID_MODEL_FROM_DATABASE=NV48 [GeForce 6800 LE] + +pci:v000010DEd00000215* + ID_MODEL_FROM_DATABASE=NV48 [GeForce 6800 GT] + +pci:v000010DEd00000218* + ID_MODEL_FROM_DATABASE=NV48 [GeForce 6800 XT] + +pci:v000010DEd00000221* + ID_MODEL_FROM_DATABASE=NV44A [GeForce 6200] + +pci:v000010DEd00000221sv00001043sd000081E1* + ID_MODEL_FROM_DATABASE=N6200/TD/256M/A + +pci:v000010DEd00000221sv00003842sd0000A341* + ID_MODEL_FROM_DATABASE=256A8N341DX + +pci:v000010DEd00000222* + ID_MODEL_FROM_DATABASE=NV44 [GeForce 6200 A-LE] + +pci:v000010DEd00000224* + ID_MODEL_FROM_DATABASE=NV44 + +pci:v000010DEd00000240* + ID_MODEL_FROM_DATABASE=C51PV [GeForce 6150] + +pci:v000010DEd00000240sv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM + +pci:v000010DEd00000240sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000241* + ID_MODEL_FROM_DATABASE=C51 [GeForce 6150 LE] + +pci:v000010DEd00000242* + ID_MODEL_FROM_DATABASE=C51G [GeForce 6100] + +pci:v000010DEd00000242sv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd00000243* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd00000244* + ID_MODEL_FROM_DATABASE=C51 [GeForce Go 6150] + +pci:v000010DEd00000244sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v000010DEd00000244sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000244sv000010DEsd00000244* + ID_MODEL_FROM_DATABASE=GeForce Go 6150 + +pci:v000010DEd00000245* + ID_MODEL_FROM_DATABASE=C51 [Quadro NVS 210S/GeForce 6150LE] + +pci:v000010DEd00000246* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd00000247* + ID_MODEL_FROM_DATABASE=C51 [GeForce Go 6100] + +pci:v000010DEd00000247sv00001043sd00001382* + ID_MODEL_FROM_DATABASE=MCP51 PCI-X GeForce Go 6100 + +pci:v000010DEd00000248* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd00000249* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024A* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024B* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024C* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024D* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024E* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd0000024F* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd00000250* + ID_MODEL_FROM_DATABASE=NV25 [GeForce4 Ti 4600] + +pci:v000010DEd00000251* + ID_MODEL_FROM_DATABASE=NV25 [GeForce4 Ti 4400] + +pci:v000010DEd00000251sv00001043sd00008023* + ID_MODEL_FROM_DATABASE=v8440 GeForce 4 Ti4400 + +pci:v000010DEd00000251sv000010DEsd00000251* + ID_MODEL_FROM_DATABASE=PNY GeForce4 Ti 4400 + +pci:v000010DEd00000251sv00001462sd00008710* + ID_MODEL_FROM_DATABASE=PNY GeForce4 Ti 4400 + +pci:v000010DEd00000252* + ID_MODEL_FROM_DATABASE=NV25 [GeForce4 Ti] + +pci:v000010DEd00000253* + ID_MODEL_FROM_DATABASE=NV25 [GeForce4 Ti 4200] + +pci:v000010DEd00000253sv0000107Dsd00002896* + ID_MODEL_FROM_DATABASE=WinFast A250 LE TD (Dual VGA/TV-out/DVI) + +pci:v000010DEd00000253sv0000147Bsd00008F09* + ID_MODEL_FROM_DATABASE=Siluro (Dual VGA/TV-out/DVI) + +pci:v000010DEd00000258* + ID_MODEL_FROM_DATABASE=NV25GL [Quadro4 900 XGL] + +pci:v000010DEd00000259* + ID_MODEL_FROM_DATABASE=NV25GL [Quadro4 750 XGL] + +pci:v000010DEd0000025B* + ID_MODEL_FROM_DATABASE=NV25GL [Quadro4 700 XGL] + +pci:v000010DEd00000260* + ID_MODEL_FROM_DATABASE=MCP51 LPC Bridge + +pci:v000010DEd00000260sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000260sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000260sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000260sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd00000260sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000261* + ID_MODEL_FROM_DATABASE=MCP51 LPC Bridge + +pci:v000010DEd00000261sv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd00000262* + ID_MODEL_FROM_DATABASE=MCP51 LPC Bridge + +pci:v000010DEd00000263* + ID_MODEL_FROM_DATABASE=MCP51 LPC Bridge + +pci:v000010DEd00000264* + ID_MODEL_FROM_DATABASE=MCP51 SMBus + +pci:v000010DEd00000264sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000264sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000264sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000264sv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd00000264sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000265* + ID_MODEL_FROM_DATABASE=MCP51 IDE + +pci:v000010DEd00000265sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000265sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000265sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000265sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000265sv0000F05Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd00000266* + ID_MODEL_FROM_DATABASE=MCP51 Serial ATA Controller + +pci:v000010DEd00000266sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000266sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000266sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000266sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000267* + ID_MODEL_FROM_DATABASE=MCP51 Serial ATA Controller + +pci:v000010DEd00000267sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000267sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000267sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000268* + ID_MODEL_FROM_DATABASE=MCP51 Ethernet Controller + +pci:v000010DEd00000269* + ID_MODEL_FROM_DATABASE=MCP51 Ethernet Controller + +pci:v000010DEd00000269sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000269sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000269sv00001043sd00008141* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000269sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd0000026A* + ID_MODEL_FROM_DATABASE=MCP51 MCI + +pci:v000010DEd0000026B* + ID_MODEL_FROM_DATABASE=MCP51 AC97 Audio Controller + +pci:v000010DEd0000026Bsv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd0000026C* + ID_MODEL_FROM_DATABASE=MCP51 High Definition Audio + +pci:v000010DEd0000026Csv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd0000026Csv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v000010DEd0000026Csv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd0000026Csv000010DEsd0000CB84* + ID_MODEL_FROM_DATABASE=ASUSTeK Computer Inc. A8N-VM CSM Mainboard + +pci:v000010DEd0000026Csv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd0000026D* + ID_MODEL_FROM_DATABASE=MCP51 USB Controller + +pci:v000010DEd0000026Dsv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd0000026Dsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd0000026Dsv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd0000026Dsv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd0000026Dsv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd0000026E* + ID_MODEL_FROM_DATABASE=MCP51 USB Controller + +pci:v000010DEd0000026Esv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd0000026Esv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd0000026Esv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd0000026Esv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd0000026Esv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd0000026F* + ID_MODEL_FROM_DATABASE=MCP51 PCI Bridge + +pci:v000010DEd0000026Fsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000270* + ID_MODEL_FROM_DATABASE=MCP51 Host Bridge + +pci:v000010DEd00000270sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000270sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000270sv00001043sd000081BC* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd00000270sv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd00000270sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd00000270sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000271* + ID_MODEL_FROM_DATABASE=MCP51 PMU + +pci:v000010DEd00000271sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v000010DEd00000271sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd00000272* + ID_MODEL_FROM_DATABASE=MCP51 Memory Controller 0 + +pci:v000010DEd00000272sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd00000272sv0000105Bsd00000CAD* + ID_MODEL_FROM_DATABASE=Winfast 6100K8MB + +pci:v000010DEd0000027E* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 2 + +pci:v000010DEd0000027Esv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd0000027Esv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd0000027Esv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd0000027Esv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd0000027Esv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd0000027F* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 3 + +pci:v000010DEd0000027Fsv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd0000027Fsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd0000027Fsv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd0000027Fsv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd0000027Fsv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000280* + ID_MODEL_FROM_DATABASE=NV28 [GeForce4 Ti 4800] + +pci:v000010DEd00000281* + ID_MODEL_FROM_DATABASE=NV28 [GeForce4 Ti 4200 AGP 8x] + +pci:v000010DEd00000282* + ID_MODEL_FROM_DATABASE=NV28 [GeForce4 Ti 4800 SE] + +pci:v000010DEd00000286* + ID_MODEL_FROM_DATABASE=NV28M [GeForce4 Ti 4200 Go AGP 8x] + +pci:v000010DEd00000288* + ID_MODEL_FROM_DATABASE=NV28GL [Quadro4 980 XGL] + +pci:v000010DEd00000289* + ID_MODEL_FROM_DATABASE=NV28GL [Quadro4 780 XGL] + +pci:v000010DEd0000028C* + ID_MODEL_FROM_DATABASE=NV28GLM [Quadro4 Go700] + +pci:v000010DEd00000290* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GTX] + +pci:v000010DEd00000291* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GT/GTO] + +pci:v000010DEd00000291sv000010DEsd0000042B* + ID_MODEL_FROM_DATABASE=NX7900GTO-T2D512E [7900 GTO] + +pci:v000010DEd00000292* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GS] + +pci:v000010DEd00000293* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GX2] + +pci:v000010DEd00000294* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GX2] + +pci:v000010DEd00000295* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT] + +pci:v000010DEd00000295sv00001043sd00008225* + ID_MODEL_FROM_DATABASE=GeForce 7950 GT + +pci:v000010DEd00000295sv0000107Dsd00002A68* + ID_MODEL_FROM_DATABASE=WinFast PX7950GT TDH + +pci:v000010DEd00000295sv00001462sd00000663* + ID_MODEL_FROM_DATABASE=NX7950GT-VT2D512EZ-HD + +pci:v000010DEd00000297* + ID_MODEL_FROM_DATABASE=G71M [GeForce Go 7950 GTX] + +pci:v000010DEd00000298* + ID_MODEL_FROM_DATABASE=G71M [GeForce Go 7900 GS] + +pci:v000010DEd00000299* + ID_MODEL_FROM_DATABASE=G71M [GeForce Go 7900 GTX] + +pci:v000010DEd0000029A* + ID_MODEL_FROM_DATABASE=G71GLM [Quadro FX 2500M] + +pci:v000010DEd0000029B* + ID_MODEL_FROM_DATABASE=G71GLM [Quadro FX 1500M] + +pci:v000010DEd0000029C* + ID_MODEL_FROM_DATABASE=G71GL [Quadro FX 5500] + +pci:v000010DEd0000029D* + ID_MODEL_FROM_DATABASE=G71GL [Quadro FX 3500] + +pci:v000010DEd0000029Dsv00001028sd0000019B* + ID_MODEL_FROM_DATABASE=G71GLM [Quadro FX 3500M] + +pci:v000010DEd0000029E* + ID_MODEL_FROM_DATABASE=G71GL [Quadro FX 1500] + +pci:v000010DEd0000029F* + ID_MODEL_FROM_DATABASE=G71GL [Quadro FX 4500 X2] + +pci:v000010DEd000002A0* + ID_MODEL_FROM_DATABASE=NV2A [XGPU] + +pci:v000010DEd000002A5* + ID_MODEL_FROM_DATABASE=MCPX CPU Bridge + +pci:v000010DEd000002A6* + ID_MODEL_FROM_DATABASE=MCPX Memory Controller + +pci:v000010DEd000002E0* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT] + +pci:v000010DEd000002E0sv000002E0sd00002249* + ID_MODEL_FROM_DATABASE=GF 7600GT 560M 256MB DDR3 DUAL DVI TV + +pci:v000010DEd000002E1* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS] + +pci:v000010DEd000002E1sv00001682sd0000222B* + ID_MODEL_FROM_DATABASE=PV-T73K-UAL3 (256MB) + +pci:v000010DEd000002E1sv00001682sd00002247* + ID_MODEL_FROM_DATABASE=GF 7600GS 512MB DDR2 + +pci:v000010DEd000002E2* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7300 GT] + +pci:v000010DEd000002E3* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7900 GS] + +pci:v000010DEd000002E4* + ID_MODEL_FROM_DATABASE=G71 [GeForce 7950 GT] + +pci:v000010DEd000002E4sv00001682sd00002271* + ID_MODEL_FROM_DATABASE=PV-T71A-YDF7 (512MB) + +pci:v000010DEd000002F0* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F0sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002F0sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002F0sv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002F0sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd000002F1* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F1sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002F2* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F3* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F4* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F5* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F6* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F7* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002F8* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 5 + +pci:v000010DEd000002F8sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002F8sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002F8sv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002F8sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002F8sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd000002F9* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 4 + +pci:v000010DEd000002F9sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002F9sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002F9sv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002F9sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002F9sv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd000002FA* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 0 + +pci:v000010DEd000002FAsv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002FAsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002FAsv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002FAsv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002FAsv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd000002FB* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd000002FC* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd000002FCsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002FD* + ID_MODEL_FROM_DATABASE=C51 PCI Express Bridge + +pci:v000010DEd000002FDsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002FE* + ID_MODEL_FROM_DATABASE=C51 Memory Controller 1 + +pci:v000010DEd000002FEsv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002FEsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002FEsv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002FEsv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002FEsv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd000002FF* + ID_MODEL_FROM_DATABASE=C51 Host Bridge + +pci:v000010DEd000002FFsv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000010DEd000002FFsv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v000010DEd000002FFsv00001043sd000081CD* + ID_MODEL_FROM_DATABASE=A8N-VM CSM Mainboard + +pci:v000010DEd000002FFsv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-M55plus-S3G + +pci:v000010DEd000002FFsv00001462sd00007207* + ID_MODEL_FROM_DATABASE=K8NGM2 series + +pci:v000010DEd00000300* + ID_MODEL_FROM_DATABASE=NV30 [GeForce FX] + +pci:v000010DEd00000301* + ID_MODEL_FROM_DATABASE=NV30 [GeForce FX 5800 Ultra] + +pci:v000010DEd00000302* + ID_MODEL_FROM_DATABASE=NV30 [GeForce FX 5800] + +pci:v000010DEd00000308* + ID_MODEL_FROM_DATABASE=NV30GL [Quadro FX 2000] + +pci:v000010DEd00000309* + ID_MODEL_FROM_DATABASE=NV30GL [Quadro FX 1000] + +pci:v000010DEd00000311* + ID_MODEL_FROM_DATABASE=NV31 [GeForce FX 5600 Ultra] + +pci:v000010DEd00000312* + ID_MODEL_FROM_DATABASE=NV31 [GeForce FX 5600] + +pci:v000010DEd00000314* + ID_MODEL_FROM_DATABASE=NV31 [GeForce FX 5600XT] + +pci:v000010DEd00000314sv00001043sd0000814A* + ID_MODEL_FROM_DATABASE=V9560XT/TD + +pci:v000010DEd00000316* + ID_MODEL_FROM_DATABASE=NV31M + +pci:v000010DEd00000318* + ID_MODEL_FROM_DATABASE=NV31GL + +pci:v000010DEd0000031A* + ID_MODEL_FROM_DATABASE=NV31M [GeForce FX Go5600] + +pci:v000010DEd0000031B* + ID_MODEL_FROM_DATABASE=NV31M [GeForce FX Go5650] + +pci:v000010DEd0000031C* + ID_MODEL_FROM_DATABASE=NV31GLM [Quadro FX Go700] + +pci:v000010DEd00000320* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5200] + +pci:v000010DEd00000321* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5200 Ultra] + +pci:v000010DEd00000322* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5200] + +pci:v000010DEd00000322sv00001043sd000002FB* + ID_MODEL_FROM_DATABASE=V9250 Magic + +pci:v000010DEd00000322sv00001043sd00008180* + ID_MODEL_FROM_DATABASE=V9520-X/TD/128M + +pci:v000010DEd00000322sv0000107Dsd00002967* + ID_MODEL_FROM_DATABASE=WinFast A340T 128MB + +pci:v000010DEd00000322sv00001462sd00009110* + ID_MODEL_FROM_DATABASE=MS-8911 (FX5200-TD128) + +pci:v000010DEd00000322sv00001462sd00009171* + ID_MODEL_FROM_DATABASE=MS-8917 (FX5200-T128) + +pci:v000010DEd00000322sv00001462sd00009360* + ID_MODEL_FROM_DATABASE=MS-8936 (FX5200-T128) + +pci:v000010DEd00000322sv00001682sd00001351* + ID_MODEL_FROM_DATABASE=GeForce FX 5200 + +pci:v000010DEd00000323* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5200LE] + +pci:v000010DEd00000324* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5200 64M] + +pci:v000010DEd00000324sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v000010DEd00000324sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=Pavilion ZD7000 laptop + +pci:v000010DEd00000324sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v000010DEd00000325* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5250] + +pci:v000010DEd00000326* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5500] + +pci:v000010DEd00000326sv00001458sd0000310D* + ID_MODEL_FROM_DATABASE=GeForce FX 5500 128 MB + +pci:v000010DEd00000326sv00001682sd00002034* + ID_MODEL_FROM_DATABASE=GeForce 5500 256 MB + +pci:v000010DEd00000327* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5100] + +pci:v000010DEd00000328* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5200 32M/64M] + +pci:v000010DEd00000329* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5200] + +pci:v000010DEd00000329sv000010DEsd00000010* + ID_MODEL_FROM_DATABASE=Powerbook G4 + +pci:v000010DEd0000032A* + ID_MODEL_FROM_DATABASE=NV34GL [Quadro NVS 280 PCI] + +pci:v000010DEd0000032B* + ID_MODEL_FROM_DATABASE=NV34GL [Quadro FX 500/600 PCI] + +pci:v000010DEd0000032C* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5300 / Go5350] + +pci:v000010DEd0000032D* + ID_MODEL_FROM_DATABASE=NV34M [GeForce FX Go5100] + +pci:v000010DEd0000032E* + ID_MODEL_FROM_DATABASE=NV34 + +pci:v000010DEd0000032F* + ID_MODEL_FROM_DATABASE=NV34 [GeForce FX 5200] + +pci:v000010DEd00000330* + ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900 Ultra] + +pci:v000010DEd00000330sv00001043sd00008137* + ID_MODEL_FROM_DATABASE=V9950 Ultra / 256 MB + +pci:v000010DEd00000331* + ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900] + +pci:v000010DEd00000331sv00001043sd00008145* + ID_MODEL_FROM_DATABASE=V9950GE + +pci:v000010DEd00000332* + ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900XT] + +pci:v000010DEd00000333* + ID_MODEL_FROM_DATABASE=NV38 [GeForce FX 5950 Ultra] + +pci:v000010DEd00000334* + ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900ZT] + +pci:v000010DEd00000334sv00001462sd00009373* + ID_MODEL_FROM_DATABASE=FX5900ZT-VTD128 (MS-8937) + +pci:v000010DEd00000338* + ID_MODEL_FROM_DATABASE=NV35GL [Quadro FX 3000] + +pci:v000010DEd0000033F* + ID_MODEL_FROM_DATABASE=NV35GL [Quadro FX 700] + +pci:v000010DEd00000341* + ID_MODEL_FROM_DATABASE=NV36 [GeForce FX 5700 Ultra] + +pci:v000010DEd00000341sv00001462sd00009380* + ID_MODEL_FROM_DATABASE=MS-8938 (FX5700U-TD128) + +pci:v000010DEd00000342* + ID_MODEL_FROM_DATABASE=NV36 [GeForce FX 5700] + +pci:v000010DEd00000343* + ID_MODEL_FROM_DATABASE=NV36 [GeForce FX 5700LE] + +pci:v000010DEd00000344* + ID_MODEL_FROM_DATABASE=NV36 [GeForce FX 5700VE] + +pci:v000010DEd00000347* + ID_MODEL_FROM_DATABASE=NV36M [GeForce FX Go5700] + +pci:v000010DEd00000347sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v000010DEd00000348* + ID_MODEL_FROM_DATABASE=NV36M [GeForce FX Go5700] + +pci:v000010DEd0000034C* + ID_MODEL_FROM_DATABASE=NV36 [Quadro FX Go1000] + +pci:v000010DEd0000034D* + ID_MODEL_FROM_DATABASE=NV36 + +pci:v000010DEd0000034E* + ID_MODEL_FROM_DATABASE=NV36GL [Quadro FX 1100] + +pci:v000010DEd00000360* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000361* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000361sv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 LPC Bridge + +pci:v000010DEd00000362* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000362sv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd00000363* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000364* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000364sv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 LPC Bridge + +pci:v000010DEd00000365* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000366* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000367* + ID_MODEL_FROM_DATABASE=MCP55 LPC Bridge + +pci:v000010DEd00000368* + ID_MODEL_FROM_DATABASE=MCP55 SMBus + +pci:v000010DEd00000368sv00001028sd0000020C* + ID_MODEL_FROM_DATABASE=PowerEdge M605 MCP55 SMBus + +pci:v000010DEd00000368sv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 SMBus + +pci:v000010DEd00000368sv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd00000369* + ID_MODEL_FROM_DATABASE=MCP55 Memory Controller + +pci:v000010DEd00000369sv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd0000036A* + ID_MODEL_FROM_DATABASE=MCP55 Memory Controller + +pci:v000010DEd0000036B* + ID_MODEL_FROM_DATABASE=MCP55 SMU + +pci:v000010DEd0000036C* + ID_MODEL_FROM_DATABASE=MCP55 USB Controller + +pci:v000010DEd0000036Csv00001028sd0000020C* + ID_MODEL_FROM_DATABASE=PowerEdge M605 MCP55 USB Controller + +pci:v000010DEd0000036Csv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 USB Controller + +pci:v000010DEd0000036Csv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd0000036D* + ID_MODEL_FROM_DATABASE=MCP55 USB Controller + +pci:v000010DEd0000036Dsv00001028sd0000020C* + ID_MODEL_FROM_DATABASE=PowerEdge M605 MCP55 USB Controller + +pci:v000010DEd0000036Dsv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 USB Controller + +pci:v000010DEd0000036Dsv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd0000036E* + ID_MODEL_FROM_DATABASE=MCP55 IDE + +pci:v000010DEd0000036Esv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd00000370* + ID_MODEL_FROM_DATABASE=MCP55 PCI bridge + +pci:v000010DEd00000371* + ID_MODEL_FROM_DATABASE=MCP55 High Definition Audio + +pci:v000010DEd00000371sv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd00000372* + ID_MODEL_FROM_DATABASE=MCP55 Ethernet + +pci:v000010DEd00000373* + ID_MODEL_FROM_DATABASE=MCP55 Ethernet + +pci:v000010DEd00000373sv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd00000374* + ID_MODEL_FROM_DATABASE=MCP55 PCI Express bridge + +pci:v000010DEd00000375* + ID_MODEL_FROM_DATABASE=MCP55 PCI Express bridge + +pci:v000010DEd00000376* + ID_MODEL_FROM_DATABASE=MCP55 PCI Express bridge + +pci:v000010DEd00000377* + ID_MODEL_FROM_DATABASE=MCP55 PCI Express bridge + +pci:v000010DEd00000378* + ID_MODEL_FROM_DATABASE=MCP55 PCI Express bridge + +pci:v000010DEd0000037A* + ID_MODEL_FROM_DATABASE=MCP55 Memory Controller + +pci:v000010DEd0000037E* + ID_MODEL_FROM_DATABASE=MCP55 SATA Controller + +pci:v000010DEd0000037F* + ID_MODEL_FROM_DATABASE=MCP55 SATA Controller + +pci:v000010DEd0000037Fsv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 MCP55 SATA Controller + +pci:v000010DEd0000037Fsv0000147Bsd00001C24* + ID_MODEL_FROM_DATABASE=KN9 series mainboard + +pci:v000010DEd0000038B* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7650 GS] + +pci:v000010DEd00000390* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7650 GS] + +pci:v000010DEd00000391* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GT] + +pci:v000010DEd00000391sv00001458sd00003427* + ID_MODEL_FROM_DATABASE=GV-NX76T128D-RH + +pci:v000010DEd00000391sv00001462sd00000452* + ID_MODEL_FROM_DATABASE=NX7600GT-VT2D256E + +pci:v000010DEd00000392* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 GS] + +pci:v000010DEd00000392sv00001462sd00000622* + ID_MODEL_FROM_DATABASE=NX7600GS-T2D256EH + +pci:v000010DEd00000393* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7300 GT] + +pci:v000010DEd00000393sv000010DEsd00000412* + ID_MODEL_FROM_DATABASE=NX7300GT-TD256EH + +pci:v000010DEd00000393sv00001462sd00000412* + ID_MODEL_FROM_DATABASE=NX7300GT-TD256EH + +pci:v000010DEd00000394* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7600 LE] + +pci:v000010DEd00000395* + ID_MODEL_FROM_DATABASE=G73 [GeForce 7300 GT] + +pci:v000010DEd00000396* + ID_MODEL_FROM_DATABASE=G73 + +pci:v000010DEd00000397* + ID_MODEL_FROM_DATABASE=G73M [GeForce Go 7700] + +pci:v000010DEd00000398* + ID_MODEL_FROM_DATABASE=G73M [GeForce Go 7600] + +pci:v000010DEd00000398sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=Acer 9814 WKMI + +pci:v000010DEd00000399* + ID_MODEL_FROM_DATABASE=G73M [GeForce Go 7600 GT] + +pci:v000010DEd0000039A* + ID_MODEL_FROM_DATABASE=G73M [Quadro NVS 300M] + +pci:v000010DEd0000039B* + ID_MODEL_FROM_DATABASE=G73M [GeForce Go 7900 SE] + +pci:v000010DEd0000039C* + ID_MODEL_FROM_DATABASE=G73GLM [Quadro FX 550M] + +pci:v000010DEd0000039Csv000010DEsd0000039C* + ID_MODEL_FROM_DATABASE=Quadro FX 560M + +pci:v000010DEd0000039D* + ID_MODEL_FROM_DATABASE=G73 + +pci:v000010DEd0000039E* + ID_MODEL_FROM_DATABASE=G73GL [Quadro FX 560] + +pci:v000010DEd0000039F* + ID_MODEL_FROM_DATABASE=G73 + +pci:v000010DEd000003A0* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A1* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A2* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A3* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A4* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A5* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A6* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A7* + ID_MODEL_FROM_DATABASE=C55 Host Bridge + +pci:v000010DEd000003A8* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003A9* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AA* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AB* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AC* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AD* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AE* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003AF* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B0* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B1* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B2* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B3* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B4* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B5* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B6* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003B7* + ID_MODEL_FROM_DATABASE=C55 PCI Express bridge + +pci:v000010DEd000003B8* + ID_MODEL_FROM_DATABASE=C55 PCI Express bridge + +pci:v000010DEd000003B9* + ID_MODEL_FROM_DATABASE=C55 PCI Express bridge + +pci:v000010DEd000003BA* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003BB* + ID_MODEL_FROM_DATABASE=C55 PCI Express bridge + +pci:v000010DEd000003BC* + ID_MODEL_FROM_DATABASE=C55 Memory Controller + +pci:v000010DEd000003D0* + ID_MODEL_FROM_DATABASE=C61 [GeForce 6150SE nForce 430] + +pci:v000010DEd000003D0sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003D1* + ID_MODEL_FROM_DATABASE=C61 [GeForce 6100 nForce 405] + +pci:v000010DEd000003D2* + ID_MODEL_FROM_DATABASE=C61 [GeForce 6100 nForce 400] + +pci:v000010DEd000003D5* + ID_MODEL_FROM_DATABASE=C61 [GeForce 6100 nForce 420] + +pci:v000010DEd000003D6* + ID_MODEL_FROM_DATABASE=C61 [GeForce 7025 / nForce 630a] + +pci:v000010DEd000003E0* + ID_MODEL_FROM_DATABASE=MCP61 LPC Bridge + +pci:v000010DEd000003E0sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003E0sv00001849sd000003E0* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003E1* + ID_MODEL_FROM_DATABASE=MCP61 LPC Bridge + +pci:v000010DEd000003E1sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003E2* + ID_MODEL_FROM_DATABASE=MCP61 Host Bridge + +pci:v000010DEd000003E2sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003E3* + ID_MODEL_FROM_DATABASE=MCP61 LPC Bridge + +pci:v000010DEd000003E4* + ID_MODEL_FROM_DATABASE=MCP61 High Definition Audio + +pci:v000010DEd000003E5* + ID_MODEL_FROM_DATABASE=MCP61 Ethernet + +pci:v000010DEd000003E6* + ID_MODEL_FROM_DATABASE=MCP61 Ethernet + +pci:v000010DEd000003E7* + ID_MODEL_FROM_DATABASE=MCP61 SATA Controller + +pci:v000010DEd000003E8* + ID_MODEL_FROM_DATABASE=MCP61 PCI Express bridge + +pci:v000010DEd000003E8sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003E8sv00001849sd000003E8* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003E9* + ID_MODEL_FROM_DATABASE=MCP61 PCI Express bridge + +pci:v000010DEd000003E9sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003E9sv00001849sd000003E9* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003EA* + ID_MODEL_FROM_DATABASE=MCP61 Memory Controller + +pci:v000010DEd000003EAsv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003EAsv00001849sd000003EA* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003EB* + ID_MODEL_FROM_DATABASE=MCP61 SMBus + +pci:v000010DEd000003EBsv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003EBsv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003EBsv00001849sd000003EB* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003EC* + ID_MODEL_FROM_DATABASE=MCP61 IDE + +pci:v000010DEd000003ECsv00001025sd00000392* + ID_MODEL_FROM_DATABASE=ET1350 + +pci:v000010DEd000003ECsv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003ECsv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003ECsv00001849sd000003EC* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003EE* + ID_MODEL_FROM_DATABASE=MCP61 Ethernet + +pci:v000010DEd000003EF* + ID_MODEL_FROM_DATABASE=MCP61 Ethernet + +pci:v000010DEd000003EFsv00001025sd00008000* + ID_MODEL_FROM_DATABASE=ET1350 + +pci:v000010DEd000003EFsv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003EFsv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003EFsv00001849sd000003EF* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F0* + ID_MODEL_FROM_DATABASE=MCP61 High Definition Audio + +pci:v000010DEd000003F0sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F0sv00001043sd00008415* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003F0sv00001849sd00000888* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F1* + ID_MODEL_FROM_DATABASE=MCP61 USB 1.1 Controller + +pci:v000010DEd000003F1sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F1sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003F1sv00001849sd000003F1* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F2* + ID_MODEL_FROM_DATABASE=MCP61 USB 2.0 Controller + +pci:v000010DEd000003F2sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F2sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003F2sv00001849sd000003F2* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F3* + ID_MODEL_FROM_DATABASE=MCP61 PCI bridge + +pci:v000010DEd000003F3sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F3sv00001849sd000003F3* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F4* + ID_MODEL_FROM_DATABASE=MCP61 SMU + +pci:v000010DEd000003F5* + ID_MODEL_FROM_DATABASE=MCP61 Memory Controller + +pci:v000010DEd000003F5sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F5sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003F5sv00001849sd000003EB* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F6* + ID_MODEL_FROM_DATABASE=MCP61 SATA Controller + +pci:v000010DEd000003F6sv00001028sd0000020E* + ID_MODEL_FROM_DATABASE=Inspiron 531 + +pci:v000010DEd000003F6sv00001043sd000083A4* + ID_MODEL_FROM_DATABASE=M4N68T series motherboard + +pci:v000010DEd000003F6sv00001849sd000003F6* + ID_MODEL_FROM_DATABASE=939NF6G-VSTA Board + +pci:v000010DEd000003F7* + ID_MODEL_FROM_DATABASE=MCP61 SATA Controller + +pci:v000010DEd00000400* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8600 GTS] + +pci:v000010DEd00000400sv00001043sd00008241* + ID_MODEL_FROM_DATABASE=EN8600GTS + +pci:v000010DEd00000401* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8600 GT] + +pci:v000010DEd00000402* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8600 GT] + +pci:v000010DEd00000402sv00001458sd00003455* + ID_MODEL_FROM_DATABASE=GV-NX86T512H + +pci:v000010DEd00000402sv00001462sd00000910* + ID_MODEL_FROM_DATABASE=NX8600GT-T2D256EZ + +pci:v000010DEd00000403* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8600 GS] + +pci:v000010DEd00000404* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8400 GS] + +pci:v000010DEd00000404sv00001462sd00001230* + ID_MODEL_FROM_DATABASE=NX8400GS-TD256E + +pci:v000010DEd00000405* + ID_MODEL_FROM_DATABASE=G84M [GeForce 9500M GS] + +pci:v000010DEd00000406* + ID_MODEL_FROM_DATABASE=G84 [GeForce 8300 GS] + +pci:v000010DEd00000407* + ID_MODEL_FROM_DATABASE=G84M [GeForce 8600M GT] + +pci:v000010DEd00000408* + ID_MODEL_FROM_DATABASE=G84M [GeForce 9650M GS] + +pci:v000010DEd00000409* + ID_MODEL_FROM_DATABASE=G84M [GeForce 8700M GT] + +pci:v000010DEd0000040A* + ID_MODEL_FROM_DATABASE=G84GL [Quadro FX 370] + +pci:v000010DEd0000040B* + ID_MODEL_FROM_DATABASE=G84GLM [Quadro NVS 320M] + +pci:v000010DEd0000040C* + ID_MODEL_FROM_DATABASE=G84GLM [Quadro FX 570M] + +pci:v000010DEd0000040Csv000017AAsd000020D9* + ID_MODEL_FROM_DATABASE=ThinkPad T61p + +pci:v000010DEd0000040D* + ID_MODEL_FROM_DATABASE=G84GLM [Quadro FX 1600M] + +pci:v000010DEd0000040E* + ID_MODEL_FROM_DATABASE=G84GL [Quadro FX 570] + +pci:v000010DEd0000040F* + ID_MODEL_FROM_DATABASE=G84GL [Quadro FX 1700] + +pci:v000010DEd00000410* + ID_MODEL_FROM_DATABASE=G92 [GeForce GT 330] + +pci:v000010DEd00000414* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GT] + +pci:v000010DEd00000420* + ID_MODEL_FROM_DATABASE=G86 [GeForce 8400 SE] + +pci:v000010DEd00000421* + ID_MODEL_FROM_DATABASE=G86 [GeForce 8500 GT] + +pci:v000010DEd00000421sv00001462sd00000960* + ID_MODEL_FROM_DATABASE=NX8500GT-TD512EH/M2 + +pci:v000010DEd00000422* + ID_MODEL_FROM_DATABASE=G86 [GeForce 8400 GS] + +pci:v000010DEd00000423* + ID_MODEL_FROM_DATABASE=G86 [GeForce 8300 GS] + +pci:v000010DEd00000424* + ID_MODEL_FROM_DATABASE=G86 [GeForce 8400 GS] + +pci:v000010DEd00000425* + ID_MODEL_FROM_DATABASE=G86M [GeForce 8600M GS] + +pci:v000010DEd00000425sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v000010DEd00000426* + ID_MODEL_FROM_DATABASE=G86M [GeForce 8400M GT] + +pci:v000010DEd00000427* + ID_MODEL_FROM_DATABASE=G86M [GeForce 8400M GS] + +pci:v000010DEd00000427sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v000010DEd00000427sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000428* + ID_MODEL_FROM_DATABASE=G86M [GeForce 8400M G] + +pci:v000010DEd00000429* + ID_MODEL_FROM_DATABASE=G86M [Quadro NVS 140M] + +pci:v000010DEd00000429sv000017AAsd000020D8* + ID_MODEL_FROM_DATABASE=ThinkPad T61 + +pci:v000010DEd0000042A* + ID_MODEL_FROM_DATABASE=G86M [Quadro NVS 130M] + +pci:v000010DEd0000042B* + ID_MODEL_FROM_DATABASE=G86M [Quadro NVS 135M] + +pci:v000010DEd0000042C* + ID_MODEL_FROM_DATABASE=G86 [GeForce 9400 GT] + +pci:v000010DEd0000042D* + ID_MODEL_FROM_DATABASE=G86GLM [Quadro FX 360M] + +pci:v000010DEd0000042E* + ID_MODEL_FROM_DATABASE=G86M [GeForce 9300M G] + +pci:v000010DEd0000042F* + ID_MODEL_FROM_DATABASE=G86 [Quadro NVS 290] + +pci:v000010DEd00000440* + ID_MODEL_FROM_DATABASE=MCP65 LPC Bridge + +pci:v000010DEd00000441* + ID_MODEL_FROM_DATABASE=MCP65 LPC Bridge + +pci:v000010DEd00000442* + ID_MODEL_FROM_DATABASE=MCP65 LPC Bridge + +pci:v000010DEd00000442sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000443* + ID_MODEL_FROM_DATABASE=MCP65 LPC Bridge + +pci:v000010DEd00000444* + ID_MODEL_FROM_DATABASE=MCP65 Memory Controller + +pci:v000010DEd00000444sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000445* + ID_MODEL_FROM_DATABASE=MCP65 Memory Controller + +pci:v000010DEd00000446* + ID_MODEL_FROM_DATABASE=MCP65 SMBus + +pci:v000010DEd00000446sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000447* + ID_MODEL_FROM_DATABASE=MCP65 SMU + +pci:v000010DEd00000447sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000448* + ID_MODEL_FROM_DATABASE=MCP65 IDE + +pci:v000010DEd00000448sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000449* + ID_MODEL_FROM_DATABASE=MCP65 PCI bridge + +pci:v000010DEd00000449sv000010DEsd0000CB84* + ID_MODEL_FROM_DATABASE=HP Pavilion dv9668eg Laptop + +pci:v000010DEd0000044A* + ID_MODEL_FROM_DATABASE=MCP65 High Definition Audio + +pci:v000010DEd0000044Asv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd0000044B* + ID_MODEL_FROM_DATABASE=MCP65 High Definition Audio + +pci:v000010DEd0000044C* + ID_MODEL_FROM_DATABASE=MCP65 AHCI Controller + +pci:v000010DEd0000044D* + ID_MODEL_FROM_DATABASE=MCP65 AHCI Controller + +pci:v000010DEd0000044E* + ID_MODEL_FROM_DATABASE=MCP65 AHCI Controller + +pci:v000010DEd0000044F* + ID_MODEL_FROM_DATABASE=MCP65 AHCI Controller + +pci:v000010DEd00000450* + ID_MODEL_FROM_DATABASE=MCP65 Ethernet + +pci:v000010DEd00000450sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000451* + ID_MODEL_FROM_DATABASE=MCP65 Ethernet + +pci:v000010DEd00000452* + ID_MODEL_FROM_DATABASE=MCP65 Ethernet + +pci:v000010DEd00000453* + ID_MODEL_FROM_DATABASE=MCP65 Ethernet + +pci:v000010DEd00000454* + ID_MODEL_FROM_DATABASE=MCP65 USB 1.1 OHCI Controller + +pci:v000010DEd00000454sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000455* + ID_MODEL_FROM_DATABASE=MCP65 USB 2.0 EHCI Controller + +pci:v000010DEd00000455sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd00000456* + ID_MODEL_FROM_DATABASE=MCP65 USB Controller + +pci:v000010DEd00000457* + ID_MODEL_FROM_DATABASE=MCP65 USB Controller + +pci:v000010DEd00000458* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd00000458sv000010DEsd00000000* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd00000459* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd00000459sv000010DEsd00000000* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd0000045A* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd0000045Asv000010DEsd00000000* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd0000045B* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd0000045Bsv000010DEsd00000000* + ID_MODEL_FROM_DATABASE=MCP65 PCI Express bridge + +pci:v000010DEd0000045C* + ID_MODEL_FROM_DATABASE=MCP65 SATA Controller + +pci:v000010DEd0000045D* + ID_MODEL_FROM_DATABASE=MCP65 SATA Controller + +pci:v000010DEd0000045Dsv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v000010DEd0000045E* + ID_MODEL_FROM_DATABASE=MCP65 SATA Controller + +pci:v000010DEd0000045F* + ID_MODEL_FROM_DATABASE=MCP65 SATA Controller + +pci:v000010DEd00000531* + ID_MODEL_FROM_DATABASE=C67 [GeForce 7150M / nForce 630M] + +pci:v000010DEd00000533* + ID_MODEL_FROM_DATABASE=C67 [GeForce 7000M / nForce 610M] + +pci:v000010DEd0000053A* + ID_MODEL_FROM_DATABASE=C68 [GeForce 7050 PV / nForce 630a] + +pci:v000010DEd0000053B* + ID_MODEL_FROM_DATABASE=C68 [GeForce 7050 PV / nForce 630a] + +pci:v000010DEd0000053Bsv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherbord + +pci:v000010DEd0000053E* + ID_MODEL_FROM_DATABASE=C68 [GeForce 7025 / nForce 630a] + +pci:v000010DEd00000541* + ID_MODEL_FROM_DATABASE=MCP67 Memory Controller + +pci:v000010DEd00000542* + ID_MODEL_FROM_DATABASE=MCP67 SMBus + +pci:v000010DEd00000542sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherbord + +pci:v000010DEd00000543* + ID_MODEL_FROM_DATABASE=MCP67 Co-processor + +pci:v000010DEd00000547* + ID_MODEL_FROM_DATABASE=MCP67 Memory Controller + +pci:v000010DEd00000547sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherbord + +pci:v000010DEd00000547sv00001849sd00000547* + ID_MODEL_FROM_DATABASE=ALiveNF7G-HDready + +pci:v000010DEd00000548* + ID_MODEL_FROM_DATABASE=MCP67 ISA Bridge + +pci:v000010DEd00000548sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd0000054C* + ID_MODEL_FROM_DATABASE=MCP67 Ethernet + +pci:v000010DEd0000054Csv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherbord + +pci:v000010DEd0000054Csv00001849sd0000054C* + ID_MODEL_FROM_DATABASE=ALiveNF7G-HDready, MCP67 Gigabit Ethernet + +pci:v000010DEd0000054D* + ID_MODEL_FROM_DATABASE=MCP67 Ethernet + +pci:v000010DEd0000054E* + ID_MODEL_FROM_DATABASE=MCP67 Ethernet + +pci:v000010DEd0000054F* + ID_MODEL_FROM_DATABASE=MCP67 Ethernet + +pci:v000010DEd00000550* + ID_MODEL_FROM_DATABASE=MCP67 AHCI Controller + +pci:v000010DEd00000550sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd00000554* + ID_MODEL_FROM_DATABASE=MCP67 AHCI Controller + +pci:v000010DEd00000554sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd00000555* + ID_MODEL_FROM_DATABASE=MCP67 SATA Controller + +pci:v000010DEd00000555sv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd0000055C* + ID_MODEL_FROM_DATABASE=MCP67 High Definition Audio + +pci:v000010DEd0000055Csv00001043sd00008290* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd0000055D* + ID_MODEL_FROM_DATABASE=MCP67 High Definition Audio + +pci:v000010DEd0000055E* + ID_MODEL_FROM_DATABASE=MCP67 OHCI USB 1.1 Controller + +pci:v000010DEd0000055Esv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd0000055F* + ID_MODEL_FROM_DATABASE=MCP67 EHCI USB 2.0 Controller + +pci:v000010DEd0000055Fsv00001043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd00000560* + ID_MODEL_FROM_DATABASE=MCP67 IDE Controller + +pci:v000010DEd00000560sv0000F043sd00008308* + ID_MODEL_FROM_DATABASE=M2N68-AM Motherboard + +pci:v000010DEd00000561* + ID_MODEL_FROM_DATABASE=MCP67 PCI Bridge + +pci:v000010DEd00000562* + ID_MODEL_FROM_DATABASE=MCP67 PCI Express Bridge + +pci:v000010DEd00000562sv00001849sd00000562* + ID_MODEL_FROM_DATABASE=ALiveNF7G-HDready + +pci:v000010DEd00000563* + ID_MODEL_FROM_DATABASE=MCP67 PCI Express Bridge + +pci:v000010DEd00000568* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] Memory Controller + +pci:v000010DEd00000568sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000568sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000568sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000568sv00001849sd00000568* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 Memory Controller + +pci:v000010DEd00000569* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] PCI Express Bridge + +pci:v000010DEd00000569sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000569sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000569sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000569sv00001849sd00000569* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 PCI Express Bridge + +pci:v000010DEd0000056A* + ID_MODEL_FROM_DATABASE=MCP73 [nForce 630i] USB 2.0 Controller (EHCI) + +pci:v000010DEd0000056Asv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd0000056C* + ID_MODEL_FROM_DATABASE=MCP73 IDE + +pci:v000010DEd0000056Csv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd0000056Csv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd0000056D* + ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge + +pci:v000010DEd0000056Dsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd0000056E* + ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge + +pci:v000010DEd0000056Esv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd0000056F* + ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge + +pci:v000010DEd0000056Fsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000005B1* + ID_MODEL_FROM_DATABASE=NF200 PCIe 2.0 switch + +pci:v000010DEd000005B8* + ID_MODEL_FROM_DATABASE=NF200 PCIe 2.0 switch for GTX 295 + +pci:v000010DEd000005BE* + ID_MODEL_FROM_DATABASE=NF200 PCIe 2.0 switch for Quadro Plex S4 / Tesla S870 / Tesla S1070 / Tesla S2050 + +pci:v000010DEd000005E0* + ID_MODEL_FROM_DATABASE=GT200b [GeForce GTX 295] + +pci:v000010DEd000005E1* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 280] + +pci:v000010DEd000005E2* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 260] + +pci:v000010DEd000005E3* + ID_MODEL_FROM_DATABASE=GT200b [GeForce GTX 285] + +pci:v000010DEd000005E3sv00001682sd00002490* + ID_MODEL_FROM_DATABASE=GX-285N-ZDF + +pci:v000010DEd000005E6* + ID_MODEL_FROM_DATABASE=GT200b [GeForce GTX 275] + +pci:v000010DEd000005E7* + ID_MODEL_FROM_DATABASE=GT200GL [Tesla C1060 / M1060] + +pci:v000010DEd000005E7sv000010DEsd00000595* + ID_MODEL_FROM_DATABASE=Tesla T10 Processor + +pci:v000010DEd000005E7sv000010DEsd0000068F* + ID_MODEL_FROM_DATABASE=Tesla T10 Processor + +pci:v000010DEd000005E7sv000010DEsd00000697* + ID_MODEL_FROM_DATABASE=Tesla M1060 + +pci:v000010DEd000005E7sv000010DEsd00000714* + ID_MODEL_FROM_DATABASE=Tesla M1060 + +pci:v000010DEd000005E7sv000010DEsd00000743* + ID_MODEL_FROM_DATABASE=Tesla M1060 + +pci:v000010DEd000005EA* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 260] + +pci:v000010DEd000005EB* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 295] + +pci:v000010DEd000005ED* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro Plex 2200 D2] + +pci:v000010DEd000005F1* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 280] + +pci:v000010DEd000005F2* + ID_MODEL_FROM_DATABASE=GT200 [GeForce GTX 260] + +pci:v000010DEd000005F8* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro Plex 2200 S4] + +pci:v000010DEd000005F9* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro CX] + +pci:v000010DEd000005FD* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro FX 5800] + +pci:v000010DEd000005FE* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro FX 4800] + +pci:v000010DEd000005FF* + ID_MODEL_FROM_DATABASE=GT200GL [Quadro FX 3800] + +pci:v000010DEd00000600* + ID_MODEL_FROM_DATABASE=G92 [GeForce 8800 GTS 512] + +pci:v000010DEd00000601* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GT] + +pci:v000010DEd00000602* + ID_MODEL_FROM_DATABASE=G92 [GeForce 8800 GT] + +pci:v000010DEd00000603* + ID_MODEL_FROM_DATABASE=G92 [GeForce GT 230 OEM] + +pci:v000010DEd00000604* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GX2] + +pci:v000010DEd00000605* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GT] + +pci:v000010DEd00000606* + ID_MODEL_FROM_DATABASE=G92 [GeForce 8800 GS] + +pci:v000010DEd00000607* + ID_MODEL_FROM_DATABASE=G92 [GeForce GTS 240] + +pci:v000010DEd00000608* + ID_MODEL_FROM_DATABASE=G92M [GeForce 9800M GTX] + +pci:v000010DEd00000609* + ID_MODEL_FROM_DATABASE=G92M [GeForce 8800M GTS] + +pci:v000010DEd00000609sv0000106Bsd000000A7* + ID_MODEL_FROM_DATABASE=GeForce 8800 GS + +pci:v000010DEd0000060A* + ID_MODEL_FROM_DATABASE=G92M [GeForce GTX 280M] + +pci:v000010DEd0000060B* + ID_MODEL_FROM_DATABASE=G92M [GeForce 9800M GT] + +pci:v000010DEd0000060C* + ID_MODEL_FROM_DATABASE=G92M [GeForce 8800M GTX] + +pci:v000010DEd0000060D* + ID_MODEL_FROM_DATABASE=G92 [GeForce 8800 GS] + +pci:v000010DEd0000060F* + ID_MODEL_FROM_DATABASE=G92M [GeForce GTX 285M] + +pci:v000010DEd00000610* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9600 GSO] + +pci:v000010DEd00000610sv00001682sd00002385* + ID_MODEL_FROM_DATABASE=GeForce 9600 GSO 768mb + +pci:v000010DEd00000611* + ID_MODEL_FROM_DATABASE=G92 [GeForce 8800 GT] + +pci:v000010DEd00000611sv0000107Dsd00002AB0* + ID_MODEL_FROM_DATABASE=Winfast PX8800 GT PCI-E + +pci:v000010DEd00000611sv000019DAsd00001040* + ID_MODEL_FROM_DATABASE=ZT-88TES2P-FSP + +pci:v000010DEd00000612* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GTX / 9800 GTX+] + +pci:v000010DEd00000613* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GTX+] + +pci:v000010DEd00000614* + ID_MODEL_FROM_DATABASE=G92 [GeForce 9800 GT] + +pci:v000010DEd00000614sv0000107Dsd00002AB3* + ID_MODEL_FROM_DATABASE=WinFast PX9800 GT (S-Fanpipe) + +pci:v000010DEd00000615* + ID_MODEL_FROM_DATABASE=G92 [GeForce GTS 250] + +pci:v000010DEd00000615sv00003842sd00001150* + ID_MODEL_FROM_DATABASE=GeForce GTS 250 P/N 512-P3-1150-TR + +pci:v000010DEd00000615sv00003842sd00001151* + ID_MODEL_FROM_DATABASE=GeForce GTS 250 P/N 512-P3-1151-TR + +pci:v000010DEd00000615sv00003842sd00001155* + ID_MODEL_FROM_DATABASE=GeForce GTS 250 P/N 01G-P3-1155-TR + +pci:v000010DEd00000615sv00003842sd00001156* + ID_MODEL_FROM_DATABASE=GeForce GTS 250 P/N 01G-P3-1156-TR + +pci:v000010DEd00000617* + ID_MODEL_FROM_DATABASE=G92M [GeForce 9800M GTX] + +pci:v000010DEd00000618* + ID_MODEL_FROM_DATABASE=G92M [GeForce GTX 260M] + +pci:v000010DEd00000619* + ID_MODEL_FROM_DATABASE=G92GL [Quadro FX 4700 X2] + +pci:v000010DEd0000061A* + ID_MODEL_FROM_DATABASE=G92GL [Quadro FX 3700] + +pci:v000010DEd0000061B* + ID_MODEL_FROM_DATABASE=G92GL [Quadro VX 200] + +pci:v000010DEd0000061C* + ID_MODEL_FROM_DATABASE=G92GLM [Quadro FX 3600M] + +pci:v000010DEd0000061D* + ID_MODEL_FROM_DATABASE=G92GLM [Quadro FX 2800M] + +pci:v000010DEd0000061E* + ID_MODEL_FROM_DATABASE=G92GLM [Quadro FX 3700M] + +pci:v000010DEd0000061F* + ID_MODEL_FROM_DATABASE=G92GLM [Quadro FX 3800M] + +pci:v000010DEd00000620* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9800 GT] + +pci:v000010DEd00000621* + ID_MODEL_FROM_DATABASE=G94 [GeForce GT 230] + +pci:v000010DEd00000622* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT] + +pci:v000010DEd00000622sv0000107Dsd00002AC1* + ID_MODEL_FROM_DATABASE=WinFast PX9600GT 1024MB + +pci:v000010DEd00000622sv00001458sd00003481* + ID_MODEL_FROM_DATABASE=GV-NX96T512HP + +pci:v000010DEd00000623* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GS] + +pci:v000010DEd00000624* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT Green Edition] + +pci:v000010DEd00000625* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GSO 512] + +pci:v000010DEd00000626* + ID_MODEL_FROM_DATABASE=G94 [GeForce GT 130] + +pci:v000010DEd00000627* + ID_MODEL_FROM_DATABASE=G94 [GeForce GT 140] + +pci:v000010DEd00000628* + ID_MODEL_FROM_DATABASE=G94M [GeForce 9800M GTS] + +pci:v000010DEd0000062A* + ID_MODEL_FROM_DATABASE=G94M [GeForce 9700M GTS] + +pci:v000010DEd0000062B* + ID_MODEL_FROM_DATABASE=G94M [GeForce 9800M GS] + +pci:v000010DEd0000062C* + ID_MODEL_FROM_DATABASE=G94M [GeForce 9800M GTS] + +pci:v000010DEd0000062D* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT] + +pci:v000010DEd0000062E* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT] + +pci:v000010DEd0000062Esv0000106Bsd00000605* + ID_MODEL_FROM_DATABASE=GeForce GT 130 + +pci:v000010DEd0000062F* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9800 S] + +pci:v000010DEd00000630* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT] + +pci:v000010DEd00000631* + ID_MODEL_FROM_DATABASE=G94M [GeForce GTS 160M] + +pci:v000010DEd00000632* + ID_MODEL_FROM_DATABASE=G94M [GeForce GTS 150M] + +pci:v000010DEd00000633* + ID_MODEL_FROM_DATABASE=G94 [GeForce GT 220] + +pci:v000010DEd00000635* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GSO] + +pci:v000010DEd00000637* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GT] + +pci:v000010DEd00000638* + ID_MODEL_FROM_DATABASE=G94GL [Quadro FX 1800] + +pci:v000010DEd0000063A* + ID_MODEL_FROM_DATABASE=G94GLM [Quadro FX 2700M] + +pci:v000010DEd0000063F* + ID_MODEL_FROM_DATABASE=G94 [GeForce 9600 GE] + +pci:v000010DEd00000640* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GT] + +pci:v000010DEd00000641* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9400 GT] + +pci:v000010DEd00000643* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GT] + +pci:v000010DEd00000644* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GS] + +pci:v000010DEd00000645* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GS] + +pci:v000010DEd00000646* + ID_MODEL_FROM_DATABASE=G96 [GeForce GT 120] + +pci:v000010DEd00000647* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9600M GT] + +pci:v000010DEd00000648* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9600M GS] + +pci:v000010DEd00000649* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9600M GT] + +pci:v000010DEd00000649sv00001043sd0000202D* + ID_MODEL_FROM_DATABASE=GeForce GT 220M + +pci:v000010DEd0000064A* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9700M GT] + +pci:v000010DEd0000064B* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9500M G] + +pci:v000010DEd0000064C* + ID_MODEL_FROM_DATABASE=G96M [GeForce 9650M GT] + +pci:v000010DEd0000064D* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9600 GT] + +pci:v000010DEd0000064E* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9600 GT / 9800 GT] + +pci:v000010DEd00000651* + ID_MODEL_FROM_DATABASE=G96M [GeForce G 110M] + +pci:v000010DEd00000652* + ID_MODEL_FROM_DATABASE=G96M [GeForce GT 130M] + +pci:v000010DEd00000652sv0000152Dsd00000850* + ID_MODEL_FROM_DATABASE=GeForce GT 240M LE + +pci:v000010DEd00000653* + ID_MODEL_FROM_DATABASE=G96M [GeForce GT 120M] + +pci:v000010DEd00000654* + ID_MODEL_FROM_DATABASE=G96M [GeForce GT 220M] + +pci:v000010DEd00000654sv00001043sd000014A2* + ID_MODEL_FROM_DATABASE=GeForce GT 320M + +pci:v000010DEd00000654sv00001043sd000014D2* + ID_MODEL_FROM_DATABASE=GeForce GT 320M + +pci:v000010DEd00000655* + ID_MODEL_FROM_DATABASE=G96 [GeForce GT 120] + +pci:v000010DEd00000656* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9650 S] + +pci:v000010DEd00000658* + ID_MODEL_FROM_DATABASE=G96GL [Quadro FX 380] + +pci:v000010DEd00000659* + ID_MODEL_FROM_DATABASE=G96GL [Quadro FX 580] + +pci:v000010DEd0000065A* + ID_MODEL_FROM_DATABASE=G96GLM [Quadro FX 1700M] + +pci:v000010DEd0000065B* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9400 GT] + +pci:v000010DEd0000065C* + ID_MODEL_FROM_DATABASE=G96GLM [Quadro FX 770M] + +pci:v000010DEd0000065D* + ID_MODEL_FROM_DATABASE=G96 [GeForce 9500 GA / 9600 GT / GTS 250] + +pci:v000010DEd0000065F* + ID_MODEL_FROM_DATABASE=G96 [GeForce G210] + +pci:v000010DEd000006C0* + ID_MODEL_FROM_DATABASE=GF100 [GeForce GTX 480] + +pci:v000010DEd000006C4* + ID_MODEL_FROM_DATABASE=GF100 [GeForce GTX 465] + +pci:v000010DEd000006CA* + ID_MODEL_FROM_DATABASE=GF100M [GeForce GTX 480M] + +pci:v000010DEd000006CB* + ID_MODEL_FROM_DATABASE=GF100 [GeForce GTX 480] + +pci:v000010DEd000006CD* + ID_MODEL_FROM_DATABASE=GF100 [GeForce GTX 470] + +pci:v000010DEd000006D1* + ID_MODEL_FROM_DATABASE=GF100GL [Tesla C2050 / C2070] + +pci:v000010DEd000006D1sv000010DEsd00000771* + ID_MODEL_FROM_DATABASE=Tesla C2050 + +pci:v000010DEd000006D1sv000010DEsd00000772* + ID_MODEL_FROM_DATABASE=Tesla C2070 + +pci:v000010DEd000006D2* + ID_MODEL_FROM_DATABASE=GF100GL [Tesla M2070] + +pci:v000010DEd000006D2sv000010DEsd00000774* + ID_MODEL_FROM_DATABASE=Tesla M2070 + +pci:v000010DEd000006D2sv000010DEsd00000830* + ID_MODEL_FROM_DATABASE=Tesla M2070 + +pci:v000010DEd000006D2sv000010DEsd00000842* + ID_MODEL_FROM_DATABASE=Tesla M2070 + +pci:v000010DEd000006D2sv000010DEsd0000088F* + ID_MODEL_FROM_DATABASE=Tesla X2070 + +pci:v000010DEd000006D2sv000010DEsd00000908* + ID_MODEL_FROM_DATABASE=Tesla M2070 + +pci:v000010DEd000006D8* + ID_MODEL_FROM_DATABASE=GF100GL [Quadro 6000] + +pci:v000010DEd000006D9* + ID_MODEL_FROM_DATABASE=GF100GL [Quadro 5000] + +pci:v000010DEd000006DA* + ID_MODEL_FROM_DATABASE=GF100GLM [Quadro 5000M] + +pci:v000010DEd000006DC* + ID_MODEL_FROM_DATABASE=GF100GL [Quadro 6000] + +pci:v000010DEd000006DD* + ID_MODEL_FROM_DATABASE=GF100GL [Quadro 4000] + +pci:v000010DEd000006DE* + ID_MODEL_FROM_DATABASE=GF100GL [Tesla T20 Processor] + +pci:v000010DEd000006DEsv000010DEsd00000773* + ID_MODEL_FROM_DATABASE=Tesla S2050 + +pci:v000010DEd000006DEsv000010DEsd0000082F* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DEsv000010DEsd00000840* + ID_MODEL_FROM_DATABASE=Tesla X2070 + +pci:v000010DEd000006DEsv000010DEsd00000842* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DEsv000010DEsd00000846* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DEsv000010DEsd00000866* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DEsv000010DEsd00000907* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DEsv000010DEsd0000091E* + ID_MODEL_FROM_DATABASE=Tesla M2050 + +pci:v000010DEd000006DF* + ID_MODEL_FROM_DATABASE=GF100GL [Tesla M2070-Q] + +pci:v000010DEd000006DFsv000010DEsd0000084D* + ID_MODEL_FROM_DATABASE=Tesla M2070-Q + +pci:v000010DEd000006DFsv000010DEsd0000087F* + ID_MODEL_FROM_DATABASE=Tesla M2070-Q + +pci:v000010DEd000006E0* + ID_MODEL_FROM_DATABASE=G98 [GeForce 9300 GE] + +pci:v000010DEd000006E1* + ID_MODEL_FROM_DATABASE=G98 [GeForce 9300 GS] + +pci:v000010DEd000006E2* + ID_MODEL_FROM_DATABASE=G98 [GeForce 8400] + +pci:v000010DEd000006E3* + ID_MODEL_FROM_DATABASE=G98 [GeForce 8300 GS] + +pci:v000010DEd000006E4* + ID_MODEL_FROM_DATABASE=G98 [GeForce 8400 GS Rev. 2] + +pci:v000010DEd000006E4sv00001458sd00003475* + ID_MODEL_FROM_DATABASE=GV-NX84S256HE [GeForce 8400 GS] + +pci:v000010DEd000006E5* + ID_MODEL_FROM_DATABASE=G98M [GeForce 9300M GS] + +pci:v000010DEd000006E6* + ID_MODEL_FROM_DATABASE=G98 [GeForce G 100] + +pci:v000010DEd000006E7* + ID_MODEL_FROM_DATABASE=G98 [GeForce 9300 SE] + +pci:v000010DEd000006E8* + ID_MODEL_FROM_DATABASE=G98M [GeForce 9200M GS] + +pci:v000010DEd000006E8sv0000103Csd0000360B* + ID_MODEL_FROM_DATABASE=GeForce 9200M GE + +pci:v000010DEd000006E9* + ID_MODEL_FROM_DATABASE=G98M [GeForce 9300M GS] + +pci:v000010DEd000006E9sv00001043sd000019B2* + ID_MODEL_FROM_DATABASE=U6V laptop + +pci:v000010DEd000006EA* + ID_MODEL_FROM_DATABASE=G98M [Quadro NVS 150M] + +pci:v000010DEd000006EB* + ID_MODEL_FROM_DATABASE=G98M [Quadro NVS 160M] + +pci:v000010DEd000006EC* + ID_MODEL_FROM_DATABASE=G98M [GeForce G 105M] + +pci:v000010DEd000006ED* + ID_MODEL_FROM_DATABASE=G98 [GeForce 9600 GT / 9800 GT] + +pci:v000010DEd000006EE* + ID_MODEL_FROM_DATABASE=G98 [GeForce 9600 GT / 9800 GT] + +pci:v000010DEd000006EF* + ID_MODEL_FROM_DATABASE=G98M [GeForce G 103M] + +pci:v000010DEd000006F1* + ID_MODEL_FROM_DATABASE=G98M [GeForce G 105M] + +pci:v000010DEd000006F8* + ID_MODEL_FROM_DATABASE=G98 [Quadro NVS 420] + +pci:v000010DEd000006F9* + ID_MODEL_FROM_DATABASE=G98GL [Quadro FX 370 LP] + +pci:v000010DEd000006FA* + ID_MODEL_FROM_DATABASE=G98 [Quadro NVS 450] + +pci:v000010DEd000006FB* + ID_MODEL_FROM_DATABASE=G98GLM [Quadro FX 370M] + +pci:v000010DEd000006FD* + ID_MODEL_FROM_DATABASE=G98 [Quadro NVS 295] + +pci:v000010DEd000006FF* + ID_MODEL_FROM_DATABASE=G98 [HICx16 + Graphics] + +pci:v000010DEd000006FFsv000010DEsd00000711* + ID_MODEL_FROM_DATABASE=HICx8 + Graphics + +pci:v000010DEd00000751* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] Memory Controller + +pci:v000010DEd00000751sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000751sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000751sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000751sv00001849sd00000751* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 Memory Controller + +pci:v000010DEd00000752* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] SMBus + +pci:v000010DEd00000752sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000752sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000752sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000752sv00001849sd00000752* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 SMBus + +pci:v000010DEd00000753* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] Co-Processor + +pci:v000010DEd00000753sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000753sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000753sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000753sv00001849sd00000753* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 Co-Processor + +pci:v000010DEd00000754* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] Memory Controller + +pci:v000010DEd00000754sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000754sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000754sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000754sv00001849sd00000754* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 Memory Controller + +pci:v000010DEd00000759* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] IDE + +pci:v000010DEd00000759sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000759sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000759sv00001849sd00000759* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 IDE + +pci:v000010DEd0000075A* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] PCI Bridge + +pci:v000010DEd0000075Asv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000075Asv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000075Asv00001849sd0000075A* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 PCI Bridge + +pci:v000010DEd0000075B* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] PCI Express Bridge + +pci:v000010DEd0000075Bsv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000075Bsv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000075Bsv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000075Bsv00001849sd0000075B* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 PCI Express Bridge + +pci:v000010DEd0000075C* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] LPC Bridge + +pci:v000010DEd0000075Csv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000075Csv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000075Csv00001849sd0000075C* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 LPC Bridge + +pci:v000010DEd0000075D* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] LPC Bridge + +pci:v000010DEd0000075Dsv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000760* + ID_MODEL_FROM_DATABASE=MCP77 Ethernet + +pci:v000010DEd00000760sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000760sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000760sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000760sv00001849sd00000760* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 Ethernet + +pci:v000010DEd00000761* + ID_MODEL_FROM_DATABASE=MCP77 Ethernet + +pci:v000010DEd00000762* + ID_MODEL_FROM_DATABASE=MCP77 Ethernet + +pci:v000010DEd00000763* + ID_MODEL_FROM_DATABASE=MCP77 Ethernet + +pci:v000010DEd00000774* + ID_MODEL_FROM_DATABASE=MCP72XE/MCP72P/MCP78U/MCP78S High Definition Audio + +pci:v000010DEd00000774sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000774sv00001043sd000082FE* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000774sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000774sv00001849sd00003662* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 High Definition Audio + +pci:v000010DEd00000778* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] PCI Express Bridge + +pci:v000010DEd00000778sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000778sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000778sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000778sv00001849sd00000778* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 PCI Express Bridge + +pci:v000010DEd0000077A* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] PCI Bridge + +pci:v000010DEd0000077Asv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000077Asv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000077Asv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000077Asv00001849sd0000077A* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 PCI Bridge + +pci:v000010DEd0000077B* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] OHCI USB 1.1 Controller + +pci:v000010DEd0000077Bsv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000077Bsv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000077Bsv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000077Bsv00001849sd0000077B* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 OHCI USB 1.1 Controller + +pci:v000010DEd0000077C* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] EHCI USB 2.0 Controller + +pci:v000010DEd0000077Csv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000077Csv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000077Csv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000077Csv00001849sd0000077C* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 EHCI USB 2.0 Controller + +pci:v000010DEd0000077D* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] OHCI USB 1.1 Controller + +pci:v000010DEd0000077Dsv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000077Dsv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000077Dsv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000077Dsv00001849sd0000077D* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 OHCI USB 1.1 Controller + +pci:v000010DEd0000077E* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] EHCI USB 2.0 Controller + +pci:v000010DEd0000077Esv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd0000077Esv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd0000077Esv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd0000077Esv00001849sd0000077E* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 EHCI USB 2.0 Controller + +pci:v000010DEd000007C0* + ID_MODEL_FROM_DATABASE=MCP73 Host Bridge + +pci:v000010DEd000007C0sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007C1* + ID_MODEL_FROM_DATABASE=MCP73 Host Bridge + +pci:v000010DEd000007C1sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007C2* + ID_MODEL_FROM_DATABASE=MCP73 Host Bridge + +pci:v000010DEd000007C5* + ID_MODEL_FROM_DATABASE=MCP73 Host Bridge + +pci:v000010DEd000007C8* + ID_MODEL_FROM_DATABASE=MCP73 Memory Controller + +pci:v000010DEd000007C8sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007C8sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007CB* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007CBsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007CBsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007CD* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007CDsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007CDsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007CE* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007CEsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007CEsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007CF* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007CFsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007CFsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D0* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007D0sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D0sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D1* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007D1sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D1sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D2* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007D2sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D2sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D3* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007D3sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D3sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D6* + ID_MODEL_FROM_DATABASE=nForce 630i memory controller + +pci:v000010DEd000007D6sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D6sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D7* + ID_MODEL_FROM_DATABASE=MCP73 LPC Bridge + +pci:v000010DEd000007D7sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D7sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D8* + ID_MODEL_FROM_DATABASE=MCP73 SMBus + +pci:v000010DEd000007D8sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D8sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007D9* + ID_MODEL_FROM_DATABASE=MCP73 Memory Controller + +pci:v000010DEd000007D9sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007D9sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007DA* + ID_MODEL_FROM_DATABASE=MCP73 Co-processor + +pci:v000010DEd000007DAsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007DC* + ID_MODEL_FROM_DATABASE=MCP73 Ethernet + +pci:v000010DEd000007DD* + ID_MODEL_FROM_DATABASE=MCP73 Ethernet + +pci:v000010DEd000007DE* + ID_MODEL_FROM_DATABASE=MCP73 Ethernet + +pci:v000010DEd000007DF* + ID_MODEL_FROM_DATABASE=MCP73 Ethernet + +pci:v000010DEd000007E0* + ID_MODEL_FROM_DATABASE=C73 [GeForce 7150 / nForce 630i] + +pci:v000010DEd000007E0sv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd000007E1* + ID_MODEL_FROM_DATABASE=C73 [GeForce 7100 / nForce 630i] + +pci:v000010DEd000007E1sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007E2* + ID_MODEL_FROM_DATABASE=C73 [GeForce 7050 / nForce 630i] + +pci:v000010DEd000007E3* + ID_MODEL_FROM_DATABASE=C73 [GeForce 7050 / nForce 610i] + +pci:v000010DEd000007E5* + ID_MODEL_FROM_DATABASE=C73 [GeForce 7100 / nForce 620i] + +pci:v000010DEd000007F0* + ID_MODEL_FROM_DATABASE=MCP73 IDE + +pci:v000010DEd000007F4* + ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i SATA + +pci:v000010DEd000007F4sv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007F8* + ID_MODEL_FROM_DATABASE=MCP73 SATA RAID Controller + +pci:v000010DEd000007FC* + ID_MODEL_FROM_DATABASE=MCP73 High Definition Audio + +pci:v000010DEd000007FCsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007FCsv000010DEsd000007FC* + ID_MODEL_FROM_DATABASE=MCP73 High Definition Audio + +pci:v000010DEd000007FE* + ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i USB + +pci:v000010DEd000007FEsv00001019sd0000297A* + ID_MODEL_FROM_DATABASE=MCP73PVT-SM + +pci:v000010DEd000007FEsv00001AFAsd00007150* + ID_MODEL_FROM_DATABASE=JW-IN7150-HD + +pci:v000010DEd00000840* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8200M] + +pci:v000010DEd00000844* + ID_MODEL_FROM_DATABASE=C77 [GeForce 9100M G] + +pci:v000010DEd00000845* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8200M G] + +pci:v000010DEd00000846* + ID_MODEL_FROM_DATABASE=C77 [GeForce 9200] + +pci:v000010DEd00000847* + ID_MODEL_FROM_DATABASE=C78 [GeForce 9100] + +pci:v000010DEd00000847sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000848* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8300] + +pci:v000010DEd00000849* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8200] + +pci:v000010DEd00000849sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000849sv00001849sd00000849* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 GeForce 8200 + +pci:v000010DEd0000084A* + ID_MODEL_FROM_DATABASE=C77 [nForce 730a] + +pci:v000010DEd0000084B* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8200] + +pci:v000010DEd0000084C* + ID_MODEL_FROM_DATABASE=C77 [nForce 780a/980a SLI] + +pci:v000010DEd0000084D* + ID_MODEL_FROM_DATABASE=C77 [nForce 750a SLI] + +pci:v000010DEd0000084Dsv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D mGPU + +pci:v000010DEd0000084F* + ID_MODEL_FROM_DATABASE=C77 [GeForce 8100 / nForce 720a] + +pci:v000010DEd00000860* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9300] + +pci:v000010DEd00000861* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400] + +pci:v000010DEd00000862* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400M G] + +pci:v000010DEd00000863* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400M] + +pci:v000010DEd00000863sv0000106Bsd000000AA* + ID_MODEL_FROM_DATABASE=MacBook5,1 + +pci:v000010DEd00000864* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9300] + +pci:v000010DEd00000865* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9300/ION] + +pci:v000010DEd00000866* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400M G] + +pci:v000010DEd00000866sv0000106Bsd000000B1* + ID_MODEL_FROM_DATABASE=GeForce 9400M + +pci:v000010DEd00000867* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400] + +pci:v000010DEd00000867sv0000106Bsd000000AD* + ID_MODEL_FROM_DATABASE=iMac 9,1 + +pci:v000010DEd00000868* + ID_MODEL_FROM_DATABASE=C79 [nForce 760i SLI] + +pci:v000010DEd00000869* + ID_MODEL_FROM_DATABASE=MCP7A [GeForce 9400] + +pci:v000010DEd0000086A* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400] + +pci:v000010DEd0000086C* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9300 / nForce 730i] + +pci:v000010DEd0000086D* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9200] + +pci:v000010DEd0000086E* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9100M G] + +pci:v000010DEd0000086F* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9200M G] + +pci:v000010DEd00000870* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400M] + +pci:v000010DEd00000871* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9200] + +pci:v000010DEd00000872* + ID_MODEL_FROM_DATABASE=C79 [GeForce G102M] + +pci:v000010DEd00000872sv00001043sd000019B4* + ID_MODEL_FROM_DATABASE=GeForce G102M + +pci:v000010DEd00000872sv00001043sd00001AA2* + ID_MODEL_FROM_DATABASE=GeForce G102M + +pci:v000010DEd00000872sv00001043sd00001C02* + ID_MODEL_FROM_DATABASE=GeForce G102M + +pci:v000010DEd00000872sv00001043sd00001C42* + ID_MODEL_FROM_DATABASE=GeForce G205M + +pci:v000010DEd00000873* + ID_MODEL_FROM_DATABASE=C79 [GeForce G102M] + +pci:v000010DEd00000873sv00001043sd000019B4* + ID_MODEL_FROM_DATABASE=GeForce G102M + +pci:v000010DEd00000873sv00001043sd00001C12* + ID_MODEL_FROM_DATABASE=GeForce G102M + +pci:v000010DEd00000873sv00001043sd00001C52* + ID_MODEL_FROM_DATABASE=GeForce G205M + +pci:v000010DEd00000874* + ID_MODEL_FROM_DATABASE=C79 [ION] + +pci:v000010DEd00000876* + ID_MODEL_FROM_DATABASE=ION VGA [GeForce 9400M] + +pci:v000010DEd0000087A* + ID_MODEL_FROM_DATABASE=C79 [GeForce 9400] + +pci:v000010DEd0000087D* + ID_MODEL_FROM_DATABASE=ION VGA + +pci:v000010DEd0000087Dsv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd0000087E* + ID_MODEL_FROM_DATABASE=ION LE VGA + +pci:v000010DEd0000087F* + ID_MODEL_FROM_DATABASE=ION LE VGA + +pci:v000010DEd000008A0* + ID_MODEL_FROM_DATABASE=MCP89 [GeForce 320M] + +pci:v000010DEd000008A2* + ID_MODEL_FROM_DATABASE=MCP89 [GeForce 320M] + +pci:v000010DEd000008A3* + ID_MODEL_FROM_DATABASE=MCP89 [GeForce 320M] + +pci:v000010DEd000008A4* + ID_MODEL_FROM_DATABASE=MCP89 [GeForce 320M] + +pci:v000010DEd000008A5* + ID_MODEL_FROM_DATABASE=MCP89 [GeForce 320M] + +pci:v000010DEd00000A20* + ID_MODEL_FROM_DATABASE=GT216 [GeForce GT 220] + +pci:v000010DEd00000A20sv00001043sd00008311* + ID_MODEL_FROM_DATABASE=ENGT220/DI/1GD3(LP)/V2 + +pci:v000010DEd00000A21* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 330M] + +pci:v000010DEd00000A22* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 315] + +pci:v000010DEd00000A23* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 210] + +pci:v000010DEd00000A26* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 405] + +pci:v000010DEd00000A27* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 405] + +pci:v000010DEd00000A28* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 230M] + +pci:v000010DEd00000A29* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 330M] + +pci:v000010DEd00000A2A* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 230M] + +pci:v000010DEd00000A2B* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 330M] + +pci:v000010DEd00000A2C* + ID_MODEL_FROM_DATABASE=GT216M [NVS 5100M] + +pci:v000010DEd00000A2D* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 320M] + +pci:v000010DEd00000A30* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 505] + +pci:v000010DEd00000A32* + ID_MODEL_FROM_DATABASE=GT216 [GeForce GT 415] + +pci:v000010DEd00000A34* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 240M] + +pci:v000010DEd00000A35* + ID_MODEL_FROM_DATABASE=GT216M [GeForce GT 325M] + +pci:v000010DEd00000A38* + ID_MODEL_FROM_DATABASE=GT216GL [Quadro 400] + +pci:v000010DEd00000A3C* + ID_MODEL_FROM_DATABASE=GT216GLM [Quadro FX 880M] + +pci:v000010DEd00000A60* + ID_MODEL_FROM_DATABASE=GT218 [GeForce G210] + +pci:v000010DEd00000A62* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 205] + +pci:v000010DEd00000A63* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 310] + +pci:v000010DEd00000A64* + ID_MODEL_FROM_DATABASE=GT218 [ION] + +pci:v000010DEd00000A65* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 210] + +pci:v000010DEd00000A65sv00001043sd00008334* + ID_MODEL_FROM_DATABASE=EN210 SILENT + +pci:v000010DEd00000A66* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 310] + +pci:v000010DEd00000A67* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 315] + +pci:v000010DEd00000A68* + ID_MODEL_FROM_DATABASE=GT218M [GeForce G 105M] + +pci:v000010DEd00000A69* + ID_MODEL_FROM_DATABASE=GT218M [GeForce G 105M] + +pci:v000010DEd00000A6A* + ID_MODEL_FROM_DATABASE=GT218M [NVS 2100M] + +pci:v000010DEd00000A6C* + ID_MODEL_FROM_DATABASE=GT218M [NVS 3100M] + +pci:v000010DEd00000A6Csv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v000010DEd00000A6Csv000017AAsd00002142* + ID_MODEL_FROM_DATABASE=ThinkPad T410 + +pci:v000010DEd00000A6E* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 305M] + +pci:v000010DEd00000A6F* + ID_MODEL_FROM_DATABASE=GT218 [ION] + +pci:v000010DEd00000A70* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 310M] + +pci:v000010DEd00000A71* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 305M] + +pci:v000010DEd00000A72* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 310M] + +pci:v000010DEd00000A73* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 305M] + +pci:v000010DEd00000A74* + ID_MODEL_FROM_DATABASE=GT218M [GeForce G210M] + +pci:v000010DEd00000A74sv00001B0Asd0000903A* + ID_MODEL_FROM_DATABASE=GeForce G210 + +pci:v000010DEd00000A75* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 310M] + +pci:v000010DEd00000A76* + ID_MODEL_FROM_DATABASE=GT218 [ION 2] + +pci:v000010DEd00000A78* + ID_MODEL_FROM_DATABASE=GT218GL [Quadro FX 380 LP] + +pci:v000010DEd00000A7A* + ID_MODEL_FROM_DATABASE=GT218M [GeForce 315M] + +pci:v000010DEd00000A7Asv0000104Dsd0000907E* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FC50* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FC61* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FC71* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FC90* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FCC0* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FCD0* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FCE2* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FCF2* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD16* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD40* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD50* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD52* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD61* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD71* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD92* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FD96* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FDD0* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FDD2* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001179sd0000FDFE* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C0A2* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C0B2* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C581* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C587* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C588* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C597* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv0000144Dsd0000C606* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001462sd0000AA51* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001462sd0000AA58* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001462sd0000AC71* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001462sd0000AC81* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001462sd0000AC82* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001462sd0000AE33* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001642sd00003980* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv000017AAsd00003950* + ID_MODEL_FROM_DATABASE=GeForce 405M + +pci:v000010DEd00000A7Asv000017AAsd0000397D* + ID_MODEL_FROM_DATABASE=GeForce 405M + +pci:v000010DEd00000A7Asv00001B0Asd00002091* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7Asv00001B0Asd000090B4* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001BFDsd00000003* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001BFDsd00008006* + ID_MODEL_FROM_DATABASE=GeForce 405 + +pci:v000010DEd00000A7Asv00001BFDsd00008007* + ID_MODEL_FROM_DATABASE=GeForce 315M + +pci:v000010DEd00000A7B* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 505] + +pci:v000010DEd00000A7C* + ID_MODEL_FROM_DATABASE=GT218GLM [Quadro FX 380M] + +pci:v000010DEd00000A80* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A81* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A82* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A83* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A84* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A85* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A86* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A87* + ID_MODEL_FROM_DATABASE=MCP79 Host Bridge + +pci:v000010DEd00000A88* + ID_MODEL_FROM_DATABASE=MCP79 Memory Controller + +pci:v000010DEd00000A89* + ID_MODEL_FROM_DATABASE=MCP79 Memory Controller + +pci:v000010DEd00000A98* + ID_MODEL_FROM_DATABASE=MCP79 Memory Controller + +pci:v000010DEd00000A98sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=iMac 9,1 + +pci:v000010DEd00000AA0* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AA0sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA2* + ID_MODEL_FROM_DATABASE=MCP79 SMBus + +pci:v000010DEd00000AA2sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA2sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA3* + ID_MODEL_FROM_DATABASE=MCP79 Co-processor + +pci:v000010DEd00000AA3sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA3sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA4* + ID_MODEL_FROM_DATABASE=MCP79 Memory Controller + +pci:v000010DEd00000AA4sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA5* + ID_MODEL_FROM_DATABASE=MCP79 OHCI USB 1.1 Controller + +pci:v000010DEd00000AA5sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA5sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA6* + ID_MODEL_FROM_DATABASE=MCP79 EHCI USB 2.0 Controller + +pci:v000010DEd00000AA6sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA6sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA7* + ID_MODEL_FROM_DATABASE=MCP79 OHCI USB 1.1 Controller + +pci:v000010DEd00000AA7sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA7sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AA8* + ID_MODEL_FROM_DATABASE=MCP79 OHCI USB 1.1 Controller + +pci:v000010DEd00000AA9* + ID_MODEL_FROM_DATABASE=MCP79 EHCI USB 2.0 Controller + +pci:v000010DEd00000AA9sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AA9sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AAA* + ID_MODEL_FROM_DATABASE=MCP79 EHCI USB 2.0 Controller + +pci:v000010DEd00000AAB* + ID_MODEL_FROM_DATABASE=MCP79 PCI Bridge + +pci:v000010DEd00000AABsv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AAC* + ID_MODEL_FROM_DATABASE=MCP79 LPC Bridge + +pci:v000010DEd00000AAD* + ID_MODEL_FROM_DATABASE=MCP79 LPC Bridge + +pci:v000010DEd00000AADsv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AAE* + ID_MODEL_FROM_DATABASE=MCP79 LPC Bridge + +pci:v000010DEd00000AAEsv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AAF* + ID_MODEL_FROM_DATABASE=MCP79 LPC Bridge + +pci:v000010DEd00000AB0* + ID_MODEL_FROM_DATABASE=MCP79 Ethernet + +pci:v000010DEd00000AB0sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AB0sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AB1* + ID_MODEL_FROM_DATABASE=MCP79 Ethernet + +pci:v000010DEd00000AB2* + ID_MODEL_FROM_DATABASE=MCP79 Ethernet + +pci:v000010DEd00000AB3* + ID_MODEL_FROM_DATABASE=MCP79 Ethernet + +pci:v000010DEd00000AB4* + ID_MODEL_FROM_DATABASE=MCP79 SATA Controller + +pci:v000010DEd00000AB4sv000019DAsd0000A123* + ID_MODEL_FROM_DATABASE=IONITX-F-E + +pci:v000010DEd00000AB5* + ID_MODEL_FROM_DATABASE=MCP79 SATA Controller + +pci:v000010DEd00000AB6* + ID_MODEL_FROM_DATABASE=MCP79 SATA Controller + +pci:v000010DEd00000AB7* + ID_MODEL_FROM_DATABASE=MCP79 SATA Controller + +pci:v000010DEd00000AB8* + ID_MODEL_FROM_DATABASE=MCP79 AHCI Controller + +pci:v000010DEd00000AB9* + ID_MODEL_FROM_DATABASE=MCP79 AHCI Controller + +pci:v000010DEd00000AB9sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000ABA* + ID_MODEL_FROM_DATABASE=MCP79 AHCI Controller + +pci:v000010DEd00000ABB* + ID_MODEL_FROM_DATABASE=MCP79 AHCI Controller + +pci:v000010DEd00000ABC* + ID_MODEL_FROM_DATABASE=MCP79 RAID Controller + +pci:v000010DEd00000ABD* + ID_MODEL_FROM_DATABASE=MCP79 RAID Controller + +pci:v000010DEd00000ABE* + ID_MODEL_FROM_DATABASE=MCP79 RAID Controller + +pci:v000010DEd00000ABF* + ID_MODEL_FROM_DATABASE=MCP79 RAID Controller + +pci:v000010DEd00000AC0* + ID_MODEL_FROM_DATABASE=MCP79 High Definition Audio + +pci:v000010DEd00000AC0sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AC1* + ID_MODEL_FROM_DATABASE=MCP79 High Definition Audio + +pci:v000010DEd00000AC2* + ID_MODEL_FROM_DATABASE=MCP79 High Definition Audio + +pci:v000010DEd00000AC3* + ID_MODEL_FROM_DATABASE=MCP79 High Definition Audio + +pci:v000010DEd00000AC4* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AC4sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AC5* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AC6* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AC6sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AC7* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AC7sv000010DEsd0000CB79* + ID_MODEL_FROM_DATABASE=Apple iMac 9,1 + +pci:v000010DEd00000AC8* + ID_MODEL_FROM_DATABASE=MCP79 PCI Express Bridge + +pci:v000010DEd00000AD0* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] SATA Controller (non-AHCI mode) + +pci:v000010DEd00000AD0sv00001462sd00007508* + ID_MODEL_FROM_DATABASE=K9N2GM-FIH + +pci:v000010DEd00000AD0sv00001849sd00000AD0* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 IDE + +pci:v000010DEd00000AD4* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] AHCI Controller + +pci:v000010DEd00000AD4sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000010DEd00000AD4sv00001043sd000082E8* + ID_MODEL_FROM_DATABASE=M3N72-D + +pci:v000010DEd00000AD4sv00001849sd00000AD4* + ID_MODEL_FROM_DATABASE=K10N78FullHD-hSLI R3.0 AHCI Controller + +pci:v000010DEd00000AD8* + ID_MODEL_FROM_DATABASE=MCP78S [GeForce 8200] SATA Controller (RAID mode) + +pci:v000010DEd00000BE2* + ID_MODEL_FROM_DATABASE=GT216 HDMI Audio Controller + +pci:v000010DEd00000BE2sv00001043sd00008311* + ID_MODEL_FROM_DATABASE=ENGT220/DI/1GD3(LP)/V2 + +pci:v000010DEd00000BE3* + ID_MODEL_FROM_DATABASE=High Definition Audio Controller + +pci:v000010DEd00000BE3sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v000010DEd00000BE3sv000010DEsd0000066D* + ID_MODEL_FROM_DATABASE=G98 [GeForce 8400GS] + +pci:v000010DEd00000BE4* + ID_MODEL_FROM_DATABASE=High Definition Audio Controller + +pci:v000010DEd00000BE5* + ID_MODEL_FROM_DATABASE=GF100 High Definition Audio Controller + +pci:v000010DEd00000BE9* + ID_MODEL_FROM_DATABASE=GF106 High Definition Audio Controller + +pci:v000010DEd00000BE9sv00001558sd00008687* + ID_MODEL_FROM_DATABASE=CLEVO/KAPOK W860CU + +pci:v000010DEd00000BE9sv00003842sd00001452* + ID_MODEL_FROM_DATABASE=GeForce GTS 450 + +pci:v000010DEd00000BEA* + ID_MODEL_FROM_DATABASE=GF108 High Definition Audio Controller + +pci:v000010DEd00000BEAsv00003842sd00001430* + ID_MODEL_FROM_DATABASE=GeForce GT 430 + +pci:v000010DEd00000BEB* + ID_MODEL_FROM_DATABASE=GF104 High Definition Audio Controller + +pci:v000010DEd00000BEBsv00001462sd00002322* + ID_MODEL_FROM_DATABASE=N460GTX Cyclone 1GD5/OC + +pci:v000010DEd00000BEE* + ID_MODEL_FROM_DATABASE=GF116 High Definition Audio Controller + +pci:v000010DEd00000CA0* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 330] + +pci:v000010DEd00000CA2* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 320] + +pci:v000010DEd00000CA3* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 240] + +pci:v000010DEd00000CA4* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 340] + +pci:v000010DEd00000CA5* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 220] + +pci:v000010DEd00000CA7* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 330] + +pci:v000010DEd00000CA8* + ID_MODEL_FROM_DATABASE=GT215M [GeForce GTS 260M] + +pci:v000010DEd00000CA9* + ID_MODEL_FROM_DATABASE=GT215M [GeForce GTS 250M] + +pci:v000010DEd00000CAC* + ID_MODEL_FROM_DATABASE=GT215 [GeForce GT 220/315] + +pci:v000010DEd00000CAF* + ID_MODEL_FROM_DATABASE=GT215M [GeForce GT 335M] + +pci:v000010DEd00000CB0* + ID_MODEL_FROM_DATABASE=GT215M [GeForce GTS 350M] + +pci:v000010DEd00000CB1* + ID_MODEL_FROM_DATABASE=GT215M [GeForce GTS 360M] + +pci:v000010DEd00000CBC* + ID_MODEL_FROM_DATABASE=GT215GLM [Quadro FX 1800M] + +pci:v000010DEd00000D60* + ID_MODEL_FROM_DATABASE=MCP89 HOST Bridge + +pci:v000010DEd00000D68* + ID_MODEL_FROM_DATABASE=MCP89 Memory Controller + +pci:v000010DEd00000D69* + ID_MODEL_FROM_DATABASE=MCP89 Memory Controller + +pci:v000010DEd00000D76* + ID_MODEL_FROM_DATABASE=MCP89 PCI Express Bridge + +pci:v000010DEd00000D79* + ID_MODEL_FROM_DATABASE=MCP89 SMBus + +pci:v000010DEd00000D7A* + ID_MODEL_FROM_DATABASE=MCP89 Co-Processor + +pci:v000010DEd00000D7B* + ID_MODEL_FROM_DATABASE=MCP89 Memory Controller + +pci:v000010DEd00000D7D* + ID_MODEL_FROM_DATABASE=MCP89 Ethernet + +pci:v000010DEd00000D80* + ID_MODEL_FROM_DATABASE=MCP89 LPC Bridge + +pci:v000010DEd00000D85* + ID_MODEL_FROM_DATABASE=MCP89 SATA Controller + +pci:v000010DEd00000D88* + ID_MODEL_FROM_DATABASE=MCP89 SATA Controller (AHCI mode) + +pci:v000010DEd00000D89* + ID_MODEL_FROM_DATABASE=MCP89 SATA Controller (AHCI mode) + +pci:v000010DEd00000D8D* + ID_MODEL_FROM_DATABASE=MCP89 SATA Controller (RAID mode) + +pci:v000010DEd00000D94* + ID_MODEL_FROM_DATABASE=MCP89 High Definition Audio + +pci:v000010DEd00000D9C* + ID_MODEL_FROM_DATABASE=MCP89 OHCI USB 1.1 Controller + +pci:v000010DEd00000D9D* + ID_MODEL_FROM_DATABASE=MCP89 EHCI USB 2.0 Controller + +pci:v000010DEd00000DC0* + ID_MODEL_FROM_DATABASE=GF106 [GeForce GT 440] + +pci:v000010DEd00000DC4* + ID_MODEL_FROM_DATABASE=GF106 [GeForce GTS 450] + +pci:v000010DEd00000DC5* + ID_MODEL_FROM_DATABASE=GF106 [GeForce GTS 450 OEM] + +pci:v000010DEd00000DC6* + ID_MODEL_FROM_DATABASE=GF106 [GeForce GTS 450] + +pci:v000010DEd00000DCD* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GT 555M] + +pci:v000010DEd00000DCE* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GT 555M] + +pci:v000010DEd00000DD1* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GTX 460M] + +pci:v000010DEd00000DD1sv00001558sd00008687* + ID_MODEL_FROM_DATABASE=CLEVO/KAPOK W860CU + +pci:v000010DEd00000DD2* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GT 445M] + +pci:v000010DEd00000DD3* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GT 435M] + +pci:v000010DEd00000DD6* + ID_MODEL_FROM_DATABASE=GF106M [GeForce GT 550M] + +pci:v000010DEd00000DD8* + ID_MODEL_FROM_DATABASE=GF106GL [Quadro 2000] + +pci:v000010DEd00000DD8sv000010DEsd00000914* + ID_MODEL_FROM_DATABASE=Quadro 2000D + +pci:v000010DEd00000DDA* + ID_MODEL_FROM_DATABASE=GF106GLM [Quadro 2000M] + +pci:v000010DEd00000DE0* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 440] + +pci:v000010DEd00000DE1* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 430] + +pci:v000010DEd00000DE1sv00003842sd00001430* + ID_MODEL_FROM_DATABASE=GeForce GT 430 + +pci:v000010DEd00000DE2* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 420] + +pci:v000010DEd00000DE3* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 635M] + +pci:v000010DEd00000DE4* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 520] + +pci:v000010DEd00000DE5* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 530] + +pci:v000010DEd00000DE7* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 610] + +pci:v000010DEd00000DE8* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 620M] + +pci:v000010DEd00000DE9* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 630M] + +pci:v000010DEd00000DE9sv00001025sd00000692* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd00000725* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd00000728* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd0000072B* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd0000072E* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd00000753* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv00001025sd00000754* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00000DE9sv000017AAsd00003977* + ID_MODEL_FROM_DATABASE=GeForce GT 640M LE + +pci:v000010DEd00000DE9sv00001B0Asd00002210* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00000DEA* + ID_MODEL_FROM_DATABASE=GF108M [GeForce 610M] + +pci:v000010DEd00000DEAsv000017AAsd0000365A* + ID_MODEL_FROM_DATABASE=GeForce 615 + +pci:v000010DEd00000DEAsv000017AAsd0000365B* + ID_MODEL_FROM_DATABASE=GeForce 615 + +pci:v000010DEd00000DEAsv000017AAsd0000365E* + ID_MODEL_FROM_DATABASE=GeForce 615 + +pci:v000010DEd00000DEAsv000017AAsd00003660* + ID_MODEL_FROM_DATABASE=GeForce 615 + +pci:v000010DEd00000DEAsv000017AAsd0000366C* + ID_MODEL_FROM_DATABASE=GeForce 615 + +pci:v000010DEd00000DEB* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 555M] + +pci:v000010DEd00000DEC* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 525M] + +pci:v000010DEd00000DED* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 520M] + +pci:v000010DEd00000DEE* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 415M] + +pci:v000010DEd00000DEF* + ID_MODEL_FROM_DATABASE=GF108M [NVS 5400M] + +pci:v000010DEd00000DF0* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 425M] + +pci:v000010DEd00000DF1* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 420M] + +pci:v000010DEd00000DF2* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 435M] + +pci:v000010DEd00000DF3* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 420M] + +pci:v000010DEd00000DF4* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 540M] + +pci:v000010DEd00000DF4sv0000152Dsd00000952* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00000DF4sv0000152Dsd00000953* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00000DF5* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 525M] + +pci:v000010DEd00000DF6* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 550M] + +pci:v000010DEd00000DF7* + ID_MODEL_FROM_DATABASE=GF108M [GeForce GT 520M] + +pci:v000010DEd00000DF8* + ID_MODEL_FROM_DATABASE=GF108GL [Quadro 600] + +pci:v000010DEd00000DF9* + ID_MODEL_FROM_DATABASE=GF108GLM [Quadro 500M] + +pci:v000010DEd00000DFA* + ID_MODEL_FROM_DATABASE=GF108GLM [Quadro 1000M] + +pci:v000010DEd00000DFC* + ID_MODEL_FROM_DATABASE=GF108GLM [NVS 5200M] + +pci:v000010DEd00000E08* + ID_MODEL_FROM_DATABASE=GF119 HDMI Audio Controller + +pci:v000010DEd00000E08sv000010B0sd0000104A* + ID_MODEL_FROM_DATABASE=Gainward GeForce GT 610 + +pci:v000010DEd00000E09* + ID_MODEL_FROM_DATABASE=GF110 High Definition Audio Controller + +pci:v000010DEd00000E0A* + ID_MODEL_FROM_DATABASE=GK104 HDMI Audio Controller + +pci:v000010DEd00000E0B* + ID_MODEL_FROM_DATABASE=GK106 HDMI Audio Controller + +pci:v000010DEd00000E0C* + ID_MODEL_FROM_DATABASE=GF114 HDMI Audio Controller + +pci:v000010DEd00000E1A* + ID_MODEL_FROM_DATABASE=GK110 HDMI Audio + +pci:v000010DEd00000E1B* + ID_MODEL_FROM_DATABASE=GK107 HDMI Audio Controller + +pci:v000010DEd00000E1Bsv00001043sd00008428* + ID_MODEL_FROM_DATABASE=GTX650-DC-1GD5 + +pci:v000010DEd00000E22* + ID_MODEL_FROM_DATABASE=GF104 [GeForce GTX 460] + +pci:v000010DEd00000E22sv00001462sd00002322* + ID_MODEL_FROM_DATABASE=N460GTX Cyclone 1GD5/OC + +pci:v000010DEd00000E23* + ID_MODEL_FROM_DATABASE=GF104 [GeForce GTX 460 SE] + +pci:v000010DEd00000E24* + ID_MODEL_FROM_DATABASE=GF104 [GeForce GTX 460 OEM] + +pci:v000010DEd00000E30* + ID_MODEL_FROM_DATABASE=GF104M [GeForce GTX 470M] + +pci:v000010DEd00000E31* + ID_MODEL_FROM_DATABASE=GF104M [GeForce GTX 485M] + +pci:v000010DEd00000E3A* + ID_MODEL_FROM_DATABASE=GF104GLM [Quadro 3000M] + +pci:v000010DEd00000E3B* + ID_MODEL_FROM_DATABASE=GF104GLM [Quadro 4000M] + +pci:v000010DEd00000F00* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 630] + +pci:v000010DEd00000F01* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 620] + +pci:v000010DEd00000FC0* + ID_MODEL_FROM_DATABASE=GK107 [GeForce GT 640 OEM] + +pci:v000010DEd00000FC1* + ID_MODEL_FROM_DATABASE=GK107 [GeForce GT 640] + +pci:v000010DEd00000FC2* + ID_MODEL_FROM_DATABASE=GK107 [GeForce GT 630 OEM] + +pci:v000010DEd00000FC6* + ID_MODEL_FROM_DATABASE=GK107 [GeForce GTX 650] + +pci:v000010DEd00000FC6sv00001043sd00008428* + ID_MODEL_FROM_DATABASE=GTX650-DC-1GD5 + +pci:v000010DEd00000FCD* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 755M] + +pci:v000010DEd00000FCE* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 640M LE] + +pci:v000010DEd00000FD1* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 650M] + +pci:v000010DEd00000FD1sv00001043sd00001597* + ID_MODEL_FROM_DATABASE=GeForce GT 650M + +pci:v000010DEd00000FD1sv00001043sd000015A7* + ID_MODEL_FROM_DATABASE=GeForce GT 650M + +pci:v000010DEd00000FD1sv00001043sd00002103* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v000010DEd00000FD1sv00001043sd00002105* + ID_MODEL_FROM_DATABASE=GeForce GT 650M + +pci:v000010DEd00000FD1sv00001043sd00002141* + ID_MODEL_FROM_DATABASE=GeForce GT 650M + +pci:v000010DEd00000FD2* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 640M] + +pci:v000010DEd00000FD2sv00001028sd0000054F* + ID_MODEL_FROM_DATABASE=GeForce GT 640M + +pci:v000010DEd00000FD2sv00001028sd0000055F* + ID_MODEL_FROM_DATABASE=GeForce GT 640M + +pci:v000010DEd00000FD2sv00001028sd00000595* + ID_MODEL_FROM_DATABASE=GeForce GT 640M LE + +pci:v000010DEd00000FD2sv00001028sd000005B2* + ID_MODEL_FROM_DATABASE=GeForce GT 640M LE + +pci:v000010DEd00000FD3* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 640M LE] + +pci:v000010DEd00000FD4* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GTX 660M] + +pci:v000010DEd00000FD5* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 650M Mac Edition] + +pci:v000010DEd00000FD8* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 640M Mac Edition] + +pci:v000010DEd00000FD9* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 645M] + +pci:v000010DEd00000FDF* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 740M] + +pci:v000010DEd00000FE0* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GTX 660M Mac Edition] + +pci:v000010DEd00000FE1* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 730M] + +pci:v000010DEd00000FE2* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 745M] + +pci:v000010DEd00000FE3* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 745M] + +pci:v000010DEd00000FE3sv000017AAsd00003675* + ID_MODEL_FROM_DATABASE=GeForce GT 745A + +pci:v000010DEd00000FE4* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 750M] + +pci:v000010DEd00000FE5* + ID_MODEL_FROM_DATABASE=GK107 [GeForce K340 USM] + +pci:v000010DEd00000FE6* + ID_MODEL_FROM_DATABASE=GK107 [GRID K1 NVS USM] + +pci:v000010DEd00000FE7* + ID_MODEL_FROM_DATABASE=GK107GL [GRID K100 vGPU] + +pci:v000010DEd00000FE7sv000010DEsd0000101E* + ID_MODEL_FROM_DATABASE=GRID K100 + +pci:v000010DEd00000FE9* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 750M Mac Edition] + +pci:v000010DEd00000FEA* + ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 755M Mac Edition] + +pci:v000010DEd00000FEF* + ID_MODEL_FROM_DATABASE=GK107GL [GRID K340] + +pci:v000010DEd00000FF1* + ID_MODEL_FROM_DATABASE=GK107 [NVS 1000] + +pci:v000010DEd00000FF2* + ID_MODEL_FROM_DATABASE=GK107GL [GRID K1] + +pci:v000010DEd00000FF5* + ID_MODEL_FROM_DATABASE=GK107GL [GRID K1 Tesla USM] + +pci:v000010DEd00000FF6* + ID_MODEL_FROM_DATABASE=GK107GLM [Quadro K1100M] + +pci:v000010DEd00000FF7* + ID_MODEL_FROM_DATABASE=GK107GL [GRID K140Q vGPU] + +pci:v000010DEd00000FF7sv000010DEsd00001037* + ID_MODEL_FROM_DATABASE=GRID K140Q + +pci:v000010DEd00000FF8* + ID_MODEL_FROM_DATABASE=GK107GLM [Quadro K500M] + +pci:v000010DEd00000FF9* + ID_MODEL_FROM_DATABASE=GK107GL [Quadro K2000D] + +pci:v000010DEd00000FFA* + ID_MODEL_FROM_DATABASE=GK107GL [Quadro K600] + +pci:v000010DEd00000FFB* + ID_MODEL_FROM_DATABASE=GK107GLM [Quadro K2000M] + +pci:v000010DEd00000FFC* + ID_MODEL_FROM_DATABASE=GK107GLM [Quadro K1000M] + +pci:v000010DEd00000FFD* + ID_MODEL_FROM_DATABASE=GK107 [NVS 510] + +pci:v000010DEd00000FFE* + ID_MODEL_FROM_DATABASE=GK107GL [Quadro K2000] + +pci:v000010DEd00000FFF* + ID_MODEL_FROM_DATABASE=GK107GL [Quadro 410] + +pci:v000010DEd00001003* + ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan LE] + +pci:v000010DEd00001004* + ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX 780] + +pci:v000010DEd00001004sv00003842sd00000784* + ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX 780 SC w/ ACX Cooler] + +pci:v000010DEd00001004sv00003842sd00001784* + ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX 780 Dual FTW w/ ACX Cooler] + +pci:v000010DEd00001004sv00003842sd00001788* + ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX 780 Dual Classified w/ ACX Cooler] + +pci:v000010DEd00001005* + ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] + +pci:v000010DEd00001005sv00001043sd00008451* + ID_MODEL_FROM_DATABASE=GTXTITAN-6GD5 + +pci:v000010DEd00001005sv000010DEsd00001035* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan + +pci:v000010DEd00001005sv00003842sd00002790* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan + +pci:v000010DEd00001005sv00003842sd00002791* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan SC + +pci:v000010DEd00001005sv00003842sd00002793* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan SC Signature + +pci:v000010DEd00001005sv00003842sd00002794* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan SC Hydro Copper + +pci:v000010DEd00001005sv00003842sd00002795* + ID_MODEL_FROM_DATABASE=GeForce GTX Titan SC Hydro Copper Signature + +pci:v000010DEd0000100A* + ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX 780 Ti] + +pci:v000010DEd0000101F* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20] + +pci:v000010DEd00001020* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20X] + +pci:v000010DEd00001021* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20Xm] + +pci:v000010DEd00001022* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20c] + +pci:v000010DEd00001023* + ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40m] + +pci:v000010DEd00001024* + ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40c] + +pci:v000010DEd00001026* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20s] + +pci:v000010DEd00001027* + ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40st] + +pci:v000010DEd00001028* + ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20m] + +pci:v000010DEd00001029* + ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40s] + +pci:v000010DEd0000103A* + ID_MODEL_FROM_DATABASE=GK110GL [Quadro K6000] + +pci:v000010DEd00001040* + ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 520] + +pci:v000010DEd00001042* + ID_MODEL_FROM_DATABASE=GF119 [GeForce 510] + +pci:v000010DEd00001048* + ID_MODEL_FROM_DATABASE=GF119 [GeForce 605] + +pci:v000010DEd00001049* + ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 620 OEM] + +pci:v000010DEd0000104A* + ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 610] + +pci:v000010DEd0000104Asv000010B0sd0000104A* + ID_MODEL_FROM_DATABASE=Gainward GeForce GT 610 + +pci:v000010DEd0000104B* + ID_MODEL_FROM_DATABASE=GF119 [GeForce GT 625 OEM] + +pci:v000010DEd00001050* + ID_MODEL_FROM_DATABASE=GF119M [GeForce GT 520M] + +pci:v000010DEd00001051* + ID_MODEL_FROM_DATABASE=GF119M [GeForce GT 520MX] + +pci:v000010DEd00001052* + ID_MODEL_FROM_DATABASE=GF119M [GeForce GT 520M] + +pci:v000010DEd00001054* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 410M] + +pci:v000010DEd00001055* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 410M] + +pci:v000010DEd00001056* + ID_MODEL_FROM_DATABASE=GF119M [NVS 4200M] + +pci:v000010DEd00001057* + ID_MODEL_FROM_DATABASE=GF119M [Quadro NVS 4200M] + +pci:v000010DEd00001058* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 610M] + +pci:v000010DEd00001058sv0000103Csd00002AED* + ID_MODEL_FROM_DATABASE=GeForce 610 + +pci:v000010DEd00001058sv0000103Csd00002AF1* + ID_MODEL_FROM_DATABASE=GeForce 610 + +pci:v000010DEd00001058sv00001043sd000010AC* + ID_MODEL_FROM_DATABASE=GeForce GT 610M + +pci:v000010DEd00001058sv00001043sd000010BC* + ID_MODEL_FROM_DATABASE=GeForce GT 610M + +pci:v000010DEd00001058sv00001043sd00001652* + ID_MODEL_FROM_DATABASE=GeForce GT 610M + +pci:v000010DEd00001059* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 610M] + +pci:v000010DEd0000105A* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 610M] + +pci:v000010DEd0000105Asv00001043sd00002111* + ID_MODEL_FROM_DATABASE=GeForce GT 610M + +pci:v000010DEd0000105Asv00001043sd00002112* + ID_MODEL_FROM_DATABASE=GeForce GT 610M + +pci:v000010DEd0000105B* + ID_MODEL_FROM_DATABASE=GF119M [GeForce 705M] + +pci:v000010DEd0000105Bsv0000103Csd00002AFB* + ID_MODEL_FROM_DATABASE=GeForce 705A + +pci:v000010DEd0000107C* + ID_MODEL_FROM_DATABASE=GF119 [NVS 315] + +pci:v000010DEd0000107D* + ID_MODEL_FROM_DATABASE=GF119 [NVS 310] + +pci:v000010DEd00001080* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 580] + +pci:v000010DEd00001081* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 570] + +pci:v000010DEd00001081sv000010DEsd0000087E* + ID_MODEL_FROM_DATABASE=Leadtek WinFast GTX 570 + +pci:v000010DEd00001082* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 560 Ti OEM] + +pci:v000010DEd00001084* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 560 OEM] + +pci:v000010DEd00001086* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 570 Rev. 2] + +pci:v000010DEd00001087* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 560 Ti 448 Cores] + +pci:v000010DEd00001088* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 590] + +pci:v000010DEd00001089* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 580] + +pci:v000010DEd0000108B* + ID_MODEL_FROM_DATABASE=GF110 [GeForce GTX 580] + +pci:v000010DEd0000108E* + ID_MODEL_FROM_DATABASE=GF110GL [Tesla C2090] + +pci:v000010DEd00001091* + ID_MODEL_FROM_DATABASE=GF110GL [Tesla M2090] + +pci:v000010DEd00001091sv000010DEsd0000088E* + ID_MODEL_FROM_DATABASE=Tesla X2090 + +pci:v000010DEd00001091sv000010DEsd00000891* + ID_MODEL_FROM_DATABASE=Tesla X2090 + +pci:v000010DEd00001091sv000010DEsd00000974* + ID_MODEL_FROM_DATABASE=Tesla X2090 + +pci:v000010DEd00001091sv000010DEsd0000098D* + ID_MODEL_FROM_DATABASE=Tesla X2090 + +pci:v000010DEd00001094* + ID_MODEL_FROM_DATABASE=GF110GL [Tesla M2075] + +pci:v000010DEd00001094sv000010DEsd00000888* + ID_MODEL_FROM_DATABASE=Tesla M2075 + +pci:v000010DEd00001096* + ID_MODEL_FROM_DATABASE=GF110GL [Tesla C2050 / C2075] + +pci:v000010DEd00001096sv000010DEsd00000910* + ID_MODEL_FROM_DATABASE=Tesla C2075 + +pci:v000010DEd00001096sv000010DEsd00000911* + ID_MODEL_FROM_DATABASE=Tesla C2050 + +pci:v000010DEd0000109A* + ID_MODEL_FROM_DATABASE=GF100GLM [Quadro 5010M] + +pci:v000010DEd0000109B* + ID_MODEL_FROM_DATABASE=GF100GL [Quadro 7000] + +pci:v000010DEd0000109Bsv000010DEsd00000918* + ID_MODEL_FROM_DATABASE=Quadro 7000 + +pci:v000010DEd000010C0* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 9300 GS Rev. 2] + +pci:v000010DEd000010C3* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 8400 GS Rev. 3] + +pci:v000010DEd000010C5* + ID_MODEL_FROM_DATABASE=GT218 [GeForce 405] + +pci:v000010DEd000010D8* + ID_MODEL_FROM_DATABASE=GT218 [NVS 300] + +pci:v000010DEd00001140* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] + +pci:v000010DEd00001140sv00001025sd00000600* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000606* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd0000064A* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd0000064C* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd0000067A* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000680* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000686* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000689* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000068B* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000068D* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000068E* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000691* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000692* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000694* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000702* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000719* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000725* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000728* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd0000072B* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd0000072E* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000732* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001025sd00000763* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000773* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000774* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000776* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd0000077A* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000077B* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000077C* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000077D* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000077E* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd0000077F* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001025sd00000781* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000798* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000799* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd0000079B* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd0000079C* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000807* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000821* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000823* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000830* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000837* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001025sd00000841* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001028sd0000054D* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd0000054E* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd00000554* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001028sd00000557* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001028sd00000562* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd00000565* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd00000568* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd00000590* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd00000592* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd00000594* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd00000595* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd000005A2* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd000005B1* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd000005B3* + ID_MODEL_FROM_DATABASE=GeForce GT 625M + +pci:v000010DEd00001140sv00001028sd000005DA* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd000005DE* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001028sd000005E0* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001028sd000005E8* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv00001028sd000005F4* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv0000103Csd000018EF* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000103Csd000018F9* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000103Csd000018FB* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000103Csd000018FD* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000103Csd000018FF* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000103Csd00002AEF* + ID_MODEL_FROM_DATABASE=GeForce GT 720A + +pci:v000010DEd00001140sv0000103Csd00002AF9* + ID_MODEL_FROM_DATABASE=GeForce 710A + +pci:v000010DEd00001140sv00001043sd000010DD* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv00001043sd000010ED* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv00001043sd000011FD* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000124D* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000126D* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000131D* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd000013FD* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd000014C7* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd00001507* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001043sd00002132* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001043sd00002136* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv00001043sd000021BA* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd000021FA* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000220A* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000221A* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001043sd0000223A* + ID_MODEL_FROM_DATABASE=GeForce GT 710M + +pci:v000010DEd00001140sv00001043sd0000224A* + ID_MODEL_FROM_DATABASE=GeForce GT 710M + +pci:v000010DEd00001140sv00001043sd00008595* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001072sd0000152D* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000010CFsd000017F5* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001179sd0000FA01* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA02* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA03* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA05* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA11* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA13* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA18* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA19* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA21* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA23* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA2A* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA32* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA33* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA36* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA38* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA42* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA43* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA45* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA47* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA49* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA58* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA59* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA88* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001179sd0000FA89* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv0000144Dsd0000B092* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv0000144Dsd0000C0D5* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000144Dsd0000C0D7* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv0000144Dsd0000C0E2* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv0000144Dsd0000C0E3* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv0000144Dsd0000C0E4* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv0000144Dsd0000C652* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv0000144Dsd0000C709* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv0000144Dsd0000C711* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv0000144Dsd0000C736* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001462sd000010B8* + ID_MODEL_FROM_DATABASE=GeForce GT 710M + +pci:v000010DEd00001140sv00001462sd000010E9* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001462sd0000AA33* + ID_MODEL_FROM_DATABASE=GeForce 720M + +pci:v000010DEd00001140sv00001462sd0000AAA2* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001462sd0000AAA3* + ID_MODEL_FROM_DATABASE=GeForce 820M + +pci:v000010DEd00001140sv00001462sd0000AE71* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv0000152Dsd00000926* + ID_MODEL_FROM_DATABASE=GeForce 620M + +pci:v000010DEd00001140sv0000152Dsd00000982* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000152Dsd00000983* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000152Dsd00001012* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv0000152Dsd00001030* + ID_MODEL_FROM_DATABASE=GeForce GT 630M + +pci:v000010DEd00001140sv0000152Dsd00001055* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv0000152Dsd00001067* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv0000152Dsd00001072* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00002200* + ID_MODEL_FROM_DATABASE=NVS 5200M + +pci:v000010DEd00001140sv000017AAsd00002213* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00002220* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003656* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv000017AAsd00003800* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003801* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003802* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003803* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003804* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003901* + ID_MODEL_FROM_DATABASE=GeForce 610M / GT 620M + +pci:v000010DEd00001140sv000017AAsd00003902* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd00003903* + ID_MODEL_FROM_DATABASE=GeForce 610M/710M + +pci:v000010DEd00001140sv000017AAsd00003904* + ID_MODEL_FROM_DATABASE=GeForce GT 620M/625M + +pci:v000010DEd00001140sv000017AAsd00003905* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003910* + ID_MODEL_FROM_DATABASE=GeForce 720M + +pci:v000010DEd00001140sv000017AAsd00003912* + ID_MODEL_FROM_DATABASE=GeForce 720M + +pci:v000010DEd00001140sv000017AAsd00003977* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00003983* + ID_MODEL_FROM_DATABASE=GeForce 610M + +pci:v000010DEd00001140sv000017AAsd00005001* + ID_MODEL_FROM_DATABASE=GeForce 610M + +pci:v000010DEd00001140sv000017AAsd00005003* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00005005* + ID_MODEL_FROM_DATABASE=GeForce 705M + +pci:v000010DEd00001140sv000017AAsd0000500D* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv000017AAsd00005014* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd00005017* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd00005019* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000501A* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000501F* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd00005025* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd00005027* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000502A* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000502B* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd0000502D* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000502E* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd0000502F* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv000017AAsd0000503E* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv000017AAsd0000503F* + ID_MODEL_FROM_DATABASE=GeForce 820M + +pci:v000010DEd00001140sv00001854sd00000177* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001854sd00000180* + ID_MODEL_FROM_DATABASE=GeForce 710M + +pci:v000010DEd00001140sv00001854sd00000190* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001854sd00000192* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001140sv00001B0Asd000020DD* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001B0Asd000020DF* + ID_MODEL_FROM_DATABASE=GeForce GT 620M + +pci:v000010DEd00001140sv00001B0Asd00002202* + ID_MODEL_FROM_DATABASE=GeForce GT 720M + +pci:v000010DEd00001180* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 680] + +pci:v000010DEd00001180sv00003842sd00003682* + ID_MODEL_FROM_DATABASE=GeForce GTX 680 Mac Edition + +pci:v000010DEd00001182* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 Ti] + +pci:v000010DEd00001183* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 660 Ti] + +pci:v000010DEd00001184* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 770] + +pci:v000010DEd00001185* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 660 OEM] + +pci:v000010DEd00001185sv000010DEsd0000106F* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 OEM] + +pci:v000010DEd00001187* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760] + +pci:v000010DEd00001188* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 690] + +pci:v000010DEd00001189* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 670] + +pci:v000010DEd00001189sv000010DEsd00001074* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 Ti OEM] + +pci:v000010DEd0000118A* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K520] + +pci:v000010DEd0000118B* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K2 GeForce USM] + +pci:v000010DEd0000118C* + ID_MODEL_FROM_DATABASE=GK104 [GRID K2 NVS USM] + +pci:v000010DEd0000118D* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K200 vGPU] + +pci:v000010DEd0000118Dsv000010DEsd0000101D* + ID_MODEL_FROM_DATABASE=GRID K200 + +pci:v000010DEd0000118E* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 OEM] + +pci:v000010DEd0000118F* + ID_MODEL_FROM_DATABASE=GK104GL [Tesla K10] + +pci:v000010DEd00001193* + ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 760 Ti OEM] + +pci:v000010DEd0000119D* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 775M Mac Edition] + +pci:v000010DEd0000119E* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 780M Mac Edition] + +pci:v000010DEd0000119F* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 780M] + +pci:v000010DEd000011A0* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 680M] + +pci:v000010DEd000011A1* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 670MX] + +pci:v000010DEd000011A2* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 675MX Mac Edition] + +pci:v000010DEd000011A3* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 680MX] + +pci:v000010DEd000011A3sv0000106Bsd0000010D* + ID_MODEL_FROM_DATABASE=iMac 13,2 + +pci:v000010DEd000011A7* + ID_MODEL_FROM_DATABASE=GK104M [GeForce GTX 675MX] + +pci:v000010DEd000011B0* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K240Q\K260Q vGPU] + +pci:v000010DEd000011B0sv000010DEsd0000101A* + ID_MODEL_FROM_DATABASE=GRID K240Q + +pci:v000010DEd000011B0sv000010DEsd0000101B* + ID_MODEL_FROM_DATABASE=GRID K260Q + +pci:v000010DEd000011B1* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K2 Tesla USM] + +pci:v000010DEd000011B6* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K3100M] + +pci:v000010DEd000011B7* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K4100M] + +pci:v000010DEd000011B8* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K5100M] + +pci:v000010DEd000011BA* + ID_MODEL_FROM_DATABASE=GK104GL [Quadro K5000] + +pci:v000010DEd000011BB* + ID_MODEL_FROM_DATABASE=GK104GL [Quadro 4100] + +pci:v000010DEd000011BC* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K5000M] + +pci:v000010DEd000011BD* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K4000M] + +pci:v000010DEd000011BE* + ID_MODEL_FROM_DATABASE=GK104GLM [Quadro K3000M] + +pci:v000010DEd000011BF* + ID_MODEL_FROM_DATABASE=GK104GL [GRID K2] + +pci:v000010DEd000011C0* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 660] + +pci:v000010DEd000011C2* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 650 Ti Boost] + +pci:v000010DEd000011C2sv00001043sd0000845B* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost DirectCU II OC + +pci:v000010DEd000011C2sv00001462sd00002874* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost TwinFrozr II OC + +pci:v000010DEd000011C2sv00001569sd000011C2* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost OC + +pci:v000010DEd000011C2sv000019DAsd00001281* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost OC + +pci:v000010DEd000011C2sv00003842sd00003657* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost + +pci:v000010DEd000011C2sv00003842sd00003658* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti Boost Superclocked + +pci:v000010DEd000011C3* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 650 Ti OEM] + +pci:v000010DEd000011C3sv000010DEsd00001030* + ID_MODEL_FROM_DATABASE=GeForce GTX 650 Ti OEM + +pci:v000010DEd000011C4* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 645 OEM] + +pci:v000010DEd000011C6* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 650 Ti] + +pci:v000010DEd000011C7* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 750 Ti] + +pci:v000010DEd000011C8* + ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 650 OEM] + +pci:v000010DEd000011E0* + ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 770M] + +pci:v000010DEd000011E1* + ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 765M] + +pci:v000010DEd000011E2* + ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 765M] + +pci:v000010DEd000011E3* + ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 760M] + +pci:v000010DEd000011FA* + ID_MODEL_FROM_DATABASE=GK106GL [Quadro K4000] + +pci:v000010DEd000011FC* + ID_MODEL_FROM_DATABASE=GK106GLM [Quadro K2100M] + +pci:v000010DEd00001200* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 560 Ti] + +pci:v000010DEd00001201* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 560] + +pci:v000010DEd00001202* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 560 Ti OEM] + +pci:v000010DEd00001203* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 460 SE v2] + +pci:v000010DEd00001205* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 460 v2] + +pci:v000010DEd00001206* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 555] + +pci:v000010DEd00001207* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GT 645 OEM] + +pci:v000010DEd00001208* + ID_MODEL_FROM_DATABASE=GF114 [GeForce GTX 560 SE] + +pci:v000010DEd00001210* + ID_MODEL_FROM_DATABASE=GF114M [GeForce GTX 570M] + +pci:v000010DEd00001211* + ID_MODEL_FROM_DATABASE=GF114M [GeForce GTX 580M] + +pci:v000010DEd00001212* + ID_MODEL_FROM_DATABASE=GF114M [GeForce GTX 675M] + +pci:v000010DEd00001213* + ID_MODEL_FROM_DATABASE=GF114M [GeForce GTX 670M] + +pci:v000010DEd00001241* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GT 545 OEM] + +pci:v000010DEd00001243* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GT 545] + +pci:v000010DEd00001244* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GTX 550 Ti] + +pci:v000010DEd00001245* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GTS 450 Rev. 2] + +pci:v000010DEd00001246* + ID_MODEL_FROM_DATABASE=GF116M [GeForce GT 550M] + +pci:v000010DEd00001247* + ID_MODEL_FROM_DATABASE=GF116M [GeForce GT 555M/635M] + +pci:v000010DEd00001247sv00001043sd00001752* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001247sv00001043sd00002050* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001247sv00001043sd00002051* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001247sv00001043sd0000212A* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001247sv00001043sd0000212B* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001247sv00001043sd0000212C* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001247sv0000152Dsd00000930* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001248* + ID_MODEL_FROM_DATABASE=GF116M [GeForce GT 555M/635M] + +pci:v000010DEd00001248sv0000152Dsd00000930* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001248sv000017C0sd000010E7* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv000017C0sd000010E8* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv000017C0sd000010EA* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv00001854sd00000890* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv00001854sd00000891* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv00001854sd00001795* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv00001854sd00001796* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001248sv00001854sd00003005* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd00001249* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GTS 450 Rev. 3] + +pci:v000010DEd0000124B* + ID_MODEL_FROM_DATABASE=GF116 [GeForce GT 640 OEM] + +pci:v000010DEd0000124D* + ID_MODEL_FROM_DATABASE=GF116M [GeForce GT 555M/635M] + +pci:v000010DEd0000124Dsv00001028sd00000491* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd0000124Dsv00001028sd00000570* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd0000124Dsv00001028sd00000571* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd0000124Dsv00001462sd0000108D* + ID_MODEL_FROM_DATABASE=GeForce GT 555M + +pci:v000010DEd0000124Dsv00001462sd000010CC* + ID_MODEL_FROM_DATABASE=GeForce GT 635M + +pci:v000010DEd00001251* + ID_MODEL_FROM_DATABASE=GF116M [GeForce GT 560M] + +pci:v000010DEd00001280* + ID_MODEL_FROM_DATABASE=GK208 [GeForce GT 635] + +pci:v000010DEd00001282* + ID_MODEL_FROM_DATABASE=GK208 [GeForce GT 640 Rev. 2] + +pci:v000010DEd00001284* + ID_MODEL_FROM_DATABASE=GK208 [GeForce GT 630 Rev. 2] + +pci:v000010DEd00001290* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 730M] + +pci:v000010DEd00001290sv0000103Csd00002AFA* + ID_MODEL_FROM_DATABASE=GeForce GT 730A + +pci:v000010DEd00001290sv0000103Csd00002B04* + ID_MODEL_FROM_DATABASE=GeForce GT 730A + +pci:v000010DEd00001290sv00001043sd000013AD* + ID_MODEL_FROM_DATABASE=GeForce GT 730M + +pci:v000010DEd00001290sv00001043sd000013CD* + ID_MODEL_FROM_DATABASE=GeForce GT 730M + +pci:v000010DEd00001291* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 735M] + +pci:v000010DEd00001292* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 740M] + +pci:v000010DEd00001292sv000017AAsd00003675* + ID_MODEL_FROM_DATABASE=GeForce GT 740A + +pci:v000010DEd00001292sv000017AAsd00003684* + ID_MODEL_FROM_DATABASE=GeForce GT 740A + +pci:v000010DEd00001293* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 730M] + +pci:v000010DEd00001294* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 740M] + +pci:v000010DEd00001295* + ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] + +pci:v000010DEd00001298* + ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 720M] + +pci:v000010DEd000012A0* + ID_MODEL_FROM_DATABASE=GK208 + +pci:v000010DEd000012B9* + ID_MODEL_FROM_DATABASE=GK208GLM [Quadro K610M] + +pci:v000010DEd000012BA* + ID_MODEL_FROM_DATABASE=GK208GLM [Quadro K510M] + +pci:v000010DF* + ID_VENDOR_FROM_DATABASE=Emulex Corporation + +pci:v000010DFd00000720* + ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) + +pci:v000010DFd00000722* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator (Skyhawk) + +pci:v000010DFd00000723* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator + Target (Skyhawk) + +pci:v000010DFd00000724* + ID_MODEL_FROM_DATABASE=OneConnect FCoE Initiator (Skyhawk) + +pci:v000010DFd00000728* + ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk-VF) + +pci:v000010DFd0000072A* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator (Skyhawk-VF) + +pci:v000010DFd0000072B* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator + Target (Skyhawk-VF) + +pci:v000010DFd0000072C* + ID_MODEL_FROM_DATABASE=OneConnect FCoE Initiator (Skyhawk-VF) + +pci:v000010DFd00001AE5* + ID_MODEL_FROM_DATABASE=LP6000 Fibre Channel Host Adapter + +pci:v000010DFd0000E100* + ID_MODEL_FROM_DATABASE=Proteus-X: LightPulse IOV Fibre Channel Host Adapter + +pci:v000010DFd0000E131* + ID_MODEL_FROM_DATABASE=LightPulse 8Gb/s PCIe Shared I/O Fibre Channel Adapter + +pci:v000010DFd0000E180* + ID_MODEL_FROM_DATABASE=Proteus-X: LightPulse IOV Fibre Channel Host Adapter + +pci:v000010DFd0000E200* + ID_MODEL_FROM_DATABASE=Lancer-X: LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000E208* + ID_MODEL_FROM_DATABASE=LightPulse 16Gb Fibre Channel Host Adapter (Lancer-VF) + +pci:v000010DFd0000E220* + ID_MODEL_FROM_DATABASE=OneConnect NIC (Lancer) + +pci:v000010DFd0000E240* + ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator (Lancer) + +pci:v000010DFd0000E260* + ID_MODEL_FROM_DATABASE=OneConnect FCoE Initiator (Lancer) + +pci:v000010DFd0000E268* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb FCoE Converged Network Adapter (Lancer-VF) + +pci:v000010DFd0000F011* + ID_MODEL_FROM_DATABASE=Saturn: LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F015* + ID_MODEL_FROM_DATABASE=Saturn: LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F085* + ID_MODEL_FROM_DATABASE=LP850 Fibre Channel Host Adapter + +pci:v000010DFd0000F095* + ID_MODEL_FROM_DATABASE=LP952 Fibre Channel Host Adapter + +pci:v000010DFd0000F098* + ID_MODEL_FROM_DATABASE=LP982 Fibre Channel Host Adapter + +pci:v000010DFd0000F0A1* + ID_MODEL_FROM_DATABASE=Thor LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0A5* + ID_MODEL_FROM_DATABASE=Thor LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0B5* + ID_MODEL_FROM_DATABASE=Viper LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0D1* + ID_MODEL_FROM_DATABASE=Helios LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0D5* + ID_MODEL_FROM_DATABASE=Helios LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0E1* + ID_MODEL_FROM_DATABASE=Zephyr LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0E5* + ID_MODEL_FROM_DATABASE=Zephyr LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F0F5* + ID_MODEL_FROM_DATABASE=Neptune LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F100* + ID_MODEL_FROM_DATABASE=Saturn-X: LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F111* + ID_MODEL_FROM_DATABASE=Saturn-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F112* + ID_MODEL_FROM_DATABASE=Saturn-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000F180* + ID_MODEL_FROM_DATABASE=LPSe12002 EmulexSecure Fibre Channel Adapter + +pci:v000010DFd0000F700* + ID_MODEL_FROM_DATABASE=LP7000 Fibre Channel Host Adapter + +pci:v000010DFd0000F701* + ID_MODEL_FROM_DATABASE=LP7000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2) + +pci:v000010DFd0000F800* + ID_MODEL_FROM_DATABASE=LP8000 Fibre Channel Host Adapter + +pci:v000010DFd0000F801* + ID_MODEL_FROM_DATABASE=LP8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2) + +pci:v000010DFd0000F900* + ID_MODEL_FROM_DATABASE=LP9000 Fibre Channel Host Adapter + +pci:v000010DFd0000F901* + ID_MODEL_FROM_DATABASE=LP9000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2) + +pci:v000010DFd0000F980* + ID_MODEL_FROM_DATABASE=LP9802 Fibre Channel Host Adapter + +pci:v000010DFd0000F981* + ID_MODEL_FROM_DATABASE=LP9802 Fibre Channel Host Adapter Alternate ID + +pci:v000010DFd0000F982* + ID_MODEL_FROM_DATABASE=LP9802 Fibre Channel Host Adapter Alternate ID + +pci:v000010DFd0000FA00* + ID_MODEL_FROM_DATABASE=Thor-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FB00* + ID_MODEL_FROM_DATABASE=Viper LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC00* + ID_MODEL_FROM_DATABASE=Thor-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC00sv000010DFsd0000FC00* + ID_MODEL_FROM_DATABASE=LP10000 LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC10* + ID_MODEL_FROM_DATABASE=Helios-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC20* + ID_MODEL_FROM_DATABASE=Zephyr-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC40* + ID_MODEL_FROM_DATABASE=Saturn-X: LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FC50* + ID_MODEL_FROM_DATABASE=Proteus-X: LightPulse IOV Fibre Channel Host Adapter + +pci:v000010DFd0000FD00* + ID_MODEL_FROM_DATABASE=Helios-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FD11* + ID_MODEL_FROM_DATABASE=Helios-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FD12* + ID_MODEL_FROM_DATABASE=Helios-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FE00* + ID_MODEL_FROM_DATABASE=Zephyr-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FE05* + ID_MODEL_FROM_DATABASE=Zephyr-X: LightPulse FCoE Adapter + +pci:v000010DFd0000FE11* + ID_MODEL_FROM_DATABASE=Zephyr-X LightPulse Fibre Channel Host Adapter + +pci:v000010DFd0000FE12* + ID_MODEL_FROM_DATABASE=Zephyr-X LightPulse FCoE Adapter + +pci:v000010DFd0000FF00* + ID_MODEL_FROM_DATABASE=Neptune LightPulse Fibre Channel Host Adapter + +pci:v000010E0* + ID_VENDOR_FROM_DATABASE=Integrated Micro Solutions Inc. + +pci:v000010E0d00005026* + ID_MODEL_FROM_DATABASE=IMS5026/27/28 + +pci:v000010E0d00005027* + ID_MODEL_FROM_DATABASE=IMS5027 + +pci:v000010E0d00005028* + ID_MODEL_FROM_DATABASE=IMS5028 + +pci:v000010E0d00008849* + ID_MODEL_FROM_DATABASE=IMS8849 + +pci:v000010E0d00008853* + ID_MODEL_FROM_DATABASE=IMS8853 + +pci:v000010E0d00009128* + ID_MODEL_FROM_DATABASE=IMS9128 [Twin turbo 128] + +pci:v000010E1* + ID_VENDOR_FROM_DATABASE=Tekram Technology Co.,Ltd. + +pci:v000010E1d00000391* + ID_MODEL_FROM_DATABASE=TRM-S1040 + +pci:v000010E1d00000391sv000010E1sd00000391* + ID_MODEL_FROM_DATABASE=DC-315U SCSI-3 Host Adapter + +pci:v000010E1d0000690C* + ID_MODEL_FROM_DATABASE=DC-690c + +pci:v000010E1d0000DC29* + ID_MODEL_FROM_DATABASE=DC-290 + +pci:v000010E2* + ID_VENDOR_FROM_DATABASE=Aptix Corporation + +pci:v000010E3* + ID_VENDOR_FROM_DATABASE=Tundra Semiconductor Corp. + +pci:v000010E3d00000000* + ID_MODEL_FROM_DATABASE=CA91C042 [Universe] + +pci:v000010E3d00000108* + ID_MODEL_FROM_DATABASE=Tsi108 Host Bridge for Single PowerPC + +pci:v000010E3d00000148* + ID_MODEL_FROM_DATABASE=Tsi148 [Tempe] + +pci:v000010E3d00000148sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=VR11 Single Board Computer + +pci:v000010E3d00000860* + ID_MODEL_FROM_DATABASE=CA91C860 [QSpan] + +pci:v000010E3d00000862* + ID_MODEL_FROM_DATABASE=CA91C862A [QSpan-II] + +pci:v000010E3d00008260* + ID_MODEL_FROM_DATABASE=CA91L8200B [Dual PCI PowerSpan II] + +pci:v000010E3d00008261* + ID_MODEL_FROM_DATABASE=CA91L8260B [Single PCI PowerSpan II] + +pci:v000010E3d0000A108* + ID_MODEL_FROM_DATABASE=Tsi109 Host Bridge for Dual PowerPC + +pci:v000010E4* + ID_VENDOR_FROM_DATABASE=Tandem Computers + +pci:v000010E4d00008029* + ID_MODEL_FROM_DATABASE=Realtek 8029 Network Card + +pci:v000010E5* + ID_VENDOR_FROM_DATABASE=Micro Industries Corporation + +pci:v000010E6* + ID_VENDOR_FROM_DATABASE=Gainbery Computer Products Inc. + +pci:v000010E7* + ID_VENDOR_FROM_DATABASE=Vadem + +pci:v000010E8* + ID_VENDOR_FROM_DATABASE=Applied Micro Circuits Corp. + +pci:v000010E8d00001072* + ID_MODEL_FROM_DATABASE=INES GPIB-PCI (AMCC5920 based) + +pci:v000010E8d00002011* + ID_MODEL_FROM_DATABASE=Q-Motion Video Capture/Edit board + +pci:v000010E8d00004750* + ID_MODEL_FROM_DATABASE=S5930 [Matchmaker] + +pci:v000010E8d00005920* + ID_MODEL_FROM_DATABASE=S5920 + +pci:v000010E8d00008043* + ID_MODEL_FROM_DATABASE=LANai4.x [Myrinet LANai interface chip] + +pci:v000010E8d00008062* + ID_MODEL_FROM_DATABASE=S5933_PARASTATION + +pci:v000010E8d0000807D* + ID_MODEL_FROM_DATABASE=S5933 [Matchmaker] + +pci:v000010E8d00008088* + ID_MODEL_FROM_DATABASE=Kongsberg Spacetec Format Synchronizer + +pci:v000010E8d00008089* + ID_MODEL_FROM_DATABASE=Kongsberg Spacetec Serial Output Board + +pci:v000010E8d0000809C* + ID_MODEL_FROM_DATABASE=S5933_HEPC3 + +pci:v000010E8d000080B9* + ID_MODEL_FROM_DATABASE=Harmonix Hi-Card P8 (4x active ISDN BRI) + +pci:v000010E8d000080D7* + ID_MODEL_FROM_DATABASE=PCI-9112 + +pci:v000010E8d000080D8* + ID_MODEL_FROM_DATABASE=PCI-7200 + +pci:v000010E8d000080D9* + ID_MODEL_FROM_DATABASE=PCI-9118 + +pci:v000010E8d000080DA* + ID_MODEL_FROM_DATABASE=PCI-9812 + +pci:v000010E8d000080FC* + ID_MODEL_FROM_DATABASE=APCI1500 Signal processing controller (16 dig. inputs + 16 dig. outputs) + +pci:v000010E8d0000811A* + ID_MODEL_FROM_DATABASE=PCI-IEEE1355-DS-DE Interface + +pci:v000010E8d0000814C* + ID_MODEL_FROM_DATABASE=Fastcom ESCC-PCI (Commtech, Inc.) + +pci:v000010E8d00008170* + ID_MODEL_FROM_DATABASE=S5933 [Matchmaker] (Chipset Development Tool) + +pci:v000010E8d000081E6* + ID_MODEL_FROM_DATABASE=Multimedia video controller + +pci:v000010E8d0000828D* + ID_MODEL_FROM_DATABASE=APCI3001 Signal processing controller (up to 16 analog inputs) + +pci:v000010E8d00008291* + ID_MODEL_FROM_DATABASE=Fastcom 232/8-PCI (Commtech, Inc.) + +pci:v000010E8d000082C4* + ID_MODEL_FROM_DATABASE=Fastcom 422/4-PCI (Commtech, Inc.) + +pci:v000010E8d000082C5* + ID_MODEL_FROM_DATABASE=Fastcom 422/2-PCI (Commtech, Inc.) + +pci:v000010E8d000082C6* + ID_MODEL_FROM_DATABASE=Fastcom IG422/1-PCI (Commtech, Inc.) + +pci:v000010E8d000082C7* + ID_MODEL_FROM_DATABASE=Fastcom IG232/2-PCI (Commtech, Inc.) + +pci:v000010E8d000082CA* + ID_MODEL_FROM_DATABASE=Fastcom 232/4-PCI (Commtech, Inc.) + +pci:v000010E8d000082DB* + ID_MODEL_FROM_DATABASE=AJA HDNTV HD SDI Framestore + +pci:v000010E8d000082E2* + ID_MODEL_FROM_DATABASE=Fastcom DIO24H-PCI (Commtech, Inc.) + +pci:v000010E8d00008406* + ID_MODEL_FROM_DATABASE=PCIcanx/PCIcan CAN interface [Kvaser AB] + +pci:v000010E8d00008407* + ID_MODEL_FROM_DATABASE=PCIcan II CAN interface (A1021, PCB-07, PCB-08) [Kvaser AB] + +pci:v000010E8d00008851* + ID_MODEL_FROM_DATABASE=S5933 on Innes Corp FM Radio Capture card + +pci:v000010E9* + ID_VENDOR_FROM_DATABASE=Alps Electric Co., Ltd. + +pci:v000010EA* + ID_VENDOR_FROM_DATABASE=Integraphics + +pci:v000010EAd00001680* + ID_MODEL_FROM_DATABASE=IGA-1680 + +pci:v000010EAd00001682* + ID_MODEL_FROM_DATABASE=IGA-1682 + +pci:v000010EAd00001683* + ID_MODEL_FROM_DATABASE=IGA-1683 + +pci:v000010EAd00002000* + ID_MODEL_FROM_DATABASE=CyberPro 2000 + +pci:v000010EAd00002010* + ID_MODEL_FROM_DATABASE=CyberPro 2000A + +pci:v000010EAd00005000* + ID_MODEL_FROM_DATABASE=CyberPro 5000 + +pci:v000010EAd00005050* + ID_MODEL_FROM_DATABASE=CyberPro 5050 + +pci:v000010EAd00005202* + ID_MODEL_FROM_DATABASE=CyberPro 5202 + +pci:v000010EAd00005252* + ID_MODEL_FROM_DATABASE=CyberPro5252 + +pci:v000010EB* + ID_VENDOR_FROM_DATABASE=Artists Graphics + +pci:v000010EBd00000101* + ID_MODEL_FROM_DATABASE=3GA + +pci:v000010EBd00008111* + ID_MODEL_FROM_DATABASE=Twist3 Frame Grabber + +pci:v000010EC* + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Co., Ltd. + +pci:v000010ECd00000139* + ID_MODEL_FROM_DATABASE=RTL-8139/8139C/8139C+ Ethernet Controller + +pci:v000010ECd00005209* + ID_MODEL_FROM_DATABASE=RTS5209 PCI Express Card Reader + +pci:v000010ECd00005227* + ID_MODEL_FROM_DATABASE=RTS5227 PCI Express Card Reader + +pci:v000010ECd00005227sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v000010ECd00005229* + ID_MODEL_FROM_DATABASE=RTS5229 PCI Express Card Reader + +pci:v000010ECd00005229sv00001025sd00000813* + ID_MODEL_FROM_DATABASE=Aspire R7-571 + +pci:v000010ECd00005229sv0000103Csd0000194E* + ID_MODEL_FROM_DATABASE=ProBook 455 G1 Notebook + +pci:v000010ECd00005288* + ID_MODEL_FROM_DATABASE=Barossa PCI Express Card Reader + +pci:v000010ECd00008029* + ID_MODEL_FROM_DATABASE=RTL-8029(AS) + +pci:v000010ECd00008029sv000010B8sd00002011* + ID_MODEL_FROM_DATABASE=EZ-Card (SMC1208) + +pci:v000010ECd00008029sv000010ECsd00008029* + ID_MODEL_FROM_DATABASE=RTL-8029(AS) + +pci:v000010ECd00008029sv00001113sd00001208* + ID_MODEL_FROM_DATABASE=EN1208 + +pci:v000010ECd00008029sv00001186sd00000300* + ID_MODEL_FROM_DATABASE=DE-528 + +pci:v000010ECd00008029sv00001259sd00002400* + ID_MODEL_FROM_DATABASE=AT-2400 + +pci:v000010ECd00008029sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v000010ECd00008129* + ID_MODEL_FROM_DATABASE=RTL-8129 + +pci:v000010ECd00008129sv000010ECsd00008129* + ID_MODEL_FROM_DATABASE=RT8129 Fast Ethernet Adapter + +pci:v000010ECd00008129sv000011ECsd00008129* + ID_MODEL_FROM_DATABASE=RTL8111/8168 PCIe Gigabit Ethernet (misconfigured) + +pci:v000010ECd00008136* + ID_MODEL_FROM_DATABASE=RTL8101E/RTL8102E PCI Express Fast Ethernet controller + +pci:v000010ECd00008136sv0000103Csd00002AB1* + ID_MODEL_FROM_DATABASE=Pavillion p6774 + +pci:v000010ECd00008136sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v000010ECd00008136sv00001179sd0000FF64* + ID_MODEL_FROM_DATABASE=RTL8102E PCI-E Fast Ethernet NIC + +pci:v000010ECd00008138* + ID_MODEL_FROM_DATABASE=RT8139 (B/C) Cardbus Fast Ethernet Adapter + +pci:v000010ECd00008138sv000010ECsd00008138* + ID_MODEL_FROM_DATABASE=RT8139 (B/C) Fast Ethernet Adapter + +pci:v000010ECd00008139* + ID_MODEL_FROM_DATABASE=RTL-8139/8139C/8139C+ + +pci:v000010ECd00008139sv00000357sd0000000A* + ID_MODEL_FROM_DATABASE=TTP-Monitoring Card V2.0 + +pci:v000010ECd00008139sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v000010ECd00008139sv00001025sd00008920* + ID_MODEL_FROM_DATABASE=ALN-325 + +pci:v000010ECd00008139sv00001025sd00008921* + ID_MODEL_FROM_DATABASE=ALN-325 + +pci:v000010ECd00008139sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v000010ECd00008139sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v000010ECd00008139sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v000010ECd00008139sv00001043sd00001045* + ID_MODEL_FROM_DATABASE=L8400B or L3C/S notebook + +pci:v000010ECd00008139sv00001043sd00008109* + ID_MODEL_FROM_DATABASE=P5P800-MX Mainboard + +pci:v000010ECd00008139sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v000010ECd00008139sv000010BDsd00000320* + ID_MODEL_FROM_DATABASE=EP-320X-R + +pci:v000010ECd00008139sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v000010ECd00008139sv00001113sd0000EC01* + ID_MODEL_FROM_DATABASE=FNC-0107TX + +pci:v000010ECd00008139sv00001186sd00001300* + ID_MODEL_FROM_DATABASE=DFE-538TX + +pci:v000010ECd00008139sv00001186sd00001320* + ID_MODEL_FROM_DATABASE=SN5200 + +pci:v000010ECd00008139sv00001186sd00008139* + ID_MODEL_FROM_DATABASE=DRN-32TX + +pci:v000010ECd00008139sv000011F6sd00008139* + ID_MODEL_FROM_DATABASE=FN22-3(A) LinxPRO Ethernet Adapter + +pci:v000010ECd00008139sv00001259sd00002500* + ID_MODEL_FROM_DATABASE=AT-2500TX + +pci:v000010ECd00008139sv00001259sd00002503* + ID_MODEL_FROM_DATABASE=AT-2500TX/ACPI + +pci:v000010ECd00008139sv00001385sd0000F31D* + ID_MODEL_FROM_DATABASE=FA311 v2 + +pci:v000010ECd00008139sv00001395sd00002100* + ID_MODEL_FROM_DATABASE=AMB2100 + +pci:v000010ECd00008139sv00001429sd0000D010* + ID_MODEL_FROM_DATABASE=ND010/ND012 + +pci:v000010ECd00008139sv00001432sd00009130* + ID_MODEL_FROM_DATABASE=EN-9130TX + +pci:v000010ECd00008139sv00001436sd00008139* + ID_MODEL_FROM_DATABASE=RT8139 + +pci:v000010ECd00008139sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v000010ECd00008139sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=GA-7VM400M/7VT600 Motherboard + +pci:v000010ECd00008139sv00001462sd00000131* + ID_MODEL_FROM_DATABASE=MS-1013 Notebook + +pci:v000010ECd00008139sv00001462sd0000217C* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v000010ECd00008139sv00001462sd0000788C* + ID_MODEL_FROM_DATABASE=865PE Neo2-V Mainboard + +pci:v000010ECd00008139sv0000146Csd00001439* + ID_MODEL_FROM_DATABASE=FE-1439TX + +pci:v000010ECd00008139sv00001489sd00006001* + ID_MODEL_FROM_DATABASE=GF100TXRII + +pci:v000010ECd00008139sv00001489sd00006002* + ID_MODEL_FROM_DATABASE=GF100TXRA + +pci:v000010ECd00008139sv0000149Csd0000139A* + ID_MODEL_FROM_DATABASE=LFE-8139ATX + +pci:v000010ECd00008139sv0000149Csd00008139* + ID_MODEL_FROM_DATABASE=LFE-8139TX + +pci:v000010ECd00008139sv000014CBsd00000200* + ID_MODEL_FROM_DATABASE=LNR-100 Family 10/100 Base-TX Ethernet + +pci:v000010ECd00008139sv00001565sd00002300* + ID_MODEL_FROM_DATABASE=P4TSV Onboard LAN (RTL8100B) + +pci:v000010ECd00008139sv00001631sd00007003* + ID_MODEL_FROM_DATABASE=Onboard RTL8111 on GA-8SIML Rev1.0 Mainboard + +pci:v000010ECd00008139sv00001695sd00009001* + ID_MODEL_FROM_DATABASE=Onboard RTL8101L 10/100 MBit + +pci:v000010ECd00008139sv000016ECsd000000FF* + ID_MODEL_FROM_DATABASE=USR997900A + +pci:v000010ECd00008139sv00001799sd00005000* + ID_MODEL_FROM_DATABASE=F5D5000 PCI Card/Desktop Network PCI Card + +pci:v000010ECd00008139sv00001799sd00005010* + ID_MODEL_FROM_DATABASE=F5D5010 CardBus Notebook Network Card + +pci:v000010ECd00008139sv0000187Esd00003303* + ID_MODEL_FROM_DATABASE=FN312 + +pci:v000010ECd00008139sv00001904sd00008139* + ID_MODEL_FROM_DATABASE=RTL8139D Fast Ethernet Adapter + +pci:v000010ECd00008139sv00002646sd00000001* + ID_MODEL_FROM_DATABASE=KNE120TX + +pci:v000010ECd00008139sv00008E2Esd00007000* + ID_MODEL_FROM_DATABASE=KF-230TX + +pci:v000010ECd00008139sv00008E2Esd00007100* + ID_MODEL_FROM_DATABASE=KF-230TX/2 + +pci:v000010ECd00008139sv0000A0A0sd00000007* + ID_MODEL_FROM_DATABASE=ALN-325C + +pci:v000010ECd00008167* + ID_MODEL_FROM_DATABASE=RTL-8110SC/8169SC Gigabit Ethernet + +pci:v000010ECd00008167sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=GA-MA69G-S3H Motherboard + +pci:v000010ECd00008167sv00001462sd0000235C* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v000010ECd00008167sv00001462sd0000236C* + ID_MODEL_FROM_DATABASE=945P Neo3-F motherboard + +pci:v000010ECd00008168* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller + +pci:v000010ECd00008168sv00001019sd00008168* + ID_MODEL_FROM_DATABASE=RTL8111/8168 PCI Express Gigabit Ethernet controller + +pci:v000010ECd00008168sv00001028sd00000283* + ID_MODEL_FROM_DATABASE=Vostro 220 + +pci:v000010ECd00008168sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v000010ECd00008168sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v000010ECd00008168sv0000103Csd00001611* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 + +pci:v000010ECd00008168sv0000103Csd00001950* + ID_MODEL_FROM_DATABASE=ProBook 450/455 + +pci:v000010ECd00008168sv00001043sd000011F5* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v000010ECd00008168sv00001043sd000016D5* + ID_MODEL_FROM_DATABASE=U6V/U31J laptop + +pci:v000010ECd00008168sv00001043sd000081AA* + ID_MODEL_FROM_DATABASE=P5B + +pci:v000010ECd00008168sv00001043sd000082C6* + ID_MODEL_FROM_DATABASE=M3A78-EH Motherboard + +pci:v000010ECd00008168sv00001043sd000083A3* + ID_MODEL_FROM_DATABASE=M4A785TD Motherboard + +pci:v000010ECd00008168sv00001043sd00008432* + ID_MODEL_FROM_DATABASE=P8P67 and other motherboards + +pci:v000010ECd00008168sv00001043sd00008505* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v000010ECd00008168sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v000010ECd00008168sv000010ECsd00008168* + ID_MODEL_FROM_DATABASE=RTL8111/8168 PCI Express Gigabit Ethernet controller + +pci:v000010ECd00008168sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v000010ECd00008168sv00001462sd0000238C* + ID_MODEL_FROM_DATABASE=Onboard RTL8111b on MSI P965 Platinum Mainboard + +pci:v000010ECd00008168sv00001462sd0000368C* + ID_MODEL_FROM_DATABASE=K9AG Neo2 + +pci:v000010ECd00008168sv00001462sd00007522* + ID_MODEL_FROM_DATABASE=X58 Pro-E + +pci:v000010ECd00008168sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v000010ECd00008168sv00001849sd00008168* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v000010ECd00008168sv00008086sd0000D615* + ID_MODEL_FROM_DATABASE=Desktop Board D510MO/D525MW + +pci:v000010ECd00008169* + ID_MODEL_FROM_DATABASE=RTL8169 PCI Gigabit Ethernet Controller + +pci:v000010ECd00008169sv00001025sd00000079* + ID_MODEL_FROM_DATABASE=Aspire 5024WLMi + +pci:v000010ECd00008169sv000010BDsd00003202* + ID_MODEL_FROM_DATABASE=EP-320G-TX1 32-bit PCI Gigabit Ethernet Adapter + +pci:v000010ECd00008169sv000010ECsd00008169* + ID_MODEL_FROM_DATABASE=RTL8169/8110 Family PCI Gigabit Ethernet NIC + +pci:v000010ECd00008169sv00001259sd0000C107* + ID_MODEL_FROM_DATABASE=CG-LAPCIGT + +pci:v000010ECd00008169sv00001371sd0000434E* + ID_MODEL_FROM_DATABASE=ProG-2000L + +pci:v000010ECd00008169sv00001385sd0000311A* + ID_MODEL_FROM_DATABASE=GA311 + +pci:v000010ECd00008169sv00001385sd00005200* + ID_MODEL_FROM_DATABASE=GA511 Gigabit PC Card + +pci:v000010ECd00008169sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v000010ECd00008169sv00001462sd0000030C* + ID_MODEL_FROM_DATABASE=K8N Neo-FSR v2.0 mainboard + +pci:v000010ECd00008169sv00001462sd0000065C* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v000010ECd00008169sv00001462sd0000702C* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v000010ECd00008169sv00001462sd00007094* + ID_MODEL_FROM_DATABASE=K8T Neo2-F V2.0 + +pci:v000010ECd00008169sv000016ECsd0000011F* + ID_MODEL_FROM_DATABASE=USR997903 + +pci:v000010ECd00008169sv00001734sd00001091* + ID_MODEL_FROM_DATABASE=D2030-A1 + +pci:v000010ECd00008169sv0000A0A0sd00000449* + ID_MODEL_FROM_DATABASE=AK86-L motherboard + +pci:v000010ECd00008171* + ID_MODEL_FROM_DATABASE=RTL8191SEvA Wireless LAN Controller + +pci:v000010ECd00008172* + ID_MODEL_FROM_DATABASE=RTL8191SEvB Wireless LAN Controller + +pci:v000010ECd00008173* + ID_MODEL_FROM_DATABASE=RTL8192SE Wireless LAN Controller + +pci:v000010ECd00008174* + ID_MODEL_FROM_DATABASE=RTL8192SE Wireless LAN Controller + +pci:v000010ECd00008176* + ID_MODEL_FROM_DATABASE=RTL8188CE 802.11b/g/n WiFi Adapter + +pci:v000010ECd00008176sv00001A3Bsd00001139* + ID_MODEL_FROM_DATABASE=AW-NE139H Half-size Mini PCIe Card + +pci:v000010ECd00008177* + ID_MODEL_FROM_DATABASE=RTL8188CE 802.11b/g/n WiFi Adapter + +pci:v000010ECd00008178* + ID_MODEL_FROM_DATABASE=RTL8188CE 802.11b/g/n WiFi Adapter + +pci:v000010ECd00008179* + ID_MODEL_FROM_DATABASE=RTL8188EE Wireless Network Adapter + +pci:v000010ECd00008180* + ID_MODEL_FROM_DATABASE=RTL8180L 802.11b MAC + +pci:v000010ECd00008180sv00001385sd00004700* + ID_MODEL_FROM_DATABASE=MA521 802.11b Wireless PC Card + +pci:v000010ECd00008180sv00001737sd00000019* + ID_MODEL_FROM_DATABASE=WPC11v4 802.11b Wireless-B Notebook Adapter + +pci:v000010ECd00008185* + ID_MODEL_FROM_DATABASE=RTL-8185 IEEE 802.11a/b/g Wireless LAN Controller + +pci:v000010ECd00008190* + ID_MODEL_FROM_DATABASE=RTL8190 802.11n Wireless LAN + +pci:v000010ECd00008191* + ID_MODEL_FROM_DATABASE=RTL8188CE 802.11b/g/n WiFi Adapter + +pci:v000010ECd00008192* + ID_MODEL_FROM_DATABASE=RTL8192E/RTL8192SE Wireless LAN Controller + +pci:v000010ECd00008193* + ID_MODEL_FROM_DATABASE=RTL8192DE Wireless LAN Controller + +pci:v000010ECd00008197* + ID_MODEL_FROM_DATABASE=SmartLAN56 56K Modem + +pci:v000010ECd00008199* + ID_MODEL_FROM_DATABASE=RTL8187SE Wireless LAN Controller + +pci:v000010ECd00008199sv00001462sd00006894* + ID_MODEL_FROM_DATABASE=MN54G2 / MS-6894 Wireless Mini PCIe Card + +pci:v000010ECd00008723* + ID_MODEL_FROM_DATABASE=RTL8723AE PCIe Wireless Network Adapter + +pci:v000010ECd0000B723* + ID_MODEL_FROM_DATABASE=RTL8723BE PCIe Wireless Network Adapter + +pci:v000010ED* + ID_VENDOR_FROM_DATABASE=Ascii Corporation + +pci:v000010EDd00007310* + ID_MODEL_FROM_DATABASE=V7310 + +pci:v000010EE* + ID_VENDOR_FROM_DATABASE=Xilinx Corporation + +pci:v000010EEd00000001* + ID_MODEL_FROM_DATABASE=EUROCOM for PCI (ECOMP) + +pci:v000010EEd00000002* + ID_MODEL_FROM_DATABASE=Octal E1/T1 for PCI ETP Card + +pci:v000010EEd00000007* + ID_MODEL_FROM_DATABASE=Default PCIe endpoint ID + +pci:v000010EEd00000205* + ID_MODEL_FROM_DATABASE=Wildcard TE205P + +pci:v000010EEd00000210* + ID_MODEL_FROM_DATABASE=Wildcard TE210P + +pci:v000010EEd00000300* + ID_MODEL_FROM_DATABASE=Spartan 3 Designs (Xilinx IP) + +pci:v000010EEd00000314* + ID_MODEL_FROM_DATABASE=Wildcard TE405P/TE410P (1st Gen) + +pci:v000010EEd00000405* + ID_MODEL_FROM_DATABASE=Wildcard TE405P (2nd Gen) + +pci:v000010EEd00000410* + ID_MODEL_FROM_DATABASE=Wildcard TE410P (2nd Gen) + +pci:v000010EEd00000600* + ID_MODEL_FROM_DATABASE=Xilinx 6 Designs (Xilinx IP) + +pci:v000010EEd00002B00* + ID_MODEL_FROM_DATABASE=Zomojo Zcard + +pci:v000010EEd00003FC0* + ID_MODEL_FROM_DATABASE=RME Digi96 + +pci:v000010EEd00003FC1* + ID_MODEL_FROM_DATABASE=RME Digi96/8 + +pci:v000010EEd00003FC2* + ID_MODEL_FROM_DATABASE=RME Digi96/8 Pro + +pci:v000010EEd00003FC3* + ID_MODEL_FROM_DATABASE=RME Digi96/8 Pad + +pci:v000010EEd00003FC4* + ID_MODEL_FROM_DATABASE=RME Digi9652 (Hammerfall) + +pci:v000010EEd00003FC5* + ID_MODEL_FROM_DATABASE=RME Hammerfall DSP + +pci:v000010EEd00003FC6* + ID_MODEL_FROM_DATABASE=RME Hammerfall DSP MADI + +pci:v000010EEd00008380* + ID_MODEL_FROM_DATABASE=Ellips ProfiXpress Profibus Master + +pci:v000010EEd00008381* + ID_MODEL_FROM_DATABASE=Ellips Santos Frame Grabber + +pci:v000010EEd0000D154* + ID_MODEL_FROM_DATABASE=Copley Controls CAN card (PCI-CAN-02) + +pci:v000010EEd0000EBF0* + ID_MODEL_FROM_DATABASE=SED Systems Modulator/Demodulator + +pci:v000010EEd0000EBF1* + ID_MODEL_FROM_DATABASE=SED Systems Audio Interface Card + +pci:v000010EEd0000EBF2* + ID_MODEL_FROM_DATABASE=SED Systems Common PCI Interface + +pci:v000010EF* + ID_VENDOR_FROM_DATABASE=Racore Computer Products, Inc. + +pci:v000010EFd00008154* + ID_MODEL_FROM_DATABASE=M815x Token Ring Adapter + +pci:v000010F0* + ID_VENDOR_FROM_DATABASE=Peritek Corporation + +pci:v000010F1* + ID_VENDOR_FROM_DATABASE=Tyan Computer + +pci:v000010F1d00002865* + ID_MODEL_FROM_DATABASE=Tyan Thunder K8E S2865 + +pci:v000010F1d00005300* + ID_MODEL_FROM_DATABASE=Tyan S5380 Mainboard + +pci:v000010F2* + ID_VENDOR_FROM_DATABASE=Achme Computer, Inc. + +pci:v000010F3* + ID_VENDOR_FROM_DATABASE=Alaris, Inc. + +pci:v000010F4* + ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc. + +pci:v000010F5* + ID_VENDOR_FROM_DATABASE=NKK Corporation + +pci:v000010F5d0000A001* + ID_MODEL_FROM_DATABASE=NDR4000 [NR4600 Bridge] + +pci:v000010F6* + ID_VENDOR_FROM_DATABASE=Creative Electronic Systems SA + +pci:v000010F7* + ID_VENDOR_FROM_DATABASE=Matsushita Electric Industrial Co., Ltd. + +pci:v000010F8* + ID_VENDOR_FROM_DATABASE=Altos India Ltd + +pci:v000010F9* + ID_VENDOR_FROM_DATABASE=PC Direct + +pci:v000010FA* + ID_VENDOR_FROM_DATABASE=Truevision + +pci:v000010FAd0000000C* + ID_MODEL_FROM_DATABASE=TARGA 1000 + +pci:v000010FB* + ID_VENDOR_FROM_DATABASE=Thesys Gesellschaft fuer Mikroelektronik mbH + +pci:v000010FBd0000186F* + ID_MODEL_FROM_DATABASE=TH 6255 + +pci:v000010FC* + ID_VENDOR_FROM_DATABASE=I-O Data Device, Inc. + +pci:v000010FCd00000003* + ID_MODEL_FROM_DATABASE=Cardbus IDE Controller + +pci:v000010FCd00000005* + ID_MODEL_FROM_DATABASE=Cardbus SCSI CBSC II + +pci:v000010FD* + ID_VENDOR_FROM_DATABASE=Soyo Computer, Inc + +pci:v000010FE* + ID_VENDOR_FROM_DATABASE=Fast Multimedia AG + +pci:v000010FF* + ID_VENDOR_FROM_DATABASE=NCube + +pci:v00001100* + ID_VENDOR_FROM_DATABASE=Jazz Multimedia + +pci:v00001101* + ID_VENDOR_FROM_DATABASE=Initio Corporation + +pci:v00001101d00000002* + ID_MODEL_FROM_DATABASE=INI-920 Ultra SCSI Adapter + +pci:v00001101d00001060* + ID_MODEL_FROM_DATABASE=INI-A100U2W + +pci:v00001101d00001622* + ID_MODEL_FROM_DATABASE=INI-1623 PCI SATA-II Controller + +pci:v00001101d00009100* + ID_MODEL_FROM_DATABASE=INI-9100/9100W + +pci:v00001101d00009400* + ID_MODEL_FROM_DATABASE=INI-940 Fast Wide SCSI Adapter + +pci:v00001101d00009401* + ID_MODEL_FROM_DATABASE=INI-935 Fast Wide SCSI Adapter + +pci:v00001101d00009500* + ID_MODEL_FROM_DATABASE=INI-950 SCSI Adapter + +pci:v00001101d00009502* + ID_MODEL_FROM_DATABASE=INI-950P Ultra Wide SCSI Adapter + +pci:v00001102* + ID_VENDOR_FROM_DATABASE=Creative Labs + +pci:v00001102d00000002* + ID_MODEL_FROM_DATABASE=SB Live! EMU10k1 + +pci:v00001102d00000002sv0000100Asd00001102* + ID_MODEL_FROM_DATABASE=SB Live! 5.1 Digital OEM SB0220 EMU10K1-JFF + +pci:v00001102d00000002sv00001102sd00000020* + ID_MODEL_FROM_DATABASE=CT4850 SBLive! Value + +pci:v00001102d00000002sv00001102sd00000021* + ID_MODEL_FROM_DATABASE=CT4620 SBLive! + +pci:v00001102d00000002sv00001102sd0000002F* + ID_MODEL_FROM_DATABASE=SBLive! mainboard implementation + +pci:v00001102d00000002sv00001102sd0000100A* + ID_MODEL_FROM_DATABASE=SB Live! 5.1 Digital OEM [SB0220] + +pci:v00001102d00000002sv00001102sd00004001* + ID_MODEL_FROM_DATABASE=E-mu APS + +pci:v00001102d00000002sv00001102sd00008022* + ID_MODEL_FROM_DATABASE=CT4780 SBLive! Value + +pci:v00001102d00000002sv00001102sd00008023* + ID_MODEL_FROM_DATABASE=CT4790 SoundBlaster PCI512 + +pci:v00001102d00000002sv00001102sd00008024* + ID_MODEL_FROM_DATABASE=CT4760 SBLive! + +pci:v00001102d00000002sv00001102sd00008025* + ID_MODEL_FROM_DATABASE=SBLive! Mainboard Implementation + +pci:v00001102d00000002sv00001102sd00008026* + ID_MODEL_FROM_DATABASE=CT4830 SBLive! Value + +pci:v00001102d00000002sv00001102sd00008027* + ID_MODEL_FROM_DATABASE=CT4832 SBLive! Value + +pci:v00001102d00000002sv00001102sd00008028* + ID_MODEL_FROM_DATABASE=CT4760 SBLive! OEM version + +pci:v00001102d00000002sv00001102sd00008031* + ID_MODEL_FROM_DATABASE=CT4831 SBLive! Value + +pci:v00001102d00000002sv00001102sd00008040* + ID_MODEL_FROM_DATABASE=CT4760 SBLive! + +pci:v00001102d00000002sv00001102sd00008051* + ID_MODEL_FROM_DATABASE=CT4850 SBLive! Value + +pci:v00001102d00000002sv00001102sd00008061* + ID_MODEL_FROM_DATABASE=SBLive! Player 5.1 + +pci:v00001102d00000002sv00001102sd00008064* + ID_MODEL_FROM_DATABASE=SBLive! 5.1 Model SB0100 + +pci:v00001102d00000002sv00001102sd00008065* + ID_MODEL_FROM_DATABASE=SBLive! 5.1 Digital Model SB0220 + +pci:v00001102d00000002sv00001102sd00008066* + ID_MODEL_FROM_DATABASE=Live! 5.1 Digital [SB0228] + +pci:v00001102d00000002sv00001102sd00008067* + ID_MODEL_FROM_DATABASE=SBLive! 5.1 eMicro 28028 + +pci:v00001102d00000004* + ID_MODEL_FROM_DATABASE=SB Audigy + +pci:v00001102d00000004sv00001102sd00000051* + ID_MODEL_FROM_DATABASE=SB0090 Audigy Player + +pci:v00001102d00000004sv00001102sd00000053* + ID_MODEL_FROM_DATABASE=SB0090 Audigy Player/OEM + +pci:v00001102d00000004sv00001102sd00000058* + ID_MODEL_FROM_DATABASE=SB0090 Audigy Player/OEM + +pci:v00001102d00000004sv00001102sd00001002* + ID_MODEL_FROM_DATABASE=SB Audigy2 Platinum + +pci:v00001102d00000004sv00001102sd00001007* + ID_MODEL_FROM_DATABASE=SB0240 Audigy 2 Platinum 6.1 + +pci:v00001102d00000004sv00001102sd00001009* + ID_MODEL_FROM_DATABASE=SB Audigy2 OEM HP + +pci:v00001102d00000004sv00001102sd00002001* + ID_MODEL_FROM_DATABASE=SB Audigy 2 ZS Platinum Pro + +pci:v00001102d00000004sv00001102sd00002002* + ID_MODEL_FROM_DATABASE=SB Audigy 2 ZS (SB0350) + +pci:v00001102d00000004sv00001102sd00004001* + ID_MODEL_FROM_DATABASE=E-MU 1010 + +pci:v00001102d00000004sv00001102sd00004002* + ID_MODEL_FROM_DATABASE=E-MU 0404 + +pci:v00001102d00000005* + ID_MODEL_FROM_DATABASE=SB X-Fi + +pci:v00001102d00000005sv00001102sd00000021* + ID_MODEL_FROM_DATABASE=X-Fi Platinum + +pci:v00001102d00000005sv00001102sd0000002C* + ID_MODEL_FROM_DATABASE=X-Fi XtremeGamer FATAL1TY PRO + +pci:v00001102d00000005sv00001102sd00001003* + ID_MODEL_FROM_DATABASE=X-Fi XtremeMusic + +pci:v00001102d00000006* + ID_MODEL_FROM_DATABASE=[SB Live! Value] EMU10k1X + +pci:v00001102d00000007* + ID_MODEL_FROM_DATABASE=CA0106 Soundblaster + +pci:v00001102d00000007sv00001102sd00000007* + ID_MODEL_FROM_DATABASE=SBLive! 24bit + +pci:v00001102d00000007sv00001102sd00001001* + ID_MODEL_FROM_DATABASE=SB0310 Audigy LS + +pci:v00001102d00000007sv00001102sd00001002* + ID_MODEL_FROM_DATABASE=SB0312 Audigy LS + +pci:v00001102d00000007sv00001102sd00001006* + ID_MODEL_FROM_DATABASE=SB0410 SBLive! 24-bit + +pci:v00001102d00000007sv00001102sd0000100A* + ID_MODEL_FROM_DATABASE=SB0570 [SB Audigy SE] + +pci:v00001102d00000007sv00001102sd00001012* + ID_MODEL_FROM_DATABASE=SB0790 X-Fi XA + +pci:v00001102d00000007sv00001102sd00001013* + ID_MODEL_FROM_DATABASE=Soundblaster X-Fi Xtreme Audio + +pci:v00001102d00000007sv00001462sd00001009* + ID_MODEL_FROM_DATABASE=K8N Diamond + +pci:v00001102d00000008* + ID_MODEL_FROM_DATABASE=SB0400 Audigy2 Value + +pci:v00001102d00000008sv00001102sd00000008* + ID_MODEL_FROM_DATABASE=EMU0404 Digital Audio System + +pci:v00001102d00000008sv00001102sd00004004* + ID_MODEL_FROM_DATABASE=EMU1010 Digital Audio System [MAEM8960] + +pci:v00001102d00000009* + ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG + +pci:v00001102d00000009sv00001102sd00000010* + ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG + +pci:v00001102d00000009sv00001102sd00000018* + ID_MODEL_FROM_DATABASE=SB1040 + +pci:v00001102d0000000B* + ID_MODEL_FROM_DATABASE=EMU20k2 [X-Fi Titanium Series] + +pci:v00001102d0000000Bsv00001102sd00000041* + ID_MODEL_FROM_DATABASE=SB0880 [SoundBlaster X-Fi Titanium PCI-e] + +pci:v00001102d00004001* + ID_MODEL_FROM_DATABASE=SB Audigy FireWire Port + +pci:v00001102d00004001sv00001102sd00000010* + ID_MODEL_FROM_DATABASE=SB Audigy FireWire Port + +pci:v00001102d00007002* + ID_MODEL_FROM_DATABASE=SB Live! Game Port + +pci:v00001102d00007002sv00001102sd00000020* + ID_MODEL_FROM_DATABASE=Gameport Joystick + +pci:v00001102d00007003* + ID_MODEL_FROM_DATABASE=SB Audigy Game Port + +pci:v00001102d00007003sv00001102sd00000040* + ID_MODEL_FROM_DATABASE=SB Audigy Game Port + +pci:v00001102d00007003sv00001102sd00000060* + ID_MODEL_FROM_DATABASE=SB Audigy2 MIDI/Game Port + +pci:v00001102d00007004* + ID_MODEL_FROM_DATABASE=[SB Live! Value] Input device controller + +pci:v00001102d00007005* + ID_MODEL_FROM_DATABASE=SB Audigy LS Game Port + +pci:v00001102d00007005sv00001102sd00001001* + ID_MODEL_FROM_DATABASE=SB0310 Audigy LS MIDI/Game port + +pci:v00001102d00007005sv00001102sd00001002* + ID_MODEL_FROM_DATABASE=SB0312 Audigy LS MIDI/Game port + +pci:v00001102d00007006* + ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG PCI to PCIe Bridge + +pci:v00001102d00008938* + ID_MODEL_FROM_DATABASE=Ectiva EV1938 + +pci:v00001102d00008938sv00001033sd000080E5* + ID_MODEL_FROM_DATABASE=SlimTower-Jim (NEC) + +pci:v00001102d00008938sv00001071sd00007150* + ID_MODEL_FROM_DATABASE=Mitac 7150 + +pci:v00001102d00008938sv0000110Asd00005938* + ID_MODEL_FROM_DATABASE=Siemens Scenic Mobile 510PIII + +pci:v00001102d00008938sv000013BDsd0000100C* + ID_MODEL_FROM_DATABASE=Ceres-C (Sharp, Intel BX) + +pci:v00001102d00008938sv000013BDsd0000100D* + ID_MODEL_FROM_DATABASE=Sharp, Intel Banister + +pci:v00001102d00008938sv000013BDsd0000100E* + ID_MODEL_FROM_DATABASE=TwinHead P09S/P09S3 (Sharp) + +pci:v00001102d00008938sv000013BDsd0000F6F1* + ID_MODEL_FROM_DATABASE=Marlin (Sharp) + +pci:v00001102d00008938sv000014FFsd00000E70* + ID_MODEL_FROM_DATABASE=P88TE (TWINHEAD INTERNATIONAL Corp) + +pci:v00001102d00008938sv000014FFsd0000C401* + ID_MODEL_FROM_DATABASE=Notebook 9100/9200/2000 (TWINHEAD INTERNATIONAL Corp) + +pci:v00001102d00008938sv0000156Dsd0000B400* + ID_MODEL_FROM_DATABASE=G400 - Geo (AlphaTop (Taiwan)) + +pci:v00001102d00008938sv0000156Dsd0000B550* + ID_MODEL_FROM_DATABASE=G560 (AlphaTop (Taiwan)) + +pci:v00001102d00008938sv0000156Dsd0000B560* + ID_MODEL_FROM_DATABASE=G560 (AlphaTop (Taiwan)) + +pci:v00001102d00008938sv0000156Dsd0000B700* + ID_MODEL_FROM_DATABASE=G700/U700 (AlphaTop (Taiwan)) + +pci:v00001102d00008938sv0000156Dsd0000B795* + ID_MODEL_FROM_DATABASE=G795 (AlphaTop (Taiwan)) + +pci:v00001102d00008938sv0000156Dsd0000B797* + ID_MODEL_FROM_DATABASE=G797 (AlphaTop (Taiwan)) + +pci:v00001103* + ID_VENDOR_FROM_DATABASE=HighPoint Technologies, Inc. + +pci:v00001103d00000003* + ID_MODEL_FROM_DATABASE=HPT343/345/346/363 + +pci:v00001103d00000004* + ID_MODEL_FROM_DATABASE=HPT366/368/370/370A/372/372N + +pci:v00001103d00000004sv00001103sd00000001* + ID_MODEL_FROM_DATABASE=HPT370A + +pci:v00001103d00000004sv00001103sd00000004* + ID_MODEL_FROM_DATABASE=HPT366 UDMA66 (r1) / HPT368 UDMA66 (r2) / HPT370 UDMA100 (r3) / HPT370 UDMA100 RAID (r4) + +pci:v00001103d00000004sv00001103sd00000005* + ID_MODEL_FROM_DATABASE=HPT370 UDMA100 + +pci:v00001103d00000004sv00001103sd00000006* + ID_MODEL_FROM_DATABASE=HPT302/302N + +pci:v00001103d00000005* + ID_MODEL_FROM_DATABASE=HPT372A/372N + +pci:v00001103d00000006* + ID_MODEL_FROM_DATABASE=HPT302/302N + +pci:v00001103d00000007* + ID_MODEL_FROM_DATABASE=HPT371/371N + +pci:v00001103d00000008* + ID_MODEL_FROM_DATABASE=HPT374 + +pci:v00001103d00000009* + ID_MODEL_FROM_DATABASE=HPT372N + +pci:v00001103d00000620* + ID_MODEL_FROM_DATABASE=RocketRAID 620 2 Port SATA-III Controller + +pci:v00001103d00000622* + ID_MODEL_FROM_DATABASE=RocketRAID 622 2 Port SATA-III Controller + +pci:v00001103d00000640* + ID_MODEL_FROM_DATABASE=RocketRAID 640 4 Port SATA-III Controller + +pci:v00001103d00001720* + ID_MODEL_FROM_DATABASE=RocketRAID 1720 (2x SATA II RAID Controller) + +pci:v00001103d00001740* + ID_MODEL_FROM_DATABASE=RocketRAID 1740 + +pci:v00001103d00001742* + ID_MODEL_FROM_DATABASE=RocketRAID 1742 + +pci:v00001103d00002210* + ID_MODEL_FROM_DATABASE=RocketRAID 2210 SATA-II Controller + +pci:v00001103d00002300* + ID_MODEL_FROM_DATABASE=RocketRAID 230x 4 Port SATA-II Controller + +pci:v00001103d00002310* + ID_MODEL_FROM_DATABASE=RocketRAID 2310 4 Port SATA-II Controller + +pci:v00001103d00002320* + ID_MODEL_FROM_DATABASE=RocketRAID 2320 SATA-II Controller + +pci:v00001103d00002322* + ID_MODEL_FROM_DATABASE=RocketRAID 2322 SATA-II Controller + +pci:v00001103d00002340* + ID_MODEL_FROM_DATABASE=RocketRAID 2340 16 Port SATA-II Controller + +pci:v00001103d00002640* + ID_MODEL_FROM_DATABASE=RocketRAID 2640 SAS/SATA Controller + +pci:v00001103d00002722* + ID_MODEL_FROM_DATABASE=RocketRAID 2722 + +pci:v00001103d00002740* + ID_MODEL_FROM_DATABASE=RocketRAID 2740 + +pci:v00001103d00002744* + ID_MODEL_FROM_DATABASE=RocketRaid 2744 + +pci:v00001103d00002782* + ID_MODEL_FROM_DATABASE=RocketRAID 2782 + +pci:v00001103d00003120* + ID_MODEL_FROM_DATABASE=RocketRAID 3120 + +pci:v00001103d00003220* + ID_MODEL_FROM_DATABASE=RocketRAID 3220 + +pci:v00001103d00003320* + ID_MODEL_FROM_DATABASE=RocketRAID 3320 + +pci:v00001103d00004310* + ID_MODEL_FROM_DATABASE=RocketRaid 4310 + +pci:v00001104* + ID_VENDOR_FROM_DATABASE=RasterOps Corp. + +pci:v00001105* + ID_VENDOR_FROM_DATABASE=Sigma Designs, Inc. + +pci:v00001105d00001105* + ID_MODEL_FROM_DATABASE=REALmagic Xcard MPEG 1/2/3/4 DVD Decoder + +pci:v00001105d00008300* + ID_MODEL_FROM_DATABASE=REALmagic Hollywood Plus DVD Decoder + +pci:v00001105d00008400* + ID_MODEL_FROM_DATABASE=EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder + +pci:v00001105d00008401* + ID_MODEL_FROM_DATABASE=EM8401 REALmagic DVD/MPEG-2 A/V Decoder + +pci:v00001105d00008470* + ID_MODEL_FROM_DATABASE=EM8470 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d00008471* + ID_MODEL_FROM_DATABASE=EM8471 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d00008475* + ID_MODEL_FROM_DATABASE=EM8475 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d00008475sv00001105sd00000001* + ID_MODEL_FROM_DATABASE=REALmagic X-Card + +pci:v00001105d00008476* + ID_MODEL_FROM_DATABASE=EM8476 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d00008476sv0000127Dsd00000000* + ID_MODEL_FROM_DATABASE=CineView II + +pci:v00001105d00008485* + ID_MODEL_FROM_DATABASE=EM8485 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d00008486* + ID_MODEL_FROM_DATABASE=EM8486 REALmagic DVD/MPEG-4 A/V Decoder + +pci:v00001105d0000C622* + ID_MODEL_FROM_DATABASE=EM8622L MPEG-4.10 (H.264) and SMPTE 421M (VC-1) A/V Decoder + +pci:v00001106* + ID_VENDOR_FROM_DATABASE=VIA Technologies, Inc. + +pci:v00001106d00000102* + ID_MODEL_FROM_DATABASE=Embedded VIA Ethernet Controller + +pci:v00001106d00000130* + ID_MODEL_FROM_DATABASE=VT6305 1394.A Controller + +pci:v00001106d00000198* + ID_MODEL_FROM_DATABASE=P4X600 Host Bridge + +pci:v00001106d00000204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00000208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00000238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00000258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00000259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 Host Bridge + +pci:v00001106d00000269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00000282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00000282sv00001043sd000080A3* + ID_MODEL_FROM_DATABASE=A8V Deluxe + +pci:v00001106d00000290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00000293* + ID_MODEL_FROM_DATABASE=PM896 Host Bridge + +pci:v00001106d00000296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00000305* + ID_MODEL_FROM_DATABASE=VT8363/8365 [KT133/KM133] + +pci:v00001106d00000305sv00001019sd00000987* + ID_MODEL_FROM_DATABASE=K7VZA Mainboard + +pci:v00001106d00000305sv00001043sd00008033* + ID_MODEL_FROM_DATABASE=A7V Mainboard + +pci:v00001106d00000305sv00001043sd0000803E* + ID_MODEL_FROM_DATABASE=A7V-E Mainboard + +pci:v00001106d00000305sv00001043sd00008042* + ID_MODEL_FROM_DATABASE=A7V133/A7V133-C Mainboard + +pci:v00001106d00000305sv0000147Bsd0000A401* + ID_MODEL_FROM_DATABASE=KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard + +pci:v00001106d00000308* + ID_MODEL_FROM_DATABASE=PT880 Ultra/PT894 Host Bridge + +pci:v00001106d00000308sv00001043sd00008199* + ID_MODEL_FROM_DATABASE=P4V800D-X Mainboard + +pci:v00001106d00000308sv00001849sd00000308* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00001106d00000314* + ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge + +pci:v00001106d00000324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00000327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00000336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00000340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00000351* + ID_MODEL_FROM_DATABASE=K8T890CF Host Bridge + +pci:v00001106d00000353* + ID_MODEL_FROM_DATABASE=VX800 Host Bridge + +pci:v00001106d00000364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00000364sv00001043sd000081CE* + ID_MODEL_FROM_DATABASE=P5VD2-VM mothervoard + +pci:v00001106d00000391* + ID_MODEL_FROM_DATABASE=VT8371 [KX133] + +pci:v00001106d00000409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Host Bridge: Host Control + +pci:v00001106d00000410* + ID_MODEL_FROM_DATABASE=VX900 Host Bridge: Host Control + +pci:v00001106d00000415* + ID_MODEL_FROM_DATABASE=VT6415 PATA IDE Host Controller + +pci:v00001106d00000415sv00001043sd0000838F* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001106d00000501* + ID_MODEL_FROM_DATABASE=VT8501 [Apollo MVP4] + +pci:v00001106d00000505* + ID_MODEL_FROM_DATABASE=VT82C505 + +pci:v00001106d00000561* + ID_MODEL_FROM_DATABASE=VT82C576MV + +pci:v00001106d00000571* + ID_MODEL_FROM_DATABASE=VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE + +pci:v00001106d00000571sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00000571sv00001019sd00000A81* + ID_MODEL_FROM_DATABASE=L7VTA v1.0 Motherboard (KT400-8235) + +pci:v00001106d00000571sv00001043sd00008052* + ID_MODEL_FROM_DATABASE=VT8233A Bus Master ATA100/66/33 IDE + +pci:v00001106d00000571sv00001043sd0000808C* + ID_MODEL_FROM_DATABASE=A7V8X / A7V333 motherboard + +pci:v00001106d00000571sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X motherboard rev. 1.01 + +pci:v00001106d00000571sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600/K8V-X/A8V Deluxe motherboard + +pci:v00001106d00000571sv00001106sd00000571* + ID_MODEL_FROM_DATABASE=VT82C586/B/VT82C686/A/B/VT8233/A/C/VT8235 PIPC Bus Master IDE + +pci:v00001106d00000571sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001106d00000571sv00001297sd0000F641* + ID_MODEL_FROM_DATABASE=FX41 motherboard + +pci:v00001106d00000571sv00001458sd00005002* + ID_MODEL_FROM_DATABASE=GA-7VAX Mainboard + +pci:v00001106d00000571sv00001462sd00005901* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00000571sv00001462sd00007020* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v00001106d00000571sv00001462sd00007094* + ID_MODEL_FROM_DATABASE=K8T Neo2-F V2.0 + +pci:v00001106d00000571sv00001462sd00007120* + ID_MODEL_FROM_DATABASE=KT4AV motherboard + +pci:v00001106d00000571sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00000571sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00000571sv00001849sd00000571* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00000576* + ID_MODEL_FROM_DATABASE=VT82C576 3V [Apollo Master] + +pci:v00001106d00000581* + ID_MODEL_FROM_DATABASE=CX700/VX700 RAID Controller + +pci:v00001106d00000581sv00001106sd00000581* + ID_MODEL_FROM_DATABASE=Wrong IDE ID + +pci:v00001106d00000585* + ID_MODEL_FROM_DATABASE=VT82C585VP [Apollo VP1/VPX] + +pci:v00001106d00000586* + ID_MODEL_FROM_DATABASE=VT82C586/A/B PCI-to-ISA [Apollo VP] + +pci:v00001106d00000586sv00001106sd00000000* + ID_MODEL_FROM_DATABASE=MVP3 ISA Bridge + +pci:v00001106d00000591* + ID_MODEL_FROM_DATABASE=VT8237A SATA 2-Port Controller + +pci:v00001106d00000595* + ID_MODEL_FROM_DATABASE=VT82C595 [Apollo VP2] + +pci:v00001106d00000596* + ID_MODEL_FROM_DATABASE=VT82C596 ISA [Mobile South] + +pci:v00001106d00000596sv00001106sd00000000* + ID_MODEL_FROM_DATABASE=VT82C596/A/B PCI to ISA Bridge + +pci:v00001106d00000596sv00001458sd00000596* + ID_MODEL_FROM_DATABASE=VT82C596/A/B PCI to ISA Bridge + +pci:v00001106d00000597* + ID_MODEL_FROM_DATABASE=VT82C597 [Apollo VP3] + +pci:v00001106d00000598* + ID_MODEL_FROM_DATABASE=VT82C598 [Apollo MVP3] + +pci:v00001106d00000601* + ID_MODEL_FROM_DATABASE=VT8601 [Apollo ProMedia] + +pci:v00001106d00000605* + ID_MODEL_FROM_DATABASE=VT8605 [ProSavage PM133] + +pci:v00001106d00000605sv0000103Csd00001254* + ID_MODEL_FROM_DATABASE=D9840-60001 [Brio BA410 Motherboard] + +pci:v00001106d00000605sv00001043sd0000802C* + ID_MODEL_FROM_DATABASE=CUV4X mainboard + +pci:v00001106d00000680* + ID_MODEL_FROM_DATABASE=VT82C680 [Apollo P6] + +pci:v00001106d00000686* + ID_MODEL_FROM_DATABASE=VT82C686 [Apollo Super South] + +pci:v00001106d00000686sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00000686sv0000103Csd00001256* + ID_MODEL_FROM_DATABASE=D9840-60001 [Brio BA410 Motherboard] + +pci:v00001106d00000686sv00001043sd0000802C* + ID_MODEL_FROM_DATABASE=CUV4X mainboard + +pci:v00001106d00000686sv00001043sd00008033* + ID_MODEL_FROM_DATABASE=A7V Mainboard + +pci:v00001106d00000686sv00001043sd0000803E* + ID_MODEL_FROM_DATABASE=A7V-E Mainboard + +pci:v00001106d00000686sv00001043sd00008040* + ID_MODEL_FROM_DATABASE=A7M266 Mainboard + +pci:v00001106d00000686sv00001043sd00008042* + ID_MODEL_FROM_DATABASE=A7V133/A7V133-C Mainboard + +pci:v00001106d00000686sv00001106sd00000000* + ID_MODEL_FROM_DATABASE=VT82C686/A PCI to ISA Bridge + +pci:v00001106d00000686sv00001106sd00000686* + ID_MODEL_FROM_DATABASE=VT82C686/A PCI to ISA Bridge + +pci:v00001106d00000686sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001106d00000686sv0000147Bsd0000A702* + ID_MODEL_FROM_DATABASE=KG7-Lite Mainboard + +pci:v00001106d00000691* + ID_MODEL_FROM_DATABASE=VT82C693A/694x [Apollo PRO133x] + +pci:v00001106d00000691sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00000691sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001106d00000691sv00001458sd00000691* + ID_MODEL_FROM_DATABASE=VT82C691 Apollo Pro System Controller + +pci:v00001106d00000693* + ID_MODEL_FROM_DATABASE=VT82C693 [Apollo Pro Plus] + +pci:v00001106d00000698* + ID_MODEL_FROM_DATABASE=VT82C693A [Apollo Pro133 AGP] + +pci:v00001106d00000926* + ID_MODEL_FROM_DATABASE=VT82C926 [Amazon] + +pci:v00001106d00001000* + ID_MODEL_FROM_DATABASE=VT82C570MV + +pci:v00001106d00001106* + ID_MODEL_FROM_DATABASE=VT82C570MV + +pci:v00001106d00001122* + ID_MODEL_FROM_DATABASE=VX800/VX820 Chrome 9 HC3 Integrated Graphics + +pci:v00001106d00001204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00001208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00001238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00001258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00001259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 Host Bridge + +pci:v00001106d00001269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00001282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00001290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00001293* + ID_MODEL_FROM_DATABASE=PM896 Host Bridge + +pci:v00001106d00001296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00001308* + ID_MODEL_FROM_DATABASE=PT894 Host Bridge + +pci:v00001106d00001314* + ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge + +pci:v00001106d00001324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00001327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00001336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00001340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00001351* + ID_MODEL_FROM_DATABASE=VT3351 Host Bridge + +pci:v00001106d00001353* + ID_MODEL_FROM_DATABASE=VX800/VX820 Error Reporting + +pci:v00001106d00001364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00001409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Error Reporting + +pci:v00001106d00001410* + ID_MODEL_FROM_DATABASE=VX900 Error Reporting + +pci:v00001106d00001571* + ID_MODEL_FROM_DATABASE=VT82C576M/VT82C586 + +pci:v00001106d00001595* + ID_MODEL_FROM_DATABASE=VT82C595/97 [Apollo VP2/97] + +pci:v00001106d00001732* + ID_MODEL_FROM_DATABASE=VT1732 [Envy24 II] PCI Multi-Channel Audio Controller + +pci:v00001106d00002106* + ID_MODEL_FROM_DATABASE=VIA Rhine Family Fast Ethernet Adapter (VT6105) + +pci:v00001106d00002204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00002208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00002238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00002258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00002259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 CPU Host Bridge + +pci:v00001106d00002269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00002282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00002290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00002293* + ID_MODEL_FROM_DATABASE=PM896 Host Bridge + +pci:v00001106d00002296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00002308* + ID_MODEL_FROM_DATABASE=PT894 Host Bridge + +pci:v00001106d00002314* + ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge + +pci:v00001106d00002324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00002327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00002336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00002340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00002351* + ID_MODEL_FROM_DATABASE=VT3351 Host Bridge + +pci:v00001106d00002353* + ID_MODEL_FROM_DATABASE=VX800/VX820 Host Bus Control + +pci:v00001106d00002364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00002409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Host Bus Control + +pci:v00001106d00002410* + ID_MODEL_FROM_DATABASE=VX900 CPU Bus Controller + +pci:v00001106d0000287A* + ID_MODEL_FROM_DATABASE=VT8251 PCI to PCI Bridge + +pci:v00001106d0000287B* + ID_MODEL_FROM_DATABASE=VT8251 Host Bridge + +pci:v00001106d0000287C* + ID_MODEL_FROM_DATABASE=VT8251 PCIE Root Port + +pci:v00001106d0000287D* + ID_MODEL_FROM_DATABASE=VT8251 PCIE Root Port + +pci:v00001106d0000287E* + ID_MODEL_FROM_DATABASE=VT8237/8251 Ultra VLINK Controller + +pci:v00001106d00003022* + ID_MODEL_FROM_DATABASE=CLE266 + +pci:v00001106d00003038* + ID_MODEL_FROM_DATABASE=VT82xxxxx UHCI USB 1.1 Controller + +pci:v00001106d00003038sv00000925sd00001234* + ID_MODEL_FROM_DATABASE=VA-502 Mainboard + +pci:v00001106d00003038sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00003038sv00001019sd00000A81* + ID_MODEL_FROM_DATABASE=L7VTA v1.0 Motherboard (KT400-8235) + +pci:v00001106d00003038sv00001043sd00008080* + ID_MODEL_FROM_DATABASE=A7V333 motherboard + +pci:v00001106d00003038sv00001043sd0000808C* + ID_MODEL_FROM_DATABASE=VT6202 USB2.0 4 port controller + +pci:v00001106d00003038sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X motherboard + +pci:v00001106d00003038sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600/K8V-X/A8V Deluxe motherboard + +pci:v00001106d00003038sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001106d00003038sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-7VAX Mainboard + +pci:v00001106d00003038sv00001462sd00005901* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00003038sv00001462sd00007020* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v00001106d00003038sv00001462sd00007094* + ID_MODEL_FROM_DATABASE=K8T Neo2-F V2.0 + +pci:v00001106d00003038sv00001462sd00007120* + ID_MODEL_FROM_DATABASE=KT4AV motherboard + +pci:v00001106d00003038sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00003038sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003038sv0000182Dsd0000201D* + ID_MODEL_FROM_DATABASE=CN-029 USB2.0 4 port PCI Card + +pci:v00001106d00003038sv00001849sd00003038* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003038sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00003040* + ID_MODEL_FROM_DATABASE=VT82C586B ACPI + +pci:v00001106d00003043* + ID_MODEL_FROM_DATABASE=VT86C100A [Rhine] + +pci:v00001106d00003043sv000010BDsd00000000* + ID_MODEL_FROM_DATABASE=VT86C100A Fast Ethernet Adapter + +pci:v00001106d00003043sv00001106sd00000100* + ID_MODEL_FROM_DATABASE=VT86C100A Fast Ethernet Adapter + +pci:v00001106d00003043sv00001186sd00001400* + ID_MODEL_FROM_DATABASE=DFE-530TX rev A + +pci:v00001106d00003044* + ID_MODEL_FROM_DATABASE=VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller + +pci:v00001106d00003044sv00000010sd00000001* + ID_MODEL_FROM_DATABASE=IEEE 1394 4port DCST 1394-3+1B + +pci:v00001106d00003044sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00001106d00003044sv0000103Csd00002A20* + ID_MODEL_FROM_DATABASE=Pavilion t3030.de Desktop PC + +pci:v00001106d00003044sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Media Center PC m7590n + +pci:v00001106d00003044sv00001043sd0000808A* + ID_MODEL_FROM_DATABASE=A8V/A8N/P4P800 series motherboard + +pci:v00001106d00003044sv00001043sd000081FE* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00001106d00003044sv00001458sd00001000* + ID_MODEL_FROM_DATABASE=GA-7VT600-1394 Motherboard + +pci:v00001106d00003044sv00001462sd0000207D* + ID_MODEL_FROM_DATABASE=K8NGM2 series motherboard + +pci:v00001106d00003044sv00001462sd0000217D* + ID_MODEL_FROM_DATABASE=Aspire L250 + +pci:v00001106d00003044sv00001462sd0000590D* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00003044sv00001462sd0000702D* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v00001106d00003044sv00001462sd0000971D* + ID_MODEL_FROM_DATABASE=MS-6917 + +pci:v00001106d00003050* + ID_MODEL_FROM_DATABASE=VT82C596 Power Management + +pci:v00001106d00003051* + ID_MODEL_FROM_DATABASE=VT82C596 Power Management + +pci:v00001106d00003053* + ID_MODEL_FROM_DATABASE=VT6105M [Rhine-III] + +pci:v00001106d00003057* + ID_MODEL_FROM_DATABASE=VT82C686 [Apollo Super ACPI] + +pci:v00001106d00003057sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00003057sv00001019sd00000987* + ID_MODEL_FROM_DATABASE=K7VZA Motherboard + +pci:v00001106d00003057sv00001043sd00008033* + ID_MODEL_FROM_DATABASE=A7V Mainboard + +pci:v00001106d00003057sv00001043sd0000803E* + ID_MODEL_FROM_DATABASE=A7V-E Mainboard + +pci:v00001106d00003057sv00001043sd00008040* + ID_MODEL_FROM_DATABASE=A7M266 Mainboard + +pci:v00001106d00003057sv00001043sd00008042* + ID_MODEL_FROM_DATABASE=A7V133/A7V133-C Mainboard + +pci:v00001106d00003057sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001106d00003058* + ID_MODEL_FROM_DATABASE=VT82C686 AC97 Audio Controller + +pci:v00001106d00003058sv00000E11sd00000097* + ID_MODEL_FROM_DATABASE=SoundMax Digital Integrated Audio + +pci:v00001106d00003058sv00000E11sd0000B194* + ID_MODEL_FROM_DATABASE=Soundmax integrated digital audio + +pci:v00001106d00003058sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00003058sv00001019sd00000987* + ID_MODEL_FROM_DATABASE=K7VZA Motherboard + +pci:v00001106d00003058sv0000103Csd00001251* + ID_MODEL_FROM_DATABASE=D9840-60001 [Brio BA410 Motherboard] + +pci:v00001106d00003058sv00001043sd00001106* + ID_MODEL_FROM_DATABASE=A7V133/A7V133-C Mainboard + +pci:v00001106d00003058sv00001106sd00004511* + ID_MODEL_FROM_DATABASE=Onboard Audio on EP7KXA + +pci:v00001106d00003058sv00001106sd0000AA03* + ID_MODEL_FROM_DATABASE=VT1612A AC'97 Audio Controller + +pci:v00001106d00003058sv000011D4sd00005348* + ID_MODEL_FROM_DATABASE=AD1881A audio + +pci:v00001106d00003058sv00001458sd00007600* + ID_MODEL_FROM_DATABASE=Onboard Audio + +pci:v00001106d00003058sv00001462sd00003091* + ID_MODEL_FROM_DATABASE=MS-6309 Onboard Audio + +pci:v00001106d00003058sv00001462sd00003092* + ID_MODEL_FROM_DATABASE=MS-6309 v2.x Mainboard (VIA VT1611A codec) + +pci:v00001106d00003058sv00001462sd00003300* + ID_MODEL_FROM_DATABASE=MS-6330 Onboard Audio + +pci:v00001106d00003058sv000015DDsd00007609* + ID_MODEL_FROM_DATABASE=Onboard Audio + +pci:v00001106d00003059* + ID_MODEL_FROM_DATABASE=VT8233/A/8235/8237 AC97 Audio Controller + +pci:v00001106d00003059sv00001019sd00000A81* + ID_MODEL_FROM_DATABASE=L7VTA v1.0 Motherboard (KT400-8235) + +pci:v00001106d00003059sv00001019sd00001877* + ID_MODEL_FROM_DATABASE=K8M800-M2 (V2.0) onboard audio + +pci:v00001106d00003059sv00001043sd00008095* + ID_MODEL_FROM_DATABASE=A7V8X Motherboard (Realtek ALC650 codec) + +pci:v00001106d00003059sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X Motherboard + +pci:v00001106d00003059sv00001043sd000080B0* + ID_MODEL_FROM_DATABASE=A7V600/K8V-X/K8V Deluxe motherboard (ADI AD1980 codec [SoundMAX]) + +pci:v00001106d00003059sv00001043sd0000810D* + ID_MODEL_FROM_DATABASE=Asus P5VD1-X (AD1888 codec [SoundMax]) + +pci:v00001106d00003059sv00001043sd0000812A* + ID_MODEL_FROM_DATABASE=A8V Deluxe motherboard (Realtek ALC850 codec) + +pci:v00001106d00003059sv000010ECsd00008168* + ID_MODEL_FROM_DATABASE=High Definition Audio + +pci:v00001106d00003059sv00001106sd00003059* + ID_MODEL_FROM_DATABASE=L7VMM2 Motherboard + +pci:v00001106d00003059sv00001106sd00004161* + ID_MODEL_FROM_DATABASE=K7VT2 motherboard + +pci:v00001106d00003059sv00001106sd00004170* + ID_MODEL_FROM_DATABASE=PCPartner P4M800-8237R Motherboard + +pci:v00001106d00003059sv00001106sd00004552* + ID_MODEL_FROM_DATABASE=Soyo KT-600 Dragon Plus (Realtek ALC 650) + +pci:v00001106d00003059sv00001297sd0000C160* + ID_MODEL_FROM_DATABASE=FX41 motherboard (Realtek ALC650 codec) + +pci:v00001106d00003059sv00001413sd0000147B* + ID_MODEL_FROM_DATABASE=KV8 Pro motherboard onboard audio + +pci:v00001106d00003059sv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-7VAX Onboard Audio (Realtek ALC650) + +pci:v00001106d00003059sv00001462sd00000080* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v00001106d00003059sv00001462sd00003800* + ID_MODEL_FROM_DATABASE=KT266 onboard audio + +pci:v00001106d00003059sv00001462sd00005901* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00003059sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00003059sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003059sv00001695sd0000300C* + ID_MODEL_FROM_DATABASE=EP-8KRA2+ Mainboard + +pci:v00001106d00003059sv00001849sd00000850* + ID_MODEL_FROM_DATABASE=ASRock 775Dual-880 Pro onboard audio (Realtek ALC850) + +pci:v00001106d00003059sv00001849sd00009739* + ID_MODEL_FROM_DATABASE=P4VT8 Mainboard (C-Media CMI9739A codec) + +pci:v00001106d00003059sv00001849sd00009761* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003059sv00004005sd00004710* + ID_MODEL_FROM_DATABASE=MSI K7T266 Pro2-RU (MSI-6380 v2) onboard audio (Realtek/ALC 200/200P) + +pci:v00001106d00003059sv0000A0A0sd000001B6* + ID_MODEL_FROM_DATABASE=AK77-8XN onboard audio + +pci:v00001106d00003059sv0000A0A0sd00000342* + ID_MODEL_FROM_DATABASE=AK86-L motherboard + +pci:v00001106d00003065* + ID_MODEL_FROM_DATABASE=VT6102 [Rhine-II] + +pci:v00001106d00003065sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X Motherboard + +pci:v00001106d00003065sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600-X Motherboard + +pci:v00001106d00003065sv00001106sd00000102* + ID_MODEL_FROM_DATABASE=VT6102 [Rhine II] Embeded Ethernet Controller on VT8235 + +pci:v00001106d00003065sv00001186sd00001400* + ID_MODEL_FROM_DATABASE=DFE-530TX rev A + +pci:v00001106d00003065sv00001186sd00001401* + ID_MODEL_FROM_DATABASE=DFE-530TX rev B + +pci:v00001106d00003065sv000013B9sd00001421* + ID_MODEL_FROM_DATABASE=LD-10/100AL PCI Fast Ethernet Adapter (rev.B) + +pci:v00001106d00003065sv00001462sd00007061* + ID_MODEL_FROM_DATABASE=MS-7061 + +pci:v00001106d00003065sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00003065sv0000147Bsd00001C09* + ID_MODEL_FROM_DATABASE=NV7 Motherboard + +pci:v00001106d00003065sv00001695sd00003005* + ID_MODEL_FROM_DATABASE=VT6103 + +pci:v00001106d00003065sv00001695sd0000300C* + ID_MODEL_FROM_DATABASE=Realtek ALC655 sound chip + +pci:v00001106d00003065sv00001849sd00003065* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003068* + ID_MODEL_FROM_DATABASE=AC'97 Modem Controller + +pci:v00001106d00003068sv00001462sd0000309E* + ID_MODEL_FROM_DATABASE=MS-6309 Saturn Motherboard + +pci:v00001106d00003074* + ID_MODEL_FROM_DATABASE=VT8233 PCI to ISA Bridge + +pci:v00001106d00003074sv00001043sd00008052* + ID_MODEL_FROM_DATABASE=VT8233A + +pci:v00001106d00003091* + ID_MODEL_FROM_DATABASE=VT8633 [Apollo Pro266] + +pci:v00001106d00003099* + ID_MODEL_FROM_DATABASE=VT8366/A/7 [Apollo KT266/A/333] + +pci:v00001106d00003099sv00001043sd00008064* + ID_MODEL_FROM_DATABASE=A7V266-E Mainboard + +pci:v00001106d00003099sv00001043sd0000807F* + ID_MODEL_FROM_DATABASE=A7V333 Mainboard + +pci:v00001106d00003099sv00001849sd00003099* + ID_MODEL_FROM_DATABASE=K7VT2 motherboard + +pci:v00001106d00003101* + ID_MODEL_FROM_DATABASE=VT8653 Host Bridge + +pci:v00001106d00003102* + ID_MODEL_FROM_DATABASE=VT8662 Host Bridge + +pci:v00001106d00003103* + ID_MODEL_FROM_DATABASE=VT8615 Host Bridge + +pci:v00001106d00003104* + ID_MODEL_FROM_DATABASE=USB 2.0 + +pci:v00001106d00003104sv00001019sd00000A81* + ID_MODEL_FROM_DATABASE=L7VTA v1.0 Motherboard (KT400-8235) + +pci:v00001106d00003104sv00001043sd0000808C* + ID_MODEL_FROM_DATABASE=A7V8X motherboard + +pci:v00001106d00003104sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X motherboard rev 1.01 + +pci:v00001106d00003104sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600/K8V-X/A8V Deluxe motherboard + +pci:v00001106d00003104sv00001106sd00003104* + ID_MODEL_FROM_DATABASE=USB 2.0 Controller + +pci:v00001106d00003104sv00001297sd0000F641* + ID_MODEL_FROM_DATABASE=FX41 motherboard + +pci:v00001106d00003104sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-7VAX Mainboard + +pci:v00001106d00003104sv00001462sd00005901* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00003104sv00001462sd00007020* + ID_MODEL_FROM_DATABASE=K8T NEO 2 motherboard + +pci:v00001106d00003104sv00001462sd00007094* + ID_MODEL_FROM_DATABASE=K8T Neo2-F V2.0 + +pci:v00001106d00003104sv00001462sd00007120* + ID_MODEL_FROM_DATABASE=KT4AV motherboard + +pci:v00001106d00003104sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00003104sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003104sv0000182Dsd0000201D* + ID_MODEL_FROM_DATABASE=CN-029 USB 2.0 4 port PCI Card + +pci:v00001106d00003104sv00001849sd00003104* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003104sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00003106* + ID_MODEL_FROM_DATABASE=VT6105/VT6106S [Rhine-III] + +pci:v00001106d00003106sv00001106sd00000105* + ID_MODEL_FROM_DATABASE=VT6106S [Rhine-III] + +pci:v00001106d00003106sv00001186sd00001403* + ID_MODEL_FROM_DATABASE=DFE-530TX rev C + +pci:v00001106d00003106sv00001186sd00001405* + ID_MODEL_FROM_DATABASE=DFE-520TX Fast Ethernet PCI Adapter + +pci:v00001106d00003106sv00001186sd00001406* + ID_MODEL_FROM_DATABASE=DFE-530TX+ rev F2 + +pci:v00001106d00003106sv00001186sd00001407* + ID_MODEL_FROM_DATABASE=DFE-538TX + +pci:v00001106d00003108* + ID_MODEL_FROM_DATABASE=K8M800/K8N800/K8N800A [S3 UniChrome Pro] + +pci:v00001106d00003109* + ID_MODEL_FROM_DATABASE=VT8233C PCI to ISA Bridge + +pci:v00001106d00003112* + ID_MODEL_FROM_DATABASE=VT8361 [KLE133] Host Bridge + +pci:v00001106d00003113* + ID_MODEL_FROM_DATABASE=VPX/VPX2 PCI to PCI Bridge Controller + +pci:v00001106d00003116* + ID_MODEL_FROM_DATABASE=VT8375 [KM266/KL266] Host Bridge + +pci:v00001106d00003116sv00001297sd0000F641* + ID_MODEL_FROM_DATABASE=FX41 motherboard + +pci:v00001106d00003118* + ID_MODEL_FROM_DATABASE=CN400/PM800/PM880/PN800/PN880 [S3 UniChrome Pro] + +pci:v00001106d00003119* + ID_MODEL_FROM_DATABASE=VT6120/VT6121/VT6122 Gigabit Ethernet Adapter + +pci:v00001106d00003122* + ID_MODEL_FROM_DATABASE=VT8623 [Apollo CLE266] integrated CastleRock graphics + +pci:v00001106d00003123* + ID_MODEL_FROM_DATABASE=VT8623 [Apollo CLE266] + +pci:v00001106d00003128* + ID_MODEL_FROM_DATABASE=VT8753 [P4X266 AGP] + +pci:v00001106d00003133* + ID_MODEL_FROM_DATABASE=VT3133 Host Bridge + +pci:v00001106d00003142* + ID_MODEL_FROM_DATABASE=VT6651 WiFi Adapter, 802.11b + +pci:v00001106d00003147* + ID_MODEL_FROM_DATABASE=VT8233A ISA Bridge + +pci:v00001106d00003147sv00001043sd0000808C* + ID_MODEL_FROM_DATABASE=A7V333 motherboard + +pci:v00001106d00003148* + ID_MODEL_FROM_DATABASE=P4M266 Host Bridge + +pci:v00001106d00003149* + ID_MODEL_FROM_DATABASE=VIA VT6420 SATA RAID Controller + +pci:v00001106d00003149sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600/K8V Deluxe/K8V-X/A8V Deluxe motherboard + +pci:v00001106d00003149sv00001458sd0000B003* + ID_MODEL_FROM_DATABASE=GA-7VM400AM(F) Motherboard + +pci:v00001106d00003149sv00001462sd00005901* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v00001106d00003149sv00001462sd00007020* + ID_MODEL_FROM_DATABASE=K8T Neo 2 Motherboard + +pci:v00001106d00003149sv00001462sd00007094* + ID_MODEL_FROM_DATABASE=K8T Neo2-F V2.0 + +pci:v00001106d00003149sv00001462sd00007181* + ID_MODEL_FROM_DATABASE=K8MM3-V mainboard + +pci:v00001106d00003149sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003149sv0000147Bsd00001408* + ID_MODEL_FROM_DATABASE=KV7 + +pci:v00001106d00003149sv00001849sd00003149* + ID_MODEL_FROM_DATABASE=K7VT6 motherboard + +pci:v00001106d00003149sv0000A0A0sd000004AD* + ID_MODEL_FROM_DATABASE=AK86-L motherboard + +pci:v00001106d00003156* + ID_MODEL_FROM_DATABASE=P/KN266 Host Bridge + +pci:v00001106d00003157* + ID_MODEL_FROM_DATABASE=CX700/VX700 [S3 UniChrome Pro] + +pci:v00001106d00003164* + ID_MODEL_FROM_DATABASE=VT6410 ATA133 RAID controller + +pci:v00001106d00003164sv00001043sd000080F4* + ID_MODEL_FROM_DATABASE=P4P800 Mainboard Deluxe ATX + +pci:v00001106d00003164sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00001106d00003168* + ID_MODEL_FROM_DATABASE=P4X333/P4X400/PT800 AGP Bridge + +pci:v00001106d00003168sv00001849sd00003168* + ID_MODEL_FROM_DATABASE=P4VT8 Mainboard + +pci:v00001106d00003177* + ID_MODEL_FROM_DATABASE=VT8235 ISA Bridge + +pci:v00001106d00003177sv00001019sd00000A81* + ID_MODEL_FROM_DATABASE=L7VTA v1.0 Motherboard (KT400-8235) + +pci:v00001106d00003177sv00001043sd0000808C* + ID_MODEL_FROM_DATABASE=A7V8X motherboard + +pci:v00001106d00003177sv00001043sd000080A1* + ID_MODEL_FROM_DATABASE=A7V8X-X motherboard + +pci:v00001106d00003177sv00001106sd00000000* + ID_MODEL_FROM_DATABASE=KT4AV motherboard + +pci:v00001106d00003177sv00001297sd0000F641* + ID_MODEL_FROM_DATABASE=FX41 motherboard + +pci:v00001106d00003177sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-7VAX Mainboard + +pci:v00001106d00003177sv00001849sd00003177* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003178* + ID_MODEL_FROM_DATABASE=ProSavageDDR P4N333 Host Bridge + +pci:v00001106d00003188* + ID_MODEL_FROM_DATABASE=VT8385 [K8T800 AGP] Host Bridge + +pci:v00001106d00003188sv00001043sd000080A3* + ID_MODEL_FROM_DATABASE=K8V Deluxe/K8V-X motherboard + +pci:v00001106d00003188sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003189* + ID_MODEL_FROM_DATABASE=VT8377 [KT400/KT600 AGP] Host Bridge + +pci:v00001106d00003189sv00001043sd0000807F* + ID_MODEL_FROM_DATABASE=A7V8X motherboard + +pci:v00001106d00003189sv00001106sd00000000* + ID_MODEL_FROM_DATABASE=KT4AV motherboard (KT400A) + +pci:v00001106d00003189sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-7VAX Mainboard + +pci:v00001106d00003189sv00001849sd00003189* + ID_MODEL_FROM_DATABASE=K7VT series Motherboards + +pci:v00001106d00003204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00003205* + ID_MODEL_FROM_DATABASE=VT8378 [KM400/A] Chipset Host Bridge + +pci:v00001106d00003205sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-7VM400M Motherboard + +pci:v00001106d00003208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00003213* + ID_MODEL_FROM_DATABASE=VPX/VPX2 PCI to PCI Bridge Controller + +pci:v00001106d00003218* + ID_MODEL_FROM_DATABASE=K8T800M Host Bridge + +pci:v00001106d00003227* + ID_MODEL_FROM_DATABASE=VT8237 ISA bridge [KT600/K8T800/K8T890 South] + +pci:v00001106d00003227sv00001043sd000080ED* + ID_MODEL_FROM_DATABASE=A7V600/K8V-X/A8V Deluxe motherboard + +pci:v00001106d00003227sv00001106sd00003227* + ID_MODEL_FROM_DATABASE=DFI KT600-AL / Soltek SL-B9D-FGR Motherboard + +pci:v00001106d00003227sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-7VT600 Motherboard + +pci:v00001106d00003227sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d00003227sv00001849sd00003227* + ID_MODEL_FROM_DATABASE=K7VT4 motherboard + +pci:v00001106d00003230* + ID_MODEL_FROM_DATABASE=K8M890CE/K8N890CE [Chrome 9] + +pci:v00001106d00003238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00003249* + ID_MODEL_FROM_DATABASE=VT6421 IDE/SATA Controller + +pci:v00001106d0000324A* + ID_MODEL_FROM_DATABASE=CX700/VX700 PCI to PCI Bridge + +pci:v00001106d0000324B* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d0000324E* + ID_MODEL_FROM_DATABASE=CX700/VX700 Internal Module Bus + +pci:v00001106d00003253* + ID_MODEL_FROM_DATABASE=VT6655 WiFi Adapter, 802.11a/b/g + +pci:v00001106d00003258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00003259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 Host Bridge + +pci:v00001106d00003260* + ID_MODEL_FROM_DATABASE=VIA Chrome9 HC IGP + +pci:v00001106d00003269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00003282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00003287* + ID_MODEL_FROM_DATABASE=VT8251 PCI to ISA Bridge + +pci:v00001106d00003288* + ID_MODEL_FROM_DATABASE=VT8237A/VT8251 HDA Controller + +pci:v00001106d00003288sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX VD01 + +pci:v00001106d00003290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00003296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00003324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00003327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00003336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00003337* + ID_MODEL_FROM_DATABASE=VT8237A PCI to ISA Bridge + +pci:v00001106d00003340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00003343* + ID_MODEL_FROM_DATABASE=P4M890 [S3 UniChrome Pro] + +pci:v00001106d00003344* + ID_MODEL_FROM_DATABASE=CN700/P4M800 Pro/P4M800 CE/VN800 Graphics [S3 UniChrome Pro] + +pci:v00001106d00003349* + ID_MODEL_FROM_DATABASE=VT8251 AHCI/SATA 4-Port Controller + +pci:v00001106d00003351* + ID_MODEL_FROM_DATABASE=VT3351 Host Bridge + +pci:v00001106d00003353* + ID_MODEL_FROM_DATABASE=VX800 PCI to PCI Bridge + +pci:v00001106d00003364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00003371* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 [Chrome 9 HC] + +pci:v00001106d00003372* + ID_MODEL_FROM_DATABASE=VT8237S PCI to ISA Bridge + +pci:v00001106d0000337A* + ID_MODEL_FROM_DATABASE=VT8237A PCI to PCI Bridge + +pci:v00001106d0000337B* + ID_MODEL_FROM_DATABASE=VT8237A Host Bridge + +pci:v00001106d00003403* + ID_MODEL_FROM_DATABASE=VT6315 Series Firewire Controller + +pci:v00001106d00003403sv00001043sd00008374* + ID_MODEL_FROM_DATABASE=M5A88-V EVO + +pci:v00001106d00003403sv00001043sd00008384* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00001106d00003409* + ID_MODEL_FROM_DATABASE=VX855/VX875 DRAM Bus Control + +pci:v00001106d00003410* + ID_MODEL_FROM_DATABASE=VX900 DRAM Bus Control + +pci:v00001106d00003410sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00003432* + ID_MODEL_FROM_DATABASE=VL80x xHCI USB 3.0 Controller + +pci:v00001106d00004149* + ID_MODEL_FROM_DATABASE=VIA VT6420 (ATA133) Controller + +pci:v00001106d00004204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00004208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00004238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00004258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00004259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 Host Bridge + +pci:v00001106d00004269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00004282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00004290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00004293* + ID_MODEL_FROM_DATABASE=PM896 Host Bridge + +pci:v00001106d00004296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00004308* + ID_MODEL_FROM_DATABASE=PT894 Host Bridge + +pci:v00001106d00004314* + ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge + +pci:v00001106d00004324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00004327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00004336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00004340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00004351* + ID_MODEL_FROM_DATABASE=VT3351 Host Bridge + +pci:v00001106d00004353* + ID_MODEL_FROM_DATABASE=VX800/VX820 Power Management Control + +pci:v00001106d00004364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00004409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Power Management Control + +pci:v00001106d00004410* + ID_MODEL_FROM_DATABASE=VX900 Power Management and Chip Testing Control + +pci:v00001106d00004410sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00005030* + ID_MODEL_FROM_DATABASE=VT82C596 ACPI [Apollo PRO] + +pci:v00001106d00005122* + ID_MODEL_FROM_DATABASE=VX855/VX875 Chrome 9 HCM Integrated Graphics + +pci:v00001106d00005208* + ID_MODEL_FROM_DATABASE=PT890 I/O APIC Interrupt Controller + +pci:v00001106d00005238* + ID_MODEL_FROM_DATABASE=K8T890 I/O APIC Interrupt Controller + +pci:v00001106d00005287* + ID_MODEL_FROM_DATABASE=VT8251 Serial ATA Controller + +pci:v00001106d00005290* + ID_MODEL_FROM_DATABASE=K8M890 I/O APIC Interrupt Controller + +pci:v00001106d00005308* + ID_MODEL_FROM_DATABASE=PT894 I/O APIC Interrupt Controller + +pci:v00001106d00005324* + ID_MODEL_FROM_DATABASE=VX800 Serial ATA and EIDE Controller + +pci:v00001106d00005327* + ID_MODEL_FROM_DATABASE=P4M890 I/O APIC Interrupt Controller + +pci:v00001106d00005336* + ID_MODEL_FROM_DATABASE=K8M890CE I/O APIC Interrupt Controller + +pci:v00001106d00005340* + ID_MODEL_FROM_DATABASE=PT900 I/O APIC Interrupt Controller + +pci:v00001106d00005351* + ID_MODEL_FROM_DATABASE=VT3351 I/O APIC Interrupt Controller + +pci:v00001106d00005353* + ID_MODEL_FROM_DATABASE=VX800/VX820 APIC and Central Traffic Control + +pci:v00001106d00005364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 I/O APIC Interrupt Controller + +pci:v00001106d00005372* + ID_MODEL_FROM_DATABASE=VT8237/8251 Serial ATA Controller + +pci:v00001106d00005409* + ID_MODEL_FROM_DATABASE=VX855/VX875 APIC and Central Traffic Control + +pci:v00001106d00005410* + ID_MODEL_FROM_DATABASE=VX900 APIC and Central Traffic Control + +pci:v00001106d00006100* + ID_MODEL_FROM_DATABASE=VT85C100A [Rhine II] + +pci:v00001106d00006287* + ID_MODEL_FROM_DATABASE=SATA RAID Controller + +pci:v00001106d00006290* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00006327* + ID_MODEL_FROM_DATABASE=P4M890 Security Device + +pci:v00001106d00006353* + ID_MODEL_FROM_DATABASE=VX800/VX820 Scratch Registers + +pci:v00001106d00006364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Security Device + +pci:v00001106d00006409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Scratch Registers + +pci:v00001106d00006410* + ID_MODEL_FROM_DATABASE=VX900 Scratch Registers + +pci:v00001106d00006410sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00007122* + ID_MODEL_FROM_DATABASE=VX900 Graphics [Chrome9 HD] + +pci:v00001106d00007204* + ID_MODEL_FROM_DATABASE=K8M800 Host Bridge + +pci:v00001106d00007205* + ID_MODEL_FROM_DATABASE=KM400/KN400/P4M800 [S3 UniChrome] + +pci:v00001106d00007205sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=Gigabyte GA-7VM400(A)M(F) Motherboard + +pci:v00001106d00007205sv00001462sd00007061* + ID_MODEL_FROM_DATABASE=MS-7061 + +pci:v00001106d00007208* + ID_MODEL_FROM_DATABASE=PT890 Host Bridge + +pci:v00001106d00007238* + ID_MODEL_FROM_DATABASE=K8T890 Host Bridge + +pci:v00001106d00007258* + ID_MODEL_FROM_DATABASE=PT880 Host Bridge + +pci:v00001106d00007259* + ID_MODEL_FROM_DATABASE=CN333/CN400/PM880 Host Bridge + +pci:v00001106d00007269* + ID_MODEL_FROM_DATABASE=KT880 Host Bridge + +pci:v00001106d00007282* + ID_MODEL_FROM_DATABASE=K8T800Pro Host Bridge + +pci:v00001106d00007290* + ID_MODEL_FROM_DATABASE=K8M890 Host Bridge + +pci:v00001106d00007293* + ID_MODEL_FROM_DATABASE=PM896 Host Bridge + +pci:v00001106d00007296* + ID_MODEL_FROM_DATABASE=P4M800 Host Bridge + +pci:v00001106d00007308* + ID_MODEL_FROM_DATABASE=PT894 Host Bridge + +pci:v00001106d00007314* + ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge + +pci:v00001106d00007324* + ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + +pci:v00001106d00007327* + ID_MODEL_FROM_DATABASE=P4M890 Host Bridge + +pci:v00001106d00007336* + ID_MODEL_FROM_DATABASE=K8M890CE Host Bridge + +pci:v00001106d00007340* + ID_MODEL_FROM_DATABASE=PT900 Host Bridge + +pci:v00001106d00007351* + ID_MODEL_FROM_DATABASE=VT3351 Host Bridge + +pci:v00001106d00007353* + ID_MODEL_FROM_DATABASE=VX800/VX820 North-South Module Interface Control + +pci:v00001106d00007364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge + +pci:v00001106d00007409* + ID_MODEL_FROM_DATABASE=VX855/VX875 North-South Module Interface Control + +pci:v00001106d00007410* + ID_MODEL_FROM_DATABASE=VX900 North-South Module Interface Control + +pci:v00001106d00007410sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX nano VD01 + +pci:v00001106d00008231* + ID_MODEL_FROM_DATABASE=VT8231 [PCI-to-ISA Bridge] + +pci:v00001106d00008235* + ID_MODEL_FROM_DATABASE=VT8235 ACPI + +pci:v00001106d00008305* + ID_MODEL_FROM_DATABASE=VT8363/8365 [KT133/KM133 AGP] + +pci:v00001106d00008324* + ID_MODEL_FROM_DATABASE=CX700/VX700 PCI to ISA Bridge + +pci:v00001106d00008353* + ID_MODEL_FROM_DATABASE=VX800/VX820 Bus Control and Power Management + +pci:v00001106d00008391* + ID_MODEL_FROM_DATABASE=VT8371 [KX133 AGP] + +pci:v00001106d00008400* + ID_MODEL_FROM_DATABASE=MVP4 + +pci:v00001106d00008409* + ID_MODEL_FROM_DATABASE=VX855/VX875 Bus Control and Power Management + +pci:v00001106d00008410* + ID_MODEL_FROM_DATABASE=VX900 Bus Control and Power Management + +pci:v00001106d00008410sv000019DAsd0000A179* + ID_MODEL_FROM_DATABASE=ZBOX VD01 + +pci:v00001106d00008500* + ID_MODEL_FROM_DATABASE=KLE133/PLE133/PLE133T + +pci:v00001106d00008501* + ID_MODEL_FROM_DATABASE=VT8501 [Apollo MVP4 AGP] + +pci:v00001106d00008596* + ID_MODEL_FROM_DATABASE=VT82C596 [Apollo PRO AGP] + +pci:v00001106d00008597* + ID_MODEL_FROM_DATABASE=VT82C597 [Apollo VP3 AGP] + +pci:v00001106d00008598* + ID_MODEL_FROM_DATABASE=VT82C598/694x [Apollo MVP3/Pro133x AGP] + +pci:v00001106d00008598sv00001019sd00000985* + ID_MODEL_FROM_DATABASE=P6VXA Motherboard + +pci:v00001106d00008601* + ID_MODEL_FROM_DATABASE=VT8601 [Apollo ProMedia AGP] + +pci:v00001106d00008605* + ID_MODEL_FROM_DATABASE=VT8605 [PM133 AGP] + +pci:v00001106d00008691* + ID_MODEL_FROM_DATABASE=VT82C691 [Apollo Pro] + +pci:v00001106d00008693* + ID_MODEL_FROM_DATABASE=VT82C693 [Apollo Pro Plus] PCI Bridge + +pci:v00001106d00008A25* + ID_MODEL_FROM_DATABASE=PL133/PL133T [S3 ProSavage] + +pci:v00001106d00008A26* + ID_MODEL_FROM_DATABASE=KL133/KL133A/KM133/KM133A [S3 ProSavage] + +pci:v00001106d00008D01* + ID_MODEL_FROM_DATABASE=PN133/PN133T [S3 Twister] + +pci:v00001106d00008D04* + ID_MODEL_FROM_DATABASE=KM266/P4M266/P4M266A/P4N266 [S3 ProSavageDDR] + +pci:v00001106d00009001* + ID_MODEL_FROM_DATABASE=VX900 Serial ATA Controller + +pci:v00001106d00009530* + ID_MODEL_FROM_DATABASE=Secure Digital Memory Card Controller + +pci:v00001106d000095D0* + ID_MODEL_FROM_DATABASE=SDIO Host Controller + +pci:v00001106d0000A208* + ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller + +pci:v00001106d0000A238* + ID_MODEL_FROM_DATABASE=K8T890 PCI to PCI Bridge Controller + +pci:v00001106d0000A327* + ID_MODEL_FROM_DATABASE=P4M890 PCI to PCI Bridge Controller + +pci:v00001106d0000A353* + ID_MODEL_FROM_DATABASE=VX8xx South-North Module Interface Control + +pci:v00001106d0000A364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 PCI to PCI Bridge Controller + +pci:v00001106d0000A409* + ID_MODEL_FROM_DATABASE=VX855/VX875 USB Device Controller + +pci:v00001106d0000A410* + ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 0 + +pci:v00001106d0000B091* + ID_MODEL_FROM_DATABASE=VT8633 [Apollo Pro266 AGP] + +pci:v00001106d0000B099* + ID_MODEL_FROM_DATABASE=VT8366/A/7 [Apollo KT266/A/333 AGP] + +pci:v00001106d0000B101* + ID_MODEL_FROM_DATABASE=VT8653 AGP Bridge + +pci:v00001106d0000B102* + ID_MODEL_FROM_DATABASE=VT8362 AGP Bridge + +pci:v00001106d0000B103* + ID_MODEL_FROM_DATABASE=VT8615 AGP Bridge + +pci:v00001106d0000B112* + ID_MODEL_FROM_DATABASE=VT8361 [KLE133] AGP Bridge + +pci:v00001106d0000B113* + ID_MODEL_FROM_DATABASE=VPX/VPX2 I/O APIC Interrupt Controller + +pci:v00001106d0000B115* + ID_MODEL_FROM_DATABASE=VT8363/8365 [KT133/KM133] PCI Bridge + +pci:v00001106d0000B168* + ID_MODEL_FROM_DATABASE=VT8235 PCI Bridge + +pci:v00001106d0000B188* + ID_MODEL_FROM_DATABASE=VT8237/8251 PCI bridge [K8M890/K8T800/K8T890 South] + +pci:v00001106d0000B188sv0000147Bsd00001407* + ID_MODEL_FROM_DATABASE=KV8-MAX3 motherboard + +pci:v00001106d0000B198* + ID_MODEL_FROM_DATABASE=VT8237/VX700 PCI Bridge + +pci:v00001106d0000B213* + ID_MODEL_FROM_DATABASE=VPX/VPX2 I/O APIC Interrupt Controller + +pci:v00001106d0000B353* + ID_MODEL_FROM_DATABASE=VX855/VX875/VX900 PCI to PCI Bridge + +pci:v00001106d0000B410* + ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 1 + +pci:v00001106d0000B999* + ID_MODEL_FROM_DATABASE=[K8T890 North / VT8237 South] PCI Bridge + +pci:v00001106d0000C208* + ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller + +pci:v00001106d0000C238* + ID_MODEL_FROM_DATABASE=K8T890 PCI to PCI Bridge Controller + +pci:v00001106d0000C327* + ID_MODEL_FROM_DATABASE=P4M890 PCI to PCI Bridge Controller + +pci:v00001106d0000C340* + ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller + +pci:v00001106d0000C353* + ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + +pci:v00001106d0000C364* + ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 PCI to PCI Bridge Controller + +pci:v00001106d0000C409* + ID_MODEL_FROM_DATABASE=VX855/VX875 EIDE Controller + +pci:v00001106d0000C410* + ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 2 + +pci:v00001106d0000D104* + ID_MODEL_FROM_DATABASE=VT8237R USB UDCI Controller + +pci:v00001106d0000D208* + ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller + +pci:v00001106d0000D213* + ID_MODEL_FROM_DATABASE=VPX/VPX2 PCI to PCI Bridge Controller + +pci:v00001106d0000D238* + ID_MODEL_FROM_DATABASE=K8T890 PCI to PCI Bridge Controller + +pci:v00001106d0000D340* + ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller + +pci:v00001106d0000D410* + ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 3 + +pci:v00001106d0000E208* + ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller + +pci:v00001106d0000E238* + ID_MODEL_FROM_DATABASE=K8T890 PCI to PCI Bridge Controller + +pci:v00001106d0000E340* + ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller + +pci:v00001106d0000E353* + ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + +pci:v00001106d0000F208* + ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller + +pci:v00001106d0000F238* + ID_MODEL_FROM_DATABASE=K8T890 PCI to PCI Bridge Controller + +pci:v00001106d0000F340* + ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller + +pci:v00001106d0000F353* + ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + +pci:v00001107* + ID_VENDOR_FROM_DATABASE=Stratus Computers + +pci:v00001107d00000576* + ID_MODEL_FROM_DATABASE=VIA VT82C570MV [Apollo] (Wrong vendor ID!) + +pci:v00001108* + ID_VENDOR_FROM_DATABASE=Proteon, Inc. + +pci:v00001108d00000100* + ID_MODEL_FROM_DATABASE=p1690plus_AA + +pci:v00001108d00000101* + ID_MODEL_FROM_DATABASE=p1690plus_AB + +pci:v00001108d00000105* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001108d00000108* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001108d00000138* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001108d00000139* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001108d0000013C* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001108d0000013D* + ID_MODEL_FROM_DATABASE=P1690Plus + +pci:v00001109* + ID_VENDOR_FROM_DATABASE=Cogent Data Technologies, Inc. + +pci:v00001109d00001400* + ID_MODEL_FROM_DATABASE=EM110TX [EX110TX] + +pci:v0000110A* + ID_VENDOR_FROM_DATABASE=Siemens Nixdorf AG + +pci:v0000110Ad00000002* + ID_MODEL_FROM_DATABASE=Pirahna 2-port + +pci:v0000110Ad00000005* + ID_MODEL_FROM_DATABASE=Tulip controller, power management, switch extender + +pci:v0000110Ad00000006* + ID_MODEL_FROM_DATABASE=FSC PINC (I/O-APIC) + +pci:v0000110Ad00000015* + ID_MODEL_FROM_DATABASE=FSC Multiprocessor Interrupt Controller + +pci:v0000110Ad0000001D* + ID_MODEL_FROM_DATABASE=FSC Copernicus Management Controller + +pci:v0000110Ad0000007B* + ID_MODEL_FROM_DATABASE=FSC Remote Service Controller, mailbox device + +pci:v0000110Ad0000007C* + ID_MODEL_FROM_DATABASE=FSC Remote Service Controller, shared memory device + +pci:v0000110Ad0000007D* + ID_MODEL_FROM_DATABASE=FSC Remote Service Controller, SMIC device + +pci:v0000110Ad00002101* + ID_MODEL_FROM_DATABASE=HST SAPHIR V Primary PCI (ISDN/PMx) + +pci:v0000110Ad00002102* + ID_MODEL_FROM_DATABASE=DSCC4 PEB/PEF 20534 DMA Supported Serial Communication Controller with 4 Channels + +pci:v0000110Ad00002104* + ID_MODEL_FROM_DATABASE=Eicon Diva 2.02 compatible passive ISDN card + +pci:v0000110Ad00003141* + ID_MODEL_FROM_DATABASE=SIMATIC NET CP 5611 (Profibus Adapter) + +pci:v0000110Ad00003142* + ID_MODEL_FROM_DATABASE=SIMATIC NET CP 5613A1 (Profibus Adapter) + +pci:v0000110Ad00004021* + ID_MODEL_FROM_DATABASE=SIMATIC NET CP 5512 (Profibus and MPI Cardbus Adapter) + +pci:v0000110Ad00004029* + ID_MODEL_FROM_DATABASE=SIMATIC NET CP 5613A2 (Profibus Adapter) + +pci:v0000110Ad00004035* + ID_MODEL_FROM_DATABASE=SIMATIC NET CP 1613 A2 + +pci:v0000110Ad00004942* + ID_MODEL_FROM_DATABASE=FPGA I-Bus Tracer for MBD + +pci:v0000110Ad00006120* + ID_MODEL_FROM_DATABASE=SZB6120 + +pci:v0000110B* + ID_VENDOR_FROM_DATABASE=Chromatic Research Inc. + +pci:v0000110Bd00000001* + ID_MODEL_FROM_DATABASE=Mpact Media Processor + +pci:v0000110Bd00000004* + ID_MODEL_FROM_DATABASE=Mpact 2 + +pci:v0000110C* + ID_VENDOR_FROM_DATABASE=Mini-Max Technology, Inc. + +pci:v0000110D* + ID_VENDOR_FROM_DATABASE=Znyx Advanced Systems + +pci:v0000110E* + ID_VENDOR_FROM_DATABASE=CPU Technology + +pci:v0000110F* + ID_VENDOR_FROM_DATABASE=Ross Technology + +pci:v00001110* + ID_VENDOR_FROM_DATABASE=Powerhouse Systems + +pci:v00001110d00006037* + ID_MODEL_FROM_DATABASE=Firepower Powerized SMP I/O ASIC + +pci:v00001110d00006073* + ID_MODEL_FROM_DATABASE=Firepower Powerized SMP I/O ASIC + +pci:v00001111* + ID_VENDOR_FROM_DATABASE=Santa Cruz Operation + +pci:v00001112* + ID_VENDOR_FROM_DATABASE=Osicom Technologies Inc + +pci:v00001112d00002200* + ID_MODEL_FROM_DATABASE=FDDI Adapter + +pci:v00001112d00002300* + ID_MODEL_FROM_DATABASE=Fast Ethernet Adapter + +pci:v00001112d00002340* + ID_MODEL_FROM_DATABASE=4 Port Fast Ethernet Adapter + +pci:v00001112d00002400* + ID_MODEL_FROM_DATABASE=ATM Adapter + +pci:v00001113* + ID_VENDOR_FROM_DATABASE=Accton Technology Corporation + +pci:v00001113d00001211* + ID_MODEL_FROM_DATABASE=SMC2-1211TX + +pci:v00001113d00001211sv0000103Csd00001207* + ID_MODEL_FROM_DATABASE=EN-1207D Fast Ethernet Adapter + +pci:v00001113d00001211sv00001113sd00001211* + ID_MODEL_FROM_DATABASE=EN-1207D Fast Ethernet Adapter + +pci:v00001113d00001216* + ID_MODEL_FROM_DATABASE=EN-1216 Ethernet Adapter + +pci:v00001113d00001216sv00001113sd00001216* + ID_MODEL_FROM_DATABASE=EN1207F series PCI Fast Ethernet Adapter + +pci:v00001113d00001216sv00001113sd00002220* + ID_MODEL_FROM_DATABASE=EN2220A Cardbus Fast Ethernet Adapter + +pci:v00001113d00001216sv00001113sd00002242* + ID_MODEL_FROM_DATABASE=EN2242 10/100 Ethernet Mini-PCI Card + +pci:v00001113d00001216sv0000111Asd00001020* + ID_MODEL_FROM_DATABASE=SpeedStream 1020 PCI 10/100 Ethernet Adaptor [EN-1207F-TX ?] + +pci:v00001113d00001217* + ID_MODEL_FROM_DATABASE=EN-1217 Ethernet Adapter + +pci:v00001113d00005105* + ID_MODEL_FROM_DATABASE=10Mbps Network card + +pci:v00001113d00009211* + ID_MODEL_FROM_DATABASE=EN-1207D Fast Ethernet Adapter + +pci:v00001113d00009211sv00001113sd00009211* + ID_MODEL_FROM_DATABASE=EN-1207D Fast Ethernet Adapter + +pci:v00001113d00009511* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible Fast Ethernet + +pci:v00001113d0000D301* + ID_MODEL_FROM_DATABASE=CPWNA100 (Philips wireless PCMCIA) + +pci:v00001113d0000EC02* + ID_MODEL_FROM_DATABASE=SMC 1244TX v3 + +pci:v00001113d0000EE23* + ID_MODEL_FROM_DATABASE=SMCWPCIT-G 108Mbps Wireless PCI adapter + +pci:v00001114* + ID_VENDOR_FROM_DATABASE=Atmel Corporation + +pci:v00001114d00000506* + ID_MODEL_FROM_DATABASE=at76c506 802.11b Wireless Network Adaptor + +pci:v00001115* + ID_VENDOR_FROM_DATABASE=3D Labs + +pci:v00001116* + ID_VENDOR_FROM_DATABASE=Data Translation + +pci:v00001116d00000022* + ID_MODEL_FROM_DATABASE=DT3001 + +pci:v00001116d00000023* + ID_MODEL_FROM_DATABASE=DT3002 + +pci:v00001116d00000024* + ID_MODEL_FROM_DATABASE=DT3003 + +pci:v00001116d00000025* + ID_MODEL_FROM_DATABASE=DT3004 + +pci:v00001116d00000026* + ID_MODEL_FROM_DATABASE=DT3005 + +pci:v00001116d00000027* + ID_MODEL_FROM_DATABASE=DT3001-PGL + +pci:v00001116d00000028* + ID_MODEL_FROM_DATABASE=DT3003-PGL + +pci:v00001116d00000051* + ID_MODEL_FROM_DATABASE=DT322 + +pci:v00001116d00000060* + ID_MODEL_FROM_DATABASE=DT340 + +pci:v00001116d00000069* + ID_MODEL_FROM_DATABASE=DT332 + +pci:v00001116d000080C2* + ID_MODEL_FROM_DATABASE=DT3162 + +pci:v00001117* + ID_VENDOR_FROM_DATABASE=Datacube, Inc + +pci:v00001117d00009500* + ID_MODEL_FROM_DATABASE=Max-1C SVGA card + +pci:v00001117d00009501* + ID_MODEL_FROM_DATABASE=Max-1C image processing + +pci:v00001118* + ID_VENDOR_FROM_DATABASE=Berg Electronics + +pci:v00001119* + ID_VENDOR_FROM_DATABASE=ICP Vortex Computersysteme GmbH + +pci:v00001119d00000000* + ID_MODEL_FROM_DATABASE=GDT 6000/6020/6050 + +pci:v00001119d00000001* + ID_MODEL_FROM_DATABASE=GDT 6000B/6010 + +pci:v00001119d00000002* + ID_MODEL_FROM_DATABASE=GDT 6110/6510 + +pci:v00001119d00000003* + ID_MODEL_FROM_DATABASE=GDT 6120/6520 + +pci:v00001119d00000004* + ID_MODEL_FROM_DATABASE=GDT 6530 + +pci:v00001119d00000005* + ID_MODEL_FROM_DATABASE=GDT 6550 + +pci:v00001119d00000006* + ID_MODEL_FROM_DATABASE=GDT 6117/6517 + +pci:v00001119d00000007* + ID_MODEL_FROM_DATABASE=GDT 6127/6527 + +pci:v00001119d00000008* + ID_MODEL_FROM_DATABASE=GDT 6537 + +pci:v00001119d00000009* + ID_MODEL_FROM_DATABASE=GDT 6557/6557-ECC + +pci:v00001119d0000000A* + ID_MODEL_FROM_DATABASE=GDT 6115/6515 + +pci:v00001119d0000000B* + ID_MODEL_FROM_DATABASE=GDT 6125/6525 + +pci:v00001119d0000000C* + ID_MODEL_FROM_DATABASE=GDT 6535 + +pci:v00001119d0000000D* + ID_MODEL_FROM_DATABASE=GDT 6555/6555-ECC + +pci:v00001119d00000100* + ID_MODEL_FROM_DATABASE=GDT 6117RP/6517RP + +pci:v00001119d00000101* + ID_MODEL_FROM_DATABASE=GDT 6127RP/6527RP + +pci:v00001119d00000102* + ID_MODEL_FROM_DATABASE=GDT 6537RP + +pci:v00001119d00000103* + ID_MODEL_FROM_DATABASE=GDT 6557RP + +pci:v00001119d00000104* + ID_MODEL_FROM_DATABASE=GDT 6111RP/6511RP + +pci:v00001119d00000105* + ID_MODEL_FROM_DATABASE=GDT 6121RP/6521RP + +pci:v00001119d00000110* + ID_MODEL_FROM_DATABASE=GDT 6117RD/6517RD + +pci:v00001119d00000111* + ID_MODEL_FROM_DATABASE=GDT 6127RD/6527RD + +pci:v00001119d00000112* + ID_MODEL_FROM_DATABASE=GDT 6537RD + +pci:v00001119d00000113* + ID_MODEL_FROM_DATABASE=GDT 6557RD + +pci:v00001119d00000114* + ID_MODEL_FROM_DATABASE=GDT 6111RD/6511RD + +pci:v00001119d00000115* + ID_MODEL_FROM_DATABASE=GDT 6121RD/6521RD + +pci:v00001119d00000118* + ID_MODEL_FROM_DATABASE=GDT 6118RD/6518RD/6618RD + +pci:v00001119d00000119* + ID_MODEL_FROM_DATABASE=GDT 6128RD/6528RD/6628RD + +pci:v00001119d0000011A* + ID_MODEL_FROM_DATABASE=GDT 6538RD/6638RD + +pci:v00001119d0000011B* + ID_MODEL_FROM_DATABASE=GDT 6558RD/6658RD + +pci:v00001119d00000120* + ID_MODEL_FROM_DATABASE=GDT 6117RP2/6517RP2 + +pci:v00001119d00000121* + ID_MODEL_FROM_DATABASE=GDT 6127RP2/6527RP2 + +pci:v00001119d00000122* + ID_MODEL_FROM_DATABASE=GDT 6537RP2 + +pci:v00001119d00000123* + ID_MODEL_FROM_DATABASE=GDT 6557RP2 + +pci:v00001119d00000124* + ID_MODEL_FROM_DATABASE=GDT 6111RP2/6511RP2 + +pci:v00001119d00000125* + ID_MODEL_FROM_DATABASE=GDT 6121RP2/6521RP2 + +pci:v00001119d00000136* + ID_MODEL_FROM_DATABASE=GDT 6113RS/6513RS + +pci:v00001119d00000137* + ID_MODEL_FROM_DATABASE=GDT 6123RS/6523RS + +pci:v00001119d00000138* + ID_MODEL_FROM_DATABASE=GDT 6118RS/6518RS/6618RS + +pci:v00001119d00000139* + ID_MODEL_FROM_DATABASE=GDT 6128RS/6528RS/6628RS + +pci:v00001119d0000013A* + ID_MODEL_FROM_DATABASE=GDT 6538RS/6638RS + +pci:v00001119d0000013B* + ID_MODEL_FROM_DATABASE=GDT 6558RS/6658RS + +pci:v00001119d0000013C* + ID_MODEL_FROM_DATABASE=GDT 6533RS/6633RS + +pci:v00001119d0000013D* + ID_MODEL_FROM_DATABASE=GDT 6543RS/6643RS + +pci:v00001119d0000013E* + ID_MODEL_FROM_DATABASE=GDT 6553RS/6653RS + +pci:v00001119d0000013F* + ID_MODEL_FROM_DATABASE=GDT 6563RS/6663RS + +pci:v00001119d00000166* + ID_MODEL_FROM_DATABASE=GDT 7113RN/7513RN/7613RN + +pci:v00001119d00000167* + ID_MODEL_FROM_DATABASE=GDT 7123RN/7523RN/7623RN + +pci:v00001119d00000168* + ID_MODEL_FROM_DATABASE=GDT 7118RN/7518RN/7518RN + +pci:v00001119d00000169* + ID_MODEL_FROM_DATABASE=GDT 7128RN/7528RN/7628RN + +pci:v00001119d0000016A* + ID_MODEL_FROM_DATABASE=GDT 7538RN/7638RN + +pci:v00001119d0000016B* + ID_MODEL_FROM_DATABASE=GDT 7558RN/7658RN + +pci:v00001119d0000016C* + ID_MODEL_FROM_DATABASE=GDT 7533RN/7633RN + +pci:v00001119d0000016D* + ID_MODEL_FROM_DATABASE=GDT 7543RN/7643RN + +pci:v00001119d0000016E* + ID_MODEL_FROM_DATABASE=GDT 7553RN/7653RN + +pci:v00001119d0000016F* + ID_MODEL_FROM_DATABASE=GDT 7563RN/7663RN + +pci:v00001119d000001D6* + ID_MODEL_FROM_DATABASE=GDT 4x13RZ + +pci:v00001119d000001D7* + ID_MODEL_FROM_DATABASE=GDT 4x23RZ + +pci:v00001119d000001F6* + ID_MODEL_FROM_DATABASE=GDT 8x13RZ + +pci:v00001119d000001F7* + ID_MODEL_FROM_DATABASE=GDT 8x23RZ + +pci:v00001119d000001FC* + ID_MODEL_FROM_DATABASE=GDT 8x33RZ + +pci:v00001119d000001FD* + ID_MODEL_FROM_DATABASE=GDT 8x43RZ + +pci:v00001119d000001FE* + ID_MODEL_FROM_DATABASE=GDT 8x53RZ + +pci:v00001119d000001FF* + ID_MODEL_FROM_DATABASE=GDT 8x63RZ + +pci:v00001119d00000210* + ID_MODEL_FROM_DATABASE=GDT 6519RD/6619RD + +pci:v00001119d00000211* + ID_MODEL_FROM_DATABASE=GDT 6529RD/6629RD + +pci:v00001119d00000260* + ID_MODEL_FROM_DATABASE=GDT 7519RN/7619RN + +pci:v00001119d00000261* + ID_MODEL_FROM_DATABASE=GDT 7529RN/7629RN + +pci:v00001119d000002FF* + ID_MODEL_FROM_DATABASE=GDT MAXRP + +pci:v00001119d00000300* + ID_MODEL_FROM_DATABASE=GDT NEWRX + +pci:v00001119d00000301* + ID_MODEL_FROM_DATABASE=GDT NEWRX2 + +pci:v0000111A* + ID_VENDOR_FROM_DATABASE=Efficient Networks, Inc + +pci:v0000111Ad00000000* + ID_MODEL_FROM_DATABASE=155P-MF1 (FPGA) + +pci:v0000111Ad00000002* + ID_MODEL_FROM_DATABASE=155P-MF1 (ASIC) + +pci:v0000111Ad00000003* + ID_MODEL_FROM_DATABASE=ENI-25P ATM + +pci:v0000111Ad00000003sv0000111Asd00000000* + ID_MODEL_FROM_DATABASE=ENI-25p Miniport ATM Adapter + +pci:v0000111Ad00000005* + ID_MODEL_FROM_DATABASE=SpeedStream (LANAI) + +pci:v0000111Ad00000005sv0000111Asd00000001* + ID_MODEL_FROM_DATABASE=ENI-3010 ATM + +pci:v0000111Ad00000005sv0000111Asd00000009* + ID_MODEL_FROM_DATABASE=ENI-3060 ADSL (VPI=0) + +pci:v0000111Ad00000005sv0000111Asd00000101* + ID_MODEL_FROM_DATABASE=ENI-3010 ATM + +pci:v0000111Ad00000005sv0000111Asd00000109* + ID_MODEL_FROM_DATABASE=ENI-3060CO ADSL (VPI=0) + +pci:v0000111Ad00000005sv0000111Asd00000809* + ID_MODEL_FROM_DATABASE=ENI-3060 ADSL (VPI=0 or 8) + +pci:v0000111Ad00000005sv0000111Asd00000909* + ID_MODEL_FROM_DATABASE=ENI-3060CO ADSL (VPI=0 or 8) + +pci:v0000111Ad00000005sv0000111Asd00000A09* + ID_MODEL_FROM_DATABASE=ENI-3060 ADSL (VPI=<0..15>) + +pci:v0000111Ad00000007* + ID_MODEL_FROM_DATABASE=SpeedStream ADSL + +pci:v0000111Ad00000007sv0000111Asd00001001* + ID_MODEL_FROM_DATABASE=ENI-3061 ADSL [ASIC] + +pci:v0000111Ad00001020* + ID_MODEL_FROM_DATABASE=SpeedStream PCI 10/100 Network Card + +pci:v0000111Ad00001203* + ID_MODEL_FROM_DATABASE=SpeedStream 1023 Wireless PCI Adapter + +pci:v0000111B* + ID_VENDOR_FROM_DATABASE=Teledyne Electronic Systems + +pci:v0000111C* + ID_VENDOR_FROM_DATABASE=Tricord Systems Inc. + +pci:v0000111Cd00000001* + ID_MODEL_FROM_DATABASE=Powerbis Bridge + +pci:v0000111D* + ID_VENDOR_FROM_DATABASE=Integrated Device Technology, Inc. [IDT] + +pci:v0000111Dd00000001* + ID_MODEL_FROM_DATABASE=IDT77201/77211 155Mbps ATM SAR Controller [NICStAR] + +pci:v0000111Dd00000003* + ID_MODEL_FROM_DATABASE=IDT77222/77252 155Mbps ATM MICRO ABR SAR Controller + +pci:v0000111Dd00000004* + ID_MODEL_FROM_DATABASE=IDT77V252 155Mbps ATM MICRO ABR SAR Controller + +pci:v0000111Dd00000005* + ID_MODEL_FROM_DATABASE=IDT77V222 155Mbps ATM MICRO ABR SAR Controller + +pci:v0000111Dd00008018* + ID_MODEL_FROM_DATABASE=PES12N3A PCI Express Switch + +pci:v0000111Dd0000801C* + ID_MODEL_FROM_DATABASE=PES24N3A PCI Express Switch + +pci:v0000111Dd00008028* + ID_MODEL_FROM_DATABASE=PES4T4 PCI Express Switch + +pci:v0000111Dd0000802B* + ID_MODEL_FROM_DATABASE=PES8T5A PCI Express Switch + +pci:v0000111Dd0000802C* + ID_MODEL_FROM_DATABASE=PES16T4 PCI Express Switch + +pci:v0000111Dd0000802D* + ID_MODEL_FROM_DATABASE=PES16T7 PCI Express Switch + +pci:v0000111Dd0000802E* + ID_MODEL_FROM_DATABASE=PES24T6 PCI Express Switch + +pci:v0000111Dd0000802F* + ID_MODEL_FROM_DATABASE=PES32T8 PCI Express Switch + +pci:v0000111Dd00008032* + ID_MODEL_FROM_DATABASE=PES48T12 PCI Express Switch + +pci:v0000111Dd00008034* + ID_MODEL_FROM_DATABASE=PES16/22/34H16 PCI Express Switch + +pci:v0000111Dd00008035* + ID_MODEL_FROM_DATABASE=PES32H8 PCI Express Switch + +pci:v0000111Dd00008036* + ID_MODEL_FROM_DATABASE=PES48H12 PCI Express Switch + +pci:v0000111Dd00008037* + ID_MODEL_FROM_DATABASE=PES64H16 PCI Express Switch + +pci:v0000111Dd00008039* + ID_MODEL_FROM_DATABASE=PES3T3 PCI Express Switch + +pci:v0000111Dd0000803A* + ID_MODEL_FROM_DATABASE=PES4T4 PCI Express Switch + +pci:v0000111Dd0000803C* + ID_MODEL_FROM_DATABASE=PES5T5 PCI Express Switch + +pci:v0000111Dd0000803D* + ID_MODEL_FROM_DATABASE=PES6T5 PCI Express Switch + +pci:v0000111Dd00008048* + ID_MODEL_FROM_DATABASE=PES8NT2 PCI Express Switch + +pci:v0000111Dd00008049* + ID_MODEL_FROM_DATABASE=PES8NT2 PCI Express Switch + +pci:v0000111Dd0000804A* + ID_MODEL_FROM_DATABASE=PES8NT2 PCI Express Internal NTB + +pci:v0000111Dd0000804B* + ID_MODEL_FROM_DATABASE=PES8NT2 PCI Express External NTB + +pci:v0000111Dd0000804C* + ID_MODEL_FROM_DATABASE=PES16NT2 PCI Express Switch + +pci:v0000111Dd0000804D* + ID_MODEL_FROM_DATABASE=PES16NT2 PCI Express Switch + +pci:v0000111Dd0000804E* + ID_MODEL_FROM_DATABASE=PES16NT2 PCI Express Internal NTB + +pci:v0000111Dd0000804F* + ID_MODEL_FROM_DATABASE=PES16NT2 PCI Express External NTB + +pci:v0000111Dd00008058* + ID_MODEL_FROM_DATABASE=PES12NT3 PCI Express Switch + +pci:v0000111Dd00008059* + ID_MODEL_FROM_DATABASE=PES12NT3 PCI Express Switch + +pci:v0000111Dd0000805A* + ID_MODEL_FROM_DATABASE=PES12NT3 PCI Express Internal NTB + +pci:v0000111Dd0000805B* + ID_MODEL_FROM_DATABASE=PES12NT3 PCI Express External NTB + +pci:v0000111Dd0000805C* + ID_MODEL_FROM_DATABASE=PES24NT3 PCI Express Switch + +pci:v0000111Dd0000805D* + ID_MODEL_FROM_DATABASE=PES24NT3 PCI Express Switch + +pci:v0000111Dd0000805E* + ID_MODEL_FROM_DATABASE=PES24NT3 PCI Express Internal NTB + +pci:v0000111Dd0000805F* + ID_MODEL_FROM_DATABASE=PES24NT3 PCI Express External NTB + +pci:v0000111Dd00008060* + ID_MODEL_FROM_DATABASE=PES16T4G2 PCI Express Gen2 Switch + +pci:v0000111Dd00008061* + ID_MODEL_FROM_DATABASE=PES12T3G2 PCI Express Gen2 Switch + +pci:v0000111Dd00008068* + ID_MODEL_FROM_DATABASE=PES6T6G2 PCI Express Gen2 Switch + +pci:v0000111Dd0000806A* + ID_MODEL_FROM_DATABASE=PES24T3G2 PCI Express Gen2 Switch + +pci:v0000111Dd0000806Asv000014C1sd0000000C* + ID_MODEL_FROM_DATABASE=10G-PCIE2-8B2 + +pci:v0000111Dd0000806C* + ID_MODEL_FROM_DATABASE=PES16T4A/4T4G2 PCI Express Gen2 Switch + +pci:v0000111Dd0000806E* + ID_MODEL_FROM_DATABASE=PES24T6G2 PCI Express Gen2 Switch + +pci:v0000111Dd0000806F* + ID_MODEL_FROM_DATABASE=HIO524G2 PCI Express Gen2 Switch + +pci:v0000111E* + ID_VENDOR_FROM_DATABASE=Eldec + +pci:v0000111F* + ID_VENDOR_FROM_DATABASE=Precision Digital Images + +pci:v0000111Fd00004A47* + ID_MODEL_FROM_DATABASE=Precision MX Video engine interface + +pci:v0000111Fd00005243* + ID_MODEL_FROM_DATABASE=Frame capture bus interface + +pci:v00001120* + ID_VENDOR_FROM_DATABASE=EMC Corporation + +pci:v00001121* + ID_VENDOR_FROM_DATABASE=Zilog + +pci:v00001122* + ID_VENDOR_FROM_DATABASE=Multi-tech Systems, Inc. + +pci:v00001123* + ID_VENDOR_FROM_DATABASE=Excellent Design, Inc. + +pci:v00001124* + ID_VENDOR_FROM_DATABASE=Leutron Vision AG + +pci:v00001124d00002581* + ID_MODEL_FROM_DATABASE=Picport Monochrome + +pci:v00001125* + ID_VENDOR_FROM_DATABASE=Eurocore + +pci:v00001126* + ID_VENDOR_FROM_DATABASE=Vigra + +pci:v00001127* + ID_VENDOR_FROM_DATABASE=FORE Systems Inc + +pci:v00001127d00000200* + ID_MODEL_FROM_DATABASE=ForeRunner PCA-200 ATM + +pci:v00001127d00000210* + ID_MODEL_FROM_DATABASE=PCA-200PC + +pci:v00001127d00000250* + ID_MODEL_FROM_DATABASE=ATM + +pci:v00001127d00000300* + ID_MODEL_FROM_DATABASE=ForeRunner PCA-200EPC ATM + +pci:v00001127d00000310* + ID_MODEL_FROM_DATABASE=ATM + +pci:v00001127d00000400* + ID_MODEL_FROM_DATABASE=ForeRunnerHE ATM Adapter + +pci:v00001127d00000400sv00001127sd00000400* + ID_MODEL_FROM_DATABASE=ForeRunnerHE ATM + +pci:v00001129* + ID_VENDOR_FROM_DATABASE=Firmworks + +pci:v0000112A* + ID_VENDOR_FROM_DATABASE=Hermes Electronics Company, Ltd. + +pci:v0000112B* + ID_VENDOR_FROM_DATABASE=Linotype - Hell AG + +pci:v0000112C* + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +pci:v0000112D* + ID_VENDOR_FROM_DATABASE=Ravicad + +pci:v0000112E* + ID_VENDOR_FROM_DATABASE=Infomedia Microelectronics Inc. + +pci:v0000112F* + ID_VENDOR_FROM_DATABASE=Dalsa Inc. + +pci:v0000112Fd00000000* + ID_MODEL_FROM_DATABASE=MVC IC-PCI + +pci:v0000112Fd00000001* + ID_MODEL_FROM_DATABASE=MVC IM-PCI Video frame grabber/processor + +pci:v0000112Fd00000008* + ID_MODEL_FROM_DATABASE=PC-CamLink PCI framegrabber + +pci:v00001130* + ID_VENDOR_FROM_DATABASE=Computervision + +pci:v00001131* + ID_VENDOR_FROM_DATABASE=Philips Semiconductors + +pci:v00001131d00001561* + ID_MODEL_FROM_DATABASE=USB 1.1 Host Controller + +pci:v00001131d00001561sv00001775sd0000C200* + ID_MODEL_FROM_DATABASE=C2K onboard USB 1.1 host controller + +pci:v00001131d00001562* + ID_MODEL_FROM_DATABASE=USB 2.0 Host Controller + +pci:v00001131d00001562sv00001775sd0000C200* + ID_MODEL_FROM_DATABASE=C2K onboard USB 2.0 host controller + +pci:v00001131d00003400* + ID_MODEL_FROM_DATABASE=SmartPCI56(UCB1500) 56K Modem + +pci:v00001131d00005400* + ID_MODEL_FROM_DATABASE=TriMedia TM1000/1100 + +pci:v00001131d00005400sv000012CAsd00000000* + ID_MODEL_FROM_DATABASE=BlueICE + +pci:v00001131d00005402* + ID_MODEL_FROM_DATABASE=TriMedia TM1300 + +pci:v00001131d00005402sv00001244sd00000F00* + ID_MODEL_FROM_DATABASE=Fritz!Card DSL + +pci:v00001131d00005402sv000015EBsd00001300* + ID_MODEL_FROM_DATABASE=DT1300 + +pci:v00001131d00005402sv000015EBsd00001302* + ID_MODEL_FROM_DATABASE=DT1302 + +pci:v00001131d00005402sv000015EBsd00001304* + ID_MODEL_FROM_DATABASE=DT1304 + +pci:v00001131d00005402sv000015EBsd00001305* + ID_MODEL_FROM_DATABASE=DT1305 + +pci:v00001131d00005402sv000015EBsd00001306* + ID_MODEL_FROM_DATABASE=PMCDT1306 + +pci:v00001131d00005402sv000015EBsd00001308* + ID_MODEL_FROM_DATABASE=DT1308 + +pci:v00001131d00005402sv000015EBsd00001331* + ID_MODEL_FROM_DATABASE=DT1301 with SAA7121 + +pci:v00001131d00005402sv000015EBsd00001337* + ID_MODEL_FROM_DATABASE=DT1301 with SAA7127 + +pci:v00001131d00005402sv000015EBsd00002D3D* + ID_MODEL_FROM_DATABASE=X3D + +pci:v00001131d00005402sv000015EBsd00007022* + ID_MODEL_FROM_DATABASE=PTM1300 + +pci:v00001131d00005405* + ID_MODEL_FROM_DATABASE=TriMedia TM1500 + +pci:v00001131d00005405sv00001136sd00000005* + ID_MODEL_FROM_DATABASE=LCP-1500 + +pci:v00001131d00005406* + ID_MODEL_FROM_DATABASE=TriMedia TM1700 + +pci:v00001131d0000540B* + ID_MODEL_FROM_DATABASE=PNX1005 Media Processor + +pci:v00001131d0000540Bsv00001131sd00000020* + ID_MODEL_FROM_DATABASE=PNXLite PCI Demo Board + +pci:v00001131d00007130* + ID_MODEL_FROM_DATABASE=SAA7130 Video Broadcast Decoder + +pci:v00001131d00007130sv00000000sd00004016* + ID_MODEL_FROM_DATABASE=Behold TV 401 + +pci:v00001131d00007130sv00000000sd00004051* + ID_MODEL_FROM_DATABASE=Behold TV 405 FM + +pci:v00001131d00007130sv00000000sd00005051* + ID_MODEL_FROM_DATABASE=Behold TV 505 RDS + +pci:v00001131d00007130sv00000000sd0000505B* + ID_MODEL_FROM_DATABASE=Behold TV 505 RDS + +pci:v00001131d00007130sv0000102Bsd000048D0* + ID_MODEL_FROM_DATABASE=Matrox CronosPlus + +pci:v00001131d00007130sv00001048sd0000226B* + ID_MODEL_FROM_DATABASE=ELSA EX-VISION 300TV + +pci:v00001131d00007130sv0000107Dsd00006655* + ID_MODEL_FROM_DATABASE=WinFast DTV1000S + +pci:v00001131d00007130sv00001131sd00000000* + ID_MODEL_FROM_DATABASE=SAA7130-based TV tuner card + +pci:v00001131d00007130sv00001131sd00002001* + ID_MODEL_FROM_DATABASE=10MOONS PCI TV CAPTURE CARD + +pci:v00001131d00007130sv00001131sd00002005* + ID_MODEL_FROM_DATABASE=Techcom (India) TV Tuner Card (SSD-TV-670) + +pci:v00001131d00007130sv00001458sd00009006* + ID_MODEL_FROM_DATABASE=GT-PS700 DVB-S tuner + +pci:v00001131d00007130sv00001461sd0000050C* + ID_MODEL_FROM_DATABASE=Nagase Sangyo TransGear 3000TV + +pci:v00001131d00007130sv00001461sd000010FF* + ID_MODEL_FROM_DATABASE=AVerMedia DVD EZMaker + +pci:v00001131d00007130sv00001461sd00002108* + ID_MODEL_FROM_DATABASE=AverMedia AverTV/305 + +pci:v00001131d00007130sv00001461sd00002115* + ID_MODEL_FROM_DATABASE=AverMedia AverTV Studio 305 + +pci:v00001131d00007130sv0000153Bsd00001152* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 200 TV + +pci:v00001131d00007130sv0000185Bsd0000C100* + ID_MODEL_FROM_DATABASE=Compro VideoMate TV PVR/FM + +pci:v00001131d00007130sv0000185Bsd0000C901* + ID_MODEL_FROM_DATABASE=Videomate DVB-T200 + +pci:v00001131d00007130sv00005168sd00000138* + ID_MODEL_FROM_DATABASE=LifeView FlyVIDEO2000 + +pci:v00001131d00007130sv00005ACEsd00005010* + ID_MODEL_FROM_DATABASE=Behold TV 501 + +pci:v00001131d00007130sv00005ACEsd00005050* + ID_MODEL_FROM_DATABASE=Behold TV 505 FM + +pci:v00001131d00007133* + ID_MODEL_FROM_DATABASE=SAA7131/SAA7133/SAA7135 Video Broadcast Decoder + +pci:v00001131d00007133sv00000000sd00004091* + ID_MODEL_FROM_DATABASE=Beholder BeholdTV 409 FM + +pci:v00001131d00007133sv00000000sd00005071* + ID_MODEL_FROM_DATABASE=Behold TV 507 RDS + +pci:v00001131d00007133sv00000000sd0000507B* + ID_MODEL_FROM_DATABASE=Behold TV 507 RDS + +pci:v00001131d00007133sv00000000sd00005201* + ID_MODEL_FROM_DATABASE=Behold TV Columbus + +pci:v00001131d00007133sv00000070sd00006701* + ID_MODEL_FROM_DATABASE=WinTV HVR-1110 + +pci:v00001131d00007133sv00001019sd00004CB5* + ID_MODEL_FROM_DATABASE=Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) + +pci:v00001131d00007133sv00001043sd00000210* + ID_MODEL_FROM_DATABASE=FlyTV mini Asus Digimatrix + +pci:v00001131d00007133sv00001043sd00004843* + ID_MODEL_FROM_DATABASE=ASUS TV-FM 7133 + +pci:v00001131d00007133sv00001043sd00004845* + ID_MODEL_FROM_DATABASE=TV-FM 7135 + +pci:v00001131d00007133sv00001043sd00004862* + ID_MODEL_FROM_DATABASE=P7131 Dual + +pci:v00001131d00007133sv00001043sd00004876* + ID_MODEL_FROM_DATABASE=My Cinema-P7131 Hybrid + +pci:v00001131d00007133sv00001131sd00000000* + ID_MODEL_FROM_DATABASE=SAA713x-based TV tuner card + +pci:v00001131d00007133sv00001131sd00002001* + ID_MODEL_FROM_DATABASE=Proteus Pro [philips reference design] + +pci:v00001131d00007133sv00001131sd00002018* + ID_MODEL_FROM_DATABASE=Tiger reference design + +pci:v00001131d00007133sv00001131sd00004EE9* + ID_MODEL_FROM_DATABASE=MonsterTV Mobile + +pci:v00001131d00007133sv00001131sd00007133* + ID_MODEL_FROM_DATABASE=Pinnacle PCTV 301i + +pci:v00001131d00007133sv000011BDsd0000002B* + ID_MODEL_FROM_DATABASE=PCTV Stereo + +pci:v00001131d00007133sv000011BDsd0000002E* + ID_MODEL_FROM_DATABASE=PCTV 110i (saa7133) + +pci:v00001131d00007133sv000012ABsd00000800* + ID_MODEL_FROM_DATABASE=PURPLE TV + +pci:v00001131d00007133sv000013C2sd00002804* + ID_MODEL_FROM_DATABASE=Technotrend Budget T-3000 Hybrid + +pci:v00001131d00007133sv00001421sd00000335* + ID_MODEL_FROM_DATABASE=Instant TV DVB-T Cardbus + +pci:v00001131d00007133sv00001421sd00001370* + ID_MODEL_FROM_DATABASE=Instant TV (saa7135) + +pci:v00001131d00007133sv00001435sd00007330* + ID_MODEL_FROM_DATABASE=VFG7330 + +pci:v00001131d00007133sv00001435sd00007350* + ID_MODEL_FROM_DATABASE=VFG7350 + +pci:v00001131d00007133sv00001458sd00009001* + ID_MODEL_FROM_DATABASE=GC-PTV-TAF Hybrid TV card + +pci:v00001131d00007133sv00001458sd00009002* + ID_MODEL_FROM_DATABASE=GT-PTV-TAF-RH DVB-T/Analog TV/FM tuner + +pci:v00001131d00007133sv00001458sd00009003* + ID_MODEL_FROM_DATABASE=GT-PTV-AF-RH Analog TV/FM tuner + +pci:v00001131d00007133sv00001458sd00009004* + ID_MODEL_FROM_DATABASE=GT-P8000 DVB-T/Analog TV/FM tuner + +pci:v00001131d00007133sv00001458sd00009005* + ID_MODEL_FROM_DATABASE=GT-P6000 Analog TV/FM tuner + +pci:v00001131d00007133sv00001458sd00009008* + ID_MODEL_FROM_DATABASE=GT-P5100 Analog TV tuner + +pci:v00001131d00007133sv00001461sd00001044* + ID_MODEL_FROM_DATABASE=AVerTVHD MCE A180 + +pci:v00001131d00007133sv00001461sd00004836* + ID_MODEL_FROM_DATABASE=M10D Hybrid DVBT + +pci:v00001131d00007133sv00001461sd0000861E* + ID_MODEL_FROM_DATABASE=M105 PAL/SECAM/NTSC/FM Tuner + +pci:v00001131d00007133sv00001461sd0000A14B* + ID_MODEL_FROM_DATABASE=AVerTV Studio 509 + +pci:v00001131d00007133sv00001461sd0000A836* + ID_MODEL_FROM_DATABASE=M115 DVB-T, PAL/SECAM/NTSC Tuner + +pci:v00001131d00007133sv00001461sd0000F01D* + ID_MODEL_FROM_DATABASE=DVB-T Super 007 + +pci:v00001131d00007133sv00001461sd0000F31F* + ID_MODEL_FROM_DATABASE=Avermedia AVerTV GO 007 FM + +pci:v00001131d00007133sv00001461sd0000F936* + ID_MODEL_FROM_DATABASE=Hybrid+FM PCI (rev A16D) + +pci:v00001131d00007133sv00001462sd00006231* + ID_MODEL_FROM_DATABASE=TV@nywhere Plus + +pci:v00001131d00007133sv00001489sd00000214* + ID_MODEL_FROM_DATABASE=LifeView FlyTV Platinum FM + +pci:v00001131d00007133sv000014C0sd00001212* + ID_MODEL_FROM_DATABASE=LifeView FlyTV Platinum Mini2 + +pci:v00001131d00007133sv0000153Bsd00001160* + ID_MODEL_FROM_DATABASE=Cinergy 250 PCI TV + +pci:v00001131d00007133sv0000153Bsd00001162* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 400 mobile + +pci:v00001131d00007133sv000017DEsd00007350* + ID_MODEL_FROM_DATABASE=ATSC 110 Digital / Analog HDTV Tuner + +pci:v00001131d00007133sv000017DEsd00007352* + ID_MODEL_FROM_DATABASE=ATSC 115 Digital / Analog HDTV Tuner + +pci:v00001131d00007133sv0000185Bsd0000C100* + ID_MODEL_FROM_DATABASE=VideoMate TV + +pci:v00001131d00007133sv0000185Bsd0000C900* + ID_MODEL_FROM_DATABASE=VideoMate T750 + +pci:v00001131d00007133sv00005168sd00000306* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB-T DUO + +pci:v00001131d00007133sv00005168sd00000319* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB Trio + +pci:v00001131d00007133sv00005168sd00000502* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB-T Duo CardBus + +pci:v00001131d00007133sv00005168sd00000520* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB Trio CardBus + +pci:v00001131d00007133sv00005168sd00001502* + ID_MODEL_FROM_DATABASE=LifeView FlyTV CardBus + +pci:v00001131d00007133sv00005168sd00002502* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB-T CardBus + +pci:v00001131d00007133sv00005168sd00002520* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB-S Duo CardBus + +pci:v00001131d00007133sv00005168sd00003502* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB-T Hybrid CardBus + +pci:v00001131d00007133sv00005168sd00003520* + ID_MODEL_FROM_DATABASE=LifeView FlyDVB Trio N CardBus + +pci:v00001131d00007133sv00005ACEsd00005030* + ID_MODEL_FROM_DATABASE=Behold TV 503 FM + +pci:v00001131d00007133sv00005ACEsd00005090* + ID_MODEL_FROM_DATABASE=Behold TV 509 FM + +pci:v00001131d00007133sv00005ACEsd00006090* + ID_MODEL_FROM_DATABASE=Behold TV 609 FM + +pci:v00001131d00007133sv00005ACEsd00006091* + ID_MODEL_FROM_DATABASE=Behold TV 609 FM + +pci:v00001131d00007133sv00005ACEsd00006092* + ID_MODEL_FROM_DATABASE=Behold TV 609 RDS + +pci:v00001131d00007133sv00005ACEsd00006093* + ID_MODEL_FROM_DATABASE=Behold TV 609 RDS + +pci:v00001131d00007133sv00005ACEsd00006190* + ID_MODEL_FROM_DATABASE=Behold TV M6 + +pci:v00001131d00007133sv00005ACEsd00006191* + ID_MODEL_FROM_DATABASE=Behold TV M63 + +pci:v00001131d00007133sv00005ACEsd00006193* + ID_MODEL_FROM_DATABASE=Behold TV M6 Extra + +pci:v00001131d00007133sv00005ACEsd00006290* + ID_MODEL_FROM_DATABASE=Behold TV H6 + +pci:v00001131d00007133sv00005ACEsd00007090* + ID_MODEL_FROM_DATABASE=Behold TV A7 + +pci:v00001131d00007133sv00005ACEsd00007190* + ID_MODEL_FROM_DATABASE=Behold TV H7 + +pci:v00001131d00007133sv00005ACEsd00007595* + ID_MODEL_FROM_DATABASE=Behold TV X7 + +pci:v00001131d00007134* + ID_MODEL_FROM_DATABASE=SAA7134/SAA7135HL Video Broadcast Decoder + +pci:v00001131d00007134sv00000000sd00004036* + ID_MODEL_FROM_DATABASE=Behold TV 403 + +pci:v00001131d00007134sv00000000sd00004037* + ID_MODEL_FROM_DATABASE=Behold TV 403 FM + +pci:v00001131d00007134sv00000000sd00004071* + ID_MODEL_FROM_DATABASE=Behold TV 407 FM + +pci:v00001131d00007134sv00001019sd00004CB4* + ID_MODEL_FROM_DATABASE=Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) + +pci:v00001131d00007134sv00001043sd00000210* + ID_MODEL_FROM_DATABASE=Digimatrix TV + +pci:v00001131d00007134sv00001043sd00004840* + ID_MODEL_FROM_DATABASE=ASUS TV-FM 7134 + +pci:v00001131d00007134sv00001043sd00004842* + ID_MODEL_FROM_DATABASE=TV-FM 7134 + +pci:v00001131d00007134sv00001131sd00000000* + ID_MODEL_FROM_DATABASE=SAA713x-based TV tuner card + +pci:v00001131d00007134sv00001131sd00002004* + ID_MODEL_FROM_DATABASE=EUROPA V3 reference design + +pci:v00001131d00007134sv00001131sd00004E85* + ID_MODEL_FROM_DATABASE=SKNet Monster TV + +pci:v00001131d00007134sv00001131sd00006752* + ID_MODEL_FROM_DATABASE=EMPRESS + +pci:v00001131d00007134sv000011BDsd0000002B* + ID_MODEL_FROM_DATABASE=PCTV Stereo + +pci:v00001131d00007134sv000011BDsd0000002D* + ID_MODEL_FROM_DATABASE=PCTV 300i DVB-T + PAL + +pci:v00001131d00007134sv00001461sd00002C00* + ID_MODEL_FROM_DATABASE=AverTV Hybrid+FM PCI + +pci:v00001131d00007134sv00001461sd00009715* + ID_MODEL_FROM_DATABASE=AVerTV Studio 307 + +pci:v00001131d00007134sv00001461sd0000A70A* + ID_MODEL_FROM_DATABASE=Avermedia AVerTV 307 + +pci:v00001131d00007134sv00001461sd0000A70B* + ID_MODEL_FROM_DATABASE=AverMedia M156 / Medion 2819 + +pci:v00001131d00007134sv00001461sd0000D6EE* + ID_MODEL_FROM_DATABASE=Cardbus TV/Radio (E500) + +pci:v00001131d00007134sv00001471sd0000B7E9* + ID_MODEL_FROM_DATABASE=AVerTV Cardbus plus + +pci:v00001131d00007134sv0000153Bsd00001142* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 400 TV + +pci:v00001131d00007134sv0000153Bsd00001143* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 600 TV + +pci:v00001131d00007134sv0000153Bsd00001158* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 600 TV MK3 + +pci:v00001131d00007134sv00001540sd00009524* + ID_MODEL_FROM_DATABASE=ProVideo PV952 + +pci:v00001131d00007134sv000016BEsd00000003* + ID_MODEL_FROM_DATABASE=Medion 7134 + +pci:v00001131d00007134sv0000185Bsd0000C200* + ID_MODEL_FROM_DATABASE=Compro VideoMate Gold+ Pal + +pci:v00001131d00007134sv0000185Bsd0000C900* + ID_MODEL_FROM_DATABASE=Videomate DVB-T300 + +pci:v00001131d00007134sv00001894sd0000A006* + ID_MODEL_FROM_DATABASE=KNC One TV-Station DVR + +pci:v00001131d00007134sv00001894sd0000FE01* + ID_MODEL_FROM_DATABASE=KNC One TV-Station RDS / Typhoon TV Tuner RDS + +pci:v00001131d00007134sv00005168sd00000138* + ID_MODEL_FROM_DATABASE=FLY TV PRIME 34FM + +pci:v00001131d00007134sv00005168sd00000300* + ID_MODEL_FROM_DATABASE=FlyDVB-S + +pci:v00001131d00007134sv00005ACEsd00005070* + ID_MODEL_FROM_DATABASE=Behold TV 507 FM + +pci:v00001131d00007134sv00005ACEsd00006070* + ID_MODEL_FROM_DATABASE=Behold TV 607 FM + +pci:v00001131d00007134sv00005ACEsd00006071* + ID_MODEL_FROM_DATABASE=Behold TV 607 FM + +pci:v00001131d00007134sv00005ACEsd00006072* + ID_MODEL_FROM_DATABASE=Behold TV 607 RDS + +pci:v00001131d00007134sv00005ACEsd00006073* + ID_MODEL_FROM_DATABASE=Behold TV 607 RDS + +pci:v00001131d00007145* + ID_MODEL_FROM_DATABASE=SAA7145 + +pci:v00001131d00007146* + ID_MODEL_FROM_DATABASE=SAA7146 + +pci:v00001131d00007146sv0000110Asd00000000* + ID_MODEL_FROM_DATABASE=Fujitsu/Siemens DVB-C card rev1.5 + +pci:v00001131d00007146sv0000110Asd0000FFFF* + ID_MODEL_FROM_DATABASE=Fujitsu/Siemens DVB-C card rev1.5 + +pci:v00001131d00007146sv00001124sd00002581* + ID_MODEL_FROM_DATABASE=Leutron Vision PicPort + +pci:v00001131d00007146sv00001131sd00004F56* + ID_MODEL_FROM_DATABASE=KNC1 DVB-S Budget + +pci:v00001131d00007146sv00001131sd00004F60* + ID_MODEL_FROM_DATABASE=Fujitsu-Siemens Activy DVB-S Budget Rev AL + +pci:v00001131d00007146sv00001131sd00004F61* + ID_MODEL_FROM_DATABASE=Activy DVB-S Budget Rev GR + +pci:v00001131d00007146sv00001131sd00005F61* + ID_MODEL_FROM_DATABASE=Activy DVB-T Budget + +pci:v00001131d00007146sv0000114Bsd00002003* + ID_MODEL_FROM_DATABASE=DVRaptor Video Edit/Capture Card + +pci:v00001131d00007146sv000011BDsd00000006* + ID_MODEL_FROM_DATABASE=DV500 Overlay + +pci:v00001131d00007146sv000011BDsd0000000A* + ID_MODEL_FROM_DATABASE=DV500 Overlay + +pci:v00001131d00007146sv000011BDsd0000000F* + ID_MODEL_FROM_DATABASE=DV500 Overlay + +pci:v00001131d00007146sv000013C2sd00000000* + ID_MODEL_FROM_DATABASE=Siemens/Technotrend/Hauppauge DVB card rev1.3 or rev1.5 + +pci:v00001131d00007146sv000013C2sd00000001* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev1.3 or rev1.6 + +pci:v00001131d00007146sv000013C2sd00000002* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.1 + +pci:v00001131d00007146sv000013C2sd00000003* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.1 + +pci:v00001131d00007146sv000013C2sd00000004* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.1 + +pci:v00001131d00007146sv000013C2sd00000006* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev1.3 or rev1.6 + +pci:v00001131d00007146sv000013C2sd00000008* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB-T + +pci:v00001131d00007146sv000013C2sd0000000A* + ID_MODEL_FROM_DATABASE=Octal/Technotrend DVB-C for iTV + +pci:v00001131d00007146sv000013C2sd0000000E* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.3 + +pci:v00001131d00007146sv000013C2sd00001003* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-S DVB card + +pci:v00001131d00007146sv000013C2sd00001004* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-C DVB card + +pci:v00001131d00007146sv000013C2sd00001005* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-T DVB card + +pci:v00001131d00007146sv000013C2sd0000100C* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-CI DVB card + +pci:v00001131d00007146sv000013C2sd0000100F* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-CI DVB card + +pci:v00001131d00007146sv000013C2sd00001010* + ID_MODEL_FROM_DATABASE=DVB C-1500 + +pci:v00001131d00007146sv000013C2sd00001011* + ID_MODEL_FROM_DATABASE=Technotrend-Budget/Hauppauge WinTV-NOVA-T DVB card + +pci:v00001131d00007146sv000013C2sd00001012* + ID_MODEL_FROM_DATABASE=DVB T-1500 + +pci:v00001131d00007146sv000013C2sd00001013* + ID_MODEL_FROM_DATABASE=SATELCO Multimedia DVB + +pci:v00001131d00007146sv000013C2sd00001016* + ID_MODEL_FROM_DATABASE=WinTV-NOVA-SE DVB card + +pci:v00001131d00007146sv000013C2sd00001018* + ID_MODEL_FROM_DATABASE=DVB S-1401 + +pci:v00001131d00007146sv000013C2sd00001019* + ID_MODEL_FROM_DATABASE=S2-3200 + +pci:v00001131d00007146sv000013C2sd00001102* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.1 + +pci:v00001131d00007146sv0000153Bsd00001155* + ID_MODEL_FROM_DATABASE=Cinergy 1200 DVB-S + +pci:v00001131d00007146sv0000153Bsd00001156* + ID_MODEL_FROM_DATABASE=Terratec Cynergy 1200C + +pci:v00001131d00007146sv0000153Bsd00001157* + ID_MODEL_FROM_DATABASE=Cinergy 1200 DVB-T + +pci:v00001131d00007146sv00001894sd00000020* + ID_MODEL_FROM_DATABASE=KNC One DVB-C V1.0 + +pci:v00001131d00007146sv00001894sd00000023* + ID_MODEL_FROM_DATABASE=TVStation DVB-C plus + +pci:v00001131d00007160* + ID_MODEL_FROM_DATABASE=SAA7160 + +pci:v00001131d00007160sv00001458sd00009009* + ID_MODEL_FROM_DATABASE=E8000 DVB-T/Analog TV/FM tuner + +pci:v00001131d00007162* + ID_MODEL_FROM_DATABASE=SAA7162 + +pci:v00001131d00007162sv000011BDsd00000101* + ID_MODEL_FROM_DATABASE=Pinnacle PCTV 7010iX TV Card + +pci:v00001131d00007164* + ID_MODEL_FROM_DATABASE=SAA7164 + +pci:v00001131d00007164sv00000070sd00008800* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008810* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008851* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008853* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008880* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008891* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd000088A0* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd000088A1* + ID_MODEL_FROM_DATABASE=WinTV HVR-2250 + +pci:v00001131d00007164sv00000070sd00008900* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008901* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008940* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 (submodel 89619) + +pci:v00001131d00007164sv00000070sd00008951* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008953* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008980* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008991* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd00008993* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd000089A0* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007164sv00000070sd000089A1* + ID_MODEL_FROM_DATABASE=WinTV HVR-2200 + +pci:v00001131d00007231* + ID_MODEL_FROM_DATABASE=SAA7231 + +pci:v00001131d00007231sv00005ACEsd00008000* + ID_MODEL_FROM_DATABASE=Behold TV H8 + +pci:v00001131d00007231sv00005ACEsd00008100* + ID_MODEL_FROM_DATABASE=Behold TV A8 + +pci:v00001131d00009730* + ID_MODEL_FROM_DATABASE=SAA9730 Integrated Multimedia and Peripheral Controller + +pci:v00001131d00009730sv00001131sd00000000* + ID_MODEL_FROM_DATABASE=Integrated Multimedia and Peripheral Controller + +pci:v00001132* + ID_VENDOR_FROM_DATABASE=Mitel Corp. + +pci:v00001133* + ID_VENDOR_FROM_DATABASE=Dialogic Corporation + +pci:v00001133d00007701* + ID_MODEL_FROM_DATABASE=Eiconcard C90 + +pci:v00001133d00007711* + ID_MODEL_FROM_DATABASE=Eiconcard C91 + +pci:v00001133d00007901* + ID_MODEL_FROM_DATABASE=EiconCard S90 + +pci:v00001133d00007902* + ID_MODEL_FROM_DATABASE=EiconCard S90 + +pci:v00001133d00007911* + ID_MODEL_FROM_DATABASE=EiconCard S91 + +pci:v00001133d00007912* + ID_MODEL_FROM_DATABASE=EiconCard S91 + +pci:v00001133d00007921* + ID_MODEL_FROM_DATABASE=Eiconcard S92 + +pci:v00001133d00007941* + ID_MODEL_FROM_DATABASE=EiconCard S94 + +pci:v00001133d00007942* + ID_MODEL_FROM_DATABASE=EiconCard S94 + +pci:v00001133d00007943* + ID_MODEL_FROM_DATABASE=EiconCard S94 + +pci:v00001133d00007944* + ID_MODEL_FROM_DATABASE=EiconCard S94 + +pci:v00001133d00007945* + ID_MODEL_FROM_DATABASE=Eiconcard S94 + +pci:v00001133d00007948* + ID_MODEL_FROM_DATABASE=Eiconcard S94 64bit/66MHz + +pci:v00001133d00009711* + ID_MODEL_FROM_DATABASE=Eiconcard S91 V2 + +pci:v00001133d00009911* + ID_MODEL_FROM_DATABASE=Eiconcard S91 V2 + +pci:v00001133d00009941* + ID_MODEL_FROM_DATABASE=Eiconcard S94 V2 + +pci:v00001133d00009A41* + ID_MODEL_FROM_DATABASE=Eiconcard S94 PCIe + +pci:v00001133d0000B921* + ID_MODEL_FROM_DATABASE=EiconCard P92 + +pci:v00001133d0000B922* + ID_MODEL_FROM_DATABASE=EiconCard P92 + +pci:v00001133d0000B923* + ID_MODEL_FROM_DATABASE=EiconCard P92 + +pci:v00001133d0000E001* + ID_MODEL_FROM_DATABASE=Diva Pro 2.0 S/T + +pci:v00001133d0000E002* + ID_MODEL_FROM_DATABASE=Diva 2.0 S/T PCI + +pci:v00001133d0000E003* + ID_MODEL_FROM_DATABASE=Diva Pro 2.0 U + +pci:v00001133d0000E004* + ID_MODEL_FROM_DATABASE=Diva 2.0 U PCI + +pci:v00001133d0000E005* + ID_MODEL_FROM_DATABASE=Diva 2.01 S/T PCI + +pci:v00001133d0000E006* + ID_MODEL_FROM_DATABASE=Diva CT S/T PCI + +pci:v00001133d0000E007* + ID_MODEL_FROM_DATABASE=Diva CT U PCI + +pci:v00001133d0000E008* + ID_MODEL_FROM_DATABASE=Diva CT Lite S/T PCI + +pci:v00001133d0000E009* + ID_MODEL_FROM_DATABASE=Diva CT Lite U PCI + +pci:v00001133d0000E00A* + ID_MODEL_FROM_DATABASE=Diva ISDN+V.90 PCI + +pci:v00001133d0000E00B* + ID_MODEL_FROM_DATABASE=Diva ISDN PCI 2.02 + +pci:v00001133d0000E00C* + ID_MODEL_FROM_DATABASE=Diva 2.02 PCI U + +pci:v00001133d0000E00D* + ID_MODEL_FROM_DATABASE=Diva Pro 3.0 PCI + +pci:v00001133d0000E00E* + ID_MODEL_FROM_DATABASE=Diva ISDN+CT S/T PCI Rev 2 + +pci:v00001133d0000E010* + ID_MODEL_FROM_DATABASE=Diva Server BRI-2M PCI + +pci:v00001133d0000E010sv0000110Asd00000021* + ID_MODEL_FROM_DATABASE=Fujitsu Siemens ISDN S0 + +pci:v00001133d0000E011* + ID_MODEL_FROM_DATABASE=Diva Server BRI S/T Rev 2 + +pci:v00001133d0000E012* + ID_MODEL_FROM_DATABASE=Diva Server 4BRI-8M PCI + +pci:v00001133d0000E013* + ID_MODEL_FROM_DATABASE=4BRI + +pci:v00001133d0000E013sv00001133sd00001300* + ID_MODEL_FROM_DATABASE=Diva V-4BRI-8 PCI v2 + +pci:v00001133d0000E013sv00001133sd0000E013* + ID_MODEL_FROM_DATABASE=Diva 4BRI-8 PCI v2 + +pci:v00001133d0000E014* + ID_MODEL_FROM_DATABASE=Diva Server PRI-30M PCI + +pci:v00001133d0000E015* + ID_MODEL_FROM_DATABASE=Diva PRI PCI v2 + +pci:v00001133d0000E016* + ID_MODEL_FROM_DATABASE=Diva Server Voice 4BRI PCI + +pci:v00001133d0000E017* + ID_MODEL_FROM_DATABASE=Diva Server Voice 4BRI Rev 2 + +pci:v00001133d0000E017sv00001133sd0000E017* + ID_MODEL_FROM_DATABASE=Diva Server Voice 4BRI-8M 2.0 PCI + +pci:v00001133d0000E018* + ID_MODEL_FROM_DATABASE=BRI + +pci:v00001133d0000E018sv00001133sd00001800* + ID_MODEL_FROM_DATABASE=Diva V-BRI-2 PCI v2 + +pci:v00001133d0000E018sv00001133sd0000E018* + ID_MODEL_FROM_DATABASE=Diva BRI-2 PCI v2 + +pci:v00001133d0000E019* + ID_MODEL_FROM_DATABASE=Diva Server Voice PRI Rev 2 + +pci:v00001133d0000E019sv00001133sd0000E019* + ID_MODEL_FROM_DATABASE=Diva Server Voice PRI 2.0 PCI + +pci:v00001133d0000E01A* + ID_MODEL_FROM_DATABASE=Diva BRI-2FX PCI v2 + +pci:v00001133d0000E01B* + ID_MODEL_FROM_DATABASE=Diva Server Voice BRI-2M 2.0 PCI + +pci:v00001133d0000E01Bsv00001133sd0000E01B* + ID_MODEL_FROM_DATABASE=Diva Server Voice BRI-2M 2.0 PCI + +pci:v00001133d0000E01C* + ID_MODEL_FROM_DATABASE=PRI + +pci:v00001133d0000E01Csv00001133sd00001C01* + ID_MODEL_FROM_DATABASE=Diva PRI/E1/T1-8 PCI v3 + +pci:v00001133d0000E01Csv00001133sd00001C02* + ID_MODEL_FROM_DATABASE=Diva PRI/T1-24 PCI(e) v3 + +pci:v00001133d0000E01Csv00001133sd00001C03* + ID_MODEL_FROM_DATABASE=Diva PRI/E1-30 PCI(e) v3 + +pci:v00001133d0000E01Csv00001133sd00001C04* + ID_MODEL_FROM_DATABASE=Diva PRI/E1/T1-CTI PCI(e) v3 + +pci:v00001133d0000E01Csv00001133sd00001C05* + ID_MODEL_FROM_DATABASE=Diva V-PRI/T1-24 PCI(e) v3 + +pci:v00001133d0000E01Csv00001133sd00001C06* + ID_MODEL_FROM_DATABASE=Diva V-PRI/E1-30 PCI(e) v3 + +pci:v00001133d0000E01Csv00001133sd00001C07* + ID_MODEL_FROM_DATABASE=Diva Server PRI/E1/T1-8 Cornet NQ + +pci:v00001133d0000E01Csv00001133sd00001C08* + ID_MODEL_FROM_DATABASE=Diva Server PRI/T1-24 Cornet NQ + +pci:v00001133d0000E01Csv00001133sd00001C09* + ID_MODEL_FROM_DATABASE=Diva Server PRI/E1-30 Cornet NQ + +pci:v00001133d0000E01Csv00001133sd00001C0A* + ID_MODEL_FROM_DATABASE=Diva Server PRI/E1/T1 Cornet NQ + +pci:v00001133d0000E01Csv00001133sd00001C0B* + ID_MODEL_FROM_DATABASE=Diva Server V-PRI/T1-24 Cornet NQ + +pci:v00001133d0000E01Csv00001133sd00001C0C* + ID_MODEL_FROM_DATABASE=Diva Server V-PRI/E1-30 Cornet NQ + +pci:v00001133d0000E01E* + ID_MODEL_FROM_DATABASE=2PRI + +pci:v00001133d0000E01Esv00001133sd00001E01* + ID_MODEL_FROM_DATABASE=Diva 2PRI/E1/T1-60 PCI v1 + +pci:v00001133d0000E01Esv00001133sd0000E01E* + ID_MODEL_FROM_DATABASE=Diva V-2PRI/E1/T1-60 PCI v1 + +pci:v00001133d0000E020* + ID_MODEL_FROM_DATABASE=4PRI + +pci:v00001133d0000E020sv00001133sd00002001* + ID_MODEL_FROM_DATABASE=Diva 4PRI/E1/T1-120 PCI v1 + +pci:v00001133d0000E020sv00001133sd0000E020* + ID_MODEL_FROM_DATABASE=Diva V-4PRI/E1/T1-120 PCI v1 + +pci:v00001133d0000E022* + ID_MODEL_FROM_DATABASE=Analog-2 + +pci:v00001133d0000E022sv00001133sd00002200* + ID_MODEL_FROM_DATABASE=Diva V-Analog-2 PCI v1 + +pci:v00001133d0000E022sv00001133sd0000E022* + ID_MODEL_FROM_DATABASE=Diva Analog-2 PCI v1 + +pci:v00001133d0000E024* + ID_MODEL_FROM_DATABASE=Analog-4 + +pci:v00001133d0000E024sv00001133sd00002400* + ID_MODEL_FROM_DATABASE=Diva V-Analog-4 PCI v1 + +pci:v00001133d0000E024sv00001133sd0000E024* + ID_MODEL_FROM_DATABASE=Diva Analog-4 PCI v1 + +pci:v00001133d0000E028* + ID_MODEL_FROM_DATABASE=Analog-8 + +pci:v00001133d0000E028sv00001133sd00002800* + ID_MODEL_FROM_DATABASE=Diva V-Analog-8 PCI v1 + +pci:v00001133d0000E028sv00001133sd0000E028* + ID_MODEL_FROM_DATABASE=Diva Analog-8 PCI v1 + +pci:v00001133d0000E02A* + ID_MODEL_FROM_DATABASE=Diva IPM-300 PCI v1 + +pci:v00001133d0000E02C* + ID_MODEL_FROM_DATABASE=Diva IPM-600 PCI v1 + +pci:v00001133d0000E02E* + ID_MODEL_FROM_DATABASE=4BRI + +pci:v00001133d0000E02Esv00001133sd00002E01* + ID_MODEL_FROM_DATABASE=Diva V-4BRI-8 PCIe v2 + +pci:v00001133d0000E02Esv00001133sd0000E02E* + ID_MODEL_FROM_DATABASE=Diva 4BRI-8 PCIe v2 + +pci:v00001133d0000E032* + ID_MODEL_FROM_DATABASE=BRI + +pci:v00001133d0000E032sv00001133sd00003201* + ID_MODEL_FROM_DATABASE=Diva V-BRI-2 PCIe v2 + +pci:v00001133d0000E032sv00001133sd0000E032* + ID_MODEL_FROM_DATABASE=Diva BRI-2 PCIe v2 + +pci:v00001133d0000E034* + ID_MODEL_FROM_DATABASE=Diva BRI-CTI PCI v2 + +pci:v00001134* + ID_VENDOR_FROM_DATABASE=Mercury Computer Systems + +pci:v00001134d00000001* + ID_MODEL_FROM_DATABASE=Raceway Bridge + +pci:v00001134d00000002* + ID_MODEL_FROM_DATABASE=Dual PCI to RapidIO Bridge + +pci:v00001134d0000000B* + ID_MODEL_FROM_DATABASE=POET Serial RapidIO Bridge + +pci:v00001134d0000000D* + ID_MODEL_FROM_DATABASE=POET PSDMS Device + +pci:v00001135* + ID_VENDOR_FROM_DATABASE=Fuji Xerox Co Ltd + +pci:v00001135d00000001* + ID_MODEL_FROM_DATABASE=Printer controller + +pci:v00001136* + ID_VENDOR_FROM_DATABASE=Momentum Data Systems + +pci:v00001136d00000002* + ID_MODEL_FROM_DATABASE=PCI-JTAG + +pci:v00001137* + ID_VENDOR_FROM_DATABASE=Cisco Systems Inc + +pci:v00001137d00000023* + ID_MODEL_FROM_DATABASE=VIC 81 PCIe Upstream Port + +pci:v00001137d00000040* + ID_MODEL_FROM_DATABASE=VIC PCIe Upstream Port + +pci:v00001137d00000041* + ID_MODEL_FROM_DATABASE=VIC PCIe Downstream Port + +pci:v00001137d00000042* + ID_MODEL_FROM_DATABASE=VIC Management Controller + +pci:v00001137d00000042sv00001137sd00000047* + ID_MODEL_FROM_DATABASE=VIC P81E PCIe Management Controller + +pci:v00001137d00000042sv00001137sd00000085* + ID_MODEL_FROM_DATABASE=VIC 1225 PCIe Management Controller + +pci:v00001137d00000042sv00001137sd000000CD* + ID_MODEL_FROM_DATABASE=VIC 1285 PCIe Management Controller + +pci:v00001137d00000042sv00001137sd000000CE* + ID_MODEL_FROM_DATABASE=VIC 1225T PCIe Management Controller + +pci:v00001137d00000043* + ID_MODEL_FROM_DATABASE=VIC Ethernet NIC + +pci:v00001137d00000043sv00001137sd00000047* + ID_MODEL_FROM_DATABASE=VIC P81E PCIe Ethernet NIC + +pci:v00001137d00000043sv00001137sd00000048* + ID_MODEL_FROM_DATABASE=VIC M81KR Mezzanine Ethernet NIC + +pci:v00001137d00000043sv00001137sd0000004F* + ID_MODEL_FROM_DATABASE=VIC 1280 Mezzanine Ethernet NIC + +pci:v00001137d00000043sv00001137sd00000084* + ID_MODEL_FROM_DATABASE=VIC 1240 MLOM Ethernet NIC + +pci:v00001137d00000043sv00001137sd00000085* + ID_MODEL_FROM_DATABASE=VIC 1225 PCIe Ethernet NIC + +pci:v00001137d00000043sv00001137sd000000CD* + ID_MODEL_FROM_DATABASE=VIC 1285 PCIe Ethernet NIC + +pci:v00001137d00000043sv00001137sd000000CE* + ID_MODEL_FROM_DATABASE=VIC 1225T PCIe Ethernet NIC + +pci:v00001137d00000044* + ID_MODEL_FROM_DATABASE=VIC Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd00000047* + ID_MODEL_FROM_DATABASE=VIC P81E PCIe Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd00000048* + ID_MODEL_FROM_DATABASE=VIC M81KR Mezzanine Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd0000004F* + ID_MODEL_FROM_DATABASE=VIC 1280 Mezzanine Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd00000084* + ID_MODEL_FROM_DATABASE=VIC 1240 MLOM Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd00000085* + ID_MODEL_FROM_DATABASE=VIC 1225 PCIe Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd000000CD* + ID_MODEL_FROM_DATABASE=VIC 1285 PCIe Ethernet NIC Dynamic + +pci:v00001137d00000044sv00001137sd000000CE* + ID_MODEL_FROM_DATABASE=VIC 1225T PCIe Ethernet NIC Dynamic + +pci:v00001137d00000045* + ID_MODEL_FROM_DATABASE=VIC FCoE HBA + +pci:v00001137d00000045sv00001137sd00000047* + ID_MODEL_FROM_DATABASE=VIC P81E PCIe FCoE HBA + +pci:v00001137d00000045sv00001137sd00000048* + ID_MODEL_FROM_DATABASE=VIC M81KR Mezzanine FCoE HBA + +pci:v00001137d00000045sv00001137sd0000004F* + ID_MODEL_FROM_DATABASE=VIC 1280 Mezzanine FCoE HBA + +pci:v00001137d00000045sv00001137sd00000084* + ID_MODEL_FROM_DATABASE=VIC 1240 MLOM FCoE HBA + +pci:v00001137d00000045sv00001137sd00000085* + ID_MODEL_FROM_DATABASE=VIC 1225 PCIe FCoE HBA + +pci:v00001137d00000045sv00001137sd000000CD* + ID_MODEL_FROM_DATABASE=VIC 1285 PCIe FCoE HBA + +pci:v00001137d00000045sv00001137sd000000CE* + ID_MODEL_FROM_DATABASE=VIC 1225T PCIe FCoE HBA + +pci:v00001137d0000004E* + ID_MODEL_FROM_DATABASE=VIC 82 PCIe Upstream Port + +pci:v00001137d00000071* + ID_MODEL_FROM_DATABASE=VIC SR-IOV VF + +pci:v00001137d000000CF* + ID_MODEL_FROM_DATABASE=VIC Userspace NIC + +pci:v00001138* + ID_VENDOR_FROM_DATABASE=Ziatech Corporation + +pci:v00001138d00008905* + ID_MODEL_FROM_DATABASE=8905 [STD 32 Bridge] + +pci:v00001139* + ID_VENDOR_FROM_DATABASE=Dynamic Pictures, Inc + +pci:v00001139d00000001* + ID_MODEL_FROM_DATABASE=VGA Compatable 3D Graphics + +pci:v0000113A* + ID_VENDOR_FROM_DATABASE=FWB Inc + +pci:v0000113B* + ID_VENDOR_FROM_DATABASE=Network Computing Devices + +pci:v0000113C* + ID_VENDOR_FROM_DATABASE=Cyclone Microsystems, Inc. + +pci:v0000113Cd00000000* + ID_MODEL_FROM_DATABASE=PCI-9060 i960 Bridge + +pci:v0000113Cd00000001* + ID_MODEL_FROM_DATABASE=PCI-SDK [PCI i960 Evaluation Platform] + +pci:v0000113Cd00000911* + ID_MODEL_FROM_DATABASE=PCI-911 [i960Jx-based Intelligent I/O Controller] + +pci:v0000113Cd00000912* + ID_MODEL_FROM_DATABASE=PCI-912 [i960CF-based Intelligent I/O Controller] + +pci:v0000113Cd00000913* + ID_MODEL_FROM_DATABASE=PCI-913 + +pci:v0000113Cd00000914* + ID_MODEL_FROM_DATABASE=PCI-914 [I/O Controller w/ secondary PCI bus] + +pci:v0000113D* + ID_VENDOR_FROM_DATABASE=Leading Edge Products Inc + +pci:v0000113E* + ID_VENDOR_FROM_DATABASE=Sanyo Electric Co - Computer Engineering Dept + +pci:v0000113F* + ID_VENDOR_FROM_DATABASE=Equinox Systems, Inc. + +pci:v0000113Fd00000808* + ID_MODEL_FROM_DATABASE=SST-64P Adapter + +pci:v0000113Fd00001010* + ID_MODEL_FROM_DATABASE=SST-128P Adapter + +pci:v0000113Fd000080C0* + ID_MODEL_FROM_DATABASE=SST-16P DB Adapter + +pci:v0000113Fd000080C4* + ID_MODEL_FROM_DATABASE=SST-16P RJ Adapter + +pci:v0000113Fd000080C8* + ID_MODEL_FROM_DATABASE=SST-16P Adapter + +pci:v0000113Fd00008888* + ID_MODEL_FROM_DATABASE=SST-4P Adapter + +pci:v0000113Fd00009090* + ID_MODEL_FROM_DATABASE=SST-8P Adapter + +pci:v00001140* + ID_VENDOR_FROM_DATABASE=Intervoice Inc + +pci:v00001141* + ID_VENDOR_FROM_DATABASE=Crest Microsystem Inc + +pci:v00001142* + ID_VENDOR_FROM_DATABASE=Alliance Semiconductor Corporation + +pci:v00001142d00003210* + ID_MODEL_FROM_DATABASE=AP6410 + +pci:v00001142d00006422* + ID_MODEL_FROM_DATABASE=ProVideo 6422 + +pci:v00001142d00006424* + ID_MODEL_FROM_DATABASE=ProVideo 6424 + +pci:v00001142d00006425* + ID_MODEL_FROM_DATABASE=ProMotion AT25 + +pci:v00001142d0000643D* + ID_MODEL_FROM_DATABASE=ProMotion AT3D + +pci:v00001143* + ID_VENDOR_FROM_DATABASE=NetPower, Inc + +pci:v00001144* + ID_VENDOR_FROM_DATABASE=Cincinnati Milacron + +pci:v00001144d00000001* + ID_MODEL_FROM_DATABASE=Noservo controller + +pci:v00001145* + ID_VENDOR_FROM_DATABASE=Workbit Corporation + +pci:v00001145d00008007* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Workbit + +pci:v00001145d0000F007* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 KME + +pci:v00001145d0000F010* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Workbit + +pci:v00001145d0000F012* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Logitec + +pci:v00001145d0000F013* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Logitec + +pci:v00001145d0000F015* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Melco + +pci:v00001145d0000F020* + ID_MODEL_FROM_DATABASE=NinjaSCSI-32 Sony PCGA-DVD51 + +pci:v00001145d0000F021* + ID_MODEL_FROM_DATABASE=NinjaPATA-32 Delkin Cardbus UDMA + +pci:v00001145d0000F024* + ID_MODEL_FROM_DATABASE=NinjaPATA-32 Delkin Cardbus UDMA + +pci:v00001145d0000F103* + ID_MODEL_FROM_DATABASE=NinjaPATA-32 Delkin Cardbus UDMA + +pci:v00001146* + ID_VENDOR_FROM_DATABASE=Force Computers + +pci:v00001147* + ID_VENDOR_FROM_DATABASE=Interface Corp + +pci:v00001148* + ID_VENDOR_FROM_DATABASE=SysKonnect + +pci:v00001148d00004000* + ID_MODEL_FROM_DATABASE=FDDI Adapter + +pci:v00001148d00004000sv00000E11sd0000B03B* + ID_MODEL_FROM_DATABASE=Netelligent 100 FDDI DAS Fibre SC + +pci:v00001148d00004000sv00000E11sd0000B03C* + ID_MODEL_FROM_DATABASE=Netelligent 100 FDDI SAS Fibre SC + +pci:v00001148d00004000sv00000E11sd0000B03D* + ID_MODEL_FROM_DATABASE=Netelligent 100 FDDI DAS UTP + +pci:v00001148d00004000sv00000E11sd0000B03E* + ID_MODEL_FROM_DATABASE=Netelligent 100 FDDI SAS UTP + +pci:v00001148d00004000sv00000E11sd0000B03F* + ID_MODEL_FROM_DATABASE=Netelligent 100 FDDI SAS Fibre MIC + +pci:v00001148d00004000sv00001148sd00005521* + ID_MODEL_FROM_DATABASE=FDDI SK-5521 (SK-NET FDDI-UP) + +pci:v00001148d00004000sv00001148sd00005522* + ID_MODEL_FROM_DATABASE=FDDI SK-5522 (SK-NET FDDI-UP DAS) + +pci:v00001148d00004000sv00001148sd00005541* + ID_MODEL_FROM_DATABASE=FDDI SK-5541 (SK-NET FDDI-FP) + +pci:v00001148d00004000sv00001148sd00005543* + ID_MODEL_FROM_DATABASE=FDDI SK-5543 (SK-NET FDDI-LP) + +pci:v00001148d00004000sv00001148sd00005544* + ID_MODEL_FROM_DATABASE=FDDI SK-5544 (SK-NET FDDI-LP DAS) + +pci:v00001148d00004000sv00001148sd00005821* + ID_MODEL_FROM_DATABASE=FDDI SK-5821 (SK-NET FDDI-UP64) + +pci:v00001148d00004000sv00001148sd00005822* + ID_MODEL_FROM_DATABASE=FDDI SK-5822 (SK-NET FDDI-UP64 DAS) + +pci:v00001148d00004000sv00001148sd00005841* + ID_MODEL_FROM_DATABASE=FDDI SK-5841 (SK-NET FDDI-FP64) + +pci:v00001148d00004000sv00001148sd00005843* + ID_MODEL_FROM_DATABASE=FDDI SK-5843 (SK-NET FDDI-LP64) + +pci:v00001148d00004000sv00001148sd00005844* + ID_MODEL_FROM_DATABASE=FDDI SK-5844 (SK-NET FDDI-LP64 DAS) + +pci:v00001148d00004200* + ID_MODEL_FROM_DATABASE=Token Ring adapter + +pci:v00001148d00004300* + ID_MODEL_FROM_DATABASE=SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) + +pci:v00001148d00004300sv00001148sd00009821* + ID_MODEL_FROM_DATABASE=SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T) + +pci:v00001148d00004300sv00001148sd00009822* + ID_MODEL_FROM_DATABASE=SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link) + +pci:v00001148d00004300sv00001148sd00009841* + ID_MODEL_FROM_DATABASE=SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX) + +pci:v00001148d00004300sv00001148sd00009842* + ID_MODEL_FROM_DATABASE=SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link) + +pci:v00001148d00004300sv00001148sd00009843* + ID_MODEL_FROM_DATABASE=SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX) + +pci:v00001148d00004300sv00001148sd00009844* + ID_MODEL_FROM_DATABASE=SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link) + +pci:v00001148d00004300sv00001148sd00009861* + ID_MODEL_FROM_DATABASE=SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition) + +pci:v00001148d00004300sv00001148sd00009862* + ID_MODEL_FROM_DATABASE=SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link) + +pci:v00001148d00004300sv00001148sd00009871* + ID_MODEL_FROM_DATABASE=SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX) + +pci:v00001148d00004300sv00001148sd00009872* + ID_MODEL_FROM_DATABASE=SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) + +pci:v00001148d00004300sv00001259sd00002970* + ID_MODEL_FROM_DATABASE=AT-2970SX Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002971* + ID_MODEL_FROM_DATABASE=AT-2970LX Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002972* + ID_MODEL_FROM_DATABASE=AT-2970TX Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002973* + ID_MODEL_FROM_DATABASE=AT-2971SX Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002974* + ID_MODEL_FROM_DATABASE=AT-2971T Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002975* + ID_MODEL_FROM_DATABASE=AT-2970SX/2SC Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002976* + ID_MODEL_FROM_DATABASE=AT-2970LX/2SC Gigabit Ethernet Adapter + +pci:v00001148d00004300sv00001259sd00002977* + ID_MODEL_FROM_DATABASE=AT-2970TX/2TX Gigabit Ethernet Adapter + +pci:v00001148d00004320* + ID_MODEL_FROM_DATABASE=SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter, PCI64, Fiber ZX/SC + +pci:v00001148d00004320sv00001148sd00000121* + ID_MODEL_FROM_DATABASE=Marvell RDK-8001 Adapter + +pci:v00001148d00004320sv00001148sd00000221* + ID_MODEL_FROM_DATABASE=Marvell RDK-8002 Adapter + +pci:v00001148d00004320sv00001148sd00000321* + ID_MODEL_FROM_DATABASE=Marvell RDK-8003 Adapter + +pci:v00001148d00004320sv00001148sd00000421* + ID_MODEL_FROM_DATABASE=Marvell RDK-8004 Adapter + +pci:v00001148d00004320sv00001148sd00000621* + ID_MODEL_FROM_DATABASE=Marvell RDK-8006 Adapter + +pci:v00001148d00004320sv00001148sd00000721* + ID_MODEL_FROM_DATABASE=Marvell RDK-8007 Adapter + +pci:v00001148d00004320sv00001148sd00000821* + ID_MODEL_FROM_DATABASE=Marvell RDK-8008 Adapter + +pci:v00001148d00004320sv00001148sd00000921* + ID_MODEL_FROM_DATABASE=Marvell RDK-8009 Adapter + +pci:v00001148d00004320sv00001148sd00001121* + ID_MODEL_FROM_DATABASE=Marvell RDK-8011 Adapter + +pci:v00001148d00004320sv00001148sd00001221* + ID_MODEL_FROM_DATABASE=Marvell RDK-8012 Adapter + +pci:v00001148d00004320sv00001148sd00003221* + ID_MODEL_FROM_DATABASE=SK-9521 V2.0 10/100/1000Base-T Adapter + +pci:v00001148d00004320sv00001148sd00005021* + ID_MODEL_FROM_DATABASE=SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter + +pci:v00001148d00004320sv00001148sd00005041* + ID_MODEL_FROM_DATABASE=SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter + +pci:v00001148d00004320sv00001148sd00005043* + ID_MODEL_FROM_DATABASE=SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter + +pci:v00001148d00004320sv00001148sd00005051* + ID_MODEL_FROM_DATABASE=SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter + +pci:v00001148d00004320sv00001148sd00005061* + ID_MODEL_FROM_DATABASE=SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter + +pci:v00001148d00004320sv00001148sd00005071* + ID_MODEL_FROM_DATABASE=SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter + +pci:v00001148d00004320sv00001148sd00009521* + ID_MODEL_FROM_DATABASE=SK-9521 10/100/1000Base-T Adapter + +pci:v00001148d00004400* + ID_MODEL_FROM_DATABASE=SK-9Dxx Gigabit Ethernet Adapter + +pci:v00001148d00004500* + ID_MODEL_FROM_DATABASE=SK-9Mxx Gigabit Ethernet Adapter + +pci:v00001148d00009000* + ID_MODEL_FROM_DATABASE=SK-9S21 10/100/1000Base-T Server Adapter, PCI-X, Copper RJ-45 + +pci:v00001148d00009843* + ID_MODEL_FROM_DATABASE=[Fujitsu] Gigabit Ethernet + +pci:v00001148d00009E00* + ID_MODEL_FROM_DATABASE=SK-9E21D 10/100/1000Base-T Adapter, Copper RJ-45 + +pci:v00001148d00009E00sv00001148sd00002100* + ID_MODEL_FROM_DATABASE=SK-9E21 Server Adapter + +pci:v00001148d00009E00sv00001148sd000021D0* + ID_MODEL_FROM_DATABASE=SK-9E21D 10/100/1000Base-T Adapter + +pci:v00001148d00009E00sv00001148sd00002200* + ID_MODEL_FROM_DATABASE=SK-9E22 Server Adapter + +pci:v00001148d00009E00sv00001148sd00008100* + ID_MODEL_FROM_DATABASE=SK-9E81 Server Adapter + +pci:v00001148d00009E00sv00001148sd00008200* + ID_MODEL_FROM_DATABASE=SK-9E82 Server Adapter + +pci:v00001148d00009E00sv00001148sd00009100* + ID_MODEL_FROM_DATABASE=SK-9E91 Server Adapter + +pci:v00001148d00009E00sv00001148sd00009200* + ID_MODEL_FROM_DATABASE=SK-9E92 Server Adapter + +pci:v00001148d00009E01* + ID_MODEL_FROM_DATABASE=SK-9E21M 10/100/1000Base-T Adapter + +pci:v00001149* + ID_VENDOR_FROM_DATABASE=Win System Corporation + +pci:v0000114A* + ID_VENDOR_FROM_DATABASE=VMIC + +pci:v0000114Ad00005565* + ID_MODEL_FROM_DATABASE=GE-IP PCI5565,PMC5565 Reflective Memory Node + +pci:v0000114Ad00005579* + ID_MODEL_FROM_DATABASE=VMIPCI-5579 (Reflective Memory Card) + +pci:v0000114Ad00005587* + ID_MODEL_FROM_DATABASE=VMIPCI-5587 (Reflective Memory Card) + +pci:v0000114Ad00006504* + ID_MODEL_FROM_DATABASE=VMIC PCI 7755 FPGA + +pci:v0000114Ad00007587* + ID_MODEL_FROM_DATABASE=VMIVME-7587 + +pci:v0000114B* + ID_VENDOR_FROM_DATABASE=Canopus Co., Ltd + +pci:v0000114C* + ID_VENDOR_FROM_DATABASE=Annabooks + +pci:v0000114D* + ID_VENDOR_FROM_DATABASE=IC Corporation + +pci:v0000114E* + ID_VENDOR_FROM_DATABASE=Nikon Systems Inc + +pci:v0000114F* + ID_VENDOR_FROM_DATABASE=Digi International + +pci:v0000114Fd00000002* + ID_MODEL_FROM_DATABASE=AccelePort EPC + +pci:v0000114Fd00000003* + ID_MODEL_FROM_DATABASE=RightSwitch SE-6 + +pci:v0000114Fd00000004* + ID_MODEL_FROM_DATABASE=AccelePort Xem + +pci:v0000114Fd00000005* + ID_MODEL_FROM_DATABASE=AccelePort Xr + +pci:v0000114Fd00000006* + ID_MODEL_FROM_DATABASE=AccelePort Xr,C/X + +pci:v0000114Fd00000009* + ID_MODEL_FROM_DATABASE=AccelePort Xr/J + +pci:v0000114Fd0000000A* + ID_MODEL_FROM_DATABASE=AccelePort EPC/J + +pci:v0000114Fd0000000C* + ID_MODEL_FROM_DATABASE=DataFirePRIme T1 (1-port) + +pci:v0000114Fd0000000D* + ID_MODEL_FROM_DATABASE=SyncPort 2-Port (x.25/FR) + +pci:v0000114Fd00000011* + ID_MODEL_FROM_DATABASE=AccelePort 8r EIA-232 (IBM) + +pci:v0000114Fd00000012* + ID_MODEL_FROM_DATABASE=AccelePort 8r EIA-422 + +pci:v0000114Fd00000013* + ID_MODEL_FROM_DATABASE=AccelePort Xr + +pci:v0000114Fd00000014* + ID_MODEL_FROM_DATABASE=AccelePort 8r EIA-422 + +pci:v0000114Fd00000015* + ID_MODEL_FROM_DATABASE=AccelePort Xem + +pci:v0000114Fd00000016* + ID_MODEL_FROM_DATABASE=AccelePort EPC/X + +pci:v0000114Fd00000017* + ID_MODEL_FROM_DATABASE=AccelePort C/X + +pci:v0000114Fd0000001A* + ID_MODEL_FROM_DATABASE=DataFirePRIme E1 (1-port) + +pci:v0000114Fd0000001B* + ID_MODEL_FROM_DATABASE=AccelePort C/X (IBM) + +pci:v0000114Fd0000001C* + ID_MODEL_FROM_DATABASE=AccelePort Xr (SAIP) + +pci:v0000114Fd0000001D* + ID_MODEL_FROM_DATABASE=DataFire RAS T1/E1/PRI + +pci:v0000114Fd0000001Dsv0000114Fsd00000050* + ID_MODEL_FROM_DATABASE=DataFire RAS E1 Adapter + +pci:v0000114Fd0000001Dsv0000114Fsd00000051* + ID_MODEL_FROM_DATABASE=DataFire RAS Dual E1 Adapter + +pci:v0000114Fd0000001Dsv0000114Fsd00000052* + ID_MODEL_FROM_DATABASE=DataFire RAS T1 Adapter + +pci:v0000114Fd0000001Dsv0000114Fsd00000053* + ID_MODEL_FROM_DATABASE=DataFire RAS Dual T1 Adapter + +pci:v0000114Fd00000023* + ID_MODEL_FROM_DATABASE=AccelePort RAS + +pci:v0000114Fd00000024* + ID_MODEL_FROM_DATABASE=DataFire RAS B4 ST/U + +pci:v0000114Fd00000024sv0000114Fsd00000030* + ID_MODEL_FROM_DATABASE=DataFire RAS BRI U Adapter + +pci:v0000114Fd00000024sv0000114Fsd00000031* + ID_MODEL_FROM_DATABASE=DataFire RAS BRI S/T Adapter + +pci:v0000114Fd00000026* + ID_MODEL_FROM_DATABASE=AccelePort 4r 920 + +pci:v0000114Fd00000027* + ID_MODEL_FROM_DATABASE=AccelePort Xr 920 + +pci:v0000114Fd00000028* + ID_MODEL_FROM_DATABASE=ClassicBoard 4 + +pci:v0000114Fd00000029* + ID_MODEL_FROM_DATABASE=ClassicBoard 8 + +pci:v0000114Fd00000034* + ID_MODEL_FROM_DATABASE=AccelePort 2r 920 + +pci:v0000114Fd00000035* + ID_MODEL_FROM_DATABASE=DataFire DSP T1/E1/PRI cPCI + +pci:v0000114Fd00000040* + ID_MODEL_FROM_DATABASE=AccelePort Xp + +pci:v0000114Fd00000040sv0000114Fsd00000042* + ID_MODEL_FROM_DATABASE=AccelePort 2p PCI + +pci:v0000114Fd00000040sv0000114Fsd00000043* + ID_MODEL_FROM_DATABASE=AccelePort 4p PCI + +pci:v0000114Fd00000040sv0000114Fsd00000044* + ID_MODEL_FROM_DATABASE=AccelePort 8p PCI + +pci:v0000114Fd00000040sv0000114Fsd00000045* + ID_MODEL_FROM_DATABASE=AccelePort 16p PCI + +pci:v0000114Fd00000040sv0000114Fsd0000004E* + ID_MODEL_FROM_DATABASE=AccelePort 32p PCI + +pci:v0000114Fd00000042* + ID_MODEL_FROM_DATABASE=AccelePort 2p + +pci:v0000114Fd00000043* + ID_MODEL_FROM_DATABASE=AccelePort 4p + +pci:v0000114Fd00000044* + ID_MODEL_FROM_DATABASE=AccelePort 8p + +pci:v0000114Fd00000045* + ID_MODEL_FROM_DATABASE=AccelePort 16p + +pci:v0000114Fd0000004E* + ID_MODEL_FROM_DATABASE=AccelePort 32p + +pci:v0000114Fd00000070* + ID_MODEL_FROM_DATABASE=Datafire Micro V IOM2 (Europe) + +pci:v0000114Fd00000071* + ID_MODEL_FROM_DATABASE=Datafire Micro V (Europe) + +pci:v0000114Fd00000072* + ID_MODEL_FROM_DATABASE=Datafire Micro V IOM2 (North America) + +pci:v0000114Fd00000073* + ID_MODEL_FROM_DATABASE=Datafire Micro V (North America) + +pci:v0000114Fd000000B0* + ID_MODEL_FROM_DATABASE=Digi Neo 4 + +pci:v0000114Fd000000B1* + ID_MODEL_FROM_DATABASE=Digi Neo 8 + +pci:v0000114Fd000000C8* + ID_MODEL_FROM_DATABASE=Digi Neo 2 DB9 + +pci:v0000114Fd000000C9* + ID_MODEL_FROM_DATABASE=Digi Neo 2 DB9 PRI + +pci:v0000114Fd000000CA* + ID_MODEL_FROM_DATABASE=Digi Neo 2 RJ45 + +pci:v0000114Fd000000CB* + ID_MODEL_FROM_DATABASE=Digi Neo 2 RJ45 PRI + +pci:v0000114Fd000000CC* + ID_MODEL_FROM_DATABASE=Digi Neo 1 422 + +pci:v0000114Fd000000CD* + ID_MODEL_FROM_DATABASE=Digi Neo 1 422 485 + +pci:v0000114Fd000000CE* + ID_MODEL_FROM_DATABASE=Digi Neo 2 422 485 + +pci:v0000114Fd000000D0* + ID_MODEL_FROM_DATABASE=ClassicBoard 4 422 + +pci:v0000114Fd000000D1* + ID_MODEL_FROM_DATABASE=ClassicBoard 8 422 + +pci:v0000114Fd000000F1* + ID_MODEL_FROM_DATABASE=Digi Neo PCI-E 4 port + +pci:v0000114Fd000000F4* + ID_MODEL_FROM_DATABASE=Digi Neo 4 (IBM version) + +pci:v0000114Fd00006001* + ID_MODEL_FROM_DATABASE=Avanstar + +pci:v00001150* + ID_VENDOR_FROM_DATABASE=Thinking Machines Corp + +pci:v00001151* + ID_VENDOR_FROM_DATABASE=JAE Electronics Inc. + +pci:v00001152* + ID_VENDOR_FROM_DATABASE=Megatek + +pci:v00001153* + ID_VENDOR_FROM_DATABASE=Land Win Electronic Corp + +pci:v00001154* + ID_VENDOR_FROM_DATABASE=Melco Inc + +pci:v00001155* + ID_VENDOR_FROM_DATABASE=Pine Technology Ltd + +pci:v00001156* + ID_VENDOR_FROM_DATABASE=Periscope Engineering + +pci:v00001157* + ID_VENDOR_FROM_DATABASE=Avsys Corporation + +pci:v00001158* + ID_VENDOR_FROM_DATABASE=Voarx R & D Inc + +pci:v00001158d00003011* + ID_MODEL_FROM_DATABASE=Tokenet/vg 1001/10m anylan + +pci:v00001158d00009050* + ID_MODEL_FROM_DATABASE=Lanfleet/Truevalue + +pci:v00001158d00009051* + ID_MODEL_FROM_DATABASE=Lanfleet/Truevalue + +pci:v00001159* + ID_VENDOR_FROM_DATABASE=Mutech Corp + +pci:v00001159d00000001* + ID_MODEL_FROM_DATABASE=MV-1000 + +pci:v00001159d00000002* + ID_MODEL_FROM_DATABASE=MV-1500 + +pci:v0000115A* + ID_VENDOR_FROM_DATABASE=Harlequin Ltd + +pci:v0000115B* + ID_VENDOR_FROM_DATABASE=Parallax Graphics + +pci:v0000115C* + ID_VENDOR_FROM_DATABASE=Photron Ltd. + +pci:v0000115D* + ID_VENDOR_FROM_DATABASE=Xircom + +pci:v0000115Dd00000003* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000003sv00001014sd00000181* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000003sv00001014sd00001181* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000003sv00001014sd00008181* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000003sv00001014sd00009181* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000003sv0000115Dsd00000181* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000003sv0000115Dsd00000182* + ID_MODEL_FROM_DATABASE=RealPort2 CardBus Ethernet 10/100 (R2BE-100) + +pci:v0000115Dd00000003sv0000115Dsd00001181* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000003sv00001179sd00000181* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000003sv00008086sd00008181* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Mobile CardBus 32 Adapter + +pci:v0000115Dd00000003sv00008086sd00009181* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Mobile CardBus 32 Adapter + +pci:v0000115Dd00000005* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000005sv00001014sd00000182* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000005sv00001014sd00001182* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000005sv0000115Dsd00000182* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000005sv0000115Dsd00001182* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000007* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000007sv00001014sd00000182* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000007sv00001014sd00001182* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd00000007sv0000115Dsd00000182* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd00000007sv0000115Dsd00001182* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd0000000B* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd0000000Bsv00001014sd00000183* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd0000000Bsv0000115Dsd00000183* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd0000000C* + ID_MODEL_FROM_DATABASE=Mini-PCI V.90 56k Modem + +pci:v0000115Dd0000000F* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd0000000Fsv00001014sd00000183* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Cardbus Adapter + +pci:v0000115Dd0000000Fsv0000115Dsd00000183* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 10/100 + +pci:v0000115Dd000000D4* + ID_MODEL_FROM_DATABASE=Mini-PCI K56Flex Modem + +pci:v0000115Dd00000101* + ID_MODEL_FROM_DATABASE=Cardbus 56k modem + +pci:v0000115Dd00000101sv0000115Dsd00001081* + ID_MODEL_FROM_DATABASE=Cardbus 56k Modem + +pci:v0000115Dd00000103* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet + 56k Modem + +pci:v0000115Dd00000103sv00001014sd00009181* + ID_MODEL_FROM_DATABASE=Cardbus 56k Modem + +pci:v0000115Dd00000103sv00001115sd00001181* + ID_MODEL_FROM_DATABASE=Cardbus Ethernet 100 + 56k Modem + +pci:v0000115Dd00000103sv0000115Dsd00001181* + ID_MODEL_FROM_DATABASE=CBEM56G-100 Ethernet + 56k Modem + +pci:v0000115Dd00000103sv00008086sd00009181* + ID_MODEL_FROM_DATABASE=PRO/100 LAN + Modem56 CardBus + +pci:v0000115E* + ID_VENDOR_FROM_DATABASE=Peer Protocols Inc + +pci:v0000115F* + ID_VENDOR_FROM_DATABASE=Maxtor Corporation + +pci:v00001160* + ID_VENDOR_FROM_DATABASE=Megasoft Inc + +pci:v00001161* + ID_VENDOR_FROM_DATABASE=PFU Limited + +pci:v00001162* + ID_VENDOR_FROM_DATABASE=OA Laboratory Co Ltd + +pci:v00001163* + ID_VENDOR_FROM_DATABASE=Rendition + +pci:v00001163d00000001* + ID_MODEL_FROM_DATABASE=Verite 1000 + +pci:v00001163d00002000* + ID_MODEL_FROM_DATABASE=Verite V2000/V2100/V2200 + +pci:v00001163d00002000sv00001092sd00002000* + ID_MODEL_FROM_DATABASE=Stealth II S220 + +pci:v00001164* + ID_VENDOR_FROM_DATABASE=Advanced Peripherals Technologies + +pci:v00001165* + ID_VENDOR_FROM_DATABASE=Imagraph Corporation + +pci:v00001165d00000001* + ID_MODEL_FROM_DATABASE=Motion TPEG Recorder/Player with audio + +pci:v00001166* + ID_VENDOR_FROM_DATABASE=Broadcom + +pci:v00001166d00000000* + ID_MODEL_FROM_DATABASE=CMIC-LE + +pci:v00001166d00000005* + ID_MODEL_FROM_DATABASE=CNB20-LE Host Bridge + +pci:v00001166d00000006* + ID_MODEL_FROM_DATABASE=CNB20HE Host Bridge + +pci:v00001166d00000007* + ID_MODEL_FROM_DATABASE=CNB20-LE Host Bridge + +pci:v00001166d00000008* + ID_MODEL_FROM_DATABASE=CNB20HE Host Bridge + +pci:v00001166d00000009* + ID_MODEL_FROM_DATABASE=CNB20LE Host Bridge + +pci:v00001166d00000010* + ID_MODEL_FROM_DATABASE=CIOB30 + +pci:v00001166d00000011* + ID_MODEL_FROM_DATABASE=CMIC-HE + +pci:v00001166d00000012* + ID_MODEL_FROM_DATABASE=CMIC-WS Host Bridge (GC-LE chipset) + +pci:v00001166d00000013* + ID_MODEL_FROM_DATABASE=CNB20-HE Host Bridge + +pci:v00001166d00000014* + ID_MODEL_FROM_DATABASE=CMIC-LE Host Bridge (GC-LE chipset) + +pci:v00001166d00000015* + ID_MODEL_FROM_DATABASE=CMIC-GC Host Bridge + +pci:v00001166d00000016* + ID_MODEL_FROM_DATABASE=CMIC-GC Host Bridge + +pci:v00001166d00000017* + ID_MODEL_FROM_DATABASE=GCNB-LE Host Bridge + +pci:v00001166d00000031* + ID_MODEL_FROM_DATABASE=HT1100 HPX0 HT Host Bridge + +pci:v00001166d00000036* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] PCI/PCI-X Bridge + +pci:v00001166d00000101* + ID_MODEL_FROM_DATABASE=CIOB-X2 PCI-X I/O Bridge + +pci:v00001166d00000103* + ID_MODEL_FROM_DATABASE=EPB PCI-Express to PCI-X Bridge + +pci:v00001166d00000104* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] PCI/PCI-X Bridge + +pci:v00001166d00000110* + ID_MODEL_FROM_DATABASE=CIOB-E I/O Bridge with Gigabit Ethernet + +pci:v00001166d00000130* + ID_MODEL_FROM_DATABASE=BCM5780 [HT2000] PCI-X bridge + +pci:v00001166d00000132* + ID_MODEL_FROM_DATABASE=BCM5780 [HT2000] PCI-Express Bridge + +pci:v00001166d00000132sv00001166sd00000132* + ID_MODEL_FROM_DATABASE=HT2000 PCI-Express bridge + +pci:v00001166d00000140* + ID_MODEL_FROM_DATABASE=HT2100 PCI-Express Bridge + +pci:v00001166d00000141* + ID_MODEL_FROM_DATABASE=HT2100 PCI-Express Bridge + +pci:v00001166d00000142* + ID_MODEL_FROM_DATABASE=HT2100 PCI-Express Bridge + +pci:v00001166d00000144* + ID_MODEL_FROM_DATABASE=HT2100 PCI-Express Bridge + +pci:v00001166d00000200* + ID_MODEL_FROM_DATABASE=OSB4 South Bridge + +pci:v00001166d00000201* + ID_MODEL_FROM_DATABASE=CSB5 South Bridge + +pci:v00001166d00000201sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00001166d00000203* + ID_MODEL_FROM_DATABASE=CSB6 South Bridge + +pci:v00001166d00000203sv00001734sd00001012* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series + +pci:v00001166d00000205* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] Legacy South Bridge + +pci:v00001166d00000211* + ID_MODEL_FROM_DATABASE=OSB4 IDE Controller + +pci:v00001166d00000212* + ID_MODEL_FROM_DATABASE=CSB5 IDE Controller + +pci:v00001166d00000212sv00001028sd0000014A* + ID_MODEL_FROM_DATABASE=PowerEdge 1750 + +pci:v00001166d00000212sv00001028sd0000810B* + ID_MODEL_FROM_DATABASE=PowerEdge 1650/2550 + +pci:v00001166d00000212sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00001166d00000213* + ID_MODEL_FROM_DATABASE=CSB6 RAID/IDE Controller + +pci:v00001166d00000213sv00001028sd00004134* + ID_MODEL_FROM_DATABASE=PowerEdge 600SC + +pci:v00001166d00000213sv00001028sd0000C134* + ID_MODEL_FROM_DATABASE=Poweredge SC600 + +pci:v00001166d00000213sv00001734sd00001012* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series onboard IDE + +pci:v00001166d00000214* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] IDE + +pci:v00001166d00000214sv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 HT1000 IDE + +pci:v00001166d00000217* + ID_MODEL_FROM_DATABASE=CSB6 IDE Controller + +pci:v00001166d00000217sv00001028sd00004134* + ID_MODEL_FROM_DATABASE=Poweredge SC600 + +pci:v00001166d0000021B* + ID_MODEL_FROM_DATABASE=HT1100 HD Audio + +pci:v00001166d00000220* + ID_MODEL_FROM_DATABASE=OSB4/CSB5 OHCI USB Controller + +pci:v00001166d00000220sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00001166d00000221* + ID_MODEL_FROM_DATABASE=CSB6 OHCI USB Controller + +pci:v00001166d00000221sv00001734sd00001012* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series onboard OHCI + +pci:v00001166d00000223* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] USB + +pci:v00001166d00000223sv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 HT1000 USB Controller + +pci:v00001166d00000223sv00001028sd0000020B* + ID_MODEL_FROM_DATABASE=PowerEdge T605 HT1000 USB Controller + +pci:v00001166d00000225* + ID_MODEL_FROM_DATABASE=CSB5 LPC bridge + +pci:v00001166d00000227* + ID_MODEL_FROM_DATABASE=GCLE-2 Host Bridge + +pci:v00001166d00000227sv00001734sd00001012* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series + +pci:v00001166d00000230* + ID_MODEL_FROM_DATABASE=CSB5 LPC bridge + +pci:v00001166d00000230sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00001166d00000234* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] LPC + +pci:v00001166d00000234sv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 HT1000 LPC + +pci:v00001166d00000234sv00001028sd0000020B* + ID_MODEL_FROM_DATABASE=PowerEdge T605 HT1000 LPC + +pci:v00001166d00000235* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] XIOAPIC0-2 + +pci:v00001166d00000238* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] WDTimer + +pci:v00001166d00000240* + ID_MODEL_FROM_DATABASE=K2 SATA + +pci:v00001166d00000241* + ID_MODEL_FROM_DATABASE=RAIDCore RC4000 + +pci:v00001166d00000242* + ID_MODEL_FROM_DATABASE=RAIDCore BC4000 + +pci:v00001166d0000024A* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] SATA (Native SATA Mode) + +pci:v00001166d0000024Asv00001028sd0000020B* + ID_MODEL_FROM_DATABASE=PowerEdge T605 onboard SATA Controller + +pci:v00001166d0000024B* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] SATA (PATA/IDE Mode) + +pci:v00001166d0000024Bsv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 HT1000 SATA controller + +pci:v00001166d00000406* + ID_MODEL_FROM_DATABASE=HT1100 PCI-X Bridge + +pci:v00001166d00000408* + ID_MODEL_FROM_DATABASE=HT1100 Legacy Device + +pci:v00001166d0000040A* + ID_MODEL_FROM_DATABASE=HT1100 ISA-LPC Bridge + +pci:v00001166d0000040Asv00001028sd00000223* + ID_MODEL_FROM_DATABASE=PowerEdge R905 HT1100 ISA-LPC Bridge + +pci:v00001166d00000410* + ID_MODEL_FROM_DATABASE=HT1100 SATA Controller (Native SATA Mode) + +pci:v00001166d00000411* + ID_MODEL_FROM_DATABASE=HT1100 SATA Controller (PATA / IDE Mode) + +pci:v00001166d00000412* + ID_MODEL_FROM_DATABASE=HT1100 USB OHCI Controller + +pci:v00001166d00000414* + ID_MODEL_FROM_DATABASE=HT1100 USB EHCI Controller + +pci:v00001166d00000416* + ID_MODEL_FROM_DATABASE=HT1100 USB EHCI Controller (with Debug Port) + +pci:v00001166d00000420* + ID_MODEL_FROM_DATABASE=HT1100 PCI-Express Bridge + +pci:v00001166d00000421* + ID_MODEL_FROM_DATABASE=HT1100 SAS/SATA Controller + +pci:v00001166d00000422* + ID_MODEL_FROM_DATABASE=HT1100 PCI-Express Bridge + +pci:v00001167* + ID_VENDOR_FROM_DATABASE=Mutoh Industries Inc + +pci:v00001168* + ID_VENDOR_FROM_DATABASE=Thine Electronics Inc + +pci:v00001169* + ID_VENDOR_FROM_DATABASE=Centre for Development of Advanced Computing + +pci:v0000116A* + ID_VENDOR_FROM_DATABASE=Luminex Software, Inc. + +pci:v0000116Ad00006100* + ID_MODEL_FROM_DATABASE=Bus/Tag Channel + +pci:v0000116Ad00006800* + ID_MODEL_FROM_DATABASE=Escon Channel + +pci:v0000116Ad00007100* + ID_MODEL_FROM_DATABASE=Bus/Tag Channel + +pci:v0000116Ad00007800* + ID_MODEL_FROM_DATABASE=Escon Channel + +pci:v0000116B* + ID_VENDOR_FROM_DATABASE=Connectware Inc + +pci:v0000116C* + ID_VENDOR_FROM_DATABASE=Intelligent Resources Integrated Systems + +pci:v0000116D* + ID_VENDOR_FROM_DATABASE=Martin-Marietta + +pci:v0000116E* + ID_VENDOR_FROM_DATABASE=Electronics for Imaging + +pci:v0000116F* + ID_VENDOR_FROM_DATABASE=Workstation Technology + +pci:v00001170* + ID_VENDOR_FROM_DATABASE=Inventec Corporation + +pci:v00001171* + ID_VENDOR_FROM_DATABASE=Loughborough Sound Images Plc + +pci:v00001172* + ID_VENDOR_FROM_DATABASE=Altera Corporation + +pci:v00001173* + ID_VENDOR_FROM_DATABASE=Adobe Systems, Inc + +pci:v00001174* + ID_VENDOR_FROM_DATABASE=Bridgeport Machines + +pci:v00001175* + ID_VENDOR_FROM_DATABASE=Mitron Computer Inc. + +pci:v00001176* + ID_VENDOR_FROM_DATABASE=SBE Incorporated + +pci:v00001177* + ID_VENDOR_FROM_DATABASE=Silicon Engineering + +pci:v00001178* + ID_VENDOR_FROM_DATABASE=Alfa, Inc. + +pci:v00001178d0000AFA1* + ID_MODEL_FROM_DATABASE=Fast Ethernet Adapter + +pci:v00001179* + ID_VENDOR_FROM_DATABASE=Toshiba America Info Systems + +pci:v00001179d00000102* + ID_MODEL_FROM_DATABASE=Extended IDE Controller + +pci:v00001179d00000103* + ID_MODEL_FROM_DATABASE=EX-IDE Type-B + +pci:v00001179d00000404* + ID_MODEL_FROM_DATABASE=DVD Decoder card + +pci:v00001179d00000406* + ID_MODEL_FROM_DATABASE=Tecra Video Capture device + +pci:v00001179d00000407* + ID_MODEL_FROM_DATABASE=DVD Decoder card (Version 2) + +pci:v00001179d00000601* + ID_MODEL_FROM_DATABASE=CPU to PCI bridge + +pci:v00001179d00000601sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Satellite Pro + +pci:v00001179d00000602* + ID_MODEL_FROM_DATABASE=PCI to ISA bridge + +pci:v00001179d00000603* + ID_MODEL_FROM_DATABASE=ToPIC95 PCI to CardBus Bridge for Notebooks + +pci:v00001179d00000604* + ID_MODEL_FROM_DATABASE=PCI-Docking Host bridge + +pci:v00001179d0000060A* + ID_MODEL_FROM_DATABASE=ToPIC95 + +pci:v00001179d0000060Asv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Satellite Pro + +pci:v00001179d0000060F* + ID_MODEL_FROM_DATABASE=ToPIC97 + +pci:v00001179d0000060Fsv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Satellite 4010 + +pci:v00001179d00000617* + ID_MODEL_FROM_DATABASE=ToPIC100 PCI to Cardbus Bridge with ZV Support + +pci:v00001179d00000618* + ID_MODEL_FROM_DATABASE=CPU to PCI and PCI to ISA bridge + +pci:v00001179d00000701* + ID_MODEL_FROM_DATABASE=FIR Port Type-O + +pci:v00001179d00000803* + ID_MODEL_FROM_DATABASE=TC6371AF SD Host Controller + +pci:v00001179d00000804* + ID_MODEL_FROM_DATABASE=TC6371AF SmartMedia Controller + +pci:v00001179d00000805* + ID_MODEL_FROM_DATABASE=SD TypA Controller + +pci:v00001179d00000D01* + ID_MODEL_FROM_DATABASE=FIR Port Type-DO + +pci:v00001179d00000D01sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=FIR Port Type-DO + +pci:v0000117A* + ID_VENDOR_FROM_DATABASE=A-Trend Technology + +pci:v0000117B* + ID_VENDOR_FROM_DATABASE=L G Electronics, Inc. + +pci:v0000117C* + ID_VENDOR_FROM_DATABASE=ATTO Technology, Inc. + +pci:v0000117Cd0000002C* + ID_MODEL_FROM_DATABASE=SAS RAID Adapter + +pci:v0000117Cd00000030* + ID_MODEL_FROM_DATABASE=Ultra320 SCSI Host Adapter + +pci:v0000117Cd00000030sv0000117Csd00008013* + ID_MODEL_FROM_DATABASE=ExpressPCI UL4D + +pci:v0000117Cd00000030sv0000117Csd00008014* + ID_MODEL_FROM_DATABASE=ExpressPCI UL4S + +pci:v0000117Cd00000030sv0000117Csd00008027* + ID_MODEL_FROM_DATABASE=ExpressPCI UL5D + +pci:v0000117Cd00000030sv0000117Csd0000802F* + ID_MODEL_FROM_DATABASE=ExpressPCI UL5D Low Profile + +pci:v0000117Cd00000033* + ID_MODEL_FROM_DATABASE=SAS Adapter + +pci:v0000117D* + ID_VENDOR_FROM_DATABASE=Becton & Dickinson + +pci:v0000117E* + ID_VENDOR_FROM_DATABASE=T/R Systems + +pci:v0000117F* + ID_VENDOR_FROM_DATABASE=Integrated Circuit Systems + +pci:v00001180* + ID_VENDOR_FROM_DATABASE=Ricoh Co Ltd + +pci:v00001180d00000465* + ID_MODEL_FROM_DATABASE=RL5c465 + +pci:v00001180d00000466* + ID_MODEL_FROM_DATABASE=RL5c466 + +pci:v00001180d00000475* + ID_MODEL_FROM_DATABASE=RL5c475 + +pci:v00001180d00000475sv0000144Dsd0000C006* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 CardBus bridge + +pci:v00001180d00000476* + ID_MODEL_FROM_DATABASE=RL5c476 II + +pci:v00001180d00000476sv00001014sd00000185* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00001180d00000476sv00001014sd0000056C* + ID_MODEL_FROM_DATABASE=ThinkPad Z60t + +pci:v00001180d00000476sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 laptop + +pci:v00001180d00000476sv00001028sd00000188* + ID_MODEL_FROM_DATABASE=Inspiron 6000 laptop + +pci:v00001180d00000476sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00001180d00000476sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00001180d00000476sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00001180d00000476sv00001043sd00001967* + ID_MODEL_FROM_DATABASE=V6800V + +pci:v00001180d00000476sv00001043sd00001987* + ID_MODEL_FROM_DATABASE=Asus A4K and Z81K notebooks, possibly others ( mid-2005 machines ) + +pci:v00001180d00000476sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00001180d00000476sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00001180d00000476sv0000104Dsd0000814E* + ID_MODEL_FROM_DATABASE=VAIO GRZ390Z + +pci:v00001180d00000476sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00001180d00000476sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00001180d00000476sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00001180d00000476sv000014EFsd00000220* + ID_MODEL_FROM_DATABASE=PCD-RP-220S + +pci:v00001180d00000476sv000017AAsd0000201C* + ID_MODEL_FROM_DATABASE=ThinkPad X60s + +pci:v00001180d00000476sv000017AAsd000020C4* + ID_MODEL_FROM_DATABASE=ThinkPad T61 + +pci:v00001180d00000476sv000017AAsd000020C6* + ID_MODEL_FROM_DATABASE=ThinkPad R61 + +pci:v00001180d00000477* + ID_MODEL_FROM_DATABASE=RL5c477 + +pci:v00001180d00000478* + ID_MODEL_FROM_DATABASE=RL5c478 + +pci:v00001180d00000478sv00001014sd00000184* + ID_MODEL_FROM_DATABASE=ThinkPad A30p + +pci:v00001180d00000511* + ID_MODEL_FROM_DATABASE=R5C511 + +pci:v00001180d00000522* + ID_MODEL_FROM_DATABASE=R5C522 IEEE 1394 Controller + +pci:v00001180d00000522sv00001014sd000001CF* + ID_MODEL_FROM_DATABASE=ThinkPad A30p + +pci:v00001180d00000522sv00001043sd00001967* + ID_MODEL_FROM_DATABASE=V6800V + +pci:v00001180d00000551* + ID_MODEL_FROM_DATABASE=R5C551 IEEE 1394 Controller + +pci:v00001180d00000551sv0000144Dsd0000C006* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00001180d00000552* + ID_MODEL_FROM_DATABASE=R5C552 IEEE 1394 Controller + +pci:v00001180d00000552sv00001014sd00000511* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00001180d00000552sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 laptop + +pci:v00001180d00000552sv00001028sd00000188* + ID_MODEL_FROM_DATABASE=Inspiron 6000 laptop + +pci:v00001180d00000552sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00001180d00000552sv00001043sd00001757* + ID_MODEL_FROM_DATABASE=M2400N laptop + +pci:v00001180d00000552sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00001180d00000552sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00001180d00000552sv000017AAsd0000201E* + ID_MODEL_FROM_DATABASE=ThinkPad X60s + +pci:v00001180d00000554* + ID_MODEL_FROM_DATABASE=R5C554 + +pci:v00001180d00000575* + ID_MODEL_FROM_DATABASE=R5C575 SD Bus Host Adapter + +pci:v00001180d00000576* + ID_MODEL_FROM_DATABASE=R5C576 SD Bus Host Adapter + +pci:v00001180d00000592* + ID_MODEL_FROM_DATABASE=R5C592 Memory Stick Bus Host Adapter + +pci:v00001180d00000592sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00001180d00000592sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00001180d00000592sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00001180d00000592sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v00001180d00000592sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v00001180d00000592sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00001180d00000592sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v00001180d00000592sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00001180d00000592sv00001043sd00001967* + ID_MODEL_FROM_DATABASE=V6800V + +pci:v00001180d00000592sv0000144Dsd0000C018* + ID_MODEL_FROM_DATABASE=X20 IV + +pci:v00001180d00000592sv000017AAsd000020CA* + ID_MODEL_FROM_DATABASE=ThinkPad T61 + +pci:v00001180d00000811* + ID_MODEL_FROM_DATABASE=R5C811 + +pci:v00001180d00000822* + ID_MODEL_FROM_DATABASE=R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter + +pci:v00001180d00000822sv00001014sd00000556* + ID_MODEL_FROM_DATABASE=ThinkPad X60s / Z60t + +pci:v00001180d00000822sv00001014sd00000598* + ID_MODEL_FROM_DATABASE=ThinkPad Z60m + +pci:v00001180d00000822sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00001180d00000822sv00001028sd00000188* + ID_MODEL_FROM_DATABASE=Inspiron 6000 laptop + +pci:v00001180d00000822sv00001028sd000001A2* + ID_MODEL_FROM_DATABASE=Inspiron 9200 + +pci:v00001180d00000822sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00001180d00000822sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00001180d00000822sv0000103Csd000003B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v00001180d00000822sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v00001180d00000822sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00001180d00000822sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00001180d00000822sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v00001180d00000822sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00001180d00000822sv00001043sd00001967* + ID_MODEL_FROM_DATABASE=ASUS V6800V + +pci:v00001180d00000822sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00001180d00000822sv0000144Dsd0000C018* + ID_MODEL_FROM_DATABASE=X20 IV + +pci:v00001180d00000822sv000017AAsd0000201D* + ID_MODEL_FROM_DATABASE=ThinkPad X60s + +pci:v00001180d00000822sv000017AAsd000020C7* + ID_MODEL_FROM_DATABASE=ThinkPad T61 + +pci:v00001180d00000822sv000017AAsd000020C8* + ID_MODEL_FROM_DATABASE=ThinkPad W500 + +pci:v00001180d00000832* + ID_MODEL_FROM_DATABASE=R5C832 IEEE 1394 Controller + +pci:v00001180d00000832sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00001180d00000832sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00001180d00000832sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00001180d00000832sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v00001180d00000832sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v00001180d00000832sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00001180d00000832sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00001180d00000832sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v00001180d00000832sv000017AAsd000020C7* + ID_MODEL_FROM_DATABASE=ThinkPad R61 + +pci:v00001180d00000841* + ID_MODEL_FROM_DATABASE=R5C841 CardBus/SD/SDIO/MMC/MS/MSPro/xD/IEEE1394 + +pci:v00001180d00000843* + ID_MODEL_FROM_DATABASE=R5C843 MMC Host Controller + +pci:v00001180d00000843sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00001180d00000843sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00001180d00000843sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00001180d00000843sv00001028sd000001F5* + ID_MODEL_FROM_DATABASE=Dell Inspiron 1501 + +pci:v00001180d00000843sv00001028sd0000024F* + ID_MODEL_FROM_DATABASE=Dell Latitude e6500 + +pci:v00001180d00000843sv0000103Csd000003B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v00001180d00000843sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v00001180d00000843sv00001183sd00000843* + ID_MODEL_FROM_DATABASE=Alienware Aurora m9700 + +pci:v00001180d00000852* + ID_MODEL_FROM_DATABASE=xD-Picture Card Controller + +pci:v00001180d00000852sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00001180d00000852sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00001180d00000852sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v00001180d00000852sv0000103Csd000030B7* + ID_MODEL_FROM_DATABASE=Presario V6133CL + +pci:v00001180d00000852sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00001180d00000852sv0000103Csd000030CF* + ID_MODEL_FROM_DATABASE=Pavilion dv9668eg Laptop + +pci:v00001180d00000852sv00001043sd00001967* + ID_MODEL_FROM_DATABASE=V6800V + +pci:v00001180d00000852sv00001180sd00000852* + ID_MODEL_FROM_DATABASE=Pavilion 2410us + +pci:v00001180d00000852sv00001324sd000010CF* + ID_MODEL_FROM_DATABASE=P7120 + +pci:v00001180d0000E230* + ID_MODEL_FROM_DATABASE=R5U2xx (R5U230 / R5U231 / R5U241) [Memory Stick Host Controller] + +pci:v00001180d0000E476* + ID_MODEL_FROM_DATABASE=CardBus bridge + +pci:v00001180d0000E476sv00001028sd0000040A* + ID_MODEL_FROM_DATABASE=Latitude E6410 + +pci:v00001180d0000E476sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00001180d0000E822* + ID_MODEL_FROM_DATABASE=MMC/SD Host Controller + +pci:v00001180d0000E822sv00001028sd0000040A* + ID_MODEL_FROM_DATABASE=Latitude E6410 + +pci:v00001180d0000E822sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00001180d0000E823* + ID_MODEL_FROM_DATABASE=PCIe SDXC/MMC Host Controller + +pci:v00001180d0000E832* + ID_MODEL_FROM_DATABASE=R5C832 PCIe IEEE 1394 Controller + +pci:v00001180d0000E832sv00001028sd0000040A* + ID_MODEL_FROM_DATABASE=Latitude E6410 + +pci:v00001180d0000E832sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00001180d0000E852* + ID_MODEL_FROM_DATABASE=PCIe xD-Picture Card Controller + +pci:v00001181* + ID_VENDOR_FROM_DATABASE=Telmatics International + +pci:v00001183* + ID_VENDOR_FROM_DATABASE=Fujikura Ltd + +pci:v00001184* + ID_VENDOR_FROM_DATABASE=Forks Inc + +pci:v00001185* + ID_VENDOR_FROM_DATABASE=Dataworld International Ltd + +pci:v00001186* + ID_VENDOR_FROM_DATABASE=D-Link System Inc + +pci:v00001186d00001002* + ID_MODEL_FROM_DATABASE=DL10050 Sundance Ethernet + +pci:v00001186d00001002sv00001186sd00001002* + ID_MODEL_FROM_DATABASE=DFE-550TX/FX + +pci:v00001186d00001002sv00001186sd00001012* + ID_MODEL_FROM_DATABASE=DFE-580TX + +pci:v00001186d00001025* + ID_MODEL_FROM_DATABASE=AirPlus Xtreme G DWL-G650 Adapter + +pci:v00001186d00001026* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG650 Wireless Cardbus Adapter + +pci:v00001186d00001043* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG650 Wireless Cardbus Adapter + +pci:v00001186d00001300* + ID_MODEL_FROM_DATABASE=RTL8139 Ethernet + +pci:v00001186d00001300sv00001186sd00001300* + ID_MODEL_FROM_DATABASE=DFE-538TX 10/100 Ethernet Adapter + +pci:v00001186d00001300sv00001186sd00001301* + ID_MODEL_FROM_DATABASE=DFE-530TX+ 10/100 Ethernet Adapter + +pci:v00001186d00001300sv00001186sd00001303* + ID_MODEL_FROM_DATABASE=DFE-528TX 10/100 Fast Ethernet PCI Adapter + +pci:v00001186d00001340* + ID_MODEL_FROM_DATABASE=DFE-690TXD CardBus PC Card + +pci:v00001186d00001540* + ID_MODEL_FROM_DATABASE=DFE-680TX + +pci:v00001186d00001541* + ID_MODEL_FROM_DATABASE=DFE-680TXD CardBus PC Card + +pci:v00001186d00001561* + ID_MODEL_FROM_DATABASE=DRP-32TXD Cardbus PC Card + +pci:v00001186d00003300* + ID_MODEL_FROM_DATABASE=DWL-510 / DWL-610 802.11b [Realtek RTL8180L] + +pci:v00001186d00003300sv00001186sd00003300* + ID_MODEL_FROM_DATABASE=DWL-610 Wireless Cardbus Adapter + +pci:v00001186d00003300sv00001186sd00003301* + ID_MODEL_FROM_DATABASE=DWL-510 Wireless PCI Adapter + +pci:v00001186d00003A10* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG650 Wireless Cardbus Adapter(rev.B) + +pci:v00001186d00003A11* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG520 Wireless PCI Adapter(rev.B) + +pci:v00001186d00004000* + ID_MODEL_FROM_DATABASE=DL2000-based Gigabit Ethernet + +pci:v00001186d00004001* + ID_MODEL_FROM_DATABASE=DGE-550SX PCI-X Gigabit Ethernet Adapter + +pci:v00001186d00004300* + ID_MODEL_FROM_DATABASE=DGE-528T Gigabit Ethernet Adapter + +pci:v00001186d00004300sv00001186sd00004B10* + ID_MODEL_FROM_DATABASE=DGE-560T PCI Express (x1) Gigabit Ethernet Adapter + +pci:v00001186d00004302* + ID_MODEL_FROM_DATABASE=DGE-530T Gigabit Ethernet Adapter (rev.C1) [Realtek RTL8169] + +pci:v00001186d00004B00* + ID_MODEL_FROM_DATABASE=DGE-560T PCI Express Gigabit Ethernet Adapter + +pci:v00001186d00004B01* + ID_MODEL_FROM_DATABASE=DGE-530T Gigabit Ethernet Adapter (rev 11) + +pci:v00001186d00004B02* + ID_MODEL_FROM_DATABASE=DGE-560SX PCI Express Gigabit Ethernet Adapter + +pci:v00001186d00004B03* + ID_MODEL_FROM_DATABASE=DGE-550T Gigabit Ethernet Adapter V.B1 + +pci:v00001186d00004C00* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet Adapter + +pci:v00001186d00004C00sv00001186sd00004C00* + ID_MODEL_FROM_DATABASE=DGE-530T Gigabit Ethernet Adapter + +pci:v00001186d00008400* + ID_MODEL_FROM_DATABASE=D-Link DWL-650+ CardBus PC Card + +pci:v00001187* + ID_VENDOR_FROM_DATABASE=Advanced Technology Laboratories, Inc. + +pci:v00001188* + ID_VENDOR_FROM_DATABASE=Shima Seiki Manufacturing Ltd. + +pci:v00001189* + ID_VENDOR_FROM_DATABASE=Matsushita Electronics Co Ltd + +pci:v0000118A* + ID_VENDOR_FROM_DATABASE=Hilevel Technology + +pci:v0000118B* + ID_VENDOR_FROM_DATABASE=Hypertec Pty Limited + +pci:v0000118C* + ID_VENDOR_FROM_DATABASE=Corollary, Inc + +pci:v0000118Cd00000014* + ID_MODEL_FROM_DATABASE=PCIB [C-bus II to PCI bus host bridge chip] + +pci:v0000118Cd00001117* + ID_MODEL_FROM_DATABASE=Intel 8-way XEON Profusion Chipset [Cache Coherency Filter] + +pci:v0000118D* + ID_VENDOR_FROM_DATABASE=BitFlow Inc + +pci:v0000118Dd00000001* + ID_MODEL_FROM_DATABASE=Raptor-PCI framegrabber + +pci:v0000118Dd00000012* + ID_MODEL_FROM_DATABASE=Model 12 Road Runner Frame Grabber + +pci:v0000118Dd00000014* + ID_MODEL_FROM_DATABASE=Model 14 Road Runner Frame Grabber + +pci:v0000118Dd00000024* + ID_MODEL_FROM_DATABASE=Model 24 Road Runner Frame Grabber + +pci:v0000118Dd00000044* + ID_MODEL_FROM_DATABASE=Model 44 Road Runner Frame Grabber + +pci:v0000118Dd00000112* + ID_MODEL_FROM_DATABASE=Model 12 Road Runner Frame Grabber + +pci:v0000118Dd00000114* + ID_MODEL_FROM_DATABASE=Model 14 Road Runner Frame Grabber + +pci:v0000118Dd00000124* + ID_MODEL_FROM_DATABASE=Model 24 Road Runner Frame Grabber + +pci:v0000118Dd00000144* + ID_MODEL_FROM_DATABASE=Model 44 Road Runner Frame Grabber + +pci:v0000118Dd00000212* + ID_MODEL_FROM_DATABASE=Model 12 Road Runner Frame Grabber + +pci:v0000118Dd00000214* + ID_MODEL_FROM_DATABASE=Model 14 Road Runner Frame Grabber + +pci:v0000118Dd00000224* + ID_MODEL_FROM_DATABASE=Model 24 Road Runner Frame Grabber + +pci:v0000118Dd00000244* + ID_MODEL_FROM_DATABASE=Model 44 Road Runner Frame Grabber + +pci:v0000118Dd00000312* + ID_MODEL_FROM_DATABASE=Model 12 Road Runner Frame Grabber + +pci:v0000118Dd00000314* + ID_MODEL_FROM_DATABASE=Model 14 Road Runner Frame Grabber + +pci:v0000118Dd00000324* + ID_MODEL_FROM_DATABASE=Model 24 Road Runner Frame Grabber + +pci:v0000118Dd00000344* + ID_MODEL_FROM_DATABASE=Model 44 Road Runner Frame Grabber + +pci:v0000118E* + ID_VENDOR_FROM_DATABASE=Hermstedt GmbH + +pci:v0000118F* + ID_VENDOR_FROM_DATABASE=Green Logic + +pci:v00001190* + ID_VENDOR_FROM_DATABASE=Tripace + +pci:v00001190d0000C731* + ID_MODEL_FROM_DATABASE=TP-910/920/940 PCI Ultra(Wide) SCSI Adapter + +pci:v00001191* + ID_VENDOR_FROM_DATABASE=Artop Electronic Corp + +pci:v00001191d00000003* + ID_MODEL_FROM_DATABASE=SCSI Cache Host Adapter + +pci:v00001191d00000004* + ID_MODEL_FROM_DATABASE=ATP8400 + +pci:v00001191d00000005* + ID_MODEL_FROM_DATABASE=ATP850UF + +pci:v00001191d00000006* + ID_MODEL_FROM_DATABASE=ATP860 NO-BIOS + +pci:v00001191d00000007* + ID_MODEL_FROM_DATABASE=ATP860 + +pci:v00001191d00000008* + ID_MODEL_FROM_DATABASE=ATP865 NO-ROM + +pci:v00001191d00000009* + ID_MODEL_FROM_DATABASE=ATP865 + +pci:v00001191d0000000A* + ID_MODEL_FROM_DATABASE=ATP867-A + +pci:v00001191d0000000B* + ID_MODEL_FROM_DATABASE=ATP867-B + +pci:v00001191d0000000D* + ID_MODEL_FROM_DATABASE=ATP8620 + +pci:v00001191d0000000E* + ID_MODEL_FROM_DATABASE=ATP8620 + +pci:v00001191d00008002* + ID_MODEL_FROM_DATABASE=AEC6710 SCSI-2 Host Adapter + +pci:v00001191d00008010* + ID_MODEL_FROM_DATABASE=AEC6712UW SCSI + +pci:v00001191d00008020* + ID_MODEL_FROM_DATABASE=AEC6712U SCSI + +pci:v00001191d00008030* + ID_MODEL_FROM_DATABASE=AEC6712S SCSI + +pci:v00001191d00008040* + ID_MODEL_FROM_DATABASE=AEC6712D SCSI + +pci:v00001191d00008050* + ID_MODEL_FROM_DATABASE=AEC6712SUW SCSI + +pci:v00001191d00008060* + ID_MODEL_FROM_DATABASE=AEC6712 SCSI + +pci:v00001191d00008080* + ID_MODEL_FROM_DATABASE=AEC67160 SCSI + +pci:v00001191d00008081* + ID_MODEL_FROM_DATABASE=AEC67160S SCSI + +pci:v00001191d0000808A* + ID_MODEL_FROM_DATABASE=AEC67162 2-ch. LVD SCSI + +pci:v00001192* + ID_VENDOR_FROM_DATABASE=Densan Company Ltd + +pci:v00001193* + ID_VENDOR_FROM_DATABASE=Zeitnet Inc. + +pci:v00001193d00000001* + ID_MODEL_FROM_DATABASE=1221 + +pci:v00001193d00000002* + ID_MODEL_FROM_DATABASE=1225 + +pci:v00001194* + ID_VENDOR_FROM_DATABASE=Toucan Technology + +pci:v00001195* + ID_VENDOR_FROM_DATABASE=Ratoc System Inc + +pci:v00001196* + ID_VENDOR_FROM_DATABASE=Hytec Electronics Ltd + +pci:v00001197* + ID_VENDOR_FROM_DATABASE=Gage Applied Sciences, Inc. + +pci:v00001197d0000010C* + ID_MODEL_FROM_DATABASE=CompuScope 82G 8bit 2GS/s Analog Input Card + +pci:v00001198* + ID_VENDOR_FROM_DATABASE=Lambda Systems Inc + +pci:v00001199* + ID_VENDOR_FROM_DATABASE=Attachmate Corporation + +pci:v00001199d00000101* + ID_MODEL_FROM_DATABASE=Advanced ISCA/PCI Adapter + +pci:v00001199d00006832* + ID_MODEL_FROM_DATABASE=Sierra Wireless MC8780 Device + +pci:v0000119A* + ID_VENDOR_FROM_DATABASE=Mind Share, Inc. + +pci:v0000119B* + ID_VENDOR_FROM_DATABASE=Omega Micro Inc. + +pci:v0000119Bd00001221* + ID_MODEL_FROM_DATABASE=82C092G + +pci:v0000119C* + ID_VENDOR_FROM_DATABASE=Information Technology Inst. + +pci:v0000119D* + ID_VENDOR_FROM_DATABASE=Bug, Inc. Sapporo Japan + +pci:v0000119E* + ID_VENDOR_FROM_DATABASE=Fujitsu Microelectronics Ltd. + +pci:v0000119Ed00000001* + ID_MODEL_FROM_DATABASE=FireStream 155 + +pci:v0000119Ed00000003* + ID_MODEL_FROM_DATABASE=FireStream 50 + +pci:v0000119F* + ID_VENDOR_FROM_DATABASE=Bull HN Information Systems + +pci:v000011A0* + ID_VENDOR_FROM_DATABASE=Convex Computer Corporation + +pci:v000011A1* + ID_VENDOR_FROM_DATABASE=Hamamatsu Photonics K.K. + +pci:v000011A2* + ID_VENDOR_FROM_DATABASE=Sierra Research and Technology + +pci:v000011A3* + ID_VENDOR_FROM_DATABASE=Deuretzbacher GmbH & Co. Eng. KG + +pci:v000011A4* + ID_VENDOR_FROM_DATABASE=Barco Graphics NV + +pci:v000011A5* + ID_VENDOR_FROM_DATABASE=Microunity Systems Eng. Inc + +pci:v000011A6* + ID_VENDOR_FROM_DATABASE=Pure Data Ltd. + +pci:v000011A7* + ID_VENDOR_FROM_DATABASE=Power Computing Corp. + +pci:v000011A8* + ID_VENDOR_FROM_DATABASE=Systech Corp. + +pci:v000011A9* + ID_VENDOR_FROM_DATABASE=InnoSys Inc. + +pci:v000011A9d00004240* + ID_MODEL_FROM_DATABASE=AMCC S933Q Intelligent Serial Card + +pci:v000011AA* + ID_VENDOR_FROM_DATABASE=Actel + +pci:v000011AB* + ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. + +pci:v000011ABd00000146* + ID_MODEL_FROM_DATABASE=GT-64010/64010A System Controller + +pci:v000011ABd00000F53* + ID_MODEL_FROM_DATABASE=88E6318 Link Street network controller + +pci:v000011ABd000011AB* + ID_MODEL_FROM_DATABASE=MV88SE614x SATA II PCI-E controller + +pci:v000011ABd0000138F* + ID_MODEL_FROM_DATABASE=W8300 802.11 Adapter (rev 07) + +pci:v000011ABd00001FA6* + ID_MODEL_FROM_DATABASE=Marvell W8300 802.11 Adapter + +pci:v000011ABd00001FA6sv00001186sd00003B08* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.A1) + +pci:v000011ABd00001FA7* + ID_MODEL_FROM_DATABASE=88W8310 and 88W8000G [Libertas] 802.11g client chipset + +pci:v000011ABd00001FAA* + ID_MODEL_FROM_DATABASE=88w8335 [Libertas] 802.11b/g Wireless + +pci:v000011ABd00001FAAsv00001385sd00004E00* + ID_MODEL_FROM_DATABASE=WG511v2 54 Mbps Wireless PC Card + +pci:v000011ABd00001FAAsv00001385sd00006B00* + ID_MODEL_FROM_DATABASE=WG311v3 802.11g Wireless PCI Adapter + +pci:v000011ABd00001FAAsv00001737sd00000040* + ID_MODEL_FROM_DATABASE=WPC54G v5 802.11g Wireless-G Notebook Adapter + +pci:v000011ABd00002211* + ID_MODEL_FROM_DATABASE=88SB2211 PCI Express to PCI Bridge + +pci:v000011ABd00002A01* + ID_MODEL_FROM_DATABASE=88W8335 [Libertas] 802.11b/g Wireless + +pci:v000011ABd00002A02* + ID_MODEL_FROM_DATABASE=88W8361 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A02sv000007D1sd00003B02* + ID_MODEL_FROM_DATABASE=DIR-615 rev. A1 Mini PCI Wireless Module + +pci:v000011ABd00002A02sv00001385sd00007C00* + ID_MODEL_FROM_DATABASE=WN511T RangeMax Next 300 Mbps Wireless PC Card + +pci:v000011ABd00002A02sv00001385sd00007C01* + ID_MODEL_FROM_DATABASE=WN511T RangeMax Next 300 Mbps Wireless Notebook Adapter + +pci:v000011ABd00002A02sv00001385sd00007E00* + ID_MODEL_FROM_DATABASE=WN311T RangeMax Next 300 Mbps Wireless PCI Adapter + +pci:v000011ABd00002A02sv00001799sd0000801B* + ID_MODEL_FROM_DATABASE=F5D8011 v2 802.11n N1 Wireless Notebook Card + +pci:v000011ABd00002A08* + ID_MODEL_FROM_DATABASE=88W8362e [TopDog] 802.11a/b/g/n Wireless + +pci:v000011ABd00002A0A* + ID_MODEL_FROM_DATABASE=88W8363 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A0C* + ID_MODEL_FROM_DATABASE=88W8363 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A24* + ID_MODEL_FROM_DATABASE=88W8363 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A2B* + ID_MODEL_FROM_DATABASE=88W8687 [TopDog] 802.11b/g Wireless + +pci:v000011ABd00002A30* + ID_MODEL_FROM_DATABASE=88W8687 [TopDog] 802.11b/g Wireless + +pci:v000011ABd00002A40* + ID_MODEL_FROM_DATABASE=88W8366 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A41* + ID_MODEL_FROM_DATABASE=88W8366 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A42* + ID_MODEL_FROM_DATABASE=88W8366 [TopDog] 802.11n Wireless + +pci:v000011ABd00002A43* + ID_MODEL_FROM_DATABASE=88W8366 [TopDog] 802.11n Wireless + +pci:v000011ABd00002B36* + ID_MODEL_FROM_DATABASE=88W8764 [Avastar] 802.11n Wireless + +pci:v000011ABd00004101* + ID_MODEL_FROM_DATABASE=OLPC Cafe Controller Secure Digital Controller + +pci:v000011ABd00004320* + ID_MODEL_FROM_DATABASE=88E8001 Gigabit Ethernet Controller + +pci:v000011ABd00004320sv00001019sd00000F38* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (ECS) + +pci:v000011ABd00004320sv00001019sd00008001* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (ECS) + +pci:v000011ABd00004320sv00001043sd0000173C* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Asus) + +pci:v000011ABd00004320sv00001043sd0000811A* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Asus) + +pci:v000011ABd00004320sv0000105Bsd00000C19* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Foxconn) + +pci:v000011ABd00004320sv000010B8sd0000B452* + ID_MODEL_FROM_DATABASE=EZ Card 1000 (SMC9452TXV.2) + +pci:v000011ABd00004320sv000011ABsd00000121* + ID_MODEL_FROM_DATABASE=Marvell RDK-8001 + +pci:v000011ABd00004320sv000011ABsd00000321* + ID_MODEL_FROM_DATABASE=Marvell RDK-8003 + +pci:v000011ABd00004320sv000011ABsd00001021* + ID_MODEL_FROM_DATABASE=Marvell RDK-8010 + +pci:v000011ABd00004320sv000011ABsd00004320* + ID_MODEL_FROM_DATABASE=Marvell Yukon Gigabit Ethernet 10/100/1000Baset-T Constroller (Asus) + +pci:v000011ABd00004320sv000011ABsd00005021* + ID_MODEL_FROM_DATABASE=Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (64 bit) + +pci:v000011ABd00004320sv000011ABsd00009521* + ID_MODEL_FROM_DATABASE=Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (32 bit) + +pci:v000011ABd00004320sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Gigabyte) + +pci:v000011ABd00004320sv0000147Bsd00001406* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Abit) + +pci:v000011ABd00004320sv000015D4sd00000047* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Iwill) + +pci:v000011ABd00004320sv00001695sd00009025* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Epox) + +pci:v000011ABd00004320sv000017F2sd00001C03* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Albatron) + +pci:v000011ABd00004320sv0000270Fsd00002803* + ID_MODEL_FROM_DATABASE=Marvell 88E8001 Gigabit Ethernet Controller (Chaintech) + +pci:v000011ABd00004340* + ID_MODEL_FROM_DATABASE=88E8021 PCI-X IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004341* + ID_MODEL_FROM_DATABASE=88E8022 PCI-X IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004342* + ID_MODEL_FROM_DATABASE=88E8061 PCI-E IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004343* + ID_MODEL_FROM_DATABASE=88E8062 PCI-E IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004344* + ID_MODEL_FROM_DATABASE=88E8021 PCI-X IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004345* + ID_MODEL_FROM_DATABASE=88E8022 PCI-X IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004346* + ID_MODEL_FROM_DATABASE=88E8061 PCI-E IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004347* + ID_MODEL_FROM_DATABASE=88E8062 PCI-E IPMI Gigabit Ethernet Controller + +pci:v000011ABd00004347sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 PrAMC Gigabit Ethernet + +pci:v000011ABd00004350* + ID_MODEL_FROM_DATABASE=88E8035 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004350sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (Toshiba) + +pci:v000011ABd00004350sv000011ABsd00003521* + ID_MODEL_FROM_DATABASE=Marvell RDK-8035 + +pci:v000011ABd00004350sv00001854sd0000000D* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd0000000E* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd0000000F* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000011* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000012* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000016* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000017* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000018* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000019* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd0000001C* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd0000001E* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004350sv00001854sd00000020* + ID_MODEL_FROM_DATABASE=Marvell 88E8035 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351* + ID_MODEL_FROM_DATABASE=88E8036 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004351sv0000107Bsd00004009* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Wistron) + +pci:v000011ABd00004351sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Panasonic) + +pci:v000011ABd00004351sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Toshiba) + +pci:v000011ABd00004351sv00001179sd0000FF00* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Compal) + +pci:v000011ABd00004351sv00001179sd0000FF10* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Inventec) + +pci:v000011ABd00004351sv000011ABsd00003621* + ID_MODEL_FROM_DATABASE=Marvell RDK-8036 + +pci:v000011ABd00004351sv000013D1sd0000AC12* + ID_MODEL_FROM_DATABASE=Abocom EFE3K - 10/100 Ethernet Expresscard + +pci:v000011ABd00004351sv0000161Fsd0000203D* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (Arima) + +pci:v000011ABd00004351sv00001854sd0000000D* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd0000000E* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd0000000F* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000011* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000012* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000016* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000017* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000018* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000019* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd0000001C* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd0000001E* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004351sv00001854sd00000020* + ID_MODEL_FROM_DATABASE=Marvell 88E8036 Fast Ethernet Controller (LGE) + +pci:v000011ABd00004352* + ID_MODEL_FROM_DATABASE=88E8038 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004353* + ID_MODEL_FROM_DATABASE=88E8039 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004353sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v000011ABd00004354* + ID_MODEL_FROM_DATABASE=88E8040 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004354sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v000011ABd00004355* + ID_MODEL_FROM_DATABASE=88E8040T PCI-E Fast Ethernet Controller + +pci:v000011ABd00004355sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v000011ABd00004356* + ID_MODEL_FROM_DATABASE=88EC033 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004357* + ID_MODEL_FROM_DATABASE=88E8042 PCI-E Fast Ethernet Controller + +pci:v000011ABd0000435A* + ID_MODEL_FROM_DATABASE=88E8048 PCI-E Fast Ethernet Controller + +pci:v000011ABd00004360* + ID_MODEL_FROM_DATABASE=88E8052 PCI-E ASF Gigabit Ethernet Controller + +pci:v000011ABd00004360sv00001043sd00008134* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (Asus) + +pci:v000011ABd00004360sv0000107Bsd00004009* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (Wistron) + +pci:v000011ABd00004360sv000011ABsd00005221* + ID_MODEL_FROM_DATABASE=Marvell RDK-8052 + +pci:v000011ABd00004360sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte) + +pci:v000011ABd00004360sv00001462sd0000052C* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (MSI) + +pci:v000011ABd00004360sv00001849sd00008052* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (ASRock) + +pci:v000011ABd00004360sv0000A0A0sd00000509* + ID_MODEL_FROM_DATABASE=Marvell 88E8052 Gigabit Ethernet Controller (Aopen) + +pci:v000011ABd00004361* + ID_MODEL_FROM_DATABASE=88E8050 PCI-E ASF Gigabit Ethernet Controller + +pci:v000011ABd00004361sv0000107Bsd00003015* + ID_MODEL_FROM_DATABASE=Marvell 88E8050 Gigabit Ethernet Controller (Gateway) + +pci:v000011ABd00004361sv000011ABsd00005021* + ID_MODEL_FROM_DATABASE=Marvell 88E8050 Gigabit Ethernet Controller (Intel) + +pci:v000011ABd00004361sv00008086sd00003063* + ID_MODEL_FROM_DATABASE=D925XCVLK mainboard + +pci:v000011ABd00004361sv00008086sd00003439* + ID_MODEL_FROM_DATABASE=Marvell 88E8050 Gigabit Ethernet Controller (Intel) + +pci:v000011ABd00004362* + ID_MODEL_FROM_DATABASE=88E8053 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004362sv0000103Csd00002A0D* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Asus) + +pci:v000011ABd00004362sv00001043sd00008142* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet controller PCIe (Asus) + +pci:v000011ABd00004362sv0000109Fsd00003197* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Trigem) + +pci:v000011ABd00004362sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Panasonic) + +pci:v000011ABd00004362sv000010FDsd0000A430* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (SOYO) + +pci:v000011ABd00004362sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Toshiba) + +pci:v000011ABd00004362sv00001179sd0000FF00* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Compal) + +pci:v000011ABd00004362sv00001179sd0000FF10* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Inventec) + +pci:v000011ABd00004362sv000011ABsd00005321* + ID_MODEL_FROM_DATABASE=Marvell RDK-8053 + +pci:v000011ABd00004362sv00001297sd0000C240* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Shuttle) + +pci:v000011ABd00004362sv00001297sd0000C241* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Shuttle) + +pci:v000011ABd00004362sv00001297sd0000C242* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Shuttle) + +pci:v000011ABd00004362sv00001297sd0000C243* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Shuttle) + +pci:v000011ABd00004362sv00001297sd0000C244* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Shuttle) + +pci:v000011ABd00004362sv000013D1sd0000AC11* + ID_MODEL_FROM_DATABASE=EGE5K - Giga Ethernet Expresscard + +pci:v000011ABd00004362sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte) + +pci:v000011ABd00004362sv00001462sd0000058C* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (MSI) + +pci:v000011ABd00004362sv000014C0sd00000012* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Compal) + +pci:v000011ABd00004362sv00001558sd000004A0* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Clevo) + +pci:v000011ABd00004362sv000015BDsd00001003* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (DFI) + +pci:v000011ABd00004362sv0000161Fsd0000203C* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Arima) + +pci:v000011ABd00004362sv0000161Fsd0000203D* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Arima) + +pci:v000011ABd00004362sv00001695sd00009029* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Epox) + +pci:v000011ABd00004362sv000017F2sd00002C08* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Albatron) + +pci:v000011ABd00004362sv000017FFsd00000585* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Quanta) + +pci:v000011ABd00004362sv00001849sd00008053* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (ASRock) + +pci:v000011ABd00004362sv00001854sd0000000B* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd0000000C* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000010* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000013* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000014* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000015* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd0000001A* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd0000001B* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd0000001D* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd0000001F* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000021* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv00001854sd00000022* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (LGE) + +pci:v000011ABd00004362sv0000270Fsd00002801* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Chaintech) + +pci:v000011ABd00004362sv0000A0A0sd00000506* + ID_MODEL_FROM_DATABASE=Marvell 88E8053 Gigabit Ethernet Controller (Aopen) + +pci:v000011ABd00004363* + ID_MODEL_FROM_DATABASE=88E8055 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004364* + ID_MODEL_FROM_DATABASE=88E8056 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004364sv00001043sd000081F8* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v000011ABd00004364sv000011BAsd000000BA* + ID_MODEL_FROM_DATABASE=8056 Gigabit Ethernet Controller + +pci:v000011ABd00004365* + ID_MODEL_FROM_DATABASE=88E8070 based Ethernet Controller + +pci:v000011ABd00004366* + ID_MODEL_FROM_DATABASE=88EC036 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004367* + ID_MODEL_FROM_DATABASE=88EC032 Ethernet Controller + +pci:v000011ABd00004368* + ID_MODEL_FROM_DATABASE=88EC034 Ethernet Controller + +pci:v000011ABd00004369* + ID_MODEL_FROM_DATABASE=88EC042 Ethernet Controller + +pci:v000011ABd0000436A* + ID_MODEL_FROM_DATABASE=88E8058 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd0000436Asv000011ABsd000000BA* + ID_MODEL_FROM_DATABASE=Imac 8,1 Wired Ethernet Adapter + +pci:v000011ABd0000436B* + ID_MODEL_FROM_DATABASE=88E8071 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd0000436C* + ID_MODEL_FROM_DATABASE=88E8072 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd0000436D* + ID_MODEL_FROM_DATABASE=88E8055 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004370* + ID_MODEL_FROM_DATABASE=88E8075 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004380* + ID_MODEL_FROM_DATABASE=88E8057 PCI-E Gigabit Ethernet Controller + +pci:v000011ABd00004381* + ID_MODEL_FROM_DATABASE=Yukon Optima 88E8059 [PCIe Gigabit Ethernet Controller with AVB] + +pci:v000011ABd00004611* + ID_MODEL_FROM_DATABASE=GT-64115 System Controller + +pci:v000011ABd00004620* + ID_MODEL_FROM_DATABASE=GT-64120/64120A/64121A System Controller + +pci:v000011ABd00004801* + ID_MODEL_FROM_DATABASE=GT-48001 + +pci:v000011ABd00005005* + ID_MODEL_FROM_DATABASE=Belkin F5D5005 Gigabit Desktop Network PCI Card + +pci:v000011ABd00005040* + ID_MODEL_FROM_DATABASE=MV88SX5040 4-port SATA I PCI-X Controller + +pci:v000011ABd00005041* + ID_MODEL_FROM_DATABASE=MV88SX5041 4-port SATA I PCI-X Controller + +pci:v000011ABd00005080* + ID_MODEL_FROM_DATABASE=MV88SX5080 8-port SATA I PCI-X Controller + +pci:v000011ABd00005081* + ID_MODEL_FROM_DATABASE=MV88SX5081 8-port SATA I PCI-X Controller + +pci:v000011ABd00005181* + ID_MODEL_FROM_DATABASE=88f5181 [Orion-1] ARM SoC + +pci:v000011ABd00005182* + ID_MODEL_FROM_DATABASE=88f5182 [Orion-NAS] ARM SoC + +pci:v000011ABd00005281* + ID_MODEL_FROM_DATABASE=88f5281 [Orion-2] ARM SoC + +pci:v000011ABd00006041* + ID_MODEL_FROM_DATABASE=MV88SX6041 4-port SATA II PCI-X Controller + +pci:v000011ABd00006042* + ID_MODEL_FROM_DATABASE=88SX6042 PCI-X 4-Port SATA-II + +pci:v000011ABd00006081* + ID_MODEL_FROM_DATABASE=MV88SX6081 8-port SATA II PCI-X Controller + +pci:v000011ABd00006101* + ID_MODEL_FROM_DATABASE=88SE6101/6102 single-port PATA133 interface + +pci:v000011ABd00006101sv00001043sd000082E0* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v000011ABd00006111* + ID_MODEL_FROM_DATABASE=88SE6111 1-port PATA133(IDE) and 1-port SATA II Controllers + +pci:v000011ABd00006121* + ID_MODEL_FROM_DATABASE=88SE6121 SATA II / PATA Controller + +pci:v000011ABd00006141* + ID_MODEL_FROM_DATABASE=88SE614x SATA II PCI-E controller + +pci:v000011ABd00006145* + ID_MODEL_FROM_DATABASE=88SE6145 SATA II PCI-E controller + +pci:v000011ABd00006180* + ID_MODEL_FROM_DATABASE=88F6180 [Kirkwood] ARM SoC + +pci:v000011ABd00006192* + ID_MODEL_FROM_DATABASE=88F6190/6192 [Kirkwood] ARM SoC + +pci:v000011ABd00006281* + ID_MODEL_FROM_DATABASE=88F6281 [Kirkwood] ARM SoC + +pci:v000011ABd00006381* + ID_MODEL_FROM_DATABASE=MV78xx0 [Discovery Innovation] ARM SoC + +pci:v000011ABd00006440* + ID_MODEL_FROM_DATABASE=88SE6440 SAS/SATA PCIe controller + +pci:v000011ABd00006450* + ID_MODEL_FROM_DATABASE=64560 System Controller + +pci:v000011ABd00006460* + ID_MODEL_FROM_DATABASE=MV64360/64361/64362 System Controller + +pci:v000011ABd00006480* + ID_MODEL_FROM_DATABASE=MV64460/64461/64462 System Controller + +pci:v000011ABd00006480sv00001775sd0000C200* + ID_MODEL_FROM_DATABASE=C2K CompactPCI single board computer + +pci:v000011ABd00006485* + ID_MODEL_FROM_DATABASE=MV64460/64461/64462 System Controller, Revision B + +pci:v000011ABd00007042* + ID_MODEL_FROM_DATABASE=88SX7042 PCI-e 4-port SATA-II + +pci:v000011ABd00007042sv000016B8sd0000434B* + ID_MODEL_FROM_DATABASE=Tempo SATA E4P + +pci:v000011ABd00007810* + ID_MODEL_FROM_DATABASE=MV78100 [Discovery Innovation] ARM SoC + +pci:v000011ABd00007820* + ID_MODEL_FROM_DATABASE=MV78200 [Discovery Innovation] ARM SoC + +pci:v000011ABd0000F003* + ID_MODEL_FROM_DATABASE=GT-64010 Primary Image Piranha Image Generator + +pci:v000011AC* + ID_VENDOR_FROM_DATABASE=Canon Information Systems Research Aust. + +pci:v000011AD* + ID_VENDOR_FROM_DATABASE=Lite-On Communications Inc + +pci:v000011ADd00000002* + ID_MODEL_FROM_DATABASE=LNE100TX + +pci:v000011ADd00000002sv000011ADsd00000002* + ID_MODEL_FROM_DATABASE=LNE100TX + +pci:v000011ADd00000002sv000011ADsd00000003* + ID_MODEL_FROM_DATABASE=LNE100TX + +pci:v000011ADd00000002sv000011ADsd0000F003* + ID_MODEL_FROM_DATABASE=LNE100TX + +pci:v000011ADd00000002sv000011ADsd0000FFFF* + ID_MODEL_FROM_DATABASE=LNE100TX + +pci:v000011ADd00000002sv00001385sd0000F004* + ID_MODEL_FROM_DATABASE=FA310TX + +pci:v000011ADd00000002sv00002646sd0000F002* + ID_MODEL_FROM_DATABASE=KNE110TX EtheRx Fast Ethernet + +pci:v000011ADd0000C115* + ID_MODEL_FROM_DATABASE=LNE100TX [Linksys EtherFast 10/100] + +pci:v000011ADd0000C115sv000011ADsd0000C001* + ID_MODEL_FROM_DATABASE=LNE100TX [ver 2.0] + +pci:v000011ADd0000C115sv00002646sd0000000B* + ID_MODEL_FROM_DATABASE=KNE111TX + +pci:v000011AE* + ID_VENDOR_FROM_DATABASE=Aztech System Ltd + +pci:v000011AF* + ID_VENDOR_FROM_DATABASE=Avid Technology Inc. + +pci:v000011AFd00000001* + ID_MODEL_FROM_DATABASE=Cinema + +pci:v000011AFd0000EE40* + ID_MODEL_FROM_DATABASE=Digidesign Audiomedia III + +pci:v000011B0* + ID_VENDOR_FROM_DATABASE=V3 Semiconductor Inc. + +pci:v000011B0d00000002* + ID_MODEL_FROM_DATABASE=V300PSC + +pci:v000011B0d00000292* + ID_MODEL_FROM_DATABASE=V292PBC [Am29030/40 Bridge] + +pci:v000011B0d00000960* + ID_MODEL_FROM_DATABASE=V96xPBC + +pci:v000011B0d0000C960* + ID_MODEL_FROM_DATABASE=V96DPC + +pci:v000011B1* + ID_VENDOR_FROM_DATABASE=Apricot Computers + +pci:v000011B2* + ID_VENDOR_FROM_DATABASE=Eastman Kodak + +pci:v000011B3* + ID_VENDOR_FROM_DATABASE=Barr Systems Inc. + +pci:v000011B4* + ID_VENDOR_FROM_DATABASE=Leitch Technology International + +pci:v000011B5* + ID_VENDOR_FROM_DATABASE=Radstone Technology Plc + +pci:v000011B6* + ID_VENDOR_FROM_DATABASE=United Video Corp + +pci:v000011B7* + ID_VENDOR_FROM_DATABASE=Motorola + +pci:v000011B8* + ID_VENDOR_FROM_DATABASE=XPoint Technologies, Inc + +pci:v000011B8d00000001* + ID_MODEL_FROM_DATABASE=Quad PeerMaster + +pci:v000011B9* + ID_VENDOR_FROM_DATABASE=Pathlight Technology Inc. + +pci:v000011B9d0000C0ED* + ID_MODEL_FROM_DATABASE=SSA Controller + +pci:v000011BA* + ID_VENDOR_FROM_DATABASE=Videotron Corp + +pci:v000011BB* + ID_VENDOR_FROM_DATABASE=Pyramid Technology + +pci:v000011BC* + ID_VENDOR_FROM_DATABASE=Network Peripherals Inc + +pci:v000011BCd00000001* + ID_MODEL_FROM_DATABASE=NP-PCI + +pci:v000011BD* + ID_VENDOR_FROM_DATABASE=Pinnacle Systems Inc. + +pci:v000011BDd0000002E* + ID_MODEL_FROM_DATABASE=PCTV 40i + +pci:v000011BDd00000040* + ID_MODEL_FROM_DATABASE=Royal TS Function 1 + +pci:v000011BDd00000040sv000011BDsd00000044* + ID_MODEL_FROM_DATABASE=PCTV 2000i Dual DVB-T Pro PCI Tuner 1 + +pci:v000011BDd00000040sv000011BDsd00000045* + ID_MODEL_FROM_DATABASE=PCTV Dual Sat Pro PCI 4000i Tuner 1 + +pci:v000011BDd00000041* + ID_MODEL_FROM_DATABASE=RoyalTS Function 2 + +pci:v000011BDd00000041sv000011BDsd00000044* + ID_MODEL_FROM_DATABASE=PCTV 2000i Dual DVB-T Pro PCI Tuner 2 + +pci:v000011BDd00000041sv000011BDsd00000045* + ID_MODEL_FROM_DATABASE=PCTV Dual Sat Pro PCI 4000i Tuner 2 + +pci:v000011BDd00000042* + ID_MODEL_FROM_DATABASE=Royal TS Function 3 + +pci:v000011BDd00000042sv000011BDsd00000044* + ID_MODEL_FROM_DATABASE=PCTV 2000i Dual DVB-T Pro PCI Common + +pci:v000011BDd00000042sv000011BDsd00000045* + ID_MODEL_FROM_DATABASE=PCTV Dual Sat Pro PCI 4000i Common + +pci:v000011BDd00000051* + ID_MODEL_FROM_DATABASE=PCTV HD 800i + +pci:v000011BDd0000BEDE* + ID_MODEL_FROM_DATABASE=AV/DV Studio Capture Card + +pci:v000011BE* + ID_VENDOR_FROM_DATABASE=International Microcircuits Inc + +pci:v000011BF* + ID_VENDOR_FROM_DATABASE=Astrodesign, Inc. + +pci:v000011C0* + ID_VENDOR_FROM_DATABASE=Hewlett Packard + +pci:v000011C1* + ID_VENDOR_FROM_DATABASE=LSI Corporation + +pci:v000011C1d00000440* + ID_MODEL_FROM_DATABASE=56k WinModem + +pci:v000011C1d00000440sv00001033sd00008015* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv00001033sd00008047* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv00001033sd0000804F* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000010CFsd0000102C* + ID_MODEL_FROM_DATABASE=LB LT Modem V.90 56k + +pci:v000011C1d00000440sv000010CFsd0000104A* + ID_MODEL_FROM_DATABASE=BIBLO LT Modem 56k + +pci:v000011C1d00000440sv000010CFsd0000105F* + ID_MODEL_FROM_DATABASE=LB2 LT Modem V.90 56k + +pci:v000011C1d00000440sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Internal V.90 Modem + +pci:v000011C1d00000440sv000011C1sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv0000122Dsd00004101* + ID_MODEL_FROM_DATABASE=MDP7800-U Modem + +pci:v000011C1d00000440sv0000122Dsd00004102* + ID_MODEL_FROM_DATABASE=MDP7800SP-U Modem + +pci:v000011C1d00000440sv000013E0sd00000040* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000013E0sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000013E0sd00000441* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000013E0sd00000450* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000013E0sd0000F100* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv000013E0sd0000F101* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000440sv0000144Dsd00002101* + ID_MODEL_FROM_DATABASE=LT56PV Modem + +pci:v000011C1d00000440sv0000149Fsd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000441* + ID_MODEL_FROM_DATABASE=56k WinModem + +pci:v000011C1d00000441sv00001033sd0000804D* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv00001033sd00008065* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv00001092sd00000440* + ID_MODEL_FROM_DATABASE=Supra 56i + +pci:v000011C1d00000441sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Internal V.90 Modem + +pci:v000011C1d00000441sv000011C1sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000011C1sd00000441* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv0000122Dsd00004100* + ID_MODEL_FROM_DATABASE=MDP7800-U Modem + +pci:v000011C1d00000441sv000013E0sd00000040* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000013E0sd00000100* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000013E0sd00000410* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000013E0sd00000420* + ID_MODEL_FROM_DATABASE=TelePath Internet 56k WinModem + +pci:v000011C1d00000441sv000013E0sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000013E0sd00000443* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv000013E0sd0000F102* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv00001416sd00009804* + ID_MODEL_FROM_DATABASE=CommWave 56k Modem + +pci:v000011C1d00000441sv0000141Dsd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000441sv0000144Fsd00000441* + ID_MODEL_FROM_DATABASE=Lucent 56k V.90 DF Modem + +pci:v000011C1d00000441sv0000144Fsd00000449* + ID_MODEL_FROM_DATABASE=Lucent 56k V.90 DF Modem + +pci:v000011C1d00000441sv0000144Fsd0000110D* + ID_MODEL_FROM_DATABASE=Lucent Win Modem + +pci:v000011C1d00000441sv00001468sd00000441* + ID_MODEL_FROM_DATABASE=Presario 56k V.90 DF Modem + +pci:v000011C1d00000441sv00001668sd00000440* + ID_MODEL_FROM_DATABASE=Lucent Win Modem + +pci:v000011C1d00000442* + ID_MODEL_FROM_DATABASE=56k WinModem + +pci:v000011C1d00000442sv000011C1sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv000011C1sd00000442* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv000013E0sd00000412* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv000013E0sd00000442* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv000013FCsd00002471* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv0000144Dsd00002104* + ID_MODEL_FROM_DATABASE=LT56PT Modem + +pci:v000011C1d00000442sv0000144Fsd00001104* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv0000149Fsd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000442sv00001668sd00000440* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d00000443* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000444* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000445* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000445sv00008086sd00002203* + ID_MODEL_FROM_DATABASE=PRO/100+ MiniPCI (probably an Ambit U98.003.C.00 combo card) + +pci:v000011C1d00000445sv00008086sd00002204* + ID_MODEL_FROM_DATABASE=PRO/100+ MiniPCI on Armada E500 + +pci:v000011C1d00000446* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000447* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000448* + ID_MODEL_FROM_DATABASE=WinModem 56k + +pci:v000011C1d00000448sv00001014sd00000131* + ID_MODEL_FROM_DATABASE=Lucent Win Modem + +pci:v000011C1d00000448sv00001033sd00008066* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000448sv000013E0sd00000030* + ID_MODEL_FROM_DATABASE=56k Voice Modem + +pci:v000011C1d00000448sv000013E0sd00000040* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+Dsvd + +pci:v000011C1d00000448sv00001668sd00002400* + ID_MODEL_FROM_DATABASE=LT WinModem 56k (MiniPCI Ethernet+Modem) + +pci:v000011C1d00000449* + ID_MODEL_FROM_DATABASE=L56xM+S [Mars-2] WinModem 56k + +pci:v000011C1d00000449sv00000E11sd0000B14D* + ID_MODEL_FROM_DATABASE=56k V.90 Modem + +pci:v000011C1d00000449sv00001014sd0000018C* + ID_MODEL_FROM_DATABASE=ThinkPad 600X + +pci:v000011C1d00000449sv000013E0sd00000020* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax + +pci:v000011C1d00000449sv000013E0sd00000041* + ID_MODEL_FROM_DATABASE=TelePath Internet 56k WinModem + +pci:v000011C1d00000449sv00001436sd00000440* + ID_MODEL_FROM_DATABASE=Lucent Win Modem + +pci:v000011C1d00000449sv0000144Fsd00000449* + ID_MODEL_FROM_DATABASE=Lucent 56k V.90 DFi Modem + +pci:v000011C1d00000449sv00001468sd00000410* + ID_MODEL_FROM_DATABASE=IBM ThinkPad T23 + +pci:v000011C1d00000449sv00001468sd00000440* + ID_MODEL_FROM_DATABASE=Lucent Win Modem + +pci:v000011C1d00000449sv00001468sd00000449* + ID_MODEL_FROM_DATABASE=Presario 56k V.90 DFi Modem + +pci:v000011C1d0000044A* + ID_MODEL_FROM_DATABASE=F-1156IV WinModem (V90, 56KFlex) + +pci:v000011C1d0000044Asv000010CFsd00001072* + ID_MODEL_FROM_DATABASE=LB Global LT Modem + +pci:v000011C1d0000044Asv000013E0sd00000012* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d0000044Asv000013E0sd00000042* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d0000044Asv0000144Fsd00001005* + ID_MODEL_FROM_DATABASE=LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd + +pci:v000011C1d0000044B* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000044C* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000044D* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000044E* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000044F* + ID_MODEL_FROM_DATABASE=V90 WildWire Modem + +pci:v000011C1d00000450* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000450sv00001033sd000080A8* + ID_MODEL_FROM_DATABASE=Versa Note Vxi + +pci:v000011C1d00000450sv0000144Fsd00004005* + ID_MODEL_FROM_DATABASE=Magnia SG20 + +pci:v000011C1d00000450sv00001468sd00000450* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v000011C1d00000451* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000452* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000453* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000454* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000455* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000456* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000457* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000458* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000459* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000045A* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d0000045C* + ID_MODEL_FROM_DATABASE=LT WinModem + +pci:v000011C1d00000461* + ID_MODEL_FROM_DATABASE=V90 WildWire Modem + +pci:v000011C1d00000462* + ID_MODEL_FROM_DATABASE=V90 WildWire Modem + +pci:v000011C1d00000480* + ID_MODEL_FROM_DATABASE=Venus Modem (V90, 56KFlex) + +pci:v000011C1d0000048C* + ID_MODEL_FROM_DATABASE=V.92 56K WinModem + +pci:v000011C1d0000048F* + ID_MODEL_FROM_DATABASE=V.92 56k WinModem + +pci:v000011C1d00000620* + ID_MODEL_FROM_DATABASE=Lucent V.92 Data/Fax Modem + +pci:v000011C1d00002600* + ID_MODEL_FROM_DATABASE=StarPro26XX family (SP2601, SP2603, SP2612) DSP + +pci:v000011C1d00005400* + ID_MODEL_FROM_DATABASE=OR3TP12 FPSC + +pci:v000011C1d00005656* + ID_MODEL_FROM_DATABASE=Venus Modem + +pci:v000011C1d00005801* + ID_MODEL_FROM_DATABASE=USB + +pci:v000011C1d00005802* + ID_MODEL_FROM_DATABASE=USS-312 USB Controller + +pci:v000011C1d00005803* + ID_MODEL_FROM_DATABASE=USS-344S USB Controller + +pci:v000011C1d00005811* + ID_MODEL_FROM_DATABASE=FW322/323 [TrueFire] 1394a Controller + +pci:v000011C1d00005811sv0000103Csd00002A34* + ID_MODEL_FROM_DATABASE=Pavilion a1677c + +pci:v000011C1d00005811sv0000103Csd00002A9E* + ID_MODEL_FROM_DATABASE=Pavilion p6310f + +pci:v000011C1d00005811sv00001043sd00008294* + ID_MODEL_FROM_DATABASE=LSI FW322/323 IEEE 1394a FireWire Controller + +pci:v000011C1d00005811sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v000011C1d00005811sv0000DEADsd00000800* + ID_MODEL_FROM_DATABASE=FireWire Host Bus Adapter + +pci:v000011C1d00005901* + ID_MODEL_FROM_DATABASE=FW643 [TrueFire] PCIe 1394b Controller + +pci:v000011C1d00005901sv000011C1sd00005900* + ID_MODEL_FROM_DATABASE=FW643 [TrueFire] PCIe 1394b Controller + +pci:v000011C1d00005901sv00001443sd00000643* + ID_MODEL_FROM_DATABASE=FireBoard800-e V.2 + +pci:v000011C1d00005901sv00001546sd00000643* + ID_MODEL_FROM_DATABASE=FWB-PCIE1X2x + +pci:v000011C1d00005903* + ID_MODEL_FROM_DATABASE=FW533 [TrueFire] PCIe 1394a Controller + +pci:v000011C1d00008110* + ID_MODEL_FROM_DATABASE=T8110 H.100/H.110 TDM switch + +pci:v000011C1d00008110sv000012D9sd0000000C* + ID_MODEL_FROM_DATABASE=E1/T1 PMXc cPCI carrier card + +pci:v000011C1d0000AB10* + ID_MODEL_FROM_DATABASE=WL60010 Wireless LAN MAC + +pci:v000011C1d0000AB11* + ID_MODEL_FROM_DATABASE=WL60040 Multimode Wireles LAN MAC + +pci:v000011C1d0000AB11sv000011C1sd0000AB12* + ID_MODEL_FROM_DATABASE=WaveLAN 11abg Cardbus card (Model 1102) + +pci:v000011C1d0000AB11sv000011C1sd0000AB13* + ID_MODEL_FROM_DATABASE=WaveLAN 11abg MiniPCI card (Model 0512) + +pci:v000011C1d0000AB11sv000011C1sd0000AB15* + ID_MODEL_FROM_DATABASE=WaveLAN 11abg Cardbus card (Model 1106) + +pci:v000011C1d0000AB11sv000011C1sd0000AB16* + ID_MODEL_FROM_DATABASE=WaveLAN 11abg MiniPCI card (Model 0516) + +pci:v000011C1d0000AB20* + ID_MODEL_FROM_DATABASE=ORiNOCO PCI Adapter + +pci:v000011C1d0000AB21* + ID_MODEL_FROM_DATABASE=Agere Wireless PCI Adapter + +pci:v000011C1d0000AB30* + ID_MODEL_FROM_DATABASE=Hermes2 Mini-PCI WaveLAN a/b/g + +pci:v000011C1d0000AB30sv000014CDsd00002012* + ID_MODEL_FROM_DATABASE=Hermes2 Mini-PCI WaveLAN a/b/g + +pci:v000011C1d0000ED00* + ID_MODEL_FROM_DATABASE=ET-131x PCI-E Ethernet Controller + +pci:v000011C1d0000ED01* + ID_MODEL_FROM_DATABASE=ET-131x PCI-E Ethernet Controller + +pci:v000011C2* + ID_VENDOR_FROM_DATABASE=Sand Microelectronics + +pci:v000011C3* + ID_VENDOR_FROM_DATABASE=NEC Corporation + +pci:v000011C4* + ID_VENDOR_FROM_DATABASE=Document Technologies, Inc + +pci:v000011C5* + ID_VENDOR_FROM_DATABASE=Shiva Corporation + +pci:v000011C6* + ID_VENDOR_FROM_DATABASE=Dainippon Screen Mfg. Co. Ltd + +pci:v000011C7* + ID_VENDOR_FROM_DATABASE=D.C.M. Data Systems + +pci:v000011C8* + ID_VENDOR_FROM_DATABASE=Dolphin Interconnect Solutions AS + +pci:v000011C8d00000658* + ID_MODEL_FROM_DATABASE=PSB32 SCI-Adapter D31x + +pci:v000011C8d0000D665* + ID_MODEL_FROM_DATABASE=PSB64 SCI-Adapter D32x + +pci:v000011C8d0000D667* + ID_MODEL_FROM_DATABASE=PSB66 SCI-Adapter D33x + +pci:v000011C9* + ID_VENDOR_FROM_DATABASE=Magma + +pci:v000011C9d00000010* + ID_MODEL_FROM_DATABASE=16-line serial port w/- DMA + +pci:v000011C9d00000011* + ID_MODEL_FROM_DATABASE=4-line serial port w/- DMA + +pci:v000011CA* + ID_VENDOR_FROM_DATABASE=LSI Systems, Inc + +pci:v000011CB* + ID_VENDOR_FROM_DATABASE=Specialix Research Ltd. + +pci:v000011CBd00002000* + ID_MODEL_FROM_DATABASE=PCI_9050 + +pci:v000011CBd00002000sv000011CBsd00000200* + ID_MODEL_FROM_DATABASE=SX + +pci:v000011CBd00002000sv000011CBsd0000B008* + ID_MODEL_FROM_DATABASE=I/O8+ + +pci:v000011CBd00004000* + ID_MODEL_FROM_DATABASE=SUPI_1 + +pci:v000011CBd00008000* + ID_MODEL_FROM_DATABASE=T225 + +pci:v000011CC* + ID_VENDOR_FROM_DATABASE=Michels & Kleberhoff Computer GmbH + +pci:v000011CD* + ID_VENDOR_FROM_DATABASE=HAL Computer Systems, Inc. + +pci:v000011CE* + ID_VENDOR_FROM_DATABASE=Netaccess + +pci:v000011CF* + ID_VENDOR_FROM_DATABASE=Pioneer Electronic Corporation + +pci:v000011D0* + ID_VENDOR_FROM_DATABASE=Lockheed Martin Federal Systems-Manassas + +pci:v000011D1* + ID_VENDOR_FROM_DATABASE=Auravision + +pci:v000011D1d000001F7* + ID_MODEL_FROM_DATABASE=VxP524 + +pci:v000011D1d000001F9* + ID_MODEL_FROM_DATABASE=VxP951 + +pci:v000011D2* + ID_VENDOR_FROM_DATABASE=Intercom Inc. + +pci:v000011D3* + ID_VENDOR_FROM_DATABASE=Trancell Systems Inc + +pci:v000011D4* + ID_VENDOR_FROM_DATABASE=Analog Devices + +pci:v000011D4d00001535* + ID_MODEL_FROM_DATABASE=Blackfin BF535 processor + +pci:v000011D4d00001805* + ID_MODEL_FROM_DATABASE=SM56 PCI modem + +pci:v000011D5* + ID_VENDOR_FROM_DATABASE=Ikon Corporation + +pci:v000011D5d00000115* + ID_MODEL_FROM_DATABASE=10115 + +pci:v000011D5d00000117* + ID_MODEL_FROM_DATABASE=10117 + +pci:v000011D6* + ID_VENDOR_FROM_DATABASE=Tekelec Telecom + +pci:v000011D7* + ID_VENDOR_FROM_DATABASE=Trenton Technology, Inc. + +pci:v000011D8* + ID_VENDOR_FROM_DATABASE=Image Technologies Development + +pci:v000011D9* + ID_VENDOR_FROM_DATABASE=TEC Corporation + +pci:v000011DA* + ID_VENDOR_FROM_DATABASE=Novell + +pci:v000011DB* + ID_VENDOR_FROM_DATABASE=Sega Enterprises Ltd + +pci:v000011DC* + ID_VENDOR_FROM_DATABASE=Questra Corporation + +pci:v000011DD* + ID_VENDOR_FROM_DATABASE=Crosfield Electronics Limited + +pci:v000011DE* + ID_VENDOR_FROM_DATABASE=Zoran Corporation + +pci:v000011DEd00006017* + ID_MODEL_FROM_DATABASE=miroVIDEO DC30 + +pci:v000011DEd00006057* + ID_MODEL_FROM_DATABASE=ZR36057PQC Video cutting chipset + +pci:v000011DEd00006057sv00001031sd00007EFE* + ID_MODEL_FROM_DATABASE=DC10 Plus + +pci:v000011DEd00006057sv00001031sd0000FC00* + ID_MODEL_FROM_DATABASE=MiroVIDEO DC50, Motion JPEG Capture/CODEC Board + +pci:v000011DEd00006057sv000012F8sd00008A02* + ID_MODEL_FROM_DATABASE=Tekram Video Kit + +pci:v000011DEd00006057sv000013CAsd00004231* + ID_MODEL_FROM_DATABASE=JPEG/TV Card + +pci:v000011DEd00006120* + ID_MODEL_FROM_DATABASE=ZR36120 + +pci:v000011DEd00006120sv00001328sd0000F001* + ID_MODEL_FROM_DATABASE=Cinemaster C DVD Decoder + +pci:v000011DEd00006120sv000013C2sd00000000* + ID_MODEL_FROM_DATABASE=MediaFocus Satellite TV Card + +pci:v000011DEd00006120sv00001DE1sd00009FFF* + ID_MODEL_FROM_DATABASE=Video Kit C210 + +pci:v000011DF* + ID_VENDOR_FROM_DATABASE=New Wave PDG + +pci:v000011E0* + ID_VENDOR_FROM_DATABASE=Cray Communications A/S + +pci:v000011E1* + ID_VENDOR_FROM_DATABASE=GEC Plessey Semi Inc. + +pci:v000011E2* + ID_VENDOR_FROM_DATABASE=Samsung Information Systems America + +pci:v000011E3* + ID_VENDOR_FROM_DATABASE=Quicklogic Corporation + +pci:v000011E3d00000001* + ID_MODEL_FROM_DATABASE=COM-ON-AIR Dosch&Amand DECT + +pci:v000011E3d00000560* + ID_MODEL_FROM_DATABASE=QL5064 Companion Design Demo Board + +pci:v000011E3d00005030* + ID_MODEL_FROM_DATABASE=PC Watchdog + +pci:v000011E3d00008417* + ID_MODEL_FROM_DATABASE=QL5064 [QuickPCI] PCI v2.2 bridge for SMT417 Dual TMS320C6416T PMC Module + +pci:v000011E4* + ID_VENDOR_FROM_DATABASE=Second Wave Inc + +pci:v000011E5* + ID_VENDOR_FROM_DATABASE=IIX Consulting + +pci:v000011E6* + ID_VENDOR_FROM_DATABASE=Mitsui-Zosen System Research + +pci:v000011E7* + ID_VENDOR_FROM_DATABASE=Toshiba America, Elec. Company + +pci:v000011E8* + ID_VENDOR_FROM_DATABASE=Digital Processing Systems Inc. + +pci:v000011E9* + ID_VENDOR_FROM_DATABASE=Highwater Designs Ltd. + +pci:v000011EA* + ID_VENDOR_FROM_DATABASE=Elsag Bailey + +pci:v000011EB* + ID_VENDOR_FROM_DATABASE=Formation Inc. + +pci:v000011EC* + ID_VENDOR_FROM_DATABASE=Coreco Inc + +pci:v000011ECd0000000D* + ID_MODEL_FROM_DATABASE=Oculus-F/64P + +pci:v000011ECd00001800* + ID_MODEL_FROM_DATABASE=Cobra/C6 + +pci:v000011ED* + ID_VENDOR_FROM_DATABASE=Mediamatics + +pci:v000011EE* + ID_VENDOR_FROM_DATABASE=Dome Imaging Systems Inc + +pci:v000011EF* + ID_VENDOR_FROM_DATABASE=Nicolet Technologies B.V. + +pci:v000011F0* + ID_VENDOR_FROM_DATABASE=Compu-Shack + +pci:v000011F0d00004231* + ID_MODEL_FROM_DATABASE=FDDI + +pci:v000011F0d00004232* + ID_MODEL_FROM_DATABASE=FASTline UTP Quattro + +pci:v000011F0d00004233* + ID_MODEL_FROM_DATABASE=FASTline FO + +pci:v000011F0d00004234* + ID_MODEL_FROM_DATABASE=FASTline UTP + +pci:v000011F0d00004235* + ID_MODEL_FROM_DATABASE=FASTline-II UTP + +pci:v000011F0d00004236* + ID_MODEL_FROM_DATABASE=FASTline-II FO + +pci:v000011F0d00004731* + ID_MODEL_FROM_DATABASE=GIGAline + +pci:v000011F1* + ID_VENDOR_FROM_DATABASE=Symbios Logic Inc + +pci:v000011F2* + ID_VENDOR_FROM_DATABASE=Picture Tel Japan K.K. + +pci:v000011F3* + ID_VENDOR_FROM_DATABASE=Keithley Metrabyte + +pci:v000011F3d00000011* + ID_MODEL_FROM_DATABASE=KPCI-PIO24 + +pci:v000011F4* + ID_VENDOR_FROM_DATABASE=Kinetic Systems Corporation + +pci:v000011F4d00002915* + ID_MODEL_FROM_DATABASE=CAMAC controller + +pci:v000011F5* + ID_VENDOR_FROM_DATABASE=Computing Devices International + +pci:v000011F6* + ID_VENDOR_FROM_DATABASE=Compex + +pci:v000011F6d00000112* + ID_MODEL_FROM_DATABASE=ENet100VG4 + +pci:v000011F6d00000113* + ID_MODEL_FROM_DATABASE=FreedomLine 100 + +pci:v000011F6d00001401* + ID_MODEL_FROM_DATABASE=ReadyLink 2000 + +pci:v000011F6d00002011* + ID_MODEL_FROM_DATABASE=RL100-ATX 10/100 + +pci:v000011F6d00002011sv000011F6sd00002011* + ID_MODEL_FROM_DATABASE=RL100-ATX + +pci:v000011F6d00002201* + ID_MODEL_FROM_DATABASE=ReadyLink 100TX (Winbond W89C840) + +pci:v000011F6d00002201sv000011F6sd00002011* + ID_MODEL_FROM_DATABASE=ReadyLink 100TX + +pci:v000011F6d00009881* + ID_MODEL_FROM_DATABASE=RL100TX Fast Ethernet + +pci:v000011F7* + ID_VENDOR_FROM_DATABASE=Scientific Atlanta + +pci:v000011F8* + ID_VENDOR_FROM_DATABASE=PMC-Sierra Inc. + +pci:v000011F8d00005220* + ID_MODEL_FROM_DATABASE=BR522x [PMC-Sierra maxRAID SAS Controller] + +pci:v000011F8d00007364* + ID_MODEL_FROM_DATABASE=PM7364 [FREEDM - 32 Frame Engine & Datalink Mgr] + +pci:v000011F8d00007375* + ID_MODEL_FROM_DATABASE=PM7375 [LASAR-155 ATM SAR] + +pci:v000011F8d00007384* + ID_MODEL_FROM_DATABASE=PM7384 [FREEDM - 84P672 Frm Engine & Datalink Mgr] + +pci:v000011F8d00008000* + ID_MODEL_FROM_DATABASE=PM8000 [SPC - SAS Protocol Controller] + +pci:v000011F8d00008032* + ID_MODEL_FROM_DATABASE=ATTO Celerity FC8xEN + +pci:v000011F8d00008032sv0000117Csd0000003B* + ID_MODEL_FROM_DATABASE=Celerity FC-82EN Fibre Channel Adapter + +pci:v000011F8d00008032sv0000117Csd0000003C* + ID_MODEL_FROM_DATABASE=Celerity FC-84EN Fibre Channel Adapter + +pci:v000011F9* + ID_VENDOR_FROM_DATABASE=I-Cube Inc + +pci:v000011FA* + ID_VENDOR_FROM_DATABASE=Kasan Electronics Company, Ltd. + +pci:v000011FB* + ID_VENDOR_FROM_DATABASE=Datel Inc + +pci:v000011FC* + ID_VENDOR_FROM_DATABASE=Silicon Magic + +pci:v000011FD* + ID_VENDOR_FROM_DATABASE=High Street Consultants + +pci:v000011FE* + ID_VENDOR_FROM_DATABASE=Comtrol Corporation + +pci:v000011FEd00000001* + ID_MODEL_FROM_DATABASE=RocketPort 32 port w/external I/F + +pci:v000011FEd00000002* + ID_MODEL_FROM_DATABASE=RocketPort 8 port w/external I/F + +pci:v000011FEd00000003* + ID_MODEL_FROM_DATABASE=RocketPort 16 port w/external I/F + +pci:v000011FEd00000004* + ID_MODEL_FROM_DATABASE=RocketPort 4 port w/quad cable + +pci:v000011FEd00000005* + ID_MODEL_FROM_DATABASE=RocketPort 8 port w/octa cable + +pci:v000011FEd00000006* + ID_MODEL_FROM_DATABASE=RocketPort 8 port w/RJ11 connectors + +pci:v000011FEd00000007* + ID_MODEL_FROM_DATABASE=RocketPort 4 port w/RJ11 connectors + +pci:v000011FEd00000008* + ID_MODEL_FROM_DATABASE=RocketPort 8 port w/ DB78 SNI (Siemens) connector + +pci:v000011FEd00000009* + ID_MODEL_FROM_DATABASE=RocketPort 16 port w/ DB78 SNI (Siemens) connector + +pci:v000011FEd0000000A* + ID_MODEL_FROM_DATABASE=RocketPort Plus 4 port + +pci:v000011FEd0000000B* + ID_MODEL_FROM_DATABASE=RocketPort Plus 8 port + +pci:v000011FEd0000000C* + ID_MODEL_FROM_DATABASE=RocketModem 6 port + +pci:v000011FEd0000000D* + ID_MODEL_FROM_DATABASE=RocketModem 4-port + +pci:v000011FEd0000000E* + ID_MODEL_FROM_DATABASE=RocketPort Plus 2 port RS232 + +pci:v000011FEd0000000F* + ID_MODEL_FROM_DATABASE=RocketPort Plus 2 port RS422 + +pci:v000011FEd00000040* + ID_MODEL_FROM_DATABASE=RocketPort Infinity Octa, 8port, RJ45 + +pci:v000011FEd00000041* + ID_MODEL_FROM_DATABASE=RocketPort Infinity 32port, External Interface + +pci:v000011FEd00000042* + ID_MODEL_FROM_DATABASE=RocketPort Infinity 8port, External Interface + +pci:v000011FEd00000043* + ID_MODEL_FROM_DATABASE=RocketPort Infinity 16port, External Interface + +pci:v000011FEd00000044* + ID_MODEL_FROM_DATABASE=RocketPort Infinity Quad, 4port, DB + +pci:v000011FEd00000045* + ID_MODEL_FROM_DATABASE=RocketPort Infinity Octa, 8port, DB + +pci:v000011FEd00000047* + ID_MODEL_FROM_DATABASE=RocketPort Infinity 4port, RJ45 + +pci:v000011FEd0000004F* + ID_MODEL_FROM_DATABASE=RocketPort Infinity 2port, SMPTE + +pci:v000011FEd00000052* + ID_MODEL_FROM_DATABASE=RocketPort Infinity Octa, 8port, SMPTE + +pci:v000011FEd00000801* + ID_MODEL_FROM_DATABASE=RocketPort UPCI 32 port w/external I/F + +pci:v000011FEd00000802* + ID_MODEL_FROM_DATABASE=RocketPort UPCI 8 port w/external I/F + +pci:v000011FEd00000803* + ID_MODEL_FROM_DATABASE=RocketPort UPCI 16 port w/external I/F + +pci:v000011FEd00000805* + ID_MODEL_FROM_DATABASE=RocketPort UPCI 8 port w/octa cable + +pci:v000011FEd0000080C* + ID_MODEL_FROM_DATABASE=RocketModem III 8 port + +pci:v000011FEd0000080D* + ID_MODEL_FROM_DATABASE=RocketModem III 4 port + +pci:v000011FEd00000810* + ID_MODEL_FROM_DATABASE=RocketPort UPCI Plus 4 port RS232 + +pci:v000011FEd00000811* + ID_MODEL_FROM_DATABASE=RocketPort UPCI Plus 8 port RS232 + +pci:v000011FEd00000812* + ID_MODEL_FROM_DATABASE=RocketPort UPCI Plus 8 port RS422 + +pci:v000011FEd00000903* + ID_MODEL_FROM_DATABASE=RocketPort Compact PCI 16 port w/external I/F + +pci:v000011FEd00008015* + ID_MODEL_FROM_DATABASE=RocketPort 4-port UART 16954 + +pci:v000011FF* + ID_VENDOR_FROM_DATABASE=Scion Corporation + +pci:v000011FFd00000003* + ID_MODEL_FROM_DATABASE=AG-5 + +pci:v00001200* + ID_VENDOR_FROM_DATABASE=CSS Corporation + +pci:v00001201* + ID_VENDOR_FROM_DATABASE=Vista Controls Corp + +pci:v00001202* + ID_VENDOR_FROM_DATABASE=Network General Corp. + +pci:v00001202d00004300* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet Adapter + +pci:v00001202d00004300sv00001202sd00009841* + ID_MODEL_FROM_DATABASE=SK-9841 LX + +pci:v00001202d00004300sv00001202sd00009842* + ID_MODEL_FROM_DATABASE=SK-9841 LX dual link + +pci:v00001202d00004300sv00001202sd00009843* + ID_MODEL_FROM_DATABASE=SK-9843 SX + +pci:v00001202d00004300sv00001202sd00009844* + ID_MODEL_FROM_DATABASE=SK-9843 SX dual link + +pci:v00001203* + ID_VENDOR_FROM_DATABASE=Bayer Corporation, Agfa Division + +pci:v00001204* + ID_VENDOR_FROM_DATABASE=Lattice Semiconductor Corporation + +pci:v00001205* + ID_VENDOR_FROM_DATABASE=Array Corporation + +pci:v00001206* + ID_VENDOR_FROM_DATABASE=Amdahl Corporation + +pci:v00001208* + ID_VENDOR_FROM_DATABASE=Parsytec GmbH + +pci:v00001208d00004853* + ID_MODEL_FROM_DATABASE=HS-Link Device + +pci:v00001209* + ID_VENDOR_FROM_DATABASE=SCI Systems Inc + +pci:v0000120A* + ID_VENDOR_FROM_DATABASE=Synaptel + +pci:v0000120B* + ID_VENDOR_FROM_DATABASE=Adaptive Solutions + +pci:v0000120C* + ID_VENDOR_FROM_DATABASE=Technical Corp. + +pci:v0000120D* + ID_VENDOR_FROM_DATABASE=Compression Labs, Inc. + +pci:v0000120E* + ID_VENDOR_FROM_DATABASE=Cyclades Corporation + +pci:v0000120Ed00000100* + ID_MODEL_FROM_DATABASE=Cyclom-Y below first megabyte + +pci:v0000120Ed00000101* + ID_MODEL_FROM_DATABASE=Cyclom-Y above first megabyte + +pci:v0000120Ed00000102* + ID_MODEL_FROM_DATABASE=Cyclom-4Y below first megabyte + +pci:v0000120Ed00000103* + ID_MODEL_FROM_DATABASE=Cyclom-4Y above first megabyte + +pci:v0000120Ed00000104* + ID_MODEL_FROM_DATABASE=Cyclom-8Y below first megabyte + +pci:v0000120Ed00000105* + ID_MODEL_FROM_DATABASE=Cyclom-8Y above first megabyte + +pci:v0000120Ed00000200* + ID_MODEL_FROM_DATABASE=Cyclades-Z below first megabyte + +pci:v0000120Ed00000201* + ID_MODEL_FROM_DATABASE=Cyclades-Z above first megabyte + +pci:v0000120Ed00000300* + ID_MODEL_FROM_DATABASE=PC300/RSV or /X21 (2 ports) + +pci:v0000120Ed00000301* + ID_MODEL_FROM_DATABASE=PC300/RSV or /X21 (1 port) + +pci:v0000120Ed00000310* + ID_MODEL_FROM_DATABASE=PC300/TE (2 ports) + +pci:v0000120Ed00000311* + ID_MODEL_FROM_DATABASE=PC300/TE (1 port) + +pci:v0000120Ed00000320* + ID_MODEL_FROM_DATABASE=PC300/TE-M (2 ports) + +pci:v0000120Ed00000321* + ID_MODEL_FROM_DATABASE=PC300/TE-M (1 port) + +pci:v0000120Ed00000400* + ID_MODEL_FROM_DATABASE=PC400 + +pci:v0000120F* + ID_VENDOR_FROM_DATABASE=Essential Communications + +pci:v0000120Fd00000001* + ID_MODEL_FROM_DATABASE=Roadrunner serial HIPPI + +pci:v00001210* + ID_VENDOR_FROM_DATABASE=Hyperparallel Technologies + +pci:v00001211* + ID_VENDOR_FROM_DATABASE=Braintech Inc + +pci:v00001212* + ID_VENDOR_FROM_DATABASE=Kingston Technology Corp. + +pci:v00001213* + ID_VENDOR_FROM_DATABASE=Applied Intelligent Systems, Inc. + +pci:v00001214* + ID_VENDOR_FROM_DATABASE=Performance Technologies, Inc. + +pci:v00001215* + ID_VENDOR_FROM_DATABASE=Interware Co., Ltd + +pci:v00001216* + ID_VENDOR_FROM_DATABASE=Purup Prepress A/S + +pci:v00001217* + ID_VENDOR_FROM_DATABASE=O2 Micro, Inc. + +pci:v00001217d000000F7* + ID_MODEL_FROM_DATABASE=Firewire (IEEE 1394) + +pci:v00001217d000000F7sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001217d000010F7* + ID_MODEL_FROM_DATABASE=1394 OHCI Compliant Host Controller + +pci:v00001217d000011F7* + ID_MODEL_FROM_DATABASE=OZ600 1394a-2000 Controller + +pci:v00001217d000011F7sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001217d000013F7* + ID_MODEL_FROM_DATABASE=1394 OHCI Compliant Host Controller + +pci:v00001217d00006729* + ID_MODEL_FROM_DATABASE=OZ6729 + +pci:v00001217d0000673A* + ID_MODEL_FROM_DATABASE=OZ6730 + +pci:v00001217d00006832* + ID_MODEL_FROM_DATABASE=OZ6832/6833 CardBus Controller + +pci:v00001217d00006836* + ID_MODEL_FROM_DATABASE=OZ6836/6860 CardBus Controller + +pci:v00001217d00006872* + ID_MODEL_FROM_DATABASE=OZ6812 CardBus Controller + +pci:v00001217d00006925* + ID_MODEL_FROM_DATABASE=OZ6922 CardBus Controller + +pci:v00001217d00006933* + ID_MODEL_FROM_DATABASE=OZ6933/711E1 CardBus/SmartCardBus Controller + +pci:v00001217d00006933sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00001217d00006972* + ID_MODEL_FROM_DATABASE=OZ601/6912/711E0 CardBus/SmartCardBus Controller + +pci:v00001217d00006972sv00001014sd0000020C* + ID_MODEL_FROM_DATABASE=ThinkPad R30 + +pci:v00001217d00006972sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00001217d00006972sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00001217d00007110* + ID_MODEL_FROM_DATABASE=OZ711Mx 4-in-1 MemoryCardBus Accelerator + +pci:v00001217d00007110sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00001217d00007110sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00001217d00007110sv00001734sd0000106C* + ID_MODEL_FROM_DATABASE=Amilo A1645 + +pci:v00001217d00007112* + ID_MODEL_FROM_DATABASE=OZ711EC1/M1 SmartCardBus/MemoryCardBus Controller + +pci:v00001217d00007113* + ID_MODEL_FROM_DATABASE=OZ711EC1 SmartCardBus Controller + +pci:v00001217d00007113sv00001025sd00000035* + ID_MODEL_FROM_DATABASE=TravelMate 660 + +pci:v00001217d00007114* + ID_MODEL_FROM_DATABASE=OZ711M1/MC1 4-in-1 MemoryCardBus Controller + +pci:v00001217d00007120* + ID_MODEL_FROM_DATABASE=Integrated MMC/SD Controller + +pci:v00001217d00007120sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001217d00007130* + ID_MODEL_FROM_DATABASE=Integrated MS/xD Controller + +pci:v00001217d00007130sv00001179sd0000FF50* + ID_MODEL_FROM_DATABASE=Satellite P305D-S8995E + +pci:v00001217d00007134* + ID_MODEL_FROM_DATABASE=OZ711MP1/MS1 MemoryCardBus Controller + +pci:v00001217d00007135* + ID_MODEL_FROM_DATABASE=Cardbus bridge + +pci:v00001217d00007136* + ID_MODEL_FROM_DATABASE=OZ711SP1 Memory CardBus Controller + +pci:v00001217d000071E2* + ID_MODEL_FROM_DATABASE=OZ711E2 SmartCardBus Controller + +pci:v00001217d00007212* + ID_MODEL_FROM_DATABASE=OZ711M2 4-in-1 MemoryCardBus Controller + +pci:v00001217d00007213* + ID_MODEL_FROM_DATABASE=OZ6933E CardBus Controller + +pci:v00001217d00007223* + ID_MODEL_FROM_DATABASE=OZ711M3/MC3 4-in-1 MemoryCardBus Controller + +pci:v00001217d00007223sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00001217d00007223sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00001217d00007223sv000010CFsd000011C4* + ID_MODEL_FROM_DATABASE=Lifebook P5020D Laptop + +pci:v00001217d00007233* + ID_MODEL_FROM_DATABASE=OZ711MP3/MS3 4-in-1 MemoryCardBus Controller + +pci:v00001217d00008120* + ID_MODEL_FROM_DATABASE=Integrated MMC/SD Controller + +pci:v00001217d00008130* + ID_MODEL_FROM_DATABASE=Integrated MS/MSPRO/xD Controller + +pci:v00001217d00008320* + ID_MODEL_FROM_DATABASE=OZ600 MMC/SD Controller + +pci:v00001217d00008320sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001217d00008321* + ID_MODEL_FROM_DATABASE=Integrated MMC/SD controller + +pci:v00001217d00008330* + ID_MODEL_FROM_DATABASE=OZ600 MS/xD Controller + +pci:v00001217d00008330sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00001217d00008331* + ID_MODEL_FROM_DATABASE=O2 Flash Memory Card + +pci:v00001218* + ID_VENDOR_FROM_DATABASE=Hybricon Corp. + +pci:v00001219* + ID_VENDOR_FROM_DATABASE=First Virtual Corporation + +pci:v0000121A* + ID_VENDOR_FROM_DATABASE=3Dfx Interactive, Inc. + +pci:v0000121Ad00000001* + ID_MODEL_FROM_DATABASE=Voodoo + +pci:v0000121Ad00000002* + ID_MODEL_FROM_DATABASE=Voodoo 2 + +pci:v0000121Ad00000003* + ID_MODEL_FROM_DATABASE=Voodoo Banshee + +pci:v0000121Ad00000003sv00001092sd00000003* + ID_MODEL_FROM_DATABASE=Monster Fusion + +pci:v0000121Ad00000003sv00001092sd00004000* + ID_MODEL_FROM_DATABASE=Monster Fusion + +pci:v0000121Ad00000003sv00001092sd00004002* + ID_MODEL_FROM_DATABASE=Monster Fusion + +pci:v0000121Ad00000003sv00001092sd00004801* + ID_MODEL_FROM_DATABASE=Monster Fusion AGP + +pci:v0000121Ad00000003sv00001092sd00004803* + ID_MODEL_FROM_DATABASE=Monster Fusion AGP + +pci:v0000121Ad00000003sv00001092sd00008030* + ID_MODEL_FROM_DATABASE=Monster Fusion + +pci:v0000121Ad00000003sv00001092sd00008035* + ID_MODEL_FROM_DATABASE=Monster Fusion AGP + +pci:v0000121Ad00000003sv000010B0sd00000001* + ID_MODEL_FROM_DATABASE=Dragon 4000 + +pci:v0000121Ad00000003sv00001102sd00001017* + ID_MODEL_FROM_DATABASE=3D Blaster Banshee PCI (CT6760) + +pci:v0000121Ad00000003sv00001102sd00001018* + ID_MODEL_FROM_DATABASE=3D Blaster Banshee VE + +pci:v0000121Ad00000003sv0000121Asd00000001* + ID_MODEL_FROM_DATABASE=Voodoo Banshee AGP + +pci:v0000121Ad00000003sv0000121Asd00000003* + ID_MODEL_FROM_DATABASE=Voodoo Banshee AGP SGRAM + +pci:v0000121Ad00000003sv0000121Asd00000004* + ID_MODEL_FROM_DATABASE=Voodoo Banshee + +pci:v0000121Ad00000003sv0000139Csd00000016* + ID_MODEL_FROM_DATABASE=Raven + +pci:v0000121Ad00000003sv0000139Csd00000017* + ID_MODEL_FROM_DATABASE=Raven + +pci:v0000121Ad00000003sv000014AFsd00000002* + ID_MODEL_FROM_DATABASE=Maxi Gamer Phoenix + +pci:v0000121Ad00000004* + ID_MODEL_FROM_DATABASE=Voodoo Banshee [Velocity 100] + +pci:v0000121Ad00000005* + ID_MODEL_FROM_DATABASE=Voodoo 3 + +pci:v0000121Ad00000005sv0000121Asd00000004* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000030* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000031* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000034* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000036* + ID_MODEL_FROM_DATABASE=Voodoo3 2000 PCI + +pci:v0000121Ad00000005sv0000121Asd00000037* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000038* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd0000003A* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000044* + ID_MODEL_FROM_DATABASE=Voodoo3 + +pci:v0000121Ad00000005sv0000121Asd0000004B* + ID_MODEL_FROM_DATABASE=Velocity 100 + +pci:v0000121Ad00000005sv0000121Asd0000004C* + ID_MODEL_FROM_DATABASE=Velocity 200 + +pci:v0000121Ad00000005sv0000121Asd0000004D* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd0000004E* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000051* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000052* + ID_MODEL_FROM_DATABASE=Voodoo3 AGP + +pci:v0000121Ad00000005sv0000121Asd00000057* + ID_MODEL_FROM_DATABASE=Voodoo3 3000 PCI + +pci:v0000121Ad00000005sv0000121Asd00000060* + ID_MODEL_FROM_DATABASE=Voodoo3 3500 TV (NTSC) + +pci:v0000121Ad00000005sv0000121Asd00000061* + ID_MODEL_FROM_DATABASE=Voodoo3 3500 TV (PAL) + +pci:v0000121Ad00000005sv0000121Asd00000062* + ID_MODEL_FROM_DATABASE=Voodoo3 3500 TV (SECAM) + +pci:v0000121Ad00000009* + ID_MODEL_FROM_DATABASE=Voodoo 4 / Voodoo 5 + +pci:v0000121Ad00000009sv0000121Asd00000003* + ID_MODEL_FROM_DATABASE=Voodoo5 PCI 5500 + +pci:v0000121Ad00000009sv0000121Asd00000009* + ID_MODEL_FROM_DATABASE=Voodoo5 AGP 5500/6000 + +pci:v0000121Ad00000057* + ID_MODEL_FROM_DATABASE=Voodoo 3/3000 [Avenger] + +pci:v0000121B* + ID_VENDOR_FROM_DATABASE=Advanced Telecommunications Modules + +pci:v0000121C* + ID_VENDOR_FROM_DATABASE=Nippon Texaco., Ltd + +pci:v0000121D* + ID_VENDOR_FROM_DATABASE=LiPPERT ADLINK Technology GmbH + +pci:v0000121E* + ID_VENDOR_FROM_DATABASE=CSPI + +pci:v0000121Ed00000201* + ID_MODEL_FROM_DATABASE=Myrinet 2000 Scalable Cluster Interconnect + +pci:v0000121F* + ID_VENDOR_FROM_DATABASE=Arcus Technology, Inc. + +pci:v00001220* + ID_VENDOR_FROM_DATABASE=Ariel Corporation + +pci:v00001220d00001220* + ID_MODEL_FROM_DATABASE=AMCC 5933 TMS320C80 DSP/Imaging board + +pci:v00001221* + ID_VENDOR_FROM_DATABASE=Contec Co., Ltd + +pci:v00001221d00009172* + ID_MODEL_FROM_DATABASE=PO-64L(PCI)H [Isolated Digital Output Board for PCI] + +pci:v00001221d000091A2* + ID_MODEL_FROM_DATABASE=PO-32L(PCI)H [Isolated Digital Output Board for PCI] + +pci:v00001221d000091C3* + ID_MODEL_FROM_DATABASE=DA16-16(LPCI)L [Un-insulated highly precise analog output board for Low Profile PCI] + +pci:v00001221d0000B152* + ID_MODEL_FROM_DATABASE=DIO-96D2-LPCI + +pci:v00001221d0000C103* + ID_MODEL_FROM_DATABASE=ADA16-32/2(PCI)F [High-Speed Analog I/O Board for PCI] + +pci:v00001222* + ID_VENDOR_FROM_DATABASE=Ancor Communications, Inc. + +pci:v00001223* + ID_VENDOR_FROM_DATABASE=Artesyn Communication Products + +pci:v00001223d00000003* + ID_MODEL_FROM_DATABASE=PM/Link + +pci:v00001223d00000004* + ID_MODEL_FROM_DATABASE=PM/T1 + +pci:v00001223d00000005* + ID_MODEL_FROM_DATABASE=PM/E1 + +pci:v00001223d00000008* + ID_MODEL_FROM_DATABASE=PM/SLS + +pci:v00001223d00000009* + ID_MODEL_FROM_DATABASE=BajaSpan Resource Target + +pci:v00001223d0000000A* + ID_MODEL_FROM_DATABASE=BajaSpan Section 0 + +pci:v00001223d0000000B* + ID_MODEL_FROM_DATABASE=BajaSpan Section 1 + +pci:v00001223d0000000C* + ID_MODEL_FROM_DATABASE=BajaSpan Section 2 + +pci:v00001223d0000000D* + ID_MODEL_FROM_DATABASE=BajaSpan Section 3 + +pci:v00001223d0000000E* + ID_MODEL_FROM_DATABASE=PM/PPC + +pci:v00001224* + ID_VENDOR_FROM_DATABASE=Interactive Images + +pci:v00001225* + ID_VENDOR_FROM_DATABASE=Power I/O, Inc. + +pci:v00001227* + ID_VENDOR_FROM_DATABASE=Tech-Source + +pci:v00001227d00000006* + ID_MODEL_FROM_DATABASE=Raptor GFX 8P + +pci:v00001227d00000023* + ID_MODEL_FROM_DATABASE=Raptor GFX [1100T] + +pci:v00001227d00000045* + ID_MODEL_FROM_DATABASE=Raptor 4000-L [Linux version] + +pci:v00001227d0000004A* + ID_MODEL_FROM_DATABASE=Raptor 4000-LR-L [Linux version] + +pci:v00001228* + ID_VENDOR_FROM_DATABASE=Norsk Elektro Optikk A/S + +pci:v00001229* + ID_VENDOR_FROM_DATABASE=Data Kinesis Inc. + +pci:v0000122A* + ID_VENDOR_FROM_DATABASE=Integrated Telecom + +pci:v0000122B* + ID_VENDOR_FROM_DATABASE=LG Industrial Systems Co., Ltd + +pci:v0000122C* + ID_VENDOR_FROM_DATABASE=Sican GmbH + +pci:v0000122D* + ID_VENDOR_FROM_DATABASE=Aztech System Ltd + +pci:v0000122Dd00001206* + ID_MODEL_FROM_DATABASE=368DSP + +pci:v0000122Dd00001400* + ID_MODEL_FROM_DATABASE=Trident PCI288-Q3DII (NX) + +pci:v0000122Dd000050DC* + ID_MODEL_FROM_DATABASE=3328 Audio + +pci:v0000122Dd000050DCsv0000122Dsd00000001* + ID_MODEL_FROM_DATABASE=3328 Audio + +pci:v0000122Dd000080DA* + ID_MODEL_FROM_DATABASE=3328 Audio + +pci:v0000122Dd000080DAsv0000122Dsd00000001* + ID_MODEL_FROM_DATABASE=3328 Audio + +pci:v0000122E* + ID_VENDOR_FROM_DATABASE=Xyratex + +pci:v0000122Ed00007722* + ID_MODEL_FROM_DATABASE=Napatech XL1 + +pci:v0000122Ed00007724* + ID_MODEL_FROM_DATABASE=Napatech XL2/XA + +pci:v0000122Ed00007729* + ID_MODEL_FROM_DATABASE=Napatech XD + +pci:v0000122F* + ID_VENDOR_FROM_DATABASE=Andrew Corporation + +pci:v00001230* + ID_VENDOR_FROM_DATABASE=Fishcamp Engineering + +pci:v00001231* + ID_VENDOR_FROM_DATABASE=Woodward McCoach, Inc. + +pci:v00001231d000004E1* + ID_MODEL_FROM_DATABASE=Desktop PCI Telephony 4 + +pci:v00001231d000005E1* + ID_MODEL_FROM_DATABASE=Desktop PCI Telephony 5/6 + +pci:v00001231d00000D00* + ID_MODEL_FROM_DATABASE=LightParser + +pci:v00001231d00000D02* + ID_MODEL_FROM_DATABASE=LightParser 2 + +pci:v00001231d00000D13* + ID_MODEL_FROM_DATABASE=Desktop PCI L1/L3 Telephony + +pci:v00001232* + ID_VENDOR_FROM_DATABASE=GPT Limited + +pci:v00001233* + ID_VENDOR_FROM_DATABASE=Bus-Tech, Inc. + +pci:v00001235* + ID_VENDOR_FROM_DATABASE=Risq Modular Systems, Inc. + +pci:v00001236* + ID_VENDOR_FROM_DATABASE=Sigma Designs Corporation + +pci:v00001236d00000000* + ID_MODEL_FROM_DATABASE=RealMagic64/GX + +pci:v00001236d00006401* + ID_MODEL_FROM_DATABASE=REALmagic 64/GX (SD 6425) + +pci:v00001237* + ID_VENDOR_FROM_DATABASE=Alta Technology Corporation + +pci:v00001238* + ID_VENDOR_FROM_DATABASE=Adtran + +pci:v00001239* + ID_VENDOR_FROM_DATABASE=3DO Company + +pci:v0000123A* + ID_VENDOR_FROM_DATABASE=Visicom Laboratories, Inc. + +pci:v0000123B* + ID_VENDOR_FROM_DATABASE=Seeq Technology, Inc. + +pci:v0000123C* + ID_VENDOR_FROM_DATABASE=Century Systems, Inc. + +pci:v0000123D* + ID_VENDOR_FROM_DATABASE=Engineering Design Team, Inc. + +pci:v0000123Dd00000000* + ID_MODEL_FROM_DATABASE=EasyConnect 8/32 + +pci:v0000123Dd00000002* + ID_MODEL_FROM_DATABASE=EasyConnect 8/64 + +pci:v0000123Dd00000003* + ID_MODEL_FROM_DATABASE=EasyIO + +pci:v0000123E* + ID_VENDOR_FROM_DATABASE=Simutech, Inc. + +pci:v0000123F* + ID_VENDOR_FROM_DATABASE=LSI Logic + +pci:v0000123Fd000000E4* + ID_MODEL_FROM_DATABASE=MPEG + +pci:v0000123Fd00008120* + ID_MODEL_FROM_DATABASE=DVxplore Codec + +pci:v0000123Fd00008120sv000010DEsd000001E1* + ID_MODEL_FROM_DATABASE=NVTV PAL + +pci:v0000123Fd00008120sv000010DEsd000001E2* + ID_MODEL_FROM_DATABASE=NVTV NTSC + +pci:v0000123Fd00008120sv000010DEsd000001E3* + ID_MODEL_FROM_DATABASE=NVTV PAL + +pci:v0000123Fd00008120sv000010DEsd00000248* + ID_MODEL_FROM_DATABASE=NVTV NTSC + +pci:v0000123Fd00008120sv000010DEsd00000249* + ID_MODEL_FROM_DATABASE=NVTV PAL + +pci:v0000123Fd00008120sv000011BDsd00000006* + ID_MODEL_FROM_DATABASE=DV500 E4 + +pci:v0000123Fd00008120sv000011BDsd0000000A* + ID_MODEL_FROM_DATABASE=DV500 E4 + +pci:v0000123Fd00008120sv000011BDsd0000000F* + ID_MODEL_FROM_DATABASE=DV500 E4 + +pci:v0000123Fd00008120sv00001809sd00000016* + ID_MODEL_FROM_DATABASE=Emuzed MAUI-III PCI PVR FM TV + +pci:v0000123Fd00008888* + ID_MODEL_FROM_DATABASE=Cinemaster C 3.0 DVD Decoder + +pci:v0000123Fd00008888sv00001002sd00000001* + ID_MODEL_FROM_DATABASE=Cinemaster C 3.0 DVD Decoder + +pci:v0000123Fd00008888sv00001002sd00000002* + ID_MODEL_FROM_DATABASE=Cinemaster C 3.0 DVD Decoder + +pci:v0000123Fd00008888sv00001328sd00000001* + ID_MODEL_FROM_DATABASE=Cinemaster C 3.0 DVD Decoder + +pci:v00001240* + ID_VENDOR_FROM_DATABASE=Marathon Technologies Corp. + +pci:v00001241* + ID_VENDOR_FROM_DATABASE=DSC Communications + +pci:v00001242* + ID_VENDOR_FROM_DATABASE=JNI Corporation + +pci:v00001242d00001560* + ID_MODEL_FROM_DATABASE=JNIC-1560 PCI-X Fibre Channel Controller + +pci:v00001242d00001560sv00001242sd00006562* + ID_MODEL_FROM_DATABASE=FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter + +pci:v00001242d00001560sv00001242sd0000656A* + ID_MODEL_FROM_DATABASE=FCX-6562 PCI-X Fibre Channel Adapter + +pci:v00001242d00004643* + ID_MODEL_FROM_DATABASE=FCI-1063 Fibre Channel Adapter + +pci:v00001242d00006562* + ID_MODEL_FROM_DATABASE=FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter + +pci:v00001242d0000656A* + ID_MODEL_FROM_DATABASE=FCX-6562 PCI-X Fibre Channel Adapter + +pci:v00001243* + ID_VENDOR_FROM_DATABASE=Delphax + +pci:v00001244* + ID_VENDOR_FROM_DATABASE=AVM GmbH + +pci:v00001244d00000700* + ID_MODEL_FROM_DATABASE=B1 ISDN + +pci:v00001244d00000800* + ID_MODEL_FROM_DATABASE=C4 ISDN + +pci:v00001244d00000A00* + ID_MODEL_FROM_DATABASE=A1 ISDN [Fritz] + +pci:v00001244d00000A00sv00001244sd00000A00* + ID_MODEL_FROM_DATABASE=FRITZ!Card ISDN Controller + +pci:v00001244d00000E00* + ID_MODEL_FROM_DATABASE=Fritz!PCI v2.0 ISDN + +pci:v00001244d00001100* + ID_MODEL_FROM_DATABASE=C2 ISDN + +pci:v00001244d00001200* + ID_MODEL_FROM_DATABASE=T1 ISDN + +pci:v00001244d00002700* + ID_MODEL_FROM_DATABASE=Fritz!Card DSL SL + +pci:v00001244d00002900* + ID_MODEL_FROM_DATABASE=Fritz!Card DSL v2.0 + +pci:v00001245* + ID_VENDOR_FROM_DATABASE=A.P.D., S.A. + +pci:v00001246* + ID_VENDOR_FROM_DATABASE=Dipix Technologies, Inc. + +pci:v00001247* + ID_VENDOR_FROM_DATABASE=Xylon Research, Inc. + +pci:v00001248* + ID_VENDOR_FROM_DATABASE=Central Data Corporation + +pci:v00001249* + ID_VENDOR_FROM_DATABASE=Samsung Electronics Co., Ltd. + +pci:v0000124A* + ID_VENDOR_FROM_DATABASE=AEG Electrocom GmbH + +pci:v0000124B* + ID_VENDOR_FROM_DATABASE=SBS/Greenspring Modular I/O + +pci:v0000124Bd00000040* + ID_MODEL_FROM_DATABASE=PCI-40A or cPCI-200 Quad IndustryPack carrier + +pci:v0000124Bd00000040sv0000124Bsd00009080* + ID_MODEL_FROM_DATABASE=PCI9080 Bridge + +pci:v0000124C* + ID_VENDOR_FROM_DATABASE=Solitron Technologies, Inc. + +pci:v0000124D* + ID_VENDOR_FROM_DATABASE=Stallion Technologies, Inc. + +pci:v0000124Dd00000000* + ID_MODEL_FROM_DATABASE=EasyConnection 8/32 + +pci:v0000124Dd00000002* + ID_MODEL_FROM_DATABASE=EasyConnection 8/64 + +pci:v0000124Dd00000003* + ID_MODEL_FROM_DATABASE=EasyIO + +pci:v0000124Dd00000004* + ID_MODEL_FROM_DATABASE=EasyConnection/RA + +pci:v0000124E* + ID_VENDOR_FROM_DATABASE=Cylink + +pci:v0000124F* + ID_VENDOR_FROM_DATABASE=Infortrend Technology, Inc. + +pci:v0000124Fd00000041* + ID_MODEL_FROM_DATABASE=IFT-2000 Series RAID Controller + +pci:v00001250* + ID_VENDOR_FROM_DATABASE=Hitachi Microcomputer System Ltd + +pci:v00001251* + ID_VENDOR_FROM_DATABASE=VLSI Solutions Oy + +pci:v00001253* + ID_VENDOR_FROM_DATABASE=Guzik Technical Enterprises + +pci:v00001254* + ID_VENDOR_FROM_DATABASE=Linear Systems Ltd. + +pci:v00001254d00000065* + ID_MODEL_FROM_DATABASE=DVB Master FD + +pci:v00001254d0000007C* + ID_MODEL_FROM_DATABASE=DVB Master Quad/o + +pci:v00001255* + ID_VENDOR_FROM_DATABASE=Optibase Ltd + +pci:v00001255d00001110* + ID_MODEL_FROM_DATABASE=MPEG Forge + +pci:v00001255d00001210* + ID_MODEL_FROM_DATABASE=MPEG Fusion + +pci:v00001255d00002110* + ID_MODEL_FROM_DATABASE=VideoPlex + +pci:v00001255d00002120* + ID_MODEL_FROM_DATABASE=VideoPlex CC + +pci:v00001255d00002130* + ID_MODEL_FROM_DATABASE=VideoQuest + +pci:v00001256* + ID_VENDOR_FROM_DATABASE=Perceptive Solutions, Inc. + +pci:v00001256d00004201* + ID_MODEL_FROM_DATABASE=PCI-2220I + +pci:v00001256d00004401* + ID_MODEL_FROM_DATABASE=PCI-2240I + +pci:v00001256d00005201* + ID_MODEL_FROM_DATABASE=PCI-2000 + +pci:v00001257* + ID_VENDOR_FROM_DATABASE=Vertex Networks, Inc. + +pci:v00001258* + ID_VENDOR_FROM_DATABASE=Gilbarco, Inc. + +pci:v00001259* + ID_VENDOR_FROM_DATABASE=Allied Telesis + +pci:v00001259d00002560* + ID_MODEL_FROM_DATABASE=AT-2560 Fast Ethernet Adapter (i82557B) + +pci:v00001259d00002801* + ID_MODEL_FROM_DATABASE=AT-2801FX (RTL-8139) + +pci:v00001259d0000A117* + ID_MODEL_FROM_DATABASE=RTL81xx Fast Ethernet + +pci:v00001259d0000A11E* + ID_MODEL_FROM_DATABASE=RTL81xx Fast Ethernet + +pci:v00001259d0000A120* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v0000125A* + ID_VENDOR_FROM_DATABASE=ABB Power Systems + +pci:v0000125B* + ID_VENDOR_FROM_DATABASE=Asix Electronics Corporation + +pci:v0000125Bd00001400* + ID_MODEL_FROM_DATABASE=AX88141 Fast Ethernet Controller + +pci:v0000125Bd00001400sv00001186sd00001100* + ID_MODEL_FROM_DATABASE=AX8814X Based PCI Fast Ethernet Adapter + +pci:v0000125C* + ID_VENDOR_FROM_DATABASE=Aurora Technologies, Inc. + +pci:v0000125Cd00000101* + ID_MODEL_FROM_DATABASE=Saturn 4520P + +pci:v0000125Cd00000640* + ID_MODEL_FROM_DATABASE=Aries 16000P + +pci:v0000125D* + ID_VENDOR_FROM_DATABASE=ESS Technology + +pci:v0000125Dd00000000* + ID_MODEL_FROM_DATABASE=ES336H Fax Modem (Early Model) + +pci:v0000125Dd00001948* + ID_MODEL_FROM_DATABASE=ES1948 Maestro-1 + +pci:v0000125Dd00001968* + ID_MODEL_FROM_DATABASE=ES1968 Maestro 2 + +pci:v0000125Dd00001968sv00001028sd00000085* + ID_MODEL_FROM_DATABASE=ES1968 Maestro-2 PCI + +pci:v0000125Dd00001968sv00001033sd00008051* + ID_MODEL_FROM_DATABASE=ES1968 Maestro-2 Audiodrive + +pci:v0000125Dd00001969* + ID_MODEL_FROM_DATABASE=ES1938/ES1946/ES1969 Solo-1 Audiodrive + +pci:v0000125Dd00001969sv00001014sd00000166* + ID_MODEL_FROM_DATABASE=ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard + +pci:v0000125Dd00001969sv0000125Dsd00008888* + ID_MODEL_FROM_DATABASE=Solo-1 Audio Adapter + +pci:v0000125Dd00001969sv0000153Bsd0000111B* + ID_MODEL_FROM_DATABASE=Terratec 128i PCI + +pci:v0000125Dd00001978* + ID_MODEL_FROM_DATABASE=ES1978 Maestro 2E + +pci:v0000125Dd00001978sv00000E11sd0000B112* + ID_MODEL_FROM_DATABASE=Armada M700/E500 + +pci:v0000125Dd00001978sv00001033sd0000803C* + ID_MODEL_FROM_DATABASE=ES1978 Maestro-2E Audiodrive + +pci:v0000125Dd00001978sv00001033sd00008058* + ID_MODEL_FROM_DATABASE=ES1978 Maestro-2E Audiodrive + +pci:v0000125Dd00001978sv00001092sd00004000* + ID_MODEL_FROM_DATABASE=Monster Sound MX400 + +pci:v0000125Dd00001978sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=ES1978 Maestro-2E Audiodrive + +pci:v0000125Dd00001988* + ID_MODEL_FROM_DATABASE=ES1988 Allegro-1 + +pci:v0000125Dd00001988sv00000E11sd00000098* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v0000125Dd00001988sv00001092sd00004100* + ID_MODEL_FROM_DATABASE=Sonic Impact S100 + +pci:v0000125Dd00001988sv0000125Dsd00000431* + ID_MODEL_FROM_DATABASE=Allegro AudioDrive + +pci:v0000125Dd00001988sv0000125Dsd00001988* + ID_MODEL_FROM_DATABASE=ESS Allegro-1 Audiodrive + +pci:v0000125Dd00001988sv0000125Dsd00001998* + ID_MODEL_FROM_DATABASE=Allegro AudioDrive + +pci:v0000125Dd00001988sv0000125Dsd00001999* + ID_MODEL_FROM_DATABASE=Allegro-1 AudioDrive + +pci:v0000125Dd00001989* + ID_MODEL_FROM_DATABASE=ESS Modem + +pci:v0000125Dd00001989sv0000125Dsd00001989* + ID_MODEL_FROM_DATABASE=ESS Modem + +pci:v0000125Dd00001998* + ID_MODEL_FROM_DATABASE=ES1983S Maestro-3i PCI Audio Accelerator + +pci:v0000125Dd00001998sv00001028sd000000B1* + ID_MODEL_FROM_DATABASE=Latitude C600 + +pci:v0000125Dd00001998sv00001028sd000000E5* + ID_MODEL_FROM_DATABASE=Latitude C810 + +pci:v0000125Dd00001998sv00001028sd000000E6* + ID_MODEL_FROM_DATABASE=ES1983S Maestro-3i (Dell Inspiron 8100) + +pci:v0000125Dd00001999* + ID_MODEL_FROM_DATABASE=ES1983S Maestro-3i PCI Modem Accelerator + +pci:v0000125Dd0000199A* + ID_MODEL_FROM_DATABASE=ES1983S Maestro-3i PCI Audio Accelerator + +pci:v0000125Dd0000199B* + ID_MODEL_FROM_DATABASE=ES1983S Maestro-3i PCI Modem Accelerator + +pci:v0000125Dd00002808* + ID_MODEL_FROM_DATABASE=ES336H Fax Modem (Later Model) + +pci:v0000125Dd00002838* + ID_MODEL_FROM_DATABASE=ES2838/2839 SuperLink Modem + +pci:v0000125Dd00002898* + ID_MODEL_FROM_DATABASE=ES2898 Modem + +pci:v0000125Dd00002898sv0000125Dsd00000424* + ID_MODEL_FROM_DATABASE=ES56-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000125Dsd00000425* + ID_MODEL_FROM_DATABASE=ES56T-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000125Dsd00000426* + ID_MODEL_FROM_DATABASE=ES56V-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000125Dsd00000427* + ID_MODEL_FROM_DATABASE=VW-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000125Dsd00000428* + ID_MODEL_FROM_DATABASE=ES56ST-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000125Dsd00000429* + ID_MODEL_FROM_DATABASE=ES56SV-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000147Asd0000C001* + ID_MODEL_FROM_DATABASE=ES56-PI Data Fax Modem + +pci:v0000125Dd00002898sv0000148Dsd00001030* + ID_MODEL_FROM_DATABASE=HCF WV-PI56 [ESS ES56-PI Data Fax Modem] + +pci:v0000125Dd00002898sv000014FEsd00000428* + ID_MODEL_FROM_DATABASE=ES56-PI Data Fax Modem + +pci:v0000125Dd00002898sv000014FEsd00000429* + ID_MODEL_FROM_DATABASE=ES56-PI Data Fax Modem + +pci:v0000125E* + ID_VENDOR_FROM_DATABASE=Specialvideo Engineering SRL + +pci:v0000125F* + ID_VENDOR_FROM_DATABASE=Concurrent Technologies, Inc. + +pci:v00001260* + ID_VENDOR_FROM_DATABASE=Intersil Corporation + +pci:v00001260d00003872* + ID_MODEL_FROM_DATABASE=ISL3872 [Prism 3] + +pci:v00001260d00003872sv00001468sd00000202* + ID_MODEL_FROM_DATABASE=LAN-Express IEEE 802.11b Wireless LAN + +pci:v00001260d00003873* + ID_MODEL_FROM_DATABASE=ISL3874 [Prism 2.5]/ISL3872 [Prism 3] + +pci:v00001260d00003873sv000010CFsd00001169* + ID_MODEL_FROM_DATABASE=MBH7WM01-8734 802.11b Wireless Mini PCI Card [ISL3874] + +pci:v00001260d00003873sv00001186sd00003501* + ID_MODEL_FROM_DATABASE=DWL-520 Wireless PCI Adapter (rev A or B) [ISL3874] + +pci:v00001260d00003873sv00001186sd00003700* + ID_MODEL_FROM_DATABASE=DWL-520 Wireless PCI Adapter (rev E1) [ISL3872] + +pci:v00001260d00003873sv00001385sd00004105* + ID_MODEL_FROM_DATABASE=MA311 802.11b wireless adapter [ISL3874] + +pci:v00001260d00003873sv00001668sd00000414* + ID_MODEL_FROM_DATABASE=HWP01170-01 802.11b PCI Wireless Adapter + +pci:v00001260d00003873sv000016A5sd00001601* + ID_MODEL_FROM_DATABASE=AIR.mate PC-400 PCI Wireless LAN Adapter + +pci:v00001260d00003873sv00001737sd00003874* + ID_MODEL_FROM_DATABASE=WMP11 v1 802.11b Wireless-B PCI Adapter [ISL3874] + +pci:v00001260d00003873sv00004033sd00007033* + ID_MODEL_FROM_DATABASE=PCW200 802.11b Wireless PCI Adapter [ISL3874] + +pci:v00001260d00003873sv00008086sd00002510* + ID_MODEL_FROM_DATABASE=M3AWEB Wireless 802.11b MiniPCI Adapter + +pci:v00001260d00003873sv00008086sd00002513* + ID_MODEL_FROM_DATABASE=Wireless 802.11b MiniPCI Adapter + +pci:v00001260d00003877* + ID_MODEL_FROM_DATABASE=ISL3877 [Prism Indigo] + +pci:v00001260d00003886* + ID_MODEL_FROM_DATABASE=ISL3886 [Prism Javelin/Prism Xbow] + +pci:v00001260d00003886sv000017CFsd00000037* + ID_MODEL_FROM_DATABASE=XG-901 and clones Wireless Adapter + +pci:v00001260d00003890* + ID_MODEL_FROM_DATABASE=ISL3890 [Prism GT/Prism Duette]/ISL3886 [Prism Javelin/Prism Xbow] + +pci:v00001260d00003890sv000010B8sd00002802* + ID_MODEL_FROM_DATABASE=SMC2802W V1 Wireless PCI Adapter [ISL3890] + +pci:v00001260d00003890sv000010B8sd00002835* + ID_MODEL_FROM_DATABASE=SMC2835W Wireless Cardbus Adapter + +pci:v00001260d00003890sv000010B8sd0000A835* + ID_MODEL_FROM_DATABASE=SMC2835W V2 Wireless Cardbus Adapter + +pci:v00001260d00003890sv00001113sd00004203* + ID_MODEL_FROM_DATABASE=WN4201B + +pci:v00001260d00003890sv00001113sd00008201* + ID_MODEL_FROM_DATABASE=T-Com T-Sinus 154pcicard Wireless PCI Adapter + +pci:v00001260d00003890sv00001113sd0000B301* + ID_MODEL_FROM_DATABASE=T-Sinus 154card Cardbus + +pci:v00001260d00003890sv00001113sd0000EE03* + ID_MODEL_FROM_DATABASE=SMC2802W V2 Wireless PCI Adapter [ISL3886] + +pci:v00001260d00003890sv00001113sd0000EE08* + ID_MODEL_FROM_DATABASE=SMC2835W V3 EU Wireless Cardbus Adapter + +pci:v00001260d00003890sv00001186sd00003202* + ID_MODEL_FROM_DATABASE=DWL-G650 A1 Wireless Adapter + +pci:v00001260d00003890sv00001259sd0000C104* + ID_MODEL_FROM_DATABASE=CG-WLCB54GT Wireless Adapter + +pci:v00001260d00003890sv00001260sd00000000* + ID_MODEL_FROM_DATABASE=WG511 v1 54 Mbps Wireless PC Card + +pci:v00001260d00003890sv00001385sd00004800* + ID_MODEL_FROM_DATABASE=WG511 v2/v3 54 Mbps Wireless PC Card + +pci:v00001260d00003890sv000016A5sd00001605* + ID_MODEL_FROM_DATABASE=ALLNET ALL0271 Wireless PCI Adapter + +pci:v00001260d00003890sv000017CFsd00000014* + ID_MODEL_FROM_DATABASE=XG-600 and clones Wireless Adapter + +pci:v00001260d00003890sv000017CFsd00000020* + ID_MODEL_FROM_DATABASE=XG-900 and clones Wireless Adapter + +pci:v00001260d00003890sv0000187Esd00003403* + ID_MODEL_FROM_DATABASE=G-110 802.11g Wireless Cardbus Adapter + +pci:v00001260d00008130* + ID_MODEL_FROM_DATABASE=HMP8130 NTSC/PAL Video Decoder + +pci:v00001260d00008131* + ID_MODEL_FROM_DATABASE=HMP8131 NTSC/PAL Video Decoder + +pci:v00001260d0000FFFF* + ID_MODEL_FROM_DATABASE=ISL3886IK + +pci:v00001260d0000FFFFsv00001260sd00000000* + ID_MODEL_FROM_DATABASE=Senao 3054MP+ (J) mini-PCI WLAN 802.11g adapter + +pci:v00001261* + ID_VENDOR_FROM_DATABASE=Matsushita-Kotobuki Electronics Industries, Ltd. + +pci:v00001262* + ID_VENDOR_FROM_DATABASE=ES Computer Company, Ltd. + +pci:v00001263* + ID_VENDOR_FROM_DATABASE=Sonic Solutions + +pci:v00001264* + ID_VENDOR_FROM_DATABASE=Aval Nagasaki Corporation + +pci:v00001265* + ID_VENDOR_FROM_DATABASE=Casio Computer Co., Ltd. + +pci:v00001266* + ID_VENDOR_FROM_DATABASE=Microdyne Corporation + +pci:v00001266d00000001* + ID_MODEL_FROM_DATABASE=NE10/100 Adapter (i82557B) + +pci:v00001266d00001910* + ID_MODEL_FROM_DATABASE=NE2000Plus (RT8029) Ethernet Adapter + +pci:v00001266d00001910sv00001266sd00001910* + ID_MODEL_FROM_DATABASE=NE2000Plus Ethernet Adapter + +pci:v00001267* + ID_VENDOR_FROM_DATABASE=S. A. Telecommunications + +pci:v00001267d00005352* + ID_MODEL_FROM_DATABASE=PCR2101 + +pci:v00001267d00005A4B* + ID_MODEL_FROM_DATABASE=Telsat Turbo + +pci:v00001268* + ID_VENDOR_FROM_DATABASE=Tektronix + +pci:v00001269* + ID_VENDOR_FROM_DATABASE=Thomson-CSF/TTM + +pci:v0000126A* + ID_VENDOR_FROM_DATABASE=Lexmark International, Inc. + +pci:v0000126B* + ID_VENDOR_FROM_DATABASE=Adax, Inc. + +pci:v0000126C* + ID_VENDOR_FROM_DATABASE=Northern Telecom + +pci:v0000126Cd00001211* + ID_MODEL_FROM_DATABASE=10/100BaseTX [RTL81xx] + +pci:v0000126Cd0000126C* + ID_MODEL_FROM_DATABASE=802.11b Wireless Ethernet Adapter + +pci:v0000126D* + ID_VENDOR_FROM_DATABASE=Splash Technology, Inc. + +pci:v0000126E* + ID_VENDOR_FROM_DATABASE=Sumitomo Metal Industries, Ltd. + +pci:v0000126F* + ID_VENDOR_FROM_DATABASE=Silicon Motion, Inc. + +pci:v0000126Fd00000501* + ID_MODEL_FROM_DATABASE=SM501 VoyagerGX Rev. AA + +pci:v0000126Fd00000510* + ID_MODEL_FROM_DATABASE=SM501 VoyagerGX Rev. B + +pci:v0000126Fd00000710* + ID_MODEL_FROM_DATABASE=SM710 LynxEM + +pci:v0000126Fd00000712* + ID_MODEL_FROM_DATABASE=SM712 LynxEM+ + +pci:v0000126Fd00000718* + ID_MODEL_FROM_DATABASE=SM718 LynxSE+ + +pci:v0000126Fd00000720* + ID_MODEL_FROM_DATABASE=SM720 Lynx3DM + +pci:v0000126Fd00000730* + ID_MODEL_FROM_DATABASE=SM731 Cougar3DR + +pci:v0000126Fd00000810* + ID_MODEL_FROM_DATABASE=SM810 LynxE + +pci:v0000126Fd00000811* + ID_MODEL_FROM_DATABASE=SM811 LynxE + +pci:v0000126Fd00000820* + ID_MODEL_FROM_DATABASE=SM820 Lynx3D + +pci:v0000126Fd00000910* + ID_MODEL_FROM_DATABASE=SM910 + +pci:v00001270* + ID_VENDOR_FROM_DATABASE=Olympus Optical Co., Ltd. + +pci:v00001271* + ID_VENDOR_FROM_DATABASE=GW Instruments + +pci:v00001272* + ID_VENDOR_FROM_DATABASE=Telematics International + +pci:v00001273* + ID_VENDOR_FROM_DATABASE=Hughes Network Systems + +pci:v00001273d00000002* + ID_MODEL_FROM_DATABASE=DirecPC + +pci:v00001274* + ID_VENDOR_FROM_DATABASE=Ensoniq + +pci:v00001274d00001171* + ID_MODEL_FROM_DATABASE=ES1373 [AudioPCI] (also Creative Labs CT5803) + +pci:v00001274d00001371* + ID_MODEL_FROM_DATABASE=ES1371 [AudioPCI-97] + +pci:v00001274d00001371sv00000E11sd00000024* + ID_MODEL_FROM_DATABASE=AudioPCI on Motherboard Compaq Deskpro + +pci:v00001274d00001371sv00000E11sd0000B1A7* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI + +pci:v00001274d00001371sv00001033sd000080AC* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI + +pci:v00001274d00001371sv00001042sd00001854* + ID_MODEL_FROM_DATABASE=Tazer + +pci:v00001274d00001371sv0000107Bsd00008054* + ID_MODEL_FROM_DATABASE=Tabor2 + +pci:v00001274d00001371sv00001274sd00001371* + ID_MODEL_FROM_DATABASE=Creative Sound Blaster AudioPCI64V, AudioPCI128 + +pci:v00001274d00001371sv00001274sd00008001* + ID_MODEL_FROM_DATABASE=CT4751 board + +pci:v00001274d00001371sv00001462sd00006470* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A + +pci:v00001274d00001371sv00001462sd00006560* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10 + +pci:v00001274d00001371sv00001462sd00006630* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A + +pci:v00001274d00001371sv00001462sd00006631* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A + +pci:v00001274d00001371sv00001462sd00006632* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A + +pci:v00001274d00001371sv00001462sd00006633* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A + +pci:v00001274d00001371sv00001462sd00006820* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00 + +pci:v00001274d00001371sv00001462sd00006822* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A + +pci:v00001274d00001371sv00001462sd00006830* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00 + +pci:v00001274d00001371sv00001462sd00006880* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00 + +pci:v00001274d00001371sv00001462sd00006900* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00 + +pci:v00001274d00001371sv00001462sd00006910* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6191 + +pci:v00001274d00001371sv00001462sd00006930* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6193 + +pci:v00001274d00001371sv00001462sd00006990* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A + +pci:v00001274d00001371sv00001462sd00006991* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A + +pci:v00001274d00001371sv000014A4sd00002077* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard KR639 + +pci:v00001274d00001371sv000014A4sd00002105* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MR800 + +pci:v00001274d00001371sv000014A4sd00002107* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard MR801 + +pci:v00001274d00001371sv000014A4sd00002172* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard DR739 + +pci:v00001274d00001371sv00001509sd00009902* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard KW11 + +pci:v00001274d00001371sv00001509sd00009903* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard KW31 + +pci:v00001274d00001371sv00001509sd00009904* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard KA11 + +pci:v00001274d00001371sv00001509sd00009905* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard KC13 + +pci:v00001274d00001371sv0000152Dsd00008801* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard CP810E + +pci:v00001274d00001371sv0000152Dsd00008802* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard CP810 + +pci:v00001274d00001371sv0000152Dsd00008803* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard P3810E + +pci:v00001274d00001371sv0000152Dsd00008804* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard P3810-S + +pci:v00001274d00001371sv0000152Dsd00008805* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard P3820-S + +pci:v00001274d00001371sv0000270Fsd00002001* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6CTR + +pci:v00001274d00001371sv0000270Fsd00002200* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6WTX + +pci:v00001274d00001371sv0000270Fsd00003000* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6WSV + +pci:v00001274d00001371sv0000270Fsd00003100* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6WIV2 + +pci:v00001274d00001371sv0000270Fsd00003102* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6WIV + +pci:v00001274d00001371sv0000270Fsd00007060* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard 6ASA2 + +pci:v00001274d00001371sv00008086sd00004249* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard BI440ZX + +pci:v00001274d00001371sv00008086sd0000424C* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard BL440ZX + +pci:v00001274d00001371sv00008086sd0000425A* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard BZ440ZX + +pci:v00001274d00001371sv00008086sd00004341* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard Cayman + +pci:v00001274d00001371sv00008086sd00004343* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard Cape Cod + +pci:v00001274d00001371sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=D815EEA Motherboard + +pci:v00001274d00001371sv00008086sd00004649* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard Fire Island + +pci:v00001274d00001371sv00008086sd0000464A* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard FJ440ZX + +pci:v00001274d00001371sv00008086sd00004D4F* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard Montreal + +pci:v00001274d00001371sv00008086sd00004F43* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard OC440LX + +pci:v00001274d00001371sv00008086sd00005243* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard RC440BX + +pci:v00001274d00001371sv00008086sd00005352* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard SunRiver + +pci:v00001274d00001371sv00008086sd00005643* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard Vancouver + +pci:v00001274d00001371sv00008086sd00005753* + ID_MODEL_FROM_DATABASE=ES1371, ES1373 AudioPCI On Motherboard WS440BX + +pci:v00001274d00005000* + ID_MODEL_FROM_DATABASE=ES1370 [AudioPCI] + +pci:v00001274d00005880* + ID_MODEL_FROM_DATABASE=5880B [AudioPCI] + +pci:v00001274d00005880sv00001274sd00002000* + ID_MODEL_FROM_DATABASE=Creative Sound Blaster AudioPCI128 + +pci:v00001274d00005880sv00001274sd00002003* + ID_MODEL_FROM_DATABASE=Creative SoundBlaster AudioPCI 128 + +pci:v00001274d00005880sv00001274sd00005880* + ID_MODEL_FROM_DATABASE=Creative Sound Blaster AudioPCI128 + +pci:v00001274d00005880sv00001274sd00008001* + ID_MODEL_FROM_DATABASE=Sound Blaster 16PCI 4.1ch + +pci:v00001274d00005880sv00001458sd0000A000* + ID_MODEL_FROM_DATABASE=5880 AudioPCI On Motherboard 6OXET + +pci:v00001274d00005880sv00001462sd00006880* + ID_MODEL_FROM_DATABASE=5880 AudioPCI On Motherboard MS-6188 1.00 + +pci:v00001274d00005880sv0000270Fsd00002001* + ID_MODEL_FROM_DATABASE=5880 AudioPCI On Motherboard 6CTR + +pci:v00001274d00005880sv0000270Fsd00002200* + ID_MODEL_FROM_DATABASE=5880 AudioPCI On Motherboard 6WTX + +pci:v00001274d00005880sv0000270Fsd00007040* + ID_MODEL_FROM_DATABASE=5880 AudioPCI On Motherboard 6ATA4 + +pci:v00001274d00008001* + ID_MODEL_FROM_DATABASE=CT5880 [AudioPCI] + +pci:v00001274d00008002* + ID_MODEL_FROM_DATABASE=5880A [AudioPCI] + +pci:v00001275* + ID_VENDOR_FROM_DATABASE=Network Appliance Corporation + +pci:v00001276* + ID_VENDOR_FROM_DATABASE=Switched Network Technologies, Inc. + +pci:v00001277* + ID_VENDOR_FROM_DATABASE=Comstream + +pci:v00001278* + ID_VENDOR_FROM_DATABASE=Transtech Parallel Systems Ltd. + +pci:v00001278d00000701* + ID_MODEL_FROM_DATABASE=TPE3/TM3 PowerPC Node + +pci:v00001278d00000710* + ID_MODEL_FROM_DATABASE=TPE5 PowerPC PCI board + +pci:v00001278d00001100* + ID_MODEL_FROM_DATABASE=PMC-FPGA02 + +pci:v00001278d00001101* + ID_MODEL_FROM_DATABASE=TS-C43 card with 4 ADSP-TS101 processors + +pci:v00001279* + ID_VENDOR_FROM_DATABASE=Transmeta Corporation + +pci:v00001279d00000060* + ID_MODEL_FROM_DATABASE=TM8000 Northbridge + +pci:v00001279d00000061* + ID_MODEL_FROM_DATABASE=TM8000 AGP bridge + +pci:v00001279d00000295* + ID_MODEL_FROM_DATABASE=Northbridge + +pci:v00001279d00000395* + ID_MODEL_FROM_DATABASE=LongRun Northbridge + +pci:v00001279d00000396* + ID_MODEL_FROM_DATABASE=SDRAM controller + +pci:v00001279d00000397* + ID_MODEL_FROM_DATABASE=BIOS scratchpad + +pci:v0000127A* + ID_VENDOR_FROM_DATABASE=Rockwell International + +pci:v0000127Ad00001002* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v0000127Ad00001002sv00001092sd0000094C* + ID_MODEL_FROM_DATABASE=SupraExpress 56i PRO [Diamond SUP2380] + +pci:v0000127Ad00001002sv0000122Dsd00004002* + ID_MODEL_FROM_DATABASE=HPG / MDP3858-U + +pci:v0000127Ad00001002sv0000122Dsd00004005* + ID_MODEL_FROM_DATABASE=MDP3858-E + +pci:v0000127Ad00001002sv0000122Dsd00004007* + ID_MODEL_FROM_DATABASE=MDP3858-A/-NZ + +pci:v0000127Ad00001002sv0000122Dsd00004012* + ID_MODEL_FROM_DATABASE=MDP3858-SA + +pci:v0000127Ad00001002sv0000122Dsd00004017* + ID_MODEL_FROM_DATABASE=MDP3858-W + +pci:v0000127Ad00001002sv0000122Dsd00004018* + ID_MODEL_FROM_DATABASE=MDP3858-W + +pci:v0000127Ad00001002sv0000127Asd00001002* + ID_MODEL_FROM_DATABASE=Rockwell 56K D/F HCF Modem + +pci:v0000127Ad00001003* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v0000127Ad00001003sv00000E11sd0000B0BC* + ID_MODEL_FROM_DATABASE=229-DF Zephyr + +pci:v0000127Ad00001003sv00000E11sd0000B114* + ID_MODEL_FROM_DATABASE=229-DF Cheetah + +pci:v0000127Ad00001003sv00001033sd0000802B* + ID_MODEL_FROM_DATABASE=229-DF + +pci:v0000127Ad00001003sv000013DFsd00001003* + ID_MODEL_FROM_DATABASE=PCI56RX Modem + +pci:v0000127Ad00001003sv000013E0sd00000117* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001003sv000013E0sd00000147* + ID_MODEL_FROM_DATABASE=IBM F-1156IV+/R3 Spain V.90 Modem + +pci:v0000127Ad00001003sv000013E0sd00000197* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001003sv000013E0sd000001C7* + ID_MODEL_FROM_DATABASE=IBM F-1156IV+/R3 WW V.90 Modem + +pci:v0000127Ad00001003sv000013E0sd000001F7* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001003sv00001436sd00001003* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001003sv00001436sd00001103* + ID_MODEL_FROM_DATABASE=IBM 5614PM3G V.90 Modem + +pci:v0000127Ad00001003sv00001436sd00001602* + ID_MODEL_FROM_DATABASE=Compaq 229-DF Ducati + +pci:v0000127Ad00001004* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v0000127Ad00001004sv00001048sd00001500* + ID_MODEL_FROM_DATABASE=MicroLink 56k Modem + +pci:v0000127Ad00001004sv000010CFsd00001059* + ID_MODEL_FROM_DATABASE=Fujitsu 229-DFRT + +pci:v0000127Ad00001005* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v0000127Ad00001005sv00001005sd0000127A* + ID_MODEL_FROM_DATABASE=AOpen FM56-P + +pci:v0000127Ad00001005sv00001033sd00008029* + ID_MODEL_FROM_DATABASE=229-DFSV + +pci:v0000127Ad00001005sv00001033sd00008054* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00001005sv000010CFsd0000103C* + ID_MODEL_FROM_DATABASE=Fujitsu + +pci:v0000127Ad00001005sv000010CFsd00001055* + ID_MODEL_FROM_DATABASE=Fujitsu 229-DFSV + +pci:v0000127Ad00001005sv000010CFsd00001056* + ID_MODEL_FROM_DATABASE=Fujitsu 229-DFSV + +pci:v0000127Ad00001005sv0000122Dsd00004003* + ID_MODEL_FROM_DATABASE=MDP3858SP-U + +pci:v0000127Ad00001005sv0000122Dsd00004006* + ID_MODEL_FROM_DATABASE=Packard Bell MDP3858V-E + +pci:v0000127Ad00001005sv0000122Dsd00004008* + ID_MODEL_FROM_DATABASE=MDP3858SP-A/SP-NZ + +pci:v0000127Ad00001005sv0000122Dsd00004009* + ID_MODEL_FROM_DATABASE=MDP3858SP-E + +pci:v0000127Ad00001005sv0000122Dsd00004010* + ID_MODEL_FROM_DATABASE=MDP3858V-U + +pci:v0000127Ad00001005sv0000122Dsd00004011* + ID_MODEL_FROM_DATABASE=MDP3858SP-SA + +pci:v0000127Ad00001005sv0000122Dsd00004013* + ID_MODEL_FROM_DATABASE=MDP3858V-A/V-NZ + +pci:v0000127Ad00001005sv0000122Dsd00004015* + ID_MODEL_FROM_DATABASE=MDP3858SP-W + +pci:v0000127Ad00001005sv0000122Dsd00004016* + ID_MODEL_FROM_DATABASE=MDP3858V-W + +pci:v0000127Ad00001005sv0000122Dsd00004019* + ID_MODEL_FROM_DATABASE=MDP3858V-SA + +pci:v0000127Ad00001005sv000013DFsd00001005* + ID_MODEL_FROM_DATABASE=PCI56RVP Modem + +pci:v0000127Ad00001005sv000013E0sd00000187* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001005sv000013E0sd000001A7* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001005sv000013E0sd000001B7* + ID_MODEL_FROM_DATABASE=IBM DF-1156IV+/R3 Spain V.90 Modem + +pci:v0000127Ad00001005sv000013E0sd000001D7* + ID_MODEL_FROM_DATABASE=IBM DF-1156IV+/R3 WW V.90 Modem + +pci:v0000127Ad00001005sv00001436sd00001005* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001005sv00001436sd00001105* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001005sv00001437sd00001105* + ID_MODEL_FROM_DATABASE=IBM 5614PS3G V.90 Modem + +pci:v0000127Ad00001022* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v0000127Ad00001022sv00001436sd00001303* + ID_MODEL_FROM_DATABASE=M3-5614PM3G V.90 Modem + +pci:v0000127Ad00001023* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v0000127Ad00001023sv0000122Dsd00004020* + ID_MODEL_FROM_DATABASE=Packard Bell MDP3858-WE + +pci:v0000127Ad00001023sv0000122Dsd00004023* + ID_MODEL_FROM_DATABASE=MDP3858-UE + +pci:v0000127Ad00001023sv000013E0sd00000247* + ID_MODEL_FROM_DATABASE=IBM F-1156IV+/R6 Spain V.90 Modem + +pci:v0000127Ad00001023sv000013E0sd00000297* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001023sv000013E0sd000002C7* + ID_MODEL_FROM_DATABASE=IBM F-1156IV+/R6 WW V.90 Modem + +pci:v0000127Ad00001023sv00001436sd00001203* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001023sv00001436sd00001303* + ID_MODEL_FROM_DATABASE=IBM + +pci:v0000127Ad00001024* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v0000127Ad00001025* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v0000127Ad00001025sv000010CFsd0000106A* + ID_MODEL_FROM_DATABASE=Fujitsu 235-DFSV + +pci:v0000127Ad00001025sv0000122Dsd00004021* + ID_MODEL_FROM_DATABASE=Packard Bell MDP3858V-WE + +pci:v0000127Ad00001025sv0000122Dsd00004022* + ID_MODEL_FROM_DATABASE=MDP3858SP-WE + +pci:v0000127Ad00001025sv0000122Dsd00004024* + ID_MODEL_FROM_DATABASE=MDP3858V-UE + +pci:v0000127Ad00001025sv0000122Dsd00004025* + ID_MODEL_FROM_DATABASE=MDP3858SP-UE + +pci:v0000127Ad00001026* + ID_MODEL_FROM_DATABASE=HCF 56k PCI Speakerphone Modem + +pci:v0000127Ad00001032* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v0000127Ad00001033* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v0000127Ad00001034* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v0000127Ad00001035* + ID_MODEL_FROM_DATABASE=HCF 56k PCI Speakerphone Modem + +pci:v0000127Ad00001036* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v0000127Ad00001085* + ID_MODEL_FROM_DATABASE=HCF 56k Volcano PCI Modem + +pci:v0000127Ad00002004* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v0000127Ad00002005* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v0000127Ad00002005sv0000104Dsd00008044* + ID_MODEL_FROM_DATABASE=229-DFSV + +pci:v0000127Ad00002005sv0000104Dsd00008045* + ID_MODEL_FROM_DATABASE=229-DFSV + +pci:v0000127Ad00002005sv0000104Dsd00008055* + ID_MODEL_FROM_DATABASE=PBE/Aztech 235W-DFSV + +pci:v0000127Ad00002005sv0000104Dsd00008056* + ID_MODEL_FROM_DATABASE=235-DFSV + +pci:v0000127Ad00002005sv0000104Dsd0000805A* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00002005sv0000104Dsd0000805F* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00002005sv0000104Dsd00008074* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00002013* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem + +pci:v0000127Ad00002013sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00002013sv00001179sd0000FF00* + ID_MODEL_FROM_DATABASE=Modem + +pci:v0000127Ad00002014* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem + +pci:v0000127Ad00002014sv000010CFsd00001057* + ID_MODEL_FROM_DATABASE=Fujitsu Citicorp III + +pci:v0000127Ad00002014sv0000122Dsd00004050* + ID_MODEL_FROM_DATABASE=MSP3880-U + +pci:v0000127Ad00002014sv0000122Dsd00004055* + ID_MODEL_FROM_DATABASE=MSP3880-W + +pci:v0000127Ad00002015* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v0000127Ad00002015sv000010CFsd00001063* + ID_MODEL_FROM_DATABASE=Fujitsu + +pci:v0000127Ad00002015sv000010CFsd00001064* + ID_MODEL_FROM_DATABASE=Fujitsu + +pci:v0000127Ad00002015sv00001468sd00002015* + ID_MODEL_FROM_DATABASE=Fujitsu + +pci:v0000127Ad00002016* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem + +pci:v0000127Ad00002016sv0000122Dsd00004051* + ID_MODEL_FROM_DATABASE=MSP3880V-W + +pci:v0000127Ad00002016sv0000122Dsd00004052* + ID_MODEL_FROM_DATABASE=MSP3880SP-W + +pci:v0000127Ad00002016sv0000122Dsd00004054* + ID_MODEL_FROM_DATABASE=MSP3880V-U + +pci:v0000127Ad00002016sv0000122Dsd00004056* + ID_MODEL_FROM_DATABASE=MSP3880SP-U + +pci:v0000127Ad00002016sv0000122Dsd00004057* + ID_MODEL_FROM_DATABASE=MSP3880SP-A + +pci:v0000127Ad00004311* + ID_MODEL_FROM_DATABASE=Riptide HSF 56k PCI Modem + +pci:v0000127Ad00004311sv0000127Asd00004311* + ID_MODEL_FROM_DATABASE=Ring Modular? Riptide HSF RT HP Dom + +pci:v0000127Ad00004311sv000013E0sd00000210* + ID_MODEL_FROM_DATABASE=HP-GVC + +pci:v0000127Ad00004320* + ID_MODEL_FROM_DATABASE=Riptide PCI Audio Controller + +pci:v0000127Ad00004320sv00001235sd00004320* + ID_MODEL_FROM_DATABASE=Riptide PCI Audio Controller + +pci:v0000127Ad00004321* + ID_MODEL_FROM_DATABASE=Riptide HCF 56k PCI Modem + +pci:v0000127Ad00004321sv00001235sd00004321* + ID_MODEL_FROM_DATABASE=Hewlett Packard DF + +pci:v0000127Ad00004321sv00001235sd00004324* + ID_MODEL_FROM_DATABASE=Hewlett Packard DF + +pci:v0000127Ad00004321sv000013E0sd00000210* + ID_MODEL_FROM_DATABASE=Hewlett Packard DF + +pci:v0000127Ad00004321sv0000144Dsd00002321* + ID_MODEL_FROM_DATABASE=Riptide + +pci:v0000127Ad00004322* + ID_MODEL_FROM_DATABASE=Riptide PCI Game Controller + +pci:v0000127Ad00004322sv00001235sd00004322* + ID_MODEL_FROM_DATABASE=Riptide PCI Game Controller + +pci:v0000127Ad00008234* + ID_MODEL_FROM_DATABASE=RapidFire 616X ATM155 Adapter + +pci:v0000127Ad00008234sv0000108Dsd00000022* + ID_MODEL_FROM_DATABASE=RapidFire 616X ATM155 Adapter + +pci:v0000127Ad00008234sv0000108Dsd00000027* + ID_MODEL_FROM_DATABASE=RapidFire 616X ATM155 Adapter + +pci:v0000127B* + ID_VENDOR_FROM_DATABASE=Pixera Corporation + +pci:v0000127C* + ID_VENDOR_FROM_DATABASE=Crosspoint Solutions, Inc. + +pci:v0000127D* + ID_VENDOR_FROM_DATABASE=Vela Research + +pci:v0000127E* + ID_VENDOR_FROM_DATABASE=Winnov, L.P. + +pci:v0000127Ed00000010* + ID_MODEL_FROM_DATABASE=Videum 1000 Plus + +pci:v0000127F* + ID_VENDOR_FROM_DATABASE=Fujifilm + +pci:v00001280* + ID_VENDOR_FROM_DATABASE=Photoscript Group Ltd. + +pci:v00001281* + ID_VENDOR_FROM_DATABASE=Yokogawa Electric Corporation + +pci:v00001282* + ID_VENDOR_FROM_DATABASE=Davicom Semiconductor, Inc. + +pci:v00001282d00006585* + ID_MODEL_FROM_DATABASE=DM562P V90 Modem + +pci:v00001282d00009009* + ID_MODEL_FROM_DATABASE=Ethernet 100/10 MBit + +pci:v00001282d00009100* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001282d00009102* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001282d00009102sv00000291sd00008212* + ID_MODEL_FROM_DATABASE=DM9102A (DM9102AE, SM9102AF) Ethernet 100/10 MBit + +pci:v00001282d00009132* + ID_MODEL_FROM_DATABASE=Ethernet 100/10 MBit + +pci:v00001283* + ID_VENDOR_FROM_DATABASE=Integrated Technology Express, Inc. + +pci:v00001283d0000673A* + ID_MODEL_FROM_DATABASE=IT8330G + +pci:v00001283d00008152* + ID_MODEL_FROM_DATABASE=IT8152F/G Advanced RISC-to-PCI Companion Chip + +pci:v00001283d00008211* + ID_MODEL_FROM_DATABASE=ITE 8211F Single Channel UDMA 133 + +pci:v00001283d00008211sv00001043sd00008138* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00001283d00008212* + ID_MODEL_FROM_DATABASE=IT8212 Dual channel ATA RAID controller + +pci:v00001283d00008212sv00001283sd00000001* + ID_MODEL_FROM_DATABASE=IT/ITE8212 Dual channel ATA RAID controller + +pci:v00001283d00008213* + ID_MODEL_FROM_DATABASE=IT8213 IDE Controller + +pci:v00001283d00008213sv00001458sd0000B000* + ID_MODEL_FROM_DATABASE=GA-EG45M-DS2H Mainboard + +pci:v00001283d00008330* + ID_MODEL_FROM_DATABASE=IT8330G + +pci:v00001283d00008872* + ID_MODEL_FROM_DATABASE=IT8874F PCI Dual Serial Port Controller + +pci:v00001283d00008888* + ID_MODEL_FROM_DATABASE=IT8888F/G PCI to ISA Bridge with SMB [Golden Gate] + +pci:v00001283d00008889* + ID_MODEL_FROM_DATABASE=IT8889F PCI to ISA Bridge + +pci:v00001283d0000E886* + ID_MODEL_FROM_DATABASE=IT8330G + +pci:v00001284* + ID_VENDOR_FROM_DATABASE=Sahara Networks, Inc. + +pci:v00001285* + ID_VENDOR_FROM_DATABASE=Platform Technologies, Inc. + +pci:v00001285d00000100* + ID_MODEL_FROM_DATABASE=AGOGO sound chip (aka ESS Maestro 1) + +pci:v00001286* + ID_VENDOR_FROM_DATABASE=Mazet GmbH + +pci:v00001287* + ID_VENDOR_FROM_DATABASE=M-Pact, Inc. + +pci:v00001287d0000001E* + ID_MODEL_FROM_DATABASE=LS220D DVD Decoder + +pci:v00001287d0000001F* + ID_MODEL_FROM_DATABASE=LS220C DVD Decoder + +pci:v00001288* + ID_VENDOR_FROM_DATABASE=Timestep Corporation + +pci:v00001289* + ID_VENDOR_FROM_DATABASE=AVC Technology, Inc. + +pci:v0000128A* + ID_VENDOR_FROM_DATABASE=Asante Technologies, Inc. + +pci:v0000128B* + ID_VENDOR_FROM_DATABASE=Transwitch Corporation + +pci:v0000128C* + ID_VENDOR_FROM_DATABASE=Retix Corporation + +pci:v0000128D* + ID_VENDOR_FROM_DATABASE=G2 Networks, Inc. + +pci:v0000128Dd00000021* + ID_MODEL_FROM_DATABASE=ATM155 Adapter + +pci:v0000128E* + ID_VENDOR_FROM_DATABASE=Hoontech Corporation/Samho Multi Tech Ltd. + +pci:v0000128Ed00000008* + ID_MODEL_FROM_DATABASE=ST128 WSS/SB + +pci:v0000128Ed00000009* + ID_MODEL_FROM_DATABASE=ST128 SAM9407 + +pci:v0000128Ed0000000A* + ID_MODEL_FROM_DATABASE=ST128 Game Port + +pci:v0000128Ed0000000B* + ID_MODEL_FROM_DATABASE=ST128 MPU Port + +pci:v0000128Ed0000000C* + ID_MODEL_FROM_DATABASE=ST128 Ctrl Port + +pci:v0000128F* + ID_VENDOR_FROM_DATABASE=Tateno Dennou, Inc. + +pci:v00001290* + ID_VENDOR_FROM_DATABASE=Sord Computer Corporation + +pci:v00001291* + ID_VENDOR_FROM_DATABASE=NCS Computer Italia + +pci:v00001292* + ID_VENDOR_FROM_DATABASE=Tritech Microelectronics Inc + +pci:v00001292d0000FC02* + ID_MODEL_FROM_DATABASE=Pyramid3D TR25202 + +pci:v00001293* + ID_VENDOR_FROM_DATABASE=Media Reality Technology + +pci:v00001294* + ID_VENDOR_FROM_DATABASE=Rhetorex, Inc. + +pci:v00001295* + ID_VENDOR_FROM_DATABASE=Imagenation Corporation + +pci:v00001295d00000800* + ID_MODEL_FROM_DATABASE=PXR800 + +pci:v00001295d00001000* + ID_MODEL_FROM_DATABASE=PXD1000 + +pci:v00001296* + ID_VENDOR_FROM_DATABASE=Kofax Image Products + +pci:v00001297* + ID_VENDOR_FROM_DATABASE=Holco Enterprise Co, Ltd/Shuttle Computer + +pci:v00001298* + ID_VENDOR_FROM_DATABASE=Spellcaster Telecommunications Inc. + +pci:v00001299* + ID_VENDOR_FROM_DATABASE=Knowledge Technology Lab. + +pci:v0000129A* + ID_VENDOR_FROM_DATABASE=VMetro, inc. + +pci:v0000129Ad00000615* + ID_MODEL_FROM_DATABASE=PBT-615 PCI-X Bus Analyzer + +pci:v0000129Ad00001100* + ID_MODEL_FROM_DATABASE=PMC-FPGA05 + +pci:v0000129Ad00001106* + ID_MODEL_FROM_DATABASE=XMC-FPGA05F, PCI interface + +pci:v0000129Ad00001107* + ID_MODEL_FROM_DATABASE=XMC-FPGA05F, PCIe interface + +pci:v0000129Ad00001108* + ID_MODEL_FROM_DATABASE=XMC-FPGA05D, PCI interface + +pci:v0000129Ad00001109* + ID_MODEL_FROM_DATABASE=XMC-FPGA05D, PCIe interface + +pci:v0000129B* + ID_VENDOR_FROM_DATABASE=Image Access + +pci:v0000129C* + ID_VENDOR_FROM_DATABASE=Jaycor + +pci:v0000129D* + ID_VENDOR_FROM_DATABASE=Compcore Multimedia, Inc. + +pci:v0000129E* + ID_VENDOR_FROM_DATABASE=Victor Company of Japan, Ltd. + +pci:v0000129F* + ID_VENDOR_FROM_DATABASE=OEC Medical Systems, Inc. + +pci:v000012A0* + ID_VENDOR_FROM_DATABASE=Allen-Bradley Company + +pci:v000012A1* + ID_VENDOR_FROM_DATABASE=Simpact Associates, Inc. + +pci:v000012A2* + ID_VENDOR_FROM_DATABASE=Newgen Systems Corporation + +pci:v000012A3* + ID_VENDOR_FROM_DATABASE=Lucent Technologies + +pci:v000012A3d00008105* + ID_MODEL_FROM_DATABASE=T8105 H100 Digital Switch + +pci:v000012A4* + ID_VENDOR_FROM_DATABASE=NTT Electronics Technology Company + +pci:v000012A5* + ID_VENDOR_FROM_DATABASE=Vision Dynamics Ltd. + +pci:v000012A6* + ID_VENDOR_FROM_DATABASE=Scalable Networks, Inc. + +pci:v000012A7* + ID_VENDOR_FROM_DATABASE=AMO GmbH + +pci:v000012A8* + ID_VENDOR_FROM_DATABASE=News Datacom + +pci:v000012A9* + ID_VENDOR_FROM_DATABASE=Xiotech Corporation + +pci:v000012AA* + ID_VENDOR_FROM_DATABASE=SDL Communications, Inc. + +pci:v000012AB* + ID_VENDOR_FROM_DATABASE=Yuan Yuan Enterprise Co., Ltd. + +pci:v000012ABd00000000* + ID_MODEL_FROM_DATABASE=MPG160/Kuroutoshikou ITVC15-STVLP + +pci:v000012ABd00000002* + ID_MODEL_FROM_DATABASE=AU8830 [Vortex2] Based Sound Card With A3D Support + +pci:v000012ABd00000003* + ID_MODEL_FROM_DATABASE=T507 (DVB-T) TV tuner/capture device + +pci:v000012ABd00002300* + ID_MODEL_FROM_DATABASE=Club-3D Zap TV2100 + +pci:v000012ABd00003000* + ID_MODEL_FROM_DATABASE=MPG-200C PCI DVD Decoder Card + +pci:v000012ABd00004789* + ID_MODEL_FROM_DATABASE=MPC788 MiniPCI Hybrid TV Tuner + +pci:v000012ABd0000FFF3* + ID_MODEL_FROM_DATABASE=MPG600/Kuroutoshikou ITVC16-STVLP + +pci:v000012ABd0000FFFF* + ID_MODEL_FROM_DATABASE=MPG600/Kuroutoshikou ITVC16-STVLP + +pci:v000012AC* + ID_VENDOR_FROM_DATABASE=Measurex Corporation + +pci:v000012AD* + ID_VENDOR_FROM_DATABASE=Multidata GmbH + +pci:v000012AE* + ID_VENDOR_FROM_DATABASE=Alteon Networks Inc. + +pci:v000012AEd00000001* + ID_MODEL_FROM_DATABASE=AceNIC Gigabit Ethernet + +pci:v000012AEd00000001sv00001014sd00000104* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet-SX PCI Adapter + +pci:v000012AEd00000001sv000012AEsd00000001* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet-SX (Universal) + +pci:v000012AEd00000002* + ID_MODEL_FROM_DATABASE=AceNIC Gigabit Ethernet (Copper) + +pci:v000012AEd00000002sv000010A9sd00008002* + ID_MODEL_FROM_DATABASE=Acenic Gigabit Ethernet + +pci:v000012AEd00000002sv000012AEsd00000002* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet-T (3C986-T) + +pci:v000012AEd000000FA* + ID_MODEL_FROM_DATABASE=Farallon PN9100-T Gigabit Ethernet + +pci:v000012AF* + ID_VENDOR_FROM_DATABASE=TDK USA Corp + +pci:v000012B0* + ID_VENDOR_FROM_DATABASE=Jorge Scientific Corp + +pci:v000012B1* + ID_VENDOR_FROM_DATABASE=GammaLink + +pci:v000012B2* + ID_VENDOR_FROM_DATABASE=General Signal Networks + +pci:v000012B3* + ID_VENDOR_FROM_DATABASE=Inter-Face Co Ltd + +pci:v000012B4* + ID_VENDOR_FROM_DATABASE=FutureTel Inc + +pci:v000012B5* + ID_VENDOR_FROM_DATABASE=Granite Systems Inc. + +pci:v000012B6* + ID_VENDOR_FROM_DATABASE=Natural Microsystems + +pci:v000012B7* + ID_VENDOR_FROM_DATABASE=Cognex Modular Vision Systems Div. - Acumen Inc. + +pci:v000012B8* + ID_VENDOR_FROM_DATABASE=Korg + +pci:v000012B9* + ID_VENDOR_FROM_DATABASE=3Com Corp, Modem Division + +pci:v000012B9d00001006* + ID_MODEL_FROM_DATABASE=WinModem + +pci:v000012B9d00001006sv000012B9sd0000005C* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Model 3472) + +pci:v000012B9d00001006sv000012B9sd0000005E* + ID_MODEL_FROM_DATABASE=USR 56k Internal WinModem (Models 662975) + +pci:v000012B9d00001006sv000012B9sd00000062* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Model 662978) + +pci:v000012B9d00001006sv000012B9sd00000068* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Model 5690) + +pci:v000012B9d00001006sv000012B9sd0000007A* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Model 662974) + +pci:v000012B9d00001006sv000012B9sd0000007F* + ID_MODEL_FROM_DATABASE=USR 56k Internal WinModem (Models 5698, 5699) + +pci:v000012B9d00001006sv000012B9sd00000080* + ID_MODEL_FROM_DATABASE=USR 56k Internal WinModem (Models 2975, 3528) + +pci:v000012B9d00001006sv000012B9sd00000081* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Models 2974, 3529) + +pci:v000012B9d00001006sv000012B9sd00000091* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice WinModem (Model 2978) + +pci:v000012B9d00001007* + ID_MODEL_FROM_DATABASE=USR 56k Internal WinModem + +pci:v000012B9d00001007sv000012B9sd000000A3* + ID_MODEL_FROM_DATABASE=USR 56k Internal WinModem (Model 3595) + +pci:v000012B9d00001007sv000012B9sd000000C4* + ID_MODEL_FROM_DATABASE=U.S. Robotics V.92 Voice Faxmodem (2884A/B/C) + +pci:v000012B9d00001008* + ID_MODEL_FROM_DATABASE=56K FaxModem Model 5610 + +pci:v000012B9d00001008sv000012B9sd000000A2* + ID_MODEL_FROM_DATABASE=USR 56k Internal FAX Modem (Model 2977) + +pci:v000012B9d00001008sv000012B9sd000000AA* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice Modem (Model 2976) + +pci:v000012B9d00001008sv000012B9sd000000AB* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice Modem (Model 5609) + +pci:v000012B9d00001008sv000012B9sd000000AC* + ID_MODEL_FROM_DATABASE=USR 56k Internal Voice Modem (Model 3298) + +pci:v000012B9d00001008sv000012B9sd000000AD* + ID_MODEL_FROM_DATABASE=USR 56k Internal FAX Modem (Model 5610) + +pci:v000012B9d00001008sv000012B9sd000000D3* + ID_MODEL_FROM_DATABASE=USR 56K Internal V92 FAX Modem (Model 5610) + +pci:v000012B9d00001008sv000012B9sd0000BABA* + ID_MODEL_FROM_DATABASE=USR 56K Internal Voice Modem 3CP3298-DEL (Model 5601) [Hawk] + +pci:v000012BA* + ID_VENDOR_FROM_DATABASE=BittWare, Inc. + +pci:v000012BB* + ID_VENDOR_FROM_DATABASE=Nippon Unisoft Corporation + +pci:v000012BC* + ID_VENDOR_FROM_DATABASE=Array Microsystems + +pci:v000012BD* + ID_VENDOR_FROM_DATABASE=Computerm Corp. + +pci:v000012BE* + ID_VENDOR_FROM_DATABASE=Anchor Chips Inc. + +pci:v000012BEd00003041* + ID_MODEL_FROM_DATABASE=AN3041Q CO-MEM + +pci:v000012BEd00003042* + ID_MODEL_FROM_DATABASE=AN3042Q CO-MEM Lite + +pci:v000012BEd00003042sv000012BEsd00003042* + ID_MODEL_FROM_DATABASE=Anchor Chips Lite Evaluation Board + +pci:v000012BF* + ID_VENDOR_FROM_DATABASE=Fujifilm Microdevices + +pci:v000012C0* + ID_VENDOR_FROM_DATABASE=Infimed + +pci:v000012C1* + ID_VENDOR_FROM_DATABASE=GMM Research Corp + +pci:v000012C2* + ID_VENDOR_FROM_DATABASE=Mentec Limited + +pci:v000012C3* + ID_VENDOR_FROM_DATABASE=Holtek Microelectronics Inc + +pci:v000012C3d00000058* + ID_MODEL_FROM_DATABASE=PCI NE2K Ethernet + +pci:v000012C3d00005598* + ID_MODEL_FROM_DATABASE=PCI NE2K Ethernet + +pci:v000012C4* + ID_VENDOR_FROM_DATABASE=Connect Tech Inc + +pci:v000012C4d00000001* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 8 (RS232/CL/RJ11) + +pci:v000012C4d00000002* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 4 (RS232) + +pci:v000012C4d00000003* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2 (RS232) + +pci:v000012C4d00000004* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 8 (UNIV, RS485) + +pci:v000012C4d00000005* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 4+4/6+2 (UNIV, RS232/485) + +pci:v000012C4d00000006* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 4 (OPTO, RS485) + +pci:v000012C4d00000007* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2+2 (RS232/485) + +pci:v000012C4d00000008* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2 (OPTO, Tx, RS485) + +pci:v000012C4d00000009* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2+6 (RS232/485) + +pci:v000012C4d0000000A* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 8 (Tx, RS485) + +pci:v000012C4d0000000B* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 4 (Tx, RS485) + +pci:v000012C4d0000000C* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2 (20 MHz, RS485) + +pci:v000012C4d0000000D* + ID_MODEL_FROM_DATABASE=Blue HEAT/PCI 2 PTM + +pci:v000012C4d00000100* + ID_MODEL_FROM_DATABASE=NT960/PCI + +pci:v000012C4d00000201* + ID_MODEL_FROM_DATABASE=cPCI Titan - 2 Port + +pci:v000012C4d00000202* + ID_MODEL_FROM_DATABASE=cPCI Titan - 4 Port + +pci:v000012C4d00000300* + ID_MODEL_FROM_DATABASE=CTI PCI UART 2 (RS232) + +pci:v000012C4d00000301* + ID_MODEL_FROM_DATABASE=CTI PCI UART 4 (RS232) + +pci:v000012C4d00000302* + ID_MODEL_FROM_DATABASE=CTI PCI UART 8 (RS232) + +pci:v000012C4d00000310* + ID_MODEL_FROM_DATABASE=CTI PCI UART 1+1 (RS232/485) + +pci:v000012C4d00000311* + ID_MODEL_FROM_DATABASE=CTI PCI UART 2+2 (RS232/485) + +pci:v000012C4d00000312* + ID_MODEL_FROM_DATABASE=CTI PCI UART 4+4 (RS232/485) + +pci:v000012C4d00000320* + ID_MODEL_FROM_DATABASE=CTI PCI UART 2 + +pci:v000012C4d00000321* + ID_MODEL_FROM_DATABASE=CTI PCI UART 4 + +pci:v000012C4d00000322* + ID_MODEL_FROM_DATABASE=CTI PCI UART 8 + +pci:v000012C4d00000330* + ID_MODEL_FROM_DATABASE=CTI PCI UART 2 (RS485) + +pci:v000012C4d00000331* + ID_MODEL_FROM_DATABASE=CTI PCI UART 4 (RS485) + +pci:v000012C4d00000332* + ID_MODEL_FROM_DATABASE=CTI PCI UART 8 (RS485) + +pci:v000012C5* + ID_VENDOR_FROM_DATABASE=Picture Elements Incorporated + +pci:v000012C5d0000007E* + ID_MODEL_FROM_DATABASE=Imaging/Scanning Subsystem Engine + +pci:v000012C5d0000007F* + ID_MODEL_FROM_DATABASE=Imaging/Scanning Subsystem Engine + +pci:v000012C5d00000081* + ID_MODEL_FROM_DATABASE=PCIVST [Grayscale Thresholding Engine] + +pci:v000012C5d00000085* + ID_MODEL_FROM_DATABASE=Video Simulator/Sender + +pci:v000012C5d00000086* + ID_MODEL_FROM_DATABASE=THR2 Multi-scale Thresholder + +pci:v000012C6* + ID_VENDOR_FROM_DATABASE=Mitani Corporation + +pci:v000012C7* + ID_VENDOR_FROM_DATABASE=Dialogic Corp + +pci:v000012C7d00000546* + ID_MODEL_FROM_DATABASE=Springware D/120JCT-LS + +pci:v000012C7d00000647* + ID_MODEL_FROM_DATABASE=Springware D/240JCT-T1 + +pci:v000012C7d00000676* + ID_MODEL_FROM_DATABASE=Springware D/41JCT-LS + +pci:v000012C7d00000685* + ID_MODEL_FROM_DATABASE=Springware D/480JCT-2T1 + +pci:v000012C8* + ID_VENDOR_FROM_DATABASE=G Force Co, Ltd + +pci:v000012C9* + ID_VENDOR_FROM_DATABASE=Gigi Operations + +pci:v000012CA* + ID_VENDOR_FROM_DATABASE=Integrated Computing Engines + +pci:v000012CB* + ID_VENDOR_FROM_DATABASE=Antex Electronics Corporation + +pci:v000012CBd00000027* + ID_MODEL_FROM_DATABASE=SC4 (StudioCard) + +pci:v000012CBd0000002E* + ID_MODEL_FROM_DATABASE=StudioCard 2000 + +pci:v000012CC* + ID_VENDOR_FROM_DATABASE=Pluto Technologies International + +pci:v000012CD* + ID_VENDOR_FROM_DATABASE=Aims Lab + +pci:v000012CE* + ID_VENDOR_FROM_DATABASE=Netspeed Inc. + +pci:v000012CF* + ID_VENDOR_FROM_DATABASE=Prophet Systems, Inc. + +pci:v000012D0* + ID_VENDOR_FROM_DATABASE=GDE Systems, Inc. + +pci:v000012D1* + ID_VENDOR_FROM_DATABASE=PSITech + +pci:v000012D2* + ID_VENDOR_FROM_DATABASE=NVidia / SGS Thomson (Joint Venture) + +pci:v000012D2d00000008* + ID_MODEL_FROM_DATABASE=NV1 + +pci:v000012D2d00000009* + ID_MODEL_FROM_DATABASE=DAC64 + +pci:v000012D2d00000018* + ID_MODEL_FROM_DATABASE=Riva128 + +pci:v000012D2d00000018sv00001048sd00000C10* + ID_MODEL_FROM_DATABASE=VICTORY Erazor + +pci:v000012D2d00000018sv0000107Bsd00008030* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv00001092sd00000350* + ID_MODEL_FROM_DATABASE=Viper V330 + +pci:v000012D2d00000018sv00001092sd00001092* + ID_MODEL_FROM_DATABASE=Viper V330 + +pci:v000012D2d00000018sv000010B4sd00001B1B* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv000010B4sd00001B1D* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv000010B4sd00001B1E* + ID_MODEL_FROM_DATABASE=STB Velocity 128, PAL TV-Out + +pci:v000012D2d00000018sv000010B4sd00001B20* + ID_MODEL_FROM_DATABASE=STB Velocity 128 Sapphire + +pci:v000012D2d00000018sv000010B4sd00001B21* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv000010B4sd00001B22* + ID_MODEL_FROM_DATABASE=STB Velocity 128 AGP, NTSC TV-Out + +pci:v000012D2d00000018sv000010B4sd00001B23* + ID_MODEL_FROM_DATABASE=STB Velocity 128 AGP, PAL TV-Out + +pci:v000012D2d00000018sv000010B4sd00001B27* + ID_MODEL_FROM_DATABASE=STB Velocity 128 DVD + +pci:v000012D2d00000018sv000010B4sd00001B88* + ID_MODEL_FROM_DATABASE=MVP Pro 128 + +pci:v000012D2d00000018sv000010B4sd0000222A* + ID_MODEL_FROM_DATABASE=STB Velocity 128 AGP + +pci:v000012D2d00000018sv000010B4sd00002230* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv000010B4sd00002232* + ID_MODEL_FROM_DATABASE=STB Velocity 128 + +pci:v000012D2d00000018sv000010B4sd00002235* + ID_MODEL_FROM_DATABASE=STB Velocity 128 AGP + +pci:v000012D2d00000018sv00002A15sd000054A3* + ID_MODEL_FROM_DATABASE=3DVision-SAGP / 3DexPlorer 3000 + +pci:v000012D2d00000019* + ID_MODEL_FROM_DATABASE=Riva128ZX + +pci:v000012D2d00000020* + ID_MODEL_FROM_DATABASE=TNT + +pci:v000012D2d00000028* + ID_MODEL_FROM_DATABASE=TNT2 + +pci:v000012D2d00000029* + ID_MODEL_FROM_DATABASE=UTNT2 + +pci:v000012D2d0000002C* + ID_MODEL_FROM_DATABASE=VTNT2 + +pci:v000012D2d000000A0* + ID_MODEL_FROM_DATABASE=ITNT2 + +pci:v000012D3* + ID_VENDOR_FROM_DATABASE=Vingmed Sound A/S + +pci:v000012D4* + ID_VENDOR_FROM_DATABASE=Ulticom (Formerly DGM&S) + +pci:v000012D4d00000200* + ID_MODEL_FROM_DATABASE=T1 Card + +pci:v000012D5* + ID_VENDOR_FROM_DATABASE=Equator Technologies Inc + +pci:v000012D5d00000003* + ID_MODEL_FROM_DATABASE=BSP16 + +pci:v000012D5d00001000* + ID_MODEL_FROM_DATABASE=BSP15 + +pci:v000012D6* + ID_VENDOR_FROM_DATABASE=Analogic Corp + +pci:v000012D7* + ID_VENDOR_FROM_DATABASE=Biotronic SRL + +pci:v000012D8* + ID_VENDOR_FROM_DATABASE=Pericom Semiconductor + +pci:v000012D8d000001A7* + ID_MODEL_FROM_DATABASE=PI7C21P100 PCI to PCI Bridge + +pci:v000012D8d0000400A* + ID_MODEL_FROM_DATABASE=PI7C9X442SL PCI Express Bridge Port + +pci:v000012D8d0000400E* + ID_MODEL_FROM_DATABASE=PI7C9X442SL USB OHCI Controller + +pci:v000012D8d0000400F* + ID_MODEL_FROM_DATABASE=PI7C9X442SL USB EHCI Controller + +pci:v000012D8d000071E2* + ID_MODEL_FROM_DATABASE=PI7C7300A/PI7C7300D PCI-to-PCI Bridge + +pci:v000012D8d000071E3* + ID_MODEL_FROM_DATABASE=PI7C7300A/PI7C7300D PCI-to-PCI Bridge (Secondary Bus 2) + +pci:v000012D8d00008140* + ID_MODEL_FROM_DATABASE=PI7C8140A PCI-to-PCI Bridge + +pci:v000012D8d00008148* + ID_MODEL_FROM_DATABASE=PI7C8148A/PI7C8148B PCI-to-PCI Bridge + +pci:v000012D8d00008150* + ID_MODEL_FROM_DATABASE=PCI to PCI Bridge + +pci:v000012D8d00008152* + ID_MODEL_FROM_DATABASE=PI7C8152A/PI7C8152B/PI7C8152BI PCI-to-PCI Bridge + +pci:v000012D8d00008154* + ID_MODEL_FROM_DATABASE=PI7C8154A/PI7C8154B/PI7C8154BI PCI-to-PCI Bridge + +pci:v000012D8d0000E110* + ID_MODEL_FROM_DATABASE=PI7C9X110 PCI Express to PCI bridge + +pci:v000012D8d0000E110sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 CompactPCI Bridge + +pci:v000012D8d0000E111* + ID_MODEL_FROM_DATABASE=PI7C9X111SL PCIe-to-PCI Reversible Bridge + +pci:v000012D8d0000E130* + ID_MODEL_FROM_DATABASE=PCI Express to PCI-XPI7C9X130 PCI-X Bridge + +pci:v000012D9* + ID_VENDOR_FROM_DATABASE=Aculab PLC + +pci:v000012D9d00000002* + ID_MODEL_FROM_DATABASE=PCI Prosody + +pci:v000012D9d00000004* + ID_MODEL_FROM_DATABASE=cPCI Prosody + +pci:v000012D9d00000005* + ID_MODEL_FROM_DATABASE=Aculab E1/T1 PCI card + +pci:v000012D9d00001078* + ID_MODEL_FROM_DATABASE=Prosody X class e1000 device + +pci:v000012D9d00001078sv000012D9sd0000000D* + ID_MODEL_FROM_DATABASE=Prosody X PCI + +pci:v000012D9d00001078sv000012D9sd0000000E* + ID_MODEL_FROM_DATABASE=Prosody X cPCI + +pci:v000012DA* + ID_VENDOR_FROM_DATABASE=True Time Inc. + +pci:v000012DB* + ID_VENDOR_FROM_DATABASE=Annapolis Micro Systems, Inc + +pci:v000012DC* + ID_VENDOR_FROM_DATABASE=Symicron Computer Communication Ltd. + +pci:v000012DD* + ID_VENDOR_FROM_DATABASE=Management Graphics + +pci:v000012DE* + ID_VENDOR_FROM_DATABASE=Rainbow Technologies + +pci:v000012DEd00000200* + ID_MODEL_FROM_DATABASE=CryptoSwift CS200 + +pci:v000012DF* + ID_VENDOR_FROM_DATABASE=SBS Technologies Inc + +pci:v000012E0* + ID_VENDOR_FROM_DATABASE=Chase Research + +pci:v000012E0d00000010* + ID_MODEL_FROM_DATABASE=ST16C654 Quad UART + +pci:v000012E0d00000020* + ID_MODEL_FROM_DATABASE=ST16C654 Quad UART + +pci:v000012E0d00000030* + ID_MODEL_FROM_DATABASE=ST16C654 Quad UART + +pci:v000012E1* + ID_VENDOR_FROM_DATABASE=Nintendo Co, Ltd + +pci:v000012E2* + ID_VENDOR_FROM_DATABASE=Datum Inc. Bancomm-Timing Division + +pci:v000012E3* + ID_VENDOR_FROM_DATABASE=Imation Corp - Medical Imaging Systems + +pci:v000012E4* + ID_VENDOR_FROM_DATABASE=Brooktrout Technology Inc + +pci:v000012E5* + ID_VENDOR_FROM_DATABASE=Apex Semiconductor Inc + +pci:v000012E6* + ID_VENDOR_FROM_DATABASE=Cirel Systems + +pci:v000012E7* + ID_VENDOR_FROM_DATABASE=Sunsgroup Corporation + +pci:v000012E8* + ID_VENDOR_FROM_DATABASE=Crisc Corp + +pci:v000012E9* + ID_VENDOR_FROM_DATABASE=GE Spacenet + +pci:v000012EA* + ID_VENDOR_FROM_DATABASE=Zuken + +pci:v000012EB* + ID_VENDOR_FROM_DATABASE=Aureal Semiconductor + +pci:v000012EBd00000001* + ID_MODEL_FROM_DATABASE=Vortex 1 + +pci:v000012EBd00000001sv0000104Dsd00008036* + ID_MODEL_FROM_DATABASE=AU8820 Vortex Digital Audio Processor + +pci:v000012EBd00000001sv00001092sd00002000* + ID_MODEL_FROM_DATABASE=Sonic Impact A3D + +pci:v000012EBd00000001sv00001092sd00002100* + ID_MODEL_FROM_DATABASE=Sonic Impact A3D + +pci:v000012EBd00000001sv00001092sd00002110* + ID_MODEL_FROM_DATABASE=Sonic Impact A3D + +pci:v000012EBd00000001sv00001092sd00002200* + ID_MODEL_FROM_DATABASE=Sonic Impact A3D + +pci:v000012EBd00000001sv0000122Dsd00001002* + ID_MODEL_FROM_DATABASE=AU8820 Vortex Digital Audio Processor + +pci:v000012EBd00000001sv000012EBsd00000001* + ID_MODEL_FROM_DATABASE=AU8820 Vortex Digital Audio Processor + +pci:v000012EBd00000001sv00005053sd00003355* + ID_MODEL_FROM_DATABASE=Montego + +pci:v000012EBd00000001sv000050B2sd00001111* + ID_MODEL_FROM_DATABASE=XLerate + +pci:v000012EBd00000002* + ID_MODEL_FROM_DATABASE=Vortex 2 + +pci:v000012EBd00000002sv0000104Dsd00008049* + ID_MODEL_FROM_DATABASE=AU8830 Vortex 3D Digital Audio Processor + +pci:v000012EBd00000002sv0000104Dsd0000807B* + ID_MODEL_FROM_DATABASE=AU8830 Vortex 3D Digital Audio Processor + +pci:v000012EBd00000002sv00001092sd00003000* + ID_MODEL_FROM_DATABASE=Monster Sound II + +pci:v000012EBd00000002sv00001092sd00003001* + ID_MODEL_FROM_DATABASE=Monster Sound II + +pci:v000012EBd00000002sv00001092sd00003002* + ID_MODEL_FROM_DATABASE=Monster Sound II + +pci:v000012EBd00000002sv00001092sd00003003* + ID_MODEL_FROM_DATABASE=Monster Sound II + +pci:v000012EBd00000002sv00001092sd00003004* + ID_MODEL_FROM_DATABASE=Monster Sound II + +pci:v000012EBd00000002sv000012EBsd00000002* + ID_MODEL_FROM_DATABASE=AU8830 Vortex 3D Digital Audio Processor + +pci:v000012EBd00000002sv000012EBsd00000088* + ID_MODEL_FROM_DATABASE=AU8830 Vortex 3D Digital Audio Processor + +pci:v000012EBd00000002sv0000144Dsd00003510* + ID_MODEL_FROM_DATABASE=AU8830 Vortex 3D Digital Audio Processor + +pci:v000012EBd00000002sv00005053sd00003356* + ID_MODEL_FROM_DATABASE=Montego II + +pci:v000012EBd00000003* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv0000104Dsd00008049* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv0000104Dsd00008077* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv0000109Fsd00001000* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv000012EBsd00000003* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv00001462sd00006780* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv000014A4sd00002073* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv000014A4sd00002091* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv000014A4sd00002104* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00000003sv000014A4sd00002106* + ID_MODEL_FROM_DATABASE=AU8810 Vortex Digital Audio Processor + +pci:v000012EBd00008803* + ID_MODEL_FROM_DATABASE=Vortex 56k Software Modem + +pci:v000012EBd00008803sv000012EBsd00008803* + ID_MODEL_FROM_DATABASE=Vortex 56k Software Modem + +pci:v000012EC* + ID_VENDOR_FROM_DATABASE=3A International, Inc. + +pci:v000012ED* + ID_VENDOR_FROM_DATABASE=Optivision Inc. + +pci:v000012EE* + ID_VENDOR_FROM_DATABASE=Orange Micro + +pci:v000012EF* + ID_VENDOR_FROM_DATABASE=Vienna Systems + +pci:v000012F0* + ID_VENDOR_FROM_DATABASE=Pentek + +pci:v000012F1* + ID_VENDOR_FROM_DATABASE=Sorenson Vision Inc + +pci:v000012F2* + ID_VENDOR_FROM_DATABASE=Gammagraphx, Inc. + +pci:v000012F3* + ID_VENDOR_FROM_DATABASE=Radstone Technology + +pci:v000012F4* + ID_VENDOR_FROM_DATABASE=Megatel + +pci:v000012F5* + ID_VENDOR_FROM_DATABASE=Forks + +pci:v000012F6* + ID_VENDOR_FROM_DATABASE=Dawson France + +pci:v000012F7* + ID_VENDOR_FROM_DATABASE=Cognex + +pci:v000012F8* + ID_VENDOR_FROM_DATABASE=Electronic Design GmbH + +pci:v000012F8d00000002* + ID_MODEL_FROM_DATABASE=VideoMaker + +pci:v000012F9* + ID_VENDOR_FROM_DATABASE=Four Fold Ltd + +pci:v000012FB* + ID_VENDOR_FROM_DATABASE=Spectrum Signal Processing + +pci:v000012FBd00000001* + ID_MODEL_FROM_DATABASE=PMC-MAI + +pci:v000012FBd000000F5* + ID_MODEL_FROM_DATABASE=F5 Dakar + +pci:v000012FBd000002AD* + ID_MODEL_FROM_DATABASE=PMC-2MAI + +pci:v000012FBd00002ADC* + ID_MODEL_FROM_DATABASE=ePMC-2ADC + +pci:v000012FBd00003100* + ID_MODEL_FROM_DATABASE=PRO-3100 + +pci:v000012FBd00003500* + ID_MODEL_FROM_DATABASE=PRO-3500 + +pci:v000012FBd00004D4F* + ID_MODEL_FROM_DATABASE=Modena + +pci:v000012FBd00008120* + ID_MODEL_FROM_DATABASE=ePMC-8120 + +pci:v000012FBd0000DA62* + ID_MODEL_FROM_DATABASE=Daytona C6201 PCI (Hurricane) + +pci:v000012FBd0000DB62* + ID_MODEL_FROM_DATABASE=Ingliston XBIF + +pci:v000012FBd0000DC62* + ID_MODEL_FROM_DATABASE=Ingliston PLX9054 + +pci:v000012FBd0000DD62* + ID_MODEL_FROM_DATABASE=Ingliston JTAG/ISP + +pci:v000012FBd0000EDDC* + ID_MODEL_FROM_DATABASE=ePMC-MSDDC + +pci:v000012FBd0000FA01* + ID_MODEL_FROM_DATABASE=ePMC-FPGA + +pci:v000012FC* + ID_VENDOR_FROM_DATABASE=Capital Equipment Corp + +pci:v000012FD* + ID_VENDOR_FROM_DATABASE=I2S + +pci:v000012FE* + ID_VENDOR_FROM_DATABASE=ESD Electronic System Design GmbH + +pci:v000012FF* + ID_VENDOR_FROM_DATABASE=Lexicon + +pci:v00001300* + ID_VENDOR_FROM_DATABASE=Harman International Industries Inc + +pci:v00001302* + ID_VENDOR_FROM_DATABASE=Computer Sciences Corp + +pci:v00001303* + ID_VENDOR_FROM_DATABASE=Innovative Integration + +pci:v00001303d00000030* + ID_MODEL_FROM_DATABASE=X3-SDF 4-channel XMC acquisition board + +pci:v00001304* + ID_VENDOR_FROM_DATABASE=Juniper Networks + +pci:v00001305* + ID_VENDOR_FROM_DATABASE=Netphone, Inc + +pci:v00001306* + ID_VENDOR_FROM_DATABASE=Duet Technologies + +pci:v00001307* + ID_VENDOR_FROM_DATABASE=Measurement Computing + +pci:v00001307d00000001* + ID_MODEL_FROM_DATABASE=PCI-DAS1602/16 + +pci:v00001307d0000000B* + ID_MODEL_FROM_DATABASE=PCI-DIO48H + +pci:v00001307d0000000C* + ID_MODEL_FROM_DATABASE=PCI-PDISO8 + +pci:v00001307d0000000D* + ID_MODEL_FROM_DATABASE=PCI-PDISO16 + +pci:v00001307d0000000F* + ID_MODEL_FROM_DATABASE=PCI-DAS1200 + +pci:v00001307d00000010* + ID_MODEL_FROM_DATABASE=PCI-DAS1602/12 + +pci:v00001307d00000014* + ID_MODEL_FROM_DATABASE=PCI-DIO24H + +pci:v00001307d00000015* + ID_MODEL_FROM_DATABASE=PCI-DIO24H/CTR3 + +pci:v00001307d00000016* + ID_MODEL_FROM_DATABASE=PCI-DIO48H/CTR15 + +pci:v00001307d00000017* + ID_MODEL_FROM_DATABASE=PCI-DIO96H + +pci:v00001307d00000018* + ID_MODEL_FROM_DATABASE=PCI-CTR05 + +pci:v00001307d00000019* + ID_MODEL_FROM_DATABASE=PCI-DAS1200/JR + +pci:v00001307d0000001A* + ID_MODEL_FROM_DATABASE=PCI-DAS1001 + +pci:v00001307d0000001B* + ID_MODEL_FROM_DATABASE=PCI-DAS1002 + +pci:v00001307d0000001C* + ID_MODEL_FROM_DATABASE=PCI-DAS1602JR/16 + +pci:v00001307d0000001D* + ID_MODEL_FROM_DATABASE=PCI-DAS6402/16 + +pci:v00001307d0000001E* + ID_MODEL_FROM_DATABASE=PCI-DAS6402/12 + +pci:v00001307d0000001F* + ID_MODEL_FROM_DATABASE=PCI-DAS16/M1 + +pci:v00001307d00000020* + ID_MODEL_FROM_DATABASE=PCI-DDA02/12 + +pci:v00001307d00000021* + ID_MODEL_FROM_DATABASE=PCI-DDA04/12 + +pci:v00001307d00000022* + ID_MODEL_FROM_DATABASE=PCI-DDA08/12 + +pci:v00001307d00000023* + ID_MODEL_FROM_DATABASE=PCI-DDA02/16 + +pci:v00001307d00000024* + ID_MODEL_FROM_DATABASE=PCI-DDA04/16 + +pci:v00001307d00000025* + ID_MODEL_FROM_DATABASE=PCI-DDA08/16 + +pci:v00001307d00000026* + ID_MODEL_FROM_DATABASE=PCI-DAC04/12-HS + +pci:v00001307d00000027* + ID_MODEL_FROM_DATABASE=PCI-DAC04/16-HS + +pci:v00001307d00000028* + ID_MODEL_FROM_DATABASE=PCI-DIO24 + +pci:v00001307d00000029* + ID_MODEL_FROM_DATABASE=PCI-DAS08 + +pci:v00001307d0000002C* + ID_MODEL_FROM_DATABASE=PCI-INT32 + +pci:v00001307d00000033* + ID_MODEL_FROM_DATABASE=PCI-DUAL-AC5 + +pci:v00001307d00000034* + ID_MODEL_FROM_DATABASE=PCI-DAS-TC + +pci:v00001307d00000035* + ID_MODEL_FROM_DATABASE=PCI-DAS64/M1/16 + +pci:v00001307d00000036* + ID_MODEL_FROM_DATABASE=PCI-DAS64/M2/16 + +pci:v00001307d00000037* + ID_MODEL_FROM_DATABASE=PCI-DAS64/M3/16 + +pci:v00001307d0000004C* + ID_MODEL_FROM_DATABASE=PCI-DAS1000 + +pci:v00001307d0000004D* + ID_MODEL_FROM_DATABASE=PCI-QUAD04 + +pci:v00001307d00000052* + ID_MODEL_FROM_DATABASE=PCI-DAS4020/12 + +pci:v00001307d00000053* + ID_MODEL_FROM_DATABASE=PCIM-DDA06/16 + +pci:v00001307d00000054* + ID_MODEL_FROM_DATABASE=PCI-DIO96 + +pci:v00001307d0000005D* + ID_MODEL_FROM_DATABASE=PCI-DAS6023 + +pci:v00001307d0000005E* + ID_MODEL_FROM_DATABASE=PCI-DAS6025 + +pci:v00001307d0000005F* + ID_MODEL_FROM_DATABASE=PCI-DAS6030 + +pci:v00001307d00000060* + ID_MODEL_FROM_DATABASE=PCI-DAS6031 + +pci:v00001307d00000061* + ID_MODEL_FROM_DATABASE=PCI-DAS6032 + +pci:v00001307d00000062* + ID_MODEL_FROM_DATABASE=PCI-DAS6033 + +pci:v00001307d00000063* + ID_MODEL_FROM_DATABASE=PCI-DAS6034 + +pci:v00001307d00000064* + ID_MODEL_FROM_DATABASE=PCI-DAS6035 + +pci:v00001307d00000065* + ID_MODEL_FROM_DATABASE=PCI-DAS6040 + +pci:v00001307d00000066* + ID_MODEL_FROM_DATABASE=PCI-DAS6052 + +pci:v00001307d00000067* + ID_MODEL_FROM_DATABASE=PCI-DAS6070 + +pci:v00001307d00000068* + ID_MODEL_FROM_DATABASE=PCI-DAS6071 + +pci:v00001307d0000006F* + ID_MODEL_FROM_DATABASE=PCI-DAS6036 + +pci:v00001307d00000070* + ID_MODEL_FROM_DATABASE=PCI-DAC6702 + +pci:v00001307d00000078* + ID_MODEL_FROM_DATABASE=PCI-DAS6013 + +pci:v00001307d00000079* + ID_MODEL_FROM_DATABASE=PCI-DAS6014 + +pci:v00001307d00000115* + ID_MODEL_FROM_DATABASE=PCIe-DAS1602/16 + +pci:v00001308* + ID_VENDOR_FROM_DATABASE=Jato Technologies Inc. + +pci:v00001308d00000001* + ID_MODEL_FROM_DATABASE=NetCelerator Adapter + +pci:v00001308d00000001sv00001308sd00000001* + ID_MODEL_FROM_DATABASE=NetCelerator Adapter + +pci:v00001309* + ID_VENDOR_FROM_DATABASE=AB Semiconductor Ltd + +pci:v0000130A* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Microcomputer + +pci:v0000130B* + ID_VENDOR_FROM_DATABASE=Colorgraphic Communications Corp + +pci:v0000130C* + ID_VENDOR_FROM_DATABASE=Ambex Technologies, Inc + +pci:v0000130D* + ID_VENDOR_FROM_DATABASE=Accelerix Inc + +pci:v0000130E* + ID_VENDOR_FROM_DATABASE=Yamatake-Honeywell Co. Ltd + +pci:v0000130F* + ID_VENDOR_FROM_DATABASE=Advanet Inc + +pci:v00001310* + ID_VENDOR_FROM_DATABASE=Gespac + +pci:v00001311* + ID_VENDOR_FROM_DATABASE=Videoserver, Inc + +pci:v00001312* + ID_VENDOR_FROM_DATABASE=Acuity Imaging, Inc + +pci:v00001313* + ID_VENDOR_FROM_DATABASE=Yaskawa Electric Co. + +pci:v00001315* + ID_VENDOR_FROM_DATABASE=Wavesat + +pci:v00001316* + ID_VENDOR_FROM_DATABASE=Teradyne Inc + +pci:v00001317* + ID_VENDOR_FROM_DATABASE=ADMtek + +pci:v00001317d00000981* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001317d00000985* + ID_MODEL_FROM_DATABASE=NC100 Network Everywhere Fast Ethernet 10/100 + +pci:v00001317d00000985sv00001734sd0000100C* + ID_MODEL_FROM_DATABASE=Scenic N300 ADMtek AN983 10/100 Mbps PCI Adapter + +pci:v00001317d00001985* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001317d00001985sv00001385sd0000511A* + ID_MODEL_FROM_DATABASE=FA511 + +pci:v00001317d00001985sv00001395sd00002103* + ID_MODEL_FROM_DATABASE=CB100-EZ (4-LED version) + +pci:v00001317d00002850* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v00001317d00005120* + ID_MODEL_FROM_DATABASE=ADM5120 OpenGate System-on-Chip + +pci:v00001317d00008201* + ID_MODEL_FROM_DATABASE=ADM8211 802.11b Wireless Interface + +pci:v00001317d00008201sv000010B8sd00002635* + ID_MODEL_FROM_DATABASE=SMC2635W v1 802.11b Wireless Cardbus Adapter + +pci:v00001317d00008201sv00001317sd00008201* + ID_MODEL_FROM_DATABASE=SMC2635W v2 802.11b Wireless Cardbus Adapter + +pci:v00001317d00008211* + ID_MODEL_FROM_DATABASE=ADM8211 802.11b Wireless Interface + +pci:v00001317d00009511* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001318* + ID_VENDOR_FROM_DATABASE=Packet Engines Inc. + +pci:v00001318d00000911* + ID_MODEL_FROM_DATABASE=GNIC-II PCI Gigabit Ethernet [Hamachi] + +pci:v00001319* + ID_VENDOR_FROM_DATABASE=Fortemedia, Inc + +pci:v00001319d00000801* + ID_MODEL_FROM_DATABASE=Xwave QS3000A [FM801] + +pci:v00001319d00000801sv00001319sd00001319* + ID_MODEL_FROM_DATABASE=FM801 PCI Audio + +pci:v00001319d00000802* + ID_MODEL_FROM_DATABASE=Xwave QS3000A [FM801 game port] + +pci:v00001319d00000802sv00001319sd00001319* + ID_MODEL_FROM_DATABASE=FM801 PCI Joystick + +pci:v00001319d00001000* + ID_MODEL_FROM_DATABASE=FM801 PCI Audio + +pci:v00001319d00001001* + ID_MODEL_FROM_DATABASE=FM801 PCI Joystick + +pci:v0000131A* + ID_VENDOR_FROM_DATABASE=Finisar Corp. + +pci:v0000131C* + ID_VENDOR_FROM_DATABASE=Nippon Electro-Sensory Devices Corp + +pci:v0000131D* + ID_VENDOR_FROM_DATABASE=Sysmic, Inc. + +pci:v0000131E* + ID_VENDOR_FROM_DATABASE=Xinex Networks Inc + +pci:v0000131F* + ID_VENDOR_FROM_DATABASE=Siig Inc + +pci:v0000131Fd00001000* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16550 + +pci:v0000131Fd00001001* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16650 + +pci:v0000131Fd00001002* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16850 + +pci:v0000131Fd00001010* + ID_MODEL_FROM_DATABASE=Duet 1S(16550)+1P + +pci:v0000131Fd00001011* + ID_MODEL_FROM_DATABASE=Duet 1S(16650)+1P + +pci:v0000131Fd00001012* + ID_MODEL_FROM_DATABASE=Duet 1S(16850)+1P + +pci:v0000131Fd00001020* + ID_MODEL_FROM_DATABASE=CyberParallel (1-port) + +pci:v0000131Fd00001021* + ID_MODEL_FROM_DATABASE=CyberParallel (2-port) + +pci:v0000131Fd00001030* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16550 + +pci:v0000131Fd00001031* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16650 + +pci:v0000131Fd00001032* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16850 + +pci:v0000131Fd00001034* + ID_MODEL_FROM_DATABASE=Trio 2S(16550)+1P + +pci:v0000131Fd00001035* + ID_MODEL_FROM_DATABASE=Trio 2S(16650)+1P + +pci:v0000131Fd00001036* + ID_MODEL_FROM_DATABASE=Trio 2S(16850)+1P + +pci:v0000131Fd00001050* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16550 + +pci:v0000131Fd00001051* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16650 + +pci:v0000131Fd00001052* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16850 + +pci:v0000131Fd00002000* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16550 + +pci:v0000131Fd00002001* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16650 + +pci:v0000131Fd00002002* + ID_MODEL_FROM_DATABASE=CyberSerial (1-port) 16850 + +pci:v0000131Fd00002010* + ID_MODEL_FROM_DATABASE=Duet 1S(16550)+1P + +pci:v0000131Fd00002011* + ID_MODEL_FROM_DATABASE=Duet 1S(16650)+1P + +pci:v0000131Fd00002012* + ID_MODEL_FROM_DATABASE=Duet 1S(16850)+1P + +pci:v0000131Fd00002020* + ID_MODEL_FROM_DATABASE=CyberParallel (1-port) + +pci:v0000131Fd00002021* + ID_MODEL_FROM_DATABASE=CyberParallel (2-port) + +pci:v0000131Fd00002030* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16550 + +pci:v0000131Fd00002030sv0000131Fsd00002030* + ID_MODEL_FROM_DATABASE=PCI Serial Card + +pci:v0000131Fd00002031* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16650 + +pci:v0000131Fd00002032* + ID_MODEL_FROM_DATABASE=CyberSerial (2-port) 16850 + +pci:v0000131Fd00002040* + ID_MODEL_FROM_DATABASE=Trio 1S(16550)+2P + +pci:v0000131Fd00002041* + ID_MODEL_FROM_DATABASE=Trio 1S(16650)+2P + +pci:v0000131Fd00002042* + ID_MODEL_FROM_DATABASE=Trio 1S(16850)+2P + +pci:v0000131Fd00002050* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16550 + +pci:v0000131Fd00002051* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16650 + +pci:v0000131Fd00002052* + ID_MODEL_FROM_DATABASE=CyberSerial (4-port) 16850 + +pci:v0000131Fd00002060* + ID_MODEL_FROM_DATABASE=Trio 2S(16550)+1P + +pci:v0000131Fd00002061* + ID_MODEL_FROM_DATABASE=Trio 2S(16650)+1P + +pci:v0000131Fd00002062* + ID_MODEL_FROM_DATABASE=Trio 2S(16850)+1P + +pci:v0000131Fd00002081* + ID_MODEL_FROM_DATABASE=CyberSerial (8-port) ST16654 + +pci:v00001320* + ID_VENDOR_FROM_DATABASE=Crypto AG + +pci:v00001321* + ID_VENDOR_FROM_DATABASE=Arcobel Graphics BV + +pci:v00001322* + ID_VENDOR_FROM_DATABASE=MTT Co., Ltd + +pci:v00001323* + ID_VENDOR_FROM_DATABASE=Dome Inc + +pci:v00001324* + ID_VENDOR_FROM_DATABASE=Sphere Communications + +pci:v00001325* + ID_VENDOR_FROM_DATABASE=Salix Technologies, Inc + +pci:v00001326* + ID_VENDOR_FROM_DATABASE=Seachange international + +pci:v00001327* + ID_VENDOR_FROM_DATABASE=Voss scientific + +pci:v00001328* + ID_VENDOR_FROM_DATABASE=quadrant international + +pci:v00001329* + ID_VENDOR_FROM_DATABASE=Productivity Enhancement + +pci:v0000132A* + ID_VENDOR_FROM_DATABASE=Microcom Inc. + +pci:v0000132B* + ID_VENDOR_FROM_DATABASE=Broadband Technologies + +pci:v0000132C* + ID_VENDOR_FROM_DATABASE=Micrel Inc + +pci:v0000132D* + ID_VENDOR_FROM_DATABASE=Integrated Silicon Solution, Inc. + +pci:v00001330* + ID_VENDOR_FROM_DATABASE=MMC Networks + +pci:v00001331* + ID_VENDOR_FROM_DATABASE=RadiSys Corporation + +pci:v00001331d00000030* + ID_MODEL_FROM_DATABASE=ENP-2611 + +pci:v00001331d00008200* + ID_MODEL_FROM_DATABASE=82600 Host Bridge + +pci:v00001331d00008201* + ID_MODEL_FROM_DATABASE=82600 IDE + +pci:v00001331d00008202* + ID_MODEL_FROM_DATABASE=82600 USB + +pci:v00001331d00008210* + ID_MODEL_FROM_DATABASE=82600 PCI Bridge + +pci:v00001332* + ID_VENDOR_FROM_DATABASE=Micro Memory + +pci:v00001332d00005415* + ID_MODEL_FROM_DATABASE=MM-5415CN PCI Memory Module with Battery Backup + +pci:v00001332d00005425* + ID_MODEL_FROM_DATABASE=MM-5425CN PCI 64/66 Memory Module with Battery Backup + +pci:v00001332d00006140* + ID_MODEL_FROM_DATABASE=MM-6140D + +pci:v00001334* + ID_VENDOR_FROM_DATABASE=Redcreek Communications, Inc + +pci:v00001335* + ID_VENDOR_FROM_DATABASE=Videomail, Inc + +pci:v00001337* + ID_VENDOR_FROM_DATABASE=Third Planet Publishing + +pci:v00001338* + ID_VENDOR_FROM_DATABASE=BT Electronics + +pci:v0000133A* + ID_VENDOR_FROM_DATABASE=Vtel Corp + +pci:v0000133B* + ID_VENDOR_FROM_DATABASE=Softcom Microsystems + +pci:v0000133C* + ID_VENDOR_FROM_DATABASE=Holontech Corp + +pci:v0000133D* + ID_VENDOR_FROM_DATABASE=SS Technologies + +pci:v0000133E* + ID_VENDOR_FROM_DATABASE=Virtual Computer Corp + +pci:v0000133F* + ID_VENDOR_FROM_DATABASE=SCM Microsystems + +pci:v00001340* + ID_VENDOR_FROM_DATABASE=Atalla Corp + +pci:v00001341* + ID_VENDOR_FROM_DATABASE=Kyoto Microcomputer Co + +pci:v00001342* + ID_VENDOR_FROM_DATABASE=Promax Systems Inc + +pci:v00001343* + ID_VENDOR_FROM_DATABASE=Phylon Communications Inc + +pci:v00001344* + ID_VENDOR_FROM_DATABASE=Micron Technology Inc + +pci:v00001344d00005150* + ID_MODEL_FROM_DATABASE=RealSSD P320h + +pci:v00001344d00005151* + ID_MODEL_FROM_DATABASE=RealSSD P320m + +pci:v00001344d00005152* + ID_MODEL_FROM_DATABASE=RealSSD P320s + +pci:v00001344d00005153* + ID_MODEL_FROM_DATABASE=RealSSD P325m + +pci:v00001344d00005160* + ID_MODEL_FROM_DATABASE=RealSSD P420h + +pci:v00001344d00005161* + ID_MODEL_FROM_DATABASE=RealSSD P420m + +pci:v00001344d00005163* + ID_MODEL_FROM_DATABASE=RealSSD P425m + +pci:v00001345* + ID_VENDOR_FROM_DATABASE=Arescom Inc + +pci:v00001347* + ID_VENDOR_FROM_DATABASE=Odetics + +pci:v00001349* + ID_VENDOR_FROM_DATABASE=Sumitomo Electric Industries, Ltd. + +pci:v0000134A* + ID_VENDOR_FROM_DATABASE=DTC Technology Corp. + +pci:v0000134Ad00000001* + ID_MODEL_FROM_DATABASE=Domex 536 + +pci:v0000134Ad00000002* + ID_MODEL_FROM_DATABASE=Domex DMX3194UP SCSI Adapter + +pci:v0000134B* + ID_VENDOR_FROM_DATABASE=ARK Research Corp. + +pci:v0000134C* + ID_VENDOR_FROM_DATABASE=Chori Joho System Co. Ltd + +pci:v0000134D* + ID_VENDOR_FROM_DATABASE=PCTel Inc + +pci:v0000134Dd00002189* + ID_MODEL_FROM_DATABASE=HSP56 MicroModem + +pci:v0000134Dd00002486* + ID_MODEL_FROM_DATABASE=2304WT V.92 MDC Modem + +pci:v0000134Dd00007890* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007890sv0000134Dsd00000001* + ID_MODEL_FROM_DATABASE=PCT789 adapter + +pci:v0000134Dd00007891* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007891sv0000134Dsd00000001* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007892* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007893* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007894* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007895* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007896* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134Dd00007897* + ID_MODEL_FROM_DATABASE=HSP MicroModem 56 + +pci:v0000134E* + ID_VENDOR_FROM_DATABASE=CSTI + +pci:v0000134F* + ID_VENDOR_FROM_DATABASE=Algo System Co Ltd + +pci:v00001350* + ID_VENDOR_FROM_DATABASE=Systec Co. Ltd + +pci:v00001351* + ID_VENDOR_FROM_DATABASE=Sonix Inc + +pci:v00001353* + ID_VENDOR_FROM_DATABASE=Vierling Communication SAS + +pci:v00001353d00000002* + ID_MODEL_FROM_DATABASE=Proserver + +pci:v00001353d00000003* + ID_MODEL_FROM_DATABASE=PCI-FUT + +pci:v00001353d00000004* + ID_MODEL_FROM_DATABASE=PCI-S0 + +pci:v00001353d00000005* + ID_MODEL_FROM_DATABASE=PCI-FUT-S0 + +pci:v00001354* + ID_VENDOR_FROM_DATABASE=Dwave System Inc + +pci:v00001355* + ID_VENDOR_FROM_DATABASE=Kratos Analytical Ltd + +pci:v00001356* + ID_VENDOR_FROM_DATABASE=The Logical Co + +pci:v00001359* + ID_VENDOR_FROM_DATABASE=Prisa Networks + +pci:v0000135A* + ID_VENDOR_FROM_DATABASE=Brain Boxes + +pci:v0000135Ad00000A61* + ID_MODEL_FROM_DATABASE=UC-324 [VELOCITY RS422/485] + +pci:v0000135B* + ID_VENDOR_FROM_DATABASE=Giganet Inc + +pci:v0000135C* + ID_VENDOR_FROM_DATABASE=Quatech Inc + +pci:v0000135Cd00000010* + ID_MODEL_FROM_DATABASE=QSC-100 + +pci:v0000135Cd00000020* + ID_MODEL_FROM_DATABASE=DSC-100 + +pci:v0000135Cd00000030* + ID_MODEL_FROM_DATABASE=DSC-200/300 + +pci:v0000135Cd00000040* + ID_MODEL_FROM_DATABASE=QSC-200/300 + +pci:v0000135Cd00000050* + ID_MODEL_FROM_DATABASE=ESC-100D + +pci:v0000135Cd00000060* + ID_MODEL_FROM_DATABASE=ESC-100M + +pci:v0000135Cd000000F0* + ID_MODEL_FROM_DATABASE=MPAC-100 Syncronous Serial Card (Zilog 85230) + +pci:v0000135Cd00000170* + ID_MODEL_FROM_DATABASE=QSCLP-100 + +pci:v0000135Cd00000180* + ID_MODEL_FROM_DATABASE=DSCLP-100 + +pci:v0000135Cd00000190* + ID_MODEL_FROM_DATABASE=SSCLP-100 + +pci:v0000135Cd000001A0* + ID_MODEL_FROM_DATABASE=QSCLP-200/300 + +pci:v0000135Cd000001B0* + ID_MODEL_FROM_DATABASE=DSCLP-200/300 + +pci:v0000135Cd000001C0* + ID_MODEL_FROM_DATABASE=SSCLP-200/300 + +pci:v0000135Cd00000258* + ID_MODEL_FROM_DATABASE=DSPSX-200/300 + +pci:v0000135D* + ID_VENDOR_FROM_DATABASE=ABB Network Partner AB + +pci:v0000135E* + ID_VENDOR_FROM_DATABASE=Sealevel Systems Inc + +pci:v0000135Ed00005101* + ID_MODEL_FROM_DATABASE=Route 56.PCI - Multi-Protocol Serial Interface (Zilog Z16C32) + +pci:v0000135Ed00007101* + ID_MODEL_FROM_DATABASE=Single Port RS-232/422/485/530 + +pci:v0000135Ed00007201* + ID_MODEL_FROM_DATABASE=Dual Port RS-232/422/485 Interface + +pci:v0000135Ed00007202* + ID_MODEL_FROM_DATABASE=Dual Port RS-232 Interface + +pci:v0000135Ed00007401* + ID_MODEL_FROM_DATABASE=Four Port RS-232 Interface + +pci:v0000135Ed00007402* + ID_MODEL_FROM_DATABASE=Four Port RS-422/485 Interface + +pci:v0000135Ed00007801* + ID_MODEL_FROM_DATABASE=Eight Port RS-232 Interface + +pci:v0000135Ed00007804* + ID_MODEL_FROM_DATABASE=Eight Port RS-232/422/485 Interface + +pci:v0000135Ed00008001* + ID_MODEL_FROM_DATABASE=8001 Digital I/O Adapter + +pci:v0000135F* + ID_VENDOR_FROM_DATABASE=I-Data International A-S + +pci:v00001360* + ID_VENDOR_FROM_DATABASE=Meinberg Funkuhren + +pci:v00001360d00000101* + ID_MODEL_FROM_DATABASE=PCI32 DCF77 Radio Clock + +pci:v00001360d00000102* + ID_MODEL_FROM_DATABASE=PCI509 DCF77 Radio Clock + +pci:v00001360d00000103* + ID_MODEL_FROM_DATABASE=PCI510 DCF77 Radio Clock + +pci:v00001360d00000104* + ID_MODEL_FROM_DATABASE=PCI511 DCF77 Radio Clock + +pci:v00001360d00000105* + ID_MODEL_FROM_DATABASE=PEX511 DCF77 Radio Clock (PCI Express) + +pci:v00001360d00000106* + ID_MODEL_FROM_DATABASE=PZF180PEX High Precision DCF77 Radio Clock (PCI Express) + +pci:v00001360d00000201* + ID_MODEL_FROM_DATABASE=GPS167PCI GPS Receiver + +pci:v00001360d00000202* + ID_MODEL_FROM_DATABASE=GPS168PCI GPS Receiver + +pci:v00001360d00000203* + ID_MODEL_FROM_DATABASE=GPS169PCI GPS Receiver + +pci:v00001360d00000204* + ID_MODEL_FROM_DATABASE=GPS170PCI GPS Receiver + +pci:v00001360d00000205* + ID_MODEL_FROM_DATABASE=GPS170PEX GPS Receiver (PCI Express) + +pci:v00001360d00000206* + ID_MODEL_FROM_DATABASE=GPS180PEX GPS Receiver (PCI Express) + +pci:v00001360d00000301* + ID_MODEL_FROM_DATABASE=TCR510PCI IRIG Timecode Reader + +pci:v00001360d00000302* + ID_MODEL_FROM_DATABASE=TCR167PCI IRIG Timecode Reader + +pci:v00001360d00000303* + ID_MODEL_FROM_DATABASE=TCR511PCI IRIG Timecode Reader + +pci:v00001360d00000304* + ID_MODEL_FROM_DATABASE=TCR511PEX IRIG Timecode Reader (PCI Express) + +pci:v00001360d00000305* + ID_MODEL_FROM_DATABASE=TCR170PEX IRIG Timecode Reader (PCI Express) + +pci:v00001360d00000306* + ID_MODEL_FROM_DATABASE=TCR180PEX IRIG Timecode Reader (PCI Express) + +pci:v00001360d00000501* + ID_MODEL_FROM_DATABASE=PTP270PEX PTP/IEEE1588 slave card (PCI Express) + +pci:v00001360d00000601* + ID_MODEL_FROM_DATABASE=FRC511PEX Free Running Clock (PCI Express) + +pci:v00001361* + ID_VENDOR_FROM_DATABASE=Soliton Systems K.K. + +pci:v00001362* + ID_VENDOR_FROM_DATABASE=Fujifacom Corporation + +pci:v00001363* + ID_VENDOR_FROM_DATABASE=Phoenix Technology Ltd + +pci:v00001364* + ID_VENDOR_FROM_DATABASE=ATM Communications Inc + +pci:v00001365* + ID_VENDOR_FROM_DATABASE=Hypercope GmbH + +pci:v00001366* + ID_VENDOR_FROM_DATABASE=Teijin Seiki Co. Ltd + +pci:v00001367* + ID_VENDOR_FROM_DATABASE=Hitachi Zosen Corporation + +pci:v00001368* + ID_VENDOR_FROM_DATABASE=Skyware Corporation + +pci:v00001369* + ID_VENDOR_FROM_DATABASE=Digigram + +pci:v0000136A* + ID_VENDOR_FROM_DATABASE=High Soft Tech + +pci:v0000136Ad00000004* + ID_MODEL_FROM_DATABASE=HST Saphir VII mini PCI + +pci:v0000136Ad00000007* + ID_MODEL_FROM_DATABASE=HST Saphir III E MultiLink 4 + +pci:v0000136Ad00000008* + ID_MODEL_FROM_DATABASE=HST Saphir III E MultiLink 8 + +pci:v0000136Ad0000000A* + ID_MODEL_FROM_DATABASE=HST Saphir III E MultiLink 2 + +pci:v0000136B* + ID_VENDOR_FROM_DATABASE=Kawasaki Steel Corporation + +pci:v0000136Bd0000FF01* + ID_MODEL_FROM_DATABASE=KL5A72002 Motion JPEG + +pci:v0000136C* + ID_VENDOR_FROM_DATABASE=Adtek System Science Co Ltd + +pci:v0000136D* + ID_VENDOR_FROM_DATABASE=Gigalabs Inc + +pci:v0000136F* + ID_VENDOR_FROM_DATABASE=Applied Magic Inc + +pci:v00001370* + ID_VENDOR_FROM_DATABASE=ATL Products + +pci:v00001371* + ID_VENDOR_FROM_DATABASE=CNet Technology Inc + +pci:v00001371d0000434E* + ID_MODEL_FROM_DATABASE=GigaCard Network Adapter + +pci:v00001371d0000434Esv00001371sd0000434E* + ID_MODEL_FROM_DATABASE=N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L) + +pci:v00001373* + ID_VENDOR_FROM_DATABASE=Silicon Vision Inc + +pci:v00001374* + ID_VENDOR_FROM_DATABASE=Silicom Ltd. + +pci:v00001374d00000024* + ID_MODEL_FROM_DATABASE=Silicom Dual port Giga Ethernet BGE Bypass Server Adapter + +pci:v00001374d00000025* + ID_MODEL_FROM_DATABASE=Silicom Quad port Giga Ethernet BGE Bypass Server Adapter + +pci:v00001374d00000026* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber Giga Ethernet 546 Bypass Server Adapter + +pci:v00001374d00000027* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber LX Giga Ethernet 546 Bypass Server Adapter + +pci:v00001374d00000029* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Giga Ethernet 546GB Bypass Server Adapter + +pci:v00001374d0000002A* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber Giga Ethernet 546 TAP/Bypass Server Adapter + +pci:v00001374d0000002B* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Fast Ethernet 546 TAP/Bypass Server Adapter (PXE2TBI) + +pci:v00001374d0000002C* + ID_MODEL_FROM_DATABASE=Silicom Quad port Copper Giga Ethernet 546GB Bypass Server Adapter (PXG4BPI) + +pci:v00001374d0000002D* + ID_MODEL_FROM_DATABASE=Silicom Quad port Fiber-SX Giga Ethernet 546GB Bypass Server Adapter (PXG4BPFI) + +pci:v00001374d0000002E* + ID_MODEL_FROM_DATABASE=Silicom Quad port Fiber-LX Giga Ethernet 546GB Bypass Server Adapter (PXG4BPFI-LX) + +pci:v00001374d0000002F* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber-SX Giga Ethernet 546GB Low profile Bypass Server Adapter (PXG2BPFIL) + +pci:v00001374d00000030* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber-LX Giga Ethernet 546GB Low profile Bypass Server Adapter + +pci:v00001374d00000031* + ID_MODEL_FROM_DATABASE=Silicom Quad port Copper Giga Ethernet PCI-E Bypass Server Adapter + +pci:v00001374d00000032* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Fast Ethernet 546 TAP/Bypass Server Adapter + +pci:v00001374d00000034* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Giga Ethernet PCI-E BGE Bypass Server Adapter + +pci:v00001374d00000035* + ID_MODEL_FROM_DATABASE=Silicom Quad port Copper Giga Ethernet PCI-E BGE Bypass Server Adapter + +pci:v00001374d00000036* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber Giga Ethernet PCI-E BGE Bypass Server Adapter + +pci:v00001374d00000037* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Ethernet PCI-E Intel based Bypass Server Adapter + +pci:v00001374d00000038* + ID_MODEL_FROM_DATABASE=Silicom Quad port Copper Ethernet PCI-E Intel based Bypass Server Adapter + +pci:v00001374d00000039* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber-SX Ethernet PCI-E Intel based Bypass Server Adapter + +pci:v00001374d0000003A* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber-LX Ethernet PCI-E Intel based Bypass Server Adapter + +pci:v00001374d0000003B* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber Ethernet PMC Intel based Bypass Server Adapter (PMCX2BPFI) + +pci:v00001374d0000003C* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Ethernet PCI-X BGE based Bypass Server Adapter (PXG2BPRB) + +pci:v00001374d0000003D* + ID_MODEL_FROM_DATABASE=2-port Copper GBE Bypass with Caviume 1010 PCI-X + +pci:v00001374d0000003E* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber Giga Ethernet PCI-E 571 TAP/Bypass Server Adapter (PEG2TBFI) + +pci:v00001374d0000003F* + ID_MODEL_FROM_DATABASE=Silicom Dual port Copper Giga Ethernet PCI-X 546 TAP/Bypass Server Adapter (PXG2TBI) + +pci:v00001374d00000040* + ID_MODEL_FROM_DATABASE=Silicom Quad port Fiber-SX Giga Ethernet 571 Bypass Server Adapter (PEG4BPFI) + +pci:v00001374d00000042* + ID_MODEL_FROM_DATABASE=4-port Copper GBE PMC-X Bypass + +pci:v00001374d00000043* + ID_MODEL_FROM_DATABASE=Silicom Quad port Fiber-SX Giga Ethernet 546 Bypass Server Adapter (PXG4BPFID) + +pci:v00001374d00000045* + ID_MODEL_FROM_DATABASE=Silicom 6 port Copper Giga Ethernet 546 Bypass Server Adapter (PXG6BPI) + +pci:v00001374d00000046* + ID_MODEL_FROM_DATABASE=4-port bypass PCI-E w disconnect low profile + +pci:v00001374d00000047* + ID_MODEL_FROM_DATABASE=Silicom Dual port Fiber-SX Giga Ethernet 571 Bypass Disconnect Server Adapter (PEG2BPFID) + +pci:v00001374d0000004A* + ID_MODEL_FROM_DATABASE=Silicom Quad port Fiber-LX Giga Ethernet 571 Bypass Server Adapter (PEG4BPFI-LX) + +pci:v00001374d0000004D* + ID_MODEL_FROM_DATABASE=Dual port Copper Giga Ethernet PCI-E Bypass Server Adapter + +pci:v00001374d00000401* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001374d00000420* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001374d00000460* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet Express Module Bypass Server Adapter + +pci:v00001374d00000461* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001374d00000462* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001374d00000470* + ID_MODEL_FROM_DATABASE=Octal-port Copper Gigabit Ethernet Express Module Bypass Server Adapter + +pci:v00001374d00000482* + ID_MODEL_FROM_DATABASE=Dual-port Fiber (SR) 10 Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001374d00000483* + ID_MODEL_FROM_DATABASE=Dual-port Fiber (LR) 10 Gigabit Ethernet ExpressModule Bypass Server Adapter + +pci:v00001375* + ID_VENDOR_FROM_DATABASE=Argosystems Inc + +pci:v00001376* + ID_VENDOR_FROM_DATABASE=LMC + +pci:v00001377* + ID_VENDOR_FROM_DATABASE=Electronic Equipment Production & Distribution GmbH + +pci:v00001378* + ID_VENDOR_FROM_DATABASE=Telemann Co. Ltd + +pci:v00001379* + ID_VENDOR_FROM_DATABASE=Asahi Kasei Microsystems Co Ltd + +pci:v0000137A* + ID_VENDOR_FROM_DATABASE=Mark of the Unicorn Inc + +pci:v0000137Ad00000001* + ID_MODEL_FROM_DATABASE=PCI-324 Audiowire Interface + +pci:v0000137B* + ID_VENDOR_FROM_DATABASE=PPT Vision + +pci:v0000137C* + ID_VENDOR_FROM_DATABASE=Iwatsu Electric Co Ltd + +pci:v0000137D* + ID_VENDOR_FROM_DATABASE=Dynachip Corporation + +pci:v0000137E* + ID_VENDOR_FROM_DATABASE=Patriot Scientific Corporation + +pci:v0000137F* + ID_VENDOR_FROM_DATABASE=Japan Satellite Systems Inc + +pci:v00001380* + ID_VENDOR_FROM_DATABASE=Sanritz Automation Co Ltd + +pci:v00001381* + ID_VENDOR_FROM_DATABASE=Brains Co. Ltd + +pci:v00001382* + ID_VENDOR_FROM_DATABASE=Marian - Electronic & Software + +pci:v00001382d00000001* + ID_MODEL_FROM_DATABASE=ARC88 audio recording card + +pci:v00001382d00002008* + ID_MODEL_FROM_DATABASE=Prodif 96 Pro sound system + +pci:v00001382d00002048* + ID_MODEL_FROM_DATABASE=Prodif Plus sound system + +pci:v00001382d00002088* + ID_MODEL_FROM_DATABASE=Marc 8 Midi sound system + +pci:v00001382d000020C8* + ID_MODEL_FROM_DATABASE=Marc A sound system + +pci:v00001382d00004008* + ID_MODEL_FROM_DATABASE=Marc 2 sound system + +pci:v00001382d00004010* + ID_MODEL_FROM_DATABASE=Marc 2 Pro sound system + +pci:v00001382d00004048* + ID_MODEL_FROM_DATABASE=Marc 4 MIDI sound system + +pci:v00001382d00004088* + ID_MODEL_FROM_DATABASE=Marc 4 Digi sound system + +pci:v00001382d00004248* + ID_MODEL_FROM_DATABASE=Marc X sound system + +pci:v00001382d00004424* + ID_MODEL_FROM_DATABASE=TRACE D4 Sound System + +pci:v00001383* + ID_VENDOR_FROM_DATABASE=Controlnet Inc + +pci:v00001384* + ID_VENDOR_FROM_DATABASE=Reality Simulation Systems Inc + +pci:v00001385* + ID_VENDOR_FROM_DATABASE=Netgear + +pci:v00001385d0000006B* + ID_MODEL_FROM_DATABASE=WA301 802.11b Wireless PCI Adapter + +pci:v00001385d00004100* + ID_MODEL_FROM_DATABASE=MA301 802.11b Wireless PCI Adapter + +pci:v00001385d00004601* + ID_MODEL_FROM_DATABASE=WAG511 802.11a/b/g Dual Band Wireless PC Card + +pci:v00001385d0000620A* + ID_MODEL_FROM_DATABASE=GA620 Gigabit Ethernet + +pci:v00001385d0000630A* + ID_MODEL_FROM_DATABASE=GA630 Gigabit Ethernet + +pci:v00001386* + ID_VENDOR_FROM_DATABASE=Video Domain Technologies + +pci:v00001387* + ID_VENDOR_FROM_DATABASE=Systran Corp + +pci:v00001388* + ID_VENDOR_FROM_DATABASE=Hitachi Information Technology Co Ltd + +pci:v00001389* + ID_VENDOR_FROM_DATABASE=Applicom International + +pci:v00001389d00000001* + ID_MODEL_FROM_DATABASE=PCI1500PFB [Intelligent fieldbus adaptor] + +pci:v0000138A* + ID_VENDOR_FROM_DATABASE=Fusion Micromedia Corp + +pci:v0000138Ad0000003D* + ID_MODEL_FROM_DATABASE=VFS491 Validity Sensor + +pci:v0000138B* + ID_VENDOR_FROM_DATABASE=Tokimec Inc + +pci:v0000138C* + ID_VENDOR_FROM_DATABASE=Silicon Reality + +pci:v0000138D* + ID_VENDOR_FROM_DATABASE=Future Techno Designs pte Ltd + +pci:v0000138E* + ID_VENDOR_FROM_DATABASE=Basler GmbH + +pci:v0000138F* + ID_VENDOR_FROM_DATABASE=Patapsco Designs Inc + +pci:v00001390* + ID_VENDOR_FROM_DATABASE=Concept Development Inc + +pci:v00001391* + ID_VENDOR_FROM_DATABASE=Development Concepts Inc + +pci:v00001392* + ID_VENDOR_FROM_DATABASE=Medialight Inc + +pci:v00001393* + ID_VENDOR_FROM_DATABASE=Moxa Technologies Co Ltd + +pci:v00001393d00000001* + ID_MODEL_FROM_DATABASE=UC7000 Serial + +pci:v00001393d00001020* + ID_MODEL_FROM_DATABASE=CP102 (2-port RS-232 PCI) + +pci:v00001393d00001021* + ID_MODEL_FROM_DATABASE=CP102UL (2-port RS-232 Universal PCI) + +pci:v00001393d00001022* + ID_MODEL_FROM_DATABASE=CP102U (2-port RS-232 Universal PCI) + +pci:v00001393d00001023* + ID_MODEL_FROM_DATABASE=CP-102UF + +pci:v00001393d00001024* + ID_MODEL_FROM_DATABASE=CP-102E (2-port RS-232 Smart PCI Express Serial Board) + +pci:v00001393d00001025* + ID_MODEL_FROM_DATABASE=CP-102EL (2-port RS-232 Smart PCI Express Serial Board) + +pci:v00001393d00001040* + ID_MODEL_FROM_DATABASE=Smartio C104H/PCI + +pci:v00001393d00001041* + ID_MODEL_FROM_DATABASE=CP104U (4-port RS-232 Universal PCI) + +pci:v00001393d00001042* + ID_MODEL_FROM_DATABASE=CP104JU (4-port RS-232 Universal PCI) + +pci:v00001393d00001043* + ID_MODEL_FROM_DATABASE=CP104EL (4-port RS-232 Smart PCI Express) + +pci:v00001393d00001044* + ID_MODEL_FROM_DATABASE=POS104UL (4-port RS-232 Universal PCI) + +pci:v00001393d00001045* + ID_MODEL_FROM_DATABASE=CP-104EL-A (4-port RS-232 PCI Express Serial Board) + +pci:v00001393d00001080* + ID_MODEL_FROM_DATABASE=CB108 (8-port RS-232 PC/104-plus Module) + +pci:v00001393d00001140* + ID_MODEL_FROM_DATABASE=CT-114 series + +pci:v00001393d00001141* + ID_MODEL_FROM_DATABASE=Industrio CP-114 + +pci:v00001393d00001142* + ID_MODEL_FROM_DATABASE=CB114 (4-port RS-232/422/485 PC/104-plus Module) + +pci:v00001393d00001143* + ID_MODEL_FROM_DATABASE=CP-114UL (4-port RS-232/422/485 Smart Universal PCI Serial Board) + +pci:v00001393d00001144* + ID_MODEL_FROM_DATABASE=CP-114EL (4-port RS-232/422/485 Smart PCI Express Serial Board) + +pci:v00001393d00001180* + ID_MODEL_FROM_DATABASE=CP118U (8-port RS-232/422/485 Smart Universal PCI) + +pci:v00001393d00001181* + ID_MODEL_FROM_DATABASE=CP118EL (8-port RS-232/422/485 Smart PCI Express) + +pci:v00001393d00001182* + ID_MODEL_FROM_DATABASE=CP-118EL-A (8-port RS-232/422/485 PCI Express Serial Board) + +pci:v00001393d00001320* + ID_MODEL_FROM_DATABASE=CP132 (2-port RS-422/485 PCI) + +pci:v00001393d00001321* + ID_MODEL_FROM_DATABASE=CP132U (2-Port RS-422/485 Universal PCI) + +pci:v00001393d00001322* + ID_MODEL_FROM_DATABASE=CP-132EL (2-port RS-422/485 Smart PCI Express Serial Board) + +pci:v00001393d00001340* + ID_MODEL_FROM_DATABASE=CP134U (4-Port RS-422/485 Universal PCI) + +pci:v00001393d00001341* + ID_MODEL_FROM_DATABASE=CB134I (4-port RS-422/485 PC/104-plus Module) + +pci:v00001393d00001380* + ID_MODEL_FROM_DATABASE=CP138U (8-port RS-232/422/485 Smart Universal PCI) + +pci:v00001393d00001680* + ID_MODEL_FROM_DATABASE=Smartio C168H/PCI + +pci:v00001393d00001681* + ID_MODEL_FROM_DATABASE=CP-168U V2 Smart Serial Board (8-port RS-232) + +pci:v00001393d00001682* + ID_MODEL_FROM_DATABASE=CP168EL (8-port RS-232 Smart PCI Express) + +pci:v00001393d00001683* + ID_MODEL_FROM_DATABASE=CP-168EL-A (8-port RS-232 PCI Express Serial Board) + +pci:v00001393d00002040* + ID_MODEL_FROM_DATABASE=Intellio CP-204J + +pci:v00001393d00002180* + ID_MODEL_FROM_DATABASE=Intellio C218 Turbo PCI + +pci:v00001393d00003200* + ID_MODEL_FROM_DATABASE=Intellio C320 Turbo PCI + +pci:v00001394* + ID_VENDOR_FROM_DATABASE=Level One Communications + +pci:v00001394d00000001* + ID_MODEL_FROM_DATABASE=LXT1001 Gigabit Ethernet + +pci:v00001394d00000001sv00001186sd00004800* + ID_MODEL_FROM_DATABASE=DGE-500SX + +pci:v00001394d00000001sv00001394sd00000001* + ID_MODEL_FROM_DATABASE=NetCelerator Adapter + +pci:v00001395* + ID_VENDOR_FROM_DATABASE=Ambicom Inc + +pci:v00001396* + ID_VENDOR_FROM_DATABASE=Cipher Systems Inc + +pci:v00001397* + ID_VENDOR_FROM_DATABASE=Cologne Chip Designs GmbH + +pci:v00001397d000008B4* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] + +pci:v00001397d000008B4sv00001397sd0000B520* + ID_MODEL_FROM_DATABASE=HFC-4S [IOB4ST] + +pci:v00001397d000008B4sv00001397sd0000B540* + ID_MODEL_FROM_DATABASE=HFC-4S [Swyx 4xS0 SX2 QuadBri] + +pci:v00001397d000008B4sv00001397sd0000B550* + ID_MODEL_FROM_DATABASE=HFC-4S [Junghanns quadBRI] + +pci:v00001397d000008B4sv00001397sd0000B556* + ID_MODEL_FROM_DATABASE=HFC-4S [Junghanns DuoDBRI] + +pci:v00001397d000008B4sv00001397sd0000E888* + ID_MODEL_FROM_DATABASE=HFC-4S [OpenVox B200P / B400P] + +pci:v00001397d000016B8* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] + +pci:v00001397d000016B8sv00001397sd0000B562* + ID_MODEL_FROM_DATABASE=HFC-8S [IOB8ST] + +pci:v00001397d00002BD0* + ID_MODEL_FROM_DATABASE=ISDN network controller [HFC-PCI] + +pci:v00001397d00002BD0sv00000675sd00001704* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, C) + +pci:v00001397d00002BD0sv00000675sd00001708* + ID_MODEL_FROM_DATABASE=ISDN Adapter (PCI Bus, D, C, ACPI) + +pci:v00001397d00002BD0sv00001397sd00002BD0* + ID_MODEL_FROM_DATABASE=ISDN Board + +pci:v00001397d00002BD0sv0000E4BFsd00001000* + ID_MODEL_FROM_DATABASE=CI1-1-Harp + +pci:v00001397d000030B1* + ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] + +pci:v00001397d0000B700* + ID_MODEL_FROM_DATABASE=ISDN network controller PrimuX S0 [HFC-PCI] + +pci:v00001397d0000F001* + ID_MODEL_FROM_DATABASE=GSM Network Controller [HFC-4GSM] + +pci:v00001398* + ID_VENDOR_FROM_DATABASE=Clarion co. Ltd + +pci:v00001399* + ID_VENDOR_FROM_DATABASE=Rios systems Co Ltd + +pci:v0000139A* + ID_VENDOR_FROM_DATABASE=Alacritech Inc + +pci:v0000139Ad00000001* + ID_MODEL_FROM_DATABASE=Quad Port 10/100 Server Accelerator + +pci:v0000139Ad00000003* + ID_MODEL_FROM_DATABASE=Single Port 10/100 Server Accelerator + +pci:v0000139Ad00000005* + ID_MODEL_FROM_DATABASE=Single Port Gigabit Server Accelerator + +pci:v0000139B* + ID_VENDOR_FROM_DATABASE=Mediasonic Multimedia Systems Ltd + +pci:v0000139C* + ID_VENDOR_FROM_DATABASE=Quantum 3d Inc + +pci:v0000139D* + ID_VENDOR_FROM_DATABASE=EPL limited + +pci:v0000139E* + ID_VENDOR_FROM_DATABASE=Media4 + +pci:v0000139F* + ID_VENDOR_FROM_DATABASE=Aethra s.r.l. + +pci:v000013A0* + ID_VENDOR_FROM_DATABASE=Crystal Group Inc + +pci:v000013A1* + ID_VENDOR_FROM_DATABASE=Kawasaki Heavy Industries Ltd + +pci:v000013A2* + ID_VENDOR_FROM_DATABASE=Ositech Communications Inc + +pci:v000013A3* + ID_VENDOR_FROM_DATABASE=Hifn Inc. + +pci:v000013A3d00000005* + ID_MODEL_FROM_DATABASE=7751 Security Processor + +pci:v000013A3d00000006* + ID_MODEL_FROM_DATABASE=6500 Public Key Processor + +pci:v000013A3d00000007* + ID_MODEL_FROM_DATABASE=7811 Security Processor + +pci:v000013A3d00000012* + ID_MODEL_FROM_DATABASE=7951 Security Processor + +pci:v000013A3d00000014* + ID_MODEL_FROM_DATABASE=78XX Security Processor + +pci:v000013A3d00000016* + ID_MODEL_FROM_DATABASE=8065 Security Processor + +pci:v000013A3d00000017* + ID_MODEL_FROM_DATABASE=8165 Security Processor + +pci:v000013A3d00000018* + ID_MODEL_FROM_DATABASE=8154 Security Processor + +pci:v000013A3d0000001D* + ID_MODEL_FROM_DATABASE=7956 Security Processor + +pci:v000013A3d0000001F* + ID_MODEL_FROM_DATABASE=7855 Security Processor + +pci:v000013A3d00000020* + ID_MODEL_FROM_DATABASE=7955 Security Processor + +pci:v000013A3d00000026* + ID_MODEL_FROM_DATABASE=8155 Security Processor + +pci:v000013A3d0000002E* + ID_MODEL_FROM_DATABASE=9630 Compression Processor + +pci:v000013A3d0000002F* + ID_MODEL_FROM_DATABASE=9725 Compression and Security Processor + +pci:v000013A3d0000002Fsv000013A3sd00001600* + ID_MODEL_FROM_DATABASE=DR1600 Acceleration Card + +pci:v000013A3d0000002Fsv000013A3sd00001605* + ID_MODEL_FROM_DATABASE=DR1605 Acceleration Card + +pci:v000013A3d0000002Fsv000013A3sd00001610* + ID_MODEL_FROM_DATABASE=DR1610 Acceleration Card + +pci:v000013A3d0000002Fsv000013A3sd00001615* + ID_MODEL_FROM_DATABASE=DR1615 Acceleration Card + +pci:v000013A3d0000002Fsv000013A3sd00001620* + ID_MODEL_FROM_DATABASE=DR1620 Acceleration Card + +pci:v000013A3d0000002Fsv000013A3sd00001625* + ID_MODEL_FROM_DATABASE=DR1625 Acceleration Card + +pci:v000013A3d00000033* + ID_MODEL_FROM_DATABASE=8201 Acceleration Processor + +pci:v000013A3d00000033sv000013A3sd00000036* + ID_MODEL_FROM_DATABASE=DX1710 Acceleration Card + +pci:v000013A3d00000034* + ID_MODEL_FROM_DATABASE=8202 Acceleration Processor + +pci:v000013A3d00000034sv000013A3sd00000036* + ID_MODEL_FROM_DATABASE=DX1720 Acceleration Card + +pci:v000013A3d00000035* + ID_MODEL_FROM_DATABASE=8203 Acceleration Processor + +pci:v000013A3d00000035sv000013A3sd00000036* + ID_MODEL_FROM_DATABASE=DX1730 Acceleration Card + +pci:v000013A3d00000037* + ID_MODEL_FROM_DATABASE=8204 Acceleration Processor + +pci:v000013A3d00000037sv000013A3sd00000036* + ID_MODEL_FROM_DATABASE=DX1740 Acceleration Card + +pci:v000013A4* + ID_VENDOR_FROM_DATABASE=Rascom Inc + +pci:v000013A5* + ID_VENDOR_FROM_DATABASE=Audio Digital Imaging Inc + +pci:v000013A6* + ID_VENDOR_FROM_DATABASE=Videonics Inc + +pci:v000013A7* + ID_VENDOR_FROM_DATABASE=Teles AG + +pci:v000013A8* + ID_VENDOR_FROM_DATABASE=Exar Corp. + +pci:v000013A8d00000152* + ID_MODEL_FROM_DATABASE=XR17C/D152 Dual PCI UART + +pci:v000013A8d00000154* + ID_MODEL_FROM_DATABASE=XR17C154 Quad UART + +pci:v000013A8d00000158* + ID_MODEL_FROM_DATABASE=XR17C158 Octal UART + +pci:v000013A8d00000252* + ID_MODEL_FROM_DATABASE=XR17V252 Dual UART PCI controller + +pci:v000013A8d00000254* + ID_MODEL_FROM_DATABASE=XR17V254 Quad UART PCI controller + +pci:v000013A8d00000258* + ID_MODEL_FROM_DATABASE=XR17V258 Octal UART PCI controller + +pci:v000013A9* + ID_VENDOR_FROM_DATABASE=Siemens Medical Systems, Ultrasound Group + +pci:v000013AA* + ID_VENDOR_FROM_DATABASE=Broadband Networks Inc + +pci:v000013AB* + ID_VENDOR_FROM_DATABASE=Arcom Control Systems Ltd + +pci:v000013AC* + ID_VENDOR_FROM_DATABASE=Motion Media Technology Ltd + +pci:v000013AD* + ID_VENDOR_FROM_DATABASE=Nexus Inc + +pci:v000013AE* + ID_VENDOR_FROM_DATABASE=ALD Technology Ltd + +pci:v000013AF* + ID_VENDOR_FROM_DATABASE=T.Sqware + +pci:v000013B0* + ID_VENDOR_FROM_DATABASE=Maxspeed Corp + +pci:v000013B1* + ID_VENDOR_FROM_DATABASE=Tamura corporation + +pci:v000013B2* + ID_VENDOR_FROM_DATABASE=Techno Chips Co. Ltd + +pci:v000013B3* + ID_VENDOR_FROM_DATABASE=Lanart Corporation + +pci:v000013B4* + ID_VENDOR_FROM_DATABASE=Wellbean Co Inc + +pci:v000013B5* + ID_VENDOR_FROM_DATABASE=ARM + +pci:v000013B6* + ID_VENDOR_FROM_DATABASE=Dlog GmbH + +pci:v000013B7* + ID_VENDOR_FROM_DATABASE=Logic Devices Inc + +pci:v000013B8* + ID_VENDOR_FROM_DATABASE=Nokia Telecommunications oy + +pci:v000013B9* + ID_VENDOR_FROM_DATABASE=Elecom Co Ltd + +pci:v000013BA* + ID_VENDOR_FROM_DATABASE=Oxford Instruments + +pci:v000013BB* + ID_VENDOR_FROM_DATABASE=Sanyo Technosound Co Ltd + +pci:v000013BC* + ID_VENDOR_FROM_DATABASE=Bitran Corporation + +pci:v000013BD* + ID_VENDOR_FROM_DATABASE=Sharp corporation + +pci:v000013BE* + ID_VENDOR_FROM_DATABASE=Miroku Jyoho Service Co. Ltd + +pci:v000013BF* + ID_VENDOR_FROM_DATABASE=Sharewave Inc + +pci:v000013C0* + ID_VENDOR_FROM_DATABASE=Microgate Corporation + +pci:v000013C0d00000010* + ID_MODEL_FROM_DATABASE=SyncLink Adapter v1 + +pci:v000013C0d00000020* + ID_MODEL_FROM_DATABASE=SyncLink SCC Adapter + +pci:v000013C0d00000030* + ID_MODEL_FROM_DATABASE=SyncLink Multiport Adapter + +pci:v000013C0d00000070* + ID_MODEL_FROM_DATABASE=SyncLink GT Adapter + +pci:v000013C0d00000080* + ID_MODEL_FROM_DATABASE=SyncLink GT4 Adapter + +pci:v000013C0d000000A0* + ID_MODEL_FROM_DATABASE=SyncLink GT2 Adapter + +pci:v000013C0d00000210* + ID_MODEL_FROM_DATABASE=SyncLink Adapter v2 + +pci:v000013C1* + ID_VENDOR_FROM_DATABASE=3ware Inc + +pci:v000013C1d00001000* + ID_MODEL_FROM_DATABASE=5xxx/6xxx-series PATA-RAID + +pci:v000013C1d00001001* + ID_MODEL_FROM_DATABASE=7xxx/8xxx-series PATA/SATA-RAID + +pci:v000013C1d00001001sv000013C1sd00001001* + ID_MODEL_FROM_DATABASE=7xxx/8xxx-series PATA/SATA-RAID + +pci:v000013C1d00001002* + ID_MODEL_FROM_DATABASE=9xxx-series SATA-RAID + +pci:v000013C1d00001003* + ID_MODEL_FROM_DATABASE=9550SX SATA-II RAID PCI-X + +pci:v000013C1d00001004* + ID_MODEL_FROM_DATABASE=9650SE SATA-II RAID PCIe + +pci:v000013C1d00001005* + ID_MODEL_FROM_DATABASE=9690SA SAS/SATA-II RAID PCIe + +pci:v000013C1d00001010* + ID_MODEL_FROM_DATABASE=9750 SAS2/SATA-II RAID PCIe + +pci:v000013C2* + ID_VENDOR_FROM_DATABASE=Technotrend Systemtechnik GmbH + +pci:v000013C2d0000000E* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DVB card rev2.3 + +pci:v000013C2d00001019* + ID_MODEL_FROM_DATABASE=TTechnoTrend-budget DVB S2-3200 + +pci:v000013C3* + ID_VENDOR_FROM_DATABASE=Janz Computer AG + +pci:v000013C4* + ID_VENDOR_FROM_DATABASE=Phase Metrics + +pci:v000013C5* + ID_VENDOR_FROM_DATABASE=Alphi Technology Corp + +pci:v000013C6* + ID_VENDOR_FROM_DATABASE=Condor Engineering Inc + +pci:v000013C6d00000520* + ID_MODEL_FROM_DATABASE=CEI-520 A429 Card + +pci:v000013C6d00000620* + ID_MODEL_FROM_DATABASE=CEI-620 A429 Card + +pci:v000013C6d00000820* + ID_MODEL_FROM_DATABASE=CEI-820 A429 Card + +pci:v000013C6d00000830* + ID_MODEL_FROM_DATABASE=CEI-830 A429 Card + +pci:v000013C6d00001004* + ID_MODEL_FROM_DATABASE=P-SER Multi-channel PMC to RS-485/422/232 adapter + +pci:v000013C7* + ID_VENDOR_FROM_DATABASE=Blue Chip Technology Ltd + +pci:v000013C7d00000ADC* + ID_MODEL_FROM_DATABASE=PCI-ADC + +pci:v000013C7d00000B10* + ID_MODEL_FROM_DATABASE=PCI-PIO + +pci:v000013C7d00000D10* + ID_MODEL_FROM_DATABASE=PCI-DIO + +pci:v000013C7d0000524C* + ID_MODEL_FROM_DATABASE=PCI-RLY + +pci:v000013C7d00005744* + ID_MODEL_FROM_DATABASE=PCI-WDT + +pci:v000013C8* + ID_VENDOR_FROM_DATABASE=Apptech Inc + +pci:v000013C9* + ID_VENDOR_FROM_DATABASE=Eaton Corporation + +pci:v000013CA* + ID_VENDOR_FROM_DATABASE=Iomega Corporation + +pci:v000013CB* + ID_VENDOR_FROM_DATABASE=Yano Electric Co Ltd + +pci:v000013CC* + ID_VENDOR_FROM_DATABASE=Metheus Corporation + +pci:v000013CD* + ID_VENDOR_FROM_DATABASE=Compatible Systems Corporation + +pci:v000013CE* + ID_VENDOR_FROM_DATABASE=Cocom A/S + +pci:v000013CF* + ID_VENDOR_FROM_DATABASE=Studio Audio & Video Ltd + +pci:v000013D0* + ID_VENDOR_FROM_DATABASE=Techsan Electronics Co Ltd + +pci:v000013D0d00002103* + ID_MODEL_FROM_DATABASE=B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card + +pci:v000013D0d00002104* + ID_MODEL_FROM_DATABASE=B2C2 FlexCopIII DVB chip / Technisat SkyStar2 DVB card (rev 01) + +pci:v000013D0d00002200* + ID_MODEL_FROM_DATABASE=B2C2 FlexCopIII DVB chip / Technisat SkyStar2 DVB card + +pci:v000013D1* + ID_VENDOR_FROM_DATABASE=Abocom Systems Inc + +pci:v000013D1d0000AB02* + ID_MODEL_FROM_DATABASE=ADMtek Centaur-C rev 17 [D-Link DFE-680TX] CardBus Fast Ethernet Adapter + +pci:v000013D1d0000AB03* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v000013D1d0000AB06* + ID_MODEL_FROM_DATABASE=RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter + +pci:v000013D1d0000AB08* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v000013D2* + ID_VENDOR_FROM_DATABASE=Shark Multimedia Inc + +pci:v000013D4* + ID_VENDOR_FROM_DATABASE=Graphics Microsystems Inc + +pci:v000013D5* + ID_VENDOR_FROM_DATABASE=Media 100 Inc + +pci:v000013D6* + ID_VENDOR_FROM_DATABASE=K.I. Technology Co Ltd + +pci:v000013D7* + ID_VENDOR_FROM_DATABASE=Toshiba Engineering Corporation + +pci:v000013D8* + ID_VENDOR_FROM_DATABASE=Phobos corporation + +pci:v000013D9* + ID_VENDOR_FROM_DATABASE=Apex PC Solutions Inc + +pci:v000013DA* + ID_VENDOR_FROM_DATABASE=Intresource Systems pte Ltd + +pci:v000013DB* + ID_VENDOR_FROM_DATABASE=Janich & Klass Computertechnik GmbH + +pci:v000013DC* + ID_VENDOR_FROM_DATABASE=Netboost Corporation + +pci:v000013DD* + ID_VENDOR_FROM_DATABASE=Multimedia Bundle Inc + +pci:v000013DE* + ID_VENDOR_FROM_DATABASE=ABB Robotics Products AB + +pci:v000013DF* + ID_VENDOR_FROM_DATABASE=E-Tech Inc + +pci:v000013DFd00000001* + ID_MODEL_FROM_DATABASE=PCI56RVP Modem + +pci:v000013DFd00000001sv000013DFsd00000001* + ID_MODEL_FROM_DATABASE=PCI56RVP Modem + +pci:v000013E0* + ID_VENDOR_FROM_DATABASE=GVC Corporation + +pci:v000013E1* + ID_VENDOR_FROM_DATABASE=Silicom Multimedia Systems Inc + +pci:v000013E2* + ID_VENDOR_FROM_DATABASE=Dynamics Research Corporation + +pci:v000013E3* + ID_VENDOR_FROM_DATABASE=Nest Inc + +pci:v000013E4* + ID_VENDOR_FROM_DATABASE=Calculex Inc + +pci:v000013E5* + ID_VENDOR_FROM_DATABASE=Telesoft Design Ltd + +pci:v000013E6* + ID_VENDOR_FROM_DATABASE=Argosy research Inc + +pci:v000013E7* + ID_VENDOR_FROM_DATABASE=NAC Incorporated + +pci:v000013E8* + ID_VENDOR_FROM_DATABASE=Chip Express Corporation + +pci:v000013E9* + ID_VENDOR_FROM_DATABASE=Intraserver Technology Inc + +pci:v000013EA* + ID_VENDOR_FROM_DATABASE=Dallas Semiconductor + +pci:v000013EB* + ID_VENDOR_FROM_DATABASE=Hauppauge Computer Works Inc + +pci:v000013EC* + ID_VENDOR_FROM_DATABASE=Zydacron Inc + +pci:v000013ECd0000000A* + ID_MODEL_FROM_DATABASE=NPC-RC01 Remote control receiver + +pci:v000013ED* + ID_VENDOR_FROM_DATABASE=Raytheion E-Systems + +pci:v000013EE* + ID_VENDOR_FROM_DATABASE=Hayes Microcomputer Products Inc + +pci:v000013EF* + ID_VENDOR_FROM_DATABASE=Coppercom Inc + +pci:v000013F0* + ID_VENDOR_FROM_DATABASE=Sundance Technology Inc / IC Plus Corp + +pci:v000013F0d00000200* + ID_MODEL_FROM_DATABASE=IC Plus IP100A Integrated 10/100 Ethernet MAC + PHY + +pci:v000013F0d00000200sv00001043sd00008213* + ID_MODEL_FROM_DATABASE=NX1001 + +pci:v000013F0d00000201* + ID_MODEL_FROM_DATABASE=ST201 Sundance Ethernet + +pci:v000013F0d00001021* + ID_MODEL_FROM_DATABASE=TC902x Gigabit Ethernet + +pci:v000013F0d00001023* + ID_MODEL_FROM_DATABASE=IP1000 Family Gigabit Ethernet + +pci:v000013F0d00001023sv00001043sd00008180* + ID_MODEL_FROM_DATABASE=NX1101 + +pci:v000013F1* + ID_VENDOR_FROM_DATABASE=Oce' - Technologies B.V. + +pci:v000013F2* + ID_VENDOR_FROM_DATABASE=Ford Microelectronics Inc + +pci:v000013F3* + ID_VENDOR_FROM_DATABASE=Mcdata Corporation + +pci:v000013F4* + ID_VENDOR_FROM_DATABASE=Troika Networks, Inc. + +pci:v000013F4d00001401* + ID_MODEL_FROM_DATABASE=Zentai Fibre Channel Adapter + +pci:v000013F5* + ID_VENDOR_FROM_DATABASE=Kansai Electric Co. Ltd + +pci:v000013F6* + ID_VENDOR_FROM_DATABASE=C-Media Electronics Inc + +pci:v000013F6d00000011* + ID_MODEL_FROM_DATABASE=CMI8738 + +pci:v000013F6d00000100* + ID_MODEL_FROM_DATABASE=CM8338A + +pci:v000013F6d00000100sv000013F6sd0000FFFF* + ID_MODEL_FROM_DATABASE=CMI8338/C3DX PCI Audio Device + +pci:v000013F6d00000101* + ID_MODEL_FROM_DATABASE=CM8338B + +pci:v000013F6d00000101sv000013F6sd00000101* + ID_MODEL_FROM_DATABASE=CMI8338-031 PCI Audio Device + +pci:v000013F6d00000111* + ID_MODEL_FROM_DATABASE=CMI8738/CMI8768 PCI Audio + +pci:v000013F6d00000111sv00001019sd00000970* + ID_MODEL_FROM_DATABASE=P6STP-FL motherboard + +pci:v000013F6d00000111sv00001043sd00008035* + ID_MODEL_FROM_DATABASE=CUSI-FX motherboard + +pci:v000013F6d00000111sv00001043sd00008077* + ID_MODEL_FROM_DATABASE=CMI8738 6-channel audio controller + +pci:v000013F6d00000111sv00001043sd000080E2* + ID_MODEL_FROM_DATABASE=CMI8738 6ch-MX + +pci:v000013F6d00000111sv000013F6sd00000111* + ID_MODEL_FROM_DATABASE=CMI8738/C3DX PCI Audio Device + +pci:v000013F6d00000111sv000013F6sd00009761* + ID_MODEL_FROM_DATABASE=Theatron Agrippa + +pci:v000013F6d00000111sv0000153Bsd00001144* + ID_MODEL_FROM_DATABASE=Aureon 5.1 + +pci:v000013F6d00000111sv0000153Bsd00001170* + ID_MODEL_FROM_DATABASE=Aureon 7.1 + +pci:v000013F6d00000111sv00001681sd0000A000* + ID_MODEL_FROM_DATABASE=Gamesurround MUSE XL + +pci:v000013F6d00000111sv000017ABsd00000604* + ID_MODEL_FROM_DATABASE=PSC604 Dynamic Edge + +pci:v000013F6d00000111sv000017ABsd00000605* + ID_MODEL_FROM_DATABASE=PSC605 Sonic Edge + +pci:v000013F6d00000111sv000017ABsd00007777* + ID_MODEL_FROM_DATABASE=PSC605 Sonic Edge + +pci:v000013F6d00000111sv0000270Fsd00001103* + ID_MODEL_FROM_DATABASE=CT-7NJS Ultra motherboard + +pci:v000013F6d00000111sv0000270Fsd0000F462* + ID_MODEL_FROM_DATABASE=7NJL1 motherboard + +pci:v000013F6d00000111sv0000584Dsd00003731* + ID_MODEL_FROM_DATABASE=Digital X-Mystique + +pci:v000013F6d00000111sv0000584Dsd00003741* + ID_MODEL_FROM_DATABASE=X-Plosion 7.1 + +pci:v000013F6d00000111sv0000584Dsd00003751* + ID_MODEL_FROM_DATABASE=X-Raider 7.1 + +pci:v000013F6d00000111sv0000584Dsd00003761* + ID_MODEL_FROM_DATABASE=X-Mystique 7.1 LP + +pci:v000013F6d00000111sv0000584Dsd00003771* + ID_MODEL_FROM_DATABASE=X-Mystique 7.1 LP Value + +pci:v000013F6d00000111sv00007284sd00008384* + ID_MODEL_FROM_DATABASE=Striker 7.1 + +pci:v000013F6d00000211* + ID_MODEL_FROM_DATABASE=CM8738 + +pci:v000013F6d00005011* + ID_MODEL_FROM_DATABASE=CM8888 [Oxygen Express] + +pci:v000013F6d00005011sv000013F6sd00005011* + ID_MODEL_FROM_DATABASE=HDA Controller + +pci:v000013F6d00008788* + ID_MODEL_FROM_DATABASE=CMI8788 [Oxygen HD Audio] + +pci:v000013F6d00008788sv00001043sd00008269* + ID_MODEL_FROM_DATABASE=Virtuoso 200 (Xonar D2) + +pci:v000013F6d00008788sv00001043sd00008275* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar DX) + +pci:v000013F6d00008788sv00001043sd000082B7* + ID_MODEL_FROM_DATABASE=Virtuoso 200 (Xonar D2X) + +pci:v000013F6d00008788sv00001043sd00008314* + ID_MODEL_FROM_DATABASE=Virtuoso 200 (Xonar HDAV1.3) + +pci:v000013F6d00008788sv00001043sd00008327* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar DX) + +pci:v000013F6d00008788sv00001043sd0000834F* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar D1) + +pci:v000013F6d00008788sv00001043sd0000835C* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar Essence STX) + +pci:v000013F6d00008788sv00001043sd0000835D* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar ST) + +pci:v000013F6d00008788sv00001043sd0000835E* + ID_MODEL_FROM_DATABASE=Virtuoso 200 (Xonar HDAV1.3 Slim) + +pci:v000013F6d00008788sv00001043sd0000838E* + ID_MODEL_FROM_DATABASE=Virtuoso 66 (Xonar DS) + +pci:v000013F6d00008788sv00001043sd00008428* + ID_MODEL_FROM_DATABASE=Virtuoso 100 (Xonar Xense) + +pci:v000013F6d00008788sv00001043sd00008467* + ID_MODEL_FROM_DATABASE=CMI8786 (Xonar DG) + +pci:v000013F6d00008788sv000013F6sd00008782* + ID_MODEL_FROM_DATABASE=PCI 2.0 HD Audio + +pci:v000013F6d00008788sv000013F6sd0000FFFF* + ID_MODEL_FROM_DATABASE=CMI8787-HG2PCI + +pci:v000013F6d00008788sv000014C3sd00001710* + ID_MODEL_FROM_DATABASE=HiFier Fantasia + +pci:v000013F6d00008788sv000014C3sd00001711* + ID_MODEL_FROM_DATABASE=HiFier Serenade + +pci:v000013F6d00008788sv000014C3sd00001713* + ID_MODEL_FROM_DATABASE=HiFier Serenade III + +pci:v000013F6d00008788sv00001A58sd00000910* + ID_MODEL_FROM_DATABASE=Barracuda AC-1 + +pci:v000013F6d00008788sv0000415Asd00005431* + ID_MODEL_FROM_DATABASE=X-Meridian 7.1 + +pci:v000013F6d00008788sv00005431sd0000017A* + ID_MODEL_FROM_DATABASE=X-Meridian 7.1 2G + +pci:v000013F6d00008788sv0000584Dsd00003781* + ID_MODEL_FROM_DATABASE=HDA X-Purity 7.1 Platinum + +pci:v000013F6d00008788sv00007284sd00009761* + ID_MODEL_FROM_DATABASE=CLARO + +pci:v000013F6d00008788sv00007284sd00009781* + ID_MODEL_FROM_DATABASE=CLARO halo + +pci:v000013F6d00008788sv00007284sd00009783* + ID_MODEL_FROM_DATABASE=eCLARO + +pci:v000013F6d00008788sv00007284sd00009787* + ID_MODEL_FROM_DATABASE=CLARO II + +pci:v000013F7* + ID_VENDOR_FROM_DATABASE=Wildfire Communications + +pci:v000013F8* + ID_VENDOR_FROM_DATABASE=Ad Lib Multimedia Inc + +pci:v000013F9* + ID_VENDOR_FROM_DATABASE=NTT Advanced Technology Corp. + +pci:v000013FA* + ID_VENDOR_FROM_DATABASE=Pentland Systems Ltd + +pci:v000013FB* + ID_VENDOR_FROM_DATABASE=Aydin Corp + +pci:v000013FC* + ID_VENDOR_FROM_DATABASE=Computer Peripherals International + +pci:v000013FD* + ID_VENDOR_FROM_DATABASE=Micro Science Inc + +pci:v000013FE* + ID_VENDOR_FROM_DATABASE=Advantech Co. Ltd + +pci:v000013FEd00001240* + ID_MODEL_FROM_DATABASE=PCI-1240 4-channel stepper motor controller card + +pci:v000013FEd00001600* + ID_MODEL_FROM_DATABASE=PCI-16xx series PCI multiport serial board (function 0) + +pci:v000013FEd00001600sv00001601sd00000002* + ID_MODEL_FROM_DATABASE=PCI-1601 2-port unisolated RS-422/485 + +pci:v000013FEd00001600sv00001602sd00000002* + ID_MODEL_FROM_DATABASE=PCI-1602 2-port isolated RS-422/485 + +pci:v000013FEd00001600sv00001612sd00000004* + ID_MODEL_FROM_DATABASE=PCI-1612 4-port RS-232/422/485 + +pci:v000013FEd00001603* + ID_MODEL_FROM_DATABASE=PCI-1603 2-port isolated RS-232/current loop + +pci:v000013FEd00001604* + ID_MODEL_FROM_DATABASE=PCI-1604 2-port RS-232 + +pci:v000013FEd000016FF* + ID_MODEL_FROM_DATABASE=PCI-16xx series PCI multiport serial board (function 1: RX/TX steering CPLD) + +pci:v000013FEd000016FFsv00001601sd00000000* + ID_MODEL_FROM_DATABASE=PCI-1601 2-port unisolated RS-422/485 PCI communications card + +pci:v000013FEd000016FFsv00001602sd00000000* + ID_MODEL_FROM_DATABASE=PCI-1602 2-port isolated RS-422/485 + +pci:v000013FEd000016FFsv00001612sd00000000* + ID_MODEL_FROM_DATABASE=PCI-1612 4-port RS-232/422/485 + +pci:v000013FEd00001711* + ID_MODEL_FROM_DATABASE=PCI-1711 16-channel data acquisition card 12-bit, 100kS/s + +pci:v000013FEd00001733* + ID_MODEL_FROM_DATABASE=PCI-1733 32-channel isolated digital input card + +pci:v000013FEd00001752* + ID_MODEL_FROM_DATABASE=PCI-1752 + +pci:v000013FEd00001754* + ID_MODEL_FROM_DATABASE=PCI-1754 + +pci:v000013FEd00001756* + ID_MODEL_FROM_DATABASE=PCI-1756 + +pci:v000013FF* + ID_VENDOR_FROM_DATABASE=Silicon Spice Inc + +pci:v00001400* + ID_VENDOR_FROM_DATABASE=Artx Inc + +pci:v00001400d00001401* + ID_MODEL_FROM_DATABASE=9432 TX + +pci:v00001401* + ID_VENDOR_FROM_DATABASE=CR-Systems A/S + +pci:v00001402* + ID_VENDOR_FROM_DATABASE=Meilhaus Electronic GmbH + +pci:v00001402d00000630* + ID_MODEL_FROM_DATABASE=ME-630 + +pci:v00001402d00000940* + ID_MODEL_FROM_DATABASE=ME-94 + +pci:v00001402d00000950* + ID_MODEL_FROM_DATABASE=ME-95 + +pci:v00001402d00000960* + ID_MODEL_FROM_DATABASE=ME-96 + +pci:v00001402d00001000* + ID_MODEL_FROM_DATABASE=ME-1000 + +pci:v00001402d0000100A* + ID_MODEL_FROM_DATABASE=ME-1000 + +pci:v00001402d0000100B* + ID_MODEL_FROM_DATABASE=ME-1000 + +pci:v00001402d00001400* + ID_MODEL_FROM_DATABASE=ME-1400 + +pci:v00001402d0000140A* + ID_MODEL_FROM_DATABASE=ME-1400A + +pci:v00001402d0000140B* + ID_MODEL_FROM_DATABASE=ME-1400B + +pci:v00001402d0000140C* + ID_MODEL_FROM_DATABASE=ME-1400C + +pci:v00001402d0000140D* + ID_MODEL_FROM_DATABASE=ME-1400D + +pci:v00001402d0000140E* + ID_MODEL_FROM_DATABASE=ME-1400E + +pci:v00001402d000014EA* + ID_MODEL_FROM_DATABASE=ME-1400EA + +pci:v00001402d000014EB* + ID_MODEL_FROM_DATABASE=ME-1400EB + +pci:v00001402d00001604* + ID_MODEL_FROM_DATABASE=ME-1600/4U + +pci:v00001402d00001608* + ID_MODEL_FROM_DATABASE=ME-1600/8U + +pci:v00001402d0000160C* + ID_MODEL_FROM_DATABASE=ME-1600/12U + +pci:v00001402d0000160F* + ID_MODEL_FROM_DATABASE=ME-1600/16U + +pci:v00001402d0000168F* + ID_MODEL_FROM_DATABASE=ME-1600/16U8I + +pci:v00001402d00004610* + ID_MODEL_FROM_DATABASE=ME-4610 + +pci:v00001402d00004650* + ID_MODEL_FROM_DATABASE=ME-4650 + +pci:v00001402d00004660* + ID_MODEL_FROM_DATABASE=ME-4660 + +pci:v00001402d00004661* + ID_MODEL_FROM_DATABASE=ME-4660I + +pci:v00001402d00004662* + ID_MODEL_FROM_DATABASE=ME-4660 + +pci:v00001402d00004663* + ID_MODEL_FROM_DATABASE=ME-4660I + +pci:v00001402d00004670* + ID_MODEL_FROM_DATABASE=ME-4670 + +pci:v00001402d00004671* + ID_MODEL_FROM_DATABASE=ME-4670I + +pci:v00001402d00004672* + ID_MODEL_FROM_DATABASE=ME-4670S + +pci:v00001402d00004673* + ID_MODEL_FROM_DATABASE=ME-4670IS + +pci:v00001402d00004680* + ID_MODEL_FROM_DATABASE=ME-4680 + +pci:v00001402d00004681* + ID_MODEL_FROM_DATABASE=ME-4680I + +pci:v00001402d00004682* + ID_MODEL_FROM_DATABASE=ME-4680S + +pci:v00001402d00004683* + ID_MODEL_FROM_DATABASE=ME-4680IS + +pci:v00001402d00006004* + ID_MODEL_FROM_DATABASE=ME-6000/4 + +pci:v00001402d00006008* + ID_MODEL_FROM_DATABASE=ME-6000/8 + +pci:v00001402d0000600F* + ID_MODEL_FROM_DATABASE=ME-6000/16 + +pci:v00001402d00006014* + ID_MODEL_FROM_DATABASE=ME-6000I/4 + +pci:v00001402d00006018* + ID_MODEL_FROM_DATABASE=ME-6000I/8 + +pci:v00001402d0000601F* + ID_MODEL_FROM_DATABASE=ME-6000I/16 + +pci:v00001402d00006034* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/4 + +pci:v00001402d00006038* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/8 + +pci:v00001402d0000603F* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/16 + +pci:v00001402d00006044* + ID_MODEL_FROM_DATABASE=ME-6000/4/DIO + +pci:v00001402d00006048* + ID_MODEL_FROM_DATABASE=ME-6000/8/DIO + +pci:v00001402d0000604F* + ID_MODEL_FROM_DATABASE=ME-6000/16/DIO + +pci:v00001402d00006054* + ID_MODEL_FROM_DATABASE=ME-6000I/4/DIO + +pci:v00001402d00006058* + ID_MODEL_FROM_DATABASE=ME-6000I/8/DIO + +pci:v00001402d0000605F* + ID_MODEL_FROM_DATABASE=ME-6000I/16/DIO + +pci:v00001402d00006074* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/4/DIO + +pci:v00001402d00006078* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/8/DIO + +pci:v00001402d0000607F* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/16/DIO + +pci:v00001402d00006104* + ID_MODEL_FROM_DATABASE=ME-6100/4 + +pci:v00001402d00006108* + ID_MODEL_FROM_DATABASE=ME-6100/8 + +pci:v00001402d0000610F* + ID_MODEL_FROM_DATABASE=ME-6100/16 + +pci:v00001402d00006114* + ID_MODEL_FROM_DATABASE=ME-6100I/4 + +pci:v00001402d00006118* + ID_MODEL_FROM_DATABASE=ME-6100I/8 + +pci:v00001402d0000611F* + ID_MODEL_FROM_DATABASE=ME-6100I/16 + +pci:v00001402d00006134* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/4 + +pci:v00001402d00006138* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/8 + +pci:v00001402d0000613F* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/16 + +pci:v00001402d00006144* + ID_MODEL_FROM_DATABASE=ME-6100/4/DIO + +pci:v00001402d00006148* + ID_MODEL_FROM_DATABASE=ME-6100/8/DIO + +pci:v00001402d0000614F* + ID_MODEL_FROM_DATABASE=ME-6100/16/DIO + +pci:v00001402d00006154* + ID_MODEL_FROM_DATABASE=ME-6100I/4/DIO + +pci:v00001402d00006158* + ID_MODEL_FROM_DATABASE=ME-6100I/8/DIO + +pci:v00001402d0000615F* + ID_MODEL_FROM_DATABASE=ME-6100I/16/DIO + +pci:v00001402d00006174* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/4/DIO + +pci:v00001402d00006178* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/8/DIO + +pci:v00001402d0000617F* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/16/DIO + +pci:v00001402d00006259* + ID_MODEL_FROM_DATABASE=ME-6200I/9/DIO + +pci:v00001402d00006359* + ID_MODEL_FROM_DATABASE=ME-6300I/9/DIO + +pci:v00001402d0000810A* + ID_MODEL_FROM_DATABASE=ME-8100A + +pci:v00001402d0000810B* + ID_MODEL_FROM_DATABASE=ME-8100B + +pci:v00001402d0000820A* + ID_MODEL_FROM_DATABASE=ME-8200A + +pci:v00001402d0000820B* + ID_MODEL_FROM_DATABASE=ME-8200B + +pci:v00001403* + ID_VENDOR_FROM_DATABASE=Ascor Inc + +pci:v00001404* + ID_VENDOR_FROM_DATABASE=Fundamental Software Inc + +pci:v00001405* + ID_VENDOR_FROM_DATABASE=Excalibur Systems Inc + +pci:v00001406* + ID_VENDOR_FROM_DATABASE=Oce' Printing Systems GmbH + +pci:v00001407* + ID_VENDOR_FROM_DATABASE=Lava Computer mfg Inc + +pci:v00001407d00000100* + ID_MODEL_FROM_DATABASE=Lava Dual Serial + +pci:v00001407d00000101* + ID_MODEL_FROM_DATABASE=Lava Quatro A + +pci:v00001407d00000102* + ID_MODEL_FROM_DATABASE=Lava Quatro B + +pci:v00001407d00000110* + ID_MODEL_FROM_DATABASE=Lava DSerial-PCI Port A + +pci:v00001407d00000111* + ID_MODEL_FROM_DATABASE=Lava DSerial-PCI Port B + +pci:v00001407d00000120* + ID_MODEL_FROM_DATABASE=Quattro-PCI A + +pci:v00001407d00000121* + ID_MODEL_FROM_DATABASE=Quattro-PCI B + +pci:v00001407d00000180* + ID_MODEL_FROM_DATABASE=Lava Octo A + +pci:v00001407d00000181* + ID_MODEL_FROM_DATABASE=Lava Octo B + +pci:v00001407d00000200* + ID_MODEL_FROM_DATABASE=Lava Port Plus + +pci:v00001407d00000201* + ID_MODEL_FROM_DATABASE=Lava Quad A + +pci:v00001407d00000202* + ID_MODEL_FROM_DATABASE=Lava Quad B + +pci:v00001407d00000220* + ID_MODEL_FROM_DATABASE=Lava Quattro PCI Ports A/B + +pci:v00001407d00000221* + ID_MODEL_FROM_DATABASE=Lava Quattro PCI Ports C/D + +pci:v00001407d00000400* + ID_MODEL_FROM_DATABASE=Lava 8255-PIO-PCI + +pci:v00001407d00000500* + ID_MODEL_FROM_DATABASE=Lava Single Serial + +pci:v00001407d00000520* + ID_MODEL_FROM_DATABASE=Lava RS422-SS-PCI + +pci:v00001407d00000600* + ID_MODEL_FROM_DATABASE=Lava Port 650 + +pci:v00001407d00008000* + ID_MODEL_FROM_DATABASE=Lava Parallel + +pci:v00001407d00008001* + ID_MODEL_FROM_DATABASE=Dual parallel port controller A + +pci:v00001407d00008002* + ID_MODEL_FROM_DATABASE=Lava Dual Parallel port A + +pci:v00001407d00008003* + ID_MODEL_FROM_DATABASE=Lava Dual Parallel port B + +pci:v00001407d00008800* + ID_MODEL_FROM_DATABASE=BOCA Research IOPPAR + +pci:v00001408* + ID_VENDOR_FROM_DATABASE=Aloka Co. Ltd + +pci:v00001409* + ID_VENDOR_FROM_DATABASE=Timedia Technology Co Ltd + +pci:v00001409d00007168* + ID_MODEL_FROM_DATABASE=PCI2S550 (Dual 16550 UART) + +pci:v00001409d00007168sv00001409sd00000002* + ID_MODEL_FROM_DATABASE=SER4036A3V (2x RS232 port) + +pci:v00001409d00007168sv00001409sd00004027* + ID_MODEL_FROM_DATABASE=SER4027A (1x RS232 port) + +pci:v00001409d00007168sv00001409sd00004037* + ID_MODEL_FROM_DATABASE=SER4037A (2x RS232 port) + +pci:v00001409d00007168sv00001409sd00004056* + ID_MODEL_FROM_DATABASE=SER4056A (4x RS232) + +pci:v00001409d00007168sv00001409sd00005027* + ID_MODEL_FROM_DATABASE=SER4027D + +pci:v00001409d00007168sv00001409sd00005037* + ID_MODEL_FROM_DATABASE=SER4037D (2x RS232 port) + +pci:v00001409d00007168sv00001409sd00005066* + ID_MODEL_FROM_DATABASE=SER4066R (8x RS232) + +pci:v00001409d00007168sv00001409sd00006056* + ID_MODEL_FROM_DATABASE=SER4056D (4x RS232 port) + +pci:v00001409d00007268* + ID_MODEL_FROM_DATABASE=SUN1888 (Dual IEEE1284 parallel port) + +pci:v00001409d00007268sv00001409sd00000103* + ID_MODEL_FROM_DATABASE=PAR4008A + +pci:v00001409d00007268sv00001409sd00000104* + ID_MODEL_FROM_DATABASE=PAR4018A + +pci:v0000140A* + ID_VENDOR_FROM_DATABASE=DSP Research Inc + +pci:v0000140B* + ID_VENDOR_FROM_DATABASE=GE Intelligent Platforms + +pci:v0000140C* + ID_VENDOR_FROM_DATABASE=Elmic Systems Inc + +pci:v0000140D* + ID_VENDOR_FROM_DATABASE=Matsushita Electric Works Ltd + +pci:v0000140E* + ID_VENDOR_FROM_DATABASE=Goepel Electronic GmbH + +pci:v0000140F* + ID_VENDOR_FROM_DATABASE=Salient Systems Corp + +pci:v00001410* + ID_VENDOR_FROM_DATABASE=Midas lab Inc + +pci:v00001411* + ID_VENDOR_FROM_DATABASE=Ikos Systems Inc + +pci:v00001412* + ID_VENDOR_FROM_DATABASE=VIA Technologies Inc. + +pci:v00001412d00001712* + ID_MODEL_FROM_DATABASE=ICE1712 [Envy24] PCI Multi-Channel I/O Controller + +pci:v00001412d00001712sv00001412sd00001712* + ID_MODEL_FROM_DATABASE=Hoontech ST Audio DSP 24 + +pci:v00001412d00001712sv00001412sd00003632* + ID_MODEL_FROM_DATABASE=M-Audio Delta Audiophile 192 + +pci:v00001412d00001712sv00001412sd0000D630* + ID_MODEL_FROM_DATABASE=M-Audio Delta 1010 + +pci:v00001412d00001712sv00001412sd0000D631* + ID_MODEL_FROM_DATABASE=M-Audio Delta DiO + +pci:v00001412d00001712sv00001412sd0000D632* + ID_MODEL_FROM_DATABASE=M-Audio Delta 66 + +pci:v00001412d00001712sv00001412sd0000D633* + ID_MODEL_FROM_DATABASE=M-Audio Delta 44 + +pci:v00001412d00001712sv00001412sd0000D634* + ID_MODEL_FROM_DATABASE=M-Audio Delta Audiophile 2496 + +pci:v00001412d00001712sv00001412sd0000D635* + ID_MODEL_FROM_DATABASE=M-Audio Delta TDIF + +pci:v00001412d00001712sv00001412sd0000D637* + ID_MODEL_FROM_DATABASE=M-Audio Delta RBUS + +pci:v00001412d00001712sv00001412sd0000D638* + ID_MODEL_FROM_DATABASE=M-Audio Delta 410 + +pci:v00001412d00001712sv00001412sd0000D63B* + ID_MODEL_FROM_DATABASE=M-Audio Delta 1010LT + +pci:v00001412d00001712sv00001412sd0000D63C* + ID_MODEL_FROM_DATABASE=Digigram VX442 + +pci:v00001412d00001712sv00001416sd00001712* + ID_MODEL_FROM_DATABASE=Hoontech ST Audio DSP 24 Media 7.1 + +pci:v00001412d00001712sv0000153Bsd00001115* + ID_MODEL_FROM_DATABASE=EWS88 MT + +pci:v00001412d00001712sv0000153Bsd00001125* + ID_MODEL_FROM_DATABASE=EWS88 MT (Master) + +pci:v00001412d00001712sv0000153Bsd0000112B* + ID_MODEL_FROM_DATABASE=EWS88 D + +pci:v00001412d00001712sv0000153Bsd0000112C* + ID_MODEL_FROM_DATABASE=EWS88 D (Master) + +pci:v00001412d00001712sv0000153Bsd00001130* + ID_MODEL_FROM_DATABASE=EWX 24/96 + +pci:v00001412d00001712sv0000153Bsd00001138* + ID_MODEL_FROM_DATABASE=DMX 6fire 24/96 + +pci:v00001412d00001712sv0000153Bsd00001151* + ID_MODEL_FROM_DATABASE=PHASE88 + +pci:v00001412d00001712sv000016CEsd00001040* + ID_MODEL_FROM_DATABASE=Edirol DA-2496 + +pci:v00001412d00001724* + ID_MODEL_FROM_DATABASE=VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller + +pci:v00001412d00001724sv000010B0sd00000200* + ID_MODEL_FROM_DATABASE=Hollywood@Home 7.1 + +pci:v00001412d00001724sv00001412sd00001724* + ID_MODEL_FROM_DATABASE=Albatron PX865PE 7.1 + +pci:v00001412d00001724sv00001412sd00003630* + ID_MODEL_FROM_DATABASE=M-Audio Revolution 7.1 + +pci:v00001412d00001724sv00001412sd00003631* + ID_MODEL_FROM_DATABASE=M-Audio Revolution 5.1 + +pci:v00001412d00001724sv0000153Bsd00001145* + ID_MODEL_FROM_DATABASE=Aureon 7.1 Space + +pci:v00001412d00001724sv0000153Bsd00001147* + ID_MODEL_FROM_DATABASE=Aureon 5.1 Sky + +pci:v00001412d00001724sv0000153Bsd00001150* + ID_MODEL_FROM_DATABASE=PHASE 22 + +pci:v00001412d00001724sv0000153Bsd00001153* + ID_MODEL_FROM_DATABASE=Aureon 7.1 Universe + +pci:v00001412d00001724sv000017ABsd00001906* + ID_MODEL_FROM_DATABASE=PSC 724 [Ultimate Edge] + +pci:v00001412d00001724sv0000270Fsd0000F641* + ID_MODEL_FROM_DATABASE=ZNF3-150 + +pci:v00001412d00001724sv0000270Fsd0000F645* + ID_MODEL_FROM_DATABASE=ZNF3-250 + +pci:v00001412d00001724sv00003130sd00004154* + ID_MODEL_FROM_DATABASE=MAYA 44 MKII + +pci:v00001413* + ID_VENDOR_FROM_DATABASE=Addonics + +pci:v00001414* + ID_VENDOR_FROM_DATABASE=Microsoft Corporation + +pci:v00001414d00000001* + ID_MODEL_FROM_DATABASE=MN-120 (ADMtek Centaur-C based) + +pci:v00001414d00000002* + ID_MODEL_FROM_DATABASE=MN-130 (ADMtek Centaur-P based) + +pci:v00001414d00005353* + ID_MODEL_FROM_DATABASE=Hyper-V virtual VGA + +pci:v00001414d00005801* + ID_MODEL_FROM_DATABASE=XMA Decoder (Xenon) + +pci:v00001414d00005802* + ID_MODEL_FROM_DATABASE=SATA Controller - CdRom (Xenon) + +pci:v00001414d00005803* + ID_MODEL_FROM_DATABASE=SATA Controller - Disk (Xenon) + +pci:v00001414d00005804* + ID_MODEL_FROM_DATABASE=OHCI Controller 0 (Xenon) + +pci:v00001414d00005805* + ID_MODEL_FROM_DATABASE=EHCI Controller 0 (Xenon) + +pci:v00001414d00005806* + ID_MODEL_FROM_DATABASE=OHCI Controller 1 (Xenon) + +pci:v00001414d00005807* + ID_MODEL_FROM_DATABASE=EHCI Controller 1 (Xenon) + +pci:v00001414d0000580A* + ID_MODEL_FROM_DATABASE=Fast Ethernet Adapter (Xenon) + +pci:v00001414d0000580B* + ID_MODEL_FROM_DATABASE=Secure Flash Controller (Xenon) + +pci:v00001414d0000580D* + ID_MODEL_FROM_DATABASE=System Management Controller (Xenon) + +pci:v00001414d00005811* + ID_MODEL_FROM_DATABASE=Xenos GPU (Xenon) + +pci:v00001415* + ID_VENDOR_FROM_DATABASE=Oxford Semiconductor Ltd + +pci:v00001415d00008401* + ID_MODEL_FROM_DATABASE=OX9162 Mode 1 (8-bit bus) + +pci:v00001415d00008403* + ID_MODEL_FROM_DATABASE=OX9162 Mode 0 (parallel port) + +pci:v00001415d00009500* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 0 (Disabled) + +pci:v00001415d00009501* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 0 (Uart) + +pci:v00001415d00009501sv000012C4sd00000201* + ID_MODEL_FROM_DATABASE=Titan/cPCI (2 port) + +pci:v00001415d00009501sv000012C4sd00000202* + ID_MODEL_FROM_DATABASE=Titan/cPCI (4 port) + +pci:v00001415d00009501sv000012C4sd00000203* + ID_MODEL_FROM_DATABASE=Titan/cPCI (8 port) + +pci:v00001415d00009501sv000012C4sd00000210* + ID_MODEL_FROM_DATABASE=Titan/104-Plus (8 port, p1-4) + +pci:v00001415d00009501sv0000131Fsd00002050* + ID_MODEL_FROM_DATABASE=CyberPro (4-port) + +pci:v00001415d00009501sv0000131Fsd00002051* + ID_MODEL_FROM_DATABASE=CyberSerial 4S Plus + +pci:v00001415d00009501sv000015EDsd00002000* + ID_MODEL_FROM_DATABASE=MCCR Serial p0-3 of 8 + +pci:v00001415d00009501sv000015EDsd00002001* + ID_MODEL_FROM_DATABASE=MCCR Serial p0-3 of 16 + +pci:v00001415d00009505* + ID_MODEL_FROM_DATABASE=OXuPCI952 (Dual 16C950 UART) + +pci:v00001415d0000950A* + ID_MODEL_FROM_DATABASE=EXSYS EX-41092 Dual 16950 Serial adapter + +pci:v00001415d0000950B* + ID_MODEL_FROM_DATABASE=OXCB950 Cardbus 16950 UART + +pci:v00001415d00009510* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 1 (Disabled) + +pci:v00001415d00009510sv000012C4sd00000200* + ID_MODEL_FROM_DATABASE=Titan/cPCI (Unused) + +pci:v00001415d00009511* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 1 (8bit bus) + +pci:v00001415d00009511sv000012C4sd00000211* + ID_MODEL_FROM_DATABASE=Titan/104-Plus (8 port, p5-8) + +pci:v00001415d00009511sv000015EDsd00002000* + ID_MODEL_FROM_DATABASE=MCCR Serial p4-7 of 8 + +pci:v00001415d00009511sv000015EDsd00002001* + ID_MODEL_FROM_DATABASE=MCCR Serial p4-15 of 16 + +pci:v00001415d00009512* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 1 (32bit bus) + +pci:v00001415d00009513* + ID_MODEL_FROM_DATABASE=OX16PCI954 (Quad 16950 UART) function 1 (parallel port) + +pci:v00001415d00009521* + ID_MODEL_FROM_DATABASE=OX16PCI952 (Dual 16950 UART) + +pci:v00001415d00009523* + ID_MODEL_FROM_DATABASE=OX16PCI952 Integrated Parallel Port + +pci:v00001415d0000C158* + ID_MODEL_FROM_DATABASE=OXPCIe952 Dual 16C950 UART + +pci:v00001415d0000C158sv0000E4BFsd0000C504* + ID_MODEL_FROM_DATABASE=CP4-SCAT Wireless Technologies Carrier Board + +pci:v00001415d0000C158sv0000E4BFsd0000D551* + ID_MODEL_FROM_DATABASE=DU1-MUSTANG Dual-Port RS-485 Interface + +pci:v00001415d0000C308* + ID_MODEL_FROM_DATABASE=EX-44016 16-port serial + +pci:v00001416* + ID_VENDOR_FROM_DATABASE=Multiwave Innovation pte Ltd + +pci:v00001417* + ID_VENDOR_FROM_DATABASE=Convergenet Technologies Inc + +pci:v00001418* + ID_VENDOR_FROM_DATABASE=Kyushu electronics systems Inc + +pci:v00001419* + ID_VENDOR_FROM_DATABASE=Excel Switching Corp + +pci:v0000141A* + ID_VENDOR_FROM_DATABASE=Apache Micro Peripherals Inc + +pci:v0000141B* + ID_VENDOR_FROM_DATABASE=Zoom Telephonics Inc + +pci:v0000141D* + ID_VENDOR_FROM_DATABASE=Digitan Systems Inc + +pci:v0000141E* + ID_VENDOR_FROM_DATABASE=Fanuc Ltd + +pci:v0000141F* + ID_VENDOR_FROM_DATABASE=Visiontech Ltd + +pci:v00001420* + ID_VENDOR_FROM_DATABASE=Psion Dacom plc + +pci:v00001420d00008002* + ID_MODEL_FROM_DATABASE=Gold Card NetGlobal 56k+10/100Mb CardBus (Ethernet part) + +pci:v00001420d00008003* + ID_MODEL_FROM_DATABASE=Gold Card NetGlobal 56k+10/100Mb CardBus (Modem part) + +pci:v00001421* + ID_VENDOR_FROM_DATABASE=Ads Technologies Inc + +pci:v00001422* + ID_VENDOR_FROM_DATABASE=Ygrec Systems Co Ltd + +pci:v00001423* + ID_VENDOR_FROM_DATABASE=Custom Technology Corp. + +pci:v00001424* + ID_VENDOR_FROM_DATABASE=Videoserver Connections + +pci:v00001425* + ID_VENDOR_FROM_DATABASE=Chelsio Communications Inc + +pci:v00001425d0000000B* + ID_MODEL_FROM_DATABASE=T210 Protocol Engine + +pci:v00001425d0000000C* + ID_MODEL_FROM_DATABASE=T204 Protocol Engine + +pci:v00001425d00000022* + ID_MODEL_FROM_DATABASE=10GbE Ethernet Adapter + +pci:v00001425d00000030* + ID_MODEL_FROM_DATABASE=T310 10GbE Single Port Adapter + +pci:v00001425d00000030sv0000103Csd0000705E* + ID_MODEL_FROM_DATABASE=PCIe 10GBase-SR [AD386A] + +pci:v00001425d00000031* + ID_MODEL_FROM_DATABASE=T320 10GbE Dual Port Adapter + +pci:v00001425d00000032* + ID_MODEL_FROM_DATABASE=T302 1GbE Dual Port Adapter + +pci:v00001425d00000033* + ID_MODEL_FROM_DATABASE=T304 1GbE Quad Port Adapter + +pci:v00001425d00000034* + ID_MODEL_FROM_DATABASE=B320 10GbE Dual Port Adapter + +pci:v00001425d00000035* + ID_MODEL_FROM_DATABASE=S310-CR 10GbE Single Port Adapter + +pci:v00001425d00000036* + ID_MODEL_FROM_DATABASE=S320-LP-CR 10GbE Dual Port Adapter + +pci:v00001425d00000037* + ID_MODEL_FROM_DATABASE=N320-G2-CR 10GbE Dual Port Adapter + +pci:v00001425d00004001* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Ethernet Controller + +pci:v00001425d00004002* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Ethernet Controller + +pci:v00001425d00004003* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Ethernet Controller + +pci:v00001425d00004004* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004005* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004006* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Ethernet Controller + +pci:v00001425d00004007* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Ethernet Controller + +pci:v00001425d00004008* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Ethernet Controller + +pci:v00001425d00004009* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Ethernet Controller + +pci:v00001425d0000400A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000400B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Ethernet Controller + +pci:v00001425d0000400C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000400D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Ethernet Controller + +pci:v00001425d0000400E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000400F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00004080* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Ethernet Controller + +pci:v00001425d00004081* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Ethernet Controller + +pci:v00001425d00004082* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Ethernet Controller + +pci:v00001425d00004083* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Ethernet Controller + +pci:v00001425d00004084* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Ethernet Controller + +pci:v00001425d00004085* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Ethernet Controller + +pci:v00001425d00004086* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Ethernet Controller + +pci:v00001425d00004087* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Ethernet Controller + +pci:v00001425d00004088* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Ethernet Controller + +pci:v00001425d00004401* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Ethernet Controller + +pci:v00001425d00004402* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Ethernet Controller + +pci:v00001425d00004403* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Ethernet Controller + +pci:v00001425d00004404* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004405* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004406* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Ethernet Controller + +pci:v00001425d00004407* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Ethernet Controller + +pci:v00001425d00004408* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Ethernet Controller + +pci:v00001425d00004409* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Ethernet Controller + +pci:v00001425d0000440A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000440B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Ethernet Controller + +pci:v00001425d0000440C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000440D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Ethernet Controller + +pci:v00001425d0000440E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000440F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00004480* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Ethernet Controller + +pci:v00001425d00004481* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Ethernet Controller + +pci:v00001425d00004482* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Ethernet Controller + +pci:v00001425d00004483* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Ethernet Controller + +pci:v00001425d00004484* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Ethernet Controller + +pci:v00001425d00004485* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Ethernet Controller + +pci:v00001425d00004486* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Ethernet Controller + +pci:v00001425d00004487* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Ethernet Controller + +pci:v00001425d00004488* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Ethernet Controller + +pci:v00001425d00004501* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Storage Controller + +pci:v00001425d00004502* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Storage Controller + +pci:v00001425d00004503* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Storage Controller + +pci:v00001425d00004504* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Storage Controller + +pci:v00001425d00004505* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Storage Controller + +pci:v00001425d00004506* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Storage Controller + +pci:v00001425d00004507* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Storage Controller + +pci:v00001425d00004508* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Storage Controller + +pci:v00001425d00004509* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Storage Controller + +pci:v00001425d0000450A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Storage Controller + +pci:v00001425d0000450B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Storage Controller + +pci:v00001425d0000450C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Storage Controller + +pci:v00001425d0000450D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Storage Controller + +pci:v00001425d0000450E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Storage Controller + +pci:v00001425d0000450F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Storage Controller + +pci:v00001425d00004580* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Storage Controller + +pci:v00001425d00004581* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Storage Controller + +pci:v00001425d00004582* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Storage Controller + +pci:v00001425d00004583* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Storage Controller + +pci:v00001425d00004584* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Storage Controller + +pci:v00001425d00004585* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Storage Controller + +pci:v00001425d00004586* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Storage Controller + +pci:v00001425d00004587* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Storage Controller + +pci:v00001425d00004588* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Storage Controller + +pci:v00001425d00004601* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Storage Controller + +pci:v00001425d00004602* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Storage Controller + +pci:v00001425d00004603* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Storage Controller + +pci:v00001425d00004604* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Storage Controller + +pci:v00001425d00004605* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Storage Controller + +pci:v00001425d00004606* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Storage Controller + +pci:v00001425d00004607* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Storage Controller + +pci:v00001425d00004608* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Storage Controller + +pci:v00001425d00004609* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Storage Controller + +pci:v00001425d0000460A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Storage Controller + +pci:v00001425d0000460B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Storage Controller + +pci:v00001425d0000460C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Storage Controller + +pci:v00001425d0000460D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Storage Controller + +pci:v00001425d0000460E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Storage Controller + +pci:v00001425d0000460F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Storage Controller + +pci:v00001425d00004680* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Storage Controller + +pci:v00001425d00004681* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Storage Controller + +pci:v00001425d00004682* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Storage Controller + +pci:v00001425d00004683* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Storage Controller + +pci:v00001425d00004684* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Storage Controller + +pci:v00001425d00004685* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Storage Controller + +pci:v00001425d00004686* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Storage Controller + +pci:v00001425d00004687* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Storage Controller + +pci:v00001425d00004688* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Storage Controller + +pci:v00001425d00004701* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Ethernet Controller + +pci:v00001425d00004702* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Ethernet Controller + +pci:v00001425d00004703* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Ethernet Controller + +pci:v00001425d00004704* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004705* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004706* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Ethernet Controller + +pci:v00001425d00004707* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Ethernet Controller + +pci:v00001425d00004708* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Ethernet Controller + +pci:v00001425d00004709* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Ethernet Controller + +pci:v00001425d0000470A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000470B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Ethernet Controller + +pci:v00001425d0000470C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000470D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Ethernet Controller + +pci:v00001425d0000470E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000470F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00004780* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Ethernet Controller + +pci:v00001425d00004781* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Ethernet Controller + +pci:v00001425d00004782* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Ethernet Controller + +pci:v00001425d00004783* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Ethernet Controller + +pci:v00001425d00004784* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Ethernet Controller + +pci:v00001425d00004785* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Ethernet Controller + +pci:v00001425d00004786* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Ethernet Controller + +pci:v00001425d00004787* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Ethernet Controller + +pci:v00001425d00004788* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Ethernet Controller + +pci:v00001425d00004801* + ID_MODEL_FROM_DATABASE=T420-CR Unified Wire Ethernet Controller + +pci:v00001425d00004802* + ID_MODEL_FROM_DATABASE=T422-CR Unified Wire Ethernet Controller + +pci:v00001425d00004803* + ID_MODEL_FROM_DATABASE=T440-CR Unified Wire Ethernet Controller + +pci:v00001425d00004804* + ID_MODEL_FROM_DATABASE=T420-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004805* + ID_MODEL_FROM_DATABASE=T440-BCH Unified Wire Ethernet Controller + +pci:v00001425d00004806* + ID_MODEL_FROM_DATABASE=T440-CH Unified Wire Ethernet Controller + +pci:v00001425d00004807* + ID_MODEL_FROM_DATABASE=T420-SO Unified Wire Ethernet Controller + +pci:v00001425d00004808* + ID_MODEL_FROM_DATABASE=T420-CX Unified Wire Ethernet Controller + +pci:v00001425d00004809* + ID_MODEL_FROM_DATABASE=T420-BT Unified Wire Ethernet Controller + +pci:v00001425d0000480A* + ID_MODEL_FROM_DATABASE=T404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000480B* + ID_MODEL_FROM_DATABASE=B420-SR Unified Wire Ethernet Controller + +pci:v00001425d0000480C* + ID_MODEL_FROM_DATABASE=B404-BT Unified Wire Ethernet Controller + +pci:v00001425d0000480D* + ID_MODEL_FROM_DATABASE=T480 Unified Wire Ethernet Controller + +pci:v00001425d0000480E* + ID_MODEL_FROM_DATABASE=T440-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000480F* + ID_MODEL_FROM_DATABASE=T440 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00004880* + ID_MODEL_FROM_DATABASE=T480-4080 T480 Unified Wire Ethernet Controller + +pci:v00001425d00004881* + ID_MODEL_FROM_DATABASE=T440F-4081 T440-FCoE Unified Wire Ethernet Controller + +pci:v00001425d00004882* + ID_MODEL_FROM_DATABASE=T420-4082 Unified Wire Ethernet Controller + +pci:v00001425d00004883* + ID_MODEL_FROM_DATABASE=T420X-4083 Unified Wire Ethernet Controller + +pci:v00001425d00004884* + ID_MODEL_FROM_DATABASE=T420-4084 Unified Wire Ethernet Controller + +pci:v00001425d00004885* + ID_MODEL_FROM_DATABASE=T420-4085 SFP+ Unified Wire Ethernet Controller + +pci:v00001425d00004886* + ID_MODEL_FROM_DATABASE=T440-4086 10Gbase-T Unified Wire Ethernet Controller + +pci:v00001425d00004887* + ID_MODEL_FROM_DATABASE=T440T-4087 Unified Wire Ethernet Controller + +pci:v00001425d00004888* + ID_MODEL_FROM_DATABASE=T440-4088 Unified Wire Ethernet Controller + +pci:v00001425d00005001* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +pci:v00001425d00005002* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Ethernet Controller + +pci:v00001425d00005003* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Ethernet Controller + +pci:v00001425d00005004* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005005* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005006* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Ethernet Controller + +pci:v00001425d00005007* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Ethernet Controller + +pci:v00001425d00005008* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Ethernet Controller + +pci:v00001425d00005009* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Ethernet Controller + +pci:v00001425d0000500A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000500B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Ethernet Controller + +pci:v00001425d0000500C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000500D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d0000500E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000500F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00005010* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d00005011* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Ethernet Controller + +pci:v00001425d00005012* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Ethernet Controller + +pci:v00001425d00005013* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d00005014* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Ethernet Controller + +pci:v00001425d00005080* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Ethernet Controller + +pci:v00001425d00005081* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Ethernet Controller + +pci:v00001425d00005401* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +pci:v00001425d00005402* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Ethernet Controller + +pci:v00001425d00005403* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Ethernet Controller + +pci:v00001425d00005404* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005405* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005406* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Ethernet Controller + +pci:v00001425d00005407* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Ethernet Controller + +pci:v00001425d00005408* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Ethernet Controller + +pci:v00001425d00005409* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Ethernet Controller + +pci:v00001425d0000540A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000540B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Ethernet Controller + +pci:v00001425d0000540C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000540D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d0000540E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000540F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00005410* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d00005411* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Ethernet Controller + +pci:v00001425d00005412* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Ethernet Controller + +pci:v00001425d00005413* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d00005414* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Ethernet Controller + +pci:v00001425d00005480* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Ethernet Controller + +pci:v00001425d00005481* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Ethernet Controller + +pci:v00001425d00005501* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +pci:v00001425d00005502* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Storage Controller + +pci:v00001425d00005503* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Storage Controller + +pci:v00001425d00005504* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Storage Controller + +pci:v00001425d00005505* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Storage Controller + +pci:v00001425d00005506* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Storage Controller + +pci:v00001425d00005507* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Storage Controller + +pci:v00001425d00005508* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Storage Controller + +pci:v00001425d00005509* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Storage Controller + +pci:v00001425d0000550A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Storage Controller + +pci:v00001425d0000550B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Storage Controller + +pci:v00001425d0000550C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Storage Controller + +pci:v00001425d0000550D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Storage Controller + +pci:v00001425d0000550E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Storage Controller + +pci:v00001425d0000550F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Storage Controller + +pci:v00001425d00005510* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Storage Controller + +pci:v00001425d00005511* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Storage Controller + +pci:v00001425d00005512* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Storage Controller + +pci:v00001425d00005513* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Storage Controller + +pci:v00001425d00005514* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Storage Controller + +pci:v00001425d00005580* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Storage Controller + +pci:v00001425d00005581* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Storage Controller + +pci:v00001425d00005601* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller + +pci:v00001425d00005602* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Storage Controller + +pci:v00001425d00005603* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Storage Controller + +pci:v00001425d00005604* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Storage Controller + +pci:v00001425d00005605* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Storage Controller + +pci:v00001425d00005606* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Storage Controller + +pci:v00001425d00005607* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Storage Controller + +pci:v00001425d00005608* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Storage Controller + +pci:v00001425d00005609* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Storage Controller + +pci:v00001425d0000560A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Storage Controller + +pci:v00001425d0000560B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Storage Controller + +pci:v00001425d0000560C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Storage Controller + +pci:v00001425d0000560D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Storage Controller + +pci:v00001425d0000560E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Storage Controller + +pci:v00001425d0000560F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Storage Controller + +pci:v00001425d00005610* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Storage Controller + +pci:v00001425d00005611* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Storage Controller + +pci:v00001425d00005612* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Storage Controller + +pci:v00001425d00005613* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Storage Controller + +pci:v00001425d00005614* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Storage Controller + +pci:v00001425d00005680* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Storage Controller + +pci:v00001425d00005681* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Storage Controller + +pci:v00001425d00005701* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +pci:v00001425d00005702* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Ethernet Controller + +pci:v00001425d00005703* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Ethernet Controller + +pci:v00001425d00005704* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005705* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005706* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Ethernet Controller + +pci:v00001425d00005707* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Ethernet Controller + +pci:v00001425d00005708* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Ethernet Controller + +pci:v00001425d00005709* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Ethernet Controller + +pci:v00001425d0000570A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000570B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Ethernet Controller + +pci:v00001425d0000570C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000570D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d0000570E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000570F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00005710* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d00005711* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Ethernet Controller + +pci:v00001425d00005712* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Ethernet Controller + +pci:v00001425d00005713* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d00005714* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Ethernet Controller + +pci:v00001425d00005780* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Ethernet Controller + +pci:v00001425d00005781* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Ethernet Controller + +pci:v00001425d00005801* + ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller + +pci:v00001425d00005802* + ID_MODEL_FROM_DATABASE=T522-CR Unified Wire Ethernet Controller + +pci:v00001425d00005803* + ID_MODEL_FROM_DATABASE=T540-CR Unified Wire Ethernet Controller + +pci:v00001425d00005804* + ID_MODEL_FROM_DATABASE=T520-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005805* + ID_MODEL_FROM_DATABASE=T540-BCH Unified Wire Ethernet Controller + +pci:v00001425d00005806* + ID_MODEL_FROM_DATABASE=T540-CH Unified Wire Ethernet Controller + +pci:v00001425d00005807* + ID_MODEL_FROM_DATABASE=T520-SO Unified Wire Ethernet Controller + +pci:v00001425d00005808* + ID_MODEL_FROM_DATABASE=T520-CX Unified Wire Ethernet Controller + +pci:v00001425d00005809* + ID_MODEL_FROM_DATABASE=T520-BT Unified Wire Ethernet Controller + +pci:v00001425d0000580A* + ID_MODEL_FROM_DATABASE=T504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000580B* + ID_MODEL_FROM_DATABASE=B520-SR Unified Wire Ethernet Controller + +pci:v00001425d0000580C* + ID_MODEL_FROM_DATABASE=B504-BT Unified Wire Ethernet Controller + +pci:v00001425d0000580D* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d0000580E* + ID_MODEL_FROM_DATABASE=T540-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d0000580F* + ID_MODEL_FROM_DATABASE=T540 [Amsterdam] Unified Wire Ethernet Controller + +pci:v00001425d00005810* + ID_MODEL_FROM_DATABASE=T580-LP-CR Unified Wire Ethernet Controller + +pci:v00001425d00005811* + ID_MODEL_FROM_DATABASE=T520-LL-CR Unified Wire Ethernet Controller + +pci:v00001425d00005812* + ID_MODEL_FROM_DATABASE=T560-CR Unified Wire Ethernet Controller + +pci:v00001425d00005813* + ID_MODEL_FROM_DATABASE=T580-CR Unified Wire Ethernet Controller + +pci:v00001425d00005814* + ID_MODEL_FROM_DATABASE=T580-LP-SO-CR Unified Wire Ethernet Controller + +pci:v00001425d00005880* + ID_MODEL_FROM_DATABASE=T540-5080 Unified Wire Ethernet Controller + +pci:v00001425d00005881* + ID_MODEL_FROM_DATABASE=T540-5081 Unified Wire Ethernet Controller + +pci:v00001425d0000A000* + ID_MODEL_FROM_DATABASE=PE10K Unified Wire Ethernet Controller + +pci:v00001426* + ID_VENDOR_FROM_DATABASE=Storage Technology Corp. + +pci:v00001427* + ID_VENDOR_FROM_DATABASE=Better On-Line Solutions + +pci:v00001428* + ID_VENDOR_FROM_DATABASE=Edec Co Ltd + +pci:v00001429* + ID_VENDOR_FROM_DATABASE=Unex Technology Corp. + +pci:v0000142A* + ID_VENDOR_FROM_DATABASE=Kingmax Technology Inc + +pci:v0000142B* + ID_VENDOR_FROM_DATABASE=Radiolan + +pci:v0000142C* + ID_VENDOR_FROM_DATABASE=Minton Optic Industry Co Ltd + +pci:v0000142D* + ID_VENDOR_FROM_DATABASE=Pix stream Inc + +pci:v0000142E* + ID_VENDOR_FROM_DATABASE=Vitec Multimedia + +pci:v0000142Ed00004020* + ID_MODEL_FROM_DATABASE=VM2-2 [Video Maker 2] MPEG1/2 Encoder + +pci:v0000142Ed00004337* + ID_MODEL_FROM_DATABASE=VM2-2-C7 [Video Maker 2 rev. C7] MPEG1/2 Encoder + +pci:v0000142F* + ID_VENDOR_FROM_DATABASE=Radicom Research Inc + +pci:v00001430* + ID_VENDOR_FROM_DATABASE=ITT Aerospace/Communications Division + +pci:v00001431* + ID_VENDOR_FROM_DATABASE=Gilat Satellite Networks + +pci:v00001432* + ID_VENDOR_FROM_DATABASE=Edimax Computer Co. + +pci:v00001432d00009130* + ID_MODEL_FROM_DATABASE=RTL81xx Fast Ethernet + +pci:v00001433* + ID_VENDOR_FROM_DATABASE=Eltec Elektronik GmbH + +pci:v00001435* + ID_VENDOR_FROM_DATABASE=RTD Embedded Technologies, Inc. + +pci:v00001435d00004520* + ID_MODEL_FROM_DATABASE=PCI4520 + +pci:v00001435d00006020* + ID_MODEL_FROM_DATABASE=SPM6020 + +pci:v00001435d00006030* + ID_MODEL_FROM_DATABASE=SPM6030 + +pci:v00001435d00006420* + ID_MODEL_FROM_DATABASE=SPM186420 + +pci:v00001435d00006430* + ID_MODEL_FROM_DATABASE=SPM176430 + +pci:v00001435d00006431* + ID_MODEL_FROM_DATABASE=SPM176431 + +pci:v00001435d00007520* + ID_MODEL_FROM_DATABASE=DM7520 + +pci:v00001435d00007540* + ID_MODEL_FROM_DATABASE=SDM7540 + +pci:v00001435d00007820* + ID_MODEL_FROM_DATABASE=DM7820 + +pci:v00001436* + ID_VENDOR_FROM_DATABASE=CIS Technology Inc + +pci:v00001437* + ID_VENDOR_FROM_DATABASE=Nissin Inc Co + +pci:v00001438* + ID_VENDOR_FROM_DATABASE=Atmel-dream + +pci:v00001439* + ID_VENDOR_FROM_DATABASE=Outsource Engineering & Mfg. Inc + +pci:v0000143A* + ID_VENDOR_FROM_DATABASE=Stargate Solutions Inc + +pci:v0000143B* + ID_VENDOR_FROM_DATABASE=Canon Research Center, America + +pci:v0000143C* + ID_VENDOR_FROM_DATABASE=Amlogic Inc + +pci:v0000143D* + ID_VENDOR_FROM_DATABASE=Tamarack Microelectronics Inc + +pci:v0000143E* + ID_VENDOR_FROM_DATABASE=Jones Futurex Inc + +pci:v0000143F* + ID_VENDOR_FROM_DATABASE=Lightwell Co Ltd - Zax Division + +pci:v00001440* + ID_VENDOR_FROM_DATABASE=ALGOL Corp. + +pci:v00001441* + ID_VENDOR_FROM_DATABASE=AGIE Ltd + +pci:v00001442* + ID_VENDOR_FROM_DATABASE=Phoenix Contact GmbH & Co. + +pci:v00001443* + ID_VENDOR_FROM_DATABASE=Unibrain S.A. + +pci:v00001444* + ID_VENDOR_FROM_DATABASE=TRW + +pci:v00001445* + ID_VENDOR_FROM_DATABASE=Logical DO Ltd + +pci:v00001446* + ID_VENDOR_FROM_DATABASE=Graphin Co Ltd + +pci:v00001447* + ID_VENDOR_FROM_DATABASE=AIM GmBH + +pci:v00001448* + ID_VENDOR_FROM_DATABASE=Alesis Studio Electronics + +pci:v00001449* + ID_VENDOR_FROM_DATABASE=TUT Systems Inc + +pci:v0000144A* + ID_VENDOR_FROM_DATABASE=Adlink Technology + +pci:v0000144Ad00006208* + ID_MODEL_FROM_DATABASE=PCI-6208V + +pci:v0000144Ad00007250* + ID_MODEL_FROM_DATABASE=PCI-7250 + +pci:v0000144Ad00007296* + ID_MODEL_FROM_DATABASE=PCI-7296 + +pci:v0000144Ad00007432* + ID_MODEL_FROM_DATABASE=PCI-7432 + +pci:v0000144Ad00007433* + ID_MODEL_FROM_DATABASE=PCI-7433 + +pci:v0000144Ad00007434* + ID_MODEL_FROM_DATABASE=PCI-7434 + +pci:v0000144Ad00007841* + ID_MODEL_FROM_DATABASE=PCI-7841 + +pci:v0000144Ad00008133* + ID_MODEL_FROM_DATABASE=PCI-8133 + +pci:v0000144Ad00008164* + ID_MODEL_FROM_DATABASE=PCI-8164 + +pci:v0000144Ad00008554* + ID_MODEL_FROM_DATABASE=PCI-8554 + +pci:v0000144Ad00009111* + ID_MODEL_FROM_DATABASE=PCI-9111 + +pci:v0000144Ad00009113* + ID_MODEL_FROM_DATABASE=PCI-9113 + +pci:v0000144Ad00009114* + ID_MODEL_FROM_DATABASE=PCI-9114 + +pci:v0000144B* + ID_VENDOR_FROM_DATABASE=Verint Systems Inc. + +pci:v0000144C* + ID_VENDOR_FROM_DATABASE=Catalina Research Inc + +pci:v0000144D* + ID_VENDOR_FROM_DATABASE=Samsung Electronics Co Ltd + +pci:v0000144Dd00001600* + ID_MODEL_FROM_DATABASE=Apple PCIe SSD + +pci:v0000144Dd0000A800* + ID_MODEL_FROM_DATABASE=XP941 PCIe SSD + +pci:v0000144Dd0000A820* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller 171X + +pci:v0000144Dd0000A820sv00001028sd00001F95* + ID_MODEL_FROM_DATABASE=Express Flash NVMe XS1715 SSD 400GB + +pci:v0000144Dd0000A820sv00001028sd00001F96* + ID_MODEL_FROM_DATABASE=Express Flash NVMe XS1715 SSD 800GB + +pci:v0000144Dd0000A820sv00001028sd00001F97* + ID_MODEL_FROM_DATABASE=Express Flash NVMe XS1715 SSD 1600GB + +pci:v0000144E* + ID_VENDOR_FROM_DATABASE=OLITEC + +pci:v0000144F* + ID_VENDOR_FROM_DATABASE=Askey Computer Corp. + +pci:v00001450* + ID_VENDOR_FROM_DATABASE=Octave Communications Ind. + +pci:v00001451* + ID_VENDOR_FROM_DATABASE=SP3D Chip Design GmBH + +pci:v00001453* + ID_VENDOR_FROM_DATABASE=MYCOM Inc + +pci:v00001454* + ID_VENDOR_FROM_DATABASE=Altiga Networks + +pci:v00001455* + ID_VENDOR_FROM_DATABASE=Logic Plus Plus Inc + +pci:v00001456* + ID_VENDOR_FROM_DATABASE=Advanced Hardware Architectures + +pci:v00001457* + ID_VENDOR_FROM_DATABASE=Nuera Communications Inc + +pci:v00001458* + ID_VENDOR_FROM_DATABASE=Gigabyte Technology Co., Ltd + +pci:v00001459* + ID_VENDOR_FROM_DATABASE=DOOIN Electronics + +pci:v0000145A* + ID_VENDOR_FROM_DATABASE=Escalate Networks Inc + +pci:v0000145B* + ID_VENDOR_FROM_DATABASE=PRAIM SRL + +pci:v0000145C* + ID_VENDOR_FROM_DATABASE=Cryptek + +pci:v0000145D* + ID_VENDOR_FROM_DATABASE=Gallant Computer Inc + +pci:v0000145E* + ID_VENDOR_FROM_DATABASE=Aashima Technology B.V. + +pci:v0000145F* + ID_VENDOR_FROM_DATABASE=Baldor Electric Company + +pci:v0000145Fd00000001* + ID_MODEL_FROM_DATABASE=NextMove PCI + +pci:v00001460* + ID_VENDOR_FROM_DATABASE=DYNARC INC + +pci:v00001461* + ID_VENDOR_FROM_DATABASE=Avermedia Technologies Inc + +pci:v00001461d0000A3CE* + ID_MODEL_FROM_DATABASE=M179 + +pci:v00001461d0000A3CF* + ID_MODEL_FROM_DATABASE=M179 + +pci:v00001461d0000A836* + ID_MODEL_FROM_DATABASE=M115 DVB-T, PAL/SECAM/NTSC Tuner + +pci:v00001461d0000E836* + ID_MODEL_FROM_DATABASE=M115S Hybrid Analog/DVB PAL/SECAM/NTSC Tuner + +pci:v00001461d0000F436* + ID_MODEL_FROM_DATABASE=AVerTV Hybrid+FM + +pci:v00001462* + ID_VENDOR_FROM_DATABASE=Micro-Star International Co., Ltd. + +pci:v00001463* + ID_VENDOR_FROM_DATABASE=Fast Corporation + +pci:v00001464* + ID_VENDOR_FROM_DATABASE=Interactive Circuits & Systems Ltd + +pci:v00001465* + ID_VENDOR_FROM_DATABASE=GN NETTEST Telecom DIV. + +pci:v00001466* + ID_VENDOR_FROM_DATABASE=Designpro Inc. + +pci:v00001467* + ID_VENDOR_FROM_DATABASE=DIGICOM SPA + +pci:v00001468* + ID_VENDOR_FROM_DATABASE=AMBIT Microsystem Corp. + +pci:v00001469* + ID_VENDOR_FROM_DATABASE=Cleveland Motion Controls + +pci:v0000146A* + ID_VENDOR_FROM_DATABASE=IFR + +pci:v0000146B* + ID_VENDOR_FROM_DATABASE=Parascan Technologies Ltd + +pci:v0000146C* + ID_VENDOR_FROM_DATABASE=Ruby Tech Corp. + +pci:v0000146Cd00001430* + ID_MODEL_FROM_DATABASE=FE-1430TX Fast Ethernet PCI Adapter + +pci:v0000146D* + ID_VENDOR_FROM_DATABASE=Tachyon, INC. + +pci:v0000146E* + ID_VENDOR_FROM_DATABASE=Williams Electronics Games, Inc. + +pci:v0000146F* + ID_VENDOR_FROM_DATABASE=Multi Dimensional Consulting Inc + +pci:v00001470* + ID_VENDOR_FROM_DATABASE=Bay Networks + +pci:v00001471* + ID_VENDOR_FROM_DATABASE=Integrated Telecom Express Inc + +pci:v00001472* + ID_VENDOR_FROM_DATABASE=DAIKIN Industries, Ltd + +pci:v00001473* + ID_VENDOR_FROM_DATABASE=ZAPEX Technologies Inc + +pci:v00001474* + ID_VENDOR_FROM_DATABASE=Doug Carson & Associates + +pci:v00001475* + ID_VENDOR_FROM_DATABASE=PICAZO Communications + +pci:v00001476* + ID_VENDOR_FROM_DATABASE=MORTARA Instrument Inc + +pci:v00001477* + ID_VENDOR_FROM_DATABASE=Net Insight + +pci:v00001478* + ID_VENDOR_FROM_DATABASE=DIATREND Corporation + +pci:v00001479* + ID_VENDOR_FROM_DATABASE=TORAY Industries Inc + +pci:v0000147A* + ID_VENDOR_FROM_DATABASE=FORMOSA Industrial Computing + +pci:v0000147B* + ID_VENDOR_FROM_DATABASE=ABIT Computer Corp. + +pci:v0000147Bd00001084* + ID_MODEL_FROM_DATABASE=IP35 [Dark Raider] + +pci:v0000147C* + ID_VENDOR_FROM_DATABASE=AWARE, Inc. + +pci:v0000147D* + ID_VENDOR_FROM_DATABASE=Interworks Computer Products + +pci:v0000147E* + ID_VENDOR_FROM_DATABASE=Matsushita Graphic Communication Systems, Inc. + +pci:v0000147F* + ID_VENDOR_FROM_DATABASE=NIHON UNISYS, Ltd. + +pci:v00001480* + ID_VENDOR_FROM_DATABASE=SCII Telecom + +pci:v00001481* + ID_VENDOR_FROM_DATABASE=BIOPAC Systems Inc + +pci:v00001482* + ID_VENDOR_FROM_DATABASE=ISYTEC - Integrierte Systemtechnik GmBH + +pci:v00001482d00000001* + ID_MODEL_FROM_DATABASE=PCI-16 Host Interface for ITC-16 + +pci:v00001483* + ID_VENDOR_FROM_DATABASE=LABWAY Corporation + +pci:v00001484* + ID_VENDOR_FROM_DATABASE=Logic Corporation + +pci:v00001485* + ID_VENDOR_FROM_DATABASE=ERMA - Electronic GmBH + +pci:v00001486* + ID_VENDOR_FROM_DATABASE=L3 Communications Telemetry & Instrumentation + +pci:v00001487* + ID_VENDOR_FROM_DATABASE=MARQUETTE Medical Systems + +pci:v00001488* + ID_VENDOR_FROM_DATABASE=KONTRON Electronik GmBH + +pci:v00001489* + ID_VENDOR_FROM_DATABASE=KYE Systems Corporation + +pci:v0000148A* + ID_VENDOR_FROM_DATABASE=OPTO + +pci:v0000148B* + ID_VENDOR_FROM_DATABASE=INNOMEDIALOGIC Inc. + +pci:v0000148C* + ID_VENDOR_FROM_DATABASE=Tul Corporation / PowerColor + +pci:v0000148D* + ID_VENDOR_FROM_DATABASE=DIGICOM Systems, Inc. + +pci:v0000148Dd00001003* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v0000148E* + ID_VENDOR_FROM_DATABASE=OSI Plus Corporation + +pci:v0000148F* + ID_VENDOR_FROM_DATABASE=Plant Equipment, Inc. + +pci:v00001490* + ID_VENDOR_FROM_DATABASE=Stone Microsystems PTY Ltd. + +pci:v00001491* + ID_VENDOR_FROM_DATABASE=ZEAL Corporation + +pci:v00001492* + ID_VENDOR_FROM_DATABASE=Time Logic Corporation + +pci:v00001493* + ID_VENDOR_FROM_DATABASE=MAKER Communications + +pci:v00001494* + ID_VENDOR_FROM_DATABASE=WINTOP Technology, Inc. + +pci:v00001495* + ID_VENDOR_FROM_DATABASE=TOKAI Communications Industry Co. Ltd + +pci:v00001496* + ID_VENDOR_FROM_DATABASE=JOYTECH Computer Co., Ltd. + +pci:v00001497* + ID_VENDOR_FROM_DATABASE=SMA Regelsysteme GmBH + +pci:v00001497d00001497* + ID_MODEL_FROM_DATABASE=SMA Technologie AG + +pci:v00001498* + ID_VENDOR_FROM_DATABASE=TEWS Technologies GmbH + +pci:v00001498d00000330* + ID_MODEL_FROM_DATABASE=TPMC816 2 Channel CAN bus controller. + +pci:v00001498d0000035D* + ID_MODEL_FROM_DATABASE=TPMC861 4-Channel Isolated Serial Interface RS422/RS485 + +pci:v00001498d00000385* + ID_MODEL_FROM_DATABASE=TPMC901 Extended CAN bus with 2/4/6 CAN controller + +pci:v00001498d000021CC* + ID_MODEL_FROM_DATABASE=TCP460 CompactPCI 16 Channel Serial Interface RS232/RS422 + +pci:v00001498d000021CD* + ID_MODEL_FROM_DATABASE=TCP461 CompactPCI 8 Channel Serial Interface RS232/RS422 + +pci:v00001498d00003064* + ID_MODEL_FROM_DATABASE=TPCI100 (2 Slot IndustryPack PCI Carrier) + +pci:v00001498d000030C8* + ID_MODEL_FROM_DATABASE=TPCI200 4 Slot IndustryPack PCI Carrier + +pci:v00001498d000070C8* + ID_MODEL_FROM_DATABASE=TPCE200 4 Slot IndustryPack PCIe Carrier + +pci:v00001499* + ID_VENDOR_FROM_DATABASE=EMTEC CO., Ltd + +pci:v0000149A* + ID_VENDOR_FROM_DATABASE=ANDOR Technology Ltd + +pci:v0000149B* + ID_VENDOR_FROM_DATABASE=SEIKO Instruments Inc + +pci:v0000149C* + ID_VENDOR_FROM_DATABASE=OVISLINK Corp. + +pci:v0000149D* + ID_VENDOR_FROM_DATABASE=NEWTEK Inc + +pci:v0000149Dd00000001* + ID_MODEL_FROM_DATABASE=Video Toaster for PC + +pci:v0000149E* + ID_VENDOR_FROM_DATABASE=Mapletree Networks Inc. + +pci:v0000149F* + ID_VENDOR_FROM_DATABASE=LECTRON Co Ltd + +pci:v000014A0* + ID_VENDOR_FROM_DATABASE=SOFTING GmBH + +pci:v000014A1* + ID_VENDOR_FROM_DATABASE=Systembase Co Ltd + +pci:v000014A2* + ID_VENDOR_FROM_DATABASE=Millennium Engineering Inc + +pci:v000014A3* + ID_VENDOR_FROM_DATABASE=Maverick Networks + +pci:v000014A4* + ID_VENDOR_FROM_DATABASE=Broadcom Corporation (Wrong ID) + +pci:v000014A4d00004318* + ID_MODEL_FROM_DATABASE=BCM4318 [AirForce One 54g] 802.11g Wireless LAN Controller + +pci:v000014A5* + ID_VENDOR_FROM_DATABASE=XIONICS Document Technologies Inc + +pci:v000014A6* + ID_VENDOR_FROM_DATABASE=INOVA Computers GmBH & Co KG + +pci:v000014A7* + ID_VENDOR_FROM_DATABASE=MYTHOS Systems Inc + +pci:v000014A8* + ID_VENDOR_FROM_DATABASE=FEATRON Technologies Corporation + +pci:v000014A9* + ID_VENDOR_FROM_DATABASE=HIVERTEC Inc + +pci:v000014AA* + ID_VENDOR_FROM_DATABASE=Advanced MOS Technology Inc + +pci:v000014AB* + ID_VENDOR_FROM_DATABASE=Mentor Graphics Corp. + +pci:v000014AC* + ID_VENDOR_FROM_DATABASE=Novaweb Technologies Inc + +pci:v000014AD* + ID_VENDOR_FROM_DATABASE=Time Space Radio AB + +pci:v000014AE* + ID_VENDOR_FROM_DATABASE=CTI, Inc + +pci:v000014AF* + ID_VENDOR_FROM_DATABASE=Guillemot Corporation + +pci:v000014AFd00007102* + ID_MODEL_FROM_DATABASE=3D Prophet II MX + +pci:v000014B0* + ID_VENDOR_FROM_DATABASE=BST Communication Technology Ltd + +pci:v000014B1* + ID_VENDOR_FROM_DATABASE=Nextcom K.K. + +pci:v000014B2* + ID_VENDOR_FROM_DATABASE=ENNOVATE Networks Inc + +pci:v000014B3* + ID_VENDOR_FROM_DATABASE=XPEED Inc + +pci:v000014B3d00000000* + ID_MODEL_FROM_DATABASE=DSL NIC + +pci:v000014B4* + ID_VENDOR_FROM_DATABASE=PHILIPS Business Electronics B.V. + +pci:v000014B5* + ID_VENDOR_FROM_DATABASE=Creamware GmBH + +pci:v000014B5d00000200* + ID_MODEL_FROM_DATABASE=Scope + +pci:v000014B5d00000300* + ID_MODEL_FROM_DATABASE=Pulsar + +pci:v000014B5d00000400* + ID_MODEL_FROM_DATABASE=PulsarSRB + +pci:v000014B5d00000600* + ID_MODEL_FROM_DATABASE=Pulsar2 + +pci:v000014B5d00000800* + ID_MODEL_FROM_DATABASE=DSP-Board + +pci:v000014B5d00000900* + ID_MODEL_FROM_DATABASE=DSP-Board + +pci:v000014B5d00000A00* + ID_MODEL_FROM_DATABASE=DSP-Board + +pci:v000014B5d00000B00* + ID_MODEL_FROM_DATABASE=DSP-Board + +pci:v000014B6* + ID_VENDOR_FROM_DATABASE=Quantum Data Corp. + +pci:v000014B7* + ID_VENDOR_FROM_DATABASE=PROXIM Inc + +pci:v000014B7d00000001* + ID_MODEL_FROM_DATABASE=Symphony 4110 + +pci:v000014B8* + ID_VENDOR_FROM_DATABASE=Techsoft Technology Co Ltd + +pci:v000014B9* + ID_VENDOR_FROM_DATABASE=Cisco Aironet Wireless Communications + +pci:v000014B9d00000001* + ID_MODEL_FROM_DATABASE=PC4800 + +pci:v000014B9d00000340* + ID_MODEL_FROM_DATABASE=PC4800 + +pci:v000014B9d00000350* + ID_MODEL_FROM_DATABASE=350 series 802.11b Wireless LAN Adapter + +pci:v000014B9d00004500* + ID_MODEL_FROM_DATABASE=PC4500 + +pci:v000014B9d00004800* + ID_MODEL_FROM_DATABASE=Cisco Aironet 340 802.11b Wireless LAN Adapter/Aironet PC4800 + +pci:v000014B9d0000A504* + ID_MODEL_FROM_DATABASE=Cisco Aironet Wireless 802.11b + +pci:v000014B9d0000A505* + ID_MODEL_FROM_DATABASE=Cisco Aironet CB20a 802.11a Wireless LAN Adapter + +pci:v000014B9d0000A506* + ID_MODEL_FROM_DATABASE=Cisco Aironet Mini PCI b/g + +pci:v000014BA* + ID_VENDOR_FROM_DATABASE=INTERNIX Inc. + +pci:v000014BAd00000600* + ID_MODEL_FROM_DATABASE=ARC-PCI/22 + +pci:v000014BB* + ID_VENDOR_FROM_DATABASE=SEMTECH Corporation + +pci:v000014BC* + ID_VENDOR_FROM_DATABASE=Globespan Semiconductor Inc. + +pci:v000014BCd0000D002* + ID_MODEL_FROM_DATABASE=Pulsar [PCI ADSL Card] + +pci:v000014BCd0000D00F* + ID_MODEL_FROM_DATABASE=Pulsar [PCI ADSL Card] + +pci:v000014BD* + ID_VENDOR_FROM_DATABASE=CARDIO Control N.V. + +pci:v000014BE* + ID_VENDOR_FROM_DATABASE=L3 Communications + +pci:v000014BF* + ID_VENDOR_FROM_DATABASE=SPIDER Communications Inc. + +pci:v000014C0* + ID_VENDOR_FROM_DATABASE=COMPAL Electronics Inc + +pci:v000014C1* + ID_VENDOR_FROM_DATABASE=MYRICOM Inc. + +pci:v000014C1d00000008* + ID_MODEL_FROM_DATABASE=Myri-10G Dual-Protocol NIC + +pci:v000014C1d00000008sv000014C1sd00000008* + ID_MODEL_FROM_DATABASE=10G-PCIE-8A + +pci:v000014C1d00000008sv000014C1sd00000009* + ID_MODEL_FROM_DATABASE=10G-PCIE-8A (MSI-X firmware) + +pci:v000014C1d00000008sv000014C1sd0000000A* + ID_MODEL_FROM_DATABASE=10G-PCIE-8B + +pci:v000014C1d00008043* + ID_MODEL_FROM_DATABASE=Myrinet 2000 Scalable Cluster Interconnect + +pci:v000014C1d00008043sv0000103Csd00001240* + ID_MODEL_FROM_DATABASE=Myrinet M2L-PCI64/2-3.0 LANai 7.4 (HP OEM) + +pci:v000014C2* + ID_VENDOR_FROM_DATABASE=DTK Computer + +pci:v000014C3* + ID_VENDOR_FROM_DATABASE=MEDIATEK Corp. + +pci:v000014C3d00007630* + ID_MODEL_FROM_DATABASE=MT7630e 802.11bgn Wireless Network Adapter + +pci:v000014C4* + ID_VENDOR_FROM_DATABASE=IWASAKI Information Systems Co Ltd + +pci:v000014C5* + ID_VENDOR_FROM_DATABASE=Automation Products AB + +pci:v000014C6* + ID_VENDOR_FROM_DATABASE=Data Race Inc + +pci:v000014C7* + ID_VENDOR_FROM_DATABASE=Modular Technology Holdings Ltd + +pci:v000014C8* + ID_VENDOR_FROM_DATABASE=Turbocomm Tech. Inc. + +pci:v000014C9* + ID_VENDOR_FROM_DATABASE=ODIN Telesystems Inc + +pci:v000014CA* + ID_VENDOR_FROM_DATABASE=PE Logic Corp. + +pci:v000014CB* + ID_VENDOR_FROM_DATABASE=Billionton Systems Inc + +pci:v000014CC* + ID_VENDOR_FROM_DATABASE=NAKAYO Telecommunications Inc + +pci:v000014CD* + ID_VENDOR_FROM_DATABASE=Universal Scientific Ind. + +pci:v000014CE* + ID_VENDOR_FROM_DATABASE=Whistle Communications + +pci:v000014CF* + ID_VENDOR_FROM_DATABASE=TEK Microsystems Inc. + +pci:v000014D0* + ID_VENDOR_FROM_DATABASE=Ericsson Axe R & D + +pci:v000014D1* + ID_VENDOR_FROM_DATABASE=Computer Hi-Tech Co Ltd + +pci:v000014D2* + ID_VENDOR_FROM_DATABASE=Titan Electronics Inc + +pci:v000014D2d00008001* + ID_MODEL_FROM_DATABASE=VScom 010L 1 port parallel adaptor + +pci:v000014D2d00008002* + ID_MODEL_FROM_DATABASE=VScom 020L 2 port parallel adaptor + +pci:v000014D2d00008010* + ID_MODEL_FROM_DATABASE=VScom 100L 1 port serial adaptor + +pci:v000014D2d00008011* + ID_MODEL_FROM_DATABASE=VScom 110L 1 port serial and 1 port parallel adaptor + +pci:v000014D2d00008020* + ID_MODEL_FROM_DATABASE=VScom 200L 1 or 2 port serial adaptor + +pci:v000014D2d00008021* + ID_MODEL_FROM_DATABASE=VScom 210L 2 port serial and 1 port parallel adaptor + +pci:v000014D2d00008028* + ID_MODEL_FROM_DATABASE=VScom 200I/200I-SI 2-port serial adapter + +pci:v000014D2d00008040* + ID_MODEL_FROM_DATABASE=VScom 400L 4 port serial adaptor + +pci:v000014D2d00008043* + ID_MODEL_FROM_DATABASE=VScom 430L 4-port serial and 3-port parallel adapter + +pci:v000014D2d00008048* + ID_MODEL_FROM_DATABASE=VScom 400I 4-port serial adapter + +pci:v000014D2d00008080* + ID_MODEL_FROM_DATABASE=VScom 800L 8 port serial adaptor + +pci:v000014D2d00008088* + ID_MODEL_FROM_DATABASE=VScom 800I 8-port serial adapter + +pci:v000014D2d0000A000* + ID_MODEL_FROM_DATABASE=VScom 010H 1 port parallel adaptor + +pci:v000014D2d0000A001* + ID_MODEL_FROM_DATABASE=VScom 100H 1 port serial adaptor + +pci:v000014D2d0000A003* + ID_MODEL_FROM_DATABASE=VScom 400H 4 port serial adaptor + +pci:v000014D2d0000A004* + ID_MODEL_FROM_DATABASE=VScom 400HF1 4 port serial adaptor + +pci:v000014D2d0000A005* + ID_MODEL_FROM_DATABASE=VScom 200H 2 port serial adaptor + +pci:v000014D2d0000A007* + ID_MODEL_FROM_DATABASE=VScom PCI800EH (PCIe) 8-port serial adapter Port 1-4 + +pci:v000014D2d0000A008* + ID_MODEL_FROM_DATABASE=VScom PCI800EH (PCIe) 8-port serial adapter Port 5-8 + +pci:v000014D2d0000A009* + ID_MODEL_FROM_DATABASE=VScom PCI400EH (PCIe) 4-port serial adapter + +pci:v000014D2d0000E001* + ID_MODEL_FROM_DATABASE=VScom 010HV2 1 port parallel adaptor + +pci:v000014D2d0000E010* + ID_MODEL_FROM_DATABASE=VScom 100HV2 1 port serial adaptor + +pci:v000014D2d0000E020* + ID_MODEL_FROM_DATABASE=VScom 200HV2 2 port serial adaptor + +pci:v000014D3* + ID_VENDOR_FROM_DATABASE=CIRTECH (UK) Ltd + +pci:v000014D4* + ID_VENDOR_FROM_DATABASE=Panacom Technology Corp + +pci:v000014D5* + ID_VENDOR_FROM_DATABASE=Nitsuko Corporation + +pci:v000014D6* + ID_VENDOR_FROM_DATABASE=Accusys Inc + +pci:v000014D6d00006101* + ID_MODEL_FROM_DATABASE=ACS-61xxx, PCIe to SAS/SATA RAID HBA + +pci:v000014D6d00006201* + ID_MODEL_FROM_DATABASE=ACS-62xxx, External PCIe to SAS/SATA RAID controller + +pci:v000014D7* + ID_VENDOR_FROM_DATABASE=Hirakawa Hewtech Corp + +pci:v000014D8* + ID_VENDOR_FROM_DATABASE=HOPF Elektronik GmBH + +pci:v000014D9* + ID_VENDOR_FROM_DATABASE=Alliance Semiconductor Corporation + +pci:v000014D9d00000010* + ID_MODEL_FROM_DATABASE=AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon] + +pci:v000014D9d00009000* + ID_MODEL_FROM_DATABASE=AS90L10204/10208 HyperTransport to PCI-X Bridge + +pci:v000014DA* + ID_VENDOR_FROM_DATABASE=National Aerospace Laboratories + +pci:v000014DB* + ID_VENDOR_FROM_DATABASE=AFAVLAB Technology Inc + +pci:v000014DBd00002120* + ID_MODEL_FROM_DATABASE=TK9902 + +pci:v000014DBd00002182* + ID_MODEL_FROM_DATABASE=AFAVLAB Technology Inc. 8-port serial card + +pci:v000014DC* + ID_VENDOR_FROM_DATABASE=Amplicon Liveline Ltd + +pci:v000014DCd00000000* + ID_MODEL_FROM_DATABASE=PCI230 + +pci:v000014DCd00000001* + ID_MODEL_FROM_DATABASE=PCI242 + +pci:v000014DCd00000002* + ID_MODEL_FROM_DATABASE=PCI244 + +pci:v000014DCd00000003* + ID_MODEL_FROM_DATABASE=PCI247 + +pci:v000014DCd00000004* + ID_MODEL_FROM_DATABASE=PCI248 + +pci:v000014DCd00000005* + ID_MODEL_FROM_DATABASE=PCI249 + +pci:v000014DCd00000006* + ID_MODEL_FROM_DATABASE=PCI260 + +pci:v000014DCd00000007* + ID_MODEL_FROM_DATABASE=PCI224 + +pci:v000014DCd00000008* + ID_MODEL_FROM_DATABASE=PCI234 + +pci:v000014DCd00000009* + ID_MODEL_FROM_DATABASE=PCI236 + +pci:v000014DCd0000000A* + ID_MODEL_FROM_DATABASE=PCI272 + +pci:v000014DCd0000000B* + ID_MODEL_FROM_DATABASE=PCI215 + +pci:v000014DD* + ID_VENDOR_FROM_DATABASE=Boulder Design Labs Inc + +pci:v000014DE* + ID_VENDOR_FROM_DATABASE=Applied Integration Corporation + +pci:v000014DF* + ID_VENDOR_FROM_DATABASE=ASIC Communications Corp + +pci:v000014E1* + ID_VENDOR_FROM_DATABASE=INVERTEX + +pci:v000014E2* + ID_VENDOR_FROM_DATABASE=INFOLIBRIA + +pci:v000014E3* + ID_VENDOR_FROM_DATABASE=AMTELCO + +pci:v000014E4* + ID_VENDOR_FROM_DATABASE=Broadcom Corporation + +pci:v000014E4d00000576* + ID_MODEL_FROM_DATABASE=BCM43224 802.11a/b/g/n + +pci:v000014E4d00000800* + ID_MODEL_FROM_DATABASE=Sentry5 Chipcommon I/O Controller + +pci:v000014E4d00000804* + ID_MODEL_FROM_DATABASE=Sentry5 PCI Bridge + +pci:v000014E4d00000805* + ID_MODEL_FROM_DATABASE=Sentry5 MIPS32 CPU + +pci:v000014E4d00000806* + ID_MODEL_FROM_DATABASE=Sentry5 Ethernet Controller + +pci:v000014E4d0000080B* + ID_MODEL_FROM_DATABASE=Sentry5 Crypto Accelerator + +pci:v000014E4d0000080F* + ID_MODEL_FROM_DATABASE=Sentry5 DDR/SDR RAM Controller + +pci:v000014E4d00000811* + ID_MODEL_FROM_DATABASE=Sentry5 External Interface Core + +pci:v000014E4d00000816* + ID_MODEL_FROM_DATABASE=BCM3302 Sentry5 MIPS32 CPU + +pci:v000014E4d00001600* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5752 Gigabit Ethernet PCI Express + +pci:v000014E4d00001600sv00001028sd000001C1* + ID_MODEL_FROM_DATABASE=Precision 490 + +pci:v000014E4d00001600sv00001028sd000001C2* + ID_MODEL_FROM_DATABASE=Latitude D620 + +pci:v000014E4d00001600sv0000103Csd00003015* + ID_MODEL_FROM_DATABASE=PCIe LAN on Motherboard + +pci:v000014E4d00001600sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 Onboard + +pci:v000014E4d00001600sv00001259sd00002705* + ID_MODEL_FROM_DATABASE=AT-2711FX + +pci:v000014E4d00001601* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5752M Gigabit Ethernet PCI Express + +pci:v000014E4d00001612* + ID_MODEL_FROM_DATABASE=BCM70012 Video Decoder [Crystal HD] + +pci:v000014E4d00001615* + ID_MODEL_FROM_DATABASE=BCM70015 Video Decoder [Crystal HD] + +pci:v000014E4d00001639* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5709 Gigabit Ethernet + +pci:v000014E4d00001639sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 BCM5709 Gigabit Ethernet + +pci:v000014E4d00001639sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 BCM5709 Gigabit Ethernet + +pci:v000014E4d00001639sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 BCM5709 Gigabit Ethernet + +pci:v000014E4d00001639sv0000103Csd00007055* + ID_MODEL_FROM_DATABASE=NC382i Integrated Multi-port PCI Express Gigabit Server Adapter + +pci:v000014E4d00001639sv0000103Csd00007059* + ID_MODEL_FROM_DATABASE=NC382T PCI Express Dual Port Multifunction Gigabit Server Adapter + +pci:v000014E4d00001639sv000010A9sd00008027* + ID_MODEL_FROM_DATABASE=Quad port Gigabit Ethernet Controller + +pci:v000014E4d0000163A* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5709S Gigabit Ethernet + +pci:v000014E4d0000163Asv00001028sd0000027B* + ID_MODEL_FROM_DATABASE=PowerEdge M805 Broadcom NetXtreme II BCM5709S + +pci:v000014E4d0000163Asv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 BCM5709S Gigabit Ethernet + +pci:v000014E4d0000163Asv0000103Csd0000171D* + ID_MODEL_FROM_DATABASE=NC382m Dual Port 1GbE Multifunction BL-c Adapter + +pci:v000014E4d0000163Asv0000103Csd00007056* + ID_MODEL_FROM_DATABASE=NC382i Integrated Quad Port PCI Express Gigabit Server Adapter + +pci:v000014E4d0000163Asv00001259sd00002984* + ID_MODEL_FROM_DATABASE=AT-2973SX + +pci:v000014E4d0000163B* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5716 Gigabit Ethernet + +pci:v000014E4d0000163Bsv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 BCM5716 Gigabit Ethernet + +pci:v000014E4d0000163Bsv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 BCM5716 Gigabit Ethernet + +pci:v000014E4d0000163Bsv00001028sd000002F1* + ID_MODEL_FROM_DATABASE=PowerEdge R510 BCM5716 Gigabit Ethernet + +pci:v000014E4d0000163C* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5716S Gigabit Ethernet + +pci:v000014E4d0000163D* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57811 10-Gigabit Ethernet + +pci:v000014E4d0000163E* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function + +pci:v000014E4d0000163F* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57811 10-Gigabit Ethernet Virtual Function + +pci:v000014E4d00001641* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57787 Gigabit Ethernet PCIe + +pci:v000014E4d00001642* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57764 Gigabit Ethernet PCIe + +pci:v000014E4d00001643* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5725 Gigabit Ethernet PCIe + +pci:v000014E4d00001644* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5700 Gigabit Ethernet + +pci:v000014E4d00001644sv00001014sd00000277* + ID_MODEL_FROM_DATABASE=Broadcom Vigil B5700 1000Base-T + +pci:v000014E4d00001644sv00001028sd000000D1* + ID_MODEL_FROM_DATABASE=Broadcom BCM5700 + +pci:v000014E4d00001644sv00001028sd00000106* + ID_MODEL_FROM_DATABASE=Broadcom BCM5700 + +pci:v000014E4d00001644sv00001028sd00000109* + ID_MODEL_FROM_DATABASE=Broadcom BCM5700 1000Base-T + +pci:v000014E4d00001644sv00001028sd0000010A* + ID_MODEL_FROM_DATABASE=Broadcom BCM5700 1000BaseTX + +pci:v000014E4d00001644sv000010B7sd00001000* + ID_MODEL_FROM_DATABASE=3C996-T 1000Base-T + +pci:v000014E4d00001644sv000010B7sd00001001* + ID_MODEL_FROM_DATABASE=3C996B-T 1000Base-T + +pci:v000014E4d00001644sv000010B7sd00001002* + ID_MODEL_FROM_DATABASE=3C996C-T 1000Base-T + +pci:v000014E4d00001644sv000010B7sd00001003* + ID_MODEL_FROM_DATABASE=3C997-T 1000Base-T Dual Port + +pci:v000014E4d00001644sv000010B7sd00001004* + ID_MODEL_FROM_DATABASE=3C996-SX 1000Base-SX + +pci:v000014E4d00001644sv000010B7sd00001005* + ID_MODEL_FROM_DATABASE=3C997-SX 1000Base-SX Dual Port + +pci:v000014E4d00001644sv000010B7sd00001008* + ID_MODEL_FROM_DATABASE=3C942 Gigabit LOM (31X31) + +pci:v000014E4d00001644sv000014E4sd00000002* + ID_MODEL_FROM_DATABASE=NetXtreme 1000Base-SX + +pci:v000014E4d00001644sv000014E4sd00000003* + ID_MODEL_FROM_DATABASE=NetXtreme 1000Base-SX + +pci:v000014E4d00001644sv000014E4sd00000004* + ID_MODEL_FROM_DATABASE=NetXtreme 1000Base-T + +pci:v000014E4d00001644sv000014E4sd00001028* + ID_MODEL_FROM_DATABASE=NetXtreme 1000BaseTX + +pci:v000014E4d00001644sv000014E4sd00001644* + ID_MODEL_FROM_DATABASE=BCM5700 1000Base-T + +pci:v000014E4d00001645* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5701 Gigabit Ethernet + +pci:v000014E4d00001645sv00000E11sd0000007C* + ID_MODEL_FROM_DATABASE=NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T) + +pci:v000014E4d00001645sv00000E11sd0000007D* + ID_MODEL_FROM_DATABASE=NC6770 Gigabit Server Adapter (PCI-X, 1000-SX) + +pci:v000014E4d00001645sv00000E11sd00000085* + ID_MODEL_FROM_DATABASE=NC7780 Gigabit Server Adapter (embedded, WOL) + +pci:v000014E4d00001645sv00000E11sd00000099* + ID_MODEL_FROM_DATABASE=NC7780 Gigabit Server Adapter (embedded, WOL) + +pci:v000014E4d00001645sv00000E11sd0000009A* + ID_MODEL_FROM_DATABASE=NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T) + +pci:v000014E4d00001645sv00000E11sd000000C1* + ID_MODEL_FROM_DATABASE=NC6770 Gigabit Server Adapter (PCI-X, 1000-SX) + +pci:v000014E4d00001645sv00001028sd00000121* + ID_MODEL_FROM_DATABASE=Broadcom BCM5701 1000Base-T + +pci:v000014E4d00001645sv0000103Csd0000128A* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T (HP, OEM 3COM) + +pci:v000014E4d00001645sv0000103Csd0000128B* + ID_MODEL_FROM_DATABASE=1000Base-SX (PCI) [A7073A] + +pci:v000014E4d00001645sv0000103Csd000012A4* + ID_MODEL_FROM_DATABASE=Core Lan 1000Base-T + +pci:v000014E4d00001645sv0000103Csd000012C1* + ID_MODEL_FROM_DATABASE=IOX Core Lan 1000Base-T [A7109AX] + +pci:v000014E4d00001645sv0000103Csd00001300* + ID_MODEL_FROM_DATABASE=Core LAN/SCSI Combo [A6794A] + +pci:v000014E4d00001645sv000010A9sd00008010* + ID_MODEL_FROM_DATABASE=IO9/IO10 Gigabit Ethernet (Copper) + +pci:v000014E4d00001645sv000010A9sd00008011* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet (Copper) + +pci:v000014E4d00001645sv000010A9sd00008012* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet (Fiber) + +pci:v000014E4d00001645sv000010B7sd00001004* + ID_MODEL_FROM_DATABASE=3C996-SX 1000Base-SX + +pci:v000014E4d00001645sv000010B7sd00001006* + ID_MODEL_FROM_DATABASE=3C996B-T 1000Base-T + +pci:v000014E4d00001645sv000010B7sd00001007* + ID_MODEL_FROM_DATABASE=3C1000-T 1000Base-T + +pci:v000014E4d00001645sv000010B7sd00001008* + ID_MODEL_FROM_DATABASE=3C940-BR01 1000Base-T + +pci:v000014E4d00001645sv000014E4sd00000001* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T + +pci:v000014E4d00001645sv000014E4sd00000005* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T + +pci:v000014E4d00001645sv000014E4sd00000006* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T + +pci:v000014E4d00001645sv000014E4sd00000007* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-SX + +pci:v000014E4d00001645sv000014E4sd00000008* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T + +pci:v000014E4d00001645sv000014E4sd00001645* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5701 Gigabit Ethernet + +pci:v000014E4d00001645sv000014E4sd00008008* + ID_MODEL_FROM_DATABASE=BCM5701 1000Base-T + +pci:v000014E4d00001646* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5702 Gigabit Ethernet + +pci:v000014E4d00001646sv00000E11sd000000BB* + ID_MODEL_FROM_DATABASE=NC7760 1000BaseTX + +pci:v000014E4d00001646sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Broadcom BCM5702 1000BaseTX + +pci:v000014E4d00001646sv000014E4sd00008009* + ID_MODEL_FROM_DATABASE=BCM5702 1000BaseTX + +pci:v000014E4d00001647* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 Gigabit Ethernet + +pci:v000014E4d00001647sv00000E11sd00000099* + ID_MODEL_FROM_DATABASE=NC7780 1000BaseTX + +pci:v000014E4d00001647sv00000E11sd0000009A* + ID_MODEL_FROM_DATABASE=NC7770 1000BaseTX + +pci:v000014E4d00001647sv000010A9sd00008010* + ID_MODEL_FROM_DATABASE=SGI IO9 Gigabit Ethernet (Copper) + +pci:v000014E4d00001647sv000014E4sd00000009* + ID_MODEL_FROM_DATABASE=BCM5703 1000BaseTX + +pci:v000014E4d00001647sv000014E4sd0000000A* + ID_MODEL_FROM_DATABASE=BCM5703 1000BaseSX + +pci:v000014E4d00001647sv000014E4sd0000000B* + ID_MODEL_FROM_DATABASE=BCM5703 1000BaseTX + +pci:v000014E4d00001647sv000014E4sd00008009* + ID_MODEL_FROM_DATABASE=BCM5703 1000BaseTX + +pci:v000014E4d00001647sv000014E4sd0000800A* + ID_MODEL_FROM_DATABASE=BCM5703 1000BaseTX + +pci:v000014E4d00001648* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5704 Gigabit Ethernet + +pci:v000014E4d00001648sv00000E11sd000000CF* + ID_MODEL_FROM_DATABASE=NC7772 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d00001648sv00000E11sd000000D0* + ID_MODEL_FROM_DATABASE=NC7782 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d00001648sv00000E11sd000000D1* + ID_MODEL_FROM_DATABASE=NC7783 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d00001648sv00001028sd0000014A* + ID_MODEL_FROM_DATABASE=PowerEdge 1750 + +pci:v000014E4d00001648sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Broadcom NetXtreme BCM5704 + +pci:v000014E4d00001648sv0000103Csd0000310F* + ID_MODEL_FROM_DATABASE=NC7782 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d00001648sv000010A9sd00008013* + ID_MODEL_FROM_DATABASE=Dual Port Gigabit Ethernet (PCI-X,Copper) + +pci:v000014E4d00001648sv000010A9sd00008018* + ID_MODEL_FROM_DATABASE=Dual Port Gigabit Ethernet (A330) + +pci:v000014E4d00001648sv000010A9sd0000801A* + ID_MODEL_FROM_DATABASE=Dual Port Gigabit Ethernet (IA-blade) + +pci:v000014E4d00001648sv000010A9sd0000801B* + ID_MODEL_FROM_DATABASE=Quad Port Gigabit Ethernet (PCI-E,Copper) + +pci:v000014E4d00001648sv000010B7sd00002000* + ID_MODEL_FROM_DATABASE=3C998-T Dual Port 10/100/1000 PCI-X + +pci:v000014E4d00001648sv000010B7sd00003000* + ID_MODEL_FROM_DATABASE=3C999-T Quad Port 10/100/1000 PCI-X + +pci:v000014E4d00001648sv00001166sd00001648* + ID_MODEL_FROM_DATABASE=NetXtreme CIOB-E 1000Base-T + +pci:v000014E4d00001648sv00001734sd0000100B* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series onboard LAN + +pci:v000014E4d00001649* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5704S_2 Gigabit Ethernet + +pci:v000014E4d0000164A* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5706 Gigabit Ethernet + +pci:v000014E4d0000164Asv0000103Csd00001709* + ID_MODEL_FROM_DATABASE=NC371i Integrated PCI-X Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164Asv0000103Csd00003070* + ID_MODEL_FROM_DATABASE=NC380T PCI Express Dual Port Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164Asv0000103Csd00003101* + ID_MODEL_FROM_DATABASE=NC370T MultifuNCtion Gigabit Server Adapter + +pci:v000014E4d0000164Asv0000103Csd00003106* + ID_MODEL_FROM_DATABASE=NC370i Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164C* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5708 Gigabit Ethernet + +pci:v000014E4d0000164Csv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv00001028sd00000205* + ID_MODEL_FROM_DATABASE=PowerEdge 2970 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv00001028sd0000020B* + ID_MODEL_FROM_DATABASE=PowerEdge T605 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv00001028sd00000221* + ID_MODEL_FROM_DATABASE=PowerEdge R805 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv00001028sd00000223* + ID_MODEL_FROM_DATABASE=PowerEdge R905 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv00001028sd00001F12* + ID_MODEL_FROM_DATABASE=PowerEdge R805/R905 Broadcom NetXtreme II BCM5708 + +pci:v000014E4d0000164Csv0000103Csd00007037* + ID_MODEL_FROM_DATABASE=NC373T PCI Express Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164Csv0000103Csd00007038* + ID_MODEL_FROM_DATABASE=NC373i Integrated Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164Csv0000103Csd00007045* + ID_MODEL_FROM_DATABASE=NC374m PCI Express Dual Port Multifunction Gigabit Server Adapter + +pci:v000014E4d0000164D* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5702FE Gigabit Ethernet + +pci:v000014E4d0000164E* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57710 10-Gigabit PCIe [Everest] + +pci:v000014E4d0000164Esv0000103Csd0000171C* + ID_MODEL_FROM_DATABASE=NC532m Dual Port 10GbE Multifunction BL-C Adapter + +pci:v000014E4d0000164Esv0000103Csd00007058* + ID_MODEL_FROM_DATABASE=NC532i Dual Port 10GbE Multifunction BL-C Adapter + +pci:v000014E4d0000164F* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57711 10-Gigabit PCIe + +pci:v000014E4d00001650* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57711E 10-Gigabit PCIe + +pci:v000014E4d00001650sv0000103Csd0000171C* + ID_MODEL_FROM_DATABASE=NC532m Dual Port 10GbE Multifunction BL-C Adapter + +pci:v000014E4d00001650sv0000103Csd00007058* + ID_MODEL_FROM_DATABASE=NC532i Dual Port 10GbE Multifunction BL-C Adapter + +pci:v000014E4d00001653* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5705 Gigabit Ethernet + +pci:v000014E4d00001653sv00000E11sd000000E3* + ID_MODEL_FROM_DATABASE=NC7761 Gigabit Server Adapter + +pci:v000014E4d00001653sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v000014E4d00001654* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5705_2 Gigabit Ethernet + +pci:v000014E4d00001654sv00000E11sd000000E3* + ID_MODEL_FROM_DATABASE=NC7761 Gigabit Server Adapter + +pci:v000014E4d00001654sv0000103Csd00003100* + ID_MODEL_FROM_DATABASE=NC1020 ProLiant Gigabit Server Adapter 32 PCI + +pci:v000014E4d00001654sv0000103Csd00003226* + ID_MODEL_FROM_DATABASE=NC150T 4-port Gigabit Combo Switch & Adapter + +pci:v000014E4d00001655* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5717 Gigabit Ethernet PCIe + +pci:v000014E4d00001656* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5718 Gigabit Ethernet PCIe + +pci:v000014E4d00001657* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5719 Gigabit Ethernet PCIe + +pci:v000014E4d00001659* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5721 Gigabit Ethernet PCI Express + +pci:v000014E4d00001659sv00001014sd000002C6* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v000014E4d00001659sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v000014E4d00001659sv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 Broadcom NetXtreme BCM5721 + +pci:v000014E4d00001659sv0000103Csd0000170B* + ID_MODEL_FROM_DATABASE=NC320m PCI Express Dual Port Gigabit Server Adapter + +pci:v000014E4d00001659sv0000103Csd00007031* + ID_MODEL_FROM_DATABASE=NC320T PCIe Gigabit Server Adapter + +pci:v000014E4d00001659sv0000103Csd00007032* + ID_MODEL_FROM_DATABASE=NC320i PCIe Gigabit Server Adapter + +pci:v000014E4d00001659sv00001734sd00001061* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series onboard LAN + +pci:v000014E4d0000165A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5722 Gigabit Ethernet PCI Express + +pci:v000014E4d0000165Asv00001014sd00000378* + ID_MODEL_FROM_DATABASE=IBM System x3350 (Machine type 4192) + +pci:v000014E4d0000165Asv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 Broadcom NetXtreme 5722 + +pci:v000014E4d0000165Asv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 Broadcom NetXtreme 5722 + +pci:v000014E4d0000165Asv00001028sd00000225* + ID_MODEL_FROM_DATABASE=PowerEdge T105 Broadcom NetXtreme 5722 + +pci:v000014E4d0000165Asv0000103Csd00007051* + ID_MODEL_FROM_DATABASE=NC105i PCIe Gigabit Server Adapter + +pci:v000014E4d0000165Asv0000103Csd00007052* + ID_MODEL_FROM_DATABASE=NC105T PCIe Gigabit Server Adapter + +pci:v000014E4d0000165B* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5723 Gigabit Ethernet PCIe + +pci:v000014E4d0000165Bsv0000103Csd0000705D* + ID_MODEL_FROM_DATABASE=NC107i Integrated PCI Express Gigabit Server Adapter + +pci:v000014E4d0000165C* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5724 Gigabit Ethernet PCIe + +pci:v000014E4d0000165D* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5705M Gigabit Ethernet + +pci:v000014E4d0000165Dsv00001028sd0000865D* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v000014E4d0000165Dsv000014E4sd0000165D* + ID_MODEL_FROM_DATABASE=Dell Latitude D600 + +pci:v000014E4d0000165E* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5705M_2 Gigabit Ethernet + +pci:v000014E4d0000165Esv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v000014E4d0000165Esv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v000014E4d0000165Esv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v000014E4d0000165Esv000010CFsd00001279* + ID_MODEL_FROM_DATABASE=LifeBook E8010D + +pci:v000014E4d0000165F* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe + +pci:v000014E4d00001662* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57712 10 Gigabit Ethernet + +pci:v000014E4d00001663* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function + +pci:v000014E4d00001665* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5717 Gigabit Ethernet PCIe + +pci:v000014E4d00001668* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5714 Gigabit Ethernet + +pci:v000014E4d00001668sv0000103Csd00007039* + ID_MODEL_FROM_DATABASE=NC324i PCIe Dual Port Gigabit Server Adapter + +pci:v000014E4d00001669* + ID_MODEL_FROM_DATABASE=NetXtreme 5714S Gigabit Ethernet + +pci:v000014E4d0000166A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5780 Gigabit Ethernet + +pci:v000014E4d0000166Asv0000103Csd00007035* + ID_MODEL_FROM_DATABASE=NC325i Integrated Dual port PCIe Express Gigabit Server Adapter + +pci:v000014E4d0000166B* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5780S Gigabit Ethernet + +pci:v000014E4d0000166E* + ID_MODEL_FROM_DATABASE=570x 10/100 Integrated Controller + +pci:v000014E4d0000166F* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function + +pci:v000014E4d00001672* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5754M Gigabit Ethernet PCI Express + +pci:v000014E4d00001673* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5755M Gigabit Ethernet PCI Express + +pci:v000014E4d00001674* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5756ME Gigabit Ethernet PCI Express + +pci:v000014E4d00001677* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5751 Gigabit Ethernet PCI Express + +pci:v000014E4d00001677sv00001028sd00000176* + ID_MODEL_FROM_DATABASE=Dimension XPS Gen 4 + +pci:v000014E4d00001677sv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v000014E4d00001677sv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v000014E4d00001677sv00001028sd00000182* + ID_MODEL_FROM_DATABASE=Latitude D610 + +pci:v000014E4d00001677sv00001028sd00000187* + ID_MODEL_FROM_DATABASE=Precision M70 + +pci:v000014E4d00001677sv00001028sd000001A8* + ID_MODEL_FROM_DATABASE=Precision 380 + +pci:v000014E4d00001677sv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v000014E4d00001677sv0000103Csd00003006* + ID_MODEL_FROM_DATABASE=DC7100 SFF(DX878AV) + +pci:v000014E4d00001677sv00001462sd0000028C* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v000014E4d00001677sv00001734sd0000105D* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v000014E4d00001678* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5715 Gigabit Ethernet + +pci:v000014E4d00001678sv0000103Csd0000703E* + ID_MODEL_FROM_DATABASE=NC326i PCIe Dual Port Gigabit Server Adapter + +pci:v000014E4d00001679* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5715S Gigabit Ethernet + +pci:v000014E4d00001679sv0000103Csd00001707* + ID_MODEL_FROM_DATABASE=NC326m PCIe Dual Port Adapter + +pci:v000014E4d00001679sv0000103Csd0000170C* + ID_MODEL_FROM_DATABASE=NC325m PCIe Quad Port Adapter + +pci:v000014E4d00001679sv0000103Csd0000703C* + ID_MODEL_FROM_DATABASE=NC326i PCIe Dual Port Gigabit Server Adapter + +pci:v000014E4d0000167A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5754 Gigabit Ethernet PCI Express + +pci:v000014E4d0000167Asv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v000014E4d0000167Asv00001028sd000001DE* + ID_MODEL_FROM_DATABASE=Precision 390 + +pci:v000014E4d0000167Asv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v000014E4d0000167Asv00001028sd00000214* + ID_MODEL_FROM_DATABASE=Precision T3400 + +pci:v000014E4d0000167Asv00001028sd0000021E* + ID_MODEL_FROM_DATABASE=Precision T5400 + +pci:v000014E4d0000167B* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5755 Gigabit Ethernet PCI Express + +pci:v000014E4d0000167Bsv0000103Csd0000280A* + ID_MODEL_FROM_DATABASE=DC5750 Microtower + +pci:v000014E4d0000167D* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5751M Gigabit Ethernet PCI Express + +pci:v000014E4d0000167Dsv00001014sd00000577* + ID_MODEL_FROM_DATABASE=ThinkPad Z60t + +pci:v000014E4d0000167Dsv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=HP nx8220 + +pci:v000014E4d0000167Dsv0000103Csd00000940* + ID_MODEL_FROM_DATABASE=HP Compaq nw8240 Mobile Workstation + +pci:v000014E4d0000167Dsv000017AAsd00002081* + ID_MODEL_FROM_DATABASE=ThinkPad R60e + +pci:v000014E4d0000167E* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5751F Fast Ethernet PCI Express + +pci:v000014E4d0000167F* + ID_MODEL_FROM_DATABASE=NetLink BCM5787F Fast Ethernet PCI Express + +pci:v000014E4d00001680* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5761e Gigabit Ethernet PCIe + +pci:v000014E4d00001681* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5761 Gigabit Ethernet PCIe + +pci:v000014E4d00001682* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57762 Gigabit Ethernet PCIe + +pci:v000014E4d00001683* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57767 Gigabit Ethernet PCIe + +pci:v000014E4d00001684* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5764M Gigabit Ethernet PCIe + +pci:v000014E4d00001685* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57500S Gigabit Ethernet + +pci:v000014E4d00001686* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57766 Gigabit Ethernet PCIe + +pci:v000014E4d00001687* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5762 Gigabit Ethernet PCIe + +pci:v000014E4d00001688* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5761 10/100/1000BASE-T Ethernet + +pci:v000014E4d00001688sv00001259sd00002708* + ID_MODEL_FROM_DATABASE=AT-2712 FX + +pci:v000014E4d0000168A* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1/10 Gigabit Ethernet + +pci:v000014E4d0000168Asv00001028sd00001F5C* + ID_MODEL_FROM_DATABASE=BCM57800 10-Gigabit Ethernet + +pci:v000014E4d0000168Asv00001028sd00001F5D* + ID_MODEL_FROM_DATABASE=BCM57800 10-Gigabit Ethernet + +pci:v000014E4d0000168Asv00001028sd00001F67* + ID_MODEL_FROM_DATABASE=BCM57800 1-Gigabit Ethernet + +pci:v000014E4d0000168Asv00001028sd00001F68* + ID_MODEL_FROM_DATABASE=BCM57800 1-Gigabit Ethernet + +pci:v000014E4d0000168D* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57840 10/20 Gigabit Ethernet + +pci:v000014E4d0000168E* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57810 10 Gigabit Ethernet + +pci:v000014E4d0000168Esv0000103Csd00001798* + ID_MODEL_FROM_DATABASE=Flex-10 10Gb 2-port 530FLB Adapter [Meru] + +pci:v000014E4d00001690* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57760 Gigabit Ethernet PCIe + +pci:v000014E4d00001691* + ID_MODEL_FROM_DATABASE=NetLink BCM57788 Gigabit Ethernet PCIe + +pci:v000014E4d00001691sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v000014E4d00001692* + ID_MODEL_FROM_DATABASE=NetLink BCM57780 Gigabit Ethernet PCIe + +pci:v000014E4d00001692sv00001025sd0000033D* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v000014E4d00001693* + ID_MODEL_FROM_DATABASE=NetLink BCM5787M Gigabit Ethernet PCI Express + +pci:v000014E4d00001693sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v000014E4d00001693sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=6710b + +pci:v000014E4d00001694* + ID_MODEL_FROM_DATABASE=NetLink BCM57790 Gigabit Ethernet PCIe + +pci:v000014E4d00001696* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5782 Gigabit Ethernet + +pci:v000014E4d00001696sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v000014E4d00001696sv000014E4sd0000000D* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5782 1000Base-T + +pci:v000014E4d00001698* + ID_MODEL_FROM_DATABASE=NetLink BCM5784M Gigabit Ethernet PCIe + +pci:v000014E4d00001699* + ID_MODEL_FROM_DATABASE=NetLink BCM5785 Gigabit Ethernet + +pci:v000014E4d0000169A* + ID_MODEL_FROM_DATABASE=NetLink BCM5786 Gigabit Ethernet PCI Express + +pci:v000014E4d0000169B* + ID_MODEL_FROM_DATABASE=NetLink BCM5787 Gigabit Ethernet PCI Express + +pci:v000014E4d0000169C* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5788 Gigabit Ethernet + +pci:v000014E4d0000169Csv0000103Csd0000308B* + ID_MODEL_FROM_DATABASE=MX6125 + +pci:v000014E4d0000169Csv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v000014E4d0000169Csv0000144Dsd0000C018* + ID_MODEL_FROM_DATABASE=X20 + +pci:v000014E4d0000169Csv00001462sd0000590C* + ID_MODEL_FROM_DATABASE=KT6 Delta-FIS2R (MS-6590) + +pci:v000014E4d0000169D* + ID_MODEL_FROM_DATABASE=NetLink BCM5789 Gigabit Ethernet PCI Express + +pci:v000014E4d000016A0* + ID_MODEL_FROM_DATABASE=NetLink BCM5785 Fast Ethernet + +pci:v000014E4d000016A1* + ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II 10 Gigabit Ethernet + +pci:v000014E4d000016A2* + ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II 10/20-Gigabit Ethernet + +pci:v000014E4d000016A4* + ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II Ethernet Multi Function + +pci:v000014E4d000016A5* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1/10 Gigabit Ethernet Multi Function + +pci:v000014E4d000016A5sv00001028sd00001F5C* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 10-Gigabit Ethernet Multi Function + +pci:v000014E4d000016A5sv00001028sd00001F5D* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 10-Gigabit Ethernet Multi Function + +pci:v000014E4d000016A5sv00001028sd00001F67* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1-Gigabit Ethernet Multi Function + +pci:v000014E4d000016A5sv00001028sd00001F68* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1-Gigabit Ethernet Multi Function + +pci:v000014E4d000016A6* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5702X Gigabit Ethernet + +pci:v000014E4d000016A6sv00000E11sd000000BB* + ID_MODEL_FROM_DATABASE=NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T) + +pci:v000014E4d000016A6sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=BCM5702 1000Base-T + +pci:v000014E4d000016A6sv000014E4sd0000000C* + ID_MODEL_FROM_DATABASE=BCM5702 1000Base-T + +pci:v000014E4d000016A6sv000014E4sd00008009* + ID_MODEL_FROM_DATABASE=BCM5702 1000Base-T + +pci:v000014E4d000016A7* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703X Gigabit Ethernet + +pci:v000014E4d000016A7sv00000E11sd000000CA* + ID_MODEL_FROM_DATABASE=NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d000016A7sv00000E11sd000000CB* + ID_MODEL_FROM_DATABASE=NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d000016A7sv00001014sd0000026F* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v000014E4d000016A7sv000014E4sd00000009* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-T + +pci:v000014E4d000016A7sv000014E4sd0000000A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-SX + +pci:v000014E4d000016A7sv000014E4sd0000000B* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-T + +pci:v000014E4d000016A7sv000014E4sd0000800A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-T + +pci:v000014E4d000016A8* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5704S Gigabit Ethernet + +pci:v000014E4d000016A8sv0000103Csd0000132B* + ID_MODEL_FROM_DATABASE=PCI-X 1000Mbps Dual-port Built-in + +pci:v000014E4d000016A8sv000010A9sd00008014* + ID_MODEL_FROM_DATABASE=Dual Port Gigabit Ethernet (PCI-X,Fiber) + +pci:v000014E4d000016A8sv000010A9sd0000801C* + ID_MODEL_FROM_DATABASE=Quad Port Gigabit Ethernet (PCI-E,Fiber) + +pci:v000014E4d000016A8sv000010B7sd00002001* + ID_MODEL_FROM_DATABASE=3C998-SX Dual Port 1000-SX PCI-X + +pci:v000014E4d000016A9* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1/10 Gigabit Ethernet Virtual Function + +pci:v000014E4d000016A9sv00001028sd00001F5C* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 10-Gigabit Ethernet Virtual Function + +pci:v000014E4d000016A9sv00001028sd00001F5D* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 10-Gigabit Ethernet Virtual Function + +pci:v000014E4d000016A9sv00001028sd00001F67* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1-Gigabit Ethernet Virtual Function + +pci:v000014E4d000016A9sv00001028sd00001F68* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57800 1-Gigabit Ethernet Virtual Function + +pci:v000014E4d000016AA* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5706S Gigabit Ethernet + +pci:v000014E4d000016AAsv0000103Csd00003102* + ID_MODEL_FROM_DATABASE=NC370F MultifuNCtion Gigabit Server Adapter + +pci:v000014E4d000016AAsv0000103Csd0000310C* + ID_MODEL_FROM_DATABASE=NC370i Multifunction Gigabit Server Adapter + +pci:v000014E4d000016AB* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function + +pci:v000014E4d000016AC* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5708S Gigabit Ethernet + +pci:v000014E4d000016ACsv00001014sd00000304* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM5708S Gigabit Ethernet + +pci:v000014E4d000016ACsv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 Broadcom NetXtreme II BCM5708S + +pci:v000014E4d000016ACsv00001028sd0000020C* + ID_MODEL_FROM_DATABASE=PowerEdge M605 Broadcom NetXtreme II BCM5708S + +pci:v000014E4d000016ACsv0000103Csd00001706* + ID_MODEL_FROM_DATABASE=NC373m Multifunction Gigabit Server Adapter + +pci:v000014E4d000016ACsv0000103Csd00007038* + ID_MODEL_FROM_DATABASE=NC373i PCI Express Multifunction Gigabit Server Adapter + +pci:v000014E4d000016ACsv0000103Csd0000703B* + ID_MODEL_FROM_DATABASE=NC373i Integrated Multifunction Gigabit Server Adapter + +pci:v000014E4d000016ACsv0000103Csd0000703D* + ID_MODEL_FROM_DATABASE=NC373F PCI Express Multifunction Gigabit Server Adapter + +pci:v000014E4d000016AD* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function + +pci:v000014E4d000016AE* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function + +pci:v000014E4d000016AF* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function + +pci:v000014E4d000016B0* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57761 Gigabit Ethernet PCIe + +pci:v000014E4d000016B1* + ID_MODEL_FROM_DATABASE=NetLink BCM57781 Gigabit Ethernet PCIe + +pci:v000014E4d000016B1sv00001849sd000096B1* + ID_MODEL_FROM_DATABASE=Z77 Extreme4 motherboard + +pci:v000014E4d000016B2* + ID_MODEL_FROM_DATABASE=NetLink BCM57791 Gigabit Ethernet PCIe + +pci:v000014E4d000016B3* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57786 Gigabit Ethernet PCIe + +pci:v000014E4d000016B4* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57765 Gigabit Ethernet PCIe + +pci:v000014E4d000016B5* + ID_MODEL_FROM_DATABASE=NetLink BCM57785 Gigabit Ethernet PCIe + +pci:v000014E4d000016B6* + ID_MODEL_FROM_DATABASE=NetLink BCM57795 Gigabit Ethernet PCIe + +pci:v000014E4d000016B7* + ID_MODEL_FROM_DATABASE=NetXtreme BCM57782 Gigabit Ethernet PCIe + +pci:v000014E4d000016BC* + ID_MODEL_FROM_DATABASE=BCM57765/57785 SDXC/MMC Card Reader + +pci:v000014E4d000016BE* + ID_MODEL_FROM_DATABASE=BCM57765/57785 MS Card Reader + +pci:v000014E4d000016BF* + ID_MODEL_FROM_DATABASE=BCM57765/57785 xD-Picture Card Reader + +pci:v000014E4d000016C6* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5702A3 Gigabit Ethernet + +pci:v000014E4d000016C6sv000010B7sd00001100* + ID_MODEL_FROM_DATABASE=3C1000B-T 10/100/1000 PCI + +pci:v000014E4d000016C6sv000014E4sd0000000C* + ID_MODEL_FROM_DATABASE=BCM5702 1000Base-T + +pci:v000014E4d000016C6sv000014E4sd00008009* + ID_MODEL_FROM_DATABASE=BCM5702 1000Base-T + +pci:v000014E4d000016C7* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 Gigabit Ethernet + +pci:v000014E4d000016C7sv00000E11sd000000CA* + ID_MODEL_FROM_DATABASE=NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d000016C7sv00000E11sd000000CB* + ID_MODEL_FROM_DATABASE=NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T) + +pci:v000014E4d000016C7sv0000103Csd000012C3* + ID_MODEL_FROM_DATABASE=Combo FC/GigE-SX [A9782A] + +pci:v000014E4d000016C7sv0000103Csd000012CA* + ID_MODEL_FROM_DATABASE=Combo FC/GigE-T [A9784A] + +pci:v000014E4d000016C7sv0000103Csd00001321* + ID_MODEL_FROM_DATABASE=Core I/O LAN/SCSI Combo [AB314A] + +pci:v000014E4d000016C7sv000014E4sd00000009* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-T + +pci:v000014E4d000016C7sv000014E4sd0000000A* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 1000Base-SX + +pci:v000014E4d000016DD* + ID_MODEL_FROM_DATABASE=NetLink BCM5781 Gigabit Ethernet PCI Express + +pci:v000014E4d000016F3* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5727 Gigabit Ethernet PCIe + +pci:v000014E4d000016F7* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5753 Gigabit Ethernet PCI Express + +pci:v000014E4d000016FD* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5753M Gigabit Ethernet PCI Express + +pci:v000014E4d000016FDsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v000014E4d000016FDsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v000014E4d000016FE* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5753F Fast Ethernet PCI Express + +pci:v000014E4d0000170C* + ID_MODEL_FROM_DATABASE=BCM4401-B0 100Base-TX + +pci:v000014E4d0000170Csv00001028sd00000188* + ID_MODEL_FROM_DATABASE=Inspiron 6000 laptop + +pci:v000014E4d0000170Csv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v000014E4d0000170Csv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v000014E4d0000170Csv00001028sd000001AF* + ID_MODEL_FROM_DATABASE=Inspiron 6400 + +pci:v000014E4d0000170Csv00001028sd000001CD* + ID_MODEL_FROM_DATABASE=Inspiron 9400 Laptop + +pci:v000014E4d0000170Csv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v000014E4d0000170Csv00001028sd000001D8* + ID_MODEL_FROM_DATABASE=Inspiron E1405 + +pci:v000014E4d0000170Csv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v000014E4d0000170Csv0000103Csd000030A2* + ID_MODEL_FROM_DATABASE=NX7300 laptop + +pci:v000014E4d0000170Csv000014E4sd0000170C* + ID_MODEL_FROM_DATABASE=HP Compaq 6720t Mobile Thin Client + +pci:v000014E4d0000170D* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5901 100Base-TX + +pci:v000014E4d0000170Dsv00001014sd00000545* + ID_MODEL_FROM_DATABASE=ThinkPad R40e + +pci:v000014E4d0000170E* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5901 100Base-TX + +pci:v000014E4d00001712* + ID_MODEL_FROM_DATABASE=NetLink BCM5906 Fast Ethernet PCI Express + +pci:v000014E4d00001713* + ID_MODEL_FROM_DATABASE=NetLink BCM5906M Fast Ethernet PCI Express + +pci:v000014E4d00001713sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v000014E4d00001713sv00001028sd00000209* + ID_MODEL_FROM_DATABASE=XPS M1330 + +pci:v000014E4d00001713sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v000014E4d00001713sv000017AAsd00003A23* + ID_MODEL_FROM_DATABASE=IdeaPad S10e + +pci:v000014E4d00003352* + ID_MODEL_FROM_DATABASE=BCM3352 + +pci:v000014E4d00003360* + ID_MODEL_FROM_DATABASE=BCM3360 + +pci:v000014E4d00004210* + ID_MODEL_FROM_DATABASE=BCM4210 iLine10 HomePNA 2.0 + +pci:v000014E4d00004211* + ID_MODEL_FROM_DATABASE=BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem + +pci:v000014E4d00004212* + ID_MODEL_FROM_DATABASE=BCM4212 v.90 56k modem + +pci:v000014E4d00004220* + ID_MODEL_FROM_DATABASE=802-11b/g Wireless PCI controller, packaged as a Linksys WPC54G ver 1.2 PCMCIA card + +pci:v000014E4d00004222* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5753M Gigabit Ethernet PCI Express + +pci:v000014E4d00004301* + ID_MODEL_FROM_DATABASE=BCM4301 802.11b Wireless LAN Controller + +pci:v000014E4d00004301sv00001028sd00000407* + ID_MODEL_FROM_DATABASE=TrueMobile 1180 Onboard WLAN + +pci:v000014E4d00004301sv00001043sd00000120* + ID_MODEL_FROM_DATABASE=WL-103b Wireless LAN PC Card + +pci:v000014E4d00004301sv000016A5sd00001602* + ID_MODEL_FROM_DATABASE=B-300 802.11b Wireless CardBus Adapter + +pci:v000014E4d00004301sv00001737sd00004301* + ID_MODEL_FROM_DATABASE=WMP11 v2.7 802.11b Wireless-B PCI Adapter + +pci:v000014E4d00004305* + ID_MODEL_FROM_DATABASE=BCM4307 V.90 56k Modem + +pci:v000014E4d00004306* + ID_MODEL_FROM_DATABASE=BCM4306 802.11bg Wireless LAN controller + +pci:v000014E4d00004307* + ID_MODEL_FROM_DATABASE=BCM4306 802.11bg Wireless LAN Controller + +pci:v000014E4d00004310* + ID_MODEL_FROM_DATABASE=BCM4310 Chipcommon I/OController + +pci:v000014E4d00004311* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g WLAN + +pci:v000014E4d00004311sv00001028sd00000007* + ID_MODEL_FROM_DATABASE=Wireless 1390 WLAN Mini-Card + +pci:v000014E4d00004311sv00001028sd00000008* + ID_MODEL_FROM_DATABASE=Wireless 1390 WLAN ExpressCard + +pci:v000014E4d00004311sv0000103Csd00001363* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001364* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001365* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001374* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001375* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001376* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001377* + ID_MODEL_FROM_DATABASE=BCM4311 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd0000137F* + ID_MODEL_FROM_DATABASE=BCM4322 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004311sv0000103Csd00001380* + ID_MODEL_FROM_DATABASE=BCM4322 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004311sv000014E4sd00004311* + ID_MODEL_FROM_DATABASE=BCM94311MCG + +pci:v000014E4d00004312* + ID_MODEL_FROM_DATABASE=BCM4311 802.11a/b/g + +pci:v000014E4d00004312sv00001028sd00000007* + ID_MODEL_FROM_DATABASE=Wireless 1490 Dual Band WLAN Mini-Card + +pci:v000014E4d00004312sv00001028sd00000008* + ID_MODEL_FROM_DATABASE=Wireless 1490 Dual Band WLAN ExpressCard + +pci:v000014E4d00004312sv0000103Csd0000135A* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd0000135F* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001360* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001361* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001362* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001370* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001371* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001372* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd00001373* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004312sv0000103Csd000030B5* + ID_MODEL_FROM_DATABASE=Presario V3242AU + +pci:v000014E4d00004312sv0000106Bsd00000089* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004312sv00001371sd0000103C* + ID_MODEL_FROM_DATABASE=Broadcom 802.11 Multiband-netwerkadapter(6715s) + +pci:v000014E4d00004313* + ID_MODEL_FROM_DATABASE=BCM4311 802.11a + +pci:v000014E4d00004315* + ID_MODEL_FROM_DATABASE=BCM4312 802.11b/g LP-PHY + +pci:v000014E4d00004315sv00001028sd0000000B* + ID_MODEL_FROM_DATABASE=Wireless 1395 WLAN Mini-Card + +pci:v000014E4d00004315sv00001028sd0000000C* + ID_MODEL_FROM_DATABASE=Wireless 1397 WLAN Mini-Card + +pci:v000014E4d00004315sv0000103Csd0000137C* + ID_MODEL_FROM_DATABASE=BCM4312 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004315sv0000103Csd0000137D* + ID_MODEL_FROM_DATABASE=BCM4312 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004315sv0000103Csd00001507* + ID_MODEL_FROM_DATABASE=U98Z049.00 Wireless Mini PCIe Card + +pci:v000014E4d00004315sv0000105Bsd0000E003* + ID_MODEL_FROM_DATABASE=T77H030.00 Wireless Mini PCIe Card + +pci:v000014E4d00004315sv0000105Bsd0000E01B* + ID_MODEL_FROM_DATABASE=T77H106.00 Wireless Half-size Mini PCIe Card + +pci:v000014E4d00004318* + ID_MODEL_FROM_DATABASE=BCM4318 [AirForce One 54g] 802.11g Wireless LAN Controller + +pci:v000014E4d00004318sv00001028sd00000005* + ID_MODEL_FROM_DATABASE=Wireless 1370 WLAN Mini-PCI Card + +pci:v000014E4d00004318sv00001028sd00000006* + ID_MODEL_FROM_DATABASE=Wireless 1370 WLAN PC Card + +pci:v000014E4d00004318sv0000103Csd00001355* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004318sv0000103Csd00001356* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004318sv0000103Csd00001357* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004318sv00001043sd0000100F* + ID_MODEL_FROM_DATABASE=WL-138G v2 / WL-138gE / WL-100gE + +pci:v000014E4d00004318sv00001043sd0000120F* + ID_MODEL_FROM_DATABASE=A6U notebook embedded card + +pci:v000014E4d00004318sv00001154sd00000355* + ID_MODEL_FROM_DATABASE=Buffalo WLI2-PCI-G54S High Speed Mode Wireless Adapter + +pci:v000014E4d00004318sv00001468sd00000311* + ID_MODEL_FROM_DATABASE=Aspire 3022WLMi, 5024WLMi, 5020 + +pci:v000014E4d00004318sv00001468sd00000312* + ID_MODEL_FROM_DATABASE=TravelMate 2410 + +pci:v000014E4d00004318sv000014E4sd00000449* + ID_MODEL_FROM_DATABASE=Gateway 7510GX + +pci:v000014E4d00004318sv000016ECsd00000119* + ID_MODEL_FROM_DATABASE=U.S.Robotics Wireless MAXg PC Card + +pci:v000014E4d00004318sv00001737sd00000042* + ID_MODEL_FROM_DATABASE=WMP54GS v1.1 802.11g Wireless-G PCI Adapter with SpeedBooster + +pci:v000014E4d00004318sv00001737sd00000048* + ID_MODEL_FROM_DATABASE=WPC54G v3 802.11g Wireless-G Notebook Adapter + +pci:v000014E4d00004318sv00001737sd00000049* + ID_MODEL_FROM_DATABASE=WPC54GS v2 802.11g Wireless-G Notebook Adapter with SpeedBooster + +pci:v000014E4d00004318sv00001799sd00007000* + ID_MODEL_FROM_DATABASE=F5D7000 v4000 Wireless G Desktop Card + +pci:v000014E4d00004318sv00001799sd00007001* + ID_MODEL_FROM_DATABASE=F5D7001 v2000 Wireless G Plus Desktop Card + +pci:v000014E4d00004318sv00001799sd00007010* + ID_MODEL_FROM_DATABASE=F5D7010 v4000 Wireless G Notebook Card + +pci:v000014E4d00004318sv00001799sd00007011* + ID_MODEL_FROM_DATABASE=F5D7011 v2000 High-Speed Mode Wireless G Notebook Card + +pci:v000014E4d00004319* + ID_MODEL_FROM_DATABASE=BCM4318 [AirForce 54g] 802.11a/b/g PCI Express Transceiver + +pci:v000014E4d00004319sv00001028sd00000005* + ID_MODEL_FROM_DATABASE=Wireless 1470 Dual Band WLAN Mini-PCI Card + +pci:v000014E4d00004319sv00001028sd00000006* + ID_MODEL_FROM_DATABASE=Wireless 1470 Dual Band WLAN PC Card + +pci:v000014E4d00004319sv0000103Csd00001358* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004319sv0000103Csd00001359* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004319sv0000103Csd0000135A* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004320* + ID_MODEL_FROM_DATABASE=BCM4306 802.11b/g Wireless LAN Controller + +pci:v000014E4d00004320sv00001028sd00000001* + ID_MODEL_FROM_DATABASE=TrueMobile 1300 WLAN Mini-PCI Card + +pci:v000014E4d00004320sv00001028sd00000002* + ID_MODEL_FROM_DATABASE=TrueMobile 1300 WLAN PC Card + +pci:v000014E4d00004320sv00001028sd00000003* + ID_MODEL_FROM_DATABASE=Wireless 1350 WLAN Mini-PCI Card + +pci:v000014E4d00004320sv00001028sd00000004* + ID_MODEL_FROM_DATABASE=Wireless 1350 WLAN PC Card + +pci:v000014E4d00004320sv0000103Csd000012F4* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004320sv0000103Csd000012F8* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004320sv0000103Csd000012FA* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004320sv0000103Csd000012FB* + ID_MODEL_FROM_DATABASE=Broadcom 802.11b/g WLAN + +pci:v000014E4d00004320sv00001043sd0000100F* + ID_MODEL_FROM_DATABASE=WL-100G + +pci:v000014E4d00004320sv00001057sd00007025* + ID_MODEL_FROM_DATABASE=WN825G + +pci:v000014E4d00004320sv0000106Bsd0000004E* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004320sv00001154sd00000330* + ID_MODEL_FROM_DATABASE=Buffalo WLI2-PCI-G54S High Speed Mode Wireless Desktop Adapter + +pci:v000014E4d00004320sv0000144Fsd00007050* + ID_MODEL_FROM_DATABASE=eMachines M6805 802.11g Built-in Wireless + +pci:v000014E4d00004320sv0000144Fsd00007051* + ID_MODEL_FROM_DATABASE=Sonnet Aria Extreme PCI + +pci:v000014E4d00004320sv00001737sd00000013* + ID_MODEL_FROM_DATABASE=WMP54G v1 802.11g PCI Adapter + +pci:v000014E4d00004320sv00001737sd00000014* + ID_MODEL_FROM_DATABASE=WMP54G v2 802.11g PCI Adapter + +pci:v000014E4d00004320sv00001737sd00000015* + ID_MODEL_FROM_DATABASE=WMP54GS v1.0 802.11g Wireless-G PCI Adapter with SpeedBooster + +pci:v000014E4d00004320sv00001737sd00004320* + ID_MODEL_FROM_DATABASE=WPC54G v1 / WPC54GS v1 802.11g Wireless-G Notebook Adapter + +pci:v000014E4d00004320sv00001799sd00007000* + ID_MODEL_FROM_DATABASE=F5D7000 v1000 Wireless G Desktop Card + +pci:v000014E4d00004320sv00001799sd00007001* + ID_MODEL_FROM_DATABASE=F5D7001 v1000 Wireless G Plus Desktop Card + +pci:v000014E4d00004320sv00001799sd00007010* + ID_MODEL_FROM_DATABASE=F5D7010 v1000 Wireless G Notebook Card + +pci:v000014E4d00004320sv00001799sd00007011* + ID_MODEL_FROM_DATABASE=F5D7011 v1000 High-Speed Mode Wireless G Notebook Card + +pci:v000014E4d00004320sv0000185Fsd00001220* + ID_MODEL_FROM_DATABASE=TravelMate 290E WLAN Mini-PCI Card + +pci:v000014E4d00004321* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a Wireless Network Controller + +pci:v000014E4d00004322* + ID_MODEL_FROM_DATABASE=BCM4322 802.11bgn Wireless Network Controller + +pci:v000014E4d00004324* + ID_MODEL_FROM_DATABASE=BCM4309 802.11abg Wireless Network Controller + +pci:v000014E4d00004324sv00001028sd00000001* + ID_MODEL_FROM_DATABASE=Truemobile 1400 + +pci:v000014E4d00004324sv00001028sd00000002* + ID_MODEL_FROM_DATABASE=TrueMobile 1400 Dual Band WLAN PC Card + +pci:v000014E4d00004324sv00001028sd00000003* + ID_MODEL_FROM_DATABASE=Truemobile 1450 MiniPCI + +pci:v000014E4d00004324sv00001028sd00000004* + ID_MODEL_FROM_DATABASE=Wireless 1450 Dual Band WLAN PC Card + +pci:v000014E4d00004324sv0000103Csd000012F9* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004324sv0000103Csd000012FC* + ID_MODEL_FROM_DATABASE=Broadcom 802.11a/b/g WLAN + +pci:v000014E4d00004325* + ID_MODEL_FROM_DATABASE=BCM4306 802.11bg Wireless Network Controller + +pci:v000014E4d00004325sv00001414sd00000003* + ID_MODEL_FROM_DATABASE=Wireless Notebook Adapter MN-720 + +pci:v000014E4d00004325sv00001414sd00000004* + ID_MODEL_FROM_DATABASE=Wireless PCI Adapter MN-730 + +pci:v000014E4d00004326* + ID_MODEL_FROM_DATABASE=BCM4307 Chipcommon I/O Controller? + +pci:v000014E4d00004328* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a/b/g/n + +pci:v000014E4d00004328sv00001028sd00000009* + ID_MODEL_FROM_DATABASE=Wireless 1500 Draft 802.11n WLAN Mini-Card + +pci:v000014E4d00004328sv00001028sd0000000A* + ID_MODEL_FROM_DATABASE=Wireless 1500 Draft 802.11n WLAN Mini-card + +pci:v000014E4d00004328sv0000103Csd00001366* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004328sv0000103Csd00001367* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004328sv0000103Csd00001368* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004328sv0000103Csd00001369* + ID_MODEL_FROM_DATABASE=BCM4321 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d00004328sv0000106Bsd00000087* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004328sv0000106Bsd00000088* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004328sv0000106Bsd0000008B* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004328sv0000106Bsd0000008C* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004328sv0000106Bsd00000090* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004328sv000014E4sd00004328* + ID_MODEL_FROM_DATABASE=BCM4328 802.11a/b/g/n + +pci:v000014E4d00004328sv00001737sd00000066* + ID_MODEL_FROM_DATABASE=WPC600N v1 802.11a/b/g/n Wireless-N CardBus Adapter + +pci:v000014E4d00004328sv00001737sd00000068* + ID_MODEL_FROM_DATABASE=WEC600N v1 802.11a/b/g/n Wireless-N ExpressCard + +pci:v000014E4d00004329* + ID_MODEL_FROM_DATABASE=BCM4321 802.11b/g/n + +pci:v000014E4d00004329sv00001385sd00007B00* + ID_MODEL_FROM_DATABASE=WN511B RangeMax NEXT Wireless Notebook Adapter + +pci:v000014E4d00004329sv00001385sd00007D00* + ID_MODEL_FROM_DATABASE=WN311B RangeMax Next 270 Mbps Wireless PCI Adapter + +pci:v000014E4d00004329sv00001737sd00000058* + ID_MODEL_FROM_DATABASE=WPC300N v1 Wireless-N Notebook Adapter + +pci:v000014E4d0000432A* + ID_MODEL_FROM_DATABASE=BCM4321 802.11an Wireless Network Controller + +pci:v000014E4d0000432B* + ID_MODEL_FROM_DATABASE=BCM4322 802.11a/b/g/n Wireless LAN Controller + +pci:v000014E4d0000432Bsv00001028sd0000000D* + ID_MODEL_FROM_DATABASE=Wireless 1510 Wireless-N WLAN Mini-Card + +pci:v000014E4d0000432Bsv0000106Bsd0000008D* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d0000432Bsv0000106Bsd0000008E* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d0000432C* + ID_MODEL_FROM_DATABASE=BCM4322 802.11b/g/n + +pci:v000014E4d0000432Csv00001799sd0000D311* + ID_MODEL_FROM_DATABASE=Dynex DX-NNBX 802.11n WLAN Cardbus Card + +pci:v000014E4d0000432D* + ID_MODEL_FROM_DATABASE=BCM4322 802.11an Wireless Network Controller + +pci:v000014E4d00004331* + ID_MODEL_FROM_DATABASE=BCM4331 802.11a/b/g/n + +pci:v000014E4d00004331sv0000106Bsd000000D6* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd000000E4* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd000000EF* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd000000F4* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd000000F5* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd0000010E* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004331sv0000106Bsd0000010F* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004333* + ID_MODEL_FROM_DATABASE=Serial (EDGE/GPRS modem part of Option GT Combo Edge) + +pci:v000014E4d00004344* + ID_MODEL_FROM_DATABASE=EDGE/GPRS data and 802.11b/g combo cardbus [GC89] + +pci:v000014E4d00004350* + ID_MODEL_FROM_DATABASE=BCM43222 Wireless Network Adapter + +pci:v000014E4d00004353* + ID_MODEL_FROM_DATABASE=BCM43224 802.11a/b/g/n + +pci:v000014E4d00004353sv00001028sd0000000E* + ID_MODEL_FROM_DATABASE=Wireless 1520 Half-size Mini PCIe Card + +pci:v000014E4d00004353sv0000103Csd00001509* + ID_MODEL_FROM_DATABASE=WMIB-275N Half-size Mini PCIe Card + +pci:v000014E4d00004353sv0000106Bsd00000093* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004353sv0000106Bsd000000D1* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004353sv0000106Bsd000000E9* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v000014E4d00004357* + ID_MODEL_FROM_DATABASE=BCM43225 802.11b/g/n + +pci:v000014E4d00004357sv0000105Bsd0000E021* + ID_MODEL_FROM_DATABASE=T77H103.00 Wireless Half-size Mini PCIe Card + +pci:v000014E4d00004358* + ID_MODEL_FROM_DATABASE=BCM43227 802.11b/g/n + +pci:v000014E4d00004359* + ID_MODEL_FROM_DATABASE=BCM43228 802.11a/b/g/n + +pci:v000014E4d00004359sv00001028sd00000011* + ID_MODEL_FROM_DATABASE=Wireless 1530 Half-size Mini PCIe Card + +pci:v000014E4d00004359sv0000103Csd0000182C* + ID_MODEL_FROM_DATABASE=BCM943228HM4L 802.11a/b/g/n 2x2 Wi-Fi Adapter + +pci:v000014E4d00004365* + ID_MODEL_FROM_DATABASE=BCM43142 802.11b/g/n + +pci:v000014E4d00004365sv00001028sd00000016* + ID_MODEL_FROM_DATABASE=Wireless 1704 802.11n + BT 4.0 + +pci:v000014E4d000043A0* + ID_MODEL_FROM_DATABASE=BCM4360 802.11ac Wireless Network Adapter + +pci:v000014E4d000043B1* + ID_MODEL_FROM_DATABASE=BCM4352 802.11ac Wireless Network Adapter + +pci:v000014E4d00004401* + ID_MODEL_FROM_DATABASE=BCM4401 100Base-T + +pci:v000014E4d00004401sv00001025sd00000035* + ID_MODEL_FROM_DATABASE=TravelMate 660 + +pci:v000014E4d00004401sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v000014E4d00004401sv00001043sd000080A8* + ID_MODEL_FROM_DATABASE=A7V8X motherboard + +pci:v000014E4d00004402* + ID_MODEL_FROM_DATABASE=BCM4402 Integrated 10/100BaseT + +pci:v000014E4d00004403* + ID_MODEL_FROM_DATABASE=BCM4402 V.90 56k Modem + +pci:v000014E4d00004410* + ID_MODEL_FROM_DATABASE=BCM4413 iLine32 HomePNA 2.0 + +pci:v000014E4d00004411* + ID_MODEL_FROM_DATABASE=BCM4413 V.90 56k modem + +pci:v000014E4d00004412* + ID_MODEL_FROM_DATABASE=BCM4412 10/100BaseT + +pci:v000014E4d00004430* + ID_MODEL_FROM_DATABASE=BCM44xx CardBus iLine32 HomePNA 2.0 + +pci:v000014E4d00004432* + ID_MODEL_FROM_DATABASE=BCM4432 CardBus 10/100BaseT + +pci:v000014E4d00004610* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 PCI to SB Bridge + +pci:v000014E4d00004611* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 iLine32 HomePNA 1.0 + +pci:v000014E4d00004612* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 V.90 56k Modem + +pci:v000014E4d00004613* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 Ethernet Controller + +pci:v000014E4d00004614* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 External Interface + +pci:v000014E4d00004615* + ID_MODEL_FROM_DATABASE=BCM4610 Sentry5 USB Controller + +pci:v000014E4d00004704* + ID_MODEL_FROM_DATABASE=BCM4704 PCI to SB Bridge + +pci:v000014E4d00004705* + ID_MODEL_FROM_DATABASE=BCM4704 Sentry5 802.11b Wireless LAN Controller + +pci:v000014E4d00004706* + ID_MODEL_FROM_DATABASE=BCM4704 Sentry5 Ethernet Controller + +pci:v000014E4d00004707* + ID_MODEL_FROM_DATABASE=BCM4704 Sentry5 USB Controller + +pci:v000014E4d00004708* + ID_MODEL_FROM_DATABASE=BCM4704 Crypto Accelerator + +pci:v000014E4d00004710* + ID_MODEL_FROM_DATABASE=BCM4710 Sentry5 PCI to SB Bridge + +pci:v000014E4d00004711* + ID_MODEL_FROM_DATABASE=BCM47xx Sentry5 iLine32 HomePNA 2.0 + +pci:v000014E4d00004712* + ID_MODEL_FROM_DATABASE=BCM47xx V.92 56k modem + +pci:v000014E4d00004713* + ID_MODEL_FROM_DATABASE=Sentry5 Ethernet Controller + +pci:v000014E4d00004714* + ID_MODEL_FROM_DATABASE=BCM47xx Sentry5 External Interface + +pci:v000014E4d00004715* + ID_MODEL_FROM_DATABASE=BCM47xx Sentry5 USB / Ethernet Controller + +pci:v000014E4d00004716* + ID_MODEL_FROM_DATABASE=BCM47xx Sentry5 USB Host Controller + +pci:v000014E4d00004717* + ID_MODEL_FROM_DATABASE=BCM47xx Sentry5 USB Device Controller + +pci:v000014E4d00004718* + ID_MODEL_FROM_DATABASE=Sentry5 Crypto Accelerator + +pci:v000014E4d00004719* + ID_MODEL_FROM_DATABASE=BCM47xx/53xx RoboSwitch Core + +pci:v000014E4d00004720* + ID_MODEL_FROM_DATABASE=BCM4712 MIPS CPU + +pci:v000014E4d00004727* + ID_MODEL_FROM_DATABASE=BCM4313 802.11bgn Wireless Network Adapter + +pci:v000014E4d00004727sv00001028sd00000010* + ID_MODEL_FROM_DATABASE=Inspiron M5010 / XPS 8300 + +pci:v000014E4d00005365* + ID_MODEL_FROM_DATABASE=BCM5365P Sentry5 Host Bridge + +pci:v000014E4d00005600* + ID_MODEL_FROM_DATABASE=BCM5600 StrataSwitch 24+2 Ethernet Switch Controller + +pci:v000014E4d00005605* + ID_MODEL_FROM_DATABASE=BCM5605 StrataSwitch 24+2 Ethernet Switch Controller + +pci:v000014E4d00005615* + ID_MODEL_FROM_DATABASE=BCM5615 StrataSwitch 24+2 Ethernet Switch Controller + +pci:v000014E4d00005625* + ID_MODEL_FROM_DATABASE=BCM5625 StrataSwitch 24+2 Ethernet Switch Controller + +pci:v000014E4d00005645* + ID_MODEL_FROM_DATABASE=BCM5645 StrataSwitch 24+2 Ethernet Switch Controller + +pci:v000014E4d00005670* + ID_MODEL_FROM_DATABASE=BCM5670 8-Port 10GE Ethernet Switch Fabric + +pci:v000014E4d00005680* + ID_MODEL_FROM_DATABASE=BCM5680 G-Switch 8 Port Gigabit Ethernet Switch Controller + +pci:v000014E4d00005690* + ID_MODEL_FROM_DATABASE=BCM5690 12-port Multi-Layer Gigabit Ethernet Switch + +pci:v000014E4d00005691* + ID_MODEL_FROM_DATABASE=BCM5691 GE/10GE 8+2 Gigabit Ethernet Switch Controller + +pci:v000014E4d00005692* + ID_MODEL_FROM_DATABASE=BCM5692 12-port Multi-Layer Gigabit Ethernet Switch + +pci:v000014E4d00005695* + ID_MODEL_FROM_DATABASE=BCM5695 12-port + HiGig Multi-Layer Gigabit Ethernet Switch + +pci:v000014E4d00005698* + ID_MODEL_FROM_DATABASE=BCM5698 12-port Multi-Layer Gigabit Ethernet Switch + +pci:v000014E4d00005820* + ID_MODEL_FROM_DATABASE=BCM5820 Crypto Accelerator + +pci:v000014E4d00005821* + ID_MODEL_FROM_DATABASE=BCM5821 Crypto Accelerator + +pci:v000014E4d00005822* + ID_MODEL_FROM_DATABASE=BCM5822 Crypto Accelerator + +pci:v000014E4d00005823* + ID_MODEL_FROM_DATABASE=BCM5823 Crypto Accelerator + +pci:v000014E4d00005824* + ID_MODEL_FROM_DATABASE=BCM5824 Crypto Accelerator + +pci:v000014E4d00005840* + ID_MODEL_FROM_DATABASE=BCM5840 Crypto Accelerator + +pci:v000014E4d00005841* + ID_MODEL_FROM_DATABASE=BCM5841 Crypto Accelerator + +pci:v000014E4d00005850* + ID_MODEL_FROM_DATABASE=BCM5850 Crypto Accelerator + +pci:v000014E4d00008602* + ID_MODEL_FROM_DATABASE=BCM7400/BCM7405 Serial ATA Controller + +pci:v000014E4d0000A8D8* + ID_MODEL_FROM_DATABASE=BCM43224/5 Wireless Network Adapter + +pci:v000014E4d0000B302* + ID_MODEL_FROM_DATABASE=BCM56302 StrataXGS 24x1GE 2x10GE Switch Controller + +pci:v000014E4d0000B334* + ID_MODEL_FROM_DATABASE=BCM56334 StrataXGS 24x1GE 4x10GE Switch Controller + +pci:v000014E4d0000B800* + ID_MODEL_FROM_DATABASE=BCM56800 StrataXGS 10GE Switch Controller + +pci:v000014E4d0000B842* + ID_MODEL_FROM_DATABASE=BCM56842 Trident 10GE Switch Controller + +pci:v000014E5* + ID_VENDOR_FROM_DATABASE=Pixelfusion Ltd + +pci:v000014E6* + ID_VENDOR_FROM_DATABASE=SHINING Technology Inc + +pci:v000014E7* + ID_VENDOR_FROM_DATABASE=3CX + +pci:v000014E8* + ID_VENDOR_FROM_DATABASE=RAYCER Inc + +pci:v000014E9* + ID_VENDOR_FROM_DATABASE=GARNETS System CO Ltd + +pci:v000014EA* + ID_VENDOR_FROM_DATABASE=Planex Communications, Inc + +pci:v000014EAd0000AB06* + ID_MODEL_FROM_DATABASE=FNW-3603-TX CardBus Fast Ethernet + +pci:v000014EAd0000AB07* + ID_MODEL_FROM_DATABASE=RTL81xx RealTek Ethernet + +pci:v000014EAd0000AB08* + ID_MODEL_FROM_DATABASE=FNW-3602-TX CardBus Fast Ethernet + +pci:v000014EB* + ID_VENDOR_FROM_DATABASE=SEIKO EPSON Corp + +pci:v000014EC* + ID_VENDOR_FROM_DATABASE=Agilent Technologies + +pci:v000014ECd00000000* + ID_MODEL_FROM_DATABASE=Aciris Digitizer (malformed ID) + +pci:v000014ED* + ID_VENDOR_FROM_DATABASE=DATAKINETICS Ltd + +pci:v000014EE* + ID_VENDOR_FROM_DATABASE=MASPRO KENKOH Corp + +pci:v000014EF* + ID_VENDOR_FROM_DATABASE=CARRY Computer ENG. CO Ltd + +pci:v000014F0* + ID_VENDOR_FROM_DATABASE=CANON RESEACH CENTRE FRANCE + +pci:v000014F1* + ID_VENDOR_FROM_DATABASE=Conexant Systems, Inc. + +pci:v000014F1d00001002* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001003* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001004* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001005* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001006* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001022* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001023* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001024* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001025* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001026* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001032* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001033* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v000014F1d00001033sv00001033sd00008077* + ID_MODEL_FROM_DATABASE=NEC + +pci:v000014F1d00001033sv0000122Dsd00004027* + ID_MODEL_FROM_DATABASE=Dell Zeus - MDP3880-W(B) Data Fax Modem + +pci:v000014F1d00001033sv0000122Dsd00004030* + ID_MODEL_FROM_DATABASE=Dell Mercury - MDP3880-U(B) Data Fax Modem + +pci:v000014F1d00001033sv0000122Dsd00004034* + ID_MODEL_FROM_DATABASE=Dell Thor - MDP3880-W(U) Data Fax Modem + +pci:v000014F1d00001033sv000013E0sd0000020D* + ID_MODEL_FROM_DATABASE=Dell Copper + +pci:v000014F1d00001033sv000013E0sd0000020E* + ID_MODEL_FROM_DATABASE=Dell Silver + +pci:v000014F1d00001033sv000013E0sd00000261* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001033sv000013E0sd00000290* + ID_MODEL_FROM_DATABASE=Compaq Goldwing + +pci:v000014F1d00001033sv000013E0sd000002A0* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001033sv000013E0sd000002B0* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001033sv000013E0sd000002C0* + ID_MODEL_FROM_DATABASE=Compaq Scooter + +pci:v000014F1d00001033sv000013E0sd000002D0* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001033sv0000144Fsd00001500* + ID_MODEL_FROM_DATABASE=IBM P85-DF (1) + +pci:v000014F1d00001033sv0000144Fsd00001501* + ID_MODEL_FROM_DATABASE=IBM P85-DF (2) + +pci:v000014F1d00001033sv0000144Fsd0000150A* + ID_MODEL_FROM_DATABASE=IBM P85-DF (3) + +pci:v000014F1d00001033sv0000144Fsd0000150B* + ID_MODEL_FROM_DATABASE=IBM P85-DF Low Profile (1) + +pci:v000014F1d00001033sv0000144Fsd00001510* + ID_MODEL_FROM_DATABASE=IBM P85-DF Low Profile (2) + +pci:v000014F1d00001034* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v000014F1d00001035* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00001035sv000010CFsd00001098* + ID_MODEL_FROM_DATABASE=Fujitsu P85-DFSV + +pci:v000014F1d00001036* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00001036sv0000104Dsd00008067* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001036sv0000122Dsd00004029* + ID_MODEL_FROM_DATABASE=MDP3880SP-W + +pci:v000014F1d00001036sv0000122Dsd00004031* + ID_MODEL_FROM_DATABASE=MDP3880SP-U + +pci:v000014F1d00001036sv000013E0sd00000209* + ID_MODEL_FROM_DATABASE=Dell Titanium + +pci:v000014F1d00001036sv000013E0sd0000020A* + ID_MODEL_FROM_DATABASE=Dell Graphite + +pci:v000014F1d00001036sv000013E0sd00000260* + ID_MODEL_FROM_DATABASE=Gateway Red Owl + +pci:v000014F1d00001036sv000013E0sd00000270* + ID_MODEL_FROM_DATABASE=Gateway White Horse + +pci:v000014F1d00001052* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem (Worldwide) + +pci:v000014F1d00001053* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem (Worldwide) + +pci:v000014F1d00001054* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem (Worldwide) + +pci:v000014F1d00001055* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Worldwide) + +pci:v000014F1d00001056* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide) + +pci:v000014F1d00001056sv0000122Dsd00004035* + ID_MODEL_FROM_DATABASE=MDP3900V-W + +pci:v000014F1d00001057* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide) + +pci:v000014F1d00001059* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem (Worldwide) + +pci:v000014F1d00001063* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v000014F1d00001064* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v000014F1d00001065* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00001066* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00001066sv0000122Dsd00004033* + ID_MODEL_FROM_DATABASE=Dell Athena - MDP3900V-U + +pci:v000014F1d00001085* + ID_MODEL_FROM_DATABASE=HCF V90 56k Data/Fax/Voice/Spkp PCI Modem + +pci:v000014F1d000010B6* + ID_MODEL_FROM_DATABASE=CX06834-11 HCF V.92 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00001433* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v000014F1d00001434* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v000014F1d00001435* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00001436* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v000014F1d00001453* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax Modem + +pci:v000014F1d00001453sv000013E0sd00000240* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001453sv000013E0sd00000250* + ID_MODEL_FROM_DATABASE=IBM + +pci:v000014F1d00001453sv0000144Fsd00001502* + ID_MODEL_FROM_DATABASE=IBM P95-DF (1) + +pci:v000014F1d00001453sv0000144Fsd00001503* + ID_MODEL_FROM_DATABASE=IBM P95-DF (2) + +pci:v000014F1d00001454* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice Modem + +pci:v000014F1d00001455* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00001456* + ID_MODEL_FROM_DATABASE=HCF 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00001456sv0000122Dsd00004035* + ID_MODEL_FROM_DATABASE=Dell Europa - MDP3900V-W + +pci:v000014F1d00001456sv0000122Dsd00004302* + ID_MODEL_FROM_DATABASE=Dell MP3930V-W(C) MiniPCI + +pci:v000014F1d00001610* + ID_MODEL_FROM_DATABASE=ADSL AccessRunner PCI Arbitration Device + +pci:v000014F1d00001611* + ID_MODEL_FROM_DATABASE=AccessRunner PCI ADSL Interface Device + +pci:v000014F1d00001620* + ID_MODEL_FROM_DATABASE=AccessRunner V2 PCI ADSL Arbitration Device + +pci:v000014F1d00001621* + ID_MODEL_FROM_DATABASE=AccessRunner V2 PCI ADSL Interface Device + +pci:v000014F1d00001622* + ID_MODEL_FROM_DATABASE=AccessRunner V2 PCI ADSL Yukon WAN Adapter + +pci:v000014F1d00001803* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001803sv00000E11sd00000023* + ID_MODEL_FROM_DATABASE=623-LAN Grizzly + +pci:v000014F1d00001803sv00000E11sd00000043* + ID_MODEL_FROM_DATABASE=623-LAN Yogi + +pci:v000014F1d00001811* + ID_MODEL_FROM_DATABASE=MiniPCI Network Adapter + +pci:v000014F1d00001815* + ID_MODEL_FROM_DATABASE=HCF 56k Modem + +pci:v000014F1d00001815sv00000E11sd00000022* + ID_MODEL_FROM_DATABASE=Grizzly + +pci:v000014F1d00001815sv00000E11sd00000042* + ID_MODEL_FROM_DATABASE=Yogi + +pci:v000014F1d00002003* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem + +pci:v000014F1d00002004* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem + +pci:v000014F1d00002005* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00002006* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00002013* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem + +pci:v000014F1d00002013sv00000E11sd0000B195* + ID_MODEL_FROM_DATABASE=Bear + +pci:v000014F1d00002013sv00000E11sd0000B196* + ID_MODEL_FROM_DATABASE=Seminole 1 + +pci:v000014F1d00002013sv00000E11sd0000B1BE* + ID_MODEL_FROM_DATABASE=Seminole 2 + +pci:v000014F1d00002013sv00001025sd00008013* + ID_MODEL_FROM_DATABASE=Acer + +pci:v000014F1d00002013sv00001033sd0000809D* + ID_MODEL_FROM_DATABASE=NEC + +pci:v000014F1d00002013sv00001033sd000080BC* + ID_MODEL_FROM_DATABASE=NEC + +pci:v000014F1d00002013sv0000155Dsd00006793* + ID_MODEL_FROM_DATABASE=HP + +pci:v000014F1d00002013sv0000155Dsd00008850* + ID_MODEL_FROM_DATABASE=E Machines + +pci:v000014F1d00002014* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem + +pci:v000014F1d00002015* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem + +pci:v000014F1d00002016* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem + +pci:v000014F1d00002043* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem (WorldW SmartDAA) + +pci:v000014F1d00002044* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem (WorldW SmartDAA) + +pci:v000014F1d00002045* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (WorldW SmartDAA) + +pci:v000014F1d00002045sv000014F1sd00002045* + ID_MODEL_FROM_DATABASE=Generic SoftK56 + +pci:v000014F1d00002046* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem (WorldW SmartDAA) + +pci:v000014F1d00002063* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem (SmartDAA) + +pci:v000014F1d00002064* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem (SmartDAA) + +pci:v000014F1d00002065* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (SmartDAA) + +pci:v000014F1d00002066* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem (SmartDAA) + +pci:v000014F1d00002093* + ID_MODEL_FROM_DATABASE=HSF 56k Modem + +pci:v000014F1d00002093sv0000155Dsd00002F07* + ID_MODEL_FROM_DATABASE=Legend + +pci:v000014F1d00002143* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Cell Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002144* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Cell Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002145* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002146* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002163* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Cell Modem (Mob SmartDAA) + +pci:v000014F1d00002164* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Cell Modem (Mob SmartDAA) + +pci:v000014F1d00002165* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob SmartDAA) + +pci:v000014F1d00002166* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob SmartDAA) + +pci:v000014F1d00002343* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax CardBus Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002344* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice CardBus Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002345* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002346* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002363* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax CardBus Modem (Mob SmartDAA) + +pci:v000014F1d00002364* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice CardBus Modem (Mob SmartDAA) + +pci:v000014F1d00002365* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA) + +pci:v000014F1d00002366* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA) + +pci:v000014F1d00002443* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002443sv0000104Dsd00008075* + ID_MODEL_FROM_DATABASE=Modem + +pci:v000014F1d00002443sv0000104Dsd00008083* + ID_MODEL_FROM_DATABASE=Modem + +pci:v000014F1d00002443sv0000104Dsd00008097* + ID_MODEL_FROM_DATABASE=Modem + +pci:v000014F1d00002444* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002445* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002446* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA) + +pci:v000014F1d00002463* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem (Mob SmartDAA) + +pci:v000014F1d00002464* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice Modem (Mob SmartDAA) + +pci:v000014F1d00002465* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob SmartDAA) + +pci:v000014F1d00002466* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax/Voice/Spkp Modem (Mob SmartDAA) + +pci:v000014F1d00002F00* + ID_MODEL_FROM_DATABASE=HSF 56k HSFi Modem + +pci:v000014F1d00002F00sv000013E0sd00008D84* + ID_MODEL_FROM_DATABASE=IBM HSFi V.90 + +pci:v000014F1d00002F00sv000013E0sd00008D85* + ID_MODEL_FROM_DATABASE=Compaq Stinger + +pci:v000014F1d00002F00sv000014F1sd00002004* + ID_MODEL_FROM_DATABASE=Dynalink 56PMi + +pci:v000014F1d00002F02* + ID_MODEL_FROM_DATABASE=HSF 56k HSFi Data/Fax + +pci:v000014F1d00002F11* + ID_MODEL_FROM_DATABASE=HSF 56k HSFi Modem + +pci:v000014F1d00002F20* + ID_MODEL_FROM_DATABASE=HSF 56k Data/Fax Modem + +pci:v000014F1d00002F20sv000014F1sd0000200C* + ID_MODEL_FROM_DATABASE=Soft Data Fax Modem with SmartCP + +pci:v000014F1d00002F20sv000014F1sd0000200F* + ID_MODEL_FROM_DATABASE=Dimension 3000 + +pci:v000014F1d00002F30* + ID_MODEL_FROM_DATABASE=SoftV92 SpeakerPhone SoftRing Modem with SmartSP + +pci:v000014F1d00002F30sv000014F1sd00002014* + ID_MODEL_FROM_DATABASE=Devolo MikroLink 56K Modem PCI + +pci:v000014F1d00002F50* + ID_MODEL_FROM_DATABASE=Conexant SoftK56 Data/Fax Modem + +pci:v000014F1d00005B7A* + ID_MODEL_FROM_DATABASE=CX23418 Single-Chip MPEG-2 Encoder with Integrated Analog Video/Broadcast Audio Decoder + +pci:v000014F1d00005B7Asv00000070sd00007444* + ID_MODEL_FROM_DATABASE=WinTV HVR-1600 + +pci:v000014F1d00005B7Asv0000107Dsd00006F34* + ID_MODEL_FROM_DATABASE=WinFast DVR3100 H + +pci:v000014F1d00005B7Asv00005854sd00003343* + ID_MODEL_FROM_DATABASE=GoTView PCI DVD3 Hybrid + +pci:v000014F1d00008200* + ID_MODEL_FROM_DATABASE=CX25850 + +pci:v000014F1d00008234* + ID_MODEL_FROM_DATABASE=RS8234 ATM SAR Controller [ServiceSAR Plus] + +pci:v000014F1d00008800* + ID_MODEL_FROM_DATABASE=CX23880/1/2/3 PCI Video and Audio Decoder + +pci:v000014F1d00008800sv00000070sd00002801* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV 28xxx (Roslyn) models + +pci:v000014F1d00008800sv00000070sd00003400* + ID_MODEL_FROM_DATABASE=WinTV 34604 + +pci:v000014F1d00008800sv00000070sd00003401* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV 34xxx models + +pci:v000014F1d00008800sv00000070sd00006902* + ID_MODEL_FROM_DATABASE=WinTV HVR-4000-HD + +pci:v000014F1d00008800sv00000070sd00007801* + ID_MODEL_FROM_DATABASE=WinTV HVR-1800 MCE + +pci:v000014F1d00008800sv00000070sd00009001* + ID_MODEL_FROM_DATABASE=Nova-T DVB-T + +pci:v000014F1d00008800sv00000070sd00009200* + ID_MODEL_FROM_DATABASE=Nova-SE2 DVB-S + +pci:v000014F1d00008800sv00000070sd00009202* + ID_MODEL_FROM_DATABASE=Nova-S-Plus DVB-S + +pci:v000014F1d00008800sv00000070sd00009402* + ID_MODEL_FROM_DATABASE=WinTV-HVR1100 DVB-T/Hybrid + +pci:v000014F1d00008800sv00000070sd00009600* + ID_MODEL_FROM_DATABASE=WinTV 88x Video + +pci:v000014F1d00008800sv00000070sd00009802* + ID_MODEL_FROM_DATABASE=WinTV-HVR1100 DVB-T/Hybrid (Low Profile) + +pci:v000014F1d00008800sv00001002sd000000F8* + ID_MODEL_FROM_DATABASE=ATI TV Wonder Pro + +pci:v000014F1d00008800sv00001002sd0000A101* + ID_MODEL_FROM_DATABASE=HDTV Wonder + +pci:v000014F1d00008800sv00001043sd00004823* + ID_MODEL_FROM_DATABASE=ASUS PVR-416 + +pci:v000014F1d00008800sv0000107Dsd00006611* + ID_MODEL_FROM_DATABASE=Winfast TV 2000XP Expert + +pci:v000014F1d00008800sv0000107Dsd00006613* + ID_MODEL_FROM_DATABASE=Leadtek Winfast 2000XP Expert + +pci:v000014F1d00008800sv0000107Dsd00006620* + ID_MODEL_FROM_DATABASE=Leadtek Winfast DV2000 + +pci:v000014F1d00008800sv0000107Dsd0000663C* + ID_MODEL_FROM_DATABASE=Leadtek PVR 2000 + +pci:v000014F1d00008800sv0000107Dsd0000665F* + ID_MODEL_FROM_DATABASE=WinFast DTV1000-T + +pci:v000014F1d00008800sv000010FCsd0000D003* + ID_MODEL_FROM_DATABASE=IODATA GV-VCP3/PCI + +pci:v000014F1d00008800sv000010FCsd0000D035* + ID_MODEL_FROM_DATABASE=IODATA GV/BCTV7E + +pci:v000014F1d00008800sv00001421sd00000334* + ID_MODEL_FROM_DATABASE=Instant TV DVB-T PCI + +pci:v000014F1d00008800sv00001461sd0000000A* + ID_MODEL_FROM_DATABASE=AVerTV 303 (M126) + +pci:v000014F1d00008800sv00001461sd0000000B* + ID_MODEL_FROM_DATABASE=AverTV Studio 303 (M126) + +pci:v000014F1d00008800sv00001461sd00008011* + ID_MODEL_FROM_DATABASE=UltraTV Media Center PCI 550 + +pci:v000014F1d00008800sv00001462sd00008606* + ID_MODEL_FROM_DATABASE=MSI TV-@nywhere Master + +pci:v000014F1d00008800sv000014C7sd00000107* + ID_MODEL_FROM_DATABASE=GDI Black Gold + +pci:v000014F1d00008800sv000014F1sd00000187* + ID_MODEL_FROM_DATABASE=Conexant DVB-T reference design + +pci:v000014F1d00008800sv000014F1sd00000342* + ID_MODEL_FROM_DATABASE=Digital-Logic MICROSPACE Entertainment Center (MEC) + +pci:v000014F1d00008800sv0000153Bsd00001166* + ID_MODEL_FROM_DATABASE=Cinergy 1400 DVB-T + +pci:v000014F1d00008800sv00001540sd00002580* + ID_MODEL_FROM_DATABASE=Provideo PV259 + +pci:v000014F1d00008800sv00001554sd00004811* + ID_MODEL_FROM_DATABASE=PixelView + +pci:v000014F1d00008800sv00001554sd00004813* + ID_MODEL_FROM_DATABASE=Club 3D ZAP1000 MCE Edition + +pci:v000014F1d00008800sv000017DEsd000008A1* + ID_MODEL_FROM_DATABASE=KWorld/VStream XPert DVB-T with cx22702 + +pci:v000014F1d00008800sv000017DEsd000008A6* + ID_MODEL_FROM_DATABASE=KWorld/VStream XPert DVB-T + +pci:v000014F1d00008800sv000017DEsd000008B2* + ID_MODEL_FROM_DATABASE=KWorld DVB-S 100 + +pci:v000014F1d00008800sv000017DEsd0000A8A6* + ID_MODEL_FROM_DATABASE=digitalnow DNTV Live! DVB-T + +pci:v000014F1d00008800sv00001822sd00000025* + ID_MODEL_FROM_DATABASE=digitalnow DNTV Live! DVB-T Pro + +pci:v000014F1d00008800sv0000185Bsd0000E000* + ID_MODEL_FROM_DATABASE=VideoMate X500 + +pci:v000014F1d00008800sv000018ACsd0000D500* + ID_MODEL_FROM_DATABASE=FusionHDTV 5 Gold + +pci:v000014F1d00008800sv000018ACsd0000D810* + ID_MODEL_FROM_DATABASE=FusionHDTV 3 Gold-Q + +pci:v000014F1d00008800sv000018ACsd0000D820* + ID_MODEL_FROM_DATABASE=FusionHDTV 3 Gold-T + +pci:v000014F1d00008800sv000018ACsd0000DB00* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T1 + +pci:v000014F1d00008800sv000018ACsd0000DB11* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Plus + +pci:v000014F1d00008800sv000018ACsd0000DB50* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Dual Digital + +pci:v000014F1d00008800sv00005654sd00002388* + ID_MODEL_FROM_DATABASE=GoTView PCI Hybrid TV Tuner Card + +pci:v000014F1d00008800sv00007063sd00003000* + ID_MODEL_FROM_DATABASE=pcHDTV HD3000 HDTV + +pci:v000014F1d00008800sv00007063sd00005500* + ID_MODEL_FROM_DATABASE=pcHDTV HD-5500 + +pci:v000014F1d00008801* + ID_MODEL_FROM_DATABASE=CX23880/1/2/3 PCI Video and Audio Decoder [Audio Port] + +pci:v000014F1d00008801sv00000070sd00002801* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV 28xxx (Roslyn) models + +pci:v000014F1d00008801sv0000185Bsd0000E000* + ID_MODEL_FROM_DATABASE=VideoMate X500 + +pci:v000014F1d00008801sv00005654sd00002388* + ID_MODEL_FROM_DATABASE=GoTView PCI Hybrid Audio AVStream Device + +pci:v000014F1d00008801sv00007063sd00005500* + ID_MODEL_FROM_DATABASE=pcHDTV HD-5500 + +pci:v000014F1d00008802* + ID_MODEL_FROM_DATABASE=CX23880/1/2/3 PCI Video and Audio Decoder [MPEG Port] + +pci:v000014F1d00008802sv00000070sd00002801* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV 28xxx (Roslyn) models + +pci:v000014F1d00008802sv00000070sd00006902* + ID_MODEL_FROM_DATABASE=WinTV HVR-4000-HD + +pci:v000014F1d00008802sv00000070sd00009002* + ID_MODEL_FROM_DATABASE=Nova-T DVB-T Model 909 + +pci:v000014F1d00008802sv00000070sd00009402* + ID_MODEL_FROM_DATABASE=WinTV-HVR1100 DVB-T/Hybrid + +pci:v000014F1d00008802sv00000070sd00009600* + ID_MODEL_FROM_DATABASE=WinTV 88x MPEG Encoder + +pci:v000014F1d00008802sv00001043sd00004823* + ID_MODEL_FROM_DATABASE=ASUS PVR-416 + +pci:v000014F1d00008802sv0000107Dsd0000663C* + ID_MODEL_FROM_DATABASE=Leadtek PVR 2000 + +pci:v000014F1d00008802sv0000107Dsd0000665F* + ID_MODEL_FROM_DATABASE=WinFast DTV1000-T + +pci:v000014F1d00008802sv000014F1sd00000187* + ID_MODEL_FROM_DATABASE=Conexant DVB-T reference design + +pci:v000014F1d00008802sv000017DEsd000008A1* + ID_MODEL_FROM_DATABASE=XPert DVB-T PCI BDA DVBT 23880 Transport Stream Capture + +pci:v000014F1d00008802sv000017DEsd000008A6* + ID_MODEL_FROM_DATABASE=KWorld/VStream XPert DVB-T + +pci:v000014F1d00008802sv000018ACsd0000D500* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV5 Gold + +pci:v000014F1d00008802sv000018ACsd0000D810* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV3 Gold-Q + +pci:v000014F1d00008802sv000018ACsd0000D820* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV3 Gold-T + +pci:v000014F1d00008802sv000018ACsd0000DB00* + ID_MODEL_FROM_DATABASE=DVICO FusionHDTV DVB-T1 + +pci:v000014F1d00008802sv000018ACsd0000DB10* + ID_MODEL_FROM_DATABASE=DVICO FusionHDTV DVB-T Plus + +pci:v000014F1d00008802sv00005654sd00002388* + ID_MODEL_FROM_DATABASE=GoTView PCI Hybrid TS Capture Device + +pci:v000014F1d00008802sv00007063sd00003000* + ID_MODEL_FROM_DATABASE=pcHDTV HD3000 HDTV + +pci:v000014F1d00008802sv00007063sd00005500* + ID_MODEL_FROM_DATABASE=pcHDTV HD-5500 + +pci:v000014F1d00008804* + ID_MODEL_FROM_DATABASE=CX23880/1/2/3 PCI Video and Audio Decoder [IR Port] + +pci:v000014F1d00008804sv00000070sd00006902* + ID_MODEL_FROM_DATABASE=WinTV HVR-4000-HD + +pci:v000014F1d00008804sv00000070sd00009002* + ID_MODEL_FROM_DATABASE=Nova-T DVB-T Model 909 + +pci:v000014F1d00008804sv00000070sd00009402* + ID_MODEL_FROM_DATABASE=WinTV-HVR1100 DVB-T/Hybrid + +pci:v000014F1d00008804sv00007063sd00005500* + ID_MODEL_FROM_DATABASE=pcHDTV HD-5500 + +pci:v000014F1d00008811* + ID_MODEL_FROM_DATABASE=CX23880/1/2/3 PCI Video and Audio Decoder [Audio Port] + +pci:v000014F1d00008811sv00000070sd00003400* + ID_MODEL_FROM_DATABASE=WinTV 34604 + +pci:v000014F1d00008811sv00000070sd00003401* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV 34xxx models + +pci:v000014F1d00008811sv00000070sd00006902* + ID_MODEL_FROM_DATABASE=WinTV HVR-4000-HD + +pci:v000014F1d00008811sv00000070sd00009402* + ID_MODEL_FROM_DATABASE=WinTV-HVR1100 DVB-T/Hybrid + +pci:v000014F1d00008811sv00000070sd00009600* + ID_MODEL_FROM_DATABASE=WinTV 88x Audio + +pci:v000014F1d00008811sv00001462sd00008606* + ID_MODEL_FROM_DATABASE=MSI TV-@nywhere Master + +pci:v000014F1d00008811sv000018ACsd0000D500* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV5 Gold + +pci:v000014F1d00008811sv000018ACsd0000D810* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV3 Gold-Q + +pci:v000014F1d00008811sv000018ACsd0000D820* + ID_MODEL_FROM_DATABASE=DViCO FusionHDTV3 Gold-T + +pci:v000014F1d00008811sv000018ACsd0000DB00* + ID_MODEL_FROM_DATABASE=DVICO FusionHDTV DVB-T1 + +pci:v000014F1d00008811sv00005654sd00002388* + ID_MODEL_FROM_DATABASE=GoTView PCI Hybrid Audio Capture Device + +pci:v000014F1d00008852* + ID_MODEL_FROM_DATABASE=CX23885 PCI Video and Audio Decoder + +pci:v000014F1d00008852sv00000070sd00008010* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV HVR-1400 ExpressCard + +pci:v000014F1d00008852sv0000107Dsd00006F22* + ID_MODEL_FROM_DATABASE=WinFast PxTV1200 + +pci:v000014F1d00008852sv00001461sd0000C039* + ID_MODEL_FROM_DATABASE=AVerTV Hybrid Express (A577) + +pci:v000014F1d00008852sv0000153Bsd0000117E* + ID_MODEL_FROM_DATABASE=Cinergy T PCIe Dual + +pci:v000014F1d00008852sv000018ACsd0000DB78* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Dual Express + +pci:v000014F1d00008880* + ID_MODEL_FROM_DATABASE=CX23887/8 PCIe Broadcast Audio and Video Decoder with 3D Comb + +pci:v000014F1d00008880sv00000070sd0000C108* + ID_MODEL_FROM_DATABASE=WinTV-HVR-4400-HD model 1278 + +pci:v000014F1d00008880sv00005654sd00002389* + ID_MODEL_FROM_DATABASE=GoTView X5 DVD Hybrid PCI-E + +pci:v000014F1d00008880sv00005654sd00002390* + ID_MODEL_FROM_DATABASE=GoTView X5 3D HYBRID PCI-E + +pci:v000014F2* + ID_VENDOR_FROM_DATABASE=MOBILITY Electronics + +pci:v000014F2d00000120* + ID_MODEL_FROM_DATABASE=EV1000 bridge + +pci:v000014F2d00000121* + ID_MODEL_FROM_DATABASE=EV1000 Parallel port + +pci:v000014F2d00000122* + ID_MODEL_FROM_DATABASE=EV1000 Serial port + +pci:v000014F2d00000123* + ID_MODEL_FROM_DATABASE=EV1000 Keyboard controller + +pci:v000014F2d00000124* + ID_MODEL_FROM_DATABASE=EV1000 Mouse controller + +pci:v000014F3* + ID_VENDOR_FROM_DATABASE=BroadLogic + +pci:v000014F3d00002030* + ID_MODEL_FROM_DATABASE=2030 DVB-S Satellite Receiver + +pci:v000014F3d00002035* + ID_MODEL_FROM_DATABASE=2035 DVB-S Satellite Receiver + +pci:v000014F3d00002050* + ID_MODEL_FROM_DATABASE=2050 DVB-T Terrestrial (Cable) Receiver + +pci:v000014F3d00002060* + ID_MODEL_FROM_DATABASE=2060 ATSC Terrestrial (Cable) Receiver + +pci:v000014F4* + ID_VENDOR_FROM_DATABASE=TOKYO Electronic Industry CO Ltd + +pci:v000014F5* + ID_VENDOR_FROM_DATABASE=SOPAC Ltd + +pci:v000014F6* + ID_VENDOR_FROM_DATABASE=COYOTE Technologies LLC + +pci:v000014F7* + ID_VENDOR_FROM_DATABASE=WOLF Technology Inc + +pci:v000014F8* + ID_VENDOR_FROM_DATABASE=AUDIOCODES Inc + +pci:v000014F8d00002077* + ID_MODEL_FROM_DATABASE=TP-240 dual span E1 VoIP PCI card + +pci:v000014F9* + ID_VENDOR_FROM_DATABASE=AG COMMUNICATIONS + +pci:v000014FA* + ID_VENDOR_FROM_DATABASE=WANDEL & GOLTERMANN + +pci:v000014FB* + ID_VENDOR_FROM_DATABASE=TRANSAS MARINE (UK) Ltd + +pci:v000014FC* + ID_VENDOR_FROM_DATABASE=Quadrics Ltd + +pci:v000014FCd00000000* + ID_MODEL_FROM_DATABASE=QsNet Elan3 Network Adapter + +pci:v000014FCd00000001* + ID_MODEL_FROM_DATABASE=QsNetII Elan4 Network Adapter + +pci:v000014FCd00000002* + ID_MODEL_FROM_DATABASE=QsNetIII Elan5 Network Adapter + +pci:v000014FD* + ID_VENDOR_FROM_DATABASE=JAPAN Computer Industry Inc + +pci:v000014FE* + ID_VENDOR_FROM_DATABASE=ARCHTEK TELECOM Corp + +pci:v000014FF* + ID_VENDOR_FROM_DATABASE=TWINHEAD INTERNATIONAL Corp + +pci:v00001500* + ID_VENDOR_FROM_DATABASE=DELTA Electronics, Inc + +pci:v00001500d00001360* + ID_MODEL_FROM_DATABASE=RTL81xx RealTek Ethernet + +pci:v00001501* + ID_VENDOR_FROM_DATABASE=BANKSOFT CANADA Ltd + +pci:v00001502* + ID_VENDOR_FROM_DATABASE=MITSUBISHI ELECTRIC LOGISTICS SUPPORT Co Ltd + +pci:v00001503* + ID_VENDOR_FROM_DATABASE=KAWASAKI LSI USA Inc + +pci:v00001504* + ID_VENDOR_FROM_DATABASE=KAISER Electronics + +pci:v00001505* + ID_VENDOR_FROM_DATABASE=ITA INGENIEURBURO FUR TESTAUFGABEN GmbH + +pci:v00001506* + ID_VENDOR_FROM_DATABASE=CHAMELEON Systems Inc + +pci:v00001507* + ID_VENDOR_FROM_DATABASE=Motorola ?? / HTEC + +pci:v00001507d00000001* + ID_MODEL_FROM_DATABASE=MPC105 [Eagle] + +pci:v00001507d00000002* + ID_MODEL_FROM_DATABASE=MPC106 [Grackle] + +pci:v00001507d00000003* + ID_MODEL_FROM_DATABASE=MPC8240 [Kahlua] + +pci:v00001507d00000100* + ID_MODEL_FROM_DATABASE=MC145575 [HFC-PCI] + +pci:v00001507d00000431* + ID_MODEL_FROM_DATABASE=KTI829c 100VG + +pci:v00001507d00004801* + ID_MODEL_FROM_DATABASE=Raven + +pci:v00001507d00004802* + ID_MODEL_FROM_DATABASE=Falcon + +pci:v00001507d00004803* + ID_MODEL_FROM_DATABASE=Hawk + +pci:v00001507d00004806* + ID_MODEL_FROM_DATABASE=CPX8216 + +pci:v00001508* + ID_VENDOR_FROM_DATABASE=HONDA CONNECTORS/MHOTRONICS Inc + +pci:v00001509* + ID_VENDOR_FROM_DATABASE=FIRST INTERNATIONAL Computer Inc + +pci:v0000150A* + ID_VENDOR_FROM_DATABASE=FORVUS RESEARCH Inc + +pci:v0000150B* + ID_VENDOR_FROM_DATABASE=YAMASHITA Systems Corp + +pci:v0000150C* + ID_VENDOR_FROM_DATABASE=KYOPAL CO Ltd + +pci:v0000150D* + ID_VENDOR_FROM_DATABASE=WARPSPPED Inc + +pci:v0000150E* + ID_VENDOR_FROM_DATABASE=C-PORT Corp + +pci:v0000150F* + ID_VENDOR_FROM_DATABASE=INTEC GmbH + +pci:v00001510* + ID_VENDOR_FROM_DATABASE=BEHAVIOR TECH Computer Corp + +pci:v00001511* + ID_VENDOR_FROM_DATABASE=CENTILLIUM Technology Corp + +pci:v00001512* + ID_VENDOR_FROM_DATABASE=ROSUN Technologies Inc + +pci:v00001513* + ID_VENDOR_FROM_DATABASE=Raychem + +pci:v00001514* + ID_VENDOR_FROM_DATABASE=TFL LAN Inc + +pci:v00001515* + ID_VENDOR_FROM_DATABASE=Advent design + +pci:v00001516* + ID_VENDOR_FROM_DATABASE=MYSON Technology Inc + +pci:v00001516d00000800* + ID_MODEL_FROM_DATABASE=MTD-8xx 100/10M Ethernet PCI Adapter + +pci:v00001516d00000803* + ID_MODEL_FROM_DATABASE=SURECOM EP-320X-S 100/10M Ethernet PCI Adapter + +pci:v00001516d00000803sv00001320sd000010BD* + ID_MODEL_FROM_DATABASE=SURECOM EP-320X-S 100/10M Ethernet PCI Adapter + +pci:v00001516d00000891* + ID_MODEL_FROM_DATABASE=MTD-8xx 100/10M Ethernet PCI Adapter + +pci:v00001517* + ID_VENDOR_FROM_DATABASE=ECHOTEK Corp + +pci:v00001518* + ID_VENDOR_FROM_DATABASE=Kontron Modular Computers GmbH + +pci:v00001519* + ID_VENDOR_FROM_DATABASE=TELEFON AKTIEBOLAGET LM Ericsson + +pci:v0000151A* + ID_VENDOR_FROM_DATABASE=Globetek + +pci:v0000151Ad00001002* + ID_MODEL_FROM_DATABASE=PCI-1002 + +pci:v0000151Ad00001004* + ID_MODEL_FROM_DATABASE=PCI-1004 + +pci:v0000151Ad00001008* + ID_MODEL_FROM_DATABASE=PCI-1008 + +pci:v0000151B* + ID_VENDOR_FROM_DATABASE=COMBOX Ltd + +pci:v0000151C* + ID_VENDOR_FROM_DATABASE=DIGITAL AUDIO LABS Inc + +pci:v0000151Cd00000003* + ID_MODEL_FROM_DATABASE=Prodif T 2496 + +pci:v0000151Cd00004000* + ID_MODEL_FROM_DATABASE=Prodif 88 + +pci:v0000151D* + ID_VENDOR_FROM_DATABASE=Fujitsu Computer Products Of America + +pci:v0000151E* + ID_VENDOR_FROM_DATABASE=MATRIX Corp + +pci:v0000151F* + ID_VENDOR_FROM_DATABASE=TOPIC SEMICONDUCTOR Corp + +pci:v0000151Fd00000000* + ID_MODEL_FROM_DATABASE=TP560 Data/Fax/Voice 56k modem + +pci:v00001520* + ID_VENDOR_FROM_DATABASE=CHAPLET System Inc + +pci:v00001521* + ID_VENDOR_FROM_DATABASE=BELL Corp + +pci:v00001522* + ID_VENDOR_FROM_DATABASE=MainPine Ltd + +pci:v00001522d00000100* + ID_MODEL_FROM_DATABASE=PCI <-> IOBus Bridge + +pci:v00001522d00000100sv00001522sd00000200* + ID_MODEL_FROM_DATABASE=RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000300* + ID_MODEL_FROM_DATABASE=RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000400* + ID_MODEL_FROM_DATABASE=RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000500* + ID_MODEL_FROM_DATABASE=RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000600* + ID_MODEL_FROM_DATABASE=RockForce+ 2 Port V.90 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000700* + ID_MODEL_FROM_DATABASE=RockForce+ 4 Port V.90 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000800* + ID_MODEL_FROM_DATABASE=RockForceOCTO+ 8 Port V.92/V.44 Data/Fax/Voice Modem + +pci:v00001522d00000100sv00001522sd00000C00* + ID_MODEL_FROM_DATABASE=RockForceDUO+ 2 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem + +pci:v00001522d00000100sv00001522sd00000D00* + ID_MODEL_FROM_DATABASE=RockForceQUATRO+ 4 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem + +pci:v00001522d00000100sv00001522sd00001D00* + ID_MODEL_FROM_DATABASE=RockForceOCTO+ 8 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem + +pci:v00001522d00000100sv00001522sd00002000* + ID_MODEL_FROM_DATABASE=RockForceD1 1 Port V.90 Data Modem + +pci:v00001522d00000100sv00001522sd00002100* + ID_MODEL_FROM_DATABASE=RockForceF1 1 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00002200* + ID_MODEL_FROM_DATABASE=RockForceD2 2 Port V.90 Data Modem + +pci:v00001522d00000100sv00001522sd00002300* + ID_MODEL_FROM_DATABASE=RockForceF2 2 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00002400* + ID_MODEL_FROM_DATABASE=RockForceD4 4 Port V.90 Data Modem + +pci:v00001522d00000100sv00001522sd00002500* + ID_MODEL_FROM_DATABASE=RockForceF4 4 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00002600* + ID_MODEL_FROM_DATABASE=RockForceD8 8 Port V.90 Data Modem + +pci:v00001522d00000100sv00001522sd00002700* + ID_MODEL_FROM_DATABASE=RockForceF8 8 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00003000* + ID_MODEL_FROM_DATABASE=IQ Express D1 - 1 Port V.92 Data Modem + +pci:v00001522d00000100sv00001522sd00003100* + ID_MODEL_FROM_DATABASE=IQ Express F1 - 1 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00003200* + ID_MODEL_FROM_DATABASE=IQ Express D2 - 2 Port V.92 Data Modem + +pci:v00001522d00000100sv00001522sd00003300* + ID_MODEL_FROM_DATABASE=IQ Express F2 - 2 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00003400* + ID_MODEL_FROM_DATABASE=IQ Express D4 - 4 Port V.92 Data Modem + +pci:v00001522d00000100sv00001522sd00003500* + ID_MODEL_FROM_DATABASE=IQ Express F4 - 4 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00000100sv00001522sd00003C00* + ID_MODEL_FROM_DATABASE=IQ Express D8 - 8 Port V.92 Data Modem + +pci:v00001522d00000100sv00001522sd00003D00* + ID_MODEL_FROM_DATABASE=IQ Express F8 - 8 Port V.34 Super-G3 Fax Modem + +pci:v00001522d00004000* + ID_MODEL_FROM_DATABASE=PCI Express UART + +pci:v00001522d00004000sv00001522sd00004001* + ID_MODEL_FROM_DATABASE=IQ Express 1-port V.34 Super-G3 Fax + +pci:v00001522d00004000sv00001522sd00004002* + ID_MODEL_FROM_DATABASE=IQ Express 2-port V.34 Super-G3 Fax + +pci:v00001522d00004000sv00001522sd00004004* + ID_MODEL_FROM_DATABASE=IQ Express 4-port V.34 Super-G3 Fax + +pci:v00001522d00004000sv00001522sd00004008* + ID_MODEL_FROM_DATABASE=IQ Express 8-port V.34 Super-G3 Fax + +pci:v00001522d00004000sv00001522sd00004100* + ID_MODEL_FROM_DATABASE=IQ Express SideBand + +pci:v00001523* + ID_VENDOR_FROM_DATABASE=MUSIC Semiconductors + +pci:v00001524* + ID_VENDOR_FROM_DATABASE=ENE Technology Inc + +pci:v00001524d00000510* + ID_MODEL_FROM_DATABASE=CB710 Memory Card Reader Controller + +pci:v00001524d00000510sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00001524d00000520* + ID_MODEL_FROM_DATABASE=FLASH memory: ENE Technology Inc: + +pci:v00001524d00000530* + ID_MODEL_FROM_DATABASE=ENE PCI Memory Stick Card Reader Controller + +pci:v00001524d00000550* + ID_MODEL_FROM_DATABASE=ENE PCI Secure Digital Card Reader Controller + +pci:v00001524d00000551* + ID_MODEL_FROM_DATABASE=SD/MMC Card Reader Controller + +pci:v00001524d00000610* + ID_MODEL_FROM_DATABASE=PCI Smart Card Reader Controller + +pci:v00001524d00000720* + ID_MODEL_FROM_DATABASE=Memory Stick Card Reader Controller + +pci:v00001524d00000730* + ID_MODEL_FROM_DATABASE=ENE PCI Memory Stick Card Reader Controller + +pci:v00001524d00000750* + ID_MODEL_FROM_DATABASE=ENE PCI SmartMedia / xD Card Reader Controller + +pci:v00001524d00000751* + ID_MODEL_FROM_DATABASE=ENE PCI Secure Digital / MMC Card Reader Controller + +pci:v00001524d00001211* + ID_MODEL_FROM_DATABASE=CB1211 Cardbus Controller + +pci:v00001524d00001225* + ID_MODEL_FROM_DATABASE=CB1225 Cardbus Controller + +pci:v00001524d00001410* + ID_MODEL_FROM_DATABASE=CB1410 Cardbus Controller + +pci:v00001524d00001410sv00001025sd0000003C* + ID_MODEL_FROM_DATABASE=CL50 motherboard + +pci:v00001524d00001410sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00001524d00001411* + ID_MODEL_FROM_DATABASE=CB-710/2/4 Cardbus Controller + +pci:v00001524d00001411sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00001524d00001412* + ID_MODEL_FROM_DATABASE=CB-712/4 Cardbus Controller + +pci:v00001524d00001420* + ID_MODEL_FROM_DATABASE=CB1420 Cardbus Controller + +pci:v00001524d00001421* + ID_MODEL_FROM_DATABASE=CB-720/2/4 Cardbus Controller + +pci:v00001524d00001422* + ID_MODEL_FROM_DATABASE=CB-722/4 Cardbus Controller + +pci:v00001525* + ID_VENDOR_FROM_DATABASE=IMPACT Technologies + +pci:v00001526* + ID_VENDOR_FROM_DATABASE=ISS, Inc + +pci:v00001527* + ID_VENDOR_FROM_DATABASE=SOLECTRON + +pci:v00001528* + ID_VENDOR_FROM_DATABASE=ACKSYS + +pci:v00001529* + ID_VENDOR_FROM_DATABASE=AMERICAN MICROSystems Inc + +pci:v0000152A* + ID_VENDOR_FROM_DATABASE=QUICKTURN DESIGN Systems + +pci:v0000152B* + ID_VENDOR_FROM_DATABASE=FLYTECH Technology CO Ltd + +pci:v0000152C* + ID_VENDOR_FROM_DATABASE=MACRAIGOR Systems LLC + +pci:v0000152D* + ID_VENDOR_FROM_DATABASE=QUANTA Computer Inc + +pci:v0000152E* + ID_VENDOR_FROM_DATABASE=MELEC Inc + +pci:v0000152F* + ID_VENDOR_FROM_DATABASE=PHILIPS - CRYPTO + +pci:v00001530* + ID_VENDOR_FROM_DATABASE=ACQIS Technology Inc + +pci:v00001531* + ID_VENDOR_FROM_DATABASE=CHRYON Corp + +pci:v00001532* + ID_VENDOR_FROM_DATABASE=ECHELON Corp + +pci:v00001532d00000020* + ID_MODEL_FROM_DATABASE=LonWorks PCLTA-20 PCI LonTalk Adapter + +pci:v00001533* + ID_VENDOR_FROM_DATABASE=BALTIMORE + +pci:v00001534* + ID_VENDOR_FROM_DATABASE=ROAD Corp + +pci:v00001535* + ID_VENDOR_FROM_DATABASE=EVERGREEN Technologies Inc + +pci:v00001536* + ID_VENDOR_FROM_DATABASE=ACTIS Computer + +pci:v00001537* + ID_VENDOR_FROM_DATABASE=DATALEX COMMUNCATIONS + +pci:v00001538* + ID_VENDOR_FROM_DATABASE=ARALION Inc + +pci:v00001538d00000303* + ID_MODEL_FROM_DATABASE=ARS106S Ultra ATA 133/100/66 Host Controller + +pci:v00001539* + ID_VENDOR_FROM_DATABASE=ATELIER INFORMATIQUES et ELECTRONIQUE ETUDES S.A. + +pci:v0000153A* + ID_VENDOR_FROM_DATABASE=ONO SOKKI + +pci:v0000153B* + ID_VENDOR_FROM_DATABASE=TERRATEC Electronic GmbH + +pci:v0000153Bd00001144* + ID_MODEL_FROM_DATABASE=Aureon 5.1 + +pci:v0000153Bd00001147* + ID_MODEL_FROM_DATABASE=Aureon 5.1 Sky + +pci:v0000153Bd00001158* + ID_MODEL_FROM_DATABASE=Philips Semiconductors SAA7134 (rev 01) [Terratec Cinergy 600 TV] + +pci:v0000153C* + ID_VENDOR_FROM_DATABASE=ANTAL Electronic + +pci:v0000153D* + ID_VENDOR_FROM_DATABASE=FILANET Corp + +pci:v0000153E* + ID_VENDOR_FROM_DATABASE=TECHWELL Inc + +pci:v0000153F* + ID_VENDOR_FROM_DATABASE=MIPS Technologies, Inc. + +pci:v0000153Fd00000001* + ID_MODEL_FROM_DATABASE=SOC-it 101 System Controller + +pci:v00001540* + ID_VENDOR_FROM_DATABASE=PROVIDEO MULTIMEDIA Co Ltd + +pci:v00001541* + ID_VENDOR_FROM_DATABASE=MACHONE Communications + +pci:v00001542* + ID_VENDOR_FROM_DATABASE=Concurrent Computer Corporation + +pci:v00001542d00009260* + ID_MODEL_FROM_DATABASE=RCIM-II Real-Time Clock & Interrupt Module + +pci:v00001543* + ID_VENDOR_FROM_DATABASE=SILICON Laboratories + +pci:v00001543d00003052* + ID_MODEL_FROM_DATABASE=Intel 537 [Winmodem] + +pci:v00001543d00004C22* + ID_MODEL_FROM_DATABASE=Si3036 MC'97 DAA + +pci:v00001544* + ID_VENDOR_FROM_DATABASE=DCM DATA Systems + +pci:v00001545* + ID_VENDOR_FROM_DATABASE=VISIONTEK + +pci:v00001546* + ID_VENDOR_FROM_DATABASE=IOI Technology Corp + +pci:v00001547* + ID_VENDOR_FROM_DATABASE=MITUTOYO Corp + +pci:v00001548* + ID_VENDOR_FROM_DATABASE=JET PROPULSION Laboratory + +pci:v00001549* + ID_VENDOR_FROM_DATABASE=INTERCONNECT Systems Solutions + +pci:v0000154A* + ID_VENDOR_FROM_DATABASE=MAX Technologies Inc + +pci:v0000154B* + ID_VENDOR_FROM_DATABASE=COMPUTEX Co Ltd + +pci:v0000154C* + ID_VENDOR_FROM_DATABASE=VISUAL Technology Inc + +pci:v0000154D* + ID_VENDOR_FROM_DATABASE=PAN INTERNATIONAL Industrial Corp + +pci:v0000154E* + ID_VENDOR_FROM_DATABASE=SERVOTEST Ltd + +pci:v0000154F* + ID_VENDOR_FROM_DATABASE=STRATABEAM Technology + +pci:v00001550* + ID_VENDOR_FROM_DATABASE=OPEN NETWORK Co Ltd + +pci:v00001551* + ID_VENDOR_FROM_DATABASE=SMART Electronic DEVELOPMENT GmBH + +pci:v00001552* + ID_VENDOR_FROM_DATABASE=RACAL AIRTECH Ltd + +pci:v00001553* + ID_VENDOR_FROM_DATABASE=CHICONY Electronics Co Ltd + +pci:v00001554* + ID_VENDOR_FROM_DATABASE=PROLINK Microsystems Corp + +pci:v00001555* + ID_VENDOR_FROM_DATABASE=GESYTEC GmBH + +pci:v00001556* + ID_VENDOR_FROM_DATABASE=PLDA + +pci:v00001556d00001100* + ID_MODEL_FROM_DATABASE=PCI Express Core Reference Design + +pci:v00001556d0000110F* + ID_MODEL_FROM_DATABASE=PCI Express Core Reference Design Virtual Function + +pci:v00001557* + ID_VENDOR_FROM_DATABASE=MEDIASTAR Co Ltd + +pci:v00001558* + ID_VENDOR_FROM_DATABASE=CLEVO/KAPOK Computer + +pci:v00001559* + ID_VENDOR_FROM_DATABASE=SI LOGIC Ltd + +pci:v0000155A* + ID_VENDOR_FROM_DATABASE=INNOMEDIA Inc + +pci:v0000155B* + ID_VENDOR_FROM_DATABASE=PROTAC INTERNATIONAL Corp + +pci:v0000155C* + ID_VENDOR_FROM_DATABASE=Cemax-Icon Inc + +pci:v0000155D* + ID_VENDOR_FROM_DATABASE=Mac System Co Ltd + +pci:v0000155E* + ID_VENDOR_FROM_DATABASE=LP Elektronik GmbH + +pci:v0000155F* + ID_VENDOR_FROM_DATABASE=Perle Systems Ltd + +pci:v00001560* + ID_VENDOR_FROM_DATABASE=Terayon Communications Systems + +pci:v00001561* + ID_VENDOR_FROM_DATABASE=Viewgraphics Inc + +pci:v00001562* + ID_VENDOR_FROM_DATABASE=Symbol Technologies + +pci:v00001563* + ID_VENDOR_FROM_DATABASE=A-Trend Technology Co Ltd + +pci:v00001564* + ID_VENDOR_FROM_DATABASE=Yamakatsu Electronics Industry Co Ltd + +pci:v00001565* + ID_VENDOR_FROM_DATABASE=Biostar Microtech Int'l Corp + +pci:v00001566* + ID_VENDOR_FROM_DATABASE=Ardent Technologies Inc + +pci:v00001567* + ID_VENDOR_FROM_DATABASE=Jungsoft + +pci:v00001568* + ID_VENDOR_FROM_DATABASE=DDK Electronics Inc + +pci:v00001569* + ID_VENDOR_FROM_DATABASE=Palit Microsystems Inc. + +pci:v0000156A* + ID_VENDOR_FROM_DATABASE=Avtec Systems + +pci:v0000156B* + ID_VENDOR_FROM_DATABASE=2wire Inc + +pci:v0000156C* + ID_VENDOR_FROM_DATABASE=Vidac Electronics GmbH + +pci:v0000156D* + ID_VENDOR_FROM_DATABASE=Alpha-Top Corp + +pci:v0000156E* + ID_VENDOR_FROM_DATABASE=Alfa Inc + +pci:v0000156F* + ID_VENDOR_FROM_DATABASE=M-Systems Flash Disk Pioneers Ltd + +pci:v00001570* + ID_VENDOR_FROM_DATABASE=Lecroy Corp + +pci:v00001571* + ID_VENDOR_FROM_DATABASE=Contemporary Controls + +pci:v00001571d0000A001* + ID_MODEL_FROM_DATABASE=CCSI PCI20-485 ARCnet + +pci:v00001571d0000A002* + ID_MODEL_FROM_DATABASE=CCSI PCI20-485D ARCnet + +pci:v00001571d0000A003* + ID_MODEL_FROM_DATABASE=CCSI PCI20-485X ARCnet + +pci:v00001571d0000A004* + ID_MODEL_FROM_DATABASE=CCSI PCI20-CXB ARCnet + +pci:v00001571d0000A005* + ID_MODEL_FROM_DATABASE=CCSI PCI20-CXS ARCnet + +pci:v00001571d0000A006* + ID_MODEL_FROM_DATABASE=CCSI PCI20-FOG-SMA ARCnet + +pci:v00001571d0000A007* + ID_MODEL_FROM_DATABASE=CCSI PCI20-FOG-ST ARCnet + +pci:v00001571d0000A008* + ID_MODEL_FROM_DATABASE=CCSI PCI20-TB5 ARCnet + +pci:v00001571d0000A009* + ID_MODEL_FROM_DATABASE=CCSI PCI20-5-485 5Mbit ARCnet + +pci:v00001571d0000A00A* + ID_MODEL_FROM_DATABASE=CCSI PCI20-5-485D 5Mbit ARCnet + +pci:v00001571d0000A00B* + ID_MODEL_FROM_DATABASE=CCSI PCI20-5-485X 5Mbit ARCnet + +pci:v00001571d0000A00C* + ID_MODEL_FROM_DATABASE=CCSI PCI20-5-FOG-ST 5Mbit ARCnet + +pci:v00001571d0000A00D* + ID_MODEL_FROM_DATABASE=CCSI PCI20-5-FOG-SMA 5Mbit ARCnet + +pci:v00001571d0000A201* + ID_MODEL_FROM_DATABASE=CCSI PCI22-485 10Mbit ARCnet + +pci:v00001571d0000A202* + ID_MODEL_FROM_DATABASE=CCSI PCI22-485D 10Mbit ARCnet + +pci:v00001571d0000A203* + ID_MODEL_FROM_DATABASE=CCSI PCI22-485X 10Mbit ARCnet + +pci:v00001571d0000A204* + ID_MODEL_FROM_DATABASE=CCSI PCI22-CHB 10Mbit ARCnet + +pci:v00001571d0000A205* + ID_MODEL_FROM_DATABASE=CCSI PCI22-FOG_ST 10Mbit ARCnet + +pci:v00001571d0000A206* + ID_MODEL_FROM_DATABASE=CCSI PCI22-THB 10Mbit ARCnet + +pci:v00001572* + ID_VENDOR_FROM_DATABASE=Otis Elevator Company + +pci:v00001573* + ID_VENDOR_FROM_DATABASE=Lattice - Vantis + +pci:v00001574* + ID_VENDOR_FROM_DATABASE=Fairchild Semiconductor + +pci:v00001575* + ID_VENDOR_FROM_DATABASE=Voltaire Advanced Data Security Ltd + +pci:v00001576* + ID_VENDOR_FROM_DATABASE=Viewcast COM + +pci:v00001578* + ID_VENDOR_FROM_DATABASE=HITT + +pci:v00001578d00004D34* + ID_MODEL_FROM_DATABASE=VPMK4 [Video Processor Mk IV] + +pci:v00001578d00005615* + ID_MODEL_FROM_DATABASE=VPMK3 [Video Processor Mk III] + +pci:v00001579* + ID_VENDOR_FROM_DATABASE=Dual Technology Corp + +pci:v0000157A* + ID_VENDOR_FROM_DATABASE=Japan Elecronics Ind Inc + +pci:v0000157B* + ID_VENDOR_FROM_DATABASE=Star Multimedia Corp + +pci:v0000157C* + ID_VENDOR_FROM_DATABASE=Eurosoft (UK) + +pci:v0000157Cd00008001* + ID_MODEL_FROM_DATABASE=Fix2000 PCI Y2K Compliance Card + +pci:v0000157D* + ID_VENDOR_FROM_DATABASE=Gemflex Networks + +pci:v0000157E* + ID_VENDOR_FROM_DATABASE=Transition Networks + +pci:v0000157F* + ID_VENDOR_FROM_DATABASE=PX Instruments Technology Ltd + +pci:v00001580* + ID_VENDOR_FROM_DATABASE=Primex Aerospace Co + +pci:v00001581* + ID_VENDOR_FROM_DATABASE=SEH Computertechnik GmbH + +pci:v00001582* + ID_VENDOR_FROM_DATABASE=Cytec Corp + +pci:v00001583* + ID_VENDOR_FROM_DATABASE=Inet Technologies Inc + +pci:v00001584* + ID_VENDOR_FROM_DATABASE=Uniwill Computer Corp + +pci:v00001585* + ID_VENDOR_FROM_DATABASE=Logitron + +pci:v00001586* + ID_VENDOR_FROM_DATABASE=Lancast Inc + +pci:v00001587* + ID_VENDOR_FROM_DATABASE=Konica Corp + +pci:v00001588* + ID_VENDOR_FROM_DATABASE=Solidum Systems Corp + +pci:v00001589* + ID_VENDOR_FROM_DATABASE=Atlantek Microsystems Pty Ltd + +pci:v00001589d00000008* + ID_MODEL_FROM_DATABASE=Leutron Vision PicPortExpress CL + +pci:v00001589d00000009* + ID_MODEL_FROM_DATABASE=Leutron Vision PicPortExpress CL Stereo + +pci:v0000158A* + ID_VENDOR_FROM_DATABASE=Digalog Systems Inc + +pci:v0000158B* + ID_VENDOR_FROM_DATABASE=Allied Data Technologies + +pci:v0000158C* + ID_VENDOR_FROM_DATABASE=Hitachi Semiconductor & Devices Sales Co Ltd + +pci:v0000158D* + ID_VENDOR_FROM_DATABASE=Point Multimedia Systems + +pci:v0000158E* + ID_VENDOR_FROM_DATABASE=Lara Technology Inc + +pci:v0000158F* + ID_VENDOR_FROM_DATABASE=Ditect Coop + +pci:v00001590* + ID_VENDOR_FROM_DATABASE=Hewlett-Packard Company + +pci:v00001590d00000001* + ID_MODEL_FROM_DATABASE=Eagle Cluster Manager + +pci:v00001590d00000002* + ID_MODEL_FROM_DATABASE=Osprey Cluster Manager + +pci:v00001590d00000003* + ID_MODEL_FROM_DATABASE=Harrier Cluster Manager + +pci:v00001590d0000A01D* + ID_MODEL_FROM_DATABASE=FC044X Fibre Channel HBA + +pci:v00001591* + ID_VENDOR_FROM_DATABASE=ARN + +pci:v00001592* + ID_VENDOR_FROM_DATABASE=Syba Tech Ltd + +pci:v00001592d00000781* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d00000782* + ID_MODEL_FROM_DATABASE=Parallel Port Card 2xEPP + +pci:v00001592d00000783* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d00000785* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d00000786* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d00000787* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d00000788* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001592d0000078A* + ID_MODEL_FROM_DATABASE=Multi-IO Card + +pci:v00001593* + ID_VENDOR_FROM_DATABASE=Bops Inc + +pci:v00001594* + ID_VENDOR_FROM_DATABASE=Netgame Ltd + +pci:v00001595* + ID_VENDOR_FROM_DATABASE=Diva Systems Corp + +pci:v00001596* + ID_VENDOR_FROM_DATABASE=Folsom Research Inc + +pci:v00001597* + ID_VENDOR_FROM_DATABASE=Memec Design Services + +pci:v00001598* + ID_VENDOR_FROM_DATABASE=Granite Microsystems + +pci:v00001599* + ID_VENDOR_FROM_DATABASE=Delta Electronics Inc + +pci:v0000159A* + ID_VENDOR_FROM_DATABASE=General Instrument + +pci:v0000159B* + ID_VENDOR_FROM_DATABASE=Faraday Technology Corp + +pci:v0000159C* + ID_VENDOR_FROM_DATABASE=Stratus Computer Systems + +pci:v0000159D* + ID_VENDOR_FROM_DATABASE=Ningbo Harrison Electronics Co Ltd + +pci:v0000159E* + ID_VENDOR_FROM_DATABASE=A-Max Technology Co Ltd + +pci:v0000159F* + ID_VENDOR_FROM_DATABASE=Galea Network Security + +pci:v000015A0* + ID_VENDOR_FROM_DATABASE=Compumaster SRL + +pci:v000015A1* + ID_VENDOR_FROM_DATABASE=Geocast Network Systems + +pci:v000015A2* + ID_VENDOR_FROM_DATABASE=Catalyst Enterprises Inc + +pci:v000015A2d00000001* + ID_MODEL_FROM_DATABASE=TA700 PCI Bus Analyzer/Exerciser + +pci:v000015A3* + ID_VENDOR_FROM_DATABASE=Italtel + +pci:v000015A4* + ID_VENDOR_FROM_DATABASE=X-Net OY + +pci:v000015A5* + ID_VENDOR_FROM_DATABASE=Toyota Macs Inc + +pci:v000015A6* + ID_VENDOR_FROM_DATABASE=Sunlight Ultrasound Technologies Ltd + +pci:v000015A7* + ID_VENDOR_FROM_DATABASE=SSE Telecom Inc + +pci:v000015A8* + ID_VENDOR_FROM_DATABASE=Shanghai Communications Technologies Center + +pci:v000015AA* + ID_VENDOR_FROM_DATABASE=Moreton Bay + +pci:v000015AB* + ID_VENDOR_FROM_DATABASE=Bluesteel Networks Inc + +pci:v000015AC* + ID_VENDOR_FROM_DATABASE=North Atlantic Instruments + +pci:v000015AD* + ID_VENDOR_FROM_DATABASE=VMware + +pci:v000015ADd00000405* + ID_MODEL_FROM_DATABASE=SVGA II Adapter + +pci:v000015ADd00000710* + ID_MODEL_FROM_DATABASE=SVGA Adapter + +pci:v000015ADd00000720* + ID_MODEL_FROM_DATABASE=VMXNET Ethernet Controller + +pci:v000015ADd00000740* + ID_MODEL_FROM_DATABASE=Virtual Machine Communication Interface + +pci:v000015ADd00000770* + ID_MODEL_FROM_DATABASE=USB2 EHCI Controller + +pci:v000015ADd00000774* + ID_MODEL_FROM_DATABASE=USB1.1 UHCI Controller + +pci:v000015ADd00000778* + ID_MODEL_FROM_DATABASE=USB3 xHCI Controller + +pci:v000015ADd00000790* + ID_MODEL_FROM_DATABASE=PCI bridge + +pci:v000015ADd000007A0* + ID_MODEL_FROM_DATABASE=PCI Express Root Port + +pci:v000015ADd000007B0* + ID_MODEL_FROM_DATABASE=VMXNET3 Ethernet Controller + +pci:v000015ADd000007C0* + ID_MODEL_FROM_DATABASE=PVSCSI SCSI Controller + +pci:v000015ADd000007E0* + ID_MODEL_FROM_DATABASE=SATA AHCI controller + +pci:v000015ADd00000801* + ID_MODEL_FROM_DATABASE=Virtual Machine Interface + +pci:v000015ADd00000801sv000015ADsd00000800* + ID_MODEL_FROM_DATABASE=Hypervisor ROM Interface + +pci:v000015ADd00001977* + ID_MODEL_FROM_DATABASE=HD Audio Controller + +pci:v000015AE* + ID_VENDOR_FROM_DATABASE=Amersham Pharmacia Biotech + +pci:v000015B0* + ID_VENDOR_FROM_DATABASE=Zoltrix International Ltd + +pci:v000015B1* + ID_VENDOR_FROM_DATABASE=Source Technology Inc + +pci:v000015B2* + ID_VENDOR_FROM_DATABASE=Mosaid Technologies Inc + +pci:v000015B3* + ID_VENDOR_FROM_DATABASE=Mellanox Technologies + +pci:v000015B3d00000191* + ID_MODEL_FROM_DATABASE=MT25408 [ConnectX IB Flash Recovery] + +pci:v000015B3d000001F6* + ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3 Flash Recovery] + +pci:v000015B3d000001FF* + ID_MODEL_FROM_DATABASE=MT27600 Family [Connect-IB Flash Recovery] + +pci:v000015B3d00001002* + ID_MODEL_FROM_DATABASE=MT25400 Family [ConnectX-2 Virtual Function] + +pci:v000015B3d00001003* + ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3] + +pci:v000015B3d00001004* + ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3 Virtual Function] + +pci:v000015B3d00001005* + ID_MODEL_FROM_DATABASE=MT27510 Family + +pci:v000015B3d00001006* + ID_MODEL_FROM_DATABASE=MT27511 Family + +pci:v000015B3d00001007* + ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] + +pci:v000015B3d00001008* + ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro Virtual Function] + +pci:v000015B3d00001009* + ID_MODEL_FROM_DATABASE=MT27530 Family + +pci:v000015B3d0000100A* + ID_MODEL_FROM_DATABASE=MT27531 Family + +pci:v000015B3d0000100B* + ID_MODEL_FROM_DATABASE=MT27540 Family + +pci:v000015B3d0000100C* + ID_MODEL_FROM_DATABASE=MT27541 Family + +pci:v000015B3d0000100D* + ID_MODEL_FROM_DATABASE=MT27550 Family + +pci:v000015B3d0000100E* + ID_MODEL_FROM_DATABASE=MT27551 Family + +pci:v000015B3d0000100F* + ID_MODEL_FROM_DATABASE=MT27560 Family + +pci:v000015B3d00001010* + ID_MODEL_FROM_DATABASE=MT27561 Family + +pci:v000015B3d00001011* + ID_MODEL_FROM_DATABASE=MT27600 [Connect-IB] + +pci:v000015B3d00001012* + ID_MODEL_FROM_DATABASE=MT27600 Family [Connect-IB Virtual Function] + +pci:v000015B3d00001013* + ID_MODEL_FROM_DATABASE=MT27620 Family + +pci:v000015B3d00001014* + ID_MODEL_FROM_DATABASE=MT27621 Family + +pci:v000015B3d00001015* + ID_MODEL_FROM_DATABASE=MT27630 Family + +pci:v000015B3d00001016* + ID_MODEL_FROM_DATABASE=MT27631 Family + +pci:v000015B3d00001017* + ID_MODEL_FROM_DATABASE=MT27640 Family + +pci:v000015B3d00001018* + ID_MODEL_FROM_DATABASE=MT27641 Family + +pci:v000015B3d00005274* + ID_MODEL_FROM_DATABASE=MT21108 InfiniBridge + +pci:v000015B3d00005A44* + ID_MODEL_FROM_DATABASE=MT23108 InfiniHost + +pci:v000015B3d00005A45* + ID_MODEL_FROM_DATABASE=MT23108 [Infinihost HCA Flash Recovery] + +pci:v000015B3d00005A46* + ID_MODEL_FROM_DATABASE=MT23108 PCI Bridge + +pci:v000015B3d00005E8C* + ID_MODEL_FROM_DATABASE=MT24204 [InfiniHost III Lx HCA] + +pci:v000015B3d00005E8D* + ID_MODEL_FROM_DATABASE=MT25204 [InfiniHost III Lx HCA Flash Recovery] + +pci:v000015B3d00006274* + ID_MODEL_FROM_DATABASE=MT25204 [InfiniHost III Lx HCA] + +pci:v000015B3d00006278* + ID_MODEL_FROM_DATABASE=MT25208 InfiniHost III Ex (Tavor compatibility mode) + +pci:v000015B3d00006279* + ID_MODEL_FROM_DATABASE=MT25208 [InfiniHost III Ex HCA Flash Recovery] + +pci:v000015B3d00006282* + ID_MODEL_FROM_DATABASE=MT25208 [InfiniHost III Ex] + +pci:v000015B3d00006340* + ID_MODEL_FROM_DATABASE=MT25408 [ConnectX VPI - IB SDR / 10GigE] + +pci:v000015B3d0000634A* + ID_MODEL_FROM_DATABASE=MT25418 [ConnectX VPI PCIe 2.0 2.5GT/s - IB DDR / 10GigE] + +pci:v000015B3d00006368* + ID_MODEL_FROM_DATABASE=MT25448 [ConnectX EN 10GigE, PCIe 2.0 2.5GT/s] + +pci:v000015B3d00006372* + ID_MODEL_FROM_DATABASE=MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe 2.0 2.5GT/s] + +pci:v000015B3d00006732* + ID_MODEL_FROM_DATABASE=MT26418 [ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE] + +pci:v000015B3d0000673C* + ID_MODEL_FROM_DATABASE=MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] + +pci:v000015B3d00006746* + ID_MODEL_FROM_DATABASE=MT26438 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virtualization+] + +pci:v000015B3d00006746sv0000103Csd00001781* + ID_MODEL_FROM_DATABASE=NC543i 1-port 4x QDR IB/Flex-10 10Gb Adapter + +pci:v000015B3d00006746sv0000103Csd00003349* + ID_MODEL_FROM_DATABASE=NC543i 2-port 4xQDR IB/10Gb Adapter + +pci:v000015B3d00006750* + ID_MODEL_FROM_DATABASE=MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] + +pci:v000015B3d0000675A* + ID_MODEL_FROM_DATABASE=MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe Gen2 5GT/s] + +pci:v000015B3d00006764* + ID_MODEL_FROM_DATABASE=MT26468 [ConnectX EN 10GigE, PCIe 2.0 5GT/s Virtualization+] + +pci:v000015B3d00006764sv0000103Csd00003313* + ID_MODEL_FROM_DATABASE=HP NC542m Dual Port Flex-10 10GbE BLc Adapter + +pci:v000015B3d0000676E* + ID_MODEL_FROM_DATABASE=MT26478 [ConnectX EN 40GigE, PCIe 2.0 5GT/s] + +pci:v000015B3d00006778* + ID_MODEL_FROM_DATABASE=MT26488 [ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virtualization+] + +pci:v000015B4* + ID_VENDOR_FROM_DATABASE=CCI/TRIAD + +pci:v000015B5* + ID_VENDOR_FROM_DATABASE=Cimetrics Inc + +pci:v000015B6* + ID_VENDOR_FROM_DATABASE=Texas Memory Systems Inc + +pci:v000015B6d00000001* + ID_MODEL_FROM_DATABASE=XP15 DSP Accelerator + +pci:v000015B6d00000002* + ID_MODEL_FROM_DATABASE=XP30 DSP Accelerator + +pci:v000015B6d00000003* + ID_MODEL_FROM_DATABASE=XP00 Data Acquisition Device + +pci:v000015B6d00000004* + ID_MODEL_FROM_DATABASE=XP35 DSP Accelerator + +pci:v000015B6d00000007* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-T0] + +pci:v000015B6d00000008* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-T1] + +pci:v000015B6d00000009* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-E0] + +pci:v000015B6d0000000A* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-E1] + +pci:v000015B6d0000000E* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-0] + +pci:v000015B6d0000000F* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-1] + +pci:v000015B6d00000010* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-P0] + +pci:v000015B6d00000011* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-P1] + +pci:v000015B6d00000012* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-P2] + +pci:v000015B6d00000013* + ID_MODEL_FROM_DATABASE=XP100 DSP Accelerator [XP100-P3] + +pci:v000015B6d00000014* + ID_MODEL_FROM_DATABASE=RamSan Flash SSD + +pci:v000015B6d00000015* + ID_MODEL_FROM_DATABASE=ZBox + +pci:v000015B7* + ID_VENDOR_FROM_DATABASE=Sandisk Corp + +pci:v000015B8* + ID_VENDOR_FROM_DATABASE=ADDI-DATA GmbH + +pci:v000015B8d00001001* + ID_MODEL_FROM_DATABASE=APCI1516 SP controller (16 digi outputs) + +pci:v000015B8d00001003* + ID_MODEL_FROM_DATABASE=APCI1032 SP controller (32 digi inputs w/ opto coupler) + +pci:v000015B8d00001004* + ID_MODEL_FROM_DATABASE=APCI2032 SP controller (32 digi outputs) + +pci:v000015B8d00001005* + ID_MODEL_FROM_DATABASE=APCI2200 SP controller (8/16 digi outputs (relay)) + +pci:v000015B8d00001006* + ID_MODEL_FROM_DATABASE=APCI1564 SP controller (32 digi ins, 32 digi outs) + +pci:v000015B8d0000100A* + ID_MODEL_FROM_DATABASE=APCI1696 SP controller (96 TTL I/Os) + +pci:v000015B8d00003001* + ID_MODEL_FROM_DATABASE=APCI3501 SP controller (analog output board) + +pci:v000015B8d0000300F* + ID_MODEL_FROM_DATABASE=APCI3600 Noise and vibration measurement board + +pci:v000015B8d00007001* + ID_MODEL_FROM_DATABASE=APCI7420 2-port Serial Controller + +pci:v000015B8d00007002* + ID_MODEL_FROM_DATABASE=APCI7300 Serial Controller + +pci:v000015B9* + ID_VENDOR_FROM_DATABASE=Maestro Digital Communications + +pci:v000015BA* + ID_VENDOR_FROM_DATABASE=Impacct Technology Corp + +pci:v000015BB* + ID_VENDOR_FROM_DATABASE=Portwell Inc + +pci:v000015BC* + ID_VENDOR_FROM_DATABASE=Agilent Technologies + +pci:v000015BCd00000100* + ID_MODEL_FROM_DATABASE=HPFC-5600 Tachyon DX2+ FC + +pci:v000015BCd00000103* + ID_MODEL_FROM_DATABASE=QX4 PCI Express quad 4-gigabit Fibre Channel controller + +pci:v000015BCd00000105* + ID_MODEL_FROM_DATABASE=Celerity FC-44XS/FC-42XS/FC-41XS/FC-44ES/FC-42ES/FC-41ES + +pci:v000015BCd00000105sv0000117Csd00000022* + ID_MODEL_FROM_DATABASE=Celerity FC-42XS Fibre Channel Adapter + +pci:v000015BCd00000105sv0000117Csd00000025* + ID_MODEL_FROM_DATABASE=Celerity FC-44ES Fibre Channel Adapter + +pci:v000015BCd00000105sv0000117Csd00000026* + ID_MODEL_FROM_DATABASE=Celerity FC-42ES Fibre Channel Adapter + +pci:v000015BCd00001100* + ID_MODEL_FROM_DATABASE=E8001-66442 PCI Express CIC + +pci:v000015BCd00002922* + ID_MODEL_FROM_DATABASE=64 Bit, 133MHz PCI-X Exerciser & Protocol Checker + +pci:v000015BCd00002928* + ID_MODEL_FROM_DATABASE=64 Bit, 66MHz PCI Exerciser & Analyzer + +pci:v000015BCd00002929* + ID_MODEL_FROM_DATABASE=64 Bit, 133MHz PCI-X Analyzer & Exerciser + +pci:v000015BD* + ID_VENDOR_FROM_DATABASE=DFI Inc + +pci:v000015BE* + ID_VENDOR_FROM_DATABASE=Sola Electronics + +pci:v000015BF* + ID_VENDOR_FROM_DATABASE=High Tech Computer Corp (HTC) + +pci:v000015C0* + ID_VENDOR_FROM_DATABASE=BVM Ltd + +pci:v000015C1* + ID_VENDOR_FROM_DATABASE=Quantel + +pci:v000015C2* + ID_VENDOR_FROM_DATABASE=Newer Technology Inc + +pci:v000015C3* + ID_VENDOR_FROM_DATABASE=Taiwan Mycomp Co Ltd + +pci:v000015C4* + ID_VENDOR_FROM_DATABASE=EVSX Inc + +pci:v000015C5* + ID_VENDOR_FROM_DATABASE=Procomp Informatics Ltd + +pci:v000015C5d00008010* + ID_MODEL_FROM_DATABASE=1394b - 1394 Firewire 3-Port Host Adapter Card + +pci:v000015C6* + ID_VENDOR_FROM_DATABASE=Technical University of Budapest + +pci:v000015C7* + ID_VENDOR_FROM_DATABASE=Tateyama System Laboratory Co Ltd + +pci:v000015C7d00000349* + ID_MODEL_FROM_DATABASE=Tateyama C-PCI PLC/NC card Rev.01A + +pci:v000015C8* + ID_VENDOR_FROM_DATABASE=Penta Media Co Ltd + +pci:v000015C9* + ID_VENDOR_FROM_DATABASE=Serome Technology Inc + +pci:v000015CA* + ID_VENDOR_FROM_DATABASE=Bitboys OY + +pci:v000015CB* + ID_VENDOR_FROM_DATABASE=AG Electronics Ltd + +pci:v000015CC* + ID_VENDOR_FROM_DATABASE=Hotrail Inc + +pci:v000015CD* + ID_VENDOR_FROM_DATABASE=Dreamtech Co Ltd + +pci:v000015CE* + ID_VENDOR_FROM_DATABASE=Genrad Inc + +pci:v000015CF* + ID_VENDOR_FROM_DATABASE=Hilscher GmbH + +pci:v000015CFd00000000* + ID_MODEL_FROM_DATABASE=CIFX 50E-DP(M/S) + +pci:v000015D1* + ID_VENDOR_FROM_DATABASE=Infineon Technologies AG + +pci:v000015D2* + ID_VENDOR_FROM_DATABASE=FIC (First International Computer Inc) + +pci:v000015D3* + ID_VENDOR_FROM_DATABASE=NDS Technologies Israel Ltd + +pci:v000015D4* + ID_VENDOR_FROM_DATABASE=Iwill Corp + +pci:v000015D5* + ID_VENDOR_FROM_DATABASE=Tatung Co + +pci:v000015D6* + ID_VENDOR_FROM_DATABASE=Entridia Corp + +pci:v000015D7* + ID_VENDOR_FROM_DATABASE=Rockwell-Collins Inc + +pci:v000015D8* + ID_VENDOR_FROM_DATABASE=Cybernetics Technology Co Ltd + +pci:v000015D9* + ID_VENDOR_FROM_DATABASE=Super Micro Computer Inc + +pci:v000015DA* + ID_VENDOR_FROM_DATABASE=Cyberfirm Inc + +pci:v000015DB* + ID_VENDOR_FROM_DATABASE=Applied Computing Systems Inc + +pci:v000015DC* + ID_VENDOR_FROM_DATABASE=Litronic Inc + +pci:v000015DCd00000001* + ID_MODEL_FROM_DATABASE=Argus 300 PCI Cryptography Module + +pci:v000015DD* + ID_VENDOR_FROM_DATABASE=Sigmatel Inc + +pci:v000015DE* + ID_VENDOR_FROM_DATABASE=Malleable Technologies Inc + +pci:v000015DF* + ID_VENDOR_FROM_DATABASE=Infinilink Corp + +pci:v000015E0* + ID_VENDOR_FROM_DATABASE=Cacheflow Inc + +pci:v000015E1* + ID_VENDOR_FROM_DATABASE=Voice Technologies Group Inc + +pci:v000015E2* + ID_VENDOR_FROM_DATABASE=Quicknet Technologies Inc + +pci:v000015E2d00000500* + ID_MODEL_FROM_DATABASE=PhoneJack-PCI + +pci:v000015E3* + ID_VENDOR_FROM_DATABASE=Networth Technologies Inc + +pci:v000015E4* + ID_VENDOR_FROM_DATABASE=VSN Systemen BV + +pci:v000015E5* + ID_VENDOR_FROM_DATABASE=Valley technologies Inc + +pci:v000015E6* + ID_VENDOR_FROM_DATABASE=Agere Inc + +pci:v000015E7* + ID_VENDOR_FROM_DATABASE=Get Engineering Corp + +pci:v000015E8* + ID_VENDOR_FROM_DATABASE=National Datacomm Corp + +pci:v000015E8d00000130* + ID_MODEL_FROM_DATABASE=Wireless PCI Card + +pci:v000015E8d00000131* + ID_MODEL_FROM_DATABASE=NCP130A2 Wireless NIC + +pci:v000015E9* + ID_VENDOR_FROM_DATABASE=Pacific Digital Corp + +pci:v000015E9d00001841* + ID_MODEL_FROM_DATABASE=ADMA-100 DiscStaQ ATA Controller + +pci:v000015EA* + ID_VENDOR_FROM_DATABASE=Tokyo Denshi Sekei K.K. + +pci:v000015EB* + ID_VENDOR_FROM_DATABASE=DResearch Digital Media Systems GmbH + +pci:v000015EC* + ID_VENDOR_FROM_DATABASE=Beckhoff GmbH + +pci:v000015ECd00003101* + ID_MODEL_FROM_DATABASE=FC3101 Profibus DP 1 Channel PCI + +pci:v000015ECd00005102* + ID_MODEL_FROM_DATABASE=FC5102 + +pci:v000015ED* + ID_VENDOR_FROM_DATABASE=Macrolink Inc + +pci:v000015EE* + ID_VENDOR_FROM_DATABASE=In Win Development Inc + +pci:v000015EF* + ID_VENDOR_FROM_DATABASE=Intelligent Paradigm Inc + +pci:v000015F0* + ID_VENDOR_FROM_DATABASE=B-Tree Systems Inc + +pci:v000015F1* + ID_VENDOR_FROM_DATABASE=Times N Systems Inc + +pci:v000015F2* + ID_VENDOR_FROM_DATABASE=Diagnostic Instruments Inc + +pci:v000015F3* + ID_VENDOR_FROM_DATABASE=Digitmedia Corp + +pci:v000015F4* + ID_VENDOR_FROM_DATABASE=Valuesoft + +pci:v000015F5* + ID_VENDOR_FROM_DATABASE=Power Micro Research + +pci:v000015F6* + ID_VENDOR_FROM_DATABASE=Extreme Packet Device Inc + +pci:v000015F7* + ID_VENDOR_FROM_DATABASE=Banctec + +pci:v000015F8* + ID_VENDOR_FROM_DATABASE=Koga Electronics Co + +pci:v000015F9* + ID_VENDOR_FROM_DATABASE=Zenith Electronics Corp + +pci:v000015FA* + ID_VENDOR_FROM_DATABASE=J.P. Axzam Corp + +pci:v000015FB* + ID_VENDOR_FROM_DATABASE=Zilog Inc + +pci:v000015FC* + ID_VENDOR_FROM_DATABASE=Techsan Electronics Co Ltd + +pci:v000015FD* + ID_VENDOR_FROM_DATABASE=N-CUBED.NET + +pci:v000015FE* + ID_VENDOR_FROM_DATABASE=Kinpo Electronics Inc + +pci:v000015FF* + ID_VENDOR_FROM_DATABASE=Fastpoint Technologies Inc + +pci:v00001600* + ID_VENDOR_FROM_DATABASE=Northrop Grumman - Canada Ltd + +pci:v00001601* + ID_VENDOR_FROM_DATABASE=Tenta Technology + +pci:v00001602* + ID_VENDOR_FROM_DATABASE=Prosys-tec Inc + +pci:v00001603* + ID_VENDOR_FROM_DATABASE=Nokia Wireless Communications + +pci:v00001604* + ID_VENDOR_FROM_DATABASE=Central System Research Co Ltd + +pci:v00001605* + ID_VENDOR_FROM_DATABASE=Pairgain Technologies + +pci:v00001606* + ID_VENDOR_FROM_DATABASE=Europop AG + +pci:v00001607* + ID_VENDOR_FROM_DATABASE=Lava Semiconductor Manufacturing Inc + +pci:v00001608* + ID_VENDOR_FROM_DATABASE=Automated Wagering International + +pci:v00001609* + ID_VENDOR_FROM_DATABASE=Scimetric Instruments Inc + +pci:v00001612* + ID_VENDOR_FROM_DATABASE=Telesynergy Research Inc. + +pci:v00001618* + ID_VENDOR_FROM_DATABASE=Stone Ridge Technology + +pci:v00001618d00000001* + ID_MODEL_FROM_DATABASE=RDX 11 + +pci:v00001618d00000002* + ID_MODEL_FROM_DATABASE=HFT-01 + +pci:v00001618d00000400* + ID_MODEL_FROM_DATABASE=FarSync T2P (2 port X.21/V.35/V.24) + +pci:v00001618d00000440* + ID_MODEL_FROM_DATABASE=FarSync T4P (4 port X.21/V.35/V.24) + +pci:v00001618d00000610* + ID_MODEL_FROM_DATABASE=FarSync T1U (1 port X.21/V.35/V.24) + +pci:v00001618d00000620* + ID_MODEL_FROM_DATABASE=FarSync T2U (2 port X.21/V.35/V.24) + +pci:v00001618d00000640* + ID_MODEL_FROM_DATABASE=FarSync T4U (4 port X.21/V.35/V.24) + +pci:v00001618d00001610* + ID_MODEL_FROM_DATABASE=FarSync TE1 (T1,E1) + +pci:v00001618d00002610* + ID_MODEL_FROM_DATABASE=FarSync DSL-S1 (SHDSL) + +pci:v00001618d00003640* + ID_MODEL_FROM_DATABASE=FarSync T4E (4-port X.21/V.35/V.24) + +pci:v00001618d00004620* + ID_MODEL_FROM_DATABASE=FarSync T2Ue PCI Express (2-port X.21/V.35/V.24) + +pci:v00001618d00004640* + ID_MODEL_FROM_DATABASE=FarSync T4Ue PCI Express (4-port X.21/V.35/V.24) + +pci:v00001619* + ID_VENDOR_FROM_DATABASE=FarSite Communications Ltd + +pci:v00001619d00000400* + ID_MODEL_FROM_DATABASE=FarSync T2P (2 port X.21/V.35/V.24) + +pci:v00001619d00000440* + ID_MODEL_FROM_DATABASE=FarSync T4P (4 port X.21/V.35/V.24) + +pci:v00001619d00000610* + ID_MODEL_FROM_DATABASE=FarSync T1U (1 port X.21/V.35/V.24) + +pci:v00001619d00000620* + ID_MODEL_FROM_DATABASE=FarSync T2U (2 port X.21/V.35/V.24) + +pci:v00001619d00000640* + ID_MODEL_FROM_DATABASE=FarSync T4U (4 port X.21/V.35/V.24) + +pci:v00001619d00001610* + ID_MODEL_FROM_DATABASE=FarSync TE1 (T1,E1) + +pci:v00001619d00001612* + ID_MODEL_FROM_DATABASE=FarSync TE1 PCI Express (T1,E1) + +pci:v00001619d00002610* + ID_MODEL_FROM_DATABASE=FarSync DSL-S1 (SHDSL) + +pci:v00001619d00003640* + ID_MODEL_FROM_DATABASE=FarSync T4E (4-port X.21/V.35/V.24) + +pci:v00001619d00004620* + ID_MODEL_FROM_DATABASE=FarSync T2Ue PCI Express (2-port X.21/V.35/V.24) + +pci:v00001619d00004640* + ID_MODEL_FROM_DATABASE=FarSync T4Ue PCI Express (4-port X.21/V.35/V.24) + +pci:v00001619d00005621* + ID_MODEL_FROM_DATABASE=FarSync T2Ee PCI Express (2 port X.21/V.35/V.24) + +pci:v00001619d00005641* + ID_MODEL_FROM_DATABASE=FarSync T4Ee PCI Express (4 port X.21/V.35/V.24) + +pci:v00001619d00006620* + ID_MODEL_FROM_DATABASE=FarSync T2U-PMC PCI Express (2 port X.21/V.35/V.24) + +pci:v0000161F* + ID_VENDOR_FROM_DATABASE=Rioworks + +pci:v00001626* + ID_VENDOR_FROM_DATABASE=TDK Semiconductor Corp. + +pci:v00001626d00008410* + ID_MODEL_FROM_DATABASE=RTL81xx Fast Ethernet + +pci:v00001629* + ID_VENDOR_FROM_DATABASE=Kongsberg Spacetec AS + +pci:v00001629d00001003* + ID_MODEL_FROM_DATABASE=Format synchronizer v3.0 + +pci:v00001629d00001006* + ID_MODEL_FROM_DATABASE=Format synchronizer, model 10500 + +pci:v00001629d00001007* + ID_MODEL_FROM_DATABASE=Format synchronizer, model 21000 + +pci:v00001629d00002002* + ID_MODEL_FROM_DATABASE=Fast Universal Data Output + +pci:v00001631* + ID_VENDOR_FROM_DATABASE=Packard Bell B.V. + +pci:v00001638* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp [SMC] + +pci:v00001638d00001100* + ID_MODEL_FROM_DATABASE=SMC2602W EZConnect / Addtron AWA-100 / Eumitcom PCI WL11000 + +pci:v0000163C* + ID_VENDOR_FROM_DATABASE=Smart Link Ltd. + +pci:v0000163Cd00003052* + ID_MODEL_FROM_DATABASE=SmartLink SmartPCI562 56K Modem + +pci:v0000163Cd00005449* + ID_MODEL_FROM_DATABASE=SmartPCI561 Modem + +pci:v00001641* + ID_VENDOR_FROM_DATABASE=MKNet Corp. + +pci:v00001642* + ID_VENDOR_FROM_DATABASE=Bitland(ShenZhen) Information Technology Co., Ltd. + +pci:v00001657* + ID_VENDOR_FROM_DATABASE=Brocade Communications Systems, Inc. + +pci:v00001657d00000013* + ID_MODEL_FROM_DATABASE=425/825/42B/82B 4Gbps/8Gbps PCIe dual port FC HBA + +pci:v00001657d00000013sv0000103Csd00001742* + ID_MODEL_FROM_DATABASE=HP 82B 8Gbps dual port FC HBA + +pci:v00001657d00000013sv0000103Csd00001744* + ID_MODEL_FROM_DATABASE=HP 42B 4Gbps dual port FC HBA + +pci:v00001657d00000013sv00001657sd00000014* + ID_MODEL_FROM_DATABASE=425/825 4Gbps/8Gbps PCIe dual port FC HBA + +pci:v00001657d00000014* + ID_MODEL_FROM_DATABASE=1010/1020/1007/1741 10Gbps CNA + +pci:v00001657d00000014sv00001657sd00000014* + ID_MODEL_FROM_DATABASE=1010/1020/1007/1741 10Gbps CNA - FCOE + +pci:v00001657d00000014sv00001657sd00000015* + ID_MODEL_FROM_DATABASE=1010/1020/1007/1741 10Gbps CNA - LL + +pci:v00001657d00000017* + ID_MODEL_FROM_DATABASE=415/815/41B/81B 4Gbps/8Gbps PCIe single port FC HBA + +pci:v00001657d00000017sv0000103Csd00001741* + ID_MODEL_FROM_DATABASE=HP 41B 4Gbps single port FC HBA + +pci:v00001657d00000017sv0000103Csd00001743* + ID_MODEL_FROM_DATABASE=HP 81B 8Gbps single port FC HBA + +pci:v00001657d00000017sv00001657sd00000014* + ID_MODEL_FROM_DATABASE=415/815 4Gbps/8Gbps single port PCIe FC HBA + +pci:v00001657d00000021* + ID_MODEL_FROM_DATABASE=804 8Gbps FC HBA for HP Bladesystem c-class + +pci:v00001657d00000022* + ID_MODEL_FROM_DATABASE=1860 16Gbps/10Gbps Fabric Adapter + +pci:v00001657d00000022sv00001657sd00000022* + ID_MODEL_FROM_DATABASE=10Gbps CNA - FCOE + +pci:v00001657d00000022sv00001657sd00000023* + ID_MODEL_FROM_DATABASE=10Gbps CNA - LL + +pci:v00001657d00000022sv00001657sd00000024* + ID_MODEL_FROM_DATABASE=16Gbps FC HBA + +pci:v00001657d00000023* + ID_MODEL_FROM_DATABASE=1867/1869 16Gbps FC HBA + +pci:v00001657d00000646* + ID_MODEL_FROM_DATABASE=400 4Gbps PCIe FC HBA + +pci:v0000165A* + ID_VENDOR_FROM_DATABASE=Epix Inc + +pci:v0000165Ad0000C100* + ID_MODEL_FROM_DATABASE=PIXCI(R) CL1 Camera Link Video Capture Board [custom QL5232] + +pci:v0000165Ad0000D200* + ID_MODEL_FROM_DATABASE=PIXCI(R) D2X Digital Video Capture Board [custom QL5232] + +pci:v0000165Ad0000D300* + ID_MODEL_FROM_DATABASE=PIXCI(R) D3X Digital Video Capture Board [custom QL5232] + +pci:v0000165Ad0000EB01* + ID_MODEL_FROM_DATABASE=PIXCI(R) EB1 PCI Camera Link Video Capture Board + +pci:v0000165D* + ID_VENDOR_FROM_DATABASE=Hsing Tech. Enterprise Co., Ltd. + +pci:v0000165F* + ID_VENDOR_FROM_DATABASE=Linux Media Labs, LLC + +pci:v0000165Fd00001020* + ID_MODEL_FROM_DATABASE=LMLM4 MPEG-4 encoder + +pci:v00001661* + ID_VENDOR_FROM_DATABASE=Worldspace Corp. + +pci:v00001668* + ID_VENDOR_FROM_DATABASE=Actiontec Electronics Inc + +pci:v00001668d00000100* + ID_MODEL_FROM_DATABASE=Mini-PCI bridge + +pci:v0000166D* + ID_VENDOR_FROM_DATABASE=Broadcom Corporation + +pci:v0000166Dd00000001* + ID_MODEL_FROM_DATABASE=SiByte BCM1125/1125H/1250 System-on-a-Chip PCI + +pci:v0000166Dd00000002* + ID_MODEL_FROM_DATABASE=SiByte BCM1125H/1250 System-on-a-Chip HyperTransport + +pci:v0000166Dd00000012* + ID_MODEL_FROM_DATABASE=SiByte BCM1280/BCM1480 System-on-a-Chip PCI-X + +pci:v0000166Dd00000014* + ID_MODEL_FROM_DATABASE=Sibyte BCM1280/BCM1480 System-on-a-Chip HyperTransport + +pci:v00001677* + ID_VENDOR_FROM_DATABASE=Bernecker + Rainer + +pci:v00001677d0000104E* + ID_MODEL_FROM_DATABASE=5LS172.6 B&R Dual CAN Interface Card + +pci:v00001677d000012D7* + ID_MODEL_FROM_DATABASE=5LS172.61 B&R Dual CAN Interface Card + +pci:v00001677d000020AD* + ID_MODEL_FROM_DATABASE=5ACPCI.MFIO-K01 Profibus DP / K-Feldbus / COM + +pci:v00001678* + ID_VENDOR_FROM_DATABASE=NetEffect + +pci:v00001678d00000100* + ID_MODEL_FROM_DATABASE=NE020 10Gb Accelerated Ethernet Adapter (iWARP RNIC) + +pci:v00001679* + ID_VENDOR_FROM_DATABASE=Tokyo Electron Device Ltd. + +pci:v00001679d00003000* + ID_MODEL_FROM_DATABASE=SD Standard host controller [Ellen] + +pci:v0000167B* + ID_VENDOR_FROM_DATABASE=ZyDAS Technology Corp. + +pci:v0000167Bd00002102* + ID_MODEL_FROM_DATABASE=ZyDAS ZD1202 + +pci:v0000167Bd00002102sv0000187Esd00003406* + ID_MODEL_FROM_DATABASE=ZyAIR B-122 CardBus 11Mbs Wireless LAN Card + +pci:v0000167Bd00002102sv0000187Esd00003407* + ID_MODEL_FROM_DATABASE=ZyAIR B-320 802.11b Wireless PCI Adapter + +pci:v0000167Bd00002116* + ID_MODEL_FROM_DATABASE=ZD1212B Wireless Adapter + +pci:v0000167D* + ID_VENDOR_FROM_DATABASE=Samsung Electro-Mechanics Co., Ltd. + +pci:v0000167Dd0000A000* + ID_MODEL_FROM_DATABASE=MagicLAN SWL-2210P 802.11b [Intersil ISL3874] + +pci:v0000167E* + ID_VENDOR_FROM_DATABASE=ONNTO Corp. + +pci:v00001681* + ID_VENDOR_FROM_DATABASE=Hercules + +pci:v00001682* + ID_VENDOR_FROM_DATABASE=XFX Pine Group Inc. + +pci:v00001688* + ID_VENDOR_FROM_DATABASE=CastleNet Technology Inc. + +pci:v00001688d00001170* + ID_MODEL_FROM_DATABASE=WLAN 802.11b card + +pci:v0000168C* + ID_VENDOR_FROM_DATABASE=Qualcomm Atheros + +pci:v0000168Cd00000007* + ID_MODEL_FROM_DATABASE=AR5210 Wireless Network Adapter [AR5000 802.11a] + +pci:v0000168Cd00000007sv00001737sd00000007* + ID_MODEL_FROM_DATABASE=WPC54A Wireless PC Card + +pci:v0000168Cd00000007sv00001B47sd00000100* + ID_MODEL_FROM_DATABASE=Harmony 8450CN Wireless CardBus Module + +pci:v0000168Cd00000007sv00001B47sd00000110* + ID_MODEL_FROM_DATABASE=Skyline 4030 / Harmony 8450 802.11a Wireless CardBus Adapter + +pci:v0000168Cd00000007sv00008086sd00002501* + ID_MODEL_FROM_DATABASE=PRO/Wireless 5000 LAN PCI Adapter Module + +pci:v0000168Cd00000011* + ID_MODEL_FROM_DATABASE=AR5211 Wireless Network Adapter [AR5001A 802.11a] + +pci:v0000168Cd00000012* + ID_MODEL_FROM_DATABASE=AR5211 Wireless Network Adapter [AR5001X 802.11ab] + +pci:v0000168Cd00000012sv00001186sd00003A03* + ID_MODEL_FROM_DATABASE=AirPro DWL-A650 Wireless Cardbus Adapter (rev.B) + +pci:v0000168Cd00000012sv00001186sd00003A04* + ID_MODEL_FROM_DATABASE=AirPro DWL-AB650 Multimode Wireless Cardbus Adapter + +pci:v0000168Cd00000012sv00001186sd00003A05* + ID_MODEL_FROM_DATABASE=AirPro DWL-AB520 Multimode Wireless PCI Adapter + +pci:v0000168Cd00000012sv0000126Csd00008031* + ID_MODEL_FROM_DATABASE=2201 Mobile Adapter + +pci:v0000168Cd00000012sv00001385sd00004400* + ID_MODEL_FROM_DATABASE=WAB501 802.11ab Wireless CardBus Card + +pci:v0000168Cd00000012sv00001B47sd0000AA00* + ID_MODEL_FROM_DATABASE=8460 802.11ab Wireless CardBus Adapter + +pci:v0000168Cd00000013* + ID_MODEL_FROM_DATABASE=AR5212/AR5213 Wireless Network Adapter + +pci:v0000168Cd00000013sv00000308sd00003402* + ID_MODEL_FROM_DATABASE=AG-100 802.11ag Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00000308sd00003405* + ID_MODEL_FROM_DATABASE=G-102 v2 802.11g Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00000308sd00003408* + ID_MODEL_FROM_DATABASE=G-170S 802.11g Wireless CardBus Adapter + +pci:v0000168Cd00000013sv00000E11sd000000E5* + ID_MODEL_FROM_DATABASE=NC6000/NC8000 laptop + +pci:v0000168Cd00000013sv000010B7sd00006002* + ID_MODEL_FROM_DATABASE=3CRWE154A72 802.11abg Cardbus Adapter + +pci:v0000168Cd00000013sv00001113sd0000D301* + ID_MODEL_FROM_DATABASE=Philips CPWNA100 Wireless CardBus adapter + +pci:v0000168Cd00000013sv00001113sd0000EE23* + ID_MODEL_FROM_DATABASE=SMCWPCIT-G 108Mbps Wireless PCI adapter + +pci:v0000168Cd00000013sv00001154sd0000033B* + ID_MODEL_FROM_DATABASE=Buffalo WLI-CB-AMG54 + +pci:v0000168Cd00000013sv00001154sd0000034E* + ID_MODEL_FROM_DATABASE=Buffalo WLI-CB-AG108HP 802.11abg Cardbus Adapter + +pci:v0000168Cd00000013sv00001186sd00003202* + ID_MODEL_FROM_DATABASE=DWL-G650 (Rev B3,B5) Wireless cardbus adapter + +pci:v0000168Cd00000013sv00001186sd00003203* + ID_MODEL_FROM_DATABASE=AirPlus DWL-G520 Wireless PCI Adapter (rev. A) + +pci:v0000168Cd00000013sv00001186sd00003A07* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG650 Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00001186sd00003A08* + ID_MODEL_FROM_DATABASE=AirXpert DWL-AG520 Wireless PCI Adapter + +pci:v0000168Cd00000013sv00001186sd00003A12* + ID_MODEL_FROM_DATABASE=D-Link AirPlus DWL-G650 Wireless Cardbus Adapter(rev.C) + +pci:v0000168Cd00000013sv00001186sd00003A13* + ID_MODEL_FROM_DATABASE=AirPlus DWL-G520 Wireless PCI Adapter (rev. B) + +pci:v0000168Cd00000013sv00001186sd00003A14* + ID_MODEL_FROM_DATABASE=AirPremier AG DWL-AG530 Wireless PCI Adapter (rev.A) + +pci:v0000168Cd00000013sv00001186sd00003A17* + ID_MODEL_FROM_DATABASE=D-Link AirPremier DWL-G680 Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00001186sd00003A18* + ID_MODEL_FROM_DATABASE=D-Link AirPremier DWL-G550 Wireless PCI Adapter + +pci:v0000168Cd00000013sv00001186sd00003A1A* + ID_MODEL_FROM_DATABASE=WNA-2330 802.11bg Wireless CardBus Adapter + +pci:v0000168Cd00000013sv00001186sd00003A63* + ID_MODEL_FROM_DATABASE=D-Link AirPremier DWL-AG660 Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00001186sd00003A93* + ID_MODEL_FROM_DATABASE=Conceptronic C54I Wireless 801.11g PCI card + +pci:v0000168Cd00000013sv00001186sd00003A94* + ID_MODEL_FROM_DATABASE=Conceptronic C54C 802.11g Wireless Cardbus Adapter + +pci:v0000168Cd00000013sv00001186sd00003AB0* + ID_MODEL_FROM_DATABASE=Allnet ALL0281 Wireless PCI Card + +pci:v0000168Cd00000013sv00001385sd00004600* + ID_MODEL_FROM_DATABASE=WAG511 802.11a/b/g Dual Band Wireless PC Card + +pci:v0000168Cd00000013sv00001385sd00004610* + ID_MODEL_FROM_DATABASE=WAG511 802.11a/b/g Dual Band Wireless PC Card + +pci:v0000168Cd00000013sv00001385sd00004900* + ID_MODEL_FROM_DATABASE=WG311v1 802.11g Wireless PCI Adapter + +pci:v0000168Cd00000013sv00001385sd00004A00* + ID_MODEL_FROM_DATABASE=WAG311 802.11a/g Wireless PCI Adapter + +pci:v0000168Cd00000013sv00001385sd00004B00* + ID_MODEL_FROM_DATABASE=WG511T 108 Mbps Wireless PC Card (rev.A/B) + +pci:v0000168Cd00000013sv00001385sd00004D00* + ID_MODEL_FROM_DATABASE=WG311T 108 Mbps Wireless PCI Adapter (rev.A2) + +pci:v0000168Cd00000013sv00001385sd00004F00* + ID_MODEL_FROM_DATABASE=WG511U Double 108 Mbps Wireless PC Card + +pci:v0000168Cd00000013sv00001385sd00005A00* + ID_MODEL_FROM_DATABASE=WG311T 108 Mbps Wireless PCI Adapter (rev.A3) + +pci:v0000168Cd00000013sv00001385sd00005B00* + ID_MODEL_FROM_DATABASE=WG511T 108 Mbps Wireless PC Card (rev.C) + +pci:v0000168Cd00000013sv00001385sd00005D00* + ID_MODEL_FROM_DATABASE=WPN511 RangeMax Wireless PC Card + +pci:v0000168Cd00000013sv00001458sd0000E911* + ID_MODEL_FROM_DATABASE=GN-WIAG02 + +pci:v0000168Cd00000013sv00001468sd00000403* + ID_MODEL_FROM_DATABASE=U10H014 802.11g Cardbus Adapter + +pci:v0000168Cd00000013sv00001468sd00000408* + ID_MODEL_FROM_DATABASE=ThinkPad 11b/g Wireless LAN Mini PCI Adapter + +pci:v0000168Cd00000013sv000014B7sd00000A10* + ID_MODEL_FROM_DATABASE=8480-WD 802.11abg Cardbus Adapter + +pci:v0000168Cd00000013sv000014B7sd00000A60* + ID_MODEL_FROM_DATABASE=8482-WD ORiNOCO 11a/b/g Wireless PCI Adapter + +pci:v0000168Cd00000013sv000014B7sd0000AA30* + ID_MODEL_FROM_DATABASE=8800-FC 802.11bg Cardbus Adapter + +pci:v0000168Cd00000013sv000014B7sd0000AA40* + ID_MODEL_FROM_DATABASE=8470-WD 802.11bg Cardbus Adapter + +pci:v0000168Cd00000013sv000014B9sd0000CB21* + ID_MODEL_FROM_DATABASE=CB21 802.11a/b/g Cardbus Adapter + +pci:v0000168Cd00000013sv00001668sd00001026* + ID_MODEL_FROM_DATABASE=IBM HighRate 11 a/b/g Wireless CardBus Adapter + +pci:v0000168Cd00000013sv0000168Csd00000013* + ID_MODEL_FROM_DATABASE=AirPlus XtremeG DWL-G650 Wireless PCMCIA Adapter + +pci:v0000168Cd00000013sv0000168Csd00001025* + ID_MODEL_FROM_DATABASE=DWL-G650B2 Wireless CardBus Adapter + +pci:v0000168Cd00000013sv0000168Csd00001027* + ID_MODEL_FROM_DATABASE=Engenius NL-3054CB ARIES b/g CardBus Adapter + +pci:v0000168Cd00000013sv0000168Csd00001042* + ID_MODEL_FROM_DATABASE=Ubiquiti Networks SuperRange a/b/g Cardbus Adapter + +pci:v0000168Cd00000013sv0000168Csd00001051* + ID_MODEL_FROM_DATABASE=EZ Connect g 802.11g 108Mbps Wireless PCI Adapter + +pci:v0000168Cd00000013sv0000168Csd00002026* + ID_MODEL_FROM_DATABASE=Netgate 5354MP ARIES a(108Mb turbo)/b/g MiniPCI Adapter + +pci:v0000168Cd00000013sv0000168Csd00002027* + ID_MODEL_FROM_DATABASE=D-Link AirPlus DWL-G520 Wireless PCI Adapter (rev. A) + +pci:v0000168Cd00000013sv0000168Csd00002041* + ID_MODEL_FROM_DATABASE=Engenius 5354MP Plus ARIES2 b/g MiniPCI Adapter + +pci:v0000168Cd00000013sv0000168Csd00002042* + ID_MODEL_FROM_DATABASE=Engenius 5354MP Plus ARIES2 a/b/g MiniPCI Adapter + +pci:v0000168Cd00000013sv0000168Csd00002051* + ID_MODEL_FROM_DATABASE=TRENDnet TEW-443PI Wireless PCI Adapter + +pci:v0000168Cd00000013sv000016A5sd0000160A* + ID_MODEL_FROM_DATABASE=BWP712 802.11bg Wireless CardBus Adapter + +pci:v0000168Cd00000013sv000016ABsd00007302* + ID_MODEL_FROM_DATABASE=Trust Speedshare Turbo Pro Wireless PCI Adapter + +pci:v0000168Cd00000013sv00001737sd00000017* + ID_MODEL_FROM_DATABASE=WPC55AG + +pci:v0000168Cd00000013sv00001737sd00000026* + ID_MODEL_FROM_DATABASE=WMP55AG v1.1 + +pci:v0000168Cd00000013sv00001737sd00000035* + ID_MODEL_FROM_DATABASE=WPC55AG v1.2 802.11abg Cardbus Adapter + +pci:v0000168Cd00000013sv00001737sd00000036* + ID_MODEL_FROM_DATABASE=WMP55AG v1.2 802.11abg PCI Adapter + +pci:v0000168Cd00000013sv00001799sd00003000* + ID_MODEL_FROM_DATABASE=F6D3000 Dual-Band Wireless A+G Desktop Card + +pci:v0000168Cd00000013sv00001799sd00003010* + ID_MODEL_FROM_DATABASE=F6D3010 Dual-Band Wireless A+G Notebook Card + +pci:v0000168Cd00000013sv000017CFsd00000042* + ID_MODEL_FROM_DATABASE=Z-COMAX Highpower XG-622H (400mw) 802.11b/g mini-PCI Adapter + +pci:v0000168Cd00000013sv0000185Fsd00001012* + ID_MODEL_FROM_DATABASE=CM9 Wireless a/b/g MiniPCI Adapter + +pci:v0000168Cd00000013sv0000185Fsd00002012* + ID_MODEL_FROM_DATABASE=Wistron NeWeb WLAN a+b+g model CB9 + +pci:v0000168Cd00000013sv0000A727sd00006801* + ID_MODEL_FROM_DATABASE=3CRXJK10075 OfficeConnect Wireless 108Mbps 11g XJACK PC Card + +pci:v0000168Cd0000001A* + ID_MODEL_FROM_DATABASE=AR2413/AR2414 Wireless Network Adapter [AR5005G(S) 802.11bg] + +pci:v0000168Cd0000001Asv00001052sd0000168C* + ID_MODEL_FROM_DATABASE=Sweex Wireless Lan PC Card 54Mbps + +pci:v0000168Cd0000001Asv00001113sd0000EE20* + ID_MODEL_FROM_DATABASE=SMC Wireless CardBus Adapter 802.11g (SMCWCB-G EU) + +pci:v0000168Cd0000001Asv00001113sd0000EE24* + ID_MODEL_FROM_DATABASE=SMC Wireless PCI Card WPCI-G + +pci:v0000168Cd0000001Asv00001186sd00003A15* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.D1) + +pci:v0000168Cd0000001Asv00001186sd00003A16* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G510 Wireless PCI Adapter(rev.B) + +pci:v0000168Cd0000001Asv00001186sd00003A1C* + ID_MODEL_FROM_DATABASE=WNA-1330 Notebook Adapter + +pci:v0000168Cd0000001Asv00001186sd00003A1D* + ID_MODEL_FROM_DATABASE=WDA-1320 Desktop Adapter + +pci:v0000168Cd0000001Asv00001186sd00003A23* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G520+A Wireless PCI Adapter + +pci:v0000168Cd0000001Asv00001186sd00003A24* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G650+A Wireless Cardbus Adapter + +pci:v0000168Cd0000001Asv00001186sd00003B08* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.C1) + +pci:v0000168Cd0000001Asv0000168Csd0000001A* + ID_MODEL_FROM_DATABASE=Belkin FD7000 + +pci:v0000168Cd0000001Asv0000168Csd00001052* + ID_MODEL_FROM_DATABASE=TP-Link TL-WN510G Wireless CardBus Adapter + +pci:v0000168Cd0000001Asv0000168Csd00002052* + ID_MODEL_FROM_DATABASE=Compex Wireless 802.11 b/g MiniPCI Adapter, Rev A1 [WLM54G] + +pci:v0000168Cd0000001Asv000016ECsd00000122* + ID_MODEL_FROM_DATABASE=Wireless PCI Adapter Model 5418 + +pci:v0000168Cd0000001Asv00001737sd00000053* + ID_MODEL_FROM_DATABASE=WPC54G v7 802.11g Wireless-G Notebook Adapter + +pci:v0000168Cd0000001Asv00001799sd0000700C* + ID_MODEL_FROM_DATABASE=F5D7000 v5000 Wireless G Desktop Card + +pci:v0000168Cd0000001Asv00001799sd0000701D* + ID_MODEL_FROM_DATABASE=F5D7010 v5000 Wireless G Notebook Card + +pci:v0000168Cd0000001Asv000017F9sd00000008* + ID_MODEL_FROM_DATABASE=DX-WGNBC 802.11bg Wireless CardBus Adapter + +pci:v0000168Cd0000001Asv000017F9sd00000018* + ID_MODEL_FROM_DATABASE=DX-WGDTC 802.11bg Wireless PCI Adapter + +pci:v0000168Cd0000001B* + ID_MODEL_FROM_DATABASE=AR5413/AR5414 Wireless Network Adapter [AR5006X(S) 802.11abg] + +pci:v0000168Cd0000001Bsv00000777sd00001107* + ID_MODEL_FROM_DATABASE=UB5 802.11a Wireless Mini PCI Adapter + +pci:v0000168Cd0000001Bsv00000777sd00003002* + ID_MODEL_FROM_DATABASE=XR2 802.11g Wireless Mini PCI Adapter + +pci:v0000168Cd0000001Bsv00000777sd00003005* + ID_MODEL_FROM_DATABASE=XR5 802.11a Wireless Mini PCI Adapter + +pci:v0000168Cd0000001Bsv00000777sd00003009* + ID_MODEL_FROM_DATABASE=XR9 900MHz Wireless Mini PCI Adapter + +pci:v0000168Cd0000001Bsv00001154sd0000034E* + ID_MODEL_FROM_DATABASE=WLI-CB-AG108HP 802.11abg Wireless CardBus Adapter + +pci:v0000168Cd0000001Bsv00001186sd00003A19* + ID_MODEL_FROM_DATABASE=D-Link AirPremier AG DWL-AG660 Wireless Cardbus Adapter + +pci:v0000168Cd0000001Bsv00001186sd00003A22* + ID_MODEL_FROM_DATABASE=AirPremier AG DWL-AG530 Wireless PCI Adapter (rev.B) + +pci:v0000168Cd0000001Bsv000011ADsd00005001* + ID_MODEL_FROM_DATABASE=WN5301A 802.11bg Wireless PCI Adapter + +pci:v0000168Cd0000001Bsv00001458sd0000E901* + ID_MODEL_FROM_DATABASE=GN-WI01HT Wireless a/b/g MiniPCI Adapter + +pci:v0000168Cd0000001Bsv0000168Csd0000001B* + ID_MODEL_FROM_DATABASE=Wireless LAN PCI LiteOn + +pci:v0000168Cd0000001Bsv0000168Csd00001062* + ID_MODEL_FROM_DATABASE=IPN-W100CB 802.11abg Wireless CardBus Adapter + +pci:v0000168Cd0000001Bsv0000168Csd00002062* + ID_MODEL_FROM_DATABASE=EnGenius EMP-8602 (400mw) or Compex WLM54AG (SuperAG) + +pci:v0000168Cd0000001Bsv0000168Csd00002063* + ID_MODEL_FROM_DATABASE=EnGenius EMP-8602 (400mw) or Compex WLM54AG + +pci:v0000168Cd0000001Bsv000017F9sd0000000B* + ID_MODEL_FROM_DATABASE=WL-711A 802.11abg Wireless CardBus Adapter + +pci:v0000168Cd0000001Bsv000017F9sd0000000C* + ID_MODEL_FROM_DATABASE=WPIA-112AG 802.11abg Wireless PCI Adapter + +pci:v0000168Cd0000001Bsv000017F9sd0000000D* + ID_MODEL_FROM_DATABASE=PC-686X 802.11abg Wireless Mini PCI Adapter + +pci:v0000168Cd0000001Bsv0000185Fsd00001600* + ID_MODEL_FROM_DATABASE=DCMA-82 High Power WLAN 802.11a/b/g mini-PCI Module (Super A/G, eXtended Range, 400mW) + +pci:v0000168Cd0000001Bsv00001948sd00003ABA* + ID_MODEL_FROM_DATABASE=RBTBJ-AW 802.11abg Wireless Cardbus Adapter + +pci:v0000168Cd0000001Bsv0000A727sd00006804* + ID_MODEL_FROM_DATABASE=Wireless 11a/b/g PC Card with XJACK(r) Antenna + +pci:v0000168Cd0000001C* + ID_MODEL_FROM_DATABASE=AR242x / AR542x Wireless Network Adapter (PCI-Express) + +pci:v0000168Cd0000001Csv00000777sd00003006* + ID_MODEL_FROM_DATABASE=SRX 802.11abg Wireless ExpressCard Adapter + +pci:v0000168Cd0000001Csv0000103Csd0000137A* + ID_MODEL_FROM_DATABASE=AR5BXB63 (Foxconn) 802.11bg Mini PCIe NIC + +pci:v0000168Cd0000001Csv0000106Bsd00000086* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v0000168Cd0000001Csv0000144Fsd00007106* + ID_MODEL_FROM_DATABASE=WLL3140 (Toshiba PA3501U-1MPC) 802.11bg Wireless Mini PCIe Card + +pci:v0000168Cd0000001Csv0000144Fsd00007128* + ID_MODEL_FROM_DATABASE=WLL3141 (Toshiba PA3613U-1MPC) 802.11bg Wireless Mini PCIe Card + +pci:v0000168Cd0000001Csv00001468sd00000428* + ID_MODEL_FROM_DATABASE=AR5BXB63 802.11bg NIC + +pci:v0000168Cd0000001Csv00001468sd0000042A* + ID_MODEL_FROM_DATABASE=AR5007EG 802.11bg NIC + +pci:v0000168Cd0000001Csv0000147Bsd00001033* + ID_MODEL_FROM_DATABASE=AirPace Wi-Fi + +pci:v0000168Cd0000001Csv0000168Csd0000001C* + ID_MODEL_FROM_DATABASE=AR242x 802.11abg NIC (PCI Express) + +pci:v0000168Cd0000001Csv0000168Csd00003061* + ID_MODEL_FROM_DATABASE=AR5006EGS 802.11bg NIC (2.4GHz, PCI Express) + +pci:v0000168Cd0000001Csv0000168Csd00003062* + ID_MODEL_FROM_DATABASE=AR5006EXS 802.11abg NIC (2.4/5.0GHz, PCI Express) + +pci:v0000168Cd0000001Csv0000168Csd00003063* + ID_MODEL_FROM_DATABASE=AR5006EX 802.11abg NIC (2.4/5.0GHz, PCI Express) + +pci:v0000168Cd0000001Csv0000168Csd00003065* + ID_MODEL_FROM_DATABASE=AR5006EG 802.11bg NIC (2.4GHz, PCI Express) + +pci:v0000168Cd0000001Csv0000168Csd00003067* + ID_MODEL_FROM_DATABASE=AR242x 802.11abg Wireless PCI Express Adapter (rev 01) + +pci:v0000168Cd0000001Csv00001A3Bsd00001026* + ID_MODEL_FROM_DATABASE=AW-GE780 802.11bg Wireless Mini PCIe Card + +pci:v0000168Cd0000001D* + ID_MODEL_FROM_DATABASE=AR2417 Wireless Network Adapter [AR5007G 802.11bg] + +pci:v0000168Cd0000001Dsv00001799sd0000720B* + ID_MODEL_FROM_DATABASE=F5D7000 v8000 Wireless G Desktop Card + +pci:v0000168Cd0000001Dsv00001799sd0000721B* + ID_MODEL_FROM_DATABASE=F5D7010 v8000 Wireless G Notebook Card + +pci:v0000168Cd00000020* + ID_MODEL_FROM_DATABASE=AR5513 802.11abg Wireless NIC + +pci:v0000168Cd00000020sv00000308sd00003407* + ID_MODEL_FROM_DATABASE=M-102 802.11g Wireless Cardbus Adapter + +pci:v0000168Cd00000020sv00001186sd00003A67* + ID_MODEL_FROM_DATABASE=DWL-G650M Super G MIMO Wireless Notebook Adapter + +pci:v0000168Cd00000020sv00001186sd00003A68* + ID_MODEL_FROM_DATABASE=DWL-G520M Wireless 108G MIMO Desktop Adapter + +pci:v0000168Cd00000020sv0000187Esd0000340E* + ID_MODEL_FROM_DATABASE=M-302 802.11g Wireless PCI Adapter + +pci:v0000168Cd00000020sv00001976sd00002003* + ID_MODEL_FROM_DATABASE=TEW-601PC 802.11g Wireless CardBus Adapter + +pci:v0000168Cd00000023* + ID_MODEL_FROM_DATABASE=AR5416 Wireless Network Adapter [AR5008 802.11(a)bgn] + +pci:v0000168Cd00000023sv00000308sd0000340B* + ID_MODEL_FROM_DATABASE=NWD-170N 802.11bgn Wireless CardBus Adapter + +pci:v0000168Cd00000023sv00001154sd00000365* + ID_MODEL_FROM_DATABASE=Buffalo WLP-CB-AG300 802.11abgn Cardbus Adapter + +pci:v0000168Cd00000023sv00001154sd00000367* + ID_MODEL_FROM_DATABASE=WLI-CB-AG301N 802.11abgn Wireless CardBus Adapter + +pci:v0000168Cd00000023sv00001186sd00003A6A* + ID_MODEL_FROM_DATABASE=DWA-642 802.11n RangeBooster N CardBus Adapter + +pci:v0000168Cd00000023sv00001186sd00003A6B* + ID_MODEL_FROM_DATABASE=DWA-547 802.11n RangeBooster N 650 DeskTop Adapter + +pci:v0000168Cd00000023sv00001186sd00003A6D* + ID_MODEL_FROM_DATABASE=DWA-552 802.11n Xtreme N Desktop Adapter (rev A1) + +pci:v0000168Cd00000023sv00001186sd00003A76* + ID_MODEL_FROM_DATABASE=DWA-645 802.11n RangeBooster N 650 Notebook Adapter (rev A1) + +pci:v0000168Cd00000023sv00001737sd00000059* + ID_MODEL_FROM_DATABASE=WPC300N v2 Wireless-N Notebook Adapter + +pci:v0000168Cd00000023sv00001737sd00000069* + ID_MODEL_FROM_DATABASE=WPC100 v1 802.11n RangePlus Wireless Notebook Adapter + +pci:v0000168Cd00000023sv00001737sd00000072* + ID_MODEL_FROM_DATABASE=WMP110 v1 802.11n RangePlus Wireless PCI Adapter + +pci:v0000168Cd00000023sv00001799sd00008011* + ID_MODEL_FROM_DATABASE=F5D8011 v1 802.11n N1 Wireless Notebook Card + +pci:v0000168Cd00000023sv0000187Esd00003411* + ID_MODEL_FROM_DATABASE=NWD-370N 802.11n Wireless PCI Adapter + +pci:v0000168Cd00000023sv00001976sd00002008* + ID_MODEL_FROM_DATABASE=TEW-621PC 802.11bgn Wireless CardBus Adapter + +pci:v0000168Cd00000024* + ID_MODEL_FROM_DATABASE=AR5418 Wireless Network Adapter [AR5008E 802.11(a)bgn] (PCI-Express) + +pci:v0000168Cd00000024sv0000106Bsd00000087* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v0000168Cd00000024sv00001186sd00003A70* + ID_MODEL_FROM_DATABASE=DWA-556 Xtreme N PCI Express Desktop Adapter + +pci:v0000168Cd00000027* + ID_MODEL_FROM_DATABASE=AR9160 Wireless Network Adapter [AR9001 802.11(a)bgn] + +pci:v0000168Cd00000027sv00000777sd00004082* + ID_MODEL_FROM_DATABASE=SR71-A 802.11abgn Wireless Mini PCI Adapter + +pci:v0000168Cd00000029* + ID_MODEL_FROM_DATABASE=AR922X Wireless Network Adapter + +pci:v0000168Cd00000029sv00000777sd00004005* + ID_MODEL_FROM_DATABASE=SR71-15 802.11an Mini PCI Adapter + +pci:v0000168Cd00000029sv00001186sd00003A7A* + ID_MODEL_FROM_DATABASE=DWA-552 802.11n Xtreme N Desktop Adapter (rev A2) + +pci:v0000168Cd00000029sv00001186sd00003A7D* + ID_MODEL_FROM_DATABASE=DWA-552 802.11n Xtreme N Desktop Adapter (rev A3) + +pci:v0000168Cd0000002A* + ID_MODEL_FROM_DATABASE=AR928X Wireless Network Adapter (PCI-Express) + +pci:v0000168Cd0000002Asv00000777sd00004F05* + ID_MODEL_FROM_DATABASE=SR71-X 802.11abgn Wireless ExpressCard Adapter [AR9280] + +pci:v0000168Cd0000002Asv0000103Csd00003041* + ID_MODEL_FROM_DATABASE=AR5BHB92-H 802.11abgn Wireless Half-size Mini PCIe Card [AR9280] + +pci:v0000168Cd0000002Asv0000105Bsd0000E006* + ID_MODEL_FROM_DATABASE=T77H053.00 802.11bgn Wireless Mini PCIe Card [AR9281] + +pci:v0000168Cd0000002Asv0000105Bsd0000E01F* + ID_MODEL_FROM_DATABASE=T77H047.31 802.11bgn Wireless Half-size Mini PCIe Card [AR9283] + +pci:v0000168Cd0000002Asv0000106Bsd0000008F* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v0000168Cd0000002Asv000011ADsd00006600* + ID_MODEL_FROM_DATABASE=WN6600A 802.11bgn Wireless Mini PCIe Card [AR9281] + +pci:v0000168Cd0000002Asv0000144Fsd00007141* + ID_MODEL_FROM_DATABASE=WLL6080 802.11bgn Wireless Mini PCIe Card [AR9281] + +pci:v0000168Cd0000002Asv0000168Csd00000203* + ID_MODEL_FROM_DATABASE=DW1525 802.11abgn WLAN PCIe Card [AR9280] + +pci:v0000168Cd0000002Asv00001A32sd00000303* + ID_MODEL_FROM_DATABASE=EM303 802.11bgn Wireless Mini PCIe Card [AR9281] + +pci:v0000168Cd0000002Asv00001A32sd00000306* + ID_MODEL_FROM_DATABASE=EM306 802.11bgn Wireless Half-size Mini PCIe Card [AR9283] + +pci:v0000168Cd0000002Asv00001A3Bsd00001067* + ID_MODEL_FROM_DATABASE=AW-NE771 802.11bgn Wireless Mini PCIe Card [AR9281] + +pci:v0000168Cd0000002Asv00001A3Bsd00001081* + ID_MODEL_FROM_DATABASE=AW-NE773 802.11abgn Wireless Half-size Mini PCIe Card [AR9280] + +pci:v0000168Cd0000002B* + ID_MODEL_FROM_DATABASE=AR9285 Wireless Network Adapter (PCI-Express) + +pci:v0000168Cd0000002Bsv00001028sd00000204* + ID_MODEL_FROM_DATABASE=Wireless 1502 802.11bgn Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv00001028sd00000205* + ID_MODEL_FROM_DATABASE=Wireless 1702 802.11bgn Half-size Mini PCIe Card [AR9002WB-1NGCD] + +pci:v0000168Cd0000002Bsv0000103Csd0000303F* + ID_MODEL_FROM_DATABASE=U98Z062.10 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv0000103Csd00003040* + ID_MODEL_FROM_DATABASE=U98Z062.12 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv0000105Bsd0000E017* + ID_MODEL_FROM_DATABASE=T77H126.00 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv0000105Bsd0000E023* + ID_MODEL_FROM_DATABASE=T77H121.04 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv00001113sd0000E811* + ID_MODEL_FROM_DATABASE=WN7811A (Toshiba PA3722U-1MPC) 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv0000185Fsd000030AF* + ID_MODEL_FROM_DATABASE=DNXA-95 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv00001931sd00000023* + ID_MODEL_FROM_DATABASE=Option GTM67x PCIe WiFi Adapter + +pci:v0000168Cd0000002Bsv00001A3Bsd00001089* + ID_MODEL_FROM_DATABASE=AW-NE785 / AW-NE785H 802.11bgn Wireless Full or Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv00001A3Bsd00002C37* + ID_MODEL_FROM_DATABASE=AW-NB037H 802.11bgn Wireless Half-size Mini PCIe Card [AR9002WB-1NGCD] + +pci:v0000168Cd0000002Bsv00001B9Asd00000401* + ID_MODEL_FROM_DATABASE=XW204E 802.11bgn Wireless Half-size Mini PCIe Card + +pci:v0000168Cd0000002Bsv00001B9Asd00000C03* + ID_MODEL_FROM_DATABASE=WB214E 802.11bgn Wireless Half-size Mini PCIe Card [AR9002WB-1NGCD] + +pci:v0000168Cd0000002C* + ID_MODEL_FROM_DATABASE=AR2427 802.11bg Wireless Network Adapter (PCI-Express) + +pci:v0000168Cd0000002D* + ID_MODEL_FROM_DATABASE=AR9227 Wireless Network Adapter + +pci:v0000168Cd0000002E* + ID_MODEL_FROM_DATABASE=AR9287 Wireless Network Adapter (PCI-Express) + +pci:v0000168Cd00000030* + ID_MODEL_FROM_DATABASE=AR93xx Wireless Network Adapter + +pci:v0000168Cd00000030sv0000103Csd00001627* + ID_MODEL_FROM_DATABASE=AR9380/HB112 802.11abgn 3×3 Wi-Fi Adapter + +pci:v0000168Cd00000030sv0000106Bsd0000009A* + ID_MODEL_FROM_DATABASE=AirPort Extreme + +pci:v0000168Cd00000030sv00001186sd00003A7E* + ID_MODEL_FROM_DATABASE=DWA-566 Wireless N 300 Dual Band PCIe Desktop Adapter + +pci:v0000168Cd00000030sv00001A56sd00002000* + ID_MODEL_FROM_DATABASE=Killer Wireless-N 1102 Half-size Mini PCIe Card [AR9382] + +pci:v0000168Cd00000030sv00001A56sd00002001* + ID_MODEL_FROM_DATABASE=Killer Wireless-N 1103 Half-size Mini PCIe Card [AR9380] + +pci:v0000168Cd00000032* + ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter + +pci:v0000168Cd00000032sv0000103Csd00001838* + ID_MODEL_FROM_DATABASE=AR9485/HB125 802.11bgn 1×1 Wi-Fi Adapter + +pci:v0000168Cd00000033* + ID_MODEL_FROM_DATABASE=AR9580 Wireless Network Adapter + +pci:v0000168Cd00000034* + ID_MODEL_FROM_DATABASE=AR9462 Wireless Network Adapter + +pci:v0000168Cd00000034sv00001A56sd00002003* + ID_MODEL_FROM_DATABASE=Killer Wireless-N 1202 Half-size Mini PCIe Card + +pci:v0000168Cd00000036* + ID_MODEL_FROM_DATABASE=QCA9565 / AR9565 Wireless Network Adapter + +pci:v0000168Cd00000037* + ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter + +pci:v0000168Cd00000037sv00001A3Bsd00002100* + ID_MODEL_FROM_DATABASE=AW-NB100H 802.11n Wireless Mini PCIe Card + +pci:v0000168Cd0000003C* + ID_MODEL_FROM_DATABASE=QCA988x 802.11ac Wireless Network Adapter + +pci:v0000168Cd00000207* + ID_MODEL_FROM_DATABASE=AR5210 Wireless Network Adapter [AR5000 802.11a] + +pci:v0000168Cd00001014* + ID_MODEL_FROM_DATABASE=AR5212 802.11abg NIC + +pci:v0000168Cd00001014sv00001014sd0000058A* + ID_MODEL_FROM_DATABASE=ThinkPad 11a/b/g Wireless LAN Mini Express Adapter (AR5BXB6) + +pci:v0000168Cd00009013* + ID_MODEL_FROM_DATABASE=AR5002X Wireless Network Adapter + +pci:v0000168Cd0000FF19* + ID_MODEL_FROM_DATABASE=AR5006X Wireless Network Adapter + +pci:v0000168Cd0000FF1B* + ID_MODEL_FROM_DATABASE=AR2425 Wireless Network Adapter [AR5007EG 802.11bg] + +pci:v0000168Cd0000FF1C* + ID_MODEL_FROM_DATABASE=AR5008 Wireless Network Adapter + +pci:v0000168Cd0000FF1D* + ID_MODEL_FROM_DATABASE=AR922x Wireless Network Adapter + +pci:v0000168Cd0000FF1Dsv0000168Csd0000EE1C* + ID_MODEL_FROM_DATABASE=AR9220-AC1A [AVM Fritz!Box FON WLAN 7270 v3] + +pci:v00001695* + ID_VENDOR_FROM_DATABASE=EPoX Computer Co., Ltd. + +pci:v0000169C* + ID_VENDOR_FROM_DATABASE=Netcell Corporation + +pci:v0000169Cd00000044* + ID_MODEL_FROM_DATABASE=Revolution Storage Processing Card + +pci:v0000169D* + ID_VENDOR_FROM_DATABASE=Club-3D VB (Wrong ID) + +pci:v000016A5* + ID_VENDOR_FROM_DATABASE=Tekram Technology Co.,Ltd. + +pci:v000016AB* + ID_VENDOR_FROM_DATABASE=Global Sun Technology Inc + +pci:v000016ABd00001100* + ID_MODEL_FROM_DATABASE=GL24110P + +pci:v000016ABd00001101* + ID_MODEL_FROM_DATABASE=PLX9052 PCMCIA-to-PCI Wireless LAN + +pci:v000016ABd00001102* + ID_MODEL_FROM_DATABASE=PCMCIA-to-PCI Wireless Network Bridge + +pci:v000016ABd00008501* + ID_MODEL_FROM_DATABASE=WL-8305 Wireless LAN PCI Adapter + +pci:v000016AE* + ID_VENDOR_FROM_DATABASE=SafeNet Inc + +pci:v000016AEd00000001* + ID_MODEL_FROM_DATABASE=SafeXcel 1140 + +pci:v000016AEd0000000A* + ID_MODEL_FROM_DATABASE=SafeXcel 1841 + +pci:v000016AEd00001141* + ID_MODEL_FROM_DATABASE=SafeXcel 1141 + +pci:v000016AEd00001841* + ID_MODEL_FROM_DATABASE=SafeXcel 1842 + +pci:v000016AF* + ID_VENDOR_FROM_DATABASE=SparkLAN Communications, Inc. + +pci:v000016B4* + ID_VENDOR_FROM_DATABASE=Aspex Semiconductor Ltd + +pci:v000016B8* + ID_VENDOR_FROM_DATABASE=Sonnet Technologies, Inc. + +pci:v000016BE* + ID_VENDOR_FROM_DATABASE=Creatix Polymedia GmbH + +pci:v000016C6* + ID_VENDOR_FROM_DATABASE=Micrel-Kendin + +pci:v000016C6d00008695* + ID_MODEL_FROM_DATABASE=Centaur KS8695 ARM processor + +pci:v000016C6d00008842* + ID_MODEL_FROM_DATABASE=KSZ8842-PMQL 2-Port Ethernet Switch + +pci:v000016C8* + ID_VENDOR_FROM_DATABASE=Octasic Inc. + +pci:v000016C9* + ID_VENDOR_FROM_DATABASE=EONIC B.V. The Netherlands + +pci:v000016CA* + ID_VENDOR_FROM_DATABASE=CENATEK Inc + +pci:v000016CAd00000001* + ID_MODEL_FROM_DATABASE=Rocket Drive DL + +pci:v000016CD* + ID_VENDOR_FROM_DATABASE=Advantech Co. Ltd + +pci:v000016CDd00000101* + ID_MODEL_FROM_DATABASE=DirectPCI SRAM for DPX-11x series + +pci:v000016CDd00000102* + ID_MODEL_FROM_DATABASE=DirectPCI SRAM for DPX-S/C/E-series + +pci:v000016CDd00000103* + ID_MODEL_FROM_DATABASE=DirectPCI ROM for DPX-11x series + +pci:v000016CDd00000104* + ID_MODEL_FROM_DATABASE=DirectPCI ROM for DPX-S/C/E-series + +pci:v000016CDd00000105* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-114/DPX-115 + +pci:v000016CDd00000106* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-116 + +pci:v000016CDd00000107* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-116U + +pci:v000016CDd00000108* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-117 + +pci:v000016CDd00000109* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-112 + +pci:v000016CDd0000010A* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-C/E-series + +pci:v000016CDd0000010B* + ID_MODEL_FROM_DATABASE=DirectPCI I/O for DPX-S series + +pci:v000016CE* + ID_VENDOR_FROM_DATABASE=Roland Corp. + +pci:v000016D5* + ID_VENDOR_FROM_DATABASE=Acromag, Inc. + +pci:v000016D5d00000504* + ID_MODEL_FROM_DATABASE=PMC-DX504 Reconfigurable FPGA with LVDS I/O + +pci:v000016D5d00000520* + ID_MODEL_FROM_DATABASE=PMC520 Serial Communication, 232 Octal + +pci:v000016D5d00000521* + ID_MODEL_FROM_DATABASE=PMC521 Serial Communication, 422/485 Octal + +pci:v000016D5d00001020* + ID_MODEL_FROM_DATABASE=PMC-AX1020 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00001065* + ID_MODEL_FROM_DATABASE=PMC-AX1065 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00002004* + ID_MODEL_FROM_DATABASE=PMC-DX2004 Reconfigurable FPGA with LVDS I/O + +pci:v000016D5d00002020* + ID_MODEL_FROM_DATABASE=PMC-AX2020 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00002065* + ID_MODEL_FROM_DATABASE=PMC-AX2065 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00003020* + ID_MODEL_FROM_DATABASE=PMC-AX3020 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00003065* + ID_MODEL_FROM_DATABASE=PMC-AX3065 Reconfigurable FPGA with A/D & D/A + +pci:v000016D5d00004243* + ID_MODEL_FROM_DATABASE=PMC424, APC424, AcPC424 Digital I/O and Counter Timer Module + +pci:v000016D5d00004248* + ID_MODEL_FROM_DATABASE=PMC464, APC464, AcPC464 Digital I/O and Counter Timer Module + +pci:v000016D5d0000424B* + ID_MODEL_FROM_DATABASE=PMC-DX2002 Reconfigurable FPGA with Differential I/O + +pci:v000016D5d00004253* + ID_MODEL_FROM_DATABASE=PMC-DX503 Reconfigurable FPGA with TTL and Differential I/O + +pci:v000016D5d00004312* + ID_MODEL_FROM_DATABASE=PMC-CX1002 Reconfigurable Conduction-Cooled FPGA Virtex-II with Differential I/O + +pci:v000016D5d00004313* + ID_MODEL_FROM_DATABASE=PMC-CX1003 Reconfigurable Conduction-Cooled FPGA Virtex-II with CMOS and Differential I/O + +pci:v000016D5d00004322* + ID_MODEL_FROM_DATABASE=PMC-CX2002 Reconfigurable Conduction-Cooled FPGA Virtex-II with Differential I/O + +pci:v000016D5d00004323* + ID_MODEL_FROM_DATABASE=PMC-CX2003 Reconfigurable Conduction-Cooled FPGA Virtex-II with CMOS and Differential I/O + +pci:v000016D5d00004350* + ID_MODEL_FROM_DATABASE=PMC-DX501 Reconfigurable Digital I/O Module + +pci:v000016D5d00004353* + ID_MODEL_FROM_DATABASE=PMC-DX2003 Reconfigurable FPGA with TTL and Differential I/O + +pci:v000016D5d00004357* + ID_MODEL_FROM_DATABASE=PMC-DX502 Reconfigurable Differential I/O Module + +pci:v000016D5d00004457* + ID_MODEL_FROM_DATABASE=PMC730, APC730, AcPC730 Multifunction Module + +pci:v000016D5d0000464D* + ID_MODEL_FROM_DATABASE=PMC408 32-Channel Digital Input/Output Module + +pci:v000016D5d00004850* + ID_MODEL_FROM_DATABASE=PMC220-16 12-Bit Analog Output Module + +pci:v000016D5d00004A42* + ID_MODEL_FROM_DATABASE=PMC483, APC483, AcPC483 Counter Timer Module + +pci:v000016D5d00004A50* + ID_MODEL_FROM_DATABASE=PMC484, APC484, AcPC484 Counter Timer Module + +pci:v000016D5d00004A56* + ID_MODEL_FROM_DATABASE=PMC230 16-Bit Analog Output Module + +pci:v000016D5d00004B47* + ID_MODEL_FROM_DATABASE=PMC330, APC330, AcPC330 Analog Input Module, 16-bit A/D + +pci:v000016D5d00004C40* + ID_MODEL_FROM_DATABASE=PMC-LX40 Reconfigurable Virtex-4 FPGA with plug-in I/O + +pci:v000016D5d00004C60* + ID_MODEL_FROM_DATABASE=PMC-LX60 Reconfigurable Virtex-4 FPGA with plug-in I/O + +pci:v000016D5d00004D4D* + ID_MODEL_FROM_DATABASE=PMC341, APC341, AcPC341 Analog Input Module, Simultaneous Sample & Hold + +pci:v000016D5d00004D4E* + ID_MODEL_FROM_DATABASE=PMC482, APC482, AcPC482 Counter Timer Board + +pci:v000016D5d0000524D* + ID_MODEL_FROM_DATABASE=PMC-DX2001 Reconfigurable FPGA with TTL I/O + +pci:v000016D5d00005335* + ID_MODEL_FROM_DATABASE=PMC-SX35 Reconfigurable Virtex-4 FPGA with plug-in I/O + +pci:v000016D5d00005456* + ID_MODEL_FROM_DATABASE=PMC470 48-Channel Digital Input/Output Module + +pci:v000016D5d00005601* + ID_MODEL_FROM_DATABASE=PMC-VLX85 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005602* + ID_MODEL_FROM_DATABASE=PMC-VLX110 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005603* + ID_MODEL_FROM_DATABASE=PMC-VSX95 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005604* + ID_MODEL_FROM_DATABASE=PMC-VLX155 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005605* + ID_MODEL_FROM_DATABASE=PMC-VFX70 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005606* + ID_MODEL_FROM_DATABASE=PMC-VLX155-1M Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005701* + ID_MODEL_FROM_DATABASE=PMC-SLX150: Reconfigurable Spartan-6 FPGA with plug-in I/O + +pci:v000016D5d00005702* + ID_MODEL_FROM_DATABASE=PMC-SLX150-1M: Reconfigurable Spartan-6 FPGA with plug-in I/O + +pci:v000016D5d00005801* + ID_MODEL_FROM_DATABASE=XMC-VLX85 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005802* + ID_MODEL_FROM_DATABASE=XMC-VLX110 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005803* + ID_MODEL_FROM_DATABASE=XMC-VSX95 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005804* + ID_MODEL_FROM_DATABASE=XMC-VLX155 Reconfigurable Virtex-5 FPGA with plug-in I/O + +pci:v000016D5d00005807* + ID_MODEL_FROM_DATABASE=XMC-SLX150: Reconfigurable Spartan-6 FPGA with plug-in I/O + +pci:v000016D5d00005808* + ID_MODEL_FROM_DATABASE=XMC-SLX150-1M: Reconfigurable Spartan-6 FPGA with plug-in I/O + +pci:v000016D5d00005901* + ID_MODEL_FROM_DATABASE=APCe8650 PCI Express IndustryPack Carrier Card + +pci:v000016D5d00006301* + ID_MODEL_FROM_DATABASE=XMC Module with user-configurable Virtex-6 FPGA, 240k logic cells, SFP front I/O + +pci:v000016D5d00006302* + ID_MODEL_FROM_DATABASE=XMC Module with user-configurable Virtex-6 FPGA, 365k logic cells, SFP front I/O + +pci:v000016D5d00006303* + ID_MODEL_FROM_DATABASE=XMC Module with user-configurable Virtex-6 FPGA, 240k logic cells, no front I/O + +pci:v000016D5d00006304* + ID_MODEL_FROM_DATABASE=XMC Module with user-configurable Virtex-6 FPGA, 365k logic cells, no front I/O + +pci:v000016DA* + ID_VENDOR_FROM_DATABASE=Advantech Co., Ltd. + +pci:v000016DAd00000011* + ID_MODEL_FROM_DATABASE=INES GPIB-PCI + +pci:v000016DF* + ID_VENDOR_FROM_DATABASE=PIKA Technologies Inc. + +pci:v000016E2* + ID_VENDOR_FROM_DATABASE=Geotest-MTS + +pci:v000016E3* + ID_VENDOR_FROM_DATABASE=European Space Agency + +pci:v000016E3d00001E0F* + ID_MODEL_FROM_DATABASE=LEON2FT Processor + +pci:v000016E5* + ID_VENDOR_FROM_DATABASE=Intellon Corp. + +pci:v000016E5d00006000* + ID_MODEL_FROM_DATABASE=INT6000 Ethernet-to-Powerline Bridge [HomePlug AV] + +pci:v000016E5d00006300* + ID_MODEL_FROM_DATABASE=INT6300 Ethernet-to-Powerline Bridge [HomePlug AV] + +pci:v000016EC* + ID_VENDOR_FROM_DATABASE=U.S. Robotics + +pci:v000016ECd000000ED* + ID_MODEL_FROM_DATABASE=USR997900 + +pci:v000016ECd00000116* + ID_MODEL_FROM_DATABASE=USR997902 10/100/1000 Mbps PCI Network Card + +pci:v000016ECd00002F00* + ID_MODEL_FROM_DATABASE=USR5660A (USR265660A, USR5660A-BP) 56K PCI Faxmodem + +pci:v000016ECd00003685* + ID_MODEL_FROM_DATABASE=Wireless Access PCI Adapter Model 022415 + +pci:v000016ECd00004320* + ID_MODEL_FROM_DATABASE=USR997904 10/100/1000 64-bit NIC (Marvell Yukon) + +pci:v000016ECd0000AB06* + ID_MODEL_FROM_DATABASE=USR997901A 10/100 Cardbus NIC + +pci:v000016ED* + ID_VENDOR_FROM_DATABASE=Sycron N. V. + +pci:v000016EDd00001001* + ID_MODEL_FROM_DATABASE=UMIO communication card + +pci:v000016F3* + ID_VENDOR_FROM_DATABASE=Jetway Information Co., Ltd. + +pci:v000016F4* + ID_VENDOR_FROM_DATABASE=Vweb Corp + +pci:v000016F4d00008000* + ID_MODEL_FROM_DATABASE=VW2010 + +pci:v000016F6* + ID_VENDOR_FROM_DATABASE=VideoTele.com, Inc. + +pci:v00001702* + ID_VENDOR_FROM_DATABASE=Internet Machines Corporation (IMC) + +pci:v00001705* + ID_VENDOR_FROM_DATABASE=Digital First, Inc. + +pci:v0000170B* + ID_VENDOR_FROM_DATABASE=NetOctave + +pci:v0000170Bd00000100* + ID_MODEL_FROM_DATABASE=NSP2000-SSL crypto accelerator + +pci:v0000170C* + ID_VENDOR_FROM_DATABASE=YottaYotta Inc. + +pci:v00001719* + ID_VENDOR_FROM_DATABASE=EZChip Technologies + +pci:v00001719d00001000* + ID_MODEL_FROM_DATABASE=NPA Access Network Processor Family + +pci:v00001725* + ID_VENDOR_FROM_DATABASE=Vitesse Semiconductor + +pci:v00001725d00007174* + ID_MODEL_FROM_DATABASE=VSC7174 PCI/PCI-X Serial ATA Host Bus Controller + +pci:v0000172A* + ID_VENDOR_FROM_DATABASE=Accelerated Encryption + +pci:v0000172Ad000013C8* + ID_MODEL_FROM_DATABASE=AEP SureWare Runner 1000V3 + +pci:v00001734* + ID_VENDOR_FROM_DATABASE=Fujitsu Technology Solutions + +pci:v00001735* + ID_VENDOR_FROM_DATABASE=Aten International Co. Ltd. + +pci:v00001737* + ID_VENDOR_FROM_DATABASE=Linksys + +pci:v00001737d00000029* + ID_MODEL_FROM_DATABASE=WPG54G ver. 4 PCI Card + +pci:v00001737d00001032* + ID_MODEL_FROM_DATABASE=Gigabit Network Adapter + +pci:v00001737d00001032sv00001737sd00000015* + ID_MODEL_FROM_DATABASE=EG1032 v2 Instant Gigabit Network Adapter + +pci:v00001737d00001032sv00001737sd00000024* + ID_MODEL_FROM_DATABASE=EG1032 v3 Instant Gigabit Network Adapter + +pci:v00001737d00001064* + ID_MODEL_FROM_DATABASE=Gigabit Network Adapter + +pci:v00001737d00001064sv00001737sd00000016* + ID_MODEL_FROM_DATABASE=EG1064 v2 Instant Gigabit Network Adapter + +pci:v00001737d0000AB08* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v00001737d0000AB09* + ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + +pci:v0000173B* + ID_VENDOR_FROM_DATABASE=Altima (nee Broadcom) + +pci:v0000173Bd000003E8* + ID_MODEL_FROM_DATABASE=AC1000 Gigabit Ethernet + +pci:v0000173Bd000003E9* + ID_MODEL_FROM_DATABASE=AC1001 Gigabit Ethernet + +pci:v0000173Bd000003EA* + ID_MODEL_FROM_DATABASE=AC9100 Gigabit Ethernet + +pci:v0000173Bd000003EAsv0000173Bsd00000001* + ID_MODEL_FROM_DATABASE=AC1002 + +pci:v0000173Bd000003EB* + ID_MODEL_FROM_DATABASE=AC1003 Gigabit Ethernet + +pci:v00001743* + ID_VENDOR_FROM_DATABASE=Peppercon AG + +pci:v00001743d00008139* + ID_MODEL_FROM_DATABASE=ROL/F-100 Fast Ethernet Adapter with ROL + +pci:v00001745* + ID_VENDOR_FROM_DATABASE=ViXS Systems, Inc. + +pci:v00001745d00002020* + ID_MODEL_FROM_DATABASE=XCode II Series + +pci:v00001745d00002100* + ID_MODEL_FROM_DATABASE=XCode 2100 Series + +pci:v00001749* + ID_VENDOR_FROM_DATABASE=RLX Technologies + +pci:v0000174B* + ID_VENDOR_FROM_DATABASE=PC Partner Limited / Sapphire Technology + +pci:v0000174D* + ID_VENDOR_FROM_DATABASE=WellX Telecom SA + +pci:v0000175C* + ID_VENDOR_FROM_DATABASE=AudioScience Inc + +pci:v0000175E* + ID_VENDOR_FROM_DATABASE=Sanera Systems, Inc. + +pci:v00001760* + ID_VENDOR_FROM_DATABASE=TEDIA spol. s r. o. + +pci:v00001760d00000101* + ID_MODEL_FROM_DATABASE=PCD-7004 Digital Bi-Directional Ports PCI Card + +pci:v00001760d00000102* + ID_MODEL_FROM_DATABASE=PCD-7104 Digital Input & Output PCI Card + +pci:v00001771* + ID_VENDOR_FROM_DATABASE=InnoVISION Multimedia Ltd. + +pci:v00001775* + ID_VENDOR_FROM_DATABASE=GE Intelligent Platforms + +pci:v0000177D* + ID_VENDOR_FROM_DATABASE=Cavium Networks + +pci:v0000177Dd00000001* + ID_MODEL_FROM_DATABASE=Nitrox XL N1 + +pci:v0000177Dd00000003* + ID_MODEL_FROM_DATABASE=Nitrox XL N1 Lite + +pci:v0000177Dd00000004* + ID_MODEL_FROM_DATABASE=Octeon (and older) FIPS + +pci:v0000177Dd00000005* + ID_MODEL_FROM_DATABASE=Octeon CN38XX Network Processor Pass 3.x + +pci:v0000177Dd00000006* + ID_MODEL_FROM_DATABASE=RoHS + +pci:v0000177Dd00000010* + ID_MODEL_FROM_DATABASE=Nitrox XL NPX + +pci:v0000177Dd00000020* + ID_MODEL_FROM_DATABASE=Octeon CN31XX Network Processor + +pci:v0000177Dd00000030* + ID_MODEL_FROM_DATABASE=Octeon CN30XX Network Processor + +pci:v0000177Dd00000040* + ID_MODEL_FROM_DATABASE=Octeon CN58XX Network Processor + +pci:v0000177Dd00000050* + ID_MODEL_FROM_DATABASE=Octeon CN57XX Network Processor (CN54XX/CN55XX/CN56XX) + +pci:v0000177Dd00000070* + ID_MODEL_FROM_DATABASE=Octeon CN50XX Network Processor + +pci:v0000177Dd00000080* + ID_MODEL_FROM_DATABASE=Octeon CN52XX Network Processor + +pci:v0000177Dd00000090* + ID_MODEL_FROM_DATABASE=Octeon II CN63XX Network Processor + +pci:v0000177Dd00000091* + ID_MODEL_FROM_DATABASE=Octeon II CN68XX Network Processor + +pci:v0000177Dd00000092* + ID_MODEL_FROM_DATABASE=Octeon II CN65XX Network Processor + +pci:v0000177Dd00000093* + ID_MODEL_FROM_DATABASE=Octeon II CN61XX Network Processor + +pci:v0000177Dd00000094* + ID_MODEL_FROM_DATABASE=Octeon Fusion CNF71XX Cell processor + +pci:v0000177Dd00000095* + ID_MODEL_FROM_DATABASE=Octeon III CN78XX Network Processor + +pci:v0000177Dd00000096* + ID_MODEL_FROM_DATABASE=Octeon III CN70XX Network Processor + +pci:v00001787* + ID_VENDOR_FROM_DATABASE=Hightech Information System Ltd. + +pci:v00001789* + ID_VENDOR_FROM_DATABASE=Ennyah Technologies Corp. + +pci:v00001796* + ID_VENDOR_FROM_DATABASE=Research Centre Juelich + +pci:v00001796d00000001* + ID_MODEL_FROM_DATABASE=SIS1100 [Gigabit link] + +pci:v00001796d00000002* + ID_MODEL_FROM_DATABASE=HOTlink + +pci:v00001796d00000003* + ID_MODEL_FROM_DATABASE=Counter Timer + +pci:v00001796d00000004* + ID_MODEL_FROM_DATABASE=CAMAC Controller + +pci:v00001796d00000005* + ID_MODEL_FROM_DATABASE=PROFIBUS + +pci:v00001796d00000006* + ID_MODEL_FROM_DATABASE=AMCC HOTlink + +pci:v00001796d0000000D* + ID_MODEL_FROM_DATABASE=Synchronisation Slave + +pci:v00001796d0000000E* + ID_MODEL_FROM_DATABASE=SIS1100-eCMC + +pci:v00001796d0000000F* + ID_MODEL_FROM_DATABASE=TDC (GPX) + +pci:v00001796d00000010* + ID_MODEL_FROM_DATABASE=PCIe Counter Timer + +pci:v00001796d00000011* + ID_MODEL_FROM_DATABASE=SIS1100-e single link + +pci:v00001796d00000012* + ID_MODEL_FROM_DATABASE=SIS1100-e quad link + +pci:v00001797* + ID_VENDOR_FROM_DATABASE=Techwell Inc. + +pci:v00001797d00006801* + ID_MODEL_FROM_DATABASE=TW6802 multimedia video card + +pci:v00001797d00006802* + ID_MODEL_FROM_DATABASE=TW6802 multimedia other device + +pci:v00001797d00006810* + ID_MODEL_FROM_DATABASE=TW6816 multimedia video controller + +pci:v00001797d00006811* + ID_MODEL_FROM_DATABASE=TW6816 multimedia video controller + +pci:v00001797d00006812* + ID_MODEL_FROM_DATABASE=TW6816 multimedia video controller + +pci:v00001797d00006813* + ID_MODEL_FROM_DATABASE=TW6816 multimedia video controller + +pci:v00001799* + ID_VENDOR_FROM_DATABASE=Belkin + +pci:v00001799d00006001* + ID_MODEL_FROM_DATABASE=F5D6001 Wireless PCI Card [Realtek RTL8180] + +pci:v00001799d00006020* + ID_MODEL_FROM_DATABASE=F5D6020 v3000 Wireless PCMCIA Card [Realtek RTL8180] + +pci:v00001799d00006060* + ID_MODEL_FROM_DATABASE=F5D6060 Wireless PDA Card + +pci:v00001799d0000700F* + ID_MODEL_FROM_DATABASE=F5D7000 v7000 Wireless G Desktop Card [Realtek RTL8185] + +pci:v00001799d0000701F* + ID_MODEL_FROM_DATABASE=F5D7010 v7000 Wireless G Notebook Card [Realtek RTL8185] + +pci:v0000179A* + ID_VENDOR_FROM_DATABASE=id Quantique + +pci:v0000179Ad00000001* + ID_MODEL_FROM_DATABASE=Quantis PCI 16Mbps + +pci:v0000179C* + ID_VENDOR_FROM_DATABASE=Data Patterns + +pci:v0000179Cd00000557* + ID_MODEL_FROM_DATABASE=DP-PCI-557 [PCI 1553B] + +pci:v0000179Cd00000566* + ID_MODEL_FROM_DATABASE=DP-PCI-566 [Intelligent PCI 1553B] + +pci:v0000179Cd00001152* + ID_MODEL_FROM_DATABASE=DP-cPCI-1152 (8-channel Isolated ADC Module) + +pci:v0000179Cd00005031* + ID_MODEL_FROM_DATABASE=DP-CPCI-5031-Synchro Module + +pci:v0000179Cd00005112* + ID_MODEL_FROM_DATABASE=DP-cPCI-5112 [MM-Carrier] + +pci:v0000179Cd00005121* + ID_MODEL_FROM_DATABASE=DP-CPCI-5121-IP Carrier + +pci:v0000179Cd00005211* + ID_MODEL_FROM_DATABASE=DP-CPCI-5211-IP Carrier + +pci:v0000179Cd00005679* + ID_MODEL_FROM_DATABASE=AGE Display Module + +pci:v000017A0* + ID_VENDOR_FROM_DATABASE=Genesys Logic, Inc + +pci:v000017A0d00007163* + ID_MODEL_FROM_DATABASE=GL9701 PCIe to PCI Bridge + +pci:v000017A0d00008083* + ID_MODEL_FROM_DATABASE=GL880 USB 1.1 UHCI controller + +pci:v000017A0d00008084* + ID_MODEL_FROM_DATABASE=GL880 USB 2.0 EHCI controller + +pci:v000017AA* + ID_VENDOR_FROM_DATABASE=Lenovo + +pci:v000017AB* + ID_VENDOR_FROM_DATABASE=Phillips Components + +pci:v000017AF* + ID_VENDOR_FROM_DATABASE=Hightech Information System Ltd. + +pci:v000017B3* + ID_VENDOR_FROM_DATABASE=Hawking Technologies + +pci:v000017B3d0000AB08* + ID_MODEL_FROM_DATABASE=PN672TX 10/100 Ethernet + +pci:v000017B4* + ID_VENDOR_FROM_DATABASE=Indra Networks, Inc. + +pci:v000017B4d00000011* + ID_MODEL_FROM_DATABASE=WebEnhance 100 GZIP Compression Card + +pci:v000017B4d00000012* + ID_MODEL_FROM_DATABASE=WebEnhance 200 GZIP Compression Card + +pci:v000017B4d00000015* + ID_MODEL_FROM_DATABASE=WebEnhance 300 GZIP Compression Card + +pci:v000017B4d00000016* + ID_MODEL_FROM_DATABASE=StorCompress 300 GZIP Compression Card + +pci:v000017B4d00000017* + ID_MODEL_FROM_DATABASE=StorSecure 300 GZIP Compression and AES Encryption Card + +pci:v000017C0* + ID_VENDOR_FROM_DATABASE=Wistron Corp. + +pci:v000017C2* + ID_VENDOR_FROM_DATABASE=Newisys, Inc. + +pci:v000017CB* + ID_VENDOR_FROM_DATABASE=Airgo Networks, Inc. + +pci:v000017CBd00000001* + ID_MODEL_FROM_DATABASE=AGN100 802.11 a/b/g True MIMO Wireless Card + +pci:v000017CBd00000001sv00001385sd00005C00* + ID_MODEL_FROM_DATABASE=WGM511 Pre-N 802.11g Wireless CardBus Adapter + +pci:v000017CBd00000001sv00001737sd00000045* + ID_MODEL_FROM_DATABASE=WMP54GX v1 802.11g Wireless-G PCI Adapter with SRX + +pci:v000017CBd00000002* + ID_MODEL_FROM_DATABASE=AGN300 802.11 a/b/g True MIMO Wireless Card + +pci:v000017CBd00000002sv00001385sd00006D00* + ID_MODEL_FROM_DATABASE=WPNT511 RangeMax 240 Mbps Wireless CardBus Adapter + +pci:v000017CBd00000002sv00001737sd00000054* + ID_MODEL_FROM_DATABASE=WPC54GX4 v1 802.11g Wireless-G Notebook Adapter with SRX400 + +pci:v000017CC* + ID_VENDOR_FROM_DATABASE=NetChip Technology, Inc + +pci:v000017CCd00002280* + ID_MODEL_FROM_DATABASE=USB 2.0 + +pci:v000017CF* + ID_VENDOR_FROM_DATABASE=Z-Com, Inc. + +pci:v000017D3* + ID_VENDOR_FROM_DATABASE=Areca Technology Corp. + +pci:v000017D3d00001110* + ID_MODEL_FROM_DATABASE=ARC-1110 4-Port PCI-X to SATA RAID Controller + +pci:v000017D3d00001120* + ID_MODEL_FROM_DATABASE=ARC-1120 8-Port PCI-X to SATA RAID Controller + +pci:v000017D3d00001130* + ID_MODEL_FROM_DATABASE=ARC-1130 12-Port PCI-X to SATA RAID Controller + +pci:v000017D3d00001160* + ID_MODEL_FROM_DATABASE=ARC-1160 16-Port PCI-X to SATA RAID Controller + +pci:v000017D3d00001170* + ID_MODEL_FROM_DATABASE=ARC-1170 24-Port PCI-X to SATA RAID Controller + +pci:v000017D3d00001201* + ID_MODEL_FROM_DATABASE=ARC-1200 2-Port PCI-Express to SATA II RAID Controller + +pci:v000017D3d00001210* + ID_MODEL_FROM_DATABASE=ARC-1210 4-Port PCI-Express to SATA RAID Controller + +pci:v000017D3d00001220* + ID_MODEL_FROM_DATABASE=ARC-1220 8-Port PCI-Express to SATA RAID Controller + +pci:v000017D3d00001222* + ID_MODEL_FROM_DATABASE=ARC-1222 8-Port PCI-Express to SAS/SATA II RAID Controller + +pci:v000017D3d00001230* + ID_MODEL_FROM_DATABASE=ARC-1230 12-Port PCI-Express to SATA RAID Controller + +pci:v000017D3d00001260* + ID_MODEL_FROM_DATABASE=ARC-1260 16-Port PCI-Express to SATA RAID Controller + +pci:v000017D3d00001280* + ID_MODEL_FROM_DATABASE=ARC-1280/1280ML 24-Port PCI-Express to SATA II RAID Controller + +pci:v000017D3d00001280sv000017D3sd00001221* + ID_MODEL_FROM_DATABASE=ARC-1221 8-Port PCI-Express to SATA RAID Controller + +pci:v000017D3d00001300* + ID_MODEL_FROM_DATABASE=ARC-1300ix-16 16-Port PCI-Express to SAS Non-RAID Host Adapter + +pci:v000017D3d00001680* + ID_MODEL_FROM_DATABASE=ARC-1680 8 port PCIe/PCI-X to SAS/SATA II RAID Controller + +pci:v000017D3d00001680sv000017D3sd00001212* + ID_MODEL_FROM_DATABASE=ARC-1212 4-Port PCIe to SAS/SATA II RAID Controller + +pci:v000017D3d00001880* + ID_MODEL_FROM_DATABASE=ARC-1880 8/12 port PCIe/PCI-X to SAS/SATA II RAID Controller + +pci:v000017D5* + ID_VENDOR_FROM_DATABASE=Exar Corp. + +pci:v000017D5d00005731* + ID_MODEL_FROM_DATABASE=Xframe 10-Gigabit Ethernet PCI-X + +pci:v000017D5d00005732* + ID_MODEL_FROM_DATABASE=Xframe II 10-Gigabit Ethernet PCI-X 2.0 + +pci:v000017D5d00005831* + ID_MODEL_FROM_DATABASE=Xframe 10-Gigabit Ethernet PCI-X + +pci:v000017D5d00005831sv0000103Csd000012D5* + ID_MODEL_FROM_DATABASE=PCI-X 133MHz 10GbE SR Fiber + +pci:v000017D5d00005831sv000010A9sd00008020* + ID_MODEL_FROM_DATABASE=Single Port 10-Gigabit Ethernet (PCI-X, Fiber) + +pci:v000017D5d00005831sv000010A9sd00008024* + ID_MODEL_FROM_DATABASE=Single Port 10-Gigabit Ethernet (PCI-X, Fiber) + +pci:v000017D5d00005832* + ID_MODEL_FROM_DATABASE=Xframe II 10-Gigabit Ethernet PCI-X 2.0 + +pci:v000017D5d00005832sv0000103Csd00001337* + ID_MODEL_FROM_DATABASE=PCI-X 266MHz 10GigE SR [AD385A] + +pci:v000017D5d00005832sv000010A9sd00008021* + ID_MODEL_FROM_DATABASE=Single Port 10-Gigabit Ethernet II (PCI-X, Fiber) + +pci:v000017D5d00005832sv000017D5sd00006020* + ID_MODEL_FROM_DATABASE=Xframe II SR + +pci:v000017D5d00005832sv000017D5sd00006021* + ID_MODEL_FROM_DATABASE=Xframe II SR, Low Profile + +pci:v000017D5d00005832sv000017D5sd00006022* + ID_MODEL_FROM_DATABASE=Xframe E SR + +pci:v000017D5d00005832sv000017D5sd00006420* + ID_MODEL_FROM_DATABASE=Xframe II LR + +pci:v000017D5d00005832sv000017D5sd00006421* + ID_MODEL_FROM_DATABASE=Xframe II LR, Low Profile + +pci:v000017D5d00005832sv000017D5sd00006422* + ID_MODEL_FROM_DATABASE=Xframe E LR + +pci:v000017D5d00005832sv000017D5sd00006C20* + ID_MODEL_FROM_DATABASE=Xframe II CX4 + +pci:v000017D5d00005832sv000017D5sd00006C21* + ID_MODEL_FROM_DATABASE=Xframe II CX4, Low Profile + +pci:v000017D5d00005832sv000017D5sd00006C22* + ID_MODEL_FROM_DATABASE=Xframe E CX4 + +pci:v000017D5d00005833* + ID_MODEL_FROM_DATABASE=X3100 Series 10 Gigabit Ethernet PCIe + +pci:v000017D5d00005833sv000017D5sd00006030* + ID_MODEL_FROM_DATABASE=X3110 Single Port SR + +pci:v000017D5d00005833sv000017D5sd00006031* + ID_MODEL_FROM_DATABASE=X3120 Dual Port SR + +pci:v000017D5d00005833sv000017D5sd00006430* + ID_MODEL_FROM_DATABASE=X3110 Single Port LR + +pci:v000017D5d00005833sv000017D5sd00006431* + ID_MODEL_FROM_DATABASE=X3120 Dual Port LR + +pci:v000017D5d00005833sv000017D5sd00007030* + ID_MODEL_FROM_DATABASE=X3110 Single Port LRM + +pci:v000017D5d00005833sv000017D5sd00007031* + ID_MODEL_FROM_DATABASE=X3120 Dual Port LRM + +pci:v000017D5d00005833sv000017D5sd00007430* + ID_MODEL_FROM_DATABASE=X3110 Single Port 10GBase-T + +pci:v000017D5d00005833sv000017D5sd00007431* + ID_MODEL_FROM_DATABASE=X3120 Dual Port 10GBase-T + +pci:v000017D5d00005833sv000017D5sd00007830* + ID_MODEL_FROM_DATABASE=X3110 Single Port 10GBase-CR + +pci:v000017D5d00005833sv000017D5sd00007831* + ID_MODEL_FROM_DATABASE=X3120 Dual Port 10GBase-CR + +pci:v000017DB* + ID_VENDOR_FROM_DATABASE=Cray Inc + +pci:v000017DBd00000101* + ID_MODEL_FROM_DATABASE=XT Series [Seastar] 3D Toroidal Router + +pci:v000017DE* + ID_VENDOR_FROM_DATABASE=KWorld Computer Co. Ltd. + +pci:v000017E4* + ID_VENDOR_FROM_DATABASE=Sectra AB + +pci:v000017E4d00000001* + ID_MODEL_FROM_DATABASE=KK671 Cardbus encryption board + +pci:v000017E4d00000002* + ID_MODEL_FROM_DATABASE=KK672 Cardbus encryption board + +pci:v000017E6* + ID_VENDOR_FROM_DATABASE=Entropic Communications Inc. + +pci:v000017E6d00000010* + ID_MODEL_FROM_DATABASE=EN2010 [c.Link] MoCA Network Controller (Coax, PCI interface) + +pci:v000017E6d00000011* + ID_MODEL_FROM_DATABASE=EN2010 [c.Link] MoCA Network Controller (Coax, MPEG interface) + +pci:v000017E6d00000021* + ID_MODEL_FROM_DATABASE=EN2210 [c.Link] MoCA Network Controller (Coax) + +pci:v000017E6d00000025* + ID_MODEL_FROM_DATABASE=EN2510 [c.Link] MoCA Network Controller (Coax, PCIe interface) + +pci:v000017E6d00000027* + ID_MODEL_FROM_DATABASE=EN2710 [c.Link] MoCA 2.0 Network Controller (Coax, PCIe interface) + +pci:v000017EE* + ID_VENDOR_FROM_DATABASE=Connect Components Ltd + +pci:v000017F2* + ID_VENDOR_FROM_DATABASE=Albatron Corp. + +pci:v000017F3* + ID_VENDOR_FROM_DATABASE=RDC Semiconductor, Inc. + +pci:v000017F3d00001010* + ID_MODEL_FROM_DATABASE=R1010 IDE Controller + +pci:v000017F3d00006020* + ID_MODEL_FROM_DATABASE=R6020 North Bridge + +pci:v000017F3d00006021* + ID_MODEL_FROM_DATABASE=R6021 Host Bridge + +pci:v000017F3d00006030* + ID_MODEL_FROM_DATABASE=R6030 ISA Bridge + +pci:v000017F3d00006031* + ID_MODEL_FROM_DATABASE=R6031 ISA Bridge + +pci:v000017F3d00006040* + ID_MODEL_FROM_DATABASE=R6040 MAC Controller + +pci:v000017F3d00006060* + ID_MODEL_FROM_DATABASE=R6060 USB 1.1 Controller + +pci:v000017F3d00006061* + ID_MODEL_FROM_DATABASE=R6061 USB 2.0 Controller + +pci:v000017F7* + ID_VENDOR_FROM_DATABASE=Topdek Semiconductor Inc. + +pci:v000017F9* + ID_VENDOR_FROM_DATABASE=Gemtek Technology Co., Ltd + +pci:v000017FC* + ID_VENDOR_FROM_DATABASE=IOGEAR, Inc. + +pci:v000017FE* + ID_VENDOR_FROM_DATABASE=InProComm Inc. + +pci:v000017FEd00002120* + ID_MODEL_FROM_DATABASE=IPN 2120 802.11b + +pci:v000017FEd00002120sv00001737sd00000020* + ID_MODEL_FROM_DATABASE=WMP11 v4 802.11b Wireless-B PCI Adapter + +pci:v000017FEd00002220* + ID_MODEL_FROM_DATABASE=IPN 2220 802.11g + +pci:v000017FEd00002220sv00001468sd00000305* + ID_MODEL_FROM_DATABASE=T60N871 802.11g Mini PCI Wireless Adapter + +pci:v000017FEd00002220sv00001737sd00000029* + ID_MODEL_FROM_DATABASE=WPC54G v4 802.11g Wireless-G Notebook Adapter + +pci:v000017FF* + ID_VENDOR_FROM_DATABASE=Benq Corporation + +pci:v00001803* + ID_VENDOR_FROM_DATABASE=ProdaSafe GmbH + +pci:v00001805* + ID_VENDOR_FROM_DATABASE=Euresys S.A. + +pci:v00001809* + ID_VENDOR_FROM_DATABASE=Lumanate, Inc. + +pci:v00001813* + ID_VENDOR_FROM_DATABASE=Ambient Technologies Inc + +pci:v00001813d00004000* + ID_MODEL_FROM_DATABASE=HaM controllerless modem + +pci:v00001813d00004000sv000016BEsd00000001* + ID_MODEL_FROM_DATABASE=V9x HAM Data Fax Modem + +pci:v00001813d00004100* + ID_MODEL_FROM_DATABASE=HaM plus Data Fax Modem + +pci:v00001813d00004100sv000016BEsd00000002* + ID_MODEL_FROM_DATABASE=V9x HAM 1394 + +pci:v00001814* + ID_VENDOR_FROM_DATABASE=Ralink corp. + +pci:v00001814d00000101* + ID_MODEL_FROM_DATABASE=Wireless PCI Adapter RT2400 / RT2460 + +pci:v00001814d00000101sv00001043sd00000127* + ID_MODEL_FROM_DATABASE=WiFi-b add-on Card + +pci:v00001814d00000101sv00001371sd00000010* + ID_MODEL_FROM_DATABASE=Minitar MNW2BPCI Wireless PCI Card + +pci:v00001814d00000101sv00001462sd00006828* + ID_MODEL_FROM_DATABASE=PC11B2 (MS-6828) Wireless 11b PCI Card + +pci:v00001814d00000200* + ID_MODEL_FROM_DATABASE=RT2500 802.11g PCI [PC54G2] + +pci:v00001814d00000201* + ID_MODEL_FROM_DATABASE=RT2500 Wireless 802.11bg + +pci:v00001814d00000201sv00001043sd0000130F* + ID_MODEL_FROM_DATABASE=WL-130g + +pci:v00001814d00000201sv00001186sd00003C00* + ID_MODEL_FROM_DATABASE=DWL-G650X Wireless 11g CardBus Adapter + +pci:v00001814d00000201sv00001371sd0000001E* + ID_MODEL_FROM_DATABASE=CWC-854 Wireless-G CardBus Adapter + +pci:v00001814d00000201sv00001371sd0000001F* + ID_MODEL_FROM_DATABASE=CWM-854 Wireless-G Mini PCI Adapter + +pci:v00001814d00000201sv00001371sd00000020* + ID_MODEL_FROM_DATABASE=CWP-854 Wireless-G PCI Adapter + +pci:v00001814d00000201sv00001458sd0000E381* + ID_MODEL_FROM_DATABASE=GN-WMKG 802.11b/g Wireless CardBus Adapter + +pci:v00001814d00000201sv00001458sd0000E931* + ID_MODEL_FROM_DATABASE=GN-WIKG 802.11b/g mini-PCI Adapter + +pci:v00001814d00000201sv00001462sd00006833* + ID_MODEL_FROM_DATABASE=Unknown 802.11g mini-PCI Adapter + +pci:v00001814d00000201sv00001462sd00006835* + ID_MODEL_FROM_DATABASE=Wireless 11G CardBus CB54G2 + +pci:v00001814d00000201sv00001737sd00000032* + ID_MODEL_FROM_DATABASE=WMP54G v4.0 PCI Adapter + +pci:v00001814d00000201sv00001799sd0000700A* + ID_MODEL_FROM_DATABASE=F5D7000 v2000/v3000 Wireless G Desktop Card + +pci:v00001814d00000201sv00001799sd0000701A* + ID_MODEL_FROM_DATABASE=F5D7010 v2000/v3000 Wireless G Notebook Card + +pci:v00001814d00000201sv00001814sd00002560* + ID_MODEL_FROM_DATABASE=RT2500 Wireless 802.11bg + +pci:v00001814d00000201sv0000182Dsd00009073* + ID_MODEL_FROM_DATABASE=WL-115 Wireless Network PCI Adapter + +pci:v00001814d00000201sv0000185Fsd000022A0* + ID_MODEL_FROM_DATABASE=CN-WF513 Wireless Cardbus Adapter + +pci:v00001814d00000201sv000018EBsd00005312* + ID_MODEL_FROM_DATABASE=WL531P IEEE 802.11g PCI Card-EU + +pci:v00001814d00000201sv00001948sd00003C00* + ID_MODEL_FROM_DATABASE=C54RC v1 Wireless 11g CardBus Adapter + +pci:v00001814d00000201sv00001948sd00003C01* + ID_MODEL_FROM_DATABASE=C54Ri v1 Wireless 11g PCI Adapter + +pci:v00001814d00000300* + ID_MODEL_FROM_DATABASE=Wireless Adapter Canyon CN-WF511 + +pci:v00001814d00000301* + ID_MODEL_FROM_DATABASE=RT2561/RT61 802.11g PCI + +pci:v00001814d00000301sv00001186sd00003C08* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.E1) + +pci:v00001814d00000301sv00001186sd00003C09* + ID_MODEL_FROM_DATABASE=DWL-G510 Rev C + +pci:v00001814d00000301sv000013D1sd0000ABE3* + ID_MODEL_FROM_DATABASE=miniPCI Pluscom 802.11 a/b/g + +pci:v00001814d00000301sv00001458sd0000E933* + ID_MODEL_FROM_DATABASE=GN-WI01GS + +pci:v00001814d00000301sv00001458sd0000E934* + ID_MODEL_FROM_DATABASE=GN-WP01GS + +pci:v00001814d00000301sv00001737sd00000055* + ID_MODEL_FROM_DATABASE=WMP54G v4.1 + +pci:v00001814d00000301sv00001799sd0000700E* + ID_MODEL_FROM_DATABASE=F5D7000 v6000 Wireless G Desktop Card + +pci:v00001814d00000301sv00001799sd0000701E* + ID_MODEL_FROM_DATABASE=F5D7010 v6000 Wireless G Notebook Card + +pci:v00001814d00000301sv000017F9sd00000012* + ID_MODEL_FROM_DATABASE=AWLC3026T 802.11g Wireless CardBus Adapter + +pci:v00001814d00000301sv00001814sd00002561* + ID_MODEL_FROM_DATABASE=EW-7108PCg/EW-7128g + +pci:v00001814d00000302* + ID_MODEL_FROM_DATABASE=RT2561/RT61 rev B 802.11g + +pci:v00001814d00000302sv00001186sd00003A71* + ID_MODEL_FROM_DATABASE=DWA-510 Wireless G Desktop Adapter + +pci:v00001814d00000302sv00001186sd00003C08* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G630 Wireless Cardbus Adapter (rev.E2) + +pci:v00001814d00000302sv00001186sd00003C09* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G510 Wireless Network Adapter (Rev.C) + +pci:v00001814d00000302sv00001462sd0000B834* + ID_MODEL_FROM_DATABASE=PC54G3 Wireless 11g PCI Card + +pci:v00001814d00000302sv00001948sd00003C23* + ID_MODEL_FROM_DATABASE=C54RC v2 Wireless 11g CardBus Adapter + +pci:v00001814d00000302sv00001948sd00003C24* + ID_MODEL_FROM_DATABASE=C54Ri v2 Wireless 11g PCI Adapter + +pci:v00001814d00000401* + ID_MODEL_FROM_DATABASE=RT2600 802.11 MIMO + +pci:v00001814d00000401sv00001737sd00000052* + ID_MODEL_FROM_DATABASE=WPC54GR v1 802.11g Wireless-G Notebook Adapter with RangeBooster + +pci:v00001814d00000401sv000017F9sd00000011* + ID_MODEL_FROM_DATABASE=WPCR-137G 802.11bg Wireless CardBus Adapter + +pci:v00001814d00000401sv000017F9sd00000016* + ID_MODEL_FROM_DATABASE=WPIR-119GH 802.11bg Wireless Desktop Adapter + +pci:v00001814d00000601* + ID_MODEL_FROM_DATABASE=RT2800 802.11n PCI + +pci:v00001814d00000601sv00001799sd0000801C* + ID_MODEL_FROM_DATABASE=F5D8011 v3 802.11n N1 Wireless Notebook Card + +pci:v00001814d00000601sv0000187Esd00003412* + ID_MODEL_FROM_DATABASE=NWD-310N 802.11n Wireless PCI Adapter + +pci:v00001814d00000681* + ID_MODEL_FROM_DATABASE=RT2890 Wireless 802.11n PCIe + +pci:v00001814d00000681sv00001458sd0000E939* + ID_MODEL_FROM_DATABASE=GN-WS30N-RH 802.11bgn Mini PCIe Card + +pci:v00001814d00000701* + ID_MODEL_FROM_DATABASE=RT2760 Wireless 802.11n 1T/2R + +pci:v00001814d00000701sv00001737sd00000074* + ID_MODEL_FROM_DATABASE=WMP110 v2 802.11n RangePlus Wireless PCI Adapter + +pci:v00001814d00000781* + ID_MODEL_FROM_DATABASE=RT2790 Wireless 802.11n 1T/2R PCIe + +pci:v00001814d00003060* + ID_MODEL_FROM_DATABASE=RT3060 Wireless 802.11n 1T/1R + +pci:v00001814d00003060sv00001186sd00003C04* + ID_MODEL_FROM_DATABASE=DWA-525 Wireless N 150 Desktop Adapter (rev.A1) + +pci:v00001814d00003062* + ID_MODEL_FROM_DATABASE=RT3062 Wireless 802.11n 2T/2R + +pci:v00001814d00003090* + ID_MODEL_FROM_DATABASE=RT3090 Wireless 802.11n 1T/1R PCIe + +pci:v00001814d00003090sv000013BDsd00001057* + ID_MODEL_FROM_DATABASE=GN-WS32L-RH Half-size Mini PCIe Card + +pci:v00001814d00003091* + ID_MODEL_FROM_DATABASE=RT3091 Wireless 802.11n 1T/2R PCIe + +pci:v00001814d00003092* + ID_MODEL_FROM_DATABASE=RT3092 Wireless 802.11n 2T/2R PCIe + +pci:v00001814d00003290* + ID_MODEL_FROM_DATABASE=RT3290 Wireless 802.11n 1T/1R PCIe + +pci:v00001814d00003290sv0000103Csd000018EC* + ID_MODEL_FROM_DATABASE=Ralink RT3290LE 802.11bgn 1x1 Wi-Fi and Bluetooth 4.0 Combo Adapter + +pci:v00001814d00003298* + ID_MODEL_FROM_DATABASE=RT3290 Bluetooth + +pci:v00001814d00003298sv0000103Csd000018EC* + ID_MODEL_FROM_DATABASE=Ralink RT3290LE 802.11bgn 1x1 Wi-Fi and Bluetooth 4.0 Combo Adapter + +pci:v00001814d00003592* + ID_MODEL_FROM_DATABASE=RT3592 Wireless 802.11abgn 2T/2R PCIe + +pci:v00001814d0000359F* + ID_MODEL_FROM_DATABASE=RT3592 PCIe Wireless Network Adapter + +pci:v00001814d00005360* + ID_MODEL_FROM_DATABASE=RT5360 Wireless 802.11n 1T/1R + +pci:v00001814d00005360sv00001186sd00003C05* + ID_MODEL_FROM_DATABASE=DWA-525 Wireless N 150 Desktop Adapter (rev.A2) + +pci:v00001814d00005360sv000020F4sd0000703A* + ID_MODEL_FROM_DATABASE=TEW-703PI N150 Wireless PCI Adapter + +pci:v00001814d00005390* + ID_MODEL_FROM_DATABASE=RT5390 Wireless 802.11n 1T/1R PCIe + +pci:v00001814d00005390sv0000103Csd00001636* + ID_MODEL_FROM_DATABASE=U98Z077.00 Half-size Mini PCIe Card + +pci:v00001814d00005392* + ID_MODEL_FROM_DATABASE=RT5392 PCIe Wireless Network Adapter + +pci:v00001814d0000539F* + ID_MODEL_FROM_DATABASE=RT5390 [802.11 b/g/n 1T1R G-band PCI Express Single Chip] + +pci:v00001814d0000539Fsv0000103Csd00001637* + ID_MODEL_FROM_DATABASE=Pavilion DM1Z-3000 PCIe wireless card + +pci:v00001814d0000E932* + ID_MODEL_FROM_DATABASE=RT2560F 802.11 b/g PCI + +pci:v00001815* + ID_VENDOR_FROM_DATABASE=Devolo AG + +pci:v00001820* + ID_VENDOR_FROM_DATABASE=InfiniCon Systems Inc. + +pci:v00001822* + ID_VENDOR_FROM_DATABASE=Twinhan Technology Co. Ltd + +pci:v00001822d00004E35* + ID_MODEL_FROM_DATABASE=Mantis DTV PCI Bridge Controller [Ver 1.0] + +pci:v0000182D* + ID_VENDOR_FROM_DATABASE=SiteCom Europe BV + +pci:v0000182Dd00003069* + ID_MODEL_FROM_DATABASE=ISDN PCI DC-105V2 + +pci:v0000182Dd00009790* + ID_MODEL_FROM_DATABASE=WL-121 Wireless Network Adapter 100g+ [Ver.3] + +pci:v0000182E* + ID_VENDOR_FROM_DATABASE=Raza Microelectronics, Inc. + +pci:v0000182Ed00000008* + ID_MODEL_FROM_DATABASE=XLR516 Processor + +pci:v0000182F* + ID_VENDOR_FROM_DATABASE=Broadcom + +pci:v0000182Fd0000000B* + ID_MODEL_FROM_DATABASE=BCM5785 [HT1000] SATA (RAID Mode) + +pci:v00001830* + ID_VENDOR_FROM_DATABASE=Credence Systems Corporation + +pci:v0000183B* + ID_VENDOR_FROM_DATABASE=MikroM GmbH + +pci:v0000183Bd000008A7* + ID_MODEL_FROM_DATABASE=MVC100 DVI + +pci:v0000183Bd000008A8* + ID_MODEL_FROM_DATABASE=MVC101 SDI + +pci:v0000183Bd000008A9* + ID_MODEL_FROM_DATABASE=MVC102 DVI+Audio + +pci:v0000183Bd000008B0* + ID_MODEL_FROM_DATABASE=MVC200-DC + +pci:v00001846* + ID_VENDOR_FROM_DATABASE=Alcatel-Lucent + +pci:v00001849* + ID_VENDOR_FROM_DATABASE=ASRock Incorporation + +pci:v0000184A* + ID_VENDOR_FROM_DATABASE=Thales Computers + +pci:v0000184Ad00001100* + ID_MODEL_FROM_DATABASE=MAX II cPLD + +pci:v00001851* + ID_VENDOR_FROM_DATABASE=Microtune, Inc. + +pci:v00001852* + ID_VENDOR_FROM_DATABASE=Anritsu Corp. + +pci:v00001853* + ID_VENDOR_FROM_DATABASE=SMSC Automotive Infotainment System Group + +pci:v00001854* + ID_VENDOR_FROM_DATABASE=LG Electronics, Inc. + +pci:v0000185B* + ID_VENDOR_FROM_DATABASE=Compro Technology, Inc. + +pci:v0000185Bd00001489* + ID_MODEL_FROM_DATABASE=VideoMate Vista T100 + +pci:v0000185F* + ID_VENDOR_FROM_DATABASE=Wistron NeWeb Corp. + +pci:v00001864* + ID_VENDOR_FROM_DATABASE=SilverBack + +pci:v00001864d00002110* + ID_MODEL_FROM_DATABASE=ISNAP 2110 + +pci:v00001867* + ID_VENDOR_FROM_DATABASE=Topspin Communications + +pci:v00001867d00005A44* + ID_MODEL_FROM_DATABASE=MT23108 InfiniHost HCA + +pci:v00001867d00005A45* + ID_MODEL_FROM_DATABASE=MT23108 InfiniHost HCA flash recovery + +pci:v00001867d00005A46* + ID_MODEL_FROM_DATABASE=MT23108 InfiniHost HCA bridge + +pci:v00001867d00006278* + ID_MODEL_FROM_DATABASE=MT25208 InfiniHost III Ex (Tavor compatibility mode) + +pci:v00001867d00006282* + ID_MODEL_FROM_DATABASE=MT25208 InfiniHost III Ex + +pci:v0000186C* + ID_VENDOR_FROM_DATABASE=Humusoft, s.r.o. + +pci:v0000186Cd00000612* + ID_MODEL_FROM_DATABASE=AD612 Data Acquisition Device + +pci:v0000186Cd00000614* + ID_MODEL_FROM_DATABASE=MF614 Multifunction I/O Card + +pci:v0000186Cd00000622* + ID_MODEL_FROM_DATABASE=AD622 Data Acquisition Device + +pci:v0000186Cd00000624* + ID_MODEL_FROM_DATABASE=MF624 Multifunction I/O Card + +pci:v0000186Cd00000625* + ID_MODEL_FROM_DATABASE=MF625 3-phase Motor Driver + +pci:v0000186F* + ID_VENDOR_FROM_DATABASE=WiNRADiO Communications + +pci:v00001876* + ID_VENDOR_FROM_DATABASE=L-3 Communications + +pci:v00001876d0000A101* + ID_MODEL_FROM_DATABASE=VigraWATCH PCI + +pci:v00001876d0000A102* + ID_MODEL_FROM_DATABASE=VigraWATCH PMC + +pci:v00001876d0000A103* + ID_MODEL_FROM_DATABASE=Vigra I/O + +pci:v0000187E* + ID_VENDOR_FROM_DATABASE=ZyXEL Communications Corporation + +pci:v0000187Ed00003403* + ID_MODEL_FROM_DATABASE=ZyAir G-110 802.11g + +pci:v0000187Ed0000340E* + ID_MODEL_FROM_DATABASE=M-302 802.11g XtremeMIMO + +pci:v00001885* + ID_VENDOR_FROM_DATABASE=Avvida Systems Inc. + +pci:v00001888* + ID_VENDOR_FROM_DATABASE=Varisys Ltd + +pci:v00001888d00000301* + ID_MODEL_FROM_DATABASE=VMFX1 FPGA PMC module + +pci:v00001888d00000601* + ID_MODEL_FROM_DATABASE=VSM2 dual PMC carrier + +pci:v00001888d00000710* + ID_MODEL_FROM_DATABASE=VS14x series PowerPC PCI board + +pci:v00001888d00000720* + ID_MODEL_FROM_DATABASE=VS24x series PowerPC PCI board + +pci:v0000188A* + ID_VENDOR_FROM_DATABASE=Ample Communications, Inc + +pci:v00001890* + ID_VENDOR_FROM_DATABASE=Egenera, Inc. + +pci:v00001894* + ID_VENDOR_FROM_DATABASE=KNC One + +pci:v00001896* + ID_VENDOR_FROM_DATABASE=B&B Electronics Manufacturing Company, Inc. + +pci:v00001896d00004202* + ID_MODEL_FROM_DATABASE=MIport 3PCIU2 2-port Serial + +pci:v00001896d00004204* + ID_MODEL_FROM_DATABASE=MIport 3PCIU4 4-port Serial + +pci:v00001896d00004208* + ID_MODEL_FROM_DATABASE=MIport 3PCIU8 8-port Serial + +pci:v00001896d00004211* + ID_MODEL_FROM_DATABASE=MIport 3PCIOU1 1-port Isolated Serial + +pci:v00001896d00004212* + ID_MODEL_FROM_DATABASE=MIport 3PCIOU2 2-port Isolated Serial + +pci:v00001896d00004214* + ID_MODEL_FROM_DATABASE=MIport 3PCIOU4 4-port Isolated Serial + +pci:v00001896d0000BB10* + ID_MODEL_FROM_DATABASE=3PCI2 2-Port Serial + +pci:v00001896d0000BB11* + ID_MODEL_FROM_DATABASE=3PCIO1 1-Port Isolated Serial + +pci:v00001897* + ID_VENDOR_FROM_DATABASE=AMtek + +pci:v000018A1* + ID_VENDOR_FROM_DATABASE=Astute Networks Inc. + +pci:v000018A2* + ID_VENDOR_FROM_DATABASE=Stretch Inc. + +pci:v000018A2d00000002* + ID_MODEL_FROM_DATABASE=VRC6016 16-Channel PCIe DVR Card + +pci:v000018A3* + ID_VENDOR_FROM_DATABASE=AT&T + +pci:v000018AC* + ID_VENDOR_FROM_DATABASE=DViCO Corporation + +pci:v000018ACd0000D500* + ID_MODEL_FROM_DATABASE=FusionHDTV 5 + +pci:v000018ACd0000D800* + ID_MODEL_FROM_DATABASE=FusionHDTV 3 Gold + +pci:v000018ACd0000D810* + ID_MODEL_FROM_DATABASE=FusionHDTV 3 Gold-Q + +pci:v000018ACd0000D820* + ID_MODEL_FROM_DATABASE=FusionHDTV 3 Gold-T + +pci:v000018ACd0000DB30* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Pro + +pci:v000018ACd0000DB40* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Hybrid + +pci:v000018ACd0000DB78* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Dual Express + +pci:v000018B8* + ID_VENDOR_FROM_DATABASE=Ammasso + +pci:v000018B8d0000B001* + ID_MODEL_FROM_DATABASE=AMSO 1100 iWARP/RDMA Gigabit Ethernet Coprocessor + +pci:v000018BC* + ID_VENDOR_FROM_DATABASE=GeCube Technologies, Inc. + +pci:v000018C3* + ID_VENDOR_FROM_DATABASE=Micronas Semiconductor Holding AG + +pci:v000018C3d00000720* + ID_MODEL_FROM_DATABASE=nGene PCI-Express Multimedia Controller + +pci:v000018C3d00000720sv000007CAsd0000032E* + ID_MODEL_FROM_DATABASE=Hybrid M779 PCI-E + +pci:v000018C8* + ID_VENDOR_FROM_DATABASE=Cray Inc + +pci:v000018C9* + ID_VENDOR_FROM_DATABASE=ARVOO Engineering BV + +pci:v000018CA* + ID_VENDOR_FROM_DATABASE=XGI Technology Inc. (eXtreme Graphics Innovation) + +pci:v000018CAd00000020* + ID_MODEL_FROM_DATABASE=Z7/Z9 (XG20 core) + +pci:v000018CAd00000021* + ID_MODEL_FROM_DATABASE=Z9s/Z9m (XG21 core) + +pci:v000018CAd00000027* + ID_MODEL_FROM_DATABASE=Z11/Z11M + +pci:v000018CAd00000040* + ID_MODEL_FROM_DATABASE=Volari V3XT/V5/V8 + +pci:v000018CAd00000047* + ID_MODEL_FROM_DATABASE=Volari 8300 (chip: XP10, codename: XG47) + +pci:v000018D2* + ID_VENDOR_FROM_DATABASE=Sitecom Europe BV (Wrong ID) + +pci:v000018D2d00003069* + ID_MODEL_FROM_DATABASE=DC-105v2 ISDN controller + +pci:v000018D8* + ID_VENDOR_FROM_DATABASE=Dialogue Technology Corp. + +pci:v000018DD* + ID_VENDOR_FROM_DATABASE=Artimi Inc + +pci:v000018DDd00004C6F* + ID_MODEL_FROM_DATABASE=Artimi RTMI-100 UWB adapter + +pci:v000018DF* + ID_VENDOR_FROM_DATABASE=LeWiz Communications + +pci:v000018E6* + ID_VENDOR_FROM_DATABASE=MPL AG + +pci:v000018E6d00000001* + ID_MODEL_FROM_DATABASE=OSCI [Octal Serial Communication Interface] + +pci:v000018EB* + ID_VENDOR_FROM_DATABASE=Advance Multimedia Internet Technology, Inc. + +pci:v000018EC* + ID_VENDOR_FROM_DATABASE=Cesnet, z.s.p.o. + +pci:v000018ECd00006D05* + ID_MODEL_FROM_DATABASE=ML555 + +pci:v000018ECd00006D05sv000018ECsd00000100* + ID_MODEL_FROM_DATABASE=NIC (ethernet interfaces) + +pci:v000018ECd00006D05sv000018ECsd00000200* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 4x1G + +pci:v000018ECd00006D05sv000018ECsd00000201* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 2x10G + +pci:v000018ECd00006D05sv000018ECsd00000300* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 4x1G + +pci:v000018ECd00006D05sv000018ECsd00000302* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 2x10G + +pci:v000018ECd00006D05sv000018ECsd00004200* + ID_MODEL_FROM_DATABASE=Flexible FlowMon (szedata2) 1x10G + +pci:v000018ECd00006D05sv000018ECsd0000FF00* + ID_MODEL_FROM_DATABASE=Testing design + +pci:v000018ECd00006D05sv000018ECsd0000FF01* + ID_MODEL_FROM_DATABASE=Boot design + +pci:v000018ECd0000C006* + ID_MODEL_FROM_DATABASE=COMBO6 + +pci:v000018ECd0000C006sv000018ECsd0000D001* + ID_MODEL_FROM_DATABASE=COMBO-4MTX + +pci:v000018ECd0000C006sv000018ECsd0000D002* + ID_MODEL_FROM_DATABASE=COMBO-4SFP + +pci:v000018ECd0000C006sv000018ECsd0000D003* + ID_MODEL_FROM_DATABASE=COMBO-4SFPRO + +pci:v000018ECd0000C006sv000018ECsd0000D004* + ID_MODEL_FROM_DATABASE=COMBO-2XFP + +pci:v000018ECd0000C032* + ID_MODEL_FROM_DATABASE=COMBO-LXT110 + +pci:v000018ECd0000C032sv000018ECsd00000100* + ID_MODEL_FROM_DATABASE=NIC (ethernet interfaces) + +pci:v000018ECd0000C032sv000018ECsd00000200* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 4x1G + +pci:v000018ECd0000C032sv000018ECsd00000201* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 2x10G + +pci:v000018ECd0000C032sv000018ECsd00000300* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 4x1G + +pci:v000018ECd0000C032sv000018ECsd00000302* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 2x10G + +pci:v000018ECd0000C032sv000018ECsd00004200* + ID_MODEL_FROM_DATABASE=Flexible FlowMon (szedata2) 1x10G + +pci:v000018ECd0000C032sv000018ECsd0000FF00* + ID_MODEL_FROM_DATABASE=Testing design + +pci:v000018ECd0000C032sv000018ECsd0000FF01* + ID_MODEL_FROM_DATABASE=Boot design + +pci:v000018ECd0000C045* + ID_MODEL_FROM_DATABASE=COMBO6E + +pci:v000018ECd0000C050* + ID_MODEL_FROM_DATABASE=COMBO-PTM + +pci:v000018ECd0000C058* + ID_MODEL_FROM_DATABASE=COMBO6X + +pci:v000018ECd0000C058sv000018ECsd0000D001* + ID_MODEL_FROM_DATABASE=COMBO-4MTX + +pci:v000018ECd0000C058sv000018ECsd0000D002* + ID_MODEL_FROM_DATABASE=COMBO-4SFP + +pci:v000018ECd0000C058sv000018ECsd0000D003* + ID_MODEL_FROM_DATABASE=COMBO-4SFPRO + +pci:v000018ECd0000C058sv000018ECsd0000D004* + ID_MODEL_FROM_DATABASE=COMBO-2XFP + +pci:v000018ECd0000C132* + ID_MODEL_FROM_DATABASE=COMBO-LXT155 + +pci:v000018ECd0000C132sv000018ECsd00000100* + ID_MODEL_FROM_DATABASE=NIC (ethernet interfaces) + +pci:v000018ECd0000C132sv000018ECsd00000200* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 4x1G + +pci:v000018ECd0000C132sv000018ECsd00000201* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 2x10G + +pci:v000018ECd0000C132sv000018ECsd00000300* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 4x1G + +pci:v000018ECd0000C132sv000018ECsd00000302* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 2x10G + +pci:v000018ECd0000C132sv000018ECsd00004200* + ID_MODEL_FROM_DATABASE=Flexible FlowMon (szedata2) 1x10G + +pci:v000018ECd0000C132sv000018ECsd0000FF00* + ID_MODEL_FROM_DATABASE=Testing design + +pci:v000018ECd0000C132sv000018ECsd0000FF01* + ID_MODEL_FROM_DATABASE=Boot design + +pci:v000018ECd0000C232* + ID_MODEL_FROM_DATABASE=COMBO-FXT100 + +pci:v000018ECd0000C232sv000018ECsd00000100* + ID_MODEL_FROM_DATABASE=NIC (ethernet interfaces) + +pci:v000018ECd0000C232sv000018ECsd00000200* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 4x1G + +pci:v000018ECd0000C232sv000018ECsd00000201* + ID_MODEL_FROM_DATABASE=NIC (szedata2) 2x10G + +pci:v000018ECd0000C232sv000018ECsd00000300* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 4x1G + +pci:v000018ECd0000C232sv000018ECsd00000302* + ID_MODEL_FROM_DATABASE=NIFIC (szedata2) 2x10G + +pci:v000018ECd0000C232sv000018ECsd00004200* + ID_MODEL_FROM_DATABASE=Flexible FlowMon (szedata2) 1x10G + +pci:v000018ECd0000C232sv000018ECsd0000FF00* + ID_MODEL_FROM_DATABASE=Testing design + +pci:v000018ECd0000C232sv000018ECsd0000FF01* + ID_MODEL_FROM_DATABASE=Boot design + +pci:v000018EE* + ID_VENDOR_FROM_DATABASE=Chenming Mold Ind. Corp. + +pci:v000018F1* + ID_VENDOR_FROM_DATABASE=Spectrum GmbH + +pci:v000018F4* + ID_VENDOR_FROM_DATABASE=Napatech A/S + +pci:v000018F4d00000031* + ID_MODEL_FROM_DATABASE=NT20X Network Adapter + +pci:v000018F4d00000051* + ID_MODEL_FROM_DATABASE=NT20X Capture Card + +pci:v000018F4d00000061* + ID_MODEL_FROM_DATABASE=NT20E Capture Card + +pci:v000018F4d00000064* + ID_MODEL_FROM_DATABASE=NT20E Inline Card + +pci:v000018F4d00000071* + ID_MODEL_FROM_DATABASE=NT4E Capture Card + +pci:v000018F4d00000074* + ID_MODEL_FROM_DATABASE=NT4E Inline Card + +pci:v000018F4d00000081* + ID_MODEL_FROM_DATABASE=NT4E 4-port Expansion Card + +pci:v000018F4d00000091* + ID_MODEL_FROM_DATABASE=NT20X Capture Card [New Rev] + +pci:v000018F4d000000A1* + ID_MODEL_FROM_DATABASE=NT4E-STD Capture Card + +pci:v000018F4d000000A4* + ID_MODEL_FROM_DATABASE=NT4E-STD Inline Card + +pci:v000018F4d000000B1* + ID_MODEL_FROM_DATABASE=NTBPE Optical Bypass Adapter + +pci:v000018F4d000000C5* + ID_MODEL_FROM_DATABASE=NT20E2 Network Adapter 2x10Gb + +pci:v000018F4d000000D5* + ID_MODEL_FROM_DATABASE=NT40E2-4 Network Adapter 4x10Gb + +pci:v000018F4d000000E5* + ID_MODEL_FROM_DATABASE=NT40E2-1 Network Adapter 1x40Gb + +pci:v000018F4d000000F5* + ID_MODEL_FROM_DATABASE=NT4E2-4T-BP Network Adapter 4x1Gb with Electrical Bypass + +pci:v000018F4d00000105* + ID_MODEL_FROM_DATABASE=NT4E2-4-PTP Network Adapter 4x1Gb + +pci:v000018F4d00000115* + ID_MODEL_FROM_DATABASE=NT20E2-PTP Network Adapter 2x10Gb + +pci:v000018F4d00000125* + ID_MODEL_FROM_DATABASE=NT4E2-4-PTP Network Adapter 4x1Gb + +pci:v000018F4d00000135* + ID_MODEL_FROM_DATABASE=NT20E2-PTP Network Adapter 2x10Gb + +pci:v000018F6* + ID_VENDOR_FROM_DATABASE=NextIO + +pci:v000018F6d00001000* + ID_MODEL_FROM_DATABASE=[Nexsis] Switch Virtual P2P PCIe Bridge + +pci:v000018F6d00001001* + ID_MODEL_FROM_DATABASE=[Texsis] Switch Virtual P2P PCIe Bridge + +pci:v000018F6d00001050* + ID_MODEL_FROM_DATABASE=[Nexsis] Switch Virtual P2P PCI Bridge + +pci:v000018F6d00001051* + ID_MODEL_FROM_DATABASE=[Texsis] Switch Virtual P2P PCI Bridge + +pci:v000018F6d00002000* + ID_MODEL_FROM_DATABASE=[Nexsis] Switch Integrated Mgmt. Endpoint + +pci:v000018F6d00002001* + ID_MODEL_FROM_DATABASE=[Texsis] Switch Integrated Mgmt. Endpoint + +pci:v000018F7* + ID_VENDOR_FROM_DATABASE=Commtech, Inc. + +pci:v000018F7d00000001* + ID_MODEL_FROM_DATABASE=ESCC-PCI-335 Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000002* + ID_MODEL_FROM_DATABASE=422/4-PCI-335 Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000003* + ID_MODEL_FROM_DATABASE=232/4-1M-PCI Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000004* + ID_MODEL_FROM_DATABASE=422/2-PCI-335 Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000005* + ID_MODEL_FROM_DATABASE=IGESCC-PCI-ISO/1 Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000000A* + ID_MODEL_FROM_DATABASE=232/4-PCI-335 Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000000B* + ID_MODEL_FROM_DATABASE=232/8-PCI-335 Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000000F* + ID_MODEL_FROM_DATABASE=FSCC Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000010* + ID_MODEL_FROM_DATABASE=GSCC Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000011* + ID_MODEL_FROM_DATABASE=QSSB Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000014* + ID_MODEL_FROM_DATABASE=SuperFSCC Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000015* + ID_MODEL_FROM_DATABASE=SuperFSCC-104-LVDS Serial PC/104+ Adapter [Fastcom] + +pci:v000018F7d00000016* + ID_MODEL_FROM_DATABASE=FSCC-232 RS-232 Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000017* + ID_MODEL_FROM_DATABASE=SuperFSCC-104 Serial PC/104+ Adapter [Fastcom] + +pci:v000018F7d00000018* + ID_MODEL_FROM_DATABASE=SuperFSCC/4 Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000019* + ID_MODEL_FROM_DATABASE=SuperFSCC Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000001A* + ID_MODEL_FROM_DATABASE=SuperFSCC-LVDS Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000001B* + ID_MODEL_FROM_DATABASE=FSCC/4 Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000001C* + ID_MODEL_FROM_DATABASE=SuperFSCC/4-LVDS Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000001D* + ID_MODEL_FROM_DATABASE=FSCC Serial PCI Adapter [Fastcom] + +pci:v000018F7d0000001E* + ID_MODEL_FROM_DATABASE=SuperFSCC/4 Serial PCIe Adapter [Fastcom] + +pci:v000018F7d0000001F* + ID_MODEL_FROM_DATABASE=SuperFSCC/4 Serial cPCI Adapter [Fastcom] + +pci:v000018F7d00000020* + ID_MODEL_FROM_DATABASE=422/4-PCIe Serial PCIe Adapter [Fastcom] + +pci:v000018F7d00000021* + ID_MODEL_FROM_DATABASE=422/8-PCIe Serial PCIe Adapter [Fastcom] + +pci:v000018F7d00000022* + ID_MODEL_FROM_DATABASE=SuperFSCC/4-LVDS Serial PCIe Adapter [Fastcom] + +pci:v000018F7d00000023* + ID_MODEL_FROM_DATABASE=SuperFSCC/4 Serial cPCI Adapter [Fastcom] + +pci:v000018F7d00000025* + ID_MODEL_FROM_DATABASE=SuperFSCC/4-LVDS Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000026* + ID_MODEL_FROM_DATABASE=SuperFSCC-LVDS Serial PCI Adapter [Fastcom] + +pci:v000018F7d00000027* + ID_MODEL_FROM_DATABASE=FSCC/4 Serial PCIe Adapter [Fastcom] + +pci:v000018FB* + ID_VENDOR_FROM_DATABASE=Resilience Corporation + +pci:v00001904* + ID_VENDOR_FROM_DATABASE=Hangzhou Silan Microelectronics Co., Ltd. + +pci:v00001904d00002031* + ID_MODEL_FROM_DATABASE=SC92031 PCI Fast Ethernet Adapter + +pci:v00001904d00008139* + ID_MODEL_FROM_DATABASE=RTL8139D [Realtek] PCI 10/100BaseTX ethernet adaptor + +pci:v00001905* + ID_VENDOR_FROM_DATABASE=Micronas USA, Inc. + +pci:v00001912* + ID_VENDOR_FROM_DATABASE=Renesas Technology Corp. + +pci:v00001912d00000002* + ID_MODEL_FROM_DATABASE=SH7780 PCI Controller (PCIC) + +pci:v00001912d00000011* + ID_MODEL_FROM_DATABASE=SH7757 PCIe End-Point [PBI] + +pci:v00001912d00000012* + ID_MODEL_FROM_DATABASE=SH7757 PCIe-PCI Bridge [PPB] + +pci:v00001912d00000013* + ID_MODEL_FROM_DATABASE=SH7757 PCIe Switch [PS] + +pci:v00001912d00000014* + ID_MODEL_FROM_DATABASE=uPD720201 USB 3.0 Host Controller + +pci:v00001912d00000015* + ID_MODEL_FROM_DATABASE=uPD720202 USB 3.0 Host Controller + +pci:v00001919* + ID_VENDOR_FROM_DATABASE=Soltek Computer Inc. + +pci:v00001923* + ID_VENDOR_FROM_DATABASE=Sangoma Technologies Corp. + +pci:v00001923d00000040* + ID_MODEL_FROM_DATABASE=A200/Remora FXO/FXS Analog AFT card + +pci:v00001923d00000100* + ID_MODEL_FROM_DATABASE=A104d QUAD T1/E1 AFT card + +pci:v00001923d00000300* + ID_MODEL_FROM_DATABASE=A101 single-port T1/E1 + +pci:v00001923d00000400* + ID_MODEL_FROM_DATABASE=A104u Quad T1/E1 AFT + +pci:v00001924* + ID_VENDOR_FROM_DATABASE=Solarflare Communications + +pci:v00001924d00000703* + ID_MODEL_FROM_DATABASE=SFC4000 rev A net [Solarstorm] + +pci:v00001924d00000703sv000010B8sd00000102* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-10BT (A2) [TigerCard] + +pci:v00001924d00000703sv000010B8sd00000103* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-10BT (A3) [TigerCard] + +pci:v00001924d00000703sv000010B8sd00000201* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-XFP (A1) [TigerCard] + +pci:v00001924d00000703sv00001924sd00000101* + ID_MODEL_FROM_DATABASE=SFE4001-A1 + +pci:v00001924d00000703sv00001924sd00000102* + ID_MODEL_FROM_DATABASE=SFE4001-A2 + +pci:v00001924d00000703sv00001924sd00000103* + ID_MODEL_FROM_DATABASE=SFE4001-A3 + +pci:v00001924d00000703sv00001924sd00000201* + ID_MODEL_FROM_DATABASE=SFE4002-A1 + +pci:v00001924d00000703sv00001924sd00000301* + ID_MODEL_FROM_DATABASE=SFE4003-A1 + +pci:v00001924d00000703sv00001924sd00000302* + ID_MODEL_FROM_DATABASE=SFE4003-A2 + +pci:v00001924d00000703sv00001924sd00000303* + ID_MODEL_FROM_DATABASE=SFE4003-A3 + +pci:v00001924d00000703sv00001924sd00000304* + ID_MODEL_FROM_DATABASE=SFE4003-A4 + +pci:v00001924d00000703sv00001924sd00000500* + ID_MODEL_FROM_DATABASE=SFE4005-A0 + +pci:v00001924d00000710* + ID_MODEL_FROM_DATABASE=SFC4000 rev B [Solarstorm] + +pci:v00001924d00000710sv000010B8sd00000103* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-10BT (A3) [TigerCard] + +pci:v00001924d00000710sv000010B8sd00000201* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-XFP (A1) [TigerCard] + +pci:v00001924d00000710sv00001924sd00000102* + ID_MODEL_FROM_DATABASE=SFE4001-A2 + +pci:v00001924d00000710sv00001924sd00000103* + ID_MODEL_FROM_DATABASE=SFE4001-A3 + +pci:v00001924d00000710sv00001924sd00000201* + ID_MODEL_FROM_DATABASE=SFE4002-A1 + +pci:v00001924d00000710sv00001924sd00000302* + ID_MODEL_FROM_DATABASE=SFE4003-A2 + +pci:v00001924d00000710sv00001924sd00000303* + ID_MODEL_FROM_DATABASE=SFE4003-A3 + +pci:v00001924d00000710sv00001924sd00000304* + ID_MODEL_FROM_DATABASE=SFE4003-A4 + +pci:v00001924d00000710sv00001924sd00000500* + ID_MODEL_FROM_DATABASE=SFE4005-A0 + +pci:v00001924d00000710sv00001924sd00005102* + ID_MODEL_FROM_DATABASE=SFN4111T-A2 + +pci:v00001924d00000710sv00001924sd00005103* + ID_MODEL_FROM_DATABASE=SFN4111T-R3 + +pci:v00001924d00000710sv00001924sd00005104* + ID_MODEL_FROM_DATABASE=SFN4111T-R4 + +pci:v00001924d00000710sv00001924sd00005105* + ID_MODEL_FROM_DATABASE=SFN4111T-R5 + +pci:v00001924d00000710sv00001924sd00005201* + ID_MODEL_FROM_DATABASE=SFN4112F-R1 + +pci:v00001924d00000710sv00001924sd00005202* + ID_MODEL_FROM_DATABASE=SFN4112F-R2 + +pci:v00001924d00000803* + ID_MODEL_FROM_DATABASE=SFC9020 [Solarstorm] + +pci:v00001924d00000803sv00001014sd00000478* + ID_MODEL_FROM_DATABASE=2-port 10GbE Low-Latency (R7) + +pci:v00001924d00000803sv00001014sd00000479* + ID_MODEL_FROM_DATABASE=2-port 10GbE OpenOnload (R7) + +pci:v00001924d00000803sv00001014sd000004A7* + ID_MODEL_FROM_DATABASE=Solarflare 10Gb Low-latency Dual-port HBA (R7) + +pci:v00001924d00000803sv00001014sd000004A8* + ID_MODEL_FROM_DATABASE=Solarflare 10Gb Dual-port HBA (R7) + +pci:v00001924d00000803sv0000103Csd00002132* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 570FLR-SFP+ Adapter (R1) + +pci:v00001924d00000803sv0000103Csd00002136* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 570SFP+ Adapter (R7) + +pci:v00001924d00000803sv00001924sd00001201* + ID_MODEL_FROM_DATABASE=SFA6902F-R1 SFP+ AOE Adapter + +pci:v00001924d00000803sv00001924sd00006200* + ID_MODEL_FROM_DATABASE=SFN5122F-R0 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006201* + ID_MODEL_FROM_DATABASE=SFN5122F-R1 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006202* + ID_MODEL_FROM_DATABASE=SFN5122F-R2 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006204* + ID_MODEL_FROM_DATABASE=SFN5122F-R4 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006205* + ID_MODEL_FROM_DATABASE=SFN5122F-R5 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006206* + ID_MODEL_FROM_DATABASE=SFN5122F-R6 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006207* + ID_MODEL_FROM_DATABASE=SFN5122F-R7 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006210* + ID_MODEL_FROM_DATABASE=SFN5322F-R0 SFP+ Precision Time Synchronization Server Adapter + +pci:v00001924d00000803sv00001924sd00006211* + ID_MODEL_FROM_DATABASE=SFN5322F-R1 SFP+ Precision Time Synchronization Server Adapter + +pci:v00001924d00000803sv00001924sd00006217* + ID_MODEL_FROM_DATABASE=SFN5322F-R7 SFP+ Precision Time Synchronization Server Adapter + +pci:v00001924d00000803sv00001924sd00006227* + ID_MODEL_FROM_DATABASE=SFN6122F-R7 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006237* + ID_MODEL_FROM_DATABASE=SFN6322F-R7 SFP+ Precision Time Synchronization Server Adapter + +pci:v00001924d00000803sv00001924sd00006501* + ID_MODEL_FROM_DATABASE=SFN5802K-R1 Mezzanine Adapter + +pci:v00001924d00000803sv00001924sd00006511* + ID_MODEL_FROM_DATABASE=SFN5814H-R1 Mezzanine Adapter + +pci:v00001924d00000803sv00001924sd00006521* + ID_MODEL_FROM_DATABASE=SFN5812H-R1 Mezzanine Adapter + +pci:v00001924d00000803sv00001924sd00006562* + ID_MODEL_FROM_DATABASE=SFN6832F-R2 SFP+ Mezzanine Adapter + +pci:v00001924d00000803sv00001924sd00006A05* + ID_MODEL_FROM_DATABASE=SFN5112F-R5 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00006A06* + ID_MODEL_FROM_DATABASE=SFN5112F-R6 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00007206* + ID_MODEL_FROM_DATABASE=SFN5162F-R6 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00007207* + ID_MODEL_FROM_DATABASE=SFN5162F-R7 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00007A06* + ID_MODEL_FROM_DATABASE=SFN5152F-R6 SFP+ Server Adapter + +pci:v00001924d00000803sv00001924sd00007A07* + ID_MODEL_FROM_DATABASE=SFN5152F-R7 SFP+ Server Adapter + +pci:v00001924d00000813* + ID_MODEL_FROM_DATABASE=SFL9021 [Solarstorm] + +pci:v00001924d00000813sv00001924sd00006100* + ID_MODEL_FROM_DATABASE=SFN5121T-R0 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00006102* + ID_MODEL_FROM_DATABASE=SFN5121T-R2 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00006103* + ID_MODEL_FROM_DATABASE=SFN5121T-R3 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00006104* + ID_MODEL_FROM_DATABASE=SFN5121T-R4 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00006902* + ID_MODEL_FROM_DATABASE=SFN5111T-R2 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00006904* + ID_MODEL_FROM_DATABASE=SFN5111T-R4 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00007104* + ID_MODEL_FROM_DATABASE=SFN5161T-R4 10GBASE-T Server Adapter + +pci:v00001924d00000813sv00001924sd00007904* + ID_MODEL_FROM_DATABASE=SFN5151T-R4 10GBASE-T Server Adapter + +pci:v00001924d00000903* + ID_MODEL_FROM_DATABASE=SFC9120 + +pci:v00001924d00000903sv00001924sd00008002* + ID_MODEL_FROM_DATABASE=SFN7122F-R1 SFP+ Server Adapter + +pci:v00001924d00000903sv00001924sd00008006* + ID_MODEL_FROM_DATABASE=SFN7022F-R1 SFP+ Server Adapter + +pci:v00001924d00001803* + ID_MODEL_FROM_DATABASE=SFC9020 Virtual Function [Solarstorm] + +pci:v00001924d00001813* + ID_MODEL_FROM_DATABASE=SFL9021 Virtual Function [Solarstorm] + +pci:v00001924d00006703* + ID_MODEL_FROM_DATABASE=SFC4000 rev A iSCSI/Onload [Solarstorm] + +pci:v00001924d00006703sv000010B8sd00000102* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-10BT (A2) [TigerCard] + +pci:v00001924d00006703sv000010B8sd00000103* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-10BT (A3) [TigerCard] + +pci:v00001924d00006703sv000010B8sd00000201* + ID_MODEL_FROM_DATABASE=SMC10GPCIe-XFP (A1) [TigerCard] + +pci:v00001924d00006703sv00001924sd00000101* + ID_MODEL_FROM_DATABASE=SFE4001-A1 + +pci:v00001924d00006703sv00001924sd00000102* + ID_MODEL_FROM_DATABASE=SFE4001-A2 + +pci:v00001924d00006703sv00001924sd00000103* + ID_MODEL_FROM_DATABASE=SFE4001-A3 + +pci:v00001924d00006703sv00001924sd00000201* + ID_MODEL_FROM_DATABASE=SFE4002-A1 + +pci:v00001924d00006703sv00001924sd00000301* + ID_MODEL_FROM_DATABASE=SFE4003-A1 + +pci:v00001924d00006703sv00001924sd00000302* + ID_MODEL_FROM_DATABASE=SFE4003-A2 + +pci:v00001924d00006703sv00001924sd00000303* + ID_MODEL_FROM_DATABASE=SFE4003-A3 + +pci:v00001924d00006703sv00001924sd00000304* + ID_MODEL_FROM_DATABASE=SFE4003-A4 + +pci:v00001924d00006703sv00001924sd00000500* + ID_MODEL_FROM_DATABASE=SFE4005-A0 + +pci:v00001924d0000C101* + ID_MODEL_FROM_DATABASE=EF1-21022T [EtherFabric] + +pci:v0000192A* + ID_VENDOR_FROM_DATABASE=BiTMICRO Networks Inc. + +pci:v0000192E* + ID_VENDOR_FROM_DATABASE=TransDimension + +pci:v00001931* + ID_VENDOR_FROM_DATABASE=Option N.V. + +pci:v00001931d0000000C* + ID_MODEL_FROM_DATABASE=Qualcomm MSM6275 UMTS chip + +pci:v00001932* + ID_VENDOR_FROM_DATABASE=DiBcom + +pci:v0000193C* + ID_VENDOR_FROM_DATABASE=MAXIM Integrated Products + +pci:v0000193F* + ID_VENDOR_FROM_DATABASE=Comtech AHA Corp. + +pci:v0000193Fd00000001* + ID_MODEL_FROM_DATABASE=AHA36x-PCIX + +pci:v0000193Fd00000360* + ID_MODEL_FROM_DATABASE=AHA360-PCIe + +pci:v0000193Fd00000363* + ID_MODEL_FROM_DATABASE=AHA363-PCIe + +pci:v0000193Fd00000364* + ID_MODEL_FROM_DATABASE=AHA364-PCIe + +pci:v0000193Fd00000367* + ID_MODEL_FROM_DATABASE=AHA367-PCIe + +pci:v0000193Fd00000370* + ID_MODEL_FROM_DATABASE=AHA370-PCIe + +pci:v00001942* + ID_VENDOR_FROM_DATABASE=ClearSpeed Technology plc + +pci:v00001942d0000E511* + ID_MODEL_FROM_DATABASE=Advance X620 accelerator card + +pci:v00001942d0000E521* + ID_MODEL_FROM_DATABASE=Advance e620 accelerator card + +pci:v00001947* + ID_VENDOR_FROM_DATABASE=C-guys, Inc. + +pci:v00001947d00004743* + ID_MODEL_FROM_DATABASE=CG200 Dual SD/SDIO Host controller device + +pci:v00001948* + ID_VENDOR_FROM_DATABASE=Alpha Networks Inc. + +pci:v0000194A* + ID_VENDOR_FROM_DATABASE=DapTechnology B.V. + +pci:v0000194Ad00001111* + ID_MODEL_FROM_DATABASE=FireSpy3850 + +pci:v0000194Ad00001112* + ID_MODEL_FROM_DATABASE=FireSpy450b + +pci:v0000194Ad00001113* + ID_MODEL_FROM_DATABASE=FireSpy450bT + +pci:v0000194Ad00001114* + ID_MODEL_FROM_DATABASE=FireSpy850 + +pci:v0000194Ad00001115* + ID_MODEL_FROM_DATABASE=FireSpy850bT + +pci:v0000194Ad00001200* + ID_MODEL_FROM_DATABASE=FireTrac 3460bT + +pci:v0000194Ad00001201* + ID_MODEL_FROM_DATABASE=FireTrac 3460bT (fallback firmware) + +pci:v0000194Ad00001202* + ID_MODEL_FROM_DATABASE=FireTrac 3460bT + +pci:v0000194Ad00001203* + ID_MODEL_FROM_DATABASE=FireTrac 3460bT (fallback firmware) + +pci:v00001954* + ID_VENDOR_FROM_DATABASE=One Stop Systems, Inc. + +pci:v00001957* + ID_VENDOR_FROM_DATABASE=Freescale Semiconductor Inc + +pci:v00001957d00000012* + ID_MODEL_FROM_DATABASE=MPC8548E + +pci:v00001957d00000013* + ID_MODEL_FROM_DATABASE=MPC8548 + +pci:v00001957d00000014* + ID_MODEL_FROM_DATABASE=MPC8543E + +pci:v00001957d00000015* + ID_MODEL_FROM_DATABASE=MPC8543 + +pci:v00001957d00000018* + ID_MODEL_FROM_DATABASE=MPC8547E + +pci:v00001957d00000019* + ID_MODEL_FROM_DATABASE=MPC8545E + +pci:v00001957d0000001A* + ID_MODEL_FROM_DATABASE=MPC8545 + +pci:v00001957d00000020* + ID_MODEL_FROM_DATABASE=MPC8568E + +pci:v00001957d00000021* + ID_MODEL_FROM_DATABASE=MPC8568 + +pci:v00001957d00000022* + ID_MODEL_FROM_DATABASE=MPC8567E + +pci:v00001957d00000023* + ID_MODEL_FROM_DATABASE=MPC8567 + +pci:v00001957d00000030* + ID_MODEL_FROM_DATABASE=MPC8533E + +pci:v00001957d00000031* + ID_MODEL_FROM_DATABASE=MPC8533 + +pci:v00001957d00000032* + ID_MODEL_FROM_DATABASE=MPC8544E + +pci:v00001957d00000033* + ID_MODEL_FROM_DATABASE=MPC8544 + +pci:v00001957d00000040* + ID_MODEL_FROM_DATABASE=MPC8572E + +pci:v00001957d00000041* + ID_MODEL_FROM_DATABASE=MPC8572 + +pci:v00001957d00000050* + ID_MODEL_FROM_DATABASE=MPC8536E + +pci:v00001957d00000051* + ID_MODEL_FROM_DATABASE=MPC8536 + +pci:v00001957d00000052* + ID_MODEL_FROM_DATABASE=MPC8535E + +pci:v00001957d00000053* + ID_MODEL_FROM_DATABASE=MPC8535 + +pci:v00001957d00000060* + ID_MODEL_FROM_DATABASE=MPC8569 + +pci:v00001957d00000061* + ID_MODEL_FROM_DATABASE=MPC8569E + +pci:v00001957d00000070* + ID_MODEL_FROM_DATABASE=P2020E + +pci:v00001957d00000071* + ID_MODEL_FROM_DATABASE=P2020 + +pci:v00001957d00000078* + ID_MODEL_FROM_DATABASE=P2010E + +pci:v00001957d00000079* + ID_MODEL_FROM_DATABASE=P2010 + +pci:v00001957d00000080* + ID_MODEL_FROM_DATABASE=MPC8349E + +pci:v00001957d00000081* + ID_MODEL_FROM_DATABASE=MPC8349 + +pci:v00001957d00000082* + ID_MODEL_FROM_DATABASE=MPC8347E TBGA + +pci:v00001957d00000083* + ID_MODEL_FROM_DATABASE=MPC8347 TBGA + +pci:v00001957d00000084* + ID_MODEL_FROM_DATABASE=MPC8347E PBGA + +pci:v00001957d00000085* + ID_MODEL_FROM_DATABASE=MPC8347 PBGA + +pci:v00001957d00000086* + ID_MODEL_FROM_DATABASE=MPC8343E + +pci:v00001957d00000087* + ID_MODEL_FROM_DATABASE=MPC8343 + +pci:v00001957d000000B4* + ID_MODEL_FROM_DATABASE=MPC8315E + +pci:v00001957d000000B6* + ID_MODEL_FROM_DATABASE=MPC8314E + +pci:v00001957d000000B6sv00001A56sd00001101* + ID_MODEL_FROM_DATABASE=Killer Xeno Pro Gigabit Ethernet Controller + +pci:v00001957d000000C2* + ID_MODEL_FROM_DATABASE=MPC8379E + +pci:v00001957d000000C3* + ID_MODEL_FROM_DATABASE=MPC8379 + +pci:v00001957d000000C4* + ID_MODEL_FROM_DATABASE=MPC8378E + +pci:v00001957d000000C5* + ID_MODEL_FROM_DATABASE=MPC8378 + +pci:v00001957d000000C6* + ID_MODEL_FROM_DATABASE=MPC8377E + +pci:v00001957d000000C7* + ID_MODEL_FROM_DATABASE=MPC8377 + +pci:v00001957d00000100* + ID_MODEL_FROM_DATABASE=P1020E + +pci:v00001957d00000101* + ID_MODEL_FROM_DATABASE=P1020 + +pci:v00001957d00000102* + ID_MODEL_FROM_DATABASE=P1021E + +pci:v00001957d00000103* + ID_MODEL_FROM_DATABASE=P1021 + +pci:v00001957d00000108* + ID_MODEL_FROM_DATABASE=P1011E + +pci:v00001957d00000109* + ID_MODEL_FROM_DATABASE=P1011 + +pci:v00001957d0000010A* + ID_MODEL_FROM_DATABASE=P1012E + +pci:v00001957d0000010B* + ID_MODEL_FROM_DATABASE=P1012 + +pci:v00001957d00000110* + ID_MODEL_FROM_DATABASE=P1022E + +pci:v00001957d00000111* + ID_MODEL_FROM_DATABASE=P1022 + +pci:v00001957d00000111sv00001C7Fsd00005200* + ID_MODEL_FROM_DATABASE=EB5200 + +pci:v00001957d00000118* + ID_MODEL_FROM_DATABASE=P1013E + +pci:v00001957d00000119* + ID_MODEL_FROM_DATABASE=P1013 + +pci:v00001957d00000128* + ID_MODEL_FROM_DATABASE=P1010 + +pci:v00001957d00000400* + ID_MODEL_FROM_DATABASE=P4080E + +pci:v00001957d00000401* + ID_MODEL_FROM_DATABASE=P4080 + +pci:v00001957d00000408* + ID_MODEL_FROM_DATABASE=P4040E + +pci:v00001957d00000409* + ID_MODEL_FROM_DATABASE=P4040 + +pci:v00001957d0000580C* + ID_MODEL_FROM_DATABASE=MPC5121e + +pci:v00001957d00007010* + ID_MODEL_FROM_DATABASE=MPC8641 PCI Host Bridge + +pci:v00001957d00007011* + ID_MODEL_FROM_DATABASE=MPC8641D PCI Host Bridge + +pci:v00001957d00007018* + ID_MODEL_FROM_DATABASE=MPC8610 + +pci:v00001957d0000C006* + ID_MODEL_FROM_DATABASE=MPC8308 + +pci:v00001957d0000C006sv00001A56sd00001201* + ID_MODEL_FROM_DATABASE=Killer E2100 Gigabit Ethernet Controller + +pci:v00001958* + ID_VENDOR_FROM_DATABASE=Faster Technology, LLC. + +pci:v00001959* + ID_VENDOR_FROM_DATABASE=PA Semi, Inc + +pci:v00001959d0000A000* + ID_MODEL_FROM_DATABASE=PA6T Core + +pci:v00001959d0000A001* + ID_MODEL_FROM_DATABASE=PWRficient Host Bridge + +pci:v00001959d0000A002* + ID_MODEL_FROM_DATABASE=PWRficient PCI-Express Port + +pci:v00001959d0000A003* + ID_MODEL_FROM_DATABASE=PWRficient SMBus Controller + +pci:v00001959d0000A004* + ID_MODEL_FROM_DATABASE=PWRficient 16550 UART + +pci:v00001959d0000A005* + ID_MODEL_FROM_DATABASE=PWRficient Gigabit Ethernet + +pci:v00001959d0000A006* + ID_MODEL_FROM_DATABASE=PWRficient 10-Gigabit Ethernet + +pci:v00001959d0000A007* + ID_MODEL_FROM_DATABASE=PWRficient DMA Controller + +pci:v00001959d0000A008* + ID_MODEL_FROM_DATABASE=PWRficient LPC/Localbus Interface + +pci:v00001959d0000A009* + ID_MODEL_FROM_DATABASE=PWRficient L2 Cache + +pci:v00001959d0000A00A* + ID_MODEL_FROM_DATABASE=PWRficient DDR2 Memory Controller + +pci:v00001959d0000A00B* + ID_MODEL_FROM_DATABASE=PWRficient SERDES + +pci:v00001959d0000A00C* + ID_MODEL_FROM_DATABASE=PWRficient System/Debug Controller + +pci:v00001959d0000A00D* + ID_MODEL_FROM_DATABASE=PWRficient PCI-Express Internal Endpoint + +pci:v00001966* + ID_VENDOR_FROM_DATABASE=Orad Hi-Tec Systems + +pci:v00001966d00001975* + ID_MODEL_FROM_DATABASE=DVG64 family + +pci:v00001966d00001977* + ID_MODEL_FROM_DATABASE=DVG128 family + +pci:v00001969* + ID_VENDOR_FROM_DATABASE=Qualcomm Atheros + +pci:v00001969d00001026* + ID_MODEL_FROM_DATABASE=AR8121/AR8113/AR8114 Gigabit or Fast Ethernet + +pci:v00001969d00001026sv00001043sd00008304* + ID_MODEL_FROM_DATABASE=P5KPL-CM Motherboard + +pci:v00001969d00001048* + ID_MODEL_FROM_DATABASE=Attansic L1 Gigabit Ethernet + +pci:v00001969d00001048sv00001043sd00008226* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00001969d00001062* + ID_MODEL_FROM_DATABASE=AR8132 Fast Ethernet + +pci:v00001969d00001063* + ID_MODEL_FROM_DATABASE=AR8131 Gigabit Ethernet + +pci:v00001969d00001063sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=GA-G31M-ES2L Motherboard + +pci:v00001969d00001066* + ID_MODEL_FROM_DATABASE=Attansic L2c Gigabit Ethernet + +pci:v00001969d00001067* + ID_MODEL_FROM_DATABASE=Attansic L1c Gigabit Ethernet + +pci:v00001969d00001073* + ID_MODEL_FROM_DATABASE=AR8151 v1.0 Gigabit Ethernet + +pci:v00001969d00001083* + ID_MODEL_FROM_DATABASE=AR8151 v2.0 Gigabit Ethernet + +pci:v00001969d00001090* + ID_MODEL_FROM_DATABASE=AR8162 Fast Ethernet + +pci:v00001969d00001091* + ID_MODEL_FROM_DATABASE=AR8161 Gigabit Ethernet + +pci:v00001969d00001091sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00001969d000010A0* + ID_MODEL_FROM_DATABASE=QCA8172 Fast Ethernet + +pci:v00001969d000010A1* + ID_MODEL_FROM_DATABASE=QCA8171 Gigabit Ethernet + +pci:v00001969d00002048* + ID_MODEL_FROM_DATABASE=Attansic L2 Fast Ethernet + +pci:v00001969d00002060* + ID_MODEL_FROM_DATABASE=AR8152 v1.1 Fast Ethernet + +pci:v00001969d00002062* + ID_MODEL_FROM_DATABASE=AR8152 v2.0 Fast Ethernet + +pci:v00001969d0000E091* + ID_MODEL_FROM_DATABASE=Killer E2200 Gigabit Ethernet Controller + +pci:v0000196A* + ID_VENDOR_FROM_DATABASE=Sensory Networks Inc. + +pci:v0000196Ad00000101* + ID_MODEL_FROM_DATABASE=NodalCore C-1000 Content Classification Accelerator + +pci:v0000196Ad00000102* + ID_MODEL_FROM_DATABASE=NodalCore C-2000 Content Classification Accelerator + +pci:v0000196Ad00000105* + ID_MODEL_FROM_DATABASE=NodalCore C-3000 Content Classification Accelerator + +pci:v0000196D* + ID_VENDOR_FROM_DATABASE=Club-3D BV + +pci:v00001971* + ID_VENDOR_FROM_DATABASE=AGEIA Technologies, Inc. + +pci:v00001971d00001011* + ID_MODEL_FROM_DATABASE=Physics Processing Unit [PhysX] + +pci:v00001971d00001011sv00001043sd00000001* + ID_MODEL_FROM_DATABASE=PhysX P1 + +pci:v00001974* + ID_VENDOR_FROM_DATABASE=Eberspaecher Electronics + +pci:v00001976* + ID_VENDOR_FROM_DATABASE=TRENDnet + +pci:v00001977* + ID_VENDOR_FROM_DATABASE=Parsec + +pci:v0000197B* + ID_VENDOR_FROM_DATABASE=JMicron Technology Corp. + +pci:v0000197Bd00000250* + ID_MODEL_FROM_DATABASE=JMC250 PCI Express Gigabit Ethernet Controller + +pci:v0000197Bd00000260* + ID_MODEL_FROM_DATABASE=JMC260 PCI Express Fast Ethernet Controller + +pci:v0000197Bd00000368* + ID_MODEL_FROM_DATABASE=JMB368 IDE controller + +pci:v0000197Bd00002360* + ID_MODEL_FROM_DATABASE=JMB360 AHCI Controller + +pci:v0000197Bd00002361* + ID_MODEL_FROM_DATABASE=JMB361 AHCI/IDE + +pci:v0000197Bd00002361sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v0000197Bd00002362* + ID_MODEL_FROM_DATABASE=JMB362 SATA Controller + +pci:v0000197Bd00002362sv00001043sd00008460* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v0000197Bd00002363* + ID_MODEL_FROM_DATABASE=JMB363 SATA/IDE Controller + +pci:v0000197Bd00002363sv00001043sd000081E4* + ID_MODEL_FROM_DATABASE=P5B [JMB363] + +pci:v0000197Bd00002363sv00001458sd0000B000* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v0000197Bd00002363sv00001849sd00002363* + ID_MODEL_FROM_DATABASE=Motherboard (one of many) + +pci:v0000197Bd00002364* + ID_MODEL_FROM_DATABASE=JMB364 AHCI Controller + +pci:v0000197Bd00002365* + ID_MODEL_FROM_DATABASE=JMB365 AHCI/IDE + +pci:v0000197Bd00002366* + ID_MODEL_FROM_DATABASE=JMB366 AHCI/IDE + +pci:v0000197Bd00002368* + ID_MODEL_FROM_DATABASE=JMB368 IDE controller + +pci:v0000197Bd00002369* + ID_MODEL_FROM_DATABASE=JMB369 Serial ATA Controller + +pci:v0000197Bd00002380* + ID_MODEL_FROM_DATABASE=IEEE 1394 Host Controller + +pci:v0000197Bd00002381* + ID_MODEL_FROM_DATABASE=Standard SD Host Controller + +pci:v0000197Bd00002382* + ID_MODEL_FROM_DATABASE=SD/MMC Host Controller + +pci:v0000197Bd00002383* + ID_MODEL_FROM_DATABASE=MS Host Controller + +pci:v0000197Bd00002384* + ID_MODEL_FROM_DATABASE=xD Host Controller + +pci:v0000197Bd00002386* + ID_MODEL_FROM_DATABASE=Standard SD Host Controller + +pci:v0000197Bd00002387* + ID_MODEL_FROM_DATABASE=SD/MMC Host Controller + +pci:v0000197Bd00002388* + ID_MODEL_FROM_DATABASE=MS Host Controller + +pci:v0000197Bd00002389* + ID_MODEL_FROM_DATABASE=xD Host Controller + +pci:v0000197Bd00002391* + ID_MODEL_FROM_DATABASE=Standard SD Host Controller + +pci:v0000197Bd00002392* + ID_MODEL_FROM_DATABASE=SD/MMC Host Controller + +pci:v0000197Bd00002393* + ID_MODEL_FROM_DATABASE=MS Host Controller + +pci:v0000197Bd00002394* + ID_MODEL_FROM_DATABASE=xD Host Controller + +pci:v00001982* + ID_VENDOR_FROM_DATABASE=Distant Early Warning Communications Inc + +pci:v00001982d00001600* + ID_MODEL_FROM_DATABASE=OX16C954 HOST-A + +pci:v00001982d000016FF* + ID_MODEL_FROM_DATABASE=OX16C954 HOST-B + +pci:v00001989* + ID_VENDOR_FROM_DATABASE=Montilio Inc. + +pci:v00001989d00000001* + ID_MODEL_FROM_DATABASE=RapidFile Bridge + +pci:v00001989d00008001* + ID_MODEL_FROM_DATABASE=RapidFile + +pci:v0000198A* + ID_VENDOR_FROM_DATABASE=Nallatech Ltd. + +pci:v00001993* + ID_VENDOR_FROM_DATABASE=Innominate Security Technologies AG + +pci:v00001999* + ID_VENDOR_FROM_DATABASE=A-Logics + +pci:v00001999d0000A900* + ID_MODEL_FROM_DATABASE=AM-7209 Video Processor + +pci:v0000199A* + ID_VENDOR_FROM_DATABASE=Pulse-LINK, Inc. + +pci:v0000199D* + ID_VENDOR_FROM_DATABASE=Xsigo Systems + +pci:v0000199Dd00008209* + ID_MODEL_FROM_DATABASE=Virtual NIC Device + +pci:v0000199Dd0000890A* + ID_MODEL_FROM_DATABASE=Virtual HBA Device + +pci:v0000199F* + ID_VENDOR_FROM_DATABASE=Auvitek + +pci:v0000199Fd00008501* + ID_MODEL_FROM_DATABASE=AU85X1 PCI REV1.1 + +pci:v0000199Fd00008521* + ID_MODEL_FROM_DATABASE=AU8521 TV card + +pci:v000019A2* + ID_VENDOR_FROM_DATABASE=Emulex Corporation + +pci:v000019A2d00000200* + ID_MODEL_FROM_DATABASE=BladeEngine 10Gb PCI-E iSCSI adapter + +pci:v000019A2d00000201* + ID_MODEL_FROM_DATABASE=BladeEngine 10Gb PCIe Network Adapter + +pci:v000019A2d00000211* + ID_MODEL_FROM_DATABASE=BladeEngine2 10Gb Gen2 PCIe Network Adapter + +pci:v000019A2d00000212* + ID_MODEL_FROM_DATABASE=BladeEngine2 10Gb Gen2 PCIe iSCSI Adapter + +pci:v000019A2d00000221* + ID_MODEL_FROM_DATABASE=BladeEngine3 10Gb Gen2 PCIe Network Adapter + +pci:v000019A2d00000222* + ID_MODEL_FROM_DATABASE=BladeEngine3 10Gb Gen2 PCIe iSCSI Adapter + +pci:v000019A2d00000700* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb NIC + +pci:v000019A2d00000700sv0000103Csd00001747* + ID_MODEL_FROM_DATABASE=NC550SFP DualPort 10GbE Server Adapter + +pci:v000019A2d00000700sv0000103Csd00001749* + ID_MODEL_FROM_DATABASE=NC550SFP Dual Port Server Adapter + +pci:v000019A2d00000700sv0000103Csd0000174A* + ID_MODEL_FROM_DATABASE=NC551m Dual Port FlexFabric 10Gb Adapter + +pci:v000019A2d00000700sv0000103Csd0000174B* + ID_MODEL_FROM_DATABASE=StorageWorks NC550 DualPort Converged Network Adapter + +pci:v000019A2d00000700sv0000103Csd00003314* + ID_MODEL_FROM_DATABASE=NC551i Dual Port FlexFabric 10Gb Adapter + +pci:v000019A2d00000702* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb iSCSI Initiator + +pci:v000019A2d00000704* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb FCoE Initiator + +pci:v000019A2d00000710* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb NIC (be3) + +pci:v000019A2d00000710sv0000103Csd00003315* + ID_MODEL_FROM_DATABASE=NC553i 10Gb 2-port FlexFabric Converged Network Adapter + +pci:v000019A2d00000710sv0000103Csd00003340* + ID_MODEL_FROM_DATABASE=NC552SFP 2-port 10Gb Server Adapter + +pci:v000019A2d00000710sv0000103Csd00003341* + ID_MODEL_FROM_DATABASE=NC552m 10Gb 2-port FlexFabric Converged Network Adapter + +pci:v000019A2d00000710sv0000103Csd00003345* + ID_MODEL_FROM_DATABASE=NC553m 10Gb 2-port FlexFabric Converged Network Adapter + +pci:v000019A2d00000712* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb iSCSI Initiator (be3) + +pci:v000019A2d00000714* + ID_MODEL_FROM_DATABASE=OneConnect 10Gb FCoE Initiator (be3) + +pci:v000019A2d00000714sv0000103Csd00003315* + ID_MODEL_FROM_DATABASE=NC553i 10Gb 2-port FlexFabric Converged Network Adapter + +pci:v000019A8* + ID_VENDOR_FROM_DATABASE=DAQDATA GmbH + +pci:v000019AC* + ID_VENDOR_FROM_DATABASE=Kasten Chase Applied Research + +pci:v000019ACd00000001* + ID_MODEL_FROM_DATABASE=ACA2400 Crypto Accelerator + +pci:v000019AE* + ID_VENDOR_FROM_DATABASE=Progeny Systems Corporation + +pci:v000019AEd00000520* + ID_MODEL_FROM_DATABASE=4135 HFT Interface Controller + +pci:v000019AEd00000521* + ID_MODEL_FROM_DATABASE=Decimator + +pci:v000019C1* + ID_VENDOR_FROM_DATABASE=Exegy Inc. + +pci:v000019D1* + ID_VENDOR_FROM_DATABASE=Motorola Expedience + +pci:v000019D4* + ID_VENDOR_FROM_DATABASE=Quixant Limited + +pci:v000019DA* + ID_VENDOR_FROM_DATABASE=ZOTAC International (MCO) Ltd. + +pci:v000019DE* + ID_VENDOR_FROM_DATABASE=Pico Computing + +pci:v000019E2* + ID_VENDOR_FROM_DATABASE=Vector Informatik GmbH + +pci:v000019E3* + ID_VENDOR_FROM_DATABASE=DDRdrive LLC + +pci:v000019E3d00005801* + ID_MODEL_FROM_DATABASE=DDRdrive X1 + +pci:v000019E3d00005808* + ID_MODEL_FROM_DATABASE=DDRdrive X8 + +pci:v000019E3d0000DD52* + ID_MODEL_FROM_DATABASE=DDRdrive X1-30 + +pci:v000019E7* + ID_VENDOR_FROM_DATABASE=NET (Network Equipment Technologies) + +pci:v000019E7d00001001* + ID_MODEL_FROM_DATABASE=STIX DSP Card + +pci:v000019E7d00001002* + ID_MODEL_FROM_DATABASE=STIX - 1 Port T1/E1 Card + +pci:v000019E7d00001003* + ID_MODEL_FROM_DATABASE=STIX - 2 Port T1/E1 Card + +pci:v000019E7d00001004* + ID_MODEL_FROM_DATABASE=STIX - 4 Port T1/E1 Card + +pci:v000019E7d00001005* + ID_MODEL_FROM_DATABASE=STIX - 4 Port FXS Card + +pci:v000019EE* + ID_VENDOR_FROM_DATABASE=Netronome Systems, Inc. + +pci:v000019F1* + ID_VENDOR_FROM_DATABASE=BFG Tech + +pci:v000019FF* + ID_VENDOR_FROM_DATABASE=Eclipse Electronic Systems, Inc. + +pci:v00001A03* + ID_VENDOR_FROM_DATABASE=ASPEED Technology, Inc. + +pci:v00001A03d00001150* + ID_MODEL_FROM_DATABASE=AST1150 PCI-to-PCI Bridge + +pci:v00001A03d00002000* + ID_MODEL_FROM_DATABASE=ASPEED Graphics Family + +pci:v00001A07* + ID_VENDOR_FROM_DATABASE=Kvaser AB + +pci:v00001A07d00000006* + ID_MODEL_FROM_DATABASE=CAN interface PC104+ HS/HS + +pci:v00001A07d00000007* + ID_MODEL_FROM_DATABASE=CAN interface PCIcanx II HS or HS/HS + +pci:v00001A07d00000008* + ID_MODEL_FROM_DATABASE=CAN interface PCIEcan HS or HS/HS + +pci:v00001A07d00000009* + ID_MODEL_FROM_DATABASE=CAN interface PCI104 HS/HS + +pci:v00001A08* + ID_VENDOR_FROM_DATABASE=Sierra semiconductor + +pci:v00001A08d00000000* + ID_MODEL_FROM_DATABASE=SC15064 + +pci:v00001A0E* + ID_VENDOR_FROM_DATABASE=DekTec Digital Video B.V. + +pci:v00001A0Ed0000083F* + ID_MODEL_FROM_DATABASE=DTA-2111 VHF/UHF Modulator + +pci:v00001A17* + ID_VENDOR_FROM_DATABASE=Force10 Networks, Inc. + +pci:v00001A17d00008002* + ID_MODEL_FROM_DATABASE=PB-10GE-2P 10GbE Security Card + +pci:v00001A1D* + ID_VENDOR_FROM_DATABASE=GFaI e.V. + +pci:v00001A1Dd00001A17* + ID_MODEL_FROM_DATABASE=Meta Networks MTP-1G IDPS NIC + +pci:v00001A1E* + ID_VENDOR_FROM_DATABASE=3Leaf Systems, Inc. + +pci:v00001A22* + ID_VENDOR_FROM_DATABASE=Ambric Inc. + +pci:v00001A29* + ID_VENDOR_FROM_DATABASE=Fortinet, Inc. + +pci:v00001A2B* + ID_VENDOR_FROM_DATABASE=Ascom AG + +pci:v00001A2Bd00000000* + ID_MODEL_FROM_DATABASE=GESP v1.2 + +pci:v00001A2Bd00000001* + ID_MODEL_FROM_DATABASE=GESP v1.3 + +pci:v00001A2Bd00000002* + ID_MODEL_FROM_DATABASE=ECOMP v1.3 + +pci:v00001A2Bd00000005* + ID_MODEL_FROM_DATABASE=ETP v1.4 + +pci:v00001A2Bd0000000A* + ID_MODEL_FROM_DATABASE=ETP-104 v1.1 + +pci:v00001A2Bd0000000E* + ID_MODEL_FROM_DATABASE=DSLP-104 v1.1 + +pci:v00001A32* + ID_VENDOR_FROM_DATABASE=Quanta Microsystems, Inc + +pci:v00001A3B* + ID_VENDOR_FROM_DATABASE=AzureWave + +pci:v00001A3Bd00001112* + ID_MODEL_FROM_DATABASE=AR9285 Wireless Network Adapter (PCI-Express) + +pci:v00001A41* + ID_VENDOR_FROM_DATABASE=Tilera Corp. + +pci:v00001A41d00000001* + ID_MODEL_FROM_DATABASE=TILE64 processor + +pci:v00001A41d00000002* + ID_MODEL_FROM_DATABASE=TILEPro processor + +pci:v00001A41d00000200* + ID_MODEL_FROM_DATABASE=TILE-Gx processor + +pci:v00001A41d00000201* + ID_MODEL_FROM_DATABASE=TILE-Gx Processor Virtual Function + +pci:v00001A41d00002000* + ID_MODEL_FROM_DATABASE=TILE-Gx PCI Express Root Port + +pci:v00001A4A* + ID_VENDOR_FROM_DATABASE=SLAC National Accelerator Lab PPA-REG + +pci:v00001A4Ad00001000* + ID_MODEL_FROM_DATABASE=MCOR Power Supply Controller + +pci:v00001A4Ad00001010* + ID_MODEL_FROM_DATABASE=AMC EVR - Stockholm Timing Board + +pci:v00001A4Ad00002000* + ID_MODEL_FROM_DATABASE=PGPCard - 4 Lane + +pci:v00001A4Ad00002001* + ID_MODEL_FROM_DATABASE=PGPCard - 8 Lane Plus EVR + +pci:v00001A4Ad00002010* + ID_MODEL_FROM_DATABASE=PCI-Express EVR + +pci:v00001A51* + ID_VENDOR_FROM_DATABASE=Hectronic AB + +pci:v00001A55* + ID_VENDOR_FROM_DATABASE=Rohde & Schwarz DVS GmbH + +pci:v00001A55d00000010* + ID_MODEL_FROM_DATABASE=SDStationOEM + +pci:v00001A55d00000011* + ID_MODEL_FROM_DATABASE=SDStationOEM II + +pci:v00001A55d00000020* + ID_MODEL_FROM_DATABASE=Centaurus + +pci:v00001A55d00000021* + ID_MODEL_FROM_DATABASE=Centaurus II + +pci:v00001A55d00000022* + ID_MODEL_FROM_DATABASE=Centaurus II LT + +pci:v00001A55d00000030* + ID_MODEL_FROM_DATABASE=CLIPSTER-VPU 1.x (Hugo) + +pci:v00001A55d00000040* + ID_MODEL_FROM_DATABASE=Hydra Cinema (JPEG) + +pci:v00001A55d00000050* + ID_MODEL_FROM_DATABASE=CLIPSTER-VPU 2.x (DigiLab) + +pci:v00001A55d00000060* + ID_MODEL_FROM_DATABASE=CLIPSTER-DCI 2.x (HydraX) + +pci:v00001A55d00000061* + ID_MODEL_FROM_DATABASE=Atomix + +pci:v00001A55d00000062* + ID_MODEL_FROM_DATABASE=Atomix LT + +pci:v00001A55d00000063* + ID_MODEL_FROM_DATABASE=Atomix HDMI + +pci:v00001A55d00000064* + ID_MODEL_FROM_DATABASE=Atomix STAN + +pci:v00001A55d00000065* + ID_MODEL_FROM_DATABASE=Atomix HDMI STAN + +pci:v00001A55d00000070* + ID_MODEL_FROM_DATABASE=RED Rocket + +pci:v00001A55d00000090* + ID_MODEL_FROM_DATABASE=CinePlay + +pci:v00001A56* + ID_VENDOR_FROM_DATABASE=Bigfoot Networks, Inc. + +pci:v00001A57* + ID_VENDOR_FROM_DATABASE=Highly Reliable Systems + +pci:v00001A58* + ID_VENDOR_FROM_DATABASE=Razer USA Ltd. + +pci:v00001A5D* + ID_VENDOR_FROM_DATABASE=Celoxica + +pci:v00001A5E* + ID_VENDOR_FROM_DATABASE=Aprius Inc. + +pci:v00001A5F* + ID_VENDOR_FROM_DATABASE=System TALKS Inc. + +pci:v00001A68* + ID_VENDOR_FROM_DATABASE=VirtenSys Limited + +pci:v00001A71* + ID_VENDOR_FROM_DATABASE=XenSource, Inc. + +pci:v00001A73* + ID_VENDOR_FROM_DATABASE=Violin Memory, Inc + +pci:v00001A73d00000001* + ID_MODEL_FROM_DATABASE=Mozart [Memory Appliance 1010] + +pci:v00001A76* + ID_VENDOR_FROM_DATABASE=Wavesat + +pci:v00001A77* + ID_VENDOR_FROM_DATABASE=Lightfleet Corporation + +pci:v00001A78* + ID_VENDOR_FROM_DATABASE=Virident Systems Inc. + +pci:v00001A78d00000031* + ID_MODEL_FROM_DATABASE=Virident FlashMAX Drive + +pci:v00001A78d00000031sv00001A78sd00000034* + ID_MODEL_FROM_DATABASE=FlashMAX PCIe SSD [rev 3] + +pci:v00001A78d00000031sv00001A78sd00000037* + ID_MODEL_FROM_DATABASE=FlashMAX PCIe SSD [rev 3D] + +pci:v00001A78d00000031sv00001A78sd00000038* + ID_MODEL_FROM_DATABASE=FlashMAX PCIe SSD [rev 4] + +pci:v00001A78d00000031sv00001A78sd00000039* + ID_MODEL_FROM_DATABASE=FlashMAX PCIe SSD [rev 4D] + +pci:v00001A78d00000040* + ID_MODEL_FROM_DATABASE=FlashMAX II + +pci:v00001A78d00000041* + ID_MODEL_FROM_DATABASE=FlashMAX II + +pci:v00001A78d00000042* + ID_MODEL_FROM_DATABASE=FlashMAX II + +pci:v00001A84* + ID_VENDOR_FROM_DATABASE=Commex Technologies + +pci:v00001A84d00000001* + ID_MODEL_FROM_DATABASE=Vulcan SP HT6210 10-Gigabit Ethernet (rev 02) + +pci:v00001A88* + ID_VENDOR_FROM_DATABASE=MEN Mikro Elektronik + +pci:v00001A88d00004D45* + ID_MODEL_FROM_DATABASE=Multifunction IP core + +pci:v00001A8C* + ID_VENDOR_FROM_DATABASE=Verigy Pte. Ltd. + +pci:v00001A8Cd00001100* + ID_MODEL_FROM_DATABASE=E8001-66443 PCI Express CIC + +pci:v00001A8E* + ID_VENDOR_FROM_DATABASE=DRS Technologies + +pci:v00001A8Ed00002090* + ID_MODEL_FROM_DATABASE=Model 2090 PCI Express + +pci:v00001AA8* + ID_VENDOR_FROM_DATABASE=Ciprico, Inc. + +pci:v00001AA8d00000009* + ID_MODEL_FROM_DATABASE=RAIDCore Controller + +pci:v00001AA8d0000000A* + ID_MODEL_FROM_DATABASE=RAIDCore Controller + +pci:v00001AAE* + ID_VENDOR_FROM_DATABASE=Global Velocity, Inc. + +pci:v00001AB6* + ID_VENDOR_FROM_DATABASE=CalDigit, Inc. + +pci:v00001AB6d00006201* + ID_MODEL_FROM_DATABASE=RAID Card + +pci:v00001AB8* + ID_VENDOR_FROM_DATABASE=Parallels, Inc. + +pci:v00001AB8d00004000* + ID_MODEL_FROM_DATABASE=Virtual Machine Communication Interface + +pci:v00001AB8d00004005* + ID_MODEL_FROM_DATABASE=Accelerated Virtual Video Adapter + +pci:v00001AB8d00004006* + ID_MODEL_FROM_DATABASE=Memory Ballooning Controller + +pci:v00001AB9* + ID_VENDOR_FROM_DATABASE=Espia Srl + +pci:v00001ACC* + ID_VENDOR_FROM_DATABASE=Point of View BV + +pci:v00001AD7* + ID_VENDOR_FROM_DATABASE=Spectracom Corporation + +pci:v00001AD7d00008000* + ID_MODEL_FROM_DATABASE=TSync-PCIe Time Code Processor + +pci:v00001AD7d00009100* + ID_MODEL_FROM_DATABASE=TPRO-PCI-66U Timecode Reader/Generator + +pci:v00001ADE* + ID_VENDOR_FROM_DATABASE=Spin Master Ltd. + +pci:v00001ADEd00001501* + ID_MODEL_FROM_DATABASE=Swipetech barcode scanner + +pci:v00001AE0* + ID_VENDOR_FROM_DATABASE=Google, Inc. + +pci:v00001AE7* + ID_VENDOR_FROM_DATABASE=First Wise Media GmbH + +pci:v00001AE7d00000520* + ID_MODEL_FROM_DATABASE=HFC-S PCI A [X-TENSIONS XC-520] + +pci:v00001AE8* + ID_VENDOR_FROM_DATABASE=Silicon Software GmbH + +pci:v00001AE8d00000A40* + ID_MODEL_FROM_DATABASE=microEnable IV-BASE x1 + +pci:v00001AE8d00000A41* + ID_MODEL_FROM_DATABASE=microEnable IV-FULL x1 + +pci:v00001AE8d00000A44* + ID_MODEL_FROM_DATABASE=microEnable IV-FULL x4 + +pci:v00001AE8d00000E44* + ID_MODEL_FROM_DATABASE=microEnable IV-GigE x4 + +pci:v00001AE9* + ID_VENDOR_FROM_DATABASE=Wilocity Ltd. + +pci:v00001AE9d00000101* + ID_MODEL_FROM_DATABASE=Wil6200 PCI Express Root Port + +pci:v00001AE9d00000200* + ID_MODEL_FROM_DATABASE=Wil6200 PCI Express Port + +pci:v00001AE9d00000201* + ID_MODEL_FROM_DATABASE=Wil6200 Wireless PCI Express Port + +pci:v00001AE9d00000301* + ID_MODEL_FROM_DATABASE=Wil6200 802.11ad Wireless Network Adapter + +pci:v00001AEC* + ID_VENDOR_FROM_DATABASE=Wolfson Microelectronics + +pci:v00001AED* + ID_VENDOR_FROM_DATABASE=Fusion-io + +pci:v00001AEDd00001003* + ID_MODEL_FROM_DATABASE=ioDimm3 (v1.2) + +pci:v00001AEDd00001005* + ID_MODEL_FROM_DATABASE=ioDimm3 + +pci:v00001AEDd00001005sv00001014sd000003C3* + ID_MODEL_FROM_DATABASE=High IOPS SSD PCIe Adapter + +pci:v00001AEDd00001005sv0000103Csd0000176F* + ID_MODEL_FROM_DATABASE=1.28TB MLC PCIe ioDrive Duo + +pci:v00001AEDd00001005sv0000103Csd00001770* + ID_MODEL_FROM_DATABASE=5.2TB MLC PCIe ioDrive Octal + +pci:v00001AEDd00001005sv0000103Csd0000178B* + ID_MODEL_FROM_DATABASE=160GB SLC PCIe ioDrive + +pci:v00001AEDd00001005sv0000103Csd0000178C* + ID_MODEL_FROM_DATABASE=320GB MLC PCIe ioDrive + +pci:v00001AEDd00001005sv0000103Csd0000178D* + ID_MODEL_FROM_DATABASE=320GB SLC PCIe ioDrive Duo + +pci:v00001AEDd00001005sv0000103Csd0000178E* + ID_MODEL_FROM_DATABASE=640GB MLC PCIe ioDrive Duo + +pci:v00001AEDd00001006* + ID_MODEL_FROM_DATABASE=ioXtreme + +pci:v00001AEDd00001007* + ID_MODEL_FROM_DATABASE=ioXtreme Pro + +pci:v00001AEDd00001008* + ID_MODEL_FROM_DATABASE=ioXtreme-2 + +pci:v00001AEDd00002001* + ID_MODEL_FROM_DATABASE=ioDrive2 + +pci:v00001AEE* + ID_VENDOR_FROM_DATABASE=Caustic Graphics Inc. + +pci:v00001AF4* + ID_VENDOR_FROM_DATABASE=Red Hat, Inc + +pci:v00001AF4d00001000* + ID_MODEL_FROM_DATABASE=Virtio network device + +pci:v00001AF4d00001001* + ID_MODEL_FROM_DATABASE=Virtio block device + +pci:v00001AF4d00001002* + ID_MODEL_FROM_DATABASE=Virtio memory balloon + +pci:v00001AF4d00001003* + ID_MODEL_FROM_DATABASE=Virtio console + +pci:v00001AF4d00001004* + ID_MODEL_FROM_DATABASE=Virtio SCSI + +pci:v00001AF4d00001005* + ID_MODEL_FROM_DATABASE=Virtio RNG + +pci:v00001AF4d00001009* + ID_MODEL_FROM_DATABASE=Virtio filesystem + +pci:v00001AF5* + ID_VENDOR_FROM_DATABASE=Netezza Corp. + +pci:v00001AFA* + ID_VENDOR_FROM_DATABASE=J & W Electronics Co., Ltd. + +pci:v00001B03* + ID_VENDOR_FROM_DATABASE=Magnum Semiconductor, Inc, + +pci:v00001B03d00006100* + ID_MODEL_FROM_DATABASE=DXT/DXTPro Multiformat Broadcast HD/SD Encoder/Decoder/Transcoder + +pci:v00001B08* + ID_VENDOR_FROM_DATABASE=MSC Vertriebs GmbH + +pci:v00001B0A* + ID_VENDOR_FROM_DATABASE=Pegatron + +pci:v00001B13* + ID_VENDOR_FROM_DATABASE=Jaton Corp + +pci:v00001B1A* + ID_VENDOR_FROM_DATABASE=K&F Computing Research Co. + +pci:v00001B1Ad00000E70* + ID_MODEL_FROM_DATABASE=GRAPE + +pci:v00001B21* + ID_VENDOR_FROM_DATABASE=ASMedia Technology Inc. + +pci:v00001B21d00000611* + ID_MODEL_FROM_DATABASE=ASM1061 SATA IDE Controller + +pci:v00001B21d00000612* + ID_MODEL_FROM_DATABASE=ASM1062 Serial ATA Controller + +pci:v00001B21d00000612sv00001849sd00000612* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00001B21d00001042* + ID_MODEL_FROM_DATABASE=ASM1042 SuperSpeed USB Host Controller + +pci:v00001B21d00001042sv00001849sd00001042* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00001B21d00001080* + ID_MODEL_FROM_DATABASE=ASM1083/1085 PCIe to PCI Bridge + +pci:v00001B21d00001080sv00001849sd00001080* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00001B2C* + ID_VENDOR_FROM_DATABASE=Opal-RT Technologies Inc. + +pci:v00001B36* + ID_VENDOR_FROM_DATABASE=Red Hat, Inc. + +pci:v00001B37* + ID_VENDOR_FROM_DATABASE=Signal Processing Devices Sweden AB + +pci:v00001B37d00000014* + ID_MODEL_FROM_DATABASE=ADQ412 + +pci:v00001B3A* + ID_VENDOR_FROM_DATABASE=Westar Display Technologies + +pci:v00001B3Ad00007589* + ID_MODEL_FROM_DATABASE=HRED J2000 - JPEG 2000 Video Codec Device + +pci:v00001B3E* + ID_VENDOR_FROM_DATABASE=Teradata Corp. + +pci:v00001B3Ed00001FA8* + ID_MODEL_FROM_DATABASE=BYNET BIC2SE/X + +pci:v00001B3Ed00001FA8sv00001B3Esd000000A3* + ID_MODEL_FROM_DATABASE=BYNET BIC2SX + +pci:v00001B3Ed00001FA8sv00001B3Esd000000C3* + ID_MODEL_FROM_DATABASE=BYNET BIC2SE + +pci:v00001B40* + ID_VENDOR_FROM_DATABASE=Schooner Information Technology, Inc. + +pci:v00001B47* + ID_VENDOR_FROM_DATABASE=Numascale AS + +pci:v00001B47d00000601* + ID_MODEL_FROM_DATABASE=NumaChip N601 + +pci:v00001B47d00000602* + ID_MODEL_FROM_DATABASE=NumaChip N602 + +pci:v00001B4B* + ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. + +pci:v00001B4Bd00000640* + ID_MODEL_FROM_DATABASE=88SE9128 SATA III 6Gb/s RAID Controller + +pci:v00001B4Bd00009120* + ID_MODEL_FROM_DATABASE=88SE9120 SATA 6Gb/s Controller + +pci:v00001B4Bd00009123* + ID_MODEL_FROM_DATABASE=88SE9123 PCIe SATA 6.0 Gb/s controller + +pci:v00001B4Bd00009125* + ID_MODEL_FROM_DATABASE=88SE9125 PCIe SATA 6.0 Gb/s controller + +pci:v00001B4Bd00009128* + ID_MODEL_FROM_DATABASE=88SE9128 PCIe SATA 6 Gb/s RAID controller + +pci:v00001B4Bd00009130* + ID_MODEL_FROM_DATABASE=88SE9128 PCIe SATA 6 Gb/s RAID controller with HyperDuo + +pci:v00001B4Bd00009130sv00001043sd00008438* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00001B4Bd00009172* + ID_MODEL_FROM_DATABASE=88SE9172 SATA 6Gb/s Controller + +pci:v00001B4Bd0000917A* + ID_MODEL_FROM_DATABASE=88SE9172 SATA III 6Gb/s RAID Controller + +pci:v00001B4Bd00009183* + ID_MODEL_FROM_DATABASE=88SS9183 PCIe SSD Controller + +pci:v00001B4Bd00009192* + ID_MODEL_FROM_DATABASE=88SE9172 SATA III 6Gb/s RAID Controller + +pci:v00001B4Bd000091A0* + ID_MODEL_FROM_DATABASE=88SE912x SATA 6Gb/s Controller [IDE mode] + +pci:v00001B4Bd000091A4* + ID_MODEL_FROM_DATABASE=88SE912x IDE Controller + +pci:v00001B4Bd00009230* + ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller + +pci:v00001B4Bd00009480* + ID_MODEL_FROM_DATABASE=88SE9480 SAS/SATA 6Gb/s RAID controller + +pci:v00001B4Bd00009485* + ID_MODEL_FROM_DATABASE=88SE9485 SAS/SATA 6Gb/s controller + +pci:v00001B55* + ID_VENDOR_FROM_DATABASE=NetUP Inc. + +pci:v00001B55d00002A2C* + ID_MODEL_FROM_DATABASE=Dual DVB-S2-CI card + +pci:v00001B55d0000E2E4* + ID_MODEL_FROM_DATABASE=Dual DVB-T/C-CI RF card + +pci:v00001B55d0000E5F4* + ID_MODEL_FROM_DATABASE=MPEG2 and H264 Encoder-Transcoder + +pci:v00001B55d0000F1C4* + ID_MODEL_FROM_DATABASE=Dual ASI-RX/TX-CI card + +pci:v00001B6F* + ID_VENDOR_FROM_DATABASE=Etron Technology, Inc. + +pci:v00001B6Fd00007023* + ID_MODEL_FROM_DATABASE=EJ168 USB 3.0 Host Controller + +pci:v00001B6Fd00007052* + ID_MODEL_FROM_DATABASE=EJ188/EJ198 USB 3.0 Host Controller + +pci:v00001B73* + ID_VENDOR_FROM_DATABASE=Fresco Logic + +pci:v00001B73d00001000* + ID_MODEL_FROM_DATABASE=FL1000G USB 3.0 Host Controller + +pci:v00001B73d00001000sv00001D5Csd00001000* + ID_MODEL_FROM_DATABASE=Anker USB 3.0 Express Card + +pci:v00001B73d00001009* + ID_MODEL_FROM_DATABASE=FL1009 USB 3.0 Host Controller + +pci:v00001B74* + ID_VENDOR_FROM_DATABASE=OpenVox Communication Co. Ltd. + +pci:v00001B74d00000115* + ID_MODEL_FROM_DATABASE=D115P/D115E Single-port E1/T1 card + +pci:v00001B74d0000D130* + ID_MODEL_FROM_DATABASE=D130P/D130E Single-port E1/T1 card (3rd GEN) + +pci:v00001B74d0000D210* + ID_MODEL_FROM_DATABASE=D210P/D210E Dual-port E1/T1 card(2nd generation) + +pci:v00001B74d0000D230* + ID_MODEL_FROM_DATABASE=D230 Dual-port E1/T1 card (2nd generation) + +pci:v00001B74d0000D410* + ID_MODEL_FROM_DATABASE=D410/430 Quad-port E1/T1 card + +pci:v00001B74d0000D430* + ID_MODEL_FROM_DATABASE=D410/430 Quad-port E1/T1 card + +pci:v00001B85* + ID_VENDOR_FROM_DATABASE=OCZ Technology Group, Inc. + +pci:v00001B85d00001041* + ID_MODEL_FROM_DATABASE=RevoDrive 3 X2 PCI-Express SSD 240 GB (Marvell Controller) + +pci:v00001B96* + ID_VENDOR_FROM_DATABASE=Western Digital + +pci:v00001B9A* + ID_VENDOR_FROM_DATABASE=XAVi Technologies Corp. + +pci:v00001BAD* + ID_VENDOR_FROM_DATABASE=ReFLEX CES + +pci:v00001BB0* + ID_VENDOR_FROM_DATABASE=SimpliVity Corporation + +pci:v00001BB0d00000002* + ID_MODEL_FROM_DATABASE=OmniCube Accelerator OA-3000 + +pci:v00001BB0d00000010* + ID_MODEL_FROM_DATABASE=OmniCube Accelerator OA-3000-2 + +pci:v00001BB3* + ID_VENDOR_FROM_DATABASE=Bluecherry + +pci:v00001BB3d00004304* + ID_MODEL_FROM_DATABASE=BC-04120A MPEG4 4 port video encoder / decoder + +pci:v00001BB3d00004309* + ID_MODEL_FROM_DATABASE=BC-08240A MPEG4 4 port video encoder / decoder + +pci:v00001BB3d00004310* + ID_MODEL_FROM_DATABASE=BC-16480A MPEG4 16 port video encoder / decoder + +pci:v00001BB3d00004E04* + ID_MODEL_FROM_DATABASE=BC-04120A 4 port MPEG4 video encoder / decoder + +pci:v00001BB3d00004E09* + ID_MODEL_FROM_DATABASE=BC-08240A 8 port MPEG4 video encoder / decoder + +pci:v00001BB3d00004E10* + ID_MODEL_FROM_DATABASE=BC-16480A 16 port MPEG4 video encoder / decoder + +pci:v00001BB3d00005304* + ID_MODEL_FROM_DATABASE=BC-H04120A 4 port H.264 video and audio encoder / decoder + +pci:v00001BB3d00005308* + ID_MODEL_FROM_DATABASE=BC-H08240A 8 port H.264 video and audio encoder / decoder + +pci:v00001BB3d00005310* + ID_MODEL_FROM_DATABASE=BC-H16480A 16 port H.264 video and audio encoder / decoder + +pci:v00001BB5* + ID_VENDOR_FROM_DATABASE=Quantenna Communications, Inc. + +pci:v00001BBF* + ID_VENDOR_FROM_DATABASE=Maxeler Technologies Ltd. + +pci:v00001BBFd00000003* + ID_MODEL_FROM_DATABASE=MAX3 + +pci:v00001BBFd00000004* + ID_MODEL_FROM_DATABASE=MAX4 + +pci:v00001BF4* + ID_VENDOR_FROM_DATABASE=VTI Instruments Corporation + +pci:v00001BFD* + ID_VENDOR_FROM_DATABASE=EeeTOP + +pci:v00001C1C* + ID_VENDOR_FROM_DATABASE=Symphony + +pci:v00001C1Cd00000001* + ID_MODEL_FROM_DATABASE=82C101 + +pci:v00001C2C* + ID_VENDOR_FROM_DATABASE=Fiberblaze + +pci:v00001C2Cd0000000A* + ID_MODEL_FROM_DATABASE=Capture + +pci:v00001C2Cd0000000F* + ID_MODEL_FROM_DATABASE=SmartNIC + +pci:v00001C2Cd000000A0* + ID_MODEL_FROM_DATABASE=FBC4G Capture 4x1Gb + +pci:v00001C2Cd000000A1* + ID_MODEL_FROM_DATABASE=FBC4XG Capture 4x10Gb + +pci:v00001C2Cd000000A2* + ID_MODEL_FROM_DATABASE=FBC8XG Capture 8x10Gb + +pci:v00001C32* + ID_VENDOR_FROM_DATABASE=Highland Technology, Inc. + +pci:v00001C33* + ID_VENDOR_FROM_DATABASE=Daktronics, Inc + +pci:v00001C3B* + ID_VENDOR_FROM_DATABASE=Accensus, LLC + +pci:v00001C3Bd00000200* + ID_MODEL_FROM_DATABASE=Telas2 + +pci:v00001C3Bd00000300* + ID_MODEL_FROM_DATABASE=Telas 2.V + +pci:v00001C44* + ID_VENDOR_FROM_DATABASE=Enmotus Inc + +pci:v00001C44d00008000* + ID_MODEL_FROM_DATABASE=8000 Storage IO Controller + +pci:v00001C7F* + ID_VENDOR_FROM_DATABASE=Elektrobit Austria GmbH + +pci:v00001C7Fd00005100* + ID_MODEL_FROM_DATABASE=EB5100 + +pci:v00001C8A* + ID_VENDOR_FROM_DATABASE=TSF5 Corporation + +pci:v00001C8Ad00000001* + ID_MODEL_FROM_DATABASE=Hunter PCI Express + +pci:v00001CB1* + ID_VENDOR_FROM_DATABASE=Collion UG & Co.KG + +pci:v00001CC5* + ID_VENDOR_FROM_DATABASE=Embedded Intelligence, Inc. + +pci:v00001CC5d00000100* + ID_MODEL_FROM_DATABASE=CAN-PCIe-02 + +pci:v00001CE4* + ID_VENDOR_FROM_DATABASE=Exablaze + +pci:v00001CE4d00000001* + ID_MODEL_FROM_DATABASE=ExaNIC X4 + +pci:v00001CE4d00000002* + ID_MODEL_FROM_DATABASE=ExaNIC X2 + +pci:v00001CF7* + ID_VENDOR_FROM_DATABASE=Subspace Dynamics + +pci:v00001D44* + ID_VENDOR_FROM_DATABASE=DPT + +pci:v00001D44d0000A400* + ID_MODEL_FROM_DATABASE=PM2x24/PM3224 + +pci:v00001D5C* + ID_VENDOR_FROM_DATABASE=Fantasia Trading LLC + +pci:v00001DE1* + ID_VENDOR_FROM_DATABASE=Tekram Technology Co.,Ltd. + +pci:v00001DE1d00000391* + ID_MODEL_FROM_DATABASE=TRM-S1040 + +pci:v00001DE1d00002020* + ID_MODEL_FROM_DATABASE=DC-390 + +pci:v00001DE1d0000690C* + ID_MODEL_FROM_DATABASE=690c + +pci:v00001DE1d0000DC29* + ID_MODEL_FROM_DATABASE=DC290 + +pci:v00001FC0* + ID_VENDOR_FROM_DATABASE=Ascom (Finland) Oy + +pci:v00001FC0d00000300* + ID_MODEL_FROM_DATABASE=E2200 Dual E1/Rawpipe Card + +pci:v00001FC0d00000301* + ID_MODEL_FROM_DATABASE=C5400 SHDSL/E1 Card + +pci:v00001FC1* + ID_VENDOR_FROM_DATABASE=QLogic, Corp. + +pci:v00001FC1d0000000D* + ID_MODEL_FROM_DATABASE=IBA6110 InfiniBand HCA + +pci:v00001FC1d00000010* + ID_MODEL_FROM_DATABASE=IBA6120 InfiniBand HCA + +pci:v00001FC9* + ID_VENDOR_FROM_DATABASE=Tehuti Networks Ltd. + +pci:v00001FC9d00003009* + ID_MODEL_FROM_DATABASE=10-Giga TOE SmartNIC + +pci:v00001FC9d00003010* + ID_MODEL_FROM_DATABASE=10-Giga TOE SmartNIC + +pci:v00001FC9d00003010sv00000000sd00003002* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port XFP SmartNIC + +pci:v00001FC9d00003010sv00000000sd00003004* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port SFP+ SmartNIC + +pci:v00001FC9d00003010sv00000000sd00003008* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port CX4 SmartNIC + +pci:v00001FC9d00003014* + ID_MODEL_FROM_DATABASE=10-Giga TOE SmartNIC 2-Port + +pci:v00001FC9d00003014sv00000000sd00003003* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port XFP Low Profile SmartNIC + +pci:v00001FC9d00003014sv00000000sd00003005* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port SFP+ Low Profile SmartNIC + +pci:v00001FC9d00003014sv00000000sd00003014* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port CX4 Low Profile SmartNIC + +pci:v00001FC9d00003110* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port SmartNIC + +pci:v00001FC9d00003110sv00000000sd00003004* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port SFP+ SmartNIC + +pci:v00001FC9d00003114* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port Low Profile SmartNIC + +pci:v00001FC9d00003114sv00000000sd00003005* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port SFP+ Low Profile SmartNIC + +pci:v00001FC9d00003114sv00000000sd00003011* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port SFP+/CX4 Low Profile SmartNIC + +pci:v00001FC9d00003114sv00000000sd00003012* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port CX4/SFP+ Low Profile SmartNIC + +pci:v00001FC9d00003114sv00000000sd00003014* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port CX4 Low Profile SmartNIC + +pci:v00001FC9d00003310* + ID_MODEL_FROM_DATABASE=10-Giga TOE SFP+ Single Port SmartNIC + +pci:v00001FC9d00003310sv00000000sd00003004* + ID_MODEL_FROM_DATABASE=10-Giga TOE Single Port SFP+ SmartNIC + +pci:v00001FC9d00003314* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port Low Profile SmartNIC + +pci:v00001FC9d00003314sv00000000sd00003005* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port SFP+ Low Profile SmartNIC + +pci:v00001FC9d00003314sv00000000sd00003011* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port SFP+/CX4 Low Profile SmartNIC + +pci:v00001FC9d00003314sv00000000sd00003012* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port CX4/SFP+ Low Profile SmartNIC + +pci:v00001FC9d00003314sv00000000sd00003014* + ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port CX4 Low Profile SmartNIC + +pci:v00001FCE* + ID_VENDOR_FROM_DATABASE=Cognio Inc. + +pci:v00001FCEd00000001* + ID_MODEL_FROM_DATABASE=Spectrum Analyzer PC Card (SAgE) + +pci:v00001FD4* + ID_VENDOR_FROM_DATABASE=SUNIX Co., Ltd. + +pci:v00001FD4d00000001* + ID_MODEL_FROM_DATABASE=Matrix multiport serial adapter + +pci:v00001FD4d00001999* + ID_MODEL_FROM_DATABASE=Multiport serial controller + +pci:v00002000* + ID_VENDOR_FROM_DATABASE=Smart Link Ltd. + +pci:v00002000d00002800* + ID_MODEL_FROM_DATABASE=SmartPCI2800 V.92 PCI Soft DFT + +pci:v00002001* + ID_VENDOR_FROM_DATABASE=Temporal Research Ltd + +pci:v00002003* + ID_VENDOR_FROM_DATABASE=Smart Link Ltd. + +pci:v00002003d00008800* + ID_MODEL_FROM_DATABASE=LM-I56N + +pci:v00002004* + ID_VENDOR_FROM_DATABASE=Smart Link Ltd. + +pci:v000020F4* + ID_VENDOR_FROM_DATABASE=TRENDnet + +pci:v00002116* + ID_VENDOR_FROM_DATABASE=ZyDAS Technology Corp. + +pci:v000021C3* + ID_VENDOR_FROM_DATABASE=21st Century Computer Corp. + +pci:v00002304* + ID_VENDOR_FROM_DATABASE=Colorgraphic Communications Corp. + +pci:v00002348* + ID_VENDOR_FROM_DATABASE=Racore + +pci:v00002348d00002010* + ID_MODEL_FROM_DATABASE=8142 100VG/AnyLAN + +pci:v00002646* + ID_VENDOR_FROM_DATABASE=Kingston Technologies + +pci:v0000270B* + ID_VENDOR_FROM_DATABASE=Xantel Corporation + +pci:v0000270F* + ID_VENDOR_FROM_DATABASE=Chaintech Computer Co. Ltd + +pci:v00002711* + ID_VENDOR_FROM_DATABASE=AVID Technology Inc. + +pci:v00002955* + ID_VENDOR_FROM_DATABASE=Connectix Virtual PC + +pci:v00002955d00006E61* + ID_MODEL_FROM_DATABASE=OHCI USB 1.1 controller + +pci:v00002A15* + ID_VENDOR_FROM_DATABASE=3D Vision(???) + +pci:v00003000* + ID_VENDOR_FROM_DATABASE=Hansol Electronics Inc. + +pci:v00003142* + ID_VENDOR_FROM_DATABASE=Post Impression Systems. + +pci:v000031AB* + ID_VENDOR_FROM_DATABASE=Zonet + +pci:v000031ABd00001FAA* + ID_MODEL_FROM_DATABASE=ZEW1602 802.11b/g Wireless Adapter + +pci:v00003388* + ID_VENDOR_FROM_DATABASE=Hint Corp + +pci:v00003388d00000013* + ID_MODEL_FROM_DATABASE=HiNT HC4 PCI to ISDN bridge, Multimedia audio controller + +pci:v00003388d00000014* + ID_MODEL_FROM_DATABASE=HiNT HC4 PCI to ISDN bridge, Network controller + +pci:v00003388d00000020* + ID_MODEL_FROM_DATABASE=HB6 Universal PCI-PCI bridge (transparent mode) + +pci:v00003388d00000021* + ID_MODEL_FROM_DATABASE=HB6 Universal PCI-PCI bridge (non-transparent mode) + +pci:v00003388d00000021sv00001775sd0000C200* + ID_MODEL_FROM_DATABASE=C2K CompactPCI interface bridge + +pci:v00003388d00000021sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00003388d00000021sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00003388d00000021sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00003388d00000021sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 mainboard + +pci:v00003388d00000021sv00004C53sd000010A0* + ID_MODEL_FROM_DATABASE=CA3/CR3 mainboard + +pci:v00003388d00000021sv00004C53sd00003010* + ID_MODEL_FROM_DATABASE=PPCI mezzanine (32-bit PMC) + +pci:v00003388d00000021sv00004C53sd00003011* + ID_MODEL_FROM_DATABASE=PPCI mezzanine (64-bit PMC) + +pci:v00003388d00000021sv00004C53sd00004000* + ID_MODEL_FROM_DATABASE=PMCCARR1 carrier board + +pci:v00003388d00000022* + ID_MODEL_FROM_DATABASE=HiNT HB4 PCI-PCI Bridge (PCI6150) + +pci:v00003388d00000026* + ID_MODEL_FROM_DATABASE=HB2 PCI-PCI Bridge + +pci:v00003388d00001018* + ID_MODEL_FROM_DATABASE=Audiotrak INCA88 + +pci:v00003388d00001019* + ID_MODEL_FROM_DATABASE=Miditrak 2120 + +pci:v00003388d0000101A* + ID_MODEL_FROM_DATABASE=E.Band [AudioTrak Inca88] + +pci:v00003388d0000101B* + ID_MODEL_FROM_DATABASE=E.Band [AudioTrak Inca88] + +pci:v00003388d00008011* + ID_MODEL_FROM_DATABASE=VXPro II Chipset + +pci:v00003388d00008011sv00003388sd00008011* + ID_MODEL_FROM_DATABASE=VXPro II Chipset CPU to PCI Bridge + +pci:v00003388d00008012* + ID_MODEL_FROM_DATABASE=VXPro II Chipset + +pci:v00003388d00008012sv00003388sd00008012* + ID_MODEL_FROM_DATABASE=VXPro II Chipset PCI to ISA Bridge + +pci:v00003388d00008013* + ID_MODEL_FROM_DATABASE=VXPro II IDE + +pci:v00003388d00008013sv00003388sd00008013* + ID_MODEL_FROM_DATABASE=VXPro II Chipset EIDE Controller + +pci:v00003388d0000A103* + ID_MODEL_FROM_DATABASE=Blackmagic Design DeckLink HD Pro + +pci:v00003411* + ID_VENDOR_FROM_DATABASE=Quantum Designs (H.K.) Inc + +pci:v00003442* + ID_VENDOR_FROM_DATABASE=Bihl+Wiedemann GmbH + +pci:v00003442d00001783* + ID_MODEL_FROM_DATABASE=AS-i 3.0 cPCI Master + +pci:v00003442d00001922* + ID_MODEL_FROM_DATABASE=AS-i 3.0 PCI Master + +pci:v00003475* + ID_VENDOR_FROM_DATABASE=Arastra Inc. + +pci:v00003513* + ID_VENDOR_FROM_DATABASE=ARCOM Control Systems Ltd + +pci:v000037D9* + ID_VENDOR_FROM_DATABASE=ITD Firm ltd. + +pci:v000037D9d00001138* + ID_MODEL_FROM_DATABASE=SCHD-PH-8 Phase detector + +pci:v00003842* + ID_VENDOR_FROM_DATABASE=eVga.com. Corp. + +pci:v000038EF* + ID_VENDOR_FROM_DATABASE=4Links + +pci:v00003D3D* + ID_VENDOR_FROM_DATABASE=3DLabs + +pci:v00003D3Dd00000001* + ID_MODEL_FROM_DATABASE=GLINT 300SX + +pci:v00003D3Dd00000002* + ID_MODEL_FROM_DATABASE=GLINT 500TX + +pci:v00003D3Dd00000002sv00000000sd00000000* + ID_MODEL_FROM_DATABASE=GLoria L + +pci:v00003D3Dd00000003* + ID_MODEL_FROM_DATABASE=GLINT Delta + +pci:v00003D3Dd00000003sv00000000sd00000000* + ID_MODEL_FROM_DATABASE=GLoria XL + +pci:v00003D3Dd00000004* + ID_MODEL_FROM_DATABASE=Permedia + +pci:v00003D3Dd00000005* + ID_MODEL_FROM_DATABASE=Permedia + +pci:v00003D3Dd00000006* + ID_MODEL_FROM_DATABASE=GLINT MX + +pci:v00003D3Dd00000006sv00000000sd00000000* + ID_MODEL_FROM_DATABASE=GLoria XL + +pci:v00003D3Dd00000006sv00001048sd00000A42* + ID_MODEL_FROM_DATABASE=GLoria XXL + +pci:v00003D3Dd00000007* + ID_MODEL_FROM_DATABASE=3D Extreme + +pci:v00003D3Dd00000008* + ID_MODEL_FROM_DATABASE=GLINT Gamma G1 + +pci:v00003D3Dd00000008sv00001048sd00000A42* + ID_MODEL_FROM_DATABASE=GLoria XXL + +pci:v00003D3Dd00000009* + ID_MODEL_FROM_DATABASE=Permedia II 2D+3D + +pci:v00003D3Dd00000009sv00001040sd00000011* + ID_MODEL_FROM_DATABASE=AccelStar II + +pci:v00003D3Dd00000009sv00001048sd00000A42* + ID_MODEL_FROM_DATABASE=GLoria XXL + +pci:v00003D3Dd00000009sv000013E9sd00001000* + ID_MODEL_FROM_DATABASE=6221L-4U + +pci:v00003D3Dd00000009sv00003D3Dsd00000100* + ID_MODEL_FROM_DATABASE=AccelStar II 3D Accelerator + +pci:v00003D3Dd00000009sv00003D3Dsd00000111* + ID_MODEL_FROM_DATABASE=Permedia 3:16 + +pci:v00003D3Dd00000009sv00003D3Dsd00000114* + ID_MODEL_FROM_DATABASE=Santa Ana + +pci:v00003D3Dd00000009sv00003D3Dsd00000116* + ID_MODEL_FROM_DATABASE=Oxygen GVX1 + +pci:v00003D3Dd00000009sv00003D3Dsd00000119* + ID_MODEL_FROM_DATABASE=Scirocco + +pci:v00003D3Dd00000009sv00003D3Dsd00000120* + ID_MODEL_FROM_DATABASE=Santa Ana PCL + +pci:v00003D3Dd00000009sv00003D3Dsd00000125* + ID_MODEL_FROM_DATABASE=Oxygen VX1 + +pci:v00003D3Dd00000009sv00003D3Dsd00000127* + ID_MODEL_FROM_DATABASE=Permedia3 Create! + +pci:v00003D3Dd0000000A* + ID_MODEL_FROM_DATABASE=GLINT R3 + +pci:v00003D3Dd0000000Asv00003D3Dsd00000121* + ID_MODEL_FROM_DATABASE=Oxygen VX1 + +pci:v00003D3Dd0000000C* + ID_MODEL_FROM_DATABASE=GLINT R3 [Oxygen VX1] + +pci:v00003D3Dd0000000Csv00003D3Dsd00000144* + ID_MODEL_FROM_DATABASE=Oxygen VX1-4X AGP [Permedia 4] + +pci:v00003D3Dd0000000D* + ID_MODEL_FROM_DATABASE=GLint R4 rev A + +pci:v00003D3Dd0000000E* + ID_MODEL_FROM_DATABASE=GLINT Gamma G2 + +pci:v00003D3Dd00000011* + ID_MODEL_FROM_DATABASE=GLint R4 rev B + +pci:v00003D3Dd00000012* + ID_MODEL_FROM_DATABASE=GLint R5 rev A + +pci:v00003D3Dd00000013* + ID_MODEL_FROM_DATABASE=GLint R5 rev B + +pci:v00003D3Dd00000020* + ID_MODEL_FROM_DATABASE=VP10 visual processor + +pci:v00003D3Dd00000022* + ID_MODEL_FROM_DATABASE=VP10 visual processor + +pci:v00003D3Dd00000024* + ID_MODEL_FROM_DATABASE=VP9 visual processor + +pci:v00003D3Dd0000002C* + ID_MODEL_FROM_DATABASE=Wildcat Realizm 100/200 + +pci:v00003D3Dd00000030* + ID_MODEL_FROM_DATABASE=Wildcat Realizm 800 + +pci:v00003D3Dd00000032* + ID_MODEL_FROM_DATABASE=Wildcat Realizm 500 + +pci:v00003D3Dd00000100* + ID_MODEL_FROM_DATABASE=Permedia II 2D+3D + +pci:v00003D3Dd000007A1* + ID_MODEL_FROM_DATABASE=Wildcat III 6210 + +pci:v00003D3Dd000007A2* + ID_MODEL_FROM_DATABASE=Sun XVR-500 Graphics Accelerator + +pci:v00003D3Dd000007A3* + ID_MODEL_FROM_DATABASE=Wildcat IV 7210 + +pci:v00003D3Dd00001004* + ID_MODEL_FROM_DATABASE=Permedia + +pci:v00003D3Dd00003D04* + ID_MODEL_FROM_DATABASE=Permedia + +pci:v00003D3Dd0000FFFF* + ID_MODEL_FROM_DATABASE=Glint VGA + +pci:v00004005* + ID_VENDOR_FROM_DATABASE=Avance Logic Inc. + +pci:v00004005d00000300* + ID_MODEL_FROM_DATABASE=ALS300 PCI Audio Device + +pci:v00004005d00000308* + ID_MODEL_FROM_DATABASE=ALS300+ PCI Audio Device + +pci:v00004005d00000309* + ID_MODEL_FROM_DATABASE=PCI Input Controller + +pci:v00004005d00001064* + ID_MODEL_FROM_DATABASE=ALG-2064 + +pci:v00004005d00002064* + ID_MODEL_FROM_DATABASE=ALG-2064i + +pci:v00004005d00002128* + ID_MODEL_FROM_DATABASE=ALG-2364A GUI Accelerator + +pci:v00004005d00002301* + ID_MODEL_FROM_DATABASE=ALG-2301 + +pci:v00004005d00002302* + ID_MODEL_FROM_DATABASE=ALG-2302 + +pci:v00004005d00002303* + ID_MODEL_FROM_DATABASE=AVG-2302 GUI Accelerator + +pci:v00004005d00002364* + ID_MODEL_FROM_DATABASE=ALG-2364A + +pci:v00004005d00002464* + ID_MODEL_FROM_DATABASE=ALG-2464 + +pci:v00004005d00002501* + ID_MODEL_FROM_DATABASE=ALG-2564A/25128A + +pci:v00004005d00004000* + ID_MODEL_FROM_DATABASE=ALS4000 Audio Chipset + +pci:v00004005d00004000sv00004005sd00004000* + ID_MODEL_FROM_DATABASE=ALS4000 Audio Chipset + +pci:v00004005d00004710* + ID_MODEL_FROM_DATABASE=ALC200/200P + +pci:v00004033* + ID_VENDOR_FROM_DATABASE=Addtron Technology Co, Inc. + +pci:v00004033d00001360* + ID_MODEL_FROM_DATABASE=RTL8139 Ethernet + +pci:v00004040* + ID_VENDOR_FROM_DATABASE=NetXen Incorporated + +pci:v00004040d00000001* + ID_MODEL_FROM_DATABASE=NXB-10GXSR 10-Gigabit Ethernet PCIe Adapter with SR-XFP optical interface + +pci:v00004040d00000001sv0000103Csd00007047* + ID_MODEL_FROM_DATABASE=NC510F PCIe 10-Gigabit Server Adapter + +pci:v00004040d00000002* + ID_MODEL_FROM_DATABASE=NXB-10GCX4 10-Gigabit Ethernet PCIe Adapter with CX4 copper interface + +pci:v00004040d00000002sv0000103Csd00007048* + ID_MODEL_FROM_DATABASE=NC510c PCIe 10-Gigabit Server Adapter + +pci:v00004040d00000003* + ID_MODEL_FROM_DATABASE=NXB-4GCU Quad Gigabit Ethernet PCIe Adapter with 1000-BASE-T interface + +pci:v00004040d00000004* + ID_MODEL_FROM_DATABASE=BladeCenter-H 10-Gigabit Ethernet High Speed Daughter Card + +pci:v00004040d00000005* + ID_MODEL_FROM_DATABASE=NetXen Dual Port 10GbE Multifunction Adapter for c-Class + +pci:v00004040d00000005sv0000103Csd0000170E* + ID_MODEL_FROM_DATABASE=NC512m Dual Port 10GbE Multifunction BL-C Adapter + +pci:v00004040d00000024* + ID_MODEL_FROM_DATABASE=XG Mgmt + +pci:v00004040d00000025* + ID_MODEL_FROM_DATABASE=XG Mgmt + +pci:v00004040d00000100* + ID_MODEL_FROM_DATABASE=NX3031 Multifunction 1/10-Gigabit Server Adapter + +pci:v00004040d00000100sv0000103Csd0000171B* + ID_MODEL_FROM_DATABASE=NC522m Dual Port 10GbE Multifunction BL-c Adapter + +pci:v00004040d00000100sv0000103Csd00001740* + ID_MODEL_FROM_DATABASE=NC375T PCI Express Quad Port Gigabit Server Adapter + +pci:v00004040d00000100sv0000103Csd00003251* + ID_MODEL_FROM_DATABASE=NC375i 1G w/NC524SFP 10G Module + +pci:v00004040d00000100sv0000103Csd0000705A* + ID_MODEL_FROM_DATABASE=NC375i Integrated Quad Port Multifunction Gigabit Server Adapter + +pci:v00004040d00000100sv0000103Csd0000705B* + ID_MODEL_FROM_DATABASE=NC522SFP Dual Port 10GbE Server Adapter + +pci:v00004040d00000100sv0000152Dsd0000896B* + ID_MODEL_FROM_DATABASE=TG20 Dual Port 10GbE Server/Storage Adapter + +pci:v00004040d00000100sv00004040sd00000124* + ID_MODEL_FROM_DATABASE=NX3031 Quad Port Gigabit Server Adapter + +pci:v00004040d00000100sv00004040sd00000126* + ID_MODEL_FROM_DATABASE=Dual Port SFP+ 10GbE Server Adapter + +pci:v00004143* + ID_VENDOR_FROM_DATABASE=Digital Equipment Corp + +pci:v00004144* + ID_VENDOR_FROM_DATABASE=Alpha Data + +pci:v00004144d00000044* + ID_MODEL_FROM_DATABASE=ADM-XRCIIPro + +pci:v00004150* + ID_VENDOR_FROM_DATABASE=ONA Electroerosion + +pci:v00004150d00000001* + ID_MODEL_FROM_DATABASE=PCI32TLITE FILSTRUP1 PCI to VME Bridge Controller + +pci:v00004150d00000006* + ID_MODEL_FROM_DATABASE=PCI32TLITE UART 16550 Opencores + +pci:v00004150d00000007* + ID_MODEL_FROM_DATABASE=PCI32TLITE CAN Controller Opencores + +pci:v0000415A* + ID_VENDOR_FROM_DATABASE=Auzentech, Inc. + +pci:v0000416C* + ID_VENDOR_FROM_DATABASE=Aladdin Knowledge Systems + +pci:v0000416Cd00000100* + ID_MODEL_FROM_DATABASE=AladdinCARD + +pci:v0000416Cd00000200* + ID_MODEL_FROM_DATABASE=CPC + +pci:v00004321* + ID_VENDOR_FROM_DATABASE=Tata Power Strategic Electronics Division + +pci:v0000434E* + ID_VENDOR_FROM_DATABASE=CAST Navigation LLC + +pci:v00004444* + ID_VENDOR_FROM_DATABASE=Internext Compression Inc + +pci:v00004444d00000016* + ID_MODEL_FROM_DATABASE=iTVC16 (CX23416) Video Decoder + +pci:v00004444d00000016sv00000070sd00000003* + ID_MODEL_FROM_DATABASE=WinTV PVR 250 + +pci:v00004444d00000016sv00000070sd00000009* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd00000801* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd00000807* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd00004001* + ID_MODEL_FROM_DATABASE=WinTV PVR 250 + +pci:v00004444d00000016sv00000070sd00004009* + ID_MODEL_FROM_DATABASE=WinTV PVR 250 + +pci:v00004444d00000016sv00000070sd00004801* + ID_MODEL_FROM_DATABASE=WinTV PVR 250 + +pci:v00004444d00000016sv00000070sd00004803* + ID_MODEL_FROM_DATABASE=WinTV PVR 250 + +pci:v00004444d00000016sv00000070sd00008003* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd00008801* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd0000C801* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv00000070sd0000E807* + ID_MODEL_FROM_DATABASE=WinTV PVR 500 (1st unit) + +pci:v00004444d00000016sv00000070sd0000E817* + ID_MODEL_FROM_DATABASE=WinTV PVR 500 (2nd unit) + +pci:v00004444d00000016sv00000070sd0000FF92* + ID_MODEL_FROM_DATABASE=WiNTV PVR-550 + +pci:v00004444d00000016sv00000270sd00000801* + ID_MODEL_FROM_DATABASE=WinTV PVR 150 + +pci:v00004444d00000016sv0000104Dsd0000013D* + ID_MODEL_FROM_DATABASE=ENX-26 TV Encoder + +pci:v00004444d00000016sv000010FCsd0000D038* + ID_MODEL_FROM_DATABASE=GV-MVP/RX2W (1st unit) + +pci:v00004444d00000016sv000010FCsd0000D039* + ID_MODEL_FROM_DATABASE=GV-MVP/RX2W (2nd unit) + +pci:v00004444d00000016sv000012ABsd0000FFF3* + ID_MODEL_FROM_DATABASE=MPG600 + +pci:v00004444d00000016sv000012ABsd0000FFFF* + ID_MODEL_FROM_DATABASE=MPG600 + +pci:v00004444d00000016sv00001461sd0000C00A* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM, Philips FQ1216MK3 tuner) + +pci:v00004444d00000016sv00001461sd0000C00B* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM+FM, Philips FM1216MK3 tuner) + +pci:v00004444d00000016sv00001461sd0000C00C* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC, JAPAN version, Philips FI1286MK2 tuner) + +pci:v00004444d00000016sv00001461sd0000C010* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC, Philips FI1236MK3 tuner) + +pci:v00004444d00000016sv00001461sd0000C011* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC+FM, Philips FM1236MK3 tuner) + +pci:v00004444d00000016sv00001461sd0000C018* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC, Philips FQ1236MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C019* + ID_MODEL_FROM_DATABASE=UltraTV 1500 MCE, a.k.a. M113 PCI Analog TV (NTSC+FM, Philips FQ1236MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C01A* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM, Philips FQ1216MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C01B* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM+FM, Philips FM1216MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C030* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC-J, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C031* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC-J+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C032* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C033* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (PAL/SECAM+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C034* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C035* + ID_MODEL_FROM_DATABASE=M113 PCI Analog TV (NTSC+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C03F* + ID_MODEL_FROM_DATABASE=C115 PCI video capture card (no tuner) + +pci:v00004444d00000016sv00001461sd0000C136* + ID_MODEL_FROM_DATABASE=M104 mini-PCI Analog TV + +pci:v00004444d00000016sv00001461sd0000C20A* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (PAL/SECAM, Philips FQ1216MK3 tuner) + +pci:v00004444d00000016sv00001461sd0000C218* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC, Philips FQ1236MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C219* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC+FM, Philips FQ1236MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C21A* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (PAL/SECAM, Philips FQ1216MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C21B* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (PAL/SECAM+FM, Philips FM1216MK5 tuner) + +pci:v00004444d00000016sv00001461sd0000C230* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC-J, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C231* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC-J+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C232* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (PAL/SECAM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C233* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (PAL/SECAM+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C234* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C235* + ID_MODEL_FROM_DATABASE=M755 AVerTV Video Capture (NTSC+FM, Partsnic tuner) + +pci:v00004444d00000016sv00001461sd0000C337* + ID_MODEL_FROM_DATABASE=E106 AVerMedia AVerTV Video Capture + +pci:v00004444d00000016sv00001461sd0000C439* + ID_MODEL_FROM_DATABASE=M116 AVerMedia AVerTV MCE 116 Plus (NTSC/PAL/SECAM+FM+REMOTE, Xceive 2028 tuner) + +pci:v00004444d00000016sv00001461sd0000C5FF* + ID_MODEL_FROM_DATABASE=C755 AVerTV Video Capture card (no tuner) + +pci:v00004444d00000016sv00001461sd0000C6FF* + ID_MODEL_FROM_DATABASE=C115 PCI video capture card (no tuner) + +pci:v00004444d00000016sv00001461sd0000C739* + ID_MODEL_FROM_DATABASE=M785 AVerMedia PCI Analog TV (NTSC/PAL/SECAM+FM, Xceive 2028 tuner) + +pci:v00004444d00000016sv00009005sd00000092* + ID_MODEL_FROM_DATABASE=VideOh! AVC-2010 + +pci:v00004444d00000016sv00009005sd00000093* + ID_MODEL_FROM_DATABASE=VideOh! AVC-2410 + +pci:v00004444d00000803* + ID_MODEL_FROM_DATABASE=iTVC15 (CX23415) Video Decoder + +pci:v00004444d00000803sv00000070sd00004000* + ID_MODEL_FROM_DATABASE=WinTV PVR-350 + +pci:v00004444d00000803sv00000070sd00004001* + ID_MODEL_FROM_DATABASE=WinTV PVR-250 + +pci:v00004444d00000803sv00000070sd00004800* + ID_MODEL_FROM_DATABASE=WinTV PVR-350 (V1) + +pci:v00004444d00000803sv000012ABsd00000000* + ID_MODEL_FROM_DATABASE=MPG160 + +pci:v00004444d00000803sv00001461sd0000A3CE* + ID_MODEL_FROM_DATABASE=M179 + +pci:v00004444d00000803sv00001461sd0000A3CF* + ID_MODEL_FROM_DATABASE=M179 + +pci:v00004468* + ID_VENDOR_FROM_DATABASE=Bridgeport machines + +pci:v00004594* + ID_VENDOR_FROM_DATABASE=Cogetec Informatique Inc + +pci:v000045FB* + ID_VENDOR_FROM_DATABASE=Baldor Electric Company + +pci:v00004624* + ID_VENDOR_FROM_DATABASE=Budker Institute of Nuclear Physics + +pci:v00004624d0000ADC1* + ID_MODEL_FROM_DATABASE=ADC200ME High speed ADC + +pci:v00004624d0000DE01* + ID_MODEL_FROM_DATABASE=DL200ME High resolution delay line PCI based card + +pci:v00004624d0000DE02* + ID_MODEL_FROM_DATABASE=DL200ME Middle resolution delay line PCI based card + +pci:v00004680* + ID_VENDOR_FROM_DATABASE=Umax Computer Corp + +pci:v00004843* + ID_VENDOR_FROM_DATABASE=Hercules Computer Technology Inc + +pci:v00004916* + ID_VENDOR_FROM_DATABASE=RedCreek Communications Inc + +pci:v00004916d00001960* + ID_MODEL_FROM_DATABASE=RedCreek PCI adapter + +pci:v00004943* + ID_VENDOR_FROM_DATABASE=Growth Networks + +pci:v0000494F* + ID_VENDOR_FROM_DATABASE=ACCES I/O Products, Inc. + +pci:v0000494Fd00000520* + ID_MODEL_FROM_DATABASE=PCI-IDO-48 + +pci:v0000494Fd00000920* + ID_MODEL_FROM_DATABASE=PCI-IDI-48 + +pci:v0000494Fd00000C50* + ID_MODEL_FROM_DATABASE=PCI-DIO-24H + +pci:v0000494Fd00000C51* + ID_MODEL_FROM_DATABASE=PCI-DIO-24D + +pci:v0000494Fd00000C60* + ID_MODEL_FROM_DATABASE=PCI-DIO-48(H) + +pci:v0000494Fd00000C68* + ID_MODEL_FROM_DATABASE=PCI-DIO-72 + +pci:v0000494Fd00000C70* + ID_MODEL_FROM_DATABASE=PCI-DIO-96 + +pci:v0000494Fd00000C78* + ID_MODEL_FROM_DATABASE=PCI-DIO-120 + +pci:v0000494Fd00000DC8* + ID_MODEL_FROM_DATABASE=PCI-IDIO-16 + +pci:v0000494Fd00000E50* + ID_MODEL_FROM_DATABASE=PCI-DIO-24S + +pci:v0000494Fd00000E51* + ID_MODEL_FROM_DATABASE=PCI-DIO-24H(C) + +pci:v0000494Fd00000E52* + ID_MODEL_FROM_DATABASE=PCI-DIO-24D(C) + +pci:v0000494Fd00000E60* + ID_MODEL_FROM_DATABASE=PCI-DIO-48S(H) + +pci:v0000494Fd00000E61* + ID_MODEL_FROM_DATABASE=P104-DIO-24S + +pci:v0000494Fd00000F00* + ID_MODEL_FROM_DATABASE=PCI-IIRO-8 + +pci:v0000494Fd00000F01* + ID_MODEL_FROM_DATABASE=LPCI-IIRO-8 + +pci:v0000494Fd00000F08* + ID_MODEL_FROM_DATABASE=PCI-IIRO-16 + +pci:v0000494Fd00001050* + ID_MODEL_FROM_DATABASE=PCI-422/485-2 + +pci:v0000494Fd00001058* + ID_MODEL_FROM_DATABASE=PCI-COM422/4 + +pci:v0000494Fd00001059* + ID_MODEL_FROM_DATABASE=PCI-COM485/4 + +pci:v0000494Fd00001068* + ID_MODEL_FROM_DATABASE=PCI-COM422/8 + +pci:v0000494Fd00001069* + ID_MODEL_FROM_DATABASE=PCI-COM485/8 + +pci:v0000494Fd00001088* + ID_MODEL_FROM_DATABASE=PCI-COM232/1 + +pci:v0000494Fd00001090* + ID_MODEL_FROM_DATABASE=PCI-COM232/2 + +pci:v0000494Fd000010A8* + ID_MODEL_FROM_DATABASE=P104-COM232-8 + +pci:v0000494Fd000010C9* + ID_MODEL_FROM_DATABASE=PCI-COM-1S + +pci:v0000494Fd000010D0* + ID_MODEL_FROM_DATABASE=PCI-COM2S + +pci:v0000494Fd000010E8* + ID_MODEL_FROM_DATABASE=PCI-COM-8SM + +pci:v0000494Fd00001148* + ID_MODEL_FROM_DATABASE=PCI-ICM-1S + +pci:v0000494Fd00001150* + ID_MODEL_FROM_DATABASE=PCI-ICM-2S + +pci:v0000494Fd00001158* + ID_MODEL_FROM_DATABASE=PCI-ICM422/4 + +pci:v0000494Fd00001159* + ID_MODEL_FROM_DATABASE=PCI-ICM485/4 + +pci:v0000494Fd00001250* + ID_MODEL_FROM_DATABASE=PCI-WDG-2S + +pci:v0000494Fd000012D0* + ID_MODEL_FROM_DATABASE=PCI-WDG-IMPAC + +pci:v0000494Fd000022C0* + ID_MODEL_FROM_DATABASE=PCI-WDG-CSM + +pci:v0000494Fd00002C50* + ID_MODEL_FROM_DATABASE=PCI-DIO-96CT + +pci:v0000494Fd00002C58* + ID_MODEL_FROM_DATABASE=PCI-DIO-96C3 + +pci:v0000494Fd00005ED0* + ID_MODEL_FROM_DATABASE=PCI-DAC + +pci:v0000494Fd00006C90* + ID_MODEL_FROM_DATABASE=PCI-DA12-2 + +pci:v0000494Fd00006C98* + ID_MODEL_FROM_DATABASE=PCI-DA12-4 + +pci:v0000494Fd00006CA0* + ID_MODEL_FROM_DATABASE=PCI-DA12-6 + +pci:v0000494Fd00006CA8* + ID_MODEL_FROM_DATABASE=PCI-DA12-8 + +pci:v0000494Fd00006CA9* + ID_MODEL_FROM_DATABASE=PCI-DA12-8V + +pci:v0000494Fd00006CB0* + ID_MODEL_FROM_DATABASE=PCI-DA12-16 + +pci:v0000494Fd00006CB1* + ID_MODEL_FROM_DATABASE=PCI-DA12-16V + +pci:v0000494Fd00008EF0* + ID_MODEL_FROM_DATABASE=P104-FAS16-16 + +pci:v0000494Fd0000ACA8* + ID_MODEL_FROM_DATABASE=PCI-AI12-16 + +pci:v0000494Fd0000ACA9* + ID_MODEL_FROM_DATABASE=PCI-AI12-16A + +pci:v0000494Fd0000ECA8* + ID_MODEL_FROM_DATABASE=PCI-AIO12-16 + +pci:v0000494Fd0000ECA9* + ID_MODEL_FROM_DATABASE=PCI-A12-16 + +pci:v0000494Fd0000ECAA* + ID_MODEL_FROM_DATABASE=PCI-A12-16A + +pci:v0000494Fd0000ECE8* + ID_MODEL_FROM_DATABASE=PCI-A16-16 + +pci:v00004978* + ID_VENDOR_FROM_DATABASE=Axil Computer Inc + +pci:v00004A14* + ID_VENDOR_FROM_DATABASE=NetVin + +pci:v00004A14d00005000* + ID_MODEL_FROM_DATABASE=NV5000SC + +pci:v00004A14d00005000sv00004A14sd00005000* + ID_MODEL_FROM_DATABASE=RT8029-Based Ethernet Adapter + +pci:v00004B10* + ID_VENDOR_FROM_DATABASE=Buslogic Inc. + +pci:v00004C48* + ID_VENDOR_FROM_DATABASE=LUNG HWA Electronics + +pci:v00004C53* + ID_VENDOR_FROM_DATABASE=SBS Technologies + +pci:v00004C53d00000000* + ID_MODEL_FROM_DATABASE=PLUSTEST device + +pci:v00004C53d00000000sv00004C53sd00003000* + ID_MODEL_FROM_DATABASE=PLUSTEST card (PC104+) + +pci:v00004C53d00000000sv00004C53sd00003001* + ID_MODEL_FROM_DATABASE=PLUSTEST card (PMC) + +pci:v00004C53d00000001* + ID_MODEL_FROM_DATABASE=PLUSTEST-MM device + +pci:v00004C53d00000001sv00004C53sd00003002* + ID_MODEL_FROM_DATABASE=PLUSTEST-MM card (PMC) + +pci:v00004CA1* + ID_VENDOR_FROM_DATABASE=Seanix Technology Inc + +pci:v00004D51* + ID_VENDOR_FROM_DATABASE=MediaQ Inc. + +pci:v00004D51d00000200* + ID_MODEL_FROM_DATABASE=MQ-200 + +pci:v00004D54* + ID_VENDOR_FROM_DATABASE=Microtechnica Co Ltd + +pci:v00004D56* + ID_VENDOR_FROM_DATABASE=MATRIX VISION GmbH + +pci:v00004D56d00000000* + ID_MODEL_FROM_DATABASE=[mvHYPERION-CLe/CLb] CameraLink PCI Express x1 Frame Grabber + +pci:v00004D56d00000001* + ID_MODEL_FROM_DATABASE=[mvHYPERION-CLf/CLm] CameraLink PCI Express x4 Frame Grabber + +pci:v00004D56d00000010* + ID_MODEL_FROM_DATABASE=[mvHYPERION-16R16/-32R16] 16 Video Channel PCI Express x4 Frame Grabber + +pci:v00004D56d00000020* + ID_MODEL_FROM_DATABASE=[mvHYPERION-HD-SDI] HD-SDI PCI Express x4 Frame Grabber + +pci:v00004D56d00000030* + ID_MODEL_FROM_DATABASE=[mvHYPERION-HD-SDI-Merger] HD-SDI PCI Express x4 Frame Grabber + +pci:v00004DDC* + ID_VENDOR_FROM_DATABASE=ILC Data Device Corp + +pci:v00004DDCd00000100* + ID_MODEL_FROM_DATABASE=DD-42924I5-300 (ARINC 429 Data Bus) + +pci:v00004DDCd00000801* + ID_MODEL_FROM_DATABASE=BU-65570I1 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000802* + ID_MODEL_FROM_DATABASE=BU-65570I2 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000811* + ID_MODEL_FROM_DATABASE=BU-65572I1 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000812* + ID_MODEL_FROM_DATABASE=BU-65572I2 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000881* + ID_MODEL_FROM_DATABASE=BU-65570T1 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000882* + ID_MODEL_FROM_DATABASE=BU-65570T2 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000891* + ID_MODEL_FROM_DATABASE=BU-65572T1 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000892* + ID_MODEL_FROM_DATABASE=BU-65572T2 MIL-STD-1553 Test and Simulation + +pci:v00004DDCd00000901* + ID_MODEL_FROM_DATABASE=BU-65565C1 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000902* + ID_MODEL_FROM_DATABASE=BU-65565C2 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000903* + ID_MODEL_FROM_DATABASE=BU-65565C3 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000904* + ID_MODEL_FROM_DATABASE=BU-65565C4 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000B01* + ID_MODEL_FROM_DATABASE=BU-65569I1 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000B02* + ID_MODEL_FROM_DATABASE=BU-65569I2 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000B03* + ID_MODEL_FROM_DATABASE=BU-65569I3 MIL-STD-1553 Data Bus + +pci:v00004DDCd00000B04* + ID_MODEL_FROM_DATABASE=BU-65569I4 MIL-STD-1553 Data Bus + +pci:v00005045* + ID_VENDOR_FROM_DATABASE=University of Toronto + +pci:v00005045d00004243* + ID_MODEL_FROM_DATABASE=BLASTbus PCI Interface Card v1 + +pci:v00005046* + ID_VENDOR_FROM_DATABASE=GemTek Technology Corporation + +pci:v00005046d00001001* + ID_MODEL_FROM_DATABASE=PCI Radio + +pci:v00005053* + ID_VENDOR_FROM_DATABASE=Voyetra Technologies + +pci:v00005053d00002010* + ID_MODEL_FROM_DATABASE=Daytona Audio Adapter + +pci:v000050B2* + ID_VENDOR_FROM_DATABASE=TerraTec Electronic GmbH + +pci:v00005136* + ID_VENDOR_FROM_DATABASE=S S Technologies + +pci:v00005143* + ID_VENDOR_FROM_DATABASE=Qualcomm Inc + +pci:v00005145* + ID_VENDOR_FROM_DATABASE=Ensoniq (Old) + +pci:v00005145d00003031* + ID_MODEL_FROM_DATABASE=Concert AudioPCI + +pci:v00005168* + ID_VENDOR_FROM_DATABASE=Animation Technologies Inc. + +pci:v00005168d00000300* + ID_MODEL_FROM_DATABASE=FlyDVB-S + +pci:v00005168d00000301* + ID_MODEL_FROM_DATABASE=FlyDVB-T + +pci:v00005301* + ID_VENDOR_FROM_DATABASE=Alliance Semiconductor Corp. + +pci:v00005301d00000001* + ID_MODEL_FROM_DATABASE=ProMotion aT3D + +pci:v00005333* + ID_VENDOR_FROM_DATABASE=S3 Graphics Ltd. + +pci:v00005333d00000551* + ID_MODEL_FROM_DATABASE=Plato/PX (system) + +pci:v00005333d00005631* + ID_MODEL_FROM_DATABASE=86c325 [ViRGE] + +pci:v00005333d00008800* + ID_MODEL_FROM_DATABASE=86c866 [Vision 866] + +pci:v00005333d00008801* + ID_MODEL_FROM_DATABASE=86c964 [Vision 964] + +pci:v00005333d00008810* + ID_MODEL_FROM_DATABASE=86c764_0 [Trio 32 vers 0] + +pci:v00005333d00008811* + ID_MODEL_FROM_DATABASE=86c764/765 [Trio32/64/64V+] + +pci:v00005333d00008812* + ID_MODEL_FROM_DATABASE=86cM65 [Aurora64V+] + +pci:v00005333d00008813* + ID_MODEL_FROM_DATABASE=86c764_3 [Trio 32/64 vers 3] + +pci:v00005333d00008814* + ID_MODEL_FROM_DATABASE=86c767 [Trio 64UV+] + +pci:v00005333d00008815* + ID_MODEL_FROM_DATABASE=86cM65 [Aurora 128] + +pci:v00005333d0000883D* + ID_MODEL_FROM_DATABASE=86c988 [ViRGE/VX] + +pci:v00005333d00008870* + ID_MODEL_FROM_DATABASE=FireGL + +pci:v00005333d00008880* + ID_MODEL_FROM_DATABASE=86c868 [Vision 868 VRAM] vers 0 + +pci:v00005333d00008881* + ID_MODEL_FROM_DATABASE=86c868 [Vision 868 VRAM] vers 1 + +pci:v00005333d00008882* + ID_MODEL_FROM_DATABASE=86c868 [Vision 868 VRAM] vers 2 + +pci:v00005333d00008883* + ID_MODEL_FROM_DATABASE=86c868 [Vision 868 VRAM] vers 3 + +pci:v00005333d000088B0* + ID_MODEL_FROM_DATABASE=86c928 [Vision 928 VRAM] vers 0 + +pci:v00005333d000088B1* + ID_MODEL_FROM_DATABASE=86c928 [Vision 928 VRAM] vers 1 + +pci:v00005333d000088B2* + ID_MODEL_FROM_DATABASE=86c928 [Vision 928 VRAM] vers 2 + +pci:v00005333d000088B3* + ID_MODEL_FROM_DATABASE=86c928 [Vision 928 VRAM] vers 3 + +pci:v00005333d000088C0* + ID_MODEL_FROM_DATABASE=86c864 [Vision 864 DRAM] vers 0 + +pci:v00005333d000088C1* + ID_MODEL_FROM_DATABASE=86c864 [Vision 864 DRAM] vers 1 + +pci:v00005333d000088C2* + ID_MODEL_FROM_DATABASE=86c864 [Vision 864-P DRAM] vers 2 + +pci:v00005333d000088C3* + ID_MODEL_FROM_DATABASE=86c864 [Vision 864-P DRAM] vers 3 + +pci:v00005333d000088D0* + ID_MODEL_FROM_DATABASE=86c964 [Vision 964 VRAM] vers 0 + +pci:v00005333d000088D1* + ID_MODEL_FROM_DATABASE=86c964 [Vision 964 VRAM] vers 1 + +pci:v00005333d000088D2* + ID_MODEL_FROM_DATABASE=86c964 [Vision 964-P VRAM] vers 2 + +pci:v00005333d000088D3* + ID_MODEL_FROM_DATABASE=86c964 [Vision 964-P VRAM] vers 3 + +pci:v00005333d000088F0* + ID_MODEL_FROM_DATABASE=86c968 [Vision 968 VRAM] rev 0 + +pci:v00005333d000088F1* + ID_MODEL_FROM_DATABASE=86c968 [Vision 968 VRAM] rev 1 + +pci:v00005333d000088F2* + ID_MODEL_FROM_DATABASE=86c968 [Vision 968 VRAM] rev 2 + +pci:v00005333d000088F3* + ID_MODEL_FROM_DATABASE=86c968 [Vision 968 VRAM] rev 3 + +pci:v00005333d00008900* + ID_MODEL_FROM_DATABASE=86c755 [Trio 64V2/DX] + +pci:v00005333d00008900sv00005333sd00008900* + ID_MODEL_FROM_DATABASE=86C775 Trio64V2/DX + +pci:v00005333d00008901* + ID_MODEL_FROM_DATABASE=86c775/86c785 [Trio 64V2/DX or /GX] + +pci:v00005333d00008901sv00005333sd00008901* + ID_MODEL_FROM_DATABASE=86C775 Trio64V2/DX, 86C785 Trio64V2/GX + +pci:v00005333d00008902* + ID_MODEL_FROM_DATABASE=Plato/PX + +pci:v00005333d00008903* + ID_MODEL_FROM_DATABASE=Trio 3D business multimedia + +pci:v00005333d00008904* + ID_MODEL_FROM_DATABASE=86c365, 86c366 [Trio 3D] + +pci:v00005333d00008904sv00001014sd000000DB* + ID_MODEL_FROM_DATABASE=Integrated Trio3D + +pci:v00005333d00008904sv00004843sd0000314A* + ID_MODEL_FROM_DATABASE=Terminator 128/3D GLH + +pci:v00005333d00008904sv00005333sd00008904* + ID_MODEL_FROM_DATABASE=86C365 Trio3D AGP + +pci:v00005333d00008905* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d00008906* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d00008907* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d00008908* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d00008909* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890A* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890B* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890C* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890D* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890E* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d0000890F* + ID_MODEL_FROM_DATABASE=Trio 64V+ family + +pci:v00005333d00008A01* + ID_MODEL_FROM_DATABASE=86c375 [ViRGE/DX] or 86c385 [ViRGE/GX] + +pci:v00005333d00008A01sv00000E11sd0000B032* + ID_MODEL_FROM_DATABASE=ViRGE/GX + +pci:v00005333d00008A01sv000010B4sd00001617* + ID_MODEL_FROM_DATABASE=Nitro 3D + +pci:v00005333d00008A01sv000010B4sd00001717* + ID_MODEL_FROM_DATABASE=Nitro 3D + +pci:v00005333d00008A01sv00005333sd00008A01* + ID_MODEL_FROM_DATABASE=ViRGE/DX + +pci:v00005333d00008A10* + ID_MODEL_FROM_DATABASE=ViRGE/GX2 + +pci:v00005333d00008A10sv00001092sd00008A10* + ID_MODEL_FROM_DATABASE=Stealth 3D 4000 + +pci:v00005333d00008A13* + ID_MODEL_FROM_DATABASE=86c360 [Trio 3D/1X], 86c362, 86c368 [Trio 3D/2X] + +pci:v00005333d00008A13sv00005333sd00008A13* + ID_MODEL_FROM_DATABASE=Trio3D/2X + +pci:v00005333d00008A20* + ID_MODEL_FROM_DATABASE=86c794 [Savage 3D] + +pci:v00005333d00008A20sv00005333sd00008A20* + ID_MODEL_FROM_DATABASE=86C391 Savage3D + +pci:v00005333d00008A21* + ID_MODEL_FROM_DATABASE=86c390 [Savage 3D/MV] + +pci:v00005333d00008A21sv00005333sd00008A21* + ID_MODEL_FROM_DATABASE=86C390 Savage3D/MV + +pci:v00005333d00008A22* + ID_MODEL_FROM_DATABASE=Savage 4 + +pci:v00005333d00008A22sv00001033sd00008068* + ID_MODEL_FROM_DATABASE=Savage 4 + +pci:v00005333d00008A22sv00001033sd00008069* + ID_MODEL_FROM_DATABASE=Savage 4 + +pci:v00005333d00008A22sv00001033sd00008110* + ID_MODEL_FROM_DATABASE=Savage 4 LT + +pci:v00005333d00008A22sv0000105Dsd00000018* + ID_MODEL_FROM_DATABASE=SR9 8Mb SDRAM + +pci:v00005333d00008A22sv0000105Dsd0000002A* + ID_MODEL_FROM_DATABASE=SR9 Pro 16Mb SDRAM + +pci:v00005333d00008A22sv0000105Dsd0000003A* + ID_MODEL_FROM_DATABASE=SR9 Pro 32Mb SDRAM + +pci:v00005333d00008A22sv0000105Dsd0000092F* + ID_MODEL_FROM_DATABASE=SR9 Pro+ 16Mb SGRAM + +pci:v00005333d00008A22sv00001092sd00004207* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004800* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004807* + ID_MODEL_FROM_DATABASE=SpeedStar A90 + +pci:v00005333d00008A22sv00001092sd00004808* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004809* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd0000480E* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004904* + ID_MODEL_FROM_DATABASE=Stealth III S520 + +pci:v00005333d00008A22sv00001092sd00004905* + ID_MODEL_FROM_DATABASE=SpeedStar A200 + +pci:v00005333d00008A22sv00001092sd00004A09* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004A0B* + ID_MODEL_FROM_DATABASE=Stealth III S540 Xtreme + +pci:v00005333d00008A22sv00001092sd00004A0F* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001092sd00004E01* + ID_MODEL_FROM_DATABASE=Stealth III S540 + +pci:v00005333d00008A22sv00001102sd0000101D* + ID_MODEL_FROM_DATABASE=3d Blaster Savage 4 + +pci:v00005333d00008A22sv00001102sd0000101E* + ID_MODEL_FROM_DATABASE=3d Blaster Savage 4 + +pci:v00005333d00008A22sv00005333sd00008100* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SDRAM 100 + +pci:v00005333d00008A22sv00005333sd00008110* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SDRAM 110 + +pci:v00005333d00008A22sv00005333sd00008125* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SDRAM 125 + +pci:v00005333d00008A22sv00005333sd00008143* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SDRAM 143 + +pci:v00005333d00008A22sv00005333sd00008A22* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 + +pci:v00005333d00008A22sv00005333sd00008A2E* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 32bit + +pci:v00005333d00008A22sv00005333sd00009125* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SGRAM 125 + +pci:v00005333d00008A22sv00005333sd00009143* + ID_MODEL_FROM_DATABASE=86C394-397 Savage4 SGRAM 143 + +pci:v00005333d00008A23* + ID_MODEL_FROM_DATABASE=Savage 4 + +pci:v00005333d00008A25* + ID_MODEL_FROM_DATABASE=ProSavage PM133 + +pci:v00005333d00008A25sv00000303sd00000303* + ID_MODEL_FROM_DATABASE=D9840-60001 [Brio BA410 Motherboard] + +pci:v00005333d00008A26* + ID_MODEL_FROM_DATABASE=ProSavage KM133 + +pci:v00005333d00008C00* + ID_MODEL_FROM_DATABASE=ViRGE/M3 + +pci:v00005333d00008C01* + ID_MODEL_FROM_DATABASE=ViRGE/MX + +pci:v00005333d00008C01sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=ViRGE/MX + +pci:v00005333d00008C02* + ID_MODEL_FROM_DATABASE=ViRGE/MX+ + +pci:v00005333d00008C03* + ID_MODEL_FROM_DATABASE=ViRGE/MX+MV + +pci:v00005333d00008C10* + ID_MODEL_FROM_DATABASE=86C270-294 [SavageMX-MV] + +pci:v00005333d00008C11* + ID_MODEL_FROM_DATABASE=82C270-294 [SavageMX] + +pci:v00005333d00008C12* + ID_MODEL_FROM_DATABASE=86C270-294 [SavageIX-MV] + +pci:v00005333d00008C12sv00001014sd0000017F* + ID_MODEL_FROM_DATABASE=ThinkPad T20/T22 + +pci:v00005333d00008C12sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=86C584 SuperSavage/IXC Toshiba + +pci:v00005333d00008C13* + ID_MODEL_FROM_DATABASE=86C270-294 [SavageIX] + +pci:v00005333d00008C13sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00005333d00008C22* + ID_MODEL_FROM_DATABASE=SuperSavage MX/128 + +pci:v00005333d00008C24* + ID_MODEL_FROM_DATABASE=SuperSavage MX/64 + +pci:v00005333d00008C26* + ID_MODEL_FROM_DATABASE=SuperSavage MX/64C + +pci:v00005333d00008C2A* + ID_MODEL_FROM_DATABASE=SuperSavage IX/128 SDR + +pci:v00005333d00008C2B* + ID_MODEL_FROM_DATABASE=SuperSavage IX/128 DDR + +pci:v00005333d00008C2C* + ID_MODEL_FROM_DATABASE=SuperSavage IX/64 SDR + +pci:v00005333d00008C2D* + ID_MODEL_FROM_DATABASE=SuperSavage IX/64 DDR + +pci:v00005333d00008C2E* + ID_MODEL_FROM_DATABASE=SuperSavage IX/C SDR + +pci:v00005333d00008C2Esv00001014sd000001FC* + ID_MODEL_FROM_DATABASE=ThinkPad T23 + +pci:v00005333d00008C2F* + ID_MODEL_FROM_DATABASE=SuperSavage IX/C DDR + +pci:v00005333d00008D01* + ID_MODEL_FROM_DATABASE=86C380 [ProSavageDDR K4M266] + +pci:v00005333d00008D02* + ID_MODEL_FROM_DATABASE=VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK) + +pci:v00005333d00008D03* + ID_MODEL_FROM_DATABASE=VT8751 [ProSavageDDR P4M266] + +pci:v00005333d00008D04* + ID_MODEL_FROM_DATABASE=VT8375 [ProSavage8 KM266/KL266] + +pci:v00005333d00008E00* + ID_MODEL_FROM_DATABASE=DeltaChrome + +pci:v00005333d00008E26* + ID_MODEL_FROM_DATABASE=ProSavage + +pci:v00005333d00008E40* + ID_MODEL_FROM_DATABASE=2300E Graphics Processor + +pci:v00005333d00008E48* + ID_MODEL_FROM_DATABASE=Matrix [Chrome S25 / S27] + +pci:v00005333d00008E48sv00005333sd00000130* + ID_MODEL_FROM_DATABASE=Chrome S27 256M DDR2 + +pci:v00005333d00009043* + ID_MODEL_FROM_DATABASE=Chrome 430 GT + +pci:v00005333d00009045* + ID_MODEL_FROM_DATABASE=Chrome 430 ULP / 435 ULP / 440 GTX + +pci:v00005333d00009060* + ID_MODEL_FROM_DATABASE=Chrome 530 GT + +pci:v00005333d00009102* + ID_MODEL_FROM_DATABASE=86C410 [Savage 2000] + +pci:v00005333d00009102sv00001092sd00005932* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005934* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005952* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005954* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005A35* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005A37* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005A55* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d00009102sv00001092sd00005A57* + ID_MODEL_FROM_DATABASE=Viper II Z200 + +pci:v00005333d0000CA00* + ID_MODEL_FROM_DATABASE=SonicVibes + +pci:v00005431* + ID_VENDOR_FROM_DATABASE=AuzenTech, Inc. + +pci:v0000544C* + ID_VENDOR_FROM_DATABASE=Teralogic Inc + +pci:v0000544Cd00000350* + ID_MODEL_FROM_DATABASE=TL880-based HDTV/ATSC tuner + +pci:v00005452* + ID_VENDOR_FROM_DATABASE=SCANLAB AG + +pci:v00005452d00003443* + ID_MODEL_FROM_DATABASE=RTC4 + +pci:v00005455* + ID_VENDOR_FROM_DATABASE=Technische University Berlin + +pci:v00005455d00004458* + ID_MODEL_FROM_DATABASE=S5933 + +pci:v00005456* + ID_VENDOR_FROM_DATABASE=GoTView + +pci:v00005519* + ID_VENDOR_FROM_DATABASE=Cnet Technologies, Inc. + +pci:v00005544* + ID_VENDOR_FROM_DATABASE=Dunord Technologies + +pci:v00005544d00000001* + ID_MODEL_FROM_DATABASE=I-30xx Scanner Interface + +pci:v00005555* + ID_VENDOR_FROM_DATABASE=Genroco, Inc + +pci:v00005555d00000003* + ID_MODEL_FROM_DATABASE=TURBOstor HFP-832 [HiPPI NIC] + +pci:v00005646* + ID_VENDOR_FROM_DATABASE=Vector Fabrics BV + +pci:v00005654* + ID_VENDOR_FROM_DATABASE=VoiceTronix Pty Ltd + +pci:v00005700* + ID_VENDOR_FROM_DATABASE=Netpower + +pci:v0000584D* + ID_VENDOR_FROM_DATABASE=AuzenTech Co., Ltd. + +pci:v00005851* + ID_VENDOR_FROM_DATABASE=Exacq Technologies + +pci:v00005853* + ID_VENDOR_FROM_DATABASE=XenSource, Inc. + +pci:v00005853d00000001* + ID_MODEL_FROM_DATABASE=Xen Platform Device + +pci:v00005853d0000C110* + ID_MODEL_FROM_DATABASE=Virtualized HID + +pci:v00005853d0000C147* + ID_MODEL_FROM_DATABASE=Virtualized Graphics Device + +pci:v00005854* + ID_VENDOR_FROM_DATABASE=GoTView + +pci:v00005ACE* + ID_VENDOR_FROM_DATABASE=Beholder International Ltd. + +pci:v0000631C* + ID_VENDOR_FROM_DATABASE=SmartInfra Ltd + +pci:v0000631Cd00001652* + ID_MODEL_FROM_DATABASE=PXI-1652 Signal Generator + +pci:v0000631Cd00002504* + ID_MODEL_FROM_DATABASE=PXI-2504 Signal Interrogator + +pci:v00006356* + ID_VENDOR_FROM_DATABASE=UltraStor + +pci:v00006374* + ID_VENDOR_FROM_DATABASE=c't Magazin fuer Computertechnik + +pci:v00006374d00006773* + ID_MODEL_FROM_DATABASE=GPPCI + +pci:v00006409* + ID_VENDOR_FROM_DATABASE=Logitec Corp. + +pci:v00006549* + ID_VENDOR_FROM_DATABASE=Teradici Corp. + +pci:v00006549d00001200* + ID_MODEL_FROM_DATABASE=TERA1200 PC-over-IP Host + +pci:v00006666* + ID_VENDOR_FROM_DATABASE=Decision Computer International Co. + +pci:v00006666d00000001* + ID_MODEL_FROM_DATABASE=PCCOM4 + +pci:v00006666d00000002* + ID_MODEL_FROM_DATABASE=PCCOM8 + +pci:v00006666d00000004* + ID_MODEL_FROM_DATABASE=PCCOM2 + +pci:v00006666d00000101* + ID_MODEL_FROM_DATABASE=PCI 8255/8254 I/O Card + +pci:v00006666d00000200* + ID_MODEL_FROM_DATABASE=12-bit AD/DA Card + +pci:v00006666d00000201* + ID_MODEL_FROM_DATABASE=14-bit AD/DA Card + +pci:v00006666d00001011* + ID_MODEL_FROM_DATABASE=Industrial Card + +pci:v00006666d00001021* + ID_MODEL_FROM_DATABASE=8 photo couple 8 relay Card + +pci:v00006666d00001022* + ID_MODEL_FROM_DATABASE=4 photo couple 4 relay Card + +pci:v00006666d00001025* + ID_MODEL_FROM_DATABASE=16 photo couple 16 relay Card + +pci:v00006666d00004000* + ID_MODEL_FROM_DATABASE=WatchDog Card + +pci:v00006688* + ID_VENDOR_FROM_DATABASE=Zycoo Co., Ltd + +pci:v00006688d00001200* + ID_MODEL_FROM_DATABASE=CooVOX TDM Analog Module + +pci:v00006688d00001400* + ID_MODEL_FROM_DATABASE=CooVOX TDM GSM Module + +pci:v00006688d00001600* + ID_MODEL_FROM_DATABASE=CooVOX TDM E1/T1 Module + +pci:v00006688d00001800* + ID_MODEL_FROM_DATABASE=CooVOX TDM BRI Module + +pci:v00006900* + ID_VENDOR_FROM_DATABASE=Red Hat, Inc. + +pci:v00007063* + ID_VENDOR_FROM_DATABASE=pcHDTV + +pci:v00007063d00002000* + ID_MODEL_FROM_DATABASE=HD-2000 + +pci:v00007063d00003000* + ID_MODEL_FROM_DATABASE=HD-3000 + +pci:v00007063d00005500* + ID_MODEL_FROM_DATABASE=HD5500 HDTV + +pci:v00007284* + ID_VENDOR_FROM_DATABASE=HT OMEGA Inc. + +pci:v00007604* + ID_VENDOR_FROM_DATABASE=O.N. Electronic Co Ltd. + +pci:v00007BDE* + ID_VENDOR_FROM_DATABASE=MIDAC Corporation + +pci:v00007FED* + ID_VENDOR_FROM_DATABASE=PowerTV + +pci:v00008008* + ID_VENDOR_FROM_DATABASE=Quancom Electronic GmbH + +pci:v00008008d00000010* + ID_MODEL_FROM_DATABASE=WDOG1 [PCI-Watchdog 1] + +pci:v00008008d00000011* + ID_MODEL_FROM_DATABASE=PWDOG2 [PCI-Watchdog 2] + +pci:v00008008d00000015* + ID_MODEL_FROM_DATABASE=Clock77/PCI & Clock77/PCIe (DCF-77 receiver) + +pci:v0000807D* + ID_VENDOR_FROM_DATABASE=Asustek Computer, Inc. + +pci:v00008086* + ID_VENDOR_FROM_DATABASE=Intel Corporation + +pci:v00008086d00000007* + ID_MODEL_FROM_DATABASE=82379AB + +pci:v00008086d00000008* + ID_MODEL_FROM_DATABASE=Extended Express System Support Controller + +pci:v00008086d00000039* + ID_MODEL_FROM_DATABASE=21145 Fast Ethernet + +pci:v00008086d00000040* + ID_MODEL_FROM_DATABASE=Core Processor DRAM Controller + +pci:v00008086d00000041* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express x16 Root Port + +pci:v00008086d00000042* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Graphics Controller + +pci:v00008086d00000043* + ID_MODEL_FROM_DATABASE=Core Processor Secondary PCI Express Root Port + +pci:v00008086d00000044* + ID_MODEL_FROM_DATABASE=Core Processor DRAM Controller + +pci:v00008086d00000044sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00000044sv00001025sd00000487* + ID_MODEL_FROM_DATABASE=TravelMate 5742 + +pci:v00008086d00000044sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00000045* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express x16 Root Port + +pci:v00008086d00000046* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Graphics Controller + +pci:v00008086d00000046sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00000047* + ID_MODEL_FROM_DATABASE=Core Processor Secondary PCI Express Root Port + +pci:v00008086d00000048* + ID_MODEL_FROM_DATABASE=Core Processor DRAM Controller + +pci:v00008086d00000049* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express x16 Root Port + +pci:v00008086d0000004A* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Graphics Controller + +pci:v00008086d0000004B* + ID_MODEL_FROM_DATABASE=Core Processor Secondary PCI Express Root Port + +pci:v00008086d00000050* + ID_MODEL_FROM_DATABASE=Core Processor Thermal Management Controller + +pci:v00008086d00000069* + ID_MODEL_FROM_DATABASE=Core Processor DRAM Controller + +pci:v00008086d00000082* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 [Taylor Peak] + +pci:v00008086d00000082sv00008086sd00001301* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 AGN + +pci:v00008086d00000082sv00008086sd00001306* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 ABG + +pci:v00008086d00000082sv00008086sd00001307* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 BG + +pci:v00008086d00000082sv00008086sd00001321* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 AGN + +pci:v00008086d00000082sv00008086sd00001326* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 ABG + +pci:v00008086d00000083* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 [Condor Peak] + +pci:v00008086d00000083sv00008086sd00001205* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000083sv00008086sd00001206* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000083sv00008086sd00001225* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000083sv00008086sd00001226* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000083sv00008086sd00001305* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000083sv00008086sd00001306* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000083sv00008086sd00001325* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000083sv00008086sd00001326* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000084* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 [Condor Peak] + +pci:v00008086d00000084sv00008086sd00001215* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000084sv00008086sd00001216* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000084sv00008086sd00001315* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BGN + +pci:v00008086d00000084sv00008086sd00001316* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1000 BG + +pci:v00008086d00000085* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 [Taylor Peak] + +pci:v00008086d00000085sv00008086sd00001311* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 AGN + +pci:v00008086d00000085sv00008086sd00001316* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6205 ABG + +pci:v00008086d00000087* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 [Kilmer Peak] + +pci:v00008086d00000087sv00008086sd00001301* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 AGN + +pci:v00008086d00000087sv00008086sd00001306* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 ABG + +pci:v00008086d00000087sv00008086sd00001321* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 AGN + +pci:v00008086d00000087sv00008086sd00001326* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 ABG + +pci:v00008086d00000089* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 [Kilmer Peak] + +pci:v00008086d00000089sv00008086sd00001311* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 AGN + +pci:v00008086d00000089sv00008086sd00001316* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N + WiMAX 6250 2x2 ABG + +pci:v00008086d0000008A* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 [Rainbow Peak] + +pci:v00008086d0000008Asv00008086sd00005305* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BGN + +pci:v00008086d0000008Asv00008086sd00005307* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BG + +pci:v00008086d0000008Asv00008086sd00005325* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BGN + +pci:v00008086d0000008Asv00008086sd00005327* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BG + +pci:v00008086d0000008B* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 [Rainbow Peak] + +pci:v00008086d0000008Bsv00008086sd00005315* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BGN + +pci:v00008086d0000008Bsv00008086sd00005317* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 1030 BG + +pci:v00008086d00000090* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 [Rainbow Peak] + +pci:v00008086d00000090sv00008086sd00005211* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 AGN + +pci:v00008086d00000090sv00008086sd00005215* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 BGN + +pci:v00008086d00000090sv00008086sd00005216* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 ABG + +pci:v00008086d00000091* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 [Rainbow Peak] + +pci:v00008086d00000091sv00008086sd00005201* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 AGN + +pci:v00008086d00000091sv00008086sd00005205* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 BGN + +pci:v00008086d00000091sv00008086sd00005206* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 ABG + +pci:v00008086d00000091sv00008086sd00005207* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 BG + +pci:v00008086d00000091sv00008086sd00005221* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 AGN + +pci:v00008086d00000091sv00008086sd00005225* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 BGN + +pci:v00008086d00000091sv00008086sd00005226* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6230 ABG + +pci:v00008086d00000100* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family DRAM Controller + +pci:v00008086d00000100sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00000100sv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00000101* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port + +pci:v00008086d00000101sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00000101sv0000106Bsd000000DC* + ID_MODEL_FROM_DATABASE=MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00000102* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000102sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00000104* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family DRAM Controller + +pci:v00008086d00000104sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00000104sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00000104sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00000104sv0000106Bsd000000DC* + ID_MODEL_FROM_DATABASE=MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00000105* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port + +pci:v00008086d00000105sv0000106Bsd000000DC* + ID_MODEL_FROM_DATABASE=MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00000106* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000108* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 Processor Family DRAM Controller + +pci:v00008086d00000109* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port + +pci:v00008086d0000010A* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 Processor Family Integrated Graphics Controller + +pci:v00008086d0000010B* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d0000010C* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller + +pci:v00008086d0000010D* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port + +pci:v00008086d0000010E* + ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000112* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000116* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000116sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00000122* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000126* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller + +pci:v00008086d00000126sv00001028sd000004CC* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00000150* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller + +pci:v00008086d00000150sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00000150sv00001849sd00000150* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00000151* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port + +pci:v00008086d00000151sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00000151sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00000152* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller + +pci:v00008086d00000152sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00000153* + ID_MODEL_FROM_DATABASE=3rd Gen Core Processor Thermal Subsystem + +pci:v00008086d00000153sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00000154* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor DRAM Controller + +pci:v00008086d00000154sv00001025sd00000813* + ID_MODEL_FROM_DATABASE=Aspire R7-571 + +pci:v00008086d00000154sv0000103Csd000017F6* + ID_MODEL_FROM_DATABASE=ProBook 4540s + +pci:v00008086d00000154sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00000154sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00000155* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port + +pci:v00008086d00000156* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller + +pci:v00008086d00000158* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/Ivy Bridge DRAM Controller + +pci:v00008086d00000159* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port + +pci:v00008086d0000015A* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/Ivy Bridge Graphics Controller + +pci:v00008086d0000015C* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller + +pci:v00008086d0000015D* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port + +pci:v00008086d0000015E* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller + +pci:v00008086d00000162* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller + +pci:v00008086d00000162sv00001849sd00000162* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00000166* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller + +pci:v00008086d00000166sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00000166sv00001043sd00002103* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d0000016A* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller + +pci:v00008086d00000172* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller + +pci:v00008086d00000176* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller + +pci:v00008086d00000309* + ID_MODEL_FROM_DATABASE=80303 I/O Processor PCI-to-PCI Bridge + +pci:v00008086d0000030D* + ID_MODEL_FROM_DATABASE=80312 I/O Companion Chip PCI-to-PCI Bridge + +pci:v00008086d00000326* + ID_MODEL_FROM_DATABASE=6700/6702PXH I/OxAPIC Interrupt Controller A + +pci:v00008086d00000326sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d00000326sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00000327* + ID_MODEL_FROM_DATABASE=6700PXH I/OxAPIC Interrupt Controller B + +pci:v00008086d00000327sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d00000327sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00000329* + ID_MODEL_FROM_DATABASE=6700PXH PCI Express-to-PCI Bridge A + +pci:v00008086d0000032A* + ID_MODEL_FROM_DATABASE=6700PXH PCI Express-to-PCI Bridge B + +pci:v00008086d0000032C* + ID_MODEL_FROM_DATABASE=6702PXH PCI Express-to-PCI Bridge A + +pci:v00008086d00000330* + ID_MODEL_FROM_DATABASE=80332 [Dobson] I/O processor (A-Segment Bridge) + +pci:v00008086d00000331* + ID_MODEL_FROM_DATABASE=80332 [Dobson] I/O processor (A-Segment IOAPIC) + +pci:v00008086d00000332* + ID_MODEL_FROM_DATABASE=80332 [Dobson] I/O processor (B-Segment Bridge) + +pci:v00008086d00000333* + ID_MODEL_FROM_DATABASE=80332 [Dobson] I/O processor (B-Segment IOAPIC) + +pci:v00008086d00000334* + ID_MODEL_FROM_DATABASE=80332 [Dobson] I/O processor (ATU) + +pci:v00008086d00000335* + ID_MODEL_FROM_DATABASE=80331 [Lindsay] I/O processor (PCI-X Bridge) + +pci:v00008086d00000336* + ID_MODEL_FROM_DATABASE=80331 [Lindsay] I/O processor (ATU) + +pci:v00008086d00000340* + ID_MODEL_FROM_DATABASE=41210 [Lanai] Serial to Parallel PCI Bridge (A-Segment Bridge) + +pci:v00008086d00000341* + ID_MODEL_FROM_DATABASE=41210 [Lanai] Serial to Parallel PCI Bridge (B-Segment Bridge) + +pci:v00008086d00000370* + ID_MODEL_FROM_DATABASE=80333 Segment-A PCI Express-to-PCI Express Bridge + +pci:v00008086d00000371* + ID_MODEL_FROM_DATABASE=80333 A-Bus IOAPIC + +pci:v00008086d00000372* + ID_MODEL_FROM_DATABASE=80333 Segment-B PCI Express-to-PCI Express Bridge + +pci:v00008086d00000373* + ID_MODEL_FROM_DATABASE=80333 B-Bus IOAPIC + +pci:v00008086d00000374* + ID_MODEL_FROM_DATABASE=80333 Address Translation Unit + +pci:v00008086d00000402* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller + +pci:v00008086d00000406* + ID_MODEL_FROM_DATABASE=4th Gen Core Processor Integrated Graphics Controller + +pci:v00008086d0000040A* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3 Processor Integrated Graphics Controller + +pci:v00008086d00000412* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller + +pci:v00008086d00000416* + ID_MODEL_FROM_DATABASE=4th Gen Core Processor Integrated Graphics Controller + +pci:v00008086d00000416sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d0000041A* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3 Processor Integrated Graphics Controller + +pci:v00008086d00000433* + ID_MODEL_FROM_DATABASE=Coleto Creek ACC - ME/CPM interface + +pci:v00008086d00000435* + ID_MODEL_FROM_DATABASE=Coleto Creek PCIe Endpoint + +pci:v00008086d00000436* + ID_MODEL_FROM_DATABASE=DH8900CC Null Device + +pci:v00008086d00000438* + ID_MODEL_FROM_DATABASE=DH8900CC Series Gigabit Network Connection + +pci:v00008086d0000043A* + ID_MODEL_FROM_DATABASE=DH8900CC Series Gigabit Fiber Network Connection + +pci:v00008086d0000043C* + ID_MODEL_FROM_DATABASE=DH8900CC Series Gigabit Backplane Network Connection + +pci:v00008086d00000440* + ID_MODEL_FROM_DATABASE=DH8900CC Series Gigabit SFP Network Connection + +pci:v00008086d00000482* + ID_MODEL_FROM_DATABASE=82375EB/SB PCI to EISA Bridge + +pci:v00008086d00000483* + ID_MODEL_FROM_DATABASE=82424TX/ZX [Saturn] CPU to PCI bridge + +pci:v00008086d00000484* + ID_MODEL_FROM_DATABASE=82378ZB/IB, 82379AB (SIO, SIO.A) PCI to ISA Bridge + +pci:v00008086d00000486* + ID_MODEL_FROM_DATABASE=82425EX/ZX [Aries] PCIset with ISA bridge + +pci:v00008086d000004A3* + ID_MODEL_FROM_DATABASE=82434LX/NX [Mercury/Neptune] Processor to PCI bridge + +pci:v00008086d000004D0* + ID_MODEL_FROM_DATABASE=82437FX [Triton FX] + +pci:v00008086d00000500* + ID_MODEL_FROM_DATABASE=E8870 Processor bus control + +pci:v00008086d00000501* + ID_MODEL_FROM_DATABASE=E8870 Memory controller + +pci:v00008086d00000502* + ID_MODEL_FROM_DATABASE=E8870 Scalability Port 0 + +pci:v00008086d00000503* + ID_MODEL_FROM_DATABASE=E8870 Scalability Port 1 + +pci:v00008086d00000510* + ID_MODEL_FROM_DATABASE=E8870IO Hub Interface Port 0 registers (8-bit compatibility port) + +pci:v00008086d00000511* + ID_MODEL_FROM_DATABASE=E8870IO Hub Interface Port 1 registers + +pci:v00008086d00000512* + ID_MODEL_FROM_DATABASE=E8870IO Hub Interface Port 2 registers + +pci:v00008086d00000513* + ID_MODEL_FROM_DATABASE=E8870IO Hub Interface Port 3 registers + +pci:v00008086d00000514* + ID_MODEL_FROM_DATABASE=E8870IO Hub Interface Port 4 registers + +pci:v00008086d00000515* + ID_MODEL_FROM_DATABASE=E8870IO General SIOH registers + +pci:v00008086d00000516* + ID_MODEL_FROM_DATABASE=E8870IO RAS registers + +pci:v00008086d00000530* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 0 registers + +pci:v00008086d00000531* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 1 registers + +pci:v00008086d00000532* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 2 registers + +pci:v00008086d00000533* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 3 registers + +pci:v00008086d00000534* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 4 registers + +pci:v00008086d00000535* + ID_MODEL_FROM_DATABASE=E8870SP Scalability Port 5 registers + +pci:v00008086d00000536* + ID_MODEL_FROM_DATABASE=E8870SP Interleave registers 0 and 1 + +pci:v00008086d00000537* + ID_MODEL_FROM_DATABASE=E8870SP Interleave registers 2 and 3 + +pci:v00008086d00000600* + ID_MODEL_FROM_DATABASE=RAID Controller + +pci:v00008086d00000600sv00008086sd00000136* + ID_MODEL_FROM_DATABASE=SRCU31L + +pci:v00008086d00000600sv00008086sd000001AF* + ID_MODEL_FROM_DATABASE=SRCZCR + +pci:v00008086d00000600sv00008086sd000001C1* + ID_MODEL_FROM_DATABASE=ICP Vortex GDT8546RZ + +pci:v00008086d00000600sv00008086sd000001F7* + ID_MODEL_FROM_DATABASE=SCRU32 + +pci:v00008086d0000061F* + ID_MODEL_FROM_DATABASE=80303 I/O Processor + +pci:v00008086d00000700* + ID_MODEL_FROM_DATABASE=CE Media Processor A/V Bridge + +pci:v00008086d00000701* + ID_MODEL_FROM_DATABASE=CE Media Processor NAND Flash Controller + +pci:v00008086d00000703* + ID_MODEL_FROM_DATABASE=CE Media Processor Media Control Unit 1 + +pci:v00008086d00000704* + ID_MODEL_FROM_DATABASE=CE Media Processor Video Capture Interface + +pci:v00008086d00000707* + ID_MODEL_FROM_DATABASE=CE Media Processor SPI Slave + +pci:v00008086d00000708* + ID_MODEL_FROM_DATABASE=CE Media Processor 4100 + +pci:v00008086d00000800* + ID_MODEL_FROM_DATABASE=Moorestown SPI Ctrl 0 + +pci:v00008086d00000801* + ID_MODEL_FROM_DATABASE=Moorestown SPI Ctrl 1 + +pci:v00008086d00000802* + ID_MODEL_FROM_DATABASE=Moorestown I2C 0 + +pci:v00008086d00000803* + ID_MODEL_FROM_DATABASE=Moorestown I2C 1 + +pci:v00008086d00000804* + ID_MODEL_FROM_DATABASE=Moorestown I2C 2 + +pci:v00008086d00000805* + ID_MODEL_FROM_DATABASE=Moorestown Keyboard Ctrl + +pci:v00008086d00000806* + ID_MODEL_FROM_DATABASE=Moorestown USB Ctrl + +pci:v00008086d00000807* + ID_MODEL_FROM_DATABASE=Moorestown SD Host Ctrl 0 + +pci:v00008086d00000808* + ID_MODEL_FROM_DATABASE=Moorestown SD Host Ctrl 1 + +pci:v00008086d00000809* + ID_MODEL_FROM_DATABASE=Moorestown NAND Ctrl + +pci:v00008086d0000080A* + ID_MODEL_FROM_DATABASE=Moorestown Audio Ctrl + +pci:v00008086d0000080B* + ID_MODEL_FROM_DATABASE=Moorestown ISP + +pci:v00008086d0000080C* + ID_MODEL_FROM_DATABASE=Moorestown Security Controller + +pci:v00008086d0000080D* + ID_MODEL_FROM_DATABASE=Moorestown External Displays + +pci:v00008086d0000080E* + ID_MODEL_FROM_DATABASE=Moorestown SCU IPC + +pci:v00008086d0000080F* + ID_MODEL_FROM_DATABASE=Moorestown GPIO Controller + +pci:v00008086d00000810* + ID_MODEL_FROM_DATABASE=Moorestown Power Management Unit + +pci:v00008086d00000811* + ID_MODEL_FROM_DATABASE=Moorestown OTG Ctrl + +pci:v00008086d00000812* + ID_MODEL_FROM_DATABASE=Moorestown SPI Ctrl 2 + +pci:v00008086d00000813* + ID_MODEL_FROM_DATABASE=Moorestown SC DMA + +pci:v00008086d00000814* + ID_MODEL_FROM_DATABASE=Moorestown LPE DMA + +pci:v00008086d00000815* + ID_MODEL_FROM_DATABASE=Moorestown SSP0 + +pci:v00008086d00000885* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 + +pci:v00008086d00000885sv00008086sd00001305* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BGN + +pci:v00008086d00000885sv00008086sd00001307* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BG + +pci:v00008086d00000885sv00008086sd00001325* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BGN + +pci:v00008086d00000885sv00008086sd00001327* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BG + +pci:v00008086d00000886* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 + +pci:v00008086d00000886sv00008086sd00001315* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BGN + +pci:v00008086d00000886sv00008086sd00001317* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N + WiMAX 6150 BG + +pci:v00008086d00000887* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2230 + +pci:v00008086d00000887sv00008086sd00004062* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2230 BGN + +pci:v00008086d00000887sv00008086sd00004462* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2230 BGN + +pci:v00008086d00000888* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2230 + +pci:v00008086d00000888sv00008086sd00004262* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2230 BGN + +pci:v00008086d0000088E* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6235 + +pci:v00008086d0000088Esv00008086sd00004060* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6235 AGN + +pci:v00008086d0000088Esv00008086sd00004460* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6235 AGN + +pci:v00008086d0000088F* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6235 + +pci:v00008086d0000088Fsv00008086sd00004260* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6235 AGN + +pci:v00008086d00000890* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 + +pci:v00008086d00000890sv00008086sd00004022* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 BGN + +pci:v00008086d00000890sv00008086sd00004422* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 BGN + +pci:v00008086d00000890sv00008086sd00004822* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 BGN + +pci:v00008086d00000891* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 + +pci:v00008086d00000891sv00008086sd00004222* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 2200 BGN + +pci:v00008086d00000892* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 135 + +pci:v00008086d00000892sv00008086sd00000062* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 135 BGN + +pci:v00008086d00000892sv00008086sd00000462* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 135 BGN + +pci:v00008086d00000893* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 135 + +pci:v00008086d00000893sv00008086sd00000262* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 135 BGN + +pci:v00008086d00000894* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 + +pci:v00008086d00000894sv00008086sd00000022* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 BGN + +pci:v00008086d00000894sv00008086sd00000422* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 BGN + +pci:v00008086d00000894sv00008086sd00000822* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 BGN + +pci:v00008086d00000895* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 + +pci:v00008086d00000895sv00008086sd00000222* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 105 BGN + +pci:v00008086d00000896* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 + +pci:v00008086d00000896sv00008086sd00005005* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BGN + +pci:v00008086d00000896sv00008086sd00005007* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BG + +pci:v00008086d00000896sv00008086sd00005025* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BGN + +pci:v00008086d00000896sv00008086sd00005027* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BG + +pci:v00008086d00000897* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 + +pci:v00008086d00000897sv00008086sd00005015* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BGN + +pci:v00008086d00000897sv00008086sd00005017* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 130 BG + +pci:v00008086d000008AE* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 + +pci:v00008086d000008AEsv00008086sd00001005* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BGN + +pci:v00008086d000008AEsv00008086sd00001007* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BG + +pci:v00008086d000008AEsv00008086sd00001025* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BGN + +pci:v00008086d000008AEsv00008086sd00001027* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BG + +pci:v00008086d000008AF* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 + +pci:v00008086d000008AFsv00008086sd00001015* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BGN + +pci:v00008086d000008AFsv00008086sd00001017* + ID_MODEL_FROM_DATABASE=Centrino Wireless-N 100 BG + +pci:v00008086d000008B1* + ID_MODEL_FROM_DATABASE=Wireless 7260 + +pci:v00008086d000008B1sv00008086sd00004060* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004062* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004070* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004160* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004162* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004170* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004460* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004462* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd00004470* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd0000486E* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004870* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004A6C* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004A6E* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd00004A70* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd0000C020* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C060* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C062* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C070* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd0000C160* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C162* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C170* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B1sv00008086sd0000C420* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C460* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C462* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B1sv00008086sd0000C470* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B2* + ID_MODEL_FROM_DATABASE=Wireless 7260 + +pci:v00008086d000008B2sv00008086sd00004220* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd00004260* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd00004262* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd00004270* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B2sv00008086sd0000C220* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd0000C260* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd0000C262* + ID_MODEL_FROM_DATABASE=Wireless-N 7260 + +pci:v00008086d000008B2sv00008086sd0000C270* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7260 + +pci:v00008086d000008B3* + ID_MODEL_FROM_DATABASE=Wireless 3160 + +pci:v00008086d000008B3sv00008086sd00000060* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 3160 + +pci:v00008086d000008B3sv00008086sd00000062* + ID_MODEL_FROM_DATABASE=Wireless-N 3160 + +pci:v00008086d000008B3sv00008086sd00000070* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 3160 + +pci:v00008086d000008B3sv00008086sd00000170* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 3160 + +pci:v00008086d000008B3sv00008086sd00000470* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 3160 + +pci:v00008086d000008B3sv00008086sd00008060* + ID_MODEL_FROM_DATABASE=Dual Band Wireless N-3160 + +pci:v00008086d000008B3sv00008086sd00008062* + ID_MODEL_FROM_DATABASE=Wireless N-3160 + +pci:v00008086d000008B3sv00008086sd00008070* + ID_MODEL_FROM_DATABASE=Dual Band Wireless AC 3160 + +pci:v00008086d000008B3sv00008086sd00008170* + ID_MODEL_FROM_DATABASE=Dual Band Wireless AC 3160 + +pci:v00008086d000008B3sv00008086sd00008470* + ID_MODEL_FROM_DATABASE=Dual Band Wireless AC 3160 + +pci:v00008086d000008B4* + ID_MODEL_FROM_DATABASE=Wireless 3160 + +pci:v00008086d000008B4sv00008086sd00000270* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 3160 + +pci:v00008086d000008B4sv00008086sd00008270* + ID_MODEL_FROM_DATABASE=Dual Band Wireless AC 3160 + +pci:v00008086d000008CF* + ID_MODEL_FROM_DATABASE=Atom Processor Z2760 Integrated Graphics Controller + +pci:v00008086d0000095A* + ID_MODEL_FROM_DATABASE=Wireless 7265 + +pci:v00008086d0000095Asv00008086sd00001010* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005000* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7265 + +pci:v00008086d0000095Asv00008086sd00005002* + ID_MODEL_FROM_DATABASE=Wireless-N 7265 + +pci:v00008086d0000095Asv00008086sd0000500A* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005010* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005012* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005020* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7265 + +pci:v00008086d0000095Asv00008086sd0000502A* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7265 + +pci:v00008086d0000095Asv00008086sd00005090* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005110* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005190* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005400* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005410* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005420* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7265 + +pci:v00008086d0000095Asv00008086sd00005490* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00005590* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009010* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009110* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009210* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009310* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009410* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Asv00008086sd00009510* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095B* + ID_MODEL_FROM_DATABASE=Wireless 7265 + +pci:v00008086d0000095Bsv00008086sd00005200* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-N 7265 + +pci:v00008086d0000095Bsv00008086sd00005202* + ID_MODEL_FROM_DATABASE=Wireless-N 7265 + +pci:v00008086d0000095Bsv00008086sd00005210* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Bsv00008086sd00005290* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Bsv00008086sd00005302* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d0000095Bsv00008086sd00005310* + ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 7265 + +pci:v00008086d00000960* + ID_MODEL_FROM_DATABASE=80960RP (i960RP) Microprocessor/Bridge + +pci:v00008086d00000962* + ID_MODEL_FROM_DATABASE=80960RM (i960RM) Bridge + +pci:v00008086d00000964* + ID_MODEL_FROM_DATABASE=80960RP (i960RP) Microprocessor/Bridge + +pci:v00008086d00000A04* + ID_MODEL_FROM_DATABASE=Haswell-ULT DRAM Controller + +pci:v00008086d00000A06* + ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller + +pci:v00008086d00000A0C* + ID_MODEL_FROM_DATABASE=Haswell-ULT HD Audio Controller + +pci:v00008086d00000A16* + ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller + +pci:v00008086d00000A22* + ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller + +pci:v00008086d00000A26* + ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller + +pci:v00008086d00000A2A* + ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller + +pci:v00008086d00000BE0* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE1* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE1sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d00000BE2* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE3* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE4* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE5* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE6* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE7* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE8* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BE9* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BEA* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BEB* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BEC* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BED* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BEE* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BEF* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller + +pci:v00008086d00000BF0* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF1* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF2* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF3* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF4* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF5* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF5sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d00000BF6* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000BF7* + ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx DRAM Controller + +pci:v00008086d00000C00* + ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller + +pci:v00008086d00000C01* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller + +pci:v00008086d00000C04* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller + +pci:v00008086d00000C04sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00000C05* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor PCI Express x8 Controller + +pci:v00008086d00000C08* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3 Processor DRAM Controller + +pci:v00008086d00000C09* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor PCI Express x4 Controller + +pci:v00008086d00000C0C* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller + +pci:v00008086d00000C0Csv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00000C46* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 PCI Express Root Port 1 + +pci:v00008086d00000C47* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 PCI Express Root Port 2 + +pci:v00008086d00000C48* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 PCI Express Root Port 3 + +pci:v00008086d00000C49* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 PCI Express Root Port 4 + +pci:v00008086d00000C4E* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 NTB Primary + +pci:v00008086d00000C54* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C55* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 DFX 1 + +pci:v00008086d00000C56* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 DFX 2 + +pci:v00008086d00000C59* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus 2.0 Controller 0 + +pci:v00008086d00000C5A* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus 2.0 Controller 1 + +pci:v00008086d00000C5B* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus Controller 2 + +pci:v00008086d00000C5C* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus Controller 3 + +pci:v00008086d00000C5D* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus Controller 4 + +pci:v00008086d00000C5E* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 SMBus Controller 5 + +pci:v00008086d00000C5F* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 UART + +pci:v00008086d00000C60* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Integrated Legacy Bus + +pci:v00008086d00000C70* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C71* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C72* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C73* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C74* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C75* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C76* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C77* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C78* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C79* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7A* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7B* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7C* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7D* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7E* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000C7F* + ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal + +pci:v00008086d00000D00* + ID_MODEL_FROM_DATABASE=Crystal Well DRAM Controller + +pci:v00008086d00000D01* + ID_MODEL_FROM_DATABASE=Crystal Well PCI Express x16 Controller + +pci:v00008086d00000D04* + ID_MODEL_FROM_DATABASE=Crystal Well DRAM Controller + +pci:v00008086d00000D05* + ID_MODEL_FROM_DATABASE=Crystal Well PCI Express x8 Controller + +pci:v00008086d00000D09* + ID_MODEL_FROM_DATABASE=Crystal Well PCI Express x4 Controller + +pci:v00008086d00000D0C* + ID_MODEL_FROM_DATABASE=Crystal Well HD Audio Controller + +pci:v00008086d00000D16* + ID_MODEL_FROM_DATABASE=Crystal Well Integrated Graphics Controller + +pci:v00008086d00000D26* + ID_MODEL_FROM_DATABASE=Crystal Well Integrated Graphics Controller + +pci:v00008086d00000D36* + ID_MODEL_FROM_DATABASE=Crystal Well Integrated Graphics Controller + +pci:v00008086d00000E00* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DMI2 + +pci:v00008086d00000E01* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port in DMI2 Mode + +pci:v00008086d00000E02* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 1a + +pci:v00008086d00000E03* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 1b + +pci:v00008086d00000E04* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 2a + +pci:v00008086d00000E05* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 2b + +pci:v00008086d00000E06* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 2c + +pci:v00008086d00000E07* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 2d + +pci:v00008086d00000E08* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 3a + +pci:v00008086d00000E09* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 3b + +pci:v00008086d00000E0A* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 3c + +pci:v00008086d00000E0B* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 PCI Express Root Port 3d + +pci:v00008086d00000E10* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO Configuration Registers + +pci:v00008086d00000E13* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO Configuration Registers + +pci:v00008086d00000E17* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO Configuration Registers + +pci:v00008086d00000E18* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO Configuration Registers + +pci:v00008086d00000E1C* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO Configuration Registers + +pci:v00008086d00000E1D* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 R2PCIe + +pci:v00008086d00000E1E* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 UBOX Registers + +pci:v00008086d00000E1F* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 UBOX Registers + +pci:v00008086d00000E20* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 0 + +pci:v00008086d00000E21* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 1 + +pci:v00008086d00000E22* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 2 + +pci:v00008086d00000E23* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 3 + +pci:v00008086d00000E24* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 4 + +pci:v00008086d00000E25* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 5 + +pci:v00008086d00000E26* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 6 + +pci:v00008086d00000E27* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Crystal Beach DMA Channel 7 + +pci:v00008086d00000E28* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 VTd/Memory Map/Misc + +pci:v00008086d00000E29* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Memory Hotplug + +pci:v00008086d00000E2A* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IIO RAS + +pci:v00008086d00000E2C* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 IOAPIC + +pci:v00008086d00000E2E* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 CBDMA + +pci:v00008086d00000E2F* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 CBDMA + +pci:v00008086d00000E30* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Home Agent 0 + +pci:v00008086d00000E32* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 0 + +pci:v00008086d00000E33* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 1 + +pci:v00008086d00000E34* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 R2PCIe + +pci:v00008086d00000E36* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring + +pci:v00008086d00000E37* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring + +pci:v00008086d00000E38* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Home Agent 1 + +pci:v00008086d00000E3A* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 2 + +pci:v00008086d00000E3E* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring + +pci:v00008086d00000E3F* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Performance Ring Monitoring + +pci:v00008086d00000E40* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 2 + +pci:v00008086d00000E41* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Registers + +pci:v00008086d00000E43* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link Reut 2 + +pci:v00008086d00000E44* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link Reut 2 + +pci:v00008086d00000E60* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Home Agent 1 + +pci:v00008086d00000E68* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Target Address/Thermal Registers + +pci:v00008086d00000E6A* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers + +pci:v00008086d00000E6B* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers + +pci:v00008086d00000E6C* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers + +pci:v00008086d00000E6D* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel Target Address Decoder Registers + +pci:v00008086d00000E71* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 RAS Registers + +pci:v00008086d00000E74* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 R2PCIe + +pci:v00008086d00000E75* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 R2PCIe + +pci:v00008086d00000E77* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Registers + +pci:v00008086d00000E79* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 RAS Registers + +pci:v00008086d00000E7D* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 UBOX Registers + +pci:v00008086d00000E7F* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Registers + +pci:v00008086d00000E80* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 0 + +pci:v00008086d00000E81* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Ring Registers + +pci:v00008086d00000E83* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link Reut 0 + +pci:v00008086d00000E84* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link Reut 0 + +pci:v00008086d00000E87* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Registers + +pci:v00008086d00000E90* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 1 + +pci:v00008086d00000E93* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link 1 + +pci:v00008086d00000E94* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 QPI Link Reut 1 + +pci:v00008086d00000EA0* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Home Agent 0 + +pci:v00008086d00000EA8* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Target Address/Thermal Registers + +pci:v00008086d00000EAA* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers + +pci:v00008086d00000EAB* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers + +pci:v00008086d00000EAC* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers + +pci:v00008086d00000EAD* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel Target Address Decoder Registers + +pci:v00008086d00000EAE* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO Registers + +pci:v00008086d00000EAF* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO Registers + +pci:v00008086d00000EB0* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 0 + +pci:v00008086d00000EB1* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 1 + +pci:v00008086d00000EB2* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 0 + +pci:v00008086d00000EB3* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 1 + +pci:v00008086d00000EB4* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 2 + +pci:v00008086d00000EB5* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 Thermal Control 3 + +pci:v00008086d00000EB6* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 2 + +pci:v00008086d00000EB7* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 1 Channel 0-3 ERROR Registers 3 + +pci:v00008086d00000EBC* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO Registers + +pci:v00008086d00000EBE* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO Registers + +pci:v00008086d00000EBF* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO Registers + +pci:v00008086d00000EC0* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Power Control Unit 0 + +pci:v00008086d00000EC1* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Power Control Unit 1 + +pci:v00008086d00000EC2* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Power Control Unit 2 + +pci:v00008086d00000EC3* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Power Control Unit 3 + +pci:v00008086d00000EC4* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Power Control Unit 4 + +pci:v00008086d00000EC8* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 System Address Decoder + +pci:v00008086d00000EC9* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Broadcast Registers + +pci:v00008086d00000ECA* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Broadcast Registers + +pci:v00008086d00000ED8* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000ED9* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EDC* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EDD* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EDE* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EDF* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EE0* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE1* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE2* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE3* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE4* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE5* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE6* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE7* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE8* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EE9* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EEA* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EEB* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EEC* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EED* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EEE* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Unicast Registers + +pci:v00008086d00000EF0* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 0 + +pci:v00008086d00000EF1* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 1 + +pci:v00008086d00000EF2* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 0 + +pci:v00008086d00000EF3* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 1 + +pci:v00008086d00000EF4* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 2 + +pci:v00008086d00000EF5* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 Thermal Control 3 + +pci:v00008086d00000EF6* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 2 + +pci:v00008086d00000EF7* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 Integrated Memory Controller 0 Channel 0-3 ERROR Registers 3 + +pci:v00008086d00000EF8* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EF9* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EFA* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EFB* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EFC* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000EFD* + ID_MODEL_FROM_DATABASE=Xeon E5 v2/Core i7 DDRIO + +pci:v00008086d00000F00* + ID_MODEL_FROM_DATABASE=ValleyView SSA-CUnit + +pci:v00008086d00000F01* + ID_MODEL_FROM_DATABASE=ValleyView SSA-CUnit + +pci:v00008086d00000F02* + ID_MODEL_FROM_DATABASE=ValleyView SSA-CUnit + +pci:v00008086d00000F03* + ID_MODEL_FROM_DATABASE=ValleyView SSA-CUnit + +pci:v00008086d00000F04* + ID_MODEL_FROM_DATABASE=ValleyView High Definition Audio Controller + +pci:v00008086d00000F05* + ID_MODEL_FROM_DATABASE=ValleyView High Definition Audio Controller + +pci:v00008086d00000F06* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 DMA Controller + +pci:v00008086d00000F07* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 DMA Controller + +pci:v00008086d00000F08* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 PWM Controller + +pci:v00008086d00000F09* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 PWM Controller + +pci:v00008086d00000F0A* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 HSUART Controller #1 + +pci:v00008086d00000F0B* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 HSUART Controller #1 + +pci:v00008086d00000F0C* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 HSUART Controller #2 + +pci:v00008086d00000F0D* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 HSUART Controller #2 + +pci:v00008086d00000F0E* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 SPI Controller + +pci:v00008086d00000F0F* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 SPI Controller + +pci:v00008086d00000F10* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 Controller + +pci:v00008086d00000F11* + ID_MODEL_FROM_DATABASE=ValleyView LPIO1 Controller + +pci:v00008086d00000F12* + ID_MODEL_FROM_DATABASE=ValleyView SMBus Controller + +pci:v00008086d00000F13* + ID_MODEL_FROM_DATABASE=ValleyView SMBus Controller + +pci:v00008086d00000F14* + ID_MODEL_FROM_DATABASE=ValleyView SDIO Controller + +pci:v00008086d00000F15* + ID_MODEL_FROM_DATABASE=ValleyView SDIO Controller + +pci:v00008086d00000F16* + ID_MODEL_FROM_DATABASE=ValleyView SDIO Controller + +pci:v00008086d00000F17* + ID_MODEL_FROM_DATABASE=ValleyView SDIO Controller + +pci:v00008086d00000F18* + ID_MODEL_FROM_DATABASE=ValleyView SEC + +pci:v00008086d00000F19* + ID_MODEL_FROM_DATABASE=ValleyView SEC + +pci:v00008086d00000F1A* + ID_MODEL_FROM_DATABASE=ValleyView SEC + +pci:v00008086d00000F1B* + ID_MODEL_FROM_DATABASE=ValleyView SEC + +pci:v00008086d00000F1C* + ID_MODEL_FROM_DATABASE=ValleyView Power Control Unit + +pci:v00008086d00000F1D* + ID_MODEL_FROM_DATABASE=ValleyView Power Control Unit + +pci:v00008086d00000F1E* + ID_MODEL_FROM_DATABASE=ValleyView Power Control Unit + +pci:v00008086d00000F1F* + ID_MODEL_FROM_DATABASE=ValleyView Power Control Unit + +pci:v00008086d00000F20* + ID_MODEL_FROM_DATABASE=ValleyView 4-Port SATA Storage Controller + +pci:v00008086d00000F21* + ID_MODEL_FROM_DATABASE=ValleyView 4-Port SATA Storage Controller + +pci:v00008086d00000F22* + ID_MODEL_FROM_DATABASE=ValleyView 6-Port SATA AHCI Controller + +pci:v00008086d00000F23* + ID_MODEL_FROM_DATABASE=ValleyView 6-Port SATA AHCI Controller + +pci:v00008086d00000F24* + ID_MODEL_FROM_DATABASE=ValleyView SATA RAID Storage Controller + +pci:v00008086d00000F25* + ID_MODEL_FROM_DATABASE=ValleyView SATA RAID Storage Controller + +pci:v00008086d00000F26* + ID_MODEL_FROM_DATABASE=ValleyView 2-Port SATA Storage Controller + +pci:v00008086d00000F27* + ID_MODEL_FROM_DATABASE=ValleyView 2-Port SATA Storage Controller + +pci:v00008086d00000F28* + ID_MODEL_FROM_DATABASE=ValleyView LPE Audio Controller + +pci:v00008086d00000F29* + ID_MODEL_FROM_DATABASE=ValleyView LPE Audio Controller + +pci:v00008086d00000F2A* + ID_MODEL_FROM_DATABASE=ValleyView LPE Audio Controller + +pci:v00008086d00000F2B* + ID_MODEL_FROM_DATABASE=ValleyView LPE Audio Controller + +pci:v00008086d00000F2E* + ID_MODEL_FROM_DATABASE=ValleyView SATA RAID Storage Controller + +pci:v00008086d00000F2F* + ID_MODEL_FROM_DATABASE=ValleyView SATA RAID Storage Controller + +pci:v00008086d00000F30* + ID_MODEL_FROM_DATABASE=ValleyView Gen7 + +pci:v00008086d00000F31* + ID_MODEL_FROM_DATABASE=ValleyView Gen7 + +pci:v00008086d00000F32* + ID_MODEL_FROM_DATABASE=ValleyView Gen7 + +pci:v00008086d00000F33* + ID_MODEL_FROM_DATABASE=ValleyView Gen7 + +pci:v00008086d00000F34* + ID_MODEL_FROM_DATABASE=ValleyView USB Enhanced Host Controller + +pci:v00008086d00000F35* + ID_MODEL_FROM_DATABASE=ValleyView USB xHCI Host Controller + +pci:v00008086d00000F36* + ID_MODEL_FROM_DATABASE=ValleyView USB xHCI Host Controller + +pci:v00008086d00000F37* + ID_MODEL_FROM_DATABASE=ValleyView OTG + +pci:v00008086d00000F38* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F39* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3A* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3B* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3C* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3D* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3E* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F3F* + ID_MODEL_FROM_DATABASE=ValleyView ISP + +pci:v00008086d00000F40* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 DMA Controller + +pci:v00008086d00000F41* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #1 + +pci:v00008086d00000F42* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #2 + +pci:v00008086d00000F43* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #3 + +pci:v00008086d00000F44* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #4 + +pci:v00008086d00000F45* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #5 + +pci:v00008086d00000F46* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #6 + +pci:v00008086d00000F47* + ID_MODEL_FROM_DATABASE=ValleyView LPIO2 I2C Controller #7 + +pci:v00008086d00000F48* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F49* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4A* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4B* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4C* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4D* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4E* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F4F* + ID_MODEL_FROM_DATABASE=ValleyView PCI Express Root Port + +pci:v00008086d00000F50* + ID_MODEL_FROM_DATABASE=ValleyView MIPI-HSI Controller + +pci:v00008086d00001000* + ID_MODEL_FROM_DATABASE=82542 Gigabit Ethernet Controller (Fiber) + +pci:v00008086d00001000sv00000E11sd0000B0DF* + ID_MODEL_FROM_DATABASE=NC6132 Gigabit Ethernet Adapter (1000-SX) + +pci:v00008086d00001000sv00000E11sd0000B0E0* + ID_MODEL_FROM_DATABASE=NC6133 Gigabit Ethernet Adapter (1000-LX) + +pci:v00008086d00001000sv00000E11sd0000B123* + ID_MODEL_FROM_DATABASE=NC6134 Gigabit Ethernet Adapter (1000-LX) + +pci:v00008086d00001000sv00001014sd00000119* + ID_MODEL_FROM_DATABASE=Netfinity Gigabit Ethernet SX Adapter + +pci:v00008086d00001000sv00008086sd00001000* + ID_MODEL_FROM_DATABASE=PRO/1000 Gigabit Server Adapter + +pci:v00008086d00001001* + ID_MODEL_FROM_DATABASE=82543GC Gigabit Ethernet Controller (Fiber) + +pci:v00008086d00001001sv00000E11sd0000004A* + ID_MODEL_FROM_DATABASE=NC6136 Gigabit Server Adapter + +pci:v00008086d00001001sv00001014sd000001EA* + ID_MODEL_FROM_DATABASE=Netfinity Gigabit Ethernet SX Adapter + +pci:v00008086d00001001sv00008086sd00001002* + ID_MODEL_FROM_DATABASE=PRO/1000 F Server Adapter + +pci:v00008086d00001001sv00008086sd00001003* + ID_MODEL_FROM_DATABASE=PRO/1000 F Server Adapter + +pci:v00008086d00001002* + ID_MODEL_FROM_DATABASE=Pro 100 LAN+Modem 56 Cardbus II + +pci:v00008086d00001002sv00008086sd0000200E* + ID_MODEL_FROM_DATABASE=Pro 100 LAN+Modem 56 Cardbus II + +pci:v00008086d00001002sv00008086sd00002013* + ID_MODEL_FROM_DATABASE=Pro 100 SR Mobile Combo Adapter + +pci:v00008086d00001002sv00008086sd00002017* + ID_MODEL_FROM_DATABASE=Pro 100 S Combo Mobile Adapter + +pci:v00008086d00001004* + ID_MODEL_FROM_DATABASE=82543GC Gigabit Ethernet Controller (Copper) + +pci:v00008086d00001004sv00000E11sd00000049* + ID_MODEL_FROM_DATABASE=NC7132 Gigabit Upgrade Module + +pci:v00008086d00001004sv00000E11sd0000B1A4* + ID_MODEL_FROM_DATABASE=NC7131 Gigabit Server Adapter + +pci:v00008086d00001004sv00001014sd000010F2* + ID_MODEL_FROM_DATABASE=Gigabit Ethernet Server Adapter + +pci:v00008086d00001004sv00008086sd00001004* + ID_MODEL_FROM_DATABASE=PRO/1000 T Server Adapter + +pci:v00008086d00001004sv00008086sd00002004* + ID_MODEL_FROM_DATABASE=PRO/1000 T Server Adapter + +pci:v00008086d00001008* + ID_MODEL_FROM_DATABASE=82544EI Gigabit Ethernet Controller (Copper) + +pci:v00008086d00001008sv00001014sd00000269* + ID_MODEL_FROM_DATABASE=iSeries 1000/100/10 Ethernet Adapter + +pci:v00008086d00001008sv00001028sd0000011B* + ID_MODEL_FROM_DATABASE=PowerEdge 1650/2550 + +pci:v00008086d00001008sv00001028sd0000011C* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Network Connection + +pci:v00008086d00001008sv00008086sd00001107* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Server Adapter + +pci:v00008086d00001008sv00008086sd00002107* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Server Adapter + +pci:v00008086d00001008sv00008086sd00002110* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Desktop Adapter + +pci:v00008086d00001008sv00008086sd00003108* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Network Connection + +pci:v00008086d00001009* + ID_MODEL_FROM_DATABASE=82544EI Gigabit Ethernet Controller (Fiber) + +pci:v00008086d00001009sv00001014sd00000268* + ID_MODEL_FROM_DATABASE=iSeries Gigabit Ethernet Adapter + +pci:v00008086d00001009sv00008086sd00001109* + ID_MODEL_FROM_DATABASE=PRO/1000 XF Server Adapter + +pci:v00008086d00001009sv00008086sd00002109* + ID_MODEL_FROM_DATABASE=PRO/1000 XF Server Adapter + +pci:v00008086d0000100A* + ID_MODEL_FROM_DATABASE=82540EM Gigabit Ethernet Controller + +pci:v00008086d0000100C* + ID_MODEL_FROM_DATABASE=82544GC Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000100Csv00008086sd00001112* + ID_MODEL_FROM_DATABASE=PRO/1000 T Desktop Adapter + +pci:v00008086d0000100Csv00008086sd00002112* + ID_MODEL_FROM_DATABASE=PRO/1000 T Desktop Adapter + +pci:v00008086d0000100D* + ID_MODEL_FROM_DATABASE=82544GC Gigabit Ethernet Controller (LOM) + +pci:v00008086d0000100Dsv00001028sd00000123* + ID_MODEL_FROM_DATABASE=PRO/1000 XT Network Connection + +pci:v00008086d0000100Dsv00001079sd0000891F* + ID_MODEL_FROM_DATABASE=82544GC Based Network Connection + +pci:v00008086d0000100Dsv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00008086d0000100Dsv00008086sd0000110D* + ID_MODEL_FROM_DATABASE=82544GC Based Network Connection + +pci:v00008086d0000100E* + ID_MODEL_FROM_DATABASE=82540EM Gigabit Ethernet Controller + +pci:v00008086d0000100Esv00001014sd00000265* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d0000100Esv00001014sd00000267* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d0000100Esv00001014sd0000026A* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d0000100Esv00001028sd0000002E* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d0000100Esv00001028sd00000134* + ID_MODEL_FROM_DATABASE=PowerEdge 600SC + +pci:v00008086d0000100Esv00001028sd00000151* + ID_MODEL_FROM_DATABASE=Optiplex GX270 + +pci:v00008086d0000100Esv0000107Bsd00008920* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Adapter + +pci:v00008086d0000100Esv00008086sd0000001E* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Adapter + +pci:v00008086d0000100Esv00008086sd0000002E* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Adapter + +pci:v00008086d0000100Esv00008086sd00001376* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Desktop Adapter + +pci:v00008086d0000100Esv00008086sd00001476* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Desktop Adapter + +pci:v00008086d0000100F* + ID_MODEL_FROM_DATABASE=82545EM Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000100Fsv00001014sd00000269* + ID_MODEL_FROM_DATABASE=iSeries 1000/100/10 Ethernet Adapter + +pci:v00008086d0000100Fsv00001014sd0000028E* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d0000100Fsv000015ADsd00000750* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Single Port Adapter + +pci:v00008086d0000100Fsv00008086sd00001000* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d0000100Fsv00008086sd00001001* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Server Adapter + +pci:v00008086d00001010* + ID_MODEL_FROM_DATABASE=82546EB Gigabit Ethernet Controller (Copper) + +pci:v00008086d00001010sv00000E11sd000000DB* + ID_MODEL_FROM_DATABASE=NC7170 Gigabit Server Adapter + +pci:v00008086d00001010sv00001014sd0000027C* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Network Adapter + +pci:v00008086d00001010sv000015ADsd00000760* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Adapter + +pci:v00008086d00001010sv000018FBsd00007872* + ID_MODEL_FROM_DATABASE=RESlink-X + +pci:v00008086d00001010sv00001FC1sd00000026* + ID_MODEL_FROM_DATABASE=Niagara 2260 Bypass Card + +pci:v00008086d00001010sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00008086d00001010sv00004C53sd000010A0* + ID_MODEL_FROM_DATABASE=CA3/CR3 mainboard + +pci:v00008086d00001010sv00008086sd00001011* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Server Adapter + +pci:v00008086d00001010sv00008086sd00001012* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Server Adapter + +pci:v00008086d00001010sv00008086sd0000101A* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Network Connection + +pci:v00008086d00001010sv00008086sd00003424* + ID_MODEL_FROM_DATABASE=SE7501HG2 Mainboard + +pci:v00008086d00001011* + ID_MODEL_FROM_DATABASE=82545EM Gigabit Ethernet Controller (Fiber) + +pci:v00008086d00001011sv00001014sd00000268* + ID_MODEL_FROM_DATABASE=iSeries Gigabit Ethernet Adapter + +pci:v00008086d00001011sv00008086sd00001002* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter + +pci:v00008086d00001011sv00008086sd00001003* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter (LX) + +pci:v00008086d00001012* + ID_MODEL_FROM_DATABASE=82546EB Gigabit Ethernet Controller (Fiber) + +pci:v00008086d00001012sv00000E11sd000000DC* + ID_MODEL_FROM_DATABASE=NC6170 Gigabit Server Adapter + +pci:v00008086d00001012sv00008086sd00001012* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Dual Port Server Adapter + +pci:v00008086d00001013* + ID_MODEL_FROM_DATABASE=82541EI Gigabit Ethernet Controller + +pci:v00008086d00001013sv00008086sd00000013* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001013sv00008086sd00001013* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001013sv00008086sd00001113* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Adapter + +pci:v00008086d00001014* + ID_MODEL_FROM_DATABASE=82541ER Gigabit Ethernet Controller + +pci:v00008086d00001014sv00008086sd00000014* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Connection + +pci:v00008086d00001014sv00008086sd00001014* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001015* + ID_MODEL_FROM_DATABASE=82540EM Gigabit Ethernet Controller (LOM) + +pci:v00008086d00001015sv00008086sd00001015* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001016* + ID_MODEL_FROM_DATABASE=82540EP Gigabit Ethernet Controller (Mobile) + +pci:v00008086d00001016sv00001014sd0000052C* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001016sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001016sv00008086sd00001016* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001017* + ID_MODEL_FROM_DATABASE=82540EP Gigabit Ethernet Controller + +pci:v00008086d00001017sv00008086sd00001017* + ID_MODEL_FROM_DATABASE=PR0/1000 MT Desktop Connection + +pci:v00008086d00001018* + ID_MODEL_FROM_DATABASE=82541EI Gigabit Ethernet Controller + +pci:v00008086d00001018sv00008086sd00001018* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001019* + ID_MODEL_FROM_DATABASE=82547EI Gigabit Ethernet Controller + +pci:v00008086d00001019sv00001458sd00001019* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d00001019sv00001458sd0000E000* + ID_MODEL_FROM_DATABASE=Intel Gigabit Ethernet (Kenai II) + +pci:v00008086d00001019sv00008086sd00001019* + ID_MODEL_FROM_DATABASE=PRO/1000 CT Desktop Connection + +pci:v00008086d00001019sv00008086sd0000301F* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d00001019sv00008086sd00003025* + ID_MODEL_FROM_DATABASE=D875PBZ motherboard + +pci:v00008086d00001019sv00008086sd0000302C* + ID_MODEL_FROM_DATABASE=Intel 82865G Mainboard (D865GBF) + +pci:v00008086d00001019sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d0000101A* + ID_MODEL_FROM_DATABASE=82547EI Gigabit Ethernet Controller (Mobile) + +pci:v00008086d0000101Asv00008086sd0000101A* + ID_MODEL_FROM_DATABASE=PRO/1000 CT Mobile Connection + +pci:v00008086d0000101D* + ID_MODEL_FROM_DATABASE=82546EB Gigabit Ethernet Controller + +pci:v00008086d0000101Dsv00008086sd00001000* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Quad Port Server Adapter + +pci:v00008086d0000101E* + ID_MODEL_FROM_DATABASE=82540EP Gigabit Ethernet Controller (Mobile) + +pci:v00008086d0000101Esv00001014sd00000549* + ID_MODEL_FROM_DATABASE=Thinkpad + +pci:v00008086d0000101Esv00001179sd00000001* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d0000101Esv00008086sd0000101E* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001026* + ID_MODEL_FROM_DATABASE=82545GM Gigabit Ethernet Controller + +pci:v00008086d00001026sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d00001026sv00008086sd00001000* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Server Connection + +pci:v00008086d00001026sv00008086sd00001001* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Server Adapter + +pci:v00008086d00001026sv00008086sd00001002* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Server Adapter + +pci:v00008086d00001026sv00008086sd00001003* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Server Adapter + +pci:v00008086d00001026sv00008086sd00001026* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Server Connection + +pci:v00008086d00001027* + ID_MODEL_FROM_DATABASE=82545GM Gigabit Ethernet Controller + +pci:v00008086d00001027sv0000103Csd00003103* + ID_MODEL_FROM_DATABASE=NC310F PCI-X Gigabit Server Adapter + +pci:v00008086d00001027sv00008086sd00001001* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter(LX) + +pci:v00008086d00001027sv00008086sd00001002* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter(LX) + +pci:v00008086d00001027sv00008086sd00001003* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter(LX) + +pci:v00008086d00001027sv00008086sd00001027* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter + +pci:v00008086d00001028* + ID_MODEL_FROM_DATABASE=82545GM Gigabit Ethernet Controller + +pci:v00008086d00001028sv00008086sd00001028* + ID_MODEL_FROM_DATABASE=PRO/1000 MB Server Connection + +pci:v00008086d00001029* + ID_MODEL_FROM_DATABASE=82559 Ethernet Controller + +pci:v00008086d00001030* + ID_MODEL_FROM_DATABASE=82559 InBusiness 10/100 + +pci:v00008086d00001031* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller + +pci:v00008086d00001031sv00001014sd00000209* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00001031sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00001031sv0000104Dsd0000813C* + ID_MODEL_FROM_DATABASE=Vaio PCG-GRV616G + +pci:v00008086d00001031sv0000107Bsd00005350* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00001031sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00001031sv0000144Dsd0000C000* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00001031sv0000144Dsd0000C001* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00001031sv0000144Dsd0000C003* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00001031sv0000144Dsd0000C006* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d00001032* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) PRO/100 VE Ethernet Controller + +pci:v00008086d00001033* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller + +pci:v00008086d00001034* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) PRO/100 VM Ethernet Controller + +pci:v00008086d00001035* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3)/82562EH (LOM) Ethernet Controller + +pci:v00008086d00001036* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) 82562EH Ethernet Controller + +pci:v00008086d00001037* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) Chipset Ethernet Controller + +pci:v00008086d00001038* + ID_MODEL_FROM_DATABASE=82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller + +pci:v00008086d00001038sv00000E11sd00000098* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d00001039* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VE (LOM) Ethernet Controller + +pci:v00008086d00001039sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d00001039sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard ethernet ETH1 + +pci:v00008086d0000103A* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VE (CNR) Ethernet Controller + +pci:v00008086d0000103B* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VM (LOM) Ethernet Controller + +pci:v00008086d0000103C* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VM (CNR) Ethernet Controller + +pci:v00008086d0000103D* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VE (MOB) Ethernet Controller + +pci:v00008086d0000103Dsv00001014sd00000522* + ID_MODEL_FROM_DATABASE=ThinkPad R40 + +pci:v00008086d0000103Dsv00001028sd00002002* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d0000103Dsv00008086sd0000103D* + ID_MODEL_FROM_DATABASE=82562EZ 10/100 Ethernet Controller + +pci:v00008086d0000103E* + ID_MODEL_FROM_DATABASE=82801DB PRO/100 VM (MOB) Ethernet Controller + +pci:v00008086d00001040* + ID_MODEL_FROM_DATABASE=536EP Data Fax Modem + +pci:v00008086d00001040sv000016BEsd00001040* + ID_MODEL_FROM_DATABASE=V.9X DSP Data Fax Modem + +pci:v00008086d00001043* + ID_MODEL_FROM_DATABASE=PRO/Wireless LAN 2100 3B Mini PCI Adapter + +pci:v00008086d00001043sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d00001043sv00008086sd00002522* + ID_MODEL_FROM_DATABASE=Samsung X10/P30 integrated WLAN + +pci:v00008086d00001043sv00008086sd00002527* + ID_MODEL_FROM_DATABASE=MIM2000/Centrino + +pci:v00008086d00001043sv00008086sd00002561* + ID_MODEL_FROM_DATABASE=Dell Latitude D800 + +pci:v00008086d00001043sv00008086sd00002581* + ID_MODEL_FROM_DATABASE=Toshiba Satellite M10 + +pci:v00008086d00001048* + ID_MODEL_FROM_DATABASE=82597EX 10GbE Ethernet Controller + +pci:v00008086d00001048sv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=PRO/10GbE LR Server Adapter + +pci:v00008086d00001048sv00008086sd0000A11F* + ID_MODEL_FROM_DATABASE=PRO/10GbE LR Server Adapter + +pci:v00008086d00001049* + ID_MODEL_FROM_DATABASE=82566MM Gigabit Network Connection + +pci:v00008086d00001049sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00001049sv000017AAsd000020B9* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d0000104A* + ID_MODEL_FROM_DATABASE=82566DM Gigabit Network Connection + +pci:v00008086d0000104B* + ID_MODEL_FROM_DATABASE=82566DC Gigabit Network Connection + +pci:v00008086d0000104C* + ID_MODEL_FROM_DATABASE=82562V 10/100 Network Connection + +pci:v00008086d0000104D* + ID_MODEL_FROM_DATABASE=82566MC Gigabit Network Connection + +pci:v00008086d00001050* + ID_MODEL_FROM_DATABASE=82562EZ 10/100 Ethernet Controller + +pci:v00008086d00001050sv00001028sd0000019D* + ID_MODEL_FROM_DATABASE=Dimension 3000 + +pci:v00008086d00001050sv00001462sd0000728C* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d00001050sv00001462sd0000758C* + ID_MODEL_FROM_DATABASE=MS-6758 (875P Neo) + +pci:v00008086d00001050sv00008086sd00003020* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d00001050sv00008086sd0000302F* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d00001050sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d00001051* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) integrated LAN Controller + +pci:v00008086d00001052* + ID_MODEL_FROM_DATABASE=PRO/100 VM Network Connection + +pci:v00008086d00001053* + ID_MODEL_FROM_DATABASE=PRO/100 VM Network Connection + +pci:v00008086d00001054* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001055* + ID_MODEL_FROM_DATABASE=PRO/100 VM Network Connection + +pci:v00008086d00001056* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001057* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001059* + ID_MODEL_FROM_DATABASE=82551QM Ethernet Controller + +pci:v00008086d0000105B* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000105E* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller + +pci:v00008086d0000105Esv0000103Csd00007044* + ID_MODEL_FROM_DATABASE=NC360T PCI Express Dual Port Gigabit Server Adapter + +pci:v00008086d0000105Esv0000103Csd0000704E* + ID_MODEL_FROM_DATABASE=Dual Port 1000Base-T (PCIe) [AD337A] + +pci:v00008086d0000105Esv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d0000105Esv00001775sd00006003* + ID_MODEL_FROM_DATABASE=Telum GE-QT + +pci:v00008086d0000105Esv000018DFsd00001214* + ID_MODEL_FROM_DATABASE=2x 1GbE, PCIe x1, dual Intel 82571EB chips + +pci:v00008086d0000105Esv00008086sd0000005E* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Dual Port Server Connection + +pci:v00008086d0000105Esv00008086sd0000105E* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Dual Port Network Connection + +pci:v00008086d0000105Esv00008086sd000010D5* + ID_MODEL_FROM_DATABASE=82571PT Gigabit PT Quad Port Server ExpressModule + +pci:v00008086d0000105Esv00008086sd0000115E* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Dual Port Server Adapter + +pci:v00008086d0000105Esv00008086sd0000125E* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Dual Port Server Adapter + +pci:v00008086d0000105Esv00008086sd0000135E* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Dual Port Server Adapter + +pci:v00008086d0000105F* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller + +pci:v00008086d0000105Fsv0000103Csd0000704F* + ID_MODEL_FROM_DATABASE=Dual Port 1000Base-SX (PCIe) [AD338A] + +pci:v00008086d0000105Fsv00008086sd0000005A* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Dual Port Server Adapter + +pci:v00008086d0000105Fsv00008086sd0000115F* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Dual Port Server Adapter + +pci:v00008086d0000105Fsv00008086sd0000125F* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Dual Port Server Adapter + +pci:v00008086d0000105Fsv00008086sd0000135F* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Dual Port Server Adapter + +pci:v00008086d00001060* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller + +pci:v00008086d00001060sv00008086sd00000060* + ID_MODEL_FROM_DATABASE=PRO/1000 PB Dual Port Server Connection + +pci:v00008086d00001060sv00008086sd00001060* + ID_MODEL_FROM_DATABASE=PRO/1000 PB Dual Port Server Connection + +pci:v00008086d00001064* + ID_MODEL_FROM_DATABASE=82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller + +pci:v00008086d00001064sv00001043sd000080F8* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00001065* + ID_MODEL_FROM_DATABASE=82562ET/EZ/GT/GZ - PRO/100 VE Ethernet Controller + +pci:v00008086d00001066* + ID_MODEL_FROM_DATABASE=82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller + +pci:v00008086d00001067* + ID_MODEL_FROM_DATABASE=82562 EM/EX/GX - PRO/100 VM Ethernet Controller + +pci:v00008086d00001068* + ID_MODEL_FROM_DATABASE=82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller Mobile + +pci:v00008086d00001069* + ID_MODEL_FROM_DATABASE=82562EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller Mobile + +pci:v00008086d0000106A* + ID_MODEL_FROM_DATABASE=82562G - PRO/100 VE (LOM) Ethernet Controller + +pci:v00008086d0000106B* + ID_MODEL_FROM_DATABASE=82562G - PRO/100 VE Ethernet Controller Mobile + +pci:v00008086d00001075* + ID_MODEL_FROM_DATABASE=82547GI Gigabit Ethernet Controller + +pci:v00008086d00001075sv00001028sd00000165* + ID_MODEL_FROM_DATABASE=PowerEdge 750 + +pci:v00008086d00001075sv00008086sd00000075* + ID_MODEL_FROM_DATABASE=PRO/1000 CT Network Connection + +pci:v00008086d00001075sv00008086sd00001075* + ID_MODEL_FROM_DATABASE=PRO/1000 CT Network Connection + +pci:v00008086d00001076* + ID_MODEL_FROM_DATABASE=82541GI Gigabit Ethernet Controller + +pci:v00008086d00001076sv00001028sd00000165* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00001028sd0000106D* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00008086sd00000076* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00008086sd00001076* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Connection + +pci:v00008086d00001076sv00008086sd00001176* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Desktop Adapter + +pci:v00008086d00001076sv00008086sd00001276* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Network Adapter + +pci:v00008086d00001077* + ID_MODEL_FROM_DATABASE=82541GI Gigabit Ethernet Controller + +pci:v00008086d00001077sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001077sv00008086sd00000077* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001077sv00008086sd00001077* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Mobile Connection + +pci:v00008086d00001078* + ID_MODEL_FROM_DATABASE=82541ER Gigabit Ethernet Controller + +pci:v00008086d00001078sv00008086sd00001078* + ID_MODEL_FROM_DATABASE=82541ER-based Network Connection + +pci:v00008086d00001079* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller + +pci:v00008086d00001079sv0000103Csd000012A6* + ID_MODEL_FROM_DATABASE=Dual Port 1000Base-T [A9900A] + +pci:v00008086d00001079sv0000103Csd000012CF* + ID_MODEL_FROM_DATABASE=Core Dual Port 1000Base-T [AB352A] + +pci:v00008086d00001079sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer Gigabit Ethernet + +pci:v00008086d00001079sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00001079sv00001FC1sd00000027* + ID_MODEL_FROM_DATABASE=Niagara 2261 Failover NIC + +pci:v00008086d00001079sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d00001079sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d00001079sv00008086sd00000079* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Network Connection + +pci:v00008086d00001079sv00008086sd00001079* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Network Connection + +pci:v00008086d00001079sv00008086sd00001179* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Server Adapter + +pci:v00008086d00001079sv00008086sd0000117A* + ID_MODEL_FROM_DATABASE=PRO/1000 MT Dual Port Server Adapter + +pci:v00008086d0000107A* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller + +pci:v00008086d0000107Asv0000103Csd000012A8* + ID_MODEL_FROM_DATABASE=Dual Port 1000base-SX [A9899A] + +pci:v00008086d0000107Asv00008086sd0000107A* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Dual Port Server Adapter + +pci:v00008086d0000107Asv00008086sd0000127A* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Dual Port Server Adapter + +pci:v00008086d0000107B* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller + +pci:v00008086d0000107Bsv00008086sd0000007B* + ID_MODEL_FROM_DATABASE=PRO/1000 MB Dual Port Server Connection + +pci:v00008086d0000107Bsv00008086sd0000107B* + ID_MODEL_FROM_DATABASE=PRO/1000 MB Dual Port Server Connection + +pci:v00008086d0000107C* + ID_MODEL_FROM_DATABASE=82541PI Gigabit Ethernet Controller + +pci:v00008086d0000107Csv00008086sd00001376* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Desktop Adapter + +pci:v00008086d0000107Csv00008086sd00001476* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Desktop Adapter + +pci:v00008086d0000107D* + ID_MODEL_FROM_DATABASE=82572EI Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000107Dsv00008086sd00001082* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Server Adapter + +pci:v00008086d0000107Dsv00008086sd00001084* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Server Adapter + +pci:v00008086d0000107Dsv00008086sd00001092* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Server Adapter + +pci:v00008086d0000107E* + ID_MODEL_FROM_DATABASE=82572EI Gigabit Ethernet Controller (Fiber) + +pci:v00008086d0000107Esv00008086sd00001084* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Server Adapter + +pci:v00008086d0000107Esv00008086sd00001085* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Server Adapter + +pci:v00008086d0000107Esv00008086sd00001094* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Server Adapter + +pci:v00008086d0000107F* + ID_MODEL_FROM_DATABASE=82572EI Gigabit Ethernet Controller + +pci:v00008086d00001080* + ID_MODEL_FROM_DATABASE=FA82537EP 56K V.92 Data/Fax Modem PCI + +pci:v00008086d00001081* + ID_MODEL_FROM_DATABASE=631xESB/632xESB LAN Controller Copper + +pci:v00008086d00001082* + ID_MODEL_FROM_DATABASE=631xESB/632xESB LAN Controller fiber + +pci:v00008086d00001083* + ID_MODEL_FROM_DATABASE=631xESB/632xESB LAN Controller SERDES + +pci:v00008086d00001084* + ID_MODEL_FROM_DATABASE=631xESB/632xESB IDE Redirection + +pci:v00008086d00001085* + ID_MODEL_FROM_DATABASE=631xESB/632xESB Serial Port Redirection + +pci:v00008086d00001086* + ID_MODEL_FROM_DATABASE=631xESB/632xESB IPMI/KCS0 + +pci:v00008086d00001087* + ID_MODEL_FROM_DATABASE=631xESB/632xESB UHCI Redirection + +pci:v00008086d00001089* + ID_MODEL_FROM_DATABASE=631xESB/632xESB BT + +pci:v00008086d0000108A* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller + +pci:v00008086d0000108Asv00008086sd0000108A* + ID_MODEL_FROM_DATABASE=PRO/1000 P Dual Port Server Adapter + +pci:v00008086d0000108Asv00008086sd0000118A* + ID_MODEL_FROM_DATABASE=PRO/1000 P Dual Port Server Adapter + +pci:v00008086d0000108B* + ID_MODEL_FROM_DATABASE=82573V Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000108Bsv00001462sd0000176C* + ID_MODEL_FROM_DATABASE=on board on MSI 945P - NEO (MS-7176) + +pci:v00008086d0000108C* + ID_MODEL_FROM_DATABASE=82573E Gigabit Ethernet Controller (Copper) + +pci:v00008086d0000108E* + ID_MODEL_FROM_DATABASE=82573E KCS (Active Management) + +pci:v00008086d0000108F* + ID_MODEL_FROM_DATABASE=Active Management Technology - SOL + +pci:v00008086d00001091* + ID_MODEL_FROM_DATABASE=PRO/100 VM Network Connection + +pci:v00008086d00001092* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001093* + ID_MODEL_FROM_DATABASE=PRO/100 VM Network Connection + +pci:v00008086d00001094* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001095* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00001096* + ID_MODEL_FROM_DATABASE=80003ES2LAN Gigabit Ethernet Controller (Copper) + +pci:v00008086d00001096sv000015D9sd00001096* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001096sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00001096sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00001097* + ID_MODEL_FROM_DATABASE=631xESB/632xESB DPT LAN Controller (Fiber) + +pci:v00008086d00001098* + ID_MODEL_FROM_DATABASE=80003ES2LAN Gigabit Ethernet Controller (Serdes) + +pci:v00008086d00001099* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller (Copper) + +pci:v00008086d00001099sv00008086sd00001099* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Quad Port Server Adapter + +pci:v00008086d0000109A* + ID_MODEL_FROM_DATABASE=82573L Gigabit Ethernet Controller + +pci:v00008086d0000109Asv00001179sd0000FF10* + ID_MODEL_FROM_DATABASE=PRO/1000 PL + +pci:v00008086d0000109Asv000017AAsd00002001* + ID_MODEL_FROM_DATABASE=ThinkPad T60 + +pci:v00008086d0000109Asv000017AAsd0000207E* + ID_MODEL_FROM_DATABASE=ThinkPad X60s + +pci:v00008086d0000109Asv00008086sd0000109A* + ID_MODEL_FROM_DATABASE=PRO/1000 PL Network Connection + +pci:v00008086d0000109Asv00008086sd0000309C* + ID_MODEL_FROM_DATABASE=Desktop Board D945GTP + +pci:v00008086d0000109Asv00008086sd000030A5* + ID_MODEL_FROM_DATABASE=Desktop Board D975XBX + +pci:v00008086d0000109B* + ID_MODEL_FROM_DATABASE=82546GB PRO/1000 GF Quad Port Server Adapter + +pci:v00008086d0000109E* + ID_MODEL_FROM_DATABASE=82597EX 10GbE Ethernet Controller + +pci:v00008086d0000109Esv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=PRO/10GbE CX4 Server Adapter + +pci:v00008086d0000109Esv00008086sd0000A11F* + ID_MODEL_FROM_DATABASE=PRO/10GbE CX4 Server Adapter + +pci:v00008086d000010A0* + ID_MODEL_FROM_DATABASE=82571EB PRO/1000 AT Quad Port Bypass Adapter + +pci:v00008086d000010A1* + ID_MODEL_FROM_DATABASE=82571EB PRO/1000 AF Quad Port Bypass Adapter + +pci:v00008086d000010A4* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller + +pci:v00008086d000010A4sv00008086sd000010A4* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Quad Port Server Adapter + +pci:v00008086d000010A4sv00008086sd000011A4* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Quad Port Server Adapter + +pci:v00008086d000010A5* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller (Fiber) + +pci:v00008086d000010A5sv00008086sd000010A5* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Quad Port Server Adapter + +pci:v00008086d000010A5sv00008086sd000010A6* + ID_MODEL_FROM_DATABASE=PRO/1000 PF Quad Port Server Adapter + +pci:v00008086d000010A6* + ID_MODEL_FROM_DATABASE=82599EB 10-Gigabit Dummy Function + +pci:v00008086d000010A7* + ID_MODEL_FROM_DATABASE=82575EB Gigabit Network Connection + +pci:v00008086d000010A7sv00008086sd000010A8* + ID_MODEL_FROM_DATABASE=82575EB Gigabit Riser Card + +pci:v00008086d000010A9* + ID_MODEL_FROM_DATABASE=82575EB Gigabit Backplane Connection + +pci:v00008086d000010B0* + ID_MODEL_FROM_DATABASE=82573L PRO/1000 PL Network Connection + +pci:v00008086d000010B2* + ID_MODEL_FROM_DATABASE=82573V PRO/1000 PM Network Connection + +pci:v00008086d000010B3* + ID_MODEL_FROM_DATABASE=82573E PRO/1000 PM Network Connection + +pci:v00008086d000010B4* + ID_MODEL_FROM_DATABASE=82573L PRO/1000 PL Network Connection + +pci:v00008086d000010B5* + ID_MODEL_FROM_DATABASE=82546GB Gigabit Ethernet Controller (Copper) + +pci:v00008086d000010B5sv0000103Csd00003109* + ID_MODEL_FROM_DATABASE=NC340T PCI-X Quad-port Gigabit Server Adapter + +pci:v00008086d000010B5sv00008086sd00001099* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Quad Port Server Adapter + +pci:v00008086d000010B5sv00008086sd00001199* + ID_MODEL_FROM_DATABASE=PRO/1000 GT Quad Port Server Adapter + +pci:v00008086d000010B6* + ID_MODEL_FROM_DATABASE=82598 10GbE PCI-Express Ethernet Controller + +pci:v00008086d000010B9* + ID_MODEL_FROM_DATABASE=82572EI Gigabit Ethernet Controller (Copper) + +pci:v00008086d000010B9sv0000103Csd0000704A* + ID_MODEL_FROM_DATABASE=HP 110T PCIe Gigabit Server Adapter + +pci:v00008086d000010B9sv00008086sd00001083* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Desktop Adapter + +pci:v00008086d000010B9sv00008086sd00001093* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Desktop Adapter + +pci:v00008086d000010BA* + ID_MODEL_FROM_DATABASE=80003ES2LAN Gigabit Ethernet Controller (Copper) + +pci:v00008086d000010BB* + ID_MODEL_FROM_DATABASE=80003ES2LAN Gigabit Ethernet Controller (Serdes) + +pci:v00008086d000010BC* + ID_MODEL_FROM_DATABASE=82571EB Gigabit Ethernet Controller (Copper) + +pci:v00008086d000010BCsv0000103Csd0000704B* + ID_MODEL_FROM_DATABASE=NC364T PCI Express Quad Port Gigabit Server Adapter + +pci:v00008086d000010BCsv0000108Esd000011BC* + ID_MODEL_FROM_DATABASE=x4 PCI-Express Quad Gigabit Ethernet UTP Low Profile Adapter + +pci:v00008086d000010BCsv00008086sd000010BC* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Quad Port LP Server Adapter + +pci:v00008086d000010BCsv00008086sd000011BC* + ID_MODEL_FROM_DATABASE=PRO/1000 PT Quad Port LP Server Adapter + +pci:v00008086d000010BD* + ID_MODEL_FROM_DATABASE=82566DM-2 Gigabit Network Connection + +pci:v00008086d000010BDsv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000010BF* + ID_MODEL_FROM_DATABASE=82567LF Gigabit Network Connection + +pci:v00008086d000010C0* + ID_MODEL_FROM_DATABASE=82562V-2 10/100 Network Connection + +pci:v00008086d000010C0sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d000010C2* + ID_MODEL_FROM_DATABASE=82562G-2 10/100 Network Connection + +pci:v00008086d000010C3* + ID_MODEL_FROM_DATABASE=82562GT-2 10/100 Network Connection + +pci:v00008086d000010C4* + ID_MODEL_FROM_DATABASE=82562GT 10/100 Network Connection + +pci:v00008086d000010C5* + ID_MODEL_FROM_DATABASE=82562G 10/100 Network Connection + +pci:v00008086d000010C6* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AF Dual Port Network Connection + +pci:v00008086d000010C6sv00008086sd0000A05F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Dual Port Server Adapter + +pci:v00008086d000010C6sv00008086sd0000A15F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Dual Port Server Adapter + +pci:v00008086d000010C7* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AF Network Connection + +pci:v00008086d000010C7sv00001014sd0000037F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Server Adapter + +pci:v00008086d000010C7sv00001014sd00000380* + ID_MODEL_FROM_DATABASE=10-Gigabit XF LR Server Adapter + +pci:v00008086d000010C7sv00008086sd0000A05F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Server Adapter + +pci:v00008086d000010C7sv00008086sd0000A15F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Server Adapter + +pci:v00008086d000010C7sv00008086sd0000A16F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF SR Server Adapter + +pci:v00008086d000010C8* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT Network Connection + +pci:v00008086d000010C8sv00008086sd0000A10C* + ID_MODEL_FROM_DATABASE=10-Gigabit AT Server Adapter + +pci:v00008086d000010C8sv00008086sd0000A11C* + ID_MODEL_FROM_DATABASE=10-Gigabit AT Server Adapter + +pci:v00008086d000010C8sv00008086sd0000A12C* + ID_MODEL_FROM_DATABASE=10-Gigabit AT Server Adapter + +pci:v00008086d000010C9* + ID_MODEL_FROM_DATABASE=82576 Gigabit Network Connection + +pci:v00008086d000010C9sv0000103Csd000031EF* + ID_MODEL_FROM_DATABASE=NC362i Integrated Dual port Gigabit Server Adapter + +pci:v00008086d000010C9sv0000103Csd0000323F* + ID_MODEL_FROM_DATABASE=NC362i Integrated Dual port Gigabit Server Adapter + +pci:v00008086d000010C9sv000010A9sd00008028* + ID_MODEL_FROM_DATABASE=UV-BaseIO dual-port GbE + +pci:v00008086d000010C9sv000013A3sd00000037* + ID_MODEL_FROM_DATABASE=DS4100 Secure Multi-Gigabit Server Adapter with Compression + +pci:v00008086d000010C9sv000015D9sd0000A811* + ID_MODEL_FROM_DATABASE=H8DGU + +pci:v00008086d000010C9sv00008086sd0000A01C* + ID_MODEL_FROM_DATABASE=Gigabit ET Dual Port Server Adapter + +pci:v00008086d000010C9sv00008086sd0000A03C* + ID_MODEL_FROM_DATABASE=Gigabit ET Dual Port Server Adapter + +pci:v00008086d000010C9sv00008086sd0000A04C* + ID_MODEL_FROM_DATABASE=Gigabit ET Dual Port Server Adapter + +pci:v00008086d000010CA* + ID_MODEL_FROM_DATABASE=82576 Virtual Function + +pci:v00008086d000010CB* + ID_MODEL_FROM_DATABASE=82567V Gigabit Network Connection + +pci:v00008086d000010CC* + ID_MODEL_FROM_DATABASE=82567LM-2 Gigabit Network Connection + +pci:v00008086d000010CD* + ID_MODEL_FROM_DATABASE=82567LF-2 Gigabit Network Connection + +pci:v00008086d000010CE* + ID_MODEL_FROM_DATABASE=82567V-2 Gigabit Network Connection + +pci:v00008086d000010D3* + ID_MODEL_FROM_DATABASE=82574L Gigabit Network Connection + +pci:v00008086d000010D3sv0000103Csd00003250* + ID_MODEL_FROM_DATABASE=NC112T PCI Express single Port Gigabit Server Adapter + +pci:v00008086d000010D3sv000010A9sd00008029* + ID_MODEL_FROM_DATABASE=Prism XL Single Port Gigabit Ethernet + +pci:v00008086d000010D3sv000015D9sd0000060A* + ID_MODEL_FROM_DATABASE=X7SPA-H/X7SPA-HF Motherboard + +pci:v00008086d000010D3sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Gigabit CT2 Desktop Adapter + +pci:v00008086d000010D3sv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=Gigabit CT Desktop Adapter + +pci:v00008086d000010D3sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d000010D3sv0000E4BFsd000050C2* + ID_MODEL_FROM_DATABASE=PC2-LIMBO + +pci:v00008086d000010D4* + ID_MODEL_FROM_DATABASE=Matrox Concord GE (customized Intel 82574) + +pci:v00008086d000010D5* + ID_MODEL_FROM_DATABASE=82571PT Gigabit PT Quad Port Server ExpressModule + +pci:v00008086d000010D6* + ID_MODEL_FROM_DATABASE=82575GB Gigabit Network Connection + +pci:v00008086d000010D6sv00008086sd000010D6* + ID_MODEL_FROM_DATABASE=Gigabit VT Quad Port Server Adapter + +pci:v00008086d000010D6sv00008086sd0000145A* + ID_MODEL_FROM_DATABASE=Gigabit VT Quad Port Server Adapter + +pci:v00008086d000010D6sv00008086sd0000147A* + ID_MODEL_FROM_DATABASE=Gigabit VT Quad Port Server Adapter + +pci:v00008086d000010D8* + ID_MODEL_FROM_DATABASE=82599EB 10 Gigabit Unprogrammed + +pci:v00008086d000010D9* + ID_MODEL_FROM_DATABASE=82571EB Dual Port Gigabit Mezzanine Adapter + +pci:v00008086d000010D9sv0000103Csd00001716* + ID_MODEL_FROM_DATABASE=NC360m Dual Port 1GbE BL-c Adapter + +pci:v00008086d000010DA* + ID_MODEL_FROM_DATABASE=82571EB Quad Port Gigabit Mezzanine Adapter + +pci:v00008086d000010DAsv0000103Csd00001717* + ID_MODEL_FROM_DATABASE=NC364m Quad Port 1GbE BL-c Adapter + +pci:v00008086d000010DB* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit Dual Port Network Connection + +pci:v00008086d000010DD* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT CX4 Network Connection + +pci:v00008086d000010DE* + ID_MODEL_FROM_DATABASE=82567LM-3 Gigabit Network Connection + +pci:v00008086d000010DF* + ID_MODEL_FROM_DATABASE=82567LF-3 Gigabit Network Connection + +pci:v00008086d000010E1* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AF Dual Port Network Connection + +pci:v00008086d000010E1sv00008086sd0000A15F* + ID_MODEL_FROM_DATABASE=10-Gigabit SR Dual Port Express Module + +pci:v00008086d000010E2* + ID_MODEL_FROM_DATABASE=82575GB Gigabit Network Connection + +pci:v00008086d000010E2sv00008086sd000010E2* + ID_MODEL_FROM_DATABASE=Gigabit VT Quad Port Server Adapter + +pci:v00008086d000010E5* + ID_MODEL_FROM_DATABASE=82567LM-4 Gigabit Network Connection + +pci:v00008086d000010E6* + ID_MODEL_FROM_DATABASE=82576 Gigabit Network Connection + +pci:v00008086d000010E6sv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=Gigabit EF Dual Port Server Adapter + +pci:v00008086d000010E6sv00008086sd0000A02F* + ID_MODEL_FROM_DATABASE=Gigabit EF Dual Port Server Adapter + +pci:v00008086d000010E7* + ID_MODEL_FROM_DATABASE=82576 Gigabit Network Connection + +pci:v00008086d000010E7sv0000103Csd000031FF* + ID_MODEL_FROM_DATABASE=NC362i Integrated Dual Port BL-c Gigabit Server Adapter + +pci:v00008086d000010E8* + ID_MODEL_FROM_DATABASE=82576 Gigabit Network Connection + +pci:v00008086d000010E8sv00008086sd0000A02B* + ID_MODEL_FROM_DATABASE=Gigabit ET Quad Port Server Adapter + +pci:v00008086d000010E8sv00008086sd0000A02C* + ID_MODEL_FROM_DATABASE=Gigabit ET Quad Port Server Adapter + +pci:v00008086d000010EA* + ID_MODEL_FROM_DATABASE=82577LM Gigabit Network Connection + +pci:v00008086d000010EAsv00001028sd0000040A* + ID_MODEL_FROM_DATABASE=Latitude E6410 + +pci:v00008086d000010EAsv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d000010EAsv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d000010EB* + ID_MODEL_FROM_DATABASE=82577LC Gigabit Network Connection + +pci:v00008086d000010EC* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT CX4 Network Connection + +pci:v00008086d000010ECsv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=10-Gigabit CX4 Dual Port Server Adapter + +pci:v00008086d000010ECsv00008086sd0000A11F* + ID_MODEL_FROM_DATABASE=10-Gigabit CX4 Dual Port Server Adapter + +pci:v00008086d000010ED* + ID_MODEL_FROM_DATABASE=82599 Ethernet Controller Virtual Function + +pci:v00008086d000010EF* + ID_MODEL_FROM_DATABASE=82578DM Gigabit Network Connection + +pci:v00008086d000010EFsv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d000010F0* + ID_MODEL_FROM_DATABASE=82578DC Gigabit Network Connection + +pci:v00008086d000010F1* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AF Dual Port Network Connection + +pci:v00008086d000010F1sv00008086sd0000A20F* + ID_MODEL_FROM_DATABASE=10-Gigabit AF DA Dual Port Server Adapter + +pci:v00008086d000010F1sv00008086sd0000A21F* + ID_MODEL_FROM_DATABASE=10-Gigabit AF DA Dual Port Server Adapter + +pci:v00008086d000010F4* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AF Network Connection + +pci:v00008086d000010F4sv00008086sd0000106F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF LR Server Adapter + +pci:v00008086d000010F4sv00008086sd0000A06F* + ID_MODEL_FROM_DATABASE=10-Gigabit XF LR Server Adapter + +pci:v00008086d000010F5* + ID_MODEL_FROM_DATABASE=82567LM Gigabit Network Connection + +pci:v00008086d000010F6* + ID_MODEL_FROM_DATABASE=82574L Gigabit Network Connection + +pci:v00008086d000010F7* + ID_MODEL_FROM_DATABASE=10 Gigabit BR KX4 Dual Port Network Connection + +pci:v00008086d000010F7sv0000108Esd00007B12* + ID_MODEL_FROM_DATABASE=Sun Dual 10GbE PCIe 2.0 FEM + +pci:v00008086d000010F7sv00008086sd0000000D* + ID_MODEL_FROM_DATABASE=Ethernet Mezzanine Adapter X520-KX4-2 + +pci:v00008086d000010F8* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Backplane Connection + +pci:v00008086d000010F8sv00001028sd00001F63* + ID_MODEL_FROM_DATABASE=10GbE 2P X520k bNDC + +pci:v00008086d000010F8sv0000103Csd000017D2* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 560M Adapter + +pci:v00008086d000010F8sv0000103Csd000018D0* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 560FLB Adapter + +pci:v00008086d000010F8sv00008086sd0000000C* + ID_MODEL_FROM_DATABASE=Ethernet X520 10GbE Dual Port KX4-KR Mezz + +pci:v00008086d000010F9* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Network Connection + +pci:v00008086d000010FB* + ID_MODEL_FROM_DATABASE=82599ES 10-Gigabit SFI/SFP+ Network Connection + +pci:v00008086d000010FBsv00001028sd00001F72* + ID_MODEL_FROM_DATABASE=Ethernet 10G 4P X520/I350 rNDC + +pci:v00008086d000010FBsv0000103Csd000017D0* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 560FLR-SFP+ Adapter + +pci:v00008086d000010FBsv0000103Csd000017D2* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 560M Adapter + +pci:v00008086d000010FBsv0000103Csd000017D3* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 560SFP+ Adapter + +pci:v00008086d000010FBsv0000103Csd0000211B* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 1-port P560FLR-SFP+ Adapter + +pci:v00008086d000010FBsv0000103Csd00002147* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 1-port 561i Adapter + +pci:v00008086d000010FBsv0000103Csd00002159* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 562i Adapter + +pci:v00008086d000010FBsv0000108Esd00007B11* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-2 + +pci:v00008086d000010FBsv00001734sd000011A9* + ID_MODEL_FROM_DATABASE=10 Gigabit Dual Port Network Connection + +pci:v00008086d000010FBsv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-DA2 + +pci:v00008086d000010FBsv00008086sd00000003* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-2 + +pci:v00008086d000010FBsv00008086sd00000006* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-1 + +pci:v00008086d000010FBsv00008086sd00000008* + ID_MODEL_FROM_DATABASE=Ethernet OCP Server Adapter X520-2 + +pci:v00008086d000010FBsv00008086sd0000000A* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-1 + +pci:v00008086d000010FBsv00008086sd0000000C* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-2 + +pci:v00008086d000010FBsv00008086sd00007A11* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-2 + +pci:v00008086d000010FBsv00008086sd00007A12* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-2 + +pci:v00008086d000010FC* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Network Connection + +pci:v00008086d000010FE* + ID_MODEL_FROM_DATABASE=82552 10/100 Network Connection + +pci:v00008086d00001107* + ID_MODEL_FROM_DATABASE=PRO/1000 MF Server Adapter (LX) + +pci:v00008086d00001130* + ID_MODEL_FROM_DATABASE=82815 815 Chipset Host Bridge and Memory Controller Hub + +pci:v00008086d00001130sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00001130sv00001043sd00008027* + ID_MODEL_FROM_DATABASE=TUSL2-C Mainboard + +pci:v00008086d00001130sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00001130sv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 mainboard + +pci:v00008086d00001130sv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d00001131* + ID_MODEL_FROM_DATABASE=82815 815 Chipset AGP Bridge + +pci:v00008086d00001132* + ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) + +pci:v00008086d00001132sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00001132sv0000103Csd00002001* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d00001132sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00001132sv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 Mainboard + +pci:v00008086d00001132sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=D815EEA Motherboard + +pci:v00008086d00001132sv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d00001161* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub Advanced Programmable Interrupt Controller + +pci:v00008086d00001161sv00008086sd00001161* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub APIC + +pci:v00008086d00001162* + ID_MODEL_FROM_DATABASE=Xscale 80200 Big Endian Companion Chip + +pci:v00008086d00001200* + ID_MODEL_FROM_DATABASE=IXP1200 Network Processor + +pci:v00008086d00001200sv0000172Asd00000000* + ID_MODEL_FROM_DATABASE=AEP SSL Accelerator + +pci:v00008086d00001209* + ID_MODEL_FROM_DATABASE=8255xER/82551IT Fast Ethernet Controller + +pci:v00008086d00001209sv0000140Bsd00000610* + ID_MODEL_FROM_DATABASE=PMC610 quad Ethernet board + +pci:v00008086d00001209sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00008086d00001209sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v00008086d00001209sv00004C53sd00001070* + ID_MODEL_FROM_DATABASE=PC6 mainboard + +pci:v00008086d00001221* + ID_MODEL_FROM_DATABASE=82092AA PCI to PCMCIA Bridge + +pci:v00008086d00001222* + ID_MODEL_FROM_DATABASE=82092AA IDE Controller + +pci:v00008086d00001223* + ID_MODEL_FROM_DATABASE=SAA7116 + +pci:v00008086d00001225* + ID_MODEL_FROM_DATABASE=82452KX/GX [Orion] + +pci:v00008086d00001226* + ID_MODEL_FROM_DATABASE=82596 PRO/10 PCI + +pci:v00008086d00001227* + ID_MODEL_FROM_DATABASE=82865 EtherExpress PRO/100A + +pci:v00008086d00001228* + ID_MODEL_FROM_DATABASE=82556 EtherExpress PRO/100 Smart + +pci:v00008086d00001229* + ID_MODEL_FROM_DATABASE=82557/8/9/0/1 Ethernet Pro 100 + +pci:v00008086d00001229sv00000E11sd00003001* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003002* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003003* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003004* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003005* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003006* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd00003007* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN* + +pci:v00008086d00001229sv00000E11sd0000B01E* + ID_MODEL_FROM_DATABASE=NC3120 Fast Ethernet NIC + +pci:v00008086d00001229sv00000E11sd0000B01F* + ID_MODEL_FROM_DATABASE=NC3122 Fast Ethernet NIC (dual port) + +pci:v00008086d00001229sv00000E11sd0000B02F* + ID_MODEL_FROM_DATABASE=NC1120 Ethernet NIC + +pci:v00008086d00001229sv00000E11sd0000B04A* + ID_MODEL_FROM_DATABASE=Netelligent 10/100TX NIC with Wake on LAN + +pci:v00008086d00001229sv00000E11sd0000B0C6* + ID_MODEL_FROM_DATABASE=NC3161 Fast Ethernet NIC (embedded, WOL) + +pci:v00008086d00001229sv00000E11sd0000B0C7* + ID_MODEL_FROM_DATABASE=NC3160 Fast Ethernet NIC (embedded) + +pci:v00008086d00001229sv00000E11sd0000B0D7* + ID_MODEL_FROM_DATABASE=NC3121 Fast Ethernet NIC (WOL) + +pci:v00008086d00001229sv00000E11sd0000B0DD* + ID_MODEL_FROM_DATABASE=NC3131 Fast Ethernet NIC (dual port) + +pci:v00008086d00001229sv00000E11sd0000B0DE* + ID_MODEL_FROM_DATABASE=NC3132 Fast Ethernet Module (dual port) + +pci:v00008086d00001229sv00000E11sd0000B0E1* + ID_MODEL_FROM_DATABASE=NC3133 Fast Ethernet Module (100-FX) + +pci:v00008086d00001229sv00000E11sd0000B134* + ID_MODEL_FROM_DATABASE=NC3163 Fast Ethernet NIC (embedded, WOL) + +pci:v00008086d00001229sv00000E11sd0000B13C* + ID_MODEL_FROM_DATABASE=NC3162 Fast Ethernet NIC (embedded) + +pci:v00008086d00001229sv00000E11sd0000B144* + ID_MODEL_FROM_DATABASE=NC3123 Fast Ethernet NIC (WOL) + +pci:v00008086d00001229sv00000E11sd0000B163* + ID_MODEL_FROM_DATABASE=NC3134 Fast Ethernet NIC (dual port) + +pci:v00008086d00001229sv00000E11sd0000B164* + ID_MODEL_FROM_DATABASE=NC3135 Fast Ethernet Upgrade Module (dual port) + +pci:v00008086d00001229sv00000E11sd0000B1A4* + ID_MODEL_FROM_DATABASE=NC7131 Gigabit Server Adapter + +pci:v00008086d00001229sv00001014sd0000005C* + ID_MODEL_FROM_DATABASE=82558B Ethernet Pro 10/100 + +pci:v00008086d00001229sv00001014sd000001BC* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LAN On Motherboard + +pci:v00008086d00001229sv00001014sd000001F1* + ID_MODEL_FROM_DATABASE=10/100 Ethernet Server Adapter + +pci:v00008086d00001229sv00001014sd000001F2* + ID_MODEL_FROM_DATABASE=10/100 Ethernet Server Adapter + +pci:v00008086d00001229sv00001014sd00000207* + ID_MODEL_FROM_DATABASE=Ethernet Pro/100 S + +pci:v00008086d00001229sv00001014sd00000232* + ID_MODEL_FROM_DATABASE=10/100 Dual Port Server Adapter + +pci:v00008086d00001229sv00001014sd0000023A* + ID_MODEL_FROM_DATABASE=ThinkPad R30 + +pci:v00008086d00001229sv00001014sd0000105C* + ID_MODEL_FROM_DATABASE=Netfinity 10/100 + +pci:v00008086d00001229sv00001014sd00002205* + ID_MODEL_FROM_DATABASE=ThinkPad A22p + +pci:v00008086d00001229sv00001014sd0000305C* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Management Adapter + +pci:v00008086d00001229sv00001014sd0000405C* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Adapter with Alert on LAN + +pci:v00008086d00001229sv00001014sd0000505C* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Secure Management Adapter + +pci:v00008086d00001229sv00001014sd0000605C* + ID_MODEL_FROM_DATABASE=10/100 EtherJet Secure Management Adapter + +pci:v00008086d00001229sv00001014sd0000705C* + ID_MODEL_FROM_DATABASE=10/100 Netfinity 10/100 Ethernet Security Adapter + +pci:v00008086d00001229sv00001014sd0000805C* + ID_MODEL_FROM_DATABASE=10/100 Netfinity 10/100 Ethernet Security Adapter + +pci:v00008086d00001229sv00001028sd0000009B* + ID_MODEL_FROM_DATABASE=10/100 Ethernet Server Adapter + +pci:v00008086d00001229sv00001028sd000000CE* + ID_MODEL_FROM_DATABASE=10/100 Ethernet Server Adapter + +pci:v00008086d00001229sv00001033sd00008000* + ID_MODEL_FROM_DATABASE=PC-9821X-B06 + +pci:v00008086d00001229sv00001033sd00008016* + ID_MODEL_FROM_DATABASE=PK-UG-X006 + +pci:v00008086d00001229sv00001033sd0000801F* + ID_MODEL_FROM_DATABASE=PK-UG-X006 + +pci:v00008086d00001229sv00001033sd00008026* + ID_MODEL_FROM_DATABASE=PK-UG-X006 + +pci:v00008086d00001229sv00001033sd00008063* + ID_MODEL_FROM_DATABASE=82559-based Fast Ethernet Adapter + +pci:v00008086d00001229sv00001033sd00008064* + ID_MODEL_FROM_DATABASE=82559-based Fast Ethernet Adapter + +pci:v00008086d00001229sv0000103Csd000010C0* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd000010C3* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd000010CA* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd000010CB* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd000010E3* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd000010E4* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000103Csd00001200* + ID_MODEL_FROM_DATABASE=NetServer 10/100TX + +pci:v00008086d00001229sv0000108Esd000010CF* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100(B) + +pci:v00008086d00001229sv000010C3sd00001100* + ID_MODEL_FROM_DATABASE=SmartEther100 SC1100 + +pci:v00008086d00001229sv000010CFsd00001115* + ID_MODEL_FROM_DATABASE=8255x-based Ethernet Adapter (10/100) + +pci:v00008086d00001229sv000010CFsd00001143* + ID_MODEL_FROM_DATABASE=8255x-based Ethernet Adapter (10/100) + +pci:v00008086d00001229sv0000110Asd0000008B* + ID_MODEL_FROM_DATABASE=82551QM Fast Ethernet Multifuction PCI/CardBus Controller + +pci:v00008086d00001229sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard ethernet ETH2 + +pci:v00008086d00001229sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=8255x-based Ethernet Adapter (10/100) + +pci:v00008086d00001229sv00001179sd00000002* + ID_MODEL_FROM_DATABASE=PCI FastEther LAN on Docker + +pci:v00008086d00001229sv00001179sd00000003* + ID_MODEL_FROM_DATABASE=8255x-based Fast Ethernet + +pci:v00008086d00001229sv00001259sd00002560* + ID_MODEL_FROM_DATABASE=AT-2560 100 + +pci:v00008086d00001229sv00001259sd00002561* + ID_MODEL_FROM_DATABASE=AT-2560 100 FX Ethernet Adapter + +pci:v00008086d00001229sv00001266sd00000001* + ID_MODEL_FROM_DATABASE=NE10/100 Adapter + +pci:v00008086d00001229sv000013E9sd00001000* + ID_MODEL_FROM_DATABASE=6221L-4U + +pci:v00008086d00001229sv0000144Dsd00002501* + ID_MODEL_FROM_DATABASE=SEM-2000 MiniPCI LAN Adapter + +pci:v00008086d00001229sv0000144Dsd00002502* + ID_MODEL_FROM_DATABASE=SEM-2100IL MiniPCI LAN Adapter + +pci:v00008086d00001229sv00001668sd00001100* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem) + +pci:v00008086d00001229sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00001229sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00001229sv00004C53sd00001080* + ID_MODEL_FROM_DATABASE=CT8 mainboard + +pci:v00008086d00001229sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d00001229sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100B (TX) + +pci:v00008086d00001229sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100B (T4) + +pci:v00008086d00001229sv00008086sd00000003* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/10+ + +pci:v00008086d00001229sv00008086sd00000004* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 WfM + +pci:v00008086d00001229sv00008086sd00000005* + ID_MODEL_FROM_DATABASE=82557 10/100 + +pci:v00008086d00001229sv00008086sd00000006* + ID_MODEL_FROM_DATABASE=82557 10/100 with Wake on LAN + +pci:v00008086d00001229sv00008086sd00000007* + ID_MODEL_FROM_DATABASE=82558 10/100 Adapter + +pci:v00008086d00001229sv00008086sd00000008* + ID_MODEL_FROM_DATABASE=82558 10/100 with Wake on LAN + +pci:v00008086d00001229sv00008086sd00000009* + ID_MODEL_FROM_DATABASE=82558B PRO/100+ PCI (TP) + +pci:v00008086d00001229sv00008086sd0000000A* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Management Adapter + +pci:v00008086d00001229sv00008086sd0000000B* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ + +pci:v00008086d00001229sv00008086sd0000000C* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Management Adapter + +pci:v00008086d00001229sv00008086sd0000000D* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Alert On LAN II* Adapter + +pci:v00008086d00001229sv00008086sd0000000E* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Management Adapter with Alert On LAN* + +pci:v00008086d00001229sv00008086sd0000000F* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Desktop Adapter + +pci:v00008086d00001229sv00008086sd00000010* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Management Adapter + +pci:v00008086d00001229sv00008086sd00000011* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Management Adapter + +pci:v00008086d00001229sv00008086sd00000012* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Advanced Management Adapter (D) + +pci:v00008086d00001229sv00008086sd00000013* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Advanced Management Adapter (E) + +pci:v00008086d00001229sv00008086sd00000030* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Management Adapter with Alert On LAN* GC + +pci:v00008086d00001229sv00008086sd00000031* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Desktop Adapter + +pci:v00008086d00001229sv00008086sd00000040* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Desktop Adapter + +pci:v00008086d00001229sv00008086sd00000041* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Desktop Adapter + +pci:v00008086d00001229sv00008086sd00000042* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Desktop Adapter + +pci:v00008086d00001229sv00008086sd00000050* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Desktop Adapter + +pci:v00008086d00001229sv00008086sd00001009* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Server Adapter + +pci:v00008086d00001229sv00008086sd0000100C* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Server Adapter (PILA8470B) + +pci:v00008086d00001229sv00008086sd00001012* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Server Adapter (D) + +pci:v00008086d00001229sv00008086sd00001013* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Server Adapter (E) + +pci:v00008086d00001229sv00008086sd00001015* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Dual Port Server Adapter + +pci:v00008086d00001229sv00008086sd00001017* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Dual Port Server Adapter + +pci:v00008086d00001229sv00008086sd00001030* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server + +pci:v00008086d00001229sv00008086sd00001040* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Server Adapter + +pci:v00008086d00001229sv00008086sd00001041* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Server Adapter + +pci:v00008086d00001229sv00008086sd00001042* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Server Adapter + +pci:v00008086d00001229sv00008086sd00001050* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Server Adapter + +pci:v00008086d00001229sv00008086sd00001051* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Server Adapter + +pci:v00008086d00001229sv00008086sd00001052* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Server Adapter + +pci:v00008086d00001229sv00008086sd000010F0* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ Dual Port Adapter + +pci:v00008086d00001229sv00008086sd00001229* + ID_MODEL_FROM_DATABASE=82557/8/9 [Ethernet Pro 100] + +pci:v00008086d00001229sv00008086sd00002009* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Mobile Adapter + +pci:v00008086d00001229sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Cardbus + +pci:v00008086d00001229sv00008086sd0000200E* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 LAN+V90 Cardbus Modem + +pci:v00008086d00001229sv00008086sd0000200F* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SR Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002010* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002013* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SR Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002016* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002017* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Combo Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002018* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SR Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002019* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SR Combo Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002101* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002102* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002103* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002104* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002105* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002106* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Adapter + +pci:v00008086d00001229sv00008086sd00002107* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Network Connection + +pci:v00008086d00001229sv00008086sd00002108* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Network Connection + +pci:v00008086d00001229sv00008086sd00002200* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002201* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002202* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002203* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002204* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002205* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002206* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002207* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 SP Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002208* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Combo Adapter + +pci:v00008086d00001229sv00008086sd00002402* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002407* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002408* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002409* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd0000240F* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002410* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002411* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002412* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00002413* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100+ MiniPCI + +pci:v00008086d00001229sv00008086sd00003000* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LAN on Motherboard + +pci:v00008086d00001229sv00008086sd00003001* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Basic Alert on LAN* + +pci:v00008086d00001229sv00008086sd00003002* + ID_MODEL_FROM_DATABASE=82559 Fast Ethernet LOM with Alert on LAN II* + +pci:v00008086d00001229sv00008086sd00003006* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Network Connection + +pci:v00008086d00001229sv00008086sd00003007* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Network Connection + +pci:v00008086d00001229sv00008086sd00003008* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Network Connection + +pci:v00008086d00001229sv00008086sd00003010* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Network Connection + +pci:v00008086d00001229sv00008086sd00003011* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 S Network Connection + +pci:v00008086d00001229sv00008086sd00003012* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Network Connection + +pci:v00008086d00001229sv00008086sd0000301A* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00008086d00001229sv00008086sd00003411* + ID_MODEL_FROM_DATABASE=SDS2 Mainboard + +pci:v00008086d0000122D* + ID_MODEL_FROM_DATABASE=430FX - 82437FX TSC [Triton I] + +pci:v00008086d0000122E* + ID_MODEL_FROM_DATABASE=82371FB PIIX ISA [Triton I] + +pci:v00008086d00001230* + ID_MODEL_FROM_DATABASE=82371FB PIIX IDE [Triton I] + +pci:v00008086d00001231* + ID_MODEL_FROM_DATABASE=DSVD Modem + +pci:v00008086d00001234* + ID_MODEL_FROM_DATABASE=430MX - 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX) + +pci:v00008086d00001235* + ID_MODEL_FROM_DATABASE=430MX - 82437MX Mob. System Ctrlr (MTSC) & 82438MX Data Path (MTDP) + +pci:v00008086d00001237* + ID_MODEL_FROM_DATABASE=440FX - 82441FX PMC [Natoma] + +pci:v00008086d00001237sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v00008086d00001239* + ID_MODEL_FROM_DATABASE=82371FB PIIX IDE Interface + +pci:v00008086d0000123B* + ID_MODEL_FROM_DATABASE=82380PB PCI to PCI Docking Bridge + +pci:v00008086d0000123C* + ID_MODEL_FROM_DATABASE=82380AB (MISA) Mobile PCI-to-ISA Bridge + +pci:v00008086d0000123D* + ID_MODEL_FROM_DATABASE=683053 Programmable Interrupt Device + +pci:v00008086d0000123E* + ID_MODEL_FROM_DATABASE=82466GX (IHPC) Integrated Hot-Plug Controller (hidden mode) + +pci:v00008086d0000123F* + ID_MODEL_FROM_DATABASE=82466GX Integrated Hot-Plug Controller (IHPC) + +pci:v00008086d00001240* + ID_MODEL_FROM_DATABASE=82752 (752) AGP Graphics Accelerator + +pci:v00008086d0000124B* + ID_MODEL_FROM_DATABASE=82380FB (MPCI2) Mobile Docking Controller + +pci:v00008086d00001250* + ID_MODEL_FROM_DATABASE=430HX - 82439HX TXC [Triton II] + +pci:v00008086d00001360* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub PCI Bridge + +pci:v00008086d00001361* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub Controller (HRes) + +pci:v00008086d00001361sv00008086sd00001361* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub Controller (HRes) + +pci:v00008086d00001361sv00008086sd00008000* + ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub Controller (HRes) + +pci:v00008086d00001460* + ID_MODEL_FROM_DATABASE=82870P2 P64H2 Hub PCI Bridge + +pci:v00008086d00001461* + ID_MODEL_FROM_DATABASE=82870P2 P64H2 I/OxAPIC + +pci:v00008086d00001461sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00001461sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9/Vx9 mainboard + +pci:v00008086d00001462* + ID_MODEL_FROM_DATABASE=82870P2 P64H2 Hot Plug Controller + +pci:v00008086d00001501* + ID_MODEL_FROM_DATABASE=82567V-3 Gigabit Network Connection + +pci:v00008086d00001502* + ID_MODEL_FROM_DATABASE=82579LM Gigabit Network Connection + +pci:v00008086d00001502sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001503* + ID_MODEL_FROM_DATABASE=82579V Gigabit Network Connection + +pci:v00008086d00001503sv00001043sd0000849C* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001507* + ID_MODEL_FROM_DATABASE=Ethernet Express Module X520-P2 + +pci:v00008086d00001508* + ID_MODEL_FROM_DATABASE=82598EB Gigabit BX Network Connection + +pci:v00008086d0000150A* + ID_MODEL_FROM_DATABASE=82576NS Gigabit Network Connection + +pci:v00008086d0000150B* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT2 Server Adapter + +pci:v00008086d0000150Bsv00008086sd0000A10C* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT2 Server Adapter + +pci:v00008086d0000150Bsv00008086sd0000A11C* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT2 Server Adapter + +pci:v00008086d0000150Bsv00008086sd0000A12C* + ID_MODEL_FROM_DATABASE=82598EB 10-Gigabit AT2 Server Adapter + +pci:v00008086d0000150C* + ID_MODEL_FROM_DATABASE=82583V Gigabit Network Connection + +pci:v00008086d0000150D* + ID_MODEL_FROM_DATABASE=82576 Gigabit Backplane Connection + +pci:v00008086d0000150Dsv00008086sd0000A10C* + ID_MODEL_FROM_DATABASE=Gigabit ET Quad Port Mezzanine Card + +pci:v00008086d0000150E* + ID_MODEL_FROM_DATABASE=82580 Gigabit Network Connection + +pci:v00008086d0000150Esv0000103Csd00001780* + ID_MODEL_FROM_DATABASE=NC365T 4-port Ethernet Server Adapter + +pci:v00008086d0000150Esv00008086sd000012A1* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-T4 + +pci:v00008086d0000150Esv00008086sd000012A2* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-T4 + +pci:v00008086d0000150F* + ID_MODEL_FROM_DATABASE=82580 Gigabit Fiber Network Connection + +pci:v00008086d00001510* + ID_MODEL_FROM_DATABASE=82580 Gigabit Backplane Connection + +pci:v00008086d00001511* + ID_MODEL_FROM_DATABASE=82580 Gigabit SFP Connection + +pci:v00008086d00001514* + ID_MODEL_FROM_DATABASE=Ethernet X520 10GbE Dual Port KX4 Mezz + +pci:v00008086d00001514sv00008086sd0000000B* + ID_MODEL_FROM_DATABASE=Ethernet X520 10GbE Dual Port KX4 Mezz + +pci:v00008086d00001515* + ID_MODEL_FROM_DATABASE=X540 Ethernet Controller Virtual Function + +pci:v00008086d00001516* + ID_MODEL_FROM_DATABASE=82580 Gigabit Network Connection + +pci:v00008086d00001516sv00008086sd000012B1* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-T2 + +pci:v00008086d00001516sv00008086sd000012B2* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-T2 + +pci:v00008086d00001517* + ID_MODEL_FROM_DATABASE=82599ES 10 Gigabit Network Connection + +pci:v00008086d00001517sv00001137sd0000006A* + ID_MODEL_FROM_DATABASE=UCS CNA M61KR-I Intel Converged Network Adapter + +pci:v00008086d00001518* + ID_MODEL_FROM_DATABASE=82576NS SerDes Gigabit Network Connection + +pci:v00008086d0000151C* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit TN Network Connection + +pci:v00008086d0000151Csv0000108Esd00007B13* + ID_MODEL_FROM_DATABASE=Dual 10GBASE-T LP + +pci:v00008086d00001520* + ID_MODEL_FROM_DATABASE=I350 Ethernet Controller Virtual Function + +pci:v00008086d00001521* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection + +pci:v00008086d00001521sv00001028sd00001F60* + ID_MODEL_FROM_DATABASE=Intel GbE 4P I350crNDC + +pci:v00008086d00001521sv00001028sd00001F62* + ID_MODEL_FROM_DATABASE=Intel GbE 2P I350crNDC + +pci:v00008086d00001521sv0000103Csd000017D1* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 4-port 366FLR Adapter + +pci:v00008086d00001521sv0000103Csd00002003* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 367i Adapter + +pci:v00008086d00001521sv0000103Csd00002226* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 1-port 364i Adapter + +pci:v00008086d00001521sv0000103Csd0000337F* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 361i Adapter + +pci:v00008086d00001521sv0000103Csd00003380* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 4-port 366i Adapter + +pci:v00008086d00001521sv0000103Csd0000339E* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 361T Adapter + +pci:v00008086d00001521sv0000108Esd00007B16* + ID_MODEL_FROM_DATABASE=Quad Port GbE PCIe 2.0 ExpressModule, UTP + +pci:v00008086d00001521sv0000108Esd00007B18* + ID_MODEL_FROM_DATABASE=Quad Port GbE PCIe 2.0 Low Profile Adapter, UTP + +pci:v00008086d00001521sv000010A9sd0000802A* + ID_MODEL_FROM_DATABASE=UV2-BaseIO dual-port GbE + +pci:v00008086d00001521sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T4 + +pci:v00008086d00001521sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T2 + +pci:v00008086d00001521sv00008086sd000000A1* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T4 + +pci:v00008086d00001521sv00008086sd000000A2* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T2 + +pci:v00008086d00001521sv00008086sd00005001* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T4 + +pci:v00008086d00001521sv00008086sd00005002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T2 + +pci:v00008086d00001522* + ID_MODEL_FROM_DATABASE=I350 Gigabit Fiber Network Connection + +pci:v00008086d00001522sv0000108Esd00007B17* + ID_MODEL_FROM_DATABASE=Quad Port GbE PCIe 2.0 ExpressModule, MMF + +pci:v00008086d00001522sv0000108Esd00007B19* + ID_MODEL_FROM_DATABASE=Dual Port GbE PCIe 2.0 Low Profile Adapter, MMF + +pci:v00008086d00001522sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T2 + +pci:v00008086d00001522sv00008086sd00000003* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-F4 + +pci:v00008086d00001522sv00008086sd00000004* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-F2 + +pci:v00008086d00001522sv00008086sd00000005* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-F1 + +pci:v00008086d00001522sv00008086sd000000A2* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-T2 + +pci:v00008086d00001522sv00008086sd000000A3* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-F4 + +pci:v00008086d00001522sv00008086sd000000A4* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I350-F2 + +pci:v00008086d00001523* + ID_MODEL_FROM_DATABASE=I350 Gigabit Backplane Connection + +pci:v00008086d00001523sv0000103Csd00001784* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 361FLB Adapter + +pci:v00008086d00001523sv0000103Csd000018D1* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 361FLB Adapter + +pci:v00008086d00001523sv0000103Csd00001989* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 2-port 363i Adapter + +pci:v00008086d00001523sv0000103Csd0000339F* + ID_MODEL_FROM_DATABASE=Ethernet 1Gb 4-port 366M Adapter + +pci:v00008086d00001523sv00008086sd00001F52* + ID_MODEL_FROM_DATABASE=1GbE 4P I350 Mezz + +pci:v00008086d00001524* + ID_MODEL_FROM_DATABASE=I350 Gigabit Connection + +pci:v00008086d00001525* + ID_MODEL_FROM_DATABASE=82567V-4 Gigabit Network Connection + +pci:v00008086d00001526* + ID_MODEL_FROM_DATABASE=82576 Gigabit Network Connection + +pci:v00008086d00001526sv00008086sd0000A05C* + ID_MODEL_FROM_DATABASE=Gigabit ET2 Quad Port Server Adapter + +pci:v00008086d00001526sv00008086sd0000A06C* + ID_MODEL_FROM_DATABASE=Gigabit ET2 Quad Port Server Adapter + +pci:v00008086d00001527* + ID_MODEL_FROM_DATABASE=82580 Gigabit Fiber Network Connection + +pci:v00008086d00001527sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-F4 + +pci:v00008086d00001527sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I340-F4 + +pci:v00008086d00001528* + ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2 + +pci:v00008086d00001528sv00001028sd00001F61* + ID_MODEL_FROM_DATABASE=Ethernet 10G 4P X540/I350 rNDC + +pci:v00008086d00001528sv0000103Csd0000192D* + ID_MODEL_FROM_DATABASE=561FLR-T 2-port 10Gb Ethernet Adapter + +pci:v00008086d00001528sv0000103Csd00002004* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 561i Adapter + +pci:v00008086d00001528sv0000103Csd0000211A* + ID_MODEL_FROM_DATABASE=Ethernet 10Gb 2-port 561T Adapter + +pci:v00008086d00001528sv0000108Esd00007B14* + ID_MODEL_FROM_DATABASE=Sun Dual Port 10 GbE PCIe 2.0 ExpressModule, Base-T + +pci:v00008086d00001528sv0000108Esd00007B15* + ID_MODEL_FROM_DATABASE=Sun Dual Port 10 GbE PCIe 2.0 Low Profile Adapter, Base-T + +pci:v00008086d00001528sv00001137sd000000BF* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X540-T2 + +pci:v00008086d00001528sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X540-T2 + +pci:v00008086d00001528sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X540-T1 + +pci:v00008086d00001528sv00008086sd0000001A* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X540-T2 + +pci:v00008086d00001528sv00008086sd000000A2* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X540-T1 + +pci:v00008086d00001528sv00008086sd00001F61* + ID_MODEL_FROM_DATABASE=Ethernet 10G 4P X540/I350 rNDC + +pci:v00008086d00001528sv00008086sd00005003* + ID_MODEL_FROM_DATABASE=Ethernet 10G 2P X540-t Adapter + +pci:v00008086d00001529* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Network Connection with FCoE + +pci:v00008086d0000152A* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Backplane Connection with FCoE + +pci:v00008086d00001533* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection + +pci:v00008086d00001533sv0000103Csd00000003* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I210-T1 + +pci:v00008086d00001533sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I210-T1 + +pci:v00008086d00001533sv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter I210-T1 + +pci:v00008086d00001534* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection + +pci:v00008086d00001536* + ID_MODEL_FROM_DATABASE=I210 Gigabit Fiber Network Connection + +pci:v00008086d00001537* + ID_MODEL_FROM_DATABASE=I210 Gigabit Backplane Connection + +pci:v00008086d00001538* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection + +pci:v00008086d00001539* + ID_MODEL_FROM_DATABASE=I211 Gigabit Network Connection + +pci:v00008086d0000153A* + ID_MODEL_FROM_DATABASE=Ethernet Connection I217-LM + +pci:v00008086d0000153Asv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d0000153B* + ID_MODEL_FROM_DATABASE=Ethernet Connection I217-V + +pci:v00008086d00001547* + ID_MODEL_FROM_DATABASE=DSL3510 Thunderbolt Port [Cactus Ridge] + +pci:v00008086d00001549* + ID_MODEL_FROM_DATABASE=DSL3510 Thunderbolt Controller [Cactus Ridge] + +pci:v00008086d0000154A* + ID_MODEL_FROM_DATABASE=Ethernet Server Adapter X520-4 + +pci:v00008086d0000154Asv00008086sd0000011A* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-4 + +pci:v00008086d0000154Asv00008086sd0000011B* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-4 + +pci:v00008086d0000154Asv00008086sd0000011C* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-4 + +pci:v00008086d0000154D* + ID_MODEL_FROM_DATABASE=Ethernet 10G 2P X520 Adapter + +pci:v00008086d0000154Dsv00008086sd00007B11* + ID_MODEL_FROM_DATABASE=10GbE 2P X520 Adapter + +pci:v00008086d00001557* + ID_MODEL_FROM_DATABASE=82599 10 Gigabit Network Connection + +pci:v00008086d00001557sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet OCP Server Adapter X520-1 + +pci:v00008086d00001558* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-Q1 + +pci:v00008086d00001558sv00008086sd0000011A* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-Q1 + +pci:v00008086d00001558sv00008086sd0000011B* + ID_MODEL_FROM_DATABASE=Ethernet Converged Network Adapter X520-Q1 + +pci:v00008086d00001559* + ID_MODEL_FROM_DATABASE=Ethernet Connection I218-V + +pci:v00008086d0000155A* + ID_MODEL_FROM_DATABASE=Ethernet Connection I218-LM + +pci:v00008086d0000155C* + ID_MODEL_FROM_DATABASE=Ethernet Server Bypass Adapter + +pci:v00008086d0000155Csv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Server Bypass Adapter X540-T2 + +pci:v00008086d0000155D* + ID_MODEL_FROM_DATABASE=Ethernet Server Bypass Adapter + +pci:v00008086d0000155Dsv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Server Bypass Adapter X520-SR2 + +pci:v00008086d0000155Dsv00008086sd00000002* + ID_MODEL_FROM_DATABASE=Ethernet Server Bypass Adapter X520-LR2 + +pci:v00008086d00001560* + ID_MODEL_FROM_DATABASE=Ethernet Controller X540 + +pci:v00008086d0000157B* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection + +pci:v00008086d0000157C* + ID_MODEL_FROM_DATABASE=I210 Gigabit Backplane Connection + +pci:v00008086d000015A0* + ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I218-LM + +pci:v00008086d000015A1* + ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I218-V + +pci:v00008086d000015A2* + ID_MODEL_FROM_DATABASE=Ethernet Connection (3) I218-LM + +pci:v00008086d000015A3* + ID_MODEL_FROM_DATABASE=Ethernet Connection (3) I218-V + +pci:v00008086d00001960* + ID_MODEL_FROM_DATABASE=80960RP (i960RP) Microprocessor + +pci:v00008086d00001960sv0000101Esd00000431* + ID_MODEL_FROM_DATABASE=MegaRAID 431 RAID Controller + +pci:v00008086d00001960sv0000101Esd00000438* + ID_MODEL_FROM_DATABASE=MegaRAID 438 Ultra2 LVD RAID Controller + +pci:v00008086d00001960sv0000101Esd00000466* + ID_MODEL_FROM_DATABASE=MegaRAID 466 Express Plus RAID Controller + +pci:v00008086d00001960sv0000101Esd00000467* + ID_MODEL_FROM_DATABASE=MegaRAID 467 Enterprise 1500 RAID Controller + +pci:v00008086d00001960sv0000101Esd00000490* + ID_MODEL_FROM_DATABASE=MegaRAID 490 Express 300 RAID Controller + +pci:v00008086d00001960sv0000101Esd00000762* + ID_MODEL_FROM_DATABASE=MegaRAID 762 Express RAID Controller + +pci:v00008086d00001960sv0000101Esd000009A0* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 2/SC + +pci:v00008086d00001960sv00001028sd00000467* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 2/DC + +pci:v00008086d00001960sv00001028sd00001111* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 2/SC + +pci:v00008086d00001960sv0000103Csd000003A2* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00008086d00001960sv0000103Csd000010C6* + ID_MODEL_FROM_DATABASE=MegaRAID 438, NetRAID-3Si + +pci:v00008086d00001960sv0000103Csd000010C7* + ID_MODEL_FROM_DATABASE=MegaRAID T5, Integrated NetRAID + +pci:v00008086d00001960sv0000103Csd000010CC* + ID_MODEL_FROM_DATABASE=MegaRAID, Integrated NetRAID + +pci:v00008086d00001960sv0000103Csd000010CD* + ID_MODEL_FROM_DATABASE=NetRAID-1Si + +pci:v00008086d00001960sv0000105Asd00000000* + ID_MODEL_FROM_DATABASE=SuperTrak + +pci:v00008086d00001960sv0000105Asd00002168* + ID_MODEL_FROM_DATABASE=SuperTrak Pro + +pci:v00008086d00001960sv0000105Asd00005168* + ID_MODEL_FROM_DATABASE=SuperTrak66/100 + +pci:v00008086d00001960sv00001111sd00001111* + ID_MODEL_FROM_DATABASE=MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC + +pci:v00008086d00001960sv00001111sd00001112* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 2/SC + +pci:v00008086d00001960sv0000113Csd000003A2* + ID_MODEL_FROM_DATABASE=MegaRAID + +pci:v00008086d00001960sv0000E4BFsd00001010* + ID_MODEL_FROM_DATABASE=CG1-RADIO + +pci:v00008086d00001960sv0000E4BFsd00001020* + ID_MODEL_FROM_DATABASE=CU2-QUARTET + +pci:v00008086d00001960sv0000E4BFsd00001040* + ID_MODEL_FROM_DATABASE=CU1-CHORUS + +pci:v00008086d00001960sv0000E4BFsd00003100* + ID_MODEL_FROM_DATABASE=CX1-BAND + +pci:v00008086d00001962* + ID_MODEL_FROM_DATABASE=80960RM (i960RM) Microprocessor + +pci:v00008086d00001962sv0000105Asd00000000* + ID_MODEL_FROM_DATABASE=SuperTrak SX6000 I2O CPU + +pci:v00008086d00001A21* + ID_MODEL_FROM_DATABASE=82840 840 [Carmel] Chipset Host Bridge (Hub A) + +pci:v00008086d00001A23* + ID_MODEL_FROM_DATABASE=82840 840 [Carmel] Chipset AGP Bridge + +pci:v00008086d00001A24* + ID_MODEL_FROM_DATABASE=82840 840 [Carmel] Chipset PCI Bridge (Hub B) + +pci:v00008086d00001A30* + ID_MODEL_FROM_DATABASE=82845 845 [Brookdale] Chipset Host Bridge + +pci:v00008086d00001A30sv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v00008086d00001A30sv000015D9sd00003280* + ID_MODEL_FROM_DATABASE=Supermicro P4SBE Mainboard + +pci:v00008086d00001A31* + ID_MODEL_FROM_DATABASE=82845 845 [Brookdale] Chipset AGP Bridge + +pci:v00008086d00001A38* + ID_MODEL_FROM_DATABASE=5000 Series Chipset DMA Engine + +pci:v00008086d00001A38sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00001A38sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00001A48* + ID_MODEL_FROM_DATABASE=82597EX 10GbE Ethernet Controller + +pci:v00008086d00001A48sv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=PRO/10GbE SR Server Adapter + +pci:v00008086d00001A48sv00008086sd0000A11F* + ID_MODEL_FROM_DATABASE=PRO/10GbE SR Server Adapter + +pci:v00008086d00001B48* + ID_MODEL_FROM_DATABASE=82597EX 10GbE Ethernet Controller + +pci:v00008086d00001B48sv00008086sd0000A01F* + ID_MODEL_FROM_DATABASE=PRO/10GbE LR Server Adapter + +pci:v00008086d00001B48sv00008086sd0000A11F* + ID_MODEL_FROM_DATABASE=PRO/10GbE LR Server Adapter + +pci:v00008086d00001C00* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 4 port SATA IDE Controller + +pci:v00008086d00001C01* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 4 port SATA IDE Controller + +pci:v00008086d00001C02* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SATA AHCI Controller + +pci:v00008086d00001C02sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C02sv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C03* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 6 port SATA AHCI Controller + +pci:v00008086d00001C03sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C03sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C03sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C03sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C04* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SATA RAID Controller + +pci:v00008086d00001C05* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SATA RAID Controller + +pci:v00008086d00001C08* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 2 port SATA IDE Controller + +pci:v00008086d00001C09* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 2 port SATA IDE Controller + +pci:v00008086d00001C10* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 1 + +pci:v00008086d00001C10sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C10sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C10sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C12* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 2 + +pci:v00008086d00001C12sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C12sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C14* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 3 + +pci:v00008086d00001C14sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C14sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C16* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 4 + +pci:v00008086d00001C16sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C18* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 5 + +pci:v00008086d00001C18sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C1A* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 6 + +pci:v00008086d00001C1Asv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C1C* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 7 + +pci:v00008086d00001C1E* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family PCI Express Root Port 8 + +pci:v00008086d00001C20* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family High Definition Audio Controller + +pci:v00008086d00001C20sv00001028sd00000490* + ID_MODEL_FROM_DATABASE=Alienware M17x R3 + +pci:v00008086d00001C20sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C20sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C20sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C20sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C20sv00001043sd00008418* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C20sv00008086sd00002008* + ID_MODEL_FROM_DATABASE=DQ67SW board + +pci:v00008086d00001C20sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C22* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SMBus Controller + +pci:v00008086d00001C22sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C22sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C22sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C22sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C22sv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C22sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C24* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family Thermal Management Controller + +pci:v00008086d00001C25* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family DMI to PCI Bridge + +pci:v00008086d00001C26* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 + +pci:v00008086d00001C26sv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C26sv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C26sv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C26sv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C26sv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C26sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C27* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Universal Host Controller #1 + +pci:v00008086d00001C27sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C2C* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Universal Host Controller #5 + +pci:v00008086d00001C2Csv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C2D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 + +pci:v00008086d00001C2Dsv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C2Dsv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C2Dsv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C2Dsv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C2Dsv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C2Dsv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C33* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LAN Controller + +pci:v00008086d00001C35* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family VECI Controller + +pci:v00008086d00001C3A* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family MEI Controller #1 + +pci:v00008086d00001C3Asv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C3Asv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C3Asv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C3Asv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C3Asv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C3Asv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C3B* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family MEI Controller #2 + +pci:v00008086d00001C3C* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family IDE-r Controller + +pci:v00008086d00001C3D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family KT Controller + +pci:v00008086d00001C40* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C41* + ID_MODEL_FROM_DATABASE=Mobile SFF 6 Series Chipset Family LPC Controller + +pci:v00008086d00001C42* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C43* + ID_MODEL_FROM_DATABASE=Mobile 6 Series Chipset Family LPC Controller + +pci:v00008086d00001C44* + ID_MODEL_FROM_DATABASE=Z68 Express Chipset Family LPC Controller + +pci:v00008086d00001C45* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C46* + ID_MODEL_FROM_DATABASE=P67 Express Chipset Family LPC Controller + +pci:v00008086d00001C46sv00001043sd0000844D* + ID_MODEL_FROM_DATABASE=P8P67 Deluxe Motherboard + +pci:v00008086d00001C47* + ID_MODEL_FROM_DATABASE=UM67 Express Chipset Family LPC Controller + +pci:v00008086d00001C48* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C49* + ID_MODEL_FROM_DATABASE=HM65 Express Chipset Family LPC Controller + +pci:v00008086d00001C49sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=Apple MacBookPro8,2 [Core i7, 15", 2011] + +pci:v00008086d00001C4A* + ID_MODEL_FROM_DATABASE=H67 Express Chipset Family LPC Controller + +pci:v00008086d00001C4Asv00001028sd000004AA* + ID_MODEL_FROM_DATABASE=XPS 8300 + +pci:v00008086d00001C4B* + ID_MODEL_FROM_DATABASE=HM67 Express Chipset Family LPC Controller + +pci:v00008086d00001C4Bsv00001028sd000004B2* + ID_MODEL_FROM_DATABASE=Vostro 3350 + +pci:v00008086d00001C4Bsv00001028sd000004DA* + ID_MODEL_FROM_DATABASE=Vostro 3750 + +pci:v00008086d00001C4C* + ID_MODEL_FROM_DATABASE=Q65 Express Chipset Family LPC Controller + +pci:v00008086d00001C4D* + ID_MODEL_FROM_DATABASE=QS67 Express Chipset Family LPC Controller + +pci:v00008086d00001C4E* + ID_MODEL_FROM_DATABASE=Q67 Express Chipset Family LPC Controller + +pci:v00008086d00001C4F* + ID_MODEL_FROM_DATABASE=QM67 Express Chipset Family LPC Controller + +pci:v00008086d00001C4Fsv00001028sd000004A3* + ID_MODEL_FROM_DATABASE=Precision M4600 + +pci:v00008086d00001C50* + ID_MODEL_FROM_DATABASE=B65 Express Chipset Family LPC Controller + +pci:v00008086d00001C51* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C52* + ID_MODEL_FROM_DATABASE=C202 Chipset Family LPC Controller + +pci:v00008086d00001C53* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C54* + ID_MODEL_FROM_DATABASE=C204 Chipset Family LPC Controller + +pci:v00008086d00001C55* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C56* + ID_MODEL_FROM_DATABASE=C206 Chipset Family LPC Controller + +pci:v00008086d00001C57* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C58* + ID_MODEL_FROM_DATABASE=Upgraded B65 Express Chipset Family LPC Controller + +pci:v00008086d00001C59* + ID_MODEL_FROM_DATABASE=Upgraded HM67 Express Chipset Family LPC Controller + +pci:v00008086d00001C5A* + ID_MODEL_FROM_DATABASE=Upgraded Q67 Express Chipset Family LPC Controller + +pci:v00008086d00001C5B* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C5C* + ID_MODEL_FROM_DATABASE=H61 Express Chipset Family LPC Controller + +pci:v00008086d00001C5D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C5E* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001C5F* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller + +pci:v00008086d00001D00* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA IDE Controller + +pci:v00008086d00001D02* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 6-Port SATA AHCI Controller + +pci:v00008086d00001D04* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset SATA RAID Controller + +pci:v00008086d00001D06* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset SATA Premium RAID Controller + +pci:v00008086d00001D08* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 2-Port SATA IDE Controller + +pci:v00008086d00001D10* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 1 + +pci:v00008086d00001D11* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 1 + +pci:v00008086d00001D12* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 2 + +pci:v00008086d00001D13* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 2 + +pci:v00008086d00001D14* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 3 + +pci:v00008086d00001D15* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 3 + +pci:v00008086d00001D16* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 4 + +pci:v00008086d00001D17* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 4 + +pci:v00008086d00001D18* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 5 + +pci:v00008086d00001D19* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 5 + +pci:v00008086d00001D1A* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 6 + +pci:v00008086d00001D1B* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 6 + +pci:v00008086d00001D1C* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 7 + +pci:v00008086d00001D1D* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 7 + +pci:v00008086d00001D1E* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 8 + +pci:v00008086d00001D1F* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Root Port 8 + +pci:v00008086d00001D20* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset High Definition Audio Controller + +pci:v00008086d00001D22* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset SMBus Host Controller + +pci:v00008086d00001D24* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Thermal Management Controller + +pci:v00008086d00001D25* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset DMI to PCI Bridge + +pci:v00008086d00001D26* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset USB2 Enhanced Host Controller #1 + +pci:v00008086d00001D2D* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset USB2 Enhanced Host Controller #2 + +pci:v00008086d00001D33* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset LAN Controller + +pci:v00008086d00001D35* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset VECI Controller + +pci:v00008086d00001D3A* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset MEI Controller #1 + +pci:v00008086d00001D3B* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset MEI Controller #2 + +pci:v00008086d00001D3C* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset IDE-r Controller + +pci:v00008086d00001D3D* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset KT Controller + +pci:v00008086d00001D3E* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset PCI Express Virtual Root Port + +pci:v00008086d00001D3F* + ID_MODEL_FROM_DATABASE=C608/C606/X79 series chipset PCI Express Virtual Switch Port + +pci:v00008086d00001D40* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset LPC Controller + +pci:v00008086d00001D41* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset LPC Controller + +pci:v00008086d00001D50* + ID_MODEL_FROM_DATABASE=C608 chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D54* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D55* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D58* + ID_MODEL_FROM_DATABASE=C606 chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D59* + ID_MODEL_FROM_DATABASE=C604/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D5A* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA Storage Control Unit + +pci:v00008086d00001D5B* + ID_MODEL_FROM_DATABASE=C602 chipset 4-Port SATA Storage Control Unit + +pci:v00008086d00001D5C* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D5D* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D5E* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA Storage Control Unit + +pci:v00008086d00001D5F* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA Storage Control Unit + +pci:v00008086d00001D60* + ID_MODEL_FROM_DATABASE=C608 chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D64* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D65* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D68* + ID_MODEL_FROM_DATABASE=C606 chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D69* + ID_MODEL_FROM_DATABASE=C604/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D6A* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA Storage Control Unit + +pci:v00008086d00001D6B* + ID_MODEL_FROM_DATABASE=C602 chipset 4-Port SATA Storage Control Unit + +pci:v00008086d00001D6C* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D6D* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA/SAS Storage Control Unit + +pci:v00008086d00001D6E* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Dual 4-Port SATA Storage Control Unit + +pci:v00008086d00001D6F* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset 4-Port SATA Storage Control Unit + +pci:v00008086d00001D70* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset SMBus Controller 0 + +pci:v00008086d00001D71* + ID_MODEL_FROM_DATABASE=C608/C606/X79 series chipset SMBus Controller 1 + +pci:v00008086d00001D72* + ID_MODEL_FROM_DATABASE=C608 chipset SMBus Controller 2 + +pci:v00008086d00001D74* + ID_MODEL_FROM_DATABASE=C608/C606/X79 series chipset PCI Express Upstream Port + +pci:v00008086d00001D76* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset Multi-Function Glue + +pci:v00008086d00001E00* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family 4-port SATA Controller [IDE mode] + +pci:v00008086d00001E01* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family 4-port SATA Controller [IDE mode] + +pci:v00008086d00001E02* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family 6-port SATA Controller [AHCI mode] + +pci:v00008086d00001E02sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E02sv00001849sd00001E02* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E03* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family 6-port SATA Controller [AHCI mode] + +pci:v00008086d00001E03sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E03sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E04* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SATA Controller [RAID mode] + +pci:v00008086d00001E05* + ID_MODEL_FROM_DATABASE=7 Series Chipset SATA Controller [RAID mode] + +pci:v00008086d00001E06* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SATA Controller [RAID mode] + +pci:v00008086d00001E07* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family SATA Controller [RAID mode] + +pci:v00008086d00001E08* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family 2-port SATA Controller [IDE mode] + +pci:v00008086d00001E09* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family 2-port SATA Controller [IDE mode] + +pci:v00008086d00001E0E* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SATA Controller [RAID mode] + +pci:v00008086d00001E10* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 1 + +pci:v00008086d00001E10sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E10sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E10sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E10sv00001849sd00001E10* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E12* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 2 + +pci:v00008086d00001E12sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E12sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E14* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 3 + +pci:v00008086d00001E16* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 4 + +pci:v00008086d00001E16sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E16sv00001849sd00001618* + ID_MODEL_FROM_DATABASE=Z77 Extreme4 motherboard + +pci:v00008086d00001E18* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 5 + +pci:v00008086d00001E18sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E18sv00001849sd00001E18* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E1A* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 6 + +pci:v00008086d00001E1Asv00001849sd00001E1A* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E1C* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 7 + +pci:v00008086d00001E1E* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 8 + +pci:v00008086d00001E1Esv00001849sd00001E1E* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E20* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family High Definition Audio Controller + +pci:v00008086d00001E20sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E20sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E20sv00001043sd00008415* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E20sv00001849sd00001898* + ID_MODEL_FROM_DATABASE=Z77 Extreme4 motherboard + +pci:v00008086d00001E22* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SMBus Controller + +pci:v00008086d00001E22sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E22sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E22sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E22sv00001849sd00001E22* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E24* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family Thermal Management Controller + +pci:v00008086d00001E24sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E25* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family DMI to PCI Bridge + +pci:v00008086d00001E26* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 + +pci:v00008086d00001E26sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E26sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E26sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E26sv00001849sd00001E26* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E2D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 + +pci:v00008086d00001E2Dsv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E2Dsv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E2Dsv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E2Dsv00001849sd00001E2D* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E31* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB xHCI Host Controller + +pci:v00008086d00001E31sv0000103Csd000017AB* + ID_MODEL_FROM_DATABASE=ProBook 6570b + +pci:v00008086d00001E31sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E31sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E31sv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E31sv00001849sd00001E31* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E33* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family LAN Controller + +pci:v00008086d00001E3A* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family MEI Controller #1 + +pci:v00008086d00001E3Asv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E3Asv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E3Asv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E3Asv00001849sd00001E3A* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E3B* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family MEI Controller #2 + +pci:v00008086d00001E3C* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family IDE-r Controller + +pci:v00008086d00001E3D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family KT Controller + +pci:v00008086d00001E41* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E42* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E43* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E44* + ID_MODEL_FROM_DATABASE=Z77 Express Chipset LPC Controller + +pci:v00008086d00001E44sv00001849sd00001E44* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00001E45* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E46* + ID_MODEL_FROM_DATABASE=Z75 Express Chipset LPC Controller + +pci:v00008086d00001E47* + ID_MODEL_FROM_DATABASE=Q77 Express Chipset LPC Controller + +pci:v00008086d00001E48* + ID_MODEL_FROM_DATABASE=Q75 Express Chipset LPC Controller + +pci:v00008086d00001E49* + ID_MODEL_FROM_DATABASE=B75 Express Chipset LPC Controller + +pci:v00008086d00001E4A* + ID_MODEL_FROM_DATABASE=H77 Express Chipset LPC Controller + +pci:v00008086d00001E4Asv00001043sd000084CA* + ID_MODEL_FROM_DATABASE=P8H77-I Motherboard + +pci:v00008086d00001E4B* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E4C* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E4D* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E4E* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E4F* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E50* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E51* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E52* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E53* + ID_MODEL_FROM_DATABASE=C216 Series Chipset LPC Controller + +pci:v00008086d00001E54* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E55* + ID_MODEL_FROM_DATABASE=QM77 Express Chipset LPC Controller + +pci:v00008086d00001E56* + ID_MODEL_FROM_DATABASE=QS77 Express Chipset LPC Controller + +pci:v00008086d00001E57* + ID_MODEL_FROM_DATABASE=HM77 Express Chipset LPC Controller + +pci:v00008086d00001E58* + ID_MODEL_FROM_DATABASE=UM77 Express Chipset LPC Controller + +pci:v00008086d00001E59* + ID_MODEL_FROM_DATABASE=HM76 Express Chipset LPC Controller + +pci:v00008086d00001E59sv00001043sd00001477* + ID_MODEL_FROM_DATABASE=N56VZ + +pci:v00008086d00001E59sv00001043sd00001517* + ID_MODEL_FROM_DATABASE=Zenbook Prime UX31A + +pci:v00008086d00001E5A* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E5B* + ID_MODEL_FROM_DATABASE=UM77 Express Chipset LPC Controller + +pci:v00008086d00001E5C* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E5D* + ID_MODEL_FROM_DATABASE=HM75 Express Chipset LPC Controller + +pci:v00008086d00001E5E* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001E5F* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller + +pci:v00008086d00001F00* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F01* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F02* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F03* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F04* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F05* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F06* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F07* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F08* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F09* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0A* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0B* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0C* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0D* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0E* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F0F* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SoC Transaction Router + +pci:v00008086d00001F10* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCIe Root Port 1 + +pci:v00008086d00001F11* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCIe Root Port 2 + +pci:v00008086d00001F12* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCIe Root Port 3 + +pci:v00008086d00001F13* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCIe Root Port 4 + +pci:v00008086d00001F14* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAS + +pci:v00008086d00001F15* + ID_MODEL_FROM_DATABASE=Atom processor C2000 SMBus 2.0 + +pci:v00008086d00001F16* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RCEC + +pci:v00008086d00001F18* + ID_MODEL_FROM_DATABASE=Atom processor C2000 nCPM + +pci:v00008086d00001F19* + ID_MODEL_FROM_DATABASE=Atom processor C2000 nCPM + +pci:v00008086d00001F20* + ID_MODEL_FROM_DATABASE=Atom processor C2000 4-Port IDE SATA2 Controller + +pci:v00008086d00001F21* + ID_MODEL_FROM_DATABASE=Atom processor C2000 4-Port IDE SATA2 Controller + +pci:v00008086d00001F22* + ID_MODEL_FROM_DATABASE=Atom processor C2000 AHCI SATA2 Controller + +pci:v00008086d00001F23* + ID_MODEL_FROM_DATABASE=Atom processor C2000 AHCI SATA2 Controller + +pci:v00008086d00001F24* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F25* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F26* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F27* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F2C* + ID_MODEL_FROM_DATABASE=Atom processor C2000 USB Enhanced Host Controller + +pci:v00008086d00001F2E* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F2F* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA2 Controller + +pci:v00008086d00001F30* + ID_MODEL_FROM_DATABASE=Atom processor C2000 2-Port IDE SATA3 Controller + +pci:v00008086d00001F31* + ID_MODEL_FROM_DATABASE=Atom processor C2000 2-Port IDE SATA3 Controller + +pci:v00008086d00001F32* + ID_MODEL_FROM_DATABASE=Atom processor C2000 AHCI SATA3 Controller + +pci:v00008086d00001F33* + ID_MODEL_FROM_DATABASE=Atom processor C2000 AHCI SATA3 Controller + +pci:v00008086d00001F34* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F35* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F36* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F37* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F38* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCU + +pci:v00008086d00001F39* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCU + +pci:v00008086d00001F3A* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCU + +pci:v00008086d00001F3B* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCU + +pci:v00008086d00001F3C* + ID_MODEL_FROM_DATABASE=Atom processor C2000 PCU SMBus + +pci:v00008086d00001F3E* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F3F* + ID_MODEL_FROM_DATABASE=Atom processor C2000 RAID SATA3 Controller + +pci:v00008086d00001F40* + ID_MODEL_FROM_DATABASE=Ethernet Connection I354 1.0 GbE Backplane + +pci:v00008086d00001F40sv00001028sd000005F1* + ID_MODEL_FROM_DATABASE=Ethernet Connection I354 1.0 GbE Backplane + +pci:v00008086d00001F41* + ID_MODEL_FROM_DATABASE=Ethernet Connection I354 + +pci:v00008086d00001F42* + ID_MODEL_FROM_DATABASE=Atom processor C2000 GbE + +pci:v00008086d00001F44* + ID_MODEL_FROM_DATABASE=Atom processor C2000 GbE Virtual Function + +pci:v00008086d00001F45* + ID_MODEL_FROM_DATABASE=Ethernet Connection I354 2.5 GbE Backplane + +pci:v00008086d00002250* + ID_MODEL_FROM_DATABASE=Xeon Phi coprocessor 5100 series + +pci:v00008086d0000225C* + ID_MODEL_FROM_DATABASE=Xeon Phi coprocessor SE10/7120 series + +pci:v00008086d0000225D* + ID_MODEL_FROM_DATABASE=Xeon Phi coprocessor 3120 series + +pci:v00008086d00002310* + ID_MODEL_FROM_DATABASE=DH89xxCC LPC Controller + +pci:v00008086d00002323* + ID_MODEL_FROM_DATABASE=DH89xxCC 4 Port SATA AHCI Controller + +pci:v00008086d00002330* + ID_MODEL_FROM_DATABASE=DH89xxCC SMBus Controller + +pci:v00008086d00002331* + ID_MODEL_FROM_DATABASE=DH89xxCC Chap Counter + +pci:v00008086d00002332* + ID_MODEL_FROM_DATABASE=DH89xxCC Thermal Subsystem + +pci:v00008086d00002334* + ID_MODEL_FROM_DATABASE=DH89xxCC USB2 Enhanced Host Controller #1 + +pci:v00008086d00002335* + ID_MODEL_FROM_DATABASE=DH89xxCC USB2 Enhanced Host Controller #1 + +pci:v00008086d00002342* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #1 + +pci:v00008086d00002343* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #1 + +pci:v00008086d00002344* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #2 + +pci:v00008086d00002345* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #2 + +pci:v00008086d00002346* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #3 + +pci:v00008086d00002347* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #3 + +pci:v00008086d00002348* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #4 + +pci:v00008086d00002349* + ID_MODEL_FROM_DATABASE=DH89xxCC PCI Express Root Port #4 + +pci:v00008086d00002360* + ID_MODEL_FROM_DATABASE=DH89xxCC Watchdog Timer + +pci:v00008086d00002364* + ID_MODEL_FROM_DATABASE=DH89xxCC MEI 0 + +pci:v00008086d00002365* + ID_MODEL_FROM_DATABASE=DH89xxCC MEI 1 + +pci:v00008086d00002390* + ID_MODEL_FROM_DATABASE=Coleto Creek LPC Controller + +pci:v00008086d000023A1* + ID_MODEL_FROM_DATABASE=Coleto Creek 2-Port SATA Controller [IDE Mode] + +pci:v00008086d000023A3* + ID_MODEL_FROM_DATABASE=Coleto Creek 4-Port SATA Controller [AHCI Mode] + +pci:v00008086d000023A6* + ID_MODEL_FROM_DATABASE=Coleto Creek 2-Port SATA Controller [IDE Mode] + +pci:v00008086d000023B0* + ID_MODEL_FROM_DATABASE=Coleto Creek SMBus Controller + +pci:v00008086d000023B1* + ID_MODEL_FROM_DATABASE=Coleto Creek CHAP Counter + +pci:v00008086d000023B2* + ID_MODEL_FROM_DATABASE=Coleto Creek Thermal Management Controller + +pci:v00008086d000023B4* + ID_MODEL_FROM_DATABASE=Coleto Creek USB2 Enhanced Host Controller #1 + +pci:v00008086d000023B5* + ID_MODEL_FROM_DATABASE=Coleto Creek USB2 Enhanced Host Controller #1 + +pci:v00008086d000023C2* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #1 + +pci:v00008086d000023C3* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #1 + +pci:v00008086d000023C4* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #2 + +pci:v00008086d000023C5* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #2 + +pci:v00008086d000023C6* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #3 + +pci:v00008086d000023C7* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #3 + +pci:v00008086d000023C8* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #4 + +pci:v00008086d000023C9* + ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #4 + +pci:v00008086d000023E0* + ID_MODEL_FROM_DATABASE=Coleto Creek Watchdog Timer + +pci:v00008086d000023E4* + ID_MODEL_FROM_DATABASE=Coleto Creek MEI Controller #1 + +pci:v00008086d000023E5* + ID_MODEL_FROM_DATABASE=Coleto Creek MEI Controller #2 + +pci:v00008086d00002410* + ID_MODEL_FROM_DATABASE=82801AA ISA Bridge (LPC) + +pci:v00008086d00002411* + ID_MODEL_FROM_DATABASE=82801AA IDE Controller + +pci:v00008086d00002412* + ID_MODEL_FROM_DATABASE=82801AA USB Controller + +pci:v00008086d00002413* + ID_MODEL_FROM_DATABASE=82801AA SMBus Controller + +pci:v00008086d00002415* + ID_MODEL_FROM_DATABASE=82801AA AC'97 Audio Controller + +pci:v00008086d00002415sv00001028sd00000095* + ID_MODEL_FROM_DATABASE=Precision Workstation 220 Integrated Digital Audio + +pci:v00008086d00002415sv00001028sd000000B4* + ID_MODEL_FROM_DATABASE=OptiPlex GX110 + +pci:v00008086d00002415sv0000110Asd00000051* + ID_MODEL_FROM_DATABASE=Activy 2xx + +pci:v00008086d00002415sv000011D4sd00000040* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00002415sv000011D4sd00000048* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00002415sv000011D4sd00005340* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00002415sv00001734sd00001025* + ID_MODEL_FROM_DATABASE=Activy 3xx + +pci:v00008086d00002416* + ID_MODEL_FROM_DATABASE=82801AA AC'97 Modem Controller + +pci:v00008086d00002418* + ID_MODEL_FROM_DATABASE=82801AA PCI Bridge + +pci:v00008086d00002420* + ID_MODEL_FROM_DATABASE=82801AB ISA Bridge (LPC) + +pci:v00008086d00002421* + ID_MODEL_FROM_DATABASE=82801AB IDE Controller + +pci:v00008086d00002422* + ID_MODEL_FROM_DATABASE=82801AB USB Controller + +pci:v00008086d00002423* + ID_MODEL_FROM_DATABASE=82801AB SMBus Controller + +pci:v00008086d00002425* + ID_MODEL_FROM_DATABASE=82801AB AC'97 Audio Controller + +pci:v00008086d00002425sv000011D4sd00000040* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00002425sv000011D4sd00000048* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00002426* + ID_MODEL_FROM_DATABASE=82801AB AC'97 Modem Controller + +pci:v00008086d00002428* + ID_MODEL_FROM_DATABASE=82801AB PCI Bridge + +pci:v00008086d00002440* + ID_MODEL_FROM_DATABASE=82801BA ISA Bridge (LPC) + +pci:v00008086d00002440sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E + +pci:v00008086d00002442* + ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 + +pci:v00008086d00002442sv00001014sd000001C6* + ID_MODEL_FROM_DATABASE=Netvista A40/A40p + +pci:v00008086d00002442sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00002442sv00001028sd000000C7* + ID_MODEL_FROM_DATABASE=Dimension 8100 + +pci:v00008086d00002442sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d00002442sv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v00008086d00002442sv0000103Csd0000126F* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d00002442sv00001043sd00008027* + ID_MODEL_FROM_DATABASE=TUSL2-C Mainboard + +pci:v00008086d00002442sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00002442sv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d00002442sv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 mainboard + +pci:v00008086d00002442sv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d00002442sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00008086d00002443* + ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller + +pci:v00008086d00002443sv00001014sd000001C6* + ID_MODEL_FROM_DATABASE=Netvista A40/A40p + +pci:v00008086d00002443sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00002443sv00001028sd000000C7* + ID_MODEL_FROM_DATABASE=Dimension 8100 + +pci:v00008086d00002443sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d00002443sv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v00008086d00002443sv0000103Csd0000126F* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d00002443sv00001043sd00008027* + ID_MODEL_FROM_DATABASE=TUSL2-C Mainboard + +pci:v00008086d00002443sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00002443sv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d00002443sv000015D9sd00003280* + ID_MODEL_FROM_DATABASE=Supermicro P4SBE Mainboard + +pci:v00008086d00002443sv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 mainboard + +pci:v00008086d00002443sv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d00002443sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00008086d00002444* + ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 + +pci:v00008086d00002444sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00002444sv00001028sd000000C7* + ID_MODEL_FROM_DATABASE=Dimension 8100 + +pci:v00008086d00002444sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d00002444sv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v00008086d00002444sv0000103Csd0000126F* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d00002444sv00001043sd00008027* + ID_MODEL_FROM_DATABASE=TUSL2-C Mainboard + +pci:v00008086d00002444sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00002444sv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d00002444sv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 mainboard + +pci:v00008086d00002444sv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00008086d00002445* + ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller + +pci:v00008086d00002445sv00000E11sd0000000B* + ID_MODEL_FROM_DATABASE=Compaq Deskpro EN Audio + +pci:v00008086d00002445sv00000E11sd00000088* + ID_MODEL_FROM_DATABASE=Evo D500 + +pci:v00008086d00002445sv00001014sd000001C6* + ID_MODEL_FROM_DATABASE=Netvista A40/A40p + +pci:v00008086d00002445sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00002445sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d00002445sv0000103Csd0000126F* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d00002445sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00002445sv00001462sd00003370* + ID_MODEL_FROM_DATABASE=STAC9721 AC + +pci:v00008086d00002445sv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d00002445sv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d00002446* + ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Modem Controller + +pci:v00008086d00002446sv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612 TX + +pci:v00008086d00002446sv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d00002448* + ID_MODEL_FROM_DATABASE=82801 Mobile PCI Bridge + +pci:v00008086d00002448sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00002448sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=HP Compaq nw8240 Mobile Workstation + +pci:v00008086d00002448sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002448sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d00002448sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d00002448sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002448sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002448sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d00002448sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30 notebook + +pci:v00008086d00002448sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d00002448sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d00002448sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d00002448sv000017AAsd000020AE* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002448sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d00002448sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002449* + ID_MODEL_FROM_DATABASE=82801BA/BAM/CA/CAM Ethernet Controller + +pci:v00008086d00002449sv00000E11sd00000012* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VM + +pci:v00008086d00002449sv00000E11sd00000091* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd000001CE* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd000001DC* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd000001EB* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd000001EC* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000202* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000205* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000217* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000234* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd0000023D* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000244* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000245* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001014sd00000265* + ID_MODEL_FROM_DATABASE=PRO/100 VE Desktop Connection + +pci:v00008086d00002449sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=PRO/100 VE Desktop Connection + +pci:v00008086d00002449sv00001014sd0000026A* + ID_MODEL_FROM_DATABASE=PRO/100 VE Desktop Connection + +pci:v00008086d00002449sv0000109Fsd0000315D* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv0000109Fsd00003181* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00001179sd0000FF01* + ID_MODEL_FROM_DATABASE=PRO/100 VE Network Connection + +pci:v00008086d00002449sv00001186sd00007801* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv0000144Dsd00002602* + ID_MODEL_FROM_DATABASE=HomePNA 1M CNR + +pci:v00008086d00002449sv00008086sd00003010* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00008086sd00003011* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VM + +pci:v00008086d00002449sv00008086sd00003012* + ID_MODEL_FROM_DATABASE=82562EH based Phoneline + +pci:v00008086d00002449sv00008086sd00003013* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VE + +pci:v00008086d00002449sv00008086sd00003014* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 VM + +pci:v00008086d00002449sv00008086sd00003015* + ID_MODEL_FROM_DATABASE=82562EH based Phoneline + +pci:v00008086d00002449sv00008086sd00003016* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile Combo + +pci:v00008086d00002449sv00008086sd00003017* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 P Mobile + +pci:v00008086d00002449sv00008086sd00003018* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 + +pci:v00008086d0000244A* + ID_MODEL_FROM_DATABASE=82801BAM IDE U100 Controller + +pci:v00008086d0000244Asv00001025sd00001016* + ID_MODEL_FROM_DATABASE=Travelmate 612TX + +pci:v00008086d0000244Asv0000104Dsd000080DF* + ID_MODEL_FROM_DATABASE=Vaio PCG-FX403 + +pci:v00008086d0000244B* + ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller + +pci:v00008086d0000244Bsv00001014sd000001C6* + ID_MODEL_FROM_DATABASE=Netvista A40/A40p + +pci:v00008086d0000244Bsv00001028sd000000C7* + ID_MODEL_FROM_DATABASE=Dimension 8100 + +pci:v00008086d0000244Bsv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d0000244Bsv00001028sd0000010E* + ID_MODEL_FROM_DATABASE=Optiplex GX240 + +pci:v00008086d0000244Bsv0000103Csd0000126F* + ID_MODEL_FROM_DATABASE=e-pc 40 + +pci:v00008086d0000244Bsv00001043sd00008027* + ID_MODEL_FROM_DATABASE=TUSL2-C Mainboard + +pci:v00008086d0000244Bsv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d0000244Bsv000015D9sd00003280* + ID_MODEL_FROM_DATABASE=Supermicro P4SBE Mainboard + +pci:v00008086d0000244Bsv00008086sd00004532* + ID_MODEL_FROM_DATABASE=D815EEA2 mainboard + +pci:v00008086d0000244Bsv00008086sd00004557* + ID_MODEL_FROM_DATABASE=D815EGEW Mainboard + +pci:v00008086d0000244Bsv00008086sd00005744* + ID_MODEL_FROM_DATABASE=S845WD1-E mainboard + +pci:v00008086d0000244C* + ID_MODEL_FROM_DATABASE=82801BAM ISA Bridge (LPC) + +pci:v00008086d0000244E* + ID_MODEL_FROM_DATABASE=82801 PCI Bridge + +pci:v00008086d0000244Esv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d0000244Esv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d0000244Esv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000244Esv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d0000244Esv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d0000244Esv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000244Esv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d0000244Esv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000244Esv00001458sd00005000* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d0000244Esv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d0000244Esv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d00002450* + ID_MODEL_FROM_DATABASE=82801E ISA Bridge (LPC) + +pci:v00008086d00002452* + ID_MODEL_FROM_DATABASE=82801E USB Controller + +pci:v00008086d00002453* + ID_MODEL_FROM_DATABASE=82801E SMBus Controller + +pci:v00008086d00002459* + ID_MODEL_FROM_DATABASE=82801E Ethernet Controller 0 + +pci:v00008086d0000245B* + ID_MODEL_FROM_DATABASE=82801E IDE U100 Controller + +pci:v00008086d0000245D* + ID_MODEL_FROM_DATABASE=82801E Ethernet Controller 1 + +pci:v00008086d0000245E* + ID_MODEL_FROM_DATABASE=82801E PCI Bridge + +pci:v00008086d00002480* + ID_MODEL_FROM_DATABASE=82801CA LPC Interface Controller + +pci:v00008086d00002482* + ID_MODEL_FROM_DATABASE=82801CA/CAM USB Controller #1 + +pci:v00008086d00002482sv00000E11sd00000030* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d00002482sv00001014sd00000220* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002482sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002482sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002482sv00008086sd00001958* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d00002482sv00008086sd00003424* + ID_MODEL_FROM_DATABASE=SE7501HG2 Mainboard + +pci:v00008086d00002482sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude C640 + +pci:v00008086d00002483* + ID_MODEL_FROM_DATABASE=82801CA/CAM SMBus Controller + +pci:v00008086d00002483sv00001014sd00000220* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002483sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002483sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002483sv00008086sd00001958* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d00002484* + ID_MODEL_FROM_DATABASE=82801CA/CAM USB Controller #2 + +pci:v00008086d00002484sv00000E11sd00000030* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d00002484sv00001014sd00000220* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002484sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002484sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002484sv00008086sd00001958* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d00002485* + ID_MODEL_FROM_DATABASE=82801CA/CAM AC'97 Audio Controller + +pci:v00008086d00002485sv00001013sd00005959* + ID_MODEL_FROM_DATABASE=Crystal WMD Audio Codec + +pci:v00008086d00002485sv00001014sd00000222* + ID_MODEL_FROM_DATABASE=ThinkPad A30/A30p/T23 + +pci:v00008086d00002485sv00001014sd00000508* + ID_MODEL_FROM_DATABASE=ThinkPad T30 + +pci:v00008086d00002485sv00001014sd0000051C* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002485sv00001043sd00001583* + ID_MODEL_FROM_DATABASE=L3C (SPDIF) + +pci:v00008086d00002485sv00001043sd00001623* + ID_MODEL_FROM_DATABASE=L2B (no SPDIF) + +pci:v00008086d00002485sv00001043sd00001643* + ID_MODEL_FROM_DATABASE=L3F + +pci:v00008086d00002485sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002485sv0000144Dsd0000C006* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d00002486* + ID_MODEL_FROM_DATABASE=82801CA/CAM AC'97 Modem Controller + +pci:v00008086d00002486sv00001014sd00000223* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002486sv00001014sd00000503* + ID_MODEL_FROM_DATABASE=ThinkPad R31 + +pci:v00008086d00002486sv00001014sd0000051A* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002486sv0000101Fsd00001025* + ID_MODEL_FROM_DATABASE=620 Series + +pci:v00008086d00002486sv00001043sd00001496* + ID_MODEL_FROM_DATABASE=PCtel HSP56 MR + +pci:v00008086d00002486sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002486sv0000134Dsd00004C21* + ID_MODEL_FROM_DATABASE=Dell Inspiron 2100 internal modem + +pci:v00008086d00002486sv0000144Dsd00002115* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 internal modem + +pci:v00008086d00002486sv000014F1sd00005421* + ID_MODEL_FROM_DATABASE=MD56ORD V.92 MDC Modem + +pci:v00008086d00002487* + ID_MODEL_FROM_DATABASE=82801CA/CAM USB Controller #3 + +pci:v00008086d00002487sv00000E11sd00000030* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d00002487sv00001014sd00000220* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00002487sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00002487sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002487sv00008086sd00001958* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d0000248A* + ID_MODEL_FROM_DATABASE=82801CAM IDE U100 Controller + +pci:v00008086d0000248Asv00000E11sd00000030* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d0000248Asv00001014sd00000220* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d0000248Asv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d0000248Asv00008086sd00001958* + ID_MODEL_FROM_DATABASE=vpr Matrix 170B4 + +pci:v00008086d0000248Asv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude C640 + +pci:v00008086d0000248B* + ID_MODEL_FROM_DATABASE=82801CA Ultra ATA Storage Controller + +pci:v00008086d0000248Bsv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d0000248C* + ID_MODEL_FROM_DATABASE=82801CAM ISA Bridge (LPC) + +pci:v00008086d000024C0* + ID_MODEL_FROM_DATABASE=82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge + +pci:v00008086d000024C0sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C0sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C1* + ID_MODEL_FROM_DATABASE=82801DBL (ICH4-L) IDE Controller + +pci:v00008086d000024C2* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 + +pci:v00008086d000024C2sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C2sv00001014sd0000052D* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024C2sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C2sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024C2sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024C2sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024C2sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024C2sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C2sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C2sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C2sv00001043sd00008089* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024C2sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C2sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard USB 1.x + +pci:v00008086d000024C2sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024C2sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C2sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C2sv00001509sd00002990* + ID_MODEL_FROM_DATABASE=Averatec 5110H laptop + +pci:v00008086d000024C2sv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024C2sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024C2sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024C2sv00008086sd000024C2* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024C2sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude D400/D500 + +pci:v00008086d000024C2sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024C2sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024C3* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller + +pci:v00008086d000024C3sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C3sv00001014sd0000052D* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024C3sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C3sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024C3sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024C3sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024C3sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C3sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C3sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C3sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C3sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard SMbus + +pci:v00008086d000024C3sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024C3sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C3sv00001458sd000024C2* + ID_MODEL_FROM_DATABASE=GA-8PE667 Ultra + +pci:v00008086d000024C3sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C3sv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024C3sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024C3sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024C3sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024C3sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024C4* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 + +pci:v00008086d000024C4sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C4sv00001014sd0000052D* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024C4sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C4sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024C4sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024C4sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024C4sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024C4sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C4sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C4sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C4sv00001043sd00008089* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024C4sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C4sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C4sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C4sv00001509sd00002990* + ID_MODEL_FROM_DATABASE=Averatec 5110H + +pci:v00008086d000024C4sv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024C4sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024C4sv00008086sd000024C2* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024C4sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude D400/D500 + +pci:v00008086d000024C4sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024C4sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024C5* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller + +pci:v00008086d000024C5sv00000E11sd000000B8* + ID_MODEL_FROM_DATABASE=Analog Devices Inc. codec [SoundMAX] + +pci:v00008086d000024C5sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C5sv00001014sd00000537* + ID_MODEL_FROM_DATABASE=ThinkPad T41 + +pci:v00008086d000024C5sv00001014sd0000055F* + ID_MODEL_FROM_DATABASE=Thinkpad R50e model 1634 + +pci:v00008086d000024C5sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C5sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d000024C5sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024C5sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d000024C5sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024C5sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m [SigmaTel STAC9750,51] + +pci:v00008086d000024C5sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024C5sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C5sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C5sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C5sv00001043sd00001713* + ID_MODEL_FROM_DATABASE=M2400N/M6800N laptop + +pci:v00008086d000024C5sv00001043sd000080B0* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024C5sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C5sv00001179sd00000201* + ID_MODEL_FROM_DATABASE=Toshiba Tecra M1 + +pci:v00008086d000024C5sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024C5sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C5sv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-8PE667 Ultra + +pci:v00008086d000024C5sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C5sv00001734sd00001005* + ID_MODEL_FROM_DATABASE=D1451 (SCENIC N300, i845GV) Sigmatel STAC9750T + +pci:v00008086d000024C5sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024C5sv00008086sd000024C5* + ID_MODEL_FROM_DATABASE=Dell Dimension 2400 + +pci:v00008086d000024C6* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller + +pci:v00008086d000024C6sv00001014sd00000524* + ID_MODEL_FROM_DATABASE=ThinkPad T41 + +pci:v00008086d000024C6sv00001014sd00000525* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024C6sv00001014sd00000559* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v00008086d000024C6sv00001025sd0000003C* + ID_MODEL_FROM_DATABASE=Aspire 2001WLCi (Compal CL50 motherboard) implementation + +pci:v00008086d000024C6sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C6sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024C6sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C6sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C6sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C6sv00001043sd00001716* + ID_MODEL_FROM_DATABASE=M2400N laptop + +pci:v00008086d000024C6sv00001043sd00001826* + ID_MODEL_FROM_DATABASE=M6800N + +pci:v00008086d000024C6sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C6sv0000134Dsd00004C21* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d000024C6sv0000144Dsd00002115* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024C6sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C6sv000014F1sd00005422* + ID_MODEL_FROM_DATABASE=D480 MDC V.9x Modem + +pci:v00008086d000024C7* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 + +pci:v00008086d000024C7sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024C7sv00001014sd0000052D* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024C7sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024C7sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024C7sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024C7sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024C7sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024C7sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024C7sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024C7sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024C7sv00001043sd00008089* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024C7sv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024C7sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024C7sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024C7sv00001509sd00002990* + ID_MODEL_FROM_DATABASE=Averatec 5110H + +pci:v00008086d000024C7sv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024C7sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024C7sv00008086sd000024C2* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024C7sv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude D400/D500 + +pci:v00008086d000024C7sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024C7sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024CA* + ID_MODEL_FROM_DATABASE=82801DBM (ICH4-M) IDE Controller + +pci:v00008086d000024CAsv00001014sd0000052D* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024CAsv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024CAsv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024CAsv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024CAsv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024CAsv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024CAsv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024CAsv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024CAsv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024CAsv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024CAsv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024CAsv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024CAsv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024CAsv00008086sd00004541* + ID_MODEL_FROM_DATABASE=Latitude D400/D500 + +pci:v00008086d000024CB* + ID_MODEL_FROM_DATABASE=82801DB (ICH4) IDE Controller + +pci:v00008086d000024CBsv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024CBsv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024CBsv00001043sd00008089* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024CBsv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard IDE + +pci:v00008086d000024CBsv00001458sd000024C2* + ID_MODEL_FROM_DATABASE=GA-8PE667 Ultra + +pci:v00008086d000024CBsv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024CBsv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024CBsv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024CBsv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024CBsv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024CC* + ID_MODEL_FROM_DATABASE=82801DBM (ICH4-M) LPC Interface Bridge + +pci:v00008086d000024CCsv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30 notebook + +pci:v00008086d000024CCsv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024CD* + ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller + +pci:v00008086d000024CDsv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d000024CDsv00001014sd0000052E* + ID_MODEL_FROM_DATABASE=ThinkPad + +pci:v00008086d000024CDsv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d000024CDsv00001028sd0000011D* + ID_MODEL_FROM_DATABASE=Latitude D600 + +pci:v00008086d000024CDsv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d000024CDsv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d000024CDsv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d000024CDsv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d000024CDsv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d000024CDsv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d000024CDsv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d000024CDsv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d000024CDsv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d000024CDsv00001043sd00008089* + ID_MODEL_FROM_DATABASE=P4B533 + +pci:v00008086d000024CDsv00001071sd00008160* + ID_MODEL_FROM_DATABASE=MIM2000 + +pci:v00008086d000024CDsv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 onboard USB 2.0 + +pci:v00008086d000024CDsv00001179sd0000FF00* + ID_MODEL_FROM_DATABASE=Satellite 2430 + +pci:v00008086d000024CDsv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d000024CDsv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d000024CDsv00001462sd00003981* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d000024CDsv00001509sd00001968* + ID_MODEL_FROM_DATABASE=Averatec 5110H + +pci:v00008086d000024CDsv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d000024CDsv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d000024CDsv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d000024CDsv00008086sd000024C2* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d000024CDsv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d000024CDsv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d000024D0* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) LPC Interface Bridge + +pci:v00008086d000024D1* + ID_MODEL_FROM_DATABASE=82801EB (ICH5) SATA Controller + +pci:v00008086d000024D1sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D1sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d000024D1sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024D1sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d000024D1sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800 series motherboard + +pci:v00008086d000024D1sv00001458sd000024D1* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024D1sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D1sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024D1sv00001565sd00005200* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024D1sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024D1sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024D1sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D1sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024D1sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D2* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) USB UHCI Controller #1 + +pci:v00008086d000024D2sv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D2sv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D2sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D2sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 onboard UHCI + +pci:v00008086d000024D2sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 onboard UHCI + +pci:v00008086d000024D2sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 onboard UHCI + +pci:v00008086d000024D2sv00001028sd00000183* + ID_MODEL_FROM_DATABASE=PowerEdge 1800 + +pci:v00008086d000024D2sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d000024D2sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024D2sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024D2sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d000024D2sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024D2sv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000/8KNXP motherboard + +pci:v00008086d000024D2sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D2sv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024D2sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024D2sv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX series onboard UHCI + +pci:v00008086d000024D2sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024D2sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D2sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024D2sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D3* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) SMBus Controller + +pci:v00008086d000024D3sv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D3sv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D3sv00001028sd00000156* + ID_MODEL_FROM_DATABASE=Precision 360 + +pci:v00008086d000024D3sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D3sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d330 uT + +pci:v00008086d000024D3sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d000024D3sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024D3sv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024D3sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D3sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024D3sv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024D3sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024D3sv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series SMBus + +pci:v00008086d000024D3sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024D3sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D3sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024D3sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D4* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) USB UHCI Controller #2 + +pci:v00008086d000024D4sv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D4sv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024D4sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D4sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 onboard UHCI + +pci:v00008086d000024D4sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 onboard UHCI + +pci:v00008086d000024D4sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 onboard UHCI + +pci:v00008086d000024D4sv00001028sd00000183* + ID_MODEL_FROM_DATABASE=PowerEdge 1800 + +pci:v00008086d000024D4sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d000024D4sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024D4sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024D4sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d000024D4sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024D4sv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024D4sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D4sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024D4sv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024D4sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024D4sv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series onboard UHCI + +pci:v00008086d000024D4sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024D4sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D4sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024D4sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D5* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller + +pci:v00008086d000024D5sv0000100Asd0000147B* + ID_MODEL_FROM_DATABASE=Abit IS7-E motherboard + +pci:v00008086d000024D5sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D5sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024D5sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d330 uT + +pci:v00008086d000024D5sv00001043sd000080F3* + ID_MODEL_FROM_DATABASE=P4P800 series motherboard + +pci:v00008086d000024D5sv00001043sd0000810F* + ID_MODEL_FROM_DATABASE=P5P800-MX Mainboard + +pci:v00008086d000024D5sv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-8IPE1000/8KNXP motherboard + +pci:v00008086d000024D5sv00001462sd00000080* + ID_MODEL_FROM_DATABASE=865PE Neo2-V (MS-6788) Mainboard + +pci:v00008086d000024D5sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D5sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024D5sv00008086sd0000A000* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D5sv00008086sd0000E000* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024D5sv00008086sd0000E001* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D5sv00008086sd0000E002* + ID_MODEL_FROM_DATABASE=SoundMax Intergrated Digital Audio + +pci:v00008086d000024D6* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) AC'97 Modem Controller + +pci:v00008086d000024D6sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024D7* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) USB UHCI Controller #3 + +pci:v00008086d000024D7sv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=xSeries server mainboard + +pci:v00008086d000024D7sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024D7sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 onboard UHCI + +pci:v00008086d000024D7sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 onboard UHCI + +pci:v00008086d000024D7sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 onboard UHCI + +pci:v00008086d000024D7sv00001028sd00000183* + ID_MODEL_FROM_DATABASE=PowerEdge 1800 + +pci:v00008086d000024D7sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024D7sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024D7sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024D7sv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024D7sv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024D7sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024D7sv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024D7sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024D7sv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series onboard UHCI + +pci:v00008086d000024D7sv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024D7sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024D7sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024D7sv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024DB* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) IDE Controller + +pci:v00008086d000024DBsv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024DBsv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024DBsv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024DBsv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 IDE Controller + +pci:v00008086d000024DBsv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 IDE Controller + +pci:v00008086d000024DBsv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 IDE Controller + +pci:v00008086d000024DBsv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d000024DBsv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024DBsv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024DBsv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024DBsv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024DBsv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024DBsv00001462sd00007580* + ID_MODEL_FROM_DATABASE=MSI 875P + +pci:v00008086d000024DBsv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024DBsv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024DBsv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024DBsv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series onboard IDE + +pci:v00008086d000024DBsv00008086sd000024DB* + ID_MODEL_FROM_DATABASE=P4C800 Mainboard + +pci:v00008086d000024DBsv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024DBsv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024DBsv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024DBsv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024DC* + ID_MODEL_FROM_DATABASE=82801EB (ICH5) LPC Interface Bridge + +pci:v00008086d000024DD* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller + +pci:v00008086d000024DDsv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024DDsv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d000024DDsv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024DDsv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 onboard EHCI + +pci:v00008086d000024DDsv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 onboard EHCI + +pci:v00008086d000024DDsv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 onboard EHCI + +pci:v00008086d000024DDsv00001028sd00000183* + ID_MODEL_FROM_DATABASE=PowerEdge 1800 + +pci:v00008086d000024DDsv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d000024DDsv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d000024DDsv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d530 CMT (DG746A) + +pci:v00008086d000024DDsv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d000024DDsv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024DDsv00001458sd00005006* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024DDsv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024DDsv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024DDsv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024DDsv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024DDsv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024DDsv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024DE* + ID_MODEL_FROM_DATABASE=82801EB/ER (ICH5/ICH5R) USB UHCI Controller #4 + +pci:v00008086d000024DEsv00001014sd000002ED* + ID_MODEL_FROM_DATABASE=xSeries server mainboard + +pci:v00008086d000024DEsv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000024DEsv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d000024DEsv00001458sd000024D2* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d000024DEsv00001462sd00007280* + ID_MODEL_FROM_DATABASE=865PE Neo2 (MS-6728) + +pci:v00008086d000024DEsv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d000024DEsv00001565sd00003101* + ID_MODEL_FROM_DATABASE=P4TSV Motherboard (865G) + +pci:v00008086d000024DEsv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Mainboard + +pci:v00008086d000024DEsv00001734sd0000101C* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series onboard UHCI + +pci:v00008086d000024DEsv00008086sd00003427* + ID_MODEL_FROM_DATABASE=S875WP1-E mainboard + +pci:v00008086d000024DEsv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d000024DEsv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d000024DEsv00008086sd0000524C* + ID_MODEL_FROM_DATABASE=D865PERL mainboard + +pci:v00008086d000024DF* + ID_MODEL_FROM_DATABASE=82801ER (ICH5R) SATA Controller + +pci:v00008086d00002500* + ID_MODEL_FROM_DATABASE=82820 820 (Camino) Chipset Host Bridge (MCH) + +pci:v00008086d00002500sv00001028sd00000095* + ID_MODEL_FROM_DATABASE=Precision Workstation 220 Chipset + +pci:v00008086d00002500sv00001043sd0000801C* + ID_MODEL_FROM_DATABASE=P3C-2000 system chipset + +pci:v00008086d00002501* + ID_MODEL_FROM_DATABASE=82820 820 (Camino) Chipset Host Bridge (MCH) + +pci:v00008086d00002501sv00001043sd0000801C* + ID_MODEL_FROM_DATABASE=P3C-2000 system chipset + +pci:v00008086d0000250B* + ID_MODEL_FROM_DATABASE=82820 820 (Camino) Chipset Host Bridge + +pci:v00008086d0000250F* + ID_MODEL_FROM_DATABASE=82820 820 (Camino) Chipset AGP Bridge + +pci:v00008086d00002520* + ID_MODEL_FROM_DATABASE=82805AA MTH Memory Translator Hub + +pci:v00008086d00002521* + ID_MODEL_FROM_DATABASE=82804AA MRH-S Memory Repeater Hub for SDRAM + +pci:v00008086d00002530* + ID_MODEL_FROM_DATABASE=82850 850 (Tehama) Chipset Host Bridge (MCH) + +pci:v00008086d00002530sv00001028sd000000C7* + ID_MODEL_FROM_DATABASE=Dimension 8100 + +pci:v00008086d00002530sv0000147Bsd00000507* + ID_MODEL_FROM_DATABASE=TH7II-RAID + +pci:v00008086d00002531* + ID_MODEL_FROM_DATABASE=82860 860 (Wombat) Chipset Host Bridge (MCH) + +pci:v00008086d00002531sv00001028sd000000D8* + ID_MODEL_FROM_DATABASE=Precision 530 + +pci:v00008086d00002532* + ID_MODEL_FROM_DATABASE=82850 850 (Tehama) Chipset AGP Bridge + +pci:v00008086d00002533* + ID_MODEL_FROM_DATABASE=82860 860 (Wombat) Chipset AGP Bridge + +pci:v00008086d00002534* + ID_MODEL_FROM_DATABASE=82860 860 (Wombat) Chipset PCI Bridge + +pci:v00008086d00002540* + ID_MODEL_FROM_DATABASE=E7500 Memory Controller Hub + +pci:v00008086d00002540sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002541* + ID_MODEL_FROM_DATABASE=E7500/E7501 Host RASUM Controller + +pci:v00008086d00002541sv000015D9sd00003480* + ID_MODEL_FROM_DATABASE=P4DP6 + +pci:v00008086d00002541sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d00002541sv00008086sd00003424* + ID_MODEL_FROM_DATABASE=SE7501HG2 Mainboard + +pci:v00008086d00002543* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface B PCI-to-PCI Bridge + +pci:v00008086d00002544* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface B RASUM Controller + +pci:v00008086d00002544sv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d00002545* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface C PCI-to-PCI Bridge + +pci:v00008086d00002546* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface C RASUM Controller + +pci:v00008086d00002547* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface D PCI-to-PCI Bridge + +pci:v00008086d00002548* + ID_MODEL_FROM_DATABASE=E7500/E7501 Hub Interface D RASUM Controller + +pci:v00008086d0000254C* + ID_MODEL_FROM_DATABASE=E7501 Memory Controller Hub + +pci:v00008086d0000254Csv00004C53sd00001090* + ID_MODEL_FROM_DATABASE=Cx9 / Vx9 mainboard + +pci:v00008086d0000254Csv00008086sd00003424* + ID_MODEL_FROM_DATABASE=SE7501HG2 Mainboard + +pci:v00008086d00002550* + ID_MODEL_FROM_DATABASE=E7505 Memory Controller Hub + +pci:v00008086d00002551* + ID_MODEL_FROM_DATABASE=E7505/E7205 Series RAS Controller + +pci:v00008086d00002552* + ID_MODEL_FROM_DATABASE=E7505/E7205 PCI-to-AGP Bridge + +pci:v00008086d00002553* + ID_MODEL_FROM_DATABASE=E7505 Hub Interface B PCI-to-PCI Bridge + +pci:v00008086d00002554* + ID_MODEL_FROM_DATABASE=E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller + +pci:v00008086d0000255D* + ID_MODEL_FROM_DATABASE=E7205 Memory Controller Hub + +pci:v00008086d00002560* + ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface + +pci:v00008086d00002560sv00001028sd00000126* + ID_MODEL_FROM_DATABASE=Optiplex GX260 + +pci:v00008086d00002560sv00001458sd00002560* + ID_MODEL_FROM_DATABASE=GA-8PE667 Ultra + +pci:v00008086d00002560sv00001462sd00005800* + ID_MODEL_FROM_DATABASE=845PE Max (MS-6580) + +pci:v00008086d00002561* + ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE/PE Host-to-AGP Bridge + +pci:v00008086d00002562* + ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device + +pci:v00008086d00002562sv00000E11sd000000B9* + ID_MODEL_FROM_DATABASE=Evo D510 SFF + +pci:v00008086d00002562sv00001014sd00000267* + ID_MODEL_FROM_DATABASE=NetVista A30p + +pci:v00008086d00002562sv00001734sd00001003* + ID_MODEL_FROM_DATABASE=D1521 Mainboard (Fujitsu-Siemens) + +pci:v00008086d00002562sv00001734sd00001004* + ID_MODEL_FROM_DATABASE=D1451 Mainboard (SCENIC N300, i845GV) + +pci:v00008086d00002570* + ID_MODEL_FROM_DATABASE=82865G/PE/P DRAM Controller/Host-Hub Interface + +pci:v00008086d00002570sv0000103Csd0000006A* + ID_MODEL_FROM_DATABASE=NX9500 + +pci:v00008086d00002570sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=d330 uT + +pci:v00008086d00002570sv00001043sd000080F2* + ID_MODEL_FROM_DATABASE=P4P800/P5P800 series motherboard + +pci:v00008086d00002570sv00001458sd00002570* + ID_MODEL_FROM_DATABASE=GA-8IPE1000 Pro2 motherboard (865PE) + +pci:v00008086d00002571* + ID_MODEL_FROM_DATABASE=82865G/PE/P AGP Bridge + +pci:v00008086d00002572* + ID_MODEL_FROM_DATABASE=82865G Integrated Graphics Controller + +pci:v00008086d00002572sv00001028sd0000019D* + ID_MODEL_FROM_DATABASE=Dimension 3000 + +pci:v00008086d00002572sv0000103Csd000012BC* + ID_MODEL_FROM_DATABASE=D530 sff(dc578av) + +pci:v00008086d00002572sv00001043sd000080A5* + ID_MODEL_FROM_DATABASE=P5P800-MX Mainboard + +pci:v00008086d00002572sv00001462sd00007650* + ID_MODEL_FROM_DATABASE=Hetis 865GV-E (MS-7065) + +pci:v00008086d00002572sv00001734sd0000101B* + ID_MODEL_FROM_DATABASE=Fujitsu-Siemens Scenic E300 i865GV + +pci:v00008086d00002572sv00008086sd00004246* + ID_MODEL_FROM_DATABASE=Desktop Board D865GBF + +pci:v00008086d00002572sv00008086sd00004C43* + ID_MODEL_FROM_DATABASE=Desktop Board D865GLC + +pci:v00008086d00002573* + ID_MODEL_FROM_DATABASE=82865G/PE/P PCI to CSA Bridge + +pci:v00008086d00002576* + ID_MODEL_FROM_DATABASE=82865G/PE/P Processor to I/O Memory Interface + +pci:v00008086d00002578* + ID_MODEL_FROM_DATABASE=82875P/E7210 Memory Controller Hub + +pci:v00008086d00002578sv00001458sd00002578* + ID_MODEL_FROM_DATABASE=GA-8KNXP motherboard (875P) + +pci:v00008086d00002578sv00001462sd00007580* + ID_MODEL_FROM_DATABASE=MS-6758 (875P Neo) + +pci:v00008086d00002578sv000015D9sd00004580* + ID_MODEL_FROM_DATABASE=P4SCE Motherboard + +pci:v00008086d00002579* + ID_MODEL_FROM_DATABASE=82875P Processor to AGP Controller + +pci:v00008086d0000257B* + ID_MODEL_FROM_DATABASE=82875P/E7210 Processor to PCI to CSA Bridge + +pci:v00008086d0000257E* + ID_MODEL_FROM_DATABASE=82875P/E7210 Processor to I/O Memory Interface + +pci:v00008086d00002580* + ID_MODEL_FROM_DATABASE=82915G/P/GV/GL/PL/910GL Memory Controller Hub + +pci:v00008086d00002580sv00001458sd00002580* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d00002580sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d00002580sv00001734sd0000105B* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002581* + ID_MODEL_FROM_DATABASE=82915G/P/GV/GL/PL/910GL PCI Express Root Port + +pci:v00008086d00002582* + ID_MODEL_FROM_DATABASE=82915G/GV/910GL Integrated Graphics Controller + +pci:v00008086d00002582sv00001028sd00001079* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d00002582sv0000103Csd00003006* + ID_MODEL_FROM_DATABASE=DC7100 SFF(DX878AV) + +pci:v00008086d00002582sv00001043sd00002582* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002582sv00001458sd00002582* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d00002582sv00001734sd0000105B* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002582sv00001849sd00002582* + ID_MODEL_FROM_DATABASE=ASRock P4Dual-915GL + +pci:v00008086d00002584* + ID_MODEL_FROM_DATABASE=82925X/XE Memory Controller Hub + +pci:v00008086d00002584sv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d00002585* + ID_MODEL_FROM_DATABASE=82925X/XE PCI Express Root Port + +pci:v00008086d00002588* + ID_MODEL_FROM_DATABASE=E7220/E7221 Memory Controller Hub + +pci:v00008086d00002589* + ID_MODEL_FROM_DATABASE=E7220/E7221 PCI Express Root Port + +pci:v00008086d0000258A* + ID_MODEL_FROM_DATABASE=E7221 Integrated Graphics Controller + +pci:v00008086d00002590* + ID_MODEL_FROM_DATABASE=Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller + +pci:v00008086d00002590sv00001014sd00000575* + ID_MODEL_FROM_DATABASE=ThinkPad Z60t + +pci:v00008086d00002590sv00001028sd00000182* + ID_MODEL_FROM_DATABASE=Dell Latitude C610 + +pci:v00008086d00002590sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d00002590sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002590sv0000104Dsd000081B7* + ID_MODEL_FROM_DATABASE=Vaio VGN-S3XP + +pci:v00008086d00002590sv0000A304sd000081B7* + ID_MODEL_FROM_DATABASE=Vaio VGN-S3XP + +pci:v00008086d00002590sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002590sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002590sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002591* + ID_MODEL_FROM_DATABASE=Mobile 915GM/PM Express PCI Express Root Port + +pci:v00008086d00002591sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=HP Compaq nw8240 Mobile Workstation + +pci:v00008086d00002592* + ID_MODEL_FROM_DATABASE=Mobile 915GM/GMS/910GML Express Graphics Controller + +pci:v00008086d00002592sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002592sv0000103Csd0000308A* + ID_MODEL_FROM_DATABASE=NC6220 + +pci:v00008086d00002592sv00001043sd00001881* + ID_MODEL_FROM_DATABASE=GMA 900 915GM Integrated Graphics + +pci:v00008086d00002592sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002592sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002592sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d000025A1* + ID_MODEL_FROM_DATABASE=6300ESB LPC Interface Controller + +pci:v00008086d000025A2* + ID_MODEL_FROM_DATABASE=6300ESB PATA Storage Controller + +pci:v00008086d000025A2sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025A2sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer IDE + +pci:v00008086d000025A2sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025A2sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025A2sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025A2sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025A3* + ID_MODEL_FROM_DATABASE=6300ESB SATA Storage Controller + +pci:v00008086d000025A3sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025A3sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025A3sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025A3sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025A3sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025A3sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025A4* + ID_MODEL_FROM_DATABASE=6300ESB SMBus Controller + +pci:v00008086d000025A4sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025A4sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d000025A4sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025A4sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025A4sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025A4sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025A4sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025A6* + ID_MODEL_FROM_DATABASE=6300ESB AC'97 Audio Controller + +pci:v00008086d000025A6sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025A6sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025A6sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025A7* + ID_MODEL_FROM_DATABASE=6300ESB AC'97 Modem Controller + +pci:v00008086d000025A9* + ID_MODEL_FROM_DATABASE=6300ESB USB Universal Host Controller + +pci:v00008086d000025A9sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025A9sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer USB + +pci:v00008086d000025A9sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025A9sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025A9sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025A9sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025A9sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025AA* + ID_MODEL_FROM_DATABASE=6300ESB USB Universal Host Controller + +pci:v00008086d000025AAsv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025AAsv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025AAsv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025AAsv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025AAsv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025AAsv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025AB* + ID_MODEL_FROM_DATABASE=6300ESB Watchdog Timer + +pci:v00008086d000025ABsv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025ABsv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d000025ABsv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025ABsv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025ABsv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025ABsv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025ABsv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025AC* + ID_MODEL_FROM_DATABASE=6300ESB I/O Advanced Programmable Interrupt Controller + +pci:v00008086d000025ACsv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025ACsv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d000025ACsv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025ACsv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025ACsv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025ACsv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025ACsv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025AD* + ID_MODEL_FROM_DATABASE=6300ESB USB2 Enhanced Host Controller + +pci:v00008086d000025ADsv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d000025ADsv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer USB 2.0 + +pci:v00008086d000025ADsv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025ADsv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d000025ADsv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d000025ADsv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025ADsv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025AE* + ID_MODEL_FROM_DATABASE=6300ESB 64-bit PCI-X Bridge + +pci:v00008086d000025B0* + ID_MODEL_FROM_DATABASE=6300ESB SATA RAID Controller + +pci:v00008086d000025B0sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d000025B0sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d000025B0sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d000025C0* + ID_MODEL_FROM_DATABASE=5000X Chipset Memory Controller Hub + +pci:v00008086d000025D0* + ID_MODEL_FROM_DATABASE=5000Z Chipset Memory Controller Hub + +pci:v00008086d000025D4* + ID_MODEL_FROM_DATABASE=5000V Chipset Memory Controller Hub + +pci:v00008086d000025D4sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025D8* + ID_MODEL_FROM_DATABASE=5000P Chipset Memory Controller Hub + +pci:v00008086d000025D8sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025D8sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025E2* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 2 + +pci:v00008086d000025E3* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 3 + +pci:v00008086d000025E4* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 4 + +pci:v00008086d000025E5* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 5 + +pci:v00008086d000025E6* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 6 + +pci:v00008086d000025E7* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x4 Port 7 + +pci:v00008086d000025F0* + ID_MODEL_FROM_DATABASE=5000 Series Chipset FSB Registers + +pci:v00008086d000025F0sv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 FSB Registers + +pci:v00008086d000025F0sv0000103Csd000031FD* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d000025F0sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025F0sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025F0sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025F1* + ID_MODEL_FROM_DATABASE=5000 Series Chipset Reserved Registers + +pci:v00008086d000025F1sv0000103Csd000031FD* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d000025F1sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025F1sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025F1sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025F3* + ID_MODEL_FROM_DATABASE=5000 Series Chipset Reserved Registers + +pci:v00008086d000025F3sv0000103Csd000031FD* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d000025F3sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025F3sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025F3sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025F5* + ID_MODEL_FROM_DATABASE=5000 Series Chipset FBD Registers + +pci:v00008086d000025F5sv0000103Csd000031FD* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d000025F5sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025F5sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025F5sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025F6* + ID_MODEL_FROM_DATABASE=5000 Series Chipset FBD Registers + +pci:v00008086d000025F6sv0000103Csd000031FD* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d000025F6sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d000025F6sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d000025F6sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=S5000PSLSATA Server Board + +pci:v00008086d000025F7* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x8 Port 2-3 + +pci:v00008086d000025F8* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x8 Port 4-5 + +pci:v00008086d000025F9* + ID_MODEL_FROM_DATABASE=5000 Series Chipset PCI Express x8 Port 6-7 + +pci:v00008086d000025FA* + ID_MODEL_FROM_DATABASE=5000X Chipset PCI Express x16 Port 4-7 + +pci:v00008086d00002600* + ID_MODEL_FROM_DATABASE=E8500/E8501 Hub Interface 1.5 + +pci:v00008086d00002600sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Hub Interface + +pci:v00008086d00002601* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port D + +pci:v00008086d00002602* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port C0 + +pci:v00008086d00002603* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port C1 + +pci:v00008086d00002604* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port B0 + +pci:v00008086d00002605* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port B1 + +pci:v00008086d00002606* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port A0 + +pci:v00008086d00002607* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x4 Port A1 + +pci:v00008086d00002608* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x8 Port C + +pci:v00008086d00002609* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x8 Port B + +pci:v00008086d0000260A* + ID_MODEL_FROM_DATABASE=E8500/E8501 PCI Express x8 Port A + +pci:v00008086d0000260C* + ID_MODEL_FROM_DATABASE=E8500/E8501 IMI Registers + +pci:v00008086d00002610* + ID_MODEL_FROM_DATABASE=E8500/E8501 FSB Registers + +pci:v00008086d00002611* + ID_MODEL_FROM_DATABASE=E8500/E8501 Address Mapping Registers + +pci:v00008086d00002612* + ID_MODEL_FROM_DATABASE=E8500/E8501 RAS Registers + +pci:v00008086d00002613* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d00002614* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d00002615* + ID_MODEL_FROM_DATABASE=E8500/E8501 Miscellaneous Registers + +pci:v00008086d00002617* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d00002618* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d00002619* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d0000261A* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d0000261B* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d0000261C* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d0000261D* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d0000261E* + ID_MODEL_FROM_DATABASE=E8500/E8501 Reserved Registers + +pci:v00008086d00002620* + ID_MODEL_FROM_DATABASE=E8500/E8501 eXternal Memory Bridge + +pci:v00008086d00002620sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Memory Bridge + +pci:v00008086d00002621* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Miscellaneous Registers + +pci:v00008086d00002621sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 XMB Registers + +pci:v00008086d00002622* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Memory Interleaving Registers + +pci:v00008086d00002622sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Memory Interleaving Registers + +pci:v00008086d00002623* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB DDR Initialization and Calibration + +pci:v00008086d00002623sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 DDR Initialization and Calibration + +pci:v00008086d00002624* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Reserved Registers + +pci:v00008086d00002624sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Reserved Registers + +pci:v00008086d00002625* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Reserved Registers + +pci:v00008086d00002625sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Reserved Registers + +pci:v00008086d00002626* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Reserved Registers + +pci:v00008086d00002626sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Reserved Registers + +pci:v00008086d00002627* + ID_MODEL_FROM_DATABASE=E8500/E8501 XMB Reserved Registers + +pci:v00008086d00002627sv00001028sd00000170* + ID_MODEL_FROM_DATABASE=PowerEdge 6850 Reserved Registers + +pci:v00008086d00002640* + ID_MODEL_FROM_DATABASE=82801FB/FR (ICH6/ICH6R) LPC Interface Bridge + +pci:v00008086d00002640sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d00002640sv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002640sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002640sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002640sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002641* + ID_MODEL_FROM_DATABASE=82801FBM (ICH6M) LPC Interface Bridge + +pci:v00008086d00002641sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d00002641sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002642* + ID_MODEL_FROM_DATABASE=82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge + +pci:v00008086d00002651* + ID_MODEL_FROM_DATABASE=82801FB/FW (ICH6/ICH6W) SATA Controller + +pci:v00008086d00002651sv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d00002651sv00001043sd00002601* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002651sv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002651sv00008086sd00004147* + ID_MODEL_FROM_DATABASE=D915GAG Motherboard + +pci:v00008086d00002651sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002651sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002651sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002652* + ID_MODEL_FROM_DATABASE=82801FR/FRW (ICH6R/ICH6RW) SATA Controller + +pci:v00008086d00002652sv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d00002652sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d00002653* + ID_MODEL_FROM_DATABASE=82801FBM (ICH6M) SATA Controller + +pci:v00008086d00002658* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1 + +pci:v00008086d00002658sv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d00002658sv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d00002658sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d00002658sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002658sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002658sv00001458sd00002558* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d00002658sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d00002658sv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002658sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002658sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002658sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002659* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2 + +pci:v00008086d00002659sv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d00002659sv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d00002659sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d00002659sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002659sv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002659sv00001458sd00002659* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d00002659sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d00002659sv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002659sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002659sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002659sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d0000265A* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3 + +pci:v00008086d0000265Asv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000265Asv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d0000265Asv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d0000265Asv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000265Asv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d0000265Asv00001458sd0000265A* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000265Asv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000265Asv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000265Asv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d0000265Asv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d0000265Asv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d0000265B* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4 + +pci:v00008086d0000265Bsv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000265Bsv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d0000265Bsv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000265Bsv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d0000265Bsv00001458sd0000265A* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000265Bsv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000265Bsv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000265Bsv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d0000265Bsv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d0000265Bsv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d0000265C* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller + +pci:v00008086d0000265Csv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000265Csv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d0000265Csv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d0000265Csv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000265Csv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d0000265Csv00001458sd00005006* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000265Csv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000265Csv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000265Csv00008086sd0000265C* + ID_MODEL_FROM_DATABASE=Dimension 3100 + +pci:v00008086d0000265Csv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d0000265Csv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d0000265Csv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002660* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1 + +pci:v00008086d00002660sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=HP Compaq nw8240 Mobile Workstation + +pci:v00008086d00002660sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002660sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002660sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002660sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002662* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2 + +pci:v00008086d00002662sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=HP Compaq nw8240 Mobile Workstation + +pci:v00008086d00002662sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002662sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002662sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002664* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3 + +pci:v00008086d00002664sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002664sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002664sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002666* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4 + +pci:v00008086d00002666sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002666sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002666sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002668* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller + +pci:v00008086d00002668sv00001014sd000005B7* + ID_MODEL_FROM_DATABASE=ThinkPad Z60t + +pci:v00008086d00002668sv0000103Csd00002A09* + ID_MODEL_FROM_DATABASE=PufferM-UL8E + +pci:v00008086d00002668sv00001043sd00001173* + ID_MODEL_FROM_DATABASE=Asus A6VC + +pci:v00008086d00002668sv00001043sd0000814E* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002668sv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000266A* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller + +pci:v00008086d0000266Asv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000266Asv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d0000266Asv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d0000266Asv00001458sd0000266A* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000266Asv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000266Asv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000266Asv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d0000266Asv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d0000266Asv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d0000266C* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller + +pci:v00008086d0000266D* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller + +pci:v00008086d0000266Dsv00001025sd0000006A* + ID_MODEL_FROM_DATABASE=Conexant AC'97 CoDec (in Acer TravelMate 2410 serie laptop) + +pci:v00008086d0000266Dsv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d0000266Dsv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000266E* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller + +pci:v00008086d0000266Esv00001025sd0000006A* + ID_MODEL_FROM_DATABASE=Realtek ALC 655 codec (in Acer TravelMate 2410 serie laptop) + +pci:v00008086d0000266Esv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000266Esv00001028sd00000179* + ID_MODEL_FROM_DATABASE=Optiplex GX280 + +pci:v00008086d0000266Esv00001028sd00000182* + ID_MODEL_FROM_DATABASE=Latitude D610 Laptop + +pci:v00008086d0000266Esv00001028sd00000187* + ID_MODEL_FROM_DATABASE=Dell Precision M70 Laptop + +pci:v00008086d0000266Esv00001028sd00000188* + ID_MODEL_FROM_DATABASE=Inspiron 6000 laptop + +pci:v00008086d0000266Esv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d0000266Esv0000103Csd00000944* + ID_MODEL_FROM_DATABASE=Compaq NC6220 + +pci:v00008086d0000266Esv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000266Esv0000103Csd00003006* + ID_MODEL_FROM_DATABASE=DC7100 SFF(DX878AV) + +pci:v00008086d0000266Esv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000266Esv0000152Dsd00000745* + ID_MODEL_FROM_DATABASE=Packard Bell A8550 Laptop + +pci:v00008086d0000266Esv00001734sd0000105A* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000266F* + ID_MODEL_FROM_DATABASE=82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller + +pci:v00008086d0000266Fsv00001028sd00000177* + ID_MODEL_FROM_DATABASE=Dimension 8400 + +pci:v00008086d0000266Fsv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d0000266Fsv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d0000266Fsv00001043sd000080A6* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d0000266Fsv00001458sd0000266F* + ID_MODEL_FROM_DATABASE=GA-8I915ME-G Mainboard + +pci:v00008086d0000266Fsv00001462sd00007028* + ID_MODEL_FROM_DATABASE=915P/G Neo2 + +pci:v00008086d0000266Fsv00001734sd0000105C* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d0000266Fsv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d0000266Fsv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d0000266Fsv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d00002670* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset LPC Interface Controller + +pci:v00008086d00002670sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002670sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00002670sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002670sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00002680* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset SATA IDE Controller + +pci:v00008086d00002681* + ID_MODEL_FROM_DATABASE=631xESB/632xESB SATA AHCI Controller + +pci:v00008086d00002681sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002681sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00002681sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002681sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00002682* + ID_MODEL_FROM_DATABASE=631xESB/632xESB SATA RAID Controller + +pci:v00008086d00002682sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=Adaptec Serial ATA HostRAID + +pci:v00008086d00002683* + ID_MODEL_FROM_DATABASE=631xESB/632xESB SATA RAID Controller + +pci:v00008086d00002688* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset UHCI USB Controller #1 + +pci:v00008086d00002688sv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 onboard USB + +pci:v00008086d00002688sv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 onboard USB + +pci:v00008086d00002688sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002688sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00002688sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002688sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00002689* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset UHCI USB Controller #2 + +pci:v00008086d00002689sv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 onboard USB + +pci:v00008086d00002689sv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 onboard USB + +pci:v00008086d00002689sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002689sv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d00002689sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002689sv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d0000268A* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset UHCI USB Controller #3 + +pci:v00008086d0000268Asv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 onboard USB + +pci:v00008086d0000268Asv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000268Asv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d0000268Asv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d0000268Asv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d0000268B* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset UHCI USB Controller #4 + +pci:v00008086d0000268Bsv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 onboard USB + +pci:v00008086d0000268Bsv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d0000268Bsv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d0000268C* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset EHCI USB2 Controller + +pci:v00008086d0000268Csv00001028sd000001BB* + ID_MODEL_FROM_DATABASE=PowerEdge 1955 onboard USB + +pci:v00008086d0000268Csv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 onboard USB + +pci:v00008086d0000268Csv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000268Csv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d0000268Csv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d0000268Csv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d00002690* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset PCI Express Root Port 1 + +pci:v00008086d00002690sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002690sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002692* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset PCI Express Root Port 2 + +pci:v00008086d00002692sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00002694* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset PCI Express Root Port 3 + +pci:v00008086d00002696* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset PCI Express Root Port 4 + +pci:v00008086d00002698* + ID_MODEL_FROM_DATABASE=631xESB/632xESB AC '97 Audio Controller + +pci:v00008086d00002699* + ID_MODEL_FROM_DATABASE=631xESB/632xESB AC '97 Modem Controller + +pci:v00008086d0000269A* + ID_MODEL_FROM_DATABASE=631xESB/632xESB High Definition Audio Controller + +pci:v00008086d0000269B* + ID_MODEL_FROM_DATABASE=631xESB/632xESB/3100 Chipset SMBus Controller + +pci:v00008086d0000269Bsv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000269Bsv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d0000269Bsv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d0000269Bsv00008086sd00003476* + ID_MODEL_FROM_DATABASE=Intel S5000PSLSATA Server Board + +pci:v00008086d0000269E* + ID_MODEL_FROM_DATABASE=631xESB/632xESB IDE Controller + +pci:v00008086d0000269Esv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000269Esv000015D9sd00008680* + ID_MODEL_FROM_DATABASE=X7DVL-E-O motherboard + +pci:v00008086d0000269Esv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00002770* + ID_MODEL_FROM_DATABASE=82945G/GZ/P/PL Memory Controller Hub + +pci:v00008086d00002770sv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d00002770sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d00002770sv00001043sd0000817A* + ID_MODEL_FROM_DATABASE=P5LD2-VM Mainboard + +pci:v00008086d00002770sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d00002770sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d00002771* + ID_MODEL_FROM_DATABASE=82945G/GZ/P/PL PCI Express Root Port + +pci:v00008086d00002772* + ID_MODEL_FROM_DATABASE=82945G/GZ Integrated Graphics Controller + +pci:v00008086d00002772sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d00002772sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d00002772sv00008086sd0000D605* + ID_MODEL_FROM_DATABASE=Intel Desktop Board D945GCCR + +pci:v00008086d00002774* + ID_MODEL_FROM_DATABASE=82955X Memory Controller Hub + +pci:v00008086d00002775* + ID_MODEL_FROM_DATABASE=82955X PCI Express Root Port + +pci:v00008086d00002776* + ID_MODEL_FROM_DATABASE=82945G/GZ Integrated Graphics Controller + +pci:v00008086d00002778* + ID_MODEL_FROM_DATABASE=E7230/3000/3010 Memory Controller Hub + +pci:v00008086d00002778sv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d00002778sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d00002779* + ID_MODEL_FROM_DATABASE=E7230/3000/3010 PCI Express Root Port + +pci:v00008086d0000277A* + ID_MODEL_FROM_DATABASE=82975X/3010 PCI Express Root Port + +pci:v00008086d0000277C* + ID_MODEL_FROM_DATABASE=82975X Memory Controller Hub + +pci:v00008086d0000277Csv00001043sd00008178* + ID_MODEL_FROM_DATABASE=P5WDG2 WS Professional motherboard + +pci:v00008086d0000277D* + ID_MODEL_FROM_DATABASE=82975X PCI Express Root Port + +pci:v00008086d00002782* + ID_MODEL_FROM_DATABASE=82915G Integrated Graphics Controller + +pci:v00008086d00002782sv00001043sd00002582* + ID_MODEL_FROM_DATABASE=P5GD1-VW Mainboard + +pci:v00008086d00002782sv00001734sd0000105B* + ID_MODEL_FROM_DATABASE=Scenic W620 + +pci:v00008086d00002792* + ID_MODEL_FROM_DATABASE=Mobile 915GM/GMS/910GML Express Graphics Controller + +pci:v00008086d00002792sv0000103Csd0000099C* + ID_MODEL_FROM_DATABASE=NX6110/NC6120 + +pci:v00008086d00002792sv00001043sd00001881* + ID_MODEL_FROM_DATABASE=GMA 900 915GM Integrated Graphics + +pci:v00008086d00002792sv0000E4BFsd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v00008086d00002792sv0000E4BFsd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v00008086d00002792sv0000E4BFsd000058B1* + ID_MODEL_FROM_DATABASE=XB1 + +pci:v00008086d000027A0* + ID_MODEL_FROM_DATABASE=Mobile 945GM/PM/GMS, 943/940GML and 945GT Express Memory Controller Hub + +pci:v00008086d000027A0sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027A0sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027A0sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027A0sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027A0sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027A0sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027A0sv000017AAsd00002015* + ID_MODEL_FROM_DATABASE=ThinkPad T60 + +pci:v00008086d000027A0sv000017AAsd00002017* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027A1* + ID_MODEL_FROM_DATABASE=Mobile 945GM/PM/GMS, 943/940GML and 945GT Express PCI Express Root Port + +pci:v00008086d000027A1sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027A1sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027A2* + ID_MODEL_FROM_DATABASE=Mobile 945GM/GMS, 943/940GML Express Integrated Graphics Controller + +pci:v00008086d000027A2sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027A2sv000017AAsd0000201A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027A2sv00009902sd00001584* + ID_MODEL_FROM_DATABASE=CCE MPL-D10H120F + +pci:v00008086d000027A6* + ID_MODEL_FROM_DATABASE=Mobile 945GM/GMS/GME, 943/940GML Express Integrated Graphics Controller + +pci:v00008086d000027A6sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027A6sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 integrated graphics (secondary) + +pci:v00008086d000027A6sv000017AAsd0000201A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027AC* + ID_MODEL_FROM_DATABASE=Mobile 945GSE Express Memory Controller Hub + +pci:v00008086d000027ACsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027AD* + ID_MODEL_FROM_DATABASE=Mobile 945GSE Express PCI Express Root Port + +pci:v00008086d000027AE* + ID_MODEL_FROM_DATABASE=Mobile 945GSE Express Integrated Graphics Controller + +pci:v00008086d000027AEsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 integrated graphics (primary) + +pci:v00008086d000027B0* + ID_MODEL_FROM_DATABASE=82801GH (ICH7DH) LPC Interface Bridge + +pci:v00008086d000027B0sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027B0sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027B8* + ID_MODEL_FROM_DATABASE=82801GB/GR (ICH7 Family) LPC Interface Bridge + +pci:v00008086d000027B8sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027B8sv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000027B8sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027B8sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027B8sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027B9* + ID_MODEL_FROM_DATABASE=82801GBM (ICH7-M) LPC Interface Bridge + +pci:v00008086d000027B9sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027B9sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027B9sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027B9sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027B9sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00008086d000027B9sv000017AAsd00002009* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027BC* + ID_MODEL_FROM_DATABASE=NM10 Family LPC Controller + +pci:v00008086d000027BCsv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027BCsv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027BCsv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027BCsv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027BCsv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027BD* + ID_MODEL_FROM_DATABASE=82801GHM (ICH7-M DH) LPC Interface Bridge + +pci:v00008086d000027BDsv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027C0* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family SATA Controller [IDE mode] + +pci:v00008086d000027C0sv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027C0sv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027C0sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027C0sv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000027C0sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027C0sv00001462sd00002310* + ID_MODEL_FROM_DATABASE=MSI Hetis 945 + +pci:v00008086d000027C0sv00001462sd00007236* + ID_MODEL_FROM_DATABASE=945P Neo3-F Rev. 2.2 motherboard + +pci:v00008086d000027C0sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027C0sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027C0sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027C1* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family SATA Controller [AHCI mode] + +pci:v00008086d000027C1sv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027C1sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027C1sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027C1sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027C1sv00001458sd0000B005* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027C1sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027C1sv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027C1sv00008086sd00005842* + ID_MODEL_FROM_DATABASE=DeskTop Board D975XBX + +pci:v00008086d000027C3* + ID_MODEL_FROM_DATABASE=82801GR/GDH (ICH7R/ICH7DH) SATA Controller [RAID mode] + +pci:v00008086d000027C3sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027C3sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027C4* + ID_MODEL_FROM_DATABASE=82801GBM/GHM (ICH7-M Family) SATA Controller [IDE mode] + +pci:v00008086d000027C4sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027C4sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027C4sv000017AAsd0000200E* + ID_MODEL_FROM_DATABASE=Thinkpad T60 model 2007 + +pci:v00008086d000027C5* + ID_MODEL_FROM_DATABASE=82801GBM/GHM (ICH7-M Family) SATA Controller [AHCI mode] + +pci:v00008086d000027C5sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027C5sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027C5sv000017AAsd0000200D* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027C6* + ID_MODEL_FROM_DATABASE=82801GHM (ICH7-M DH) SATA Controller [RAID mode] + +pci:v00008086d000027C8* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family USB UHCI Controller #1 + +pci:v00008086d000027C8sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027C8sv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027C8sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027C8sv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027C8sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027C8sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027C8sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027C8sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027C8sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027C8sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027C8sv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM,P5LD2-VM Mainboard + +pci:v00008086d000027C8sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027C8sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027C8sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027C8sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027C8sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027C8sv000017AAsd0000200A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027C8sv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027C8sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027C8sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027C9* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family USB UHCI Controller #2 + +pci:v00008086d000027C9sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027C9sv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027C9sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027C9sv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027C9sv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027C9sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027C9sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027C9sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027C9sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027C9sv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027C9sv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM,P5LD2-VM Mainboard + +pci:v00008086d000027C9sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027C9sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027C9sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027C9sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027C9sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027C9sv000017AAsd0000200A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027C9sv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027C9sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027C9sv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027CA* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family USB UHCI Controller #3 + +pci:v00008086d000027CAsv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027CAsv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027CAsv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027CAsv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027CAsv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027CAsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027CAsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027CAsv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027CAsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027CAsv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027CAsv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM,P5LD2-VM Mainboard + +pci:v00008086d000027CAsv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027CAsv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027CAsv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027CAsv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027CAsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027CAsv000017AAsd0000200A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027CAsv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027CAsv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027CB* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family USB UHCI Controller #4 + +pci:v00008086d000027CBsv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027CBsv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027CBsv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027CBsv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027CBsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027CBsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027CBsv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027CBsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027CBsv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027CBsv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM,P5LD2-VM Mainboard + +pci:v00008086d000027CBsv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027CBsv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027CBsv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027CBsv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027CBsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027CBsv000017AAsd0000200A* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027CBsv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027CBsv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027CC* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family USB2 EHCI Controller + +pci:v00008086d000027CCsv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027CCsv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027CCsv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027CCsv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027CCsv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027CCsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027CCsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027CCsv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027CCsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027CCsv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027CCsv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM,P5LD2-VM Mainboard + +pci:v00008086d000027CCsv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027CCsv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027CCsv00001458sd00005006* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027CCsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027CCsv000017AAsd0000200B* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027CCsv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027CCsv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027CCsv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027D0* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family PCI Express Port 1 + +pci:v00008086d000027D0sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027D0sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027D0sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027D0sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d000027D0sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027D0sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027D2* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family PCI Express Port 2 + +pci:v00008086d000027D2sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027D2sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027D2sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027D2sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027D2sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027D4* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family PCI Express Port 3 + +pci:v00008086d000027D4sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027D4sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027D4sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027D6* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family PCI Express Port 4 + +pci:v00008086d000027D6sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027D6sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027D6sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027D6sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027D8* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family High Definition Audio Controller + +pci:v00008086d000027D8sv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027D8sv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027D8sv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027D8sv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027D8sv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027D8sv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027D8sv00001043sd00001123* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027D8sv00001043sd000013C4* + ID_MODEL_FROM_DATABASE=Asus G2P + +pci:v00008086d000027D8sv00001043sd0000817F* + ID_MODEL_FROM_DATABASE=P5LD2-VM Mainboard (Realtek ALC 882 codec) + +pci:v00008086d000027D8sv00001043sd00008290* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000027D8sv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P5KPL-CM Motherboard + +pci:v00008086d000027D8sv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027D8sv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027D8sv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00008086d000027D8sv00001179sd0000FF10* + ID_MODEL_FROM_DATABASE=Toshiba Satellite A100-796 audio (Realtek ALC861) + +pci:v00008086d000027D8sv00001179sd0000FF31* + ID_MODEL_FROM_DATABASE=AC97 Data Fax SoftModem with SmartCP + +pci:v00008086d000027D8sv00001447sd00001043* + ID_MODEL_FROM_DATABASE=Asus A8JP (Analog Devices AD1986A) + +pci:v00008086d000027D8sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027D8sv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-D525TUD (Realtek ALC887) + +pci:v00008086d000027D8sv00001458sd0000A102* + ID_MODEL_FROM_DATABASE=GA-8I945PG-RH Mainboard + +pci:v00008086d000027D8sv0000152Dsd00000753* + ID_MODEL_FROM_DATABASE=Softmodem + +pci:v00008086d000027D8sv00001734sd000010AD* + ID_MODEL_FROM_DATABASE=Conexant softmodem SmartCP + +pci:v00008086d000027D8sv000017AAsd00002010* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027D8sv000017AAsd00003802* + ID_MODEL_FROM_DATABASE=Lenovo 3000 C200 audio [Realtek ALC861VD] + +pci:v00008086d000027D8sv00008086sd00001112* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027D8sv00008086sd000027D8* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027D8sv00008086sd0000D618* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027D8sv00008384sd00007680* + ID_MODEL_FROM_DATABASE=STAC9221 HD Audio Codec + +pci:v00008086d000027DA* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family SMBus Controller + +pci:v00008086d000027DAsv00001025sd0000006C* + ID_MODEL_FROM_DATABASE=9814 WKMI + +pci:v00008086d000027DAsv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027DAsv00001028sd000001D7* + ID_MODEL_FROM_DATABASE=XPS M1210 + +pci:v00008086d000027DAsv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027DAsv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027DAsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027DAsv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000027DAsv0000105Bsd00000D7C* + ID_MODEL_FROM_DATABASE=D270S/D250S Motherboard + +pci:v00008086d000027DAsv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00008086d000027DAsv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d000027DAsv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-8I945PG-RH/GA-D525TUD Mainboard + +pci:v00008086d000027DAsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027DAsv000017AAsd0000200F* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027DAsv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d000027DAsv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d000027DAsv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027DAsv00008086sd00005842* + ID_MODEL_FROM_DATABASE=DeskTop Board D975XBX + +pci:v00008086d000027DC* + ID_MODEL_FROM_DATABASE=NM10/ICH7 Family LAN Controller + +pci:v00008086d000027DCsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027DCsv00008086sd0000308D* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027DD* + ID_MODEL_FROM_DATABASE=82801G (ICH7 Family) AC'97 Modem Controller + +pci:v00008086d000027DE* + ID_MODEL_FROM_DATABASE=82801G (ICH7 Family) AC'97 Audio Controller + +pci:v00008086d000027DEsv00001028sd000001AD* + ID_MODEL_FROM_DATABASE=OptiPlex GX620 + +pci:v00008086d000027DEsv00001462sd00007267* + ID_MODEL_FROM_DATABASE=Realtek ALC883 Audio Controller + +pci:v00008086d000027DEsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11 integrated audio (AD1981BL codec) + +pci:v00008086d000027DF* + ID_MODEL_FROM_DATABASE=82801G (ICH7 Family) IDE Controller + +pci:v00008086d000027DFsv00001028sd000001DF* + ID_MODEL_FROM_DATABASE=PowerEdge SC440 + +pci:v00008086d000027DFsv00001028sd000001E6* + ID_MODEL_FROM_DATABASE=PowerEdge 860 + +pci:v00008086d000027DFsv0000103Csd00002A3B* + ID_MODEL_FROM_DATABASE=Pavilion A1512X + +pci:v00008086d000027DFsv0000103Csd0000309F* + ID_MODEL_FROM_DATABASE=Compaq nx9420 Notebook + +pci:v00008086d000027DFsv0000103Csd000030A1* + ID_MODEL_FROM_DATABASE=NC2400 + +pci:v00008086d000027DFsv0000103Csd000030A3* + ID_MODEL_FROM_DATABASE=Compaq nw8440 + +pci:v00008086d000027DFsv00001043sd00001237* + ID_MODEL_FROM_DATABASE=A6J-Q008 + +pci:v00008086d000027DFsv00001043sd00008179* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000027DFsv0000107Bsd00005048* + ID_MODEL_FROM_DATABASE=E4500 + +pci:v00008086d000027DFsv000010F7sd00008338* + ID_MODEL_FROM_DATABASE=Panasonic CF-Y5 laptop + +pci:v00008086d000027DFsv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027DFsv000017AAsd0000200C* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60 series + +pci:v00008086d000027DFsv00008086sd0000544E* + ID_MODEL_FROM_DATABASE=DeskTop Board D945GTP + +pci:v00008086d000027E0* + ID_MODEL_FROM_DATABASE=82801GR/GH/GHM (ICH7 Family) PCI Express Port 5 + +pci:v00008086d000027E0sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d000027E2* + ID_MODEL_FROM_DATABASE=82801GR/GH/GHM (ICH7 Family) PCI Express Port 6 + +pci:v00008086d000027E2sv00001775sd000011CC* + ID_MODEL_FROM_DATABASE=CC11/CL11 + +pci:v00008086d00002810* + ID_MODEL_FROM_DATABASE=82801HB/HR (ICH8/R) LPC Interface Controller + +pci:v00008086d00002810sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002811* + ID_MODEL_FROM_DATABASE=82801HEM (ICH8M-E) LPC Interface Controller + +pci:v00008086d00002811sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002811sv000017AAsd000020B6* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002811sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002812* + ID_MODEL_FROM_DATABASE=82801HH (ICH8DH) LPC Interface Controller + +pci:v00008086d00002814* + ID_MODEL_FROM_DATABASE=82801HO (ICH8DO) LPC Interface Controller + +pci:v00008086d00002815* + ID_MODEL_FROM_DATABASE=82801HM (ICH8M) LPC Interface Controller + +pci:v00008086d00002815sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002815sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002815sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002815sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002815sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002815sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002815sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002820* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) 4 port SATA Controller [IDE mode] + +pci:v00008086d00002820sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002820sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002821* + ID_MODEL_FROM_DATABASE=82801HR/HO/HH (ICH8R/DO/DH) 6 port SATA Controller [AHCI mode] + +pci:v00008086d00002822* + ID_MODEL_FROM_DATABASE=82801 SATA Controller [RAID mode] + +pci:v00008086d00002822sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002823* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA RAID Controller + +pci:v00008086d00002824* + ID_MODEL_FROM_DATABASE=82801HB (ICH8) 4 port SATA Controller [AHCI mode] + +pci:v00008086d00002824sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002825* + ID_MODEL_FROM_DATABASE=82801HR/HO/HH (ICH8R/DO/DH) 2 port SATA Controller [IDE mode] + +pci:v00008086d00002825sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002825sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002826* + ID_MODEL_FROM_DATABASE=C600/X79 series chipset SATA RAID Controller + +pci:v00008086d00002827* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA RAID Controller + +pci:v00008086d00002828* + ID_MODEL_FROM_DATABASE=82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [IDE mode] + +pci:v00008086d00002828sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002828sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002828sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002829* + ID_MODEL_FROM_DATABASE=82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode] + +pci:v00008086d00002829sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002829sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002829sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002829sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002829sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002829sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002829sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002829sv000017AAsd000020A7* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002829sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d0000282A* + ID_MODEL_FROM_DATABASE=82801 Mobile SATA Controller [RAID mode] + +pci:v00008086d0000282Asv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d0000282Asv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00002830* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #1 + +pci:v00008086d00002830sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Acer Aspire 5920G + +pci:v00008086d00002830sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002830sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002830sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002830sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002830sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002830sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002830sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002830sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002830sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002830sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002830sv000017AAsd000020AA* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002830sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002831* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #2 + +pci:v00008086d00002831sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002831sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002831sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002831sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002831sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002831sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002831sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002831sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002831sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002831sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002831sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002831sv000017AAsd000020AA* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002831sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002832* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #3 + +pci:v00008086d00002832sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002832sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002832sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002832sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002832sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002832sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002832sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002832sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002832sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002832sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002832sv000017AAsd000020AA* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002832sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002833* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #4 + +pci:v00008086d00002833sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002834* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #4 + +pci:v00008086d00002834sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002834sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002834sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002834sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002834sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002834sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002834sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002834sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002834sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002834sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002834sv000017AAsd000020AA* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002834sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002835* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB UHCI Controller #5 + +pci:v00008086d00002835sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Acer Aspire 5920G + +pci:v00008086d00002835sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002835sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002835sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002835sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002835sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002835sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002835sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002835sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002835sv000017AAsd000020AA* + ID_MODEL_FROM_DATABASE=Thinkpad T61/R61 + +pci:v00008086d00002835sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002836* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB2 EHCI Controller #1 + +pci:v00008086d00002836sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002836sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002836sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002836sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002836sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002836sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002836sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002836sv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d00002836sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002836sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002836sv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d00002836sv000017AAsd000020AB* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002836sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d0000283A* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) USB2 EHCI Controller #2 + +pci:v00008086d0000283Asv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Acer Aspire 5920G + +pci:v00008086d0000283Asv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d0000283Asv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d0000283Asv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d0000283Asv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d0000283Asv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d0000283Asv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d0000283Asv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d0000283Asv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d0000283Asv000017AAsd000020AB* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d0000283Asv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d0000283E* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) SMBus Controller + +pci:v00008086d0000283Esv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d0000283Esv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d0000283Esv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d0000283Esv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d0000283Esv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d0000283Esv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d0000283Esv0000104Dsd00009008* + ID_MODEL_FROM_DATABASE=Vaio VGN-SZ79SN_C + +pci:v00008086d0000283Esv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d0000283Esv00001462sd00007235* + ID_MODEL_FROM_DATABASE=P965 Neo MS-7235 mainboard + +pci:v00008086d0000283Esv000017AAsd000020A9* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d0000283Esv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d0000283F* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 1 + +pci:v00008086d0000283Fsv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d0000283Fsv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d0000283Fsv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d0000283Fsv000017AAsd000020AD* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002841* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 2 + +pci:v00008086d00002841sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002841sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002841sv000017AAsd000020AD* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002843* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 3 + +pci:v00008086d00002843sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002843sv000017AAsd000020AD* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002845* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 4 + +pci:v00008086d00002845sv000017AAsd000020AD* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002847* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 5 + +pci:v00008086d00002847sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002847sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002847sv000017AAsd000020AD* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002849* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) PCI Express Port 6 + +pci:v00008086d0000284B* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) HD Audio Controller + +pci:v00008086d0000284Bsv00001025sd0000011F* + ID_MODEL_FROM_DATABASE=Realtek ALC268 audio codec + +pci:v00008086d0000284Bsv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d0000284Bsv00001025sd00000145* + ID_MODEL_FROM_DATABASE=Realtek ALC889 (Aspire 8920G w. Dolby Theather) + +pci:v00008086d0000284Bsv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d0000284Bsv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d0000284Bsv00001028sd000001F9* + ID_MODEL_FROM_DATABASE=Dell Latitude D630 + +pci:v00008086d0000284Bsv00001028sd000001FF* + ID_MODEL_FROM_DATABASE=Dell Precision M4300 + +pci:v00008086d0000284Bsv00001028sd00000256* + ID_MODEL_FROM_DATABASE=Studio 1735 + +pci:v00008086d0000284Bsv0000103Csd00002802* + ID_MODEL_FROM_DATABASE=HP Compaq dc7700p + +pci:v00008086d0000284Bsv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d0000284Bsv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d0000284Bsv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d0000284Bsv00001043sd00001339* + ID_MODEL_FROM_DATABASE=Asus M51S series + +pci:v00008086d0000284Bsv00001043sd000081EC* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d0000284Bsv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d0000284Bsv0000104Dsd00009008* + ID_MODEL_FROM_DATABASE=Vaio VGN-SZ79SN_C + +pci:v00008086d0000284Bsv0000104Dsd00009016* + ID_MODEL_FROM_DATABASE=Sony VAIO VGN-AR51M + +pci:v00008086d0000284Bsv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d0000284Bsv000014F1sd00005051* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d0000284Bsv000017AAsd000020AC* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d0000284Bsv00008384sd00007616* + ID_MODEL_FROM_DATABASE=Dell Vostro 1400 + +pci:v00008086d0000284Bsv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d0000284F* + ID_MODEL_FROM_DATABASE=82801H (ICH8 Family) Thermal Reporting Device + +pci:v00008086d00002850* + ID_MODEL_FROM_DATABASE=82801HM/HEM (ICH8M/ICH8M-E) IDE Controller + +pci:v00008086d00002850sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Aspire 5920G + +pci:v00008086d00002850sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002850sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002850sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002850sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002850sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002850sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002850sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002850sv000017AAsd000020A6* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002850sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002912* + ID_MODEL_FROM_DATABASE=82801IH (ICH9DH) LPC Interface Controller + +pci:v00008086d00002914* + ID_MODEL_FROM_DATABASE=82801IO (ICH9DO) LPC Interface Controller + +pci:v00008086d00002914sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002916* + ID_MODEL_FROM_DATABASE=82801IR (ICH9R) LPC Interface Controller + +pci:v00008086d00002916sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002916sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002916sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002917* + ID_MODEL_FROM_DATABASE=ICH9M-E LPC Interface Controller + +pci:v00008086d00002917sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002918* + ID_MODEL_FROM_DATABASE=82801IB (ICH9) LPC Interface Controller + +pci:v00008086d00002918sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 82801IB (ICH9) LPC Interface Controller + +pci:v00008086d00002918sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002919* + ID_MODEL_FROM_DATABASE=ICH9M LPC Interface Controller + +pci:v00008086d00002920* + ID_MODEL_FROM_DATABASE=82801IR/IO/IH (ICH9R/DO/DH) 4 port SATA Controller [IDE mode] + +pci:v00008086d00002920sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002920sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard SATA Controller + +pci:v00008086d00002920sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard SATA Controller + +pci:v00008086d00002920sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002920sv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 onboard SATA Controller + +pci:v00008086d00002920sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002921* + ID_MODEL_FROM_DATABASE=82801IB (ICH9) 2 port SATA Controller [IDE mode] + +pci:v00008086d00002921sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 SATA IDE Controller + +pci:v00008086d00002921sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 SATA IDE Controller + +pci:v00008086d00002921sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 SATA IDE Controller + +pci:v00008086d00002921sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002922* + ID_MODEL_FROM_DATABASE=82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] + +pci:v00008086d00002922sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002923* + ID_MODEL_FROM_DATABASE=82801IB (ICH9) 4 port SATA Controller [AHCI mode] + +pci:v00008086d00002925* + ID_MODEL_FROM_DATABASE=82801IR/IO (ICH9R/DO) SATA Controller [RAID mode] + +pci:v00008086d00002925sv00001734sd000010E0* + ID_MODEL_FROM_DATABASE=System Board D2542 + +pci:v00008086d00002925sv00008086sd00002925* + ID_MODEL_FROM_DATABASE=System Board D2542 + +pci:v00008086d00002926* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) 2 port SATA Controller [IDE mode] + +pci:v00008086d00002926sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002926sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard SATA Controller + +pci:v00008086d00002926sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard SATA Controller + +pci:v00008086d00002926sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002926sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002926sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002928* + ID_MODEL_FROM_DATABASE=82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode] + +pci:v00008086d00002929* + ID_MODEL_FROM_DATABASE=82801IBM/IEM (ICH9M/ICH9M-E) 4 port SATA Controller [AHCI mode] + +pci:v00008086d00002929sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=dv6-1190en + +pci:v00008086d00002929sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d0000292C* + ID_MODEL_FROM_DATABASE=82801IEM (ICH9M-E) SATA Controller [RAID mode] + +pci:v00008086d0000292D* + ID_MODEL_FROM_DATABASE=82801IBM/IEM (ICH9M/ICH9M-E) 2 port SATA Controller [IDE mode] + +pci:v00008086d0000292Dsv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002930* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) SMBus Controller + +pci:v00008086d00002930sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002930sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002930sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=dv6-1190en + +pci:v00008086d00002930sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002930sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002930sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002930sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002932* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) Thermal Subsystem + +pci:v00008086d00002932sv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=dv6-1190en + +pci:v00008086d00002934* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #1 + +pci:v00008086d00002934sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002934sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard UHCI + +pci:v00008086d00002934sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard UHCI + +pci:v00008086d00002934sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002934sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB UHCI Controller + +pci:v00008086d00002934sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB UHCI Controller + +pci:v00008086d00002934sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002934sv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 onboard UHCI + +pci:v00008086d00002934sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard UHCI + +pci:v00008086d00002934sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB UHCI Controller + +pci:v00008086d00002934sv00001028sd00002011* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002934sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002934sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002934sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002934sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002935* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #2 + +pci:v00008086d00002935sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002935sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard UHCI + +pci:v00008086d00002935sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard UHCI + +pci:v00008086d00002935sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002935sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB UHCI Controller + +pci:v00008086d00002935sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB UHCI Controller + +pci:v00008086d00002935sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002935sv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 onboard UHCI + +pci:v00008086d00002935sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard UHCI + +pci:v00008086d00002935sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB UHCI Controller + +pci:v00008086d00002935sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002935sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002935sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002935sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002936* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #3 + +pci:v00008086d00002936sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002936sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard UHCI + +pci:v00008086d00002936sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard UHCI + +pci:v00008086d00002936sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002936sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002936sv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 onboard UHCI + +pci:v00008086d00002936sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard UHCI + +pci:v00008086d00002936sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB UHCI Controller + +pci:v00008086d00002936sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002936sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002936sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002936sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002937* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #4 + +pci:v00008086d00002937sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002937sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002937sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB UHCI Controller + +pci:v00008086d00002937sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB UHCI Controller + +pci:v00008086d00002937sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002937sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard UHCI + +pci:v00008086d00002937sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB UHCI Controller + +pci:v00008086d00002937sv00001028sd00002011* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002937sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002937sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002937sv00008086sd00002937* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002937sv00008086sd00002942* + ID_MODEL_FROM_DATABASE=828011 (ICH9 Family ) USB UHCI Controller + +pci:v00008086d00002937sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002937sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002938* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #5 + +pci:v00008086d00002938sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002938sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002938sv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB UHCI Controller + +pci:v00008086d00002938sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB UHCI Controller + +pci:v00008086d00002938sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002938sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard UHCI + +pci:v00008086d00002938sv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB UHCI Controller + +pci:v00008086d00002938sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002938sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002938sv00008086sd00002938* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002938sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002938sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002939* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB UHCI Controller #6 + +pci:v00008086d00002939sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002939sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard UHCI + +pci:v00008086d00002939sv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB UHCI Controller + +pci:v00008086d00002939sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002939sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d00002939sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d00002939sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d0000293A* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB2 EHCI Controller #1 + +pci:v00008086d0000293Asv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d0000293Asv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 onboard EHCI + +pci:v00008086d0000293Asv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 onboard EHCI + +pci:v00008086d0000293Asv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Asv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB EHCI Controller + +pci:v00008086d0000293Asv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB EHCI Controller + +pci:v00008086d0000293Asv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB EHCI Controller + +pci:v00008086d0000293Asv00001028sd0000023C* + ID_MODEL_FROM_DATABASE=PowerEdge R200 onboard EHCI + +pci:v00008086d0000293Asv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard EHCI + +pci:v00008086d0000293Asv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB EHCI Controller + +pci:v00008086d0000293Asv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000293Asv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d0000293Asv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d0000293Asv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d0000293C* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) USB2 EHCI Controller #2 + +pci:v00008086d0000293Csv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d0000293Csv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Csv00001028sd00000235* + ID_MODEL_FROM_DATABASE=PowerEdge R710 USB EHCI Controller + +pci:v00008086d0000293Csv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 USB EHCI Controller + +pci:v00008086d0000293Csv00001028sd00000237* + ID_MODEL_FROM_DATABASE=PowerEdge T610 USB EHCI Controller + +pci:v00008086d0000293Csv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 onboard EHCI + +pci:v00008086d0000293Csv00001028sd0000029C* + ID_MODEL_FROM_DATABASE=PowerEdge M710 USB EHCI Controller + +pci:v00008086d0000293Csv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000293Csv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d0000293Csv00008086sd0000293C* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Csv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d0000293Csv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d0000293E* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) HD Audio Controller + +pci:v00008086d0000293Esv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d0000293Esv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Esv0000103Csd00003628* + ID_MODEL_FROM_DATABASE=dv6-1190en + +pci:v00008086d0000293Esv00001043sd0000829F* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000293Esv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d0000293Esv00008086sd0000293E* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Esv00008086sd00002940* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d0000293Esv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002940* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 1 + +pci:v00008086d00002940sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002940sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002940sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d00002940sv00008086sd00002940* + ID_MODEL_FROM_DATABASE=Optiplex 755 + +pci:v00008086d00002942* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 2 + +pci:v00008086d00002942sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002944* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 3 + +pci:v00008086d00002944sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002946* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 4 + +pci:v00008086d00002946sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002948* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 5 + +pci:v00008086d00002948sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d00002948sv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000294A* + ID_MODEL_FROM_DATABASE=82801I (ICH9 Family) PCI Express Port 6 + +pci:v00008086d0000294Asv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d0000294Asv00001043sd00008277* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d0000294C* + ID_MODEL_FROM_DATABASE=82566DC-2 Gigabit Network Connection + +pci:v00008086d0000294Csv000017AAsd0000302E* + ID_MODEL_FROM_DATABASE=82566DM-2 Gigabit Network Connection + +pci:v00008086d00002970* + ID_MODEL_FROM_DATABASE=82946GZ/PL/GL Memory Controller Hub + +pci:v00008086d00002971* + ID_MODEL_FROM_DATABASE=82946GZ/PL/GL PCI Express Root Port + +pci:v00008086d00002972* + ID_MODEL_FROM_DATABASE=82946GZ/GL Integrated Graphics Controller + +pci:v00008086d00002973* + ID_MODEL_FROM_DATABASE=82946GZ/GL Integrated Graphics Controller + +pci:v00008086d00002974* + ID_MODEL_FROM_DATABASE=82946GZ/GL HECI Controller + +pci:v00008086d00002975* + ID_MODEL_FROM_DATABASE=82946GZ/GL HECI Controller + +pci:v00008086d00002976* + ID_MODEL_FROM_DATABASE=82946GZ/GL PT IDER Controller + +pci:v00008086d00002977* + ID_MODEL_FROM_DATABASE=82946GZ/GL KT Controller + +pci:v00008086d00002980* + ID_MODEL_FROM_DATABASE=82G35 Express DRAM Controller + +pci:v00008086d00002981* + ID_MODEL_FROM_DATABASE=82G35 Express PCI Express Root Port + +pci:v00008086d00002982* + ID_MODEL_FROM_DATABASE=82G35 Express Integrated Graphics Controller + +pci:v00008086d00002983* + ID_MODEL_FROM_DATABASE=82G35 Express Integrated Graphics Controller + +pci:v00008086d00002984* + ID_MODEL_FROM_DATABASE=82G35 Express HECI Controller + +pci:v00008086d00002990* + ID_MODEL_FROM_DATABASE=82Q963/Q965 Memory Controller Hub + +pci:v00008086d00002990sv00001028sd000001DA* + ID_MODEL_FROM_DATABASE=OptiPlex 745 + +pci:v00008086d00002991* + ID_MODEL_FROM_DATABASE=82Q963/Q965 PCI Express Root Port + +pci:v00008086d00002992* + ID_MODEL_FROM_DATABASE=82Q963/Q965 Integrated Graphics Controller + +pci:v00008086d00002993* + ID_MODEL_FROM_DATABASE=82Q963/Q965 Integrated Graphics Controller + +pci:v00008086d00002994* + ID_MODEL_FROM_DATABASE=82Q963/Q965 HECI Controller + +pci:v00008086d00002995* + ID_MODEL_FROM_DATABASE=82Q963/Q965 HECI Controller + +pci:v00008086d00002996* + ID_MODEL_FROM_DATABASE=82Q963/Q965 PT IDER Controller + +pci:v00008086d00002997* + ID_MODEL_FROM_DATABASE=82Q963/Q965 KT Controller + +pci:v00008086d000029A0* + ID_MODEL_FROM_DATABASE=82P965/G965 Memory Controller Hub + +pci:v00008086d000029A0sv00001043sd000081EA* + ID_MODEL_FROM_DATABASE=P5B + +pci:v00008086d000029A0sv00001462sd00007276* + ID_MODEL_FROM_DATABASE=MS-7276 [G965MDH] + +pci:v00008086d000029A1* + ID_MODEL_FROM_DATABASE=82P965/G965 PCI Express Root Port + +pci:v00008086d000029A2* + ID_MODEL_FROM_DATABASE=82G965 Integrated Graphics Controller + +pci:v00008086d000029A2sv00001462sd00007276* + ID_MODEL_FROM_DATABASE=MS-7276 [G965MDH] + +pci:v00008086d000029A3* + ID_MODEL_FROM_DATABASE=82G965 Integrated Graphics Controller + +pci:v00008086d000029A4* + ID_MODEL_FROM_DATABASE=82P965/G965 HECI Controller + +pci:v00008086d000029A5* + ID_MODEL_FROM_DATABASE=82P965/G965 HECI Controller + +pci:v00008086d000029A6* + ID_MODEL_FROM_DATABASE=82P965/G965 PT IDER Controller + +pci:v00008086d000029A7* + ID_MODEL_FROM_DATABASE=82P965/G965 KT Controller + +pci:v00008086d000029B0* + ID_MODEL_FROM_DATABASE=82Q35 Express DRAM Controller + +pci:v00008086d000029B0sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B1* + ID_MODEL_FROM_DATABASE=82Q35 Express PCI Express Root Port + +pci:v00008086d000029B1sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B2* + ID_MODEL_FROM_DATABASE=82Q35 Express Integrated Graphics Controller + +pci:v00008086d000029B2sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B3* + ID_MODEL_FROM_DATABASE=82Q35 Express Integrated Graphics Controller + +pci:v00008086d000029B3sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B4* + ID_MODEL_FROM_DATABASE=82Q35 Express MEI Controller + +pci:v00008086d000029B4sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B5* + ID_MODEL_FROM_DATABASE=82Q35 Express MEI Controller + +pci:v00008086d000029B6* + ID_MODEL_FROM_DATABASE=82Q35 Express PT IDER Controller + +pci:v00008086d000029B6sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029B7* + ID_MODEL_FROM_DATABASE=82Q35 Express Serial KT Controller + +pci:v00008086d000029B7sv00001028sd00000211* + ID_MODEL_FROM_DATABASE=OptiPlex 755 + +pci:v00008086d000029C0* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express DRAM Controller + +pci:v00008086d000029C0sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d000029C0sv00001043sd00008276* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d000029C0sv00001043sd000082B0* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000029C0sv00001462sd00007360* + ID_MODEL_FROM_DATABASE=G33/P35 Neo + +pci:v00008086d000029C0sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d000029C1* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express PCI Express Root Port + +pci:v00008086d000029C1sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d000029C1sv00001043sd00008276* + ID_MODEL_FROM_DATABASE=P5K PRO Motherboard + +pci:v00008086d000029C2* + ID_MODEL_FROM_DATABASE=82G33/G31 Express Integrated Graphics Controller + +pci:v00008086d000029C2sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d000029C2sv00001043sd000082B0* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000029C3* + ID_MODEL_FROM_DATABASE=82G33/G31 Express Integrated Graphics Controller + +pci:v00008086d000029C3sv00001028sd0000020D* + ID_MODEL_FROM_DATABASE=Inspiron 530 + +pci:v00008086d000029C3sv00001043sd000082B0* + ID_MODEL_FROM_DATABASE=P5KPL-VM Motherboard + +pci:v00008086d000029C4* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express MEI Controller + +pci:v00008086d000029C4sv00008086sd00005044* + ID_MODEL_FROM_DATABASE=Desktop Board DP35DP + +pci:v00008086d000029C5* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express MEI Controller + +pci:v00008086d000029C6* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express PT IDER Controller + +pci:v00008086d000029C7* + ID_MODEL_FROM_DATABASE=82G33/G31/P35/P31 Express Serial KT Controller + +pci:v00008086d000029CF* + ID_MODEL_FROM_DATABASE=Virtual HECI Controller + +pci:v00008086d000029D0* + ID_MODEL_FROM_DATABASE=82Q33 Express DRAM Controller + +pci:v00008086d000029D1* + ID_MODEL_FROM_DATABASE=82Q33 Express PCI Express Root Port + +pci:v00008086d000029D2* + ID_MODEL_FROM_DATABASE=82Q33 Express Integrated Graphics Controller + +pci:v00008086d000029D3* + ID_MODEL_FROM_DATABASE=82Q33 Express Integrated Graphics Controller + +pci:v00008086d000029D4* + ID_MODEL_FROM_DATABASE=82Q33 Express MEI Controller + +pci:v00008086d000029D5* + ID_MODEL_FROM_DATABASE=82Q33 Express MEI Controller + +pci:v00008086d000029D6* + ID_MODEL_FROM_DATABASE=82Q33 Express PT IDER Controller + +pci:v00008086d000029D7* + ID_MODEL_FROM_DATABASE=82Q33 Express Serial KT Controller + +pci:v00008086d000029E0* + ID_MODEL_FROM_DATABASE=82X38/X48 Express DRAM Controller + +pci:v00008086d000029E1* + ID_MODEL_FROM_DATABASE=82X38/X48 Express Host-Primary PCI Express Bridge + +pci:v00008086d000029E4* + ID_MODEL_FROM_DATABASE=82X38/X48 Express MEI Controller + +pci:v00008086d000029E5* + ID_MODEL_FROM_DATABASE=82X38/X48 Express MEI Controller + +pci:v00008086d000029E6* + ID_MODEL_FROM_DATABASE=82X38/X48 Express PT IDER Controller + +pci:v00008086d000029E7* + ID_MODEL_FROM_DATABASE=82X38/X48 Express Serial KT Controller + +pci:v00008086d000029E9* + ID_MODEL_FROM_DATABASE=82X38/X48 Express Host-Secondary PCI Express Bridge + +pci:v00008086d000029F0* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset DRAM Controller + +pci:v00008086d000029F1* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset Host-Primary PCI Express Bridge + +pci:v00008086d000029F4* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset MEI Controller + +pci:v00008086d000029F5* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset MEI Controller + +pci:v00008086d000029F6* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset PT IDER Controller + +pci:v00008086d000029F7* + ID_MODEL_FROM_DATABASE=3200/3210 Chipset Serial KT Controller + +pci:v00008086d000029F9* + ID_MODEL_FROM_DATABASE=3210 Chipset Host-Secondary PCI Express Bridge + +pci:v00008086d00002A00* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965/GL960 Memory Controller Hub + +pci:v00008086d00002A00sv00001025sd00000121* + ID_MODEL_FROM_DATABASE=Acer Aspire 5920G + +pci:v00008086d00002A00sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002A00sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002A00sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002A00sv0000103Csd000030CC* + ID_MODEL_FROM_DATABASE=Pavilion dv6700 + +pci:v00008086d00002A00sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002A00sv0000104Dsd00009005* + ID_MODEL_FROM_DATABASE=Vaio VGN-FZ260E + +pci:v00008086d00002A00sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002A00sv000017AAsd000020B1* + ID_MODEL_FROM_DATABASE=ThinkPad T61 + +pci:v00008086d00002A00sv000017AAsd000020B3* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002A00sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A01* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965/GL960 PCI Express Root Port + +pci:v00008086d00002A02* + ID_MODEL_FROM_DATABASE=Mobile GM965/GL960 Integrated Graphics Controller (primary) + +pci:v00008086d00002A02sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Inspiron 1420 + +pci:v00008086d00002A02sv00001028sd000001F9* + ID_MODEL_FROM_DATABASE=Latitude D630 + +pci:v00008086d00002A02sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002A02sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002A02sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002A02sv000017AAsd000020B5* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002A02sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A03* + ID_MODEL_FROM_DATABASE=Mobile GM965/GL960 Integrated Graphics Controller (secondary) + +pci:v00008086d00002A03sv00001028sd000001F3* + ID_MODEL_FROM_DATABASE=Dell Inspiron 1420 + +pci:v00008086d00002A03sv0000103Csd000030C0* + ID_MODEL_FROM_DATABASE=Compaq 6710b + +pci:v00008086d00002A03sv0000103Csd000030D9* + ID_MODEL_FROM_DATABASE=Presario C700 + +pci:v00008086d00002A03sv0000104Dsd0000902D* + ID_MODEL_FROM_DATABASE=VAIO VGN-NR120E + +pci:v00008086d00002A03sv000017AAsd000020B5* + ID_MODEL_FROM_DATABASE=ThinkPad T61/R61 + +pci:v00008086d00002A03sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A04* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965 MEI Controller + +pci:v00008086d00002A04sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002A05* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965 MEI Controller + +pci:v00008086d00002A06* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965 PT IDER Controller + +pci:v00008086d00002A06sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002A07* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965 KT Controller + +pci:v00008086d00002A07sv0000103Csd000030C1* + ID_MODEL_FROM_DATABASE=Compaq 6910p + +pci:v00008086d00002A10* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 Memory Controller Hub + +pci:v00008086d00002A10sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A11* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 PCI Express Root Port + +pci:v00008086d00002A12* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 Integrated Graphics Controller + +pci:v00008086d00002A12sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A13* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 Integrated Graphics Controller + +pci:v00008086d00002A13sv0000E4BFsd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v00008086d00002A14* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 MEI Controller + +pci:v00008086d00002A15* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 MEI Controller + +pci:v00008086d00002A16* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 PT IDER Controller + +pci:v00008086d00002A17* + ID_MODEL_FROM_DATABASE=Mobile GME965/GLE960 KT Controller + +pci:v00008086d00002A40* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Memory Controller Hub + +pci:v00008086d00002A40sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002A41* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset PCI Express Graphics Port + +pci:v00008086d00002A41sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002A42* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002A42sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002A43* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002A43sv0000E4BFsd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v00008086d00002A44* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset MEI Controller + +pci:v00008086d00002A45* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset MEI Controller + +pci:v00008086d00002A46* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset PT IDER Controller + +pci:v00008086d00002A47* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset AMT SOL Redirection + +pci:v00008086d00002A50* + ID_MODEL_FROM_DATABASE=Cantiga MEI Controller + +pci:v00008086d00002A51* + ID_MODEL_FROM_DATABASE=Cantiga MEI Controller + +pci:v00008086d00002A52* + ID_MODEL_FROM_DATABASE=Cantiga PT IDER Controller + +pci:v00008086d00002A53* + ID_MODEL_FROM_DATABASE=Cantiga AMT SOL Redirection + +pci:v00008086d00002B00* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family System Configuration Controller 1 + +pci:v00008086d00002B02* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family System Configuration Controller 2 + +pci:v00008086d00002B04* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Power Controller + +pci:v00008086d00002B08* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Caching Agent 0 + +pci:v00008086d00002B0C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Caching Agent 1 + +pci:v00008086d00002B10* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Home Agent 0 + +pci:v00008086d00002B13* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 0c + +pci:v00008086d00002B14* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 0a + +pci:v00008086d00002B16* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 0b + +pci:v00008086d00002B18* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Home Agent 1 + +pci:v00008086d00002B1B* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 1c + +pci:v00008086d00002B1C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 1a + +pci:v00008086d00002B1E* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Memory Controller 1b + +pci:v00008086d00002B20* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 0 + +pci:v00008086d00002B22* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family System Configuration Controller 3 + +pci:v00008086d00002B24* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 1 + +pci:v00008086d00002B28* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 2 + +pci:v00008086d00002B2A* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family System Configuration Controller 4 + +pci:v00008086d00002B2C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 3 + +pci:v00008086d00002B30* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 4 + +pci:v00008086d00002B34* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 5 + +pci:v00008086d00002B38* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 6 + +pci:v00008086d00002B3C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 7 + +pci:v00008086d00002B40* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Router Port 0-1 + +pci:v00008086d00002B42* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Router Port 2-3 + +pci:v00008086d00002B44* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Router Port 4-5 + +pci:v00008086d00002B46* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Router Port 6-7 + +pci:v00008086d00002B48* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Test and Debug 0 + +pci:v00008086d00002B4C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Test and Debug 1 + +pci:v00008086d00002B50* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 0: REUT control/status + +pci:v00008086d00002B52* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 0: Misc. control/status + +pci:v00008086d00002B54* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 1: REUT control/status + +pci:v00008086d00002B56* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 1: Misc. control/status + +pci:v00008086d00002B58* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 2: REUT control/status + +pci:v00008086d00002B5A* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 2: Misc. control/status + +pci:v00008086d00002B5C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 3: REUT control/status + +pci:v00008086d00002B5E* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family QPI Physical Port 3: Misc. control/status + +pci:v00008086d00002B60* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family SMI Physical Port 0: REUT control/status + +pci:v00008086d00002B62* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family SMI Physical Port 0: Misc control/status + +pci:v00008086d00002B64* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family SMI Physical Port 1: REUT control/status + +pci:v00008086d00002B66* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family SMI Physical Port 1: Misc control/status + +pci:v00008086d00002B68* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 8 + +pci:v00008086d00002B6C* + ID_MODEL_FROM_DATABASE=Xeon Processor E7 Product Family Last Level Cache Coherence Engine 9 + +pci:v00008086d00002C01* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QuickPath Architecture System Address Decoder + +pci:v00008086d00002C10* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QPI Link 0 + +pci:v00008086d00002C11* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QPI Physical 0 + +pci:v00008086d00002C14* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QPI Link 1 + +pci:v00008086d00002C15* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QPI Physical 1 + +pci:v00008086d00002C18* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller + +pci:v00008086d00002C19* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Target Address Decoder + +pci:v00008086d00002C1A* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller RAS Registers + +pci:v00008086d00002C1C* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Test Registers + +pci:v00008086d00002C20* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Control Registers + +pci:v00008086d00002C21* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Address Registers + +pci:v00008086d00002C22* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Rank Registers + +pci:v00008086d00002C23* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 0 Thermal Control Registers + +pci:v00008086d00002C28* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Control Registers + +pci:v00008086d00002C29* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Address Registers + +pci:v00008086d00002C2A* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Rank Registers + +pci:v00008086d00002C2B* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 1 Thermal Control Registers + +pci:v00008086d00002C30* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Control Registers + +pci:v00008086d00002C31* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Address Registers + +pci:v00008086d00002C32* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Rank Registers + +pci:v00008086d00002C33* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 Integrated Memory Controller Channel 2 Thermal Control Registers + +pci:v00008086d00002C40* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C41* + ID_MODEL_FROM_DATABASE=Xeon 5500/Core i7 QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C50* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C51* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C52* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C53* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C54* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C55* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C56* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C57* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-Core Registers + +pci:v00008086d00002C58* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C59* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5A* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5B* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5C* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5D* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5E* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C5F* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Generic Non-core Registers + +pci:v00008086d00002C61* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-core Registers + +pci:v00008086d00002C62* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture Generic Non-core Registers + +pci:v00008086d00002C70* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QuickPath Architecture Generic Non-core Registers + +pci:v00008086d00002C81* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture System Address Decoder + +pci:v00008086d00002C90* + ID_MODEL_FROM_DATABASE=Core Processor QPI Link 0 + +pci:v00008086d00002C91* + ID_MODEL_FROM_DATABASE=Core Processor QPI Physical 0 + +pci:v00008086d00002C98* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller + +pci:v00008086d00002C99* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Target Address Decoder + +pci:v00008086d00002C9A* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Test Registers + +pci:v00008086d00002C9C* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Test Registers + +pci:v00008086d00002CA0* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 0 Control Registers + +pci:v00008086d00002CA1* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 0 Address Registers + +pci:v00008086d00002CA2* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 0 Rank Registers + +pci:v00008086d00002CA3* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 0 Thermal Control Registers + +pci:v00008086d00002CA8* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 1 Control Registers + +pci:v00008086d00002CA9* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 1 Address Registers + +pci:v00008086d00002CAA* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 1 Rank Registers + +pci:v00008086d00002CAB* + ID_MODEL_FROM_DATABASE=Core Processor Integrated Memory Controller Channel 1 Thermal Control Registers + +pci:v00008086d00002CC1* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI System Address Decoder + +pci:v00008086d00002CD0* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Link 0 + +pci:v00008086d00002CD1* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Physical 0 + +pci:v00008086d00002CD4* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Link 1 + +pci:v00008086d00002CD5* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Physical 1 + +pci:v00008086d00002CD8* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Registers + +pci:v00008086d00002CD9* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Target Address Decoder + +pci:v00008086d00002CDA* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller RAS Registers + +pci:v00008086d00002CDC* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Test Registers + +pci:v00008086d00002CE0* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 0 Control + +pci:v00008086d00002CE1* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 0 Address + +pci:v00008086d00002CE2* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 0 Rank + +pci:v00008086d00002CE3* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 0 Thermal Control + +pci:v00008086d00002CE8* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 1 Control + +pci:v00008086d00002CE9* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 1 Address + +pci:v00008086d00002CEA* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 1 Rank + +pci:v00008086d00002CEB* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 1 Thermal Control + +pci:v00008086d00002CF0* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 2 Control + +pci:v00008086d00002CF1* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 2 Address + +pci:v00008086d00002CF2* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 2 Rank + +pci:v00008086d00002CF3* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Integrated Memory Controller Channel 2 Thermal Control + +pci:v00008086d00002D01* + ID_MODEL_FROM_DATABASE=Core Processor QuickPath Architecture System Address Decoder + +pci:v00008086d00002D10* + ID_MODEL_FROM_DATABASE=Core Processor QPI Link 0 + +pci:v00008086d00002D11* + ID_MODEL_FROM_DATABASE=Core Processor QPI Physical 0 + +pci:v00008086d00002D12* + ID_MODEL_FROM_DATABASE=Core Processor Reserved + +pci:v00008086d00002D13* + ID_MODEL_FROM_DATABASE=Core Processor Reserved + +pci:v00008086d00002D81* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QuickPath Architecture System Address Decoder + +pci:v00008086d00002D90* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QPI Link 0 + +pci:v00008086d00002D91* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QPI Physical 0 + +pci:v00008086d00002D92* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Mirror Port Link 0 + +pci:v00008086d00002D93* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Mirror Port Link 1 + +pci:v00008086d00002D94* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QPI Link 1 + +pci:v00008086d00002D95* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series QPI Physical 1 + +pci:v00008086d00002D98* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Registers + +pci:v00008086d00002D99* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Target Address Decoder + +pci:v00008086d00002D9A* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller RAS Registers + +pci:v00008086d00002D9C* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Test Registers + +pci:v00008086d00002DA0* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 0 Control + +pci:v00008086d00002DA1* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 0 Address + +pci:v00008086d00002DA2* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 0 Rank + +pci:v00008086d00002DA3* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 0 Thermal Control + +pci:v00008086d00002DA8* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 1 Control + +pci:v00008086d00002DA9* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 1 Address + +pci:v00008086d00002DAA* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 1 Rank + +pci:v00008086d00002DAB* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 1 Thermal Control + +pci:v00008086d00002DB0* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 2 Control + +pci:v00008086d00002DB1* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 2 Address + +pci:v00008086d00002DB2* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 2 Rank + +pci:v00008086d00002DB3* + ID_MODEL_FROM_DATABASE=Xeon 5600 Series Integrated Memory Controller Channel 2 Thermal Control + +pci:v00008086d00002E00* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E01* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E02* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E03* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E04* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E05* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E06* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002E07* + ID_MODEL_FROM_DATABASE=4 Series Chipset Serial KT Controller + +pci:v00008086d00002E10* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E11* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E12* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E13* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E14* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E15* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E16* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002E17* + ID_MODEL_FROM_DATABASE=4 Series Chipset Serial KT Controller + +pci:v00008086d00002E20* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E20sv00001028sd00000283* + ID_MODEL_FROM_DATABASE=Dell Vostro 220 + +pci:v00008086d00002E20sv00001043sd000082D3* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00002E20sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00002E21* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E21sv00001043sd000082D3* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00002E21sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00002E22* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E22sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=GA-EG45M-DS2H Mainboard + +pci:v00008086d00002E23* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E23sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=GA-EG45M-DS2H Mainboard + +pci:v00008086d00002E24* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E25* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E26* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002E27* + ID_MODEL_FROM_DATABASE=4 Series Chipset Serial KT Controller + +pci:v00008086d00002E29* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E30* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E31* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E32* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E33* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E34* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E35* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E36* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002E37* + ID_MODEL_FROM_DATABASE=4 Series Chipset Serial KT Controller + +pci:v00008086d00002E40* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E41* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E42* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E43* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E44* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E45* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E46* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002E47* + ID_MODEL_FROM_DATABASE=4 Series Chipset Serial KT Controller + +pci:v00008086d00002E50* + ID_MODEL_FROM_DATABASE=CE Media Processor CE3100 + +pci:v00008086d00002E52* + ID_MODEL_FROM_DATABASE=CE Media Processor Clock and Reset Controller + +pci:v00008086d00002E58* + ID_MODEL_FROM_DATABASE=CE Media Processor Interrupt Controller + +pci:v00008086d00002E5A* + ID_MODEL_FROM_DATABASE=CE Media Processor CE3100 A/V Bridge + +pci:v00008086d00002E5B* + ID_MODEL_FROM_DATABASE=Graphics Media Accelerator 500 Graphics + +pci:v00008086d00002E5C* + ID_MODEL_FROM_DATABASE=CE Media Processor Video Decoder + +pci:v00008086d00002E5D* + ID_MODEL_FROM_DATABASE=CE Media Processor Transport Stream Interface + +pci:v00008086d00002E5E* + ID_MODEL_FROM_DATABASE=CE Media Processor Transport Stream Processor 0 + +pci:v00008086d00002E5F* + ID_MODEL_FROM_DATABASE=CE Media Processor Audio DSP + +pci:v00008086d00002E60* + ID_MODEL_FROM_DATABASE=CE Media Processor Audio Interfaces + +pci:v00008086d00002E61* + ID_MODEL_FROM_DATABASE=CE Media Processor Video Display Controller + +pci:v00008086d00002E62* + ID_MODEL_FROM_DATABASE=CE Media Processor Video Processing Unit + +pci:v00008086d00002E63* + ID_MODEL_FROM_DATABASE=CE Media Processor HDMI Tx Interface + +pci:v00008086d00002E65* + ID_MODEL_FROM_DATABASE=CE Media Processor Expansion Bus Interface + +pci:v00008086d00002E66* + ID_MODEL_FROM_DATABASE=CE Media Processor UART + +pci:v00008086d00002E67* + ID_MODEL_FROM_DATABASE=CE Media Processor General Purpose I/Os + +pci:v00008086d00002E68* + ID_MODEL_FROM_DATABASE=CE Media Processor I2C Interface + +pci:v00008086d00002E69* + ID_MODEL_FROM_DATABASE=CE Media Processor Smart Card Interface + +pci:v00008086d00002E6A* + ID_MODEL_FROM_DATABASE=CE Media Processor SPI Master Interface + +pci:v00008086d00002E6E* + ID_MODEL_FROM_DATABASE=CE Media Processor Gigabit Ethernet Controller + +pci:v00008086d00002E6F* + ID_MODEL_FROM_DATABASE=CE Media Processor Media Timing Unit + +pci:v00008086d00002E70* + ID_MODEL_FROM_DATABASE=CE Media Processor USB + +pci:v00008086d00002E71* + ID_MODEL_FROM_DATABASE=CE Media Processor SATA + +pci:v00008086d00002E73* + ID_MODEL_FROM_DATABASE=CE Media Processor CE3100 PCI Express + +pci:v00008086d00002E90* + ID_MODEL_FROM_DATABASE=4 Series Chipset DRAM Controller + +pci:v00008086d00002E91* + ID_MODEL_FROM_DATABASE=4 Series Chipset PCI Express Root Port + +pci:v00008086d00002E92* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E93* + ID_MODEL_FROM_DATABASE=4 Series Chipset Integrated Graphics Controller + +pci:v00008086d00002E94* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E95* + ID_MODEL_FROM_DATABASE=4 Series Chipset HECI Controller + +pci:v00008086d00002E96* + ID_MODEL_FROM_DATABASE=4 Series Chipset PT IDER Controller + +pci:v00008086d00002F00* + ID_MODEL_FROM_DATABASE=Haswell-E DMI2 + +pci:v00008086d00002F01* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 0 + +pci:v00008086d00002F02* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 1 + +pci:v00008086d00002F03* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 1 + +pci:v00008086d00002F04* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 2 + +pci:v00008086d00002F05* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 2 + +pci:v00008086d00002F06* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 2 + +pci:v00008086d00002F07* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 2 + +pci:v00008086d00002F08* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 3 + +pci:v00008086d00002F09* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 3 + +pci:v00008086d00002F0A* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 3 + +pci:v00008086d00002F0B* + ID_MODEL_FROM_DATABASE=Haswell-E PCI Express Root Port 3 + +pci:v00008086d00002F10* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F11* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F12* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F13* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F14* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F15* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F16* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F17* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F18* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F19* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F1A* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F1B* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F1C* + ID_MODEL_FROM_DATABASE=Haswell-E IIO Debug + +pci:v00008086d00002F1D* + ID_MODEL_FROM_DATABASE=Haswell-E PCIe Ring Interface + +pci:v00008086d00002F1E* + ID_MODEL_FROM_DATABASE=Haswell-E Scratchpad & Semaphore Registers + +pci:v00008086d00002F1F* + ID_MODEL_FROM_DATABASE=Haswell-E Scratchpad & Semaphore Registers + +pci:v00008086d00002F20* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 0 + +pci:v00008086d00002F21* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 1 + +pci:v00008086d00002F22* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 2 + +pci:v00008086d00002F23* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 3 + +pci:v00008086d00002F24* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 4 + +pci:v00008086d00002F25* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 5 + +pci:v00008086d00002F26* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 6 + +pci:v00008086d00002F27* + ID_MODEL_FROM_DATABASE=Haswell-E DMA Channel 7 + +pci:v00008086d00002F28* + ID_MODEL_FROM_DATABASE=Haswell-E Address Map, VTd_Misc, System Management + +pci:v00008086d00002F29* + ID_MODEL_FROM_DATABASE=Haswell-E Hot Plug + +pci:v00008086d00002F2A* + ID_MODEL_FROM_DATABASE=Haswell-E RAS, Control Status and Global Errors + +pci:v00008086d00002F2C* + ID_MODEL_FROM_DATABASE=Haswell-E I/O Apic + +pci:v00008086d00002F2E* + ID_MODEL_FROM_DATABASE=Haswell-E RAID 5/6 + +pci:v00008086d00002F2F* + ID_MODEL_FROM_DATABASE=Haswell-E RAID 5/6 + +pci:v00008086d00002F30* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 0 + +pci:v00008086d00002F32* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 + +pci:v00008086d00002F33* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 1 + +pci:v00008086d00002F34* + ID_MODEL_FROM_DATABASE=Haswell-E PCIe Ring Interface + +pci:v00008086d00002F36* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 0 & 1 Monitoring + +pci:v00008086d00002F37* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 0 & 1 Monitoring + +pci:v00008086d00002F38* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 1 + +pci:v00008086d00002F3A* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 + +pci:v00008086d00002F3E* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 2 Monitoring + +pci:v00008086d00002F3F* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 2 Monitoring + +pci:v00008086d00002F40* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 + +pci:v00008086d00002F41* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 2 Monitoring + +pci:v00008086d00002F43* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 + +pci:v00008086d00002F45* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 Debug + +pci:v00008086d00002F46* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 Debug + +pci:v00008086d00002F47* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 2 Debug + +pci:v00008086d00002F60* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 1 + +pci:v00008086d00002F68* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Target Address, Thermal & RAS Registers + +pci:v00008086d00002F6A* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel Target Address Decoder + +pci:v00008086d00002F6B* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel Target Address Decoder + +pci:v00008086d00002F6C* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel Target Address Decoder + +pci:v00008086d00002F6D* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel Target Address Decoder + +pci:v00008086d00002F6E* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO Channel 2/3 Broadcast + +pci:v00008086d00002F6F* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO Global Broadcast + +pci:v00008086d00002F70* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 0 Debug + +pci:v00008086d00002F71* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Target Address, Thermal & RAS Registers + +pci:v00008086d00002F76* + ID_MODEL_FROM_DATABASE=Haswell-E E3 QPI Link Debug + +pci:v00008086d00002F78* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 1 Debug + +pci:v00008086d00002F79* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Target Address, Thermal & RAS Registers + +pci:v00008086d00002F7D* + ID_MODEL_FROM_DATABASE=Haswell-E Scratchpad & Semaphore Registers + +pci:v00008086d00002F7E* + ID_MODEL_FROM_DATABASE=Haswell-E E3 QPI Link Debug + +pci:v00008086d00002F80* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 + +pci:v00008086d00002F81* + ID_MODEL_FROM_DATABASE=Haswell-E R3 QPI Link 0 & 1 Monitoring + +pci:v00008086d00002F83* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 + +pci:v00008086d00002F85* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 Debug + +pci:v00008086d00002F86* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 Debug + +pci:v00008086d00002F87* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 0 Debug + +pci:v00008086d00002F88* + ID_MODEL_FROM_DATABASE=Haswell-E VCU + +pci:v00008086d00002F8A* + ID_MODEL_FROM_DATABASE=Haswell-E VCU + +pci:v00008086d00002F90* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 1 + +pci:v00008086d00002F93* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 1 + +pci:v00008086d00002F95* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 1 Debug + +pci:v00008086d00002F96* + ID_MODEL_FROM_DATABASE=Haswell-E QPI Link 1 Debug + +pci:v00008086d00002F98* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002F99* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002F9A* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002F9C* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FA0* + ID_MODEL_FROM_DATABASE=Haswell-E Home Agent 0 + +pci:v00008086d00002FA8* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Target Address, Thermal & RAS Registers + +pci:v00008086d00002FAA* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel Target Address Decoder + +pci:v00008086d00002FAB* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel Target Address Decoder + +pci:v00008086d00002FAC* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel Target Address Decoder + +pci:v00008086d00002FAD* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel Target Address Decoder + +pci:v00008086d00002FAE* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO Channel 0/1 Broadcast + +pci:v00008086d00002FAF* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO Global Broadcast + +pci:v00008086d00002FB0* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 0 Thermal Control + +pci:v00008086d00002FB1* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 1 Thermal Control + +pci:v00008086d00002FB2* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 0 ERROR Registers + +pci:v00008086d00002FB3* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 1 ERROR Registers + +pci:v00008086d00002FB4* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 2 Thermal Control + +pci:v00008086d00002FB5* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 3 Thermal Control + +pci:v00008086d00002FB6* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 2 ERROR Registers + +pci:v00008086d00002FB7* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 0 Channel 3 ERROR Registers + +pci:v00008086d00002FB8* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 2 & 3 + +pci:v00008086d00002FB9* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 2 & 3 + +pci:v00008086d00002FBA* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 2 & 3 + +pci:v00008086d00002FBB* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 2 & 3 + +pci:v00008086d00002FBC* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 0 & 1 + +pci:v00008086d00002FBD* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 0 & 1 + +pci:v00008086d00002FBE* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 0 & 1 + +pci:v00008086d00002FBF* + ID_MODEL_FROM_DATABASE=Haswell-E DDRIO (VMSE) 0 & 1 + +pci:v00008086d00002FC0* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FC1* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FC2* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FC3* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FC4* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FC5* + ID_MODEL_FROM_DATABASE=Haswell-E Power Control Unit + +pci:v00008086d00002FD0* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 0 Thermal Control + +pci:v00008086d00002FD1* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 1 Thermal Control + +pci:v00008086d00002FD2* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 0 ERROR Registers + +pci:v00008086d00002FD3* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 1 ERROR Registers + +pci:v00008086d00002FD4* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 2 Thermal Control + +pci:v00008086d00002FD5* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 3 Thermal Control + +pci:v00008086d00002FD6* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 2 ERROR Registers + +pci:v00008086d00002FD7* + ID_MODEL_FROM_DATABASE=Haswell-E Integrated Memory Controller 1 Channel 3 ERROR Registers + +pci:v00008086d00002FE0* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE1* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE2* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE3* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE4* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE5* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE6* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE7* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE8* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FE9* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FEA* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FEB* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FEC* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FED* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FEE* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FEF* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF0* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF1* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF2* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF3* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF4* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF5* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF6* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF7* + ID_MODEL_FROM_DATABASE=Haswell-E Unicast Registers + +pci:v00008086d00002FF8* + ID_MODEL_FROM_DATABASE=Haswell-E Buffered Ring Agent + +pci:v00008086d00002FF9* + ID_MODEL_FROM_DATABASE=Haswell-E Buffered Ring Agent + +pci:v00008086d00002FFA* + ID_MODEL_FROM_DATABASE=Haswell-E Buffered Ring Agent + +pci:v00008086d00002FFB* + ID_MODEL_FROM_DATABASE=Haswell-E Buffered Ring Agent + +pci:v00008086d00002FFC* + ID_MODEL_FROM_DATABASE=Haswell-E System Address Decoder & Broadcast Registers + +pci:v00008086d00002FFD* + ID_MODEL_FROM_DATABASE=Haswell-E System Address Decoder & Broadcast Registers + +pci:v00008086d00002FFE* + ID_MODEL_FROM_DATABASE=Haswell-E System Address Decoder & Broadcast Registers + +pci:v00008086d00003200* + ID_MODEL_FROM_DATABASE=GD31244 PCI-X SATA HBA + +pci:v00008086d00003200sv00001775sd0000C200* + ID_MODEL_FROM_DATABASE=C2K onboard SATA host bus adapter + +pci:v00008086d00003310* + ID_MODEL_FROM_DATABASE=IOP348 I/O Processor + +pci:v00008086d00003310sv00001054sd00003030* + ID_MODEL_FROM_DATABASE=HRA380 Hitachi RAID Adapter to PCIe + +pci:v00008086d00003310sv00001054sd00003034* + ID_MODEL_FROM_DATABASE=HRA381 Hitachi RAID Adapter to PCIe + +pci:v00008086d00003313* + ID_MODEL_FROM_DATABASE=IOP348 I/O Processor (SL8e) in IOC Mode SAS/SATA + +pci:v00008086d0000331B* + ID_MODEL_FROM_DATABASE=IOP348 I/O Processor (SL8x) in IOC Mode SAS/SATA + +pci:v00008086d00003331* + ID_MODEL_FROM_DATABASE=IOC340 I/O Controller (VV8e) SAS/SATA + +pci:v00008086d00003339* + ID_MODEL_FROM_DATABASE=IOC340 I/O Controller (VV8x) SAS/SATA + +pci:v00008086d00003340* + ID_MODEL_FROM_DATABASE=82855PM Processor to I/O Controller + +pci:v00008086d00003340sv00001014sd00000529* + ID_MODEL_FROM_DATABASE=Thinkpad T40 series + +pci:v00008086d00003340sv00001025sd0000005A* + ID_MODEL_FROM_DATABASE=TravelMate 290 + +pci:v00008086d00003340sv0000103Csd0000088C* + ID_MODEL_FROM_DATABASE=NC8000 laptop + +pci:v00008086d00003340sv0000103Csd00000890* + ID_MODEL_FROM_DATABASE=NC6000 laptop + +pci:v00008086d00003340sv0000103Csd000008B0* + ID_MODEL_FROM_DATABASE=tc1100 tablet + +pci:v00008086d00003340sv0000144Dsd0000C005* + ID_MODEL_FROM_DATABASE=X10 Laptop + +pci:v00008086d00003340sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30/P35 notebook + +pci:v00008086d00003341* + ID_MODEL_FROM_DATABASE=82855PM Processor to AGP Controller + +pci:v00008086d00003341sv0000144Dsd0000C00C* + ID_MODEL_FROM_DATABASE=P30 notebook + +pci:v00008086d00003363* + ID_MODEL_FROM_DATABASE=IOC340 I/O Controller in IOC Mode SAS/SATA + +pci:v00008086d00003382* + ID_MODEL_FROM_DATABASE=81342 [Chevelon] I/O Processor (ATUe) + +pci:v00008086d000033C3* + ID_MODEL_FROM_DATABASE=IOP348 I/O Processor (SL8De) in IOC Mode SAS/SATA + +pci:v00008086d000033CB* + ID_MODEL_FROM_DATABASE=IOP348 I/O Processor (SL8Dx) in IOC Mode SAS/SATA + +pci:v00008086d00003400* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003401* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003402* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003403* + ID_MODEL_FROM_DATABASE=5500 I/O Hub to ESI Port + +pci:v00008086d00003403sv00001028sd00000236* + ID_MODEL_FROM_DATABASE=PowerEdge R610 I/O Hub to ESI Port + +pci:v00008086d00003403sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge M610 I/O Hub to ESI Port + +pci:v00008086d00003403sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 I/O Hub to ESI Port + +pci:v00008086d00003403sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 I/O Hub to ESI Port + +pci:v00008086d00003403sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003404* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003405* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003406* + ID_MODEL_FROM_DATABASE=5520 I/O Hub to ESI Port + +pci:v00008086d00003406sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003407* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub to ESI Port + +pci:v00008086d00003408* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub PCI Express Root Port 1 + +pci:v00008086d00003408sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003409* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub PCI Express Root Port 2 + +pci:v00008086d0000340A* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub PCI Express Root Port 3 + +pci:v00008086d0000340Asv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d0000340B* + ID_MODEL_FROM_DATABASE=5520/X58 I/O Hub PCI Express Root Port 4 + +pci:v00008086d0000340C* + ID_MODEL_FROM_DATABASE=5520/X58 I/O Hub PCI Express Root Port 5 + +pci:v00008086d0000340D* + ID_MODEL_FROM_DATABASE=5520/X58 I/O Hub PCI Express Root Port 6 + +pci:v00008086d0000340E* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub PCI Express Root Port 7 + +pci:v00008086d0000340Esv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d0000340F* + ID_MODEL_FROM_DATABASE=5520/5500/X58 I/O Hub PCI Express Root Port 8 + +pci:v00008086d00003410* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub PCI Express Root Port 9 + +pci:v00008086d00003411* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub PCI Express Root Port 10 + +pci:v00008086d00003418* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 Physical Layer Port 0 + +pci:v00008086d00003419* + ID_MODEL_FROM_DATABASE=7500/5520/5500 Physical Layer Port 1 + +pci:v00008086d00003420* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub PCI Express Root Port 0 + +pci:v00008086d00003421* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub PCI Express Root Port 0 + +pci:v00008086d00003422* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub GPIO and Scratch Pad Registers + +pci:v00008086d00003422sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003423* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub Control Status and RAS Registers + +pci:v00008086d00003423sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003425* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 Physical and Link Layer Registers Port 0 + +pci:v00008086d00003426* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 Routing and Protocol Layer Registers Port 0 + +pci:v00008086d00003427* + ID_MODEL_FROM_DATABASE=7500/5520/5500 Physical and Link Layer Registers Port 1 + +pci:v00008086d00003428* + ID_MODEL_FROM_DATABASE=7500/5520/5500 Routing & Protocol Layer Register Port 1 + +pci:v00008086d00003429* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d0000342A* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d0000342B* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d0000342C* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d0000342D* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub I/OxAPIC Interrupt Controller + +pci:v00008086d0000342E* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub System Management Registers + +pci:v00008086d0000342Esv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d0000342F* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 Trusted Execution Technology Registers + +pci:v00008086d00003430* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d00003431* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d00003432* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d00003433* + ID_MODEL_FROM_DATABASE=5520/5500/X58 Chipset QuickData Technology Device + +pci:v00008086d00003438* + ID_MODEL_FROM_DATABASE=7500/5520/5500/X58 I/O Hub Throttle Registers + +pci:v00008086d00003500* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express Upstream Port + +pci:v00008086d00003500sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00003500sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00003501* + ID_MODEL_FROM_DATABASE=6310ESB PCI Express Upstream Port + +pci:v00008086d00003504* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB I/OxAPIC Interrupt Controller + +pci:v00008086d00003505* + ID_MODEL_FROM_DATABASE=6310ESB I/OxAPIC Interrupt Controller + +pci:v00008086d0000350C* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express to PCI-X Bridge + +pci:v00008086d0000350Csv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d0000350Csv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d0000350D* + ID_MODEL_FROM_DATABASE=6310ESB PCI Express to PCI-X Bridge + +pci:v00008086d00003510* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express Downstream Port E1 + +pci:v00008086d00003510sv0000103Csd000031FE* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G3 + +pci:v00008086d00003510sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00003511* + ID_MODEL_FROM_DATABASE=6310ESB PCI Express Downstream Port E1 + +pci:v00008086d00003514* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express Downstream Port E2 + +pci:v00008086d00003515* + ID_MODEL_FROM_DATABASE=6310ESB PCI Express Downstream Port E2 + +pci:v00008086d00003518* + ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express Downstream Port E3 + +pci:v00008086d00003518sv000015D9sd00009680* + ID_MODEL_FROM_DATABASE=X7DBN Motherboard + +pci:v00008086d00003519* + ID_MODEL_FROM_DATABASE=6310ESB PCI Express Downstream Port E3 + +pci:v00008086d00003575* + ID_MODEL_FROM_DATABASE=82830M/MG/MP Host Bridge + +pci:v00008086d00003575sv00000E11sd00000030* + ID_MODEL_FROM_DATABASE=Evo N600c + +pci:v00008086d00003575sv00001014sd0000021D* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00003575sv0000104Dsd000080E7* + ID_MODEL_FROM_DATABASE=VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP + +pci:v00008086d00003576* + ID_MODEL_FROM_DATABASE=82830M/MP AGP Bridge + +pci:v00008086d00003577* + ID_MODEL_FROM_DATABASE=82830M/MG Integrated Graphics Controller + +pci:v00008086d00003577sv00001014sd00000513* + ID_MODEL_FROM_DATABASE=ThinkPad A/T/X Series + +pci:v00008086d00003578* + ID_MODEL_FROM_DATABASE=82830M/MG/MP Host Bridge + +pci:v00008086d00003580* + ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller + +pci:v00008086d00003580sv00001014sd0000055C* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v00008086d00003580sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d00003580sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d00003580sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d00003580sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d00003580sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d00003580sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d00003580sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 + +pci:v00008086d00003580sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d00003580sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d00003580sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00003580sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d00003580sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d00003580sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d00003580sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d00003581* + ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to AGP Controller + +pci:v00008086d00003581sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d00003582* + ID_MODEL_FROM_DATABASE=82852/855GM Integrated Graphics Device + +pci:v00008086d00003582sv00001014sd00000562* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v00008086d00003582sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d00003582sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d00003582sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d00003582sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d00003582sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d00003582sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 integrated graphics + +pci:v00008086d00003582sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer VGA + +pci:v00008086d00003582sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00003582sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d00003582sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d00003582sv0000E4BFsd00000CC9* + ID_MODEL_FROM_DATABASE=CC9-SAMBA + +pci:v00008086d00003582sv0000E4BFsd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v00008086d00003584* + ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller + +pci:v00008086d00003584sv00001014sd0000055D* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v00008086d00003584sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d00003584sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d00003584sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d00003584sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d00003584sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d00003584sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d00003584sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 + +pci:v00008086d00003584sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d00003584sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d00003584sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00003584sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d00003584sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d00003585* + ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller + +pci:v00008086d00003585sv00001014sd0000055E* + ID_MODEL_FROM_DATABASE=ThinkPad R50e + +pci:v00008086d00003585sv00001028sd00000139* + ID_MODEL_FROM_DATABASE=Latitude D400 + +pci:v00008086d00003585sv00001028sd0000014F* + ID_MODEL_FROM_DATABASE=Latitude X300 + +pci:v00008086d00003585sv00001028sd00000152* + ID_MODEL_FROM_DATABASE=Latitude D500 + +pci:v00008086d00003585sv00001028sd00000163* + ID_MODEL_FROM_DATABASE=Latitude D505 + +pci:v00008086d00003585sv00001028sd0000018D* + ID_MODEL_FROM_DATABASE=Inspiron 700m/710m + +pci:v00008086d00003585sv00001028sd00000196* + ID_MODEL_FROM_DATABASE=Inspiron 5160 + +pci:v00008086d00003585sv0000114Asd00000582* + ID_MODEL_FROM_DATABASE=PC8 + +pci:v00008086d00003585sv00001734sd00001055* + ID_MODEL_FROM_DATABASE=Amilo M1420 + +pci:v00008086d00003585sv00001775sd000010D0* + ID_MODEL_FROM_DATABASE=V5D Single Board Computer + +pci:v00008086d00003585sv00001775sd0000CE90* + ID_MODEL_FROM_DATABASE=CE9 + +pci:v00008086d00003585sv00004C53sd000010B0* + ID_MODEL_FROM_DATABASE=CL9 mainboard + +pci:v00008086d00003585sv00004C53sd000010E0* + ID_MODEL_FROM_DATABASE=PSL09 PrPMC + +pci:v00008086d0000358C* + ID_MODEL_FROM_DATABASE=82854 GMCH + +pci:v00008086d0000358E* + ID_MODEL_FROM_DATABASE=82854 GMCH Integrated Graphics Device + +pci:v00008086d00003590* + ID_MODEL_FROM_DATABASE=E7520 Memory Controller Hub + +pci:v00008086d00003590sv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d00003590sv00001028sd0000016C* + ID_MODEL_FROM_DATABASE=PowerEdge 1850 Memory Controller Hub + +pci:v00008086d00003590sv00001028sd0000016D* + ID_MODEL_FROM_DATABASE=PowerEdge 2850 Memory Controller Hub + +pci:v00008086d00003590sv00001028sd0000019A* + ID_MODEL_FROM_DATABASE=PowerEdge SC1425 + +pci:v00008086d00003590sv00001734sd0000103E* + ID_MODEL_FROM_DATABASE=PRIMERGY RX/TX S2 series + +pci:v00008086d00003590sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00003590sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d00003591* + ID_MODEL_FROM_DATABASE=E7525/E7520 Error Reporting Registers + +pci:v00008086d00003591sv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d00003591sv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d00003591sv0000103Csd00003208* + ID_MODEL_FROM_DATABASE=ProLiant DL140 G2 + +pci:v00008086d00003591sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d00003592* + ID_MODEL_FROM_DATABASE=E7320 Memory Controller Hub + +pci:v00008086d00003592sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d00003593* + ID_MODEL_FROM_DATABASE=E7320 Error Reporting Registers + +pci:v00008086d00003593sv00001734sd00001073* + ID_MODEL_FROM_DATABASE=Primergy Econel 200 D2020 mainboard + +pci:v00008086d00003594* + ID_MODEL_FROM_DATABASE=E7520 DMA Controller + +pci:v00008086d00003594sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00003594sv00004C53sd000010D0* + ID_MODEL_FROM_DATABASE=Telum ASLP10 Processor AMC + +pci:v00008086d00003595* + ID_MODEL_FROM_DATABASE=E7525/E7520/E7320 PCI Express Port A + +pci:v00008086d00003595sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00003596* + ID_MODEL_FROM_DATABASE=E7525/E7520/E7320 PCI Express Port A1 + +pci:v00008086d00003597* + ID_MODEL_FROM_DATABASE=E7525/E7520 PCI Express Port B + +pci:v00008086d00003597sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00003598* + ID_MODEL_FROM_DATABASE=E7520 PCI Express Port B1 + +pci:v00008086d00003598sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d00003599* + ID_MODEL_FROM_DATABASE=E7520 PCI Express Port C + +pci:v00008086d00003599sv00001775sd00001100* + ID_MODEL_FROM_DATABASE=CR11/VR11 Single Board Computer + +pci:v00008086d0000359A* + ID_MODEL_FROM_DATABASE=E7520 PCI Express Port C1 + +pci:v00008086d0000359B* + ID_MODEL_FROM_DATABASE=E7525/E7520/E7320 Extended Configuration Registers + +pci:v00008086d0000359Bsv00001014sd000002DD* + ID_MODEL_FROM_DATABASE=eServer xSeries server mainboard + +pci:v00008086d0000359E* + ID_MODEL_FROM_DATABASE=E7525 Memory Controller Hub + +pci:v00008086d0000359Esv00001028sd00000169* + ID_MODEL_FROM_DATABASE=Precision 470 + +pci:v00008086d000035B0* + ID_MODEL_FROM_DATABASE=3100 Chipset Memory I/O Controller Hub + +pci:v00008086d000035B1* + ID_MODEL_FROM_DATABASE=3100 DRAM Controller Error Reporting Registers + +pci:v00008086d000035B5* + ID_MODEL_FROM_DATABASE=3100 Chipset Enhanced DMA Controller + +pci:v00008086d000035B6* + ID_MODEL_FROM_DATABASE=3100 Chipset PCI Express Port A + +pci:v00008086d000035B7* + ID_MODEL_FROM_DATABASE=3100 Chipset PCI Express Port A1 + +pci:v00008086d000035C8* + ID_MODEL_FROM_DATABASE=3100 Extended Configuration Test Overflow Registers + +pci:v00008086d00003600* + ID_MODEL_FROM_DATABASE=7300 Chipset Memory Controller Hub + +pci:v00008086d00003604* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 1 + +pci:v00008086d00003605* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 2 + +pci:v00008086d00003606* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 3 + +pci:v00008086d00003607* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 4 + +pci:v00008086d00003608* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 5 + +pci:v00008086d00003609* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 6 + +pci:v00008086d0000360A* + ID_MODEL_FROM_DATABASE=7300 Chipset PCI Express Port 7 + +pci:v00008086d0000360B* + ID_MODEL_FROM_DATABASE=7300 Chipset QuickData Technology Device + +pci:v00008086d0000360C* + ID_MODEL_FROM_DATABASE=7300 Chipset FSB Registers + +pci:v00008086d0000360Csv00001028sd000001F0* + ID_MODEL_FROM_DATABASE=PowerEdge R900 7300 Chipset FSB Registers + +pci:v00008086d0000360D* + ID_MODEL_FROM_DATABASE=7300 Chipset Snoop Filter Registers + +pci:v00008086d0000360E* + ID_MODEL_FROM_DATABASE=7300 Chipset Debug and Miscellaneous Registers + +pci:v00008086d0000360F* + ID_MODEL_FROM_DATABASE=7300 Chipset FBD Branch 0 Registers + +pci:v00008086d00003610* + ID_MODEL_FROM_DATABASE=7300 Chipset FBD Branch 1 Registers + +pci:v00008086d00003700* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003701* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003702* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003703* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003704* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003705* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003706* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003707* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003708* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003709* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370A* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370B* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370C* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370D* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370E* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d0000370F* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 DMI + +pci:v00008086d00003710* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003711* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003712* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003713* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003714* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003715* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003716* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003717* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003718* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d00003719* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 CB3 DMA + +pci:v00008086d0000371A* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Link + +pci:v00008086d0000371B* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Routing and Protocol + +pci:v00008086d0000371D* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 QPI Routing and Protocol + +pci:v00008086d00003720* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 PCI Express Root Port 0 + +pci:v00008086d00003721* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 PCI Express Root Port 1 + +pci:v00008086d00003722* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 PCI Express Root Port 2 + +pci:v00008086d00003723* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 PCI Express Root Port 3 + +pci:v00008086d00003724* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 PCI Express Root Port 4 + +pci:v00008086d00003725* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 NTB Primary + +pci:v00008086d00003726* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 NTB Primary + +pci:v00008086d00003727* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 NTB Secondary + +pci:v00008086d00003728* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Core + +pci:v00008086d00003729* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Core + +pci:v00008086d0000372A* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Core + +pci:v00008086d0000372B* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Core + +pci:v00008086d0000372C* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 Reserved + +pci:v00008086d0000373F* + ID_MODEL_FROM_DATABASE=Xeon C5500/C3500 IOxAPIC + +pci:v00008086d00003A00* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) 4-port SATA IDE Controller + +pci:v00008086d00003A02* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) SATA AHCI Controller + +pci:v00008086d00003A05* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) SATA RAID Controller + +pci:v00008086d00003A06* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) 2-port SATA IDE Controller + +pci:v00008086d00003A14* + ID_MODEL_FROM_DATABASE=82801JDO (ICH10DO) LPC Interface Controller + +pci:v00008086d00003A16* + ID_MODEL_FROM_DATABASE=82801JIR (ICH10R) LPC Interface Controller + +pci:v00008086d00003A16sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 LPC Interface Controller + +pci:v00008086d00003A16sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 LPC Interface Controller + +pci:v00008086d00003A16sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A16sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A16sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A18* + ID_MODEL_FROM_DATABASE=82801JIB (ICH10) LPC Interface Controller + +pci:v00008086d00003A1A* + ID_MODEL_FROM_DATABASE=82801JD (ICH10D) LPC Interface Controller + +pci:v00008086d00003A20* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) 4 port SATA IDE Controller #1 + +pci:v00008086d00003A20sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 SATA IDE Controller + +pci:v00008086d00003A20sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 SATA IDE Controller + +pci:v00008086d00003A22* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) SATA AHCI Controller + +pci:v00008086d00003A22sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A22sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A22sv00001458sd0000B005* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00003A25* + ID_MODEL_FROM_DATABASE=82801JIR (ICH10R) SATA RAID Controller + +pci:v00008086d00003A25sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PERC S100 Controller (PE R410) + +pci:v00008086d00003A25sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PERC S100 Controller (PE T410) + +pci:v00008086d00003A25sv00001028sd000002F1* + ID_MODEL_FROM_DATABASE=PERC S100 Controller (PE R510) + +pci:v00008086d00003A26* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) 2 port SATA IDE Controller #2 + +pci:v00008086d00003A26sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 SATA IDE Controller + +pci:v00008086d00003A26sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 SATA IDE Controller + +pci:v00008086d00003A30* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) SMBus Controller + +pci:v00008086d00003A30sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A30sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00003A32* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) Thermal Subsystem + +pci:v00008086d00003A34* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #1 + +pci:v00008086d00003A34sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A34sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A34sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A34sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A34sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A35* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #2 + +pci:v00008086d00003A35sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A35sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A35sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A35sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A35sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A36* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #3 + +pci:v00008086d00003A36sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A36sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A36sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A36sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A36sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A37* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #4 + +pci:v00008086d00003A37sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A37sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A37sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A37sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A37sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00003A38* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #5 + +pci:v00008086d00003A38sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A38sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A38sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003A38sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A38sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00003A39* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB UHCI Controller #6 + +pci:v00008086d00003A39sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB UHCI Controller + +pci:v00008086d00003A39sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB UHCI Controller + +pci:v00008086d00003A39sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003A39sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A39sv00001458sd00005004* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00003A3A* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB2 EHCI Controller #1 + +pci:v00008086d00003A3Asv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB EHCI Controller + +pci:v00008086d00003A3Asv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB EHCI Controller + +pci:v00008086d00003A3Asv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A3Asv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A3Asv00001458sd00005006* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A3C* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) USB2 EHCI Controller #2 + +pci:v00008086d00003A3Csv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 USB EHCI Controller + +pci:v00008086d00003A3Csv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 USB EHCI Controller + +pci:v00008086d00003A3Csv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant G6 series + +pci:v00008086d00003A3Csv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A3Csv00001458sd00005006* + ID_MODEL_FROM_DATABASE=Motherboard + +pci:v00008086d00003A3E* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) HD Audio Controller + +pci:v00008086d00003A3Esv00001043sd00008311* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A3Esv00001458sd0000A002* + ID_MODEL_FROM_DATABASE=GA-EP45-UD3R Motherboard + +pci:v00008086d00003A3Esv00001458sd0000A102* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00003A40* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Root Port 1 + +pci:v00008086d00003A40sv00001028sd0000028C* + ID_MODEL_FROM_DATABASE=PowerEdge R410 PCI Express Port 1 + +pci:v00008086d00003A40sv00001028sd0000028D* + ID_MODEL_FROM_DATABASE=PowerEdge T410 PCI Express Port 1 + +pci:v00008086d00003A40sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003A40sv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A40sv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P6T DeLuxe Motherboard + +pci:v00008086d00003A40sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00003A42* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Port 2 + +pci:v00008086d00003A44* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Root Port 3 + +pci:v00008086d00003A44sv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P6T DeLuxe Motherboard + +pci:v00008086d00003A46* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Root Port 4 + +pci:v00008086d00003A46sv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P6T DeLuxe Motherboard + +pci:v00008086d00003A46sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A48* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Root Port 5 + +pci:v00008086d00003A48sv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003A48sv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P6T Deluxe Motherboard + +pci:v00008086d00003A48sv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5 Motherboard + +pci:v00008086d00003A4A* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) PCI Express Root Port 6 + +pci:v00008086d00003A4Asv0000103Csd0000330B* + ID_MODEL_FROM_DATABASE=ProLiant ML150 G6 Server + +pci:v00008086d00003A4Asv00001043sd000082D4* + ID_MODEL_FROM_DATABASE=P5Q Deluxe Motherboard + +pci:v00008086d00003A4Asv00001043sd000082EA* + ID_MODEL_FROM_DATABASE=P6T DeLuxe Motherboard + +pci:v00008086d00003A4Asv00001458sd00005001* + ID_MODEL_FROM_DATABASE=GA-EP45-DS5/GA-EG45M-DS2H Motherboard + +pci:v00008086d00003A4C* + ID_MODEL_FROM_DATABASE=82801JI (ICH10 Family) Gigabit Ethernet Controller + +pci:v00008086d00003A51* + ID_MODEL_FROM_DATABASE=82801JDO (ICH10DO) VECI Controller + +pci:v00008086d00003A55* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) Virtual SATA Controller + +pci:v00008086d00003A60* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) SMBus Controller + +pci:v00008086d00003A62* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) Thermal Subsystem + +pci:v00008086d00003A64* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #1 + +pci:v00008086d00003A65* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #2 + +pci:v00008086d00003A66* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #3 + +pci:v00008086d00003A67* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #4 + +pci:v00008086d00003A68* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #5 + +pci:v00008086d00003A69* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB UHCI Controller #6 + +pci:v00008086d00003A6A* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB2 EHCI Controller #1 + +pci:v00008086d00003A6C* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) USB2 EHCI Controller #2 + +pci:v00008086d00003A6E* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) HD Audio Controller + +pci:v00008086d00003A70* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 1 + +pci:v00008086d00003A72* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 2 + +pci:v00008086d00003A74* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 3 + +pci:v00008086d00003A76* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 4 + +pci:v00008086d00003A78* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 5 + +pci:v00008086d00003A7A* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) PCI Express Port 6 + +pci:v00008086d00003A7C* + ID_MODEL_FROM_DATABASE=82801JD/DO (ICH10 Family) Gigabit Ethernet Controller + +pci:v00008086d00003B00* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B01* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B02* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B03* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B04* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B05* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B06* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B07* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B07sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B07sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B08* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B09* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B09sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B0A* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B0Asv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B0B* + ID_MODEL_FROM_DATABASE=Mobile 5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B0C* + ID_MODEL_FROM_DATABASE=5 Series Chipset LPC Interface Controller + +pci:v00008086d00003B0D* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B0E* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B0F* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B10* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B11* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B12* + ID_MODEL_FROM_DATABASE=3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B13* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B14* + ID_MODEL_FROM_DATABASE=3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B15* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B16* + ID_MODEL_FROM_DATABASE=3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B17* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B18* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B19* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1A* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1B* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1C* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1D* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1E* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B1F* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LPC Interface Controller + +pci:v00008086d00003B20* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 4 port SATA IDE Controller + +pci:v00008086d00003B21* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 2 port SATA IDE Controller + +pci:v00008086d00003B22* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 6 port SATA AHCI Controller + +pci:v00008086d00003B22sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B23* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 4 port SATA AHCI Controller + +pci:v00008086d00003B25* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset SATA RAID Controller + +pci:v00008086d00003B26* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 2 port SATA IDE Controller + +pci:v00008086d00003B28* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 4 port SATA IDE Controller + +pci:v00008086d00003B29* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 4 port SATA AHCI Controller + +pci:v00008086d00003B29sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B2C* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset SATA RAID Controller + +pci:v00008086d00003B2D* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 2 port SATA IDE Controller + +pci:v00008086d00003B2Dsv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B2E* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 4 port SATA IDE Controller + +pci:v00008086d00003B2Esv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B2F* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset 6 port SATA AHCI Controller + +pci:v00008086d00003B2Fsv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B2Fsv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B30* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset SMBus Controller + +pci:v00008086d00003B30sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B30sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B30sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B30sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B32* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset Thermal Subsystem + +pci:v00008086d00003B32sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B34* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB2 Enhanced Host Controller + +pci:v00008086d00003B34sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B34sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B34sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B34sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B36* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B37* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B38* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B39* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B3A* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B3B* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B3C* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB2 Enhanced Host Controller + +pci:v00008086d00003B3Csv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B3Csv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B3Csv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B3Csv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B3E* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B3F* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B40* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset USB Universal Host Controller + +pci:v00008086d00003B41* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset LAN Controller + +pci:v00008086d00003B42* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 1 + +pci:v00008086d00003B42sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B42sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B44* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 2 + +pci:v00008086d00003B44sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B46* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 3 + +pci:v00008086d00003B46sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B48* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 4 + +pci:v00008086d00003B48sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B4A* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 5 + +pci:v00008086d00003B4Asv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B4C* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 6 + +pci:v00008086d00003B4E* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 7 + +pci:v00008086d00003B50* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PCI Express Root Port 8 + +pci:v00008086d00003B53* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset VECI Controller + +pci:v00008086d00003B56* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset High Definition Audio + +pci:v00008086d00003B56sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B56sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d00003B56sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d00003B56sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B57* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset High Definition Audio + +pci:v00008086d00003B64* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset HECI Controller + +pci:v00008086d00003B64sv00001025sd00000347* + ID_MODEL_FROM_DATABASE=Aspire 7740G + +pci:v00008086d00003B64sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003B65* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset HECI Controller + +pci:v00008086d00003B66* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset PT IDER Controller + +pci:v00008086d00003B67* + ID_MODEL_FROM_DATABASE=5 Series/3400 Series Chipset KT Controller + +pci:v00008086d00003B67sv0000E4BFsd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v00008086d00003C00* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMI2 + +pci:v00008086d00003C01* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMI2 in PCI Express Mode + +pci:v00008086d00003C02* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 1a + +pci:v00008086d00003C03* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 1b + +pci:v00008086d00003C04* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 2a + +pci:v00008086d00003C05* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 2b + +pci:v00008086d00003C06* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 2c + +pci:v00008086d00003C07* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 2d + +pci:v00008086d00003C08* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 3a in PCI Express Mode + +pci:v00008086d00003C09* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 3b + +pci:v00008086d00003C0A* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 3c + +pci:v00008086d00003C0B* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO PCI Express Root Port 3d + +pci:v00008086d00003C0D* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Non-Transparent Bridge + +pci:v00008086d00003C0E* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Non-Transparent Bridge + +pci:v00008086d00003C0F* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Non-Transparent Bridge + +pci:v00008086d00003C20* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 0 + +pci:v00008086d00003C21* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 1 + +pci:v00008086d00003C22* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 2 + +pci:v00008086d00003C23* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 3 + +pci:v00008086d00003C24* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 4 + +pci:v00008086d00003C25* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 5 + +pci:v00008086d00003C26* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 6 + +pci:v00008086d00003C27* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA Channel 7 + +pci:v00008086d00003C28* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Address Map, VTd_Misc, System Management + +pci:v00008086d00003C2A* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Control Status and Global Errors + +pci:v00008086d00003C2C* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 I/O APIC + +pci:v00008086d00003C2E* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA + +pci:v00008086d00003C2F* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DMA + +pci:v00008086d00003C40* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 IIO Switch and IRP Performance Monitor + +pci:v00008086d00003C43* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Ring to PCI Express Performance Monitor + +pci:v00008086d00003C44* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Ring to QuickPath Interconnect Link 0 Performance Monitor + +pci:v00008086d00003C45* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Ring to QuickPath Interconnect Link 1 Performance Monitor + +pci:v00008086d00003C46* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Processor Home Agent Performance Monitoring + +pci:v00008086d00003C71* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller RAS Registers + +pci:v00008086d00003C80* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link 0 + +pci:v00008086d00003C83* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link Reut 0 + +pci:v00008086d00003C84* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link Reut 0 + +pci:v00008086d00003C90* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link 1 + +pci:v00008086d00003C93* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link Reut 1 + +pci:v00008086d00003C94* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QPI Link Reut 1 + +pci:v00008086d00003CA0* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Processor Home Agent + +pci:v00008086d00003CA8* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Registers + +pci:v00008086d00003CAA* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 0 + +pci:v00008086d00003CAB* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 1 + +pci:v00008086d00003CAC* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 2 + +pci:v00008086d00003CAD* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 3 + +pci:v00008086d00003CAE* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Target Address Decoder 4 + +pci:v00008086d00003CB0* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 0 + +pci:v00008086d00003CB1* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 1 + +pci:v00008086d00003CB2* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 0 + +pci:v00008086d00003CB3* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 1 + +pci:v00008086d00003CB4* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 2 + +pci:v00008086d00003CB5* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller Channel 0-3 Thermal Control 3 + +pci:v00008086d00003CB6* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 2 + +pci:v00008086d00003CB7* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller ERROR Registers 3 + +pci:v00008086d00003CB8* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 DDRIO + +pci:v00008086d00003CC0* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Power Control Unit 0 + +pci:v00008086d00003CC1* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Power Control Unit 1 + +pci:v00008086d00003CC2* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Power Control Unit 2 + +pci:v00008086d00003CD0* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Power Control Unit 3 + +pci:v00008086d00003CE0* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Interrupt Control Registers + +pci:v00008086d00003CE3* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Semaphore and Scratchpad Configuration Registers + +pci:v00008086d00003CE4* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 R2PCIe + +pci:v00008086d00003CE6* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 QuickPath Interconnect Agent Ring Registers + +pci:v00008086d00003CE8* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 0 + +pci:v00008086d00003CE9* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 5 + +pci:v00008086d00003CEA* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 1 + +pci:v00008086d00003CEB* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 6 + +pci:v00008086d00003CEC* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 3 + +pci:v00008086d00003CED* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 7 + +pci:v00008086d00003CEE* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 4 + +pci:v00008086d00003CEF* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Unicast Register 8 + +pci:v00008086d00003CF4* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 0 + +pci:v00008086d00003CF5* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 Integrated Memory Controller System Address Decoder 1 + +pci:v00008086d00003CF6* + ID_MODEL_FROM_DATABASE=Xeon E5/Core i7 System Address Decoder + +pci:v00008086d00004000* + ID_MODEL_FROM_DATABASE=5400 Chipset Memory Controller Hub + +pci:v00008086d00004001* + ID_MODEL_FROM_DATABASE=5400 Chipset Memory Controller Hub + +pci:v00008086d00004003* + ID_MODEL_FROM_DATABASE=5400 Chipset Memory Controller Hub + +pci:v00008086d00004021* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 1 + +pci:v00008086d00004022* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 2 + +pci:v00008086d00004023* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 3 + +pci:v00008086d00004024* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 4 + +pci:v00008086d00004025* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 5 + +pci:v00008086d00004026* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 6 + +pci:v00008086d00004027* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 7 + +pci:v00008086d00004028* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 8 + +pci:v00008086d00004029* + ID_MODEL_FROM_DATABASE=5400 Chipset PCI Express Port 9 + +pci:v00008086d0000402D* + ID_MODEL_FROM_DATABASE=5400 Chipset IBIST Registers + +pci:v00008086d0000402E* + ID_MODEL_FROM_DATABASE=5400 Chipset IBIST Registers + +pci:v00008086d0000402F* + ID_MODEL_FROM_DATABASE=5400 Chipset QuickData Technology Device + +pci:v00008086d00004030* + ID_MODEL_FROM_DATABASE=5400 Chipset FSB Registers + +pci:v00008086d00004031* + ID_MODEL_FROM_DATABASE=5400 Chipset CE/SF Registers + +pci:v00008086d00004032* + ID_MODEL_FROM_DATABASE=5400 Chipset IOxAPIC + +pci:v00008086d00004035* + ID_MODEL_FROM_DATABASE=5400 Chipset FBD Registers + +pci:v00008086d00004036* + ID_MODEL_FROM_DATABASE=5400 Chipset FBD Registers + +pci:v00008086d00004100* + ID_MODEL_FROM_DATABASE=Moorestown Graphics and Video + +pci:v00008086d00004108* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d00004109* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410A* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410B* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410C* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410D* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410E* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d0000410F* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d00004114* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Host Bridge #1 + +pci:v00008086d00004115* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Host Bridge #2 + +pci:v00008086d00004116* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Host Bridge #3 + +pci:v00008086d00004117* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Host Bridge #4 + +pci:v00008086d00004220* + ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection + +pci:v00008086d00004220sv0000103Csd00000934* + ID_MODEL_FROM_DATABASE=Compaq nw8240/nx8220 + +pci:v00008086d00004220sv0000103Csd000012F6* + ID_MODEL_FROM_DATABASE=nc6120/nx8220/nw8240 + +pci:v00008086d00004220sv00008086sd00002701* + ID_MODEL_FROM_DATABASE=WM3B2300BG Mini-PCI Card + +pci:v00008086d00004220sv00008086sd00002712* + ID_MODEL_FROM_DATABASE=IBM ThinkPad R50e + +pci:v00008086d00004220sv00008086sd00002721* + ID_MODEL_FROM_DATABASE=Dell B130 laptop integrated WLAN + +pci:v00008086d00004220sv00008086sd00002722* + ID_MODEL_FROM_DATABASE=Dell Latitude D600 + +pci:v00008086d00004220sv00008086sd00002731* + ID_MODEL_FROM_DATABASE=Samsung P35 integrated WLAN + +pci:v00008086d00004222* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG [Golan] Network Connection + +pci:v00008086d00004222sv0000103Csd0000135C* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG [Golan] Network Connection + +pci:v00008086d00004222sv00008086sd00001000* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG Network Connection + +pci:v00008086d00004222sv00008086sd00001001* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG Network Connection + +pci:v00008086d00004222sv00008086sd00001005* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945BG Network Connection + +pci:v00008086d00004222sv00008086sd00001034* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945BG Network Connection + +pci:v00008086d00004222sv00008086sd00001044* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945BG Network Connection + +pci:v00008086d00004222sv00008086sd00001C00* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG Network Connection + +pci:v00008086d00004223* + ID_MODEL_FROM_DATABASE=PRO/Wireless 2915ABG [Calexico2] Network Connection + +pci:v00008086d00004223sv00001000sd00008086* + ID_MODEL_FROM_DATABASE=mPCI 3B Americas/Europe ZZA + +pci:v00008086d00004223sv00001001sd00008086* + ID_MODEL_FROM_DATABASE=mPCI 3B Europe ZZE + +pci:v00008086d00004223sv00001002sd00008086* + ID_MODEL_FROM_DATABASE=mPCI 3B Japan ZZJ + +pci:v00008086d00004223sv00001003sd00008086* + ID_MODEL_FROM_DATABASE=mPCI 3B High-Band ZZH + +pci:v00008086d00004223sv00001351sd0000103C* + ID_MODEL_FROM_DATABASE=Compaq NC6220 + +pci:v00008086d00004224* + ID_MODEL_FROM_DATABASE=PRO/Wireless 2915ABG [Calexico2] Network Connection + +pci:v00008086d00004227* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945ABG [Golan] Network Connection + +pci:v00008086d00004227sv00008086sd00001011* + ID_MODEL_FROM_DATABASE=ThinkPad T60/R60e/X60s + +pci:v00008086d00004227sv00008086sd00001014* + ID_MODEL_FROM_DATABASE=PRO/Wireless 3945BG Network Connection + +pci:v00008086d00004229* + ID_MODEL_FROM_DATABASE=PRO/Wireless 4965 AG or AGN [Kedron] Network Connection + +pci:v00008086d00004229sv00008086sd00001100* + ID_MODEL_FROM_DATABASE=Vaio VGN-SZ79SN_C + +pci:v00008086d00004229sv00008086sd00001101* + ID_MODEL_FROM_DATABASE=PRO/Wireless 4965 AG or AGN + +pci:v00008086d0000422B* + ID_MODEL_FROM_DATABASE=Centrino Ultimate-N 6300 + +pci:v00008086d0000422Bsv00008086sd00001101* + ID_MODEL_FROM_DATABASE=Centrino Ultimate-N 6300 3x3 AGN + +pci:v00008086d0000422Bsv00008086sd00001121* + ID_MODEL_FROM_DATABASE=Centrino Ultimate-N 6300 3x3 AGN + +pci:v00008086d0000422C* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 + +pci:v00008086d0000422Csv00008086sd00001301* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 AGN + +pci:v00008086d0000422Csv00008086sd00001306* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 ABG + +pci:v00008086d0000422Csv00008086sd00001307* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 BG + +pci:v00008086d0000422Csv00008086sd00001321* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 AGN + +pci:v00008086d0000422Csv00008086sd00001326* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 ABG + +pci:v00008086d00004230* + ID_MODEL_FROM_DATABASE=PRO/Wireless 4965 AG or AGN [Kedron] Network Connection + +pci:v00008086d00004230sv00008086sd00001110* + ID_MODEL_FROM_DATABASE=Lenovo ThinkPad T51 + +pci:v00008086d00004230sv00008086sd00001111* + ID_MODEL_FROM_DATABASE=Lenovo ThinkPad T61 + +pci:v00008086d00004232* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 + +pci:v00008086d00004232sv00008086sd00001201* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001204* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001205* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004232sv00008086sd00001206* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004232sv00008086sd00001221* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001224* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001225* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004232sv00008086sd00001226* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004232sv00008086sd00001301* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001304* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001305* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004232sv00008086sd00001306* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004232sv00008086sd00001321* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001324* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004232sv00008086sd00001325* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004232sv00008086sd00001326* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004235* + ID_MODEL_FROM_DATABASE=Ultimate N WiFi Link 5300 + +pci:v00008086d00004236* + ID_MODEL_FROM_DATABASE=Ultimate N WiFi Link 5300 + +pci:v00008086d00004237* + ID_MODEL_FROM_DATABASE=PRO/Wireless 5100 AGN [Shiloh] Network Connection + +pci:v00008086d00004237sv00008086sd00001211* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004237sv00008086sd00001214* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004237sv00008086sd00001215* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004237sv00008086sd00001216* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004237sv00008086sd00001311* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004237sv00008086sd00001314* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 AGN + +pci:v00008086d00004237sv00008086sd00001315* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 BGN + +pci:v00008086d00004237sv00008086sd00001316* + ID_MODEL_FROM_DATABASE=WiFi Link 5100 ABG + +pci:v00008086d00004238* + ID_MODEL_FROM_DATABASE=Centrino Ultimate-N 6300 + +pci:v00008086d00004238sv00008086sd00001111* + ID_MODEL_FROM_DATABASE=Centrino Ultimate-N 6300 3x3 AGN + +pci:v00008086d00004239* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 + +pci:v00008086d00004239sv00008086sd00001311* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 AGN + +pci:v00008086d00004239sv00008086sd00001316* + ID_MODEL_FROM_DATABASE=Centrino Advanced-N 6200 2x2 ABG + +pci:v00008086d0000423A* + ID_MODEL_FROM_DATABASE=PRO/Wireless 5350 AGN [Echo Peak] Network Connection + +pci:v00008086d0000423B* + ID_MODEL_FROM_DATABASE=PRO/Wireless 5350 AGN [Echo Peak] Network Connection + +pci:v00008086d0000423C* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 + +pci:v00008086d0000423Csv00008086sd00001201* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423Csv00008086sd00001206* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 ABG + +pci:v00008086d0000423Csv00008086sd00001221* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423Csv00008086sd00001301* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423Csv00008086sd00001306* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 ABG + +pci:v00008086d0000423Csv00008086sd00001321* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423D* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 + +pci:v00008086d0000423Dsv00008086sd00001211* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423Dsv00008086sd00001216* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 ABG + +pci:v00008086d0000423Dsv00008086sd00001311* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 AGN + +pci:v00008086d0000423Dsv00008086sd00001316* + ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 ABG + +pci:v00008086d0000444E* + ID_MODEL_FROM_DATABASE=Turbo Memory Controller + +pci:v00008086d00005001* + ID_MODEL_FROM_DATABASE=LE80578 + +pci:v00008086d00005002* + ID_MODEL_FROM_DATABASE=LE80578 Graphics Processor Unit + +pci:v00008086d00005009* + ID_MODEL_FROM_DATABASE=LE80578 Video Display Controller + +pci:v00008086d0000500D* + ID_MODEL_FROM_DATABASE=LE80578 Expansion Bus + +pci:v00008086d0000500E* + ID_MODEL_FROM_DATABASE=LE80578 UART Controller + +pci:v00008086d0000500F* + ID_MODEL_FROM_DATABASE=LE80578 General Purpose IO + +pci:v00008086d00005010* + ID_MODEL_FROM_DATABASE=LE80578 I2C Controller + +pci:v00008086d00005012* + ID_MODEL_FROM_DATABASE=LE80578 Serial Peripheral Interface Bus + +pci:v00008086d00005020* + ID_MODEL_FROM_DATABASE=EP80579 Memory Controller Hub + +pci:v00008086d00005021* + ID_MODEL_FROM_DATABASE=EP80579 DRAM Error Reporting Registers + +pci:v00008086d00005023* + ID_MODEL_FROM_DATABASE=EP80579 EDMA Controller + +pci:v00008086d00005024* + ID_MODEL_FROM_DATABASE=EP80579 PCI Express Port PEA0 + +pci:v00008086d00005025* + ID_MODEL_FROM_DATABASE=EP80579 PCI Express Port PEA1 + +pci:v00008086d00005028* + ID_MODEL_FROM_DATABASE=EP80579 S-ATA IDE + +pci:v00008086d00005029* + ID_MODEL_FROM_DATABASE=EP80579 S-ATA AHCI + +pci:v00008086d0000502A* + ID_MODEL_FROM_DATABASE=EP80579 S-ATA Reserved + +pci:v00008086d0000502B* + ID_MODEL_FROM_DATABASE=EP80579 S-ATA Reserved + +pci:v00008086d0000502C* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor ASU + +pci:v00008086d0000502D* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor with QuickAssist ASU + +pci:v00008086d0000502E* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d0000502F* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005030* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005031* + ID_MODEL_FROM_DATABASE=EP80579 LPC Bus + +pci:v00008086d00005032* + ID_MODEL_FROM_DATABASE=EP80579 SMBus Controller + +pci:v00008086d00005033* + ID_MODEL_FROM_DATABASE=EP80579 USB 1.1 Controller + +pci:v00008086d00005035* + ID_MODEL_FROM_DATABASE=EP80579 USB 2.0 Controller + +pci:v00008086d00005037* + ID_MODEL_FROM_DATABASE=EP80579 PCI-PCI Bridge (transparent mode) + +pci:v00008086d00005039* + ID_MODEL_FROM_DATABASE=EP80579 Controller Area Network (CAN) interface #1 + +pci:v00008086d0000503A* + ID_MODEL_FROM_DATABASE=EP80579 Controller Area Network (CAN) interface #2 + +pci:v00008086d0000503B* + ID_MODEL_FROM_DATABASE=EP80579 Synchronous Serial Port (SPP) + +pci:v00008086d0000503C* + ID_MODEL_FROM_DATABASE=EP80579 IEEE 1588 Hardware Assist + +pci:v00008086d0000503D* + ID_MODEL_FROM_DATABASE=EP80579 Local Expansion Bus + +pci:v00008086d0000503E* + ID_MODEL_FROM_DATABASE=EP80579 Global Control Unit (GCU) + +pci:v00008086d0000503F* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005040* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor Gigabit Ethernet MAC + +pci:v00008086d00005041* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC + +pci:v00008086d00005042* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005043* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005044* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor Gigabit Ethernet MAC + +pci:v00008086d00005045* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC + +pci:v00008086d00005046* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005047* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d00005048* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor Gigabit Ethernet MAC + +pci:v00008086d00005049* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor with QuickAssist Gigabit Ethernet MAC + +pci:v00008086d0000504A* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d0000504B* + ID_MODEL_FROM_DATABASE=EP80579 Reserved + +pci:v00008086d0000504C* + ID_MODEL_FROM_DATABASE=EP80579 Integrated Processor with QuickAssist TDM + +pci:v00008086d00005200* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Intelligent Server + +pci:v00008086d00005201* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Intelligent Server + +pci:v00008086d00005201sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=EtherExpress PRO/100 Server Ethernet Adapter + +pci:v00008086d0000530D* + ID_MODEL_FROM_DATABASE=80310 (IOP) IO Processor + +pci:v00008086d000065C0* + ID_MODEL_FROM_DATABASE=5100 Chipset Memory Controller Hub + +pci:v00008086d000065E2* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 2 + +pci:v00008086d000065E3* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 3 + +pci:v00008086d000065E4* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 4 + +pci:v00008086d000065E5* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 5 + +pci:v00008086d000065E6* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 6 + +pci:v00008086d000065E7* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x4 Port 7 + +pci:v00008086d000065F0* + ID_MODEL_FROM_DATABASE=5100 Chipset FSB Registers + +pci:v00008086d000065F0sv00001028sd0000020F* + ID_MODEL_FROM_DATABASE=PowerEdge R300 + +pci:v00008086d000065F0sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 + +pci:v00008086d000065F1* + ID_MODEL_FROM_DATABASE=5100 Chipset Reserved Registers + +pci:v00008086d000065F1sv00001028sd00000210* + ID_MODEL_FROM_DATABASE=PowerEdge T300 + +pci:v00008086d000065F3* + ID_MODEL_FROM_DATABASE=5100 Chipset Reserved Registers + +pci:v00008086d000065F5* + ID_MODEL_FROM_DATABASE=5100 Chipset DDR Channel 0 Registers + +pci:v00008086d000065F6* + ID_MODEL_FROM_DATABASE=5100 Chipset DDR Channel 1 Registers + +pci:v00008086d000065F7* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x8 Port 2-3 + +pci:v00008086d000065F8* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x8 Port 4-5 + +pci:v00008086d000065F9* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x8 Port 6-7 + +pci:v00008086d000065FA* + ID_MODEL_FROM_DATABASE=5100 Chipset PCI Express x16 Port 4-7 + +pci:v00008086d000065FF* + ID_MODEL_FROM_DATABASE=5100 Chipset DMA Engine + +pci:v00008086d00007000* + ID_MODEL_FROM_DATABASE=82371SB PIIX3 ISA [Natoma/Triton II] + +pci:v00008086d00007000sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v00008086d00007010* + ID_MODEL_FROM_DATABASE=82371SB PIIX3 IDE [Natoma/Triton II] + +pci:v00008086d00007010sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v00008086d00007020* + ID_MODEL_FROM_DATABASE=82371SB PIIX3 USB [Natoma/Triton II] + +pci:v00008086d00007020sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v00008086d00007030* + ID_MODEL_FROM_DATABASE=430VX - 82437VX TVX [Triton VX] + +pci:v00008086d00007050* + ID_MODEL_FROM_DATABASE=Intercast Video Capture Card + +pci:v00008086d00007051* + ID_MODEL_FROM_DATABASE=PB 642365-003 (Business Video Conferencing Card) + +pci:v00008086d00007100* + ID_MODEL_FROM_DATABASE=430TX - 82439TX MTXC + +pci:v00008086d00007110* + ID_MODEL_FROM_DATABASE=82371AB/EB/MB PIIX4 ISA + +pci:v00008086d00007110sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=Virtual Machine Chipset + +pci:v00008086d00007111* + ID_MODEL_FROM_DATABASE=82371AB/EB/MB PIIX4 IDE + +pci:v00008086d00007111sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=Virtual Machine Chipset + +pci:v00008086d00007112* + ID_MODEL_FROM_DATABASE=82371AB/EB/MB PIIX4 USB + +pci:v00008086d00007112sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=Virtual Machine Chipset + +pci:v00008086d00007113* + ID_MODEL_FROM_DATABASE=82371AB/EB/MB PIIX4 ACPI + +pci:v00008086d00007113sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=Virtual Machine Chipset + +pci:v00008086d00007113sv00001AF4sd00001100* + ID_MODEL_FROM_DATABASE=Qemu virtual machine + +pci:v00008086d00007120* + ID_MODEL_FROM_DATABASE=82810 GMCH (Graphics Memory Controller Hub) + +pci:v00008086d00007120sv00004C53sd00001040* + ID_MODEL_FROM_DATABASE=CL7 mainboard + +pci:v00008086d00007120sv00004C53sd00001060* + ID_MODEL_FROM_DATABASE=PC7 mainboard + +pci:v00008086d00007121* + ID_MODEL_FROM_DATABASE=82810 (CGC) Chipset Graphics Controller + +pci:v00008086d00007121sv00004C53sd00001040* + ID_MODEL_FROM_DATABASE=CL7 mainboard + +pci:v00008086d00007121sv00004C53sd00001060* + ID_MODEL_FROM_DATABASE=PC7 mainboard + +pci:v00008086d00007121sv00008086sd00004341* + ID_MODEL_FROM_DATABASE=Cayman (CA810) Mainboard + +pci:v00008086d00007122* + ID_MODEL_FROM_DATABASE=82810 DC-100 (GMCH) Graphics Memory Controller Hub + +pci:v00008086d00007123* + ID_MODEL_FROM_DATABASE=82810 DC-100 (CGC) Chipset Graphics Controller + +pci:v00008086d00007124* + ID_MODEL_FROM_DATABASE=82810E DC-133 (GMCH) Graphics Memory Controller Hub + +pci:v00008086d00007124sv00001028sd000000B4* + ID_MODEL_FROM_DATABASE=OptiPlex GX110 + +pci:v00008086d00007125* + ID_MODEL_FROM_DATABASE=82810E DC-133 (CGC) Chipset Graphics Controller + +pci:v00008086d00007125sv00001028sd000000B4* + ID_MODEL_FROM_DATABASE=OptiPlex GX110 + +pci:v00008086d00007126* + ID_MODEL_FROM_DATABASE=82810 DC-133 System and Graphics Controller + +pci:v00008086d00007128* + ID_MODEL_FROM_DATABASE=82810-M DC-100 System and Graphics Controller + +pci:v00008086d0000712A* + ID_MODEL_FROM_DATABASE=82810-M DC-133 System and Graphics Controller + +pci:v00008086d00007180* + ID_MODEL_FROM_DATABASE=440LX/EX - 82443LX/EX Host bridge + +pci:v00008086d00007181* + ID_MODEL_FROM_DATABASE=440LX/EX - 82443LX/EX AGP bridge + +pci:v00008086d00007190* + ID_MODEL_FROM_DATABASE=440BX/ZX/DX - 82443BX/ZX/DX Host bridge + +pci:v00008086d00007190sv00000E11sd00000500* + ID_MODEL_FROM_DATABASE=Armada 1750 Laptop System Chipset + +pci:v00008086d00007190sv00000E11sd0000B110* + ID_MODEL_FROM_DATABASE=Armada M700/E500 + +pci:v00008086d00007190sv00001028sd0000008E* + ID_MODEL_FROM_DATABASE=PowerEdge 1300 mainboard + +pci:v00008086d00007190sv00001043sd0000803B* + ID_MODEL_FROM_DATABASE=CUBX-L/E Mainboard + +pci:v00008086d00007190sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Toshiba Tecra 8100 Laptop System Chipset + +pci:v00008086d00007190sv000015ADsd00001976* + ID_MODEL_FROM_DATABASE=Virtual Machine Chipset + +pci:v00008086d00007190sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00008086d00007190sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v00008086d00007191* + ID_MODEL_FROM_DATABASE=440BX/ZX/DX - 82443BX/ZX/DX AGP bridge + +pci:v00008086d00007191sv00001028sd0000008E* + ID_MODEL_FROM_DATABASE=PowerEdge 1300 mainboard + +pci:v00008086d00007192* + ID_MODEL_FROM_DATABASE=440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled) + +pci:v00008086d00007192sv00000E11sd00000460* + ID_MODEL_FROM_DATABASE=Armada 1700 Laptop System Chipset + +pci:v00008086d00007192sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Satellite 4010 + +pci:v00008086d00007192sv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v00008086d00007192sv00008086sd00007190* + ID_MODEL_FROM_DATABASE=Dell PowerEdge 350 + +pci:v00008086d00007194* + ID_MODEL_FROM_DATABASE=82440MX Host Bridge + +pci:v00008086d00007194sv00001033sd00000000* + ID_MODEL_FROM_DATABASE=Versa Note Vxi + +pci:v00008086d00007194sv00004C53sd000010A0* + ID_MODEL_FROM_DATABASE=CA3/CR3 mainboard + +pci:v00008086d00007195* + ID_MODEL_FROM_DATABASE=82440MX AC'97 Audio Controller + +pci:v00008086d00007195sv00001033sd000080CC* + ID_MODEL_FROM_DATABASE=Versa Note VXi + +pci:v00008086d00007195sv000010CFsd00001099* + ID_MODEL_FROM_DATABASE=QSound_SigmaTel Stac97 PCI Audio + +pci:v00008086d00007195sv000011D4sd00000040* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00007195sv000011D4sd00000048* + ID_MODEL_FROM_DATABASE=SoundMAX Integrated Digital Audio + +pci:v00008086d00007196* + ID_MODEL_FROM_DATABASE=82440MX AC'97 Modem Controller + +pci:v00008086d00007198* + ID_MODEL_FROM_DATABASE=82440MX ISA Bridge + +pci:v00008086d00007199* + ID_MODEL_FROM_DATABASE=82440MX EIDE Controller + +pci:v00008086d0000719A* + ID_MODEL_FROM_DATABASE=82440MX USB Universal Host Controller + +pci:v00008086d0000719B* + ID_MODEL_FROM_DATABASE=82440MX Power Management Controller + +pci:v00008086d000071A0* + ID_MODEL_FROM_DATABASE=440GX - 82443GX Host bridge + +pci:v00008086d000071A0sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00008086d000071A0sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v00008086d000071A1* + ID_MODEL_FROM_DATABASE=440GX - 82443GX AGP bridge + +pci:v00008086d000071A2* + ID_MODEL_FROM_DATABASE=440GX - 82443GX Host bridge (AGP disabled) + +pci:v00008086d000071A2sv00004C53sd00001000* + ID_MODEL_FROM_DATABASE=CC7/CR7/CP7/VC7/VP7/VR7 mainboard + +pci:v00008086d00007600* + ID_MODEL_FROM_DATABASE=82372FB PIIX5 ISA + +pci:v00008086d00007601* + ID_MODEL_FROM_DATABASE=82372FB PIIX5 IDE + +pci:v00008086d00007602* + ID_MODEL_FROM_DATABASE=82372FB PIIX5 USB + +pci:v00008086d00007603* + ID_MODEL_FROM_DATABASE=82372FB PIIX5 SMBus + +pci:v00008086d00007800* + ID_MODEL_FROM_DATABASE=82740 (i740) AGP Graphics Accelerator + +pci:v00008086d00007800sv0000003Dsd00000008* + ID_MODEL_FROM_DATABASE=Starfighter AGP + +pci:v00008086d00007800sv0000003Dsd0000000B* + ID_MODEL_FROM_DATABASE=Starfighter AGP + +pci:v00008086d00007800sv00001092sd00000100* + ID_MODEL_FROM_DATABASE=Stealth II G460 + +pci:v00008086d00007800sv000010B4sd0000201A* + ID_MODEL_FROM_DATABASE=Lightspeed 740 + +pci:v00008086d00007800sv000010B4sd0000202F* + ID_MODEL_FROM_DATABASE=Lightspeed 740 + +pci:v00008086d00007800sv00008086sd00000000* + ID_MODEL_FROM_DATABASE=Terminator 2x/i + +pci:v00008086d00007800sv00008086sd00000100* + ID_MODEL_FROM_DATABASE=Intel740 Graphics Accelerator + +pci:v00008086d00008002* + ID_MODEL_FROM_DATABASE=Trusted Execution Technology Registers + +pci:v00008086d00008003* + ID_MODEL_FROM_DATABASE=Trusted Execution Technology Registers + +pci:v00008086d00008100* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) + +pci:v00008086d00008108* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) Graphics Controller + +pci:v00008086d00008110* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) PCI Express Port 1 + +pci:v00008086d00008112* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) PCI Express Port 2 + +pci:v00008086d00008114* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) USB UHCI #1 + +pci:v00008086d00008115* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) USB UHCI #2 + +pci:v00008086d00008116* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) USB UHCI #3 + +pci:v00008086d00008117* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) USB EHCI #1 + +pci:v00008086d00008118* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) USB Client Controller + +pci:v00008086d00008119* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) LPC Bridge + +pci:v00008086d0000811A* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) IDE Controller + +pci:v00008086d0000811B* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) HD Audio Controller + +pci:v00008086d0000811C* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) SDIO Controller #1 + +pci:v00008086d0000811D* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) SDIO Controller #2 + +pci:v00008086d0000811E* + ID_MODEL_FROM_DATABASE=System Controller Hub (SCH Poulsbo) SDIO Controller #3 + +pci:v00008086d00008180* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Express Port 3 + +pci:v00008086d00008181* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Express Port 4 + +pci:v00008086d00008182* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Integrated Graphics Controller + +pci:v00008086d00008183* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx Configuration Unit + +pci:v00008086d00008184* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Express Port 1 + +pci:v00008086d00008185* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Express Port 2 + +pci:v00008086d00008186* + ID_MODEL_FROM_DATABASE=Atom Processor E6xx LPC Bridge + +pci:v00008086d000084C4* + ID_MODEL_FROM_DATABASE=450KX/GX [Orion] - 82454KX/GX PCI bridge + +pci:v00008086d000084C5* + ID_MODEL_FROM_DATABASE=450KX/GX [Orion] - 82453KX/GX Memory controller + +pci:v00008086d000084CA* + ID_MODEL_FROM_DATABASE=450NX - 82451NX Memory & I/O Controller + +pci:v00008086d000084CB* + ID_MODEL_FROM_DATABASE=450NX - 82454NX/84460GX PCI Expander Bridge + +pci:v00008086d000084E0* + ID_MODEL_FROM_DATABASE=460GX - 84460GX System Address Controller (SAC) + +pci:v00008086d000084E1* + ID_MODEL_FROM_DATABASE=460GX - 84460GX System Data Controller (SDC) + +pci:v00008086d000084E2* + ID_MODEL_FROM_DATABASE=460GX - 84460GX AGP Bridge (GXB function 2) + +pci:v00008086d000084E3* + ID_MODEL_FROM_DATABASE=460GX - 84460GX Memory Address Controller (MAC) + +pci:v00008086d000084E4* + ID_MODEL_FROM_DATABASE=460GX - 84460GX Memory Data Controller (MDC) + +pci:v00008086d000084E6* + ID_MODEL_FROM_DATABASE=460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB) + +pci:v00008086d000084EA* + ID_MODEL_FROM_DATABASE=460GX - 84460GX AGP Bridge (GXB function 1) + +pci:v00008086d00008500* + ID_MODEL_FROM_DATABASE=IXP4XX Network Processor (IXP420/421/422/425/IXC1100) + +pci:v00008086d00008500sv00001993sd00000DED* + ID_MODEL_FROM_DATABASE=mGuard-PCI AV#2 + +pci:v00008086d00008500sv00001993sd00000DEE* + ID_MODEL_FROM_DATABASE=mGuard-PCI AV#1 + +pci:v00008086d00008500sv00001993sd00000DEF* + ID_MODEL_FROM_DATABASE=mGuard-PCI AV#0 + +pci:v00008086d00008800* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T PCI Express Port + +pci:v00008086d00008801* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T Packet Hub + +pci:v00008086d00008802* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T Gigabit Ethernet Controller + +pci:v00008086d00008803* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T General Purpose IO Controller + +pci:v00008086d00008804* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #4 + +pci:v00008086d00008805* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #5 + +pci:v00008086d00008806* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #6 + +pci:v00008086d00008807* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB2 EHCI Controller #2 + +pci:v00008086d00008808* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB Client Controller + +pci:v00008086d00008809* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T SDIO Controller #1 + +pci:v00008086d0000880A* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T SDIO Controller #2 + +pci:v00008086d0000880B* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T SATA AHCI Controller + +pci:v00008086d0000880C* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #1 + +pci:v00008086d0000880D* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #2 + +pci:v00008086d0000880E* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB OHCI Controller #3 + +pci:v00008086d0000880F* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T USB2 EHCI Controller #1 + +pci:v00008086d00008810* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T DMA Controller #1 + +pci:v00008086d00008811* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T UART Controller 0 + +pci:v00008086d00008812* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T UART Controller 1 + +pci:v00008086d00008813* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T UART Controller 2 + +pci:v00008086d00008814* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T UART Controller 3 + +pci:v00008086d00008815* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T DMA Controller #2 + +pci:v00008086d00008816* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T Serial Peripheral Interface Bus + +pci:v00008086d00008817* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T I2C Controller + +pci:v00008086d00008818* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T Controller Area Network (CAN) Controller + +pci:v00008086d00008819* + ID_MODEL_FROM_DATABASE=Platform Controller Hub EG20T IEEE 1588 Hardware Assist + +pci:v00008086d00008C00* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode] + +pci:v00008086d00008C01* + ID_MODEL_FROM_DATABASE=8 Series Chipset Family 4-port SATA Controller 1 [IDE mode] - Mobile + +pci:v00008086d00008C02* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] + +pci:v00008086d00008C03* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] + +pci:v00008086d00008C03sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C04* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C05* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C06* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C07* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C08* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 2-port SATA Controller 2 [IDE mode] + +pci:v00008086d00008C09* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 2-port SATA Controller 2 [IDE mode] + +pci:v00008086d00008C0E* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C0F* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SATA Controller 1 [RAID mode] + +pci:v00008086d00008C10* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 + +pci:v00008086d00008C10sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C11* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 + +pci:v00008086d00008C12* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #2 + +pci:v00008086d00008C12sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C13* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #2 + +pci:v00008086d00008C14* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #3 + +pci:v00008086d00008C15* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #3 + +pci:v00008086d00008C16* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #4 + +pci:v00008086d00008C17* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #4 + +pci:v00008086d00008C18* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #5 + +pci:v00008086d00008C19* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #5 + +pci:v00008086d00008C1A* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #6 + +pci:v00008086d00008C1B* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #6 + +pci:v00008086d00008C1C* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #7 + +pci:v00008086d00008C1D* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #7 + +pci:v00008086d00008C1E* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #8 + +pci:v00008086d00008C1F* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #8 + +pci:v00008086d00008C20* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller + +pci:v00008086d00008C20sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C21* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller + +pci:v00008086d00008C22* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller + +pci:v00008086d00008C22sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C23* + ID_MODEL_FROM_DATABASE=8 Series Chipset Family CHAP Counters + +pci:v00008086d00008C24* + ID_MODEL_FROM_DATABASE=8 Series Chipset Family Thermal Management Controller + +pci:v00008086d00008C26* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 + +pci:v00008086d00008C26sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C2D* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 + +pci:v00008086d00008C2Dsv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C31* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI + +pci:v00008086d00008C31sv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C33* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LAN Controller + +pci:v00008086d00008C34* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family NAND Controller + +pci:v00008086d00008C3A* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 + +pci:v00008086d00008C3Asv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C3B* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #2 + +pci:v00008086d00008C3C* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family IDE-r Controller + +pci:v00008086d00008C3D* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family KT Controller + +pci:v00008086d00008C40* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C41* + ID_MODEL_FROM_DATABASE=8 Series Chipset Family Mobile Super SKU LPC Controller + +pci:v00008086d00008C42* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family Desktop Super SKU LPC Controller + +pci:v00008086d00008C43* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C44* + ID_MODEL_FROM_DATABASE=Z87 Express LPC Controller + +pci:v00008086d00008C45* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C46* + ID_MODEL_FROM_DATABASE=Z85 Express LPC Controller + +pci:v00008086d00008C47* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C48* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C49* + ID_MODEL_FROM_DATABASE=HM86 Express LPC Controller + +pci:v00008086d00008C4A* + ID_MODEL_FROM_DATABASE=H87 Express LPC Controller + +pci:v00008086d00008C4B* + ID_MODEL_FROM_DATABASE=HM87 Express LPC Controller + +pci:v00008086d00008C4C* + ID_MODEL_FROM_DATABASE=Q85 Express LPC Controller + +pci:v00008086d00008C4D* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C4E* + ID_MODEL_FROM_DATABASE=Q87 Express LPC Controller + +pci:v00008086d00008C4F* + ID_MODEL_FROM_DATABASE=QM87 Express LPC Controller + +pci:v00008086d00008C4Fsv000017AAsd0000220E* + ID_MODEL_FROM_DATABASE=ThinkPad T440p + +pci:v00008086d00008C50* + ID_MODEL_FROM_DATABASE=B85 Express LPC Controller + +pci:v00008086d00008C51* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C52* + ID_MODEL_FROM_DATABASE=C222 Series Chipset Family Server Essential SKU LPC Controller + +pci:v00008086d00008C53* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C54* + ID_MODEL_FROM_DATABASE=C224 Series Chipset Family Server Standard SKU LPC Controller + +pci:v00008086d00008C55* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C56* + ID_MODEL_FROM_DATABASE=C226 Series Chipset Family Server Advanced SKU LPC Controller + +pci:v00008086d00008C57* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C58* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family WS SKU LPC Controller + +pci:v00008086d00008C59* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C5A* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C5B* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C5C* + ID_MODEL_FROM_DATABASE=C220 Series Chipset Family H81 Express LPC Controller + +pci:v00008086d00008C5D* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C5E* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008C5F* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller + +pci:v00008086d00008D00* + ID_MODEL_FROM_DATABASE=Wellsburg 4-port SATA Controller [IDE mode] + +pci:v00008086d00008D02* + ID_MODEL_FROM_DATABASE=Wellsburg 6-Port SATA Controller [AHCI mode] + +pci:v00008086d00008D04* + ID_MODEL_FROM_DATABASE=Wellsburg SATA Controller [RAID mode] + +pci:v00008086d00008D06* + ID_MODEL_FROM_DATABASE=Wellsburg SATA Controller [RAID mode] + +pci:v00008086d00008D08* + ID_MODEL_FROM_DATABASE=Wellsburg 2-port SATA Controller [IDE mode] + +pci:v00008086d00008D0E* + ID_MODEL_FROM_DATABASE=Wellsburg SATA Controller [RAID mode] + +pci:v00008086d00008D10* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #1 + +pci:v00008086d00008D11* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #1 + +pci:v00008086d00008D12* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #2 + +pci:v00008086d00008D13* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #2 + +pci:v00008086d00008D14* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #3 + +pci:v00008086d00008D15* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #3 + +pci:v00008086d00008D16* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #4 + +pci:v00008086d00008D17* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #4 + +pci:v00008086d00008D18* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #5 + +pci:v00008086d00008D19* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #5 + +pci:v00008086d00008D1A* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #6 + +pci:v00008086d00008D1B* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #6 + +pci:v00008086d00008D1C* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #7 + +pci:v00008086d00008D1D* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #7 + +pci:v00008086d00008D1E* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #8 + +pci:v00008086d00008D1F* + ID_MODEL_FROM_DATABASE=Wellsburg PCI Express Root Port #8 + +pci:v00008086d00008D20* + ID_MODEL_FROM_DATABASE=Wellsburg HD Audio Controller + +pci:v00008086d00008D21* + ID_MODEL_FROM_DATABASE=Wellsburg HD Audio Controller + +pci:v00008086d00008D22* + ID_MODEL_FROM_DATABASE=Wellsburg SMBus Controller + +pci:v00008086d00008D24* + ID_MODEL_FROM_DATABASE=Wellsburg Thermal Subsystem + +pci:v00008086d00008D26* + ID_MODEL_FROM_DATABASE=Wellsburg USB Enhanced Host Controller #1 + +pci:v00008086d00008D2D* + ID_MODEL_FROM_DATABASE=Wellsburg USB Enhanced Host Controller #2 + +pci:v00008086d00008D31* + ID_MODEL_FROM_DATABASE=Wellsburg USB xHCI Host Controller + +pci:v00008086d00008D33* + ID_MODEL_FROM_DATABASE=Wellsburg LAN Controller + +pci:v00008086d00008D34* + ID_MODEL_FROM_DATABASE=Wellsburg NAND Controller + +pci:v00008086d00008D3A* + ID_MODEL_FROM_DATABASE=Wellsburg MEI Controller #1 + +pci:v00008086d00008D3B* + ID_MODEL_FROM_DATABASE=Wellsburg MEI Controller #2 + +pci:v00008086d00008D3C* + ID_MODEL_FROM_DATABASE=Wellsburg IDE-r Controller + +pci:v00008086d00008D3D* + ID_MODEL_FROM_DATABASE=Wellsburg KT Controller + +pci:v00008086d00008D40* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D41* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D42* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D43* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D44* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D45* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D46* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D47* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D48* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D49* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4A* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4B* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4C* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4D* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4E* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D4F* + ID_MODEL_FROM_DATABASE=Wellsburg LPC Controller + +pci:v00008086d00008D60* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [IDE mode] + +pci:v00008086d00008D62* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [AHCI mode] + +pci:v00008086d00008D64* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [RAID mode] + +pci:v00008086d00008D66* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [RAID mode] + +pci:v00008086d00008D68* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [IDE mode] + +pci:v00008086d00008D6E* + ID_MODEL_FROM_DATABASE=Wellsburg sSATA Controller [RAID mode] + +pci:v00008086d00008D7C* + ID_MODEL_FROM_DATABASE=Wellsburg SPSR + +pci:v00008086d00008D7D* + ID_MODEL_FROM_DATABASE=Wellsburg MS SMBus 0 + +pci:v00008086d00008D7E* + ID_MODEL_FROM_DATABASE=Wellsburg MS SMBus 1 + +pci:v00008086d00008D7F* + ID_MODEL_FROM_DATABASE=Wellsburg MS SMBus 2 + +pci:v00008086d00009000* + ID_MODEL_FROM_DATABASE=IXP2000 Family Network Processor + +pci:v00008086d00009001* + ID_MODEL_FROM_DATABASE=IXP2400 Network Processor + +pci:v00008086d00009002* + ID_MODEL_FROM_DATABASE=IXP2300 Network Processor + +pci:v00008086d00009004* + ID_MODEL_FROM_DATABASE=IXP2800 Network Processor + +pci:v00008086d00009621* + ID_MODEL_FROM_DATABASE=Integrated RAID + +pci:v00008086d00009622* + ID_MODEL_FROM_DATABASE=Integrated RAID + +pci:v00008086d00009641* + ID_MODEL_FROM_DATABASE=Integrated RAID + +pci:v00008086d000096A1* + ID_MODEL_FROM_DATABASE=Integrated RAID + +pci:v00008086d00009C00* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [IDE mode] + +pci:v00008086d00009C01* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [IDE mode] + +pci:v00008086d00009C02* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [AHCI mode] + +pci:v00008086d00009C03* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [AHCI mode] + +pci:v00008086d00009C04* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C05* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C06* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C07* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C08* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 2 [IDE mode] + +pci:v00008086d00009C09* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 2 [IDE mode] + +pci:v00008086d00009C0A* + ID_MODEL_FROM_DATABASE=LynxPoint-LP SATA Controller [Reserved] + +pci:v00008086d00009C0B* + ID_MODEL_FROM_DATABASE=LynxPoint-LP SATA Controller [Reserved] + +pci:v00008086d00009C0C* + ID_MODEL_FROM_DATABASE=LynxPoint-LP SATA Controller [Reserved] + +pci:v00008086d00009C0D* + ID_MODEL_FROM_DATABASE=LynxPoint-LP SATA Controller [Reserved] + +pci:v00008086d00009C0E* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C0F* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SATA Controller 1 [RAID mode] + +pci:v00008086d00009C10* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 1 + +pci:v00008086d00009C11* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 1 + +pci:v00008086d00009C12* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 2 + +pci:v00008086d00009C13* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 2 + +pci:v00008086d00009C14* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 3 + +pci:v00008086d00009C15* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 3 + +pci:v00008086d00009C16* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 4 + +pci:v00008086d00009C17* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 4 + +pci:v00008086d00009C18* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 5 + +pci:v00008086d00009C19* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 5 + +pci:v00008086d00009C1A* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 6 + +pci:v00008086d00009C1B* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 6 + +pci:v00008086d00009C1C* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 7 + +pci:v00008086d00009C1D* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 7 + +pci:v00008086d00009C1E* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 8 + +pci:v00008086d00009C1F* + ID_MODEL_FROM_DATABASE=Lynx Point-LP PCI Express Root Port 8 + +pci:v00008086d00009C20* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HD Audio Controller + +pci:v00008086d00009C21* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HD Audio Controller + +pci:v00008086d00009C22* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SMBus Controller + +pci:v00008086d00009C23* + ID_MODEL_FROM_DATABASE=Lynx Point-LP CHAP Counters + +pci:v00008086d00009C24* + ID_MODEL_FROM_DATABASE=Lynx Point-LP Thermal + +pci:v00008086d00009C26* + ID_MODEL_FROM_DATABASE=Lynx Point-LP USB EHCI #1 + +pci:v00008086d00009C2D* + ID_MODEL_FROM_DATABASE=Lynx Point-LP USB EHCI #2 + +pci:v00008086d00009C31* + ID_MODEL_FROM_DATABASE=Lynx Point-LP USB xHCI HC + +pci:v00008086d00009C35* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SDIO Controller + +pci:v00008086d00009C36* + ID_MODEL_FROM_DATABASE=Lynx Point-LP Audio DSP Controller + +pci:v00008086d00009C3A* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HECI #0 + +pci:v00008086d00009C3B* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HECI #1 + +pci:v00008086d00009C3C* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HECI IDER + +pci:v00008086d00009C3D* + ID_MODEL_FROM_DATABASE=Lynx Point-LP HECI KT + +pci:v00008086d00009C40* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C41* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C42* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C43* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C44* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C45* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C46* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C47* + ID_MODEL_FROM_DATABASE=Lynx Point-LP LPC Controller + +pci:v00008086d00009C60* + ID_MODEL_FROM_DATABASE=Lynx Point-LP Low Power Sub-System DMA + +pci:v00008086d00009C61* + ID_MODEL_FROM_DATABASE=Lynx Point-LP I2C Controller #0 + +pci:v00008086d00009C62* + ID_MODEL_FROM_DATABASE=Lynx Point-LP I2C Controller #1 + +pci:v00008086d00009C63* + ID_MODEL_FROM_DATABASE=Lynx Point-LP UART Controller #0 + +pci:v00008086d00009C64* + ID_MODEL_FROM_DATABASE=Lynx Point-LP UART Controller #1 + +pci:v00008086d00009C65* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SPI Controller #0 + +pci:v00008086d00009C66* + ID_MODEL_FROM_DATABASE=Lynx Point-LP SPI Controller #1 + +pci:v00008086d00009C83* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP SATA Controller [AHCI Mode] + +pci:v00008086d00009C85* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP SATA Controller [RAID Mode] + +pci:v00008086d00009C87* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP SATA Controller [RAID Mode] + +pci:v00008086d00009C8F* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP SATA Controller [RAID Mode] + +pci:v00008086d00009C90* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #1 + +pci:v00008086d00009C92* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #2 + +pci:v00008086d00009C94* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #3 + +pci:v00008086d00009C96* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #4 + +pci:v00008086d00009C98* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #5 + +pci:v00008086d00009C9A* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP PCI Express Root Port #6 + +pci:v00008086d00009CA0* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP High Definition Audio Controller + +pci:v00008086d00009CA2* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP SMBus Controller + +pci:v00008086d00009CA4* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Thermal Management Controller + +pci:v00008086d00009CA6* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP USB EHCI Controller + +pci:v00008086d00009CB1* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP USB xHCI Controller + +pci:v00008086d00009CB5* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Secure Digital IO Controller + +pci:v00008086d00009CB6* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Smart Sound Technology Controller + +pci:v00008086d00009CBA* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP MEI Controller #1 + +pci:v00008086d00009CBB* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP MEI Controller #2 + +pci:v00008086d00009CBC* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP IDE-r Controller + +pci:v00008086d00009CBD* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP KT Controller + +pci:v00008086d00009CC1* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC2* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC3* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC5* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC6* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC7* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CC9* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP LPC Controller + +pci:v00008086d00009CE0* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO DMA Controller + +pci:v00008086d00009CE1* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO I2C Controller #0 + +pci:v00008086d00009CE2* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO I2C Controller #1 + +pci:v00008086d00009CE3* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO UART Controller #0 + +pci:v00008086d00009CE4* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO UART Controller #1 + +pci:v00008086d00009CE5* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO GSPI Controller #0 + +pci:v00008086d00009CE6* + ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO GSPI Controller #1 + +pci:v00008086d0000A000* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge + +pci:v00008086d0000A000sv00001458sd00005000* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d0000A000sv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d0000A000sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d0000A001* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller + +pci:v00008086d0000A001sv00001458sd0000D000* + ID_MODEL_FROM_DATABASE=GA-D525TUD + +pci:v00008086d0000A001sv00008086sd00004F4D* + ID_MODEL_FROM_DATABASE=DeskTop Board D510MO + +pci:v00008086d0000A001sv00008086sd0000544B* + ID_MODEL_FROM_DATABASE=Desktop Board D425KT + +pci:v00008086d0000A002* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller + +pci:v00008086d0000A003* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter + +pci:v00008086d0000A010* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge + +pci:v00008086d0000A010sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d0000A011* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller + +pci:v00008086d0000A011sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d0000A012* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller + +pci:v00008086d0000A012sv0000144Dsd0000C072* + ID_MODEL_FROM_DATABASE=Notebook N150P + +pci:v00008086d0000A013* + ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx CHAPS counter + +pci:v00008086d0000A620* + ID_MODEL_FROM_DATABASE=6400/6402 Advanced Memory Buffer (AMB) + +pci:v00008086d0000B152* + ID_MODEL_FROM_DATABASE=21152 PCI-to-PCI Bridge + +pci:v00008086d0000B152sv00008086sd0000B152* + ID_MODEL_FROM_DATABASE=21152 PCI-to-PCI Bridge + +pci:v00008086d0000B154* + ID_MODEL_FROM_DATABASE=21154 PCI-to-PCI Bridge + +pci:v00008086d0000B555* + ID_MODEL_FROM_DATABASE=21555 Non transparent PCI-to-PCI Bridge + +pci:v00008086d0000B555sv000012C7sd00005005* + ID_MODEL_FROM_DATABASE=SS7HD PCI Adaptor Card + +pci:v00008086d0000B555sv000012C7sd00005006* + ID_MODEL_FROM_DATABASE=SS7HDC cPCI Adaptor Card + +pci:v00008086d0000B555sv000012D9sd0000000A* + ID_MODEL_FROM_DATABASE=PCI VoIP Gateway + +pci:v00008086d0000B555sv00004C53sd00001050* + ID_MODEL_FROM_DATABASE=CT7 mainboard + +pci:v00008086d0000B555sv00004C53sd00001051* + ID_MODEL_FROM_DATABASE=CE7 mainboard + +pci:v00008086d0000B555sv0000E4BFsd00001000* + ID_MODEL_FROM_DATABASE=CC8-1-BLUES + +pci:v00008086d0000D130* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D131* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D131sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d0000D132* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D132sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d0000D133* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D134* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D135* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D136* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D137* + ID_MODEL_FROM_DATABASE=Core Processor DMI + +pci:v00008086d0000D138* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express Root Port 1 + +pci:v00008086d0000D138sv00001028sd000002DA* + ID_MODEL_FROM_DATABASE=OptiPlex 980 + +pci:v00008086d0000D138sv00001028sd0000040B* + ID_MODEL_FROM_DATABASE=Latitude E6510 + +pci:v00008086d0000D139* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express Root Port 2 + +pci:v00008086d0000D13A* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express Root Port 3 + +pci:v00008086d0000D13B* + ID_MODEL_FROM_DATABASE=Core Processor PCI Express Root Port 4 + +pci:v00008086d0000D150* + ID_MODEL_FROM_DATABASE=Core Processor QPI Link + +pci:v00008086d0000D151* + ID_MODEL_FROM_DATABASE=Core Processor QPI Routing and Protocol Registers + +pci:v00008086d0000D155* + ID_MODEL_FROM_DATABASE=Core Processor System Management Registers + +pci:v00008086d0000D156* + ID_MODEL_FROM_DATABASE=Core Processor Semaphore and Scratchpad Registers + +pci:v00008086d0000D157* + ID_MODEL_FROM_DATABASE=Core Processor System Control and Status Registers + +pci:v00008086d0000D158* + ID_MODEL_FROM_DATABASE=Core Processor Miscellaneous Registers + +pci:v000080EE* + ID_VENDOR_FROM_DATABASE=InnoTek Systemberatung GmbH + +pci:v000080EEd0000BEEF* + ID_MODEL_FROM_DATABASE=VirtualBox Graphics Adapter + +pci:v000080EEd0000CAFE* + ID_MODEL_FROM_DATABASE=VirtualBox Guest Service + +pci:v00008322* + ID_VENDOR_FROM_DATABASE=Sodick America Corp. + +pci:v00008384* + ID_VENDOR_FROM_DATABASE=SigmaTel + +pci:v00008401* + ID_VENDOR_FROM_DATABASE=TRENDware International Inc. + +pci:v00008686* + ID_VENDOR_FROM_DATABASE=ScaleMP + +pci:v00008686d00001010* + ID_MODEL_FROM_DATABASE=vSMPowered system controller [vSMP CTL] + +pci:v00008800* + ID_VENDOR_FROM_DATABASE=Trigem Computer Inc. + +pci:v00008800d00002008* + ID_MODEL_FROM_DATABASE=Video assistent component + +pci:v00008866* + ID_VENDOR_FROM_DATABASE=T-Square Design Inc. + +pci:v00008888* + ID_VENDOR_FROM_DATABASE=Silicon Magic + +pci:v00008912* + ID_VENDOR_FROM_DATABASE=TRX + +pci:v00008C4A* + ID_VENDOR_FROM_DATABASE=Winbond + +pci:v00008C4Ad00001980* + ID_MODEL_FROM_DATABASE=W89C940 misprogrammed [ne2k] + +pci:v00008E0E* + ID_VENDOR_FROM_DATABASE=Computone Corporation + +pci:v00008E2E* + ID_VENDOR_FROM_DATABASE=KTI + +pci:v00008E2Ed00003000* + ID_MODEL_FROM_DATABASE=ET32P2 + +pci:v00009004* + ID_VENDOR_FROM_DATABASE=Adaptec + +pci:v00009004d00000078* + ID_MODEL_FROM_DATABASE=AHA-2940U_CN + +pci:v00009004d00001078* + ID_MODEL_FROM_DATABASE=AIC-7810 + +pci:v00009004d00001160* + ID_MODEL_FROM_DATABASE=AIC-1160 [Family Fibre Channel Adapter] + +pci:v00009004d00002178* + ID_MODEL_FROM_DATABASE=AIC-7821 + +pci:v00009004d00003860* + ID_MODEL_FROM_DATABASE=AHA-2930CU + +pci:v00009004d00003B78* + ID_MODEL_FROM_DATABASE=AHA-4844W/4844UW + +pci:v00009004d00005075* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005078* + ID_MODEL_FROM_DATABASE=AIC-7850 + +pci:v00009004d00005078sv00009004sd00007850* + ID_MODEL_FROM_DATABASE=AHA-2904/Integrated AIC-7850 + +pci:v00009004d00005175* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005178* + ID_MODEL_FROM_DATABASE=AIC-7851 + +pci:v00009004d00005275* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005278* + ID_MODEL_FROM_DATABASE=AIC-7852 + +pci:v00009004d00005375* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005378* + ID_MODEL_FROM_DATABASE=AIC-7850 + +pci:v00009004d00005475* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005478* + ID_MODEL_FROM_DATABASE=AIC-7850 + +pci:v00009004d00005575* + ID_MODEL_FROM_DATABASE=AVA-2930 + +pci:v00009004d00005578* + ID_MODEL_FROM_DATABASE=AIC-7855 + +pci:v00009004d00005647* + ID_MODEL_FROM_DATABASE=ANA-7711 TCP Offload Engine + +pci:v00009004d00005647sv00009004sd00007710* + ID_MODEL_FROM_DATABASE=ANA-7711F TCP Offload Engine - Optical + +pci:v00009004d00005647sv00009004sd00007711* + ID_MODEL_FROM_DATABASE=ANA-7711LP TCP Offload Engine - Copper + +pci:v00009004d00005675* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005678* + ID_MODEL_FROM_DATABASE=AIC-7856 + +pci:v00009004d00005775* + ID_MODEL_FROM_DATABASE=AIC-755x + +pci:v00009004d00005778* + ID_MODEL_FROM_DATABASE=AIC-7850 + +pci:v00009004d00005800* + ID_MODEL_FROM_DATABASE=AIC-5800 + +pci:v00009004d00005900* + ID_MODEL_FROM_DATABASE=ANA-5910/5930/5940 ATM155 & 25 LAN Adapter + +pci:v00009004d00005905* + ID_MODEL_FROM_DATABASE=ANA-5910A/5930A/5940A ATM Adapter + +pci:v00009004d00006038* + ID_MODEL_FROM_DATABASE=AIC-3860 + +pci:v00009004d00006075* + ID_MODEL_FROM_DATABASE=AIC-1480 / APA-1480 + +pci:v00009004d00006075sv00009004sd00007560* + ID_MODEL_FROM_DATABASE=AIC-1480 / APA-1480 Cardbus + +pci:v00009004d00006078* + ID_MODEL_FROM_DATABASE=AIC-7860 + +pci:v00009004d00006178* + ID_MODEL_FROM_DATABASE=AIC-7861 + +pci:v00009004d00006178sv00009004sd00007861* + ID_MODEL_FROM_DATABASE=AHA-2940AU Single + +pci:v00009004d00006278* + ID_MODEL_FROM_DATABASE=AIC-7860 + +pci:v00009004d00006378* + ID_MODEL_FROM_DATABASE=AIC-7860 + +pci:v00009004d00006478* + ID_MODEL_FROM_DATABASE=AIC-786x + +pci:v00009004d00006578* + ID_MODEL_FROM_DATABASE=AIC-786x + +pci:v00009004d00006678* + ID_MODEL_FROM_DATABASE=AIC-786x + +pci:v00009004d00006778* + ID_MODEL_FROM_DATABASE=AIC-786x + +pci:v00009004d00006915* + ID_MODEL_FROM_DATABASE=ANA620xx/ANA69011A + +pci:v00009004d00006915sv00009004sd00000008* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 10/100 + +pci:v00009004d00006915sv00009004sd00000009* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 10/100 + +pci:v00009004d00006915sv00009004sd00000010* + ID_MODEL_FROM_DATABASE=ANA62022 2-port 10/100 + +pci:v00009004d00006915sv00009004sd00000018* + ID_MODEL_FROM_DATABASE=ANA62044 4-port 10/100 + +pci:v00009004d00006915sv00009004sd00000019* + ID_MODEL_FROM_DATABASE=ANA62044 4-port 10/100 + +pci:v00009004d00006915sv00009004sd00000020* + ID_MODEL_FROM_DATABASE=ANA62022 2-port 10/100 + +pci:v00009004d00006915sv00009004sd00000028* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 10/100 + +pci:v00009004d00006915sv00009004sd00008008* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008009* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008010* + ID_MODEL_FROM_DATABASE=ANA62022 2-port 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008018* + ID_MODEL_FROM_DATABASE=ANA62044 4-port 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008019* + ID_MODEL_FROM_DATABASE=ANA62044 4-port 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008020* + ID_MODEL_FROM_DATABASE=ANA62022 2-port 64 bit 10/100 + +pci:v00009004d00006915sv00009004sd00008028* + ID_MODEL_FROM_DATABASE=ANA69011A/TX 64 bit 10/100 + +pci:v00009004d00007078* + ID_MODEL_FROM_DATABASE=AHA-294x / AIC-7870 + +pci:v00009004d00007178* + ID_MODEL_FROM_DATABASE=AHA-2940/2940W / AIC-7871 + +pci:v00009004d00007278* + ID_MODEL_FROM_DATABASE=AHA-3940/3940W / AIC-7872 + +pci:v00009004d00007378* + ID_MODEL_FROM_DATABASE=AHA-3985 / AIC-7873 + +pci:v00009004d00007478* + ID_MODEL_FROM_DATABASE=AHA-2944/2944W / AIC-7874 + +pci:v00009004d00007578* + ID_MODEL_FROM_DATABASE=AHA-3944/3944W / AIC-7875 + +pci:v00009004d00007678* + ID_MODEL_FROM_DATABASE=AHA-4944W/UW / AIC-7876 + +pci:v00009004d00007710* + ID_MODEL_FROM_DATABASE=ANA-7711F Network Accelerator Card (NAC) - Optical + +pci:v00009004d00007711* + ID_MODEL_FROM_DATABASE=ANA-7711C Network Accelerator Card (NAC) - Copper + +pci:v00009004d00007778* + ID_MODEL_FROM_DATABASE=AIC-787x + +pci:v00009004d00007810* + ID_MODEL_FROM_DATABASE=AIC-7810 + +pci:v00009004d00007815* + ID_MODEL_FROM_DATABASE=AIC-7815 RAID+Memory Controller IC + +pci:v00009004d00007815sv00009004sd00007815* + ID_MODEL_FROM_DATABASE=ARO-1130U2 RAID Controller + +pci:v00009004d00007815sv00009004sd00007840* + ID_MODEL_FROM_DATABASE=AIC-7815 RAID+Memory Controller IC + +pci:v00009004d00007850* + ID_MODEL_FROM_DATABASE=AIC-7850 + +pci:v00009004d00007855* + ID_MODEL_FROM_DATABASE=AHA-2930 + +pci:v00009004d00007860* + ID_MODEL_FROM_DATABASE=AIC-7860 + +pci:v00009004d00007870* + ID_MODEL_FROM_DATABASE=AIC-7870 + +pci:v00009004d00007871* + ID_MODEL_FROM_DATABASE=AHA-2940 + +pci:v00009004d00007872* + ID_MODEL_FROM_DATABASE=AHA-3940 + +pci:v00009004d00007873* + ID_MODEL_FROM_DATABASE=AHA-3980 + +pci:v00009004d00007874* + ID_MODEL_FROM_DATABASE=AHA-2944 + +pci:v00009004d00007880* + ID_MODEL_FROM_DATABASE=AIC-7880P + +pci:v00009004d00007890* + ID_MODEL_FROM_DATABASE=AIC-7890 + +pci:v00009004d00007891* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00007892* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00007893* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00007894* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00007895* + ID_MODEL_FROM_DATABASE=AHA-2940U/UW / AHA-39xx / AIC-7895 + +pci:v00009004d00007895sv00009004sd00007890* + ID_MODEL_FROM_DATABASE=AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + +pci:v00009004d00007895sv00009004sd00007891* + ID_MODEL_FROM_DATABASE=AHA-2940U/2940UW Dual + +pci:v00009004d00007895sv00009004sd00007892* + ID_MODEL_FROM_DATABASE=AHA-3940AU/AUW/AUWD/UWD + +pci:v00009004d00007895sv00009004sd00007894* + ID_MODEL_FROM_DATABASE=AHA-3944AUWD + +pci:v00009004d00007895sv00009004sd00007895* + ID_MODEL_FROM_DATABASE=AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + +pci:v00009004d00007895sv00009004sd00007896* + ID_MODEL_FROM_DATABASE=AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + +pci:v00009004d00007895sv00009004sd00007897* + ID_MODEL_FROM_DATABASE=AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B + +pci:v00009004d00007896* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00007897* + ID_MODEL_FROM_DATABASE=AIC-789x + +pci:v00009004d00008078* + ID_MODEL_FROM_DATABASE=AIC-7880U + +pci:v00009004d00008078sv00009004sd00007880* + ID_MODEL_FROM_DATABASE=AIC-7880P Ultra/Ultra Wide SCSI Chipset + +pci:v00009004d00008178* + ID_MODEL_FROM_DATABASE=AHA-2940U/UW/D / AIC-7881U + +pci:v00009004d00008178sv00009004sd00007881* + ID_MODEL_FROM_DATABASE=AHA-2940UW SCSI Host Adapter + +pci:v00009004d00008278* + ID_MODEL_FROM_DATABASE=AHA-3940U/UW/UWD / AIC-7882U + +pci:v00009004d00008378* + ID_MODEL_FROM_DATABASE=AHA-3940U/UW / AIC-7883U + +pci:v00009004d00008478* + ID_MODEL_FROM_DATABASE=AHA-2944UW / AIC-7884U + +pci:v00009004d00008578* + ID_MODEL_FROM_DATABASE=AHA-3944U/UWD / AIC-7885 + +pci:v00009004d00008678* + ID_MODEL_FROM_DATABASE=AHA-4944UW / AIC-7886 + +pci:v00009004d00008778* + ID_MODEL_FROM_DATABASE=AHA-2940UW Pro / AIC-788x + +pci:v00009004d00008778sv00009004sd00007887* + ID_MODEL_FROM_DATABASE=2940UW Pro Ultra-Wide SCSI Controller + +pci:v00009004d00008878* + ID_MODEL_FROM_DATABASE=AHA-2930UW / AIC-7888 + +pci:v00009004d00008878sv00009004sd00007888* + ID_MODEL_FROM_DATABASE=AHA-2930UW SCSI Controller + +pci:v00009004d00008B78* + ID_MODEL_FROM_DATABASE=ABA-1030 + +pci:v00009004d0000EC78* + ID_MODEL_FROM_DATABASE=AHA-4944W/UW + +pci:v00009005* + ID_VENDOR_FROM_DATABASE=Adaptec + +pci:v00009005d00000010* + ID_MODEL_FROM_DATABASE=AHA-2940U2/U2W + +pci:v00009005d00000010sv00009005sd00002180* + ID_MODEL_FROM_DATABASE=AHA-2940U2 SCSI Controller + +pci:v00009005d00000010sv00009005sd00008100* + ID_MODEL_FROM_DATABASE=AHA-2940U2B SCSI Controller + +pci:v00009005d00000010sv00009005sd0000A100* + ID_MODEL_FROM_DATABASE=AHA-2940U2B SCSI Controller + +pci:v00009005d00000010sv00009005sd0000A180* + ID_MODEL_FROM_DATABASE=AHA-2940U2W SCSI Controller + +pci:v00009005d00000010sv00009005sd0000E100* + ID_MODEL_FROM_DATABASE=AHA-2950U2B SCSI Controller + +pci:v00009005d00000011* + ID_MODEL_FROM_DATABASE=AHA-2930U2 + +pci:v00009005d00000013* + ID_MODEL_FROM_DATABASE=78902 + +pci:v00009005d00000013sv00009005sd00000003* + ID_MODEL_FROM_DATABASE=AAA-131U2 Array1000 1 Channel RAID Controller + +pci:v00009005d00000013sv00009005sd0000000F* + ID_MODEL_FROM_DATABASE=AIC7890_ARO + +pci:v00009005d0000001F* + ID_MODEL_FROM_DATABASE=AHA-2940U2/U2W / 7890/7891 + +pci:v00009005d0000001Fsv00009005sd0000000F* + ID_MODEL_FROM_DATABASE=2940U2W SCSI Controller + +pci:v00009005d0000001Fsv00009005sd0000A180* + ID_MODEL_FROM_DATABASE=2940U2W SCSI Controller + +pci:v00009005d00000020* + ID_MODEL_FROM_DATABASE=AIC-7890 + +pci:v00009005d0000002F* + ID_MODEL_FROM_DATABASE=AIC-7890 + +pci:v00009005d00000030* + ID_MODEL_FROM_DATABASE=AIC-7890 + +pci:v00009005d0000003F* + ID_MODEL_FROM_DATABASE=AIC-7890 + +pci:v00009005d00000050* + ID_MODEL_FROM_DATABASE=AHA-3940U2x/395U2x + +pci:v00009005d00000050sv00009005sd0000F500* + ID_MODEL_FROM_DATABASE=AHA-3950U2B + +pci:v00009005d00000050sv00009005sd0000FFFF* + ID_MODEL_FROM_DATABASE=AHA-3950U2B + +pci:v00009005d00000051* + ID_MODEL_FROM_DATABASE=AHA-3950U2D + +pci:v00009005d00000051sv00009005sd0000B500* + ID_MODEL_FROM_DATABASE=AHA-3950U2D + +pci:v00009005d00000053* + ID_MODEL_FROM_DATABASE=AIC-7896 SCSI Controller + +pci:v00009005d00000053sv00009005sd0000FFFF* + ID_MODEL_FROM_DATABASE=AIC-7896 SCSI Controller mainboard implementation + +pci:v00009005d0000005F* + ID_MODEL_FROM_DATABASE=AIC-7896U2/7897U2 + +pci:v00009005d00000080* + ID_MODEL_FROM_DATABASE=AIC-7892A U160/m + +pci:v00009005d00000080sv00000E11sd0000E2A0* + ID_MODEL_FROM_DATABASE=Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter + +pci:v00009005d00000080sv00009005sd00006220* + ID_MODEL_FROM_DATABASE=AHA-29160C + +pci:v00009005d00000080sv00009005sd000062A0* + ID_MODEL_FROM_DATABASE=29160N Ultra160 SCSI Controller + +pci:v00009005d00000080sv00009005sd0000E220* + ID_MODEL_FROM_DATABASE=29160LP Low Profile Ultra160 SCSI Controller + +pci:v00009005d00000080sv00009005sd0000E2A0* + ID_MODEL_FROM_DATABASE=29160 Ultra160 SCSI Controller + +pci:v00009005d00000081* + ID_MODEL_FROM_DATABASE=AIC-7892B U160/m + +pci:v00009005d00000081sv00009005sd000062A1* + ID_MODEL_FROM_DATABASE=19160 Ultra160 SCSI Controller + +pci:v00009005d00000083* + ID_MODEL_FROM_DATABASE=AIC-7892D U160/m + +pci:v00009005d0000008F* + ID_MODEL_FROM_DATABASE=AIC-7892P U160/m + +pci:v00009005d0000008Fsv00001179sd00000001* + ID_MODEL_FROM_DATABASE=Magnia Z310 + +pci:v00009005d0000008Fsv000015D9sd00009005* + ID_MODEL_FROM_DATABASE=Onboard SCSI Host Adapter + +pci:v00009005d00000092* + ID_MODEL_FROM_DATABASE=AVC-2010 [VideoH!] + +pci:v00009005d00000093* + ID_MODEL_FROM_DATABASE=AVC-2410 [VideoH!] + +pci:v00009005d000000C0* + ID_MODEL_FROM_DATABASE=AHA-3960D / AIC-7899A U160/m + +pci:v00009005d000000C0sv00000E11sd0000F620* + ID_MODEL_FROM_DATABASE=Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter + +pci:v00009005d000000C0sv00009005sd0000F620* + ID_MODEL_FROM_DATABASE=AHA-3960D U160/m + +pci:v00009005d000000C1* + ID_MODEL_FROM_DATABASE=AIC-7899B U160/m + +pci:v00009005d000000C3* + ID_MODEL_FROM_DATABASE=AIC-7899D U160/m + +pci:v00009005d000000C5* + ID_MODEL_FROM_DATABASE=RAID subsystem HBA + +pci:v00009005d000000C5sv00001028sd000000C5* + ID_MODEL_FROM_DATABASE=PowerEdge 2400,2500,2550,4400 + +pci:v00009005d000000CF* + ID_MODEL_FROM_DATABASE=AIC-7899P U160/m + +pci:v00009005d000000CFsv00001028sd000000CE* + ID_MODEL_FROM_DATABASE=PowerEdge 1400 + +pci:v00009005d000000CFsv00001028sd000000D1* + ID_MODEL_FROM_DATABASE=PowerEdge 2550 + +pci:v00009005d000000CFsv00001028sd000000D9* + ID_MODEL_FROM_DATABASE=PowerEdge 2500 + +pci:v00009005d000000CFsv000010F1sd00002462* + ID_MODEL_FROM_DATABASE=Thunder K7 S2462 + +pci:v00009005d000000CFsv000015D9sd00009005* + ID_MODEL_FROM_DATABASE=Onboard SCSI Host Adapter + +pci:v00009005d000000CFsv00008086sd00003411* + ID_MODEL_FROM_DATABASE=SDS2 Mainboard + +pci:v00009005d00000241* + ID_MODEL_FROM_DATABASE=Serial ATA II RAID 1420SA + +pci:v00009005d00000242* + ID_MODEL_FROM_DATABASE=Serial ATA II RAID 1220SA + +pci:v00009005d00000243* + ID_MODEL_FROM_DATABASE=Serial ATA II RAID 1430SA + +pci:v00009005d00000244* + ID_MODEL_FROM_DATABASE=eSATA II RAID 1225SA + +pci:v00009005d00000250* + ID_MODEL_FROM_DATABASE=ServeRAID Controller + +pci:v00009005d00000250sv00001014sd00000279* + ID_MODEL_FROM_DATABASE=ServeRAID 6M + +pci:v00009005d00000250sv00001014sd0000028C* + ID_MODEL_FROM_DATABASE=ServeRAID 6i/6i+ + +pci:v00009005d00000250sv00001014sd0000028E* + ID_MODEL_FROM_DATABASE=ServeRAID 7k + +pci:v00009005d00000279* + ID_MODEL_FROM_DATABASE=ServeRAID 6M + +pci:v00009005d00000283* + ID_MODEL_FROM_DATABASE=AAC-RAID + +pci:v00009005d00000283sv00009005sd00000283* + ID_MODEL_FROM_DATABASE=Catapult + +pci:v00009005d00000284* + ID_MODEL_FROM_DATABASE=AAC-RAID + +pci:v00009005d00000284sv00009005sd00000284* + ID_MODEL_FROM_DATABASE=Tomcat + +pci:v00009005d00000285* + ID_MODEL_FROM_DATABASE=AAC-RAID + +pci:v00009005d00000285sv00000E11sd00000295* + ID_MODEL_FROM_DATABASE=SATA 6Ch (Bearcat) + +pci:v00009005d00000285sv00001014sd000002F2* + ID_MODEL_FROM_DATABASE=ServeRAID 8i + +pci:v00009005d00000285sv00001028sd00000287* + ID_MODEL_FROM_DATABASE=PowerEdge Expandable RAID Controller 320/DC + +pci:v00009005d00000285sv00001028sd00000291* + ID_MODEL_FROM_DATABASE=CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) + +pci:v00009005d00000285sv0000103Csd00003227* + ID_MODEL_FROM_DATABASE=AAR-2610SA + +pci:v00009005d00000285sv0000108Esd00000286* + ID_MODEL_FROM_DATABASE=Sun StorageTek SAS RAID HBA, Internal + +pci:v00009005d00000285sv0000108Esd00000287* + ID_MODEL_FROM_DATABASE=STK RAID EXT + +pci:v00009005d00000285sv0000108Esd00007AAC* + ID_MODEL_FROM_DATABASE=STK RAID REM + +pci:v00009005d00000285sv0000108Esd00007AAE* + ID_MODEL_FROM_DATABASE=STK RAID EX + +pci:v00009005d00000285sv000015D9sd000002B5* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S4i + +pci:v00009005d00000285sv000015D9sd000002B6* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S8i + +pci:v00009005d00000285sv000015D9sd000002C9* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S4iR + +pci:v00009005d00000285sv000015D9sd000002CA* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S8iR + +pci:v00009005d00000285sv000015D9sd000002D2* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S8i-LP + +pci:v00009005d00000285sv000015D9sd000002D3* + ID_MODEL_FROM_DATABASE=SMC AOC-USAS-S8iR-LP + +pci:v00009005d00000285sv000017AAsd00000286* + ID_MODEL_FROM_DATABASE=Legend S220 (Legend Crusader) + +pci:v00009005d00000285sv000017AAsd00000287* + ID_MODEL_FROM_DATABASE=Legend S230 (Legend Vulcan) + +pci:v00009005d00000285sv00009005sd00000285* + ID_MODEL_FROM_DATABASE=2200S (Vulcan) + +pci:v00009005d00000285sv00009005sd00000286* + ID_MODEL_FROM_DATABASE=2120S (Crusader) + +pci:v00009005d00000285sv00009005sd00000287* + ID_MODEL_FROM_DATABASE=2200S (Vulcan-2m) + +pci:v00009005d00000285sv00009005sd00000288* + ID_MODEL_FROM_DATABASE=3230S (Harrier) + +pci:v00009005d00000285sv00009005sd00000289* + ID_MODEL_FROM_DATABASE=3240S (Tornado) + +pci:v00009005d00000285sv00009005sd0000028A* + ID_MODEL_FROM_DATABASE=ASR-2020ZCR + +pci:v00009005d00000285sv00009005sd0000028B* + ID_MODEL_FROM_DATABASE=ASR-2025ZCR (Terminator) + +pci:v00009005d00000285sv00009005sd0000028E* + ID_MODEL_FROM_DATABASE=ASR-2020SA (Skyhawk) + +pci:v00009005d00000285sv00009005sd0000028F* + ID_MODEL_FROM_DATABASE=ASR-2025SA + +pci:v00009005d00000285sv00009005sd00000290* + ID_MODEL_FROM_DATABASE=AAR-2410SA PCI SATA 4ch (Jaguar II) + +pci:v00009005d00000285sv00009005sd00000292* + ID_MODEL_FROM_DATABASE=AAR-2810SA PCI SATA 8ch (Corsair-8) + +pci:v00009005d00000285sv00009005sd00000293* + ID_MODEL_FROM_DATABASE=AAR-21610SA PCI SATA 16ch (Corsair-16) + +pci:v00009005d00000285sv00009005sd00000294* + ID_MODEL_FROM_DATABASE=ESD SO-DIMM PCI-X SATA ZCR (Prowler) + +pci:v00009005d00000285sv00009005sd00000296* + ID_MODEL_FROM_DATABASE=ASR-2240S + +pci:v00009005d00000285sv00009005sd00000297* + ID_MODEL_FROM_DATABASE=ASR-4005SAS + +pci:v00009005d00000285sv00009005sd00000298* + ID_MODEL_FROM_DATABASE=ASR-4000 + +pci:v00009005d00000285sv00009005sd00000299* + ID_MODEL_FROM_DATABASE=ASR-4800SAS + +pci:v00009005d00000285sv00009005sd0000029A* + ID_MODEL_FROM_DATABASE=4805SAS + +pci:v00009005d00000285sv00009005sd000002A4* + ID_MODEL_FROM_DATABASE=ICP ICP9085LI + +pci:v00009005d00000285sv00009005sd000002A5* + ID_MODEL_FROM_DATABASE=ICP ICP5085BR + +pci:v00009005d00000285sv00009005sd000002B5* + ID_MODEL_FROM_DATABASE=ASR5800 + +pci:v00009005d00000285sv00009005sd000002B6* + ID_MODEL_FROM_DATABASE=ASR5805 + +pci:v00009005d00000285sv00009005sd000002B7* + ID_MODEL_FROM_DATABASE=ASR5808 + +pci:v00009005d00000285sv00009005sd000002B8* + ID_MODEL_FROM_DATABASE=ICP5445SL + +pci:v00009005d00000285sv00009005sd000002B9* + ID_MODEL_FROM_DATABASE=ICP5085SL + +pci:v00009005d00000285sv00009005sd000002BA* + ID_MODEL_FROM_DATABASE=ICP5805SL + +pci:v00009005d00000285sv00009005sd000002BB* + ID_MODEL_FROM_DATABASE=3405 + +pci:v00009005d00000285sv00009005sd000002BC* + ID_MODEL_FROM_DATABASE=3805 + +pci:v00009005d00000285sv00009005sd000002BD* + ID_MODEL_FROM_DATABASE=31205 + +pci:v00009005d00000285sv00009005sd000002BE* + ID_MODEL_FROM_DATABASE=31605 + +pci:v00009005d00000285sv00009005sd000002BF* + ID_MODEL_FROM_DATABASE=ICP ICP5045BL + +pci:v00009005d00000285sv00009005sd000002C0* + ID_MODEL_FROM_DATABASE=ICP ICP5085BL + +pci:v00009005d00000285sv00009005sd000002C1* + ID_MODEL_FROM_DATABASE=ICP ICP5125BR + +pci:v00009005d00000285sv00009005sd000002C2* + ID_MODEL_FROM_DATABASE=ICP ICP5165BR + +pci:v00009005d00000285sv00009005sd000002C3* + ID_MODEL_FROM_DATABASE=51205 + +pci:v00009005d00000285sv00009005sd000002C4* + ID_MODEL_FROM_DATABASE=51605 + +pci:v00009005d00000285sv00009005sd000002C5* + ID_MODEL_FROM_DATABASE=ICP ICP5125SL + +pci:v00009005d00000285sv00009005sd000002C6* + ID_MODEL_FROM_DATABASE=ICP ICP5165SL + +pci:v00009005d00000285sv00009005sd000002C7* + ID_MODEL_FROM_DATABASE=3085 + +pci:v00009005d00000285sv00009005sd000002C8* + ID_MODEL_FROM_DATABASE=ICP5805BL + +pci:v00009005d00000285sv00009005sd000002CE* + ID_MODEL_FROM_DATABASE=51245 + +pci:v00009005d00000285sv00009005sd000002CF* + ID_MODEL_FROM_DATABASE=51645 + +pci:v00009005d00000285sv00009005sd000002D0* + ID_MODEL_FROM_DATABASE=52445 + +pci:v00009005d00000285sv00009005sd000002D1* + ID_MODEL_FROM_DATABASE=5405 + +pci:v00009005d00000285sv00009005sd000002D4* + ID_MODEL_FROM_DATABASE=ASR-2045 + +pci:v00009005d00000285sv00009005sd000002D5* + ID_MODEL_FROM_DATABASE=ASR-2405 + +pci:v00009005d00000285sv00009005sd000002D6* + ID_MODEL_FROM_DATABASE=ASR-2445 + +pci:v00009005d00000285sv00009005sd000002D7* + ID_MODEL_FROM_DATABASE=ASR-2805 + +pci:v00009005d00000285sv00009005sd000002D8* + ID_MODEL_FROM_DATABASE=5405G + +pci:v00009005d00000285sv00009005sd000002D9* + ID_MODEL_FROM_DATABASE=5445G + +pci:v00009005d00000285sv00009005sd000002DA* + ID_MODEL_FROM_DATABASE=5805G + +pci:v00009005d00000285sv00009005sd000002DB* + ID_MODEL_FROM_DATABASE=5085G + +pci:v00009005d00000285sv00009005sd000002DC* + ID_MODEL_FROM_DATABASE=51245G + +pci:v00009005d00000285sv00009005sd000002DD* + ID_MODEL_FROM_DATABASE=51645G + +pci:v00009005d00000285sv00009005sd000002DE* + ID_MODEL_FROM_DATABASE=52445G + +pci:v00009005d00000285sv00009005sd000002DF* + ID_MODEL_FROM_DATABASE=ASR-2045G + +pci:v00009005d00000285sv00009005sd000002E0* + ID_MODEL_FROM_DATABASE=ASR-2405G + +pci:v00009005d00000285sv00009005sd000002E1* + ID_MODEL_FROM_DATABASE=ASR-2445G + +pci:v00009005d00000285sv00009005sd000002E2* + ID_MODEL_FROM_DATABASE=ASR-2805G + +pci:v00009005d00000286* + ID_MODEL_FROM_DATABASE=AAC-RAID (Rocket) + +pci:v00009005d00000286sv00001014sd0000034D* + ID_MODEL_FROM_DATABASE=8s + +pci:v00009005d00000286sv00001014sd00009540* + ID_MODEL_FROM_DATABASE=ServeRAID 8k/8k-l4 + +pci:v00009005d00000286sv00001014sd00009580* + ID_MODEL_FROM_DATABASE=ServeRAID 8k/8k-l8 + +pci:v00009005d00000286sv00009005sd0000028C* + ID_MODEL_FROM_DATABASE=ASR-2230S + ASR-2230SLP PCI-X (Lancer) + +pci:v00009005d00000286sv00009005sd0000028D* + ID_MODEL_FROM_DATABASE=ASR-2130S + +pci:v00009005d00000286sv00009005sd0000029B* + ID_MODEL_FROM_DATABASE=ASR-2820SA + +pci:v00009005d00000286sv00009005sd0000029C* + ID_MODEL_FROM_DATABASE=ASR-2620SA + +pci:v00009005d00000286sv00009005sd0000029D* + ID_MODEL_FROM_DATABASE=ASR-2420SA + +pci:v00009005d00000286sv00009005sd0000029E* + ID_MODEL_FROM_DATABASE=ICP ICP9024R0 + +pci:v00009005d00000286sv00009005sd0000029F* + ID_MODEL_FROM_DATABASE=ICP ICP9014R0 + +pci:v00009005d00000286sv00009005sd000002A0* + ID_MODEL_FROM_DATABASE=ICP ICP9047MA + +pci:v00009005d00000286sv00009005sd000002A1* + ID_MODEL_FROM_DATABASE=ICP ICP9087MA + +pci:v00009005d00000286sv00009005sd000002A2* + ID_MODEL_FROM_DATABASE=3800 + +pci:v00009005d00000286sv00009005sd000002A3* + ID_MODEL_FROM_DATABASE=ICP ICP5445AU + +pci:v00009005d00000286sv00009005sd000002A4* + ID_MODEL_FROM_DATABASE=ICP ICP9085LI + +pci:v00009005d00000286sv00009005sd000002A5* + ID_MODEL_FROM_DATABASE=ICP ICP5085BR + +pci:v00009005d00000286sv00009005sd000002A6* + ID_MODEL_FROM_DATABASE=ICP9067MA + +pci:v00009005d00000286sv00009005sd000002A7* + ID_MODEL_FROM_DATABASE=3805 + +pci:v00009005d00000286sv00009005sd000002A8* + ID_MODEL_FROM_DATABASE=3400 + +pci:v00009005d00000286sv00009005sd000002A9* + ID_MODEL_FROM_DATABASE=ICP ICP5085AU + +pci:v00009005d00000286sv00009005sd000002AA* + ID_MODEL_FROM_DATABASE=ICP ICP5045AU + +pci:v00009005d00000286sv00009005sd000002AC* + ID_MODEL_FROM_DATABASE=1800 + +pci:v00009005d00000286sv00009005sd000002B3* + ID_MODEL_FROM_DATABASE=2400 + +pci:v00009005d00000286sv00009005sd000002B4* + ID_MODEL_FROM_DATABASE=ICP ICP5045AL + +pci:v00009005d00000286sv00009005sd00000800* + ID_MODEL_FROM_DATABASE=Callisto + +pci:v00009005d0000028B* + ID_MODEL_FROM_DATABASE=Series 6 - 6G SAS/PCIe 2 + +pci:v00009005d0000028Bsv00009005sd00000200* + ID_MODEL_FROM_DATABASE=Series 6 Entry Level - ASR-6405E - 4 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000201* + ID_MODEL_FROM_DATABASE=Series 6 Entry Level - ASR-6805E - 8 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000300* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-6405 - 4 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000301* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-6805 - 8 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000302* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-6445 - 4 internal and 4 external 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000310* + ID_MODEL_FROM_DATABASE=Series 6 Connectors on Top - ASR-6405T - 4 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000311* + ID_MODEL_FROM_DATABASE=Series 6 Connectors on Top - ASR-6805T - 8 internal 6G SAS + +pci:v00009005d0000028Bsv00009005sd00000400* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-61205 - 12 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000401* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-61605 - 16 internal 6G SAS ports + +pci:v00009005d0000028Bsv00009005sd00000403* + ID_MODEL_FROM_DATABASE=Series 6 - ASR-62405 - 24 internal 6G SAS ports + +pci:v00009005d0000028C* + ID_MODEL_FROM_DATABASE=Series 7 6G SAS/PCIe 3 + +pci:v00009005d0000028Csv00009005sd00000500* + ID_MODEL_FROM_DATABASE=Series 7 - ASR-7805 - 8 internal 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000501* + ID_MODEL_FROM_DATABASE=Series 7 - ASR-71605 - 16 internal 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000502* + ID_MODEL_FROM_DATABASE=Series 7 - ASR-71685 - 16 internal 8 external 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000503* + ID_MODEL_FROM_DATABASE=Series 7 - ASR-72405 - 24 internal 0 external 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000504* + ID_MODEL_FROM_DATABASE=Series 7 - ASR-7885 - 8 internal 8 external 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000505* + ID_MODEL_FROM_DATABASE=Series 7 Entry Level - ASR-71685E - 16 internal 8 external 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Csv00009005sd00000506* + ID_MODEL_FROM_DATABASE=Series 7 Entry Level - ASR-72405E - 24 internal 0 external 6G SAS Port/PCIe 3.0 + +pci:v00009005d0000028D* + ID_MODEL_FROM_DATABASE=Series 8 12G SAS/PCIe 3 + +pci:v00009005d0000028Dsv00009005sd00000550* + ID_MODEL_FROM_DATABASE=Series 8 - ASR-82405 - 24 internal 0 external 12G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Dsv00009005sd00000551* + ID_MODEL_FROM_DATABASE=Series 8 - ASR-81605 - 16 internal 0 external 12G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Dsv00009005sd00000552* + ID_MODEL_FROM_DATABASE=Series 8 - ASR-8805 - 8 internal 0 external 12G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Dsv00009005sd00000553* + ID_MODEL_FROM_DATABASE=Series 8 - ASR-8085 - 0 internal 8 external 12G SAS Port/PCIe 3.0 + +pci:v00009005d0000028Dsv00009005sd00000554* + ID_MODEL_FROM_DATABASE=Series 8 - ASR-8885 - 8 internal 8 external 12G SAS Port/PCIe 3.0 + +pci:v00009005d00000410* + ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor HBA RAID) + +pci:v00009005d00000410sv00009005sd00000410* + ID_MODEL_FROM_DATABASE=ASC-48300(Spirit RAID) + +pci:v00009005d00000410sv00009005sd00000411* + ID_MODEL_FROM_DATABASE=ASC-58300 (Oakmont RAID) + +pci:v00009005d00000412* + ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor HBA non-RAID) + +pci:v00009005d00000412sv00009005sd00000412* + ID_MODEL_FROM_DATABASE=ASC-48300 (Spirit non-RAID) + +pci:v00009005d00000412sv00009005sd00000413* + ID_MODEL_FROM_DATABASE=ASC-58300 (Oakmont non-RAID) + +pci:v00009005d00000415* + ID_MODEL_FROM_DATABASE=ASC-58300 SAS (Razor-External HBA RAID) + +pci:v00009005d00000416* + ID_MODEL_FROM_DATABASE=ASC-58300 SAS (Razor-External HBA non-RAID) + +pci:v00009005d0000041E* + ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor ASIC non-RAID) + +pci:v00009005d0000041F* + ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor ASIC RAID) + +pci:v00009005d0000041Fsv00009005sd0000041F* + ID_MODEL_FROM_DATABASE=AIC-9410W SAS (Razor ASIC RAID) + +pci:v00009005d0000042F* + ID_MODEL_FROM_DATABASE=VSC7250/7251 SAS (Aurora ASIC non-RAID) + +pci:v00009005d00000430* + ID_MODEL_FROM_DATABASE=AIC-9405W SAS (Razor-Lite HBA RAID) + +pci:v00009005d00000430sv00009005sd00000430* + ID_MODEL_FROM_DATABASE=ASC-44300 (Spirit-Lite RAID) + +pci:v00009005d00000432* + ID_MODEL_FROM_DATABASE=AIC-9405W SAS (Razor-Lite HBA non-RAID) + +pci:v00009005d00000432sv00009005sd00000432* + ID_MODEL_FROM_DATABASE=ASC-44300 (Spirit-Lite non-RAID) + +pci:v00009005d0000043E* + ID_MODEL_FROM_DATABASE=AIC-9405W SAS (Razor-Lite ASIC non-RAID) + +pci:v00009005d0000043F* + ID_MODEL_FROM_DATABASE=AIC-9405W SAS (Razor-Lite ASIC RAID) + +pci:v00009005d00000450* + ID_MODEL_FROM_DATABASE=ASC-1405 Unified Serial HBA + +pci:v00009005d00000500* + ID_MODEL_FROM_DATABASE=Obsidian chipset SCSI controller + +pci:v00009005d00000500sv00001014sd000002C1* + ID_MODEL_FROM_DATABASE=PCI-X DDR 3Gb SAS Adapter (572A/572C) + +pci:v00009005d00000500sv00001014sd000002C2* + ID_MODEL_FROM_DATABASE=PCI-X DDR 3Gb SAS RAID Adapter (572B/572D) + +pci:v00009005d00000503* + ID_MODEL_FROM_DATABASE=Scamp chipset SCSI controller + +pci:v00009005d00000503sv00001014sd000002BF* + ID_MODEL_FROM_DATABASE=Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571E) + +pci:v00009005d00000503sv00001014sd000002C3* + ID_MODEL_FROM_DATABASE=PCI-X DDR 3Gb SAS RAID Adapter (572F) + +pci:v00009005d00000503sv00001014sd000002D5* + ID_MODEL_FROM_DATABASE=Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571F) + +pci:v00009005d00000910* + ID_MODEL_FROM_DATABASE=AUA-3100B + +pci:v00009005d0000091E* + ID_MODEL_FROM_DATABASE=AUA-3100B + +pci:v00009005d00008000* + ID_MODEL_FROM_DATABASE=ASC-29320A U320 + +pci:v00009005d0000800F* + ID_MODEL_FROM_DATABASE=AIC-7901 U320 + +pci:v00009005d00008010* + ID_MODEL_FROM_DATABASE=ASC-39320 U320 + +pci:v00009005d00008011* + ID_MODEL_FROM_DATABASE=ASC-39320D + +pci:v00009005d00008011sv00000E11sd000000AC* + ID_MODEL_FROM_DATABASE=ASC-39320D U320 + +pci:v00009005d00008011sv00009005sd00000041* + ID_MODEL_FROM_DATABASE=ASC-39320D U320 + +pci:v00009005d00008012* + ID_MODEL_FROM_DATABASE=ASC-29320 U320 + +pci:v00009005d00008013* + ID_MODEL_FROM_DATABASE=ASC-29320B U320 + +pci:v00009005d00008014* + ID_MODEL_FROM_DATABASE=ASC-29320LP U320 + +pci:v00009005d00008015* + ID_MODEL_FROM_DATABASE=ASC-39320B U320 + +pci:v00009005d00008016* + ID_MODEL_FROM_DATABASE=ASC-39320A U320 + +pci:v00009005d00008017* + ID_MODEL_FROM_DATABASE=ASC-29320ALP U320 + +pci:v00009005d00008017sv00009005sd00000044* + ID_MODEL_FROM_DATABASE=ASC-29320ALP PCIx U320 + +pci:v00009005d00008017sv00009005sd00000045* + ID_MODEL_FROM_DATABASE=ASC-29320LPE PCIe U320 + +pci:v00009005d0000801C* + ID_MODEL_FROM_DATABASE=ASC-39320D U320 + +pci:v00009005d0000801D* + ID_MODEL_FROM_DATABASE=AIC-7902B U320 + +pci:v00009005d0000801Dsv00001014sd000002CC* + ID_MODEL_FROM_DATABASE=ServeRAID 7e + +pci:v00009005d0000801E* + ID_MODEL_FROM_DATABASE=AIC-7901A U320 + +pci:v00009005d0000801F* + ID_MODEL_FROM_DATABASE=AIC-7902 U320 + +pci:v00009005d0000801Fsv00001734sd00001011* + ID_MODEL_FROM_DATABASE=PRIMERGY RX300 onboard SCSI + +pci:v00009005d00008080* + ID_MODEL_FROM_DATABASE=ASC-29320A U320 w/HostRAID + +pci:v00009005d00008081* + ID_MODEL_FROM_DATABASE=PMC-Sierra PM8001 SAS HBA [Series 6H] + +pci:v00009005d00008088* + ID_MODEL_FROM_DATABASE=PMC-Sierra PM8018 SAS HBA [Series 7H] + +pci:v00009005d00008089* + ID_MODEL_FROM_DATABASE=PMC-Sierra PM8019 SAS encryption HBA [Series 7He] + +pci:v00009005d0000808F* + ID_MODEL_FROM_DATABASE=AIC-7901 U320 w/HostRAID + +pci:v00009005d00008090* + ID_MODEL_FROM_DATABASE=ASC-39320 U320 w/HostRAID + +pci:v00009005d00008091* + ID_MODEL_FROM_DATABASE=ASC-39320D U320 w/HostRAID + +pci:v00009005d00008092* + ID_MODEL_FROM_DATABASE=ASC-29320 U320 w/HostRAID + +pci:v00009005d00008093* + ID_MODEL_FROM_DATABASE=ASC-29320B U320 w/HostRAID + +pci:v00009005d00008094* + ID_MODEL_FROM_DATABASE=ASC-29320LP U320 w/HostRAID + +pci:v00009005d00008095* + ID_MODEL_FROM_DATABASE=ASC-39320(B) U320 w/HostRAID + +pci:v00009005d00008096* + ID_MODEL_FROM_DATABASE=ASC-39320A U320 w/HostRAID + +pci:v00009005d00008097* + ID_MODEL_FROM_DATABASE=ASC-29320ALP U320 w/HostRAID + +pci:v00009005d0000809C* + ID_MODEL_FROM_DATABASE=ASC-39320D(B) U320 w/HostRAID + +pci:v00009005d0000809D* + ID_MODEL_FROM_DATABASE=AIC-7902(B) U320 w/HostRAID + +pci:v00009005d0000809Dsv00001014sd000002CC* + ID_MODEL_FROM_DATABASE=ServeRAID 7e + +pci:v00009005d0000809E* + ID_MODEL_FROM_DATABASE=AIC-7901A U320 w/HostRAID + +pci:v00009005d0000809F* + ID_MODEL_FROM_DATABASE=AIC-7902 U320 w/HostRAID + +pci:v0000907F* + ID_VENDOR_FROM_DATABASE=Atronics + +pci:v0000907Fd00002015* + ID_MODEL_FROM_DATABASE=IDE-2015PL + +pci:v0000919A* + ID_VENDOR_FROM_DATABASE=Gigapixel Corp + +pci:v00009412* + ID_VENDOR_FROM_DATABASE=Holtek + +pci:v00009412d00006565* + ID_MODEL_FROM_DATABASE=6565 + +pci:v00009618* + ID_VENDOR_FROM_DATABASE=JusonTech Corporation + +pci:v00009618d00000001* + ID_MODEL_FROM_DATABASE=JusonTech Gigabit Ethernet Controller + +pci:v00009699* + ID_VENDOR_FROM_DATABASE=Omni Media Technology Inc + +pci:v00009699d00006565* + ID_MODEL_FROM_DATABASE=6565 + +pci:v00009710* + ID_VENDOR_FROM_DATABASE=MosChip Semiconductor Technology Ltd. + +pci:v00009710d00009250* + ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge [MCS9250] + +pci:v00009710d00009805* + ID_MODEL_FROM_DATABASE=PCI 1 port parallel adapter + +pci:v00009710d00009815* + ID_MODEL_FROM_DATABASE=PCI 9815 Multi-I/O Controller + +pci:v00009710d00009815sv00001000sd00000020* + ID_MODEL_FROM_DATABASE=2P0S (2 port parallel adaptor) + +pci:v00009710d00009820* + ID_MODEL_FROM_DATABASE=PCI 9820 Multi-I/O Controller + +pci:v00009710d00009835* + ID_MODEL_FROM_DATABASE=PCI 9835 Multi-I/O Controller + +pci:v00009710d00009835sv00001000sd00000002* + ID_MODEL_FROM_DATABASE=2S (16C550 UART) + +pci:v00009710d00009835sv00001000sd00000012* + ID_MODEL_FROM_DATABASE=1P2S + +pci:v00009710d00009845* + ID_MODEL_FROM_DATABASE=PCI 9845 Multi-I/O Controller + +pci:v00009710d00009845sv00001000sd00000004* + ID_MODEL_FROM_DATABASE=0P4S (4 port 16550A serial card) + +pci:v00009710d00009845sv00001000sd00000006* + ID_MODEL_FROM_DATABASE=0P6S (6 port 16550a serial card) + +pci:v00009710d00009845sv00001000sd00000014* + ID_MODEL_FROM_DATABASE=1P4S (1 Parallel / 4 16550A Serial Port Adapter) + +pci:v00009710d00009855* + ID_MODEL_FROM_DATABASE=PCI 9855 Multi-I/O Controller + +pci:v00009710d00009855sv00001000sd00000014* + ID_MODEL_FROM_DATABASE=1P4S + +pci:v00009710d00009855sv00001000sd00000022* + ID_MODEL_FROM_DATABASE=2P2S (2 Parallel / 2 16550A Serial Port Adapter) + +pci:v00009710d00009865* + ID_MODEL_FROM_DATABASE=PCI 9865 Multi-I/O Controller + +pci:v00009710d00009901* + ID_MODEL_FROM_DATABASE=PCIe 9901 Multi-I/O Controller + +pci:v00009710d00009904* + ID_MODEL_FROM_DATABASE=4-Port PCIe Serial Adapter + +pci:v00009710d00009912* + ID_MODEL_FROM_DATABASE=PCIe 9912 Multi-I/O Controller + +pci:v00009710d00009922* + ID_MODEL_FROM_DATABASE=PCIe 9922 Multi-I/O Controller + +pci:v00009710d00009990* + ID_MODEL_FROM_DATABASE=MCS9990 PCIe to 4‐Port USB 2.0 Host Controller + +pci:v00009902* + ID_VENDOR_FROM_DATABASE=Stargen Inc. + +pci:v00009902d00000001* + ID_MODEL_FROM_DATABASE=SG2010 PCI over Starfabric Bridge + +pci:v00009902d00000002* + ID_MODEL_FROM_DATABASE=SG2010 PCI to Starfabric Gateway + +pci:v00009902d00000003* + ID_MODEL_FROM_DATABASE=SG1010 Starfabric Switch and PCI Bridge + +pci:v0000A0A0* + ID_VENDOR_FROM_DATABASE=AOPEN Inc. + +pci:v0000A0F1* + ID_VENDOR_FROM_DATABASE=UNISYS Corporation + +pci:v0000A200* + ID_VENDOR_FROM_DATABASE=NEC Corporation + +pci:v0000A259* + ID_VENDOR_FROM_DATABASE=Hewlett Packard + +pci:v0000A25B* + ID_VENDOR_FROM_DATABASE=Hewlett Packard GmbH PL24-MKT + +pci:v0000A304* + ID_VENDOR_FROM_DATABASE=Sony + +pci:v0000A727* + ID_VENDOR_FROM_DATABASE=3Com Corporation + +pci:v0000A727d00000013* + ID_MODEL_FROM_DATABASE=3CRPAG175 Wireless PC Card + +pci:v0000A727d00006803* + ID_MODEL_FROM_DATABASE=3CRDAG675B Wireless 11a/b/g Adapter + +pci:v0000AA42* + ID_VENDOR_FROM_DATABASE=Scitex Digital Video + +pci:v0000AA55* + ID_VENDOR_FROM_DATABASE=Ncomputing X300 PCI-Engine + +pci:v0000AAAA* + ID_VENDOR_FROM_DATABASE=Adnaco Technology Inc. + +pci:v0000AAAAd00000001* + ID_MODEL_FROM_DATABASE=H1 PCIe over fiber optic host controller + +pci:v0000AAAAd00000002* + ID_MODEL_FROM_DATABASE=R1BP1 PCIe over fiber optic expansion chassis + +pci:v0000ABCD* + ID_VENDOR_FROM_DATABASE=Vadatech Inc. + +pci:v0000AC1E* + ID_VENDOR_FROM_DATABASE=Digital Receiver Technology Inc + +pci:v0000AC3D* + ID_VENDOR_FROM_DATABASE=Actuality Systems + +pci:v0000AD00* + ID_VENDOR_FROM_DATABASE=Alta Data Technologies LLC + +pci:v0000AECB* + ID_VENDOR_FROM_DATABASE=Adrienne Electronics Corporation + +pci:v0000AECBd00006250* + ID_MODEL_FROM_DATABASE=VITC/LTC Timecode Reader card [PCI-VLTC/RDR] + +pci:v0000AFFE* + ID_VENDOR_FROM_DATABASE=Sirrix AG security technologies + +pci:v0000AFFEd000001E1* + ID_MODEL_FROM_DATABASE=PCI1E1 1-port ISDN E1 interface + +pci:v0000AFFEd000002E1* + ID_MODEL_FROM_DATABASE=PCI2E1 2-port ISDN E1 interface + +pci:v0000AFFEd0000450E* + ID_MODEL_FROM_DATABASE=PCI4S0EC 4-port ISDN S0 interface + +pci:v0000AFFEd0000DEAD* + ID_MODEL_FROM_DATABASE=Sirrix.PCI4S0 4-port ISDN S0 interface + +pci:v0000B100* + ID_VENDOR_FROM_DATABASE=OpenVox Communication Co. Ltd. + +pci:v0000B10B* + ID_VENDOR_FROM_DATABASE=Uakron PCI Project + +pci:v0000B1B3* + ID_VENDOR_FROM_DATABASE=Shiva Europe Limited + +pci:v0000B1D9* + ID_VENDOR_FROM_DATABASE=ATCOM Technology co., LTD. + +pci:v0000BD11* + ID_VENDOR_FROM_DATABASE=Pinnacle Systems, Inc. (Wrong ID) + +pci:v0000BDBD* + ID_VENDOR_FROM_DATABASE=Blackmagic Design + +pci:v0000BDBDd0000A117* + ID_MODEL_FROM_DATABASE=Intensity Pro + +pci:v0000BDBDd0000A11A* + ID_MODEL_FROM_DATABASE=DeckLink HD Extreme 2 + +pci:v0000BDBDd0000A11B* + ID_MODEL_FROM_DATABASE=DeckLink SDI/Duo/Quad + +pci:v0000BDBDd0000A11C* + ID_MODEL_FROM_DATABASE=DeckLink HD Extreme 3 + +pci:v0000BDBDd0000A11D* + ID_MODEL_FROM_DATABASE=DeckLink Studio + +pci:v0000BDBDd0000A11E* + ID_MODEL_FROM_DATABASE=DeckLink Optical Fibre + +pci:v0000BDBDd0000A121* + ID_MODEL_FROM_DATABASE=DeckLink HD Extreme 3D/3D+ + +pci:v0000BDBDd0000A124* + ID_MODEL_FROM_DATABASE=Intensity Extreme + +pci:v0000BDBDd0000A126* + ID_MODEL_FROM_DATABASE=Intensity Shuttle + +pci:v0000BDBDd0000A127* + ID_MODEL_FROM_DATABASE=UltraStudio Express + +pci:v0000BDBDd0000A129* + ID_MODEL_FROM_DATABASE=UltraStudio Mini Monitor + +pci:v0000BDBDd0000A12A* + ID_MODEL_FROM_DATABASE=UltraStudio Mini Recorder + +pci:v0000BDBDd0000A12D* + ID_MODEL_FROM_DATABASE=UltraStudio 4K + +pci:v0000BDBDd0000A12E* + ID_MODEL_FROM_DATABASE=DeckLink 4K Extreme + +pci:v0000BDBDd0000A12F* + ID_MODEL_FROM_DATABASE=DeckLink Mini Monitor + +pci:v0000BDBDd0000A130* + ID_MODEL_FROM_DATABASE=DeckLink Mini Recorder + +pci:v0000BDBDd0000A132* + ID_MODEL_FROM_DATABASE=UltraStudio 4K + +pci:v0000C001* + ID_VENDOR_FROM_DATABASE=TSI Telsys + +pci:v0000C0A9* + ID_VENDOR_FROM_DATABASE=Micron/Crucial Technology + +pci:v0000C0DE* + ID_VENDOR_FROM_DATABASE=Motorola + +pci:v0000C0FE* + ID_VENDOR_FROM_DATABASE=Motion Engineering, Inc. + +pci:v0000CA50* + ID_VENDOR_FROM_DATABASE=Varian Australia Pty Ltd + +pci:v0000CACE* + ID_VENDOR_FROM_DATABASE=CACE Technologies, Inc. + +pci:v0000CACEd00000001* + ID_MODEL_FROM_DATABASE=TurboCap Port A + +pci:v0000CACEd00000002* + ID_MODEL_FROM_DATABASE=TurboCap Port B + +pci:v0000CACEd00000023* + ID_MODEL_FROM_DATABASE=AirPcap N + +pci:v0000CAED* + ID_VENDOR_FROM_DATABASE=Canny Edge + +pci:v0000CAFE* + ID_VENDOR_FROM_DATABASE=Chrysalis-ITS + +pci:v0000CAFEd00000003* + ID_MODEL_FROM_DATABASE=Luna K3 Hardware Security Module + +pci:v0000CAFEd00000006* + ID_MODEL_FROM_DATABASE=Luna PCI-e 3000 Hardware Security Module + +pci:v0000CCCC* + ID_VENDOR_FROM_DATABASE=Catapult Communications + +pci:v0000CCEC* + ID_VENDOR_FROM_DATABASE=Curtiss-Wright Controls Embedded Computing + +pci:v0000CDDD* + ID_VENDOR_FROM_DATABASE=Tyzx, Inc. + +pci:v0000CDDDd00000101* + ID_MODEL_FROM_DATABASE=DeepSea 1 High Speed Stereo Vision Frame Grabber + +pci:v0000CDDDd00000200* + ID_MODEL_FROM_DATABASE=DeepSea 2 High Speed Stereo Vision Frame Grabber + +pci:v0000CEBA* + ID_VENDOR_FROM_DATABASE=KEBA AG + +pci:v0000D161* + ID_VENDOR_FROM_DATABASE=Digium, Inc. + +pci:v0000D161d00000120* + ID_MODEL_FROM_DATABASE=Wildcard TE120P single-span T1/E1/J1 card + +pci:v0000D161d00000205* + ID_MODEL_FROM_DATABASE=Wildcard TE205P/TE207P dual-span T1/E1/J1 card 5.0V + +pci:v0000D161d00000210* + ID_MODEL_FROM_DATABASE=Wildcard TE210P/TE212P dual-span T1/E1/J1 card 3.3V + +pci:v0000D161d00000220* + ID_MODEL_FROM_DATABASE=Wildcard TE220 dual-span T1/E1/J1 card 3.3V (PCI-Express) + +pci:v0000D161d00000405* + ID_MODEL_FROM_DATABASE=Wildcard TE405P/TE407P quad-span T1/E1/J1 card 5.0V + +pci:v0000D161d00000410* + ID_MODEL_FROM_DATABASE=Wildcard TE410P/TE412P quad-span T1/E1/J1 card 3.3V + +pci:v0000D161d00000420* + ID_MODEL_FROM_DATABASE=Wildcard TE420P quad-span T1/E1/J1 card 3.3V (PCI-Express) + +pci:v0000D161d00000800* + ID_MODEL_FROM_DATABASE=Wildcard TDM800P 8-port analog card + +pci:v0000D161d00001205* + ID_MODEL_FROM_DATABASE=Wildcard TE205P/TE207P dual-span T1/E1/J1 card 5.0V (u1) + +pci:v0000D161d00001220* + ID_MODEL_FROM_DATABASE=Wildcard TE220 dual-span T1/E1/J1 card 3.3V (PCI-Express) (5th gen) + +pci:v0000D161d00001405* + ID_MODEL_FROM_DATABASE=Wildcard TE405P/TE407P quad-span T1/E1/J1 card 5.0V (u1) + +pci:v0000D161d00001420* + ID_MODEL_FROM_DATABASE=Wildcard TE420 quad-span T1/E1/J1 card 3.3V (PCI-Express) (5th gen) + +pci:v0000D161d00002400* + ID_MODEL_FROM_DATABASE=Wildcard TDM2400P 24-port analog card + +pci:v0000D161d00003400* + ID_MODEL_FROM_DATABASE=Wildcard TC400P transcoder base card + +pci:v0000D161d00008000* + ID_MODEL_FROM_DATABASE=Wildcard TE121 single-span T1/E1/J1 card (PCI-Express) + +pci:v0000D161d00008001* + ID_MODEL_FROM_DATABASE=Wildcard TE122 single-span T1/E1/J1 card + +pci:v0000D161d00008002* + ID_MODEL_FROM_DATABASE=Wildcard AEX800 8-port analog card (PCI-Express) + +pci:v0000D161d00008003* + ID_MODEL_FROM_DATABASE=Wildcard AEX2400 24-port analog card (PCI-Express) + +pci:v0000D161d00008004* + ID_MODEL_FROM_DATABASE=Wildcard TCE400P transcoder base card + +pci:v0000D161d00008005* + ID_MODEL_FROM_DATABASE=Wildcard TDM410 4-port analog card + +pci:v0000D161d00008006* + ID_MODEL_FROM_DATABASE=Wildcard AEX410 4-port analog card (PCI-Express) + +pci:v0000D161d00008007* + ID_MODEL_FROM_DATABASE=Hx8 Series 8-port Base Card + +pci:v0000D161d00008008* + ID_MODEL_FROM_DATABASE=Hx8 Series 8-port Base Card (PCI-Express) + +pci:v0000D161d0000800A* + ID_MODEL_FROM_DATABASE=Wildcard TE133 single-span T1/E1/J1 card (PCI Express) + +pci:v0000D161d0000800B* + ID_MODEL_FROM_DATABASE=Wildcard TE134 single-span T1/E1/J1 card + +pci:v0000D161d0000B410* + ID_MODEL_FROM_DATABASE=Wildcard B410 quad-BRI card + +pci:v0000D4D4* + ID_VENDOR_FROM_DATABASE=Dy4 Systems Inc + +pci:v0000D4D4d00000601* + ID_MODEL_FROM_DATABASE=PCI Mezzanine Card + +pci:v0000D531* + ID_VENDOR_FROM_DATABASE=I+ME ACTIA GmbH + +pci:v0000D84D* + ID_VENDOR_FROM_DATABASE=Exsys + +pci:v0000DADA* + ID_VENDOR_FROM_DATABASE=Datapath Limited + +pci:v0000DB10* + ID_VENDOR_FROM_DATABASE=Diablo Technologies + +pci:v0000DCBA* + ID_VENDOR_FROM_DATABASE=Dynamic Engineering + +pci:v0000DCBAd00000046* + ID_MODEL_FROM_DATABASE=PCIe Altera Cyclone IV + +pci:v0000DCBAd00000047* + ID_MODEL_FROM_DATABASE=VPX-RCB + +pci:v0000DCBAd00000048* + ID_MODEL_FROM_DATABASE=PMC-Biserial-III-BAE9 + +pci:v0000DCBAd0000004E* + ID_MODEL_FROM_DATABASE=PC104p-Biserial-III-NVY5 + +pci:v0000DCBAd0000004F* + ID_MODEL_FROM_DATABASE=PC104p-Biserial-III-NVY6 + +pci:v0000DCBAd00000052* + ID_MODEL_FROM_DATABASE=PCIeBiSerialDb37 BA22 LVDS IO + +pci:v0000DD01* + ID_VENDOR_FROM_DATABASE=Digital Devices GmbH + +pci:v0000DD01d00000003* + ID_MODEL_FROM_DATABASE=Octopus DVB Adapter + +pci:v0000DD01d00000003sv0000DD01sd00000001* + ID_MODEL_FROM_DATABASE=Octopus DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd00000002* + ID_MODEL_FROM_DATABASE=Octopus LE DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd00000003* + ID_MODEL_FROM_DATABASE=Octopus OEM + +pci:v0000DD01d00000003sv0000DD01sd00000004* + ID_MODEL_FROM_DATABASE=Octopus V3 DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd00000010* + ID_MODEL_FROM_DATABASE=Octopus Mini + +pci:v0000DD01d00000003sv0000DD01sd00000020* + ID_MODEL_FROM_DATABASE=Cine S2 V6 DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd00000021* + ID_MODEL_FROM_DATABASE=Cine S2 V6.5 DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd00000030* + ID_MODEL_FROM_DATABASE=Cine CT V6.1 DVB adapter + +pci:v0000DD01d00000003sv0000DD01sd0000DB03* + ID_MODEL_FROM_DATABASE=Mystique SaTiX-S2 V3 DVB adapter + +pci:v0000DD01d00000011* + ID_MODEL_FROM_DATABASE=Octopus CI DVB Adapter + +pci:v0000DD01d00000011sv0000DD01sd00000040* + ID_MODEL_FROM_DATABASE=Octopus CI + +pci:v0000DD01d00000011sv0000DD01sd00000041* + ID_MODEL_FROM_DATABASE=Octopus CI Single + +pci:v0000DEAD* + ID_VENDOR_FROM_DATABASE=Indigita Corporation + +pci:v0000DEAF* + ID_VENDOR_FROM_DATABASE=Middle Digital Inc. + +pci:v0000DEAFd00009050* + ID_MODEL_FROM_DATABASE=PC Weasel Virtual VGA + +pci:v0000DEAFd00009051* + ID_MODEL_FROM_DATABASE=PC Weasel Serial Port + +pci:v0000DEAFd00009052* + ID_MODEL_FROM_DATABASE=PC Weasel Watchdog Timer + +pci:v0000DEDA* + ID_VENDOR_FROM_DATABASE=SoftHard Technology Ltd. + +pci:v0000E000* + ID_VENDOR_FROM_DATABASE=Winbond + +pci:v0000E000d0000E000* + ID_MODEL_FROM_DATABASE=W89C940 + +pci:v0000E159* + ID_VENDOR_FROM_DATABASE=Tiger Jet Network Inc. + +pci:v0000E159d00000001* + ID_MODEL_FROM_DATABASE=Tiger3XX Modem/ISDN interface + +pci:v0000E159d00000001sv00000059sd00000001* + ID_MODEL_FROM_DATABASE=128k ISDN-S/T Adapter + +pci:v0000E159d00000001sv00000059sd00000003* + ID_MODEL_FROM_DATABASE=128k ISDN-U Adapter + +pci:v0000E159d00000001sv000000A7sd00000001* + ID_MODEL_FROM_DATABASE=TELES.S0/PCI 2.x ISDN Adapter + +pci:v0000E159d00000001sv00008086sd00000003* + ID_MODEL_FROM_DATABASE=Digium X100P/X101P analogue PSTN FXO interface + +pci:v0000E159d00000001sv0000B100sd00000003* + ID_MODEL_FROM_DATABASE=OpenVox A400P 4-port analog card + +pci:v0000E159d00000001sv0000B1D9sd00000003* + ID_MODEL_FROM_DATABASE=AX400P 4-port analog card + +pci:v0000E159d00000002* + ID_MODEL_FROM_DATABASE=Tiger100APC ISDN chipset + +pci:v0000E1C5* + ID_VENDOR_FROM_DATABASE=Elcus + +pci:v0000E4BF* + ID_VENDOR_FROM_DATABASE=EKF Elektronik GmbH + +pci:v0000E4BFd00000CCD* + ID_MODEL_FROM_DATABASE=CCD-CALYPSO + +pci:v0000E4BFd00000CD1* + ID_MODEL_FROM_DATABASE=CD1-OPERA + +pci:v0000E4BFd00000CD2* + ID_MODEL_FROM_DATABASE=CD2-BEBOP + +pci:v0000E4BFd00000CD3* + ID_MODEL_FROM_DATABASE=CD3-JIVE + +pci:v0000E4BFd000050C1* + ID_MODEL_FROM_DATABASE=PC1-GROOVE + +pci:v0000E4BFd000050C2* + ID_MODEL_FROM_DATABASE=PC2-LIMBO + +pci:v0000E4BFd000053C1* + ID_MODEL_FROM_DATABASE=SC1-ALLEGRO + +pci:v0000E4BFd0000CC47* + ID_MODEL_FROM_DATABASE=CCG-RUMBA + +pci:v0000E4BFd0000CC4D* + ID_MODEL_FROM_DATABASE=CCM-BOOGIE + +pci:v0000E55E* + ID_VENDOR_FROM_DATABASE=Essence Technology, Inc. + +pci:v0000EA01* + ID_VENDOR_FROM_DATABASE=Eagle Technology + +pci:v0000EA01d0000000A* + ID_MODEL_FROM_DATABASE=PCI-773 Temperature Card + +pci:v0000EA01d00000032* + ID_MODEL_FROM_DATABASE=PCI-730 & PC104P-30 Card + +pci:v0000EA01d0000003E* + ID_MODEL_FROM_DATABASE=PCI-762 Opto-Isolator Card + +pci:v0000EA01d00000041* + ID_MODEL_FROM_DATABASE=PCI-763 Reed Relay Card + +pci:v0000EA01d00000043* + ID_MODEL_FROM_DATABASE=PCI-769 Opto-Isolator Reed Relay Combo Card + +pci:v0000EA01d00000046* + ID_MODEL_FROM_DATABASE=PCI-766 Analog Output Card + +pci:v0000EA01d00000052* + ID_MODEL_FROM_DATABASE=PCI-703 Analog I/O Card + +pci:v0000EA01d00000800* + ID_MODEL_FROM_DATABASE=PCI-800 Digital I/O Card + +pci:v0000EA60* + ID_VENDOR_FROM_DATABASE=RME + +pci:v0000EA60d00009896* + ID_MODEL_FROM_DATABASE=Digi32 + +pci:v0000EA60d00009897* + ID_MODEL_FROM_DATABASE=Digi32 Pro + +pci:v0000EA60d00009898* + ID_MODEL_FROM_DATABASE=Digi32/8 + +pci:v0000EABB* + ID_VENDOR_FROM_DATABASE=Aashima Technology B.V. + +pci:v0000EACE* + ID_VENDOR_FROM_DATABASE=Endace Measurement Systems, Ltd + +pci:v0000EACEd00003100* + ID_MODEL_FROM_DATABASE=DAG 3.10 OC-3/OC-12 + +pci:v0000EACEd00003200* + ID_MODEL_FROM_DATABASE=DAG 3.2x OC-3/OC-12 + +pci:v0000EACEd0000320E* + ID_MODEL_FROM_DATABASE=DAG 3.2E Fast Ethernet + +pci:v0000EACEd0000340E* + ID_MODEL_FROM_DATABASE=DAG 3.4E Fast Ethernet + +pci:v0000EACEd0000341E* + ID_MODEL_FROM_DATABASE=DAG 3.41E Fast Ethernet + +pci:v0000EACEd00003500* + ID_MODEL_FROM_DATABASE=DAG 3.5 OC-3/OC-12 + +pci:v0000EACEd0000351C* + ID_MODEL_FROM_DATABASE=DAG 3.5ECM Fast Ethernet + +pci:v0000EACEd0000360D* + ID_MODEL_FROM_DATABASE=DAG 3.6D DS3 + +pci:v0000EACEd0000360E* + ID_MODEL_FROM_DATABASE=DAG 3.6E Fast Ethernet + +pci:v0000EACEd0000368E* + ID_MODEL_FROM_DATABASE=DAG 3.6E Gig Ethernet + +pci:v0000EACEd00003707* + ID_MODEL_FROM_DATABASE=DAG 3.7T T1/E1/J1 + +pci:v0000EACEd0000370D* + ID_MODEL_FROM_DATABASE=DAG 3.7D DS3/E3 + +pci:v0000EACEd0000378E* + ID_MODEL_FROM_DATABASE=DAG 3.7G Gig Ethernet + +pci:v0000EACEd00003800* + ID_MODEL_FROM_DATABASE=DAG 3.8S OC-3/OC-12 + +pci:v0000EACEd00004100* + ID_MODEL_FROM_DATABASE=DAG 4.10 OC-48 + +pci:v0000EACEd00004110* + ID_MODEL_FROM_DATABASE=DAG 4.11 OC-48 + +pci:v0000EACEd00004220* + ID_MODEL_FROM_DATABASE=DAG 4.2 OC-48 + +pci:v0000EACEd0000422E* + ID_MODEL_FROM_DATABASE=DAG 4.2GE Gig Ethernet + +pci:v0000EACEd00004230* + ID_MODEL_FROM_DATABASE=DAG 4.2S OC-48 + +pci:v0000EACEd0000423E* + ID_MODEL_FROM_DATABASE=DAG 4.2GE Gig Ethernet + +pci:v0000EACEd00004300* + ID_MODEL_FROM_DATABASE=DAG 4.3S OC-48 + +pci:v0000EACEd0000430E* + ID_MODEL_FROM_DATABASE=DAG 4.3GE Gig Ethernet + +pci:v0000EACEd0000452E* + ID_MODEL_FROM_DATABASE=DAG 4.5G2 Gig Ethernet + +pci:v0000EACEd0000454E* + ID_MODEL_FROM_DATABASE=DAG 4.5G4 Gig Ethernet + +pci:v0000EACEd000045B8* + ID_MODEL_FROM_DATABASE=DAG 4.5Z8 Gig Ethernet + +pci:v0000EACEd000045BE* + ID_MODEL_FROM_DATABASE=DAG 4.5Z2 Gig Ethernet + +pci:v0000EACEd0000520E* + ID_MODEL_FROM_DATABASE=DAG 5.2X 10G Ethernet + +pci:v0000EACEd0000521A* + ID_MODEL_FROM_DATABASE=DAG 5.2SXA 10G Ethernet/OC-192 + +pci:v0000EACEd00005400* + ID_MODEL_FROM_DATABASE=DAG 5.4S-12 OC-3/OC-12 + +pci:v0000EACEd00005401* + ID_MODEL_FROM_DATABASE=DAG 5.4SG-48 Gig Ethernet/OC-3/OC-12/OC-48 + +pci:v0000EACEd0000540A* + ID_MODEL_FROM_DATABASE=DAG 5.4GA Gig Ethernet + +pci:v0000EACEd0000541A* + ID_MODEL_FROM_DATABASE=DAG 5.4SA-12 OC-3/OC-12 + +pci:v0000EACEd0000542A* + ID_MODEL_FROM_DATABASE=DAG 5.4SGA-48 Gig Ethernet/OC-3/OC-12/OC-48 + +pci:v0000EACEd00006000* + ID_MODEL_FROM_DATABASE=DAG 6.0SE 10G Ethernet/OC-192 + +pci:v0000EACEd00006100* + ID_MODEL_FROM_DATABASE=DAG 6.1SE 10G Ethernet/OC-192 + +pci:v0000EACEd00006200* + ID_MODEL_FROM_DATABASE=DAG 6.2SE 10G Ethernet/OC-192 + +pci:v0000EACEd00007100* + ID_MODEL_FROM_DATABASE=DAG 7.1S OC-3/OC-12 + +pci:v0000EACEd00007400* + ID_MODEL_FROM_DATABASE=DAG 7.4S OC-3/OC-12 + +pci:v0000EACEd00007401* + ID_MODEL_FROM_DATABASE=DAG 7.4S48 OC-48 + +pci:v0000EACEd0000752E* + ID_MODEL_FROM_DATABASE=DAG 7.5G2 Gig Ethernet + +pci:v0000EACEd0000754E* + ID_MODEL_FROM_DATABASE=DAG 7.5G4 Gig Ethernet + +pci:v0000EACEd00008100* + ID_MODEL_FROM_DATABASE=DAG 8.1X 10G Ethernet + +pci:v0000EACEd00008101* + ID_MODEL_FROM_DATABASE=DAG 8.1SX 10G Ethernet/OC-192 + +pci:v0000EACEd00008102* + ID_MODEL_FROM_DATABASE=DAG 8.1X 10G Ethernet + +pci:v0000EACEd0000820E* + ID_MODEL_FROM_DATABASE=DAG 8.2X 10G Ethernet + +pci:v0000EACEd0000820F* + ID_MODEL_FROM_DATABASE=DAG 8.2X 10G Ethernet (2nd bus) + +pci:v0000EACEd00008400* + ID_MODEL_FROM_DATABASE=DAG 8.4I Infiniband x4 SDR + +pci:v0000EACEd00008500* + ID_MODEL_FROM_DATABASE=DAG 8.5I Infiniband x4 DDR + +pci:v0000EACEd0000920E* + ID_MODEL_FROM_DATABASE=DAG 9.2X2 10G Ethernet + +pci:v0000EC80* + ID_VENDOR_FROM_DATABASE=Belkin Corporation + +pci:v0000EC80d0000EC00* + ID_MODEL_FROM_DATABASE=F5D6000 + +pci:v0000ECC0* + ID_VENDOR_FROM_DATABASE=Echo Digital Audio Corporation + +pci:v0000EDD8* + ID_VENDOR_FROM_DATABASE=ARK Logic Inc + +pci:v0000EDD8d0000A091* + ID_MODEL_FROM_DATABASE=1000PV [Stingray] + +pci:v0000EDD8d0000A099* + ID_MODEL_FROM_DATABASE=2000PV [Stingray] + +pci:v0000EDD8d0000A0A1* + ID_MODEL_FROM_DATABASE=2000MT + +pci:v0000EDD8d0000A0A9* + ID_MODEL_FROM_DATABASE=2000MI + +pci:v0000F043* + ID_VENDOR_FROM_DATABASE=ASUSTeK Computer Inc. (Wrong ID) + +pci:v0000F05B* + ID_VENDOR_FROM_DATABASE=Foxconn International, Inc. (Wrong ID) + +pci:v0000F1D0* + ID_VENDOR_FROM_DATABASE=AJA Video + +pci:v0000F1D0d0000C0FE* + ID_MODEL_FROM_DATABASE=Xena HS/HD-R + +pci:v0000F1D0d0000C0FF* + ID_MODEL_FROM_DATABASE=Kona/Xena 2 + +pci:v0000F1D0d0000CAFE* + ID_MODEL_FROM_DATABASE=Kona SD + +pci:v0000F1D0d0000CFEE* + ID_MODEL_FROM_DATABASE=Xena LS/SD-22-DA/SD-DA + +pci:v0000F1D0d0000DCAF* + ID_MODEL_FROM_DATABASE=Kona HD + +pci:v0000F1D0d0000DFEE* + ID_MODEL_FROM_DATABASE=Xena HD-DA + +pci:v0000F1D0d0000EFAC* + ID_MODEL_FROM_DATABASE=Xena SD-MM/SD-22-MM + +pci:v0000F1D0d0000FACD* + ID_MODEL_FROM_DATABASE=Xena HD-MM + +pci:v0000F5F5* + ID_VENDOR_FROM_DATABASE=F5 Networks, Inc. + +pci:v0000F849* + ID_VENDOR_FROM_DATABASE=ASRock Incorporation (Wrong ID) + +pci:v0000FA57* + ID_VENDOR_FROM_DATABASE=Interagon AS + +pci:v0000FA57d00000001* + ID_MODEL_FROM_DATABASE=PMC [Pattern Matching Chip] + +pci:v0000FAB7* + ID_VENDOR_FROM_DATABASE=Fabric7 Systems, Inc. + +pci:v0000FEBD* + ID_VENDOR_FROM_DATABASE=Ultraview Corp. + +pci:v0000FEDA* + ID_VENDOR_FROM_DATABASE=Broadcom Inc + +pci:v0000FEDAd0000A0FA* + ID_MODEL_FROM_DATABASE=BCM4210 iLine10 HomePNA 2.0 + +pci:v0000FEDAd0000A10E* + ID_MODEL_FROM_DATABASE=BCM4230 iLine10 HomePNA 2.0 + +pci:v0000FEDE* + ID_VENDOR_FROM_DATABASE=Fedetec Inc. + +pci:v0000FEDEd00000003* + ID_MODEL_FROM_DATABASE=TABIC PCI v3 + +pci:v0000FFFD* + ID_VENDOR_FROM_DATABASE=XenSource, Inc. + +pci:v0000FFFDd00000101* + ID_MODEL_FROM_DATABASE=PCI Event Channel Controller + +pci:v0000FFFE* + ID_VENDOR_FROM_DATABASE=VMWare Inc (temporary ID) + +pci:v0000FFFEd00000710* + ID_MODEL_FROM_DATABASE=Virtual SVGA + +pci:v0000FFFF* + ID_VENDOR_FROM_DATABASE=Illegal Vendor ID diff --git a/hwdb/20-sdio-classes.hwdb b/hwdb/20-sdio-classes.hwdb new file mode 100644 index 0000000..72cce9d --- /dev/null +++ b/hwdb/20-sdio-classes.hwdb @@ -0,0 +1,33 @@ +# This file is part of systemd. +# +# Data imported from: hwdb/sdio.ids + +sdio:c00v*d* + ID_SDIO_CLASS_FROM_DATABASE=Not a SDIO standard interface + +sdio:c01v*d* + ID_SDIO_CLASS_FROM_DATABASE=UART standard interface + +sdio:c02v*d* + ID_SDIO_CLASS_FROM_DATABASE=Bluetooth Type-A standard interface + +sdio:c03v*d* + ID_SDIO_CLASS_FROM_DATABASE=Bluetooth Type-B standard interface + +sdio:c04v*d* + ID_SDIO_CLASS_FROM_DATABASE=GPS standard interface + +sdio:c05v*d* + ID_SDIO_CLASS_FROM_DATABASE=Camera standard interface + +sdio:c06v*d* + ID_SDIO_CLASS_FROM_DATABASE=PHS standard interface + +sdio:c07v*d* + ID_SDIO_CLASS_FROM_DATABASE=WLAN interface + +sdio:c08v*d* + ID_SDIO_CLASS_FROM_DATABASE=Embedded SDIO-ATA standard interface + +sdio:c09v*d* + ID_SDIO_CLASS_FROM_DATABASE=Bluetooth AMP standard interface diff --git a/hwdb/20-sdio-vendor-model.hwdb b/hwdb/20-sdio-vendor-model.hwdb new file mode 100644 index 0000000..626d673 --- /dev/null +++ b/hwdb/20-sdio-vendor-model.hwdb @@ -0,0 +1,177 @@ +# This file is part of systemd. +# +# Data imported from: hwdb/sdio.ids + +sdio:c*v0020* + ID_VENDOR_FROM_DATABASE=ST-Ericsson + +sdio:c*v0020d2280* + ID_MODEL_FROM_DATABASE=CW1200 + +sdio:c*v0089* + ID_VENDOR_FROM_DATABASE=Intel Corp. + +sdio:c*v0092* + ID_VENDOR_FROM_DATABASE=C-guys, Inc. + +sdio:c*v0092d0001* + ID_MODEL_FROM_DATABASE=SD-Link11b WiFi Card (TI ACX100) + +sdio:c*v0092d0004* + ID_MODEL_FROM_DATABASE=EW-CG1102GC + +sdio:c*v0092d0005* + ID_MODEL_FROM_DATABASE=SD FM Radio 2 + +sdio:c*v0092d5544* + ID_MODEL_FROM_DATABASE=SD FM Radio + +sdio:c*v0097* + ID_VENDOR_FROM_DATABASE=Texas Instruments, Inc. + +sdio:c*v0097d4076* + ID_MODEL_FROM_DATABASE=WL1271 + +sdio:c*v0098* + ID_VENDOR_FROM_DATABASE=Toshiba Corp. + +sdio:c*v0098d0001* + ID_MODEL_FROM_DATABASE=SD BT Card 1 + +sdio:c*v0098d0002* + ID_MODEL_FROM_DATABASE=SD BT Card 2 + +sdio:c*v0098d0003* + ID_MODEL_FROM_DATABASE=SD BT Card 3 + +sdio:c*v0104* + ID_VENDOR_FROM_DATABASE=Socket Communications, Inc. + +sdio:c*v0104d005E* + ID_MODEL_FROM_DATABASE=SD Scanner + +sdio:c*v0104d00C5* + ID_MODEL_FROM_DATABASE=Bluetooth SDIO Card + +sdio:c*v0271* + ID_VENDOR_FROM_DATABASE=Atheros Communications, Inc. + +sdio:c*v0271d0108* + ID_MODEL_FROM_DATABASE=AR6001 + +sdio:c*v0271d0109* + ID_MODEL_FROM_DATABASE=AR6001 + +sdio:c*v0271d010A* + ID_MODEL_FROM_DATABASE=AR6001 + +sdio:c*v0271d010B* + ID_MODEL_FROM_DATABASE=AR6001 + +sdio:c*v0296* + ID_VENDOR_FROM_DATABASE=GCT Semiconductor, Inc. + +sdio:c*v0296d5347* + ID_MODEL_FROM_DATABASE=GDM72xx WiMAX + +sdio:c*v02D0* + ID_VENDOR_FROM_DATABASE=Broadcom Corp. + +sdio:c*v02D0d044B* + ID_MODEL_FROM_DATABASE=Nintendo Wii WLAN daughter card + +sdio:c*v02DB* + ID_VENDOR_FROM_DATABASE=SyChip Inc. + +sdio:c*v02DBd0002* + ID_MODEL_FROM_DATABASE=Pegasus WLAN SDIO Card (6060SD) + +sdio:c*v02DF* + ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. + +sdio:c*v02DFd9103* + ID_MODEL_FROM_DATABASE=Libertas + +sdio:c*v02DFd9104* + ID_MODEL_FROM_DATABASE=SD8688 WLAN + +sdio:c*v02DFd9105* + ID_MODEL_FROM_DATABASE=SD8688 BT + +sdio:c*v02DFd9116* + ID_MODEL_FROM_DATABASE=SD8786 WLAN + +sdio:c*v02DFd9119* + ID_MODEL_FROM_DATABASE=SD8787 WLAN + +sdio:c*v02DFd911A* + ID_MODEL_FROM_DATABASE=SD8787 BT + +sdio:c*v02DFd911B* + ID_MODEL_FROM_DATABASE=SD8787 BT AMP + +sdio:c*v02DFd9129* + ID_MODEL_FROM_DATABASE=SD8797 WLAN + +sdio:c*v02DFd912A* + ID_MODEL_FROM_DATABASE=SD8797 BT + +sdio:c*v02DFd912E* + ID_MODEL_FROM_DATABASE=SD8897 BT + +sdio:c*v02DFd912D* + ID_MODEL_FROM_DATABASE=SD8897 WLAN + +sdio:c*v02FE* + ID_VENDOR_FROM_DATABASE=Spectec Computer Co., Ltd + +sdio:c*v02FEd2128* + ID_MODEL_FROM_DATABASE=SDIO WLAN Card (SDW820) + +sdio:c*v032A* + ID_VENDOR_FROM_DATABASE=Cambridge Silicon Radio + +sdio:c*v032Ad0001* + ID_MODEL_FROM_DATABASE=UniFi 1 + +sdio:c*v032Ad0002* + ID_MODEL_FROM_DATABASE=UniFi 2 + +sdio:c*v032Ad0007* + ID_MODEL_FROM_DATABASE=UniFi 3 + +sdio:c*v032Ad0008* + ID_MODEL_FROM_DATABASE=UniFi 4 + +sdio:c*v037A* + ID_VENDOR_FROM_DATABASE=MediaTek Inc. + +sdio:c*v037Ad5911* + ID_MODEL_FROM_DATABASE=Spectec WLAN-11b/g + +sdio:c*v039A* + ID_VENDOR_FROM_DATABASE=Siano Mobile Silicon + +sdio:c*v0501* + ID_VENDOR_FROM_DATABASE=Globalsat Technology Co. + +sdio:c*v0501dF501* + ID_MODEL_FROM_DATABASE=SD-501 GPS Card + +sdio:c*v104C* + ID_VENDOR_FROM_DATABASE=Texas Instruments, Inc. + +sdio:c*v104Cd9066* + ID_MODEL_FROM_DATABASE=WL1251 + +sdio:c*v1180* + ID_VENDOR_FROM_DATABASE=Ricoh Co., Ltd + +sdio:c*v1180dE823* + ID_MODEL_FROM_DATABASE=MMC card reader + +sdio:c*v13D1* + ID_VENDOR_FROM_DATABASE=AboCom Systems, Inc. + +sdio:c*v13D1dAC02* + ID_MODEL_FROM_DATABASE=SDW11G diff --git a/hwdb/20-usb-classes.hwdb b/hwdb/20-usb-classes.hwdb new file mode 100644 index 0000000..3294d8a --- /dev/null +++ b/hwdb/20-usb-classes.hwdb @@ -0,0 +1,339 @@ +# This file is part of systemd. +# +# Data imported from: http://www.linux-usb.org/usb.ids + +usb:v*p*d*dc01* + ID_USB_CLASS_FROM_DATABASE=Audio + +usb:v*p*d*dc01dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Control Device + +usb:v*p*d*dc01dsc02* + ID_USB_SUBCLASS_FROM_DATABASE=Streaming + +usb:v*p*d*dc01dsc03* + ID_USB_SUBCLASS_FROM_DATABASE=MIDI Streaming + +usb:v*p*d*dc02* + ID_USB_CLASS_FROM_DATABASE=Communications + +usb:v*p*d*dc02dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Direct Line + +usb:v*p*d*dc02dsc02* + ID_USB_SUBCLASS_FROM_DATABASE=Abstract (modem) + +usb:v*p*d*dc02dsc02dp01* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (v.25ter) + +usb:v*p*d*dc02dsc02dp02* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (PCCA101) + +usb:v*p*d*dc02dsc02dp03* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (PCCA101 + wakeup) + +usb:v*p*d*dc02dsc02dp04* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (GSM) + +usb:v*p*d*dc02dsc02dp05* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (3G) + +usb:v*p*d*dc02dsc02dp06* + ID_USB_PROTOCOL_FROM_DATABASE=AT-commands (CDMA) + +usb:v*p*d*dc02dsc02dpFE* + ID_USB_PROTOCOL_FROM_DATABASE=Defined by command set descriptor + +usb:v*p*d*dc02dsc02dpFF* + ID_USB_PROTOCOL_FROM_DATABASE=Vendor Specific (MSFT RNDIS?) + +usb:v*p*d*dc02dsc03* + ID_USB_SUBCLASS_FROM_DATABASE=Telephone + +usb:v*p*d*dc02dsc04* + ID_USB_SUBCLASS_FROM_DATABASE=Multi-Channel + +usb:v*p*d*dc02dsc05* + ID_USB_SUBCLASS_FROM_DATABASE=CAPI Control + +usb:v*p*d*dc02dsc06* + ID_USB_SUBCLASS_FROM_DATABASE=Ethernet Networking + +usb:v*p*d*dc02dsc07* + ID_USB_SUBCLASS_FROM_DATABASE=ATM Networking + +usb:v*p*d*dc02dsc08* + ID_USB_SUBCLASS_FROM_DATABASE=Wireless Handset Control + +usb:v*p*d*dc02dsc09* + ID_USB_SUBCLASS_FROM_DATABASE=Device Management + +usb:v*p*d*dc02dsc0A* + ID_USB_SUBCLASS_FROM_DATABASE=Mobile Direct Line + +usb:v*p*d*dc02dsc0B* + ID_USB_SUBCLASS_FROM_DATABASE=OBEX + +usb:v*p*d*dc02dsc0C* + ID_USB_SUBCLASS_FROM_DATABASE=Ethernet Emulation + +usb:v*p*d*dc02dsc0Cdp07* + ID_USB_PROTOCOL_FROM_DATABASE=Ethernet Emulation (EEM) + +usb:v*p*d*dc03* + ID_USB_CLASS_FROM_DATABASE=Human Interface Device + +usb:v*p*d*dc03dsc00dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Keyboard + +usb:v*p*d*dc03dsc00dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Mouse + +usb:v*p*d*dc03dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Boot Interface Subclass + +usb:v*p*d*dc03dsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Keyboard + +usb:v*p*d*dc03dsc01dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Mouse + +usb:v*p*d*dc05* + ID_USB_CLASS_FROM_DATABASE=Physical Interface Device + +usb:v*p*d*dc06* + ID_USB_CLASS_FROM_DATABASE=Imaging + +usb:v*p*d*dc06dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Still Image Capture + +usb:v*p*d*dc06dsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Picture Transfer Protocol (PIMA 15470) + +usb:v*p*d*dc07* + ID_USB_CLASS_FROM_DATABASE=Printer + +usb:v*p*d*dc07dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Printer + +usb:v*p*d*dc07dsc01dp00* + ID_USB_PROTOCOL_FROM_DATABASE=Reserved/Undefined + +usb:v*p*d*dc07dsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Unidirectional + +usb:v*p*d*dc07dsc01dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Bidirectional + +usb:v*p*d*dc07dsc01dp03* + ID_USB_PROTOCOL_FROM_DATABASE=IEEE 1284.4 compatible bidirectional + +usb:v*p*d*dc07dsc01dpFF* + ID_USB_PROTOCOL_FROM_DATABASE=Vendor Specific + +usb:v*p*d*dc08* + ID_USB_CLASS_FROM_DATABASE=Mass Storage + +usb:v*p*d*dc08dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=RBC (typically Flash) + +usb:v*p*d*dc08dsc01dp00* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk/Interrupt + +usb:v*p*d*dc08dsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk + +usb:v*p*d*dc08dsc01dp50* + ID_USB_PROTOCOL_FROM_DATABASE=Bulk-Only + +usb:v*p*d*dc08dsc02* + ID_USB_SUBCLASS_FROM_DATABASE=SFF-8020i, MMC-2 (ATAPI) + +usb:v*p*d*dc08dsc03* + ID_USB_SUBCLASS_FROM_DATABASE=QIC-157 + +usb:v*p*d*dc08dsc04* + ID_USB_SUBCLASS_FROM_DATABASE=Floppy (UFI) + +usb:v*p*d*dc08dsc04dp00* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk/Interrupt + +usb:v*p*d*dc08dsc04dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk + +usb:v*p*d*dc08dsc04dp50* + ID_USB_PROTOCOL_FROM_DATABASE=Bulk-Only + +usb:v*p*d*dc08dsc05* + ID_USB_SUBCLASS_FROM_DATABASE=SFF-8070i + +usb:v*p*d*dc08dsc06* + ID_USB_SUBCLASS_FROM_DATABASE=SCSI + +usb:v*p*d*dc08dsc06dp00* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk/Interrupt + +usb:v*p*d*dc08dsc06dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Control/Bulk + +usb:v*p*d*dc08dsc06dp50* + ID_USB_PROTOCOL_FROM_DATABASE=Bulk-Only + +usb:v*p*d*dc09* + ID_USB_CLASS_FROM_DATABASE=Hub + +usb:v*p*d*dc09dsc00dp00* + ID_USB_PROTOCOL_FROM_DATABASE=Full speed (or root) hub + +usb:v*p*d*dc09dsc00dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Single TT + +usb:v*p*d*dc09dsc00dp02* + ID_USB_PROTOCOL_FROM_DATABASE=TT per port + +usb:v*p*d*dc0A* + ID_USB_CLASS_FROM_DATABASE=CDC Data + +usb:v*p*d*dc0Adsc00dp30* + ID_USB_PROTOCOL_FROM_DATABASE=I.430 ISDN BRI + +usb:v*p*d*dc0Adsc00dp31* + ID_USB_PROTOCOL_FROM_DATABASE=HDLC + +usb:v*p*d*dc0Adsc00dp32* + ID_USB_PROTOCOL_FROM_DATABASE=Transparent + +usb:v*p*d*dc0Adsc00dp50* + ID_USB_PROTOCOL_FROM_DATABASE=Q.921M + +usb:v*p*d*dc0Adsc00dp51* + ID_USB_PROTOCOL_FROM_DATABASE=Q.921 + +usb:v*p*d*dc0Adsc00dp52* + ID_USB_PROTOCOL_FROM_DATABASE=Q.921TM + +usb:v*p*d*dc0Adsc00dp90* + ID_USB_PROTOCOL_FROM_DATABASE=V.42bis + +usb:v*p*d*dc0Adsc00dp91* + ID_USB_PROTOCOL_FROM_DATABASE=Q.932 EuroISDN + +usb:v*p*d*dc0Adsc00dp92* + ID_USB_PROTOCOL_FROM_DATABASE=V.120 V.24 rate ISDN + +usb:v*p*d*dc0Adsc00dp93* + ID_USB_PROTOCOL_FROM_DATABASE=CAPI 2.0 + +usb:v*p*d*dc0Adsc00dpFD* + ID_USB_PROTOCOL_FROM_DATABASE=Host Based Driver + +usb:v*p*d*dc0Adsc00dpFE* + ID_USB_PROTOCOL_FROM_DATABASE=CDC PUF + +usb:v*p*d*dc0Adsc00dpFF* + ID_USB_PROTOCOL_FROM_DATABASE=Vendor specific + +usb:v*p*d*dc0B* + ID_USB_CLASS_FROM_DATABASE=Chip/SmartCard + +usb:v*p*d*dc0D* + ID_USB_CLASS_FROM_DATABASE=Content Security + +usb:v*p*d*dc0E* + ID_USB_CLASS_FROM_DATABASE=Video + +usb:v*p*d*dc0Edsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Video Control + +usb:v*p*d*dc0Edsc02* + ID_USB_SUBCLASS_FROM_DATABASE=Video Streaming + +usb:v*p*d*dc0Edsc03* + ID_USB_SUBCLASS_FROM_DATABASE=Video Interface Collection + +usb:v*p*d*dc58* + ID_USB_CLASS_FROM_DATABASE=Xbox + +usb:v*p*d*dc58dsc42* + ID_USB_SUBCLASS_FROM_DATABASE=Controller + +usb:v*p*d*dcDC* + ID_USB_CLASS_FROM_DATABASE=Diagnostic + +usb:v*p*d*dcDCdsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Reprogrammable Diagnostics + +usb:v*p*d*dcDCdsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=USB2 Compliance + +usb:v*p*d*dcE0* + ID_USB_CLASS_FROM_DATABASE=Wireless + +usb:v*p*d*dcE0dsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Radio Frequency + +usb:v*p*d*dcE0dsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Bluetooth + +usb:v*p*d*dcE0dsc01dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Ultra WideBand Radio Control + +usb:v*p*d*dcE0dsc01dp03* + ID_USB_PROTOCOL_FROM_DATABASE=RNDIS + +usb:v*p*d*dcE0dsc02* + ID_USB_SUBCLASS_FROM_DATABASE=Wireless USB Wire Adapter + +usb:v*p*d*dcE0dsc02dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Host Wire Adapter Control/Data Streaming + +usb:v*p*d*dcE0dsc02dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Device Wire Adapter Control/Data Streaming + +usb:v*p*d*dcE0dsc02dp03* + ID_USB_PROTOCOL_FROM_DATABASE=Device Wire Adapter Isochronous Streaming + +usb:v*p*d*dcEF* + ID_USB_CLASS_FROM_DATABASE=Miscellaneous Device + +usb:v*p*d*dcEFdsc01dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Microsoft ActiveSync + +usb:v*p*d*dcEFdsc01dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Palm Sync + +usb:v*p*d*dcEFdsc02dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Interface Association + +usb:v*p*d*dcEFdsc02dp02* + ID_USB_PROTOCOL_FROM_DATABASE=Wire Adapter Multifunction Peripheral + +usb:v*p*d*dcEFdsc03dp01* + ID_USB_PROTOCOL_FROM_DATABASE=Cable Based Association + +usb:v*p*d*dcFE* + ID_USB_CLASS_FROM_DATABASE=Application Specific Interface + +usb:v*p*d*dcFEdsc01* + ID_USB_SUBCLASS_FROM_DATABASE=Device Firmware Update + +usb:v*p*d*dcFEdsc02* + ID_USB_SUBCLASS_FROM_DATABASE=IRDA Bridge + +usb:v*p*d*dcFEdsc03* + ID_USB_SUBCLASS_FROM_DATABASE=Test and Measurement + +usb:v*p*d*dcFEdsc03dp01* + ID_USB_PROTOCOL_FROM_DATABASE=TMC + +usb:v*p*d*dcFEdsc03dp02* + ID_USB_PROTOCOL_FROM_DATABASE=USB488 + +usb:v*p*d*dcFF* + ID_USB_CLASS_FROM_DATABASE=Vendor Specific Class + +usb:v*p*d*dcFFdscFF* + ID_USB_SUBCLASS_FROM_DATABASE=Vendor Specific Subclass + +usb:v*p*d*dcFFdscFFdpFF* + ID_USB_PROTOCOL_FROM_DATABASE=Vendor Specific Protocol diff --git a/hwdb/20-usb-vendor-model.hwdb b/hwdb/20-usb-vendor-model.hwdb new file mode 100644 index 0000000..60dbcd2 --- /dev/null +++ b/hwdb/20-usb-vendor-model.hwdb @@ -0,0 +1,49953 @@ +# This file is part of systemd. +# +# Data imported from: http://www.linux-usb.org/usb.ids + +usb:v0001* + ID_VENDOR_FROM_DATABASE=Fry's Electronics + +usb:v0001p142B* + ID_MODEL_FROM_DATABASE=Arbiter Systems, Inc. + +usb:v0001p7778* + ID_MODEL_FROM_DATABASE=Counterfeit flash drive [Kingston] + +usb:v0002* + ID_VENDOR_FROM_DATABASE=Ingram + +usb:v0003* + ID_VENDOR_FROM_DATABASE=Club Mac + +usb:v0004* + ID_VENDOR_FROM_DATABASE=Nebraska Furniture Mart + +usb:v0053* + ID_VENDOR_FROM_DATABASE=Planex + +usb:v0053p5301* + ID_MODEL_FROM_DATABASE=GW-US54ZGL 802.11bg + +usb:v0079* + ID_VENDOR_FROM_DATABASE=DragonRise Inc. + +usb:v0079p0006* + ID_MODEL_FROM_DATABASE=Generic USB Joystick + +usb:v0079p0011* + ID_MODEL_FROM_DATABASE=Gamepad + +usb:v0105* + ID_VENDOR_FROM_DATABASE=Trust International B.V. + +usb:v0105p145F* + ID_MODEL_FROM_DATABASE=NW-3100 802.11b/g 54Mbps Wireless Network Adapter [zd1211] + +usb:v0145* + ID_VENDOR_FROM_DATABASE=Unknown + +usb:v0145p0112* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v017C* + ID_VENDOR_FROM_DATABASE=MLK + +usb:v017Cp145F* + ID_MODEL_FROM_DATABASE=Trust Deskset + +usb:v0200* + ID_VENDOR_FROM_DATABASE=TP-Link + +usb:v0200p0201* + ID_MODEL_FROM_DATABASE=MA180 UMTS Modem + +usb:v0204* + ID_VENDOR_FROM_DATABASE=Chipsbank Microelectronics Co., Ltd + +usb:v0204p6025* + ID_MODEL_FROM_DATABASE=CBM2080 Flash drive controller + +usb:v0204p6026* + ID_MODEL_FROM_DATABASE=CBM1180 Flash drive controller + +usb:v0218* + ID_VENDOR_FROM_DATABASE=Hangzhou Worlde + +usb:v0218p0301* + ID_MODEL_FROM_DATABASE=MIDI Port + +usb:v02AD* + ID_VENDOR_FROM_DATABASE=HUMAX Co., Ltd. + +usb:v02ADp138C* + ID_MODEL_FROM_DATABASE=PVR Mass Storage + +usb:v0300* + ID_VENDOR_FROM_DATABASE=MM300 eBook Reader + +usb:v0324* + ID_VENDOR_FROM_DATABASE=OCZ Technology Inc + +usb:v0324pBC06* + ID_MODEL_FROM_DATABASE=OCZ ATV USB 2.0 Flash Drive + +usb:v0324pBC08* + ID_MODEL_FROM_DATABASE=OCZ Rally2/ATV USB 2.0 Flash Drive + +usb:v0325* + ID_VENDOR_FROM_DATABASE=OCZ Technology Inc + +usb:v0325pAC02* + ID_MODEL_FROM_DATABASE=ATV Turbo / Rally2 Dual Channel USB 2.0 Flash Drive + +usb:v0386* + ID_VENDOR_FROM_DATABASE=LTS + +usb:v0386p0001* + ID_MODEL_FROM_DATABASE=PSX for USB Converter + +usb:v03D9* + ID_VENDOR_FROM_DATABASE=Shenzhen Sinote Tech-Electron Co., Ltd + +usb:v03D9p0499* + ID_MODEL_FROM_DATABASE=SE340D PC Remote Control + +usb:v03DA* + ID_VENDOR_FROM_DATABASE=Bernd Walter Computer Technology + +usb:v03DAp0002* + ID_MODEL_FROM_DATABASE=HD44780 LCD interface + +usb:v03E8* + ID_VENDOR_FROM_DATABASE=EndPoints, Inc. + +usb:v03E8p0004* + ID_MODEL_FROM_DATABASE=SE401 Webcam + +usb:v03E8p0008* + ID_MODEL_FROM_DATABASE=101 Ethernet [klsi] + +usb:v03E8p0015* + ID_MODEL_FROM_DATABASE=ATAPI Enclosure + +usb:v03E8p2123* + ID_MODEL_FROM_DATABASE=SiPix StyleCam Deluxe + +usb:v03E8p8004* + ID_MODEL_FROM_DATABASE=Aox 99001 + +usb:v03E9* + ID_VENDOR_FROM_DATABASE=Thesys Microelectronics + +usb:v03EA* + ID_VENDOR_FROM_DATABASE=Data Broadcasting Corp. + +usb:v03EB* + ID_VENDOR_FROM_DATABASE=Atmel Corp. + +usb:v03EBp0902* + ID_MODEL_FROM_DATABASE=4-Port Hub + +usb:v03EBp2002* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v03EBp2015* + ID_MODEL_FROM_DATABASE=at90usbkey sample firmware (HID keyboard) + +usb:v03EBp2018* + ID_MODEL_FROM_DATABASE=at90usbkey sample firmware (CDC ACM) + +usb:v03EBp2019* + ID_MODEL_FROM_DATABASE=stk525 sample firmware (microphone) + +usb:v03EBp201C* + ID_MODEL_FROM_DATABASE=at90usbkey sample firmware (HID mouse) + +usb:v03EBp201D* + ID_MODEL_FROM_DATABASE=at90usbkey sample firmware (HID generic) + +usb:v03EBp2022* + ID_MODEL_FROM_DATABASE=at90usbkey sample firmware (composite device) + +usb:v03EBp2040* + ID_MODEL_FROM_DATABASE=LUFA Test PID + +usb:v03EBp2041* + ID_MODEL_FROM_DATABASE=LUFA Mouse Demo Application + +usb:v03EBp2042* + ID_MODEL_FROM_DATABASE=LUFA Keyboard Demo Application + +usb:v03EBp2043* + ID_MODEL_FROM_DATABASE=LUFA Joystick Demo Application + +usb:v03EBp2044* + ID_MODEL_FROM_DATABASE=LUFA CDC Demo Application + +usb:v03EBp2045* + ID_MODEL_FROM_DATABASE=LUFA Mass Storage Demo Application + +usb:v03EBp2046* + ID_MODEL_FROM_DATABASE=LUFA Audio Output Demo Application + +usb:v03EBp2047* + ID_MODEL_FROM_DATABASE=LUFA Audio Input Demo Application + +usb:v03EBp2048* + ID_MODEL_FROM_DATABASE=LUFA MIDI Demo Application + +usb:v03EBp2049* + ID_MODEL_FROM_DATABASE=Stripe Snoop Magnetic Stripe Reader + +usb:v03EBp204A* + ID_MODEL_FROM_DATABASE=LUFA CDC Class Bootloader + +usb:v03EBp204B* + ID_MODEL_FROM_DATABASE=LUFA USB to Serial Adapter Project + +usb:v03EBp204C* + ID_MODEL_FROM_DATABASE=LUFA RNDIS Demo Application + +usb:v03EBp204D* + ID_MODEL_FROM_DATABASE=LUFA Combined Mouse and Keyboard Demo Application + +usb:v03EBp204E* + ID_MODEL_FROM_DATABASE=LUFA Dual CDC Demo Application + +usb:v03EBp204F* + ID_MODEL_FROM_DATABASE=LUFA Generic HID Demo Application + +usb:v03EBp2060* + ID_MODEL_FROM_DATABASE=Benito Programmer Project + +usb:v03EBp2061* + ID_MODEL_FROM_DATABASE=LUFA Combined Mass Storage and Keyboard Demo Application + +usb:v03EBp2062* + ID_MODEL_FROM_DATABASE=LUFA Combined CDC and Mouse Demo Application + +usb:v03EBp2063* + ID_MODEL_FROM_DATABASE=LUFA Datalogger Device + +usb:v03EBp2064* + ID_MODEL_FROM_DATABASE=Interfaceless Control-Only LUFA Devices + +usb:v03EBp2065* + ID_MODEL_FROM_DATABASE=LUFA Test and Measurement Demo Application + +usb:v03EBp2066* + ID_MODEL_FROM_DATABASE=LUFA Multiple Report HID Demo + +usb:v03EBp2068* + ID_MODEL_FROM_DATABASE=LUFA Virtual Serial/Mass Storage Demo + +usb:v03EBp2069* + ID_MODEL_FROM_DATABASE=LUFA Webserver Project + +usb:v03EBp2103* + ID_MODEL_FROM_DATABASE=JTAG ICE mkII + +usb:v03EBp2104* + ID_MODEL_FROM_DATABASE=AVR ISP mkII + +usb:v03EBp2105* + ID_MODEL_FROM_DATABASE=AVRONE! + +usb:v03EBp2106* + ID_MODEL_FROM_DATABASE=STK600 development board + +usb:v03EBp2107* + ID_MODEL_FROM_DATABASE=AVR Dragon + +usb:v03EBp2109* + ID_MODEL_FROM_DATABASE=STK541 ZigBee Development Board + +usb:v03EBp210D* + ID_MODEL_FROM_DATABASE=XPLAIN evaluation kit (CDC ACM) + +usb:v03EBp2122* + ID_MODEL_FROM_DATABASE=XMEGA-A1 Explained evaluation kit + +usb:v03EBp2310* + ID_MODEL_FROM_DATABASE=EVK11xx evaluation board + +usb:v03EBp2FE4* + ID_MODEL_FROM_DATABASE=ATxmega32A4U DFU bootloader + +usb:v03EBp2FF0* + ID_MODEL_FROM_DATABASE=atmega32u2 DFU bootloader + +usb:v03EBp2FFA* + ID_MODEL_FROM_DATABASE=at90usb162 DFU bootloader + +usb:v03EBp2FFB* + ID_MODEL_FROM_DATABASE=at90usb AVR DFU bootloader + +usb:v03EBp2FFD* + ID_MODEL_FROM_DATABASE=at89c5130/c5131 DFU bootloader + +usb:v03EBp2FFF* + ID_MODEL_FROM_DATABASE=at89c5132/c51snd1c DFU bootloader + +usb:v03EBp3301* + ID_MODEL_FROM_DATABASE=at43301 4-Port Hub + +usb:v03EBp3312* + ID_MODEL_FROM_DATABASE=4-Port Hub + +usb:v03EBp4102* + ID_MODEL_FROM_DATABASE=AirVast W-Buddie WN210 + +usb:v03EBp5601* + ID_MODEL_FROM_DATABASE=at76c510 Prism-II 802.11b Access Point + +usb:v03EBp5603* + ID_MODEL_FROM_DATABASE=Cisco 7920 WiFi IP Phone + +usb:v03EBp6119* + ID_MODEL_FROM_DATABASE=AT91SAM CDC Demo Application + +usb:v03EBp6124* + ID_MODEL_FROM_DATABASE=at91sam SAMBA bootloader + +usb:v03EBp6127* + ID_MODEL_FROM_DATABASE=AT91SAM HID Keyboard Demo Application + +usb:v03EBp6129* + ID_MODEL_FROM_DATABASE=AT91SAM Mass Storage Demo Application + +usb:v03EBp6200* + ID_MODEL_FROM_DATABASE=AT91SAM HID Mouse Demo Application + +usb:v03EBp7603* + ID_MODEL_FROM_DATABASE=D-Link DWL-120 802.11b Wireless Adapter [Atmel at76c503a] + +usb:v03EBp7604* + ID_MODEL_FROM_DATABASE=at76c503a 802.11b Adapter + +usb:v03EBp7605* + ID_MODEL_FROM_DATABASE=at76c503a 802.11b Adapter + +usb:v03EBp7606* + ID_MODEL_FROM_DATABASE=at76c505 802.11b Adapter + +usb:v03EBp7611* + ID_MODEL_FROM_DATABASE=at76c510 rfmd2948 802.11b Access Point + +usb:v03EBp7613* + ID_MODEL_FROM_DATABASE=WL-1130 USB + +usb:v03EBp7614* + ID_MODEL_FROM_DATABASE=AT76c505a Wireless Adapter + +usb:v03EBp7615* + ID_MODEL_FROM_DATABASE=AT76C505AMX Wireless Adapter + +usb:v03EBp7617* + ID_MODEL_FROM_DATABASE=AT76C505AS Wireless Adapter + +usb:v03EBp7800* + ID_MODEL_FROM_DATABASE=Mini Album + +usb:v03EBpFF07* + ID_MODEL_FROM_DATABASE=Tux Droid fish dongle + +usb:v03EC* + ID_VENDOR_FROM_DATABASE=Iwatsu America, Inc. + +usb:v03ED* + ID_VENDOR_FROM_DATABASE=Mitel Corp. + +usb:v03EE* + ID_VENDOR_FROM_DATABASE=Mitsumi + +usb:v03EEp0000* + ID_MODEL_FROM_DATABASE=CD-R/RW Drive + +usb:v03EEp2501* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v03EEp2502* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v03EEp5609* + ID_MODEL_FROM_DATABASE=Japanese Keyboard + +usb:v03EEp641F* + ID_MODEL_FROM_DATABASE=WIF-0402C Bluetooth Adapter + +usb:v03EEp6438* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v03EEp6440* + ID_MODEL_FROM_DATABASE=WML-C52APR Bluetooth Adapter + +usb:v03EEp6901* + ID_MODEL_FROM_DATABASE=SmartDisk FDD + +usb:v03EEp6902* + ID_MODEL_FROM_DATABASE=Floppy Disk Drive + +usb:v03EEp7500* + ID_MODEL_FROM_DATABASE=CD-R/RW + +usb:v03EEpFFFF* + ID_MODEL_FROM_DATABASE=Dongle with BlueCore in DFU mode + +usb:v03F0* + ID_VENDOR_FROM_DATABASE=Hewlett-Packard + +usb:v03F0p0004* + ID_MODEL_FROM_DATABASE=DeskJet 895c + +usb:v03F0p0011* + ID_MODEL_FROM_DATABASE=OfficeJet G55 + +usb:v03F0p0012* + ID_MODEL_FROM_DATABASE=DeskJet 1125C Printer Port + +usb:v03F0p0024* + ID_MODEL_FROM_DATABASE=KU-0316 Keyboard + +usb:v03F0p002A* + ID_MODEL_FROM_DATABASE=LaserJet P1102 + +usb:v03F0p0101* + ID_MODEL_FROM_DATABASE=ScanJet 4100c + +usb:v03F0p0102* + ID_MODEL_FROM_DATABASE=PhotoSmart S20 + +usb:v03F0p0104* + ID_MODEL_FROM_DATABASE=DeskJet 880c/970c + +usb:v03F0p0105* + ID_MODEL_FROM_DATABASE=ScanJet 4200c + +usb:v03F0p0107* + ID_MODEL_FROM_DATABASE=CD-Writer Plus + +usb:v03F0p010C* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard Hub + +usb:v03F0p0111* + ID_MODEL_FROM_DATABASE=G55xi Printer/Scanner/Copier + +usb:v03F0p0117* + ID_MODEL_FROM_DATABASE=LaserJet 3200 + +usb:v03F0p011C* + ID_MODEL_FROM_DATABASE=hn210w 802.11b Adapter + +usb:v03F0p011D* + ID_MODEL_FROM_DATABASE=Bluetooth 1.2 Interface [Broadcom BCM2035] + +usb:v03F0p0121* + ID_MODEL_FROM_DATABASE=HP49g+ Calculator + +usb:v03F0p0122* + ID_MODEL_FROM_DATABASE=HID Internet Keyboard + +usb:v03F0p0201* + ID_MODEL_FROM_DATABASE=ScanJet 6200c + +usb:v03F0p0202* + ID_MODEL_FROM_DATABASE=PhotoSmart S20 + +usb:v03F0p0204* + ID_MODEL_FROM_DATABASE=DeskJet 815c + +usb:v03F0p0205* + ID_MODEL_FROM_DATABASE=ScanJet 3300c + +usb:v03F0p0207* + ID_MODEL_FROM_DATABASE=CD-Writer Plus 8200e + +usb:v03F0p020C* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard + +usb:v03F0p0211* + ID_MODEL_FROM_DATABASE=OfficeJet G85 + +usb:v03F0p0212* + ID_MODEL_FROM_DATABASE=DeskJet 1220C + +usb:v03F0p0217* + ID_MODEL_FROM_DATABASE=LaserJet 2200 + +usb:v03F0p0218* + ID_MODEL_FROM_DATABASE=APOLLO P2500/2600 + +usb:v03F0p0304* + ID_MODEL_FROM_DATABASE=DeskJet 810c/812c + +usb:v03F0p0305* + ID_MODEL_FROM_DATABASE=ScanJet 4300c + +usb:v03F0p0307* + ID_MODEL_FROM_DATABASE=CD-Writer+ CD-4e + +usb:v03F0p0311* + ID_MODEL_FROM_DATABASE=OfficeJet G85xi + +usb:v03F0p0312* + ID_MODEL_FROM_DATABASE=Color Inkjet CP1700 + +usb:v03F0p0314* + ID_MODEL_FROM_DATABASE=designjet 30/130 series + +usb:v03F0p0317* + ID_MODEL_FROM_DATABASE=LaserJet 1200 + +usb:v03F0p0324* + ID_MODEL_FROM_DATABASE=SK-2885 keyboard + +usb:v03F0p0401* + ID_MODEL_FROM_DATABASE=ScanJet 5200c + +usb:v03F0p0404* + ID_MODEL_FROM_DATABASE=DeskJet 830c/832c + +usb:v03F0p0405* + ID_MODEL_FROM_DATABASE=ScanJet 3400cse + +usb:v03F0p0411* + ID_MODEL_FROM_DATABASE=OfficeJet G95 + +usb:v03F0p0412* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p0417* + ID_MODEL_FROM_DATABASE=LaserJet 1200 series + +usb:v03F0p0423* + ID_MODEL_FROM_DATABASE=HS-COMBO Cardreader + +usb:v03F0p042A* + ID_MODEL_FROM_DATABASE=LaserJet M1132 MFP + +usb:v03F0p0441* + ID_MODEL_FROM_DATABASE=HP Prime Calculator + +usb:v03F0p0504* + ID_MODEL_FROM_DATABASE=DeskJet 885c + +usb:v03F0p0505* + ID_MODEL_FROM_DATABASE=ScanJet 2100c + +usb:v03F0p0507* + ID_MODEL_FROM_DATABASE=DVD+RW + +usb:v03F0p050C* + ID_MODEL_FROM_DATABASE=5219 Wireless Keyboard + +usb:v03F0p0511* + ID_MODEL_FROM_DATABASE=OfficeJet K60 + +usb:v03F0p0512* + ID_MODEL_FROM_DATABASE=DeckJet 450 + +usb:v03F0p0517* + ID_MODEL_FROM_DATABASE=LaserJet 1000 + +usb:v03F0p051D* + ID_MODEL_FROM_DATABASE=Bluetooth Interface + +usb:v03F0p0601* + ID_MODEL_FROM_DATABASE=ScanJet 6300c + +usb:v03F0p0604* + ID_MODEL_FROM_DATABASE=DeskJet 840c + +usb:v03F0p0605* + ID_MODEL_FROM_DATABASE=ScanJet 2200c + +usb:v03F0p0611* + ID_MODEL_FROM_DATABASE=OfficeJet K60xi + +usb:v03F0p0612* + ID_MODEL_FROM_DATABASE=business inkjet 3000 + +usb:v03F0p0624* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v03F0p0701* + ID_MODEL_FROM_DATABASE=ScanJet 5300c/5370c + +usb:v03F0p0704* + ID_MODEL_FROM_DATABASE=DeskJet 825c + +usb:v03F0p0705* + ID_MODEL_FROM_DATABASE=ScanJet 4400c + +usb:v03F0p0711* + ID_MODEL_FROM_DATABASE=OfficeJet K80 + +usb:v03F0p0712* + ID_MODEL_FROM_DATABASE=DeskJet 1180c + +usb:v03F0p0714* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p0801* + ID_MODEL_FROM_DATABASE=ScanJet 7400c + +usb:v03F0p0804* + ID_MODEL_FROM_DATABASE=DeskJet 816c + +usb:v03F0p0805* + ID_MODEL_FROM_DATABASE=HP4470C + +usb:v03F0p0811* + ID_MODEL_FROM_DATABASE=OfficeJet K80xi + +usb:v03F0p0817* + ID_MODEL_FROM_DATABASE=LaserJet 3300 + +usb:v03F0p0901* + ID_MODEL_FROM_DATABASE=ScanJet 2300c + +usb:v03F0p0904* + ID_MODEL_FROM_DATABASE=DeskJet 845c + +usb:v03F0p0912* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p0917* + ID_MODEL_FROM_DATABASE=LaserJet 3330 + +usb:v03F0p0924* + ID_MODEL_FROM_DATABASE=Modular Smartcard Keyboard + +usb:v03F0p094A* + ID_MODEL_FROM_DATABASE=Optical Mouse [672662-001] + +usb:v03F0p0A01* + ID_MODEL_FROM_DATABASE=ScanJet 2400c + +usb:v03F0p0A17* + ID_MODEL_FROM_DATABASE=color LaserJet 3700 + +usb:v03F0p0B01* + ID_MODEL_FROM_DATABASE=ScanJet 82x0C + +usb:v03F0p0B0C* + ID_MODEL_FROM_DATABASE=Wireless Keyboard and Optical Mouse receiver + +usb:v03F0p0B17* + ID_MODEL_FROM_DATABASE=LaserJet 2300d + +usb:v03F0p0C17* + ID_MODEL_FROM_DATABASE=LaserJet 1010 + +usb:v03F0p0C24* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v03F0p0D12* + ID_MODEL_FROM_DATABASE=OfficeJet 9100 series + +usb:v03F0p0D17* + ID_MODEL_FROM_DATABASE=LaserJet 1012 + +usb:v03F0p0E17* + ID_MODEL_FROM_DATABASE=LaserJet 1015 + +usb:v03F0p0F0C* + ID_MODEL_FROM_DATABASE=Wireless Keyboard and Optical Mouse receiver + +usb:v03F0p0F11* + ID_MODEL_FROM_DATABASE=OfficeJet V40 + +usb:v03F0p0F12* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p0F17* + ID_MODEL_FROM_DATABASE=LaserJet 1150 + +usb:v03F0p1001* + ID_MODEL_FROM_DATABASE=Photo Scanner 1000 + +usb:v03F0p1002* + ID_MODEL_FROM_DATABASE=PhotoSmart 140 series + +usb:v03F0p1004* + ID_MODEL_FROM_DATABASE=DeskJet 970c/970cse + +usb:v03F0p1005* + ID_MODEL_FROM_DATABASE=ScanJet 5400c + +usb:v03F0p1011* + ID_MODEL_FROM_DATABASE=OfficeJet V40xi + +usb:v03F0p1016* + ID_MODEL_FROM_DATABASE=Jornada 548 / iPAQ HW6515 Pocket PC + +usb:v03F0p1017* + ID_MODEL_FROM_DATABASE=LaserJet 1300 + +usb:v03F0p1024* + ID_MODEL_FROM_DATABASE=Smart Card Keyboard + +usb:v03F0p1027* + ID_MODEL_FROM_DATABASE=Virtual keyboard and mouse + +usb:v03F0p1102* + ID_MODEL_FROM_DATABASE=PhotoSmart 240 series + +usb:v03F0p1104* + ID_MODEL_FROM_DATABASE=DeskJet 959c + +usb:v03F0p1105* + ID_MODEL_FROM_DATABASE=ScanJet 5470c/5490c + +usb:v03F0p1111* + ID_MODEL_FROM_DATABASE=OfficeJet v60 + +usb:v03F0p1116* + ID_MODEL_FROM_DATABASE=Jornada 568 Pocket PC + +usb:v03F0p1117* + ID_MODEL_FROM_DATABASE=LaserJet 1300n + +usb:v03F0p1151* + ID_MODEL_FROM_DATABASE=PSC-750xi Printer/Scanner/Copier + +usb:v03F0p1202* + ID_MODEL_FROM_DATABASE=PhotoSmart 320 series + +usb:v03F0p1204* + ID_MODEL_FROM_DATABASE=DeskJet 930c + +usb:v03F0p1205* + ID_MODEL_FROM_DATABASE=ScanJet 4500C/5550C + +usb:v03F0p1211* + ID_MODEL_FROM_DATABASE=OfficeJet v60xi + +usb:v03F0p1217* + ID_MODEL_FROM_DATABASE=LaserJet 2300L + +usb:v03F0p1302* + ID_MODEL_FROM_DATABASE=PhotoSmart 370 series + +usb:v03F0p1305* + ID_MODEL_FROM_DATABASE=ScanJet 4570c + +usb:v03F0p1311* + ID_MODEL_FROM_DATABASE=OfficeJet V30 + +usb:v03F0p1312* + ID_MODEL_FROM_DATABASE=DeskJet 460 + +usb:v03F0p1317* + ID_MODEL_FROM_DATABASE=LaserJet 1005 + +usb:v03F0p1327* + ID_MODEL_FROM_DATABASE=iLO Virtual Hub + +usb:v03F0p1405* + ID_MODEL_FROM_DATABASE=ScanJet 3670 + +usb:v03F0p1411* + ID_MODEL_FROM_DATABASE=PSC 750 + +usb:v03F0p1424* + ID_MODEL_FROM_DATABASE=f2105 Monitor Hub + +usb:v03F0p1502* + ID_MODEL_FROM_DATABASE=PhotoSmart 420 series + +usb:v03F0p1504* + ID_MODEL_FROM_DATABASE=DeskJet 920c + +usb:v03F0p150C* + ID_MODEL_FROM_DATABASE=Mood Lighting (Microchip Technology Inc.) + +usb:v03F0p1511* + ID_MODEL_FROM_DATABASE=PSC 750xi + +usb:v03F0p1512* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p1517* + ID_MODEL_FROM_DATABASE=color LaserJet 3500 + +usb:v03F0p1524* + ID_MODEL_FROM_DATABASE=Smart Card Keyboard - KR + +usb:v03F0p1602* + ID_MODEL_FROM_DATABASE=PhotoSmart 330 series + +usb:v03F0p1604* + ID_MODEL_FROM_DATABASE=DeskJet 940c + +usb:v03F0p1605* + ID_MODEL_FROM_DATABASE=ScanJet 5530C PhotoSmart + +usb:v03F0p1611* + ID_MODEL_FROM_DATABASE=psc 780 + +usb:v03F0p1617* + ID_MODEL_FROM_DATABASE=LaserJet 3015 + +usb:v03F0p161D* + ID_MODEL_FROM_DATABASE=Wireless Rechargeable Optical Mouse (HID) + +usb:v03F0p1624* + ID_MODEL_FROM_DATABASE=Smart Card Keyboard - JP + +usb:v03F0p1702* + ID_MODEL_FROM_DATABASE=PhotoSmart 380 series + +usb:v03F0p1704* + ID_MODEL_FROM_DATABASE=DeskJet 948C + +usb:v03F0p1705* + ID_MODEL_FROM_DATABASE=ScanJet 5590 + +usb:v03F0p1711* + ID_MODEL_FROM_DATABASE=psc 780xi + +usb:v03F0p1712* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p1717* + ID_MODEL_FROM_DATABASE=LaserJet 3020 + +usb:v03F0p171D* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 Interface [Broadcom BCM2045] + +usb:v03F0p1801* + ID_MODEL_FROM_DATABASE=Inkjet P-2000U + +usb:v03F0p1802* + ID_MODEL_FROM_DATABASE=PhotoSmart 470 series + +usb:v03F0p1804* + ID_MODEL_FROM_DATABASE=DeskJet 916C + +usb:v03F0p1805* + ID_MODEL_FROM_DATABASE=ScanJet 7650 + +usb:v03F0p1811* + ID_MODEL_FROM_DATABASE=PSC 720 + +usb:v03F0p1812* + ID_MODEL_FROM_DATABASE=OfficeJet Pro K550 + +usb:v03F0p1817* + ID_MODEL_FROM_DATABASE=LaserJet 3030 + +usb:v03F0p181D* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 Interface + +usb:v03F0p1902* + ID_MODEL_FROM_DATABASE=PhotoSmart A430 series + +usb:v03F0p1904* + ID_MODEL_FROM_DATABASE=DeskJet 3820 + +usb:v03F0p1911* + ID_MODEL_FROM_DATABASE=OfficeJet V45 + +usb:v03F0p1917* + ID_MODEL_FROM_DATABASE=LaserJet 3380 + +usb:v03F0p1A02* + ID_MODEL_FROM_DATABASE=PhotoSmart A510 series + +usb:v03F0p1A11* + ID_MODEL_FROM_DATABASE=OfficeJet 5100 series + +usb:v03F0p1A17* + ID_MODEL_FROM_DATABASE=color LaserJet 4650 + +usb:v03F0p1B02* + ID_MODEL_FROM_DATABASE=PhotoSmart A610 series + +usb:v03F0p1B04* + ID_MODEL_FROM_DATABASE=DeskJet 3810 + +usb:v03F0p1B05* + ID_MODEL_FROM_DATABASE=ScanJet 4850C/4890C + +usb:v03F0p1B07* + ID_MODEL_FROM_DATABASE=Premium Starter Webcam + +usb:v03F0p1C02* + ID_MODEL_FROM_DATABASE=PhotoSmart A710 series + +usb:v03F0p1C17* + ID_MODEL_FROM_DATABASE=Color LaserJet 2550l + +usb:v03F0p1D02* + ID_MODEL_FROM_DATABASE=PhotoSmart A310 series + +usb:v03F0p1D17* + ID_MODEL_FROM_DATABASE=LaserJet 1320 + +usb:v03F0p1E02* + ID_MODEL_FROM_DATABASE=PhotoSmart A320 Printer series + +usb:v03F0p1E11* + ID_MODEL_FROM_DATABASE=PSC-950 + +usb:v03F0p1E17* + ID_MODEL_FROM_DATABASE=LaserJet 1160 series + +usb:v03F0p1F02* + ID_MODEL_FROM_DATABASE=PhotoSmart A440 Printer series + +usb:v03F0p1F11* + ID_MODEL_FROM_DATABASE=PSC 920 + +usb:v03F0p1F12* + ID_MODEL_FROM_DATABASE=OfficeJet Pro K5300 + +usb:v03F0p1F17* + ID_MODEL_FROM_DATABASE=color LaserJet 5550 + +usb:v03F0p1F1D* + ID_MODEL_FROM_DATABASE=un2400 Gobi Wireless Modem + +usb:v03F0p2001* + ID_MODEL_FROM_DATABASE=Floppy + +usb:v03F0p2002* + ID_MODEL_FROM_DATABASE=Hub + +usb:v03F0p2004* + ID_MODEL_FROM_DATABASE=DeskJet 640c + +usb:v03F0p2005* + ID_MODEL_FROM_DATABASE=ScanJet 3570c + +usb:v03F0p2012* + ID_MODEL_FROM_DATABASE=OfficeJet Pro K5400 + +usb:v03F0p201D* + ID_MODEL_FROM_DATABASE=un2400 Gobi Wireless Modem (QDL mode) + +usb:v03F0p2102* + ID_MODEL_FROM_DATABASE=PhotoSmart 7345 + +usb:v03F0p2104* + ID_MODEL_FROM_DATABASE=DeskJet 630c + +usb:v03F0p2112* + ID_MODEL_FROM_DATABASE=OfficeJet Pro L7500 + +usb:v03F0p211D* + ID_MODEL_FROM_DATABASE=Sierra MC5725 [ev2210] + +usb:v03F0p2202* + ID_MODEL_FROM_DATABASE=PhotoSmart 7600 series + +usb:v03F0p2205* + ID_MODEL_FROM_DATABASE=ScanJet 3500c + +usb:v03F0p2212* + ID_MODEL_FROM_DATABASE=OfficeJet Pro L7600 + +usb:v03F0p2217* + ID_MODEL_FROM_DATABASE=color LaserJet 9500 MFP + +usb:v03F0p2302* + ID_MODEL_FROM_DATABASE=PhotoSmart 7600 series + +usb:v03F0p2304* + ID_MODEL_FROM_DATABASE=DeskJet 656c + +usb:v03F0p2305* + ID_MODEL_FROM_DATABASE=ScanJet 3970c + +usb:v03F0p2311* + ID_MODEL_FROM_DATABASE=OfficeJet d series + +usb:v03F0p2312* + ID_MODEL_FROM_DATABASE=OfficeJet Pro L7700 + +usb:v03F0p2317* + ID_MODEL_FROM_DATABASE=LaserJet 4350 + +usb:v03F0p231D* + ID_MODEL_FROM_DATABASE=Broadcom 2070 Bluetooth Combo + +usb:v03F0p2402* + ID_MODEL_FROM_DATABASE=PhotoSmart 7700 series + +usb:v03F0p2404* + ID_MODEL_FROM_DATABASE=Deskjet F2280 series + +usb:v03F0p2405* + ID_MODEL_FROM_DATABASE=ScanJet 4070 PhotoSmart + +usb:v03F0p2417* + ID_MODEL_FROM_DATABASE=LaserJet 4250 + +usb:v03F0p241D* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem (QDL mode) + +usb:v03F0p2424* + ID_MODEL_FROM_DATABASE=LP1965 19" Monitor Hub + +usb:v03F0p2502* + ID_MODEL_FROM_DATABASE=PhotoSmart 7700 series + +usb:v03F0p2504* + ID_MODEL_FROM_DATABASE=DeskJet F4200 series + +usb:v03F0p2505* + ID_MODEL_FROM_DATABASE=ScanJet 3770 + +usb:v03F0p2512* + ID_MODEL_FROM_DATABASE=OfficeJet Pro L7300 + +usb:v03F0p2517* + ID_MODEL_FROM_DATABASE=LaserJet 2410 + +usb:v03F0p251D* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v03F0p2524* + ID_MODEL_FROM_DATABASE=LP3065 30" Monitor Hub + +usb:v03F0p2602* + ID_MODEL_FROM_DATABASE=PhotoSmart A520 series + +usb:v03F0p2605* + ID_MODEL_FROM_DATABASE=ScanJet 3800c + +usb:v03F0p2611* + ID_MODEL_FROM_DATABASE=OfficeJet 7100 series + +usb:v03F0p2617* + ID_MODEL_FROM_DATABASE=Color LaserJet 2820 series + +usb:v03F0p2624* + ID_MODEL_FROM_DATABASE=Pole Display (HP522 2 x 20 Line Display) + +usb:v03F0p2702* + ID_MODEL_FROM_DATABASE=PhotoSmart A620 series + +usb:v03F0p2704* + ID_MODEL_FROM_DATABASE=DeskJet 915 + +usb:v03F0p2717* + ID_MODEL_FROM_DATABASE=Color LaserJet 2830 + +usb:v03F0p2811* + ID_MODEL_FROM_DATABASE=PSC-2100 + +usb:v03F0p2817* + ID_MODEL_FROM_DATABASE=Color LaserJet 2840 + +usb:v03F0p2902* + ID_MODEL_FROM_DATABASE=PhotoSmart A820 series + +usb:v03F0p2911* + ID_MODEL_FROM_DATABASE=PSC 2200 + +usb:v03F0p2917* + ID_MODEL_FROM_DATABASE=LaserJet 2420 + +usb:v03F0p2A11* + ID_MODEL_FROM_DATABASE=PSC 2150 series + +usb:v03F0p2A17* + ID_MODEL_FROM_DATABASE=LaserJet 2430 + +usb:v03F0p2B11* + ID_MODEL_FROM_DATABASE=PSC 2170 series + +usb:v03F0p2B17* + ID_MODEL_FROM_DATABASE=LaserJet 1020 + +usb:v03F0p2C12* + ID_MODEL_FROM_DATABASE=Officejet J4680 + +usb:v03F0p2C17* + ID_MODEL_FROM_DATABASE=LaserJet 1022 + +usb:v03F0p2C24* + ID_MODEL_FROM_DATABASE=Logitech M-UAL-96 Mouse + +usb:v03F0p2D05* + ID_MODEL_FROM_DATABASE=Scanjet 7000 + +usb:v03F0p2D11* + ID_MODEL_FROM_DATABASE=OfficeJet 6110 + +usb:v03F0p2D17* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p2E11* + ID_MODEL_FROM_DATABASE=PSC 1000 + +usb:v03F0p2E17* + ID_MODEL_FROM_DATABASE=LaserJet 2600n + +usb:v03F0p2E24* + ID_MODEL_FROM_DATABASE=LP2275w Monitor Hub + +usb:v03F0p2F11* + ID_MODEL_FROM_DATABASE=PSC 1200 + +usb:v03F0p2F17* + ID_MODEL_FROM_DATABASE=EWS 2605dn + +usb:v03F0p2F24* + ID_MODEL_FROM_DATABASE=LP2475w Monitor Hub + +usb:v03F0p3002* + ID_MODEL_FROM_DATABASE=PhotoSmart P1000 + +usb:v03F0p3004* + ID_MODEL_FROM_DATABASE=DeskJet 980c + +usb:v03F0p3005* + ID_MODEL_FROM_DATABASE=ScanJet 4670v + +usb:v03F0p3011* + ID_MODEL_FROM_DATABASE=PSC 1100 series + +usb:v03F0p3017* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p3102* + ID_MODEL_FROM_DATABASE=PhotoSmart P1100 Printer w/ Card Reader + +usb:v03F0p3104* + ID_MODEL_FROM_DATABASE=DeskJet 960c + +usb:v03F0p3111* + ID_MODEL_FROM_DATABASE=OfficeJet 4100 series + +usb:v03F0p3117* + ID_MODEL_FROM_DATABASE=EWS 2605dtn + +usb:v03F0p311D* + ID_MODEL_FROM_DATABASE=Atheros AR9285 Malbec Bluetooth Adapter + +usb:v03F0p3202* + ID_MODEL_FROM_DATABASE=PhotoSmart 1215 + +usb:v03F0p3207* + ID_MODEL_FROM_DATABASE=4 GB flash drive + +usb:v03F0p3211* + ID_MODEL_FROM_DATABASE=OfficeJet 4105 series + +usb:v03F0p3217* + ID_MODEL_FROM_DATABASE=LaserJet 3050 + +usb:v03F0p3302* + ID_MODEL_FROM_DATABASE=PhotoSmart 1218 + +usb:v03F0p3304* + ID_MODEL_FROM_DATABASE=DeskJet 990c + +usb:v03F0p3312* + ID_MODEL_FROM_DATABASE=OfficeJet J6410 + +usb:v03F0p3317* + ID_MODEL_FROM_DATABASE=LaserJet 3052 + +usb:v03F0p3402* + ID_MODEL_FROM_DATABASE=PhotoSmart 1115 + +usb:v03F0p3404* + ID_MODEL_FROM_DATABASE=DeskJet 6122 + +usb:v03F0p3417* + ID_MODEL_FROM_DATABASE=LaserJet 3055 + +usb:v03F0p3502* + ID_MODEL_FROM_DATABASE=PhotoSmart 230 + +usb:v03F0p3504* + ID_MODEL_FROM_DATABASE=DeskJet 6127c + +usb:v03F0p3511* + ID_MODEL_FROM_DATABASE=PSC 2300 + +usb:v03F0p3517* + ID_MODEL_FROM_DATABASE=LaserJet 3390 + +usb:v03F0p3602* + ID_MODEL_FROM_DATABASE=PhotoSmart 1315 + +usb:v03F0p3611* + ID_MODEL_FROM_DATABASE=PSC 2410 PhotoSmart + +usb:v03F0p3617* + ID_MODEL_FROM_DATABASE=Color LaserJet 2605 + +usb:v03F0p3711* + ID_MODEL_FROM_DATABASE=PSC 2500 + +usb:v03F0p3717* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p3724* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v03F0p3802* + ID_MODEL_FROM_DATABASE=PhotoSmart 100 + +usb:v03F0p3807* + ID_MODEL_FROM_DATABASE=c485w Flash Drive + +usb:v03F0p3817* + ID_MODEL_FROM_DATABASE=LaserJet P2015 series + +usb:v03F0p3902* + ID_MODEL_FROM_DATABASE=PhotoSmart 130 + +usb:v03F0p3A02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7150 + +usb:v03F0p3A11* + ID_MODEL_FROM_DATABASE=OfficeJet 5500 series + +usb:v03F0p3A17* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p3B02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7150~ + +usb:v03F0p3B05* + ID_MODEL_FROM_DATABASE=Scanjet N8460 + +usb:v03F0p3B11* + ID_MODEL_FROM_DATABASE=PSC 1300 series + +usb:v03F0p3B17* + ID_MODEL_FROM_DATABASE=LaserJet M1005 MFP + +usb:v03F0p3C02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7350 + +usb:v03F0p3C05* + ID_MODEL_FROM_DATABASE=Scanjet Professional 1000 Mobile Scanner + +usb:v03F0p3C11* + ID_MODEL_FROM_DATABASE=PSC 1358 + +usb:v03F0p3C17* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p3D02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7350~ + +usb:v03F0p3D11* + ID_MODEL_FROM_DATABASE=OfficeJet 4215 + +usb:v03F0p3D17* + ID_MODEL_FROM_DATABASE=LaserJet P1005 + +usb:v03F0p3E02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7550 + +usb:v03F0p3E17* + ID_MODEL_FROM_DATABASE=LaserJet P1006 + +usb:v03F0p3F02* + ID_MODEL_FROM_DATABASE=PhotoSmart 7550~ + +usb:v03F0p3F11* + ID_MODEL_FROM_DATABASE=PSC-1315/PSC-1317 + +usb:v03F0p4002* + ID_MODEL_FROM_DATABASE=PhotoSmart 635/715/720/735/935 (storage) + +usb:v03F0p4004* + ID_MODEL_FROM_DATABASE=cp1160 + +usb:v03F0p4102* + ID_MODEL_FROM_DATABASE=PhotoSmart 618 + +usb:v03F0p4105* + ID_MODEL_FROM_DATABASE=ScanJet 4370 + +usb:v03F0p4111* + ID_MODEL_FROM_DATABASE=OfficeJet 7200 series + +usb:v03F0p4117* + ID_MODEL_FROM_DATABASE=LaserJet 1018 + +usb:v03F0p4202* + ID_MODEL_FROM_DATABASE=PhotoSmart 812 + +usb:v03F0p4205* + ID_MODEL_FROM_DATABASE=ScanJet G3010 + +usb:v03F0p4211* + ID_MODEL_FROM_DATABASE=OfficeJet 7300 series + +usb:v03F0p4217* + ID_MODEL_FROM_DATABASE=EWS CM1015 + +usb:v03F0p4302* + ID_MODEL_FROM_DATABASE=PhotoSmart 850 (ptp) + +usb:v03F0p4305* + ID_MODEL_FROM_DATABASE=ScanJet G3110 + +usb:v03F0p4311* + ID_MODEL_FROM_DATABASE=OfficeJet 7400 series + +usb:v03F0p4317* + ID_MODEL_FROM_DATABASE=Color LaserJet CM1017 + +usb:v03F0p4402* + ID_MODEL_FROM_DATABASE=PhotoSmart 935 (ptp) + +usb:v03F0p4417* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p4502* + ID_MODEL_FROM_DATABASE=PhotoSmart 945 (PTP mode) + +usb:v03F0p4505* + ID_MODEL_FROM_DATABASE=ScanJet G4010 + +usb:v03F0p4507* + ID_MODEL_FROM_DATABASE=External HDD + +usb:v03F0p4511* + ID_MODEL_FROM_DATABASE=PhotoSmart 2600 + +usb:v03F0p4512* + ID_MODEL_FROM_DATABASE=E709n [Officejet 6500 Wireless] + +usb:v03F0p4517* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p4605* + ID_MODEL_FROM_DATABASE=ScanJet G4050 + +usb:v03F0p4611* + ID_MODEL_FROM_DATABASE=PhotoSmart 2700 + +usb:v03F0p4717* + ID_MODEL_FROM_DATABASE=Color LaserJet CP1215 + +usb:v03F0p4811* + ID_MODEL_FROM_DATABASE=PSC 1600 + +usb:v03F0p4911* + ID_MODEL_FROM_DATABASE=PSC 2350 + +usb:v03F0p4B11* + ID_MODEL_FROM_DATABASE=OfficeJet 6200 + +usb:v03F0p4C11* + ID_MODEL_FROM_DATABASE=PSC 1500 series + +usb:v03F0p4C17* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p4D11* + ID_MODEL_FROM_DATABASE=PSC 1400 + +usb:v03F0p4D17* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p4E11* + ID_MODEL_FROM_DATABASE=PhotoSmart 2570 series + +usb:v03F0p4F11* + ID_MODEL_FROM_DATABASE=OfficeJet 5600 (USBHUB) + +usb:v03F0p4F17* + ID_MODEL_FROM_DATABASE=Color LaserJet CM1312 MFP + +usb:v03F0p5004* + ID_MODEL_FROM_DATABASE=DeskJet 995c + +usb:v03F0p5011* + ID_MODEL_FROM_DATABASE=PhotoSmart 3100 series + +usb:v03F0p5017* + ID_MODEL_FROM_DATABASE=EWS UPD + +usb:v03F0p5111* + ID_MODEL_FROM_DATABASE=PhotoSmart 3200 series + +usb:v03F0p5211* + ID_MODEL_FROM_DATABASE=PhotoSmart 3300 series + +usb:v03F0p5311* + ID_MODEL_FROM_DATABASE=OfficeJet 6300 + +usb:v03F0p5312* + ID_MODEL_FROM_DATABASE=Officejet Pro 8500A + +usb:v03F0p5411* + ID_MODEL_FROM_DATABASE=OfficeJet 4300 + +usb:v03F0p5511* + ID_MODEL_FROM_DATABASE=DeskJet F300 series + +usb:v03F0p5611* + ID_MODEL_FROM_DATABASE=PhotoSmart C3180 + +usb:v03F0p5617* + ID_MODEL_FROM_DATABASE=LaserJet M1120 MFP + +usb:v03F0p5711* + ID_MODEL_FROM_DATABASE=PhotoSmart C4100 series + +usb:v03F0p5717* + ID_MODEL_FROM_DATABASE=LaserJet M1120n MFP + +usb:v03F0p5811* + ID_MODEL_FROM_DATABASE=PhotoSmart C5100 series + +usb:v03F0p5817* + ID_MODEL_FROM_DATABASE=LaserJet M1319f MFP + +usb:v03F0p5911* + ID_MODEL_FROM_DATABASE=PhotoSmart C6180 + +usb:v03F0p5A11* + ID_MODEL_FROM_DATABASE=PhotoSmart C7100 series + +usb:v03F0p5B11* + ID_MODEL_FROM_DATABASE=OfficeJet J2100 series + +usb:v03F0p5C11* + ID_MODEL_FROM_DATABASE=PhotoSmart C4200 Printer series + +usb:v03F0p5C12* + ID_MODEL_FROM_DATABASE=OfficeJet 6700 + +usb:v03F0p5C17* + ID_MODEL_FROM_DATABASE=LaserJet P2055 series + +usb:v03F0p5D11* + ID_MODEL_FROM_DATABASE=PhotoSmart C5200 series + +usb:v03F0p5E11* + ID_MODEL_FROM_DATABASE=PhotoSmart D7400 series + +usb:v03F0p6004* + ID_MODEL_FROM_DATABASE=DeskJet 5550 + +usb:v03F0p6102* + ID_MODEL_FROM_DATABASE=Hewlett Packard Digital Camera + +usb:v03F0p6104* + ID_MODEL_FROM_DATABASE=DeskJet 5650c + +usb:v03F0p6117* + ID_MODEL_FROM_DATABASE=color LaserJet 3550 + +usb:v03F0p6202* + ID_MODEL_FROM_DATABASE=PhotoSmart 215 + +usb:v03F0p6204* + ID_MODEL_FROM_DATABASE=DeskJet 5150c + +usb:v03F0p6217* + ID_MODEL_FROM_DATABASE=Color LaserJet 4700 + +usb:v03F0p6302* + ID_MODEL_FROM_DATABASE=PhotoSmart 318/612 + +usb:v03F0p6317* + ID_MODEL_FROM_DATABASE=Color LaserJet 4730mfp + +usb:v03F0p6402* + ID_MODEL_FROM_DATABASE=PhotoSmart 715 (ptp) + +usb:v03F0p6411* + ID_MODEL_FROM_DATABASE=PhotoSmart C8100 series + +usb:v03F0p6417* + ID_MODEL_FROM_DATABASE=LaserJet 5200 + +usb:v03F0p6502* + ID_MODEL_FROM_DATABASE=PhotoSmart 120 (ptp) + +usb:v03F0p6511* + ID_MODEL_FROM_DATABASE=PhotoSmart C7200 series + +usb:v03F0p6602* + ID_MODEL_FROM_DATABASE=PhotoSmart 320 + +usb:v03F0p6611* + ID_MODEL_FROM_DATABASE=PhotoSmart C4380 series + +usb:v03F0p6617* + ID_MODEL_FROM_DATABASE=LaserJet 5200L + +usb:v03F0p6702* + ID_MODEL_FROM_DATABASE=PhotoSmart 720 (ptp) + +usb:v03F0p6717* + ID_MODEL_FROM_DATABASE=Color LaserJet 3000 + +usb:v03F0p6802* + ID_MODEL_FROM_DATABASE=PhotoSmart 620 (ptp) + +usb:v03F0p6811* + ID_MODEL_FROM_DATABASE=PhotoSmart D5300 series + +usb:v03F0p6817* + ID_MODEL_FROM_DATABASE=Color LaserJet 3800 + +usb:v03F0p6911* + ID_MODEL_FROM_DATABASE=PhotoSmart D7200 series + +usb:v03F0p6917* + ID_MODEL_FROM_DATABASE=Color LaserJet 3600 + +usb:v03F0p6A02* + ID_MODEL_FROM_DATABASE=PhotoSmart 735 (ptp) + +usb:v03F0p6A11* + ID_MODEL_FROM_DATABASE=PhotoSmart C6200 series + +usb:v03F0p6A17* + ID_MODEL_FROM_DATABASE=LaserJet 4240 + +usb:v03F0p6B02* + ID_MODEL_FROM_DATABASE=PhotoSmart R707 (PTP mode) + +usb:v03F0p6B11* + ID_MODEL_FROM_DATABASE=Photosmart C4500 series + +usb:v03F0p6C17* + ID_MODEL_FROM_DATABASE=Color LaserJet 4610 + +usb:v03F0p6F17* + ID_MODEL_FROM_DATABASE=Color LaserJet CP6015 series + +usb:v03F0p7004* + ID_MODEL_FROM_DATABASE=DeskJet 3320c + +usb:v03F0p7102* + ID_MODEL_FROM_DATABASE=PhotoSmart 635 (PTP mode) + +usb:v03F0p7104* + ID_MODEL_FROM_DATABASE=DeskJet 3420c + +usb:v03F0p7117* + ID_MODEL_FROM_DATABASE=CM8060 Color MFP with Edgeline Technology + +usb:v03F0p7202* + ID_MODEL_FROM_DATABASE=PhotoSmart 43x (ptp) + +usb:v03F0p7204* + ID_MODEL_FROM_DATABASE=DeskJet 36xx + +usb:v03F0p7217* + ID_MODEL_FROM_DATABASE=LaserJet M5035 MFP + +usb:v03F0p7302* + ID_MODEL_FROM_DATABASE=PhotoSmart M307 (PTP mode) + +usb:v03F0p7304* + ID_MODEL_FROM_DATABASE=DeskJet 35xx + +usb:v03F0p7311* + ID_MODEL_FROM_DATABASE=Photosmart Premium C309 + +usb:v03F0p7317* + ID_MODEL_FROM_DATABASE=LaserJet P3005 + +usb:v03F0p7404* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p7417* + ID_MODEL_FROM_DATABASE=LaserJet M4345 MFP + +usb:v03F0p7504* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p7517* + ID_MODEL_FROM_DATABASE=LaserJet M3035 MFP + +usb:v03F0p7604* + ID_MODEL_FROM_DATABASE=DeskJet 3940 + +usb:v03F0p7611* + ID_MODEL_FROM_DATABASE=DeskJet F2492 All-in-One + +usb:v03F0p7617* + ID_MODEL_FROM_DATABASE=LaserJet P3004 + +usb:v03F0p7702* + ID_MODEL_FROM_DATABASE=PhotoSmart R817 (PTP mode) + +usb:v03F0p7704* + ID_MODEL_FROM_DATABASE=DeskJet D4100 + +usb:v03F0p7717* + ID_MODEL_FROM_DATABASE=CM8050 Color MFP with Edgeline Technology + +usb:v03F0p7804* + ID_MODEL_FROM_DATABASE=DeskJet D1360 + +usb:v03F0p7817* + ID_MODEL_FROM_DATABASE=Color LaserJet CP3505 + +usb:v03F0p7917* + ID_MODEL_FROM_DATABASE=LaserJet M5025 MFP + +usb:v03F0p7A02* + ID_MODEL_FROM_DATABASE=PhotoSmart M415 (PTP mode) + +usb:v03F0p7A04* + ID_MODEL_FROM_DATABASE=DeskJet D2460 + +usb:v03F0p7A17* + ID_MODEL_FROM_DATABASE=LaserJet M3027 MFP + +usb:v03F0p7B02* + ID_MODEL_FROM_DATABASE=PhotoSmart M23 (PTP mode) + +usb:v03F0p7B17* + ID_MODEL_FROM_DATABASE=Color LaserJet CP4005 + +usb:v03F0p7C17* + ID_MODEL_FROM_DATABASE=Color LaserJet CM6040 series + +usb:v03F0p7D04* + ID_MODEL_FROM_DATABASE=DeskJet F2100 Printer series + +usb:v03F0p7D17* + ID_MODEL_FROM_DATABASE=Color LaserJet CM4730 MFP + +usb:v03F0p7E04* + ID_MODEL_FROM_DATABASE=DeskJet F4100 Printer series + +usb:v03F0p8017* + ID_MODEL_FROM_DATABASE=LaserJet P4515 + +usb:v03F0p8104* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p8117* + ID_MODEL_FROM_DATABASE=LaserJet P4015 + +usb:v03F0p811C* + ID_MODEL_FROM_DATABASE=Ethernet HN210E + +usb:v03F0p8204* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v03F0p8207* + ID_MODEL_FROM_DATABASE=FHA-3510 2.4GHz Wireless Optical Mobile Mouse + +usb:v03F0p8217* + ID_MODEL_FROM_DATABASE=LaserJet P4014 + +usb:v03F0p8317* + ID_MODEL_FROM_DATABASE=LaserJet M9050 MFP + +usb:v03F0p8404* + ID_MODEL_FROM_DATABASE=DeskJet 6800 series + +usb:v03F0p8417* + ID_MODEL_FROM_DATABASE=LaserJet M9040 MFP + +usb:v03F0p8504* + ID_MODEL_FROM_DATABASE=DeskJet 6600 series + +usb:v03F0p8604* + ID_MODEL_FROM_DATABASE=DeskJet 5440 + +usb:v03F0p8607* + ID_MODEL_FROM_DATABASE=Optical Mobile Mouse + +usb:v03F0p8704* + ID_MODEL_FROM_DATABASE=DeskJet 5940 + +usb:v03F0p8711* + ID_MODEL_FROM_DATABASE=Deskjet 2050 J510 + +usb:v03F0p8804* + ID_MODEL_FROM_DATABASE=DeskJet 6980 series + +usb:v03F0p8904* + ID_MODEL_FROM_DATABASE=DeskJet 6940 series + +usb:v03F0p8C07* + ID_MODEL_FROM_DATABASE=Digital Stereo Headset + +usb:v03F0p8C11* + ID_MODEL_FROM_DATABASE=Deskjet F4500 series + +usb:v03F0p9002* + ID_MODEL_FROM_DATABASE=PhotoSmart M437 + +usb:v03F0p9102* + ID_MODEL_FROM_DATABASE=PhotoSmart M537 + +usb:v03F0p9302* + ID_MODEL_FROM_DATABASE=PhotoSmart R930 series + +usb:v03F0p9402* + ID_MODEL_FROM_DATABASE=PhotoSmart R837 + +usb:v03F0p9502* + ID_MODEL_FROM_DATABASE=PhotoSmart R840 series + +usb:v03F0p9602* + ID_MODEL_FROM_DATABASE=PhotoSmart M730 series + +usb:v03F0p9702* + ID_MODEL_FROM_DATABASE=PhotoSmart R740 series + +usb:v03F0p9802* + ID_MODEL_FROM_DATABASE=PhotoSmart Mz60 series + +usb:v03F0p9902* + ID_MODEL_FROM_DATABASE=PhotoSmart M630 series + +usb:v03F0p9A02* + ID_MODEL_FROM_DATABASE=PhotoSmart E330 series + +usb:v03F0p9B02* + ID_MODEL_FROM_DATABASE=PhotoSmart M540 series + +usb:v03F0p9B07* + ID_MODEL_FROM_DATABASE=Portable Drive + +usb:v03F0p9C02* + ID_MODEL_FROM_DATABASE=PhotoSmart M440 series + +usb:v03F0pA004* + ID_MODEL_FROM_DATABASE=DeskJet 5850c + +usb:v03F0pA011* + ID_MODEL_FROM_DATABASE=Deskjet 3050A + +usb:v03F0pB002* + ID_MODEL_FROM_DATABASE=PhotoSmart 7200 series + +usb:v03F0pB102* + ID_MODEL_FROM_DATABASE=PhotoSmart 7200 series + +usb:v03F0pB107* + ID_MODEL_FROM_DATABASE=v255w/c310w Flash Drive + +usb:v03F0pB116* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v03F0pB202* + ID_MODEL_FROM_DATABASE=PhotoSmart 7600 series + +usb:v03F0pB302* + ID_MODEL_FROM_DATABASE=PhotoSmart 7600 series + +usb:v03F0pB402* + ID_MODEL_FROM_DATABASE=PhotoSmart 7700 series + +usb:v03F0pB502* + ID_MODEL_FROM_DATABASE=PhotoSmart 7700 series + +usb:v03F0pB602* + ID_MODEL_FROM_DATABASE=PhotoSmart 7900 series + +usb:v03F0pB702* + ID_MODEL_FROM_DATABASE=PhotoSmart 7900 series + +usb:v03F0pB802* + ID_MODEL_FROM_DATABASE=PhotoSmart 7400 series + +usb:v03F0pB902* + ID_MODEL_FROM_DATABASE=PhotoSmart 7800 series + +usb:v03F0pBA02* + ID_MODEL_FROM_DATABASE=PhotoSmart 8100 series + +usb:v03F0pBB02* + ID_MODEL_FROM_DATABASE=PhotoSmart 8400 series + +usb:v03F0pBC02* + ID_MODEL_FROM_DATABASE=PhotoSmart 8700 series + +usb:v03F0pBD02* + ID_MODEL_FROM_DATABASE=PhotoSmart Pro B9100 series + +usb:v03F0pBEF4* + ID_MODEL_FROM_DATABASE=NEC Picty760 + +usb:v03F0pC002* + ID_MODEL_FROM_DATABASE=PhotoSmart 7800 series + +usb:v03F0pC102* + ID_MODEL_FROM_DATABASE=PhotoSmart 8000 series + +usb:v03F0pC202* + ID_MODEL_FROM_DATABASE=PhotoSmart 8200 series + +usb:v03F0pC302* + ID_MODEL_FROM_DATABASE=DeskJet D2300 + +usb:v03F0pC402* + ID_MODEL_FROM_DATABASE=PhotoSmart D5100 series + +usb:v03F0pC502* + ID_MODEL_FROM_DATABASE=PhotoSmart D6100 series + +usb:v03F0pC602* + ID_MODEL_FROM_DATABASE=PhotoSmart D7100 series + +usb:v03F0pC702* + ID_MODEL_FROM_DATABASE=PhotoSmart D7300 series + +usb:v03F0pC802* + ID_MODEL_FROM_DATABASE=PhotoSmart D5060 Printer + +usb:v03F0pD104* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v03F0pEFBE* + ID_MODEL_FROM_DATABASE=NEC Picty900 + +usb:v03F0pF0BE* + ID_MODEL_FROM_DATABASE=NEC Picty920 + +usb:v03F0pF1BE* + ID_MODEL_FROM_DATABASE=NEC Picty800 + +usb:v03F1* + ID_VENDOR_FROM_DATABASE=Genoa Technology + +usb:v03F2* + ID_VENDOR_FROM_DATABASE=Oak Technology, Inc. + +usb:v03F3* + ID_VENDOR_FROM_DATABASE=Adaptec, Inc. + +usb:v03F3p0020* + ID_MODEL_FROM_DATABASE=AWN-8020 WLAN [Intersil PRISM 2.5] + +usb:v03F3p0080* + ID_MODEL_FROM_DATABASE=AVC-1100 Audio Capture + +usb:v03F3p0083* + ID_MODEL_FROM_DATABASE=AVC-2200 Device + +usb:v03F3p0087* + ID_MODEL_FROM_DATABASE=AVC-2210 Loader + +usb:v03F3p0088* + ID_MODEL_FROM_DATABASE=AVC-2210 Device + +usb:v03F3p008B* + ID_MODEL_FROM_DATABASE=AVC-2310 Loader + +usb:v03F3p008C* + ID_MODEL_FROM_DATABASE=AVC-2310 Device + +usb:v03F3p0094* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v03F3p009B* + ID_MODEL_FROM_DATABASE=AVC-1410 GameBridge TV NTSC + +usb:v03F3p2000* + ID_MODEL_FROM_DATABASE=USBXchange + +usb:v03F3p2001* + ID_MODEL_FROM_DATABASE=USBXchange Adapter + +usb:v03F3p2002* + ID_MODEL_FROM_DATABASE=USB2-Xchange + +usb:v03F3p2003* + ID_MODEL_FROM_DATABASE=USB2-Xchange Adapter + +usb:v03F3p4000* + ID_MODEL_FROM_DATABASE=4-port hub + +usb:v03F3pADCC* + ID_MODEL_FROM_DATABASE=Composite Device Support + +usb:v03F4* + ID_VENDOR_FROM_DATABASE=Diebold, Inc. + +usb:v03F5* + ID_VENDOR_FROM_DATABASE=Siemens Electromechanical + +usb:v03F8* + ID_VENDOR_FROM_DATABASE=Epson Imaging Technology Center + +usb:v03F9* + ID_VENDOR_FROM_DATABASE=KeyTronic Corp. + +usb:v03F9p0100* + ID_MODEL_FROM_DATABASE=KT-2001 Keyboard + +usb:v03F9p0101* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v03F9p0102* + ID_MODEL_FROM_DATABASE=Keyboard Mouse + +usb:v03FB* + ID_VENDOR_FROM_DATABASE=OPTi, Inc. + +usb:v03FC* + ID_VENDOR_FROM_DATABASE=Elitegroup Computer Systems + +usb:v03FD* + ID_VENDOR_FROM_DATABASE=Xilinx, Inc. + +usb:v03FE* + ID_VENDOR_FROM_DATABASE=Farallon Comunications + +usb:v0400* + ID_VENDOR_FROM_DATABASE=National Semiconductor Corp. + +usb:v0400p05DC* + ID_MODEL_FROM_DATABASE=Rigol Technologies DS1000USB Oscilloscope + +usb:v0400p0807* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0400p080A* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0400p09C4* + ID_MODEL_FROM_DATABASE=Rigol Technologies DG1022 Arbitrary Waveform Generator + +usb:v0400p1000* + ID_MODEL_FROM_DATABASE=Mustek BearPaw 1200 Scanner + +usb:v0400p1001* + ID_MODEL_FROM_DATABASE=Mustek BearPaw 2400 Scanner + +usb:v0400p1237* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0400pA000* + ID_MODEL_FROM_DATABASE=Smart Display Reference Device + +usb:v0400pC359* + ID_MODEL_FROM_DATABASE=Logitech Harmony + +usb:v0400pC35B* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v0400pC55D* + ID_MODEL_FROM_DATABASE=Rigol Technologies DS5000USB Oscilloscope + +usb:v0401* + ID_VENDOR_FROM_DATABASE=National Registry, Inc. + +usb:v0402* + ID_VENDOR_FROM_DATABASE=ALi Corp. + +usb:v0402p5462* + ID_MODEL_FROM_DATABASE=M5462 IDE Controller + +usb:v0402p5602* + ID_MODEL_FROM_DATABASE=M5602 Video Camera Controller + +usb:v0402p5603* + ID_MODEL_FROM_DATABASE=M5603 Video Camera Controller + +usb:v0402p5606* + ID_MODEL_FROM_DATABASE=M5606 Video Camera Controller [UVC] + +usb:v0402p5621* + ID_MODEL_FROM_DATABASE=M5621 High-Speed IDE Controller + +usb:v0402p5623* + ID_MODEL_FROM_DATABASE=M5623 Scanner Controller + +usb:v0402p5627* + ID_MODEL_FROM_DATABASE=Welland ME-740PS USB2 3.5" Power Saving Enclosure + +usb:v0402p5632* + ID_MODEL_FROM_DATABASE=M5632 Host-to-Host Link + +usb:v0402p5635* + ID_MODEL_FROM_DATABASE=M5635 Flash Card Reader + +usb:v0402p5636* + ID_MODEL_FROM_DATABASE=USB 2.0 Storage Device + +usb:v0402p5637* + ID_MODEL_FROM_DATABASE=M5637 IDE Controller + +usb:v0402p5661* + ID_MODEL_FROM_DATABASE=M5661 MP3 player + +usb:v0402p5667* + ID_MODEL_FROM_DATABASE=M5667 MP3 player + +usb:v0402p9665* + ID_MODEL_FROM_DATABASE=Gateway Webcam + +usb:v0403* + ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd + +usb:v0403p0000* + ID_MODEL_FROM_DATABASE=H4SMK 7 Port Hub + +usb:v0403p0232* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v0403p1060* + ID_MODEL_FROM_DATABASE=JTAG adapter + +usb:v0403p6001* + ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC + +usb:v0403p6002* + ID_MODEL_FROM_DATABASE=Lumel PD12 + +usb:v0403p6007* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v0403p6008* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v0403p6009* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v0403p6010* + ID_MODEL_FROM_DATABASE=FT2232C Dual USB-UART/FIFO IC + +usb:v0403p6011* + ID_MODEL_FROM_DATABASE=FT4232H Quad HS USB-UART/FIFO IC + +usb:v0403p6014* + ID_MODEL_FROM_DATABASE=FT232H Single HS USB-UART/FIFO IC + +usb:v0403p6015* + ID_MODEL_FROM_DATABASE=Bridge(I2C/SPI/UART/FIFO) + +usb:v0403p8028* + ID_MODEL_FROM_DATABASE=Dev board JTAG (FT232H based) + +usb:v0403p8040* + ID_MODEL_FROM_DATABASE=4 Port Hub + +usb:v0403p8070* + ID_MODEL_FROM_DATABASE=7 Port Hub + +usb:v0403p8140* + ID_MODEL_FROM_DATABASE=Vehicle Explorer Interface + +usb:v0403p8210* + ID_MODEL_FROM_DATABASE=MGTimer - MGCC (Vic) Timing System + +usb:v0403p8370* + ID_MODEL_FROM_DATABASE=7 Port Hub + +usb:v0403p8371* + ID_MODEL_FROM_DATABASE=PS/2 Keyboard And Mouse + +usb:v0403p8372* + ID_MODEL_FROM_DATABASE=FT8U100AX Serial Port + +usb:v0403p8A28* + ID_MODEL_FROM_DATABASE=Rainforest Automation ZigBee Controller + +usb:v0403p8A98* + ID_MODEL_FROM_DATABASE=TIAO Multi-Protocol Adapter + +usb:v0403p9133* + ID_MODEL_FROM_DATABASE=CallerID + +usb:v0403p9135* + ID_MODEL_FROM_DATABASE=Rotary Pub alarm + +usb:v0403p9E90* + ID_MODEL_FROM_DATABASE=Marvell OpenRD Base/Client + +usb:v0403p9F80* + ID_MODEL_FROM_DATABASE=Ewert Energy Systems CANdapter + +usb:v0403pA6D0* + ID_MODEL_FROM_DATABASE=Texas Instruments XDS100v2 JTAG / BeagleBone A3 + +usb:v0403pA951* + ID_MODEL_FROM_DATABASE=HCP HIT GSM/GPRS modem [Cinterion MC55i] + +usb:v0403pABB8* + ID_MODEL_FROM_DATABASE=Lego Mindstorms NXTCam + +usb:v0403pB810* + ID_MODEL_FROM_DATABASE=US Interface Navigator (CAT and 2nd PTT lines) + +usb:v0403pB811* + ID_MODEL_FROM_DATABASE=US Interface Navigator (WKEY and FSK lines) + +usb:v0403pB812* + ID_MODEL_FROM_DATABASE=US Interface Navigator (RS232 and CONFIG lines) + +usb:v0403pB9B0* + ID_MODEL_FROM_DATABASE=Fujitsu SK-16FX-100PMC V1.1 + +usb:v0403pBAF8* + ID_MODEL_FROM_DATABASE=Amontec JTAGkey + +usb:v0403pBCD8* + ID_MODEL_FROM_DATABASE=Stellaris Development Board + +usb:v0403pBCD9* + ID_MODEL_FROM_DATABASE=Stellaris Evaluation Board + +usb:v0403pBCDA* + ID_MODEL_FROM_DATABASE=Stellaris ICDI Board + +usb:v0403pBDC8* + ID_MODEL_FROM_DATABASE=Egnite GmbH - JTAG/RS-232 adapter + +usb:v0403pBFD8* + ID_MODEL_FROM_DATABASE=OpenDCC + +usb:v0403pBFD9* + ID_MODEL_FROM_DATABASE=OpenDCC (Sniffer) + +usb:v0403pBFDA* + ID_MODEL_FROM_DATABASE=OpenDCC (Throttle) + +usb:v0403pBFDB* + ID_MODEL_FROM_DATABASE=OpenDCC (Gateway) + +usb:v0403pBFDC* + ID_MODEL_FROM_DATABASE=OpenDCC (GBM) + +usb:v0403pC630* + ID_MODEL_FROM_DATABASE=lcd2usb interface + +usb:v0403pC631* + ID_MODEL_FROM_DATABASE=i2c-tiny-usb interface + +usb:v0403pC632* + ID_MODEL_FROM_DATABASE=xu1541 c64 floppy drive interface + +usb:v0403pC633* + ID_MODEL_FROM_DATABASE=TinyCrypt dongle + +usb:v0403pC634* + ID_MODEL_FROM_DATABASE=glcd2usb interface + +usb:v0403pC7D0* + ID_MODEL_FROM_DATABASE=RR-CirKits LocoBuffer-USB + +usb:v0403pC8B8* + ID_MODEL_FROM_DATABASE=Alpermann+Velte MTD TCU + +usb:v0403pC8B9* + ID_MODEL_FROM_DATABASE=Alpermann+Velte MTD TCU 1HE + +usb:v0403pC8BA* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Rubidium H1 + +usb:v0403pC8BB* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Rubidium H3 + +usb:v0403pC8BC* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Rubidium S1 + +usb:v0403pC8BD* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Rubidium T1 + +usb:v0403pC8BE* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Rubidium D1 + +usb:v0403pCC48* + ID_MODEL_FROM_DATABASE=Tactrix OpenPort 1.3 Mitsubishi + +usb:v0403pCC49* + ID_MODEL_FROM_DATABASE=Tactrix OpenPort 1.3 Subaru + +usb:v0403pCC4A* + ID_MODEL_FROM_DATABASE=Tactrix OpenPort 1.3 Universal + +usb:v0403pCFF8* + ID_MODEL_FROM_DATABASE=Amontec JTAGkey + +usb:v0403pD010* + ID_MODEL_FROM_DATABASE=SCS PTC-IIusb + +usb:v0403pD011* + ID_MODEL_FROM_DATABASE=SCS Position-Tracker/TNC + +usb:v0403pD012* + ID_MODEL_FROM_DATABASE=SCS DRAGON 1 + +usb:v0403pD013* + ID_MODEL_FROM_DATABASE=SCS DRAGON 1 + +usb:v0403pD491* + ID_MODEL_FROM_DATABASE=Zolix Omni 1509 monochromator + +usb:v0403pD578* + ID_MODEL_FROM_DATABASE=Accesio USB-COM-4SM + +usb:v0403pD6F8* + ID_MODEL_FROM_DATABASE=UNI Black BOX + +usb:v0403pD738* + ID_MODEL_FROM_DATABASE=Propox JTAGcable II + +usb:v0403pD739* + ID_MODEL_FROM_DATABASE=Propox ISPcable III + +usb:v0403pD9A9* + ID_MODEL_FROM_DATABASE=Actisense USG-1 NMEA Serial Gateway + +usb:v0403pD9AA* + ID_MODEL_FROM_DATABASE=Actisense NGT-1 NMEA2000 PC Interface + +usb:v0403pE0D0* + ID_MODEL_FROM_DATABASE=Total Phase Aardvark I2C/SPI Host Adapter + +usb:v0403pE521* + ID_MODEL_FROM_DATABASE=EVER Sinline XL Series UPS + +usb:v0403pE6C8* + ID_MODEL_FROM_DATABASE=PYRAMID Computer GmbH LCD + +usb:v0403pE700* + ID_MODEL_FROM_DATABASE=Elster Unicom III Optical Probe + +usb:v0403pE729* + ID_MODEL_FROM_DATABASE=Segway Robotic Mobility Platforms 200 + +usb:v0403pE888* + ID_MODEL_FROM_DATABASE=Expert ISDN Control USB + +usb:v0403pE889* + ID_MODEL_FROM_DATABASE=USB-RS232 OptoBridge + +usb:v0403pE88A* + ID_MODEL_FROM_DATABASE=Expert mouseCLOCK USB II + +usb:v0403pE88B* + ID_MODEL_FROM_DATABASE=Precision Clock MSF USB + +usb:v0403pE88C* + ID_MODEL_FROM_DATABASE=Expert mouseCLOCK USB II HBG + +usb:v0403pE8D8* + ID_MODEL_FROM_DATABASE=Aaronia AG Spectran Spectrum Analyzer + +usb:v0403pE8DC* + ID_MODEL_FROM_DATABASE=Aaronia AG UBBV Preamplifier + +usb:v0403pEA90* + ID_MODEL_FROM_DATABASE=Eclo 1-Wire Adapter + +usb:v0403pED71* + ID_MODEL_FROM_DATABASE=HAMEG HO870 Serial Port + +usb:v0403pED72* + ID_MODEL_FROM_DATABASE=HAMEG HO720 Serial Port + +usb:v0403pED73* + ID_MODEL_FROM_DATABASE=HAMEG HO730 Serial Port + +usb:v0403pED74* + ID_MODEL_FROM_DATABASE=HAMEG HO820 Serial Port + +usb:v0403pEF10* + ID_MODEL_FROM_DATABASE=FT1245BL + +usb:v0403pF070* + ID_MODEL_FROM_DATABASE=Serial Converter 422/485 [Vardaan VEUSB422R3] + +usb:v0403pF1A0* + ID_MODEL_FROM_DATABASE=Asix PRESTO Programmer + +usb:v0403pF208* + ID_MODEL_FROM_DATABASE=Papenmeier Braille-Display + +usb:v0403pF3C0* + ID_MODEL_FROM_DATABASE=4N-GALAXY Serial Converter + +usb:v0403pF608* + ID_MODEL_FROM_DATABASE=CTI USB-485-Mini + +usb:v0403pF60B* + ID_MODEL_FROM_DATABASE=CTI USB-Nano-485 + +usb:v0403pF680* + ID_MODEL_FROM_DATABASE=Suunto Sports Instrument + +usb:v0403pF758* + ID_MODEL_FROM_DATABASE=GW Instek GDS-8x0 Oscilloscope + +usb:v0403pF7C0* + ID_MODEL_FROM_DATABASE=ZeitControl Cardsystems TagTracer MIFARE + +usb:v0403pF850* + ID_MODEL_FROM_DATABASE=USB-UIRT (Universal Infrared Receiver+Transmitter) + +usb:v0403pF918* + ID_MODEL_FROM_DATABASE=Ant8 Logic Probe + +usb:v0403pFA00* + ID_MODEL_FROM_DATABASE=Matrix Orbital USB Serial + +usb:v0403pFA01* + ID_MODEL_FROM_DATABASE=Matrix Orbital MX2 or MX3 + +usb:v0403pFA02* + ID_MODEL_FROM_DATABASE=Matrix Orbital MX4 or MX5 + +usb:v0403pFA03* + ID_MODEL_FROM_DATABASE=Matrix Orbital VK/LK202 Family + +usb:v0403pFA04* + ID_MODEL_FROM_DATABASE=Matrix Orbital VK/LK204 Family + +usb:v0403pFA20* + ID_MODEL_FROM_DATABASE=Ross-Tech HEX-USB + +usb:v0403pFC08* + ID_MODEL_FROM_DATABASE=Crystalfontz CFA-632 USB LCD + +usb:v0403pFC09* + ID_MODEL_FROM_DATABASE=Crystalfontz CFA-634 USB LCD + +usb:v0403pFC0B* + ID_MODEL_FROM_DATABASE=Crystalfontz CFA-633 USB LCD + +usb:v0403pFC0C* + ID_MODEL_FROM_DATABASE=Crystalfontz CFA-631 USB LCD + +usb:v0403pFC0D* + ID_MODEL_FROM_DATABASE=Crystalfontz CFA-635 USB LCD + +usb:v0403pFC82* + ID_MODEL_FROM_DATABASE=SEMC DSS-20/DSS-25 SyncStation + +usb:v0403pFD48* + ID_MODEL_FROM_DATABASE=ShipModul MiniPlex-4xUSB NMEA Multiplexer + +usb:v0403pFD49* + ID_MODEL_FROM_DATABASE=ShipModul MiniPlex-4xUSB-AIS NMEA Multiplexer + +usb:v0403pFF08* + ID_MODEL_FROM_DATABASE=ToolHouse LoopBack Adapter + +usb:v0403pFF18* + ID_MODEL_FROM_DATABASE=ScienceScope Logbook ML + +usb:v0403pFF19* + ID_MODEL_FROM_DATABASE=Logbook Bus + +usb:v0403pFF1A* + ID_MODEL_FROM_DATABASE=Logbook Bus + +usb:v0403pFF1B* + ID_MODEL_FROM_DATABASE=Logbook Bus + +usb:v0403pFF1C* + ID_MODEL_FROM_DATABASE=ScienceScope Logbook LS + +usb:v0403pFF1D* + ID_MODEL_FROM_DATABASE=ScienceScope Logbook HS + +usb:v0403pFF1E* + ID_MODEL_FROM_DATABASE=Logbook Bus + +usb:v0403pFF1F* + ID_MODEL_FROM_DATABASE=Logbook Bus + +usb:v0404* + ID_VENDOR_FROM_DATABASE=NCR Corp. + +usb:v0404p0202* + ID_MODEL_FROM_DATABASE=78XX Scanner + +usb:v0404p0203* + ID_MODEL_FROM_DATABASE=78XX Scanner - Embedded System + +usb:v0404p0310* + ID_MODEL_FROM_DATABASE=K590 Printer, Self-Service + +usb:v0404p0311* + ID_MODEL_FROM_DATABASE=7167 Printer, Receipt/Slip + +usb:v0404p0312* + ID_MODEL_FROM_DATABASE=7197 Printer Receipt + +usb:v0404p0320* + ID_MODEL_FROM_DATABASE=5932-USB Keyboard + +usb:v0404p0321* + ID_MODEL_FROM_DATABASE=5953-USB Dynakey + +usb:v0404p0322* + ID_MODEL_FROM_DATABASE=5932-USB Enhanced Keyboard + +usb:v0404p0323* + ID_MODEL_FROM_DATABASE=5932-USB Enhanced Keyboard, Flash-Recovery/Download + +usb:v0404p0324* + ID_MODEL_FROM_DATABASE=5953-USB Enhanced Dynakey + +usb:v0404p0325* + ID_MODEL_FROM_DATABASE=5953-USB Enhanced Dynakey Flash-Recovery/Download + +usb:v0404p0328* + ID_MODEL_FROM_DATABASE=K016: USB-MSR ISO 3-track MSR: POS Standard (See HID pages) + +usb:v0404p0329* + ID_MODEL_FROM_DATABASE=K018: USB-MSR JIS 2-Track MSR: POS Standard + +usb:v0404p032A* + ID_MODEL_FROM_DATABASE=K016: USB-MSR ISO 3-Track MSR: HID Keyboard Mode + +usb:v0404p032B* + ID_MODEL_FROM_DATABASE=K016/K018: USB-MSR Flash-Recovery/Download + +usb:v0405* + ID_VENDOR_FROM_DATABASE=Synopsys, Inc. + +usb:v0406* + ID_VENDOR_FROM_DATABASE=Fujitsu-ICL Computers + +usb:v0407* + ID_VENDOR_FROM_DATABASE=Fujitsu Personal Systems, Inc. + +usb:v0408* + ID_VENDOR_FROM_DATABASE=Quanta Computer, Inc. + +usb:v0408p0103* + ID_MODEL_FROM_DATABASE=FV TouchCam N1 (Audio) + +usb:v0408p030C* + ID_MODEL_FROM_DATABASE=HP Webcam + +usb:v0408p03B2* + ID_MODEL_FROM_DATABASE=HP Webcam + +usb:v0408p1030* + ID_MODEL_FROM_DATABASE=FV TouchCam N1 (Video) + +usb:v0408p3000* + ID_MODEL_FROM_DATABASE=Optical dual-touch panel + +usb:v0408p3001* + ID_MODEL_FROM_DATABASE=Optical Touch Screen + +usb:v0409* + ID_VENDOR_FROM_DATABASE=NEC Corp. + +usb:v0409p0011* + ID_MODEL_FROM_DATABASE=PC98 Series Layout Keyboard Mouse + +usb:v0409p0012* + ID_MODEL_FROM_DATABASE=ATerm IT75DSU ISDN TA + +usb:v0409p0014* + ID_MODEL_FROM_DATABASE=Japanese Keyboard + +usb:v0409p0019* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard with Bus-Powered Hub + +usb:v0409p001A* + ID_MODEL_FROM_DATABASE=PC98 Series Layout Keyboard with Bus-Powered Hub + +usb:v0409p0025* + ID_MODEL_FROM_DATABASE=Mini Keyboard with Bus-Powered Hub + +usb:v0409p0027* + ID_MODEL_FROM_DATABASE=MultiSync Monitor + +usb:v0409p002C* + ID_MODEL_FROM_DATABASE=Clik!-USB Drive + +usb:v0409p0034* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard with One-touch start buttons + +usb:v0409p003F* + ID_MODEL_FROM_DATABASE=Wireless Keyboard with One-touch start buttons + +usb:v0409p0040* + ID_MODEL_FROM_DATABASE=Floppy + +usb:v0409p004E* + ID_MODEL_FROM_DATABASE=SuperScript 1400 Series + +usb:v0409p004F* + ID_MODEL_FROM_DATABASE=Wireless Keyboard with One-touch start buttons + +usb:v0409p0050* + ID_MODEL_FROM_DATABASE=7-port hub + +usb:v0409p0058* + ID_MODEL_FROM_DATABASE=HighSpeed Hub + +usb:v0409p0059* + ID_MODEL_FROM_DATABASE=HighSpeed Hub + +usb:v0409p005A* + ID_MODEL_FROM_DATABASE=HighSpeed Hub + +usb:v0409p006A* + ID_MODEL_FROM_DATABASE=Conceptronic USB Harddisk Box + +usb:v0409p007D* + ID_MODEL_FROM_DATABASE=MINICUBE2 + +usb:v0409p007E* + ID_MODEL_FROM_DATABASE=PG-FP5 Flash Memory Programmer + +usb:v0409p0081* + ID_MODEL_FROM_DATABASE=SuperScript 1400 Series + +usb:v0409p0082* + ID_MODEL_FROM_DATABASE=SuperScript 1400 Series + +usb:v0409p0094* + ID_MODEL_FROM_DATABASE=Japanese Keyboard with One-touch start buttons + +usb:v0409p0095* + ID_MODEL_FROM_DATABASE=Japanese Keyboard + +usb:v0409p00A9* + ID_MODEL_FROM_DATABASE=AtermIT21L 128K Support Standard + +usb:v0409p00AA* + ID_MODEL_FROM_DATABASE=AtermITX72 128K Support Standard + +usb:v0409p00AB* + ID_MODEL_FROM_DATABASE=AtermITX62 128K Support Standard + +usb:v0409p00AC* + ID_MODEL_FROM_DATABASE=AtermIT42 128K Support Standard + +usb:v0409p00AE* + ID_MODEL_FROM_DATABASE=INSMATEV70G-MAX Standard + +usb:v0409p00AF* + ID_MODEL_FROM_DATABASE=AtermITX70 128K Support Standard + +usb:v0409p00B0* + ID_MODEL_FROM_DATABASE=AtermITX80 128K Support Standard + +usb:v0409p00B2* + ID_MODEL_FROM_DATABASE=AtermITX80D 128K Support Standard + +usb:v0409p00C0* + ID_MODEL_FROM_DATABASE=Wireless Remocon + +usb:v0409p00F7* + ID_MODEL_FROM_DATABASE=Smart Display PK-SD10 + +usb:v0409p011D* + ID_MODEL_FROM_DATABASE=e228 Mobile Phone + +usb:v0409p0203* + ID_MODEL_FROM_DATABASE=HID Audio Controls + +usb:v0409p021D* + ID_MODEL_FROM_DATABASE=Aterm WL54SU2 802.11g Wireless Adapter [Atheros AR5523] + +usb:v0409p0248* + ID_MODEL_FROM_DATABASE=Aterm PA-WL54GU + +usb:v0409p0249* + ID_MODEL_FROM_DATABASE=Aterm WL300NU-G + +usb:v0409p02B4* + ID_MODEL_FROM_DATABASE=Aterm WL300NU-AG + +usb:v0409p02B6* + ID_MODEL_FROM_DATABASE=Aterm WL300NU-GS 802.11n Wireless Adapter + +usb:v0409p0300* + ID_MODEL_FROM_DATABASE=LifeTouch Note + +usb:v0409p0301* + ID_MODEL_FROM_DATABASE=LifeTouch Note (debug mode) + +usb:v0409p55AA* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0409p55AB* + ID_MODEL_FROM_DATABASE=Hub [iMac/iTouch kbd] + +usb:v0409p8010* + ID_MODEL_FROM_DATABASE=Intellibase Hub + +usb:v0409p8011* + ID_MODEL_FROM_DATABASE=Intellibase Hub + +usb:v0409pEFBE* + ID_MODEL_FROM_DATABASE=P!cty 900 [HP DJ] + +usb:v0409pF0BE* + ID_MODEL_FROM_DATABASE=P!cty 920 [HP DJ 812c] + +usb:v040A* + ID_VENDOR_FROM_DATABASE=Kodak Co. + +usb:v040Ap0001* + ID_MODEL_FROM_DATABASE=DVC-323 + +usb:v040Ap0002* + ID_MODEL_FROM_DATABASE=DVC-325 + +usb:v040Ap0100* + ID_MODEL_FROM_DATABASE=DC-220 + +usb:v040Ap0110* + ID_MODEL_FROM_DATABASE=DC-260 + +usb:v040Ap0111* + ID_MODEL_FROM_DATABASE=DC-265 + +usb:v040Ap0112* + ID_MODEL_FROM_DATABASE=DC-290 + +usb:v040Ap0120* + ID_MODEL_FROM_DATABASE=DC-240 + +usb:v040Ap0121* + ID_MODEL_FROM_DATABASE=DC-240 (PTP firmware) + +usb:v040Ap0130* + ID_MODEL_FROM_DATABASE=DC-280 + +usb:v040Ap0131* + ID_MODEL_FROM_DATABASE=DC-5000 + +usb:v040Ap0132* + ID_MODEL_FROM_DATABASE=DC-3400 + +usb:v040Ap0140* + ID_MODEL_FROM_DATABASE=DC-4800 + +usb:v040Ap0160* + ID_MODEL_FROM_DATABASE=DC4800 + +usb:v040Ap0170* + ID_MODEL_FROM_DATABASE=DX3900 + +usb:v040Ap0200* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0300* + ID_MODEL_FROM_DATABASE=EZ-200 + +usb:v040Ap0400* + ID_MODEL_FROM_DATABASE=MC3 + +usb:v040Ap0402* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0403* + ID_MODEL_FROM_DATABASE=Z7590 + +usb:v040Ap0500* + ID_MODEL_FROM_DATABASE=DX3500 + +usb:v040Ap0510* + ID_MODEL_FROM_DATABASE=DX3600 + +usb:v040Ap0525* + ID_MODEL_FROM_DATABASE=DX3215 + +usb:v040Ap0530* + ID_MODEL_FROM_DATABASE=DX3700 + +usb:v040Ap0535* + ID_MODEL_FROM_DATABASE=EasyShare CX4230 Camera + +usb:v040Ap0540* + ID_MODEL_FROM_DATABASE=LS420 + +usb:v040Ap0550* + ID_MODEL_FROM_DATABASE=DX4900 + +usb:v040Ap0555* + ID_MODEL_FROM_DATABASE=DX4330 + +usb:v040Ap0560* + ID_MODEL_FROM_DATABASE=CX4200 + +usb:v040Ap0565* + ID_MODEL_FROM_DATABASE=CX4210 + +usb:v040Ap0566* + ID_MODEL_FROM_DATABASE=CX4300 + +usb:v040Ap0567* + ID_MODEL_FROM_DATABASE=LS753 + +usb:v040Ap0568* + ID_MODEL_FROM_DATABASE=LS443 + +usb:v040Ap0569* + ID_MODEL_FROM_DATABASE=LS663 + +usb:v040Ap0570* + ID_MODEL_FROM_DATABASE=DX6340 + +usb:v040Ap0571* + ID_MODEL_FROM_DATABASE=CX6330 + +usb:v040Ap0572* + ID_MODEL_FROM_DATABASE=DX6440 + +usb:v040Ap0573* + ID_MODEL_FROM_DATABASE=CX6230 + +usb:v040Ap0574* + ID_MODEL_FROM_DATABASE=CX6200 + +usb:v040Ap0575* + ID_MODEL_FROM_DATABASE=DX6490 + +usb:v040Ap0576* + ID_MODEL_FROM_DATABASE=DX4530 + +usb:v040Ap0577* + ID_MODEL_FROM_DATABASE=DX7630 + +usb:v040Ap0578* + ID_MODEL_FROM_DATABASE=CX7300/CX7310 + +usb:v040Ap0579* + ID_MODEL_FROM_DATABASE=CX7220 + +usb:v040Ap057A* + ID_MODEL_FROM_DATABASE=CX7330 + +usb:v040Ap057B* + ID_MODEL_FROM_DATABASE=CX7430 + +usb:v040Ap057C* + ID_MODEL_FROM_DATABASE=CX7530 + +usb:v040Ap057D* + ID_MODEL_FROM_DATABASE=DX7440 + +usb:v040Ap057E* + ID_MODEL_FROM_DATABASE=C300 + +usb:v040Ap057F* + ID_MODEL_FROM_DATABASE=DX7590 + +usb:v040Ap0580* + ID_MODEL_FROM_DATABASE=Z730 + +usb:v040Ap0581* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0582* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0583* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0584* + ID_MODEL_FROM_DATABASE=CX6445 + +usb:v040Ap0585* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0586* + ID_MODEL_FROM_DATABASE=CX7525 + +usb:v040Ap0587* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0588* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0589* + ID_MODEL_FROM_DATABASE=EasyShare C360 + +usb:v040Ap058A* + ID_MODEL_FROM_DATABASE=C310 + +usb:v040Ap058B* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap058C* + ID_MODEL_FROM_DATABASE=C330 + +usb:v040Ap058D* + ID_MODEL_FROM_DATABASE=C340 + +usb:v040Ap058E* + ID_MODEL_FROM_DATABASE=V530 + +usb:v040Ap058F* + ID_MODEL_FROM_DATABASE=V550 + +usb:v040Ap0590* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0591* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0592* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0593* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0594* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0595* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0596* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0597* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap0598* + ID_MODEL_FROM_DATABASE=EASYSHARE M1033 digital camera + +usb:v040Ap0599* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059A* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059B* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059C* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059D* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059E* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap059F* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A0* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A1* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A2* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A3* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A4* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A5* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A6* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A7* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A8* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05A9* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AA* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AB* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AC* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AD* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AE* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05AF* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B0* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B1* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B2* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B3* + ID_MODEL_FROM_DATABASE=EasyShare Z710 Camera + +usb:v040Ap05B4* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B5* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B6* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B7* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B8* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05B9* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BA* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BB* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BC* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BD* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BE* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05BF* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C0* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C1* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C2* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C3* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C4* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C5* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v040Ap05C8* + ID_MODEL_FROM_DATABASE=EASYSHARE Z1485 IS Digital Camera + +usb:v040Ap05D3* + ID_MODEL_FROM_DATABASE=EasyShare M320 Camera + +usb:v040Ap05D4* + ID_MODEL_FROM_DATABASE=EasyShare C180 Digital Camera + +usb:v040Ap1001* + ID_MODEL_FROM_DATABASE=EasyShare SV811 Digital Picture Frame + +usb:v040Ap4000* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v040Ap4021* + ID_MODEL_FROM_DATABASE=Photo Printer 6800 + +usb:v040Ap4022* + ID_MODEL_FROM_DATABASE=1400 Digital Photo Printer + +usb:v040Ap4034* + ID_MODEL_FROM_DATABASE=805 Photo Printer + +usb:v040Ap4056* + ID_MODEL_FROM_DATABASE=ESP 7200 Series AiO + +usb:v040Ap4109* + ID_MODEL_FROM_DATABASE=EasyShare Printer Dock Series 3 + +usb:v040Ap410D* + ID_MODEL_FROM_DATABASE=EasyShare G600 Printer Dock + +usb:v040Ap5010* + ID_MODEL_FROM_DATABASE=Wireless Adapter + +usb:v040Ap5012* + ID_MODEL_FROM_DATABASE=DBT-220 Bluetooth Adapter + +usb:v040Ap6001* + ID_MODEL_FROM_DATABASE=i30 + +usb:v040Ap6002* + ID_MODEL_FROM_DATABASE=i40 + +usb:v040Ap6003* + ID_MODEL_FROM_DATABASE=i50 + +usb:v040Ap6004* + ID_MODEL_FROM_DATABASE=i60 + +usb:v040Ap6005* + ID_MODEL_FROM_DATABASE=i80 + +usb:v040B* + ID_VENDOR_FROM_DATABASE=Weltrend Semiconductor + +usb:v040Bp0A68* + ID_MODEL_FROM_DATABASE=Func MS-3 gaming mouse [WT6573F MCU] + +usb:v040Bp6510* + ID_MODEL_FROM_DATABASE=Weltrend Bar Code Reader + +usb:v040Bp6520* + ID_MODEL_FROM_DATABASE=XBOX Xploder + +usb:v040Bp6533* + ID_MODEL_FROM_DATABASE=Speed-Link Competition Pro + +usb:v040Bp6543* + ID_MODEL_FROM_DATABASE=Manhattan Magnetic Card Strip Reader + +usb:v040C* + ID_VENDOR_FROM_DATABASE=VTech Computers, Ltd + +usb:v040D* + ID_VENDOR_FROM_DATABASE=VIA Technologies, Inc. + +usb:v040Dp3184* + ID_MODEL_FROM_DATABASE=VNT VT6656 USB-802.11 Wireless LAN Adapter + +usb:v040Dp6205* + ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader + +usb:v040E* + ID_VENDOR_FROM_DATABASE=MCCI + +usb:v040F* + ID_VENDOR_FROM_DATABASE=Echo Speech Corp. + +usb:v0411* + ID_VENDOR_FROM_DATABASE=BUFFALO INC. (formerly MelCo., Inc.) + +usb:v0411p0001* + ID_MODEL_FROM_DATABASE=LUA-TX Ethernet [pegasus] + +usb:v0411p0005* + ID_MODEL_FROM_DATABASE=LUA-TX Ethernet + +usb:v0411p0006* + ID_MODEL_FROM_DATABASE=WLI-USB-L11 Wireless LAN Adapter + +usb:v0411p0009* + ID_MODEL_FROM_DATABASE=LUA2-TX Ethernet + +usb:v0411p000B* + ID_MODEL_FROM_DATABASE=WLI-USB-L11G-WR Wireless LAN Adapter + +usb:v0411p000D* + ID_MODEL_FROM_DATABASE=WLI-USB-L11G Wireless LAN Adapter + +usb:v0411p0012* + ID_MODEL_FROM_DATABASE=LUA-KTX Ethernet + +usb:v0411p0013* + ID_MODEL_FROM_DATABASE=USB2-IDE Adapter + +usb:v0411p0016* + ID_MODEL_FROM_DATABASE=WLI-USB-S11 802.11b Adapter + +usb:v0411p0018* + ID_MODEL_FROM_DATABASE=USB2-IDE Adapter + +usb:v0411p001C* + ID_MODEL_FROM_DATABASE=USB-IDE Bridge: DUB-PxxG + +usb:v0411p0027* + ID_MODEL_FROM_DATABASE=WLI-USB-KS11G 802.11b Adapter + +usb:v0411p002A* + ID_MODEL_FROM_DATABASE=SMSC USB97C202 "HD-HB300V2-EU" + +usb:v0411p003D* + ID_MODEL_FROM_DATABASE=LUA-U2-KTX Ethernet + +usb:v0411p0044* + ID_MODEL_FROM_DATABASE=WLI-USB-KB11 Wireless LAN Adapter + +usb:v0411p004B* + ID_MODEL_FROM_DATABASE=WLI-USB-G54 802.11g Adapter [Broadcom 4320 USB] + +usb:v0411p004D* + ID_MODEL_FROM_DATABASE=WLI-USB-B11 Wireless LAN Adapter + +usb:v0411p0050* + ID_MODEL_FROM_DATABASE=WLI2-USB2-G54 Wireless LAN Adapter + +usb:v0411p005E* + ID_MODEL_FROM_DATABASE=WLI-U2-KG54-YB WLAN + +usb:v0411p0065* + ID_MODEL_FROM_DATABASE=Python2 WDM Encoder + +usb:v0411p0066* + ID_MODEL_FROM_DATABASE=WLI-U2-KG54 WLAN + +usb:v0411p0067* + ID_MODEL_FROM_DATABASE=WLI-U2-KG54-AI WLAN + +usb:v0411p006E* + ID_MODEL_FROM_DATABASE=LUA-U2-GT 10/100/1000 Ethernet Adapter + +usb:v0411p0089* + ID_MODEL_FROM_DATABASE=RUF-C/U2 Flash Drive + +usb:v0411p008B* + ID_MODEL_FROM_DATABASE=Nintendo Wi-Fi + +usb:v0411p0091* + ID_MODEL_FROM_DATABASE=WLI-U2-KAMG54 Wireless LAN Adapter + +usb:v0411p0092* + ID_MODEL_FROM_DATABASE=WLI-U2-KAMG54 Bootloader + +usb:v0411p0097* + ID_MODEL_FROM_DATABASE=WLI-U2-KG54-BB + +usb:v0411p00A9* + ID_MODEL_FROM_DATABASE=WLI-U2-AMG54HP Wireless LAN Adapter + +usb:v0411p00AA* + ID_MODEL_FROM_DATABASE=WLI-U2-AMG54HP Bootloader + +usb:v0411p00B3* + ID_MODEL_FROM_DATABASE=PC-OP-RS1 RemoteStation + +usb:v0411p00BC* + ID_MODEL_FROM_DATABASE=WLI-U2-KG125S 802.11g Adapter [Broadcom 4320 USB] + +usb:v0411p00CA* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0411p00CB* + ID_MODEL_FROM_DATABASE=WLI-U2-G300N 802.11n Adapter + +usb:v0411p00D8* + ID_MODEL_FROM_DATABASE=WLI-U2-SG54HP + +usb:v0411p00D9* + ID_MODEL_FROM_DATABASE=WLI-U2-G54HP + +usb:v0411p00DA* + ID_MODEL_FROM_DATABASE=WLI-U2-KG54L 802.11bg [ZyDAS ZD1211B] + +usb:v0411p00DB* + ID_MODEL_FROM_DATABASE=External Hard Drive HD-PF32OU2 [Buffalo Ministation] + +usb:v0411p00E8* + ID_MODEL_FROM_DATABASE=WLI-UC-G300N Wireless LAN Adapter [Ralink RT2870] + +usb:v0411p0105* + ID_MODEL_FROM_DATABASE=External Hard Drive HD-CEU2 [Drive Station] + +usb:v0411p012E* + ID_MODEL_FROM_DATABASE=WLI-UC-AG300N Wireless LAN Adapter + +usb:v0411p0148* + ID_MODEL_FROM_DATABASE=WLI-UC-G300HP Wireless LAN Adapter + +usb:v0411p0150* + ID_MODEL_FROM_DATABASE=WLP-UC-AG300 Wireless LAN Adapter + +usb:v0411p0157* + ID_MODEL_FROM_DATABASE=External Hard Drive HD-PEU2 + +usb:v0411p0158* + ID_MODEL_FROM_DATABASE=WLI-UC-GNHP Wireless LAN Adapter + +usb:v0411p015D* + ID_MODEL_FROM_DATABASE=WLI-UC-GN Wireless LAN Adapter [Ralink RT3070] + +usb:v0411p016F* + ID_MODEL_FROM_DATABASE=WLI-UC-G301N Wireless LAN Adapter [Ralink RT3072] + +usb:v0411p017F* + ID_MODEL_FROM_DATABASE=Sony UWA-BR100 802.11abgn Wireless Adapter [Atheros AR7010+AR9280] + +usb:v0411p019E* + ID_MODEL_FROM_DATABASE=WLI-UC-GNP Wireless LAN Adapter + +usb:v0411p01A1* + ID_MODEL_FROM_DATABASE=MiniStation Metro + +usb:v0411p01A2* + ID_MODEL_FROM_DATABASE=WLI-UC-GNM Wireless LAN Adapter [Ralink RT8070] + +usb:v0411p01DC* + ID_MODEL_FROM_DATABASE=Ultra-Slim Portable DVD Writer (DVSM-PC58U2V) + +usb:v0411p01DE* + ID_MODEL_FROM_DATABASE=External Hard Drive HD-PCTU3 [Buffalo MiniStation] + +usb:v0411p01EE* + ID_MODEL_FROM_DATABASE=WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070] + +usb:v0411p01F1* + ID_MODEL_FROM_DATABASE=SATA Adapter [HD-LBU3] + +usb:v0411p01FD* + ID_MODEL_FROM_DATABASE=WLI-UC-G450 Wireless LAN Adapter + +usb:v0412* + ID_VENDOR_FROM_DATABASE=Award Software International + +usb:v0413* + ID_VENDOR_FROM_DATABASE=Leadtek Research, Inc. + +usb:v0413p1310* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC + FM + +usb:v0413p1311* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC + MTS + FM + +usb:v0413p1312* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL BG + FM + +usb:v0413p1313* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL BG+TXT + FM + +usb:v0413p1314* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL I + +usb:v0413p1315* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL I+TXT + +usb:v0413p1316* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL DK + +usb:v0413p1317* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL DK+TXT + +usb:v0413p1318* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL I/DK + FM + +usb:v0413p1319* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL N + FM + +usb:v0413p131A* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM LL + +usb:v0413p131B* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM LL+TXT + +usb:v0413p131C* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM DK + +usb:v0413p131D* + ID_MODEL_FROM_DATABASE=WinFast TV - SECAM DK + TXT + FM + +usb:v0413p131E* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC Japan + FM + +usb:v0413p1320* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC + +usb:v0413p1321* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC + MTS + +usb:v0413p1322* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL BG + +usb:v0413p1323* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL BG+TXT + +usb:v0413p1324* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL I + +usb:v0413p1325* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL I+TXT + +usb:v0413p1326* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL DK + +usb:v0413p1327* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP PAL DK+TXT + +usb:v0413p1328* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL I/DK + +usb:v0413p1329* + ID_MODEL_FROM_DATABASE=WinFast TV - PAL N + +usb:v0413p132A* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM LL + +usb:v0413p132B* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM LL+TXT + +usb:v0413p132C* + ID_MODEL_FROM_DATABASE=WinFast TV Audio - PHP SECAM DK + +usb:v0413p132D* + ID_MODEL_FROM_DATABASE=WinFast TV - SECAM DK + TXT + +usb:v0413p132E* + ID_MODEL_FROM_DATABASE=WinFast TV - NTSC Japan + +usb:v0413p6023* + ID_MODEL_FROM_DATABASE=EMP Audio Device + +usb:v0413p6024* + ID_MODEL_FROM_DATABASE=WinFast PalmTop/Novo TV Video + +usb:v0413p6025* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle (cold state) + +usb:v0413p6026* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle (warm state) + +usb:v0413p6029* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle Gold + +usb:v0413p6125* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle + +usb:v0413p6126* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle BDA Driver + +usb:v0413p6A03* + ID_MODEL_FROM_DATABASE=RTL2832 [WinFast DTV Dongle Mini] + +usb:v0413p6F00* + ID_MODEL_FROM_DATABASE=WinFast DTV Dongle (STK7700P based) + +usb:v0414* + ID_VENDOR_FROM_DATABASE=Giga-Byte Technology Co., Ltd + +usb:v0416* + ID_VENDOR_FROM_DATABASE=Winbond Electronics Corp. + +usb:v0416p0035* + ID_MODEL_FROM_DATABASE=W89C35 802.11bg WLAN Adapter + +usb:v0416p0101* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0416p0961* + ID_MODEL_FROM_DATABASE=AVL Flash Card Reader + +usb:v0416p3810* + ID_MODEL_FROM_DATABASE=Smart Card Controller + +usb:v0416p3811* + ID_MODEL_FROM_DATABASE=Generic Controller - Single interface + +usb:v0416p3812* + ID_MODEL_FROM_DATABASE=Smart Card Controller_2Interface + +usb:v0416p3813* + ID_MODEL_FROM_DATABASE=Panel Display + +usb:v0416p5011* + ID_MODEL_FROM_DATABASE=Virtual Com Port + +usb:v0416p5518* + ID_MODEL_FROM_DATABASE=4-Port Hub + +usb:v0416p551A* + ID_MODEL_FROM_DATABASE=PC Sync Keypad + +usb:v0416p551B* + ID_MODEL_FROM_DATABASE=PC Async Keypad + +usb:v0416p551C* + ID_MODEL_FROM_DATABASE=Sync Tenkey + +usb:v0416p551D* + ID_MODEL_FROM_DATABASE=Async Tenkey + +usb:v0416p551E* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0416p551F* + ID_MODEL_FROM_DATABASE=Keyboard w/ Sys and Media + +usb:v0416p5521* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0416p6481* + ID_MODEL_FROM_DATABASE=16-bit Scanner + +usb:v0416p7721* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v0416p7722* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v0416p7723* + ID_MODEL_FROM_DATABASE=SD Card Reader + +usb:v0417* + ID_VENDOR_FROM_DATABASE=Symbios Logic + +usb:v0418* + ID_VENDOR_FROM_DATABASE=AST Research + +usb:v0419* + ID_VENDOR_FROM_DATABASE=Samsung Info. Systems America, Inc. + +usb:v0419p0001* + ID_MODEL_FROM_DATABASE=IrDA Remote Controller / Creative Cordless Mouse + +usb:v0419p0600* + ID_MODEL_FROM_DATABASE=Desktop Wireless 6000 + +usb:v0419p3001* + ID_MODEL_FROM_DATABASE=Xerox P1202 Laser Printer + +usb:v0419p3003* + ID_MODEL_FROM_DATABASE=Olivetti PG L12L + +usb:v0419p3201* + ID_MODEL_FROM_DATABASE=Docuprint P8ex + +usb:v0419p3404* + ID_MODEL_FROM_DATABASE=SCX-5x12 series + +usb:v0419p3406* + ID_MODEL_FROM_DATABASE=MFP 830 series + +usb:v0419p3407* + ID_MODEL_FROM_DATABASE=ML-912 + +usb:v0419p3601* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0419p3602* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0419p4602* + ID_MODEL_FROM_DATABASE=Remote NDIS Network Device + +usb:v0419p8001* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0419p8002* + ID_MODEL_FROM_DATABASE=SyncMaster HID Monitor Control + +usb:v0419pAA03* + ID_MODEL_FROM_DATABASE=SDAS-3 MP3 Player + +usb:v041A* + ID_VENDOR_FROM_DATABASE=Phoenix Technologies, Ltd + +usb:v041B* + ID_VENDOR_FROM_DATABASE=d'TV + +usb:v041D* + ID_VENDOR_FROM_DATABASE=S3, Inc. + +usb:v041E* + ID_VENDOR_FROM_DATABASE=Creative Technology, Ltd + +usb:v041Ep1002* + ID_MODEL_FROM_DATABASE=Nomad II + +usb:v041Ep1003* + ID_MODEL_FROM_DATABASE=Blaster GamePad Cobra + +usb:v041Ep1050* + ID_MODEL_FROM_DATABASE=GamePad Cobra + +usb:v041Ep1053* + ID_MODEL_FROM_DATABASE=Mouse Gamer HD7600L + +usb:v041Ep200C* + ID_MODEL_FROM_DATABASE=MuVo V100 + +usb:v041Ep2020* + ID_MODEL_FROM_DATABASE=Zen X-Fi 2 + +usb:v041Ep2029* + ID_MODEL_FROM_DATABASE=ZiiO + +usb:v041Ep2801* + ID_MODEL_FROM_DATABASE=Prodikeys PC-MIDI multifunction keyboard + +usb:v041Ep3000* + ID_MODEL_FROM_DATABASE=SoundBlaster Extigy + +usb:v041Ep3002* + ID_MODEL_FROM_DATABASE=SB External Composite Device + +usb:v041Ep3010* + ID_MODEL_FROM_DATABASE=SoundBlaster MP3+ + +usb:v041Ep3014* + ID_MODEL_FROM_DATABASE=SB External Composite Device + +usb:v041Ep3015* + ID_MODEL_FROM_DATABASE=Sound Blaster Digital Music LX + +usb:v041Ep3020* + ID_MODEL_FROM_DATABASE=SoundBlaster Audigy 2 NX + +usb:v041Ep3030* + ID_MODEL_FROM_DATABASE=SB External Composite Device + +usb:v041Ep3040* + ID_MODEL_FROM_DATABASE=SoundBlaster Live! 24-bit External SB0490 + +usb:v041Ep3060* + ID_MODEL_FROM_DATABASE=Sound Blaster Audigy 2 ZS External + +usb:v041Ep3061* + ID_MODEL_FROM_DATABASE=SoundBlaster Audigy 2 ZS Video Editor + +usb:v041Ep3090* + ID_MODEL_FROM_DATABASE=Sound Blaster Digital Music SX + +usb:v041Ep30D3* + ID_MODEL_FROM_DATABASE=Sound Blaster Play! + +usb:v041Ep3121* + ID_MODEL_FROM_DATABASE=WoW tap chat + +usb:v041Ep3220* + ID_MODEL_FROM_DATABASE=Sound Blaster Tactic(3D) Sigma sound card + +usb:v041Ep3F00* + ID_MODEL_FROM_DATABASE=E-Mu Xboard 25 MIDI Controller + +usb:v041Ep3F02* + ID_MODEL_FROM_DATABASE=E-Mu 0202 + +usb:v041Ep3F04* + ID_MODEL_FROM_DATABASE=E-Mu 0404 + +usb:v041Ep3F07* + ID_MODEL_FROM_DATABASE=E-Mu Xmidi 1x1 + +usb:v041Ep4003* + ID_MODEL_FROM_DATABASE=VideoBlaster Webcam Go Plus [W9967CF] + +usb:v041Ep4004* + ID_MODEL_FROM_DATABASE=Nomad II MG + +usb:v041Ep4005* + ID_MODEL_FROM_DATABASE=Webcam Blaster Go ES + +usb:v041Ep4007* + ID_MODEL_FROM_DATABASE=Go Mini + +usb:v041Ep400A* + ID_MODEL_FROM_DATABASE=PC-Cam 300 + +usb:v041Ep400B* + ID_MODEL_FROM_DATABASE=PC-Cam 600 + +usb:v041Ep400C* + ID_MODEL_FROM_DATABASE=Webcam 5 [pwc] + +usb:v041Ep400D* + ID_MODEL_FROM_DATABASE=Webcam PD1001 + +usb:v041Ep400F* + ID_MODEL_FROM_DATABASE=PC-CAM 550 (Composite) + +usb:v041Ep4011* + ID_MODEL_FROM_DATABASE=Webcam PRO eX + +usb:v041Ep4012* + ID_MODEL_FROM_DATABASE=PC-CAM350 + +usb:v041Ep4013* + ID_MODEL_FROM_DATABASE=PC-Cam 750 + +usb:v041Ep4015* + ID_MODEL_FROM_DATABASE=CardCam Value + +usb:v041Ep4016* + ID_MODEL_FROM_DATABASE=CardCam + +usb:v041Ep4017* + ID_MODEL_FROM_DATABASE=Webcam Mobile [PD1090] + +usb:v041Ep4018* + ID_MODEL_FROM_DATABASE=Webcam Vista [PD1100] + +usb:v041Ep4019* + ID_MODEL_FROM_DATABASE=Audio Device + +usb:v041Ep401A* + ID_MODEL_FROM_DATABASE=Webcam Vista [PD1100] + +usb:v041Ep401C* + ID_MODEL_FROM_DATABASE=Webcam NX [PD1110] + +usb:v041Ep401D* + ID_MODEL_FROM_DATABASE=Webcam NX Ultra + +usb:v041Ep401E* + ID_MODEL_FROM_DATABASE=Webcam NX Pro + +usb:v041Ep401F* + ID_MODEL_FROM_DATABASE=Webcam Notebook [PD1171] + +usb:v041Ep4020* + ID_MODEL_FROM_DATABASE=Webcam NX + +usb:v041Ep4021* + ID_MODEL_FROM_DATABASE=Webcam NX Ultra + +usb:v041Ep4022* + ID_MODEL_FROM_DATABASE=Webcam NX Pro + +usb:v041Ep4028* + ID_MODEL_FROM_DATABASE=Vista Plus cam [VF0090] + +usb:v041Ep4029* + ID_MODEL_FROM_DATABASE=Webcam Live! + +usb:v041Ep402F* + ID_MODEL_FROM_DATABASE=DC-CAM 3000Z + +usb:v041Ep4034* + ID_MODEL_FROM_DATABASE=Webcam Instant + +usb:v041Ep4035* + ID_MODEL_FROM_DATABASE=Webcam Instant + +usb:v041Ep4036* + ID_MODEL_FROM_DATABASE=Webcam Live!/Live! Pro + +usb:v041Ep4037* + ID_MODEL_FROM_DATABASE=Webcam Live! + +usb:v041Ep4038* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam [PC370R] + +usb:v041Ep4039* + ID_MODEL_FROM_DATABASE=Webcam Live! Effects + +usb:v041Ep403A* + ID_MODEL_FROM_DATABASE=Webcam NX Pro 2 + +usb:v041Ep403B* + ID_MODEL_FROM_DATABASE=Creative Webcam Vista [VF0010] + +usb:v041Ep403C* + ID_MODEL_FROM_DATABASE=Webcam Live! Ultra + +usb:v041Ep403D* + ID_MODEL_FROM_DATABASE=Webcam Notebook Ultra + +usb:v041Ep403E* + ID_MODEL_FROM_DATABASE=Webcam Vista Plus + +usb:v041Ep4041* + ID_MODEL_FROM_DATABASE=Webcam Live! Motion + +usb:v041Ep4043* + ID_MODEL_FROM_DATABASE=Vibra Plus Webcam + +usb:v041Ep4045* + ID_MODEL_FROM_DATABASE=Live! Cam Voice + +usb:v041Ep4049* + ID_MODEL_FROM_DATABASE=Live! Cam Voice + +usb:v041Ep4051* + ID_MODEL_FROM_DATABASE=Live! Cam Notebook Pro [VF0250] + +usb:v041Ep4052* + ID_MODEL_FROM_DATABASE=Live! Cam Vista IM + +usb:v041Ep4053* + ID_MODEL_FROM_DATABASE=Live! Cam Video IM + +usb:v041Ep4054* + ID_MODEL_FROM_DATABASE=Live! Cam Video IM + +usb:v041Ep4055* + ID_MODEL_FROM_DATABASE=Live! Cam Video IM Pro + +usb:v041Ep4056* + ID_MODEL_FROM_DATABASE=Live! Cam Video IM Pro + +usb:v041Ep4057* + ID_MODEL_FROM_DATABASE=Live! Cam Optia + +usb:v041Ep4058* + ID_MODEL_FROM_DATABASE=Live! Cam Optia AF + +usb:v041Ep405F* + ID_MODEL_FROM_DATABASE=WebCam Vista (VF0330) + +usb:v041Ep4061* + ID_MODEL_FROM_DATABASE=Live! Cam Notebook Pro [VF0400] + +usb:v041Ep4063* + ID_MODEL_FROM_DATABASE=Live! Cam Video IM Pro + +usb:v041Ep4068* + ID_MODEL_FROM_DATABASE=Live! Cam Notebook [VF0470] + +usb:v041Ep406C* + ID_MODEL_FROM_DATABASE=Live! Cam Sync [VF0520] + +usb:v041Ep4083* + ID_MODEL_FROM_DATABASE=Live! Cam Socialize [VF0640] + +usb:v041Ep4087* + ID_MODEL_FROM_DATABASE=Live! Cam Socialize HD 1080 [VF0680] + +usb:v041Ep4088* + ID_MODEL_FROM_DATABASE=Live! Cam Chat HD [VF0700] + +usb:v041Ep4100* + ID_MODEL_FROM_DATABASE=Nomad Jukebox 2 + +usb:v041Ep4101* + ID_MODEL_FROM_DATABASE=Nomad Jukebox 3 + +usb:v041Ep4102* + ID_MODEL_FROM_DATABASE=NOMAD MuVo^2 + +usb:v041Ep4106* + ID_MODEL_FROM_DATABASE=Nomad MuVo + +usb:v041Ep4107* + ID_MODEL_FROM_DATABASE=NOMAD MuVo + +usb:v041Ep4108* + ID_MODEL_FROM_DATABASE=Nomad Jukebox Zen + +usb:v041Ep4109* + ID_MODEL_FROM_DATABASE=Nomad Jukebox Zen NX + +usb:v041Ep410B* + ID_MODEL_FROM_DATABASE=Nomad Jukebox Zen USB 2.0 + +usb:v041Ep410C* + ID_MODEL_FROM_DATABASE=Nomad MuVo NX + +usb:v041Ep410F* + ID_MODEL_FROM_DATABASE=NOMAD MuVo^2 (Flash) + +usb:v041Ep4110* + ID_MODEL_FROM_DATABASE=Nomad Jukebox Zen Xtra + +usb:v041Ep4111* + ID_MODEL_FROM_DATABASE=Dell Digital Jukebox + +usb:v041Ep4116* + ID_MODEL_FROM_DATABASE=MuVo^2 + +usb:v041Ep4117* + ID_MODEL_FROM_DATABASE=Nomad MuVo TX + +usb:v041Ep411B* + ID_MODEL_FROM_DATABASE=Zen Touch + +usb:v041Ep411C* + ID_MODEL_FROM_DATABASE=Nomad MuVo USB 2.0 + +usb:v041Ep411D* + ID_MODEL_FROM_DATABASE=Zen + +usb:v041Ep411E* + ID_MODEL_FROM_DATABASE=Zen Micro + +usb:v041Ep4120* + ID_MODEL_FROM_DATABASE=Nomad MuVo TX FM + +usb:v041Ep4123* + ID_MODEL_FROM_DATABASE=Zen Portable Media Center + +usb:v041Ep4124* + ID_MODEL_FROM_DATABASE=MuVo^2 FM (uHDD) + +usb:v041Ep4126* + ID_MODEL_FROM_DATABASE=Dell DJ (2nd gen) + +usb:v041Ep4127* + ID_MODEL_FROM_DATABASE=Dell DJ + +usb:v041Ep4128* + ID_MODEL_FROM_DATABASE=NOMAD Jukebox Zen Xtra (mtp) + +usb:v041Ep412B* + ID_MODEL_FROM_DATABASE=MuVo N200 with FM radio + +usb:v041Ep412F* + ID_MODEL_FROM_DATABASE=Dell Digital Jukebox 2.Gen + +usb:v041Ep4130* + ID_MODEL_FROM_DATABASE=Zen Micro (mtp) + +usb:v041Ep4131* + ID_MODEL_FROM_DATABASE=DAP-HD0014 [Zen Touch] (MTP) + +usb:v041Ep4133* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v041Ep4134* + ID_MODEL_FROM_DATABASE=Zen Neeon + +usb:v041Ep4136* + ID_MODEL_FROM_DATABASE=Zen Sleek + +usb:v041Ep4137* + ID_MODEL_FROM_DATABASE=Zen Sleek (mtp) + +usb:v041Ep4139* + ID_MODEL_FROM_DATABASE=Zen Nano Plus + +usb:v041Ep413C* + ID_MODEL_FROM_DATABASE=Zen MicroPhoto + +usb:v041Ep4150* + ID_MODEL_FROM_DATABASE=Zen V (MTP) + +usb:v041Ep4151* + ID_MODEL_FROM_DATABASE=Zen Vision:M (mtp) + +usb:v041Ep4152* + ID_MODEL_FROM_DATABASE=Zen V Plus + +usb:v041Ep4153* + ID_MODEL_FROM_DATABASE=Zen Vision W + +usb:v041Ep4154* + ID_MODEL_FROM_DATABASE=Zen Stone + +usb:v041Ep4155* + ID_MODEL_FROM_DATABASE=Zen Stone plus + +usb:v041Ep4157* + ID_MODEL_FROM_DATABASE=Zen (MTP) + +usb:v041Ep500F* + ID_MODEL_FROM_DATABASE=Broadband Blaster 8012U-V + +usb:v041Ep5015* + ID_MODEL_FROM_DATABASE=TECOM Bluetooth Device + +usb:v041EpFFFF* + ID_MODEL_FROM_DATABASE=Webcam Live! Ultra + +usb:v041F* + ID_VENDOR_FROM_DATABASE=LCS Telegraphics + +usb:v0420* + ID_VENDOR_FROM_DATABASE=Chips and Technologies + +usb:v0420p1307* + ID_MODEL_FROM_DATABASE=Celly SIM Card Reader + +usb:v0421* + ID_VENDOR_FROM_DATABASE=Nokia Mobile Phones + +usb:v0421p0001* + ID_MODEL_FROM_DATABASE=E61i (PC Suite mode) + +usb:v0421p0018* + ID_MODEL_FROM_DATABASE=6288 GSM Smartphone + +usb:v0421p0019* + ID_MODEL_FROM_DATABASE=6288 GSM Smartphone (imaging mode) + +usb:v0421p001A* + ID_MODEL_FROM_DATABASE=6288 GSM Smartphone (file transfer mode) + +usb:v0421p0024* + ID_MODEL_FROM_DATABASE=5610 XpressMusic (Storage mode) + +usb:v0421p0025* + ID_MODEL_FROM_DATABASE=5610 XpressMusic (PC Suite mode) + +usb:v0421p0028* + ID_MODEL_FROM_DATABASE=5610 XpressMusic (Imaging mode) + +usb:v0421p002D* + ID_MODEL_FROM_DATABASE=6120 Phone (Mass storage mode) + +usb:v0421p002E* + ID_MODEL_FROM_DATABASE=6120 Phone (Media-Player mode) + +usb:v0421p002F* + ID_MODEL_FROM_DATABASE=6120 Phone (PC-Suite mode) + +usb:v0421p0042* + ID_MODEL_FROM_DATABASE=E51 (PC Suite mode) + +usb:v0421p0064* + ID_MODEL_FROM_DATABASE=3109c GSM Phone + +usb:v0421p006B* + ID_MODEL_FROM_DATABASE=5310 Xpress Music (PC Suite mode) + +usb:v0421p006C* + ID_MODEL_FROM_DATABASE=5310 Xpress music (Storage mode) + +usb:v0421p006D* + ID_MODEL_FROM_DATABASE=N95 (Storage mode) + +usb:v0421p006E* + ID_MODEL_FROM_DATABASE=N95 (Multimedia mode) + +usb:v0421p006F* + ID_MODEL_FROM_DATABASE=N95 (Printing mode) + +usb:v0421p0070* + ID_MODEL_FROM_DATABASE=N95 (PC Suite mode) + +usb:v0421p0096* + ID_MODEL_FROM_DATABASE=N810 Internet Tablet + +usb:v0421p00AA* + ID_MODEL_FROM_DATABASE=E71 (Mass storage mode) + +usb:v0421p00AB* + ID_MODEL_FROM_DATABASE=E71 (PC Suite mode) + +usb:v0421p00E4* + ID_MODEL_FROM_DATABASE=E71 (Media transfer mode) + +usb:v0421p0103* + ID_MODEL_FROM_DATABASE=ADL Flashing Engine AVALON Parent + +usb:v0421p0104* + ID_MODEL_FROM_DATABASE=ADL Re-Flashing Engine Parent + +usb:v0421p0105* + ID_MODEL_FROM_DATABASE=Nokia Firmware Upgrade Mode + +usb:v0421p0106* + ID_MODEL_FROM_DATABASE=ROM Parent + +usb:v0421p0154* + ID_MODEL_FROM_DATABASE=5800 XpressMusic (PC Suite mode) + +usb:v0421p0155* + ID_MODEL_FROM_DATABASE=5800 XpressMusic (Multimedia mode) + +usb:v0421p0156* + ID_MODEL_FROM_DATABASE=5800 XpressMusic (Storage mode) + +usb:v0421p0157* + ID_MODEL_FROM_DATABASE=5800 XpressMusic (Imaging mode) + +usb:v0421p0199* + ID_MODEL_FROM_DATABASE=6700 Classic (msc) + +usb:v0421p019A* + ID_MODEL_FROM_DATABASE=6700 Classic (PC Suite) + +usb:v0421p019B* + ID_MODEL_FROM_DATABASE=6700 Classic (mtp) + +usb:v0421p01B0* + ID_MODEL_FROM_DATABASE=6303 classic Phone (PC Suite mode) + +usb:v0421p01B1* + ID_MODEL_FROM_DATABASE=6303 classic Phone (Mass storage mode) + +usb:v0421p01B2* + ID_MODEL_FROM_DATABASE=6303 classic Phone (Printing and media mode) + +usb:v0421p01C7* + ID_MODEL_FROM_DATABASE=N900 (Storage Mode) + +usb:v0421p01C8* + ID_MODEL_FROM_DATABASE=N900 (PC-Suite Mode) + +usb:v0421p0228* + ID_MODEL_FROM_DATABASE=5530 XpressMusic + +usb:v0421p023A* + ID_MODEL_FROM_DATABASE=6730 Classic + +usb:v0421p026A* + ID_MODEL_FROM_DATABASE=N97 (mass storage) + +usb:v0421p026B* + ID_MODEL_FROM_DATABASE=N97 (Multimedia) + +usb:v0421p026C* + ID_MODEL_FROM_DATABASE=N97 (PC Suite) + +usb:v0421p026D* + ID_MODEL_FROM_DATABASE=N97 (Pictures) + +usb:v0421p0295* + ID_MODEL_FROM_DATABASE=660i/6600i Slide Phone (Mass Storage) + +usb:v0421p0297* + ID_MODEL_FROM_DATABASE=660i/6600i Slide Phone (Still Image) + +usb:v0421p02E1* + ID_MODEL_FROM_DATABASE=5230 (Storage mode) + +usb:v0421p02E2* + ID_MODEL_FROM_DATABASE=5230 (Multimedia mode) + +usb:v0421p02E3* + ID_MODEL_FROM_DATABASE=5230 (PC-Suite mode) + +usb:v0421p02E4* + ID_MODEL_FROM_DATABASE=5230 (Imaging mode) + +usb:v0421p0360* + ID_MODEL_FROM_DATABASE=C1-01 Ovi Suite Mode + +usb:v0421p03A4* + ID_MODEL_FROM_DATABASE=C5 (Storage mode) + +usb:v0421p03C0* + ID_MODEL_FROM_DATABASE=C7-00 + +usb:v0421p03D1* + ID_MODEL_FROM_DATABASE=N950 + +usb:v0421p0400* + ID_MODEL_FROM_DATABASE=7600 Phone Parent + +usb:v0421p0401* + ID_MODEL_FROM_DATABASE=6650 GSM Phone + +usb:v0421p0402* + ID_MODEL_FROM_DATABASE=6255 Phone Parent + +usb:v0421p0404* + ID_MODEL_FROM_DATABASE=5510 + +usb:v0421p0405* + ID_MODEL_FROM_DATABASE=9500 GSM Communicator + +usb:v0421p0407* + ID_MODEL_FROM_DATABASE=Music Player HDR-1(tm) + +usb:v0421p040B* + ID_MODEL_FROM_DATABASE=N-Gage GSM Phone + +usb:v0421p040D* + ID_MODEL_FROM_DATABASE=6620 Phone Parent + +usb:v0421p040E* + ID_MODEL_FROM_DATABASE=6651 Phone Parent + +usb:v0421p040F* + ID_MODEL_FROM_DATABASE=6230 GSM Phone + +usb:v0421p0410* + ID_MODEL_FROM_DATABASE=6630 Imaging Smartphone + +usb:v0421p0411* + ID_MODEL_FROM_DATABASE=7610 Phone Parent + +usb:v0421p0413* + ID_MODEL_FROM_DATABASE=6260 Phone Parent + +usb:v0421p0414* + ID_MODEL_FROM_DATABASE=7370 + +usb:v0421p0415* + ID_MODEL_FROM_DATABASE=9300 GSM Smartphone + +usb:v0421p0416* + ID_MODEL_FROM_DATABASE=6170 Phone Parent + +usb:v0421p0417* + ID_MODEL_FROM_DATABASE=7270 Phone Parent + +usb:v0421p0418* + ID_MODEL_FROM_DATABASE=E70 (PC Suite mode) + +usb:v0421p0419* + ID_MODEL_FROM_DATABASE=E60 (PC Suite mode) + +usb:v0421p041A* + ID_MODEL_FROM_DATABASE=9500 GSM Communicator (RNDIS) + +usb:v0421p041B* + ID_MODEL_FROM_DATABASE=9300 GSM Smartphone (RNDIS) + +usb:v0421p041C* + ID_MODEL_FROM_DATABASE=7710 Phone Parent + +usb:v0421p041D* + ID_MODEL_FROM_DATABASE=6670 Phone Parent + +usb:v0421p041E* + ID_MODEL_FROM_DATABASE=6680 + +usb:v0421p041F* + ID_MODEL_FROM_DATABASE=6235 Phone Parent + +usb:v0421p0421* + ID_MODEL_FROM_DATABASE=3230 Phone Parent + +usb:v0421p0422* + ID_MODEL_FROM_DATABASE=6681 Phone Parent + +usb:v0421p0423* + ID_MODEL_FROM_DATABASE=6682 Phone Parent + +usb:v0421p0428* + ID_MODEL_FROM_DATABASE=6230i Modem + +usb:v0421p0429* + ID_MODEL_FROM_DATABASE=6230i MultiMedia Card + +usb:v0421p0431* + ID_MODEL_FROM_DATABASE=770 Internet Tablet + +usb:v0421p0432* + ID_MODEL_FROM_DATABASE=N90 Phone Parent + +usb:v0421p0435* + ID_MODEL_FROM_DATABASE=E70 (IP Passthrough/RNDIS mode) + +usb:v0421p0436* + ID_MODEL_FROM_DATABASE=E60 (IP Passthrough/RNDIS mode) + +usb:v0421p0437* + ID_MODEL_FROM_DATABASE=6265 Phone Parent + +usb:v0421p043A* + ID_MODEL_FROM_DATABASE=N70 USB Phone Parent + +usb:v0421p043B* + ID_MODEL_FROM_DATABASE=3155 Phone Parent + +usb:v0421p043C* + ID_MODEL_FROM_DATABASE=6155 Phone Parent + +usb:v0421p043D* + ID_MODEL_FROM_DATABASE=6270 Phone Parent + +usb:v0421p0443* + ID_MODEL_FROM_DATABASE=N70 Phone Parent + +usb:v0421p0444* + ID_MODEL_FROM_DATABASE=N91 + +usb:v0421p044C* + ID_MODEL_FROM_DATABASE=NM850iG Phone Parent + +usb:v0421p044D* + ID_MODEL_FROM_DATABASE=E61 (PC Suite mode) + +usb:v0421p044E* + ID_MODEL_FROM_DATABASE=E61 (Data Exchange mode) + +usb:v0421p044F* + ID_MODEL_FROM_DATABASE=E61 (IP Passthrough/RNDIS mode) + +usb:v0421p0453* + ID_MODEL_FROM_DATABASE=9300 Phone Parent + +usb:v0421p0456* + ID_MODEL_FROM_DATABASE=6111 Phone Parent + +usb:v0421p0457* + ID_MODEL_FROM_DATABASE=6111 Phone (Printing mode) + +usb:v0421p045A* + ID_MODEL_FROM_DATABASE=6280 Phone Parent + +usb:v0421p045D* + ID_MODEL_FROM_DATABASE=6282 Phone Parent + +usb:v0421p046E* + ID_MODEL_FROM_DATABASE=6110 Navigator + +usb:v0421p0471* + ID_MODEL_FROM_DATABASE=6110 Navigator + +usb:v0421p0485* + ID_MODEL_FROM_DATABASE=MTP Device + +usb:v0421p04B9* + ID_MODEL_FROM_DATABASE=5300 + +usb:v0421p04BC* + ID_MODEL_FROM_DATABASE=5200 (Nokia mode) + +usb:v0421p04BD* + ID_MODEL_FROM_DATABASE=5200 (Storage mode) + +usb:v0421p04BE* + ID_MODEL_FROM_DATABASE=5200 (MTP mode) + +usb:v0421p04C3* + ID_MODEL_FROM_DATABASE=N800 Internet Tablet + +usb:v0421p04CE* + ID_MODEL_FROM_DATABASE=E90 Communicator (PC Suite mode) + +usb:v0421p04CF* + ID_MODEL_FROM_DATABASE=E90 Communicator (Storage mode) + +usb:v0421p04F0* + ID_MODEL_FROM_DATABASE=Nokia N95 (PC Suite mode) + +usb:v0421p04F9* + ID_MODEL_FROM_DATABASE=6300 (PC Suite mode) + +usb:v0421p0508* + ID_MODEL_FROM_DATABASE=E65 (PC Suite mode) + +usb:v0421p0509* + ID_MODEL_FROM_DATABASE=E65 (Storage mode) + +usb:v0421p0518* + ID_MODEL_FROM_DATABASE=N9 Phone + +usb:v0421p0600* + ID_MODEL_FROM_DATABASE=Digital Pen SU-1B + +usb:v0421p0610* + ID_MODEL_FROM_DATABASE=CS-15 (Internet Stick 3G modem) + +usb:v0421p0661* + ID_MODEL_FROM_DATABASE=Lumia 920 + +usb:v0421p0800* + ID_MODEL_FROM_DATABASE=Connectivity Cable DKU-5 + +usb:v0421p0801* + ID_MODEL_FROM_DATABASE=Data Cable DKU-6 + +usb:v0421p0802* + ID_MODEL_FROM_DATABASE=CA-42 Phone Parent + +usb:v0422* + ID_VENDOR_FROM_DATABASE=ADI Systems, Inc. + +usb:v0423* + ID_VENDOR_FROM_DATABASE=Computer Access Technology Corp. + +usb:v0423p000A* + ID_MODEL_FROM_DATABASE=NetMate Ethernet + +usb:v0423p000C* + ID_MODEL_FROM_DATABASE=NetMate2 Ethernet + +usb:v0423p000D* + ID_MODEL_FROM_DATABASE=USB Chief Analyzer + +usb:v0423p0100* + ID_MODEL_FROM_DATABASE=Generic Universal Protocol Analyzer + +usb:v0423p0101* + ID_MODEL_FROM_DATABASE=UPA USBTracer + +usb:v0423p0200* + ID_MODEL_FROM_DATABASE=Generic 10K Universal Protocol Analyzer + +usb:v0423p020A* + ID_MODEL_FROM_DATABASE=PETracer ML + +usb:v0423p0300* + ID_MODEL_FROM_DATABASE=Generic Universal Protocol Analyzer + +usb:v0423p0301* + ID_MODEL_FROM_DATABASE=2500H Tracer Trainer + +usb:v0423p030A* + ID_MODEL_FROM_DATABASE=PETracer x1 + +usb:v0423p1237* + ID_MODEL_FROM_DATABASE=Andromeda Hub + +usb:v0424* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp. + +usb:v0424p0001* + ID_MODEL_FROM_DATABASE=Integrated Hub + +usb:v0424p0ACD* + ID_MODEL_FROM_DATABASE=Sitecom Internal Multi Memory reader/writer MD-005 + +usb:v0424p0FDC* + ID_MODEL_FROM_DATABASE=Floppy + +usb:v0424p10CD* + ID_MODEL_FROM_DATABASE=Sitecom Internal Multi Memory reader/writer MD-005 + +usb:v0424p2020* + ID_MODEL_FROM_DATABASE=USB Hub + +usb:v0424p20CD* + ID_MODEL_FROM_DATABASE=Sitecom Internal Multi Memory reader/writer MD-005 + +usb:v0424p20FC* + ID_MODEL_FROM_DATABASE=6-in-1 Card Reader + +usb:v0424p2228* + ID_MODEL_FROM_DATABASE=9-in-2 Card Reader + +usb:v0424p223A* + ID_MODEL_FROM_DATABASE=8-in-1 Card Reader + +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:v0424p2512* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v0424p2513* + ID_MODEL_FROM_DATABASE=2.0 Hub + +usb:v0424p2514* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v0424p2517* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0424p2524* + ID_MODEL_FROM_DATABASE=USB MultiSwitch Hub + +usb:v0424p2602* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v0424p2640* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v0424p4060* + ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader + +usb:v0424p4064* + ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader + +usb:v0424p7500* + ID_MODEL_FROM_DATABASE=LAN7500 Ethernet 10/100/1000 Adapter + +usb:v0424p9512* + ID_MODEL_FROM_DATABASE=SMC9512/9514 USB Hub + +usb:v0424pA700* + ID_MODEL_FROM_DATABASE=2 Port Hub + +usb:v0424pEC00* + ID_MODEL_FROM_DATABASE=SMSC9512/9514 Fast Ethernet Adapter + +usb:v0425* + ID_VENDOR_FROM_DATABASE=Motorola Semiconductors HK, Ltd + +usb:v0425p0101* + ID_MODEL_FROM_DATABASE=G-Tech Wireless Mouse & Keyboard + +usb:v0425pF102* + ID_MODEL_FROM_DATABASE=G-Tech U+P Wireless Mouse + +usb:v0426* + ID_VENDOR_FROM_DATABASE=Integrated Device Technology, Inc. + +usb:v0426p0426* + ID_MODEL_FROM_DATABASE=WDM Driver + +usb:v0427* + ID_VENDOR_FROM_DATABASE=Motorola Electronics Taiwan, Ltd + +usb:v0428* + ID_VENDOR_FROM_DATABASE=Advanced Gravis Computer Tech, Ltd + +usb:v0428p4001* + ID_MODEL_FROM_DATABASE=GamePad Pro + +usb:v0429* + ID_VENDOR_FROM_DATABASE=Cirrus Logic + +usb:v042A* + ID_VENDOR_FROM_DATABASE=Ericsson Austrian, AG + +usb:v042B* + ID_VENDOR_FROM_DATABASE=Intel Corp. + +usb:v042Bp9316* + ID_MODEL_FROM_DATABASE=8x931Hx Customer Hub + +usb:v042C* + ID_VENDOR_FROM_DATABASE=Innovative Semiconductors, Inc. + +usb:v042D* + ID_VENDOR_FROM_DATABASE=Micronics + +usb:v042E* + ID_VENDOR_FROM_DATABASE=Acer, Inc. + +usb:v042Ep0380* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v042F* + ID_VENDOR_FROM_DATABASE=Molex, Inc. + +usb:v0430* + ID_VENDOR_FROM_DATABASE=Sun Microsystems, Inc. + +usb:v0430p0002* + ID_MODEL_FROM_DATABASE=109 Keyboard + +usb:v0430p0005* + ID_MODEL_FROM_DATABASE=Type 6 Keyboard + +usb:v0430p000A* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard + +usb:v0430p000B* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard + +usb:v0430p0082* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard + +usb:v0430p0083* + ID_MODEL_FROM_DATABASE=109 Japanese Keyboard + +usb:v0430p00A2* + ID_MODEL_FROM_DATABASE=Type 7 Keyboard + +usb:v0430p0100* + ID_MODEL_FROM_DATABASE=3-button Mouse + +usb:v0430p100E* + ID_MODEL_FROM_DATABASE=24.1" LCD Monitor v4 / FID-638 Mouse + +usb:v0430p36BA* + ID_MODEL_FROM_DATABASE=Bus Powered Hub + +usb:v0430pA101* + ID_MODEL_FROM_DATABASE=remote key/mouse for P3 chip + +usb:v0430pA102* + ID_MODEL_FROM_DATABASE=remote key/mouse/storage for P3 chip + +usb:v0430pA103* + ID_MODEL_FROM_DATABASE=remote storage for P3 chip + +usb:v0430pA4A2* + ID_MODEL_FROM_DATABASE=Ethernet (RNDIS and CDC ethernet) + +usb:v0430pCDAB* + ID_MODEL_FROM_DATABASE=Raritan KVM dongle + +usb:v0431* + ID_VENDOR_FROM_DATABASE=Itac Systems, Inc. + +usb:v0431p0100* + ID_MODEL_FROM_DATABASE=Mouse-Trak 3-button Track Ball + +usb:v0432* + ID_VENDOR_FROM_DATABASE=Unisys Corp. + +usb:v0433* + ID_VENDOR_FROM_DATABASE=Alps Electric, Inc. + +usb:v0433p1101* + ID_MODEL_FROM_DATABASE=IBM Game Controller + +usb:v0433pABAB* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0434* + ID_VENDOR_FROM_DATABASE=Samsung Info. Systems America, Inc. + +usb:v0435* + ID_VENDOR_FROM_DATABASE=Hyundai Electronics America + +usb:v0436* + ID_VENDOR_FROM_DATABASE=Taugagreining HF + +usb:v0436p0005* + ID_MODEL_FROM_DATABASE=CameraMate (DPCM_USB) + +usb:v0437* + ID_VENDOR_FROM_DATABASE=Framatome Connectors USA + +usb:v0438* + ID_VENDOR_FROM_DATABASE=Advanced Micro Devices, Inc. + +usb:v0439* + ID_VENDOR_FROM_DATABASE=Voice Technologies Group + +usb:v043D* + ID_VENDOR_FROM_DATABASE=Lexmark International, Inc. + +usb:v043Dp0001* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0002* + ID_MODEL_FROM_DATABASE=Optra E310 Printer + +usb:v043Dp0003* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0004* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0005* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0006* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0007* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0008* + ID_MODEL_FROM_DATABASE=Inkjet Color Printer + +usb:v043Dp0009* + ID_MODEL_FROM_DATABASE=Optra S2450 Printer + +usb:v043Dp000A* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp000B* + ID_MODEL_FROM_DATABASE=Inkjet Color Printer + +usb:v043Dp000C* + ID_MODEL_FROM_DATABASE=Optra E312 Printer + +usb:v043Dp000D* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp000E* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp000F* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0010* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0011* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0012* + ID_MODEL_FROM_DATABASE=Inkjet Color Printer + +usb:v043Dp0013* + ID_MODEL_FROM_DATABASE=Inkjet Color Printer + +usb:v043Dp0014* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0015* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0016* + ID_MODEL_FROM_DATABASE=Z12 Color Jetprinter + +usb:v043Dp0017* + ID_MODEL_FROM_DATABASE=Z32 printer + +usb:v043Dp0018* + ID_MODEL_FROM_DATABASE=Z52 Printer + +usb:v043Dp0019* + ID_MODEL_FROM_DATABASE=Forms Printer + +usb:v043Dp001A* + ID_MODEL_FROM_DATABASE=Z65 Printer + +usb:v043Dp001B* + ID_MODEL_FROM_DATABASE=InkJet Photo Printer + +usb:v043Dp001C* + ID_MODEL_FROM_DATABASE=Kodak Personal Picture Maker 200 Printer + +usb:v043Dp001D* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp001E* + ID_MODEL_FROM_DATABASE=InkJet Photo Printer + +usb:v043Dp001F* + ID_MODEL_FROM_DATABASE=Kodak Personal Picture Maker 200 Card Reader + +usb:v043Dp0020* + ID_MODEL_FROM_DATABASE=Z51 Printer + +usb:v043Dp0021* + ID_MODEL_FROM_DATABASE=Z33 Printer + +usb:v043Dp0022* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0023* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0024* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0025* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0026* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0027* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0028* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0029* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp002A* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp002B* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp002C* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp002D* + ID_MODEL_FROM_DATABASE=X70/X73 Scan/Print/Copy + +usb:v043Dp002E* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp002F* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0030* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0031* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0032* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0033* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0034* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0035* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0036* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0037* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0038* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0039* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp003A* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp003B* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp003C* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp003D* + ID_MODEL_FROM_DATABASE=X83 Scan/Print/Copy + +usb:v043Dp003E* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp003F* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0040* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0041* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0042* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0043* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0044* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0045* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0046* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0047* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0048* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp0049* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp004A* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp004B* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp004C* + ID_MODEL_FROM_DATABASE=Scan Print Copy + +usb:v043Dp004D* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp004E* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp004F* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0050* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0051* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0052* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp0053* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0054* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0057* + ID_MODEL_FROM_DATABASE=Z35 Printer + +usb:v043Dp0058* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v043Dp005A* + ID_MODEL_FROM_DATABASE=X63 + +usb:v043Dp005C* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0060* + ID_MODEL_FROM_DATABASE=X74/X75 Scanner + +usb:v043Dp0061* + ID_MODEL_FROM_DATABASE=X74 Hub + +usb:v043Dp0065* + ID_MODEL_FROM_DATABASE=X5130 + +usb:v043Dp0069* + ID_MODEL_FROM_DATABASE=X74/X75 Printer + +usb:v043Dp006D* + ID_MODEL_FROM_DATABASE=X125 + +usb:v043Dp006E* + ID_MODEL_FROM_DATABASE=C510 + +usb:v043Dp0072* + ID_MODEL_FROM_DATABASE=X6170 Printer + +usb:v043Dp0073* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0078* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp0079* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp007A* + ID_MODEL_FROM_DATABASE=Generic Hub + +usb:v043Dp007B* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp007C* + ID_MODEL_FROM_DATABASE=X1110/X1130/X1140/X1150/X1170/X1180/X1185 + +usb:v043Dp007D* + ID_MODEL_FROM_DATABASE=Photo 3150 + +usb:v043Dp008A* + ID_MODEL_FROM_DATABASE=4200 series + +usb:v043Dp008B* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp008C* + ID_MODEL_FROM_DATABASE=to CF/SM/SD/MS Card Reader + +usb:v043Dp008E* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp008F* + ID_MODEL_FROM_DATABASE=X422 + +usb:v043Dp0093* + ID_MODEL_FROM_DATABASE=X5250 + +usb:v043Dp0095* + ID_MODEL_FROM_DATABASE=E220 Printer + +usb:v043Dp0096* + ID_MODEL_FROM_DATABASE=2200 series + +usb:v043Dp0097* + ID_MODEL_FROM_DATABASE=P6250 + +usb:v043Dp0098* + ID_MODEL_FROM_DATABASE=7100 series + +usb:v043Dp009E* + ID_MODEL_FROM_DATABASE=P910 series Human Interface Device + +usb:v043Dp009F* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp00A9* + ID_MODEL_FROM_DATABASE=IBM Infoprint 1410 MFP + +usb:v043Dp00AB* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp00B2* + ID_MODEL_FROM_DATABASE=3300 series + +usb:v043Dp00B8* + ID_MODEL_FROM_DATABASE=7300 series + +usb:v043Dp00B9* + ID_MODEL_FROM_DATABASE=8300 series + +usb:v043Dp00BA* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp00BB* + ID_MODEL_FROM_DATABASE=2300 series + +usb:v043Dp00BD* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00BE* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00BF* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00C0* + ID_MODEL_FROM_DATABASE=6300 series + +usb:v043Dp00C1* + ID_MODEL_FROM_DATABASE=4300 series + +usb:v043Dp00C7* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00C8* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00C9* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00CB* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00CC* + ID_MODEL_FROM_DATABASE=E120(n) + +usb:v043Dp00D0* + ID_MODEL_FROM_DATABASE=9300 series + +usb:v043Dp00D3* + ID_MODEL_FROM_DATABASE=X340 Scanner + +usb:v043Dp00D4* + ID_MODEL_FROM_DATABASE=X342n Scanner + +usb:v043Dp00D5* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v043Dp00D6* + ID_MODEL_FROM_DATABASE=X340 Scanner + +usb:v043Dp00E8* + ID_MODEL_FROM_DATABASE=X642e + +usb:v043Dp00E9* + ID_MODEL_FROM_DATABASE=2400 series + +usb:v043Dp00F6* + ID_MODEL_FROM_DATABASE=3400 series + +usb:v043Dp00F7* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp00FF* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v043Dp010B* + ID_MODEL_FROM_DATABASE=2500 series + +usb:v043Dp010D* + ID_MODEL_FROM_DATABASE=3500-4500 series + +usb:v043Dp010F* + ID_MODEL_FROM_DATABASE=6500 series + +usb:v043Dp0142* + ID_MODEL_FROM_DATABASE=X3650 (Printer, Scanner, Copier) + +usb:v043Dp01FA* + ID_MODEL_FROM_DATABASE=S310 series + +usb:v043Dp4303* + ID_MODEL_FROM_DATABASE=Xerox WorkCentre Pro 412 + +usb:v043E* + ID_VENDOR_FROM_DATABASE=LG Electronics USA, Inc. + +usb:v043Ep3001* + ID_MODEL_FROM_DATABASE=AN-WF100 802.11abgn Wireless Adapter [Broadcom BCM4323] + +usb:v043Ep42BD* + ID_MODEL_FROM_DATABASE=Flatron 795FT Plus Monitor + +usb:v043Ep4A4D* + ID_MODEL_FROM_DATABASE=Flatron 915FT Plus Monitor + +usb:v043Ep7001* + ID_MODEL_FROM_DATABASE=MF-PD100 Soul Digital MP3 Player + +usb:v043Ep7013* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v043Ep70F5* + ID_MODEL_FROM_DATABASE=External HDD + +usb:v043Ep8484* + ID_MODEL_FROM_DATABASE=LPC-U30 Webcam II + +usb:v043Ep8585* + ID_MODEL_FROM_DATABASE=LPC-UC35 Webcam + +usb:v043Ep8888* + ID_MODEL_FROM_DATABASE=Electronics VCS Camera II(LPC-U20) + +usb:v043Ep9800* + ID_MODEL_FROM_DATABASE=Remote Control Receiver_iMON + +usb:v043Ep9803* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v043Ep9804* + ID_MODEL_FROM_DATABASE=DMB Receiver Control + +usb:v043Ep9C01* + ID_MODEL_FROM_DATABASE=LGE Sync + +usb:v043F* + ID_VENDOR_FROM_DATABASE=RadiSys Corp. + +usb:v0440* + ID_VENDOR_FROM_DATABASE=Eizo Nanao Corp. + +usb:v0441* + ID_VENDOR_FROM_DATABASE=Winbond Systems Lab. + +usb:v0441p1456* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0442* + ID_VENDOR_FROM_DATABASE=Ericsson, Inc. + +usb:v0442pABBA* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0443* + ID_VENDOR_FROM_DATABASE=Gateway, Inc. + +usb:v0443p000E* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard + +usb:v0443p002E* + ID_MODEL_FROM_DATABASE=Millennium Keyboard + +usb:v0445* + ID_VENDOR_FROM_DATABASE=Lucent Technologies, Inc. + +usb:v0446* + ID_VENDOR_FROM_DATABASE=NMB Technologies Corp. + +usb:v0446p6781* + ID_MODEL_FROM_DATABASE=Keyboard with PS/2 Mouse Port + +usb:v0446p6782* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0447* + ID_VENDOR_FROM_DATABASE=Momentum Microsystems + +usb:v044A* + ID_VENDOR_FROM_DATABASE=Shamrock Tech. Co., Ltd + +usb:v044B* + ID_VENDOR_FROM_DATABASE=WSI + +usb:v044C* + ID_VENDOR_FROM_DATABASE=CCL/ITRI + +usb:v044D* + ID_VENDOR_FROM_DATABASE=Siemens Nixdorf AG + +usb:v044E* + ID_VENDOR_FROM_DATABASE=Alps Electric Co., Ltd + +usb:v044Ep1104* + ID_MODEL_FROM_DATABASE=Japanese Keyboard + +usb:v044Ep2002* + ID_MODEL_FROM_DATABASE=MD-5500 Printer + +usb:v044Ep2014* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v044Ep3001* + ID_MODEL_FROM_DATABASE=UGTZ4 Bluetooth + +usb:v044Ep3002* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v044Ep3003* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v044Ep3004* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v044Ep3005* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth Device + +usb:v044Ep3006* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v044Ep3007* + ID_MODEL_FROM_DATABASE=Bluetooth Controller (ALPS/UGX) + +usb:v044Ep300C* + ID_MODEL_FROM_DATABASE=Bluetooth Controller (ALPS/UGPZ6) + +usb:v044Ep300D* + ID_MODEL_FROM_DATABASE=Bluetooth Controller (ALPS/UGPZ6) + +usb:v044Ep3010* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v044Ep3017* + ID_MODEL_FROM_DATABASE=BCM2046 Bluetooth Device + +usb:v044EpFFFF* + ID_MODEL_FROM_DATABASE=Compaq Bluetooth Multiport Module + +usb:v044F* + ID_VENDOR_FROM_DATABASE=ThrustMaster, Inc. + +usb:v044Fp0400* + ID_MODEL_FROM_DATABASE=HOTAS Cougar + +usb:v044Fp044F* + ID_MODEL_FROM_DATABASE=GP XID + +usb:v044FpA003* + ID_MODEL_FROM_DATABASE=Rage 3D Game Pad + +usb:v044FpA01B* + ID_MODEL_FROM_DATABASE=PK-GP301 Driving Wheel + +usb:v044FpA0A0* + ID_MODEL_FROM_DATABASE=Top Gun Joystick + +usb:v044FpA0A1* + ID_MODEL_FROM_DATABASE=Top Gun Joystick (rev2) + +usb:v044FpA0A3* + ID_MODEL_FROM_DATABASE=Fusion Digital GamePad + +usb:v044FpA201* + ID_MODEL_FROM_DATABASE=PK-GP201 PlayStick + +usb:v044FpB108* + ID_MODEL_FROM_DATABASE=T-Flight Hotas X Flight Stick + +usb:v044FpB10A* + ID_MODEL_FROM_DATABASE=T.16000M Joystick + +usb:v044FpB203* + ID_MODEL_FROM_DATABASE=360 Modena Pro Wheel + +usb:v044FpB300* + ID_MODEL_FROM_DATABASE=Firestorm Dual Power + +usb:v044FpB304* + ID_MODEL_FROM_DATABASE=Firestorm Dual Power + +usb:v044FpB307* + ID_MODEL_FROM_DATABASE=vibrating Upad + +usb:v044FpB30B* + ID_MODEL_FROM_DATABASE=Wireless VibrationPad + +usb:v044FpB315* + ID_MODEL_FROM_DATABASE=Firestorm Dual Analog 3 + +usb:v044FpB323* + ID_MODEL_FROM_DATABASE=Dual Trigger 3-in-1 (PC Mode) + +usb:v044FpB324* + ID_MODEL_FROM_DATABASE=Dual Trigger 3-in-1 (PS3 Mode) + +usb:v044FpB603* + ID_MODEL_FROM_DATABASE=force feedback Wheel + +usb:v044FpB605* + ID_MODEL_FROM_DATABASE=force feedback Racing Wheel + +usb:v044FpB651* + ID_MODEL_FROM_DATABASE=Ferrari GT Rumble Force Wheel + +usb:v044FpB653* + ID_MODEL_FROM_DATABASE=RGT Force Feedback Clutch Racing Wheel + +usb:v044FpB654* + ID_MODEL_FROM_DATABASE=Ferrari GT Force Feedback Wheel + +usb:v044FpB700* + ID_MODEL_FROM_DATABASE=Tacticalboard + +usb:v0450* + ID_VENDOR_FROM_DATABASE=DFI, Inc. + +usb:v0451* + ID_VENDOR_FROM_DATABASE=Texas Instruments, Inc. + +usb:v0451p1234* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0451p1428* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0451p1446* + ID_MODEL_FROM_DATABASE=TUSB2040/2070 Hub + +usb:v0451p16A6* + ID_MODEL_FROM_DATABASE=BM-USBD1 BlueRobin RF heart rate sensor receiver + +usb:v0451p2036* + ID_MODEL_FROM_DATABASE=TUSB2036 Hub + +usb:v0451p2046* + ID_MODEL_FROM_DATABASE=TUSB2046 Hub + +usb:v0451p2077* + ID_MODEL_FROM_DATABASE=TUSB2077 Hub + +usb:v0451p3410* + ID_MODEL_FROM_DATABASE=TUSB3410 Microcontroller + +usb:v0451p3F00* + ID_MODEL_FROM_DATABASE=OMAP1610 + +usb:v0451p3F02* + ID_MODEL_FROM_DATABASE=SMC WSKP100 Wi-Fi Phone + +usb:v0451p5409* + ID_MODEL_FROM_DATABASE=Frontier Labs NEX IA+ Digital Audio Player + +usb:v0451p6000* + ID_MODEL_FROM_DATABASE=AU5 ADSL Modem (pre-reenum) + +usb:v0451p6001* + ID_MODEL_FROM_DATABASE=AU5 ADSL Modem + +usb:v0451p6060* + ID_MODEL_FROM_DATABASE=RNDIS/BeWAN ADSL2+ + +usb:v0451p6070* + ID_MODEL_FROM_DATABASE=RNDIS/BeWAN ADSL2+ + +usb:v0451p625F* + ID_MODEL_FROM_DATABASE=TUSB6250 ATA Bridge + +usb:v0451p8042* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0451pDBC0* + ID_MODEL_FROM_DATABASE=Device Bay Controller + +usb:v0451pE001* + ID_MODEL_FROM_DATABASE=GraphLink [SilverLink] + +usb:v0451pE003* + ID_MODEL_FROM_DATABASE=TI-84 Plus Calculator + +usb:v0451pE004* + ID_MODEL_FROM_DATABASE=TI-89 Titanium Calculator + +usb:v0451pE008* + ID_MODEL_FROM_DATABASE=TI-84 Plus Silver Calculator + +usb:v0451pE012* + ID_MODEL_FROM_DATABASE=TI-Nspire Calculator + +usb:v0451pF430* + ID_MODEL_FROM_DATABASE=MSP-FET430UIF JTAG Tool + +usb:v0451pF432* + ID_MODEL_FROM_DATABASE=eZ430 Development Tool + +usb:v0451pFFFF* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0452* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electronics America, Inc. + +usb:v0452p0021* + ID_MODEL_FROM_DATABASE=HID Monitor Controls + +usb:v0452p0050* + ID_MODEL_FROM_DATABASE=Diamond Pro 900u CRT Monitor + +usb:v0452p0051* + ID_MODEL_FROM_DATABASE=Integrated Hub + +usb:v0453* + ID_VENDOR_FROM_DATABASE=CMD Technology + +usb:v0453p6781* + ID_MODEL_FROM_DATABASE=NMB Keyboard + +usb:v0453p6783* + ID_MODEL_FROM_DATABASE=Chicony Composite Keyboard + +usb:v0454* + ID_VENDOR_FROM_DATABASE=Vobis Microcomputer AG + +usb:v0455* + ID_VENDOR_FROM_DATABASE=Telematics International, Inc. + +usb:v0456* + ID_VENDOR_FROM_DATABASE=Analog Devices, Inc. + +usb:v0456pF000* + ID_MODEL_FROM_DATABASE=FT2232 JTAG ICE [gnICE] + +usb:v0456pF001* + ID_MODEL_FROM_DATABASE=FT2232H Hi-Speed JTAG ICE [gnICE+] + +usb:v0457* + ID_VENDOR_FROM_DATABASE=Silicon Integrated Systems Corp. + +usb:v0457p0150* + ID_MODEL_FROM_DATABASE=Super Talent 1GB Flash Drive + +usb:v0457p0151* + ID_MODEL_FROM_DATABASE=Super Flash 1GB / GXT 64MB Flash Drive + +usb:v0457p0162* + ID_MODEL_FROM_DATABASE=SiS162 usb Wireless LAN Adapter + +usb:v0457p0163* + ID_MODEL_FROM_DATABASE=802.11 Wireless LAN Adapter + +usb:v0457p0817* + ID_MODEL_FROM_DATABASE=SiS-184-ASUS-4352.17 touch panel + +usb:v0457p5401* + ID_MODEL_FROM_DATABASE=Wireless Adapter RO80211GS-USB + +usb:v0458* + ID_VENDOR_FROM_DATABASE=KYE Systems Corp. (Mouse Systems) + +usb:v0458p0001* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0458p0002* + ID_MODEL_FROM_DATABASE=Genius NetMouse Pro + +usb:v0458p0003* + ID_MODEL_FROM_DATABASE=Genius NetScroll+ + +usb:v0458p0006* + ID_MODEL_FROM_DATABASE=Easy Mouse+ + +usb:v0458p000B* + ID_MODEL_FROM_DATABASE=NetMouse Wheel(P+U) + +usb:v0458p000C* + ID_MODEL_FROM_DATABASE=TACOMA Fingerprint V1.06.01 + +usb:v0458p000E* + ID_MODEL_FROM_DATABASE=VideoCAM Web + +usb:v0458p0013* + ID_MODEL_FROM_DATABASE=TACOMA Fingerprint Mouse V1.06.01 + +usb:v0458p001A* + ID_MODEL_FROM_DATABASE=Genius WebScroll+ + +usb:v0458p0036* + ID_MODEL_FROM_DATABASE=Pocket Mouse LE + +usb:v0458p0039* + ID_MODEL_FROM_DATABASE=NetScroll+ Superior + +usb:v0458p003A* + ID_MODEL_FROM_DATABASE=NetScroll+ Mini Traveler / Genius NetScroll 120 + +usb:v0458p004C* + ID_MODEL_FROM_DATABASE=Slimstar Pro Keyboard + +usb:v0458p0056* + ID_MODEL_FROM_DATABASE=Ergo 300 Mouse + +usb:v0458p0057* + ID_MODEL_FROM_DATABASE=Enhanced Gaming Device + +usb:v0458p0059* + ID_MODEL_FROM_DATABASE=Enhanced Laser Device + +usb:v0458p005A* + ID_MODEL_FROM_DATABASE=Enhanced Device + +usb:v0458p005B* + ID_MODEL_FROM_DATABASE=Enhanced Device + +usb:v0458p005C* + ID_MODEL_FROM_DATABASE=Enhanced Laser Gaming Device + +usb:v0458p005D* + ID_MODEL_FROM_DATABASE=Enhanced Device + +usb:v0458p0061* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0458p0066* + ID_MODEL_FROM_DATABASE=Genius Traveler 1000 Wireless Mouse + +usb:v0458p0072* + ID_MODEL_FROM_DATABASE=Navigator 335 + +usb:v0458p0083* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0458p0087* + ID_MODEL_FROM_DATABASE=Ergo 525V Laser Mouse + +usb:v0458p00CA* + ID_MODEL_FROM_DATABASE=Pen Mouse + +usb:v0458p0100* + ID_MODEL_FROM_DATABASE=EasyPen Tablet + +usb:v0458p0101* + ID_MODEL_FROM_DATABASE=CueCat + +usb:v0458p011B* + ID_MODEL_FROM_DATABASE=NetScroll T220 + +usb:v0458p1001* + ID_MODEL_FROM_DATABASE=Joystick + +usb:v0458p1002* + ID_MODEL_FROM_DATABASE=Game Pad + +usb:v0458p1003* + ID_MODEL_FROM_DATABASE=Genius VideoCam + +usb:v0458p1004* + ID_MODEL_FROM_DATABASE=Flight2000 F-23 Joystick + +usb:v0458p100A* + ID_MODEL_FROM_DATABASE=Aashima Technology Trust Sight Fighter Vibration Feedback Joystick + +usb:v0458p2001* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid Pro Scanner + +usb:v0458p2004* + ID_MODEL_FROM_DATABASE=ColorPage-HR6 V1 Scanner + +usb:v0458p2005* + ID_MODEL_FROM_DATABASE=ColorPage-HR6/Vivid3 + +usb:v0458p2007* + ID_MODEL_FROM_DATABASE=ColorPage-HR6 V2 Scanner + +usb:v0458p2008* + ID_MODEL_FROM_DATABASE=ColorPage-HR6 V2 Scanner + +usb:v0458p2009* + ID_MODEL_FROM_DATABASE=ColorPage-HR6A Scanner + +usb:v0458p2011* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid3x Scanner + +usb:v0458p2012* + ID_MODEL_FROM_DATABASE=Plustek Scanner + +usb:v0458p2013* + ID_MODEL_FROM_DATABASE=ColorPage-HR7 Scanner + +usb:v0458p2014* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid4 + +usb:v0458p2015* + ID_MODEL_FROM_DATABASE=ColorPage-HR7LE Scanner + +usb:v0458p2016* + ID_MODEL_FROM_DATABASE=ColorPage-HR6X Scanner + +usb:v0458p2017* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid3xe + +usb:v0458p2018* + ID_MODEL_FROM_DATABASE=ColorPage-HR7X + +usb:v0458p2019* + ID_MODEL_FROM_DATABASE=ColorPage-HR6X Slim + +usb:v0458p201A* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid4xe + +usb:v0458p201B* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid4x + +usb:v0458p201C* + ID_MODEL_FROM_DATABASE=ColorPage-HR8 + +usb:v0458p201D* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid 1200 X + +usb:v0458p201E* + ID_MODEL_FROM_DATABASE=ColorPage-Slim 1200 + +usb:v0458p201F* + ID_MODEL_FROM_DATABASE=ColorPage-Vivid 1200 XE + +usb:v0458p2020* + ID_MODEL_FROM_DATABASE=ColorPage-Slim 1200 USB2 + +usb:v0458p2021* + ID_MODEL_FROM_DATABASE=ColorPage-SF600 + +usb:v0458p3017* + ID_MODEL_FROM_DATABASE=SPEED WHEEL 3 Vibration + +usb:v0458p3018* + ID_MODEL_FROM_DATABASE=Wireless 2.4Ghz Game Pad + +usb:v0458p3019* + ID_MODEL_FROM_DATABASE=10-Button USB Joystick with Vibration + +usb:v0458p301A* + ID_MODEL_FROM_DATABASE=MaxFire G-12U Vibration + +usb:v0458p301D* + ID_MODEL_FROM_DATABASE=Genius MaxFire MiniPad + +usb:v0458p400F* + ID_MODEL_FROM_DATABASE=Genius TVGo DVB-T02Q MCE + +usb:v0458p4012* + ID_MODEL_FROM_DATABASE=TVGo DVB-T03 [AF9015] + +usb:v0458p5003* + ID_MODEL_FROM_DATABASE=G-pen 560 Tablet + +usb:v0458p5004* + ID_MODEL_FROM_DATABASE=G-pen Tablet + +usb:v0458p6001* + ID_MODEL_FROM_DATABASE=GF3000F Ethernet Adapter + +usb:v0458p7004* + ID_MODEL_FROM_DATABASE=VideoCAM Express V2 + +usb:v0458p7006* + ID_MODEL_FROM_DATABASE=Dsc 1.3 Smart Camera Device + +usb:v0458p7007* + ID_MODEL_FROM_DATABASE=VideoCAM Web + +usb:v0458p7009* + ID_MODEL_FROM_DATABASE=G-Shot G312 Still Camera Device + +usb:v0458p700C* + ID_MODEL_FROM_DATABASE=VideoCAM Web V3 + +usb:v0458p700D* + ID_MODEL_FROM_DATABASE=G-Shot G511 Composite Device + +usb:v0458p700F* + ID_MODEL_FROM_DATABASE=VideoCAM Web + +usb:v0458p7012* + ID_MODEL_FROM_DATABASE=WebCAM USB2.0 + +usb:v0458p7014* + ID_MODEL_FROM_DATABASE=VideoCAM Live V3 + +usb:v0458p701C* + ID_MODEL_FROM_DATABASE=G-Shot G512 Still Camera + +usb:v0458p7020* + ID_MODEL_FROM_DATABASE=Sim 321C + +usb:v0458p7025* + ID_MODEL_FROM_DATABASE=Eye 311Q Camera + +usb:v0458p7029* + ID_MODEL_FROM_DATABASE=Genius Look 320s (SN9C201 + HV7131R) + +usb:v0458p702F* + ID_MODEL_FROM_DATABASE=Genius Slim 322 + +usb:v0458p7035* + ID_MODEL_FROM_DATABASE=i-Look 325T Camera + +usb:v0458p7045* + ID_MODEL_FROM_DATABASE=Genius Look 1320 V2 + +usb:v0458p704C* + ID_MODEL_FROM_DATABASE=Genius i-Look 1321 + +usb:v0458p704D* + ID_MODEL_FROM_DATABASE=Slim 1322AF + +usb:v0458p7055* + ID_MODEL_FROM_DATABASE=Slim 2020AF camera + +usb:v0458p705A* + ID_MODEL_FROM_DATABASE=Asus USB2.0 Webcam + +usb:v0458p705C* + ID_MODEL_FROM_DATABASE=Genius iSlim 1300AF + +usb:v0458p7079* + ID_MODEL_FROM_DATABASE=FaceCam 2025R + +usb:v0458p707F* + ID_MODEL_FROM_DATABASE=TVGo DVB-T03 [RTL2832] + +usb:v0458p7088* + ID_MODEL_FROM_DATABASE=WideCam 1050 + +usb:v0459* + ID_VENDOR_FROM_DATABASE=Adobe Systems, Inc. + +usb:v045A* + ID_VENDOR_FROM_DATABASE=SONICblue, Inc. + +usb:v045Ap07DA* + ID_MODEL_FROM_DATABASE=Supra Express 56K modem + +usb:v045Ap0B4A* + ID_MODEL_FROM_DATABASE=SupraMax 2890 56K Modem [Lucent Atlas] + +usb:v045Ap0B68* + ID_MODEL_FROM_DATABASE=SupraMax 56K Modem + +usb:v045Ap5001* + ID_MODEL_FROM_DATABASE=Rio 600 MP3 Player + +usb:v045Ap5002* + ID_MODEL_FROM_DATABASE=Rio 800 MP3 Player + +usb:v045Ap5003* + ID_MODEL_FROM_DATABASE=Nike Psa/Play MP3 Player + +usb:v045Ap5005* + ID_MODEL_FROM_DATABASE=Rio S10 MP3 Player + +usb:v045Ap5006* + ID_MODEL_FROM_DATABASE=Rio S50 MP3 Player + +usb:v045Ap5007* + ID_MODEL_FROM_DATABASE=Rio S35 MP3 Player + +usb:v045Ap5008* + ID_MODEL_FROM_DATABASE=Rio 900 MP3 Player + +usb:v045Ap5009* + ID_MODEL_FROM_DATABASE=Rio S30 MP3 Player + +usb:v045Ap500D* + ID_MODEL_FROM_DATABASE=Fuse MP3 Player + +usb:v045Ap500E* + ID_MODEL_FROM_DATABASE=Chiba MP3 Player + +usb:v045Ap500F* + ID_MODEL_FROM_DATABASE=Cali MP3 Player + +usb:v045Ap5010* + ID_MODEL_FROM_DATABASE=Rio S11 MP3 Player + +usb:v045Ap501C* + ID_MODEL_FROM_DATABASE=Virgin MPF-1000 + +usb:v045Ap501D* + ID_MODEL_FROM_DATABASE=Rio Fuse + +usb:v045Ap501E* + ID_MODEL_FROM_DATABASE=Rio Chiba + +usb:v045Ap501F* + ID_MODEL_FROM_DATABASE=Rio Cali + +usb:v045Ap503F* + ID_MODEL_FROM_DATABASE=Cali256 MP3 Player + +usb:v045Ap5202* + ID_MODEL_FROM_DATABASE=Rio Riot MP3 Player + +usb:v045Ap5210* + ID_MODEL_FROM_DATABASE=Rio Karma Music Player + +usb:v045Ap5220* + ID_MODEL_FROM_DATABASE=Rio Nitrus MP3 Player + +usb:v045Ap5221* + ID_MODEL_FROM_DATABASE=Rio Eigen + +usb:v045B* + ID_VENDOR_FROM_DATABASE=Hitachi, Ltd + +usb:v045Bp0053* + ID_MODEL_FROM_DATABASE=RX610 RX-Stick + +usb:v045D* + ID_VENDOR_FROM_DATABASE=Nortel Networks, Ltd + +usb:v045E* + ID_VENDOR_FROM_DATABASE=Microsoft Corp. + +usb:v045Ep0007* + ID_MODEL_FROM_DATABASE=SideWinder Game Pad + +usb:v045Ep0008* + ID_MODEL_FROM_DATABASE=SideWinder Precision Pro + +usb:v045Ep0009* + ID_MODEL_FROM_DATABASE=IntelliMouse + +usb:v045Ep000B* + ID_MODEL_FROM_DATABASE=Natural Keyboard Elite + +usb:v045Ep000E* + ID_MODEL_FROM_DATABASE=SideWinder® Freestyle Pro + +usb:v045Ep0014* + ID_MODEL_FROM_DATABASE=Digital Sound System 80 + +usb:v045Ep001A* + ID_MODEL_FROM_DATABASE=SideWinder Precision Racing Wheel + +usb:v045Ep001B* + ID_MODEL_FROM_DATABASE=SideWinder Force Feedback 2 Joystick + +usb:v045Ep001C* + ID_MODEL_FROM_DATABASE=Internet Keyboard Pro + +usb:v045Ep001D* + ID_MODEL_FROM_DATABASE=Natural Keyboard Pro + +usb:v045Ep001E* + ID_MODEL_FROM_DATABASE=IntelliMouse Explorer + +usb:v045Ep0023* + ID_MODEL_FROM_DATABASE=Trackball Optical + +usb:v045Ep0024* + ID_MODEL_FROM_DATABASE=Trackball Explorer + +usb:v045Ep0025* + ID_MODEL_FROM_DATABASE=IntelliEye Mouse + +usb:v045Ep0026* + ID_MODEL_FROM_DATABASE=SideWinder GamePad Pro + +usb:v045Ep0027* + ID_MODEL_FROM_DATABASE=SideWinder PnP GamePad + +usb:v045Ep0028* + ID_MODEL_FROM_DATABASE=SideWinder Dual Strike + +usb:v045Ep0029* + ID_MODEL_FROM_DATABASE=IntelliMouse Optical + +usb:v045Ep002B* + ID_MODEL_FROM_DATABASE=Internet Keyboard Pro + +usb:v045Ep002D* + ID_MODEL_FROM_DATABASE=Internet Keyboard + +usb:v045Ep002F* + ID_MODEL_FROM_DATABASE=Integrated Hub + +usb:v045Ep0033* + ID_MODEL_FROM_DATABASE=Sidewinder Strategic Commander + +usb:v045Ep0034* + ID_MODEL_FROM_DATABASE=SideWinder Force Feedback Wheel + +usb:v045Ep0038* + ID_MODEL_FROM_DATABASE=SideWinder Precision 2 + +usb:v045Ep0039* + ID_MODEL_FROM_DATABASE=IntelliMouse Optical + +usb:v045Ep003B* + ID_MODEL_FROM_DATABASE=SideWinder Game Voice + +usb:v045Ep003C* + ID_MODEL_FROM_DATABASE=SideWinder Joystick + +usb:v045Ep0040* + ID_MODEL_FROM_DATABASE=Wheel Mouse Optical + +usb:v045Ep0047* + ID_MODEL_FROM_DATABASE=IntelliMouse Explorer 3.0 + +usb:v045Ep0048* + ID_MODEL_FROM_DATABASE=Office Keyboard 1.0A + +usb:v045Ep0053* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v045Ep0059* + ID_MODEL_FROM_DATABASE=Wireless IntelliMouse Explorer + +usb:v045Ep005C* + ID_MODEL_FROM_DATABASE=Office Keyboard (106/109) + +usb:v045Ep005F* + ID_MODEL_FROM_DATABASE=Wireless MultiMedia Keyboard + +usb:v045Ep0061* + ID_MODEL_FROM_DATABASE=Wireless MultiMedia Keyboard (106/109) + +usb:v045Ep0063* + ID_MODEL_FROM_DATABASE=Wireless Natural MultiMedia Keyboard + +usb:v045Ep0065* + ID_MODEL_FROM_DATABASE=Wireless Natural MultiMedia Keyboard (106/109) + +usb:v045Ep006A* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse (IntelliPoint) + +usb:v045Ep006D* + ID_MODEL_FROM_DATABASE=eHome Remote Control Keyboard keys + +usb:v045Ep006E* + ID_MODEL_FROM_DATABASE=MN-510 802.11b Wireless Adapter [Intersil ISL3873B] + +usb:v045Ep006F* + ID_MODEL_FROM_DATABASE=Smart Display Reference Device + +usb:v045Ep0070* + ID_MODEL_FROM_DATABASE=Wireless MultiMedia Keyboard + +usb:v045Ep0071* + ID_MODEL_FROM_DATABASE=Wireless MultiMedia Keyboard (106/109) + +usb:v045Ep0072* + ID_MODEL_FROM_DATABASE=Wireless Natural MultiMedia Keyboard + +usb:v045Ep0073* + ID_MODEL_FROM_DATABASE=Wireless Natural MultiMedia Keyboard (106/109) + +usb:v045Ep0079* + ID_MODEL_FROM_DATABASE=IXI Ogo CT-17 handheld device + +usb:v045Ep007A* + ID_MODEL_FROM_DATABASE=10/100 USB NIC + +usb:v045Ep007D* + ID_MODEL_FROM_DATABASE=Notebook Optical Mouse + +usb:v045Ep007E* + ID_MODEL_FROM_DATABASE=Wireless Transceiver for Bluetooth + +usb:v045Ep0080* + ID_MODEL_FROM_DATABASE=Digital Media Pro Keyboard + +usb:v045Ep0083* + ID_MODEL_FROM_DATABASE=Basic Optical Mouse + +usb:v045Ep0084* + ID_MODEL_FROM_DATABASE=Basic Optical Mouse + +usb:v045Ep008A* + ID_MODEL_FROM_DATABASE=Wireless Keyboard and Mouse + +usb:v045Ep008B* + ID_MODEL_FROM_DATABASE=Dual Receiver Wireless Mouse (IntelliPoint) + +usb:v045Ep008C* + ID_MODEL_FROM_DATABASE=Wireless Intellimouse Explorer 2.0 + +usb:v045Ep0095* + ID_MODEL_FROM_DATABASE=IntelliMouse Explorer 4.0 (IntelliPoint) + +usb:v045Ep009C* + ID_MODEL_FROM_DATABASE=Wireless Transceiver for Bluetooth 2.0 + +usb:v045Ep009D* + ID_MODEL_FROM_DATABASE=Wireless Optical Desktop 3.0 + +usb:v045Ep00A0* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v045Ep00A4* + ID_MODEL_FROM_DATABASE=Compact Optical Mouse, model 1016 + +usb:v045Ep00B0* + ID_MODEL_FROM_DATABASE=Digital Media Pro Keyboard + +usb:v045Ep00B4* + ID_MODEL_FROM_DATABASE=Digital Media Keyboard 1.0A + +usb:v045Ep00B9* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse 3.0 + +usb:v045Ep00BB* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v045Ep00BC* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v045Ep00BD* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v045Ep00C2* + ID_MODEL_FROM_DATABASE=MN-710 802.11g Wireless Adapter [Intersil ISL3886] + +usb:v045Ep00C9* + ID_MODEL_FROM_DATABASE=MTP Device + +usb:v045Ep00CA* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v045Ep00CB* + ID_MODEL_FROM_DATABASE=Basic Optical Mouse v2.0 + +usb:v045Ep00CE* + ID_MODEL_FROM_DATABASE=Generic PPC Flash device + +usb:v045Ep00D1* + ID_MODEL_FROM_DATABASE=Optical Mouse with Tilt Wheel + +usb:v045Ep00DA* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v045Ep00DB* + ID_MODEL_FROM_DATABASE=Natural Ergonomic Keyboard 4000 V1.0 + +usb:v045Ep00DD* + ID_MODEL_FROM_DATABASE=Comfort Curve Keyboard 2000 V1.0 + +usb:v045Ep00E1* + ID_MODEL_FROM_DATABASE=Wireless Laser Mouse 6000 Reciever + +usb:v045Ep00F4* + ID_MODEL_FROM_DATABASE=LifeCam VX-6000 (SN9C20x + OV9650) + +usb:v045Ep00F5* + ID_MODEL_FROM_DATABASE=LifeCam VX-3000 + +usb:v045Ep00F6* + ID_MODEL_FROM_DATABASE=Comfort Optical Mouse 1000 + +usb:v045Ep00F7* + ID_MODEL_FROM_DATABASE=LifeCam VX-1000 + +usb:v045Ep00F8* + ID_MODEL_FROM_DATABASE=LifeCam NX-6000 + +usb:v045Ep00F9* + ID_MODEL_FROM_DATABASE=Wireless Desktop Receiver 3.1 + +usb:v045Ep0202* + ID_MODEL_FROM_DATABASE=Xbox Controller + +usb:v045Ep0280* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v045Ep0283* + ID_MODEL_FROM_DATABASE=Xbox Communicator + +usb:v045Ep0284* + ID_MODEL_FROM_DATABASE=Xbox DVD Playback Kit + +usb:v045Ep0285* + ID_MODEL_FROM_DATABASE=Xbox Controller S + +usb:v045Ep0288* + ID_MODEL_FROM_DATABASE=Xbox Controller S Hub + +usb:v045Ep0289* + ID_MODEL_FROM_DATABASE=Xbox Controller S + +usb:v045Ep028B* + ID_MODEL_FROM_DATABASE=Xbox360 DVD Emulator + +usb:v045Ep028D* + ID_MODEL_FROM_DATABASE=Xbox360 Memory Unit 64MB + +usb:v045Ep028E* + ID_MODEL_FROM_DATABASE=Xbox360 Controller + +usb:v045Ep028F* + ID_MODEL_FROM_DATABASE=Xbox360 Wireless Controller + +usb:v045Ep0290* + ID_MODEL_FROM_DATABASE=Xbox360 Performance Pipe (PIX) + +usb:v045Ep0291* + ID_MODEL_FROM_DATABASE=Xbox 360 Wireless Receiver for Windows + +usb:v045Ep0292* + ID_MODEL_FROM_DATABASE=Xbox360 Wireless Networking Adapter + +usb:v045Ep029C* + ID_MODEL_FROM_DATABASE=Xbox360 HD-DVD Drive + +usb:v045Ep029D* + ID_MODEL_FROM_DATABASE=Xbox360 HD-DVD Drive + +usb:v045Ep029E* + ID_MODEL_FROM_DATABASE=Xbox360 HD-DVD Memory Unit + +usb:v045Ep02A0* + ID_MODEL_FROM_DATABASE=Xbox360 Big Button IR + +usb:v045Ep02A1* + ID_MODEL_FROM_DATABASE=Xbox 360 Wireless Receiver for Windows + +usb:v045Ep02A8* + ID_MODEL_FROM_DATABASE=Xbox360 Wireless N Networking Adapter [Atheros AR7010+AR9280] + +usb:v045Ep02AD* + ID_MODEL_FROM_DATABASE=Xbox NUI Audio + +usb:v045Ep02AE* + ID_MODEL_FROM_DATABASE=Xbox NUI Camera + +usb:v045Ep02B0* + ID_MODEL_FROM_DATABASE=Xbox NUI Motor + +usb:v045Ep02B6* + ID_MODEL_FROM_DATABASE=Xbox 360 / Bluetooth Wireless Headset + +usb:v045Ep0400* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0401* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0402* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0403* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0404* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0405* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0406* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0407* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0408* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0409* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040C* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040D* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040E* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep040F* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0410* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0411* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0412* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0413* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0414* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0415* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0416* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0417* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002 + +usb:v045Ep0432* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0433* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0434* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0435* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0436* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0437* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0438* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0439* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep043A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep043B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep043C* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep043D* + ID_MODEL_FROM_DATABASE=Becker Traffic Assist Highspeed 7934 + +usb:v045Ep043E* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep043F* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0440* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0441* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0442* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0443* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0444* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0445* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0446* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0447* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0448* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0449* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044C* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044D* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044E* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep044F* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0450* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0451* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0452* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0453* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0454* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0455* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0456* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0457* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0458* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0459* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045C* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045D* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045E* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep045F* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0460* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0461* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0462* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0463* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0464* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0465* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0466* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0467* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0468* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0469* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046C* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046D* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046E* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep046F* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0470* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0471* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0472* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0473* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0474* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0475* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0476* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0477* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0478* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep0479* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep047A* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep047B* + ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2003 + +usb:v045Ep04C8* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04C9* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04CA* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04CB* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04CC* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04CD* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04CE* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2002 + +usb:v045Ep04D7* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04D8* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04D9* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DA* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DB* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DC* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DD* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DE* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04DF* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E0* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E1* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E2* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E3* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E4* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E5* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E6* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E7* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E8* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04E9* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04EA* + ID_MODEL_FROM_DATABASE=Windows Powered Smartphone 2003 + +usb:v045Ep04EC* + ID_MODEL_FROM_DATABASE=Windows Phone (Zune) + +usb:v045Ep063E* + ID_MODEL_FROM_DATABASE=Zune HD Media Player + +usb:v045Ep0640* + ID_MODEL_FROM_DATABASE=KIN Phone + +usb:v045Ep0641* + ID_MODEL_FROM_DATABASE=KIN Phone + +usb:v045Ep0642* + ID_MODEL_FROM_DATABASE=KIN Phone + +usb:v045Ep0707* + ID_MODEL_FROM_DATABASE=Wireless Laser Mouse 8000 + +usb:v045Ep0708* + ID_MODEL_FROM_DATABASE=Transceiver v 3.0 for Bluetooth + +usb:v045Ep070A* + ID_MODEL_FROM_DATABASE=Charon Bluetooth Dongle (DFU) + +usb:v045Ep0710* + ID_MODEL_FROM_DATABASE=Zune Media Player + +usb:v045Ep0713* + ID_MODEL_FROM_DATABASE=Wireless Presenter Mouse 8000 + +usb:v045Ep0719* + ID_MODEL_FROM_DATABASE=Xbox 360 Wireless Adapter + +usb:v045Ep071F* + ID_MODEL_FROM_DATABASE=Mouse/Keyboard 2.4GHz Transceiver V2.0 + +usb:v045Ep0721* + ID_MODEL_FROM_DATABASE=LifeCam NX-3000 (UVC-compliant) + +usb:v045Ep0723* + ID_MODEL_FROM_DATABASE=LifeCam VX-7000 (UVC-compliant) + +usb:v045Ep0724* + ID_MODEL_FROM_DATABASE=SideWinder Mouse + +usb:v045Ep0730* + ID_MODEL_FROM_DATABASE=Digital Media Keyboard 3000 + +usb:v045Ep0734* + ID_MODEL_FROM_DATABASE=Wireless Optical Desktop 700 + +usb:v045Ep0736* + ID_MODEL_FROM_DATABASE=Sidewinder X5 Mouse + +usb:v045Ep0737* + ID_MODEL_FROM_DATABASE=Compact Optical Mouse 500 + +usb:v045Ep0745* + ID_MODEL_FROM_DATABASE=Nano Transceiver v1.0 for Bluetooth + +usb:v045Ep0750* + ID_MODEL_FROM_DATABASE=Wired Keyboard 600 + +usb:v045Ep0752* + ID_MODEL_FROM_DATABASE=Wired Keyboard 400 + +usb:v045Ep075D* + ID_MODEL_FROM_DATABASE=LifeCam Cinema + +usb:v045Ep0766* + ID_MODEL_FROM_DATABASE=LifeCam VX-800 + +usb:v045Ep0768* + ID_MODEL_FROM_DATABASE=Sidewinder X4 + +usb:v045Ep076C* + ID_MODEL_FROM_DATABASE=Comfort Mouse 4500 + +usb:v045Ep076D* + ID_MODEL_FROM_DATABASE=LifeCam HD-5000 + +usb:v045Ep0772* + ID_MODEL_FROM_DATABASE=LifeCam Studio + +usb:v045Ep0779* + ID_MODEL_FROM_DATABASE=LifeCam HD-3000 + +usb:v045Ep0797* + ID_MODEL_FROM_DATABASE=Optical Mouse 200 + +usb:v045Ep930A* + ID_MODEL_FROM_DATABASE=ISOUSB.SYS Intel 82930 Isochronous IO Test Board + +usb:v045EpFFCA* + ID_MODEL_FROM_DATABASE=Catalina + +usb:v045EpFFF8* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v045EpFFFF* + ID_MODEL_FROM_DATABASE=Windows CE Mass Storage + +usb:v0460* + ID_VENDOR_FROM_DATABASE=Ace Cad Enterprise Co., Ltd + +usb:v0460p0004* + ID_MODEL_FROM_DATABASE=Tablet (5x3.75) + +usb:v0460p0006* + ID_MODEL_FROM_DATABASE=LCD Tablet (12x9) + +usb:v0460p0008* + ID_MODEL_FROM_DATABASE=Tablet (3x2.25) + +usb:v0461* + ID_VENDOR_FROM_DATABASE=Primax Electronics, Ltd + +usb:v0461p0010* + ID_MODEL_FROM_DATABASE=HP Keyboard + +usb:v0461p0300* + ID_MODEL_FROM_DATABASE=G2-300 Scanner + +usb:v0461p0301* + ID_MODEL_FROM_DATABASE=G2E-300 Scanner + +usb:v0461p0302* + ID_MODEL_FROM_DATABASE=G2-300 #2 Scanner + +usb:v0461p0303* + ID_MODEL_FROM_DATABASE=G2E-300 #2 Scanner + +usb:v0461p0340* + ID_MODEL_FROM_DATABASE=Colorado 9600 Scanner + +usb:v0461p0341* + ID_MODEL_FROM_DATABASE=Colorado 600u Scanner + +usb:v0461p0345* + ID_MODEL_FROM_DATABASE=Visioneer 6200 Scanner + +usb:v0461p0346* + ID_MODEL_FROM_DATABASE=Memorex Maxx 6136u Scanner + +usb:v0461p0347* + ID_MODEL_FROM_DATABASE=Primascan Colorado 2600u/Visioneer 4400 Scanner + +usb:v0461p0360* + ID_MODEL_FROM_DATABASE=Colorado 19200 Scanner + +usb:v0461p0361* + ID_MODEL_FROM_DATABASE=Colorado 1200u Scanner + +usb:v0461p0363* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p0364* + ID_MODEL_FROM_DATABASE=LG Electronics Scanworks 600U Scanner + +usb:v0461p0365* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p0366* + ID_MODEL_FROM_DATABASE=6400 + +usb:v0461p0367* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p0371* + ID_MODEL_FROM_DATABASE=Visioneer Onetouch 8920 Scanner + +usb:v0461p0374* + ID_MODEL_FROM_DATABASE=UMAX Astra 2500 + +usb:v0461p0375* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p0377* + ID_MODEL_FROM_DATABASE=Medion MD 5345 Scanner + +usb:v0461p0378* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p037B* + ID_MODEL_FROM_DATABASE=Medion MD 6190 Scanner + +usb:v0461p037C* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v0461p0380* + ID_MODEL_FROM_DATABASE=G2-600 Scanner + +usb:v0461p0381* + ID_MODEL_FROM_DATABASE=ReadyScan 636i Scanner + +usb:v0461p0382* + ID_MODEL_FROM_DATABASE=G2-600 #2 Scanner + +usb:v0461p0383* + ID_MODEL_FROM_DATABASE=G2E-600 Scanner + +usb:v0461p038A* + ID_MODEL_FROM_DATABASE=UMAX Astra 3000/3600 + +usb:v0461p038B* + ID_MODEL_FROM_DATABASE=Xerox 2400 Onetouch + +usb:v0461p038C* + ID_MODEL_FROM_DATABASE=UMAX Astra 4100 + +usb:v0461p0392* + ID_MODEL_FROM_DATABASE=Medion/Lifetec/Tevion/Cytron MD 6190 + +usb:v0461p03A8* + ID_MODEL_FROM_DATABASE=9420M + +usb:v0461p0813* + ID_MODEL_FROM_DATABASE=IBM UltraPort Camera + +usb:v0461p0815* + ID_MODEL_FROM_DATABASE=Micro Innovations IC200 Webcam + +usb:v0461p0819* + ID_MODEL_FROM_DATABASE=Fujifilm IX-30 Camera [webcam mode] + +usb:v0461p081A* + ID_MODEL_FROM_DATABASE=Fujifilm IX-30 Camera [storage mode] + +usb:v0461p081C* + ID_MODEL_FROM_DATABASE=Elitegroup ECS-C11 Camera + +usb:v0461p081D* + ID_MODEL_FROM_DATABASE=Elitegroup ECS-C11 Storage + +usb:v0461p0A00* + ID_MODEL_FROM_DATABASE=Micro Innovations Web Cam 320 + +usb:v0461p4D01* + ID_MODEL_FROM_DATABASE=Comfort Keyboard + +usb:v0461p4D02* + ID_MODEL_FROM_DATABASE=Mouse-in-a-Box + +usb:v0461p4D03* + ID_MODEL_FROM_DATABASE=Kensington Mouse-in-a-box + +usb:v0461p4D04* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0461p4D06* + ID_MODEL_FROM_DATABASE=Balless Mouse (HID) + +usb:v0461p4D0F* + ID_MODEL_FROM_DATABASE=HP Optical Mouse + +usb:v0461p4D15* + ID_MODEL_FROM_DATABASE=Dell Optical Mouse + +usb:v0461p4D17* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v0461p4D20* + ID_MODEL_FROM_DATABASE=HP Optical Mouse + +usb:v0461p4D2A* + ID_MODEL_FROM_DATABASE=PoPo Elixir Mouse (HID) + +usb:v0461p4D2B* + ID_MODEL_FROM_DATABASE=Wireless Laser Mini Mouse (HID) + +usb:v0461p4D2C* + ID_MODEL_FROM_DATABASE=PoPo Mini Pointer Mouse (HID) + +usb:v0461p4D2E* + ID_MODEL_FROM_DATABASE=Optical Mobile Mouse (HID) + +usb:v0461p4D51* + ID_MODEL_FROM_DATABASE=0Y357C PMX-MMOCZUL (B) [Dell Laser Mouse] + +usb:v0461p4D62* + ID_MODEL_FROM_DATABASE=HP Laser Mobile Mini Mouse + +usb:v0461p4D75* + ID_MODEL_FROM_DATABASE=Rocketfish RF-FLBTAD Bluetooth Adapter + +usb:v0461p4D81* + ID_MODEL_FROM_DATABASE=Dell N889 Optical Mouse + +usb:v0461p4DE7* + ID_MODEL_FROM_DATABASE=webcam + +usb:v0463* + ID_VENDOR_FROM_DATABASE=MGE UPS Systems + +usb:v0463p0001* + ID_MODEL_FROM_DATABASE=UPS + +usb:v0463pFFFF* + ID_MODEL_FROM_DATABASE=UPS + +usb:v0464* + ID_VENDOR_FROM_DATABASE=AMP/Tycoelectronics Corp. + +usb:v0467* + ID_VENDOR_FROM_DATABASE=AT&T Paradyne + +usb:v0468* + ID_VENDOR_FROM_DATABASE=Wieson Technologies Co., Ltd + +usb:v046A* + ID_VENDOR_FROM_DATABASE=Cherry GmbH + +usb:v046Ap0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v046Ap0003* + ID_MODEL_FROM_DATABASE=My3000 Hub + +usb:v046Ap0004* + ID_MODEL_FROM_DATABASE=CyBoard Keyboard + +usb:v046Ap0005* + ID_MODEL_FROM_DATABASE=XX33 SmartCard Reader Keyboard + +usb:v046Ap0008* + ID_MODEL_FROM_DATABASE=Wireless Keyboard and Mouse + +usb:v046Ap0010* + ID_MODEL_FROM_DATABASE=SmartBoard XX44 + +usb:v046Ap0011* + ID_MODEL_FROM_DATABASE=G83 (RS 6000) Keyboard + +usb:v046Ap0021* + ID_MODEL_FROM_DATABASE=CyMotion Expert Combo + +usb:v046Ap0023* + ID_MODEL_FROM_DATABASE=CyMotion Master Linux Keyboard G230 + +usb:v046Ap0027* + ID_MODEL_FROM_DATABASE=CyMotion Master Solar Keyboard + +usb:v046Ap002A* + ID_MODEL_FROM_DATABASE=Wireless Mouse & Keyboard + +usb:v046Ap002D* + ID_MODEL_FROM_DATABASE=SmartTerminal XX44 + +usb:v046Ap003E* + ID_MODEL_FROM_DATABASE=SmartTerminal ST-2xxx + +usb:v046Ap0041* + ID_MODEL_FROM_DATABASE=G86 6240 Keyboard + +usb:v046Ap0080* + ID_MODEL_FROM_DATABASE=eHealth Terminal ST 1503 + +usb:v046Ap0081* + ID_MODEL_FROM_DATABASE=eHealth Keyboard G87 1504 + +usb:v046Ap0106* + ID_MODEL_FROM_DATABASE=R-300 Wireless Mouse Receiver + +usb:v046B* + ID_VENDOR_FROM_DATABASE=American Megatrends, Inc. + +usb:v046Bp0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v046Bp0101* + ID_MODEL_FROM_DATABASE=PS/2 Keyboard, Mouse & Joystick Ports + +usb:v046Bp0301* + ID_MODEL_FROM_DATABASE=USB 1.0 Hub + +usb:v046Bp0500* + ID_MODEL_FROM_DATABASE=Serial & Parallel Ports + +usb:v046BpFF10* + ID_MODEL_FROM_DATABASE=Virtual Keyboard and Mouse + +usb:v046C* + ID_VENDOR_FROM_DATABASE=Toshiba Corp., Digital Media Equipment + +usb:v046D* + ID_VENDOR_FROM_DATABASE=Logitech, Inc. + +usb:v046Dp0082* + ID_MODEL_FROM_DATABASE=Acer Aspire 5672 Webcam + +usb:v046Dp0200* + ID_MODEL_FROM_DATABASE=WingMan Extreme Joystick + +usb:v046Dp0203* + ID_MODEL_FROM_DATABASE=M2452 Keyboard + +usb:v046Dp0301* + ID_MODEL_FROM_DATABASE=M4848 Mouse + +usb:v046Dp0401* + ID_MODEL_FROM_DATABASE=HP PageScan + +usb:v046Dp0402* + ID_MODEL_FROM_DATABASE=NEC PageScan + +usb:v046Dp040F* + ID_MODEL_FROM_DATABASE=Logitech/Storm PageScan + +usb:v046Dp0430* + ID_MODEL_FROM_DATABASE=Mic (Cordless) + +usb:v046Dp0801* + ID_MODEL_FROM_DATABASE=QuickCam Home + +usb:v046Dp0802* + ID_MODEL_FROM_DATABASE=Webcam C200 + +usb:v046Dp0804* + ID_MODEL_FROM_DATABASE=Webcam C250 + +usb:v046Dp0805* + ID_MODEL_FROM_DATABASE=Webcam C300 + +usb:v046Dp0807* + ID_MODEL_FROM_DATABASE=Webcam B500 + +usb:v046Dp0808* + ID_MODEL_FROM_DATABASE=Webcam C600 + +usb:v046Dp0809* + ID_MODEL_FROM_DATABASE=Webcam Pro 9000 + +usb:v046Dp080A* + ID_MODEL_FROM_DATABASE=Portable Webcam C905 + +usb:v046Dp080F* + ID_MODEL_FROM_DATABASE=Webcam C120 + +usb:v046Dp0810* + ID_MODEL_FROM_DATABASE=QuickCam Pro + +usb:v046Dp0819* + ID_MODEL_FROM_DATABASE=Webcam C210 + +usb:v046Dp081B* + ID_MODEL_FROM_DATABASE=Webcam C310 + +usb:v046Dp081D* + ID_MODEL_FROM_DATABASE=HD Webcam C510 + +usb:v046Dp0820* + ID_MODEL_FROM_DATABASE=QuickCam VC + +usb:v046Dp0821* + ID_MODEL_FROM_DATABASE=HD Webcam C910 + +usb:v046Dp0825* + ID_MODEL_FROM_DATABASE=Webcam C270 + +usb:v046Dp0828* + ID_MODEL_FROM_DATABASE=HD Webcam B990 + +usb:v046Dp082D* + ID_MODEL_FROM_DATABASE=HD Pro Webcam C920 + +usb:v046Dp0830* + ID_MODEL_FROM_DATABASE=QuickClip + +usb:v046Dp0840* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp0850* + ID_MODEL_FROM_DATABASE=QuickCam Web + +usb:v046Dp0870* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp0890* + ID_MODEL_FROM_DATABASE=QuickCam Traveler + +usb:v046Dp0892* + ID_MODEL_FROM_DATABASE=OrbiCam + +usb:v046Dp0894* + ID_MODEL_FROM_DATABASE=CrystalCam + +usb:v046Dp0895* + ID_MODEL_FROM_DATABASE=QuickCam for Dell Notebooks + +usb:v046Dp0896* + ID_MODEL_FROM_DATABASE=OrbiCam + +usb:v046Dp0897* + ID_MODEL_FROM_DATABASE=QuickCam for Dell Notebooks + +usb:v046Dp0899* + ID_MODEL_FROM_DATABASE=QuickCam for Dell Notebooks + +usb:v046Dp089D* + ID_MODEL_FROM_DATABASE=QuickCam E2500 series + +usb:v046Dp08A0* + ID_MODEL_FROM_DATABASE=QuickCam IM + +usb:v046Dp08A1* + ID_MODEL_FROM_DATABASE=QuickCam IM with sound + +usb:v046Dp08A2* + ID_MODEL_FROM_DATABASE=Labtec Webcam Pro + +usb:v046Dp08A3* + ID_MODEL_FROM_DATABASE=QuickCam QuickCam Chat + +usb:v046Dp08A6* + ID_MODEL_FROM_DATABASE=QuickCam IM + +usb:v046Dp08A7* + ID_MODEL_FROM_DATABASE=QuickCam Image + +usb:v046Dp08A9* + ID_MODEL_FROM_DATABASE=Notebook Deluxe + +usb:v046Dp08AA* + ID_MODEL_FROM_DATABASE=Labtec Notebooks + +usb:v046Dp08AC* + ID_MODEL_FROM_DATABASE=QuickCam Cool + +usb:v046Dp08AD* + ID_MODEL_FROM_DATABASE=QuickCam Communicate STX + +usb:v046Dp08AE* + ID_MODEL_FROM_DATABASE=QuickCam for Notebooks + +usb:v046Dp08AF* + ID_MODEL_FROM_DATABASE=QuickCam Easy/Cool + +usb:v046Dp08B0* + ID_MODEL_FROM_DATABASE=QuickCam 3000 Pro [pwc] + +usb:v046Dp08B1* + ID_MODEL_FROM_DATABASE=QuickCam Notebook Pro + +usb:v046Dp08B2* + ID_MODEL_FROM_DATABASE=QuickCam Pro 4000 + +usb:v046Dp08B3* + ID_MODEL_FROM_DATABASE=QuickCam Zoom + +usb:v046Dp08B4* + ID_MODEL_FROM_DATABASE=QuickCam Zoom + +usb:v046Dp08B5* + ID_MODEL_FROM_DATABASE=QuickCam Sphere + +usb:v046Dp08B9* + ID_MODEL_FROM_DATABASE=QuickCam IM + +usb:v046Dp08BD* + ID_MODEL_FROM_DATABASE=Microphone (Pro 4000) + +usb:v046Dp08C0* + ID_MODEL_FROM_DATABASE=QuickCam Pro 3000 + +usb:v046Dp08C1* + ID_MODEL_FROM_DATABASE=QuickCam Fusion + +usb:v046Dp08C2* + ID_MODEL_FROM_DATABASE=QuickCam PTZ + +usb:v046Dp08C3* + ID_MODEL_FROM_DATABASE=Camera (Notebooks Pro) + +usb:v046Dp08C5* + ID_MODEL_FROM_DATABASE=QuickCam Pro 5000 + +usb:v046Dp08C6* + ID_MODEL_FROM_DATABASE=QuickCam for DELL Notebooks + +usb:v046Dp08C7* + ID_MODEL_FROM_DATABASE=QuickCam OEM Cisco VT Camera II + +usb:v046Dp08C9* + ID_MODEL_FROM_DATABASE=QuickCam Ultra Vision + +usb:v046Dp08CA* + ID_MODEL_FROM_DATABASE=Mic (Fusion) + +usb:v046Dp08CB* + ID_MODEL_FROM_DATABASE=Mic (Notebooks Pro) + +usb:v046Dp08CC* + ID_MODEL_FROM_DATABASE=Mic (PTZ) + +usb:v046Dp08CE* + ID_MODEL_FROM_DATABASE=QuickCam Pro 5000 + +usb:v046Dp08CF* + ID_MODEL_FROM_DATABASE=QuickCam UpdateMe + +usb:v046Dp08D0* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp08D7* + ID_MODEL_FROM_DATABASE=QuickCam Communicate STX + +usb:v046Dp08D8* + ID_MODEL_FROM_DATABASE=QuickCam for Notebook Deluxe + +usb:v046Dp08D9* + ID_MODEL_FROM_DATABASE=QuickCam IM/Connect + +usb:v046Dp08DA* + ID_MODEL_FROM_DATABASE=QuickCam Messanger + +usb:v046Dp08DD* + ID_MODEL_FROM_DATABASE=QuickCam for Notebooks + +usb:v046Dp08E0* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp08E1* + ID_MODEL_FROM_DATABASE=Labtec Webcam + +usb:v046Dp08F0* + ID_MODEL_FROM_DATABASE=QuickCam Messenger + +usb:v046Dp08F1* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp08F2* + ID_MODEL_FROM_DATABASE=Microphone (Messenger) + +usb:v046Dp08F3* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp08F4* + ID_MODEL_FROM_DATABASE=Labtec Webcam + +usb:v046Dp08F5* + ID_MODEL_FROM_DATABASE=QuickCam Messenger Communicate + +usb:v046Dp08F6* + ID_MODEL_FROM_DATABASE=QuickCam Messenger Plus + +usb:v046Dp0900* + ID_MODEL_FROM_DATABASE=ClickSmart 310 + +usb:v046Dp0901* + ID_MODEL_FROM_DATABASE=ClickSmart 510 + +usb:v046Dp0903* + ID_MODEL_FROM_DATABASE=ClickSmart 820 + +usb:v046Dp0905* + ID_MODEL_FROM_DATABASE=ClickSmart 820 + +usb:v046Dp0910* + ID_MODEL_FROM_DATABASE=QuickCam Cordless + +usb:v046Dp0920* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp0921* + ID_MODEL_FROM_DATABASE=Labtec Webcam + +usb:v046Dp0922* + ID_MODEL_FROM_DATABASE=QuickCam Live + +usb:v046Dp0928* + ID_MODEL_FROM_DATABASE=QuickCam Express + +usb:v046Dp0929* + ID_MODEL_FROM_DATABASE=Labtec Webcam Pro + +usb:v046Dp092A* + ID_MODEL_FROM_DATABASE=QuickCam for Notebooks + +usb:v046Dp092B* + ID_MODEL_FROM_DATABASE=Labtec Webcam Plus + +usb:v046Dp092C* + ID_MODEL_FROM_DATABASE=QuickCam Chat + +usb:v046Dp092D* + ID_MODEL_FROM_DATABASE=QuickCam Express / Go + +usb:v046Dp092E* + ID_MODEL_FROM_DATABASE=QuickCam Chat + +usb:v046Dp092F* + ID_MODEL_FROM_DATABASE=QuickCam Express Plus + +usb:v046Dp0950* + ID_MODEL_FROM_DATABASE=Pocket Camera + +usb:v046Dp0960* + ID_MODEL_FROM_DATABASE=ClickSmart 420 + +usb:v046Dp0970* + ID_MODEL_FROM_DATABASE=Pocket750 + +usb:v046Dp0990* + ID_MODEL_FROM_DATABASE=QuickCam Pro 9000 + +usb:v046Dp0991* + ID_MODEL_FROM_DATABASE=QuickCam Pro for Notebooks + +usb:v046Dp0992* + ID_MODEL_FROM_DATABASE=QuickCam Communicate Deluxe + +usb:v046Dp0994* + ID_MODEL_FROM_DATABASE=QuickCam Orbit/Sphere AF + +usb:v046Dp09A1* + ID_MODEL_FROM_DATABASE=QuickCam Communicate MP/S5500 + +usb:v046Dp09A2* + ID_MODEL_FROM_DATABASE=QuickCam Communicate Deluxe/S7500 + +usb:v046Dp09A4* + ID_MODEL_FROM_DATABASE=QuickCam E 3500 + +usb:v046Dp09A5* + ID_MODEL_FROM_DATABASE=Quickcam 3000 For Business + +usb:v046Dp09A6* + ID_MODEL_FROM_DATABASE=QuickCam Vision Pro + +usb:v046Dp09B0* + ID_MODEL_FROM_DATABASE=Acer OrbiCam + +usb:v046Dp09B2* + ID_MODEL_FROM_DATABASE=Fujitsu Webcam + +usb:v046Dp09C0* + ID_MODEL_FROM_DATABASE=QuickCam for Dell Notebooks Mic + +usb:v046Dp09C1* + ID_MODEL_FROM_DATABASE=QuickCam Deluxe for Notebooks + +usb:v046Dp0A01* + ID_MODEL_FROM_DATABASE=USB Headset + +usb:v046Dp0A02* + ID_MODEL_FROM_DATABASE=Premium Stereo USB Headset 350 + +usb:v046Dp0A03* + ID_MODEL_FROM_DATABASE=Logitech USB Microphone + +usb:v046Dp0A04* + ID_MODEL_FROM_DATABASE=V20 portable speakers (USB powered) + +usb:v046Dp0A07* + ID_MODEL_FROM_DATABASE=Z-10 Speakers + +usb:v046Dp0A0B* + ID_MODEL_FROM_DATABASE=ClearChat Pro USB + +usb:v046Dp0A0C* + ID_MODEL_FROM_DATABASE=Clear Chat Comfort USB Headset + +usb:v046Dp0A13* + ID_MODEL_FROM_DATABASE=Z-5 Speakers + +usb:v046Dp0A17* + ID_MODEL_FROM_DATABASE=G330 Headset + +usb:v046Dp0A1F* + ID_MODEL_FROM_DATABASE=G930 + +usb:v046Dp0A29* + ID_MODEL_FROM_DATABASE=H600 [Wireless Headset] + +usb:v046Dp0B02* + ID_MODEL_FROM_DATABASE=C-UV35 [Bluetooth Mini-Receiver] (HID proxy mode) + +usb:v046Dp8801* + ID_MODEL_FROM_DATABASE=Video Camera + +usb:v046DpB305* + ID_MODEL_FROM_DATABASE=BT Mini-Receiver + +usb:v046DpBFE4* + ID_MODEL_FROM_DATABASE=Premium Optical Wheel Mouse + +usb:v046DpC000* + ID_MODEL_FROM_DATABASE=N43 [Pilot Mouse] + +usb:v046DpC001* + ID_MODEL_FROM_DATABASE=N48/M-BB48 [FirstMouse Plus] + +usb:v046DpC002* + ID_MODEL_FROM_DATABASE=M-BA47 [MouseMan Plus] + +usb:v046DpC003* + ID_MODEL_FROM_DATABASE=MouseMan + +usb:v046DpC004* + ID_MODEL_FROM_DATABASE=WingMan Gaming Mouse + +usb:v046DpC005* + ID_MODEL_FROM_DATABASE=WingMan Gaming Wheel Mouse + +usb:v046DpC00B* + ID_MODEL_FROM_DATABASE=MouseMan Wheel + +usb:v046DpC00C* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse + +usb:v046DpC00D* + ID_MODEL_FROM_DATABASE=MouseMan Wheel+ + +usb:v046DpC00E* + ID_MODEL_FROM_DATABASE=M-BJ58/M-BJ69 Optical Wheel Mouse + +usb:v046DpC00F* + ID_MODEL_FROM_DATABASE=MouseMan Traveler/Mobile + +usb:v046DpC011* + ID_MODEL_FROM_DATABASE=Optical MouseMan + +usb:v046DpC012* + ID_MODEL_FROM_DATABASE=Mouseman Dual Optical + +usb:v046DpC014* + ID_MODEL_FROM_DATABASE=Corded Workstation Mouse + +usb:v046DpC015* + ID_MODEL_FROM_DATABASE=Corded Workstation Mouse + +usb:v046DpC016* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse + +usb:v046DpC018* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse + +usb:v046DpC019* + ID_MODEL_FROM_DATABASE=Optical Tilt Wheel Mouse + +usb:v046DpC01A* + ID_MODEL_FROM_DATABASE=M-BQ85 Optical Wheel Mouse + +usb:v046DpC01B* + ID_MODEL_FROM_DATABASE=MX310 Optical Mouse + +usb:v046DpC01C* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v046DpC01D* + ID_MODEL_FROM_DATABASE=MX510 Optical Mouse + +usb:v046DpC01E* + ID_MODEL_FROM_DATABASE=MX518 Optical Mouse + +usb:v046DpC024* + ID_MODEL_FROM_DATABASE=MX300 Optical Mouse + +usb:v046DpC025* + ID_MODEL_FROM_DATABASE=MX500 Optical Mouse + +usb:v046DpC030* + ID_MODEL_FROM_DATABASE=iFeel Mouse + +usb:v046DpC031* + ID_MODEL_FROM_DATABASE=iFeel Mouse+ + +usb:v046DpC032* + ID_MODEL_FROM_DATABASE=MouseMan iFeel + +usb:v046DpC033* + ID_MODEL_FROM_DATABASE=iFeel MouseMan+ + +usb:v046DpC034* + ID_MODEL_FROM_DATABASE=MouseMan Optical + +usb:v046DpC035* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v046DpC036* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v046DpC037* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v046DpC038* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v046DpC03D* + ID_MODEL_FROM_DATABASE=M-BT96a Pilot Optical Mouse + +usb:v046DpC03E* + ID_MODEL_FROM_DATABASE=Premium Optical Wheel Mouse (M-BT58) + +usb:v046DpC03F* + ID_MODEL_FROM_DATABASE=M-BT85 [UltraX Optical Mouse] + +usb:v046DpC040* + ID_MODEL_FROM_DATABASE=Corded Tilt-Wheel Mouse + +usb:v046DpC041* + ID_MODEL_FROM_DATABASE=G5 Laser Mouse + +usb:v046DpC042* + ID_MODEL_FROM_DATABASE=G3 Laser Mouse + +usb:v046DpC043* + ID_MODEL_FROM_DATABASE=MX320/MX400 Laser Mouse + +usb:v046DpC044* + ID_MODEL_FROM_DATABASE=LX3 Optical Mouse + +usb:v046DpC045* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v046DpC046* + ID_MODEL_FROM_DATABASE=RX1000 Laser Mouse + +usb:v046DpC047* + ID_MODEL_FROM_DATABASE=Laser Mouse M-UAL120 + +usb:v046DpC048* + ID_MODEL_FROM_DATABASE=G9 Laser Mouse + +usb:v046DpC049* + ID_MODEL_FROM_DATABASE=G5 Laser Mouse + +usb:v046DpC050* + ID_MODEL_FROM_DATABASE=RX 250 Optical Mouse + +usb:v046DpC051* + ID_MODEL_FROM_DATABASE=G3 (MX518) Optical Mouse + +usb:v046DpC053* + ID_MODEL_FROM_DATABASE=Laser Mouse + +usb:v046DpC054* + ID_MODEL_FROM_DATABASE=Bluetooth mini-receiver + +usb:v046DpC058* + ID_MODEL_FROM_DATABASE=M115 Mouse + +usb:v046DpC05A* + ID_MODEL_FROM_DATABASE=M90/M100 Optical Mouse + +usb:v046DpC05B* + ID_MODEL_FROM_DATABASE=M-U0004 810-001317 [B110 Optical USB Mouse] + +usb:v046DpC05D* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v046DpC05F* + ID_MODEL_FROM_DATABASE=M115 Optical Mouse + +usb:v046DpC061* + ID_MODEL_FROM_DATABASE=RX1500 Laser Mouse + +usb:v046DpC062* + ID_MODEL_FROM_DATABASE=M-UAS144 [LS1 Laser Mouse] + +usb:v046DpC063* + ID_MODEL_FROM_DATABASE=DELL Laser Mouse + +usb:v046DpC066* + ID_MODEL_FROM_DATABASE=G9x Laser Mouse + +usb:v046DpC068* + ID_MODEL_FROM_DATABASE=G500 Laser Mouse + +usb:v046DpC069* + ID_MODEL_FROM_DATABASE=M500 Laser Mouse + +usb:v046DpC06A* + ID_MODEL_FROM_DATABASE=USB Optical Mouse + +usb:v046DpC06B* + ID_MODEL_FROM_DATABASE=G700 Wireless Gaming Mouse + +usb:v046DpC06C* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v046DpC101* + ID_MODEL_FROM_DATABASE=UltraX Media Remote + +usb:v046DpC110* + ID_MODEL_FROM_DATABASE=Harmony 785/885 Remote + +usb:v046DpC111* + ID_MODEL_FROM_DATABASE=Harmony 525 Remote + +usb:v046DpC112* + ID_MODEL_FROM_DATABASE=Harmony 890 Remote + +usb:v046DpC11F* + ID_MODEL_FROM_DATABASE=Harmony 900/1100 Remote + +usb:v046DpC121* + ID_MODEL_FROM_DATABASE=Harmony One Remote + +usb:v046DpC122* + ID_MODEL_FROM_DATABASE=Harmony 650/700 Remote + +usb:v046DpC124* + ID_MODEL_FROM_DATABASE=Harmony 300 Remote + +usb:v046DpC125* + ID_MODEL_FROM_DATABASE=Harmony 200 Remote + +usb:v046DpC126* + ID_MODEL_FROM_DATABASE=Harmony Link + +usb:v046DpC201* + ID_MODEL_FROM_DATABASE=WingMan Extreme Joystick with Throttle + +usb:v046DpC202* + ID_MODEL_FROM_DATABASE=WingMan Formula + +usb:v046DpC207* + ID_MODEL_FROM_DATABASE=WingMan Extreme Digital 3D + +usb:v046DpC208* + ID_MODEL_FROM_DATABASE=WingMan Gamepad Extreme + +usb:v046DpC209* + ID_MODEL_FROM_DATABASE=WingMan Gamepad + +usb:v046DpC20A* + ID_MODEL_FROM_DATABASE=WingMan RumblePad + +usb:v046DpC20B* + ID_MODEL_FROM_DATABASE=WingMan Action Pad + +usb:v046DpC20C* + ID_MODEL_FROM_DATABASE=WingMan Precision + +usb:v046DpC20D* + ID_MODEL_FROM_DATABASE=WingMan Attack 2 + +usb:v046DpC20E* + ID_MODEL_FROM_DATABASE=WingMan Formula GP + +usb:v046DpC211* + ID_MODEL_FROM_DATABASE=iTouch Cordless Reciever + +usb:v046DpC212* + ID_MODEL_FROM_DATABASE=WingMan Extreme Digital 3D + +usb:v046DpC213* + ID_MODEL_FROM_DATABASE=J-UH16 (Freedom 2.4 Cordless Joystick) + +usb:v046DpC214* + ID_MODEL_FROM_DATABASE=ATK3 (Attack III Joystick) + +usb:v046DpC215* + ID_MODEL_FROM_DATABASE=Extreme 3D Pro + +usb:v046DpC216* + ID_MODEL_FROM_DATABASE=Dual Action Gamepad + +usb:v046DpC218* + ID_MODEL_FROM_DATABASE=Logitech RumblePad 2 USB + +usb:v046DpC219* + ID_MODEL_FROM_DATABASE=Cordless RumblePad 2 + +usb:v046DpC21A* + ID_MODEL_FROM_DATABASE=Precision Gamepad + +usb:v046DpC21C* + ID_MODEL_FROM_DATABASE=G13 Advanced Gameboard + +usb:v046DpC21D* + ID_MODEL_FROM_DATABASE=F310 Gamepad [XInput Mode] + +usb:v046DpC21E* + ID_MODEL_FROM_DATABASE=F510 Gamepad [XInput Mode] + +usb:v046DpC21F* + ID_MODEL_FROM_DATABASE=F710 Wireless Gamepad [XInput Mode] + +usb:v046DpC221* + ID_MODEL_FROM_DATABASE=G11/G15 Keyboard / Keyboard + +usb:v046DpC222* + ID_MODEL_FROM_DATABASE=G15 Keyboard / LCD + +usb:v046DpC223* + ID_MODEL_FROM_DATABASE=G11/G15 Keyboard / USB Hub + +usb:v046DpC225* + ID_MODEL_FROM_DATABASE=G11/G15 Keyboard / G keys + +usb:v046DpC226* + ID_MODEL_FROM_DATABASE=G15 Refresh Keyboard + +usb:v046DpC227* + ID_MODEL_FROM_DATABASE=G15 Refresh Keyboard + +usb:v046DpC22A* + ID_MODEL_FROM_DATABASE=Gaming Keyboard G110 + +usb:v046DpC22B* + ID_MODEL_FROM_DATABASE=Gaming Keyboard G110 G-keys + +usb:v046DpC22D* + ID_MODEL_FROM_DATABASE=G510 Gaming Keyboard + +usb:v046DpC22E* + ID_MODEL_FROM_DATABASE=G510 Gaming Keyboard onboard audio + +usb:v046DpC245* + ID_MODEL_FROM_DATABASE=G400 Optical Mouse + +usb:v046DpC246* + ID_MODEL_FROM_DATABASE=Gaming Mouse G300 + +usb:v046DpC281* + ID_MODEL_FROM_DATABASE=WingMan Force + +usb:v046DpC283* + ID_MODEL_FROM_DATABASE=WingMan Force 3D + +usb:v046DpC285* + ID_MODEL_FROM_DATABASE=WingMan Strike Force 3D + +usb:v046DpC286* + ID_MODEL_FROM_DATABASE=Force 3D Pro + +usb:v046DpC287* + ID_MODEL_FROM_DATABASE=Flight System G940 + +usb:v046DpC291* + ID_MODEL_FROM_DATABASE=WingMan Formula Force + +usb:v046DpC293* + ID_MODEL_FROM_DATABASE=WingMan Formula Force GP + +usb:v046DpC294* + ID_MODEL_FROM_DATABASE=Driving Force + +usb:v046DpC295* + ID_MODEL_FROM_DATABASE=Momo Force Steering Wheel + +usb:v046DpC298* + ID_MODEL_FROM_DATABASE=Driving Force Pro + +usb:v046DpC299* + ID_MODEL_FROM_DATABASE=G25 Racing Wheel + +usb:v046DpC29B* + ID_MODEL_FROM_DATABASE=G27 Racing Wheel + +usb:v046DpC29C* + ID_MODEL_FROM_DATABASE=Speed Force Wireless Wheel for Wii + +usb:v046DpC2A0* + ID_MODEL_FROM_DATABASE=Wingman Force Feedback Mouse + +usb:v046DpC2A1* + ID_MODEL_FROM_DATABASE=WingMan Force Feedback Mouse + +usb:v046DpC301* + ID_MODEL_FROM_DATABASE=iTouch Keyboard + +usb:v046DpC302* + ID_MODEL_FROM_DATABASE=iTouch Pro Keyboard + +usb:v046DpC303* + ID_MODEL_FROM_DATABASE=iTouch Keyboard + +usb:v046DpC305* + ID_MODEL_FROM_DATABASE=Internet Keyboard + +usb:v046DpC307* + ID_MODEL_FROM_DATABASE=Internet Keyboard + +usb:v046DpC308* + ID_MODEL_FROM_DATABASE=Internet Navigator Keyboard + +usb:v046DpC309* + ID_MODEL_FROM_DATABASE=Internet Keyboard + +usb:v046DpC30A* + ID_MODEL_FROM_DATABASE=iTouch Composite + +usb:v046DpC30B* + ID_MODEL_FROM_DATABASE=NetPlay Keyboard + +usb:v046DpC30C* + ID_MODEL_FROM_DATABASE=Internet Keys (X) + +usb:v046DpC30D* + ID_MODEL_FROM_DATABASE=Internet Keys + +usb:v046DpC30E* + ID_MODEL_FROM_DATABASE=UltraX Keyboard (Y-BL49) + +usb:v046DpC30F* + ID_MODEL_FROM_DATABASE=Logicool HID-Compliant Keyboard (106 key) + +usb:v046DpC311* + ID_MODEL_FROM_DATABASE=Y-UF49 [Internet Pro Keyboard] + +usb:v046DpC312* + ID_MODEL_FROM_DATABASE=DeLuxe 250 Keyboard + +usb:v046DpC313* + ID_MODEL_FROM_DATABASE=Internet 350 Keyboard + +usb:v046DpC315* + ID_MODEL_FROM_DATABASE=Classic Keyboard 200 + +usb:v046DpC316* + ID_MODEL_FROM_DATABASE=HID-Compliant Keyboard + +usb:v046DpC317* + ID_MODEL_FROM_DATABASE=Wave Corded Keyboard + +usb:v046DpC318* + ID_MODEL_FROM_DATABASE=Illuminated Keyboard + +usb:v046DpC31A* + ID_MODEL_FROM_DATABASE=Comfort Wave 450 + +usb:v046DpC31B* + ID_MODEL_FROM_DATABASE=Compact Keyboard K300 + +usb:v046DpC31C* + ID_MODEL_FROM_DATABASE=Keyboard K120 for Business + +usb:v046DpC31D* + ID_MODEL_FROM_DATABASE=Media Keyboard K200 + +usb:v046DpC401* + ID_MODEL_FROM_DATABASE=TrackMan Marble Wheel + +usb:v046DpC402* + ID_MODEL_FROM_DATABASE=Marble Mouse (2-button) + +usb:v046DpC403* + ID_MODEL_FROM_DATABASE=Turbo TrackMan Marble FX + +usb:v046DpC404* + ID_MODEL_FROM_DATABASE=TrackMan Wheel + +usb:v046DpC408* + ID_MODEL_FROM_DATABASE=Marble Mouse (4-button) + +usb:v046DpC501* + ID_MODEL_FROM_DATABASE=Cordless Mouse Receiver + +usb:v046DpC502* + ID_MODEL_FROM_DATABASE=Cordless Mouse & iTouch Keys + +usb:v046DpC503* + ID_MODEL_FROM_DATABASE=Cordless Mouse+Keyboard Receiver + +usb:v046DpC504* + ID_MODEL_FROM_DATABASE=Cordless Mouse+Keyboard Receiver + +usb:v046DpC505* + ID_MODEL_FROM_DATABASE=Cordless Mouse+Keyboard Receiver + +usb:v046DpC506* + ID_MODEL_FROM_DATABASE=MX700 Cordless Mouse Receiver + +usb:v046DpC508* + ID_MODEL_FROM_DATABASE=Cordless Trackball + +usb:v046DpC509* + ID_MODEL_FROM_DATABASE=Cordless Keyboard & Mouse + +usb:v046DpC50A* + ID_MODEL_FROM_DATABASE=Cordless Mouse + +usb:v046DpC50B* + ID_MODEL_FROM_DATABASE=Cordless Desktop Optical + +usb:v046DpC50C* + ID_MODEL_FROM_DATABASE=Cordless Desktop S510 + +usb:v046DpC50D* + ID_MODEL_FROM_DATABASE=Cordless Mouse + +usb:v046DpC50E* + ID_MODEL_FROM_DATABASE=Cordless Mouse Receiver + +usb:v046DpC510* + ID_MODEL_FROM_DATABASE=Cordless Mouse + +usb:v046DpC512* + ID_MODEL_FROM_DATABASE=LX-700 Cordless Desktop Receiver + +usb:v046DpC513* + ID_MODEL_FROM_DATABASE=MX3000 Cordless Desktop Receiver + +usb:v046DpC514* + ID_MODEL_FROM_DATABASE=Cordless Mouse + +usb:v046DpC515* + ID_MODEL_FROM_DATABASE=Cordless 2.4 GHz Presenter Presentation remote control + +usb:v046DpC517* + ID_MODEL_FROM_DATABASE=LX710 Cordless Desktop Laser + +usb:v046DpC518* + ID_MODEL_FROM_DATABASE=MX610 Laser Cordless Mouse + +usb:v046DpC51A* + ID_MODEL_FROM_DATABASE=MX Revolution/G7 Cordless Mouse + +usb:v046DpC51B* + ID_MODEL_FROM_DATABASE=V220 Cordless Optical Mouse for Notebooks + +usb:v046DpC521* + ID_MODEL_FROM_DATABASE=Cordless Mouse Receiver + +usb:v046DpC525* + ID_MODEL_FROM_DATABASE=MX Revolution Cordless Mouse + +usb:v046DpC526* + ID_MODEL_FROM_DATABASE=Nano Receiver + +usb:v046DpC529* + ID_MODEL_FROM_DATABASE=Logitech Keyboard + Mice + +usb:v046DpC52B* + ID_MODEL_FROM_DATABASE=Unifying Receiver + +usb:v046DpC52E* + ID_MODEL_FROM_DATABASE=MK260 Wireless Combo Receiver + +usb:v046DpC52F* + ID_MODEL_FROM_DATABASE=Unifying Receiver + +usb:v046DpC532* + ID_MODEL_FROM_DATABASE=Unifying Receiver + +usb:v046DpC623* + ID_MODEL_FROM_DATABASE=3Dconnexion Space Traveller 3D Mouse + +usb:v046DpC625* + ID_MODEL_FROM_DATABASE=3Dconnexion Space Pilot 3D Mouse + +usb:v046DpC626* + ID_MODEL_FROM_DATABASE=3Dconnexion Space Navigator 3D Mouse + +usb:v046DpC627* + ID_MODEL_FROM_DATABASE=3Dconnexion Space Explorer 3D Mouse + +usb:v046DpC629* + ID_MODEL_FROM_DATABASE=3Dconnexion SpacePilot Pro 3D Mouse + +usb:v046DpC702* + ID_MODEL_FROM_DATABASE=Cordless Presenter + +usb:v046DpC703* + ID_MODEL_FROM_DATABASE=Elite Keyboard Y-RP20 + Mouse MX900 (Bluetooth) + +usb:v046DpC704* + ID_MODEL_FROM_DATABASE=diNovo Wireless Desktop + +usb:v046DpC705* + ID_MODEL_FROM_DATABASE=MX900 Bluetooth Wireless Hub (C-UJ16A) + +usb:v046DpC707* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC708* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC709* + ID_MODEL_FROM_DATABASE=BT Mini-Receiver (HCI mode) + +usb:v046DpC70A* + ID_MODEL_FROM_DATABASE=MX5000 Cordless Desktop + +usb:v046DpC70B* + ID_MODEL_FROM_DATABASE=BT Mini-Receiver (HID proxy mode) + +usb:v046DpC70C* + ID_MODEL_FROM_DATABASE=BT Mini-Receiver (HID proxy mode) + +usb:v046DpC70D* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC70E* + ID_MODEL_FROM_DATABASE=MX1000 Bluetooth Laser Mouse + +usb:v046DpC70F* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC712* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC714* + ID_MODEL_FROM_DATABASE=diNovo Edge Keyboard + +usb:v046DpC715* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC71A* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC71D* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpC71F* + ID_MODEL_FROM_DATABASE=diNovo Mini Wireless Keyboard + +usb:v046DpC720* + ID_MODEL_FROM_DATABASE=Bluetooth wireless hub + +usb:v046DpCA03* + ID_MODEL_FROM_DATABASE=MOMO Racing + +usb:v046DpCA04* + ID_MODEL_FROM_DATABASE=Formula Vibration Feedback Wheel + +usb:v046DpCAB1* + ID_MODEL_FROM_DATABASE=Cordless Keyboard for Wii HID Receiver + +usb:v046DpD001* + ID_MODEL_FROM_DATABASE=QuickCam Pro + +usb:v046E* + ID_VENDOR_FROM_DATABASE=Behavior Tech. Computer Corp. + +usb:v046Ep0100* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v046Ep3001* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v046Ep3002* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v046Ep3003* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v046Ep3005* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v046Ep3008* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v046Ep5250* + ID_MODEL_FROM_DATABASE=KeyMaestro Multimedia Keyboard + +usb:v046Ep5273* + ID_MODEL_FROM_DATABASE=KeyMaestro Multimedia Keyboard + +usb:v046Ep52E6* + ID_MODEL_FROM_DATABASE=Cordless Mouse + +usb:v046Ep5308* + ID_MODEL_FROM_DATABASE=KeyMaestro Keyboard + +usb:v046Ep5408* + ID_MODEL_FROM_DATABASE=KeyMaestro Multimedia Keyboard/Hub + +usb:v046Ep5500* + ID_MODEL_FROM_DATABASE=Portable Keyboard 86+9 keys (Model 6100C US) + +usb:v046Ep5720* + ID_MODEL_FROM_DATABASE=Smart Card Reader + +usb:v046Ep6782* + ID_MODEL_FROM_DATABASE=BTC 7932 mouse+keyboard + +usb:v046F* + ID_VENDOR_FROM_DATABASE=Crystal Semiconductor + +usb:v0471* + ID_VENDOR_FROM_DATABASE=Philips (or NXP) + +usb:v0471p0101* + ID_MODEL_FROM_DATABASE=DSS350 Digital Speaker System + +usb:v0471p0104* + ID_MODEL_FROM_DATABASE=DSS330 Digital Speaker System [uda1321] + +usb:v0471p0105* + ID_MODEL_FROM_DATABASE=UDA1321 + +usb:v0471p014F* + ID_MODEL_FROM_DATABASE=GoGear SA9200 + +usb:v0471p0160* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0471p0161* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0471p0163* + ID_MODEL_FROM_DATABASE=GoGear SA1100 + +usb:v0471p0164* + ID_MODEL_FROM_DATABASE=GoGear SA1110/02 + +usb:v0471p0165* + ID_MODEL_FROM_DATABASE=GoGear SA1330 + +usb:v0471p0201* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0471p0222* + ID_MODEL_FROM_DATABASE=Creative Nomad Jukebox + +usb:v0471p0302* + ID_MODEL_FROM_DATABASE=PCA645VC Webcam [pwc] + +usb:v0471p0303* + ID_MODEL_FROM_DATABASE=PCA646VC Webcam [pwc] + +usb:v0471p0304* + ID_MODEL_FROM_DATABASE=Askey VC010 Webcam [pwc] + +usb:v0471p0307* + ID_MODEL_FROM_DATABASE=PCVC675K Webcam [pwc] + +usb:v0471p0308* + ID_MODEL_FROM_DATABASE=PCVC680K Webcam [pwc] + +usb:v0471p030B* + ID_MODEL_FROM_DATABASE=PC VGA Camera (Vesta Fun) + +usb:v0471p030C* + ID_MODEL_FROM_DATABASE=PCVC690K Webcam [pwc] + +usb:v0471p0310* + ID_MODEL_FROM_DATABASE=PCVC730K Webcam [pwc] + +usb:v0471p0311* + ID_MODEL_FROM_DATABASE=PCVC740K ToUcam Pro [pwc] + +usb:v0471p0312* + ID_MODEL_FROM_DATABASE=PCVC750K Webcam [pwc] + +usb:v0471p0314* + ID_MODEL_FROM_DATABASE=DMVC 1000K + +usb:v0471p0316* + ID_MODEL_FROM_DATABASE=DMVC 2000K Video Capture + +usb:v0471p0321* + ID_MODEL_FROM_DATABASE=FunCam + +usb:v0471p0322* + ID_MODEL_FROM_DATABASE=DMVC1300K PC Camera + +usb:v0471p0325* + ID_MODEL_FROM_DATABASE=SPC 200NC PC Camera + +usb:v0471p0326* + ID_MODEL_FROM_DATABASE=SPC 300NC PC Camera + +usb:v0471p0327* + ID_MODEL_FROM_DATABASE=Webcam SPC 6000 NC (Webcam w/ mic) + +usb:v0471p0328* + ID_MODEL_FROM_DATABASE=SPC 700NC PC Camera + +usb:v0471p0329* + ID_MODEL_FROM_DATABASE=SPC 900NC PC Camera / ORITE CCD Webcam(PC370R) + +usb:v0471p032D* + ID_MODEL_FROM_DATABASE=SPC 210NC PC Camera + +usb:v0471p032E* + ID_MODEL_FROM_DATABASE=SPC 315NC PC Camera + +usb:v0471p0330* + ID_MODEL_FROM_DATABASE=SPC 710NC PC Camera + +usb:v0471p0331* + ID_MODEL_FROM_DATABASE=SPC 1300NC PC Camera + +usb:v0471p0332* + ID_MODEL_FROM_DATABASE=SPC 1000NC PC Camera + +usb:v0471p0333* + ID_MODEL_FROM_DATABASE=SPC 620NC PC Camera + +usb:v0471p0334* + ID_MODEL_FROM_DATABASE=SPC 520/525NC PC Camera + +usb:v0471p0401* + ID_MODEL_FROM_DATABASE=Semiconductors CICT Keyboard + +usb:v0471p0402* + ID_MODEL_FROM_DATABASE=PS/2 Mouse on Semiconductors CICT Keyboard + +usb:v0471p0406* + ID_MODEL_FROM_DATABASE=15 inch Detachable Monitor + +usb:v0471p0407* + ID_MODEL_FROM_DATABASE=10 inch Mobile Monitor + +usb:v0471p0408* + ID_MODEL_FROM_DATABASE=SG3WA1/74 802.11b WLAN Adapter [Atmel AT76C503A] + +usb:v0471p0471* + ID_MODEL_FROM_DATABASE=Digital Speaker System + +usb:v0471p0601* + ID_MODEL_FROM_DATABASE=OVU1020 IR Dongle (Kbd+Mouse) + +usb:v0471p0602* + ID_MODEL_FROM_DATABASE=ATI Remote Wonder II Input Device + +usb:v0471p0603* + ID_MODEL_FROM_DATABASE=ATI Remote Wonder II Controller + +usb:v0471p0608* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0471p060A* + ID_MODEL_FROM_DATABASE=TSU9600 Remote Control + +usb:v0471p060C* + ID_MODEL_FROM_DATABASE=Consumer Infrared Transceiver (HP) + +usb:v0471p060D* + ID_MODEL_FROM_DATABASE=Consumer Infrared Transceiver (SRM5100) + +usb:v0471p060E* + ID_MODEL_FROM_DATABASE=RF Dongle + +usb:v0471p060F* + ID_MODEL_FROM_DATABASE=Consumer Infrared Transceiver + +usb:v0471p0613* + ID_MODEL_FROM_DATABASE=Infrared Transceiver + +usb:v0471p0617* + ID_MODEL_FROM_DATABASE=IEEE802.15.4 RF Dongle + +usb:v0471p0619* + ID_MODEL_FROM_DATABASE=TSU9400 Remote Control + +usb:v0471p0666* + ID_MODEL_FROM_DATABASE=Hantek DDS-3005 Arbitrary Waveform Generator + +usb:v0471p0700* + ID_MODEL_FROM_DATABASE=Semiconductors CICT Hub + +usb:v0471p0701* + ID_MODEL_FROM_DATABASE=150P1 TFT Display + +usb:v0471p0809* + ID_MODEL_FROM_DATABASE=AVNET Bluetooth Device + +usb:v0471p0811* + ID_MODEL_FROM_DATABASE=JR24 CDRW + +usb:v0471p0814* + ID_MODEL_FROM_DATABASE=DCCX38/P data cable + +usb:v0471p0815* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0471p0844* + ID_MODEL_FROM_DATABASE=SA2111/02 1GB Flash Audio Player + +usb:v0471p084A* + ID_MODEL_FROM_DATABASE=GoGear SA3125 + +usb:v0471p084E* + ID_MODEL_FROM_DATABASE=GoGear SA60xx (mtp) + +usb:v0471p0888* + ID_MODEL_FROM_DATABASE=Hantek DDS-3005 Arbitrary Waveform Generator + +usb:v0471p1103* + ID_MODEL_FROM_DATABASE=Digital Speaker System + +usb:v0471p1120* + ID_MODEL_FROM_DATABASE=Creative Rhomba MP3 player + +usb:v0471p1125* + ID_MODEL_FROM_DATABASE=Nike psa[128max Player + +usb:v0471p1137* + ID_MODEL_FROM_DATABASE=HDD065 MP3 player + +usb:v0471p1201* + ID_MODEL_FROM_DATABASE=Arima Bluetooth Device + +usb:v0471p1230* + ID_MODEL_FROM_DATABASE=Wireless Adapter 11g + +usb:v0471p1232* + ID_MODEL_FROM_DATABASE=SNU6500 Wireless Adapter + +usb:v0471p1233* + ID_MODEL_FROM_DATABASE=Wireless Adapter Bootloader Download + +usb:v0471p1236* + ID_MODEL_FROM_DATABASE=SNU5600 802.11bg + +usb:v0471p1237* + ID_MODEL_FROM_DATABASE=TalkTalk SNU5630NS/05 802.11bg + +usb:v0471p1552* + ID_MODEL_FROM_DATABASE=ISP 1581 Hi-Speed USB MPEG2 Encoder Reference Kit + +usb:v0471p1801* + ID_MODEL_FROM_DATABASE=Diva MP3 player + +usb:v0471p200A* + ID_MODEL_FROM_DATABASE=Wireless Network Adapter + +usb:v0471p200F* + ID_MODEL_FROM_DATABASE=802.11n Wireless Adapter + +usb:v0471p2021* + ID_MODEL_FROM_DATABASE=SDE3273FC/97 2.5" SATA HDD Enclosure [INIC-1608L] + +usb:v0471p2022* + ID_MODEL_FROM_DATABASE=GoGear SA52XX + +usb:v0471p2034* + ID_MODEL_FROM_DATABASE=Webcam SPC530NC + +usb:v0471p2036* + ID_MODEL_FROM_DATABASE=Webcam SPC1030NC + +usb:v0471p203F* + ID_MODEL_FROM_DATABASE=TSU9200 Remote Control + +usb:v0471p2046* + ID_MODEL_FROM_DATABASE=TSU9800 Remote Control + +usb:v0471p204E* + ID_MODEL_FROM_DATABASE=GoGear RaGa (SA1942/02) + +usb:v0471p205E* + ID_MODEL_FROM_DATABASE=TSU9300 Remote Control + +usb:v0471p206C* + ID_MODEL_FROM_DATABASE=MCE IR Receiver - Spinel plusf0r ASUS + +usb:v0471p2070* + ID_MODEL_FROM_DATABASE=GoGear Mix + +usb:v0471p2076* + ID_MODEL_FROM_DATABASE=GoGear Aria + +usb:v0471p2079* + ID_MODEL_FROM_DATABASE=GoGear Opus + +usb:v0471p2088* + ID_MODEL_FROM_DATABASE=MCE IR Receiver with ALS- Spinel plus for ASUS + +usb:v0471p209E* + ID_MODEL_FROM_DATABASE=PTA01 Wireless Adapter + +usb:v0471p20B6* + ID_MODEL_FROM_DATABASE=GoGear Vibe + +usb:v0471p20D0* + ID_MODEL_FROM_DATABASE=SPZ2000 Webcam [PixArt PAC7332] + +usb:v0471p20E3* + ID_MODEL_FROM_DATABASE=GoGear Raga + +usb:v0471p20E4* + ID_MODEL_FROM_DATABASE=GoGear ViBE 8GB + +usb:v0471p262C* + ID_MODEL_FROM_DATABASE=SPC230NC Webcam + +usb:v0471p485D* + ID_MODEL_FROM_DATABASE=Senselock SenseIV v2.x + +usb:v0471pDF55* + ID_MODEL_FROM_DATABASE=LPCXpresso LPC-Link + +usb:v0472* + ID_VENDOR_FROM_DATABASE=Chicony Electronics Co., Ltd + +usb:v0472p0065* + ID_MODEL_FROM_DATABASE=PFU-65 Keyboard [Chicony] + +usb:v0472pB086* + ID_MODEL_FROM_DATABASE=Asus USB2.0 Webcam + +usb:v0472pB091* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v0473* + ID_VENDOR_FROM_DATABASE=Sanyo Information Business Co., Ltd + +usb:v0474* + ID_VENDOR_FROM_DATABASE=Sanyo Electric Co., Ltd + +usb:v0474p0110* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder R200 + +usb:v0474p0217* + ID_MODEL_FROM_DATABASE=Xacti J2 + +usb:v0474p022F* + ID_MODEL_FROM_DATABASE=C5 Digital Media Camera (mass storage mode) + +usb:v0474p0230* + ID_MODEL_FROM_DATABASE=C5 Digital Media Camera (PictBridge mode) + +usb:v0474p0231* + ID_MODEL_FROM_DATABASE=C5 Digital Media Camera (PC control mode) + +usb:v0474p0401* + ID_MODEL_FROM_DATABASE=Optical Drive + +usb:v0474p0701* + ID_MODEL_FROM_DATABASE=SCP-4900 Cellphone + +usb:v0474p071F* + ID_MODEL_FROM_DATABASE=Usb Com Port Enumerator + +usb:v0474p0722* + ID_MODEL_FROM_DATABASE=W33SA Camera + +usb:v0475* + ID_VENDOR_FROM_DATABASE=Relisys/Teco Information System + +usb:v0475p0100* + ID_MODEL_FROM_DATABASE=NEC Petiscan + +usb:v0475p0103* + ID_MODEL_FROM_DATABASE=Eclipse 1200U/Episode + +usb:v0475p0210* + ID_MODEL_FROM_DATABASE=Scorpio Ultra 3 + +usb:v0476* + ID_VENDOR_FROM_DATABASE=AESP + +usb:v0477* + ID_VENDOR_FROM_DATABASE=Seagate Technology, Inc. + +usb:v0478* + ID_VENDOR_FROM_DATABASE=Connectix Corp. + +usb:v0478p0001* + ID_MODEL_FROM_DATABASE=QuickCam + +usb:v0478p0002* + ID_MODEL_FROM_DATABASE=QuickClip + +usb:v0478p0003* + ID_MODEL_FROM_DATABASE=QuickCam Pro + +usb:v0479* + ID_VENDOR_FROM_DATABASE=Advanced Peripheral Laboratories + +usb:v047A* + ID_VENDOR_FROM_DATABASE=Semtech Corp. + +usb:v047Ap0004* + ID_MODEL_FROM_DATABASE=ScreenCoder UR7HCTS2-USB + +usb:v047B* + ID_VENDOR_FROM_DATABASE=Silitek Corp. + +usb:v047Bp0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v047Bp0002* + ID_MODEL_FROM_DATABASE=Keyboard and Mouse + +usb:v047Bp0011* + ID_MODEL_FROM_DATABASE=SK-1688U Keyboard + +usb:v047Bp00F9* + ID_MODEL_FROM_DATABASE=SK-1789u Keyboard + +usb:v047Bp0101* + ID_MODEL_FROM_DATABASE=BlueTooth Keyboard and Mouse + +usb:v047Bp020B* + ID_MODEL_FROM_DATABASE=SK-3105 SmartCard Reader + +usb:v047Bp050E* + ID_MODEL_FROM_DATABASE=Internet Compact Keyboard + +usb:v047Bp1000* + ID_MODEL_FROM_DATABASE=Trust Office Scan USB 19200 + +usb:v047Bp1002* + ID_MODEL_FROM_DATABASE=HP ScanJet 4300c Parallel Port + +usb:v047C* + ID_VENDOR_FROM_DATABASE=Dell Computer Corp. + +usb:v047D* + ID_VENDOR_FROM_DATABASE=Kensington + +usb:v047Dp1001* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box + +usb:v047Dp1002* + ID_MODEL_FROM_DATABASE=Expert Mouse Pro + +usb:v047Dp1003* + ID_MODEL_FROM_DATABASE=Orbit TrackBall + +usb:v047Dp1004* + ID_MODEL_FROM_DATABASE=MouseWorks + +usb:v047Dp1005* + ID_MODEL_FROM_DATABASE=TurboBall + +usb:v047Dp1006* + ID_MODEL_FROM_DATABASE=TurboRing + +usb:v047Dp1009* + ID_MODEL_FROM_DATABASE=Orbit TrackBall for Mac + +usb:v047Dp1012* + ID_MODEL_FROM_DATABASE=PocketMouse + +usb:v047Dp1013* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box Optical Pro + +usb:v047Dp1014* + ID_MODEL_FROM_DATABASE=Expert Mouse Pro Wireless + +usb:v047Dp1015* + ID_MODEL_FROM_DATABASE=Expert Mouse + +usb:v047Dp1016* + ID_MODEL_FROM_DATABASE=ADB/USB Orbit + +usb:v047Dp1018* + ID_MODEL_FROM_DATABASE=Studio Mouse + +usb:v047Dp101D* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box Optical Pro + +usb:v047Dp101E* + ID_MODEL_FROM_DATABASE=Studio Mouse Wireless + +usb:v047Dp101F* + ID_MODEL_FROM_DATABASE=PocketMouse Pro + +usb:v047Dp1020* + ID_MODEL_FROM_DATABASE=Expert Mouse Trackball + +usb:v047Dp1021* + ID_MODEL_FROM_DATABASE=Expert Mouse Wireless + +usb:v047Dp1022* + ID_MODEL_FROM_DATABASE=Orbit Optical + +usb:v047Dp1023* + ID_MODEL_FROM_DATABASE=Pocket Mouse Pro Wireless + +usb:v047Dp1024* + ID_MODEL_FROM_DATABASE=PocketMouse + +usb:v047Dp1025* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box Optical Elite Wireless + +usb:v047Dp1026* + ID_MODEL_FROM_DATABASE=Pocket Mouse Pro + +usb:v047Dp1027* + ID_MODEL_FROM_DATABASE=StudioMouse + +usb:v047Dp1028* + ID_MODEL_FROM_DATABASE=StudioMouse Wireless + +usb:v047Dp1029* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box Optical Elite + +usb:v047Dp102A* + ID_MODEL_FROM_DATABASE=Mouse*in*a*Box Optical + +usb:v047Dp102B* + ID_MODEL_FROM_DATABASE=PocketMouse + +usb:v047Dp102C* + ID_MODEL_FROM_DATABASE=Iridio + +usb:v047Dp102D* + ID_MODEL_FROM_DATABASE=Pilot Optical + +usb:v047Dp102E* + ID_MODEL_FROM_DATABASE=Pilot Optical Pro + +usb:v047Dp102F* + ID_MODEL_FROM_DATABASE=Pilot Optical Pro Wireless + +usb:v047Dp1042* + ID_MODEL_FROM_DATABASE=Ci25m Notebook Optical Mouse [Diamond Eye Precision] + +usb:v047Dp1043* + ID_MODEL_FROM_DATABASE=Ci65m Wireless Notebook Optical Mouse + +usb:v047Dp104A* + ID_MODEL_FROM_DATABASE=PilotMouse Mini Retractable + +usb:v047Dp105D* + ID_MODEL_FROM_DATABASE=PocketMouse Bluetooth + +usb:v047Dp105E* + ID_MODEL_FROM_DATABASE=Bluetooth EDR Dongle + +usb:v047Dp1061* + ID_MODEL_FROM_DATABASE=PocketMouse Grip + +usb:v047Dp1062* + ID_MODEL_FROM_DATABASE=PocketMouse Max + +usb:v047Dp1063* + ID_MODEL_FROM_DATABASE=PocketMouse Max Wireless + +usb:v047Dp1064* + ID_MODEL_FROM_DATABASE=PocketMouse 2.0 Wireless + +usb:v047Dp1065* + ID_MODEL_FROM_DATABASE=PocketMouse 2.0 + +usb:v047Dp1066* + ID_MODEL_FROM_DATABASE=PocketMouse Max Glow + +usb:v047Dp1067* + ID_MODEL_FROM_DATABASE=ValueMouse + +usb:v047Dp1068* + ID_MODEL_FROM_DATABASE=ValueOpt White + +usb:v047Dp1069* + ID_MODEL_FROM_DATABASE=ValueOpt Black + +usb:v047Dp106A* + ID_MODEL_FROM_DATABASE=PilotMouse Laser Wireless Mini + +usb:v047Dp106B* + ID_MODEL_FROM_DATABASE=PilotMouse Laser - 3 Button + +usb:v047Dp106C* + ID_MODEL_FROM_DATABASE=PilotMouse Laser - Gaming + +usb:v047Dp106D* + ID_MODEL_FROM_DATABASE=PilotMouse Laser - Wired + +usb:v047Dp106E* + ID_MODEL_FROM_DATABASE=PilotMouse Micro Laser + +usb:v047Dp1070* + ID_MODEL_FROM_DATABASE=ValueOpt Travel + +usb:v047Dp1071* + ID_MODEL_FROM_DATABASE=ValueOpt RF TX + +usb:v047Dp1072* + ID_MODEL_FROM_DATABASE=PocketMouse Colour + +usb:v047Dp1073* + ID_MODEL_FROM_DATABASE=PilotMouse Laser - 6 Button + +usb:v047Dp1074* + ID_MODEL_FROM_DATABASE=PilotMouse Laser Wireless Mini + +usb:v047Dp1075* + ID_MODEL_FROM_DATABASE=SlimBlade Presenter Media Mouse + +usb:v047Dp1076* + ID_MODEL_FROM_DATABASE=SlimBlade Media Mouse + +usb:v047Dp1077* + ID_MODEL_FROM_DATABASE=SlimBlade Presenter Mouse + +usb:v047Dp1152* + ID_MODEL_FROM_DATABASE=Bluetooth EDR Dongle + +usb:v047Dp2002* + ID_MODEL_FROM_DATABASE=Optical Elite Wireless + +usb:v047Dp2010* + ID_MODEL_FROM_DATABASE=Wireless Presentation Remote + +usb:v047Dp2012* + ID_MODEL_FROM_DATABASE=Wireless Presenter with Laser Pointer + +usb:v047Dp2021* + ID_MODEL_FROM_DATABASE=PilotBoard Wireless + +usb:v047Dp2030* + ID_MODEL_FROM_DATABASE=PilotBoard Wireless + +usb:v047Dp2034* + ID_MODEL_FROM_DATABASE=SlimBlade Media Notebook Set + +usb:v047Dp2041* + ID_MODEL_FROM_DATABASE=SlimBlade Trackball + +usb:v047Dp2048* + ID_MODEL_FROM_DATABASE=Orbit Trackball with Scroll Ring + +usb:v047Dp4003* + ID_MODEL_FROM_DATABASE=Gravis Xterminator Digital Gamepad + +usb:v047Dp4005* + ID_MODEL_FROM_DATABASE=Gravis Eliminator GamePad Pro + +usb:v047Dp4006* + ID_MODEL_FROM_DATABASE=Gravis Eliminator AfterShock + +usb:v047Dp4007* + ID_MODEL_FROM_DATABASE=Gravis Xterminator Force + +usb:v047Dp4008* + ID_MODEL_FROM_DATABASE=Gravis Destroyer TiltPad + +usb:v047Dp5001* + ID_MODEL_FROM_DATABASE=Cabo I Camera + +usb:v047Dp5002* + ID_MODEL_FROM_DATABASE=VideoCam CABO II + +usb:v047Dp5003* + ID_MODEL_FROM_DATABASE=VideoCam + +usb:v047E* + ID_VENDOR_FROM_DATABASE=Agere Systems, Inc. (Lucent) + +usb:v047Ep0300* + ID_MODEL_FROM_DATABASE=ORiNOCO Card + +usb:v047Ep1001* + ID_MODEL_FROM_DATABASE=USS720 Parallel Port + +usb:v047Ep2892* + ID_MODEL_FROM_DATABASE=Systems Soft Modem + +usb:v047EpBAD1* + ID_MODEL_FROM_DATABASE=Lucent 56k Modem + +usb:v047EpF101* + ID_MODEL_FROM_DATABASE=Atlas Modem + +usb:v047F* + ID_VENDOR_FROM_DATABASE=Plantronics, Inc. + +usb:v047Fp0101* + ID_MODEL_FROM_DATABASE=Bulk Driver + +usb:v047Fp0301* + ID_MODEL_FROM_DATABASE=Bulk Driver + +usb:v047Fp0411* + ID_MODEL_FROM_DATABASE=Savi Office Base Station + +usb:v047Fp0CA1* + ID_MODEL_FROM_DATABASE=USB DSP v4 Audio Interface + +usb:v047Fp4254* + ID_MODEL_FROM_DATABASE=BUA-100 Bluetooth Adapter + +usb:v047FpAC01* + ID_MODEL_FROM_DATABASE=Savi 7xx + +usb:v047FpAD01* + ID_MODEL_FROM_DATABASE=GameCom 777 5.1 Headset + +usb:v047FpC00E* + ID_MODEL_FROM_DATABASE=Blackwire C310 headset + +usb:v0480* + ID_VENDOR_FROM_DATABASE=Toshiba America Info. Systems, Inc. + +usb:v0480p0001* + ID_MODEL_FROM_DATABASE=InTouch Module + +usb:v0480p0004* + ID_MODEL_FROM_DATABASE=InTouch Module + +usb:v0480p0011* + ID_MODEL_FROM_DATABASE=InTouch Module + +usb:v0480p0014* + ID_MODEL_FROM_DATABASE=InTouch Module + +usb:v0480pA006* + ID_MODEL_FROM_DATABASE=External Disk 1.5TB + +usb:v0480pA007* + ID_MODEL_FROM_DATABASE=External Disk USB 3.0 + +usb:v0480pD010* + ID_MODEL_FROM_DATABASE=External Disk 3TB + +usb:v0481* + ID_VENDOR_FROM_DATABASE=Zenith Data Systems + +usb:v0482* + ID_VENDOR_FROM_DATABASE=Kyocera Corp. + +usb:v0482p000E* + ID_MODEL_FROM_DATABASE=FS-1020D Printer + +usb:v0482p000F* + ID_MODEL_FROM_DATABASE=FS-1920 Mono Printer + +usb:v0482p0100* + ID_MODEL_FROM_DATABASE=Finecam S3x + +usb:v0482p0101* + ID_MODEL_FROM_DATABASE=Finecam S4 + +usb:v0482p0103* + ID_MODEL_FROM_DATABASE=Finecam S5 + +usb:v0482p0105* + ID_MODEL_FROM_DATABASE=Finecam L3 + +usb:v0482p0106* + ID_MODEL_FROM_DATABASE=Finecam + +usb:v0482p0107* + ID_MODEL_FROM_DATABASE=Digital Camera Device + +usb:v0482p0108* + ID_MODEL_FROM_DATABASE=Digital Camera Device + +usb:v0482p0203* + ID_MODEL_FROM_DATABASE=AH-K3001V + +usb:v0482p0204* + ID_MODEL_FROM_DATABASE=iBurst Terminal + +usb:v0483* + ID_VENDOR_FROM_DATABASE=STMicroelectronics + +usb:v0483p0137* + ID_MODEL_FROM_DATABASE=BeWAN ADSL USB ST (blue or green) + +usb:v0483p0138* + ID_MODEL_FROM_DATABASE=Unicorn II (ST70138B + MTC-20174TQ chipset) + +usb:v0483p1307* + ID_MODEL_FROM_DATABASE=Cytronix 6in1 Card Reader + +usb:v0483p163D* + ID_MODEL_FROM_DATABASE=Cool Icam Digi-MP3 + +usb:v0483p2015* + ID_MODEL_FROM_DATABASE=TouchChip® Fingerprint Reader + +usb:v0483p2016* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v0483p2017* + ID_MODEL_FROM_DATABASE=Biometric Smart Card Reader + +usb:v0483p2018* + ID_MODEL_FROM_DATABASE=BioSimKey + +usb:v0483p2302* + ID_MODEL_FROM_DATABASE=Portable Flash Device (PFD) + +usb:v0483p3744* + ID_MODEL_FROM_DATABASE=STLINK Pseudo disk + +usb:v0483p3747* + ID_MODEL_FROM_DATABASE=ST Micro Connect Lite + +usb:v0483p3748* + ID_MODEL_FROM_DATABASE=ST-LINK/V2 + +usb:v0483p4810* + ID_MODEL_FROM_DATABASE=ISDN adapter + +usb:v0483p481D* + ID_MODEL_FROM_DATABASE=BT Digital Access adapter + +usb:v0483p5000* + ID_MODEL_FROM_DATABASE=ST Micro/Ergenic ERG BT-002 Bluetooth Adapter + +usb:v0483p5001* + ID_MODEL_FROM_DATABASE=ST Micro Bluetooth Device + +usb:v0483p5710* + ID_MODEL_FROM_DATABASE=Joystick in FS Mode + +usb:v0483p5720* + ID_MODEL_FROM_DATABASE=STM microSD Flash Device + +usb:v0483p5721* + ID_MODEL_FROM_DATABASE=Hantek DDS-3X25 Arbitrary Waveform Generator + +usb:v0483p5740* + ID_MODEL_FROM_DATABASE=STM32F407 + +usb:v0483p7270* + ID_MODEL_FROM_DATABASE=ST Micro Serial Bridge + +usb:v0483p7554* + ID_MODEL_FROM_DATABASE=56k SoftModem + +usb:v0483pDF11* + ID_MODEL_FROM_DATABASE=STM Device in DFU Mode + +usb:v0483pFF10* + ID_MODEL_FROM_DATABASE=Swann ST56 Modem + +usb:v0484* + ID_VENDOR_FROM_DATABASE=Specialix + +usb:v0485* + ID_VENDOR_FROM_DATABASE=Nokia Monitors + +usb:v0486* + ID_VENDOR_FROM_DATABASE=ASUS Computers, Inc. + +usb:v0486p0185* + ID_MODEL_FROM_DATABASE=EeePC T91MT HID Touch Panel + +usb:v0487* + ID_VENDOR_FROM_DATABASE=Stewart Connector + +usb:v0488* + ID_VENDOR_FROM_DATABASE=Cirque Corp. + +usb:v0489* + ID_VENDOR_FROM_DATABASE=Foxconn / Hon Hai + +usb:v0489p0502* + ID_MODEL_FROM_DATABASE=SmartMedia Card Reader Firmware Loader + +usb:v0489p0503* + ID_MODEL_FROM_DATABASE=SmartMedia Card Reader + +usb:v0489pD00C* + ID_MODEL_FROM_DATABASE=Rollei Compactline (Storage Mode) + +usb:v0489pD00E* + ID_MODEL_FROM_DATABASE=Rollei Compactline (Video Mode) + +usb:v0489pE000* + ID_MODEL_FROM_DATABASE=T-Com TC 300 + +usb:v0489pE003* + ID_MODEL_FROM_DATABASE=Pirelli DP-L10 + +usb:v0489pE00D* + ID_MODEL_FROM_DATABASE=Broadcom Bluetooth 2.1 Device + +usb:v0489pE00F* + ID_MODEL_FROM_DATABASE=Foxconn T77H114 BCM2070 [Single-Chip Bluetooth 2.1 + EDR Adapter] + +usb:v0489pE016* + ID_MODEL_FROM_DATABASE=Ubee PXU1900 WiMAX Adapter [Beceem BCSM250] + +usb:v0489pE02C* + ID_MODEL_FROM_DATABASE=Atheros AR5BBU12 Bluetooth Device + +usb:v048A* + ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc. + +usb:v048C* + ID_VENDOR_FROM_DATABASE=Alps Electric Ireland, Ltd + +usb:v048D* + ID_VENDOR_FROM_DATABASE=Integrated Technology Express, Inc. + +usb:v048Dp1165* + ID_MODEL_FROM_DATABASE=IT1165 Flash Controller + +usb:v048Dp1336* + ID_MODEL_FROM_DATABASE=SD/MMC Cardreader + +usb:v048Dp1345* + ID_MODEL_FROM_DATABASE=Multi Cardreader + +usb:v048Dp9006* + ID_MODEL_FROM_DATABASE=IT9135 BDA Afatech DVB-T HDTV Dongle + +usb:v048Dp9009* + ID_MODEL_FROM_DATABASE=Zolid HD DVD Maker + +usb:v048Dp9135* + ID_MODEL_FROM_DATABASE=Zolid Mini DVB-T Stick + +usb:v048Dp9503* + ID_MODEL_FROM_DATABASE=ITE it9503 feature-limited DVB-T transmission chip [ccHDtv] + +usb:v048Dp9507* + ID_MODEL_FROM_DATABASE=ITE it9507 full featured DVB-T transmission chip [ccHDtv] + +usb:v048F* + ID_VENDOR_FROM_DATABASE=Eicon Tech. + +usb:v0490* + ID_VENDOR_FROM_DATABASE=United Microelectronics Corp. + +usb:v0491* + ID_VENDOR_FROM_DATABASE=Capetronic + +usb:v0491p0003* + ID_MODEL_FROM_DATABASE=Taxan Monitor Control + +usb:v0492* + ID_VENDOR_FROM_DATABASE=Samsung SemiConductor, Inc. + +usb:v0492p0140* + ID_MODEL_FROM_DATABASE=MP3 player + +usb:v0492p0141* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0493* + ID_VENDOR_FROM_DATABASE=MAG Technology Co., Ltd + +usb:v0495* + ID_VENDOR_FROM_DATABASE=ESS Technology, Inc. + +usb:v0496* + ID_VENDOR_FROM_DATABASE=Micron Electronics + +usb:v0497* + ID_VENDOR_FROM_DATABASE=Smile International + +usb:v0497pC001* + ID_MODEL_FROM_DATABASE=Camera Device + +usb:v0498* + ID_VENDOR_FROM_DATABASE=Capetronic (Kaohsiung) Corp. + +usb:v0499* + ID_VENDOR_FROM_DATABASE=Yamaha Corp. + +usb:v0499p1000* + ID_MODEL_FROM_DATABASE=UX256 MIDI I/F + +usb:v0499p1001* + ID_MODEL_FROM_DATABASE=MU1000 + +usb:v0499p1002* + ID_MODEL_FROM_DATABASE=MU2000 + +usb:v0499p1003* + ID_MODEL_FROM_DATABASE=MU500 + +usb:v0499p1004* + ID_MODEL_FROM_DATABASE=UW500 + +usb:v0499p1005* + ID_MODEL_FROM_DATABASE=MOTIF6 + +usb:v0499p1006* + ID_MODEL_FROM_DATABASE=MOTIF7 + +usb:v0499p1007* + ID_MODEL_FROM_DATABASE=MOTIF8 + +usb:v0499p1008* + ID_MODEL_FROM_DATABASE=UX96 MIDI I/F + +usb:v0499p1009* + ID_MODEL_FROM_DATABASE=UX16 MIDI I/F + +usb:v0499p100A* + ID_MODEL_FROM_DATABASE=EOS BX + +usb:v0499p100C* + ID_MODEL_FROM_DATABASE=UC-MX + +usb:v0499p100D* + ID_MODEL_FROM_DATABASE=UC-KX + +usb:v0499p100E* + ID_MODEL_FROM_DATABASE=S08 + +usb:v0499p100F* + ID_MODEL_FROM_DATABASE=CLP-150 + +usb:v0499p1010* + ID_MODEL_FROM_DATABASE=CLP-170 + +usb:v0499p1011* + ID_MODEL_FROM_DATABASE=P-250 + +usb:v0499p1012* + ID_MODEL_FROM_DATABASE=TYROS + +usb:v0499p1013* + ID_MODEL_FROM_DATABASE=PF-500 + +usb:v0499p1014* + ID_MODEL_FROM_DATABASE=S90 + +usb:v0499p1015* + ID_MODEL_FROM_DATABASE=MOTIF-R + +usb:v0499p1016* + ID_MODEL_FROM_DATABASE=MDP-5 + +usb:v0499p1017* + ID_MODEL_FROM_DATABASE=CVP-204 + +usb:v0499p1018* + ID_MODEL_FROM_DATABASE=CVP-206 + +usb:v0499p1019* + ID_MODEL_FROM_DATABASE=CVP-208 + +usb:v0499p101A* + ID_MODEL_FROM_DATABASE=CVP-210 + +usb:v0499p101B* + ID_MODEL_FROM_DATABASE=PSR-1100 + +usb:v0499p101C* + ID_MODEL_FROM_DATABASE=PSR-2100 + +usb:v0499p101D* + ID_MODEL_FROM_DATABASE=CLP-175 + +usb:v0499p101E* + ID_MODEL_FROM_DATABASE=PSR-K1 + +usb:v0499p101F* + ID_MODEL_FROM_DATABASE=EZ-J24 + +usb:v0499p1020* + ID_MODEL_FROM_DATABASE=EZ-250i + +usb:v0499p1021* + ID_MODEL_FROM_DATABASE=MOTIF ES 6 + +usb:v0499p1022* + ID_MODEL_FROM_DATABASE=MOTIF ES 7 + +usb:v0499p1023* + ID_MODEL_FROM_DATABASE=MOTIF ES 8 + +usb:v0499p1024* + ID_MODEL_FROM_DATABASE=CVP-301 + +usb:v0499p1025* + ID_MODEL_FROM_DATABASE=CVP-303 + +usb:v0499p1026* + ID_MODEL_FROM_DATABASE=CVP-305 + +usb:v0499p1027* + ID_MODEL_FROM_DATABASE=CVP-307 + +usb:v0499p1028* + ID_MODEL_FROM_DATABASE=CVP-309 + +usb:v0499p1029* + ID_MODEL_FROM_DATABASE=CVP-309GP + +usb:v0499p102A* + ID_MODEL_FROM_DATABASE=PSR-1500 + +usb:v0499p102B* + ID_MODEL_FROM_DATABASE=PSR-3000 + +usb:v0499p102E* + ID_MODEL_FROM_DATABASE=ELS-01/01C + +usb:v0499p1030* + ID_MODEL_FROM_DATABASE=PSR-295/293 + +usb:v0499p1031* + ID_MODEL_FROM_DATABASE=DGX-205/203 + +usb:v0499p1032* + ID_MODEL_FROM_DATABASE=DGX-305 + +usb:v0499p1033* + ID_MODEL_FROM_DATABASE=DGX-505 + +usb:v0499p1037* + ID_MODEL_FROM_DATABASE=PSR-E403 + +usb:v0499p103C* + ID_MODEL_FROM_DATABASE=MOTIF-RACK ES + +usb:v0499p1054* + ID_MODEL_FROM_DATABASE=S90XS Keyboard/Music Synthesizer + +usb:v0499p2000* + ID_MODEL_FROM_DATABASE=DGP-7 + +usb:v0499p2001* + ID_MODEL_FROM_DATABASE=DGP-5 + +usb:v0499p3001* + ID_MODEL_FROM_DATABASE=YST-MS55D USB Speaker + +usb:v0499p3003* + ID_MODEL_FROM_DATABASE=YST-M45D USB Speaker + +usb:v0499p4000* + ID_MODEL_FROM_DATABASE=NetVolante RTA54i Broadband&ISDN Router + +usb:v0499p4001* + ID_MODEL_FROM_DATABASE=NetVolante RTW65b Broadband Wireless Router + +usb:v0499p4002* + ID_MODEL_FROM_DATABASE=NetVolante RTW65i Broadband&ISDN Wireless Router + +usb:v0499p4004* + ID_MODEL_FROM_DATABASE=NetVolante RTA55i Broadband VoIP Router + +usb:v0499p5000* + ID_MODEL_FROM_DATABASE=CS1D + +usb:v0499p5001* + ID_MODEL_FROM_DATABASE=DSP1D + +usb:v0499p5002* + ID_MODEL_FROM_DATABASE=DME32 + +usb:v0499p5003* + ID_MODEL_FROM_DATABASE=DM2000 + +usb:v0499p5004* + ID_MODEL_FROM_DATABASE=02R96 + +usb:v0499p5005* + ID_MODEL_FROM_DATABASE=ACU16-C + +usb:v0499p5006* + ID_MODEL_FROM_DATABASE=NHB32-C + +usb:v0499p5007* + ID_MODEL_FROM_DATABASE=DM1000 + +usb:v0499p5008* + ID_MODEL_FROM_DATABASE=01V96 + +usb:v0499p5009* + ID_MODEL_FROM_DATABASE=SPX2000 + +usb:v0499p500A* + ID_MODEL_FROM_DATABASE=PM5D + +usb:v0499p500B* + ID_MODEL_FROM_DATABASE=DME64N + +usb:v0499p500C* + ID_MODEL_FROM_DATABASE=DME24N + +usb:v0499p6001* + ID_MODEL_FROM_DATABASE=CRW2200UX Lightspeed 2 External CD-RW Drive + +usb:v0499p7000* + ID_MODEL_FROM_DATABASE=DTX + +usb:v0499p7010* + ID_MODEL_FROM_DATABASE=UB99 + +usb:v049A* + ID_VENDOR_FROM_DATABASE=Gandalf Technologies, Ltd + +usb:v049B* + ID_VENDOR_FROM_DATABASE=Curtis Computer Products + +usb:v049C* + ID_VENDOR_FROM_DATABASE=Acer Advanced Labs, Inc. + +usb:v049Cp0002* + ID_MODEL_FROM_DATABASE=Keyboard (???) + +usb:v049D* + ID_VENDOR_FROM_DATABASE=VLSI Technology + +usb:v049F* + ID_VENDOR_FROM_DATABASE=Compaq Computer Corp. + +usb:v049Fp0002* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v049Fp0003* + ID_MODEL_FROM_DATABASE=iPAQ PocketPC + +usb:v049Fp000E* + ID_MODEL_FROM_DATABASE=Internet Keyboard + +usb:v049Fp0012* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v049Fp0018* + ID_MODEL_FROM_DATABASE=PA-1/PA-2 MP3 Player + +usb:v049Fp0019* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v049Fp001A* + ID_MODEL_FROM_DATABASE=S4 100 Scanner + +usb:v049Fp001E* + ID_MODEL_FROM_DATABASE=IJ650 Inkjet Printer + +usb:v049Fp001F* + ID_MODEL_FROM_DATABASE=WL215 Adapter + +usb:v049Fp0021* + ID_MODEL_FROM_DATABASE=S200 Scanner + +usb:v049Fp0027* + ID_MODEL_FROM_DATABASE=Bluetooth Multiport Module by Compaq + +usb:v049Fp002A* + ID_MODEL_FROM_DATABASE=1400P Inkjet Printer + +usb:v049Fp002B* + ID_MODEL_FROM_DATABASE=A3000 + +usb:v049Fp002C* + ID_MODEL_FROM_DATABASE=Lexmark X125 + +usb:v049Fp0032* + ID_MODEL_FROM_DATABASE=802.11b Adapter [ipaq h5400] + +usb:v049Fp0033* + ID_MODEL_FROM_DATABASE=Wireless LAN MultiPort W100 [Intersil PRISM 2.5] + +usb:v049Fp0036* + ID_MODEL_FROM_DATABASE=Bluetooth Multiport Module + +usb:v049Fp0051* + ID_MODEL_FROM_DATABASE=KU-0133 Easy Access Interner Keyboard + +usb:v049Fp0076* + ID_MODEL_FROM_DATABASE=Wireless LAN MultiPort W200 + +usb:v049Fp0080* + ID_MODEL_FROM_DATABASE=GPRS Multiport + +usb:v049Fp0086* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v049Fp504A* + ID_MODEL_FROM_DATABASE=Personal Jukebox PJB100 + +usb:v049Fp505A* + ID_MODEL_FROM_DATABASE=Linux-USB "CDC Subset" Device, or Itsy (experimental) + +usb:v049Fp8511* + ID_MODEL_FROM_DATABASE=iPAQ Networking 10/100 Ethernet [pegasus2] + +usb:v04A0* + ID_VENDOR_FROM_DATABASE=Digital Equipment Corp. + +usb:v04A1* + ID_VENDOR_FROM_DATABASE=SystemSoft Corp. + +usb:v04A1pFFF0* + ID_MODEL_FROM_DATABASE=Telex Composite Device + +usb:v04A2* + ID_VENDOR_FROM_DATABASE=FirePower Systems + +usb:v04A3* + ID_VENDOR_FROM_DATABASE=Trident Microsystems, Inc. + +usb:v04A4* + ID_VENDOR_FROM_DATABASE=Hitachi, Ltd + +usb:v04A4p0004* + ID_MODEL_FROM_DATABASE=DVD-CAM DZ-MV100A Camcorder + +usb:v04A4p001E* + ID_MODEL_FROM_DATABASE=DVDCAM USB HS Interface + +usb:v04A5* + ID_VENDOR_FROM_DATABASE=Acer Peripherals Inc. (now BenQ Corp.) + +usb:v04A5p0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04A5p0002* + ID_MODEL_FROM_DATABASE=API Ergo K/B + +usb:v04A5p0003* + ID_MODEL_FROM_DATABASE=API Generic K/B Mouse + +usb:v04A5p12A6* + ID_MODEL_FROM_DATABASE=AcerScan C310U + +usb:v04A5p1A20* + ID_MODEL_FROM_DATABASE=Prisa 310U + +usb:v04A5p1A2A* + ID_MODEL_FROM_DATABASE=Prisa 620U + +usb:v04A5p2022* + ID_MODEL_FROM_DATABASE=Prisa 320U/340U + +usb:v04A5p2040* + ID_MODEL_FROM_DATABASE=Prisa 620UT + +usb:v04A5p205E* + ID_MODEL_FROM_DATABASE=ScanPrisa 640BU + +usb:v04A5p2060* + ID_MODEL_FROM_DATABASE=Prisa 620U+/640U + +usb:v04A5p207E* + ID_MODEL_FROM_DATABASE=Prisa 640BU + +usb:v04A5p209E* + ID_MODEL_FROM_DATABASE=ScanPrisa 640BT + +usb:v04A5p20AE* + ID_MODEL_FROM_DATABASE=S2W 3000U + +usb:v04A5p20B0* + ID_MODEL_FROM_DATABASE=S2W 3300U/4300U + +usb:v04A5p20BE* + ID_MODEL_FROM_DATABASE=Prisa 640BT + +usb:v04A5p20C0* + ID_MODEL_FROM_DATABASE=Prisa 1240UT + +usb:v04A5p20DE* + ID_MODEL_FROM_DATABASE=S2W 4300U+ + +usb:v04A5p20F8* + ID_MODEL_FROM_DATABASE=Benq 5000 + +usb:v04A5p20FC* + ID_MODEL_FROM_DATABASE=Benq 5000 + +usb:v04A5p20FE* + ID_MODEL_FROM_DATABASE=SW2 5300U + +usb:v04A5p2137* + ID_MODEL_FROM_DATABASE=Benq 5150/5250 + +usb:v04A5p2202* + ID_MODEL_FROM_DATABASE=Benq 7400UT + +usb:v04A5p2311* + ID_MODEL_FROM_DATABASE=Benq 5560 + +usb:v04A5p3003* + ID_MODEL_FROM_DATABASE=Benq Webcam + +usb:v04A5p3008* + ID_MODEL_FROM_DATABASE=Benq 1500 + +usb:v04A5p300A* + ID_MODEL_FROM_DATABASE=Benq 3410 + +usb:v04A5p300C* + ID_MODEL_FROM_DATABASE=Benq 1016 + +usb:v04A5p3019* + ID_MODEL_FROM_DATABASE=Benq DC C40 + +usb:v04A5p4000* + ID_MODEL_FROM_DATABASE=P30 Composite Device + +usb:v04A5p4013* + ID_MODEL_FROM_DATABASE=BenQ-Siemens EF82/SL91 + +usb:v04A5p4044* + ID_MODEL_FROM_DATABASE=BenQ-Siemens SF71 + +usb:v04A5p4045* + ID_MODEL_FROM_DATABASE=BenQ-Siemens E81 + +usb:v04A5p4048* + ID_MODEL_FROM_DATABASE=BenQ M7 + +usb:v04A5p6001* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6002* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6003* + ID_MODEL_FROM_DATABASE=ATA/ATAPI Adapter + +usb:v04A5p6004* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6005* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6006* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6007* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6008* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6009* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600A* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600B* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600C* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600D* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600E* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p600F* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6010* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6011* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6012* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6013* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6014* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6015* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v04A5p6125* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v04A5p6180* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v04A5p6200* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v04A5p7500* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v04A5p9000* + ID_MODEL_FROM_DATABASE=AWL300 Wireless Adapter + +usb:v04A5p9001* + ID_MODEL_FROM_DATABASE=AWL400 Wireless Adapter + +usb:v04A5p9213* + ID_MODEL_FROM_DATABASE=Kbd Hub + +usb:v04A6* + ID_VENDOR_FROM_DATABASE=Nokia Display Products + +usb:v04A6p00B9* + ID_MODEL_FROM_DATABASE=Audio + +usb:v04A6p0180* + ID_MODEL_FROM_DATABASE=Hub Type P + +usb:v04A6p0181* + ID_MODEL_FROM_DATABASE=HID Monitor Controls + +usb:v04A7* + ID_VENDOR_FROM_DATABASE=Visioneer + +usb:v04A7p0100* + ID_MODEL_FROM_DATABASE=StrobePro + +usb:v04A7p0101* + ID_MODEL_FROM_DATABASE=Strobe Pro Scanner (1.01) + +usb:v04A7p0102* + ID_MODEL_FROM_DATABASE=StrobePro Scanner + +usb:v04A7p0211* + ID_MODEL_FROM_DATABASE=OneTouch 7600 Scanner + +usb:v04A7p0221* + ID_MODEL_FROM_DATABASE=OneTouch 5300 Scanner + +usb:v04A7p0223* + ID_MODEL_FROM_DATABASE=OneTouch 8200 + +usb:v04A7p0224* + ID_MODEL_FROM_DATABASE=OneTouch 4800 USB/Microtek Scanport 3000 + +usb:v04A7p0225* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v04A7p0226* + ID_MODEL_FROM_DATABASE=OneTouch 5300 USB + +usb:v04A7p0229* + ID_MODEL_FROM_DATABASE=OneTouch 7100 + +usb:v04A7p022A* + ID_MODEL_FROM_DATABASE=OneTouch 6600 + +usb:v04A7p022C* + ID_MODEL_FROM_DATABASE=OneTouch 9000/9020 + +usb:v04A7p0231* + ID_MODEL_FROM_DATABASE=6100 Scanner + +usb:v04A7p0311* + ID_MODEL_FROM_DATABASE=6200 EPP/USB Scanner + +usb:v04A7p0321* + ID_MODEL_FROM_DATABASE=OneTouch 8100 EPP/USB Scanner + +usb:v04A7p0331* + ID_MODEL_FROM_DATABASE=OneTouch 8600 EPP/USB Scanner + +usb:v04A7p0341* + ID_MODEL_FROM_DATABASE=6400 + +usb:v04A7p0361* + ID_MODEL_FROM_DATABASE=VistaScan Astra 3600(ENG) + +usb:v04A7p0362* + ID_MODEL_FROM_DATABASE=OneTouch 9320 + +usb:v04A7p0371* + ID_MODEL_FROM_DATABASE=OneTouch 8700/8920 + +usb:v04A7p0380* + ID_MODEL_FROM_DATABASE=OneTouch 7700 + +usb:v04A7p0382* + ID_MODEL_FROM_DATABASE=Photo Port 7700 + +usb:v04A7p0390* + ID_MODEL_FROM_DATABASE=9650 + +usb:v04A7p03A0* + ID_MODEL_FROM_DATABASE=Xerox 4800 One Touch + +usb:v04A7p0410* + ID_MODEL_FROM_DATABASE=OneTouch Pro 8800/8820 + +usb:v04A7p0421* + ID_MODEL_FROM_DATABASE=9450 USB + +usb:v04A7p0423* + ID_MODEL_FROM_DATABASE=9750 Scanner + +usb:v04A7p0424* + ID_MODEL_FROM_DATABASE=Strobe XP 450 + +usb:v04A7p0425* + ID_MODEL_FROM_DATABASE=Strobe XP 100 + +usb:v04A7p0426* + ID_MODEL_FROM_DATABASE=Strobe XP 200 + +usb:v04A7p0427* + ID_MODEL_FROM_DATABASE=Strobe XP 100 + +usb:v04A7p0444* + ID_MODEL_FROM_DATABASE=OneTouch 7300 + +usb:v04A7p0445* + ID_MODEL_FROM_DATABASE=CardReader 100 + +usb:v04A7p0446* + ID_MODEL_FROM_DATABASE=Xerox DocuMate 510 + +usb:v04A7p0447* + ID_MODEL_FROM_DATABASE=XEROX DocuMate 520 + +usb:v04A7p0448* + ID_MODEL_FROM_DATABASE=XEROX DocuMate 250 + +usb:v04A7p0449* + ID_MODEL_FROM_DATABASE=Xerox DocuMate 252 + +usb:v04A7p044A* + ID_MODEL_FROM_DATABASE=Xerox 6400 + +usb:v04A7p044C* + ID_MODEL_FROM_DATABASE=Xerox DocuMate 262 + +usb:v04A7p0474* + ID_MODEL_FROM_DATABASE=Strobe XP 300 + +usb:v04A7p0475* + ID_MODEL_FROM_DATABASE=Xerox DocuMate 272 + +usb:v04A7p0478* + ID_MODEL_FROM_DATABASE=Strobe XP 220 + +usb:v04A7p0479* + ID_MODEL_FROM_DATABASE=Strobe XP 470 + +usb:v04A7p047A* + ID_MODEL_FROM_DATABASE=9450 + +usb:v04A7p047B* + ID_MODEL_FROM_DATABASE=9650 + +usb:v04A7p047D* + ID_MODEL_FROM_DATABASE=9420 + +usb:v04A7p0480* + ID_MODEL_FROM_DATABASE=9520 + +usb:v04A7p048F* + ID_MODEL_FROM_DATABASE=Strobe XP 470 + +usb:v04A7p0491* + ID_MODEL_FROM_DATABASE=Strobe XP 450 + +usb:v04A7p0493* + ID_MODEL_FROM_DATABASE=9750 + +usb:v04A7p0494* + ID_MODEL_FROM_DATABASE=Strobe XP 120 + +usb:v04A7p0497* + ID_MODEL_FROM_DATABASE=Patriot 430 + +usb:v04A7p0498* + ID_MODEL_FROM_DATABASE=Patriot 680 + +usb:v04A7p0499* + ID_MODEL_FROM_DATABASE=Patriot 780 + +usb:v04A7p049B* + ID_MODEL_FROM_DATABASE=Strobe XP 100 + +usb:v04A7p04A0* + ID_MODEL_FROM_DATABASE=7400 + +usb:v04A7p04AC* + ID_MODEL_FROM_DATABASE=Xerox Travel Scanner 100 + +usb:v04A8* + ID_VENDOR_FROM_DATABASE=Multivideo Labs, Inc. + +usb:v04A8p0101* + ID_MODEL_FROM_DATABASE=Hub + +usb:v04A8p0303* + ID_MODEL_FROM_DATABASE=Peripheral Switch + +usb:v04A8p0404* + ID_MODEL_FROM_DATABASE=Peripheral Switch + +usb:v04A9* + ID_VENDOR_FROM_DATABASE=Canon, Inc. + +usb:v04A9p1005* + ID_MODEL_FROM_DATABASE=BJ Printer Hub + +usb:v04A9p1035* + ID_MODEL_FROM_DATABASE=PD Printer Storage + +usb:v04A9p1050* + ID_MODEL_FROM_DATABASE=BJC-8200 + +usb:v04A9p1051* + ID_MODEL_FROM_DATABASE=BJC-3000 Color Printer + +usb:v04A9p1052* + ID_MODEL_FROM_DATABASE=BJC-6100 + +usb:v04A9p1053* + ID_MODEL_FROM_DATABASE=BJC-6200 + +usb:v04A9p1054* + ID_MODEL_FROM_DATABASE=BJC-6500 + +usb:v04A9p1055* + ID_MODEL_FROM_DATABASE=BJC-85 + +usb:v04A9p1056* + ID_MODEL_FROM_DATABASE=BJC-2110 Color Printer + +usb:v04A9p1057* + ID_MODEL_FROM_DATABASE=LR1 + +usb:v04A9p105A* + ID_MODEL_FROM_DATABASE=BJC-55 + +usb:v04A9p105B* + ID_MODEL_FROM_DATABASE=S600 Printer + +usb:v04A9p105C* + ID_MODEL_FROM_DATABASE=S400 + +usb:v04A9p105D* + ID_MODEL_FROM_DATABASE=S450 Printer + +usb:v04A9p105E* + ID_MODEL_FROM_DATABASE=S800 + +usb:v04A9p1062* + ID_MODEL_FROM_DATABASE=S500 Printer + +usb:v04A9p1063* + ID_MODEL_FROM_DATABASE=S4500 + +usb:v04A9p1064* + ID_MODEL_FROM_DATABASE=S300 Printer + +usb:v04A9p1065* + ID_MODEL_FROM_DATABASE=S100 + +usb:v04A9p1066* + ID_MODEL_FROM_DATABASE=S630 + +usb:v04A9p1067* + ID_MODEL_FROM_DATABASE=S900 + +usb:v04A9p1068* + ID_MODEL_FROM_DATABASE=S9000 + +usb:v04A9p1069* + ID_MODEL_FROM_DATABASE=S820 + +usb:v04A9p106A* + ID_MODEL_FROM_DATABASE=S200 Printer + +usb:v04A9p106B* + ID_MODEL_FROM_DATABASE=S520 Printer + +usb:v04A9p106D* + ID_MODEL_FROM_DATABASE=S750 Printer + +usb:v04A9p106E* + ID_MODEL_FROM_DATABASE=S820D + +usb:v04A9p1070* + ID_MODEL_FROM_DATABASE=S530D + +usb:v04A9p1072* + ID_MODEL_FROM_DATABASE=I850 Printer + +usb:v04A9p1073* + ID_MODEL_FROM_DATABASE=I550 Printer + +usb:v04A9p1074* + ID_MODEL_FROM_DATABASE=S330 Printer + +usb:v04A9p1076* + ID_MODEL_FROM_DATABASE=i70 + +usb:v04A9p1077* + ID_MODEL_FROM_DATABASE=i950 + +usb:v04A9p107A* + ID_MODEL_FROM_DATABASE=S830D + +usb:v04A9p107B* + ID_MODEL_FROM_DATABASE=i320 + +usb:v04A9p107C* + ID_MODEL_FROM_DATABASE=i470D + +usb:v04A9p107D* + ID_MODEL_FROM_DATABASE=i9100 + +usb:v04A9p107E* + ID_MODEL_FROM_DATABASE=i450 + +usb:v04A9p107F* + ID_MODEL_FROM_DATABASE=i860 + +usb:v04A9p1082* + ID_MODEL_FROM_DATABASE=i350 + +usb:v04A9p1084* + ID_MODEL_FROM_DATABASE=i250 + +usb:v04A9p1085* + ID_MODEL_FROM_DATABASE=i255 + +usb:v04A9p1086* + ID_MODEL_FROM_DATABASE=i560 + +usb:v04A9p1088* + ID_MODEL_FROM_DATABASE=i965 + +usb:v04A9p108A* + ID_MODEL_FROM_DATABASE=i455 + +usb:v04A9p108B* + ID_MODEL_FROM_DATABASE=i900D + +usb:v04A9p108C* + ID_MODEL_FROM_DATABASE=i475D + +usb:v04A9p108D* + ID_MODEL_FROM_DATABASE=PIXMA iP2000 + +usb:v04A9p108F* + ID_MODEL_FROM_DATABASE=i80 + +usb:v04A9p1090* + ID_MODEL_FROM_DATABASE=i9900 Photo Printer + +usb:v04A9p1091* + ID_MODEL_FROM_DATABASE=PIXMA iP1500 + +usb:v04A9p1093* + ID_MODEL_FROM_DATABASE=PIXMA iP4000 + +usb:v04A9p1094* + ID_MODEL_FROM_DATABASE=PIXMA iP3000x Printer + +usb:v04A9p1095* + ID_MODEL_FROM_DATABASE=PIXMA iP6000D + +usb:v04A9p1097* + ID_MODEL_FROM_DATABASE=PIXMA iP5000 + +usb:v04A9p1098* + ID_MODEL_FROM_DATABASE=PIXMA iP1000 + +usb:v04A9p1099* + ID_MODEL_FROM_DATABASE=PIXMA iP8500 + +usb:v04A9p109C* + ID_MODEL_FROM_DATABASE=PIXMA iP4000R + +usb:v04A9p109D* + ID_MODEL_FROM_DATABASE=iP90 + +usb:v04A9p10A0* + ID_MODEL_FROM_DATABASE=PIXMA iP1600 Printer + +usb:v04A9p10A2* + ID_MODEL_FROM_DATABASE=iP4200 + +usb:v04A9p10A4* + ID_MODEL_FROM_DATABASE=iP5200R + +usb:v04A9p10A5* + ID_MODEL_FROM_DATABASE=iP5200 + +usb:v04A9p10A7* + ID_MODEL_FROM_DATABASE=iP6210D + +usb:v04A9p10A8* + ID_MODEL_FROM_DATABASE=iP6220D + +usb:v04A9p10A9* + ID_MODEL_FROM_DATABASE=iP6600D + +usb:v04A9p10B6* + ID_MODEL_FROM_DATABASE=PIXMA iP4300 Printer + +usb:v04A9p10C2* + ID_MODEL_FROM_DATABASE=PIXMA iP1800 Printer + +usb:v04A9p10C4* + ID_MODEL_FROM_DATABASE=Pixma iP4500 Printer + +usb:v04A9p1404* + ID_MODEL_FROM_DATABASE=W6400PG + +usb:v04A9p1405* + ID_MODEL_FROM_DATABASE=W8400PG + +usb:v04A9p150F* + ID_MODEL_FROM_DATABASE=BIJ2350 PCL + +usb:v04A9p1510* + ID_MODEL_FROM_DATABASE=BIJ1350 PCL + +usb:v04A9p1512* + ID_MODEL_FROM_DATABASE=BIJ1350D PCL + +usb:v04A9p1601* + ID_MODEL_FROM_DATABASE=DR-2080C Scanner + +usb:v04A9p1607* + ID_MODEL_FROM_DATABASE=DR-6080 Scanner + +usb:v04A9p1700* + ID_MODEL_FROM_DATABASE=PIXMA MP110 Scanner + +usb:v04A9p1701* + ID_MODEL_FROM_DATABASE=PIXMA MP130 Scanner + +usb:v04A9p1702* + ID_MODEL_FROM_DATABASE=MP410 Composite + +usb:v04A9p1703* + ID_MODEL_FROM_DATABASE=MP430 Composite + +usb:v04A9p1704* + ID_MODEL_FROM_DATABASE=MP330 Composite + +usb:v04A9p1706* + ID_MODEL_FROM_DATABASE=PIXMA MP750 Scanner + +usb:v04A9p1707* + ID_MODEL_FROM_DATABASE=PIXMA MP780 Scanner + +usb:v04A9p1708* + ID_MODEL_FROM_DATABASE=PIXMA MP760 Scanner + +usb:v04A9p1709* + ID_MODEL_FROM_DATABASE=PIXMA MP150 Scanner + +usb:v04A9p170A* + ID_MODEL_FROM_DATABASE=PIXMA MP170 Scanner + +usb:v04A9p170B* + ID_MODEL_FROM_DATABASE=PIXMA MP450 Scanner + +usb:v04A9p170C* + ID_MODEL_FROM_DATABASE=PIXMA MP500 Scanner + +usb:v04A9p170D* + ID_MODEL_FROM_DATABASE=PIXMA MP800 Scanner + +usb:v04A9p170E* + ID_MODEL_FROM_DATABASE=MP800R + +usb:v04A9p1710* + ID_MODEL_FROM_DATABASE=MP950 + +usb:v04A9p1712* + ID_MODEL_FROM_DATABASE=MP530 + +usb:v04A9p1713* + ID_MODEL_FROM_DATABASE=PIXMA MP830 Scanner + +usb:v04A9p1714* + ID_MODEL_FROM_DATABASE=MP160 + +usb:v04A9p1715* + ID_MODEL_FROM_DATABASE=MP180 Storage + +usb:v04A9p1716* + ID_MODEL_FROM_DATABASE=MP460 Composite + +usb:v04A9p1717* + ID_MODEL_FROM_DATABASE=MP510 + +usb:v04A9p1718* + ID_MODEL_FROM_DATABASE=MP600 Storage + +usb:v04A9p171A* + ID_MODEL_FROM_DATABASE=MP810 Storage + +usb:v04A9p171B* + ID_MODEL_FROM_DATABASE=MP960 + +usb:v04A9p1721* + ID_MODEL_FROM_DATABASE=MP210 ser + +usb:v04A9p1723* + ID_MODEL_FROM_DATABASE=MP470 ser + +usb:v04A9p1724* + ID_MODEL_FROM_DATABASE=PIXMA MP520 series + +usb:v04A9p1725* + ID_MODEL_FROM_DATABASE=MP610 ser + +usb:v04A9p1726* + ID_MODEL_FROM_DATABASE=MP970 ser + +usb:v04A9p1727* + ID_MODEL_FROM_DATABASE=MX300 ser + +usb:v04A9p1728* + ID_MODEL_FROM_DATABASE=MX310 ser + +usb:v04A9p1729* + ID_MODEL_FROM_DATABASE=MX700 ser + +usb:v04A9p172B* + ID_MODEL_FROM_DATABASE=MP140 ser + +usb:v04A9p173B* + ID_MODEL_FROM_DATABASE=PIXMA MP270 All-In-One Printer + +usb:v04A9p173E* + ID_MODEL_FROM_DATABASE=MP560 + +usb:v04A9p173F* + ID_MODEL_FROM_DATABASE=Pixma MP640 Multifunction device + +usb:v04A9p1748* + ID_MODEL_FROM_DATABASE=Pixma MG5150 + +usb:v04A9p174D* + ID_MODEL_FROM_DATABASE=MX360 ser + +usb:v04A9p1900* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 90 + +usb:v04A9p1901* + ID_MODEL_FROM_DATABASE=CanoScan 8800F + +usb:v04A9p1904* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 100 + +usb:v04A9p1905* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 200 + +usb:v04A9p1906* + ID_MODEL_FROM_DATABASE=CanoScan 5600F + +usb:v04A9p1907* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 700F + +usb:v04A9p1909* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 110 + +usb:v04A9p190A* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 210 + +usb:v04A9p2200* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 25 + +usb:v04A9p2201* + ID_MODEL_FROM_DATABASE=CanoScan FB320U + +usb:v04A9p2202* + ID_MODEL_FROM_DATABASE=CanoScan FB620U + +usb:v04A9p2204* + ID_MODEL_FROM_DATABASE=CanoScan FB630U + +usb:v04A9p2205* + ID_MODEL_FROM_DATABASE=CanoScan FB1210U + +usb:v04A9p2206* + ID_MODEL_FROM_DATABASE=CanoScan N650U/N656U + +usb:v04A9p2207* + ID_MODEL_FROM_DATABASE=CanoScan 1220U + +usb:v04A9p2208* + ID_MODEL_FROM_DATABASE=CanoScan D660U + +usb:v04A9p220A* + ID_MODEL_FROM_DATABASE=CanoScan D2400UF + +usb:v04A9p220B* + ID_MODEL_FROM_DATABASE=CanoScan D646U + +usb:v04A9p220C* + ID_MODEL_FROM_DATABASE=CanoScan D1250U2 + +usb:v04A9p220D* + ID_MODEL_FROM_DATABASE=CanoScan N670U/N676U/LiDE 20 + +usb:v04A9p220E* + ID_MODEL_FROM_DATABASE=CanoScan N1240U/LiDE 30 + +usb:v04A9p220F* + ID_MODEL_FROM_DATABASE=CanoScan 8000F + +usb:v04A9p2210* + ID_MODEL_FROM_DATABASE=CanoScan 9900F + +usb:v04A9p2212* + ID_MODEL_FROM_DATABASE=CanoScan 5000F + +usb:v04A9p2213* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 50/LiDE 35/LiDE 40 + +usb:v04A9p2214* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 80 + +usb:v04A9p2215* + ID_MODEL_FROM_DATABASE=CanoScan 3000/3000F/3000ex + +usb:v04A9p2216* + ID_MODEL_FROM_DATABASE=CanoScan 3200F + +usb:v04A9p2217* + ID_MODEL_FROM_DATABASE=CanoScan 5200F + +usb:v04A9p2219* + ID_MODEL_FROM_DATABASE=CanoScan 9950F + +usb:v04A9p221B* + ID_MODEL_FROM_DATABASE=CanoScan 4200F + +usb:v04A9p221C* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 60 + +usb:v04A9p221E* + ID_MODEL_FROM_DATABASE=CanoScan 8400F + +usb:v04A9p221F* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 500F + +usb:v04A9p2220* + ID_MODEL_FROM_DATABASE=CanoScan LIDE 25 + +usb:v04A9p2224* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 600F + +usb:v04A9p2225* + ID_MODEL_FROM_DATABASE=CanoScan LiDE 70 + +usb:v04A9p2228* + ID_MODEL_FROM_DATABASE=CanoScan 4400F + +usb:v04A9p2602* + ID_MODEL_FROM_DATABASE=MultiPASS C555 + +usb:v04A9p2603* + ID_MODEL_FROM_DATABASE=MultiPASS C755 + +usb:v04A9p260A* + ID_MODEL_FROM_DATABASE=CAPT Printer + +usb:v04A9p260E* + ID_MODEL_FROM_DATABASE=LBP-2000 + +usb:v04A9p2610* + ID_MODEL_FROM_DATABASE=MPC600F + +usb:v04A9p2611* + ID_MODEL_FROM_DATABASE=SmartBase MPC400 + +usb:v04A9p2612* + ID_MODEL_FROM_DATABASE=MultiPASS C855 + +usb:v04A9p2617* + ID_MODEL_FROM_DATABASE=CAPT Printer + +usb:v04A9p261A* + ID_MODEL_FROM_DATABASE=iR1600 + +usb:v04A9p261B* + ID_MODEL_FROM_DATABASE=iR1610 + +usb:v04A9p261C* + ID_MODEL_FROM_DATABASE=iC2300 + +usb:v04A9p261F* + ID_MODEL_FROM_DATABASE=MPC200 Printer + +usb:v04A9p2621* + ID_MODEL_FROM_DATABASE=iR2000 + +usb:v04A9p2622* + ID_MODEL_FROM_DATABASE=iR2010 + +usb:v04A9p2623* + ID_MODEL_FROM_DATABASE=FAX-B180C + +usb:v04A9p2629* + ID_MODEL_FROM_DATABASE=FAXPHONE L75 + +usb:v04A9p262B* + ID_MODEL_FROM_DATABASE=LaserShot LBP-1120 Printer + +usb:v04A9p262D* + ID_MODEL_FROM_DATABASE=iR C3200 + +usb:v04A9p262F* + ID_MODEL_FROM_DATABASE=MultiPASS MP730 + +usb:v04A9p2630* + ID_MODEL_FROM_DATABASE=MultiPASS MP700 + +usb:v04A9p2631* + ID_MODEL_FROM_DATABASE=LASER CLASS 700 + +usb:v04A9p2632* + ID_MODEL_FROM_DATABASE=FAX-L2000 + +usb:v04A9p2635* + ID_MODEL_FROM_DATABASE=MPC190 + +usb:v04A9p2637* + ID_MODEL_FROM_DATABASE=iR C6800 + +usb:v04A9p2638* + ID_MODEL_FROM_DATABASE=iR C3100 + +usb:v04A9p263C* + ID_MODEL_FROM_DATABASE=Smartbase MP360 + +usb:v04A9p263D* + ID_MODEL_FROM_DATABASE=MP370 + +usb:v04A9p263E* + ID_MODEL_FROM_DATABASE=MP390 FAX + +usb:v04A9p263F* + ID_MODEL_FROM_DATABASE=MP375 + +usb:v04A9p2646* + ID_MODEL_FROM_DATABASE=MF5530 Scanner Device V1.9.1 + +usb:v04A9p2647* + ID_MODEL_FROM_DATABASE=MF5550 Composite + +usb:v04A9p264D* + ID_MODEL_FROM_DATABASE=PIXMA MP710 + +usb:v04A9p264E* + ID_MODEL_FROM_DATABASE=MF5630 + +usb:v04A9p264F* + ID_MODEL_FROM_DATABASE=MF5650 (FAX) + +usb:v04A9p2650* + ID_MODEL_FROM_DATABASE=iR 6800C EUR + +usb:v04A9p2651* + ID_MODEL_FROM_DATABASE=iR 3100C EUR + +usb:v04A9p2655* + ID_MODEL_FROM_DATABASE=FP-L170/MF350/L380/L398 + +usb:v04A9p2659* + ID_MODEL_FROM_DATABASE=MF8100 + +usb:v04A9p265B* + ID_MODEL_FROM_DATABASE=CAPT Printer + +usb:v04A9p265C* + ID_MODEL_FROM_DATABASE=iR C3220 + +usb:v04A9p265D* + ID_MODEL_FROM_DATABASE=MF5730 + +usb:v04A9p265E* + ID_MODEL_FROM_DATABASE=MF5750 + +usb:v04A9p265F* + ID_MODEL_FROM_DATABASE=MF5770 + +usb:v04A9p2660* + ID_MODEL_FROM_DATABASE=MF3110 + +usb:v04A9p2663* + ID_MODEL_FROM_DATABASE=iR3570/iR4570 + +usb:v04A9p2664* + ID_MODEL_FROM_DATABASE=iR2270/iR2870 + +usb:v04A9p2665* + ID_MODEL_FROM_DATABASE=iR C2620 + +usb:v04A9p2666* + ID_MODEL_FROM_DATABASE=iR C5800 + +usb:v04A9p2667* + ID_MODEL_FROM_DATABASE=iR85PLUS + +usb:v04A9p2669* + ID_MODEL_FROM_DATABASE=iR105PLUS + +usb:v04A9p266A* + ID_MODEL_FROM_DATABASE=CAPT Device + +usb:v04A9p266B* + ID_MODEL_FROM_DATABASE=iR8070 + +usb:v04A9p266C* + ID_MODEL_FROM_DATABASE=iR9070 + +usb:v04A9p266D* + ID_MODEL_FROM_DATABASE=iR 5800C EUR + +usb:v04A9p266E* + ID_MODEL_FROM_DATABASE=CAPT Device + +usb:v04A9p266F* + ID_MODEL_FROM_DATABASE=iR2230 + +usb:v04A9p2670* + ID_MODEL_FROM_DATABASE=iR3530 + +usb:v04A9p2671* + ID_MODEL_FROM_DATABASE=iR5570/iR6570 + +usb:v04A9p2672* + ID_MODEL_FROM_DATABASE=iR C3170 + +usb:v04A9p2673* + ID_MODEL_FROM_DATABASE=iR 3170C EUR + +usb:v04A9p2674* + ID_MODEL_FROM_DATABASE=L120 + +usb:v04A9p2675* + ID_MODEL_FROM_DATABASE=iR2830 + +usb:v04A9p2676* + ID_MODEL_FROM_DATABASE=CAPT Device + +usb:v04A9p2677* + ID_MODEL_FROM_DATABASE=iR C2570 + +usb:v04A9p2678* + ID_MODEL_FROM_DATABASE=iR 2570C EUR + +usb:v04A9p2679* + ID_MODEL_FROM_DATABASE=CAPT Device + +usb:v04A9p267A* + ID_MODEL_FROM_DATABASE=iR2016 + +usb:v04A9p267B* + ID_MODEL_FROM_DATABASE=iR2020 + +usb:v04A9p267D* + ID_MODEL_FROM_DATABASE=MF7100 series + +usb:v04A9p2684* + ID_MODEL_FROM_DATABASE=MF3200 series + +usb:v04A9p2686* + ID_MODEL_FROM_DATABASE=MF6500 series + +usb:v04A9p2687* + ID_MODEL_FROM_DATABASE=iR4530 + +usb:v04A9p2688* + ID_MODEL_FROM_DATABASE=LBP3460 + +usb:v04A9p268C* + ID_MODEL_FROM_DATABASE=iR C6870 + +usb:v04A9p268D* + ID_MODEL_FROM_DATABASE=iR 6870C EUR + +usb:v04A9p268E* + ID_MODEL_FROM_DATABASE=iR C5870 + +usb:v04A9p268F* + ID_MODEL_FROM_DATABASE=iR 5870C EUR + +usb:v04A9p2691* + ID_MODEL_FROM_DATABASE=iR7105 + +usb:v04A9p26A3* + ID_MODEL_FROM_DATABASE=MF4100 series + +usb:v04A9p26B0* + ID_MODEL_FROM_DATABASE=MF4600 series + +usb:v04A9p26B4* + ID_MODEL_FROM_DATABASE=MF4010 series + +usb:v04A9p26B5* + ID_MODEL_FROM_DATABASE=MF4200 series + +usb:v04A9p26DA* + ID_MODEL_FROM_DATABASE=LBP3010B printer + +usb:v04A9p26E6* + ID_MODEL_FROM_DATABASE=iR1024 + +usb:v04A9p2737* + ID_MODEL_FROM_DATABASE=MF4410 + +usb:v04A9p3041* + ID_MODEL_FROM_DATABASE=PowerShot S10 + +usb:v04A9p3042* + ID_MODEL_FROM_DATABASE=CanoScan FS4000US Film Scanner + +usb:v04A9p3043* + ID_MODEL_FROM_DATABASE=PowerShot S20 + +usb:v04A9p3044* + ID_MODEL_FROM_DATABASE=EOS D30 + +usb:v04A9p3045* + ID_MODEL_FROM_DATABASE=PowerShot S100 + +usb:v04A9p3046* + ID_MODEL_FROM_DATABASE=IXY Digital + +usb:v04A9p3047* + ID_MODEL_FROM_DATABASE=Digital IXUS + +usb:v04A9p3048* + ID_MODEL_FROM_DATABASE=PowerShot G1 + +usb:v04A9p3049* + ID_MODEL_FROM_DATABASE=PowerShot Pro90 IS + +usb:v04A9p304A* + ID_MODEL_FROM_DATABASE=CP-10 + +usb:v04A9p304B* + ID_MODEL_FROM_DATABASE=IXY Digital 300 + +usb:v04A9p304C* + ID_MODEL_FROM_DATABASE=PowerShot S300 + +usb:v04A9p304D* + ID_MODEL_FROM_DATABASE=Digital IXUS 300 + +usb:v04A9p304E* + ID_MODEL_FROM_DATABASE=PowerShot A20 + +usb:v04A9p304F* + ID_MODEL_FROM_DATABASE=PowerShot A10 + +usb:v04A9p3050* + ID_MODEL_FROM_DATABASE=PowerShot unknown 1 + +usb:v04A9p3051* + ID_MODEL_FROM_DATABASE=PowerShot S110 + +usb:v04A9p3052* + ID_MODEL_FROM_DATABASE=Digital IXUS V + +usb:v04A9p3055* + ID_MODEL_FROM_DATABASE=PowerShot G2 + +usb:v04A9p3056* + ID_MODEL_FROM_DATABASE=PowerShot S40 + +usb:v04A9p3057* + ID_MODEL_FROM_DATABASE=PowerShot S30 + +usb:v04A9p3058* + ID_MODEL_FROM_DATABASE=PowerShot A40 + +usb:v04A9p3059* + ID_MODEL_FROM_DATABASE=PowerShot A30 + +usb:v04A9p305B* + ID_MODEL_FROM_DATABASE=ZR45MC Digital Camcorder + +usb:v04A9p305C* + ID_MODEL_FROM_DATABASE=PowerShot unknown 2 + +usb:v04A9p3060* + ID_MODEL_FROM_DATABASE=EOS D60 + +usb:v04A9p3061* + ID_MODEL_FROM_DATABASE=PowerShot A100 + +usb:v04A9p3062* + ID_MODEL_FROM_DATABASE=PowerShot A200 + +usb:v04A9p3063* + ID_MODEL_FROM_DATABASE=CP-100 + +usb:v04A9p3065* + ID_MODEL_FROM_DATABASE=PowerShot S200 + +usb:v04A9p3066* + ID_MODEL_FROM_DATABASE=Digital IXUS 330 + +usb:v04A9p3067* + ID_MODEL_FROM_DATABASE=MV550i Digital Video Camera + +usb:v04A9p3069* + ID_MODEL_FROM_DATABASE=PowerShot G3 + +usb:v04A9p306A* + ID_MODEL_FROM_DATABASE=Digital unknown 3 + +usb:v04A9p306B* + ID_MODEL_FROM_DATABASE=MVX2i Digital Video Camera + +usb:v04A9p306C* + ID_MODEL_FROM_DATABASE=PowerShot S45 + +usb:v04A9p306D* + ID_MODEL_FROM_DATABASE=PowerShot S45 PtP Mode + +usb:v04A9p306E* + ID_MODEL_FROM_DATABASE=PowerShot G3 (normal mode) + +usb:v04A9p306F* + ID_MODEL_FROM_DATABASE=PowerShot G3 (ptp) + +usb:v04A9p3070* + ID_MODEL_FROM_DATABASE=PowerShot S230 + +usb:v04A9p3071* + ID_MODEL_FROM_DATABASE=PowerShot S230 (ptp) + +usb:v04A9p3072* + ID_MODEL_FROM_DATABASE=PowerShot SD100 / Digital IXUS II (ptp) + +usb:v04A9p3073* + ID_MODEL_FROM_DATABASE=PowerShot A70 (ptp) + +usb:v04A9p3074* + ID_MODEL_FROM_DATABASE=PowerShot A60 (ptp) + +usb:v04A9p3075* + ID_MODEL_FROM_DATABASE=IXUS 400 Camera + +usb:v04A9p3076* + ID_MODEL_FROM_DATABASE=PowerShot A300 + +usb:v04A9p3077* + ID_MODEL_FROM_DATABASE=PowerShot S50 + +usb:v04A9p3078* + ID_MODEL_FROM_DATABASE=ZR70MC Digital Camcorder + +usb:v04A9p307A* + ID_MODEL_FROM_DATABASE=MV650i (normal mode) + +usb:v04A9p307B* + ID_MODEL_FROM_DATABASE=MV630i Digital Video Camera + +usb:v04A9p307C* + ID_MODEL_FROM_DATABASE=CP-200 + +usb:v04A9p307D* + ID_MODEL_FROM_DATABASE=CP-300 + +usb:v04A9p307F* + ID_MODEL_FROM_DATABASE=Optura 20 + +usb:v04A9p3080* + ID_MODEL_FROM_DATABASE=MVX150i (normal mode) / Optura 20 (normal mode) + +usb:v04A9p3081* + ID_MODEL_FROM_DATABASE=Optura 10 + +usb:v04A9p3082* + ID_MODEL_FROM_DATABASE=MVX100i / Optura 10 + +usb:v04A9p3083* + ID_MODEL_FROM_DATABASE=EOS 10D + +usb:v04A9p3084* + ID_MODEL_FROM_DATABASE=EOS 300D / EOS Digital Rebel + +usb:v04A9p3085* + ID_MODEL_FROM_DATABASE=PowerShot G5 + +usb:v04A9p3087* + ID_MODEL_FROM_DATABASE=Elura 50 (PTP mode) + +usb:v04A9p3088* + ID_MODEL_FROM_DATABASE=Elura 50 (normal mode) + +usb:v04A9p308D* + ID_MODEL_FROM_DATABASE=MVX3i + +usb:v04A9p308E* + ID_MODEL_FROM_DATABASE=FV M1 (normal mode) / MVX 3i (normal mode) / Optura Xi (normal mode) + +usb:v04A9p3093* + ID_MODEL_FROM_DATABASE=Optura 300 + +usb:v04A9p3096* + ID_MODEL_FROM_DATABASE=IXY DV M2 (normal mode) / MVX 10i (normal mode) + +usb:v04A9p3099* + ID_MODEL_FROM_DATABASE=EOS 300D (ptp) + +usb:v04A9p309A* + ID_MODEL_FROM_DATABASE=PowerShot A80 + +usb:v04A9p309B* + ID_MODEL_FROM_DATABASE=Digital IXUS (ptp) + +usb:v04A9p309C* + ID_MODEL_FROM_DATABASE=PowerShot S1 IS + +usb:v04A9p309D* + ID_MODEL_FROM_DATABASE=Powershot Pro 1 + +usb:v04A9p309F* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04A9p30A0* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04A9p30A1* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04A9p30A2* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04A9p30A8* + ID_MODEL_FROM_DATABASE=Elura 60E/Optura 40 (ptp) + +usb:v04A9p30A9* + ID_MODEL_FROM_DATABASE=MVX25i (normal mode) / Optura 40 (normal mode) + +usb:v04A9p30B1* + ID_MODEL_FROM_DATABASE=PowerShot S70 (normal mode) / PowerShot S70 (PTP mode) + +usb:v04A9p30B2* + ID_MODEL_FROM_DATABASE=PowerShot S60 (normal mode) / PowerShot S60 (PTP mode) + +usb:v04A9p30B3* + ID_MODEL_FROM_DATABASE=PowerShot G6 (normal mode) / PowerShot G6 (PTP mode) + +usb:v04A9p30B4* + ID_MODEL_FROM_DATABASE=PowerShot S500 + +usb:v04A9p30B5* + ID_MODEL_FROM_DATABASE=PowerShot A75 + +usb:v04A9p30B6* + ID_MODEL_FROM_DATABASE=Digital IXUS II2 / Digital IXUS II2 (PTP mode) / PowerShot SD110 (PTP mode) / PowerShot SD110 Digital ELPH + +usb:v04A9p30B7* + ID_MODEL_FROM_DATABASE=PowerShot A400 / PowerShot A400 (PTP mode) + +usb:v04A9p30B8* + ID_MODEL_FROM_DATABASE=PowerShot A310 / PowerShot A310 (PTP mode) + +usb:v04A9p30B9* + ID_MODEL_FROM_DATABASE=Powershot A85 + +usb:v04A9p30BA* + ID_MODEL_FROM_DATABASE=PowerShot S410 Digital Elph + +usb:v04A9p30BB* + ID_MODEL_FROM_DATABASE=PowerShot A95 + +usb:v04A9p30BD* + ID_MODEL_FROM_DATABASE=CP-220 + +usb:v04A9p30BE* + ID_MODEL_FROM_DATABASE=CP-330 + +usb:v04A9p30BF* + ID_MODEL_FROM_DATABASE=Digital IXUS 40 + +usb:v04A9p30C0* + ID_MODEL_FROM_DATABASE=Digital IXUS 30 (PTP mode) / PowerShot SD200 (PTP mode) + +usb:v04A9p30C1* + ID_MODEL_FROM_DATABASE=Digital IXUS 50 (normal mode) / IXY Digital 55 (normal mode) / PowerShot A520 (PTP mode) / PowerShot SD400 (normal mode) + +usb:v04A9p30C2* + ID_MODEL_FROM_DATABASE=PowerShot A510 (normal mode) / PowerShot A510 (PTP mode) + +usb:v04A9p30C4* + ID_MODEL_FROM_DATABASE=Digital IXUS i5 (normal mode) / IXY Digital L2 (normal mode) / PowerShot SD20 (normal mode) + +usb:v04A9p30EA* + ID_MODEL_FROM_DATABASE=EOS 1D Mark II (PTP mode) + +usb:v04A9p30EB* + ID_MODEL_FROM_DATABASE=EOS 20D + +usb:v04A9p30EC* + ID_MODEL_FROM_DATABASE=EOS 20D (ptp) + +usb:v04A9p30EE* + ID_MODEL_FROM_DATABASE=EOS 350D + +usb:v04A9p30EF* + ID_MODEL_FROM_DATABASE=EOS 350D (ptp) + +usb:v04A9p30F0* + ID_MODEL_FROM_DATABASE=PowerShot S2 IS (PTP mode) + +usb:v04A9p30F2* + ID_MODEL_FROM_DATABASE=Digital IXUS 700 (normal mode) / Digital IXUS 700 (PTP mode) / IXY Digital 600 (normal mode) / PowerShot SD500 (normal mode) / PowerShot SD500 (PTP mode) + +usb:v04A9p30F4* + ID_MODEL_FROM_DATABASE=PowerShot SD30 / Ixus iZoom / IXY DIGITAL L3 + +usb:v04A9p30F5* + ID_MODEL_FROM_DATABASE=SELPHY CP500 + +usb:v04A9p30F6* + ID_MODEL_FROM_DATABASE=SELPHY CP400 + +usb:v04A9p30F8* + ID_MODEL_FROM_DATABASE=Powershot A430 + +usb:v04A9p30F9* + ID_MODEL_FROM_DATABASE=PowerShot A410 (PTP mode) + +usb:v04A9p30FA* + ID_MODEL_FROM_DATABASE=PowerShot S80 + +usb:v04A9p30FC* + ID_MODEL_FROM_DATABASE=PowerShot A620 (PTP mode) + +usb:v04A9p30FD* + ID_MODEL_FROM_DATABASE=PowerShot A610 (normal mode)/PowerShot A610 (PTP mode) + +usb:v04A9p30FE* + ID_MODEL_FROM_DATABASE=Digital IXUS 65 (PTP mode)/PowerShot SD630 (PTP mode) + +usb:v04A9p30FF* + ID_MODEL_FROM_DATABASE=Digital IXUS 55 (PTP mode)/PowerShot SD450 (PTP mode) + +usb:v04A9p3100* + ID_MODEL_FROM_DATABASE=PowerShot TX1 + +usb:v04A9p310B* + ID_MODEL_FROM_DATABASE=SELPHY CP600 + +usb:v04A9p310E* + ID_MODEL_FROM_DATABASE=Digital IXUS 50 (PTP mode) + +usb:v04A9p310F* + ID_MODEL_FROM_DATABASE=PowerShot A420 + +usb:v04A9p3110* + ID_MODEL_FROM_DATABASE=EOS Digital Rebel XTi + +usb:v04A9p3115* + ID_MODEL_FROM_DATABASE=PowerShot SD900 / Digital IXUS 900 Ti / IXY DIGITAL 1000 + +usb:v04A9p3116* + ID_MODEL_FROM_DATABASE=Digital IXUS 750 / PowerShot SD550 (PTP mode) + +usb:v04A9p3117* + ID_MODEL_FROM_DATABASE=PowerShot A700 + +usb:v04A9p3119* + ID_MODEL_FROM_DATABASE=PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS + +usb:v04A9p311A* + ID_MODEL_FROM_DATABASE=PowerShot S3 IS + +usb:v04A9p311B* + ID_MODEL_FROM_DATABASE=PowerShot A540 + +usb:v04A9p311C* + ID_MODEL_FROM_DATABASE=PowerShot SD600 DIGITAL ELPH / DIGITAL IXUS 60 / IXY DIGITAL 70 + +usb:v04A9p3125* + ID_MODEL_FROM_DATABASE=PowerShot G7 + +usb:v04A9p3126* + ID_MODEL_FROM_DATABASE=PowerShot A530 + +usb:v04A9p3127* + ID_MODEL_FROM_DATABASE=SELPHY CP710 + +usb:v04A9p3128* + ID_MODEL_FROM_DATABASE=SELPHY CP510 + +usb:v04A9p312D* + ID_MODEL_FROM_DATABASE=Elura 100 + +usb:v04A9p3136* + ID_MODEL_FROM_DATABASE=PowerShot SD800 IS / Digital IXUS 850 IS / IXY DIGITAL 900 IS + +usb:v04A9p3137* + ID_MODEL_FROM_DATABASE=PowerShot SD40 / Digital IXUS i7 IXY / DIGITAL L4 + +usb:v04A9p3138* + ID_MODEL_FROM_DATABASE=PowerShot A710 IS + +usb:v04A9p3139* + ID_MODEL_FROM_DATABASE=PowerShot A640 + +usb:v04A9p313A* + ID_MODEL_FROM_DATABASE=PowerShot A630 + +usb:v04A9p3141* + ID_MODEL_FROM_DATABASE=SELPHY ES1 + +usb:v04A9p3142* + ID_MODEL_FROM_DATABASE=SELPHY CP730 + +usb:v04A9p3143* + ID_MODEL_FROM_DATABASE=SELPHY CP720 + +usb:v04A9p3145* + ID_MODEL_FROM_DATABASE=EOS 450D + +usb:v04A9p3146* + ID_MODEL_FROM_DATABASE=EOS 40D + +usb:v04A9p3147* + ID_MODEL_FROM_DATABASE=EOS 1Ds Mark III + +usb:v04A9p3148* + ID_MODEL_FROM_DATABASE=PowerShot S5 IS + +usb:v04A9p3149* + ID_MODEL_FROM_DATABASE=PowerShot A460 + +usb:v04A9p314B* + ID_MODEL_FROM_DATABASE=PowerShot SD850 IS DIGITAL ELPH / Digital IXUS 950 IS / IXY DIGITAL 810 IS + +usb:v04A9p314C* + ID_MODEL_FROM_DATABASE=PowerShot A570 IS + +usb:v04A9p314D* + ID_MODEL_FROM_DATABASE=PowerShot A560 + +usb:v04A9p314E* + ID_MODEL_FROM_DATABASE=PowerShot SD750 DIGITAL ELPH / DIGITAL IXUS 75 / IXY DIGITAL 90 + +usb:v04A9p314F* + ID_MODEL_FROM_DATABASE=PowerShot SD1000 DIGITAL ELPH / DIGITAL IXUS 70 / IXY DIGITAL 10 + +usb:v04A9p3150* + ID_MODEL_FROM_DATABASE=PowerShot A550 + +usb:v04A9p3155* + ID_MODEL_FROM_DATABASE=PowerShot A450 + +usb:v04A9p315A* + ID_MODEL_FROM_DATABASE=PowerShot G9 + +usb:v04A9p315B* + ID_MODEL_FROM_DATABASE=PowerShot A650 IS + +usb:v04A9p315D* + ID_MODEL_FROM_DATABASE=PowerShot A720 + +usb:v04A9p315E* + ID_MODEL_FROM_DATABASE=PowerShot SX100 IS + +usb:v04A9p315F* + ID_MODEL_FROM_DATABASE=PowerShot SD950 IS DIGITAL ELPH / DIGITAL IXUS 960 IS / IXY DIGITAL 2000 IS + +usb:v04A9p3160* + ID_MODEL_FROM_DATABASE=Digital IXUS 860 IS + +usb:v04A9p3170* + ID_MODEL_FROM_DATABASE=SELPHY CP750 + +usb:v04A9p3171* + ID_MODEL_FROM_DATABASE=SELPHY CP740 + +usb:v04A9p3173* + ID_MODEL_FROM_DATABASE=PowerShot SD890 IS DIGITAL ELPH / Digital IXUS 970 IS / IXY DIGITAL 820 IS + +usb:v04A9p3174* + ID_MODEL_FROM_DATABASE=PowerShot SD790 IS DIGITAL ELPH / Digital IXUS 90 IS / IXY DIGITAL 95 IS + +usb:v04A9p3175* + ID_MODEL_FROM_DATABASE=IXY Digital 25 IS + +usb:v04A9p3176* + ID_MODEL_FROM_DATABASE=PowerShot A590 + +usb:v04A9p3177* + ID_MODEL_FROM_DATABASE=PowerShot A580 + +usb:v04A9p317A* + ID_MODEL_FROM_DATABASE=PC1267 [Powershot A470] + +usb:v04A9p3184* + ID_MODEL_FROM_DATABASE=Digital IXUS 80 IS (PTP mode) + +usb:v04A9p3185* + ID_MODEL_FROM_DATABASE=SELPHY ES2 + +usb:v04A9p3186* + ID_MODEL_FROM_DATABASE=SELPHY ES20 + +usb:v04A9p318D* + ID_MODEL_FROM_DATABASE=PowerShot SX100 IS + +usb:v04A9p318E* + ID_MODEL_FROM_DATABASE=PowerShot A1000 IS + +usb:v04A9p318F* + ID_MODEL_FROM_DATABASE=PowerShot G10 + +usb:v04A9p3191* + ID_MODEL_FROM_DATABASE=PowerShot A2000 IS + +usb:v04A9p3192* + ID_MODEL_FROM_DATABASE=PowerShot SX110 IS + +usb:v04A9p3193* + ID_MODEL_FROM_DATABASE=PowerShot SD990 IS DIGITAL ELPH / Digital IXUS 980 IS / IXY DIGITAL 3000 IS + +usb:v04A9p3195* + ID_MODEL_FROM_DATABASE=PowerShot SX1 IS + +usb:v04A9p3196* + ID_MODEL_FROM_DATABASE=PowerShot SD880 IS DIGITAL ELPH / Digital IXUS 870 IS / IXY DIGITAL 920 IS + +usb:v04A9p319A* + ID_MODEL_FROM_DATABASE=EOS 7D + +usb:v04A9p31AA* + ID_MODEL_FROM_DATABASE=SELPHY CP770 + +usb:v04A9p31AB* + ID_MODEL_FROM_DATABASE=SELPHY CP760 + +usb:v04A9p31AD* + ID_MODEL_FROM_DATABASE=PowerShot E1 + +usb:v04A9p31AF* + ID_MODEL_FROM_DATABASE=SELPHY ES3 + +usb:v04A9p31B0* + ID_MODEL_FROM_DATABASE=SELPHY ES30 + +usb:v04A9p31B1* + ID_MODEL_FROM_DATABASE=SELPHY CP530 + +usb:v04A9p31BC* + ID_MODEL_FROM_DATABASE=PowerShot D10 + +usb:v04A9p31BD* + ID_MODEL_FROM_DATABASE=PowerShot SD960 IS DIGITAL ELPH / Digital IXUS 110 IS / IXY DIGITAL 510 IS + +usb:v04A9p31BE* + ID_MODEL_FROM_DATABASE=PowerShot A2100 IS + +usb:v04A9p31BF* + ID_MODEL_FROM_DATABASE=PowerShot A480 + +usb:v04A9p31C0* + ID_MODEL_FROM_DATABASE=PowerShot SX200 IS + +usb:v04A9p31C1* + ID_MODEL_FROM_DATABASE=PowerShot SD970 IS DIGITAL ELPH / Digital IXUS 990 IS / IXY DIGITAL 830 IS + +usb:v04A9p31C2* + ID_MODEL_FROM_DATABASE=PowerShot SD780 IS DIGITAL ELPH / Digital IXUS 100 IS / IXY DIGITAL 210 IS + +usb:v04A9p31C3* + ID_MODEL_FROM_DATABASE=PowerShot A1100 IS + +usb:v04A9p31C4* + ID_MODEL_FROM_DATABASE=PowerShot SD1200 IS DIGITAL ELPH / Digital IXUS 95 IS / IXY DIGITAL 110 IS + +usb:v04A9p31CF* + ID_MODEL_FROM_DATABASE=EOS Rebel T1i / EOS 500D / EOS Kiss X3 + +usb:v04A9p31DD* + ID_MODEL_FROM_DATABASE=SELPHY CP780 + +usb:v04A9p31DF* + ID_MODEL_FROM_DATABASE=PowerShot G11 + +usb:v04A9p31E0* + ID_MODEL_FROM_DATABASE=PowerShot SX120 IS + +usb:v04A9p31E1* + ID_MODEL_FROM_DATABASE=PowerShot S90 + +usb:v04A9p31E4* + ID_MODEL_FROM_DATABASE=PowerShot SX20 IS + +usb:v04A9p31E5* + ID_MODEL_FROM_DATABASE=Digital IXUS 200 IS + +usb:v04A9p31E6* + ID_MODEL_FROM_DATABASE=PowerShot SD940 IS DIGITAL ELPH / Digital IXUS 120 IS / IXY DIGITAL 220 IS + +usb:v04A9p31EA* + ID_MODEL_FROM_DATABASE=EOS Rebel T2i / EOS 550D / EOS Kiss X4 + +usb:v04A9p31EE* + ID_MODEL_FROM_DATABASE=SELPHY ES40 + +usb:v04A9p31EF* + ID_MODEL_FROM_DATABASE=PowerShot A495 + +usb:v04A9p31F0* + ID_MODEL_FROM_DATABASE=PowerShot A490 + +usb:v04A9p31F1* + ID_MODEL_FROM_DATABASE=PowerShot A3100 IS / PowerShot A3150 IS + +usb:v04A9p31F2* + ID_MODEL_FROM_DATABASE=PowerShot A3000 IS + +usb:v04A9p31F3* + ID_MODEL_FROM_DATABASE=PowerShot Digital ELPH SD1400 IS + +usb:v04A9p31F4* + ID_MODEL_FROM_DATABASE=PowerShot SD1300 IS / IXUS 105 + +usb:v04A9p31F5* + ID_MODEL_FROM_DATABASE=Powershot SD3500 IS / IXUS 210 IS + +usb:v04A9p31F6* + ID_MODEL_FROM_DATABASE=PowerShot SX210 IS + +usb:v04A9p31F7* + ID_MODEL_FROM_DATABASE=Powershot SD4000 IS / IXUS 300 HS / IXY 30S + +usb:v04A9p31F8* + ID_MODEL_FROM_DATABASE=Powershot SD4500 IS / IXUS 1000 HS / IXY 50S + +usb:v04A9p31FF* + ID_MODEL_FROM_DATABASE=Digital IXUS 55 + +usb:v04A9p3209* + ID_MODEL_FROM_DATABASE=Vixia HF S21 A + +usb:v04A9p320F* + ID_MODEL_FROM_DATABASE=PowerShot G12 + +usb:v04A9p3210* + ID_MODEL_FROM_DATABASE=Powershot SX30 IS + +usb:v04A9p3211* + ID_MODEL_FROM_DATABASE=PowerShot SX130 IS + +usb:v04A9p3212* + ID_MODEL_FROM_DATABASE=Powershot S95 + +usb:v04A9p3214* + ID_MODEL_FROM_DATABASE=SELPHY CP800 + +usb:v04A9p3218* + ID_MODEL_FROM_DATABASE=EOS 600D / Rebel T3i (ptp) + +usb:v04A9p3223* + ID_MODEL_FROM_DATABASE=PowerShot A3300 IS + +usb:v04A9p3224* + ID_MODEL_FROM_DATABASE=PowerShot A3200 IS + +usb:v04A9p3225* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 500 HS / IXUS 310 HS + +usb:v04A9p3226* + ID_MODEL_FROM_DATABASE=PowerShow A800 + +usb:v04A9p3227* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 100 HS / IXUS 115 HS + +usb:v04A9p3228* + ID_MODEL_FROM_DATABASE=PowerShot SX230 HS + +usb:v04A9p3229* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 300 HS / IXUS 220 HS + +usb:v04A9p322A* + ID_MODEL_FROM_DATABASE=PowerShot A2200 + +usb:v04A9p322B* + ID_MODEL_FROM_DATABASE=Powershot A1200 + +usb:v04A9p322C* + ID_MODEL_FROM_DATABASE=PowerShot SX220 HS + +usb:v04A9p3233* + ID_MODEL_FROM_DATABASE=PowerShot G1 X + +usb:v04A9p3234* + ID_MODEL_FROM_DATABASE=PowerShot SX150 IS + +usb:v04A9p3236* + ID_MODEL_FROM_DATABASE=PowerShot S100 + +usb:v04A9p3237* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 310 HS / IXUS 230 HS + +usb:v04A9p3238* + ID_MODEL_FROM_DATABASE=PowerShot SX40 HS + +usb:v04A9p323B* + ID_MODEL_FROM_DATABASE=EOS Rebel T4i + +usb:v04A9p323E* + ID_MODEL_FROM_DATABASE=PowerShot A1300 + +usb:v04A9p323F* + ID_MODEL_FROM_DATABASE=PowerShot A810 + +usb:v04A9p3240* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 320 HS / IXUS 240 HS + +usb:v04A9p3241* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 110 HS / IXUS 125 HS + +usb:v04A9p3242* + ID_MODEL_FROM_DATABASE=PowerShot D20 + +usb:v04A9p3243* + ID_MODEL_FROM_DATABASE=PowerShot A4000 IS + +usb:v04A9p3244* + ID_MODEL_FROM_DATABASE=PowerShot SX260 HS + +usb:v04A9p3245* + ID_MODEL_FROM_DATABASE=PowerShot SX240 HS + +usb:v04A9p3247* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 520 HS / IXUS 500 HS + +usb:v04A9p3248* + ID_MODEL_FROM_DATABASE=PowerShot A3400 IS + +usb:v04A9p3249* + ID_MODEL_FROM_DATABASE=PowerShot A2400 IS + +usb:v04A9p324A* + ID_MODEL_FROM_DATABASE=PowerShot A2300 + +usb:v04A9p3255* + ID_MODEL_FROM_DATABASE=SELPHY CP900 + +usb:v04A9p3256* + ID_MODEL_FROM_DATABASE=SELPHY CP810 + +usb:v04A9p3258* + ID_MODEL_FROM_DATABASE=PowerShot G15 + +usb:v04A9p3259* + ID_MODEL_FROM_DATABASE=PowerShot SX50 HS + +usb:v04A9p325A* + ID_MODEL_FROM_DATABASE=PowerShot SX160 IS + +usb:v04A9p325B* + ID_MODEL_FROM_DATABASE=PowerShot S110 + +usb:v04A9p325C* + ID_MODEL_FROM_DATABASE=PowerShot SX500 IS + +usb:v04A9p325F* + ID_MODEL_FROM_DATABASE=PowerShot SX280 HS + +usb:v04A9p3260* + ID_MODEL_FROM_DATABASE=PowerShot SX270 HS + +usb:v04A9p3264* + ID_MODEL_FROM_DATABASE=PowerShot A1400 + +usb:v04A9p3265* + ID_MODEL_FROM_DATABASE=Powershot ELPH 130 IS / IXUS 140 + +usb:v04A9p3268* + ID_MODEL_FROM_DATABASE=PowerShot ELPH 330 HS / IXUS 255 HS + +usb:v04A9p3271* + ID_MODEL_FROM_DATABASE=PowerShot A2500 + +usb:v04A9p3276* + ID_MODEL_FROM_DATABASE=PowerShot SX170 IS + +usb:v04A9p327D* + ID_MODEL_FROM_DATABASE=Powershot ELPH 115 IS / IXUS 132 + +usb:v04AA* + ID_VENDOR_FROM_DATABASE=DaeWoo Telecom, Ltd + +usb:v04AB* + ID_VENDOR_FROM_DATABASE=Chromatic Research + +usb:v04AC* + ID_VENDOR_FROM_DATABASE=Micro Audiometrics Corp. + +usb:v04AD* + ID_VENDOR_FROM_DATABASE=Dooin Electronics + +usb:v04ADp2501* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v04AF* + ID_VENDOR_FROM_DATABASE=Winnov L.P. + +usb:v04B0* + ID_VENDOR_FROM_DATABASE=Nikon Corp. + +usb:v04B0p0102* + ID_MODEL_FROM_DATABASE=Coolpix 990 + +usb:v04B0p0103* + ID_MODEL_FROM_DATABASE=Coolpix 880 + +usb:v04B0p0104* + ID_MODEL_FROM_DATABASE=Coolpix 995 + +usb:v04B0p0106* + ID_MODEL_FROM_DATABASE=Coolpix 775 + +usb:v04B0p0107* + ID_MODEL_FROM_DATABASE=Coolpix 5000 + +usb:v04B0p0108* + ID_MODEL_FROM_DATABASE=Coolpix 2500 + +usb:v04B0p0109* + ID_MODEL_FROM_DATABASE=Coolpix 2500 (ptp) + +usb:v04B0p010A* + ID_MODEL_FROM_DATABASE=Coolpix 4500 + +usb:v04B0p010B* + ID_MODEL_FROM_DATABASE=Coolpix 4500 (ptp) + +usb:v04B0p010D* + ID_MODEL_FROM_DATABASE=Coolpix 5700 (ptp) + +usb:v04B0p010E* + ID_MODEL_FROM_DATABASE=Coolpix 4300 (storage) + +usb:v04B0p010F* + ID_MODEL_FROM_DATABASE=Coolpix 4300 (ptp) + +usb:v04B0p0110* + ID_MODEL_FROM_DATABASE=Coolpix 3500 (Sierra Mode) + +usb:v04B0p0111* + ID_MODEL_FROM_DATABASE=Coolpix 3500 (ptp) + +usb:v04B0p0112* + ID_MODEL_FROM_DATABASE=Coolpix 885 (ptp) + +usb:v04B0p0113* + ID_MODEL_FROM_DATABASE=Coolpix 5000 (ptp) + +usb:v04B0p0114* + ID_MODEL_FROM_DATABASE=Coolpix 3100 (storage) + +usb:v04B0p0115* + ID_MODEL_FROM_DATABASE=Coolpix 3100 (ptp) + +usb:v04B0p0117* + ID_MODEL_FROM_DATABASE=Coolpix 2100 (ptp) + +usb:v04B0p0119* + ID_MODEL_FROM_DATABASE=Coolpix 5400 (ptp) + +usb:v04B0p011D* + ID_MODEL_FROM_DATABASE=Coolpix 3700 (ptp) + +usb:v04B0p0121* + ID_MODEL_FROM_DATABASE=Coolpix 3200 (ptp) + +usb:v04B0p0122* + ID_MODEL_FROM_DATABASE=Coolpix 2200 (ptp) + +usb:v04B0p0124* + ID_MODEL_FROM_DATABASE=Coolpix 8400 (mass storage mode) + +usb:v04B0p0125* + ID_MODEL_FROM_DATABASE=Coolpix 8400 (ptp) + +usb:v04B0p0126* + ID_MODEL_FROM_DATABASE=Coolpix 8800 + +usb:v04B0p0129* + ID_MODEL_FROM_DATABASE=Coolpix 4800 (ptp) + +usb:v04B0p012C* + ID_MODEL_FROM_DATABASE=Coolpix 4100 (storage) + +usb:v04B0p012D* + ID_MODEL_FROM_DATABASE=Coolpix 4100 (ptp) + +usb:v04B0p012E* + ID_MODEL_FROM_DATABASE=Coolpix 5600 (ptp) + +usb:v04B0p0130* + ID_MODEL_FROM_DATABASE=Coolpix 4600 (ptp) + +usb:v04B0p0135* + ID_MODEL_FROM_DATABASE=Coolpix 5900 (ptp) + +usb:v04B0p0136* + ID_MODEL_FROM_DATABASE=Coolpix 7900 (storage) + +usb:v04B0p0137* + ID_MODEL_FROM_DATABASE=Coolpix 7900 (ptp) + +usb:v04B0p013A* + ID_MODEL_FROM_DATABASE=Coolpix 100 (storage) + +usb:v04B0p013B* + ID_MODEL_FROM_DATABASE=Coolpix 100 (ptp) + +usb:v04B0p0141* + ID_MODEL_FROM_DATABASE=Coolpix P2 (storage) + +usb:v04B0p0142* + ID_MODEL_FROM_DATABASE=Coolpix P2 (ptp) + +usb:v04B0p0163* + ID_MODEL_FROM_DATABASE=Coolpix P5100 (ptp) + +usb:v04B0p0169* + ID_MODEL_FROM_DATABASE=Coolpix P50 (ptp) + +usb:v04B0p0202* + ID_MODEL_FROM_DATABASE=Coolpix SQ (ptp) + +usb:v04B0p0203* + ID_MODEL_FROM_DATABASE=Coolpix 4200 (mass storage mode) + +usb:v04B0p0204* + ID_MODEL_FROM_DATABASE=Coolpix 4200 (ptp) + +usb:v04B0p0205* + ID_MODEL_FROM_DATABASE=Coolpix 5200 (storage) + +usb:v04B0p0206* + ID_MODEL_FROM_DATABASE=Coolpix 5200 (ptp) + +usb:v04B0p0301* + ID_MODEL_FROM_DATABASE=Coolpix 2000 (storage) + +usb:v04B0p0302* + ID_MODEL_FROM_DATABASE=Coolpix 2000 (ptp) + +usb:v04B0p0317* + ID_MODEL_FROM_DATABASE=Coolpix L20 (ptp) + +usb:v04B0p0402* + ID_MODEL_FROM_DATABASE=DSC D100 (ptp) + +usb:v04B0p0403* + ID_MODEL_FROM_DATABASE=D2H (mass storage mode) + +usb:v04B0p0404* + ID_MODEL_FROM_DATABASE=D2H SLR (ptp) + +usb:v04B0p0405* + ID_MODEL_FROM_DATABASE=D70 (mass storage mode) + +usb:v04B0p0406* + ID_MODEL_FROM_DATABASE=DSC D70 (ptp) + +usb:v04B0p0408* + ID_MODEL_FROM_DATABASE=D2X SLR (ptp) + +usb:v04B0p0409* + ID_MODEL_FROM_DATABASE=D50 digital camera + +usb:v04B0p040A* + ID_MODEL_FROM_DATABASE=D50 (ptp) + +usb:v04B0p040C* + ID_MODEL_FROM_DATABASE=D2Hs + +usb:v04B0p040E* + ID_MODEL_FROM_DATABASE=DSC D70s (ptp) + +usb:v04B0p040F* + ID_MODEL_FROM_DATABASE=D200 (mass storage mode) + +usb:v04B0p0410* + ID_MODEL_FROM_DATABASE=D200 (ptp) + +usb:v04B0p0413* + ID_MODEL_FROM_DATABASE=D40 (mass storage mode) + +usb:v04B0p041E* + ID_MODEL_FROM_DATABASE=D60 digital camera (mass storage mode) + +usb:v04B0p0422* + ID_MODEL_FROM_DATABASE=D700 (ptp) + +usb:v04B0p0423* + ID_MODEL_FROM_DATABASE=D5000 + +usb:v04B0p0424* + ID_MODEL_FROM_DATABASE=D3000 + +usb:v04B0p0425* + ID_MODEL_FROM_DATABASE=D300S + +usb:v04B0p0428* + ID_MODEL_FROM_DATABASE=D7000 + +usb:v04B0p0429* + ID_MODEL_FROM_DATABASE=D5100 + +usb:v04B0p042A* + ID_MODEL_FROM_DATABASE=D800 (ptp) + +usb:v04B0p0F03* + ID_MODEL_FROM_DATABASE=PD-10 Wireless Printer Adapter + +usb:v04B0p4000* + ID_MODEL_FROM_DATABASE=Coolscan LS 40 ED + +usb:v04B0p4001* + ID_MODEL_FROM_DATABASE=LS 50 ED/Coolscan V ED + +usb:v04B0p4002* + ID_MODEL_FROM_DATABASE=Super Coolscan LS-5000 ED + +usb:v04B1* + ID_VENDOR_FROM_DATABASE=Pan International + +usb:v04B3* + ID_VENDOR_FROM_DATABASE=IBM Corp. + +usb:v04B3p3003* + ID_MODEL_FROM_DATABASE=Rapid Access III Keyboard + +usb:v04B3p3004* + ID_MODEL_FROM_DATABASE=Media Access Pro Keyboard + +usb:v04B3p300A* + ID_MODEL_FROM_DATABASE=Rapid Access IIIe Keyboard + +usb:v04B3p3016* + ID_MODEL_FROM_DATABASE=UltraNav Keyboard Hub + +usb:v04B3p3018* + ID_MODEL_FROM_DATABASE=UltraNav Keyboard + +usb:v04B3p301B* + ID_MODEL_FROM_DATABASE=SK-8815 Keyboard + +usb:v04B3p301C* + ID_MODEL_FROM_DATABASE=Enhanced Performance Keyboard + +usb:v04B3p3020* + ID_MODEL_FROM_DATABASE=Enhanced Performance Keyboard + +usb:v04B3p3025* + ID_MODEL_FROM_DATABASE=NetVista Full Width Keyboard + +usb:v04B3p3100* + ID_MODEL_FROM_DATABASE=NetVista Mouse + +usb:v04B3p3103* + ID_MODEL_FROM_DATABASE=ScrollPoint Pro Mouse + +usb:v04B3p3104* + ID_MODEL_FROM_DATABASE=ScrollPoint Wireless Mouse + +usb:v04B3p3105* + ID_MODEL_FROM_DATABASE=ScrollPoint Optical (HID) + +usb:v04B3p3107* + ID_MODEL_FROM_DATABASE=ThinkPad 800dpi Optical Travel Mouse + +usb:v04B3p3108* + ID_MODEL_FROM_DATABASE=800dpi Optical Mouse w/ Scroll Point + +usb:v04B3p3109* + ID_MODEL_FROM_DATABASE=Optical ScrollPoint Pro Mouse + +usb:v04B3p310B* + ID_MODEL_FROM_DATABASE=Red Wheel Mouse + +usb:v04B3p310C* + ID_MODEL_FROM_DATABASE=Wheel Mouse + +usb:v04B3p4427* + ID_MODEL_FROM_DATABASE=Portable CD ROM + +usb:v04B3p4482* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v04B3p4485* + ID_MODEL_FROM_DATABASE=Serial Converter + +usb:v04B3p4525* + ID_MODEL_FROM_DATABASE=Double sided CRT + +usb:v04B3p4535* + ID_MODEL_FROM_DATABASE=4610 Suremark Printer + +usb:v04B3p4550* + ID_MODEL_FROM_DATABASE=NVRAM (128 KB) + +usb:v04B3p4554* + ID_MODEL_FROM_DATABASE=Cash Drawer + +usb:v04B3p4580* + ID_MODEL_FROM_DATABASE=Hub w/ NVRAM + +usb:v04B3p4581* + ID_MODEL_FROM_DATABASE=4800-2xx Hub w/ Cash Drawer + +usb:v04B3p4604* + ID_MODEL_FROM_DATABASE=Keyboard w/ Card Reader + +usb:v04B3p4671* + ID_MODEL_FROM_DATABASE=4820 LCD w/ MSR/KB + +usb:v04B4* + ID_VENDOR_FROM_DATABASE=Cypress Semiconductor Corp. + +usb:v04B4p0001* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v04B4p0002* + ID_MODEL_FROM_DATABASE=CY7C63x0x Thermometer + +usb:v04B4p0033* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v04B4p0060* + ID_MODEL_FROM_DATABASE=Wireless optical mouse + +usb:v04B4p0100* + ID_MODEL_FROM_DATABASE=Cino FuzzyScan F760-B + +usb:v04B4p0101* + ID_MODEL_FROM_DATABASE=Keyboard/Hub + +usb:v04B4p0102* + ID_MODEL_FROM_DATABASE=Keyboard with APM + +usb:v04B4p0130* + ID_MODEL_FROM_DATABASE=MyIRC Remote Receiver + +usb:v04B4p0306* + ID_MODEL_FROM_DATABASE=Telephone Receiver + +usb:v04B4p0407* + ID_MODEL_FROM_DATABASE=Optical Skype Mouse + +usb:v04B4p0BAD* + ID_MODEL_FROM_DATABASE=MetaGeek Wi-Spy + +usb:v04B4p1002* + ID_MODEL_FROM_DATABASE=CY7C63001 R100 FM Radio + +usb:v04B4p1006* + ID_MODEL_FROM_DATABASE=Human Interface Device + +usb:v04B4p2050* + ID_MODEL_FROM_DATABASE=hub + +usb:v04B4p2830* + ID_MODEL_FROM_DATABASE=Opera1 DVB-S (cold state) + +usb:v04B4p4381* + ID_MODEL_FROM_DATABASE=SCAPS USC-1 Scanner Controller + +usb:v04B4p4611* + ID_MODEL_FROM_DATABASE=Storage Adapter FX2 (CY) + +usb:v04B4p4616* + ID_MODEL_FROM_DATABASE=Flash Disk (TPP) + +usb:v04B4p5201* + ID_MODEL_FROM_DATABASE=Combi Keyboard-Hub (Hub) + +usb:v04B4p5202* + ID_MODEL_FROM_DATABASE=Combi Keyboard-Hub (Keyboard) + +usb:v04B4p5500* + ID_MODEL_FROM_DATABASE=HID->COM RS232 Adapter + +usb:v04B4p5A9B* + ID_MODEL_FROM_DATABASE=Dacal CD/DVD Library D-101/DC-300/DC-016RW + +usb:v04B4p6370* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v04B4p6560* + ID_MODEL_FROM_DATABASE=CY7C65640 USB-2.0 "TetraHub" + +usb:v04B4p6830* + ID_MODEL_FROM_DATABASE=CY7C68300A EZ-USB AT2 USB 2.0 to ATA/ATAPI + +usb:v04B4p6831* + ID_MODEL_FROM_DATABASE=Storage Adapter ISD-300LP (CY) + +usb:v04B4p7417* + ID_MODEL_FROM_DATABASE=Wireless PC Lock/Ultra Mouse + +usb:v04B4p8329* + ID_MODEL_FROM_DATABASE=USB To keyboard/Mouse Converter + +usb:v04B4p8613* + ID_MODEL_FROM_DATABASE=CY7C68013 EZ-USB FX2 USB 2.0 Development Kit + +usb:v04B4p8614* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v04B4p861F* + ID_MODEL_FROM_DATABASE=Anysee E30 USB 2.0 DVB-T Receiver + +usb:v04B4pBCA1* + ID_MODEL_FROM_DATABASE=Barcode Reader + +usb:v04B4pCC04* + ID_MODEL_FROM_DATABASE=Centor USB RACIA-ALVAR USB PORT + +usb:v04B4pCC06* + ID_MODEL_FROM_DATABASE=Centor-P RACIA-ALVAR USB PORT + +usb:v04B4pD5D5* + ID_MODEL_FROM_DATABASE=CY7C63x0x Zoltrix Z-Boxer GamePad + +usb:v04B4pDE61* + ID_MODEL_FROM_DATABASE=Barcode Reader + +usb:v04B4pDE64* + ID_MODEL_FROM_DATABASE=Barcode Reader + +usb:v04B4pF000* + ID_MODEL_FROM_DATABASE=CY30700 Licorice evaluation board + +usb:v04B4pF111* + ID_MODEL_FROM_DATABASE=CY8CKIT-002 PSoC MiniProg3 Rev A Program and debug kit + +usb:v04B4pF115* + ID_MODEL_FROM_DATABASE=PSoC FirstTouch Programmer + +usb:v04B4pFD13* + ID_MODEL_FROM_DATABASE=Programmable power socket + +usb:v04B5* + ID_VENDOR_FROM_DATABASE=ROHM LSI Systems USA, LLC + +usb:v04B5p3064* + ID_MODEL_FROM_DATABASE=Hantek DSO-3064 + +usb:v04B6* + ID_VENDOR_FROM_DATABASE=Hint Corp. + +usb:v04B7* + ID_VENDOR_FROM_DATABASE=Compal Electronics, Inc. + +usb:v04B8* + ID_VENDOR_FROM_DATABASE=Seiko Epson Corp. + +usb:v04B8p0001* + ID_MODEL_FROM_DATABASE=Stylus Color 740 / Photo 750 + +usb:v04B8p0002* + ID_MODEL_FROM_DATABASE=ISD Smart Cable for Mac + +usb:v04B8p0003* + ID_MODEL_FROM_DATABASE=ISD Smart Cable + +usb:v04B8p0004* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04B8p0005* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04B8p0006* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04B8p0007* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04B8p0015* + ID_MODEL_FROM_DATABASE=Stylus Photo R3000 + +usb:v04B8p0101* + ID_MODEL_FROM_DATABASE=GT-7000U [Perfection 636] + +usb:v04B8p0102* + ID_MODEL_FROM_DATABASE=GT-2200 + +usb:v04B8p0103* + ID_MODEL_FROM_DATABASE=GT-6600U [Perfection 610] + +usb:v04B8p0104* + ID_MODEL_FROM_DATABASE=GT-7600UF [Perfection 1200U/1200U Photo] + +usb:v04B8p0105* + ID_MODEL_FROM_DATABASE=Stylus Scan 2000 + +usb:v04B8p0106* + ID_MODEL_FROM_DATABASE=Stylus Scan 2500 + +usb:v04B8p0107* + ID_MODEL_FROM_DATABASE=ES-2000 [Expression 1600U] + +usb:v04B8p0108* + ID_MODEL_FROM_DATABASE=CC-700 + +usb:v04B8p0109* + ID_MODEL_FROM_DATABASE=ES-8500 [Expression 1640 XL] + +usb:v04B8p010A* + ID_MODEL_FROM_DATABASE=GT-8700/GT-8700F [Perfection 1640SU/1640SU PHOTO] + +usb:v04B8p010B* + ID_MODEL_FROM_DATABASE=GT-7700U [Perfection 1240U] + +usb:v04B8p010C* + ID_MODEL_FROM_DATABASE=GT-6700U [Perfection 640] + +usb:v04B8p010D* + ID_MODEL_FROM_DATABASE=CC-500L + +usb:v04B8p010E* + ID_MODEL_FROM_DATABASE=ES-2200 [Perfection 1680] + +usb:v04B8p010F* + ID_MODEL_FROM_DATABASE=GT-7200U [Perfection 1250/1250 PHOTO] + +usb:v04B8p0110* + ID_MODEL_FROM_DATABASE=GT-8200U/GT-8200UF [Perfection 1650/1650 PHOTO] + +usb:v04B8p0112* + ID_MODEL_FROM_DATABASE=GT-9700F [Perfection 2450 PHOTO] + +usb:v04B8p0114* + ID_MODEL_FROM_DATABASE=Perfection 660 + +usb:v04B8p0116* + ID_MODEL_FROM_DATABASE=GT-9400UF [Perfection 3170] + +usb:v04B8p0118* + ID_MODEL_FROM_DATABASE=GT-F600 [Perfection 4180] + +usb:v04B8p0119* + ID_MODEL_FROM_DATABASE=GT-X750 [Perfection 4490 Photo] + +usb:v04B8p011A* + ID_MODEL_FROM_DATABASE=CC-550L [1000 ICS] + +usb:v04B8p011B* + ID_MODEL_FROM_DATABASE=GT-9300UF [Perfection 2400 PHOTO] + +usb:v04B8p011C* + ID_MODEL_FROM_DATABASE=GT-9800F [Perfection 3200] + +usb:v04B8p011D* + ID_MODEL_FROM_DATABASE=GT-7300U [Perfection 1260/1260 PHOTO] + +usb:v04B8p011E* + ID_MODEL_FROM_DATABASE=GT-8300UF [Perfection 1660 PHOTO] + +usb:v04B8p011F* + ID_MODEL_FROM_DATABASE=GT-8400UF [Perfection 1670/1670 PHOTO] + +usb:v04B8p0120* + ID_MODEL_FROM_DATABASE=GT-7400U [Perfection 1270] + +usb:v04B8p0121* + ID_MODEL_FROM_DATABASE=GT-F500/GT-F550 [Perfection 2480/2580 PHOTO] + +usb:v04B8p0122* + ID_MODEL_FROM_DATABASE=GT-F520/GT-F570 [Perfection 3590 PHOTO] + +usb:v04B8p0126* + ID_MODEL_FROM_DATABASE=ES-7000H [GT-15000] + +usb:v04B8p0128* + ID_MODEL_FROM_DATABASE=GT-X700 [Perfection 4870] + +usb:v04B8p0129* + ID_MODEL_FROM_DATABASE=ES-10000G [Expression 10000XL] + +usb:v04B8p012A* + ID_MODEL_FROM_DATABASE=GT-X800 [Perfection 4990 PHOTO] + +usb:v04B8p012B* + ID_MODEL_FROM_DATABASE=ES-H300 [GT-2500] + +usb:v04B8p012C* + ID_MODEL_FROM_DATABASE=GT-X900 [Perfection V700/V750 Photo] + +usb:v04B8p012D* + ID_MODEL_FROM_DATABASE=GT-F650 [GT-S600/Perfection V10/V100] + +usb:v04B8p012E* + ID_MODEL_FROM_DATABASE=GT-F670 [Perfection V200 Photo] + +usb:v04B8p012F* + ID_MODEL_FROM_DATABASE=GT-F700 [Perfection V350] + +usb:v04B8p0130* + ID_MODEL_FROM_DATABASE=GT-X770 [Perfection V500] + +usb:v04B8p0131* + ID_MODEL_FROM_DATABASE=GT-F720 [GT-S620/Perfection V30/V300 Photo] + +usb:v04B8p0133* + ID_MODEL_FROM_DATABASE=GT-1500 [GT-D1000] + +usb:v04B8p0135* + ID_MODEL_FROM_DATABASE=GT-X970 + +usb:v04B8p0136* + ID_MODEL_FROM_DATABASE=ES-D400 [GT-S80] + +usb:v04B8p0137* + ID_MODEL_FROM_DATABASE=ES-D200 [GT-S50] + +usb:v04B8p0138* + ID_MODEL_FROM_DATABASE=ES-H7200 [GT-20000] + +usb:v04B8p013A* + ID_MODEL_FROM_DATABASE=GT-X820 [Perfection V600 Photo] + +usb:v04B8p0142* + ID_MODEL_FROM_DATABASE=GT-F730 [GT-S630/Perfection V33/V330 Photo] + +usb:v04B8p0143* + ID_MODEL_FROM_DATABASE=GT-S55 + +usb:v04B8p0144* + ID_MODEL_FROM_DATABASE=GT-S85 + +usb:v04B8p0202* + ID_MODEL_FROM_DATABASE=Receipt Printer M129C/TM-T70 + +usb:v04B8p0401* + ID_MODEL_FROM_DATABASE=CP 800 Digital Camera + +usb:v04B8p0402* + ID_MODEL_FROM_DATABASE=PhotoPC 850z + +usb:v04B8p0403* + ID_MODEL_FROM_DATABASE=PhotoPC 3000z + +usb:v04B8p0509* + ID_MODEL_FROM_DATABASE=JVC PIX-MC10 + +usb:v04B8p0601* + ID_MODEL_FROM_DATABASE=Stylus Photo 875DC Card Reader + +usb:v04B8p0602* + ID_MODEL_FROM_DATABASE=Stylus Photo 895 Card Reader + +usb:v04B8p0801* + ID_MODEL_FROM_DATABASE=CC-600PX [Stylus CX5200/CX5400/CX6600] + +usb:v04B8p0802* + ID_MODEL_FROM_DATABASE=CC-570L [Stylus CX3100/CX3200] + +usb:v04B8p0803* + ID_MODEL_FROM_DATABASE=Printer (Composite Device) + +usb:v04B8p0804* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p0805* + ID_MODEL_FROM_DATABASE=Stylus CX6300/CX6400 + +usb:v04B8p0806* + ID_MODEL_FROM_DATABASE=PM-A850 [Stylus Photo RX600/610] + +usb:v04B8p0807* + ID_MODEL_FROM_DATABASE=Stylus Photo RX500/510 + +usb:v04B8p0808* + ID_MODEL_FROM_DATABASE=Stylus CX5200/CX5300/CX5400 + +usb:v04B8p0809* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p080A* + ID_MODEL_FROM_DATABASE=F-3200 + +usb:v04B8p080C* + ID_MODEL_FROM_DATABASE=ME100 [Stylus CX1500] + +usb:v04B8p080D* + ID_MODEL_FROM_DATABASE=Stylus CX4500/4600 + +usb:v04B8p080E* + ID_MODEL_FROM_DATABASE=PX-A550 [CX-3500/3600/3650 MFP] + +usb:v04B8p080F* + ID_MODEL_FROM_DATABASE=Stylus Photo RX420/RX425/RX430 + +usb:v04B8p0810* + ID_MODEL_FROM_DATABASE=PM-A900 [Stylus Photo RX700] + +usb:v04B8p0811* + ID_MODEL_FROM_DATABASE=PM-A870 [Stylus Photo RX620/RX630] + +usb:v04B8p0812* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p0813* + ID_MODEL_FROM_DATABASE=Stylus CX6500/6600 + +usb:v04B8p0814* + ID_MODEL_FROM_DATABASE=PM-A700 + +usb:v04B8p0815* + ID_MODEL_FROM_DATABASE=LP-A500 [AcuLaser CX1] + +usb:v04B8p0816* + ID_MODEL_FROM_DATABASE=Printer (Composite Device) + +usb:v04B8p0817* + ID_MODEL_FROM_DATABASE=LP-M5500/LP-M5500F + +usb:v04B8p0818* + ID_MODEL_FROM_DATABASE=Stylus CX3700/CX3800/DX3800 + +usb:v04B8p0819* + ID_MODEL_FROM_DATABASE=PX-A650 [Stylus CX4700/CX4800/DX4800/DX4850] + +usb:v04B8p081A* + ID_MODEL_FROM_DATABASE=PM-A750 [Stylus Photo RX520/RX530] + +usb:v04B8p081B* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p081C* + ID_MODEL_FROM_DATABASE=PM-A890 [Stylus Photo RX640/RX650] + +usb:v04B8p081D* + ID_MODEL_FROM_DATABASE=PM-A950 + +usb:v04B8p081E* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p081F* + ID_MODEL_FROM_DATABASE=Stylus CX7700/7800 + +usb:v04B8p0820* + ID_MODEL_FROM_DATABASE=Stylus CX4100/CX4200/DX4200 + +usb:v04B8p0821* + ID_MODEL_FROM_DATABASE=Stylus CX5700F/CX5800F + +usb:v04B8p0822* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p0823* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p0824* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p0825* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p0826* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p0827* + ID_MODEL_FROM_DATABASE=PM-A820 [Stylus Photo RX560/RX580/RX585/RX590] + +usb:v04B8p0828* + ID_MODEL_FROM_DATABASE=PM-A970 + +usb:v04B8p0829* + ID_MODEL_FROM_DATABASE=PM-T990 + +usb:v04B8p082A* + ID_MODEL_FROM_DATABASE=PM-A920 + +usb:v04B8p082B* + ID_MODEL_FROM_DATABASE=Stylus CX5900/CX5000/DX5000/DX5050 + +usb:v04B8p082C* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p082D* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04B8p082E* + ID_MODEL_FROM_DATABASE=PX-A720 [Stylus CX5900/CX6000/DX6000] + +usb:v04B8p082F* + ID_MODEL_FROM_DATABASE=PX-A620 [Stylus CX3900/DX4000/DX4050] + +usb:v04B8p0830* + ID_MODEL_FROM_DATABASE=ME 200 [Stylus CX2800/CX2900] + +usb:v04B8p0831* + ID_MODEL_FROM_DATABASE=Stylus CX6900F/CX7000F/DX7000F + +usb:v04B8p0832* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p0833* + ID_MODEL_FROM_DATABASE=LP-M5600 + +usb:v04B8p0834* + ID_MODEL_FROM_DATABASE=LP-M6000 + +usb:v04B8p0835* + ID_MODEL_FROM_DATABASE=AcuLaser CX21 + +usb:v04B8p0836* + ID_MODEL_FROM_DATABASE=PM-T960 + +usb:v04B8p0837* + ID_MODEL_FROM_DATABASE=PM-A940 [Stylus Photo RX680/RX685/RX690] + +usb:v04B8p0838* + ID_MODEL_FROM_DATABASE=PX-A640 [CX7300/CX7400/DX7400] + +usb:v04B8p0839* + ID_MODEL_FROM_DATABASE=PX-A740 [CX8300/CX8400/DX8400] + +usb:v04B8p083A* + ID_MODEL_FROM_DATABASE=PX-FA700 [CX9300F/CX9400Fax/DX9400F] + +usb:v04B8p083B* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p083C* + ID_MODEL_FROM_DATABASE=PM-A840S [Stylus Photo RX595/RX610] + +usb:v04B8p083D* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p083E* + ID_MODEL_FROM_DATABASE=MFP Composite Device + +usb:v04B8p083F* + ID_MODEL_FROM_DATABASE=Stylus CX4300/CX4400/CX5500/CX5600/DX4400/DX4450 + +usb:v04B8p0841* + ID_MODEL_FROM_DATABASE=PX-401A [ME 300/Stylus NX100] + +usb:v04B8p0843* + ID_MODEL_FROM_DATABASE=LP-M5000 + +usb:v04B8p0844* + ID_MODEL_FROM_DATABASE=EP-901A/EP-901F [Artisan 800/Stylus Photo PX800FW] + +usb:v04B8p0846* + ID_MODEL_FROM_DATABASE=EP-801A [Artisan 700/Stylus Photo PX700W/TX700W] + +usb:v04B8p0847* + ID_MODEL_FROM_DATABASE=PX-601F [ME Office 700FW/Stylus Office BX600FW/TX600FW] + +usb:v04B8p0848* + ID_MODEL_FROM_DATABASE=ME Office 600F/Stylus Office BX300F/TX300F + +usb:v04B8p0849* + ID_MODEL_FROM_DATABASE=Stylus SX205 + +usb:v04B8p084A* + ID_MODEL_FROM_DATABASE=PX-501A [Stylus NX400] + +usb:v04B8p084D* + ID_MODEL_FROM_DATABASE=PX-402A [Stylus SX115/Stylus NX110 Series] + +usb:v04B8p084F* + ID_MODEL_FROM_DATABASE=ME OFFICE 510 + +usb:v04B8p0850* + ID_MODEL_FROM_DATABASE=EP-702A [Stylus Photo PX650/TX650 Series] + +usb:v04B8p0851* + ID_MODEL_FROM_DATABASE=Stylus SX410 + +usb:v04B8p0852* + ID_MODEL_FROM_DATABASE=EP-802A [Artisan 710 Series/Stylus Photo PX710W/TX720W Series] + +usb:v04B8p0853* + ID_MODEL_FROM_DATABASE=EP-902A [Artisan 810 Series/Stylus Photo PX810FW Series] + +usb:v04B8p0854* + ID_MODEL_FROM_DATABASE=ME OFFICE 650FN Series/Stylus Office BX310FN/TX520FN Series + +usb:v04B8p0855* + ID_MODEL_FROM_DATABASE=PX-602F [Stylus Office BX610FW/TX620FW Series] + +usb:v04B8p0856* + ID_MODEL_FROM_DATABASE=PX-502A [Stylus SX515W] + +usb:v04B8p085C* + ID_MODEL_FROM_DATABASE=ME 320/330 Series [Stylus SX125] + +usb:v04B8p085D* + ID_MODEL_FROM_DATABASE=PX-603F [ME OFFICE 960FWD Series/Stylus Office BX625FWD/TX620FWD Series] + +usb:v04B8p085E* + ID_MODEL_FROM_DATABASE=PX-503A [ME OFFICE 900WD Series/Stylus Office BX525WD] + +usb:v04B8p085F* + ID_MODEL_FROM_DATABASE=Stylus Office BX320FW/TX525FW Series + +usb:v04B8p0860* + ID_MODEL_FROM_DATABASE=EP-903A/EP-903F [Artisan 835/Stylus Photo PX820FWD Series] + +usb:v04B8p0861* + ID_MODEL_FROM_DATABASE=EP-803A/EP-803AW [Artisan 725/Stylus Photo PX720WD/TX720WD Series] + +usb:v04B8p0862* + ID_MODEL_FROM_DATABASE=EP-703A [Stylus Photo PX660 Series] + +usb:v04B8p0863* + ID_MODEL_FROM_DATABASE=ME OFFICE 620F Series/Stylus Office BX305F/BX305FW/TX320F + +usb:v04B8p0864* + ID_MODEL_FROM_DATABASE=ME OFFICE 560W Series + +usb:v04B8p0865* + ID_MODEL_FROM_DATABASE=ME OFFICE 520 Series + +usb:v04B8p0866* + ID_MODEL_FROM_DATABASE=AcuLaser MX20DN/MX20DNF/MX21DNF + +usb:v04B8p0869* + ID_MODEL_FROM_DATABASE=PX-1600F + +usb:v04B8p086A* + ID_MODEL_FROM_DATABASE=PX-673F [Stylus Office BX925FWD] + +usb:v04B8p0870* + ID_MODEL_FROM_DATABASE=Stylus Office BX305FW Plus + +usb:v04B8p0871* + ID_MODEL_FROM_DATABASE=K200 Series + +usb:v04B8p0872* + ID_MODEL_FROM_DATABASE=K300 Series + +usb:v04B8p0873* + ID_MODEL_FROM_DATABASE=L200 Series + +usb:v04B8p0878* + ID_MODEL_FROM_DATABASE=EP-704A + +usb:v04B8p0879* + ID_MODEL_FROM_DATABASE=EP-904A/EP-904F [Artisan 837/Stylus Photo PX830FWD Series] + +usb:v04B8p087B* + ID_MODEL_FROM_DATABASE=EP-804A/EP-804AR/EP-804AW [Stylus Photo PX730WD/Artisan 730 Series] + +usb:v04B8p087C* + ID_MODEL_FROM_DATABASE=PX-1700F + +usb:v04B8p087D* + ID_MODEL_FROM_DATABASE=PX-B750F + +usb:v04B8p087F* + ID_MODEL_FROM_DATABASE=PX-403A + +usb:v04B8p0880* + ID_MODEL_FROM_DATABASE=PX-434A [Stylus NX330 Series] + +usb:v04B8p0881* + ID_MODEL_FROM_DATABASE=PX-404A [ME OFFICE 535] + +usb:v04B8p0883* + ID_MODEL_FROM_DATABASE=ME 340 Series/Stylus NX130 Series + +usb:v04B8p0884* + ID_MODEL_FROM_DATABASE=Stylus NX430W Series + +usb:v04B8p0885* + ID_MODEL_FROM_DATABASE=Stylus NX230 Series + +usb:v04B8p088F* + ID_MODEL_FROM_DATABASE=Stylus Office BX635FWD + +usb:v04B8p0890* + ID_MODEL_FROM_DATABASE=ME OFFICE 940FW Series/Stylus Office BX630FW Series + +usb:v04B8p0891* + ID_MODEL_FROM_DATABASE=Stylus Office BX535WD + +usb:v04B8p0892* + ID_MODEL_FROM_DATABASE=Stylus Office BX935FWD + +usb:v04B8p0893* + ID_MODEL_FROM_DATABASE=EP-774A + +usb:v04B9* + ID_VENDOR_FROM_DATABASE=Rainbow Technologies, Inc. + +usb:v04B9p0300* + ID_MODEL_FROM_DATABASE=SafeNet USB SuperPro/UltraPro + +usb:v04B9p1000* + ID_MODEL_FROM_DATABASE=iKey 1000 Token + +usb:v04B9p1001* + ID_MODEL_FROM_DATABASE=iKey 1200 Token + +usb:v04B9p1002* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1003* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1004* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1005* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1006* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1200* + ID_MODEL_FROM_DATABASE=iKey 2000 Token + +usb:v04B9p1201* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1202* + ID_MODEL_FROM_DATABASE=iKey 2032 Token + +usb:v04B9p1203* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1204* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1205* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1206* + ID_MODEL_FROM_DATABASE=iKey 4000 Token + +usb:v04B9p1300* + ID_MODEL_FROM_DATABASE=iKey 3000 Token + +usb:v04B9p1301* + ID_MODEL_FROM_DATABASE=iKey 3000 + +usb:v04B9p1302* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1303* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1304* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1305* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04B9p1306* + ID_MODEL_FROM_DATABASE=iKey Token + +usb:v04BA* + ID_VENDOR_FROM_DATABASE=Toucan Systems, Ltd + +usb:v04BB* + ID_VENDOR_FROM_DATABASE=I-O Data Device, Inc. + +usb:v04BBp0101* + ID_MODEL_FROM_DATABASE=USB2-IDE/ATAPI Bridge Adapter + +usb:v04BBp0201* + ID_MODEL_FROM_DATABASE=USB2-IDE/ATAPI Bridge Adapter + +usb:v04BBp0204* + ID_MODEL_FROM_DATABASE=DVD Multi-plus unit iU-CD2 + +usb:v04BBp0206* + ID_MODEL_FROM_DATABASE=DVD Multi-plus unit DVR-UEH8 + +usb:v04BBp0301* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v04BBp0314* + ID_MODEL_FROM_DATABASE=USB-SSMRW SD-card + +usb:v04BBp0319* + ID_MODEL_FROM_DATABASE=USB2-IDE/ATAPI Bridge Adapter + +usb:v04BBp031A* + ID_MODEL_FROM_DATABASE=USB2-IDE/ATAPI Bridge Adapter + +usb:v04BBp031B* + ID_MODEL_FROM_DATABASE=USB2-IDE/ATAPI Bridge Adapter + +usb:v04BBp031E* + ID_MODEL_FROM_DATABASE=USB-SDRW SD-card + +usb:v04BBp0502* + ID_MODEL_FROM_DATABASE=Nogatech Live! (BT) + +usb:v04BBp0528* + ID_MODEL_FROM_DATABASE=GV-USB Video Capture + +usb:v04BBp0901* + ID_MODEL_FROM_DATABASE=USB ETT + +usb:v04BBp0904* + ID_MODEL_FROM_DATABASE=ET/TX Ethernet [pegasus] + +usb:v04BBp0913* + ID_MODEL_FROM_DATABASE=ET/TX-S Ethernet [pegasus2] + +usb:v04BBp0919* + ID_MODEL_FROM_DATABASE=USB WN-B11 + +usb:v04BBp0922* + ID_MODEL_FROM_DATABASE=IOData AirPort WN-B11/USBS 802.11b + +usb:v04BBp0930* + ID_MODEL_FROM_DATABASE=ETG-US2 + +usb:v04BBp0937* + ID_MODEL_FROM_DATABASE=WN-WAG/USL Wireless LAN Adapter + +usb:v04BBp0938* + ID_MODEL_FROM_DATABASE=WN-G54/USL Wireless LAN Adapter + +usb:v04BBp093B* + ID_MODEL_FROM_DATABASE=WN-GDN/USB + +usb:v04BBp093F* + ID_MODEL_FROM_DATABASE=WNGDNUS2 802.11n + +usb:v04BBp0944* + ID_MODEL_FROM_DATABASE=WHG-AGDN/US Wireless LAN Adapter + +usb:v04BBp0945* + ID_MODEL_FROM_DATABASE=WN-GDN/US3 Wireless LAN Adapter + +usb:v04BBp0947* + ID_MODEL_FROM_DATABASE=WN-G150U Wireless LAN Adapter + +usb:v04BBp0948* + ID_MODEL_FROM_DATABASE=WN-G300U Wireless LAN Adapter + +usb:v04BBp0A03* + ID_MODEL_FROM_DATABASE=Serial USB-RSAQ1 + +usb:v04BBp0A07* + ID_MODEL_FROM_DATABASE=USB2-iCN Adapter + +usb:v04BBp0A08* + ID_MODEL_FROM_DATABASE=USB2-iCN Adapter + +usb:v04BBp0C01* + ID_MODEL_FROM_DATABASE=FM-10 Pro Disk + +usb:v04BD* + ID_VENDOR_FROM_DATABASE=Toshiba Electronics Taiwan Corp. + +usb:v04BE* + ID_VENDOR_FROM_DATABASE=Telia Research AB + +usb:v04BF* + ID_VENDOR_FROM_DATABASE=TDK Corp. + +usb:v04BFp0100* + ID_MODEL_FROM_DATABASE=MediaReader CF + +usb:v04BFp0115* + ID_MODEL_FROM_DATABASE=USB-PDC Adapter UPA9664 + +usb:v04BFp0116* + ID_MODEL_FROM_DATABASE=USB-cdmaOne Adapter UCA1464 + +usb:v04BFp0117* + ID_MODEL_FROM_DATABASE=USB-PHS Adapter UHA6400 + +usb:v04BFp0118* + ID_MODEL_FROM_DATABASE=USB-PHS Adapter UPA6400 + +usb:v04BFp0135* + ID_MODEL_FROM_DATABASE=MediaReader Dual + +usb:v04BFp0202* + ID_MODEL_FROM_DATABASE=73S1121F Smart Card Reader- + +usb:v04BFp0309* + ID_MODEL_FROM_DATABASE=Bluetooth USB dongle + +usb:v04BFp030A* + ID_MODEL_FROM_DATABASE=IBM Bluetooth Ultraport Module + +usb:v04BFp030B* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v04BFp030C* + ID_MODEL_FROM_DATABASE=Ultraport Bluetooth Device + +usb:v04BFp0310* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth + +usb:v04BFp0311* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth Device + +usb:v04BFp0317* + ID_MODEL_FROM_DATABASE=Bluetooth UltraPort Module from IBM + +usb:v04BFp0318* + ID_MODEL_FROM_DATABASE=IBM Integrated Bluetooth + +usb:v04BFp0319* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v04BFp0320* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v04BFp0321* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v04BFp0A28* + ID_MODEL_FROM_DATABASE=INDI AV-IN Device + +usb:v04C1* + ID_VENDOR_FROM_DATABASE=U.S. Robotics (3Com) + +usb:v04C1p0020* + ID_MODEL_FROM_DATABASE=56K Voice Pro + +usb:v04C1p0022* + ID_MODEL_FROM_DATABASE=56K Voice Pro + +usb:v04C1p007E* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v04C1p0082* + ID_MODEL_FROM_DATABASE=OfficeConnect Analog Modem + +usb:v04C1p008F* + ID_MODEL_FROM_DATABASE=Pro ISDN TA + +usb:v04C1p0097* + ID_MODEL_FROM_DATABASE=OfficeConnect Analog + +usb:v04C1p009D* + ID_MODEL_FROM_DATABASE=HomeConnect Webcam [vicam] + +usb:v04C1p00A9* + ID_MODEL_FROM_DATABASE=ISDN Pro TA-U + +usb:v04C1p00B9* + ID_MODEL_FROM_DATABASE=HomeConnect IDSL Modem + +usb:v04C1p3021* + ID_MODEL_FROM_DATABASE=56k Voice FaxModem Pro + +usb:v04C2* + ID_VENDOR_FROM_DATABASE=Methode Electronics Far East PTE, Ltd + +usb:v04C3* + ID_VENDOR_FROM_DATABASE=Maxi Switch, Inc. + +usb:v04C3p1102* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v04C3p2102* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v04C4* + ID_VENDOR_FROM_DATABASE=Lockheed Martin Energy Research + +usb:v04C5* + ID_VENDOR_FROM_DATABASE=Fujitsu, Ltd + +usb:v04C5p1029* + ID_MODEL_FROM_DATABASE=fi-4010c Scanner + +usb:v04C5p1033* + ID_MODEL_FROM_DATABASE=fi-4110CU + +usb:v04C5p1041* + ID_MODEL_FROM_DATABASE=fi-4120c Scanner + +usb:v04C5p1042* + ID_MODEL_FROM_DATABASE=fi-4220c Scanner + +usb:v04C5p105B* + ID_MODEL_FROM_DATABASE=AH-F401U Air H device + +usb:v04C5p1084* + ID_MODEL_FROM_DATABASE=PalmSecure Sensor V2 + +usb:v04C5p1096* + ID_MODEL_FROM_DATABASE=fi-5110EOX + +usb:v04C5p1097* + ID_MODEL_FROM_DATABASE=fi-5110C + +usb:v04C5p10AE* + ID_MODEL_FROM_DATABASE=fi-4120C2 + +usb:v04C5p10AF* + ID_MODEL_FROM_DATABASE=fi-4220C2 + +usb:v04C5p10E0* + ID_MODEL_FROM_DATABASE=fi-5120c Scanner + +usb:v04C5p10E1* + ID_MODEL_FROM_DATABASE=fi-5220C + +usb:v04C5p10E7* + ID_MODEL_FROM_DATABASE=fi-5900C + +usb:v04C5p10FE* + ID_MODEL_FROM_DATABASE=S500 + +usb:v04C5p1150* + ID_MODEL_FROM_DATABASE=fi-6230 + +usb:v04C6* + ID_VENDOR_FROM_DATABASE=Toshiba America Electronic Components + +usb:v04C7* + ID_VENDOR_FROM_DATABASE=Micro Macro Technologies + +usb:v04C8* + ID_VENDOR_FROM_DATABASE=Konica Corp. + +usb:v04C8p0720* + ID_MODEL_FROM_DATABASE=Digital Color Camera + +usb:v04C8p0721* + ID_MODEL_FROM_DATABASE=e-miniD Camera + +usb:v04C8p0722* + ID_MODEL_FROM_DATABASE=e-mini + +usb:v04C8p0723* + ID_MODEL_FROM_DATABASE=KD-200Z Camera + +usb:v04C8p0726* + ID_MODEL_FROM_DATABASE=KD-310Z Camera + +usb:v04C8p0728* + ID_MODEL_FROM_DATABASE=Revio C2 Mass Storage Device + +usb:v04C8p0729* + ID_MODEL_FROM_DATABASE=Revio C2 Digital Camera + +usb:v04C8p072C* + ID_MODEL_FROM_DATABASE=Revio KD20M + +usb:v04C8p072D* + ID_MODEL_FROM_DATABASE=Revio KD410Z + +usb:v04CA* + ID_VENDOR_FROM_DATABASE=Lite-On Technology Corp. + +usb:v04CAp1766* + ID_MODEL_FROM_DATABASE=HID Monitor Controls + +usb:v04CAp2004* + ID_MODEL_FROM_DATABASE=Bluetooth 4.0 [Broadcom BCM20702A0] + +usb:v04CAp9304* + ID_MODEL_FROM_DATABASE=Hub + +usb:v04CApF01C* + ID_MODEL_FROM_DATABASE=TT1280DA DVB-T TV Tuner + +usb:v04CB* + ID_VENDOR_FROM_DATABASE=Fuji Photo Film Co., Ltd + +usb:v04CBp0100* + ID_MODEL_FROM_DATABASE=FinePix 30i/40i/50i, A101/201, 1300/2200, 1400/2400/2600/2800/4500/4700/4800/4900/6800/6900 Zoom + +usb:v04CBp0103* + ID_MODEL_FROM_DATABASE=FinePix NX-500/NX-700 printer + +usb:v04CBp0104* + ID_MODEL_FROM_DATABASE=FinePix A101, 2600/2800/4800/6800 Zoom (PC CAM) + +usb:v04CBp0108* + ID_MODEL_FROM_DATABASE=FinePix F601 Zoom (DSC) + +usb:v04CBp0109* + ID_MODEL_FROM_DATABASE=FinePix F601 Zoom (PC CAM) + +usb:v04CBp010A* + ID_MODEL_FROM_DATABASE=FinePix S602 (Pro) Zoom (DSC) + +usb:v04CBp010B* + ID_MODEL_FROM_DATABASE=FinePix S602 (Pro) Zoom (PC CAM) + +usb:v04CBp010D* + ID_MODEL_FROM_DATABASE=FinePix Digital Camera 020531 + +usb:v04CBp010E* + ID_MODEL_FROM_DATABASE=FinePix F402 Zoom (DSC) + +usb:v04CBp010F* + ID_MODEL_FROM_DATABASE=FinePix F402 Zoom (PC CAM) + +usb:v04CBp0110* + ID_MODEL_FROM_DATABASE=FinePix M603 Zoom (DSC) + +usb:v04CBp0111* + ID_MODEL_FROM_DATABASE=FinePix M603 Zoom (PC CAM) + +usb:v04CBp0112* + ID_MODEL_FROM_DATABASE=FinePix A202, A200 Zoom (DSC) + +usb:v04CBp0113* + ID_MODEL_FROM_DATABASE=FinePix A202, A200 Zoom (PC CAM) + +usb:v04CBp0114* + ID_MODEL_FROM_DATABASE=FinePix F401 Zoom (DSC) + +usb:v04CBp0115* + ID_MODEL_FROM_DATABASE=FinePix F401 Zoom (PC CAM) + +usb:v04CBp0116* + ID_MODEL_FROM_DATABASE=FinePix A203 Zoom (DSC) + +usb:v04CBp0117* + ID_MODEL_FROM_DATABASE=FinePix A203 Zoom (PC CAM) + +usb:v04CBp0118* + ID_MODEL_FROM_DATABASE=FinePix A303 Zoom (DSC) + +usb:v04CBp0119* + ID_MODEL_FROM_DATABASE=FinePix A303 Zoom (PC CAM) + +usb:v04CBp011A* + ID_MODEL_FROM_DATABASE=FinePix S304/3800 Zoom (DSC) + +usb:v04CBp011B* + ID_MODEL_FROM_DATABASE=FinePix S304/3800 Zoom (PC CAM) + +usb:v04CBp011C* + ID_MODEL_FROM_DATABASE=FinePix A204/2650 Zoom (DSC) + +usb:v04CBp011D* + ID_MODEL_FROM_DATABASE=FinePix A204/2650 Zoom (PC CAM) + +usb:v04CBp0120* + ID_MODEL_FROM_DATABASE=FinePix F700 Zoom (DSC) + +usb:v04CBp0121* + ID_MODEL_FROM_DATABASE=FinePix F700 Zoom (PC CAM) + +usb:v04CBp0122* + ID_MODEL_FROM_DATABASE=FinePix F410 Zoom (DSC) + +usb:v04CBp0123* + ID_MODEL_FROM_DATABASE=FinePix F410 Zoom (PC CAM) + +usb:v04CBp0124* + ID_MODEL_FROM_DATABASE=FinePix A310 Zoom (DSC) + +usb:v04CBp0125* + ID_MODEL_FROM_DATABASE=FinePix A310 Zoom (PC CAM) + +usb:v04CBp0126* + ID_MODEL_FROM_DATABASE=FinePix A210 Zoom (DSC) + +usb:v04CBp0127* + ID_MODEL_FROM_DATABASE=FinePix A210 Zoom (PC CAM) + +usb:v04CBp0128* + ID_MODEL_FROM_DATABASE=FinePix A205(S) Zoom (DSC) + +usb:v04CBp0129* + ID_MODEL_FROM_DATABASE=FinePix A205(S) Zoom (PC CAM) + +usb:v04CBp012A* + ID_MODEL_FROM_DATABASE=FinePix F610 Zoom (DSC) + +usb:v04CBp012B* + ID_MODEL_FROM_DATABASE=FinePix Digital Camera 030513 + +usb:v04CBp012C* + ID_MODEL_FROM_DATABASE=FinePix S7000 Zoom (DSC) + +usb:v04CBp012D* + ID_MODEL_FROM_DATABASE=FinePix S7000 Zoom (PC CAM) + +usb:v04CBp012F* + ID_MODEL_FROM_DATABASE=FinePix Digital Camera 030731 + +usb:v04CBp0130* + ID_MODEL_FROM_DATABASE=FinePix S5000 Zoom (DSC) + +usb:v04CBp0131* + ID_MODEL_FROM_DATABASE=FinePix S5000 Zoom (PC CAM) + +usb:v04CBp013B* + ID_MODEL_FROM_DATABASE=FinePix Digital Camera 030722 + +usb:v04CBp013C* + ID_MODEL_FROM_DATABASE=FinePix S3000 Zoom (DSC) + +usb:v04CBp013D* + ID_MODEL_FROM_DATABASE=FinePix S3000 Zoom (PC CAM) + +usb:v04CBp013E* + ID_MODEL_FROM_DATABASE=FinePix F420 Zoom (DSC) + +usb:v04CBp013F* + ID_MODEL_FROM_DATABASE=FinePix F420 Zoom (PC CAM) + +usb:v04CBp0142* + ID_MODEL_FROM_DATABASE=FinePix S7000 Zoom (PTP) + +usb:v04CBp0148* + ID_MODEL_FROM_DATABASE=FinePix A330 Zoom (DSC) + +usb:v04CBp0149* + ID_MODEL_FROM_DATABASE=FinePix A330 Zoom (UVC) + +usb:v04CBp014A* + ID_MODEL_FROM_DATABASE=FinePix A330 Zoom (PTP) + +usb:v04CBp014B* + ID_MODEL_FROM_DATABASE=FinePix A340 Zoom (DSC) + +usb:v04CBp014C* + ID_MODEL_FROM_DATABASE=FinePix A340 Zoom (UVC) + +usb:v04CBp0159* + ID_MODEL_FROM_DATABASE=FinePix F710 Zoom (DSC) + +usb:v04CBp0165* + ID_MODEL_FROM_DATABASE=FinePix S3500 Zoom (DSC) + +usb:v04CBp0168* + ID_MODEL_FROM_DATABASE=FinePix E500 Zoom (DSC) + +usb:v04CBp0169* + ID_MODEL_FROM_DATABASE=FinePix E500 Zoom (UVC) + +usb:v04CBp016B* + ID_MODEL_FROM_DATABASE=FinePix E510 Zoom (DSC) + +usb:v04CBp016C* + ID_MODEL_FROM_DATABASE=FinePix E510 Zoom (PC CAM) + +usb:v04CBp016E* + ID_MODEL_FROM_DATABASE=FinePix S5500 Zoom (DSC) + +usb:v04CBp016F* + ID_MODEL_FROM_DATABASE=FinePix S5500 Zoom (UVC) + +usb:v04CBp0171* + ID_MODEL_FROM_DATABASE=FinePix E550 Zoom (DSC) + +usb:v04CBp0172* + ID_MODEL_FROM_DATABASE=FinePix E550 Zoom (UVC) + +usb:v04CBp0177* + ID_MODEL_FROM_DATABASE=FinePix F10 (DSC) + +usb:v04CBp0179* + ID_MODEL_FROM_DATABASE=Finepix F10 (PTP) + +usb:v04CBp0186* + ID_MODEL_FROM_DATABASE=FinePix S5200/S5600 Zoom (DSC) + +usb:v04CBp0188* + ID_MODEL_FROM_DATABASE=FinePix S5200/S5600 Zoom (PTP) + +usb:v04CBp018E* + ID_MODEL_FROM_DATABASE=FinePix S9500 Zoom (DSC) + +usb:v04CBp018F* + ID_MODEL_FROM_DATABASE=FinePix S9500 Zoom (PTP) + +usb:v04CBp0192* + ID_MODEL_FROM_DATABASE=FinePix E900 Zoom (DSC) + +usb:v04CBp0193* + ID_MODEL_FROM_DATABASE=FinePix E900 Zoom (PTP) + +usb:v04CBp019B* + ID_MODEL_FROM_DATABASE=FinePix F30 (PTP) + +usb:v04CBp01AF* + ID_MODEL_FROM_DATABASE=FinePix A700 (PTP) + +usb:v04CBp01BF* + ID_MODEL_FROM_DATABASE=FinePix F6000fd/S6500fd Zoom (PTP) + +usb:v04CBp01C0* + ID_MODEL_FROM_DATABASE=FinePix F20 (PTP) + +usb:v04CBp01C1* + ID_MODEL_FROM_DATABASE=FinePix F31fd (PTP) + +usb:v04CBp01C4* + ID_MODEL_FROM_DATABASE=FinePix S5700 Zoom (PTP) + +usb:v04CBp01C5* + ID_MODEL_FROM_DATABASE=FinePix F40fd (PTP) + +usb:v04CBp01C6* + ID_MODEL_FROM_DATABASE=FinePix A820 Zoom (PTP) + +usb:v04CBp01D2* + ID_MODEL_FROM_DATABASE=FinePix A800 Zoom (PTP) + +usb:v04CBp01D3* + ID_MODEL_FROM_DATABASE=FinePix A920 (PTP) + +usb:v04CBp01D4* + ID_MODEL_FROM_DATABASE=FinePix F50fd (PTP) + +usb:v04CBp01D5* + ID_MODEL_FROM_DATABASE=FinePix F47 (PTP) + +usb:v04CBp01F7* + ID_MODEL_FROM_DATABASE=FinePix J250 (PTP) + +usb:v04CBp01FD* + ID_MODEL_FROM_DATABASE=A160 + +usb:v04CBp023E* + ID_MODEL_FROM_DATABASE=FinePix AX300 + +usb:v04CBp0240* + ID_MODEL_FROM_DATABASE=FinePix S2950 Digital Camera + +usb:v04CBp0241* + ID_MODEL_FROM_DATABASE=FinePix S3200 Digital Camera + +usb:v04CBp0278* + ID_MODEL_FROM_DATABASE=FinePix JV300 + +usb:v04CC* + ID_VENDOR_FROM_DATABASE=ST-Ericsson + +usb:v04CCp1122* + ID_MODEL_FROM_DATABASE=Hub + +usb:v04CCp1520* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub (Avocent KVM) + +usb:v04CCp1521* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v04CCp1A62* + ID_MODEL_FROM_DATABASE=GW Instek GSP-830 Spectrum Analyzer (HID) + +usb:v04CCp2323* + ID_MODEL_FROM_DATABASE=Ux500 serial debug port + +usb:v04CCp2533* + ID_MODEL_FROM_DATABASE=NFC device (PN533) + +usb:v04CCp8116* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04CD* + ID_VENDOR_FROM_DATABASE=Tatung Co. Of America + +usb:v04CE* + ID_VENDOR_FROM_DATABASE=ScanLogic Corp. + +usb:v04CEp0002* + ID_MODEL_FROM_DATABASE=SL11R-IDE IDE Bridge + +usb:v04CEp0100* + ID_MODEL_FROM_DATABASE=USB2PRN Printer Class + +usb:v04CEp0300* + ID_MODEL_FROM_DATABASE=Phantom 336CX - C3 scanner + +usb:v04CEp04CE* + ID_MODEL_FROM_DATABASE=SL11DEMO, VID: 0x4ce, PID: 0x4ce + +usb:v04CEp07D1* + ID_MODEL_FROM_DATABASE=SL11R, VID: 0x4ce, PID: 0x07D1 + +usb:v04CF* + ID_VENDOR_FROM_DATABASE=Myson Century, Inc. + +usb:v04CFp0022* + ID_MODEL_FROM_DATABASE=OCZ Alchemy Series Elixir II Keyboard + +usb:v04CFp0800* + ID_MODEL_FROM_DATABASE=MTP800 Mass Storage Device + +usb:v04CFp8810* + ID_MODEL_FROM_DATABASE=CS8810 Mass Storage Device + +usb:v04CFp8811* + ID_MODEL_FROM_DATABASE=CS8811 Mass Storage Device + +usb:v04CFp8813* + ID_MODEL_FROM_DATABASE=CS8813 Mass Storage Device + +usb:v04CFp8818* + ID_MODEL_FROM_DATABASE=USB2.0 to ATAPI Bridge Controller + +usb:v04CFp8819* + ID_MODEL_FROM_DATABASE=USB 2.0 SD/MMC Reader + +usb:v04CFp9920* + ID_MODEL_FROM_DATABASE=CS8819A2-114 Mass Storage Device + +usb:v04D0* + ID_VENDOR_FROM_DATABASE=Digi International + +usb:v04D1* + ID_VENDOR_FROM_DATABASE=ITT Canon + +usb:v04D2* + ID_VENDOR_FROM_DATABASE=Altec Lansing Technologies + +usb:v04D2p0070* + ID_MODEL_FROM_DATABASE=ADA70 Speakers + +usb:v04D2p0305* + ID_MODEL_FROM_DATABASE=Non-Compliant Audio Device + +usb:v04D2p0311* + ID_MODEL_FROM_DATABASE=ADA-310 Speakers + +usb:v04D2p2060* + ID_MODEL_FROM_DATABASE=Claritel-i750 - vp + +usb:v04D2pFF05* + ID_MODEL_FROM_DATABASE=ADA-305 Speakers + +usb:v04D2pFF47* + ID_MODEL_FROM_DATABASE=Lansing HID Audio Controls + +usb:v04D2pFF49* + ID_MODEL_FROM_DATABASE=Lansing HID Audio Controls + +usb:v04D3* + ID_VENDOR_FROM_DATABASE=VidUS, Inc. + +usb:v04D4* + ID_VENDOR_FROM_DATABASE=LSI Logic, Inc. + +usb:v04D5* + ID_VENDOR_FROM_DATABASE=Forte Technologies, Inc. + +usb:v04D6* + ID_VENDOR_FROM_DATABASE=Mentor Graphics + +usb:v04D7* + ID_VENDOR_FROM_DATABASE=Oki Semiconductor + +usb:v04D7p1BE4* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v04D8* + ID_VENDOR_FROM_DATABASE=Microchip Technology, Inc. + +usb:v04D8p0002* + ID_MODEL_FROM_DATABASE=PicoLCD 20x2 + +usb:v04D8p0003* + ID_MODEL_FROM_DATABASE=PICkit 2 Microcontroller Programmer + +usb:v04D8p000A* + ID_MODEL_FROM_DATABASE=CDC RS-232 Emulation Demo + +usb:v04D8p000B* + ID_MODEL_FROM_DATABASE=PIC18F2550 (32K Flashable 10 Channel, 10 Bit A/D USB Microcontroller) + +usb:v04D8p0032* + ID_MODEL_FROM_DATABASE=PICkit1 + +usb:v04D8p0033* + ID_MODEL_FROM_DATABASE=PICkit2 + +usb:v04D8p0036* + ID_MODEL_FROM_DATABASE=PICkit Serial Analyzer + +usb:v04D8p00E0* + ID_MODEL_FROM_DATABASE=PIC32 Starter Board + +usb:v04D8p0A04* + ID_MODEL_FROM_DATABASE=AGP LIN Serial Analyzer + +usb:v04D8p8000* + ID_MODEL_FROM_DATABASE=In-Circuit Debugger + +usb:v04D8p8001* + ID_MODEL_FROM_DATABASE=ICD2 in-circuit debugger + +usb:v04D8p8101* + ID_MODEL_FROM_DATABASE=PIC24F Starter Kit + +usb:v04D8p8107* + ID_MODEL_FROM_DATABASE=Microstick II + +usb:v04D8p9004* + ID_MODEL_FROM_DATABASE=Microchip REAL ICE + +usb:v04D8p900A* + ID_MODEL_FROM_DATABASE=PICkit3 + +usb:v04D8pC001* + ID_MODEL_FROM_DATABASE=PicoLCD 20x4 + +usb:v04D8pF8DA* + ID_MODEL_FROM_DATABASE=Hughski Ltd. ColorHug + +usb:v04D8pFAFF* + ID_MODEL_FROM_DATABASE=Dangerous Prototypes BusPirate v4 Bootloader mode + +usb:v04D8pFB00* + ID_MODEL_FROM_DATABASE=Dangerous Prototypes BusPirate v4 + +usb:v04D8pFBB2* + ID_MODEL_FROM_DATABASE=GCUSB-nStep stepper motor controller + +usb:v04D8pFBBA* + ID_MODEL_FROM_DATABASE=DiscFerret Magnetic Disc Analyser (bootloader mode) + +usb:v04D8pFBBB* + ID_MODEL_FROM_DATABASE=DiscFerret Magnetic Disc Analyser (active mode) + +usb:v04D8pFC92* + ID_MODEL_FROM_DATABASE=Open Bench Logic Sniffer + +usb:v04D8pFFEF* + ID_MODEL_FROM_DATABASE=PICoPLC [APStech] + +usb:v04D9* + ID_VENDOR_FROM_DATABASE=Holtek Semiconductor, Inc. + +usb:v04D9p0022* + ID_MODEL_FROM_DATABASE=Portable Keyboard + +usb:v04D9p048E* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v04D9p0499* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v04D9p1203* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04D9p1400* + ID_MODEL_FROM_DATABASE=PS/2 keyboard + mouse controller + +usb:v04D9p1503* + ID_MODEL_FROM_DATABASE=Shortboard Lefty + +usb:v04D9p1603* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04D9p1702* + ID_MODEL_FROM_DATABASE=Keyboard LKS02 + +usb:v04D9p2013* + ID_MODEL_FROM_DATABASE=Keyboard [Das Keyboard] + +usb:v04D9p2221* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04D9p2323* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04D9p2519* + ID_MODEL_FROM_DATABASE=Shenzhen LogoTech 2.4GHz receiver + +usb:v04D9p2832* + ID_MODEL_FROM_DATABASE=1channel Telephone line recorder + +usb:v04D9p2834* + ID_MODEL_FROM_DATABASE=HT82A834R Audio MCU + +usb:v04D9pA055* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v04DA* + ID_VENDOR_FROM_DATABASE=Panasonic (Matsushita) + +usb:v04DAp0901* + ID_MODEL_FROM_DATABASE=LS-120 Camera + +usb:v04DAp0912* + ID_MODEL_FROM_DATABASE=SDR-S10 + +usb:v04DAp0B01* + ID_MODEL_FROM_DATABASE=CD-R/RW Drive + +usb:v04DAp0B03* + ID_MODEL_FROM_DATABASE=SuperDisk 240MB + +usb:v04DAp0D01* + ID_MODEL_FROM_DATABASE=CD-R Drive KXL-840AN + +usb:v04DAp0D09* + ID_MODEL_FROM_DATABASE=CD-R Drive KXL-RW32AN + +usb:v04DAp0D0A* + ID_MODEL_FROM_DATABASE=CD-R Drive KXL-CB20AN + +usb:v04DAp0D0D* + ID_MODEL_FROM_DATABASE=CDRCB03 + +usb:v04DAp0D0E* + ID_MODEL_FROM_DATABASE=DVD-ROM & CD-R/RW + +usb:v04DAp0F40* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04DAp104D* + ID_MODEL_FROM_DATABASE=Elite Panaboard UB-T880 (HID) + +usb:v04DAp104E* + ID_MODEL_FROM_DATABASE=Elite Panaboard Pen Adaptor (HID) + +usb:v04DAp1500* + ID_MODEL_FROM_DATABASE=MFSUSB Driver + +usb:v04DAp1800* + ID_MODEL_FROM_DATABASE=DY-WL10 802.11abgn Adapter [Broadcom BCM4323] + +usb:v04DAp1B00* + ID_MODEL_FROM_DATABASE=MultiMediaCard + +usb:v04DAp2121* + ID_MODEL_FROM_DATABASE=EB-VS6 + +usb:v04DAp2316* + ID_MODEL_FROM_DATABASE=DVC Mass Storage Device + +usb:v04DAp2317* + ID_MODEL_FROM_DATABASE=DVC USB-SERIAL Driver for WinXP + +usb:v04DAp2318* + ID_MODEL_FROM_DATABASE=NV-GS11/230/250 (webcam mode) + +usb:v04DAp2319* + ID_MODEL_FROM_DATABASE=NV-GS15 (webcam mode) + +usb:v04DAp231A* + ID_MODEL_FROM_DATABASE=NV-GS11/230/250 (DV mode) + +usb:v04DAp231D* + ID_MODEL_FROM_DATABASE=DVC Web Camera Device + +usb:v04DAp231E* + ID_MODEL_FROM_DATABASE=DVC DV Stream Device + +usb:v04DAp2372* + ID_MODEL_FROM_DATABASE=Lumix Camera (Storage mode) + +usb:v04DAp2374* + ID_MODEL_FROM_DATABASE=Lumix Camera (PTP mode) + +usb:v04DAp2451* + ID_MODEL_FROM_DATABASE=HDC-SD9 + +usb:v04DAp2497* + ID_MODEL_FROM_DATABASE=HDC-TM700 + +usb:v04DAp250C* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v04DAp250D* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v04DAp3904* + ID_MODEL_FROM_DATABASE=N5HBZ0000055 802.11abgn Wireless Adapter [Atheros AR7010+AR9280] + +usb:v04DAp3C04* + ID_MODEL_FROM_DATABASE=JT-P100MR-20 [ePassport Reader] + +usb:v04DB* + ID_VENDOR_FROM_DATABASE=Hypertec Pty, Ltd + +usb:v04DC* + ID_VENDOR_FROM_DATABASE=Huan Hsin Holdings, Ltd + +usb:v04DD* + ID_VENDOR_FROM_DATABASE=Sharp Corp. + +usb:v04DDp13A6* + ID_MODEL_FROM_DATABASE=MFC2000 + +usb:v04DDp6006* + ID_MODEL_FROM_DATABASE=AL-1216 + +usb:v04DDp6007* + ID_MODEL_FROM_DATABASE=AL-1045 + +usb:v04DDp6008* + ID_MODEL_FROM_DATABASE=AL-1255 + +usb:v04DDp6009* + ID_MODEL_FROM_DATABASE=AL-1530CS + +usb:v04DDp600A* + ID_MODEL_FROM_DATABASE=AL-1540CS + +usb:v04DDp600B* + ID_MODEL_FROM_DATABASE=AL-1456 + +usb:v04DDp600C* + ID_MODEL_FROM_DATABASE=AL-1555 + +usb:v04DDp600D* + ID_MODEL_FROM_DATABASE=AL-1225 + +usb:v04DDp600E* + ID_MODEL_FROM_DATABASE=AL-1551CS + +usb:v04DDp600F* + ID_MODEL_FROM_DATABASE=AR-122E + +usb:v04DDp6010* + ID_MODEL_FROM_DATABASE=AR-152E + +usb:v04DDp6011* + ID_MODEL_FROM_DATABASE=AR-157E + +usb:v04DDp6012* + ID_MODEL_FROM_DATABASE=SN-1045 + +usb:v04DDp6013* + ID_MODEL_FROM_DATABASE=SN-1255 + +usb:v04DDp6014* + ID_MODEL_FROM_DATABASE=SN-1456 + +usb:v04DDp6015* + ID_MODEL_FROM_DATABASE=SN-1555 + +usb:v04DDp6016* + ID_MODEL_FROM_DATABASE=AR-153E + +usb:v04DDp6017* + ID_MODEL_FROM_DATABASE=AR-122E N + +usb:v04DDp6018* + ID_MODEL_FROM_DATABASE=AR-153E N + +usb:v04DDp6019* + ID_MODEL_FROM_DATABASE=AR-152E N + +usb:v04DDp601A* + ID_MODEL_FROM_DATABASE=AR-157E N + +usb:v04DDp601B* + ID_MODEL_FROM_DATABASE=AL-1217 + +usb:v04DDp601C* + ID_MODEL_FROM_DATABASE=AL-1226 + +usb:v04DDp601D* + ID_MODEL_FROM_DATABASE=AR-123E + +usb:v04DDp6021* + ID_MODEL_FROM_DATABASE=IS01 + +usb:v04DDp7002* + ID_MODEL_FROM_DATABASE=DVC Ver.1.0 + +usb:v04DDp7004* + ID_MODEL_FROM_DATABASE=VE-CG40U Digital Still Camera + +usb:v04DDp7005* + ID_MODEL_FROM_DATABASE=VE-CG30 Digital Still Camera + +usb:v04DDp7007* + ID_MODEL_FROM_DATABASE=VL-Z7S Digital Camcorder + +usb:v04DDp8004* + ID_MODEL_FROM_DATABASE=Zaurus SL-5000D/SL-5500 PDA + +usb:v04DDp8005* + ID_MODEL_FROM_DATABASE=Zaurus A-300 + +usb:v04DDp8006* + ID_MODEL_FROM_DATABASE=Zaurus SL-B500/SL-5600 PDA + +usb:v04DDp8007* + ID_MODEL_FROM_DATABASE=Zaurus C-700 PDA + +usb:v04DDp9009* + ID_MODEL_FROM_DATABASE=AR-M160 + +usb:v04DDp9014* + ID_MODEL_FROM_DATABASE=IM-DR80 Portable NetMD Player + +usb:v04DDp9031* + ID_MODEL_FROM_DATABASE=Zaurus C-750/C-760/C-860/SL-C3000 PDA + +usb:v04DDp9032* + ID_MODEL_FROM_DATABASE=Zaurus SL-6000 + +usb:v04DDp903A* + ID_MODEL_FROM_DATABASE=GSM GPRS + +usb:v04DDp9050* + ID_MODEL_FROM_DATABASE=Zaurus C-860 PDA + +usb:v04DDp9056* + ID_MODEL_FROM_DATABASE=Viewcam Z + +usb:v04DDp9073* + ID_MODEL_FROM_DATABASE=AM-900 + +usb:v04DDp9074* + ID_MODEL_FROM_DATABASE=GSM GPRS + +usb:v04DDp90A9* + ID_MODEL_FROM_DATABASE=Sharp Composite + +usb:v04DDp90D0* + ID_MODEL_FROM_DATABASE=USB-to-Serial Comm. Port + +usb:v04DDp90F2* + ID_MODEL_FROM_DATABASE=Sharp 3G GSM USB Control + +usb:v04DDp9120* + ID_MODEL_FROM_DATABASE=WS004SH + +usb:v04DDp9122* + ID_MODEL_FROM_DATABASE=WS007SH + +usb:v04DDp9123* + ID_MODEL_FROM_DATABASE=W-ZERO3 ES Smartphone + +usb:v04DDp91A3* + ID_MODEL_FROM_DATABASE=922SH Internet Machine + +usb:v04DDp939A* + ID_MODEL_FROM_DATABASE=IS03 + +usb:v04DE* + ID_VENDOR_FROM_DATABASE=MindShare, Inc. + +usb:v04DF* + ID_VENDOR_FROM_DATABASE=Interlink Electronics + +usb:v04E1* + ID_VENDOR_FROM_DATABASE=Iiyama North America, Inc. + +usb:v04E1p0201* + ID_MODEL_FROM_DATABASE=Monitor Hub + +usb:v04E2* + ID_VENDOR_FROM_DATABASE=Exar Corp. + +usb:v04E2p1410* + ID_MODEL_FROM_DATABASE=XR21V1410 USB-UART IC + +usb:v04E3* + ID_VENDOR_FROM_DATABASE=Zilog, Inc. + +usb:v04E4* + ID_VENDOR_FROM_DATABASE=ACC Microelectronics + +usb:v04E5* + ID_VENDOR_FROM_DATABASE=Promise Technology + +usb:v04E6* + ID_VENDOR_FROM_DATABASE=SCM Microsystems, Inc. + +usb:v04E6p0001* + ID_MODEL_FROM_DATABASE=E-USB ATA Bridge + +usb:v04E6p0002* + ID_MODEL_FROM_DATABASE=eUSCSI SCSI Bridge + +usb:v04E6p0003* + ID_MODEL_FROM_DATABASE=eUSB SmartMedia Card Reader + +usb:v04E6p0005* + ID_MODEL_FROM_DATABASE=eUSB SmartMedia/CompactFlash Card Reader + +usb:v04E6p0006* + ID_MODEL_FROM_DATABASE=eUSB SmartMedia Card Reader + +usb:v04E6p0007* + ID_MODEL_FROM_DATABASE=Hifd + +usb:v04E6p0009* + ID_MODEL_FROM_DATABASE=eUSB ATA/ATAPI Adapter + +usb:v04E6p000A* + ID_MODEL_FROM_DATABASE=eUSB CompactFlash Adapter + +usb:v04E6p000B* + ID_MODEL_FROM_DATABASE=eUSCSI Bridge + +usb:v04E6p000C* + ID_MODEL_FROM_DATABASE=eUSCSI Bridge + +usb:v04E6p000D* + ID_MODEL_FROM_DATABASE=Dazzle MS + +usb:v04E6p0012* + ID_MODEL_FROM_DATABASE=Dazzle SD/MMC + +usb:v04E6p0101* + ID_MODEL_FROM_DATABASE=eUSB ATA Bridge (Sony Spressa USB CDRW) + +usb:v04E6p0311* + ID_MODEL_FROM_DATABASE=Dazzle DM-CF + +usb:v04E6p0312* + ID_MODEL_FROM_DATABASE=Dazzle DM-SD/MMC + +usb:v04E6p0313* + ID_MODEL_FROM_DATABASE=Dazzle SM + +usb:v04E6p0314* + ID_MODEL_FROM_DATABASE=Dazzle MS + +usb:v04E6p0322* + ID_MODEL_FROM_DATABASE=e-Film Reader-5 + +usb:v04E6p0325* + ID_MODEL_FROM_DATABASE=eUSB ORCA Quad Reader + +usb:v04E6p0327* + ID_MODEL_FROM_DATABASE=Digital Media Reader + +usb:v04E6p03FE* + ID_MODEL_FROM_DATABASE=DMHS2 DFU Adapter + +usb:v04E6p0406* + ID_MODEL_FROM_DATABASE=eUSB SmartDM Reader + +usb:v04E6p04E6* + ID_MODEL_FROM_DATABASE=eUSB DFU Adapter + +usb:v04E6p04E7* + ID_MODEL_FROM_DATABASE=STCII DFU Adapter + +usb:v04E6p04E8* + ID_MODEL_FROM_DATABASE=eUSBDM DFU Adapter + +usb:v04E6p04E9* + ID_MODEL_FROM_DATABASE=DM-E DFU Adapter + +usb:v04E6p0500* + ID_MODEL_FROM_DATABASE=Veridicom 5thSense Fingerprint Sensor and eUSB SmartCard + +usb:v04E6p0701* + ID_MODEL_FROM_DATABASE=DCS200 Loader Device + +usb:v04E6p0702* + ID_MODEL_FROM_DATABASE=DVD Creation Station 200 + +usb:v04E6p0703* + ID_MODEL_FROM_DATABASE=DVC100 Loader Device + +usb:v04E6p0704* + ID_MODEL_FROM_DATABASE=Digital Video Creator 100 + +usb:v04E6p1001* + ID_MODEL_FROM_DATABASE=SCR300 Smart Card Reader + +usb:v04E6p1010* + ID_MODEL_FROM_DATABASE=USBAT-2 CompactFlash Card Reader + +usb:v04E6p1014* + ID_MODEL_FROM_DATABASE=e-Film Reader-3 + +usb:v04E6p1020* + ID_MODEL_FROM_DATABASE=USBAT ATA/ATAPI Adapter + +usb:v04E6p2007* + ID_MODEL_FROM_DATABASE=RSA SecurID ComboReader + +usb:v04E6p2009* + ID_MODEL_FROM_DATABASE=Citibank Smart Card Reader + +usb:v04E6p200A* + ID_MODEL_FROM_DATABASE=Reflex v.2 Smart Card Reader + +usb:v04E6p200D* + ID_MODEL_FROM_DATABASE=STR391 Reader + +usb:v04E6p5111* + ID_MODEL_FROM_DATABASE=SCR331-DI SmartCard Reader + +usb:v04E6p5113* + ID_MODEL_FROM_DATABASE=SCR333 SmartCard Reader + +usb:v04E6p5114* + ID_MODEL_FROM_DATABASE=SCR331-DI SmartCard Reader + +usb:v04E6p5115* + ID_MODEL_FROM_DATABASE=SCR335 SmartCard Reader + +usb:v04E6p5116* + ID_MODEL_FROM_DATABASE=SCR331-LC1 / SCR3310 SmartCard Reader + +usb:v04E6p5117* + ID_MODEL_FROM_DATABASE=SCR3320 - Smart Card Reader + +usb:v04E6p5118* + ID_MODEL_FROM_DATABASE=Expresscard SIM Card Reader + +usb:v04E6p5119* + ID_MODEL_FROM_DATABASE=SCR3340 - ExpressCard54 Smart Card Reader + +usb:v04E6p511B* + ID_MODEL_FROM_DATABASE=SmartCard Reader + +usb:v04E6p511D* + ID_MODEL_FROM_DATABASE=SCR3311 Smart Card Reader + +usb:v04E6p5120* + ID_MODEL_FROM_DATABASE=SCR331-DI SmartCard Reader + +usb:v04E6p5121* + ID_MODEL_FROM_DATABASE=SDI010 Smart Card Reader + +usb:v04E6p5151* + ID_MODEL_FROM_DATABASE=SCR338 Keyboard Smart Card Reader + +usb:v04E6p5292* + ID_MODEL_FROM_DATABASE=SCL011 RFID reader + +usb:v04E6p5410* + ID_MODEL_FROM_DATABASE=SCR35xx Smart Card Reader + +usb:v04E6pE000* + ID_MODEL_FROM_DATABASE=SCRx31 Reader + +usb:v04E6pE001* + ID_MODEL_FROM_DATABASE=SCR331 SmartCard Reader + +usb:v04E6pE003* + ID_MODEL_FROM_DATABASE=SPR532 PinPad SmartCard Reader + +usb:v04E7* + ID_VENDOR_FROM_DATABASE=Elo TouchSystems + +usb:v04E7p0001* + ID_MODEL_FROM_DATABASE=TouchScreen + +usb:v04E7p0002* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface 2600 Rev 2 + +usb:v04E7p0004* + ID_MODEL_FROM_DATABASE=4000U CarrollTouch® Touchmonitor Interface + +usb:v04E7p0007* + ID_MODEL_FROM_DATABASE=2500U IntelliTouch® Touchmonitor Interface + +usb:v04E7p0008* + ID_MODEL_FROM_DATABASE=3000U AccuTouch® Touchmonitor Interface + +usb:v04E7p0009* + ID_MODEL_FROM_DATABASE=4000U CarrollTouch® Touchmonitor Interface + +usb:v04E7p0020* + ID_MODEL_FROM_DATABASE=Touchscreen Interface (2700) + +usb:v04E7p0021* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0030* + ID_MODEL_FROM_DATABASE=4500U CarrollTouch® Touchmonitor Interface + +usb:v04E7p0032* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0033* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0041* + ID_MODEL_FROM_DATABASE=5010 Surface Capacitive Touchmonitor Interface + +usb:v04E7p0042* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0050* + ID_MODEL_FROM_DATABASE=2216 AccuTouch® Touchmonitor Interface + +usb:v04E7p0071* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0072* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0081* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p0082* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E7p00FF* + ID_MODEL_FROM_DATABASE=Touchmonitor Interface + +usb:v04E8* + ID_VENDOR_FROM_DATABASE=Samsung Electronics Co., Ltd + +usb:v04E8p0100* + ID_MODEL_FROM_DATABASE=Kingston Flash Drive (128MB) + +usb:v04E8p0110* + ID_MODEL_FROM_DATABASE=Connect3D Flash Drive + +usb:v04E8p0111* + ID_MODEL_FROM_DATABASE=Connect3D Flash Drive + +usb:v04E8p0300* + ID_MODEL_FROM_DATABASE=E2530 / GT-C3350 Phones (Mass storage mode) + +usb:v04E8p1003* + ID_MODEL_FROM_DATABASE=MP3 Player and Recorder + +usb:v04E8p1006* + ID_MODEL_FROM_DATABASE=SDC-200Z + +usb:v04E8p130C* + ID_MODEL_FROM_DATABASE=NX100 + +usb:v04E8p1F06* + ID_MODEL_FROM_DATABASE=HX-MU064DA portable harddisk + +usb:v04E8p2018* + ID_MODEL_FROM_DATABASE=WIS09ABGN LinkStick Wireless LAN Adapter + +usb:v04E8p2035* + ID_MODEL_FROM_DATABASE=Digital Photo Frame Mass Storage + +usb:v04E8p2036* + ID_MODEL_FROM_DATABASE=Digital Photo Frame Mini Monitor + +usb:v04E8p3004* + ID_MODEL_FROM_DATABASE=ML-4600 + +usb:v04E8p3005* + ID_MODEL_FROM_DATABASE=Docuprint P1210 + +usb:v04E8p3008* + ID_MODEL_FROM_DATABASE=ML-6060 laser printer + +usb:v04E8p300C* + ID_MODEL_FROM_DATABASE=ML-1210 Printer + +usb:v04E8p300E* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3104* + ID_MODEL_FROM_DATABASE=ML-3550N + +usb:v04E8p3210* + ID_MODEL_FROM_DATABASE=ML-5200A Laser Printer + +usb:v04E8p3226* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3228* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p322A* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p322C* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3230* + ID_MODEL_FROM_DATABASE=ML-1440 + +usb:v04E8p3232* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3236* + ID_MODEL_FROM_DATABASE=ML-1450 + +usb:v04E8p3238* + ID_MODEL_FROM_DATABASE=ML-1430 + +usb:v04E8p323A* + ID_MODEL_FROM_DATABASE=ML-1710 Printer + +usb:v04E8p323B* + ID_MODEL_FROM_DATABASE=Phaser 3130 + +usb:v04E8p323C* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p323D* + ID_MODEL_FROM_DATABASE=Phaser 3120 + +usb:v04E8p323E* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3240* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p3242* + ID_MODEL_FROM_DATABASE=ML-1510 Laser Printer + +usb:v04E8p3248* + ID_MODEL_FROM_DATABASE=Color Laser Printer + +usb:v04E8p324A* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v04E8p324C* + ID_MODEL_FROM_DATABASE=ML-1740 Printer + +usb:v04E8p324D* + ID_MODEL_FROM_DATABASE=Phaser 3121 + +usb:v04E8p3256* + ID_MODEL_FROM_DATABASE=ML-1520 Laser Printer + +usb:v04E8p325B* + ID_MODEL_FROM_DATABASE=Xerox Phaser 3117 Laser Printer + +usb:v04E8p325F* + ID_MODEL_FROM_DATABASE=Phaser 3425 Laser Printer + +usb:v04E8p3260* + ID_MODEL_FROM_DATABASE=CLP-510 Color Laser Printer + +usb:v04E8p3268* + ID_MODEL_FROM_DATABASE=ML-1610 Mono Laser Printer + +usb:v04E8p326C* + ID_MODEL_FROM_DATABASE=ML-2010P Mono Laser Printer + +usb:v04E8p3276* + ID_MODEL_FROM_DATABASE=ML-3050/ML-3051 Laser Printer + +usb:v04E8p328E* + ID_MODEL_FROM_DATABASE=CLP-310 Color Laser Printer + +usb:v04E8p3292* + ID_MODEL_FROM_DATABASE=ML-1640 Series Laser Printer + +usb:v04E8p3296* + ID_MODEL_FROM_DATABASE=ML-2580N Mono Laser Printer + +usb:v04E8p3297* + ID_MODEL_FROM_DATABASE=ML-191x/ML-252x Laser Printer + +usb:v04E8p329F* + ID_MODEL_FROM_DATABASE=CLP-325 Color Laser Printer + +usb:v04E8p330C* + ID_MODEL_FROM_DATABASE=ML-1865 + +usb:v04E8p3310* + ID_MODEL_FROM_DATABASE=ML-331x Series Laser Printer + +usb:v04E8p3315* + ID_MODEL_FROM_DATABASE=ML-2540 Series Laser Printer + +usb:v04E8p3409* + ID_MODEL_FROM_DATABASE=SCX-4216F Scanner + +usb:v04E8p340C* + ID_MODEL_FROM_DATABASE=SCX-5x15 series + +usb:v04E8p340D* + ID_MODEL_FROM_DATABASE=SCX-6x20 series + +usb:v04E8p340E* + ID_MODEL_FROM_DATABASE=MFP 560 series + +usb:v04E8p340F* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v04E8p3412* + ID_MODEL_FROM_DATABASE=SCX-4x20 series + +usb:v04E8p3413* + ID_MODEL_FROM_DATABASE=SCX-4100 Scanner + +usb:v04E8p3415* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p3419* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p341A* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v04E8p341B* + ID_MODEL_FROM_DATABASE=SCX-4200 series + +usb:v04E8p341C* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p341D* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p341F* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p3420* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04E8p3426* + ID_MODEL_FROM_DATABASE=SCX-4500 Laser Printer + +usb:v04E8p344F* + ID_MODEL_FROM_DATABASE=SCX-3400 Series + +usb:v04E8p3605* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v04E8p3606* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v04E8p3609* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v04E8p3902* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v04E8p3903* + ID_MODEL_FROM_DATABASE=Xerox WorkCentre XK50cx + +usb:v04E8p390F* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v04E8p3911* + ID_MODEL_FROM_DATABASE=SCX-1020 series + +usb:v04E8p4005* + ID_MODEL_FROM_DATABASE=GT-S8000 Jet (msc) + +usb:v04E8p4F1F* + ID_MODEL_FROM_DATABASE=GT-S8000 Jet (mtp) + +usb:v04E8p5000* + ID_MODEL_FROM_DATABASE=YP-MF series + +usb:v04E8p5001* + ID_MODEL_FROM_DATABASE=YP-100 + +usb:v04E8p5002* + ID_MODEL_FROM_DATABASE=YP-30 + +usb:v04E8p5003* + ID_MODEL_FROM_DATABASE=YP-700 + +usb:v04E8p5004* + ID_MODEL_FROM_DATABASE=YP-30 + +usb:v04E8p5005* + ID_MODEL_FROM_DATABASE=YP-300 + +usb:v04E8p5006* + ID_MODEL_FROM_DATABASE=YP-750 + +usb:v04E8p500D* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v04E8p5010* + ID_MODEL_FROM_DATABASE=Yepp YP-35 + +usb:v04E8p5011* + ID_MODEL_FROM_DATABASE=YP-780 + +usb:v04E8p5013* + ID_MODEL_FROM_DATABASE=YP-60 + +usb:v04E8p5015* + ID_MODEL_FROM_DATABASE=yepp upgrade + +usb:v04E8p501B* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v04E8p5021* + ID_MODEL_FROM_DATABASE=Yepp YP-ST5 + +usb:v04E8p5026* + ID_MODEL_FROM_DATABASE=YP-MT6V + +usb:v04E8p5027* + ID_MODEL_FROM_DATABASE=YP-T7 + +usb:v04E8p502B* + ID_MODEL_FROM_DATABASE=YP-F1 + +usb:v04E8p5032* + ID_MODEL_FROM_DATABASE=YP-J70 + +usb:v04E8p503B* + ID_MODEL_FROM_DATABASE=YP-U1 MP3 Player + +usb:v04E8p503D* + ID_MODEL_FROM_DATABASE=YP-T7F + +usb:v04E8p5041* + ID_MODEL_FROM_DATABASE=YP-Z5 + +usb:v04E8p5050* + ID_MODEL_FROM_DATABASE=YP-U2 MP3 Player + +usb:v04E8p5051* + ID_MODEL_FROM_DATABASE=YP-F2R + +usb:v04E8p5055* + ID_MODEL_FROM_DATABASE=YP-T9 + +usb:v04E8p507D* + ID_MODEL_FROM_DATABASE=YP-U3 (mtp) + +usb:v04E8p507F* + ID_MODEL_FROM_DATABASE=YP-T9J + +usb:v04E8p5080* + ID_MODEL_FROM_DATABASE=Yepp YP-K3 (msc) + +usb:v04E8p5081* + ID_MODEL_FROM_DATABASE=Yepp YP-K3 (mtp) + +usb:v04E8p5082* + ID_MODEL_FROM_DATABASE=YP-P2 (msc) + +usb:v04E8p5083* + ID_MODEL_FROM_DATABASE=YP-P2 (mtp) + +usb:v04E8p508A* + ID_MODEL_FROM_DATABASE=YP-T10 + +usb:v04E8p508B* + ID_MODEL_FROM_DATABASE=YP-S5 MP3 Player + +usb:v04E8p508C* + ID_MODEL_FROM_DATABASE=YP-S5 + +usb:v04E8p5090* + ID_MODEL_FROM_DATABASE=YP-S3 (msc) + +usb:v04E8p5091* + ID_MODEL_FROM_DATABASE=YP-S3 (mtp) + +usb:v04E8p5092* + ID_MODEL_FROM_DATABASE=YP-U4 (msc) + +usb:v04E8p5093* + ID_MODEL_FROM_DATABASE=YP-U4 (mtp) + +usb:v04E8p5095* + ID_MODEL_FROM_DATABASE=YP-S2 + +usb:v04E8p510F* + ID_MODEL_FROM_DATABASE=YP-R1 + +usb:v04E8p5119* + ID_MODEL_FROM_DATABASE=Yepp YP-P3 + +usb:v04E8p511C* + ID_MODEL_FROM_DATABASE=YP-Q2 + +usb:v04E8p5121* + ID_MODEL_FROM_DATABASE=YP-U5 + +usb:v04E8p5123* + ID_MODEL_FROM_DATABASE=Yepp YP-M1 + +usb:v04E8p5A00* + ID_MODEL_FROM_DATABASE=YP-NEU + +usb:v04E8p5A01* + ID_MODEL_FROM_DATABASE=YP-NDU + +usb:v04E8p5A03* + ID_MODEL_FROM_DATABASE=Yepp MP3 Player + +usb:v04E8p5A04* + ID_MODEL_FROM_DATABASE=YP-800 + +usb:v04E8p5A08* + ID_MODEL_FROM_DATABASE=YP-90 + +usb:v04E8p5A0F* + ID_MODEL_FROM_DATABASE=Meizu M6 MiniPlayer + +usb:v04E8p5B01* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v04E8p5B02* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v04E8p5B03* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v04E8p5B04* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v04E8p5B05* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v04E8p5B11* + ID_MODEL_FROM_DATABASE=SEW-2001u Card + +usb:v04E8p5F00* + ID_MODEL_FROM_DATABASE=NEXiO Sync + +usb:v04E8p5F01* + ID_MODEL_FROM_DATABASE=NEXiO Sync + +usb:v04E8p5F02* + ID_MODEL_FROM_DATABASE=NEXiO Sync + +usb:v04E8p5F03* + ID_MODEL_FROM_DATABASE=NEXiO Sync + +usb:v04E8p5F04* + ID_MODEL_FROM_DATABASE=NEXiO Sync + +usb:v04E8p5F05* + ID_MODEL_FROM_DATABASE=STORY Station 1TB + +usb:v04E8p6032* + ID_MODEL_FROM_DATABASE=G2 Portable hard drive + +usb:v04E8p6034* + ID_MODEL_FROM_DATABASE=G2 Portable hard drive + +usb:v04E8p60B3* + ID_MODEL_FROM_DATABASE=M2 Portable Hard Drive + +usb:v04E8p60C4* + ID_MODEL_FROM_DATABASE=M2 Portable Hard Drive USB 3.0 + +usb:v04E8p61B6* + ID_MODEL_FROM_DATABASE=M3 Portable Hard Drive 1TB + +usb:v04E8p6601* + ID_MODEL_FROM_DATABASE=Mobile Phone + +usb:v04E8p6602* + ID_MODEL_FROM_DATABASE=Galaxy + +usb:v04E8p6603* + ID_MODEL_FROM_DATABASE=Galaxy + +usb:v04E8p6611* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6613* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6615* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6617* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6619* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p661B* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p661E* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v04E8p6620* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v04E8p6622* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v04E8p6624* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v04E8p662E* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6630* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p6632* + ID_MODEL_FROM_DATABASE=MITs Sync + +usb:v04E8p663E* + ID_MODEL_FROM_DATABASE=D900e Phone + +usb:v04E8p663F* + ID_MODEL_FROM_DATABASE=SGH-E720/SGH-E840 + +usb:v04E8p6640* + ID_MODEL_FROM_DATABASE=Usb Modem Enumerator + +usb:v04E8p6651* + ID_MODEL_FROM_DATABASE=i8510 Innov8 + +usb:v04E8p6702* + ID_MODEL_FROM_DATABASE=X830 + +usb:v04E8p6708* + ID_MODEL_FROM_DATABASE=U600 Phone + +usb:v04E8p6709* + ID_MODEL_FROM_DATABASE=U600 + +usb:v04E8p6734* + ID_MODEL_FROM_DATABASE=Juke + +usb:v04E8p6759* + ID_MODEL_FROM_DATABASE=D900e Media Player + +usb:v04E8p675A* + ID_MODEL_FROM_DATABASE=D900e Mass Storage + +usb:v04E8p675B* + ID_MODEL_FROM_DATABASE=D900e Camera + +usb:v04E8p6772* + ID_MODEL_FROM_DATABASE=Standalone LTE device (Trial) + +usb:v04E8p6795* + ID_MODEL_FROM_DATABASE=S5230 + +usb:v04E8p6802* + ID_MODEL_FROM_DATABASE=Standalone HSPA device + +usb:v04E8p6806* + ID_MODEL_FROM_DATABASE=Composite LTE device (Trial) + +usb:v04E8p6807* + ID_MODEL_FROM_DATABASE=Composite HSPA device + +usb:v04E8p681C* + ID_MODEL_FROM_DATABASE=Galaxy Portal/Spica/S + +usb:v04E8p681D* + ID_MODEL_FROM_DATABASE=Galaxy Portal/Spica Android Phone + +usb:v04E8p6843* + ID_MODEL_FROM_DATABASE=E2530 Phone (Samsung Kies mode) + +usb:v04E8p684E* + ID_MODEL_FROM_DATABASE=Wave (GT-S8500) + +usb:v04E8p685B* + ID_MODEL_FROM_DATABASE=GT-I9100 Phone [Galaxy S II] (mass storage mode) + +usb:v04E8p685C* + ID_MODEL_FROM_DATABASE=GT-I9250 Phone [Galaxy Nexus] + +usb:v04E8p685D* + ID_MODEL_FROM_DATABASE=GT-I9100 Phone [Galaxy S II] (Download mode) + +usb:v04E8p685E* + ID_MODEL_FROM_DATABASE=GT-I9100 / GT-C3350 Phones (USB Debugging mode) + +usb:v04E8p6860* + ID_MODEL_FROM_DATABASE=GT-I9100 Phone [Galaxy S II], GT-I9300 Phone [Galaxy S III], GT-P7500 [Galaxy Tab 10.1] + +usb:v04E8p6865* + ID_MODEL_FROM_DATABASE=GT-I9300 Phone [Galaxy S III] (PTP mode) + +usb:v04E8p6866* + ID_MODEL_FROM_DATABASE=GT-I9300 Phone [Galaxy S III] (debugging mode) + +usb:v04E8p6875* + ID_MODEL_FROM_DATABASE=GT-B3710 Standalone LTE device (Commercial) + +usb:v04E8p6876* + ID_MODEL_FROM_DATABASE=GT-B3710 LTE Modem + +usb:v04E8p6877* + ID_MODEL_FROM_DATABASE=Galaxy S + +usb:v04E8p6888* + ID_MODEL_FROM_DATABASE=GT-B3730 Composite LTE device (Commercial) + +usb:v04E8p6889* + ID_MODEL_FROM_DATABASE=GT-B3730 Composite LTE device (Commercial) + +usb:v04E8p689A* + ID_MODEL_FROM_DATABASE=LTE Storage Driver [CMC2xx] + +usb:v04E8p689E* + ID_MODEL_FROM_DATABASE=GT-S5670 [Galaxy Fit] + +usb:v04E8p68AA* + ID_MODEL_FROM_DATABASE=Reality + +usb:v04E8p7011* + ID_MODEL_FROM_DATABASE=SEW-2003U Card + +usb:v04E8p7021* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v04E8p7061* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v04E8p7080* + ID_MODEL_FROM_DATABASE=Anycall SCH-W580 + +usb:v04E8p7081* + ID_MODEL_FROM_DATABASE=Human Interface Device + +usb:v04E8p8001* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v04E8pE020* + ID_MODEL_FROM_DATABASE=SERI E02 SCOM 6200 UMTS Phone + +usb:v04E8pE021* + ID_MODEL_FROM_DATABASE=SERI E02 SCOM 6200 Virtual UARTs + +usb:v04E8pE022* + ID_MODEL_FROM_DATABASE=SERI E02 SCOM 6200 Flash Load Disk + +usb:v04E8pF000* + ID_MODEL_FROM_DATABASE=Intensity 3 (Mass Storage Mode) + +usb:v04E8pFF30* + ID_MODEL_FROM_DATABASE=SG_iMON + +usb:v04E9* + ID_VENDOR_FROM_DATABASE=PC-Tel, Inc. + +usb:v04EA* + ID_VENDOR_FROM_DATABASE=Brooktree Corp. + +usb:v04EB* + ID_VENDOR_FROM_DATABASE=Northstar Systems, Inc. + +usb:v04EBpE004* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v04EC* + ID_VENDOR_FROM_DATABASE=Tokyo Electron Device, Ltd + +usb:v04ED* + ID_VENDOR_FROM_DATABASE=Annabooks + +usb:v04EF* + ID_VENDOR_FROM_DATABASE=Pacific Electronic International, Inc. + +usb:v04F0* + ID_VENDOR_FROM_DATABASE=Daewoo Electronics Co., Ltd + +usb:v04F1* + ID_VENDOR_FROM_DATABASE=Victor Company of Japan, Ltd + +usb:v04F1p0001* + ID_MODEL_FROM_DATABASE=GC-QX3 Digital Still Camera + +usb:v04F1p0004* + ID_MODEL_FROM_DATABASE=GR-DVL815U Digital Video Camera + +usb:v04F1p0006* + ID_MODEL_FROM_DATABASE=DV Camera Storage + +usb:v04F1p0008* + ID_MODEL_FROM_DATABASE=GZ-MG30AA/MC500E Digital Video Camera + +usb:v04F1p0009* + ID_MODEL_FROM_DATABASE=GR-DX25EK Digital Video Camera + +usb:v04F1p000A* + ID_MODEL_FROM_DATABASE=GR-D72 Digital Video Camera + +usb:v04F1p1001* + ID_MODEL_FROM_DATABASE=GC-A50 Camera Device + +usb:v04F1p3008* + ID_MODEL_FROM_DATABASE=MP-PRX1 Ethernet + +usb:v04F1p3009* + ID_MODEL_FROM_DATABASE=MP-XP7250 WLAN Adapter + +usb:v04F2* + ID_VENDOR_FROM_DATABASE=Chicony Electronics Co., Ltd + +usb:v04F2p0001* + ID_MODEL_FROM_DATABASE=KU-8933 Keyboard + +usb:v04F2p0002* + ID_MODEL_FROM_DATABASE=NT68P81 Keyboard + +usb:v04F2p0110* + ID_MODEL_FROM_DATABASE=KU-2971 Keyboard + +usb:v04F2p0111* + ID_MODEL_FROM_DATABASE=KU-9908 Keyboard + +usb:v04F2p0112* + ID_MODEL_FROM_DATABASE=KU-8933 Keyboard with PS/2 Mouse port + +usb:v04F2p0116* + ID_MODEL_FROM_DATABASE=KU-2971/KU-0325 Keyboard + +usb:v04F2p0200* + ID_MODEL_FROM_DATABASE=KBR-0108 + +usb:v04F2p0201* + ID_MODEL_FROM_DATABASE=Gaming Keyboard KPD0250 + +usb:v04F2p0220* + ID_MODEL_FROM_DATABASE=Wireless HID Receiver + +usb:v04F2p0402* + ID_MODEL_FROM_DATABASE=Genius LuxeMate i200 Keyboard + +usb:v04F2p0403* + ID_MODEL_FROM_DATABASE=KU-0420 keyboard + +usb:v04F2p0418* + ID_MODEL_FROM_DATABASE=KU-0418 Tactical Pad + +usb:v04F2p0760* + ID_MODEL_FROM_DATABASE=Acer KU-0760 Keyboard + +usb:v04F2p0841* + ID_MODEL_FROM_DATABASE=HP Multimedia Keyboard + +usb:v04F2p0860* + ID_MODEL_FROM_DATABASE=2.4G Multimedia Wireless Kit + +usb:v04F2pA001* + ID_MODEL_FROM_DATABASE=E-Video DC-100 Camera + +usb:v04F2pA120* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam(PC370R) + +usb:v04F2pA121* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam(PC370R) + +usb:v04F2pA122* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam(PC370R) + +usb:v04F2pA123* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam(PC370R) + +usb:v04F2pA124* + ID_MODEL_FROM_DATABASE=ORITE CCD Webcam(PC370R) + +usb:v04F2pA128* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C202 + OV7663 + EEPROM) + +usb:v04F2pA133* + ID_MODEL_FROM_DATABASE=Gateway Webcam + +usb:v04F2pA136* + ID_MODEL_FROM_DATABASE=LabTec Webcam 5500 + +usb:v04F2pA204* + ID_MODEL_FROM_DATABASE=DSC WIA Device (1300) + +usb:v04F2pA208* + ID_MODEL_FROM_DATABASE=DSC WIA Device (2320) + +usb:v04F2pA209* + ID_MODEL_FROM_DATABASE=Labtec DC-2320 + +usb:v04F2pA20A* + ID_MODEL_FROM_DATABASE=DSC WIA Device (3310) + +usb:v04F2pA20C* + ID_MODEL_FROM_DATABASE=DSC WIA Device (3320) + +usb:v04F2pA210* + ID_MODEL_FROM_DATABASE=Audio Device + +usb:v04F2pB008* + ID_MODEL_FROM_DATABASE=USB 2.0 Camera + +usb:v04F2pB009* + ID_MODEL_FROM_DATABASE=Integrated Camera + +usb:v04F2pB010* + ID_MODEL_FROM_DATABASE=Integrated Camera + +usb:v04F2pB012* + ID_MODEL_FROM_DATABASE=1.3 MPixel UVC Webcam + +usb:v04F2pB013* + ID_MODEL_FROM_DATABASE=USB 2.0 Camera + +usb:v04F2pB015* + ID_MODEL_FROM_DATABASE=VGA 24fps UVC Webcam + +usb:v04F2pB016* + ID_MODEL_FROM_DATABASE=VGA 30fps UVC Webcam + +usb:v04F2pB018* + ID_MODEL_FROM_DATABASE=2M UVC Webcam + +usb:v04F2pB021* + ID_MODEL_FROM_DATABASE=ViewSonic 1.3M, USB2.0 Webcam + +usb:v04F2pB022* + ID_MODEL_FROM_DATABASE=Gateway USB 2.0 Webcam + +usb:v04F2pB023* + ID_MODEL_FROM_DATABASE=Gateway USB 2.0 Webcam + +usb:v04F2pB024* + ID_MODEL_FROM_DATABASE=USB 2.0 Webcam + +usb:v04F2pB025* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04F2pB027* + ID_MODEL_FROM_DATABASE=Gateway USB 2.0 Webcam + +usb:v04F2pB028* + ID_MODEL_FROM_DATABASE=VGA UVC Webcam + +usb:v04F2pB029* + ID_MODEL_FROM_DATABASE=1.3M UVC Webcam + +usb:v04F2pB036* + ID_MODEL_FROM_DATABASE=Asus Integrated 0.3M UVC Webcam + +usb:v04F2pB044* + ID_MODEL_FROM_DATABASE=Acer CrystalEye Webcam + +usb:v04F2pB057* + ID_MODEL_FROM_DATABASE=integrated USB webcam + +usb:v04F2pB059* + ID_MODEL_FROM_DATABASE=CKF7037 HP webcam + +usb:v04F2pB071* + ID_MODEL_FROM_DATABASE=2.0M UVC Webcam / CNF7129 + +usb:v04F2pB083* + ID_MODEL_FROM_DATABASE=CKF7063 Webcam (HP) + +usb:v04F2pB091* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v04F2pB104* + ID_MODEL_FROM_DATABASE=CNF7069 Webcam + +usb:v04F2pB107* + ID_MODEL_FROM_DATABASE=CNF7070 Webcam + +usb:v04F2pB14C* + ID_MODEL_FROM_DATABASE=CNF8050 Webcam + +usb:v04F2pB15C* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Camera + +usb:v04F2pB175* + ID_MODEL_FROM_DATABASE=4-Port Hub + +usb:v04F2pB1AA* + ID_MODEL_FROM_DATABASE=Webcam-101 + +usb:v04F2pB1B4* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Camera + +usb:v04F2pB1B9* + ID_MODEL_FROM_DATABASE=Asus Integrated Webcam + +usb:v04F2pB1CF* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Camera + +usb:v04F2pB1D6* + ID_MODEL_FROM_DATABASE=CNF9055 Toshiba Webcam + +usb:v04F2pB1E4* + ID_MODEL_FROM_DATABASE=Toshiba Integrated Webcam + +usb:v04F2pB213* + ID_MODEL_FROM_DATABASE=Fujitsu Integrated Camera + +usb:v04F2pB217* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Camera (0.3MP) + +usb:v04F2pB221* + ID_MODEL_FROM_DATABASE=integrated camera + +usb:v04F2pB230* + ID_MODEL_FROM_DATABASE=Integrated HP HD Webcam + +usb:v04F2pB257* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Camera + +usb:v04F2pB26B* + ID_MODEL_FROM_DATABASE=Sony Visual Communication Camera + +usb:v04F2pB272* + ID_MODEL_FROM_DATABASE=Lenovo EasyCamera + +usb:v04F2pB2B0* + ID_MODEL_FROM_DATABASE=Camera + +usb:v04F2pB2B9* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Camera UVC + +usb:v04F2pB2EA* + ID_MODEL_FROM_DATABASE=Integrated Camera [ThinkPad] + +usb:v04F2pB330* + ID_MODEL_FROM_DATABASE=Asus 720p CMOS webcam + +usb:v04F2pB354* + ID_MODEL_FROM_DATABASE=UVC 1.00 device HD UVC WebCam + +usb:v04F3* + ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp. + +usb:v04F3p000A* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v04F3p0103* + ID_MODEL_FROM_DATABASE=ActiveJet K-2024 Multimedia Keyboard + +usb:v04F3p01A4* + ID_MODEL_FROM_DATABASE=Wireless Keyboard + +usb:v04F3p0210* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v04F3p0212* + ID_MODEL_FROM_DATABASE=Laser Mouse + +usb:v04F3p0214* + ID_MODEL_FROM_DATABASE=Lynx M9 Optical Mouse + +usb:v04F3p0230* + ID_MODEL_FROM_DATABASE=3D Optical Mouse + +usb:v04F3p0232* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v04F3p02F4* + ID_MODEL_FROM_DATABASE=2.4G Cordless Mouse + +usb:v04F3p04A0* + ID_MODEL_FROM_DATABASE=Dream Cheeky Stress/Panic Button + +usb:v04F4* + ID_VENDOR_FROM_DATABASE=Harting Elektronik, Inc. + +usb:v04F5* + ID_VENDOR_FROM_DATABASE=Fujitsu-ICL Systems, Inc. + +usb:v04F6* + ID_VENDOR_FROM_DATABASE=Norand Corp. + +usb:v04F7* + ID_VENDOR_FROM_DATABASE=Newnex Technology Corp. + +usb:v04F8* + ID_VENDOR_FROM_DATABASE=FuturePlus Systems + +usb:v04F9* + ID_VENDOR_FROM_DATABASE=Brother Industries, Ltd + +usb:v04F9p0002* + ID_MODEL_FROM_DATABASE=HL-1050 Laser Printer + +usb:v04F9p0005* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0006* + ID_MODEL_FROM_DATABASE=HL-1240 Laser Printer + +usb:v04F9p0007* + ID_MODEL_FROM_DATABASE=HL-1250 Laser Printer + +usb:v04F9p0008* + ID_MODEL_FROM_DATABASE=HL-1270 Laser Printer + +usb:v04F9p0009* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p000A* + ID_MODEL_FROM_DATABASE=P2500 series + +usb:v04F9p000B* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p000C* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p000D* + ID_MODEL_FROM_DATABASE=HL-1440 Laser Printer + +usb:v04F9p000E* + ID_MODEL_FROM_DATABASE=HL-1450 series + +usb:v04F9p000F* + ID_MODEL_FROM_DATABASE=HL-1470N series + +usb:v04F9p0010* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0011* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0012* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0013* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0014* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0015* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0016* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0017* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0018* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p001A* + ID_MODEL_FROM_DATABASE=HL-1430 Laser Printer + +usb:v04F9p001C* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p001E* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0020* + ID_MODEL_FROM_DATABASE=HL-5130 series + +usb:v04F9p0021* + ID_MODEL_FROM_DATABASE=HL-5140 series + +usb:v04F9p0022* + ID_MODEL_FROM_DATABASE=HL-5150D series + +usb:v04F9p0023* + ID_MODEL_FROM_DATABASE=HL-5170DN series + +usb:v04F9p0024* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0025* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0027* + ID_MODEL_FROM_DATABASE=HL-2030 Laser Printer + +usb:v04F9p0028* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0029* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p002A* + ID_MODEL_FROM_DATABASE=HL-52x0 series + +usb:v04F9p002B* + ID_MODEL_FROM_DATABASE=HL-5250DN Printer + +usb:v04F9p002C* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p002D* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p0039* + ID_MODEL_FROM_DATABASE=HL-5340 series + +usb:v04F9p0042* + ID_MODEL_FROM_DATABASE=HL-2270DW Laser Printer + +usb:v04F9p0100* + ID_MODEL_FROM_DATABASE=MFC8600/9650 series + +usb:v04F9p0101* + ID_MODEL_FROM_DATABASE=MFC9600/9870 series + +usb:v04F9p0102* + ID_MODEL_FROM_DATABASE=MFC9750/1200 series + +usb:v04F9p0104* + ID_MODEL_FROM_DATABASE=MFC-8300J + +usb:v04F9p0105* + ID_MODEL_FROM_DATABASE=MFC-9600J + +usb:v04F9p0106* + ID_MODEL_FROM_DATABASE=MFC-7300C + +usb:v04F9p0107* + ID_MODEL_FROM_DATABASE=MFC-7400C + +usb:v04F9p0108* + ID_MODEL_FROM_DATABASE=MFC-9200C + +usb:v04F9p0109* + ID_MODEL_FROM_DATABASE=MFC-830 + +usb:v04F9p010A* + ID_MODEL_FROM_DATABASE=MFC-840 + +usb:v04F9p010B* + ID_MODEL_FROM_DATABASE=MFC-860 + +usb:v04F9p010C* + ID_MODEL_FROM_DATABASE=MFC-7400J + +usb:v04F9p010D* + ID_MODEL_FROM_DATABASE=MFC-9200J + +usb:v04F9p010E* + ID_MODEL_FROM_DATABASE=MFC3100C Scanner + +usb:v04F9p010F* + ID_MODEL_FROM_DATABASE=MFC 5100C + +usb:v04F9p0110* + ID_MODEL_FROM_DATABASE=MFC4800 Scanner + +usb:v04F9p0111* + ID_MODEL_FROM_DATABASE=MFC 6800 + +usb:v04F9p0112* + ID_MODEL_FROM_DATABASE=DCP1000 Port(FaxModem) + +usb:v04F9p0113* + ID_MODEL_FROM_DATABASE=MFC-8500 + +usb:v04F9p0114* + ID_MODEL_FROM_DATABASE=MFC9700 Port(FaxModem) + +usb:v04F9p0115* + ID_MODEL_FROM_DATABASE=MFC9800 Scanner + +usb:v04F9p0116* + ID_MODEL_FROM_DATABASE=DCP1400 Scanner + +usb:v04F9p0119* + ID_MODEL_FROM_DATABASE=MFC-9660 + +usb:v04F9p011B* + ID_MODEL_FROM_DATABASE=MFC-9880 + +usb:v04F9p011C* + ID_MODEL_FROM_DATABASE=MFC-9760 + +usb:v04F9p011D* + ID_MODEL_FROM_DATABASE=MFC-9070 + +usb:v04F9p011E* + ID_MODEL_FROM_DATABASE=MFC-9180 + +usb:v04F9p011F* + ID_MODEL_FROM_DATABASE=MFC-9160 + +usb:v04F9p0120* + ID_MODEL_FROM_DATABASE=MFC580 Port(FaxModem) + +usb:v04F9p0121* + ID_MODEL_FROM_DATABASE=MFC-590 + +usb:v04F9p0122* + ID_MODEL_FROM_DATABASE=MFC-5100J + +usb:v04F9p0129* + ID_MODEL_FROM_DATABASE=Imagistics 2500 (MFC-8640D clone) + +usb:v04F9p012F* + ID_MODEL_FROM_DATABASE=FAX-4750e + +usb:v04F9p0132* + ID_MODEL_FROM_DATABASE=MFC-5200C RemovableDisk + +usb:v04F9p0135* + ID_MODEL_FROM_DATABASE=MFC-100 Scanner + +usb:v04F9p0136* + ID_MODEL_FROM_DATABASE=MFC-150CL Scanner + +usb:v04F9p013C* + ID_MODEL_FROM_DATABASE=MFC-890 Port + +usb:v04F9p013D* + ID_MODEL_FROM_DATABASE=MFC-5200J Printer + +usb:v04F9p013E* + ID_MODEL_FROM_DATABASE=MFC-4420C RemovableDisk + +usb:v04F9p013F* + ID_MODEL_FROM_DATABASE=MFC-4820C RemovableDisk + +usb:v04F9p0140* + ID_MODEL_FROM_DATABASE=DCP-8020 + +usb:v04F9p0141* + ID_MODEL_FROM_DATABASE=DCP-8025D + +usb:v04F9p0142* + ID_MODEL_FROM_DATABASE=MFC-8420 + +usb:v04F9p0143* + ID_MODEL_FROM_DATABASE=MFC-8820D + +usb:v04F9p0144* + ID_MODEL_FROM_DATABASE=DCP-4020C RemovableDisk + +usb:v04F9p0146* + ID_MODEL_FROM_DATABASE=MFC-3220C + +usb:v04F9p0147* + ID_MODEL_FROM_DATABASE=FAX-1820C Printer + +usb:v04F9p0148* + ID_MODEL_FROM_DATABASE=MFC-3320CN Printer + +usb:v04F9p0149* + ID_MODEL_FROM_DATABASE=FAX-1920CN Printer + +usb:v04F9p014A* + ID_MODEL_FROM_DATABASE=MFC-3420C + +usb:v04F9p014B* + ID_MODEL_FROM_DATABASE=MFC-3820CN + +usb:v04F9p014D* + ID_MODEL_FROM_DATABASE=FAX-1815C Printer + +usb:v04F9p014E* + ID_MODEL_FROM_DATABASE=MFC-8820J + +usb:v04F9p0150* + ID_MODEL_FROM_DATABASE=MFC-8220 Port(FaxModem) + +usb:v04F9p0151* + ID_MODEL_FROM_DATABASE=MFC-8210J + +usb:v04F9p0157* + ID_MODEL_FROM_DATABASE=MFC-3420J Printer + +usb:v04F9p0158* + ID_MODEL_FROM_DATABASE=MFC-3820JN Port(FaxModem) + +usb:v04F9p015D* + ID_MODEL_FROM_DATABASE=MFC Composite Device + +usb:v04F9p015E* + ID_MODEL_FROM_DATABASE=DCP-8045D + +usb:v04F9p015F* + ID_MODEL_FROM_DATABASE=MFC-8440 + +usb:v04F9p0160* + ID_MODEL_FROM_DATABASE=MFC-8840D + +usb:v04F9p0161* + ID_MODEL_FROM_DATABASE=MFC-210C + +usb:v04F9p0162* + ID_MODEL_FROM_DATABASE=MFC-420CN Remote Setup Port + +usb:v04F9p0163* + ID_MODEL_FROM_DATABASE=MFC-410CN RemovableDisk + +usb:v04F9p0165* + ID_MODEL_FROM_DATABASE=MFC-620CN + +usb:v04F9p0166* + ID_MODEL_FROM_DATABASE=MFC-610CLN RemovableDisk + +usb:v04F9p0168* + ID_MODEL_FROM_DATABASE=MFC-620CLN + +usb:v04F9p0169* + ID_MODEL_FROM_DATABASE=DCP-110C RemovableDisk + +usb:v04F9p016B* + ID_MODEL_FROM_DATABASE=DCP-310CN RemovableDisk + +usb:v04F9p016C* + ID_MODEL_FROM_DATABASE=FAX-2440C Printer + +usb:v04F9p016D* + ID_MODEL_FROM_DATABASE=MFC-5440CN + +usb:v04F9p016E* + ID_MODEL_FROM_DATABASE=MFC-5840CN Remote Setup Port + +usb:v04F9p0170* + ID_MODEL_FROM_DATABASE=FAX-1840C Printer + +usb:v04F9p0171* + ID_MODEL_FROM_DATABASE=FAX-1835C Printer + +usb:v04F9p0172* + ID_MODEL_FROM_DATABASE=FAX-1940CN Printer + +usb:v04F9p0173* + ID_MODEL_FROM_DATABASE=MFC-3240C Remote Setup Port + +usb:v04F9p0174* + ID_MODEL_FROM_DATABASE=MFC-3340CN RemovableDisk + +usb:v04F9p017B* + ID_MODEL_FROM_DATABASE=Imagistics sx2100 + +usb:v04F9p0180* + ID_MODEL_FROM_DATABASE=MFC-7420 + +usb:v04F9p0181* + ID_MODEL_FROM_DATABASE=MFC-7820N Port(FaxModem) + +usb:v04F9p0182* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04F9p0183* + ID_MODEL_FROM_DATABASE=DCP-7020 + +usb:v04F9p0184* + ID_MODEL_FROM_DATABASE=DCP-7025 Printer + +usb:v04F9p0185* + ID_MODEL_FROM_DATABASE=MFC-7220 Printer + +usb:v04F9p0186* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04F9p0187* + ID_MODEL_FROM_DATABASE=FAX-2820 Printer + +usb:v04F9p0188* + ID_MODEL_FROM_DATABASE=FAX-2920 Printer + +usb:v04F9p018A* + ID_MODEL_FROM_DATABASE=MFC-9420CN + +usb:v04F9p018C* + ID_MODEL_FROM_DATABASE=DCP-115C + +usb:v04F9p018D* + ID_MODEL_FROM_DATABASE=DCP-116C + +usb:v04F9p018E* + ID_MODEL_FROM_DATABASE=DCP-117C + +usb:v04F9p018F* + ID_MODEL_FROM_DATABASE=DCP-118C + +usb:v04F9p0190* + ID_MODEL_FROM_DATABASE=DCP-120C + +usb:v04F9p0191* + ID_MODEL_FROM_DATABASE=DCP-315CN + +usb:v04F9p0192* + ID_MODEL_FROM_DATABASE=DCP-340CW + +usb:v04F9p0193* + ID_MODEL_FROM_DATABASE=MFC-215C + +usb:v04F9p0194* + ID_MODEL_FROM_DATABASE=MFC-425CN + +usb:v04F9p0195* + ID_MODEL_FROM_DATABASE=MFC-820CW Remote Setup Port + +usb:v04F9p0196* + ID_MODEL_FROM_DATABASE=MFC-820CN Remote Setup Port + +usb:v04F9p0197* + ID_MODEL_FROM_DATABASE=MFC-640CW + +usb:v04F9p019A* + ID_MODEL_FROM_DATABASE=MFC-840CLN Remote Setup Port + +usb:v04F9p01A2* + ID_MODEL_FROM_DATABASE=MFC-8640D + +usb:v04F9p01A3* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v04F9p01A4* + ID_MODEL_FROM_DATABASE=DCP-8065DN Printer + +usb:v04F9p01A5* + ID_MODEL_FROM_DATABASE=MFC-8460N Port(FaxModem) + +usb:v04F9p01A6* + ID_MODEL_FROM_DATABASE=MFC-8860DN Port(FaxModem) + +usb:v04F9p01A7* + ID_MODEL_FROM_DATABASE=MFC-8870DW Printer + +usb:v04F9p01A8* + ID_MODEL_FROM_DATABASE=DCP-130C + +usb:v04F9p01A9* + ID_MODEL_FROM_DATABASE=DCP-330C + +usb:v04F9p01AA* + ID_MODEL_FROM_DATABASE=DCP-540CN + +usb:v04F9p01AB* + ID_MODEL_FROM_DATABASE=MFC-240C + +usb:v04F9p01AE* + ID_MODEL_FROM_DATABASE=DCP-750CW RemovableDisk + +usb:v04F9p01AF* + ID_MODEL_FROM_DATABASE=MFC-440CN + +usb:v04F9p01B0* + ID_MODEL_FROM_DATABASE=MFC-660CN + +usb:v04F9p01B1* + ID_MODEL_FROM_DATABASE=MFC-665CW Remote Setup Port + +usb:v04F9p01B2* + ID_MODEL_FROM_DATABASE=MFC-845CW Remote Setup Port + +usb:v04F9p01B4* + ID_MODEL_FROM_DATABASE=MFC-460CN Remote Setup Port + +usb:v04F9p01B5* + ID_MODEL_FROM_DATABASE=MFC-630CD + +usb:v04F9p01B6* + ID_MODEL_FROM_DATABASE=MFC-850CDN + +usb:v04F9p01B7* + ID_MODEL_FROM_DATABASE=MFC-5460CN Remote Setup Port + +usb:v04F9p01B8* + ID_MODEL_FROM_DATABASE=MFC-5860CN + +usb:v04F9p01BA* + ID_MODEL_FROM_DATABASE=MFC-3360C + +usb:v04F9p01BD* + ID_MODEL_FROM_DATABASE=MFC-8660DN + +usb:v04F9p01BE* + ID_MODEL_FROM_DATABASE=DCP-750CN RemovableDisk + +usb:v04F9p01BF* + ID_MODEL_FROM_DATABASE=MFC-860CDN Remote Setup Port + +usb:v04F9p01C0* + ID_MODEL_FROM_DATABASE=DCP-128C + +usb:v04F9p01C1* + ID_MODEL_FROM_DATABASE=DCP-129C + +usb:v04F9p01C2* + ID_MODEL_FROM_DATABASE=DCP-131C + +usb:v04F9p01C3* + ID_MODEL_FROM_DATABASE=DCP-329C + +usb:v04F9p01C4* + ID_MODEL_FROM_DATABASE=DCP-331C + +usb:v04F9p01C5* + ID_MODEL_FROM_DATABASE=MFC-239C + +usb:v04F9p01CA* + ID_MODEL_FROM_DATABASE=MFC-9440CN Remote Setup Port + +usb:v04F9p01CE* + ID_MODEL_FROM_DATABASE=DCP-135C + +usb:v04F9p01CF* + ID_MODEL_FROM_DATABASE=DCP-150C + +usb:v04F9p01D0* + ID_MODEL_FROM_DATABASE=DCP-350C + +usb:v04F9p01D1* + ID_MODEL_FROM_DATABASE=DCP-560CN + +usb:v04F9p01D4* + ID_MODEL_FROM_DATABASE=MFC-230C + +usb:v04F9p01D5* + ID_MODEL_FROM_DATABASE=MFC-235C + +usb:v04F9p01D6* + ID_MODEL_FROM_DATABASE=MFC-260C + +usb:v04F9p01DF* + ID_MODEL_FROM_DATABASE=DCP-155C + +usb:v04F9p01E0* + ID_MODEL_FROM_DATABASE=MFC-265C + +usb:v04F9p01E1* + ID_MODEL_FROM_DATABASE=DCP-153C + +usb:v04F9p01E2* + ID_MODEL_FROM_DATABASE=DCP-157C + +usb:v04F9p01E3* + ID_MODEL_FROM_DATABASE=DCP-353C + +usb:v04F9p01E4* + ID_MODEL_FROM_DATABASE=DCP-357C + +usb:v04F9p01E7* + ID_MODEL_FROM_DATABASE=MFC-7340 + +usb:v04F9p01E9* + ID_MODEL_FROM_DATABASE=DCP-7040 + +usb:v04F9p01EA* + ID_MODEL_FROM_DATABASE=DCP-7030 + +usb:v04F9p01EB* + ID_MODEL_FROM_DATABASE=MFC-7320 + +usb:v04F9p01F4* + ID_MODEL_FROM_DATABASE=MFC-5890CN + +usb:v04F9p0223* + ID_MODEL_FROM_DATABASE=DCP-365CN + +usb:v04F9p0248* + ID_MODEL_FROM_DATABASE=DCP-7055 scanner/printer + +usb:v04F9p1000* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p1002* + ID_MODEL_FROM_DATABASE=Printer + +usb:v04F9p2002* + ID_MODEL_FROM_DATABASE=PTUSB Printing + +usb:v04F9p2004* + ID_MODEL_FROM_DATABASE=PT-2300/2310 p-Touch Laber Printer + +usb:v04F9p2015* + ID_MODEL_FROM_DATABASE=QL-500 P-touch label printer + +usb:v04F9p2016* + ID_MODEL_FROM_DATABASE=QL-550 P-touch label printer + +usb:v04F9p201A* + ID_MODEL_FROM_DATABASE=PT-18R P-touch label printer + +usb:v04F9p201B* + ID_MODEL_FROM_DATABASE=QL-650TD P-Touch Label Printer + +usb:v04F9p2027* + ID_MODEL_FROM_DATABASE=QL-560 P-Touch Label Printer + +usb:v04F9p202B* + ID_MODEL_FROM_DATABASE=PT-7600 P-Touch Label Printer + +usb:v04F9p2100* + ID_MODEL_FROM_DATABASE=Card Reader Writer + +usb:v04FA* + ID_VENDOR_FROM_DATABASE=Dallas Semiconductor + +usb:v04FAp2490* + ID_MODEL_FROM_DATABASE=DS1490F 2-in-1 Fob, 1-Wire adapter + +usb:v04FAp4201* + ID_MODEL_FROM_DATABASE=DS4201 Audio DAC + +usb:v04FB* + ID_VENDOR_FROM_DATABASE=Biostar Microtech International Corp. + +usb:v04FC* + ID_VENDOR_FROM_DATABASE=Sunplus Technology Co., Ltd + +usb:v04FCp0003* + ID_MODEL_FROM_DATABASE=CM1092 / Wintech CM-5098 Optical Mouse + +usb:v04FCp0005* + ID_MODEL_FROM_DATABASE=USB OpticalWheel Mouse + +usb:v04FCp0013* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v04FCp0015* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v04FCp00D3* + ID_MODEL_FROM_DATABASE=00052486 / Laser Mouse M1052 [hama] + +usb:v04FCp0171* + ID_MODEL_FROM_DATABASE=SPCA1527A/SPCA1528 SD card camera (Mass Storage mode) + +usb:v04FCp0201* + ID_MODEL_FROM_DATABASE=RS232C Adapter + +usb:v04FCp0232* + ID_MODEL_FROM_DATABASE=Fingerprint + +usb:v04FCp0538* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse 2.4G [Bright] + +usb:v04FCp0561* + ID_MODEL_FROM_DATABASE=Flexcam 100 + +usb:v04FCp05D8* + ID_MODEL_FROM_DATABASE=Wireless keyboard/mouse + +usb:v04FCp0C15* + ID_MODEL_FROM_DATABASE=SPIF215A SATA bridge + +usb:v04FCp0C25* + ID_MODEL_FROM_DATABASE=SATALink SPIF225A + +usb:v04FCp1528* + ID_MODEL_FROM_DATABASE=SPCA1527A/SPCA1528 SD card camera (webcam mode) + +usb:v04FCp1533* + ID_MODEL_FROM_DATABASE=Mass Storage + +usb:v04FCp2080* + ID_MODEL_FROM_DATABASE=ASUS Webcam + +usb:v04FCp500C* + ID_MODEL_FROM_DATABASE=CA500C Digital Camera + +usb:v04FCp504A* + ID_MODEL_FROM_DATABASE=Aiptek Mini PenCam 1.3 + +usb:v04FCp504B* + ID_MODEL_FROM_DATABASE=Aiptek Mega PockerCam 1.3/Maxell MaxPocket LE 1.3 + +usb:v04FCp5330* + ID_MODEL_FROM_DATABASE=Digitrex 2110 + +usb:v04FCp5331* + ID_MODEL_FROM_DATABASE=Vivitar Vivicam 10 + +usb:v04FCp5360* + ID_MODEL_FROM_DATABASE=Sunplus Generic Digital Camera + +usb:v04FCp5720* + ID_MODEL_FROM_DATABASE=Card Reader Driver + +usb:v04FCp7333* + ID_MODEL_FROM_DATABASE=Finet Technology Palmpix DC-85 + +usb:v04FCp757A* + ID_MODEL_FROM_DATABASE=Aiptek, MP315 MP3 Player + +usb:v04FCpFFFF* + ID_MODEL_FROM_DATABASE=PureDigital Ritz Disposable + +usb:v04FD* + ID_VENDOR_FROM_DATABASE=Soliton Systems, K.K. + +usb:v04FDp0003* + ID_MODEL_FROM_DATABASE=Smart Card Reader II + +usb:v04FE* + ID_VENDOR_FROM_DATABASE=PFU, Ltd + +usb:v04FF* + ID_VENDOR_FROM_DATABASE=E-CMOS Corp. + +usb:v0500* + ID_VENDOR_FROM_DATABASE=Siam United Hi-Tech + +usb:v0500p0001* + ID_MODEL_FROM_DATABASE=DART Keyboard Mouse + +usb:v0500p0002* + ID_MODEL_FROM_DATABASE=DART-2 Keyboard + +usb:v0501* + ID_VENDOR_FROM_DATABASE=Fujikura DDK, Ltd + +usb:v0502* + ID_VENDOR_FROM_DATABASE=Acer, Inc. + +usb:v0502p0001* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0502p0736* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0502p15B1* + ID_MODEL_FROM_DATABASE=PDA n311 + +usb:v0502p1631* + ID_MODEL_FROM_DATABASE=c10 Series + +usb:v0502p1632* + ID_MODEL_FROM_DATABASE=c20 Series + +usb:v0502p16E1* + ID_MODEL_FROM_DATABASE=n10 Handheld Sync + +usb:v0502p16E2* + ID_MODEL_FROM_DATABASE=n20 Pocket PC Sync + +usb:v0502p16E3* + ID_MODEL_FROM_DATABASE=n30 Handheld Sync + +usb:v0502p3202* + ID_MODEL_FROM_DATABASE=Liquid + +usb:v0502p3203* + ID_MODEL_FROM_DATABASE=Liquid (Debug mode) + +usb:v0502p3230* + ID_MODEL_FROM_DATABASE=BeTouch E120 + +usb:v0502p3317* + ID_MODEL_FROM_DATABASE=Liquid + +usb:v0502p3325* + ID_MODEL_FROM_DATABASE=Iconia tablet A500 + +usb:v0502p3341* + ID_MODEL_FROM_DATABASE=Iconia tablet A500 + +usb:v0502pD001* + ID_MODEL_FROM_DATABASE=Divio NW801/DVC-V6+ Digital Camera + +usb:v0503* + ID_VENDOR_FROM_DATABASE=Hitachi America, Ltd + +usb:v0504* + ID_VENDOR_FROM_DATABASE=Hayes Microcomputer Products + +usb:v0506* + ID_VENDOR_FROM_DATABASE=3Com Corp. + +usb:v0506p009D* + ID_MODEL_FROM_DATABASE=HomeConnect Camera + +usb:v0506p00A0* + ID_MODEL_FROM_DATABASE=3CREB96 Bluetooth Adapter + +usb:v0506p00A1* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0506p00A2* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0506p00DF* + ID_MODEL_FROM_DATABASE=3Com Home Connect lite + +usb:v0506p0100* + ID_MODEL_FROM_DATABASE=HomeConnect ADSL Modem Driver + +usb:v0506p03E8* + ID_MODEL_FROM_DATABASE=3C19250 Ethernet [klsi] + +usb:v0506p0A01* + ID_MODEL_FROM_DATABASE=3CRSHEW696 Wireless Adapter + +usb:v0506p0A11* + ID_MODEL_FROM_DATABASE=3CRWE254G72 802.11g Adapter + +usb:v0506p11F8* + ID_MODEL_FROM_DATABASE=HomeConnect 3C460 + +usb:v0506p2922* + ID_MODEL_FROM_DATABASE=HomeConnect Cable Modem External with + +usb:v0506p3021* + ID_MODEL_FROM_DATABASE=U.S.Robotics 56000 Voice FaxModem Pro + +usb:v0506p4601* + ID_MODEL_FROM_DATABASE=3C460B 10/100 Ethernet Adapter + +usb:v0506pF002* + ID_MODEL_FROM_DATABASE=3CP4218 ADSL Modem (pre-init) + +usb:v0506pF003* + ID_MODEL_FROM_DATABASE=3CP4218 ADSL Modem + +usb:v0506pF100* + ID_MODEL_FROM_DATABASE=3CP4218 ADSL Modem (pre-init) + +usb:v0507* + ID_VENDOR_FROM_DATABASE=Hosiden Corp. + +usb:v0507p0011* + ID_MODEL_FROM_DATABASE=Konami ParaParaParadise Controller + +usb:v0508* + ID_VENDOR_FROM_DATABASE=Clarion Co., Ltd + +usb:v0509* + ID_VENDOR_FROM_DATABASE=Aztech Systems, Ltd + +usb:v0509p0801* + ID_MODEL_FROM_DATABASE=ADSL Modem + +usb:v0509p0802* + ID_MODEL_FROM_DATABASE=ADSL Modem (RFC1483) + +usb:v0509p0806* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0509p080F* + ID_MODEL_FROM_DATABASE=Binatone ADSL500 Modem Network Interface + +usb:v0509p0812* + ID_MODEL_FROM_DATABASE=Pirelli ADSL Modem Network Interface + +usb:v050A* + ID_VENDOR_FROM_DATABASE=Cinch Connectors + +usb:v050B* + ID_VENDOR_FROM_DATABASE=Cable System International + +usb:v050C* + ID_VENDOR_FROM_DATABASE=InnoMedia, Inc. + +usb:v050D* + ID_VENDOR_FROM_DATABASE=Belkin Components + +usb:v050Dp0004* + ID_MODEL_FROM_DATABASE=Direct Connect + +usb:v050Dp0012* + ID_MODEL_FROM_DATABASE=F8T012 Bluetooth Adapter + +usb:v050Dp0013* + ID_MODEL_FROM_DATABASE=F8T013 Bluetooth Adapter + +usb:v050Dp0017* + ID_MODEL_FROM_DATABASE=B8T017 Bluetooth+EDR 2.1 + +usb:v050Dp003A* + ID_MODEL_FROM_DATABASE=Universal Media Reader + +usb:v050Dp0050* + ID_MODEL_FROM_DATABASE=F5D6050 802.11b Wireless Adapter v2000 [Atmel at76c503a] + +usb:v050Dp0081* + ID_MODEL_FROM_DATABASE=F8T001v2 Bluetooth + +usb:v050Dp0083* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v050Dp0084* + ID_MODEL_FROM_DATABASE=F8T003v2 Bluetooth + +usb:v050Dp0102* + ID_MODEL_FROM_DATABASE=Flip KVM + +usb:v050Dp0103* + ID_MODEL_FROM_DATABASE=F5U103 Serial Adapter [etek] + +usb:v050Dp0106* + ID_MODEL_FROM_DATABASE=VideoBus II Adapter, Video + +usb:v050Dp0108* + ID_MODEL_FROM_DATABASE=F1DE108B KVM + +usb:v050Dp0109* + ID_MODEL_FROM_DATABASE=F5U109/F5U409 PDA Adapter + +usb:v050Dp0115* + ID_MODEL_FROM_DATABASE=SCSI Adapter + +usb:v050Dp0119* + ID_MODEL_FROM_DATABASE=F5U120-PC Dual PS/2 Ports / F5U118-UNV ADB Adapter + +usb:v050Dp0121* + ID_MODEL_FROM_DATABASE=F5D5050 100Mbps Ethernet + +usb:v050Dp0122* + ID_MODEL_FROM_DATABASE=Ethernet Adapter + +usb:v050Dp0131* + ID_MODEL_FROM_DATABASE=Bluetooth Device with trace filter + +usb:v050Dp016A* + ID_MODEL_FROM_DATABASE=Bluetooth Mini Dongle + +usb:v050Dp0200* + ID_MODEL_FROM_DATABASE=Nostromo SpeedPad n52te Gaming Keyboard + +usb:v050Dp0201* + ID_MODEL_FROM_DATABASE=Peripheral Switch + +usb:v050Dp0208* + ID_MODEL_FROM_DATABASE=USBView II Video Adapter [nt1004] + +usb:v050Dp0210* + ID_MODEL_FROM_DATABASE=F5U228 Hi-Speed USB 2.0 DVD Creator + +usb:v050Dp0211* + ID_MODEL_FROM_DATABASE=F5U211 USB 2.0 15-in-1 Media Reader & Writer + +usb:v050Dp0224* + ID_MODEL_FROM_DATABASE=F5U224 USB 2.0 4-Port Hub + +usb:v050Dp0234* + ID_MODEL_FROM_DATABASE=F5U234 USB 2.0 4-Port Hub + +usb:v050Dp0237* + ID_MODEL_FROM_DATABASE=F5U237 USB 2.0 7-Port Hub + +usb:v050Dp0240* + ID_MODEL_FROM_DATABASE=F5U240 USB 2.0 CF Card Reader + +usb:v050Dp0249* + ID_MODEL_FROM_DATABASE=USB 2 Flash Media Device + +usb:v050Dp0257* + ID_MODEL_FROM_DATABASE=F5U257 Serial + +usb:v050Dp0304* + ID_MODEL_FROM_DATABASE=FSU304 USB 2.0 - 4 Ports Hub + +usb:v050Dp0307* + ID_MODEL_FROM_DATABASE=USB 2.0 - 7 ports Hub [FSU307] + +usb:v050Dp0409* + ID_MODEL_FROM_DATABASE=F5U409 Serial + +usb:v050Dp0416* + ID_MODEL_FROM_DATABASE=Staples 12416 7 port desktop hub + +usb:v050Dp0551* + ID_MODEL_FROM_DATABASE=F6C550-AVR UPS + +usb:v050Dp0706* + ID_MODEL_FROM_DATABASE=2-N-1 7-Port Hub (Lower half) + +usb:v050Dp0802* + ID_MODEL_FROM_DATABASE=Nostromo n40 Gamepad + +usb:v050Dp0803* + ID_MODEL_FROM_DATABASE=Nostromo 1745 GamePad + +usb:v050Dp0805* + ID_MODEL_FROM_DATABASE=Nostromo N50 GamePad + +usb:v050Dp0815* + ID_MODEL_FROM_DATABASE=Nostromo n52 HID SpeedPad Mouse Wheel + +usb:v050Dp0826* + ID_MODEL_FROM_DATABASE=ErgoFit Wireless Optical Mouse (HID) + +usb:v050Dp0980* + ID_MODEL_FROM_DATABASE=HID UPS Battery + +usb:v050Dp1004* + ID_MODEL_FROM_DATABASE=F9L1004 802.11n Surf N300 XR Wireless Adapter [Realtek RTL8192CU] + +usb:v050Dp1102* + ID_MODEL_FROM_DATABASE=F7D1102 N150/Surf Micro Wireless Adapter v1000 [Realtek RTL8188CUS] + +usb:v050Dp1103* + ID_MODEL_FROM_DATABASE=F9L1103 N750 DB 802.11abgn 2x3:3 [Ralink RT3573] + +usb:v050Dp1106* + ID_MODEL_FROM_DATABASE=F9L1106v1 802.11a/b/g/n/ac Wireless Adapter [Broadcom BCM43526] + +usb:v050Dp1109* + ID_MODEL_FROM_DATABASE=F9L1109v1 802.11a/b/g/n/ac Wireless Adapter [Realtek RTL8812AU] + +usb:v050Dp11F2* + ID_MODEL_FROM_DATABASE=ISY Wireless Micro Adapter IWL 2000 [RTL8188CUS] + +usb:v050Dp1202* + ID_MODEL_FROM_DATABASE=F5U120-PC Parallel Printer Port + +usb:v050Dp1203* + ID_MODEL_FROM_DATABASE=F5U120-PC Serial Port + +usb:v050Dp2103* + ID_MODEL_FROM_DATABASE=F7D2102 802.11n N300 Micro Wireless Adapter v3000 [Realtek RTL8192CU] + +usb:v050Dp21F1* + ID_MODEL_FROM_DATABASE=N300 WLAN N Adapter [ISY] + +usb:v050Dp258A* + ID_MODEL_FROM_DATABASE=F5U258 Host to Host cable + +usb:v050Dp3101* + ID_MODEL_FROM_DATABASE=F1DF102U/F1DG102U Flip Hub + +usb:v050Dp3201* + ID_MODEL_FROM_DATABASE=F1DF102U/F1DG102U Flip KVM + +usb:v050Dp4050* + ID_MODEL_FROM_DATABASE=ZD1211B + +usb:v050Dp5055* + ID_MODEL_FROM_DATABASE=F5D5055 Gigabit Network Adapter [AX88xxx] + +usb:v050Dp6050* + ID_MODEL_FROM_DATABASE=F6D6050 802.11abgn Wireless Adapter [Broadcom BCM4323] + +usb:v050Dp6051* + ID_MODEL_FROM_DATABASE=F5D6051 802.11b Wireless Network Adapter [ZyDAS ZD1201] + +usb:v050Dp615A* + ID_MODEL_FROM_DATABASE=F7D4101 / F9L1101 802.11abgn Wireless Adapter [Broadcom BCM4323] + +usb:v050Dp7050* + ID_MODEL_FROM_DATABASE=F5D7050 Wireless G Adapter v1000/v2000 [Intersil ISL3887] + +usb:v050Dp7051* + ID_MODEL_FROM_DATABASE=F5D7051 802.11g Adapter v1000 [Broadcom 4320 USB] + +usb:v050Dp705A* + ID_MODEL_FROM_DATABASE=F5D7050 Wireless G Adapter v3000 [Ralink RT2571W] + +usb:v050Dp705B* + ID_MODEL_FROM_DATABASE=Wireless G Adapter + +usb:v050Dp705C* + ID_MODEL_FROM_DATABASE=F5D7050 Wireless G Adapter v4000 [Zydas ZD1211B] + +usb:v050Dp705E* + ID_MODEL_FROM_DATABASE=F5D7050 Wireless G Adapter v5000 [Realtek RTL8187B] + +usb:v050Dp706A* + ID_MODEL_FROM_DATABASE=2-N-1 7-Port Hub (Upper half) + +usb:v050Dp8053* + ID_MODEL_FROM_DATABASE=F5D8053 N Wireless USB Adapter v1000/v4000 [Ralink RT2870] + +usb:v050Dp805C* + ID_MODEL_FROM_DATABASE=F5D8053 N Wireless Adapter v3000 [Ralink RT2870] + +usb:v050Dp805E* + ID_MODEL_FROM_DATABASE=F5D8053 N Wireless USB Adapter v5000 [Realtek RTL8192U] + +usb:v050Dp815C* + ID_MODEL_FROM_DATABASE=F5D8053 N Wireless USB Adapter v3000 [Ralink RT2870] + +usb:v050Dp815F* + ID_MODEL_FROM_DATABASE=F5D8053 N Wireless USB Adapter v6000 [Realtek RTL8192SU] + +usb:v050Dp825A* + ID_MODEL_FROM_DATABASE=F5D8055 N+ Wireless Adapter v1000 [Ralink RT2870] + +usb:v050Dp825B* + ID_MODEL_FROM_DATABASE=F5D8055 N+ Wireless Adapter v2000 [Ralink RT3072] + +usb:v050Dp845A* + ID_MODEL_FROM_DATABASE=F7D2101 802.11n Surf & Share Wireless Adapter v1000 [Realtek RTL8192SU] + +usb:v050Dp905B* + ID_MODEL_FROM_DATABASE=F5D9050 Wireless G+ MIMO Network Adapter v3000 [Ralink RT2573] + +usb:v050Dp905C* + ID_MODEL_FROM_DATABASE=F5D9050 Wireless G+ MIMO Network Adapter v4000 [Ralink RT2573] + +usb:v050Dp935A* + ID_MODEL_FROM_DATABASE=F6D4050 N150 Enhanced Wireless Network Adapter v1000 [Ralink RT3070] + +usb:v050Dp935B* + ID_MODEL_FROM_DATABASE=F6D4050 N150 Enhanced Wireless Network Adapter v2000 [Ralink RT3070] + +usb:v050Dp945A* + ID_MODEL_FROM_DATABASE=F7D1101 v1 Basic Wireless Adapter [Realtek RTL8188SU] + +usb:v050Dp945B* + ID_MODEL_FROM_DATABASE=F7D1101 v2 Basic Wireless Adapter [Ralink RT3370] + +usb:v050DpD321* + ID_MODEL_FROM_DATABASE=Dynex DX-NUSB 802.11bgn Wireless Adapter [Broadcom BCM43231] + +usb:v050E* + ID_VENDOR_FROM_DATABASE=Neon Technology, Inc. + +usb:v050F* + ID_VENDOR_FROM_DATABASE=KC Technology, Inc. + +usb:v050Fp0001* + ID_MODEL_FROM_DATABASE=Hub + +usb:v050Fp0003* + ID_MODEL_FROM_DATABASE=KC82C160S Hub + +usb:v050Fp0180* + ID_MODEL_FROM_DATABASE=KC-180 IrDA Dongle + +usb:v050Fp0190* + ID_MODEL_FROM_DATABASE=KC2190 USB Host-to-Host cable + +usb:v0510* + ID_VENDOR_FROM_DATABASE=Sejin Electron, Inc. + +usb:v0510p0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0510p1000* + ID_MODEL_FROM_DATABASE=Keyboard with PS/2 Mouse Port + +usb:v0510pE001* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0511* + ID_VENDOR_FROM_DATABASE=N'Able (DataBook) Technologies, Inc. + +usb:v0511p002B* + ID_MODEL_FROM_DATABASE=AOC DVB + +usb:v0512* + ID_VENDOR_FROM_DATABASE=Hualon Microelectronics Corp. + +usb:v0513* + ID_VENDOR_FROM_DATABASE=digital-X, Inc. + +usb:v0514* + ID_VENDOR_FROM_DATABASE=FCI Electronics + +usb:v0515* + ID_VENDOR_FROM_DATABASE=ACTC + +usb:v0516* + ID_VENDOR_FROM_DATABASE=Longwell Electronics + +usb:v0517* + ID_VENDOR_FROM_DATABASE=Butterfly Communications + +usb:v0518* + ID_VENDOR_FROM_DATABASE=EzKEY Corp. + +usb:v0518p0001* + ID_MODEL_FROM_DATABASE=USB to PS2 Adaptor v1.09 + +usb:v0518p0002* + ID_MODEL_FROM_DATABASE=EZ-9900C Keyboard + +usb:v0519* + ID_VENDOR_FROM_DATABASE=Star Micronics Co., Ltd + +usb:v0519p0003* + ID_MODEL_FROM_DATABASE=TSP100ECO/TSP100II + +usb:v0519pC002* + ID_MODEL_FROM_DATABASE=Xlive Bluetooth XBM-100S MP3 Player + +usb:v051A* + ID_VENDOR_FROM_DATABASE=WYSE Technology + +usb:v051ApA005* + ID_MODEL_FROM_DATABASE=Smart Display Version 9973 + +usb:v051B* + ID_VENDOR_FROM_DATABASE=Silicon Graphics + +usb:v051C* + ID_VENDOR_FROM_DATABASE=Shuttle, Inc. + +usb:v051Cp0005* + ID_MODEL_FROM_DATABASE=VFD Module + +usb:v051CpC001* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v051CpC002* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v051D* + ID_VENDOR_FROM_DATABASE=American Power Conversion + +usb:v051Dp0001* + ID_MODEL_FROM_DATABASE=UPS + +usb:v051Dp0002* + ID_MODEL_FROM_DATABASE=Uninterruptible Power Supply + +usb:v051Dp0003* + ID_MODEL_FROM_DATABASE=UPS + +usb:v051E* + ID_VENDOR_FROM_DATABASE=Scientific Atlanta, Inc. + +usb:v051F* + ID_VENDOR_FROM_DATABASE=IO Systems (Elite Electronics), Inc. + +usb:v0520* + ID_VENDOR_FROM_DATABASE=Taiwan Semiconductor Manufacturing Co. + +usb:v0521* + ID_VENDOR_FROM_DATABASE=Airborn Connectors + +usb:v0522* + ID_VENDOR_FROM_DATABASE=Advanced Connectek, Inc. + +usb:v0523* + ID_VENDOR_FROM_DATABASE=ATEN GmbH + +usb:v0524* + ID_VENDOR_FROM_DATABASE=Sola Electronics + +usb:v0525* + ID_VENDOR_FROM_DATABASE=Netchip Technology, Inc. + +usb:v0525p100D* + ID_MODEL_FROM_DATABASE=RFMD Bluetooth Device + +usb:v0525p1080* + ID_MODEL_FROM_DATABASE=NET1080 USB-USB Bridge + +usb:v0525p1200* + ID_MODEL_FROM_DATABASE=SSDC Adapter II + +usb:v0525p1265* + ID_MODEL_FROM_DATABASE=File-backed Storage Gadget + +usb:v0525pA0F0* + ID_MODEL_FROM_DATABASE=Cambridge Electronic Devices Power1401 mk 2 + +usb:v0525pA140* + ID_MODEL_FROM_DATABASE=USB Clik! 40 + +usb:v0525pA141* + ID_MODEL_FROM_DATABASE=(OME) PocketZip 40 MP3 Player Driver + +usb:v0525pA220* + ID_MODEL_FROM_DATABASE=GVC Bluetooth Wireless Adapter + +usb:v0525pA4A0* + ID_MODEL_FROM_DATABASE=Linux-USB "Gadget Zero" + +usb:v0525pA4A1* + ID_MODEL_FROM_DATABASE=Linux-USB Ethernet Gadget + +usb:v0525pA4A2* + ID_MODEL_FROM_DATABASE=Linux-USB Ethernet/RNDIS Gadget + +usb:v0525pA4A3* + ID_MODEL_FROM_DATABASE=Linux-USB user-mode isochronous source/sink + +usb:v0525pA4A4* + ID_MODEL_FROM_DATABASE=Linux-USB user-mode bulk source/sink + +usb:v0525pA4A5* + ID_MODEL_FROM_DATABASE=Pocketbook Pro 903 + +usb:v0525pA4A6* + ID_MODEL_FROM_DATABASE=Linux-USB Serial Gadget + +usb:v0525pA4A7* + ID_MODEL_FROM_DATABASE=Linux-USB Serial Gadget (CDC ACM mode) + +usb:v0525pA4A8* + ID_MODEL_FROM_DATABASE=Linux-USB Printer Gadget + +usb:v0525pA4A9* + ID_MODEL_FROM_DATABASE=Linux-USB OBEX Gadget + +usb:v0525pA4AA* + ID_MODEL_FROM_DATABASE=Linux-USB CDC Composite Gadge (Ethernet and ACM) + +usb:v0526* + ID_VENDOR_FROM_DATABASE=Temic MHS S.A. + +usb:v0527* + ID_VENDOR_FROM_DATABASE=ALTRA + +usb:v0528* + ID_VENDOR_FROM_DATABASE=ATI Technologies, Inc. + +usb:v0528p7561* + ID_MODEL_FROM_DATABASE=TV Wonder + +usb:v0528p7562* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FN5) + +usb:v0528p7563* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FI) + +usb:v0528p7564* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FQ) + +usb:v0528p7565* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (NTSC+) + +usb:v0528p7566* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FN5) + +usb:v0528p7567* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FI) + +usb:v0528p7568* + ID_MODEL_FROM_DATABASE=TV Wonder, Edition (FQ) + +usb:v0528p7569* + ID_MODEL_FROM_DATABASE=Live! Pro (A) + +usb:v0528p756A* + ID_MODEL_FROM_DATABASE=Live! Pro Audio (O) + +usb:v0529* + ID_VENDOR_FROM_DATABASE=Aladdin Knowledge Systems + +usb:v0529p0001* + ID_MODEL_FROM_DATABASE=HASP v0.06 + +usb:v0529p030B* + ID_MODEL_FROM_DATABASE=eToken R1 v3.1.3.x + +usb:v0529p0313* + ID_MODEL_FROM_DATABASE=eToken R1 v3.2.3.x + +usb:v0529p031B* + ID_MODEL_FROM_DATABASE=eToken R1 v3.3.3.x + +usb:v0529p0323* + ID_MODEL_FROM_DATABASE=eToken R1 v3.4.3.x + +usb:v0529p0412* + ID_MODEL_FROM_DATABASE=eToken R2 v2.2.4.x + +usb:v0529p041A* + ID_MODEL_FROM_DATABASE=eToken R2 v2.2.4.x + +usb:v0529p0422* + ID_MODEL_FROM_DATABASE=eToken R2 v2.4.4.x + +usb:v0529p042A* + ID_MODEL_FROM_DATABASE=eToken R2 v2.5.4.x + +usb:v0529p050C* + ID_MODEL_FROM_DATABASE=eToken Pro v4.1.5.x + +usb:v0529p0514* + ID_MODEL_FROM_DATABASE=eToken Pro v4.2.5.4 + +usb:v0529p0600* + ID_MODEL_FROM_DATABASE=eToken Pro 64k (4.2) + +usb:v0529p0620* + ID_MODEL_FROM_DATABASE=Token JC + +usb:v052A* + ID_VENDOR_FROM_DATABASE=Crescent Heart Software + +usb:v052B* + ID_VENDOR_FROM_DATABASE=Tekom Technologies, Inc. + +usb:v052Bp0102* + ID_MODEL_FROM_DATABASE=Ca508A HP1020 Camera v.1.3.1.6 + +usb:v052Bp0801* + ID_MODEL_FROM_DATABASE=Yakumo MegaImage 37 + +usb:v052Bp1512* + ID_MODEL_FROM_DATABASE=Yakumo MegaImage IV + +usb:v052Bp1513* + ID_MODEL_FROM_DATABASE=Aosta CX100 Webcam + +usb:v052Bp1514* + ID_MODEL_FROM_DATABASE=Aosta CX100 Webcam Storage + +usb:v052Bp1905* + ID_MODEL_FROM_DATABASE=Yakumo MegaImage 47 + +usb:v052Bp1911* + ID_MODEL_FROM_DATABASE=Yakumo MegaImage 47 SL + +usb:v052Bp2202* + ID_MODEL_FROM_DATABASE=WDM Still Image Capture + +usb:v052Bp2203* + ID_MODEL_FROM_DATABASE=Sound Vision Stream Driver + +usb:v052Bp3A06* + ID_MODEL_FROM_DATABASE=DigiLife DDV-5120A + +usb:v052BpD001* + ID_MODEL_FROM_DATABASE=P35U Camera Capture + +usb:v052C* + ID_VENDOR_FROM_DATABASE=Canon Information Systems, Inc. + +usb:v052D* + ID_VENDOR_FROM_DATABASE=Avid Electronics Corp. + +usb:v052E* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp. + +usb:v052F* + ID_VENDOR_FROM_DATABASE=Unicore Software, Inc. + +usb:v0530* + ID_VENDOR_FROM_DATABASE=American Microsystems, Inc. + +usb:v0531* + ID_VENDOR_FROM_DATABASE=Wacom Technology Corp. + +usb:v0532* + ID_VENDOR_FROM_DATABASE=Systech Corp. + +usb:v0533* + ID_VENDOR_FROM_DATABASE=Alcatel Mobile Phones + +usb:v0534* + ID_VENDOR_FROM_DATABASE=Motorola, Inc. + +usb:v0535* + ID_VENDOR_FROM_DATABASE=LIH TZU Electric Co., Ltd + +usb:v0536* + ID_VENDOR_FROM_DATABASE=Hand Held Products (Welch Allyn, Inc.) + +usb:v0536p01A0* + ID_MODEL_FROM_DATABASE=PDT + +usb:v0537* + ID_VENDOR_FROM_DATABASE=Inventec Corp. + +usb:v0538* + ID_VENDOR_FROM_DATABASE=Caldera International, Inc. (SCO) + +usb:v0539* + ID_VENDOR_FROM_DATABASE=Shyh Shiun Terminals Co., Ltd + +usb:v053A* + ID_VENDOR_FROM_DATABASE=PrehKeyTec GmbH + +usb:v053Ap0B00* + ID_MODEL_FROM_DATABASE=Hub + +usb:v053Ap0B01* + ID_MODEL_FROM_DATABASE=Preh MCI 3100 + +usb:v053B* + ID_VENDOR_FROM_DATABASE=Global Village Communication + +usb:v053C* + ID_VENDOR_FROM_DATABASE=Institut of Microelectronic & Mechatronic Systems + +usb:v053D* + ID_VENDOR_FROM_DATABASE=Silicon Architect + +usb:v053E* + ID_VENDOR_FROM_DATABASE=Mobility Electronics + +usb:v053F* + ID_VENDOR_FROM_DATABASE=Synopsys, Inc. + +usb:v0540* + ID_VENDOR_FROM_DATABASE=UniAccess AB + +usb:v0540p0101* + ID_MODEL_FROM_DATABASE=Panache Surf ISDN TA + +usb:v0541* + ID_VENDOR_FROM_DATABASE=Sirf Technology, Inc. + +usb:v0543* + ID_VENDOR_FROM_DATABASE=ViewSonic Corp. + +usb:v0543p00FE* + ID_MODEL_FROM_DATABASE=G773 Monitor Hub + +usb:v0543p00FF* + ID_MODEL_FROM_DATABASE=P815 Monitor Hub + +usb:v0543p0BF2* + ID_MODEL_FROM_DATABASE=airpanel V150 Wireless Smart Display + +usb:v0543p0BF3* + ID_MODEL_FROM_DATABASE=airpanel V110 Wireless Smart Display + +usb:v0543p0ED9* + ID_MODEL_FROM_DATABASE=Color Pocket PC V35 + +usb:v0543p0F01* + ID_MODEL_FROM_DATABASE=airsync Wi-Fi Wireless Adapter + +usb:v0543p1527* + ID_MODEL_FROM_DATABASE=Color Pocket PC V36 + +usb:v0543p1529* + ID_MODEL_FROM_DATABASE=Color Pocket PC V37 + +usb:v0543p152B* + ID_MODEL_FROM_DATABASE=Color Pocket PC V38 + +usb:v0543p152E* + ID_MODEL_FROM_DATABASE=Pocket PC + +usb:v0543p1921* + ID_MODEL_FROM_DATABASE=Communicator Pocket PC + +usb:v0543p1922* + ID_MODEL_FROM_DATABASE=Smartphone + +usb:v0543p1923* + ID_MODEL_FROM_DATABASE=Pocket PC V30 + +usb:v0543p1A11* + ID_MODEL_FROM_DATABASE=Wireless 802.11g Adapter + +usb:v0543p1E60* + ID_MODEL_FROM_DATABASE=TA310 - ATSC/NTSC/PAL Driver(PCM4) + +usb:v0543p4153* + ID_MODEL_FROM_DATABASE=ViewSonic G773 Control (?) + +usb:v0544* + ID_VENDOR_FROM_DATABASE=Cristie Electronics, Ltd + +usb:v0545* + ID_VENDOR_FROM_DATABASE=Xirlink, Inc. + +usb:v0545p7333* + ID_MODEL_FROM_DATABASE=Trution Web Camera + +usb:v0545p8002* + ID_MODEL_FROM_DATABASE=IBM NetCamera + +usb:v0545p8009* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p800C* + ID_MODEL_FROM_DATABASE=Veo Stingray + +usb:v0545p800D* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p8080* + ID_MODEL_FROM_DATABASE=IBM C-It Webcam + +usb:v0545p808A* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p808B* + ID_MODEL_FROM_DATABASE=Veo Stingray + +usb:v0545p808D* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p810A* + ID_MODEL_FROM_DATABASE=Veo Advanced Connect Webcam + +usb:v0545p810B* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p810C* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p8135* + ID_MODEL_FROM_DATABASE=Veo Mobile/Advanced Web Camera + +usb:v0545p813A* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p813B* + ID_MODEL_FROM_DATABASE=Veo PC Camera + +usb:v0545p813C* + ID_MODEL_FROM_DATABASE=Veo Mobile/Advanced Web Camera + +usb:v0545p8333* + ID_MODEL_FROM_DATABASE=Veo Stingray/Connect Web Camera + +usb:v0545p888C* + ID_MODEL_FROM_DATABASE=eVision 123 digital camera + +usb:v0545p888D* + ID_MODEL_FROM_DATABASE=eVision 123 digital camera + +usb:v0546* + ID_VENDOR_FROM_DATABASE=Polaroid Corp. + +usb:v0546p0DAF* + ID_MODEL_FROM_DATABASE=PDC 2300Z + +usb:v0546p1BED* + ID_MODEL_FROM_DATABASE=PDC 1320 Camera + +usb:v0546p3097* + ID_MODEL_FROM_DATABASE=PDC 310 + +usb:v0546p3155* + ID_MODEL_FROM_DATABASE=PDC 3070 Camera + +usb:v0546p3187* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0546p3191* + ID_MODEL_FROM_DATABASE=Ion 80 Camera + +usb:v0546p3273* + ID_MODEL_FROM_DATABASE=PDC 2030 Camera + +usb:v0546p3304* + ID_MODEL_FROM_DATABASE=a500 Digital Camera + +usb:v0546pDCCF* + ID_MODEL_FROM_DATABASE=Sound Vision Stream Driver + +usb:v0547* + ID_VENDOR_FROM_DATABASE=Anchor Chips, Inc. + +usb:v0547p0001* + ID_MODEL_FROM_DATABASE=ICSI Bluetooth Device + +usb:v0547p1002* + ID_MODEL_FROM_DATABASE=Python2 WDM Encoder + +usb:v0547p1006* + ID_MODEL_FROM_DATABASE=Hantek DSO-2100 UF + +usb:v0547p2131* + ID_MODEL_FROM_DATABASE=AN2131 EZUSB Microcontroller + +usb:v0547p2235* + ID_MODEL_FROM_DATABASE=AN2235 EZUSB-FX Microcontroller + +usb:v0547p2710* + ID_MODEL_FROM_DATABASE=EZ-Link Loader (EZLNKLDR.SYS) + +usb:v0547p2720* + ID_MODEL_FROM_DATABASE=AN2720 USB-USB Bridge + +usb:v0547p2727* + ID_MODEL_FROM_DATABASE=Xircom PGUNET USB-USB Bridge + +usb:v0547p2750* + ID_MODEL_FROM_DATABASE=EZ-Link (EZLNKUSB.SYS) + +usb:v0547p2810* + ID_MODEL_FROM_DATABASE=Cypress ATAPI Bridge + +usb:v0547p4D90* + ID_MODEL_FROM_DATABASE=AmScope MD1900 camera + +usb:v0547p7777* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0547p9999* + ID_MODEL_FROM_DATABASE=AN2131 uninitialized (?) + +usb:v0548* + ID_VENDOR_FROM_DATABASE=Tyan Computer Corp. + +usb:v0548p1005* + ID_MODEL_FROM_DATABASE=EZ Cart II GameBoy Flash Programmer + +usb:v0549* + ID_VENDOR_FROM_DATABASE=Pixera Corp. + +usb:v054A* + ID_VENDOR_FROM_DATABASE=Fujitsu Microelectronics, Inc. + +usb:v054B* + ID_VENDOR_FROM_DATABASE=New Media Corp. + +usb:v054C* + ID_VENDOR_FROM_DATABASE=Sony Corp. + +usb:v054Cp0001* + ID_MODEL_FROM_DATABASE=HUB + +usb:v054Cp0002* + ID_MODEL_FROM_DATABASE=Standard HUB + +usb:v054Cp0010* + ID_MODEL_FROM_DATABASE=DSC-S30/S70/S75/F505V/F505/FD92/W1 Cybershot/Mavica Digital Camera + +usb:v054Cp0014* + ID_MODEL_FROM_DATABASE=Nogatech USBVision (SY) + +usb:v054Cp0022* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 (TPP) + +usb:v054Cp0023* + ID_MODEL_FROM_DATABASE=CD Writer + +usb:v054Cp0024* + ID_MODEL_FROM_DATABASE=Mavica CD-1000 Camera + +usb:v054Cp0025* + ID_MODEL_FROM_DATABASE=NW-MS7 Walkman MemoryStick Reader + +usb:v054Cp002B* + ID_MODEL_FROM_DATABASE=Portable USB Harddrive V2 + +usb:v054Cp002C* + ID_MODEL_FROM_DATABASE=USB Floppy Disk Drive + +usb:v054Cp002D* + ID_MODEL_FROM_DATABASE=MSAC-US1 MemoryStick Reader + +usb:v054Cp002E* + ID_MODEL_FROM_DATABASE=HandyCam MemoryStick Reader + +usb:v054Cp0030* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 (TPP) + +usb:v054Cp0032* + ID_MODEL_FROM_DATABASE=MemoryStick MSC-U01 Reader + +usb:v054Cp0035* + ID_MODEL_FROM_DATABASE=Network Walkman (E) + +usb:v054Cp0036* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0037* + ID_MODEL_FROM_DATABASE=MG Memory Stick Reader/Writer + +usb:v054Cp0038* + ID_MODEL_FROM_DATABASE=Clie PEG-S300/D PalmOS PDA + +usb:v054Cp0039* + ID_MODEL_FROM_DATABASE=Network Walkman (MS) + +usb:v054Cp003C* + ID_MODEL_FROM_DATABASE=VAIO-MX LCD Control + +usb:v054Cp0045* + ID_MODEL_FROM_DATABASE=Digital Imaging Video + +usb:v054Cp0046* + ID_MODEL_FROM_DATABASE=Network Walkman + +usb:v054Cp004A* + ID_MODEL_FROM_DATABASE=Memory Stick Hi-Fi System + +usb:v054Cp004B* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v054Cp004E* + ID_MODEL_FROM_DATABASE=DSC-xxx (ptp) + +usb:v054Cp0056* + ID_MODEL_FROM_DATABASE=MG Memory Stick Reader/Writer + +usb:v054Cp0058* + ID_MODEL_FROM_DATABASE=Clie PEG-N7x0C PalmOS PDA Mass Storage + +usb:v054Cp0066* + ID_MODEL_FROM_DATABASE=Clie PEG-N7x0C/PEG-T425 PalmOS PDA Serial + +usb:v054Cp0067* + ID_MODEL_FROM_DATABASE=CMR-PC3 Webcam + +usb:v054Cp0069* + ID_MODEL_FROM_DATABASE=Memorystick MSC-U03 Reader + +usb:v054Cp006C* + ID_MODEL_FROM_DATABASE=FeliCa S310 [PaSoRi] + +usb:v054Cp006D* + ID_MODEL_FROM_DATABASE=Clie PEG-T425 PDA Mass Storage + +usb:v054Cp006F* + ID_MODEL_FROM_DATABASE=Network Walkman (EV) + +usb:v054Cp0073* + ID_MODEL_FROM_DATABASE=Storage CRX1750U + +usb:v054Cp0075* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0076* + ID_MODEL_FROM_DATABASE=Storage Adapter ACR-U20 + +usb:v054Cp007C* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp007F* + ID_MODEL_FROM_DATABASE=IC Recorder (MS) + +usb:v054Cp0080* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0081* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0084* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0085* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0086* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp008B* + ID_MODEL_FROM_DATABASE=Micro Vault 64M Mass Storage + +usb:v054Cp0095* + ID_MODEL_FROM_DATABASE=Clie s360 + +usb:v054Cp0099* + ID_MODEL_FROM_DATABASE=Clie NR70 PDA Mass Storage + +usb:v054Cp009A* + ID_MODEL_FROM_DATABASE=Clie NR70 PDA Serial + +usb:v054Cp00AB* + ID_MODEL_FROM_DATABASE=Visual Communication Camera (PCGA-UVC10) + +usb:v054Cp00AF* + ID_MODEL_FROM_DATABASE=DPP-EX Series Digital Photo Printer + +usb:v054Cp00BF* + ID_MODEL_FROM_DATABASE=IC Recorder (S) + +usb:v054Cp00C0* + ID_MODEL_FROM_DATABASE=Handycam DCR-30 + +usb:v054Cp00C6* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp00C7* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp00C8* + ID_MODEL_FROM_DATABASE=MZ-N710 Minidisc Walkman + +usb:v054Cp00C9* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp00CA* + ID_MODEL_FROM_DATABASE=MZ-DN430 Minidisc Walkman + +usb:v054Cp00CB* + ID_MODEL_FROM_DATABASE=MSAC-US20 Memory Stick Reader + +usb:v054Cp00DA* + ID_MODEL_FROM_DATABASE=Clie nx60 + +usb:v054Cp00E8* + ID_MODEL_FROM_DATABASE=Network Walkman (MS) + +usb:v054Cp00E9* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v054Cp00EB* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0101* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0103* + ID_MODEL_FROM_DATABASE=IC Recorder (ST) + +usb:v054Cp0105* + ID_MODEL_FROM_DATABASE=Micro Vault Hub + +usb:v054Cp0107* + ID_MODEL_FROM_DATABASE=VCC-U01 Visual Communication Camera + +usb:v054Cp0110* + ID_MODEL_FROM_DATABASE=Digital Imaging Video + +usb:v054Cp0113* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0116* + ID_MODEL_FROM_DATABASE=IC Recorder (P) + +usb:v054Cp0144* + ID_MODEL_FROM_DATABASE=Clie PEG-TH55 PDA + +usb:v054Cp0147* + ID_MODEL_FROM_DATABASE=Visual Communication Camera (PCGA-UVC11) + +usb:v054Cp014C* + ID_MODEL_FROM_DATABASE=Aiwa AM-NX9 Net MD Music Recorder MDLP + +usb:v054Cp014D* + ID_MODEL_FROM_DATABASE=Memory Stick Reader/Writer + +usb:v054Cp0154* + ID_MODEL_FROM_DATABASE=Eyetoy Audio Device + +usb:v054Cp015F* + ID_MODEL_FROM_DATABASE=IC Recorder (BM) + +usb:v054Cp0169* + ID_MODEL_FROM_DATABASE=Clie PEG-TJ35 PDA Serial + +usb:v054Cp016A* + ID_MODEL_FROM_DATABASE=Clie PEG-TJ35 PDA Mass Storage + +usb:v054Cp016B* + ID_MODEL_FROM_DATABASE=Mobile HDD + +usb:v054Cp016D* + ID_MODEL_FROM_DATABASE=IC Recorder (SX) + +usb:v054Cp016E* + ID_MODEL_FROM_DATABASE=DPP-EX50 Digital Photo Printer + +usb:v054Cp0171* + ID_MODEL_FROM_DATABASE=Fingerprint Sensor 3500 + +usb:v054Cp017E* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp017F* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0180* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0181* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0182* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0183* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0184* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0185* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0186* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0187* + ID_MODEL_FROM_DATABASE=Hi-MD MZ-NH600 WALKMAN + +usb:v054Cp0188* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp018A* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp018B* + ID_MODEL_FROM_DATABASE=Hi-MD SOUND GATE + +usb:v054Cp019E* + ID_MODEL_FROM_DATABASE=Micro Vault 1.0G Mass Storage + +usb:v054Cp01AD* + ID_MODEL_FROM_DATABASE=ATRAC HDD PA + +usb:v054Cp01BB* + ID_MODEL_FROM_DATABASE=FeliCa S320 [PaSoRi] + +usb:v054Cp01BD* + ID_MODEL_FROM_DATABASE=MRW62E Multi-Card Reader/Writer + +usb:v054Cp01C3* + ID_MODEL_FROM_DATABASE=NW-E55 Network Walkman + +usb:v054Cp01C6* + ID_MODEL_FROM_DATABASE=MEMORY P-AUDIO + +usb:v054Cp01C7* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v054Cp01C8* + ID_MODEL_FROM_DATABASE=PSP Type A + +usb:v054Cp01C9* + ID_MODEL_FROM_DATABASE=PSP Type B + +usb:v054Cp01D0* + ID_MODEL_FROM_DATABASE=DVD+RW External Drive DRU-700A + +usb:v054Cp01D5* + ID_MODEL_FROM_DATABASE=IC RECORDER + +usb:v054Cp01DE* + ID_MODEL_FROM_DATABASE=VRD-VC10 [Video Capture] + +usb:v054Cp01E8* + ID_MODEL_FROM_DATABASE=UP-DR150 Photo Printer + +usb:v054Cp01E9* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp01EA* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp01EE* + ID_MODEL_FROM_DATABASE=IC RECORDER + +usb:v054Cp01FA* + ID_MODEL_FROM_DATABASE=IC Recorder (P) + +usb:v054Cp01FB* + ID_MODEL_FROM_DATABASE=NW-E405 Network Walkman + +usb:v054Cp020F* + ID_MODEL_FROM_DATABASE=Device + +usb:v054Cp0210* + ID_MODEL_FROM_DATABASE=ATRAC HDD PA + +usb:v054Cp0219* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp021A* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp021B* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp021C* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp021D* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0227* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v054Cp022C* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp022D* + ID_MODEL_FROM_DATABASE=Hi-MD AUDIO + +usb:v054Cp0233* + ID_MODEL_FROM_DATABASE=ATRAC HDD PA + +usb:v054Cp0236* + ID_MODEL_FROM_DATABASE=Mobile HDD + +usb:v054Cp023B* + ID_MODEL_FROM_DATABASE=DVD+RW External Drive DRU-800UL + +usb:v054Cp023C* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp023D* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0243* + ID_MODEL_FROM_DATABASE=MicroVault Flash Drive + +usb:v054Cp024B* + ID_MODEL_FROM_DATABASE=Vaio VGX Mouse + +usb:v054Cp0257* + ID_MODEL_FROM_DATABASE=IFU-WLM2 USB Wireless LAN Module (Wireless Mode) + +usb:v054Cp0258* + ID_MODEL_FROM_DATABASE=IFU-WLM2 USB Wireless LAN Module (Memory Mode) + +usb:v054Cp0259* + ID_MODEL_FROM_DATABASE=IC RECORDER + +usb:v054Cp0267* + ID_MODEL_FROM_DATABASE=Tachikoma Device + +usb:v054Cp0268* + ID_MODEL_FROM_DATABASE=Batoh Device / PlayStation 3 Controller + +usb:v054Cp0269* + ID_MODEL_FROM_DATABASE=HDD WALKMAN + +usb:v054Cp026A* + ID_MODEL_FROM_DATABASE=HDD WALKMAN + +usb:v054Cp0271* + ID_MODEL_FROM_DATABASE=IC Recorder (P) + +usb:v054Cp027C* + ID_MODEL_FROM_DATABASE=NETWORK WALKMAN + +usb:v054Cp027E* + ID_MODEL_FROM_DATABASE=SONY Communicator + +usb:v054Cp027F* + ID_MODEL_FROM_DATABASE=IC RECORDER + +usb:v054Cp0286* + ID_MODEL_FROM_DATABASE=Net MD + +usb:v054Cp0287* + ID_MODEL_FROM_DATABASE=Hi-MD WALKMAN + +usb:v054Cp0290* + ID_MODEL_FROM_DATABASE=VGP-UVC100 Visual Communication Camera + +usb:v054Cp029B* + ID_MODEL_FROM_DATABASE=PRS-500 eBook reader + +usb:v054Cp02A5* + ID_MODEL_FROM_DATABASE=MicroVault Flash Drive + +usb:v054Cp02AF* + ID_MODEL_FROM_DATABASE=Handycam DCR-DVD306E + +usb:v054Cp02C4* + ID_MODEL_FROM_DATABASE=Device + +usb:v054Cp02D1* + ID_MODEL_FROM_DATABASE=DVD RW + +usb:v054Cp02D2* + ID_MODEL_FROM_DATABASE=PSP Slim + +usb:v054Cp02E1* + ID_MODEL_FROM_DATABASE=FeliCa S330 [PaSoRi] + +usb:v054Cp02EA* + ID_MODEL_FROM_DATABASE=PlayStation 3 Memory Card Adaptor + +usb:v054Cp02F9* + ID_MODEL_FROM_DATABASE=DSC-H9 + +usb:v054Cp0317* + ID_MODEL_FROM_DATABASE=WALKMAN + +usb:v054Cp031A* + ID_MODEL_FROM_DATABASE=Walkman NWD-B103F + +usb:v054Cp031E* + ID_MODEL_FROM_DATABASE=PRS-300/PRS-505 eBook reader + +usb:v054Cp0325* + ID_MODEL_FROM_DATABASE=NWZ-A818 + +usb:v054Cp033E* + ID_MODEL_FROM_DATABASE=DSC-W120/W290 + +usb:v054Cp0346* + ID_MODEL_FROM_DATABASE=Handycam DCR-SR55E + +usb:v054Cp0348* + ID_MODEL_FROM_DATABASE=HandyCam HDR-TG3E + +usb:v054Cp035B* + ID_MODEL_FROM_DATABASE=Walkman NWZ-A828 + +usb:v054Cp035C* + ID_MODEL_FROM_DATABASE=NWZ-A726/A728/A729 + +usb:v054Cp0382* + ID_MODEL_FROM_DATABASE=Memory Stick PRO-HG Duo Adaptor (MSAC-UAH1) + +usb:v054Cp0385* + ID_MODEL_FROM_DATABASE=Walkman NWZ-E436F + +usb:v054Cp0387* + ID_MODEL_FROM_DATABASE=IC Recorder (P) + +usb:v054Cp03BC* + ID_MODEL_FROM_DATABASE=Webbie HD - MHS-CM1 + +usb:v054Cp03D1* + ID_MODEL_FROM_DATABASE=DPF-X95 + +usb:v054Cp03D3* + ID_MODEL_FROM_DATABASE=DR-BT100CX + +usb:v054Cp03D5* + ID_MODEL_FROM_DATABASE=PlayStation Move motion controller + +usb:v054Cp03FC* + ID_MODEL_FROM_DATABASE=WALKMAN [NWZ-E345] + +usb:v054Cp03FD* + ID_MODEL_FROM_DATABASE=Walkman NWZ-E443 + +usb:v054Cp042F* + ID_MODEL_FROM_DATABASE=PlayStation Move navigation controller + +usb:v054Cp0440* + ID_MODEL_FROM_DATABASE=DSC-H55 + +usb:v054Cp0485* + ID_MODEL_FROM_DATABASE=MHS-PM5 HD camcorder + +usb:v054Cp04CB* + ID_MODEL_FROM_DATABASE=WALKMAN NWZ-E354 + +usb:v054Cp06BB* + ID_MODEL_FROM_DATABASE=WALKMAN NWZ-F805 + +usb:v054Cp1000* + ID_MODEL_FROM_DATABASE=Wireless Buzz! Receiver + +usb:v054D* + ID_VENDOR_FROM_DATABASE=Try Corp. + +usb:v054E* + ID_VENDOR_FROM_DATABASE=Proside Corp. + +usb:v054F* + ID_VENDOR_FROM_DATABASE=WYSE Technology Taiwan + +usb:v0550* + ID_VENDOR_FROM_DATABASE=Fuji Xerox Co., Ltd + +usb:v0550p0002* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0550p0004* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0550p0005* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0551* + ID_VENDOR_FROM_DATABASE=CompuTrend Systems, Inc. + +usb:v0552* + ID_VENDOR_FROM_DATABASE=Philips Monitors + +usb:v0553* + ID_VENDOR_FROM_DATABASE=STMicroelectronics Imaging Division (VLSI Vision) + +usb:v0553p0001* + ID_MODEL_FROM_DATABASE=TerraCAM + +usb:v0553p0002* + ID_MODEL_FROM_DATABASE=CPiA Webcam + +usb:v0553p0100* + ID_MODEL_FROM_DATABASE=STV0672 Camera + +usb:v0553p0140* + ID_MODEL_FROM_DATABASE=Video Camera + +usb:v0553p0150* + ID_MODEL_FROM_DATABASE=CDE CAM 100 + +usb:v0553p0151* + ID_MODEL_FROM_DATABASE=Digital Blue QX5 Microscope + +usb:v0553p0200* + ID_MODEL_FROM_DATABASE=Dual-mode Camera0 + +usb:v0553p0201* + ID_MODEL_FROM_DATABASE=Dual-mode Camera1 + +usb:v0553p0202* + ID_MODEL_FROM_DATABASE=STV0680 Camera + +usb:v0553p0674* + ID_MODEL_FROM_DATABASE=Multi-mode Camera + +usb:v0553p0679* + ID_MODEL_FROM_DATABASE=NMS Video Camera (Webcam) + +usb:v0553p1002* + ID_MODEL_FROM_DATABASE=Che-ez! Splash + +usb:v0554* + ID_VENDOR_FROM_DATABASE=Dictaphone Corp. + +usb:v0555* + ID_VENDOR_FROM_DATABASE=ANAM S&T Co., Ltd + +usb:v0556* + ID_VENDOR_FROM_DATABASE=Asahi Kasei Microsystems Co., Ltd + +usb:v0556p0001* + ID_MODEL_FROM_DATABASE=AK5370 I/F A/D Converter + +usb:v0557* + ID_VENDOR_FROM_DATABASE=ATEN International Co., Ltd + +usb:v0557p2001* + ID_MODEL_FROM_DATABASE=UC-1284 Printer Port + +usb:v0557p2002* + ID_MODEL_FROM_DATABASE=10Mbps Ethernet [klsi] + +usb:v0557p2004* + ID_MODEL_FROM_DATABASE=UC-100KM PS/2 Mouse and Keyboard adapter + +usb:v0557p2006* + ID_MODEL_FROM_DATABASE=UC-1284B Printer Port + +usb:v0557p2007* + ID_MODEL_FROM_DATABASE=UC-110T 100Mbps Ethernet [pegasus] + +usb:v0557p2008* + ID_MODEL_FROM_DATABASE=UC-232A Serial Port [pl2303] + +usb:v0557p2009* + ID_MODEL_FROM_DATABASE=UC-210T Ethernet + +usb:v0557p2011* + ID_MODEL_FROM_DATABASE=UC-2324 4xSerial Ports [mos7840] + +usb:v0557p2202* + ID_MODEL_FROM_DATABASE=CS124U Miniview II KVM Switch + +usb:v0557p2213* + ID_MODEL_FROM_DATABASE=CS682 2-Port USB 2.0 DVI KVM Switch + +usb:v0557p2221* + ID_MODEL_FROM_DATABASE=Winbond Hermon + +usb:v0557p2404* + ID_MODEL_FROM_DATABASE=4-port switch + +usb:v0557p2600* + ID_MODEL_FROM_DATABASE=IDE Bridge + +usb:v0557p2701* + ID_MODEL_FROM_DATABASE=CE700A KVM Extender + +usb:v0557p4000* + ID_MODEL_FROM_DATABASE=DSB-650 10Mbps Ethernet [klsi] + +usb:v0557p7000* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0557p7820* + ID_MODEL_FROM_DATABASE=UC-2322 2xSerial Ports [mos7820] + +usb:v0557p8021* + ID_MODEL_FROM_DATABASE=CS1764A [CubiQ DVI KVMP Switch] + +usb:v0558* + ID_VENDOR_FROM_DATABASE=Truevision, Inc. + +usb:v0558p1009* + ID_MODEL_FROM_DATABASE=GW Instek GDS-1000 Oscilloscope + +usb:v0558p100A* + ID_MODEL_FROM_DATABASE=GW Instek GDS-1000A Oscilloscope + +usb:v0558p2009* + ID_MODEL_FROM_DATABASE=GW Instek GDS-2000 Oscilloscope + +usb:v0559* + ID_VENDOR_FROM_DATABASE=Cadence Design Systems, Inc. + +usb:v055A* + ID_VENDOR_FROM_DATABASE=Kenwood USA + +usb:v055B* + ID_VENDOR_FROM_DATABASE=KnowledgeTek, Inc. + +usb:v055C* + ID_VENDOR_FROM_DATABASE=Proton Electronic Ind. + +usb:v055D* + ID_VENDOR_FROM_DATABASE=Samsung Electro-Mechanics Co. + +usb:v055Dp0001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v055Dp0BB1* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v055Dp1030* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse (OMS3CB/OMGB30) + +usb:v055Dp1031* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse (OMA3CB/OMGI30) + +usb:v055Dp1040* + ID_MODEL_FROM_DATABASE=Mouse HID Device + +usb:v055Dp1050* + ID_MODEL_FROM_DATABASE=E-Mail Optical Wheel Mouse (OMS3CE) + +usb:v055Dp1080* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse (OMS3CH) + +usb:v055Dp2020* + ID_MODEL_FROM_DATABASE=Floppy Disk Drive + +usb:v055Dp6780* + ID_MODEL_FROM_DATABASE=Keyboard V1 + +usb:v055Dp6781* + ID_MODEL_FROM_DATABASE=Keyboard Mouse + +usb:v055Dp8001* + ID_MODEL_FROM_DATABASE=E.M. Hub + +usb:v055Dp9000* + ID_MODEL_FROM_DATABASE=AnyCam [pwc] + +usb:v055Dp9001* + ID_MODEL_FROM_DATABASE=MPC-C30 AnyCam Premium for Notebooks [pwc] + +usb:v055DpA000* + ID_MODEL_FROM_DATABASE=SWL-2100U + +usb:v055DpA010* + ID_MODEL_FROM_DATABASE=WLAN Adapter(SWL-2300) + +usb:v055DpA011* + ID_MODEL_FROM_DATABASE=Boot Device + +usb:v055DpA012* + ID_MODEL_FROM_DATABASE=WLAN Adapter(SWL-2300) + +usb:v055DpA013* + ID_MODEL_FROM_DATABASE=WLAN Adapter(SWL-2350) + +usb:v055DpA230* + ID_MODEL_FROM_DATABASE=Boot Device + +usb:v055DpB000* + ID_MODEL_FROM_DATABASE=11Mbps WLAN Mini Adapter + +usb:v055DpB230* + ID_MODEL_FROM_DATABASE=Netopia 802.11b WLAN Adapter + +usb:v055DpB231* + ID_MODEL_FROM_DATABASE=LG Wireless LAN 11b Adapter + +usb:v055E* + ID_VENDOR_FROM_DATABASE=CTX Opto-Electronics Corp. + +usb:v055F* + ID_VENDOR_FROM_DATABASE=Mustek Systems, Inc. + +usb:v055Fp0001* + ID_MODEL_FROM_DATABASE=ScanExpress 1200 CU + +usb:v055Fp0002* + ID_MODEL_FROM_DATABASE=ScanExpress 600 CU + +usb:v055Fp0003* + ID_MODEL_FROM_DATABASE=ScanExpress 1200 USB + +usb:v055Fp0006* + ID_MODEL_FROM_DATABASE=ScanExpress 1200 UB + +usb:v055Fp0007* + ID_MODEL_FROM_DATABASE=ScanExpress 1200 USB Plus + +usb:v055Fp0008* + ID_MODEL_FROM_DATABASE=ScanExpress 1200 CU Plus + +usb:v055Fp0010* + ID_MODEL_FROM_DATABASE=BearPaw 1200F + +usb:v055Fp0210* + ID_MODEL_FROM_DATABASE=ScanExpress A3 USB + +usb:v055Fp0218* + ID_MODEL_FROM_DATABASE=BearPaw 2400 TA + +usb:v055Fp0219* + ID_MODEL_FROM_DATABASE=BearPaw 2400 TA Plus + +usb:v055Fp021A* + ID_MODEL_FROM_DATABASE=BearPaw 2448 TA Plus + +usb:v055Fp021B* + ID_MODEL_FROM_DATABASE=BearPaw 1200 CU Plus + +usb:v055Fp021C* + ID_MODEL_FROM_DATABASE=BearPaw 1200 CU Plus + +usb:v055Fp021D* + ID_MODEL_FROM_DATABASE=BearPaw 2400 CU Plus + +usb:v055Fp021E* + ID_MODEL_FROM_DATABASE=BearPaw 1200 TA/CS + +usb:v055Fp021F* + ID_MODEL_FROM_DATABASE=SNAPSCAN e22 + +usb:v055Fp0400* + ID_MODEL_FROM_DATABASE=BearPaw 2400 TA Pro + +usb:v055Fp0401* + ID_MODEL_FROM_DATABASE=P 3600 A3 Pro + +usb:v055Fp0408* + ID_MODEL_FROM_DATABASE=BearPaw 2448 CU Pro + +usb:v055Fp0409* + ID_MODEL_FROM_DATABASE=BearPaw 2448 TA Pro + +usb:v055Fp040B* + ID_MODEL_FROM_DATABASE=ScanExpress A3 USB 1200 PRO + +usb:v055Fp0873* + ID_MODEL_FROM_DATABASE=ScanExpress 600 USB + +usb:v055Fp1000* + ID_MODEL_FROM_DATABASE=BearPaw 4800 TA Pro + +usb:v055FpA350* + ID_MODEL_FROM_DATABASE=gSmart 350 Camera + +usb:v055FpA800* + ID_MODEL_FROM_DATABASE=MDC 800 Camera + +usb:v055FpB500* + ID_MODEL_FROM_DATABASE=MDC 3000 Camera + +usb:v055FpC005* + ID_MODEL_FROM_DATABASE=PC CAM 300A + +usb:v055FpC200* + ID_MODEL_FROM_DATABASE=gSmart 300 + +usb:v055FpC211* + ID_MODEL_FROM_DATABASE=Kowa Bs888e Microcamera + +usb:v055FpC220* + ID_MODEL_FROM_DATABASE=gSmart mini + +usb:v055FpC230* + ID_MODEL_FROM_DATABASE=Digicam 330K + +usb:v055FpC232* + ID_MODEL_FROM_DATABASE=MDC3500 Camera + +usb:v055FpC360* + ID_MODEL_FROM_DATABASE=DV 4000 Camera + +usb:v055FpC420* + ID_MODEL_FROM_DATABASE=gSmart mini 2 Camera + +usb:v055FpC430* + ID_MODEL_FROM_DATABASE=gSmart LCD 2 Camera + +usb:v055FpC440* + ID_MODEL_FROM_DATABASE=DV 3000 Camera + +usb:v055FpC520* + ID_MODEL_FROM_DATABASE=gSmart mini 3 Camera + +usb:v055FpC530* + ID_MODEL_FROM_DATABASE=gSmart LCD 2 Camera + +usb:v055FpC540* + ID_MODEL_FROM_DATABASE=gSmart D30 Camera + +usb:v055FpC630* + ID_MODEL_FROM_DATABASE=MDC 4000 Camera + +usb:v055FpC631* + ID_MODEL_FROM_DATABASE=MDC 4000 Camera + +usb:v055FpC650* + ID_MODEL_FROM_DATABASE=MDC 5500Z Camera + +usb:v055FpD001* + ID_MODEL_FROM_DATABASE=WCam 300 + +usb:v055FpD003* + ID_MODEL_FROM_DATABASE=WCam 300A + +usb:v055FpD004* + ID_MODEL_FROM_DATABASE=WCam 300AN + +usb:v0560* + ID_VENDOR_FROM_DATABASE=Interface Corp. + +usb:v0561* + ID_VENDOR_FROM_DATABASE=Oasis Design, Inc. + +usb:v0562* + ID_VENDOR_FROM_DATABASE=Telex Communications, Inc. + +usb:v0562p0001* + ID_MODEL_FROM_DATABASE=Enhanced Microphone + +usb:v0562p0002* + ID_MODEL_FROM_DATABASE=Telex Microphone + +usb:v0563* + ID_VENDOR_FROM_DATABASE=Immersion Corp. + +usb:v0564* + ID_VENDOR_FROM_DATABASE=Kodak Digital Product Center, Japan Ltd. (formerly Chinon Industries Inc.) + +usb:v0565* + ID_VENDOR_FROM_DATABASE=Peracom Networks, Inc. + +usb:v0565p0001* + ID_MODEL_FROM_DATABASE=Serial Port [etek] + +usb:v0565p0002* + ID_MODEL_FROM_DATABASE=Enet Ethernet [klsi] + +usb:v0565p0003* + ID_MODEL_FROM_DATABASE=@Home Networks Ethernet [klsi] + +usb:v0565p0005* + ID_MODEL_FROM_DATABASE=Enet2 Ethernet [klsi] + +usb:v0565p0041* + ID_MODEL_FROM_DATABASE=Peracom Remote NDIS Ethernet Adapter + +usb:v0566* + ID_VENDOR_FROM_DATABASE=Monterey International Corp. + +usb:v0566p0110* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1001* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1002* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1003* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1004* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1005* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1006* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p1007* + ID_MODEL_FROM_DATABASE=ViewMate Desktop Mouse CC2201 + +usb:v0566p2800* + ID_MODEL_FROM_DATABASE=MIC K/B + +usb:v0566p2801* + ID_MODEL_FROM_DATABASE=MIC K/B Mouse + +usb:v0566p2802* + ID_MODEL_FROM_DATABASE=Kbd Hub + +usb:v0566p3004* + ID_MODEL_FROM_DATABASE=Genius KB-29E + +usb:v0566p3107* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0567* + ID_VENDOR_FROM_DATABASE=Xyratex International, Ltd + +usb:v0568* + ID_VENDOR_FROM_DATABASE=Quartz Ingenierie + +usb:v0569* + ID_VENDOR_FROM_DATABASE=SegaSoft + +usb:v056A* + ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd + +usb:v056Ap0000* + ID_MODEL_FROM_DATABASE=PenPartner + +usb:v056Ap0001* + ID_MODEL_FROM_DATABASE=PenPartner 4x5 + +usb:v056Ap0002* + ID_MODEL_FROM_DATABASE=PenPartner 6x8 + +usb:v056Ap0003* + ID_MODEL_FROM_DATABASE=Cintiq Partner + +usb:v056Ap0010* + ID_MODEL_FROM_DATABASE=Graphire + +usb:v056Ap0011* + ID_MODEL_FROM_DATABASE=Graphire 2 4x5 + +usb:v056Ap0012* + ID_MODEL_FROM_DATABASE=Graphire 2 5x7 + +usb:v056Ap0013* + ID_MODEL_FROM_DATABASE=Graphire 3 4x5 + +usb:v056Ap0014* + ID_MODEL_FROM_DATABASE=Graphire 3 6x8 + +usb:v056Ap0015* + ID_MODEL_FROM_DATABASE=Graphire 4 4x5 + +usb:v056Ap0016* + ID_MODEL_FROM_DATABASE=Graphire 4 6x8 + +usb:v056Ap0017* + ID_MODEL_FROM_DATABASE=CTE-450 [Bamboo Fun] + +usb:v056Ap0018* + ID_MODEL_FROM_DATABASE=Bamboo Fun 6x8 + +usb:v056Ap0019* + ID_MODEL_FROM_DATABASE=Bamboo One Medium + +usb:v056Ap0020* + ID_MODEL_FROM_DATABASE=Intuos 4x5 + +usb:v056Ap0021* + ID_MODEL_FROM_DATABASE=Intuos 6x8 + +usb:v056Ap0022* + ID_MODEL_FROM_DATABASE=Intuos 9x12 + +usb:v056Ap0023* + ID_MODEL_FROM_DATABASE=Intuos 12x12 + +usb:v056Ap0024* + ID_MODEL_FROM_DATABASE=Intuos 12x18 + +usb:v056Ap0026* + ID_MODEL_FROM_DATABASE=Intuos5 touch S + +usb:v056Ap0027* + ID_MODEL_FROM_DATABASE=Intuos5 touch M + +usb:v056Ap0028* + ID_MODEL_FROM_DATABASE=Intuos5 touch L + +usb:v056Ap0029* + ID_MODEL_FROM_DATABASE=Intuos5 S + +usb:v056Ap002A* + ID_MODEL_FROM_DATABASE=Intuos5 M + +usb:v056Ap0030* + ID_MODEL_FROM_DATABASE=PL400 + +usb:v056Ap0031* + ID_MODEL_FROM_DATABASE=PL500 + +usb:v056Ap0032* + ID_MODEL_FROM_DATABASE=PL600 + +usb:v056Ap0033* + ID_MODEL_FROM_DATABASE=PL600SX + +usb:v056Ap0034* + ID_MODEL_FROM_DATABASE=PL550 + +usb:v056Ap0035* + ID_MODEL_FROM_DATABASE=PL800 + +usb:v056Ap0037* + ID_MODEL_FROM_DATABASE=PL700 + +usb:v056Ap0038* + ID_MODEL_FROM_DATABASE=PL510 + +usb:v056Ap0039* + ID_MODEL_FROM_DATABASE=DTU-710 + +usb:v056Ap003F* + ID_MODEL_FROM_DATABASE=Cintiq 21UX (DTZ-2100) + +usb:v056Ap0041* + ID_MODEL_FROM_DATABASE=Intuos2 4x5 + +usb:v056Ap0042* + ID_MODEL_FROM_DATABASE=Intuos2 6x8 + +usb:v056Ap0043* + ID_MODEL_FROM_DATABASE=Intuos2 9x12 + +usb:v056Ap0044* + ID_MODEL_FROM_DATABASE=Intuos2 12x12 + +usb:v056Ap0045* + ID_MODEL_FROM_DATABASE=Intuos2 12x18 + +usb:v056Ap0047* + ID_MODEL_FROM_DATABASE=Intuos2 6x8 + +usb:v056Ap0060* + ID_MODEL_FROM_DATABASE=Volito + +usb:v056Ap0061* + ID_MODEL_FROM_DATABASE=PenStation2 + +usb:v056Ap0062* + ID_MODEL_FROM_DATABASE=Volito2 4x5 + +usb:v056Ap0063* + ID_MODEL_FROM_DATABASE=Volito2 2x3 + +usb:v056Ap0064* + ID_MODEL_FROM_DATABASE=PenPartner2 + +usb:v056Ap0065* + ID_MODEL_FROM_DATABASE=Bamboo + +usb:v056Ap0069* + ID_MODEL_FROM_DATABASE=Bamboo One + +usb:v056Ap0081* + ID_MODEL_FROM_DATABASE=Graphire Wireless 6x8 + +usb:v056Ap0090* + ID_MODEL_FROM_DATABASE=TPC90 + +usb:v056Ap0093* + ID_MODEL_FROM_DATABASE=TPC93 + +usb:v056Ap009A* + ID_MODEL_FROM_DATABASE=TPC9A + +usb:v056Ap00B0* + ID_MODEL_FROM_DATABASE=Intuos3 4x5 + +usb:v056Ap00B1* + ID_MODEL_FROM_DATABASE=Intuos3 6x18 + +usb:v056Ap00B2* + ID_MODEL_FROM_DATABASE=Intuos3 9x12 + +usb:v056Ap00B3* + ID_MODEL_FROM_DATABASE=Intuos3 12x12 + +usb:v056Ap00B4* + ID_MODEL_FROM_DATABASE=Intuos3 12x19 + +usb:v056Ap00B5* + ID_MODEL_FROM_DATABASE=Intuos3 6x11 (PTZ-631W) + +usb:v056Ap00B7* + ID_MODEL_FROM_DATABASE=Intuos3 4x6 + +usb:v056Ap00B8* + ID_MODEL_FROM_DATABASE=Intuos4 4x6 + +usb:v056Ap00B9* + ID_MODEL_FROM_DATABASE=Intuos4 6x9 + +usb:v056Ap00BA* + ID_MODEL_FROM_DATABASE=Intuos4 8x13 + +usb:v056Ap00BB* + ID_MODEL_FROM_DATABASE=Intuos4 12x19 + +usb:v056Ap00C0* + ID_MODEL_FROM_DATABASE=DTF-521 + +usb:v056Ap00C4* + ID_MODEL_FROM_DATABASE=DTF-720 + +usb:v056Ap00C5* + ID_MODEL_FROM_DATABASE=Cintiq 20WSX + +usb:v056Ap00C6* + ID_MODEL_FROM_DATABASE=Cintiq 12WX + +usb:v056Ap00C7* + ID_MODEL_FROM_DATABASE=DTU-1931 + +usb:v056Ap00CC* + ID_MODEL_FROM_DATABASE=Cintiq 21UX (DTK-2100) + +usb:v056Ap00D1* + ID_MODEL_FROM_DATABASE=Bamboo Pen & Touch (CTH-460-DE) + +usb:v056Ap00D3* + ID_MODEL_FROM_DATABASE=Bamboo Fun (CTH-661) + +usb:v056Ap00D6* + ID_MODEL_FROM_DATABASE=Bamboo Pen & Touch (CTH-460) + +usb:v056Ap00DB* + ID_MODEL_FROM_DATABASE=Bamboo Fun (CTH-661SE-NL) + +usb:v056Ap00DD* + ID_MODEL_FROM_DATABASE=Bamboo Pen (CTL-470) + +usb:v056Ap00DE* + ID_MODEL_FROM_DATABASE=CTH-470 [Bamboo Fun Pen & Touch] + +usb:v056Ap00F6* + ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) touchscreen + +usb:v056Ap00F8* + ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) tablet + +usb:v056Ap0400* + ID_MODEL_FROM_DATABASE=PenPartner 4x5 + +usb:v056Ap4850* + ID_MODEL_FROM_DATABASE=PenPartner 6x8 + +usb:v056B* + ID_VENDOR_FROM_DATABASE=Decicon, Inc. + +usb:v056C* + ID_VENDOR_FROM_DATABASE=eTEK Labs + +usb:v056Cp0006* + ID_MODEL_FROM_DATABASE=KwikLink Host-Host Connector + +usb:v056Cp8007* + ID_MODEL_FROM_DATABASE=Kwik232 Serial Port + +usb:v056Cp8100* + ID_MODEL_FROM_DATABASE=KwikLink Host-Host Connector + +usb:v056Cp8101* + ID_MODEL_FROM_DATABASE=KwikLink USB-USB Bridge + +usb:v056D* + ID_VENDOR_FROM_DATABASE=EIZO Corp. + +usb:v056Dp0000* + ID_MODEL_FROM_DATABASE=Hub + +usb:v056Dp0001* + ID_MODEL_FROM_DATABASE=Monitor + +usb:v056Dp0002* + ID_MODEL_FROM_DATABASE=HID Monitor Controls + +usb:v056Dp0003* + ID_MODEL_FROM_DATABASE=Device Bay Controller + +usb:v056E* + ID_VENDOR_FROM_DATABASE=Elecom Co., Ltd + +usb:v056Ep0002* + ID_MODEL_FROM_DATABASE=29UO Mouse + +usb:v056Ep0072* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v056Ep200C* + ID_MODEL_FROM_DATABASE=LD-USB/TX + +usb:v056Ep4002* + ID_MODEL_FROM_DATABASE=Laneed 100Mbps Ethernet LD-USB/TX [pegasus] + +usb:v056Ep4005* + ID_MODEL_FROM_DATABASE=LD-USBL/TX + +usb:v056Ep400B* + ID_MODEL_FROM_DATABASE=LD-USB/TX + +usb:v056Ep4010* + ID_MODEL_FROM_DATABASE=LD-USB20 + +usb:v056Ep5003* + ID_MODEL_FROM_DATABASE=UC-SGT + +usb:v056Ep5004* + ID_MODEL_FROM_DATABASE=UC-SGT + +usb:v056Ep6008* + ID_MODEL_FROM_DATABASE=Flash Disk + +usb:v056EpABC1* + ID_MODEL_FROM_DATABASE=LD-USB/TX + +usb:v056F* + ID_VENDOR_FROM_DATABASE=Korea Data Systems Co., Ltd + +usb:v056FpCD00* + ID_MODEL_FROM_DATABASE=CDM-751 CD organizer + +usb:v0570* + ID_VENDOR_FROM_DATABASE=Epson America + +usb:v0571* + ID_VENDOR_FROM_DATABASE=Interex, Inc. + +usb:v0571p0002* + ID_MODEL_FROM_DATABASE=echoFX InterView Lite + +usb:v0572* + ID_VENDOR_FROM_DATABASE=Conexant Systems (Rockwell), Inc. + +usb:v0572p0001* + ID_MODEL_FROM_DATABASE=Ezcam II Webcam + +usb:v0572p0002* + ID_MODEL_FROM_DATABASE=Ezcam II Webcam + +usb:v0572p0040* + ID_MODEL_FROM_DATABASE=Wondereye CP-115 Webcam + +usb:v0572p0041* + ID_MODEL_FROM_DATABASE=Webcam Notebook + +usb:v0572p0042* + ID_MODEL_FROM_DATABASE=Webcam Notebook + +usb:v0572p1232* + ID_MODEL_FROM_DATABASE=V.90 modem + +usb:v0572p1234* + ID_MODEL_FROM_DATABASE=Typhoon Redfun Modem V90 56k + +usb:v0572p1252* + ID_MODEL_FROM_DATABASE=HCF V90 Data Fax Voice Modem + +usb:v0572p1253* + ID_MODEL_FROM_DATABASE=Zoom V.92 Faxmodem + +usb:v0572p1300* + ID_MODEL_FROM_DATABASE=SoftK56 Data Fax Voice CARP + +usb:v0572p1301* + ID_MODEL_FROM_DATABASE=Modem Enumerator + +usb:v0572p1328* + ID_MODEL_FROM_DATABASE=TrendNet TFM-561 modem + +usb:v0572p2000* + ID_MODEL_FROM_DATABASE=SoftGate 802.11 Adapter + +usb:v0572p2002* + ID_MODEL_FROM_DATABASE=SoftGate 802.11 Adapter + +usb:v0572p262A* + ID_MODEL_FROM_DATABASE=tm5600 Video & Audio Grabber Capture + +usb:v0572p8390* + ID_MODEL_FROM_DATABASE=WinFast PalmTop/Novo TV Video + +usb:v0572p8392* + ID_MODEL_FROM_DATABASE=WinFast PalmTop/Novo TV Video + +usb:v0572pCAFC* + ID_MODEL_FROM_DATABASE=CX861xx ROM Boot Loader + +usb:v0572pCAFE* + ID_MODEL_FROM_DATABASE=AccessRunner ADSL Modem + +usb:v0572pCB00* + ID_MODEL_FROM_DATABASE=ADSL Modem + +usb:v0572pCB01* + ID_MODEL_FROM_DATABASE=ADSL Modem + +usb:v0572pCB06* + ID_MODEL_FROM_DATABASE=StarModem Network Interface + +usb:v0573* + ID_VENDOR_FROM_DATABASE=Zoran Co. Personal Media Division (Nogatech) + +usb:v0573p0003* + ID_MODEL_FROM_DATABASE=USBGear USBG-V1 + +usb:v0573p0400* + ID_MODEL_FROM_DATABASE=D-Link V100 + +usb:v0573p0600* + ID_MODEL_FROM_DATABASE=Dazzle USBVision (1006) + +usb:v0573p1300* + ID_MODEL_FROM_DATABASE=leadtek USBVision (1006) + +usb:v0573p2000* + ID_MODEL_FROM_DATABASE=X10 va10a Wireless Camera + +usb:v0573p2001* + ID_MODEL_FROM_DATABASE=Dazzle EmMe (2001) + +usb:v0573p2101* + ID_MODEL_FROM_DATABASE=Zoran Co. PMD (Nogatech) AV-grabber Manhattan + +usb:v0573p2D00* + ID_MODEL_FROM_DATABASE=Osprey 50 + +usb:v0573p2D01* + ID_MODEL_FROM_DATABASE=Hauppauge USB-Live Model 600 + +usb:v0573p3000* + ID_MODEL_FROM_DATABASE=Dazzle MicroCam (NTSC) + +usb:v0573p3001* + ID_MODEL_FROM_DATABASE=Dazzle MicroCam (PAL) + +usb:v0573p4000* + ID_MODEL_FROM_DATABASE=Nogatech TV! (NTSC) + +usb:v0573p4001* + ID_MODEL_FROM_DATABASE=Nogatech TV! (PAL) + +usb:v0573p4002* + ID_MODEL_FROM_DATABASE=Nogatech TV! (PAL-I-) + +usb:v0573p4003* + ID_MODEL_FROM_DATABASE=Nogatech TV! (MF-) + +usb:v0573p4008* + ID_MODEL_FROM_DATABASE=Nogatech TV! (NTSC) (T) + +usb:v0573p4009* + ID_MODEL_FROM_DATABASE=Nogatech TV! (PAL) (T) + +usb:v0573p4010* + ID_MODEL_FROM_DATABASE=Nogatech TV! (NTSC) (A) + +usb:v0573p4100* + ID_MODEL_FROM_DATABASE=USB-TV FM (NTSC) + +usb:v0573p4110* + ID_MODEL_FROM_DATABASE=PNY USB-TV (NTSC) FM + +usb:v0573p4400* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (NTSC) + +usb:v0573p4401* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (PAL) + +usb:v0573p4450* + ID_MODEL_FROM_DATABASE=PixelView PlayTv-USB PRO (PAL) FM + +usb:v0573p4451* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (PAL+) + +usb:v0573p4452* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (PAL-I+) + +usb:v0573p4500* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (NTSC) + +usb:v0573p4501* + ID_MODEL_FROM_DATABASE=Nogatech TV! Pro (PAL) + +usb:v0573p4550* + ID_MODEL_FROM_DATABASE=ZTV ZT-721 2.4GHz A/V Receiver + +usb:v0573p4551* + ID_MODEL_FROM_DATABASE=Dazzle TV! Pro Audio (P+) + +usb:v0573p4D00* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB USA + +usb:v0573p4D01* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB + +usb:v0573p4D02* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB UK + +usb:v0573p4D03* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB France + +usb:v0573p4D04* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV (PAL D/K) + +usb:v0573p4D10* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB with FM USA radio + +usb:v0573p4D11* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB (PAL) with FM radio + +usb:v0573p4D12* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB UK with FM Radio + +usb:v0573p4D14* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV (PAL D/K FM) + +usb:v0573p4D20* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB II (PAL) with FM radio + +usb:v0573p4D21* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB II (PAL) + +usb:v0573p4D22* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB II (PAL) Model 566 + +usb:v0573p4D23* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB France 4D23 + +usb:v0573p4D24* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV Pro (PAL D/K) + +usb:v0573p4D25* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40209 rev B234 + +usb:v0573p4D26* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40209 rev B243 + +usb:v0573p4D27* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40204 Rev B281 + +usb:v0573p4D28* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40204 rev B283 + +usb:v0573p4D29* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40205 rev B298 + +usb:v0573p4D2A* + ID_MODEL_FROM_DATABASE=Hauppague WinTV-USB Model 602 Rev B285 + +usb:v0573p4D2B* + ID_MODEL_FROM_DATABASE=Hauppague WinTV-USB Model 602 Rev B282 + +usb:v0573p4D2C* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV Pro (PAL/SECAM) + +usb:v0573p4D30* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB FM Model 40211 Rev B123 + +usb:v0573p4D31* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB III (PAL) with FM radio Model 568 + +usb:v0573p4D32* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB III (PAL) FM Model 573 + +usb:v0573p4D34* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV Pro (PAL D/K FM) + +usb:v0573p4D35* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB III (PAL) FM Model 597 + +usb:v0573p4D36* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV Pro (PAL B/G FM) + +usb:v0573p4D37* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV-USB Model 40219 rev E189 + +usb:v0573p4D38* + ID_MODEL_FROM_DATABASE=Hauppauge WinTV Pro (NTSC FM) + +usb:v0574* + ID_VENDOR_FROM_DATABASE=City University of Hong Kong + +usb:v0575* + ID_VENDOR_FROM_DATABASE=Philips Creative Display Solutions + +usb:v0576* + ID_VENDOR_FROM_DATABASE=BAFO/Quality Computer Accessories + +usb:v0577* + ID_VENDOR_FROM_DATABASE=ELSA + +usb:v0578* + ID_VENDOR_FROM_DATABASE=Intrinsix Corp. + +usb:v0579* + ID_VENDOR_FROM_DATABASE=GVC Corp. + +usb:v057A* + ID_VENDOR_FROM_DATABASE=Samsung Electronics America + +usb:v057B* + ID_VENDOR_FROM_DATABASE=Y-E Data, Inc. + +usb:v057Bp0000* + ID_MODEL_FROM_DATABASE=FlashBuster-U Floppy + +usb:v057Bp0001* + ID_MODEL_FROM_DATABASE=Tri-Media Reader Floppy + +usb:v057Bp0006* + ID_MODEL_FROM_DATABASE=Tri-Media Reader Card Reader + +usb:v057Bp0010* + ID_MODEL_FROM_DATABASE=Memory Stick Reader Writer + +usb:v057Bp0020* + ID_MODEL_FROM_DATABASE=HEXA Media Drive 6-in-1 Card Reader Writer + +usb:v057Bp0030* + ID_MODEL_FROM_DATABASE=Memory Card Viewer (TV) + +usb:v057C* + ID_VENDOR_FROM_DATABASE=AVM GmbH + +usb:v057Cp0B00* + ID_MODEL_FROM_DATABASE=ISDN-Controller B1 Family + +usb:v057Cp0C00* + ID_MODEL_FROM_DATABASE=ISDN-Controller FRITZ!Card + +usb:v057Cp1000* + ID_MODEL_FROM_DATABASE=ISDN-Controller FRITZ!Card v2.0 + +usb:v057Cp1900* + ID_MODEL_FROM_DATABASE=ISDN-Controller FRITZ!Card v2.1 + +usb:v057Cp2000* + ID_MODEL_FROM_DATABASE=ISDN-Connector FRITZ!X + +usb:v057Cp2200* + ID_MODEL_FROM_DATABASE=BlueFRITZ! + +usb:v057Cp2300* + ID_MODEL_FROM_DATABASE=Teledat X130 DSL + +usb:v057Cp2800* + ID_MODEL_FROM_DATABASE=ISDN-Connector TA + +usb:v057Cp3200* + ID_MODEL_FROM_DATABASE=Teledat X130 DSL + +usb:v057Cp3500* + ID_MODEL_FROM_DATABASE=FRITZ!Card DSL SL + +usb:v057Cp3701* + ID_MODEL_FROM_DATABASE=FRITZ!Box SL + +usb:v057Cp3702* + ID_MODEL_FROM_DATABASE=FRITZ!Box + +usb:v057Cp3800* + ID_MODEL_FROM_DATABASE=BlueFRITZ! Bluetooth Stick + +usb:v057Cp3A00* + ID_MODEL_FROM_DATABASE=FRITZ!Box Fon + +usb:v057Cp3C00* + ID_MODEL_FROM_DATABASE=FRITZ!Box WLAN + +usb:v057Cp3D00* + ID_MODEL_FROM_DATABASE=Fritz!Box + +usb:v057Cp3E01* + ID_MODEL_FROM_DATABASE=FRITZ!Box (Annex A) + +usb:v057Cp4001* + ID_MODEL_FROM_DATABASE=FRITZ!Box Fon (Annex A) + +usb:v057Cp4101* + ID_MODEL_FROM_DATABASE=FRITZ!Box WLAN (Annex A) + +usb:v057Cp4201* + ID_MODEL_FROM_DATABASE=FRITZ!Box Fon WLAN (Annex A) + +usb:v057Cp4601* + ID_MODEL_FROM_DATABASE=Eumex 5520PC (WinXP/2000) + +usb:v057Cp4602* + ID_MODEL_FROM_DATABASE=Eumex 400 (WinXP/2000) + +usb:v057Cp4701* + ID_MODEL_FROM_DATABASE=AVM FRITZ!Box Fon ata + +usb:v057Cp5401* + ID_MODEL_FROM_DATABASE=Eumex 300 IP + +usb:v057Cp5601* + ID_MODEL_FROM_DATABASE=AVM Fritz!WLAN [Texas Instruments TNETW1450] + +usb:v057Cp6201* + ID_MODEL_FROM_DATABASE=AVM Fritz!WLAN v1.1 [Texas Instruments TNETW1450] + +usb:v057Cp62FF* + ID_MODEL_FROM_DATABASE=AVM Fritz!WLAN USB (in CD-ROM-mode) + +usb:v057Cp8401* + ID_MODEL_FROM_DATABASE=Fritz!WLAN N [Atheros AR9001U] + +usb:v057Cp8402* + ID_MODEL_FROM_DATABASE=Fritz!WLAN N 2.4 [Atheros AR9001U] + +usb:v057Cp8403* + ID_MODEL_FROM_DATABASE=Fritz!WLAN N v2 [Atheros AR9271] + +usb:v057Cp84FF* + ID_MODEL_FROM_DATABASE=AVM Fritz!WLAN USB N (in CD-ROM-mode) + +usb:v057D* + ID_VENDOR_FROM_DATABASE=Shark Multimedia, Inc. + +usb:v057E* + ID_VENDOR_FROM_DATABASE=Nintendo Co., Ltd + +usb:v057Ep0305* + ID_MODEL_FROM_DATABASE=Broadcom BCM2045A Bluetooth Radio [Nintendo Wii] + +usb:v057Ep0306* + ID_MODEL_FROM_DATABASE=Wii Remote Controller RVL-003 + +usb:v057F* + ID_VENDOR_FROM_DATABASE=QuickShot, Ltd + +usb:v057Fp6238* + ID_MODEL_FROM_DATABASE=USB StrikePad + +usb:v0580* + ID_VENDOR_FROM_DATABASE=Denron, Inc. + +usb:v0581* + ID_VENDOR_FROM_DATABASE=Racal Data Group + +usb:v0582* + ID_VENDOR_FROM_DATABASE=Roland Corp. + +usb:v0582p0000* + ID_MODEL_FROM_DATABASE=UA-100(G) + +usb:v0582p0002* + ID_MODEL_FROM_DATABASE=UM-4/MPU-64 MIDI Interface + +usb:v0582p0003* + ID_MODEL_FROM_DATABASE=SoundCanvas SC-8850 + +usb:v0582p0004* + ID_MODEL_FROM_DATABASE=U-8 + +usb:v0582p0005* + ID_MODEL_FROM_DATABASE=UM-2(C/EX) + +usb:v0582p0007* + ID_MODEL_FROM_DATABASE=SoundCanvas SC-8820 + +usb:v0582p0008* + ID_MODEL_FROM_DATABASE=PC-300 + +usb:v0582p0009* + ID_MODEL_FROM_DATABASE=UM-1(E/S/X) + +usb:v0582p000B* + ID_MODEL_FROM_DATABASE=SK-500 + +usb:v0582p000C* + ID_MODEL_FROM_DATABASE=SC-D70 + +usb:v0582p0010* + ID_MODEL_FROM_DATABASE=EDIROL UA-5 + +usb:v0582p0011* + ID_MODEL_FROM_DATABASE=Edirol UA-5 Sound Capture + +usb:v0582p0012* + ID_MODEL_FROM_DATABASE=XV-5050 + +usb:v0582p0013* + ID_MODEL_FROM_DATABASE=XV-5050 + +usb:v0582p0014* + ID_MODEL_FROM_DATABASE=EDIROL UM-880 MIDI I/F (native) + +usb:v0582p0015* + ID_MODEL_FROM_DATABASE=EDIROL UM-880 MIDI I/F (generic) + +usb:v0582p0016* + ID_MODEL_FROM_DATABASE=EDIROL SD-90 + +usb:v0582p0017* + ID_MODEL_FROM_DATABASE=EDIROL SD-90 + +usb:v0582p0018* + ID_MODEL_FROM_DATABASE=UA-1A + +usb:v0582p001B* + ID_MODEL_FROM_DATABASE=MMP-2 + +usb:v0582p001C* + ID_MODEL_FROM_DATABASE=MMP-2 + +usb:v0582p001D* + ID_MODEL_FROM_DATABASE=V-SYNTH + +usb:v0582p001E* + ID_MODEL_FROM_DATABASE=V-SYNTH + +usb:v0582p0023* + ID_MODEL_FROM_DATABASE=EDIROL UM-550 + +usb:v0582p0024* + ID_MODEL_FROM_DATABASE=EDIROL UM-550 + +usb:v0582p0025* + ID_MODEL_FROM_DATABASE=EDIROL UA-20 + +usb:v0582p0026* + ID_MODEL_FROM_DATABASE=EDIROL UA-20 + +usb:v0582p0027* + ID_MODEL_FROM_DATABASE=EDIROL SD-20 + +usb:v0582p0028* + ID_MODEL_FROM_DATABASE=EDIROL SD-20 + +usb:v0582p0029* + ID_MODEL_FROM_DATABASE=EDIROL SD-80 + +usb:v0582p002A* + ID_MODEL_FROM_DATABASE=EDIROL SD-80 + +usb:v0582p002B* + ID_MODEL_FROM_DATABASE=EDIROL UA-700 + +usb:v0582p002C* + ID_MODEL_FROM_DATABASE=EDIROL UA-700 + +usb:v0582p002D* + ID_MODEL_FROM_DATABASE=XV-2020 Synthesizer + +usb:v0582p002E* + ID_MODEL_FROM_DATABASE=XV-2020 Synthesizer + +usb:v0582p002F* + ID_MODEL_FROM_DATABASE=VariOS + +usb:v0582p0030* + ID_MODEL_FROM_DATABASE=VariOS + +usb:v0582p0033* + ID_MODEL_FROM_DATABASE=EDIROL PCR + +usb:v0582p0034* + ID_MODEL_FROM_DATABASE=EDIROL PCR + +usb:v0582p0035* + ID_MODEL_FROM_DATABASE=M-1000 + +usb:v0582p0037* + ID_MODEL_FROM_DATABASE=Digital Piano + +usb:v0582p0038* + ID_MODEL_FROM_DATABASE=Digital Piano + +usb:v0582p003B* + ID_MODEL_FROM_DATABASE=BOSS GS-10 + +usb:v0582p003C* + ID_MODEL_FROM_DATABASE=BOSS GS-10 + +usb:v0582p0040* + ID_MODEL_FROM_DATABASE=GI-20 + +usb:v0582p0041* + ID_MODEL_FROM_DATABASE=GI-20 + +usb:v0582p0042* + ID_MODEL_FROM_DATABASE=RS-70 + +usb:v0582p0043* + ID_MODEL_FROM_DATABASE=RS-70 + +usb:v0582p0044* + ID_MODEL_FROM_DATABASE=EDIROL UA-1000 + +usb:v0582p0047* + ID_MODEL_FROM_DATABASE=EDIROL UR-80 WAVE + +usb:v0582p0048* + ID_MODEL_FROM_DATABASE=EDIROL UR-80 MIDI + +usb:v0582p0049* + ID_MODEL_FROM_DATABASE=EDIROL UR-80 WAVE + +usb:v0582p004A* + ID_MODEL_FROM_DATABASE=EDIROL UR-80 MIDI + +usb:v0582p004B* + ID_MODEL_FROM_DATABASE=EDIROL M-100FX + +usb:v0582p004C* + ID_MODEL_FROM_DATABASE=EDIROL PCR-A WAVE + +usb:v0582p004D* + ID_MODEL_FROM_DATABASE=EDIROL PCR-A MIDI + +usb:v0582p004E* + ID_MODEL_FROM_DATABASE=EDIROL PCR-A WAVE + +usb:v0582p004F* + ID_MODEL_FROM_DATABASE=EDIROL PCR-A MIDI + +usb:v0582p0050* + ID_MODEL_FROM_DATABASE=EDIROL UA-3FX + +usb:v0582p0052* + ID_MODEL_FROM_DATABASE=EDIROL UM-1SX + +usb:v0582p0054* + ID_MODEL_FROM_DATABASE=Digital Piano + +usb:v0582p0060* + ID_MODEL_FROM_DATABASE=EXR Series + +usb:v0582p0064* + ID_MODEL_FROM_DATABASE=EDIROL PCR-1 WAVE + +usb:v0582p0065* + ID_MODEL_FROM_DATABASE=EDIROL PCR-1 MIDI + +usb:v0582p0066* + ID_MODEL_FROM_DATABASE=EDIROL PCR-1 WAVE + +usb:v0582p0067* + ID_MODEL_FROM_DATABASE=EDIROL PCR-1 MIDI + +usb:v0582p006A* + ID_MODEL_FROM_DATABASE=SP-606 + +usb:v0582p006B* + ID_MODEL_FROM_DATABASE=SP-606 + +usb:v0582p006D* + ID_MODEL_FROM_DATABASE=FANTOM-X + +usb:v0582p006E* + ID_MODEL_FROM_DATABASE=FANTOM-X + +usb:v0582p0073* + ID_MODEL_FROM_DATABASE=EDIROL UA-25 + +usb:v0582p0074* + ID_MODEL_FROM_DATABASE=EDIROL UA-25 + +usb:v0582p0075* + ID_MODEL_FROM_DATABASE=BOSS DR-880 + +usb:v0582p0076* + ID_MODEL_FROM_DATABASE=BOSS DR-880 + +usb:v0582p007A* + ID_MODEL_FROM_DATABASE=RD + +usb:v0582p007B* + ID_MODEL_FROM_DATABASE=RD + +usb:v0582p007D* + ID_MODEL_FROM_DATABASE=EDIROL UA-101 + +usb:v0582p0080* + ID_MODEL_FROM_DATABASE=G-70 + +usb:v0582p0081* + ID_MODEL_FROM_DATABASE=G-70 + +usb:v0582p0084* + ID_MODEL_FROM_DATABASE=V-SYNTH XT + +usb:v0582p0089* + ID_MODEL_FROM_DATABASE=BOSS GT-PRO + +usb:v0582p008B* + ID_MODEL_FROM_DATABASE=EDIROL PC-50 + +usb:v0582p008C* + ID_MODEL_FROM_DATABASE=EDIROL PC-50 + +usb:v0582p008D* + ID_MODEL_FROM_DATABASE=EDIROL UA-101 USB1 + +usb:v0582p0092* + ID_MODEL_FROM_DATABASE=EDIROL PC-80 WAVE + +usb:v0582p0093* + ID_MODEL_FROM_DATABASE=EDIROL PC-80 MIDI + +usb:v0582p0096* + ID_MODEL_FROM_DATABASE=EDIROL UA-1EX + +usb:v0582p009A* + ID_MODEL_FROM_DATABASE=EDIROL UM-3EX + +usb:v0582p009D* + ID_MODEL_FROM_DATABASE=EDIROL UM-1 + +usb:v0582p00A0* + ID_MODEL_FROM_DATABASE=MD-P1 + +usb:v0582p00A2* + ID_MODEL_FROM_DATABASE=Digital Piano + +usb:v0582p00A3* + ID_MODEL_FROM_DATABASE=EDIROL UA-4FX + +usb:v0582p00A6* + ID_MODEL_FROM_DATABASE=Juno-G + +usb:v0582p00A9* + ID_MODEL_FROM_DATABASE=MC-808 + +usb:v0582p00AD* + ID_MODEL_FROM_DATABASE=SH-201 + +usb:v0582p00B2* + ID_MODEL_FROM_DATABASE=VG-99 + +usb:v0582p00B3* + ID_MODEL_FROM_DATABASE=VG-99 + +usb:v0582p00B7* + ID_MODEL_FROM_DATABASE=BK-7m/VIMA JM-5/8 + +usb:v0582p00C2* + ID_MODEL_FROM_DATABASE=SonicCell + +usb:v0582p00C4* + ID_MODEL_FROM_DATABASE=EDIROL M-16DX + +usb:v0582p00C5* + ID_MODEL_FROM_DATABASE=SP-555 + +usb:v0582p00C7* + ID_MODEL_FROM_DATABASE=V-Synth GT + +usb:v0582p00D1* + ID_MODEL_FROM_DATABASE=Music Atelier + +usb:v0582p00D3* + ID_MODEL_FROM_DATABASE=M-380/400 + +usb:v0582p00DA* + ID_MODEL_FROM_DATABASE=BOSS GT-10 + +usb:v0582p00DB* + ID_MODEL_FROM_DATABASE=BOSS GT-10 Guitar Effects Processor + +usb:v0582p00DC* + ID_MODEL_FROM_DATABASE=BOSS GT-10B + +usb:v0582p00DE* + ID_MODEL_FROM_DATABASE=Fantom G + +usb:v0582p00E6* + ID_MODEL_FROM_DATABASE=EDIROL UA-25EX (Advanced mode) + +usb:v0582p00E7* + ID_MODEL_FROM_DATABASE=EDIROL UA-25EX + +usb:v0582p00E9* + ID_MODEL_FROM_DATABASE=UA-1G + +usb:v0582p00EB* + ID_MODEL_FROM_DATABASE=VS-100 + +usb:v0582p00F6* + ID_MODEL_FROM_DATABASE=GW-8/AX-Synth + +usb:v0582p00F8* + ID_MODEL_FROM_DATABASE=JUNO Series + +usb:v0582p00FC* + ID_MODEL_FROM_DATABASE=VS-700C + +usb:v0582p00FD* + ID_MODEL_FROM_DATABASE=VS-700 + +usb:v0582p00FE* + ID_MODEL_FROM_DATABASE=VS-700 M1 + +usb:v0582p00FF* + ID_MODEL_FROM_DATABASE=VS-700 M2 + +usb:v0582p0100* + ID_MODEL_FROM_DATABASE=VS-700 + +usb:v0582p0101* + ID_MODEL_FROM_DATABASE=VS-700 M2 + +usb:v0582p0102* + ID_MODEL_FROM_DATABASE=VB-99 + +usb:v0582p0104* + ID_MODEL_FROM_DATABASE=UM-1G + +usb:v0582p0106* + ID_MODEL_FROM_DATABASE=UM-2G + +usb:v0582p0108* + ID_MODEL_FROM_DATABASE=UM-3G + +usb:v0582p0109* + ID_MODEL_FROM_DATABASE=eBand JS-8 + +usb:v0582p010D* + ID_MODEL_FROM_DATABASE=A-500S + +usb:v0582p010F* + ID_MODEL_FROM_DATABASE=A-PRO + +usb:v0582p0110* + ID_MODEL_FROM_DATABASE=A-PRO + +usb:v0582p0111* + ID_MODEL_FROM_DATABASE=GAIA SH-01 + +usb:v0582p0113* + ID_MODEL_FROM_DATABASE=ME-25 + +usb:v0582p0114* + ID_MODEL_FROM_DATABASE=SD-50 + +usb:v0582p0116* + ID_MODEL_FROM_DATABASE=WAVE/MP3 RECORDER R-05 + +usb:v0582p0117* + ID_MODEL_FROM_DATABASE=VS-20 + +usb:v0582p0119* + ID_MODEL_FROM_DATABASE=OCTAPAD SPD-30 + +usb:v0582p011C* + ID_MODEL_FROM_DATABASE=Lucina AX-09 + +usb:v0582p011E* + ID_MODEL_FROM_DATABASE=BR-800 + +usb:v0582p0120* + ID_MODEL_FROM_DATABASE=OCTA-CAPTURE + +usb:v0582p0121* + ID_MODEL_FROM_DATABASE=OCTA-CAPTURE + +usb:v0582p0123* + ID_MODEL_FROM_DATABASE=JUNO-Gi + +usb:v0582p0124* + ID_MODEL_FROM_DATABASE=M-300 + +usb:v0582p0127* + ID_MODEL_FROM_DATABASE=GR-55 + +usb:v0582p012A* + ID_MODEL_FROM_DATABASE=UM-ONE + +usb:v0582p012B* + ID_MODEL_FROM_DATABASE=DUO-CAPTURE + +usb:v0582p012F* + ID_MODEL_FROM_DATABASE=QUAD-CAPTURE + +usb:v0582p0130* + ID_MODEL_FROM_DATABASE=MICRO BR BR-80 + +usb:v0582p0132* + ID_MODEL_FROM_DATABASE=TRI-CAPTURE + +usb:v0582p0134* + ID_MODEL_FROM_DATABASE=V-Mixer + +usb:v0582p0138* + ID_MODEL_FROM_DATABASE=Boss RC-300 (Audio mode) + +usb:v0582p0139* + ID_MODEL_FROM_DATABASE=Boss RC-300 (Storage mode) + +usb:v0582p013A* + ID_MODEL_FROM_DATABASE=JUPITER-80 + +usb:v0582p013E* + ID_MODEL_FROM_DATABASE=R-26 + +usb:v0582p0145* + ID_MODEL_FROM_DATABASE=SPD-SX + +usb:v0582p014B* + ID_MODEL_FROM_DATABASE=eBand JS-10 + +usb:v0582p014D* + ID_MODEL_FROM_DATABASE=GT-100 + +usb:v0582p0150* + ID_MODEL_FROM_DATABASE=TD-15 + +usb:v0582p0151* + ID_MODEL_FROM_DATABASE=TD-11 + +usb:v0582p0154* + ID_MODEL_FROM_DATABASE=JUPITER-50 + +usb:v0582p0156* + ID_MODEL_FROM_DATABASE=A-Series + +usb:v0582p0158* + ID_MODEL_FROM_DATABASE=TD-30 + +usb:v0582p0159* + ID_MODEL_FROM_DATABASE=DUO-CAPTURE EX + +usb:v0582p015B* + ID_MODEL_FROM_DATABASE=INTEGRA-7 + +usb:v0582p015D* + ID_MODEL_FROM_DATABASE=R-88 + +usb:v0582p0505* + ID_MODEL_FROM_DATABASE=EDIROL UA-101 + +usb:v0583* + ID_VENDOR_FROM_DATABASE=Padix Co., Ltd (Rockfire) + +usb:v0583p0001* + ID_MODEL_FROM_DATABASE=4 Axis 12 button +POV + +usb:v0583p0002* + ID_MODEL_FROM_DATABASE=4 Axis 12 button +POV + +usb:v0583p2030* + ID_MODEL_FROM_DATABASE=RM-203 USB Nest [mode 1] + +usb:v0583p2031* + ID_MODEL_FROM_DATABASE=RM-203 USB Nest [mode 2] + +usb:v0583p2032* + ID_MODEL_FROM_DATABASE=RM-203 USB Nest [mode 3] + +usb:v0583p2033* + ID_MODEL_FROM_DATABASE=RM-203 USB Nest [mode 4] + +usb:v0583p2050* + ID_MODEL_FROM_DATABASE=PX-205 PSX Bridge + +usb:v0583p205F* + ID_MODEL_FROM_DATABASE=PSX/USB converter + +usb:v0583p206F* + ID_MODEL_FROM_DATABASE=USB, 2-axis 8-button gamepad + +usb:v0583p3050* + ID_MODEL_FROM_DATABASE=QF-305u Gamepad + +usb:v0583p3379* + ID_MODEL_FROM_DATABASE=Rockfire X-Force + +usb:v0583p337F* + ID_MODEL_FROM_DATABASE=Rockfire USB RacingStar Vibra + +usb:v0583p509F* + ID_MODEL_FROM_DATABASE=USB,4-Axis,12-Button with POV + +usb:v0583p5259* + ID_MODEL_FROM_DATABASE=Rockfire USB SkyShuttle Vibra + +usb:v0583p525F* + ID_MODEL_FROM_DATABASE=USB Vibration Pad + +usb:v0583p5308* + ID_MODEL_FROM_DATABASE=USB Wireless VibrationPad + +usb:v0583p5359* + ID_MODEL_FROM_DATABASE=Rockfire USB SkyShuttle Pro + +usb:v0583p535F* + ID_MODEL_FROM_DATABASE=USB,real VibrationPad + +usb:v0583p5659* + ID_MODEL_FROM_DATABASE=Rockfire USB SkyShuttle Vibra + +usb:v0583p565F* + ID_MODEL_FROM_DATABASE=USB VibrationPad + +usb:v0583p6009* + ID_MODEL_FROM_DATABASE=Revenger + +usb:v0583p600F* + ID_MODEL_FROM_DATABASE=USB,GameBoard II + +usb:v0583p6258* + ID_MODEL_FROM_DATABASE=USB, 4-axis, 6-button joystick w/view finder + +usb:v0583p6889* + ID_MODEL_FROM_DATABASE=Windstorm Pro + +usb:v0583p688F* + ID_MODEL_FROM_DATABASE=QF-688uv Windstorm Pro Joystick + +usb:v0583p7070* + ID_MODEL_FROM_DATABASE=QF-707u Bazooka Joystick + +usb:v0583pA000* + ID_MODEL_FROM_DATABASE=MaxFire G-08XU Gamepad + +usb:v0583pA015* + ID_MODEL_FROM_DATABASE=4-Axis,16-Button with POV + +usb:v0583pA019* + ID_MODEL_FROM_DATABASE=USB, Vibration ,4-axis, 8-button joystick w/view finder + +usb:v0583pA020* + ID_MODEL_FROM_DATABASE=USB,4-Axis,10-Button with POV + +usb:v0583pA021* + ID_MODEL_FROM_DATABASE=USB,4-Axis,12-Button with POV + +usb:v0583pA022* + ID_MODEL_FROM_DATABASE=USB,4-Axis,14-Button with POV + +usb:v0583pA023* + ID_MODEL_FROM_DATABASE=USB,4-Axis,16-Button with POV + +usb:v0583pA024* + ID_MODEL_FROM_DATABASE=4axis,12button vibrition audio gamepad + +usb:v0583pA025* + ID_MODEL_FROM_DATABASE=4axis,12button vibrition audio gamepad + +usb:v0583pA130* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Gamepad + +usb:v0583pA131* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Joystick + +usb:v0583pA132* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Wheelpad + +usb:v0583pA133* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Wheel&Gamepad + +usb:v0583pA202* + ID_MODEL_FROM_DATABASE=ForceFeedbackWheel + +usb:v0583pA209* + ID_MODEL_FROM_DATABASE=MetalStrike FF + +usb:v0583pB000* + ID_MODEL_FROM_DATABASE=USB,4-Axis,12-Button with POV + +usb:v0583pB001* + ID_MODEL_FROM_DATABASE=USB,4-Axis,12-Button with POV + +usb:v0583pB002* + ID_MODEL_FROM_DATABASE=Vibration,12-Button USB Wheel + +usb:v0583pB005* + ID_MODEL_FROM_DATABASE=USB,12-Button Wheel + +usb:v0583pB008* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Wheel + +usb:v0583pB009* + ID_MODEL_FROM_DATABASE=USB,12-Button Wheel + +usb:v0583pB00A* + ID_MODEL_FROM_DATABASE=PSX/USB converter + +usb:v0583pB00B* + ID_MODEL_FROM_DATABASE=PSX/USB converter + +usb:v0583pB00C* + ID_MODEL_FROM_DATABASE=PSX/USB converter + +usb:v0583pB00D* + ID_MODEL_FROM_DATABASE=PSX/USB converter + +usb:v0583pB00E* + ID_MODEL_FROM_DATABASE=4-Axis,12-Button with POV + +usb:v0583pB00F* + ID_MODEL_FROM_DATABASE=USB,5-Axis,10-Button with POV + +usb:v0583pB010* + ID_MODEL_FROM_DATABASE=MetalStrike Pro + +usb:v0583pB012* + ID_MODEL_FROM_DATABASE=Wireless MetalStrike + +usb:v0583pB013* + ID_MODEL_FROM_DATABASE=USB,Wiress 2.4GHZ Joystick + +usb:v0583pB016* + ID_MODEL_FROM_DATABASE=USB,5-Axis,10-Button with POV + +usb:v0583pB018* + ID_MODEL_FROM_DATABASE=TW6 Wheel + +usb:v0583pFF60* + ID_MODEL_FROM_DATABASE=USB Wireless VibrationPad + +usb:v0584* + ID_VENDOR_FROM_DATABASE=RATOC System, Inc. + +usb:v0584p0008* + ID_MODEL_FROM_DATABASE=Fujifilm MemoryCard ReaderWriter + +usb:v0584p0220* + ID_MODEL_FROM_DATABASE=U2SCX SCSI Converter + +usb:v0584pB000* + ID_MODEL_FROM_DATABASE=REX-USB60 + +usb:v0584pB020* + ID_MODEL_FROM_DATABASE=REX-USB60F + +usb:v0585* + ID_VENDOR_FROM_DATABASE=FlashPoint Technology, Inc. + +usb:v0585p0001* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0002* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0003* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0004* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0005* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0006* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0007* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0008* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p0009* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000A* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000B* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000C* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000D* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000E* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0585p000F* + ID_MODEL_FROM_DATABASE=Digital Camera + +usb:v0586* + ID_VENDOR_FROM_DATABASE=ZyXEL Communications Corp. + +usb:v0586p0025* + ID_MODEL_FROM_DATABASE=802.11b/g/n USB Wireless Network Adapter + +usb:v0586p0102* + ID_MODEL_FROM_DATABASE=omni.net II ISDN TA + +usb:v0586p1000* + ID_MODEL_FROM_DATABASE=Omni NET Modem / ISDN TA + +usb:v0586p1500* + ID_MODEL_FROM_DATABASE=Omni 56K Plus + +usb:v0586p2011* + ID_MODEL_FROM_DATABASE=Scorpion-980N keyboard + +usb:v0586p3304* + ID_MODEL_FROM_DATABASE=LAN Modem + +usb:v0586p3309* + ID_MODEL_FROM_DATABASE=ADSL Modem Prestige 600 series + +usb:v0586p330A* + ID_MODEL_FROM_DATABASE=ADSL Modem Interface + +usb:v0586p330E* + ID_MODEL_FROM_DATABASE=USB Broadband ADSL Modem Rev 1.10 + +usb:v0586p3400* + ID_MODEL_FROM_DATABASE=ZyAIR B-220 IEEE 802.11b Adapter + +usb:v0586p3401* + ID_MODEL_FROM_DATABASE=ZyAIR G-220 802.11bg + +usb:v0586p3402* + ID_MODEL_FROM_DATABASE=ZyAIR G-220F 802.11bg + +usb:v0586p3403* + ID_MODEL_FROM_DATABASE=AG-200 802.11abg Wireless Adapter [Atheros AR5523] + +usb:v0586p3407* + ID_MODEL_FROM_DATABASE=G-200 v2 802.11bg + +usb:v0586p3408* + ID_MODEL_FROM_DATABASE=G-260 802.11bg + +usb:v0586p3409* + ID_MODEL_FROM_DATABASE=AG-225H 802.11bg + +usb:v0586p340A* + ID_MODEL_FROM_DATABASE=M-202 802.11bg + +usb:v0586p340C* + ID_MODEL_FROM_DATABASE=G-270S 802.11bg Wireless Adapter [Atheros AR5523] + +usb:v0586p340F* + ID_MODEL_FROM_DATABASE=G-220 v2 802.11bg + +usb:v0586p3410* + ID_MODEL_FROM_DATABASE=ZyAIR G-202 802.11bg + +usb:v0586p3412* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v0586p3413* + ID_MODEL_FROM_DATABASE=ZyAIR AG-225H v2 802.11bg + +usb:v0586p3415* + ID_MODEL_FROM_DATABASE=G-210H 802.11g Wireless Adapter + +usb:v0586p3416* + ID_MODEL_FROM_DATABASE=NWD-210N 802.11b/g/n-draft wireless adapter + +usb:v0586p3417* + ID_MODEL_FROM_DATABASE=NWD271N 802.11n Wireless Adapter [Atheros AR9001U-(2)NG] + +usb:v0586p3418* + ID_MODEL_FROM_DATABASE=NWD211AN 802.11abgn Wireless Adapter [Ralink RT2870] + +usb:v0586p3419* + ID_MODEL_FROM_DATABASE=G-220 v3 802.11bg Wireless Adapter [ZyDAS ZD1211B] + +usb:v0586p341A* + ID_MODEL_FROM_DATABASE=NWD-270N Wireless N-lite USB Adapter + +usb:v0586p341E* + ID_MODEL_FROM_DATABASE=NWD2105 802.11bgn Wireless Adapter [Ralink RT3070] + +usb:v0586p341F* + ID_MODEL_FROM_DATABASE=NWD2205 802.11n Wireless N Adapter [Realtek RTL8192CU] + +usb:v0586p343E* + ID_MODEL_FROM_DATABASE=N220 802.11bgn Wireless Adapter + +usb:v0587* + ID_VENDOR_FROM_DATABASE=America Kotobuki Electronics Industries, Inc. + +usb:v0588* + ID_VENDOR_FROM_DATABASE=Sapien Design + +usb:v0589* + ID_VENDOR_FROM_DATABASE=Victron + +usb:v058A* + ID_VENDOR_FROM_DATABASE=Nohau Corp. + +usb:v058B* + ID_VENDOR_FROM_DATABASE=Infineon Technologies + +usb:v058Bp001C* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v058C* + ID_VENDOR_FROM_DATABASE=In Focus Systems + +usb:v058Cp0007* + ID_MODEL_FROM_DATABASE=Flash + +usb:v058Cp0008* + ID_MODEL_FROM_DATABASE=LP130 + +usb:v058Cp000A* + ID_MODEL_FROM_DATABASE=LP530 + +usb:v058Cp0010* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0011* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0012* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0013* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0014* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0015* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0016* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0017* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0018* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp0019* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001A* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001B* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001C* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001D* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001E* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058Cp001F* + ID_MODEL_FROM_DATABASE=Projector + +usb:v058CpFFE5* + ID_MODEL_FROM_DATABASE=IN34 Projector + +usb:v058D* + ID_VENDOR_FROM_DATABASE=Micrel Semiconductor + +usb:v058E* + ID_VENDOR_FROM_DATABASE=Tripath Technology, Inc. + +usb:v058F* + ID_VENDOR_FROM_DATABASE=Alcor Micro Corp. + +usb:v058Fp1234* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v058Fp2412* + ID_MODEL_FROM_DATABASE=SCard R/W CSR-145 + +usb:v058Fp2802* + ID_MODEL_FROM_DATABASE=Monterey Keyboard + +usb:v058Fp5492* + ID_MODEL_FROM_DATABASE=Hub + +usb:v058Fp6232* + ID_MODEL_FROM_DATABASE=Hi-Speed 16-in-1 Flash Card Reader/Writer + +usb:v058Fp6254* + ID_MODEL_FROM_DATABASE=USB Hub + +usb:v058Fp6331* + ID_MODEL_FROM_DATABASE=SD/MMC/MS Card Reader + +usb:v058Fp6332* + ID_MODEL_FROM_DATABASE=Multi-Function Card Reader + +usb:v058Fp6335* + ID_MODEL_FROM_DATABASE=SD/MMC Card Reader + +usb:v058Fp6360* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v058Fp6361* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v058Fp6362* + ID_MODEL_FROM_DATABASE=Flash Card Reader/Writer + +usb:v058Fp6364* + ID_MODEL_FROM_DATABASE=AU6477 Card Reader Controller + +usb:v058Fp6366* + ID_MODEL_FROM_DATABASE=Multi Flash Reader + +usb:v058Fp6377* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v058Fp6386* + ID_MODEL_FROM_DATABASE=Memory Card + +usb:v058Fp6387* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v058Fp6390* + ID_MODEL_FROM_DATABASE=USB 2.0-IDE bridge + +usb:v058Fp9213* + ID_MODEL_FROM_DATABASE=MacAlly Kbd Hub + +usb:v058Fp9215* + ID_MODEL_FROM_DATABASE=AU9814 Hub + +usb:v058Fp9254* + ID_MODEL_FROM_DATABASE=Hub + +usb:v058Fp9310* + ID_MODEL_FROM_DATABASE=Mass Storage (UID4/5A & UID7A) + +usb:v058Fp9320* + ID_MODEL_FROM_DATABASE=Micro Storage Driver for Win98 + +usb:v058Fp9321* + ID_MODEL_FROM_DATABASE=Micro Storage Driver for Win98 + +usb:v058Fp9330* + ID_MODEL_FROM_DATABASE=SD Reader + +usb:v058Fp9331* + ID_MODEL_FROM_DATABASE=Micro Storage Driver for Win98 + +usb:v058Fp9340* + ID_MODEL_FROM_DATABASE=Delkin eFilm Reader-32 + +usb:v058Fp9350* + ID_MODEL_FROM_DATABASE=Delkin eFilm Reader-32 + +usb:v058Fp9360* + ID_MODEL_FROM_DATABASE=8-in-1 Media Card Reader + +usb:v058Fp9361* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v058Fp9368* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v058Fp9380* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v058Fp9382* + ID_MODEL_FROM_DATABASE=Acer/Sweex Flash drive + +usb:v058Fp9384* + ID_MODEL_FROM_DATABASE=qdi U2Disk T209M + +usb:v058Fp9410* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v058Fp9472* + ID_MODEL_FROM_DATABASE=Keyboard Hub + +usb:v058Fp9510* + ID_MODEL_FROM_DATABASE=ChunghwaTL USB02 Smartcard Reader + +usb:v058Fp9520* + ID_MODEL_FROM_DATABASE=EMV Certified Smart Card Reader + +usb:v058Fp9720* + ID_MODEL_FROM_DATABASE=USB-Serial Adapter + +usb:v058FpA014* + ID_MODEL_FROM_DATABASE=Asus Integrated Webcam + +usb:v0590* + ID_VENDOR_FROM_DATABASE=Omron Corp. + +usb:v0590p0004* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v0590p000B* + ID_MODEL_FROM_DATABASE=MR56SVS + +usb:v0590p0028* + ID_MODEL_FROM_DATABASE=HJ-720IT / HEM-7080IT-E / HEM-790IT + +usb:v0591* + ID_VENDOR_FROM_DATABASE=Questra Consulting + +usb:v0592* + ID_VENDOR_FROM_DATABASE=Powerware Corp. + +usb:v0592p0002* + ID_MODEL_FROM_DATABASE=UPS (X-Slot) + +usb:v0593* + ID_VENDOR_FROM_DATABASE=Incite + +usb:v0594* + ID_VENDOR_FROM_DATABASE=Princeton Graphic Systems + +usb:v0595* + ID_VENDOR_FROM_DATABASE=Zoran Microelectronics, Ltd + +usb:v0595p1001* + ID_MODEL_FROM_DATABASE=Digitrex DSC-1300/DSC-2100 (mass storage mode) + +usb:v0595p2002* + ID_MODEL_FROM_DATABASE=DIGITAL STILL CAMERA 6M 4X + +usb:v0595p4343* + ID_MODEL_FROM_DATABASE=Digital Camera EX-20 DSC + +usb:v0596* + ID_VENDOR_FROM_DATABASE=MicroTouch Systems, Inc. + +usb:v0596p0001* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v0596p0002* + ID_MODEL_FROM_DATABASE=Touch Screen Controller + +usb:v0596p0500* + ID_MODEL_FROM_DATABASE=PCT Multitouch HID Controller + +usb:v0597* + ID_VENDOR_FROM_DATABASE=Trisignal Communications + +usb:v0598* + ID_VENDOR_FROM_DATABASE=Niigata Canotec Co., Inc. + +usb:v0599* + ID_VENDOR_FROM_DATABASE=Brilliance Semiconductor, Inc. + +usb:v059A* + ID_VENDOR_FROM_DATABASE=Spectrum Signal Processing, Inc. + +usb:v059B* + ID_VENDOR_FROM_DATABASE=Iomega Corp. + +usb:v059Bp0001* + ID_MODEL_FROM_DATABASE=Zip 100 (Type 1) + +usb:v059Bp000B* + ID_MODEL_FROM_DATABASE=Zip 100 (Type 2) + +usb:v059Bp0021* + ID_MODEL_FROM_DATABASE=Win98 Disk Controller + +usb:v059Bp0030* + ID_MODEL_FROM_DATABASE=Zip 250 (Ver 1) + +usb:v059Bp0031* + ID_MODEL_FROM_DATABASE=Zip 100 (Type 3) + +usb:v059Bp0032* + ID_MODEL_FROM_DATABASE=Zip 250 (Ver 2) + +usb:v059Bp0034* + ID_MODEL_FROM_DATABASE=Zip 100 Driver + +usb:v059Bp0037* + ID_MODEL_FROM_DATABASE=Zip 750 MB + +usb:v059Bp0040* + ID_MODEL_FROM_DATABASE=SCSI Bridge + +usb:v059Bp0042* + ID_MODEL_FROM_DATABASE=Rev 70 GB + +usb:v059Bp0050* + ID_MODEL_FROM_DATABASE=Zip CD 650 Writer + +usb:v059Bp0053* + ID_MODEL_FROM_DATABASE=CDRW55292EXT CD-RW External Drive + +usb:v059Bp0056* + ID_MODEL_FROM_DATABASE=External CD-RW Drive Enclosure + +usb:v059Bp0057* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v059Bp005D* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v059Bp005F* + ID_MODEL_FROM_DATABASE=CDRW64892EXT3-C CD-RW 52x24x52x External Drive + +usb:v059Bp0060* + ID_MODEL_FROM_DATABASE=PCMCIA PocketZip Dock + +usb:v059Bp0061* + ID_MODEL_FROM_DATABASE=Varo PocketZip 40 MP3 Player + +usb:v059Bp006D* + ID_MODEL_FROM_DATABASE=HipZip MP3 Player + +usb:v059Bp007C* + ID_MODEL_FROM_DATABASE=Ultra Max USB/1394 + +usb:v059Bp007D* + ID_MODEL_FROM_DATABASE=HTC42606 0G9AT00 [Iomega HDD] + +usb:v059Bp007E* + ID_MODEL_FROM_DATABASE=Mini 256MB/512MB Flash Drive [IOM2D5] + +usb:v059Bp00DB* + ID_MODEL_FROM_DATABASE=FotoShow Zip 250 Driver + +usb:v059Bp0150* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v059Bp015D* + ID_MODEL_FROM_DATABASE=Super DVD Writer + +usb:v059Bp0173* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp0174* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp0176* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp0177* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp0178* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp0179* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v059Bp017A* + ID_MODEL_FROM_DATABASE=HDD + +usb:v059Bp017B* + ID_MODEL_FROM_DATABASE=HDD/1394A + +usb:v059Bp017C* + ID_MODEL_FROM_DATABASE=HDD/1394B + +usb:v059Bp0251* + ID_MODEL_FROM_DATABASE=Optical + +usb:v059Bp0252* + ID_MODEL_FROM_DATABASE=Optical + +usb:v059Bp0278* + ID_MODEL_FROM_DATABASE=LDHD-UPS [Professional Desktop Hard Drive eSATA / USB2.0] + +usb:v059Bp027A* + ID_MODEL_FROM_DATABASE=LPHD250-U [Portable Hard Drive Silver Series 250 Go] + +usb:v059Bp0470* + ID_MODEL_FROM_DATABASE=Prestige Portable Hard Drive + +usb:v059Bp047A* + ID_MODEL_FROM_DATABASE=Select Portable Hard Drive + +usb:v059Bp0571* + ID_MODEL_FROM_DATABASE=Prestige Portable Hard Drive + +usb:v059Bp0579* + ID_MODEL_FROM_DATABASE=eGo Portable Hard Drive + +usb:v059Bp1052* + ID_MODEL_FROM_DATABASE=DVD+RW External Drive + +usb:v059C* + ID_VENDOR_FROM_DATABASE=A-Trend Technology Co., Ltd + +usb:v059D* + ID_VENDOR_FROM_DATABASE=Advanced Input Devices + +usb:v059E* + ID_VENDOR_FROM_DATABASE=Intelligent Instrumentation + +usb:v059F* + ID_VENDOR_FROM_DATABASE=LaCie, Ltd + +usb:v059Fp0201* + ID_MODEL_FROM_DATABASE=StudioDrive USB2 + +usb:v059Fp0202* + ID_MODEL_FROM_DATABASE=StudioDrive USB2 + +usb:v059Fp0203* + ID_MODEL_FROM_DATABASE=StudioDrive USB2 + +usb:v059Fp0211* + ID_MODEL_FROM_DATABASE=PocketDrive + +usb:v059Fp0212* + ID_MODEL_FROM_DATABASE=PocketDrive + +usb:v059Fp0213* + ID_MODEL_FROM_DATABASE=PocketDrive USB2 + +usb:v059Fp0323* + ID_MODEL_FROM_DATABASE=LaCie d2 Drive USB2 + +usb:v059Fp0421* + ID_MODEL_FROM_DATABASE=Big Disk G465 + +usb:v059Fp0641* + ID_MODEL_FROM_DATABASE=Mobile Hard Drive + +usb:v059Fp100C* + ID_MODEL_FROM_DATABASE=Rugged Triple Interface Mobile Hard Drive + +usb:v059Fp1010* + ID_MODEL_FROM_DATABASE=Desktop Hard Drive + +usb:v059Fp1019* + ID_MODEL_FROM_DATABASE=Desktop Hard Drive + +usb:v059Fp1021* + ID_MODEL_FROM_DATABASE=Little Disk + +usb:v059Fp1027* + ID_MODEL_FROM_DATABASE=iamaKey V2 + +usb:v059Fp102A* + ID_MODEL_FROM_DATABASE=Rikiki Hard Drive + +usb:v059Fp1049* + ID_MODEL_FROM_DATABASE=rikiki Harddrive + +usb:v059Fp1052* + ID_MODEL_FROM_DATABASE=P'9220 Mobile Drive + +usb:v059FpA601* + ID_MODEL_FROM_DATABASE=HardDrive + +usb:v059FpA602* + ID_MODEL_FROM_DATABASE=CD R/W + +usb:v05A0* + ID_VENDOR_FROM_DATABASE=Vetronix Corp. + +usb:v05A1* + ID_VENDOR_FROM_DATABASE=USC Corp. + +usb:v05A2* + ID_VENDOR_FROM_DATABASE=Fuji Film Microdevices Co., Ltd + +usb:v05A3* + ID_VENDOR_FROM_DATABASE=ARC International + +usb:v05A3p8388* + ID_MODEL_FROM_DATABASE=Marvell 88W8388 802.11a/b/g WLAN + +usb:v05A4* + ID_VENDOR_FROM_DATABASE=Ortek Technology, Inc. + +usb:v05A4p1000* + ID_MODEL_FROM_DATABASE=WKB-1000S Wireless Ergo Keyboard with Touchpad + +usb:v05A4p2000* + ID_MODEL_FROM_DATABASE=WKB-2000 Wireless Keyboard with Touchpad + +usb:v05A4p9720* + ID_MODEL_FROM_DATABASE=Keyboard Mouse + +usb:v05A4p9722* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v05A4p9731* + ID_MODEL_FROM_DATABASE=MCK-600W/MCK-800USB Keyboard + +usb:v05A4p9783* + ID_MODEL_FROM_DATABASE=Wireless Keypad + +usb:v05A4p9837* + ID_MODEL_FROM_DATABASE=Targus Number Keypad + +usb:v05A4p9862* + ID_MODEL_FROM_DATABASE=Targus Number Keypad (Composite Device) + +usb:v05A4p9881* + ID_MODEL_FROM_DATABASE=IR receiver [VRC-1100 Vista MCE Remote Control] + +usb:v05A5* + ID_VENDOR_FROM_DATABASE=Sampo Technology Corp. + +usb:v05A6* + ID_VENDOR_FROM_DATABASE=Cisco Systems, Inc. + +usb:v05A6p0001* + ID_MODEL_FROM_DATABASE=CVA124 Cable Voice Adapter (WDM) + +usb:v05A6p0002* + ID_MODEL_FROM_DATABASE=CVA122 Cable Voice Adapter (WDM) + +usb:v05A6p0003* + ID_MODEL_FROM_DATABASE=CVA124E Cable Voice Adapter (WDM) + +usb:v05A6p0004* + ID_MODEL_FROM_DATABASE=CVA122E Cable Voice Adapter (WDM) + +usb:v05A7* + ID_VENDOR_FROM_DATABASE=Bose Corp. + +usb:v05A8* + ID_VENDOR_FROM_DATABASE=Spacetec IMC Corp. + +usb:v05A9* + ID_VENDOR_FROM_DATABASE=OmniVision Technologies, Inc. + +usb:v05A9p0511* + ID_MODEL_FROM_DATABASE=OV511 Webcam + +usb:v05A9p0518* + ID_MODEL_FROM_DATABASE=OV518 Webcam + +usb:v05A9p0519* + ID_MODEL_FROM_DATABASE=OV519 Microphone + +usb:v05A9p1550* + ID_MODEL_FROM_DATABASE=VEHO Filmscanner + +usb:v05A9p2640* + ID_MODEL_FROM_DATABASE=OV2640 Webcam + +usb:v05A9p2643* + ID_MODEL_FROM_DATABASE=Monitor Webcam + +usb:v05A9p264B* + ID_MODEL_FROM_DATABASE=Monitor Webcam + +usb:v05A9p2800* + ID_MODEL_FROM_DATABASE=SuperCAM + +usb:v05A9p4519* + ID_MODEL_FROM_DATABASE=Webcam Classic + +usb:v05A9p7670* + ID_MODEL_FROM_DATABASE=OV7670 Webcam + +usb:v05A9p8519* + ID_MODEL_FROM_DATABASE=OV519 Webcam + +usb:v05A9pA511* + ID_MODEL_FROM_DATABASE=OV511+ Webcam + +usb:v05A9pA518* + ID_MODEL_FROM_DATABASE=D-Link DSB-C310 Webcam + +usb:v05AA* + ID_VENDOR_FROM_DATABASE=Utilux South China, Ltd + +usb:v05AB* + ID_VENDOR_FROM_DATABASE=In-System Design + +usb:v05ABp0002* + ID_MODEL_FROM_DATABASE=Parallel Port + +usb:v05ABp0030* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 (TPP) + +usb:v05ABp0031* + ID_MODEL_FROM_DATABASE=ATA Bridge + +usb:v05ABp0060* + ID_MODEL_FROM_DATABASE=USB 2.0 ATA Bridge + +usb:v05ABp0061* + ID_MODEL_FROM_DATABASE=Storage Adapter V3 (TPP-I) + +usb:v05ABp0101* + ID_MODEL_FROM_DATABASE=Storage Adapter (TPP) + +usb:v05ABp0130* + ID_MODEL_FROM_DATABASE=Compact Flash and Microdrive Reader (TPP) + +usb:v05ABp0200* + ID_MODEL_FROM_DATABASE=USS725 ATA Bridge + +usb:v05ABp0201* + ID_MODEL_FROM_DATABASE=Storage Adapter (TPP) + +usb:v05ABp0202* + ID_MODEL_FROM_DATABASE=ATA Bridge + +usb:v05ABp0300* + ID_MODEL_FROM_DATABASE=Portable Hard Drive (TPP) + +usb:v05ABp0301* + ID_MODEL_FROM_DATABASE=Portable Hard Drive V2 + +usb:v05ABp0350* + ID_MODEL_FROM_DATABASE=Portable Hard Drive (TPP) + +usb:v05ABp0351* + ID_MODEL_FROM_DATABASE=Portable Hard Drive V2 + +usb:v05ABp081A* + ID_MODEL_FROM_DATABASE=ATA Bridge + +usb:v05ABp0CDA* + ID_MODEL_FROM_DATABASE=ATA Bridge for CD-R/RW + +usb:v05ABp1001* + ID_MODEL_FROM_DATABASE=BAYI Printer Class Support + +usb:v05ABp5700* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 (TPP) + +usb:v05ABp5701* + ID_MODEL_FROM_DATABASE=USB Storage Adapter V2 + +usb:v05ABp5901* + ID_MODEL_FROM_DATABASE=Smart Board (TPP) + +usb:v05ABp5A01* + ID_MODEL_FROM_DATABASE=ATI Storage Adapter (TPP) + +usb:v05ABp5D01* + ID_MODEL_FROM_DATABASE=DataBook Adapter (TPP) + +usb:v05AC* + ID_VENDOR_FROM_DATABASE=Apple, Inc. + +usb:v05ACp0201* + ID_MODEL_FROM_DATABASE=USB Keyboard [Alps or Logitech, M2452] + +usb:v05ACp0202* + ID_MODEL_FROM_DATABASE=Keyboard [ALPS] + +usb:v05ACp0205* + ID_MODEL_FROM_DATABASE=Extended Keyboard [Mitsumi] + +usb:v05ACp0206* + ID_MODEL_FROM_DATABASE=Extended Keyboard [Mitsumi] + +usb:v05ACp020B* + ID_MODEL_FROM_DATABASE=Pro Keyboard [Mitsumi, A1048/US layout] + +usb:v05ACp020C* + ID_MODEL_FROM_DATABASE=Extended Keyboard [Mitsumi] + +usb:v05ACp020D* + ID_MODEL_FROM_DATABASE=Pro Keyboard [Mitsumi, A1048/JIS layout] + +usb:v05ACp020E* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp020F* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0214* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0215* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0216* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp0217* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0218* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0219* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp021A* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp021B* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp021C* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp021D* + ID_MODEL_FROM_DATABASE=Aluminum Mini Keyboard (ANSI) + +usb:v05ACp021E* + ID_MODEL_FROM_DATABASE=Aluminum Mini Keyboard (ISO) + +usb:v05ACp021F* + ID_MODEL_FROM_DATABASE=Aluminum Mini Keyboard (JIS) + +usb:v05ACp0220* + ID_MODEL_FROM_DATABASE=Aluminum Keyboard (ANSI) + +usb:v05ACp0221* + ID_MODEL_FROM_DATABASE=Aluminum Keyboard (ISO) + +usb:v05ACp0222* + ID_MODEL_FROM_DATABASE=Aluminum Keyboard (JIS) + +usb:v05ACp0223* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0224* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0225* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp0229* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro) (ANSI) + +usb:v05ACp022A* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro) (ISO) + +usb:v05ACp022B* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro) (JIS) + +usb:v05ACp0230* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro 4,1) (ANSI) + +usb:v05ACp0231* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro 4,1) (ISO) + +usb:v05ACp0232* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Pro 4,1) (JIS) + +usb:v05ACp0236* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0237* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0238* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp023F* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0240* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0241* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp0242* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0243* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0244* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp0245* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0246* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0247* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp024A* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Air) (ISO) + +usb:v05ACp024D* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (MacBook Air) (ISO) + +usb:v05ACp0250* + ID_MODEL_FROM_DATABASE=Aluminium Keyboard (ISO) + +usb:v05ACp0252* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ANSI) + +usb:v05ACp0253* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (ISO) + +usb:v05ACp0254* + ID_MODEL_FROM_DATABASE=Internal Keyboard/Trackpad (JIS) + +usb:v05ACp0263* + ID_MODEL_FROM_DATABASE=Apple Internal Keyboard / Trackpad (MacBook Retina) + +usb:v05ACp0301* + ID_MODEL_FROM_DATABASE=USB Mouse [Mitsumi, M4848] + +usb:v05ACp0302* + ID_MODEL_FROM_DATABASE=Optical Mouse [Fujitsu] + +usb:v05ACp0304* + ID_MODEL_FROM_DATABASE=Optical USB Mouse [Mitsumi] + +usb:v05ACp0306* + ID_MODEL_FROM_DATABASE=Optical USB Mouse [Fujitsu] + +usb:v05ACp030A* + ID_MODEL_FROM_DATABASE=Internal Trackpad + +usb:v05ACp030B* + ID_MODEL_FROM_DATABASE=Internal Trackpad + +usb:v05ACp030D* + ID_MODEL_FROM_DATABASE=Magic Mouse + +usb:v05ACp030E* + ID_MODEL_FROM_DATABASE=MC380Z/A [Magic Trackpad] + +usb:v05ACp1000* + ID_MODEL_FROM_DATABASE=Bluetooth HCI MacBookPro (HID mode) + +usb:v05ACp1001* + ID_MODEL_FROM_DATABASE=Keyboard Hub [ALPS] + +usb:v05ACp1002* + ID_MODEL_FROM_DATABASE=Extended Keyboard Hub [Mitsumi] + +usb:v05ACp1003* + ID_MODEL_FROM_DATABASE=Hub in Pro Keyboard [Mitsumi, A1048] + +usb:v05ACp1006* + ID_MODEL_FROM_DATABASE=Hub in Aluminum Keyboard + +usb:v05ACp1101* + ID_MODEL_FROM_DATABASE=Speakers + +usb:v05ACp1105* + ID_MODEL_FROM_DATABASE=Audio in LED Cinema Display + +usb:v05ACp1107* + ID_MODEL_FROM_DATABASE=Thunderbolt Display Audio + +usb:v05ACp1112* + ID_MODEL_FROM_DATABASE=FaceTime HD Camera (Display) + +usb:v05ACp1201* + ID_MODEL_FROM_DATABASE=3G iPod + +usb:v05ACp1202* + ID_MODEL_FROM_DATABASE=iPod 2G + +usb:v05ACp1203* + ID_MODEL_FROM_DATABASE=iPod 4.Gen Grayscale 40G + +usb:v05ACp1204* + ID_MODEL_FROM_DATABASE=iPod [Photo] + +usb:v05ACp1205* + ID_MODEL_FROM_DATABASE=iPod Mini 1.Gen/2.Gen + +usb:v05ACp1206* + ID_MODEL_FROM_DATABASE=iPod '06' + +usb:v05ACp1207* + ID_MODEL_FROM_DATABASE=iPod '07' + +usb:v05ACp1208* + ID_MODEL_FROM_DATABASE=iPod '08' + +usb:v05ACp1209* + ID_MODEL_FROM_DATABASE=iPod Video + +usb:v05ACp120A* + ID_MODEL_FROM_DATABASE=iPod Nano + +usb:v05ACp1223* + ID_MODEL_FROM_DATABASE=iPod Classic/Nano 3.Gen (DFU mode) + +usb:v05ACp1224* + ID_MODEL_FROM_DATABASE=iPod Nano 3.Gen (DFU mode) + +usb:v05ACp1225* + ID_MODEL_FROM_DATABASE=iPod Nano 4.Gen (DFU mode) + +usb:v05ACp1227* + ID_MODEL_FROM_DATABASE=Mobile Device (DFU Mode) + +usb:v05ACp1231* + ID_MODEL_FROM_DATABASE=iPod Nano 5.Gen (DFU mode) + +usb:v05ACp1240* + ID_MODEL_FROM_DATABASE=iPod Nano 2.Gen (DFU mode) + +usb:v05ACp1242* + ID_MODEL_FROM_DATABASE=iPod Nano 3.Gen (WTF mode) + +usb:v05ACp1243* + ID_MODEL_FROM_DATABASE=iPod Nano 4.Gen (WTF mode) + +usb:v05ACp1245* + ID_MODEL_FROM_DATABASE=iPod Classic 3.Gen (WTF mode) + +usb:v05ACp1246* + ID_MODEL_FROM_DATABASE=iPod Nano 5.Gen (WTF mode) + +usb:v05ACp1255* + ID_MODEL_FROM_DATABASE=iPod Nano 4.Gen (DFU mode) + +usb:v05ACp1260* + ID_MODEL_FROM_DATABASE=iPod Nano 2.Gen + +usb:v05ACp1261* + ID_MODEL_FROM_DATABASE=iPod Classic + +usb:v05ACp1262* + ID_MODEL_FROM_DATABASE=iPod Nano 3.Gen + +usb:v05ACp1263* + ID_MODEL_FROM_DATABASE=iPod Nano 4.Gen + +usb:v05ACp1265* + ID_MODEL_FROM_DATABASE=iPod Nano 5.Gen + +usb:v05ACp1266* + ID_MODEL_FROM_DATABASE=iPod Nano 6.Gen + +usb:v05ACp1281* + ID_MODEL_FROM_DATABASE=Apple Mobile Device [Recovery Mode] + +usb:v05ACp1290* + ID_MODEL_FROM_DATABASE=iPhone + +usb:v05ACp1291* + ID_MODEL_FROM_DATABASE=iPod Touch 1.Gen + +usb:v05ACp1292* + ID_MODEL_FROM_DATABASE=iPhone 3G + +usb:v05ACp1293* + ID_MODEL_FROM_DATABASE=iPod Touch 2.Gen + +usb:v05ACp1294* + ID_MODEL_FROM_DATABASE=iPhone 3GS + +usb:v05ACp1296* + ID_MODEL_FROM_DATABASE=iPod Touch 3.Gen (8GB) + +usb:v05ACp1297* + ID_MODEL_FROM_DATABASE=iPhone 4 + +usb:v05ACp1299* + ID_MODEL_FROM_DATABASE=iPod Touch 3.Gen + +usb:v05ACp129A* + ID_MODEL_FROM_DATABASE=iPad + +usb:v05ACp129E* + ID_MODEL_FROM_DATABASE=iPod Touch 4.Gen + +usb:v05ACp129F* + ID_MODEL_FROM_DATABASE=iPad 2 + +usb:v05ACp12A0* + ID_MODEL_FROM_DATABASE=iPhone 4S + +usb:v05ACp12A2* + ID_MODEL_FROM_DATABASE=iPad 2 (3G; 64GB) + +usb:v05ACp12A6* + ID_MODEL_FROM_DATABASE=iPad 3 (3G, 16 GB) + +usb:v05ACp12A9* + ID_MODEL_FROM_DATABASE=iPad 2 + +usb:v05ACp12AA* + ID_MODEL_FROM_DATABASE=iPod Touch 5.Gen [A1421] + +usb:v05ACp1300* + ID_MODEL_FROM_DATABASE=iPod Shuffle + +usb:v05ACp1301* + ID_MODEL_FROM_DATABASE=iPod Shuffle 2.Gen + +usb:v05ACp1302* + ID_MODEL_FROM_DATABASE=iPod Shuffle 3.Gen + +usb:v05ACp1303* + ID_MODEL_FROM_DATABASE=iPod Shuffle 4.Gen + +usb:v05ACp1401* + ID_MODEL_FROM_DATABASE=Modem + +usb:v05ACp1402* + ID_MODEL_FROM_DATABASE=Ethernet Adapter [A1277] + +usb:v05ACp1500* + ID_MODEL_FROM_DATABASE=SuperDrive [A1379] + +usb:v05ACp8202* + ID_MODEL_FROM_DATABASE=HCF V.90 Data/Fax Modem + +usb:v05ACp8203* + ID_MODEL_FROM_DATABASE=Bluetooth HCI + +usb:v05ACp8204* + ID_MODEL_FROM_DATABASE=Built-in Bluetooth 2.0+EDR HCI + +usb:v05ACp8205* + ID_MODEL_FROM_DATABASE=Bluetooth HCI + +usb:v05ACp8206* + ID_MODEL_FROM_DATABASE=Bluetooth HCI + +usb:v05ACp820A* + ID_MODEL_FROM_DATABASE=Bluetooth HID Keyboard + +usb:v05ACp820B* + ID_MODEL_FROM_DATABASE=Bluetooth HID Mouse + +usb:v05ACp820F* + ID_MODEL_FROM_DATABASE=Bluetooth HCI + +usb:v05ACp8213* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + +usb:v05ACp8215* + ID_MODEL_FROM_DATABASE=Built-in Bluetooth 2.0+EDR HCI + +usb:v05ACp8216* + ID_MODEL_FROM_DATABASE=Bluetooth USB Host Controller + +usb:v05ACp8217* + ID_MODEL_FROM_DATABASE=Bluetooth USB Host Controller + +usb:v05ACp8218* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + +usb:v05ACp821A* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + +usb:v05ACp821F* + ID_MODEL_FROM_DATABASE=Built-in Bluetooth 2.0+EDR HCI + +usb:v05ACp8240* + ID_MODEL_FROM_DATABASE=Built-in IR Receiver + +usb:v05ACp8241* + ID_MODEL_FROM_DATABASE=Built-in IR Receiver + +usb:v05ACp8242* + ID_MODEL_FROM_DATABASE=Built-in IR Receiver + +usb:v05ACp8281* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + +usb:v05ACp8286* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + +usb:v05ACp8300* + ID_MODEL_FROM_DATABASE=Built-in iSight (no firmware loaded) + +usb:v05ACp8403* + ID_MODEL_FROM_DATABASE=Internal Memory Card Reader + +usb:v05ACp8404* + ID_MODEL_FROM_DATABASE=Internal Memory Card Reader + +usb:v05ACp8501* + ID_MODEL_FROM_DATABASE=Built-in iSight [Micron] + +usb:v05ACp8502* + ID_MODEL_FROM_DATABASE=Built-in iSight + +usb:v05ACp8505* + ID_MODEL_FROM_DATABASE=Built-in iSight + +usb:v05ACp8507* + ID_MODEL_FROM_DATABASE=Built-in iSight + +usb:v05ACp8508* + ID_MODEL_FROM_DATABASE=iSight in LED Cinema Display + +usb:v05ACp8509* + ID_MODEL_FROM_DATABASE=FaceTime HD Camera + +usb:v05ACp850A* + ID_MODEL_FROM_DATABASE=FaceTime Camera + +usb:v05ACp8510* + ID_MODEL_FROM_DATABASE=FaceTime HD Camera (Built-in) + +usb:v05ACp911C* + ID_MODEL_FROM_DATABASE=Hub in A1082 [Cinema HD Display 23"] + +usb:v05ACp912F* + ID_MODEL_FROM_DATABASE=Hub in 30" Cinema Display + +usb:v05ACp9215* + ID_MODEL_FROM_DATABASE=Studio Display 15" + +usb:v05ACp9217* + ID_MODEL_FROM_DATABASE=Studio Display 17" + +usb:v05ACp9218* + ID_MODEL_FROM_DATABASE=Cinema Display 23" + +usb:v05ACp9219* + ID_MODEL_FROM_DATABASE=Cinema Display 20" + +usb:v05ACp921C* + ID_MODEL_FROM_DATABASE=A1082 [Cinema HD Display 23"] + +usb:v05ACp921E* + ID_MODEL_FROM_DATABASE=Cinema Display 24" + +usb:v05ACp9221* + ID_MODEL_FROM_DATABASE=30" Cinema Display + +usb:v05ACp9226* + ID_MODEL_FROM_DATABASE=LED Cinema Display + +usb:v05ACp9227* + ID_MODEL_FROM_DATABASE=Thunderbolt Display + +usb:v05ACp9232* + ID_MODEL_FROM_DATABASE=Cinema HD Display 30" + +usb:v05ACpFFFF* + ID_MODEL_FROM_DATABASE=Bluetooth in DFU mode - Driver + +usb:v05AD* + ID_VENDOR_FROM_DATABASE=Y.C. Cable U.S.A., Inc. + +usb:v05AE* + ID_VENDOR_FROM_DATABASE=Synopsys, Inc. + +usb:v05AF* + ID_VENDOR_FROM_DATABASE=Jing-Mold Enterprise Co., Ltd + +usb:v05AFp0806* + ID_MODEL_FROM_DATABASE=HP SK806A Keyboard + +usb:v05AFp0809* + ID_MODEL_FROM_DATABASE=Wireless Keyboard and Mouse + +usb:v05AFp0821* + ID_MODEL_FROM_DATABASE=IDE to + +usb:v05AFp3062* + ID_MODEL_FROM_DATABASE=Cordless Keyboard + +usb:v05AFp9167* + ID_MODEL_FROM_DATABASE=KB 9151B - 678 + +usb:v05AFp9267* + ID_MODEL_FROM_DATABASE=KB 9251B - 678 Mouse + +usb:v05B0* + ID_VENDOR_FROM_DATABASE=Fountain Technologies, Inc. + +usb:v05B1* + ID_VENDOR_FROM_DATABASE=First International Computer, Inc. + +usb:v05B1p1389* + ID_MODEL_FROM_DATABASE=Bluetooth Wireless Adapter + +usb:v05B4* + ID_VENDOR_FROM_DATABASE=LG Semicon Co., Ltd + +usb:v05B4p4857* + ID_MODEL_FROM_DATABASE=M-Any DAH-210 + +usb:v05B4p6001* + ID_MODEL_FROM_DATABASE=Digisette DUO-MP3 AR-100 + +usb:v05B5* + ID_VENDOR_FROM_DATABASE=Dialogic Corp. + +usb:v05B6* + ID_VENDOR_FROM_DATABASE=Proxima Corp. + +usb:v05B7* + ID_VENDOR_FROM_DATABASE=Medianix Semiconductor, Inc. + +usb:v05B8* + ID_VENDOR_FROM_DATABASE=Agiler, Inc. + +usb:v05B8p3002* + ID_MODEL_FROM_DATABASE=Scroll Mouse + +usb:v05B9* + ID_VENDOR_FROM_DATABASE=Philips Research Laboratories + +usb:v05BA* + ID_VENDOR_FROM_DATABASE=DigitalPersona, Inc. + +usb:v05BAp0007* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v05BAp0008* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v05BAp000A* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v05BB* + ID_VENDOR_FROM_DATABASE=Grey Cell Systems + +usb:v05BC* + ID_VENDOR_FROM_DATABASE=3G Green Green Globe Co., Ltd + +usb:v05BCp0004* + ID_MODEL_FROM_DATABASE=Trackball + +usb:v05BD* + ID_VENDOR_FROM_DATABASE=RAFI GmbH & Co. KG + +usb:v05BE* + ID_VENDOR_FROM_DATABASE=Tyco Electronics (Raychem) + +usb:v05BF* + ID_VENDOR_FROM_DATABASE=S & S Research + +usb:v05C0* + ID_VENDOR_FROM_DATABASE=Keil Software + +usb:v05C1* + ID_VENDOR_FROM_DATABASE=Kawasaki Microelectronics, Inc. + +usb:v05C2* + ID_VENDOR_FROM_DATABASE=Media Phonics (Suisse) S.A. + +usb:v05C5* + ID_VENDOR_FROM_DATABASE=Digi International, Inc. + +usb:v05C5p0002* + ID_MODEL_FROM_DATABASE=AccelePort USB 2 + +usb:v05C5p0004* + ID_MODEL_FROM_DATABASE=AccelePort USB 4 + +usb:v05C5p0008* + ID_MODEL_FROM_DATABASE=AccelePort USB 8 + +usb:v05C6* + ID_VENDOR_FROM_DATABASE=Qualcomm, Inc. + +usb:v05C6p0114* + ID_MODEL_FROM_DATABASE=Select RW-200 CDMA Wireless Modem + +usb:v05C6p1000* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v05C6p3100* + ID_MODEL_FROM_DATABASE=CDMA Wireless Modem/Phone + +usb:v05C6p3196* + ID_MODEL_FROM_DATABASE=CDMA Wireless Modem + +usb:v05C6p3197* + ID_MODEL_FROM_DATABASE=CDMA Wireless Modem/Phone + +usb:v05C6p6000* + ID_MODEL_FROM_DATABASE=Siemens SG75 + +usb:v05C6p6503* + ID_MODEL_FROM_DATABASE=AnyData APE-540H + +usb:v05C6p6613* + ID_MODEL_FROM_DATABASE=Onda H600/N501HS ZTE MF330 + +usb:v05C6p9000* + ID_MODEL_FROM_DATABASE=SIMCom SIM5218 modem + +usb:v05C6p9001* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v05C6p9002* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v05C6p9008* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v05C6p9018* + ID_MODEL_FROM_DATABASE=Qualcomm HSUSB Device + +usb:v05C6p9025* + ID_MODEL_FROM_DATABASE=Qualcomm HSUSB Device + +usb:v05C6p9201* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v05C6p9202* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v05C6p9203* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v05C6p9211* + ID_MODEL_FROM_DATABASE=Acer Gobi Wireless Modem (QDL mode) + +usb:v05C6p9212* + ID_MODEL_FROM_DATABASE=Acer Gobi Wireless Modem + +usb:v05C6p9214* + ID_MODEL_FROM_DATABASE=Acer Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9215* + ID_MODEL_FROM_DATABASE=Acer Gobi 2000 Wireless Modem + +usb:v05C6p9221* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v05C6p9222* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v05C6p9224* + ID_MODEL_FROM_DATABASE=Sony Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9225* + ID_MODEL_FROM_DATABASE=Sony Gobi 2000 Wireless Modem + +usb:v05C6p9231* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v05C6p9234* + ID_MODEL_FROM_DATABASE=Top Global Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9235* + ID_MODEL_FROM_DATABASE=Top Global Gobi 2000 Wireless Modem + +usb:v05C6p9244* + ID_MODEL_FROM_DATABASE=Samsung Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9245* + ID_MODEL_FROM_DATABASE=Samsung Gobi 2000 Wireless Modem + +usb:v05C6p9264* + ID_MODEL_FROM_DATABASE=Asus Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9265* + ID_MODEL_FROM_DATABASE=Asus Gobi 2000 Wireless Modem + +usb:v05C6p9274* + ID_MODEL_FROM_DATABASE=iRex Technologies Gobi 2000 Wireless Modem (QDL mode) + +usb:v05C6p9275* + ID_MODEL_FROM_DATABASE=iRex Technologies Gobi 2000 Wireless Modem + +usb:v05C7* + ID_VENDOR_FROM_DATABASE=Qtronix Corp. + +usb:v05C7p0113* + ID_MODEL_FROM_DATABASE=PC Line Mouse + +usb:v05C7p1001* + ID_MODEL_FROM_DATABASE=Lynx Mouse + +usb:v05C7p2001* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v05C7p2011* + ID_MODEL_FROM_DATABASE=SCorpius Keyboard + +usb:v05C7p6001* + ID_MODEL_FROM_DATABASE=Ten-Keypad + +usb:v05C8* + ID_VENDOR_FROM_DATABASE=Cheng Uei Precision Industry Co., Ltd (Foxlink) + +usb:v05C8p0103* + ID_MODEL_FROM_DATABASE=FO13FF-65 PC-CAM + +usb:v05C8p021A* + ID_MODEL_FROM_DATABASE=HP Webcam + +usb:v05C8p0318* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v05C8p0403* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v05C9* + ID_VENDOR_FROM_DATABASE=Semtech Corp. + +usb:v05CA* + ID_VENDOR_FROM_DATABASE=Ricoh Co., Ltd + +usb:v05CAp0101* + ID_MODEL_FROM_DATABASE=RDC-5300 Camera + +usb:v05CAp0325* + ID_MODEL_FROM_DATABASE=Caplio GX (ptp) + +usb:v05CAp032D* + ID_MODEL_FROM_DATABASE=Caplio GX 8 (ptp) + +usb:v05CAp032F* + ID_MODEL_FROM_DATABASE=Caplio R3 (ptp) + +usb:v05CAp03A1* + ID_MODEL_FROM_DATABASE=IS200e + +usb:v05CAp0403* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v05CAp0405* + ID_MODEL_FROM_DATABASE=Type 101 + +usb:v05CAp0406* + ID_MODEL_FROM_DATABASE=Type 102 + +usb:v05CAp1803* + ID_MODEL_FROM_DATABASE=V5 camera [R5U870] + +usb:v05CAp1810* + ID_MODEL_FROM_DATABASE=Pavilion Webcam [R5U870] + +usb:v05CAp1812* + ID_MODEL_FROM_DATABASE=Pavilion Webcam + +usb:v05CAp1814* + ID_MODEL_FROM_DATABASE=HD Webcam + +usb:v05CAp1820* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v05CAp1830* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC2 [R5U870] + +usb:v05CAp1832* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC3 [R5U870] + +usb:v05CAp1833* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC2 [R5U870] + +usb:v05CAp1834* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC2 [R5U870] + +usb:v05CAp1835* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC5 [R5U870] + +usb:v05CAp1836* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC4 [R5U870] + +usb:v05CAp1837* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC4 [R5U870] + +usb:v05CAp1839* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC6 [R5U870] + +usb:v05CAp183A* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC7 [R5U870] + +usb:v05CAp183B* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC8 [R5U870] + +usb:v05CAp183D* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Webcam + +usb:v05CAp183E* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC9 [R5U870] + +usb:v05CAp1841* + ID_MODEL_FROM_DATABASE=Fujitsu F01/ Lifebook U810 [R5U870] + +usb:v05CAp1870* + ID_MODEL_FROM_DATABASE=Webcam 1000 + +usb:v05CAp18B0* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Webcam + +usb:v05CAp18B1* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Webcam + +usb:v05CAp18B3* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Webcam + +usb:v05CAp18B5* + ID_MODEL_FROM_DATABASE=Sony Vaio Integrated Webcam + +usb:v05CAp2201* + ID_MODEL_FROM_DATABASE=RDC-7 Camera + +usb:v05CAp2202* + ID_MODEL_FROM_DATABASE=Caplio RR30 + +usb:v05CAp2203* + ID_MODEL_FROM_DATABASE=Caplio 300G + +usb:v05CAp2204* + ID_MODEL_FROM_DATABASE=Caplio G3 + +usb:v05CAp2205* + ID_MODEL_FROM_DATABASE=Caplio RR30 / Medion MD 6126 Camera + +usb:v05CAp2206* + ID_MODEL_FROM_DATABASE=Konica DG-3Z + +usb:v05CAp2207* + ID_MODEL_FROM_DATABASE=Caplio Pro G3 + +usb:v05CAp2208* + ID_MODEL_FROM_DATABASE=Caplio G4 + +usb:v05CAp2209* + ID_MODEL_FROM_DATABASE=Caplio 400G wide + +usb:v05CAp220A* + ID_MODEL_FROM_DATABASE=KONICA MINOLTA DG-4Wide + +usb:v05CAp220B* + ID_MODEL_FROM_DATABASE=Caplio RX + +usb:v05CAp220C* + ID_MODEL_FROM_DATABASE=Caplio GX + +usb:v05CAp220D* + ID_MODEL_FROM_DATABASE=Caplio R1/RZ1 + +usb:v05CAp220E* + ID_MODEL_FROM_DATABASE=Sea & Sea 5000G + +usb:v05CAp220F* + ID_MODEL_FROM_DATABASE=Rollei dr5 / Rollei dr5 (PTP mode) + +usb:v05CAp2211* + ID_MODEL_FROM_DATABASE=Caplio R1S + +usb:v05CAp2212* + ID_MODEL_FROM_DATABASE=Caplio R1v Camera + +usb:v05CAp2213* + ID_MODEL_FROM_DATABASE=Caplio R2 + +usb:v05CAp2214* + ID_MODEL_FROM_DATABASE=Caplio GX 8 + +usb:v05CAp2215* + ID_MODEL_FROM_DATABASE=DSC 725 + +usb:v05CAp2216* + ID_MODEL_FROM_DATABASE=Caplio R3 + +usb:v05CAp2222* + ID_MODEL_FROM_DATABASE=RDC-i500 + +usb:v05CB* + ID_VENDOR_FROM_DATABASE=PowerVision Technologies, Inc. + +usb:v05CBp1483* + ID_MODEL_FROM_DATABASE=PV8630 interface (scanners, webcams) + +usb:v05CC* + ID_VENDOR_FROM_DATABASE=ELSA AG + +usb:v05CCp2100* + ID_MODEL_FROM_DATABASE=MicroLink ISDN Office + +usb:v05CCp2219* + ID_MODEL_FROM_DATABASE=MicroLink ISDN + +usb:v05CCp2265* + ID_MODEL_FROM_DATABASE=MicroLink 56k + +usb:v05CCp2267* + ID_MODEL_FROM_DATABASE=MicroLink 56k (V.250) + +usb:v05CCp2280* + ID_MODEL_FROM_DATABASE=MicroLink 56k Fun + +usb:v05CCp3000* + ID_MODEL_FROM_DATABASE=Micolink USB2Ethernet [pegasus] + +usb:v05CCp3100* + ID_MODEL_FROM_DATABASE=AirLancer USB-11 + +usb:v05CCp3363* + ID_MODEL_FROM_DATABASE=MicroLink ADSL Fun + +usb:v05CD* + ID_VENDOR_FROM_DATABASE=Silicom, Ltd + +usb:v05CE* + ID_VENDOR_FROM_DATABASE=sci-worx GmbH + +usb:v05CF* + ID_VENDOR_FROM_DATABASE=Sung Forn Co., Ltd + +usb:v05D0* + ID_VENDOR_FROM_DATABASE=GE Medical Systems Lunar + +usb:v05D1* + ID_VENDOR_FROM_DATABASE=Brainboxes, Ltd + +usb:v05D1p0003* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter BL-554 + +usb:v05D2* + ID_VENDOR_FROM_DATABASE=Wave Systems Corp. + +usb:v05D3* + ID_VENDOR_FROM_DATABASE=Tohoku Ricoh Co., Ltd + +usb:v05D5* + ID_VENDOR_FROM_DATABASE=Super Gate Technology Co., Ltd + +usb:v05D6* + ID_VENDOR_FROM_DATABASE=Philips Semiconductors, CICT + +usb:v05D7* + ID_VENDOR_FROM_DATABASE=Thomas & Betts Corp. + +usb:v05D7p0099* + ID_MODEL_FROM_DATABASE=10Mbps Ethernet [klsi] + +usb:v05D8* + ID_VENDOR_FROM_DATABASE=Ultima Electronics Corp. + +usb:v05D8p4001* + ID_MODEL_FROM_DATABASE=Artec Ultima 2000 + +usb:v05D8p4002* + ID_MODEL_FROM_DATABASE=Artec Ultima 2000 (GT6801 based)/Lifetec LT9385/ScanMagic 1200 UB Plus Scanner + +usb:v05D8p4003* + ID_MODEL_FROM_DATABASE=Artec E+ 48U + +usb:v05D8p4004* + ID_MODEL_FROM_DATABASE=Artec E+ Pro + +usb:v05D8p4005* + ID_MODEL_FROM_DATABASE=MEM48U + +usb:v05D8p4006* + ID_MODEL_FROM_DATABASE=TRUST EASY WEBSCAN 19200 + +usb:v05D8p4007* + ID_MODEL_FROM_DATABASE=TRUST 240H EASY WEBSCAN GOLD + +usb:v05D8p4008* + ID_MODEL_FROM_DATABASE=Trust Easy Webscan 19200 + +usb:v05D8p4009* + ID_MODEL_FROM_DATABASE=Umax Astraslim + +usb:v05D8p4013* + ID_MODEL_FROM_DATABASE=IT Scan 1200 + +usb:v05D8p8105* + ID_MODEL_FROM_DATABASE=Artec T1 USB TVBOX (cold) + +usb:v05D8p8106* + ID_MODEL_FROM_DATABASE=Artec T1 USB TVBOX (warm) + +usb:v05D8p8107* + ID_MODEL_FROM_DATABASE=Artec T1 USB TVBOX with AN2235 (cold) + +usb:v05D8p8108* + ID_MODEL_FROM_DATABASE=Artec T1 USB TVBOX with AN2235 (warm) + +usb:v05D8p8109* + ID_MODEL_FROM_DATABASE=Artec T1 USB2.0 TVBOX (cold + +usb:v05D9* + ID_VENDOR_FROM_DATABASE=Axiohm Transaction Solutions + +usb:v05D9pA225* + ID_MODEL_FROM_DATABASE=A225 Printer + +usb:v05D9pA758* + ID_MODEL_FROM_DATABASE=A758 Printer + +usb:v05D9pA794* + ID_MODEL_FROM_DATABASE=A794 Printer + +usb:v05DA* + ID_VENDOR_FROM_DATABASE=Microtek International, Inc. + +usb:v05DAp0091* + ID_MODEL_FROM_DATABASE=ScanMaker X6u + +usb:v05DAp0093* + ID_MODEL_FROM_DATABASE=ScanMaker V6USL + +usb:v05DAp0094* + ID_MODEL_FROM_DATABASE=Phantom 336CX/C3 + +usb:v05DAp0099* + ID_MODEL_FROM_DATABASE=ScanMaker X6/X6U + +usb:v05DAp009A* + ID_MODEL_FROM_DATABASE=Phantom C6 + +usb:v05DAp00A0* + ID_MODEL_FROM_DATABASE=Phantom 336CX/C3 (#2) + +usb:v05DAp00A3* + ID_MODEL_FROM_DATABASE=ScanMaker V6USL + +usb:v05DAp00AC* + ID_MODEL_FROM_DATABASE=ScanMaker V6UL + +usb:v05DAp00B6* + ID_MODEL_FROM_DATABASE=ScanMaker V6UPL + +usb:v05DAp00EF* + ID_MODEL_FROM_DATABASE=ScanMaker V6UPL + +usb:v05DAp1006* + ID_MODEL_FROM_DATABASE=Jenoptik JD350 entrance + +usb:v05DAp1011* + ID_MODEL_FROM_DATABASE=NHJ Che-ez! Kiss Digital Camera + +usb:v05DAp1018* + ID_MODEL_FROM_DATABASE=Digital Dream Enigma 1.3 + +usb:v05DAp1020* + ID_MODEL_FROM_DATABASE=Digital Dream l'espion xtra + +usb:v05DAp1025* + ID_MODEL_FROM_DATABASE=Take-it Still Camera Device + +usb:v05DAp1026* + ID_MODEL_FROM_DATABASE=Take-it + +usb:v05DAp1043* + ID_MODEL_FROM_DATABASE=Take-It 1300 DSC Bulk Driver + +usb:v05DAp1045* + ID_MODEL_FROM_DATABASE=Take-it D1 + +usb:v05DAp1047* + ID_MODEL_FROM_DATABASE=Take-it Camera Composite Device + +usb:v05DAp1048* + ID_MODEL_FROM_DATABASE=Take-it Q3 + +usb:v05DAp1049* + ID_MODEL_FROM_DATABASE=3M Still Camera Device + +usb:v05DAp1051* + ID_MODEL_FROM_DATABASE=Camcorder Series + +usb:v05DAp1052* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v05DAp1053* + ID_MODEL_FROM_DATABASE=Take-it DV Composite Device + +usb:v05DAp1054* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v05DAp1055* + ID_MODEL_FROM_DATABASE=Digital Camera Series(536) + +usb:v05DAp1056* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v05DAp1057* + ID_MODEL_FROM_DATABASE=Take-it DSC Camera Device(536) + +usb:v05DAp1058* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v05DAp1059* + ID_MODEL_FROM_DATABASE=Camcorder DSC Series + +usb:v05DAp1060* + ID_MODEL_FROM_DATABASE=Microtek Take-it MV500 + +usb:v05DAp2007* + ID_MODEL_FROM_DATABASE=ArtixScan DI 1210 + +usb:v05DAp200C* + ID_MODEL_FROM_DATABASE=1394_USB2 Scanner + +usb:v05DAp200E* + ID_MODEL_FROM_DATABASE=ArtixScan DI 810 + +usb:v05DAp2017* + ID_MODEL_FROM_DATABASE=UF ICE Scanner + +usb:v05DAp201C* + ID_MODEL_FROM_DATABASE=4800 Scanner + +usb:v05DAp201D* + ID_MODEL_FROM_DATABASE=ArtixScan DI 1610 + +usb:v05DAp201F* + ID_MODEL_FROM_DATABASE=4800 Scanner-ICE + +usb:v05DAp202E* + ID_MODEL_FROM_DATABASE=ArtixScan DI 2020 + +usb:v05DAp208B* + ID_MODEL_FROM_DATABASE=ScanMaker 6800 + +usb:v05DAp208F* + ID_MODEL_FROM_DATABASE=ArtixScan DI 2010 + +usb:v05DAp209E* + ID_MODEL_FROM_DATABASE=ScanMaker 4700LP + +usb:v05DAp20A7* + ID_MODEL_FROM_DATABASE=ScanMaker 5600 + +usb:v05DAp20B0* + ID_MODEL_FROM_DATABASE=ScanMaker X12USL + +usb:v05DAp20B1* + ID_MODEL_FROM_DATABASE=ScanMaker 8700 + +usb:v05DAp20B4* + ID_MODEL_FROM_DATABASE=ScanMaker 4700 + +usb:v05DAp20BD* + ID_MODEL_FROM_DATABASE=ScanMaker 5700 + +usb:v05DAp20C9* + ID_MODEL_FROM_DATABASE=ScanMaker 6700 + +usb:v05DAp20D2* + ID_MODEL_FROM_DATABASE=Microtek ArtixScan 1800f + +usb:v05DAp20D6* + ID_MODEL_FROM_DATABASE=PS4000 + +usb:v05DAp20DE* + ID_MODEL_FROM_DATABASE=ScanMaker 9800XL + +usb:v05DAp20E0* + ID_MODEL_FROM_DATABASE=ScanMaker 9700XL + +usb:v05DAp20ED* + ID_MODEL_FROM_DATABASE=ScanMaker 4700 + +usb:v05DAp20EE* + ID_MODEL_FROM_DATABASE=Micortek ScanMaker X12USL + +usb:v05DAp3008* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v05DAp300A* + ID_MODEL_FROM_DATABASE=4800 ICE Scanner + +usb:v05DAp300B* + ID_MODEL_FROM_DATABASE=4800 Scanner + +usb:v05DAp300F* + ID_MODEL_FROM_DATABASE=MiniScan C5 + +usb:v05DAp3020* + ID_MODEL_FROM_DATABASE=4800dpi Scanner + +usb:v05DAp3021* + ID_MODEL_FROM_DATABASE=1200dpi Scanner + +usb:v05DAp3022* + ID_MODEL_FROM_DATABASE=Scanner 4800dpi + +usb:v05DAp3023* + ID_MODEL_FROM_DATABASE=USB1200II Scanner + +usb:v05DAp30C1* + ID_MODEL_FROM_DATABASE=USB600 Scanner + +usb:v05DAp30CE* + ID_MODEL_FROM_DATABASE=ScanMaker 3800 + +usb:v05DAp30CF* + ID_MODEL_FROM_DATABASE=ScanMaker 4800 + +usb:v05DAp30D4* + ID_MODEL_FROM_DATABASE=USB1200 Scanner + +usb:v05DAp30D8* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v05DAp30D9* + ID_MODEL_FROM_DATABASE=USB2400 Scanner + +usb:v05DAp30E4* + ID_MODEL_FROM_DATABASE=ScanMaker 4100 + +usb:v05DAp30E5* + ID_MODEL_FROM_DATABASE=USB3200 Scanner + +usb:v05DAp30E6* + ID_MODEL_FROM_DATABASE=ScanMaker i320 + +usb:v05DAp40B3* + ID_MODEL_FROM_DATABASE=ScanMaker 3600 + +usb:v05DAp40B8* + ID_MODEL_FROM_DATABASE=ScanMaker 3700 + +usb:v05DAp40C7* + ID_MODEL_FROM_DATABASE=ScanMaker 4600 + +usb:v05DAp40CA* + ID_MODEL_FROM_DATABASE=ScanMaker 3600 + +usb:v05DAp40CB* + ID_MODEL_FROM_DATABASE=ScanMaker 3700 + +usb:v05DAp40DD* + ID_MODEL_FROM_DATABASE=ScanMaker 3750i + +usb:v05DAp40FF* + ID_MODEL_FROM_DATABASE=ScanMaker 3600 + +usb:v05DAp5003* + ID_MODEL_FROM_DATABASE=Goya + +usb:v05DAp5013* + ID_MODEL_FROM_DATABASE=3200 Scanner + +usb:v05DAp80A3* + ID_MODEL_FROM_DATABASE=ScanMaker V6USL (#2) + +usb:v05DAp80AC* + ID_MODEL_FROM_DATABASE=ScanMaker V6UL/SpicyU + +usb:v05DB* + ID_VENDOR_FROM_DATABASE=Sun Corp. (Suntac?) + +usb:v05DBp0003* + ID_MODEL_FROM_DATABASE=SUNTAC U-Cable type D2 + +usb:v05DBp0005* + ID_MODEL_FROM_DATABASE=SUNTAC U-Cable type P1 + +usb:v05DBp0009* + ID_MODEL_FROM_DATABASE=SUNTAC Slipper U + +usb:v05DBp000A* + ID_MODEL_FROM_DATABASE=SUNTAC Ir-Trinity + +usb:v05DBp000B* + ID_MODEL_FROM_DATABASE=SUNTAC U-Cable type A3 + +usb:v05DBp0011* + ID_MODEL_FROM_DATABASE=SUNTAC U-Cable type A4 + +usb:v05DC* + ID_VENDOR_FROM_DATABASE=Lexar Media, Inc. + +usb:v05DCp0001* + ID_MODEL_FROM_DATABASE=jumpSHOT CompactFlash Reader + +usb:v05DCp0002* + ID_MODEL_FROM_DATABASE=JumpShot + +usb:v05DCp0003* + ID_MODEL_FROM_DATABASE=JumpShot + +usb:v05DCp0080* + ID_MODEL_FROM_DATABASE=Jumpdrive Secure 64MB + +usb:v05DCp0081* + ID_MODEL_FROM_DATABASE=RBC Compact Flash Drive + +usb:v05DCp00A7* + ID_MODEL_FROM_DATABASE=JumpDrive Impact + +usb:v05DCp0100* + ID_MODEL_FROM_DATABASE=JumpDrive PRO + +usb:v05DCp0200* + ID_MODEL_FROM_DATABASE=JumpDrive 2.0 Pro + +usb:v05DCp0300* + ID_MODEL_FROM_DATABASE=Jumpdrive Geysr + +usb:v05DCp0301* + ID_MODEL_FROM_DATABASE=JumpDrive Classic + +usb:v05DCp0302* + ID_MODEL_FROM_DATABASE=JD Micro + +usb:v05DCp0303* + ID_MODEL_FROM_DATABASE=JD Micro Pro + +usb:v05DCp0304* + ID_MODEL_FROM_DATABASE=JD Secure II + +usb:v05DCp0310* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0311* + ID_MODEL_FROM_DATABASE=JumpDrive Classic + +usb:v05DCp0312* + ID_MODEL_FROM_DATABASE=JD Micro + +usb:v05DCp0313* + ID_MODEL_FROM_DATABASE=JD Micro Pro + +usb:v05DCp0320* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0321* + ID_MODEL_FROM_DATABASE=JD Micro + +usb:v05DCp0322* + ID_MODEL_FROM_DATABASE=JD Micro Pro + +usb:v05DCp0323* + ID_MODEL_FROM_DATABASE=UFC + +usb:v05DCp0330* + ID_MODEL_FROM_DATABASE=JumpDrive Expression + +usb:v05DCp0340* + ID_MODEL_FROM_DATABASE=JumpDrive TAD + +usb:v05DCp0350* + ID_MODEL_FROM_DATABASE=Express Card + +usb:v05DCp0400* + ID_MODEL_FROM_DATABASE=UFDC + +usb:v05DCp0401* + ID_MODEL_FROM_DATABASE=UFDC + +usb:v05DCp0403* + ID_MODEL_FROM_DATABASE=Locked B Device + +usb:v05DCp0405* + ID_MODEL_FROM_DATABASE=Locked C Device + +usb:v05DCp0407* + ID_MODEL_FROM_DATABASE=Locked D Device + +usb:v05DCp0409* + ID_MODEL_FROM_DATABASE=Locked E Device + +usb:v05DCp040B* + ID_MODEL_FROM_DATABASE=Locked F Device + +usb:v05DCp040D* + ID_MODEL_FROM_DATABASE=Locked G Device + +usb:v05DCp040F* + ID_MODEL_FROM_DATABASE=Locked H Device + +usb:v05DCp0410* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0411* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0413* + ID_MODEL_FROM_DATABASE=Locked J Device + +usb:v05DCp0415* + ID_MODEL_FROM_DATABASE=Locked K Device + +usb:v05DCp0417* + ID_MODEL_FROM_DATABASE=Locked L Device + +usb:v05DCp0419* + ID_MODEL_FROM_DATABASE=Locked M Device + +usb:v05DCp041B* + ID_MODEL_FROM_DATABASE=Locked N Device + +usb:v05DCp041D* + ID_MODEL_FROM_DATABASE=Locked O Device + +usb:v05DCp041F* + ID_MODEL_FROM_DATABASE=Locked P Device + +usb:v05DCp0420* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0421* + ID_MODEL_FROM_DATABASE=JumpDrive + +usb:v05DCp0423* + ID_MODEL_FROM_DATABASE=Locked R Device + +usb:v05DCp0425* + ID_MODEL_FROM_DATABASE=Locked S Device + +usb:v05DCp0427* + ID_MODEL_FROM_DATABASE=Locked T Device + +usb:v05DCp0429* + ID_MODEL_FROM_DATABASE=Locked U Device + +usb:v05DCp042B* + ID_MODEL_FROM_DATABASE=Locked V Device + +usb:v05DCp042D* + ID_MODEL_FROM_DATABASE=Locked W Device + +usb:v05DCp042F* + ID_MODEL_FROM_DATABASE=Locked X Device + +usb:v05DCp0431* + ID_MODEL_FROM_DATABASE=Locked Y Device + +usb:v05DCp0433* + ID_MODEL_FROM_DATABASE=Locked Z Device + +usb:v05DCp4D02* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v05DCp4D12* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v05DCp4D30* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v05DCpA300* + ID_MODEL_FROM_DATABASE=JumpDrive2 + +usb:v05DCpA400* + ID_MODEL_FROM_DATABASE=JumpDrive trade; Pro 40-501 + +usb:v05DCpA410* + ID_MODEL_FROM_DATABASE=JumpDrive 128MB/256MB + +usb:v05DCpA411* + ID_MODEL_FROM_DATABASE=JumpDrive Traveler + +usb:v05DCpA420* + ID_MODEL_FROM_DATABASE=JumpDrive Pro + +usb:v05DCpA421* + ID_MODEL_FROM_DATABASE=JumpDrive Pro II + +usb:v05DCpA422* + ID_MODEL_FROM_DATABASE=JumpDrive Micro Pro + +usb:v05DCpA430* + ID_MODEL_FROM_DATABASE=JumpDrive Secure + +usb:v05DCpA431* + ID_MODEL_FROM_DATABASE=JumpDrive Secure II + +usb:v05DCpA432* + ID_MODEL_FROM_DATABASE=JumpDrive Classic + +usb:v05DCpA440* + ID_MODEL_FROM_DATABASE=JumpDrive Lightning + +usb:v05DCpA450* + ID_MODEL_FROM_DATABASE=JumpDrive TouchGuard + +usb:v05DCpA460* + ID_MODEL_FROM_DATABASE=JD Mercury + +usb:v05DCpA501* + ID_MODEL_FROM_DATABASE=JumpDrive Classic + +usb:v05DCpA510* + ID_MODEL_FROM_DATABASE=JumpDrive Sport + +usb:v05DCpA530* + ID_MODEL_FROM_DATABASE=JumpDrive Expression + +usb:v05DCpA531* + ID_MODEL_FROM_DATABASE=JumpDrive Secure II + +usb:v05DCpA560* + ID_MODEL_FROM_DATABASE=JumpDrive FireFly + +usb:v05DCpA701* + ID_MODEL_FROM_DATABASE=JumpDrive FireFly + +usb:v05DCpA731* + ID_MODEL_FROM_DATABASE=JumpDrive FireFly + +usb:v05DCpA790* + ID_MODEL_FROM_DATABASE=JumpDrive 2GB + +usb:v05DCpA811* + ID_MODEL_FROM_DATABASE=16GB Gizmo! + +usb:v05DCpA813* + ID_MODEL_FROM_DATABASE=16gB flash thumb drive + +usb:v05DCpB002* + ID_MODEL_FROM_DATABASE=USB CF Reader + +usb:v05DCpB018* + ID_MODEL_FROM_DATABASE=Multi-Card Reader + +usb:v05DCpB047* + ID_MODEL_FROM_DATABASE=SDHC Reader [RW047-7000] + +usb:v05DCpC753* + ID_MODEL_FROM_DATABASE=JumpDrive TwistTurn + +usb:v05DD* + ID_VENDOR_FROM_DATABASE=Delta Electronics, Inc. + +usb:v05DDpFF31* + ID_MODEL_FROM_DATABASE=AWU-120 + +usb:v05DDpFF32* + ID_MODEL_FROM_DATABASE=FriendlyNET AeroLAN AL2011 + +usb:v05DDpFF35* + ID_MODEL_FROM_DATABASE=PCW 100 - Wireless 802.11b Adapter + +usb:v05DDpFF91* + ID_MODEL_FROM_DATABASE=2Wire PC Port Phoneline 10Mbps Adapter + +usb:v05DF* + ID_VENDOR_FROM_DATABASE=Silicon Vision, Inc. + +usb:v05E0* + ID_VENDOR_FROM_DATABASE=Symbol Technologies + +usb:v05E0p0700* + ID_MODEL_FROM_DATABASE=Bar Code Scanner (CS1504) + +usb:v05E0p0800* + ID_MODEL_FROM_DATABASE=Spectrum24 Wireless LAN Adapter + +usb:v05E0p1200* + ID_MODEL_FROM_DATABASE=Bar Code Scanner + +usb:v05E0p1900* + ID_MODEL_FROM_DATABASE=SNAPI Imaging Device + +usb:v05E0p2000* + ID_MODEL_FROM_DATABASE=MC3090 Rugged Mobile Computer + +usb:v05E0p200D* + ID_MODEL_FROM_DATABASE=MC70 Rugged Mobile Computer + +usb:v05E1* + ID_VENDOR_FROM_DATABASE=Syntek Semiconductor Co., Ltd + +usb:v05E1p0100* + ID_MODEL_FROM_DATABASE=802.11g + Bluetooth Wireless Adapter + +usb:v05E1p0408* + ID_MODEL_FROM_DATABASE=STK1160 Video Capture Device + +usb:v05E1p0500* + ID_MODEL_FROM_DATABASE=DC-112X Webcam + +usb:v05E1p0501* + ID_MODEL_FROM_DATABASE=DC-1125 Webcam + +usb:v05E1p0890* + ID_MODEL_FROM_DATABASE=STK011 Camera + +usb:v05E1p0892* + ID_MODEL_FROM_DATABASE=STK013 Camera + +usb:v05E1p0895* + ID_MODEL_FROM_DATABASE=STK016 Camera + +usb:v05E1p0896* + ID_MODEL_FROM_DATABASE=STK017 Camera + +usb:v05E1p2010* + ID_MODEL_FROM_DATABASE=ARCTIC Sound P261 Headphones + +usb:v05E2* + ID_VENDOR_FROM_DATABASE=ElecVision, Inc. + +usb:v05E3* + ID_VENDOR_FROM_DATABASE=Genesys Logic, Inc. + +usb:v05E3p000A* + ID_MODEL_FROM_DATABASE=Keyboard with PS/2 Port + +usb:v05E3p000B* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v05E3p0100* + ID_MODEL_FROM_DATABASE=Nintendo Game Boy Advance SP + +usb:v05E3p0120* + ID_MODEL_FROM_DATABASE=Pacific Image Electronics PrimeFilm 1800u slide/negative scanner + +usb:v05E3p0131* + ID_MODEL_FROM_DATABASE=CF/SM Reader/Writer + +usb:v05E3p0142* + ID_MODEL_FROM_DATABASE=Multiple Slides Scanner-3600 + +usb:v05E3p0143* + ID_MODEL_FROM_DATABASE=Multiple Frames Film Scanner-36series + +usb:v05E3p0180* + ID_MODEL_FROM_DATABASE=Plustek Scanner + +usb:v05E3p0182* + ID_MODEL_FROM_DATABASE=Wize Media 1000 + +usb:v05E3p0189* + ID_MODEL_FROM_DATABASE=ScanJet 4600 series + +usb:v05E3p018A* + ID_MODEL_FROM_DATABASE=Xerox 6400 + +usb:v05E3p0300* + ID_MODEL_FROM_DATABASE=GLUSB98PT Parallel Port + +usb:v05E3p0301* + ID_MODEL_FROM_DATABASE=USB2LPT Cable Release2 + +usb:v05E3p0406* + ID_MODEL_FROM_DATABASE=Hub + +usb:v05E3p0501* + ID_MODEL_FROM_DATABASE=GL620USB Host-Host interface + +usb:v05E3p0502* + ID_MODEL_FROM_DATABASE=GL620USB-A GeneLink USB-USB Bridge + +usb:v05E3p0503* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v05E3p0504* + ID_MODEL_FROM_DATABASE=HID Keyboard Filter + +usb:v05E3p0604* + ID_MODEL_FROM_DATABASE=USB 1.1 Hub + +usb:v05E3p0605* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v05E3p0606* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub / D-Link DUB-H4 USB 2.0 Hub + +usb:v05E3p0607* + ID_MODEL_FROM_DATABASE=Logitech G110 Hub + +usb:v05E3p0608* + ID_MODEL_FROM_DATABASE=USB-2.0 4-Port HUB + +usb:v05E3p0610* + ID_MODEL_FROM_DATABASE=4-port hub + +usb:v05E3p0660* + ID_MODEL_FROM_DATABASE=USB 2.0 Hub + +usb:v05E3p0700* + ID_MODEL_FROM_DATABASE=SIIG US2256 CompactFlash Card Reader + +usb:v05E3p0701* + ID_MODEL_FROM_DATABASE=USB 2.0 IDE Adapter + +usb:v05E3p0702* + ID_MODEL_FROM_DATABASE=USB 2.0 IDE Adapter [GL811E] + +usb:v05E3p0703* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0704* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0705* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0706* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0707* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0708* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0709* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p070A* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v05E3p070B* + ID_MODEL_FROM_DATABASE=DMHS1B Rev 3 DFU Adapter + +usb:v05E3p070E* + ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader + +usb:v05E3p070F* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v05E3p0710* + ID_MODEL_FROM_DATABASE=USB 2.0 33-in-1 Card Reader + +usb:v05E3p0711* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p0712* + ID_MODEL_FROM_DATABASE=Delkin Mass Storage Device + +usb:v05E3p0715* + ID_MODEL_FROM_DATABASE=USB 2.0 microSD Reader + +usb:v05E3p0716* + ID_MODEL_FROM_DATABASE=USB 2.0 Multislot Card Reader/Writer + +usb:v05E3p0717* + ID_MODEL_FROM_DATABASE=All-in-1 Card Reader + +usb:v05E3p0718* + ID_MODEL_FROM_DATABASE=IDE/SATA Adapter + +usb:v05E3p0719* + ID_MODEL_FROM_DATABASE=SATA adapter + +usb:v05E3p0723* + ID_MODEL_FROM_DATABASE=GL827L SD/MMC/MS Flash Card Reader + +usb:v05E3p0726* + ID_MODEL_FROM_DATABASE=SD Card Reader + +usb:v05E3p0727* + ID_MODEL_FROM_DATABASE=microSD Reader/Writer + +usb:v05E3p0731* + ID_MODEL_FROM_DATABASE=GL3310 SATA 3Gb/s Bridge Controller + +usb:v05E3p0736* + ID_MODEL_FROM_DATABASE=microSD Reader/Writer + +usb:v05E3p0760* + ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader/Writer + +usb:v05E3p0761* + ID_MODEL_FROM_DATABASE=Genesys Mass Storage Device + +usb:v05E3p0780* + ID_MODEL_FROM_DATABASE=USBFS DFU Adapter + +usb:v05E3p07A0* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v05E3p0880* + ID_MODEL_FROM_DATABASE=Wasp (SL-6612) + +usb:v05E3p0927* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v05E3p1205* + ID_MODEL_FROM_DATABASE=Afilias Optical Mouse H3003 / Trust Optical USB MultiColour Mouse MI-2330 + +usb:v05E3pA700* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v05E3pF102* + ID_MODEL_FROM_DATABASE=VX7012 TV Box + +usb:v05E3pF103* + ID_MODEL_FROM_DATABASE=VX7012 TV Box + +usb:v05E3pF104* + ID_MODEL_FROM_DATABASE=VX7012 TV Box + +usb:v05E3pFD21* + ID_MODEL_FROM_DATABASE=3M TL20 Temperature Logger + +usb:v05E3pFE00* + ID_MODEL_FROM_DATABASE=Razer Mouse + +usb:v05E4* + ID_VENDOR_FROM_DATABASE=Red Wing Corp. + +usb:v05E5* + ID_VENDOR_FROM_DATABASE=Fuji Electric Co., Ltd + +usb:v05E6* + ID_VENDOR_FROM_DATABASE=Keithley Instruments + +usb:v05E8* + ID_VENDOR_FROM_DATABASE=ICC, Inc. + +usb:v05E9* + ID_VENDOR_FROM_DATABASE=Kawasaki LSI + +usb:v05E9p0008* + ID_MODEL_FROM_DATABASE=KL5KUSB101B Ethernet [klsi] + +usb:v05E9p0009* + ID_MODEL_FROM_DATABASE=Sony 10Mbps Ethernet [pegasus] + +usb:v05E9p000C* + ID_MODEL_FROM_DATABASE=USB-to-RS-232 + +usb:v05E9p000D* + ID_MODEL_FROM_DATABASE=USB-to-RS-232 + +usb:v05E9p0014* + ID_MODEL_FROM_DATABASE=RS-232 J104 + +usb:v05E9p0040* + ID_MODEL_FROM_DATABASE=Ethernet Adapter + +usb:v05E9p2008* + ID_MODEL_FROM_DATABASE=Ethernet Adapter + +usb:v05EB* + ID_VENDOR_FROM_DATABASE=FFC, Ltd + +usb:v05EC* + ID_VENDOR_FROM_DATABASE=COM21, Inc. + +usb:v05EE* + ID_VENDOR_FROM_DATABASE=Cytechinfo Inc. + +usb:v05EF* + ID_VENDOR_FROM_DATABASE=AVB, Inc. [anko?] + +usb:v05EFp020A* + ID_MODEL_FROM_DATABASE=Top Shot Pegasus Joystick + +usb:v05EFp8884* + ID_MODEL_FROM_DATABASE=Mag Turbo Force Wheel + +usb:v05EFp8888* + ID_MODEL_FROM_DATABASE=Top Shot Force Feedback Racing Wheel + +usb:v05F0* + ID_VENDOR_FROM_DATABASE=Canopus Co., Ltd + +usb:v05F0p0101* + ID_MODEL_FROM_DATABASE=DA-Port DAC + +usb:v05F1* + ID_VENDOR_FROM_DATABASE=Compass Communications + +usb:v05F2* + ID_VENDOR_FROM_DATABASE=Dexin Corp., Ltd + +usb:v05F2p0010* + ID_MODEL_FROM_DATABASE=AQ Mouse + +usb:v05F3* + ID_VENDOR_FROM_DATABASE=PI Engineering, Inc. + +usb:v05F3p0007* + ID_MODEL_FROM_DATABASE=Kinesis Advantage PRO MPC/USB Keyboard + +usb:v05F3p0081* + ID_MODEL_FROM_DATABASE=Kinesis Integrated Hub + +usb:v05F3p00FF* + ID_MODEL_FROM_DATABASE=VEC Footpedal + +usb:v05F3p020B* + ID_MODEL_FROM_DATABASE=PS2 Adapter + +usb:v05F3p0232* + ID_MODEL_FROM_DATABASE=X-Keys Switch Interface, Programming Mode + +usb:v05F3p0261* + ID_MODEL_FROM_DATABASE=X-Keys Switch Interface, SPLAT Mode + +usb:v05F3p0264* + ID_MODEL_FROM_DATABASE=X-Keys Switch Interface, Composite Mode + +usb:v05F5* + ID_VENDOR_FROM_DATABASE=Unixtar Technology, Inc. + +usb:v05F6* + ID_VENDOR_FROM_DATABASE=AOC International + +usb:v05F7* + ID_VENDOR_FROM_DATABASE=RFC Distribution(s) PTE, Ltd + +usb:v05F9* + ID_VENDOR_FROM_DATABASE=PSC Scanning, Inc. + +usb:v05F9p1104* + ID_MODEL_FROM_DATABASE=Magellan 2200VS + +usb:v05F9p2202* + ID_MODEL_FROM_DATABASE=Point of Sale Handheld Scanner + +usb:v05F9p2206* + ID_MODEL_FROM_DATABASE=Datalogic Gryphon GFS4170 + +usb:v05F9p2601* + ID_MODEL_FROM_DATABASE=Datalogin Magellan 1000i Barcode Scanner + +usb:v05F9p2602* + ID_MODEL_FROM_DATABASE=Datalogic Magellan 1100i Barcode Scanner + +usb:v05F9p5204* + ID_MODEL_FROM_DATABASE=Datalogic Gryphon GFS4170 (config mode) + +usb:v05FA* + ID_VENDOR_FROM_DATABASE=Siemens Telecommunications Systems, Ltd + +usb:v05FAp3301* + ID_MODEL_FROM_DATABASE=Keyboard with PS/2 Mouse Port + +usb:v05FAp3302* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v05FAp3303* + ID_MODEL_FROM_DATABASE=Keyboard with PS/2 Mouse Port + +usb:v05FC* + ID_VENDOR_FROM_DATABASE=Harman Multimedia + +usb:v05FCp7849* + ID_MODEL_FROM_DATABASE=Harman/Kardon SoundSticks + +usb:v05FD* + ID_VENDOR_FROM_DATABASE=InterAct, Inc. + +usb:v05FDp0239* + ID_MODEL_FROM_DATABASE=SV-239 HammerHead Digital + +usb:v05FDp0251* + ID_MODEL_FROM_DATABASE=Raider Pro + +usb:v05FDp0253* + ID_MODEL_FROM_DATABASE=ProPad 8 Digital + +usb:v05FDp0286* + ID_MODEL_FROM_DATABASE=SV-286 Cyclone Digital + +usb:v05FDp107A* + ID_MODEL_FROM_DATABASE=PowerPad Pro X-Box pad + +usb:v05FDp262A* + ID_MODEL_FROM_DATABASE=3dfx HammerHead FX + +usb:v05FDp262F* + ID_MODEL_FROM_DATABASE=HammerHead Fx + +usb:v05FDpDAAE* + ID_MODEL_FROM_DATABASE=Game Shark + +usb:v05FE* + ID_VENDOR_FROM_DATABASE=Chic Technology Corp. + +usb:v05FEp0001* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v05FEp0003* + ID_MODEL_FROM_DATABASE=Cypress USB Mouse + +usb:v05FEp0005* + ID_MODEL_FROM_DATABASE=Viewmaster 4D Browser Mouse + +usb:v05FEp0007* + ID_MODEL_FROM_DATABASE=Twinhead Mouse + +usb:v05FEp0009* + ID_MODEL_FROM_DATABASE=Inland Pro 4500/5000 Mouse + +usb:v05FEp0011* + ID_MODEL_FROM_DATABASE=Browser Mouse + +usb:v05FEp0014* + ID_MODEL_FROM_DATABASE=Gamepad + +usb:v05FEp1010* + ID_MODEL_FROM_DATABASE=Optical Wireless + +usb:v05FF* + ID_VENDOR_FROM_DATABASE=LeCroy Corp. + +usb:v0600* + ID_VENDOR_FROM_DATABASE=Barco Display Systems + +usb:v0601* + ID_VENDOR_FROM_DATABASE=Jazz Hipster Corp. + +usb:v0601p0003* + ID_MODEL_FROM_DATABASE=Internet Security Co., Ltd. SecureKey + +usb:v0602* + ID_VENDOR_FROM_DATABASE=Vista Imaging, Inc. + +usb:v0602p1001* + ID_MODEL_FROM_DATABASE=ViCam Webcam + +usb:v0603* + ID_VENDOR_FROM_DATABASE=Novatek Microelectronics Corp. + +usb:v0603p00F1* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0603p6871* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0604* + ID_VENDOR_FROM_DATABASE=Jean Co., Ltd + +usb:v0605* + ID_VENDOR_FROM_DATABASE=Anchor C&C Co., Ltd + +usb:v0606* + ID_VENDOR_FROM_DATABASE=Royal Information Electronics Co., Ltd + +usb:v0607* + ID_VENDOR_FROM_DATABASE=Bridge Information Co., Ltd + +usb:v0608* + ID_VENDOR_FROM_DATABASE=Genrad Ads + +usb:v0609* + ID_VENDOR_FROM_DATABASE=SMK Manufacturing, Inc. + +usb:v0609p031D* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0609p0322* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0609p0334* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0609pFF12* + ID_MODEL_FROM_DATABASE=SMK Bluetooth Device + +usb:v060A* + ID_VENDOR_FROM_DATABASE=Worthington Data Solutions, Inc. + +usb:v060B* + ID_VENDOR_FROM_DATABASE=Solid Year + +usb:v060Bp0001* + ID_MODEL_FROM_DATABASE=MacAlly Keyboard + +usb:v060Bp0230* + ID_MODEL_FROM_DATABASE=KSK-8003 UX Keyboard + +usb:v060Bp1006* + ID_MODEL_FROM_DATABASE=Japanese Keyboard - 260U + +usb:v060Bp2101* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v060Bp2231* + ID_MODEL_FROM_DATABASE=KSK-6001 UELX Keyboard + +usb:v060Bp2270* + ID_MODEL_FROM_DATABASE=Gigabyte K8100 Aivia Gaming Keyboard + +usb:v060Bp5811* + ID_MODEL_FROM_DATABASE=ACK-571U Wireless Keyboard + +usb:v060Bp5903* + ID_MODEL_FROM_DATABASE=Japanese Keyboard - 595U + +usb:v060Bp6001* + ID_MODEL_FROM_DATABASE=SolidTek USB 2p HUB + +usb:v060Bp6002* + ID_MODEL_FROM_DATABASE=SolidTek USB Keyboard + +usb:v060Bp6003* + ID_MODEL_FROM_DATABASE=Japanese Keyboard - 600HM + +usb:v060Bp6231* + ID_MODEL_FROM_DATABASE=Thermaltake eSPORTS Meka Keyboard + +usb:v060Bp8007* + ID_MODEL_FROM_DATABASE=P-W1G1F12 VER:1 [Macally MegaCam] + +usb:v060BpA001* + ID_MODEL_FROM_DATABASE=Maxwell Compact Pc PM3 + +usb:v060C* + ID_VENDOR_FROM_DATABASE=EEH Datalink GmbH + +usb:v060D* + ID_VENDOR_FROM_DATABASE=Auctor Corp. + +usb:v060E* + ID_VENDOR_FROM_DATABASE=Transmonde Technologies, Inc. + +usb:v060F* + ID_VENDOR_FROM_DATABASE=Joinsoon Electronics Mfg. Co., Ltd + +usb:v0610* + ID_VENDOR_FROM_DATABASE=Costar Electronics, Inc. + +usb:v0611* + ID_VENDOR_FROM_DATABASE=Totoku Electric Co., Ltd + +usb:v0613* + ID_VENDOR_FROM_DATABASE=TransAct Technologies, Inc. + +usb:v0614* + ID_VENDOR_FROM_DATABASE=Bio-Rad Laboratories + +usb:v0615* + ID_VENDOR_FROM_DATABASE=Quabbin Wire & Cable Co., Inc. + +usb:v0616* + ID_VENDOR_FROM_DATABASE=Future Techno Designs PVT, Ltd + +usb:v0617* + ID_VENDOR_FROM_DATABASE=Swiss Federal Insitute of Technology + +usb:v0618* + ID_VENDOR_FROM_DATABASE=MacAlly + +usb:v0618p0101* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0619* + ID_VENDOR_FROM_DATABASE=Seiko Instruments, Inc. + +usb:v0619p0101* + ID_MODEL_FROM_DATABASE=SLP-100 Driver + +usb:v0619p0102* + ID_MODEL_FROM_DATABASE=SLP-200 Driver + +usb:v0619p0103* + ID_MODEL_FROM_DATABASE=SLP-100N Driver + +usb:v0619p0104* + ID_MODEL_FROM_DATABASE=SLP-200N Driver + +usb:v0619p0105* + ID_MODEL_FROM_DATABASE=SLP-240 Driver + +usb:v0619p0501* + ID_MODEL_FROM_DATABASE=SLP-440 Driver + +usb:v0619p0502* + ID_MODEL_FROM_DATABASE=SLP-450 Driver + +usb:v061A* + ID_VENDOR_FROM_DATABASE=Veridicom International, Inc. + +usb:v061Ap0110* + ID_MODEL_FROM_DATABASE=5thSense Fingerprint Sensor + +usb:v061Ap0200* + ID_MODEL_FROM_DATABASE=FPS200 Fingerprint Sensor + +usb:v061Ap8200* + ID_MODEL_FROM_DATABASE=VKI-A Fingerprint Sensor/Flash Storage (dumb) + +usb:v061Ap9200* + ID_MODEL_FROM_DATABASE=VKI-B Fingerprint Sensor/Flash Storage (smart) + +usb:v061B* + ID_VENDOR_FROM_DATABASE=Promptus Communications, Inc. + +usb:v061C* + ID_VENDOR_FROM_DATABASE=Act Labs, Ltd + +usb:v061D* + ID_VENDOR_FROM_DATABASE=Quatech, Inc. + +usb:v061DpC020* + ID_MODEL_FROM_DATABASE=SSU-100 + +usb:v061E* + ID_VENDOR_FROM_DATABASE=Nissei Electric Co. + +usb:v061Ep0001* + ID_MODEL_FROM_DATABASE=nissei 128DE-USB - + +usb:v061Ep0010* + ID_MODEL_FROM_DATABASE=nissei 128DE-PNA - + +usb:v0620* + ID_VENDOR_FROM_DATABASE=Alaris, Inc. + +usb:v0620p0004* + ID_MODEL_FROM_DATABASE=QuickVideo weeCam + +usb:v0620p0007* + ID_MODEL_FROM_DATABASE=QuickVideo weeCam + +usb:v0620p000A* + ID_MODEL_FROM_DATABASE=QuickVideo weeCam + +usb:v0620p000B* + ID_MODEL_FROM_DATABASE=QuickVideo weeCam + +usb:v0621* + ID_VENDOR_FROM_DATABASE=ODU-Steckverbindungssysteme GmbH & Co. KG + +usb:v0622* + ID_VENDOR_FROM_DATABASE=Iotech, Inc. + +usb:v0623* + ID_VENDOR_FROM_DATABASE=Littelfuse, Inc. + +usb:v0624* + ID_VENDOR_FROM_DATABASE=Avocent Corp. + +usb:v0624p0248* + ID_MODEL_FROM_DATABASE=Virtual Hub + +usb:v0624p0249* + ID_MODEL_FROM_DATABASE=Virtual Keyboard/Mouse + +usb:v0624p0251* + ID_MODEL_FROM_DATABASE=Virtual Mass Storage + +usb:v0624p0294* + ID_MODEL_FROM_DATABASE=Dell 03R874 KVM dongle + +usb:v0624p0402* + ID_MODEL_FROM_DATABASE=Cisco Virtual Keyboard and Mouse + +usb:v0624p0403* + ID_MODEL_FROM_DATABASE=Cisco Virtual Mass Storage + +usb:v0625* + ID_VENDOR_FROM_DATABASE=TiMedia Technology Co., Ltd + +usb:v0626* + ID_VENDOR_FROM_DATABASE=Nippon Systems Development Co., Ltd + +usb:v0627* + ID_VENDOR_FROM_DATABASE=Adomax Technology Co., Ltd + +usb:v0628* + ID_VENDOR_FROM_DATABASE=Tasking Software, Inc. + +usb:v0629* + ID_VENDOR_FROM_DATABASE=Zida Technologies, Ltd + +usb:v062A* + ID_VENDOR_FROM_DATABASE=Creative Labs + +usb:v062Ap0000* + ID_MODEL_FROM_DATABASE=Optical mouse + +usb:v062Ap0001* + ID_MODEL_FROM_DATABASE=Notebook Optical Mouse + +usb:v062Ap0102* + ID_MODEL_FROM_DATABASE=Wireless Keyboard/Mouse Combo [MK1152WC] + +usb:v062Ap0201* + ID_MODEL_FROM_DATABASE=Defender Office Keyboard (K7310) S Zodiak KM-9010 + +usb:v062Ap0252* + ID_MODEL_FROM_DATABASE=Emerge Uni-retractable Laser Mouse + +usb:v062Ap3286* + ID_MODEL_FROM_DATABASE=Nano Receiver [Sandstrom Laser Mouse SMWLL11] + +usb:v062Ap6301* + ID_MODEL_FROM_DATABASE=Trust Wireless Optical Mouse MI-4150K + +usb:v062Ap9003* + ID_MODEL_FROM_DATABASE=VoIP Conference Hub (A16GH) + +usb:v062Ap9004* + ID_MODEL_FROM_DATABASE=USR9602 USB Internet Mini Phone + +usb:v062B* + ID_VENDOR_FROM_DATABASE=Greatlink Electronics Taiwan, Ltd + +usb:v062C* + ID_VENDOR_FROM_DATABASE=Institute for Information Industry + +usb:v062D* + ID_VENDOR_FROM_DATABASE=Taiwan Tai-Hao Enterprises Co., Ltd + +usb:v062E* + ID_VENDOR_FROM_DATABASE=Mainsuper Enterprises Co., Ltd + +usb:v062F* + ID_VENDOR_FROM_DATABASE=Sin Sheng Terminal & Machine, Inc. + +usb:v0631* + ID_VENDOR_FROM_DATABASE=JUJO Electronics Corp. + +usb:v0633* + ID_VENDOR_FROM_DATABASE=Cyrix Corp. + +usb:v0634* + ID_VENDOR_FROM_DATABASE=Micron Technology, Inc. + +usb:v0634p0655* + ID_MODEL_FROM_DATABASE=Embedded Mass Storage Drive [RealSSD] + +usb:v0635* + ID_VENDOR_FROM_DATABASE=Methode Electronics, Inc. + +usb:v0636* + ID_VENDOR_FROM_DATABASE=Sierra Imaging, Inc. + +usb:v0636p0003* + ID_MODEL_FROM_DATABASE=Vivicam 35Xx + +usb:v0638* + ID_VENDOR_FROM_DATABASE=Avision, Inc. + +usb:v0638p0268* + ID_MODEL_FROM_DATABASE=iVina 1200U Scanner + +usb:v0638p026A* + ID_MODEL_FROM_DATABASE=Minolta Dimage Scan Dual II AF-2820U (2886) + +usb:v0638p0A10* + ID_MODEL_FROM_DATABASE=iVina FB1600/UMAX Astra 4500 + +usb:v0638p0A13* + ID_MODEL_FROM_DATABASE=AV600U + +usb:v0638p0A15* + ID_MODEL_FROM_DATABASE=Konica Minolta SC-110 + +usb:v0638p0A16* + ID_MODEL_FROM_DATABASE=Konica Minolta SC-215 + +usb:v0638p0A30* + ID_MODEL_FROM_DATABASE=UMAX Astra 6700 Scanner + +usb:v0638p0A41* + ID_MODEL_FROM_DATABASE=Avision AM3000/MF3000 Series + +usb:v0638p0F01* + ID_MODEL_FROM_DATABASE=fi-4010CU + +usb:v0638p4004* + ID_MODEL_FROM_DATABASE=Minolta Dimage Scan Elite II AF-2920 (2888) + +usb:v0639* + ID_VENDOR_FROM_DATABASE=Chrontel, Inc. + +usb:v063A* + ID_VENDOR_FROM_DATABASE=Techwin Corp. + +usb:v063B* + ID_VENDOR_FROM_DATABASE=Taugagreining HF + +usb:v063C* + ID_VENDOR_FROM_DATABASE=Yamaichi Electronics Co., Ltd (Sakura) + +usb:v063D* + ID_VENDOR_FROM_DATABASE=Fong Kai Industrial Co., Ltd + +usb:v063E* + ID_VENDOR_FROM_DATABASE=RealMedia Technology, Inc. + +usb:v063F* + ID_VENDOR_FROM_DATABASE=New Technology Cable, Ltd + +usb:v0640* + ID_VENDOR_FROM_DATABASE=Hitex Development Tools + +usb:v0640p0026* + ID_MODEL_FROM_DATABASE=LPC-Stick + +usb:v0641* + ID_VENDOR_FROM_DATABASE=Woods Industries, Inc. + +usb:v0642* + ID_VENDOR_FROM_DATABASE=VIA Medical Corp. + +usb:v0644* + ID_VENDOR_FROM_DATABASE=TEAC Corp. + +usb:v0644p0000* + ID_MODEL_FROM_DATABASE=Floppy + +usb:v0644p0200* + ID_MODEL_FROM_DATABASE=All-In-One Multi-Card Reader CA200/B/S + +usb:v0644p1000* + ID_MODEL_FROM_DATABASE=CD-ROM Drive + +usb:v0644p800D* + ID_MODEL_FROM_DATABASE=TASCAM Portastudio DP-01FX + +usb:v0644p800E* + ID_MODEL_FROM_DATABASE=TASCAM US-122L + +usb:v0644p801D* + ID_MODEL_FROM_DATABASE=DR-100 + +usb:v0644p8021* + ID_MODEL_FROM_DATABASE=TASCAM US-122mkII + +usb:v0644pD001* + ID_MODEL_FROM_DATABASE=CD-R/RW Unit + +usb:v0644pD002* + ID_MODEL_FROM_DATABASE=CD-R/RW Unit + +usb:v0644pD010* + ID_MODEL_FROM_DATABASE=CD-RW/DVD Unit + +usb:v0645* + ID_VENDOR_FROM_DATABASE=Who? Vision Systems, Inc. + +usb:v0646* + ID_VENDOR_FROM_DATABASE=UMAX + +usb:v0647* + ID_VENDOR_FROM_DATABASE=Acton Research Corp. + +usb:v0647p0100* + ID_MODEL_FROM_DATABASE=ARC SpectraPro UV/VIS/IR Monochromator/Spectrograph + +usb:v0647p0101* + ID_MODEL_FROM_DATABASE=ARC AM-VM Mono Airpath/Vacuum Monochromator/Spectrograph + +usb:v0647p0102* + ID_MODEL_FROM_DATABASE=ARC Inspectrum Mono + +usb:v0647p0103* + ID_MODEL_FROM_DATABASE=ARC Filterwheel + +usb:v0647p03E9* + ID_MODEL_FROM_DATABASE=Inspectrum 128x1024 F VIS Spectrograph + +usb:v0647p03EA* + ID_MODEL_FROM_DATABASE=Inspectrum 256x1024 F VIS Spectrograph + +usb:v0647p03EB* + ID_MODEL_FROM_DATABASE=Inspectrum 128x1024 B VIS Spectrograph + +usb:v0647p03EC* + ID_MODEL_FROM_DATABASE=Inspectrum 256x1024 B VIS Spectrograph + +usb:v0648* + ID_VENDOR_FROM_DATABASE=Inside Out Networks + +usb:v0649* + ID_VENDOR_FROM_DATABASE=Weli Science Co., Ltd + +usb:v064B* + ID_VENDOR_FROM_DATABASE=Analog Devices, Inc. (White Mountain DSP) + +usb:v064Bp0165* + ID_MODEL_FROM_DATABASE=Blackfin 535 [ADZS HPUSB ICE] + +usb:v064C* + ID_VENDOR_FROM_DATABASE=Ji-Haw Industrial Co., Ltd + +usb:v064D* + ID_VENDOR_FROM_DATABASE=TriTech Microelectronics, Ltd + +usb:v064E* + ID_VENDOR_FROM_DATABASE=Suyin Corp. + +usb:v064EpA100* + ID_MODEL_FROM_DATABASE=Acer OrbiCam + +usb:v064EpA101* + ID_MODEL_FROM_DATABASE=Acer CrystalEye Webcam + +usb:v064EpA102* + ID_MODEL_FROM_DATABASE=Acer/Lenovo Webcam [CN0316] + +usb:v064EpA103* + ID_MODEL_FROM_DATABASE=Acer/HP Integrated Webcam [CN0314] + +usb:v064EpA110* + ID_MODEL_FROM_DATABASE=HP Webcam + +usb:v064EpA114* + ID_MODEL_FROM_DATABASE=Lemote Webcam + +usb:v064EpA136* + ID_MODEL_FROM_DATABASE=Asus Integrated Webcam [CN031B] + +usb:v064EpA219* + ID_MODEL_FROM_DATABASE=1.3M WebCam (notebook emachines E730, Acer sub-brand) + +usb:v064EpC107* + ID_MODEL_FROM_DATABASE=HP webcam [dv6-1190en] + +usb:v064EpD101* + ID_MODEL_FROM_DATABASE=Acer CrystalEye Webcam + +usb:v064EpD217* + ID_MODEL_FROM_DATABASE=HP TrueVision HD + +usb:v064EpE201* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam + +usb:v064EpE203* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam + +usb:v064EpE258* + ID_MODEL_FROM_DATABASE=HP TrueVision HD Integrated Webcam + +usb:v064EpF102* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam [R5U877] + +usb:v064EpF103* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam [R5U877] + +usb:v064EpF300* + ID_MODEL_FROM_DATABASE=UVC 0.3M Webcam + +usb:v064F* + ID_VENDOR_FROM_DATABASE=WIBU-Systems AG + +usb:v064Fp03E9* + ID_MODEL_FROM_DATABASE=CmStick (article no. 1001) + +usb:v064Fp03F2* + ID_MODEL_FROM_DATABASE=CmStick/M (article no. 1010) + +usb:v064Fp03F3* + ID_MODEL_FROM_DATABASE=CmStick/M (article no. 1011) + +usb:v064Fp0BD7* + ID_MODEL_FROM_DATABASE=BOX/U + +usb:v064Fp0BD8* + ID_MODEL_FROM_DATABASE=BOX/RU + +usb:v0650* + ID_VENDOR_FROM_DATABASE=Dynapro Systems + +usb:v0651* + ID_VENDOR_FROM_DATABASE=Likom Technology Sdn. Bhd. + +usb:v0652* + ID_VENDOR_FROM_DATABASE=Stargate Solutions, Inc. + +usb:v0653* + ID_VENDOR_FROM_DATABASE=CNF, Inc. + +usb:v0654* + ID_VENDOR_FROM_DATABASE=Granite Microsystems, Inc. + +usb:v0654p0005* + ID_MODEL_FROM_DATABASE=Device Bay Controller + +usb:v0654p0006* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0654p0007* + ID_MODEL_FROM_DATABASE=Device Bay Controller + +usb:v0654p0016* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0655* + ID_VENDOR_FROM_DATABASE=Space Shuttle Hi-Tech Co., Ltd + +usb:v0656* + ID_VENDOR_FROM_DATABASE=Glory Mark Electronic, Ltd + +usb:v0657* + ID_VENDOR_FROM_DATABASE=Tekcon Electronics Corp. + +usb:v0658* + ID_VENDOR_FROM_DATABASE=Sigma Designs, Inc. + +usb:v0659* + ID_VENDOR_FROM_DATABASE=Aethra + +usb:v065A* + ID_VENDOR_FROM_DATABASE=Optoelectronics Co., Ltd + +usb:v065Ap0001* + ID_MODEL_FROM_DATABASE=Opticon OPR-2001 / NLV-1001 (keyboard mode) + +usb:v065Ap0009* + ID_MODEL_FROM_DATABASE=NLV-1001 (serial mode) / OPN-2001 [Opticon] + +usb:v065B* + ID_VENDOR_FROM_DATABASE=Tracewell Systems + +usb:v065E* + ID_VENDOR_FROM_DATABASE=Silicon Graphics + +usb:v065F* + ID_VENDOR_FROM_DATABASE=Good Way Technology Co., Ltd & GWC technology Inc. + +usb:v0660* + ID_VENDOR_FROM_DATABASE=TSAY-E (BVI) International, Inc. + +usb:v0661* + ID_VENDOR_FROM_DATABASE=Hamamatsu Photonics K.K. + +usb:v0662* + ID_VENDOR_FROM_DATABASE=Kansai Electric Co., Ltd + +usb:v0663* + ID_VENDOR_FROM_DATABASE=Topmax Electronic Co., Ltd + +usb:v0663p0103* + ID_MODEL_FROM_DATABASE=CobraPad + +usb:v0664* + ID_VENDOR_FROM_DATABASE=ET&T Technology Co., Ltd. + +usb:v0664p0301* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0302* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0303* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0304* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0305* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0306* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0307* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0664p0309* + ID_MODEL_FROM_DATABASE=Groovy Technology Corp. GTouch Touch Screen + +usb:v0665* + ID_VENDOR_FROM_DATABASE=Cypress Semiconductor + +usb:v0665p5161* + ID_MODEL_FROM_DATABASE=USB to Serial + +usb:v0667* + ID_VENDOR_FROM_DATABASE=Aiwa Co., Ltd + +usb:v0667p0FA1* + ID_MODEL_FROM_DATABASE=TD-U8000 Tape Drive + +usb:v0668* + ID_VENDOR_FROM_DATABASE=WordWand + +usb:v0669* + ID_VENDOR_FROM_DATABASE=Oce' Printing Systems GmbH + +usb:v066A* + ID_VENDOR_FROM_DATABASE=Total Technologies, Ltd + +usb:v066B* + ID_VENDOR_FROM_DATABASE=Linksys, Inc. + +usb:v066Bp0105* + ID_MODEL_FROM_DATABASE=SCM eUSB SmartMedia Card Reader + +usb:v066Bp010A* + ID_MODEL_FROM_DATABASE=Melco MCR-U2 SmartMedia / CompactFlash Reader + +usb:v066Bp200C* + ID_MODEL_FROM_DATABASE=USB10TX + +usb:v066Bp2202* + ID_MODEL_FROM_DATABASE=USB10TX Ethernet [pegasus] + +usb:v066Bp2203* + ID_MODEL_FROM_DATABASE=USB100TX Ethernet [pegasus] + +usb:v066Bp2204* + ID_MODEL_FROM_DATABASE=USB100TX HomePNA Ethernet [pegasus] + +usb:v066Bp2206* + ID_MODEL_FROM_DATABASE=USB Ethernet [pegasus] + +usb:v066Bp2207* + ID_MODEL_FROM_DATABASE=HomeLink Phoneline 10M Network Adapter + +usb:v066Bp2211* + ID_MODEL_FROM_DATABASE=WUSB11 802.11b Adapter + +usb:v066Bp2212* + ID_MODEL_FROM_DATABASE=WUSB11v2.5 802.11b Adapter + +usb:v066Bp2213* + ID_MODEL_FROM_DATABASE=WUSB12v1.1 802.11b Adapter + +usb:v066Bp2219* + ID_MODEL_FROM_DATABASE=Instant Wireless Network Adapter + +usb:v066Bp400B* + ID_MODEL_FROM_DATABASE=USB10TX + +usb:v066D* + ID_VENDOR_FROM_DATABASE=Entrega, Inc. + +usb:v066E* + ID_VENDOR_FROM_DATABASE=Acer Semiconductor America, Inc. + +usb:v066F* + ID_VENDOR_FROM_DATABASE=SigmaTel, Inc. + +usb:v066Fp003B* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp003E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp003F* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp0040* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp0041* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp0042* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp0043* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp004B* + ID_MODEL_FROM_DATABASE=A-Max PA11 MP3 Player + +usb:v066Fp3400* + ID_MODEL_FROM_DATABASE=STMP3400 D-Major MP3 Player + +usb:v066Fp3410* + ID_MODEL_FROM_DATABASE=STMP3410 D-Major MP3 Player + +usb:v066Fp3500* + ID_MODEL_FROM_DATABASE=Player Recovery Device + +usb:v066Fp3780* + ID_MODEL_FROM_DATABASE=STMP3780/i.MX23 SystemOnChip in RecoveryMode + +usb:v066Fp4200* + ID_MODEL_FROM_DATABASE=STIr4200 IrDA Bridge + +usb:v066Fp4210* + ID_MODEL_FROM_DATABASE=STIr4210 IrDA Bridge + +usb:v066Fp8000* + ID_MODEL_FROM_DATABASE=MSCN MP3 Player + +usb:v066Fp8001* + ID_MODEL_FROM_DATABASE=SigmaTel MSCN Audio Player + +usb:v066Fp8004* + ID_MODEL_FROM_DATABASE=MSCNMMC MP3 Player + +usb:v066Fp8008* + ID_MODEL_FROM_DATABASE=i-Bead 100 MP3 Player + +usb:v066Fp8020* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8034* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8036* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8038* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8056* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8060* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8066* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp807E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8092* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8096* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp809A* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80AA* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80AC* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80B8* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80BA* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80BC* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80BF* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80C5* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80C8* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80CA* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp80CC* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8104* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8106* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8108* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp810A* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp810C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8122* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8124* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8126* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8128* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8134* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8136* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8138* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp813A* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp813E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8140* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8142* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8144* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8146* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8148* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp814C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8201* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8202* + ID_MODEL_FROM_DATABASE=Jens of Sweden / I-BEAD 150M/150H MP3 player + +usb:v066Fp8203* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8204* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8205* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8206* + ID_MODEL_FROM_DATABASE=Digital MP3 Music Player + +usb:v066Fp8207* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8208* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8209* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820A* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820B* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820D* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp820F* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8210* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8211* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8212* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8213* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8214* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8215* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8216* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8217* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8218* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8219* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821A* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821B* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821D* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp821F* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8220* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8221* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8222* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8223* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8224* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8225* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8226* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8227* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8228* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8229* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8230* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp829C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp82E0* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp8320* + ID_MODEL_FROM_DATABASE=TrekStor i.Beat fun + +usb:v066Fp835D* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp9000* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp9001* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v066Fp9002* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0670* + ID_VENDOR_FROM_DATABASE=Sequel Imaging + +usb:v0670p0001* + ID_MODEL_FROM_DATABASE=Calibrator + +usb:v0670p0005* + ID_MODEL_FROM_DATABASE=Enable Cable + +usb:v0672* + ID_VENDOR_FROM_DATABASE=Labtec, Inc. + +usb:v0672p1041* + ID_MODEL_FROM_DATABASE=LCS1040 Speaker System + +usb:v0672p5000* + ID_MODEL_FROM_DATABASE=SpaceBall 4000 FLX + +usb:v0673* + ID_VENDOR_FROM_DATABASE=HCL + +usb:v0673p5000* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0674* + ID_VENDOR_FROM_DATABASE=Key Mouse Electronic Enterprise Co., Ltd + +usb:v0675* + ID_VENDOR_FROM_DATABASE=DrayTek Corp. + +usb:v0675p0110* + ID_MODEL_FROM_DATABASE=Vigor 128 ISDN TA + +usb:v0675p0530* + ID_MODEL_FROM_DATABASE=Vigor530 IEEE 802.11G Adapter (ISL3880+NET2280) + +usb:v0675p0550* + ID_MODEL_FROM_DATABASE=Vigor550 + +usb:v0675p1688* + ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA + +usb:v0675p6694* + ID_MODEL_FROM_DATABASE=USB ISDN TA + +usb:v0676* + ID_VENDOR_FROM_DATABASE=Teles AG + +usb:v0677* + ID_VENDOR_FROM_DATABASE=Aiwa Co., Ltd + +usb:v0677p07D5* + ID_MODEL_FROM_DATABASE=TM-ED1285(USB) + +usb:v0677p0FA1* + ID_MODEL_FROM_DATABASE=TD-U8000 Tape Drive + +usb:v0678* + ID_VENDOR_FROM_DATABASE=ACard Technology Corp. + +usb:v067B* + ID_VENDOR_FROM_DATABASE=Prolific Technology, Inc. + +usb:v067Bp0000* + ID_MODEL_FROM_DATABASE=PL2301 USB-USB Bridge + +usb:v067Bp0001* + ID_MODEL_FROM_DATABASE=PL2302 USB-USB Bridge + +usb:v067Bp0307* + ID_MODEL_FROM_DATABASE=Motorola Serial Adapter + +usb:v067Bp04BB* + ID_MODEL_FROM_DATABASE=PL2303 Serial (IODATA USB-RSAQ2) + +usb:v067Bp0600* + ID_MODEL_FROM_DATABASE=IDE Bridge + +usb:v067Bp0610* + ID_MODEL_FROM_DATABASE=Onext EG210U MODEM + +usb:v067Bp0611* + ID_MODEL_FROM_DATABASE=AlDiga AL-11U Quad-band GSM/GPRS/EDGE modem + +usb:v067Bp2303* + ID_MODEL_FROM_DATABASE=PL2303 Serial Port + +usb:v067Bp2305* + ID_MODEL_FROM_DATABASE=PL2305 Parallel Port + +usb:v067Bp2306* + ID_MODEL_FROM_DATABASE=Raylink Bridge Controller + +usb:v067Bp2307* + ID_MODEL_FROM_DATABASE=PL2307 USB-ATAPI4 Bridge + +usb:v067Bp2313* + ID_MODEL_FROM_DATABASE=FITEL PHS U Cable Adaptor + +usb:v067Bp2315* + ID_MODEL_FROM_DATABASE=Flash Disk Embedded Hub + +usb:v067Bp2316* + ID_MODEL_FROM_DATABASE=Flash Disk Security Device + +usb:v067Bp2317* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v067Bp2501* + ID_MODEL_FROM_DATABASE=PL2501 USB-USB Bridge (USB 2.0) + +usb:v067Bp2506* + ID_MODEL_FROM_DATABASE=Kaser 8gB micro hard drive + +usb:v067Bp2507* + ID_MODEL_FROM_DATABASE=PL2507 Hi-speed USB to IDE bridge controller + +usb:v067Bp2515* + ID_MODEL_FROM_DATABASE=Flash Disk Embedded Hub + +usb:v067Bp2517* + ID_MODEL_FROM_DATABASE=Flash Disk Mass Storage Device + +usb:v067Bp2528* + ID_MODEL_FROM_DATABASE=Storage device (8gB thumb drive) + +usb:v067Bp25A1* + ID_MODEL_FROM_DATABASE=PL25A1 Host-Host Bridge + +usb:v067Bp2773* + ID_MODEL_FROM_DATABASE=PL2773 SATAII bridge controller + +usb:v067Bp3400* + ID_MODEL_FROM_DATABASE=Hi-Speed Flash Disk with TruePrint AES3400 + +usb:v067Bp3500* + ID_MODEL_FROM_DATABASE=Hi-Speed Flash Disk with TruePrint AES3500 + +usb:v067Bp3507* + ID_MODEL_FROM_DATABASE=PL3507 ATAPI6 Bridge + +usb:v067BpAAA0* + ID_MODEL_FROM_DATABASE=Prolific Pharos + +usb:v067BpAAA2* + ID_MODEL_FROM_DATABASE=PL2303 Serial Adapter (IODATA USB-RSAQ3) + +usb:v067C* + ID_VENDOR_FROM_DATABASE=Efficient Networks, Inc. + +usb:v067Cp1001* + ID_MODEL_FROM_DATABASE=Siemens SpeedStream 100MBps Ethernet + +usb:v067Cp1022* + ID_MODEL_FROM_DATABASE=Siemens SpeedStream 1022 802.11b Adapter + +usb:v067Cp1023* + ID_MODEL_FROM_DATABASE=SpeedStream Wireless + +usb:v067Cp4020* + ID_MODEL_FROM_DATABASE=SpeedStream 4020 ATM/ADSL Installer + +usb:v067Cp4031* + ID_MODEL_FROM_DATABASE=Efficient ADSL Modem + +usb:v067Cp4032* + ID_MODEL_FROM_DATABASE=SpeedStream 4031 ATM/ADSL Installer + +usb:v067Cp4033* + ID_MODEL_FROM_DATABASE=SpeedStream 4031 ATM/ADSL Installer + +usb:v067Cp4060* + ID_MODEL_FROM_DATABASE=Alcatel Speedstream 4060 ADSL Modem + +usb:v067Cp4062* + ID_MODEL_FROM_DATABASE=Efficient Networks 4060 Loader + +usb:v067Cp5667* + ID_MODEL_FROM_DATABASE=Efficient Networks Virtual Bus for ADSL Modem + +usb:v067CpC031* + ID_MODEL_FROM_DATABASE=SpeedStream 4031 ATM/ADSL Installer + +usb:v067CpC032* + ID_MODEL_FROM_DATABASE=SpeedStream 4031 ATM/ADSL Installer + +usb:v067CpC033* + ID_MODEL_FROM_DATABASE=SpeedStream 4031 ATM/ADSL Installer + +usb:v067CpC060* + ID_MODEL_FROM_DATABASE=SpeedStream 4060 Miniport ATM/ADSL Adapter + +usb:v067CpD667* + ID_MODEL_FROM_DATABASE=Efficient Networks Virtual Bus for ADSL Modem + +usb:v067CpE240* + ID_MODEL_FROM_DATABASE=Speedstream Ethernet Adapter E240 + +usb:v067CpE540* + ID_MODEL_FROM_DATABASE=Speedstream Ethernet Adapter E240 + +usb:v067D* + ID_VENDOR_FROM_DATABASE=Hohner Corp. + +usb:v067E* + ID_VENDOR_FROM_DATABASE=Intermec Technologies Corp. + +usb:v067Ep0801* + ID_MODEL_FROM_DATABASE=HID Keyboard, Barcode scanner + +usb:v067Ep0803* + ID_MODEL_FROM_DATABASE=VCP, Barcode scanner + +usb:v067Ep0805* + ID_MODEL_FROM_DATABASE=VCP + UVC, Barcode scanner + +usb:v067Ep1001* + ID_MODEL_FROM_DATABASE=Mobile Computer + +usb:v067F* + ID_VENDOR_FROM_DATABASE=Virata, Ltd + +usb:v067Fp4552* + ID_MODEL_FROM_DATABASE=DSL-200 ADSL Modem + +usb:v067Fp6542* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v067Fp6549* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v067Fp7541* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0680* + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Corp., CPP Div. (Avance Logic) + +usb:v0680p0002* + ID_MODEL_FROM_DATABASE=Arowana Optical Wheel Mouse MSOP-01 + +usb:v0681* + ID_VENDOR_FROM_DATABASE=Siemens Information and Communication Products + +usb:v0681p0001* + ID_MODEL_FROM_DATABASE=Dect Base + +usb:v0681p0002* + ID_MODEL_FROM_DATABASE=Gigaset 3075 Passive ISDN + +usb:v0681p0005* + ID_MODEL_FROM_DATABASE=ID-Mouse with Fingerprint Reader + +usb:v0681p0012* + ID_MODEL_FROM_DATABASE=I-Gate 802.11b Adapter + +usb:v0681p001B* + ID_MODEL_FROM_DATABASE=WLL013 + +usb:v0681p001D* + ID_MODEL_FROM_DATABASE=Hipath 1000 + +usb:v0681p0022* + ID_MODEL_FROM_DATABASE=Gigaset SX353 ISDN + +usb:v0681p0026* + ID_MODEL_FROM_DATABASE=DECT Data - Gigaset M34 + +usb:v0681p002B* + ID_MODEL_FROM_DATABASE=A-100-I ADSL Modem + +usb:v0681p002E* + ID_MODEL_FROM_DATABASE=ADSL Router_S-141 + +usb:v0681p0034* + ID_MODEL_FROM_DATABASE=GSM module MC35/ES75 USB Modem + +usb:v0681p3C06* + ID_MODEL_FROM_DATABASE=54g USB Network Adapter + +usb:v0682* + ID_VENDOR_FROM_DATABASE=Victor Company of Japan, Ltd + +usb:v0684* + ID_VENDOR_FROM_DATABASE=Actiontec Electronics, Inc. + +usb:v0685* + ID_VENDOR_FROM_DATABASE=ZD Incorporated + +usb:v0685p7000* + ID_MODEL_FROM_DATABASE=HSDPA Modem + +usb:v0686* + ID_VENDOR_FROM_DATABASE=Minolta Co., Ltd + +usb:v0686p2001* + ID_MODEL_FROM_DATABASE=PagePro 4110W + +usb:v0686p2004* + ID_MODEL_FROM_DATABASE=PagePro 1200W + +usb:v0686p2005* + ID_MODEL_FROM_DATABASE=Magicolor 2300 DL + +usb:v0686p3001* + ID_MODEL_FROM_DATABASE=PagePro 4100 + +usb:v0686p3005* + ID_MODEL_FROM_DATABASE=PagePro 1250E + +usb:v0686p3006* + ID_MODEL_FROM_DATABASE=PagePro 1250W + +usb:v0686p3009* + ID_MODEL_FROM_DATABASE=Magicolor 2300W + +usb:v0686p300B* + ID_MODEL_FROM_DATABASE=PagePro 1350W + +usb:v0686p300C* + ID_MODEL_FROM_DATABASE=PagePro 1300W + +usb:v0686p302E* + ID_MODEL_FROM_DATABASE=Develop D 1650iD PCL + +usb:v0686p3034* + ID_MODEL_FROM_DATABASE=Develop D 2050iD PCL + +usb:v0686p4001* + ID_MODEL_FROM_DATABASE=Dimage 2300 + +usb:v0686p4003* + ID_MODEL_FROM_DATABASE=Dimage 2330 Zoom Camera + +usb:v0686p4004* + ID_MODEL_FROM_DATABASE=Dimage Scan Elite II AF-2920 (2888) + +usb:v0686p4005* + ID_MODEL_FROM_DATABASE=Minolta DiMAGE E201 Mass Storage Device + +usb:v0686p4006* + ID_MODEL_FROM_DATABASE=Dimage 7 Camera + +usb:v0686p4007* + ID_MODEL_FROM_DATABASE=Dimage S304 Camera + +usb:v0686p4008* + ID_MODEL_FROM_DATABASE=Dimage 5 Camera + +usb:v0686p4009* + ID_MODEL_FROM_DATABASE=Dimage X Camera + +usb:v0686p400A* + ID_MODEL_FROM_DATABASE=Dimage S404 Camera + +usb:v0686p400B* + ID_MODEL_FROM_DATABASE=Dimage 7i Camera + +usb:v0686p400C* + ID_MODEL_FROM_DATABASE=Dimage F100 Camera + +usb:v0686p400D* + ID_MODEL_FROM_DATABASE=Dimage Scan Dual III AF-2840 (2889) + +usb:v0686p400E* + ID_MODEL_FROM_DATABASE=Dimage Scan Elite 5400 (2890) + +usb:v0686p400F* + ID_MODEL_FROM_DATABASE=Dimage 7Hi Camera + +usb:v0686p4010* + ID_MODEL_FROM_DATABASE=Dimage Xi Camera + +usb:v0686p4011* + ID_MODEL_FROM_DATABASE=Dimage F300 Camera + +usb:v0686p4012* + ID_MODEL_FROM_DATABASE=Dimage F200 Camera + +usb:v0686p4014* + ID_MODEL_FROM_DATABASE=Dimage S414 Camera + +usb:v0686p4015* + ID_MODEL_FROM_DATABASE=Dimage XT Camera [storage] + +usb:v0686p4016* + ID_MODEL_FROM_DATABASE=Dimage XT Camera [remote mode] + +usb:v0686p4017* + ID_MODEL_FROM_DATABASE=Dimage E223 + +usb:v0686p4018* + ID_MODEL_FROM_DATABASE=Dimage Z1 Camera + +usb:v0686p4019* + ID_MODEL_FROM_DATABASE=Dimage A1 Camera [remote mode] + +usb:v0686p401A* + ID_MODEL_FROM_DATABASE=Dimage A1 Camera [storage] + +usb:v0686p401C* + ID_MODEL_FROM_DATABASE=Dimage X20 Camera + +usb:v0686p401E* + ID_MODEL_FROM_DATABASE=Dimage E323 Camera + +usb:v068A* + ID_VENDOR_FROM_DATABASE=Pertech, Inc. + +usb:v068B* + ID_VENDOR_FROM_DATABASE=Potrans International, Inc. + +usb:v068E* + ID_VENDOR_FROM_DATABASE=CH Products, Inc. + +usb:v068Ep00D3* + ID_MODEL_FROM_DATABASE=OEM 3 axis 5 button joystick + +usb:v068Ep00E2* + ID_MODEL_FROM_DATABASE=HFX OEM Joystick + +usb:v068Ep00F1* + ID_MODEL_FROM_DATABASE=Pro Throttle + +usb:v068Ep00F2* + ID_MODEL_FROM_DATABASE=Flight Sim Pedals + +usb:v068Ep00F3* + ID_MODEL_FROM_DATABASE=Fighterstick + +usb:v068Ep00F4* + ID_MODEL_FROM_DATABASE=Combatstick + +usb:v068Ep00FA* + ID_MODEL_FROM_DATABASE=Flight Sim Pedals + +usb:v068Ep00FF* + ID_MODEL_FROM_DATABASE=Flight Sim Yoke + +usb:v068Ep0500* + ID_MODEL_FROM_DATABASE=GameStick 3D + +usb:v068Ep0501* + ID_MODEL_FROM_DATABASE=CH Pro Pedals + +usb:v068Ep0504* + ID_MODEL_FROM_DATABASE=F-16 Combat Stick + +usb:v0690* + ID_VENDOR_FROM_DATABASE=Golden Bridge Electech, Inc. + +usb:v0693* + ID_VENDOR_FROM_DATABASE=Hagiwara Sys-Com Co., Ltd + +usb:v0693p0002* + ID_MODEL_FROM_DATABASE=FlashGate SmartMedia Card Reader + +usb:v0693p0003* + ID_MODEL_FROM_DATABASE=FlashGate CompactFlash Card Reader + +usb:v0693p0005* + ID_MODEL_FROM_DATABASE=FlashGate + +usb:v0693p0006* + ID_MODEL_FROM_DATABASE=SM PCCard R/W and SPD + +usb:v0693p0007* + ID_MODEL_FROM_DATABASE=FlashGate ME (Authenticated) + +usb:v0693p000A* + ID_MODEL_FROM_DATABASE=SDCard/MMC Reader/Writer + +usb:v0694* + ID_VENDOR_FROM_DATABASE=Lego Group + +usb:v0694p0001* + ID_MODEL_FROM_DATABASE=Mindstorms Tower + +usb:v0694p0002* + ID_MODEL_FROM_DATABASE=Mindstorms NXT + +usb:v0698* + ID_VENDOR_FROM_DATABASE=Chuntex (CTX) + +usb:v0698p1786* + ID_MODEL_FROM_DATABASE=1300ex Monitor + +usb:v0698p2003* + ID_MODEL_FROM_DATABASE=CTX M730V built in Camera + +usb:v0698p9999* + ID_MODEL_FROM_DATABASE=VLxxxx Monitor+Hub + +usb:v0699* + ID_VENDOR_FROM_DATABASE=Tektronix, Inc. + +usb:v069A* + ID_VENDOR_FROM_DATABASE=Askey Computer Corp. + +usb:v069Ap0001* + ID_MODEL_FROM_DATABASE=VC010 Webcam [pwc] + +usb:v069Ap0303* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v069Ap0311* + ID_MODEL_FROM_DATABASE=ADSL Router Remote NDIS Device + +usb:v069Ap0318* + ID_MODEL_FROM_DATABASE=Remote NDIS Device + +usb:v069Ap0319* + ID_MODEL_FROM_DATABASE=220V Remote NDIS Device + +usb:v069Ap0320* + ID_MODEL_FROM_DATABASE=IEEE 802.11b Wireless LAN Card + +usb:v069Ap0321* + ID_MODEL_FROM_DATABASE=Dynalink WLL013 / Compex WLU11A 802.11b Adapter + +usb:v069Ap0402* + ID_MODEL_FROM_DATABASE=Scientific Atlanta WebSTAR 100 & 200 series Cable Modem + +usb:v069Ap0811* + ID_MODEL_FROM_DATABASE=BT Virtual Bus for Helium + +usb:v069Ap0821* + ID_MODEL_FROM_DATABASE=BT Voyager 1010 802.11b Adapter + +usb:v069Ap4402* + ID_MODEL_FROM_DATABASE=Scientific Atlanta WebSTAR 2000 series Cable Modem + +usb:v069Ap4403* + ID_MODEL_FROM_DATABASE=Scientific Atlanta WebSTAR 300 series Cable Modem + +usb:v069Ap4501* + ID_MODEL_FROM_DATABASE=Scientific-Atlanta WebSTAR 2000 series Cable Modem + +usb:v069B* + ID_VENDOR_FROM_DATABASE=Thomson, Inc. + +usb:v069Bp0704* + ID_MODEL_FROM_DATABASE=DCM245 Cable Modem + +usb:v069Bp0705* + ID_MODEL_FROM_DATABASE=THG540K Cable Modem + +usb:v069Bp0709* + ID_MODEL_FROM_DATABASE=Lyra PDP2424 + +usb:v069Bp070C* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v069Bp070D* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v069Bp070E* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v069Bp070F* + ID_MODEL_FROM_DATABASE=RCA Lyra RD1071 MP3 Player + +usb:v069Bp0731* + ID_MODEL_FROM_DATABASE=Lyra M200E256 + +usb:v069Bp0761* + ID_MODEL_FROM_DATABASE=RCA H100A + +usb:v069Bp0778* + ID_MODEL_FROM_DATABASE=PEARL USB Device + +usb:v069Bp2220* + ID_MODEL_FROM_DATABASE=RCA Kazoo RD1000 MP3 Player + +usb:v069Bp300A* + ID_MODEL_FROM_DATABASE=RCA Lyra MP3 Player + +usb:v069Bp3012* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v069Bp3013* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v069Bp5557* + ID_MODEL_FROM_DATABASE=RCA CDS6300 + +usb:v069D* + ID_VENDOR_FROM_DATABASE=Hughes Network Systems (HNS) + +usb:v069Dp0001* + ID_MODEL_FROM_DATABASE=Satellite Receiver Device + +usb:v069Dp0002* + ID_MODEL_FROM_DATABASE=Satellite Device + +usb:v069E* + ID_VENDOR_FROM_DATABASE=Welcat Inc. + +usb:v069Ep0005* + ID_MODEL_FROM_DATABASE=Marx CryptoBox v1.2 + +usb:v069F* + ID_VENDOR_FROM_DATABASE=Allied Data Technologies BV + +usb:v069Fp0010* + ID_MODEL_FROM_DATABASE=Tornado Speakerphone FaxModem 56.0 + +usb:v069Fp0011* + ID_MODEL_FROM_DATABASE=Tornado Speakerphone FaxModem 56.0 + +usb:v069Fp1000* + ID_MODEL_FROM_DATABASE=ADT VvBus for CopperJet + +usb:v069Fp1004* + ID_MODEL_FROM_DATABASE=CopperJet 821 RouterPlus + +usb:v06A2* + ID_VENDOR_FROM_DATABASE=Topro Technology, Inc. + +usb:v06A2p0033* + ID_MODEL_FROM_DATABASE=USB Mouse + +usb:v06A3* + ID_VENDOR_FROM_DATABASE=Saitek PLC + +usb:v06A3p0006* + ID_MODEL_FROM_DATABASE=Cyborg Gold Joystick + +usb:v06A3p0109* + ID_MODEL_FROM_DATABASE=P880 Pad + +usb:v06A3p0160* + ID_MODEL_FROM_DATABASE=ST290 Pro + +usb:v06A3p0200* + ID_MODEL_FROM_DATABASE=Xbox Adrenalin Hub + +usb:v06A3p0241* + ID_MODEL_FROM_DATABASE=Xbox Adrenalin Gamepad + +usb:v06A3p0255* + ID_MODEL_FROM_DATABASE=X52 Flight Controller + +usb:v06A3p040B* + ID_MODEL_FROM_DATABASE=P990 Dual Analog Pad + +usb:v06A3p040C* + ID_MODEL_FROM_DATABASE=P2900 Wireless Pad + +usb:v06A3p0422* + ID_MODEL_FROM_DATABASE=ST90 Joystick + +usb:v06A3p0460* + ID_MODEL_FROM_DATABASE=ST290 Pro Flight Stick + +usb:v06A3p0463* + ID_MODEL_FROM_DATABASE=ST290 + +usb:v06A3p0464* + ID_MODEL_FROM_DATABASE=Cyborg Evo + +usb:v06A3p0471* + ID_MODEL_FROM_DATABASE=Cyborg Graphite Stick + +usb:v06A3p0501* + ID_MODEL_FROM_DATABASE=R100 Sports Wheel + +usb:v06A3p0502* + ID_MODEL_FROM_DATABASE=ST200 Stick + +usb:v06A3p0506* + ID_MODEL_FROM_DATABASE=R220 Digital Wheel + +usb:v06A3p051E* + ID_MODEL_FROM_DATABASE=Cyborg Digital II Stick + +usb:v06A3p052D* + ID_MODEL_FROM_DATABASE=P750 Gamepad + +usb:v06A3p053C* + ID_MODEL_FROM_DATABASE=X45 Flight Controller + +usb:v06A3p053F* + ID_MODEL_FROM_DATABASE=X36F Flightstick + +usb:v06A3p056C* + ID_MODEL_FROM_DATABASE=P2000 Tilt Pad + +usb:v06A3p056F* + ID_MODEL_FROM_DATABASE=P2000 Tilt Pad + +usb:v06A3p05D2* + ID_MODEL_FROM_DATABASE=PC Dash 2 + +usb:v06A3p075C* + ID_MODEL_FROM_DATABASE=X52 Flight Controller + +usb:v06A3p0762* + ID_MODEL_FROM_DATABASE=Saitek X52 Pro Flight Control System + +usb:v06A3p0763* + ID_MODEL_FROM_DATABASE=Pro Flight Rudder Pedals + +usb:v06A3p0764* + ID_MODEL_FROM_DATABASE=Flight Pro Combat Rudder + +usb:v06A3p0805* + ID_MODEL_FROM_DATABASE=R440 Force Wheel + +usb:v06A3p0B4E* + ID_MODEL_FROM_DATABASE=Pro Flight Backlit Information Panel + +usb:v06A3p0BAC* + ID_MODEL_FROM_DATABASE=Pro Flight Yoke + +usb:v06A3p0C2D* + ID_MODEL_FROM_DATABASE=Pro Flight Quadrant + +usb:v06A3p0D05* + ID_MODEL_FROM_DATABASE=Pro Flight Radio Panel + +usb:v06A3p0D06* + ID_MODEL_FROM_DATABASE=Flight Pro Multi Panel + +usb:v06A3p0D67* + ID_MODEL_FROM_DATABASE=Pro Flight Switch Panel + +usb:v06A3p1003* + ID_MODEL_FROM_DATABASE=GM2 Action Pad + +usb:v06A3p1009* + ID_MODEL_FROM_DATABASE=Action Pad + +usb:v06A3p100A* + ID_MODEL_FROM_DATABASE=SP550 Pad and Joystick Combo + +usb:v06A3p100B* + ID_MODEL_FROM_DATABASE=SP550 Pad + +usb:v06A3p1509* + ID_MODEL_FROM_DATABASE=P3000 Wireless Pad + +usb:v06A3p1589* + ID_MODEL_FROM_DATABASE=P3000 Wireless Pad + +usb:v06A3p2541* + ID_MODEL_FROM_DATABASE=X45 Flight Controller + +usb:v06A3p3509* + ID_MODEL_FROM_DATABASE=P3000 RF GamePad + +usb:v06A3p353E* + ID_MODEL_FROM_DATABASE=Cyborg Evo Wireless + +usb:v06A3p3589* + ID_MODEL_FROM_DATABASE=P3000 Wireless Pad + +usb:v06A3p35BE* + ID_MODEL_FROM_DATABASE=Cyborg Evo + +usb:v06A3p5509* + ID_MODEL_FROM_DATABASE=P3000 Wireless Pad + +usb:v06A3p712C* + ID_MODEL_FROM_DATABASE=Pro Flight Yoke integrated hub + +usb:v06A3p8000* + ID_MODEL_FROM_DATABASE=Gamers' Keyboard + +usb:v06A3p801E* + ID_MODEL_FROM_DATABASE=Cyborg 3D Digital Stick II + +usb:v06A3p8020* + ID_MODEL_FROM_DATABASE=Eclipse Keyboard + +usb:v06A3p8021* + ID_MODEL_FROM_DATABASE=Eclipse II Keyboard + +usb:v06A3p802D* + ID_MODEL_FROM_DATABASE=P750 Pad + +usb:v06A3p803F* + ID_MODEL_FROM_DATABASE=X36 Flight Controller + +usb:v06A3p806F* + ID_MODEL_FROM_DATABASE=P2000 Tilt Pad + +usb:v06A3p80C0* + ID_MODEL_FROM_DATABASE=Pro Gamer Command Unit + +usb:v06A3p80C1* + ID_MODEL_FROM_DATABASE=Cyborg Command Pad Unit + +usb:v06A3pA2AE* + ID_MODEL_FROM_DATABASE=Pro Flight Instrument Panel + +usb:v06A3pA502* + ID_MODEL_FROM_DATABASE=Gaming Mouse + +usb:v06A3pF518* + ID_MODEL_FROM_DATABASE=P3200 Rumble Force Game Pad + +usb:v06A3pFF04* + ID_MODEL_FROM_DATABASE=R440 Force Wheel + +usb:v06A3pFF0C* + ID_MODEL_FROM_DATABASE=Cyborg Force Rumble Pad + +usb:v06A3pFF0D* + ID_MODEL_FROM_DATABASE=P2600 Rumble Force Pad + +usb:v06A3pFF12* + ID_MODEL_FROM_DATABASE=Cyborg 3D Force Stick + +usb:v06A3pFF17* + ID_MODEL_FROM_DATABASE=ST 330 Rumble Force Stick + +usb:v06A3pFF52* + ID_MODEL_FROM_DATABASE=Cyborg 3D Rumble Force Joystick + +usb:v06A3pFFB5* + ID_MODEL_FROM_DATABASE=Cyborg Evo Force Joystick + +usb:v06A4* + ID_VENDOR_FROM_DATABASE=Xiamen Doowell Electron Co., Ltd + +usb:v06A5* + ID_VENDOR_FROM_DATABASE=Divio + +usb:v06A5p0000* + ID_MODEL_FROM_DATABASE=Typhoon Webcam 100k [nw8000] + +usb:v06A5pD001* + ID_MODEL_FROM_DATABASE=ProLink DS3303u Webcam + +usb:v06A5pD800* + ID_MODEL_FROM_DATABASE=Chicony TwinkleCam + +usb:v06A5pD820* + ID_MODEL_FROM_DATABASE=Wize Media 1000 + +usb:v06A7* + ID_VENDOR_FROM_DATABASE=MicroStore, Inc. + +usb:v06A8* + ID_VENDOR_FROM_DATABASE=Topaz Systems, Inc. + +usb:v06A8p0042* + ID_MODEL_FROM_DATABASE=SignatureGem 1X5 Pad + +usb:v06A8p0043* + ID_MODEL_FROM_DATABASE=SignatureGem 1X5-HID Pad + +usb:v06A9* + ID_VENDOR_FROM_DATABASE=Westell + +usb:v06A9p0005* + ID_MODEL_FROM_DATABASE=WireSpeed Dual Connect Modem + +usb:v06A9p0006* + ID_MODEL_FROM_DATABASE=WireSpeed Dual Connect Modem + +usb:v06A9p000A* + ID_MODEL_FROM_DATABASE=WireSpeed Dual Connect Modem + +usb:v06A9p000B* + ID_MODEL_FROM_DATABASE=WireSpeed Dual Connect Modem + +usb:v06A9p000E* + ID_MODEL_FROM_DATABASE=A90-211WG-01 802.11g Adapter [Intersil ISL3887] + +usb:v06AA* + ID_VENDOR_FROM_DATABASE=Sysgration, Ltd + +usb:v06AC* + ID_VENDOR_FROM_DATABASE=Fujitsu Laboratories of America, Inc. + +usb:v06AD* + ID_VENDOR_FROM_DATABASE=Greatland Electronics Taiwan, Ltd + +usb:v06AE* + ID_VENDOR_FROM_DATABASE=Professional Multimedia Testing Centre + +usb:v06AF* + ID_VENDOR_FROM_DATABASE=Harting, Inc. of North America + +usb:v06B8* + ID_VENDOR_FROM_DATABASE=Pixela Corp. + +usb:v06B9* + ID_VENDOR_FROM_DATABASE=Alcatel Telecom + +usb:v06B9p0120* + ID_MODEL_FROM_DATABASE=SpeedTouch 120g 802.11g Wireless Adapter [Intersil ISL3886] + +usb:v06B9p0121* + ID_MODEL_FROM_DATABASE=SpeedTouch 121g Wireless Dongle + +usb:v06B9p2001* + ID_MODEL_FROM_DATABASE=SPEED TOUCH Card + +usb:v06B9p4061* + ID_MODEL_FROM_DATABASE=SpeedTouch ISDN or ADSL Modem + +usb:v06B9p4062* + ID_MODEL_FROM_DATABASE=SpeedTouch ISDN or ADSL router + +usb:v06B9pA5A5* + ID_MODEL_FROM_DATABASE=DynaMiTe Modem + +usb:v06BA* + ID_VENDOR_FROM_DATABASE=Smooth Cord & Connector Co., Ltd + +usb:v06BB* + ID_VENDOR_FROM_DATABASE=EDA, Inc. + +usb:v06BC* + ID_VENDOR_FROM_DATABASE=Oki Data Corp. + +usb:v06BCp000B* + ID_MODEL_FROM_DATABASE=Okipage 14ex Printer + +usb:v06BCp0027* + ID_MODEL_FROM_DATABASE=Okipage 14e + +usb:v06BCp00F7* + ID_MODEL_FROM_DATABASE=OKI B4600 Mono Printer + +usb:v06BCp015E* + ID_MODEL_FROM_DATABASE=OKIPOS 411/412 POS Printer + +usb:v06BCp01C9* + ID_MODEL_FROM_DATABASE=OKI B430 Mono Printer + +usb:v06BCp020B* + ID_MODEL_FROM_DATABASE=OKI ES4140 Mono Printer + +usb:v06BCp02BB* + ID_MODEL_FROM_DATABASE=OKI PT390 POS Printer + +usb:v06BCp0A91* + ID_MODEL_FROM_DATABASE=B2500MFP (printer+scanner) + +usb:v06BCp3801* + ID_MODEL_FROM_DATABASE=B6100 Laser Printer + +usb:v06BD* + ID_VENDOR_FROM_DATABASE=AGFA-Gevaert NV + +usb:v06BDp0001* + ID_MODEL_FROM_DATABASE=SnapScan 1212U + +usb:v06BDp0002* + ID_MODEL_FROM_DATABASE=SnapScan 1236U + +usb:v06BDp0100* + ID_MODEL_FROM_DATABASE=SnapScan Touch + +usb:v06BDp0101* + ID_MODEL_FROM_DATABASE=SNAPSCAN ELITE + +usb:v06BDp0200* + ID_MODEL_FROM_DATABASE=ScanMaker 8700 + +usb:v06BDp02BF* + ID_MODEL_FROM_DATABASE=DUOSCAN f40 + +usb:v06BDp0400* + ID_MODEL_FROM_DATABASE=CL30 + +usb:v06BDp0401* + ID_MODEL_FROM_DATABASE=Mass Storage + +usb:v06BDp0403* + ID_MODEL_FROM_DATABASE=ePhoto CL18 Camera + +usb:v06BDp0404* + ID_MODEL_FROM_DATABASE=ePhoto CL20 Camera + +usb:v06BDp2061* + ID_MODEL_FROM_DATABASE=SnapScan 1212U (?) + +usb:v06BDp208D* + ID_MODEL_FROM_DATABASE=Snapscan e40 + +usb:v06BDp208F* + ID_MODEL_FROM_DATABASE=SnapScan e50 + +usb:v06BDp2091* + ID_MODEL_FROM_DATABASE=SnapScan e20 + +usb:v06BDp2093* + ID_MODEL_FROM_DATABASE=SnapScan e10 + +usb:v06BDp2095* + ID_MODEL_FROM_DATABASE=SnapScan e25 + +usb:v06BDp2097* + ID_MODEL_FROM_DATABASE=SnapScan e26 + +usb:v06BDp20FD* + ID_MODEL_FROM_DATABASE=SnapScan e52 + +usb:v06BDp20FF* + ID_MODEL_FROM_DATABASE=SnapScan e42 + +usb:v06BE* + ID_VENDOR_FROM_DATABASE=AME Optimedia Technology Co., Ltd + +usb:v06BEp0800* + ID_MODEL_FROM_DATABASE=Optimedia Camera + +usb:v06BEp1005* + ID_MODEL_FROM_DATABASE=Dazzle DPVM! (1005) + +usb:v06BEpD001* + ID_MODEL_FROM_DATABASE=P35U Camera Capture + +usb:v06BF* + ID_VENDOR_FROM_DATABASE=Leoco Corp. + +usb:v06C2* + ID_VENDOR_FROM_DATABASE=Phidgets Inc. (formerly GLAB) + +usb:v06C2p0030* + ID_MODEL_FROM_DATABASE=PhidgetRFID + +usb:v06C2p0038* + ID_MODEL_FROM_DATABASE=4-Motor PhidgetServo v3.0 + +usb:v06C2p0039* + ID_MODEL_FROM_DATABASE=1-Motor PhidgetServo v3.0 + +usb:v06C2p003A* + ID_MODEL_FROM_DATABASE=8-Motor PhidgetAvancedServo + +usb:v06C2p0040* + ID_MODEL_FROM_DATABASE=PhidgetInterface Kit 0-0-4 + +usb:v06C2p0044* + ID_MODEL_FROM_DATABASE=PhidgetInterface Kit 0-16-16 + +usb:v06C2p0045* + ID_MODEL_FROM_DATABASE=PhidgetInterface Kit 8-8-8 + +usb:v06C2p0048* + ID_MODEL_FROM_DATABASE=PhidgetStepper (Under Development) + +usb:v06C2p0049* + ID_MODEL_FROM_DATABASE=PhidgetTextLED Ver 1.0 + +usb:v06C2p004A* + ID_MODEL_FROM_DATABASE=PhidgetLED Ver 1.0 + +usb:v06C2p004B* + ID_MODEL_FROM_DATABASE=PhidgetEncoder Ver 1.0 + +usb:v06C2p0051* + ID_MODEL_FROM_DATABASE=PhidgetInterface Kit 0-5-7 (Custom) + +usb:v06C2p0052* + ID_MODEL_FROM_DATABASE=PhidgetTextLCD + +usb:v06C2p0053* + ID_MODEL_FROM_DATABASE=PhidgetInterfaceKit 0-8-8 + +usb:v06C2p0058* + ID_MODEL_FROM_DATABASE=PhidgetMotorControl Ver 1.0 + +usb:v06C2p0070* + ID_MODEL_FROM_DATABASE=PhidgetTemperatureSensor Ver 1.0 + +usb:v06C2p0071* + ID_MODEL_FROM_DATABASE=PhidgetAccelerometer Ver 1.0 + +usb:v06C2p0072* + ID_MODEL_FROM_DATABASE=PhidgetWeightSensor Ver 1.0 + +usb:v06C2p0073* + ID_MODEL_FROM_DATABASE=PhidgetHumiditySensor + +usb:v06C2p0074* + ID_MODEL_FROM_DATABASE=PhidgetPHSensor + +usb:v06C2p0075* + ID_MODEL_FROM_DATABASE=PhidgetGyroscope + +usb:v06C4* + ID_VENDOR_FROM_DATABASE=Bizlink International Corp. + +usb:v06C5* + ID_VENDOR_FROM_DATABASE=Hagenuk, GmbH + +usb:v06C6* + ID_VENDOR_FROM_DATABASE=Infowave Software, Inc. + +usb:v06C8* + ID_VENDOR_FROM_DATABASE=SIIG, Inc. + +usb:v06C9* + ID_VENDOR_FROM_DATABASE=Taxan (Europe), Ltd + +usb:v06C9p0005* + ID_MODEL_FROM_DATABASE=Monitor Control + +usb:v06C9p0007* + ID_MODEL_FROM_DATABASE=Monitor Control + +usb:v06C9p0009* + ID_MODEL_FROM_DATABASE=Monitor Control + +usb:v06CA* + ID_VENDOR_FROM_DATABASE=Newer Technology, Inc. + +usb:v06CB* + ID_VENDOR_FROM_DATABASE=Synaptics, Inc. + +usb:v06CBp0001* + ID_MODEL_FROM_DATABASE=TouchPad + +usb:v06CBp0002* + ID_MODEL_FROM_DATABASE=Integrated TouchPad + +usb:v06CBp0003* + ID_MODEL_FROM_DATABASE=cPad + +usb:v06CBp0005* + ID_MODEL_FROM_DATABASE=Touchpad/FPS + +usb:v06CBp0006* + ID_MODEL_FROM_DATABASE=TouchScreen + +usb:v06CBp0007* + ID_MODEL_FROM_DATABASE=USB Styk + +usb:v06CBp0008* + ID_MODEL_FROM_DATABASE=WheelPad + +usb:v06CBp0009* + ID_MODEL_FROM_DATABASE=Composite TouchPad and TrackPoint + +usb:v06CBp000E* + ID_MODEL_FROM_DATABASE=HID Device + +usb:v06CBp0010* + ID_MODEL_FROM_DATABASE=Wireless TouchPad + +usb:v06CBp0013* + ID_MODEL_FROM_DATABASE=DisplayPad + +usb:v06CC* + ID_VENDOR_FROM_DATABASE=Terayon Communication Systems + +usb:v06CCp0101* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v06CCp0102* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v06CCp0103* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v06CCp0104* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v06CCp0304* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v06CD* + ID_VENDOR_FROM_DATABASE=Keyspan + +usb:v06CDp0101* + ID_MODEL_FROM_DATABASE=USA-28 PDA [no firmware] + +usb:v06CDp0102* + ID_MODEL_FROM_DATABASE=USA-28X PDA [no firmware] + +usb:v06CDp0103* + ID_MODEL_FROM_DATABASE=USA-19 PDA [no firmware] + +usb:v06CDp0104* + ID_MODEL_FROM_DATABASE=PDA [prerenum] + +usb:v06CDp0105* + ID_MODEL_FROM_DATABASE=USA-18X PDA [no firmware] + +usb:v06CDp0106* + ID_MODEL_FROM_DATABASE=USA-19W PDA [no firmware] + +usb:v06CDp0107* + ID_MODEL_FROM_DATABASE=USA-19 PDA + +usb:v06CDp0108* + ID_MODEL_FROM_DATABASE=USA-19W PDA + +usb:v06CDp0109* + ID_MODEL_FROM_DATABASE=USA-49W serial adapter [no firmware] + +usb:v06CDp010A* + ID_MODEL_FROM_DATABASE=USA-49W serial adapter + +usb:v06CDp010B* + ID_MODEL_FROM_DATABASE=USA-19Qi serial adapter [no firmware] + +usb:v06CDp010C* + ID_MODEL_FROM_DATABASE=USA-19Qi serial adapter + +usb:v06CDp010D* + ID_MODEL_FROM_DATABASE=USA-19Q serial Adapter (no firmware) + +usb:v06CDp010E* + ID_MODEL_FROM_DATABASE=USA-19Q serial Adapter + +usb:v06CDp010F* + ID_MODEL_FROM_DATABASE=USA-28 PDA + +usb:v06CDp0110* + ID_MODEL_FROM_DATABASE=USA-28Xb PDA + +usb:v06CDp0111* + ID_MODEL_FROM_DATABASE=USA-18 serial Adapter + +usb:v06CDp0112* + ID_MODEL_FROM_DATABASE=USA-18X PDA + +usb:v06CDp0113* + ID_MODEL_FROM_DATABASE=USA-28Xb PDA [no firmware] + +usb:v06CDp0114* + ID_MODEL_FROM_DATABASE=USA-28Xa PDA [no firmware] + +usb:v06CDp0115* + ID_MODEL_FROM_DATABASE=USA-28Xa PDA + +usb:v06CDp0116* + ID_MODEL_FROM_DATABASE=USA-18XA serial Adapter (no firmware) + +usb:v06CDp0117* + ID_MODEL_FROM_DATABASE=USA-18XA serial Adapter + +usb:v06CDp0118* + ID_MODEL_FROM_DATABASE=USA-19QW PDA [no firmware] + +usb:v06CDp0119* + ID_MODEL_FROM_DATABASE=USA-19QW PDA + +usb:v06CDp011A* + ID_MODEL_FROM_DATABASE=USA-49Wlc serial adapter [no firmware] + +usb:v06CDp011B* + ID_MODEL_FROM_DATABASE=MPR Serial Preloader (MPRQI) + +usb:v06CDp011C* + ID_MODEL_FROM_DATABASE=MPR Serial (MPRQI) + +usb:v06CDp011D* + ID_MODEL_FROM_DATABASE=MPR Serial Preloader (MPRQ) + +usb:v06CDp011E* + ID_MODEL_FROM_DATABASE=MPR Serial (MPRQ) + +usb:v06CDp0121* + ID_MODEL_FROM_DATABASE=USA-19hs serial adapter + +usb:v06CDp012A* + ID_MODEL_FROM_DATABASE=USA-49Wlc serial adapter + +usb:v06CDp0201* + ID_MODEL_FROM_DATABASE=UIA-10 Digital Media Remote [Cypress AN2131SC] + +usb:v06CDp0202* + ID_MODEL_FROM_DATABASE=UIA-11 Digital Media Remote + +usb:v06CE* + ID_VENDOR_FROM_DATABASE=Contec + +usb:v06CEp8311* + ID_MODEL_FROM_DATABASE=COM-1(USB)H + +usb:v06CF* + ID_VENDOR_FROM_DATABASE=SpheronVR AG + +usb:v06CFp1010* + ID_MODEL_FROM_DATABASE=PanoCam 10 + +usb:v06CFp1012* + ID_MODEL_FROM_DATABASE=PanoCam 12/12X + +usb:v06D0* + ID_VENDOR_FROM_DATABASE=LapLink, Inc. + +usb:v06D0p0622* + ID_MODEL_FROM_DATABASE=LapLink Gold USB-USB Bridge [net1080] + +usb:v06D1* + ID_VENDOR_FROM_DATABASE=Daewoo Electronics Co., Ltd + +usb:v06D3* + ID_VENDOR_FROM_DATABASE=Mitsubishi Electric Corp. + +usb:v06D3p0284* + ID_MODEL_FROM_DATABASE=FX-USB-AW/-BD RS482 Converters + +usb:v06D3p0380* + ID_MODEL_FROM_DATABASE=CP8000D Port + +usb:v06D3p0381* + ID_MODEL_FROM_DATABASE=CP770D Port + +usb:v06D3p0385* + ID_MODEL_FROM_DATABASE=CP900D Port + +usb:v06D3p0387* + ID_MODEL_FROM_DATABASE=CP980D Port + +usb:v06D3p038B* + ID_MODEL_FROM_DATABASE=CP3020D Port + +usb:v06D3p038C* + ID_MODEL_FROM_DATABASE=CP900DW(ID) Port + +usb:v06D3p0393* + ID_MODEL_FROM_DATABASE=CP9500D/DW Port + +usb:v06D3p0394* + ID_MODEL_FROM_DATABASE=CP9000D/DW Port + +usb:v06D3p03A1* + ID_MODEL_FROM_DATABASE=CP9550D/DW Port + +usb:v06D4* + ID_VENDOR_FROM_DATABASE=Cisco Systems + +usb:v06D5* + ID_VENDOR_FROM_DATABASE=Toshiba + +usb:v06D5p4000* + ID_MODEL_FROM_DATABASE=Japanese Keyboard + +usb:v06D6* + ID_VENDOR_FROM_DATABASE=Aashima Technology B.V. + +usb:v06D6p0025* + ID_MODEL_FROM_DATABASE=Gamepad + +usb:v06D6p0026* + ID_MODEL_FROM_DATABASE=Predator TH 400 Gamepad + +usb:v06D6p002D* + ID_MODEL_FROM_DATABASE=Trust PowerC@m 350FT + +usb:v06D6p002E* + ID_MODEL_FROM_DATABASE=Trust PowerC@m 350FS + +usb:v06D6p0030* + ID_MODEL_FROM_DATABASE=Trust 710 LCD POWERC@M ZOOM - MSD + +usb:v06D6p0031* + ID_MODEL_FROM_DATABASE=Trust 610/710 LCD POWERC@M ZOOM + +usb:v06D6p003A* + ID_MODEL_FROM_DATABASE=Trust PowerC@m 770Z (mass storage mode) + +usb:v06D6p003B* + ID_MODEL_FROM_DATABASE=Trust PowerC@m 770Z (webcam mode) + +usb:v06D6p003C* + ID_MODEL_FROM_DATABASE=Trust 910z PowerC@m + +usb:v06D6p003F* + ID_MODEL_FROM_DATABASE=Trust 735S POWERC@M ZOOM, WDM DSC Bulk Driver + +usb:v06D6p0050* + ID_MODEL_FROM_DATABASE=Trust 738AV LCD PV Digital Camera + +usb:v06D6p0062* + ID_MODEL_FROM_DATABASE=TRUST 782AV LCD P. V. Video Capture + +usb:v06D6p0066* + ID_MODEL_FROM_DATABASE=TRUST Digital PCTV and Movie Editor + +usb:v06D6p0067* + ID_MODEL_FROM_DATABASE=Trust 350FS POWERC@M FLASH + +usb:v06D6p006B* + ID_MODEL_FROM_DATABASE=TRUST AUDIO VIDEO EDITOR + +usb:v06D7* + ID_VENDOR_FROM_DATABASE=Network Computing Devices (NCD) + +usb:v06D8* + ID_VENDOR_FROM_DATABASE=Technical Marketing Research, Inc. + +usb:v06DA* + ID_VENDOR_FROM_DATABASE=Phoenixtec Power Co., Ltd + +usb:v06DAp0002* + ID_MODEL_FROM_DATABASE=UPS + +usb:v06DAp0003* + ID_MODEL_FROM_DATABASE=1300VA UPS + +usb:v06DB* + ID_VENDOR_FROM_DATABASE=Paradyne + +usb:v06DC* + ID_VENDOR_FROM_DATABASE=Foxlink Image Technology Co., Ltd + +usb:v06DCp0012* + ID_MODEL_FROM_DATABASE=Scan 1200c Scanner + +usb:v06DCp0014* + ID_MODEL_FROM_DATABASE=Prolink Winscan Pro 2448U + +usb:v06DE* + ID_VENDOR_FROM_DATABASE=Heisei Electronics Co., Ltd + +usb:v06E0* + ID_VENDOR_FROM_DATABASE=Multi-Tech Systems, Inc. + +usb:v06E0p0319* + ID_MODEL_FROM_DATABASE=MT9234ZBA-USB MultiModem ZBA + +usb:v06E0pF101* + ID_MODEL_FROM_DATABASE=MT5634ZBA-USB MultiModemUSB (old firmware) + +usb:v06E0pF103* + ID_MODEL_FROM_DATABASE=MT5634MU MultiMobileUSB + +usb:v06E0pF104* + ID_MODEL_FROM_DATABASE=MT5634ZBA-USB MultiModemUSB (new firmware) + +usb:v06E0pF107* + ID_MODEL_FROM_DATABASE=MT5634ZBA-USB-V92 MultiModemUSB + +usb:v06E0pF120* + ID_MODEL_FROM_DATABASE=MT9234ZBA-USB-CDC-ACM-XR MultiModem ZBA CDC-ACM-XR + +usb:v06E1* + ID_VENDOR_FROM_DATABASE=ADS Technologies, Inc. + +usb:v06E1p0008* + ID_MODEL_FROM_DATABASE=UBS-10BT Ethernet [klsi] + +usb:v06E1p0009* + ID_MODEL_FROM_DATABASE=UBS-10BT Ethernet + +usb:v06E1p0833* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v06E1pA155* + ID_MODEL_FROM_DATABASE=FM Radio Receiver/Instant FM Music (RDX-155-EF) + +usb:v06E1pA160* + ID_MODEL_FROM_DATABASE=Instant Video-To-Go RDX-160 (no firmware) + +usb:v06E1pA161* + ID_MODEL_FROM_DATABASE=Instant Video-To-Go RDX-160 + +usb:v06E1pA190* + ID_MODEL_FROM_DATABASE=Instand VCD Capture + +usb:v06E1pA191* + ID_MODEL_FROM_DATABASE=Instant VideoXpress + +usb:v06E1pA337* + ID_MODEL_FROM_DATABASE=Mini DigitalTV + +usb:v06E1pA701* + ID_MODEL_FROM_DATABASE=DVD Xpress + +usb:v06E1pA708* + ID_MODEL_FROM_DATABASE=saa7114H video input card (Instant VideoMPX) + +usb:v06E1pB337* + ID_MODEL_FROM_DATABASE=Mini DigitalTV + +usb:v06E1pB701* + ID_MODEL_FROM_DATABASE=DVD Xpress B + +usb:v06E4* + ID_VENDOR_FROM_DATABASE=Alcatel Microelectronics + +usb:v06E6* + ID_VENDOR_FROM_DATABASE=Tiger Jet Network, Inc. + +usb:v06E6p0200* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p0201* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p0202* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p0203* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p0210* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p0211* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p0212* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p031C* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p031D* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p031E* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p3200* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p3201* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p3202* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p3203* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p7200* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p7210* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p7250* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p825C* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p831C* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6p831D* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6p831E* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB200* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB201* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB202* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pB210* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pB211* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB212* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB250* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pB251* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pB252* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC200* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC201* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC202* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pC203* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC210* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pC211* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pC212* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pC213* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC25C* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pC290* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC291* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC292* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC293* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pC31C* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pC39C* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pC39D* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC39E* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC39F* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pC700* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC701* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC702* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pC703* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pC710* + ID_MODEL_FROM_DATABASE=VoIP Combo Device + +usb:v06E6pC711* + ID_MODEL_FROM_DATABASE=VoIP Combo + +usb:v06E6pC712* + ID_MODEL_FROM_DATABASE=VoIP Combo Device + +usb:v06E6pC713* + ID_MODEL_FROM_DATABASE=VoIP Combo Device + +usb:v06E6pCF00* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pCF01* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pCF02* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pCF03* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pD210* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pD211* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pD212* + ID_MODEL_FROM_DATABASE=PPG Device + +usb:v06E6pD213* + ID_MODEL_FROM_DATABASE=Personal PhoneGateway + +usb:v06E6pD700* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pD701* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pD702* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pD703* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pD710* + ID_MODEL_FROM_DATABASE=VoIP Combo + +usb:v06E6pD711* + ID_MODEL_FROM_DATABASE=VoIP Combo Device + +usb:v06E6pD712* + ID_MODEL_FROM_DATABASE=VoIP Combo + +usb:v06E6pD713* + ID_MODEL_FROM_DATABASE=VoIP Combo + +usb:v06E6pDF00* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pDF01* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pDF02* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pDF03* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF200* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF201* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF202* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pF203* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pF210* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF250* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06E6pF252* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF310* + ID_MODEL_FROM_DATABASE=Internet Phone + +usb:v06E6pF350* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v06EA* + ID_VENDOR_FROM_DATABASE=Sirius Technologies + +usb:v06EAp0001* + ID_MODEL_FROM_DATABASE=NetCom Roadster II 56k + +usb:v06EAp0002* + ID_MODEL_FROM_DATABASE=Roadster II 56k + +usb:v06EB* + ID_VENDOR_FROM_DATABASE=PC Expert Tech. Co., Ltd + +usb:v06EF* + ID_VENDOR_FROM_DATABASE=I.A.C. Geometrische Ingenieurs B.V. + +usb:v06F0* + ID_VENDOR_FROM_DATABASE=T.N.C Industrial Co., Ltd + +usb:v06F0pDE01* + ID_MODEL_FROM_DATABASE=DualCam Video Camera + +usb:v06F0pDE02* + ID_MODEL_FROM_DATABASE=DualCam Still Camera + +usb:v06F1* + ID_VENDOR_FROM_DATABASE=Opcode Systems, Inc. + +usb:v06F1pA011* + ID_MODEL_FROM_DATABASE=SonicPort + +usb:v06F1pA021* + ID_MODEL_FROM_DATABASE=SonicPort Optical + +usb:v06F2* + ID_VENDOR_FROM_DATABASE=Emine Technology Co. + +usb:v06F2p0011* + ID_MODEL_FROM_DATABASE=KVM Switch Keyboard + +usb:v06F6* + ID_VENDOR_FROM_DATABASE=Wintrend Technology Co., Ltd + +usb:v06F7* + ID_VENDOR_FROM_DATABASE=Wailly Technology Ltd + +usb:v06F7p0003* + ID_MODEL_FROM_DATABASE=USB->Din 4 Adaptor + +usb:v06F8* + ID_VENDOR_FROM_DATABASE=Guillemot Corp. + +usb:v06F8p3002* + ID_MODEL_FROM_DATABASE=Hercules Blog Webcam + +usb:v06F8p3004* + ID_MODEL_FROM_DATABASE=Hercules Classic Silver + +usb:v06F8p3005* + ID_MODEL_FROM_DATABASE=Hercules Dualpix Exchange + +usb:v06F8p3007* + ID_MODEL_FROM_DATABASE=Hercules Dualpix Chat and Show + +usb:v06F8p3020* + ID_MODEL_FROM_DATABASE=Hercules Webcam EC300 + +usb:v06F8pA300* + ID_MODEL_FROM_DATABASE=Dual Analog Leader GamePad + +usb:v06F8pB000* + ID_MODEL_FROM_DATABASE=Hercules DJ Console + +usb:v06F8pC000* + ID_MODEL_FROM_DATABASE=Hercules Muse Pocket + +usb:v06F8pD002* + ID_MODEL_FROM_DATABASE=Hercules DJ Console + +usb:v06F8pE000* + ID_MODEL_FROM_DATABASE=HWGUSB2-54 WLAN + +usb:v06F8pE010* + ID_MODEL_FROM_DATABASE=HWGUSB2-54-LB + +usb:v06F8pE020* + ID_MODEL_FROM_DATABASE=HWGUSB2-54V2-AP + +usb:v06F8pE031* + ID_MODEL_FROM_DATABASE=Hercules HWNUm-300 Wireless N mini [Realtek RTL8191SU] + +usb:v06F8pE032* + ID_MODEL_FROM_DATABASE=HWGUm-54 [Hercules Wireless G Ultra Mini Key] + +usb:v06F8pE033* + ID_MODEL_FROM_DATABASE=Hercules HWNUp-150 802.11n Wireless N Pico [Realtek RTL8188CUS] + +usb:v06F9* + ID_VENDOR_FROM_DATABASE=ASYST electronic d.o.o. + +usb:v06FA* + ID_VENDOR_FROM_DATABASE=HSD S.r.L + +usb:v06FC* + ID_VENDOR_FROM_DATABASE=Motorola Semiconductor Products Sector + +usb:v06FD* + ID_VENDOR_FROM_DATABASE=Boston Acoustics + +usb:v06FDp0101* + ID_MODEL_FROM_DATABASE=Audio Device + +usb:v06FDp0102* + ID_MODEL_FROM_DATABASE=Audio Device + +usb:v06FDp0201* + ID_MODEL_FROM_DATABASE=2-piece Audio Device + +usb:v06FE* + ID_VENDOR_FROM_DATABASE=Gallant Computer, Inc. + +usb:v0701* + ID_VENDOR_FROM_DATABASE=Supercomal Wire & Cable SDN. BHD. + +usb:v0703* + ID_VENDOR_FROM_DATABASE=Bvtech Industry, Inc. + +usb:v0705* + ID_VENDOR_FROM_DATABASE=NKK Corp. + +usb:v0706* + ID_VENDOR_FROM_DATABASE=Ariel Corp. + +usb:v0707* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp. + +usb:v0707p0100* + ID_MODEL_FROM_DATABASE=2202 Ethernet [klsi] + +usb:v0707p0200* + ID_MODEL_FROM_DATABASE=2202 Ethernet [pegasus] + +usb:v0707p0201* + ID_MODEL_FROM_DATABASE=EZ Connect USB Ethernet + +usb:v0707pEE04* + ID_MODEL_FROM_DATABASE=SMCWUSB32 802.11b Wireless LAN Card + +usb:v0707pEE06* + ID_MODEL_FROM_DATABASE=SMC2862W-G v1 EZ Connect 802.11g Adapter [Intersil ISL3886] + +usb:v0707pEE13* + ID_MODEL_FROM_DATABASE=SMC2862W-G v2 EZ Connect 802.11g Adapter [Intersil ISL3887] + +usb:v0708* + ID_VENDOR_FROM_DATABASE=Putercom Co., Ltd + +usb:v0708p047E* + ID_MODEL_FROM_DATABASE=USB-1284 BRIDGE + +usb:v0709* + ID_VENDOR_FROM_DATABASE=Silicon Systems, Ltd (SSL) + +usb:v070A* + ID_VENDOR_FROM_DATABASE=Oki Electric Industry Co., Ltd + +usb:v070Ap4002* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v070Ap4003* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v070D* + ID_VENDOR_FROM_DATABASE=Comoss Electronic Co., Ltd + +usb:v070E* + ID_VENDOR_FROM_DATABASE=Excel Cell Electronic Co., Ltd + +usb:v0710* + ID_VENDOR_FROM_DATABASE=Connect Tech, Inc. + +usb:v0710p0001* + ID_MODEL_FROM_DATABASE=WhiteHeat (fake ID) + +usb:v0710p8001* + ID_MODEL_FROM_DATABASE=WhiteHeat + +usb:v0711* + ID_VENDOR_FROM_DATABASE=Magic Control Technology Corp. + +usb:v0711p0100* + ID_MODEL_FROM_DATABASE=Hub + +usb:v0711p0180* + ID_MODEL_FROM_DATABASE=IRXpress Infrared Device + +usb:v0711p0181* + ID_MODEL_FROM_DATABASE=IRXpress Infrared Device + +usb:v0711p0200* + ID_MODEL_FROM_DATABASE=BAY-3U1S1P Serial Port + +usb:v0711p0210* + ID_MODEL_FROM_DATABASE=MCT1S Serial Port + +usb:v0711p0230* + ID_MODEL_FROM_DATABASE=MCT-232 Serial Port + +usb:v0711p0231* + ID_MODEL_FROM_DATABASE=PS/2 Mouse Port + +usb:v0711p0232* + ID_MODEL_FROM_DATABASE=Serial On Port + +usb:v0711p0240* + ID_MODEL_FROM_DATABASE=PS/2 to USB Converter + +usb:v0711p0300* + ID_MODEL_FROM_DATABASE=BAY-3U1S1P Parallel Port + +usb:v0711p0302* + ID_MODEL_FROM_DATABASE=Parallel Port + +usb:v0711p0900* + ID_MODEL_FROM_DATABASE=SVGA Adapter + +usb:v0711p5001* + ID_MODEL_FROM_DATABASE=Trigger UV-002BD[Startech USBVGAE] + +usb:v0711p5100* + ID_MODEL_FROM_DATABASE=Magic Control Technology Corp. (USB2VGA dongle) + +usb:v0713* + ID_VENDOR_FROM_DATABASE=Interval Research Corp. + +usb:v0714* + ID_VENDOR_FROM_DATABASE=NewMotion, Inc. + +usb:v0714p0003* + ID_MODEL_FROM_DATABASE=ADB to USB convertor + +usb:v0717* + ID_VENDOR_FROM_DATABASE=ZNK Corp. + +usb:v0718* + ID_VENDOR_FROM_DATABASE=Imation Corp. + +usb:v0718p0002* + ID_MODEL_FROM_DATABASE=SuperDisk 120MB + +usb:v0718p0003* + ID_MODEL_FROM_DATABASE=SuperDisk 120MB (Authenticated) + +usb:v0718p0060* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0061* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0062* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0063* + ID_MODEL_FROM_DATABASE=Swivel Flash Drive + +usb:v0718p0064* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0065* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0066* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0067* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0068* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v0718p0084* + ID_MODEL_FROM_DATABASE=Flash Drive Mini + +usb:v0718p043C* + ID_MODEL_FROM_DATABASE=Flash drive 16GB [Nano Pro] + +usb:v0718p0582* + ID_MODEL_FROM_DATABASE=Revo Flash Drive + +usb:v0718p0622* + ID_MODEL_FROM_DATABASE=TDK Trans-It 4GB + +usb:v0718p0624* + ID_MODEL_FROM_DATABASE=TDK Trans-It 16GB + +usb:v0718p1120* + ID_MODEL_FROM_DATABASE=RDX External dock (redbud) + +usb:v0718pD000* + ID_MODEL_FROM_DATABASE=Disc Stakka CD/DVD Manager + +usb:v0719* + ID_VENDOR_FROM_DATABASE=Tremon Enterprises Co., Ltd + +usb:v071B* + ID_VENDOR_FROM_DATABASE=Domain Technologies, Inc. + +usb:v071Bp0002* + ID_MODEL_FROM_DATABASE=DTI-56362-USB Digital Interface Unit + +usb:v071Bp0101* + ID_MODEL_FROM_DATABASE=Audio4-USB DSP Data Acquisition Unit + +usb:v071Bp0201* + ID_MODEL_FROM_DATABASE=Audio4-5410 DSP Data Acquisition Unit + +usb:v071Bp0301* + ID_MODEL_FROM_DATABASE=SB-USB JTAG Emulator + +usb:v071Bp3203* + ID_MODEL_FROM_DATABASE=Rockchip Media Player + +usb:v071Bp32BB* + ID_MODEL_FROM_DATABASE=Music Mediatouch + +usb:v071C* + ID_VENDOR_FROM_DATABASE=Xionics Document Technologies, Inc. + +usb:v071D* + ID_VENDOR_FROM_DATABASE=Eicon Networks Corp. + +usb:v071Dp1000* + ID_MODEL_FROM_DATABASE=Diva ISDN TA + +usb:v071Dp1003* + ID_MODEL_FROM_DATABASE=Diva + +usb:v071Dp2000* + ID_MODEL_FROM_DATABASE=Teledat Surf + +usb:v071E* + ID_VENDOR_FROM_DATABASE=Ariston Technologies + +usb:v0723* + ID_VENDOR_FROM_DATABASE=Centillium Communications Corp. + +usb:v0723p0002* + ID_MODEL_FROM_DATABASE=Palladia 300/400 Adsl Modem + +usb:v0726* + ID_VENDOR_FROM_DATABASE=Vanguard International Semiconductor-America + +usb:v0729* + ID_VENDOR_FROM_DATABASE=Amitm + +usb:v0729p1000* + ID_MODEL_FROM_DATABASE=USC-1000 Serial Port + +usb:v072E* + ID_VENDOR_FROM_DATABASE=Sunix Co., Ltd + +usb:v072F* + ID_VENDOR_FROM_DATABASE=Advanced Card Systems, Ltd + +usb:v072Fp0001* + ID_MODEL_FROM_DATABASE=AC1030-based SmartCard Reader + +usb:v072Fp0008* + ID_MODEL_FROM_DATABASE=ACR 80 Smart Card Reader + +usb:v072Fp1000* + ID_MODEL_FROM_DATABASE=PLDT Drive + +usb:v072Fp1001* + ID_MODEL_FROM_DATABASE=PLDT Drive + +usb:v072Fp8002* + ID_MODEL_FROM_DATABASE=AET63 BioTRUSTKey + +usb:v072Fp8003* + ID_MODEL_FROM_DATABASE=ACR120 + +usb:v072Fp8103* + ID_MODEL_FROM_DATABASE=ACR120 + +usb:v072Fp9000* + ID_MODEL_FROM_DATABASE=ACR38 AC1038-based Smart Card Reader + +usb:v072Fp90CC* + ID_MODEL_FROM_DATABASE=ACR38 SmartCard Reader + +usb:v072Fp90CF* + ID_MODEL_FROM_DATABASE=ACR38 SAM Smart Card Reader + +usb:v072Fp90D0* + ID_MODEL_FROM_DATABASE=PertoSmart EMV - Card Reader + +usb:v0731* + ID_VENDOR_FROM_DATABASE=Susteen, Inc. + +usb:v0731p0528* + ID_MODEL_FROM_DATABASE=SonyEricsson DCU-11 Cable + +usb:v0732* + ID_VENDOR_FROM_DATABASE=Goldfull Electronics & Telecommunications Corp. + +usb:v0733* + ID_VENDOR_FROM_DATABASE=ViewQuest Technologies, Inc. + +usb:v0733p0101* + ID_MODEL_FROM_DATABASE=Digital Video Camera + +usb:v0733p0110* + ID_MODEL_FROM_DATABASE=VQ110 Video Camera + +usb:v0733p0401* + ID_MODEL_FROM_DATABASE=CS330 Webcam + +usb:v0733p0402* + ID_MODEL_FROM_DATABASE=M-318B Webcam + +usb:v0733p0430* + ID_MODEL_FROM_DATABASE=Intel Pro Share Webcam + +usb:v0733p0630* + ID_MODEL_FROM_DATABASE=VQ630 Dual Mode Digital Camera(Bulk) + +usb:v0733p0631* + ID_MODEL_FROM_DATABASE=Hercules Dualpix + +usb:v0733p0780* + ID_MODEL_FROM_DATABASE=Smart Cam Deluxe(composite) + +usb:v0733p1310* + ID_MODEL_FROM_DATABASE=Epsilon 1.3/Jenoptik JD C1.3/UMAX AstraPix 470 + +usb:v0733p1311* + ID_MODEL_FROM_DATABASE=Digital Dream Epsilon 1.3 + +usb:v0733p1314* + ID_MODEL_FROM_DATABASE=Mercury 2.1MEG Deluxe Classic Cam + +usb:v0733p2211* + ID_MODEL_FROM_DATABASE=Jenoptik jdc 21 LCD Camera + +usb:v0733p2221* + ID_MODEL_FROM_DATABASE=Mercury Digital Pro 3.1p + +usb:v0733p3261* + ID_MODEL_FROM_DATABASE=Concord 3045 spca536a Camera + +usb:v0733p3281* + ID_MODEL_FROM_DATABASE=Cyberpix S550V + +usb:v0734* + ID_VENDOR_FROM_DATABASE=Lasat Communications A/S + +usb:v0734p0001* + ID_MODEL_FROM_DATABASE=560V Modem + +usb:v0734p0002* + ID_MODEL_FROM_DATABASE=Lasat 560V Modem + +usb:v0734p043A* + ID_MODEL_FROM_DATABASE=DVS Audio + +usb:v0734p043B* + ID_MODEL_FROM_DATABASE=3DeMon USB Capture + +usb:v0735* + ID_VENDOR_FROM_DATABASE=Asuscom Network + +usb:v0735p2100* + ID_MODEL_FROM_DATABASE=ISDN Adapter + +usb:v0735p2101* + ID_MODEL_FROM_DATABASE=ISDN Adapter + +usb:v0735p6694* + ID_MODEL_FROM_DATABASE=ISDNlink 128K + +usb:v0735pC541* + ID_MODEL_FROM_DATABASE=ISDN TA 280 + +usb:v0736* + ID_VENDOR_FROM_DATABASE=Lorom Industrial Co., Ltd + +usb:v0738* + ID_VENDOR_FROM_DATABASE=Mad Catz, Inc. + +usb:v0738p4507* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4516* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4520* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4526* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4536* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4540* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4556* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4566* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4576* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4586* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p4588* + ID_MODEL_FROM_DATABASE=XBox Device + +usb:v0738p8818* + ID_MODEL_FROM_DATABASE=Street Fighter IV Arcade FightStick (PS3) + +usb:v073A* + ID_VENDOR_FROM_DATABASE=Chaplet Systems, Inc. + +usb:v073Ap2230* + ID_MODEL_FROM_DATABASE=infrared dongle for remote + +usb:v073B* + ID_VENDOR_FROM_DATABASE=Suncom Technologies + +usb:v073C* + ID_VENDOR_FROM_DATABASE=Industrial Electronic Engineers, Inc. + +usb:v073Cp0305* + ID_MODEL_FROM_DATABASE=Pole Display (PC305-3415 2 x 20 Line Display) + +usb:v073Cp0322* + ID_MODEL_FROM_DATABASE=Pole Display (PC322-3415 2 x 20 Line Display) + +usb:v073Cp0324* + ID_MODEL_FROM_DATABASE=Pole Display (LB324-USB 4 x 20 Line Display) + +usb:v073Cp0330* + ID_MODEL_FROM_DATABASE=Pole Display (P330-3415 2 x 20 Line Display) + +usb:v073Cp0424* + ID_MODEL_FROM_DATABASE=Pole Display (SP324-4415 4 x 20 Line Display) + +usb:v073Cp0450* + ID_MODEL_FROM_DATABASE=Pole Display (L450-USB Graphic Line Display) + +usb:v073Cp0505* + ID_MODEL_FROM_DATABASE=Pole Display (SPC505-3415 2 x 20 Line Display) + +usb:v073Cp0522* + ID_MODEL_FROM_DATABASE=Pole Display (SPC522-3415 2 x 20 Line Display) + +usb:v073Cp0624* + ID_MODEL_FROM_DATABASE=Pole Display (SP324-3415 4 x 20 Line Display) + +usb:v073D* + ID_VENDOR_FROM_DATABASE=Eutron S.p.a. + +usb:v073Dp0005* + ID_MODEL_FROM_DATABASE=Crypto Token + +usb:v073Dp0007* + ID_MODEL_FROM_DATABASE=CryptoIdentity CCID + +usb:v073Dp0025* + ID_MODEL_FROM_DATABASE=SmartKey 3 + +usb:v073Dp0C00* + ID_MODEL_FROM_DATABASE=Pocket Reader + +usb:v073Dp0D00* + ID_MODEL_FROM_DATABASE=StarSign Bio Token 3.0 EU + +usb:v073E* + ID_VENDOR_FROM_DATABASE=NEC, Inc. + +usb:v073Ep0301* + ID_MODEL_FROM_DATABASE=Game Pad + +usb:v0745* + ID_VENDOR_FROM_DATABASE=Syntech Information Co., Ltd + +usb:v0746* + ID_VENDOR_FROM_DATABASE=Onkyo Corp. + +usb:v0746p5500* + ID_MODEL_FROM_DATABASE=SE-U55 Audio Device + +usb:v0747* + ID_VENDOR_FROM_DATABASE=Labway Corp. + +usb:v0748* + ID_VENDOR_FROM_DATABASE=Strong Man Enterprise Co., Ltd + +usb:v0749* + ID_VENDOR_FROM_DATABASE=EVer Electronics Corp. + +usb:v074A* + ID_VENDOR_FROM_DATABASE=Ming Fortune Industry Co., Ltd + +usb:v074B* + ID_VENDOR_FROM_DATABASE=Polestar Tech. Corp. + +usb:v074C* + ID_VENDOR_FROM_DATABASE=C-C-C Group PLC + +usb:v074D* + ID_VENDOR_FROM_DATABASE=Micronas GmbH + +usb:v074Dp3553* + ID_MODEL_FROM_DATABASE=Composite USB-Device + +usb:v074Dp3554* + ID_MODEL_FROM_DATABASE=Composite USB-Device + +usb:v074Dp3556* + ID_MODEL_FROM_DATABASE=Composite USB-Device + +usb:v074E* + ID_VENDOR_FROM_DATABASE=Digital Stream Corp. + +usb:v074Ep0001* + ID_MODEL_FROM_DATABASE=PS/2 Adapter + +usb:v074Ep0002* + ID_MODEL_FROM_DATABASE=PS/2 Adapter + +usb:v0755* + ID_VENDOR_FROM_DATABASE=Aureal Semiconductor + +usb:v0757* + ID_VENDOR_FROM_DATABASE=Network Technologies, Inc. + +usb:v075B* + ID_VENDOR_FROM_DATABASE=Sophisticated Circuits, Inc. + +usb:v075Bp0001* + ID_MODEL_FROM_DATABASE=Kick-off! Watchdog + +usb:v0763* + ID_VENDOR_FROM_DATABASE=Midiman + +usb:v0763p0115* + ID_MODEL_FROM_DATABASE=O2 / KeyRig 25 + +usb:v0763p0117* + ID_MODEL_FROM_DATABASE=Trigger Finger + +usb:v0763p0119* + ID_MODEL_FROM_DATABASE=MidAir + +usb:v0763p0150* + ID_MODEL_FROM_DATABASE=M-Audio Uno + +usb:v0763p0160* + ID_MODEL_FROM_DATABASE=M-Audio 1x1 + +usb:v0763p0192* + ID_MODEL_FROM_DATABASE=M-Audio Keystation 88es + +usb:v0763p0193* + ID_MODEL_FROM_DATABASE=ProKeys 88 + +usb:v0763p0194* + ID_MODEL_FROM_DATABASE=ProKeys 88sx + +usb:v0763p0195* + ID_MODEL_FROM_DATABASE=Oxygen 8 v2 + +usb:v0763p0196* + ID_MODEL_FROM_DATABASE=Oxygen 49 + +usb:v0763p0197* + ID_MODEL_FROM_DATABASE=Oxygen 61 + +usb:v0763p0198* + ID_MODEL_FROM_DATABASE=Axiom 25 + +usb:v0763p0199* + ID_MODEL_FROM_DATABASE=Axiom 49 + +usb:v0763p019A* + ID_MODEL_FROM_DATABASE=Axiom 61 + +usb:v0763p019B* + ID_MODEL_FROM_DATABASE=KeyRig 49 + +usb:v0763p019C* + ID_MODEL_FROM_DATABASE=KeyStudio + +usb:v0763p1001* + ID_MODEL_FROM_DATABASE=MidiSport 2x2 + +usb:v0763p1002* + ID_MODEL_FROM_DATABASE=MidiSport 2x2 + +usb:v0763p1003* + ID_MODEL_FROM_DATABASE=MidiSport 2x2 + +usb:v0763p1010* + ID_MODEL_FROM_DATABASE=MidiSport 1x1 + +usb:v0763p1011* + ID_MODEL_FROM_DATABASE=MidiSport 1x1 + +usb:v0763p1014* + ID_MODEL_FROM_DATABASE=M-Audio Keystation Loader + +usb:v0763p1015* + ID_MODEL_FROM_DATABASE=M-Audio Keystation + +usb:v0763p1020* + ID_MODEL_FROM_DATABASE=Midisport 4x4 + +usb:v0763p1021* + ID_MODEL_FROM_DATABASE=MidiSport 4x4 + +usb:v0763p1030* + ID_MODEL_FROM_DATABASE=Midisport 8x8 + +usb:v0763p1031* + ID_MODEL_FROM_DATABASE=MidiSport 8x8/s Loader + +usb:v0763p1033* + ID_MODEL_FROM_DATABASE=MidiSport 8x8/s + +usb:v0763p1040* + ID_MODEL_FROM_DATABASE=M-Audio MidiSport 2x4 Loader + +usb:v0763p1041* + ID_MODEL_FROM_DATABASE=M-Audio MidiSport 2x4 + +usb:v0763p1110* + ID_MODEL_FROM_DATABASE=MidiSport 1x1 + +usb:v0763p2001* + ID_MODEL_FROM_DATABASE=M Audio Quattro + +usb:v0763p2002* + ID_MODEL_FROM_DATABASE=M Audio Duo + +usb:v0763p2003* + ID_MODEL_FROM_DATABASE=M Audio AudioPhile + +usb:v0763p2004* + ID_MODEL_FROM_DATABASE=M-Audio MobilePre + +usb:v0763p2006* + ID_MODEL_FROM_DATABASE=M-Audio Transit + +usb:v0763p2007* + ID_MODEL_FROM_DATABASE=M-Audio Sonica Theater + +usb:v0763p2008* + ID_MODEL_FROM_DATABASE=M-Audio Ozone + +usb:v0763p200D* + ID_MODEL_FROM_DATABASE=M-Audio OmniStudio + +usb:v0763p200F* + ID_MODEL_FROM_DATABASE=M-Audio MobilePre + +usb:v0763p2010* + ID_MODEL_FROM_DATABASE=M-Audio Fast Track + +usb:v0763p2012* + ID_MODEL_FROM_DATABASE=M-Audio Fast Track Pro + +usb:v0763p2013* + ID_MODEL_FROM_DATABASE=M-Audio JamLab + +usb:v0763p2015* + ID_MODEL_FROM_DATABASE=M-Audio RunTime DFU + +usb:v0763p2016* + ID_MODEL_FROM_DATABASE=M-Audio RunTime DFU + +usb:v0763p2019* + ID_MODEL_FROM_DATABASE=M-Audio Ozone Academic + +usb:v0763p201A* + ID_MODEL_FROM_DATABASE=M-Audio Micro + +usb:v0763p201B* + ID_MODEL_FROM_DATABASE=M-Audio RunTime DFU + +usb:v0763p201D* + ID_MODEL_FROM_DATABASE=M-Audio Producer + +usb:v0763p2024* + ID_MODEL_FROM_DATABASE=M-Audio Fast Track MKII + +usb:v0763p2080* + ID_MODEL_FROM_DATABASE=M-Audio RunTime DFU + +usb:v0763p2081* + ID_MODEL_FROM_DATABASE=M-Audio RunTime DFU / Fast Track Ultra 8R + +usb:v0763p2803* + ID_MODEL_FROM_DATABASE=M-Audio Audiophile DFU + +usb:v0763p2804* + ID_MODEL_FROM_DATABASE=M-Audio MobilePre DFU + +usb:v0763p2806* + ID_MODEL_FROM_DATABASE=M-Audio Transit DFU + +usb:v0763p2815* + ID_MODEL_FROM_DATABASE=M-Audio DFU + +usb:v0763p2816* + ID_MODEL_FROM_DATABASE=M-Audio DFU + +usb:v0763p281B* + ID_MODEL_FROM_DATABASE=M-Audio DFU + +usb:v0763p2880* + ID_MODEL_FROM_DATABASE=M-Audio DFU + +usb:v0763p2881* + ID_MODEL_FROM_DATABASE=M-Audio DFU + +usb:v0764* + ID_VENDOR_FROM_DATABASE=Cyber Power System, Inc. + +usb:v0764p0005* + ID_MODEL_FROM_DATABASE=Cyber Power UPS + +usb:v0764p0501* + ID_MODEL_FROM_DATABASE=CP1500 AVR UPS + +usb:v0765* + ID_VENDOR_FROM_DATABASE=X-Rite, Inc. + +usb:v0765p5001* + ID_MODEL_FROM_DATABASE=Huey PRO Colorimeter + +usb:v0765pD094* + ID_MODEL_FROM_DATABASE=X-Rite DTP94 [Quato Silver Haze Pro] + +usb:v0766* + ID_VENDOR_FROM_DATABASE=Jess-Link Products Co., Ltd + +usb:v0766p001B* + ID_MODEL_FROM_DATABASE=Packard Bell Go + +usb:v0766p0204* + ID_MODEL_FROM_DATABASE=TopSpeed Cyberlink Remote Control + +usb:v0767* + ID_VENDOR_FROM_DATABASE=Tokheim Corp. + +usb:v0768* + ID_VENDOR_FROM_DATABASE=Camtel Technology Corp. + +usb:v0768p0006* + ID_MODEL_FROM_DATABASE=Camtel Technology USB TV Genie Pro FM Model TVB330 + +usb:v0768p0023* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0769* + ID_VENDOR_FROM_DATABASE=Surecom Technology Corp. + +usb:v0769p11F2* + ID_MODEL_FROM_DATABASE=EP-9001-g 802.11g 54M WLAN Adapter + +usb:v0769p11F3* + ID_MODEL_FROM_DATABASE=RT2570 + +usb:v0769p11F7* + ID_MODEL_FROM_DATABASE=802.11g 54M WLAN Adapter + +usb:v0769p31F3* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v076A* + ID_VENDOR_FROM_DATABASE=Smart Technology Enablers, Inc. + +usb:v076B* + ID_VENDOR_FROM_DATABASE=OmniKey AG + +usb:v076Bp0596* + ID_MODEL_FROM_DATABASE=CardMan 2020 + +usb:v076Bp1021* + ID_MODEL_FROM_DATABASE=CardMan 1021 + +usb:v076Bp1221* + ID_MODEL_FROM_DATABASE=CardMan 1221 + +usb:v076Bp1784* + ID_MODEL_FROM_DATABASE=CardMan 6020 + +usb:v076Bp3021* + ID_MODEL_FROM_DATABASE=CardMan 3121 + +usb:v076Bp3610* + ID_MODEL_FROM_DATABASE=CardMan 3620 + +usb:v076Bp3621* + ID_MODEL_FROM_DATABASE=CardMan 3621 + +usb:v076Bp3821* + ID_MODEL_FROM_DATABASE=CardMan 3821 + +usb:v076Bp4321* + ID_MODEL_FROM_DATABASE=CardMan 4321 + +usb:v076Bp5121* + ID_MODEL_FROM_DATABASE=CardMan 5121 + +usb:v076Bp5125* + ID_MODEL_FROM_DATABASE=CardMan 5125 + +usb:v076Bp6622* + ID_MODEL_FROM_DATABASE=CardMan 6121 + +usb:v076BpA011* + ID_MODEL_FROM_DATABASE=CCID Smart Card Reader Keyboard + +usb:v076BpA021* + ID_MODEL_FROM_DATABASE=CCID Smart Card Reader + +usb:v076BpA022* + ID_MODEL_FROM_DATABASE=CardMan Smart@Link + +usb:v076BpC000* + ID_MODEL_FROM_DATABASE=CardMan 3x21 CS + +usb:v076BpC001* + ID_MODEL_FROM_DATABASE=CardMan 5121 CS + +usb:v076C* + ID_VENDOR_FROM_DATABASE=Partner Tech + +usb:v076D* + ID_VENDOR_FROM_DATABASE=Denso Corp. + +usb:v076E* + ID_VENDOR_FROM_DATABASE=Kuan Tech Enterprise Co., Ltd + +usb:v076F* + ID_VENDOR_FROM_DATABASE=Jhen Vei Electronic Co., Ltd + +usb:v0770* + ID_VENDOR_FROM_DATABASE=Welch Allyn, Inc - Medical Division + +usb:v0771* + ID_VENDOR_FROM_DATABASE=Observator Instruments BV + +usb:v0771p4455* + ID_MODEL_FROM_DATABASE=OMC45III + +usb:v0771pAE0F* + ID_MODEL_FROM_DATABASE=OMC45III + +usb:v0772* + ID_VENDOR_FROM_DATABASE=Your data Our Care + +usb:v0774* + ID_VENDOR_FROM_DATABASE=AmTRAN Technology Co., Ltd + +usb:v0775* + ID_VENDOR_FROM_DATABASE=Longshine Electronics Corp. + +usb:v0776* + ID_VENDOR_FROM_DATABASE=Inalways Corp. + +usb:v0777* + ID_VENDOR_FROM_DATABASE=Comda Enterprise Corp. + +usb:v0778* + ID_VENDOR_FROM_DATABASE=Volex, Inc. + +usb:v0779* + ID_VENDOR_FROM_DATABASE=Fairchild Semiconductor + +usb:v077A* + ID_VENDOR_FROM_DATABASE=Sankyo Seiki Mfg. Co., Ltd + +usb:v077B* + ID_VENDOR_FROM_DATABASE=Linksys + +usb:v077Bp08BE* + ID_MODEL_FROM_DATABASE=BEFCMU10 v4 Cable Modem + +usb:v077Bp2219* + ID_MODEL_FROM_DATABASE=WUSB11 V2.6 802.11b Adapter + +usb:v077Bp2226* + ID_MODEL_FROM_DATABASE=USB200M 100baseTX Adapter + +usb:v077Bp2227* + ID_MODEL_FROM_DATABASE=Network Everywhere NWU11B + +usb:v077C* + ID_VENDOR_FROM_DATABASE=Forward Electronics Co., Ltd + +usb:v077Cp0005* + ID_MODEL_FROM_DATABASE=NEC Keyboard + +usb:v077D* + ID_VENDOR_FROM_DATABASE=Griffin Technology + +usb:v077Dp0223* + ID_MODEL_FROM_DATABASE=IMic Audio In/Out + +usb:v077Dp0405* + ID_MODEL_FROM_DATABASE=iMate, ADB Adapter + +usb:v077Dp0410* + ID_MODEL_FROM_DATABASE=PowerMate + +usb:v077Dp041A* + ID_MODEL_FROM_DATABASE=PowerWave + +usb:v077Dp04AA* + ID_MODEL_FROM_DATABASE=SoundKnob + +usb:v077Dp07AF* + ID_MODEL_FROM_DATABASE=iMic + +usb:v077Dp1016* + ID_MODEL_FROM_DATABASE=AirClick + +usb:v077Dp627A* + ID_MODEL_FROM_DATABASE=Radio SHARK + +usb:v077F* + ID_VENDOR_FROM_DATABASE=Well Excellent & Most Corp. + +usb:v0780* + ID_VENDOR_FROM_DATABASE=Sagem Monetel GmbH + +usb:v0780p1202* + ID_MODEL_FROM_DATABASE=ORGA 900 Smart Card Terminal Virtual Com Port + +usb:v0780p1302* + ID_MODEL_FROM_DATABASE=ORGA 6000 Smart Card Terminal Virtual Com Port + +usb:v0780p1303* + ID_MODEL_FROM_DATABASE=ORGA 6000 Smart Card Terminal USB RNDIS + +usb:v0780pDF55* + ID_MODEL_FROM_DATABASE=ORGA 900/6000 Smart Card Terminal DFU + +usb:v0781* + ID_VENDOR_FROM_DATABASE=SanDisk Corp. + +usb:v0781p0001* + ID_MODEL_FROM_DATABASE=SDDR-05a ImageMate CompactFlash Reader + +usb:v0781p0002* + ID_MODEL_FROM_DATABASE=SDDR-31 ImageMate II CompactFlash Reader + +usb:v0781p0005* + ID_MODEL_FROM_DATABASE=SDDR-05b (CF II) ImageMate CompactFlash Reader + +usb:v0781p0100* + ID_MODEL_FROM_DATABASE=ImageMate SDDR-12 + +usb:v0781p0200* + ID_MODEL_FROM_DATABASE=SDDR-09 (SSFDC) ImageMate SmartMedia Reader [eusb] + +usb:v0781p0400* + ID_MODEL_FROM_DATABASE=SecureMate SD/MMC Reader + +usb:v0781p0621* + ID_MODEL_FROM_DATABASE=SDDR-86 Imagemate 6-in-1 Reader + +usb:v0781p0720* + ID_MODEL_FROM_DATABASE=Sansa C200 series in recovery mode + +usb:v0781p0729* + ID_MODEL_FROM_DATABASE=Sansa E200 series in recovery mode + +usb:v0781p0810* + ID_MODEL_FROM_DATABASE=SDDR-75 ImageMate CF-SM Reader + +usb:v0781p0830* + ID_MODEL_FROM_DATABASE=ImageMate CF/MMC/SD Reader + +usb:v0781p1234* + ID_MODEL_FROM_DATABASE=Cruzer Mini Flash Drive + +usb:v0781p5150* + ID_MODEL_FROM_DATABASE=SDCZ2 Cruzer Mini Flash Drive (thin) + +usb:v0781p5151* + ID_MODEL_FROM_DATABASE=Cruzer Micro Flash Drive + +usb:v0781p5153* + ID_MODEL_FROM_DATABASE=Cruzer Flash Drive + +usb:v0781p5204* + ID_MODEL_FROM_DATABASE=Cruzer Crossfire + +usb:v0781p5402* + ID_MODEL_FROM_DATABASE=U3 Cruzer Micro + +usb:v0781p5406* + ID_MODEL_FROM_DATABASE=Cruzer Micro U3 + +usb:v0781p5408* + ID_MODEL_FROM_DATABASE=Cruzer Titanium U3 + +usb:v0781p540E* + ID_MODEL_FROM_DATABASE=Cruzer Contour Flash Drive + +usb:v0781p5530* + ID_MODEL_FROM_DATABASE=Cruzer + +usb:v0781p5567* + ID_MODEL_FROM_DATABASE=Cruzer Blade + +usb:v0781p5571* + ID_MODEL_FROM_DATABASE=Cruzer Fit + +usb:v0781p5580* + ID_MODEL_FROM_DATABASE=SDCZ80 Flash Drive + +usb:v0781p5E10* + ID_MODEL_FROM_DATABASE=Encrypted + +usb:v0781p6100* + ID_MODEL_FROM_DATABASE=Ultra II SD Plus 2GB + +usb:v0781p7100* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7101* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v0781p7102* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7103* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7104* + ID_MODEL_FROM_DATABASE=Cruzer Micro Mini 256MB Flash Drive + +usb:v0781p7105* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7106* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7112* + ID_MODEL_FROM_DATABASE=Cruzer Micro 128MB Flash Drive + +usb:v0781p7113* + ID_MODEL_FROM_DATABASE=Cruzer Micro 256MB Flash Drive + +usb:v0781p7114* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7115* + ID_MODEL_FROM_DATABASE=Cruzer Mini + +usb:v0781p7301* + ID_MODEL_FROM_DATABASE=Sansa e100 series (mtp) + +usb:v0781p7302* + ID_MODEL_FROM_DATABASE=Sansa e100 series (msc) + +usb:v0781p7400* + ID_MODEL_FROM_DATABASE=Sansa M200 series (mtp) + +usb:v0781p7401* + ID_MODEL_FROM_DATABASE=Sansa M200 series (msc) + +usb:v0781p7420* + ID_MODEL_FROM_DATABASE=Sansa E200 series (mtp) + +usb:v0781p7421* + ID_MODEL_FROM_DATABASE=Sansa E200 Series (msc) + +usb:v0781p7422* + ID_MODEL_FROM_DATABASE=Sansa E200 series v2 (mtp) + +usb:v0781p7423* + ID_MODEL_FROM_DATABASE=Sansa E200 series v2 (msc) + +usb:v0781p7430* + ID_MODEL_FROM_DATABASE=Sansa M200 series + +usb:v0781p7431* + ID_MODEL_FROM_DATABASE=Sansa M200 series V4 (msc) + +usb:v0781p7432* + ID_MODEL_FROM_DATABASE=Sansa Clip (mtp) + +usb:v0781p7433* + ID_MODEL_FROM_DATABASE=Sansa Clip (msc) + +usb:v0781p7434* + ID_MODEL_FROM_DATABASE=Sansa Clip V2 (mtp) + +usb:v0781p7435* + ID_MODEL_FROM_DATABASE=Sansa Clip V2 (msc) + +usb:v0781p7450* + ID_MODEL_FROM_DATABASE=Sansa C250 + +usb:v0781p7451* + ID_MODEL_FROM_DATABASE=Sansa C240 + +usb:v0781p7460* + ID_MODEL_FROM_DATABASE=Sansa Express + +usb:v0781p7480* + ID_MODEL_FROM_DATABASE=Sansa Connect + +usb:v0781p7481* + ID_MODEL_FROM_DATABASE=Sansa Connect (in recovery mode) + +usb:v0781p74B0* + ID_MODEL_FROM_DATABASE=Sansa View (msc) + +usb:v0781p74B1* + ID_MODEL_FROM_DATABASE=Sansa View (mtp) + +usb:v0781p74C0* + ID_MODEL_FROM_DATABASE=Sansa Fuze (mtp) + +usb:v0781p74C1* + ID_MODEL_FROM_DATABASE=Sansa Fuze (msc) + +usb:v0781p74C2* + ID_MODEL_FROM_DATABASE=Sansa Fuze V2 (mtp) + +usb:v0781p74C3* + ID_MODEL_FROM_DATABASE=Sansa Fuze V2 (msc) + +usb:v0781p74D0* + ID_MODEL_FROM_DATABASE=Sansa Clip+ (mtp) + +usb:v0781p74D1* + ID_MODEL_FROM_DATABASE=Sansa Clip+ (msc) + +usb:v0781p8181* + ID_MODEL_FROM_DATABASE=Pen Flash + +usb:v0781p8183* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v0781p8185* + ID_MODEL_FROM_DATABASE=SDCZ2 Cruzer Mini Flash Drive (older, thick) + +usb:v0781p8888* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0781p8889* + ID_MODEL_FROM_DATABASE=SDDR-88 Imagemate 8-in-1 Reader + +usb:v0781p8919* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0781p8989* + ID_MODEL_FROM_DATABASE=ImageMate 12-in-1 Reader + +usb:v0781p9191* + ID_MODEL_FROM_DATABASE=ImageMate CF + +usb:v0781p9219* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0781p9292* + ID_MODEL_FROM_DATABASE=ImageMate CF Reader/Writer + +usb:v0781p9393* + ID_MODEL_FROM_DATABASE=ImageMate SD-MMC + +usb:v0781p9595* + ID_MODEL_FROM_DATABASE=ImageMate xD-SM + +usb:v0781p9797* + ID_MODEL_FROM_DATABASE=ImageMate MS-PRO + +usb:v0781p9919* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0781p9999* + ID_MODEL_FROM_DATABASE=SDDR-99 5-in-1 Reader + +usb:v0781pA7C1* + ID_MODEL_FROM_DATABASE=Storage device (SD card reader) + +usb:v0781pA7E8* + ID_MODEL_FROM_DATABASE=SDDR-113 MicroMate SDHC Reader + +usb:v0781pB2B3* + ID_MODEL_FROM_DATABASE=SDDR-103 MobileMate SD+ Reader + +usb:v0781pB4B5* + ID_MODEL_FROM_DATABASE=SDDR-89 V4 ImageMate 12-in-1 Reader + +usb:v0782* + ID_VENDOR_FROM_DATABASE=Trackerball + +usb:v0783* + ID_VENDOR_FROM_DATABASE=C3PO + +usb:v0783p0003* + ID_MODEL_FROM_DATABASE=LTC31 SmartCard Reader + +usb:v0783p0006* + ID_MODEL_FROM_DATABASE=LTC31v2 + +usb:v0783p0009* + ID_MODEL_FROM_DATABASE=KBR36 + +usb:v0783p0010* + ID_MODEL_FROM_DATABASE=LTC32 + +usb:v0784* + ID_VENDOR_FROM_DATABASE=Vivitar, Inc. + +usb:v0784p0100* + ID_MODEL_FROM_DATABASE=Vivicam 2655 + +usb:v0784p1310* + ID_MODEL_FROM_DATABASE=Vivicam 3305 + +usb:v0784p1688* + ID_MODEL_FROM_DATABASE=Vivicam 3665 + +usb:v0784p1689* + ID_MODEL_FROM_DATABASE=Gateway DC-M42/Labtec DC-505/Vivitar Vivicam 3705 + +usb:v0784p2620* + ID_MODEL_FROM_DATABASE=AOL Photocam Plus + +usb:v0784p2888* + ID_MODEL_FROM_DATABASE=Polaroid DC700 + +usb:v0784p3330* + ID_MODEL_FROM_DATABASE=Nytec ND-3200 Camera + +usb:v0784p4300* + ID_MODEL_FROM_DATABASE=Traveler D1 + +usb:v0784p5260* + ID_MODEL_FROM_DATABASE=Werlisa Sport PX 100 / JVC GC-A33 Camera + +usb:v0784p5300* + ID_MODEL_FROM_DATABASE=Pretec dc530 + +usb:v0785* + ID_VENDOR_FROM_DATABASE=NTT-ME + +usb:v0785p0001* + ID_MODEL_FROM_DATABASE=MN128mini-V ISDN TA + +usb:v0785p0003* + ID_MODEL_FROM_DATABASE=MN128mini-J ISDN TA + +usb:v0789* + ID_VENDOR_FROM_DATABASE=Logitec Corp. + +usb:v0789p0026* + ID_MODEL_FROM_DATABASE=LHD Device + +usb:v0789p0033* + ID_MODEL_FROM_DATABASE=DVD Multi-plus unit LDR-H443SU2 + +usb:v0789p0063* + ID_MODEL_FROM_DATABASE=LDR Device + +usb:v0789p0064* + ID_MODEL_FROM_DATABASE=LDR-R Device + +usb:v0789p00B3* + ID_MODEL_FROM_DATABASE=DVD Multi-plus unit LDR-H443U2 + +usb:v0789p0105* + ID_MODEL_FROM_DATABASE=LAN-TX/U1H2 10/100 Ethernet Adapter [pegasus II] + +usb:v0789p010C* + ID_MODEL_FROM_DATABASE=Realtek RTL8187 Wireless 802.11g 54Mbps Network Adapter + +usb:v0789p0160* + ID_MODEL_FROM_DATABASE=LAN-GTJ/U2A + +usb:v0789p0162* + ID_MODEL_FROM_DATABASE=LAN-WN22/U2 Wireless LAN Adapter + +usb:v0789p0163* + ID_MODEL_FROM_DATABASE=LAN-WN12/U2 Wireless LAN Adapter + +usb:v0789p0164* + ID_MODEL_FROM_DATABASE=LAN-W150/U2M Wireless LAN Adapter + +usb:v0789p0166* + ID_MODEL_FROM_DATABASE=LAN-W300N/U2 Wireless LAN Adapter + +usb:v0789p0168* + ID_MODEL_FROM_DATABASE=LAN-W150N/U2 Wireless LAN Adapter + +usb:v0789p0170* + ID_MODEL_FROM_DATABASE=LAN-W300AN/U2 Wireless LAN Adapter + +usb:v078B* + ID_VENDOR_FROM_DATABASE=Happ Controls, Inc. + +usb:v078Bp0010* + ID_MODEL_FROM_DATABASE=Driving UGCI + +usb:v078Bp0020* + ID_MODEL_FROM_DATABASE=Flying UGCI + +usb:v078Bp0030* + ID_MODEL_FROM_DATABASE=Fighting UGCI + +usb:v078C* + ID_VENDOR_FROM_DATABASE=GTCO/CalComp + +usb:v078Cp0090* + ID_MODEL_FROM_DATABASE=Tablet Adapter + +usb:v078Cp0100* + ID_MODEL_FROM_DATABASE=Tablet Adapter + +usb:v078Cp0200* + ID_MODEL_FROM_DATABASE=Tablet Adapter + +usb:v078Cp0300* + ID_MODEL_FROM_DATABASE=Tablet Adapter + +usb:v078Cp0400* + ID_MODEL_FROM_DATABASE=Digitizer (Whiteboard) + +usb:v078E* + ID_VENDOR_FROM_DATABASE=Brincom, Inc. + +usb:v0790* + ID_VENDOR_FROM_DATABASE=Pro-Image Manufacturing Co., Ltd + +usb:v0791* + ID_VENDOR_FROM_DATABASE=Copartner Wire and Cable Mfg. Corp. + +usb:v0792* + ID_VENDOR_FROM_DATABASE=Axis Communications AB + +usb:v0793* + ID_VENDOR_FROM_DATABASE=Wha Yu Industrial Co., Ltd + +usb:v0794* + ID_VENDOR_FROM_DATABASE=ABL Electronics Corp. + +usb:v0795* + ID_VENDOR_FROM_DATABASE=RealChip, Inc. + +usb:v0796* + ID_VENDOR_FROM_DATABASE=Certicom Corp. + +usb:v0797* + ID_VENDOR_FROM_DATABASE=Grandtech Semiconductor Corp. + +usb:v0797p6801* + ID_MODEL_FROM_DATABASE=Flatbed Scanner + +usb:v0797p6802* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0797p8001* + ID_MODEL_FROM_DATABASE=SmartCam + +usb:v0797p801A* + ID_MODEL_FROM_DATABASE=Typhoon StyloCam + +usb:v0797p801C* + ID_MODEL_FROM_DATABASE=Meade Binoculars/Camera + +usb:v0797p8901* + ID_MODEL_FROM_DATABASE=ScanHex SX-35a + +usb:v0797p8909* + ID_MODEL_FROM_DATABASE=ScanHex SX-35b + +usb:v0797p8911* + ID_MODEL_FROM_DATABASE=ScanHex SX-35c + +usb:v0798* + ID_VENDOR_FROM_DATABASE=Optelec + +usb:v0798p0001* + ID_MODEL_FROM_DATABASE=Braille Voyager + +usb:v0798p0640* + ID_MODEL_FROM_DATABASE=BC640 + +usb:v0798p0680* + ID_MODEL_FROM_DATABASE=BC680 + +usb:v0799* + ID_VENDOR_FROM_DATABASE=Altera + +usb:v0799p7651* + ID_MODEL_FROM_DATABASE=Programming Unit + +usb:v079B* + ID_VENDOR_FROM_DATABASE=Sagem + +usb:v079Bp0024* + ID_MODEL_FROM_DATABASE=MSO300/MSO301 Fingerprint Sensor + +usb:v079Bp0026* + ID_MODEL_FROM_DATABASE=MSO350/MSO351 Fingerprint Sensor & SmartCard Reader + +usb:v079Bp0027* + ID_MODEL_FROM_DATABASE=USB-Serial Controller + +usb:v079Bp002F* + ID_MODEL_FROM_DATABASE=Mobile + +usb:v079Bp0030* + ID_MODEL_FROM_DATABASE=Mobile Communication Device + +usb:v079Bp0042* + ID_MODEL_FROM_DATABASE=Mobile + +usb:v079Bp0047* + ID_MODEL_FROM_DATABASE=CBM/MSO1300 Fingerprint Sensor + +usb:v079Bp004A* + ID_MODEL_FROM_DATABASE=XG-760A 802.11bg + +usb:v079Bp004B* + ID_MODEL_FROM_DATABASE=Wi-Fi 11g adapter + +usb:v079Bp0052* + ID_MODEL_FROM_DATABASE=MSO1350 Fingerprint Sensor & SmartCard Reader + +usb:v079Bp0056* + ID_MODEL_FROM_DATABASE=Agfa AP1100 Photo Printer + +usb:v079Bp005D* + ID_MODEL_FROM_DATABASE=Mobile Mass Storage + +usb:v079Bp0062* + ID_MODEL_FROM_DATABASE=XG-76NA 802.11bg + +usb:v079Bp0078* + ID_MODEL_FROM_DATABASE=Laser Pro Monochrome MFP + +usb:v079D* + ID_VENDOR_FROM_DATABASE=Alfadata Computer Corp. + +usb:v079Dp0201* + ID_MODEL_FROM_DATABASE=GamePort Adapter + +usb:v07A1* + ID_VENDOR_FROM_DATABASE=Digicom S.p.A. + +usb:v07A1pD952* + ID_MODEL_FROM_DATABASE=Palladio USB V.92 Modem + +usb:v07A2* + ID_VENDOR_FROM_DATABASE=National Technical Systems + +usb:v07A3* + ID_VENDOR_FROM_DATABASE=Onnto Corp. + +usb:v07A4* + ID_VENDOR_FROM_DATABASE=Be, Inc. + +usb:v07A6* + ID_VENDOR_FROM_DATABASE=ADMtek, Inc. + +usb:v07A6p07C2* + ID_MODEL_FROM_DATABASE=AN986A Ethernet + +usb:v07A6p0986* + ID_MODEL_FROM_DATABASE=AN986 Pegasus Ethernet + +usb:v07A6p8266* + ID_MODEL_FROM_DATABASE=Infineon WildCard-USB Wireless LAN Adapter + +usb:v07A6p8511* + ID_MODEL_FROM_DATABASE=ADM8511 Pegasus II Ethernet + +usb:v07A6p8513* + ID_MODEL_FROM_DATABASE=AN8513 Ethernet + +usb:v07A6p8515* + ID_MODEL_FROM_DATABASE=AN8515 Ethernet + +usb:v07AA* + ID_VENDOR_FROM_DATABASE=Corega K.K. + +usb:v07AAp0001* + ID_MODEL_FROM_DATABASE=Ether USB-T Ethernet [klsi] + +usb:v07AAp0004* + ID_MODEL_FROM_DATABASE=FEther USB-TX Ethernet [pegasus] + +usb:v07AAp000C* + ID_MODEL_FROM_DATABASE=WirelessLAN USB-11 + +usb:v07AAp000D* + ID_MODEL_FROM_DATABASE=FEther USB-TXS + +usb:v07AAp0011* + ID_MODEL_FROM_DATABASE=Wireless LAN USB-11 mini + +usb:v07AAp0012* + ID_MODEL_FROM_DATABASE=Stick-11 802.11b Adapter + +usb:v07AAp0017* + ID_MODEL_FROM_DATABASE=FEther USB2-TX + +usb:v07AAp0018* + ID_MODEL_FROM_DATABASE=Wireless LAN USB-11 mini 2 + +usb:v07AAp001A* + ID_MODEL_FROM_DATABASE=ULUSB-11 Key + +usb:v07AAp001C* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GTST 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v07AAp002E* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GPX [Ralink RT2571W] + +usb:v07AAp002F* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GNL + +usb:v07AAp0031* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GS 802.11bg [Atheros AR5523] + +usb:v07AAp003C* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GNL + +usb:v07AAp003F* + ID_MODEL_FROM_DATABASE=CG-WLUSB300AGN + +usb:v07AAp0041* + ID_MODEL_FROM_DATABASE=CG-WLUSB300GNS + +usb:v07AAp0042* + ID_MODEL_FROM_DATABASE=CG-WLUSB300GNM + +usb:v07AAp0043* + ID_MODEL_FROM_DATABASE=CG-WLUSB300N rev A2 [Realtek RTL8192U] + +usb:v07AAp0047* + ID_MODEL_FROM_DATABASE=CG-WLUSBNM + +usb:v07AAp0051* + ID_MODEL_FROM_DATABASE=CG-WLUSB300NM + +usb:v07AAp7613* + ID_MODEL_FROM_DATABASE=Stick-11 V2 802.11b Adapter + +usb:v07AAp9601* + ID_MODEL_FROM_DATABASE=FEther USB-TXC + +usb:v07AB* + ID_VENDOR_FROM_DATABASE=Freecom Technologies + +usb:v07ABpFC01* + ID_MODEL_FROM_DATABASE=IDE bridge + +usb:v07ABpFC02* + ID_MODEL_FROM_DATABASE=Cable II USB-2 + +usb:v07ABpFC03* + ID_MODEL_FROM_DATABASE=USB2-IDE IDE bridge + +usb:v07ABpFCD6* + ID_MODEL_FROM_DATABASE=Freecom HD Classic + +usb:v07ABpFCF6* + ID_MODEL_FROM_DATABASE=DataBar 512 MB + +usb:v07ABpFCF8* + ID_MODEL_FROM_DATABASE=Freecom Classic SL Network Drive + +usb:v07ABpFCFE* + ID_MODEL_FROM_DATABASE=Hard Drive 80GB + +usb:v07AF* + ID_VENDOR_FROM_DATABASE=Microtech + +usb:v07AFp0004* + ID_MODEL_FROM_DATABASE=SCSI-DB25 SCSI Bridge [shuttle] + +usb:v07AFp0005* + ID_MODEL_FROM_DATABASE=SCSI-HD50 SCSI Bridge [shuttle] + +usb:v07AFp0006* + ID_MODEL_FROM_DATABASE=CameraMate SmartMedia and CompactFlash Card Reader [eusb/shuttle] + +usb:v07AFpFC01* + ID_MODEL_FROM_DATABASE=Freecom USB-IDE + +usb:v07B0* + ID_VENDOR_FROM_DATABASE=Trust Technologies + +usb:v07B0p0001* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v07B0p0002* + ID_MODEL_FROM_DATABASE=ISDN TA128 Plus + +usb:v07B0p0003* + ID_MODEL_FROM_DATABASE=ISDN TA128 Deluxe + +usb:v07B0p0005* + ID_MODEL_FROM_DATABASE=ISDN TA128 SE + +usb:v07B0p0006* + ID_MODEL_FROM_DATABASE=ISDN TA128 CE + +usb:v07B0p0007* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v07B0p0008* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v07B1* + ID_VENDOR_FROM_DATABASE=IMP, Inc. + +usb:v07B2* + ID_VENDOR_FROM_DATABASE=Motorola BCS, Inc. + +usb:v07B2p0100* + ID_MODEL_FROM_DATABASE=SURFboard Voice over IP Cable Modem + +usb:v07B2p0900* + ID_MODEL_FROM_DATABASE=SURFboard Gateway + +usb:v07B2p0950* + ID_MODEL_FROM_DATABASE=SURFboard SBG950 Gateway + +usb:v07B2p1000* + ID_MODEL_FROM_DATABASE=SURFboard SBG1000 Gateway + +usb:v07B2p4100* + ID_MODEL_FROM_DATABASE=SurfBoard SB4100 Cable Modem + +usb:v07B2p4200* + ID_MODEL_FROM_DATABASE=SurfBoard SB4200 Cable Modem + +usb:v07B2p4210* + ID_MODEL_FROM_DATABASE=SurfBoard 4210 Cable Modem + +usb:v07B2p4220* + ID_MODEL_FROM_DATABASE=SURFboard SB4220 Cable Modem + +usb:v07B2p4500* + ID_MODEL_FROM_DATABASE=CG4500 Communications Gateway + +usb:v07B2p450B* + ID_MODEL_FROM_DATABASE=CG4501 Communications Gateway + +usb:v07B2p450E* + ID_MODEL_FROM_DATABASE=CG4500E Communications Gateway + +usb:v07B2p5100* + ID_MODEL_FROM_DATABASE=SurfBoard SB5100 Cable Modem + +usb:v07B2p5101* + ID_MODEL_FROM_DATABASE=SurfBoard SB5101 Cable Modem + +usb:v07B2p5120* + ID_MODEL_FROM_DATABASE=SurfBoard SB5120 Cable Modem (RNDIS) + +usb:v07B2p5121* + ID_MODEL_FROM_DATABASE=Surfboard 5121 Cable Modem + +usb:v07B2p7030* + ID_MODEL_FROM_DATABASE=WU830G 802.11bg Wireless Adapter [Envara WiND512] + +usb:v07B3* + ID_VENDOR_FROM_DATABASE=Plustek, Inc. + +usb:v07B3p0001* + ID_MODEL_FROM_DATABASE=OpticPro 1212U Scanner + +usb:v07B3p0003* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0010* + ID_MODEL_FROM_DATABASE=OpticPro U12 Scanner + +usb:v07B3p0011* + ID_MODEL_FROM_DATABASE=OpticPro U24 Scanner + +usb:v07B3p0013* + ID_MODEL_FROM_DATABASE=OpticPro UT12 Scanner + +usb:v07B3p0014* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0015* + ID_MODEL_FROM_DATABASE=OpticPro U24 Scanner + +usb:v07B3p0017* + ID_MODEL_FROM_DATABASE=OpticPro UT12/16/24 Scanner + +usb:v07B3p0204* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0400* + ID_MODEL_FROM_DATABASE=OpticPro 1248U Scanner + +usb:v07B3p0401* + ID_MODEL_FROM_DATABASE=OpticPro 1248U Scanner #2 + +usb:v07B3p0403* + ID_MODEL_FROM_DATABASE=OpticPro U16B Scanner + +usb:v07B3p0404* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0405* + ID_MODEL_FROM_DATABASE=A8 Namecard-s Controller + +usb:v07B3p0406* + ID_MODEL_FROM_DATABASE=A8 Namecard-D Controller + +usb:v07B3p0410* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0412* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v07B3p0413* + ID_MODEL_FROM_DATABASE=OpticSlim 1200 Scanner + +usb:v07B3p0601* + ID_MODEL_FROM_DATABASE=OpticPro ST24 Scanner + +usb:v07B3p0800* + ID_MODEL_FROM_DATABASE=OpticPro ST48 Scanner + +usb:v07B3p0900* + ID_MODEL_FROM_DATABASE=OpticBook 3600 Scanner + +usb:v07B3p090C* + ID_MODEL_FROM_DATABASE=OpticBook 3600 Plus Scanner + +usb:v07B3p0A06* + ID_MODEL_FROM_DATABASE=TVcam VD100 + +usb:v07B3p0B00* + ID_MODEL_FROM_DATABASE=SmartPhoto F50 + +usb:v07B3p0C03* + ID_MODEL_FROM_DATABASE=OpticPro ST64+ Scanner + +usb:v07B3p0C04* + ID_MODEL_FROM_DATABASE=Optic Film 7200i scanner + +usb:v07B3p0C0C* + ID_MODEL_FROM_DATABASE=PL806 Scanner + +usb:v07B3p0C26* + ID_MODEL_FROM_DATABASE=OpticBook 4600 Scanner + +usb:v07B3p0C2B* + ID_MODEL_FROM_DATABASE=Mobile Office D428 Scanner + +usb:v07B3p0E08* + ID_MODEL_FROM_DATABASE=Plustek OpticBook A300 Scanner + +usb:v07B3p1300* + ID_MODEL_FROM_DATABASE=OpticBook 3800 Scanner + +usb:v07B3p1301* + ID_MODEL_FROM_DATABASE=OpticBook 4800 Scanner + +usb:v07B4* + ID_VENDOR_FROM_DATABASE=Olympus Optical Co., Ltd + +usb:v07B4p0100* + ID_MODEL_FROM_DATABASE=Camedia C-2100/C-3000 Ultra Zoom Camera + +usb:v07B4p0102* + ID_MODEL_FROM_DATABASE=Camedia E-10/C-220/C-50 Camera + +usb:v07B4p0105* + ID_MODEL_FROM_DATABASE=Camedia C-310Z/C-700/C-750UZ/C-755/C-765UZ/C-3040/C-4000/C-5050Z/D-560/C-3020Z Zoom Camera + +usb:v07B4p0109* + ID_MODEL_FROM_DATABASE=C-370Z/C-500Z/D-535Z/X-450 + +usb:v07B4p010A* + ID_MODEL_FROM_DATABASE=MAUSB-10 xD and SmartMedia Card Reader + +usb:v07B4p0112* + ID_MODEL_FROM_DATABASE=MAUSB-100 xD Card Reader + +usb:v07B4p0113* + ID_MODEL_FROM_DATABASE=Mju 500 + +usb:v07B4p0114* + ID_MODEL_FROM_DATABASE=C-350Z Camera + +usb:v07B4p0118* + ID_MODEL_FROM_DATABASE=Mju Mini Digital/Mju Digital 500 Camera / Stylus 850 SW + +usb:v07B4p0184* + ID_MODEL_FROM_DATABASE=P-S100 port + +usb:v07B4p0202* + ID_MODEL_FROM_DATABASE=Foot Switch RS-26 + +usb:v07B4p0203* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DW-90 + +usb:v07B4p0206* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DS-330 + +usb:v07B4p0207* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder & Camera W-10 + +usb:v07B4p0209* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DM-20 + +usb:v07B4p020B* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DS-4000 + +usb:v07B4p020D* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder VN-240PC + +usb:v07B4p0211* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DS-2300 + +usb:v07B4p0218* + ID_MODEL_FROM_DATABASE=Foot Switch RS-28 + +usb:v07B4p0244* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder VN-8500PC + +usb:v07B4p024F* + ID_MODEL_FROM_DATABASE=Digital Voice Recorder DS-7000 + +usb:v07B4p0280* + ID_MODEL_FROM_DATABASE=m:robe 100 + +usb:v07B5* + ID_VENDOR_FROM_DATABASE=Mega World International, Ltd + +usb:v07B5p0017* + ID_MODEL_FROM_DATABASE=Joystick + +usb:v07B5p0213* + ID_MODEL_FROM_DATABASE=Thrustmaster Firestorm Digital 3 Gamepad + +usb:v07B5p0312* + ID_MODEL_FROM_DATABASE=Gamepad + +usb:v07B5p9902* + ID_MODEL_FROM_DATABASE=GamePad + +usb:v07B6* + ID_VENDOR_FROM_DATABASE=Marubun Corp. + +usb:v07B7* + ID_VENDOR_FROM_DATABASE=TIME Interconnect, Ltd + +usb:v07B8* + ID_VENDOR_FROM_DATABASE=AboCom Systems Inc + +usb:v07B8p110C* + ID_MODEL_FROM_DATABASE=XX1 + +usb:v07B8p1201* + ID_MODEL_FROM_DATABASE=IEEE 802.11b Adapter + +usb:v07B8p200C* + ID_MODEL_FROM_DATABASE=XX2 + +usb:v07B8p2573* + ID_MODEL_FROM_DATABASE=Wireless LAN Card + +usb:v07B8p2770* + ID_MODEL_FROM_DATABASE=802.11n/b/g Mini Wireless LAN USB2.0 Adapter + +usb:v07B8p2870* + ID_MODEL_FROM_DATABASE=802.11n/b/g Wireless LAN USB2.0 Adapter + +usb:v07B8p3070* + ID_MODEL_FROM_DATABASE=802.11n/b/g Mini Wireless LAN USB2.0 Adapter + +usb:v07B8p3071* + ID_MODEL_FROM_DATABASE=802.11n/b/g Mini Wireless LAN USB2.0 Adapter + +usb:v07B8p3072* + ID_MODEL_FROM_DATABASE=802.11n/b/g Mini Wireless LAN USB2.0 Adapter + +usb:v07B8p4000* + ID_MODEL_FROM_DATABASE=DU-E10 Ethernet [klsi] + +usb:v07B8p4002* + ID_MODEL_FROM_DATABASE=DU-E100 Ethernet [pegasus] + +usb:v07B8p4003* + ID_MODEL_FROM_DATABASE=1/10/100 Ethernet Adapter + +usb:v07B8p4004* + ID_MODEL_FROM_DATABASE=XX4 + +usb:v07B8p4007* + ID_MODEL_FROM_DATABASE=XX5 + +usb:v07B8p400B* + ID_MODEL_FROM_DATABASE=XX6 + +usb:v07B8p400C* + ID_MODEL_FROM_DATABASE=XX7 + +usb:v07B8p401A* + ID_MODEL_FROM_DATABASE=RTL8151 + +usb:v07B8p4102* + ID_MODEL_FROM_DATABASE=USB 1.1 10/100M Fast Ethernet Adapter + +usb:v07B8p4104* + ID_MODEL_FROM_DATABASE=XX9 + +usb:v07B8p420A* + ID_MODEL_FROM_DATABASE=UF200 Ethernet + +usb:v07B8p5301* + ID_MODEL_FROM_DATABASE=GW-US54ZGL 802.11bg + +usb:v07B8p6001* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v07B8p8188* + ID_MODEL_FROM_DATABASE=AboCom Systems Inc [WN2001 Prolink Wireless-N Nano Adapter] + +usb:v07B8pA001* + ID_MODEL_FROM_DATABASE=WUG2200 802.11g Wireless Adapter [Envara WiND512] + +usb:v07B8pABC1* + ID_MODEL_FROM_DATABASE=DU-E10 Ethernet [pegasus] + +usb:v07B8pB000* + ID_MODEL_FROM_DATABASE=BWU613 + +usb:v07B8pB02A* + ID_MODEL_FROM_DATABASE=AboCom Bluetooth Device + +usb:v07B8pB02B* + ID_MODEL_FROM_DATABASE=Bluetooth dongle + +usb:v07B8pB02C* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB02D* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB02E* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB030* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB031* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB032* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB033* + ID_MODEL_FROM_DATABASE=BCM92045DG-Flash with trace filter + +usb:v07B8pB21A* + ID_MODEL_FROM_DATABASE=WUG2400 802.11g Wireless Adapter [Texas Instruments TNETW1450] + +usb:v07B8pB21B* + ID_MODEL_FROM_DATABASE=HWU54DM + +usb:v07B8pB21C* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v07B8pB21D* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v07B8pB21E* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v07B8pB21F* + ID_MODEL_FROM_DATABASE=WUG2700 + +usb:v07B8pD011* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v07B8pE001* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE002* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE003* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE004* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE005* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE006* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE007* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE008* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE009* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE00A* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07B8pE4F0* + ID_MODEL_FROM_DATABASE=Card Reader Driver + +usb:v07B8pF101* + ID_MODEL_FROM_DATABASE=DSB-560 Modem [atlas] + +usb:v07BC* + ID_VENDOR_FROM_DATABASE=Canon Computer Systems, Inc. + +usb:v07BD* + ID_VENDOR_FROM_DATABASE=Webgear, Inc. + +usb:v07BE* + ID_VENDOR_FROM_DATABASE=Veridicom + +usb:v07C0* + ID_VENDOR_FROM_DATABASE=Code Mercenaries Hard- und Software GmbH + +usb:v07C0p1113* + ID_MODEL_FROM_DATABASE=JoyWarrior24F8 + +usb:v07C0p1116* + ID_MODEL_FROM_DATABASE=JoyWarrior24F14 + +usb:v07C0p1121* + ID_MODEL_FROM_DATABASE=The Claw + +usb:v07C0p1500* + ID_MODEL_FROM_DATABASE=IO-Warrior 40 + +usb:v07C0p1501* + ID_MODEL_FROM_DATABASE=IO-Warrior 24 + +usb:v07C0p1502* + ID_MODEL_FROM_DATABASE=IO-Warrior 48 + +usb:v07C0p1503* + ID_MODEL_FROM_DATABASE=IO-Warrior 28 + +usb:v07C0p1511* + ID_MODEL_FROM_DATABASE=IO-Warrior 24 Power Vampire + +usb:v07C0p1512* + ID_MODEL_FROM_DATABASE=IO-Warrior 24 Power Vampire + +usb:v07C1* + ID_VENDOR_FROM_DATABASE=Keisokugiken + +usb:v07C1p0068* + ID_MODEL_FROM_DATABASE=HKS-0200 USBDAQ + +usb:v07C4* + ID_VENDOR_FROM_DATABASE=Datafab Systems, Inc. + +usb:v07C4p0102* + ID_MODEL_FROM_DATABASE=USB to LS120 + +usb:v07C4p0103* + ID_MODEL_FROM_DATABASE=USB to IDE + +usb:v07C4p1234* + ID_MODEL_FROM_DATABASE=USB to ATAPI + +usb:v07C4pA000* + ID_MODEL_FROM_DATABASE=CompactFlash Card Reader + +usb:v07C4pA001* + ID_MODEL_FROM_DATABASE=CompactFlash & SmartMedia Card Reader [eusb] + +usb:v07C4pA002* + ID_MODEL_FROM_DATABASE=Disk Drive + +usb:v07C4pA003* + ID_MODEL_FROM_DATABASE=Datafab-based Reader + +usb:v07C4pA004* + ID_MODEL_FROM_DATABASE=USB to MMC Class Drive + +usb:v07C4pA005* + ID_MODEL_FROM_DATABASE=CompactFlash & SmartMedia Card Reader + +usb:v07C4pA006* + ID_MODEL_FROM_DATABASE=SmartMedia Card Reader + +usb:v07C4pA007* + ID_MODEL_FROM_DATABASE=Memory Stick Class Drive + +usb:v07C4pA103* + ID_MODEL_FROM_DATABASE=MDSM-B reader + +usb:v07C4pA107* + ID_MODEL_FROM_DATABASE=USB to Memory Stick (LC1) Drive + +usb:v07C4pA109* + ID_MODEL_FROM_DATABASE=LC1 CompactFlash & SmartMedia Card Reader + +usb:v07C4pA10B* + ID_MODEL_FROM_DATABASE=USB to CF+MS(LC1) + +usb:v07C4pA200* + ID_MODEL_FROM_DATABASE=DF-UT-06 Hama MMC/SD Reader + +usb:v07C4pA400* + ID_MODEL_FROM_DATABASE=CompactFlash & Microdrive Reader + +usb:v07C4pA600* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v07C4pAD01* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07C4pAE01* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07C4pAF01* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v07C4pB000* + ID_MODEL_FROM_DATABASE=USB to CF(LC1) + +usb:v07C4pB001* + ID_MODEL_FROM_DATABASE=USB to CF+PCMCIA + +usb:v07C4pB004* + ID_MODEL_FROM_DATABASE=MMC/SD Reader + +usb:v07C4pB006* + ID_MODEL_FROM_DATABASE=USB to PCMCIA + +usb:v07C4pB00A* + ID_MODEL_FROM_DATABASE=USB to CF+SD Drive(LC1) + +usb:v07C4pB00B* + ID_MODEL_FROM_DATABASE=USB to Memory Stick(LC1) + +usb:v07C4pC010* + ID_MODEL_FROM_DATABASE=Kingston FCR-HS2/ATA Card Reader + +usb:v07C5* + ID_VENDOR_FROM_DATABASE=APG Cash Drawer + +usb:v07C6* + ID_VENDOR_FROM_DATABASE=ShareWave, Inc. + +usb:v07C6p0002* + ID_MODEL_FROM_DATABASE=Bodega Wireless Access Point + +usb:v07C6p0003* + ID_MODEL_FROM_DATABASE=Bodega Wireless Network Adapter + +usb:v07C7* + ID_VENDOR_FROM_DATABASE=Powertech Industrial Co., Ltd + +usb:v07C8* + ID_VENDOR_FROM_DATABASE=B.U.G., Inc. + +usb:v07C8p0202* + ID_MODEL_FROM_DATABASE=MN128-SOHO PAL + +usb:v07C9* + ID_VENDOR_FROM_DATABASE=Allied Telesyn International + +usb:v07C9pB100* + ID_MODEL_FROM_DATABASE=AT-USB100 + +usb:v07CA* + ID_VENDOR_FROM_DATABASE=AVerMedia Technologies, Inc. + +usb:v07CAp0002* + ID_MODEL_FROM_DATABASE=AVerTV PVR USB/EZMaker Pro Device + +usb:v07CAp0026* + ID_MODEL_FROM_DATABASE=AVerTV + +usb:v07CAp0337* + ID_MODEL_FROM_DATABASE=A867 DVB-T dongle + +usb:v07CAp0837* + ID_MODEL_FROM_DATABASE=H837 Hybrid ATSC/QAM + +usb:v07CAp1228* + ID_MODEL_FROM_DATABASE=MPEG-2 Capture Device (M038) + +usb:v07CAp1830* + ID_MODEL_FROM_DATABASE=AVerTV Volar Video Capture (H830) + +usb:v07CAp3835* + ID_MODEL_FROM_DATABASE=AVerTV Volar Green HD (A835B) + +usb:v07CAp850A* + ID_MODEL_FROM_DATABASE=AverTV Volar Black HD (A850) + +usb:v07CAp850B* + ID_MODEL_FROM_DATABASE=AverTV Red HD+ (A850T) + +usb:v07CApA309* + ID_MODEL_FROM_DATABASE=AVerTV DVB-T (A309) + +usb:v07CApA801* + ID_MODEL_FROM_DATABASE=AVerTV DVB-T (A800) + +usb:v07CApA815* + ID_MODEL_FROM_DATABASE=AVerTV DVB-T Volar X (A815) + +usb:v07CApA827* + ID_MODEL_FROM_DATABASE=AVerTV Hybrid Volar HX (A827) + +usb:v07CApA867* + ID_MODEL_FROM_DATABASE=AVerTV DVB-T (A867) + +usb:v07CApB800* + ID_MODEL_FROM_DATABASE=MR800 FM Radio + +usb:v07CApE880* + ID_MODEL_FROM_DATABASE=MPEG-2 Capture Device (E880) + +usb:v07CApE882* + ID_MODEL_FROM_DATABASE=MPEG-2 Capture Device (E882) + +usb:v07CB* + ID_VENDOR_FROM_DATABASE=Kingmax Technology, Inc. + +usb:v07CC* + ID_VENDOR_FROM_DATABASE=Carry Computer Eng., Co., Ltd + +usb:v07CCp0000* + ID_MODEL_FROM_DATABASE=CF Card Reader + +usb:v07CCp0001* + ID_MODEL_FROM_DATABASE=Reader (UICSE) + +usb:v07CCp0002* + ID_MODEL_FROM_DATABASE=Reader (UIS) + +usb:v07CCp0003* + ID_MODEL_FROM_DATABASE=SM Card Reader + +usb:v07CCp0004* + ID_MODEL_FROM_DATABASE=SM/CF/PCMCIA Card Reader + +usb:v07CCp0005* + ID_MODEL_FROM_DATABASE=Reader (UISA2SE) + +usb:v07CCp0006* + ID_MODEL_FROM_DATABASE=SM/CF/PCMCIA Card Reader + +usb:v07CCp0007* + ID_MODEL_FROM_DATABASE=Reader (UISA6SE) + +usb:v07CCp000C* + ID_MODEL_FROM_DATABASE=SM/CF Card Reader + +usb:v07CCp000D* + ID_MODEL_FROM_DATABASE=SM/CF Card Reader + +usb:v07CCp000E* + ID_MODEL_FROM_DATABASE=Reader (UISDA) + +usb:v07CCp000F* + ID_MODEL_FROM_DATABASE=Reader (UICLIK) + +usb:v07CCp0010* + ID_MODEL_FROM_DATABASE=Reader (UISMA) + +usb:v07CCp0012* + ID_MODEL_FROM_DATABASE=Reader (UISC6SE-FLASH) + +usb:v07CCp0014* + ID_MODEL_FROM_DATABASE=Litronic Fortezza Reader + +usb:v07CCp0030* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC12S) + +usb:v07CCp0040* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC13S) + +usb:v07CCp0100* + ID_MODEL_FROM_DATABASE=Reader (UID) + +usb:v07CCp0101* + ID_MODEL_FROM_DATABASE=Reader (UIM) + +usb:v07CCp0102* + ID_MODEL_FROM_DATABASE=Reader (UISDMA) + +usb:v07CCp0103* + ID_MODEL_FROM_DATABASE=Reader (UISDMC) + +usb:v07CCp0104* + ID_MODEL_FROM_DATABASE=Reader (UISDM) + +usb:v07CCp0200* + ID_MODEL_FROM_DATABASE=6-in-1 Card Reader + +usb:v07CCp0201* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC1S & UISDMC3S) + +usb:v07CCp0202* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC5S) + +usb:v07CCp0203* + ID_MODEL_FROM_DATABASE=Mass Storage (UISMC5S) + +usb:v07CCp0204* + ID_MODEL_FROM_DATABASE=Mass Storage (UIM4/5S & UIM7S) + +usb:v07CCp0205* + ID_MODEL_FROM_DATABASE=Mass Storage (UIS4/5S & UIS7S) + +usb:v07CCp0206* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC10S & UISDMC11S) + +usb:v07CCp0207* + ID_MODEL_FROM_DATABASE=Mass Storage (UPIDMA) + +usb:v07CCp0208* + ID_MODEL_FROM_DATABASE=Mass Storage (UCFC II) + +usb:v07CCp0210* + ID_MODEL_FROM_DATABASE=Mass Storage (UPIXXA) + +usb:v07CCp0213* + ID_MODEL_FROM_DATABASE=Mass Storage (UPIDA) + +usb:v07CCp0214* + ID_MODEL_FROM_DATABASE=Mass Storage (UPIMA) + +usb:v07CCp0215* + ID_MODEL_FROM_DATABASE=Mass Storage (UPISA) + +usb:v07CCp0217* + ID_MODEL_FROM_DATABASE=Mass Storage (UPISDMA) + +usb:v07CCp0223* + ID_MODEL_FROM_DATABASE=Mass Storage (UCIDA) + +usb:v07CCp0224* + ID_MODEL_FROM_DATABASE=Mass Storage (UCIMA) + +usb:v07CCp0225* + ID_MODEL_FROM_DATABASE=Mass Storage (UIS7S) + +usb:v07CCp0227* + ID_MODEL_FROM_DATABASE=Mass Storage (UCIDMA) + +usb:v07CCp0234* + ID_MODEL_FROM_DATABASE=Mass Storage (UIM7S) + +usb:v07CCp0235* + ID_MODEL_FROM_DATABASE=Mass Storage (UIS4S-S) + +usb:v07CCp0237* + ID_MODEL_FROM_DATABASE=Velper (UISDMC4S) + +usb:v07CCp0300* + ID_MODEL_FROM_DATABASE=6-in-1 Card Reader + +usb:v07CCp0301* + ID_MODEL_FROM_DATABASE=6-in-1 Card Reader + +usb:v07CCp0303* + ID_MODEL_FROM_DATABASE=Mass Storage (UID10W) + +usb:v07CCp0304* + ID_MODEL_FROM_DATABASE=Mass Storage (UIM10W) + +usb:v07CCp0305* + ID_MODEL_FROM_DATABASE=Mass Storage (UIS10W) + +usb:v07CCp0308* + ID_MODEL_FROM_DATABASE=Mass Storage (UIC10W) + +usb:v07CCp0309* + ID_MODEL_FROM_DATABASE=Mass Storage (UISC3W) + +usb:v07CCp0310* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMA2W) + +usb:v07CCp0311* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC14W) + +usb:v07CCp0320* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC4W) + +usb:v07CCp0321* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC37W) + +usb:v07CCp0330* + ID_MODEL_FROM_DATABASE=WINTERREADER Reader + +usb:v07CCp0350* + ID_MODEL_FROM_DATABASE=9-in-1 Card Reader + +usb:v07CCp0500* + ID_MODEL_FROM_DATABASE=Mass Storage + +usb:v07CCp0501* + ID_MODEL_FROM_DATABASE=Mass Storage + +usb:v07CD* + ID_VENDOR_FROM_DATABASE=Elektor + +usb:v07CDp0001* + ID_MODEL_FROM_DATABASE=USBuart Serial Port + +usb:v07CF* + ID_VENDOR_FROM_DATABASE=Casio Computer Co., Ltd + +usb:v07CFp1001* + ID_MODEL_FROM_DATABASE=QV-8000SX/5700/3000EX Digicam; Exilim EX-M20 + +usb:v07CFp1003* + ID_MODEL_FROM_DATABASE=Exilim EX-S500 + +usb:v07CFp1004* + ID_MODEL_FROM_DATABASE=Exilim EX-Z120 + +usb:v07CFp1011* + ID_MODEL_FROM_DATABASE=USB-CASIO PC CAMERA + +usb:v07CFp1116* + ID_MODEL_FROM_DATABASE=EXILIM EX-Z19 + +usb:v07CFp1125* + ID_MODEL_FROM_DATABASE=Exilim EX-H10 Digital Camera (mass storage mode) + +usb:v07CFp1133* + ID_MODEL_FROM_DATABASE=Exilim EX-Z350 Digital Camera (mass storage mode) + +usb:v07CFp1225* + ID_MODEL_FROM_DATABASE=Exilim EX-H10 Digital Camera (PictBridge mode) + +usb:v07CFp1233* + ID_MODEL_FROM_DATABASE=Exilim EX-Z350 Digital Camera (PictBridge mode) + +usb:v07CFp2002* + ID_MODEL_FROM_DATABASE=E-125 Cassiopeia Pocket PC + +usb:v07CFp3801* + ID_MODEL_FROM_DATABASE=WMP-1 MP3-Watch + +usb:v07CFp4001* + ID_MODEL_FROM_DATABASE=Label Printer KL-P1000 + +usb:v07CFp4007* + ID_MODEL_FROM_DATABASE=CW50 Device + +usb:v07CFp4104* + ID_MODEL_FROM_DATABASE=Cw75 Device + +usb:v07CFp4107* + ID_MODEL_FROM_DATABASE=CW-L300 Device + +usb:v07CFp4500* + ID_MODEL_FROM_DATABASE=LV-20 Digital Camera + +usb:v07CFp6801* + ID_MODEL_FROM_DATABASE=PL-40R + +usb:v07CFp6802* + ID_MODEL_FROM_DATABASE=MIDI Keyboard + +usb:v07D0* + ID_VENDOR_FROM_DATABASE=Dazzle + +usb:v07D0p0001* + ID_MODEL_FROM_DATABASE=Digital Video Creator I + +usb:v07D0p0002* + ID_MODEL_FROM_DATABASE=Global Village VideoFX Grabber + +usb:v07D0p0003* + ID_MODEL_FROM_DATABASE=Fusion Model DVC-50 Rev 1 (NTSC) + +usb:v07D0p0004* + ID_MODEL_FROM_DATABASE=DVC-800 (PAL) Grabber + +usb:v07D0p0005* + ID_MODEL_FROM_DATABASE=Fusion Video and Audio Ports + +usb:v07D0p0006* + ID_MODEL_FROM_DATABASE=DVC 150 Loader Device + +usb:v07D0p0007* + ID_MODEL_FROM_DATABASE=DVC 150 + +usb:v07D0p0327* + ID_MODEL_FROM_DATABASE=Fusion Digital Media Reader + +usb:v07D0p1001* + ID_MODEL_FROM_DATABASE=DM-FLEX DFU Adapter + +usb:v07D0p1002* + ID_MODEL_FROM_DATABASE=DMHS2 DFU Adapter + +usb:v07D0p1102* + ID_MODEL_FROM_DATABASE=CF Reader/Writer + +usb:v07D0p1103* + ID_MODEL_FROM_DATABASE=SD Reader/Writer + +usb:v07D0p1104* + ID_MODEL_FROM_DATABASE=SM Reader/Writer + +usb:v07D0p1105* + ID_MODEL_FROM_DATABASE=MS Reader/Writer + +usb:v07D0p1106* + ID_MODEL_FROM_DATABASE=xD/SM Reader/Writer + +usb:v07D0p1202* + ID_MODEL_FROM_DATABASE=MultiSlot Reader/Writer + +usb:v07D0p2000* + ID_MODEL_FROM_DATABASE=FX2 DFU Adapter + +usb:v07D0p2001* + ID_MODEL_FROM_DATABASE=eUSB CompactFlash Reader + +usb:v07D0p4100* + ID_MODEL_FROM_DATABASE=Kingsun SF-620 Infrared Adapter + +usb:v07D0p4101* + ID_MODEL_FROM_DATABASE=Connectivity Cable (CA-42 clone) + +usb:v07D0p4959* + ID_MODEL_FROM_DATABASE=Kingsun KS-959 Infrared Adapter + +usb:v07D1* + ID_VENDOR_FROM_DATABASE=D-Link System + +usb:v07D1p13EC* + ID_MODEL_FROM_DATABASE=VvBus for Helium 2xx + +usb:v07D1p13ED* + ID_MODEL_FROM_DATABASE=VvBus for Helium 2xx + +usb:v07D1p13F1* + ID_MODEL_FROM_DATABASE=DSL-302G Modem + +usb:v07D1p13F2* + ID_MODEL_FROM_DATABASE=DSL-502G Router + +usb:v07D1p3300* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.E) [Realtek RTL8191SU] + +usb:v07D1p3302* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.C2) [Realtek RTL8191SU] + +usb:v07D1p3303* + ID_MODEL_FROM_DATABASE=DWA-131 802.11n Wireless N Nano Adapter(rev.A1) [Realtek RTL8192SU] + +usb:v07D1p3304* + ID_MODEL_FROM_DATABASE=FR-300USB 802.11bgn Wireless Adapter + +usb:v07D1p3A07* + ID_MODEL_FROM_DATABASE=WUA-2340 RangeBooster G Adapter(rev.A) [Atheros AR5523] + +usb:v07D1p3A08* + ID_MODEL_FROM_DATABASE=WUA-2340 RangeBooster G Adapter(rev.A) (no firmware) [Atheros AR5523] + +usb:v07D1p3A09* + ID_MODEL_FROM_DATABASE=DWA-160 802.11abgn Xtreme N Dual Band Adapter(rev.A2) [Atheros AR9170+AR9104] + +usb:v07D1p3A0D* + ID_MODEL_FROM_DATABASE=DWA-120 802.11g Wireless 108G Adapter [Atheros AR5523] + +usb:v07D1p3A0F* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.D) [Atheros AR9170+AR9102] + +usb:v07D1p3A10* + ID_MODEL_FROM_DATABASE=DWA-126 802.11n Wireless Adapter [Atheros AR9271] + +usb:v07D1p3B01* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.D) [Marvell 88W8338+88W8010] + +usb:v07D1p3B10* + ID_MODEL_FROM_DATABASE=DWA-142 RangeBooster N Adapter [Marvell 88W8362+88W8060] + +usb:v07D1p3B11* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.A1) [Marvell 88W8362+88W8060] + +usb:v07D1p3C03* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.C1) [Ralink RT2571W] + +usb:v07D1p3C04* + ID_MODEL_FROM_DATABASE=WUA-1340 + +usb:v07D1p3C05* + ID_MODEL_FROM_DATABASE=EH103 Wireless G Adapter + +usb:v07D1p3C06* + ID_MODEL_FROM_DATABASE=DWA-111 802.11bg Wireless Adapter [Ralink RT2571W] + +usb:v07D1p3C07* + ID_MODEL_FROM_DATABASE=DWA-110 Wireless G Adapter(rev.A1) [Ralink RT2571W] + +usb:v07D1p3C09* + ID_MODEL_FROM_DATABASE=DWA-140 RangeBooster N Adapter(rev.B1) [Ralink RT2870] + +usb:v07D1p3C0A* + ID_MODEL_FROM_DATABASE=DWA-140 RangeBooster N Adapter(rev.B2) [Ralink RT3072] + +usb:v07D1p3C0B* + ID_MODEL_FROM_DATABASE=DWA-110 Wireless G Adapter(rev.B) [Ralink RT2870] + +usb:v07D1p3C0D* + ID_MODEL_FROM_DATABASE=DWA-125 Wireless N 150 Adapter(rev.A1) [Ralink RT3070] + +usb:v07D1p3C0E* + ID_MODEL_FROM_DATABASE=WUA-2340 RangeBooster G Adapter(rev.B) [Ralink RT2070] + +usb:v07D1p3C0F* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.E1) [Ralink RT2070] + +usb:v07D1p3C10* + ID_MODEL_FROM_DATABASE=DWA-160 802.11abgn Xtreme N Dual Band Adapter(rev.A1) [Atheros AR9170+AR9104] + +usb:v07D1p3C11* + ID_MODEL_FROM_DATABASE=DWA-160 Xtreme N Dual Band USB Adapter(rev.B) [Ralink RT2870] + +usb:v07D1p3C13* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.B) [Ralink RT2870] + +usb:v07D1p3C15* + ID_MODEL_FROM_DATABASE=DWA-140 RangeBooster N Adapter(rev.B3) [Ralink RT2870] + +usb:v07D1p3C16* + ID_MODEL_FROM_DATABASE=DWA-125 Wireless N 150 Adapter(rev.A2) [Ralink RT3070] + +usb:v07D1p3E02* + ID_MODEL_FROM_DATABASE=DWM-156 3.75G HSUPA Adapter + +usb:v07D1p5100* + ID_MODEL_FROM_DATABASE=Remote NDIS Device + +usb:v07D1pA800* + ID_MODEL_FROM_DATABASE=DWM-152 3.75G HSUPA Adapter + +usb:v07D1pF101* + ID_MODEL_FROM_DATABASE=DBT-122 Bluetooth + +usb:v07D1pFC01* + ID_MODEL_FROM_DATABASE=DBT-120 Bluetooth Adapter + +usb:v07D2* + ID_VENDOR_FROM_DATABASE=Aptio Products, Inc. + +usb:v07D3* + ID_VENDOR_FROM_DATABASE=Cyberdata Corp. + +usb:v07D5* + ID_VENDOR_FROM_DATABASE=Radiant Systems + +usb:v07D7* + ID_VENDOR_FROM_DATABASE=GCC Technologies, Inc. + +usb:v07DA* + ID_VENDOR_FROM_DATABASE=Arasan Chip Systems + +usb:v07DE* + ID_VENDOR_FROM_DATABASE=Diamond Multimedia + +usb:v07DEp2820* + ID_MODEL_FROM_DATABASE=VC500 Video Capture Dongle + +usb:v07DF* + ID_VENDOR_FROM_DATABASE=David Electronics Co., Ltd + +usb:v07E1* + ID_VENDOR_FROM_DATABASE=Ambient Technologies, Inc. + +usb:v07E1p5201* + ID_MODEL_FROM_DATABASE=V.90 Modem + +usb:v07E2* + ID_VENDOR_FROM_DATABASE=Elmeg GmbH & Co., Ltd + +usb:v07E3* + ID_VENDOR_FROM_DATABASE=Planex Communications, Inc. + +usb:v07E4* + ID_VENDOR_FROM_DATABASE=Movado Enterprise Co., Ltd + +usb:v07E4p0967* + ID_MODEL_FROM_DATABASE=SCard R/W CSR-145 + +usb:v07E4p0968* + ID_MODEL_FROM_DATABASE=SCard R/W CSR-145 + +usb:v07E5* + ID_VENDOR_FROM_DATABASE=QPS, Inc. + +usb:v07E5p05C2* + ID_MODEL_FROM_DATABASE=IDE-to-USB2.0 PCA + +usb:v07E5p5C01* + ID_MODEL_FROM_DATABASE=Que! CDRW + +usb:v07E6* + ID_VENDOR_FROM_DATABASE=Allied Cable Corp. + +usb:v07E7* + ID_VENDOR_FROM_DATABASE=Mirvo Toys, Inc. + +usb:v07E8* + ID_VENDOR_FROM_DATABASE=Labsystems + +usb:v07EA* + ID_VENDOR_FROM_DATABASE=Iwatsu Electric Co., Ltd + +usb:v07EB* + ID_VENDOR_FROM_DATABASE=Double-H Technology Co., Ltd + +usb:v07EC* + ID_VENDOR_FROM_DATABASE=Taiyo Electric Wire & Cable Co., Ltd + +usb:v07EE* + ID_VENDOR_FROM_DATABASE=Torex Retail (formerly Logware) + +usb:v07EEp0002* + ID_MODEL_FROM_DATABASE=Cash Drawer I/F + +usb:v07EF* + ID_VENDOR_FROM_DATABASE=STSN + +usb:v07EFp0001* + ID_MODEL_FROM_DATABASE=Internet Access Device + +usb:v07F2* + ID_VENDOR_FROM_DATABASE=Microcomputer Applications, Inc. + +usb:v07F2p0001* + ID_MODEL_FROM_DATABASE=KEYLOK II + +usb:v07F6* + ID_VENDOR_FROM_DATABASE=Circuit Assembly Corp. + +usb:v07F7* + ID_VENDOR_FROM_DATABASE=Century Corp. + +usb:v07F7p0005* + ID_MODEL_FROM_DATABASE=ScanLogic/Century Corporation uATA + +usb:v07F7p011E* + ID_MODEL_FROM_DATABASE=Century USB Disk Enclosure + +usb:v07F9* + ID_VENDOR_FROM_DATABASE=Dotop Technology, Inc. + +usb:v07FA* + ID_VENDOR_FROM_DATABASE=DrayTek Corp. + +usb:v07FAp0778* + ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA + +usb:v07FAp1012* + ID_MODEL_FROM_DATABASE=BeWAN ADSL USB ST (grey) + +usb:v07FAp1196* + ID_MODEL_FROM_DATABASE=BWIFI-USB54AR 802.11bg + +usb:v07FApA904* + ID_MODEL_FROM_DATABASE=BeWAN ADSL + +usb:v07FApA905* + ID_MODEL_FROM_DATABASE=BeWAN ADSL ST + +usb:v07FD* + ID_VENDOR_FROM_DATABASE=Mark of the Unicorn + +usb:v07FDp0000* + ID_MODEL_FROM_DATABASE=FastLane MIDI Interface + +usb:v07FDp0001* + ID_MODEL_FROM_DATABASE=FastLane Quad MIDI Interface + +usb:v07FDp0002* + ID_MODEL_FROM_DATABASE=MOTU Audio for 64 bit + +usb:v07FF* + ID_VENDOR_FROM_DATABASE=Unknown + +usb:v07FFp00FF* + ID_MODEL_FROM_DATABASE=Portable Hard Drive + +usb:v0801* + ID_VENDOR_FROM_DATABASE=MagTek + +usb:v0801p0001* + ID_MODEL_FROM_DATABASE=Mini Swipe Reader (Keyboard Emulation) + +usb:v0801p0002* + ID_MODEL_FROM_DATABASE=Mini Swipe Reader + +usb:v0801p0003* + ID_MODEL_FROM_DATABASE=Magstripe Insert Reader + +usb:v0802* + ID_VENDOR_FROM_DATABASE=Mako Technologies, LLC + +usb:v0803* + ID_VENDOR_FROM_DATABASE=Zoom Telephonics, Inc. + +usb:v0803p1300* + ID_MODEL_FROM_DATABASE=V92 Faxmodem + +usb:v0803p4310* + ID_MODEL_FROM_DATABASE=4410a Wireless-G Adapter [Intersil ISL3887] + +usb:v0803p4410* + ID_MODEL_FROM_DATABASE=4410b Wireless-G Adapter [ZyDAS ZD1211B] + +usb:v0803p5241* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v0803p5551* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0803p9700* + ID_MODEL_FROM_DATABASE=2986L FaxModem + +usb:v0803p9800* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v0803pA312* + ID_MODEL_FROM_DATABASE=Wireless-G + +usb:v0809* + ID_VENDOR_FROM_DATABASE=Genicom Technology, Inc. + +usb:v080A* + ID_VENDOR_FROM_DATABASE=Evermuch Technology Co., Ltd + +usb:v080B* + ID_VENDOR_FROM_DATABASE=Cross Match Technologies + +usb:v080Bp0002* + ID_MODEL_FROM_DATABASE=Fingerprint Scanner (After ReNumeration) + +usb:v080Bp0010* + ID_MODEL_FROM_DATABASE=300LC Series Fingerprint Scanner (Before ReNumeration) + +usb:v080C* + ID_VENDOR_FROM_DATABASE=Datalogic S.p.A. + +usb:v080Cp0300* + ID_MODEL_FROM_DATABASE=Gryphon D120 Barcode Scanner + +usb:v080Cp0400* + ID_MODEL_FROM_DATABASE=Gryphon D120 Barcode Scanner + +usb:v080Cp0500* + ID_MODEL_FROM_DATABASE=Gryphon D120 Barcode Scanner + +usb:v080Cp0600* + ID_MODEL_FROM_DATABASE=Gryphon M100 Barcode Scanner + +usb:v080D* + ID_VENDOR_FROM_DATABASE=Teco Image Systems Co., Ltd + +usb:v080Dp0102* + ID_MODEL_FROM_DATABASE=Hercules Scan@home 48 + +usb:v080Dp0104* + ID_MODEL_FROM_DATABASE=3.2Slim + +usb:v080Dp0110* + ID_MODEL_FROM_DATABASE=UMAX AstraSlim 1200 Scanner + +usb:v0810* + ID_VENDOR_FROM_DATABASE=Personal Communication Systems, Inc. + +usb:v0810p0001* + ID_MODEL_FROM_DATABASE=Dual PSX Adaptor + +usb:v0810p0002* + ID_MODEL_FROM_DATABASE=Dual PCS Adaptor + +usb:v0810p0003* + ID_MODEL_FROM_DATABASE=PlayStation Gamepad + +usb:v0813* + ID_VENDOR_FROM_DATABASE=Mattel, Inc. + +usb:v0813p0001* + ID_MODEL_FROM_DATABASE=Intel Play QX3 Microscope + +usb:v0813p0002* + ID_MODEL_FROM_DATABASE=Dual Mode Camera Plus + +usb:v0819* + ID_VENDOR_FROM_DATABASE=eLicenser + +usb:v0819p0101* + ID_MODEL_FROM_DATABASE=License Management and Copy Protection + +usb:v081A* + ID_VENDOR_FROM_DATABASE=MG Logic + +usb:v081Ap1000* + ID_MODEL_FROM_DATABASE=Duo Pen Tablet + +usb:v081B* + ID_VENDOR_FROM_DATABASE=Indigita Corp. + +usb:v081Bp0600* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v081Bp0601* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v081C* + ID_VENDOR_FROM_DATABASE=Mipsys + +usb:v081E* + ID_VENDOR_FROM_DATABASE=AlphaSmart, Inc. + +usb:v081EpDF00* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0822* + ID_VENDOR_FROM_DATABASE=Reudo Corp. + +usb:v0822p2001* + ID_MODEL_FROM_DATABASE=IRXpress Infrared Device + +usb:v0825* + ID_VENDOR_FROM_DATABASE=GC Protronics + +usb:v0826* + ID_VENDOR_FROM_DATABASE=Data Transit + +usb:v0827* + ID_VENDOR_FROM_DATABASE=BroadLogic, Inc. + +usb:v0828* + ID_VENDOR_FROM_DATABASE=Sato Corp. + +usb:v0829* + ID_VENDOR_FROM_DATABASE=DirecTV Broadband, Inc. (Telocity) + +usb:v082D* + ID_VENDOR_FROM_DATABASE=Handspring + +usb:v082Dp0100* + ID_MODEL_FROM_DATABASE=Visor + +usb:v082Dp0200* + ID_MODEL_FROM_DATABASE=Treo + +usb:v082Dp0300* + ID_MODEL_FROM_DATABASE=Treo 600 + +usb:v082Dp0400* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v082Dp0500* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v082Dp0600* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830* + ID_VENDOR_FROM_DATABASE=Palm, Inc. + +usb:v0830p0001* + ID_MODEL_FROM_DATABASE=m500 + +usb:v0830p0002* + ID_MODEL_FROM_DATABASE=m505 + +usb:v0830p0003* + ID_MODEL_FROM_DATABASE=m515 + +usb:v0830p0004* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0005* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0006* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0010* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0011* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0012* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0013* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0014* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0020* + ID_MODEL_FROM_DATABASE=i705 + +usb:v0830p0021* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0022* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0023* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0024* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0030* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0031* + ID_MODEL_FROM_DATABASE=Tungsten W + +usb:v0830p0032* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0033* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0034* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0040* + ID_MODEL_FROM_DATABASE=m125 + +usb:v0830p0041* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0042* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0043* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0044* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0050* + ID_MODEL_FROM_DATABASE=m130 + +usb:v0830p0051* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0052* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0053* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0054* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0060* + ID_MODEL_FROM_DATABASE=Tungsten C/E/T/T2/T3 / Zire 71 + +usb:v0830p0061* + ID_MODEL_FROM_DATABASE=Lifedrive / Treo 650/680 / Tunsten E2/T5/TX / Centro / Zire 21/31/72 / Z22 + +usb:v0830p0062* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0063* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0064* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0070* + ID_MODEL_FROM_DATABASE=Zire + +usb:v0830p0071* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0072* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0080* + ID_MODEL_FROM_DATABASE=Serial Adapter [for Palm III] + +usb:v0830p0081* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p0082* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0830p00A0* + ID_MODEL_FROM_DATABASE=Treo 800w + +usb:v0830p0101* + ID_MODEL_FROM_DATABASE=Pre + +usb:v0832* + ID_VENDOR_FROM_DATABASE=Kouwell Electronics Corp. + +usb:v0832p5850* + ID_MODEL_FROM_DATABASE=Cable + +usb:v0833* + ID_VENDOR_FROM_DATABASE=Sourcenext Corp. + +usb:v0833p012E* + ID_MODEL_FROM_DATABASE=KeikaiDenwa 8 with charger + +usb:v0833p039F* + ID_MODEL_FROM_DATABASE=KeikaiDenwa 8 + +usb:v0835* + ID_VENDOR_FROM_DATABASE=Action Star Enterprise Co., Ltd + +usb:v0836* + ID_VENDOR_FROM_DATABASE=TrekStor + +usb:v0836p2836* + ID_MODEL_FROM_DATABASE=i.Beat mood + +usb:v0839* + ID_VENDOR_FROM_DATABASE=Samsung Techwin Co., Ltd + +usb:v0839p0005* + ID_MODEL_FROM_DATABASE=Digimax Camera + +usb:v0839p0008* + ID_MODEL_FROM_DATABASE=Digimax 230 Camera + +usb:v0839p0009* + ID_MODEL_FROM_DATABASE=Digimax 340 + +usb:v0839p000A* + ID_MODEL_FROM_DATABASE=Digimax 410 + +usb:v0839p000E* + ID_MODEL_FROM_DATABASE=Digimax 360 + +usb:v0839p0010* + ID_MODEL_FROM_DATABASE=Digimax 300 + +usb:v0839p1003* + ID_MODEL_FROM_DATABASE=Digimax 210SE + +usb:v0839p1005* + ID_MODEL_FROM_DATABASE=Digimax 220 + +usb:v0839p1009* + ID_MODEL_FROM_DATABASE=Digimax V4 + +usb:v0839p1012* + ID_MODEL_FROM_DATABASE=6500 Document Camera + +usb:v0839p1058* + ID_MODEL_FROM_DATABASE=S730 Camera + +usb:v0839p1064* + ID_MODEL_FROM_DATABASE=Digimax D830 Camera + +usb:v0839p1542* + ID_MODEL_FROM_DATABASE=Digimax 50 Duo + +usb:v0839p3000* + ID_MODEL_FROM_DATABASE=Digimax 35 MP3 + +usb:v083A* + ID_VENDOR_FROM_DATABASE=Accton Technology Corp. + +usb:v083Ap1046* + ID_MODEL_FROM_DATABASE=10/100 Ethernet [pegasus] + +usb:v083Ap1060* + ID_MODEL_FROM_DATABASE=HomeLine Adapter + +usb:v083Ap1F4D* + ID_MODEL_FROM_DATABASE=SMC8013WG Broadband Remote NDIS Device + +usb:v083Ap3046* + ID_MODEL_FROM_DATABASE=10/100 Series Adapter + +usb:v083Ap3060* + ID_MODEL_FROM_DATABASE=1/10/100 Adapter + +usb:v083Ap3501* + ID_MODEL_FROM_DATABASE=2664W + +usb:v083Ap3502* + ID_MODEL_FROM_DATABASE=WN3501D Wireless Adapter + +usb:v083Ap3503* + ID_MODEL_FROM_DATABASE=T-Sinus 111 Wireless Adapter + +usb:v083Ap4501* + ID_MODEL_FROM_DATABASE=T-Sinus 154data + +usb:v083Ap4502* + ID_MODEL_FROM_DATABASE=Siemens S30853-S1016-R107 802.11g Wireless Adapter [Intersil ISL3886] + +usb:v083Ap4505* + ID_MODEL_FROM_DATABASE=SMCWUSB-G 802.11bg + +usb:v083Ap4507* + ID_MODEL_FROM_DATABASE=SMCWUSBT-G2 802.11g Wireless Adapter [Atheros AR5523] + +usb:v083Ap4521* + ID_MODEL_FROM_DATABASE=Siemens S30863-S1016-R107-2 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v083Ap5046* + ID_MODEL_FROM_DATABASE=SpeedStream 10/100 Ethernet [pegasus] + +usb:v083Ap5501* + ID_MODEL_FROM_DATABASE=Wireless Adapter 11g + +usb:v083Ap6500* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v083Ap6618* + ID_MODEL_FROM_DATABASE=802.11n Wireless Adapter + +usb:v083Ap7511* + ID_MODEL_FROM_DATABASE=Arcadyan 802.11N Wireless Adapter + +usb:v083Ap7512* + ID_MODEL_FROM_DATABASE=Arcadyan 802.11N Wireless Adapter + +usb:v083Ap7522* + ID_MODEL_FROM_DATABASE=Arcadyan 802.11N Wireless Adapter + +usb:v083Ap8522* + ID_MODEL_FROM_DATABASE=Arcadyan 802.11N Wireless Adapter + +usb:v083Ap8541* + ID_MODEL_FROM_DATABASE=WN4501F 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v083ApA512* + ID_MODEL_FROM_DATABASE=Arcadyan 802.11N Wireless Adapter + +usb:v083ApA618* + ID_MODEL_FROM_DATABASE=SMCWUSBS-N EZ Connect N Draft 11n Wireless Adapter [Ralink RT2870] + +usb:v083ApA701* + ID_MODEL_FROM_DATABASE=SMCWUSBS-N3 EZ Connect N Wireless Adapter [Ralink RT3070] + +usb:v083ApB004* + ID_MODEL_FROM_DATABASE=CPWUE001 USB/Ethernet Adapter + +usb:v083ApB522* + ID_MODEL_FROM_DATABASE=SMCWUSBS-N2 EZ Connect N Wireless Adapter [Ralink RT2870] + +usb:v083ApBB01* + ID_MODEL_FROM_DATABASE=BlueExpert Bluetooth Device + +usb:v083ApC003* + ID_MODEL_FROM_DATABASE=802.11b Wireless Adapter + +usb:v083ApC501* + ID_MODEL_FROM_DATABASE=Zoom 4410 Wireless-G [Intersil ISL3887] + +usb:v083ApC561* + ID_MODEL_FROM_DATABASE=802.11a/g Wireless Adapter + +usb:v083ApD522* + ID_MODEL_FROM_DATABASE=Speedport W 102 Stick IEEE 802.11n USB 2.0 Adapter + +usb:v083ApE501* + ID_MODEL_FROM_DATABASE=ZD1211B + +usb:v083ApE503* + ID_MODEL_FROM_DATABASE=Arcadyan WN4501 802.11b/g + +usb:v083ApE506* + ID_MODEL_FROM_DATABASE=WUS-201 802.11bg + +usb:v083ApF501* + ID_MODEL_FROM_DATABASE=802.11g Wireless Adapter + +usb:v083ApF502* + ID_MODEL_FROM_DATABASE=802.11g Wireless Adapter + +usb:v083ApF522* + ID_MODEL_FROM_DATABASE=Arcadyan WN7512 802.11n + +usb:v083F* + ID_VENDOR_FROM_DATABASE=Global Village + +usb:v083FpB100* + ID_MODEL_FROM_DATABASE=TelePort V.90 Fax/Modem + +usb:v0840* + ID_VENDOR_FROM_DATABASE=Argosy Research, Inc. + +usb:v0840p0060* + ID_MODEL_FROM_DATABASE=Storage Adapter Bridge Module + +usb:v0841* + ID_VENDOR_FROM_DATABASE=Rioport.com, Inc. + +usb:v0841p0001* + ID_MODEL_FROM_DATABASE=Rio 500 + +usb:v0844* + ID_VENDOR_FROM_DATABASE=Welland Industrial Co., Ltd + +usb:v0846* + ID_VENDOR_FROM_DATABASE=NetGear, Inc. + +usb:v0846p1001* + ID_MODEL_FROM_DATABASE=EA101 10 Mbps 10BASE-T Ethernet [Kawasaki LSI KL5KLUSB101B] + +usb:v0846p1002* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v0846p1020* + ID_MODEL_FROM_DATABASE=FA101 Fast Ethernet USB 1.1 + +usb:v0846p1040* + ID_MODEL_FROM_DATABASE=FA120 Fast Ethernet USB 2.0 [Asix AX88172 / AX8817x] + +usb:v0846p1100* + ID_MODEL_FROM_DATABASE=Managed Switch M4100 series, M5300 series, M7100 series + +usb:v0846p4110* + ID_MODEL_FROM_DATABASE=MA111(v1) 802.11b Wireless [Intersil Prism 3.0] + +usb:v0846p4200* + ID_MODEL_FROM_DATABASE=WG121(v1) 54 Mbps Wireless [Intersil ISL3886] + +usb:v0846p4210* + ID_MODEL_FROM_DATABASE=WG121(v2) 54 Mbps Wireless [Intersil ISL3886] + +usb:v0846p4220* + ID_MODEL_FROM_DATABASE=WG111(v1) 54 Mbps Wireless [Intersil ISL3886] + +usb:v0846p4230* + ID_MODEL_FROM_DATABASE=MA111(v2) 802.11b Wireless [SIS SIS 162] + +usb:v0846p4240* + ID_MODEL_FROM_DATABASE=WG111(v1) rev 2 54 Mbps Wireless [Intersil ISL3887] + +usb:v0846p4260* + ID_MODEL_FROM_DATABASE=WG111v3 54 Mbps Wireless [realtek RTL8187B] + +usb:v0846p4300* + ID_MODEL_FROM_DATABASE=WG111U Double 108 Mbps Wireless [Atheros AR5004X / AR5005UX] + +usb:v0846p4301* + ID_MODEL_FROM_DATABASE=WG111U (no firmware) Double 108 Mbps Wireless [Atheros AR5004X / AR5005UX] + +usb:v0846p5F00* + ID_MODEL_FROM_DATABASE=WPN111 802.11g Wireless Adapter [Atheros AR5523] + +usb:v0846p6A00* + ID_MODEL_FROM_DATABASE=WG111v2 54 Mbps Wireless [RealTek RTL8187L] + +usb:v0846p7100* + ID_MODEL_FROM_DATABASE=WN121T RangeMax Next Wireless-N [Marvell TopDog] + +usb:v0846p9000* + ID_MODEL_FROM_DATABASE=WN111(v1) RangeMax Next Wireless [Marvell 88W8362+88W8060] + +usb:v0846p9001* + ID_MODEL_FROM_DATABASE=WN111(v2) RangeMax Next Wireless [Atheros AR9170+AR9101] + +usb:v0846p9010* + ID_MODEL_FROM_DATABASE=WNDA3100v1 802.11abgn [Atheros AR9170+AR9104] + +usb:v0846p9011* + ID_MODEL_FROM_DATABASE=WNDA3100v2 802.11abgn [Broadcom BCM4323] + +usb:v0846p9012* + ID_MODEL_FROM_DATABASE=WNDA4100 802.11abgn 3x3:3 [Ralink RT3573] + +usb:v0846p9018* + ID_MODEL_FROM_DATABASE=WNDA3200 802.11abgn Wireless Adapter [Atheros AR7010+AR9280] + +usb:v0846p9020* + ID_MODEL_FROM_DATABASE=WNA3100(v1) Wireless-N 300 [Broadcom BCM43231] + +usb:v0846p9030* + ID_MODEL_FROM_DATABASE=WNA1100 Wireless-N 150 [Atheros AR9271] + +usb:v0846p9040* + ID_MODEL_FROM_DATABASE=WNA1000 Wireless-N 150 [Atheros AR9170+AR9101] + +usb:v0846p9041* + ID_MODEL_FROM_DATABASE=WNA1000M 802.11bgn [Realtek RTL8188CUS] + +usb:v0846pA001* + ID_MODEL_FROM_DATABASE=PA101 10 Mbps HPNA Home Phoneline RJ-1 + +usb:v084D* + ID_VENDOR_FROM_DATABASE=Minton Optic Industry Co., Inc. + +usb:v084Dp0001* + ID_MODEL_FROM_DATABASE=Jenoptik JD800i + +usb:v084Dp0003* + ID_MODEL_FROM_DATABASE=S-Cam F5/D-Link DSC-350 Digital Camera + +usb:v084Dp0011* + ID_MODEL_FROM_DATABASE=Argus DC3500 Digital Camera + +usb:v084Dp0014* + ID_MODEL_FROM_DATABASE=Praktica DC 32 + +usb:v084Dp0019* + ID_MODEL_FROM_DATABASE=Praktica DPix3000 + +usb:v084Dp0025* + ID_MODEL_FROM_DATABASE=Praktica DC 60 + +usb:v084Dp1001* + ID_MODEL_FROM_DATABASE=ScanHex SX-35d + +usb:v084E* + ID_VENDOR_FROM_DATABASE=KB Gear + +usb:v084Ep0001* + ID_MODEL_FROM_DATABASE=JamCam Camera + +usb:v084Ep1001* + ID_MODEL_FROM_DATABASE=Jam Studio Tablet + +usb:v084Ep1002* + ID_MODEL_FROM_DATABASE=Pablo Tablet + +usb:v084F* + ID_VENDOR_FROM_DATABASE=Empeg + +usb:v084Fp0001* + ID_MODEL_FROM_DATABASE=Empeg-Car Mark I/II Player + +usb:v0850* + ID_VENDOR_FROM_DATABASE=Fast Point Technologies, Inc. + +usb:v0851* + ID_VENDOR_FROM_DATABASE=Macronix International Co., Ltd + +usb:v0851p1542* + ID_MODEL_FROM_DATABASE=SiPix Blink + +usb:v0851p1543* + ID_MODEL_FROM_DATABASE=Maxell WS30 Slim Digital Camera, or Pandigital PI8004W01 digital photo frame + +usb:v0851pA168* + ID_MODEL_FROM_DATABASE=MXIC + +usb:v0852* + ID_VENDOR_FROM_DATABASE=CSEM + +usb:v0853* + ID_VENDOR_FROM_DATABASE=Topre Corporation + +usb:v0853p0100* + ID_MODEL_FROM_DATABASE=HHKB Professional + +usb:v0854* + ID_VENDOR_FROM_DATABASE=ActiveWire, Inc. + +usb:v0854p0100* + ID_MODEL_FROM_DATABASE=I/O Board + +usb:v0854p0101* + ID_MODEL_FROM_DATABASE=I/O Board, rev1 + +usb:v0856* + ID_VENDOR_FROM_DATABASE=B&B Electronics + +usb:v0856pAC01* + ID_MODEL_FROM_DATABASE=uLinks USOTL4 RS422/485 Adapter + +usb:v0858* + ID_VENDOR_FROM_DATABASE=Hitachi Maxell, Ltd + +usb:v0858p3102* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0858pFFFF* + ID_MODEL_FROM_DATABASE=Maxell module with BlueCore in DFU mode + +usb:v0859* + ID_VENDOR_FROM_DATABASE=Minolta Systems Laboratory, Inc. + +usb:v085A* + ID_VENDOR_FROM_DATABASE=Xircom + +usb:v085Ap0001* + ID_MODEL_FROM_DATABASE=Portstation Dual Serial Port + +usb:v085Ap0003* + ID_MODEL_FROM_DATABASE=Portstation Paraller Port + +usb:v085Ap0008* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v085Ap0009* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v085Ap000B* + ID_MODEL_FROM_DATABASE=Portstation Dual PS/2 Port + +usb:v085Ap0021* + ID_MODEL_FROM_DATABASE=1 port to Serial Converter + +usb:v085Ap0022* + ID_MODEL_FROM_DATABASE=Parallel Port + +usb:v085Ap0023* + ID_MODEL_FROM_DATABASE=2 port to Serial Converter + +usb:v085Ap0024* + ID_MODEL_FROM_DATABASE=Parallel Port + +usb:v085Ap0027* + ID_MODEL_FROM_DATABASE=1 port to Serial Converter + +usb:v085Ap0028* + ID_MODEL_FROM_DATABASE=PortGear to SCSI Converter + +usb:v085Ap0032* + ID_MODEL_FROM_DATABASE=PortStation SCSI Module + +usb:v085Ap003C* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v085Ap0299* + ID_MODEL_FROM_DATABASE=Colorvision, Inc. Monitor Spyder + +usb:v085Ap8021* + ID_MODEL_FROM_DATABASE=1 port to Serial + +usb:v085Ap8023* + ID_MODEL_FROM_DATABASE=2 port to Serial + +usb:v085Ap8027* + ID_MODEL_FROM_DATABASE=PGSDB9 Serial Port + +usb:v085C* + ID_VENDOR_FROM_DATABASE=ColorVision, Inc. + +usb:v085Cp0200* + ID_MODEL_FROM_DATABASE=Monitor Spyder + +usb:v0862* + ID_VENDOR_FROM_DATABASE=Teletrol Systems, Inc. + +usb:v0863* + ID_VENDOR_FROM_DATABASE=Filanet Corp. + +usb:v0864* + ID_VENDOR_FROM_DATABASE=NetGear, Inc. + +usb:v0864p4100* + ID_MODEL_FROM_DATABASE=MA101 802.11b Adapter + +usb:v0864p4102* + ID_MODEL_FROM_DATABASE=MA101 802.11b Adapter + +usb:v0867* + ID_VENDOR_FROM_DATABASE=Data Translation, Inc. + +usb:v0867p9812* + ID_MODEL_FROM_DATABASE=ECON Data acquisition unit + +usb:v0867p9816* + ID_MODEL_FROM_DATABASE=DT9816 ECON data acquisition module + +usb:v0867p9836* + ID_MODEL_FROM_DATABASE=DT9836 data acquisition card + +usb:v086A* + ID_VENDOR_FROM_DATABASE=Emagic Soft- und Hardware GmbH + +usb:v086Ap0001* + ID_MODEL_FROM_DATABASE=Unitor8 + +usb:v086Ap0002* + ID_MODEL_FROM_DATABASE=AMT8 + +usb:v086Ap0003* + ID_MODEL_FROM_DATABASE=MT4 + +usb:v086C* + ID_VENDOR_FROM_DATABASE=DeTeWe - Deutsche Telephonwerke AG & Co. + +usb:v086Cp1001* + ID_MODEL_FROM_DATABASE=Eumex 504PC ISDN TA + +usb:v086Cp1002* + ID_MODEL_FROM_DATABASE=Eumex 504PC (FlashLoad) + +usb:v086Cp1003* + ID_MODEL_FROM_DATABASE=TA33 ISDN TA + +usb:v086Cp1004* + ID_MODEL_FROM_DATABASE=TA33 (FlashLoad) + +usb:v086Cp1005* + ID_MODEL_FROM_DATABASE=Eumex 604PC HomeNet + +usb:v086Cp1006* + ID_MODEL_FROM_DATABASE=Eumex 604PC HomeNet (FlashLoad) + +usb:v086Cp1007* + ID_MODEL_FROM_DATABASE=Eumex 704PC DSL + +usb:v086Cp1008* + ID_MODEL_FROM_DATABASE=Eumex 704PC DSL (FlashLoad) + +usb:v086Cp1009* + ID_MODEL_FROM_DATABASE=Eumex 724PC DSL + +usb:v086Cp100A* + ID_MODEL_FROM_DATABASE=Eumex 724PC DSL (FlashLoad) + +usb:v086Cp100B* + ID_MODEL_FROM_DATABASE=OpenCom 30 + +usb:v086Cp100C* + ID_MODEL_FROM_DATABASE=OpenCom 30 (FlashLoad) + +usb:v086Cp100D* + ID_MODEL_FROM_DATABASE=BeeTel Home 100 + +usb:v086Cp100E* + ID_MODEL_FROM_DATABASE=BeeTel Home 100 (FlashLoad) + +usb:v086Cp1011* + ID_MODEL_FROM_DATABASE=USB2DECT + +usb:v086Cp1012* + ID_MODEL_FROM_DATABASE=USB2DECT (FlashLoad) + +usb:v086Cp1013* + ID_MODEL_FROM_DATABASE=Eumex 704PC LAN + +usb:v086Cp1014* + ID_MODEL_FROM_DATABASE=Eumex 704PC LAN (FlashLoad) + +usb:v086Cp1019* + ID_MODEL_FROM_DATABASE=Eumex 504 SE + +usb:v086Cp101A* + ID_MODEL_FROM_DATABASE=Eumex 504 SE (Flash-Mode) + +usb:v086Cp1021* + ID_MODEL_FROM_DATABASE=OpenCom 40 + +usb:v086Cp1022* + ID_MODEL_FROM_DATABASE=OpenCom 40 (FlashLoad) + +usb:v086Cp1023* + ID_MODEL_FROM_DATABASE=OpenCom 45 + +usb:v086Cp1024* + ID_MODEL_FROM_DATABASE=OpenCom 45 (FlashLoad) + +usb:v086Cp1025* + ID_MODEL_FROM_DATABASE=Sinus 61 data + +usb:v086Cp1029* + ID_MODEL_FROM_DATABASE=dect BOX + +usb:v086Cp102C* + ID_MODEL_FROM_DATABASE=Eumex 604PC HomeNet [FlashLoad] + +usb:v086Cp1030* + ID_MODEL_FROM_DATABASE=Eumex 704PC DSL [FlashLoad] + +usb:v086Cp1032* + ID_MODEL_FROM_DATABASE=OpenCom 40 [FlashLoad] + +usb:v086Cp1033* + ID_MODEL_FROM_DATABASE=OpenCom 30 plus + +usb:v086Cp1034* + ID_MODEL_FROM_DATABASE=OpenCom 30 plus (FlashLoad) + +usb:v086Cp1041* + ID_MODEL_FROM_DATABASE=Eumex 220PC + +usb:v086Cp1042* + ID_MODEL_FROM_DATABASE=Eumex 220PC (FlashMode) + +usb:v086Cp1055* + ID_MODEL_FROM_DATABASE=Eumex 220 Version 2 ISDN TA + +usb:v086Cp1056* + ID_MODEL_FROM_DATABASE=Eumex 220 Version 2 ISDN TA (Flash-Mode) + +usb:v086Cp2000* + ID_MODEL_FROM_DATABASE=OpenCom 1000 + +usb:v086E* + ID_VENDOR_FROM_DATABASE=System TALKS, Inc. + +usb:v086Ep1920* + ID_MODEL_FROM_DATABASE=SGC-X2UL + +usb:v086F* + ID_VENDOR_FROM_DATABASE=MEC IMEX, Inc. + +usb:v0870* + ID_VENDOR_FROM_DATABASE=Metricom + +usb:v0870p0001* + ID_MODEL_FROM_DATABASE=Ricochet GS + +usb:v0871* + ID_VENDOR_FROM_DATABASE=SanDisk, Inc. + +usb:v0871p0001* + ID_MODEL_FROM_DATABASE=SDDR-01 Compact Flash Reader + +usb:v0871p0002* + ID_MODEL_FROM_DATABASE=SDDR-31 Compact Flash Reader + +usb:v0871p0005* + ID_MODEL_FROM_DATABASE=SDDR-05 Compact Flash Reader + +usb:v0873* + ID_VENDOR_FROM_DATABASE=Xpeed, Inc. + +usb:v0874* + ID_VENDOR_FROM_DATABASE=A-Tec Subsystem, Inc. + +usb:v0879* + ID_VENDOR_FROM_DATABASE=Comtrol Corp. + +usb:v087C* + ID_VENDOR_FROM_DATABASE=Adesso/Kbtek America, Inc. + +usb:v087D* + ID_VENDOR_FROM_DATABASE=Jaton Corp. + +usb:v087Dp5704* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v087E* + ID_VENDOR_FROM_DATABASE=Fujitsu Computer Products of America + +usb:v087F* + ID_VENDOR_FROM_DATABASE=QualCore Logic Inc. + +usb:v0880* + ID_VENDOR_FROM_DATABASE=APT Technologies, Inc. + +usb:v0883* + ID_VENDOR_FROM_DATABASE=Recording Industry Association of America (RIAA) + +usb:v0885* + ID_VENDOR_FROM_DATABASE=Boca Research, Inc. + +usb:v0886* + ID_VENDOR_FROM_DATABASE=XAC Automation Corp. + +usb:v0886p0630* + ID_MODEL_FROM_DATABASE=Intel PC Camera CS630 + +usb:v0887* + ID_VENDOR_FROM_DATABASE=Hannstar Electronics Corp. + +usb:v088A* + ID_VENDOR_FROM_DATABASE=TechTools + +usb:v088Ap1002* + ID_MODEL_FROM_DATABASE=DigiView DV3100 + +usb:v088B* + ID_VENDOR_FROM_DATABASE=MassWorks, Inc. + +usb:v088Bp4944* + ID_MODEL_FROM_DATABASE=MassWorks ID-75 TouchScreen + +usb:v088C* + ID_VENDOR_FROM_DATABASE=Swecoin AB + +usb:v088Cp2030* + ID_MODEL_FROM_DATABASE=Ticket Printer TTP 2030 + +usb:v088E* + ID_VENDOR_FROM_DATABASE=iLok + +usb:v088Ep5036* + ID_MODEL_FROM_DATABASE=Portable secure storage for software licenses + +usb:v0892* + ID_VENDOR_FROM_DATABASE=DioGraphy, Inc. + +usb:v0892p0101* + ID_MODEL_FROM_DATABASE=Smartdio Reader/Writer + +usb:v0897* + ID_VENDOR_FROM_DATABASE=Lauterbach + +usb:v0897p0002* + ID_MODEL_FROM_DATABASE=Power Debug/Power Debug II + +usb:v089C* + ID_VENDOR_FROM_DATABASE=United Technologies Research Cntr. + +usb:v089D* + ID_VENDOR_FROM_DATABASE=Icron Technologies Corp. + +usb:v089E* + ID_VENDOR_FROM_DATABASE=NST Co., Ltd + +usb:v089F* + ID_VENDOR_FROM_DATABASE=Primex Aerospace Co. + +usb:v08A5* + ID_VENDOR_FROM_DATABASE=e9, Inc. + +usb:v08A6* + ID_VENDOR_FROM_DATABASE=Toshiba TEC + +usb:v08A6p0051* + ID_MODEL_FROM_DATABASE=B-SV4 + +usb:v08A8* + ID_VENDOR_FROM_DATABASE=Andrea Electronics + +usb:v08A9* + ID_VENDOR_FROM_DATABASE=CWAV Inc. + +usb:v08A9p0005* + ID_MODEL_FROM_DATABASE=USBee ZX + +usb:v08A9p0009* + ID_MODEL_FROM_DATABASE=USBee SX + +usb:v08A9p0012* + ID_MODEL_FROM_DATABASE=USBee AX-Standard + +usb:v08A9p0013* + ID_MODEL_FROM_DATABASE=USBee AX-Plus + +usb:v08A9p0014* + ID_MODEL_FROM_DATABASE=USBee AX-Pro + +usb:v08A9p0015* + ID_MODEL_FROM_DATABASE=USBee DX + +usb:v08AE* + ID_VENDOR_FROM_DATABASE=Macally (Mace Group, Inc.) + +usb:v08B4* + ID_VENDOR_FROM_DATABASE=Sorenson Vision, Inc. + +usb:v08B7* + ID_VENDOR_FROM_DATABASE=NATSU + +usb:v08B7p0001* + ID_MODEL_FROM_DATABASE=Playstation adapter + +usb:v08B8* + ID_VENDOR_FROM_DATABASE=J. Gordon Electronic Design, Inc. + +usb:v08B8p01F4* + ID_MODEL_FROM_DATABASE=USBSIMM1 + +usb:v08B9* + ID_VENDOR_FROM_DATABASE=RadioShack Corp. (Tandy) + +usb:v08BB* + ID_VENDOR_FROM_DATABASE=Texas Instruments + +usb:v08BBp2702* + ID_MODEL_FROM_DATABASE=Speakers + +usb:v08BBp2704* + ID_MODEL_FROM_DATABASE=Audio Codec + +usb:v08BBp2706* + ID_MODEL_FROM_DATABASE=PCM2706 Audio Codec + +usb:v08BBp2900* + ID_MODEL_FROM_DATABASE=PCM2900 Audio Codec + +usb:v08BBp2901* + ID_MODEL_FROM_DATABASE=PCM2901 Audio Codec + +usb:v08BBp2902* + ID_MODEL_FROM_DATABASE=PCM2902 Audio Codec + +usb:v08BBp2904* + ID_MODEL_FROM_DATABASE=PCM2904 Audio Codec + +usb:v08BBp2910* + ID_MODEL_FROM_DATABASE=PCM2912 Audio Codec + +usb:v08BBp29B0* + ID_MODEL_FROM_DATABASE=PCM2900B Audio CODEC + +usb:v08BBp29B2* + ID_MODEL_FROM_DATABASE=PCM2902 Audio CODEC + +usb:v08BBp29B3* + ID_MODEL_FROM_DATABASE=PCM2903B Audio CODEC + +usb:v08BBp29B6* + ID_MODEL_FROM_DATABASE=PCM2906B Audio CODEC + +usb:v08BBp29C0* + ID_MODEL_FROM_DATABASE=PCM2900C Audio CODEC + +usb:v08BBp29C2* + ID_MODEL_FROM_DATABASE=PCM2902C Audio CODEC + +usb:v08BBp29C3* + ID_MODEL_FROM_DATABASE=PCM2903C Audio CODEC + +usb:v08BBp29C6* + ID_MODEL_FROM_DATABASE=PCM2906C Audio CODEC + +usb:v08BD* + ID_VENDOR_FROM_DATABASE=Citizen Watch Co., Ltd + +usb:v08BDp0208* + ID_MODEL_FROM_DATABASE=CLP-521 Label Printer + +usb:v08BDp1100* + ID_MODEL_FROM_DATABASE=X1-USB Floppy + +usb:v08C3* + ID_VENDOR_FROM_DATABASE=Precise Biometrics + +usb:v08C3p0001* + ID_MODEL_FROM_DATABASE=100 SC + +usb:v08C3p0002* + ID_MODEL_FROM_DATABASE=100 A + +usb:v08C3p0003* + ID_MODEL_FROM_DATABASE=100 SC BioKeyboard + +usb:v08C3p0006* + ID_MODEL_FROM_DATABASE=100 A BioKeyboard + +usb:v08C3p0100* + ID_MODEL_FROM_DATABASE=100 MC ISP + +usb:v08C3p0101* + ID_MODEL_FROM_DATABASE=100 MC FingerPrint and SmartCard Reader + +usb:v08C3p0300* + ID_MODEL_FROM_DATABASE=100 AX + +usb:v08C3p0400* + ID_MODEL_FROM_DATABASE=100 SC + +usb:v08C3p0401* + ID_MODEL_FROM_DATABASE=150 MC + +usb:v08C3p0402* + ID_MODEL_FROM_DATABASE=200 MC FingerPrint and SmartCard Reader + +usb:v08C3p0404* + ID_MODEL_FROM_DATABASE=100 SC Upgrade + +usb:v08C3p0405* + ID_MODEL_FROM_DATABASE=150 MC Upgrade + +usb:v08C3p0406* + ID_MODEL_FROM_DATABASE=100 MC Upgrade + +usb:v08C4* + ID_VENDOR_FROM_DATABASE=Proxim, Inc. + +usb:v08C4p0100* + ID_MODEL_FROM_DATABASE=Skyline 802.11b Wireless Adapter + +usb:v08C4p02F2* + ID_MODEL_FROM_DATABASE=Farallon Home Phoneline Adapter + +usb:v08C7* + ID_VENDOR_FROM_DATABASE=Key Nice Enterprise Co., Ltd + +usb:v08C8* + ID_VENDOR_FROM_DATABASE=2Wire, Inc. + +usb:v08C9* + ID_VENDOR_FROM_DATABASE=Nippon Telegraph and Telephone Corp. + +usb:v08CA* + ID_VENDOR_FROM_DATABASE=Aiptek International, Inc. + +usb:v08CAp0001* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v08CAp0010* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v08CAp0020* + ID_MODEL_FROM_DATABASE=APT-6000U Tablet + +usb:v08CAp0021* + ID_MODEL_FROM_DATABASE=APT-2 Tablet + +usb:v08CAp0022* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v08CAp0023* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v08CAp0024* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v08CAp0100* + ID_MODEL_FROM_DATABASE=Pen Drive + +usb:v08CAp0102* + ID_MODEL_FROM_DATABASE=DualCam + +usb:v08CAp0103* + ID_MODEL_FROM_DATABASE=Pocket DV Digital Camera + +usb:v08CAp0104* + ID_MODEL_FROM_DATABASE=Pocket DVII + +usb:v08CAp0105* + ID_MODEL_FROM_DATABASE=Mega DV(Disk) + +usb:v08CAp0106* + ID_MODEL_FROM_DATABASE=Pocket DV3100+ + +usb:v08CAp0107* + ID_MODEL_FROM_DATABASE=Pocket DV3100 + +usb:v08CAp0109* + ID_MODEL_FROM_DATABASE=Nisis DV4 Digital Camera + +usb:v08CAp010A* + ID_MODEL_FROM_DATABASE=Trust 738AV LCD PV Mass Storage + +usb:v08CAp0111* + ID_MODEL_FROM_DATABASE=PenCam VGA Plus + +usb:v08CAp2008* + ID_MODEL_FROM_DATABASE=Mini PenCam 2 + +usb:v08CAp2010* + ID_MODEL_FROM_DATABASE=Pocket CAM 3 Mega (webcam) + +usb:v08CAp2011* + ID_MODEL_FROM_DATABASE=Pocket CAM 3 Mega (storage) + +usb:v08CAp2016* + ID_MODEL_FROM_DATABASE=PocketCam 2 Mega + +usb:v08CAp2018* + ID_MODEL_FROM_DATABASE=Pencam SD 2M + +usb:v08CAp2020* + ID_MODEL_FROM_DATABASE=Slim 3000F + +usb:v08CAp2022* + ID_MODEL_FROM_DATABASE=Slim 3200 + +usb:v08CAp2024* + ID_MODEL_FROM_DATABASE=Pocket DV3500 + +usb:v08CAp2028* + ID_MODEL_FROM_DATABASE=Pocket Cam4M + +usb:v08CAp2040* + ID_MODEL_FROM_DATABASE=Pocket DV4100M + +usb:v08CAp2042* + ID_MODEL_FROM_DATABASE=Pocket DV5100M Composite Device + +usb:v08CAp2043* + ID_MODEL_FROM_DATABASE=Pocket DV5100M (Disk) + +usb:v08CAp2060* + ID_MODEL_FROM_DATABASE=Pocket DV5300 + +usb:v08CD* + ID_VENDOR_FROM_DATABASE=Jue Hsun Ind. Corp. + +usb:v08CE* + ID_VENDOR_FROM_DATABASE=Long Well Electronics Corp. + +usb:v08CF* + ID_VENDOR_FROM_DATABASE=Productivity Enhancement Products + +usb:v08D1* + ID_VENDOR_FROM_DATABASE=smartBridges, Inc. + +usb:v08D1p0001* + ID_MODEL_FROM_DATABASE=smartNIC Ethernet [catc] + +usb:v08D1p0003* + ID_MODEL_FROM_DATABASE=smartNIC 2 PnP Ethernet + +usb:v08D3* + ID_VENDOR_FROM_DATABASE=Virtual Ink + +usb:v08D4* + ID_VENDOR_FROM_DATABASE=Fujitsu Siemens Computers + +usb:v08D4p0009* + ID_MODEL_FROM_DATABASE=SCR SmartCard Reader + +usb:v08D8* + ID_VENDOR_FROM_DATABASE=IXXAT Automation GmbH + +usb:v08D8p0002* + ID_MODEL_FROM_DATABASE=USB-to-CAN compact + +usb:v08D8p0003* + ID_MODEL_FROM_DATABASE=USB-to-CAN II + +usb:v08D8p0100* + ID_MODEL_FROM_DATABASE=USB-to-CAN + +usb:v08D9* + ID_VENDOR_FROM_DATABASE=Increment P Corp. + +usb:v08DD* + ID_VENDOR_FROM_DATABASE=Billionton Systems, Inc. + +usb:v08DDp0112* + ID_MODEL_FROM_DATABASE=Wireless LAN Adapter + +usb:v08DDp0113* + ID_MODEL_FROM_DATABASE=Wireless LAN Adapter + +usb:v08DDp0986* + ID_MODEL_FROM_DATABASE=USB-100N Ethernet [pegasus] + +usb:v08DDp0987* + ID_MODEL_FROM_DATABASE=USBLP-100 HomePNA Ethernet [pegasus] + +usb:v08DDp0988* + ID_MODEL_FROM_DATABASE=USBEL-100 Ethernet [pegasus] + +usb:v08DDp1986* + ID_MODEL_FROM_DATABASE=10/100 LAN Adapter + +usb:v08DDp2103* + ID_MODEL_FROM_DATABASE=DVB-T TV-Tuner Card-R + +usb:v08DDp8511* + ID_MODEL_FROM_DATABASE=USBE-100 Ethernet [pegasus2] + +usb:v08DDp90FF* + ID_MODEL_FROM_DATABASE=USB2AR Ethernet + +usb:v08DE* + ID_VENDOR_FROM_DATABASE=??? + +usb:v08DEp7A01* + ID_MODEL_FROM_DATABASE=802.11b Adapter + +usb:v08DF* + ID_VENDOR_FROM_DATABASE=Spyrus, Inc. + +usb:v08DFp0001* + ID_MODEL_FROM_DATABASE=Rosetta Token V1 + +usb:v08DFp0002* + ID_MODEL_FROM_DATABASE=Rosetta Token V2 + +usb:v08DFp0003* + ID_MODEL_FROM_DATABASE=Rosetta Token V3 + +usb:v08DFp0A00* + ID_MODEL_FROM_DATABASE=Lynks Interface + +usb:v08E3* + ID_VENDOR_FROM_DATABASE=Olitec, Inc. + +usb:v08E3p0002* + ID_MODEL_FROM_DATABASE=USB-RS232 Bridge + +usb:v08E3p0100* + ID_MODEL_FROM_DATABASE=Interface ADSL + +usb:v08E3p0101* + ID_MODEL_FROM_DATABASE=Interface ADSL + +usb:v08E3p0102* + ID_MODEL_FROM_DATABASE=ADSL + +usb:v08E3p0301* + ID_MODEL_FROM_DATABASE=RNIS + +usb:v08E4* + ID_VENDOR_FROM_DATABASE=Pioneer Corp. + +usb:v08E5* + ID_VENDOR_FROM_DATABASE=Litronic + +usb:v08E6* + ID_VENDOR_FROM_DATABASE=Gemalto (was Gemplus) + +usb:v08E6p0001* + ID_MODEL_FROM_DATABASE=GemPC-Touch 430 + +usb:v08E6p0430* + ID_MODEL_FROM_DATABASE=GemPC430 SmartCard Reader + +usb:v08E6p0432* + ID_MODEL_FROM_DATABASE=GemPC432 SmartCard Reader + +usb:v08E6p0435* + ID_MODEL_FROM_DATABASE=GemPC435 SmartCard Reader + +usb:v08E6p0437* + ID_MODEL_FROM_DATABASE=GemPC433 SL SmartCard Reader + +usb:v08E6p1359* + ID_MODEL_FROM_DATABASE=UA SECURE STORAGE TOKEN + +usb:v08E6p2202* + ID_MODEL_FROM_DATABASE=Gem e-Seal Pro Token + +usb:v08E6p3437* + ID_MODEL_FROM_DATABASE=GemPC Twin SmartCard Reader + +usb:v08E6p3438* + ID_MODEL_FROM_DATABASE=GemPC Key SmartCard Reader + +usb:v08E6p3478* + ID_MODEL_FROM_DATABASE=PinPad Smart Card Reader + +usb:v08E6p34EC* + ID_MODEL_FROM_DATABASE=Compact Smart Card Reader Writer + +usb:v08E6p4433* + ID_MODEL_FROM_DATABASE=GemPC433-Swap + +usb:v08E6p5501* + ID_MODEL_FROM_DATABASE=GemProx-PU Contactless Smart Card Reader + +usb:v08E6p5503* + ID_MODEL_FROM_DATABASE=Prox-DU Contactless Interface + +usb:v08E6pACE0* + ID_MODEL_FROM_DATABASE=UA HYBRID TOKEN + +usb:v08E7* + ID_VENDOR_FROM_DATABASE=Pan-International Wire & Cable + +usb:v08E8* + ID_VENDOR_FROM_DATABASE=Integrated Memory Logic + +usb:v08E9* + ID_VENDOR_FROM_DATABASE=Extended Systems, Inc. + +usb:v08E9p0100* + ID_MODEL_FROM_DATABASE=XTNDAccess IrDA Dongle + +usb:v08EA* + ID_VENDOR_FROM_DATABASE=Ericsson, Inc., Blue Ridge Labs + +usb:v08EAp00C9* + ID_MODEL_FROM_DATABASE=ADSL Modem HM120dp Loader + +usb:v08EAp00CA* + ID_MODEL_FROM_DATABASE=ADSL WAN Modem HM120dp + +usb:v08EAp00CE* + ID_MODEL_FROM_DATABASE=HM230d Virtual Bus for Helium + +usb:v08EApABBA* + ID_MODEL_FROM_DATABASE=USB Driver for Bluetooth Wireless Technology + +usb:v08EApABBB* + ID_MODEL_FROM_DATABASE=Bluetooth Device in DFU State + +usb:v08EC* + ID_VENDOR_FROM_DATABASE=M-Systems Flash Disk Pioneers + +usb:v08ECp0001* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0002* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0005* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0008* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0010* + ID_MODEL_FROM_DATABASE=DiskOnKey + +usb:v08ECp0011* + ID_MODEL_FROM_DATABASE=DiskOnKey + +usb:v08ECp0012* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0014* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0015* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler ELITE + +usb:v08ECp0016* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler U3 + +usb:v08ECp0020* + ID_MODEL_FROM_DATABASE=TravelDrive Intuix U3 2GB + +usb:v08ECp0021* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0022* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0023* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0024* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0025* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0026* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0027* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0028* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0029* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0030* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp0822* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp0832* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v08ECp0834* + ID_MODEL_FROM_DATABASE=M-Disk 220 + +usb:v08ECp0998* + ID_MODEL_FROM_DATABASE=Kingston Data Traveler2.0 Disk Driver + +usb:v08ECp0999* + ID_MODEL_FROM_DATABASE=Kingston Data Traveler2.0 Disk Driver + +usb:v08ECp1000* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp2000* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v08ECp2038* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp2039* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp204A* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ECp204B* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v08ED* + ID_VENDOR_FROM_DATABASE=MediaTek Inc. + +usb:v08EDp0002* + ID_MODEL_FROM_DATABASE=CECT M800 memory card + +usb:v08EE* + ID_VENDOR_FROM_DATABASE=CCSI/Hesso + +usb:v08F0* + ID_VENDOR_FROM_DATABASE=Corex Technologies + +usb:v08F1* + ID_VENDOR_FROM_DATABASE=CTI Electronics Corp. + +usb:v08F2* + ID_VENDOR_FROM_DATABASE=Gotop Information Inc. + +usb:v08F2p007F* + ID_MODEL_FROM_DATABASE=Super Q2 Tablet + +usb:v08F5* + ID_VENDOR_FROM_DATABASE=SysTec Co., Ltd + +usb:v08F6* + ID_VENDOR_FROM_DATABASE=Logic 3 International, Ltd + +usb:v08F7* + ID_VENDOR_FROM_DATABASE=Vernier + +usb:v08F7p0001* + ID_MODEL_FROM_DATABASE=LabPro + +usb:v08F7p0002* + ID_MODEL_FROM_DATABASE=EasyTemp/Go!Temp + +usb:v08F7p0003* + ID_MODEL_FROM_DATABASE=Go!Link + +usb:v08F7p0004* + ID_MODEL_FROM_DATABASE=Go!Motion + +usb:v08F8* + ID_VENDOR_FROM_DATABASE=Keen Top International Enterprise Co., Ltd + +usb:v08F9* + ID_VENDOR_FROM_DATABASE=Wipro Technologies + +usb:v08FA* + ID_VENDOR_FROM_DATABASE=Caere + +usb:v08FB* + ID_VENDOR_FROM_DATABASE=Socket Communications + +usb:v08FC* + ID_VENDOR_FROM_DATABASE=Sicon Cable Technology Co., Ltd + +usb:v08FD* + ID_VENDOR_FROM_DATABASE=Digianswer A/S + +usb:v08FDp0001* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v08FF* + ID_VENDOR_FROM_DATABASE=AuthenTec, Inc. + +usb:v08FFp1600* + ID_MODEL_FROM_DATABASE=AES1600 + +usb:v08FFp1610* + ID_MODEL_FROM_DATABASE=AES1600 + +usb:v08FFp1660* + ID_MODEL_FROM_DATABASE=AES1660 Fingerprint Sensor + +usb:v08FFp1680* + ID_MODEL_FROM_DATABASE=AES1660 Fingerprint Sensor + +usb:v08FFp168F* + ID_MODEL_FROM_DATABASE=AES1660 Fingerprint Sensor + +usb:v08FFp2500* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2501* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2502* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2503* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2504* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2505* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2506* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2507* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2508* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2509* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250A* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250B* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250C* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250D* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250E* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp250F* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2510* + ID_MODEL_FROM_DATABASE=AES2510 + +usb:v08FFp2550* + ID_MODEL_FROM_DATABASE=AES2550 Fingerprint Sensor + +usb:v08FFp2580* + ID_MODEL_FROM_DATABASE=AES2501 Fingerprint Sensor + +usb:v08FFp2588* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2589* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258A* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258B* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258C* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258D* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258E* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp258F* + ID_MODEL_FROM_DATABASE=AES2501 + +usb:v08FFp2660* + ID_MODEL_FROM_DATABASE=AES2660 Fingerprint Sensor + +usb:v08FFp2680* + ID_MODEL_FROM_DATABASE=AES2660 Fingerprint Sensor + +usb:v08FFp268F* + ID_MODEL_FROM_DATABASE=AES2660 Fingerprint Sensor + +usb:v08FFp2810* + ID_MODEL_FROM_DATABASE=AES2810 + +usb:v08FFp3400* + ID_MODEL_FROM_DATABASE=AES3400 TruePrint Sensor + +usb:v08FFp3401* + ID_MODEL_FROM_DATABASE=AES3400 Sensor + +usb:v08FFp3402* + ID_MODEL_FROM_DATABASE=AES3400 Sensor + +usb:v08FFp3403* + ID_MODEL_FROM_DATABASE=AES3400 Sensor + +usb:v08FFp3404* + ID_MODEL_FROM_DATABASE=AES3400 TruePrint Sensor + +usb:v08FFp3405* + ID_MODEL_FROM_DATABASE=AES3400 TruePrint Sensor + +usb:v08FFp3406* + ID_MODEL_FROM_DATABASE=AES3400 TruePrint Sensor + +usb:v08FFp3407* + ID_MODEL_FROM_DATABASE=AES3400 TruePrint Sensor + +usb:v08FFp4902* + ID_MODEL_FROM_DATABASE=BioMV with TruePrint AES3500 + +usb:v08FFp4903* + ID_MODEL_FROM_DATABASE=BioMV with TruePrint AES3400 + +usb:v08FFp5500* + ID_MODEL_FROM_DATABASE=AES4000 + +usb:v08FFp5501* + ID_MODEL_FROM_DATABASE=AES4000 TruePrint Sensor + +usb:v08FFp5503* + ID_MODEL_FROM_DATABASE=AES4000 TruePrint Sensor + +usb:v08FFp5505* + ID_MODEL_FROM_DATABASE=AES4000 TruePrint Sensor + +usb:v08FFp5507* + ID_MODEL_FROM_DATABASE=AES4000 TruePrint Sensor + +usb:v08FFp55FF* + ID_MODEL_FROM_DATABASE=AES4000 TruePrint Sensor. + +usb:v08FFp5700* + ID_MODEL_FROM_DATABASE=AES3500 Fingerprint Reader + +usb:v08FFp5701* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5702* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5703* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5704* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5705* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5706* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5707* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5710* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5711* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5712* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5713* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5714* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5715* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5716* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5717* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5730* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5731* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5732* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5733* + ID_MODEL_FROM_DATABASE=AES3500 TruePrint Sensor + +usb:v08FFp5734* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5735* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5736* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFp5737* + ID_MODEL_FROM_DATABASE=AES3500-BZ TruePrint Sensor + +usb:v08FFpAFE3* + ID_MODEL_FROM_DATABASE=FingerLoc Sensor Module (Anchor) + +usb:v08FFpAFE4* + ID_MODEL_FROM_DATABASE=FingerLoc Sensor Module (Anchor) + +usb:v08FFpAFE5* + ID_MODEL_FROM_DATABASE=FingerLoc Sensor Module (Anchor) + +usb:v08FFpAFE6* + ID_MODEL_FROM_DATABASE=FingerLoc Sensor Module (Anchor) + +usb:v08FFpFFFD* + ID_MODEL_FROM_DATABASE=AES2510 Sensor (USB Emulator) + +usb:v08FFpFFFF* + ID_MODEL_FROM_DATABASE=Sensor (Emulator) + +usb:v0900* + ID_VENDOR_FROM_DATABASE=Pinnacle Systems, Inc. + +usb:v0901* + ID_VENDOR_FROM_DATABASE=VST Technologies + +usb:v0901p0001* + ID_MODEL_FROM_DATABASE=Hard Drive Adapter (TPP) + +usb:v0901p0002* + ID_MODEL_FROM_DATABASE=SigmaDrive Adapter (TPP) + +usb:v0906* + ID_VENDOR_FROM_DATABASE=Faraday Technology Corp. + +usb:v0908* + ID_VENDOR_FROM_DATABASE=ShenZhen SANZHAI Technology Co.,Ltd + +usb:v0908p2701* + ID_MODEL_FROM_DATABASE=Spy Pen VGA + +usb:v0909* + ID_VENDOR_FROM_DATABASE=Audio-Technica Corp. + +usb:v090A* + ID_VENDOR_FROM_DATABASE=Trumpion Microelectronics, Inc. + +usb:v090Ap1001* + ID_MODEL_FROM_DATABASE=T33520 Flash Card Controller + +usb:v090Ap1100* + ID_MODEL_FROM_DATABASE=Comotron C3310 MP3 player + +usb:v090Ap1200* + ID_MODEL_FROM_DATABASE=MP3 player + +usb:v090Ap1540* + ID_MODEL_FROM_DATABASE=Digitex Container Flash Disk + +usb:v090B* + ID_VENDOR_FROM_DATABASE=Neurosmith + +usb:v090C* + ID_VENDOR_FROM_DATABASE=Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.) + +usb:v090Cp0371* + ID_MODEL_FROM_DATABASE=Silicon Motion SM371 Camera + +usb:v090Cp0373* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp037A* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp037B* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp1000* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v090Cp1132* + ID_MODEL_FROM_DATABASE=5-in-1 Card Reader + +usb:v090Cp337B* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp3710* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp3720* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp37BC* + ID_MODEL_FROM_DATABASE=HP Webcam-101 Integrated Camera + +usb:v090Cp37C0* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp6000* + ID_MODEL_FROM_DATABASE=SD/SDHC Card Reader (SG365 / FlexiDrive XC+) + +usb:v090Cp6200* + ID_MODEL_FROM_DATABASE=microSD card reader + +usb:v090Cp71B3* + ID_MODEL_FROM_DATABASE=SM731 Camera + +usb:v090Cp837B* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090Cp937B* + ID_MODEL_FROM_DATABASE=Silicon Motion Camera + +usb:v090CpB370* + ID_MODEL_FROM_DATABASE=Silicon Motion SM370 Camera + +usb:v090CpB371* + ID_MODEL_FROM_DATABASE=Silicon Motion SM371 Camera + +usb:v090D* + ID_VENDOR_FROM_DATABASE=Multiport Computer Vertriebs GmbH + +usb:v090E* + ID_VENDOR_FROM_DATABASE=Shining Technology, Inc. + +usb:v090F* + ID_VENDOR_FROM_DATABASE=Fujitsu Devices, Inc. + +usb:v0910* + ID_VENDOR_FROM_DATABASE=Alation Systems, Inc. + +usb:v0911* + ID_VENDOR_FROM_DATABASE=Philips Speech Processing + +usb:v0911p149A* + ID_MODEL_FROM_DATABASE=SpeechMike II Pro Plus LFH5276 + +usb:v0911p2512* + ID_MODEL_FROM_DATABASE=SpeechMike Pro + +usb:v0912* + ID_VENDOR_FROM_DATABASE=Voquette, Inc. + +usb:v0915* + ID_VENDOR_FROM_DATABASE=GlobeSpan, Inc. + +usb:v0915p0001* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0915p0002* + ID_MODEL_FROM_DATABASE=ADSL ATM Modem + +usb:v0915p0005* + ID_MODEL_FROM_DATABASE=LAN Modem + +usb:v0915p2000* + ID_MODEL_FROM_DATABASE=802.11 Adapter + +usb:v0915p2002* + ID_MODEL_FROM_DATABASE=802.11 Adapter + +usb:v0915p8000* + ID_MODEL_FROM_DATABASE=ADSL LAN Modem + +usb:v0915p8005* + ID_MODEL_FROM_DATABASE=DSL-302G Modem + +usb:v0915p8101* + ID_MODEL_FROM_DATABASE=ADSL WAN Modem + +usb:v0915p8102* + ID_MODEL_FROM_DATABASE=DSL-200 ADSL Modem + +usb:v0915p8103* + ID_MODEL_FROM_DATABASE=DSL-200 ADSL Modem + +usb:v0915p8104* + ID_MODEL_FROM_DATABASE=DSL-200 Modem + +usb:v0915p8400* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0915p8401* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0915p8402* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0915p8500* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0915p8501* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v0917* + ID_VENDOR_FROM_DATABASE=SmartDisk Corp. + +usb:v0917p0001* + ID_MODEL_FROM_DATABASE=eFilm Reader-11 SM/CF + +usb:v0917p0002* + ID_MODEL_FROM_DATABASE=eFilm Reader-11 SM + +usb:v0917p0003* + ID_MODEL_FROM_DATABASE=eFilm Reader-11 CF + +usb:v0917p0200* + ID_MODEL_FROM_DATABASE=FireFly + +usb:v0917p0201* + ID_MODEL_FROM_DATABASE=FireLite + +usb:v0917p0202* + ID_MODEL_FROM_DATABASE=STORAGE ADAPTER (FirePower) + +usb:v0917p0204* + ID_MODEL_FROM_DATABASE=FlashTrax Storage + +usb:v0917p0205* + ID_MODEL_FROM_DATABASE=STORAGE ADAPTER (CrossFire) + +usb:v0917p0206* + ID_MODEL_FROM_DATABASE=FireFly 20G HDD + +usb:v0917p0207* + ID_MODEL_FROM_DATABASE=FireLite + +usb:v0917p020F* + ID_MODEL_FROM_DATABASE=STORAGE ADAPTER (FireLite) + +usb:v0917pDA01* + ID_MODEL_FROM_DATABASE=eFilm Reader-11 Test + +usb:v0917pFFFF* + ID_MODEL_FROM_DATABASE=eFilm Reader-11 (Class/PDR) + +usb:v0919* + ID_VENDOR_FROM_DATABASE=Tiger Electronics + +usb:v0919p0100* + ID_MODEL_FROM_DATABASE=Fast Flicks Digital Camera + +usb:v091E* + ID_VENDOR_FROM_DATABASE=Garmin International + +usb:v091Ep0003* + ID_MODEL_FROM_DATABASE=GPS (various models) + +usb:v091Ep0004* + ID_MODEL_FROM_DATABASE=iQue 3600 + +usb:v091Ep0200* + ID_MODEL_FROM_DATABASE=Data Card Programmer (install) + +usb:v091Ep1200* + ID_MODEL_FROM_DATABASE=Data Card Programmer + +usb:v091Ep21A5* + ID_MODEL_FROM_DATABASE=etrex Cx (msc) + +usb:v091Ep2236* + ID_MODEL_FROM_DATABASE=nuvi 360 + +usb:v091Ep2271* + ID_MODEL_FROM_DATABASE=Edge 605/705 + +usb:v091Ep2295* + ID_MODEL_FROM_DATABASE=Colorado 300 + +usb:v091Ep22B6* + ID_MODEL_FROM_DATABASE=eTrex Vista HCx (Mass Storage mode) + +usb:v091Ep231B* + ID_MODEL_FROM_DATABASE=Oregon 400t + +usb:v091Ep2353* + ID_MODEL_FROM_DATABASE=Nüvi 205T + +usb:v091Ep2380* + ID_MODEL_FROM_DATABASE=Oregon series + +usb:v091Ep23CC* + ID_MODEL_FROM_DATABASE=nüvi 1350 + +usb:v091Ep2459* + ID_MODEL_FROM_DATABASE=GPSmap 62/78 series + +usb:v091Ep2519* + ID_MODEL_FROM_DATABASE=eTrex 30 + +usb:v091Ep2535* + ID_MODEL_FROM_DATABASE=Edge 800 + +usb:v091Ep255B* + ID_MODEL_FROM_DATABASE=Nuvi 2505LM + +usb:v0920* + ID_VENDOR_FROM_DATABASE=Echelon Co. + +usb:v0920p7500* + ID_MODEL_FROM_DATABASE=Network Interface + +usb:v0921* + ID_VENDOR_FROM_DATABASE=GoHubs, Inc. + +usb:v0921p1001* + ID_MODEL_FROM_DATABASE=GoCOM232 Serial + +usb:v0922* + ID_VENDOR_FROM_DATABASE=Dymo-CoStar Corp. + +usb:v0922p0007* + ID_MODEL_FROM_DATABASE=LabelWriter 330 + +usb:v0922p0009* + ID_MODEL_FROM_DATABASE=LabelWriter 310 + +usb:v0922p001A* + ID_MODEL_FROM_DATABASE=LabelWriter 400 Turbo + +usb:v0922p0020* + ID_MODEL_FROM_DATABASE=LabelWriter 450 + +usb:v0923* + ID_VENDOR_FROM_DATABASE=IC Media Corp. + +usb:v0923p010F* + ID_MODEL_FROM_DATABASE=SIIG MobileCam + +usb:v0924* + ID_VENDOR_FROM_DATABASE=Xerox + +usb:v0924p23DD* + ID_MODEL_FROM_DATABASE=DocuPrint M760 (X760_USB) + +usb:v0924p3CE8* + ID_MODEL_FROM_DATABASE=Phaser 3428 Printer + +usb:v0924p3D5B* + ID_MODEL_FROM_DATABASE=Phaser 6115MFP TWAIN Scanner + +usb:v0924p420F* + ID_MODEL_FROM_DATABASE=WorkCentre PE220 Series + +usb:v0924p421F* + ID_MODEL_FROM_DATABASE=M20 Scanner + +usb:v0924p423B* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v0924p4274* + ID_MODEL_FROM_DATABASE=Xerox Phaser 3635MFPX + +usb:v0924pFFEF* + ID_MODEL_FROM_DATABASE=WorkCenter M15 + +usb:v0924pFFFB* + ID_MODEL_FROM_DATABASE=DocuPrint M750 (X750_USB) + +usb:v0925* + ID_VENDOR_FROM_DATABASE=Lakeview Research + +usb:v0925p0005* + ID_MODEL_FROM_DATABASE=Gamtec.,Ltd SmartJoy PLUS Adapter + +usb:v0925p3881* + ID_MODEL_FROM_DATABASE=Saleae Logic + +usb:v0925p8101* + ID_MODEL_FROM_DATABASE=Phidgets, Inc., 1-Motor PhidgetServo v2.0 + +usb:v0925p8104* + ID_MODEL_FROM_DATABASE=Phidgets, Inc., 4-Motor PhidgetServo v2.0 + +usb:v0925p8800* + ID_MODEL_FROM_DATABASE=WiseGroup Ltd, MP-8800 Quad Joypad + +usb:v0925p8866* + ID_MODEL_FROM_DATABASE=WiseGroup Ltd, MP-8866 Dual Joypad + +usb:v0927* + ID_VENDOR_FROM_DATABASE=Summus, Ltd + +usb:v0928* + ID_VENDOR_FROM_DATABASE=PLX Technology, Inc. (formerly Oxford Semiconductor, Ltd) + +usb:v0928p8000* + ID_MODEL_FROM_DATABASE=Firmware uploader + +usb:v0929* + ID_VENDOR_FROM_DATABASE=American Biometric Co. + +usb:v092A* + ID_VENDOR_FROM_DATABASE=Toshiba Information & Industrial Sys. And Services + +usb:v092B* + ID_VENDOR_FROM_DATABASE=Sena Technologies, Inc. + +usb:v092F* + ID_VENDOR_FROM_DATABASE=Northern Embedded Science/CAVNEX + +usb:v092Fp0004* + ID_MODEL_FROM_DATABASE=JTAG-4 + +usb:v092Fp0005* + ID_MODEL_FROM_DATABASE=JTAG-5 + +usb:v0930* + ID_VENDOR_FROM_DATABASE=Toshiba Corp. + +usb:v0930p0009* + ID_MODEL_FROM_DATABASE=Gigabeat F/X (HDD audio player) + +usb:v0930p000C* + ID_MODEL_FROM_DATABASE=Gigabeat F (mtp) + +usb:v0930p0010* + ID_MODEL_FROM_DATABASE=Gigabeat S (mtp) + +usb:v0930p0301* + ID_MODEL_FROM_DATABASE=PCX1100U Cable Modem (WDM) + +usb:v0930p0302* + ID_MODEL_FROM_DATABASE=PCX2000 Cable Modem (WDM) + +usb:v0930p0305* + ID_MODEL_FROM_DATABASE=Cable Modem PCX3000 + +usb:v0930p0307* + ID_MODEL_FROM_DATABASE=Cable Modem PCX2500 + +usb:v0930p0308* + ID_MODEL_FROM_DATABASE=PCX2200 Cable Modem (WDM) + +usb:v0930p0309* + ID_MODEL_FROM_DATABASE=PCX5000 Cable Modem (WDM) + +usb:v0930p030B* + ID_MODEL_FROM_DATABASE=Cable Modem PCX2600 + +usb:v0930p0501* + ID_MODEL_FROM_DATABASE=Bluetooth Controller + +usb:v0930p0502* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth + +usb:v0930p0503* + ID_MODEL_FROM_DATABASE=Bluetooth Controller + +usb:v0930p0505* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth + +usb:v0930p0506* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth + +usb:v0930p0507* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v0930p0508* + ID_MODEL_FROM_DATABASE=Integrated Bluetooth HCI + +usb:v0930p0509* + ID_MODEL_FROM_DATABASE=BT EDR Dongle + +usb:v0930p0706* + ID_MODEL_FROM_DATABASE=PocketPC e740 + +usb:v0930p0707* + ID_MODEL_FROM_DATABASE=Pocket PC e330 Series + +usb:v0930p0708* + ID_MODEL_FROM_DATABASE=Pocket PC e350 Series + +usb:v0930p0709* + ID_MODEL_FROM_DATABASE=Pocket PC e750 Series + +usb:v0930p070A* + ID_MODEL_FROM_DATABASE=Pocket PC e400 Series + +usb:v0930p070B* + ID_MODEL_FROM_DATABASE=Pocket PC e800 Series + +usb:v0930p0A07* + ID_MODEL_FROM_DATABASE=WLM-10U1 802.11abgn Wireless Adapter [Ralink RT3572] + +usb:v0930p0B05* + ID_MODEL_FROM_DATABASE=PX1220E-1G25 External hard drive + +usb:v0930p0B09* + ID_MODEL_FROM_DATABASE=PX1396E-3T01 External hard drive + +usb:v0930p0B1A* + ID_MODEL_FROM_DATABASE=STOR.E ALU 2S + +usb:v0930p1300* + ID_MODEL_FROM_DATABASE=Wireless Broadband (CDMA EV-DO) SM-Bus Minicard Status Port + +usb:v0930p1301* + ID_MODEL_FROM_DATABASE=Wireless Broadband (CDMA EV-DO) Minicard Status Port + +usb:v0930p1302* + ID_MODEL_FROM_DATABASE=Wireless Broadband (3G HSDPA) SM-Bus Minicard Status Port + +usb:v0930p1303* + ID_MODEL_FROM_DATABASE=Wireless Broadband (3G HSDPA) Minicard Status Port + +usb:v0930p1308* + ID_MODEL_FROM_DATABASE=Broadband (3G HSDPA) SM-Bus Minicard Diagnostics Port + +usb:v0930p130B* + ID_MODEL_FROM_DATABASE=F3507g Mobile Broadband Module + +usb:v0930p130C* + ID_MODEL_FROM_DATABASE=F3607gw Mobile Broadband Module + +usb:v0930p1311* + ID_MODEL_FROM_DATABASE=F3607gw v2 Mobile Broadband Module + +usb:v0930p1400* + ID_MODEL_FROM_DATABASE=Memory Stick 2GB + +usb:v0930p642F* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6506* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6507* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6508* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6509* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6510* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6517* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6518* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6519* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 2.0 USB Stick + +usb:v0930p651A* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p651B* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p651C* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p651D* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p651E* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p651F* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6520* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6521* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6522* + ID_MODEL_FROM_DATABASE=TravelDrive 2C + +usb:v0930p6523* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6524* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6525* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6526* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6527* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6528* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6529* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p652A* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p652B* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p652C* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p652D* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p652F* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6530* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6531* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p6532* + ID_MODEL_FROM_DATABASE=256M Stick + +usb:v0930p6533* + ID_MODEL_FROM_DATABASE=512M Stick + +usb:v0930p6534* + ID_MODEL_FROM_DATABASE=TravelDrive + +usb:v0930p653C* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 2.0 Stick (512M) + +usb:v0930p653D* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 2.0 Stick (1GB) + +usb:v0930p653E* + ID_MODEL_FROM_DATABASE=Flash Memory + +usb:v0930p6540* + ID_MODEL_FROM_DATABASE=TransMemory Flash Memory + +usb:v0930p6544* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 2.0 Stick (2GB) + +usb:v0930p6545* + ID_MODEL_FROM_DATABASE=Kingston DataTraveler 102 Flash Drive / HEMA Flash Drive 2 GB / PNY Attache 4GB Stick + +usb:v0931* + ID_VENDOR_FROM_DATABASE=Harmonic Data Systems, Ltd + +usb:v0932* + ID_VENDOR_FROM_DATABASE=Crescentec Corp. + +usb:v0932p0300* + ID_MODEL_FROM_DATABASE=VideoAdvantage + +usb:v0932p0302* + ID_MODEL_FROM_DATABASE=Syntek DC-112X + +usb:v0932p0320* + ID_MODEL_FROM_DATABASE=VideoAdvantage + +usb:v0932p0482* + ID_MODEL_FROM_DATABASE=USB2.0 TVBOX + +usb:v0932p1100* + ID_MODEL_FROM_DATABASE=DC-1100 Video Enhamcement Device + +usb:v0932p1112* + ID_MODEL_FROM_DATABASE=Veo Web Camera + +usb:v0932pA311* + ID_MODEL_FROM_DATABASE=Video Enhancement Device + +usb:v0933* + ID_VENDOR_FROM_DATABASE=Quantum Corp. + +usb:v0934* + ID_VENDOR_FROM_DATABASE=Spirent Communications + +usb:v0936* + ID_VENDOR_FROM_DATABASE=NuTesla + +usb:v0936p000C* + ID_MODEL_FROM_DATABASE=Rhythmedics 6 BioData Integrator + +usb:v0936p0030* + ID_MODEL_FROM_DATABASE=Composite Device, Mass Storage Device (Flash Drive) amd HID + +usb:v0936p003C* + ID_MODEL_FROM_DATABASE=Rhythmedics HID Bootloader + +usb:v0939* + ID_VENDOR_FROM_DATABASE=Lumberg, Inc. + +usb:v0939p0B15* + ID_MODEL_FROM_DATABASE=Toshiba Stor.E Alu 2 1TB (PX1710E-1HJ0) + +usb:v093A* + ID_VENDOR_FROM_DATABASE=Pixart Imaging, Inc. + +usb:v093Ap0007* + ID_MODEL_FROM_DATABASE=CMOS 100K-R Rev. 1.90 + +usb:v093Ap010E* + ID_MODEL_FROM_DATABASE=Digital camera, CD302N/Elta Medi@ digi-cam/HE-501A + +usb:v093Ap010F* + ID_MODEL_FROM_DATABASE=Argus DC-1610/DC-1620/Emprex PCD3600/Philips P44417B keychain camera/Precision Mini,Model HA513A/Vivitar Vivicam 55 + +usb:v093Ap020F* + ID_MODEL_FROM_DATABASE=Bullet Line Photo Viewer + +usb:v093Ap050F* + ID_MODEL_FROM_DATABASE=Mars-Semi Pc-Camera + +usb:v093Ap2460* + ID_MODEL_FROM_DATABASE=Q-TEC WEBCAM 100 + +usb:v093Ap2468* + ID_MODEL_FROM_DATABASE=SoC PC-Camera + +usb:v093Ap2470* + ID_MODEL_FROM_DATABASE=SoC PC-Camera + +usb:v093Ap2471* + ID_MODEL_FROM_DATABASE=SoC PC-Camera + +usb:v093Ap2500* + ID_MODEL_FROM_DATABASE=USB Optical Mouse + +usb:v093Ap2510* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v093Ap2521* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v093Ap2600* + ID_MODEL_FROM_DATABASE=Typhoon Easycam USB 330K (newer)/Typhoon Easycam USB 2.0 VGA 1.3M/Sansun SN-508 + +usb:v093Ap2601* + ID_MODEL_FROM_DATABASE=SPC 610NC Laptop Camera + +usb:v093Ap2603* + ID_MODEL_FROM_DATABASE=PAC7312 Camera + +usb:v093Ap2608* + ID_MODEL_FROM_DATABASE=PAC7311 Trust WB-3300p + +usb:v093Ap260E* + ID_MODEL_FROM_DATABASE=PAC7311 Gigaware VGA PC Camera:Trust WB-3350p:SIGMA cam 2350 + +usb:v093Ap260F* + ID_MODEL_FROM_DATABASE=PAC7311 SnakeCam + +usb:v093Ap2621* + ID_MODEL_FROM_DATABASE=PAC731x Trust Webcam + +usb:v093Ap2624* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v093B* + ID_VENDOR_FROM_DATABASE=Plextor Corp. + +usb:v093Bp0010* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v093Bp0011* + ID_MODEL_FROM_DATABASE=PlexWriter 40/12/40U + +usb:v093Bp0041* + ID_MODEL_FROM_DATABASE=PX-708A DVD RW + +usb:v093Bp0042* + ID_MODEL_FROM_DATABASE=PX-712UF DVD RW + +usb:v093BpA002* + ID_MODEL_FROM_DATABASE=ConvertX M402U XLOADER + +usb:v093BpA003* + ID_MODEL_FROM_DATABASE=ConvertX AV100U A/V Capture Audio + +usb:v093BpA004* + ID_MODEL_FROM_DATABASE=ConvertX TV402U XLOADER + +usb:v093BpA005* + ID_MODEL_FROM_DATABASE=ConvertX TV100U A/V Capture + +usb:v093BpA102* + ID_MODEL_FROM_DATABASE=ConvertX M402U A/V Capture + +usb:v093BpA104* + ID_MODEL_FROM_DATABASE=ConvertX PX-TV402U/NA + +usb:v093C* + ID_VENDOR_FROM_DATABASE=Intrepid Control Systems, Inc. + +usb:v093Cp0601* + ID_MODEL_FROM_DATABASE=ValueCAN + +usb:v093Cp0701* + ID_MODEL_FROM_DATABASE=NeoVI Blue vehicle bus interface + +usb:v093D* + ID_VENDOR_FROM_DATABASE=InnoSync, Inc. + +usb:v093E* + ID_VENDOR_FROM_DATABASE=J.S.T. Mfg. Co., Ltd + +usb:v093F* + ID_VENDOR_FROM_DATABASE=Olympia Telecom Vertriebs GmbH + +usb:v0940* + ID_VENDOR_FROM_DATABASE=Japan Storage Battery Co., Ltd + +usb:v0941* + ID_VENDOR_FROM_DATABASE=Photobit Corp. + +usb:v0942* + ID_VENDOR_FROM_DATABASE=i2Go.com, LLC + +usb:v0943* + ID_VENDOR_FROM_DATABASE=HCL Technologies India Private, Ltd + +usb:v0944* + ID_VENDOR_FROM_DATABASE=KORG, Inc. + +usb:v0944p0001* + ID_MODEL_FROM_DATABASE=PXR4 4-Track Digital Recorder + +usb:v0944p0020* + ID_MODEL_FROM_DATABASE=KAOSS Pad KP3 Dynamic Effect/Sampler + +usb:v0944p0023* + ID_MODEL_FROM_DATABASE=KAOSSILATOR PRO Dynamic Phrase Synthesizer + +usb:v0944p010D* + ID_MODEL_FROM_DATABASE=nanoKEY MIDI keyboard + +usb:v0944p010E* + ID_MODEL_FROM_DATABASE=nanoPAD pad controller + +usb:v0944p010F* + ID_MODEL_FROM_DATABASE=nanoKONTROL studio controller + +usb:v0944p0117* + ID_MODEL_FROM_DATABASE=nanoKONTROL2 MIDI Controller + +usb:v0944p0F03* + ID_MODEL_FROM_DATABASE=K-Series K61P MIDI studio controller + +usb:v0945* + ID_VENDOR_FROM_DATABASE=Pasco Scientific + +usb:v0948* + ID_VENDOR_FROM_DATABASE=Kronauer music in digital + +usb:v0948p0301* + ID_MODEL_FROM_DATABASE=USB Pro (24/48) + +usb:v0948p0302* + ID_MODEL_FROM_DATABASE=USB Pro (24/96 playback) + +usb:v0948p0303* + ID_MODEL_FROM_DATABASE=USB Pro (24/96 record) + +usb:v0948p0304* + ID_MODEL_FROM_DATABASE=USB Pro (16/48) + +usb:v0948p1105* + ID_MODEL_FROM_DATABASE=USB One + +usb:v094B* + ID_VENDOR_FROM_DATABASE=Linkup Systems Corp. + +usb:v094Bp0001* + ID_MODEL_FROM_DATABASE=neonode N2 + +usb:v094D* + ID_VENDOR_FROM_DATABASE=Cable Television Laboratories + +usb:v094F* + ID_VENDOR_FROM_DATABASE=Yano + +usb:v094Fp0101* + ID_MODEL_FROM_DATABASE=U640MO-03 + +usb:v094Fp05FC* + ID_MODEL_FROM_DATABASE=METALWEAR-HDD + +usb:v0951* + ID_VENDOR_FROM_DATABASE=Kingston Technology + +usb:v0951p0008* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v0951p000A* + ID_MODEL_FROM_DATABASE=KNU101TX 100baseTX Ethernet + +usb:v0951p1600* + ID_MODEL_FROM_DATABASE=DataTraveler II Pen Drive + +usb:v0951p1601* + ID_MODEL_FROM_DATABASE=DataTraveler II+ Pen Drive + +usb:v0951p1602* + ID_MODEL_FROM_DATABASE=DataTraveler Mini + +usb:v0951p1603* + ID_MODEL_FROM_DATABASE=DataTraveler 1GB/2GB Pen Drive + +usb:v0951p1606* + ID_MODEL_FROM_DATABASE=Eee PC 701 SD Card Reader [ENE UB6225] + +usb:v0951p1607* + ID_MODEL_FROM_DATABASE=DataTraveler 100 + +usb:v0951p160D* + ID_MODEL_FROM_DATABASE=DataTraveler Vault Privacy + +usb:v0951p1613* + ID_MODEL_FROM_DATABASE=DataTraveler DT101C Flash Drive + +usb:v0951p1616* + ID_MODEL_FROM_DATABASE=DataTraveler Locker 4GB + +usb:v0951p1621* + ID_MODEL_FROM_DATABASE=DataTraveler 150 (32GB) + +usb:v0951p1624* + ID_MODEL_FROM_DATABASE=DataTraveler G2 + +usb:v0951p1625* + ID_MODEL_FROM_DATABASE=DataTraveler 101 II + +usb:v0951p162A* + ID_MODEL_FROM_DATABASE=DataTraveler 112 4GB Pen Drive + +usb:v0951p162D* + ID_MODEL_FROM_DATABASE=DataTraveler 102 + +usb:v0951p1630* + ID_MODEL_FROM_DATABASE=DataTraveler 200 (32GB) + +usb:v0951p1642* + ID_MODEL_FROM_DATABASE=DT101 G2 + +usb:v0951p1643* + ID_MODEL_FROM_DATABASE=DataTraveler G3 + +usb:v0951p1653* + ID_MODEL_FROM_DATABASE=Data Traveler 100 G2 8 GiB + +usb:v0951p1656* + ID_MODEL_FROM_DATABASE=DataTraveler Ultimate G2 + +usb:v0951p1689* + ID_MODEL_FROM_DATABASE=DataTraveler SE9 + +usb:v0951p168A* + ID_MODEL_FROM_DATABASE=DataTraveler Micro + +usb:v0951p168C* + ID_MODEL_FROM_DATABASE=DT Elite 3.0 + +usb:v0954* + ID_VENDOR_FROM_DATABASE=RPM Systems Corp. + +usb:v0955* + ID_VENDOR_FROM_DATABASE=NVidia Corp. + +usb:v0955p7030* + ID_MODEL_FROM_DATABASE=Tegra 3 (recovery mode) + +usb:v0955p7100* + ID_MODEL_FROM_DATABASE=Notion Ink Adam + +usb:v0955p7820* + ID_MODEL_FROM_DATABASE=Tegra 2 AC100 developer mode + +usb:v0955pB400* + ID_MODEL_FROM_DATABASE=SHIELD (debug) + +usb:v0955pB401* + ID_MODEL_FROM_DATABASE=SHIELD + +usb:v0956* + ID_VENDOR_FROM_DATABASE=BSquare Corp. + +usb:v0957* + ID_VENDOR_FROM_DATABASE=Agilent Technologies, Inc. + +usb:v0957p0200* + ID_MODEL_FROM_DATABASE=E-Video DC-350 Camera + +usb:v0957p0202* + ID_MODEL_FROM_DATABASE=E-Video DC-350 Camera + +usb:v0957p0518* + ID_MODEL_FROM_DATABASE=82357B GPIB Interface + +usb:v0957p0A07* + ID_MODEL_FROM_DATABASE=34411A Multimeter + +usb:v0957p1745* + ID_MODEL_FROM_DATABASE=Test and Measurement Device (IVI) + +usb:v0957p2918* + ID_MODEL_FROM_DATABASE=U2702A oscilloscope + +usb:v0958* + ID_VENDOR_FROM_DATABASE=CompuLink Research, Inc. + +usb:v0959* + ID_VENDOR_FROM_DATABASE=Cologne Chip AG + +usb:v0959p2BD0* + ID_MODEL_FROM_DATABASE=Intelligent ISDN (Ver. 3.60.04) + +usb:v095A* + ID_VENDOR_FROM_DATABASE=Portsmith + +usb:v095Ap3003* + ID_MODEL_FROM_DATABASE=Express Ethernet + +usb:v095B* + ID_VENDOR_FROM_DATABASE=Medialogic Corp. + +usb:v095C* + ID_VENDOR_FROM_DATABASE=K-Tec Electronics + +usb:v095D* + ID_VENDOR_FROM_DATABASE=Polycom, Inc. + +usb:v095Dp0001* + ID_MODEL_FROM_DATABASE=Polycom ViaVideo + +usb:v0967* + ID_VENDOR_FROM_DATABASE=Acer (??) + +usb:v0967p0204* + ID_MODEL_FROM_DATABASE=WarpLink 802.11b Adapter + +usb:v0968* + ID_VENDOR_FROM_DATABASE=Catalyst Enterprises, Inc. + +usb:v096E* + ID_VENDOR_FROM_DATABASE=Feitian Technologies, Inc. + +usb:v096Ep0120* + ID_MODEL_FROM_DATABASE=Microcosm Ltd Dinkey + +usb:v096Ep0802* + ID_MODEL_FROM_DATABASE=ePass2000 (G&D STARCOS SPK 2.4) + +usb:v096Ep0807* + ID_MODEL_FROM_DATABASE=ePass2003 + +usb:v0971* + ID_VENDOR_FROM_DATABASE=Gretag-Macbeth AG + +usb:v0971p2003* + ID_MODEL_FROM_DATABASE=Eye-One display + +usb:v0971p2005* + ID_MODEL_FROM_DATABASE=Huey + +usb:v0971p2007* + ID_MODEL_FROM_DATABASE=ColorMunki + +usb:v0973* + ID_VENDOR_FROM_DATABASE=Schlumberger + +usb:v0973p0001* + ID_MODEL_FROM_DATABASE=e-gate Smart Card + +usb:v0974* + ID_VENDOR_FROM_DATABASE=Datagraphix, a business unit of Anacomp + +usb:v0975* + ID_VENDOR_FROM_DATABASE=OL'E Communications, Inc. + +usb:v0976* + ID_VENDOR_FROM_DATABASE=Adirondack Wire & Cable + +usb:v0977* + ID_VENDOR_FROM_DATABASE=Lightsurf Technologies + +usb:v0978* + ID_VENDOR_FROM_DATABASE=Beckhoff GmbH + +usb:v0979* + ID_VENDOR_FROM_DATABASE=Jeilin Technology Corp., Ltd + +usb:v0979p0222* + ID_MODEL_FROM_DATABASE=Keychain Display + +usb:v0979p0224* + ID_MODEL_FROM_DATABASE=JL2005A Toy Camera + +usb:v0979p0226* + ID_MODEL_FROM_DATABASE=JL2005A Toy Camera + +usb:v0979p0227* + ID_MODEL_FROM_DATABASE=JL2005B/C/D Toy Camera + +usb:v097A* + ID_VENDOR_FROM_DATABASE=Minds At Work LLC + +usb:v097Ap0001* + ID_MODEL_FROM_DATABASE=Digital Wallet + +usb:v097B* + ID_VENDOR_FROM_DATABASE=Knudsen Engineering, Ltd + +usb:v097C* + ID_VENDOR_FROM_DATABASE=Marunix Co., Ltd + +usb:v097D* + ID_VENDOR_FROM_DATABASE=Rosun Technologies, Inc. + +usb:v097E* + ID_VENDOR_FROM_DATABASE=Biopac Systems Inc. + +usb:v097Ep0035* + ID_MODEL_FROM_DATABASE=MP35 v1.0 + +usb:v097F* + ID_VENDOR_FROM_DATABASE=Barun Electronics Co., Ltd + +usb:v0981* + ID_VENDOR_FROM_DATABASE=Oak Technology, Ltd + +usb:v0984* + ID_VENDOR_FROM_DATABASE=Apricorn + +usb:v0984p0040* + ID_MODEL_FROM_DATABASE=SATA Wire (2.5") + +usb:v0984p0200* + ID_MODEL_FROM_DATABASE=Hard Drive Storage (TPP) + +usb:v0985* + ID_VENDOR_FROM_DATABASE=cab Produkttechnik GmbH & Co KG + +usb:v0985p0045* + ID_MODEL_FROM_DATABASE=Mach4/200 Label Printer + +usb:v0985p00A3* + ID_MODEL_FROM_DATABASE=A3/200 or A3/300 Label Printer + +usb:v0986* + ID_VENDOR_FROM_DATABASE=Matsushita Electric Works, Ltd. + +usb:v098C* + ID_VENDOR_FROM_DATABASE=Vitana Corp. + +usb:v098D* + ID_VENDOR_FROM_DATABASE=INDesign + +usb:v098E* + ID_VENDOR_FROM_DATABASE=Integrated Intellectual Property, Inc. + +usb:v098F* + ID_VENDOR_FROM_DATABASE=Kenwood TMI Corp. + +usb:v0993* + ID_VENDOR_FROM_DATABASE=Gemstar eBook Group, Ltd + +usb:v0993p0001* + ID_MODEL_FROM_DATABASE=REB1100 eBook Reader + +usb:v0993p0002* + ID_MODEL_FROM_DATABASE=eBook + +usb:v0996* + ID_VENDOR_FROM_DATABASE=Integrated Telecom Express, Inc. + +usb:v099A* + ID_VENDOR_FROM_DATABASE=Zippy Technology Corp. + +usb:v099Ap0638* + ID_MODEL_FROM_DATABASE=Sanwa Supply Inc. Small Keyboard + +usb:v099Ap610C* + ID_MODEL_FROM_DATABASE=EL-610 Super Mini Electron luminescent Keyboard + +usb:v099Ap7160* + ID_MODEL_FROM_DATABASE=Hyper Slim Keyboard + +usb:v09A3* + ID_VENDOR_FROM_DATABASE=PairGain Technologies + +usb:v09A4* + ID_VENDOR_FROM_DATABASE=Contech Research, Inc. + +usb:v09A5* + ID_VENDOR_FROM_DATABASE=VCON Telecommunications + +usb:v09A6* + ID_VENDOR_FROM_DATABASE=Poinchips + +usb:v09A6p8001* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v09A7* + ID_VENDOR_FROM_DATABASE=Data Transmission Network Corp. + +usb:v09A8* + ID_VENDOR_FROM_DATABASE=Lin Shiung Enterprise Co., Ltd + +usb:v09A9* + ID_VENDOR_FROM_DATABASE=Smart Card Technologies Co., Ltd + +usb:v09AA* + ID_VENDOR_FROM_DATABASE=Intersil Corp. + +usb:v09AAp1000* + ID_MODEL_FROM_DATABASE=Prism GT 802.11b/g Adapter + +usb:v09AAp3642* + ID_MODEL_FROM_DATABASE=Prism 2.x 802.11b Adapter + +usb:v09AB* + ID_VENDOR_FROM_DATABASE=Japan Cash Machine Co., Ltd. + +usb:v09AE* + ID_VENDOR_FROM_DATABASE=Tripp Lite + +usb:v09B2* + ID_VENDOR_FROM_DATABASE=Franklin Electronic Publishers, Inc. + +usb:v09B2p0001* + ID_MODEL_FROM_DATABASE=eBookman Palm Computer + +usb:v09B3* + ID_VENDOR_FROM_DATABASE=Altius Solutions, Inc. + +usb:v09B4* + ID_VENDOR_FROM_DATABASE=MDS Telephone Systems + +usb:v09B5* + ID_VENDOR_FROM_DATABASE=Celltrix Technology Co., Ltd + +usb:v09BC* + ID_VENDOR_FROM_DATABASE=Grundig + +usb:v09BCp0002* + ID_MODEL_FROM_DATABASE=MPaxx MP150 MP3 Player + +usb:v09BE* + ID_VENDOR_FROM_DATABASE=MySmart.Com + +usb:v09BEp0001* + ID_MODEL_FROM_DATABASE=MySmartPad + +usb:v09BF* + ID_VENDOR_FROM_DATABASE=Auerswald GmbH & Co. KG + +usb:v09BFp00C0* + ID_MODEL_FROM_DATABASE=COMpact 2104 ISDN PBX + +usb:v09BFp00DB* + ID_MODEL_FROM_DATABASE=COMpact 4410/2206 ISDN + +usb:v09BFp00DC* + ID_MODEL_FROM_DATABASE=COMpact 4406 DSL (PBX) + +usb:v09BFp00DD* + ID_MODEL_FROM_DATABASE=COMpact 2204 (PBX) + +usb:v09BFp00DE* + ID_MODEL_FROM_DATABASE=COMpact 2104 (Rev.2 PBX) + +usb:v09BFp00E0* + ID_MODEL_FROM_DATABASE=COMmander Business (PBX) + +usb:v09BFp00E2* + ID_MODEL_FROM_DATABASE=COMmander Basic.2 (PBX) + +usb:v09BFp00F1* + ID_MODEL_FROM_DATABASE=COMfort 2000 (System telephone) + +usb:v09BFp00F2* + ID_MODEL_FROM_DATABASE=COMfort 1200 (System telephone) + +usb:v09BFp00F5* + ID_MODEL_FROM_DATABASE=COMfortel 2500 (System telephone) + +usb:v09BFp8000* + ID_MODEL_FROM_DATABASE=COMpact 2104 DSL (DSL modem) + +usb:v09BFp8001* + ID_MODEL_FROM_DATABASE=COMpact 4406 DSL (DSL modem) + +usb:v09BFp8002* + ID_MODEL_FROM_DATABASE=Analog/ISDN Converter (Line converter) + +usb:v09BFp8005* + ID_MODEL_FROM_DATABASE=WG-640 (Automatic event dialer) + +usb:v09C0* + ID_VENDOR_FROM_DATABASE=Genpix Electronics, LLC + +usb:v09C0p0136* + ID_MODEL_FROM_DATABASE=Axon CNS, MultiClamp 700B + +usb:v09C0p0202* + ID_MODEL_FROM_DATABASE=8PSK DVB-S tuner + +usb:v09C0p0203* + ID_MODEL_FROM_DATABASE=Skywalker-1 DVB-S tuner + +usb:v09C0p0204* + ID_MODEL_FROM_DATABASE=Skywalker-CW3K DVB-S tuner + +usb:v09C0p0205* + ID_MODEL_FROM_DATABASE=Skywalker-CW3K DVB-S tuner + +usb:v09C0p0206* + ID_MODEL_FROM_DATABASE=Skywalker-2 DVB-S tuner + +usb:v09C1* + ID_VENDOR_FROM_DATABASE=Arris Interactive LLC + +usb:v09C1p1337* + ID_MODEL_FROM_DATABASE=TOUCHSTONE DEVICE + +usb:v09C2* + ID_VENDOR_FROM_DATABASE=Nisca Corp. + +usb:v09C3* + ID_VENDOR_FROM_DATABASE=ActivCard, Inc. + +usb:v09C3p0007* + ID_MODEL_FROM_DATABASE=Reader V2 + +usb:v09C3p0008* + ID_MODEL_FROM_DATABASE=ZFG-9800-AC SmartCard Reader + +usb:v09C3p0014* + ID_MODEL_FROM_DATABASE=ActivIdentity ActivKey SIM USB Token + +usb:v09C4* + ID_VENDOR_FROM_DATABASE=ACTiSYS Corp. + +usb:v09C4p0011* + ID_MODEL_FROM_DATABASE=ACT-IR2000U IrDA Dongle + +usb:v09C5* + ID_VENDOR_FROM_DATABASE=Memory Corp. + +usb:v09CC* + ID_VENDOR_FROM_DATABASE=Workbit Corp. + +usb:v09CCp0404* + ID_MODEL_FROM_DATABASE=BAFO USB-ATA/ATAPI Bridge Controller + +usb:v09CD* + ID_VENDOR_FROM_DATABASE=Psion Dacom Home Networks, Ltd + +usb:v09CDp2001* + ID_MODEL_FROM_DATABASE=Psion WaveFinder DAB radio receiver + +usb:v09CE* + ID_VENDOR_FROM_DATABASE=City Electronics, Ltd + +usb:v09CF* + ID_VENDOR_FROM_DATABASE=Electronics Testing Center, Taiwan + +usb:v09D1* + ID_VENDOR_FROM_DATABASE=NeoMagic, Inc. + +usb:v09D2* + ID_VENDOR_FROM_DATABASE=Vreelin Engineering, Inc. + +usb:v09D3* + ID_VENDOR_FROM_DATABASE=Com One + +usb:v09D3p0001* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v09D7* + ID_VENDOR_FROM_DATABASE=Novatel Wireless + +usb:v09D7p0100* + ID_MODEL_FROM_DATABASE=NovAtel FlexPack GPS receiver + +usb:v09D9* + ID_VENDOR_FROM_DATABASE=KRF Tech, Ltd + +usb:v09DA* + ID_VENDOR_FROM_DATABASE=A4 Tech Co., Ltd + +usb:v09DAp0006* + ID_MODEL_FROM_DATABASE=Optical Mouse WOP-35 / Trust 450L Optical Mouse + +usb:v09DAp000A* + ID_MODEL_FROM_DATABASE=Optical Mouse Opto 510D + +usb:v09DAp000E* + ID_MODEL_FROM_DATABASE=X-F710F Optical Mouse 3xFire Gaming Mouse + +usb:v09DAp0018* + ID_MODEL_FROM_DATABASE=Trust Human Interface Device + +usb:v09DAp001A* + ID_MODEL_FROM_DATABASE=Wireless Mouse & RXM-15 Receiver + +usb:v09DAp002A* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse NB-30 + +usb:v09DAp022B* + ID_MODEL_FROM_DATABASE=Wireless Mouse (Battery Free) + +usb:v09DAp024F* + ID_MODEL_FROM_DATABASE=RF Receiver and G6-20D Wireless Optical Mouse + +usb:v09DAp0260* + ID_MODEL_FROM_DATABASE=KV-300H Isolation Keyboard + +usb:v09DAp032B* + ID_MODEL_FROM_DATABASE=Wireless Mouse (Battery Free) + +usb:v09DAp8090* + ID_MODEL_FROM_DATABASE=X-718BK Oscar Optical Gaming Mouse + +usb:v09DAp9033* + ID_MODEL_FROM_DATABASE=X-718BK Optical Mouse + +usb:v09DAp9066* + ID_MODEL_FROM_DATABASE=F3 V-Track Gaming Mouse + +usb:v09DAp9090* + ID_MODEL_FROM_DATABASE=XL-730K / XL-750BK / XL-755BK Mice + +usb:v09DB* + ID_VENDOR_FROM_DATABASE=Measurement Computing Corp. + +usb:v09DBp0075* + ID_MODEL_FROM_DATABASE=MiniLab 1008 + +usb:v09DBp0076* + ID_MODEL_FROM_DATABASE=PMD-1024 + +usb:v09DBp007A* + ID_MODEL_FROM_DATABASE=PMD-1208LS + +usb:v09DBp0081* + ID_MODEL_FROM_DATABASE=USB-1616FS + +usb:v09DBp0082* + ID_MODEL_FROM_DATABASE=USB-1208FS + +usb:v09DBp0088* + ID_MODEL_FROM_DATABASE=USB-1616FS internal hub + +usb:v09DC* + ID_VENDOR_FROM_DATABASE=Aimex Corp. + +usb:v09DD* + ID_VENDOR_FROM_DATABASE=Fellowes, Inc. + +usb:v09DF* + ID_VENDOR_FROM_DATABASE=Addonics Technologies Corp. + +usb:v09E1* + ID_VENDOR_FROM_DATABASE=Intellon Corp. + +usb:v09E1p5121* + ID_MODEL_FROM_DATABASE=MicroLink dLAN + +usb:v09E5* + ID_VENDOR_FROM_DATABASE=Jo-Dan International, Inc. + +usb:v09E6* + ID_VENDOR_FROM_DATABASE=Silutia, Inc. + +usb:v09E7* + ID_VENDOR_FROM_DATABASE=Real 3D, Inc. + +usb:v09E8* + ID_VENDOR_FROM_DATABASE=AKAI Professional M.I. Corp. + +usb:v09E8p0062* + ID_MODEL_FROM_DATABASE=MPD16 MIDI Pad Controller Unit + +usb:v09E8p006D* + ID_MODEL_FROM_DATABASE=EWI electronic wind instrument + +usb:v09E8p0071* + ID_MODEL_FROM_DATABASE=MPK25 MIDI Keyboard + +usb:v09E8p0076* + ID_MODEL_FROM_DATABASE=LPK25 MIDI Keyboard + +usb:v09E9* + ID_VENDOR_FROM_DATABASE=Chen-Source, Inc. + +usb:v09EB* + ID_VENDOR_FROM_DATABASE=IM Networks, Inc. + +usb:v09EBp4331* + ID_MODEL_FROM_DATABASE=iRhythm Tuner Remote + +usb:v09EF* + ID_VENDOR_FROM_DATABASE=Xitel + +usb:v09EFp0101* + ID_MODEL_FROM_DATABASE=MD-Port DG2 MiniDisc Interface + +usb:v09F3* + ID_VENDOR_FROM_DATABASE=GoFlight, Inc. + +usb:v09F3p0018* + ID_MODEL_FROM_DATABASE=GF-46 Multi-Mode Display Module + +usb:v09F3p0028* + ID_MODEL_FROM_DATABASE=RP-48 Combination Pushbutton-Rotary Module + +usb:v09F3p0048* + ID_MODEL_FROM_DATABASE=LGTII - Landing Gear and Trim Control Module + +usb:v09F3p0064* + ID_MODEL_FROM_DATABASE=MCPPro - Airliner Mode Control Panel (Autopilot) + +usb:v09F3p0300* + ID_MODEL_FROM_DATABASE=EFIS - Electronic Flight Information System + +usb:v09F5* + ID_VENDOR_FROM_DATABASE=AresCom + +usb:v09F5p0168* + ID_MODEL_FROM_DATABASE=Network Adapter + +usb:v09F5p0188* + ID_MODEL_FROM_DATABASE=LAN Adapter + +usb:v09F5p0850* + ID_MODEL_FROM_DATABASE=Adapter + +usb:v09F6* + ID_VENDOR_FROM_DATABASE=RocketChips, Inc. + +usb:v09F7* + ID_VENDOR_FROM_DATABASE=Edu-Science (H.K.), Ltd + +usb:v09F8* + ID_VENDOR_FROM_DATABASE=SoftConnex Technologies, Inc. + +usb:v09F9* + ID_VENDOR_FROM_DATABASE=Bay Associates + +usb:v09FA* + ID_VENDOR_FROM_DATABASE=Mtek Vision + +usb:v09FB* + ID_VENDOR_FROM_DATABASE=Altera + +usb:v09FBp6001* + ID_MODEL_FROM_DATABASE=Blaster + +usb:v09FF* + ID_VENDOR_FROM_DATABASE=Gain Technology Corp. + +usb:v0A00* + ID_VENDOR_FROM_DATABASE=Liquid Audio + +usb:v0A01* + ID_VENDOR_FROM_DATABASE=ViA, Inc. + +usb:v0A05* + ID_VENDOR_FROM_DATABASE=Unknown Manufacturer + +usb:v0A05p7211* + ID_MODEL_FROM_DATABASE=hub + +usb:v0A07* + ID_VENDOR_FROM_DATABASE=Ontrak Control Systems Inc. + +usb:v0A07p0064* + ID_MODEL_FROM_DATABASE=ADU100 Data Acquisition Interface + +usb:v0A07p0078* + ID_MODEL_FROM_DATABASE=ADU120 Data Acquisition Interface + +usb:v0A07p0082* + ID_MODEL_FROM_DATABASE=ADU130 Data Acquisition Interface + +usb:v0A07p00C8* + ID_MODEL_FROM_DATABASE=ADU200 Relay I/O Interface + +usb:v0A07p00D0* + ID_MODEL_FROM_DATABASE=ADU208 Relay I/O Interface + +usb:v0A07p00DA* + ID_MODEL_FROM_DATABASE=ADU218 Solid-State Relay I/O Interface + +usb:v0A0B* + ID_VENDOR_FROM_DATABASE=Cybex Computer Products Co. + +usb:v0A11* + ID_VENDOR_FROM_DATABASE=Xentec, Inc. + +usb:v0A12* + ID_VENDOR_FROM_DATABASE=Cambridge Silicon Radio, Ltd + +usb:v0A12p0001* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle (HCI mode) + +usb:v0A12p0002* + ID_MODEL_FROM_DATABASE=Frontline Test Equipment Bluetooth Device + +usb:v0A12p0003* + ID_MODEL_FROM_DATABASE=Nanosira + +usb:v0A12p0004* + ID_MODEL_FROM_DATABASE=Nanosira WHQL Reference Radio + +usb:v0A12p0005* + ID_MODEL_FROM_DATABASE=Nanosira-Multimedia + +usb:v0A12p0006* + ID_MODEL_FROM_DATABASE=Nanosira-Multimedia WHQL Reference Radio + +usb:v0A12p0007* + ID_MODEL_FROM_DATABASE=Nanosira3-ROM + +usb:v0A12p0008* + ID_MODEL_FROM_DATABASE=Nanosira3-ROM + +usb:v0A12p0009* + ID_MODEL_FROM_DATABASE=Nanosira4-EDR WHQL Reference Radio + +usb:v0A12p000A* + ID_MODEL_FROM_DATABASE=Nanosira4-EDR-ROM + +usb:v0A12p000B* + ID_MODEL_FROM_DATABASE=Nanosira5-ROM + +usb:v0A12p0043* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A12p0100* + ID_MODEL_FROM_DATABASE=Casira with BlueCore2-External Module + +usb:v0A12p0101* + ID_MODEL_FROM_DATABASE=Casira with BlueCore2-Flash Module + +usb:v0A12p0102* + ID_MODEL_FROM_DATABASE=Casira with BlueCore3-Multimedia Module + +usb:v0A12p0103* + ID_MODEL_FROM_DATABASE=Casira with BlueCore3-Flash Module + +usb:v0A12p0104* + ID_MODEL_FROM_DATABASE=Casira with BlueCore4-External Module + +usb:v0A12p0105* + ID_MODEL_FROM_DATABASE=Casira with BlueCore4-Multimedia Module + +usb:v0A12p1000* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle (HID proxy mode) + +usb:v0A12p1010* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A12p1011* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A12p1012* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A12pFFFF* + ID_MODEL_FROM_DATABASE=USB Bluetooth Device in DFU State + +usb:v0A13* + ID_VENDOR_FROM_DATABASE=Telebyte, Inc. + +usb:v0A14* + ID_VENDOR_FROM_DATABASE=Spacelabs Medical, Inc. + +usb:v0A15* + ID_VENDOR_FROM_DATABASE=Scalar Corp. + +usb:v0A16* + ID_VENDOR_FROM_DATABASE=Trek Technology (S) PTE, Ltd + +usb:v0A16p1111* + ID_MODEL_FROM_DATABASE=ThumbDrive + +usb:v0A16p8888* + ID_MODEL_FROM_DATABASE=IBM USB Memory Key + +usb:v0A16p9988* + ID_MODEL_FROM_DATABASE=Trek2000 TD-G2 + +usb:v0A17* + ID_VENDOR_FROM_DATABASE=Pentax Corp. + +usb:v0A17p0004* + ID_MODEL_FROM_DATABASE=Optio 330 + +usb:v0A17p0006* + ID_MODEL_FROM_DATABASE=Optio S + +usb:v0A17p0007* + ID_MODEL_FROM_DATABASE=Optio 550 + +usb:v0A17p0009* + ID_MODEL_FROM_DATABASE=Optio 33WR + +usb:v0A17p000A* + ID_MODEL_FROM_DATABASE=Optio 555 + +usb:v0A17p000C* + ID_MODEL_FROM_DATABASE=Optio 43WR (mass storage mode) + +usb:v0A17p000D* + ID_MODEL_FROM_DATABASE=Optio 43WR + +usb:v0A17p0015* + ID_MODEL_FROM_DATABASE=Optio S40/S5i + +usb:v0A17p003B* + ID_MODEL_FROM_DATABASE=Optio 50 (mass storage mode) + +usb:v0A17p003D* + ID_MODEL_FROM_DATABASE=Optio S55 + +usb:v0A17p0043* + ID_MODEL_FROM_DATABASE=*ist DL + +usb:v0A17p0047* + ID_MODEL_FROM_DATABASE=Optio S60 + +usb:v0A17p0052* + ID_MODEL_FROM_DATABASE=Optio 60 Digital Camera + +usb:v0A17p006E* + ID_MODEL_FROM_DATABASE=K10D + +usb:v0A17p0070* + ID_MODEL_FROM_DATABASE=K100D + +usb:v0A17p0093* + ID_MODEL_FROM_DATABASE=K200D + +usb:v0A17p00A7* + ID_MODEL_FROM_DATABASE=Optio E50 + +usb:v0A17p1001* + ID_MODEL_FROM_DATABASE=EI2000 Camera powered by Digita! + +usb:v0A18* + ID_VENDOR_FROM_DATABASE=Heidelberger Druckmaschinen AG + +usb:v0A19* + ID_VENDOR_FROM_DATABASE=Hua Geng Technologies, Inc. + +usb:v0A21* + ID_VENDOR_FROM_DATABASE=Medtronic Physio Control Corp. + +usb:v0A21p8001* + ID_MODEL_FROM_DATABASE=MMT-7305WW [Medtronic Minimed CareLink] + +usb:v0A22* + ID_VENDOR_FROM_DATABASE=Century Semiconductor USA, Inc. + +usb:v0A27* + ID_VENDOR_FROM_DATABASE=Datacard Group + +usb:v0A27p0102* + ID_MODEL_FROM_DATABASE=SP35 + +usb:v0A2C* + ID_VENDOR_FROM_DATABASE=AK-Modul-Bus Computer GmbH + +usb:v0A2Cp0008* + ID_MODEL_FROM_DATABASE=GPIO Ports + +usb:v0A34* + ID_VENDOR_FROM_DATABASE=TG3 Electronics, Inc. + +usb:v0A34p0101* + ID_MODEL_FROM_DATABASE=TG82tp + +usb:v0A34p0110* + ID_MODEL_FROM_DATABASE=Deck 82-key backlit keyboard + +usb:v0A35* + ID_VENDOR_FROM_DATABASE=Radikal Technologies + +usb:v0A35p002A* + ID_MODEL_FROM_DATABASE=SAC - Software Assigned Controller + +usb:v0A35p008A* + ID_MODEL_FROM_DATABASE=SAC Hub + +usb:v0A39* + ID_VENDOR_FROM_DATABASE=Gilat Satellite Networks, Ltd + +usb:v0A3A* + ID_VENDOR_FROM_DATABASE=PentaMedia Co., Ltd + +usb:v0A3Ap0163* + ID_MODEL_FROM_DATABASE=KN-W510U 1.0 Wireless LAN Adapter + +usb:v0A3C* + ID_VENDOR_FROM_DATABASE=NTT DoCoMo, Inc. + +usb:v0A3D* + ID_VENDOR_FROM_DATABASE=Varo Vision + +usb:v0A3F* + ID_VENDOR_FROM_DATABASE=Swissonic AG + +usb:v0A43* + ID_VENDOR_FROM_DATABASE=Boca Systems, Inc. + +usb:v0A46* + ID_VENDOR_FROM_DATABASE=Davicom Semiconductor, Inc. + +usb:v0A46p0268* + ID_MODEL_FROM_DATABASE=ST268 + +usb:v0A46p6688* + ID_MODEL_FROM_DATABASE=ZT6688 Fast Ethernet Adapter + +usb:v0A46p8515* + ID_MODEL_FROM_DATABASE=ADMtek ADM8515 NIC + +usb:v0A46p9000* + ID_MODEL_FROM_DATABASE=DM9000E Fast Ethernet Adapter + +usb:v0A46p9601* + ID_MODEL_FROM_DATABASE=DM9601 Fast Ethernet Adapter + +usb:v0A47* + ID_VENDOR_FROM_DATABASE=Hirose Electric + +usb:v0A48* + ID_VENDOR_FROM_DATABASE=I/O Interconnect + +usb:v0A48p3233* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v0A48p3239* + ID_MODEL_FROM_DATABASE=Multimedia Card Reader + +usb:v0A48p3258* + ID_MODEL_FROM_DATABASE=Dane Elec zMate SD Reader + +usb:v0A48p3259* + ID_MODEL_FROM_DATABASE=Dane Elec zMate CF Reader + +usb:v0A48p5000* + ID_MODEL_FROM_DATABASE=MediaGear xD-SM + +usb:v0A48p500A* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p500F* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5010* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5011* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5014* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5020* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5021* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5022* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5023* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5024* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A48p5025* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0A4B* + ID_VENDOR_FROM_DATABASE=Fujitsu Media Devices, Ltd + +usb:v0A4C* + ID_VENDOR_FROM_DATABASE=Computex Co., Ltd + +usb:v0A4Cp15D9* + ID_MODEL_FROM_DATABASE=OPTICAL MOUSE + +usb:v0A4D* + ID_VENDOR_FROM_DATABASE=Evolution Electronics, Ltd + +usb:v0A4Dp0064* + ID_MODEL_FROM_DATABASE=MK-225 Driver + +usb:v0A4Dp0065* + ID_MODEL_FROM_DATABASE=MK-225C Driver + +usb:v0A4Dp0066* + ID_MODEL_FROM_DATABASE=MK-225C Driver + +usb:v0A4Dp0067* + ID_MODEL_FROM_DATABASE=MK-425C Driver + +usb:v0A4Dp0078* + ID_MODEL_FROM_DATABASE=MK-37 Driver + +usb:v0A4Dp0079* + ID_MODEL_FROM_DATABASE=MK-37C Driver + +usb:v0A4Dp007A* + ID_MODEL_FROM_DATABASE=MK-37C Driver + +usb:v0A4Dp008C* + ID_MODEL_FROM_DATABASE=TerraTec MIDI MASTER + +usb:v0A4Dp008D* + ID_MODEL_FROM_DATABASE=MK-249C Driver + +usb:v0A4Dp008E* + ID_MODEL_FROM_DATABASE=MK-249C MIDI Keyboard + +usb:v0A4Dp008F* + ID_MODEL_FROM_DATABASE=MK-449C Driver + +usb:v0A4Dp0090* + ID_MODEL_FROM_DATABASE=Keystation 49e Driver + +usb:v0A4Dp0091* + ID_MODEL_FROM_DATABASE=Keystation 61es Driver + +usb:v0A4Dp00A0* + ID_MODEL_FROM_DATABASE=MK-361 Driver + +usb:v0A4Dp00A1* + ID_MODEL_FROM_DATABASE=MK-361C Driver + +usb:v0A4Dp00A2* + ID_MODEL_FROM_DATABASE=MK-361C Driver + +usb:v0A4Dp00A3* + ID_MODEL_FROM_DATABASE=MK-461C MIDI Keyboard + +usb:v0A4Dp00B5* + ID_MODEL_FROM_DATABASE=Keystation Pro 88 Driver + +usb:v0A4Dp00D2* + ID_MODEL_FROM_DATABASE=E-Keys Driver + +usb:v0A4Dp00F0* + ID_MODEL_FROM_DATABASE=UC-16 Driver + +usb:v0A4Dp00F1* + ID_MODEL_FROM_DATABASE=X-Session Driver + +usb:v0A4Dp00F5* + ID_MODEL_FROM_DATABASE=UC-33e MIDI Controller + +usb:v0A4E* + ID_VENDOR_FROM_DATABASE=Steinberg Soft-und Hardware GmbH + +usb:v0A4F* + ID_VENDOR_FROM_DATABASE=Litton Systems, Inc. + +usb:v0A50* + ID_VENDOR_FROM_DATABASE=Mimaki Engineering Co., Ltd + +usb:v0A51* + ID_VENDOR_FROM_DATABASE=Sony Electronics, Inc. + +usb:v0A52* + ID_VENDOR_FROM_DATABASE=Jebsee Electronics Co., Ltd + +usb:v0A53* + ID_VENDOR_FROM_DATABASE=Portable Peripheral Co., Ltd + +usb:v0A53p1000* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v0A53p2000* + ID_MODEL_FROM_DATABASE=Q-Scan A6 Scanner + +usb:v0A53p2001* + ID_MODEL_FROM_DATABASE=Q-Scan A6 Scanner + +usb:v0A53p2013* + ID_MODEL_FROM_DATABASE=Media Drive A6 Scanner + +usb:v0A53p2014* + ID_MODEL_FROM_DATABASE=Media Drive A6 Scanner + +usb:v0A53p2015* + ID_MODEL_FROM_DATABASE=BizCardReader 600C + +usb:v0A53p2016* + ID_MODEL_FROM_DATABASE=BizCardReader 600C + +usb:v0A53p202A* + ID_MODEL_FROM_DATABASE=Scanshell-CSSN + +usb:v0A53p3000* + ID_MODEL_FROM_DATABASE=Q-Scan A8 Scanner + +usb:v0A53p3002* + ID_MODEL_FROM_DATABASE=Q-Scan A8 Reader + +usb:v0A53p3015* + ID_MODEL_FROM_DATABASE=BizCardReader 300G + +usb:v0A53p302A* + ID_MODEL_FROM_DATABASE=LM9832 - PA570 Mini Business Card Scanner [Targus] + +usb:v0A53p5001* + ID_MODEL_FROM_DATABASE=BizCardReader 900C + +usb:v0A5A* + ID_VENDOR_FROM_DATABASE=Electronics For Imaging, Inc. + +usb:v0A5B* + ID_VENDOR_FROM_DATABASE=EAsics NV + +usb:v0A5C* + ID_VENDOR_FROM_DATABASE=Broadcom Corp. + +usb:v0A5Cp0201* + ID_MODEL_FROM_DATABASE=iLine10(tm) Network Adapter + +usb:v0A5Cp2000* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp2001* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp2009* + ID_MODEL_FROM_DATABASE=BCM2035 Bluetooth + +usb:v0A5Cp200A* + ID_MODEL_FROM_DATABASE=BCM2035 Bluetooth dongle + +usb:v0A5Cp200F* + ID_MODEL_FROM_DATABASE=Bluetooth Controller + +usb:v0A5Cp201D* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp201E* + ID_MODEL_FROM_DATABASE=IBM Integrated Bluetooth IV + +usb:v0A5Cp2020* + ID_MODEL_FROM_DATABASE=Bluetooth dongle + +usb:v0A5Cp2021* + ID_MODEL_FROM_DATABASE=BCM2035B3 Bluetooth Adapter + +usb:v0A5Cp2033* + ID_MODEL_FROM_DATABASE=BCM2033 Bluetooth + +usb:v0A5Cp2035* + ID_MODEL_FROM_DATABASE=BCM2035 Bluetooth + +usb:v0A5Cp2038* + ID_MODEL_FROM_DATABASE=Blutonium Device + +usb:v0A5Cp2039* + ID_MODEL_FROM_DATABASE=BCM2045 Bluetooth + +usb:v0A5Cp2045* + ID_MODEL_FROM_DATABASE=Bluetooth Controller + +usb:v0A5Cp2046* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp2047* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp205E* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0A5Cp2100* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0+eDR dongle + +usb:v0A5Cp2101* + ID_MODEL_FROM_DATABASE=BCM2045 Bluetooth + +usb:v0A5Cp2102* + ID_MODEL_FROM_DATABASE=ANYCOM Blue USB-200/250 + +usb:v0A5Cp2110* + ID_MODEL_FROM_DATABASE=BCM2045B (BDC-2) [Bluetooth Controller] + +usb:v0A5Cp2111* + ID_MODEL_FROM_DATABASE=ANYCOM Blue USB-UHE 200/250 + +usb:v0A5Cp2120* + ID_MODEL_FROM_DATABASE=2045 Bluetooth 2.0 USB-UHE Device with trace filter + +usb:v0A5Cp2121* + ID_MODEL_FROM_DATABASE=BCM2210 Bluetooth + +usb:v0A5Cp2122* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0+EDR dongle + +usb:v0A5Cp2123* + ID_MODEL_FROM_DATABASE=Bluetooth dongle + +usb:v0A5Cp2130* + ID_MODEL_FROM_DATABASE=2045 Bluetooth 2.0 USB-UHE Device with trace filter + +usb:v0A5Cp2131* + ID_MODEL_FROM_DATABASE=2045 Bluetooth 2.0 Device with trace filter + +usb:v0A5Cp2145* + ID_MODEL_FROM_DATABASE=BCM2045B (BDC-2.1) [Bluetooth Controller] + +usb:v0A5Cp2148* + ID_MODEL_FROM_DATABASE=BCM92046DG-CL1ROM Bluetooth 2.1 Adapter + +usb:v0A5Cp2150* + ID_MODEL_FROM_DATABASE=BCM2046 Bluetooth Device + +usb:v0A5Cp2151* + ID_MODEL_FROM_DATABASE=Bluetooth + +usb:v0A5Cp2154* + ID_MODEL_FROM_DATABASE=BCM92046DG-CL1ROM Bluetooth 2.1 UHE Dongle + +usb:v0A5Cp217D* + ID_MODEL_FROM_DATABASE=HP Bluethunder + +usb:v0A5Cp217F* + ID_MODEL_FROM_DATABASE=BCM2045B (BDC-2.1) + +usb:v0A5Cp2198* + ID_MODEL_FROM_DATABASE=Bluetooth 3.0 Device + +usb:v0A5Cp219B* + ID_MODEL_FROM_DATABASE=Bluetooth 2.1 Device + +usb:v0A5Cp21B1* + ID_MODEL_FROM_DATABASE=HP Bluetooth Module + +usb:v0A5Cp21B4* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21B9* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21BA* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21BB* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21BC* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21BD* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 2.1 + EDR + +usb:v0A5Cp21D7* + ID_MODEL_FROM_DATABASE=BCM43142 Bluetooth 4.0 + +usb:v0A5Cp21E1* + ID_MODEL_FROM_DATABASE=HP Portable SoftSailing + +usb:v0A5Cp21E3* + ID_MODEL_FROM_DATABASE=HP Portable Valentine + +usb:v0A5Cp21E6* + ID_MODEL_FROM_DATABASE=BCM20702 Bluetooth 4.0 [ThinkPad] + +usb:v0A5Cp21E8* + ID_MODEL_FROM_DATABASE=BCM20702A0 Bluetooth 4.0 + +usb:v0A5Cp21F1* + ID_MODEL_FROM_DATABASE=HP Portable Bumble Bee + +usb:v0A5Cp22BE* + ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth 3.0 + HS + +usb:v0A5Cp4500* + ID_MODEL_FROM_DATABASE=BCM2046B1 USB 2.0 Hub (part of BCM2046 Bluetooth) + +usb:v0A5Cp4502* + ID_MODEL_FROM_DATABASE=Keyboard (Boot Interface Subclass) + +usb:v0A5Cp4503* + ID_MODEL_FROM_DATABASE=Mouse (Boot Interface Subclass) + +usb:v0A5Cp5800* + ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor + +usb:v0A5Cp5801* + ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor with fingerprint swipe sensor + +usb:v0A5Cp5802* + ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor with fingerprint touch sensor + +usb:v0A5Cp5803* + ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor with secure keyboard + +usb:v0A5Cp6300* + ID_MODEL_FROM_DATABASE=Pirelli Remote NDIS Device + +usb:v0A5CpBD11* + ID_MODEL_FROM_DATABASE=TiVo AG0100 802.11bg Wireless Adapter [Broadcom BCM4320] + +usb:v0A5CpBD13* + ID_MODEL_FROM_DATABASE=BCM4323 802.11abgn Wireless Adapter + +usb:v0A5CpBD17* + ID_MODEL_FROM_DATABASE=BCM43236 802.11abgn Wireless Adapter + +usb:v0A5CpD11B* + ID_MODEL_FROM_DATABASE=Eminent EM4045 [Broadcom 4320 USB] + +usb:v0A5D* + ID_VENDOR_FROM_DATABASE=Diatrend Corp. + +usb:v0A5F* + ID_VENDOR_FROM_DATABASE=Zebra + +usb:v0A5Fp0009* + ID_MODEL_FROM_DATABASE=LP2844 Printer + +usb:v0A5Fp0081* + ID_MODEL_FROM_DATABASE=GK420t Label Printer + +usb:v0A5Fp008B* + ID_MODEL_FROM_DATABASE=HC100 wristbands Printer + +usb:v0A5Fp00D1* + ID_MODEL_FROM_DATABASE=Zebra GC420d Label Printer + +usb:v0A5Fp930A* + ID_MODEL_FROM_DATABASE=Printer + +usb:v0A62* + ID_VENDOR_FROM_DATABASE=MPMan + +usb:v0A62p0010* + ID_MODEL_FROM_DATABASE=MPMan MP-F40 MP3 Player + +usb:v0A66* + ID_VENDOR_FROM_DATABASE=ClearCube Technology + +usb:v0A67* + ID_VENDOR_FROM_DATABASE=Medeli Electronics Co., Ltd + +usb:v0A68* + ID_VENDOR_FROM_DATABASE=Comaide Corp. + +usb:v0A69* + ID_VENDOR_FROM_DATABASE=Chroma ate, Inc. + +usb:v0A6B* + ID_VENDOR_FROM_DATABASE=Green House Co., Ltd + +usb:v0A6Bp0001* + ID_MODEL_FROM_DATABASE=Compact Flash R/W with MP3 player + +usb:v0A6Bp000F* + ID_MODEL_FROM_DATABASE=FlashDisk + +usb:v0A6C* + ID_VENDOR_FROM_DATABASE=Integrated Circuit Systems, Inc. + +usb:v0A6D* + ID_VENDOR_FROM_DATABASE=UPS Manufacturing + +usb:v0A6E* + ID_VENDOR_FROM_DATABASE=Benwin + +usb:v0A6F* + ID_VENDOR_FROM_DATABASE=Core Technology, Inc. + +usb:v0A6Fp0400* + ID_MODEL_FROM_DATABASE=Xanboo + +usb:v0A70* + ID_VENDOR_FROM_DATABASE=International Game Technology + +usb:v0A71* + ID_VENDOR_FROM_DATABASE=VIPColor Technologies USA, Inc. + +usb:v0A71p0001* + ID_MODEL_FROM_DATABASE=VP485 Printer + +usb:v0A72* + ID_VENDOR_FROM_DATABASE=Sanwa Denshi + +usb:v0A73* + ID_VENDOR_FROM_DATABASE=Mackie Designs + +usb:v0A73p0002* + ID_MODEL_FROM_DATABASE=XD-2 [Spike] + +usb:v0A7D* + ID_VENDOR_FROM_DATABASE=NSTL, Inc. + +usb:v0A7E* + ID_VENDOR_FROM_DATABASE=Octagon Systems Corp. + +usb:v0A80* + ID_VENDOR_FROM_DATABASE=Rexon Technology Corp., Ltd + +usb:v0A81* + ID_VENDOR_FROM_DATABASE=Chesen Electronics Corp. + +usb:v0A81p0101* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0A81p0103* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0A81p0203* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0A81p0205* + ID_MODEL_FROM_DATABASE=PS/2 Keyboard+Mouse Adapter + +usb:v0A81p0701* + ID_MODEL_FROM_DATABASE=USB Missile Launcher + +usb:v0A81pFF01* + ID_MODEL_FROM_DATABASE=Wireless Missile Launcher + +usb:v0A82* + ID_VENDOR_FROM_DATABASE=Syscan + +usb:v0A82p4600* + ID_MODEL_FROM_DATABASE=TravelScan 460/464 + +usb:v0A83* + ID_VENDOR_FROM_DATABASE=NextComm, Inc. + +usb:v0A84* + ID_VENDOR_FROM_DATABASE=Maui Innovative Peripherals + +usb:v0A85* + ID_VENDOR_FROM_DATABASE=Idexx Labs + +usb:v0A86* + ID_VENDOR_FROM_DATABASE=NITGen Co., Ltd + +usb:v0A8D* + ID_VENDOR_FROM_DATABASE=Picturetel + +usb:v0A8E* + ID_VENDOR_FROM_DATABASE=Japan Aviation Electronics Industry, Ltd + +usb:v0A8Ep2011* + ID_MODEL_FROM_DATABASE=Filter Driver For JAE XMC R/W + +usb:v0A90* + ID_VENDOR_FROM_DATABASE=Candy Technology Co., Ltd + +usb:v0A91* + ID_VENDOR_FROM_DATABASE=Globlink Technology, Inc. + +usb:v0A91p3801* + ID_MODEL_FROM_DATABASE=Targus PAKP003 Mouse + +usb:v0A92* + ID_VENDOR_FROM_DATABASE=EGO SYStems, Inc. + +usb:v0A92p0011* + ID_MODEL_FROM_DATABASE=SYS WaveTerminal U2A + +usb:v0A92p0021* + ID_MODEL_FROM_DATABASE=GIGAPort + +usb:v0A92p0031* + ID_MODEL_FROM_DATABASE=GIGAPortAG + +usb:v0A92p0053* + ID_MODEL_FROM_DATABASE=AudioTrak Optoplay + +usb:v0A92p0061* + ID_MODEL_FROM_DATABASE=Waveterminal U24 + +usb:v0A92p0071* + ID_MODEL_FROM_DATABASE=MAYA EX7 + +usb:v0A92p0091* + ID_MODEL_FROM_DATABASE=Maya 44 + +usb:v0A92p00B1* + ID_MODEL_FROM_DATABASE=MAYA EX5 + +usb:v0A92p1000* + ID_MODEL_FROM_DATABASE=MIDI Mate + +usb:v0A92p1010* + ID_MODEL_FROM_DATABASE=RoMI/O + +usb:v0A92p1020* + ID_MODEL_FROM_DATABASE=M4U + +usb:v0A92p1030* + ID_MODEL_FROM_DATABASE=M8U + +usb:v0A92p1090* + ID_MODEL_FROM_DATABASE=KeyControl49 + +usb:v0A92p10A0* + ID_MODEL_FROM_DATABASE=KeyControl25 + +usb:v0A93* + ID_VENDOR_FROM_DATABASE=C Technologies AB + +usb:v0A93p0002* + ID_MODEL_FROM_DATABASE=C-Pen 10 + +usb:v0A93p0005* + ID_MODEL_FROM_DATABASE=MyPen Light + +usb:v0A93p000D* + ID_MODEL_FROM_DATABASE=Input Pen + +usb:v0A93p0010* + ID_MODEL_FROM_DATABASE=C-Pen 20 + +usb:v0A93p0A93* + ID_MODEL_FROM_DATABASE=PayPen + +usb:v0A94* + ID_VENDOR_FROM_DATABASE=Intersense + +usb:v0AA3* + ID_VENDOR_FROM_DATABASE=Lava Computer Mfg., Inc. + +usb:v0AA4* + ID_VENDOR_FROM_DATABASE=Develco Elektronik + +usb:v0AA5* + ID_VENDOR_FROM_DATABASE=First International Digital + +usb:v0AA5p0002* + ID_MODEL_FROM_DATABASE=irock! 500 Series + +usb:v0AA5p0801* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0AA6* + ID_VENDOR_FROM_DATABASE=Perception Digital, Ltd + +usb:v0AA6p0101* + ID_MODEL_FROM_DATABASE=Hercules Jukebox + +usb:v0AA6p1501* + ID_MODEL_FROM_DATABASE=Store 'n' Go HD Drive + +usb:v0AA7* + ID_VENDOR_FROM_DATABASE=Wincor Nixdorf International GmbH + +usb:v0AA7p0100* + ID_MODEL_FROM_DATABASE=POS Keyboard, TA58P-USB + +usb:v0AA7p0101* + ID_MODEL_FROM_DATABASE=POS Keyboard, TA85P-USB + +usb:v0AA7p0102* + ID_MODEL_FROM_DATABASE=POS Keyboard, TA59-USB + +usb:v0AA7p0103* + ID_MODEL_FROM_DATABASE=POS Keyboard, TA60-USB + +usb:v0AA7p0104* + ID_MODEL_FROM_DATABASE=SNIkey Keyboard, SNIKey-KB-USB + +usb:v0AA7p0200* + ID_MODEL_FROM_DATABASE=Operator Display, BA63-USB + +usb:v0AA7p0201* + ID_MODEL_FROM_DATABASE=Operator Display, BA66-USB + +usb:v0AA7p0202* + ID_MODEL_FROM_DATABASE=Operator Display & Scanner, XiCheck-BA63 + +usb:v0AA7p0203* + ID_MODEL_FROM_DATABASE=Operator Display & Scanner, XiCheck-BA66 + +usb:v0AA7p0204* + ID_MODEL_FROM_DATABASE=Graphics Operator Display, BA63GV + +usb:v0AA7p0300* + ID_MODEL_FROM_DATABASE=POS Printer (printer class mode), TH210 + +usb:v0AA7p0301* + ID_MODEL_FROM_DATABASE=POS Printer (native mode), TH210 + +usb:v0AA7p0302* + ID_MODEL_FROM_DATABASE=POS Printer (printer class mode), TH220 + +usb:v0AA7p0303* + ID_MODEL_FROM_DATABASE=POS Printer (native mode), TH220 + +usb:v0AA7p0304* + ID_MODEL_FROM_DATABASE=POS Printer, TH230 + +usb:v0AA7p0305* + ID_MODEL_FROM_DATABASE=Lottery Printer, XiPrintPlus + +usb:v0AA7p0306* + ID_MODEL_FROM_DATABASE=POS Printer (printer class mode), TH320 + +usb:v0AA7p0307* + ID_MODEL_FROM_DATABASE=POS Printer (native mode), TH320 + +usb:v0AA7p0308* + ID_MODEL_FROM_DATABASE=POS Printer (printer class mode), TH420 + +usb:v0AA7p0309* + ID_MODEL_FROM_DATABASE=POS Printer (native mode), TH420 + +usb:v0AA7p030A* + ID_MODEL_FROM_DATABASE=POS Printer, TH200B + +usb:v0AA7p0400* + ID_MODEL_FROM_DATABASE=Lottery Scanner, Xiscan S + +usb:v0AA7p0401* + ID_MODEL_FROM_DATABASE=Lottery Scanner, Xiscan 3 + +usb:v0AA7p0402* + ID_MODEL_FROM_DATABASE=Programmable Magnetic Swipe Card Reader, MSRP-USB + +usb:v0AA7p0500* + ID_MODEL_FROM_DATABASE=IDE Adapter + +usb:v0AA7p0501* + ID_MODEL_FROM_DATABASE=Hub Printer Interface + +usb:v0AA7p0502* + ID_MODEL_FROM_DATABASE=Hub SNIKey Keyboard + +usb:v0AA7p4304* + ID_MODEL_FROM_DATABASE=Banking Printer TP07 + +usb:v0AA7p4305* + ID_MODEL_FROM_DATABASE=Banking Printer TP07c + +usb:v0AA7p4500* + ID_MODEL_FROM_DATABASE=WN Central Special Electronics + +usb:v0AA8* + ID_VENDOR_FROM_DATABASE=TriGem Computer, Inc. + +usb:v0AA8p0060* + ID_MODEL_FROM_DATABASE=TG 11Mbps WLAN Mini Adapter + +usb:v0AA8p1001* + ID_MODEL_FROM_DATABASE=DreamComboM4100 + +usb:v0AA8p3002* + ID_MODEL_FROM_DATABASE=InkJet Color Printer + +usb:v0AA8p8001* + ID_MODEL_FROM_DATABASE=TG_iMON + +usb:v0AA8p8002* + ID_MODEL_FROM_DATABASE=TG_KLOSS + +usb:v0AA8pA001* + ID_MODEL_FROM_DATABASE=TG_X2 + +usb:v0AA8pA002* + ID_MODEL_FROM_DATABASE=TGVFD_KLOSS + +usb:v0AA8pFFDA* + ID_MODEL_FROM_DATABASE=iMON_VFD + +usb:v0AA9* + ID_VENDOR_FROM_DATABASE=Baromtec Co. + +usb:v0AA9pF01B* + ID_MODEL_FROM_DATABASE=Medion MD 6242 MP3 Player + +usb:v0AAA* + ID_VENDOR_FROM_DATABASE=Japan CBM Corp. + +usb:v0AAB* + ID_VENDOR_FROM_DATABASE=Vision Shape Europe SA + +usb:v0AAC* + ID_VENDOR_FROM_DATABASE=iCompression, Inc. + +usb:v0AAD* + ID_VENDOR_FROM_DATABASE=Rohde & Schwarz GmbH & Co. KG + +usb:v0AADp0003* + ID_MODEL_FROM_DATABASE=NRP-Z21 + +usb:v0AADp000C* + ID_MODEL_FROM_DATABASE=NRP-Z11 + +usb:v0AADp0013* + ID_MODEL_FROM_DATABASE=NRP-Z22 + +usb:v0AADp0014* + ID_MODEL_FROM_DATABASE=NRP-Z23 + +usb:v0AADp0015* + ID_MODEL_FROM_DATABASE=NRP-Z24 + +usb:v0AADp0016* + ID_MODEL_FROM_DATABASE=NRP-Z51 + +usb:v0AADp0017* + ID_MODEL_FROM_DATABASE=NRP-Z52 + +usb:v0AADp0018* + ID_MODEL_FROM_DATABASE=NRP-Z55 + +usb:v0AADp0019* + ID_MODEL_FROM_DATABASE=NRP-Z56 + +usb:v0AADp0021* + ID_MODEL_FROM_DATABASE=NRP-Z91 + +usb:v0AADp0023* + ID_MODEL_FROM_DATABASE=NRP-Z81 + +usb:v0AADp002C* + ID_MODEL_FROM_DATABASE=NRP-Z31 + +usb:v0AADp002D* + ID_MODEL_FROM_DATABASE=NRP-Z37 + +usb:v0AADp002F* + ID_MODEL_FROM_DATABASE=NRP-Z27 + +usb:v0AADp0051* + ID_MODEL_FROM_DATABASE=NRP-Z28 + +usb:v0AADp0052* + ID_MODEL_FROM_DATABASE=NRP-Z98 + +usb:v0AADp0062* + ID_MODEL_FROM_DATABASE=NRP-Z92 + +usb:v0AADp0070* + ID_MODEL_FROM_DATABASE=NRP-Z57 + +usb:v0AADp0083* + ID_MODEL_FROM_DATABASE=NRP-Z85 + +usb:v0AADp0095* + ID_MODEL_FROM_DATABASE=NRP-Z86 + +usb:v0AAE* + ID_VENDOR_FROM_DATABASE=NEC infrontia Corp. (Nitsuko) + +usb:v0AAF* + ID_VENDOR_FROM_DATABASE=Digitalway Co., Ltd + +usb:v0AB0* + ID_VENDOR_FROM_DATABASE=Arrow Strong Electronics Co., Ltd + +usb:v0AB1* + ID_VENDOR_FROM_DATABASE=FEIG ELECTRONIC GmbH + +usb:v0AB1p0002* + ID_MODEL_FROM_DATABASE=OBID RFID-Reader + +usb:v0ABA* + ID_VENDOR_FROM_DATABASE=Ellisys + +usb:v0ABAp8001* + ID_MODEL_FROM_DATABASE=Tracker 110 Protocol Analyzer + +usb:v0ABAp8002* + ID_MODEL_FROM_DATABASE=Explorer 200 Protocol Analyzer + +usb:v0ABE* + ID_VENDOR_FROM_DATABASE=Stereo-Link + +usb:v0ABEp0101* + ID_MODEL_FROM_DATABASE=SL1200 DAC + +usb:v0ABF* + ID_VENDOR_FROM_DATABASE=Diolan + +usb:v0ABFp3370* + ID_MODEL_FROM_DATABASE=I2C/SPI Adapter - U2C-12 + +usb:v0AC3* + ID_VENDOR_FROM_DATABASE=Sanyo Semiconductor Company Micro + +usb:v0AC4* + ID_VENDOR_FROM_DATABASE=Leco Corp. + +usb:v0AC5* + ID_VENDOR_FROM_DATABASE=I & C Corp. + +usb:v0AC6* + ID_VENDOR_FROM_DATABASE=Singing Electrons, Inc. + +usb:v0AC7* + ID_VENDOR_FROM_DATABASE=Panwest Corp. + +usb:v0AC8* + ID_VENDOR_FROM_DATABASE=Z-Star Microelectronics Corp. + +usb:v0AC8p0301* + ID_MODEL_FROM_DATABASE=Web Camera + +usb:v0AC8p0302* + ID_MODEL_FROM_DATABASE=ZC0302 Webcam + +usb:v0AC8p0321* + ID_MODEL_FROM_DATABASE=Vimicro generic vc0321 Camera + +usb:v0AC8p0323* + ID_MODEL_FROM_DATABASE=Luxya WC-1200 USB 2.0 Webcam + +usb:v0AC8p0328* + ID_MODEL_FROM_DATABASE=A4Tech PK-130MG + +usb:v0AC8p0336* + ID_MODEL_FROM_DATABASE=Elecom UCAM-DLQ30 + +usb:v0AC8p301B* + ID_MODEL_FROM_DATABASE=ZC0301 Webcam + +usb:v0AC8p303B* + ID_MODEL_FROM_DATABASE=ZC0303 Webcam + +usb:v0AC8p305B* + ID_MODEL_FROM_DATABASE=ZC0305 Webcam + +usb:v0AC8p307B* + ID_MODEL_FROM_DATABASE=USB 1.1 Webcam + +usb:v0AC8p332D* + ID_MODEL_FROM_DATABASE=Vega USB 2.0 Camera + +usb:v0AC8p3343* + ID_MODEL_FROM_DATABASE=Sirius USB 2.0 Camera + +usb:v0AC8p3370* + ID_MODEL_FROM_DATABASE=Traveler TV 6500 SF Dia-scanner + +usb:v0AC8p3420* + ID_MODEL_FROM_DATABASE=Venus USB2.0 Camera + +usb:v0AC8pC001* + ID_MODEL_FROM_DATABASE=Sony embedded vimicro Camera + +usb:v0AC8pC002* + ID_MODEL_FROM_DATABASE=Visual Communication Camera VGP-VCC1 + +usb:v0AC8pC302* + ID_MODEL_FROM_DATABASE=Vega USB 2.0 Camera + +usb:v0AC8pC303* + ID_MODEL_FROM_DATABASE=Saturn USB 2.0 Camera + +usb:v0AC8pC326* + ID_MODEL_FROM_DATABASE=Namuga 1.3M Webcam + +usb:v0AC8pC33F* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v0AC8pC429* + ID_MODEL_FROM_DATABASE=Lenovo ThinkCentre Web Camera + +usb:v0AC9* + ID_VENDOR_FROM_DATABASE=Micro Solutions, Inc. + +usb:v0AC9p0000* + ID_MODEL_FROM_DATABASE=Backpack CD-ReWriter + +usb:v0AC9p0001* + ID_MODEL_FROM_DATABASE=BACKPACK 2 Cable + +usb:v0AC9p0010* + ID_MODEL_FROM_DATABASE=BACKPACK + +usb:v0AC9p0011* + ID_MODEL_FROM_DATABASE=Backpack 40GB Hard Drive + +usb:v0AC9p0110* + ID_MODEL_FROM_DATABASE=BACKPACK + +usb:v0AC9p0111* + ID_MODEL_FROM_DATABASE=BackPack + +usb:v0AC9p1234* + ID_MODEL_FROM_DATABASE=BACKPACK + +usb:v0ACA* + ID_VENDOR_FROM_DATABASE=OPEN Networks Ltd + +usb:v0ACAp1060* + ID_MODEL_FROM_DATABASE=OPEN NT1 Plus II + +usb:v0ACC* + ID_VENDOR_FROM_DATABASE=Koga Electronics Co. + +usb:v0ACD* + ID_VENDOR_FROM_DATABASE=ID Tech + +usb:v0ACDp0300* + ID_MODEL_FROM_DATABASE=IDT1221U RS-232 Adapter + +usb:v0ACDp0401* + ID_MODEL_FROM_DATABASE=Spectrum III Hybrid Smartcard Reader + +usb:v0ACDp0630* + ID_MODEL_FROM_DATABASE=Spectrum III Mag-Only Insert Reader (SPT3-355 Series) USB-CDC + +usb:v0ACDp0810* + ID_MODEL_FROM_DATABASE=SecurePIN (IDPA-506100Y) PIN Pad + +usb:v0ACE* + ID_VENDOR_FROM_DATABASE=ZyDAS + +usb:v0ACEp1201* + ID_MODEL_FROM_DATABASE=ZD1201 802.11b + +usb:v0ACEp1211* + ID_MODEL_FROM_DATABASE=ZD1211 802.11g + +usb:v0ACEp1215* + ID_MODEL_FROM_DATABASE=ZD1211B 802.11g + +usb:v0ACEp1221* + ID_MODEL_FROM_DATABASE=ZD1221 802.11n + +usb:v0ACEp1602* + ID_MODEL_FROM_DATABASE=ZyXEL Omni FaxModem 56K + +usb:v0ACEp1608* + ID_MODEL_FROM_DATABASE=ZyXEL Omni FaxModem 56K UNO + +usb:v0ACEp1611* + ID_MODEL_FROM_DATABASE=ZyXEL Omni FaxModem 56K Plus + +usb:v0ACEp2011* + ID_MODEL_FROM_DATABASE=Virtual media for 802.11bg + +usb:v0ACEp20FF* + ID_MODEL_FROM_DATABASE=Virtual media for 802.11bg + +usb:v0ACEpA211* + ID_MODEL_FROM_DATABASE=ZD1211 802.11b/g Wireless Adapter + +usb:v0ACEpB215* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v0ACF* + ID_VENDOR_FROM_DATABASE=Intoto, Inc. + +usb:v0AD0* + ID_VENDOR_FROM_DATABASE=Intellix Corp. + +usb:v0AD1* + ID_VENDOR_FROM_DATABASE=Remotec Technology, Ltd + +usb:v0AD2* + ID_VENDOR_FROM_DATABASE=Service & Quality Technology Co., Ltd + +usb:v0ADA* + ID_VENDOR_FROM_DATABASE=Data Encryption Systems Ltd. + +usb:v0ADAp0005* + ID_MODEL_FROM_DATABASE=DK2 + +usb:v0AE3* + ID_VENDOR_FROM_DATABASE=Allion Computer, Inc. + +usb:v0AE4* + ID_VENDOR_FROM_DATABASE=Taito Corp. + +usb:v0AE7* + ID_VENDOR_FROM_DATABASE=Neodym Systems, Inc. + +usb:v0AE8* + ID_VENDOR_FROM_DATABASE=System Support Co., Ltd + +usb:v0AE9* + ID_VENDOR_FROM_DATABASE=North Shore Circuit Design L.L.P. + +usb:v0AEA* + ID_VENDOR_FROM_DATABASE=SciEssence, LLC + +usb:v0AEB* + ID_VENDOR_FROM_DATABASE=TTP Communications, Ltd + +usb:v0AEC* + ID_VENDOR_FROM_DATABASE=Neodio Technologies Corp. + +usb:v0AECp2101* + ID_MODEL_FROM_DATABASE=SmartMedia Card Reader + +usb:v0AECp2102* + ID_MODEL_FROM_DATABASE=CompactFlash Card Reader + +usb:v0AECp2103* + ID_MODEL_FROM_DATABASE=MMC/SD Card Reader + +usb:v0AECp2104* + ID_MODEL_FROM_DATABASE=MemoryStick Card Reader + +usb:v0AECp2201* + ID_MODEL_FROM_DATABASE=SmartMedia+CompactFlash Card Reader + +usb:v0AECp2202* + ID_MODEL_FROM_DATABASE=SmartMedia+MMC/SD Card Reader + +usb:v0AECp2203* + ID_MODEL_FROM_DATABASE=SmartMedia+MemoryStick Card Reader + +usb:v0AECp2204* + ID_MODEL_FROM_DATABASE=CompactFlash+MMC/SD Card Reader + +usb:v0AECp2205* + ID_MODEL_FROM_DATABASE=CompactFlash+MemoryStick Card Reader + +usb:v0AECp2206* + ID_MODEL_FROM_DATABASE=MMC/SD+MemoryStick Card Reader + +usb:v0AECp2301* + ID_MODEL_FROM_DATABASE=SmartMedia+CompactFlash+MMC/SD Card Reader + +usb:v0AECp2302* + ID_MODEL_FROM_DATABASE=SmartMedia+CompactFlash+MemoryStick Card Reader + +usb:v0AECp2303* + ID_MODEL_FROM_DATABASE=SmartMedia+MMC/SD+MemoryStick Card Reader + +usb:v0AECp2304* + ID_MODEL_FROM_DATABASE=CompactFlash+MMC/SD+MemoryStick Card Reader + +usb:v0AECp3016* + ID_MODEL_FROM_DATABASE=MMC/SD+Memory Stick Card Reader + +usb:v0AECp3050* + ID_MODEL_FROM_DATABASE=ND3050 8-in-1 Card Reader + +usb:v0AECp3060* + ID_MODEL_FROM_DATABASE=1.1 FS Card Reader + +usb:v0AECp3101* + ID_MODEL_FROM_DATABASE=MMC/SD Card Reader + +usb:v0AECp3102* + ID_MODEL_FROM_DATABASE=MemoryStick Card Reader + +usb:v0AECp3201* + ID_MODEL_FROM_DATABASE=MMC/SD+MemoryStick Card Reader + +usb:v0AECp3216* + ID_MODEL_FROM_DATABASE=HS Card Reader + +usb:v0AECp3260* + ID_MODEL_FROM_DATABASE=7-in-1 Card Reader + +usb:v0AECp5010* + ID_MODEL_FROM_DATABASE=ND5010 Card Reader + +usb:v0AF0* + ID_VENDOR_FROM_DATABASE=Option + +usb:v0AF0p5000* + ID_MODEL_FROM_DATABASE=UMTS Card + +usb:v0AF0p6000* + ID_MODEL_FROM_DATABASE=GlobeTrotter 3G datacard + +usb:v0AF0p6300* + ID_MODEL_FROM_DATABASE=GT 3G Quad UMTS/GPRS Card + +usb:v0AF0p6600* + ID_MODEL_FROM_DATABASE=GlobeTrotter 3G+ datacard + +usb:v0AF0p6711* + ID_MODEL_FROM_DATABASE=GlobeTrotter Express 7.2 v2 + +usb:v0AF0p6971* + ID_MODEL_FROM_DATABASE=Globetrotter HSDPA Modem + +usb:v0AF0p7251* + ID_MODEL_FROM_DATABASE=Globetrotter HSUPA Modem (aka iCON HSUPA E) + +usb:v0AF0p7501* + ID_MODEL_FROM_DATABASE=Globetrotter HSUPA Modem (icon 411 aka "Vodafone K3760") + +usb:v0AF0p7601* + ID_MODEL_FROM_DATABASE=Globetrotter MO40x 3G Modem (GTM 382) + +usb:v0AF0p7701* + ID_MODEL_FROM_DATABASE=Globetrotter HSUPA Modem (aka icon 451) + +usb:v0AF0pD055* + ID_MODEL_FROM_DATABASE=Globetrotter GI0505 [iCON 505] + +usb:v0AF6* + ID_VENDOR_FROM_DATABASE=Silver I Co., Ltd + +usb:v0AF7* + ID_VENDOR_FROM_DATABASE=B2C2, Inc. + +usb:v0AF7p0101* + ID_MODEL_FROM_DATABASE=Digital TV USB Receiver (DVB-S/T/C / ATSC) + +usb:v0AF9* + ID_VENDOR_FROM_DATABASE=Hama, Inc. + +usb:v0AF9p0010* + ID_MODEL_FROM_DATABASE=USB SightCam 100 + +usb:v0AF9p0011* + ID_MODEL_FROM_DATABASE=Micro Innovations IC50C Webcam + +usb:v0AFC* + ID_VENDOR_FROM_DATABASE=Zaptronix Ltd + +usb:v0AFD* + ID_VENDOR_FROM_DATABASE=Tateno Dennou, Inc. + +usb:v0AFE* + ID_VENDOR_FROM_DATABASE=Cummins Engine Co. + +usb:v0AFF* + ID_VENDOR_FROM_DATABASE=Jump Zone Network Products, Inc. + +usb:v0B00* + ID_VENDOR_FROM_DATABASE=INGENICO + +usb:v0B05* + ID_VENDOR_FROM_DATABASE=ASUSTek Computer, Inc. + +usb:v0B05p1101* + ID_MODEL_FROM_DATABASE=Mass Storage (UISDMC4S) + +usb:v0B05p1706* + ID_MODEL_FROM_DATABASE=WL-167G v1 802.11g Adapter [Ralink RT2571] + +usb:v0B05p1707* + ID_MODEL_FROM_DATABASE=WL-167G v1 802.11g Adapter [Ralink RT2571] + +usb:v0B05p1708* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0B05p170B* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0B05p170C* + ID_MODEL_FROM_DATABASE=WL-159g 802.11bg + +usb:v0B05p170D* + ID_MODEL_FROM_DATABASE=802.11b/g Wireless Network Adapter + +usb:v0B05p1712* + ID_MODEL_FROM_DATABASE=BT-183 Bluetooth 2.0+EDR adapter + +usb:v0B05p1715* + ID_MODEL_FROM_DATABASE=2045 Bluetooth 2.0 Device with trace filter + +usb:v0B05p1716* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0B05p1717* + ID_MODEL_FROM_DATABASE=WL169gE 802.11g Adapter [Broadcom 4320 USB] + +usb:v0B05p171B* + ID_MODEL_FROM_DATABASE=A9T wireless 802.11bg + +usb:v0B05p171C* + ID_MODEL_FROM_DATABASE=802.11b/g Wireless Network Adapter + +usb:v0B05p171F* + ID_MODEL_FROM_DATABASE=My Cinema U3000 Mini [DiBcom DiB7700P] + +usb:v0B05p1723* + ID_MODEL_FROM_DATABASE=WL-167G v2 802.11g Adapter [Ralink RT2571W] + +usb:v0B05p1724* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0B05p1726* + ID_MODEL_FROM_DATABASE=Laptop OLED Display + +usb:v0B05p172A* + ID_MODEL_FROM_DATABASE=ASUS 802.11n Network Adapter + +usb:v0B05p172B* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0B05p1731* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0B05p1732* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0B05p1734* + ID_MODEL_FROM_DATABASE=ASUS AF-200 + +usb:v0B05p173C* + ID_MODEL_FROM_DATABASE=BT-183 Bluetooth 2.0 + +usb:v0B05p173F* + ID_MODEL_FROM_DATABASE=My Cinema U3100 Mini + +usb:v0B05p1742* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0B05p1743* + ID_MODEL_FROM_DATABASE=Xonar U1 Audio Station + +usb:v0B05p1751* + ID_MODEL_FROM_DATABASE=BT-253 Bluetooth Adapter + +usb:v0B05p175B* + ID_MODEL_FROM_DATABASE=Laptop OLED Display + +usb:v0B05p1760* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter + +usb:v0B05p1761* + ID_MODEL_FROM_DATABASE=USB-N11 802.11n Network Adapter [Ralink RT2870] + +usb:v0B05p1774* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v0B05p1776* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v0B05p1779* + ID_MODEL_FROM_DATABASE=My Cinema U3100 Mini Plus [AF9035A] + +usb:v0B05p1784* + ID_MODEL_FROM_DATABASE=USB-N13 802.11n Network Adapter (rev. A1) [Ralink RT3072] + +usb:v0B05p1786* + ID_MODEL_FROM_DATABASE=USB-N10 802.11n Network Adapter [Realtek RTL8188SU] + +usb:v0B05p1791* + ID_MODEL_FROM_DATABASE=WL-167G v3 802.11n Adapter [Realtek RTL8188SU] + +usb:v0B05p179D* + ID_MODEL_FROM_DATABASE=USB-N53 802.11abgn Network Adapter [Ralink RT3572] + +usb:v0B05p179E* + ID_MODEL_FROM_DATABASE=Eee Note EA800 (network mode) + +usb:v0B05p179F* + ID_MODEL_FROM_DATABASE=Eee Note EA800 (tablet mode) + +usb:v0B05p17A1* + ID_MODEL_FROM_DATABASE=Eee Note EA800 (mass storage mode) + +usb:v0B05p17AB* + ID_MODEL_FROM_DATABASE=USB-N13 802.11n Network Adapter (rev. B1) [Realtek RTL8192CU] + +usb:v0B05p4C80* + ID_MODEL_FROM_DATABASE=Transformer Pad TF300TG + +usb:v0B05p4C90* + ID_MODEL_FROM_DATABASE=Transformer Pad Infinity TF700 + +usb:v0B05p4C91* + ID_MODEL_FROM_DATABASE=Transformer Pad Infinity TF700 (Debug mode) + +usb:v0B05p4D00* + ID_MODEL_FROM_DATABASE=Transformer Prime TF201 + +usb:v0B05p4D01* + ID_MODEL_FROM_DATABASE=Transformer Prime TF201 (debug mode) + +usb:v0B05p4DAF* + ID_MODEL_FROM_DATABASE=Transformer Pad Infinity TF700 (Fastboot) + +usb:v0B05p6101* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v0B05p620A* + ID_MODEL_FROM_DATABASE=Remote NDIS Device + +usb:v0B05pB700* + ID_MODEL_FROM_DATABASE=Broadcom Bluetooth 2.1 + +usb:v0B0B* + ID_VENDOR_FROM_DATABASE=Datamax-O'Neil + +usb:v0B0Bp106E* + ID_MODEL_FROM_DATABASE=Datamax E-4304 + +usb:v0B0C* + ID_VENDOR_FROM_DATABASE=Todos AB + +usb:v0B0Cp0009* + ID_MODEL_FROM_DATABASE=Todos Argos Mini II Smart Card Reader + +usb:v0B0Cp001E* + ID_MODEL_FROM_DATABASE=e.dentifier2 (ABN AMRO electronic banking card reader NL) + +usb:v0B0Cp002E* + ID_MODEL_FROM_DATABASE=C200 smartcard controller (Nordea card reader) + +usb:v0B0Cp003F* + ID_MODEL_FROM_DATABASE=Todos C400 smartcard controller (Handelsbanken card reader) + +usb:v0B0Cp0050* + ID_MODEL_FROM_DATABASE=Argos Mini II Smart Card Reader (CCID) + +usb:v0B0D* + ID_VENDOR_FROM_DATABASE=ProjectLab + +usb:v0B0Dp0000* + ID_MODEL_FROM_DATABASE=CenturyCD + +usb:v0B0E* + ID_VENDOR_FROM_DATABASE=GN Netcom + +usb:v0B0Ep0420* + ID_MODEL_FROM_DATABASE=Jabra SPEAK 510 + +usb:v0B0Ep1022* + ID_MODEL_FROM_DATABASE=Jabra PRO 9450, Type 9400BS (DECT Headset) + +usb:v0B0Ep620C* + ID_MODEL_FROM_DATABASE=Jabra BT620s + +usb:v0B0Ep9330* + ID_MODEL_FROM_DATABASE=Jabra GN9330 Headset + +usb:v0B0F* + ID_VENDOR_FROM_DATABASE=AVID Technology + +usb:v0B10* + ID_VENDOR_FROM_DATABASE=Pcally + +usb:v0B11* + ID_VENDOR_FROM_DATABASE=I Tech Solutions Co., Ltd + +usb:v0B1E* + ID_VENDOR_FROM_DATABASE=Electronic Warfare Assoc., Inc. (EWA) + +usb:v0B1Ep8007* + ID_MODEL_FROM_DATABASE=Blackhawk USB560-BP JTAG Emulator + +usb:v0B1F* + ID_VENDOR_FROM_DATABASE=Insyde Software Corp. + +usb:v0B20* + ID_VENDOR_FROM_DATABASE=TransDimension, Inc. + +usb:v0B21* + ID_VENDOR_FROM_DATABASE=Yokogawa Electric Corp. + +usb:v0B22* + ID_VENDOR_FROM_DATABASE=Japan System Development Co., Ltd + +usb:v0B23* + ID_VENDOR_FROM_DATABASE=Pan-Asia Electronics Co., Ltd + +usb:v0B24* + ID_VENDOR_FROM_DATABASE=Link Evolution Corp. + +usb:v0B27* + ID_VENDOR_FROM_DATABASE=Ritek Corp. + +usb:v0B28* + ID_VENDOR_FROM_DATABASE=Kenwood Corp. + +usb:v0B2C* + ID_VENDOR_FROM_DATABASE=Village Center, Inc. + +usb:v0B30* + ID_VENDOR_FROM_DATABASE=PNY Technologies, Inc. + +usb:v0B30p0006* + ID_MODEL_FROM_DATABASE=SM Media-Shuttle Card Reader + +usb:v0B33* + ID_VENDOR_FROM_DATABASE=Contour Design, Inc. + +usb:v0B33p0020* + ID_MODEL_FROM_DATABASE=ShuttleXpress + +usb:v0B37* + ID_VENDOR_FROM_DATABASE=Hitachi ULSI Systems Co., Ltd + +usb:v0B38* + ID_VENDOR_FROM_DATABASE=Gear Head + +usb:v0B38p0003* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0B38p0010* + ID_MODEL_FROM_DATABASE=107-Key Keyboard + +usb:v0B39* + ID_VENDOR_FROM_DATABASE=Omnidirectional Control Technology, Inc. + +usb:v0B39p0001* + ID_MODEL_FROM_DATABASE=Composite USB PS2 Converter + +usb:v0B39p0109* + ID_MODEL_FROM_DATABASE=USB TO Ethernet + +usb:v0B39p0421* + ID_MODEL_FROM_DATABASE=Serial + +usb:v0B39p0801* + ID_MODEL_FROM_DATABASE=USB-Parallel Bridge + +usb:v0B39p0901* + ID_MODEL_FROM_DATABASE=OCT To Fast Ethernet Converter + +usb:v0B39p0C03* + ID_MODEL_FROM_DATABASE=LAN DOCK Serial Converter + +usb:v0B3A* + ID_VENDOR_FROM_DATABASE=IPaxess + +usb:v0B3B* + ID_VENDOR_FROM_DATABASE=Tekram Technology Co., Ltd + +usb:v0B3Bp0163* + ID_MODEL_FROM_DATABASE=TL-WN320G 1.0 WLAN Adapter + +usb:v0B3Bp1601* + ID_MODEL_FROM_DATABASE=Allnet 0193 802.11b Adapter + +usb:v0B3Bp1602* + ID_MODEL_FROM_DATABASE=ZyXEL ZyAIR B200 802.11b Adapter + +usb:v0B3Bp1612* + ID_MODEL_FROM_DATABASE=AIR.Mate 2@net 802.11b Adapter + +usb:v0B3Bp1613* + ID_MODEL_FROM_DATABASE=802.11b Wireless LAN Adapter + +usb:v0B3Bp1620* + ID_MODEL_FROM_DATABASE=Allnet Wireless Network Adapter [Envara WiND512] + +usb:v0B3Bp1630* + ID_MODEL_FROM_DATABASE=QuickWLAN 802.11bg + +usb:v0B3Bp5630* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v0B3Bp6630* + ID_MODEL_FROM_DATABASE=ZD1211 + +usb:v0B3C* + ID_VENDOR_FROM_DATABASE=Olivetti Techcenter + +usb:v0B3CpA010* + ID_MODEL_FROM_DATABASE=Simple_Way Printer/Scanner/Copier + +usb:v0B3CpC000* + ID_MODEL_FROM_DATABASE=Olicard 100 + +usb:v0B3CpC700* + ID_MODEL_FROM_DATABASE=Olicard 100 (Mass Storage mode) + +usb:v0B3E* + ID_VENDOR_FROM_DATABASE=Kikusui Electronics Corp. + +usb:v0B41* + ID_VENDOR_FROM_DATABASE=Hal Corp. + +usb:v0B41p0011* + ID_MODEL_FROM_DATABASE=Crossam2+USB IR commander + +usb:v0B43* + ID_VENDOR_FROM_DATABASE=Play.com, Inc. + +usb:v0B43p0003* + ID_MODEL_FROM_DATABASE=PS2 Controller Converter + +usb:v0B43p0005* + ID_MODEL_FROM_DATABASE=GameCube Adaptor + +usb:v0B47* + ID_VENDOR_FROM_DATABASE=Sportbug.com, Inc. + +usb:v0B48* + ID_VENDOR_FROM_DATABASE=TechnoTrend AG + +usb:v0B48p1003* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge USB-Nova + +usb:v0B48p1004* + ID_MODEL_FROM_DATABASE=TT-PCline + +usb:v0B48p1005* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge USB-Nova + +usb:v0B48p1006* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DEC3000-s + +usb:v0B48p1007* + ID_MODEL_FROM_DATABASE=TT-micro plus Device + +usb:v0B48p1008* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DEC2000-t + +usb:v0B48p1009* + ID_MODEL_FROM_DATABASE=Technotrend/Hauppauge DEC2540-t + +usb:v0B48p3001* + ID_MODEL_FROM_DATABASE=DVB-S receiver + +usb:v0B48p3002* + ID_MODEL_FROM_DATABASE=DVB-C receiver + +usb:v0B48p3003* + ID_MODEL_FROM_DATABASE=DVB-T receiver + +usb:v0B48p3004* + ID_MODEL_FROM_DATABASE=TT TV-Stick + +usb:v0B48p3005* + ID_MODEL_FROM_DATABASE=TT TV-Stick (8kB EEPROM) + +usb:v0B48p3006* + ID_MODEL_FROM_DATABASE=TT-connect S-2400 DVB-S receiver + +usb:v0B48p3007* + ID_MODEL_FROM_DATABASE=TT-connect S2-3600 + +usb:v0B48p3008* + ID_MODEL_FROM_DATABASE=TT-connect + +usb:v0B48p3009* + ID_MODEL_FROM_DATABASE=TT-connect S-2400 DVB-S receiver (8kB EEPROM) + +usb:v0B48p300A* + ID_MODEL_FROM_DATABASE=TT-connect S2-3650 CI + +usb:v0B48p300B* + ID_MODEL_FROM_DATABASE=TT-connect C-3650 CI + +usb:v0B48p300C* + ID_MODEL_FROM_DATABASE=TT-connect T-3650 CI + +usb:v0B48p300D* + ID_MODEL_FROM_DATABASE=TT-connect CT-3650 CI + +usb:v0B48p300E* + ID_MODEL_FROM_DATABASE=TT-connect C-2400 + +usb:v0B49* + ID_VENDOR_FROM_DATABASE=ASCII Corp. + +usb:v0B49p064F* + ID_MODEL_FROM_DATABASE=Trance Vibrator + +usb:v0B4B* + ID_VENDOR_FROM_DATABASE=Pine Corp. Ltd. + +usb:v0B4Bp0100* + ID_MODEL_FROM_DATABASE=D'music MP3 Player + +usb:v0B4D* + ID_VENDOR_FROM_DATABASE=Graphtec America, Inc. + +usb:v0B4Dp110A* + ID_MODEL_FROM_DATABASE=Graphtec CC200-20 + +usb:v0B4E* + ID_VENDOR_FROM_DATABASE=Musical Electronics, Ltd + +usb:v0B4Ep6500* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0B4Ep8028* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0B4Ep8920* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0B50* + ID_VENDOR_FROM_DATABASE=Dumpries Co., Ltd + +usb:v0B51* + ID_VENDOR_FROM_DATABASE=Comfort Keyboard Co. + +usb:v0B51p0020* + ID_MODEL_FROM_DATABASE=Comfort Keyboard + +usb:v0B52* + ID_VENDOR_FROM_DATABASE=Colorado MicroDisplay, Inc. + +usb:v0B54* + ID_VENDOR_FROM_DATABASE=Sinbon Electronics Co., Ltd + +usb:v0B56* + ID_VENDOR_FROM_DATABASE=TYI Systems, Ltd + +usb:v0B57* + ID_VENDOR_FROM_DATABASE=Beijing HanwangTechnology Co., Ltd + +usb:v0B59* + ID_VENDOR_FROM_DATABASE=Lake Communications, Ltd + +usb:v0B5A* + ID_VENDOR_FROM_DATABASE=Corel Corp. + +usb:v0B5F* + ID_VENDOR_FROM_DATABASE=Green Electronics Co., Ltd + +usb:v0B60* + ID_VENDOR_FROM_DATABASE=Nsine, Ltd + +usb:v0B61* + ID_VENDOR_FROM_DATABASE=NEC Viewtechnology, Ltd + +usb:v0B62* + ID_VENDOR_FROM_DATABASE=Orange Micro, Inc. + +usb:v0B62p000B* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0B62p0059* + ID_MODEL_FROM_DATABASE=iBOT2 Webcam + +usb:v0B63* + ID_VENDOR_FROM_DATABASE=ADLink Technology, Inc. + +usb:v0B64* + ID_VENDOR_FROM_DATABASE=Wonderful Wire Cable Co., Ltd + +usb:v0B65* + ID_VENDOR_FROM_DATABASE=Expert Magnetics Corp. + +usb:v0B66* + ID_VENDOR_FROM_DATABASE=Cybiko Inc. + +usb:v0B66p0041* + ID_MODEL_FROM_DATABASE=Xtreme + +usb:v0B67* + ID_VENDOR_FROM_DATABASE=Fairbanks Scales + +usb:v0B67p555E* + ID_MODEL_FROM_DATABASE=SCB-R9000 + +usb:v0B69* + ID_VENDOR_FROM_DATABASE=CacheVision + +usb:v0B6A* + ID_VENDOR_FROM_DATABASE=Maxim Integrated Products + +usb:v0B6ApA132* + ID_MODEL_FROM_DATABASE=WUP-005 [Nintendo Wii U Pro Controller] + +usb:v0B6F* + ID_VENDOR_FROM_DATABASE=Nagano Japan Radio Co., Ltd + +usb:v0B70* + ID_VENDOR_FROM_DATABASE=PortalPlayer, Inc. + +usb:v0B70p00BA* + ID_MODEL_FROM_DATABASE=iRiver H10 20GB + +usb:v0B71* + ID_VENDOR_FROM_DATABASE=SHIN-EI Sangyo Co., Ltd + +usb:v0B72* + ID_VENDOR_FROM_DATABASE=Embedded Wireless Technology Co., Ltd + +usb:v0B73* + ID_VENDOR_FROM_DATABASE=Computone Corp. + +usb:v0B75* + ID_VENDOR_FROM_DATABASE=Roland DG Corp. + +usb:v0B79* + ID_VENDOR_FROM_DATABASE=Sunrise Telecom, Inc. + +usb:v0B7A* + ID_VENDOR_FROM_DATABASE=Zeevo, Inc. + +usb:v0B7Ap07D0* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0B7B* + ID_VENDOR_FROM_DATABASE=Taiko Denki Co., Ltd + +usb:v0B7C* + ID_VENDOR_FROM_DATABASE=ITRAN Communications, Ltd + +usb:v0B7D* + ID_VENDOR_FROM_DATABASE=Astrodesign, Inc. + +usb:v0B81* + ID_VENDOR_FROM_DATABASE=id3 Semiconductors + +usb:v0B81p0001* + ID_MODEL_FROM_DATABASE=Biothentic II smartcard reader with fingerprint sensor + +usb:v0B81p0002* + ID_MODEL_FROM_DATABASE=DFU-Enabled Devices (DFU) + +usb:v0B81p0012* + ID_MODEL_FROM_DATABASE=BioPAD biometric module (DFU + CDC) + +usb:v0B81p0102* + ID_MODEL_FROM_DATABASE=Certis V1 fingerprint reader + +usb:v0B81p0103* + ID_MODEL_FROM_DATABASE=Certis V2 fingerprint reader + +usb:v0B81p0200* + ID_MODEL_FROM_DATABASE=CL1356T / CL1356T5 / CL1356A smartcard readers (CCID) + +usb:v0B81p0201* + ID_MODEL_FROM_DATABASE=CL1356T / CL1356T5 / CL1356A smartcard readers (DFU + CCID) + +usb:v0B81p0220* + ID_MODEL_FROM_DATABASE=CL1356A FFPJP smartcard reader (CCID + HID) + +usb:v0B81p0221* + ID_MODEL_FROM_DATABASE=CL1356A smartcard reader (DFU + CCID + HID) + +usb:v0B84* + ID_VENDOR_FROM_DATABASE=Rextron Technology, Inc. + +usb:v0B85* + ID_VENDOR_FROM_DATABASE=Elkat Electronics, Sdn., Bhd. + +usb:v0B86* + ID_VENDOR_FROM_DATABASE=Exputer Systems, Inc. + +usb:v0B86p5100* + ID_MODEL_FROM_DATABASE=XMC5100 Zippy Drive + +usb:v0B86p5110* + ID_MODEL_FROM_DATABASE=XMC5110 Flash Drive + +usb:v0B86p5200* + ID_MODEL_FROM_DATABASE=XMC5200 Zippy Drive + +usb:v0B86p5201* + ID_MODEL_FROM_DATABASE=XMC5200 Zippy Drive + +usb:v0B86p5202* + ID_MODEL_FROM_DATABASE=XMC5200 Zippy Drive + +usb:v0B86p5280* + ID_MODEL_FROM_DATABASE=XMC5280 Storage Drive + +usb:v0B86pFFF0* + ID_MODEL_FROM_DATABASE=ISP5200 Debugger + +usb:v0B87* + ID_VENDOR_FROM_DATABASE=Plus-One I & T, Inc. + +usb:v0B88* + ID_VENDOR_FROM_DATABASE=Sigma Koki Co., Ltd, Technology Center + +usb:v0B89* + ID_VENDOR_FROM_DATABASE=Advanced Digital Broadcast, Ltd + +usb:v0B8C* + ID_VENDOR_FROM_DATABASE=SMART Technologies Inc. + +usb:v0B8Cp0001* + ID_MODEL_FROM_DATABASE=Interactive Whiteboard Controller (SB6) (HID) + +usb:v0B8Cp00C3* + ID_MODEL_FROM_DATABASE=Sympodium ID350 + +usb:v0B95* + ID_VENDOR_FROM_DATABASE=ASIX Electronics Corp. + +usb:v0B95p1720* + ID_MODEL_FROM_DATABASE=10/100 Ethernet + +usb:v0B95p1780* + ID_MODEL_FROM_DATABASE=AX88178 + +usb:v0B95p7720* + ID_MODEL_FROM_DATABASE=AX88772 + +usb:v0B95p772A* + ID_MODEL_FROM_DATABASE=AX88772A Fast Ethernet + +usb:v0B95p772B* + ID_MODEL_FROM_DATABASE=AX88772B + +usb:v0B95p7E2B* + ID_MODEL_FROM_DATABASE=AX88772B + +usb:v0B96* + ID_VENDOR_FROM_DATABASE=Sewon Telecom + +usb:v0B97* + ID_VENDOR_FROM_DATABASE=O2 Micro, Inc. + +usb:v0B97p7732* + ID_MODEL_FROM_DATABASE=Smart Card Reader + +usb:v0B97p7761* + ID_MODEL_FROM_DATABASE=Oz776 1.1 Hub + +usb:v0B97p7762* + ID_MODEL_FROM_DATABASE=Oz776 SmartCard Reader + +usb:v0B97p7772* + ID_MODEL_FROM_DATABASE=OZ776 CCID Smartcard Reader + +usb:v0B98* + ID_VENDOR_FROM_DATABASE=Playmates Toys, Inc. + +usb:v0B99* + ID_VENDOR_FROM_DATABASE=Audio International, Inc. + +usb:v0B9B* + ID_VENDOR_FROM_DATABASE=Dipl.-Ing. Stefan Kunde + +usb:v0B9Bp4012* + ID_MODEL_FROM_DATABASE=Reflex RC-controller Interface + +usb:v0B9D* + ID_VENDOR_FROM_DATABASE=Softprotec Co. + +usb:v0B9F* + ID_VENDOR_FROM_DATABASE=Chippo Technologies + +usb:v0BAF* + ID_VENDOR_FROM_DATABASE=U.S. Robotics + +usb:v0BAFp00E5* + ID_MODEL_FROM_DATABASE=USR6000 + +usb:v0BAFp00EB* + ID_MODEL_FROM_DATABASE=USR1120 802.11b Adapter + +usb:v0BAFp00EC* + ID_MODEL_FROM_DATABASE=56K Faxmodem + +usb:v0BAFp00F1* + ID_MODEL_FROM_DATABASE=SureConnect ADSL ATM Adapter + +usb:v0BAFp00F2* + ID_MODEL_FROM_DATABASE=SureConnect ADSL Loader + +usb:v0BAFp00F5* + ID_MODEL_FROM_DATABASE=SureConnect ADSL ATM Adapter + +usb:v0BAFp00F6* + ID_MODEL_FROM_DATABASE=SureConnect ADSL Loader + +usb:v0BAFp00F7* + ID_MODEL_FROM_DATABASE=SureConnect ADSL ATM Adapter + +usb:v0BAFp00F8* + ID_MODEL_FROM_DATABASE=SureConnect ADSL Loader + +usb:v0BAFp00F9* + ID_MODEL_FROM_DATABASE=SureConnect ADSL ATM Adapter + +usb:v0BAFp00FA* + ID_MODEL_FROM_DATABASE=SureConnect ADSL Loader + +usb:v0BAFp00FB* + ID_MODEL_FROM_DATABASE=SureConnect ADSL Ethernet/USB Router + +usb:v0BAFp0111* + ID_MODEL_FROM_DATABASE=USR5420 802.11g Adapter [Broadcom 4320 USB] + +usb:v0BAFp0118* + ID_MODEL_FROM_DATABASE=U5 802.11g Adapter + +usb:v0BAFp011B* + ID_MODEL_FROM_DATABASE=Wireless MAXg Adapter [Broadcom 4320] + +usb:v0BAFp0121* + ID_MODEL_FROM_DATABASE=USR5423 802.11bg Wireless Adapter [ZyDAS ZD1211B] + +usb:v0BAFp6112* + ID_MODEL_FROM_DATABASE=FaxModem Model 5633 + +usb:v0BB0* + ID_VENDOR_FROM_DATABASE=Concord Camera Corp. + +usb:v0BB0p0100* + ID_MODEL_FROM_DATABASE=Sound Vision Stream + +usb:v0BB0p5007* + ID_MODEL_FROM_DATABASE=3340z/Rollei DC3100 + +usb:v0BB1* + ID_VENDOR_FROM_DATABASE=Infinilink Corp. + +usb:v0BB2* + ID_VENDOR_FROM_DATABASE=Ambit Microsystems Corp. + +usb:v0BB2p0302* + ID_MODEL_FROM_DATABASE=U10H010 802.11b Wireless Adapter [Intersil PRISM 3] + +usb:v0BB2p6098* + ID_MODEL_FROM_DATABASE=USB Cable Modem + +usb:v0BB3* + ID_VENDOR_FROM_DATABASE=Ofuji Technology + +usb:v0BB4* + ID_VENDOR_FROM_DATABASE=HTC (High Tech Computer Corp.) + +usb:v0BB4p00CE* + ID_MODEL_FROM_DATABASE=mmO2 XDA GSM/GPRS Pocket PC + +usb:v0BB4p00CF* + ID_MODEL_FROM_DATABASE=SPV C500 Smart Phone + +usb:v0BB4p0A01* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A02* + ID_MODEL_FROM_DATABASE=Himalaya GSM/GPRS Pocket PC + +usb:v0BB4p0A03* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A04* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A05* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A06* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A07* + ID_MODEL_FROM_DATABASE=Magician PocketPC SmartPhone / O2 XDA + +usb:v0BB4p0A08* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A09* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0A* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0B* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0C* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0D* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0E* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A0F* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A10* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A11* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A12* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A13* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A14* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A15* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A16* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A17* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A18* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A19* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1A* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1B* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1C* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1D* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1E* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A1F* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A20* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A21* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A22* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A23* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A24* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A25* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A26* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A27* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A28* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A29* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2A* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2B* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2C* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2D* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2E* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A2F* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A30* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A31* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A32* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A33* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A34* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A35* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A36* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A37* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A38* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A39* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3A* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3B* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3C* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3D* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3E* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A3F* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A40* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A41* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A42* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A43* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A44* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A45* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A46* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A47* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A48* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A49* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4A* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4B* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4C* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4D* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4E* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A4F* + ID_MODEL_FROM_DATABASE=PocketPC Sync + +usb:v0BB4p0A50* + ID_MODEL_FROM_DATABASE=SmartPhone (MTP) + +usb:v0BB4p0A51* + ID_MODEL_FROM_DATABASE=SPV C400 / T-Mobile SDA GSM/GPRS Pocket PC + +usb:v0BB4p0A52* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A53* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A54* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A55* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A56* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A57* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A58* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A59* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5A* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5B* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5C* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5D* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5E* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A5F* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A60* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A61* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A62* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A63* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A64* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A65* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A66* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A67* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A68* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A69* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6A* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6B* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6C* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6D* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6E* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A6F* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A70* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A71* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A72* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A73* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A74* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A75* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A76* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A77* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A78* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A79* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7A* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7B* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7C* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7D* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7E* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A7F* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A80* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A81* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A82* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A83* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A84* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A85* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A86* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A87* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A88* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A89* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8A* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8B* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8C* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8D* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8E* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A8F* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A90* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A91* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A92* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A93* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A94* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A95* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A96* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A97* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A98* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A99* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9A* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9B* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9C* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9D* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9E* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0A9F* + ID_MODEL_FROM_DATABASE=SmartPhone Sync + +usb:v0BB4p0B03* + ID_MODEL_FROM_DATABASE=Ozone Mobile Broadband + +usb:v0BB4p0B04* + ID_MODEL_FROM_DATABASE=Hermes / TyTN / T-Mobile MDA Vario II / O2 Xda Trion + +usb:v0BB4p0B05* + ID_MODEL_FROM_DATABASE=P3600 + +usb:v0BB4p0B06* + ID_MODEL_FROM_DATABASE=Athena / Advantage x7500 / Dopod U1000 / T-Mobile AMEO + +usb:v0BB4p0B0C* + ID_MODEL_FROM_DATABASE=Elf / Touch / P3450 / T-Mobile MDA Touch / O2 Xda Nova / Dopod S1 + +usb:v0BB4p0B1F* + ID_MODEL_FROM_DATABASE=Sony Ericsson XPERIA X1 + +usb:v0BB4p0B2F* + ID_MODEL_FROM_DATABASE=Rhodium + +usb:v0BB4p0B51* + ID_MODEL_FROM_DATABASE=Qtek 8310 mobile phone [Tornado Noble] + +usb:v0BB4p0BCE* + ID_MODEL_FROM_DATABASE=Vario MDA + +usb:v0BB4p0C01* + ID_MODEL_FROM_DATABASE=Dream / ADP1 / G1 / Magic / Tattoo + +usb:v0BB4p0C02* + ID_MODEL_FROM_DATABASE=Dream / ADP1 / G1 / Magic / Tattoo (Debug) + +usb:v0BB4p0C13* + ID_MODEL_FROM_DATABASE=Diamond + +usb:v0BB4p0C1F* + ID_MODEL_FROM_DATABASE=Sony Ericsson XPERIA X1 + +usb:v0BB4p0C5F* + ID_MODEL_FROM_DATABASE=Snap + +usb:v0BB4p0C86* + ID_MODEL_FROM_DATABASE=Sensation + +usb:v0BB4p0C87* + ID_MODEL_FROM_DATABASE=Desire (debug) + +usb:v0BB4p0C8D* + ID_MODEL_FROM_DATABASE=EVO 4G (debug) + +usb:v0BB4p0C91* + ID_MODEL_FROM_DATABASE=Vision + +usb:v0BB4p0C94* + ID_MODEL_FROM_DATABASE=Vision + +usb:v0BB4p0C97* + ID_MODEL_FROM_DATABASE=Legend + +usb:v0BB4p0C99* + ID_MODEL_FROM_DATABASE=Desire (debug) + +usb:v0BB4p0C9E* + ID_MODEL_FROM_DATABASE=Incredible + +usb:v0BB4p0CA2* + ID_MODEL_FROM_DATABASE=Desire HD (debug mode) + +usb:v0BB4p0CA5* + ID_MODEL_FROM_DATABASE=Android Phone [Evo Shift 4G] + +usb:v0BB4p0FF8* + ID_MODEL_FROM_DATABASE=Desire HD (Tethering Mode) + +usb:v0BB4p0FF9* + ID_MODEL_FROM_DATABASE=Desire / Desire HD / Hero / Thunderbolt (Charge Mode) + +usb:v0BB4p0FFE* + ID_MODEL_FROM_DATABASE=Desire HD (modem mode) + +usb:v0BB4p0FFF* + ID_MODEL_FROM_DATABASE=Android Fastboot Bootloader + +usb:v0BB5* + ID_VENDOR_FROM_DATABASE=Murata Manufacturing Co., Ltd + +usb:v0BB6* + ID_VENDOR_FROM_DATABASE=Network Alchemy + +usb:v0BB7* + ID_VENDOR_FROM_DATABASE=Joytech Computer Co., Ltd + +usb:v0BB8* + ID_VENDOR_FROM_DATABASE=Hitachi Semiconductor and Devices Sales Co., Ltd + +usb:v0BB9* + ID_VENDOR_FROM_DATABASE=Eiger M&C Co., Ltd + +usb:v0BBA* + ID_VENDOR_FROM_DATABASE=ZAccess Systems + +usb:v0BBB* + ID_VENDOR_FROM_DATABASE=General Meters Corp. + +usb:v0BBC* + ID_VENDOR_FROM_DATABASE=Assistive Technology, Inc. + +usb:v0BBD* + ID_VENDOR_FROM_DATABASE=System Connection, Inc. + +usb:v0BC0* + ID_VENDOR_FROM_DATABASE=Knilink Technology, Inc. + +usb:v0BC1* + ID_VENDOR_FROM_DATABASE=Fuw Yng Electronics Co., Ltd + +usb:v0BC2* + ID_VENDOR_FROM_DATABASE=Seagate RSS LLC + +usb:v0BC2p0502* + ID_MODEL_FROM_DATABASE=ST3300601CB-RK 300 GB External Hard Drive + +usb:v0BC2p0503* + ID_MODEL_FROM_DATABASE=ST3250824A [Barracuda 7200.9] + +usb:v0BC2p2000* + ID_MODEL_FROM_DATABASE=Storage Adapter V3 (TPP) + +usb:v0BC2p2100* + ID_MODEL_FROM_DATABASE=FreeAgent Go + +usb:v0BC2p2200* + ID_MODEL_FROM_DATABASE=FreeAgent Go FW + +usb:v0BC2p2300* + ID_MODEL_FROM_DATABASE=Expansion Portable + +usb:v0BC2p2320* + ID_MODEL_FROM_DATABASE=USB 3.0 bridge [Portable Expansion Drive] + +usb:v0BC2p3008* + ID_MODEL_FROM_DATABASE=FreeAgent Desk 1TB + +usb:v0BC2p3320* + ID_MODEL_FROM_DATABASE=SRD00F2 [Expansion Desktop Drive] + +usb:v0BC2p3332* + ID_MODEL_FROM_DATABASE=Expansion + +usb:v0BC2p5021* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex USB 2.0 + +usb:v0BC2p5031* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex USB 3.0 + +usb:v0BC2p50A1* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex Desk + +usb:v0BC2p50A5* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex Desk USB 3.0 + +usb:v0BC2p5121* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex + +usb:v0BC2p5161* + ID_MODEL_FROM_DATABASE=FreeAgent GoFlex dock + +usb:v0BC2pA003* + ID_MODEL_FROM_DATABASE=Backup Plus + +usb:v0BC2pA0A1* + ID_MODEL_FROM_DATABASE=Backup Plus Desktop + +usb:v0BC2pA0A4* + ID_MODEL_FROM_DATABASE=Backup Plus Desktop Drive + +usb:v0BC3* + ID_VENDOR_FROM_DATABASE=IPWireless, Inc. + +usb:v0BC3p0001* + ID_MODEL_FROM_DATABASE=UMTS-TDD (TD-CDMA) modem + +usb:v0BC4* + ID_VENDOR_FROM_DATABASE=Microcube Corp. + +usb:v0BC5* + ID_VENDOR_FROM_DATABASE=JCN Co., Ltd + +usb:v0BC6* + ID_VENDOR_FROM_DATABASE=ExWAY, Inc. + +usb:v0BC7* + ID_VENDOR_FROM_DATABASE=X10 Wireless Technology, Inc. + +usb:v0BC7p0001* + ID_MODEL_FROM_DATABASE=ActiveHome (ACPI-compliant) + +usb:v0BC7p0002* + ID_MODEL_FROM_DATABASE=Firecracker Interface (ACPI-compliant) + +usb:v0BC7p0003* + ID_MODEL_FROM_DATABASE=VGA Video Sender (ACPI-compliant) + +usb:v0BC7p0004* + ID_MODEL_FROM_DATABASE=X10 Receiver + +usb:v0BC7p0005* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p0006* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p0007* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p0008* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p0009* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p000A* + ID_MODEL_FROM_DATABASE=Wireless Transceiver (ACPI-compliant) + +usb:v0BC7p000B* + ID_MODEL_FROM_DATABASE=Transceiver (ACPI-compliant) + +usb:v0BC7p000C* + ID_MODEL_FROM_DATABASE=Transceiver (ACPI-compliant) + +usb:v0BC7p000D* + ID_MODEL_FROM_DATABASE=Transceiver (ACPI-compliant) + +usb:v0BC7p000E* + ID_MODEL_FROM_DATABASE=Transceiver (ACPI-compliant) + +usb:v0BC7p000F* + ID_MODEL_FROM_DATABASE=Transceiver (ACPI-compliant) + +usb:v0BC8* + ID_VENDOR_FROM_DATABASE=Telmax Communications + +usb:v0BC9* + ID_VENDOR_FROM_DATABASE=ECI Telecom, Ltd + +usb:v0BCA* + ID_VENDOR_FROM_DATABASE=Startek Engineering, Inc. + +usb:v0BCB* + ID_VENDOR_FROM_DATABASE=Perfect Technic Enterprise Co., Ltd + +usb:v0BD7* + ID_VENDOR_FROM_DATABASE=Andrew Pargeter & Associates + +usb:v0BD7pA021* + ID_MODEL_FROM_DATABASE=Amptek DP4 multichannel signal analyzer + +usb:v0BDA* + ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Corp. + +usb:v0BDAp0103* + ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader + +usb:v0BDAp0104* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0106* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0107* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0108* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0111* + ID_MODEL_FROM_DATABASE=RTS5111 Card Reader Controller + +usb:v0BDAp0113* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0115* + ID_MODEL_FROM_DATABASE=Mass Storage Device (Multicard Reader) + +usb:v0BDAp0116* + ID_MODEL_FROM_DATABASE=RTS5116 Card Reader Controller + +usb:v0BDAp0117* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0118* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0119* + ID_MODEL_FROM_DATABASE=Storage Device (SD card reader) + +usb:v0BDAp0129* + ID_MODEL_FROM_DATABASE=RTS5129 Card Reader Controller + +usb:v0BDAp0138* + ID_MODEL_FROM_DATABASE=RTS5138 Card Reader Controller + +usb:v0BDAp0139* + ID_MODEL_FROM_DATABASE=RTS5139 Card Reader Controller + +usb:v0BDAp0151* + ID_MODEL_FROM_DATABASE=Mass Storage Device (Multicard Reader) + +usb:v0BDAp0152* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0153* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0156* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0157* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0158* + ID_MODEL_FROM_DATABASE=USB 2.0 multicard reader + +usb:v0BDAp0159* + ID_MODEL_FROM_DATABASE=RTS5159 Card Reader Controller + +usb:v0BDAp0161* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0168* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0169* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0171* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0176* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0178* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0BDAp0184* + ID_MODEL_FROM_DATABASE=RTS5182 Card Reader + +usb:v0BDAp0186* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0BDAp2831* + ID_MODEL_FROM_DATABASE=RTL2831U DVB-T + +usb:v0BDAp2832* + ID_MODEL_FROM_DATABASE=RTL2832U DVB-T + +usb:v0BDAp2838* + ID_MODEL_FROM_DATABASE=RTL2838 DVB-T + +usb:v0BDAp8150* + ID_MODEL_FROM_DATABASE=RTL8150 Fast Ethernet Adapter + +usb:v0BDAp8151* + ID_MODEL_FROM_DATABASE=RTL8151 Adapteon Business Mobile Networks BV + +usb:v0BDAp8171* + ID_MODEL_FROM_DATABASE=RTL8188SU 802.11n WLAN Adapter + +usb:v0BDAp8172* + ID_MODEL_FROM_DATABASE=RTL8191SU 802.11n WLAN Adapter + +usb:v0BDAp8174* + ID_MODEL_FROM_DATABASE=RTL8192SU 802.11n WLAN Adapter + +usb:v0BDAp8176* + ID_MODEL_FROM_DATABASE=RTL8188CUS 802.11n WLAN Adapter + +usb:v0BDAp8178* + ID_MODEL_FROM_DATABASE=RTL8192CU 802.11n WLAN Adapter + +usb:v0BDAp8179* + ID_MODEL_FROM_DATABASE=RTL8188EUS 802.11n Wireless Network Adapter + +usb:v0BDAp817F* + ID_MODEL_FROM_DATABASE=RTL8188RU 802.11n WLAN Adapter + +usb:v0BDAp8187* + ID_MODEL_FROM_DATABASE=RTL8187 Wireless Adapter + +usb:v0BDAp8189* + ID_MODEL_FROM_DATABASE=RTL8187B Wireless 802.11g 54Mbps Network Adapter + +usb:v0BDAp8192* + ID_MODEL_FROM_DATABASE=RTL8191SU 802.11n Wireless Adapter + +usb:v0BDAp8193* + ID_MODEL_FROM_DATABASE=RTL8192DU 802.11an WLAN Adapter + +usb:v0BDAp8197* + ID_MODEL_FROM_DATABASE=RTL8187B Wireless Adapter + +usb:v0BDAp8198* + ID_MODEL_FROM_DATABASE=RTL8187B Wireless Adapter + +usb:v0BDAp8199* + ID_MODEL_FROM_DATABASE=RTL8187SU 802.11g WLAN Adapter + +usb:v0BDB* + ID_VENDOR_FROM_DATABASE=Ericsson Business Mobile Networks BV + +usb:v0BDBp1000* + ID_MODEL_FROM_DATABASE=BV Bluetooth Device + +usb:v0BDBp1002* + ID_MODEL_FROM_DATABASE=Bluetooth Device 1.2 + +usb:v0BDBp1049* + ID_MODEL_FROM_DATABASE=C3607w Mobile Broadband Module + +usb:v0BDBp1900* + ID_MODEL_FROM_DATABASE=F3507g Mobile Broadband Module + +usb:v0BDBp1902* + ID_MODEL_FROM_DATABASE=F3507g v2 Mobile Broadband Module + +usb:v0BDBp1904* + ID_MODEL_FROM_DATABASE=F3607gw Mobile Broadband Module + +usb:v0BDBp1905* + ID_MODEL_FROM_DATABASE=F3607gw v2 Mobile Broadband Module + +usb:v0BDBp1906* + ID_MODEL_FROM_DATABASE=F3607gw v3 Mobile Broadband Module + +usb:v0BDBp1909* + ID_MODEL_FROM_DATABASE=F3307 v2 Mobile Broadband Module + +usb:v0BDBp190A* + ID_MODEL_FROM_DATABASE=F3307 Mobile Broadband Module + +usb:v0BDBp190B* + ID_MODEL_FROM_DATABASE=C3607w v2 Mobile Broadband Module + +usb:v0BDC* + ID_VENDOR_FROM_DATABASE=Y Media Corp. + +usb:v0BDD* + ID_VENDOR_FROM_DATABASE=Orange PCS + +usb:v0BE2* + ID_VENDOR_FROM_DATABASE=Kanda Tsushin Kogyo Co., Ltd + +usb:v0BE3* + ID_VENDOR_FROM_DATABASE=TOYO Corp. + +usb:v0BE4* + ID_VENDOR_FROM_DATABASE=Elka International, Ltd + +usb:v0BE5* + ID_VENDOR_FROM_DATABASE=DOME imaging systems, Inc. + +usb:v0BE6* + ID_VENDOR_FROM_DATABASE=Dong Guan Humen Wonderful Wire Cable Factory + +usb:v0BED* + ID_VENDOR_FROM_DATABASE=MEI + +usb:v0BEDp1100* + ID_MODEL_FROM_DATABASE=CASHFLOW SC + +usb:v0BEDp1101* + ID_MODEL_FROM_DATABASE=Series 2000 Combo Acceptor + +usb:v0BEE* + ID_VENDOR_FROM_DATABASE=LTK Industries, Ltd + +usb:v0BEF* + ID_VENDOR_FROM_DATABASE=Way2Call Communications + +usb:v0BF0* + ID_VENDOR_FROM_DATABASE=Pace Micro Technology PLC + +usb:v0BF1* + ID_VENDOR_FROM_DATABASE=Intracom S.A. + +usb:v0BF1p0001* + ID_MODEL_FROM_DATABASE=netMod Driver Ver 2.4.17 (CAPI) + +usb:v0BF1p0002* + ID_MODEL_FROM_DATABASE=netMod Driver Ver 2.4 (CAPI) + +usb:v0BF1p0003* + ID_MODEL_FROM_DATABASE=netMod Driver Ver 2.4 (CAPI) + +usb:v0BF2* + ID_VENDOR_FROM_DATABASE=Konexx + +usb:v0BF6* + ID_VENDOR_FROM_DATABASE=Addonics Technologies, Inc. + +usb:v0BF6p0103* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v0BF6p1234* + ID_MODEL_FROM_DATABASE=Storage Device + +usb:v0BF6pA000* + ID_MODEL_FROM_DATABASE=Cable 205 (TPP) + +usb:v0BF6pA001* + ID_MODEL_FROM_DATABASE=Cable 205 + +usb:v0BF6pA002* + ID_MODEL_FROM_DATABASE=IDE Bridge + +usb:v0BF7* + ID_VENDOR_FROM_DATABASE=Sunny Giken, Inc. + +usb:v0BF8* + ID_VENDOR_FROM_DATABASE=Fujitsu Siemens Computers + +usb:v0BF8p1001* + ID_MODEL_FROM_DATABASE=Fujitsu Pocket Loox 600 PDA + +usb:v0BF8p1006* + ID_MODEL_FROM_DATABASE=SmartCard Reader 2A + +usb:v0BF8p1007* + ID_MODEL_FROM_DATABASE=Connect2Air E-5400 802.11g Wireless Adapter + +usb:v0BF8p1009* + ID_MODEL_FROM_DATABASE=Connect2Air E-5400 D1700 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v0BF8p100C* + ID_MODEL_FROM_DATABASE=Keyboard FSC KBPC PX + +usb:v0BF8p100F* + ID_MODEL_FROM_DATABASE=miniCard D2301 802.11bg Wireless Module [SiS 163U] + +usb:v0BF8p1017* + ID_MODEL_FROM_DATABASE=Keyboard KB SCR + +usb:v0BFD* + ID_VENDOR_FROM_DATABASE=Kvaser AB + +usb:v0BFDp0004* + ID_MODEL_FROM_DATABASE=USBcan II + +usb:v0BFDp000B* + ID_MODEL_FROM_DATABASE=Leaf Light HS + +usb:v0BFDp000E* + ID_MODEL_FROM_DATABASE=Leaf SemiPro HS + +usb:v0C04* + ID_VENDOR_FROM_DATABASE=MOTO Development Group, Inc. + +usb:v0C05* + ID_VENDOR_FROM_DATABASE=Appian Graphics + +usb:v0C06* + ID_VENDOR_FROM_DATABASE=Hasbro Games, Inc. + +usb:v0C07* + ID_VENDOR_FROM_DATABASE=Infinite Data Storage, Ltd + +usb:v0C08* + ID_VENDOR_FROM_DATABASE=Agate + +usb:v0C08p0378* + ID_MODEL_FROM_DATABASE=Q 16MB Storage Device + +usb:v0C09* + ID_VENDOR_FROM_DATABASE=Comjet Information System + +usb:v0C09pA5A5* + ID_MODEL_FROM_DATABASE=Litto Version USB2.0 + +usb:v0C0A* + ID_VENDOR_FROM_DATABASE=Highpoint Technologies, Inc. + +usb:v0C0B* + ID_VENDOR_FROM_DATABASE=Dura Micro, Inc. (Acomdata) + +usb:v0C0Bp27CB* + ID_MODEL_FROM_DATABASE=6-in-1 Flash Reader and Writer + +usb:v0C0Bp27D7* + ID_MODEL_FROM_DATABASE=Multi Memory reader/writer MD-005 + +usb:v0C0Bp27DA* + ID_MODEL_FROM_DATABASE=Multi Memory reader/writer MD-005 + +usb:v0C0Bp27DC* + ID_MODEL_FROM_DATABASE=Multi Memory reader/writer MD-005 + +usb:v0C0Bp27E7* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v0C0Bp27EE* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v0C0Bp2814* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v0C0Bp2815* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v0C0Bp281D* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v0C0Bp5FAB* + ID_MODEL_FROM_DATABASE=Storage Adaptor + +usb:v0C0BpA109* + ID_MODEL_FROM_DATABASE=CF/SM Reader and Writer + +usb:v0C0BpA10C* + ID_MODEL_FROM_DATABASE=SD/MS Reader and Writer + +usb:v0C0BpB001* + ID_MODEL_FROM_DATABASE=USB 2.0 Mass Storage IDE adapter + +usb:v0C0BpB004* + ID_MODEL_FROM_DATABASE=MMC/SD Reader and Writer + +usb:v0C12* + ID_VENDOR_FROM_DATABASE=Zeroplus + +usb:v0C12p0005* + ID_MODEL_FROM_DATABASE=PSX Vibration Feedback Converter + +usb:v0C12p0030* + ID_MODEL_FROM_DATABASE=PSX Vibration Feedback Converter + +usb:v0C12p700E* + ID_MODEL_FROM_DATABASE=Logic Analyzer (LAP-C-16032) + +usb:v0C12p8801* + ID_MODEL_FROM_DATABASE=Xbox Controller + +usb:v0C12p8802* + ID_MODEL_FROM_DATABASE=Xbox Controller + +usb:v0C12p8809* + ID_MODEL_FROM_DATABASE=Red Octane Ignition Xbox DDR Pad + +usb:v0C12p880A* + ID_MODEL_FROM_DATABASE=Pelican Eclipse PL-2023 + +usb:v0C12p8810* + ID_MODEL_FROM_DATABASE=Xbox Controller + +usb:v0C12p9902* + ID_MODEL_FROM_DATABASE=VibraX + +usb:v0C15* + ID_VENDOR_FROM_DATABASE=Iris Graphics + +usb:v0C16* + ID_VENDOR_FROM_DATABASE=Gyration, Inc. + +usb:v0C16p0002* + ID_MODEL_FROM_DATABASE=RF Technology Receiver + +usb:v0C16p0003* + ID_MODEL_FROM_DATABASE=RF Technology Receiver + +usb:v0C16p0008* + ID_MODEL_FROM_DATABASE=RF Technology Receiver + +usb:v0C16p0080* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0C16p0081* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0C17* + ID_VENDOR_FROM_DATABASE=Cyberboard A/S + +usb:v0C18* + ID_VENDOR_FROM_DATABASE=SynerTek Korea, Inc. + +usb:v0C19* + ID_VENDOR_FROM_DATABASE=cyberPIXIE, Inc. + +usb:v0C1A* + ID_VENDOR_FROM_DATABASE=Silicon Motion, Inc. + +usb:v0C1B* + ID_VENDOR_FROM_DATABASE=MIPS Technologies + +usb:v0C1C* + ID_VENDOR_FROM_DATABASE=Hang Zhou Silan Electronics Co., Ltd + +usb:v0C22* + ID_VENDOR_FROM_DATABASE=Tally Printer Corp. + +usb:v0C23* + ID_VENDOR_FROM_DATABASE=Lernout + Hauspie + +usb:v0C24* + ID_VENDOR_FROM_DATABASE=Taiyo Yuden + +usb:v0C24p0001* + ID_MODEL_FROM_DATABASE=Bluetooth Adaptor + +usb:v0C24p0002* + ID_MODEL_FROM_DATABASE=Bluetooth Device2 + +usb:v0C24p0005* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p000B* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p000C* + ID_MODEL_FROM_DATABASE=Bluetooth Adaptor + +usb:v0C24p000E* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p000F* + ID_MODEL_FROM_DATABASE=Bluetooth Device (V2.0+EDR) + +usb:v0C24p0010* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p0012* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p0018* + ID_MODEL_FROM_DATABASE=Bluetooth Device(BC04-External) + +usb:v0C24p0019* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0C24p0021* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0C24p0C24* + ID_MODEL_FROM_DATABASE=Bluetooth Device(SAMPLE) + +usb:v0C24pFFFF* + ID_MODEL_FROM_DATABASE=Bluetooth module with BlueCore in DFU mode + +usb:v0C25* + ID_VENDOR_FROM_DATABASE=Sampo Corp. + +usb:v0C25p0310* + ID_MODEL_FROM_DATABASE=Scream Cam + +usb:v0C26* + ID_VENDOR_FROM_DATABASE=Prolific Technology Inc. + +usb:v0C26p0018* + ID_MODEL_FROM_DATABASE=USB-Serial Controller [Icom Inc. OPC-478UC] + +usb:v0C27* + ID_VENDOR_FROM_DATABASE=RFIDeas, Inc + +usb:v0C27p3BFA* + ID_MODEL_FROM_DATABASE=pcProx Card Reader + +usb:v0C2E* + ID_VENDOR_FROM_DATABASE=Metrologic Instruments + +usb:v0C2Ep0007* + ID_MODEL_FROM_DATABASE=Metrologic MS7120 Barcode Scanner (IBM SurePOS mode) + +usb:v0C2Ep0200* + ID_MODEL_FROM_DATABASE=MS7120 Barcode Scanner + +usb:v0C2Ep0204* + ID_MODEL_FROM_DATABASE=Metrologic MS7120 Barcode Scanner (keyboard mode) + +usb:v0C2Ep0206* + ID_MODEL_FROM_DATABASE=Metrologic MS4980 Barcode Scanner + +usb:v0C2Ep0700* + ID_MODEL_FROM_DATABASE=Metrologic MS7120 Barcode Scanner (uni-directional serial mode) + +usb:v0C2Ep0720* + ID_MODEL_FROM_DATABASE=Metrologic MS7120 Barcode Scanner (bi-directional serial mode) + +usb:v0C2Ep0B61* + ID_MODEL_FROM_DATABASE=Vuquest 3310g + +usb:v0C2Ep0B6A* + ID_MODEL_FROM_DATABASE=Vuquest 3310 Area-Imaging Scanner + +usb:v0C35* + ID_VENDOR_FROM_DATABASE=Eagletron, Inc. + +usb:v0C36* + ID_VENDOR_FROM_DATABASE=E Ink Corp. + +usb:v0C37* + ID_VENDOR_FROM_DATABASE=e.Digital + +usb:v0C38* + ID_VENDOR_FROM_DATABASE=Der An Electric Wire & Cable Co., Ltd + +usb:v0C39* + ID_VENDOR_FROM_DATABASE=IFR + +usb:v0C3A* + ID_VENDOR_FROM_DATABASE=Furui Precise Component (Kunshan) Co., Ltd + +usb:v0C3B* + ID_VENDOR_FROM_DATABASE=Komatsu, Ltd + +usb:v0C3C* + ID_VENDOR_FROM_DATABASE=Radius Co., Ltd + +usb:v0C3D* + ID_VENDOR_FROM_DATABASE=Innocom, Inc. + +usb:v0C3E* + ID_VENDOR_FROM_DATABASE=Nextcell, Inc. + +usb:v0C44* + ID_VENDOR_FROM_DATABASE=Motorola iDEN + +usb:v0C44p0021* + ID_MODEL_FROM_DATABASE=iDEN P2k0 Device + +usb:v0C44p0022* + ID_MODEL_FROM_DATABASE=iDEN P2k1 Device + +usb:v0C44p03A2* + ID_MODEL_FROM_DATABASE=iDEN Smartphone + +usb:v0C44p41D9* + ID_MODEL_FROM_DATABASE=i1 phone + +usb:v0C45* + ID_VENDOR_FROM_DATABASE=Microdia + +usb:v0C45p0011* + ID_MODEL_FROM_DATABASE=EBUDDY + +usb:v0C45p1018* + ID_MODEL_FROM_DATABASE=Compact Flash storage memory card reader + +usb:v0C45p1020* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1028* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1030* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1031* + ID_MODEL_FROM_DATABASE=Sonix Mass Storage Device + +usb:v0C45p1032* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1033* + ID_MODEL_FROM_DATABASE=Sonix Mass Storage Device + +usb:v0C45p1034* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1035* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1036* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1037* + ID_MODEL_FROM_DATABASE=Sonix Mass Storage Device + +usb:v0C45p1050* + ID_MODEL_FROM_DATABASE=CF Card Reader + +usb:v0C45p1058* + ID_MODEL_FROM_DATABASE=HDD Reader + +usb:v0C45p1060* + ID_MODEL_FROM_DATABASE=iFlash SM-Direct Card Reader + +usb:v0C45p1061* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1062* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1063* + ID_MODEL_FROM_DATABASE=Sonix Mass Storage Device + +usb:v0C45p1064* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1065* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1066* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1067* + ID_MODEL_FROM_DATABASE=Mass Storage Reader + +usb:v0C45p1158* + ID_MODEL_FROM_DATABASE=A56AK + +usb:v0C45p184C* + ID_MODEL_FROM_DATABASE=VoIP Phone + +usb:v0C45p6001* + ID_MODEL_FROM_DATABASE=Genius VideoCAM NB + +usb:v0C45p6005* + ID_MODEL_FROM_DATABASE=Sweex Mini Webcam + +usb:v0C45p6007* + ID_MODEL_FROM_DATABASE=VideoCAM Eye + +usb:v0C45p6009* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p600D* + ID_MODEL_FROM_DATABASE=TwinkleCam USB camera + +usb:v0C45p6011* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C102) + +usb:v0C45p6019* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C102) + +usb:v0C45p6024* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p6025* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p6028* + ID_MODEL_FROM_DATABASE=Typhoon Easycam USB 330K (older) + +usb:v0C45p6029* + ID_MODEL_FROM_DATABASE=Triplex i-mini PC Camera + +usb:v0C45p602A* + ID_MODEL_FROM_DATABASE=Meade ETX-105EC Camera + +usb:v0C45p602B* + ID_MODEL_FROM_DATABASE=VideoCAM NB 300 + +usb:v0C45p602C* + ID_MODEL_FROM_DATABASE=Clas Ohlson TWC-30XOP Webcam + +usb:v0C45p602D* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p602E* + ID_MODEL_FROM_DATABASE=VideoCAM Messenger + +usb:v0C45p6030* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p603F* + ID_MODEL_FROM_DATABASE=VideoCAM ExpressII + +usb:v0C45p6040* + ID_MODEL_FROM_DATABASE=CCD PC Camera (PC390A) + +usb:v0C45p606A* + ID_MODEL_FROM_DATABASE=CCD PC Camera (PC390A) + +usb:v0C45p607A* + ID_MODEL_FROM_DATABASE=CCD PC Camera (PC390A) + +usb:v0C45p607B* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p607C* + ID_MODEL_FROM_DATABASE=CCD PC Camera (PC390A) + +usb:v0C45p607E* + ID_MODEL_FROM_DATABASE=CCD PC Camera (PC390A) + +usb:v0C45p6080* + ID_MODEL_FROM_DATABASE=Audio (Microphone) + +usb:v0C45p6082* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p6083* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p608C* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p608E* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p608F* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C103 + OV7630) + +usb:v0C45p60A8* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p60AA* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p60AB* + ID_MODEL_FROM_DATABASE=PC Camera + +usb:v0C45p60AF* + ID_MODEL_FROM_DATABASE=VideoCAM Look + +usb:v0C45p60B0* + ID_MODEL_FROM_DATABASE=Genius VideoCam Look + +usb:v0C45p60C0* + ID_MODEL_FROM_DATABASE=PC Camera with Mic (SN9C105) + +usb:v0C45p60C8* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p60CC* + ID_MODEL_FROM_DATABASE=PC Camera with Mic (SN9C105) + +usb:v0C45p60EC* + ID_MODEL_FROM_DATABASE=PC Camera with Mic (SN9C105) + +usb:v0C45p60EF* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p60FA* + ID_MODEL_FROM_DATABASE=PC Camera with Mic (SN9C105) + +usb:v0C45p60FB* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v0C45p60FC* + ID_MODEL_FROM_DATABASE=PC Camera with Mic (SN9C105) + +usb:v0C45p60FE* + ID_MODEL_FROM_DATABASE=Audio (Microphone) + +usb:v0C45p6108* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p6122* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C110) + +usb:v0C45p6123* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C110) + +usb:v0C45p6128* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C325 + OM6802) + +usb:v0C45p612A* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C325) + +usb:v0C45p612C* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C110) + +usb:v0C45p612E* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C110) + +usb:v0C45p612F* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C110) + +usb:v0C45p6130* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C120) + +usb:v0C45p6138* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p613A* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C120) + +usb:v0C45p613B* + ID_MODEL_FROM_DATABASE=Win2 PC Camera + +usb:v0C45p613C* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C120) + +usb:v0C45p613E* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C120) + +usb:v0C45p6143* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C120 + SP80708) + +usb:v0C45p6240* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + MI1300) + +usb:v0C45p6242* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + MI1310) + +usb:v0C45p6243* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + S5K4AAFX) + +usb:v0C45p6248* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV9655) + +usb:v0C45p624B* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + CX1332) + +usb:v0C45p624C* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + MI1320) + +usb:v0C45p624E* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + SOI968) + +usb:v0C45p624F* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV9650) + +usb:v0C45p6251* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV9650) + +usb:v0C45p6253* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV9650) + +usb:v0C45p6260* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV7670ISP) + +usb:v0C45p6262* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OM6802) + +usb:v0C45p6270* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + MI0360/MT9V011 or MI0360SOC/MT9V111) U-CAM PC Camera NE878, Whitcom WHC017, ... + +usb:v0C45p627A* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + S5K53BEB) + +usb:v0C45p627B* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV7660) + +usb:v0C45p627C* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + HV7131R) + +usb:v0C45p627F* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV965x + EEPROM) + +usb:v0C45p6280* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + MI1300) + +usb:v0C45p6282* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + MI1310) + +usb:v0C45p6283* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + S5K4AAFX) + +usb:v0C45p6288* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV9655) + +usb:v0C45p628A* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + ICM107) + +usb:v0C45p628B* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + CX1332) + +usb:v0C45p628C* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + MI1320) + +usb:v0C45p628E* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + SOI968) + +usb:v0C45p628F* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV9650) + +usb:v0C45p62A0* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV7670ISP) + +usb:v0C45p62A2* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OM6802) + +usb:v0C45p62B0* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + MI0360/MT9V011 or MI0360SOC/MT9V111) + +usb:v0C45p62B3* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV9655) + +usb:v0C45p62BA* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + S5K53BEB) + +usb:v0C45p62BB* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV7660) + +usb:v0C45p62BC* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + HV7131R) + +usb:v0C45p62BE* + ID_MODEL_FROM_DATABASE=PC Camera with Microphone (SN9C202 + OV7663) + +usb:v0C45p62C0* + ID_MODEL_FROM_DATABASE=Sonix USB 2.0 Camera + +usb:v0C45p62E0* + ID_MODEL_FROM_DATABASE=MSI Starcam Racer + +usb:v0C45p6310* + ID_MODEL_FROM_DATABASE=Sonix USB 2.0 Camera + +usb:v0C45p6341* + ID_MODEL_FROM_DATABASE=Defender G-Lens 2577 HD720p Camera + +usb:v0C45p63E0* + ID_MODEL_FROM_DATABASE=Sonix Integrated Webcam + +usb:v0C45p63F1* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v0C45p63F8* + ID_MODEL_FROM_DATABASE=Sonix Integrated Webcam + +usb:v0C45p6409* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v0C45p6413* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v0C45p6417* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v0C45p6419* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v0C45p641D* + ID_MODEL_FROM_DATABASE=1.3 MPixel Integrated Webcam + +usb:v0C45p6480* + ID_MODEL_FROM_DATABASE=Sonix 1.3 MP Laptop Integrated Webcam + +usb:v0C45p648B* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v0C45p64BD* + ID_MODEL_FROM_DATABASE=Sony Visual Communication Camera + +usb:v0C45p7402* + ID_MODEL_FROM_DATABASE=TEMPerHUM Temperature & Humidity Sensor + +usb:v0C45p7403* + ID_MODEL_FROM_DATABASE=Foot Switch + +usb:v0C45p8000* + ID_MODEL_FROM_DATABASE=DC31VC + +usb:v0C45p8006* + ID_MODEL_FROM_DATABASE=Dual Mode Camera (8006 VGA) + +usb:v0C45p800A* + ID_MODEL_FROM_DATABASE=Vivitar Vivicam3350B + +usb:v0C46* + ID_VENDOR_FROM_DATABASE=WaveRider Communications, Inc. + +usb:v0C4A* + ID_VENDOR_FROM_DATABASE=ALGE-TIMING GmbH + +usb:v0C4Ap0889* + ID_MODEL_FROM_DATABASE=Timy + +usb:v0C4Ap088A* + ID_MODEL_FROM_DATABASE=Timy 2 + +usb:v0C4B* + ID_VENDOR_FROM_DATABASE=Reiner SCT Kartensysteme GmbH + +usb:v0C4Bp0100* + ID_MODEL_FROM_DATABASE=cyberJack e-com/pinpad + +usb:v0C4Bp0300* + ID_MODEL_FROM_DATABASE=cyberJack pinpad(a) + +usb:v0C4Bp0501* + ID_MODEL_FROM_DATABASE=cyberJack RFID comfort dual interface smartcard reader + +usb:v0C4Bp9102* + ID_MODEL_FROM_DATABASE=cyberJack RFID basis contactless smartcard reader + +usb:v0C4C* + ID_VENDOR_FROM_DATABASE=Needham's Electronics + +usb:v0C4Cp0021* + ID_MODEL_FROM_DATABASE=EMP-21 Universal Programmer + +usb:v0C52* + ID_VENDOR_FROM_DATABASE=Sealevel Systems, Inc. + +usb:v0C52p2101* + ID_MODEL_FROM_DATABASE=SeaLINK+232 + +usb:v0C52p2102* + ID_MODEL_FROM_DATABASE=SeaLINK+485 + +usb:v0C52p2103* + ID_MODEL_FROM_DATABASE=SeaLINK+232I + +usb:v0C52p2104* + ID_MODEL_FROM_DATABASE=SeaLINK+485I + +usb:v0C52p2211* + ID_MODEL_FROM_DATABASE=SeaPORT+2/232 (Port 1) + +usb:v0C52p2212* + ID_MODEL_FROM_DATABASE=SeaPORT+2/485 (Port 1) + +usb:v0C52p2213* + ID_MODEL_FROM_DATABASE=SeaPORT+2 (Port 1) + +usb:v0C52p2221* + ID_MODEL_FROM_DATABASE=SeaPORT+2/232 (Port 2) + +usb:v0C52p2222* + ID_MODEL_FROM_DATABASE=SeaPORT+2/485 (Port 2) + +usb:v0C52p2223* + ID_MODEL_FROM_DATABASE=SeaPORT+2 (Port 2) + +usb:v0C52p2411* + ID_MODEL_FROM_DATABASE=SeaPORT+4/232 (Port 1) + +usb:v0C52p2412* + ID_MODEL_FROM_DATABASE=SeaPORT+4/485 (Port 1) + +usb:v0C52p2413* + ID_MODEL_FROM_DATABASE=SeaPORT+4 (Port 1) + +usb:v0C52p2421* + ID_MODEL_FROM_DATABASE=SeaPORT+4/232 (Port 2) + +usb:v0C52p2422* + ID_MODEL_FROM_DATABASE=SeaPORT+4/485 (Port 2) + +usb:v0C52p2423* + ID_MODEL_FROM_DATABASE=SeaPORT+4 (Port 2) + +usb:v0C52p2431* + ID_MODEL_FROM_DATABASE=SeaPORT+4/232 (Port 3) + +usb:v0C52p2432* + ID_MODEL_FROM_DATABASE=SeaPORT+4/485 (Port 3) + +usb:v0C52p2433* + ID_MODEL_FROM_DATABASE=SeaPORT+4 (Port 3) + +usb:v0C52p2441* + ID_MODEL_FROM_DATABASE=SeaPORT+4/232 (Port 4) + +usb:v0C52p2442* + ID_MODEL_FROM_DATABASE=SeaPORT+4/485 (Port 4) + +usb:v0C52p2443* + ID_MODEL_FROM_DATABASE=SeaPORT+4 (Port 4) + +usb:v0C52p2811* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 1) + +usb:v0C52p2812* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 1) + +usb:v0C52p2813* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 1) + +usb:v0C52p2821* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 2) + +usb:v0C52p2822* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 2) + +usb:v0C52p2823* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 2) + +usb:v0C52p2831* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 3) + +usb:v0C52p2832* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 3) + +usb:v0C52p2833* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 3) + +usb:v0C52p2841* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 4) + +usb:v0C52p2842* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 4) + +usb:v0C52p2843* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 4) + +usb:v0C52p2851* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 5) + +usb:v0C52p2852* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 5) + +usb:v0C52p2853* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 5) + +usb:v0C52p2861* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 6) + +usb:v0C52p2862* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 6) + +usb:v0C52p2863* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 6) + +usb:v0C52p2871* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 7) + +usb:v0C52p2872* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 7) + +usb:v0C52p2873* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 7) + +usb:v0C52p2881* + ID_MODEL_FROM_DATABASE=SeaLINK+8/232 (Port 8) + +usb:v0C52p2882* + ID_MODEL_FROM_DATABASE=SeaLINK+8/485 (Port 8) + +usb:v0C52p2883* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 8) + +usb:v0C52p9020* + ID_MODEL_FROM_DATABASE=SeaLINK+422 + +usb:v0C52pA02A* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 1+2) + +usb:v0C52pA02B* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 3+4) + +usb:v0C52pA02C* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 5+6) + +usb:v0C52pA02D* + ID_MODEL_FROM_DATABASE=SeaLINK+8 (Port 7+8) + +usb:v0C53* + ID_VENDOR_FROM_DATABASE=ViewPLUS, Inc. + +usb:v0C54* + ID_VENDOR_FROM_DATABASE=Glory, Ltd + +usb:v0C55* + ID_VENDOR_FROM_DATABASE=Spectrum Digital, Inc. + +usb:v0C55p0510* + ID_MODEL_FROM_DATABASE=Spectrum Digital XDS510 JTAG Debugger + +usb:v0C55p0540* + ID_MODEL_FROM_DATABASE=SPI540 + +usb:v0C55p5416* + ID_MODEL_FROM_DATABASE=TMS320C5416 DSK + +usb:v0C55p6416* + ID_MODEL_FROM_DATABASE=TMS320C6416 DDB + +usb:v0C56* + ID_VENDOR_FROM_DATABASE=Billion Bright, Ltd + +usb:v0C57* + ID_VENDOR_FROM_DATABASE=Imaginative Design Operation Co., Ltd + +usb:v0C58* + ID_VENDOR_FROM_DATABASE=Vidar Systems Corp. + +usb:v0C59* + ID_VENDOR_FROM_DATABASE=Dong Guan Shinko Wire Co., Ltd + +usb:v0C5A* + ID_VENDOR_FROM_DATABASE=TRS International Mfg., Inc. + +usb:v0C5E* + ID_VENDOR_FROM_DATABASE=Xytronix Research & Design + +usb:v0C60* + ID_VENDOR_FROM_DATABASE=Apogee Electronics Corp. + +usb:v0C62* + ID_VENDOR_FROM_DATABASE=Chant Sincere Co., Ltd + +usb:v0C63* + ID_VENDOR_FROM_DATABASE=Toko, Inc. + +usb:v0C64* + ID_VENDOR_FROM_DATABASE=Signality System Engineering Co., Ltd + +usb:v0C65* + ID_VENDOR_FROM_DATABASE=Eminence Enterprise Co., Ltd + +usb:v0C66* + ID_VENDOR_FROM_DATABASE=Rexon Electronics Corp. + +usb:v0C67* + ID_VENDOR_FROM_DATABASE=Concept Telecom, Ltd + +usb:v0C6A* + ID_VENDOR_FROM_DATABASE=ACS + +usb:v0C6Ap0005* + ID_MODEL_FROM_DATABASE=Color 320 x 240 LCD Display Terminal with Touchscreen + +usb:v0C6C* + ID_VENDOR_FROM_DATABASE=JETI Technische Instrumente GmbH + +usb:v0C6Cp04B2* + ID_MODEL_FROM_DATABASE=Specbos 1201 + +usb:v0C70* + ID_VENDOR_FROM_DATABASE=MCT Elektronikladen + +usb:v0C70p0000* + ID_MODEL_FROM_DATABASE=USB08 Development board + +usb:v0C70p0747* + ID_MODEL_FROM_DATABASE=Eye Movement Recorder [Visagraph]/[ReadAlyzer] + +usb:v0C72* + ID_VENDOR_FROM_DATABASE=PEAK System + +usb:v0C72p000C* + ID_MODEL_FROM_DATABASE=PCAN-USB + +usb:v0C72p000D* + ID_MODEL_FROM_DATABASE=PCAN Pro + +usb:v0C74* + ID_VENDOR_FROM_DATABASE=Optronic Laboratories Inc. + +usb:v0C74p0002* + ID_MODEL_FROM_DATABASE=OL 700-30 Goniometer + +usb:v0C76* + ID_VENDOR_FROM_DATABASE=JMTek, LLC. + +usb:v0C76p0001* + ID_MODEL_FROM_DATABASE=Mass Storage Controller + +usb:v0C76p0002* + ID_MODEL_FROM_DATABASE=Mass Storage Controller + +usb:v0C76p0003* + ID_MODEL_FROM_DATABASE=USBdisk + +usb:v0C76p0004* + ID_MODEL_FROM_DATABASE=Mass Storage Controller + +usb:v0C76p0005* + ID_MODEL_FROM_DATABASE=Transcend Flash disk + +usb:v0C76p0006* + ID_MODEL_FROM_DATABASE=Transcend JetFlash + +usb:v0C76p0007* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0C76p1600* + ID_MODEL_FROM_DATABASE=Ion Quick Play LP turntable + +usb:v0C76p1605* + ID_MODEL_FROM_DATABASE=SSS Headphone Set + +usb:v0C76p1607* + ID_MODEL_FROM_DATABASE=audio controller + +usb:v0C77* + ID_VENDOR_FROM_DATABASE=Sipix Group, Ltd + +usb:v0C77p1001* + ID_MODEL_FROM_DATABASE=SiPix Web2 + +usb:v0C77p1002* + ID_MODEL_FROM_DATABASE=SiPix SC2100 + +usb:v0C77p1010* + ID_MODEL_FROM_DATABASE=SiPix Snap + +usb:v0C77p1011* + ID_MODEL_FROM_DATABASE=SiPix Blink 2 + +usb:v0C77p1015* + ID_MODEL_FROM_DATABASE=SiPix CAMeleon + +usb:v0C78* + ID_VENDOR_FROM_DATABASE=Detto Corp. + +usb:v0C79* + ID_VENDOR_FROM_DATABASE=NuConnex Technologies Pte., Ltd + +usb:v0C7A* + ID_VENDOR_FROM_DATABASE=Wing-Span Enterprise Co., Ltd + +usb:v0C86* + ID_VENDOR_FROM_DATABASE=NDA Technologies, Inc. + +usb:v0C88* + ID_VENDOR_FROM_DATABASE=Kyocera Wireless Corp. + +usb:v0C88p0021* + ID_MODEL_FROM_DATABASE=Handheld + +usb:v0C88p17DA* + ID_MODEL_FROM_DATABASE=Qualcomm Kyocera CDMA Technologies MSM + +usb:v0C89* + ID_VENDOR_FROM_DATABASE=Honda Tsushin Kogyo Co., Ltd + +usb:v0C8A* + ID_VENDOR_FROM_DATABASE=Pathway Connectivity, Inc. + +usb:v0C8B* + ID_VENDOR_FROM_DATABASE=Wavefly Corp. + +usb:v0C8C* + ID_VENDOR_FROM_DATABASE=Coactive Networks + +usb:v0C8D* + ID_VENDOR_FROM_DATABASE=Tempo + +usb:v0C8E* + ID_VENDOR_FROM_DATABASE=Cesscom Co., Ltd + +usb:v0C8Ep6000* + ID_MODEL_FROM_DATABASE=Luxian Series + +usb:v0C8F* + ID_VENDOR_FROM_DATABASE=Applied Microsystems + +usb:v0C94* + ID_VENDOR_FROM_DATABASE=Cryptera + +usb:v0C94pA000* + ID_MODEL_FROM_DATABASE=EPP 1217 + +usb:v0C98* + ID_VENDOR_FROM_DATABASE=Berkshire Products, Inc. + +usb:v0C98p1140* + ID_MODEL_FROM_DATABASE=USB PC Watchdog + +usb:v0C99* + ID_VENDOR_FROM_DATABASE=Innochips Co., Ltd + +usb:v0C9A* + ID_VENDOR_FROM_DATABASE=Hanwool Robotics Corp. + +usb:v0C9B* + ID_VENDOR_FROM_DATABASE=Jobin Yvon, Inc. + +usb:v0C9D* + ID_VENDOR_FROM_DATABASE=SemTek + +usb:v0C9Dp0170* + ID_MODEL_FROM_DATABASE=3873 Manual Insert card reader + +usb:v0CA2* + ID_VENDOR_FROM_DATABASE=Zyfer + +usb:v0CA3* + ID_VENDOR_FROM_DATABASE=Sega Corp. + +usb:v0CA4* + ID_VENDOR_FROM_DATABASE=ST&T Instrument Corp. + +usb:v0CA5* + ID_VENDOR_FROM_DATABASE=BAE Systems Canada, Inc. + +usb:v0CA6* + ID_VENDOR_FROM_DATABASE=Castles Technology Co., Ltd + +usb:v0CA6p0010* + ID_MODEL_FROM_DATABASE=EZUSB PC/SC Smart Card Reader + +usb:v0CA6p0050* + ID_MODEL_FROM_DATABASE=EZ220PU Reader Controller + +usb:v0CA6p1077* + ID_MODEL_FROM_DATABASE=Bludrive Family Smart Card Reader + +usb:v0CA6p107E* + ID_MODEL_FROM_DATABASE=Reader Controller + +usb:v0CA6p2010* + ID_MODEL_FROM_DATABASE=myPad110 PC/SC Smart Card Reader + +usb:v0CA6p3050* + ID_MODEL_FROM_DATABASE=EZ710 Smart Card Reader + +usb:v0CA7* + ID_VENDOR_FROM_DATABASE=Information Systems Laboratories + +usb:v0CAD* + ID_VENDOR_FROM_DATABASE=Motorola CGISS + +usb:v0CADp9001* + ID_MODEL_FROM_DATABASE=PowerPad Pocket PC Device + +usb:v0CAE* + ID_VENDOR_FROM_DATABASE=Ascom Business Systems, Ltd + +usb:v0CAF* + ID_VENDOR_FROM_DATABASE=Buslink + +usb:v0CAFp2507* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v0CAFp2515* + ID_MODEL_FROM_DATABASE=Flash Disk Embedded Hub + +usb:v0CAFp2516* + ID_MODEL_FROM_DATABASE=Flash Disk Security Device + +usb:v0CAFp2517* + ID_MODEL_FROM_DATABASE=Flash Disk Mass Storage Device + +usb:v0CAFp25C7* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v0CAFp3A00* + ID_MODEL_FROM_DATABASE=Hard Drive + +usb:v0CAFp3A20* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0CAFp3ACD* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0CB0* + ID_VENDOR_FROM_DATABASE=Flying Pig Systems + +usb:v0CB1* + ID_VENDOR_FROM_DATABASE=Innovonics, Inc. + +usb:v0CB6* + ID_VENDOR_FROM_DATABASE=Celestix Networks, Pte., Ltd + +usb:v0CB7* + ID_VENDOR_FROM_DATABASE=Singatron Enterprise Co., Ltd + +usb:v0CB8* + ID_VENDOR_FROM_DATABASE=Opticis Co., Ltd + +usb:v0CBA* + ID_VENDOR_FROM_DATABASE=Trust Electronic (Shanghai) Co., Ltd + +usb:v0CBB* + ID_VENDOR_FROM_DATABASE=Shanghai Darong Electronics Co., Ltd + +usb:v0CBC* + ID_VENDOR_FROM_DATABASE=Palmax Technology Co., Ltd + +usb:v0CBCp0101* + ID_MODEL_FROM_DATABASE=Pocket PC P6C + +usb:v0CBCp0201* + ID_MODEL_FROM_DATABASE=Personal Digital Assistant + +usb:v0CBCp0301* + ID_MODEL_FROM_DATABASE=Personal Digital Assistant P6M+ + +usb:v0CBCp0401* + ID_MODEL_FROM_DATABASE=Pocket PC + +usb:v0CBD* + ID_VENDOR_FROM_DATABASE=Pentel Co., Ltd (Electronics Equipment Div.) + +usb:v0CBE* + ID_VENDOR_FROM_DATABASE=Keryx Technologies, Inc. + +usb:v0CBF* + ID_VENDOR_FROM_DATABASE=Union Genius Computer Co., Ltd + +usb:v0CC0* + ID_VENDOR_FROM_DATABASE=Kuon Yi Industrial Corp. + +usb:v0CC1* + ID_VENDOR_FROM_DATABASE=Given Imaging, Ltd + +usb:v0CC2* + ID_VENDOR_FROM_DATABASE=Timex Corp. + +usb:v0CC3* + ID_VENDOR_FROM_DATABASE=Rimage Corp. + +usb:v0CC4* + ID_VENDOR_FROM_DATABASE=emsys GmbH + +usb:v0CC5* + ID_VENDOR_FROM_DATABASE=Sendo + +usb:v0CC6* + ID_VENDOR_FROM_DATABASE=Intermagic Corp. + +usb:v0CC7* + ID_VENDOR_FROM_DATABASE=Kontron Medical AG + +usb:v0CC8* + ID_VENDOR_FROM_DATABASE=Technotools Corp. + +usb:v0CC9* + ID_VENDOR_FROM_DATABASE=BroadMAX Technologies, Inc. + +usb:v0CCA* + ID_VENDOR_FROM_DATABASE=Amphenol + +usb:v0CCB* + ID_VENDOR_FROM_DATABASE=SKNet Co., Ltd + +usb:v0CCC* + ID_VENDOR_FROM_DATABASE=Domex Technology Corp. + +usb:v0CCD* + ID_VENDOR_FROM_DATABASE=TerraTec Electronic GmbH + +usb:v0CCDp0012* + ID_MODEL_FROM_DATABASE=PHASE 26 + +usb:v0CCDp0013* + ID_MODEL_FROM_DATABASE=PHASE 26 + +usb:v0CCDp0014* + ID_MODEL_FROM_DATABASE=PHASE 26 + +usb:v0CCDp0015* + ID_MODEL_FROM_DATABASE=Flash Update for TerraTec PHASE 26 + +usb:v0CCDp0021* + ID_MODEL_FROM_DATABASE=Cameo Grabster 200 + +usb:v0CCDp0023* + ID_MODEL_FROM_DATABASE=Mystify Claw + +usb:v0CCDp0028* + ID_MODEL_FROM_DATABASE=Aureon 5.1 MkII + +usb:v0CCDp0032* + ID_MODEL_FROM_DATABASE=MIDI HUBBLE + +usb:v0CCDp0035* + ID_MODEL_FROM_DATABASE=Miditech Play'n Roll + +usb:v0CCDp0036* + ID_MODEL_FROM_DATABASE=Cinergy 250 Audio + +usb:v0CCDp0037* + ID_MODEL_FROM_DATABASE=Cinergy 250 Audio + +usb:v0CCDp0038* + ID_MODEL_FROM_DATABASE=Cinergy T² DVB-T Receiver + +usb:v0CCDp0039* + ID_MODEL_FROM_DATABASE=Grabster AV 400 + +usb:v0CCDp003B* + ID_MODEL_FROM_DATABASE=Cinergy 400 + +usb:v0CCDp003C* + ID_MODEL_FROM_DATABASE=Grabster AV 250 + +usb:v0CCDp0042* + ID_MODEL_FROM_DATABASE=Cinergy Hybrid T XS + +usb:v0CCDp0043* + ID_MODEL_FROM_DATABASE=Cinergy T XS + +usb:v0CCDp004E* + ID_MODEL_FROM_DATABASE=Cinergy T XS + +usb:v0CCDp004F* + ID_MODEL_FROM_DATABASE=Cinergy Analog XS + +usb:v0CCDp0055* + ID_MODEL_FROM_DATABASE=Cinergy T XE (Version 1, AF9005) + +usb:v0CCDp005C* + ID_MODEL_FROM_DATABASE=Cinergy T² + +usb:v0CCDp0069* + ID_MODEL_FROM_DATABASE=Cinergy T XE (Version 2, AF9015) + +usb:v0CCDp006B* + ID_MODEL_FROM_DATABASE=Cinergy HT PVR (EU) + +usb:v0CCDp0072* + ID_MODEL_FROM_DATABASE=Cinergy Hybrid T + +usb:v0CCDp0077* + ID_MODEL_FROM_DATABASE=Aureon Dual USB + +usb:v0CCDp0078* + ID_MODEL_FROM_DATABASE=Cinergy T XXS + +usb:v0CCDp0086* + ID_MODEL_FROM_DATABASE=Cinergy Hybrid XE + +usb:v0CCDp008E* + ID_MODEL_FROM_DATABASE=Cinergy HTC XS + +usb:v0CCDp0097* + ID_MODEL_FROM_DATABASE=Cinergy T RC MKII + +usb:v0CCDp0099* + ID_MODEL_FROM_DATABASE=AfaTech 9015 [Cinergy T Stick Dual] + +usb:v0CCDp00A5* + ID_MODEL_FROM_DATABASE=Cinergy Hybrid Stick + +usb:v0CCDp00A9* + ID_MODEL_FROM_DATABASE=RTL2838 DVB-T COFDM Demodulator [TerraTec Cinergy T Stick Black] + +usb:v0CCDp00B3* + ID_MODEL_FROM_DATABASE=NOXON DAB/DAB+ Stick + +usb:v0CCDp00E0* + ID_MODEL_FROM_DATABASE=NOXON DAB/DAB+ Stick V2 + +usb:v0CCDp10A7* + ID_MODEL_FROM_DATABASE=TerraTec G3 + +usb:v0CD4* + ID_VENDOR_FROM_DATABASE=Bang Olufsen + +usb:v0CD4p0101* + ID_MODEL_FROM_DATABASE=BeolinkPC2 + +usb:v0CD5* + ID_VENDOR_FROM_DATABASE=LabJack Corporation + +usb:v0CD5p0003* + ID_MODEL_FROM_DATABASE=U3 + +usb:v0CD5p0009* + ID_MODEL_FROM_DATABASE=UE9 + +usb:v0CD7* + ID_VENDOR_FROM_DATABASE=NewChip S.r.l. + +usb:v0CD8* + ID_VENDOR_FROM_DATABASE=JS Digitech, Inc. + +usb:v0CD8p2007* + ID_MODEL_FROM_DATABASE=Smart Card Reader/JSTU-9700 + +usb:v0CD9* + ID_VENDOR_FROM_DATABASE=Hitachi Shin Din Cable, Ltd + +usb:v0CDE* + ID_VENDOR_FROM_DATABASE=Z-Com + +usb:v0CDEp0001* + ID_MODEL_FROM_DATABASE=XI-750 802.11b Wireless Adapter [Atmel AT76C503A] + +usb:v0CDEp0002* + ID_MODEL_FROM_DATABASE=XI-725/726 Prism2.5 802.11b Adapter + +usb:v0CDEp0003* + ID_MODEL_FROM_DATABASE=Sagem 802.11b Dongle + +usb:v0CDEp0004* + ID_MODEL_FROM_DATABASE=Sagem 802.11b Dongle + +usb:v0CDEp0005* + ID_MODEL_FROM_DATABASE=XI-735 Prism3 802.11b Adapter + +usb:v0CDEp0006* + ID_MODEL_FROM_DATABASE=XG-300 802.11b Adapter + +usb:v0CDEp0008* + ID_MODEL_FROM_DATABASE=XG-703A 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v0CDEp0009* + ID_MODEL_FROM_DATABASE=(ZD1211)IEEE 802.11b+g Adapter + +usb:v0CDEp0011* + ID_MODEL_FROM_DATABASE=ZD1211 + +usb:v0CDEp0012* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0CDEp0013* + ID_MODEL_FROM_DATABASE=AR5523 driver (no firmware) + +usb:v0CDEp0014* + ID_MODEL_FROM_DATABASE=NB 802.11g Wireless LAN Adapter(3887A) + +usb:v0CDEp0015* + ID_MODEL_FROM_DATABASE=XG-705A 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v0CDEp0016* + ID_MODEL_FROM_DATABASE=NB 802.11g Wireless LAN Adapter(3887A) + +usb:v0CDEp0018* + ID_MODEL_FROM_DATABASE=NB 802.11a/b/g Wireless LAN Adapter(3887A) + +usb:v0CDEp001A* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v0CDEp001C* + ID_MODEL_FROM_DATABASE=802.11b/g Wireless Network Adapter + +usb:v0CDEp0020* + ID_MODEL_FROM_DATABASE=AG-760A 802.11abg Wireless Adapter [ZyDAS ZD1211B] + +usb:v0CDEp0022* + ID_MODEL_FROM_DATABASE=802.11b/g/n Wireless Network Adapter + +usb:v0CDEp0023* + ID_MODEL_FROM_DATABASE=UB81 802.11bgn + +usb:v0CDEp0025* + ID_MODEL_FROM_DATABASE=802.11b/g/n USB Wireless Network Adapter + +usb:v0CDEp0026* + ID_MODEL_FROM_DATABASE=UB82 802.11abgn + +usb:v0CDEp0027* + ID_MODEL_FROM_DATABASE=Sphairon Homelink 1202 802.11n Wireless Adapter [Atheros AR9170] + +usb:v0CE5* + ID_VENDOR_FROM_DATABASE=Validation Technologies International + +usb:v0CE5p0003* + ID_MODEL_FROM_DATABASE=Matrix + +usb:v0CE9* + ID_VENDOR_FROM_DATABASE=pico Technology + +usb:v0CE9p1001* + ID_MODEL_FROM_DATABASE=PicoScope3000 series PC Oscilloscope + +usb:v0CF1* + ID_VENDOR_FROM_DATABASE=e-Conn Electronic Co., Ltd + +usb:v0CF2* + ID_VENDOR_FROM_DATABASE=ENE Technology, Inc. + +usb:v0CF2p6220* + ID_MODEL_FROM_DATABASE=SD Card Reader (SG361) + +usb:v0CF2p6225* + ID_MODEL_FROM_DATABASE=SD card reader (UB6225) + +usb:v0CF2p6250* + ID_MODEL_FROM_DATABASE=SD card reader (UB6250) + +usb:v0CF3* + ID_VENDOR_FROM_DATABASE=Atheros Communications, Inc. + +usb:v0CF3p0001* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0CF3p0002* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v0CF3p0003* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0CF3p0004* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v0CF3p0005* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0CF3p0006* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v0CF3p1001* + ID_MODEL_FROM_DATABASE=Thomson TG121N [Atheros AR9001U-(2)NG] + +usb:v0CF3p1002* + ID_MODEL_FROM_DATABASE=TP-Link TL-WN821N v2 / TL-WN822N v1 802.11n [Atheros AR9170] + +usb:v0CF3p1006* + ID_MODEL_FROM_DATABASE=TP-Link TL-WN322G v3 / TL-WN422G v2 802.11g [Atheros AR9271] + +usb:v0CF3p1010* + ID_MODEL_FROM_DATABASE=3Com 3CRUSBN275 802.11abgn Wireless Adapter [Atheros AR9170] + +usb:v0CF3p20FF* + ID_MODEL_FROM_DATABASE=AR7010 (no firmware) + +usb:v0CF3p3000* + ID_MODEL_FROM_DATABASE=AR3011 Bluetooth (no firmware) + +usb:v0CF3p3002* + ID_MODEL_FROM_DATABASE=AR3011 Bluetooth + +usb:v0CF3p3005* + ID_MODEL_FROM_DATABASE=AR3011 Bluetooth + +usb:v0CF3p3008* + ID_MODEL_FROM_DATABASE=Bluetooth (AR3011) + +usb:v0CF3p7015* + ID_MODEL_FROM_DATABASE=TP-Link TL-WN821N v3 / TL-WN822N v2 802.11n [Atheros AR7010+AR9287] + +usb:v0CF3p9170* + ID_MODEL_FROM_DATABASE=AR9170 802.11n + +usb:v0CF3p9271* + ID_MODEL_FROM_DATABASE=AR9271 802.11n + +usb:v0CF3pB002* + ID_MODEL_FROM_DATABASE=Ubiquiti WiFiStation 802.11n [Atheros AR9271] + +usb:v0CF3pB003* + ID_MODEL_FROM_DATABASE=Ubiquiti WiFiStationEXT 802.11n [Atheros AR9271] + +usb:v0CF4* + ID_VENDOR_FROM_DATABASE=Fomtex Corp. + +usb:v0CF5* + ID_VENDOR_FROM_DATABASE=Cellink Co., Ltd + +usb:v0CF6* + ID_VENDOR_FROM_DATABASE=Compucable Corp. + +usb:v0CF7* + ID_VENDOR_FROM_DATABASE=ishoni Networks + +usb:v0CF8* + ID_VENDOR_FROM_DATABASE=Clarisys, Inc. + +usb:v0CF8p0750* + ID_MODEL_FROM_DATABASE=Claritel-i750 - vp + +usb:v0CF9* + ID_VENDOR_FROM_DATABASE=Central System Research Co., Ltd + +usb:v0CFA* + ID_VENDOR_FROM_DATABASE=Inviso, Inc. + +usb:v0CFC* + ID_VENDOR_FROM_DATABASE=Minolta-QMS, Inc. + +usb:v0CFCp2301* + ID_MODEL_FROM_DATABASE=Magicolor 2300 DL + +usb:v0CFCp2350* + ID_MODEL_FROM_DATABASE=Magicolor 2350EN/3300 + +usb:v0CFCp3100* + ID_MODEL_FROM_DATABASE=Magicolor 3100 + +usb:v0CFCp7300* + ID_MODEL_FROM_DATABASE=Magicolor 5450/5550 + +usb:v0CFF* + ID_VENDOR_FROM_DATABASE=SAFA MEDIA Co., Ltd. + +usb:v0CFFp0320* + ID_MODEL_FROM_DATABASE=SR-380N + +usb:v0D06* + ID_VENDOR_FROM_DATABASE=telos EDV Systementwicklung GmbH + +usb:v0D08* + ID_VENDOR_FROM_DATABASE=UTStarcom + +usb:v0D08p0602* + ID_MODEL_FROM_DATABASE=DV007 [serial] + +usb:v0D08p0603* + ID_MODEL_FROM_DATABASE=DV007 [storage] + +usb:v0D0B* + ID_VENDOR_FROM_DATABASE=Contemporary Controls + +usb:v0D0C* + ID_VENDOR_FROM_DATABASE=Astron Electronics Co., Ltd + +usb:v0D0D* + ID_VENDOR_FROM_DATABASE=MKNet Corp. + +usb:v0D0E* + ID_VENDOR_FROM_DATABASE=Hybrid Networks, Inc. + +usb:v0D0F* + ID_VENDOR_FROM_DATABASE=Feng Shin Cable Co., Ltd + +usb:v0D10* + ID_VENDOR_FROM_DATABASE=Elastic Networks + +usb:v0D10p0001* + ID_MODEL_FROM_DATABASE=StormPort (WDM) + +usb:v0D11* + ID_VENDOR_FROM_DATABASE=Maspro Denkoh Corp. + +usb:v0D12* + ID_VENDOR_FROM_DATABASE=Hansol Electronics, Inc. + +usb:v0D13* + ID_VENDOR_FROM_DATABASE=BMF Corp. + +usb:v0D14* + ID_VENDOR_FROM_DATABASE=Array Comm, Inc. + +usb:v0D15* + ID_VENDOR_FROM_DATABASE=OnStream b.v. + +usb:v0D16* + ID_VENDOR_FROM_DATABASE=Hi-Touch Imaging Technologies Co., Ltd + +usb:v0D16p0001* + ID_MODEL_FROM_DATABASE=PhotoShuttle + +usb:v0D16p0002* + ID_MODEL_FROM_DATABASE=Photo Printer 730 series + +usb:v0D16p0004* + ID_MODEL_FROM_DATABASE=Photo Printer 63xPL/PS + +usb:v0D16p0100* + ID_MODEL_FROM_DATABASE=Photo Printer 63xPL/PS + +usb:v0D16p0102* + ID_MODEL_FROM_DATABASE=Photo Printer 64xPS + +usb:v0D16p0103* + ID_MODEL_FROM_DATABASE=Photo Printer 730 series + +usb:v0D16p0104* + ID_MODEL_FROM_DATABASE=Photo Printer 63xPL/PS + +usb:v0D16p0105* + ID_MODEL_FROM_DATABASE=Photo Printer 64xPS + +usb:v0D16p0200* + ID_MODEL_FROM_DATABASE=Photo Printer 64xDL + +usb:v0D17* + ID_VENDOR_FROM_DATABASE=NALTEC, Inc. + +usb:v0D18* + ID_VENDOR_FROM_DATABASE=coaXmedia + +usb:v0D19* + ID_VENDOR_FROM_DATABASE=Hank Connection Industrial Co., Ltd + +usb:v0D28* + ID_VENDOR_FROM_DATABASE=NXP + +usb:v0D28p0204* + ID_MODEL_FROM_DATABASE=LPC1768 + +usb:v0D32* + ID_VENDOR_FROM_DATABASE=Leo Hui Electric Wire & Cable Co., Ltd + +usb:v0D33* + ID_VENDOR_FROM_DATABASE=AirSpeak, Inc. + +usb:v0D34* + ID_VENDOR_FROM_DATABASE=Rearden Steel Technologies + +usb:v0D35* + ID_VENDOR_FROM_DATABASE=Dah Kun Co., Ltd + +usb:v0D3A* + ID_VENDOR_FROM_DATABASE=Posiflex Technologies, Inc. + +usb:v0D3C* + ID_VENDOR_FROM_DATABASE=Sri Cable Technology, Ltd + +usb:v0D3D* + ID_VENDOR_FROM_DATABASE=Tangtop Technology Co., Ltd + +usb:v0D3Dp0001* + ID_MODEL_FROM_DATABASE=HID Keyboard + +usb:v0D3E* + ID_VENDOR_FROM_DATABASE=Fitcom, inc. + +usb:v0D3F* + ID_VENDOR_FROM_DATABASE=MTS Systems Corp. + +usb:v0D40* + ID_VENDOR_FROM_DATABASE=Ascor, Inc. + +usb:v0D41* + ID_VENDOR_FROM_DATABASE=Ta Yun Terminals Industrial Co., Ltd + +usb:v0D42* + ID_VENDOR_FROM_DATABASE=Full Der Co., Ltd + +usb:v0D46* + ID_VENDOR_FROM_DATABASE=Kobil Systems GmbH + +usb:v0D46p2012* + ID_MODEL_FROM_DATABASE=KAAN Standard Plus (Smartcard reader) + +usb:v0D46p3003* + ID_MODEL_FROM_DATABASE=mIDentity Light / KAAN SIM III + +usb:v0D46p4000* + ID_MODEL_FROM_DATABASE=mIDentity (mass storage) + +usb:v0D46p4001* + ID_MODEL_FROM_DATABASE=mIDentity Basic/Classic (composite device) + +usb:v0D46p4081* + ID_MODEL_FROM_DATABASE=mIDentity Basic/Classic (installationless) + +usb:v0D48* + ID_VENDOR_FROM_DATABASE=Promethean Limited + +usb:v0D48p0001* + ID_MODEL_FROM_DATABASE=ACTIVboard + +usb:v0D48p0004* + ID_MODEL_FROM_DATABASE=ACTIVboard + +usb:v0D48p0100* + ID_MODEL_FROM_DATABASE=Audio + +usb:v0D49* + ID_VENDOR_FROM_DATABASE=Maxtor + +usb:v0D49p3000* + ID_MODEL_FROM_DATABASE=Drive + +usb:v0D49p3010* + ID_MODEL_FROM_DATABASE=3000LE Drive + +usb:v0D49p3100* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-IDE Bridge Controller + +usb:v0D49p3200* + ID_MODEL_FROM_DATABASE=Personal Storage 3200 + +usb:v0D49p5000* + ID_MODEL_FROM_DATABASE=5000XT Drive + +usb:v0D49p5010* + ID_MODEL_FROM_DATABASE=5000LE Drive + +usb:v0D49p5020* + ID_MODEL_FROM_DATABASE=Mobile Hard Disk Drive + +usb:v0D49p7000* + ID_MODEL_FROM_DATABASE=OneTouch + +usb:v0D49p7010* + ID_MODEL_FROM_DATABASE=OneTouch + +usb:v0D49p7100* + ID_MODEL_FROM_DATABASE=OneTouch II 300GB External Hard Disk + +usb:v0D49p7410* + ID_MODEL_FROM_DATABASE=Mobile Hard Disk Drive (1TB) + +usb:v0D49p7450* + ID_MODEL_FROM_DATABASE=Basics Portable USB Device + +usb:v0D4A* + ID_VENDOR_FROM_DATABASE=NF Corp. + +usb:v0D4B* + ID_VENDOR_FROM_DATABASE=Grape Systems, Inc. + +usb:v0D4C* + ID_VENDOR_FROM_DATABASE=Tedas AG + +usb:v0D4D* + ID_VENDOR_FROM_DATABASE=Coherent, Inc. + +usb:v0D4E* + ID_VENDOR_FROM_DATABASE=Agere Systems Netherland BV + +usb:v0D4Ep047A* + ID_MODEL_FROM_DATABASE=WLAN Card + +usb:v0D4Ep1000* + ID_MODEL_FROM_DATABASE=Wireless Card Model 0801 + +usb:v0D4Ep1001* + ID_MODEL_FROM_DATABASE=Wireless Card Model 0802 + +usb:v0D4F* + ID_VENDOR_FROM_DATABASE=EADS Airbus France + +usb:v0D50* + ID_VENDOR_FROM_DATABASE=Cleware GmbH + +usb:v0D50p0011* + ID_MODEL_FROM_DATABASE=USB-Temp2 Thermometer + +usb:v0D50p0040* + ID_MODEL_FROM_DATABASE=F4 foot switch + +usb:v0D51* + ID_VENDOR_FROM_DATABASE=Volex (Asia) Pte., Ltd + +usb:v0D53* + ID_VENDOR_FROM_DATABASE=HMI Co., Ltd + +usb:v0D54* + ID_VENDOR_FROM_DATABASE=Holon Corp. + +usb:v0D55* + ID_VENDOR_FROM_DATABASE=ASKA Technologies, Inc. + +usb:v0D56* + ID_VENDOR_FROM_DATABASE=AVLAB Technology, Inc. + +usb:v0D57* + ID_VENDOR_FROM_DATABASE=Solomon Microtech, Ltd + +usb:v0D5C* + ID_VENDOR_FROM_DATABASE=SMC Networks, Inc. + +usb:v0D5CpA001* + ID_MODEL_FROM_DATABASE=SMC2662W (v1) EZ Connect 802.11b Wireless Adapter [Atmel AT76C503A] + +usb:v0D5CpA002* + ID_MODEL_FROM_DATABASE=SMC2662W v2 / SMC2662W-AR / Belkin F5D6050 [Atmel at76c503a] + +usb:v0D5E* + ID_VENDOR_FROM_DATABASE=Myacom, Ltd + +usb:v0D5Ep2346* + ID_MODEL_FROM_DATABASE=BT Digital Access adapter + +usb:v0D5F* + ID_VENDOR_FROM_DATABASE=CSI, Inc. + +usb:v0D60* + ID_VENDOR_FROM_DATABASE=IVL Technologies, Ltd + +usb:v0D61* + ID_VENDOR_FROM_DATABASE=Meilu Electronics (Shenzhen) Co., Ltd + +usb:v0D62* + ID_VENDOR_FROM_DATABASE=Darfon Electronics Corp. + +usb:v0D62p0003* + ID_MODEL_FROM_DATABASE=Smartcard Reader + +usb:v0D62p0004* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v0D62p001C* + ID_MODEL_FROM_DATABASE=Benq X120 Internet Keyboard Pro + +usb:v0D62p0306* + ID_MODEL_FROM_DATABASE=M530 Mouse + +usb:v0D62p0800* + ID_MODEL_FROM_DATABASE=Magic Wheel + +usb:v0D62p2021* + ID_MODEL_FROM_DATABASE=AM805 Keyboard + +usb:v0D62p2026* + ID_MODEL_FROM_DATABASE=TECOM Bluetooth Device + +usb:v0D62p2050* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v0D62p2106* + ID_MODEL_FROM_DATABASE=Dell L20U Multimedia Keyboard + +usb:v0D62pA100* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v0D63* + ID_VENDOR_FROM_DATABASE=Fritz Gegauf AG + +usb:v0D64* + ID_VENDOR_FROM_DATABASE=DXG Technology Corp. + +usb:v0D64p0105* + ID_MODEL_FROM_DATABASE=Dual Mode Digital Camera 1.3M + +usb:v0D64p0107* + ID_MODEL_FROM_DATABASE=Horus MT-409 Camera + +usb:v0D64p0108* + ID_MODEL_FROM_DATABASE=Dual Mode Digital Camera + +usb:v0D64p0202* + ID_MODEL_FROM_DATABASE=Dual Mode Video Camera Device + +usb:v0D64p0303* + ID_MODEL_FROM_DATABASE=DXG-305V Camera + +usb:v0D64p1001* + ID_MODEL_FROM_DATABASE=SiPix Stylecam/UMAX AstraPix 320s + +usb:v0D64p1002* + ID_MODEL_FROM_DATABASE=Fashion Cam 01 Dual-Mode DSC (Video Camera) + +usb:v0D64p1003* + ID_MODEL_FROM_DATABASE=Fashion Cam Dual-Mode DSC (Controller) + +usb:v0D64p1021* + ID_MODEL_FROM_DATABASE=D-Link DSC 350F + +usb:v0D64p1208* + ID_MODEL_FROM_DATABASE=Dual Mode Still Camera Device + +usb:v0D64p2208* + ID_MODEL_FROM_DATABASE=Mass Storage + +usb:v0D64p3105* + ID_MODEL_FROM_DATABASE=Dual Mode Digital Camera Disk + +usb:v0D64p3108* + ID_MODEL_FROM_DATABASE=Digicam Mass Storage Device + +usb:v0D65* + ID_VENDOR_FROM_DATABASE=KMJP Co., Ltd + +usb:v0D66* + ID_VENDOR_FROM_DATABASE=TMT + +usb:v0D67* + ID_VENDOR_FROM_DATABASE=Advanet, Inc. + +usb:v0D68* + ID_VENDOR_FROM_DATABASE=Super Link Electronics Co., Ltd + +usb:v0D69* + ID_VENDOR_FROM_DATABASE=NSI + +usb:v0D6A* + ID_VENDOR_FROM_DATABASE=Megapower International Corp. + +usb:v0D6B* + ID_VENDOR_FROM_DATABASE=And-Or Logic + +usb:v0D70* + ID_VENDOR_FROM_DATABASE=Try Computer Co., Ltd + +usb:v0D71* + ID_VENDOR_FROM_DATABASE=Hirakawa Hewtech Corp. + +usb:v0D72* + ID_VENDOR_FROM_DATABASE=Winmate Communication, Inc. + +usb:v0D73* + ID_VENDOR_FROM_DATABASE=Hit's Communications, Inc. + +usb:v0D76* + ID_VENDOR_FROM_DATABASE=MFP Korea, Inc. + +usb:v0D77* + ID_VENDOR_FROM_DATABASE=Power Sentry/Newpoint + +usb:v0D78* + ID_VENDOR_FROM_DATABASE=Japan Distributor Corp. + +usb:v0D7A* + ID_VENDOR_FROM_DATABASE=MARX Datentechnik GmbH + +usb:v0D7B* + ID_VENDOR_FROM_DATABASE=Wellco Technology Co., Ltd + +usb:v0D7C* + ID_VENDOR_FROM_DATABASE=Taiwan Line Tek Electronic Co., Ltd + +usb:v0D7D* + ID_VENDOR_FROM_DATABASE=Phison Electronics Corp. + +usb:v0D7Dp0100* + ID_MODEL_FROM_DATABASE=PS1001/1011/1006/1026 Flash Disk + +usb:v0D7Dp0110* + ID_MODEL_FROM_DATABASE=Gigabyte FlexDrive + +usb:v0D7Dp0120* + ID_MODEL_FROM_DATABASE=Disk Pro 64MB + +usb:v0D7Dp0124* + ID_MODEL_FROM_DATABASE=GIGABYTE Disk + +usb:v0D7Dp0240* + ID_MODEL_FROM_DATABASE=I/O-Magic/Transcend 6-in-1 Card Reader + +usb:v0D7Dp110E* + ID_MODEL_FROM_DATABASE=NEC uPD720121/130 USB-ATA/ATAPI Bridge + +usb:v0D7Dp1240* + ID_MODEL_FROM_DATABASE=Apacer 6-in-1 Card Reader 2.0 + +usb:v0D7Dp1270* + ID_MODEL_FROM_DATABASE=Wolverine SixPac 6000 + +usb:v0D7Dp1300* + ID_MODEL_FROM_DATABASE=Flash Disk + +usb:v0D7Dp1320* + ID_MODEL_FROM_DATABASE=PS2031 Flash Disk + +usb:v0D7Dp1400* + ID_MODEL_FROM_DATABASE=Attache 256MB USB 2.0 Flash Drive + +usb:v0D7Dp1420* + ID_MODEL_FROM_DATABASE=PS2044 Pen Drive + +usb:v0D7Dp1470* + ID_MODEL_FROM_DATABASE=Vosonic X's-Drive II+ VP2160 + +usb:v0D7Dp1620* + ID_MODEL_FROM_DATABASE=USB Disk Pro + +usb:v0D7Dp1900* + ID_MODEL_FROM_DATABASE=USB Thumb Drive + +usb:v0D7E* + ID_VENDOR_FROM_DATABASE=American Computer & Digital Components + +usb:v0D7Ep2507* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v0D7Ep2517* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v0D7Ep25C7* + ID_MODEL_FROM_DATABASE=Hi-Speed USB-to-IDE Bridge Controller + +usb:v0D7F* + ID_VENDOR_FROM_DATABASE=Essential Reality LLC + +usb:v0D7Fp0100* + ID_MODEL_FROM_DATABASE=P5 Glove glove controller + +usb:v0D80* + ID_VENDOR_FROM_DATABASE=H.R. Silvine Electronics, Inc. + +usb:v0D81* + ID_VENDOR_FROM_DATABASE=TechnoVision + +usb:v0D83* + ID_VENDOR_FROM_DATABASE=Think Outside, Inc. + +usb:v0D87* + ID_VENDOR_FROM_DATABASE=Dolby Laboratories Inc. + +usb:v0D89* + ID_VENDOR_FROM_DATABASE=Oz Software + +usb:v0D8A* + ID_VENDOR_FROM_DATABASE=King Jim Co., Ltd + +usb:v0D8Ap0101* + ID_MODEL_FROM_DATABASE=TEPRA PRO + +usb:v0D8B* + ID_VENDOR_FROM_DATABASE=Ascom Telecommunications, Ltd + +usb:v0D8C* + ID_VENDOR_FROM_DATABASE=C-Media Electronics, Inc. + +usb:v0D8Cp0001* + ID_MODEL_FROM_DATABASE=Audio Device + +usb:v0D8Cp0002* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v0D8Cp0003* + ID_MODEL_FROM_DATABASE=Sound Device + +usb:v0D8Cp0006* + ID_MODEL_FROM_DATABASE=Storm HP-USB500 5.1 Headset + +usb:v0D8Cp000C* + ID_MODEL_FROM_DATABASE=Audio Adapter + +usb:v0D8Cp000D* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v0D8Cp000E* + ID_MODEL_FROM_DATABASE=Audio Adapter (Planet UP-100, Genius G-Talk) + +usb:v0D8Cp001F* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp0102* + ID_MODEL_FROM_DATABASE=CM106 Like Sound Device + +usb:v0D8Cp0103* + ID_MODEL_FROM_DATABASE=CM102-A+/102S+ Audio Controller + +usb:v0D8Cp0104* + ID_MODEL_FROM_DATABASE=CM103+ Audio Controller + +usb:v0D8Cp0105* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp0107* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp010F* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp0115* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp013C* + ID_MODEL_FROM_DATABASE=CM108 Audio Controller + +usb:v0D8Cp0201* + ID_MODEL_FROM_DATABASE=CM6501 + +usb:v0D8Cp5000* + ID_MODEL_FROM_DATABASE=Mass Storage Controller + +usb:v0D8Cp5200* + ID_MODEL_FROM_DATABASE=Mass Storage Controller(0D8C,5200) + +usb:v0D8CpB213* + ID_MODEL_FROM_DATABASE=USB Phone CM109 (aka CT2000,VPT1000) + +usb:v0D8D* + ID_VENDOR_FROM_DATABASE=Promotion & Display Technology, Ltd + +usb:v0D8Dp0234* + ID_MODEL_FROM_DATABASE=V-234 Composite Device + +usb:v0D8Dp0550* + ID_MODEL_FROM_DATABASE=V-550 Composite Device + +usb:v0D8Dp0551* + ID_MODEL_FROM_DATABASE=V-551 Composite Device + +usb:v0D8Dp0552* + ID_MODEL_FROM_DATABASE=V-552 Composite Device + +usb:v0D8Dp0651* + ID_MODEL_FROM_DATABASE=V-651 Composite Device + +usb:v0D8Dp0652* + ID_MODEL_FROM_DATABASE=V-652 Composite Device + +usb:v0D8Dp0653* + ID_MODEL_FROM_DATABASE=V-653 Composite Device + +usb:v0D8Dp0654* + ID_MODEL_FROM_DATABASE=V-654 Composite Device + +usb:v0D8Dp0655* + ID_MODEL_FROM_DATABASE=V-655 Composite Device + +usb:v0D8Dp0656* + ID_MODEL_FROM_DATABASE=V-656 Composite Device + +usb:v0D8Dp0657* + ID_MODEL_FROM_DATABASE=V-657 Composite Device + +usb:v0D8Dp0658* + ID_MODEL_FROM_DATABASE=V-658 Composite Device + +usb:v0D8Dp0659* + ID_MODEL_FROM_DATABASE=V-659 Composite Device + +usb:v0D8Dp0660* + ID_MODEL_FROM_DATABASE=V-660 Composite Device + +usb:v0D8Dp0661* + ID_MODEL_FROM_DATABASE=V-661 Composite Device + +usb:v0D8Dp0662* + ID_MODEL_FROM_DATABASE=V-662 Composite Device + +usb:v0D8Dp0850* + ID_MODEL_FROM_DATABASE=V-850 Composite Device + +usb:v0D8Dp0851* + ID_MODEL_FROM_DATABASE=V-851 Composite Device + +usb:v0D8Dp0852* + ID_MODEL_FROM_DATABASE=V-852 Composite Device + +usb:v0D8Dp0901* + ID_MODEL_FROM_DATABASE=V-901 Composite Device + +usb:v0D8Dp0902* + ID_MODEL_FROM_DATABASE=V-902 Composite Device + +usb:v0D8Dp0903* + ID_MODEL_FROM_DATABASE=V-903 Composite Device + +usb:v0D8Dp4754* + ID_MODEL_FROM_DATABASE=Voyager DMP Composite Device + +usb:v0D8DpBB00* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpBB01* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpBB02* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpBB03* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpBB04* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpBB05* + ID_MODEL_FROM_DATABASE=Bloomberg Composite Device + +usb:v0D8DpFFFE* + ID_MODEL_FROM_DATABASE=Global Tuner Composite Device + +usb:v0D8DpFFFF* + ID_MODEL_FROM_DATABASE=Voyager DMP Composite Device + +usb:v0D8E* + ID_VENDOR_FROM_DATABASE=Global Sun Technology, Inc. + +usb:v0D8Ep0163* + ID_MODEL_FROM_DATABASE=802.11g 54 Mbps Wireless Dongle + +usb:v0D8Ep1621* + ID_MODEL_FROM_DATABASE=802.11b Wireless Adapter + +usb:v0D8Ep3762* + ID_MODEL_FROM_DATABASE=Cohiba 802.11g Wireless Mini adapter [Intersil ISL3887] + +usb:v0D8Ep3763* + ID_MODEL_FROM_DATABASE=802.11g Wireless dongle + +usb:v0D8Ep7100* + ID_MODEL_FROM_DATABASE=802.11b Adapter + +usb:v0D8Ep7110* + ID_MODEL_FROM_DATABASE=WL-210 / WU210P 802.11b Wireless Adapter [Atmel AT76C503A] + +usb:v0D8Ep7605* + ID_MODEL_FROM_DATABASE=TRENDnet TEW-224UB 802.11b Wireless Adapter [Atmel AT76C503A] + +usb:v0D8Ep7801* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0D8Ep7802* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v0D8Ep7811* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v0D8Ep7812* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v0D8Ep7A01* + ID_MODEL_FROM_DATABASE=PRISM25 802.11b Adapter + +usb:v0D8F* + ID_VENDOR_FROM_DATABASE=Pitney Bowes + +usb:v0D90* + ID_VENDOR_FROM_DATABASE=Sure-Fire Electrical Corp. + +usb:v0D96* + ID_VENDOR_FROM_DATABASE=Skanhex Technology, Inc. + +usb:v0D96p0000* + ID_MODEL_FROM_DATABASE=Jenoptik JD350 video + +usb:v0D96p3300* + ID_MODEL_FROM_DATABASE=SX330z Camera + +usb:v0D96p4100* + ID_MODEL_FROM_DATABASE=SX410z Camera + +usb:v0D96p4102* + ID_MODEL_FROM_DATABASE=MD 9700 Camera + +usb:v0D96p4104* + ID_MODEL_FROM_DATABASE=Jenoptik JD-4100z3s + +usb:v0D96p410A* + ID_MODEL_FROM_DATABASE=Medion 9801/Novatech SX-410z + +usb:v0D96p5200* + ID_MODEL_FROM_DATABASE=SX-520z Camera + +usb:v0D97* + ID_VENDOR_FROM_DATABASE=Santa Barbara Instrument Group + +usb:v0D97p0001* + ID_MODEL_FROM_DATABASE=SBIG Astronomy Camera (without firmware) + +usb:v0D97p0101* + ID_MODEL_FROM_DATABASE=SBIG Astronomy Camera (with firmware) + +usb:v0D98* + ID_VENDOR_FROM_DATABASE=Mars Semiconductor Corp. + +usb:v0D98p0300* + ID_MODEL_FROM_DATABASE=Avaya Wireless Card + +usb:v0D98p1007* + ID_MODEL_FROM_DATABASE=Discovery Kids Digital Camera + +usb:v0D99* + ID_VENDOR_FROM_DATABASE=Trazer Technologies, Inc. + +usb:v0D9A* + ID_VENDOR_FROM_DATABASE=RTX Telecom AS + +usb:v0D9Ap0001* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0D9B* + ID_VENDOR_FROM_DATABASE=Tat Shing Electrical Co. + +usb:v0D9C* + ID_VENDOR_FROM_DATABASE=Chee Chen Hi-Technology Co., Ltd + +usb:v0D9D* + ID_VENDOR_FROM_DATABASE=Sanwa Supply, Inc. + +usb:v0D9E* + ID_VENDOR_FROM_DATABASE=Avaya + +usb:v0D9Ep0300* + ID_MODEL_FROM_DATABASE=Wireless Card + +usb:v0D9F* + ID_VENDOR_FROM_DATABASE=Powercom Co., Ltd + +usb:v0D9Fp0001* + ID_MODEL_FROM_DATABASE=Uninterruptible Power Supply + +usb:v0D9Fp0002* + ID_MODEL_FROM_DATABASE=Black Knight PRO / WOW Uninterruptible Power Supply (Cypress HID->COM RS232) + +usb:v0D9Fp00A2* + ID_MODEL_FROM_DATABASE=Imperial Uninterruptible Power Supply (HID PDC) + +usb:v0D9Fp00A3* + ID_MODEL_FROM_DATABASE=Smart King PRO Uninterruptible Power Supply (HID PDC) + +usb:v0D9Fp00A4* + ID_MODEL_FROM_DATABASE=WOW Uninterruptible Power Supply (HID PDC) + +usb:v0D9Fp00A5* + ID_MODEL_FROM_DATABASE=Vanguard Uninterruptible Power Supply (HID PDC) + +usb:v0D9Fp00A6* + ID_MODEL_FROM_DATABASE=Black Knight PRO Uninterruptible Power Supply (HID PDC) + +usb:v0DA0* + ID_VENDOR_FROM_DATABASE=Danger Research + +usb:v0DA1* + ID_VENDOR_FROM_DATABASE=Suzhou Peter's Precise Industrial Co., Ltd + +usb:v0DA2* + ID_VENDOR_FROM_DATABASE=Land Instruments International, Ltd + +usb:v0DA3* + ID_VENDOR_FROM_DATABASE=Nippon Electro-Sensory Devices Corp. + +usb:v0DA4* + ID_VENDOR_FROM_DATABASE=Polar Electro OY + +usb:v0DA4p0001* + ID_MODEL_FROM_DATABASE=Interface + +usb:v0DA7* + ID_VENDOR_FROM_DATABASE=IOGear, Inc. + +usb:v0DA8* + ID_VENDOR_FROM_DATABASE=softDSP Co., Ltd + +usb:v0DA8p0001* + ID_MODEL_FROM_DATABASE=SDS 200A Oscilloscope + +usb:v0DAB* + ID_VENDOR_FROM_DATABASE=Cubig Group + +usb:v0DABp0100* + ID_MODEL_FROM_DATABASE=DVR/CVR-M140 MP3 Player + +usb:v0DAD* + ID_VENDOR_FROM_DATABASE=Westover Scientific + +usb:v0DB0* + ID_VENDOR_FROM_DATABASE=Micro Star International + +usb:v0DB0p1020* + ID_MODEL_FROM_DATABASE=PC2PC WLAN Card + +usb:v0DB0p1967* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0DB0p3801* + ID_MODEL_FROM_DATABASE=Motorola Bluetooth 2.1+EDR Device + +usb:v0DB0p4011* + ID_MODEL_FROM_DATABASE=Medion Flash XL V2.0 Card Reader + +usb:v0DB0p4023* + ID_MODEL_FROM_DATABASE=Lexar Mobile Card Reader + +usb:v0DB0p4600* + ID_MODEL_FROM_DATABASE=802.11b/g Turbo Wireless Adapter + +usb:v0DB0p5501* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0DB0p5502* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0DB0p5513* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0DB0p5515* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0DB0p5516* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0DB0p5580* + ID_MODEL_FROM_DATABASE=Mega Sky 580 DVB-T Tuner [M902x] + +usb:v0DB0p5581* + ID_MODEL_FROM_DATABASE=Mega Sky 580 DVB-T Tuner [GL861] + +usb:v0DB0p6823* + ID_MODEL_FROM_DATABASE=UB11B/MS-6823 802.11b Wi-Fi adapter + +usb:v0DB0p6826* + ID_MODEL_FROM_DATABASE=IEEE 802.11g Wireless Network Adapter + +usb:v0DB0p6855* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0DB0p6861* + ID_MODEL_FROM_DATABASE=MSI-6861 802.11g WiFi adapter + +usb:v0DB0p6865* + ID_MODEL_FROM_DATABASE=RT2570 + +usb:v0DB0p6869* + ID_MODEL_FROM_DATABASE=RT2570 + +usb:v0DB0p6874* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0DB0p6877* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0DB0p6881* + ID_MODEL_FROM_DATABASE=Bluetooth Class I EDR Device + +usb:v0DB0p688A* + ID_MODEL_FROM_DATABASE=Bluetooth Class I EDR Device + +usb:v0DB0p6899* + ID_MODEL_FROM_DATABASE=802.11bgn 1T1R Mini Card Wireless Adapter + +usb:v0DB0p6970* + ID_MODEL_FROM_DATABASE=MS-6970 BToes Bluetooth adapter + +usb:v0DB0p697A* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0DB0p6982* + ID_MODEL_FROM_DATABASE=Medion Flash XL Card Reader + +usb:v0DB0pA861* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0DB0pA874* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0DB0pA970* + ID_MODEL_FROM_DATABASE=Bluetooth dongle + +usb:v0DB0pA97A* + ID_MODEL_FROM_DATABASE=Bluetooth EDR Device + +usb:v0DB0pB970* + ID_MODEL_FROM_DATABASE=Bluetooth EDR Device + +usb:v0DB0pB97A* + ID_MODEL_FROM_DATABASE=Bluetooth EDR Device + +usb:v0DB1* + ID_VENDOR_FROM_DATABASE=Wen Te Electronics Co., Ltd + +usb:v0DB2* + ID_VENDOR_FROM_DATABASE=Shian Hwi Plug Parts, Plastic Factory + +usb:v0DB3* + ID_VENDOR_FROM_DATABASE=Tekram Technology Co., Ltd + +usb:v0DB4* + ID_VENDOR_FROM_DATABASE=Chung Fu Chen Yeh Enterprise Corp. + +usb:v0DB7* + ID_VENDOR_FROM_DATABASE=ELCON Systemtechnik + +usb:v0DB7p0002* + ID_MODEL_FROM_DATABASE=Goldpfeil P-LAN + +usb:v0DBC* + ID_VENDOR_FROM_DATABASE=A&D Medical + +usb:v0DBCp0003* + ID_MODEL_FROM_DATABASE=AND Serial Cable [AND Smart Cable] + +usb:v0DBE* + ID_VENDOR_FROM_DATABASE=Jiuh Shiuh Precision Industry Co., Ltd + +usb:v0DBF* + ID_VENDOR_FROM_DATABASE=Jess-Link International + +usb:v0DBFp0002* + ID_MODEL_FROM_DATABASE=SmartDongle Security Key + +usb:v0DBFp0200* + ID_MODEL_FROM_DATABASE=HDD Storage Solution + +usb:v0DBFp021B* + ID_MODEL_FROM_DATABASE=USB-2.0 IDE Adapter + +usb:v0DBFp0300* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v0DBFp0333* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v0DBFp0707* + ID_MODEL_FROM_DATABASE=ZIV Drive + +usb:v0DC0* + ID_VENDOR_FROM_DATABASE=G7 Solutions (formerly Great Notions) + +usb:v0DC1* + ID_VENDOR_FROM_DATABASE=Tamagawa Seiki Co., Ltd + +usb:v0DC3* + ID_VENDOR_FROM_DATABASE=Athena Smartcard Solutions, Inc. + +usb:v0DC3p0801* + ID_MODEL_FROM_DATABASE=ASEDrive III + +usb:v0DC3p0802* + ID_MODEL_FROM_DATABASE=ASEDrive IIIe + +usb:v0DC3p1104* + ID_MODEL_FROM_DATABASE=ASEDrive IIIe KB + +usb:v0DC3p1701* + ID_MODEL_FROM_DATABASE=ASEKey + +usb:v0DC3p1702* + ID_MODEL_FROM_DATABASE=ASEKey + +usb:v0DC4* + ID_VENDOR_FROM_DATABASE=Macpower Peripherals, Ltd + +usb:v0DC4p0040* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0DC4p0041* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0DC4p0042* + ID_MODEL_FROM_DATABASE=Mass Storage Device + +usb:v0DC4p0101* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v0DC4p020A* + ID_MODEL_FROM_DATABASE=Oyen Digital MiniPro 2.5" hard drive enclosure + +usb:v0DC5* + ID_VENDOR_FROM_DATABASE=SDK Co., Ltd + +usb:v0DC6* + ID_VENDOR_FROM_DATABASE=Precision Squared Technology Corp. + +usb:v0DC6p2301* + ID_MODEL_FROM_DATABASE=Wireless Touchpad Keyboard + +usb:v0DC7* + ID_VENDOR_FROM_DATABASE=First Cable Line, Inc. + +usb:v0DCD* + ID_VENDOR_FROM_DATABASE=NetworkFab Corp. + +usb:v0DCDp0001* + ID_MODEL_FROM_DATABASE=Remote Interface Adapter + +usb:v0DCDp0002* + ID_MODEL_FROM_DATABASE=High Bandwidth Codec + +usb:v0DD0* + ID_VENDOR_FROM_DATABASE=Access Solutions + +usb:v0DD0p1002* + ID_MODEL_FROM_DATABASE=Triple Talk Speech Synthesizer + +usb:v0DD1* + ID_VENDOR_FROM_DATABASE=Contek Electronics Co., Ltd + +usb:v0DD2* + ID_VENDOR_FROM_DATABASE=Power Quotient International Co., Ltd + +usb:v0DD2p0003* + ID_MODEL_FROM_DATABASE=Mass Storage (P) + +usb:v0DD3* + ID_VENDOR_FROM_DATABASE=MediaQ + +usb:v0DD4* + ID_VENDOR_FROM_DATABASE=Custom Engineering SPA + +usb:v0DD5* + ID_VENDOR_FROM_DATABASE=California Micro Devices + +usb:v0DD7* + ID_VENDOR_FROM_DATABASE=Kocom Co., Ltd + +usb:v0DD8* + ID_VENDOR_FROM_DATABASE=Netac Technology Co., Ltd + +usb:v0DD8p1060* + ID_MODEL_FROM_DATABASE=USB-CF-Card + +usb:v0DD8pE007* + ID_MODEL_FROM_DATABASE=OnlyDisk U222 Pendrive + +usb:v0DD8pF607* + ID_MODEL_FROM_DATABASE=OnlyDisk U208 1G flash drive [U-SAFE] + +usb:v0DD9* + ID_VENDOR_FROM_DATABASE=HighSpeed Surfing + +usb:v0DDA* + ID_VENDOR_FROM_DATABASE=Integrated Circuit Solution, Inc. + +usb:v0DDAp0001* + ID_MODEL_FROM_DATABASE=Multi-Card Reader 6in1 + +usb:v0DDAp0002* + ID_MODEL_FROM_DATABASE=Multi-Card Reader 7in1 + +usb:v0DDAp0003* + ID_MODEL_FROM_DATABASE=Flash Disk + +usb:v0DDAp0005* + ID_MODEL_FROM_DATABASE=Internal Multi-Card Reader 6in1 + +usb:v0DDAp0008* + ID_MODEL_FROM_DATABASE=SD single card reader + +usb:v0DDAp0009* + ID_MODEL_FROM_DATABASE=MS single card reader + +usb:v0DDAp000A* + ID_MODEL_FROM_DATABASE=MS+SD Dual Card Reader + +usb:v0DDAp000B* + ID_MODEL_FROM_DATABASE=SM single card reader + +usb:v0DDAp0101* + ID_MODEL_FROM_DATABASE=All-In-One Card Reader + +usb:v0DDAp0102* + ID_MODEL_FROM_DATABASE=All-In-One Card Reader + +usb:v0DDAp0301* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0DDAp0302* + ID_MODEL_FROM_DATABASE=Multi-Card MP3 Player + +usb:v0DDAp1001* + ID_MODEL_FROM_DATABASE=Multi-Flash Disk + +usb:v0DDAp2001* + ID_MODEL_FROM_DATABASE=Multi-Card Reader + +usb:v0DDAp2002* + ID_MODEL_FROM_DATABASE=Q018 default PID + +usb:v0DDAp2003* + ID_MODEL_FROM_DATABASE=Multi-Card Reader + +usb:v0DDAp2005* + ID_MODEL_FROM_DATABASE=Datalux DLX-1611 16in1 Card Reader + +usb:v0DDAp2006* + ID_MODEL_FROM_DATABASE=All-In-One Card Reader + +usb:v0DDAp2007* + ID_MODEL_FROM_DATABASE=USB to ATAPI bridge + +usb:v0DDAp2008* + ID_MODEL_FROM_DATABASE=All-In-One Card Reader + +usb:v0DDAp2013* + ID_MODEL_FROM_DATABASE=SD/MS Combo Card Reader + +usb:v0DDAp2014* + ID_MODEL_FROM_DATABASE=SD/MS Single Card Reader + +usb:v0DDAp2023* + ID_MODEL_FROM_DATABASE=card reader SD/MS DEMO board with ICSI brand name (MaskROM version) + +usb:v0DDAp2024* + ID_MODEL_FROM_DATABASE=card reader SD/MS DEMO board with Generic brand name (MaskROM version) + +usb:v0DDAp2026* + ID_MODEL_FROM_DATABASE=USB2.0 Card Reader + +usb:v0DDAp2027* + ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader + +usb:v0DDAp2315* + ID_MODEL_FROM_DATABASE=UFD MP3 player (model 2) + +usb:v0DDAp2318* + ID_MODEL_FROM_DATABASE=UFD MP3 player (model 1) + +usb:v0DDAp2321* + ID_MODEL_FROM_DATABASE=UFD MP3 player + +usb:v0DDB* + ID_VENDOR_FROM_DATABASE=Tamarack, Inc. + +usb:v0DDD* + ID_VENDOR_FROM_DATABASE=Datelink Technology Co., Ltd + +usb:v0DDE* + ID_VENDOR_FROM_DATABASE=Ubicom, Inc. + +usb:v0DE0* + ID_VENDOR_FROM_DATABASE=BD Consumer Healthcare + +usb:v0DE7* + ID_VENDOR_FROM_DATABASE=USBmicro + +usb:v0DE7p0191* + ID_MODEL_FROM_DATABASE=U401 Interface card + +usb:v0DE7p01A5* + ID_MODEL_FROM_DATABASE=U421 interface card + +usb:v0DE7p01C3* + ID_MODEL_FROM_DATABASE=U451 relay interface card + +usb:v0DEA* + ID_VENDOR_FROM_DATABASE=UTECH Electronic (D.G.) Co., Ltd. + +usb:v0DED* + ID_VENDOR_FROM_DATABASE=Novasonics + +usb:v0DEE* + ID_VENDOR_FROM_DATABASE=Lifetime Memory Products + +usb:v0DEEp4010* + ID_MODEL_FROM_DATABASE=Storage Adapter + +usb:v0DEF* + ID_VENDOR_FROM_DATABASE=Full Rise Electronic Co., Ltd + +usb:v0DF4* + ID_VENDOR_FROM_DATABASE=NET&SYS + +usb:v0DF4p0201* + ID_MODEL_FROM_DATABASE=MNG-2005 + +usb:v0DF6* + ID_VENDOR_FROM_DATABASE=Sitecom Europe B.V. + +usb:v0DF6p0001* + ID_MODEL_FROM_DATABASE=C-Media VOIP Device + +usb:v0DF6p0004* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 Adapter 100m + +usb:v0DF6p0007* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 Adapter 10m + +usb:v0DF6p000B* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 Adapter DFU + +usb:v0DF6p000D* + ID_MODEL_FROM_DATABASE=WL-168 Wireless Network Adapter 54g + +usb:v0DF6p0017* + ID_MODEL_FROM_DATABASE=WL-182 Wireless-N Network USB Card + +usb:v0DF6p0019* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 adapter 10m CN-512v2 001 + +usb:v0DF6p001A* + ID_MODEL_FROM_DATABASE=Bluetooth 2.0 adapter 100m CN-521v2 001 + +usb:v0DF6p002B* + ID_MODEL_FROM_DATABASE=WL-188 Wireless Network 300N USB Adapter + +usb:v0DF6p002C* + ID_MODEL_FROM_DATABASE=WL-301 Wireless Network 300N USB Adapter + +usb:v0DF6p002D* + ID_MODEL_FROM_DATABASE=WL-302 Wireless Network 300N USB dongle + +usb:v0DF6p0036* + ID_MODEL_FROM_DATABASE=WL-603 Wireless Adapter + +usb:v0DF6p0039* + ID_MODEL_FROM_DATABASE=WL-315 Wireless-N USB Adapter + +usb:v0DF6p003B* + ID_MODEL_FROM_DATABASE=WL-321 Wireless USB Gaming Adapter 300N + +usb:v0DF6p003C* + ID_MODEL_FROM_DATABASE=WL-323 Wireless-N USB Adapter + +usb:v0DF6p003D* + ID_MODEL_FROM_DATABASE=WL-324 Wireless USB Adapter 300N + +usb:v0DF6p003E* + ID_MODEL_FROM_DATABASE=WL-343 Wireless USB Adapter 150N X1 + +usb:v0DF6p003F* + ID_MODEL_FROM_DATABASE=WL-608 Wireless USB Adapter 54g + +usb:v0DF6p0040* + ID_MODEL_FROM_DATABASE=WL-344 Wireless Adapter 300N X2 [Ralink RT3071] + +usb:v0DF6p0041* + ID_MODEL_FROM_DATABASE=WL-329 Wireless Dualband USB adapter 300N + +usb:v0DF6p0042* + ID_MODEL_FROM_DATABASE=WL-345 Wireless USB adapter 300N X3 + +usb:v0DF6p0045* + ID_MODEL_FROM_DATABASE=WL-353 Wireless USB Adapter 150N Nano + +usb:v0DF6p0047* + ID_MODEL_FROM_DATABASE=WL-352v1 Wireless USB Adapter 300N 002 + +usb:v0DF6p0048* + ID_MODEL_FROM_DATABASE=WL-349v1 Wireless Adapter 150N 002 [Ralink RT3070] + +usb:v0DF6p0049* + ID_MODEL_FROM_DATABASE=WL-356 Wireless Adapter 300N + +usb:v0DF6p004A* + ID_MODEL_FROM_DATABASE=WL-358v1 Wireless Micro USB Adapter 300N X3 002 + +usb:v0DF6p004B* + ID_MODEL_FROM_DATABASE=WL-349v3 Wireless Micro Adapter 150N X1 [Realtek RTL8192SU] + +usb:v0DF6p004C* + ID_MODEL_FROM_DATABASE=WL-352 802.11n Adapter [Realtek RTL8191SU] + +usb:v0DF6p0050* + ID_MODEL_FROM_DATABASE=WL-349v4 Wireless Micro Adapter 150N X1 [Ralink RT3370] + +usb:v0DF6p0056* + ID_MODEL_FROM_DATABASE=LN-031 10/100/1000 Ethernet Adapter + +usb:v0DF6p005D* + ID_MODEL_FROM_DATABASE=WLA-2000 v1.001 WLAN [RTL8191SU] + +usb:v0DF6p0060* + ID_MODEL_FROM_DATABASE=WLA-4000 802.11bgn [Ralink RT3072] + +usb:v0DF6p0062* + ID_MODEL_FROM_DATABASE=WLA-5000 802.11abgn [Ralink RT3572] + +usb:v0DF6p061C* + ID_MODEL_FROM_DATABASE=LN-028 Network USB 2.0 Adapter + +usb:v0DF6p21F4* + ID_MODEL_FROM_DATABASE=44 St Bluetooth Device + +usb:v0DF6p2200* + ID_MODEL_FROM_DATABASE=Sitecom bluetooth2.0 class 2 dongle CN-512 + +usb:v0DF6p2208* + ID_MODEL_FROM_DATABASE=Sitecom bluetooth2.0 class 2 dongle CN-520 + +usb:v0DF6p2209* + ID_MODEL_FROM_DATABASE=Sitecom bluetooth2.0 class 1 dongle CN-521 + +usb:v0DF6p9071* + ID_MODEL_FROM_DATABASE=WL-113 rev 1 Wireless Network USB Adapter + +usb:v0DF6p9075* + ID_MODEL_FROM_DATABASE=WL-117 Hi-Speed USB Adapter + +usb:v0DF6p90AC* + ID_MODEL_FROM_DATABASE=WL-172 Wireless Network USB Adapter 54g Turbo + +usb:v0DF6p9712* + ID_MODEL_FROM_DATABASE=WL-113 rev 2 Wireless Network USB Adapter + +usb:v0DF7* + ID_VENDOR_FROM_DATABASE=Mobile Action Technology, Inc. + +usb:v0DF7p0620* + ID_MODEL_FROM_DATABASE=MA-620 Infrared Adapter + +usb:v0DF7p0700* + ID_MODEL_FROM_DATABASE=MA-700 Bluetooth Adapter + +usb:v0DF7p0720* + ID_MODEL_FROM_DATABASE=MA-720 Bluetooth Adapter + +usb:v0DF7p0722* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0DF7p0730* + ID_MODEL_FROM_DATABASE=MA-730/MA-730G Bluetooth Adapter + +usb:v0DF7p0800* + ID_MODEL_FROM_DATABASE=Data Cable + +usb:v0DF7p0820* + ID_MODEL_FROM_DATABASE=Data Cable + +usb:v0DF7p0900* + ID_MODEL_FROM_DATABASE=MA i-gotU Travel Logger GPS + +usb:v0DF7p1800* + ID_MODEL_FROM_DATABASE=Generic Card Reader + +usb:v0DF7p1802* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v0DFA* + ID_VENDOR_FROM_DATABASE=Toyo Communication Equipment Co., Ltd + +usb:v0DFC* + ID_VENDOR_FROM_DATABASE=GeneralTouch Technology Co., Ltd + +usb:v0DFCp0001* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v0E03* + ID_VENDOR_FROM_DATABASE=Nippon Systemware Co., Ltd + +usb:v0E08* + ID_VENDOR_FROM_DATABASE=Winbest Technology Co., Ltd + +usb:v0E0B* + ID_VENDOR_FROM_DATABASE=Amigo Technology Inc. + +usb:v0E0Bp9031* + ID_MODEL_FROM_DATABASE=802.11n Wireless USB Card + +usb:v0E0Bp9041* + ID_MODEL_FROM_DATABASE=802.11n Wireless USB Card + +usb:v0E0C* + ID_VENDOR_FROM_DATABASE=Gesytec + +usb:v0E0Cp0101* + ID_MODEL_FROM_DATABASE=LonUSB LonTalk Network Adapter + +usb:v0E0F* + ID_VENDOR_FROM_DATABASE=VMware, Inc. + +usb:v0E0Fp0001* + ID_MODEL_FROM_DATABASE=Device + +usb:v0E0Fp0002* + ID_MODEL_FROM_DATABASE=Virtual USB Hub + +usb:v0E0Fp0003* + ID_MODEL_FROM_DATABASE=Virtual Mouse + +usb:v0E0Fp0004* + ID_MODEL_FROM_DATABASE=Virtual CCID + +usb:v0E0Fp0005* + ID_MODEL_FROM_DATABASE=Virtual Mass Storage + +usb:v0E0Fp0006* + ID_MODEL_FROM_DATABASE=Virtual Keyboard + +usb:v0E0FpF80A* + ID_MODEL_FROM_DATABASE=Smoker FX2 + +usb:v0E16* + ID_VENDOR_FROM_DATABASE=JMTek, LLC + +usb:v0E17* + ID_VENDOR_FROM_DATABASE=Walex Electronic, Ltd + +usb:v0E1A* + ID_VENDOR_FROM_DATABASE=Unisys + +usb:v0E1B* + ID_VENDOR_FROM_DATABASE=Crewave + +usb:v0E20* + ID_VENDOR_FROM_DATABASE=Pegasus Technologies Ltd. + +usb:v0E20p0101* + ID_MODEL_FROM_DATABASE=NoteTaker + +usb:v0E21* + ID_VENDOR_FROM_DATABASE=Cowon Systems, Inc. + +usb:v0E21p0300* + ID_MODEL_FROM_DATABASE=iAudio CW200 + +usb:v0E21p0400* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0E21p0500* + ID_MODEL_FROM_DATABASE=iAudio M3 + +usb:v0E21p0510* + ID_MODEL_FROM_DATABASE=iAudio X5, subpack USB port + +usb:v0E21p0513* + ID_MODEL_FROM_DATABASE=iAudio X5, side USB port + +usb:v0E21p0520* + ID_MODEL_FROM_DATABASE=iAudio M5, side USB port + +usb:v0E21p0601* + ID_MODEL_FROM_DATABASE=iAudio G3 + +usb:v0E21p0681* + ID_MODEL_FROM_DATABASE=iAUDIO E2 + +usb:v0E21p0700* + ID_MODEL_FROM_DATABASE=iAudio U3 + +usb:v0E21p0751* + ID_MODEL_FROM_DATABASE=iAudio 7 + +usb:v0E21p0760* + ID_MODEL_FROM_DATABASE=iAUDIO U5 / iAUDIO G2 + +usb:v0E21p0800* + ID_MODEL_FROM_DATABASE=Cowon D2 (UMS mode) + +usb:v0E21p0801* + ID_MODEL_FROM_DATABASE=Cowon D2 (MTP mode) + +usb:v0E21p0910* + ID_MODEL_FROM_DATABASE=iAUDIO 9 + +usb:v0E21p0920* + ID_MODEL_FROM_DATABASE=J3 + +usb:v0E22* + ID_VENDOR_FROM_DATABASE=Symbian Ltd. + +usb:v0E23* + ID_VENDOR_FROM_DATABASE=Liou Yuane Enterprise Co., Ltd + +usb:v0E25* + ID_VENDOR_FROM_DATABASE=VinChip Systems, Inc. + +usb:v0E26* + ID_VENDOR_FROM_DATABASE=J-Phone East Co., Ltd + +usb:v0E30* + ID_VENDOR_FROM_DATABASE=HeartMath LLC + +usb:v0E34* + ID_VENDOR_FROM_DATABASE=Micro Computer Control Corp. + +usb:v0E35* + ID_VENDOR_FROM_DATABASE=3Pea Technologies, Inc. + +usb:v0E36* + ID_VENDOR_FROM_DATABASE=TiePie engineering + +usb:v0E36p0008* + ID_MODEL_FROM_DATABASE=Handyscope HS3 + +usb:v0E36p0009* + ID_MODEL_FROM_DATABASE=Handyscope HS3 (br) + +usb:v0E36p000A* + ID_MODEL_FROM_DATABASE=Handyscope HS4 + +usb:v0E36p000B* + ID_MODEL_FROM_DATABASE=Handyscope HS4 (br) + +usb:v0E36p000E* + ID_MODEL_FROM_DATABASE=Handyscope HS4-DIFF + +usb:v0E36p000F* + ID_MODEL_FROM_DATABASE=Handyscope HS4-DIFF (br) + +usb:v0E36p0010* + ID_MODEL_FROM_DATABASE=Handyscope HS2 + +usb:v0E36p0011* + ID_MODEL_FROM_DATABASE=TiePieSCOPE HS805 (br) + +usb:v0E36p0012* + ID_MODEL_FROM_DATABASE=TiePieSCOPE HS805 + +usb:v0E36p0013* + ID_MODEL_FROM_DATABASE=Handyprobe HP3 + +usb:v0E36p0014* + ID_MODEL_FROM_DATABASE=Handyprobe HP3 + +usb:v0E36p0018* + ID_MODEL_FROM_DATABASE=Handyprobe HP2 + +usb:v0E36p001B* + ID_MODEL_FROM_DATABASE=Handyscope HS5 + +usb:v0E36p0042* + ID_MODEL_FROM_DATABASE=TiePieSCOPE HS801 + +usb:v0E36p00FD* + ID_MODEL_FROM_DATABASE=USB To Parallel adapter + +usb:v0E36p00FE* + ID_MODEL_FROM_DATABASE=USB To Parallel adapter + +usb:v0E38* + ID_VENDOR_FROM_DATABASE=Stratitec, Inc. + +usb:v0E39* + ID_VENDOR_FROM_DATABASE=Smart Modular Technologies, Inc. + +usb:v0E39p0137* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v0E3A* + ID_VENDOR_FROM_DATABASE=Neostar Technology Co., Ltd + +usb:v0E3Ap1100* + ID_MODEL_FROM_DATABASE=CW-1100 Wireless Network Adapter + +usb:v0E3B* + ID_VENDOR_FROM_DATABASE=Mansella, Ltd + +usb:v0E41* + ID_VENDOR_FROM_DATABASE=Line6, Inc. + +usb:v0E41p4147* + ID_MODEL_FROM_DATABASE=TonePort GX + +usb:v0E41p414D* + ID_MODEL_FROM_DATABASE=Pod HD500 + +usb:v0E41p4156* + ID_MODEL_FROM_DATABASE=POD HD Desktop + +usb:v0E41p4250* + ID_MODEL_FROM_DATABASE=BassPODxt + +usb:v0E41p4252* + ID_MODEL_FROM_DATABASE=BassPODxt Pro + +usb:v0E41p4642* + ID_MODEL_FROM_DATABASE=BassPODxt Live + +usb:v0E41p4650* + ID_MODEL_FROM_DATABASE=PODxt Live + +usb:v0E41p4750* + ID_MODEL_FROM_DATABASE=GuitarPort + +usb:v0E41p5044* + ID_MODEL_FROM_DATABASE=PODxt + +usb:v0E41p5050* + ID_MODEL_FROM_DATABASE=PODxt Pro + +usb:v0E41p534D* + ID_MODEL_FROM_DATABASE=SeaMonkey + +usb:v0E44* + ID_VENDOR_FROM_DATABASE=Sun-Riseful Technology Co., Ltd. + +usb:v0E48* + ID_VENDOR_FROM_DATABASE=Julia Corp., Ltd + +usb:v0E48p0100* + ID_MODEL_FROM_DATABASE=CardPro SmartCard Reader + +usb:v0E4A* + ID_VENDOR_FROM_DATABASE=Shenzhen Bao Hing Electric Wire & Cable Mfr. Co. + +usb:v0E4C* + ID_VENDOR_FROM_DATABASE=Radica Games, Ltd + +usb:v0E4Cp1097* + ID_MODEL_FROM_DATABASE=Gamester Controller + +usb:v0E4Cp2390* + ID_MODEL_FROM_DATABASE=Games Jtech Controller + +usb:v0E4Cp7288* + ID_MODEL_FROM_DATABASE=funkey reader + +usb:v0E50* + ID_VENDOR_FROM_DATABASE=TechnoData Interware + +usb:v0E50p0002* + ID_MODEL_FROM_DATABASE=Matrixlock Dongle (HID) + +usb:v0E55* + ID_VENDOR_FROM_DATABASE=Speed Dragon Multimedia, Ltd + +usb:v0E55p110A* + ID_MODEL_FROM_DATABASE=Tanic S110-SG1 + ISSC IS1002N [Slow Infra-Red (SIR) & Bluetooth 1.2 (Class 2) Adapter] + +usb:v0E55p110B* + ID_MODEL_FROM_DATABASE=MS3303H USB-to-Serial Bridge + +usb:v0E56* + ID_VENDOR_FROM_DATABASE=Kingston Technology Company, Inc. + +usb:v0E56p6021* + ID_MODEL_FROM_DATABASE=K-PEX 100 + +usb:v0E5A* + ID_VENDOR_FROM_DATABASE=Active Co., Ltd + +usb:v0E5B* + ID_VENDOR_FROM_DATABASE=Union Power Information Industrial Co., Ltd + +usb:v0E5C* + ID_VENDOR_FROM_DATABASE=Bitland Information Technology Co., Ltd + +usb:v0E5Cp6118* + ID_MODEL_FROM_DATABASE=LCD Device + +usb:v0E5Cp6119* + ID_MODEL_FROM_DATABASE=remote receive and control device + +usb:v0E5Cp6441* + ID_MODEL_FROM_DATABASE=C-Media Sound Device + +usb:v0E5D* + ID_VENDOR_FROM_DATABASE=Neltron Industrial Co., Ltd + +usb:v0E5E* + ID_VENDOR_FROM_DATABASE=Conwise Technology Co., Ltd. + +usb:v0E5Ep6622* + ID_MODEL_FROM_DATABASE=CW6622 + +usb:v0E66* + ID_VENDOR_FROM_DATABASE=Hawking Technologies + +usb:v0E66p0001* + ID_MODEL_FROM_DATABASE=HWUN1 Hi-Gain Wireless-300N Adapter w/ Upgradable Antenna [Ralink RT2870] + +usb:v0E66p0003* + ID_MODEL_FROM_DATABASE=HWDN1 Hi-Gain Wireless-300N Dish Adapter [Ralink RT2870] + +usb:v0E66p0009* + ID_MODEL_FROM_DATABASE=HWUN2 Hi-Gain Wireless-150N Adapter w/ Upgradable Antenna [Ralink RT2770] + +usb:v0E66p000B* + ID_MODEL_FROM_DATABASE=HWDN2 Hi-Gain Wireless-150N Dish Adapter [Ralink RT2770] + +usb:v0E66p0013* + ID_MODEL_FROM_DATABASE=HWUN3 Hi-Gain Wireless-N Adapter [Ralink RT3070] + +usb:v0E66p0015* + ID_MODEL_FROM_DATABASE=HWDN2 Rev. E Hi-Gain Wireless-150N Dish Adapter [Realtek RTL8191SU] + +usb:v0E66p0017* + ID_MODEL_FROM_DATABASE=HAWNU1 Hi-Gain Wireless-150N Network Adapter with Range Amplifier [Ralink RT3070] + +usb:v0E66p0018* + ID_MODEL_FROM_DATABASE=Wireless-N Network Adapter [Ralink RT2870] + +usb:v0E66p400B* + ID_MODEL_FROM_DATABASE=UF100 10/100 Network Adapter + +usb:v0E66p400C* + ID_MODEL_FROM_DATABASE=UF100 Ethernet [pegasus2] + +usb:v0E67* + ID_VENDOR_FROM_DATABASE=Fossil, Inc. + +usb:v0E67p0002* + ID_MODEL_FROM_DATABASE=Wrist PDA + +usb:v0E6A* + ID_VENDOR_FROM_DATABASE=Megawin Technology Co., Ltd + +usb:v0E6Ap0101* + ID_MODEL_FROM_DATABASE=MA100 [USB-UART Bridge IC] + +usb:v0E6Ap6001* + ID_MODEL_FROM_DATABASE=GEMBIRD Flexible keyboard KB-109F-B-DE + +usb:v0E6F* + ID_VENDOR_FROM_DATABASE=Logic3 + +usb:v0E6Fp0003* + ID_MODEL_FROM_DATABASE=Freebird wireless Controller + +usb:v0E6Fp0005* + ID_MODEL_FROM_DATABASE=Eclipse wireless Controller + +usb:v0E6Fp0006* + ID_MODEL_FROM_DATABASE=Edge wireless Controller + +usb:v0E70* + ID_VENDOR_FROM_DATABASE=Tokyo Electronic Industry Co., Ltd + +usb:v0E72* + ID_VENDOR_FROM_DATABASE=Hsi-Chin Electronics Co., Ltd + +usb:v0E75* + ID_VENDOR_FROM_DATABASE=TVS Electronics, Ltd + +usb:v0E79* + ID_VENDOR_FROM_DATABASE=Archos, Inc. + +usb:v0E79p1106* + ID_MODEL_FROM_DATABASE=Pocket Media Assistant - PMA400 + +usb:v0E79p1204* + ID_MODEL_FROM_DATABASE=Gmini XS 200 + +usb:v0E79p1306* + ID_MODEL_FROM_DATABASE=504 Portable Multimedia Player + +usb:v0E79p1330* + ID_MODEL_FROM_DATABASE=5 Tablet + +usb:v0E79p1332* + ID_MODEL_FROM_DATABASE=5 IMT + +usb:v0E79p1416* + ID_MODEL_FROM_DATABASE=32 IT + +usb:v0E79p1417* + ID_MODEL_FROM_DATABASE=A43 IT + +usb:v0E79p14AD* + ID_MODEL_FROM_DATABASE=97 Titanium HD + +usb:v0E79p150E* + ID_MODEL_FROM_DATABASE=80 G9 + +usb:v0E7B* + ID_VENDOR_FROM_DATABASE=On-Tech Industry Co., Ltd + +usb:v0E7E* + ID_VENDOR_FROM_DATABASE=Gmate, Inc. + +usb:v0E7Ep0001* + ID_MODEL_FROM_DATABASE=Yopy 3000 PDA + +usb:v0E7Ep1001* + ID_MODEL_FROM_DATABASE=YP3X00 PDA + +usb:v0E82* + ID_VENDOR_FROM_DATABASE=Ching Tai Electric Wire & Cable Co., Ltd + +usb:v0E83* + ID_VENDOR_FROM_DATABASE=Shin An Wire & Cable Co. + +usb:v0E8C* + ID_VENDOR_FROM_DATABASE=Well Force Electronic Co., Ltd + +usb:v0E8D* + ID_VENDOR_FROM_DATABASE=MediaTek Inc. + +usb:v0E8Dp0003* + ID_MODEL_FROM_DATABASE=MT6227 phone + +usb:v0E8Dp0004* + ID_MODEL_FROM_DATABASE=MT6227 phone + +usb:v0E8Dp0023* + ID_MODEL_FROM_DATABASE=S103 + +usb:v0E8Dp1806* + ID_MODEL_FROM_DATABASE=Samsung SE-208AB Slim Portable DVD Writer + +usb:v0E8Dp1836* + ID_MODEL_FROM_DATABASE=Samsung SE-S084 Super WriteMaster Slim External DVD writer + +usb:v0E8Dp3329* + ID_MODEL_FROM_DATABASE=Qstarz BT-Q1000XT + +usb:v0E8F* + ID_VENDOR_FROM_DATABASE=GreenAsia Inc. + +usb:v0E8Fp0003* + ID_MODEL_FROM_DATABASE=MaxFire Blaze2 + +usb:v0E8Fp0012* + ID_MODEL_FROM_DATABASE=USB Wireless 2.4GHz Gamepad + +usb:v0E8Fp0016* + ID_MODEL_FROM_DATABASE=4 port USB 1.1 hub UH-174 + +usb:v0E8Fp0020* + ID_MODEL_FROM_DATABASE=USB to PS/2 Adapter + +usb:v0E8Fp0021* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard Controller + +usb:v0E8Fp0201* + ID_MODEL_FROM_DATABASE=SmartJoy Frag Xpad/PS2 adaptor + +usb:v0E90* + ID_VENDOR_FROM_DATABASE=WiebeTech, LLC + +usb:v0E90p0100* + ID_MODEL_FROM_DATABASE=Storage Adapter V1 + +usb:v0E91* + ID_VENDOR_FROM_DATABASE=VTech Engineering Canada, Ltd + +usb:v0E92* + ID_VENDOR_FROM_DATABASE=C's Glory Enterprise Co., Ltd + +usb:v0E93* + ID_VENDOR_FROM_DATABASE=eM Technics Co., Ltd + +usb:v0E95* + ID_VENDOR_FROM_DATABASE=Future Technology Co., Ltd + +usb:v0E96* + ID_VENDOR_FROM_DATABASE=Aplux Communications, Ltd + +usb:v0E96pC001* + ID_MODEL_FROM_DATABASE=TRUST 380 USB2 SPACEC@M + +usb:v0E97* + ID_VENDOR_FROM_DATABASE=Fingerworks, Inc. + +usb:v0E97p0908* + ID_MODEL_FROM_DATABASE=Composite HID (Keyboard and Mouse) + +usb:v0E98* + ID_VENDOR_FROM_DATABASE=Advanced Analogic Technologies, Inc. + +usb:v0E99* + ID_VENDOR_FROM_DATABASE=Parallel Dice Co., Ltd + +usb:v0E9A* + ID_VENDOR_FROM_DATABASE=TA HSING Industries, Ltd + +usb:v0E9B* + ID_VENDOR_FROM_DATABASE=ADTEC Corp. + +usb:v0E9C* + ID_VENDOR_FROM_DATABASE=Streamzap, Inc. + +usb:v0E9Cp0000* + ID_MODEL_FROM_DATABASE=Streamzap Remote Control + +usb:v0E9F* + ID_VENDOR_FROM_DATABASE=Tamura Corp. + +usb:v0EA0* + ID_VENDOR_FROM_DATABASE=Ours Technology, Inc. + +usb:v0EA0p2126* + ID_MODEL_FROM_DATABASE=7-in-1 Card Reader + +usb:v0EA0p2153* + ID_MODEL_FROM_DATABASE=SD Card Reader Key + +usb:v0EA0p2168* + ID_MODEL_FROM_DATABASE=Transcend JetFlash 2.0 / Astone USB Drive + +usb:v0EA0p6803* + ID_MODEL_FROM_DATABASE=OTI-6803 Flash Disk + +usb:v0EA0p6808* + ID_MODEL_FROM_DATABASE=OTI-6808 Flash Disk + +usb:v0EA0p6828* + ID_MODEL_FROM_DATABASE=OTI-6828 Flash Disk + +usb:v0EA0p6858* + ID_MODEL_FROM_DATABASE=OTi-6858 serial adapter + +usb:v0EA6* + ID_VENDOR_FROM_DATABASE=Nihon Computer Co., Ltd + +usb:v0EA7* + ID_VENDOR_FROM_DATABASE=MSL Enterprises Corp. + +usb:v0EA8* + ID_VENDOR_FROM_DATABASE=CenDyne, Inc. + +usb:v0EAD* + ID_VENDOR_FROM_DATABASE=Humax Co., Ltd + +usb:v0EB0* + ID_VENDOR_FROM_DATABASE=NovaTech + +usb:v0EB0p9020* + ID_MODEL_FROM_DATABASE=NovaTech NV-902W + +usb:v0EB0p9021* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v0EB1* + ID_VENDOR_FROM_DATABASE=WIS Technologies, Inc. + +usb:v0EB1p6666* + ID_MODEL_FROM_DATABASE=WinFast WalkieTV TV Loader + +usb:v0EB1p6668* + ID_MODEL_FROM_DATABASE=WinFast WalkieTV TV Loader + +usb:v0EB1p7007* + ID_MODEL_FROM_DATABASE=WinFast WalkieTV WDM Capture + +usb:v0EB2* + ID_VENDOR_FROM_DATABASE=Y-S Electronic Co., Ltd + +usb:v0EB3* + ID_VENDOR_FROM_DATABASE=Saint Technology Corp. + +usb:v0EB7* + ID_VENDOR_FROM_DATABASE=Endor AG + +usb:v0EB8* + ID_VENDOR_FROM_DATABASE=Mettler Toledo + +usb:v0EB8pF000* + ID_MODEL_FROM_DATABASE=PS60 Scale + +usb:v0EBE* + ID_VENDOR_FROM_DATABASE=VWeb Corp. + +usb:v0EBF* + ID_VENDOR_FROM_DATABASE=Omega Technology of Taiwan, Inc. + +usb:v0EC0* + ID_VENDOR_FROM_DATABASE=LHI Technology (China) Co., Ltd + +usb:v0EC1* + ID_VENDOR_FROM_DATABASE=Abit Computer Corp. + +usb:v0EC2* + ID_VENDOR_FROM_DATABASE=Sweetray Industrial, Ltd + +usb:v0EC3* + ID_VENDOR_FROM_DATABASE=Axell Co., Ltd + +usb:v0EC4* + ID_VENDOR_FROM_DATABASE=Ballracing Developments, Ltd + +usb:v0EC5* + ID_VENDOR_FROM_DATABASE=GT Information System Co., Ltd + +usb:v0EC6* + ID_VENDOR_FROM_DATABASE=InnoVISION Multimedia, Ltd + +usb:v0EC7* + ID_VENDOR_FROM_DATABASE=Theta Link Corp. + +usb:v0EC7p1008* + ID_MODEL_FROM_DATABASE=So., Show 301 Digital Camera + +usb:v0ECD* + ID_VENDOR_FROM_DATABASE=Lite-On IT Corp. + +usb:v0ECDp1400* + ID_MODEL_FROM_DATABASE=CD\RW 40X + +usb:v0ECDpA100* + ID_MODEL_FROM_DATABASE=LDW-411SX DVD/CD Rewritable Drive + +usb:v0ECE* + ID_VENDOR_FROM_DATABASE=TaiSol Electronics Co., Ltd + +usb:v0ECF* + ID_VENDOR_FROM_DATABASE=Phogenix Imaging, LLC + +usb:v0ED1* + ID_VENDOR_FROM_DATABASE=WinMaxGroup + +usb:v0ED1p6660* + ID_MODEL_FROM_DATABASE=Flash Disk 64M-C + +usb:v0ED1p6680* + ID_MODEL_FROM_DATABASE=Flash Disk 64M-B + +usb:v0ED1p7634* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v0ED2* + ID_VENDOR_FROM_DATABASE=Kyoto Micro Computer Co., Ltd + +usb:v0ED3* + ID_VENDOR_FROM_DATABASE=Wing-Tech Enterprise Co., Ltd + +usb:v0ED5* + ID_VENDOR_FROM_DATABASE=Fiberbyte + +usb:v0ED5pE000* + ID_MODEL_FROM_DATABASE=USB-inSync Device + +usb:v0ED5pF000* + ID_MODEL_FROM_DATABASE=Fiberbyte USB-inSync Device + +usb:v0ED5pF201* + ID_MODEL_FROM_DATABASE=Fiberbyte USB-inSync DAQ-2500X + +usb:v0EDA* + ID_VENDOR_FROM_DATABASE=Noriake Itron Corp. + +usb:v0EDF* + ID_VENDOR_FROM_DATABASE=e-MDT Co., Ltd + +usb:v0EDFp2060* + ID_MODEL_FROM_DATABASE=FID irock! 100 Series + +usb:v0EE0* + ID_VENDOR_FROM_DATABASE=Shima Seiki Mfg., Ltd + +usb:v0EE1* + ID_VENDOR_FROM_DATABASE=Sarotech Co., Ltd + +usb:v0EE2* + ID_VENDOR_FROM_DATABASE=AMI Semiconductor, Inc. + +usb:v0EE3* + ID_VENDOR_FROM_DATABASE=ComTrue Technology Corp. + +usb:v0EE3p1000* + ID_MODEL_FROM_DATABASE=Image Tank 1.5 + +usb:v0EE4* + ID_VENDOR_FROM_DATABASE=Sunrich Technology, Ltd + +usb:v0EEE* + ID_VENDOR_FROM_DATABASE=Digital Stream Technology, Inc. + +usb:v0EEEp8810* + ID_MODEL_FROM_DATABASE=Mass Storage Drive + +usb:v0EEF* + ID_VENDOR_FROM_DATABASE=D-WAV Scientific Co., Ltd + +usb:v0EEFp0001* + ID_MODEL_FROM_DATABASE=eGalax TouchScreen + +usb:v0EEFp0002* + ID_MODEL_FROM_DATABASE=Touchscreen Controller(Professional) + +usb:v0EF0* + ID_VENDOR_FROM_DATABASE=Hitachi Cable, Ltd + +usb:v0EF1* + ID_VENDOR_FROM_DATABASE=Aichi Micro Intelligent Corp. + +usb:v0EF2* + ID_VENDOR_FROM_DATABASE=I/O Magic Corp. + +usb:v0EF3* + ID_VENDOR_FROM_DATABASE=Lynn Products, Inc. + +usb:v0EF4* + ID_VENDOR_FROM_DATABASE=DSI Datotech + +usb:v0EF5* + ID_VENDOR_FROM_DATABASE=PointChips + +usb:v0EF5p2202* + ID_MODEL_FROM_DATABASE=Flash Disk + +usb:v0EF5p2366* + ID_MODEL_FROM_DATABASE=Flash Disk + +usb:v0EF6* + ID_VENDOR_FROM_DATABASE=Yield Microelectronics Corp. + +usb:v0EF7* + ID_VENDOR_FROM_DATABASE=SM Tech Co., Ltd (Tulip) + +usb:v0EFD* + ID_VENDOR_FROM_DATABASE=Oasis Semiconductor + +usb:v0EFE* + ID_VENDOR_FROM_DATABASE=Wem Technology, Inc. + +usb:v0F03* + ID_VENDOR_FROM_DATABASE=Unitek UPS Systems + +usb:v0F03p0001* + ID_MODEL_FROM_DATABASE=Alpha 1200Sx + +usb:v0F06* + ID_VENDOR_FROM_DATABASE=Visual Frontier Enterprise Co., Ltd + +usb:v0F08* + ID_VENDOR_FROM_DATABASE=CSL Wire & Plug (Shen Zhen) Co. + +usb:v0F0C* + ID_VENDOR_FROM_DATABASE=CAS Corp. + +usb:v0F0D* + ID_VENDOR_FROM_DATABASE=Hori Co., Ltd + +usb:v0F0Dp0011* + ID_MODEL_FROM_DATABASE=Real Arcade Pro 3 + +usb:v0F0E* + ID_VENDOR_FROM_DATABASE=Energy Full Corp. + +usb:v0F11* + ID_VENDOR_FROM_DATABASE=LD Didactic GmbH + +usb:v0F11p1000* + ID_MODEL_FROM_DATABASE=CASSY-S + +usb:v0F11p1010* + ID_MODEL_FROM_DATABASE=Pocket-CASSY + +usb:v0F11p1020* + ID_MODEL_FROM_DATABASE=Mobile-CASSY + +usb:v0F11p1080* + ID_MODEL_FROM_DATABASE=Joule and Wattmeter + +usb:v0F11p1081* + ID_MODEL_FROM_DATABASE=Digital Multimeter P + +usb:v0F11p1090* + ID_MODEL_FROM_DATABASE=UMI P + +usb:v0F11p1100* + ID_MODEL_FROM_DATABASE=X-Ray Apparatus + +usb:v0F11p1101* + ID_MODEL_FROM_DATABASE=X-Ray Apparatus + +usb:v0F11p1200* + ID_MODEL_FROM_DATABASE=VideoCom + +usb:v0F11p2000* + ID_MODEL_FROM_DATABASE=COM3LAB + +usb:v0F11p2010* + ID_MODEL_FROM_DATABASE=Terminal Adapter + +usb:v0F11p2020* + ID_MODEL_FROM_DATABASE=Network Analyser + +usb:v0F11p2030* + ID_MODEL_FROM_DATABASE=Converter Control Unit + +usb:v0F11p2040* + ID_MODEL_FROM_DATABASE=Machine Test System + +usb:v0F12* + ID_VENDOR_FROM_DATABASE=Mars Engineering Corp. + +usb:v0F13* + ID_VENDOR_FROM_DATABASE=Acetek Technology Co., Ltd + +usb:v0F18* + ID_VENDOR_FROM_DATABASE=Finger Lakes Instrumentation + +usb:v0F18p0002* + ID_MODEL_FROM_DATABASE=CCD + +usb:v0F18p0006* + ID_MODEL_FROM_DATABASE=Focuser + +usb:v0F18p0007* + ID_MODEL_FROM_DATABASE=Filter Wheel + +usb:v0F18p000A* + ID_MODEL_FROM_DATABASE=ProLine CCD + +usb:v0F18p000B* + ID_MODEL_FROM_DATABASE=Color Filter Wheel 4 + +usb:v0F18p000C* + ID_MODEL_FROM_DATABASE=PDF2 + +usb:v0F18p000D* + ID_MODEL_FROM_DATABASE=Guider + +usb:v0F19* + ID_VENDOR_FROM_DATABASE=Oracom Co., Ltd + +usb:v0F1B* + ID_VENDOR_FROM_DATABASE=Onset Computer Corp. + +usb:v0F1C* + ID_VENDOR_FROM_DATABASE=Funai Electric Co., Ltd + +usb:v0F1D* + ID_VENDOR_FROM_DATABASE=Iwill Corp. + +usb:v0F21* + ID_VENDOR_FROM_DATABASE=IOI Technology Corp. + +usb:v0F22* + ID_VENDOR_FROM_DATABASE=Senior Industries, Inc. + +usb:v0F23* + ID_VENDOR_FROM_DATABASE=Leader Tech Manufacturer Co., Ltd + +usb:v0F24* + ID_VENDOR_FROM_DATABASE=Flex-P Industries, Snd., Bhd. + +usb:v0F2D* + ID_VENDOR_FROM_DATABASE=ViPower, Inc. + +usb:v0F2E* + ID_VENDOR_FROM_DATABASE=Geniality Maple Technology Co., Ltd + +usb:v0F2F* + ID_VENDOR_FROM_DATABASE=Priva Design Services + +usb:v0F30* + ID_VENDOR_FROM_DATABASE=Jess Technology Co., Ltd + +usb:v0F30p001C* + ID_MODEL_FROM_DATABASE=PS3 Guitar Controller Dongle + +usb:v0F30p0110* + ID_MODEL_FROM_DATABASE=Dual Analog Rumble Pad + +usb:v0F30p0111* + ID_MODEL_FROM_DATABASE=Colour Rumble Pad + +usb:v0F30p0208* + ID_MODEL_FROM_DATABASE=Xbox & PC Gamepad + +usb:v0F31* + ID_VENDOR_FROM_DATABASE=Chrysalis Development + +usb:v0F32* + ID_VENDOR_FROM_DATABASE=YFC-BonEagle Electric Co., Ltd + +usb:v0F37* + ID_VENDOR_FROM_DATABASE=Kokuyo Co., Ltd + +usb:v0F38* + ID_VENDOR_FROM_DATABASE=Nien-Yi Industrial Corp. + +usb:v0F3D* + ID_VENDOR_FROM_DATABASE=Airprime, Incorporated + +usb:v0F3Dp0112* + ID_MODEL_FROM_DATABASE=CDMA 1xEVDO PC Card, PC 5220 + +usb:v0F41* + ID_VENDOR_FROM_DATABASE=RDC Semiconductor Co., Ltd + +usb:v0F42* + ID_VENDOR_FROM_DATABASE=Nital Consulting Services, Inc. + +usb:v0F44* + ID_VENDOR_FROM_DATABASE=Polhemus + +usb:v0F44pEF11* + ID_MODEL_FROM_DATABASE=Patriot (firmware not loaded) + +usb:v0F44pEF12* + ID_MODEL_FROM_DATABASE=Patriot + +usb:v0F44pFF11* + ID_MODEL_FROM_DATABASE=Liberty (firmware not loaded) + +usb:v0F44pFF12* + ID_MODEL_FROM_DATABASE=Liberty + +usb:v0F4B* + ID_VENDOR_FROM_DATABASE=St. John Technology Co., Ltd + +usb:v0F4C* + ID_VENDOR_FROM_DATABASE=WorldWide Cable Opto Corp. + +usb:v0F4D* + ID_VENDOR_FROM_DATABASE=Microtune, Inc. + +usb:v0F4Dp1000* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v0F4E* + ID_VENDOR_FROM_DATABASE=Freedom Scientific + +usb:v0F52* + ID_VENDOR_FROM_DATABASE=Wing Key Electrical Co., Ltd + +usb:v0F53* + ID_VENDOR_FROM_DATABASE=Dongguan White Horse Cable Factory, Ltd + +usb:v0F54* + ID_VENDOR_FROM_DATABASE=Kawai Musical Instruments Mfg. Co., Ltd + +usb:v0F54p0101* + ID_MODEL_FROM_DATABASE=MP6 Stage Piano + +usb:v0F55* + ID_VENDOR_FROM_DATABASE=AmbiCom, Inc. + +usb:v0F5C* + ID_VENDOR_FROM_DATABASE=Prairiecomm, Inc. + +usb:v0F5D* + ID_VENDOR_FROM_DATABASE=NewAge International, LLC + +usb:v0F5Dp9455* + ID_MODEL_FROM_DATABASE=Compact Drive + +usb:v0F5F* + ID_VENDOR_FROM_DATABASE=Key Technology Corp. + +usb:v0F60* + ID_VENDOR_FROM_DATABASE=NTK, Ltd + +usb:v0F61* + ID_VENDOR_FROM_DATABASE=Varian, Inc. + +usb:v0F62* + ID_VENDOR_FROM_DATABASE=Acrox Technologies Co., Ltd + +usb:v0F62p1001* + ID_MODEL_FROM_DATABASE=Targus Mini Trackball Optical Mouse + +usb:v0F63* + ID_VENDOR_FROM_DATABASE=LeapFrog Enterprises + +usb:v0F63p0010* + ID_MODEL_FROM_DATABASE=Leapster Explorer + +usb:v0F63p0500* + ID_MODEL_FROM_DATABASE=Fly Fusion + +usb:v0F63p0600* + ID_MODEL_FROM_DATABASE=Leap Port Turbo + +usb:v0F63p0700* + ID_MODEL_FROM_DATABASE=POGO + +usb:v0F63p0800* + ID_MODEL_FROM_DATABASE=Didj + +usb:v0F63p0900* + ID_MODEL_FROM_DATABASE=TAGSchool + +usb:v0F63p0A00* + ID_MODEL_FROM_DATABASE=Leapster 2 + +usb:v0F63p0B00* + ID_MODEL_FROM_DATABASE=Crammer + +usb:v0F63p0C00* + ID_MODEL_FROM_DATABASE=Tag Jr + +usb:v0F63p0D00* + ID_MODEL_FROM_DATABASE=My Pal Scout + +usb:v0F63p0E00* + ID_MODEL_FROM_DATABASE=Tag32 + +usb:v0F63p0F00* + ID_MODEL_FROM_DATABASE=Tag64 + +usb:v0F63p1000* + ID_MODEL_FROM_DATABASE=Kiwi16 + +usb:v0F63p1100* + ID_MODEL_FROM_DATABASE=Leapster L2x + +usb:v0F63p1111* + ID_MODEL_FROM_DATABASE=Fly Fusion + +usb:v0F63p1300* + ID_MODEL_FROM_DATABASE=Didj UK/France (Leapster Advance) + +usb:v0F68* + ID_VENDOR_FROM_DATABASE=Kobe Steel, Ltd + +usb:v0F69* + ID_VENDOR_FROM_DATABASE=Dionex Corp. + +usb:v0F6A* + ID_VENDOR_FROM_DATABASE=Vibren Technologies, Inc. + +usb:v0F6E* + ID_VENDOR_FROM_DATABASE=INTELLIGENT SYSTEMS + +usb:v0F6Ep0100* + ID_MODEL_FROM_DATABASE=GameBoy Color Emulator + +usb:v0F6Ep0201* + ID_MODEL_FROM_DATABASE=GameBoy Advance Flash Gang Writer + +usb:v0F6Ep0202* + ID_MODEL_FROM_DATABASE=GameBoy Advance Capture + +usb:v0F6Ep0300* + ID_MODEL_FROM_DATABASE=Gamecube DOL Viewer + +usb:v0F6Ep0400* + ID_MODEL_FROM_DATABASE=NDS Emulator + +usb:v0F6Ep0401* + ID_MODEL_FROM_DATABASE=NDS UIC + +usb:v0F6Ep0402* + ID_MODEL_FROM_DATABASE=NDS Writer + +usb:v0F6Ep0403* + ID_MODEL_FROM_DATABASE=NDS Capture + +usb:v0F6Ep0404* + ID_MODEL_FROM_DATABASE=NDS Emulator (Lite) + +usb:v0F73* + ID_VENDOR_FROM_DATABASE=DFI + +usb:v0F7C* + ID_VENDOR_FROM_DATABASE=DQ Technology, Inc. + +usb:v0F7D* + ID_VENDOR_FROM_DATABASE=NetBotz, Inc. + +usb:v0F7E* + ID_VENDOR_FROM_DATABASE=Fluke Corp. + +usb:v0F88* + ID_VENDOR_FROM_DATABASE=VTech Holdings, Ltd + +usb:v0F88p3012* + ID_MODEL_FROM_DATABASE=RT2570 + +usb:v0F88p3014* + ID_MODEL_FROM_DATABASE=ZD1211B + +usb:v0F8B* + ID_VENDOR_FROM_DATABASE=Yazaki Corp. + +usb:v0F8C* + ID_VENDOR_FROM_DATABASE=Young Generation International Corp. + +usb:v0F8D* + ID_VENDOR_FROM_DATABASE=Uniwill Computer Corp. + +usb:v0F8E* + ID_VENDOR_FROM_DATABASE=Kingnet Technology Co., Ltd + +usb:v0F8F* + ID_VENDOR_FROM_DATABASE=Soma Networks + +usb:v0F97* + ID_VENDOR_FROM_DATABASE=CviLux Corp. + +usb:v0F98* + ID_VENDOR_FROM_DATABASE=CyberBank Corp. + +usb:v0F9C* + ID_VENDOR_FROM_DATABASE=Hyun Won, Inc. + +usb:v0F9Cp0301* + ID_MODEL_FROM_DATABASE=M-Any Premium DAH-610 MP3/WMA Player + +usb:v0F9Cp0332* + ID_MODEL_FROM_DATABASE=mobiBLU DAH-1200 MP3/Ogg Player + +usb:v0F9E* + ID_VENDOR_FROM_DATABASE=Lucent Technologies + +usb:v0FA3* + ID_VENDOR_FROM_DATABASE=Starconn Electronic Co., Ltd + +usb:v0FA4* + ID_VENDOR_FROM_DATABASE=ATL Technology + +usb:v0FA5* + ID_VENDOR_FROM_DATABASE=Sotec Co., Ltd + +usb:v0FA7* + ID_VENDOR_FROM_DATABASE=Epox Computer Co., Ltd + +usb:v0FA8* + ID_VENDOR_FROM_DATABASE=Logic Controls, Inc. + +usb:v0FAF* + ID_VENDOR_FROM_DATABASE=Winpoint Electronic Corp. + +usb:v0FB0* + ID_VENDOR_FROM_DATABASE=Haurtian Wire & Cable Co., Ltd + +usb:v0FB1* + ID_VENDOR_FROM_DATABASE=Inclose Design, Inc. + +usb:v0FB2* + ID_VENDOR_FROM_DATABASE=Juan-Chern Industrial Co., Ltd + +usb:v0FB6* + ID_VENDOR_FROM_DATABASE=Heber Ltd + +usb:v0FB6p3FC3* + ID_MODEL_FROM_DATABASE=Firefly X10i I/O Board (with firmware) + +usb:v0FB6p3FC4* + ID_MODEL_FROM_DATABASE=Firefly X10i I/O Board (without firmware) + +usb:v0FB8* + ID_VENDOR_FROM_DATABASE=Wistron Corp. + +usb:v0FB8p0002* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v0FB9* + ID_VENDOR_FROM_DATABASE=AACom Corp. + +usb:v0FBA* + ID_VENDOR_FROM_DATABASE=San Shing Electronics Co., Ltd + +usb:v0FBB* + ID_VENDOR_FROM_DATABASE=Bitwise Systems, Inc. + +usb:v0FC1* + ID_VENDOR_FROM_DATABASE=Mitac Internatinal Corp. + +usb:v0FC2* + ID_VENDOR_FROM_DATABASE=Plug and Jack Industrial, Inc. + +usb:v0FC5* + ID_VENDOR_FROM_DATABASE=Delcom Engineering + +usb:v0FC5p1222* + ID_MODEL_FROM_DATABASE=I/O Development Board + +usb:v0FC6* + ID_VENDOR_FROM_DATABASE=Dataplus Supplies, Inc. + +usb:v0FCA* + ID_VENDOR_FROM_DATABASE=Research In Motion, Ltd. + +usb:v0FCAp0001* + ID_MODEL_FROM_DATABASE=Blackberry Handheld + +usb:v0FCAp0004* + ID_MODEL_FROM_DATABASE=Blackberry Handheld + +usb:v0FCAp0006* + ID_MODEL_FROM_DATABASE=Blackberry Pearl + +usb:v0FCAp0008* + ID_MODEL_FROM_DATABASE=Blackberry Pearl + +usb:v0FCAp8001* + ID_MODEL_FROM_DATABASE=Blackberry Handheld + +usb:v0FCAp8004* + ID_MODEL_FROM_DATABASE=Blackberry Handheld + +usb:v0FCAp8007* + ID_MODEL_FROM_DATABASE=Blackberry Handheld + +usb:v0FCAp8010* + ID_MODEL_FROM_DATABASE=Blackberry Playbook (Connect to Windows mode) + +usb:v0FCAp8011* + ID_MODEL_FROM_DATABASE=Blackberry Playbook (Connect to Mac mode) + +usb:v0FCAp8020* + ID_MODEL_FROM_DATABASE=Blackberry Playbook (CD-Rom mode) + +usb:v0FCE* + ID_VENDOR_FROM_DATABASE=Sony Ericsson Mobile Communications AB + +usb:v0FCEp0076* + ID_MODEL_FROM_DATABASE=W910i (Multimedia mode) + +usb:v0FCEp00AF* + ID_MODEL_FROM_DATABASE=V640i Phone [PTP Camera] + +usb:v0FCEp00D4* + ID_MODEL_FROM_DATABASE=C902 [MTP] + +usb:v0FCEp00D9* + ID_MODEL_FROM_DATABASE=C702 Phone + +usb:v0FCEp0112* + ID_MODEL_FROM_DATABASE=W995 Walkman Phone + +usb:v0FCEp015A* + ID_MODEL_FROM_DATABASE=Xperia Pro [Media Transfer Protocol] + +usb:v0FCEp0166* + ID_MODEL_FROM_DATABASE=Xperia Mini Pro + +usb:v0FCEp0167* + ID_MODEL_FROM_DATABASE=ST15i (Xperia mini) + +usb:v0FCEp0169* + ID_MODEL_FROM_DATABASE=Xperia S + +usb:v0FCEp0172* + ID_MODEL_FROM_DATABASE=Xperia P + +usb:v0FCEp0177* + ID_MODEL_FROM_DATABASE=Xperia Ion [Mass Storage] + +usb:v0FCEp0DDE* + ID_MODEL_FROM_DATABASE=Xperia Mini Pro Bootloader + +usb:v0FCEp1010* + ID_MODEL_FROM_DATABASE=WMC Modem + +usb:v0FCEp10AF* + ID_MODEL_FROM_DATABASE=V640i Phone [PictBridge] + +usb:v0FCEp10D4* + ID_MODEL_FROM_DATABASE=C902 Phone [PictBridge] + +usb:v0FCEp2105* + ID_MODEL_FROM_DATABASE=W715 Phone + +usb:v0FCEp2137* + ID_MODEL_FROM_DATABASE=Xperia X10 mini (USB debug) + +usb:v0FCEp2138* + ID_MODEL_FROM_DATABASE=Xperia X10 mini pro (Debug) + +usb:v0FCEp2149* + ID_MODEL_FROM_DATABASE=Xperia X8 (debug) + +usb:v0FCEp3137* + ID_MODEL_FROM_DATABASE=Xperia X10 mini + +usb:v0FCEp3138* + ID_MODEL_FROM_DATABASE=Xperia X10 mini pro + +usb:v0FCEp3149* + ID_MODEL_FROM_DATABASE=Xperia X8 + +usb:v0FCEp5177* + ID_MODEL_FROM_DATABASE=Xperia Ion [Debug Mode] + +usb:v0FCEp518C* + ID_MODEL_FROM_DATABASE=C1605 [Xperia E dual] MTD mode + +usb:v0FCEp614F* + ID_MODEL_FROM_DATABASE=Xperia X12 (debug mode) + +usb:v0FCEp6166* + ID_MODEL_FROM_DATABASE=Xperia Mini Pro + +usb:v0FCEp618C* + ID_MODEL_FROM_DATABASE=C1605 [Xperia E dual] MSC mode + +usb:v0FCEp715A* + ID_MODEL_FROM_DATABASE=Xperia Pro [Tethering] + +usb:v0FCEp7166* + ID_MODEL_FROM_DATABASE=Xperia Mini Pro (Tethering mode) + +usb:v0FCEp7177* + ID_MODEL_FROM_DATABASE=Xperia Ion [Tethering] + +usb:v0FCEp8004* + ID_MODEL_FROM_DATABASE=9000 Phone [Mass Storage] + +usb:v0FCEpADDE* + ID_MODEL_FROM_DATABASE=Boot loader + +usb:v0FCEpD008* + ID_MODEL_FROM_DATABASE=V800-Vodafone 802SE Phone + +usb:v0FCEpD016* + ID_MODEL_FROM_DATABASE=K750i Phone + +usb:v0FCEpD017* + ID_MODEL_FROM_DATABASE=K608i Phone + +usb:v0FCEpD019* + ID_MODEL_FROM_DATABASE=VDC EGPRS Modem + +usb:v0FCEpD025* + ID_MODEL_FROM_DATABASE=520 WMC Data Modem + +usb:v0FCEpD028* + ID_MODEL_FROM_DATABASE=W800i + +usb:v0FCEpD038* + ID_MODEL_FROM_DATABASE=W850i Phone + +usb:v0FCEpD039* + ID_MODEL_FROM_DATABASE=K800i (phone mode) + +usb:v0FCEpD041* + ID_MODEL_FROM_DATABASE=K510i Phone + +usb:v0FCEpD042* + ID_MODEL_FROM_DATABASE=W810i Phone + +usb:v0FCEpD043* + ID_MODEL_FROM_DATABASE=V630i Phone + +usb:v0FCEpD046* + ID_MODEL_FROM_DATABASE=K610i Phone + +usb:v0FCEpD065* + ID_MODEL_FROM_DATABASE=W960i Phone (PC Suite) + +usb:v0FCEpD076* + ID_MODEL_FROM_DATABASE=W910i (Phone mode) + +usb:v0FCEpD089* + ID_MODEL_FROM_DATABASE=W580i Phone (mass storage) + +usb:v0FCEpD0A1* + ID_MODEL_FROM_DATABASE=K810 + +usb:v0FCEpD0AF* + ID_MODEL_FROM_DATABASE=V640i Phone + +usb:v0FCEpD0CF* + ID_MODEL_FROM_DATABASE=MD300 Mobile Broadband Modem + +usb:v0FCEpD0D4* + ID_MODEL_FROM_DATABASE=C902 Phone [Modem] + +usb:v0FCEpD0E1* + ID_MODEL_FROM_DATABASE=MD400 Mobile Broadband Modem + +usb:v0FCEpD12E* + ID_MODEL_FROM_DATABASE=Xperia X10 + +usb:v0FCEpE000* + ID_MODEL_FROM_DATABASE=K810 (PictBridge mode) + +usb:v0FCEpE039* + ID_MODEL_FROM_DATABASE=K800i (msc mode) + +usb:v0FCEpE042* + ID_MODEL_FROM_DATABASE=W810i Phone + +usb:v0FCEpE043* + ID_MODEL_FROM_DATABASE=V630i Phone [Mass Storage] + +usb:v0FCEpE075* + ID_MODEL_FROM_DATABASE=K850i + +usb:v0FCEpE076* + ID_MODEL_FROM_DATABASE=W910i (Mass storage) + +usb:v0FCEpE089* + ID_MODEL_FROM_DATABASE=W580i Phone + +usb:v0FCEpE090* + ID_MODEL_FROM_DATABASE=W200 Phone (Mass Storage) + +usb:v0FCEpE0A1* + ID_MODEL_FROM_DATABASE=K810 (Mass Storage mode) + +usb:v0FCEpE0A3* + ID_MODEL_FROM_DATABASE=W660i + +usb:v0FCEpE0AF* + ID_MODEL_FROM_DATABASE=V640i Phone [Mass Storage] + +usb:v0FCEpE0D4* + ID_MODEL_FROM_DATABASE=C902 Phone [Mass Storage] + +usb:v0FCEpE0EF* + ID_MODEL_FROM_DATABASE=C905 Phone [Mass Storage] + +usb:v0FCEpE0F3* + ID_MODEL_FROM_DATABASE=W595 + +usb:v0FCEpE105* + ID_MODEL_FROM_DATABASE=W705 + +usb:v0FCEpE112* + ID_MODEL_FROM_DATABASE=W995 Phone (Mass Storage) + +usb:v0FCEpE12E* + ID_MODEL_FROM_DATABASE=X10i Phone + +usb:v0FCEpE133* + ID_MODEL_FROM_DATABASE=Vivaz + +usb:v0FCEpE14F* + ID_MODEL_FROM_DATABASE=Xperia Arc/X12 + +usb:v0FCEpE15A* + ID_MODEL_FROM_DATABASE=Xperia Pro [Mass Storage Class] + +usb:v0FCEpE161* + ID_MODEL_FROM_DATABASE=Xperia Ray + +usb:v0FCEpE166* + ID_MODEL_FROM_DATABASE=Xperia Mini Pro + +usb:v0FCEpE167* + ID_MODEL_FROM_DATABASE=XPERIA mini + +usb:v0FCF* + ID_VENDOR_FROM_DATABASE=Dynastream Innovations, Inc. + +usb:v0FCFp1003* + ID_MODEL_FROM_DATABASE=ANT Development Board + +usb:v0FCFp1004* + ID_MODEL_FROM_DATABASE=ANT2USB + +usb:v0FCFp1006* + ID_MODEL_FROM_DATABASE=ANT Development Board + +usb:v0FCFp1008* + ID_MODEL_FROM_DATABASE=Mini stick Suunto + +usb:v0FD0* + ID_VENDOR_FROM_DATABASE=Tulip Computers B.V. + +usb:v0FD1* + ID_VENDOR_FROM_DATABASE=Giant Electronics Ltd. + +usb:v0FD2* + ID_VENDOR_FROM_DATABASE=Seac Banche + +usb:v0FD2p0001* + ID_MODEL_FROM_DATABASE=RDS 6000 + +usb:v0FD4* + ID_VENDOR_FROM_DATABASE=Tenovis GmbH & Co., KG + +usb:v0FD5* + ID_VENDOR_FROM_DATABASE=Direct Access Technology, Inc. + +usb:v0FD9* + ID_VENDOR_FROM_DATABASE=Elgato Systems GmbH + +usb:v0FD9p0011* + ID_MODEL_FROM_DATABASE=EyeTV Diversity + +usb:v0FD9p0018* + ID_MODEL_FROM_DATABASE=EyeTV Hybrid + +usb:v0FD9p0020* + ID_MODEL_FROM_DATABASE=EyeTV DTT Deluxe + +usb:v0FD9p0021* + ID_MODEL_FROM_DATABASE=EyeTV DTT + +usb:v0FD9p002A* + ID_MODEL_FROM_DATABASE=EyeTV Sat + +usb:v0FD9p002C* + ID_MODEL_FROM_DATABASE=EyeTV DTT Deluxe v2 + +usb:v0FD9p0033* + ID_MODEL_FROM_DATABASE=Video Capture + +usb:v0FD9p0037* + ID_MODEL_FROM_DATABASE=Video Capture v2 + +usb:v0FDA* + ID_VENDOR_FROM_DATABASE=Quantec Networks GmbH + +usb:v0FDAp0100* + ID_MODEL_FROM_DATABASE=quanton flight control + +usb:v0FDC* + ID_VENDOR_FROM_DATABASE=Micro Plus + +usb:v0FE0* + ID_VENDOR_FROM_DATABASE=Osterhout Design Group + +usb:v0FE0p0100* + ID_MODEL_FROM_DATABASE=Bluetooth Mouse + +usb:v0FE0p0101* + ID_MODEL_FROM_DATABASE=Bluetooth IMU + +usb:v0FE0p0200* + ID_MODEL_FROM_DATABASE=Bluetooth Keypad + +usb:v0FE4* + ID_VENDOR_FROM_DATABASE=IN-Tech Electronics, Ltd + +usb:v0FE5* + ID_VENDOR_FROM_DATABASE=Greenconn (U.S.A.), Inc. + +usb:v0FE6* + ID_VENDOR_FROM_DATABASE=Kontron (Industrial Computer Source / ICS Advent) + +usb:v0FE6p8101* + ID_MODEL_FROM_DATABASE=DM9601 Fast Ethernet Adapter + +usb:v0FE6p811E* + ID_MODEL_FROM_DATABASE=Parallel Adapter + +usb:v0FE6p9700* + ID_MODEL_FROM_DATABASE=DM9601 Fast Ethernet Adapter + +usb:v0FE9* + ID_VENDOR_FROM_DATABASE=DVICO + +usb:v0FE9p4020* + ID_MODEL_FROM_DATABASE=TViX M-6500 + +usb:v0FE9pDB00* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T (MT352+LgZ201) (uninitialized) + +usb:v0FE9pDB01* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T (MT352+LgZ201) (initialized) + +usb:v0FE9pDB10* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T (MT352+Thomson7579) (uninitialized) + +usb:v0FE9pDB11* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T (MT352+Thomson7579) (initialized) + +usb:v0FE9pDB78* + ID_MODEL_FROM_DATABASE=FusionHDTV DVB-T Dual Digital 4 (ZL10353+xc2028/xc3028) (initialized) + +usb:v0FEA* + ID_VENDOR_FROM_DATABASE=United Computer Accessories + +usb:v0FEB* + ID_VENDOR_FROM_DATABASE=CRS Electronic Co., Ltd + +usb:v0FEC* + ID_VENDOR_FROM_DATABASE=UMC Electronics Co., Ltd + +usb:v0FED* + ID_VENDOR_FROM_DATABASE=Access Co., Ltd + +usb:v0FEE* + ID_VENDOR_FROM_DATABASE=Xsido Corp. + +usb:v0FEF* + ID_VENDOR_FROM_DATABASE=MJ Research, Inc. + +usb:v0FF6* + ID_VENDOR_FROM_DATABASE=Core Valley Co., Ltd + +usb:v0FF7* + ID_VENDOR_FROM_DATABASE=CHI SHING Computer Accessories Co., Ltd + +usb:v0FFC* + ID_VENDOR_FROM_DATABASE=Clavia DMI AB + +usb:v0FFCp0021* + ID_MODEL_FROM_DATABASE=Nord Stage 2 + +usb:v0FFF* + ID_VENDOR_FROM_DATABASE=Aopen, Inc. + +usb:v1000* + ID_VENDOR_FROM_DATABASE=Speed Tech Corp. + +usb:v1001* + ID_VENDOR_FROM_DATABASE=Ritronics Components (S) Pte., Ltd + +usb:v1003* + ID_VENDOR_FROM_DATABASE=Sigma Corp. + +usb:v1003p0003* + ID_MODEL_FROM_DATABASE=SD14 + +usb:v1003p0100* + ID_MODEL_FROM_DATABASE=SD9/SD10 + +usb:v1004* + ID_VENDOR_FROM_DATABASE=LG Electronics, Inc. + +usb:v1004p1FAE* + ID_MODEL_FROM_DATABASE=U8120 3G Cellphone + +usb:v1004p6000* + ID_MODEL_FROM_DATABASE=Various Mobile Phones + +usb:v1004p6005* + ID_MODEL_FROM_DATABASE=T5100 + +usb:v1004p6018* + ID_MODEL_FROM_DATABASE=GM360/GD510/GW520/KP501 + +usb:v1004p618E* + ID_MODEL_FROM_DATABASE=Ally/Optimus One/Vortex (debug mode) + +usb:v1004p618F* + ID_MODEL_FROM_DATABASE=Ally/Optimus One + +usb:v1004p61C6* + ID_MODEL_FROM_DATABASE=Vortex (msc) + +usb:v1004p61CC* + ID_MODEL_FROM_DATABASE=Optimus S + +usb:v1004p61F1* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [LG Software mode] + +usb:v1004p61F9* + ID_MODEL_FROM_DATABASE=V909 G-Slate + +usb:v1004p61FC* + ID_MODEL_FROM_DATABASE=Optimus 3 + +usb:v1004p61FE* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [USB tethering mode] + +usb:v1004p6300* + ID_MODEL_FROM_DATABASE=Optimus Android Phone + +usb:v1004p631C* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [MTP mode] + +usb:v1004p631E* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [Camera/PTP mode] + +usb:v1004p6356* + ID_MODEL_FROM_DATABASE=Optimus Android Phone [Virtual CD mode] + +usb:v1004p6800* + ID_MODEL_FROM_DATABASE=CDMA Modem + +usb:v1004p7000* + ID_MODEL_FROM_DATABASE=LG LDP-7024D(LD)USB + +usb:v1004pA400* + ID_MODEL_FROM_DATABASE=Renoir (KC910) + +usb:v1005* + ID_VENDOR_FROM_DATABASE=Apacer Technology, Inc. + +usb:v1005p1001* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v1005p1004* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v1005p1006* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v1005pB113* + ID_MODEL_FROM_DATABASE=Handy Steno 2.0/HT203 + +usb:v1005pB223* + ID_MODEL_FROM_DATABASE=CD-RW + 6in1 Card Reader Digital Storage / Converter + +usb:v1006* + ID_VENDOR_FROM_DATABASE=iRiver, Ltd. + +usb:v1006p3001* + ID_MODEL_FROM_DATABASE=iHP-100 + +usb:v1006p3002* + ID_MODEL_FROM_DATABASE=iHP-120/140 MP3 Player + +usb:v1006p3003* + ID_MODEL_FROM_DATABASE=H320/H340 + +usb:v1006p3004* + ID_MODEL_FROM_DATABASE=H340 (mtp) + +usb:v1009* + ID_VENDOR_FROM_DATABASE=Emuzed, Inc. + +usb:v1009p000E* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v1009p0013* + ID_MODEL_FROM_DATABASE=Angel MPEG Device + +usb:v1009p0015* + ID_MODEL_FROM_DATABASE=Lumanate Wave PAL SECAM DVBT Device + +usb:v1009p0016* + ID_MODEL_FROM_DATABASE=Lumanate Wave NTSC/ATSC Combo Device + +usb:v100A* + ID_VENDOR_FROM_DATABASE=AV Chaseway, Ltd + +usb:v100Ap2402* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v100Ap2404* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v100Ap2405* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v100Ap2406* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v100ApA0C0* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v100B* + ID_VENDOR_FROM_DATABASE=Chou Chin Industrial Co., Ltd + +usb:v100D* + ID_VENDOR_FROM_DATABASE=Netopia, Inc. + +usb:v100Dp3342* + ID_MODEL_FROM_DATABASE=Cayman 3352 DSL Modem + +usb:v100Dp3382* + ID_MODEL_FROM_DATABASE=3380 Series Network Interface + +usb:v100Dp6072* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v100Dp9031* + ID_MODEL_FROM_DATABASE=Motorola 802.11n Dualband USB Wireless Adapter + +usb:v100Dp9032* + ID_MODEL_FROM_DATABASE=Motorola 802.11n 5G USB Wireless Adapter + +usb:v100DpCB01* + ID_MODEL_FROM_DATABASE=Cayman 3341 Ethernet DSL Router + +usb:v1010* + ID_VENDOR_FROM_DATABASE=Fukuda Denshi Co., Ltd + +usb:v1011* + ID_VENDOR_FROM_DATABASE=Mobile Media Tech. + +usb:v1011p0001* + ID_MODEL_FROM_DATABASE=AccFast Mp3 + +usb:v1012* + ID_VENDOR_FROM_DATABASE=SDKM Fibres, Wires & Cables Berhad + +usb:v1013* + ID_VENDOR_FROM_DATABASE=TST-Touchless Sensor Technology AG + +usb:v1014* + ID_VENDOR_FROM_DATABASE=Densitron Technologies PLC + +usb:v1015* + ID_VENDOR_FROM_DATABASE=Softronics Pty., Ltd + +usb:v1016* + ID_VENDOR_FROM_DATABASE=Xiamen Hung's Enterprise Co., Ltd + +usb:v1017* + ID_VENDOR_FROM_DATABASE=Speedy Industrial Supplies, Pte., Ltd + +usb:v1019* + ID_VENDOR_FROM_DATABASE=Elitegroup Computer Systems (ECS) + +usb:v1019p0C55* + ID_MODEL_FROM_DATABASE=Flash Reader, Desknote UCR-61S2B + +usb:v1019p0F38* + ID_MODEL_FROM_DATABASE=Infrared Receiver + +usb:v1020* + ID_VENDOR_FROM_DATABASE=Labtec + +usb:v1020p0006* + ID_MODEL_FROM_DATABASE=Wireless Keyboard + +usb:v1020p000A* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse + +usb:v1020p0106* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse + +usb:v1022* + ID_VENDOR_FROM_DATABASE=Shinko Shoji Co., Ltd + +usb:v1025* + ID_VENDOR_FROM_DATABASE=Hyper-Paltek + +usb:v1025p005E* + ID_MODEL_FROM_DATABASE=USB DVB-T device + +usb:v1025p005F* + ID_MODEL_FROM_DATABASE=USB DVB-T device + +usb:v1025p0300* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v1025p0350* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v1026* + ID_VENDOR_FROM_DATABASE=Newly Corp. + +usb:v1027* + ID_VENDOR_FROM_DATABASE=Time Domain + +usb:v1028* + ID_VENDOR_FROM_DATABASE=Inovys Corp. + +usb:v1029* + ID_VENDOR_FROM_DATABASE=Atlantic Coast Telesys + +usb:v102A* + ID_VENDOR_FROM_DATABASE=Ramos Technology Co., Ltd + +usb:v102B* + ID_VENDOR_FROM_DATABASE=Infotronic America, Inc. + +usb:v102C* + ID_VENDOR_FROM_DATABASE=Etoms Electronics Corp. + +usb:v102Cp6151* + ID_MODEL_FROM_DATABASE=Q-Cam Sangha CIF + +usb:v102Cp6251* + ID_MODEL_FROM_DATABASE=Q-Cam VGA + +usb:v102D* + ID_VENDOR_FROM_DATABASE=Winic Corp. + +usb:v1031* + ID_VENDOR_FROM_DATABASE=Comax Technology, Inc. + +usb:v1032* + ID_VENDOR_FROM_DATABASE=C-One Technology Corp. + +usb:v1033* + ID_VENDOR_FROM_DATABASE=Nucam Corp. + +usb:v1033p0068* + ID_MODEL_FROM_DATABASE=3,5'' HDD case MD-231 + +usb:v1038* + ID_VENDOR_FROM_DATABASE=Ideazon, Inc. + +usb:v1038p0100* + ID_MODEL_FROM_DATABASE=Zboard + +usb:v1038p1361* + ID_MODEL_FROM_DATABASE=Sensei + +usb:v1039* + ID_VENDOR_FROM_DATABASE=devolo AG + +usb:v1039p0824* + ID_MODEL_FROM_DATABASE=1866 802.11bg [Texas Instruments TNETW1450] + +usb:v1039p2140* + ID_MODEL_FROM_DATABASE=dsl+ 1100 duo + +usb:v103D* + ID_VENDOR_FROM_DATABASE=Stanton + +usb:v103Dp0100* + ID_MODEL_FROM_DATABASE=ScratchAmp + +usb:v103Dp0101* + ID_MODEL_FROM_DATABASE=ScratchAmp + +usb:v1043* + ID_VENDOR_FROM_DATABASE=iCreate Technologies Corp. + +usb:v1043p160F* + ID_MODEL_FROM_DATABASE=Wireless Network Adapter + +usb:v1043p4901* + ID_MODEL_FROM_DATABASE=AV-836 Video Capture Device + +usb:v1043p8006* + ID_MODEL_FROM_DATABASE=Flash Disk 32-256 MB + +usb:v1043p8012* + ID_MODEL_FROM_DATABASE=Flash Disk 256 MB + +usb:v1044* + ID_VENDOR_FROM_DATABASE=Chu Yuen Enterprise Co., Ltd + +usb:v1044p7001* + ID_MODEL_FROM_DATABASE=Gigabyte U7000 DVB-T tuner + +usb:v1044p7002* + ID_MODEL_FROM_DATABASE=Gigabyte U8000 DVB-T tuner + +usb:v1044p7004* + ID_MODEL_FROM_DATABASE=Gigabyte U7100 DVB-T tuner + +usb:v1044p7005* + ID_MODEL_FROM_DATABASE=Gigabyte U7200 DVB-T tuner [AF9035] + +usb:v1044p7006* + ID_MODEL_FROM_DATABASE=Gigabyte U6000 DVB-T tuner [em2863] + +usb:v1044p8001* + ID_MODEL_FROM_DATABASE=GN-54G + +usb:v1044p8002* + ID_MODEL_FROM_DATABASE=GN-BR402W + +usb:v1044p8003* + ID_MODEL_FROM_DATABASE=GN-WLBM101 + +usb:v1044p8004* + ID_MODEL_FROM_DATABASE=GN-WLBZ101 802.11b Adapter + +usb:v1044p8005* + ID_MODEL_FROM_DATABASE=GN-WLBZ201 802.11b Adapter + +usb:v1044p8006* + ID_MODEL_FROM_DATABASE=GN-WBZB-M 802.11b Adapter + +usb:v1044p8007* + ID_MODEL_FROM_DATABASE=GN-WBKG + +usb:v1044p8008* + ID_MODEL_FROM_DATABASE=GN-WB01GS + +usb:v1044p800A* + ID_MODEL_FROM_DATABASE=GN-WI05GS + +usb:v1044p800B* + ID_MODEL_FROM_DATABASE=GN-WB30N 802.11n WLAN Card + +usb:v1044p800C* + ID_MODEL_FROM_DATABASE=GN-WB31N 802.11n USB WLAN Card + +usb:v1044p800D* + ID_MODEL_FROM_DATABASE=GN-WB32L 802.11n USB WLAN Card + +usb:v1046* + ID_VENDOR_FROM_DATABASE=Winbond Electronics Corp. [hex] + +usb:v1046p6694* + ID_MODEL_FROM_DATABASE=Generic W6694 USB + +usb:v1046p8901* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v1046p9967* + ID_MODEL_FROM_DATABASE=W9967CF/W9968CF Webcam IC + +usb:v1048* + ID_VENDOR_FROM_DATABASE=Targus Group International + +usb:v104B* + ID_VENDOR_FROM_DATABASE=Mylex / Buslogic + +usb:v104C* + ID_VENDOR_FROM_DATABASE=AMCO TEC International, Inc. + +usb:v104D* + ID_VENDOR_FROM_DATABASE=Newport Corporation + +usb:v104Dp1003* + ID_MODEL_FROM_DATABASE=Model-52 LED Light Source Power Supply and Driver + +usb:v104F* + ID_VENDOR_FROM_DATABASE=WB Electronics + +usb:v104Fp0001* + ID_MODEL_FROM_DATABASE=Infinity Phoenix + +usb:v104Fp0002* + ID_MODEL_FROM_DATABASE=Smartmouse + +usb:v104Fp0003* + ID_MODEL_FROM_DATABASE=FunProgrammer + +usb:v104Fp0004* + ID_MODEL_FROM_DATABASE=Infinity Unlimited + +usb:v104Fp0006* + ID_MODEL_FROM_DATABASE=Infinity Smart + +usb:v104Fp0007* + ID_MODEL_FROM_DATABASE=Infinity Smart module + +usb:v104Fp0008* + ID_MODEL_FROM_DATABASE=Infinity CryptoKey + +usb:v104Fp0009* + ID_MODEL_FROM_DATABASE=RE-BL PlayStation 3 IR-to-Bluetooth converter + +usb:v1050* + ID_VENDOR_FROM_DATABASE=Yubico.com + +usb:v1050p0010* + ID_MODEL_FROM_DATABASE=Yubikey + +usb:v1050p0110* + ID_MODEL_FROM_DATABASE=Yubikey NEO OTP + +usb:v1050p0111* + ID_MODEL_FROM_DATABASE=Yubikey NEO OTP+CCID + +usb:v1050p0211* + ID_MODEL_FROM_DATABASE=Gnubby + +usb:v1053* + ID_VENDOR_FROM_DATABASE=Immanuel Electronics Co., Ltd + +usb:v1054* + ID_VENDOR_FROM_DATABASE=BMS International Beheer N.V. + +usb:v1054p5004* + ID_MODEL_FROM_DATABASE=DSL 7420 Loader + +usb:v1054p5005* + ID_MODEL_FROM_DATABASE=DSL 7420 LAN Modem + +usb:v1055* + ID_VENDOR_FROM_DATABASE=Complex Micro Interconnection Co., Ltd + +usb:v1056* + ID_VENDOR_FROM_DATABASE=Hsin Chen Ent Co., Ltd + +usb:v1057* + ID_VENDOR_FROM_DATABASE=ON Semiconductor + +usb:v1058* + ID_VENDOR_FROM_DATABASE=Western Digital Technologies, Inc. + +usb:v1058p0200* + ID_MODEL_FROM_DATABASE=FireWire USB Combo + +usb:v1058p0400* + ID_MODEL_FROM_DATABASE=External HDD + +usb:v1058p0500* + ID_MODEL_FROM_DATABASE=hub + +usb:v1058p0702* + ID_MODEL_FROM_DATABASE=Passport External HDD + +usb:v1058p0704* + ID_MODEL_FROM_DATABASE=Passport External HDD + +usb:v1058p070A* + ID_MODEL_FROM_DATABASE=My Passport Essential SE + +usb:v1058p071A* + ID_MODEL_FROM_DATABASE=My Passport + +usb:v1058p0730* + ID_MODEL_FROM_DATABASE=My Passport + +usb:v1058p0740* + ID_MODEL_FROM_DATABASE=My Passport + +usb:v1058p0742* + ID_MODEL_FROM_DATABASE=My Passport Essential SE + +usb:v1058p0748* + ID_MODEL_FROM_DATABASE=My Passport 1TB USB 3.0 + +usb:v1058p0900* + ID_MODEL_FROM_DATABASE=MyBook Essential External HDD + +usb:v1058p0901* + ID_MODEL_FROM_DATABASE=MyBook External HDD + +usb:v1058p0903* + ID_MODEL_FROM_DATABASE=My Book Premium Edition + +usb:v1058p0910* + ID_MODEL_FROM_DATABASE=MyBook Essential External HDD + +usb:v1058p1001* + ID_MODEL_FROM_DATABASE=External Hard Disk [Elements] + +usb:v1058p1003* + ID_MODEL_FROM_DATABASE=Elements 1000 GB + +usb:v1058p1010* + ID_MODEL_FROM_DATABASE=Elements External HDD + +usb:v1058p1021* + ID_MODEL_FROM_DATABASE=Elements 2TB + +usb:v1058p1023* + ID_MODEL_FROM_DATABASE=Elements SE + +usb:v1058p1103* + ID_MODEL_FROM_DATABASE=My Book Studio + +usb:v1058p1104* + ID_MODEL_FROM_DATABASE=MyBook Mirror Edition External HDD + +usb:v1058p1105* + ID_MODEL_FROM_DATABASE=My Book Studio II + +usb:v1058p1123* + ID_MODEL_FROM_DATABASE=My Book 3.0 + +usb:v1058p1140* + ID_MODEL_FROM_DATABASE=My Book Essential USB3.0 + +usb:v1059* + ID_VENDOR_FROM_DATABASE=Giesecke & Devrient GmbH + +usb:v1059p000B* + ID_MODEL_FROM_DATABASE=StarSign Bio Token 3.0 + +usb:v105C* + ID_VENDOR_FROM_DATABASE=Hong Ji Electric Wire & Cable (Dongguan) Co., Ltd + +usb:v105D* + ID_VENDOR_FROM_DATABASE=Delkin Devices, Inc. + +usb:v105E* + ID_VENDOR_FROM_DATABASE=Valence Semiconductor Design, Ltd + +usb:v105F* + ID_VENDOR_FROM_DATABASE=Chin Shong Enterprise Co., Ltd + +usb:v1060* + ID_VENDOR_FROM_DATABASE=Easthome Industrial Co., Ltd + +usb:v1063* + ID_VENDOR_FROM_DATABASE=Motorola Electronics Taiwan, Ltd [hex] + +usb:v1063p1555* + ID_MODEL_FROM_DATABASE=MC141555 Hub + +usb:v1063p4100* + ID_MODEL_FROM_DATABASE=SB4100 USB Cable Modem + +usb:v1065* + ID_VENDOR_FROM_DATABASE=CCYU Technology + +usb:v1065p0020* + ID_MODEL_FROM_DATABASE=USB-DVR2 Dev Board + +usb:v1065p2136* + ID_MODEL_FROM_DATABASE=EasyDisk ED1064 + +usb:v106A* + ID_VENDOR_FROM_DATABASE=Loyal Legend, Ltd + +usb:v106C* + ID_VENDOR_FROM_DATABASE=Curitel Communications, Inc. + +usb:v106Cp1101* + ID_MODEL_FROM_DATABASE=CDMA 2000 1xRTT USB modem (HX-550C) + +usb:v106Cp1102* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1103* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1104* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1105* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp1106* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1301* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp1302* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1303* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1304* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1401* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp1402* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1403* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1501* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1502* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1503* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1601* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp1602* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp1603* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2101* + ID_MODEL_FROM_DATABASE=AudioVox 8900 Cell Phone + +usb:v106Cp2102* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2103* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2301* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2302* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2303* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2401* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2402* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2403* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2501* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2502* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2503* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2601* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp2602* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp2603* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp3701* + ID_MODEL_FROM_DATABASE=Broadband Wireless modem + +usb:v106Cp3702* + ID_MODEL_FROM_DATABASE=Pantech PX-500 + +usb:v106Cp3714* + ID_MODEL_FROM_DATABASE=PANTECH USB MODEM [UM175] + +usb:v106Cp3716* + ID_MODEL_FROM_DATABASE=UMW190 Modem + +usb:v106Cp3721* + ID_MODEL_FROM_DATABASE=Option Beemo (GI0801) LTE surfstick + +usb:v106Cp3B14* + ID_MODEL_FROM_DATABASE=Option Beemo (GI0801) LTE surfstick + +usb:v106Cp3EB4* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp4101* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp4102* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp4301* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp4302* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp4401* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp4402* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp4501* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp4502* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp4601* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp4602* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5101* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp5102* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5301* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5302* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp5401* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp5402* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5501* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5502* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp5601* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106Cp5602* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106Cp7101* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v106Cp7102* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106CpA000* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106CpA001* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106CpC100* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106CpC200* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106CpC500* + ID_MODEL_FROM_DATABASE=Packet Service Diagnostic Serial Port (WDM) + +usb:v106CpE200* + ID_MODEL_FROM_DATABASE=Packet Service + +usb:v106D* + ID_VENDOR_FROM_DATABASE=San Chieh Manufacturing, Ltd + +usb:v106E* + ID_VENDOR_FROM_DATABASE=ConectL + +usb:v106F* + ID_VENDOR_FROM_DATABASE=Money Controls + +usb:v106Fp0009* + ID_MODEL_FROM_DATABASE=CT10x Coin Transaction + +usb:v106Fp000A* + ID_MODEL_FROM_DATABASE=CR10x Coin Recycler + +usb:v1076* + ID_VENDOR_FROM_DATABASE=GCT Semiconductor, Inc. + +usb:v1076p0031* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v1076p0032* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v107B* + ID_VENDOR_FROM_DATABASE=Gateway, Inc. + +usb:v107Bp3009* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v107Bp55B2* + ID_MODEL_FROM_DATABASE=WBU-110 802.11b Wireless Adapter [Intersil PRISM 3] + +usb:v107Bp55F2* + ID_MODEL_FROM_DATABASE=WGU-210 802.11g Adapter [Intersil ISL3886] + +usb:v107D* + ID_VENDOR_FROM_DATABASE=Arlec Australia, Ltd + +usb:v107E* + ID_VENDOR_FROM_DATABASE=Midoriya Electric Co., Ltd + +usb:v107F* + ID_VENDOR_FROM_DATABASE=KidzMouse, Inc. + +usb:v1082* + ID_VENDOR_FROM_DATABASE=Shin-Etsukaken Co., Ltd + +usb:v1083* + ID_VENDOR_FROM_DATABASE=Canon Electronics, Inc. + +usb:v1083p161B* + ID_MODEL_FROM_DATABASE=DR-2010C Scanner + +usb:v1083p162C* + ID_MODEL_FROM_DATABASE=P-150 Scanner + +usb:v1084* + ID_VENDOR_FROM_DATABASE=Pantech Co., Ltd + +usb:v108A* + ID_VENDOR_FROM_DATABASE=Chloride Power Protection + +usb:v108B* + ID_VENDOR_FROM_DATABASE=Grand-tek Technology Co., Ltd + +usb:v108C* + ID_VENDOR_FROM_DATABASE=Robert Bosch GmbH + +usb:v108E* + ID_VENDOR_FROM_DATABASE=Lotes Co., Ltd. + +usb:v1099* + ID_VENDOR_FROM_DATABASE=Surface Optics Corp. + +usb:v109A* + ID_VENDOR_FROM_DATABASE=DATASOFT Systems GmbH + +usb:v109F* + ID_VENDOR_FROM_DATABASE=eSOL Co., Ltd + +usb:v109Fp3163* + ID_MODEL_FROM_DATABASE=Trigem Mobile SmartDisplay84 + +usb:v109Fp3164* + ID_MODEL_FROM_DATABASE=Trigem Mobile SmartDisplay121 + +usb:v10A0* + ID_VENDOR_FROM_DATABASE=Hirotech, Inc. + +usb:v10A3* + ID_VENDOR_FROM_DATABASE=Mitsubishi Materials Corp. + +usb:v10A9* + ID_VENDOR_FROM_DATABASE=SK Teletech Co., Ltd + +usb:v10A9p1102* + ID_MODEL_FROM_DATABASE=Sky Love Actually IM-U460K + +usb:v10A9p1104* + ID_MODEL_FROM_DATABASE=Sky Vega IM-A650S + +usb:v10A9p6021* + ID_MODEL_FROM_DATABASE=SIRIUS alpha + +usb:v10AA* + ID_VENDOR_FROM_DATABASE=Cables To Go + +usb:v10AB* + ID_VENDOR_FROM_DATABASE=USI Co., Ltd + +usb:v10ABp1002* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v10ABp1003* + ID_MODEL_FROM_DATABASE=BC02-EXT in DFU + +usb:v10ABp1005* + ID_MODEL_FROM_DATABASE=Bluetooth Adptr + +usb:v10ABp1006* + ID_MODEL_FROM_DATABASE=BC04-EXT in DFU + +usb:v10ABp10C5* + ID_MODEL_FROM_DATABASE=Sony-Ericsson / Samsung DataCable + +usb:v10AC* + ID_VENDOR_FROM_DATABASE=Honeywell, Inc. + +usb:v10AE* + ID_VENDOR_FROM_DATABASE=Princeton Technology Corp. + +usb:v10AF* + ID_VENDOR_FROM_DATABASE=Liebert Corp. + +usb:v10AFp0000* + ID_MODEL_FROM_DATABASE=UPS + +usb:v10AFp0001* + ID_MODEL_FROM_DATABASE=PowerSure PSA UPS + +usb:v10AFp0002* + ID_MODEL_FROM_DATABASE=PowerSure PST UPS + +usb:v10AFp0003* + ID_MODEL_FROM_DATABASE=PowerSure PSP UPS + +usb:v10AFp0004* + ID_MODEL_FROM_DATABASE=PowerSure PSI UPS + +usb:v10AFp0005* + ID_MODEL_FROM_DATABASE=UPStation GXT 2U UPS + +usb:v10AFp0006* + ID_MODEL_FROM_DATABASE=UPStation GXT UPS + +usb:v10AFp0007* + ID_MODEL_FROM_DATABASE=Nfinity Power Systems UPS + +usb:v10AFp0008* + ID_MODEL_FROM_DATABASE=PowerSure Interactive UPS + +usb:v10B5* + ID_VENDOR_FROM_DATABASE=Comodo (PLX?) + +usb:v10B5p9060* + ID_MODEL_FROM_DATABASE=Test Board + +usb:v10B8* + ID_VENDOR_FROM_DATABASE=DiBcom + +usb:v10B8p0BB8* + ID_MODEL_FROM_DATABASE=DiBcom USB DVB-T reference design (MOD300) (cold) + +usb:v10B8p0BB9* + ID_MODEL_FROM_DATABASE=DiBcom USB DVB-T reference design (MOD300) (warm) + +usb:v10B8p0BC6* + ID_MODEL_FROM_DATABASE=DiBcom USB2.0 DVB-T reference design (MOD3000P) (cold) + +usb:v10B8p0BC7* + ID_MODEL_FROM_DATABASE=DiBcom USB2.0 DVB-T reference design (MOD3000P) (warm) + +usb:v10BB* + ID_VENDOR_FROM_DATABASE=TM Technology, Inc. + +usb:v10BC* + ID_VENDOR_FROM_DATABASE=Dinging Technology Co., Ltd + +usb:v10BD* + ID_VENDOR_FROM_DATABASE=TMT Technology, Inc. + +usb:v10BDp1427* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v10BF* + ID_VENDOR_FROM_DATABASE=SmartHome + +usb:v10BFp0001* + ID_MODEL_FROM_DATABASE=SmartHome PowerLinc + +usb:v10C4* + ID_VENDOR_FROM_DATABASE=Cygnal Integrated Products, Inc. + +usb:v10C4p0002* + ID_MODEL_FROM_DATABASE=F32x USBXpress Device + +usb:v10C4p0003* + ID_MODEL_FROM_DATABASE=CommandIR + +usb:v10C4p8030* + ID_MODEL_FROM_DATABASE=K4JRG Ham Radio devices + +usb:v10C4p8044* + ID_MODEL_FROM_DATABASE=USB Debug Adapter + +usb:v10C4p804E* + ID_MODEL_FROM_DATABASE=Software Bisque Paramount ME + +usb:v10C4p80A9* + ID_MODEL_FROM_DATABASE=CP210x to UART Bridge Controller + +usb:v10C4p80CA* + ID_MODEL_FROM_DATABASE=ATM2400 Sensor Device + +usb:v10C4p813F* + ID_MODEL_FROM_DATABASE=tams EasyControl + +usb:v10C4p8149* + ID_MODEL_FROM_DATABASE=West Mountain Radio Computerized Battery Analyzer + +usb:v10C4p814A* + ID_MODEL_FROM_DATABASE=West Mountain Radio RIGblaster P&P + +usb:v10C4p814B* + ID_MODEL_FROM_DATABASE=West Mountain Radio RIGtalk + +usb:v10C4p818A* + ID_MODEL_FROM_DATABASE=Silicon Labs FM Radio Reference Design + +usb:v10C4p81E8* + ID_MODEL_FROM_DATABASE=Zephyr BioHarness + +usb:v10C4p8460* + ID_MODEL_FROM_DATABASE=Sangoma Wanpipe VoiceTime + +usb:v10C4p8461* + ID_MODEL_FROM_DATABASE=Sangoma U100 + +usb:v10C4p8477* + ID_MODEL_FROM_DATABASE=Balluff RFID Reader + +usb:v10C4p8605* + ID_MODEL_FROM_DATABASE=dilitronics ESoLUX solar lighting controller + +usb:v10C4p86BC* + ID_MODEL_FROM_DATABASE=C8051F34x AudioDelay [AD-340] + +usb:v10C4p8789* + ID_MODEL_FROM_DATABASE=C8051F34x Extender & EDID MGR [EMX-DVI] + +usb:v10C4p87BE* + ID_MODEL_FROM_DATABASE=C8051F34x HDMI Audio Extractor [EMX-HD-AUD] + +usb:v10C4p8863* + ID_MODEL_FROM_DATABASE=C8051F34x Bootloader + +usb:v10C4p8897* + ID_MODEL_FROM_DATABASE=C8051F38x HDMI Splitter [UHBX] + +usb:v10C4pEA60* + ID_MODEL_FROM_DATABASE=CP210x UART Bridge / myAVR mySmartUSB light + +usb:v10C4pEA61* + ID_MODEL_FROM_DATABASE=CP210x UART Bridge + +usb:v10C4pEA70* + ID_MODEL_FROM_DATABASE=CP210x UART Bridge + +usb:v10C4pEA80* + ID_MODEL_FROM_DATABASE=CP210x UART Bridge + +usb:v10C5* + ID_VENDOR_FROM_DATABASE=Sanei Electric, Inc. + +usb:v10C5p819A* + ID_MODEL_FROM_DATABASE=FM Radio + +usb:v10C6* + ID_VENDOR_FROM_DATABASE=Intec, Inc. + +usb:v10CB* + ID_VENDOR_FROM_DATABASE=Eratech + +usb:v10CC* + ID_VENDOR_FROM_DATABASE=GBM Connector Co., Ltd + +usb:v10CCp1101* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v10CD* + ID_VENDOR_FROM_DATABASE=Kycon, Inc. + +usb:v10CE* + ID_VENDOR_FROM_DATABASE=Silicon Labs + +usb:v10CEp000E* + ID_MODEL_FROM_DATABASE=Shinko/Sinfonia CHC-S2145 + +usb:v10CEpEA6A* + ID_MODEL_FROM_DATABASE=MobiData EDGE USB Modem + +usb:v10CF* + ID_VENDOR_FROM_DATABASE=Velleman Components, Inc. + +usb:v10CFp2011* + ID_MODEL_FROM_DATABASE=R-Engine MPEG2 encoder/decoder + +usb:v10CFp5500* + ID_MODEL_FROM_DATABASE=8055 Experiment Interface Board (address=0) + +usb:v10CFp5501* + ID_MODEL_FROM_DATABASE=8055 Experiment Interface Board (address=1) + +usb:v10CFp5502* + ID_MODEL_FROM_DATABASE=8055 Experiment Interface Board (address=2) + +usb:v10CFp5503* + ID_MODEL_FROM_DATABASE=8055 Experiment Interface Board (address=3) + +usb:v10D1* + ID_VENDOR_FROM_DATABASE=Hottinger Baldwin Measurement + +usb:v10D1p0101* + ID_MODEL_FROM_DATABASE=USB-Module for Spider8, CP32 + +usb:v10D1p0202* + ID_MODEL_FROM_DATABASE=CP22 - Communication Processor + +usb:v10D1p0301* + ID_MODEL_FROM_DATABASE=CP42 - Communication Processor + +usb:v10D4* + ID_VENDOR_FROM_DATABASE=Man Boon Manufactory, Ltd + +usb:v10D5* + ID_VENDOR_FROM_DATABASE=Uni Class Technology Co., Ltd + +usb:v10D5p0004* + ID_MODEL_FROM_DATABASE=PS/2 Converter + +usb:v10D5p5552* + ID_MODEL_FROM_DATABASE=KVM Human Interface Composite Device (Keyboard/Mouse ports) + +usb:v10D5p55A2* + ID_MODEL_FROM_DATABASE=2Port KVMSwitcher + +usb:v10D6* + ID_VENDOR_FROM_DATABASE=Actions Semiconductor Co., Ltd + +usb:v10D6p1000* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v10D6p1100* + ID_MODEL_FROM_DATABASE=MPMan MP-Ki 128 MP3 Player/Recorder + +usb:v10D6p1101* + ID_MODEL_FROM_DATABASE=D-Wave 2GB MP4 Player / AK1025 MP3/MP4 Player + +usb:v10D6p2200* + ID_MODEL_FROM_DATABASE=Acer MP-120 MP3 player + +usb:v10D6p8888* + ID_MODEL_FROM_DATABASE=ADFU Device + +usb:v10D6pFF51* + ID_MODEL_FROM_DATABASE=ADFU Device + +usb:v10D6pFF61* + ID_MODEL_FROM_DATABASE=MP4 Player + +usb:v10D6pFF66* + ID_MODEL_FROM_DATABASE=Craig 2GB MP3/Video Player + +usb:v10DE* + ID_VENDOR_FROM_DATABASE=Authenex, Inc. + +usb:v10DF* + ID_VENDOR_FROM_DATABASE=In-Win Development, Inc. + +usb:v10DFp0500* + ID_MODEL_FROM_DATABASE=iAPP CR-e500 Card reader + +usb:v10E0* + ID_VENDOR_FROM_DATABASE=Post-Op Video, Inc. + +usb:v10E1* + ID_VENDOR_FROM_DATABASE=CablePlus, Ltd + +usb:v10E2* + ID_VENDOR_FROM_DATABASE=Nada Electronics, Ltd + +usb:v10EC* + ID_VENDOR_FROM_DATABASE=Vast Technologies, Inc. + +usb:v10F0* + ID_VENDOR_FROM_DATABASE=Nexio Co., Ltd + +usb:v10F0p2002* + ID_MODEL_FROM_DATABASE=iNexio Touchscreen controller + +usb:v10F1* + ID_VENDOR_FROM_DATABASE=Importek + +usb:v10F1p1A08* + ID_MODEL_FROM_DATABASE=Internal Webcam + +usb:v10F1p1A1E* + ID_MODEL_FROM_DATABASE=Laptop Integrated Webcam 1.3M + +usb:v10F1p1A2A* + ID_MODEL_FROM_DATABASE=Laptop Integrated Webcam + +usb:v10F5* + ID_VENDOR_FROM_DATABASE=Turtle Beach + +usb:v10F5p0200* + ID_MODEL_FROM_DATABASE=Audio Advantage Roadie + +usb:v10FB* + ID_VENDOR_FROM_DATABASE=Pictos Technologies, Inc. + +usb:v10FD* + ID_VENDOR_FROM_DATABASE=Anubis Electronics, Ltd + +usb:v10FDp7E50* + ID_MODEL_FROM_DATABASE=FlyCam Usb 100 + +usb:v10FDp804D* + ID_MODEL_FROM_DATABASE=Typhoon Webshot II Webcam [zc0301] + +usb:v10FDp8050* + ID_MODEL_FROM_DATABASE=FlyCAM-USB 300 XP2 + +usb:v10FDpDE00* + ID_MODEL_FROM_DATABASE=WinFast WalkieTV WDM Capture Driver. + +usb:v10FE* + ID_VENDOR_FROM_DATABASE=Thrane & Thrane + +usb:v10FEp000C* + ID_MODEL_FROM_DATABASE=TT-3750 BGAN-XL Radio Module + +usb:v1100* + ID_VENDOR_FROM_DATABASE=VirTouch, Ltd + +usb:v1100p0001* + ID_MODEL_FROM_DATABASE=VTPlayer VTP-1 Braille Mouse + +usb:v1101* + ID_VENDOR_FROM_DATABASE=EasyPass Industrial Co., Ltd + +usb:v1101p0001* + ID_MODEL_FROM_DATABASE=FSK Electronics Super GSM Reader + +usb:v1108* + ID_VENDOR_FROM_DATABASE=Brightcom Technologies, Ltd + +usb:v110A* + ID_VENDOR_FROM_DATABASE=Moxa Technologies Co., Ltd. + +usb:v110Ap1250* + ID_MODEL_FROM_DATABASE=UPort 1250 2-Port RS-232/422/485 + +usb:v110Ap1251* + ID_MODEL_FROM_DATABASE=UPort 1250I 2-Port RS-232/422/485 with Isolation + +usb:v110Ap1410* + ID_MODEL_FROM_DATABASE=UPort 1410 4-Port RS-232 + +usb:v110Ap1450* + ID_MODEL_FROM_DATABASE=UPort 1450 4-Port RS-232/422/485 + +usb:v110Ap1451* + ID_MODEL_FROM_DATABASE=UPort 1450I 4-Port RS-232/422/485 with Isolation + +usb:v110Ap1613* + ID_MODEL_FROM_DATABASE=UPort 1610-16 16-Port RS-232 + +usb:v110Ap1618* + ID_MODEL_FROM_DATABASE=UPort 1610-8 8-Port RS-232 + +usb:v110Ap1653* + ID_MODEL_FROM_DATABASE=UPort 1650-16 16-Port RS-232/422/485 + +usb:v110Ap1658* + ID_MODEL_FROM_DATABASE=UPort 1650-8 8-Port RS-232/422/485 + +usb:v1110* + ID_VENDOR_FROM_DATABASE=Analog Devices Canada, Ltd (Allied Telesyn) + +usb:v1110p5C01* + ID_MODEL_FROM_DATABASE=Huawei MT-882 Remote NDIS Network Device + +usb:v1110p6489* + ID_MODEL_FROM_DATABASE=ADSL ETH/USB RTR + +usb:v1110p9000* + ID_MODEL_FROM_DATABASE=ADSL LAN Adapter + +usb:v1110p9001* + ID_MODEL_FROM_DATABASE=ADSL Loader + +usb:v1110p900F* + ID_MODEL_FROM_DATABASE=AT-AR215 DSL Modem + +usb:v1110p9010* + ID_MODEL_FROM_DATABASE=AT-AR215 DSL Modem + +usb:v1110p9021* + ID_MODEL_FROM_DATABASE=ADSL WAN Adapter + +usb:v1110p9022* + ID_MODEL_FROM_DATABASE=ADSL Loader + +usb:v1110p9023* + ID_MODEL_FROM_DATABASE=ADSL WAN Adapter + +usb:v1110p9024* + ID_MODEL_FROM_DATABASE=ADSL Loader + +usb:v1110p9031* + ID_MODEL_FROM_DATABASE=ADSL LAN Adapter + +usb:v1110p9032* + ID_MODEL_FROM_DATABASE=ADSL Loader + +usb:v1111* + ID_VENDOR_FROM_DATABASE=Pandora International Ltd. + +usb:v1111p8888* + ID_MODEL_FROM_DATABASE=Evolution Device + +usb:v1112* + ID_VENDOR_FROM_DATABASE=YM ELECTRIC CO., Ltd + +usb:v1113* + ID_VENDOR_FROM_DATABASE=Medion AG + +usb:v1113pA0A2* + ID_MODEL_FROM_DATABASE=Active Sync device + +usb:v111E* + ID_VENDOR_FROM_DATABASE=VSO Electric Co., Ltd + +usb:v112A* + ID_VENDOR_FROM_DATABASE=RedRat + +usb:v112Ap0001* + ID_MODEL_FROM_DATABASE=RedRat3 IR Transceiver + +usb:v112Ap0005* + ID_MODEL_FROM_DATABASE=RedRat3II IR Transceiver + +usb:v112E* + ID_VENDOR_FROM_DATABASE=Master Hill Electric Wire and Cable Co., Ltd + +usb:v112F* + ID_VENDOR_FROM_DATABASE=Cellon International, Inc. + +usb:v1130* + ID_VENDOR_FROM_DATABASE=Tenx Technology, Inc. + +usb:v1130p0002* + ID_MODEL_FROM_DATABASE=iBuddy + +usb:v1130p0202* + ID_MODEL_FROM_DATABASE=Rocket Launcher + +usb:v1130p6604* + ID_MODEL_FROM_DATABASE=MCE IR-Receiver + +usb:v1130p660C* + ID_MODEL_FROM_DATABASE=Foot Pedal/Thermometer + +usb:v1130p6806* + ID_MODEL_FROM_DATABASE=Keychain photo frame + +usb:v1130pC301* + ID_MODEL_FROM_DATABASE=Digital Photo viewer [Wallet Pix] + +usb:v1130pF211* + ID_MODEL_FROM_DATABASE=TP6911 Audio Headset + +usb:v1131* + ID_VENDOR_FROM_DATABASE=Integrated System Solution Corp. + +usb:v1131p1001* + ID_MODEL_FROM_DATABASE=KY-BT100 Bluetooth Adapter + +usb:v1131p1002* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v1131p1003* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v1131p1004* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v1132* + ID_VENDOR_FROM_DATABASE=Toshiba Corp., Digital Media Equipment [hex] + +usb:v1132p4331* + ID_MODEL_FROM_DATABASE=PDR-M4/M5/M70 Digital Camera + +usb:v1132p4332* + ID_MODEL_FROM_DATABASE=PDR-M60 Digital Camera + +usb:v1132p4333* + ID_MODEL_FROM_DATABASE=PDR-M2300/PDR-M700 + +usb:v1132p4334* + ID_MODEL_FROM_DATABASE=PDR-M65 + +usb:v1132p4335* + ID_MODEL_FROM_DATABASE=PDR-M61 + +usb:v1132p4337* + ID_MODEL_FROM_DATABASE=PDR-M11 + +usb:v1132p4338* + ID_MODEL_FROM_DATABASE=PDR-M25 + +usb:v1136* + ID_VENDOR_FROM_DATABASE=CTS Electronincs + +usb:v1136p3131* + ID_MODEL_FROM_DATABASE=CTS LS515 + +usb:v113C* + ID_VENDOR_FROM_DATABASE=Arin Tech Co., Ltd + +usb:v113D* + ID_VENDOR_FROM_DATABASE=Mapower Electronics Co., Ltd + +usb:v1141* + ID_VENDOR_FROM_DATABASE=V One Multimedia, Pte., Ltd + +usb:v1142* + ID_VENDOR_FROM_DATABASE=CyberScan Technologies, Inc. + +usb:v1145* + ID_VENDOR_FROM_DATABASE=Japan Radio Company + +usb:v1145p0001* + ID_MODEL_FROM_DATABASE=AirH PHONE AH-J3001V/J3002V + +usb:v1146* + ID_VENDOR_FROM_DATABASE=Shimane SANYO Electric Co., Ltd. + +usb:v1147* + ID_VENDOR_FROM_DATABASE=Ever Great Electric Wire and Cable Co., Ltd + +usb:v114B* + ID_VENDOR_FROM_DATABASE=Sphairon Access Systems GmbH + +usb:v114Bp0110* + ID_MODEL_FROM_DATABASE=Turbolink UB801R WLAN Adapter + +usb:v114Bp0150* + ID_MODEL_FROM_DATABASE=Turbolink UB801RE Wireless 802.11g 54Mbps Network Adapter [RTL8187] + +usb:v114C* + ID_VENDOR_FROM_DATABASE=Tinius Olsen Testing Machine Co., Inc. + +usb:v114D* + ID_VENDOR_FROM_DATABASE=Alpha Imaging Technology Corp. + +usb:v114F* + ID_VENDOR_FROM_DATABASE=Wavecom + +usb:v115B* + ID_VENDOR_FROM_DATABASE=Salix Technology Co., Ltd. + +usb:v1162* + ID_VENDOR_FROM_DATABASE=Secugen Corp. + +usb:v1163* + ID_VENDOR_FROM_DATABASE=DeLorme Publishing, Inc. + +usb:v1163p0100* + ID_MODEL_FROM_DATABASE=Earthmate GPS (orig) + +usb:v1163p0200* + ID_MODEL_FROM_DATABASE=Earthmate GPS (LT-20, LT-40) + +usb:v1163p2020* + ID_MODEL_FROM_DATABASE=Earthmate GPS (PN-40) + +usb:v1164* + ID_VENDOR_FROM_DATABASE=YUAN High-Tech Development Co., Ltd + +usb:v1164p0300* + ID_MODEL_FROM_DATABASE=ELSAVISION 460D + +usb:v1164p0601* + ID_MODEL_FROM_DATABASE=Analog TV Tuner + +usb:v1164p0900* + ID_MODEL_FROM_DATABASE=TigerBird BMP837 USB2.0 WDM Encoder + +usb:v1164p0BC7* + ID_MODEL_FROM_DATABASE=Digital TV Tuner + +usb:v1164p521B* + ID_MODEL_FROM_DATABASE=MC521A mini Card ATSC Tuner + +usb:v1164p6601* + ID_MODEL_FROM_DATABASE=Digital TV Tuner Card [RTL2832U] + +usb:v1165* + ID_VENDOR_FROM_DATABASE=Telson Electronics Co., Ltd + +usb:v1166* + ID_VENDOR_FROM_DATABASE=Bantam Interactive Technologies + +usb:v1167* + ID_VENDOR_FROM_DATABASE=Salient Systems Corp. + +usb:v1168* + ID_VENDOR_FROM_DATABASE=BizConn International Corp. + +usb:v116E* + ID_VENDOR_FROM_DATABASE=Gigastorage Corp. + +usb:v116F* + ID_VENDOR_FROM_DATABASE=Silicon 10 Technology Corp. + +usb:v116Fp0005* + ID_MODEL_FROM_DATABASE=Flash Card Reader + +usb:v116FpC108* + ID_MODEL_FROM_DATABASE=Flash Card Reader + +usb:v116FpC109* + ID_MODEL_FROM_DATABASE=Flash Card Reader + +usb:v1175* + ID_VENDOR_FROM_DATABASE=Shengyih Steel Mold Co., Ltd + +usb:v117D* + ID_VENDOR_FROM_DATABASE=Santa Electronic, Inc. + +usb:v117E* + ID_VENDOR_FROM_DATABASE=JNC, Inc. + +usb:v1182* + ID_VENDOR_FROM_DATABASE=Venture Corp., Ltd + +usb:v1183* + ID_VENDOR_FROM_DATABASE=Compaq Computer Corp. [hex] (Digital Dream ??) + +usb:v1183p0001* + ID_MODEL_FROM_DATABASE=DigitalDream l'espion XS + +usb:v1183p19C7* + ID_MODEL_FROM_DATABASE=ISDN TA + +usb:v1183p4008* + ID_MODEL_FROM_DATABASE=56k FaxModem + +usb:v1183p504A* + ID_MODEL_FROM_DATABASE=PJB-100 Personal Jukebox + +usb:v1184* + ID_VENDOR_FROM_DATABASE=Kyocera Elco Corp. + +usb:v1188* + ID_VENDOR_FROM_DATABASE=Bloomberg L.P. + +usb:v1189* + ID_VENDOR_FROM_DATABASE=Acer Communications & Multimedia + +usb:v1189p0893* + ID_MODEL_FROM_DATABASE=EP-1427X-2 Ethernet Adapter [Acer] + +usb:v118F* + ID_VENDOR_FROM_DATABASE=You Yang Technology Co., Ltd + +usb:v1190* + ID_VENDOR_FROM_DATABASE=Tripace + +usb:v1191* + ID_VENDOR_FROM_DATABASE=Loyalty Founder Enterprise Co., Ltd + +usb:v1196* + ID_VENDOR_FROM_DATABASE=Yankee Robotics, LLC + +usb:v1196p0010* + ID_MODEL_FROM_DATABASE=Trifid Camera without code + +usb:v1196p0011* + ID_MODEL_FROM_DATABASE=Trifid Camera + +usb:v1197* + ID_VENDOR_FROM_DATABASE=Technoimagia Co., Ltd + +usb:v1198* + ID_VENDOR_FROM_DATABASE=StarShine Technology Corp. + +usb:v1199* + ID_VENDOR_FROM_DATABASE=Sierra Wireless, Inc. + +usb:v1199p0019* + ID_MODEL_FROM_DATABASE=AC595U + +usb:v1199p0021* + ID_MODEL_FROM_DATABASE=AC597E + +usb:v1199p0024* + ID_MODEL_FROM_DATABASE=MC5727 CDMA modem + +usb:v1199p0110* + ID_MODEL_FROM_DATABASE=Composite Device + +usb:v1199p0112* + ID_MODEL_FROM_DATABASE=CDMA 1xEVDO PC Card, AirCard 580 + +usb:v1199p0120* + ID_MODEL_FROM_DATABASE=AC595U + +usb:v1199p0218* + ID_MODEL_FROM_DATABASE=MC5720 Wireless Modem + +usb:v1199p6467* + ID_MODEL_FROM_DATABASE=MP Series Network Adapter + +usb:v1199p6468* + ID_MODEL_FROM_DATABASE=MP Series Network Adapter + +usb:v1199p6469* + ID_MODEL_FROM_DATABASE=MP Series Network Adapter + +usb:v1199p6802* + ID_MODEL_FROM_DATABASE=MC8755 Device + +usb:v1199p6803* + ID_MODEL_FROM_DATABASE=MC8765 Device + +usb:v1199p6804* + ID_MODEL_FROM_DATABASE=MC8755 Device + +usb:v1199p6805* + ID_MODEL_FROM_DATABASE=MC8765 Device + +usb:v1199p6812* + ID_MODEL_FROM_DATABASE=MC8775 Device + +usb:v1199p6820* + ID_MODEL_FROM_DATABASE=AC875 Device + +usb:v1199p6832* + ID_MODEL_FROM_DATABASE=MC8780 Device + +usb:v1199p6833* + ID_MODEL_FROM_DATABASE=MC8781 Device + +usb:v1199p683A* + ID_MODEL_FROM_DATABASE=MC8785 Device + +usb:v1199p683C* + ID_MODEL_FROM_DATABASE=MC8790 Device + +usb:v1199p6850* + ID_MODEL_FROM_DATABASE=AirCard 880 Device + +usb:v1199p6851* + ID_MODEL_FROM_DATABASE=AirCard 881 Device + +usb:v1199p6852* + ID_MODEL_FROM_DATABASE=AirCard 880E Device + +usb:v1199p6853* + ID_MODEL_FROM_DATABASE=AirCard 881E Device + +usb:v1199p6854* + ID_MODEL_FROM_DATABASE=AirCard 885 Device + +usb:v1199p6856* + ID_MODEL_FROM_DATABASE=ATT "USB Connect 881" + +usb:v1199p6870* + ID_MODEL_FROM_DATABASE=MC8780 Device + +usb:v1199p6871* + ID_MODEL_FROM_DATABASE=MC8781 Device + +usb:v1199p6893* + ID_MODEL_FROM_DATABASE=MC8777 Device + +usb:v1199p68A3* + ID_MODEL_FROM_DATABASE=MC8700 Modem + +usb:v1199p68AA* + ID_MODEL_FROM_DATABASE=4G LTE adapter + +usb:v1199p9000* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem (QDL mode) + +usb:v1199p9001* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9002* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9003* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9004* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9005* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9006* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9007* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9008* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p9009* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v1199p900A* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v119A* + ID_VENDOR_FROM_DATABASE=ZHAN QI Technology Co., Ltd + +usb:v119B* + ID_VENDOR_FROM_DATABASE=ruwido austria GmbH + +usb:v119Bp0400* + ID_MODEL_FROM_DATABASE=Infrared Keyboard V2.01 + +usb:v11A0* + ID_VENDOR_FROM_DATABASE=Chipcon AS + +usb:v11A0pEB11* + ID_MODEL_FROM_DATABASE=CC2400EB 2.0 ZigBee Sniffer + +usb:v11A3* + ID_VENDOR_FROM_DATABASE=Technovas Co., Ltd + +usb:v11A3p8031* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v11A3p8032* + ID_MODEL_FROM_DATABASE=MP3 Player + +usb:v11AA* + ID_VENDOR_FROM_DATABASE=GlobalMedia Group, LLC + +usb:v11AAp1518* + ID_MODEL_FROM_DATABASE=iREZ K2 + +usb:v11AB* + ID_VENDOR_FROM_DATABASE=Exito Electronics Co., Ltd + +usb:v11AC* + ID_VENDOR_FROM_DATABASE=Nike + +usb:v11ACp6565* + ID_MODEL_FROM_DATABASE=FuelBand + +usb:v11B0* + ID_VENDOR_FROM_DATABASE=ATECH FLASH TECHNOLOGY + +usb:v11C5* + ID_VENDOR_FROM_DATABASE=Inmax + +usb:v11C5p0521* + ID_MODEL_FROM_DATABASE=IMT-0521 Smartcard Reader + +usb:v11DB* + ID_VENDOR_FROM_DATABASE=Topfield Co., Ltd. + +usb:v11DBp1000* + ID_MODEL_FROM_DATABASE=PVR + +usb:v11DBp1100* + ID_MODEL_FROM_DATABASE=PVR + +usb:v11E6* + ID_VENDOR_FROM_DATABASE=K.I. Technology Co. Ltd. + +usb:v11F5* + ID_VENDOR_FROM_DATABASE=Siemens AG + +usb:v11F5p0001* + ID_MODEL_FROM_DATABASE=SX1 + +usb:v11F5p0003* + ID_MODEL_FROM_DATABASE=Mobile phone USB cable + +usb:v11F5p0004* + ID_MODEL_FROM_DATABASE=X75 + +usb:v11F5p0005* + ID_MODEL_FROM_DATABASE=SXG75/EF81 + +usb:v11F5p0008* + ID_MODEL_FROM_DATABASE=UMTS/HSDPA Data Card + +usb:v11F6* + ID_VENDOR_FROM_DATABASE=Prolific + +usb:v11F6p2001* + ID_MODEL_FROM_DATABASE=Willcom WSIM + +usb:v11F7* + ID_VENDOR_FROM_DATABASE=Alcatel (?) + +usb:v11F7p02DF* + ID_MODEL_FROM_DATABASE=TD10 Mobile phone USB cable + +usb:v1203* + ID_VENDOR_FROM_DATABASE=TSC Auto ID Technology Co., Ltd + +usb:v1203p0140* + ID_MODEL_FROM_DATABASE=TTP-245C + +usb:v1209* + ID_VENDOR_FROM_DATABASE=InterBiometrics + +usb:v1209p1001* + ID_MODEL_FROM_DATABASE=USB Hub + +usb:v1209p1002* + ID_MODEL_FROM_DATABASE=USB Relais + +usb:v1209p1003* + ID_MODEL_FROM_DATABASE=IBSecureCam-P + +usb:v1209p1004* + ID_MODEL_FROM_DATABASE=IBSecureCam-O + +usb:v1209p1005* + ID_MODEL_FROM_DATABASE=IBSecureCam-N + +usb:v120E* + ID_VENDOR_FROM_DATABASE=Hudson Soft Co., Ltd + +usb:v120F* + ID_VENDOR_FROM_DATABASE=Magellan + +usb:v120Fp524E* + ID_MODEL_FROM_DATABASE=RoadMate 1475T + +usb:v120Fp5260* + ID_MODEL_FROM_DATABASE=Triton Handheld GPS Receiver (300/400/500/1500/2000) + +usb:v1210* + ID_VENDOR_FROM_DATABASE=DigiTech + +usb:v1210p0016* + ID_MODEL_FROM_DATABASE=RP500 Guitar Multi-Effects Processor + +usb:v1210p001B* + ID_MODEL_FROM_DATABASE=RP155 Guitar Multi-Effects Processor + +usb:v1210p001C* + ID_MODEL_FROM_DATABASE=RP255 Guitar Multi-Effects Processor + +usb:v121E* + ID_VENDOR_FROM_DATABASE=Jungsoft Co., Ltd + +usb:v121Ep3403* + ID_MODEL_FROM_DATABASE=Muzio JM250 Audio Player + +usb:v1223* + ID_VENDOR_FROM_DATABASE=SKYCABLE ENTERPRISE. CO., LTD. + +usb:v1228* + ID_VENDOR_FROM_DATABASE=Datapaq Limited + +usb:v1228p0012* + ID_MODEL_FROM_DATABASE=Q18 Data Logger + +usb:v1228p0015* + ID_MODEL_FROM_DATABASE=TPaq21/MPaq21 Datalogger + +usb:v1230* + ID_VENDOR_FROM_DATABASE=Chipidea-Microelectronica, S.A. + +usb:v1233* + ID_VENDOR_FROM_DATABASE=Denver Electronics + +usb:v1233p5677* + ID_MODEL_FROM_DATABASE=FUSB200 mp3 player + +usb:v1234* + ID_VENDOR_FROM_DATABASE=Brain Actuated Technologies + +usb:v1234p0000* + ID_MODEL_FROM_DATABASE=Neural Impulse Actuator Prototype 1.0 [NIA] + +usb:v1234p4321* + ID_MODEL_FROM_DATABASE=Human Interface Device + +usb:v1234pED02* + ID_MODEL_FROM_DATABASE=Emotiv EPOC Developer Headset Wireless Dongle + +usb:v1235* + ID_VENDOR_FROM_DATABASE=Novation EMS + +usb:v1235p0001* + ID_MODEL_FROM_DATABASE=ReMOTE Audio/XStation + +usb:v1235p0002* + ID_MODEL_FROM_DATABASE=Speedio + +usb:v1235p0003* + ID_MODEL_FROM_DATABASE=ReMOTE ZeRO SL + +usb:v1235p4661* + ID_MODEL_FROM_DATABASE=ReMOTE25 + +usb:v1235p8006* + ID_MODEL_FROM_DATABASE=Focusrite Scarlett 2i2 + +usb:v1241* + ID_VENDOR_FROM_DATABASE=Belkin + +usb:v1241p0504* + ID_MODEL_FROM_DATABASE=Wireless Trackball Keyboard + +usb:v1241p1111* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v1241p1122* + ID_MODEL_FROM_DATABASE=Typhoon Stream Optical Mouse USB+PS/2 + +usb:v1241p1155* + ID_MODEL_FROM_DATABASE=PS2/USB Browser Combo Mouse + +usb:v1241p1166* + ID_MODEL_FROM_DATABASE=MI-2150 Trust Mouse + +usb:v1241p1177* + ID_MODEL_FROM_DATABASE=F8E842-DL Mouse + +usb:v1241p1503* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v1241p1603* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v1241pF767* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v124A* + ID_VENDOR_FROM_DATABASE=AirVast + +usb:v124Ap168B* + ID_MODEL_FROM_DATABASE=PRISM3 WLAN Adapter + +usb:v124Ap4017* + ID_MODEL_FROM_DATABASE=PC-Chips 802.11b Adapter + +usb:v124Ap4023* + ID_MODEL_FROM_DATABASE=WM168g 802.11bg Wireless Adapter [Intersil ISL3886] + +usb:v124Ap4025* + ID_MODEL_FROM_DATABASE=IOGear GWU513 v2 802.11bg Wireless Adapter [Intersil ISL3887] + +usb:v124B* + ID_VENDOR_FROM_DATABASE=Nyko (Honey Bee) + +usb:v124Bp4D01* + ID_MODEL_FROM_DATABASE=Airflo EX Joystick + +usb:v124C* + ID_VENDOR_FROM_DATABASE=MXI - Memory Experts International, Inc. + +usb:v124Cp3200* + ID_MODEL_FROM_DATABASE=Stealth MXP 1GB + +usb:v125C* + ID_VENDOR_FROM_DATABASE=Apogee Inc. + +usb:v125Cp0010* + ID_MODEL_FROM_DATABASE=Alta series CCD + +usb:v125F* + ID_VENDOR_FROM_DATABASE=A-DATA Technology Co., Ltd. + +usb:v125Fp312A* + ID_MODEL_FROM_DATABASE=Superior S102 + +usb:v125Fp312B* + ID_MODEL_FROM_DATABASE=Superior S102 Pro + +usb:v125FpA91A* + ID_MODEL_FROM_DATABASE=Portable HDD CH91 + +usb:v125FpC08A* + ID_MODEL_FROM_DATABASE=C008 Flash Drive + +usb:v125FpC81A* + ID_MODEL_FROM_DATABASE=Flash drive + +usb:v125FpC93A* + ID_MODEL_FROM_DATABASE=4GB Pen Drive + +usb:v125FpC96A* + ID_MODEL_FROM_DATABASE=C906 Flash Drive + +usb:v1260* + ID_VENDOR_FROM_DATABASE=Standard Microsystems Corp. + +usb:v1260pEE22* + ID_MODEL_FROM_DATABASE=SMC2862W-G v3 EZ Connect 802.11g Adapter [Intersil ISL3887] + +usb:v1264* + ID_VENDOR_FROM_DATABASE=Covidien Energy-based Devices + +usb:v1266* + ID_VENDOR_FROM_DATABASE=Pirelli Broadband Solutions + +usb:v1266p6302* + ID_MODEL_FROM_DATABASE=Fastweb DRG A226M ADSL Router + +usb:v1267* + ID_VENDOR_FROM_DATABASE=Logic3 / SpectraVideo plc + +usb:v1267p0103* + ID_MODEL_FROM_DATABASE=G-720 Keyboard + +usb:v1267p0201* + ID_MODEL_FROM_DATABASE=A4Tech SWOP-3 Mouse + +usb:v1267p0210* + ID_MODEL_FROM_DATABASE=LG Optical Mouse 3D-310 + +usb:v1267pA001* + ID_MODEL_FROM_DATABASE=JP260 PC Game Pad + +usb:v1267pC002* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse + +usb:v126C* + ID_VENDOR_FROM_DATABASE=Aristocrat Technologies + +usb:v126D* + ID_VENDOR_FROM_DATABASE=Bel Stewart + +usb:v126E* + ID_VENDOR_FROM_DATABASE=Strobe Data, Inc. + +usb:v126F* + ID_VENDOR_FROM_DATABASE=TwinMOS + +usb:v126Fp0163* + ID_MODEL_FROM_DATABASE=Storage device (2gB thumb drive) + +usb:v126Fp1325* + ID_MODEL_FROM_DATABASE=Mobile Disk + +usb:v126Fp2168* + ID_MODEL_FROM_DATABASE=Mobile Disk III + +usb:v126FpA006* + ID_MODEL_FROM_DATABASE=G240 802.11bg + +usb:v1274* + ID_VENDOR_FROM_DATABASE=Ensoniq + +usb:v1275* + ID_VENDOR_FROM_DATABASE=Xaxero Marine Software Engineering, Ltd. + +usb:v1275p0002* + ID_MODEL_FROM_DATABASE=WeatherFax 2000 Demodulator + +usb:v1275p0080* + ID_MODEL_FROM_DATABASE=SkyEye Weather Satellite Receiver + +usb:v1278* + ID_VENDOR_FROM_DATABASE=Starlight Xpress + +usb:v1278p0105* + ID_MODEL_FROM_DATABASE=SXV-M5 + +usb:v1278p0107* + ID_MODEL_FROM_DATABASE=SXV-M7 + +usb:v1278p0109* + ID_MODEL_FROM_DATABASE=SXV-M9 + +usb:v1278p0110* + ID_MODEL_FROM_DATABASE=SXVF-H16 + +usb:v1278p0115* + ID_MODEL_FROM_DATABASE=SXVF-H5 + +usb:v1278p0119* + ID_MODEL_FROM_DATABASE=SXV-H9 + +usb:v1278p0135* + ID_MODEL_FROM_DATABASE=SXVF-H35 + +usb:v1278p0136* + ID_MODEL_FROM_DATABASE=SXVF-H36 + +usb:v1278p0200* + ID_MODEL_FROM_DATABASE=SXV interface for paraller MX cameras + +usb:v1278p0305* + ID_MODEL_FROM_DATABASE=SXV-M5C + +usb:v1278p0307* + ID_MODEL_FROM_DATABASE=SXV-M7C + +usb:v1278p0319* + ID_MODEL_FROM_DATABASE=SXV-H9C + +usb:v1278p0325* + ID_MODEL_FROM_DATABASE=SXV-M25C + +usb:v1278p0326* + ID_MODEL_FROM_DATABASE=SXVR-M26C + +usb:v1278p0507* + ID_MODEL_FROM_DATABASE=Lodestar autoguider + +usb:v1278p0517* + ID_MODEL_FROM_DATABASE=CoStar + +usb:v1283* + ID_VENDOR_FROM_DATABASE=zebris Medical GmbH + +usb:v1283p0100* + ID_MODEL_FROM_DATABASE=USB-RS232 Adaptor + +usb:v1283p0110* + ID_MODEL_FROM_DATABASE=CMS20 + +usb:v1283p0111* + ID_MODEL_FROM_DATABASE=CMS 10 + +usb:v1283p0112* + ID_MODEL_FROM_DATABASE=CMS 05 + +usb:v1283p0114* + ID_MODEL_FROM_DATABASE=ARCUS digma PC-Interface + +usb:v1283p0115* + ID_MODEL_FROM_DATABASE=SAM Axioquick recorder + +usb:v1283p0116* + ID_MODEL_FROM_DATABASE=SAM Axioquick recorder + +usb:v1283p0120* + ID_MODEL_FROM_DATABASE=emed-X + +usb:v1283p0121* + ID_MODEL_FROM_DATABASE=emed-AT + +usb:v1283p0130* + ID_MODEL_FROM_DATABASE=PDM + +usb:v1283p0150* + ID_MODEL_FROM_DATABASE=CMS10GI (Golf) + +usb:v1286* + ID_VENDOR_FROM_DATABASE=Marvell Semiconductor, Inc. + +usb:v1286p1FAB* + ID_MODEL_FROM_DATABASE=88W8338 [Libertas] 802.11g + +usb:v1286p2001* + ID_MODEL_FROM_DATABASE=88W8388 802.11a/b/g WLAN + +usb:v1286p2006* + ID_MODEL_FROM_DATABASE=88W8362 802.11n WLAN + +usb:v1286p8001* + ID_MODEL_FROM_DATABASE=BLOB boot loader firmware + +usb:v1291* + ID_VENDOR_FROM_DATABASE=Qualcomm Flarion Technologies, Inc. / Leadtek Research, Inc. + +usb:v1291p0010* + ID_MODEL_FROM_DATABASE=FDM 2xxx Flash-OFDM modem + +usb:v1291p0011* + ID_MODEL_FROM_DATABASE=LR7F06/LR7F14 Flash-OFDM modem + +usb:v1292* + ID_VENDOR_FROM_DATABASE=Innomedia + +usb:v1292p0258* + ID_MODEL_FROM_DATABASE=Creative Labs VoIP Blaster + +usb:v1293* + ID_VENDOR_FROM_DATABASE=Belkin Components [hex] + +usb:v1293p0002* + ID_MODEL_FROM_DATABASE=F5U002 Parallel Port [uss720] + +usb:v1293p2101* + ID_MODEL_FROM_DATABASE=104-key keyboard + +usb:v1294* + ID_VENDOR_FROM_DATABASE=RISO KAGAKU CORP. + +usb:v129B* + ID_VENDOR_FROM_DATABASE=CyberTAN Technology + +usb:v129Bp160B* + ID_MODEL_FROM_DATABASE=Siemens S30853-S1031-R351 802.11g Wireless Adapter [Atheros AR5523] + +usb:v129Bp160C* + ID_MODEL_FROM_DATABASE=Siemens S30853-S1038-R351 802.11g Wireless Adapter [Atheros AR5523] + +usb:v129Bp1666* + ID_MODEL_FROM_DATABASE=TG54USB 802.11bg + +usb:v129Bp1667* + ID_MODEL_FROM_DATABASE=802.11bg + +usb:v129Bp1828* + ID_MODEL_FROM_DATABASE=Gigaset USB Adapter 300 + +usb:v12A7* + ID_VENDOR_FROM_DATABASE=Trendchip Technologies Corp. + +usb:v12AB* + ID_VENDOR_FROM_DATABASE=Honey Bee Electronic International Ltd. + +usb:v12B8* + ID_VENDOR_FROM_DATABASE=Zhejiang Xinya Electronic Technology Co., Ltd. + +usb:v12B9* + ID_VENDOR_FROM_DATABASE=E28 + +usb:v12BA* + ID_VENDOR_FROM_DATABASE=Licensed by Sony Computer Entertainment America + +usb:v12BAp00FF* + ID_MODEL_FROM_DATABASE=Rocksmith Guitar Adapter + +usb:v12BAp0100* + ID_MODEL_FROM_DATABASE=RedOctane Guitar for PlayStation(R)3 + +usb:v12BAp0120* + ID_MODEL_FROM_DATABASE=RedOctane Drum Kit for PlayStation(R)3 + +usb:v12BAp0200* + ID_MODEL_FROM_DATABASE=Harmonix Guitar for PlayStation(R)3 + +usb:v12BAp0210* + ID_MODEL_FROM_DATABASE=Harmonix Drum Kit for PlayStation(R)3 + +usb:v12C4* + ID_VENDOR_FROM_DATABASE=Autocue Group Ltd + +usb:v12C4p0006* + ID_MODEL_FROM_DATABASE=Teleprompter Two-button Hand Control (v1) + +usb:v12C4p0008* + ID_MODEL_FROM_DATABASE=Teleprompter Foot Control (v1) + +usb:v12D1* + ID_VENDOR_FROM_DATABASE=Huawei Technologies Co., Ltd. + +usb:v12D1p1001* + ID_MODEL_FROM_DATABASE=E169/E620/E800 HSDPA Modem + +usb:v12D1p1003* + ID_MODEL_FROM_DATABASE=E220 HSDPA Modem / E230/E270/E870 HSDPA/HSUPA Modem + +usb:v12D1p1004* + ID_MODEL_FROM_DATABASE=E220 (bis) + +usb:v12D1p1009* + ID_MODEL_FROM_DATABASE=U120 + +usb:v12D1p1010* + ID_MODEL_FROM_DATABASE=ETS2252+ CDMA Fixed Wireless Terminal + +usb:v12D1p1021* + ID_MODEL_FROM_DATABASE=U8520 + +usb:v12D1p1035* + ID_MODEL_FROM_DATABASE=U8120 + +usb:v12D1p1037* + ID_MODEL_FROM_DATABASE=Ideos + +usb:v12D1p1038* + ID_MODEL_FROM_DATABASE=Ideos (debug mode) + +usb:v12D1p1039* + ID_MODEL_FROM_DATABASE=Ideos (tethering mode) + +usb:v12D1p1406* + ID_MODEL_FROM_DATABASE=E1750 + +usb:v12D1p140B* + ID_MODEL_FROM_DATABASE=EC1260 Wireless Data Modem HSD USB Card + +usb:v12D1p140C* + ID_MODEL_FROM_DATABASE=E180v + +usb:v12D1p1412* + ID_MODEL_FROM_DATABASE=EC168c + +usb:v12D1p1436* + ID_MODEL_FROM_DATABASE=E173 3G Modem (modem-mode) + +usb:v12D1p1446* + ID_MODEL_FROM_DATABASE=E1552/E1800/E173 (HSPA modem) + +usb:v12D1p1465* + ID_MODEL_FROM_DATABASE=K3765 HSPA + +usb:v12D1p14C3* + ID_MODEL_FROM_DATABASE=K5005 Vodafone LTE/UMTS/GSM Modem/Networkcard + +usb:v12D1p14C8* + ID_MODEL_FROM_DATABASE=K5005 Vodafone LTE/UMTS/GSM MOdem/Networkcard + +usb:v12D1p14C9* + ID_MODEL_FROM_DATABASE=K3770 3G Modem + +usb:v12D1p14CF* + ID_MODEL_FROM_DATABASE=K3772 + +usb:v12D1p14D1* + ID_MODEL_FROM_DATABASE=K3770 3G Modem (Mass Storage Mode) + +usb:v12D1p14F1* + ID_MODEL_FROM_DATABASE=Gobi 3000 HSPA+ Modem + +usb:v12D1p1501* + ID_MODEL_FROM_DATABASE=Pulse + +usb:v12D1p1505* + ID_MODEL_FROM_DATABASE=E398 LTE/UMTS/GSM Modem/Networkcard + +usb:v12D1p1506* + ID_MODEL_FROM_DATABASE=Modem/Networkcard + +usb:v12D1p150A* + ID_MODEL_FROM_DATABASE=E398 LTE/UMTS/GSM Modem/Networkcard + +usb:v12D1p1520* + ID_MODEL_FROM_DATABASE=K3765 HSPA + +usb:v12D1p1521* + ID_MODEL_FROM_DATABASE=K4505 HSPA+ + +usb:v12D1p155A* + ID_MODEL_FROM_DATABASE=R205 Mobile WiFi (CD-ROM mode) + +usb:v12D1p1805* + ID_MODEL_FROM_DATABASE=AT&T Go Phone U2800A phone + +usb:v12D1p1C05* + ID_MODEL_FROM_DATABASE=E173s 3G broadband stick (modem on) + +usb:v12D1p1C0B* + ID_MODEL_FROM_DATABASE=E173s 3G broadband stick (modem off) + +usb:v12D1p1C20* + ID_MODEL_FROM_DATABASE=R205 Mobile WiFi (Charging) + +usb:v12D1p1D50* + ID_MODEL_FROM_DATABASE=ET302s TD-SCDMA/TD-HSDPA Mobile Broadband + +usb:v12D1p380B* + ID_MODEL_FROM_DATABASE=WiMAX USB modem(s) + +usb:v12D2* + ID_VENDOR_FROM_DATABASE=LINE TECH INDUSTRIAL CO., LTD. + +usb:v12D6* + ID_VENDOR_FROM_DATABASE=EMS Dr. Thomas Wuensche + +usb:v12D6p0444* + ID_MODEL_FROM_DATABASE=CPC-USB/ARM7 + +usb:v12D6p0888* + ID_MODEL_FROM_DATABASE=CPC-USB/M16C + +usb:v12D7* + ID_VENDOR_FROM_DATABASE=BETTER WIRE FACTORY CO., LTD. + +usb:v12E6* + ID_VENDOR_FROM_DATABASE=Waldorf Music GmbH + +usb:v12E6p0013* + ID_MODEL_FROM_DATABASE=Blofeld + +usb:v12EF* + ID_VENDOR_FROM_DATABASE=Tapwave, Inc. + +usb:v12EFp0100* + ID_MODEL_FROM_DATABASE=Tapwave Handheld [Tapwave Zodiac] + +usb:v12F5* + ID_VENDOR_FROM_DATABASE=Dynamic System Electronics Corp. + +usb:v12F7* + ID_VENDOR_FROM_DATABASE=Memorex Products, Inc. + +usb:v12F7p1A00* + ID_MODEL_FROM_DATABASE=TD Classic 003B + +usb:v12F7p1E23* + ID_MODEL_FROM_DATABASE=TravelDrive 2007 Flash Drive + +usb:v12FD* + ID_VENDOR_FROM_DATABASE=AIN Comm. Technology Co., Ltd + +usb:v12FDp1001* + ID_MODEL_FROM_DATABASE=AWU2000b 802.11b Stick + +usb:v12FF* + ID_VENDOR_FROM_DATABASE=Fascinating Electronics, Inc. + +usb:v12FFp0101* + ID_MODEL_FROM_DATABASE=Advanced RC Servo Controller + +usb:v1307* + ID_VENDOR_FROM_DATABASE=Transcend Information, Inc. + +usb:v1307p0163* + ID_MODEL_FROM_DATABASE=256MB/512MB/1GB Flash Drive + +usb:v1307p0165* + ID_MODEL_FROM_DATABASE=2GB/4GB Flash Drive + +usb:v1307p0190* + ID_MODEL_FROM_DATABASE=Ut190 8 GB Flash Drive with MicroSD reader + +usb:v1307p0310* + ID_MODEL_FROM_DATABASE=SD/MicroSD CardReader [hama] + +usb:v1307p0330* + ID_MODEL_FROM_DATABASE=63-in-1 Multi-Card Reader/Writer + +usb:v1307p0361* + ID_MODEL_FROM_DATABASE=CR-75: 51-in-1 Card Reader/Writer [Sakar] + +usb:v1307p1169* + ID_MODEL_FROM_DATABASE=TS2GJF210 JetFlash 210 2GB + +usb:v1307p1171* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v1308* + ID_VENDOR_FROM_DATABASE=Shuttle, Inc. + +usb:v1308p0003* + ID_MODEL_FROM_DATABASE=VFD Module + +usb:v1308pC001* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1310* + ID_VENDOR_FROM_DATABASE=Roper + +usb:v1310p0001* + ID_MODEL_FROM_DATABASE=Class 1 Bluetooth Dongle + +usb:v1312* + ID_VENDOR_FROM_DATABASE=ICS Electronics + +usb:v1313* + ID_VENDOR_FROM_DATABASE=ThorLabs + +usb:v1313p8070* + ID_MODEL_FROM_DATABASE=PM100D + +usb:v131D* + ID_VENDOR_FROM_DATABASE=Natural Point + +usb:v131Dp0155* + ID_MODEL_FROM_DATABASE=TrackIR 3 Pro Head Tracker + +usb:v131Dp0156* + ID_MODEL_FROM_DATABASE=TrackIR 4 Pro Head Tracker + +usb:v132A* + ID_VENDOR_FROM_DATABASE=Envara Inc. + +usb:v132Ap1502* + ID_MODEL_FROM_DATABASE=WiND 802.11abg / 802.11bg WLAN + +usb:v132B* + ID_VENDOR_FROM_DATABASE=Konica Minolta + +usb:v132Bp0000* + ID_MODEL_FROM_DATABASE=Dimage A2 Camera + +usb:v132Bp0001* + ID_MODEL_FROM_DATABASE=Minolta DiMAGE A2 (ptp) + +usb:v132Bp0003* + ID_MODEL_FROM_DATABASE=Dimage Xg Camera + +usb:v132Bp0006* + ID_MODEL_FROM_DATABASE=Dimage Z2 Camera + +usb:v132Bp0007* + ID_MODEL_FROM_DATABASE=Minolta DiMAGE Z2 (PictBridge mode) + +usb:v132Bp0008* + ID_MODEL_FROM_DATABASE=Dimage X21 Camera + +usb:v132Bp000A* + ID_MODEL_FROM_DATABASE=Dimage Scan Dual IV AF-3200 (2891) + +usb:v132Bp000B* + ID_MODEL_FROM_DATABASE=Dimage Z10 Camera + +usb:v132Bp000D* + ID_MODEL_FROM_DATABASE=Dimage X50 Camera [storage?] + +usb:v132Bp000F* + ID_MODEL_FROM_DATABASE=Dimage X50 Camera [p2p?] + +usb:v132Bp0010* + ID_MODEL_FROM_DATABASE=Dimage G600 Camera + +usb:v132Bp0012* + ID_MODEL_FROM_DATABASE=Dimage Scan Elite 5400 II (2892) + +usb:v132Bp0013* + ID_MODEL_FROM_DATABASE=Dimage X31 Camera + +usb:v132Bp0015* + ID_MODEL_FROM_DATABASE=Dimage G530 Camera + +usb:v132Bp0017* + ID_MODEL_FROM_DATABASE=Dimage Z3 Camera + +usb:v132Bp0018* + ID_MODEL_FROM_DATABASE=Minolta DiMAGE Z3 (PictBridge mode) + +usb:v132Bp0019* + ID_MODEL_FROM_DATABASE=Dimage A200 Camera + +usb:v132Bp0021* + ID_MODEL_FROM_DATABASE=Dimage Z5 Camera + +usb:v132Bp0022* + ID_MODEL_FROM_DATABASE=Minolta DiMAGE Z5 (PictBridge mode) + +usb:v132Bp002C* + ID_MODEL_FROM_DATABASE=Dynax 5D camera + +usb:v132Bp2001* + ID_MODEL_FROM_DATABASE=Magicolor 2400w + +usb:v132Bp2004* + ID_MODEL_FROM_DATABASE=Magicolor 5430DL + +usb:v132Bp2005* + ID_MODEL_FROM_DATABASE=Magicolor 2430 DL + +usb:v132Bp2029* + ID_MODEL_FROM_DATABASE=Magicolor 5440DL + +usb:v132Bp2030* + ID_MODEL_FROM_DATABASE=PagePro 1350E(N) + +usb:v132Bp2033* + ID_MODEL_FROM_DATABASE=PagePro 1400W + +usb:v132Bp2043* + ID_MODEL_FROM_DATABASE=Magicolor 2530DL + +usb:v132Bp2045* + ID_MODEL_FROM_DATABASE=Magicolor 2500W + +usb:v132Bp2049* + ID_MODEL_FROM_DATABASE=Magicolor 2490MF + +usb:v1342* + ID_VENDOR_FROM_DATABASE=Mobility + +usb:v1342p0200* + ID_MODEL_FROM_DATABASE=EasiDock 200 Hub + +usb:v1342p0201* + ID_MODEL_FROM_DATABASE=EasiDock 200 Keyboard and Mouse Port + +usb:v1342p0202* + ID_MODEL_FROM_DATABASE=EasiDock 200 Serial Port + +usb:v1342p0203* + ID_MODEL_FROM_DATABASE=EasiDock 200 Printer Port + +usb:v1342p0204* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v1342p0304* + ID_MODEL_FROM_DATABASE=EasiDock Ethernet + +usb:v1345* + ID_VENDOR_FROM_DATABASE=Sino Lite Technology Corp. + +usb:v1345p001C* + ID_MODEL_FROM_DATABASE=Xbox Controller Hub + +usb:v1345p6006* + ID_MODEL_FROM_DATABASE=Defender Wireless Controller + +usb:v1347* + ID_VENDOR_FROM_DATABASE=Moravian Instruments + +usb:v1347p0400* + ID_MODEL_FROM_DATABASE=G2CCD USB 1.1 obsolete + +usb:v1347p0401* + ID_MODEL_FROM_DATABASE=G2CCD-S with Sony ICX285 CCD + +usb:v1347p0402* + ID_MODEL_FROM_DATABASE=G2CCD2 + +usb:v1347p0403* + ID_MODEL_FROM_DATABASE=G2/G3CCD-I KAI CCD + +usb:v1347p0404* + ID_MODEL_FROM_DATABASE=G2/G3/G4 CCD-F KAF CCD + +usb:v1347p0410* + ID_MODEL_FROM_DATABASE=G1-0400 CCD + +usb:v1347p0411* + ID_MODEL_FROM_DATABASE=G1-0800 CCD + +usb:v1347p0412* + ID_MODEL_FROM_DATABASE=G1-0300 CCD + +usb:v1347p0413* + ID_MODEL_FROM_DATABASE=G1-2000 CCD + +usb:v1347p0414* + ID_MODEL_FROM_DATABASE=G1-1400 CCD + +usb:v1348* + ID_VENDOR_FROM_DATABASE=Katsuragawa Electric Co., Ltd. + +usb:v134C* + ID_VENDOR_FROM_DATABASE=PanJit International Inc. + +usb:v134Cp0001* + ID_MODEL_FROM_DATABASE=Touch Panel Controller + +usb:v134Cp0002* + ID_MODEL_FROM_DATABASE=Touch Panel Controller + +usb:v134Cp0003* + ID_MODEL_FROM_DATABASE=Touch Panel Controller + +usb:v134Cp0004* + ID_MODEL_FROM_DATABASE=Touch Panel Controller + +usb:v134E* + ID_VENDOR_FROM_DATABASE=Digby's Bitpile, Inc. DBA D Bit + +usb:v1357* + ID_VENDOR_FROM_DATABASE=P&E Microcomputer Systems + +usb:v1357p0503* + ID_MODEL_FROM_DATABASE=USB-ML-12 HCS08/HCS12 Multilink + +usb:v1357p0504* + ID_MODEL_FROM_DATABASE=DEMOJM + +usb:v1366* + ID_VENDOR_FROM_DATABASE=SEGGER + +usb:v1366p0101* + ID_MODEL_FROM_DATABASE=J-Link ARM + +usb:v136B* + ID_VENDOR_FROM_DATABASE=STEC + +usb:v1370* + ID_VENDOR_FROM_DATABASE=Swissbit + +usb:v1370p0323* + ID_MODEL_FROM_DATABASE=Swissmemory cirrusWHITE + +usb:v1370p6828* + ID_MODEL_FROM_DATABASE=Victorinox Flash Drive + +usb:v1371* + ID_VENDOR_FROM_DATABASE=CNet Technology Inc. + +usb:v1371p0001* + ID_MODEL_FROM_DATABASE=CNUSB-611AR Wireless Adapter-G [AT76C503] + +usb:v1371p0002* + ID_MODEL_FROM_DATABASE=CNUSB-611AR Wireless Adapter-G [AT76C503] (FiberLine WL-240U) + +usb:v1371p0013* + ID_MODEL_FROM_DATABASE=CNUSB-611 Wireless Adapter [AT76C505] + +usb:v1371p0014* + ID_MODEL_FROM_DATABASE=CNUSB-611 Wireless Adapter [AT76C505] (FiberLine WL-240U) + +usb:v1371p5743* + ID_MODEL_FROM_DATABASE=CNUSB-611 (D) Wireless Adapter [AT76C503] + +usb:v1371p9022* + ID_MODEL_FROM_DATABASE=CWD-854 [RT2573] + +usb:v1371p9032* + ID_MODEL_FROM_DATABASE=CWD-854 rev F + +usb:v1371p9401* + ID_MODEL_FROM_DATABASE=CWD-854 Wireless 802.11g 54Mbps Network Adapter [RTL8187] + +usb:v1376* + ID_VENDOR_FROM_DATABASE=Vimtron Electronics Co., Ltd. + +usb:v137B* + ID_VENDOR_FROM_DATABASE=SCAPS GmbH + +usb:v137Bp0002* + ID_MODEL_FROM_DATABASE=SCAPS USC-2 Scanner Controller + +usb:v1385* + ID_VENDOR_FROM_DATABASE=Netgear, Inc + +usb:v1385p4250* + ID_MODEL_FROM_DATABASE=WG111T + +usb:v1385p4251* + ID_MODEL_FROM_DATABASE=WG111T (no firmware) + +usb:v1385p5F00* + ID_MODEL_FROM_DATABASE=WPN111 RangeMax(TM) Wireless USB 2.0 Adapter + +usb:v1385p5F01* + ID_MODEL_FROM_DATABASE=WPN111 (no firmware) + +usb:v1385p5F02* + ID_MODEL_FROM_DATABASE=WPN111 (no firmware) + +usb:v1385p6E00* + ID_MODEL_FROM_DATABASE=WPNT121 802.11g 240Mbps Wireless Adapter [Airgo AGN300] + +usb:v138A* + ID_VENDOR_FROM_DATABASE=Validity Sensors, Inc. + +usb:v138Ap0001* + ID_MODEL_FROM_DATABASE=VFS101 Fingerprint Reader + +usb:v138Ap0005* + ID_MODEL_FROM_DATABASE=VFS301 Fingerprint Reader + +usb:v138Ap0007* + ID_MODEL_FROM_DATABASE=VFS451 Fingerprint Reader + +usb:v138Ap0008* + ID_MODEL_FROM_DATABASE=VFS300 Fingerprint Reader + +usb:v138Ap0011* + ID_MODEL_FROM_DATABASE=VFS5011 Fingerprint Reader + +usb:v138Ap0018* + ID_MODEL_FROM_DATABASE=Fingerprint scanner + +usb:v138Ap003C* + ID_MODEL_FROM_DATABASE=VFS471 Fingerprint Reader + +usb:v138Ap003D* + ID_MODEL_FROM_DATABASE=VFS491 + +usb:v138E* + ID_VENDOR_FROM_DATABASE=Jungo LTD + +usb:v138Ep9000* + ID_MODEL_FROM_DATABASE=Raisonance S.A. STM32 ARM evaluation board + +usb:v1390* + ID_VENDOR_FROM_DATABASE=TOMTOM B.V. + +usb:v1390p0001* + ID_MODEL_FROM_DATABASE=GO 520 T/GO 630/ONE XL (v9) + +usb:v1391* + ID_VENDOR_FROM_DATABASE=IdealTEK, Inc. + +usb:v1391p1000* + ID_MODEL_FROM_DATABASE=URTC-1000 + +usb:v1395* + ID_VENDOR_FROM_DATABASE=Sennheiser Communications + +usb:v1395p3556* + ID_MODEL_FROM_DATABASE=USB Headset + +usb:v1397* + ID_VENDOR_FROM_DATABASE=BEHRINGER International GmbH + +usb:v1397p00BC* + ID_MODEL_FROM_DATABASE=BCF2000 + +usb:v1398* + ID_VENDOR_FROM_DATABASE=Q-tec + +usb:v1398p2103* + ID_MODEL_FROM_DATABASE=USB 2.0 Storage Device + +usb:v13AD* + ID_VENDOR_FROM_DATABASE=Baltech + +usb:v13ADp9999* + ID_MODEL_FROM_DATABASE=Card reader + +usb:v13B0* + ID_VENDOR_FROM_DATABASE=PerkinElmer Optoelectronics + +usb:v13B0p000A* + ID_MODEL_FROM_DATABASE=Alesis Photon X25 MIDI Controller + +usb:v13B1* + ID_VENDOR_FROM_DATABASE=Linksys + +usb:v13B1p000A* + ID_MODEL_FROM_DATABASE=WUSB54G v2 802.11g Adapter [Intersil ISL3887] + +usb:v13B1p000B* + ID_MODEL_FROM_DATABASE=WUSB11 v4.0 802.11b Adapter [ALi M4301] + +usb:v13B1p000C* + ID_MODEL_FROM_DATABASE=WUSB54AG 802.11a/g Adapter [Intersil ISL3887] + +usb:v13B1p000D* + ID_MODEL_FROM_DATABASE=WUSB54G v4 802.11g Adapter [Ralink RT2500USB] + +usb:v13B1p000E* + ID_MODEL_FROM_DATABASE=WUSB54GS v1 802.11g Adapter [Broadcom 4320 USB] + +usb:v13B1p0011* + ID_MODEL_FROM_DATABASE=WUSB54GP v4.0 802.11g Adapter [Ralink RT2500USB] + +usb:v13B1p0014* + ID_MODEL_FROM_DATABASE=WUSB54GS v2 802.11g Adapter [Broadcom 4320 USB] + +usb:v13B1p0018* + ID_MODEL_FROM_DATABASE=USB200M 10/100 Ethernet Adapter + +usb:v13B1p001A* + ID_MODEL_FROM_DATABASE=HU200TS Wireless Adapter + +usb:v13B1p001E* + ID_MODEL_FROM_DATABASE=WUSBF54G 802.11bg + +usb:v13B1p0020* + ID_MODEL_FROM_DATABASE=WUSB54GC v1 802.11g Adapter [Ralink RT73] + +usb:v13B1p0022* + ID_MODEL_FROM_DATABASE=WUSB54GX4 802.11g 240Mbps Wireless Adapter [Airgo AGN300] + +usb:v13B1p0023* + ID_MODEL_FROM_DATABASE=WUSB54GR + +usb:v13B1p0024* + ID_MODEL_FROM_DATABASE=WUSBF54G v1.1 802.11bg + +usb:v13B1p0026* + ID_MODEL_FROM_DATABASE=WUSB54GSC v1 802.11g Adapter [Broadcom 4320 USB] + +usb:v13B1p0028* + ID_MODEL_FROM_DATABASE=WUSB200 802.11g Adapter [Ralink RT2671] + +usb:v13B1p0029* + ID_MODEL_FROM_DATABASE=WUSB300N 802.11bgn Wireless Adapter [Marvell 88W8362+88W8060] + +usb:v13B1p002F* + ID_MODEL_FROM_DATABASE=AE1000 v1 802.11n [Ralink RT3572] + +usb:v13B1p0031* + ID_MODEL_FROM_DATABASE=AM10 v1 802.11n [Ralink RT3072] + +usb:v13B1p0039* + ID_MODEL_FROM_DATABASE=AE1200 802.11bgn Wireless Adapter [Broadcom BCM43235] + +usb:v13B1p003A* + ID_MODEL_FROM_DATABASE=AE2500 802.11abgn Wireless Adapter [Broadcom BCM43236] + +usb:v13B1p13B1* + ID_MODEL_FROM_DATABASE=WUSB200: Wireless-G Business Network Adapter with Rangebooster + +usb:v13B2* + ID_VENDOR_FROM_DATABASE=Alesis + +usb:v13B2p0030* + ID_MODEL_FROM_DATABASE=Multimix 8 + +usb:v13B3* + ID_VENDOR_FROM_DATABASE=Nippon Dics Co., Ltd. + +usb:v13BA* + ID_VENDOR_FROM_DATABASE=PCPlay + +usb:v13BAp0001* + ID_MODEL_FROM_DATABASE=König Electronic CMP-KEYPAD12 Numeric Keypad + +usb:v13BAp0017* + ID_MODEL_FROM_DATABASE=PS/2 Keyboard+Mouse Adapter + +usb:v13BAp0018* + ID_MODEL_FROM_DATABASE=Barcode PCP-BCG4209 + +usb:v13BE* + ID_VENDOR_FROM_DATABASE=Ricoh Printing Systems, Ltd. + +usb:v13CA* + ID_VENDOR_FROM_DATABASE=JyeTai Precision Industrial Co., Ltd. + +usb:v13CF* + ID_VENDOR_FROM_DATABASE=Wisair Ltd. + +usb:v13CFp1200* + ID_MODEL_FROM_DATABASE=Olidata Wireless Multimedia Adapter + +usb:v13D0* + ID_VENDOR_FROM_DATABASE=Techsan Electronics Co., Ltd. + +usb:v13D0p2282* + ID_MODEL_FROM_DATABASE=TechniSat DVB-PC TV Star 2 + +usb:v13D1* + ID_VENDOR_FROM_DATABASE=A-Max Technology Macao Commercial Offshore Co. Ltd. + +usb:v13D1p7019* + ID_MODEL_FROM_DATABASE=MD 82288 + +usb:v13D1pABE6* + ID_MODEL_FROM_DATABASE=Wireless 802.11g 54Mbps Network Adapter [RTL8187] + +usb:v13D2* + ID_VENDOR_FROM_DATABASE=Shark Multimedia + +usb:v13D2p0400* + ID_MODEL_FROM_DATABASE=Pocket Ethernet [klsi] + +usb:v13D3* + ID_VENDOR_FROM_DATABASE=IMC Networks + +usb:v13D3p3201* + ID_MODEL_FROM_DATABASE=VisionDTV USB-Ter/HAMA USB DVB-T device cold + +usb:v13D3p3202* + ID_MODEL_FROM_DATABASE=VisionDTV USB-Ter/HAMA USB DVB-T device warm + +usb:v13D3p3203* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v13D3p3204* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v13D3p3205* + ID_MODEL_FROM_DATABASE=DNTV Live! Tiny USB2 BDA (No Remote) + +usb:v13D3p3206* + ID_MODEL_FROM_DATABASE=DNTV Live! Tiny USB2 BDA (No Remote) + +usb:v13D3p3207* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v13D3p3208* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v13D3p3209* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7022BDA DVB-S Box(Without HID) + +usb:v13D3p3211* + ID_MODEL_FROM_DATABASE=DTV-DVB Hybrid Analog/Capture / Pinnacle PCTV 310e + +usb:v13D3p3212* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT704C - DVBT/NTSC/PAL Driver(PCM4) + +usb:v13D3p3213* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT704D - DVBT/NTSC/PAL Driver (PCM4) + +usb:v13D3p3214* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT704F -(MiniCard) DVBT/NTSC/PAL Driver(Without HID) + +usb:v13D3p3215* + ID_MODEL_FROM_DATABASE=DTV-DVB UDAT7240 - ATSC/NTSC/PAL Driver(PCM4) + +usb:v13D3p3216* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT 7047-USB 2.0 DVB-T Driver + +usb:v13D3p3217* + ID_MODEL_FROM_DATABASE=Digital-TV Receiver. + +usb:v13D3p3219* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT7049 - DVB-T Driver(Without HID) + +usb:v13D3p3220* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT 7047M-USB 2.0 DVB-T Driver + +usb:v13D3p3223* + ID_MODEL_FROM_DATABASE=DNTV Live! Tiny USB2 BDA (No Remote) + +usb:v13D3p3224* + ID_MODEL_FROM_DATABASE=DNTV Live! Tiny USB2 BDA (No Remote) + +usb:v13D3p3226* + ID_MODEL_FROM_DATABASE=DigitalNow TinyTwin DVB-T Receiver + +usb:v13D3p3234* + ID_MODEL_FROM_DATABASE=DVB-T FTA Half Minicard [RTL2832U] + +usb:v13D3p3236* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT 7047A-USB 2.0 DVB-T Driver + +usb:v13D3p3237* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT 704J - dual DVB-T Driver + +usb:v13D3p3239* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT704D - DVBT/NTSC/PAL Driver(Without HID) + +usb:v13D3p3240* + ID_MODEL_FROM_DATABASE=DTV-DVB UDXTTM6010 - A/D Driver(Without HID) + +usb:v13D3p3241* + ID_MODEL_FROM_DATABASE=DTV-DVB UDXTTM6010 - A/D Driver(Without HID) + +usb:v13D3p3242* + ID_MODEL_FROM_DATABASE=DTV-DVB UDAT7240LP - ATSC/NTSC/PAL Driver(Without HID) + +usb:v13D3p3243* + ID_MODEL_FROM_DATABASE=DTV-DVB UDXTTM6010 - A/D Driver(Without HID) + +usb:v13D3p3244* + ID_MODEL_FROM_DATABASE=DTV-DVB UDTT 7047Z-USB 2.0 DVB-T Driver + +usb:v13D3p3247* + ID_MODEL_FROM_DATABASE=802.11 n/g/b Wireless LAN Adapter + +usb:v13D3p3249* + ID_MODEL_FROM_DATABASE=Internal Bluetooth + +usb:v13D3p3262* + ID_MODEL_FROM_DATABASE=802.11 n/g/b Wireless LAN USB Adapter + +usb:v13D3p3273* + ID_MODEL_FROM_DATABASE=802.11 n/g/b Wireless LAN USB Mini-Card + +usb:v13D3p3274* + ID_MODEL_FROM_DATABASE=DVB-T Dongle [RTL2832U] + +usb:v13D3p3282* + ID_MODEL_FROM_DATABASE=DVB-T + GPS Minicard [RTL2832U] + +usb:v13D3p3284* + ID_MODEL_FROM_DATABASE=Wireless LAN USB Mini-Card + +usb:v13D3p3304* + ID_MODEL_FROM_DATABASE=Asus Integrated Bluetooth module [AR3011] + +usb:v13D3p3306* + ID_MODEL_FROM_DATABASE=Mediao 802.11n WLAN [Realtek RTL8191SU] + +usb:v13D3p3315* + ID_MODEL_FROM_DATABASE=Bluetooth module + +usb:v13D3p3375* + ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth 4.0 Adapter + +usb:v13D3p5070* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v13D3p5111* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v13D3p5115* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v13D3p5116* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v13D3p5126* + ID_MODEL_FROM_DATABASE=PC Cam + +usb:v13D3p5702* + ID_MODEL_FROM_DATABASE=UVC VGA Webcam + +usb:v13D3p5710* + ID_MODEL_FROM_DATABASE=UVC VGA Webcam + +usb:v13D3p5716* + ID_MODEL_FROM_DATABASE=UVC VGA Webcam + +usb:v13D3p7020* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7020BDA DVB-S Box(DVBS for MCE2005) + +usb:v13D3p7022* + ID_MODEL_FROM_DATABASE=DTV-DVB UDST7022BDA DVB-S Box(Without HID) + +usb:v13DC* + ID_VENDOR_FROM_DATABASE=ALEREON, INC. + +usb:v13DD* + ID_VENDOR_FROM_DATABASE=i.Tech Dynamic Limited + +usb:v13E1* + ID_VENDOR_FROM_DATABASE=Kaibo Wire & Cable (Shenzhen) Co., Ltd. + +usb:v13E5* + ID_VENDOR_FROM_DATABASE=Rane + +usb:v13E5p0001* + ID_MODEL_FROM_DATABASE=SL-1 + +usb:v13E5p0003* + ID_MODEL_FROM_DATABASE=TTM 57SL + +usb:v13E6* + ID_VENDOR_FROM_DATABASE=TechnoScope Co., Ltd. + +usb:v13EA* + ID_VENDOR_FROM_DATABASE=Hengstler + +usb:v13EAp0001* + ID_MODEL_FROM_DATABASE=C-56 Thermal Printer + +usb:v13EC* + ID_VENDOR_FROM_DATABASE=Zydacron + +usb:v13ECp0006* + ID_MODEL_FROM_DATABASE=HID Remote Control + +usb:v13EE* + ID_VENDOR_FROM_DATABASE=MosArt + +usb:v13EEp0003* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v13FD* + ID_VENDOR_FROM_DATABASE=Initio Corporation + +usb:v13FDp0840* + ID_MODEL_FROM_DATABASE=INIC-1618L SATA + +usb:v13FDp0841* + ID_MODEL_FROM_DATABASE=Samsung SE-T084M DVD-RW + +usb:v13FDp1340* + ID_MODEL_FROM_DATABASE=Hi-Speed USB to SATA Bridge + +usb:v13FDp160F* + ID_MODEL_FROM_DATABASE=RocketFish SATA Bridge [INIC-1611] + +usb:v13FDp1640* + ID_MODEL_FROM_DATABASE=INIC-1610L SATA Bridge + +usb:v13FDp1840* + ID_MODEL_FROM_DATABASE=INIC-1608 SATA bridge + +usb:v13FE* + ID_VENDOR_FROM_DATABASE=Kingston Technology Company Inc. + +usb:v13FEp1A00* + ID_MODEL_FROM_DATABASE=512MB/1GB Flash Drive + +usb:v13FEp1A23* + ID_MODEL_FROM_DATABASE=512MB Flash Drive + +usb:v13FEp1D00* + ID_MODEL_FROM_DATABASE=DataTraveler 2.0 1GB/4GB Flash Drive / Patriot Xporter 4GB Flash Drive + +usb:v13FEp1E00* + ID_MODEL_FROM_DATABASE=Flash Drive 2 GB [ICIDU 2 GB] + +usb:v13FEp1E50* + ID_MODEL_FROM_DATABASE=U3 Smart Drive + +usb:v13FEp1F00* + ID_MODEL_FROM_DATABASE=DataTraveler 2.0 4GB Flash Drive / Patriot Xporter 32GB (PEF32GUSB) Flash Drive + +usb:v13FEp1F23* + ID_MODEL_FROM_DATABASE=2Gb + +usb:v13FEp2240* + ID_MODEL_FROM_DATABASE=microSD card reader + +usb:v13FEp3100* + ID_MODEL_FROM_DATABASE=2/4 GB stick + +usb:v13FEp3123* + ID_MODEL_FROM_DATABASE=Verbatim STORE N GO 4GB + +usb:v13FEp3800* + ID_MODEL_FROM_DATABASE=Rage XT Flash Drive + +usb:v13FEp3E00* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v13FEp5100* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v1400* + ID_VENDOR_FROM_DATABASE=Axxion Group Corp. + +usb:v1402* + ID_VENDOR_FROM_DATABASE=Bowe Bell & Howell + +usb:v1403* + ID_VENDOR_FROM_DATABASE=Sitronix + +usb:v1403p0001* + ID_MODEL_FROM_DATABASE=Digital Photo Frame + +usb:v1409* + ID_VENDOR_FROM_DATABASE=IDS Imaging Development Systems GmbH + +usb:v1409p1000* + ID_MODEL_FROM_DATABASE=generic (firmware not loaded yet) + +usb:v1409p1485* + ID_MODEL_FROM_DATABASE=uEye UI1485 + +usb:v140E* + ID_VENDOR_FROM_DATABASE=Telechips, Inc. + +usb:v140EpB011* + ID_MODEL_FROM_DATABASE=TCC780X-based player (USB Boot mode) + +usb:v140EpB021* + ID_MODEL_FROM_DATABASE=TCC77X-based players (USB Boot mode) + +usb:v1410* + ID_VENDOR_FROM_DATABASE=Novatel Wireless + +usb:v1410p1110* + ID_MODEL_FROM_DATABASE=Merlin S620 + +usb:v1410p1120* + ID_MODEL_FROM_DATABASE=Merlin EX720 + +usb:v1410p1130* + ID_MODEL_FROM_DATABASE=Merlin S720 + +usb:v1410p1400* + ID_MODEL_FROM_DATABASE=Merlin U730/U740 (Vodafone) + +usb:v1410p1410* + ID_MODEL_FROM_DATABASE=Merlin U740 (non-Vodafone) + +usb:v1410p1430* + ID_MODEL_FROM_DATABASE=Merlin XU870 + +usb:v1410p1450* + ID_MODEL_FROM_DATABASE=Merlin X950D + +usb:v1410p2110* + ID_MODEL_FROM_DATABASE=Ovation U720/MCD3000 + +usb:v1410p2410* + ID_MODEL_FROM_DATABASE=Expedite EU740 + +usb:v1410p2420* + ID_MODEL_FROM_DATABASE=Expedite EU850D/EU860D/EU870D + +usb:v1410p4100* + ID_MODEL_FROM_DATABASE=U727 + +usb:v1410p4400* + ID_MODEL_FROM_DATABASE=Ovation MC930D/MC950D + +usb:v1410p9010* + ID_MODEL_FROM_DATABASE=Expedite E362 + +usb:v1410pA001* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v1410pA008* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v1410pB001* + ID_MODEL_FROM_DATABASE=Ovation MC551 + +usb:v1415* + ID_VENDOR_FROM_DATABASE=Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc. + +usb:v1415p0000* + ID_MODEL_FROM_DATABASE=Sony SingStar USBMIC + +usb:v1415p0020* + ID_MODEL_FROM_DATABASE=Sony Wireless SingStar + +usb:v1415p2000* + ID_MODEL_FROM_DATABASE=Sony Playstation Eye + +usb:v1419* + ID_VENDOR_FROM_DATABASE=ABILITY ENTERPRISE CO., LTD. + +usb:v1429* + ID_VENDOR_FROM_DATABASE=Vega Technologies Industrial (Austria) Co. + +usb:v142A* + ID_VENDOR_FROM_DATABASE=Thales E-Transactions + +usb:v142Ap0003* + ID_MODEL_FROM_DATABASE=Artema Hybrid + +usb:v142Ap0005* + ID_MODEL_FROM_DATABASE=Artema Modular + +usb:v142Ap0043* + ID_MODEL_FROM_DATABASE=medCompact + +usb:v142B* + ID_VENDOR_FROM_DATABASE=Arbiter Systems, Inc. + +usb:v142Bp03A5* + ID_MODEL_FROM_DATABASE=933A Portable Power Sentinel + +usb:v1430* + ID_VENDOR_FROM_DATABASE=RedOctane + +usb:v1430p0150* + ID_MODEL_FROM_DATABASE=wireless receiver for skylanders wii + +usb:v1430p4734* + ID_MODEL_FROM_DATABASE=Guitar Hero4 hub + +usb:v1430p474B* + ID_MODEL_FROM_DATABASE=Guitar Hero MIDI interface + +usb:v1431* + ID_VENDOR_FROM_DATABASE=Pertech Resources, Inc. + +usb:v1435* + ID_VENDOR_FROM_DATABASE=Wistron NeWeb + +usb:v1435p0427* + ID_MODEL_FROM_DATABASE=UR054g 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v1435p0711* + ID_MODEL_FROM_DATABASE=UR055G 802.11bg + +usb:v1435p0804* + ID_MODEL_FROM_DATABASE=AR9170+AR9104 802.11abgn Wireless Adapter + +usb:v1435p0826* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v1435p0827* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v1435p0828* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v1435p0829* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v1436* + ID_VENDOR_FROM_DATABASE=Denali Software, Inc. + +usb:v143C* + ID_VENDOR_FROM_DATABASE=Altek Corporation + +usb:v1443* + ID_VENDOR_FROM_DATABASE=Digilent + +usb:v1443p0007* + ID_MODEL_FROM_DATABASE=Development board JTAG + +usb:v1446* + ID_VENDOR_FROM_DATABASE=X.J.GROUP + +usb:v1446p6A73* + ID_MODEL_FROM_DATABASE=Stamps.com Model 510 5LB Scale + +usb:v1446p6A78* + ID_MODEL_FROM_DATABASE=DYMO Endicia 75lb Digital Scale + +usb:v1453* + ID_VENDOR_FROM_DATABASE=Radio Shack + +usb:v1453p4026* + ID_MODEL_FROM_DATABASE=26-183 Serial Cable + +usb:v1456* + ID_VENDOR_FROM_DATABASE=Extending Wire & Cable Co., Ltd. + +usb:v1457* + ID_VENDOR_FROM_DATABASE=First International Computer, Inc. + +usb:v1457p5117* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 kernel usbnet (g_ether, CDC Ethernet) mode + +usb:v1457p5118* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 Debug board (V2+) + +usb:v1457p5119* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 u-boot cdc_acm serial port + +usb:v1457p5120* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 u-boot usbtty generic serial + +usb:v1457p5121* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 kernel mass storage (g_storage) mode + +usb:v1457p5122* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 / Neo Freerunner kernel cdc_ether USB network + +usb:v1457p5123* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 internal USB CSR4 module + +usb:v1457p5124* + ID_MODEL_FROM_DATABASE=OpenMoko Neo1973 Bluetooth Device ID service + +usb:v145F* + ID_VENDOR_FROM_DATABASE=Trust + +usb:v145Fp0106* + ID_MODEL_FROM_DATABASE=Trust K56 V92 USB Modem + +usb:v145Fp013D* + ID_MODEL_FROM_DATABASE=PC Camera (SN9C201 + OV7660) + +usb:v145Fp013F* + ID_MODEL_FROM_DATABASE=Megapixel Auto Focus Webcam + +usb:v145Fp0142* + ID_MODEL_FROM_DATABASE=WB-6250X Webcam + +usb:v145Fp015A* + ID_MODEL_FROM_DATABASE=WB-8300X 2MP Webcam + +usb:v145Fp0161* + ID_MODEL_FROM_DATABASE=15901 802.11bg Wireless Adapter [Realtek RTL8187L] + +usb:v145Fp0167* + ID_MODEL_FROM_DATABASE=Widescreen 3MP Webcam + +usb:v145Fp0176* + ID_MODEL_FROM_DATABASE=Isla Keyboard + +usb:v1460* + ID_VENDOR_FROM_DATABASE=Tatung Co. + +usb:v1460p9150* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1461* + ID_VENDOR_FROM_DATABASE=Staccato Communications + +usb:v1462* + ID_VENDOR_FROM_DATABASE=Micro Star International + +usb:v1462p5512* + ID_MODEL_FROM_DATABASE=MegaStick-1 Flash Stick + +usb:v1462p8807* + ID_MODEL_FROM_DATABASE=DIGIVOX mini III [af9015] + +usb:v1472* + ID_VENDOR_FROM_DATABASE=Huawei-3Com + +usb:v1472p0007* + ID_MODEL_FROM_DATABASE=Aolynk WUB300g [ZyDAS ZD1211] + +usb:v1472p0009* + ID_MODEL_FROM_DATABASE=Aolynk WUB320g + +usb:v147A* + ID_VENDOR_FROM_DATABASE=Formosa Industrial Computing, Inc. + +usb:v147ApE015* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE016* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE017* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE018* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE02C* + ID_MODEL_FROM_DATABASE=Infrared Receiver + +usb:v147ApE03A* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE03C* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v147ApE03D* + ID_MODEL_FROM_DATABASE=2 Channel Audio + +usb:v147ApE03E* + ID_MODEL_FROM_DATABASE=Infrared Receiver [IR605A/Q] + +usb:v147E* + ID_VENDOR_FROM_DATABASE=Upek + +usb:v147Ep1000* + ID_MODEL_FROM_DATABASE=Biometric Touchchip/Touchstrip Fingerprint Sensor + +usb:v147Ep1001* + ID_MODEL_FROM_DATABASE=TCS5B Fingerprint sensor + +usb:v147Ep1002* + ID_MODEL_FROM_DATABASE=Biometric Touchchip/Touchstrip Fingerprint Sensor + +usb:v147Ep2016* + ID_MODEL_FROM_DATABASE=Biometric Touchchip/Touchstrip Fingerprint Sensor + +usb:v147Ep2020* + ID_MODEL_FROM_DATABASE=TouchChip Fingerprint Coprocessor (WBF advanced mode) + +usb:v147Ep3000* + ID_MODEL_FROM_DATABASE=TCS1C EIM/Cypress Fingerprint sensor + +usb:v147Ep3001* + ID_MODEL_FROM_DATABASE=TCS1C EIM/STM32 Fingerprint sensor + +usb:v147F* + ID_VENDOR_FROM_DATABASE=Hama GmbH & Co., KG + +usb:v1482* + ID_VENDOR_FROM_DATABASE=Vaillant + +usb:v1482p1005* + ID_MODEL_FROM_DATABASE=VRD PC-Interface + +usb:v1484* + ID_VENDOR_FROM_DATABASE=Elsa AG [hex] + +usb:v1484p1746* + ID_MODEL_FROM_DATABASE=Ecomo 19H99 Monitor + +usb:v1484p7616* + ID_MODEL_FROM_DATABASE=Elsa Hub + +usb:v1485* + ID_VENDOR_FROM_DATABASE=Silicom + +usb:v1485p0001* + ID_MODEL_FROM_DATABASE=U2E + +usb:v1485p0002* + ID_MODEL_FROM_DATABASE=Psion Gold Port Ethernet + +usb:v1487* + ID_VENDOR_FROM_DATABASE=DSP Group, Ltd. + +usb:v148E* + ID_VENDOR_FROM_DATABASE=EVATRONIX SA + +usb:v148F* + ID_VENDOR_FROM_DATABASE=Ralink Technology, Corp. + +usb:v148Fp1706* + ID_MODEL_FROM_DATABASE=RT2500USB Wireless Adapter + +usb:v148Fp2070* + ID_MODEL_FROM_DATABASE=RT2070 Wireless Adapter + +usb:v148Fp2570* + ID_MODEL_FROM_DATABASE=RT2570 Wireless Adapter + +usb:v148Fp2573* + ID_MODEL_FROM_DATABASE=RT2501/RT2573 Wireless Adapter + +usb:v148Fp2671* + ID_MODEL_FROM_DATABASE=RT2601/RT2671 Wireless Adapter + +usb:v148Fp2770* + ID_MODEL_FROM_DATABASE=RT2770 Wireless Adapter + +usb:v148Fp2870* + ID_MODEL_FROM_DATABASE=RT2870 Wireless Adapter + +usb:v148Fp3070* + ID_MODEL_FROM_DATABASE=RT2870/RT3070 Wireless Adapter + +usb:v148Fp3071* + ID_MODEL_FROM_DATABASE=RT3071 Wireless Adapter + +usb:v148Fp3072* + ID_MODEL_FROM_DATABASE=RT3072 Wireless Adapter + +usb:v148Fp3370* + ID_MODEL_FROM_DATABASE=RT3370 Wireless Adapter + +usb:v148Fp3572* + ID_MODEL_FROM_DATABASE=RT3572 Wireless Adapter + +usb:v148Fp3573* + ID_MODEL_FROM_DATABASE=RT3573 Wireless Adapter + +usb:v148Fp5370* + ID_MODEL_FROM_DATABASE=RT5370 Wireless Adapter + +usb:v148Fp5372* + ID_MODEL_FROM_DATABASE=RT5372 Wireless Adapter + +usb:v148Fp5572* + ID_MODEL_FROM_DATABASE=RT5572 Wireless Adapter + +usb:v148Fp9020* + ID_MODEL_FROM_DATABASE=RT2500USB Wireless Adapter + +usb:v148Fp9021* + ID_MODEL_FROM_DATABASE=RT2501USB Wireless Adapter + +usb:v1491* + ID_VENDOR_FROM_DATABASE=Futronic Technology Co. Ltd. + +usb:v1491p0020* + ID_MODEL_FROM_DATABASE=FS81 Fingerprint Scanner Module + +usb:v1493* + ID_VENDOR_FROM_DATABASE=Suunto + +usb:v1497* + ID_VENDOR_FROM_DATABASE=Panstrong Company Ltd. + +usb:v1498* + ID_VENDOR_FROM_DATABASE=Microtek International Inc. + +usb:v1498pA090* + ID_MODEL_FROM_DATABASE=DVB-T Tuner + +usb:v149A* + ID_VENDOR_FROM_DATABASE=Imagination Technologies + +usb:v149Ap2107* + ID_MODEL_FROM_DATABASE=DBX1 DSP core + +usb:v14AA* + ID_VENDOR_FROM_DATABASE=WideView Technology Inc. + +usb:v14AAp0001* + ID_MODEL_FROM_DATABASE=Avermedia AverTV DVBT USB1.1 (cold) + +usb:v14AAp0002* + ID_MODEL_FROM_DATABASE=Avermedia AverTV DVBT USB1.1 (warm) + +usb:v14AAp0201* + ID_MODEL_FROM_DATABASE=AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0 (cold) + +usb:v14AAp0221* + ID_MODEL_FROM_DATABASE=WT-220U DVB-T dongle + +usb:v14AAp022B* + ID_MODEL_FROM_DATABASE=WT-220U DVB-T dongle + +usb:v14AAp0301* + ID_MODEL_FROM_DATABASE=AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0 (warm) + +usb:v14AD* + ID_VENDOR_FROM_DATABASE=CTK Corporation + +usb:v14AE* + ID_VENDOR_FROM_DATABASE=Printronix Inc. + +usb:v14AF* + ID_VENDOR_FROM_DATABASE=ATP Electronics Inc. + +usb:v14B0* + ID_VENDOR_FROM_DATABASE=StarTech.com Ltd. + +usb:v14B2* + ID_VENDOR_FROM_DATABASE=Ralink Technology, Corp. + +usb:v14B2p3A93* + ID_MODEL_FROM_DATABASE=Topcom 802.11bg Wireless Adapter [Atheros AR5523] + +usb:v14B2p3A95* + ID_MODEL_FROM_DATABASE=Toshiba WUS-G06G-JT 802.11bg Wireless Adapter [Atheros AR5523] + +usb:v14B2p3A98* + ID_MODEL_FROM_DATABASE=Airlink101 AWLL4130 802.11bg Wireless Adapter [Atheros AR5523] + +usb:v14B2p3C02* + ID_MODEL_FROM_DATABASE=Conceptronic C54RU v2 802.11bg Wireless Adapter [Ralink RT2571] + +usb:v14B2p3C05* + ID_MODEL_FROM_DATABASE=rt2570 802.11g WLAN + +usb:v14B2p3C06* + ID_MODEL_FROM_DATABASE=Conceptronic C300RU v1 802.11bgn Wireless Adapter [Ralink RT2870] + +usb:v14B2p3C07* + ID_MODEL_FROM_DATABASE=802.11n adapter + +usb:v14B2p3C09* + ID_MODEL_FROM_DATABASE=802.11n adapter + +usb:v14B2p3C22* + ID_MODEL_FROM_DATABASE=Conceptronic C54RU v3 802.11bg Wireless Adapter [Ralink RT2571W] + +usb:v14B2p3C23* + ID_MODEL_FROM_DATABASE=Airlink101 AWLL6080 802.11bgn Wireless Adapter [Ralink RT2870] + +usb:v14B2p3C24* + ID_MODEL_FROM_DATABASE=NEC NP01LM 802.11abg Wireless Adapter [Ralink RT2571W] + +usb:v14B2p3C25* + ID_MODEL_FROM_DATABASE=DrayTek Vigor N61 802.11bgn Wireless Adapter [Ralink RT2870] + +usb:v14B2p3C27* + ID_MODEL_FROM_DATABASE=Airlink101 AWLL6070 802.11bgn Wireless Adapter [Ralink RT2770] + +usb:v14B2p3C28* + ID_MODEL_FROM_DATABASE=Conceptronic C300RU v2 802.11bgn Wireless Adapter [Ralink RT2770] + +usb:v14B2p3C2B* + ID_MODEL_FROM_DATABASE=NEC NP02LM 802.11bgn Wireless Adapter [Ralink RT3072] + +usb:v14B2p3C2C* + ID_MODEL_FROM_DATABASE=Keebox W150NU 802.11bgn Wireless Adapter [Ralink RT3070] + +usb:v14C0* + ID_VENDOR_FROM_DATABASE=Rockwell Automation, Inc. + +usb:v14C2* + ID_VENDOR_FROM_DATABASE=Gemlight Computer, Ltd + +usb:v14C2p0250* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 + +usb:v14C2p0350* + ID_MODEL_FROM_DATABASE=Storage Adapter V2 + +usb:v14C8* + ID_VENDOR_FROM_DATABASE=Zytronic + +usb:v14CD* + ID_VENDOR_FROM_DATABASE=Super Top + +usb:v14CDp121C* + ID_MODEL_FROM_DATABASE=microSD card reader + +usb:v14CDp123A* + ID_MODEL_FROM_DATABASE=SD/MMC/RS-MMC Card Reader + +usb:v14CDp125C* + ID_MODEL_FROM_DATABASE=SD card reader + +usb:v14CDp127B* + ID_MODEL_FROM_DATABASE=SDXC Reader + +usb:v14CDp6116* + ID_MODEL_FROM_DATABASE=M6116 SATA Bridge + +usb:v14CDp6600* + ID_MODEL_FROM_DATABASE=USB 2.0 IDE DEVICE + +usb:v14CDp6700* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v14CDp6900* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v14CDp8123* + ID_MODEL_FROM_DATABASE=SD MMC Reader + +usb:v14CDp8125* + ID_MODEL_FROM_DATABASE=SD MMC Reader + +usb:v14D8* + ID_VENDOR_FROM_DATABASE=JAMER INDUSTRIES CO., LTD. + +usb:v14DD* + ID_VENDOR_FROM_DATABASE=Raritan Computer, Inc. + +usb:v14DDp1007* + ID_MODEL_FROM_DATABASE=D2CIM-VUSB KVM connector + +usb:v14E0* + ID_VENDOR_FROM_DATABASE=WiNRADiO Communications + +usb:v14E0p0501* + ID_MODEL_FROM_DATABASE=WR-G528e 'CHEETAH' + +usb:v14E1* + ID_VENDOR_FROM_DATABASE=Dialogue Technology Corp. + +usb:v14E1p5000* + ID_MODEL_FROM_DATABASE=PenMount 5000 Touch Controller + +usb:v14E5* + ID_VENDOR_FROM_DATABASE=SAIN Information & Communications Co., Ltd. + +usb:v14EA* + ID_VENDOR_FROM_DATABASE=Planex Communications + +usb:v14EApAB10* + ID_MODEL_FROM_DATABASE=GW-US54GZ + +usb:v14EApAB11* + ID_MODEL_FROM_DATABASE=GU-1000T + +usb:v14EApAB13* + ID_MODEL_FROM_DATABASE=GW-US54Mini 802.11bg + +usb:v14ED* + ID_VENDOR_FROM_DATABASE=Shure Inc. + +usb:v14EDp29B6* + ID_MODEL_FROM_DATABASE=X2u Adapter + +usb:v14F7* + ID_VENDOR_FROM_DATABASE=TechniSat Digital GmbH + +usb:v14F7p0001* + ID_MODEL_FROM_DATABASE=SkyStar 2 HD CI + +usb:v14F7p0002* + ID_MODEL_FROM_DATABASE=SkyStar 2 HD CI + +usb:v14F7p0003* + ID_MODEL_FROM_DATABASE=CableStar Combo HD CI + +usb:v14F7p0004* + ID_MODEL_FROM_DATABASE=AirStar TeleStick 2 + +usb:v14F7p0500* + ID_MODEL_FROM_DATABASE=DVB-PC TV Star HD + +usb:v1500* + ID_VENDOR_FROM_DATABASE=Ellisys + +usb:v1501* + ID_VENDOR_FROM_DATABASE=Pine-Tum Enterprise Co., Ltd. + +usb:v1509* + ID_VENDOR_FROM_DATABASE=First International Computer, Inc. + +usb:v1509p9242* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1513* + ID_VENDOR_FROM_DATABASE=medMobile + +usb:v1513p0444* + ID_MODEL_FROM_DATABASE=medMobile + +usb:v1514* + ID_VENDOR_FROM_DATABASE=Actel + +usb:v1514p2003* + ID_MODEL_FROM_DATABASE=FlashPro3 Programmer + +usb:v1514p2004* + ID_MODEL_FROM_DATABASE=FlashPro3 Programmer + +usb:v1514p2005* + ID_MODEL_FROM_DATABASE=FlashPro3 Programmer + +usb:v1516* + ID_VENDOR_FROM_DATABASE=CompUSA + +usb:v1516p1603* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v1516p8628* + ID_MODEL_FROM_DATABASE=Pen Drive + +usb:v1518* + ID_VENDOR_FROM_DATABASE=Cheshire Engineering Corp. + +usb:v1518p0001* + ID_MODEL_FROM_DATABASE=HDReye High Dynamic Range Camera + +usb:v1518p0002* + ID_MODEL_FROM_DATABASE=HDReye (before firmware loads) + +usb:v1520* + ID_VENDOR_FROM_DATABASE=Bitwire Corp. + +usb:v1524* + ID_VENDOR_FROM_DATABASE=ENE Technology Inc + +usb:v1524p6680* + ID_MODEL_FROM_DATABASE=UTS 6680 + +usb:v1527* + ID_VENDOR_FROM_DATABASE=Silicon Portals + +usb:v1527p0200* + ID_MODEL_FROM_DATABASE=YAP Phone (no firmware) + +usb:v1527p0201* + ID_MODEL_FROM_DATABASE=YAP Phone + +usb:v1529* + ID_VENDOR_FROM_DATABASE=UBIQUAM Co., Ltd. + +usb:v1529p3100* + ID_MODEL_FROM_DATABASE=CDMA 1xRTT USB Modem (U-100/105/200/300/520) + +usb:v152A* + ID_VENDOR_FROM_DATABASE=Thesycon Systemsoftware & Consulting GmbH + +usb:v152D* + ID_VENDOR_FROM_DATABASE=JMicron Technology Corp. / JMicron USA Technology Corp. + +usb:v152Dp0539* + ID_MODEL_FROM_DATABASE=JMS539 SuperSpeed SATA II 3.0G Bridge + +usb:v152Dp0770* + ID_MODEL_FROM_DATABASE=Alienware Integrated Webcam + +usb:v152Dp2329* + ID_MODEL_FROM_DATABASE=JM20329 SATA Bridge + +usb:v152Dp2335* + ID_MODEL_FROM_DATABASE=ATA/ATAPI Bridge + +usb:v152Dp2336* + ID_MODEL_FROM_DATABASE=Hard Disk Drive + +usb:v152Dp2337* + ID_MODEL_FROM_DATABASE=ATA/ATAPI Bridge + +usb:v152Dp2338* + ID_MODEL_FROM_DATABASE=JM20337 Hi-Speed USB to SATA & PATA Combo Bridge + +usb:v152Dp2339* + ID_MODEL_FROM_DATABASE=JM20339 SATA Bridge + +usb:v152Dp2352* + ID_MODEL_FROM_DATABASE=ATA/ATAPI Bridge + +usb:v152Dp2509* + ID_MODEL_FROM_DATABASE=JMS539 SuperSpeed SATA II 3.0G Bridge + +usb:v152E* + ID_VENDOR_FROM_DATABASE=LG (HLDS) + +usb:v152Ep2507* + ID_MODEL_FROM_DATABASE=PL-2507 IDE Controller + +usb:v152EpE001* + ID_MODEL_FROM_DATABASE=GSA-5120D DVD-RW + +usb:v1532* + ID_VENDOR_FROM_DATABASE=Razer USA, Ltd + +usb:v1532p0001* + ID_MODEL_FROM_DATABASE=RZ01-020300 Optical Mouse [Diamondback] + +usb:v1532p0003* + ID_MODEL_FROM_DATABASE=Krait Mouse + +usb:v1532p0007* + ID_MODEL_FROM_DATABASE=DeathAdder Mouse + +usb:v1532p0013* + ID_MODEL_FROM_DATABASE=Orochi mouse + +usb:v1532p0016* + ID_MODEL_FROM_DATABASE=DeathAdder Mouse + +usb:v1532p0017* + ID_MODEL_FROM_DATABASE=RZ01-0035 Laser Gaming Mouse [Imperator] + +usb:v1532p001C* + ID_MODEL_FROM_DATABASE=RZ01-0036 Optical Gaming Mouse [Abyssus] + +usb:v1532p0024* + ID_MODEL_FROM_DATABASE=Razer Mamba + +usb:v1532p002E* + ID_MODEL_FROM_DATABASE=RZ01-0058 Gaming Mouse [Naga] + +usb:v1532p0036* + ID_MODEL_FROM_DATABASE=RZ01-0075, Gaming Mouse [Naga Hex] + +usb:v1532p0101* + ID_MODEL_FROM_DATABASE=Copperhead Mouse + +usb:v1532p0102* + ID_MODEL_FROM_DATABASE=Tarantula Keyboard + +usb:v1532p0109* + ID_MODEL_FROM_DATABASE=Lycosa Keyboard + +usb:v1532p0300* + ID_MODEL_FROM_DATABASE=RZ06-0063 Motion Sensing Controllers [Hydra] + +usb:v1546* + ID_VENDOR_FROM_DATABASE=U-Blox AG + +usb:v1547* + ID_VENDOR_FROM_DATABASE=SG Intec Ltd & Co KG + +usb:v1547p1000* + ID_MODEL_FROM_DATABASE=SG-Lock[U2] + +usb:v154A* + ID_VENDOR_FROM_DATABASE=Celectronic GmbH + +usb:v154Ap8180* + ID_MODEL_FROM_DATABASE=CARD STAR/medic2 + +usb:v154B* + ID_VENDOR_FROM_DATABASE=PNY + +usb:v154Bp0010* + ID_MODEL_FROM_DATABASE=USB 2.0 Flash Drive + +usb:v154Bp004D* + ID_MODEL_FROM_DATABASE=8 GB Flash Drive + +usb:v154Bp0057* + ID_MODEL_FROM_DATABASE=32GB Micro Slide Attache Flash Drive + +usb:v154Bp6545* + ID_MODEL_FROM_DATABASE=FD Device + +usb:v154D* + ID_VENDOR_FROM_DATABASE=ConnectCounty Holdings Berhad + +usb:v154E* + ID_VENDOR_FROM_DATABASE=D&M Holdings, Inc. (Denon/Marantz) + +usb:v154Ep3000* + ID_MODEL_FROM_DATABASE=Marantz RC9001 Remote Control + +usb:v154F* + ID_VENDOR_FROM_DATABASE=SNBC CO., Ltd + +usb:v1554* + ID_VENDOR_FROM_DATABASE=Prolink Microsystems Corp. + +usb:v1554p5010* + ID_MODEL_FROM_DATABASE=PV-D231U(RN)-F [PixelView PlayTV SBTVD Full-Seg] + +usb:v1557* + ID_VENDOR_FROM_DATABASE=OQO + +usb:v1557p0002* + ID_MODEL_FROM_DATABASE=model 01 WiFi interface + +usb:v1557p0003* + ID_MODEL_FROM_DATABASE=model 01 Bluetooth interface + +usb:v1557p0A80* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v1557p7720* + ID_MODEL_FROM_DATABASE=model 01+ Ethernet + +usb:v1557p8150* + ID_MODEL_FROM_DATABASE=model 01 Ethernet interface + +usb:v1568* + ID_VENDOR_FROM_DATABASE=Sunf Pu Technology Co., Ltd + +usb:v156F* + ID_VENDOR_FROM_DATABASE=Quantum Corporation + +usb:v1570* + ID_VENDOR_FROM_DATABASE=ALLTOP TECHNOLOGY CO., LTD. + +usb:v157B* + ID_VENDOR_FROM_DATABASE=Ketron SRL + +usb:v157E* + ID_VENDOR_FROM_DATABASE=TRENDnet + +usb:v157Ep3006* + ID_MODEL_FROM_DATABASE=TEW-444UB EU [TRENDnet] + +usb:v157Ep3007* + ID_MODEL_FROM_DATABASE=TEW-444UB EU (no firmware) + +usb:v157Ep300A* + ID_MODEL_FROM_DATABASE=TEW-429UB 802.11bg + +usb:v157Ep300B* + ID_MODEL_FROM_DATABASE=TEW-429UB 802.11bg + +usb:v157Ep300C* + ID_MODEL_FROM_DATABASE=TEW-429UF A1 802.11bg Wireless Adapter [ZyDAS ZD1211B] + +usb:v157Ep300D* + ID_MODEL_FROM_DATABASE=TEW-429UB C1 802.11bg + +usb:v157Ep300E* + ID_MODEL_FROM_DATABASE=SMC SMCWUSB-N 802.11bgn 2x2:2 Wireless Adapter [Ralink RT2870] + +usb:v157Ep3012* + ID_MODEL_FROM_DATABASE=TEW-604UB 802.11bg Wireless Adapter [Atheros AR5523] + +usb:v157Ep3013* + ID_MODEL_FROM_DATABASE=TEW-645UB 802.11bgn 1x2:2 Wireless Adapter [Ralink RT2770] + +usb:v157Ep3204* + ID_MODEL_FROM_DATABASE=Allnet ALL0298 v2 802.11bg + +usb:v157Ep3205* + ID_MODEL_FROM_DATABASE=Allnet ALL0283 [AR5523] + +usb:v157Ep3206* + ID_MODEL_FROM_DATABASE=Allnet ALL0283 [AR5523](no firmware) + +usb:v157Ep3207* + ID_MODEL_FROM_DATABASE=TEW-509UB A1 802.11abg Wireless Adapter [ZyDAS ZD1211] + +usb:v157Ep3208* + ID_MODEL_FROM_DATABASE=TEW-509UB 1.1R 802.11abg Wireless Adapter + +usb:v1582* + ID_VENDOR_FROM_DATABASE=Fiberline + +usb:v1582p6003* + ID_MODEL_FROM_DATABASE=WL-430U 802.11bg + +usb:v1587* + ID_VENDOR_FROM_DATABASE=SMA Technologie AG + +usb:v158D* + ID_VENDOR_FROM_DATABASE=Oakley Inc. + +usb:v158E* + ID_VENDOR_FROM_DATABASE=JDS Uniphase Corporation (JDSU) + +usb:v158Ep0820* + ID_MODEL_FROM_DATABASE=SmartPocket Class Device + +usb:v1598* + ID_VENDOR_FROM_DATABASE=Kunshan Guoji Electronics Co., Ltd. + +usb:v15A2* + ID_VENDOR_FROM_DATABASE=Freescale Semiconductor, Inc. + +usb:v15A2p0038* + ID_MODEL_FROM_DATABASE=9S08JS Bootloader + +usb:v15A2p003B* + ID_MODEL_FROM_DATABASE=USB2CAN Application for ColdFire DEMOJM board + +usb:v15A2p0042* + ID_MODEL_FROM_DATABASE=OSBDM - Debug Port + +usb:v15A2p004F* + ID_MODEL_FROM_DATABASE=i.MX28 SystemOnChip in RecoveryMode + +usb:v15A2p0052* + ID_MODEL_FROM_DATABASE=i.MX50 SystemOnChip in RecoveryMode + +usb:v15A2p0054* + ID_MODEL_FROM_DATABASE=i.MX6Q SystemOnChip in RecoveryMode + +usb:v15A4* + ID_VENDOR_FROM_DATABASE=Afatech Technologies, Inc. + +usb:v15A4p1000* + ID_MODEL_FROM_DATABASE=AF9015/AF9035 DVB-T stick + +usb:v15A4p1001* + ID_MODEL_FROM_DATABASE=AF9015/AF9035 DVB-T stick + +usb:v15A4p1336* + ID_MODEL_FROM_DATABASE=SDHC/MicroSD/MMC/MS/M2/CF/XD Flash Card Reader + +usb:v15A4p9015* + ID_MODEL_FROM_DATABASE=AF9015 DVB-T USB2.0 stick + +usb:v15A4p9016* + ID_MODEL_FROM_DATABASE=AF9015 DVB-T USB2.0 stick + +usb:v15A8* + ID_VENDOR_FROM_DATABASE=Teams Power Limited + +usb:v15A9* + ID_VENDOR_FROM_DATABASE=Gemtek + +usb:v15A9p0002* + ID_MODEL_FROM_DATABASE=SparkLAN WL-682 802.11bg Wireless Adapter [Intersil ISL3887] + +usb:v15A9p0004* + ID_MODEL_FROM_DATABASE=WUBR-177G [Ralink RT2571W] + +usb:v15A9p0006* + ID_MODEL_FROM_DATABASE=Wireless 11n USB Adapter + +usb:v15A9p0010* + ID_MODEL_FROM_DATABASE=802.11n USB Wireless Card + +usb:v15A9p0012* + ID_MODEL_FROM_DATABASE=WUBR-208N 802.11abgn Wireless Adapter [Ralink RT2870] + +usb:v15AA* + ID_VENDOR_FROM_DATABASE=Gearway Electronics (Dong Guan) Co., Ltd. + +usb:v15AD* + ID_VENDOR_FROM_DATABASE=VMware Inc. + +usb:v15BA* + ID_VENDOR_FROM_DATABASE=Olimex Ltd. + +usb:v15BAp0003* + ID_MODEL_FROM_DATABASE=OpenOCD JTAG + +usb:v15BAp0004* + ID_MODEL_FROM_DATABASE=OpenOCD JTAG TINY + +usb:v15BAp002A* + ID_MODEL_FROM_DATABASE=ARM-USB-TINY-H JTAG interface + +usb:v15BAp002B* + ID_MODEL_FROM_DATABASE=ARM-USB-OCD-H JTAG+RS232 + +usb:v15C0* + ID_VENDOR_FROM_DATABASE=XL Imaging + +usb:v15C0p0001* + ID_MODEL_FROM_DATABASE=2M pixel Microscope Camera + +usb:v15C0p0002* + ID_MODEL_FROM_DATABASE=3M pixel Microscope Camera + +usb:v15C0p0003* + ID_MODEL_FROM_DATABASE=1.3M pixel Microscope Camera (mono) + +usb:v15C0p0004* + ID_MODEL_FROM_DATABASE=1.3M pixel Microscope Camera (colour) + +usb:v15C0p0005* + ID_MODEL_FROM_DATABASE=3M pixel Microscope Camera (Mk 2) + +usb:v15C0p0006* + ID_MODEL_FROM_DATABASE=2M pixel Microscope Camera (with capture button) + +usb:v15C0p0007* + ID_MODEL_FROM_DATABASE=3M pixel Microscope Camera (with capture button) + +usb:v15C0p0008* + ID_MODEL_FROM_DATABASE=1.3M pixel Microscope Camera (colour, with capture button) + +usb:v15C0p0009* + ID_MODEL_FROM_DATABASE=1.3M pixel Microscope Camera (colour, with capture button) + +usb:v15C0p000A* + ID_MODEL_FROM_DATABASE=2M pixel Microscope Camera (Mk 2) + +usb:v15C0p0010* + ID_MODEL_FROM_DATABASE=1.3M pixel "Tinycam" + +usb:v15C0p0101* + ID_MODEL_FROM_DATABASE=3M pixel Microscope Camera + +usb:v15C2* + ID_VENDOR_FROM_DATABASE=SoundGraph Inc. + +usb:v15C2p0036* + ID_MODEL_FROM_DATABASE=LC16M VFD Display/IR Receiver + +usb:v15C2p0038* + ID_MODEL_FROM_DATABASE=GD01 MX LCD Display/IR Receiver + +usb:v15C2pFFDA* + ID_MODEL_FROM_DATABASE=iMON PAD Remote Controller + +usb:v15C2pFFDC* + ID_MODEL_FROM_DATABASE=iMON PAD Remote Controller + +usb:v15C5* + ID_VENDOR_FROM_DATABASE=Advance Multimedia Internet Technology Inc. (AMIT) + +usb:v15C5p0008* + ID_MODEL_FROM_DATABASE=WL532U 802.11g Adapter + +usb:v15C6* + ID_VENDOR_FROM_DATABASE=Laboratoires MXM + +usb:v15C6p1000* + ID_MODEL_FROM_DATABASE=DigistimSP (cold) + +usb:v15C6p1001* + ID_MODEL_FROM_DATABASE=DigistimSP (warm) + +usb:v15C6p1002* + ID_MODEL_FROM_DATABASE=DigimapSP USB (cold) + +usb:v15C6p1003* + ID_MODEL_FROM_DATABASE=DigimapSP USB (warm) + +usb:v15C6p1004* + ID_MODEL_FROM_DATABASE=DigistimSP (cold) + +usb:v15C6p1005* + ID_MODEL_FROM_DATABASE=DigistimSP (warm) + +usb:v15C6p1100* + ID_MODEL_FROM_DATABASE=Odyssee (cold) + +usb:v15C6p1101* + ID_MODEL_FROM_DATABASE=Odyssee (warm) + +usb:v15C6p1200* + ID_MODEL_FROM_DATABASE=Digispy + +usb:v15C8* + ID_VENDOR_FROM_DATABASE=KTF Technologies + +usb:v15C8p3201* + ID_MODEL_FROM_DATABASE=EVER EV-W100/EV-W250 + +usb:v15C9* + ID_VENDOR_FROM_DATABASE=D-Box Technologies + +usb:v15CA* + ID_VENDOR_FROM_DATABASE=Textech International Ltd. + +usb:v15CAp00C3* + ID_MODEL_FROM_DATABASE=Mini Optical Mouse + +usb:v15CAp0101* + ID_MODEL_FROM_DATABASE=MIDI Interface cable + +usb:v15CAp1806* + ID_MODEL_FROM_DATABASE=MIDI Interface cable + +usb:v15D5* + ID_VENDOR_FROM_DATABASE=Coulomb Electronics Ltd. + +usb:v15D9* + ID_VENDOR_FROM_DATABASE=Trust International B.V. + +usb:v15D9p0A33* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v15D9p0A37* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v15D9p0A41* + ID_MODEL_FROM_DATABASE=MI-2540D [Optical mouse] + +usb:v15D9p0A4C* + ID_MODEL_FROM_DATABASE=USB+PS/2 Optical Mouse + +usb:v15D9p0A4D* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v15DC* + ID_VENDOR_FROM_DATABASE=Hynix Semiconductor Inc. + +usb:v15E0* + ID_VENDOR_FROM_DATABASE=Seong Ji Industrial Co., Ltd. + +usb:v15E1* + ID_VENDOR_FROM_DATABASE=RSA + +usb:v15E1p2007* + ID_MODEL_FROM_DATABASE=RSA SecurID (R) Authenticator + +usb:v15E4* + ID_VENDOR_FROM_DATABASE=Numark + +usb:v15E4p0024* + ID_MODEL_FROM_DATABASE=Mixtrack + +usb:v15E4p0140* + ID_MODEL_FROM_DATABASE=ION VCR 2 PC / Video 2 PC + +usb:v15E8* + ID_VENDOR_FROM_DATABASE=SohoWare + +usb:v15E8p9100* + ID_MODEL_FROM_DATABASE=NUB100 Ethernet [pegasus] + +usb:v15E8p9110* + ID_MODEL_FROM_DATABASE=10/100 USB Ethernet + +usb:v15E9* + ID_VENDOR_FROM_DATABASE=Pacific Digital Corp. + +usb:v15E9p04CE* + ID_MODEL_FROM_DATABASE=MemoryFrame MF-570 + +usb:v15E9p1968* + ID_MODEL_FROM_DATABASE=MemoryFrame MF-570 + +usb:v15E9p1969* + ID_MODEL_FROM_DATABASE=Digital Frame + +usb:v15EC* + ID_VENDOR_FROM_DATABASE=Belcarra Technologies Corp. + +usb:v15F4* + ID_VENDOR_FROM_DATABASE=HanfTek + +usb:v15F4p0001* + ID_MODEL_FROM_DATABASE=HanfTek UMT-010 USB2.0 DVB-T (cold) + +usb:v15F4p0025* + ID_MODEL_FROM_DATABASE=HanfTek UMT-010 USB2.0 DVB-T (warm) + +usb:v1604* + ID_VENDOR_FROM_DATABASE=Tascam + +usb:v1604p8000* + ID_MODEL_FROM_DATABASE=US-428 Audio/Midi Controller (without fw) + +usb:v1604p8001* + ID_MODEL_FROM_DATABASE=US-428 Audio/Midi Controller + +usb:v1604p8004* + ID_MODEL_FROM_DATABASE=US-224 Audio/Midi Controller (without fw) + +usb:v1604p8005* + ID_MODEL_FROM_DATABASE=US-224 Audio/Midi Controller + +usb:v1604p8006* + ID_MODEL_FROM_DATABASE=US-122 Audio/Midi Interface (without fw) + +usb:v1604p8007* + ID_MODEL_FROM_DATABASE=US-122 Audio/Midi Interface + +usb:v1606* + ID_VENDOR_FROM_DATABASE=Umax + +usb:v1606p0002* + ID_MODEL_FROM_DATABASE=Astra 1236U Scanner + +usb:v1606p0010* + ID_MODEL_FROM_DATABASE=Astra 1220U + +usb:v1606p0030* + ID_MODEL_FROM_DATABASE=Astra 1600U/2000U + +usb:v1606p0050* + ID_MODEL_FROM_DATABASE=Scanner + +usb:v1606p0060* + ID_MODEL_FROM_DATABASE=Astra 3400/3450 + +usb:v1606p0070* + ID_MODEL_FROM_DATABASE=Astra 4400/4450 + +usb:v1606p0130* + ID_MODEL_FROM_DATABASE=Astra 2100U + +usb:v1606p0160* + ID_MODEL_FROM_DATABASE=Astra 5400U + +usb:v1606p0170* + ID_MODEL_FROM_DATABASE=Uniscan D50 + +usb:v1606p0230* + ID_MODEL_FROM_DATABASE=Astra 2200/2200SU + +usb:v1606p0350* + ID_MODEL_FROM_DATABASE=Astra 4800/4850 Scanner + +usb:v1606p1030* + ID_MODEL_FROM_DATABASE=Astra 4000U + +usb:v1606p1220* + ID_MODEL_FROM_DATABASE=Genesys Logic Scanner Controller NT5.0 + +usb:v1606p2010* + ID_MODEL_FROM_DATABASE=AstraCam Digital Camera + +usb:v1606p2020* + ID_MODEL_FROM_DATABASE=AstraCam 1000 + +usb:v1606p2030* + ID_MODEL_FROM_DATABASE=AstraCam 1800 Digital Camera + +usb:v1608* + ID_VENDOR_FROM_DATABASE=Inside Out Networks [hex] + +usb:v1608p0001* + ID_MODEL_FROM_DATABASE=EdgePort/4 Serial Port + +usb:v1608p0002* + ID_MODEL_FROM_DATABASE=Edgeport/8 + +usb:v1608p0003* + ID_MODEL_FROM_DATABASE=Rapidport/4 + +usb:v1608p0004* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0005* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0006* + ID_MODEL_FROM_DATABASE=Edgeport/4i + +usb:v1608p0007* + ID_MODEL_FROM_DATABASE=Edgeport/2i + +usb:v1608p0008* + ID_MODEL_FROM_DATABASE=Edgeport/8 + +usb:v1608p000C* + ID_MODEL_FROM_DATABASE=Edgeport/421 + +usb:v1608p000D* + ID_MODEL_FROM_DATABASE=Edgeport/21 + +usb:v1608p000E* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p000F* + ID_MODEL_FROM_DATABASE=Edgeport/8 + +usb:v1608p0010* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0011* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0012* + ID_MODEL_FROM_DATABASE=Edgeport/416 + +usb:v1608p0014* + ID_MODEL_FROM_DATABASE=Edgeport/8i + +usb:v1608p0018* + ID_MODEL_FROM_DATABASE=Edgeport/412 + +usb:v1608p0019* + ID_MODEL_FROM_DATABASE=Edgeport/412 + +usb:v1608p001A* + ID_MODEL_FROM_DATABASE=Edgeport/2+2i + +usb:v1608p0101* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0105* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0106* + ID_MODEL_FROM_DATABASE=Edgeport/4i + +usb:v1608p0107* + ID_MODEL_FROM_DATABASE=Edgeport/2i + +usb:v1608p010C* + ID_MODEL_FROM_DATABASE=Edgeport/421 + +usb:v1608p010D* + ID_MODEL_FROM_DATABASE=Edgeport/21 + +usb:v1608p0110* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0111* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0112* + ID_MODEL_FROM_DATABASE=Edgeport/416 + +usb:v1608p0114* + ID_MODEL_FROM_DATABASE=Edgeport/8i + +usb:v1608p0201* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0203* + ID_MODEL_FROM_DATABASE=Rapidport/4 + +usb:v1608p0204* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0205* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0206* + ID_MODEL_FROM_DATABASE=Edgeport/4i + +usb:v1608p0207* + ID_MODEL_FROM_DATABASE=Edgeport/2i + +usb:v1608p020C* + ID_MODEL_FROM_DATABASE=Edgeport/421 + +usb:v1608p020D* + ID_MODEL_FROM_DATABASE=Edgeport/21 + +usb:v1608p020E* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p020F* + ID_MODEL_FROM_DATABASE=Edgeport/8 + +usb:v1608p0210* + ID_MODEL_FROM_DATABASE=Edgeport/2 + +usb:v1608p0211* + ID_MODEL_FROM_DATABASE=Edgeport/4 + +usb:v1608p0212* + ID_MODEL_FROM_DATABASE=Edgeport/416 + +usb:v1608p0214* + ID_MODEL_FROM_DATABASE=Edgeport/8i + +usb:v1608p0215* + ID_MODEL_FROM_DATABASE=Edgeport/1 + +usb:v1608p0216* + ID_MODEL_FROM_DATABASE=EPOS/44 + +usb:v1608p0217* + ID_MODEL_FROM_DATABASE=Edgeport/42 + +usb:v1608p021A* + ID_MODEL_FROM_DATABASE=Edgeport/2+2i + +usb:v1608p021B* + ID_MODEL_FROM_DATABASE=Edgeport/2c + +usb:v1608p021C* + ID_MODEL_FROM_DATABASE=Edgeport/221c + +usb:v1608p021D* + ID_MODEL_FROM_DATABASE=Edgeport/22c + +usb:v1608p021E* + ID_MODEL_FROM_DATABASE=Edgeport/21c + +usb:v1608p021F* + ID_MODEL_FROM_DATABASE=Edgeport/62 + +usb:v1608p0240* + ID_MODEL_FROM_DATABASE=Edgeport/1 + +usb:v1608p0241* + ID_MODEL_FROM_DATABASE=Edgeport/1i + +usb:v1608p0242* + ID_MODEL_FROM_DATABASE=Edgeport/4s + +usb:v1608p0243* + ID_MODEL_FROM_DATABASE=Edgeport/8s + +usb:v1608p0244* + ID_MODEL_FROM_DATABASE=Edgeport/8 + +usb:v1608p0245* + ID_MODEL_FROM_DATABASE=Edgeport/22c + +usb:v1608p0301* + ID_MODEL_FROM_DATABASE=Watchport/P + +usb:v1608p0302* + ID_MODEL_FROM_DATABASE=Watchport/M + +usb:v1608p0303* + ID_MODEL_FROM_DATABASE=Watchport/W + +usb:v1608p0304* + ID_MODEL_FROM_DATABASE=Watchport/T + +usb:v1608p0305* + ID_MODEL_FROM_DATABASE=Watchport/H + +usb:v1608p0306* + ID_MODEL_FROM_DATABASE=Watchport/E + +usb:v1608p0307* + ID_MODEL_FROM_DATABASE=Watchport/L + +usb:v1608p0308* + ID_MODEL_FROM_DATABASE=Watchport/R + +usb:v1608p0309* + ID_MODEL_FROM_DATABASE=Watchport/A + +usb:v1608p030A* + ID_MODEL_FROM_DATABASE=Watchport/D + +usb:v1608p030B* + ID_MODEL_FROM_DATABASE=Watchport/D + +usb:v1608p030C* + ID_MODEL_FROM_DATABASE=Power Management Port + +usb:v1608p030E* + ID_MODEL_FROM_DATABASE=Power Management Port + +usb:v1608p030F* + ID_MODEL_FROM_DATABASE=Watchport/G + +usb:v1608p0310* + ID_MODEL_FROM_DATABASE=Watchport/Tc + +usb:v1608p0311* + ID_MODEL_FROM_DATABASE=Watchport/Hc + +usb:v1608p1403* + ID_MODEL_FROM_DATABASE=MultiTech Systems MT4X56 Modem + +usb:v1608p1A17* + ID_MODEL_FROM_DATABASE=Agilent Technologies (E6473) + +usb:v160A* + ID_VENDOR_FROM_DATABASE=VIA Technologies, Inc. + +usb:v160Ap3184* + ID_MODEL_FROM_DATABASE=VIA VNT-6656 [WiFi 802.11b/g USB Dongle] + +usb:v160E* + ID_VENDOR_FROM_DATABASE=INRO + +usb:v160Ep0001* + ID_MODEL_FROM_DATABASE=E2USBKey + +usb:v1614* + ID_VENDOR_FROM_DATABASE=Amoi Electronics + +usb:v1614p0404* + ID_MODEL_FROM_DATABASE=WMA9109 UMTS Phone + +usb:v1614p0600* + ID_MODEL_FROM_DATABASE=Vodafone VDA GPS / Toschiba Protege G710 + +usb:v1614p0804* + ID_MODEL_FROM_DATABASE=WP-S1 Phone + +usb:v1619* + ID_VENDOR_FROM_DATABASE=L & K Precision Technology Co., Ltd. + +usb:v1621* + ID_VENDOR_FROM_DATABASE=Wionics Research + +usb:v1628* + ID_VENDOR_FROM_DATABASE=Stonestreet One, Inc. + +usb:v162A* + ID_VENDOR_FROM_DATABASE=Airgo Networks Inc. + +usb:v162F* + ID_VENDOR_FROM_DATABASE=WiQuest Communications, Inc. + +usb:v1630* + ID_VENDOR_FROM_DATABASE=2Wire, Inc. + +usb:v1630p0005* + ID_MODEL_FROM_DATABASE=802.11g Wireless Adapter [Intersil ISL3886] + +usb:v1630p0011* + ID_MODEL_FROM_DATABASE=PC Port 10 Mps Adapter + +usb:v1630pFF81* + ID_MODEL_FROM_DATABASE=802.11b Wireless Adapter [Lucent/Agere Hermes I] + +usb:v1631* + ID_VENDOR_FROM_DATABASE=Good Way Technology + +usb:v1631p6200* + ID_MODEL_FROM_DATABASE=GWUSB2E + +usb:v1631pC019* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v1645* + ID_VENDOR_FROM_DATABASE=Cross Match Technologies GmbH + +usb:v1645p0001* + ID_MODEL_FROM_DATABASE=1S Serial Port + +usb:v1645p0002* + ID_MODEL_FROM_DATABASE=2S Serial Port + +usb:v1645p0003* + ID_MODEL_FROM_DATABASE=1S25 Serial Port + +usb:v1645p0004* + ID_MODEL_FROM_DATABASE=4S Serial Port + +usb:v1645p0005* + ID_MODEL_FROM_DATABASE=E45 Ethernet [klsi] + +usb:v1645p0006* + ID_MODEL_FROM_DATABASE=Parallel Port + +usb:v1645p0007* + ID_MODEL_FROM_DATABASE=U1-SC25 SCSI + +usb:v1645p0008* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v1645p0016* + ID_MODEL_FROM_DATABASE=Bi-directional to Parallel Printer Converter + +usb:v1645p0080* + ID_MODEL_FROM_DATABASE=1 port to Serial Converter + +usb:v1645p0081* + ID_MODEL_FROM_DATABASE=1 port to Serial Converter + +usb:v1645p0093* + ID_MODEL_FROM_DATABASE=1S9 Serial Port + +usb:v1645p8000* + ID_MODEL_FROM_DATABASE=EZ-USB + +usb:v1645p8001* + ID_MODEL_FROM_DATABASE=1 port to Serial + +usb:v1645p8002* + ID_MODEL_FROM_DATABASE=2x Serial Port + +usb:v1645p8003* + ID_MODEL_FROM_DATABASE=1 port to Serial + +usb:v1645p8004* + ID_MODEL_FROM_DATABASE=2U4S serial/usb hub + +usb:v1645p8005* + ID_MODEL_FROM_DATABASE=Ethernet + +usb:v1645p8080* + ID_MODEL_FROM_DATABASE=1 port to Serial + +usb:v1645p8081* + ID_MODEL_FROM_DATABASE=1 port to Serial + +usb:v1645p8093* + ID_MODEL_FROM_DATABASE=PortGear Serial Port + +usb:v1649* + ID_VENDOR_FROM_DATABASE=SofTec Microsystems + +usb:v1649p0102* + ID_MODEL_FROM_DATABASE=uDART In-Circuit Debugger + +usb:v1649p0200* + ID_MODEL_FROM_DATABASE=SpYder USBSPYDER08 + +usb:v164A* + ID_VENDOR_FROM_DATABASE=ChipX + +usb:v164C* + ID_VENDOR_FROM_DATABASE=Matrix Vision GmbH + +usb:v164Cp0101* + ID_MODEL_FROM_DATABASE=mvBlueFOX camera (no firmware) + +usb:v164Cp0103* + ID_MODEL_FROM_DATABASE=mvBlueFOX camera + +usb:v164Cp0201* + ID_MODEL_FROM_DATABASE=mvBlueLYNX-X intelligent camera (bootloader) + +usb:v164Cp0203* + ID_MODEL_FROM_DATABASE=mvBlueLYNX-X intelligent camera + +usb:v1657* + ID_VENDOR_FROM_DATABASE=Struck Innovative Systeme GmbH + +usb:v1657p3150* + ID_MODEL_FROM_DATABASE=SIS3150 USB2.0 to VME interface + +usb:v165B* + ID_VENDOR_FROM_DATABASE=Frontier Design Group + +usb:v165Bp8101* + ID_MODEL_FROM_DATABASE=Tranzport Control Surface + +usb:v165BpFAD1* + ID_MODEL_FROM_DATABASE=Alphatrack Control Surface + +usb:v165C* + ID_VENDOR_FROM_DATABASE=Kondo Kagaku + +usb:v165Cp0002* + ID_MODEL_FROM_DATABASE=Serial Adapter + +usb:v1660* + ID_VENDOR_FROM_DATABASE=Creatix Polymedia GmbH + +usb:v1668* + ID_VENDOR_FROM_DATABASE=Actiontec Electronics, Inc. [hex] + +usb:v1668p0009* + ID_MODEL_FROM_DATABASE=Gateway + +usb:v1668p0333* + ID_MODEL_FROM_DATABASE=Modem + +usb:v1668p0358* + ID_MODEL_FROM_DATABASE=InternetPhoneWizard + +usb:v1668p0405* + ID_MODEL_FROM_DATABASE=Gateway + +usb:v1668p0408* + ID_MODEL_FROM_DATABASE=Prism2.5 802.11b Adapter + +usb:v1668p0413* + ID_MODEL_FROM_DATABASE=Gateway + +usb:v1668p0421* + ID_MODEL_FROM_DATABASE=Prism2.5 802.11b Adapter + +usb:v1668p0441* + ID_MODEL_FROM_DATABASE=IBM Integrated Bluetooth II + +usb:v1668p0500* + ID_MODEL_FROM_DATABASE=BTM200B BlueTooth Adapter + +usb:v1668p1050* + ID_MODEL_FROM_DATABASE=802UIG-1 802.11g Wireless Mini Adapter [Intersil ISL3887] + +usb:v1668p1200* + ID_MODEL_FROM_DATABASE=802AIN Wireless N Network Adapter [Atheros AR9170+AR9101] + +usb:v1668p1441* + ID_MODEL_FROM_DATABASE=IBM Integrated Bluetooth II + +usb:v1668p2441* + ID_MODEL_FROM_DATABASE=BMDC-2 IBM Bluetooth III w.56k + +usb:v1668p3441* + ID_MODEL_FROM_DATABASE=IBM Integrated Bluetooth III + +usb:v1668p6010* + ID_MODEL_FROM_DATABASE=Gateway + +usb:v1668p6097* + ID_MODEL_FROM_DATABASE=802.11b Wireless Adapter + +usb:v1668p6106* + ID_MODEL_FROM_DATABASE=802UI3(B) 802.11b Wireless Adapter [Intersil PRISM 3] + +usb:v1668p7605* + ID_MODEL_FROM_DATABASE=UAT1 Wireless Ethernet Adapter + +usb:v1669* + ID_VENDOR_FROM_DATABASE=PiKRON Ltd. [hex] + +usb:v1669p1001* + ID_MODEL_FROM_DATABASE=uLan2USB Converter - PS1 protocol + +usb:v166A* + ID_VENDOR_FROM_DATABASE=Clipsal + +usb:v166Ap0101* + ID_MODEL_FROM_DATABASE=C-Bus Multi-room Audio Matrix Switcher + +usb:v166Ap0201* + ID_MODEL_FROM_DATABASE=C-Bus Pascal Automation Controller + +usb:v166Ap0301* + ID_MODEL_FROM_DATABASE=C-Bus Wireless PC Interface + +usb:v166Ap0303* + ID_MODEL_FROM_DATABASE=C-Bus interface + +usb:v166Ap0304* + ID_MODEL_FROM_DATABASE=C-Bus Black and White Touchscreen + +usb:v166Ap0305* + ID_MODEL_FROM_DATABASE=C-Bus Spectrum Colour Touchscreen + +usb:v166Ap0401* + ID_MODEL_FROM_DATABASE=C-Bus Architectural Dimmer + +usb:v1677* + ID_VENDOR_FROM_DATABASE=China Huada Integrated Circuit Design (Group) Co., Ltd. (CIDC Group) + +usb:v1677p0103* + ID_MODEL_FROM_DATABASE=Token + +usb:v1679* + ID_VENDOR_FROM_DATABASE=Total Phase + +usb:v1679p2001* + ID_MODEL_FROM_DATABASE=Beagle Protocol Analyzer + +usb:v1679p2002* + ID_MODEL_FROM_DATABASE=Cheetah SPI Host Adapter + +usb:v1680* + ID_VENDOR_FROM_DATABASE=Golden Bridge Electech Inc. + +usb:v1680pA332* + ID_MODEL_FROM_DATABASE=DVB-T Dongle [RTL2832U] + +usb:v1681* + ID_VENDOR_FROM_DATABASE=Prevo Technologies, Inc. + +usb:v1681p0001* + ID_MODEL_FROM_DATABASE=Tuner's Dashboard + +usb:v1681p0002* + ID_MODEL_FROM_DATABASE=Tubachron + +usb:v1682* + ID_VENDOR_FROM_DATABASE=Maxwise Production Enterprise Ltd. + +usb:v1684* + ID_VENDOR_FROM_DATABASE=Godspeed Computer Corp. + +usb:v1685* + ID_VENDOR_FROM_DATABASE=Delock + +usb:v1685p0200* + ID_MODEL_FROM_DATABASE=Infrared adapter + +usb:v1686* + ID_VENDOR_FROM_DATABASE=ZOOM Corporation + +usb:v1686p0045* + ID_MODEL_FROM_DATABASE=H4 Digital Recorder + +usb:v1687* + ID_VENDOR_FROM_DATABASE=Kingmax Digital Inc. + +usb:v1687p5289* + ID_MODEL_FROM_DATABASE=FlashDisk + +usb:v1687p6211* + ID_MODEL_FROM_DATABASE=FlashDisk + +usb:v1688* + ID_VENDOR_FROM_DATABASE=Saab AB + +usb:v1689* + ID_VENDOR_FROM_DATABASE=Razer USA, Ltd + +usb:v1689pFD00* + ID_MODEL_FROM_DATABASE=Onza Tournament Edition controller + +usb:v168C* + ID_VENDOR_FROM_DATABASE=Atheros Communications + +usb:v168Cp0001* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v168Cp0002* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v1690* + ID_VENDOR_FROM_DATABASE=Askey Computer Corp. [hex] + +usb:v1690p0001* + ID_MODEL_FROM_DATABASE=Arcaze Gamepad + +usb:v1690p0101* + ID_MODEL_FROM_DATABASE=Creative Modem Blaster DE5670 + +usb:v1690p0102* + ID_MODEL_FROM_DATABASE=V1456 VQE-R2 Modem [conexant] + +usb:v1690p0103* + ID_MODEL_FROM_DATABASE=1456 VQE-R3 Modem [conexant] + +usb:v1690p0104* + ID_MODEL_FROM_DATABASE=HCF V90 Data Fax RTAD Modem + +usb:v1690p0107* + ID_MODEL_FROM_DATABASE=HCF V.90 Data,Fax,RTAD Modem + +usb:v1690p0109* + ID_MODEL_FROM_DATABASE=MagicXpress V.90 Pocket Modem [conexant] + +usb:v1690p0203* + ID_MODEL_FROM_DATABASE=Voyager ADSL Modem Loader + +usb:v1690p0204* + ID_MODEL_FROM_DATABASE=Voyager ADSL Modem + +usb:v1690p0205* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v1690p0206* + ID_MODEL_FROM_DATABASE=GlobeSpan ADSL WAN Modem + +usb:v1690p0208* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v1690p0209* + ID_MODEL_FROM_DATABASE=Voyager 100 ADSL Modem + +usb:v1690p0211* + ID_MODEL_FROM_DATABASE=Globespan Virata ADSL LAN Modem + +usb:v1690p0212* + ID_MODEL_FROM_DATABASE=DSL Modem + +usb:v1690p0213* + ID_MODEL_FROM_DATABASE=HM121d DSL Modem + +usb:v1690p0214* + ID_MODEL_FROM_DATABASE=HM121d DSL Modem + +usb:v1690p0215* + ID_MODEL_FROM_DATABASE=Voyager 105 ADSL Modem + +usb:v1690p0701* + ID_MODEL_FROM_DATABASE=WLAN + +usb:v1690p0710* + ID_MODEL_FROM_DATABASE=SMCWUSBT-G + +usb:v1690p0711* + ID_MODEL_FROM_DATABASE=SMCWUSBT-G (no firmware) + +usb:v1690p0712* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v1690p0713* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v1690p0715* + ID_MODEL_FROM_DATABASE=Name: Voyager 1055 Laptop 802.11g Adapter [Broadcom 4320] + +usb:v1690p0722* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v1690p0726* + ID_MODEL_FROM_DATABASE=Wi-Fi Wireless LAN Adapter + +usb:v1690p0740* + ID_MODEL_FROM_DATABASE=802.11n Wireless LAN Card + +usb:v1690p0901* + ID_MODEL_FROM_DATABASE=Voyager 205 ADSL Router + +usb:v1696* + ID_VENDOR_FROM_DATABASE=Hitachi Video and Information System, Inc. + +usb:v1697* + ID_VENDOR_FROM_DATABASE=VTec Test, Inc. + +usb:v16A5* + ID_VENDOR_FROM_DATABASE=Shenzhen Zhengerya Cable Co., Ltd. + +usb:v16A6* + ID_VENDOR_FROM_DATABASE=Unigraf + +usb:v16A6p3000* + ID_MODEL_FROM_DATABASE=VTG-3xxx Video Test Generator family + +usb:v16A6p4000* + ID_MODEL_FROM_DATABASE=VTG-4xxx Video Test Generator family + +usb:v16A6p5000* + ID_MODEL_FROM_DATABASE=VTG-5xxx Video Test Generator family + +usb:v16A6p5001* + ID_MODEL_FROM_DATABASE=VTG-5xxx Special (update) mode of VTG-5xxx family + +usb:v16AB* + ID_VENDOR_FROM_DATABASE=Global Sun Technology + +usb:v16ABp7801* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v16ABp7802* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v16ABp7811* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:v16ABp7812* + ID_MODEL_FROM_DATABASE=AR5523 (no firmware) + +usb:v16AC* + ID_VENDOR_FROM_DATABASE=Dongguan ChingLung Wire & Cable Co., Ltd. + +usb:v16B4* + ID_VENDOR_FROM_DATABASE=iStation + +usb:v16B4p0801* + ID_MODEL_FROM_DATABASE=U43 + +usb:v16B5* + ID_VENDOR_FROM_DATABASE=Persentec, Inc. + +usb:v16B5p0002* + ID_MODEL_FROM_DATABASE=Otto driving companion + +usb:v16C0* + ID_VENDOR_FROM_DATABASE=Van Ooijen Technische Informatica + +usb:v16C0p03E8* + ID_MODEL_FROM_DATABASE=free for internal lab use 1000 + +usb:v16C0p03E9* + ID_MODEL_FROM_DATABASE=free for internal lab use 1001 + +usb:v16C0p03EA* + ID_MODEL_FROM_DATABASE=free for internal lab use 1002 + +usb:v16C0p03EB* + ID_MODEL_FROM_DATABASE=free for internal lab use 1003 + +usb:v16C0p03EC* + ID_MODEL_FROM_DATABASE=free for internal lab use 1004 + +usb:v16C0p03ED* + ID_MODEL_FROM_DATABASE=free for internal lab use 1005 + +usb:v16C0p03EE* + ID_MODEL_FROM_DATABASE=free for internal lab use 1006 + +usb:v16C0p03EF* + ID_MODEL_FROM_DATABASE=free for internal lab use 1007 + +usb:v16C0p03F0* + ID_MODEL_FROM_DATABASE=free for internal lab use 1008 + +usb:v16C0p03F1* + ID_MODEL_FROM_DATABASE=free for internal lab use 1009 + +usb:v16C0p0477* + ID_MODEL_FROM_DATABASE=Teensy Rebootor + +usb:v16C0p0478* + ID_MODEL_FROM_DATABASE=Teensy Halfkay Bootloader + +usb:v16C0p0479* + ID_MODEL_FROM_DATABASE=Teensy Debug + +usb:v16C0p047A* + ID_MODEL_FROM_DATABASE=Teensy Serial + +usb:v16C0p047B* + ID_MODEL_FROM_DATABASE=Teensy Serial+Debug + +usb:v16C0p047C* + ID_MODEL_FROM_DATABASE=Teensy Keyboard + +usb:v16C0p047D* + ID_MODEL_FROM_DATABASE=Teensy Keyboard+Debug + +usb:v16C0p047E* + ID_MODEL_FROM_DATABASE=Teensy Mouse + +usb:v16C0p047F* + ID_MODEL_FROM_DATABASE=Teensy Mouse+Debug + +usb:v16C0p0480* + ID_MODEL_FROM_DATABASE=Teensy RawHID + +usb:v16C0p0481* + ID_MODEL_FROM_DATABASE=Teensy RawHID+Debug + +usb:v16C0p0482* + ID_MODEL_FROM_DATABASE=Teensyduino Keyboard+Mouse+Joystick + +usb:v16C0p0483* + ID_MODEL_FROM_DATABASE=Teensyduino Serial + +usb:v16C0p0484* + ID_MODEL_FROM_DATABASE=Teensyduino Disk + +usb:v16C0p0485* + ID_MODEL_FROM_DATABASE=Teensyduino MIDI + +usb:v16C0p0486* + ID_MODEL_FROM_DATABASE=Teensyduino RawHID + +usb:v16C0p0487* + ID_MODEL_FROM_DATABASE=Teensyduino Serial+Keyboard+Mouse+Joystick + +usb:v16C0p0488* + ID_MODEL_FROM_DATABASE=Teensyduino Flight Sim Controls + +usb:v16C0p05DC* + ID_MODEL_FROM_DATABASE=shared ID for use with libusb + +usb:v16C0p05DD* + ID_MODEL_FROM_DATABASE=BlackcatUSB2 + +usb:v16C0p05DF* + ID_MODEL_FROM_DATABASE=HID device except mice, keyboards, and joysticks + +usb:v16C0p05E1* + ID_MODEL_FROM_DATABASE=Free shared USB VID/PID pair for CDC devices + +usb:v16C0p05E4* + ID_MODEL_FROM_DATABASE=Free shared USB VID/PID pair for MIDI devices + +usb:v16C0p06B4* + ID_MODEL_FROM_DATABASE=USB2LPT with 2 interfaces + +usb:v16C0p06B5* + ID_MODEL_FROM_DATABASE=USB2LPT with 3 interfaces (native, HID, printer) + +usb:v16C0p076B* + ID_MODEL_FROM_DATABASE=OpenPCD 13.56MHz RFID Reader + +usb:v16C0p076C* + ID_MODEL_FROM_DATABASE=OpenPICC 13.56MHz RFID Simulator (native) + +usb:v16C0p08AC* + ID_MODEL_FROM_DATABASE=OpenBeacon USB stick + +usb:v16C0p08CA* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Universal Display + +usb:v16C0p08CB* + ID_MODEL_FROM_DATABASE=Alpermann+Velte Studio Clock + +usb:v16C0p08CC* + ID_MODEL_FROM_DATABASE=Alpermann+Velte SAM7S MT Boot Loader + +usb:v16C0p08CD* + ID_MODEL_FROM_DATABASE=Alpermann+Velte SAM7X MT Boot Loader + +usb:v16C0p0A32* + ID_MODEL_FROM_DATABASE=jbmedia Light-Manager Pro + +usb:v16C0p27D8* + ID_MODEL_FROM_DATABASE=libusb-bound devices + +usb:v16C0p27D9* + ID_MODEL_FROM_DATABASE=HID device except mice, keyboards, and joysticks + +usb:v16C0p27DA* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v16C0p27DB* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v16C0p27DC* + ID_MODEL_FROM_DATABASE=Joystick + +usb:v16C0p27DD* + ID_MODEL_FROM_DATABASE=CDC-ACM class devices (modems) + +usb:v16C0p27DE* + ID_MODEL_FROM_DATABASE=MIDI class devices + +usb:v16C0p294A* + ID_MODEL_FROM_DATABASE=Eye Movement Recorder [Visagraph] + +usb:v16C0p294B* + ID_MODEL_FROM_DATABASE=Eye Movement Recorder [ReadAlyzer] + +usb:v16CA* + ID_VENDOR_FROM_DATABASE=Wireless Cables, Inc. + +usb:v16CAp1502* + ID_MODEL_FROM_DATABASE=Bluetooth Dongle + +usb:v16CC* + ID_VENDOR_FROM_DATABASE=silex technology, Inc. + +usb:v16D0* + ID_VENDOR_FROM_DATABASE=MCS + +usb:v16D0p0498* + ID_MODEL_FROM_DATABASE=Braintechnology USB-LPS + +usb:v16D0p0504* + ID_MODEL_FROM_DATABASE=RETRO Innovations ZoomFloppy + +usb:v16D0p054B* + ID_MODEL_FROM_DATABASE=GrauTec ReelBox OLED Display (external) + +usb:v16D0p05BE* + ID_MODEL_FROM_DATABASE=EasyLogic Board + +usb:v16D0p06F9* + ID_MODEL_FROM_DATABASE=Gabotronics Xminilab + +usb:v16D0p0753* + ID_MODEL_FROM_DATABASE=Digistump DigiSpark + +usb:v16D0p075C* + ID_MODEL_FROM_DATABASE=AB-1.x UAC1 [Audio Widget] + +usb:v16D0p075D* + ID_MODEL_FROM_DATABASE=AB-1.x UAC2 [Audio Widget] + +usb:v16D0p080A* + ID_MODEL_FROM_DATABASE=S2E1 Interface + +usb:v16D3* + ID_VENDOR_FROM_DATABASE=Frontline Test Equipment, Inc. + +usb:v16D5* + ID_VENDOR_FROM_DATABASE=AnyDATA Corporation + +usb:v16D5p6202* + ID_MODEL_FROM_DATABASE=CDMA/UMTS/GPRS modem + +usb:v16D5p6501* + ID_MODEL_FROM_DATABASE=CDMA 2000 1xRTT/EV-DO Modem + +usb:v16D5p6502* + ID_MODEL_FROM_DATABASE=CDMA/UMTS/GPRS modem + +usb:v16D6* + ID_VENDOR_FROM_DATABASE=JABLOCOM s.r.o. + +usb:v16D6p8000* + ID_MODEL_FROM_DATABASE=GDP-04 desktop phone + +usb:v16D6p8001* + ID_MODEL_FROM_DATABASE=EYE-02 + +usb:v16D6p8003* + ID_MODEL_FROM_DATABASE=GDP-04 modem + +usb:v16D6p8004* + ID_MODEL_FROM_DATABASE=Bootloader + +usb:v16D6p8005* + ID_MODEL_FROM_DATABASE=GDP-04i + +usb:v16D6p8007* + ID_MODEL_FROM_DATABASE=BTP-06 modem + +usb:v16D8* + ID_VENDOR_FROM_DATABASE=CMOTECH Co., Ltd. + +usb:v16D8p5141* + ID_MODEL_FROM_DATABASE=CMOTECH CDMA Technologies modem + +usb:v16D8p5533* + ID_MODEL_FROM_DATABASE=CCU-550 CDMA EV-DO modem + +usb:v16D8p5543* + ID_MODEL_FROM_DATABASE=CDMA 2000 1xRTT/1xEVDO modem + +usb:v16D8p6280* + ID_MODEL_FROM_DATABASE=CMOTECH CDMA Technologies modem + +usb:v16D8p6803* + ID_MODEL_FROM_DATABASE=CNU-680 CDMA EV-DO modem + +usb:v16D8p8001* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem (QDL mode) + +usb:v16D8p8002* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v16DC* + ID_VENDOR_FROM_DATABASE=Wiener, Plein & Baus + +usb:v16DCp0001* + ID_MODEL_FROM_DATABASE=CC + +usb:v16DCp000B* + ID_MODEL_FROM_DATABASE=VM + +usb:v16DCp0010* + ID_MODEL_FROM_DATABASE=PL512 Power Supply System + +usb:v16DCp0011* + ID_MODEL_FROM_DATABASE=MARATON Power Supply System + +usb:v16DCp0012* + ID_MODEL_FROM_DATABASE=MPOD Multi Channel Power Supply System + +usb:v16DCp0015* + ID_MODEL_FROM_DATABASE=CML Control, Measurement and Data Logging System + +usb:v16DF* + ID_VENDOR_FROM_DATABASE=King Billion Electronics Co., Ltd. + +usb:v16F0* + ID_VENDOR_FROM_DATABASE=GN ReSound A/S + +usb:v16F0p0001* + ID_MODEL_FROM_DATABASE=Speedlink Programming Interface + +usb:v16F0p0003* + ID_MODEL_FROM_DATABASE=Airlink Wireless Programming Interface + +usb:v16F5* + ID_VENDOR_FROM_DATABASE=Futurelogic Inc. + +usb:v1706* + ID_VENDOR_FROM_DATABASE=BlueView Technologies, Inc. + +usb:v1707* + ID_VENDOR_FROM_DATABASE=ARTIMI + +usb:v170B* + ID_VENDOR_FROM_DATABASE=Swissonic + +usb:v170Bp0011* + ID_MODEL_FROM_DATABASE=MIDI-USB 1x1 + +usb:v170D* + ID_VENDOR_FROM_DATABASE=Avnera + +usb:v1725* + ID_VENDOR_FROM_DATABASE=Vitesse Semiconductor + +usb:v1726* + ID_VENDOR_FROM_DATABASE=Axesstel, Inc. + +usb:v1726p1000* + ID_MODEL_FROM_DATABASE=wireless modem + +usb:v1726p2000* + ID_MODEL_FROM_DATABASE=wireless modem + +usb:v1726p3000* + ID_MODEL_FROM_DATABASE=wireless modem + +usb:v172F* + ID_VENDOR_FROM_DATABASE=Waltop International Corp. + +usb:v172Fp0022* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v172Fp0024* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v172Fp0025* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v172Fp0026* + ID_MODEL_FROM_DATABASE=Tablet + +usb:v172Fp0031* + ID_MODEL_FROM_DATABASE=Slim Tablet 12.1" + +usb:v172Fp0032* + ID_MODEL_FROM_DATABASE=Slim Tablet 5.8" + +usb:v172Fp0034* + ID_MODEL_FROM_DATABASE=Slim Tablet 12.1" + +usb:v172Fp0038* + ID_MODEL_FROM_DATABASE=Genius G-Pen F509 + +usb:v172Fp0500* + ID_MODEL_FROM_DATABASE=Media Tablet 14.1" + +usb:v172Fp0501* + ID_MODEL_FROM_DATABASE=Media Tablet 10.6" + +usb:v172Fp0502* + ID_MODEL_FROM_DATABASE=Sirius Battery Free Tablet + +usb:v1733* + ID_VENDOR_FROM_DATABASE=Cellink Technology Co., Ltd + +usb:v1733p0101* + ID_MODEL_FROM_DATABASE=RF Wireless Optical Mouse OP-701 + +usb:v1736* + ID_VENDOR_FROM_DATABASE=CANON IMAGING SYSTEM TECHNOLOGIES INC. + +usb:v1737* + ID_VENDOR_FROM_DATABASE=Linksys + +usb:v1737p0039* + ID_MODEL_FROM_DATABASE=USB1000 Gigabit Notebook Adapter + +usb:v1737p0070* + ID_MODEL_FROM_DATABASE=WUSB100 v1 RangePlus Wireless Network Adapter [Ralink RT2870] + +usb:v1737p0071* + ID_MODEL_FROM_DATABASE=WUSB600N v1 Dual-Band Wireless-N Network Adapter [Ralink RT2870] + +usb:v1737p0073* + ID_MODEL_FROM_DATABASE=WUSB54GC v2 802.11g Adapter [Realtek RTL8187B] + +usb:v1737p0075* + ID_MODEL_FROM_DATABASE=WUSB54GSC v2 802.11g Adapter [Broadcom 4326U] + +usb:v1737p0077* + ID_MODEL_FROM_DATABASE=WUSB54GC v3 802.11g Adapter [Ralink RT2070L] + +usb:v1737p0078* + ID_MODEL_FROM_DATABASE=WUSB100 v2 RangePlus Wireless Network Adapter [Ralink RT3070] + +usb:v1737p0079* + ID_MODEL_FROM_DATABASE=WUSB600N v2 Dual-Band Wireless-N Network Adapter [Ralink RT3572] + +usb:v1740* + ID_VENDOR_FROM_DATABASE=Senao + +usb:v1740p0605* + ID_MODEL_FROM_DATABASE=LevelOne WUA-0605 N_Max Wireless USB Adapter + +usb:v1740p0615* + ID_MODEL_FROM_DATABASE=LevelOne WUA-0615 N_Max Wireless USB Adapter + +usb:v1740p1000* + ID_MODEL_FROM_DATABASE=NUB-350 802.11g Wireless Adapter [Intersil ISL3887] + +usb:v1740p2000* + ID_MODEL_FROM_DATABASE=NUB-8301 802.11bg + +usb:v1740p3701* + ID_MODEL_FROM_DATABASE=EUB-3701 EXT 802.11g Wireless Adapter [Ralink RT2571W] + +usb:v1740p9603* + ID_MODEL_FROM_DATABASE=RTL8188S WLAN Adapter + +usb:v1740p9701* + ID_MODEL_FROM_DATABASE=EnGenius 802.11n Wireless USB Adapter + +usb:v1740p9702* + ID_MODEL_FROM_DATABASE=EnGenius 802.11n Wireless USB Adapter + +usb:v1740p9703* + ID_MODEL_FROM_DATABASE=EnGenius 802.11n Wireless USB Adapter + +usb:v1740p9705* + ID_MODEL_FROM_DATABASE=EnGenius 802.11n Wireless USB Adapter + +usb:v1740p9706* + ID_MODEL_FROM_DATABASE=EUB9706 802.11n Wireless Adapter [Ralink RT3072] + +usb:v1740p9801* + ID_MODEL_FROM_DATABASE=EUB9801 802.11abgn Wireless Adapter [Ralink RT3572] + +usb:v1743* + ID_VENDOR_FROM_DATABASE=General Atomics + +usb:v174C* + ID_VENDOR_FROM_DATABASE=ASMedia Technology Inc. + +usb:v174Cp5106* + ID_MODEL_FROM_DATABASE=Transcend StoreJet 25M3 + +usb:v174Cp55AA* + ID_MODEL_FROM_DATABASE=ASMedia 2105 SATA bridge + +usb:v174F* + ID_VENDOR_FROM_DATABASE=Syntek + +usb:v174Fp1105* + ID_MODEL_FROM_DATABASE=SM-MS/Pro-MMC-XD Card Reader + +usb:v174Fp110B* + ID_MODEL_FROM_DATABASE=HP Webcam + +usb:v174Fp1403* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v174Fp1404* + ID_MODEL_FROM_DATABASE=USB Camera device, 1.3 MPixel Web Cam + +usb:v174Fp5212* + ID_MODEL_FROM_DATABASE=USB 2.0 UVC PC Camera + +usb:v174Fp5A11* + ID_MODEL_FROM_DATABASE=PC Camera + +usb:v174Fp5A31* + ID_MODEL_FROM_DATABASE=Sonix USB 2.0 Camera + +usb:v174Fp5A35* + ID_MODEL_FROM_DATABASE=Sonix 1.3MPixel USB 2.0 Camera + +usb:v174Fp6A31* + ID_MODEL_FROM_DATABASE=Web Cam - Asus A8J, F3S, F5R, VX2S, V1S + +usb:v174Fp6A33* + ID_MODEL_FROM_DATABASE=Web Cam - Asus F3SA, F9J, F9S + +usb:v174Fp6A51* + ID_MODEL_FROM_DATABASE=2.0MPixel Web Cam - Asus Z96J, Z96S, S96S + +usb:v174Fp6A54* + ID_MODEL_FROM_DATABASE=Web Cam + +usb:v174Fp6D51* + ID_MODEL_FROM_DATABASE=2.0Mpixel Web Cam - Eurocom D900C + +usb:v174Fp8A12* + ID_MODEL_FROM_DATABASE=Syntek 0.3MPixel USB 2.0 UVC PC Camera + +usb:v174Fp8A33* + ID_MODEL_FROM_DATABASE=Syntek USB 2.0 UVC PC Camera + +usb:v174FpA311* + ID_MODEL_FROM_DATABASE=1.3MPixel Web Cam - Asus A3A, A6J, A6K, A6M, A6R, A6T, A6V, A7T, A7sv, A7U + +usb:v174FpA312* + ID_MODEL_FROM_DATABASE=1.3MPixel Web Cam + +usb:v174FpA821* + ID_MODEL_FROM_DATABASE=Web Cam - Packard Bell BU45, PB Easynote MX66-208W + +usb:v174FpAA11* + ID_MODEL_FROM_DATABASE=Web Cam + +usb:v1753* + ID_VENDOR_FROM_DATABASE=GERTEC Telecomunicacoes Ltda. + +usb:v1753pC901* + ID_MODEL_FROM_DATABASE=PPC900 Pinpad Terminal + +usb:v1756* + ID_VENDOR_FROM_DATABASE=ENENSYS Technologies + +usb:v1756p0006* + ID_MODEL_FROM_DATABASE=DiviPitch + +usb:v1759* + ID_VENDOR_FROM_DATABASE=LucidPort Technology, Inc. + +usb:v1761* + ID_VENDOR_FROM_DATABASE=ASUSTek Computer, Inc. (wrong ID) + +usb:v1761p0B05* + ID_MODEL_FROM_DATABASE=802.11n Network Adapter (wrong ID - swapped vendor and device) + +usb:v1772* + ID_VENDOR_FROM_DATABASE=System Level Solutions, Inc. + +usb:v1776* + ID_VENDOR_FROM_DATABASE=Arowana + +usb:v1776p501C* + ID_MODEL_FROM_DATABASE=300K CMOS Camera + +usb:v177F* + ID_VENDOR_FROM_DATABASE=Sweex + +usb:v177Fp0004* + ID_MODEL_FROM_DATABASE=MM004V5 Photo Key Chain (Digital Photo Frame) 1.5" + +usb:v177Fp0153* + ID_MODEL_FROM_DATABASE=LW153 802.11n Adapter [ralink rt3070] + +usb:v177Fp0154* + ID_MODEL_FROM_DATABASE=LW154 802.11bgn (1x1:1) Wireless Adapter [Realtek RTL8188SU] + +usb:v177Fp0313* + ID_MODEL_FROM_DATABASE=LW313 802.11n Adapter [ralink rt2770 + rt2720] + +usb:v1781* + ID_VENDOR_FROM_DATABASE=Multiple Vendors + +usb:v1781p083E* + ID_MODEL_FROM_DATABASE=MetaGeek Wi-Spy + +usb:v1781p083F* + ID_MODEL_FROM_DATABASE=MetaGeek Wi-Spy 2.4x + +usb:v1781p0938* + ID_MODEL_FROM_DATABASE=Iguanaworks USB IR Transceiver + +usb:v1781p0C30* + ID_MODEL_FROM_DATABASE=Telldus TellStick + +usb:v1781p0C31* + ID_MODEL_FROM_DATABASE=Telldus TellStick Duo + +usb:v1781p0C9F* + ID_MODEL_FROM_DATABASE=USBtiny + +usb:v1782* + ID_VENDOR_FROM_DATABASE=Spreadtrum Communications Inc. + +usb:v1784* + ID_VENDOR_FROM_DATABASE=TopSeed Technology Corp. + +usb:v1784p0001* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1784p0004* + ID_MODEL_FROM_DATABASE=RF Combo Device + +usb:v1784p0006* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1784p0007* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1784p0008* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1784p000A* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1784p0011* + ID_MODEL_FROM_DATABASE=eHome Infrared Transceiver + +usb:v1787* + ID_VENDOR_FROM_DATABASE=ATI AIB + +usb:v1788* + ID_VENDOR_FROM_DATABASE=ShenZhen Litkconn Technology Co., Ltd. + +usb:v1796* + ID_VENDOR_FROM_DATABASE=Printrex, Inc. + +usb:v1797* + ID_VENDOR_FROM_DATABASE=JALCO CO., LTD. + +usb:v1799* + ID_VENDOR_FROM_DATABASE=Thales Norway A/S + +usb:v1799p7051* + ID_MODEL_FROM_DATABASE=Belkin F5D7051 802.11g Adapter v1000 [Broadcom 4320] + +usb:v1799p8051* + ID_MODEL_FROM_DATABASE=Belkin F5D8051 v2 802.11bgn Wireless Adapter [Marvell 88W8362] + +usb:v179D* + ID_VENDOR_FROM_DATABASE=Ricavision International, Inc. + +usb:v179Dp0010* + ID_MODEL_FROM_DATABASE=Internal Infrared Transceiver + +usb:v17A0* + ID_VENDOR_FROM_DATABASE=Samson Technologies Corp. + +usb:v17A0p0001* + ID_MODEL_FROM_DATABASE=C01U condenser microphone + +usb:v17A0p0002* + ID_MODEL_FROM_DATABASE=Q1U dynamic microphone + +usb:v17A0p0100* + ID_MODEL_FROM_DATABASE=C03U multi-pattern microphone + +usb:v17A0p0101* + ID_MODEL_FROM_DATABASE=UB1 boundary microphone + +usb:v17A0p0200* + ID_MODEL_FROM_DATABASE=StudioDock monitors (internal hub) + +usb:v17A0p0201* + ID_MODEL_FROM_DATABASE=StudioDock monitors (audio) + +usb:v17A0p0210* + ID_MODEL_FROM_DATABASE=StudioGT monitors + +usb:v17A0p0301* + ID_MODEL_FROM_DATABASE=Q2U handheld microphone with XLR + +usb:v17A0p0302* + ID_MODEL_FROM_DATABASE=GoMic compact condenser microphone + +usb:v17A0p0304* + ID_MODEL_FROM_DATABASE=Q2U handheld mic with XLR + +usb:v17A0p0305* + ID_MODEL_FROM_DATABASE=GoMic compact condenser mic + +usb:v17A0p0310* + ID_MODEL_FROM_DATABASE=Meteor condenser microphone + +usb:v17A4* + ID_VENDOR_FROM_DATABASE=Concept2 + +usb:v17A4p0001* + ID_MODEL_FROM_DATABASE=Performance Monitor 3 + +usb:v17A4p0002* + ID_MODEL_FROM_DATABASE=Performance Monitor 4 + +usb:v17A5* + ID_VENDOR_FROM_DATABASE=Advanced Connection Technology Inc. + +usb:v17A7* + ID_VENDOR_FROM_DATABASE=MICOMSOFT CO., LTD. + +usb:v17A8* + ID_VENDOR_FROM_DATABASE=Kamstrup A/S + +usb:v17A8p0001* + ID_MODEL_FROM_DATABASE=Optical Eye/3-wire + +usb:v17A8p0005* + ID_MODEL_FROM_DATABASE=M-Bus Master MultiPort 250D + +usb:v17B3* + ID_VENDOR_FROM_DATABASE=Grey Innovation + +usb:v17B3p0004* + ID_MODEL_FROM_DATABASE=Linux-USB Midi Gadget + +usb:v17B5* + ID_VENDOR_FROM_DATABASE=Lunatone + +usb:v17B5p0010* + ID_MODEL_FROM_DATABASE=MFT Sensor + +usb:v17BA* + ID_VENDOR_FROM_DATABASE=SAURIS GmbH + +usb:v17BAp0001* + ID_MODEL_FROM_DATABASE=SAU510-USB [no firmware] + +usb:v17BAp0510* + ID_MODEL_FROM_DATABASE=SAU510-USB and SAU510-USB plus JTAG Emulators + +usb:v17BAp0511* + ID_MODEL_FROM_DATABASE=SAU510-USB Iso Plus JTAG Emulator + +usb:v17BAp0520* + ID_MODEL_FROM_DATABASE=SAU510-USB Nano JTAG Emulator + +usb:v17BAp1511* + ID_MODEL_FROM_DATABASE=Onboard Emulator on SAUModule development kit + +usb:v17C3* + ID_VENDOR_FROM_DATABASE=Singim International Corp. + +usb:v17CC* + ID_VENDOR_FROM_DATABASE=Native Instruments + +usb:v17CCp041C* + ID_MODEL_FROM_DATABASE=Audio 2 DJ + +usb:v17CCp0808* + ID_MODEL_FROM_DATABASE=Maschine Controller + +usb:v17CCp0815* + ID_MODEL_FROM_DATABASE=Audio Kontrol 1 + +usb:v17CCp0839* + ID_MODEL_FROM_DATABASE=Audio 4 DJ + +usb:v17CCp0D8D* + ID_MODEL_FROM_DATABASE=Guitarrig Mobile + +usb:v17CCp1915* + ID_MODEL_FROM_DATABASE=Session I/O + +usb:v17CCp1940* + ID_MODEL_FROM_DATABASE=RigKontrol3 + +usb:v17CCp1969* + ID_MODEL_FROM_DATABASE=RigKontrol2 + +usb:v17CCp1978* + ID_MODEL_FROM_DATABASE=Audio 8 DJ + +usb:v17CCp2280* + ID_MODEL_FROM_DATABASE=Medion MDPNA1500 in card reader mode + +usb:v17CCp2305* + ID_MODEL_FROM_DATABASE=Traktor Kontrol X1 + +usb:v17CCp4711* + ID_MODEL_FROM_DATABASE=Kore Controller + +usb:v17CCp4712* + ID_MODEL_FROM_DATABASE=Kore Controller 2 + +usb:v17CCpBAFF* + ID_MODEL_FROM_DATABASE=Traktor Kontrol S4 + +usb:v17CF* + ID_VENDOR_FROM_DATABASE=Hip Hing Cable & Plug Mfy. Ltd. + +usb:v17D0* + ID_VENDOR_FROM_DATABASE=Sanford L.P. + +usb:v17D3* + ID_VENDOR_FROM_DATABASE=Korea Techtron Co., Ltd. + +usb:v17E9* + ID_VENDOR_FROM_DATABASE=DisplayLink + +usb:v17E9p0051* + ID_MODEL_FROM_DATABASE=USB VGA Adaptor + +usb:v17E9p030B* + ID_MODEL_FROM_DATABASE=HP T100 + +usb:v17E9p0377* + ID_MODEL_FROM_DATABASE=Plugable UD-160-A (M) + +usb:v17E9p0378* + ID_MODEL_FROM_DATABASE=Plugable UGA-2K-A + +usb:v17E9p0379* + ID_MODEL_FROM_DATABASE=Plugable UGA-125 + +usb:v17E9p037A* + ID_MODEL_FROM_DATABASE=Plugable UGA-165 + +usb:v17E9p037B* + ID_MODEL_FROM_DATABASE=Plugable USB-VGA-165 + +usb:v17E9p037C* + ID_MODEL_FROM_DATABASE=Plugable DC-125 + +usb:v17E9p037D* + ID_MODEL_FROM_DATABASE=Plugable USB2-HDMI-165 + +usb:v17E9p430A* + ID_MODEL_FROM_DATABASE=HP Port Replicator (Composite Device) + +usb:v17E9p4312* + ID_MODEL_FROM_DATABASE=S2340T + +usb:v17EB* + ID_VENDOR_FROM_DATABASE=Cornice, Inc. + +usb:v17EF* + ID_VENDOR_FROM_DATABASE=Lenovo + +usb:v17EFp1003* + ID_MODEL_FROM_DATABASE=Integrated Smart Card Reader + +usb:v17EFp1004* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v17EFp1008* + ID_MODEL_FROM_DATABASE=Hub + +usb:v17EFp100A* + ID_MODEL_FROM_DATABASE=ThinkPad Mini Dock Plus Series 3 + +usb:v17EFp3815* + ID_MODEL_FROM_DATABASE=ChipsBnk 2GB USB Stick + +usb:v17EFp4802* + ID_MODEL_FROM_DATABASE=Lenovo Vc0323+MI1310_SOC Camera + +usb:v17EFp4807* + ID_MODEL_FROM_DATABASE=UVC Camera + +usb:v17EFp480C* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v17EFp480D* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp480E* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp480F* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4810* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4811* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4812* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4813* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4814* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4815* + ID_MODEL_FROM_DATABASE=Integrated Webcam [R5U877] + +usb:v17EFp4816* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v17EFp481C* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v17EFp481D* + ID_MODEL_FROM_DATABASE=Integrated Webcam + +usb:v17EFp6004* + ID_MODEL_FROM_DATABASE=ISD-V4 Tablet Pen + +usb:v17EFp6007* + ID_MODEL_FROM_DATABASE=Smartcard Keyboard + +usb:v17EFp6009* + ID_MODEL_FROM_DATABASE=ThinkPad Keyboard with TrackPoint + +usb:v17EFp6014* + ID_MODEL_FROM_DATABASE=Mini Wireless Keyboard N5901 + +usb:v17EFp7423* + ID_MODEL_FROM_DATABASE=IdeaPad A1 Tablet + +usb:v17EFp7435* + ID_MODEL_FROM_DATABASE=A789 (Mass Storage mode, with debug) + +usb:v17EFp743A* + ID_MODEL_FROM_DATABASE=A789 (Mass Storage mode) + +usb:v17EFp7497* + ID_MODEL_FROM_DATABASE=A789 (MTP mode) + +usb:v17EFp7498* + ID_MODEL_FROM_DATABASE=A789 (MTP mode, with debug) + +usb:v17EFp749A* + ID_MODEL_FROM_DATABASE=A789 (PTP mode) + +usb:v17EFp749B* + ID_MODEL_FROM_DATABASE=A789 (PTP mode, with debug) + +usb:v17F4* + ID_VENDOR_FROM_DATABASE=WaveSense + +usb:v17F4pAAAA* + ID_MODEL_FROM_DATABASE=Jazz Blood Glucose Meter + +usb:v17F5* + ID_VENDOR_FROM_DATABASE=K.K. Rocky + +usb:v17F6* + ID_VENDOR_FROM_DATABASE=Unicomp, Inc + +usb:v17F6p0709* + ID_MODEL_FROM_DATABASE=Model M Keyboard + +usb:v1809* + ID_VENDOR_FROM_DATABASE=Advantech + +usb:v1809p4604* + ID_MODEL_FROM_DATABASE=USB-4604 + +usb:v1809p4761* + ID_MODEL_FROM_DATABASE=USB-4761 Portable Data Acquisition Module + +usb:v1822* + ID_VENDOR_FROM_DATABASE=Twinhan + +usb:v1822p3201* + ID_MODEL_FROM_DATABASE=VisionDTV USB-Ter/HAMA USB DVB-T device cold + +usb:v1822p3202* + ID_MODEL_FROM_DATABASE=VisionDTV USB-Ter/HAMA USB DVB-T device warm + +usb:v1831* + ID_VENDOR_FROM_DATABASE=Gwo Jinn Industries Co., Ltd. + +usb:v1832* + ID_VENDOR_FROM_DATABASE=Huizhou Shenghua Industrial Co., Ltd. + +usb:v183D* + ID_VENDOR_FROM_DATABASE=VIVOphone + +usb:v183Dp0010* + ID_MODEL_FROM_DATABASE=VoiceKey + +usb:v1843* + ID_VENDOR_FROM_DATABASE=Vaisala + +usb:v1849* + ID_VENDOR_FROM_DATABASE=ASRock Incorporation + +usb:v1852* + ID_VENDOR_FROM_DATABASE=GYROCOM C&C Co., LTD + +usb:v1852p7922* + ID_MODEL_FROM_DATABASE=Audiotrak DR.DAC2 DX [GYROCOM C&C] + +usb:v1854* + ID_VENDOR_FROM_DATABASE=Memory Devices Ltd. + +usb:v185B* + ID_VENDOR_FROM_DATABASE=Compro + +usb:v185Bp3020* + ID_MODEL_FROM_DATABASE=K100 Infrared Receiver + +usb:v185Bp3082* + ID_MODEL_FROM_DATABASE=K100 Infrared Receiver v2 + +usb:v185BpD000* + ID_MODEL_FROM_DATABASE=Compro Videomate DVB-U2000 - DVB-T USB cold + +usb:v185BpD001* + ID_MODEL_FROM_DATABASE=Compro Videomate DVB-U2000 - DVB-T USB warm + +usb:v1861* + ID_VENDOR_FROM_DATABASE=Tech Technology Industrial Company + +usb:v1862* + ID_VENDOR_FROM_DATABASE=Teridian Semiconductor Corp. + +usb:v1870* + ID_VENDOR_FROM_DATABASE=Nexio Co., Ltd + +usb:v1870p0001* + ID_MODEL_FROM_DATABASE=iNexio Touchscreen controller + +usb:v1871* + ID_VENDOR_FROM_DATABASE=Aveo Technology Corp. + +usb:v1871p0101* + ID_MODEL_FROM_DATABASE=UVC camera (Bresser microscope) + +usb:v1871p0D01* + ID_MODEL_FROM_DATABASE=USB2.0 Camera + +usb:v1873* + ID_VENDOR_FROM_DATABASE=Navilock + +usb:v1873pEE93* + ID_MODEL_FROM_DATABASE=EasyLogger + +usb:v187C* + ID_VENDOR_FROM_DATABASE=Alienware Corporation + +usb:v187Cp0511* + ID_MODEL_FROM_DATABASE=AlienFX Mobile lighting + +usb:v187Cp0600* + ID_MODEL_FROM_DATABASE=Dual Compatible Game Pad + +usb:v187F* + ID_VENDOR_FROM_DATABASE=Siano Mobile Silicon + +usb:v187Fp0010* + ID_MODEL_FROM_DATABASE=Stallar Board + +usb:v187Fp0100* + ID_MODEL_FROM_DATABASE=Stallar Board + +usb:v187Fp0200* + ID_MODEL_FROM_DATABASE=Nova A + +usb:v187Fp0201* + ID_MODEL_FROM_DATABASE=Nova B + +usb:v187Fp0202* + ID_MODEL_FROM_DATABASE=Nice + +usb:v187Fp0300* + ID_MODEL_FROM_DATABASE=Vega + +usb:v187Fp0301* + ID_MODEL_FROM_DATABASE=VeNice + +usb:v1892* + ID_VENDOR_FROM_DATABASE=Vast Technologies, Inc. + +usb:v1894* + ID_VENDOR_FROM_DATABASE=Topseed + +usb:v1894p5632* + ID_MODEL_FROM_DATABASE=Atek Tote Remote + +usb:v1894p5641* + ID_MODEL_FROM_DATABASE=TSAM-004 Presentation Remote + +usb:v1897* + ID_VENDOR_FROM_DATABASE=Evertop Wire Cable Co. + +usb:v189F* + ID_VENDOR_FROM_DATABASE=3Shape A/S + +usb:v189Fp0002* + ID_MODEL_FROM_DATABASE=Legato2 3D Scanner + +usb:v18A4* + ID_VENDOR_FROM_DATABASE=CSSN + +usb:v18A4p0001* + ID_MODEL_FROM_DATABASE=Snapshell IDR + +usb:v18A5* + ID_VENDOR_FROM_DATABASE=Verbatim, Ltd + +usb:v18A5p0214* + ID_MODEL_FROM_DATABASE=Portable Hard Drive + +usb:v18A5p0216* + ID_MODEL_FROM_DATABASE=External Hard Drive + +usb:v18A5p0218* + ID_MODEL_FROM_DATABASE=External Hard Drive + +usb:v18A5p0227* + ID_MODEL_FROM_DATABASE=Pocket Hard Drive + +usb:v18A5p022B* + ID_MODEL_FROM_DATABASE=Portable Hard Drive (Store'n'Go) + +usb:v18A5p0237* + ID_MODEL_FROM_DATABASE=Portable Harddrive (500 GB) + +usb:v18A5p0302* + ID_MODEL_FROM_DATABASE=Flash Drive + +usb:v18B1* + ID_VENDOR_FROM_DATABASE=Petalynx + +usb:v18B1p0037* + ID_MODEL_FROM_DATABASE=Maxter Remote Control + +usb:v18B4* + ID_VENDOR_FROM_DATABASE=e3C Technologies + +usb:v18B4p1001* + ID_MODEL_FROM_DATABASE=DUTV007 + +usb:v18B4p1002* + ID_MODEL_FROM_DATABASE=EC168 (v5) based USB DVB-T receiver + +usb:v18B4p1689* + ID_MODEL_FROM_DATABASE=DUTV009 + +usb:v18B4pFFFA* + ID_MODEL_FROM_DATABASE=EC168 (v2) based USB DVB-T receiver + +usb:v18B4pFFFB* + ID_MODEL_FROM_DATABASE=EC168 (v3) based USB DVB-T receiver + +usb:v18B6* + ID_VENDOR_FROM_DATABASE=Mikkon Technology Limited + +usb:v18B7* + ID_VENDOR_FROM_DATABASE=Zotek Electronic Co., Ltd. + +usb:v18C5* + ID_VENDOR_FROM_DATABASE=AMIT Technology, Inc. + +usb:v18C5p0002* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GO + +usb:v18C5p0008* + ID_MODEL_FROM_DATABASE=CG-WLUSB2GNR Corega Wireless USB Adapter + +usb:v18C5p0012* + ID_MODEL_FROM_DATABASE=CG-WLUSB10 Corega Wireless USB Adapter + +usb:v18CD* + ID_VENDOR_FROM_DATABASE=Ecamm + +usb:v18CDpCAFE* + ID_MODEL_FROM_DATABASE=Pico iMage + +usb:v18D1* + ID_VENDOR_FROM_DATABASE=Google Inc. + +usb:v18D1p0D02* + ID_MODEL_FROM_DATABASE=Celkon A88 + +usb:v18D1p2D00* + ID_MODEL_FROM_DATABASE=Android-powered device in accessory mode + +usb:v18D1p2D01* + ID_MODEL_FROM_DATABASE=Android-powered device in accessory mode with ADB support + +usb:v18D1p4E11* + ID_MODEL_FROM_DATABASE=Nexus One + +usb:v18D1p4E12* + ID_MODEL_FROM_DATABASE=Nexus One (debug) + +usb:v18D1p4E13* + ID_MODEL_FROM_DATABASE=Nexus One (tether) + +usb:v18D1p4E20* + ID_MODEL_FROM_DATABASE=Nexus S (fastboot) + +usb:v18D1p4E21* + ID_MODEL_FROM_DATABASE=Nexus S + +usb:v18D1p4E22* + ID_MODEL_FROM_DATABASE=Nexus S (debug) + +usb:v18D1p4E24* + ID_MODEL_FROM_DATABASE=Nexus S (tether) + +usb:v18D1p4E40* + ID_MODEL_FROM_DATABASE=Nexus 7 (fastboot) + +usb:v18D1p4E41* + ID_MODEL_FROM_DATABASE=Nexus 7 (MTP) + +usb:v18D1p4E42* + ID_MODEL_FROM_DATABASE=Nexus 7 (debug) + +usb:v18D1p4E43* + ID_MODEL_FROM_DATABASE=Nexus 7 (PTP) + +usb:v18D1p4EE1* + ID_MODEL_FROM_DATABASE=Nexus 4 / 10 + +usb:v18D1p4EE2* + ID_MODEL_FROM_DATABASE=Nexus 4 (debug) + +usb:v18D1p4EE3* + ID_MODEL_FROM_DATABASE=Nexus 4 (tether) + +usb:v18D1p4EE4* + ID_MODEL_FROM_DATABASE=Nexus 4 (debug + tether) + +usb:v18D1p7102* + ID_MODEL_FROM_DATABASE=Toshiba Thrive tablet + +usb:v18D1pB004* + ID_MODEL_FROM_DATABASE=Pandigital / B&N Novel 9" tablet + +usb:v18D1pD109* + ID_MODEL_FROM_DATABASE=LG G2x MTP + +usb:v18D1pD10A* + ID_MODEL_FROM_DATABASE=LG G2x MTP (debug) + +usb:v18D5* + ID_VENDOR_FROM_DATABASE=Starline International Group Limited + +usb:v18D9* + ID_VENDOR_FROM_DATABASE=Kaba + +usb:v18D9p01A0* + ID_MODEL_FROM_DATABASE=B-Net 91 07 + +usb:v18DC* + ID_VENDOR_FROM_DATABASE=LKC Technologies, Inc. + +usb:v18DD* + ID_VENDOR_FROM_DATABASE=Planon System Solutions Inc. + +usb:v18DDp1000* + ID_MODEL_FROM_DATABASE=DocuPen RC800 + +usb:v18E3* + ID_VENDOR_FROM_DATABASE=Fitipower Integrated Technology Inc + +usb:v18E3p7102* + ID_MODEL_FROM_DATABASE=Multi Card Reader (Internal) + +usb:v18E3p9101* + ID_MODEL_FROM_DATABASE=All-in-1 Card Reader + +usb:v18E3p9102* + ID_MODEL_FROM_DATABASE=Multi Card Reader + +usb:v18E3p9512* + ID_MODEL_FROM_DATABASE=Webcam + +usb:v18E8* + ID_VENDOR_FROM_DATABASE=Qcom + +usb:v18E8p6144* + ID_MODEL_FROM_DATABASE=LR802UA 802.11b Wireless Adapter [ALi M4301AU] + +usb:v18E8p6196* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v18E8p6229* + ID_MODEL_FROM_DATABASE=RT2573 + +usb:v18E8p6232* + ID_MODEL_FROM_DATABASE=Wireless 802.11g 54Mbps Network Adapter [RTL8187] + +usb:v18EA* + ID_VENDOR_FROM_DATABASE=Matrox Graphics, Inc. + +usb:v18EAp0002* + ID_MODEL_FROM_DATABASE=DualHead2Go [Analog Edition] + +usb:v18EAp0004* + ID_MODEL_FROM_DATABASE=TripleHead2Go [Digital Edition] + +usb:v18EC* + ID_VENDOR_FROM_DATABASE=Arkmicro Technologies Inc. + +usb:v18ECp3118* + ID_MODEL_FROM_DATABASE=USB to IrDA adapter [ARK3116T] + +usb:v18ECp3188* + ID_MODEL_FROM_DATABASE=ARK3188 UVC Webcam + +usb:v18ECp3299* + ID_MODEL_FROM_DATABASE=Webcam Carrefour + +usb:v18ECp3366* + ID_MODEL_FROM_DATABASE=Bresser Biolux NV + +usb:v18FD* + ID_VENDOR_FROM_DATABASE=FineArch Inc. + +usb:v1908* + ID_VENDOR_FROM_DATABASE=GEMBIRD + +usb:v1908p1320* + ID_MODEL_FROM_DATABASE=PhotoFrame PF-15-1 + +usb:v190D* + ID_VENDOR_FROM_DATABASE=Motorola GSG + +usb:v1914* + ID_VENDOR_FROM_DATABASE=Alco Digital Devices Limited + +usb:v1915* + ID_VENDOR_FROM_DATABASE=Nordic Semiconductor ASA + +usb:v1915p000C* + ID_MODEL_FROM_DATABASE=Wireless Desktop nRF24L01 CX-1766 + +usb:v1915p2233* + ID_MODEL_FROM_DATABASE=Linksys WUSB11 v2.8 802.11b Adapter [Atmel AT76C505] + +usb:v1915p2234* + ID_MODEL_FROM_DATABASE=Linksys WUSB54G v1 OEM 802.11g Adapter [Intersil ISL3886] + +usb:v1915p2235* + ID_MODEL_FROM_DATABASE=Linksys WUSB54GP v1 OEM 802.11g Adapter [Intersil ISL3886] + +usb:v1915p2236* + ID_MODEL_FROM_DATABASE=Linksys WUSB11 v3.0 802.11b Adapter [Intersil PRISM 3] + +usb:v1923* + ID_VENDOR_FROM_DATABASE=FitLinxx + +usb:v1923p0002* + ID_MODEL_FROM_DATABASE=Personal SyncPoint + +usb:v1926* + ID_VENDOR_FROM_DATABASE=NextWindow + +usb:v1926p0003* + ID_MODEL_FROM_DATABASE=1900 HID Touchscreen + +usb:v1926p0006* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0064* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0065* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0066* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0067* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0068* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0069* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0071* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0072* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0073* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0074* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0075* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0076* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0077* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0078* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0079* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p007A* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p007E* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p007F* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0080* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0081* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0082* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0083* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0084* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0085* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0086* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0087* + ID_MODEL_FROM_DATABASE=1950 HID Touchscreen + +usb:v1926p0DC2* + ID_MODEL_FROM_DATABASE=HID Touchscreen + +usb:v192F* + ID_VENDOR_FROM_DATABASE=Avago Technologies, Pte. + +usb:v192Fp0000* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v192Fp0416* + ID_MODEL_FROM_DATABASE=ADNS-5700 Optical Mouse Controller (3-button) + +usb:v192Fp0616* + ID_MODEL_FROM_DATABASE=ADNS-5700 Optical Mouse Controller (5-button) + +usb:v1930* + ID_VENDOR_FROM_DATABASE=Shenzhen Xianhe Technology Co., Ltd. + +usb:v1931* + ID_VENDOR_FROM_DATABASE=Ningbo Broad Telecommunication Co., Ltd. + +usb:v1934* + ID_VENDOR_FROM_DATABASE=Feature Integration Technology Inc. (Fintek) + +usb:v1934p0602* + ID_MODEL_FROM_DATABASE=F71610 or F71612 Consumer Infrared Receiver/Transceiver + +usb:v1934p0702* + ID_MODEL_FROM_DATABASE=Integrated Consumer Infrared Receiver/Transceiver + +usb:v1934p5168* + ID_MODEL_FROM_DATABASE=F71610A or F71612A Consumer Infrared Receiver/Transceiver + +usb:v1941* + ID_VENDOR_FROM_DATABASE=Dream Link + +usb:v1941p8021* + ID_MODEL_FROM_DATABASE=WH1080 Weather Station / USB Missile Launcher + +usb:v1943* + ID_VENDOR_FROM_DATABASE=Sensoray Co., Inc. + +usb:v1943p2250* + ID_MODEL_FROM_DATABASE=Model 2250 MPEG and JPEG Capture Card + +usb:v1943p2253* + ID_MODEL_FROM_DATABASE=Model 2253 Audio/Video Codec Card + +usb:v1943p2255* + ID_MODEL_FROM_DATABASE=Model 2255 4 Channel Capture Card + +usb:v1943p2257* + ID_MODEL_FROM_DATABASE=Model 2257 4 Channel Capture Card + +usb:v1943pA250* + ID_MODEL_FROM_DATABASE=Model 2250 MPEG and JPEG Capture Card (cold) + +usb:v1943pA253* + ID_MODEL_FROM_DATABASE=Model 2253 Audio/Video Codec Card (cold) + +usb:v1949* + ID_VENDOR_FROM_DATABASE=Lab126, Inc. + +usb:v1949p0002* + ID_MODEL_FROM_DATABASE=Amazon Kindle + +usb:v1949p0004* + ID_MODEL_FROM_DATABASE=Amazon Kindle 3/4/Paperwhite + +usb:v1949p0006* + ID_MODEL_FROM_DATABASE=Kindle Fire + +usb:v1949p0008* + ID_MODEL_FROM_DATABASE=Amazon Kindle Fire HD 8.9" + +usb:v194F* + ID_VENDOR_FROM_DATABASE=PreSonus Audio Electronics, Inc. + +usb:v194Fp0101* + ID_MODEL_FROM_DATABASE=AudioBox 22 VSL + +usb:v194Fp0102* + ID_MODEL_FROM_DATABASE=AudioBox 44 VSL + +usb:v194Fp0103* + ID_MODEL_FROM_DATABASE=AudioBox 1818 VSL + +usb:v194Fp0301* + ID_MODEL_FROM_DATABASE=AudioBox + +usb:v1951* + ID_VENDOR_FROM_DATABASE=Hyperstone AG + +usb:v1953* + ID_VENDOR_FROM_DATABASE=Ironkey Inc. + +usb:v1953p0202* + ID_MODEL_FROM_DATABASE=S200 2GB Rev. 1 + +usb:v1954* + ID_VENDOR_FROM_DATABASE=Radiient Technologies + +usb:v195D* + ID_VENDOR_FROM_DATABASE=Itron Technology iONE + +usb:v195Dp7002* + ID_MODEL_FROM_DATABASE=Libra-Q11 IR remote + +usb:v195Dp7006* + ID_MODEL_FROM_DATABASE=Libra-Q26 / 1.0 Remote + +usb:v195Dp7777* + ID_MODEL_FROM_DATABASE=Scorpius wireless keyboard + +usb:v195Dp7779* + ID_MODEL_FROM_DATABASE=Scorpius-P20MT + +usb:v1965* + ID_VENDOR_FROM_DATABASE=Uniden Corporation + +usb:v1965p0016* + ID_MODEL_FROM_DATABASE=HomePatrol-1 + +usb:v1967* + ID_VENDOR_FROM_DATABASE=CASIO HITACHI Mobile Communications Co., Ltd. + +usb:v196B* + ID_VENDOR_FROM_DATABASE=Wispro Technology Inc. + +usb:v1970* + ID_VENDOR_FROM_DATABASE=Dane-Elec Corp. USA + +usb:v1970p0000* + ID_MODEL_FROM_DATABASE=Z Mate 16GB + +usb:v1975* + ID_VENDOR_FROM_DATABASE=Dongguan Guneetal Wire & Cable Co., Ltd. + +usb:v1976* + ID_VENDOR_FROM_DATABASE=Chipsbrand Microelectronics (HK) Co., Ltd. + +usb:v1976p6025* + ID_MODEL_FROM_DATABASE=Flash Drive 512 MB + +usb:v1977* + ID_VENDOR_FROM_DATABASE=T-Logic + +usb:v1977p0111* + ID_MODEL_FROM_DATABASE=TL203 MP3 Player and Voice Recorder + +usb:v197D* + ID_VENDOR_FROM_DATABASE=Leuze electronic + +usb:v197Dp0222* + ID_MODEL_FROM_DATABASE=BCL 508i + +usb:v1989* + ID_VENDOR_FROM_DATABASE=Nuconn Technology Corp. + +usb:v198F* + ID_VENDOR_FROM_DATABASE=Beceem Communications Inc. + +usb:v198Fp0210* + ID_MODEL_FROM_DATABASE=BCS200 WiMAX Adapter + +usb:v198Fp0220* + ID_MODEL_FROM_DATABASE=BCSM250 WiMAX Adapter + +usb:v1990* + ID_VENDOR_FROM_DATABASE=Acron Precision Industrial Co., Ltd. + +usb:v1995* + ID_VENDOR_FROM_DATABASE=Trillium Technology Pty. Ltd. + +usb:v1995p3202* + ID_MODEL_FROM_DATABASE=REC-ADPT-USB (recorder) + +usb:v1995p3203* + ID_MODEL_FROM_DATABASE=REC-A-ADPT-USB (recorder) + +usb:v199B* + ID_VENDOR_FROM_DATABASE=MicroStrain, Inc. + +usb:v199Bp3065* + ID_MODEL_FROM_DATABASE=3DM-GX3-25 Orientation Sensor + +usb:v199E* + ID_VENDOR_FROM_DATABASE=The Imaging Source Europe GmbH + +usb:v199Ep8101* + ID_MODEL_FROM_DATABASE=DFx 21BU04 Camera + +usb:v199F* + ID_VENDOR_FROM_DATABASE=Benica Corporation + +usb:v19A8* + ID_VENDOR_FROM_DATABASE=Biforst Technology Inc. + +usb:v19AB* + ID_VENDOR_FROM_DATABASE=Bodelin + +usb:v19ABp1000* + ID_MODEL_FROM_DATABASE=ProScope HR + +usb:v19AF* + ID_VENDOR_FROM_DATABASE=S Life + +usb:v19AFp6611* + ID_MODEL_FROM_DATABASE=Celestia VoIP Phone + +usb:v19B2* + ID_VENDOR_FROM_DATABASE=Batronix + +usb:v19B2p0010* + ID_MODEL_FROM_DATABASE=BX32 Batupo + +usb:v19B2p0011* + ID_MODEL_FROM_DATABASE=BX32P Barlino + +usb:v19B2p0012* + ID_MODEL_FROM_DATABASE=BX40 Bagero + +usb:v19B2p0013* + ID_MODEL_FROM_DATABASE=BX48 Batego + +usb:v19B4* + ID_VENDOR_FROM_DATABASE=Celestron + +usb:v19B4p0002* + ID_MODEL_FROM_DATABASE=SkyScout Personal Planetarium + +usb:v19B4p0101* + ID_MODEL_FROM_DATABASE=Handheld Digital Microscope 44302 + +usb:v19B5* + ID_VENDOR_FROM_DATABASE=B & W Group + +usb:v19B6* + ID_VENDOR_FROM_DATABASE=Infotech Logistic, LLC + +usb:v19B9* + ID_VENDOR_FROM_DATABASE=Data Robotics + +usb:v19B9p8D20* + ID_MODEL_FROM_DATABASE=Drobo Elite + +usb:v19C2* + ID_VENDOR_FROM_DATABASE=Futuba + +usb:v19C2p6A11* + ID_MODEL_FROM_DATABASE=MDM166A Fluorescent Display + +usb:v19CA* + ID_VENDOR_FROM_DATABASE=Mindtribe + +usb:v19CAp0001* + ID_MODEL_FROM_DATABASE=Sandio 3D HID Mouse + +usb:v19CF* + ID_VENDOR_FROM_DATABASE=Parrot SA + +usb:v19D2* + ID_VENDOR_FROM_DATABASE=ZTE WCDMA Technologies MSM + +usb:v19D2p0001* + ID_MODEL_FROM_DATABASE=CDMA Wireless Modem + +usb:v19D2p0002* + ID_MODEL_FROM_DATABASE=MF632/ONDA ET502HS/MT505UP + +usb:v19D2p0007* + ID_MODEL_FROM_DATABASE=TU25 WiMAX Adapter [Beceem BCS200] + +usb:v19D2p0031* + ID_MODEL_FROM_DATABASE=MF110/MF627/MF636 + +usb:v19D2p0063* + ID_MODEL_FROM_DATABASE=K3565-Z HSDPA + +usb:v19D2p0064* + ID_MODEL_FROM_DATABASE=MF627 AU + +usb:v19D2p0083* + ID_MODEL_FROM_DATABASE=MF190 + +usb:v19D2p0103* + ID_MODEL_FROM_DATABASE=MF112 + +usb:v19D2p0104* + ID_MODEL_FROM_DATABASE=K4505-Z + +usb:v19D2p0146* + ID_MODEL_FROM_DATABASE=MF 195E (HSPA+ Modem) + +usb:v19D2p0167* + ID_MODEL_FROM_DATABASE=MF820 4G LTE + +usb:v19D2p0172* + ID_MODEL_FROM_DATABASE=AX226 WIMAX MODEM (After Modeswitch) + +usb:v19D2p0325* + ID_MODEL_FROM_DATABASE=LTE4G O2 ZTE MF821D LTE/UMTS/GSM Modem/Networkcard + +usb:v19D2p0326* + ID_MODEL_FROM_DATABASE=LTE4G O2 ZTE MF821D LTE/UMTS/GSM Modem/Networkcard + +usb:v19D2p1008* + ID_MODEL_FROM_DATABASE=K3570-Z + +usb:v19D2p1010* + ID_MODEL_FROM_DATABASE=K3571-Z + +usb:v19D2p1017* + ID_MODEL_FROM_DATABASE=K5006-Z vodafone LTE/UMTS/GSM Modem/Networkcard + +usb:v19D2p1018* + ID_MODEL_FROM_DATABASE=K5006-Z vodafone LTE/UMTS/GSM Modem/Networkcard + +usb:v19D2p1203* + ID_MODEL_FROM_DATABASE=MF691 [ T-Mobile webConnect Rocket 2.0] + +usb:v19D2p1217* + ID_MODEL_FROM_DATABASE=MF652 + +usb:v19D2p1218* + ID_MODEL_FROM_DATABASE=MF652 + +usb:v19D2p2000* + ID_MODEL_FROM_DATABASE=MF627/MF628/MF628+/MF636+ HSDPA/HSUPA + +usb:v19D2pFFF2* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v19D2pFFF3* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v19DB* + ID_VENDOR_FROM_DATABASE=KFI Printers + +usb:v19DBp02F1* + ID_MODEL_FROM_DATABASE=NAUT324C + +usb:v19E1* + ID_VENDOR_FROM_DATABASE=WeiDuan Electronic Accessory (S.Z.) Co., Ltd. + +usb:v19E8* + ID_VENDOR_FROM_DATABASE=Industrial Technology Research Institute + +usb:v19EF* + ID_VENDOR_FROM_DATABASE=Pak Heng Technology (Shenzhen) Co., Ltd. + +usb:v19F7* + ID_VENDOR_FROM_DATABASE=RODE Microphones + +usb:v19F7p0001* + ID_MODEL_FROM_DATABASE=Podcaster + +usb:v19FA* + ID_VENDOR_FROM_DATABASE=Gampaq Co.Ltd + +usb:v19FAp0703* + ID_MODEL_FROM_DATABASE=Steering Wheel + +usb:v19FF* + ID_VENDOR_FROM_DATABASE=Dynex + +usb:v19FFp0102* + ID_MODEL_FROM_DATABASE=1.3MP Webcam + +usb:v19FFp0201* + ID_MODEL_FROM_DATABASE=Rocketfish Wireless 2.4G Laser Mouse + +usb:v19FFp0238* + ID_MODEL_FROM_DATABASE=DX-WRM1401 Mouse + +usb:v1A08* + ID_VENDOR_FROM_DATABASE=Bellwood International, Inc. + +usb:v1A0A* + ID_VENDOR_FROM_DATABASE=USB-IF non-workshop + +usb:v1A0ApBADD* + ID_MODEL_FROM_DATABASE=USB OTG Compliance test device + +usb:v1A12* + ID_VENDOR_FROM_DATABASE=KES Co., Ltd. + +usb:v1A1D* + ID_VENDOR_FROM_DATABASE=Veho + +usb:v1A1Dp0407* + ID_MODEL_FROM_DATABASE=Mimi WiFi speakers + +usb:v1A25* + ID_VENDOR_FROM_DATABASE=Amphenol East Asia Ltd. + +usb:v1A2A* + ID_VENDOR_FROM_DATABASE=Seagate Branded Solutions + +usb:v1A2C* + ID_VENDOR_FROM_DATABASE=China Resource Semico Co., Ltd + +usb:v1A2Cp0021* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v1A2Cp0024* + ID_MODEL_FROM_DATABASE=Multimedia Keyboard + +usb:v1A32* + ID_VENDOR_FROM_DATABASE=Quanta Microsystems, Inc. + +usb:v1A32p0304* + ID_MODEL_FROM_DATABASE=802.11n Wireless LAN Card + +usb:v1A34* + ID_VENDOR_FROM_DATABASE=ACRUX + +usb:v1A34p0802* + ID_MODEL_FROM_DATABASE=Gamepad + +usb:v1A36* + ID_VENDOR_FROM_DATABASE=Biwin Technology Ltd. + +usb:v1A40* + ID_VENDOR_FROM_DATABASE=Terminus Technology Inc. + +usb:v1A40p0101* + ID_MODEL_FROM_DATABASE=Hub + +usb:v1A40p0201* + ID_MODEL_FROM_DATABASE=FE 2.1 7-port Hub + +usb:v1A41* + ID_VENDOR_FROM_DATABASE=Action Electronics Co., Ltd. + +usb:v1A44* + ID_VENDOR_FROM_DATABASE=VASCO Data Security International + +usb:v1A44p0001* + ID_MODEL_FROM_DATABASE=Digipass 905 SmartCard Reader + +usb:v1A4A* + ID_VENDOR_FROM_DATABASE=Silicon Image + +usb:v1A4B* + ID_VENDOR_FROM_DATABASE=SafeBoot International B.V. + +usb:v1A5A* + ID_VENDOR_FROM_DATABASE=Tandberg Data + +usb:v1A61* + ID_VENDOR_FROM_DATABASE=Abbott Diabetes Care + +usb:v1A61p3410* + ID_MODEL_FROM_DATABASE=CoPilot System Cable + +usb:v1A6A* + ID_VENDOR_FROM_DATABASE=Spansion Inc. + +usb:v1A6D* + ID_VENDOR_FROM_DATABASE=SamYoung Electronics Co., Ltd + +usb:v1A6E* + ID_VENDOR_FROM_DATABASE=Global Unichip Corp. + +usb:v1A6F* + ID_VENDOR_FROM_DATABASE=Sagem Orga GmbH + +usb:v1A72* + ID_VENDOR_FROM_DATABASE=Physik Instrumente + +usb:v1A72p1008* + ID_MODEL_FROM_DATABASE=E-861 PiezoWalk NEXACT Controller + +usb:v1A79* + ID_VENDOR_FROM_DATABASE=Bayer Health Care LLC + +usb:v1A79p6002* + ID_MODEL_FROM_DATABASE=Contour + +usb:v1A79p7410* + ID_MODEL_FROM_DATABASE=Contour Next + +usb:v1A7B* + ID_VENDOR_FROM_DATABASE=Lumberg Connect GmbH & Co. KG + +usb:v1A7C* + ID_VENDOR_FROM_DATABASE=Evoluent + +usb:v1A7Cp0068* + ID_MODEL_FROM_DATABASE=VerticalMouse 3 + +usb:v1A7Cp0168* + ID_MODEL_FROM_DATABASE=VerticalMouse 3 Wireless + +usb:v1A7Cp0191* + ID_MODEL_FROM_DATABASE=VerticalMouse 4 + +usb:v1A81* + ID_VENDOR_FROM_DATABASE=Holtek Semiconductor, Inc. + +usb:v1A81p2203* + ID_MODEL_FROM_DATABASE=Laser Gaming mouse + +usb:v1A81p2204* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v1A81p2205* + ID_MODEL_FROM_DATABASE=Laser Mouse + +usb:v1A86* + ID_VENDOR_FROM_DATABASE=QinHeng Electronics + +usb:v1A86p5512* + ID_MODEL_FROM_DATABASE=CH341 in EPP/MEM/I2C mode, EPP/I2C adapter + +usb:v1A86p5523* + ID_MODEL_FROM_DATABASE=CH341 in serial mode, usb to serial port converter + +usb:v1A86p5584* + ID_MODEL_FROM_DATABASE=CH341 in parallel mode, usb to printer port converter + +usb:v1A86p7523* + ID_MODEL_FROM_DATABASE=HL-340 USB-Serial adapter + +usb:v1A86p752D* + ID_MODEL_FROM_DATABASE=CH345 MIDI adapter + +usb:v1A86p7584* + ID_MODEL_FROM_DATABASE=CH340S + +usb:v1A86pE008* + ID_MODEL_FROM_DATABASE=HID-based serial adapater + +usb:v1A89* + ID_VENDOR_FROM_DATABASE=Dynalith Systems Co., Ltd. + +usb:v1A8B* + ID_VENDOR_FROM_DATABASE=SGS Taiwan Ltd. + +usb:v1A8D* + ID_VENDOR_FROM_DATABASE=BandRich, Inc. + +usb:v1A8Dp1002* + ID_MODEL_FROM_DATABASE=BandLuxe 3.5G HSDPA Adapter + +usb:v1A8Dp1009* + ID_MODEL_FROM_DATABASE=BandLuxe 3.5G HSPA Adapter + +usb:v1A8Dp100D* + ID_MODEL_FROM_DATABASE=4G LTE adapter + +usb:v1A98* + ID_VENDOR_FROM_DATABASE=Leica Camera AG + +usb:v1AA4* + ID_VENDOR_FROM_DATABASE=Data Drive Thru, Inc. + +usb:v1AA5* + ID_VENDOR_FROM_DATABASE=UBeacon Technologies, Inc. + +usb:v1AA6* + ID_VENDOR_FROM_DATABASE=eFortune Technology Corp. + +usb:v1AAD* + ID_VENDOR_FROM_DATABASE=KeeTouch + +usb:v1AADp0001* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v1AB1* + ID_VENDOR_FROM_DATABASE=Rigol Technologies + +usb:v1AB1p0588* + ID_MODEL_FROM_DATABASE=DS1000 SERIES + +usb:v1ACB* + ID_VENDOR_FROM_DATABASE=Salcomp Plc + +usb:v1ACC* + ID_VENDOR_FROM_DATABASE=Midiplus Co, Ltd. + +usb:v1ACCp0103* + ID_MODEL_FROM_DATABASE=AudioLink plus 4x4 2.9.28 + +usb:v1AD1* + ID_VENDOR_FROM_DATABASE=Desay Wire Co., Ltd. + +usb:v1AD4* + ID_VENDOR_FROM_DATABASE=APS + +usb:v1AD4p0002* + ID_MODEL_FROM_DATABASE=KM290-HRS + +usb:v1ADB* + ID_VENDOR_FROM_DATABASE=SEL C662 Serial Cable + +usb:v1AE4* + ID_VENDOR_FROM_DATABASE=ic-design Reinhard Gottinger GmbH + +usb:v1AE7* + ID_VENDOR_FROM_DATABASE=X-TENSIONS + +usb:v1AE7p0381* + ID_MODEL_FROM_DATABASE=VS-DVB-T 380U (af9015 based) + +usb:v1AE7p2001* + ID_MODEL_FROM_DATABASE=SpeedLink Snappy Mic webcam (SL-6825-SBK) + +usb:v1AE7p9003* + ID_MODEL_FROM_DATABASE=SpeedLink Vicious And Devine Laplace webcam, white (VD-1504-SWT) + +usb:v1AE7p9004* + ID_MODEL_FROM_DATABASE=SpeedLink Vicious And Devine Laplace webcam, black (VD-1504-SBK) + +usb:v1AED* + ID_VENDOR_FROM_DATABASE=High Top Precision Electronic Co., Ltd. + +usb:v1AEF* + ID_VENDOR_FROM_DATABASE=Conntech Electronic (Suzhou) Corporation + +usb:v1AF1* + ID_VENDOR_FROM_DATABASE=Connect One Ltd. + +usb:v1AFE* + ID_VENDOR_FROM_DATABASE=A. Eberle GmbH & Co. KG + +usb:v1AFEp0001* + ID_MODEL_FROM_DATABASE=PQ Box 100 + +usb:v1B04* + ID_VENDOR_FROM_DATABASE=Meilhaus Electronic GmbH + +usb:v1B04p0630* + ID_MODEL_FROM_DATABASE=ME-630 + +usb:v1B04p0940* + ID_MODEL_FROM_DATABASE=ME-94 + +usb:v1B04p0950* + ID_MODEL_FROM_DATABASE=ME-95 + +usb:v1B04p0960* + ID_MODEL_FROM_DATABASE=ME-96 + +usb:v1B04p1000* + ID_MODEL_FROM_DATABASE=ME-1000 + +usb:v1B04p100A* + ID_MODEL_FROM_DATABASE=ME-1000 + +usb:v1B04p100B* + ID_MODEL_FROM_DATABASE=ME-1000 + +usb:v1B04p1400* + ID_MODEL_FROM_DATABASE=ME-1400 + +usb:v1B04p140A* + ID_MODEL_FROM_DATABASE=ME-1400A + +usb:v1B04p140B* + ID_MODEL_FROM_DATABASE=ME-1400B + +usb:v1B04p140C* + ID_MODEL_FROM_DATABASE=ME-1400C + +usb:v1B04p140D* + ID_MODEL_FROM_DATABASE=ME-1400D + +usb:v1B04p140E* + ID_MODEL_FROM_DATABASE=ME-1400E + +usb:v1B04p14EA* + ID_MODEL_FROM_DATABASE=ME-1400EA + +usb:v1B04p14EB* + ID_MODEL_FROM_DATABASE=ME-1400EB + +usb:v1B04p1604* + ID_MODEL_FROM_DATABASE=ME-1600/4U + +usb:v1B04p1608* + ID_MODEL_FROM_DATABASE=ME-1600/8U + +usb:v1B04p160C* + ID_MODEL_FROM_DATABASE=ME-1600/12U + +usb:v1B04p160F* + ID_MODEL_FROM_DATABASE=ME-1600/16U + +usb:v1B04p168F* + ID_MODEL_FROM_DATABASE=ME-1600/16U8I + +usb:v1B04p4610* + ID_MODEL_FROM_DATABASE=ME-4610 + +usb:v1B04p4650* + ID_MODEL_FROM_DATABASE=ME-4650 + +usb:v1B04p4660* + ID_MODEL_FROM_DATABASE=ME-4660 + +usb:v1B04p4661* + ID_MODEL_FROM_DATABASE=ME-4660I + +usb:v1B04p4662* + ID_MODEL_FROM_DATABASE=ME-4660 + +usb:v1B04p4663* + ID_MODEL_FROM_DATABASE=ME-4660I + +usb:v1B04p4670* + ID_MODEL_FROM_DATABASE=ME-4670 + +usb:v1B04p4671* + ID_MODEL_FROM_DATABASE=ME-4670I + +usb:v1B04p4672* + ID_MODEL_FROM_DATABASE=ME-4670S + +usb:v1B04p4673* + ID_MODEL_FROM_DATABASE=ME-4670IS + +usb:v1B04p4680* + ID_MODEL_FROM_DATABASE=ME-4680 + +usb:v1B04p4681* + ID_MODEL_FROM_DATABASE=ME-4680I + +usb:v1B04p4682* + ID_MODEL_FROM_DATABASE=ME-4680S + +usb:v1B04p4683* + ID_MODEL_FROM_DATABASE=ME-4680IS + +usb:v1B04p6004* + ID_MODEL_FROM_DATABASE=ME-6000/4 + +usb:v1B04p6008* + ID_MODEL_FROM_DATABASE=ME-6000/8 + +usb:v1B04p600F* + ID_MODEL_FROM_DATABASE=ME-6000/16 + +usb:v1B04p6014* + ID_MODEL_FROM_DATABASE=ME-6000I/4 + +usb:v1B04p6018* + ID_MODEL_FROM_DATABASE=ME-6000I/8 + +usb:v1B04p601F* + ID_MODEL_FROM_DATABASE=ME-6000I/16 + +usb:v1B04p6034* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/4 + +usb:v1B04p6038* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/8 + +usb:v1B04p603F* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/16 + +usb:v1B04p6044* + ID_MODEL_FROM_DATABASE=ME-6000/4/DIO + +usb:v1B04p6048* + ID_MODEL_FROM_DATABASE=ME-6000/8/DIO + +usb:v1B04p604F* + ID_MODEL_FROM_DATABASE=ME-6000/16/DIO + +usb:v1B04p6054* + ID_MODEL_FROM_DATABASE=ME-6000I/4/DIO + +usb:v1B04p6058* + ID_MODEL_FROM_DATABASE=ME-6000I/8/DIO + +usb:v1B04p605F* + ID_MODEL_FROM_DATABASE=ME-6000I/16/DIO + +usb:v1B04p6074* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/4/DIO + +usb:v1B04p6078* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/8/DIO + +usb:v1B04p607F* + ID_MODEL_FROM_DATABASE=ME-6000ISLE/16/DIO + +usb:v1B04p6104* + ID_MODEL_FROM_DATABASE=ME-6100/4 + +usb:v1B04p6108* + ID_MODEL_FROM_DATABASE=ME-6100/8 + +usb:v1B04p610F* + ID_MODEL_FROM_DATABASE=ME-6100/16 + +usb:v1B04p6114* + ID_MODEL_FROM_DATABASE=ME-6100I/4 + +usb:v1B04p6118* + ID_MODEL_FROM_DATABASE=ME-6100I/8 + +usb:v1B04p611F* + ID_MODEL_FROM_DATABASE=ME-6100I/16 + +usb:v1B04p6134* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/4 + +usb:v1B04p6138* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/8 + +usb:v1B04p613F* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/16 + +usb:v1B04p6144* + ID_MODEL_FROM_DATABASE=ME-6100/4/DIO + +usb:v1B04p6148* + ID_MODEL_FROM_DATABASE=ME-6100/8/DIO + +usb:v1B04p614F* + ID_MODEL_FROM_DATABASE=ME-6100/16/DIO + +usb:v1B04p6154* + ID_MODEL_FROM_DATABASE=ME-6100I/4/DIO + +usb:v1B04p6158* + ID_MODEL_FROM_DATABASE=ME-6100I/8/DIO + +usb:v1B04p615F* + ID_MODEL_FROM_DATABASE=ME-6100I/16/DIO + +usb:v1B04p6174* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/4/DIO + +usb:v1B04p6178* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/8/DIO + +usb:v1B04p617F* + ID_MODEL_FROM_DATABASE=ME-6100ISLE/16/DIO + +usb:v1B04p6259* + ID_MODEL_FROM_DATABASE=ME-6200I/9/DIO + +usb:v1B04p6359* + ID_MODEL_FROM_DATABASE=ME-6300I/9/DIO + +usb:v1B04p810A* + ID_MODEL_FROM_DATABASE=ME-8100A + +usb:v1B04p810B* + ID_MODEL_FROM_DATABASE=ME-8100B + +usb:v1B04p820A* + ID_MODEL_FROM_DATABASE=ME-8200A + +usb:v1B04p820B* + ID_MODEL_FROM_DATABASE=ME-8200B + +usb:v1B0E* + ID_VENDOR_FROM_DATABASE=BLUTRONICS S.r.l. + +usb:v1B0Ep1078* + ID_MODEL_FROM_DATABASE=BLUDRIVE II CCID + +usb:v1B0Ep1079* + ID_MODEL_FROM_DATABASE=BLUDRIVE II CCID + +usb:v1B0Ep1080* + ID_MODEL_FROM_DATABASE=WRITECHIP II CCID + +usb:v1B1C* + ID_VENDOR_FROM_DATABASE=Corsair + +usb:v1B1Cp0890* + ID_MODEL_FROM_DATABASE=Flash Padlock + +usb:v1B1Cp0A00* + ID_MODEL_FROM_DATABASE=SP2500 Speakers + +usb:v1B1Cp0A60* + ID_MODEL_FROM_DATABASE=Vengeance K60 Keyboard + +usb:v1B1Cp1A01* + ID_MODEL_FROM_DATABASE=Flash Voyager GT + +usb:v1B1Cp1A0A* + ID_MODEL_FROM_DATABASE=Survivor Stealth Flash Drive + +usb:v1B1Cp1A90* + ID_MODEL_FROM_DATABASE=Flash Voyager GT + +usb:v1B20* + ID_VENDOR_FROM_DATABASE=MStar Semiconductor, Inc. + +usb:v1B22* + ID_VENDOR_FROM_DATABASE=WiLinx Corp. + +usb:v1B26* + ID_VENDOR_FROM_DATABASE=Cellex Power Products, Inc. + +usb:v1B27* + ID_VENDOR_FROM_DATABASE=Current Electronics Inc. + +usb:v1B28* + ID_VENDOR_FROM_DATABASE=NAVIsis Inc. + +usb:v1B32* + ID_VENDOR_FROM_DATABASE=Ugobe Life Forms, Inc. + +usb:v1B32p0064* + ID_MODEL_FROM_DATABASE=Pleo robotic dinosaur + +usb:v1B36* + ID_VENDOR_FROM_DATABASE=ViXS Systems, Inc. + +usb:v1B3B* + ID_VENDOR_FROM_DATABASE=iPassion Technology Inc. + +usb:v1B3Bp2933* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2935* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2936* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2937* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2938* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2939* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2950* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2951* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2952* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2953* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2955* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2956* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2957* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2958* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2959* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2960* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2961* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2962* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2963* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2965* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2966* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2967* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2968* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3Bp2969* + ID_MODEL_FROM_DATABASE=PC Camera/Webcam controller + +usb:v1B3F* + ID_VENDOR_FROM_DATABASE=Generalplus Technology Inc. + +usb:v1B3Fp0C52* + ID_MODEL_FROM_DATABASE=808 Camera #9 (mass storage mode) + +usb:v1B3Fp2002* + ID_MODEL_FROM_DATABASE=808 Camera #9 (web-cam mode) + +usb:v1B47* + ID_VENDOR_FROM_DATABASE=Energizer Holdings, Inc. + +usb:v1B47p0001* + ID_MODEL_FROM_DATABASE=CHUSB Duo Charger (NiMH AA/AAA USB smart charger) + +usb:v1B48* + ID_VENDOR_FROM_DATABASE=Plastron Precision Co., Ltd. + +usb:v1B52* + ID_VENDOR_FROM_DATABASE=ARH Inc. + +usb:v1B52p2101* + ID_MODEL_FROM_DATABASE=FXMC Neural Network Controller + +usb:v1B52p2102* + ID_MODEL_FROM_DATABASE=FXMC Neural Network Controller V2 + +usb:v1B52p2103* + ID_MODEL_FROM_DATABASE=FXMC Neural Network Controller V3 + +usb:v1B52p4101* + ID_MODEL_FROM_DATABASE=Passport Reader CLR device + +usb:v1B52p4201* + ID_MODEL_FROM_DATABASE=Passport Reader PRM device + +usb:v1B52p4202* + ID_MODEL_FROM_DATABASE=Passport Reader PRM extension device + +usb:v1B52p4203* + ID_MODEL_FROM_DATABASE=Passport Reader PRM DSP device + +usb:v1B52p4204* + ID_MODEL_FROM_DATABASE=Passport Reader PRMC device + +usb:v1B52p4205* + ID_MODEL_FROM_DATABASE=Passport Reader CSHR device + +usb:v1B52p4206* + ID_MODEL_FROM_DATABASE=Passport Reader PRMC V2 device + +usb:v1B52p4301* + ID_MODEL_FROM_DATABASE=Passport Reader MRZ device + +usb:v1B52p4302* + ID_MODEL_FROM_DATABASE=Passport Reader MRZ DSP device + +usb:v1B52p4303* + ID_MODEL_FROM_DATABASE=Passport Reader CSLR device + +usb:v1B52p4401* + ID_MODEL_FROM_DATABASE=Card Reader + +usb:v1B52p4501* + ID_MODEL_FROM_DATABASE=Passport Reader RFID device + +usb:v1B52p4502* + ID_MODEL_FROM_DATABASE=Passport Reader RFID AIG device + +usb:v1B52p6101* + ID_MODEL_FROM_DATABASE=Neural Network Controller + +usb:v1B52p6202* + ID_MODEL_FROM_DATABASE=Fingerprint Reader device + +usb:v1B52p6203* + ID_MODEL_FROM_DATABASE=Fingerprint Scanner device + +usb:v1B52p8101* + ID_MODEL_FROM_DATABASE=Camera V1 + +usb:v1B52p8102* + ID_MODEL_FROM_DATABASE=Recovery / Camera V2 + +usb:v1B52p8103* + ID_MODEL_FROM_DATABASE=Camera V3 + +usb:v1B59* + ID_VENDOR_FROM_DATABASE=K.S. Terminals Inc. + +usb:v1B5A* + ID_VENDOR_FROM_DATABASE=Chao Zhou Kai Yuan Electric Co., Ltd. + +usb:v1B65* + ID_VENDOR_FROM_DATABASE=The Hong Kong Standards and Testing Centre Ltd. + +usb:v1B71* + ID_VENDOR_FROM_DATABASE=Fushicai + +usb:v1B71p3002* + ID_MODEL_FROM_DATABASE=USBTV007 Video Grabber [EasyCAP] + +usb:v1B72* + ID_VENDOR_FROM_DATABASE=ATERGI TECHNOLOGY CO., LTD. + +usb:v1B73* + ID_VENDOR_FROM_DATABASE=Fresco Logic + +usb:v1B73p1000* + ID_MODEL_FROM_DATABASE=xHC1 Controller + +usb:v1B75* + ID_VENDOR_FROM_DATABASE=Ovislink Corp. + +usb:v1B75p3072* + ID_MODEL_FROM_DATABASE=AirLive WN-360USB adapter + +usb:v1B75p8171* + ID_MODEL_FROM_DATABASE=WN-370USB 802.11bgn Wireless Adapter [Realtek RTL8188SU] + +usb:v1B75p8187* + ID_MODEL_FROM_DATABASE=AirLive WL-1600USB 802.11g Adapter [Realtek RTL8187L] + +usb:v1B75p9170* + ID_MODEL_FROM_DATABASE=AirLive X.USB 802.11abgn [Atheros AR9170+AR9104] + +usb:v1B75pA200* + ID_MODEL_FROM_DATABASE=AirLive WN-200USB wireless 11b/g/n dongle + +usb:v1B76* + ID_VENDOR_FROM_DATABASE=Legend Silicon Corp. + +usb:v1B80* + ID_VENDOR_FROM_DATABASE=Afatech + +usb:v1B80pC810* + ID_MODEL_FROM_DATABASE=MC810 [af9015] + +usb:v1B80pD393* + ID_MODEL_FROM_DATABASE=DVB-T receiver [RTL2832U] + +usb:v1B80pD396* + ID_MODEL_FROM_DATABASE=UB396-T [RTL2832U] + +usb:v1B80pD397* + ID_MODEL_FROM_DATABASE=DVB-T receiver [RTL2832U] + +usb:v1B80pD398* + ID_MODEL_FROM_DATABASE=DVB-T receiver [RTL2832U] + +usb:v1B80pD700* + ID_MODEL_FROM_DATABASE=FM Radio SnapMusic Mobile 700 (FM700) + +usb:v1B80pE297* + ID_MODEL_FROM_DATABASE=Conceptronic DVB-T CTVDIGRCU V3.0 + +usb:v1B80pE383* + ID_MODEL_FROM_DATABASE=DVB-T UB383-T [af9015] + +usb:v1B80pE385* + ID_MODEL_FROM_DATABASE=DVB-T UB385-T [af9015] + +usb:v1B80pE386* + ID_MODEL_FROM_DATABASE=DVB-T UB385-T [af9015] + +usb:v1B80pE399* + ID_MODEL_FROM_DATABASE=DVB-T KWorld PlusTV 399U [af9015] + +usb:v1B80pE39A* + ID_MODEL_FROM_DATABASE=DVB-T395U [af9015] + +usb:v1B80pE39B* + ID_MODEL_FROM_DATABASE=DVB-T395U [af9015] + +usb:v1B80pE401* + ID_MODEL_FROM_DATABASE=Sveon STV22 DVB-T [af9015] + +usb:v1B80pE409* + ID_MODEL_FROM_DATABASE=IT9137FN Dual DVB-T [KWorld UB499-2T] + +usb:v1B86* + ID_VENDOR_FROM_DATABASE=Dongguan Guanshang Electronics Co., Ltd. + +usb:v1B88* + ID_VENDOR_FROM_DATABASE=ShenMing Electron (Dong Guan) Co., Ltd. + +usb:v1B8C* + ID_VENDOR_FROM_DATABASE=Altium Limited + +usb:v1B8D* + ID_VENDOR_FROM_DATABASE=e-MOVE Technology Co., Ltd. + +usb:v1B8E* + ID_VENDOR_FROM_DATABASE=Amlogic, Inc. + +usb:v1B8F* + ID_VENDOR_FROM_DATABASE=MA LABS, Inc. + +usb:v1B96* + ID_VENDOR_FROM_DATABASE=N-Trig + +usb:v1B96p0001* + ID_MODEL_FROM_DATABASE=Duosense Transparent Electromagnetic Digitizer + +usb:v1B98* + ID_VENDOR_FROM_DATABASE=YMax Communications Corp. + +usb:v1B99* + ID_VENDOR_FROM_DATABASE=Shenzhen Yuanchuan Electronic + +usb:v1BA1* + ID_VENDOR_FROM_DATABASE=JINQ CHERN ENTERPRISE CO., LTD. + +usb:v1BA2* + ID_VENDOR_FROM_DATABASE=Lite Metals & Plastic (Shenzhen) Co., Ltd. + +usb:v1BA4* + ID_VENDOR_FROM_DATABASE=Ember Corporation + +usb:v1BA4p0001* + ID_MODEL_FROM_DATABASE=InSight USB Link + +usb:v1BA6* + ID_VENDOR_FROM_DATABASE=Abilis Systems + +usb:v1BA8* + ID_VENDOR_FROM_DATABASE=China Telecommunication Technology Labs + +usb:v1BAD* + ID_VENDOR_FROM_DATABASE=Harmonix Music + +usb:v1BADp0002* + ID_MODEL_FROM_DATABASE=Guitar for Xbox 360 + +usb:v1BADp0003* + ID_MODEL_FROM_DATABASE=Drum Kit for Xbox 360 + +usb:v1BAE* + ID_VENDOR_FROM_DATABASE=Vuzix Corporation + +usb:v1BAEp0002* + ID_MODEL_FROM_DATABASE=VR920 Immersive Eyewear + +usb:v1BBB* + ID_VENDOR_FROM_DATABASE=T & A Mobile Phones + +usb:v1BBBp011E* + ID_MODEL_FROM_DATABASE=Alcatel One Touch L100V / Telekom Speedstick LTE II + +usb:v1BBBpF017* + ID_MODEL_FROM_DATABASE=Alcatel One Touch L100V / Telekom Speedstick LTE II + +usb:v1BC4* + ID_VENDOR_FROM_DATABASE=Ford Motor Co. + +usb:v1BC5* + ID_VENDOR_FROM_DATABASE=AVIXE Technology (China) Ltd. + +usb:v1BC7* + ID_VENDOR_FROM_DATABASE=Telit Wireless Solutions + +usb:v1BC7p0020* + ID_MODEL_FROM_DATABASE=HE863 + +usb:v1BC7p0021* + ID_MODEL_FROM_DATABASE=HE910 + +usb:v1BC7p0023* + ID_MODEL_FROM_DATABASE=HE910-D ECM + +usb:v1BC7p1003* + ID_MODEL_FROM_DATABASE=UC864-E + +usb:v1BC7p1004* + ID_MODEL_FROM_DATABASE=UC864-G + +usb:v1BC7p1005* + ID_MODEL_FROM_DATABASE=CC864-DUAL + +usb:v1BC7p1006* + ID_MODEL_FROM_DATABASE=CC864-SINGLE + +usb:v1BC7p1010* + ID_MODEL_FROM_DATABASE=DE910-DUAL + +usb:v1BC7p1011* + ID_MODEL_FROM_DATABASE=CE910-DUAL + +usb:v1BC7p1200* + ID_MODEL_FROM_DATABASE=LE920 + +usb:v1BCE* + ID_VENDOR_FROM_DATABASE=Contac Cable Industrial Limited + +usb:v1BCF* + ID_VENDOR_FROM_DATABASE=Sunplus Innovation Technology Inc. + +usb:v1BCFp0007* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v1BCFp053A* + ID_MODEL_FROM_DATABASE=Targa Silvercrest OMC807-C optische Funkmaus + +usb:v1BCFp05C5* + ID_MODEL_FROM_DATABASE=SPRF2413A [2.4GHz Wireless Keyboard/Mouse Receiver] + +usb:v1BCFp05CF* + ID_MODEL_FROM_DATABASE=Micro keyboard & mouse receiver + +usb:v1BCFp0C31* + ID_MODEL_FROM_DATABASE=SPIF30x Serial-ATA bridge + +usb:v1BCFp2885* + ID_MODEL_FROM_DATABASE=ASUS Webcam + +usb:v1BCFp2888* + ID_MODEL_FROM_DATABASE=HP Universal Camera + +usb:v1BCFp2B83* + ID_MODEL_FROM_DATABASE=Laptop Integrated Webcam FHD + +usb:v1BD0* + ID_VENDOR_FROM_DATABASE=Hangzhou Riyue Electronic Co., Ltd. + +usb:v1BD5* + ID_VENDOR_FROM_DATABASE=BG Systems, Inc. + +usb:v1BDE* + ID_VENDOR_FROM_DATABASE=P-TWO INDUSTRIES, INC. + +usb:v1BEF* + ID_VENDOR_FROM_DATABASE=Shenzhen Tongyuan Network-Communication Cables Co., Ltd + +usb:v1BF0* + ID_VENDOR_FROM_DATABASE=RealVision Inc. + +usb:v1BF5* + ID_VENDOR_FROM_DATABASE=Extranet Systems Inc. + +usb:v1BF6* + ID_VENDOR_FROM_DATABASE=Orient Semiconductor Electronics, Ltd. + +usb:v1BFD* + ID_VENDOR_FROM_DATABASE=TouchPack + +usb:v1BFDp1268* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v1BFDp1368* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v1BFDp1568* + ID_MODEL_FROM_DATABASE=Capacitive Touch Screen + +usb:v1BFDp1668* + ID_MODEL_FROM_DATABASE=IR Touch Screen + +usb:v1BFDp1688* + ID_MODEL_FROM_DATABASE=Resistive Touch Screen + +usb:v1BFDp2968* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v1BFDp5968* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v1BFDp6968* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v1C02* + ID_VENDOR_FROM_DATABASE=Kreton Corporation + +usb:v1C04* + ID_VENDOR_FROM_DATABASE=QNAP System Inc. + +usb:v1C0C* + ID_VENDOR_FROM_DATABASE=Ionics EMS, Inc. + +usb:v1C0Cp0102* + ID_MODEL_FROM_DATABASE=Plug Computer + +usb:v1C0D* + ID_VENDOR_FROM_DATABASE=Relm Wireless + +usb:v1C10* + ID_VENDOR_FROM_DATABASE=Lanterra Industrial Co., Ltd. + +usb:v1C13* + ID_VENDOR_FROM_DATABASE=ALECTRONIC LIMITED + +usb:v1C1A* + ID_VENDOR_FROM_DATABASE=Datel Electronics Ltd. + +usb:v1C1B* + ID_VENDOR_FROM_DATABASE=Volkswagen of America, Inc. + +usb:v1C1F* + ID_VENDOR_FROM_DATABASE=Goldvish S.A. + +usb:v1C20* + ID_VENDOR_FROM_DATABASE=Fuji Electric Device Technology Co., Ltd. + +usb:v1C21* + ID_VENDOR_FROM_DATABASE=ADDMM LLC + +usb:v1C22* + ID_VENDOR_FROM_DATABASE=ZHONGSHAN CHIANG YU ELECTRIC CO., LTD. + +usb:v1C26* + ID_VENDOR_FROM_DATABASE=Shanghai Haiying Electronics Co., Ltd. + +usb:v1C27* + ID_VENDOR_FROM_DATABASE=HuiYang D & S Cable Co., Ltd. + +usb:v1C31* + ID_VENDOR_FROM_DATABASE=LS Cable Ltd. + +usb:v1C34* + ID_VENDOR_FROM_DATABASE=SpringCard + +usb:v1C34p7241* + ID_MODEL_FROM_DATABASE=Prox'N'Roll RFID Scanner + +usb:v1C37* + ID_VENDOR_FROM_DATABASE=Authorizer Technologies, Inc. + +usb:v1C3D* + ID_VENDOR_FROM_DATABASE=NONIN MEDICAL INC. + +usb:v1C3E* + ID_VENDOR_FROM_DATABASE=Wep Peripherals + +usb:v1C40* + ID_VENDOR_FROM_DATABASE=EZPrototypes + +usb:v1C40p0533* + ID_MODEL_FROM_DATABASE=TiltStick + +usb:v1C40p0534* + ID_MODEL_FROM_DATABASE=i2c-tiny-usb interface + +usb:v1C40p0535* + ID_MODEL_FROM_DATABASE=glcd2usb interface + +usb:v1C40p0536* + ID_MODEL_FROM_DATABASE=Swiss ColorPAL + +usb:v1C49* + ID_VENDOR_FROM_DATABASE=Cherng Weei Technology Corp. + +usb:v1C4F* + ID_VENDOR_FROM_DATABASE=SiGma Micro + +usb:v1C4Fp0002* + ID_MODEL_FROM_DATABASE=Keyboard TRACER Gamma Ivory + +usb:v1C4Fp0003* + ID_MODEL_FROM_DATABASE=HID controller + +usb:v1C4Fp000E* + ID_MODEL_FROM_DATABASE=Genius KB-120 Keyboard + +usb:v1C4Fp0026* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v1C4Fp3000* + ID_MODEL_FROM_DATABASE=Micro USB Web Camera + +usb:v1C4Fp3002* + ID_MODEL_FROM_DATABASE=WebCam SiGma Micro + +usb:v1C6B* + ID_VENDOR_FROM_DATABASE=Philips & Lite-ON Digital Solutions Corporation + +usb:v1C6BpA222* + ID_MODEL_FROM_DATABASE=DVD Writer Slimtype eTAU108 + +usb:v1C6C* + ID_VENDOR_FROM_DATABASE=Skydigital Inc. + +usb:v1C73* + ID_VENDOR_FROM_DATABASE=AMT + +usb:v1C73p861F* + ID_MODEL_FROM_DATABASE=Anysee E30 USB 2.0 DVB-T Receiver + +usb:v1C77* + ID_VENDOR_FROM_DATABASE=Kaetat Industrial Co., Ltd. + +usb:v1C78* + ID_VENDOR_FROM_DATABASE=Datascope Corp. + +usb:v1C79* + ID_VENDOR_FROM_DATABASE=Unigen Corporation + +usb:v1C7A* + ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc. + +usb:v1C7Ap0801* + ID_MODEL_FROM_DATABASE=Fingerprint Reader + +usb:v1C7B* + ID_VENDOR_FROM_DATABASE=LUXSHARE PRECISION INDUSTRY (SHENZHEN) CO., LTD. + +usb:v1C83* + ID_VENDOR_FROM_DATABASE=Schomäcker GmbH + +usb:v1C83p0001* + ID_MODEL_FROM_DATABASE=RS150 V2 + +usb:v1C87* + ID_VENDOR_FROM_DATABASE=2N TELEKOMUNIKACE a.s. + +usb:v1C88* + ID_VENDOR_FROM_DATABASE=Somagic, Inc. + +usb:v1C88p0007* + ID_MODEL_FROM_DATABASE=SMI Grabber (EasyCAP DC60+ clone) (no firmware) [SMI-2021CBE] + +usb:v1C88p003C* + ID_MODEL_FROM_DATABASE=SMI Grabber (EasyCAP DC60+ clone) [SMI-2021CBE] + +usb:v1C89* + ID_VENDOR_FROM_DATABASE=HONGKONG WEIDIDA ELECTRON LIMITED + +usb:v1C8E* + ID_VENDOR_FROM_DATABASE=ASTRON INTERNATIONAL CORP. + +usb:v1C98* + ID_VENDOR_FROM_DATABASE=ALPINE ELECTRONICS, INC. + +usb:v1C9E* + ID_VENDOR_FROM_DATABASE=OMEGA TECHNOLOGY + +usb:v1C9Ep6061* + ID_MODEL_FROM_DATABASE=WL-72B 3.5G MODEM + +usb:v1CA0* + ID_VENDOR_FROM_DATABASE=ACCARIO Inc. + +usb:v1CA1* + ID_VENDOR_FROM_DATABASE=Symwave + +usb:v1CA1p18AB* + ID_MODEL_FROM_DATABASE=SATA bridge + +usb:v1CAC* + ID_VENDOR_FROM_DATABASE=Kinstone + +usb:v1CACpA332* + ID_MODEL_FROM_DATABASE=C8 Webcam + +usb:v1CACpB288* + ID_MODEL_FROM_DATABASE=C18 Webcam + +usb:v1CB3* + ID_VENDOR_FROM_DATABASE=Aces Electronic Co., Ltd. + +usb:v1CB4* + ID_VENDOR_FROM_DATABASE=OPEX CORPORATION + +usb:v1CB6* + ID_VENDOR_FROM_DATABASE=IdeaCom Technology Inc. + +usb:v1CB6p6681* + ID_MODEL_FROM_DATABASE=IDC6681 + +usb:v1CBE* + ID_VENDOR_FROM_DATABASE=Luminary Micro Inc. + +usb:v1CBEp00FD* + ID_MODEL_FROM_DATABASE=In-Circuit Debug Interface + +usb:v1CBEp00FF* + ID_MODEL_FROM_DATABASE=Stellaris ROM DFU Bootloader + +usb:v1CBEp0166* + ID_MODEL_FROM_DATABASE=CANAL USB2CAN + +usb:v1CBF* + ID_VENDOR_FROM_DATABASE=FORTAT SKYMARK INDUSTRIAL COMPANY + +usb:v1CC0* + ID_VENDOR_FROM_DATABASE=PlantSense + +usb:v1CCA* + ID_VENDOR_FROM_DATABASE=NextWave Broadband Inc. + +usb:v1CCD* + ID_VENDOR_FROM_DATABASE=Bodatong Technology (Shenzhen) Co., Ltd. + +usb:v1CD4* + ID_VENDOR_FROM_DATABASE=adp corporation + +usb:v1CD5* + ID_VENDOR_FROM_DATABASE=Firecomms Ltd. + +usb:v1CD6* + ID_VENDOR_FROM_DATABASE=Antonio Precise Products Manufactory Ltd. + +usb:v1CDE* + ID_VENDOR_FROM_DATABASE=Telecommunications Technology Association (TTA) + +usb:v1CDF* + ID_VENDOR_FROM_DATABASE=WonTen Technology Co., Ltd. + +usb:v1CE0* + ID_VENDOR_FROM_DATABASE=EDIMAX TECHNOLOGY CO., LTD. + +usb:v1CE1* + ID_VENDOR_FROM_DATABASE=Amphenol KAE + +usb:v1CF1* + ID_VENDOR_FROM_DATABASE=Dresden Elektronik + +usb:v1CF1p0001* + ID_MODEL_FROM_DATABASE=Sensor Terminal Board + +usb:v1CF1p0004* + ID_MODEL_FROM_DATABASE=Wireless Handheld Terminal + +usb:v1CF1p0017* + ID_MODEL_FROM_DATABASE=deRFusbSniffer 2.4 GHz + +usb:v1CF1p0018* + ID_MODEL_FROM_DATABASE=deRFusb24E001 + +usb:v1CF1p0019* + ID_MODEL_FROM_DATABASE=deRFusb14E001 + +usb:v1CF1p001A* + ID_MODEL_FROM_DATABASE=deRFusb23E00 + +usb:v1CF1p001B* + ID_MODEL_FROM_DATABASE=deRFusb13E00 + +usb:v1CF1p001C* + ID_MODEL_FROM_DATABASE=deRFnode + +usb:v1CF1p001D* + ID_MODEL_FROM_DATABASE=deRFnode / gateway + +usb:v1CF1p0022* + ID_MODEL_FROM_DATABASE=deUSB level shifter + +usb:v1CF1p0023* + ID_MODEL_FROM_DATABASE=deRFusbSniffer Sub-GHz + +usb:v1CF1p0025* + ID_MODEL_FROM_DATABASE=deRFusb23E06 + +usb:v1CF1p0027* + ID_MODEL_FROM_DATABASE=deRFusb13E06 + +usb:v1CFC* + ID_VENDOR_FROM_DATABASE=ANDES TECHNOLOGY CORPORATION + +usb:v1CFD* + ID_VENDOR_FROM_DATABASE=Flextronics Digital Design Japan, LTD. + +usb:v1D03* + ID_VENDOR_FROM_DATABASE=iCON + +usb:v1D03p0028* + ID_MODEL_FROM_DATABASE=iCreativ MIDI Controller + +usb:v1D07* + ID_VENDOR_FROM_DATABASE=Solid-Motion + +usb:v1D08* + ID_VENDOR_FROM_DATABASE=NINGBO HENTEK DRAGON ELECTRONICS CO., LTD. + +usb:v1D09* + ID_VENDOR_FROM_DATABASE=TechFaith Wireless Technology Limited + +usb:v1D09p1026* + ID_MODEL_FROM_DATABASE=HSUPA Modem FLYING-LARK46-VER0.07 [Flying Angel] + +usb:v1D0A* + ID_VENDOR_FROM_DATABASE=Johnson Controls, Inc. The Automotive Business Unit + +usb:v1D0B* + ID_VENDOR_FROM_DATABASE=HAN HUA CABLE & WIRE TECHNOLOGY (J.X.) CO., LTD. + +usb:v1D0F* + ID_VENDOR_FROM_DATABASE=Sonix Technology Co., Ltd. + +usb:v1D14* + ID_VENDOR_FROM_DATABASE=ALPHA-SAT TECHNOLOGY LIMITED + +usb:v1D17* + ID_VENDOR_FROM_DATABASE=C-Thru Music Ltd. + +usb:v1D17p0001* + ID_MODEL_FROM_DATABASE=AXiS-49 Harmonic Table MIDI Keyboard + +usb:v1D19* + ID_VENDOR_FROM_DATABASE=Dexatek Technology Ltd. + +usb:v1D19p1101* + ID_MODEL_FROM_DATABASE=DK DVB-T Dongle + +usb:v1D19p1102* + ID_MODEL_FROM_DATABASE=DK mini DVB-T Dongle + +usb:v1D19p1103* + ID_MODEL_FROM_DATABASE=DK 5217 DVB-T Dongle + +usb:v1D19p6105* + ID_MODEL_FROM_DATABASE=Video grabber + +usb:v1D19p8202* + ID_MODEL_FROM_DATABASE=DK DVBC/T DONGLE + +usb:v1D1F* + ID_VENDOR_FROM_DATABASE=Diostech Co., Ltd. + +usb:v1D20* + ID_VENDOR_FROM_DATABASE=SAMTACK INC. + +usb:v1D27* + ID_VENDOR_FROM_DATABASE=ASUS + +usb:v1D34* + ID_VENDOR_FROM_DATABASE=Dream Cheeky + +usb:v1D34p0001* + ID_MODEL_FROM_DATABASE=Dream Cheeky Fidget + +usb:v1D34p0004* + ID_MODEL_FROM_DATABASE=Dream Cheeky Webmail Notifier + +usb:v1D34p0008* + ID_MODEL_FROM_DATABASE=Dream Cheeky button + +usb:v1D34p000A* + ID_MODEL_FROM_DATABASE=Dream Cheeky Mailbox Friends Alert + +usb:v1D34p000D* + ID_MODEL_FROM_DATABASE=Dream Cheeky Big Red Button + +usb:v1D34p0013* + ID_MODEL_FROM_DATABASE=Dream Cheeky LED Message Board + +usb:v1D45* + ID_VENDOR_FROM_DATABASE=Touch + +usb:v1D45p1D45* + ID_MODEL_FROM_DATABASE=Foxlink Optical touch sensor + +usb:v1D4D* + ID_VENDOR_FROM_DATABASE=PEGATRON CORPORATION + +usb:v1D4Dp0002* + ID_MODEL_FROM_DATABASE=Ralink RT2770/2720 802.11b/g/n Wireless LAN Mini-USB Device + +usb:v1D4Dp000C* + ID_MODEL_FROM_DATABASE=Ralink RT3070 802.11b/g/n Wireless Lan USB Device + +usb:v1D4Dp000E* + ID_MODEL_FROM_DATABASE=Ralink RT3070 802.11b/g/n Wireless Lan USB Device + +usb:v1D50* + ID_VENDOR_FROM_DATABASE=OpenMoko, Inc. + +usb:v1D50p5119* + ID_MODEL_FROM_DATABASE=GTA01/GTA02 U-Boot Bootloader + +usb:v1D50p602B* + ID_MODEL_FROM_DATABASE=FPGALink + +usb:v1D50p6053* + ID_MODEL_FROM_DATABASE=Darkgame Controller + +usb:v1D57* + ID_VENDOR_FROM_DATABASE=Xenta + +usb:v1D57p0005* + ID_MODEL_FROM_DATABASE=Wireless Receiver (Keyboard and Mouse) + +usb:v1D57p0006* + ID_MODEL_FROM_DATABASE=Wireless Receiver (RC Laser Pointer) + +usb:v1D57p000C* + ID_MODEL_FROM_DATABASE=Optical Mouse + +usb:v1D57p2400* + ID_MODEL_FROM_DATABASE=Wireless Mouse Receiver + +usb:v1D57p32DA* + ID_MODEL_FROM_DATABASE=2.4GHz Receiver (Keyboard and Mouse) + +usb:v1D57p83D0* + ID_MODEL_FROM_DATABASE=Click-mouse! + +usb:v1D57pAC01* + ID_MODEL_FROM_DATABASE=Wireless Receiver (Keyboard and Mouse) + +usb:v1D57pAD02* + ID_MODEL_FROM_DATABASE=SE340D PC Remote Control + +usb:v1D57pAF01* + ID_MODEL_FROM_DATABASE=AUVIO Universal Remote Receiver for PlayStation 3 + +usb:v1D5B* + ID_VENDOR_FROM_DATABASE=Smartronix, Inc. + +usb:v1D6B* + ID_VENDOR_FROM_DATABASE=Linux Foundation + +usb:v1D6Bp0001* + ID_MODEL_FROM_DATABASE=1.1 root hub + +usb:v1D6Bp0002* + ID_MODEL_FROM_DATABASE=2.0 root hub + +usb:v1D6Bp0003* + ID_MODEL_FROM_DATABASE=3.0 root hub + +usb:v1D6Bp0100* + ID_MODEL_FROM_DATABASE=PTP Gadget + +usb:v1D6Bp0101* + ID_MODEL_FROM_DATABASE=Audio Gadget + +usb:v1D6Bp0102* + ID_MODEL_FROM_DATABASE=EEM Gadget + +usb:v1D6Bp0103* + ID_MODEL_FROM_DATABASE=NCM (Ethernet) Gadget + +usb:v1D6Bp0104* + ID_MODEL_FROM_DATABASE=Multifunction Composite Gadget + +usb:v1D6Bp0105* + ID_MODEL_FROM_DATABASE=FunctionFS Gadget + +usb:v1D6Bp0200* + ID_MODEL_FROM_DATABASE=Qemu Audio Device + +usb:v1D90* + ID_VENDOR_FROM_DATABASE=Citizen + +usb:v1D90p201E* + ID_MODEL_FROM_DATABASE=PPU-700 + +usb:v1DE1* + ID_VENDOR_FROM_DATABASE=Actions Microelectronics Co. + +usb:v1DE1p1101* + ID_MODEL_FROM_DATABASE=Generic Display Device (Mass storage mode) + +usb:v1DE1pC101* + ID_MODEL_FROM_DATABASE=Generic Display Device + +usb:v1E0E* + ID_VENDOR_FROM_DATABASE=Qualcomm / Option + +usb:v1E0EpF000* + ID_MODEL_FROM_DATABASE=iCON 210 UMTS Surfstick + +usb:v1E10* + ID_VENDOR_FROM_DATABASE=Point Grey Research, Inc. + +usb:v1E10p2004* + ID_MODEL_FROM_DATABASE=Sony 1.3MP 1/3" ICX445 IIDC video camera [Chameleon] + +usb:v1E17* + ID_VENDOR_FROM_DATABASE=Mirion Technologies Dosimetry Services Division + +usb:v1E17p0001* + ID_MODEL_FROM_DATABASE=instadose dosimeter + +usb:v1E1D* + ID_VENDOR_FROM_DATABASE=Lumension Security + +usb:v1E1Dp0165* + ID_MODEL_FROM_DATABASE=Secure Pen drive + +usb:v1E1F* + ID_VENDOR_FROM_DATABASE=INVIA + +usb:v1E29* + ID_VENDOR_FROM_DATABASE=Festo AG & Co. KG + +usb:v1E29p0101* + ID_MODEL_FROM_DATABASE=CPX Adapter + +usb:v1E29p0102* + ID_MODEL_FROM_DATABASE=CPX Adapter >=HW10.09 [CP2102] + +usb:v1E29p0401* + ID_MODEL_FROM_DATABASE=iL3-TP [AT90USB646] + +usb:v1E29p0402* + ID_MODEL_FROM_DATABASE=FTDI232 [EasyPort] + +usb:v1E29p0403* + ID_MODEL_FROM_DATABASE=FTDI232 [EasyPort Mini] + +usb:v1E29p0404* + ID_MODEL_FROM_DATABASE=FTDI232 [Netzteil-GL] + +usb:v1E29p0405* + ID_MODEL_FROM_DATABASE=FTDI232 [MotorPrüfstand] + +usb:v1E29p0406* + ID_MODEL_FROM_DATABASE=STM32F103 [EasyKit] + +usb:v1E29p0407* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino] + +usb:v1E29p0408* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino-Arm] + +usb:v1E29p0409* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino-Arm Bootloader] + +usb:v1E29p040A* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino Bootloader] + +usb:v1E29p040B* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino XT] + +usb:v1E29p040C* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino XT Bootloader] + +usb:v1E29p040D* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino 3] + +usb:v1E29p040E* + ID_MODEL_FROM_DATABASE=LPC2378 [Robotino 3 Bootloader] + +usb:v1E29p0501* + ID_MODEL_FROM_DATABASE=CP2102 [CMSP] + +usb:v1E29p0601* + ID_MODEL_FROM_DATABASE=CMMP-AS + +usb:v1E3D* + ID_VENDOR_FROM_DATABASE=Chipsbank Microelectronics Co., Ltd + +usb:v1E3Dp2093* + ID_MODEL_FROM_DATABASE=CBM209x Flash Drive (OEM) + +usb:v1E3Dp4082* + ID_MODEL_FROM_DATABASE=CBM4082 SD Card Reader + +usb:v1E41* + ID_VENDOR_FROM_DATABASE=Cleverscope + +usb:v1E41p0001* + ID_MODEL_FROM_DATABASE=CS328A PC Oscilloscope + +usb:v1E4E* + ID_VENDOR_FROM_DATABASE=Cubeternet + +usb:v1E4Ep0100* + ID_MODEL_FROM_DATABASE=WebCam + +usb:v1E4Ep0102* + ID_MODEL_FROM_DATABASE=GL-UPC822 UVC WebCam + +usb:v1E54* + ID_VENDOR_FROM_DATABASE=TypeMatrix + +usb:v1E54p2030* + ID_MODEL_FROM_DATABASE=2030 USB Keyboard + +usb:v1E68* + ID_VENDOR_FROM_DATABASE=TrekStor GmbH & Co. KG + +usb:v1E68p001B* + ID_MODEL_FROM_DATABASE=DataStation maxi g.u + +usb:v1E68p0050* + ID_MODEL_FROM_DATABASE=DataStation maxi light + +usb:v1E71* + ID_VENDOR_FROM_DATABASE=NZXT + +usb:v1E71p0001* + ID_MODEL_FROM_DATABASE=Avatar Optical Mouse + +usb:v1E74* + ID_VENDOR_FROM_DATABASE=Coby Electronics Corporation + +usb:v1E74p2211* + ID_MODEL_FROM_DATABASE=MP300 + +usb:v1E74p2647* + ID_MODEL_FROM_DATABASE=2 GB 2 Go Video MP3 Player [MP601-2G] + +usb:v1E74p2659* + ID_MODEL_FROM_DATABASE=Coby 4GB Go Video MP3 Player [MP620-4G] + +usb:v1E74p4641* + ID_MODEL_FROM_DATABASE=A8705 MP3/Video Player + +usb:v1E74p6511* + ID_MODEL_FROM_DATABASE=MP705-8G MP3 player + +usb:v1E74p6512* + ID_MODEL_FROM_DATABASE=MP705-4G + +usb:v1E74p7111* + ID_MODEL_FROM_DATABASE=MP957 Music and Video Player + +usb:v1E7D* + ID_VENDOR_FROM_DATABASE=ROCCAT + +usb:v1E7Dp2C24* + ID_MODEL_FROM_DATABASE=Pyra Mouse (wired) + +usb:v1E7Dp2CED* + ID_MODEL_FROM_DATABASE=Kone Mouse + +usb:v1E7Dp2CF6* + ID_MODEL_FROM_DATABASE=Pyra Mouse (wireless) + +usb:v1E7Dp2D50* + ID_MODEL_FROM_DATABASE=Kova+ Mouse + +usb:v1E7Dp2D51* + ID_MODEL_FROM_DATABASE=Kone+ Mouse + +usb:v1E7Dp30D4* + ID_MODEL_FROM_DATABASE=Arvo Keyboard + +usb:v1EBB* + ID_VENDOR_FROM_DATABASE=NuCORE Technology, Inc. + +usb:v1EDA* + ID_VENDOR_FROM_DATABASE=AirTies Wireless Networks + +usb:v1EDAp2012* + ID_MODEL_FROM_DATABASE=Air2210 54 Mbps Wireless Adapter + +usb:v1EDAp2210* + ID_MODEL_FROM_DATABASE=Air2210 54 Mbps Wireless Adapter + +usb:v1EDAp2310* + ID_MODEL_FROM_DATABASE=Air2310 150 Mbps Wireless Adapter + +usb:v1EDAp2410* + ID_MODEL_FROM_DATABASE=Air2410 300 Mbps Wireless Adapter + +usb:v1EDB* + ID_VENDOR_FROM_DATABASE=Blackmagic design + +usb:v1EDBpBD3B* + ID_MODEL_FROM_DATABASE=Intensity Shuttle + +usb:v1EE8* + ID_VENDOR_FROM_DATABASE=ONDA COMMUNICATION S.p.a. + +usb:v1EE8p0014* + ID_MODEL_FROM_DATABASE=MT833UP + +usb:v1EF6* + ID_VENDOR_FROM_DATABASE=EADS Deutschland GmbH + +usb:v1EF6p2233* + ID_MODEL_FROM_DATABASE=Cassidian NH90 STTE + +usb:v1EF6p5064* + ID_MODEL_FROM_DATABASE=FDR Interface + +usb:v1EF6p5523* + ID_MODEL_FROM_DATABASE=Cassidian SSDC Adapter II + +usb:v1EF6p5545* + ID_MODEL_FROM_DATABASE=Cassidian SSDC Adapter III + +usb:v1EF6p5648* + ID_MODEL_FROM_DATABASE=RIU CSMU/BSD + +usb:v1EF6p564A* + ID_MODEL_FROM_DATABASE=Cassidian RIU CSMU/BSD Simulator + +usb:v1F28* + ID_VENDOR_FROM_DATABASE=Cal-Comp + +usb:v1F28p0020* + ID_MODEL_FROM_DATABASE=CDMA USB Modem A600 + +usb:v1F28p0021* + ID_MODEL_FROM_DATABASE=CD INSTALLER USB Device + +usb:v1F3A* + ID_VENDOR_FROM_DATABASE=Onda (unverified) + +usb:v1F3ApEFE8* + ID_MODEL_FROM_DATABASE=V972 tablet in flashing mode + +usb:v1F44* + ID_VENDOR_FROM_DATABASE=The Neat Company + +usb:v1F44p0001* + ID_MODEL_FROM_DATABASE=NM-1000 scanner + +usb:v1F48* + ID_VENDOR_FROM_DATABASE=H-TRONIC GmbH + +usb:v1F48p0627* + ID_MODEL_FROM_DATABASE=Data capturing system + +usb:v1F48p0628* + ID_MODEL_FROM_DATABASE=Data capturing and control module + +usb:v1F4D* + ID_VENDOR_FROM_DATABASE=G-Tek Electronics Group + +usb:v1F4DpB803* + ID_MODEL_FROM_DATABASE=Lifeview LV5TDLX DVB-T [RTL2832U] + +usb:v1F6F* + ID_VENDOR_FROM_DATABASE=Aliph + +usb:v1F6Fp0023* + ID_MODEL_FROM_DATABASE=Jawbone Jambox + +usb:v1F6Fp8000* + ID_MODEL_FROM_DATABASE=Jawbone Jambox - Updating + +usb:v1F75* + ID_VENDOR_FROM_DATABASE=Innostor Technology Corporation + +usb:v1F75p0888* + ID_MODEL_FROM_DATABASE=IS888 SATA Storage Controller + +usb:v1F75p0902* + ID_MODEL_FROM_DATABASE=IS902 UFD controller + +usb:v1F82* + ID_VENDOR_FROM_DATABASE=TANDBERG + +usb:v1F82p0001* + ID_MODEL_FROM_DATABASE=PrecisionHD Camera + +usb:v1F84* + ID_VENDOR_FROM_DATABASE=Alere, Inc. + +usb:v1F87* + ID_VENDOR_FROM_DATABASE=Stantum + +usb:v1F87p0002* + ID_MODEL_FROM_DATABASE=Multi-touch HID Controller + +usb:v1F9B* + ID_VENDOR_FROM_DATABASE=Ubiquiti Networks, Inc. + +usb:v1F9Bp0241* + ID_MODEL_FROM_DATABASE=AirView2-EXT + +usb:v1FAB* + ID_VENDOR_FROM_DATABASE=Samsung Opto-Electroncs Co., Ltd. + +usb:v1FABp104D* + ID_MODEL_FROM_DATABASE=ES65 + +usb:v1FBD* + ID_VENDOR_FROM_DATABASE=Delphin Technology AG + +usb:v1FBDp0001* + ID_MODEL_FROM_DATABASE=Expert Key - Data aquisition system + +usb:v1FC9* + ID_VENDOR_FROM_DATABASE=NXP Semiconductors + +usb:v1FC9p0003* + ID_MODEL_FROM_DATABASE=LPC1343 + +usb:v1FC9p010B* + ID_MODEL_FROM_DATABASE=PR533 + +usb:v1FDE* + ID_VENDOR_FROM_DATABASE=ILX Lightwave Corporation + +usb:v1FDEp0001* + ID_MODEL_FROM_DATABASE=UART Bridge + +usb:v1FE7* + ID_VENDOR_FROM_DATABASE=Vertex Wireless Co., Ltd. + +usb:v1FE7p1000* + ID_MODEL_FROM_DATABASE=VW100 series CDMA EV-DO Rev.A modem + +usb:v1FF7* + ID_VENDOR_FROM_DATABASE=CVT Electronics.Co.,Ltd + +usb:v1FF7p0013* + ID_MODEL_FROM_DATABASE=CVTouch Screen (HID) + +usb:v1FF7p001A* + ID_MODEL_FROM_DATABASE=Human Interface Device + +usb:v1FFF* + ID_VENDOR_FROM_DATABASE=Ideofy Inc. + +usb:v2001* + ID_VENDOR_FROM_DATABASE=D-Link Corp. + +usb:v2001p0001* + ID_MODEL_FROM_DATABASE=DWL-120 WIRELESS ADAPTER + +usb:v2001p0201* + ID_MODEL_FROM_DATABASE=DHN-120 10Mb Home Phoneline Adapter + +usb:v2001p1A00* + ID_MODEL_FROM_DATABASE=DUB-E100 Fast Ethernet Adapter(rev.A) [ASIX AX88172] + +usb:v2001p1A02* + ID_MODEL_FROM_DATABASE=DUB-E100 Fast Ethernet Adapter(rev.C1) [ASIX AX88772] + +usb:v2001p200C* + ID_MODEL_FROM_DATABASE=10/100 Ethernet + +usb:v2001p3200* + ID_MODEL_FROM_DATABASE=DWL-120 802.11b Wireless Adapter(rev.E1) [Atmel at76c503a] + +usb:v2001p3301* + ID_MODEL_FROM_DATABASE=DWA-130 802.11n Wireless N Adapter(rev.C1) [Realtek RTL8192U] + +usb:v2001p3306* + ID_MODEL_FROM_DATABASE=DWL-G122 Wireless Adapter(rev.F1) [Realtek RTL8188SU] + +usb:v2001p3308* + ID_MODEL_FROM_DATABASE=DWA-121 802.11n Wireless N 150 Pico Adapter [Realtek RTL8188CUS] + +usb:v2001p3309* + ID_MODEL_FROM_DATABASE=DWA-135 802.11n Wireless N Adapter(rev.A1) [Realtek RTL8192CU] + +usb:v2001p330A* + ID_MODEL_FROM_DATABASE=DWA-133 802.11n Wireless N Adapter [Realtek RTL8192CU] + +usb:v2001p3500* + ID_MODEL_FROM_DATABASE=Elitegroup Computer Systems WLAN card WL-162 + +usb:v2001p3700* + ID_MODEL_FROM_DATABASE=DWL-122 802.11b [Intersil Prism 3] + +usb:v2001p3701* + ID_MODEL_FROM_DATABASE=DWL-G120 Spinnaker 802.11g [Intersil ISL3886] + +usb:v2001p3702* + ID_MODEL_FROM_DATABASE=DWL-120 802.11b Wireless Adapter(rev.F) [Intersil ISL3871] + +usb:v2001p3703* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.A1) [Intersil ISL3880] + +usb:v2001p3704* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.A2) [Intersil ISL3887] + +usb:v2001p3705* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G120 Wireless Adapter(rev.C) [Intersil ISL3887] + +usb:v2001p3761* + ID_MODEL_FROM_DATABASE=IEEE 802.11g USB2.0 Wireless Network Adapter-PN + +usb:v2001p3A00* + ID_MODEL_FROM_DATABASE=DWL-AG132 [Atheros AR5523] + +usb:v2001p3A01* + ID_MODEL_FROM_DATABASE=DWL-AG132 (no firmware) [Atheros AR5523] + +usb:v2001p3A02* + ID_MODEL_FROM_DATABASE=DWL-G132 [Atheros AR5523] + +usb:v2001p3A03* + ID_MODEL_FROM_DATABASE=DWL-G132 (no firmware) [Atheros AR5523] + +usb:v2001p3A04* + ID_MODEL_FROM_DATABASE=DWL-AG122 [Atheros AR5523] + +usb:v2001p3A05* + ID_MODEL_FROM_DATABASE=DWL-AG122 (no firmware) [Atheros AR5523] + +usb:v2001p3A80* + ID_MODEL_FROM_DATABASE=AirPlus Xtreme G DWL-G132 Wireless Adapter + +usb:v2001p3A81* + ID_MODEL_FROM_DATABASE=predator Bootloader Download + +usb:v2001p3A82* + ID_MODEL_FROM_DATABASE=AirPremier AG DWL-AG132 Wireless Adapter + +usb:v2001p3A83* + ID_MODEL_FROM_DATABASE=predator Bootloader Download + +usb:v2001p3B00* + ID_MODEL_FROM_DATABASE=AirPlus DWL-120+ Wireless Adapter [Texas Instruments ACX100USB] + +usb:v2001p3B01* + ID_MODEL_FROM_DATABASE=WLAN Boot Device + +usb:v2001p3C00* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter(rev.B1) [Ralink RT2571] + +usb:v2001p3C01* + ID_MODEL_FROM_DATABASE=AirPlus AG DWL-AG122 Wireless Adapter + +usb:v2001p3C02* + ID_MODEL_FROM_DATABASE=AirPlus G DWL-G122 Wireless Adapter + +usb:v2001p3C05* + ID_MODEL_FROM_DATABASE=DUB-E100 Fast Ethernet Adapter(rev.B1) [ASIX AX88772] + +usb:v2001p3C15* + ID_MODEL_FROM_DATABASE=DWA-140 RangeBooster N Adapter(rev.B3) [Ralink RT5372] + +usb:v2001p3C17* + ID_MODEL_FROM_DATABASE=DWA-123 Wireless N 150 Adapter(rev.A1) [Ralink RT3370] + +usb:v2001p3C19* + ID_MODEL_FROM_DATABASE=DWA-125 Wireless N 150 Adapter(rev.A3) [Ralink RT5370] + +usb:v2001p3C1A* + ID_MODEL_FROM_DATABASE=DWA-160 802.11abgn Xtreme N Dual Band Adapter(rev.B2) [Ralink RT5572] + +usb:v2001p3C1B* + ID_MODEL_FROM_DATABASE=DWA-127 Wireless N 150 High-Gain Adapter(rev.A1) [Ralink RT3070] + +usb:v2001p4000* + ID_MODEL_FROM_DATABASE=DSB-650C Ethernet [klsi] + +usb:v2001p4001* + ID_MODEL_FROM_DATABASE=DSB-650TX Ethernet [pegasus] + +usb:v2001p4002* + ID_MODEL_FROM_DATABASE=DSB-650TX Ethernet [pegasus] + +usb:v2001p4003* + ID_MODEL_FROM_DATABASE=DSB-650TX-PNA Ethernet [pegasus] + +usb:v2001p400B* + ID_MODEL_FROM_DATABASE=10/100 Ethernet + +usb:v2001p4102* + ID_MODEL_FROM_DATABASE=10/100 Ethernet + +usb:v2001p5100* + ID_MODEL_FROM_DATABASE=DSL-200 ADSL ATM Modem + +usb:v2001p5102* + ID_MODEL_FROM_DATABASE=DSL-200 ADSL Loader + +usb:v2001p5B00* + ID_MODEL_FROM_DATABASE=Remote NDIS Network Device + +usb:v2001p9414* + ID_MODEL_FROM_DATABASE=Cable Modem + +usb:v2001p9B00* + ID_MODEL_FROM_DATABASE=Broadband Cable Modem Remote NDIS Device + +usb:v2001pABC1* + ID_MODEL_FROM_DATABASE=DSB-650 Ethernet [pegasus] + +usb:v2001pF013* + ID_MODEL_FROM_DATABASE=DLink 7 port USB2.0 Hub + +usb:v2001pF103* + ID_MODEL_FROM_DATABASE=DUB-H7 7-port USB 2.0 hub + +usb:v2001pF10D* + ID_MODEL_FROM_DATABASE=Accent Communications Modem + +usb:v2001pF110* + ID_MODEL_FROM_DATABASE=DUB-AV300 A/V Capture + +usb:v2001pF111* + ID_MODEL_FROM_DATABASE=DBT-122 Bluetooth adapter + +usb:v2001pF112* + ID_MODEL_FROM_DATABASE=DUB-T210 Audio Device + +usb:v2001pF116* + ID_MODEL_FROM_DATABASE=Formosa 2 + +usb:v2001pF117* + ID_MODEL_FROM_DATABASE=Formosa 3 + +usb:v2001pF118* + ID_MODEL_FROM_DATABASE=Formosa 4 + +usb:v2002* + ID_VENDOR_FROM_DATABASE=DAP Technologies + +usb:v200C* + ID_VENDOR_FROM_DATABASE=Reloop + +usb:v200Cp100B* + ID_MODEL_FROM_DATABASE=Play audio soundcard + +usb:v2013* + ID_VENDOR_FROM_DATABASE=PCTV Systems + +usb:v2013p0245* + ID_MODEL_FROM_DATABASE=PCTV 73ESE + +usb:v2013p0246* + ID_MODEL_FROM_DATABASE=PCTV 74E + +usb:v2013p0248* + ID_MODEL_FROM_DATABASE=PCTV 282E + +usb:v2013p024F* + ID_MODEL_FROM_DATABASE=nanoStick T2 290e + +usb:v2019* + ID_VENDOR_FROM_DATABASE=PLANEX + +usb:v2019p3220* + ID_MODEL_FROM_DATABASE=GW-US11S WLAN [Atmel AT76C503A] + +usb:v2019p4901* + ID_MODEL_FROM_DATABASE=GW-USSuper300 802.11bgn Wireless Adapter [Realtek RTL8191SU] + +usb:v2019p4903* + ID_MODEL_FROM_DATABASE=GW-USFang300 802.11abgn Wireless Adapter [Realtek RTL8192DU] + +usb:v2019p4904* + ID_MODEL_FROM_DATABASE=GW-USUltra300 802.11abgn Wireless Adapter [Realtek RTL8192DU] + +usb:v2019p5303* + ID_MODEL_FROM_DATABASE=GW-US54GXS 802.11bg + +usb:v2019p5304* + ID_MODEL_FROM_DATABASE=GWUS300 802.11n + +usb:v2019pAB01* + ID_MODEL_FROM_DATABASE=GW-US54HP + +usb:v2019pAB24* + ID_MODEL_FROM_DATABASE=GW-US300MiniS + +usb:v2019pAB25* + ID_MODEL_FROM_DATABASE=GW-USMini2N 802.11n Wireless Adapter [Ralink RT2870] + +usb:v2019pAB28* + ID_MODEL_FROM_DATABASE=GW-USNano + +usb:v2019pAB29* + ID_MODEL_FROM_DATABASE=GW-USMicro300 + +usb:v2019pAB2A* + ID_MODEL_FROM_DATABASE=GW-USNano2 802.11n Wireless Adapter [Realtek RTL8188CUS] + +usb:v2019pAB2B* + ID_MODEL_FROM_DATABASE=GW-USEco300 802.11bgn Wireless Adapter [Realtek RTL8192CU] + +usb:v2019pAB2C* + ID_MODEL_FROM_DATABASE=GW-USDual300 802.11abgn Wireless Adapter [Realtek RTL8192DU] + +usb:v2019pAB50* + ID_MODEL_FROM_DATABASE=GW-US54Mini2 + +usb:v2019pC002* + ID_MODEL_FROM_DATABASE=GW-US54SG + +usb:v2019pC007* + ID_MODEL_FROM_DATABASE=GW-US54GZL + +usb:v2019pED02* + ID_MODEL_FROM_DATABASE=GW-USMM + +usb:v2019pED06* + ID_MODEL_FROM_DATABASE=GW-US300MiniW 802.11bgn Wireless Adapter + +usb:v2019pED10* + ID_MODEL_FROM_DATABASE=GW-US300Mini2 + +usb:v2019pED14* + ID_MODEL_FROM_DATABASE=GW-USMicroN + +usb:v2019pED16* + ID_MODEL_FROM_DATABASE=GW-USMicroN2W 802.11bgn Wireless Adapter [Realtek RTL8188SU] + +usb:v2019pED17* + ID_MODEL_FROM_DATABASE=GW-USValue-EZ 802.11n Wireless Adapter [Realtek RTL8188CUS] + +usb:v2019pED18* + ID_MODEL_FROM_DATABASE=GW-USHyper300 / GW-USH300N 802.11bgn Wireless Adapter [Realtek RTL8191SU] + +usb:v2040* + ID_VENDOR_FROM_DATABASE=Hauppauge + +usb:v2040p0C80* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p0C90* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p1700* + ID_MODEL_FROM_DATABASE=CataMount + +usb:v2040p1800* + ID_MODEL_FROM_DATABASE=Okemo A + +usb:v2040p1801* + ID_MODEL_FROM_DATABASE=Okemo B + +usb:v2040p2000* + ID_MODEL_FROM_DATABASE=Tiger Minicard + +usb:v2040p2009* + ID_MODEL_FROM_DATABASE=Tiger Minicard R2 + +usb:v2040p200A* + ID_MODEL_FROM_DATABASE=Tiger Minicard + +usb:v2040p2010* + ID_MODEL_FROM_DATABASE=Tiger Minicard + +usb:v2040p2011* + ID_MODEL_FROM_DATABASE=WinTV MiniCard [Dell Digital TV Receiver] + +usb:v2040p2019* + ID_MODEL_FROM_DATABASE=Tiger Minicard + +usb:v2040p2400* + ID_MODEL_FROM_DATABASE=WinTV PVR USB2 (Model 24019) + +usb:v2040p4700* + ID_MODEL_FROM_DATABASE=WinTV Nova-S-USB2 + +usb:v2040p4902* + ID_MODEL_FROM_DATABASE=HD PVR + +usb:v2040p4903* + ID_MODEL_FROM_DATABASE=HS PVR + +usb:v2040p4982* + ID_MODEL_FROM_DATABASE=HD PVR + +usb:v2040p5500* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p5510* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p5520* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p5530* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p5580* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p5590* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040p6500* + ID_MODEL_FROM_DATABASE=WinTV HVR-900 + +usb:v2040p6502* + ID_MODEL_FROM_DATABASE=WinTV HVR-900 + +usb:v2040p6503* + ID_MODEL_FROM_DATABASE=WinTV HVR-930 + +usb:v2040p6513* + ID_MODEL_FROM_DATABASE=WinTV HVR-980 + +usb:v2040p7050* + ID_MODEL_FROM_DATABASE=Nova-T Stick + +usb:v2040p7060* + ID_MODEL_FROM_DATABASE=Nova-T Stick 2 + +usb:v2040p7070* + ID_MODEL_FROM_DATABASE=Nova-T Stick 3 + +usb:v2040p7240* + ID_MODEL_FROM_DATABASE=WinTV HVR-850 + +usb:v2040p8400* + ID_MODEL_FROM_DATABASE=WinTV Nova-T-500 + +usb:v2040p9300* + ID_MODEL_FROM_DATABASE=WinTV NOVA-T USB2 (cold) + +usb:v2040p9301* + ID_MODEL_FROM_DATABASE=WinTV NOVA-T USB2 (warm) + +usb:v2040p9941* + ID_MODEL_FROM_DATABASE=WinTV Nova-T-500 + +usb:v2040p9950* + ID_MODEL_FROM_DATABASE=WinTV Nova-T-500 + +usb:v2040pB910* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040pB980* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040pB990* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040pC000* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2040pC010* + ID_MODEL_FROM_DATABASE=Windham + +usb:v2047* + ID_VENDOR_FROM_DATABASE=Texas Instruments + +usb:v2047p0200* + ID_MODEL_FROM_DATABASE=MSP430 USB HID Bootstrap Loader + +usb:v2080* + ID_VENDOR_FROM_DATABASE=Barnes & Noble + +usb:v2080p0001* + ID_MODEL_FROM_DATABASE=nook + +usb:v2080p0002* + ID_MODEL_FROM_DATABASE=NOOKcolor + +usb:v2080p0003* + ID_MODEL_FROM_DATABASE=NOOK Simple Touch + +usb:v2080p0004* + ID_MODEL_FROM_DATABASE=NOOK Tablet + +usb:v2087* + ID_VENDOR_FROM_DATABASE=Cando + +usb:v2087p0A01* + ID_MODEL_FROM_DATABASE=Multi Touch Panel + +usb:v2087p0A02* + ID_MODEL_FROM_DATABASE=Multi Touch Panel + +usb:v2087p0B03* + ID_MODEL_FROM_DATABASE=Multi Touch Panel + +usb:v20A0* + ID_VENDOR_FROM_DATABASE=Clay Logic + +usb:v20A0p4123* + ID_MODEL_FROM_DATABASE=IKALOGIC SCANALOGIC 2 + +usb:v20A0p414A* + ID_MODEL_FROM_DATABASE=MDE SPI Interface + +usb:v20A0p415A* + ID_MODEL_FROM_DATABASE=OpenPilot + +usb:v20A0p415B* + ID_MODEL_FROM_DATABASE=CopterControl + +usb:v20A0p415C* + ID_MODEL_FROM_DATABASE=PipXtreme + +usb:v20B1* + ID_VENDOR_FROM_DATABASE=XMOS Ltd + +usb:v20B1p10AD* + ID_MODEL_FROM_DATABASE=XUSB Loader + +usb:v20B1pF7D1* + ID_MODEL_FROM_DATABASE=XTAG2 - JTAG Adapter + +usb:v20B3* + ID_VENDOR_FROM_DATABASE=Hanvon + +usb:v20B3p0A18* + ID_MODEL_FROM_DATABASE=10.1 Touch screen overlay + +usb:v20B7* + ID_VENDOR_FROM_DATABASE=Qi Hardware + +usb:v20B7p0713* + ID_MODEL_FROM_DATABASE=Milkymist JTAG/serial + +usb:v20B7p1540* + ID_MODEL_FROM_DATABASE=ben-wpan, AT86RF230-based + +usb:v20B7p1DB5* + ID_MODEL_FROM_DATABASE=IDBG in DFU mode + +usb:v20B7p1DB6* + ID_MODEL_FROM_DATABASE=IDBG in normal mode + +usb:v20B7pC25B* + ID_MODEL_FROM_DATABASE=C2 Dongle + +usb:v20B7pCB72* + ID_MODEL_FROM_DATABASE=ben-wpan, cntr + +usb:v20DF* + ID_VENDOR_FROM_DATABASE=Simtec Electronics + +usb:v20DFp0001* + ID_MODEL_FROM_DATABASE=Entropy Key [UDEKEY01] + +usb:v20F4* + ID_VENDOR_FROM_DATABASE=TRENDnet + +usb:v20F4p648B* + ID_MODEL_FROM_DATABASE=TEW-648UBM 802.11n 150Mbps Micro Wireless N Adapter [Realtek RTL8188CUS] + +usb:v2101* + ID_VENDOR_FROM_DATABASE=ActionStar + +usb:v2101p0201* + ID_MODEL_FROM_DATABASE=SIIG 4-to-2 Printer Switch + +usb:v2149* + ID_VENDOR_FROM_DATABASE=Advanced Silicon S.A. + +usb:v2149p211B* + ID_MODEL_FROM_DATABASE=Touchscreen Controller + +usb:v2149p2703* + ID_MODEL_FROM_DATABASE=TS58xxA/TC56xxA [CoolTouch] + +usb:v2162* + ID_VENDOR_FROM_DATABASE=Creative (?) + +usb:v2162p2031* + ID_MODEL_FROM_DATABASE=Network Blaster Wireless Adapter + +usb:v2162p500C* + ID_MODEL_FROM_DATABASE=DE5771 Modem Blaster + +usb:v2162p8001* + ID_MODEL_FROM_DATABASE=Broadxent BritePort DSL Bridge 8010U + +usb:v2184* + ID_VENDOR_FROM_DATABASE=GW Instek + +usb:v2184p0005* + ID_MODEL_FROM_DATABASE=GDS-3000 Oscilloscope + +usb:v2184p0006* + ID_MODEL_FROM_DATABASE=GDS-3000 Oscilloscope + +usb:v2184p0011* + ID_MODEL_FROM_DATABASE=AFG Function Generator (CDC) + +usb:v21A1* + ID_VENDOR_FROM_DATABASE=Emotiv Systems Pty. Ltd. + +usb:v21A1p0001* + ID_MODEL_FROM_DATABASE=EPOC Consumer Headset Wireless Dongle + +usb:v21D6* + ID_VENDOR_FROM_DATABASE=Agecodagis SARL + +usb:v21D6p0002* + ID_MODEL_FROM_DATABASE=Seismic recorder [Tellus] + +usb:v2222* + ID_VENDOR_FROM_DATABASE=MacAlly + +usb:v2222p0004* + ID_MODEL_FROM_DATABASE=iWebKey Keyboard + +usb:v2222p2520* + ID_MODEL_FROM_DATABASE=Mini Tablet + +usb:v2222p4050* + ID_MODEL_FROM_DATABASE=AirStick joystick + +usb:v2227* + ID_VENDOR_FROM_DATABASE=SAMWOO Enterprise + +usb:v2227p3105* + ID_MODEL_FROM_DATABASE=SKYDATA SKD-U100 + +usb:v2232* + ID_VENDOR_FROM_DATABASE=Silicon Motion + +usb:v2232p1005* + ID_MODEL_FROM_DATABASE=WebCam SCB-0385N + +usb:v2232p1028* + ID_MODEL_FROM_DATABASE=WebCam SC-03FFL11939N + +usb:v2232p1029* + ID_MODEL_FROM_DATABASE=WebCam SC-13HDL11939N + +usb:v2232p1037* + ID_MODEL_FROM_DATABASE=WebCam SC-03FFM12339N + +usb:v2233* + ID_VENDOR_FROM_DATABASE=RadioShack Corporation + +usb:v2233p6323* + ID_MODEL_FROM_DATABASE=USB Electronic Scale + +usb:v2237* + ID_VENDOR_FROM_DATABASE=Kobo Inc. + +usb:v2237p4161* + ID_MODEL_FROM_DATABASE=eReader White + +usb:v22A6* + ID_VENDOR_FROM_DATABASE=Pie Digital, Inc. + +usb:v22A6pFFFF* + ID_MODEL_FROM_DATABASE=PieKey "beta" 4GB model 4E4F41482E4F5247 (SM3251Q BB) + +usb:v22B8* + ID_VENDOR_FROM_DATABASE=Motorola PCS + +usb:v22B8p0001* + ID_MODEL_FROM_DATABASE=Wally 2.2 chipset + +usb:v22B8p0002* + ID_MODEL_FROM_DATABASE=Wally 2.4 chipset + +usb:v22B8p0005* + ID_MODEL_FROM_DATABASE=V.60c/V.60i GSM Phone + +usb:v22B8p0830* + ID_MODEL_FROM_DATABASE=2386C-HT820 + +usb:v22B8p0833* + ID_MODEL_FROM_DATABASE=2386C-HT820 [Flash Mode] + +usb:v22B8p0850* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v22B8p1001* + ID_MODEL_FROM_DATABASE=Patriot 1.0 (GSM) chipset + +usb:v22B8p1002* + ID_MODEL_FROM_DATABASE=Patriot 2.0 chipset + +usb:v22B8p1005* + ID_MODEL_FROM_DATABASE=T280e GSM/GPRS Phone + +usb:v22B8p1101* + ID_MODEL_FROM_DATABASE=Patriot 1.0 (TDMA) chipset + +usb:v22B8p1801* + ID_MODEL_FROM_DATABASE=Rainbow chipset flash + +usb:v22B8p2035* + ID_MODEL_FROM_DATABASE=Bluetooth Device + +usb:v22B8p2805* + ID_MODEL_FROM_DATABASE=GSM Modem + +usb:v22B8p2821* + ID_MODEL_FROM_DATABASE=T720 GSM Phone + +usb:v22B8p2822* + ID_MODEL_FROM_DATABASE=V.120e GSM Phone + +usb:v22B8p2823* + ID_MODEL_FROM_DATABASE=Flash Interface + +usb:v22B8p2A01* + ID_MODEL_FROM_DATABASE=MSM6050 chipset + +usb:v22B8p2A02* + ID_MODEL_FROM_DATABASE=CDMA modem + +usb:v22B8p2A03* + ID_MODEL_FROM_DATABASE=MSM6050 chipset flash + +usb:v22B8p2A21* + ID_MODEL_FROM_DATABASE=V710 GSM Phone (P2K) + +usb:v22B8p2A22* + ID_MODEL_FROM_DATABASE=V710 GSM Phone (AT) + +usb:v22B8p2A23* + ID_MODEL_FROM_DATABASE=MSM6100 chipset flash + +usb:v22B8p2A41* + ID_MODEL_FROM_DATABASE=MSM6300 chipset + +usb:v22B8p2A42* + ID_MODEL_FROM_DATABASE=Usb Modem + +usb:v22B8p2A43* + ID_MODEL_FROM_DATABASE=MSM6300 chipset flash + +usb:v22B8p2A61* + ID_MODEL_FROM_DATABASE=E815 GSM Phone (P2K) + +usb:v22B8p2A62* + ID_MODEL_FROM_DATABASE=E815 GSM Phone (AT) + +usb:v22B8p2A63* + ID_MODEL_FROM_DATABASE=MSM6500 chipset flash + +usb:v22B8p2A81* + ID_MODEL_FROM_DATABASE=MSM6025 chipset + +usb:v22B8p2A83* + ID_MODEL_FROM_DATABASE=MSM6025 chipset flash + +usb:v22B8p2AC1* + ID_MODEL_FROM_DATABASE=MSM6100 chipset + +usb:v22B8p2AC3* + ID_MODEL_FROM_DATABASE=MSM6100 chipset flash + +usb:v22B8p2D78* + ID_MODEL_FROM_DATABASE=XT300[SPICE] + +usb:v22B8p3001* + ID_MODEL_FROM_DATABASE=A835/E1000 GSM Phone (P2K) + +usb:v22B8p3002* + ID_MODEL_FROM_DATABASE=A835/E1000 GSM Phone (AT) + +usb:v22B8p3801* + ID_MODEL_FROM_DATABASE=C350L/C450 (P2K) + +usb:v22B8p3802* + ID_MODEL_FROM_DATABASE=C330/C350L/C450/EZX GSM Phone (AT) + +usb:v22B8p3803* + ID_MODEL_FROM_DATABASE=Neptune LT chipset flash + +usb:v22B8p4001* + ID_MODEL_FROM_DATABASE=OMAP 1.0 chipset + +usb:v22B8p4002* + ID_MODEL_FROM_DATABASE=A920/A925 UMTS Phone + +usb:v22B8p4003* + ID_MODEL_FROM_DATABASE=OMAP 1.0 chipset flash + +usb:v22B8p4008* + ID_MODEL_FROM_DATABASE=OMAP 1.0 chipset RDL + +usb:v22B8p41D6* + ID_MODEL_FROM_DATABASE=Droid X (Windows media mode) + +usb:v22B8p41D9* + ID_MODEL_FROM_DATABASE=Droid/Milestone + +usb:v22B8p41DB* + ID_MODEL_FROM_DATABASE=Droid/Milestone (Debug mode) + +usb:v22B8p41DE* + ID_MODEL_FROM_DATABASE=Droid X (PC mode) + +usb:v22B8p4204* + ID_MODEL_FROM_DATABASE=MPx200 Smartphone + +usb:v22B8p4214* + ID_MODEL_FROM_DATABASE=MPc GSM + +usb:v22B8p4224* + ID_MODEL_FROM_DATABASE=MPx220 Smartphone + +usb:v22B8p4234* + ID_MODEL_FROM_DATABASE=MPc CDMA + +usb:v22B8p4244* + ID_MODEL_FROM_DATABASE=MPx100 Smartphone + +usb:v22B8p4285* + ID_MODEL_FROM_DATABASE=Droid X (Mass storage) + +usb:v22B8p4801* + ID_MODEL_FROM_DATABASE=Neptune LTS chipset + +usb:v22B8p4803* + ID_MODEL_FROM_DATABASE=Neptune LTS chipset flash + +usb:v22B8p4810* + ID_MODEL_FROM_DATABASE=Triplet GSM Phone (storage) + +usb:v22B8p4901* + ID_MODEL_FROM_DATABASE=Triplet GSM Phone (P2K) + +usb:v22B8p4902* + ID_MODEL_FROM_DATABASE=Triplet GSM Phone (AT) + +usb:v22B8p4903* + ID_MODEL_FROM_DATABASE=Neptune LTE chipset flash + +usb:v22B8p4A01* + ID_MODEL_FROM_DATABASE=Neptune LTX chipset + +usb:v22B8p4A03* + ID_MODEL_FROM_DATABASE=Neptune LTX chipset flash + +usb:v22B8p4A32* + ID_MODEL_FROM_DATABASE=L6-imode Phone + +usb:v22B8p5801* + ID_MODEL_FROM_DATABASE=Neptune ULS chipset + +usb:v22B8p5803* + ID_MODEL_FROM_DATABASE=Neptune ULS chipset flash + +usb:v22B8p5901* + ID_MODEL_FROM_DATABASE=Neptune VLT chipset + +usb:v22B8p5903* + ID_MODEL_FROM_DATABASE=Neptune VLT chipset flash + +usb:v22B8p6001* + ID_MODEL_FROM_DATABASE=Dalhart EZX + +usb:v22B8p6003* + ID_MODEL_FROM_DATABASE=Dalhart flash + +usb:v22B8p6004* + ID_MODEL_FROM_DATABASE=EZX GSM Phone (CDC Net) + +usb:v22B8p6006* + ID_MODEL_FROM_DATABASE=MOTOROKR E6 + +usb:v22B8p6008* + ID_MODEL_FROM_DATABASE=Dalhart RDL + +usb:v22B8p6009* + ID_MODEL_FROM_DATABASE=EZX GSM Phone (P2K) + +usb:v22B8p600A* + ID_MODEL_FROM_DATABASE=Dalhart EZX config 17 + +usb:v22B8p600B* + ID_MODEL_FROM_DATABASE=Dalhart EZX config 18 + +usb:v22B8p600C* + ID_MODEL_FROM_DATABASE=EZX GSM Phone (USBLAN) + +usb:v22B8p6021* + ID_MODEL_FROM_DATABASE=JUIX chipset + +usb:v22B8p6023* + ID_MODEL_FROM_DATABASE=JUIX chipset flash + +usb:v22B8p6026* + ID_MODEL_FROM_DATABASE=Flash RAM Downloader/miniOS + +usb:v22B8p6027* + ID_MODEL_FROM_DATABASE=USBLAN + +usb:v22B8p604C* + ID_MODEL_FROM_DATABASE=EZX GSM Phone (Storage) + +usb:v22B8p6101* + ID_MODEL_FROM_DATABASE=Talon integrated chipset + +usb:v22B8p6401* + ID_MODEL_FROM_DATABASE=Argon chipset + +usb:v22B8p6403* + ID_MODEL_FROM_DATABASE=Argon chipset flash + +usb:v22B8p6415* + ID_MODEL_FROM_DATABASE=ROKR Z6 (MTP mode) + +usb:v22B8p6604* + ID_MODEL_FROM_DATABASE=Washington CDMA Phone + +usb:v22B8p6631* + ID_MODEL_FROM_DATABASE=CDC Modem + +usb:v22B8p7001* + ID_MODEL_FROM_DATABASE=Q Smartphone + +usb:v22B8pFE01* + ID_MODEL_FROM_DATABASE=StarTAC III MS900 + +usb:v22B9* + ID_VENDOR_FROM_DATABASE=eTurboTouch Technology, Inc. + +usb:v22B9p0006* + ID_MODEL_FROM_DATABASE=Touch Screen + +usb:v22BA* + ID_VENDOR_FROM_DATABASE=Technology Innovation Holdings, Ltd + +usb:v2304* + ID_VENDOR_FROM_DATABASE=Pinnacle Systems, Inc. + +usb:v2304p0109* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (SECAM) + +usb:v2304p0110* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (PAL) + +usb:v2304p0111* + ID_MODEL_FROM_DATABASE=Miro PCTV USB + +usb:v2304p0112* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (NTSC) with FM radio + +usb:v2304p0201* + ID_MODEL_FROM_DATABASE=Systems MovieBox Device + +usb:v2304p0204* + ID_MODEL_FROM_DATABASE=MovieBox USB_B + +usb:v2304p0205* + ID_MODEL_FROM_DATABASE=DVC 150B + +usb:v2304p0206* + ID_MODEL_FROM_DATABASE=Systems MovieBox Deluxe Device + +usb:v2304p0207* + ID_MODEL_FROM_DATABASE=Dazzle DVC90 Video Device + +usb:v2304p0208* + ID_MODEL_FROM_DATABASE=Studio PCTV USB2 + +usb:v2304p020E* + ID_MODEL_FROM_DATABASE=PCTV 200e + +usb:v2304p020F* + ID_MODEL_FROM_DATABASE=PCTV 400e BDA Device + +usb:v2304p0210* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (PAL) with FM radio + +usb:v2304p0212* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (NTSC) + +usb:v2304p0213* + ID_MODEL_FROM_DATABASE=500-USB Device + +usb:v2304p0214* + ID_MODEL_FROM_DATABASE=Studio PCTV USB (PAL) with FM radio + +usb:v2304p0216* + ID_MODEL_FROM_DATABASE=PCTV 60e + +usb:v2304p0219* + ID_MODEL_FROM_DATABASE=PCTV 260e + +usb:v2304p021A* + ID_MODEL_FROM_DATABASE=Dazzle DVC100 Audio Device + +usb:v2304p021B* + ID_MODEL_FROM_DATABASE=Dazzle DVC130/DVC170 + +usb:v2304p021D* + ID_MODEL_FROM_DATABASE=Dazzle DVC130 + +usb:v2304p021E* + ID_MODEL_FROM_DATABASE=Dazzle DVC170 + +usb:v2304p021F* + ID_MODEL_FROM_DATABASE=PCTV Sat HDTV Pro BDA Device + +usb:v2304p0222* + ID_MODEL_FROM_DATABASE=PCTV Sat Pro BDA Device + +usb:v2304p0223* + ID_MODEL_FROM_DATABASE=DazzleTV Sat BDA Device + +usb:v2304p0225* + ID_MODEL_FROM_DATABASE=Remote Kit Infrared Transceiver + +usb:v2304p0226* + ID_MODEL_FROM_DATABASE=PCTV 330e + +usb:v2304p0227* + ID_MODEL_FROM_DATABASE=PCTV for Mac, HD Stick + +usb:v2304p0228* + ID_MODEL_FROM_DATABASE=PCTV DVB-T Flash Stick + +usb:v2304p0229* + ID_MODEL_FROM_DATABASE=PCTV Dual DVB-T 2001e + +usb:v2304p022A* + ID_MODEL_FROM_DATABASE=PCTV 160e + +usb:v2304p022B* + ID_MODEL_FROM_DATABASE=PCTV 71e [Afatech AF9015] + +usb:v2304p0232* + ID_MODEL_FROM_DATABASE=PCTV 170e + +usb:v2304p0236* + ID_MODEL_FROM_DATABASE=PCTV 72e [DiBcom DiB7000PC] + +usb:v2304p0237* + ID_MODEL_FROM_DATABASE=PCTV 73e [DiBcom DiB7000PC] + +usb:v2304p023A* + ID_MODEL_FROM_DATABASE=PCTV 801e + +usb:v2304p023B* + ID_MODEL_FROM_DATABASE=PCTV 801e SE + +usb:v2304p023D* + ID_MODEL_FROM_DATABASE=PCTV 340e + +usb:v2304p023E* + ID_MODEL_FROM_DATABASE=PCTV 340e SE + +usb:v2304p0300* + ID_MODEL_FROM_DATABASE=Studio Linx Video input cable (NTSC) + +usb:v2304p0301* + ID_MODEL_FROM_DATABASE=Studio Linx Video input cable (PAL) + +usb:v2304p0302* + ID_MODEL_FROM_DATABASE=Dazzle DVC120 + +usb:v2304p0419* + ID_MODEL_FROM_DATABASE=PCTV Bungee USB (PAL) with FM radio + +usb:v2304p061D* + ID_MODEL_FROM_DATABASE=PCTV Deluxe (NTSC) Device + +usb:v2304p061E* + ID_MODEL_FROM_DATABASE=PCTV Deluxe (PAL) Device + +usb:v2318* + ID_VENDOR_FROM_DATABASE=Shining Technologies, Inc. [hex] + +usb:v2318p0011* + ID_MODEL_FROM_DATABASE=CitiDISK Jr. IDE Enclosure + +usb:v2341* + ID_VENDOR_FROM_DATABASE=Arduino SA + +usb:v2341p0001* + ID_MODEL_FROM_DATABASE=Uno (CDC ACM) + +usb:v2341p0010* + ID_MODEL_FROM_DATABASE=Mega 2560 (CDC ACM) + +usb:v2341p003B* + ID_MODEL_FROM_DATABASE=Serial Adapter (CDC ACM) + +usb:v2341p003F* + ID_MODEL_FROM_DATABASE=Mega ADK (CDC ACM) + +usb:v2341p0042* + ID_MODEL_FROM_DATABASE=Mega 2560 R3 (CDC ACM) + +usb:v2341p0043* + ID_MODEL_FROM_DATABASE=Uno R3 (CDC ACM) + +usb:v2341p0044* + ID_MODEL_FROM_DATABASE=Mega ADK R3 (CDC ACM) + +usb:v2341p0045* + ID_MODEL_FROM_DATABASE=Serial R3 (CDC ACM) + +usb:v2341p8036* + ID_MODEL_FROM_DATABASE=Leonardo (CDC ACM, HID) + +usb:v2373* + ID_VENDOR_FROM_DATABASE=Pumatronix Ltda + +usb:v2373p0001* + ID_MODEL_FROM_DATABASE=5 MegaPixel Digital Still Camera [DSC5M] + +usb:v2375* + ID_VENDOR_FROM_DATABASE=Digit@lway, Inc. + +usb:v2375p0001* + ID_MODEL_FROM_DATABASE=Digital Audio Player + +usb:v2406* + ID_VENDOR_FROM_DATABASE=SANHO Digital Electronics Co., Ltd. + +usb:v2406p6688* + ID_MODEL_FROM_DATABASE=PD7X Portable Storage + +usb:v2443* + ID_VENDOR_FROM_DATABASE=Aessent Technology Ltd + +usb:v2443p00DC* + ID_MODEL_FROM_DATABASE=aes220 FPGA Mini-Module + +usb:v2478* + ID_VENDOR_FROM_DATABASE=Tripp-Lite + +usb:v2478p2008* + ID_MODEL_FROM_DATABASE=U209-000-R Serial Port + +usb:v2632* + ID_VENDOR_FROM_DATABASE=TwinMOS + +usb:v2632p3209* + ID_MODEL_FROM_DATABASE=7-in-1 Card Reader + +usb:v2650* + ID_VENDOR_FROM_DATABASE=Electronics For Imaging, Inc. [hex] + +usb:v2659* + ID_VENDOR_FROM_DATABASE=Sundtek + +usb:v2659p1101* + ID_MODEL_FROM_DATABASE=TNT DVB-T/DAB/DAB+/FM + +usb:v2659p1201* + ID_MODEL_FROM_DATABASE=FM Transmitter/Receiver + +usb:v2659p1202* + ID_MODEL_FROM_DATABASE=MediaTV Analog/FM/DVB-T + +usb:v2659p1203* + ID_MODEL_FROM_DATABASE=MediaTV Analog/FM/DVB-T MiniPCIe + +usb:v2659p1204* + ID_MODEL_FROM_DATABASE=MediaTV Analog/FM/ATSC + +usb:v2659p1205* + ID_MODEL_FROM_DATABASE=SkyTV Ultimate V + +usb:v2659p1206* + ID_MODEL_FROM_DATABASE=MediaTV DVB-T MiniPCIe + +usb:v2659p1207* + ID_MODEL_FROM_DATABASE=Sundtek HD Capture + +usb:v2659p1208* + ID_MODEL_FROM_DATABASE=Sundtek SkyTV Ultimate III + +usb:v2659p1209* + ID_MODEL_FROM_DATABASE=MediaTV Analog/FM/ATSC MiniPCIe + +usb:v2659p1210* + ID_MODEL_FROM_DATABASE=MediaTV Pro III (EU) + +usb:v2659p1211* + ID_MODEL_FROM_DATABASE=MediaTV Pro III (US) + +usb:v2659p1212* + ID_MODEL_FROM_DATABASE=MediaTV Pro III MiniPCIe (EU) + +usb:v2659p1213* + ID_MODEL_FROM_DATABASE=MediaTV Pro III MiniPCIe (US) + +usb:v2730* + ID_VENDOR_FROM_DATABASE=Citizen + +usb:v2730p200F* + ID_MODEL_FROM_DATABASE=CT-S310 Label printer + +usb:v2735* + ID_VENDOR_FROM_DATABASE=DigitalWay + +usb:v2735p0003* + ID_MODEL_FROM_DATABASE=MPIO HS100 + +usb:v2735p1001* + ID_MODEL_FROM_DATABASE=MPIO FY200 + +usb:v2735p1002* + ID_MODEL_FROM_DATABASE=MPIO FL100 + +usb:v2735p1003* + ID_MODEL_FROM_DATABASE=MPIO FD100 + +usb:v2735p1004* + ID_MODEL_FROM_DATABASE=MPIO HD200 + +usb:v2735p1005* + ID_MODEL_FROM_DATABASE=MPIO HD300 + +usb:v2735p1006* + ID_MODEL_FROM_DATABASE=MPIO FG100 + +usb:v2735p1007* + ID_MODEL_FROM_DATABASE=MPIO FG130 + +usb:v2735p1008* + ID_MODEL_FROM_DATABASE=MPIO FY300 + +usb:v2735p1009* + ID_MODEL_FROM_DATABASE=MPIO FY400 + +usb:v2735p100A* + ID_MODEL_FROM_DATABASE=MPIO FL300 + +usb:v2735p100B* + ID_MODEL_FROM_DATABASE=MPIO HS200 + +usb:v2735p100C* + ID_MODEL_FROM_DATABASE=MPIO FL350 + +usb:v2735p100D* + ID_MODEL_FROM_DATABASE=MPIO FY500 + +usb:v2735p100E* + ID_MODEL_FROM_DATABASE=MPIO FY500 + +usb:v2735p100F* + ID_MODEL_FROM_DATABASE=MPIO FY600 + +usb:v2735p1012* + ID_MODEL_FROM_DATABASE=MPIO FL400 + +usb:v2735p1013* + ID_MODEL_FROM_DATABASE=MPIO HD400 + +usb:v2735p1014* + ID_MODEL_FROM_DATABASE=MPIO HD400 + +usb:v2735p1016* + ID_MODEL_FROM_DATABASE=MPIO FY700 + +usb:v2735p1017* + ID_MODEL_FROM_DATABASE=MPIO FY700 + +usb:v2735p1018* + ID_MODEL_FROM_DATABASE=MPIO FY800 + +usb:v2735p1019* + ID_MODEL_FROM_DATABASE=MPIO FY800 + +usb:v2735p101A* + ID_MODEL_FROM_DATABASE=MPIO FY900 + +usb:v2735p101B* + ID_MODEL_FROM_DATABASE=MPIO FY900 + +usb:v2735p102B* + ID_MODEL_FROM_DATABASE=MPIO FL500 + +usb:v2735p102C* + ID_MODEL_FROM_DATABASE=MPIO FL500 + +usb:v2735p103F* + ID_MODEL_FROM_DATABASE=MPIO FY570 + +usb:v2735p1040* + ID_MODEL_FROM_DATABASE=MPIO FY570 + +usb:v2735p1041* + ID_MODEL_FROM_DATABASE=MPIO FY670 + +usb:v2735p1042* + ID_MODEL_FROM_DATABASE=MPIO FY670 + +usb:v2735p1043* + ID_MODEL_FROM_DATABASE=HCT HMD-180A + +usb:v2735p1044* + ID_MODEL_FROM_DATABASE=HCT HMD-180A + +usb:v2770* + ID_VENDOR_FROM_DATABASE=NHJ, Ltd + +usb:v2770p0A01* + ID_MODEL_FROM_DATABASE=ScanJet 4600 series + +usb:v2770p905C* + ID_MODEL_FROM_DATABASE=Che-Ez Snap SNAP-U/Digigr8/Soundstar TDC-35 + +usb:v2770p9060* + ID_MODEL_FROM_DATABASE=A130 + +usb:v2770p9120* + ID_MODEL_FROM_DATABASE=Che-ez! Snap / iClick Tiny VGA Digital Camera + +usb:v2770p9130* + ID_MODEL_FROM_DATABASE=TCG 501 + +usb:v2770p913C* + ID_MODEL_FROM_DATABASE=Argus DC-1730 + +usb:v2770p9150* + ID_MODEL_FROM_DATABASE=Mini Cam + +usb:v2770p9153* + ID_MODEL_FROM_DATABASE=iClick 5X + +usb:v2770p915D* + ID_MODEL_FROM_DATABASE=Cyberpix S-210S / Little Tikes My Real Digital Camera + +usb:v2770p930B* + ID_MODEL_FROM_DATABASE=CCD Webcam(PC370R) + +usb:v2770p930C* + ID_MODEL_FROM_DATABASE=CCD Webcam(PC370R) + +usb:v2821* + ID_VENDOR_FROM_DATABASE=ASUSTek Computer Inc. + +usb:v2821p0161* + ID_MODEL_FROM_DATABASE=WL-161 802.11b Wireless Adapter [SiS 162U] + +usb:v2821p160F* + ID_MODEL_FROM_DATABASE=WL-160g 802.11g Wireless Adapter [Envara WiND512] + +usb:v2821p3300* + ID_MODEL_FROM_DATABASE=WL-140 / Hawking HWU36D 802.11b Wireless Adapter [Intersil PRISM 3] + +usb:v2899* + ID_VENDOR_FROM_DATABASE=Toptronic Industrial Co., Ltd + +usb:v2899p012C* + ID_MODEL_FROM_DATABASE=Camera Device + +usb:v2C02* + ID_VENDOR_FROM_DATABASE=Planex Communications + +usb:v2C02p14EA* + ID_MODEL_FROM_DATABASE=GW-US11H WLAN + +usb:v2C1A* + ID_VENDOR_FROM_DATABASE=Dolphin Peripherals + +usb:v2C1Ap0000* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse + +usb:v2FB2* + ID_VENDOR_FROM_DATABASE=Fujitsu, Ltd + +usb:v3125* + ID_VENDOR_FROM_DATABASE=Eagletron + +usb:v3125p0001* + ID_MODEL_FROM_DATABASE=TrackerPod Camera Stand + +usb:v3176* + ID_VENDOR_FROM_DATABASE=Whanam Electronics Co., Ltd + +usb:v3275* + ID_VENDOR_FROM_DATABASE=VidzMedia Pte Ltd + +usb:v3275p4FB1* + ID_MODEL_FROM_DATABASE=MonsterTV P2H + +usb:v3334* + ID_VENDOR_FROM_DATABASE=AEI + +usb:v3334p1701* + ID_MODEL_FROM_DATABASE=Fast Ethernet + +usb:v3340* + ID_VENDOR_FROM_DATABASE=Yakumo + +usb:v3340p043A* + ID_MODEL_FROM_DATABASE=Mio A701 DigiWalker PPCPhone + +usb:v3340p0E3A* + ID_MODEL_FROM_DATABASE=Pocket PC 300 GPS SL / Typhoon MyGuide 3500 + +usb:v3340pA0A3* + ID_MODEL_FROM_DATABASE=deltaX 5 BT (D) PDA + +usb:v3504* + ID_VENDOR_FROM_DATABASE=Micro Star + +usb:v3504pF110* + ID_MODEL_FROM_DATABASE=Security Key + +usb:v3538* + ID_VENDOR_FROM_DATABASE=Power Quotient International Co., Ltd + +usb:v3538p0001* + ID_MODEL_FROM_DATABASE=Travel Flash + +usb:v3538p0015* + ID_MODEL_FROM_DATABASE=Mass Storge Device + +usb:v3538p0022* + ID_MODEL_FROM_DATABASE=Hi-Speed Mass Storage Device + +usb:v3538p0042* + ID_MODEL_FROM_DATABASE=Cool Drive U339 Flash Disk + +usb:v3538p0054* + ID_MODEL_FROM_DATABASE=Flash Drive (2GB) + +usb:v3579* + ID_VENDOR_FROM_DATABASE=DIVA + +usb:v3579p6901* + ID_MODEL_FROM_DATABASE=Media Reader + +usb:v3636* + ID_VENDOR_FROM_DATABASE=InVibro + +usb:v3838* + ID_VENDOR_FROM_DATABASE=WEM + +usb:v3838p0001* + ID_MODEL_FROM_DATABASE=5-in-1 Card Reader + +usb:v3923* + ID_VENDOR_FROM_DATABASE=National Instruments Corp. + +usb:v3923p12C0* + ID_MODEL_FROM_DATABASE=DAQPad-6020E + +usb:v3923p12D0* + ID_MODEL_FROM_DATABASE=DAQPad-6507 + +usb:v3923p12E0* + ID_MODEL_FROM_DATABASE=NI 4350 + +usb:v3923p12F0* + ID_MODEL_FROM_DATABASE=NI 5102 + +usb:v3923p1750* + ID_MODEL_FROM_DATABASE=DAQPad-6508 + +usb:v3923p17B0* + ID_MODEL_FROM_DATABASE=USB-ISA-Bridge + +usb:v3923p1820* + ID_MODEL_FROM_DATABASE=DAQPad-6020E (68 pin I/O) + +usb:v3923p1830* + ID_MODEL_FROM_DATABASE=DAQPad-6020E (BNC) + +usb:v3923p1F00* + ID_MODEL_FROM_DATABASE=DAQPad-6024E + +usb:v3923p1F10* + ID_MODEL_FROM_DATABASE=DAQPad-6024E + +usb:v3923p1F20* + ID_MODEL_FROM_DATABASE=DAQPad-6025E + +usb:v3923p1F30* + ID_MODEL_FROM_DATABASE=DAQPad-6025E + +usb:v3923p1F40* + ID_MODEL_FROM_DATABASE=DAQPad-6036E + +usb:v3923p1F50* + ID_MODEL_FROM_DATABASE=DAQPad-6036E + +usb:v3923p2F80* + ID_MODEL_FROM_DATABASE=DAQPad-6052E + +usb:v3923p2F90* + ID_MODEL_FROM_DATABASE=DAQPad-6052E + +usb:v3923p702B* + ID_MODEL_FROM_DATABASE=GPIB-USB-B + +usb:v3923p703C* + ID_MODEL_FROM_DATABASE=USB-485 RS485 Cable + +usb:v3923p709B* + ID_MODEL_FROM_DATABASE=GPIB-USB-HS + +usb:v3923p7254* + ID_MODEL_FROM_DATABASE=NI MIO (data acquisition card) firmware updater + +usb:v3923p729E* + ID_MODEL_FROM_DATABASE=USB-6251 (OEM) data acquisition card + +usb:v40BB* + ID_VENDOR_FROM_DATABASE=I-O Data + +usb:v40BBp0A09* + ID_MODEL_FROM_DATABASE=USB2.0-SCSI Bridge USB2-SC + +usb:v4101* + ID_VENDOR_FROM_DATABASE=i-rocks + +usb:v4101p1301* + ID_MODEL_FROM_DATABASE=IR-2510 usb phone + +usb:v4102* + ID_VENDOR_FROM_DATABASE=iRiver, Ltd. + +usb:v4102p1001* + ID_MODEL_FROM_DATABASE=iFP-100 series mp3 player + +usb:v4102p1003* + ID_MODEL_FROM_DATABASE=iFP-300 series mp3 player + +usb:v4102p1005* + ID_MODEL_FROM_DATABASE=iFP-500 series mp3 player + +usb:v4102p1007* + ID_MODEL_FROM_DATABASE=iFP-700 series mp3/ogg vorbis player + +usb:v4102p1008* + ID_MODEL_FROM_DATABASE=iFP-800 series mp3/ogg vorbis player + +usb:v4102p100A* + ID_MODEL_FROM_DATABASE=iFP-1000 series mp3/ogg vorbis player + +usb:v4102p1014* + ID_MODEL_FROM_DATABASE=T20 series mp3/ogg vorbis player (ums firmware) + +usb:v4102p1019* + ID_MODEL_FROM_DATABASE=T30 + +usb:v4102p1034* + ID_MODEL_FROM_DATABASE=T60 + +usb:v4102p1040* + ID_MODEL_FROM_DATABASE=M1Player + +usb:v4102p1041* + ID_MODEL_FROM_DATABASE=E100 (ums) + +usb:v4102p1101* + ID_MODEL_FROM_DATABASE=iFP-100 series mp3 player (ums firmware) + +usb:v4102p1103* + ID_MODEL_FROM_DATABASE=iFP-300 series mp3 player (ums firmware) + +usb:v4102p1105* + ID_MODEL_FROM_DATABASE=iFP-500 series mp3 player (ums firmware) + +usb:v4102p1113* + ID_MODEL_FROM_DATABASE=T10 (alternate) + +usb:v4102p1117* + ID_MODEL_FROM_DATABASE=T10 + +usb:v4102p1119* + ID_MODEL_FROM_DATABASE=T30 series mp3/ogg/wma player + +usb:v4102p1141* + ID_MODEL_FROM_DATABASE=E100 (mtp) + +usb:v4102p2002* + ID_MODEL_FROM_DATABASE=H10 6GB + +usb:v4102p2101* + ID_MODEL_FROM_DATABASE=H10 20GB (mtp) + +usb:v4102p2102* + ID_MODEL_FROM_DATABASE=H10 5GB (mtp) + +usb:v4102p2105* + ID_MODEL_FROM_DATABASE=H10 5/6GB (mtp) + +usb:v413C* + ID_VENDOR_FROM_DATABASE=Dell Computer Corp. + +usb:v413Cp0000* + ID_MODEL_FROM_DATABASE=DRAC 5 Virtual Keyboard and Mouse + +usb:v413Cp0001* + ID_MODEL_FROM_DATABASE=DRAC 5 Virtual Media + +usb:v413Cp0058* + ID_MODEL_FROM_DATABASE=Port Replicator + +usb:v413Cp1001* + ID_MODEL_FROM_DATABASE=Keyboard Hub + +usb:v413Cp1002* + ID_MODEL_FROM_DATABASE=Keyboard Hub + +usb:v413Cp1003* + ID_MODEL_FROM_DATABASE=Keyboard Hub + +usb:v413Cp1005* + ID_MODEL_FROM_DATABASE=Multimedia Pro Keyboard Hub + +usb:v413Cp2001* + ID_MODEL_FROM_DATABASE=Keyboard HID Support + +usb:v413Cp2002* + ID_MODEL_FROM_DATABASE=SK-8125 Keyboard + +usb:v413Cp2003* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v413Cp2005* + ID_MODEL_FROM_DATABASE=RT7D50 Keyboard + +usb:v413Cp2010* + ID_MODEL_FROM_DATABASE=Keyboard + +usb:v413Cp2011* + ID_MODEL_FROM_DATABASE=Multimedia Pro Keyboard + +usb:v413Cp2100* + ID_MODEL_FROM_DATABASE=SK-3106 Keyboard + +usb:v413Cp2101* + ID_MODEL_FROM_DATABASE=SmartCard Reader Keyboard + +usb:v413Cp2105* + ID_MODEL_FROM_DATABASE=Model L100 Keyboard + +usb:v413Cp2106* + ID_MODEL_FROM_DATABASE=Dell QuietKey Keyboard + +usb:v413Cp2500* + ID_MODEL_FROM_DATABASE=DRAC4 Remote Access Card + +usb:v413Cp2513* + ID_MODEL_FROM_DATABASE=internal USB Hub of E-Port Replicator + +usb:v413Cp3010* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse + +usb:v413Cp3012* + ID_MODEL_FROM_DATABASE=Optical Wheel Mouse + +usb:v413Cp3016* + ID_MODEL_FROM_DATABASE=Optical 5-Button Wheel Mouse + +usb:v413Cp3200* + ID_MODEL_FROM_DATABASE=Mouse + +usb:v413Cp4001* + ID_MODEL_FROM_DATABASE=Axim X5 + +usb:v413Cp4002* + ID_MODEL_FROM_DATABASE=Axim X3 + +usb:v413Cp4003* + ID_MODEL_FROM_DATABASE=Axim X30 + +usb:v413Cp4004* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4005* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4006* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4007* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4008* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4009* + ID_MODEL_FROM_DATABASE=Axim Sync + +usb:v413Cp4011* + ID_MODEL_FROM_DATABASE=Axim X51v + +usb:v413Cp5103* + ID_MODEL_FROM_DATABASE=AIO Printer A940 + +usb:v413Cp5105* + ID_MODEL_FROM_DATABASE=AIO Printer A920 + +usb:v413Cp5107* + ID_MODEL_FROM_DATABASE=AIO Printer A960 + +usb:v413Cp5109* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 922 + +usb:v413Cp5110* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 962 + +usb:v413Cp5111* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 942 + +usb:v413Cp5112* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 924 + +usb:v413Cp5113* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 944 + +usb:v413Cp5114* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 964 + +usb:v413Cp5115* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 926 + +usb:v413Cp5116* + ID_MODEL_FROM_DATABASE=AIO Printer 946 + +usb:v413Cp5117* + ID_MODEL_FROM_DATABASE=Photo AIO Printer 966 + +usb:v413Cp5118* + ID_MODEL_FROM_DATABASE=AIO 810 + +usb:v413Cp5124* + ID_MODEL_FROM_DATABASE=Laser MFP 1815 + +usb:v413Cp5128* + ID_MODEL_FROM_DATABASE=Photo AIO 928 + +usb:v413Cp5200* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v413Cp5202* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp5203* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp5210* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp5211* + ID_MODEL_FROM_DATABASE=1110 Laser Printer + +usb:v413Cp5220* + ID_MODEL_FROM_DATABASE=Laser MFP 1600n + +usb:v413Cp5225* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp5226* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp5300* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v413Cp5400* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v413Cp5401* + ID_MODEL_FROM_DATABASE=Laser Printer + +usb:v413Cp5513* + ID_MODEL_FROM_DATABASE=WLA3310 Wireless Adapter [Intersil ISL3887] + +usb:v413Cp5601* + ID_MODEL_FROM_DATABASE=Laser Printer 3100cn + +usb:v413Cp5602* + ID_MODEL_FROM_DATABASE=Laser Printer 3000cn + +usb:v413Cp5631* + ID_MODEL_FROM_DATABASE=Laser Printer 5100cn + +usb:v413Cp5905* + ID_MODEL_FROM_DATABASE=Printing Support + +usb:v413Cp8000* + ID_MODEL_FROM_DATABASE=BC02 Bluetooth Adapter + +usb:v413Cp8010* + ID_MODEL_FROM_DATABASE=TrueMobile Bluetooth Module in + +usb:v413Cp8100* + ID_MODEL_FROM_DATABASE=TrueMobile 1180 802.11b Adapter [Intersil PRISM 3] + +usb:v413Cp8102* + ID_MODEL_FROM_DATABASE=TrueMobile 1300 802.11g Wireless Adapter [Intersil ISL3880] + +usb:v413Cp8103* + ID_MODEL_FROM_DATABASE=Wireless 350 Bluetooth + +usb:v413Cp8104* + ID_MODEL_FROM_DATABASE=Wireless 1450 Dual-band (802.11a/b/g) Adapter [Intersil ISL3887] + +usb:v413Cp8105* + ID_MODEL_FROM_DATABASE=U2 in HID - Driver + +usb:v413Cp8106* + ID_MODEL_FROM_DATABASE=Wireless 350 Bluetooth Internal Card in + +usb:v413Cp8110* + ID_MODEL_FROM_DATABASE=Wireless 3xx Bluetooth Internal Card + +usb:v413Cp8111* + ID_MODEL_FROM_DATABASE=Wireless 3xx Bluetooth Internal Card in + +usb:v413Cp8114* + ID_MODEL_FROM_DATABASE=Wireless 5700 Mobile Broadband (CDMA EV-DO) Minicard Modem + +usb:v413Cp8115* + ID_MODEL_FROM_DATABASE=Wireless 5500 Mobile Broadband (3G HSDPA) Minicard Modem + +usb:v413Cp8116* + ID_MODEL_FROM_DATABASE=Wireless 5505 Mobile Broadband (3G HSDPA) Minicard Modem + +usb:v413Cp8117* + ID_MODEL_FROM_DATABASE=Wireless 5700 Mobile Broadband (CDMA EV-DO) Expresscard Modem + +usb:v413Cp8118* + ID_MODEL_FROM_DATABASE=Wireless 5510 Mobile Broadband (3G HSDPA) Expresscard Status Port + +usb:v413Cp8120* + ID_MODEL_FROM_DATABASE=Bluetooth adapter + +usb:v413Cp8121* + ID_MODEL_FROM_DATABASE=Eastfold in HID + +usb:v413Cp8122* + ID_MODEL_FROM_DATABASE=Eastfold in DFU + +usb:v413Cp8123* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v413Cp8124* + ID_MODEL_FROM_DATABASE=eHome Infrared Receiver + +usb:v413Cp8126* + ID_MODEL_FROM_DATABASE=Wireless 355 Bluetooth + +usb:v413Cp8127* + ID_MODEL_FROM_DATABASE=Wireless 355 Module with Bluetooth 2.0 + EDR Technology. + +usb:v413Cp8128* + ID_MODEL_FROM_DATABASE=Wireless 5700-Sprint Mobile Broadband (CDMA EV-DO) Mini-Card Status Port + +usb:v413Cp8129* + ID_MODEL_FROM_DATABASE=Wireless 5700-Telus Mobile Broadband (CDMA EV-DO) Mini-Card Status Port + +usb:v413Cp8131* + ID_MODEL_FROM_DATABASE=Wireless 360 Bluetooth 2.0 + EDR module. + +usb:v413Cp8133* + ID_MODEL_FROM_DATABASE=Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port + +usb:v413Cp8134* + ID_MODEL_FROM_DATABASE=Wireless 5720 Sprint Mobile Broadband (EVDO Rev-A) Minicard Status Port + +usb:v413Cp8135* + ID_MODEL_FROM_DATABASE=Wireless 5720 TELUS Mobile Broadband (EVDO Rev-A) Minicard Diagnostics Port + +usb:v413Cp8136* + ID_MODEL_FROM_DATABASE=Wireless 5520 Cingular Mobile Broadband (3G HSDPA) Minicard Diagnostics Port + +usb:v413Cp8137* + ID_MODEL_FROM_DATABASE=Wireless 5520 Voda L Mobile Broadband (3G HSDPA) Minicard Status Port + +usb:v413Cp8138* + ID_MODEL_FROM_DATABASE=Wireless 5520 Voda I Mobile Broadband (3G HSDPA) Minicard EAP-SIM Port + +usb:v413Cp8140* + ID_MODEL_FROM_DATABASE=Wireless 360 Bluetooth + +usb:v413Cp8142* + ID_MODEL_FROM_DATABASE=Mobile 360 in DFU + +usb:v413Cp8147* + ID_MODEL_FROM_DATABASE=F3507g Mobile Broadband Module + +usb:v413Cp8156* + ID_MODEL_FROM_DATABASE=Wireless 370 Bluetooth Mini-card + +usb:v413Cp8157* + ID_MODEL_FROM_DATABASE=Integrated Keyboard + +usb:v413Cp8158* + ID_MODEL_FROM_DATABASE=Integrated Touchpad / Trackstick + +usb:v413Cp8160* + ID_MODEL_FROM_DATABASE=Wireless 365 Bluetooth + +usb:v413Cp8161* + ID_MODEL_FROM_DATABASE=Integrated Keyboard + +usb:v413Cp8162* + ID_MODEL_FROM_DATABASE=Integrated Touchpad [Synaptics] + +usb:v413Cp8171* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode) + +usb:v413Cp8172* + ID_MODEL_FROM_DATABASE=Gobi Wireless Modem + +usb:v413Cp8183* + ID_MODEL_FROM_DATABASE=F3607gw Mobile Broadband Module + +usb:v413Cp8184* + ID_MODEL_FROM_DATABASE=F3607gw v2 Mobile Broadband Module + +usb:v413Cp8185* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem (QDL mode) + +usb:v413Cp8186* + ID_MODEL_FROM_DATABASE=Gobi 2000 Wireless Modem + +usb:v413Cp8187* + ID_MODEL_FROM_DATABASE=DW375 Bluetooth Module + +usb:v413Cp8501* + ID_MODEL_FROM_DATABASE=Bluetooth Adapter + +usb:v413Cp9500* + ID_MODEL_FROM_DATABASE=USB CP210x UART Bridge Controller [DW700] + +usb:v413CpA001* + ID_MODEL_FROM_DATABASE=Hub + +usb:v413CpA005* + ID_MODEL_FROM_DATABASE=Internal 2.0 Hub + +usb:v413CpA700* + ID_MODEL_FROM_DATABASE=Hub (in 1905FP LCD Monitor) + +usb:v4146* + ID_VENDOR_FROM_DATABASE=USBest Technology + +usb:v4146p9281* + ID_MODEL_FROM_DATABASE=Iomega Micro Mini 128MB Flash Drive + +usb:v4146pBA01* + ID_MODEL_FROM_DATABASE=Intuix Flash Drive + +usb:v4242* + ID_VENDOR_FROM_DATABASE=USB Design by Example + +usb:v4242p4201* + ID_MODEL_FROM_DATABASE=Buttons and Lights HID device + +usb:v4242p4220* + ID_MODEL_FROM_DATABASE=Echo 1 Camera + +usb:v4317* + ID_VENDOR_FROM_DATABASE=Broadcom Corp. + +usb:v4317p0700* + ID_MODEL_FROM_DATABASE=U.S. Robotics USR5426 802.11g Adapter + +usb:v4317p0701* + ID_MODEL_FROM_DATABASE=U.S. Robotics USR5425 Wireless MAXg Adapter + +usb:v4317p0711* + ID_MODEL_FROM_DATABASE=Belkin F5D7051 v3000 802.11g + +usb:v4317p0720* + ID_MODEL_FROM_DATABASE=Dynex DX-BUSB + +usb:v4348* + ID_VENDOR_FROM_DATABASE=WinChipHead + +usb:v4348p5523* + ID_MODEL_FROM_DATABASE=USB->RS 232 adapter with Prolifec PL 2303 chipset + +usb:v4348p5537* + ID_MODEL_FROM_DATABASE=13.56Mhz RFID Card Reader and Writer + +usb:v4348p5584* + ID_MODEL_FROM_DATABASE=CH34x printer adapter cable + +usb:v4572* + ID_VENDOR_FROM_DATABASE=Shuttle, Inc. + +usb:v4572p4572* + ID_MODEL_FROM_DATABASE=Shuttle PN31 Remote + +usb:v4586* + ID_VENDOR_FROM_DATABASE=Panram + +usb:v4586p1026* + ID_MODEL_FROM_DATABASE=Crystal Bar Flash Drive + +usb:v4670* + ID_VENDOR_FROM_DATABASE=EMS Production + +usb:v4670p9394* + ID_MODEL_FROM_DATABASE=Game Cube USB Memory Adaptor 64M + +usb:v4752* + ID_VENDOR_FROM_DATABASE=Miditech + +usb:v4752p0011* + ID_MODEL_FROM_DATABASE=Midistart-2 + +usb:v4757* + ID_VENDOR_FROM_DATABASE=GW Instek + +usb:v4757p2009* + ID_MODEL_FROM_DATABASE=PEL-2000 Series Electronic Load (CDC) + +usb:v4757p2010* + ID_MODEL_FROM_DATABASE=PEL-2000 Series Electronic Load (CDC) + +usb:v4766* + ID_VENDOR_FROM_DATABASE=Aceeca + +usb:v4766p0001* + ID_MODEL_FROM_DATABASE=MEZ1000 RDA + +usb:v4855* + ID_VENDOR_FROM_DATABASE=Memorex + +usb:v4855p7288* + ID_MODEL_FROM_DATABASE=Ultra Traveldrive 160G 2.5" HDD + +usb:v4971* + ID_VENDOR_FROM_DATABASE=SimpleTech + +usb:v4971pCB01* + ID_MODEL_FROM_DATABASE=SP-U25/120G + +usb:v4971pCE17* + ID_MODEL_FROM_DATABASE=1TB SimpleDrive II USB External Hard Drive + +usb:v4D46* + ID_VENDOR_FROM_DATABASE=Musical Fidelity + +usb:v4D46p0001* + ID_MODEL_FROM_DATABASE=V-Link + +usb:v4D46p0002* + ID_MODEL_FROM_DATABASE=V-DAC II + +usb:v5032* + ID_VENDOR_FROM_DATABASE=Grandtec + +usb:v5032p0BB8* + ID_MODEL_FROM_DATABASE=Grandtec USB1.1 DVB-T (cold) + +usb:v5032p0BB9* + ID_MODEL_FROM_DATABASE=Grandtec USB1.1 DVB-T (warm) + +usb:v5032p0FA0* + ID_MODEL_FROM_DATABASE=Grandtec USB1.1 DVB-T (cold) + +usb:v5032p0FA1* + ID_MODEL_FROM_DATABASE=Grandtec USB1.1 DVB-T (warm) + +usb:v5041* + ID_VENDOR_FROM_DATABASE=Linksys (?) + +usb:v5041p2234* + ID_MODEL_FROM_DATABASE=WUSB54G v1 802.11g Adapter [Intersil ISL3886] + +usb:v5041p2235* + ID_MODEL_FROM_DATABASE=WUSB54GP v1 802.11g Adapter [Intersil ISL3886] + +usb:v50C2* + ID_VENDOR_FROM_DATABASE=Averatec (?) + +usb:v50C2p4013* + ID_MODEL_FROM_DATABASE=WLAN Adapter + +usb:v5173* + ID_VENDOR_FROM_DATABASE=Sweex + +usb:v5173p1809* + ID_MODEL_FROM_DATABASE=ZD1211 + +usb:v5219* + ID_VENDOR_FROM_DATABASE=I-Tetra + +usb:v5219p1001* + ID_MODEL_FROM_DATABASE=Cetus CDC Device + +usb:v5345* + ID_VENDOR_FROM_DATABASE=Owon + +usb:v5345p1234* + ID_MODEL_FROM_DATABASE=PDS6062T Oscilloscope + +usb:v544D* + ID_VENDOR_FROM_DATABASE=Transmeta Corp. + +usb:v5543* + ID_VENDOR_FROM_DATABASE=UC-Logic Technology Corp. + +usb:v5543p0002* + ID_MODEL_FROM_DATABASE=SuperPen WP3325U Tablet + +usb:v5543p0003* + ID_MODEL_FROM_DATABASE=Tablet WP4030U + +usb:v5543p0004* + ID_MODEL_FROM_DATABASE=Tablet WP5540U + +usb:v5543p0005* + ID_MODEL_FROM_DATABASE=Tablet WP8060U + +usb:v5543p0041* + ID_MODEL_FROM_DATABASE=Genius PenSketch 6x8 Tablet + +usb:v5543p0042* + ID_MODEL_FROM_DATABASE=Tablet PF1209 + +usb:v5543p0064* + ID_MODEL_FROM_DATABASE=Aiptek HyperPen 10000U + +usb:v5555* + ID_VENDOR_FROM_DATABASE=Epiphan Systems Inc. + +usb:v5555p1110* + ID_MODEL_FROM_DATABASE=VGA2USB + +usb:v5555p1120* + ID_MODEL_FROM_DATABASE=KVM2USB + +usb:v5555p2222* + ID_MODEL_FROM_DATABASE=DVI2USB + +usb:v5555p3333* + ID_MODEL_FROM_DATABASE=VGA2USB Pro + +usb:v5555p3337* + ID_MODEL_FROM_DATABASE=KVM2USB Pro + +usb:v5555p3340* + ID_MODEL_FROM_DATABASE=VGA2USB LR + +usb:v5555p3344* + ID_MODEL_FROM_DATABASE=KVM2USB LR + +usb:v5555p3411* + ID_MODEL_FROM_DATABASE=DVI2USB Solo + +usb:v5555p3422* + ID_MODEL_FROM_DATABASE=DVI2USB Duo + +usb:v55AA* + ID_VENDOR_FROM_DATABASE=OnSpec Electronic, Inc. + +usb:v55AAp0015* + ID_MODEL_FROM_DATABASE=Hard Drive + +usb:v55AAp0102* + ID_MODEL_FROM_DATABASE=SuperDisk + +usb:v55AAp0103* + ID_MODEL_FROM_DATABASE=IDE Hard Drive + +usb:v55AAp0201* + ID_MODEL_FROM_DATABASE=DDI to Reader-19 + +usb:v55AAp1234* + ID_MODEL_FROM_DATABASE=ATAPI Bridge + +usb:v55AApA103* + ID_MODEL_FROM_DATABASE=Sandisk SDDR-55 SmartMedia Card Reader + +usb:v55AApB000* + ID_MODEL_FROM_DATABASE=USB to CompactFlash Card Reader + +usb:v55AApB004* + ID_MODEL_FROM_DATABASE=OnSpec MMC/SD Reader/Writer + +usb:v55AApB00B* + ID_MODEL_FROM_DATABASE=USB to Memory Stick Card Reader + +usb:v55AApB00C* + ID_MODEL_FROM_DATABASE=USB to SmartMedia Card Reader + +usb:v55AApB012* + ID_MODEL_FROM_DATABASE=Mitsumi FA402M 8-in-2 Card Reader + +usb:v55AApB200* + ID_MODEL_FROM_DATABASE=Compact Flash Reader + +usb:v55AApB204* + ID_MODEL_FROM_DATABASE=MMC/ SD Reader + +usb:v55AApB207* + ID_MODEL_FROM_DATABASE=Memory Stick Reader + +usb:v5656* + ID_VENDOR_FROM_DATABASE=Uni-Trend Group Limited + +usb:v5656p0832* + ID_MODEL_FROM_DATABASE=UT2000/UT3000 Digital Storage Oscilloscope + +usb:v595A* + ID_VENDOR_FROM_DATABASE=IRTOUCHSYSTEMS Co. Ltd. + +usb:v595Ap0001* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v5986* + ID_VENDOR_FROM_DATABASE=Acer, Inc + +usb:v5986p0100* + ID_MODEL_FROM_DATABASE=Orbicam + +usb:v5986p0101* + ID_MODEL_FROM_DATABASE=USB2.0 Camera + +usb:v5986p0102* + ID_MODEL_FROM_DATABASE=Crystal Eye Webcam + +usb:v5986p01A6* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam + +usb:v5986p01A7* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam + +usb:v5986p01A9* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam + +usb:v5986p0200* + ID_MODEL_FROM_DATABASE=OrbiCam + +usb:v5986p0203* + ID_MODEL_FROM_DATABASE=BisonCam NB Pro 1300 + +usb:v5986p0241* + ID_MODEL_FROM_DATABASE=BisonCam, NB Pro + +usb:v5986p02D0* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam [R5U877] + +usb:v5986p03D0* + ID_MODEL_FROM_DATABASE=Lenovo Integrated Webcam [R5U877] + +usb:v5A57* + ID_VENDOR_FROM_DATABASE=Zinwell + +usb:v5A57p0260* + ID_MODEL_FROM_DATABASE=RT2570 + +usb:v5A57p0280* + ID_MODEL_FROM_DATABASE=802.11a/b/g/n USB Wireless LAN Card + +usb:v5A57p0282* + ID_MODEL_FROM_DATABASE=802.11b/g/n USB Wireless LAN Card + +usb:v5A57p0283* + ID_MODEL_FROM_DATABASE=802.11b/g/n USB Wireless LAN Card + +usb:v5A57p0284* + ID_MODEL_FROM_DATABASE=802.11a/b/g/n USB Wireless LAN Card + +usb:v5A57p0290* + ID_MODEL_FROM_DATABASE=ZW-N290 802.11n [Realtek RTL8192SU] + +usb:v5A57p5257* + ID_MODEL_FROM_DATABASE=Metronic 495257 wifi 802.11ng + +usb:v6000* + ID_VENDOR_FROM_DATABASE=Beholder International Ltd. + +usb:v6000pDEC0* + ID_MODEL_FROM_DATABASE=TV Wander + +usb:v6000pDEC1* + ID_MODEL_FROM_DATABASE=TV Voyage + +usb:v601A* + ID_VENDOR_FROM_DATABASE=Ingenic Semiconductor Ltd. + +usb:v601Ap4740* + ID_MODEL_FROM_DATABASE=XBurst Jz4740 boot mode + +usb:v6189* + ID_VENDOR_FROM_DATABASE=Sitecom + +usb:v6189p182D* + ID_MODEL_FROM_DATABASE=USB 2.0 Ethernet + +usb:v6189p2068* + ID_MODEL_FROM_DATABASE=USB to serial cable (v2) + +usb:v6253* + ID_VENDOR_FROM_DATABASE=TwinHan Technology Co., Ltd + +usb:v6253p0100* + ID_MODEL_FROM_DATABASE=Ir reciver f. remote control + +usb:v636C* + ID_VENDOR_FROM_DATABASE=CoreLogic, Inc. + +usb:v6472* + ID_VENDOR_FROM_DATABASE=Unknown (Sony?) + +usb:v6472p01C8* + ID_MODEL_FROM_DATABASE=PlayStation Portable [Mass Storage] + +usb:v6547* + ID_VENDOR_FROM_DATABASE=Arkmicro Technologies Inc. + +usb:v6547p0232* + ID_MODEL_FROM_DATABASE=ARK3116 Serial + +usb:v6615* + ID_VENDOR_FROM_DATABASE=IRTOUCHSYSTEMS Co. Ltd. + +usb:v6615p0001* + ID_MODEL_FROM_DATABASE=Touchscreen + +usb:v6666* + ID_VENDOR_FROM_DATABASE=Prototype product Vendor ID + +usb:v6666p0667* + ID_MODEL_FROM_DATABASE=WiseGroup Smart Joy PSX, PS-PC Smart JoyPad + +usb:v6666p2667* + ID_MODEL_FROM_DATABASE=JCOP BlueZ Smartcard reader + +usb:v6666p8802* + ID_MODEL_FROM_DATABASE=SmartJoy Dual Plus PS2 converter + +usb:v6666p8804* + ID_MODEL_FROM_DATABASE=WiseGroup SuperJoy Box 5 + +usb:v6677* + ID_VENDOR_FROM_DATABASE=WiseGroup, Ltd. + +usb:v6677p8802* + ID_MODEL_FROM_DATABASE=SmartJoy Dual Plus PS2 converter + +usb:v6677p8811* + ID_MODEL_FROM_DATABASE=Deluxe Dance Mat + +usb:v6891* + ID_VENDOR_FROM_DATABASE=3Com + +usb:v6891pA727* + ID_MODEL_FROM_DATABASE=3CRUSB10075 802.11bg [ZyDAS ZD1211] + +usb:v695C* + ID_VENDOR_FROM_DATABASE=Opera1 + +usb:v695Cp3829* + ID_MODEL_FROM_DATABASE=Opera1 DVB-S (warm state) + +usb:v6993* + ID_VENDOR_FROM_DATABASE=Yealink Network Technology Co., Ltd. + +usb:v6993pB001* + ID_MODEL_FROM_DATABASE=VoIP Phone + +usb:v6A75* + ID_VENDOR_FROM_DATABASE=Shanghai Jujo Electronics Co., Ltd + +usb:v7104* + ID_VENDOR_FROM_DATABASE=CME (Central Music Co.) + +usb:v7104p2202* + ID_MODEL_FROM_DATABASE=UF5/UF6/UF7/UF8 MIDI Master Keyboard + +usb:v726C* + ID_VENDOR_FROM_DATABASE=StackFoundry LLC + +usb:v726Cp2149* + ID_MODEL_FROM_DATABASE=EntropyKing Random Number Generator + +usb:v734C* + ID_VENDOR_FROM_DATABASE=TBS Technologies China + +usb:v734Cp5920* + ID_MODEL_FROM_DATABASE=Q-Box II DVB-S2 HD + +usb:v734Cp5928* + ID_MODEL_FROM_DATABASE=Q-Box II DVB-S2 HD + +usb:v7392* + ID_VENDOR_FROM_DATABASE=Edimax Technology Co., Ltd + +usb:v7392p7711* + ID_MODEL_FROM_DATABASE=EW-7711UTn nLite Wireless Adapter [Ralink RT2870] + +usb:v7392p7717* + ID_MODEL_FROM_DATABASE=EW-7717UN 802.11n Wireless Adapter [Ralink RT2870] + +usb:v7392p7718* + ID_MODEL_FROM_DATABASE=EW-7718UN 802.11n Wireless Adapter [Ralink RT2870] + +usb:v7392p7722* + ID_MODEL_FROM_DATABASE=EW-7722UTn 802.11n Wireless Adapter [Ralink RT307x] + +usb:v7392p7811* + ID_MODEL_FROM_DATABASE=EW-7811Un 802.11n Wireless Adapter [Realtek RTL8188CUS] + +usb:v8086* + ID_VENDOR_FROM_DATABASE=Intel Corp. + +usb:v8086p0001* + ID_MODEL_FROM_DATABASE=AnyPoint (TM) Home Network 1.6 Mbps Wireless Adapter + +usb:v8086p0044* + ID_MODEL_FROM_DATABASE=CPU DRAM Controller + +usb:v8086p0046* + ID_MODEL_FROM_DATABASE=HD Graphics + +usb:v8086p0100* + ID_MODEL_FROM_DATABASE=Personal Audio Player 3000 + +usb:v8086p0101* + ID_MODEL_FROM_DATABASE=Personal Audio Player 3000 + +usb:v8086p0110* + ID_MODEL_FROM_DATABASE=Easy PC Camera + +usb:v8086p0120* + ID_MODEL_FROM_DATABASE=PC Camera CS120 + +usb:v8086p0180* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p0181* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p0182* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p0186* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p0188* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p0200* + ID_MODEL_FROM_DATABASE=AnyPoint(TM) Wireless II Network 11Mbps Adapter [Atmel AT76C503A] + +usb:v8086p0431* + ID_MODEL_FROM_DATABASE=Intel Pro Video PC Camera + +usb:v8086p0510* + ID_MODEL_FROM_DATABASE=Digital Movie Creator + +usb:v8086p0630* + ID_MODEL_FROM_DATABASE=Pocket PC Camera + +usb:v8086p0780* + ID_MODEL_FROM_DATABASE=CS780 Microphone Input + +usb:v8086p07D3* + ID_MODEL_FROM_DATABASE=BLOB boot loader firmware + +usb:v8086p0DAD* + ID_MODEL_FROM_DATABASE=Cherry MiniatureCard Keyboard + +usb:v8086p1010* + ID_MODEL_FROM_DATABASE=AnyPoint(TM) Home Network 10 Mbps Phoneline Adapter + +usb:v8086p110A* + ID_MODEL_FROM_DATABASE=Bluetooth Controller from (Ericsson P4A) + +usb:v8086p110B* + ID_MODEL_FROM_DATABASE=Bluetooth Controller from (Intel/CSR) + +usb:v8086p1110* + ID_MODEL_FROM_DATABASE=PRO/Wireless LAN Module + +usb:v8086p1111* + ID_MODEL_FROM_DATABASE=PRO/Wireless 2011B 802.11b Adapter [Intersil PRISM 2.5] + +usb:v8086p1134* + ID_MODEL_FROM_DATABASE=Hollister Mobile Monitor + +usb:v8086p1139* + ID_MODEL_FROM_DATABASE=In-Target Probe (ITP) + +usb:v8086p1234* + ID_MODEL_FROM_DATABASE=Prototype Reader/Writer + +usb:v8086p1403* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p1405* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p1406* + ID_MODEL_FROM_DATABASE=WiMAX Connection 2400m + +usb:v8086p2448* + ID_MODEL_FROM_DATABASE=82801 PCI Bridge + +usb:v8086p3100* + ID_MODEL_FROM_DATABASE=PRO/DSL 3220 Modem - WAN + +usb:v8086p3101* + ID_MODEL_FROM_DATABASE=PRO/DSL 3220 Modem + +usb:v8086p3240* + ID_MODEL_FROM_DATABASE=AnyPoint® 3240 Modem - WAN + +usb:v8086p3241* + ID_MODEL_FROM_DATABASE=AnyPoint® 3240 Modem + +usb:v8086p8602* + ID_MODEL_FROM_DATABASE=Miniature Card Slot + +usb:v8086p9303* + ID_MODEL_FROM_DATABASE=Intel 8x930Hx Hub + +usb:v8086p9500* + ID_MODEL_FROM_DATABASE=CE 9500 DVB-T + +usb:v8086p9890* + ID_MODEL_FROM_DATABASE=82930 Test Board + +usb:v8086pBEEF* + ID_MODEL_FROM_DATABASE=SCM Miniature Card Reader/Writer + +usb:v8086pC013* + ID_MODEL_FROM_DATABASE=Wireless HID Station + +usb:v8086pF001* + ID_MODEL_FROM_DATABASE=XScale PXA27x Bulverde flash + +usb:v8086pF1A5* + ID_MODEL_FROM_DATABASE=Z-U130 [Value Solid State Drive] + +usb:v8087* + ID_VENDOR_FROM_DATABASE=Intel Corp. + +usb:v8087p0020* + ID_MODEL_FROM_DATABASE=Integrated Rate Matching Hub + +usb:v8087p0024* + ID_MODEL_FROM_DATABASE=Integrated Rate Matching Hub + +usb:v80EE* + ID_VENDOR_FROM_DATABASE=VirtualBox + +usb:v80EEp0021* + ID_MODEL_FROM_DATABASE=USB Tablet + +usb:v8282* + ID_VENDOR_FROM_DATABASE=Keio + +usb:v8282p3201* + ID_MODEL_FROM_DATABASE=Retro Adapter + +usb:v8282p3301* + ID_MODEL_FROM_DATABASE=Retro Adapter Mouse + +usb:v8341* + ID_VENDOR_FROM_DATABASE=EGO Systems, Inc. + +usb:v8341p2000* + ID_MODEL_FROM_DATABASE=Flashdisk + +usb:v9016* + ID_VENDOR_FROM_DATABASE=Sitecom + +usb:v9016p182D* + ID_MODEL_FROM_DATABASE=WL-022 802.11b Adapter + +usb:v9022* + ID_VENDOR_FROM_DATABASE=TeVii Technology Ltd. + +usb:v9022pD630* + ID_MODEL_FROM_DATABASE=DVB-S S630 + +usb:v9022pD650* + ID_MODEL_FROM_DATABASE=DVB-S2 S650 + +usb:v9022pD660* + ID_MODEL_FROM_DATABASE=DVB-S2 S660 + +usb:v9148* + ID_VENDOR_FROM_DATABASE=GeoLab, Ltd + +usb:v9148p0004* + ID_MODEL_FROM_DATABASE=R3 Compatible Device + +usb:v9710* + ID_VENDOR_FROM_DATABASE=MosChip Semiconductor + +usb:v9710p7703* + ID_MODEL_FROM_DATABASE=MCS7703 Serial Port Adapter + +usb:v9710p7705* + ID_MODEL_FROM_DATABASE=MCS7705 Parallel port adapter + +usb:v9710p7715* + ID_MODEL_FROM_DATABASE=MCS7715 Parallel and serial port adapter + +usb:v9710p7717* + ID_MODEL_FROM_DATABASE=MCS7717 3-port hub with serial and parallel adapter + +usb:v9710p7720* + ID_MODEL_FROM_DATABASE=MCS7720 Dual serial port adapter + +usb:v9710p7730* + ID_MODEL_FROM_DATABASE=MCS7730 10/100 Mbps Ethernet adapter + +usb:v9710p7780* + ID_MODEL_FROM_DATABASE=MCS7780 4Mbps Fast IrDA Adapter + +usb:v9710p7830* + ID_MODEL_FROM_DATABASE=MCS7830 10/100 Mbps Ethernet adapter + +usb:v9710p7832* + ID_MODEL_FROM_DATABASE=MCS7832 10/100 Mbps Ethernet adapter + +usb:v9710p7840* + ID_MODEL_FROM_DATABASE=MCS7820/MCS7840 2/4 port serial adapter + +usb:v99FA* + ID_VENDOR_FROM_DATABASE=Grandtec + +usb:v99FAp8988* + ID_MODEL_FROM_DATABASE=V.cap Camera Device + +usb:v9AC4* + ID_VENDOR_FROM_DATABASE=J. Westhues + +usb:v9AC4p4B8F* + ID_MODEL_FROM_DATABASE=ProxMark-3 RFID Instrument + +usb:vA128* + ID_VENDOR_FROM_DATABASE=AnMo Electronics Corp. / Dino-Lite (?) + +usb:vA128p0610* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + HV7131R) + +usb:vA128p0611* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + HV7131R) + +usb:vA128p0612* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C120 + HV7131R) + +usb:vA128p0613* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + HV7131R) + +usb:vA128p0614* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + MI1310/MT9M111) + +usb:vA128p0615* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + MI1310/MT9M111) + +usb:vA128p0616* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C120 + HV7131R) + +usb:vA128p0617* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + MI1310/MT9M111) + +usb:vA128p0618* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope (SN9C201 + HV7131R) + +usb:vA168* + ID_VENDOR_FROM_DATABASE=AnMo Electronics Corporation + +usb:vA168p0610* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope + +usb:vA168p0611* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope + +usb:vA168p0613* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope + +usb:vA168p0614* + ID_MODEL_FROM_DATABASE=Dino-Lite Pro Digital Microscope + +usb:vA168p0615* + ID_MODEL_FROM_DATABASE=Dino-Lite Pro Digital Microscope + +usb:vA168p0617* + ID_MODEL_FROM_DATABASE=Dino-Lite Pro Digital Microscope + +usb:vA168p0618* + ID_MODEL_FROM_DATABASE=Dino-Lite Digital Microscope + +usb:vA600* + ID_VENDOR_FROM_DATABASE=Asix + +usb:vA600pE110* + ID_MODEL_FROM_DATABASE=OK1ZIA Davac 4.x + +usb:vA727* + ID_VENDOR_FROM_DATABASE=3Com + +usb:vA727p6893* + ID_MODEL_FROM_DATABASE=3CRUSB20075 OfficeConnect Wireless 108Mbps 11g Adapter [Atheros AR5523] + +usb:vA727p6895* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:vA727p6897* + ID_MODEL_FROM_DATABASE=AR5523 + +usb:vABCD* + ID_VENDOR_FROM_DATABASE=Unknown + +usb:vABCDpCDEE* + ID_MODEL_FROM_DATABASE=Petcam + +usb:vC251* + ID_VENDOR_FROM_DATABASE=Keil Software, Inc. + +usb:vC251p2710* + ID_MODEL_FROM_DATABASE=ULink + +usb:vCACE* + ID_VENDOR_FROM_DATABASE=CACE Technologies Inc. + +usb:vCACEp0002* + ID_MODEL_FROM_DATABASE=AirPCAP Classic 802.11 packet capture adapter + +usb:vCACEp0300* + ID_MODEL_FROM_DATABASE=AirPcap NX [Atheros AR9001U-(2)NG] + +usb:vD209* + ID_VENDOR_FROM_DATABASE=Ultimarc + +usb:vD209p0301* + ID_MODEL_FROM_DATABASE=I-PAC Arcade Control Interface + +usb:vD209p0501* + ID_MODEL_FROM_DATABASE=Ultra-Stik Ultimarc Ultra-Stik Player 1 + +usb:vE4E4* + ID_VENDOR_FROM_DATABASE=Xorcom Ltd. + +usb:vE4E4p1130* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1131* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1132* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1140* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1141* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1142* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1150* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1151* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1152* + ID_MODEL_FROM_DATABASE=Astribank series + +usb:vE4E4p1160* + ID_MODEL_FROM_DATABASE=Astribank 2 series + +usb:vE4E4p1161* + ID_MODEL_FROM_DATABASE=Astribank 2 series + +usb:vE4E4p1162* + ID_MODEL_FROM_DATABASE=Astribank 2 series + +usb:vEB03* + ID_VENDOR_FROM_DATABASE=MakingThings + +usb:vEB03p0920* + ID_MODEL_FROM_DATABASE=Make Controller Kit + +usb:vEB1A* + ID_VENDOR_FROM_DATABASE=eMPIA Technology, Inc. + +usb:vEB1Ap17DE* + ID_MODEL_FROM_DATABASE=KWorld V-Stream XPERT DTV - DVB-T USB cold + +usb:vEB1Ap17DF* + ID_MODEL_FROM_DATABASE=KWorld V-Stream XPERT DTV - DVB-T USB warm + +usb:vEB1Ap2571* + ID_MODEL_FROM_DATABASE=M035 Compact Web Cam + +usb:vEB1Ap2710* + ID_MODEL_FROM_DATABASE=SilverCrest Webcam + +usb:vEB1Ap2750* + ID_MODEL_FROM_DATABASE=ECS Elitegroup G220 integrated Webcam + +usb:vEB1Ap2761* + ID_MODEL_FROM_DATABASE=EeePC 701 integrated Webcam + +usb:vEB1Ap2776* + ID_MODEL_FROM_DATABASE=Combined audio and video input device + +usb:vEB1Ap2800* + ID_MODEL_FROM_DATABASE=Terratec Cinergy 200 + +usb:vEB1Ap2801* + ID_MODEL_FROM_DATABASE=GrabBeeX+ Video Encoder + +usb:vEB1Ap2863* + ID_MODEL_FROM_DATABASE=Video Grabber + +usb:vEB1Ap2870* + ID_MODEL_FROM_DATABASE=Pinnacle PCTV Stick + +usb:vEB1Ap2881* + ID_MODEL_FROM_DATABASE=EM2881 Video Controller + +usb:vEB1Ap50A3* + ID_MODEL_FROM_DATABASE=Gadmei UTV380 TV Box + +usb:vEB1Ap50A6* + ID_MODEL_FROM_DATABASE=Gadmei UTV330 TV Box + +usb:vEB1ApE355* + ID_MODEL_FROM_DATABASE=KWorld DVB-T 355U Digital TV Dongle + +usb:vEB2A* + ID_VENDOR_FROM_DATABASE=KWorld + +usb:vF003* + ID_VENDOR_FROM_DATABASE=Hewlett Packard + +usb:vF003p6002* + ID_MODEL_FROM_DATABASE=PhotoSmart C500 + +usb:vF4EC* + ID_VENDOR_FROM_DATABASE=Atten Electronics / Siglent Technologies + +usb:vF4ECpEE38* + ID_MODEL_FROM_DATABASE=Digital Storage Oscilloscope diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb new file mode 100644 index 0000000..edfa842 --- /dev/null +++ b/hwdb/60-keyboard.hwdb @@ -0,0 +1,1104 @@ +# This file is part of systemd. +# +# Keyboard mapping of scan codes to key codes, and +# scan codes to add to the AT keyboard's 'force-release' list. +# +# The lookup keys are composed in: +# 60-keyboard.rules +# +# Note: The format of the "keyboard:" prefix match key is a +# contract between the rules file and the hardware data, it might +# change in later revisions to support more or better matches, it +# is not necessarily expected to be a stable ABI. +# +# Supported hardware matches are: +# - USB keyboards identified by the usb kernel modalias: +# keyboard:usb:vXXXXpYYYY* +# XXXX is the 4-digit hex uppercase vendor, and YYYY +# the 4-digit hex uppercase product. +# +# - AT keyboard DMI data matches: +# keyboard:dmi:bvn*:bvr*:bd*:svn:pn:pvr* +# and are the firmware-provided strings +# exported by the kernel DMI modalias. +# +# - Platform driver device name and DMI data match: +# keyboard:name::dmi:bvn*:bvr*:bd*:svn:pn* +# is the name device specified by the +# driver, is the firmware-provided string exported +# by the kernel DMI modalias. +# +# Scan codes are specified as: +# KEYBOARD_KEY_= +# The scan code should be expressed in hex lowercase and in +# full bytes, a multiple of 2 digits. The key codes are retrieved +# and normalized from the kernel input API header. +# +# A '!' as the first charcter of the key identifier string +# will add the scan code to the AT keyboard's list of scan codes +# where the driver will synthesize a release event and not expect +# it to be generated by the hardware. +# +# To debug key presses and access scan code mapping data of +# an input device use the commonly available tool: evtest(1). + +########################################## +# Acer +########################################## + +# common keys +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn* +keyboard:dmi:bvn*:bvr*:bd*:svnGateway*:pnA0A1*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr* + KEYBOARD_KEY_a5=help # Fn+F1 + KEYBOARD_KEY_a6=setup # Fn+F2 Acer eSettings + KEYBOARD_KEY_a7=battery # Fn+F3 Power Management + KEYBOARD_KEY_a9=switchvideomode # Fn+F5 + KEYBOARD_KEY_b2=www + KEYBOARD_KEY_b3=euro + KEYBOARD_KEY_b4=dollar + KEYBOARD_KEY_ce=brightnessup # Fn+Right + KEYBOARD_KEY_d4=bluetooth # (toggle) off-to-on + KEYBOARD_KEY_d5=wlan # (toggle) on-to-off + KEYBOARD_KEY_d6=wlan # (toggle) off-to-on + KEYBOARD_KEY_d7=bluetooth # (toggle) on-to-off + KEYBOARD_KEY_d8=bluetooth # (toggle) off-to-on + KEYBOARD_KEY_d9=brightnessup # Fn+Right + KEYBOARD_KEY_ee=brightnessup # Fn+Right + KEYBOARD_KEY_ef=brightnessdown # Fn+Left + KEYBOARD_KEY_f1=f22 # Fn+F7 Touchpad toggle (off-to-on) + KEYBOARD_KEY_f2=f23 # Fn+F7 Touchpad toggle (on-to-off) + KEYBOARD_KEY_f3=prog2 # "P2" programmable button + KEYBOARD_KEY_f4=prog1 # "P1" programmable button + KEYBOARD_KEY_f5=presentation + KEYBOARD_KEY_f8=fn + KEYBOARD_KEY_f9=prog1 # Launch NTI shadow + +# Acer platform kernel driver +keyboard:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:pvr* + KEYBOARD_KEY_82=f21 # Touchpad toggle + +# Aspire models +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:pvr* + KEYBOARD_KEY_84=bluetooth # sent when bluetooth module missing, and key pressed + KEYBOARD_KEY_d9=bluetooth # Bluetooth off + KEYBOARD_KEY_92=media # Acer arcade + +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5720*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnZG8*:pvr* + KEYBOARD_KEY_f4=prog3 # e-key + +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5920G:* + KEYBOARD_KEY_8a=media + KEYBOARD_KEY_a6=setup + +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*6920:* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*8930:* + KEYBOARD_KEY_ca=prog3 # key 'HOLD' on CineDash Media Console + KEYBOARD_KEY_83=rewind + KEYBOARD_KEY_89=fastforward + KEYBOARD_KEY_9e=back + +# Travelmate C300 +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr* + KEYBOARD_KEY_67=f24 # FIXME: rotate screen + KEYBOARD_KEY_68=up + KEYBOARD_KEY_69=down + KEYBOARD_KEY_6b=fn + KEYBOARD_KEY_6c=screenlock # FIXME: lock tablet device/buttons + +# on some models this isn't brightnessup +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5220*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5610*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5620*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5720*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*4720*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*6593:* +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*1640:* + KEYBOARD_KEY_ee=screenlock + +keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr* + KEYBOARD_KEY_a9=!switchvideomode # Fn+F5 + +########################################################### +# Alienware +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnAlienware*:pn* + KEYBOARD_KEY_8a=ejectcd + +########################################################### +# Asus +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnASUS:pn* + KEYBOARD_KEY_ed=volumeup + KEYBOARD_KEY_ee=volumedown + KEYBOARD_KEY_ef=mute + +keyboard:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr* + KEYBOARD_KEY_6b=f21 # Touchpad Toggle + +########################################################### +# BenQ +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:pvr* + KEYBOARD_KEY_6e=wlan + +########################################################### +# Compal +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnCOMPAL:pnHEL80I:* + KEYBOARD_KEY_84=wlan + +########################################################### +# COMPAQ +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*E500*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:pvr* + KEYBOARD_KEY_a3=www # I key + KEYBOARD_KEY_9a=search + KEYBOARD_KEY_9e=email + KEYBOARD_KEY_9f=homepage + +########################################################### +# Dell +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pn* + KEYBOARD_KEY_81=playpause # Play/Pause + KEYBOARD_KEY_82=stopcd # Stop + KEYBOARD_KEY_83=previoussong # Previous song + KEYBOARD_KEY_84=nextsong # Next song + KEYBOARD_KEY_85=brightnessdown # Fn+Down Brightness Down + KEYBOARD_KEY_86=brightnessup # Fn+Up Brightness Up + KEYBOARD_KEY_87=battery # Fn+F3 battery icon + KEYBOARD_KEY_88=unknown # Fn+F2 Turn On/Off Wireless - handled in hardware + KEYBOARD_KEY_89=ejectclosecd # Fn+F10 Eject CD + KEYBOARD_KEY_8a=suspend # Fn+F1 hibernate + KEYBOARD_KEY_8b=switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle") + KEYBOARD_KEY_8c=unknown # Fn+Right Auto Brightness + KEYBOARD_KEY_8F=switchvideomode # Fn+F7 aspect ratio + KEYBOARD_KEY_90=previoussong # Front panel previous song + KEYBOARD_KEY_91=prog1 # Wi-Fi Catcher (Dell-specific) + KEYBOARD_KEY_92=media # MediaDirect button (house icon) + KEYBOARD_KEY_93=unknown # FIXME Fn+Left Auto Brightness + KEYBOARD_KEY_95=camera # Shutter button - Takes a picture if optional camera available + KEYBOARD_KEY_97=email # Tablet email button + KEYBOARD_KEY_98=f21 # FIXME: Tablet screen rotation + KEYBOARD_KEY_99=nextsong # Front panel next song + KEYBOARD_KEY_9a=setup # Tablet tools button + KEYBOARD_KEY_9b=switchvideomode # Display toggle button + KEYBOARD_KEY_9e=f21 # Touchpad toggle + KEYBOARD_KEY_a2=playpause # Front panel play/pause + KEYBOARD_KEY_a4=stopcd # Front panel stop + KEYBOARD_KEY_ed=media # MediaDirect button + KEYBOARD_KEY_d8=screenlock # FIXME: Tablet lock button + KEYBOARD_KEY_d9=f21 # Touchpad toggle + +# +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*101[012]:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:pvr* + KEYBOARD_KEY_84=wlan + +# Latitude XT2 +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*XT2:pvr* + KEYBOARD_KEY_9b=up # tablet rocker up + KEYBOARD_KEY_9e=enter # tablet rocker press + KEYBOARD_KEY_9f=back # tablet back + KEYBOARD_KEY_a3=down # tablet rocker down + +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:pvr* + KEYBOARD_KEY_a0=! # mute + KEYBOARD_KEY_ae=! # volume down + KEYBOARD_KEY_b0=! # volume up + +# Dell Touchpad +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:pvr* + KEYBOARD_KEY_9e=!f21 + +# Dell XPS +keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr* + KEYBOARD_KEY_8c=!unknown + +########################################################### +# Everex +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr* + KEYBOARD_KEY_5c=media + KEYBOARD_KEY_65=f21 # Fn+F5 Touchpad toggle + KEYBOARD_KEY_67=prog3 # Fan speed control button + KEYBOARD_KEY_6f=brightnessup + KEYBOARD_KEY_7f=brightnessdown + KEYBOARD_KEY_b2=www + KEYBOARD_KEY_ec=mail + +########################################## +# Fujitsu +########################################## + +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*M*:pvr* + KEYBOARD_KEY_97=prog2 + KEYBOARD_KEY_9f=prog1 + +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAmilo*Li*1718:* + KEYBOARD_KEY_d6=wlan + +# Amilo Li 2732 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*Li*2732:* + KEYBOARD_KEY_d9=brightnessdown # Fn+F8 brightness down + KEYBOARD_KEY_ef=brightnessup # Fn+F9 brightness up + KEYBOARD_KEY_a9=switchvideomode # Fn+F10 Cycle between available video outputs + +# Amilo Pa 2548 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pa*2548*:pvr* + KEYBOARD_KEY_e0=volumedown + KEYBOARD_KEY_e1=volumeup + KEYBOARD_KEY_e5=prog1 + +# Amilo Pro Edition V3505 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:pvr* + KEYBOARD_KEY_a5=help # Fn+F1 + KEYBOARD_KEY_a9=switchvideomode # Fn+F3 + KEYBOARD_KEY_d9=brightnessdown # Fn+F8 + KEYBOARD_KEY_e0=brightnessup # Fn+F9 + +# Amilo Pro v3205 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:pvr* + KEYBOARD_KEY_f4=f21 # FIXME: silent-mode decrease CPU/GPU clock + KEYBOARD_KEY_f7=switchvideomode # Fn+F3 + +# Amilo Si 1520 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr* + KEYBOARD_KEY_e1=wlan + KEYBOARD_KEY_f3=wlan + KEYBOARD_KEY_ee=brightnessdown + KEYBOARD_KEY_e0=brightnessup + KEYBOARD_KEY_e2=bluetooth + KEYBOARD_KEY_f7=video + +# Esprimo Mobile V5 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V5*:pvr* + KEYBOARD_KEY_a9=switchvideomode + KEYBOARD_KEY_d9=brightnessdown + KEYBOARD_KEY_df=sleep + KEYBOARD_KEY_ef=brightnessup + +# Esprimo Mobile V6 +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:pvr* + KEYBOARD_KEY_ce=brightnessup + KEYBOARD_KEY_ef=brightnessdown + +########################################################### +# GIGABYTE +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pnU2442:* + KEYBOARD_KEY_a0=! # mute + +########################################################### +# Genius +########################################################### + +# Slimstar 320 +keyboard:usb:v0458p0708d*dc*dsc*dp*ic*isc*ip*in01* + KEYBOARD_KEY_0900f0=scrollup + KEYBOARD_KEY_0900f1=scrolldown + KEYBOARD_KEY_0900f3=back + KEYBOARD_KEY_0900f2=forward + KEYBOARD_KEY_0900f5=wordprocessor + KEYBOARD_KEY_0900f6=spreadsheet + KEYBOARD_KEY_0900f4=presentation + KEYBOARD_KEY_0c0223=www + KEYBOARD_KEY_0900f7=chat + KEYBOARD_KEY_0900fb=prog1 + KEYBOARD_KEY_0900f8=close + KEYBOARD_KEY_0900f9=graphicseditor + KEYBOARD_KEY_0900fd=scale + KEYBOARD_KEY_0900fc=screenlock + +########################################################### +# Hewlett Packard +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:pvr* + KEYBOARD_KEY_81=fn_esc + KEYBOARD_KEY_89=battery # Fn+F8 + KEYBOARD_KEY_8a=screenlock # Fn+F6 + KEYBOARD_KEY_8b=camera + KEYBOARD_KEY_8c=media # music + KEYBOARD_KEY_8e=dvd + KEYBOARD_KEY_b1=help + KEYBOARD_KEY_b3=unknown # FIXME: Auto brightness + KEYBOARD_KEY_d7=wlan + KEYBOARD_KEY_92=brightnessdown # Fn+F7 (Fn+F9 on 6730b) + KEYBOARD_KEY_97=brightnessup # Fn+F8 (Fn+F10 on 6730b) + KEYBOARD_KEY_ee=switchvideomode # Fn+F4 + +# Tablet +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:pvr* + KEYBOARD_KEY_82=prog2 # Funny Key + KEYBOARD_KEY_83=prog1 # Q + KEYBOARD_KEY_84=tab + KEYBOARD_KEY_85=esc + KEYBOARD_KEY_86=pageup + KEYBOARD_KEY_87=pagedown + +# Pavilion +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:pvr* + KEYBOARD_KEY_88=media # FIXME: quick play + KEYBOARD_KEY_b7=print + KEYBOARD_KEY_d8=!f23 # touchpad off + KEYBOARD_KEY_d9=!f22 # touchpad on + +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:pvr* + KEYBOARD_KEY_b7=print + KEYBOARD_KEY_c2=media # FIXME: quick play + KEYBOARD_KEY_c6=break + KEYBOARD_KEY_94=0 + +# Elitebook +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:pvr* + KEYBOARD_KEY_88=presentation + KEYBOARD_KEY_d9=help # I key (high keycode: "info") + +# Presario +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:pvr* + KEYBOARD_KEY_d8=f21 + KEYBOARD_KEY_d9=f21 + +# 2510p 2530p +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:pvr* + KEYBOARD_KEY_d8=!f23 # touchpad off + KEYBOARD_KEY_d9=!f22 # touchpad on + +# 2570p +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:pvr* + KEYBOARD_KEY_f8=wlan # Wireless HW switch button + +# TX2 +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:pvr* + KEYBOARD_KEY_c2=media + KEYBOARD_KEY_d8=!f23 # Toggle touchpad button on tx2 (OFF) + KEYBOARD_KEY_d9=!f22 # Toggle touchpad button on tx2 (ON) + +# Presario 2100 +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:pvr* + KEYBOARD_KEY_f0=help + KEYBOARD_KEY_f1=screenlock + KEYBOARD_KEY_f3=search + +# Elitebook 8440p +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr* + KEYBOARD_KEY_88=www + KEYBOARD_KEY_a0=mute + KEYBOARD_KEY_ae=volumedown + KEYBOARD_KEY_b0=volumeup + KEYBOARD_KEY_ec=mail + +# Elitebook 8460p +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:pvr* + KEYBOARD_KEY_f8=wlan # Wireless HW switch button + KEYBOARD_KEY_b3=prog1 # Fn+F11 - Ambient Light Sensor button + KEYBOARD_KEY_b1=prog2 # Fn+ESC - System information button + +# HDX9494nr +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:pvr* + KEYBOARD_KEY_b2=www # Fn+F3 + KEYBOARD_KEY_d8=!f23 # touchpad off + KEYBOARD_KEY_d9=!f22 # touchpad on + +# Chromebook 14 +# Top row keys (between ESC and power button) +keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr* + KEYBOARD_KEY_3b=back + KEYBOARD_KEY_3c=forward + KEYBOARD_KEY_3d=refresh + KEYBOARD_KEY_3f=switchvideomode + KEYBOARD_KEY_40=brightnessdown + KEYBOARD_KEY_41=brightnessup + KEYBOARD_KEY_42=mute + KEYBOARD_KEY_43=volumedown + KEYBOARD_KEY_44=volumeup + KEYBOARD_KEY_db=search # Same position as caps lock key on most keyboards +# KEYBOARD_KEY_3e=fullscreen, no defined key sym + + +########################################################### +# IBM +########################################################### + +# thinkpad_acpi driver +keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr* + KEYBOARD_KEY_01=battery # Fn+F2 + KEYBOARD_KEY_02=screenlock # Fn+F3 + KEYBOARD_KEY_03=sleep # Fn+F4 + KEYBOARD_KEY_04=wlan # Fn+F5 + KEYBOARD_KEY_06=switchvideomode # Fn+F7 + KEYBOARD_KEY_07=zoom # Fn+F8 screen expand + KEYBOARD_KEY_08=f24 # Fn+F9 undock + KEYBOARD_KEY_0b=suspend # Fn+F12 + KEYBOARD_KEY_0f=brightnessup # Fn+Home + KEYBOARD_KEY_10=brightnessdown # Fn+End + KEYBOARD_KEY_11=kbdillumtoggle # Fn+PgUp - ThinkLight + KEYBOARD_KEY_13=zoom # Fn+Space + KEYBOARD_KEY_14=volumeup + KEYBOARD_KEY_15=volumedown + KEYBOARD_KEY_16=mute + KEYBOARD_KEY_17=prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor") + +# IBM Thinkpad USB Keyboard Trackpoint +keyboard:usb:v04B3p301[89]* + KEYBOARD_KEY_900f0=screenlock + KEYBOARD_KEY_900f1=wlan + KEYBOARD_KEY_900f2=switchvideomode + KEYBOARD_KEY_900f3=suspend + KEYBOARD_KEY_900f4=brightnessup + KEYBOARD_KEY_900f5=brightnessdown + KEYBOARD_KEY_900f8=zoom + +########################################################### +# Inventec +########################################################### + +# Symphony +keyboard:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr* + KEYBOARD_KEY_f3=prog2 + KEYBOARD_KEY_f4=prog1 + +########################################################### +# Lenovo +########################################################### + +# thinkpad_acpi driver +keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn* + KEYBOARD_KEY_01=screenlock + KEYBOARD_KEY_02=battery + KEYBOARD_KEY_03=sleep + KEYBOARD_KEY_04=wlan + KEYBOARD_KEY_06=switchvideomode + KEYBOARD_KEY_07=f21 + KEYBOARD_KEY_08=f24 + KEYBOARD_KEY_0b=suspend + KEYBOARD_KEY_0f=brightnessup + KEYBOARD_KEY_10=brightnessdown + KEYBOARD_KEY_11=kbdillumtoggle + KEYBOARD_KEY_13=zoom + KEYBOARD_KEY_14=volumeup + KEYBOARD_KEY_15=volumedown + KEYBOARD_KEY_16=mute + KEYBOARD_KEY_17=prog1 + KEYBOARD_KEY_1a=f20 + +# ThinkPad Keyboard with TrackPoint +keyboard:usb:v17EFp6009* + KEYBOARD_KEY_090012=screenlock # Fn+F2 + KEYBOARD_KEY_090013=battery # Fn+F3 + KEYBOARD_KEY_090014=wlan # Fn+F5 + KEYBOARD_KEY_090016=switchvideomode # Fn+F7 + KEYBOARD_KEY_090017=f21 # Fn+F8 touchpad toggle + KEYBOARD_KEY_090019=suspend # Fn+F12 + KEYBOARD_KEY_09001a=brightnessup # Fn+Home + KEYBOARD_KEY_09001b=brightnessdown # Fn+End + KEYBOARD_KEY_09001d=zoom # Fn+Space + KEYBOARD_KEY_090011=prog1 # ThinkVantage button + KEYBOARD_KEY_090015=camera # Fn+F6 headset/camera VoIP key ?? + KEYBOARD_KEY_090010=f20 # Microphone mute button; should be micmute + +# Lenovo 3000 +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr* + KEYBOARD_KEY_8b=switchvideomode # Fn+F7 video + KEYBOARD_KEY_96=wlan # Fn+F5 wireless + KEYBOARD_KEY_97=sleep # Fn+F4 suspend + KEYBOARD_KEY_98=suspend # Fn+F12 hibernate + KEYBOARD_KEY_b4=prog1 # Lenovo Care + +# lenovo-ideapad +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr* + KEYBOARD_KEY_81=rfkill # does nothing in BIOS + KEYBOARD_KEY_83=display_off # BIOS toggles screen state + KEYBOARD_KEY_b9=brightnessup # does nothing in BIOS + KEYBOARD_KEY_ba=brightnessdown # does nothing in BIOS + KEYBOARD_KEY_f1=camera # BIOS toggles camera power + KEYBOARD_KEY_f2=f21 # touchpad toggle (key alternately emits F2 and F3) + KEYBOARD_KEY_f3=f21 + +# Thinkpad X200_Tablet +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X2*Tablet*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet* + KEYBOARD_KEY_5d=menu + KEYBOARD_KEY_63=fn + KEYBOARD_KEY_66=screenlock + KEYBOARD_KEY_67=cyclewindows # bezel circular arrow + KEYBOARD_KEY_68=setup # bezel setup / menu + KEYBOARD_KEY_6c=direction # rotate screen + +# ThinkPad X6 Tablet +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X6*:pvr* + KEYBOARD_KEY_6c=f21 # rotate + KEYBOARD_KEY_68=screenlock # screenlock + KEYBOARD_KEY_6b=esc # escape + KEYBOARD_KEY_6d=right # right on d-pad + KEYBOARD_KEY_6e=left # left on d-pad + KEYBOARD_KEY_71=up # up on d-pad + KEYBOARD_KEY_6f=down # down on d-pad + KEYBOARD_KEY_69=enter # enter on d-pad + +# IdeaPad +keyboard:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn* + KEYBOARD_KEY_42=f23 + KEYBOARD_KEY_43=f22 + +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr* + KEYBOARD_KEY_95=media + KEYBOARD_KEY_a3=play + +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr* + KEYBOARD_KEY_f1=f21 + KEYBOARD_KEY_ce=f20 + +keyboard:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr* + KEYBOARD_KEY_a0=!mute + KEYBOARD_KEY_ae=!volumedown + KEYBOARD_KEY_b0=!volumeup + +# V480 +keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr* + KEYBOARD_KEY_f1=f21 + +########################################################### +# Logitech +########################################################### + +# iTouch +keyboard:usb:v046DpC308* + KEYBOARD_KEY_90001=shop # Shopping + KEYBOARD_KEY_90002=config # iTouch + KEYBOARD_KEY_90003=finance # Finance + KEYBOARD_KEY_90004=prog1 # My Sites + KEYBOARD_KEY_90005=prog2 # Community + KEYBOARD_KEY_C0183=media # Media + +# Cordless Desktop S510 +keyboard:usb:v046DpC50C* + KEYBOARD_KEY_d4=zoomin + KEYBOARD_KEY_cc=zoomout + +# Wave cordless +keyboard:usb:v046DpC317* + KEYBOARD_KEY_9001c=scale # expo + KEYBOARD_KEY_9001f=zoomout + KEYBOARD_KEY_90020=zoomin + KEYBOARD_KEY_9003d=prog1 # gadget + KEYBOARD_KEY_90005=camera + KEYBOARD_KEY_90018=media + KEYBOARD_KEY_90041=wordprocessor + KEYBOARD_KEY_90042=spreadsheet + KEYBOARD_KEY_90043=calendar + KEYBOARD_KEY_90044=prog2 # fn+f4 (program a) + KEYBOARD_KEY_90045=prog3 # fn+f5 (program b) + KEYBOARD_KEY_90046=prog4 # fn+f6 (program c) + KEYBOARD_KEY_90048=messenger # fn+f8 (msn messenger) + KEYBOARD_KEY_9002d=search # fn+f10 (search www) + KEYBOARD_KEY_9004b=find # fn+f11 (search pc) + KEYBOARD_KEY_9004c=ejectclosecd + +# Wave cordless +keyboard:usb:v046DpC517* + KEYBOARD_KEY_c101f=zoomout + KEYBOARD_KEY_c1020=zoomin + KEYBOARD_KEY_c1005=camera + KEYBOARD_KEY_c0183=media + KEYBOARD_KEY_c1041=wordprocessor + KEYBOARD_KEY_c1042=spreadsheet + KEYBOARD_KEY_c1043=calendar + KEYBOARD_KEY_c1044=prog2 # fn+f4 (program a) + KEYBOARD_KEY_c1045=prog3 # fn+f5 (program b) + KEYBOARD_KEY_c1046=prog4 # fn+f6 (program c) + KEYBOARD_KEY_c1048=messenger # fn+f8 (msn messenger) + KEYBOARD_KEY_c104a=find # fn+f10 (search www) + KEYBOARD_KEY_c104c=ejectclosecd + +# Cordless Wave Pro +keyboard:usb:v046DpC52[9B]* + KEYBOARD_KEY_0c01b6=camera + KEYBOARD_KEY_0c0183=media + KEYBOARD_KEY_0c0184=wordprocessor + KEYBOARD_KEY_0c0186=spreadsheet + KEYBOARD_KEY_0c018e=calendar + KEYBOARD_KEY_0c0223=homepage + KEYBOARD_KEY_0c01bc=messenger + KEYBOARD_KEY_0c018a=mail + KEYBOARD_KEY_0c0221=search + KEYBOARD_KEY_0c00b8=ejectcd + KEYBOARD_KEY_0c022d=zoomin + KEYBOARD_KEY_0c022e=zoomout + +# Logitech Presenter R400 +keyboard:usb:v046DpC52Dd*dc*dsc*dp*ic*isc*ip*in00* + KEYBOARD_KEY_070029=presentation + KEYBOARD_KEY_07003e=presentation + KEYBOARD_KEY_070037=displaytoggle + +# Internet Navigator +keyboard:usb:v046DpC309* + KEYBOARD_KEY_90001=chat # Messenger/SMS + KEYBOARD_KEY_90002=camera # webcam + KEYBOARD_KEY_90003=prog1 # iTouch + KEYBOARD_KEY_90004=shop # Shopping + KEYBOARD_KEY_C0201=new # New (F1) + KEYBOARD_KEY_C0289=reply # Reply mail (F2) + KEYBOARD_KEY_C028B=forwardmail # Forward mail (F3) + KEYBOARD_KEY_C028C=send # Send (F4) + KEYBOARD_KEY_C021A=undo # Undo (F5). + KEYBOARD_KEY_C0279=redo # Redo (F6). + KEYBOARD_KEY_C0208=print # Print (F7) + KEYBOARD_KEY_C0207=save # Save (F8) + KEYBOARD_KEY_C0194=file # My Computer (F9) + KEYBOARD_KEY_C01A7=documents # My Documents (F10) + KEYBOARD_KEY_C01B6=images # My Pictures (F11) ?? + KEYBOARD_KEY_C01B7=sound # My Music (F12) ?? + + +########################################################### +# Maxdata +########################################################### + +# Pro 7000 +keyboard:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr* + KEYBOARD_KEY_97=prog2 + KEYBOARD_KEY_9f=prog1 + KEYBOARD_KEY_a0=mute # Fn+F5 + KEYBOARD_KEY_82=www + KEYBOARD_KEY_ec=email + KEYBOARD_KEY_ae=volumedown # Fn+Down + KEYBOARD_KEY_b0=volumeup # Fn+Up + KEYBOARD_KEY_df=suspend # Fn+F2 + KEYBOARD_KEY_f5=help + +########################################################### +# Medion +########################################################### + +# FID2060 +keyboard:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:pvr* + KEYBOARD_KEY_6b=channeldown # Thottle Down + KEYBOARD_KEY_6d=channelup # Thottle Up + +# NB-A555 +keyboard:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr* + KEYBOARD_KEY_63=www # N button + KEYBOARD_KEY_66=prog1 # link 1 button + KEYBOARD_KEY_67=email # envelope button + KEYBOARD_KEY_69=prog2 # link 2 button + +########################################################### +# Microsoft +########################################################### + +# Microsoft Natural Ergonomic Keyboard 4000 +keyboard:usb:v045Ep00DB* + KEYBOARD_KEY_c022d=zoomin + KEYBOARD_KEY_c022e=zoomout + +########################################################### +# Micro Star +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn* +keyboard:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn* + KEYBOARD_KEY_a0=mute # Fn+F9 + KEYBOARD_KEY_ae=volumedown # Fn+F7 + KEYBOARD_KEY_b0=volumeup # Fn+F8 + KEYBOARD_KEY_b2=www # e button + KEYBOARD_KEY_df=sleep # Fn+F12 + KEYBOARD_KEY_e2=bluetooth # satellite dish2 + KEYBOARD_KEY_e4=f21 # Fn+F3 Touchpad disable + KEYBOARD_KEY_ec=email # envelope button + KEYBOARD_KEY_ee=camera # Fn+F6 camera disable + KEYBOARD_KEY_f6=wlan # satellite dish1 + KEYBOARD_KEY_f7=brightnessdown # Fn+F4 + KEYBOARD_KEY_f8=brightnessup # Fn+F5 + KEYBOARD_KEY_f9=search + +# +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE60*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE70*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:pvr* + KEYBOARD_KEY_c2=ejectcd + +# +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U-100*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U100*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*N033:* + KEYBOARD_KEY_f7=reserved + KEYBOARD_KEY_f8=reserved + +# +keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:* + KEYBOARD_KEY_e4=reserved + +########################################################### +# MSI +########################################################### + +keyboard:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:pvr* + KEYBOARD_KEY_0213=f22 + KEYBOARD_KEY_0214=f23 + +########################################################### +# OLPC +########################################################### + +# XO +keyboard:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:* + KEYBOARD_KEY_59=fn + KEYBOARD_KEY_81=fn_esc + KEYBOARD_KEY_f9=camera + KEYBOARD_KEY_f8=sound # Fn+CAMERA = Mic + KEYBOARD_KEY_43=brightnessdown + KEYBOARD_KEY_44=brightnessup + KEYBOARD_KEY_57=volumedown + KEYBOARD_KEY_58=volumeup + KEYBOARD_KEY_bb=f1 + KEYBOARD_KEY_bc=f2 + KEYBOARD_KEY_bd=f3 + KEYBOARD_KEY_be=f4 + KEYBOARD_KEY_bf=f5 + KEYBOARD_KEY_c0=f6 + KEYBOARD_KEY_c1=f7 + KEYBOARD_KEY_c2=f8 + KEYBOARD_KEY_c3=f9 + KEYBOARD_KEY_c4=f10 + KEYBOARD_KEY_c7=f11 + KEYBOARD_KEY_d8=f12 + KEYBOARD_KEY_f7=f13 + KEYBOARD_KEY_f6=f14 + KEYBOARD_KEY_f5=f15 + KEYBOARD_KEY_f4=f16 + KEYBOARD_KEY_f3=f17 + KEYBOARD_KEY_f2=f18 + KEYBOARD_KEY_f1=f19 + KEYBOARD_KEY_f0=f20 + KEYBOARD_KEY_ef=f21 + KEYBOARD_KEY_ee=chat + KEYBOARD_KEY_e4=chat + KEYBOARD_KEY_dd=menu # Frame + KEYBOARD_KEY_da=prog1 # Fn+Frame + KEYBOARD_KEY_d3=delete + KEYBOARD_KEY_d2=insert + KEYBOARD_KEY_c9=pageup + KEYBOARD_KEY_d1=pagedown + KEYBOARD_KEY_c7=home + KEYBOARD_KEY_cF=end + KEYBOARD_KEY_73=hp + KEYBOARD_KEY_7e=hp + KEYBOARD_KEY_db=leftmeta # left grab + KEYBOARD_KEY_dc=rightmeta # right grab + KEYBOARD_KEY_85=rightmeta # Right grab releases on a different scancode + KEYBOARD_KEY_d6=kbdillumtoggle # Fn+Space + KEYBOARD_KEY_69=switchvideomode # Brightness key + KEYBOARD_KEY_65=kp8 # up + KEYBOARD_KEY_66=kp2 # down + KEYBOARD_KEY_67=kp4 # left + KEYBOARD_KEY_68=kp6 # right + KEYBOARD_KEY_e5=kp9 # pgup + KEYBOARD_KEY_e6=kp3 # pgdn + KEYBOARD_KEY_e7=kp7 # home + KEYBOARD_KEY_e8=kp1 # end + +########################################################### +# Onkyo +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:* + KEYBOARD_KEY_a0=mute # Fn+D + KEYBOARD_KEY_ae=volumedown # Fn+F + KEYBOARD_KEY_b0=volumeup # Fn+G + KEYBOARD_KEY_df=sleep # Fn+W + KEYBOARD_KEY_e0=bluetooth # Fn+H + KEYBOARD_KEY_e2=cyclewindows # Fn+Esc + KEYBOARD_KEY_ee=battery # Fn+Q + KEYBOARD_KEY_f0=media # Fn+R + KEYBOARD_KEY_f5=switchvideomode # Fn+E + KEYBOARD_KEY_f6=camera # Fn+T + KEYBOARD_KEY_f7=f21 # Fn+Y (touchpad toggle) + KEYBOARD_KEY_f8=brightnessup # Fn+S + KEYBOARD_KEY_f9=brightnessdown # Fn+A + KEYBOARD_KEY_fb=wlan # Fn+J + +########################################################### +# OQO +########################################################### + +# Model 2 +keyboard:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr* + KEYBOARD_KEY_8e=wlan + KEYBOARD_KEY_f0=switchvideomode + KEYBOARD_KEY_f1=mute + KEYBOARD_KEY_f2=volumedown + KEYBOARD_KEY_f3=volumeup + +########################################################### +# Quanta +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*:rvnQuanta:rn30B7:rvr65.2B:* + KEYBOARD_KEY_88=media # "quick play + +########################################################### +# Samsung +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn* + KEYBOARD_KEY_74=prog1 # User key + KEYBOARD_KEY_75=www + KEYBOARD_KEY_78=mail + KEYBOARD_KEY_82=!switchvideomode # Fn+F4 CRT/LCD (high keycode: "displaytoggle") + KEYBOARD_KEY_83=!battery # Fn+F2 + KEYBOARD_KEY_84=!prog1 # Fn+F5 backlight on/off + KEYBOARD_KEY_86=!wlan # Fn+F9 + KEYBOARD_KEY_88=!brightnessup # Fn+Up + KEYBOARD_KEY_89=!brightnessdown # Fn+Down + KEYBOARD_KEY_b1=!prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice) + KEYBOARD_KEY_b3=!prog3 # Fn+F8 switch power mode (battery/dynamic/performance) + KEYBOARD_KEY_b4=!wlan # Fn+F9 (X60P) + KEYBOARD_KEY_c5=!prog3 # Fn+F8 switch power mode (battery/dynamic/performance) + KEYBOARD_KEY_d5=!wlan # Fn+F12 wlan/airplane switch + KEYBOARD_KEY_f7=!f22 # Fn+F10 Touchpad on + KEYBOARD_KEY_f9=!f23 # Fn+F10 Touchpad off + +# Series 3 +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:pvr* + KEYBOARD_KEY_ce=! # Fn+F1 launch control setting + +# Series 5 +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_a8=! # Fn Lock - Function lock on + KEYBOARD_KEY_a9=! # Fn Lock - Function lock off + +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_a8=! # Fn Lock - Function lock on + KEYBOARD_KEY_a9=! # Fn Lock - Function lock off + +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][CDG]*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_a0=!mute # Fn+F6 mute + KEYBOARD_KEY_ae=!volumedown # Fn+F7 + KEYBOARD_KEY_b0=!volumeup # Fn+F8 + KEYBOARD_KEY_97=!kbdillumdown # Fn+F9 keyboard backlight down + KEYBOARD_KEY_96=!kbdillumup # Fn+F10 keyboard backlight up + KEYBOARD_KEY_b3=!prog3 # Fn+F11 fan/cooling mode changer + +# Series 9 +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:pvr* + KEYBOARD_KEY_ce=! # Fn+F8 keyboard backlight up + KEYBOARD_KEY_8d=! # Fn+F7 keyboard backlight down + KEYBOARD_KEY_96=! # Fn+F1 performance mode (?) + KEYBOARD_KEY_97=! # Fn+F12 Wi-Fi toggle + KEYBOARD_KEY_d5=! # Fn+F6 battery life extender + +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings + KEYBOARD_KEY_8d=!prog3 # Fn+F6 performance mode + KEYBOARD_KEY_97=!kbdillumdown # Fn+F7 keyboard backlight down + KEYBOARD_KEY_96=!kbdillumup # Fn+F8 keyboard backlight up + KEYBOARD_KEY_d5=!wlan # Fn+F12 Wi-Fi toggle + +# SQ1US +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr* + KEYBOARD_KEY_d4=menu + KEYBOARD_KEY_d8=f1 + KEYBOARD_KEY_d9=f10 + KEYBOARD_KEY_d6=f3 + KEYBOARD_KEY_d7=f9 + KEYBOARD_KEY_e4=f5 + KEYBOARD_KEY_ee=f11 + +# SX20S +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:pvr* + KEYBOARD_KEY_74=mute + KEYBOARD_KEY_75=mute + KEYBOARD_KEY_77=f22 # Touchpad on + KEYBOARD_KEY_79=f23 # Touchpad off + +keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr* + KEYBOARD_KEY_ad=leftmeta + +########################################################### +# SONY +########################################################### + +# sony-laptop driver +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn* + KEYBOARD_KEY_06=mute # Fn+F2 + KEYBOARD_KEY_07=volumedown # Fn+F3 + KEYBOARD_KEY_08=volumeup # Fn+F4 + KEYBOARD_KEY_09=brightnessdown # Fn+F5 + KEYBOARD_KEY_0a=brightnessup # Fn+F6 + KEYBOARD_KEY_0b=switchvideomode # Fn+F7 + KEYBOARD_KEY_0e=zoom # Fn+F10 + KEYBOARD_KEY_10=suspend # Fn+F12 + +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-C1*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-K25*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-F[1-6]*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FX*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FRV*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-GR*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-TR*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-NV*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-Z*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*VGN-S360*:pvr* + KEYBOARD_KEY_06=battery + KEYBOARD_KEY_07=mute + +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-AR71*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW*:pvr* +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr* + KEYBOARD_KEY_00=brightnessdown # Fn+F5 + KEYBOARD_KEY_10=brightnessup # Fn+F6 + KEYBOARD_KEY_11=switchvideomode # Fn+F7 + KEYBOARD_KEY_12=zoomout + KEYBOARD_KEY_14=zoomin + KEYBOARD_KEY_15=suspend # Fn+F12 + KEYBOARD_KEY_17=prog1 + KEYBOARD_KEY_20=media + +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:pvr* + KEYBOARD_KEY_10=suspend # Fn+F12 + +keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr* + KEYBOARD_KEY_05=f21 # Fn+F1 -> KEY_F21 (The actual touchpad toggle) + KEYBOARD_KEY_0d=zoomout # Fn+F9 + KEYBOARD_KEY_0e=zoomin # Fn+F10 + +########################################################### +# Toshiba +########################################################### + +# Satellite A100 +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITE*A100:pvr* + KEYBOARD_KEY_a4=stopcd + KEYBOARD_KEY_b2=www + +# Satellite A110 +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr* + KEYBOARD_KEY_92=stop + KEYBOARD_KEY_93=www + KEYBOARD_KEY_94=media + KEYBOARD_KEY_9e=f22 # Touchpad on + KEYBOARD_KEY_9f=f23 # Touchpad off + KEYBOARD_KEY_b9=nextsong + KEYBOARD_KEY_d9=brightnessup + KEYBOARD_KEY_ee=screenlock + KEYBOARD_KEY_f4=previoussong + KEYBOARD_KEY_f7=playpause + +# Satellite M30X +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr* + KEYBOARD_KEY_ef=brightnessdown + KEYBOARD_KEY_d9=brightnessup + KEYBOARD_KEY_ee=screenlock + KEYBOARD_KEY_93=media + KEYBOARD_KEY_9e=f22 # touchpad enable + KEYBOARD_KEY_9f=f23 # touchpad disable + +# Satellite P75-A +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr* + KEYBOARD_KEY_ef=brightnessdown + KEYBOARD_KEY_ee=brightnessup + KEYBOARD_KEY_a9=switchvideomode # switch display outputs + KEYBOARD_KEY_d4=wlan # RF Switch Off + +# Satellite U940 +keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:pvr* + KEYBOARD_KEY_13c=brightnessdown + KEYBOARD_KEY_13d=brightnessup + KEYBOARD_KEY_13e=switchvideomode + KEYBOARD_KEY_13f=f21 # Touchpad toggle + +# Satellite P75-A7200 +keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr* + KEYBOARD_KEY_13c=brightnessdown + KEYBOARD_KEY_13d=brightnessup + KEYBOARD_KEY_13e=switchvideomode + KEYBOARD_KEY_13f=touchpad_toggle + KEYBOARD_KEY_9e=wlan + +########################################################### +# VIA +########################################################### + +keyboard:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:pvr* + KEYBOARD_KEY_81=prog1 + +########################################################### +# Zepto +########################################################### + +# Znote +keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote:* + KEYBOARD_KEY_93=switchvideomode # Fn+F3 Toggle Video Output + KEYBOARD_KEY_95=brightnessdown # Fn+F4 Brightness Down + KEYBOARD_KEY_91=brightnessup # Fn+F5 Brightness Up + KEYBOARD_KEY_a5=f23 # Fn+F6 Disable Touchpad + KEYBOARD_KEY_a6=f22 # Fn+F6 Enable Touchpad + KEYBOARD_KEY_a7=bluetooth # Fn+F10 Enable Bluetooth + KEYBOARD_KEY_a9=bluetooth # Fn+F10 Disable Bluetooth + KEYBOARD_KEY_f1=wlan # RF Switch Off + KEYBOARD_KEY_f2=wlan # RF Switch On + KEYBOARD_KEY_f4=prog1 # P1 Button + KEYBOARD_KEY_f3=prog2 # P2 Button + KEYBOARD_KEY_a0=! # mute + KEYBOARD_KEY_ae=! # volume down + KEYBOARD_KEY_b0=! # volume up + +# Znote 6615WD +keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote*6615WD:* + KEYBOARD_KEY_a0=! # mute + KEYBOARD_KEY_ae=! # volume down + KEYBOARD_KEY_b0=! # volume up + +########################################################### +# Other +########################################################### + +# Common Volume Keys +keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*SIEMENS:pnAMILO*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnFOXCONN:pnQBOOK:* +keyboard:dmi:bvn*:bvr*:bd*:svnMTC:pn*:pvrA0:* +keyboard:dmi:bvn*:bvr*:bd*:svnMio*Technology:pnN890:* +keyboard:dmi:bvn*:bvr*:bd*:svnPEGATRON*CORP.:pnSpring*Peak:* +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*[uU][35]0[05]*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSATELLITE*[uU][35]0[05]*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*Pro*[uU]300*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnEQUIUM [uU][35]0[05]*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnViooo*Corporation:pnPT17:* +keyboard:dmi:bvn*:bvr*:bd*:svnHANNspree:pnSN10E100:* +keyboard:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pni1520M:* +keyboard:dmi:bvn*:bvr*:bd*:svnBenQ:pn*nScreen*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnBenQ:pnJoybook*Lite*:pvr* +keyboard:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:pvr* + KEYBOARD_KEY_a0=! # mute + KEYBOARD_KEY_ae=! # volume down + KEYBOARD_KEY_b0=! # volume up diff --git a/hwdb/Makefile b/hwdb/Makefile new file mode 120000 index 0000000..bd10475 --- /dev/null +++ b/hwdb/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/hwdb/ids-update.pl b/hwdb/ids-update.pl new file mode 100755 index 0000000..b72c415 --- /dev/null +++ b/hwdb/ids-update.pl @@ -0,0 +1,340 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +sub usb_vendor { + my $vendor; + + open(IN, "<", "usb.ids"); + open(OUT, ">", "20-usb-vendor-model.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: http://www.linux-usb.org/usb.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + $line =~ m/^([0-9a-f]{4})\s*(.+)$/; + if (defined $1) { + $vendor = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "usb:v" . $vendor . "*\n"); + print(OUT " ID_VENDOR_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t([0-9a-f]{4})\s*(.+)$/; + if (defined $1) { + my $model = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "usb:v" . $vendor . "p" . $model . "*\n"); + print(OUT " ID_MODEL_FROM_DATABASE=" . $text . "\n"); + } + } + + close(IN); + close(OUT); +} + +sub usb_classes { + my $class; + my $subclass; + my $protocol; + + open(IN, "<", "usb.ids"); + open(OUT, ">", "20-usb-classes.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: http://www.linux-usb.org/usb.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + + $line =~ m/^C\ ([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $class = uc $1; + if ($class =~ m/^00$/) { + next; + } + my $text = $2; + print(OUT "\n"); + print(OUT "usb:v*p*d*dc" . $class . "*\n"); + print(OUT " ID_USB_CLASS_FROM_DATABASE=" . $text . "\n"); + next; + } + + if (not defined $class) { + next; + } elsif ($line =~ m/^$/) { + last; + } + + $line =~ m/^\t([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $subclass = uc $1; + if ($subclass =~ m/^00$/) { + next; + } + my $text = $2; + if ($text =~ m/^(\?|None|Unused)$/) { + next; + } + print(OUT "\n"); + print(OUT "usb:v*p*d*dc" . $class . "dsc" . $subclass . "*\n"); + print(OUT " ID_USB_SUBCLASS_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t\t([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $protocol = uc $1; + my $text = $2; + if ($text =~ m/^(\?|None|Unused)$/) { + next; + } + print(OUT "\n"); + print(OUT "usb:v*p*d*dc" . $class . "dsc" . $subclass . "dp" . $protocol . "*\n"); + print(OUT " ID_USB_PROTOCOL_FROM_DATABASE=" . $text . "\n"); + } + } + + close(IN); + close(OUT); +} + +sub pci_vendor { + my $vendor; + my $device; + + open(IN, "<", "pci.ids"); + open(OUT, ">", "20-pci-vendor-model.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: http://pci-ids.ucw.cz/v2.2/pci.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + $line =~ m/^([0-9a-f]{4})\s*(.+)$/; + + if (defined $1) { + $vendor = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "pci:v0000" . $vendor . "*\n"); + print(OUT " ID_VENDOR_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t([0-9a-f]{4})\s*(.+)$/; + if (defined $1) { + $device = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "pci:v0000" . $vendor . "d0000" . $device . "*\n"); + print(OUT " ID_MODEL_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t\t([0-9a-f]{4})\s*([0-9a-f]{4})\s*(.*)$/; + if (defined $1) { + my $sub_vendor = uc $1; + my $sub_device = uc $2; + my $text = $3; + print(OUT "\n"); + print(OUT "pci:v0000" . $vendor . "d0000" . $device . "sv0000" . $sub_vendor . "sd0000" . $sub_device . "*\n"); + print(OUT " ID_MODEL_FROM_DATABASE=" . $text . "\n"); + } + } + + close(IN); + close(OUT); +} + +sub pci_classes { + my $class; + my $subclass; + my $interface; + + open(IN, "<", "pci.ids"); + open(OUT, ">", "20-pci-classes.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: http://pci-ids.ucw.cz/v2.2/pci.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + + $line =~ m/^C\ ([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $class = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "pci:v*d*sv*sd*bc" . $class . "*\n"); + print(OUT " ID_PCI_CLASS_FROM_DATABASE=" . $text . "\n"); + next; + } + + if (not defined $class) { + next; + } elsif ($line =~ m/^$/) { + last; + } + + $line =~ m/^\t([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $subclass = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "pci:v*d*sv*sd*bc" . $class . "sc" . $subclass . "*\n"); + print(OUT " ID_PCI_SUBCLASS_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t\t([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $interface = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "pci:v*d*sv*sd*bc" . $class . "sc" . $subclass . "i" . $interface . "*\n"); + print(OUT " ID_PCI_INTERFACE_FROM_DATABASE=" . $text . "\n"); + } + } + + close(IN); + close(OUT); +} + +sub sdio_vendor { + my $vendor; + my $device; + + open(IN, "<", "sdio.ids"); + open(OUT, ">", "20-sdio-vendor-model.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: hwdb/sdio.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + $line =~ m/^([0-9a-f]{4})\s*(.+)$/; + + if (defined $1) { + $vendor = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "sdio:c*v" . $vendor . "*\n"); + print(OUT " ID_VENDOR_FROM_DATABASE=" . $text . "\n"); + next; + } + + $line =~ m/^\t([0-9a-f]{4})\s*(.+)$/; + if (defined $1) { + $device = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "sdio:c*v" . $vendor . "d" . $device . "*\n"); + print(OUT " ID_MODEL_FROM_DATABASE=" . $text . "\n"); + next; + } + } + + close(IN); + close(OUT); +} + +sub sdio_classes { + my $class; + my $subclass; + my $interface; + + open(IN, "<", "sdio.ids"); + open(OUT, ">", "20-sdio-classes.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from: hwdb/sdio.ids\n"); + + while (my $line = ) { + $line =~ s/\s+$//; + + $line =~ m/^C\ ([0-9a-f]{2})\s*(.+)$/; + if (defined $1) { + $class = uc $1; + my $text = $2; + print(OUT "\n"); + print(OUT "sdio:c" . $class . "v*d*\n"); + print(OUT " ID_SDIO_CLASS_FROM_DATABASE=" . $text . "\n"); + next; + } + } + + close(IN); + close(OUT); +} + +sub oui { + my $iab_prefix; + my %iab_prefixes = (); + + open(OUT, ">", "20-OUI.hwdb"); + print(OUT "# This file is part of systemd.\n" . + "#\n" . + "# Data imported from:\n" . + "# http://standards.ieee.org/develop/regauth/oui/oui.txt\n" . + "# http://standards.ieee.org/develop/regauth/iab/iab.txt\n"); + + open(IN, "<", "iab.txt"); + while (my $line = ) { + $line =~ s/^ +//; + $line =~ s/\s+$//; + $line =~ m/^([0-9A-F]{2})-([0-9A-F]{2})-([0-9A-F]{2})\s*\(hex\)\s*.+$/; + if (defined $1) { + $iab_prefix = $1 . $2 . $3; + $iab_prefixes{ $iab_prefix } = 1; + next; + } + + $line =~ m/^([0-9A-F]{3})000-\g1FFF\s*\(base 16\)\s*(.+)$/; + if (defined $1) { + my $vendor = uc $1; + my $text = $2; + + print(OUT "\n"); + print(OUT "OUI:" . $iab_prefix . $vendor . "*\n"); + print(OUT " ID_OUI_FROM_DATABASE=" . $text . "\n"); + } + } + close(IN); + + open(IN, "<", "oui.txt"); + while (my $line = ) { + $line =~ s/^ +//; + $line =~ s/\s+$//; + $line =~ m/^([0-9A-F]{6})\s*\(base 16\)\s*(.+)$/; + if (defined $1) { + my $vendor = uc $1; + my $text = $2; + + # skip the IAB prefixes + if (! exists $iab_prefixes{ $vendor }) { + print(OUT "\n"); + print(OUT "OUI:" . $vendor . "*\n"); + print(OUT " ID_OUI_FROM_DATABASE=" . $text . "\n"); + } + } + } + close(IN); + close(OUT); +} + +usb_vendor(); +usb_classes(); + +pci_vendor(); +pci_classes(); + +sdio_vendor(); +sdio_classes(); + +oui(); diff --git a/hwdb/sdio.ids b/hwdb/sdio.ids new file mode 100644 index 0000000..8a4c713 --- /dev/null +++ b/hwdb/sdio.ids @@ -0,0 +1,84 @@ +# +# List of SDIO ID's +# + +# Vendors and devices. Please keep sorted. + +# Syntax: +# vendor vendor_name +# device device_name <-- single tab + +0020 ST-Ericsson + 2280 CW1200 +0089 Intel Corp. +0092 C-guys, Inc. + 0001 SD-Link11b WiFi Card (TI ACX100) + 0004 EW-CG1102GC + 0005 SD FM Radio 2 + 5544 SD FM Radio +0097 Texas Instruments, Inc. + 4076 WL1271 +0098 Toshiba Corp. + 0001 SD BT Card 1 + 0002 SD BT Card 2 + 0003 SD BT Card 3 +0104 Socket Communications, Inc. + 005e SD Scanner + 00c5 Bluetooth SDIO Card +0271 Atheros Communications, Inc. + 0108 AR6001 + 0109 AR6001 + 010a AR6001 + 010b AR6001 +0296 GCT Semiconductor, Inc. + 5347 GDM72xx WiMAX +02d0 Broadcom Corp. + 044b Nintendo Wii WLAN daughter card +02db SyChip Inc. + 0002 Pegasus WLAN SDIO Card (6060SD) +02df Marvell Technology Group Ltd. + 9103 Libertas + 9104 SD8688 WLAN + 9105 SD8688 BT + 9116 SD8786 WLAN + 9119 SD8787 WLAN + 911a SD8787 BT + 911b SD8787 BT AMP + 9129 SD8797 WLAN + 912a SD8797 BT + 912e SD8897 BT + 912d SD8897 WLAN +02fe Spectec Computer Co., Ltd + 2128 SDIO WLAN Card (SDW820) +032a Cambridge Silicon Radio + 0001 UniFi 1 + 0002 UniFi 2 + 0007 UniFi 3 + 0008 UniFi 4 +037a MediaTek Inc. + 5911 Spectec WLAN-11b/g +039a Siano Mobile Silicon +0501 Globalsat Technology Co. + f501 SD-501 GPS Card +104c Texas Instruments, Inc. + 9066 WL1251 +1180 Ricoh Co., Ltd + e823 MMC card reader +13d1 AboCom Systems, Inc. + ac02 SDW11G + +# List of known interface classes +# +# Syntax: +# C class class_name + +C 00 Not a SDIO standard interface +C 01 UART standard interface +C 02 Bluetooth Type-A standard interface +C 03 Bluetooth Type-B standard interface +C 04 GPS standard interface +C 05 Camera standard interface +C 06 PHS standard interface +C 07 WLAN interface +C 08 Embedded SDIO-ATA standard interface +C 09 Bluetooth AMP standard interface diff --git a/introspect.awk b/introspect.awk deleted file mode 100644 index 5931913..0000000 --- a/introspect.awk +++ /dev/null @@ -1,13 +0,0 @@ -BEGIN { - print "" - print "" -} - -// { - print -} - -END { - print "" -} diff --git a/libsystemd-daemon.pc.in b/libsystemd-daemon.pc.in deleted file mode 100644 index 8bb3a74..0000000 --- a/libsystemd-daemon.pc.in +++ /dev/null @@ -1,19 +0,0 @@ -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Daemon Utility Library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd-daemon -Cflags: -I${includedir} diff --git a/libsystemd-login.pc.in b/libsystemd-login.pc.in deleted file mode 100644 index cd36a9c..0000000 --- a/libsystemd-login.pc.in +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Login Utility Library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd-login -Cflags: -I${includedir} diff --git a/m4/.gitignore b/m4/.gitignore index 55eaa80..cf35a86 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -4,3 +4,4 @@ ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 +gtk-doc.m4 diff --git a/m4/attributes.m4 b/m4/attributes.m4 index 9d561c2..aa53ef2 100644 --- a/m4/attributes.m4 +++ b/m4/attributes.m4 @@ -1,6 +1,7 @@ dnl Macros to check the presence of generic (non-typed) symbols. dnl Copyright (c) 2006-2008 Diego Pettenò dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2012 Lucas De Marchi dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -32,52 +33,28 @@ dnl distribute a modified version of the Autoconf Macro, you may extend dnl this special exception to the GPL to apply to your modified version as dnl well. -dnl Check if the flag is supported by compiler -dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) - -AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ - AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), - [ac_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $1" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], - [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], - [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) - CFLAGS="$ac_save_CFLAGS" - ]) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], - [$2], [$3]) -]) - -dnl Check if the flag is supported by compiler (cacheable) -dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) - -AC_DEFUN([CC_CHECK_CFLAGS], [ - AC_CACHE_CHECK([if $CC supports $1 flag], - AS_TR_SH([cc_cv_cflags_$1]), - CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! - ) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], - [$2], [$3]) -]) - -dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) -dnl Check for CFLAG and appends them to CFLAGS if supported -AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ - AC_CACHE_CHECK([if $CC supports $1 flag], - AS_TR_SH([cc_cv_cflags_$1]), - CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! - ) - - AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], - [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) +dnl Check if FLAG in ENV-VAR is supported by compiler and append it +dnl to WHERE-TO-APPEND variable +dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG]) + +AC_DEFUN([CC_CHECK_FLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], + AS_TR_SH([cc_cv_$2_$3]), + [eval "AS_TR_SH([cc_save_$2])='${$2}'" + eval "AS_TR_SH([$2])='-Werror $3'" + AC_LINK_IFELSE([AC_LANG_SOURCE([int a = 0; int main(void) { return a; } ])], + [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], + [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) + eval "AS_TR_SH([$2])='$cc_save_$2'"]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], + [eval "$1='${$1} $3'"]) ]) -dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) -AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ - for flag in $1; do - CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) +dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2]) +AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ + for flag in $3; do + CC_CHECK_FLAG_APPEND($1, $2, $flag) done ]) @@ -115,10 +92,10 @@ AC_DEFUN([CC_NOUNDEFINED], [ dnl for a much more readable commandline, so that people can understand what dnl it does without going to look for what the heck -z defs does. for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do - CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) - break + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break done - ;; + ;; esac AC_SUBST([LDFLAGS_NOUNDEFINED]) @@ -254,8 +231,8 @@ AC_DEFUN([CC_FLAG_VISIBILITY], [ [cc_flag_visibility_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $cc_cv_werror" CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], - cc_cv_flag_visibility='yes', - cc_cv_flag_visibility='no') + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') CFLAGS="$cc_flag_visibility_save_CFLAGS"]) AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], @@ -275,7 +252,7 @@ AC_DEFUN([CC_FUNC_EXPECT], [ [int some_function() { int a = 3; return (int)__builtin_expect(a, 3); - }])], + }])], [cc_cv_func_expect=yes], [cc_cv_func_expect=no]) CFLAGS="$ac_save_CFLAGS" diff --git a/m4/gtk-doc.m4 b/m4/gtk-doc.m4 new file mode 100644 index 0000000..0ada151 --- /dev/null +++ b/m4/gtk-doc.m4 @@ -0,0 +1,67 @@ +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_REQUIRE([PKG_PROG_PKG_CONFIG]) + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + + dnl check for tools we added during development + AC_PATH_PROG([GTKDOC_CHECK],[gtkdoc-check]) + AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true]) + AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf]) + + dnl for overriding the documentation installation directory + AC_ARG_WITH([html-dir], + AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST([HTML_DIR]) + + dnl enable/disable documentation building + AC_ARG_ENABLE([gtk-doc], + AS_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [[default=no]]]),, + [enable_gtk_doc=no]) + + if test x$enable_gtk_doc = xyes; then + ifelse([$1],[], + [PKG_CHECK_EXISTS([gtk-doc],, + AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))], + [PKG_CHECK_EXISTS([gtk-doc >= $1],, + AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build $PACKAGE_NAME]))]) + dnl don't check for glib if we build glib + if test "x$PACKAGE_NAME" != "xglib"; then + dnl don't fail if someone does not have glib + PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,) + fi + fi + + AC_MSG_CHECKING([whether to build gtk-doc documentation]) + AC_MSG_RESULT($enable_gtk_doc) + + dnl enable/disable output formats + AC_ARG_ENABLE([gtk-doc-html], + AS_HELP_STRING([--enable-gtk-doc-html], + [build documentation in html format [[default=yes]]]),, + [enable_gtk_doc_html=yes]) + AC_ARG_ENABLE([gtk-doc-pdf], + AS_HELP_STRING([--enable-gtk-doc-pdf], + [build documentation in pdf format [[default=no]]]),, + [enable_gtk_doc_pdf=no]) + + if test -z "$GTKDOC_MKPDF"; then + enable_gtk_doc_pdf=no + fi + + + AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes]) + AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"]) + AM_CONDITIONAL([GTK_DOC_USE_REBASE], [test -n "$GTKDOC_REBASE"]) +]) diff --git a/m4/libgcrypt.m4 b/m4/libgcrypt.m4 new file mode 100644 index 0000000..831dc0c --- /dev/null +++ b/m4/libgcrypt.m4 @@ -0,0 +1,123 @@ +dnl Autoconf macros for libgcrypt +dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. +dnl +dnl This file is free software; as a special exception the author gives +dnl unlimited permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl +dnl This file is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. +dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed +dnl with the API version to also check the API compatibility. Example: +dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed +dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using +dnl this features allows to prevent build against newer versions of libgcrypt +dnl with a changed API. +dnl +AC_DEFUN([AM_PATH_LIBGCRYPT], +[ AC_ARG_WITH(libgcrypt-prefix, + AC_HELP_STRING([--with-libgcrypt-prefix=PFX], + [prefix where LIBGCRYPT is installed (optional)]), + libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") + if test x$libgcrypt_config_prefix != x ; then + if test x${LIBGCRYPT_CONFIG+set} != xset ; then + LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config + fi + fi + + AC_PATH_TOOL(LIBGCRYPT_CONFIG, libgcrypt-config, no) + tmp=ifelse([$1], ,1:1.2.0,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_libgcrypt_api=0 + min_libgcrypt_version="$tmp" + fi + + AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) + ok=no + if test "$LIBGCRYPT_CONFIG" != "no" ; then + req_major=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_libgcrypt_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` + major=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + minor=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + micro=`echo $libgcrypt_config_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` + if test "$major" -gt "$req_major"; then + ok=yes + else + if test "$major" -eq "$req_major"; then + if test "$minor" -gt "$req_minor"; then + ok=yes + else + if test "$minor" -eq "$req_minor"; then + if test "$micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + AC_MSG_RESULT([yes ($libgcrypt_config_version)]) + else + AC_MSG_RESULT(no) + fi + if test $ok = yes; then + # If we have a recent libgcrypt, we should also check that the + # API is compatible + if test "$req_libgcrypt_api" -gt 0 ; then + tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + AC_MSG_CHECKING([LIBGCRYPT API version]) + if test "$req_libgcrypt_api" -eq "$tmp" ; then + AC_MSG_RESULT([okay]) + else + ok=no + AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp]) + fi + fi + fi + fi + if test $ok = yes; then + LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` + LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` + ifelse([$2], , :, [$2]) + if test x"$host" != x ; then + libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none` + if test x"$libgcrypt_config_host" != xnone ; then + if test x"$libgcrypt_config_host" != x"$host" ; then + AC_MSG_WARN([[ +*** +*** The config script $LIBGCRYPT_CONFIG was +*** built for $libgcrypt_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-libgcrypt-prefix +*** to specify a matching config script. +***]]) + fi + fi + fi + else + LIBGCRYPT_CFLAGS="" + LIBGCRYPT_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(LIBGCRYPT_CFLAGS) + AC_SUBST(LIBGCRYPT_LIBS) +]) diff --git a/man/.gitignore b/man/.gitignore index b127cf1..bf5eeab 100644 --- a/man/.gitignore +++ b/man/.gitignore @@ -1,2 +1,4 @@ -systemd.special.7.in -systemd.special.html.in +/systemd.directives.xml +/systemd.index.xml +/*.[13578] +/custom-entities.ent diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml index 966778d..6f8668b 100644 --- a/man/binfmt.d.xml +++ b/man/binfmt.d.xml @@ -7,19 +7,19 @@ Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + binfmt.d @@ -42,30 +42,32 @@ binfmt.d - Configure additional binary formats at boot + Configure additional binary formats for + executables at boot - /usr/lib/binfmt.d/*.conf /etc/binfmt.d/*.conf /run/binfmt.d/*.conf + /usr/lib/binfmt.d/*.conf Description - systemd uses - files from the above directories to configure - additional binary formats to register during boot in - the kernel. + At boot, + systemd-binfmt.service8 + reads configuration files from the above directories + to register in the kernel additional binary + formats for executables. - Configuration Format + Configuration Format Each file contains a list of binfmt_misc kernel binary format rules. Consult binfmt_misc.txt + url="https://www.kernel.org/doc/Documentation/binfmt_misc.txt">binfmt_misc.txt for more information on registration of additional binary formats and how to write rules. @@ -73,21 +75,30 @@ ignored. Note that this means you may not use ; and # as delimiter in binary format rules. - Each configuration file is named in the style of - <program>.conf. - Files in /etc/ overwrite - files with the same name in /usr/lib/. - Files in /run overwrite files with - the same name in /etc/ and - /usr/lib/. Packages should install their - configuration files in /usr/lib/, files - in /etc/ are reserved for the local - administration, which possibly decides to overwrite the - configurations installed from packages. All files are sorted - by filename in alphabetical order, regardless in which of the - directories they reside, to ensure that a specific - configuration file takes precedence over another file with - an alphabetically later name. + Each configuration file shall be named in the + style of program.conf. + Files in /etc/ override files + with the same name in /usr/lib/ + and /run/. Files in + /run/ override files with the + same name in /usr/lib/. Packages + should install their configuration files in + /usr/lib/, files in + /etc/ are reserved for the local + administrator, who may use this logic to override the + configuration files installed from vendor + packages. All files are sorted by their filename in + lexicographic order, regardless of which of the + directories they reside in. If multiple files specify + the same binary type name, the entry in the file with + the lexicographically latest name will be applied. + + If the administrator wants to disable a + configuration file supplied by the vendor, the + recommended way is to place a symlink to + /dev/null in + /etc/binfmt.d/ bearing the + same filename. @@ -104,6 +115,8 @@ See Also systemd1, + systemd-binfmt.service8, + systemd-delta1, wine8 diff --git a/man/bootchart.conf.xml b/man/bootchart.conf.xml new file mode 100644 index 0000000..68834c7 --- /dev/null +++ b/man/bootchart.conf.xml @@ -0,0 +1,164 @@ + + + + + + + + + bootchart.conf + systemd + + + + Developer + Auke + Kok + auke-jan.h.kok@intel.com + + + + + + bootchart.conf + 5 + + + + bootchart.conf + Boot performance analysis graphing tool configuration file + + + + /etc/systemd/bootchart.conf + + + + Description + + When starting, systemd-bootchart will read the + configuration file bootchart.conf. + This configuration file determines logging parameters and + graph output. + + + + + Options + + + + + Samples=500 + Configure the amount of samples to + record in total before bootchart exits. Each sample will + record at intervals defined by Frequency=. + + + + Frequency=25 + Configure the sample log frequency. + This can be a fractional number, but must be larger than + 0.0. Most systems can cope with values under 25-50 without + impacting boot time severely. + + + + Relative=no + Configures whether the left axis of the + output graph equals time=0.0 (CLOCK_MONOTONIC start). This + is useful for using bootchart at post-boot time to profile + an already booted system, otherwise the graph would become + extremely large. If set to yes, the horizontal axis starts + at the first recorded sample instead of time=0.0. + + + + + Filter=no + Configures whether the resulting graph + should omit tasks that did not contribute significantly + to the boot. Processes that are too short-lived (only + seen in one sample) or that do not consume any significant + CPU time (less than 0.001sec) will not be displayed in + the output graph. + + + + Output=[path] + Configures the output directory for writing + the graphs. By default, bootchart writes the graphs to + /run/log. + + + + Init=[path] + Configures bootchart to run a non-standard + binary instead of /sbin/init. This + option is only relevant if bootchart was invoked from the + kernel command line with + init=/usr/lib/systemd/systemd-bootchart. + + + + PlotMemoryUsage=no + If set to yes, enables logging and graphing + of processes' PSS memory consumption. + + + + PlotEntropyGraph=no + If set to yes, enables logging and graphing + of the kernel random entropy pool size. + + + + ScaleX=100 + Horizontal scaling factor for all variable + graph components. + + + + ScaleY=20 + Vertical scaling factor for all variable + graph components. + + + + ControlGroup=no + Display process control group. + + + + + + + See Also + + systemd-bootchart1, + systemd.directives7 + + + + diff --git a/man/bootctl.xml b/man/bootctl.xml new file mode 100644 index 0000000..5f19847 --- /dev/null +++ b/man/bootctl.xml @@ -0,0 +1,114 @@ + + + + + + + + + bootctl + systemd + + + + Developer + Kay + Sievers + kay@vrfy.org + + + + + + bootctl + 1 + + + + bootctl + Control the firmware and boot manager settings + + + + + bootctl + OPTIONS + COMMAND + + + + + Description + + bootctl may be used to + query or (in the future) change the firmware and boot + manager settings. + + Firmware information is available only on EFI + systems. + + Currently, only the gummiboot8 boot + manager implements the required boot loader interface + to provide complete boot manager information. + + + + Options + + The following options are understood: + + + + + + + The following commands are understood: + + + + status + + Show firmware and boot + manager information about the system, + including secure boot mode status and + selected firmware entry (where + available). + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + Boot loader interface, + Boot loader specification, + gummiboot + + + + diff --git a/man/bootup.xml b/man/bootup.xml new file mode 100644 index 0000000..65c2cee --- /dev/null +++ b/man/bootup.xml @@ -0,0 +1,318 @@ + + + + + + + + + bootup + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + bootup + 7 + + + + bootup + System bootup process + + + + Description + + 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 + dracut8, + which looks for the root file system (possibly using + systemd1 + for this). After the root file system is found and + mounted, the initrd hands over control to the host's + system manager (such as + systemd1) + stored on the OS image, which is then responsible for + probing all remaining hardware, mounting all necessary + file systems and spawning all configured + services. + + On shutdown, the system manager stops all + services, unmounts all file systems (detaching the + storage technologies backing them), and then + (optionally) jumps back into the initrd code which + unmounts/detaches the root file system and the storage + it resides on. As a last step, the system is powered down. + + Additional information about the system boot + process may be found in + boot7. + + + + System Manager Bootup + + At boot, the system manager on the OS image is + responsible for initializing the required file + systems, services and drivers that are necessary for + operation of the system. On + systemd1 + systems, this process is split up in various discrete + steps which are exposed as target units. (See + systemd.target5 + for detailed information about target units.) The + boot-up process is highly parallelized so that the + order in which specific target units are reached is not + deterministic, but still adheres to a limited amount + of ordering structure. + + When systemd starts up the system, it will + activate all units that are dependencies of + default.target (as well as + recursively all dependencies of these + dependencies). Usually, + default.target is simply an alias + of graphical.target or + multi-user.target, depending on + whether the system is configured for a graphical UI or + only for a text console. To enforce minimal ordering + between the units pulled in, a number of well-known + target units are available, as listed on + systemd.special7. + + The following chart is a structural overview of + these well-known units and their position in the + boot-up logic. The arrows describe which units are + pulled in and ordered before which other units. Units + near the top are started before units nearer to the + bottom of the chart. + +local-fs-pre.target + | + v +(various mounts and (various swap (various cryptsetup + fsck services...) devices...) devices...) (various low-level (various low-level + | | | services: udevd, API VFS mounts: + v v v tmpfiles, random mqueue, configfs, + local-fs.target swap.target cryptsetup.target seed, sysctl, ...) debugfs, ...) + | | | | | + \__________________|_________________ | ___________________|____________________/ + \|/ + v + sysinit.target + | + ____________________________________/|\________________________________________ + / | | | \ + | | | | | + v v | v v + (various (various | (various rescue.service + timers...) paths...) | sockets...) | + | | | | v + v v | v rescue.target + timers.target paths.target | sockets.target + | | | | + \__________________|_________________ | ___________________/ + \|/ + v + basic.target + | + ____________________________________/| emergency.service + / | | | + | | | v + v v v emergency.target + display- (various system (various system + manager.service services services) + | required for | + | graphical UIs) v + | | multi-user.target + | | | + \_________________ | _________________/ + \|/ + v + graphical.target + + Target units that are commonly used as boot + targets are emphasized. These + units are good choices as goal targets, for + example by passing them to the + systemd.unit= kernel command line + option (see + systemd1) + or by symlinking default.target + to them. + + + + Bootup in the Initial RAM Disk (initrd) + The initial RAM disk implementation (initrd) can + be set up using systemd as well. In this case, boot up + inside the initrd follows the following + structure. + + The default target in the initrd is + initrd.target. The bootup process + begins identical to the system manager bootup (see + above) until it reaches + basic.target. From there, systemd + approaches the special target + initrd.target. If the root device + can be mounted at /sysroot, the + sysroot.mount unit becomes active + and initrd-root-fs.target is + reached. The service + initrd-parse-etc.service scans + /sysroot/etc/fstab for a possible + /usr mount point and additional + entries marked with the + x-initrd.mount option. All + entries found are mounted below + /sysroot, and + initrd-fs.target is reached. The + service initrd-cleanup.service + isolates to the + initrd-switch-root.target, where + cleanup services can run. As the very last step, the + initrd-switch-root.service is + activated, which will cause the system to switch its + root to /sysroot. + + + : (beginning identical to above) + : + v + basic.target + | emergency.service + ______________________/| | + / | v + | sysroot.mount emergency.target + | | + | v + | initrd-root-fs.target + | | + | v + v initrd-parse-etc.service + (custom initrd | + services...) v + | (sysroot-usr.mount and + | various mounts marked + | with fstab option + | x-initrd.mount...) + | | + | v + | initrd-fs.target + \______________________ | + \| + v + initrd.target + | + v + initrd-cleanup.service + isolates to + initrd-switch-root.target + | + v + ______________________/| + / v + | initrd-udevadm-cleanup-db.service + v | + (custom initrd | + services...) | + \______________________ | + \| + v + initrd-switch-root.target + | + v + initrd-switch-root.service + | + v + Transition to Host OS + + + + + System Manager Shutdown + + System shutdown with systemd also consists of + various target units with some minimal ordering + structure applied: + + + + + (conflicts with (conflicts with + all system all file system + services) mounts, swaps, + | cryptsetup + | devices, ...) + | | + v v + shutdown.target umount.target + | | + \_______ ______/ + \ / + v + (various low-level + services) + | + v + final.target + | + _____________________________________/ \_________________________________ + / | | \ + | | | | + v v v v +systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service + | | | | + v v v v + reboot.target poweroff.target halt.target kexec.target + + Commonly used system shutdown targets are emphasized. + + + + See Also + + systemd1, + boot7, + systemd.special7, + systemd.target5, + dracut8 + + + + diff --git a/man/busctl.xml b/man/busctl.xml new file mode 100644 index 0000000..9865b17 --- /dev/null +++ b/man/busctl.xml @@ -0,0 +1,197 @@ + + + + + + + + + busctl + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + busctl + 1 + + + + busctl + Introspect the bus + + + + + busctl + OPTIONS + COMMAND + NAME + + + + + Description + + busctl may be used to + introspect and monitor the D-Bus bus. + + + + Options + + The following options are understood: + + + + + + Connect to the bus specified by + ADDRESS instead of using suitable + defaults for either the system or user bus (see + and + options). + + + + + + When showing the list of endpoints, show a + column containing the names of containers they belong to. + See + systemd-machined.service8. + + + + + + + When showing the list of endpoints, show + only "unique" names (of the form + :number.number). + + + + + + + The opposite of — + only "well-known" names will be shown. + + + + + + When showing the list of endpoints, show + only endpoints which have actually not been activated yet, + but may be started automatically if accessed. + + + + + + + When showing messages being exchanged, show only the + subset matching MATCH. + + + + + + + + Do not print the legend, + i.e. the column headers and the + footer. + + + + + + + + + + + + + + + + Commands + + The following commands are understood: + + + + list + + Show endpoints attached to the bus. This is + the default if no command is specified. + + + + monitor NAME + + Dump messages being exchanged. If + NAME is specified, show messages + to or from this endpoint. Otherwise, show all messages on the + bus. + + + + status NAME + + Show process information and credentials of a + bus endpoint. + + + + help + + Show command syntax help. + + + + + + See Also + + + dbus-daemon1, + D-Bus, + kdbus, + sd-bus3, + systemd1, + systemd-bus-proxyd8, + machinectl1 + + + diff --git a/man/crypttab.xml b/man/crypttab.xml new file mode 100644 index 0000000..668e51d --- /dev/null +++ b/man/crypttab.xml @@ -0,0 +1,388 @@ + + + + + + + + crypttab + systemd + + + + Documentation + Miloslav + Trmac + mitr@redhat.com + + + Documentation + Lennart + Poettering + lennart@poettering.net + + + + + + crypttab + 5 + + + + crypttab + Configuration for encrypted block devices + + + + /etc/crypttab + + + + Description + + The /etc/crypttab file + describes encrypted block devices that are set up + during system boot. + + Empty lines and lines starting with the # + character are ignored. Each of the remaining lines + describes one encrypted block device, fields on the + line are delimited by white space. The first two + fields are mandatory, the remaining two are + optional. + + Setting up encrypted block devices using this file + supports three encryption modes: LUKS, TrueCrypt and plain. + See cryptsetup8 + for more information about each mode. When no mode is specified + in the options field and the block device contains a LUKS + signature, it is opened as a LUKS device; otherwise, it is + assumed to be in raw dm-crypt (plain mode) format. + + The first field contains the name of the + resulting encrypted block device; the device is set up + within /dev/mapper/. + + The second field contains a path to the + underlying block device or file, or a specification of a block + device via UUID= followed by the + UUID. + + The third field specifies the encryption + password. If the field is not present or the password + is set to none or -, + the password has to be manually entered during system boot. + Otherwise, the field is interpreted as a absolute path to + a file containing the encryption password. For swap encryption, + /dev/urandom or the hardware + device /dev/hw_random can be used + as the password file; using + /dev/random may prevent boot + completion if the system does not have enough entropy + to generate a truly random encryption key. + + The fourth field, if present, is a + comma-delimited list of options. The following + options are recognized: + + + + + discard + + Allow discard requests to be + passed through the encrypted block device. This + improves performance on SSD storage but has + security implications. + + + + cipher= + + Specifies the cipher to use. See + cryptsetup8 + for possible values and the default value of + this option. A cipher with unpredictable IV + values, such as aes-cbc-essiv:sha256, + is recommended. + + + + hash= + + Specifies the hash to use for + password hashing. See + cryptsetup8 + for possible values and the default value of + this option. + + + + keyfile-offset= + + Specifies the number of bytes to + skip at the start of the key file. See + cryptsetup8 + for possible values and the default value of + this option. + + + + keyfile-size= + + Specifies the maximum number + of bytes to read from the key file. See + cryptsetup8 + for possible values and the default value of + this option. This option is ignored in plain + encryption mode, as the key file size is then + given by the key size. + + + + key-slot= + + Specifies the key slot to + compare the passphrase or key against. + If the key slot does not match the given + passphrase or key, but another would, the + setup of the device will fail regardless. + This option implies luks. See + cryptsetup8 + for possible values. The default is to try + all key slots in sequential order. + + + + luks + + Force LUKS mode. When this mode + is used, the following options are ignored since + they are provided by the LUKS header on the + device: cipher=, + hash=, + size=. + + + + noauto + + This device will not be + automatically unlocked on boot. + + + + nofail + + The system will not wait for the + device to show up and be unlocked at boot, and + not fail the boot if it does not show up. + + + + plain + + Force plain encryption mode. + + + + read-onlyreadonly + + Set up the encrypted block + device in read-only mode. + + + + size= + + Specifies the key size + in bits. See + cryptsetup8 + for possible values and the default value of + this option. + + + + swap + + The encrypted block device will + be used as a swap device, and will be formatted + accordingly after setting up the encrypted + block device, with + mkswap8. + This option implies plain. + + WARNING: Using the swap + option will destroy the contents of the named + partition during every boot, so make sure the + underlying block device is specified correctly. + + + + tcrypt + + Use TrueCrypt encryption mode. + When this mode is used, the following options are + ignored since they are provided by the TrueCrypt + header on the device or do not apply: + cipher=, + hash=, + keyfile-offset=, + keyfile-size=, + size=. + + When this mode is used, the passphrase is + read from the key file given in the third field. + Only the first line of this file is read, + excluding the new line character. + + Note that the TrueCrypt format uses both + passphrase and key files to derive a password + for the volume. Therefore, the passphrase and + all key files need to be provided. Use + tcrypt-keyfile= to provide + the absolute path to all key files. When using + an empty passphrase in combination with one or + more key files, use /dev/null + as the password file in the third field. + + + + tcrypt-hidden + + Use the hidden TrueCrypt volume. + This option implies tcrypt. + + This will map the hidden volume that is + inside of the volume provided in the second + field. Please note that there is no protection + for the hidden volume if the outer volume is + mounted instead. See + cryptsetup8 + for more information on this limitation. + + + + tcrypt-keyfile= + + Specifies the absolute path to a + key file to use for a TrueCrypt volume. This + implies tcrypt and can be + used more than once to provide several key + files. + + See the entry for tcrypt + on the behavior of the passphrase and key files + when using TrueCrypt encryption mode. + + + + tcrypt-system + + Use TrueCrypt in system + encryption mode. This option implies + tcrypt. + + + + timeout= + + Specifies the timeout for + querying for a password. If no unit is + specified, seconds is used. Supported units are + s, ms, us, min, h, d. A timeout of 0 waits + indefinitely (which is the default). + + + + tmp + + The encrypted block device will + be prepared for using it as /tmp; + it will be formatted using + mke2fs8. + This option implies plain. + + WARNING: Using the tmp + option will destroy the contents of the named + partition during every boot, so make sure the + underlying block device is specified correctly. + + + + tries= + + Specifies the maximum number of + times the user is queried for a password. + The default is 3. If set to 0, the user is + queried for a password indefinitely. + + + + verify + + If the encryption password is + read from console, it has to be entered twice to + prevent typos. + + + + + At early boot and when the system manager + configuration is reloaded, this file is translated into + native systemd units + by systemd-cryptsetup-generator8. + + + + Example + + /etc/crypttab example + Set up four encrypted block devices. One using + LUKS for normal storage, another one for usage as a swap + device and two TrueCrypt volumes. + + luks UUID=2505567a-9e27-4efe-a4d5-15ad146c258b +swap /dev/sda7 /dev/urandom swap +truecrypt /dev/sda2 /etc/container_password tcrypt +hidden /mnt/tc_hidden /null tcrypt-hidden,tcrypt-keyfile=/etc/keyfile + + + + + See Also + + systemd1, + systemd-cryptsetup@.service8, + systemd-cryptsetup-generator8, + cryptsetup8, + mkswap8, + mke2fs8 + + + + diff --git a/man/custom-html.xsl b/man/custom-html.xsl new file mode 100644 index 0000000..060af2e --- /dev/null +++ b/man/custom-html.xsl @@ -0,0 +1,184 @@ + + + + + + + + + + + + + .html + + + + + + + +

+ + + + + + + headerlink + + + Permalink to this headline + + + # + + + ¶ + +

+
+ + +

+ + + + + + + headerlink + + + Permalink to this headline + + + # + + + ¶ + +

+
+ + +
+ + + + + + + + + + + headerlink + + + Permalink to this term + + + + # + + + + + + + ¶ + +
+
+ +
+
+ + + + + + + + + index.html + + Index + · + + + systemd.directives.html + + Directives + · + + + ../python-systemd/index.html + + Python + · + + + ../libudev/index.html + + libudev + · + + + ../libudev/index.html + + gudev + + + + systemd + + +
+
+ + + " + + " + + + + + +
diff --git a/man/custom-man.xsl b/man/custom-man.xsl new file mode 100644 index 0000000..e1b8d36 --- /dev/null +++ b/man/custom-man.xsl @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + .TH " + + + + + + " " + + " "" "systemd + + " " + + " + + + + + + + + " + + " + + + diff --git a/man/daemon.xml b/man/daemon.xml index 997ee5b..88dd082 100644 --- a/man/daemon.xml +++ b/man/daemon.xml @@ -8,16 +8,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,7 +44,7 @@ daemon - Writing and Packaging System Daemons + Writing and packaging system daemons @@ -74,12 +74,12 @@ Close all open file - descriptors except STDIN, STDOUT, - STDERR (i.e. the first three file + descriptors except stdin, stdout, + stderr (i.e. the first three file descriptors 0, 1, 2). This ensures that no accidentally passed file descriptor stays around in the daemon - process. On Linux this is best + process. On Linux, this is best implemented by iterating through /proc/self/fd, with a fallback of iterating from file @@ -92,7 +92,7 @@ best done by iterating through the available signals up to the limit of _NSIG and resetting them to - SIG_DFL. + SIG_DFL. Reset the signal mask using @@ -115,21 +115,21 @@ In the child, call fork() again, to - ensure the daemon can never re-acquire + ensure that the daemon can never re-acquire a terminal again. Call exit() in the first child, so that only the second child (the actual daemon process) stays around. This ensures that the - daemon process is reparented to + daemon process is re-parented to init/PID 1, as all daemons should be. In the daemon process, connect /dev/null - to STDIN, STDOUT, - STDERR. + to standard input, output, and error. + In the daemon process, reset the umask to 0, so that the file @@ -150,15 +150,15 @@ getpid()) to a PID file, for example /var/run/foobar.pid - (for a hypothetical daemon "foobar"), + (for a hypothetical daemon "foobar") to ensure that the daemon cannot be started more than once. This must be implemented in race-free fashion so that the PID file is only updated when - at the same time it is verified that + it is verified at the same time that the PID previously stored in the PID file no longer exists or belongs to a - foreign process. Commonly some kind of + foreign process. Commonly, some kind of file locking is employed to implement this logic. @@ -167,7 +167,7 @@ applicable. From the daemon - process notify the original process + process, notify the original process started that initialization is complete. This can be implemented via an unnamed pipe or similar @@ -181,11 +181,11 @@ exit() in the original process. The process that invoked the daemon must be able to - rely that this + rely on that this exit() happens after initialization is complete and all external communication channels - established and + are established and accessible. @@ -196,8 +196,8 @@ compatibility with SysV systems should implement the scheme pointed out above. However, it is recommended to make this - behaviour optional and configurable via a - command line argument, to ease debugging as + behavior optional and configurable via a + command line argument to ease debugging as well as to simplify integration into systems using systemd. @@ -211,37 +211,38 @@ runtime and simplifies their implementation. - For developing a new-style daemon none + For developing a new-style daemon, none of the initialization steps recommended for SysV daemons need to be implemented. New-style init systems such as systemd make all of them redundant. Moreover, since some of these steps interfere with process monitoring, file descriptor passing and other functionality of - the init system it is recommended not to + the init system, it is recommended not to execute them when run as new-style service. Note that new-style init systems - guarantee execution of daemon processes in - clean process contexts: it is guaranteed that + guarantee execution of daemon processes in a + clean process context: it is guaranteed that the environment block is sanitized, that the signal handlers and mask is reset and that no left-over file descriptors are passed. Daemons - will be executed in their own session, and - STDIN/STDOUT/STDERR connected to + will be executed in their own session, with + standard input/output/error connected to /dev/null unless - otherwise configured. The umask is reset. + otherwise configured. The umask is reset. + It is recommended for new-style daemons to implement the following: - If SIGTERM is + If SIGTERM is received, shut down the daemon and exit cleanly. - If SIGHUP is received, + If SIGHUP is received, reload the configuration files, if this applies. @@ -256,7 +257,7 @@ scripts. If possible and - applicable expose the daemon's control + applicable, expose the daemon's control interface via the D-Bus IPC system and grab a bus name as last step of initialization. @@ -271,10 +272,10 @@ for details. As much as possible, - rely on the init systemd's + rely on the init system's functionality to limit the access of the daemon to files, services and - other resources. i.e. in the case of + other resources, i.e. in the case of systemd, rely on systemd's resource limit control instead of implementing your own, rely on systemd's privilege @@ -285,7 +286,7 @@ controls. If D-Bus is used, make - your daemon bus-activatable, via + your daemon bus-activatable by supplying a D-Bus service activation configuration file. This has multiple advantages: your daemon may be started @@ -293,7 +294,7 @@ parallel to other daemons requiring it -- which maximizes parallelization and boot-up speed; your daemon can be - restarted on failure, without losing + restarted on failure without losing any bus requests, as the bus queues requests for activatable services. See below for details. @@ -304,17 +305,17 @@ socket, it should be made socket-activatable following the scheme pointed out below. Like D-Bus - activation this enables on-demand + activation, this enables on-demand starting of services as well as it allows improved parallelization of service start-up. Also, for state-less - protocols (such as syslog, DNS) a + protocols (such as syslog, DNS), a daemon implementing socket-based activation can be restarted without losing a single request. See below for details. - If applicable a daemon + If applicable, a daemon should notify the init system about startup completion or status updates via the @@ -324,10 +325,10 @@ Instead of using the syslog() call to log directly to the system syslog service, a new-style daemon may - choose to simply log to STDERR via + choose to simply log to standard error via fprintf(), which is then forwarded to syslog by the init system. If log - priorities are necessary these can be + priorities are necessary, these can be encoded by prefixing individual log lines with strings like "<4>" (for log priority 4 "WARNING" in the @@ -343,9 +344,9 @@ kind of logging may be enabled by setting StandardError=syslog - in the service unit file. For details + in the service unit file. For details, see - sd-daemon7 + sd-daemon3 and systemd.exec5. @@ -374,9 +375,9 @@ when a printer is plugged in, or when a file is queued in the printer spool directory. Even for services that are intended to be started on system bootup - unconditionally it is a good idea to implement some of + unconditionally, it is a good idea to implement some of the various activation schemes outlined below, in - order to maximize parallelization: if a daemon + order to maximize parallelization. If a daemon implements a D-Bus service or listening socket, implementing the full bus and socket activation scheme allows starting of the daemon with its clients in @@ -384,7 +385,7 @@ communication channels are established already, and no request is lost because client requests will be queued by the bus system (in case of D-Bus) or the kernel (in - case of sockets), until the activation is + case of sockets) until the activation is completed. @@ -399,7 +400,7 @@ Specification. This method of activation is supported ubiquitously on Linux init systems, both old-style and new-style - systems. Among other issues SysV init scripts + systems. Among other issues, SysV init scripts have the disadvantage of involving shell scripts in the boot process. New-style init systems generally employ updated versions of @@ -408,8 +409,8 @@ description files. In systemd, if the developer or - administrator wants to make sure a service or - other unit is activated automatically on boot + administrator wants to make sure that a service or + other unit is activated automatically on boot, it is recommended to place a symlink to the unit file in the .wants/ directory of either @@ -434,25 +435,25 @@ recommended for all new-style daemons that communicate via listening sockets to employ socket-based activation. In a socket-based - activation scheme the creation and binding of + activation scheme, the creation and binding of the listening socket as primary communication channel of daemons to local (and sometimes remote) clients is moved out of the daemon code and into the init system. Based on - per-daemon configuration the init system + per-daemon configuration, the init system installs the sockets and then hands them off to the spawned process as soon as the respective daemon is to be started. - Optionally activation of the service can be + Optionally, activation of the service can be delayed until the first inbound traffic - arrives at the socket, to implement on-demand + arrives at the socket to implement on-demand activation of daemons. However, the primary advantage of this scheme is that all providers and all consumers of the sockets can be started in parallel as soon as all sockets - are established. In addition to that daemons + are established. In addition to that, daemons can be restarted with losing only a minimal - number of client transactions or even any + number of client transactions, or even any client request at all (the latter is particularly true for state-less protocols, such as DNS or syslog), because the socket @@ -462,16 +463,16 @@ New-style daemons which support socket activation must be able to receive their - sockets from the init system, instead of of + sockets from the init system instead of creating and binding them themselves. For details about the programming interfaces for - this scheme provided by systemd see + this scheme provided by systemd, see sd_listen_fds3 and - sd-daemon7. For + sd-daemon3. For details about porting existing daemons to - socket-based activation see below. With - minimal effort it is possible to implement + socket-based activation, see below. With + minimal effort, it is possible to implement socket-based activation in addition to traditional internal socket creation in the same codebase in order to support both @@ -483,20 +484,20 @@ units, which are described in systemd.socket5. When configuring socket units for socket-based - activation it is essential that all listening + activation, it is essential that all listening sockets are pulled in by the special target unit sockets.target. It is recommended to place a WantedBy=sockets.target directive in the [Install] - section, to automatically add such a + section to automatically add such a dependency on installation of a socket unit. Unless DefaultDependencies=no is - set the necessary ordering dependencies are + set, the necessary ordering dependencies are implicitly created for all socket units. For more information about - sockets.target see + sockets.target, see systemd.special7. It is not necessary or recommended to place any additional dependencies on socket units (for @@ -518,16 +519,16 @@ service files (not to be confused with systemd service unit files!). To ensure that D-Bus uses systemd to start-up and maintain the - daemon use the + daemon, use the SystemdService= directive - in these service files, to configure the + in these service files to configure the matching systemd service for a D-Bus - service. e.g.: for a D-Bus service whose D-Bus + service. e.g.: For a D-Bus service whose D-Bus activation file is named org.freedesktop.RealtimeKit.service, make sure to set SystemdService=rtkit-daemon.service - in that file, to bind it to the systemd + in that file to bind it to the systemd service rtkit-daemon.service. This is needed to make sure that the daemon is @@ -542,23 +543,23 @@ type of hardware should be activated only when the hardware of the respective kind is plugged in or otherwise becomes available. In a - new-style init system it is possible to bind + new-style init system, it is possible to bind activation to hardware plug/unplug events. In systemd, kernel devices appearing in the sysfs/udev device tree can be exposed as units if they are tagged with the string - "systemd". Like any other - kind of unit they may then pull in other units - when activated (i.e. Plugged in) and thus - implement device-based activation. Systemd + systemd. Like any other + kind of unit, they may then pull in other units + when activated (i.e. plugged in) and thus + implement device-based activation. systemd dependencies may be encoded in the udev database via the SYSTEMD_WANTS= property. See systemd.device5 - for details. Often it is nicer to pull in + for details. Often, it is nicer to pull in services from devices only indirectly via - dedicated targets. Example: instead of pulling + dedicated targets. Example: Instead of pulling in bluetoothd.service from all the various bluetooth dongles and other hardware available, pull in @@ -610,10 +611,10 @@ Other forms of activation have been suggested and implemented in some - systems. However, often there are simpler or + systems. However, there are often simpler or better alternatives, or they can be put together of combinations of the schemes - above. Example: sometimes it appears useful to + above. Example: Sometimes, it appears useful to start daemons or .socket units when a specific IP address is configured on a network interface, because network @@ -634,7 +635,7 @@ service activation is low system load. However, here too, a more convincing approach might be to make proper use of - features of the operating system: in + features of the operating system, in particular, the CPU or IO scheduler of Linux. Instead of scheduling jobs from userspace based on monitoring the OS @@ -668,7 +669,7 @@ suggestions: - If possible do not use + If possible, do not use the Type=forking setting in service files. But if you do, make sure to set the PID file path @@ -711,15 +712,15 @@ information for the unit file. See systemd.unit5 for details. To activate your service - on boot make sure to add a + on boot, make sure to add a WantedBy=multi-user.target or WantedBy=graphical.target directive. To activate your socket on boot, make sure to add - WantedBy=sockets.target. Usually + WantedBy=sockets.target. Usually, you also want to make sure that when - your service is installed your socket + your service is installed, your socket is installed too, hence add Also=foo.socket in your service file @@ -735,12 +736,12 @@ At the build installation time (e.g. make install during - package build) packages are recommended to + package build), packages are recommended to install their systemd unit files in the directory returned by pkg-config systemd --variable=systemdsystemunitdir (for - system services), resp. pkg-config + system services) or pkg-config systemd --variable=systemduserunitdir (for user services). This will make the @@ -748,12 +749,12 @@ request but not activate them automatically during boot. Optionally, during package installation (e.g. rpm -i - by the administrator) symlinks should be + by the administrator), symlinks should be created in the systemd configuration directories via the enable command of the systemctl1 - tool, to activate them automatically on + tool to activate them automatically on boot. Packages using @@ -765,12 +766,19 @@ PKG_PROG_PKG_CONFIG AC_ARG_WITH([systemdsystemunitdir], - AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), - [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) -if test "x$with_systemdsystemunitdir" != xno; then - AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) -fi -AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) + [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],, + [with_systemdsystemunitdir=auto]) +AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [ + def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) + + AS_IF([test "x$def_systemdsystemunitdir" = "x"], + [AS_IF([test "x$with_systemdsystemunitdir" = "xyes"], + [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])]) + with_systemdsystemunitdir=no], + [with_systemdsystemunitdir="$def_systemdsystemunitdir"])]) +AS_IF([test "x$with_systemdsystemunitdir" != "xno"], + [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) +AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"]) This snippet allows automatic installation of the unit files on systemd @@ -801,48 +809,49 @@ endif In the rpm8 - .spec file use a snippet like - the following to enable/disable the service - during installation/deinstallation. Consult + .spec file, use snippets + like the following to enable/disable the + service during + installation/deinstallation. This makes use of + the RPM macros shipped along systemd. Consult the packaging guidelines of your distribution for details and the equivalent for other - package managers: + package managers. - %post -if [ $1 -eq 1 ]; then - # On install (not upgrade), enable (but don't start) the - # units by default - /bin/systemctl enable foobar.service foobar.socket >/dev/null 2>&1 || : + At the top of the file: + + BuildRequires: systemd +%{?systemd_requires} - # Alternatively, just call - # /bin/systemctl daemon-reload >/dev/null 2>&1 || : - # here, if the daemon should not be enabled by default on - # installation -fi + And as scriptlets, further down: + + %post +%systemd_post foobar.service foobar.socket %preun -if [ $1 -eq 0 ]; then - # On uninstall (not upgrade), disable and stop the units - /bin/systemctl --no-reload disable foobar.service foobar.socket >/dev/null 2>&1 || : - /bin/systemctl stop foobar.service foobar.socket >/dev/null 2>&1 || : -fi +%systemd_preun foobar.service foobar.socket %postun -# Reload init system configuration, to make systemd honour changed -# or deleted unit files -/bin/systemctl daemon-reload >/dev/null 2>&1 || : -if [ $1 -ge 1 ] ; then - # On upgrade (not uninstall), optionally, restart the daemon - /bin/systemctl try-restart foobar.service >/dev/null 2>&1 || : -fi - - Depending on whether your service should - or should not be started/stopped/restarted - during package installation, deinstallation or - upgrade, a different set of commands may be - specified. See - systemctl1 - for details. +%systemd_postun + + If the service shall be restarted during + upgrades, replace the + %postun scriptlet above + with the following: + + %postun +%systemd_postun_with_restart foobar.service + + Note that + %systemd_post and + %systemd_preun expect the + names of all units that are installed/removed + as arguments, separated by + spaces. %systemd_postun + expects no + arguments. %systemd_postun_with_restart + expects the units to restart as + arguments. To facilitate upgrades from a package version that shipped only SysV init scripts to @@ -858,7 +867,7 @@ fi Where 0.47.11-1 is the first package version that includes the native unit file. This fragment will ensure that the first - time the unit file is installed it will be + time the unit file is installed, it will be enabled if and only if the SysV init script is enabled, thus making sure that the enable status is not changed. Note that @@ -874,13 +883,13 @@ fi Porting Existing Daemons Since new-style init systems such as systemd are - compatible with traditional SysV init systems it is + compatible with traditional SysV init systems, it is not strictly necessary to port existing daemons to the - new style. However doing so offers additional + new style. However, doing so offers additional functionality to the daemons as well as simplifying integration into new-style init systems. - To port an existing SysV compatible daemon the + To port an existing SysV compatible daemon, the following steps are recommended: @@ -893,9 +902,9 @@ fi If the daemon offers interfaces to other software running on the - local system via local AF_UNIX sockets, + local system via local AF_UNIX sockets, consider implementing socket-based activation - (see above). Usually a minimal patch is + (see above). Usually, a minimal patch is sufficient to implement this: Extend the socket creation in the daemon code so that sd_listen_fds3 @@ -904,8 +913,8 @@ fi sd_listen_fds() returns a positive value), skip the socket creation step and use the passed sockets. Secondly, ensure - that the file-system socket nodes for local - AF_UNIX sockets used in the socket-based + that the file system socket nodes for local + AF_UNIX sockets used in the socket-based activation are not removed when the daemon shuts down, if sockets have been passed. Third, if the daemon normally closes @@ -937,7 +946,7 @@ fi See Also systemd1, - sd-daemon7, + sd-daemon3, sd_listen_fds3, sd_notify3, daemon3, diff --git a/man/halt.xml b/man/halt.xml index 97a53ba..d3b686e 100644 --- a/man/halt.xml +++ b/man/halt.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + halt @@ -80,15 +81,14 @@ - Prints a short help - text and exits. + Halt the machine, - regardless which one of the three + regardless of which one of the three commands is invoked. @@ -97,7 +97,7 @@ Power-off the machine, - regardless which one of the three + regardless of which one of the three commands is invoked. @@ -105,7 +105,7 @@ Reboot the machine, - regardless which one of the three + regardless of which one of the three commands is invoked. @@ -114,7 +114,7 @@ Force immediate halt, - power-off, reboot. Don't contact the + power-off, reboot. Do not contact the init system. @@ -123,7 +123,7 @@ Only write wtmp - shutdown entry, don't actually halt, + shutdown entry, do not actually halt, power-off, reboot. @@ -131,23 +131,14 @@ - Don't write wtmp + Do not write wtmp shutdown entry. - - - - Don't sync hard disks/storage media before - halt, power-off, - reboot. - - - - Don't send wall + Do not send wall message before halt, power-off, reboot. @@ -157,7 +148,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. diff --git a/man/hostname.xml b/man/hostname.xml index b8b05c8..a8648c5 100644 --- a/man/hostname.xml +++ b/man/hostname.xml @@ -9,22 +9,22 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - /etc/hostname + hostname systemd @@ -44,7 +44,7 @@ hostname - Local host name configuration file + Local hostname configuration file @@ -56,20 +56,25 @@ The /etc/hostname file configures the name of the local system that is set - during boot, with the + during boot using the sethostname2 system call. It should contain a single - newline-terminated host name string. The - host name may be a free-form string up to 64 characters - in length, however it is recommended that it consists - only of 7bit ASCII lower-case characters and no spaces or dots, + newline-terminated hostname string. The + hostname may be a free-form string up to 64 characters + in length; however, it is recommended that it consists + only of 7-bit ASCII lower-case characters and no spaces or dots, and limits itself to the format allowed for DNS domain name labels, even though this is not a strict requirement. - Depending on the operating system other + Depending on the operating system, other configuration files might be checked for configuration - of the host name as well, however only as fallback. + of the hostname as well, however only as fallback. + + You may use + hostnamectl1 + to change the value of this file from the command + line. @@ -86,9 +91,11 @@ systemd1, sethostname2, hostname1, - hostname5, + hostname7, machine-id5, - machine-info5 + machine-info5, + hostnamectl1, + systemd-hostnamed.service8 diff --git a/man/hostnamectl.xml b/man/hostnamectl.xml new file mode 100644 index 0000000..6746a70 --- /dev/null +++ b/man/hostnamectl.xml @@ -0,0 +1,253 @@ + + + + + + + + + hostnamectl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + hostnamectl + 1 + + + + hostnamectl + Control the system hostname + + + + + hostnamectl + OPTIONS + COMMAND + + + + + Description + + hostnamectl may be used to + query and change the system hostname and related + settings. + + This tool distinguishes three different + hostnames: the high-level "pretty" hostname which + might include all kinds of special characters + (e.g. "Lennart's Laptop"), the static hostname which + is used to initialize the kernel hostname at boot + (e.g. "lennarts-laptop"), and the transient hostname + which might be assigned temporarily due to network + configuration and might revert back to the static + hostname if network connectivity is lost and is only + temporarily written to the kernel hostname + (e.g. "dhcp-47-11"). + + Note that the pretty hostname has little + restrictions on the characters used, while the static + and transient hostnames are limited to the usually + accepted characters of Internet domain names. + + The static hostname is stored in + /etc/hostname, see + hostname5 + for more information. The pretty hostname, chassis + type, and icon name are stored in + /etc/machine-info, see + machine-id5. + + + + Options + + The following options are understood: + + + + + + Do not query the user + for authentication for privileged + operations. + + + + + + + Acquire privileges via PolicyKit + before executing the operation. + + + + + + + + If + status is used (or + no explicit command is given) and one + of those fields is given, + hostnamectl will + print out just this selected + hostname. + + If used with + set-hostname, only + the selected hostname(s) will be + updated. When more than one of those + options is used, all the specified + hostnames will be updated. + + + + + + + + + + The following commands are understood: + + + + status + + Show current system + hostname and related + information. + + + + set-hostname [NAME] + + Set the system + hostname. By default, this will alter + the pretty, the static, and the + transient hostname alike; however, if + one or more of + , + , + are used, + only the selected hostnames are + changed. If the pretty hostname is + being set, and static or transient are + being set as well, the specified + hostname will be simplified in regards + to the character set used before the + latter are updated. This is done by + replacing spaces with + - and removing + special characters. This ensures that + the pretty and the static hostname are + always closely related while still + following the validity rules of the + specific name. This simplification of + the hostname string is not done if + only the transient and/or static host + names are set, and the pretty host + name is left untouched. Pass the empty + string as the + hostname to reset the selected + hostnames to their default (usually + localhost). + + + + set-icon-name [NAME] + + Set the system icon + name. The icon name is used by some + graphical applications to visualize + this host. The icon name should follow + the Icon + Naming Specification. Pass an + empty string to this operation to + reset the icon name to the default + value, which is determined from chassis + type (see below) and possibly other + parameters. + + + + set-chassis [TYPE] + + Set the chassis + type. The chassis type is used by some + graphical applications to visualize + the host or alter user + interaction. Currently, the following + chassis types are defined: + desktop, + laptop, + server, + tablet, + handset, as well as + the special chassis types + vm and + container for + virtualized systems that lack an + immediate physical chassis. Pass an + empty string to this operation to + reset the chassis type to the default + value which is determined from the + firmware and possibly other + parameters. + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + hostname1, + hostname5, + machine-info5, + systemctl1, + systemd-hostnamed.service8 + + + + diff --git a/man/journalctl.xml b/man/journalctl.xml new file mode 100644 index 0000000..78fc6f6 --- /dev/null +++ b/man/journalctl.xml @@ -0,0 +1,916 @@ + + + + + + + + + journalctl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + journalctl + 1 + + + + journalctl + Query the systemd journal + + + + + journalctl + OPTIONS + MATCHES + + + + + Description + + journalctl may be used to + query the contents of the + systemd1 + journal as written by + systemd-journald.service8. + + If called without parameters, it will show the full + contents of the journal, starting with the oldest + entry collected. + + If one or more match arguments are passed, the + output is filtered accordingly. A match is in the + format FIELD=VALUE, + e.g. _SYSTEMD_UNIT=httpd.service, + referring to the components of a structured journal + entry. See + systemd.journal-fields7 + for a list of well-known fields. If multiple matches + are specified matching different fields, the log + entries are filtered by both, i.e. the resulting output + will show only entries matching all the specified + matches of this kind. If two matches apply to the same + field, then they are automatically matched as + alternatives, i.e. the resulting output will show + entries matching any of the specified matches for the + same field. Finally, if the character + + appears as a separate word on the + command line, all matches before and after are combined + in a disjunction (i.e. logical OR). + + As shortcuts for a few types of field/value + matches, file paths may be specified. If a file path + refers to an executable file, this is equivalent to an + _EXE= match for the canonicalized + binary path. Similarly, if a path refers to a device + node, this is equivalent to a + _KERNEL_DEVICE= match for the + device. + + Output is interleaved from all accessible + journal files, whether they are rotated or currently + being written, and regardless of whether they belong to the + system itself or are accessible user journals. + + All users are granted access to their private + per-user journals. However, by default, only root and + users who are members of the systemd-journal + group get access to the system journal and the + journals of other users. + + The output is paged through + less by default, and long lines are + "truncated" to screen width. The hidden part can be + viewed by using the left-arrow and right-arrow + keys. Paging can be disabled; see the + option and the "Environment" + section below. + + When outputing to a tty, lines are colored + according to priority: lines of level ERROR and higher + are colored red; lines of level NOTICE and higher are + highlighted; other lines are displayed normally. + + + + + Options + + The following options are understood: + + + + + + + + Ellipsize fields when + they do not fit in available columns. + The default is to show full fields, + allowing them to wrap or be truncated + by the pager, if one is used. + + The old options + / + are not useful anymore, except to undo + . + + + + + + + Show all fields in + full, even if they include unprintable + characters or are very + long. + + + + + + + Show only the most recent + journal entries, and continuously print + new entries as they are appended to + the journal. + + + + + + + Immediately jump to + the end of the journal inside the + implied pager tool. This implies + to guarantee + that the pager will not buffer logs of + unbounded size. This may be overridden + with an explicit + with some other numeric value on the + command line. Note that this option is + only supported for the + less1 + pager. + + + + + + + Show the most recent + journal events and limit the number of + events shown. If + is used, + this option is implied. The argument, + a positive integer, is optional, and + defaults to 10. + + + + + + Show all stored output + lines, even in follow mode. Undoes the + effect of + . + + + + + + + Reverse output so that the newest + entries are displayed first. + + + + + + + Controls the + formatting of the journal entries that + are shown. Takes one of the following options: + + + + + + + + is the default + and generates an output + that is mostly identical + to the formatting of + classic syslog files, + showing one line per + journal entry. + + + + + + + + + is very similar, + but shows ISO 8601 + wallclock timestamps. + + + + + + + + + + is very similar, + but shows timestamps + with full microsecond + precision. + + + + + + + + + + is very similar, + but shows monotonic + timestamps instead of + wallclock timestamps. + + + + + + + + + + shows the + full-structured entry + items with all fields. + + + + + + + + + + serializes the + journal into a binary + (but mostly text-based) + stream suitable for + backups and network + transfer (see Journal + Export Format + for more + information). + + + + + + + + + formats entries + as JSON data structures, + one per line (see Journal + JSON Format for + more information). + + + + + + + + + formats entries as + JSON data structures, + but formats them in + multiple lines in order + to make them more + readable by humans. + + + + + + + + + formats entries as + JSON data structures, + but wraps them in a + format suitable for Server-Sent + Events. + + + + + + + + + generates a very + terse output, only + showing the actual + message of each journal + entry with no metadata, + not even a timestamp. + + + + + + + + + + + + Augment log lines with + explanation texts from the message + catalog. This will add explanatory + help texts to log messages in the + output where this is available. These + short help texts will explain the + context of an error or log event, + possible solutions, as well as + pointers to support forums, developer + documentation, and any other relevant + manuals. Note that help texts are not + available for all messages, but only + for selected ones. For more + information on the message catalog, + please refer to the Message + Catalog Developer + Documentation. + + Note: when attaching + journalctl output + to bug reports, please do + not use + . + + + + + + + + Suppresses any warning + messages regarding inaccessible system + journals when run as a normal + user. + + + + + + + Show entries + interleaved from all available + journals, including remote + ones. + + + + + + + Show messages from a specific + boot. This will add a match for + _BOOT_ID=. + + The argument may be empty, in which case + logs for the current boot will be shown. + + If the boot ID is omitted, a positive + offset will look up + the boots starting from the beginning of the + journal, and a equal-or-less-than zero + offset will look up + boots starting from the end of the + journal. Thus, 1 means the + first boot found in the journal in + chronological order, 2 the + second and so on; while -0 + is the last boot, -1 the + boot before last, and so on. An empty + offset is equivalent + to specifying -0, except + when the current boot is not the last boot + (e.g. because was + specified to look at logs from a different + machine). + + If the 32-character + ID is specified, it + may optionally be followed by + offset which + identifies the boot relative to the one given by + boot ID. Negative + values mean earlier boots and a positive values + mean later boots. If + offset is not + specified, a value of zero is assumed, and the + logs for the boot given by + ID are shown. + + + + + + + + + Show a tabular list of + boot numbers (relative to the current + boot), their IDs, and the timestamps + of the first and last message + pertaining to the boot. + + + + + + + + Show only kernel messages. This + implies and adds the match + _TRANSPORT=kernel. + + + + + + + + Show messages for the + specified systemd unit + UNIT, or + for any of the units matched by + PATTERN. + If a pattern is specified, a list of + unit names found in the journal is + compared with the specified pattern + and all that match are used. For each + unit name, a match is added for + messages from the unit + (_SYSTEMD_UNIT=UNIT), + along with additional matches for + messages from systemd and messages + about coredumps for the specified + unit. + + This parameter can be specified + multiple times. + + + + + + Show messages for the + specified user session unit. This will + add a match for messages from the unit + (_SYSTEMD_USER_UNIT= + and _UID=) and + additional matches for messages from + session systemd and messages about + coredumps for the specified unit. + This parameter can be specified multiple times. + + + + + + + + Filter output by + message priorities or priority + ranges. Takes either a single numeric + or textual log level (i.e. between + 0/emerg and + 7/debug), or a + range of numeric/text log levels in + the form FROM..TO. The log levels are + the usual syslog log levels as + documented in + syslog3, + i.e. emerg (0), + alert (1), + crit (2), + err (3), + warning (4), + notice (5), + info (6), + debug (7). If a + single log level is specified, all + messages with this log level or a + lower (hence more important) log level + are shown. If a range is specified, all + messages within the range are shown, + including both the start and the end + value of the range. This will add + PRIORITY= matches + for the specified + priorities. + + + + + + + Start showing entries + from the location in the journal + specified by the passed + cursor. + + + + + + Start showing entries + from the location in the journal + after the + location specified by the this cursor. + The cursor is shown when the + option + is used. + + + + + + The cursor is shown after the last + entry after two dashes: + -- cursor: s=0639... + The format of the cursor is private + and subject to change. + + + + + + + Start showing entries + on or newer than the specified date, + or on or older than the specified + date, respectively. Date specifications + should be of the format + 2012-10-30 18:17:16. + If the time part is omitted, + 00:00:00 is assumed. + If only the seconds component is omitted, + :00 is assumed. If the + date component is omitted, the current + day is assumed. Alternatively the strings + yesterday, + today, + tomorrow are + understood, which refer to 00:00:00 of + the day before the current day, the + current day, or the day after the + current day, respectively. now + refers to the current time. Finally, + relative times may be specified, + prefixed with - or + +, referring to + times before or after the current + time, respectively. + + + + + + + Print all possible + data values the specified field can + take in all entries of the + journal. + + + + + + + Show messages from + system services and the kernel (with + ). Show + messages from service of current user + (with ). + If neither is specified, show all + messages that the user can see. + + + + + + + + Show messages from a + running, local container. Specify a + container name to connect + to. + + + + + + + Takes a directory path + as argument. If specified, journalctl + will operate on the specified journal + directory + DIR instead + of the default runtime and system + journal paths. + + + + + + Takes a file glob as an + argument. If specified, journalctl will + operate on the specified journal files + matching GLOB + instead of the default runtime and + system journal paths. May be specified + multiple times, in which case files will + be suitably interleaved. + + + + + + Takes a directory path + as an argument. If specified, journalctl + will operate on catalog file hierarchy + underneath the specified directory + instead of the root directory + (e.g. + will create + ROOT/var/lib/systemd/catalog/database). + + + + + + + Instead of showing + journal contents, generate a new 128-bit + ID suitable for identifying + messages. This is intended for usage + by developers who need a new + identifier for a new message they + introduce and want to make + recognizable. This will print the new ID in + three different formats which can be + copied into source code or + similar. + + + + + + Instead of showing + journal contents, show internal header + information of the journal fields + accessed. + + + + + + Shows the current disk + usage of all + journal files. + + + + + + List the contents of + the message catalog as a table of + message IDs, plus their short + description strings. + + If any + 128-bit-IDs are + specified, only those entries are shown. + + + + + + + + Show the contents of + the message catalog, with entries + separated by a line consisting of two + dashes and the ID (the format is the + same as .catalog + files). + + If any + 128-bit-IDs are + specified, only those entries are shown. + + + + + + + + Update the message + catalog index. This command needs to + be executed each time new catalog + files are installed, removed, or + updated to rebuild the binary catalog + index. + + + + + + Instead of showing + journal contents, generate a new key + pair for Forward Secure Sealing + (FSS). This will generate a sealing + key and a verification key. The + sealing key is stored in the journal + data directory and shall remain on the + host. The verification key should be + stored externally. Refer to the + option in + journald.conf5 + for information on Forward Secure + Sealing and for a link to a refereed + scholarly paper detailing the + cryptographic theory it is based on. + + + + + + + When + is passed and + Forward Secure Sealing (FSS) has already been + configured, recreate FSS keys. + + + + + + Specifies the change + interval for the sealing key when + generating an FSS key pair with + . Shorter + intervals increase CPU consumption but + shorten the time range of + undetectable journal + alterations. Defaults to + 15min. + + + + + + Check the journal file + for internal consistency. If the + file has been generated with FSS + enabled and the FSS verification key + has been specified with + , + authenticity of the journal file is + verified. + + + + + + Specifies the FSS + verification key to use for the + + operation. + + + + + + + + + + Exit status + + On success, 0 is returned; otherwise, a non-zero + failure code is returned. + + + + + + Examples + + Without arguments, all collected logs are shown + unfiltered: + + journalctl + + With one match specified, all entries with a field matching the expression are shown: + + journalctl _SYSTEMD_UNIT=avahi-daemon.service + + If two different fields are matched, only entries matching both expressions at the same time are shown: + + journalctl _SYSTEMD_UNIT=avahi-daemon.service _PID=28097 + + If two matches refer to the same field, all entries matching either expression are shown: + + journalctl _SYSTEMD_UNIT=avahi-daemon.service _SYSTEMD_UNIT=dbus.service + + If the separator + is used, + two expressions may be combined in a logical OR. The + following will show all messages from the Avahi + service process with the PID 28097 plus all messages + from the D-Bus service (from any of its + processes): + + journalctl _SYSTEMD_UNIT=avahi-daemon.service _PID=28097 + _SYSTEMD_UNIT=dbus.service + + Show all logs generated by the D-Bus executable: + + journalctl /usr/bin/dbus-daemon + + Show all logs of the kernel device node /dev/sda: + + journalctl /dev/sda + + Show all kernel logs from previous boot: + + journalctl -k -b -1 + + + + + See Also + + systemd1, + systemd-journald.service8, + systemctl1, + systemd.journal-fields7, + journald.conf5 + + + + diff --git a/man/journald.conf.xml b/man/journald.conf.xml new file mode 100644 index 0000000..a814ec1 --- /dev/null +++ b/man/journald.conf.xml @@ -0,0 +1,469 @@ + + + + + + + + + journald.conf + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + journald.conf + 5 + + + + journald.conf + Journal service configuration file + + + + /etc/systemd/journald.conf + + + + Description + + This file configures various parameters of the + systemd journal service, + systemd-journald.service8. + + + + + Options + + All options are configured in the + [Journal] section: + + + + + Storage= + + Controls where to + store journal data. One of + volatile, + persistent, + auto and + none. If + volatile, journal + log data will be stored only in + memory, i.e. below the + /run/log/journal + hierarchy (which is created if + needed). If + persistent, data will + be stored preferably on disk, + i.e. below the + /var/log/journal + hierarchy (which is created if + needed), with a fallback to + /run/log/journal + (which is created if needed), during + early boot and if the disk is not + writable. auto is + similar to + persistent but the + directory + /var/log/journal + is not created if needed, so that its + existence controls where log data + goes. none turns + off all storage, all log data received + will be dropped. Forwarding to other + targets, such as the console, the + kernel log buffer or a syslog daemon + will still work however. Defaults to + auto. + + + + Compress= + + Takes a boolean + value. If enabled (the default), data + objects that shall be stored in the + journal and are larger than a certain + threshold are compressed with the XZ + compression algorithm before they are + written to the file + system. + + + + Seal= + + Takes a boolean + value. If enabled (the default), and a + sealing key is available (as created + by + journalctl1's + + command), Forward Secure Sealing (FSS) + for all persistent journal files is + enabled. FSS is based on Seekable + Sequential Key Generators by + G. A. Marson and B. Poettering + (doi:10.1007/978-3-642-40203-6_7) + and may be used to protect journal files + from unnoticed alteration. + + + + SplitMode= + + Controls whether to + split up journal files per user. One + of login, + uid and + none. If + login, each logged-in + user will get his own journal + files, but systemd user IDs will log + into the system journal. If + uid, any user ID + will get his own journal files + regardless of whether it belongs to a + system service or refers to a real + logged in user. If + none, journal files + are not split up by user and all + messages are instead stored in the single + system journal. Note that splitting + up journal files by user is only + available for journals stored + persistently. If journals are stored + on volatile storage (see above), only a + single journal file for all user IDs + is kept. Defaults to + login. + + + + RateLimitInterval= + RateLimitBurst= + + Configures the rate + limiting that is applied to all + messages generated on the system. If, + in the time interval defined by + RateLimitInterval=, + more messages than specified in + RateLimitBurst= are + logged by a service, all further + messages within the interval are + dropped until the interval is over. A + message about the number of dropped + messages is generated. This rate + limiting is applied per-service, so + that two services which log do not + interfere with each other's + limits. Defaults to 200 messages in + 10s. The time specification for + RateLimitInterval= + may be specified in the following + units: s, + min, + h, + ms, + us. To turn off any + kind of rate limiting, set either + value to 0. + + + + SystemMaxUse= + SystemKeepFree= + SystemMaxFileSize= + RuntimeMaxUse= + RuntimeKeepFree= + RuntimeMaxFileSize= + + Enforce size limits on + the journal files stored. The options + prefixed with + System apply to the + journal files when stored on a + persistent file system, more + specifically + /var/log/journal. The + options prefixed with + Runtime apply to + the journal files when stored on a + volatile in-memory file system, more + specifically + /run/log/journal. The + former is used only when + /var is mounted, + writable, and the directory + /var/log/journal + exists. Otherwise, only the latter + applies. Note that this means that + during early boot and if the + administrator disabled persistent + logging, only the latter options apply, + while the former apply if persistent + logging is enabled and the system is + fully booted + up. journalctl and + systemd-journald + ignore all files with names not ending + with .journal or + .journal~, so only + such files, located in the appropriate + directories, are taken into account + when calculating current disk usage. + + + SystemMaxUse= + and RuntimeMaxUse= + control how much disk space the + journal may use up at maximum. + SystemKeepFree= and + RuntimeKeepFree= + control how much disk space + systemd-journald shall leave free for + other uses. + systemd-journald + will respect both limits and use the + smaller of the two values. + + The first pair defaults to 10% + and the second to 15% of the size of + the respective file system. If the + file system is nearly full and either + SystemKeepFree= or + RuntimeKeepFree= is + violated when systemd-journald is + started, the value will be raised to + percentage that is actually free. This + means that if there was enough + free space before and journal files were + created, and subsequently something + else causes the file system to fill + up, journald will stop using more + space, but it will not be removing + existing files to go reduce footprint + either. + + SystemMaxFileSize= + and + RuntimeMaxFileSize= + control how large individual journal + files may grow at maximum. This + influences the granularity in which + disk space is made available through + rotation, i.e. deletion of historic + data. Defaults to one eighth of the + values configured with + SystemMaxUse= and + RuntimeMaxUse=, so + that usually seven rotated journal + files are kept as history. Specify + values in bytes or use K, M, G, T, P, + E as units for the specified sizes + (equal to 1024, 1024²,... bytes). + Note that size limits are enforced + synchronously when journal files are + extended, and no explicit rotation + step triggered by time is + needed. + + + + MaxFileSec= + + The maximum time to + store entries in a single journal + file before rotating to the next + one. Normally, time-based rotation + should not be required as size-based + rotation with options such as + SystemMaxFileSize= + should be sufficient to ensure that + journal files do not grow without + bounds. However, to ensure that not + too much data is lost at once when old + journal files are deleted, it might + make sense to change this value from + the default of one month. Set to 0 to + turn off this feature. This setting + takes time values which may be + suffixed with the units + year, + month, + week, day, + h or m + to override the default time unit of + seconds. + + + + MaxRetentionSec= + + The maximum time to + store journal entries. This + controls whether journal files + containing entries older then the + specified time span are + deleted. Normally, time-based deletion + of old journal files should not be + required as size-based deletion with + options such as + SystemMaxUse= + should be sufficient to ensure that + journal files do not grow without + bounds. However, to enforce data + retention policies, it might make sense + to change this value from the + default of 0 (which turns off this + feature). This setting also takes + time values which may be suffixed with + the units year, + month, + week, day, + h or m + to override the default time unit of + seconds. + + + + + SyncIntervalSec= + + The timeout before + synchronizing journal files to + disk. After syncing, journal files are + placed in the OFFLINE state. Note that + syncing is unconditionally done + immediately after a log message of + priority CRIT, ALERT or EMERG has been + logged. This setting hence applies + only to messages of the levels ERR, + WARNING, NOTICE, INFO, DEBUG. The + default timeout is 5 minutes. + + + + + ForwardToSyslog= + ForwardToKMsg= + ForwardToConsole= + + Control whether log + messages received by the journal + daemon shall be forwarded to a + traditional syslog daemon, to the + kernel log buffer (kmsg), or to the + system console. These options take + boolean arguments. If forwarding to + syslog is enabled but no syslog daemon + is running, the respective option has + no effect. By default, only forwarding + to syslog is enabled. These settings + may be overridden at boot time with + the kernel command line options + systemd.journald.forward_to_syslog=, + systemd.journald.forward_to_kmsg= + and + systemd.journald.forward_to_console=. + When forwarding to the console, the + TTY to log to can be changed + with TTYPath=, + described below. + + + + MaxLevelStore= + MaxLevelSyslog= + MaxLevelKMsg= + MaxLevelConsole= + + Controls the maximum + log level of messages that are stored + on disk, forwarded to syslog, kmsg or + the console (if that is enabled, see + above). As argument, takes one of + emerg, + alert, + crit, + err, + warning, + notice, + info, + debug or integer + values in the range of 0..7 (corresponding + to the same levels). Messages equal or below + the log level specified are + stored/forwarded, messages above are + dropped. Defaults to + debug for + MaxLevelStore= and + MaxLevelSyslog=, to + ensure that the all messages are + written to disk and forwarded to + syslog. Defaults to + notice for + MaxLevelKMsg= and + info for + MaxLevelConsole=. + + + + TTYPath= + + Change the console TTY + to use if + ForwardToConsole=yes + is used. Defaults to + /dev/console. + + + + + + + + See Also + + systemd1, + systemd-journald.service8, + journalctl1, + systemd.journal-fields7, + systemd-system.conf5 + + + + diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml new file mode 100644 index 0000000..afcff7c --- /dev/null +++ b/man/kernel-command-line.xml @@ -0,0 +1,330 @@ + + + + + + + + + kernel-command-line + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + kernel-command-line + 7 + + + + kernel-command-line + Kernel command line parameters + + + + /proc/cmdline + + + + Description + + The kernel, the initial RAM disk (initrd) and + basic userspace functionality may be configured at boot via + kernel command line arguments. + + For command line parameters understood by the + kernel, please see kernel-parameters.txt + and + bootparam7. + + For command line parameters understood by the + initial RAM disk, please see + dracut.cmdline7, + or the documentation of the specific initrd + implementation of your installation. + + + + Core OS Command Line Arguments + + + + systemd.unit= + rd.systemd.unit= + systemd.dump_core= + systemd.crash_shell= + systemd.crash_chvt= + systemd.confirm_spawn= + systemd.show_status= + systemd.log_target= + systemd.log_level= + systemd.log_color= + systemd.log_location= + systemd.default_standard_output= + systemd.default_standard_error= + systemd.setenv= + + Parameters understood by + the system and service manager + to control system behavior. For details, see + systemd1. + + + + + systemd.restore_state= + + This parameter is understood by + several system tools to control + whether or not they should restore + system state from the previous boot. + For details, see + systemd-backlight@.service8 + and + systemd-rfkill@.service8. + + + + + + quiet + + Parameter understood by + both the kernel and the system + and service manager to control + console log verbosity. For + details, see + systemd1. + + + + + debug + + Parameter understood by + both the kernel and the system + and service manager to control + console log verbosity. For + details, see + systemd1. + + + + + -b + emergency + single + s + S + 1 + 2 + 3 + 4 + 5 + + Parameters understood by + the system and service + manager, as compatibility + options. For details, see + systemd1. + + + + + locale.LANG= + locale.LANGUAGE= + locale.LC_CTYPE= + locale.LC_NUMERIC= + locale.LC_TIME= + locale.LC_COLLATE= + locale.LC_MONETARY= + locale.LC_MESSAGES= + locale.LC_PAPER= + locale.LC_NAME= + locale.LC_ADDRESS= + locale.LC_TELEPHONE= + locale.LC_MEASUREMENT= + locale.LC_IDENTIFICATION= + + Parameters understood by + the system and service manager + to control locale and language + settings. For details, see + systemd1. + + + + + fsck.mode= + + + Parameter understood by + the file system checker + services. For details, see + systemd-fsck@.service8. + + + + + quotacheck.mode= + + + Parameter understood by + the file quota checker + service. For details, see + systemd-quotacheck.service8. + + + + + systemd.journald.forward_to_syslog= + systemd.journald.forward_to_kmsg= + systemd.journald.forward_to_console= + + + Parameters understood by + the journal service. For + details, see + systemd-journald.service8. + + + + + vconsole.keymap= + vconsole.keymap.toggle= + vconsole.font= + vconsole.font.map= + vconsole.font.unimap= + + + Parameters understood by + the virtual console setup logic. For + details, see + systemd-vconsole-setup.service8. + + + + + udev.log-priority= + rd.udev.log-priority= + udev.children-max= + rd.udev.children-max= + udev.exec-delay= + rd.udev.exec-delay= + net.ifnames= + + + Parameters understood by + the device event managing daemon. For + details, see + systemd-udevd.service8. + + + + + plymouth.enable= + + + May be used to disable + the Plymouth boot splash. For + details, see + plymouth8. + + + + + luks= + rd.luks= + luks.crypttab= + rd.luks.crypttab= + luks.uuid= + rd.luks.uuid= + luks.options= + rd.luks.options= + luks.key= + rd.luks.key= + + + Configures the LUKS + full-disk encryption logic at + boot. For details, see + systemd-cryptsetup-generator8. + + + + + fstab= + rd.fstab= + + + Configures the + /etc/fstab + logic at boot. For details, see + systemd-fstab-generator8. + + + + + modules-load= + rd.modules-load= + + + Load a specific kernel + module early at boot. For + details, see + systemd-modules-load.service8. + + + + + + + + + See Also + + systemd1, + bootparam7, + dracut.cmdline7, + systemd-fsck@.service8, + systemd-quotacheck.service8, + systemd-journald.service8, + systemd-vconsole-setup.service8, + systemd-udevd.service8, + plymouth8, + systemd-cryptsetup-generator8, + systemd-fstab-generator8, + systemd-modules-load.service8 + systemd-backlight@.service8 + systemd-rfkill@.service8 + + + + diff --git a/man/kernel-install.xml b/man/kernel-install.xml new file mode 100644 index 0000000..3612b7d --- /dev/null +++ b/man/kernel-install.xml @@ -0,0 +1,185 @@ + + + + + + + + + kernel-install + systemd + + + + Developer + Harald + Hoyer + harald@redhat.com + + + + + + kernel-install + 8 + + + + kernel-install + Add and remove kernel and initramfs images to and from /boot + + + + + kernel-install + COMMAND + KERNEL-VERSION + KERNEL-IMAGE + + + + + Description + + kernel-install is used to install and remove kernel and + initramfs images to and from /boot. + + + kernel-install will execute the files + located in the directory /usr/lib/kernel/install.d/ + and the local administration directory /etc/kernel/install.d/. + All files are collectively sorted and executed in lexical order, regardless of the directory in + which they live. However, files with identical filenames replace each other. + Files in /etc/kernel/install.d/ take precedence over files with the same name + in /usr/lib/kernel/install.d/. This can be used to override a system-supplied + executables with a local file if needed; a symbolic link in /etc/kernel/install.d/ + with the same name as an executable in /usr/lib/kernel/install.d/, + pointing to /dev/null, disables the executable entirely. Executables must have the + extension .install; other extensions are ignored. + + + + + Commands + The following commands are understood: + + + add KERNEL-VERSION KERNEL-IMAGE + + kernel-install creates the directory + /boot/MACHINE-ID/KERNEL-VERSION/ + and calls every executable + /usr/lib/kernel/install.d/*.install and + /etc/kernel/install.d/*.install with + the arguments + add KERNEL-VERSION /boot/MACHINE-ID/KERNEL-VERSION/ + + + The kernel-install plugin 50-depmod.install runs depmod for the KERNEL-VERSION. + + The kernel-install plugin 90-loaderentry.install copies + KERNEL-IMAGE to + /boot/MACHINE-ID/KERNEL-VERSION/linux. + It also creates a boot loader entry according to the boot loader specification in + /boot/loader/entries/MACHINE-ID-KERNEL-VERSION.conf. + The title of the entry is the PRETTY_NAME parameter specified in /etc/os-release, + or "Linux KERNEL-VERSION", if unset. + If the file initrd is found next to the + linux file, the initrd will be added to + the configuration. + + + + remove KERNEL-VERSION + + Calls every executable /usr/lib/kernel/install.d/*.install + and /etc/kernel/install.d/*.install with the arguments + remove KERNEL-VERSION /boot/MACHINE-ID/KERNEL-VERSION/ + + + kernel-install removes the entire directory + /boot/MACHINE-ID/KERNEL-VERSION/ afterwards. + + The kernel-install plugin 90-loaderentry.install removes the file + /boot/loader/entries/MACHINE-ID-KERNEL-VERSION.conf. + + + + + + + + + Exit status + If every executable returns with 0, 0 is returned, a non-zero failure code otherwise. + + + + Files + + + + /usr/lib/kernel/install.d/*.install + /etc/kernel/install.d/*.install + + + Drop-in files which are executed by kernel-install. + + + + + /etc/kernel/cmdline + /proc/cmdline + + + The content of the file /etc/kernel/cmdline specifies the kernel command line to use. + If that file does not exist, /proc/cmdline is used. + + + + + /etc/machine-id + + + The content of the file specifies the machine identification MACHINE-ID. + + + + + /etc/os-release + + + The content of the file specifies the operating system title PRETTY_NAME. + + + + + + + See Also + + machine-id5, + os-release5, + Boot loader specification + + + + diff --git a/man/less-variables.xml b/man/less-variables.xml new file mode 100644 index 0000000..09cbd42 --- /dev/null +++ b/man/less-variables.xml @@ -0,0 +1,29 @@ + + + + + Environment + + + + $SYSTEMD_PAGER + + Pager to use when + is not given; + overrides $PAGER. Setting + this to an empty string or the value + cat is equivalent to passing + . + + + + $SYSTEMD_LESS + + Override the default + options passed to + less + (FRSXMK). + + + diff --git a/man/libsystemd-pkgconfig.xml b/man/libsystemd-pkgconfig.xml new file mode 100644 index 0000000..56a72e1 --- /dev/null +++ b/man/libsystemd-pkgconfig.xml @@ -0,0 +1,12 @@ + + + + + Notes + + These APIs are implemented as a shared + library, which can be compiled and linked to with the + libsystemd pkg-config1 + file. + diff --git a/man/locale.conf.xml b/man/locale.conf.xml index 3723997..e970921 100644 --- a/man/locale.conf.xml +++ b/man/locale.conf.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,7 +44,7 @@ locale.conf - configuration file for locale settings + Configuration file for locale settings @@ -55,14 +55,16 @@ Description The /etc/locale.conf file - configures system-wide locale settings. + configures system-wide locale settings. It is read at + early-boot by + systemd1. The basic file format of locale.conf is a newline-separated list of environment-like shell-compatible variable assignments. It is possible to source the configuration from shell scripts, - however, beyond mere variable assignments no shell + however, beyond mere variable assignments, no shell features are supported, allowing applications to read the file without implementing a shell compatible execution engine. @@ -90,7 +92,7 @@ overridden or unset by individual programs or individual users. - Depending on the operating system other + Depending on the operating system, other configuration files might be checked for locale configuration as well, however only as fallback. @@ -115,7 +117,7 @@ LC_TELEPHONE=, LC_MEASUREMENT=, LC_IDENTIFICATION=. Note that - LC_ALL may not be be configured in + LC_ALL may not be configured in this file. For details about the meaning and semantics of these settings, refer to locale7. @@ -127,10 +129,10 @@ German locale with English messages - /etc/locale.conf: + /etc/locale.conf: LANG=de_DE.UTF-8 -LC_MESSAGES=C +LC_MESSAGES=en_US.UTF-8 @@ -139,7 +141,8 @@ LC_MESSAGES=C See Also systemd1, - locale7 + locale7, + systemd-localed.service8 diff --git a/man/localectl.xml b/man/localectl.xml new file mode 100644 index 0000000..c2e79a2 --- /dev/null +++ b/man/localectl.xml @@ -0,0 +1,248 @@ + + + + + + + + + localectl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + localectl + 1 + + + + localectl + Control the system locale and keyboard layout settings + + + + + localectl + OPTIONS + COMMAND + + + + + Description + + localectl may be used to + query and change the system locale and keyboard layout + settings. + + The system locale controls the language settings + of system services and of the UI before the user logs + in, such as the display manager, as well as the + default for users after login. + + The keyboard settings control the keyboard + layout used on the text console and of the graphical + UI before the user logs in, such as the display + manager, as well as the default for users after + login. + + + + Options + + The following options are understood: + + + + + + Do not query the user + for authentication for privileged + operations. + + + + + + + Acquire privileges via PolicyKit + before executing the operation. + + + + + + If + set-keymap or + set-x11-keymap is + invoked and this option is passed, then + the keymap will not be converted from + the console to X11, or X11 to console, + respectively. + + + + + + + + + + The following commands are understood: + + + + status + + Show current settings + of the system locale and keyboard + mapping. + + + + set-locale LOCALE... + + Set the system + locale. This takes one or more + assignments such as "LANG=de_DE.utf8", + "LC_MESSAGES=en_GB.utf8", and so + on. See + locale7 + for details on the available settings + and their meanings. Use + list-locales for a + list of available locales (see below). + + + + + list-locales + + List available locales + useful for configuration with + set-locale. + + + + set-keymap MAP [TOGGLEMAP] + + Set the system + keyboard mapping for the console. This + takes a keyboard mapping name (such as + "de" or "us"), and possibly a second + one to define a toggle keyboard + mapping. Unless + is + passed, the selected setting is also + applied to the default keyboard + mapping of X11, after converting it to + the closest matching X11 keyboard + mapping. Use + list-keymaps for a + list of available keyboard mappings + (see below). + + + + list-keymaps + + List available + keyboard mappings for the console, + useful for configuration with + set-keymap. + + + + set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS] + + Set the system default + keyboard mapping for X11. This takes a + keyboard mapping name (such as "de" or + "us"), and possibly a model, variant + and options, see + kbd4 + for details. Unless + is + passed, the selected setting is also + applied to the system console keyboard + mapping, after converting it to the + closest matching console keyboard + mapping. + + + + list-x11-keymap-models + list-x11-keymap-layouts + list-x11-keymap-variants [LAYOUT] + list-x11-keymap-options + + List available X11 + keymap models, layouts, variants and + options, useful for configuration with + set-keymap. The + command + list-x11-keymap-variants + optionally takes a layout parameter to + limit the output to the variants + suitable for the specific + layout. + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + + + See Also + + systemd1, + locale7, + locale.conf5, + vconsole.conf5, + loadkeys1, + kbd4, + + The XKB Configuration Guide + , + systemctl1, + systemd-localed.service8 + + + + diff --git a/man/localtime.xml b/man/localtime.xml new file mode 100644 index 0000000..dbf2379 --- /dev/null +++ b/man/localtime.xml @@ -0,0 +1,103 @@ + + + + + + + + + localtime + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + Developer + Shawn + Landden + shawnlandden@gmail.com + + + + + + localtime + 5 + + + + localtime + Local timezone configuration file + + + + /etc/localtime -> ../usr/share/zoneinfo/… + + + + Description + + The /etc/localtime file + configures the system-wide timezone of the local + system that is used by applications for presentation + to the user. It should be an absolute or relative + symbolic link pointing to + /usr/share/zoneinfo/, followed by + a timezone identifier such as + Europe/Berlin or + Etc/UTC. The resulting link should + lead to the corresponding binary + tzfile5 + timezone data for the configured timezone. + + Because the timezone identifier is extracted from + the symlink target name of + /etc/localtime, this file may not + be a normal file or hardlink. + + The timezone may be overridden for individual + programs by using the TZ environment variable. See + environ7. + + You may use + timedatectl1 + to change the settings of this file from the command + line. + + + + See Also + + systemd1, + tzset3, + localtime3, + timedatectl1, + systemd-timedated.service8 + + + + diff --git a/man/loginctl.xml b/man/loginctl.xml new file mode 100644 index 0000000..749db92 --- /dev/null +++ b/man/loginctl.xml @@ -0,0 +1,453 @@ + + + + + + + + + loginctl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + loginctl + 1 + + + + loginctl + Control the systemd login manager + + + + + loginctl + OPTIONS + COMMAND + NAME + + + + + Description + + loginctl may be used to + introspect and control the state of the + systemd1 + login manager systemd-logind.service8. + + + + Options + + The following options are understood: + + + + + + + Do not print the legend, + i.e. the column headers and + the footer. + + + + + + + Do not query the user + for authentication for privileged + operations. + + + + + + + When showing + session/user/seat properties, limit + display to certain properties as + specified as argument. If not + specified, all set properties are + shown. The argument should be a + property name, such as + Sessions. If + specified more than once, all + properties with the specified names + are shown. + + + + + + + When showing + session/user/seat properties, show all + properties regardless of whether they are + set or not. + + + + + + + Do not ellipsize + process tree entries. + + + + + + + When used with + kill-session, + choose which processes to kill. Must + be one of , or + to select whether + to kill only the leader process of the + session or all processes of the + session. If omitted, defaults to + . + + + + + + + When used with + kill-session or + kill-user, choose + which signal to send to selected + processes. Must be one of the well + known signal specifiers, such as + SIGTERM, + SIGINT or + SIGSTOP. If + omitted, defaults to + SIGTERM. + + + + + + + + + + + The following commands are understood: + + + + list-sessions + + List current sessions. + + + + session-status ID... + + Show terse runtime + status information about one or more + sessions. This function is intended to + generate human-readable output. If you + are looking for computer-parsable + output, use + show-session + instead. + + + + show-session ID... + + Show properties of one + or more sessions or the manager + itself. If no argument is specified, + properties of the manager will be + shown. If a session ID is specified, + properties of the session are shown. By + default, empty properties are + suppressed. Use + to show those too. To select specific + properties to show, use + . This + command is intended to be used + whenever computer-parsable output is + required. Use + session-status if + you are looking for formatted + human-readable + output. + + + + activate ID... + + Activate one or more + sessions. This brings one or more + sessions into the foreground, if + another session is currently in the + foreground on the respective + seat. + + + + lock-session ID... + unlock-session ID... + + Activates/deactivates + the screen lock on one or more + sessions, if the session supports it. + + + + + lock-sessions + unlock-sessions + + Activates/deactivates + the screen lock on all current + sessions supporting it. + + + + + terminate-session ID... + + Terminates a session. + This kills all processes of the + session and deallocates all resources + attached to the session. + + + + + kill-session ID... + + Send a signal to one + or more processes of the session. Use + to select + which process to kill. Use + to select + the signal to send. + + + + list-users + + List currently logged + in users. + + + + user-status USER... + + Show terse runtime + status information about one or more + logged in users. This function is + intended to generate human-readable + output. If you are looking for + computer-parsable output, use + show-user instead. + Users may be specified by their + usernames or numeric user IDs. + + + + + show-user USER... + + Show properties of one + or more users or the manager + itself. If no argument is specified, + properties of the manager will be + shown. If a user is specified, + properties of the user are shown. By + default, empty properties are + suppressed. Use + to show those too. To select specific + properties to show, use + . This + command is intended to be used + whenever computer-parsable output is + required. Use + user-status if + you are looking for formatted + human-readable + output. + + + + enable-linger USER... + disable-linger USER... + + Enable/disable user + lingering for one or more users. If + enabled for a specific user, a user + manager is spawned for the user at + boot and kept around after + logouts. This allows users who are not + logged in to run long-running + services. + + + + terminate-user USER... + + Terminates all + sessions of a user. This kills all + processes of all sessions of the user + and deallocates all runtime resources + attached to the user. + + + + + kill-user USER... + + Send a signal to all + processes of a user. Use + to select + the signal to send. + + + + list-seats + + List currently + available seats on the local + system. + + + + seat-status NAME... + + Show terse runtime + status information about one or more + seats. This function is + intended to generate human-readable + output. If you are looking for + computer-parsable output, use + show-seat + instead. + + + + show-seat NAME... + + Show properties of one + or more seats or the manager + itself. If no argument is specified, + properties of the manager will be + shown. If a seat is specified, + properties of the seat are shown. By + default, empty properties are + suppressed. Use + to show those too. To select specific + properties to show, use + . This + command is intended to be used + whenever computer-parsable output is + required. Use + seat-status if you + are looking for formatted + human-readable + output. + + + + attach NAME DEVICE... + + Persistently attach + one or more devices to a seat. The + devices should be specified via device + paths in the /sys + file system. To create a new seat, + attach at least one graphics card to a + previously unused seat name. Seat + names may consist only of a-z, A-Z, + 0-9, - and + _ and must be + prefixed with seat. + To drop assignment of a device to a + specific seat, just reassign it to a + different seat, or use + flush-devices. + + + + + flush-devices + + Removes all device + assignments previously created with + attach. After this + call, only automatically generated + seats will remain, and all seat + hardware is assigned to + them. + + + + terminate-seat NAME... + + Terminates all + sessions on a seat. This kills all + processes of all sessions on the seat + and deallocates all runtime resources + attached to them. + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + + + See Also + + systemd1, + systemctl1, + systemd-logind.service8, + logind.conf5 + + + + diff --git a/man/logind.conf.xml b/man/logind.conf.xml new file mode 100644 index 0000000..54cc379 --- /dev/null +++ b/man/logind.conf.xml @@ -0,0 +1,307 @@ + + + + + + + + + logind.conf + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + logind.conf + 5 + + + + logind.conf + Login manager configuration file + + + + /etc/systemd/logind.conf + + + + Description + + This file configures various parameters of the systemd login manager, systemd-logind.service8. + + + + + Options + + All options are configured in the + [Login] section: + + + + + NAutoVTs= + + Takes a positive + integer. Configures how many virtual + terminals (VTs) to allocate by default + that, when switched to and are + previously unused, + autovt services are + automatically spawned on. These + services are instantiated from the + template unit + autovt@.service + for the respective VT TTY name, + e.g. autovt@tty4.service. By + default, + autovt@.service + is linked to + getty@.service, + i.e. login prompts are started + dynamically as the user switches to + unused virtual terminals. Hence, this + parameter controls how many login + gettys are + available on the VTs. If a VT is + already used by some other subsystem + (for example a graphical login), this + kind of activation will not be + attempted. Note that the VT configured + in ReserveVT= is + always subject to this kind of + activation, even if it is not one of + VTs configured with the + NAutoVTs= + directive. Defaults to 6. When set to + 0, automatic spawning of + autovt services is + disabled. + + + + ReserveVT= + + Takes a positive + integer. Configures the number of one + virtual terminal that shall + unconditionally be reserved for + autovt@.service + activation (see above). The VT + selected with this option will be + marked busy unconditionally, so that no + other subsystem will allocate it. This + functionality is useful to ensure that + regardless of how many VTs are allocated + by other subsystems, one login + getty is always + available. Defaults to 6 (in other + words, there will always be a + getty available on + Alt-F6.). When set to 0, VT + reservation is + disabled. + + + + KillUserProcesses= + + Takes a boolean + argument. Configures whether the + processes of a user should be killed + when she or he completely logs out (i.e. after + her/his last session ended). Defaults to + no. + + Note that setting + KillUserProcesses=1 + will break tools like + screen1. + + + + KillOnlyUsers= + KillExcludeUsers= + + These settings take + space-separated lists of usernames + that influence the effect of + KillUserProcesses=. If + not empty, only processes of users + listed in + KillOnlyUsers= will + be killed when they log out + entirely. Processes of users listed in + KillExcludeUsers= + are excluded from being + killed. KillExcludeUsers= + defaults to root + and takes precedence over + KillOnlyUsers=, + which defaults to the empty list. + + + + IdleAction= + + Configures the action + to take when the system is idle. Takes + one of ignore, + poweroff, + reboot, + halt, + kexec, + suspend, + hibernate, + hybrid-sleep, + lock. Defaults to + ignore. + + Note that this requires that + user sessions correctly report the + idle status to the system. The system + will execute the action after all + sessions report that they are idle, + no idle inhibitor lock is active, + and subsequently, the time configured + with IdleActionSec= + (see below) has expired. + + + + + IdleActionSec= + + Configures the delay + after which the action configured in + IdleAction= (see + above) is taken after the system is + idle. + + + + InhibitDelayMaxSec= + + Specifies the maximum + time a system shutdown or sleep + request is delayed due to an inhibitor + lock of type delay + being active before the inhibitor is + ignored and the operation executes + anyway. Defaults to + 5s. + + + + HandlePowerKey= + HandleSuspendKey= + HandleHibernateKey= + HandleLidSwitch= + + Controls whether + logind shall handle the system power + and sleep keys and the lid switch to + trigger actions such as system + power-off or suspend. Can be one of + ignore, + poweroff, + reboot, + halt, + kexec, + suspend, + hibernate, + hybrid-sleep and + lock. If + ignore, logind will + never handle these keys. If + lock, all running + sessions will be screen-locked; otherwise, + the specified action + will be taken in the respective + event. Only input devices with the + power-switch udev + tag will be watched for key/lid switch + events. HandlePowerKey= + defaults to + poweroff. + HandleSuspendKey= + and + HandleLidSwitch= + default to suspend. + HandleHibernateKey= + defaults to + hibernate. + + + + PowerKeyIgnoreInhibited= + SuspendKeyIgnoreInhibited= + HibernateKeyIgnoreInhibited= + LidSwitchIgnoreInhibited= + + Controls whether + actions triggered by the power and + sleep keys and the lid switch are + subject to inhibitor locks. These + settings take boolean arguments. If + off, the inhibitor + locks taken by applications in order + to block the requested operation are + respected. If on, + the requested operation is executed in + any + case. PowerKeyIgnoreInhibited=, + SuspendKeyIgnoreInhibited= + and + HibernateKeyIgnoreInhibited= + default to off. + LidSwitchIgnoreInhibited= + defaults to + yes. This means + that the lid switch does not respect + suspend blockers by default, but the + power and sleep keys do. + + + + + + + + See Also + + systemd1, + systemd-logind.service8, + loginctl1, + systemd-system.conf5 + + + + diff --git a/man/machine-id.xml b/man/machine-id.xml index 6ca9990..4b4759e 100644 --- a/man/machine-id.xml +++ b/man/machine-id.xml @@ -9,22 +9,22 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - /etc/machine-id + machine-id systemd @@ -44,7 +44,7 @@ machine-id - local machine ID configuration file + Local machine ID configuration file @@ -55,32 +55,37 @@ Description The /etc/machine-id file - contains the unique machine id of the local system + contains the unique machine ID of the local system that is set during installation. The machine ID is a - single newline-terminated, hexadecimal, lowercase 32 - character machine ID string. (When decoded from - hexadecimal this corresponds with a 16 byte/128 bit - string.) + single newline-terminated, hexadecimal, 32-character, + lowercase machine ID string. When decoded from + hexadecimal, this corresponds with a 16-byte/128-bit + string. The machine ID is usually generated from a random source during system installation and stays constant for all subsequent boots. Optionally, for - stateless systems it is generated during runtime at + stateless systems, it is generated during runtime at boot if it is found to be empty. The machine ID does not change based on user - configuration, or when hardware is replaced. + configuration or when hardware is replaced. This machine ID adheres to the same format and logic as the D-Bus machine ID. Programs may use this ID to identify the host - with a globally unique ID in the network, that does + with a globally unique ID in the network, which does not change even if the local network configuration - changes. Due to this and its greater length it is + changes. Due to this and its greater length, it is a more useful replacement for the gethostid3 - call POSIX specifies. + call that POSIX specifies. + + The + systemd-machine-id-setup1 + tool may be used by installer tools to initialize the + machine ID at install time. @@ -88,9 +93,9 @@ Note that the machine ID historically is not an OSF UUID as defined by RFC - 4122, nor a Microsoft GUID. Starting with - systemd v30 newly generated machine IDs however do + url="https://tools.ietf.org/html/rfc4122">RFC + 4122, nor a Microsoft GUID; however, starting with + systemd v30, newly generated machine IDs do qualify as v4 UUIDs. In order to maintain compatibility with existing @@ -108,7 +113,7 @@ id[8] = (id[8] & 0x3F) | 0x80; (This code is inspired by generate_random_uuid() of drivers/char/random.c from the - kernel sources.) + Linux kernel sources.) @@ -118,7 +123,7 @@ id[8] = (id[8] & 0x3F) | 0x80; The simple configuration file format of /etc/machine-id originates in the /var/lib/dbus/machine-id file - introduced by D-Bus. In fact this latter file might be a + introduced by D-Bus. In fact, this latter file might be a symlink to /etc/machine-id. @@ -127,10 +132,13 @@ id[8] = (id[8] & 0x3F) | 0x80; See Also systemd1, + systemd-machine-id-setup1, gethostid3, hostname5, machine-info5, - os-release5 + os-release5, + sd-id1283, + sd_id128_get_machine3 diff --git a/man/machine-info.xml b/man/machine-info.xml index c6d3e92..7448e68 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -55,7 +55,7 @@ Description The /etc/machine-info file - contains machine meta data. + contains machine metadata. The basic file format of machine-info is a @@ -68,18 +68,23 @@ execution engine. /etc/machine-info contains - meta data about the machine that is set by the user or + metadata about the machine that is set by the user or administrator. Depending on the operating system other configuration files might be checked for machine information as well, however only as fallback. + + You may use + hostnamectl1 + to change the settings of this file from the command + line. Options - The following machine meta data parameters may + The following machine metadata parameters may be set using /etc/machine-info: @@ -89,22 +94,22 @@ PRETTY_HOSTNAME= A pretty - human-readable UTF8 machine identifier + human-readable UTF-8 machine identifier string. This should contain a name like Lennart's Laptop which is useful to present to the user and does not suffer by the syntax limitations of - internet domain names. If possible the - internet host name as configured in + internet domain names. If possible, the + internet hostname as configured in /etc/hostname should be kept similar to this one. Example: if this value is Lennart's Computer - an Internet host name of + an Internet hostname of lennarts-computer might be a good choice. If this - parameter is not set an application + parameter is not set, an application should fall back to the Internet host name for presentation purposes. @@ -117,12 +122,40 @@ this machine according to the XDG Icon Naming Specification. If - this parameter is not set an + this parameter is not set, an application should fall back to computer or a similar icon name. + + CHASSIS= + + The chassis + type. Currently, the following chassis + types are defined: + desktop, + laptop, + server, + tablet, + handset, as well as + the special chassis types + vm and + container for + virtualized systems that lack an + immediate physical chassis. Note that + many systems allow detection of the + chassis type automatically (based on + firmware information or + suchlike). This setting (if set) shall + take precedence over automatically + detected information and is useful to + override misdetected configuration or + to manually configure the chassis type + where automatic detection is not + available. + + @@ -130,8 +163,9 @@ Example - PRETTY_NAME="Lennart's Computer" -ICON_NAME=computer-laptop + PRETTY_HOSTNAME="Lennart's Tablet" +ICON_NAME=computer-tablet +CHASSIS=tablet @@ -140,7 +174,9 @@ ICON_NAME=computer-laptop systemd1, os-release5, hostname5, - machine-id5 + machine-id5, + hostnamectl1, + systemd-hostnamed.service8 diff --git a/man/machinectl.xml b/man/machinectl.xml new file mode 100644 index 0000000..89dca9c --- /dev/null +++ b/man/machinectl.xml @@ -0,0 +1,277 @@ + + + + + + + + + machinectl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + machinectl + 1 + + + + machinectl + Control the systemd machine manager + + + + + machinectl + OPTIONS + COMMAND + NAME + + + + + Description + + machinectl may be used to + introspect and control the state of the + systemd1 + virtual machine and container registration manager systemd-machined.service8. + + + + Options + + The following options are understood: + + + + + + + When showing + machine properties, limit the + output to certain properties as + specified by the argument. If not + specified, all set properties are + shown. The argument should be a + property name, such as + Name. If + specified more than once, all + properties with the specified names + are shown. + + + + + + + When showing + machine properties, show all + properties regardless of whether they are + set or not. + + + + + + + Do not ellipsize + process tree entries. + + + + + + + When used with + kill, + choose which processes to kill. Must + be one of , or + to select whether + to kill only the leader process of the + machine or all processes of the + machine. If omitted, defaults to + . + + + + + + + When used with + kill, choose + which signal to send to selected + processes. Must be one of the + well-known signal specifiers, such as + SIGTERM, + SIGINT or + SIGSTOP. If + omitted, defaults to + SIGTERM. + + + + + + Do not print the legend, + i.e. the column headers and the + footer. + + + + + + + + + + + The following commands are understood: + + + + list + + List currently running + virtual machines and containers. + + + + + status ID... + + Show terse runtime + status information about one or more + virtual machines and containers. This + function is intended to generate + human-readable output. If you are + looking for computer-parsable output, + use show instead. + + + + + show ID... + + Show properties of one + or more registered virtual machines or + containers or the manager itself. If + no argument is specified, properties + of the manager will be shown. If an + ID is specified, properties of this + virtual machine or container are + shown. By default, empty properties + are suppressed. Use + to show those + too. To select specific properties to + show, use + . This + command is intended to be used + whenever computer-parsable output is + required. Use + status if you are + looking for formatted human-readable + output. + + + + terminate ID... + + Terminates a virtual + machine or container. This kills all + processes of the virtual machine or + container and deallocates all + resources attached to that + instance. + + + + kill ID... + + Send a signal to one + or more processes of the virtual + machine or container. This means + processes as seen by the host, not the + processes inside the virtual machine + or container. + Use to + select which process to kill. Use + to select + the signal to send. + + + + reboot ID... + + Reboot one or more + containers. This will trigger a reboot + by sending SIGINT to the container's + init process, which is roughly + equivalent to pressing Ctrl+Alt+Del on + a non-containerized + system. + + + + login ID + + Open a terminal login + session to a container. This will + create a TTY connection to a specific + container and asks for the execution of a + getty on it. Note that this is only + supported for containers running + systemd1 + as init system. + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + + + See Also + + systemd-machined.service8, + systemd-nspawn1, + systemd.special7 + + + + diff --git a/man/modules-load.d.xml b/man/modules-load.d.xml index b633663..33c466f 100644 --- a/man/modules-load.d.xml +++ b/man/modules-load.d.xml @@ -7,19 +7,19 @@ Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + modules-load.d @@ -46,49 +46,55 @@ - /usr/lib/modules-load.d/*.conf /etc/modules-load.d/*.conf /run/modules-load.d/*.conf + /usr/lib/modules-load.d/*.conf Description - systemd uses - files from the above directories to configure - kernel modules to load during boot in a static list. - Each configuration file is named in the style of - /etc/modules-load.d/<program>.conf. Note - that it is usually a better idea to use the automatic - module loading by PCI ID, by DMI ID or similar - triggers configured in the kernel modules themselves - instead of relying on static configuration like - this. + systemd-modules-load.service8 + reads files from the above directories which contain + kernel modules to load during boot in a static list. + Each configuration file is named in the style of + /etc/modules-load.d/program.conf. Note + that it is usually a better idea to rely on the + automatic module loading by PCI IDs, USB IDs, DMI IDs + or similar triggers encoded in the kernel modules + themselves instead of static configuration like + this. In fact, most modern kernel modules are prepared + for automatic loading already. - Configuration Format - - The configuration files should simply contain a - list of kernel module names to load, separated by - newlines. Empty lines and lines whose first - non-whitespace character is # or ; are ignored. - - Each configuration file is named in the style of - <program>.conf. - Files in /etc/ overwrite - files with the same name in /usr/lib/. - Files in /run overwrite files with - the same name in /etc/ and - /usr/lib/. Packages should install their - configuration files in /usr/lib/, files - in /etc/ are reserved for the local - administration, which possibly decides to overwrite the - configurations installed from packages. All files are sorted - by filename in alphabetical order, regardless in which of the - directories they reside, to ensure that a specific - configuration file takes precedence over another file with - an alphabetically later name. + Configuration Format + + The configuration files should simply contain a + list of kernel module names to load, separated by + newlines. Empty lines and lines whose first + non-whitespace character is # or ; are ignored. + + Each configuration file shall be named in the + style of program.conf. + Files in /etc/ override files + with the same name in /usr/lib/ + and /run/. Files in + /run/ override files with the + same name in /usr/lib/. Packages + should install their configuration files in + /usr/lib/, files in + /etc/ are reserved for the local + administrator, who may use this logic to override the + configuration files installed from vendor + packages. + + If the administrator wants to disable a + configuration file supplied by the vendor, the + recommended way is to place a symlink to + /dev/null in + /etc/modules-load.d/ bearing the + same filename. @@ -105,6 +111,8 @@ virtio-net See Also systemd1, + systemd-modules-load.service8, + systemd-delta1, modprobe8 diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml new file mode 100644 index 0000000..cca3a99 --- /dev/null +++ b/man/nss-myhostname.xml @@ -0,0 +1,133 @@ + + + + + + + + + nss-myhostname + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + nss-myhostname + 8 + + + + nss-myhostname + Provide hostname resolution for the locally + configured system hostname. + + + + nss-myhostname.la + + + + Description + + nss-myhostname is a plugin for the GNU Name Service Switch + (NSS) functionality of the GNU C Library (glibc) + providing hostname resolution for the locally configured system + hostname as returned by + gethostname2. + Various software relies on an always-resolvable local hostname. When + using dynamic hostnames, this is usually achieved by patching + /etc/hosts at the same time as changing the host + name. This however is not ideal since it requires a writable + /etc file system and is fragile because the file + might be edited by the administrator at the same time. nss-myhostname + simply returns all locally configured public IP addresses, or, if none + are configured, the IPv4 address 127.0.0.2 (which is on the local + loopback) and the IPv6 address ::1 (which is the local host) for + whatever system hostname is configured locally. Patching + /etc/hosts is thus no longer necessary. + + To activate the NSS modules, + has to be added to the line starting with "hosts:" in + /etc/nsswitch.conf + + It is recommended to put + last in the nsswitch.conf line to make + sure that this mapping is only used as fallback, and any DNS + or /etc/hosts based mapping takes precedence. + + + + Example + +# /etc/nsswitch.conf + +passwd: compat +group: compat +shadow: compat + +hosts: files dns myhostname +networks: files + +protocols: db files +services: db files +ethers: db files +rpc: db files + +netgroup: nis + + To test, use glibc's getent tool: + + $ getent ahosts `hostname` +::1 STREAM omega +::1 DGRAM +::1 RAW +127.0.0.2 STREAM +127.0.0.2 DGRAM +127.0.0.2 RAW + + In this case the local hostname is omega. + + + + + See Also + + systemd1, + systemd-logind.service8, + logind.conf5, + loginctl1, + pam.conf5, + pam.d5, + pam8, + pam_loginuid8 + + + + diff --git a/man/os-release.xml b/man/os-release.xml index f85119d..c1dd62f 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -58,23 +58,42 @@ contains operating system identification data. The basic file format of - os-release is a - newline-separated list of environment-like - shell-compatible variable assignments. It is possible - to source the configuration from shell scripts, - however, beyond mere variable assignments no shell - features are supported, allowing applications to read - the file without implementing a shell compatible - execution engine. + os-release is a newline-separated + list of environment-like shell-compatible variable + assignments. It is possible to source the + configuration from shell scripts, however, beyond mere + variable assignments, no shell features are supported + (this means variable expansion is explicitly not + supported), allowing applications to read the file + without implementing a shell compatible execution + engine. Variable assignment values should be enclosed + in double or single quotes if they include spaces, + semicolons or other special characters outside of A-Z, + a-z, 0-9. All strings should be in UTF-8 format, and + non-printable characters should not be used. If double + or single quotes or backslashes are to be used within + variable assignments, they should be escaped with + backslashes, following shell style. It is not + supported to concatenate multiple individually quoted + strings. Lines beginning with "#" shall be ignored as + comments. /etc/os-release contains data that is defined by the operating system vendor and should not be changed by the administrator. - Depending on the operating system other - configuration files might be checked for OS - identification as well, however only as - fallback. + As this file only encodes names and identifiers + it should not be localized. + + The file /etc/os-release might + be a symlink to another file, but it is important that + the file is available from earliest boot on, and hence + must be located on the root file system. + + For a longer rationale for + /etc/os-release please refer to + the Announcement of /etc/os-release. @@ -90,10 +109,10 @@ A string identifying the operating system, without a - version string, and not necessarily - suitable for presentation to the - user. If not set defaults to - Linux. Example: + version component, and suitable for + presentation to the user. If not set, + defaults to + NAME=Linux. Example: NAME=Fedora or NAME="Debian GNU/Linux". @@ -104,37 +123,86 @@ A string identifying the operating system version, - excluding any name information and - suitable for presentation to the - user. Example: - VERSION=15 or - VERSION="15 - (Rawhide)". + excluding any OS name information, + possibly including a release code + name, and suitable for presentation to + the user. This field is + optional. Example: + VERSION=17 or + VERSION="17 (Beefy + Miracle)". ID= A lower-case string - (no spaces) identifying the operating - system, excluding any version - information and suitable for - processing by scripts or usage in - generated file names. If not set - defaults to - linux. Example: - ID=fedora. + (no spaces or other characters outside + of 0-9, a-z, ".", "_" and "-") + identifying the operating system, + excluding any version information and + suitable for processing by scripts or + usage in generated filenames. If not + set, defaults to + ID=linux. Example: + ID=fedora or + ID=debian. + + + + ID_LIKE= + + A space-separated list + of operating system identifiers in the + same syntax as the + ID= setting. It should + list identifiers of operating systems + that are closely related to the local + operating system in regards to + packaging and programming interfaces, + for example listing one or more + OS identifiers the local + OS is a derivative from. An + OS should generally only list other OS + identifiers it itself is a derivative + of, and not any OSes that + are derived from it, though symmetric + relationships are possible. Build + scripts and similar should check this + variable if they need to identify the + local operating system and the value + of ID= is not + recognized. Operating systems should + be listed in order of how closely the + local operating system relates to the + listed ones, starting with the + closest. This field is + optional. Example: for an operating + system with + ID=centos, an + assignment of ID_LIKE="rhel + fedora" would be + appropriate. For an operating system + with ID=ubuntu, an + assignment of + ID_LIKE=debian is + appropriate. VERSION_ID= A lower-case string - (mostly numeric, no spaces) identifying the - operating system version, excluding - any name information and suitable for - processing by scripts or usage in generated file names. Example: - VERSION_ID=15. + (mostly numeric, no spaces or other + characters outside of 0-9, a-z, ".", + "_" and "-") identifying the operating + system version, excluding any OS name + information or release code name, and + suitable for processing by scripts or + usage in generated filenames. This + field is optional. Example: + VERSION_ID=17 or + VERSION_ID=11.04. @@ -143,11 +211,12 @@ A pretty operating system name in a format suitable for presentation to the user. May or may - not contain an OS version of some - kind, as suitable. If not set defaults - to Linux. Example: - PRETTY_NAME=Fedora 15 - (Rawhide). + not contain a release code name or OS + version of some kind, as suitable. If + not set, defaults to + PRETTY_NAME="Linux". Example: + PRETTY_NAME="Fedora 17 (Beefy + Miracle)". @@ -155,40 +224,138 @@ A suggested presentation color when showing the - distribution name on the console. This + OS name on the console. This should be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for setting - graphical rendition. Example: - ANSI_COLOR=0;31 for - red, or - ANSI_COLOR=1;34 for - light blue. + graphical rendition. This field is + optional. Example: + ANSI_COLOR="0;31" + for red, or + ANSI_COLOR="1;34" + for light blue. + + + + CPE_NAME= + + A CPE name for the + operating system, following the Common + Platform Enumeration + Specification as proposed by + the MITRE Corporation. This field + is optional. Example: + CPE_NAME="cpe:/o:fedoraproject:fedora:17" + + + + HOME_URL= + SUPPORT_URL= + BUG_REPORT_URL= + + Links to resources on + the Internet related the operating + system. HOME_URL= + should refer to the homepage of the + operating system, or alternatively + some homepage of the specific version + of the operating + system. SUPPORT_URL= + should refer to the main support page + for the operating system, if there is + any. This is primarily intended for + operating systems which vendors + provide support + for. BUG_REPORT_URL= + should refer to the main bug reporting + page for the operating system, if + there is any. This is primarily + intended for operating systems that + rely on community QA. These settings + are optional, and providing only some + of these settings is common. These + URLs are intended to be exposed in + "About this system" UIs behind links + with captions such as "About this + Operating System", "Obtain Support", + and "Report a Bug". The values should + be in RFC3986 + format, and should be + http: or + https: URLs, and + possibly mailto: or + tel:. Only one URL + shall be listed in each setting. If + multiple resources need to be + referenced, it is recommended to + provide an online landing page linking + all available resources. Examples: + HOME_URL="https://fedoraproject.org/" + and + BUG_REPORT_URL="https://bugzilla.redhat.com/" + + + + BUILD_ID= + + A string uniquely + identifying the system image used as + the origin for a distribution (it is + not updated with system updates). The + field can be identical between + different VERSION_IDs as BUILD_ID is + an only a unique identifier to a + specific version. Distributions that + release each update as a new version + would only need to use VERSION_ID as + each build is already distinct based + on the VERSION_ID. This field is + optional. Example: + BUILD_ID="2013-03-20.3" + or + BUILD_ID=201303203. + + + + - If you are reading this file from code or a + If you are reading this file from C code or a shell script to determine the OS or a specific version - of it, use the ID and VERSION_ID fields. When looking - for an OS identification string for presentation to - the user use the PRETTY_NAME field. + of it, use the ID and VERSION_ID fields, possibly with + ID_LIKE as fallback for ID. When looking for an OS + identification string for presentation to the user use + the PRETTY_NAME field. Note that operating system vendors may choose not to provide version information, for example to - accommodate for rolling releases. In this case VERSION + accommodate for rolling releases. In this case, VERSION and VERSION_ID may be unset. Applications should not rely on these fields to be set. + + Operating system vendors may extend the file + format and introduce new fields. It is highly + recommended to prefix new fields with an OS specific + name in order to avoid name clashes. Applications + reading this file must ignore unknown fields. Example: + DEBIAN_BTS="debbugs://bugs.debian.org/" Example NAME=Fedora -VERSION="15 (Rawhide)" +VERSION="17 (Beefy Miracle)" ID=fedora -VERSION_ID=15 -PRETTY_NAME="Fedora 15 (Rawhide)" -ANSI_COLOR=0;34 +VERSION_ID=17 +PRETTY_NAME="Fedora 17 (Beefy Miracle)" +ANSI_COLOR="0;34" +CPE_NAME="cpe:/o:fedoraproject:fedora:17" +HOME_URL="https://fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml index 883b50b..3022cdb 100644 --- a/man/pam_systemd.xml +++ b/man/pam_systemd.xml @@ -8,20 +8,20 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + pam_systemd @@ -44,21 +44,20 @@ pam_systemd - Register user sessions in the systemd control group hierarchy + Register user sessions in the systemd login manager - - pam_systemd.so - + pam_systemd.so Description pam_systemd registers user - sessions in the systemd control group - hierarchy. + sessions with the systemd login manager + systemd-logind.service8, + and hence the systemd control group hierarchy. On login, this module ensures the following: @@ -81,29 +80,32 @@ an independent session counter is used. - A new control group - /user/$USER/$XDG_SESSION_ID - is created and the login process moved into - it. + A new systemd scope unit is + created for the session. If this is the first + concurrent session of the user, an implicit + slice below user.slice is + automatically created and the scope placed in + it. In instance of the system service + user@.service which runs + the systemd user manager + instance. On logout, this module ensures the following: - If - $XDG_SESSION_ID is set and - specified, all - remaining processes in the - /user/$USER/$XDG_SESSION_ID - control group are killed and the control group - is removed. - - If last subgroup of the - /user/$USER control group - was removed the + If this is enabled, all + processes of the session are terminated. If + the last concurrent session of a user ends, his + user systemd instance will be terminated too, + and so will the user's slice + unit. + + If the last concurrent session + of a user ends, the $XDG_RUNTIME_DIR directory - and all its contents are - removed, too. + and all its contents are removed, + too. If the system was not booted up with systemd as @@ -117,113 +119,48 @@ The following options are understood: - - - - - Takes a boolean - argument. If true, all processes - created by the user during his session - and from his session will be - terminated when he logs out from his - session. - + - - - Takes a comma - separated list of user names or - numeric user ids as argument. If this - option is used the effect of the - options - will apply only to the listed - users. If this option is not used the - option applies to all local - users. Note that - - takes precedence over this list and is - hence subtracted from the list - specified here. + + + Takes a string + argument which sets the session class. + The XDG_SESSION_CLASS environmental variable + takes precedence. One of + user, + greeter, + lock-screen or + background. See + sd_session_get_class3 + for details about the session class. - - - Takes a comma - separated list of user names or - numeric user ids as argument. Users - listed in this argument will not be - subject to the effect of - . Note - that that this option takes precedence - over - , and - hence whatever is listed for - - is guaranteed to never be killed by - this PAM module, independent of any - other configuration - setting. + + + Takes a string + argument which sets the session type. + The XDG_SESSION_TYPE environmental + variable takes precedence. One of + unspecified, + tty, + x11 or + wayland. See + sd_session_get_type3 + for details about the session type. - - - Takes a comma - separated list of control group - controllers in which hierarchies a - user/session control group will be - created by default for each user - logging in, in addition to the control - group in the named 'name=systemd' - hierarchy. If omitted, defaults to an - empty list. - + - - - - Takes a comma - separated list of control group - controllers in which hierarchies the - logged in processes will be reset to - the root control - group. - - - - - - Takes a boolean - argument. If yes, the module will log + Takes an optional + boolean argument. If yes or without + the argument, the module will log debugging information as it operates. - - Note that setting - kill-session-processes=1 will break tools - like - screen1. - - Note that - kill-session-processes=1 is a - stricter version of - KillUserProcesses=1 which may be - configured system-wide in - systemd-logind.conf5. The - former kills processes of a session as soon as it - ends, the latter kills processes as soon as the last - session of the user ends. - - If the options are omitted they default to - , - , - , - , - , - . @@ -237,12 +174,12 @@ The following environment variables are set for the processes of the user's session: - + $XDG_SESSION_ID A session identifier, - suitable to be used in file names. The + suitable to be used in filenames. The string itself should be considered opaque, although often it is just the audit session ID as reported by @@ -271,13 +208,13 @@ in again, the directory contents will have been lost in between, but applications should not rely on this - behaviour and must be able to deal with + behavior and must be able to deal with stale files. To store session-private - data in this directory the user should + data in this directory, the user should include the value of $XDG_SESSION_ID in the filename. This directory shall be used for runtime file system - objects such as AF_UNIX sockets, + objects such as AF_UNIX sockets, FIFOs, PID files and similar. It is guaranteed that this directory is local and offers the greatest possible @@ -285,6 +222,66 @@ operating system provides. + + + + The following environment variables are read by + the module and may be used by the PAM service to pass + metadata to the module: + + + + $XDG_SESSION_TYPE + + The session type. This + may be used instead of + on the + module parameter line, and is usually + preferred. + + + + $XDG_SESSION_CLASS + + The session class. This + may be used instead of + on the + module parameter line, and is usually + preferred. + + + + $XDG_SESSION_DESKTOP + + The session + deskop. This may be used to indicate + the session desktop used, where this + applies. This should be a short, + lowercase string identifying the + desktop environment used if this + information is available. For example: + gnome, or + kde. + + + + $XDG_SEAT + + The seat name the session + shall be registered for, if + any. + + + + $XDG_VTNR + + The VT number the + session shall be registered for, if + any. (Only applies to seats with a VT + available, such as + seat0) + + @@ -298,18 +295,23 @@ account required pam_unix.so password required pam_unix.so session required pam_unix.so session required pam_loginuid.so -session required pam_systemd.so kill-session-processes=1 +session required pam_systemd.so See Also + systemd1, + systemd-logind.service8, + logind.conf5, + loginctl1, pam.conf5, pam.d5, pam8, pam_loginuid8, - systemd-logind.conf5, - systemd1 + systemd.scope5, + systemd.slice5, + systemd.service5 diff --git a/man/runlevel.xml b/man/runlevel.xml index 160d1b1..976753a 100644 --- a/man/runlevel.xml +++ b/man/runlevel.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + runlevel @@ -78,8 +79,7 @@ - Prints a short help - text and exits. + @@ -96,7 +96,7 @@ Environment - + $RUNLEVEL @@ -111,7 +111,7 @@ $PREVLEVEL If - $PREVLEVEL is set + $PREVLEVEL is set, runlevel will print this value as previous runlevel and ignore utmp. @@ -124,7 +124,7 @@ - /var/run/utmp + /var/run/utmp The utmp database runlevel reads the diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml index cd67d99..2b4f3a5 100644 --- a/man/sd-daemon.xml +++ b/man/sd-daemon.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd-daemon @@ -39,22 +40,30 @@ sd-daemon - 7 + 3 sd-daemon - Reference implementation of APIs for + SD_EMERG + SD_ALERT + SD_CRIT + SD_ERR + SD_WARNING + SD_NOTICE + SD_INFO + SD_DEBUG + APIs for new-style daemons - #include "sd-daemon.h" + #include <systemd/sd-daemon.h> - pkg-config --cflags --libs libsystemd-daemon + pkg-config --cflags --libs libsystemd @@ -62,10 +71,8 @@ Description - sd-daemon.c and - sd-daemon.h provide a reference - implementation of various APIs for new-style daemons, - as implemented by the + sd-daemon.h provide APIs + for new-style daemons, as implemented by the systemd1 init system. @@ -73,9 +80,10 @@ sd_listen_fds3, sd_notify3, sd_booted3, - sd_is_fifo3 + sd_is_fifo3, + sd_watchdog_enabled3 for more information about the functions - implemented. In addition to these functions a couple + implemented. In addition to these functions, a couple of logging prefixes are defined as macros: #define SD_EMERG "<0>" /* system is unusable */ @@ -88,10 +96,10 @@ #define SD_DEBUG "<7>" /* debug-level messages */ These prefixes are intended to be used in - conjunction with STDERR-based logging as implemented + conjunction with stderr-based logging as implemented by systemd. If a systemd service definition file is configured with StandardError=syslog - or StandardError=kmsg these + or StandardError=kmsg, these prefixes can be used to encode a log level in lines printed. This is similar to the kernel printk()-style logging. See @@ -115,42 +123,7 @@ - - Notes - - These interfaces are provided by the reference - implementation of APIs for new-style daemons and - distributed with the systemd package. The algorithms - they implement are simple, and can easily be - reimplemented in daemons if it is important to support - this interface without using the reference - implementation. See the respective function man pages - for details. - - In addition, for details about the algorithms - check the liberally licensed reference implementation - sources: - - resp. - - These APIs are implemented in the reference - implementation's sd-daemon.c and - sd-daemon.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming these APIs - may copy the implementation into their source tree, - either verbatim or in excerpts. - - The functions directly related to new-style - daemons become NOPs when -DDISABLE_SYSTEMD is set - during compilation and the reference implementation is - used as drop-in files. In addition, if - sd-daemon.c is compiled on - non-Linux systems they become NOPs. - + See Also @@ -160,11 +133,12 @@ sd_notify3, sd_booted3, sd_is_fifo3, + sd_watchdog_enabled3, daemon7, systemd.service5, systemd.socket5, fprintf3, - sd-readahead7, + sd-readahead3, pkg-config1 diff --git a/man/sd-id128.xml b/man/sd-id128.xml new file mode 100644 index 0000000..5a4146a --- /dev/null +++ b/man/sd-id128.xml @@ -0,0 +1,173 @@ + + + + + + + + + sd-id128 + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd-id128 + 3 + + + + sd-id128 + sd_id128_t + SD_ID128_MAKE + SD_ID128_CONST_STR + SD_ID128_FORMAT_STR + SD_ID128_FORMAT_VAL + sd_id128_equal + APIs for processing 128-bit IDs + + + + + #include <systemd/sd-id128.h> + + + + pkg-config --cflags --libs libsystemd + + + + + + Description + + sd-id128.h provides APIs to + process and generate 128-bit ID values. The 128-bit ID + values processed and generated by these APIs are a + generalization of OSF UUIDs as defined by RFC + 4122 but use a simpler string + format. These functions impose no structure on the + used IDs, much unlike OSF UUIDs or Microsoft GUIDs, + but are fully compatible with those types of IDs. + + + See + sd_id128_to_string3, + sd_id128_randomize3 and + sd_id128_get_machine3 + for more information about the implemented + functions. + + A 128-bit ID is implemented as the following + union type: + + typedef union sd_id128 { + uint8_t bytes[16]; + uint64_t qwords[2]; +} sd_id128_t; + + This union type allows accessing the 128-bit ID + as 16 separate bytes or two 64-bit words. It is generally + safer to access the ID components by their 8-bit array + to avoid endianness issues. This union is intended to + be passed call-by-value (as opposed to + call-by-reference) and may be directly manipulated by + clients. + + A couple of macros are defined to denote and + decode 128-bit IDs: + + SD_ID128_MAKE() may be used + to denote a constant 128-bit ID in source code. A + commonly used idiom is to assign a name to a 128-bit + ID using this macro: + + #define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) + + SD_ID128_CONST_STR() may be + used to convert constant 128-bit IDs into constant + strings for output. The following example code will + output the string + "fc2e22bc6ee647b6b90729ab34a250b1": + int main(int argc, char *argv[]) { + puts(SD_ID128_CONST_STR(SD_MESSAGE_COREDUMP)); +} + + SD_ID128_FORMAT_STR and + SD_ID128_FORMAT_VAL() may be used + to format a 128-bit ID in a + printf3 + format string, as shown in the following + example: + + int main(int argc, char *argv[]) { + sd_id128_t id; + id = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); + printf("The ID encoded in this C file is " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(id)); + return 0; +} + + Use sd_id128_equal() to compare two 128-bit IDs: + + int main(int argc, char *argv[]) { + sd_id128_t a, b, c; + a = SD_ID128_MAKE(ee,89,be,71,bd,6e,43,d6,91,e6,c5,5d,eb,03,02,07); + b = SD_ID128_MAKE(f2,28,88,9c,5f,09,44,15,9d,d7,04,77,58,cb,e7,3e); + c = a; + assert(sd_id128_equal(a, c)); + assert(!sd_id128_equal(a, b)); + return 0; +} + + Note that new, randomized IDs may be generated + with + journalctl1's + option. + + + + + + See Also + + systemd1, + sd_id128_to_string3, + sd_id128_randomize3, + sd_id128_get_machine3, + printf3, + journalctl1, + sd-journal7, + pkg-config1, + machine-id5 + + + + diff --git a/man/sd-journal.xml b/man/sd-journal.xml new file mode 100644 index 0000000..7a05aee --- /dev/null +++ b/man/sd-journal.xml @@ -0,0 +1,125 @@ + + + + + + + + + sd-journal + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd-journal + 3 + + + + sd-journal + APIs for submitting and querying log entries to and from the journal + + + + + #include <systemd/sd-journal.h> + + + + pkg-config --cflags --libs libsystemd + + + + + + Description + + sd-journal.h provides APIs + to submit and query log entries. The APIs exposed act + both as client for the + systemd-journald.service8 + journal service and as parser for the journal files + on disk. + + + See + sd_journal_print3, + sd_journal_stream_fd3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_realtime_usec3, + sd_journal_add_match3, + sd_journal_seek_head3, + sd_journal_get_cursor3, + sd_journal_cutoff_realtime_usec3, + sd_journal_get_usage3, + sd_journal_get_catalog3 + and + sd_journal_get_fd3 + for more information about the functions + implemented. + + Command line access for submitting entries to + the journal is available with the + systemd-cat1 + tool. Command line access for querying entries from + the journal is available with the + journalctl1 + tool. + + + + + + See Also + + systemd1, + sd_journal_print3, + sd_journal_stream_fd3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3, + sd_journal_get_realtime_usec3, + sd_journal_add_match3, + sd_journal_seek_head3, + sd_journal_get_cursor3, + sd_journal_cutoff_realtime_usec3, + sd_journal_get_usage3, + sd_journal_get_fd3, + sd_journal_query_unique3, + sd_journal_get_catalog3, + journalctl1, + sd-id1283, + pkg-config1 + + + + diff --git a/man/sd-login.xml b/man/sd-login.xml new file mode 100644 index 0000000..e68f4fd --- /dev/null +++ b/man/sd-login.xml @@ -0,0 +1,139 @@ + + + + + + + + + sd-login + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd-login + 3 + + + + sd-login + APIs for + tracking logins + + + + + #include <systemd/sd-login.h> + + + + pkg-config --cflags --libs libsystemd + + + + + Description + + sd-login.h provides APIs to + introspect and monitor seat, login session and user + status information on the local system. + + See Multi-Seat + on Linux for an introduction into multi-seat + support on Linux, the background for this set of APIs. + + Note that these APIs only allow purely passive access + and monitoring of seats, sessions and users. To + actively make changes to the seat configuration, + terminate login sessions, or switch session on a seat + you need to utilize the D-Bus API of + systemd-logind, instead. + + These functions synchronously access data in + /proc, + /sys/fs/cgroup and + /run. All of these are virtual + file systems, hence the runtime cost of the accesses + is relatively cheap. + + It is possible (and often a very good choice) to + mix calls to the synchronous interface of + sd-login.h with the asynchronous + D-Bus interface of systemd-logind. However, if this is + done you need to think a bit about possible races + since the stream of events from D-Bus and from + sd-login.h interfaces such as the + login monitor are asynchronous and not ordered against + each other. + + If the functions return string arrays, these are + generally NULL terminated and need to be freed by the + caller with the libc + free3 + call after use, including the strings referenced + therein. Similarly, individual strings returned need to + be freed, as well. + + As a special exception, instead of an empty + string array NULL may be returned, which should be + treated equivalent to an empty string array. + + See + sd_pid_get_session3, + sd_uid_get_state3, + sd_session_is_active3, + sd_seat_get_active3, + sd_get_seats3, + sd_login_monitor_new3 + for more information about the functions + implemented. + + + + + + See Also + + systemd1, + sd_pid_get_session3, + sd_uid_get_state3, + sd_session_is_active3, + sd_seat_get_active3, + sd_get_seats3, + sd_login_monitor_new3, + sd-daemon3, + sd-readahead3, + pkg-config1 + + + + diff --git a/man/sd-readahead.xml b/man/sd-readahead.xml index 819691e..bcc46b2 100644 --- a/man/sd-readahead.xml +++ b/man/sd-readahead.xml @@ -8,20 +8,20 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd-readahead @@ -39,7 +39,7 @@ sd-readahead - 7 + 3 @@ -83,11 +83,11 @@ reference implementation. See the respective function man pages for details. - In addition, for details about the algorithms + In addition, for details about the algorithms, check the liberally licensed reference implementation sources: - - resp. + + and These APIs are implemented in the reference implementation's drop-in @@ -110,7 +110,7 @@ systemd1, sd_readahead3, - sd-daemon7 + sd-daemon3 diff --git a/man/sd_booted.xml b/man/sd_booted.xml index ebcde36..28c153a 100644 --- a/man/sd_booted.xml +++ b/man/sd_booted.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd_booted @@ -44,12 +45,12 @@ sd_booted - Test whether the system is running the systemd init system. + Test whether the system is running the systemd init system - #include "sd-daemon.h" + #include <systemd/sd-daemon.h> int sd_booted @@ -76,52 +77,20 @@ Notes - This function is provided by the reference - implementation of APIs for new-style daemons and - distributed with the systemd package. The algorithm it - implements is simple, and can easily be reimplemented - in daemons if it is important to support this - interface without using the reference - implementation. + Internally, this function checks whether the - /sys/fs/cgroup/systemd virtual file - system is mounted, by comparing the st_dev value of - the stat() data of - /sys/fs/cgroup and - /sys/fs/cgroup/systemd. - - For details about the algorithm check the - liberally licensed reference implementation sources: - - resp. - - sd_booted() is implemented - in the reference implementation's - sd-daemon.c and - sd-daemon.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming these APIs - may copy the implementation into their source - tree. For more details about the reference - implementation see - sd_daemon7. - - If the reference implementation is used as - drop-in files and -DDISABLE_SYSTEMD is set during - compilation this function will always return 0 and - otherwise become a NOP. + directory /run/systemd/system/ + exists. A simple check like this can also be + implemented trivially in shell or any other + language. See Also systemd1, - sd_daemon7 + sd-daemon3 diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml new file mode 100644 index 0000000..f84fbae --- /dev/null +++ b/man/sd_bus_creds_get_pid.xml @@ -0,0 +1,453 @@ + + + + + + + + + sd_bus_creds_get_pid + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_creds_get_pid + 3 + + + + sd_bus_creds_get_pid + sd_bus_creds_get_pid_starttime + sd_bus_creds_get_tid + sd_bus_creds_get_uid + sd_bus_creds_get_gid + sd_bus_creds_get_comm + sd_bus_creds_get_tid_comm + sd_bus_creds_get_exe + sd_bus_creds_get_cmdline + sd_bus_creds_get_cgroup + sd_bus_creds_get_unit + sd_bus_creds_get_user_unit + sd_bus_creds_get_slice + sd_bus_creds_get_session + sd_bus_creds_get_owner_uid + sd_bus_creds_has_effective_cap + sd_bus_creds_has_permitted_cap + sd_bus_creds_has_inheritable_cap + sd_bus_creds_has_bounding_cap + sd_bus_creds_get_selinux_context + sd_bus_creds_get_audit_session_id + sd_bus_creds_get_audit_login_uid + sd_bus_creds_get_unique_name + sd_bus_creds_get_well_known_names + + Retrieve fields from a credentials object + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_creds_get_pid + sd_bus_creds *c + pid_t *pid + + + + int sd_bus_creds_get_pid_starttime + sd_bus_creds *c + uint64_t *usec + + + + int sd_bus_creds_get_tid + sd_bus_creds *c + pid_t *tid + + + + int sd_bus_creds_get_pid + sd_bus_creds *c + uid_t *uid + + + + int sd_bus_creds_get_gid + sd_bus_creds *c + gid_t *gid + + + + int sd_bus_creds_get_comm + sd_bus_creds *c + const char **comm + + + + int sd_bus_creds_get_tid_comm + sd_bus_creds *c + const char **comm + + + + int sd_bus_creds_get_exe + sd_bus_creds *c + const char **exe + + + + int sd_bus_creds_get_cmdline + sd_bus_creds *c + char ***cmdline + + + + int sd_bus_creds_get_cgroup + sd_bus_creds *c + const char **cgroup + + + + int sd_bus_creds_get_unit + sd_bus_creds *c + const char **unit + + + + int sd_bus_creds_get_user_unit + sd_bus_creds *c + const char **unit + + + + int sd_bus_creds_get_slice + sd_bus_creds *c + const char **slice + + + + int sd_bus_creds_get_session + sd_bus_creds *c + const char **slice + + + + int sd_bus_creds_get_owner_uid + sd_bus_creds *c + uid_t *uid + + + + int sd_bus_creds_has_effective_cap + sd_bus_creds *c + int capability + + + + int sd_bus_creds_has_permitted_cap + sd_bus_creds *c + int capability + + + + int sd_bus_creds_has_inheritable_cap + sd_bus_creds *c + int capability + + + + int sd_bus_creds_has_bounding_cap + sd_bus_creds *c + int capability + + + + int sd_bus_creds_get_selinux_context + sd_bus_creds *c + const char **context + + + + int sd_bus_creds_get_audit_session_id + sd_bus_creds *c + uint32_t *sessionid + + + + int sd_bus_creds_get_audit_login_uid + sd_bus_creds *c + uid_t *loginuid + + + + int sd_bus_creds_get_unique_name + sd_bus_creds *c + const char **name + + + + int sd_bus_creds_get_well_known_names + sd_bus_creds *c + char ***name + + + + + + + Description + + These functions return information from an + sd_bus_creds object. It may be created with + sd_bus_creds_new_from_pid3, + in which case it will describe the specified process, or it may be + created by + sd_bus_get_peer_creds3, + in which case it will describe the process at the other endpoint + of a connection. + + + sd_bus_creds_get_pid will retrieve the + PID (process identifier). + + sd_bus_creds_get_pid_starttime will + retrieve the time since the start of the epoch in microseconds + since the process was started. + + sd_bus_creds_get_tid will retrieve the + TID (thread identifier). + + sd_bus_creds_get_uid will retrieve the + numeric UID (user identifier). + + sd_bus_creds_get_gid will retrieve the + numeric GID (group identifier). + + sd_bus_creds_get_comm will retrieve the + comm field (truncated name of the executable, as stored in + /proc/pid/comm). + + + sd_bus_creds_get_tid_comm will retrieve + the comm field of the thread (as stored in + /proc/pid/task/tid/comm). + + + sd_bus_creds_get_exe will retrieve the + path to the program (as stored in the + /proc/pid/exe + link, but with (deleted) suffix removed). + + + sd_bus_creds_get_cmdline will retrieve + an array of command-line arguments (as stored in + /proc/pid/cmdline). + + + sd_bus_creds_get_cgroup will retrieve + the cgroup path. See cgroups.txt. + + + sd_bus_creds_get_unit will retrieve the + systemd unit name (in the system instance of systemd) that the + process is part of. See + systemd.unit5. + + + sd_bus_creds_get_user_unit will + retrieve the systemd unit name (in the user instance of systemd) + that the process is part of. See + systemd.unit5. + + + sd_bus_creds_get_slice will retrieve + the systemd slice (a unit in the system instance of systemd) that + the process is part of. See + systemd.slice5. + + + sd_bus_creds_get_session will retrieve + the logind session that the process is part of. See + systemd-logind.service8. + + + sd_bus_creds_get_owner_uid will retrieve + the numeric UID (user identifier) of the user who owns the slice + that the process is part of. See + systemd.slice5 + . + + + sd_bus_creds_has_effective_cap will + check whether the capability specified by + capability was set in the effective + capabilities mask. A positive return value means that is was + set, zero means that it was not set, and a negative return + value signifies an error. See + capabilities7 + and Capabilities= and + CapabilityBoundingSet= settings in + systemd.exec5. + + + sd_bus_creds_has_permitted_cap is + similar to sd_bus_creds_has_effective_cap, + but will check the permitted capabilities mask. + + sd_bus_creds_has_inheritable_cap is + similar to sd_bus_creds_has_effective_cap, + but will check the inheritable capabilities mask. + + sd_bus_creds_has_bounding_cap is + similar to sd_bus_creds_has_effective_cap, + but will check the bounding capabilities mask. + + sd_bus_creds_get_selinux_context will + retrieve the SELinux security context (label) of the process. + + sd_bus_creds_get_audit_session_id will + retrieve the audit session identifier of the process. + + sd_bus_creds_get_audit_login_uid will + retrieve the audit user login identifier (the identifier of the + user who is "responsible" for the session). + + sd_bus_creds_get_unique_name will + retrieve the D-Bus unique name. See The + D-Bus specification. + + sd_bus_creds_get_well_known_names will + retrieve the set of D-Bus well-known names. See The + D-Bus specification. + + All functions that take a const + char** parameter will store the answer there as an + address of a NUL-terminated string. It will be valid as long as + c remains valid, and should not be freed or + modified by the caller. + + All functions that take a char*** + parameter will store the answer there as an address of a an array + of strings. Each invidividual string is NUL-terminated, and the + array is NULL-terminated as a whole. It will be valid as long as + c remains valid, and should not be freed or + modified by the caller. + + + + Return Value + + On success, these calls return 0 or a positive integer. On + failure, these calls return a negative errno-style error code. + + + + + Errors + + Returned errors may indicate the following problems: + + + + -ENODATA + + Given field is not available in + c. + + + + + -ENOENT + + Given field is not specified for the sender. + This will be returned by sd_bus_get_unit, + sd_bus_get_user_unit, + sd_bus_get_slice, + sd_bus_get_session, and + sd_bus_get_owner_uid if the sender is not + part of a systemd system unit, systemd user unit, systemd + slice, logind session, or a systemd user session. + + + + + -ENXIO + + An error occured in parsing cgroup paths. + libsystemd might be out of sync with + the running systemd version. + + + + -EINVAL + + Specified pointer parameter is NULL. + + + + + -ENOMEM + + Memory allocation failed. + + + + + + Notes + + sd_bus_open_user() and other functions + described here are available as a shared library, which can be + compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + credentials7, + fork2, + execve2, + free3, + proc5, + systemd.journald-fields7 + + + + diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml new file mode 100644 index 0000000..64b92e2 --- /dev/null +++ b/man/sd_bus_creds_new_from_pid.xml @@ -0,0 +1,275 @@ + + + + + + + + + sd_bus_creds_new_from_pid + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_creds_new_from_pid + 3 + + + + sd_bus_creds_new_from_pid + sd_bus_creds_get_mask + sd_bus_creds_ref + sd_bus_creds_unref + + Retrieve credentials object for the specified PID + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_creds_new_from_pid + pid_t pid + uint64_t creds_mask + sd_bus_creds **ret + + + + uint64_t sd_bus_creds_get_mask + const sd_bus_creds *c + + + + sd_bus_creds *sd_bus_creds_ref + sd_bus_creds *c + + + + sd_bus_creds *sd_bus_creds_unref + sd_bus_creds *c + + + + + SD_BUS_CREDS_PID, + SD_BUS_CREDS_PID_STARTTIME, + SD_BUS_CREDS_TID, + SD_BUS_CREDS_UID, + SD_BUS_CREDS_GID, + SD_BUS_CREDS_COMM, + SD_BUS_CREDS_TID_COMM, + SD_BUS_CREDS_EXE, + SD_BUS_CREDS_CMDLINE, + SD_BUS_CREDS_CGROUP, + SD_BUS_CREDS_UNIT, + SD_BUS_CREDS_USER_UNIT, + SD_BUS_CREDS_SLICE, + SD_BUS_CREDS_SESSION, + SD_BUS_CREDS_OWNER_UID, + SD_BUS_CREDS_EFFECTIVE_CAPS, + SD_BUS_CREDS_PERMITTED_CAPS, + SD_BUS_CREDS_INHERITABLE_CAPS, + SD_BUS_CREDS_BOUNDING_CAPS, + SD_BUS_CREDS_SELINUX_CONTEXT, + SD_BUS_CREDS_AUDIT_SESSION_ID, + SD_BUS_CREDS_AUDIT_LOGIN_UID, + SD_BUS_CREDS_UNIQUE_NAME, + SD_BUS_CREDS_WELL_KNOWN_NAMES, + _SD_BUS_CREDS_ALL + + + + + Description + + sd_bus_creds_new_from_pid() creates a new + credentials object and fills it with information about the process + pid. This pointer to this object will + be stored in ret pointer. + + The information that will be stored is determined by + creds_mask. It may contain a subset of ORed + constants SD_BUS_CREDS_PID, + SD_BUS_CREDS_PID_STARTTIME, + SD_BUS_CREDS_TID, + SD_BUS_CREDS_UID, + SD_BUS_CREDS_GID, + SD_BUS_CREDS_COMM, + SD_BUS_CREDS_TID_COMM, + SD_BUS_CREDS_EXE, + SD_BUS_CREDS_CMDLINE, + SD_BUS_CREDS_CGROUP, + SD_BUS_CREDS_UNIT, + SD_BUS_CREDS_USER_UNIT, + SD_BUS_CREDS_SLICE, + SD_BUS_CREDS_SESSION, + SD_BUS_CREDS_OWNER_UID, + SD_BUS_CREDS_EFFECTIVE_CAPS, + SD_BUS_CREDS_PERMITTED_CAPS, + SD_BUS_CREDS_INHERITABLE_CAPS, + SD_BUS_CREDS_BOUNDING_CAPS, + SD_BUS_CREDS_SELINUX_CONTEXT, + SD_BUS_CREDS_AUDIT_SESSION_ID, + SD_BUS_CREDS_AUDIT_LOGIN_UID, + SD_BUS_CREDS_UNIQUE_NAME, + SD_BUS_CREDS_WELL_KNOWN_NAMES, + or _SD_BUS_CREDS_ALL to indicate + all known fields. + + Fields can be retrieved from the credentials object using + sd_bus_creds_get_pid3 + and other functions which correspond directly to the constants + listed above. + + A mask of fields which were actually sucessfully set + (acquired from /proc, etc.) can be retrieved + with sd_bus_creds_get_mask(). If the + credentials object was created with + sd_bus_creds_new_from_pid(), this will be a + subset of fields requested in creds_mask. + + + sd_bus_creds_ref creates a new + reference to the credentials object c. This + object will not be destroyed until + sd_bus_creds_unref has been called as many + times plus once more. Once the reference count has dropped to zero, + c cannot be used anymore, so futher + calls to sd_bus_creds_ref(c) or + sd_bus_creds_unref(c) are illegal. + + sd_bus_creds_unref destroys a reference + to c. + + + + Return Value + + On success, sd_bus_creds_new_from_pid() + returns 0 or a positive integer. On failure, it returns a negative + errno-style error code. + + sd_bus_creds_get_mask() returns the + mask of successfully acquired fields. + + sd_bus_creds_ref always returns the + argument. + + sd_bus_creds_unref always returns + NULL. + + + + Reference ownership + + Function sd_bus_creds_new_from_pid() + creates a new object and the caller owns the sole reference. When + not needed anymore, this reference should be destroyed with + sd_bus_creds_unref3. + + + + + Errors + + Returned errors may indicate the following problems: + + + + + -ESRCH + + Specified pid could not + be found. + + + + -EINVAL + + Specified parameter is invalid + (NULL in case of output + parameters). + + + + -ENOMEM + + Memory allocation failed. + + + + + + Notes + + sd_bus_creds_new_from_pid() is + available as a shared library, which can be compiled and linked to + with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_creds_ref3, + sd_bus_creds_unref3, + sd_bus_creds_get_pid3, + sd_bus_creds_get_pid_starttime3, + sd_bus_creds_get_tid3, + sd_bus_creds_get_uid3, + sd_bus_creds_get_gid3, + sd_bus_creds_get_comm3, + sd_bus_creds_get_tid_comm3, + sd_bus_creds_get_exe3, + sd_bus_creds_get_cmdline3, + sd_bus_creds_get_cgroup3, + sd_bus_creds_get_unit3, + sd_bus_creds_get_user_unit3, + sd_bus_creds_get_slice3, + sd_bus_creds_get_session3, + sd_bus_creds_get_owner_uid3, + sd_bus_creds_has_effective_cap3, + sd_bus_creds_has_permitted_cap3, + sd_bus_creds_has_inheritable_cap3, + sd_bus_creds_has_bounding_cap3, + sd_bus_creds_get_selinux_context3, + sd_bus_creds_get_audit_session_id3, + sd_bus_creds_get_audit_login_uid3, + sd_bus_creds_get_unique_name3, + sd_bus_creds_get_well_known_names3 + + + + diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml new file mode 100644 index 0000000..68f1d7b --- /dev/null +++ b/man/sd_bus_error.xml @@ -0,0 +1,415 @@ + + + + + + + + + sd_bus_error + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_error + 3 + + + + sd_bus_error + sd_bus_error_free + sd_bus_error_set + sd_bus_error_set_const + sd_bus_error_set_errno + sd_bus_error_set_errnof + sd_bus_error_get_errno + sd_bus_error_copy + sd_bus_error_is_set + sd_bus_error_has_name + + sd-bus error handling + + + + + #include <systemd/sd-bus.h> + + typedef struct { + const char *name; + const char *message; + ... +} sd_bus_error; + + + SD_BUS_ERROR_MAKE_CONST(name, message) + + + SD_BUS_ERROR_NULL + + + + int sd_bus_error_free + sd_bus_error *e + + + + int sd_bus_error_set + sd_bus_error *e + const char *name + const char *message + + + + int sd_bus_error_setf + sd_bus_error *e + const char *name + const char *format + ... + + + + int sd_bus_error_set_const + sd_bus_error *e + const char *name + const char *message + + + + int sd_bus_error_set_errno + sd_bus_error *e + int error + + + + int sd_bus_error_set_errnof + sd_bus_error *e + int error + const char *format + ... + + + + int sd_bus_error_get_errno + const sd_bus_error *e + + + + int sd_bus_error_copy + sd_bus_error *dst + const sd_bus_error *e + + + + int sd_bus_error_is_set + const sd_bus_error *e + + + + int sd_bus_error_has_name + const sd_bus_error *e + const char *name + + + + + SD_BUS_ERROR_FAILED + + + SD_BUS_ERROR_NO_MEMORY + + + SD_BUS_ERROR_SERVICE_UNKNOWN + + + SD_BUS_ERROR_NAME_HAS_NO_OWNER + + + SD_BUS_ERROR_NO_REPLY + + + SD_BUS_ERROR_IO_ERROR + + + SD_BUS_ERROR_BAD_ADDRESS + + + SD_BUS_ERROR_NOT_SUPPORTED + + + SD_BUS_ERROR_LIMITS_EXCEEDED + + + SD_BUS_ERROR_ACCESS_DENIED + + + SD_BUS_ERROR_AUTH_FAILED + + + SD_BUS_ERROR_NO_SERVER + + + SD_BUS_ERROR_TIMEOUT + + + SD_BUS_ERROR_NO_NETWORK + + + SD_BUS_ERROR_ADDRESS_IN_USE + + + SD_BUS_ERROR_DISCONNECTED + + + SD_BUS_ERROR_INVALID_ARGS + + + SD_BUS_ERROR_FILE_NOT_FOUND + + + SD_BUS_ERROR_FILE_EXISTS + + + SD_BUS_ERROR_UNKNOWN_METHOD + + + SD_BUS_ERROR_UNKNOWN_OBJECT + + + SD_BUS_ERROR_UNKNOWN_INTERFACE + + + SD_BUS_ERROR_UNKNOWN_PROPERTY + + + SD_BUS_ERROR_PROPERTY_READ_ONLY + + + SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN + + + SD_BUS_ERROR_INVALID_SIGNATURE + + + SD_BUS_ERROR_INCONSISTENT_MESSAGE + + + SD_BUS_ERROR_MATCH_RULE_NOT_FOUND + + + SD_BUS_ERROR_MATCH_RULE_INVALID + + + + + + Description + + The sd_bus_error structure carries + information for a sd-bus error. + Functions described below can be used to set and query fields in + this structure. The name field contains a + short identifier of an error. It should follow the rules for error + names described in the D-Bus specification, subsection Valid + Names. The message is a human + readable string describing the details. When no longer necessary, + resources held by this structure should be destroyed with + sd_bus_error_free. + + sd_bus_error_set will return an + errno-like negative value returned based on parameter + name (see + errno3). + Various well-known D-Bus errors are converted to specific values, + and the remaining ones to -ENXIO. Well-known + D-Bus error names are available as constants + SD_BUS_ERROR_FAILED, etc., listed above. If + name is NULL, it is + assumed that no error occured, and 0 is returned. This means that + this function may be conveniently used in a + return statement. + + If e is not + NULL, name and + message in the + sd_bus_error structure + e points at will be filled in. As described above, + name may be NULL, + which is treated as no error. Parameter + message may also be + NULL, in which case no message is specified. + sd_bus_error_set will make internal copies of + specified strings. + + sd_bus_error_setf is similar to + sd_bus_error_set, but takes a + printf3 + format string and corresponding arguments to generate + message. + + sd_bus_error_set_const is similar to + sd_bus_error_set, but string parameters are + not copied internally, and must remain valid for the lifetime of + e. + + sd_bus_error_set_errno will set + name based on an errno-like value. + strerror3 + will be used to set message. Well-known + D-Bus error names will be used for name + if available, otherwise a name in the + System.Error namespace will be generated. + + + sd_bus_error_set_errnof is similar to + sd_bus_error_set_errno, but in addition to + name, takes a + printf3 + format and corresponding arguments. + name will be generated from + format and the arguments. + + sd_bus_error_get_errno is will convert + e->name to an errno-like value using the + same rules as sd_bus_error_set. If + e is NULL, 0 will be + returned. + + sd_bus_error_copy will initialize + dst using the values in + e. If the strings in + e were set using + sd_bus_set_error_const, they will be shared. + Otherwise, they will be copied. + + sd_bus_error_is_set will return + true if e is + non-NULL and an error has been set, + false otherwise. + + sd_bus_error_has_name will return true + if e is non-NULL and + an error with the same name has been set, + false otherwise. + + sd_bus_error_free will destroy resources + held by e. The parameter itself will not + be deallocated, and must be + free3d + by the caller if necessary. + + + + Return Value + + Functions sd_bus_error_set, + sd_bus_error_setf, + sd_bus_error_set_const, when successful, + return the negative errno value corresponding to the + name parameter. Functions + sd_bus_error_set_errno and + sd_bus_error_set_errnof, when successful, + return the value of the errno parameter. If + an error occurs, one of the negative error values listed below + will be returned. + + sd_bus_error_get_errno returns + false when e is + NULL, and a positive errno value mapped from + e->name otherwise. + + sd_bus_error_copy returns 0 or a + positive integer on success, and one of the negative error values + listed below otherwise. + + sd_bus_error_is_set returns + true when e and + e->name are non-NULL, + false otherwise. + + sd_bus_error_has_name returns + true when e is + non-NULL and e->name + is equal to name, + false otherwise. + + + + Reference ownership + sd_bus_error is not reference + counted. Users should destroy resources held by it by calling + sd_bus_error_free. + + + + Errors + + Returned errors may indicate the following problems: + + + + + -EINVAL + + Error was already set in + sd_bus_error structure when one the + error-setting functions was called. + + + + -ENOMEM + + Memory allocation failed. + + + + + + Notes + + sd_bus_set_error() and other functions + described here are available as a shared library, which can be + compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + errno3, + strerror3 + + + + diff --git a/man/sd_bus_label_escape.xml b/man/sd_bus_label_escape.xml new file mode 100644 index 0000000..0b5564f --- /dev/null +++ b/man/sd_bus_label_escape.xml @@ -0,0 +1,111 @@ + + + + + + + + + sd_bus_label_escape + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_label_escape + 3 + + + + sd_bus_label_escape + sd_bus_label_unescape + + Escape D-Bus object path special characters + + + + + #include <systemd/sd-bus.h> + + + char *sd_bus_label_escape + const char *s + + + + char *sd_bus_label_unescape + const char *f + + + + + + Description + + sd_bus_label_escape() takes a + NUL-terminated string as a argument. It will + replace all characters which are invalid in a D-Bus object path by + _ and a hexadecimal number. As a special case, + the empty string will be replaced by a lone _. + sd_bus_label_unescape() can be used to + reverse this process. + + + + Return Value + + On success, a new NUL-terminated string + will be returned. It must be + free3d + by the caller. If a memory allocation failure occurs, + NULL will be returned. + + + + + Notes + + sd_bus_label_escape() and + sd_bus_label_unescape() are available as a + shared library, which can be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + free3 + + + + diff --git a/man/sd_bus_message_get_cookie.xml b/man/sd_bus_message_get_cookie.xml new file mode 100644 index 0000000..5e25263 --- /dev/null +++ b/man/sd_bus_message_get_cookie.xml @@ -0,0 +1,152 @@ + + + + + + + + + sd_bus_message_get_cookie + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_bus_message_get_cookie + 3 + + + + sd_bus_message_get_cookie + sd_bus_message_get_reply_cookie + Returns the transaction cookie of a message + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_message_get_cookie + sd_bus_message* message + uint64_t* cookie + + + + int sd_bus_message_get_reply_cookie + sd_bus_message* message + uint64_t* cookie + + + + + + Description + + sd_bus_message_get_cookie() returns + the transaction cookie of a message. The cookie + uniquely identifies a message within each bus peer, + but is not globally unique. It is assigned when a + message is sent. + + sd_bus_message_get_reply_cookie() + returns the transaction cookie of the message the + specified message is a response to. When a reply + message is generated for a method call message, its + cookie is copied over into this field. Note that while + every message that is transferred is identified by a + cookie, only response messages carry a reply cookie + field. + + Both functions take a message object as first + parameter and a place to store the 64-bit cookie + in. + + + + Return Value + + On success, these calls return 0 or a positive + integer. On failure, these calls return a negative + errno-style error code. + + On success, the cookie/reply cookie is returned + in the specified 64-bit unsigned integer variable. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + A specified parameter + is invalid. + + + + -ENODATA + + 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. + + + + + + Notes + + The sd_bus_message_get_cookie() + and sd_bus_message_get_reply_cookie() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_new3 + + + + diff --git a/man/sd_bus_message_get_monotonic_usec.xml b/man/sd_bus_message_get_monotonic_usec.xml new file mode 100644 index 0000000..683931c --- /dev/null +++ b/man/sd_bus_message_get_monotonic_usec.xml @@ -0,0 +1,183 @@ + + + + + + + + + sd_bus_message_get_monotonic_usec + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_bus_message_get_monotonic_usec + 3 + + + + sd_bus_message_get_monotonic_usec + sd_bus_message_get_realtime_usec + sd_bus_message_get_seqnum + Retrieve the sender timestamps and sequence number of a message + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_message_get_monotonic_usec + sd_bus_message *message + uint64_t *usec + + + + int sd_bus_message_get_realtime_usec + sd_bus_message *message + uint64_t *usec + + + + int sd_bus_message_get_seqnum + sd_bus_message *message + uint64_t *seqnum + + + + + + Description + + sd_bus_message_get_monotonic_usec() + returns the monotonic timestamp of the time the + message was sent. This value is in microseconds since + the CLOCK_MONOTONIC epoch, see + clock_gettime2 + for details. + + Similar, + sd_bus_message_get_realtime_usec() + returns the realtime (wallclock) timestamp of the time + the message was sent. This value is in microseconds + since Jan 1st, 1970, i.e. in the + CLOCK_REALTIME clock. + + sd_bus_message_get_seqnum() + returns the kernel-assigned sequence number of the + message. The kernel assigns a global monotonically increasing + sequence number to all messages sent on the local + system. This sequence number is useful for determining + message send order, even across different busses of + the local system. The sequence number combined with + the boot ID of the system (as returned by + sd_id128_get_boot3) + is a suitable globally unique identifier for bus + messages. + + These timestamps and the sequence number are + attached to each message by the kernel and cannot be + manipulated by the sender. + + Note that these timestamps are only available on + some bus transports, and only after support for them + has been negotiated with the + sd_bus_negotiate_timestamp3 + call. + + + + Return Value + + On success, these calls return 0 or a positive + integer. On failure, these calls return a negative + errno-style error code. + + On success, the timestamp or sequence number is + returned in the specified 64-bit unsigned integer + variable. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + A specified parameter + is invalid. + + + + -ENODATA + + 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 + sd_bus_negotiate_timestamp3. + + + + + + Notes + + The + sd_bus_message_get_monotonic_usec(), + sd_bus_message_get_realtime_usec(), + and sd_bus_message_get_seqnum() + interfaces are available as a shared library, which + can be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_new3, + sd_bus_negotiate_timestamp3, + clock_gettime2, + sd_id128_get_boot3 + + + + diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml new file mode 100644 index 0000000..b36d66c --- /dev/null +++ b/man/sd_bus_new.xml @@ -0,0 +1,145 @@ + + + + + + + + + sd_bus_new + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_new + 3 + + + + sd_bus_new + sd_bus_ref + sd_bus_unref + + Create a new bus object and create or destroy references to it + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_new + sd_bus **bus + + + + sd_bus *sd_bus_ref + sd_bus *bus + + + + sd_bus *sd_bus_unref + sd_bus *bus + + + + + + Description + + sd_bus_new() creates a new bus + object. This object is reference-counted, and will be destroyed + when all references are gone. Initially, the caller of this + function owns the sole reference. + + sd_bus_ref() creates a new reference to + bus. This bus object will not be destroyed + until sd_bus_unref() has been called as many + times plus once more. Once the reference count has dropped to + zero, bus cannot be used anymore, so + further calls to sd_bus_ref() or + sd_bus_unref() are illegal. + + sd_bus_unref() destroys a reference to + bus. + + + + Return Value + + On success, sd_bus_new() returns 0 or a + positive integer. On failure, it returns a negative errno-style + error code. + + sd_bus_ref always returns the argument. + + + sd_bus_unref always returns + NULL. + + + + Errors + + Returned errors may indicate the following problems: + + + + -ENOMEM + + Memory allocation failed. + + + + + + Notes + + sd_bus_new() and other functions + described here are available as a shared library, which can be + compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_open_user3, + sd_bus_open_system3, + sd_bus_default_user3, + sd_bus_default_system3 + + + + diff --git a/man/sd_bus_open_user.xml b/man/sd_bus_open_user.xml new file mode 100644 index 0000000..7fa1be6 --- /dev/null +++ b/man/sd_bus_open_user.xml @@ -0,0 +1,217 @@ + + + + + + + + + sd_bus_open_user + systemd + + + + A monkey with a typewriter + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_bus_open_user + 3 + + + + sd_bus_open_user + sd_bus_open_system + sd_bus_open_system_remote + sd_bus_open_system_container + + sd_bus_default_user + sd_bus_default_system + + Open a connection to the system or user bus + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_open_user + sd_bus **bus + + + + int sd_bus_open_system + sd_bus **bus + + + + int sd_bus_open_system_remote + const char *host + sd_bus **bus + + + + int sd_bus_open_system_container + const char *machine + sd_bus **bus + + + + int sd_bus_default_user + sd_bus **bus + + + + int sd_bus_default_system + sd_bus **bus + + + + + + Description + + sd_bus_open_user() creates a new bus + object and opens a connection to the the user bus. + sd_bus_open_system() does the same, but + connects to the system bus. + + If the $DBUS_SESSION_BUS_ADDRESS environment + variable is set + (c.f. environ7), + it will be used as the address of the user bus. This variable can + contain multiple addresses separated by ;. If + this variable is not set, a suitable default for the default user + D-Bus instance will be used. + + If the $DBUS_SYSTEM_BUS_ADDRESS environment + variable is set, it will be used as the address of the system + bus. This variable uses the same syntax as + $DBUS_SESSION_BUS_ADDRESS/. If this variable is + not set, a suitable default for the default system D-Bus instance + will be used. + + sd_bus_open_system_remote() connects to + the system bus on the specified host using + SSH. host consists of an optional user name + followed by the @ symbol, and the hostname. + + + sd_bus_open_system_remote() connects to + the system bus in the specified machine, + where machine is the name of a container. + See + machinectl1 + for more information about "machines". + + sd_bus_default_user() returns a bus + object connected to the user bus. Each thread has its own object, but it + may be passed around. It is created on the first invocation of + sd_bus_default_user(), and subsequent + invocations returns a reference to the same object. + + sd_bus_default_system() is similar to + sd_bus_default_user(), but connects to the + system bus. + + + + Return Value + + On success, these calls return 0 or a positive + integer. On failure, these calls return a negative + errno-style error code. + + + + Reference ownership + Functions sd_bus_open_user(), + sd_bus_open_system(), + sd_bus_open_system_remote(), and + sd_bus_open_system_machine() return a new + object and the caller owns the sole reference. When not needed + anymore, this reference should be destroyed with + sd_bus_unref3. + + + The functions sd_bus_default_user() and + sd_bus_default_system() do not create a new + reference. + + + + Errors + + Returned errors may indicate the following problems: + + + + + -EINVAL + + Specified parameter is invalid + (NULL in case of output + parameters). + + + + -ENOMEM + + Memory allocation failed. + + + In addition, any further connection-related errors may be + by returned. See sd_bus_send3. + + + + + Notes + + sd_bus_open_user() and other functions + described here are available as a shared library, which can be + compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_new3, + sd_bus_ref3, + sd_bus_unref3, + ssh1, + systemd-machined.service8, + machinectl1 + + + + diff --git a/man/sd_bus_request_name.xml b/man/sd_bus_request_name.xml new file mode 100644 index 0000000..9003f9f --- /dev/null +++ b/man/sd_bus_request_name.xml @@ -0,0 +1,228 @@ + + + + + + + + + sd_bus_request_name + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_bus_request_name + 3 + + + + sd_bus_request_name + sd_bus_release_name + Request or release a well-known name on a bus + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_request_name + sd_bus* bus + const char *name + uint64_t flags + + + + int sd_bus_release_name + sd_bus* bus + const char *name + + + + + + Description + + sd_bus_request_name() requests + a well-known name on a bus. It takes a bus connection, + a valid bus name and a flags parameter. The flags + parameter is a combination of the following + flags: + + + + SD_BUS_NAME_ALLOW_REPLACEMENT + + After acquiring the + name successfully, permit other peers + to take over the name when they try to + acquire it with the + SD_BUS_NAME_REPLACE_EXISTING + flag set. If + SD_BUS_NAME_ALLOW_REPLACEMENT + is not set on the original request, + such a request by other peers will be + denied. + + + + SD_BUS_NAME_REPLACE_EXISTING + + Take over the name + if it is already acquired by another + peer, and that other peer has permitted + takeover by setting + SD_BUS_NAME_ALLOW_REPLACEMENT + while acquiring it. + + + + SD_BUS_NAME_QUEUE + + Queue the acquisition + of the name when the name is already + taken. + + + + sd_bus_release_name() releases + an acquired well-known name. It takes a bus connection + and a valid bus name as parameters. + + + + Return Value + + On success, these calls return 0 or a positive + integer. On failure, these calls return a negative + errno-style error code. + + If SD_BUS_NAME_QUEUE is + specified, sd_bus_request_name() + will return 0 when the name is already taken by + another peer and the client has been added to the + queue for the name. In that case, the caller can + subscribe to NameOwnerChanged + signals to be notified when the name is successfully + acquired. sd_bus_request_name() + returns > 0 when the name has immediately been + acquired successfully. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EALREADY + + The caller already is + the owner of the specified + name. + + + + -EEXIST + + 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. + + + + -ESRCH + + It was attempted to + release a name that is currently not + registered on the + bus. + + + + -EADDRINUSE + + It was attempted to + release a name that is owned by a + different peer on the + bus. + + + + -EINVAL + + A specified parameter + is invalid. + + + + -ENOTCONN + + The bus connection has + been disconnected. + + + + -ECHILD + + The bus connection has + been created in a different process + than the current one. + + + + + + Notes + + The sd_bus_acquire_name() + and sd_bus_release_name() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_new3 + + + + diff --git a/man/sd_get_seats.xml b/man/sd_get_seats.xml new file mode 100644 index 0000000..0fc8243 --- /dev/null +++ b/man/sd_get_seats.xml @@ -0,0 +1,141 @@ + + + + + + + + + sd_get_seats + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_get_seats + 3 + + + + sd_get_seats + sd_get_sessions + sd_get_uids + sd_get_machine_names + Determine available seats, sessions, logged in users and virtual machines/containers + + + + + #include <systemd/sd-login.h> + + + int sd_get_seats + char*** seats + + + + int sd_get_sessions + char*** sessions + + + + int sd_get_uids + uid_t** users + + + + int sd_get_machine_names + char*** machines + + + + + + + Description + + sd_get_seats() may be used + to determine all currently available local + seats. Returns a NULL terminated array of seat + identifiers. The returned array and all strings it + references need to be freed with the libc + free3 + call after use. Note that instead of an empty array + NULL may be returned and should be considered + equivalent to an empty array. + + Similarly, sd_get_sessions() may + be used to determine all current login sessions. + + Similarly, sd_get_uids() may + be used to determine all Unix users who currently have login sessions. + + Similarly, + sd_get_machine_names() may be + used to determine all current virtual machines and + containers on the system. + + Note that the returned lists are not sorted and in an undefined order. + + + + Return Value + + On success, sd_get_seats(), + sd_get_sessions(), + sd_get_uids() and + sd_get_machine_names() return the + number of entries in the arrays. On failure, these + calls return a negative errno-style error code. + + + + Notes + + The sd_get_seats(), + sd_get_sessions(), + sd_get_uids() and + sd_get_machine_names() interfaces + are available as a shared library, which can be compiled + and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-login3, + sd_session_get_seat3 + + + + diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml new file mode 100644 index 0000000..cce3979 --- /dev/null +++ b/man/sd_id128_get_machine.xml @@ -0,0 +1,137 @@ + + + + + + + + + sd_id128_get_machine + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_id128_get_machine + 3 + + + + sd_id128_get_machine + sd_id128_get_boot + Retrieve 128-bit IDs + + + + + #include <systemd/sd-id128.h> + + + int sd_id128_get_machine + sd_id128_t* ret + + + + int sd_id128_get_boot + sd_id128_t* ret + + + + + + + Description + + sd_id128_get_machine() + returns the machine ID of the executing host. This + reads and parses the + machine-id5 + file. This function caches the machine ID internally + to make retrieving the machine ID a cheap + operation. + + sd_id128_get_boot() returns + the boot ID of the executing kernel. This reads and + parses the + /proc/sys/kernel/random/boot_id + file exposed by the kernel. It is randomly generated + early at boot and is unique for every running kernel + instance. See + random4 + for more information. This function also internally + caches the returned ID to make this call a cheap + operation. + + Note that + sd_id128_get_boot() always returns + a UUID v4 compatible + ID. sd_id128_get_machine() will + also return a UUID v4-compatible ID on new + installations but might not on older. It is possible + to convert the machine ID into a UUID v4-compatible + one. For more information, see + machine-id5. + + For more information about the + sd_id128_t type see + sd-id1283. + + + + Return Value + + The two calls return 0 on success (in which + case ret is filled in), or a + negative errno-style error code. + + + + Notes + + The sd_id128_get_machine() + and sd_id128_get_boot() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-id1283, + machine-id5, + random4, + sd_id128_randomize3 + + + + diff --git a/man/sd_id128_randomize.xml b/man/sd_id128_randomize.xml new file mode 100644 index 0000000..7e8c646 --- /dev/null +++ b/man/sd_id128_randomize.xml @@ -0,0 +1,116 @@ + + + + + + + + + sd_id128_randomize + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_id128_randomize + 3 + + + + sd_id128_randomize + Generate 128-bit IDs + + + + + #include <systemd/sd-id128.h> + + + int sd_id128_randomize + sd_id128_t* ret + + + + + + + Description + + sd_id128_randomize() + generates a new randomized 128-bit ID and returns it + in ret. Every invocation + returns a new randomly generated ID. This uses the + /dev/urandom kernel random number + generator. + + Note that + sd_id128_randomize() always returns + a UUID v4-compatible ID. + + For more information about the + sd_id128_t type, see + sd-id1283. + + journalctl1's + option may be used as a + command-line front-end for + sd_id128_randomize(). + + + + Return Value + + The call returns 0 on success (in which + case ret is filled in), or a + negative errno-style error code. + + + + Notes + + The sd_id128_randomize() interface + is available as a shared library, which can be compiled + and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-id1283, + machine-id5, + random4, + sd_id128_get_machine3 + + + + diff --git a/man/sd_id128_to_string.xml b/man/sd_id128_to_string.xml new file mode 100644 index 0000000..72a67dc --- /dev/null +++ b/man/sd_id128_to_string.xml @@ -0,0 +1,136 @@ + + + + + + + + + sd_id128_to_string + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_id128_to_string + 3 + + + + sd_id128_to_string + sd_id128_from_string + Format or parse 128-bit IDs as strings + + + + + #include <systemd/sd-id128.h> + + + char* sd_id128_to_string + sd_id128_t id, char s[33] + + + + int sd_id128_from_string + const char* s, sd_id128_t* ret + + + + + + + Description + + sd_id128_to_string() + formats a 128-bit ID as a character string. It expects + the ID and a string array capable of storing 33 + characters. The ID will be formatted as 32 lowercase + hexadecimal digits and be terminated by a + NUL byte. + + sd_id128_from_string() + implements the reverse operation: it takes a 33 + character string with 32 hexadecimal digits (either + lowercase or uppercase, terminated by + NUL) and parses them back into a + 128-bit ID returned in + ret. Alternatively, this call + can also parse a 37-character string with a 128-bit ID + formatted as RFC UUID. + + For more information about the + sd_id128_t type see + sd-id1283. Note + that these calls operate the same way on all + architectures, i.e. the results do not depend on + endianness. + + When formatting a 128-bit ID into a string, it is + often easier to use a format string for + printf3. This + is easily done using the + SD_ID128_FORMAT_STR and + SD_ID128_FORMAT_VAL() macros. For + more information see + sd-id1283. + + + + Return Value + + sd_id128_to_string() always + succeeds and returns a pointer to the string array + passed in. sd_id128_from_string + returns 0 on success, in which case + ret is filled in, or a negative + errno-style error code. + + + + Notes + + The sd_id128_to_string() + and sd_id128_from_string() interfaces are + available as a shared library, which can be compiled and + linked to with the libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-id1283, + printf3 + + + + diff --git a/man/sd_is_fifo.xml b/man/sd_is_fifo.xml index f6fafab..bb851d1 100644 --- a/man/sd_is_fifo.xml +++ b/man/sd_is_fifo.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd_is_fifo @@ -48,12 +49,13 @@ sd_is_socket_inet sd_is_socket_unix sd_is_mq + sd_is_special Check the type of a file descriptor - #include "sd-daemon.h" + #include <systemd/sd-daemon.h> int sd_is_fifo @@ -93,6 +95,12 @@ const char *path + + int sd_is_special + int fd + const char *path + + @@ -102,19 +110,22 @@ sd_is_fifo() may be called to check whether the specified file descriptor refers to a FIFO or pipe. If the path - parameter is not NULL, it is checked whether the FIFO - is bound to the specified file system path. + parameter is not NULL, it is + checked whether the FIFO is bound to the specified + file system path. sd_is_socket() may be called to check whether the specified file descriptor - refers to a socket. It the + refers to a socket. If the family parameter is not - AF_UNSPEC it is checked whether the socket is of the - specified family (AF_UNIX, AF_INET, ...). If the - type parameter is not 0 it is + AF_UNSPEC, it is checked whether + the socket is of the specified family (AF_UNIX, + AF_INET, ...). If the + type parameter is not 0, it is checked whether the socket is of the specified type - (SOCK_STREAM, SOCK_DGRAM, ...). If the - listening parameter is positive + (SOCK_STREAM, + SOCK_DGRAM, ...). If the + listening parameter is positive, it is checked whether the socket is in accepting mode, i.e. listen() has been called for it. If listening is 0, it is @@ -129,27 +140,37 @@ optionally checks the IPv4 or IPv6 port number the socket is bound to, unless port is zero. For this call family - must be passed as either AF_UNSPEC, AF_INET or - AF_INET6. + must be passed as either AF_UNSPEC, AF_INET, or + AF_INET6. sd_is_socket_unix() is - similar to sd_is_socket(), but - optionally checks the AF_UNIX path the socket is bound + similar to sd_is_socket() but + optionally checks the AF_UNIX path the socket is bound to, unless the path parameter - is NULL. For normal file system AF_UNIX sockets set - the length parameter to 0. For - Linux abstract namespace sockets set the + is NULL. For normal file system AF_UNIX sockets, + set the length parameter to 0. For + Linux abstract namespace sockets, set the length to the size of the - address, including the initial 0 byte and set + address, including the initial 0 byte, and set the path to the initial 0 byte of the socket address. sd_is_mq() may be called to check whether the specified file descriptor refers to a POSIX message queue. If the - path parameter is not NULL, it - is checked whether the message queue is bound to the - specified name. + path parameter is not + NULL, it is checked whether the + message queue is bound to the specified name. + + sd_is_special() may be + called to check whether the specified file descriptor + refers to a special file. If the + path parameter is not + NULL, it is checked whether the file + descriptor is bound to the specified file + name. Special files in this context are character + device nodes and files in /proc + or /sys. @@ -157,7 +178,7 @@ On failure, these calls return a negative errno-style error code. If the file descriptor is of - the specified type and bound to the specified address + the specified type and bound to the specified address, a positive return value is returned, otherwise zero. @@ -165,49 +186,19 @@ Notes - These functions are provided by the reference - implementation of APIs for new-style daemons and - distributed with the systemd package. The algorithms - they implement are simple, and can easily be - reimplemented in daemons if it is important to support - this interface without using the reference - implementation. + Internally, these function use a combination of fstat() and getsockname() to check the file descriptor type and where it is bound to. - - For details about the algorithms check the - liberally licensed reference implementation sources: - - resp. - - sd_is_fifo() and the - related functions are implemented in the reference - implementation's sd-daemon.c and - sd-daemon.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming these APIs - may copy the implementation into their source - tree. For more details about the reference - implementation see - sd_daemon7. - - These functions continue to work as described, - even if -DDISABLE_SYSTEMD is set during - compilation. See Also systemd1, - sd-daemon7, + sd-daemon3, sd_listen_fds3, systemd.service5, systemd.socket5 diff --git a/man/sd_journal_add_match.xml b/man/sd_journal_add_match.xml new file mode 100644 index 0000000..d776b14 --- /dev/null +++ b/man/sd_journal_add_match.xml @@ -0,0 +1,220 @@ + + + + + + + + + sd_journal_add_match + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_add_match + 3 + + + + sd_journal_add_match + sd_journal_add_disjunction + sd_journal_add_conjunction + sd_journal_flush_matches + Add or remove entry matches + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_add_match + sd_journal* j + const void* data + size_t size + + + + int sd_journal_add_disjunction + sd_journal* j + + + + int sd_journal_add_conjunction + sd_journal* j + + + + void sd_journal_flush_matches + sd_journal* j + + + + + + Description + + sd_journal_add_match() adds + a match by which to filter the entries of the journal + file. Matches applied with this call will filter what + can be iterated through and read from the journal file + via calls like + sd_journal_next3 + and + sd_journal_get_data3. Matches + are of the form FIELD=value, where + the field part is a short uppercase string consisting + only of 0-9, A-Z and the underscore. It may not begin + with two underscores or be the empty string. The value + part may be any value, including binary. If a match is + applied, only entries with this field set will be + iterated. Multiple matches may be active at the same + time: If they apply to different fields, only entries + with both fields set like this will be iterated. If + they apply to the same fields, only entries where the + field takes one of the specified values will be + iterated. Well known fields are documented in + systemd.journal-fields7. Whenever + a new match is added the current entry position is + reset, and + sd_journal_next3 (or a similar call) + needs to be called before entries can be read + again. + + sd_journal_add_disjunction() + may be used to insert a disjunction (i.e. logical OR) + in the match list. If this call is invoked, all + previously added matches since the last invocation of + sd_journal_add_disjunction() or + sd_journal_add_conjunction() are + combined in an OR with all matches added afterwards, + until + sd_journal_add_disjunction() or + sd_journal_add_conjunction() is + invoked again to begin the next OR or AND + term. + + sd_journal_add_conjunction() + may be used to insert a conjunction (i.e. logical AND) + in the match list. If this call is invoked, all + previously added matches since the last invocation of + sd_journal_add_conjunction() are + combined in an AND with all matches added afterwards, + until + sd_journal_add_conjunction() is + invoked again to begin the next AND term. The + combination of + sd_journal_add_match(), + sd_journal_add_disjunction() and + sd_journal_add_conjunction() may + be used to build complex search terms, even though + full logical expressions are not available. Note that + sd_journal_add_conjunction() + operates one level 'higher' than + sd_journal_add_disjunction(). It + is hence possible to build an expression of AND terms, + consisting of OR terms, consisting of AND terms, + consisting of OR terms of matches (the latter OR + expression is implicitly created for matches with the + same field name, see above). + + sd_journal_flush_matches() + may be used to flush all matches, disjunction and + conjunction terms again. After this call all filtering + is removed and all entries in the journal will be + iterated again. + + Note that filtering via matches only applies to + the way the journal is read, it has no effect on storage + on disk. + + + + Return Value + + sd_journal_add_match(), + sd_journal_add_disjunction() and + sd_journal_add_conjunction() + return 0 on success or a negative errno-style error + code. sd_journal_flush_matches() + returns nothing. + + + + Notes + + The sd_journal_add_match(), + sd_journal_add_disjunction(), + sd_journal_add_conjunction() and + sd_journal_flush_matches() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + The following example adds matches to a journal + context object to iterate only through messages + generated by the Avahi service at the four error log + levels, plus all messages of the message ID + 03bb1dab98ab4ecfbf6fff2738bdd964 coming from any + service (this example lacks the necessary error + checking): + + ... +int add_matches(sd_journal *j) { + sd_journal_add_match(j, "_SYSTEMD_UNIT=avahi-daemon.service", 0); + sd_journal_add_match(j, "PRIORITY=0", 0); + sd_journal_add_match(j, "PRIORITY=1", 0); + sd_journal_add_match(j, "PRIORITY=2", 0); + sd_journal_add_match(j, "PRIORITY=3", 0); + sd_journal_add_disjunction(j); + sd_journal_add_match(j, "MESSAGE_ID=03bb1dab98ab4ecfbf6fff2738bdd964", 0); +} + + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3, + systemd.journal-fields7 + + + + diff --git a/man/sd_journal_get_catalog.xml b/man/sd_journal_get_catalog.xml new file mode 100644 index 0000000..2495648 --- /dev/null +++ b/man/sd_journal_get_catalog.xml @@ -0,0 +1,141 @@ + + + + + + + + + sd_journal_get_catalog + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_catalog + 3 + + + + sd_journal_get_catalog + sd_journal_get_catalog_for_message_id + Retrieve message catalog entry + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_catalog + sd_journal* j + char** ret + + + + int sd_journal_get_catalog_for_message_id + sd_id128_t id + char** ret + + + + + + + + Description + + sd_journal_get_catalog() + retrieves a message catalog entry for the current + journal entry. This will look up an entry in the + message catalog by using the + MESSAGE_ID= field of the current + journal entry. Before returning the entry all journal + field names in the catalog entry text enclosed in "@" + will be replaced by the respective field values of the + current entry. If a field name referenced in the + message catalog entry does not exist, in the current + journal entry, the "@" will be removed, but the field + name otherwise left untouched. + + sd_journal_get_catalog_for_message_id() + works similar to + sd_journal_get_catalog() but the + entry is looked up by the specified message ID (no + open journal context is necessary for this), and no + field substitution is performed. + + For more information about the journal message + catalog please refer to the Journal + Message Catalogs documentation page. + + + + Return Value + + sd_journal_get_catalog() + and + sd_journal_get_catalog_for_message_id() + return 0 on success or a negative errno-style error + code. If no matching message catalog entry is found, + -ENOENT is returned. + + On successful return, ret + points to a new string, which must be freed with + free3. + + + + + Notes + + The sd_journal_get_catalog() and + sd_journal_get_catalog_for_message_id() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + systemd.journal-fields7, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3 + malloc3 + + + + diff --git a/man/sd_journal_get_cursor.xml b/man/sd_journal_get_cursor.xml new file mode 100644 index 0000000..4410d6e --- /dev/null +++ b/man/sd_journal_get_cursor.xml @@ -0,0 +1,150 @@ + + + + + + + + + sd_journal_get_cursor + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_cursor + 3 + + + + sd_journal_get_cursor + sd_journal_test_cursor + Get cursor string for or test cursor string against the current journal entry + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_cursor + sd_journal* j + char ** cursor + + + + int sd_journal_test_cursor + sd_journal* j + const char * cursor + + + + + + + Description + + sd_journal_get_cursor() + returns a cursor string for the current journal + entry. A cursor is a serialization of the current + journal position formatted as text. The string only + contains printable characters and can be passed around + in text form. The cursor identifies a journal entry + globally and in a stable way and may be used to later + seek to it via + sd_journal_seek_cursor3. The + cursor string should be considered opaque and not be + parsed by clients. Seeking to a cursor position + without the specific entry being available locally + will seek to the next closest (in terms of time) + available entry. The call takes two arguments: a + journal context object and a pointer to a string + pointer where the cursor string will be placed. The + string is allocated via libc + malloc3 + and should be freed after use with + free3. + + Note that + sd_journal_get_cursor() will not + work before + sd_journal_next3 + (or related call) has been called at least once, in + order to position the read pointer at a valid + entry. + + sd_journal_test_cursor() + may be used to check whether the current position in + the journal matches the specified cursor. This is + useful since cursor strings do not uniquely identify + an entry: the same entry might be referred to by + multiple different cursor strings, and hence string + comparing cursors is not possible. Use this call to + verify after an invocation of + sd_journal_seek_cursor3 + whether the entry being sought to was actually found + in the journal or the next closest entry was used + instead. + + + + Return Value + + sd_journal_get_cursor() + returns 0 on success or a negative errno-style error + code. sd_journal_test_cursor() + returns positive if the current entry matches the + specified cursor, 0 if it does not match the specified + cursor or a negative errno-style error code on + failure. + + + + Notes + + The sd_journal_get_cursor() + and sd_journal_test_cursor() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_seek_cursor3 + + + + diff --git a/man/sd_journal_get_cutoff_realtime_usec.xml b/man/sd_journal_get_cutoff_realtime_usec.xml new file mode 100644 index 0000000..d32ab01 --- /dev/null +++ b/man/sd_journal_get_cutoff_realtime_usec.xml @@ -0,0 +1,144 @@ + + + + + + + + + sd_journal_get_cutoff_realtime_usec + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_cutoff_realtime_usec + 3 + + + + sd_journal_get_cutoff_realtime_usec + sd_journal_get_cutoff_monotonic_usec + Read cut-off timestamps from the current journal entry + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_cutoff_realtime_usec + sd_journal* j + uint64_t* from + uint64_t* to + + + + int sd_journal_get_cutoff_monotonic_usec + sd_journal* j + sd_id128_t boot_id + uint64_t* from + uint64_t* to + + + + + + + Description + + sd_journal_get_cutoff_realtime_usec() + gets the realtime (wallclock) timestamps of the first + and last entries accessible in the journal. It takes + three arguments: the journal context object and two + pointers to 64-bit unsigned integers to store the + timestamps in. The timestamps are in microseconds + since the epoch, + i.e. CLOCK_REALTIME. Either one + of the two timestamp arguments may be passed as + NULL in case the timestamp is not + needed, but not both. + + sd_journal_get_cutoff_monotonic_usec() + gets the monotonic timestamps of the first and last + entries accessible in the journal. It takes three + arguments: the journal context object, a 128-bit + identifier for the boot, and two pointers to 64-bit + unsigned integers to store the timestamps. The + timestamps are in microseconds since boot-up of the + specific boot, + i.e. CLOCK_MONOTONIC. Since the + monotonic clock begins new with every reboot it only + defines a well-defined point in time when used + together with an identifier identifying the boot, see + sd_id128_get_boot3 + for more information. The function will return the + timestamps for the boot identified by the passed boot + ID. Either one of the two timestamp arguments may be + passed as NULL in case the + timestamp is not needed, but not both. + + + + Return Value + + sd_journal_get_cutoff_realtime_usec() + and + sd_journal_get_cutoff_monotonic_usec() + return 1 on success, 0 if not suitable entries are in + the journal or a negative errno-style error code. + + + + Notes + + The + sd_journal_get_cutoff_realtime_usec() + and + sd_journal_get_cutoff_monotonic_usec() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_get_realtime_usec3, + sd_id128_get_boot3, + clock_gettime2 + + + + diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml new file mode 100644 index 0000000..c01db4e --- /dev/null +++ b/man/sd_journal_get_data.xml @@ -0,0 +1,250 @@ + + + + + + + + + sd_journal_get_data + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_data + 3 + + + + sd_journal_get_data + sd_journal_enumerate_data + sd_journal_restart_data + SD_JOURNAL_FOREACH_DATA + sd_journal_set_data_threshold + sd_journal_get_data_threshold + Read data fields from the current journal entry + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_data + sd_journal* j + const char* field + const void** data + size_t* length + + + + int sd_journal_enumerate_data + sd_journal* j + const void** data + size_t* length + + + + void sd_journal_restart_data + sd_journal* j + + + + SD_JOURNAL_FOREACH_DATA + sd_journal* j + const void* data + size_t length + + + + int sd_journal_set_data_threshold + sd_journal* j + size_t sz + + + + int sd_journal_get_data_threshold + sd_journal* j + size_t* sz + + + + + + Description + + sd_journal_get_data() gets + the data object associated with a specific field from + the current journal entry. It takes four arguments: + the journal context object, a string with the field + name to request, plus a pair of pointers to + pointer/size variables where the data object and its + size shall be stored in. The field name should be an + entry field name. Well-known field names are listed in + systemd.journal-fields7. The + returned data is in a read-only memory map and is only + valid until the next invocation of + sd_journal_get_data() or + sd_journal_enumerate_data(), or + the read pointer is altered. Note that the data + returned will be prefixed with the field name and + '='. Also note that by default data fields larger than + 64K might get truncated to 64K. This threshold may be + changed and turned off with + sd_journal_set_data_threshold() (see + below). + + sd_journal_enumerate_data() + may be used to iterate through all fields of the + current entry. On each invocation the data for the + next field is returned. The order of these fields is + not defined. The data returned is in the same format + as with sd_journal_get_data() and + also follows the same life-time semantics. + + sd_journal_restart_data() + resets the data enumeration index to the beginning of + the entry. The next invocation of + sd_journal_enumerate_data() will return the first + field of the entry again. + + Note that the + SD_JOURNAL_FOREACH_DATA() macro + may be used as a handy wrapper around + sd_journal_restart_data() and + sd_journal_enumerate_data(). + + Note that these functions will not work before + sd_journal_next3 + (or related call) has been called at least + once, in order to position the read pointer at a valid entry. + + sd_journal_set_data_threshold() + may be used to change the data field size threshold + for data returned by + sd_journal_get_data(), + sd_journal_enumerate_data() and + sd_journal_enumerate_unique(). This + threshold is a hint only: it indicates that the client + program is interested only in the initial parts of the + data fields, up to the threshold in size -- but the + library might still return larger data objects. That + means applications should not rely exclusively on this + setting to limit the size of the data fields returned, + but need to apply a explicit size limit on the + returned data as well. This threshold defaults to 64K + by default. To retrieve the complete data fields this + threshold should be turned off by setting it to 0, so + that the library always returns the complete data + objects. It is recommended to set this threshold as + low as possible since this relieves the library from + having to decompress large compressed data objects in + full. + + sd_journal_get_data_threshold() + returns the currently configured data field size + threshold. + + + + Return Value + + sd_journal_get_data() + returns 0 on success or a negative errno-style error + code. If the current entry does not include the + specified field, -ENOENT is returned. If + sd_journal_next3 + has not been called at least once, -EADDRNOTAVAIL is + returned. sd_journal_enumerate_data() + returns a positive integer if the next field has been + read, 0 when no more fields are known, or a negative + errno-style error + code. sd_journal_restart_data() + returns + nothing. sd_journal_set_data_threshold() + and sd_journal_get_threshold() + return 0 on success or a negative errno-style error + code. + + + + Notes + + The sd_journal_get_data(), + sd_journal_enumerate_data(), + sd_journal_restart_data(), + sd_journal_set_data_threshold() + and + sd_journal_get_data_threshold() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + See + sd_journal_next3 + for a complete example how to use + sd_journal_get_data(). + + Use the + SD_JOURNAL_FOREACH_DATA macro to + iterate through all fields of the current journal + entry: + + ... +int print_fields(sd_journal *j) { + const void *data; + size_t l; + SD_JOURNAL_FOREACH_DATA(j, data, length) + printf("%.*s\n", (int) length, data); +} +... + + + + + See Also + + + systemd1, + systemd.journal-fields7, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_realtime_usec3, + sd_journal_query_unique3 + + + + diff --git a/man/sd_journal_get_fd.xml b/man/sd_journal_get_fd.xml new file mode 100644 index 0000000..16aeea2 --- /dev/null +++ b/man/sd_journal_get_fd.xml @@ -0,0 +1,349 @@ + + + + + + + + + sd_journal_get_fd + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_fd + 3 + + + + sd_journal_get_fd + sd_journal_get_events + sd_journal_get_timeout + sd_journal_process + sd_journal_wait + sd_journal_reliable_fd + SD_JOURNAL_NOP + SD_JOURNAL_APPEND + SD_JOURNAL_INVALIDATE + Journal change notification + interface + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_fd + sd_journal* j + + + + int sd_journal_get_events + sd_journal* j + + + + int sd_journal_get_timeout + sd_journal* j + uint64_t* timeout_usec + + + + int sd_journal_process + sd_journal* j + + + + int sd_journal_wait + sd_journal* j + uint64_t timeout_usec + + + + int sd_journal_reliable_fd + sd_journal* j + + + + + + + Description + + sd_journal_get_fd() returns + a file descriptor that may be asynchronously polled in + an external event loop and is signaled as soon as the + journal changes, because new entries or files were + added, rotation took place, or files have been + deleted, and similar. The file descriptor is suitable + for usage in + poll2. Use + sd_journal_get_events() for an + events mask to watch for. The call takes one argument: + the journal context object. Note that not all file + systems are capable of generating the necessary events + for wakeups from this file descriptor for changes to + be noticed immediately. In particular network files + systems do not generate suitable file change events in + all cases. Cases like this can be detected with + sd_journal_reliable_fd(), + below. sd_journal_get_timeout() + will ensure in these cases that wake-ups happen + frequently enough for changes to be noticed, although + with a certain latency. + + sd_journal_get_events() + will return the poll() mask to + wait for. This function will return a combination of + POLLIN and + POLLOUT and similar to fill into + the .events field of + struct pollfd. + + sd_journal_get_timeout() + will return a timeout value for usage in + poll(). This returns a value in + microseconds since the epoch of + CLOCK_MONOTONIC for timing out + poll() in + timeout_usec. See + clock_gettime2 + for details about + CLOCK_MONOTONIC. If there is no + timeout to wait for, this will fill in + (uint64_t) -1 instead. Note that + poll() takes a relative timeout + in milliseconds rather than an absolute timeout in + microseconds. To convert the absolute 'us' timeout + into relative 'ms', use code like the + following: + + uint64_t t; +int msec; +sd_journal_get_timeout(m, &t); +if (t == (uint64_t) -1) + msec = -1; +else { + struct timespec ts; + uint64_t n; + clock_getttime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; +} + + The code above does not do any error checking + for brevity's sake. The calculated msec + integer can be passed directly as + poll()'s timeout + parameter. + + After each poll() wake-up + sd_journal_process() needs to be + called to process events. This call will also indicate + what kind of change has been detected (see below; note + that spurious wake-ups are possible). + + A synchronous alternative for using + sd_journal_get_fd(), + sd_journal_get_events(), + sd_journal_get_timeout() and + sd_journal_process() is + sd_journal_wait(). It will + synchronously wait until the journal gets changed. The + maximum time this call sleeps may be controlled with + the timeout_usec + parameter. Pass (uint64_t) -1 to + wait indefinitely. Internally this call simply + combines sd_journal_get_fd(), + sd_journal_get_events(), + sd_journal_get_timeout(), + poll() and + sd_journal_process() into + one. + + sd_journal_reliable_fd() + may be used to check whether the wakeup events from + the file descriptor returned by + sd_journal_get_fd() are known to + be immediately triggered. On certain file systems + where file change events from the OS are not available + (such as NFS) changes need to be polled for + repeatedly, and hence are detected only with a certain + latency. This call will return a positive value if the + journal changes are detected immediately and zero when + they need to be polled for and hence might be noticed + only with a certain latency. Note that there's usually + no need to invoke this function directly as + sd_journal_get_timeout() on these + file systems will ask for timeouts explicitly + anyway. + + + + Return Value + + sd_journal_get_fd() returns + a valid file descriptor on success or a negative + errno-style error code. + + sd_journal_get_events() + returns a combination of POLLIN, + POLLOUT and suchlike on success or + a negative errno-style error code. + + sd_journal_reliable_fd() + returns a positive integer if the file descriptor + returned by sd_journal_get_fd() + will generate wake-ups immediately for all journal + changes. Returns 0 if there might be a latency + involved. + + sd_journal_process() and + sd_journal_wait() return one of + SD_JOURNAL_NOP, + SD_JOURNAL_APPEND or + SD_JOURNAL_INVALIDATE on success or + a negative errno-style error code. If + SD_JOURNAL_NOP is returned, the + journal did not change since the last invocation. If + SD_JOURNAL_APPEND is returned, new + entries have been appended to the end of the + journal. If SD_JOURNAL_INVALIDATE, + journal files were added or removed (possibly due to + rotation). In the latter event, live-view UIs should + probably refresh their entire display, while in the + case of SD_JOURNAL_APPEND, it is + sufficient to simply continue reading at the previous + end of the journal. + + + + Notes + + The sd_journal_get_fd(), + sd_journal_get_events(), + sd_journal_reliable_fd(), + sd_journal_process() and + sd_journal_wait() interfaces are + available as a shared library, which can be compiled and + linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + Iterating through the journal, in a live view tracking all changes: + + #include <stdio.h> +#include <string.h> +#include <systemd/sd-journal.h> + +int main(int argc, char *argv[]) { + int r; + sd_journal *j; + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); + return 1; + } + for (;;) { + const void *d; + size_t l; + r = sd_journal_next(j); + if (r < 0) { + fprintf(stderr, "Failed to iterate to next entry: %s\n", strerror(-r)); + break; + } + if (r == 0) { + /* Reached the end, let's wait for changes, and try again */ + r = sd_journal_wait(j, (uint64_t) -1); + if (r < 0) { + fprintf(stderr, "Failed to wait for changes: %s\n", strerror(-r)); + break; + } + continue; + } + r = sd_journal_get_data(j, "MESSAGE", &d, &l); + if (r < 0) { + fprintf(stderr, "Failed to read message field: %s\n", strerror(-r)); + continue; + } + printf("%.*s\n", (int) l, (const char*) d); + } + sd_journal_close(j); + return 0; +} + + Waiting with poll() (this + example lacks all error checking for the sake of + simplicity): + + #include <sys/poll.h> +#include <systemd/sd-journal.h> + +int wait_for_changes(sd_journal *j) { + struct pollfd pollfd; + int msec; + + sd_journal_get_timeout(m, &t); + if (t == (uint64_t) -1) + msec = -1; + else { + struct timespec ts; + uint64_t n; + clock_getttime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; + } + + pollfd.fd = sd_journal_get_fd(j); + pollfd.events = sd_journal_get_events(j); + poll(&pollfd, 1, msec); + return sd_journal_process(j); +} + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + poll2, + clock_gettime2 + + + + diff --git a/man/sd_journal_get_realtime_usec.xml b/man/sd_journal_get_realtime_usec.xml new file mode 100644 index 0000000..a9e6f07 --- /dev/null +++ b/man/sd_journal_get_realtime_usec.xml @@ -0,0 +1,146 @@ + + + + + + + + + sd_journal_get_realtime_usec + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_realtime_usec + 3 + + + + sd_journal_get_realtime_usec + sd_journal_get_monotonic_usec + Read timestamps from the current journal entry + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_realtime_usec + sd_journal* j + uint64_t* usec + + + + int sd_journal_get_monotonic_usec + sd_journal* j + uint64_t* usec + sd_id128_t* boot_id + + + + + + + Description + + sd_journal_get_realtime_usec() + gets the realtime (wallclock) timestamp of the + current journal entry. It takes two arguments: the + journal context object and a pointer to a 64-bit + unsigned integer to store the timestamp in. The + timestamp is in microseconds since the epoch, + i.e. CLOCK_REALTIME. + + sd_journal_get_monotonic_usec() + gets the monotonic timestamp of the current journal + entry. It takes three arguments: the journal context + object, a pointer to a 64-bit unsigned integer to + store the timestamp in, as well as a 128-bit ID buffer + to store the boot ID of the monotonic timestamp. + The timestamp is in microseconds since boot-up of + the specific boot, + i.e. CLOCK_MONOTONIC. Since the + monotonic clock begins new with every reboot, it only + defines a well-defined point in time when used + together with an identifier identifying the boot. See + sd_id128_get_boot3 + for more information. If the boot ID parameter is + passed NULL, the function will + fail if the monotonic timestamp of the current entry + is not of the current system boot. + + Note that these functions will not work before + sd_journal_next3 + (or related call) has been called at least + once, in order to position the read pointer at a valid entry. + + + + Return Value + + sd_journal_get_realtime_usec() + and + sd_journal_get_monotonic_usec() + returns 0 on success or a negative errno-style error + code. If the boot ID parameter was passed NULL and the + monotonic timestamp of the current journal entry is + not of the current system boot, -ESTALE is returned by sd_journal_get_monotonic_usec(). + + + + Notes + + The + sd_journal_get_realtime_usec() + and + sd_journal_get_monotonic_usec() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3, + sd_id128_get_boot3, + clock_gettime2, + sd_journal_get_cutoff_realtime_usec3 + + + + diff --git a/man/sd_journal_get_usage.xml b/man/sd_journal_get_usage.xml new file mode 100644 index 0000000..e677b5f --- /dev/null +++ b/man/sd_journal_get_usage.xml @@ -0,0 +1,103 @@ + + + + + + + + + sd_journal_get_usage + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_get_usage + 3 + + + + sd_journal_get_usage + Journal disk usage + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_get_usage + sd_journal* j + uint64_t* bytes + + + + + + + Description + + sd_journal_get_usage() + determines the total disk space currently used by + journal files (in bytes). If + SD_JOURNAL_LOCAL_ONLY was passed + when opening the journal, this value will only reflect + the size of journal files of the local host, otherwise + of all hosts. + + + + Return Value + + sd_journal_get_usage() + returns 0 on success or a negative errno-style error + code. + + + + Notes + + The sd_journal_get_usage() + interface is available as a shared library, which can be + compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + + + + diff --git a/man/sd_journal_next.xml b/man/sd_journal_next.xml new file mode 100644 index 0000000..d3a7183 --- /dev/null +++ b/man/sd_journal_next.xml @@ -0,0 +1,213 @@ + + + + + + + + + sd_journal_next + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_next + 3 + + + + sd_journal_next + sd_journal_previous + sd_journal_next_skip + sd_journal_previous_skip + SD_JOURNAL_FOREACH + SD_JOURNAL_FOREACH_BACKWARDS + Advance or set back the read pointer in the journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_next + sd_journal* j + + + + int sd_journal_previous + sd_journal* j + + + + int sd_journal_next_skip + sd_journal* j + uint64_t skip + + + + int sd_journal_previous_skip + sd_journal* j + uint64_t skip + + + + SD_JOURNAL_FOREACH + sd_journal* j + + + + SD_JOURNAL_FOREACH_BACKWARDS + sd_journal* j + + + + + + Description + + sd_journal_next() advances + the read pointer into the journal by one entry. The + only argument taken is a journal context object as + allocated via + sd_journal_open3. After + successful invocation the entry may be read with + functions such as + sd_journal_get_data3. + + Similarly, sd_journal_previous() sets + the read pointer back one entry. + + sd_journal_next_skip() and + sd_journal_previous_skip() + advance/set back the read pointer by multiple entries + at once, as specified in the skip + parameter. + + The journal is strictly ordered by reception + time, and hence advancing to the next entry guarantees + that the entry then pointing to is later in time than + then previous one, or has the same timestamp. + + Note that + sd_journal_get_data3 + and related calls will fail unless + sd_journal_next() has been + invoked at least once in order to position the read + pointer on a journal entry. + + Note that the + SD_JOURNAL_FOREACH() macro may be used + as a wrapper around + sd_journal_seek_head3 + and sd_journal_next() in order to + make iterating through the journal easier. See below + for an example. Similarly, + SD_JOURNAL_FOREACH_BACKWARDS() + may be used for iterating the journal in reverse + order. + + + + Return Value + + The four calls return the number of entries + advanced/set back on success or a negative errno-style + error code. When the end or beginning of the journal + is reached, a number smaller than requested is + returned. More specifically, if + sd_journal_next() or + sd_journal_previous() reach the + end/beginning of the journal they will return 0, + instead of 1 when they are successful. This should be + considered an EOF marker. + + + + Notes + + The sd_journal_next(), sd_journal_previous(), + sd_journal_next_skip() and + sd_journal_previous_skip() interfaces are + available as a shared library, which can be compiled and + linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + Iterating through the journal: + + #include <stdio.h> +#include <string.h> +#include <systemd/sd-journal.h> + +int main(int argc, char *argv[]) { + int r; + sd_journal *j; + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); + return 1; + } + SD_JOURNAL_FOREACH(j) { + const char *d; + size_t l; + + r = sd_journal_get_data(j, "MESSAGE", &d, &l); + if (r < 0) { + fprintf(stderr, "Failed to read message field: %s\n", strerror(-r)); + continue; + } + + printf("%.*s\n", (int) l, d); + } + sd_journal_close(j); + return 0; +} + + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_get_data3, + sd_journal_get_realtime_usec3, + sd_journal_get_cursor3 + + + + diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml new file mode 100644 index 0000000..3fc0d0c --- /dev/null +++ b/man/sd_journal_open.xml @@ -0,0 +1,253 @@ + + + + + + + + + sd_journal_open + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_open + 3 + + + + sd_journal_open + sd_journal_open_directory + sd_journal_open_files + sd_journal_open_container + sd_journal_close + sd_journal + SD_JOURNAL_LOCAL_ONLY + SD_JOURNAL_RUNTIME_ONLY + SD_JOURNAL_SYSTEM + SD_JOURNAL_CURRENT_USER + Open the system journal for reading + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_open + sd_journal** ret + int flags + + + + int sd_journal_open_directory + sd_journal** ret + const char* path + int flags + + + + int sd_journal_open_files + sd_journal** ret + const char** paths + int flags + + + + int sd_journal_open_container + sd_journal** ret + const char* machine + int flags + + + + void sd_journal_close + sd_journal* j + + + + + + Description + + sd_journal_open() opens + the log journal for reading. It will find all journal + files automatically and interleave them automatically + when reading. As first argument it takes a pointer to + a sd_journal pointer, which on + success will contain a journal context object. The + second argument is a flags field, which may consist of + the following flags ORed together: + SD_JOURNAL_LOCAL_ONLY makes sure + only journal files generated on the local machine will + be opened. SD_JOURNAL_RUNTIME_ONLY + makes sure only volatile journal files will be opened, + excluding those which are stored on persistent + storage. SD_JOURNAL_SYSTEM + will cause journal files of system services and the + kernel (in opposition to user session processes) to + be opened. SD_JOURNAL_CURRENT_USER + will cause journal files of the current user to be + opened. If neither SD_JOURNAL_SYSTEM + nor SD_JOURNAL_CURRENT_USER are + specified, all journal file types will be opened. + + sd_journal_open_directory() + is similar to sd_journal_open() + but takes an absolute directory path as argument. All + journal files in this directory will be opened and + interleaved automatically. This call also takes a + flags argument, but it must be passed as 0 as no flags + are currently understood for this call. + + sd_journal_open_files() + is similar to sd_journal_open() + but takes a NULL-terminated list + of file paths to open. All files will be opened and + interleaved automatically. This call also takes a + flags argument, but it must be passed as 0 as no flags + are currently understood for this call. Please note + that in the case of a live journal, this function is only + useful for debugging, because individual journal files + can be rotated at any moment, and the opening of + specific files is inherently racy. + + sd_journal_open_container() + is similar to sd_journal_open() + but opens the journal files of a running + OS container. The specified machine name refers to a + container that is registered with + systemd-machined8. + + sd_journal objects cannot be + used in the child after a fork. Functions which take a + journal object as an argument + (sd_journal_next() and others) + will return -ECHILD after a fork. + + + sd_journal_close() will + close the journal context allocated with + sd_journal_open() or + sd_journal_open_directory() and + free its resources. + + When opening the journal only journal files + accessible to the calling user will be opened. If + journal files are not accessible to the caller, this + will be silently ignored. + + See + sd_journal_next3 + for an example of how to iterate through the journal + after opening it with + sd_journal_open(). + + A journal context object returned by + sd_journal_open() references a + specific journal entry as current entry, + similar to a file seek index in a classic file system + file, but without absolute positions. It may be + altered with + sd_journal_next3 + and + sd_journal_seek_head3 + and related calls. The current entry position may be + exported in cursor strings, as accessible + via + sd_journal_get_cursor3. Cursor + strings may be used to globally identify a specific + journal entry in a stable way and then later to seek + to it (or if the specific entry is not available + locally, to its closest entry in time) + sd_journal_seek_cursor3. + + Notification of journal changes is available via + sd_journal_get_fd() and related + calls. + + + + Return Value + + The sd_journal_open(), + sd_journal_open_directory(), and + sd_journal_open_files() calls + return 0 on success or a negative errno-style error + code. sd_journal_close() returns + nothing. + + + + Notes + + The sd_journal_open(), + sd_journal_open_directory() and + sd_journal_close() interfaces are + available as a shared library, which can be compiled and + linked to with the + libsystemd pkg-config1 + file. + + + + History + + sd_journal_open(), + sd_journal_close(), + SD_JOURNAL_LOCAL_ONLY, + SD_JOURNAL_RUNTIME_ONLY, + SD_JOURNAL_SYSTEM_ONLY were added + in systemd-38. + + sd_journal_open_directory() + was added in systemd-187. + + SD_JOURNAL_SYSTEM, + SD_JOURNAL_CURRENT_USER, + and sd_journal_open_files() + were added in systemd-205. + SD_JOURNAL_SYSTEM_ONLY + was deprecated. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_next3, + sd_journal_get_data3, + systemd-machined8 + + + + diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml new file mode 100644 index 0000000..c6f204b --- /dev/null +++ b/man/sd_journal_print.xml @@ -0,0 +1,265 @@ + + + + + + + + + sd_journal_print + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_print + 3 + + + + sd_journal_print + sd_journal_printv + sd_journal_send + sd_journal_sendv + sd_journal_perror + SD_JOURNAL_SUPPRESS_LOCATION + Submit log entries to the journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_print + int priority + const char* format + ... + + + + int sd_journal_printv + int priority + const char* format + va_list ap + + + + int sd_journal_send + const char* format + ... + + + + int sd_journal_sendv + const struct iovec *iov + int n + + + + int sd_journal_perror + const char* message + + + + + + + Description + + sd_journal_print() may be + used to submit simple, plain text log entries to the + system journal. The first argument is a priority + value. This is followed by a format string and its + parameters, similar to + printf3 + or + syslog3. The + priority value is one of + LOG_EMERG, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG, as defined in + syslog.h, see + syslog3 + for details. It is recommended to use this call to + submit log messages in the application locale or system + locale and in UTF-8 format, but no such restrictions + are enforced. + + sd_journal_printv() is + similar to sd_journal_print() but + takes a variable argument list encapsulated in an + object of type va_list (see + stdarg3 + for more information) instead of the format string. It + is otherwise equivalent in behavior. + + sd_journal_send() may be + used to submit structured log entries to the system + journal. It takes a series of format strings, each + immediately followed by their associated parameters, + terminated by NULL. The strings passed should be of + the format VARIABLE=value. The + variable name must be in uppercase and consist only of + characters, numbers and underscores, and may not begin + with an underscore. (All assignments that do not + follow this syntax will be ignored.) The value can be + of any size and format. It is highly recommended to + submit text strings formatted in the UTF-8 character + encoding only, and submit binary fields only when + formatting in UTF-8 strings is not sensible. A number + of well known fields are defined, see + systemd.journal-fields7 + for details, but additional application defined fields + may be used. A variable may be assigned more than one + value per entry. + + sd_journal_sendv() is + similar to sd_journal_send() but + takes an array of struct iovec (as + defined in uio.h, see + readv3 + for details) instead of the format string. Each + structure should reference one field of the entry to + submit. The second argument specifies the number of + structures in the array. + sd_journal_sendv() is + particularly useful to submit binary objects to the + journal where that is necessary. + + sd_journal_perror() is a + similar to + perror3 + and writes a message to the journal that consists of + the passed string, suffixed with ": " and a human + readable representation of the current error code + stored in + errno3. If + the message string is passed as NULL or empty string, + only the error string representation will be written, + prefixed with nothing. An additional journal field + ERRNO= is included in the entry containing the numeric + error code formatted as decimal string. The log + priority used is LOG_ERR (3). + + Note that sd_journal_send() + is a wrapper around + sd_journal_sendv() to make it + easier to use when only text strings shall be + submitted. Also, the following two calls are + mostly equivalent: + + sd_journal_print(LOG_INFO, "Hello World, this is PID %lu!", (unsigned long) getpid()); + +sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid(), + "PRIORITY=%i", LOG_INFO, + NULL); + + Note that these calls implicitly add fields for + the source file, function name and code line where + invoked. This is implemented with macros. If this is + not desired, it can be turned off by defining + SD_JOURNAL_SUPPRESS_LOCATION before including + sd-journal.h. + + syslog3 + and sd_journal_print() may + largely be used interchangeably + functionality-wise. However, note that log messages + logged via the former take a different path to the + journal server than the later, and hence global + chronological ordering between the two streams cannot + be guaranteed. Using + sd_journal_print() has the + benefit of logging source code line, filenames, and + functions as metadata along all entries, and + guaranteeing chronological ordering with structured + log entries that are generated via + sd_journal_send(). Using + syslog() has the benefit of being + more portable. + + + + Return Value + + The four calls return 0 on success or a negative + errno-style error code. The + errno3 + variable itself is not altered. + + + + Async signal safety + sd_journal_sendv() is "async signal + safe" in the meaning of signal7. + + + sd_journal_print, + sd_journal_printv, + sd_journal_send, and + sd_journal_perror are + not async signal safe. + + + + Notes + + The sd_journal_print(), + sd_journal_printv(), + sd_journal_send() and + sd_journal_sendv() interfaces + are available as a shared library, which can be compiled + and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_stream_fd3, + syslog3, + perror3, + errno3, + systemd.journal-fields7, + signal7, + socket7 + + + + diff --git a/man/sd_journal_query_unique.xml b/man/sd_journal_query_unique.xml new file mode 100644 index 0000000..6f489bb --- /dev/null +++ b/man/sd_journal_query_unique.xml @@ -0,0 +1,215 @@ + + + + + + + + + sd_journal_query_unique + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_query_unique + 3 + + + + sd_journal_query_unique + sd_journal_enumerate_unique + sd_journal_restart_unique + SD_JOURNAL_FOREACH_UNIQUE + Read unique data fields from the journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_query_unique + sd_journal* j + const char* field + + + + int sd_journal_enumerate_unique + sd_journal* j + const void** data + size_t* length + + + + void sd_journal_restart_unique + sd_journal* j + + + + SD_JOURNAL_FOREACH_UNIQUE + sd_journal* j + const void* data + size_t length + + + + + + + Description + + sd_journal_query_unique() + queries the journal for all unique values the + specified field can take. It takes two arguments: the + journal to query and the field name to look + for. Well-known field names are listed on + systemd.journal-fields7. Field + names must be specified without a trailing '='. After + this function has been executed successfully the field + values may be queried using + sd_journal_enumerate_unique(). Invoking + this call a second time will change the field name + being queried and reset the enumeration index to the + first field value that matches. + + sd_journal_enumerate_unique() + may be used to iterate through all data fields which + match the previously selected field name as set with + sd_journal_query_unique(). On + each invocation the next field data matching the field + name is returned. The order of the returned data + fields is not defined. It takes three arguments: the + journal context object, plus a pair of pointers to + pointer/size variables where the data object and its + size shall be stored in. The returned data is in a + read-only memory map and is only valid until the next + invocation of + sd_journal_enumerate_unique(). Note + that the data returned will be prefixed with the field + name and '='. Note that this call is subject to the + data field size threshold as controlled by + sd_journal_set_data_threshold(). + + sd_journal_restart_unique() + resets the data enumeration index to the beginning of + the list. The next invocation of + sd_journal_enumerate_unique() + will return the first field data matching the field + name again. + + Note that the + SD_JOURNAL_FOREACH_UNIQUE() macro + may be used as a handy wrapper around + sd_journal_restart_unique() and + sd_journal_enumerate_unique(). + + Note that these functions currently are not + influenced by matches set with + sd_journal_add_match() but this + might change in a later version of this + software. + + + + Return Value + + sd_journal_query_unique() + returns 0 on success or a negative errno-style error + code. sd_journal_enumerate_unique() + returns a positive integer if the next field data has + been read, 0 when no more fields are known, or a + negative errno-style error + code. sd_journal_restart_unique() + returns nothing. + + + + Notes + + The sd_journal_query_unique(), + sd_journal_enumerate_unique() and + sd_journal_restart_unique() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + Use the + SD_JOURNAL_FOREACH_UNIQUE macro + to iterate through all values a field of the journal + can take. The following example lists all unit names + referenced in the journal: + + #include <stdio.h> +#include <string.h> +#include <systemd/sd-journal.h> + +int main(int argc, char *argv[]) { + sd_journal *j; + const void *d; + size_t l; + int r; + + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); + return 1; + } + r = sd_journal_query_unique(j, "_SYSTEMD_UNIT"); + if (r < 0) { + fprintf(stderr, "Failed to query journal: %s\n", strerror(-r)); + return 1; + } + SD_JOURNAL_FOREACH_UNIQUE(j, d, l) + printf("%.*s\n", (int) l, (const char*) d); + sd_journal_close(j); + return 0; +} + + + + + See Also + + + systemd1, + systemd.journal-fields7, + sd-journal3, + sd_journal_open3, + sd_journal_get_data3, + sd_journal_add_match3 + + + + diff --git a/man/sd_journal_seek_head.xml b/man/sd_journal_seek_head.xml new file mode 100644 index 0000000..9ee14e4 --- /dev/null +++ b/man/sd_journal_seek_head.xml @@ -0,0 +1,179 @@ + + + + + + + + + sd_journal_seek_head + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_seek_head + 3 + + + + sd_journal_seek_head + sd_journal_seek_tail + sd_journal_seek_monotonic_usec + sd_journal_seek_realtime_usec + sd_journal_seek_cursor + Seek to a position in the + journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_seek_head + sd_journal* j + + + + int sd_journal_seek_tail + sd_journal* j + + + + int sd_journal_seek_monotonic_usec + sd_journal* j + sd_id128_t boot_id + uint64_t usec + + + + int sd_journal_seek_realtime_usec + sd_journal* j + uint64_t usec + + + + int sd_journal_seek_cursor + sd_journal* j + const char * cursor + + + + + + Description + + sd_journal_seek_head() + seeks to the beginning of the journal, i.e. the oldest + available entry. + + Similarly, + sd_journal_seek_tail() may be + used to seek to the end of the journal, i.e. the most + recent available entry. + + sd_journal_seek_monotonic_usec() + seeks to the entry with the specified monotonic + timestamp, + i.e. CLOCK_MONOTONIC. Since + monotonic time restarts on every reboot a boot ID + needs to be specified as well. + + sd_journal_seek_realtime_usec() + seeks to the entry with the specified realtime + (wallclock) timestamp, + i.e. CLOCK_REALTIME. Note that + the realtime clock is not necessarily monotonic. If a + realtime timestamp is ambiguous, it is not defined + which position is sought to. + + sd_journal_seek_cursor() + seeks to the entry located at the specified cursor + string. For details on cursors, see + sd_journal_get_cursor3. 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 + sd_journal_test_cursor3. + + 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 + sd_journal_next3 + invocation (or a similar call). Only then, entry data + may be retrieved via + sd_journal_get_data3. If + no entry exists that matches exactly the specified + seek address, the next closest is sought to. If + sd_journal_next3 + is used, the closest following entry will be sought to, + if + sd_journal_previous3 + is used the closest preceding entry is sought + to. + + + + Return Value + + The functions return 0 on success or a negative + errno-style error code. + + + + Notes + + The sd_journal_seek_head(), + sd_journal_seek_tail(), + sd_journal_seek_monotonic_usec(), + sd_journal_seek_realtime_usec(), + and sd_journal_seek_cursor() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-journal3, + sd_journal_open3, + sd_journal_next3, + sd_journal_get_data3, + sd_journal_get_cursor3, + sd_journal_get_realtime_usec3 + + + + diff --git a/man/sd_journal_stream_fd.xml b/man/sd_journal_stream_fd.xml new file mode 100644 index 0000000..e7bd661 --- /dev/null +++ b/man/sd_journal_stream_fd.xml @@ -0,0 +1,170 @@ + + + + + + + + + sd_journal_stream_fd + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_stream_fd + 3 + + + + sd_journal_stream_fd + Create log stream file descriptor to the journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_stream_fd + const char* identifier + int priority + int level_prefix + + + + + + + Description + + sd_journal_stream_fd() may + be used to create a log stream file descriptor. Log + messages written to this file descriptor as simple + newline-separated text strings are written to the + journal. This file descriptor can be used internally + by applications or be made standard output or standard + error of other processes executed. + + sd_journal_stream_fd() + takes a short program identifier string as first + argument, which will be written to the journal as + _SYSLOG_IDENTIFIER= field for each log entry (see + systemd.journal-fields7 + for more information). The second argument shall be + the default priority level for all messages. The + priority level is one of LOG_EMERG, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG, as defined in + syslog.h, see + syslog3 + for details. The third argument is a boolean: if true + kernel-style log priority level prefixes (such as + SD_WARNING) are interpreted, see + sd-daemon3 + for more information. + + It is recommended that applications log UTF-8 + messages only with this API, but this is not + enforced. + + + + + Return Value + + The call returns a valid write-only file descriptor on success or a + negative errno-style error code. + + + + Notes + + The sd_journal_stream_fd() + interface is available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + Examples + + Creating a log stream suitable for + fprintf3: + + #include <syslog.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <systemd/sd-journal.h> +#include <systemd/sd-daemon.h> + +int main(int argc, char *argv[]) { + int fd; + FILE *log; + fd = sd_journal_stream_fd("test", LOG_INFO, 1); + if (fd < 0) { + fprintf(stderr, "Failed to create stream fd: %s\n", strerror(-fd)); + return 1; + } + log = fdopen(fd, "w"); + if (!log) { + fprintf(stderr, "Failed to create file object: %m\n"); + close(fd); + return 1; + } + fprintf(log, "Hello World!\n"); + fprintf(log, SD_WARNING "This is a warning!\n"); + fclose(log); + return 0; +} + + + + + See Also + + + systemd1, + sd-journal3, + sd-daemon3, + sd_journal_print3, + syslog3, + fprintf3, + systemd.journal-fields7 + + + + diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml index 3276aff..6999db9 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd_listen_fds @@ -44,12 +45,13 @@ sd_listen_fds - Check for file descriptors passed by the init system. + SD_LISTEN_FDS_START + Check for file descriptors passed by the system manager - #include "sd-daemon.h" + #include <systemd/sd-daemon.h> #define SD_LISTEN_FDS_START 3 @@ -69,10 +71,10 @@ activation logic. If the unset_environment - parameter is non-zero + parameter is non-zero, sd_listen_fds() will unset the $LISTEN_FDS/$LISTEN_PID - environment variables before returning (regardless + environment variables before returning (regardless of whether the function call itself succeeded or not). Further calls to sd_listen_fds() will then fail, @@ -82,16 +84,16 @@ If a daemon receives more than one file descriptor, they will be passed in the same order as configured in the systemd socket definition - file. Nonetheless it is recommended to verify the + file. Nonetheless, it is recommended to verify the correct socket types before using them. To simplify - this checking the functions + this checking, the functions sd_is_fifo3, sd_is_socket3, sd_is_socket_inet3, sd_is_socket_unix3 - are provided. In order to maximize flexibility it is + are provided. In order to maximize flexibility, it is recommended to make these checks as loose as possible - without allowing incorrect setups. i.e. often the + without allowing incorrect setups. i.e. often, the actual port number a socket is bound to matters little for the service to work, hence it should not be verified. On the other hand, whether a socket is a @@ -111,7 +113,7 @@ $LISTEN_FDS/$LISTEN_PID was not set or was not correctly set for this daemon and hence no file descriptors were received, 0 is - returned. Otherwise the number of file descriptors + returned. Otherwise, the number of file descriptors passed is returned. The application may find them starting with file descriptor SD_LISTEN_FDS_START, i.e. file descriptor 3. @@ -120,54 +122,23 @@ Notes - This function is provided by the reference - implementation of APIs for new-style daemons and - distributed with the systemd package. The algorithm it - implements is simple, and can easily be reimplemented - in daemons if it is important to support this - interface without using the reference - implementation. + Internally, this function checks whether the $LISTEN_PID environment variable equals the daemon PID. If not, it returns - immediately. Otherwise it parses the number passed in + immediately. Otherwise, it parses the number passed in the $LISTEN_FDS environment variable, then sets the FD_CLOEXEC flag for the parsed number of file descriptors starting from - SD_LISTEN_FDS_START. Finally it returns the parsed + SD_LISTEN_FDS_START. Finally, it returns the parsed number. - - For details about the algorithm check the - liberally licensed reference implementation sources: - - resp. - - sd_listen_fds() is - implemented in the reference implementation's - sd-daemon.c and - sd-daemon.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming these APIs - may copy the implementation into their source - tree. For more details about the reference - implementation see - sd-daemon7. - - If the reference implementation is used as - drop-in files and -DDISABLE_SYSTEMD is set during - compilation this function will always return 0 and - otherwise become a NOP. Environment - + $LISTEN_PID $LISTEN_FDS @@ -189,7 +160,7 @@ systemd1, - sd-daemon7, + sd-daemon3, sd_is_fifo3, sd_is_socket3, sd_is_socket_inet3, diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml new file mode 100644 index 0000000..aca7087 --- /dev/null +++ b/man/sd_login_monitor_new.xml @@ -0,0 +1,245 @@ + + + + + + + + + sd_login_monitor_new + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_login_monitor_new + 3 + + + + sd_login_monitor_new + sd_login_monitor_unref + sd_login_monitor_flush + sd_login_monitor_get_fd + sd_login_monitor_get_events + sd_login_monitor_get_timeout + sd_login_monitor + Monitor login sessions, seats, users and virtual machines/containers + + + + + #include <systemd/sd-login.h> + + + int sd_login_monitor_new + const char* category + sd_login_monitor** ret + + + + sd_login_monitor* sd_login_monitor_unref + sd_login_monitor* m + + + + int sd_login_monitor_flush + sd_login_monitor* m + + + + int sd_login_monitor_get_fd + sd_login_monitor* m + + + + int sd_login_monitor_get_events + sd_login_monitor* m + + + + int sd_login_monitor_get_timeout + sd_login_monitor* m + uint64_t* timeout_usec + + + + + + + Description + + sd_login_monitor_new() may + be used to monitor login sessions, users, seats, and + virtual machines/containers. Via a monitor object a + file descriptor can be integrated into an application + defined event loop which is woken up each time a user + logs in, logs out or a seat is added or removed, or a + session, user, seat or virtual machine/container + changes state otherwise. The first parameter takes a + string which can be seat (to get + only notifications about seats being added, removed or + changed), session (to get only + notifications about sessions being created or removed + or changed), uid (to get only + notifications when a user changes state in respect to + logins) or machine (to get only + notifications when a virtual machine or container is + started or stopped). If notifications shall be + generated in all these conditions, NULL may be + passed. Note that in the future additional categories + may be defined. The second parameter returns a monitor + object and needs to be freed with the + sd_login_monitor_unref() call + after use. + + sd_login_monitor_unref() + may be used to destroy a monitor object. Note that + this will invalidate any file descriptor returned by + sd_login_monitor_get_fd(). + + sd_login_monitor_flush() + may be used to reset the wakeup state of the monitor + object. Whenever an event causes the monitor to wake + up the event loop via the file descriptor this + function needs to be called to reset the wake-up + state. If this call is not invoked, the file descriptor + will immediately wake up the event loop again. + + sd_login_monitor_get_fd() + may be used to retrieve the file descriptor of the + monitor object that may be integrated in an + application defined event loop, based around + poll2 + or a similar interface. The application should include + the returned file descriptor as wake-up source for the + events mask returned by + sd_login_monitor_get_events(). It + should pass a timeout value as returned by + sd_login_monitor_get_timeout(). Whenever + a wake-up is triggered the file descriptor needs to be + reset via + sd_login_monitor_flush(). An + application needs to reread the login state with a + function like + sd_get_seats3 + or similar to determine what changed. + + sd_login_monitor_get_events() + will return the poll() mask to + wait for. This function will return a combination of + POLLIN, POLLOUT + and similar to fill into the + .events field of struct + pollfd. + + sd_login_monitor_get_timeout() + will return a timeout value for usage in + poll(). This returns a value in + microseconds since the epoch of CLOCK_MONOTONIC + for timing out poll() in + timeout_usec. See + clock_gettime2 + for details about + CLOCK_MONOTONIC. If there is no + timeout to wait for this will fill in + (uint64_t) -1 instead. Note that + poll() takes a relative timeout + in milliseconds rather than an absolute timeout in + microseconds. To convert the absolute 'us' timeout into + relative 'ms', use code like the following: + + uint64_t t; +int msec; +sd_login_monitor_get_timeout(m, &t); +if (t == (uint64_t) -1) + msec = -1; +else { + struct timespec ts; + uint64_t n; + clock_getttime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; +} + + The code above does not do any error checking + for brevity's sake. The calculated msec + integer can be passed directly as + poll()'s timeout + parameter. + + + + Return Value + + On success, + sd_login_monitor_new(), + sd_login_monitor_flush() and + sd_login_monitor_get_timeout() + return 0 or a positive integer. On success, + sd_login_monitor_get_fd() returns + a Unix file descriptor. On success, + sd_login_monitor_get_events() + returns a combination of POLLIN, + POLLOUT and suchlike. On failure, + these calls return a negative errno-style error + code. + + sd_login_monitor_unref() + always returns NULL. + + + + Notes + + The sd_login_monitor_new(), + sd_login_monitor_unref(), + sd_login_monitor_flush(), + sd_login_monitor_get_fd(), + sd_login_monitor_get_events() and + sd_login_monitor_get_timeout() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-login3, + sd_get_seats3, + poll2, + clock_gettime2 + + + + diff --git a/man/sd_notify.xml b/man/sd_notify.xml index dd0ba93..6bf8230 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd_notify @@ -45,12 +46,12 @@ sd_notify sd_notifyf - Notify init system about start-up completion and other daemon status changes + Notify service manager about start-up completion and other daemon status changes - #include "sd-daemon.h" + #include <systemd/sd-daemon.h> int sd_notify @@ -77,9 +78,9 @@ notification. If the unset_environment - parameter is non-zero sd_notify() + parameter is non-zero, sd_notify() will unset the $NOTIFY_SOCKET - environment variable before returning (regardless + environment variable before returning (regardless of whether the function call itself succeeded or not). Further calls to sd_notify() will then fail, but @@ -87,7 +88,7 @@ processes. The state parameter - should contain an newline-separated list of variable + should contain a newline-separated list of variable assignments, similar in style to an environment block. A trailing newline is implied if none is specified. The string may contain any kind of variable @@ -104,7 +105,7 @@ definition file has Type=notify set. The passed argument is a boolean "1" or "0". Since there is little - value in signalling non-readiness, the + value in signaling non-readiness, the only value daemons should send is "READY=1". @@ -151,6 +152,29 @@ itself. Example: "MAINPID=4711" + + + WATCHDOG=1 + + Tells systemd to + update the watchdog timestamp. This is + the keep-alive ping that services need + to issue in regular intervals if + WatchdogSec= is + enabled for it. See + systemd.service5 + for details. It is recommended to send + this message if the + $WATCHDOG_PID + environment variable has been set to + the PID of the service process, in + every half the time interval that is + specified in the + $WATCHDOG_USEC + environment variable. See + sd_watchdog_enabled3 + for details. + It is recommended to prefix variable names that @@ -166,7 +190,7 @@ for details. sd_notifyf() is similar to - sd_notifyf() but takes a + sd_notify() but takes a printf()-like format string plus arguments. @@ -178,64 +202,33 @@ errno-style error code. If $NOTIFY_SOCKET was not set and hence no status data could be sent, 0 is returned. If - the status was sent these functions return with a + the status was sent, these functions return with a positive return value. In order to support both, init systems that implement this scheme and those which - don't, it is generally recommended to ignore the return + do not, it is generally recommended to ignore the return value of this call. Notes - These functions are provided by the reference - implementation of APIs for new-style daemons and - distributed with the systemd package. The algorithms - they implement are simple, and can easily be - reimplemented in daemons if it is important to support - this interface without using the reference - implementation. + Internally, these functions send a single datagram with the state string as payload to the - AF_UNIX socket referenced in the + AF_UNIX socket referenced in the $NOTIFY_SOCKET environment variable. If the first character of - $NOTIFY_SOCKET is @ the string is + $NOTIFY_SOCKET is @, the string is understood as Linux abstract namespace socket. The datagram is accompanied by the process credentials of the sending daemon, using SCM_CREDENTIALS. - - For details about the algorithms check the - liberally licensed reference implementation sources: - - resp. - - sd_notify() and - sd_notifyf() are implemented in - the reference implementation's - sd-daemon.c and - sd-daemon.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming these APIs - may copy the implementation into their source tree. For - more details about the reference implementation see - sd_daemon7. - - If the reference implementation is used as - drop-in files and -DDISABLE_SYSTEMD is set during - compilation these functions will always return 0 and - otherwise become a NOP. Environment - + $NOTIFY_SOCKET @@ -291,9 +284,10 @@ See Also systemd1, - sd_daemon7, + sd-daemon3, daemon7, - systemd.service5 + systemd.service5, + sd_watchdog_enabled3 diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_session.xml new file mode 100644 index 0000000..1e762f4 --- /dev/null +++ b/man/sd_pid_get_session.xml @@ -0,0 +1,213 @@ + + + + + + + + + sd_pid_get_session + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_pid_get_session + 3 + + + + sd_pid_get_session + sd_pid_get_unit + sd_pid_get_user_unit + sd_pid_get_owner_uid + sd_pid_get_machine_name + sd_pid_get_slice + Determine session, service, owner of a + session, container/VM or slice of a specific + PID + + + + + #include <systemd/sd-login.h> + + + int sd_pid_get_session + pid_t pid + char** session + + + + int sd_pid_get_unit + pid_t pid + char** unit + + + + int sd_pid_get_user_unit + pid_t pid + char** unit + + + + int sd_pid_get_owner_uid + pid_t pid + uid_t* uid + + + + int sd_pid_get_machine_name + pid_t pid + char** name + + + + int sd_pid_get_slice + pid_t pid + char** slice + + + + + + Description + + sd_pid_get_session() may be + used to determine the login session identifier of a + process identified by the specified process + identifier. The session identifier is a short string, + suitable for usage in file system paths. Note that not + all processes are part of a login session (e.g. system + service processes, user processes that are shared + between multiple sessions of the same user, or kernel + threads). For processes not being part of a login + session this function will fail. The returned string + needs to be freed with the libc + free3 + call after use. + + sd_pid_get_unit() may be + used to determine the systemd system unit (i.e. system + service) identifier of a process identified by the + specified PID. The unit name is a short string, + suitable for usage in file system paths. Note that not + all processes are part of a system unit/service + (e.g. user processes, or kernel threads). For + processes not being part of a systemd system unit this + function will fail. (More specifically: this call will + not work for processes that are part of user units, + use sd_pid_get_user_unit() for + that.) The returned string needs to be freed with the + libc + free3 + call after use. + + sd_pid_get_user_unit() may + be used to determine the systemd user unit (i.e. user + service) identifier of a process identified by the + specified PID. This is similar to + sd_pid_get_unit() but applies to + user units instead of system units. + + sd_pid_get_owner_uid() may + be used to determine the Unix user identifier of the + owner of the session of a process identified the + specified PID. Note that this function will succeed + for user processes which are shared between multiple + login sessions of the same user, where + sd_pid_get_session() will + fail. For processes not being part of a login session + and not being a shared process of a user this function + will fail. + + sd_pid_get_machine_name() + may be used to determine the name of the VM or + container is a member of. The machine name is a short + string, suitable for usage in file system paths. The + returned string needs to be freed with the libc + free3 + call after use. + + sd_pid_get_slice() may be + used to determine the slice unit the process is a + member of. See + systemd.slice5 + for details about slices. The returned string needs to + be freed with the libc + free3 + call after use. + + If the pid parameter of any + of these functions is passed as 0, the operation is + executed for the calling process. + + + + Return Value + + On success, these calls return 0 or a positive + integer. On failure, these calls return a negative + errno-style error code. + + + + Notes + + The sd_pid_get_session(), + sd_pid_get_unit(), + sd_pid_get_user_unit(), + sd_pid_get_owner_uid(), + sd_pid_get_machine_name() and + sd_pid_get_slice() interfaces are + available as a shared library, which can be compiled and + linked to with the + libsystemd pkg-config1 + file. + + Note that the login session identifier as + returned by sd_pid_get_session() + is completely unrelated to the process session + identifier as returned by + getsid2. + + + + See Also + + + systemd1, + sd-login3, + sd_session_is_active3, + getsid2, + systemd.slice5 + + + + diff --git a/man/sd_readahead.xml b/man/sd_readahead.xml index 88b135b..9827299 100644 --- a/man/sd_readahead.xml +++ b/man/sd_readahead.xml @@ -8,20 +8,20 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + sd_readahead @@ -49,7 +49,7 @@ - #include "sd-daemon.h" + #include "sd-readahead.h" int sd_readahead @@ -129,28 +129,22 @@ For details about the algorithm check the liberally licensed reference implementation sources: - - resp. + + and sd_readahead() is - implemented in the reference implementation's + implemented in the reference implementation's drop-in sd-readahead.c and - sd-readahead.h files. These - interfaces are available as shared library, which can - be compiled and linked to with the - libsystemd-daemon - pkg-config1 - file. Alternatively, applications consuming this API - may copy the implementation into their source - tree. For more details about the reference - implementation see - sd-readahead7. - - If the reference implementation is used as - drop-in files and -DDISABLE_SYSTEMD is set during - compilation this function will always return 0 and - otherwise become a NOP. + sd-readahead.h files. It is + recommended that applications consuming this API copy + the implementation into their source tree. For more + details about the reference implementation, see + sd-readahead3 + + If -DDISABLE_SYSTEMD is set during compilation, + this function will always return 0 and otherwise + become a NOP. @@ -176,7 +170,7 @@ sd_readahead("noreplay"); See Also systemd1, - sd-readahead7, + sd-readahead3, daemon7 diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml new file mode 100644 index 0000000..f2550dd --- /dev/null +++ b/man/sd_seat_get_active.xml @@ -0,0 +1,183 @@ + + + + + + + + + sd_seat_get_active + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_seat_get_active + 3 + + + + sd_seat_get_active + sd_seat_get_sessions + sd_seat_can_multi_session + sd_seat_can_tty + sd_seat_can_graphical + Determine state of a specific seat + + + + + #include <systemd/sd-login.h> + + + int sd_seat_get_active + const char* seat + char** session + uid_t* uid + + + + int sd_seat_get_sessions + const char* seat + char*** sessions + uid_t** uid + unsigned int* n_uids + + + + int sd_seat_can_multi_session + const char* seat + + + + int sd_seat_can_tty + const char* seat + + + + int sd_seat_can_graphical + const char* seat + + + + + + Description + + sd_seat_get_active() may be + used to determine which session is currently active on + a seat, if there is any. Returns the session + identifier and the user identifier of the Unix user + the session is belonging to. Either the session or the + user identifier parameter can be passed + NULL, in case only one of the + parameters shall be queried. The returned string needs + to be freed with the libc + free3 + call after use. + + sd_seat_get_sessions() may + be used to determine all sessions on the specified + seat. Returns two arrays, one (NULL terminated) with + the session identifiers of the sessions and one with + the user identifiers of the Unix users the sessions + belong to. An additional parameter may be used to + return the number of entries in the latter array. The + two arrays and the latter parameter may be passed as + NULL in case these values need not to be + determined. The arrays and the strings referenced by + them need to be freed with the libc + free3 + call after use. Note that instead of an empty array + NULL may be returned and should be considered + equivalent to an empty array. + + sd_seat_can_multi_session() + may be used to determine whether a specific seat is + capable of multi-session, i.e. allows multiple login + sessions in parallel (with only one being active at a + time). + + sd_seat_can_tty() may be + used to determine whether a specific seat provides TTY + functionality, i.e. is useful as a text console. + + sd_seat_can_graphical() may + be used to determine whether a specific seat provides + graphics functionality, i.e. is useful as a graphics + display. + + If the seat parameter of any + of these functions is passed as + NULL, the operation is executed + for the seat of the session of the calling process, if + there is any. + + + + Return Value + + On success, + sd_seat_get_active() + returns 0 or a positive integer. On success, + sd_seat_get_sessions() returns + the number of entries in the session identifier + array. If the test succeeds, + sd_seat_can_multi_session, + sd_seat_can_tty and + sd_seat_can_graphical return a + positive integer, if it fails 0. On failure, these + calls return a negative errno-style error code. + + + + Notes + + The sd_seat_get_active(), + sd_seat_get_sessions(), + sd_seat_can_multi_session(), + sd_seat_can_tty() and + sd_seat_can_grapical() interfaces + are available as a shared library, which can be compiled + and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-login3, + sd_session_get_seat3 + + + + diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml new file mode 100644 index 0000000..ddb2bee --- /dev/null +++ b/man/sd_session_is_active.xml @@ -0,0 +1,318 @@ + + + + + + + + + sd_session_is_active + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_session_is_active + 3 + + + + sd_session_is_active + sd_session_is_remote + sd_session_get_state + sd_session_get_uid + sd_session_get_seat + sd_session_get_service + sd_session_get_type + sd_session_get_class + sd_session_get_display + sd_session_get_tty + sd_session_get_vt + sd_session_get_remote_host + sd_session_get_remote_user + Determine state of a specific session + + + + + #include <systemd/sd-login.h> + + + int sd_session_is_active + const char* session + + + + int sd_session_is_remote + const char* session + + + + int sd_session_get_state + const char* session + char** state + + + + int sd_session_get_uid + const char* session + uid_t* uid + + + + int sd_session_get_seat + const char* session + char** seat + + + + int sd_session_get_service + const char* session + char** service + + + + int sd_session_get_type + const char* session + char** type + + + + int sd_session_get_class + const char* session + char** class + + + + int sd_session_get_display + const char* session + char** display + + + + int sd_session_get_remote_host + const char* session + char** remote_host + + + + int sd_session_get_remote_user + const char* session + char** remote_user + + + + int sd_session_get_tty + const char* session + char** tty + + + + int sd_session_get_vt + const char* session + unsigned int* vt + + + + + + Description + + sd_session_is_active() may + be used to determine whether the session identified by + the specified session identifier is currently active + (i.e. currently in the foreground and available for + user input) or not. + + sd_session_is_remote() may + be used to determine whether the session identified by + the specified session identifier is a remote session + (i.e. its remote host is known) or not. + + sd_session_get_state() may + be used to determine the state of the session + identified by the specified session identifier. The + following states are currently known: + online (session logged in, but + session not active, i.e. not in the foreground), + active (session logged in and + active, i.e. in the foreground), + closing (session nominally logged + out, but some processes belonging to it are still + around). In the future additional states might be + defined, client code should be written to be robust in + regards to additional state strings being + returned. This function is a more generic version of + sd_session_is_active(). The returned + string needs to be freed with the libc + free3 + call after use. + + sd_session_get_uid() may be + used to determine the user identifier of the Unix user the session + identified by the specified session identifier belongs + to. + + sd_session_get_seat() may + be used to determine the seat identifier of the seat + the session identified by the specified session + identifier belongs to. Note that not all sessions are + attached to a seat, this call will fail for them. The + returned string needs to be freed with the libc + free3 + call after use. + + sd_session_get_service() + may be used to determine the name of the service (as + passed during PAM session setup) that registered the + session identified by the specified session + identifier. The returned string needs to be freed with + the libc + free3 + call after use. + + sd_session_get_type() may + be used to determine the type of the session + identified by the specified session identifier. The + returned string is one of x11, + wayland, tty or + unspecified and needs to be freed + with the libc + free3 + call after use. + + sd_session_get_class() may + be used to determine the class of the session + identified by the specified session identifier. The + returned string is one of user, + greeter, + lock-screen, or + background and needs to be freed + with the libc + free3 + call after use. + + sd_session_get_display() + may be used to determine the X11 display of the + session identified by the specified session + identifier. The returned string needs to be + freed with the libc + free3 + call after use. + + sd_session_get_remote_host() + may be used to determine the remote hostname of the + session identified by the specified session + identifier. The returned string needs to be + freed with the libc + free3 + call after use. + + sd_session_get_remote_user() + may be used to determine the remote username of the + session identified by the specified session + identifier. The returned string needs to be + freed with the libc + free3 + call after use. Note that this value is rarely known + to the system, and even then should not be relied on. + + sd_session_get_tty() + may be used to determine the TTY device of the + session identified by the specified session + identifier. The returned string needs to be + freed with the libc + free3 + call after use. + + sd_session_get_vt() + may be used to determine the VT number of the + session identified by the specified session + identifier. This function will return an error if + the seat does not support VTs. + + If the session parameter of + any of these functions is passed as + NULL, the operation is executed + for the session the calling process is a member of, if + there is any. + + + + Return Value + + If the test succeeds, + sd_session_is_active() and + sd_session_is_remote() return a + positive integer; if it fails, 0. On success, + sd_session_get_state(), + sd_session_get_uid(), + sd_session_get_seat(), + sd_session_get_service(), + sd_session_get_type(), + sd_session_get_class(), + sd_session_get_display(), + sd_session_get_remote_user(), + sd_session_get_remote_host() and + sd_session_get_tty() return 0 or + a positive integer. On failure, these calls return a + negative errno-style error code. + + + + Notes + + The sd_session_is_active(), + sd_session_get_state(), + sd_session_get_uid(), + sd_session_get_seat(), + sd_session_get_service(), + sd_session_get_type(), + sd_session_get_class(), + sd_session_get_display(), + sd_session_get_remote_host(), + sd_session_get_remote_user() and + sd_session_get_tty() + interfaces are available as a shared library, which can + be compiled and linked to with the + libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-login3, + sd_pid_get_session3 + + + + diff --git a/man/sd_uid_get_state.xml b/man/sd_uid_get_state.xml new file mode 100644 index 0000000..f2899ee --- /dev/null +++ b/man/sd_uid_get_state.xml @@ -0,0 +1,189 @@ + + + + + + + + + sd_uid_get_state + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_uid_get_state + 3 + + + + sd_uid_get_state + sd_uid_is_on_seat + sd_uid_get_sessions + sd_uid_get_seats + Determine login state of a specific Unix user ID + + + + + #include <systemd/sd-login.h> + + + int sd_uid_get_state + uid_t uid + char** state + + + + int sd_uid_is_on_seat + uid_t uid + int require_active + const char* seat + + + + int sd_uid_get_sessions + uid_t uid + int require_active + char*** sessions + + + + int sd_uid_get_seats + uid_t uid + int require_active + char*** seats + + + + + + Description + + sd_uid_get_state() may be + used to determine the login state of a specific Unix + user identifier. The following states are currently + known: offline (user not logged in + at all), lingering (user not logged + in, but some user services running), + online (user logged in, but not + active, i.e. has no session in the foreground), + active (user logged in, and has at + least one active session, i.e. one session in the + foreground), closing (user not + logged in, and not lingering, but some processes are + still around). In the future additional states might + be defined, client code should be written to be robust + in regards to additional state strings being + returned. The returned string needs to be freed with + the libc + free3 + call after use. + + sd_uid_is_on_seat() may be + used to determine whether a specific user is logged in + or active on a specific seat. Accepts a Unix user + identifier and a seat identifier string as + parameters. The require_active + parameter is a boolean value. If non-zero (true), this + function will test if the user is active (i.e. has a + session that is in the foreground and accepting user + input) on the specified seat, otherwise (false) only + if the user is logged in (and possibly inactive) on + the specified seat. + + sd_uid_get_sessions() may + be used to determine the current sessions of the + specified user. Accepts a Unix user identifier as + parameter. The require_active + parameter controls whether the returned list shall + consist of only those sessions where the user is + currently active (> 0), where the user is currently + online but possibly inactive (= 0), or + logged in at all but possibly closing the session (< 0). The call returns a + NULL terminated string array of session identifiers in + sessions which needs to be + freed by the caller with the libc + free3 + call after use, including all the strings + referenced. If the string array parameter is passed as + NULL, the array will not be filled in, but the return + code still indicates the number of current + sessions. Note that instead of an empty array NULL may + be returned and should be considered equivalent to an + empty array. + + Similarly, sd_uid_get_seats() + may be used to determine the list of seats on which + the user currently has sessions. Similar semantics + apply, however note that the user may have + multiple sessions on the same seat as well as sessions + with no attached seat and hence the number of entries + in the returned array may differ from the one returned + by sd_uid_get_sessions(). + + + + Return Value + + On success, + sd_uid_get_state() returns 0 or a + positive integer. If the test succeeds, + sd_uid_is_on_seat() returns a + positive integer; if it fails, + 0. sd_uid_get_sessions() and + sd_uid_get_seats() return the + number of entries in the returned arrays. On failure, + these calls return a negative errno-style error + code. + + + + Notes + + The sd_uid_get_state(), + sd_uid_is_on_seat(), + sd_uid_get_sessions(), and + sd_uid_get_seats() interfaces are + available as a shared library, which can be compiled and + linked to with the libsystemd pkg-config1 + file. + + + + See Also + + + systemd1, + sd-login3, + sd_pid_get_owner_uid3 + + + + diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml new file mode 100644 index 0000000..88d1e5b --- /dev/null +++ b/man/sd_watchdog_enabled.xml @@ -0,0 +1,170 @@ + + + + + + + + + sd_watchdog_enabled + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_watchdog_enabled + 3 + + + + sd_watchdog_enabled + Check whether the service manager expects watchdog keep-alive notifications from a service + + + + + #include <systemd/sd-daemon.h> + + + int sd_watchdog_enabled + int unset_environment + const uint64_t *usec + + + + + + Description + sd_watchdog_enabled() may + be called by a service to detect whether the service + manager expects regular keep-alive watchdog + notification events from it, and the timeout after + which the manager will act on the service if it did + not get such a notification. + + If the unset_environment + parameter is non-zero, + sd_watchdog_enabled() will unset + the $WATCHDOG_USEC and + $WATCHDOG_PID environment variables + before returning (regardless of whether the function call + itself succeeded or not). Further calls to + sd_watchdog_enabled() will then + return with zero, but the variable is no longer + inherited by child processes. + + If the usec parameter is + non-NULL, sd_watchdog_enabled() + will return the timeout in µs for the watchdog + logic. The service manager will usually terminate a + service when it did not get a notification message + within the specified time after startup and after each + previous message. It is recommended that a daemon + sends a keep-alive notification message to the service + manager every half of the time returned + here. Notification messages may be sent with + sd_notify3 + with a message string of + WATCHDOG=1. + + To enable service supervision with the watchdog + logic, use WatchdogSec= in service + files. See + systemd.service5 + for details. + + + + Return Value + + On failure, this call returns a negative + errno-style error code. If the service manager expects + watchdog keep-alive notification messages to be sent, + > 0 is returned, otherwise 0 is returned. Only if + the return value is > 0, the + usec parameter is valid after + the call. + + + + Notes + + + + Internally, this functions parses the + $WATCHDOG_PID and + $WATCHDOG_USEC environment + variable. The call will ignore these variables if + $WATCHDOG_PID does containe the PID + of the current process, under the assumption that in + that case, the variables were set for a different + process further up the process tree. + + + + + Environment + + + + $WATCHDOG_PID + + Set by the system + manager for supervised process for + which watchdog support is enabled, and + contains the PID of that process. See + above for details. + + + + $WATCHDOG_USEC + + Set by the system + manager for supervised process for + which watchdog support is enabled, and + contains the watchdog timeout in µs + See above for + details. + + + + + + See Also + + systemd1, + sd-daemon3, + daemon7, + systemd.service5, + sd_notify3 + + + + diff --git a/man/shutdown.xml b/man/shutdown.xml index c8c4b54..7372585 100644 --- a/man/shutdown.xml +++ b/man/shutdown.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + shutdown @@ -80,7 +81,7 @@ If the time argument is used, 5 minutes before the system goes down the - /etc/nologin file is created to + /run/nologin file is created to ensure that further logins shall not be allowed. @@ -94,8 +95,7 @@ - Prints a short help - text and exits. + @@ -133,7 +133,7 @@ - Don't halt, power-off, + Do not halt, power-off, reboot, just write wall message. @@ -141,7 +141,7 @@ - Don't send wall + Do not send wall message before halt, power-off, reboot. @@ -164,18 +164,11 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. - Notes - - This is a legacy command available for - compatibility only. - - - See Also systemd1, diff --git a/man/standard-options.xml b/man/standard-options.xml new file mode 100644 index 0000000..7ae8a96 --- /dev/null +++ b/man/standard-options.xml @@ -0,0 +1,30 @@ + + + + + + + + + + Print a short help text and exit. + + + + + + + + Print a short version string and exit. + + + + + + + + Do not pipe output into a pager. + + + diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml index 240aa81..00a857b 100644 --- a/man/sysctl.d.xml +++ b/man/sysctl.d.xml @@ -7,16 +7,16 @@ Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -46,46 +46,73 @@ - /usr/lib/sysctl.d/*.conf /etc/sysctl.d/*.conf /run/sysctl.d/*.conf + /usr/lib/sysctl.d/*.conf Description - systemd uses configuration files - from the above directories to configure - sysctl8 - kernel parameters to load during boot. + At boot, + systemd-sysctl.service8 + reads configuration files from the above directories + to configure + sysctl8 + kernel parameters. - Configuration Format - - The configuration files should simply contain a - list of variable assignments, separated by - newlines. Empty lines and lines whose first - non-whitespace character is # or ; are ignored. - - Note that both / and . are accepted as - separators in sysctl variable names. - - Each configuration file is named in the style of - <program>.conf. - Files in /etc/ overwrite - files with the same name in /usr/lib/. - Files in /run overwrite files with - the same name in /etc/ and - /usr/lib/. Packages should install their - configuration files in /usr/lib/, files - in /etc/ are reserved for the local - administration, which possibly decides to overwrite the - configurations installed from packages. All files are sorted - by filename in alphabetical order, regardless in which of the - directories they reside, to ensure that a specific - configuration file takes precedence over another file with - an alphabetically later name. + Configuration Format + + The configuration files contain a list of + variable assignments, separated by newlines. Empty + lines and lines whose first non-whitespace character + is # or ; are ignored. + + Note that both / and . are accepted as label + separators within sysctl variable + names. kernel.domainname=foo and + kernel/domainname=foo hence are + entirely equivalent. + + Each configuration file shall be named in the + style of program.conf. + Files in /etc/ override files + with the same name in /usr/lib/ + and /run/. Files in + /run/ override files with the same + name in /usr/lib/. Packages + should install their configuration files in + /usr/lib/. Files in + /etc/ 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 the + directories they reside in. If multiple files specify the + same variable name, the entry in the file with the + lexicographically latest name will be applied. It is + recommended to prefix all filenames with a two-digit + number and a dash, to simplify the ordering of the + files. + + If the administrator wants to disable a + configuration file supplied by the vendor, the + recommended way is to place a symlink to + /dev/null in + /etc/sysctl.d/ bearing the + same filename. + + The settings configured with + sysctl.d files will be applied + early on boot. The network interface-specific options + will also be applied individually for each network + interface as it shows up in the system. (More + specifically, that is + net.ipv4.conf.*, + net.ipv6.conf.*, + net.ipv4.neigh.* and net.ipv6.neigh.*) @@ -102,6 +129,8 @@ kernel.domainname=example.com See Also systemd1, + systemd-sysctl.service8, + systemd-delta1, sysctl8, sysctl.conf5 diff --git a/man/systemadm.xml b/man/systemadm.xml deleted file mode 100644 index cefc300..0000000 --- a/man/systemadm.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - systemadm - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemadm - 1 - - - - systemadm - Graphical frontend for the systemd system - and service manager - - - - - systemadm OPTIONS - - - - - Description - - systemadm is a graphical - frontend for the systemd system and service manager - and allows introspection and control of - systemd. - - - - Options - - The following options are understood: - - - - - - - Prints a short help - text and exits. - - - - - - - Connect to the systemd - system - manager. (Default) - - - - - - Connect to the systemd - manager of the calling - user. - - - - - In addition to this a number of parameters - common to all Gtk+ programs are supported. - - - - See Also - - systemd1, - systemctl1 - - - - diff --git a/man/systemctl.xml b/man/systemctl.xml index 5adee45..355cd11 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1,1128 +1,1436 @@ +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> - - - - systemctl - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemctl - 1 - - - - systemctl - Control the systemd system and service manager - - - - - systemctl OPTIONS COMMAND NAME - - - - - Description - - systemctl may be used to - introspect and control the state of the - systemd1 - system and service manager. - - - - Options - - The following options are understood: - - - - - - - Prints a short help - text and exits. - - - - - - Prints a short version - string and exits. - - - - - - - When listing units, - limit display to certain unit - types. If not specified units of all - types will be shown. The argument - should be a unit type name such as - , - and - similar. - - - - - - - When showing - unit/job/manager properties, limit - display to certain properties as - specified as argument. If not - specified all set properties are - shown. The argument should be a - property name, such as - MainPID. If - specified more than once all - properties with the specified names - are shown. - - - - - - - When listing units, - show all units, regardless of their - state, including inactive units. When - showing unit/job/manager properties, - show all properties regardless whether - they are set or not. - - - - - - When listing units, - show only failed units. Do not confuse - with - . - - - - - - Do not ellipsize unit - names and truncate unit descriptions - in the output of - list-units and - list-jobs. - - - - - - If the requested - operation conflicts with a pending - unfinished job, fail the command. If - this is not specified the requested - operation will replace the pending job, - if necessary. Do not confuse - with - . - - - - - - When enqueuing a new - job ignore all its dependencies and - execute it immediately. If passed no - required units of the unit passed will - be pulled in, and no ordering - dependencies will be honoured. This is - mostly a debugging and rescue tool for - the administrator and should not be - used by - applications. - - - - - - - Suppress output to - STDOUT in - snapshot, - is-active, - enable and - disable. - - - - - - Do not synchronously wait for - the requested operation to finish. If this is - not specified the job will be verified, - enqueued and systemctl will - wait until it is completed. By passing this - argument it is only verified and - enqueued. - - - - - - Do not print a legend, i.e. - the column headers and the footer with hints. - - - - - - - Do not pipe output into a - pager. - - - - - - Talk to the systemd - system manager. (Default) - - - - - - Talk to the systemd - manager of the calling user. - - - - - - - When used in - conjunction with the - dot command (see - below), selects which dependencies are - shown in the dependency graph. If - is passed - only dependencies of type - After= or - Before= are - shown. If - is passed only dependencies of type - Requires=, - RequiresOverridable=, - Requisite=, - RequisiteOverridable=, - Wants= and - Conflicts= are - shown. If neither is passed, shows - dependencies of all these - types. - - - - - - Don't send wall - message before - halt, power-off, reboot. - - - - - - When used with - enable and - disable, operate on the - global user configuration - directory, thus enabling or disabling - a unit file globally for all future - logins of all users. - - - - - - When used with - enable and - disable, do not - implicitly reload daemon configuration - after executing the - changes. - - - - - - When used with - start and related - commands, disables asking for - passwords. Background services may - require input of a password or - passphrase string, for example to - unlock system hard disks or - cryptographic certificates. Unless - this option is specified and the - command is invoked from a terminal - systemctl will - query the user on the terminal for the - necessary secrets. Use this option to - switch this behavior off. In this - case the password must be supplied by - some other means (for example - graphical password agents) or the - service might fail. - - - - - - When used with - kill, choose which - processes to kill. Must be one of - , - or - to select whether - to kill only the main process of the - unit, the control process or all - processes of the unit. If omitted - defaults to - . - - - - - - - When used with - kill, choose which - signal to send to selected - processes. Must be one of the well - known signal specifiers such as - SIGTERM, SIGINT or SIGSTOP. If - omitted defaults to - . - - - - - - - When used with - enable, override any - existing conflicting - symlinks. - - When used with - halt, - poweroff, - reboot or - kexec execute - selected operation without shutting - down all units. However, all processes - will be killed forcibly and all file - systems are unmounted or remounted - read-only. This is hence a drastic but - relatively safe option to request an - immediate reboot. - - - - - - When used with - enable/disable/is-enabled (and - related commands), use alternative - root path when looking for unit - files. - - - - - - When used with - enable/disable/is-enabled (and related commands), make - changes only temporarily, so that they - are dropped on the next reboot. This - will have the effect that changes are - not made in subdirectories of - /etc but in - /run, with - identical immediate effects, however, - since the latter is lost on reboot, - the changes are lost - too. - - - - - - - Execute operation - remotely. Specify a hostname, or - username and hostname separated by @, - to connect to. This will use SSH to - talk to the remote systemd - instance. - - - - - - - Acquire privileges via - PolicyKit before executing the - operation. - - - - The following commands are understood: - - - - list-units - - List known units. - - - start [NAME...] - - Start (activate) one - or more units specified on the command - line. - - - stop [NAME...] - - Stop (deactivate) one - or more units specified on the command - line. - - - reload [NAME...] - - Asks all units listed - on the command line to reload their - configuration. Note that this will - reload the service-specific - configuration, not the unit - configuration file of systemd. If you - want systemd to reload the - configuration file of a unit use the - daemon-reload - command. In other words: for the - example case of Apache, this will - reload Apache's - httpd.conf in the - web server, not the - apache.service - systemd unit file. - - This command should not be - confused with the - daemon-reload or - load - commands. - - - - restart [NAME...] - - Restart one or more - units specified on the command - line. If the units are not running yet - they will be - started. - - - try-restart [NAME...] - - Restart one or more - units specified on the command - line if the units are running. Do - nothing if units are not running. - Note that for compatibility - with Red Hat init scripts - condrestart is - equivalent to this command. - - - reload-or-restart [NAME...] - - Reload one or more - units if they support it. If not, - restart them instead. If the units - are not running yet they will be - started. - - - reload-or-try-restart [NAME...] - - Reload one or more - units if they support it. If not, - restart them instead. Do nothing if - the units are not running. Note that - for compatibility with SysV init - scripts - force-reload is - equivalent to this - command. - - - isolate [NAME] - - Start the unit - specified on the command line and its - dependencies and stop all others. - - This is similar to changing the - runlevel in a traditional init system. The - isolate command will - immediately stop processes that are not - enabled in the new unit, possibly including - the graphical environment or terminal you - are currently using. - - Note that this works only on units - where is - enabled. See - systemd.unit5 - for details. - - - kill [NAME...] - - Send a signal to one - or more processes of the unit. Use - to select - which process to kill. Use - to - select the kill mode and - to select - the signal to send. - - - is-active [NAME...] - - Check whether any of - the specified units are active - (i.e. running). Returns an exit code - 0 if at least one is active, non-zero - otherwise. Unless - is specified - this will also print the current unit - state to STDOUT. - - - status [NAME...|PID...] - - Show terse runtime - status information about one or more - units. This function is intended to - generate human-readable output. If you - are looking for computer-parsable - output, use show - instead. If a PID is passed - information about the unit the process - of the PID belongs to is - shown. - - - show [NAME...|JOB...] - - Show properties of one - or more units, jobs or the manager - itself. If no argument is specified - properties of the manager will be - shown. If a unit name is specified - properties of the unit is shown, and - if a job id is specified properties of - the job is shown. By default, empty - properties are suppressed. Use - to show those - too. To select specific properties to - show use - . This - command is intended to be used - whenever computer-parsable output is - required. Use - status if you are - looking for formatted human-readable - output. - - - - reset-failed [NAME...] - - Reset the - 'failed' state of the - specified units, or if no unit name is - passed of all units. When a unit fails - in some way (i.e. process exiting with - non-zero error code, terminating - abnormally or timing out) it will - automatically enter the - 'failed' state and - its exit code and status is recorded - for introspection by the administrator - until the service is restarted or - reset with this - command. - - - - list-unit-files - - List installed unit files. - - - - - enable [NAME...] - - Enable one or more - unit files, as specified on the - command line. This will create a - number of symlinks as encoded in the - [Install] sections - of the unit files. After the symlinks - have been created the systemd - configuration is reloaded (in a way - that is equivalent to - daemon-reload) to - ensure the changes are taken into - account immediately. Note that this - does not have the effect that any of - the units enabled are also started at - the same time. If this is desired a - separate start - command must be invoked for the - unit. - - This command will - print the actions executed. This - output may be suppressed by passing - . - - Note that this operation creates - only the suggested symlinks for the - units. While this command is the - recommended way to manipulate the unit - configuration directory, the - administrator is free to make - additional changes manually, by - placing or removing symlinks in the - directory. This is particularly useful - to create configurations that deviate - from the suggested default - installation. In this case the - administrator must make sure to invoke - daemon-reload - manually as necessary, to ensure his - changes are taken into account. - - Enabling units should not be - confused with starting (activating) - units, as done by the - start - command. Enabling and starting units - is orthogonal: units may be enabled - without being started and started - without being enabled. Enabling simply - hooks the unit into various suggested - places (for example, so that the unit - is automatically started on boot or - when a particular kind of hardware is - plugged in). Starting actually spawns - the daemon process (in case of service - units), or binds the socket (in case - of socket units), and so - on. - - Depending on whether - , - or - is specified - this enables the unit for the system, - for the calling user only - or for all future logins of all - users. Note that in the latter case no - systemd daemon configuration is - reloaded. - - - - - disable [NAME...] - - Disables one or more - units. This removes all symlinks to - the specified unit files from the unit - configuration directory, and hence - undoes the changes made by - enable. Note - however that this removes - all symlinks to the unit files - (i.e. including manual additions), not - just those actually created by - enable. This call - implicitly reloads the systemd daemon - configuration after completing the - disabling of the units. Note that this - command does not implicitly stop the - units that is being disabled. If this - is desired an additional - stopcommand should - be executed afterwards. - - This command will print the - actions executed. This output may be - suppressed by passing - . - - - This command honors - , - , - in a similar - way as - enable. - - - - is-enabled [NAME...] - - Checks whether any of - the specified unit files is enabled - (as with - enable). Returns an - exit code of 0 if at least one is - enabled, non-zero otherwise. Prints - the current enable status. To suppress - this output use - . - - - - reenable [NAME...] - - Reenable one or more - unit files, as specified on the - command line. This is a combination of - disable and - enable and is - useful to reset the symlinks a unit is - enabled with to the defaults - configured in the - [Install] section - of the unit file. - - - - - preset [NAME...] - - Reset one or more unit - files, as specified on the command - line, to the defaults configured in a - preset file. This has the same effect - as disable or - enable, depending - how the unit is listed in the preset - files. - - - - - mask [NAME...] - - Mask one or more unit - files, as specified on the command - line. This will link these units to - /dev/null, making - it impossible to start them. This is a stronger version - of disable, since - it prohibits all kinds of activation - of the unit, including manual - activation. Use this option with - care. - - - - - unmask [NAME...] - - Unmask one or more - unit files, as specified on the - command line. This will undo the - effect of - mask. - - - - - link [NAME...] - - Link a unit file that - is not in the unit file search paths - into the unit file search path. This - requires an absolute path to a unit - file. The effect of this can be undone - with disable. The - effect of this command is that a unit - file is available for - start and other - commands although it isn't installed - directly in the unit search - path. - - - - - load [NAME...] - - Load one or more units - specified on the command line. This - will simply load their configuration - from disk, but not start them. To - start them you need to use the - start command which - will implicitly load a unit that has - not been loaded yet. Note that systemd - garbage collects loaded units that are - not active or referenced by an active - unit. This means that units loaded - this way will usually not stay loaded - for long. Also note that this command - cannot be used to reload unit - configuration. Use the - daemon-reload - command for that. All in all, this - command is of little use except for - debugging. - This command should not be - confused with the - daemon-reload or - reload - commands. - - - list-jobs - - List jobs that are in progress. - - - cancel [JOB...] - - Cancel one or more - jobs specified on the command line by - their numeric job - IDs. If no job id is specified, cancel all pending jobs. - - - dump - - Dump server - status. This will output a (usually - very long) human readable manager - status dump. Its format is subject to - change without notice and should not - be parsed by - applications. - - - dot - - Generate textual - dependency graph description in dot - format for further processing with the - GraphViz - dot1 - tool. Use a command line like - systemctl dot | dot -Tsvg > - systemd.svg to generate a - graphical dependency tree. Unless - or - is passed - the generated graph will show both - ordering and requirement - dependencies. - - - snapshot [NAME] - - Create a snapshot. If - a snapshot name is specified, the new - snapshot will be named after it. If - none is specified an automatic - snapshot name is generated. In either - case, the snapshot name used is - printed to STDOUT, unless - is - specified. - - A snapshot refers to a saved - state of the systemd manager. It is - implemented itself as a unit that is - generated dynamically with this - command and has dependencies on all - units active at the time. At a later - time the user may return to this state - by using the - isolate command on - the snapshot unit. - - Snapshots are only useful for - saving and restoring which units are - running or are stopped, they do not - save/restore any other - state. Snapshots are dynamic and lost - on reboot. - - - delete [NAME...] - - Remove a snapshot - previously created with - snapshot. - - - daemon-reload - - Reload systemd manager - configuration. This will reload all - unit files and recreate the entire - dependency tree. While the daemon is - reloaded, all sockets systemd listens - on on behalf of user configuration will - stay accessible. This - command should not be confused with - the load or - reload - commands. - - - daemon-reexec - - Reexecute the systemd - manager. This will serialize the - manager state, reexecute the process - and deserialize the state again. This - command is of little use except for - debugging and package - upgrades. Sometimes it might be - helpful as a heavy-weight - daemon-reload. While - the daemon is reexecuted all sockets - systemd listens on on behalf of user - configuration will stay - accessible. - - - show-environment - - Dump the systemd - manager environment block. The - environment block will be dumped in - straight-forward form suitable for - sourcing into a shell script. This - environment block will be passed to - all processes the manager - spawns. - - - set-environment [NAME=VALUE...] - - Set one or more - systemd manager environment variables, - as specified on the command - line. - - - unset-environment [NAME...] - - Unset one or more - systemd manager environment - variables. If only a variable name is - specified it will be removed - regardless of its value. If a variable - and a value are specified the variable - is only removed if it has the - specified value. - - - default - - Enter default - mode. This is mostly equivalent to - start - default.target. - - - rescue - - Enter rescue - mode. This is mostly equivalent to - isolate - rescue.target but also - prints a wall message to all - users. - - - emergency - - Enter emergency - mode. This is mostly equivalent to - isolate - emergency.target but also - prints a wall message to all - users. - - - halt - - Shut down and halt the - system. This is mostly equivalent to - start halt.target - but also prints a wall message to all - users. If - combined with - shutdown of all running services is - skipped, however all processes are killed - and all file systems are unmounted or - mounted read-only, immediately - followed by the - system halt. - - - poweroff - - Shut down and - power-off the system. This is mostly - equivalent to start - poweroff.target but also - prints a wall message to all - users. If - combined with - shutdown of all running services is - skipped, however all processes are killed - and all file systems are unmounted or - mounted read-only, immediately - followed by the - powering off. - - - reboot - - Shut down and - reboot the system. This is mostly - equivalent to start - reboot.target but also - prints a wall message to all - users. If - combined with - shutdown of all running services is - skipped, however all processes are killed - and all file systems are unmounted or - mounted read-only, immediately - followed by the - reboot. - - - kexec - - Shut down and reboot - the system via kexec. This is mostly - equivalent to start - kexec.target but also prints - a wall message to all users. If - combined with - shutdown of all running services is - skipped, however all processes are killed - and all file systems are unmounted or - mounted read-only, immediately - followed by the - reboot. - - - exit - - Ask the systemd - manager to quit. This is only - supported for user service managers - (i.e. in conjunction with the - option) and - will fail otherwise. - - - - - - - Exit status - - On success 0 is returned, a non-zero failure - code otherwise. - - - - Environment - - - - $SYSTEMD_PAGER - Pager to use when - is not given; - overrides $PAGER. Setting - this to an empty string or the value - cat is equivalent to passing - . - - - - - - See Also - - systemd1, - systemadm1, - systemd-loginctl1, - systemd.unit5, - systemd.special7, - wall1 - - + + + + systemctl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemctl + 1 + + + + systemctl + Control the systemd system and service manager + + + + + systemctl + OPTIONS + COMMAND + NAME + + + + + Description + + systemctl may be used to + introspect and control the state of the + systemd1 + system and service manager. + + + + Options + + The following options are understood: + + + + + + + + The argument should be a comma-separated list of unit + types such as and + . + + + If one of the arguments is a unit type, when listing + units, limit display to certain unit types. Otherwise, units + of all types will be shown. + + As a special case, if one of the arguments is + , a list of allowed values will be + printed and the program will exit. + + + + + + + + The argument should be a comma-separated list of unit LOAD, + SUB, or ACTIVE states. When listing units, show only those + in specified states. + + + + + + + + + When showing unit/job/manager properties with the + show command, limit display to certain + properties as specified as argument. If not specified, all + set properties are shown. The argument should be a + comma-separated list of property names, such as + MainPID. If specified more than once, all + properties with the specified names are shown. + + + + + + + + + When listing units, show all loaded units, regardless + of their state, including inactive units. When showing + unit/job/manager properties, show all properties regardless + whether they are set or not. + To list all units installed on the system, use the + list-unit-files command instead. + + + + + + + + Show reverse dependencies between units with + list-dependencies, i.e. units with + dependencies of type Wants= or + Requires= on the given unit. + + + + + + + + + + Show which units are started after or before + with list-dependencies, respectively. + + + + + + + + + + Do not ellipsize unit names, process tree entries, + journal output, or truncate unit descriptions in the output + of status, list-units, + list-jobs, and + list-timers. + + + + + + + + When showing sockets, show the type of the socket. + + + + + + + + When queuing a new job, this option controls how to deal with + already queued jobs. It takes one of fail, + replace, + replace-irreversibly, + isolate, + ignore-dependencies, + ignore-requirements or + flush. Defaults to + replace, except when the + isolate command is used which implies the + isolate job mode. + + If fail is specified and a requested + operation conflicts with a pending job (more specifically: + causes an already pending start job to be reversed into a stop + job or vice versa), cause the operation to fail. + + If replace (the default) is + specified, any conflicting pending job will be replaced, as + necessary. + + If replace-irreversibly is specified, + operate like replace, but also mark the new + jobs as irreversible. This prevents future conflicting + transactions from replacing these jobs. The jobs can still be + cancelled using the cancel command. + + isolate is only valid for start + operations and causes all other units to be stopped when the + specified unit is started. This mode is always used when the + isolate command is used. + + flush will cause all queued jobs to + be canceled when the new job is enqueued. + + If ignore-dependencies is specified, + then all unit dependencies are ignored for this new job and + the operation is executed immediately. If passed, no required + units of the unit passed will be pulled in, and no ordering + dependencies will be honored. This is mostly a debugging and + rescue tool for the administrator and should not be used by + applications. + + ignore-requirements is similar to + ignore-dependencies, but only causes the + requirement dependencies to be ignored, the ordering + dependencies will still be honoured. + + + + + + + + + + When system shutdown or a sleep state is requested, + ignore inhibitor locks. Applications can establish inhibitor + locks to avoid that certain important operations (such as CD + burning or suchlike) are interrupted by system shutdown or a + sleep state. Any user may take these locks and privileged + users may override these locks. If any locks are taken, + shutdown and sleep state requests will normally fail + (regardless of whether privileged or not) and a list of active locks + is printed. However, if + is specified, the locks are ignored and not printed, and the + operation attempted anyway, possibly requiring additional + privileges. + + + + + + + + + Suppress output to standard output in + snapshot, + is-active, + is-failed, + enable and + disable. + + + + + + + + Do not synchronously wait for the requested operation + to finish. If this is not specified, the job will be + verified, enqueued and systemctl will + wait until it is completed. By passing this argument, it is + only verified and enqueued. + + + + + + + + Do not print the legend, i.e. the column headers and + the footer with hints. + + + + + + + + + + + Do not send wall message before halt, power-off, + reboot. + + + + + + + + When used with enable and + disable, operate on the global user + configuration directory, thus enabling or disabling a unit + file globally for all future logins of all users. + + + + + + + + When used with enable and + disable, do not implicitly reload daemon + configuration after executing the changes. + + + + + + + + When used with start and related + commands, disables asking for passwords. Background services + may require input of a password or passphrase string, for + example to unlock system hard disks or cryptographic + certificates. Unless this option is specified and the + command is invoked from a terminal, + systemctl will query the user on the + terminal for the necessary secrets. Use this option to + switch this behavior off. In this case, the password must be + supplied by some other means (for example graphical password + agents) or the service might fail. This also disables + querying the user for authentication for privileged + operations. + + + + + + + + + When used with kill, choose which + processes to kill. Must be one of , + or to select + whether to kill only the main process of the unit, the + control process or all processes of the unit. If omitted, + defaults to . + + + + + + + + + + When used with kill, choose which + signal to send to selected processes. Must be one of the + well known signal specifiers such as SIGTERM, SIGINT or + SIGSTOP. If omitted, defaults to + . + + + + + + + + + When used with enable, overwrite + any existing conflicting symlinks. + + When used with halt, + poweroff, reboot or + kexec, execute the selected operation + without shutting down all units. However, all processes will + be killed forcibly and all file systems are unmounted or + remounted read-only. This is hence a drastic but relatively + safe option to request an immediate reboot. If + is specified twice for these + operations, they will be executed immediately without + terminating any processes or umounting any file + systems. Warning: specifying twice + with any of these operations might result in data + loss. + + + + + + + + When used with + enable/disable/is-enabled + (and related commands), use alternative root path when + looking for unit files. + + + + + + + + + When used with enable, + disable, + (and related commands), make changes only temporarily, so + that they are lost on the next reboot. This will have the + effect that changes are not made in subdirectories of + /etc but in /run, + with identical immediate effects, however, since the latter + is lost on reboot, the changes are lost too. + + Similarly, when used with + set-property, make changes only + temporarily, so that they are lost on the next + reboot. + + + + + + + + + When used with status, controls the + number of journal lines to show, counting from the most + recent ones. Takes a positive integer argument. Defaults to + 10. + + + + + + + + + When used with status, controls the + formatting of the journal entries that are shown. For the + available choices, see + journalctl1. + Defaults to short. + + + + + + + + When used with list-dependencies, + the output is printed as a list instead of a tree. + + + + + + + + + + + + + + Commands + + The following commands are understood: + + + Unit Commands + + + + list-units PATTERN... + + + List known units (subject to limitations specified + with ). If one or more + PATTERNs are specified, only + units matching one of them are shown. + + This is the default command. + + + + + list-sockets PATTERN... + + + List socket units ordered by listening address. + If one or more PATTERNs are + specified, only socket units matching one of them are + shown. Produces output similar to + +LISTEN UNIT ACTIVATES +/dev/initctl systemd-initctl.socket systemd-initctl.service +... +[::]:22 sshd.socket sshd.service +kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + +5 sockets listed. + Note: because the addresses might contains spaces, this output + is not suitable for programmatic consumption. + + + See also the options , + , and . + + + + + list-timers PATTERN... + + + List timer units ordered by the time they elapse + next. If one or more PATTERNs + are specified, only units matching one of them are shown. + + + See also the options and + . + + + + + start PATTERN... + + + Start (activate) one or more units specified on the + command line. + + Note that glob patterns operate on a list of currently + loaded units. Units which are not active and are not in a + failed state usually are not loaded, and would not be + matched by any pattern. In addition, in case of + instantiated units, systemd is often unaware of the + instance name until the instance has been started. Therefore, + using glob patterns with start + has limited usefulness. + + + + stop PATTERN... + + + Stop (deactivate) one or more units specified on the + command line. + + + + reload PATTERN... + + + Asks all units listed on the command line to reload + their configuration. Note that this will reload the + service-specific configuration, not the unit configuration + file of systemd. If you want systemd to reload the + configuration file of a unit, use the + daemon-reload command. In other words: + for the example case of Apache, this will reload Apache's + httpd.conf in the web server, not the + apache.service systemd unit + file. + + This command should not be confused with the + daemon-reload or load + commands. + + + + + restart PATTERN... + + + Restart one or more units specified on the command + line. If the units are not running yet, they will be + started. + + + + try-restart PATTERN... + + + Restart one or more units specified on the command + line if the units are running. This does nothing if units are not + running. Note that, for compatibility with Red Hat init + scripts, condrestart is equivalent to this + command. + + + + reload-or-restart PATTERN... + + + Reload one or more units if they support it. If not, + restart them instead. If the units are not running yet, they + will be started. + + + + reload-or-try-restart PATTERN... + + + Reload one or more units if they support it. If not, + restart them instead. This does nothing if the units are not + running. Note that, for compatibility with SysV init scripts, + force-reload is equivalent to this + command. + + + + isolate NAME + + + Start the unit specified on the command line and its + dependencies and stop all others. + + This is similar to changing the runlevel in a + traditional init system. The isolate + command will immediately stop processes that are not enabled + in the new unit, possibly including the graphical + environment or terminal you are currently using. + + Note that this is allowed only on units where + is enabled. See + systemd.unit5 + for details. + + + + kill PATTERN... + + + Send a signal to one or more processes of the + unit. Use to select which + process to kill. Use to select + the kill mode and to select the + signal to send. + + + + is-active PATTERN... + + + Check whether any of the specified units are active + (i.e. running). Returns an exit code + 0 if at least one is active, or + non-zero otherwise. Unless is + specified, this will also print the current unit state to + standard output. + + + + is-failed PATTERN... + + + Check whether any of the specified units are in a + "failed" state. Returns an exit code + 0 if at least one has failed, + non-zero otherwise. Unless is + specified, this will also print the current unit state to + standard output. + + + + status PATTERN...|PID...] + + + Show terse runtime status information about one or + more units, followed by most recent log data from the + journal. If no units are specified, show all units (subject + to limitations specified with ). If a PID + is passed, show information about the unit the process + belongs to. + + This function is intended to generate human-readable + output. If you are looking for computer-parsable output, + use show instead. By default this + function only shows 10 lines of output and ellipsizes + lines to fit in the terminal window. This can be changes + with and , + see above. In addition, journalctl + --unit=NAME or + journalctl + --user-unit=NAME use + a similar filter for messages and might be more + convenient. + + + + + show PATTERN...|JOB... + + + Show properties of one or more units, jobs, or the + manager itself. If no argument is specified, properties of + the manager will be shown. If a unit name is specified, + properties of the unit is shown, and if a job id is + specified, properties of the job is shown. By default, empty + properties are suppressed. Use to + show those too. To select specific properties to show, use + . This command is intended to be + used whenever computer-parsable output is required. Use + status if you are looking for formatted + human-readable output. + + + + cat PATTERN... + + + Show backing files of one or more units. Prints the + "fragment" and "drop-ins" (source files) of units. Each + file is preceded by a comment which includes the file + name. + + + + set-property NAME ASSIGNMENT... + + + Set the specified unit properties at runtime where + this is supported. This allows changing configuration + parameter properties such as resource control settings at + runtime. Not all properties may be changed at runtime, but + many resource control settings (primarily those in + systemd.resource-control5) + may. The changes are applied instantly, and stored on disk + for future boots, unless is + passed, in which case the settings only apply until the + next reboot. The syntax of the property assignment follows + closely the syntax of assignments in unit files. + + Example: systemctl set-property foobar.service CPUShares=777 + + Note that this command allows changing multiple + properties at the same time, which is preferable over + setting them individually. Like unit file configuration + settings, assigning the empty list to list parameters will + reset the list. + + + + + help PATTERN...|PID... + + + Show manual pages for one or more units, if + available. If a PID is given, the manual pages for the unit + the process belongs to are shown. + + + + + reset-failed [PATTERN...] + + + Reset the failed state of the + specified units, or if no unit name is passed, reset the state of all + units. When a unit fails in some way (i.e. process exiting + with non-zero error code, terminating abnormally or timing + out), it will automatically enter the + failed state and its exit code and status + is recorded for introspection by the administrator until the + service is restarted or reset with this command. + + + + + list-dependencies NAME + + + Shows required and wanted units of the specified + unit. If no unit is specified, + default.target is implied. Target units + are recursively expanded. When is + passed, all other units are recursively expanded as + well. + + + + + + + Unit File Commands + + + + list-unit-files PATTERN... + + + List installed unit files. If one or more + PATTERNs are specified, only + units whose filename (just the last component of the path) + matches one of them are shown. + + + + + enable NAME... + + + Enable one or more unit files or unit file instances, + as specified on the command line. This will create a number + of symlinks as encoded in the [Install] + sections of the unit files. After the symlinks have been + created, the systemd configuration is reloaded (in a way that + is equivalent to daemon-reload) to ensure + the changes are taken into account immediately. Note that + this does not have the effect of also + starting any of the units being enabled. If this + is desired, a separate start command must + be invoked for the unit. Also note that in case of instance + enablement, symlinks named the same as instances are created in + the install location, however they all point to the same + template unit file. + + This command will print the actions executed. This + output may be suppressed by passing . + + + Note that this operation creates only the suggested + symlinks for the units. While this command is the + recommended way to manipulate the unit configuration + directory, the administrator is free to make additional + changes manually by placing or removing symlinks in the + directory. This is particularly useful to create + configurations that deviate from the suggested default + installation. In this case, the administrator must make sure + to invoke daemon-reload manually as + necessary to ensure the changes are taken into account. + + + Enabling units should not be confused with starting + (activating) units, as done by the start + command. Enabling and starting units is orthogonal: units + may be enabled without being started and started without + being enabled. Enabling simply hooks the unit into various + suggested places (for example, so that the unit is + automatically started on boot or when a particular kind of + hardware is plugged in). Starting actually spawns the daemon + process (in case of service units), or binds the socket (in + case of socket units), and so on. + + Depending on whether , + , , + or is specified, this enables the unit + for the system, for the calling user only, for only this boot of + the system, or for all future logins of all users, or only this + boot. Note that in the last case, no systemd daemon + configuration is reloaded. + + + + + disable NAME... + + + Disables one or more units. This removes all symlinks + to the specified unit files from the unit configuration + directory, and hence undoes the changes made by + enable. Note however that this removes + all symlinks to the unit files (i.e. including manual + additions), not just those actually created by + enable. This call implicitly reloads the + systemd daemon configuration after completing the disabling + of the units. Note that this command does not implicitly + stop the units that are being disabled. If this is desired, + an additional stop command should be + executed afterwards. + + This command will print the actions executed. This + output may be suppressed by passing . + + + This command honors , + , and + in a similar way as + enable. + + + + + is-enabled NAME... + + + Checks whether any of the specified unit files are + enabled (as with enable). Returns an + exit code of 0 if at least one is enabled, non-zero + otherwise. Prints the current enable status (see table). + To suppress this output, use . + + + + + <command>is-enabled</command> output + + + + + + Printed string + Meaning + Return value + + + + + enabled + Enabled through a symlink in .wants directory (permanently or just in /run) + 0 + + + enabled-runtime + + + linked + Made available through a symlink to the unit file (permanently or just in /run) + 1 + + + linked-runtime + + + masked + Disabled entirely (permanently or just in /run) + 1 + + + masked-runtime + + + static + Unit is not enabled, but has no provisions for enabling in [Install] section + 0 + + + disabled + Unit is not enabled + 1 + + + +
+ +
+
+ + + reenable NAME... + + + Reenable one or more unit files, as specified on the + command line. This is a combination of + disable and enable and + is useful to reset the symlinks a unit is enabled with to + the defaults configured in the [Install] + section of the unit file. + + + + + preset NAME... + + + Reset one or more unit files, as specified on the + command line, to the defaults configured in the preset + policy files. This has the same effect as + disable or enable, + depending how the unit is listed in the preset files. For + more information on the preset policy format, see + systemd.preset5. + For more information on the concept of presets, please + consult the + Preset + document. + + + + + mask NAME... + + + Mask one or more unit files, as specified on the + command line. This will link these units to + /dev/null, making it impossible to + start them. This is a stronger version of + disable, since it prohibits all kinds of + activation of the unit, including manual activation. Use + this option with care. This honors the + option to only mask temporarily + until the next reoobt of the system. + + + + + unmask NAME... + + + Unmask one or more unit files, as specified on the + command line. This will undo the effect of + mask. + + + + + link FILENAME... + + + Link a unit file that is not in the unit file search + paths into the unit file search path. This requires an + absolute path to a unit file. The effect of this can be + undone with disable. The effect of this + command is that a unit file is available for + start and other commands although it + is not installed directly in the unit search path. + + + + + get-default + + + Get the default target specified + via default.target link. + + + + + set-default NAME + + + Set the default target to boot into. Command links + default.target to the given unit. + + +
+
+ + + Job Commands + + + + list-jobs PATTERN... + + + List jobs that are in progress. If one or more + PATTERNs are specified, only + jobs for units matching one of them are shown. + + + + cancel JOB... + + + Cancel one or more jobs specified on the command line + by their numeric job IDs. If no job ID is specified, cancel + all pending jobs. + + + + + + + Snapshot Commands + + + + snapshot NAME + + + Create a snapshot. If a snapshot name is specified, + the new snapshot will be named after it. If none is + specified, an automatic snapshot name is generated. In + either case, the snapshot name used is printed to standard + output, unless is specified. + + + A snapshot refers to a saved state of the systemd + manager. It is implemented itself as a unit that is + generated dynamically with this command and has dependencies + on all units active at the time. At a later time, the user + may return to this state by using the + isolate command on the snapshot unit. + + + Snapshots are only useful for saving and restoring + which units are running or are stopped, they do not + save/restore any other state. Snapshots are dynamic and lost + on reboot. + + + + delete PATTERN... + + + Remove a snapshot previously created with + snapshot. + + + + + + + Environment Commands + + + + show-environment + + + Dump the systemd manager environment block. The + environment block will be dumped in straight-forward form + suitable for sourcing into a shell script. This environment + block will be passed to all processes the manager + spawns. + + + + set-environment VARIABLE=VALUE... + + + Set one or more systemd manager environment variables, + as specified on the command line. + + + + unset-environment VARIABLE... + + + Unset one or more systemd manager environment + variables. If only a variable name is specified, it will be + removed regardless of its value. If a variable and a value + are specified, the variable is only removed if it has the + specified value. + + + + import-environment VARIABLE... + + + Import all, one or more environment variables set on + the client into the systemd manager environment block. If + no arguments are passed, the entire environment block is + imported. Otherwise, a list of one or more environment + variable names should be passed, whose client-side values + are then imported into the manager's environment + block. + + + + + + + Manager Lifecycle Commands + + + + daemon-reload + + + Reload systemd manager configuration. This will reload + all unit files and recreate the entire dependency + tree. While the daemon is being reloaded, all sockets systemd + listens on on behalf of user configuration will stay + accessible. This command should not be confused + with the load or + reload commands. + + + + daemon-reexec + + + Reexecute the systemd manager. This will serialize the + manager state, reexecute the process and deserialize the + state again. This command is of little use except for + debugging and package upgrades. Sometimes, it might be + helpful as a heavy-weight daemon-reload. + While the daemon is being reexecuted, all sockets systemd listening + on behalf of user configuration will stay accessible. + + + + + + + + System Commands + + + + default + + + Enter default mode. This is mostly equivalent to + isolate default.target. + + + + rescue + + + Enter rescue mode. This is mostly equivalent to + isolate rescue.target, but also prints a + wall message to all users. + + + + emergency + + + Enter emergency mode. This is mostly equivalent to + isolate emergency.target, but also prints + a wall message to all users. + + + + halt + + + Shut down and halt the system. This is mostly equivalent to + start halt.target --irreversible, but also + prints a wall message to all users. If combined with + , shutdown of all running services is + skipped, however all processes are killed and all file + systems are unmounted or mounted read-only, immediately + followed by the system halt. If is + specified twice, the operation is immediately executed + without terminating any processes or unmounting any file + systems. This may result in data loss. + + + + poweroff + + + Shut down and power-off the system. This is mostly + equivalent to start poweroff.target --irreversible, + but also prints a wall message to all users. If combined with + , shutdown of all running services is + skipped, however all processes are killed and all file + systems are unmounted or mounted read-only, immediately + followed by the powering off. If is + specified twice, the operation is immediately executed + without terminating any processes or unmounting any file + systems. This may result in data loss. + + + + reboot arg + + + Shut down and reboot the system. This is mostly + equivalent to start reboot.target --irreversible, + but also prints a wall message to all users. If combined with + , shutdown of all running services is + skipped, however all processes are killed and all file + systems are unmounted or mounted read-only, immediately + followed by the reboot. If is + specified twice, the operation is immediately executed + without terminating any processes or unmounting any file + systems. This may result in data loss. + + If the optional argument + arg is given, it will be passed + as the optional argument to the + reboot2 + system call. The value is architecture and firmware + specific. As an example, recovery might + be used to trigger system recovery, and + fota might be used to trigger a + firmware over the air update. + + + + kexec + + + Shut down and reboot the system via kexec. This is + mostly equivalent to start kexec.target --irreversible, + but also prints a wall message to all users. If combined + with , shutdown of all running + services is skipped, however all processes are killed and + all file systems are unmounted or mounted read-only, + immediately followed by the reboot. + + + + exit + + + Ask the systemd manager to quit. This is only + supported for user service managers (i.e. in conjunction + with the option) and will fail + otherwise. + + + + + suspend + + + Suspend the system. This will trigger activation of + the special suspend.target target. + + + + + hibernate + + + Hibernate the system. This will trigger activation of + the special hibernate.target target. + + + + + hybrid-sleep + + + Hibernate and suspend the system. This will trigger + activation of the special + hybrid-sleep.target target. + + + + switch-root ROOT INIT + + + Switches to a different root directory and executes a + new system manager process below it. This is intended for + usage in initial RAM disks ("initrd"), and will transition + from the initrd's system manager process (a.k.a "init" + process) to the main system manager process. This call takes two + arguments: the directory that is to become the new root directory, and + the path to the new system manager binary below it to + execute as PID 1. If the latter is omitted or the empty + string, a systemd binary will automatically be searched for + and used as init. If the system manager path is omitted or + equal to the empty string, the state of the initrd's system + manager process is passed to the main system manager, which + allows later introspection of the state of the services + involved in the initrd boot. + + + + + + + Parameter Syntax + + Unit ommands listed above take either a single unit name + (designated as NAME), or multiple + unit specifications (designated as + PATTERN...). In the first case, the + unit name with or without a suffix must be given. If the suffix + is not specified, systemctl will append a suitable suffix, + .service by default, and a type-specific + suffix in case of commands which operate only on specific unit + types. For example, + # systemctl start sshd and + # systemctl start sshd.service + are equivalent, as are + # systemctl isolate snapshot-11 + and + # systemctl isolate snapshot-11.snapshot + Note that (absolute) paths to device nodes are automatically + converted to device unit names, and other (absolute) paths to + mount unit names. + # systemctl status /dev/sda +# systemctl status /home + are equivalent to: + # systemctl status dev-sda.device +# systemctl status home.mount + In the second case, shell-style globs will be matched against + currently loaded units; literal unit names, with or without + a suffix, will be treated as in the first case. This means that + literal unit names always refer to exactly one unit, but globs + may match zero units and this is not considered an error. + + Glob patterns use + fnmatch3, + so normal shell-style globbing rules are used, and + *, ?, + [] may be used. See + glob7 + for more details. The patterns are matched against the names of + currently loaded units, and patterns which do not match anything + are silently skipped. For example: + # systemctl stop sshd@*.service + will stop all sshd@.service instances. + + + For unit file commands, the specified + NAME should be the full name of the + unit file, or the absolute path to the unit file: + # systemctl enable foo.service + or + # systemctl link /path/to/foo.service + + + +
+ + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + + + See Also + + systemd1, + systemadm1, + journalctl1, + loginctl1, + systemd.unit5, + systemd.resource-management5, + systemd.special7, + wall1, + systemd.preset5 + glob7 + +
diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml new file mode 100644 index 0000000..717f5c0 --- /dev/null +++ b/man/systemd-activate.xml @@ -0,0 +1,172 @@ + + + + + + + + + systemd-activate + systemd + + + + Developer + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + systemd-activate + 8 + + + + systemd-activate + Test socket activation of daemons + + + + + /usr/lib/systemd/systemd-activate + OPTIONS + daemon + OPTIONS + + + + + Description + + systemd-activate can be used to + launch a socket activated daemon from the command-line for + testing purposes. It can also be used to launch single instances + of the daemon per connection (inetd-style). + + + The daemon to launch and its options should be specifed + after options intended for systemd-activate. + + + If the option is given, file descriptor + of the connection will be used as the standard input and output of + the launched process. Otherwise, standard input and output will be + inherited, and sockets will be passed through file descriptors 3 + and higher. Sockets passed through $LISTEN_FDS + to systemd-activate will be passed through to + the dameon, in the original positions. Other sockets specified + with will use consecutive descriptors. + + + + + Options + + + + + + Listen on this address. + Takes a string like 2000 or + 127.0.0.1:2001. + + + + + + + + Launch a separate instance of daemon per + connection and pass the connection socket as standard input + and standard output. + + + + + + + Add this variable to the environment of the + launched process. If VAR is + followed by =, assume that it is a + variable–value pair. Otherwise, obtain the value from the + environment of systemd-activate itself. + + + + + + + + + + Environment variables + + + $LISTEN_FDS + $LISTEN_PID + + See + sd_listen_fds3. + + + + $SYSTEMD_LOG_TARGET + $SYSTEMD_LOG_LEVEL + $SYSTEMD_LOG_COLOR + $SYSTEMD_LOG_LOCATION + + Same as in + systemd1. + + + + + + Example 1 + + $ /usr/lib/systemd/systemd-activate -l 2000 -a cat + + This runs an echo server on port 2000. + + + + Example 2 + + $ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd + + This runs a socket activated instance of + systemd-journal-gatewayd8. + + + + See Also + + systemd1, + systemd.socket5, + systemd.service5, + cat1 + + + diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml new file mode 100644 index 0000000..c7a2598 --- /dev/null +++ b/man/systemd-analyze.xml @@ -0,0 +1,304 @@ + + + + + + + + + systemd-analyze + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + Developer + Harald + Hoyer + harald@redhat.com + + + + + + systemd-analyze + 1 + + + + systemd-analyze + Analyze system boot-up performance + + + + + systemd-analyze + OPTIONS + time + + + systemd-analyze + OPTIONS + blame + + + systemd-analyze + OPTIONS + critical-chain + UNIT + + + systemd-analyze + OPTIONS + plot + > file.svg + + + systemd-analyze + OPTIONS + dot + PATTERN + > file.dot + + + systemd-analyze + OPTIONS + dump + + + systemd-analyze + OPTIONS + set-log-level + LEVEL + + + + + Description + + systemd-analyze may be used + to determine system boot-up performance statistics and + retrieve other state and tracing information from the + system and service manager. + + systemd-analyze time + 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. + + systemd-analyze blame 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. + + systemd-analyze critical-chain [UNIT...] + prints a tree of the time-critical chain of units + (for each of the specified UNITs + 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. + + systemd-analyze plot prints + an SVG graphic detailing which system services have + been started at what time, highlighting the time they + spent on initialization. + + systemd-analyze dot generates + textual dependency graph description in dot format for + further processing with the GraphViz + dot1 + tool. Use a command line like systemd-analyze + dot | dot -Tsvg > systemd.svg to generate a + graphical dependency tree. Unless + or + is passed, the generated graph will show both ordering + and requirement dependencies. Optional pattern + globbing style specifications + (e.g. *.target) 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. + + systemd-analyze dump 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. + + systemd-analyze set-log-level + LEVEL changes the + current log level of the systemd + daemon to LEVEL (accepts + the same values as + described in + systemd1). + + If no command is passed, systemd-analyze + time is implied. + + + + + Options + + The following options are understood: + + + + + + Shows performance data + of user sessions instead of the system + manager. + + + + + + Shows performance data + of the system manager. This is the + implied default. + + + + + + + When used in + conjunction with the + dot command (see + above), selects which dependencies are + shown in the dependency graph. If + is passed, + only dependencies of type + After= or + Before= are + shown. If + is passed, only dependencies of type + Requires=, + RequiresOverridable=, + Requisite=, + RequisiteOverridable=, + Wants= and + Conflicts= are + shown. If neither is passed, this shows + dependencies of all these + types. + + + + + + + When used in + conjunction with the + dot command (see + above), this selects which relationships + are shown in the dependency graph. + They both require + glob7 + patterns as arguments, which are + matched against left-hand and + right-hand, respectively, nodes of a + relationship. Each of these can be + used more than once, which means a + unit name must match one of the given + values. + + + + timespan + + When used in conjunction + with the critical-chain + command (see above), also show units, which + finished timespan earlier, than the + latest unit in the same level. The unit of + timespan is seconds + unless specified with a different unit, + e.g. "50ms". + + + + + + + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + Examples + + This plots all dependencies of any unit whose + name starts with avahi-daemon.: + + $ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg > avahi.svg +$ eog avahi.svg + + This plots the dependencies between all known target units: + + systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' | dot -Tsvg > targets.svg +$ eog targets.svg + + + + + + + + See Also + + systemd1, + systemctl1 + + + + diff --git a/man/systemd-ask-password-console.service.xml b/man/systemd-ask-password-console.service.xml new file mode 100644 index 0000000..6c87feb --- /dev/null +++ b/man/systemd-ask-password-console.service.xml @@ -0,0 +1,96 @@ + + + + + + + + systemd-ask-password-console.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-ask-password-console.service + 8 + + + + systemd-ask-password-console.service + systemd-ask-password-console.path + systemd-ask-password-wall.service + systemd-ask-password-wall.path + Query the user for system passwords on the + console and via wall + + + + systemd-ask-password-console.service + systemd-ask-password-console.path + systemd-ask-password-wall.service + systemd-ask-password-wall.path + + + + Description + + systemd-ask-password-console.service + is a system service that queries the user for system + passwords (such as hard disk encryption keys and SSL + certificate passphrases) on the console. It is + intended to be used during boot to ensure proper + handling of passwords necessary for + boot. systemd-ask-password-wall.service + is a system service that informs all logged in users + for system passwords via + wall1. It + is intended to be used after boot to ensure that users + are properly notified. + + See the + developer documentation for more information + about the system password logic. + + Note that these services invoke + systemd-tty-ask-password-agent1 + with either the --watch --console + or --watch --wall command line + parameters. + + + + See Also + + systemd1, + systemd-tty-ask-password-agent1, + wall1 + + + + diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index c607b1a..805827e 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -8,20 +8,21 @@ Copyright 2011 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd-ask-password @@ -60,7 +61,7 @@ used to query a system password or passphrase from the user, using a question message specified on the command line. When run from a TTY it will query a - password on the TTY and print it to STDOUT. When run + password on the TTY and print it to standard output. When run with no TTY or with it will query the password system-wide and allow active users to respond via several agents. The latter is @@ -90,7 +91,7 @@ url="http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">systemd Password Agent Specification
. - If a password is queried on a tty the user may + If a password is queried on a TTY, the user may press TAB to hide the asterisks normally shown for each character typed. Pressing Backspace as first key achieves the same effect. @@ -104,14 +105,6 @@ - - - - Prints a short help - text and exits. - - - Specify an icon name @@ -129,7 +122,8 @@ Specify the query timeout in seconds. Defaults to - 90s. + 90s. A timeout of 0 waits indefinitely. + @@ -144,7 +138,7 @@ - If passed accept + If passed, accept cached passwords, i.e. passwords previously typed in. @@ -159,6 +153,8 @@ output one password per line. + + @@ -166,7 +162,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. diff --git a/man/systemd-backlight@.service.xml b/man/systemd-backlight@.service.xml new file mode 100644 index 0000000..453afbf --- /dev/null +++ b/man/systemd-backlight@.service.xml @@ -0,0 +1,92 @@ + + + + + + + + systemd-backlight@.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-backlight@.service + 8 + + + + systemd-backlight@.service + systemd-backlight + Load and save the display backlight brightness at boot and shutdown + + + + systemd-backlight@.service + /usr/lib/systemd/systemd-backlight + + + + Description + + systemd-backlight@.service + is a service that restores the display backlight + brightness at early boot and saves it at shutdown. On + disk, the backlight brightness is stored in + /var/lib/systemd/backlight/. + + + + Kernel Command Line + + systemd-backlight understands + the following kernel command line parameter: + + + + systemd.restore_state= + + Takes a boolean + argument. Defaults to + 1. If + 0, does not restore + the backlight settings on boot. However, + settings will still be stored on shutdown. + + + + + + + See Also + + systemd1 + + + + diff --git a/man/systemd-binfmt.service.xml b/man/systemd-binfmt.service.xml new file mode 100644 index 0000000..748e417 --- /dev/null +++ b/man/systemd-binfmt.service.xml @@ -0,0 +1,76 @@ + + + + + + + + systemd-binfmt.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-binfmt.service + 8 + + + + systemd-binfmt.service + systemd-binfmt + Configure additional binary formats for executables at boot + + + + systemd-binfmt.service + /usr/lib/systemd/systemd-binfmt + + + + Description + + systemd-binfmt.service is + an early-boot service that registers additional binary + formats for executables in the kernel. + + See + binfmt.d5 + for information about the configuration of this + service. + + + + See Also + + systemd1, + binfmt.d5, + wine8 + + + + diff --git a/man/systemd-bootchart.xml b/man/systemd-bootchart.xml new file mode 100644 index 0000000..6659b90 --- /dev/null +++ b/man/systemd-bootchart.xml @@ -0,0 +1,335 @@ + + + + + + + + + + systemd-bootchart + systemd + + + + Developer + Auke + Kok + auke-jan.h.kok@intel.com + + + + + + systemd-bootchart + 1 + + + + systemd-bootchart + Boot performance graphing tool + + + + Description + + systemd-bootchart is a + tool, usually run at system startup, that + collects the CPU load, disk load, memory + usage, as well as per-process information from + a running system. Collected results are output + as an SVG graph. Normally, systemd-bootchart + is invoked by the kernel by passing + + on the kernel commandline. systemd-bootchart will then + fork the real init off to resume normal system + startup, while monitoring and logging startup + information in the background. + + + After collecting a certain amount of data + (usually 15-30 seconds, default 20 s) the + logging stops and a graph is generated from + the logged information. This graph contains + vital clues as to which resources are being used, + in which order, and where possible problems + exist in the startup sequence of the system. + It is essentially a more detailed version of + the systemd-analyze + plot function. + + + Of course, bootchart can also be used at any + moment in time to collect and graph some data + for an amount of time. It is + recommended to use the + switch in this case. + + + Bootchart does not require root privileges, + and will happily run as a normal user. + + + Bootchart graphs are by default written + time-stamped in /run/log + and saved to the journal with + MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518. + Journal field BOOTCHART= contains + the bootchart in SVG format. + + + + + + Invocation + + systemd-bootchart can be invoked in several different ways: + + + + + Kernel invocation + The kernel can invoke + systemd-bootchart + instead of the init process. In turn, + systemd-bootchart + will invoke /sbin/init. + + + + + Started as a standalone program + One can execute + systemd-bootchart + as normal application from the + commandline. In this mode it is highly + recommended to pass the + flag in order to + not graph the time elapsed since boot + and before systemd-bootchart was + started, as it may result in extremely + large graphs. + + + + + + Options + + These options can also be set in the + /etc/systemd/bootchart.conf + file. See + bootchart.conf5. + + + + + + + + + Specify the number of + samples, N, + to record. Samples will be recorded at + intervals defined with . + + + + + + + Specify the sample log + frequency, a positive real f, in Hz. + Most systems can cope with values up to 25-50 without + creating too much overhead. + + + + + + Use relative times instead of absolute + times. This is useful for using bootchart at post-boot + time to profile an already booted system. Without this + option the graph would become extremely large. If set, the + horizontal axis starts at the first recorded sample + instead of time 0.0. + + + + + + Disable filtering of tasks that + did not contribute significantly to the boot. Processes + that are too short-lived (only seen in one sample) or + that do not consume any significant CPU time (less than + 0.001 s) will not be displayed in the output graph. + + + + + + + Display the full command line with arguments of processes, + instead of only the process name. + + + + + + + Display process control group + + + + + + + Specify the output directory for the + graphs. By default, bootchart writes the graphs to + /run/log. + + + + + + Use this init binary. Defaults to + /sbin/init. + + + + + + + Enable logging and graphing + of processes' PSS (Proportional Set Size) + memory consumption. See filesystems/proc.txt + in the kernel documentation for an + explanation of this field. + + + + + + + Enable logging and graphing + of the kernel random entropy pool size. + + + + + + Horizontal scaling factor for all variable + graph components. + + + + + + Vertical scaling factor for all variable + graph components. + + + + + + + + + Output + + systemd-bootchart generates SVG graphs. In order to render those + on a graphical display any SVG capable viewer can be used. It should be + noted that the SVG render engines in most browsers (including Chrome + and Firefox) are many times faster than dedicated graphical applications + like Gimp and Inkscape. Just point your browser at ! + + + + + History + + This version of bootchart was implemented from + scratch, but is inspired by former bootchart + incantations: + + + + Original bash + The original bash/shell code implemented + bootchart. This version created a compressed tarball for + processing with external applications. This version did + not graph anything, only generated data. + + + + Ubuntu C Implementation + This version replaced the shell version with + a fast and efficient data logger, but also did not graph + the data. + + + + Java bootchart + This was the original graphing application + for charting the data, written in java. + + + + pybootchartgui.py + pybootchart created a graph from the data + collected by either the bash or C version. + + + + The version of bootchart you are using now combines both the data + collection and the charting into a single application, making it more + efficient and simpler. There are no longer any timing issues with the data + collector and the grapher, as the graphing cannot be run until the data + has been collected. Also, the data kept in memory is reduced to the absolute + minimum needed. + + + + + See Also + + bootchart.conf5 + + + + + Bugs + systemd-bootchart does not get the model information for the hard drive + unless the root device is specified with root=/dev/sdxY. Using + UUIDs or PARTUUIDs will boot fine, but the hard drive model will not be + added to the chart. + For bugs, please contact the author and current maintainer: + + Auke Kok auke-jan.h.kok@intel.com + + + + diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml new file mode 100644 index 0000000..91a6fe3 --- /dev/null +++ b/man/systemd-bus-proxyd.xml @@ -0,0 +1,109 @@ + + + + + + + + + systemd-bus-proxyd + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-bus-proxyd + 8 + + + + systemd-bus-proxyd + Connect STDIO or a socket to a given bus address + + + + + /usr/lib/systemd/systemd-bus-proxyd + OPTIONS + PLACEHOLDER + + + + + Description + + systemd-bus-proxyd will proxy D-Bus + messages to and from a bus. The will be either the system bus or + the bus specified with when that option + is given. Messages will be proxied to/from standard input and + output, or the socket received through socket activation. + + This program can be used to connect a program using classic + D-Bus to kdbus. + + + + Options and Arguments + + The following options are understood: + + + + + + + Connect to the bus specified by + ADDRESS. Multiple colon-seperated + addresses can be specified, in which case + systemd-bus-proxyd will attempt to + connect to them in turn. + + + + + + + + PLACEHOLDER, if given, must be a string + of x and will be used to display information about + the process that systemd-bus-proxyd is forwarding + messages for. + + + + See Also + + + dbus-daemon1, + D-Bus, + kdbus + + + diff --git a/man/systemd-bus-proxyd@.service.xml b/man/systemd-bus-proxyd@.service.xml new file mode 100644 index 0000000..75a3c8b --- /dev/null +++ b/man/systemd-bus-proxyd@.service.xml @@ -0,0 +1,81 @@ + + + + + + + + + systemd-bus-proxyd@.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-bus-proxyd@.service + 8 + + + + systemd-bus-proxyd@.service + systemd-bus-proxyd.socket + Proxy classic D-Bus clients to kdbus + + + + systemd-bus-proxyd@.service + systemd-bus-proxyd.socket + + + + Description + + systemd-bus-proxyd.socket will launch + systemd-bus-proxyd@.service for connections + to the classic D-Bus socket in + /run/dbus/system_bus_socket. + + systemd-bus-proxyd@.service is launched + for an existing D-Bus connection and will use + systemd-bus-proxyd to proxy messages from this + connection to the system bus (either kdbus or classic D-Bus). + + + + + See Also + + + systemd-bus-proxyd8 + dbus-daemon1 + D-Bus + kdbus + + + diff --git a/man/systemd-cat.xml b/man/systemd-cat.xml new file mode 100644 index 0000000..4098a76 --- /dev/null +++ b/man/systemd-cat.xml @@ -0,0 +1,194 @@ + + + + + + + + + systemd-cat + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-cat + 1 + + + + systemd-cat + Connect a pipeline or program's output with the journal + + + + + systemd-cat OPTIONS COMMAND ARGUMENTS + + + systemd-cat OPTIONS + + + + + Description + + systemd-cat may be used to + connect the standard input and output of a process to the + journal, or as a filter tool in a shell pipeline to + pass the output the previous pipeline element + generates to the journal. + + If no parameter is passed, + systemd-cat will write + everything it reads from standard input (stdin) to the journal. + + If parameters are passed, they are executed as + command line with standard output (stdout) and standard + error output (stderr) connected to the journal, so + that all it writes is stored in the journal. + + + + Options + + The following options are understood: + + + + + + + + + + Specify a short string + that is used to identify the logging + tool. If not specified, no identification + string is written to the journal. + + + + + + + Specify the default + priority level for the logged + messages. Pass one of + emerg, + alert, + crit, + err, + warning, + notice, + info, + debug, or a + value between 0 and 7 (corresponding + to the same named levels). These + priority values are the same as + defined by + syslog3. Defaults + to info. Note that + this simply controls the default, + individual lines may be logged with + different levels if they are prefixed + accordingly. For details see + + below. + + + + + + Controls whether lines + read are parsed for syslog priority + level prefixes. If enabled (the + default), a line prefixed with a + priority prefix such as + <5> is logged + at priority 5 + (notice), and + similar for the other priority + levels. Takes a boolean + argument. + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + Examples + + + Invoke a program + + This calls /bin/ls + with standard output and error connected to the + journal: + + # systemd-cat ls + + + + Usage in a shell pipeline + + This builds a shell pipeline also + invoking /bin/ls and + writes the output it generates to the + journal: + + # ls | systemd-cat + + + Even though the two examples have very similar + effects the first is preferable since only one process + is running at a time, and both stdout and stderr are + captured while in the second example, only stdout is + captured. + + + + See Also + + systemd1, + systemctl1, + logger1 + + + + diff --git a/man/systemd-cgls.xml b/man/systemd-cgls.xml index 8546e39..230957b 100644 --- a/man/systemd-cgls.xml +++ b/man/systemd-cgls.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd-cgls @@ -49,7 +50,9 @@ - systemd-cgls OPTIONS CGROUP + systemd-cgls + OPTIONS + CGROUP @@ -58,17 +61,20 @@ systemd-cgls recursively shows the contents of the selected Linux control group - hierarchy in a tree. If arguments are specified shows + hierarchy in a tree. If arguments are specified, shows all member processes of the specified control groups plus all their subgroups and their members. The control groups may either be specified by their full file paths or are assumed in the systemd control group hierarchy. If no argument is specified and the current working directory is beneath the control group mount - point /sys/fs/cgroup shows the contents + point /sys/fs/cgroup, shows the contents of the control group the working directory refers - to. Otherwise the full systemd control group hierarchy + to. Otherwise, the full systemd control group hierarchy is shown. + + By default, empty control groups are not + shown. @@ -78,12 +84,42 @@ - + + + Do not hide empty + control groups in the + output. + + + + + + + Do not ellipsize + process tree members. + + + + + + + Include kernel + threads in output. + + + + + - Prints a short help - text and exits. + Limit control groups shown to + the part corresponding to the + container MACHINE. + + + + @@ -91,7 +127,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. @@ -99,7 +135,10 @@ See Also systemd1, - systemctl1 + systemctl1, + systemd-cgtop1, + systemd-nspawn1, + ps1 diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml new file mode 100644 index 0000000..73f8e74 --- /dev/null +++ b/man/systemd-cgtop.xml @@ -0,0 +1,270 @@ + + + + + + + + + systemd-cgtop + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-cgtop + 1 + + + + systemd-cgtop + Show top control groups by their resource usage + + + + + systemd-cgtop + OPTIONS + + + + + Description + + systemd-cgtop shows the top + control groups of the local Linux control group + hierarchy, ordered by their CPU, memory, or disk I/O load. The + display is refreshed in regular intervals (by default + every 1s), similar in style to + top1. + If systemd-cgtop is not connected + to a tty, only one iteration is performed and no + columns headers are printed. This mode is suitable for + scripting. + + Resource usage is only accounted for control + groups in the relevant hierarchy, i.e. CPU usage is + only accounted for control groups in the + cpuacct hierarchy, memory usage + only for those in memory and disk + I/O usage for those in blkio. If + resource monitoring for these resources is required, + it is recommended to add the + CPUAccounting=1, + MemoryAccounting=1 and + BlockIOAccounting=1 settings in the + unit files in question. See + systemd.resource-control5 + for details. + + To emphasize this: unless + CPUAccounting=1, + MemoryAccounting=1 and + BlockIOAccounting=1 are enabled for + the services in question, no resource accounting will + be available for system services and the data shown by + systemd-cgtop will be + incomplete. + + + + Options + + The following options are understood: + + + + + + Order by control group + path name. + + + + + + Order by number of + tasks in control + group (i.e. threads and processes). + + + + + + Order by CPU load. + + + + + + Order by memory usage. + + + + + + Order by disk I/O load. + + + + + + + Run in "batch" mode: + do not accept input and run until the + iteration limit set with + is + exhausted or until killed. This mode + could be useful for sending output + from systemd-cgtop + to other programs or to a + file. + + + + + + + Perform only this many + iterations. + + + + + + + Specify refresh delay + in seconds (or if one of + ms, + us, + min is specified as + unit in this time + unit). + + + + + + Maximum control group + tree traversal depth. Specifies how + deep systemd-cgtop + shall traverse the control group + hierarchies. If 0 is specified, only + the root group is monitored. For 1, + only the first level of control groups + is monitored, and so on. Defaults to + 3. + + + + + + + + + + + Keys + + systemd-cgtop is an + interactive tool and may be controlled via user input + using the following keys: + + + + h + + Shows a short help text. + + + + SPACE + + Immediately refresh output. + + + + q + + Terminate the program. + + + + + p + t + c + m + i + + Sort the control groups + by path, number of tasks, CPU load, + memory usage, or IO + load, respectively. + + + + % + + Toggle between showing CPU time as + time or percentage. + + + + + + - + + Increase + or decrease refresh + delay, respectively. + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + systemctl1, + systemd-cgls1, + systemd.resource-control5, + top1 + + + + diff --git a/man/systemd-coredumpctl.xml b/man/systemd-coredumpctl.xml new file mode 100644 index 0000000..092ec56 --- /dev/null +++ b/man/systemd-coredumpctl.xml @@ -0,0 +1,198 @@ + + + + + + + + + systemd-coredumpctl + systemd + + + + Developer + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + systemd-coredumpctl + 1 + + + + systemd-coredumpctl + Retrieve coredumps from the journal + + + + + systemd-coredumpctl + OPTIONS + COMMAND + PID|COMM|EXE|MATCH + + + + + Description + + systemd-coredumpctl may be used to + retrieve coredumps from + systemd-journald8. + + + + Options + + The following options are understood: + + + + + + + Print all possible + data values the specified field + takes in matching coredump entries of the + journal. + + + + + + + Write the core to + . + + + + + + Do not print the column headers. + + + + + + + + + The following commands are understood: + + + + list + + List coredumps captured in the journal + matching specified characteristics. + + + + dump + + Extract the last coredump + matching specified characteristics. + The coredump will be written on standard output, + unless an output file is specified with + . + + + + + + gdb + + Invoke the GNU + debugger on the last coredump matching + specified characteristics. + + + + + + + + + Matching + + Match can be: + + + + PID + + Process ID of the + process that dumped + core. An integer. + + + + COMM + + Name of the executable + (matches ). + Must not contain slashes. + + + + + EXE + + Path to the executable + (matches ). + Must contain at least one slash. + + + + + MATCH + + General journalctl predicates + (see journalctl1). + Must contain an equals sign. + + + + + + + Exit status + On success, 0 is returned; otherwise, a non-zero failure + code is returned. Not finding any matching coredumps is treated + as failure. + + + + + See Also + + systemd-journald.service8, + gdb1 + + + + diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml new file mode 100644 index 0000000..3abb39d --- /dev/null +++ b/man/systemd-cryptsetup-generator.xml @@ -0,0 +1,194 @@ + + + + + + + + systemd-cryptsetup-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-cryptsetup-generator + 8 + + + + systemd-cryptsetup-generator + Unit generator for /etc/crypttab + + + + /usr/lib/systemd/system-generators/systemd-cryptsetup-generator + + + + Description + + systemd-cryptsetup-generator + is a generator that translates + /etc/crypttab into native systemd + units early at boot and when configuration of the + system manager is reloaded. This will create + systemd-cryptsetup@.service8 + units as necessary. + + systemd-cryptsetup-generator + implements the generator + specification. + + + + Kernel Command Line + + systemd-cryptsetup-generator understands + the following kernel command line parameters: + + + + luks= + rd.luks= + + Takes a boolean + argument. Defaults to + yes. If + no, disables the + generator + entirely. rd.luks= + is honored only by initial RAM disk + (initrd) while + luks= is honored + by both the main system and the + initrd. + + + + luks.crypttab= + rd.luks.crypttab= + + Takes a boolean + argument. Defaults to + yes. If + no, causes the + generator to ignore any devices + configured in + /etc/crypttab + (luks.uuid= will + still work + however). rd.luks.crypttab= + is honored only by initial RAM disk + (initrd) while + luks.crypttab= is + honored by both the main system and + the initrd. + + + + luks.uuid= + rd.luks.uuid= + + Takes a LUKS superblock + UUID as argument. This will + activate the specified device as part + of the boot process as if it was + listed in + /etc/fstab. This + option may be specified more than once + in order to set up multiple + devices. rd.luks.uuid= + is honored only by initial RAM disk + (initrd) while + luks.uuid= is + honored by both the main system and + the initrd. + If /etc/crypttab contains entries with + the same UUID, then the options for this entry + will be used. + If /etc/crypttab exists, only those UUID + specified on the kernel command line + will be activated in the initrd or the real root. + + + + + luks.options= + rd.luks.options= + + Takes a LUKS super + block UUID followed by an '=' and a string + of options separated by commas as argument. + This will override the options for the given + UUID. + If only a list of options, without an + UUID, is specified, they apply to any UUIDs not + specified elsewhere, and without an entry in + /etc/crypttab. + rd.luks.options= + is honored only by initial RAM disk + (initrd) while + luks.options= is + honored by both the main system and + the initrd. + + + + + luks.key= + rd.luks.key= + + Takes a password file as argument. + For those entries specified with + rd.luks.uuid= or luks.uuid=, + the password file will be set to the password file specified by + rd.luks.key= or luks.key + rd.luks.key= + is honored only by initial RAM disk + (initrd) while + luks.key= is + honored by both the main system and + the initrd. + + + + + + + See Also + + systemd1, + crypttab5, + systemd-cryptsetup@.service8, + cryptsetup8, + systemd-fstab-generator8 + + + + diff --git a/man/systemd-cryptsetup@.service.xml b/man/systemd-cryptsetup@.service.xml new file mode 100644 index 0000000..6fa2e0c --- /dev/null +++ b/man/systemd-cryptsetup@.service.xml @@ -0,0 +1,87 @@ + + + + + + + + systemd-cryptsetup@.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-cryptsetup@.service + 8 + + + + systemd-cryptsetup@.service + systemd-cryptsetup + Full disk decryption logic + + + + systemd-cryptsetup@.service + /usr/lib/systemd/systemd-cryptsetup + + + + Description + + systemd-cryptsetup@.service + is a service responsible for setting up encrypted + block devices. It is instantiated for each device that + requires decryption for access. + + systemd-cryptsetup@.service + will ask for hard disk passwords via the + password agent logic, in order to query the + user for the password using the right mechanism at + boot and during runtime. + + At early boot and when the system manager + configuration is reloaded this + /etc/crypttab is translated into + systemd-cryptsetup@.service units + by + systemd-cryptsetup-generator8. + + + + See Also + + systemd1, + systemd-cryptsetup-generator8, + crypttab5, + cryptsetup8 + + + + diff --git a/man/systemd-delta.xml b/man/systemd-delta.xml new file mode 100644 index 0000000..9117773 --- /dev/null +++ b/man/systemd-delta.xml @@ -0,0 +1,216 @@ + + + + + + + + + systemd-delta + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-delta + 1 + + + + systemd-delta + Find overridden configuration files + + + + + systemd-delta + OPTIONS + PREFIX/SUFFIX|SUFFIX + + + + + Description + + systemd-delta may be used to + identify and compare configuration files that override + other configuration files. Files in + /etc have highest priority, files + in /run have the second highest + priority, ..., files in /lib have + lowest priority. Files in a directory with higher + priority override files with the same name in + directories of lower priority. In addition, certain + configuration files can have .d + directories which contain "drop-in" files with + configuration snippets which augment the main + configuration file. "Drop-in" files can be overriden + in the same way by placing files with the same name in + a directory of higher priority (except that in case of + "drop-in" files, both the "drop-in" file name and the + name of the containing directory, which corresponds to + the name of the main configuration file, must match). + For a fuller explanation, see + systemd.unit5. + + + The command line argument will be split into a + prefix and a suffix. Either is optional. The prefix + must be one of the directories containing + configuration files (/etc, + /run, + /usr/lib, ...). If it is given, + only overriding files contained in this directory will + be shown. Otherwise, all overriding files will be + shown. The suffix must be a name of a subdirectory + containing configuration files like + tmpfiles.d, + sysctl.d or + systemd/system. If it is given, + only configuration files in this subdirectory (across + all configuration paths) will be analyzed. Otherwise, + all configuration files will be analyzed. If the + commandline argument is not given at all, all + configuration files will be analyzed. See below for + some examples. + + + + Options + + The following options are understood: + + + + + + + When listing the + differences, only list those that are + asked for. The list itself is a + comma-separated list of desired + difference types. + + Recognized types are: + + + + masked + + Show masked files + + + + equivalent + + Show overridden + files that while overridden, do + not differ in content. + + + + redirected + + Show files that + are redirected to another. + + + + overridden + + Show overridden, + and changed files. + + + + extended + + Show *.conf files in drop-in + directories for units. + + + + unchanged + + Show unmodified + files too. + + + + + + + + + When showing modified + files, when a file is overridden show a + diff as well. This option takes a + boolean argument. If omitted, it defaults + to . + + + + + + + + + + Examples + + To see all local configuration: + systemd-delta + + To see all runtime configuration: + systemd-delta /run + + To see all system unit configuration changes: + systemd-delta systemd/system + + To see all runtime "drop-in" changes for system units: + systemd-delta --type=extended /run/systemd/system + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + systemd.unit5 + + + + diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml new file mode 100644 index 0000000..bdf220e --- /dev/null +++ b/man/systemd-detect-virt.xml @@ -0,0 +1,140 @@ + + + + + + + + + systemd-detect-virt + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-detect-virt + 1 + + + + systemd-detect-virt + Detect execution in a virtualized environment + + + + + systemd-detect-virt OPTIONS + + + + + Description + + systemd-detect-virt detects + execution in a virtualized environment. It identifies + the virtualization technology and can distinguish full + VM virtualization from container + virtualization. + + When executed without + will print a short identifier for the detected + virtualization technology. The following technologies + are currently identified: qemu, + kvm, vmware, + microsoft, + oracle, xen, + bochs, chroot, + uml, + openvz, lxc, + lxc-libvirt, + systemd-nspawn. + + If multiple virtualization solutions are used, + only the "innermost" is detected and identified. That + means if both VM virtualization and container + virtualization are used in conjunction, only the latter + will be identified (unless is + passed). + + + + Options + + The following options are understood: + + + + + + + Only detects container + virtualization (i.e. shared kernel + virtualization). + + + + + + + Only detects VM + virtualization (i.e. full hardware + virtualization). + + + + + + + Suppress output of the + virtualization technology + identifier. + + + + + + + + + + Exit status + + If a virtualization technology is detected, 0 is + returned, a non-zero code otherwise. + + + + See Also + + systemd1 + + + + diff --git a/man/systemd-efi-boot-generator.xml b/man/systemd-efi-boot-generator.xml new file mode 100644 index 0000000..3a79dfb --- /dev/null +++ b/man/systemd-efi-boot-generator.xml @@ -0,0 +1,88 @@ + + + + + + + + systemd-efi-boot-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-efi-boot-generator + 8 + + + + systemd-efi-boot-generator + Generator for automatically mounting the + EFI System Partition used by the current boot to + /boot + + + + /usr/lib/systemd/system-generators/systemd-efi-boot-generator + + + + Description + + systemd-efi-boot-generator + is a generator that automatically creates mount and + automount units for the EFI System Partition (ESP), + mounting it to /boot. Note that + this generator will execute no operation on non-EFI + systems, on systems where the boot loader does not + communicate the used ESP to the OS, on systems where + /boot is an explicitly configured + mount (for example, listed in fstab5) or where the /boot mount + point is non-empty. Since this generator creates an + automount unit, the mount will only be activated + on-demand, when accessed. + + systemd-efi-boot-generator + implements the generator + specification. + + + + See Also + + systemd1, + systemd.mount5, + systemd.automount5, + systemd-gpt-auto-generator8, + gummiboot8, + fstab5 + + + + diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml new file mode 100644 index 0000000..c653dc5 --- /dev/null +++ b/man/systemd-fsck@.service.xml @@ -0,0 +1,113 @@ + + + + + + + + systemd-fsck@.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-fsck@.service + 8 + + + + systemd-fsck@.service + systemd-fsck-root.service + systemd-fsck + File system checker logic + + + + systemd-fsck@.service + systemd-fsck-root.service + /usr/lib/systemd/systemd-fsck + + + + Description + + systemd-fsck@.service is a + service responsible for file system checks. It is + instantiated for each device that requires a file + system + check. systemd-fsck-root.service is + responsible for file system checks on the root + file system. The root file system check is performed + before the other file systems. Either service is enabled + at boot if passno in /etc/fstab for + the file system is set to a value greater than zero. + + systemd-fsck will + forward file system checking progress to the + console. If a file system check fails, emergency mode + is activated, by isolating to + emergency.target. + + + + Kernel Command Line + + systemd-fsck understands + one kernel command line parameter: + + + + fsck.mode= + + One of + auto, + force, + skip. Controls the + mode of operation. The default is + auto, and ensures + that file system checks are done when + the file system checker deems them + necessary. force + unconditionally results in full file + system checks. skip + skips any file system + checks. + + + + + + See Also + + systemd1, + fsck8, + systemd-quotacheck.service8 + + + + diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml new file mode 100644 index 0000000..e3cf5d2 --- /dev/null +++ b/man/systemd-fstab-generator.xml @@ -0,0 +1,124 @@ + + + + + + + + systemd-fstab-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-fstab-generator + 8 + + + + systemd-fstab-generator + Unit generator for /etc/fstab + + + + /usr/lib/systemd/system-generators/systemd-fstab-generator + + + + Description + + systemd-fstab-generator is + a generator that translates + /etc/fstab (see + fstab5 + for details) into native systemd units early at boot + and when configuration of the system manager is + reloaded. This will instantiate mount and swap units + as necessary. + + The passno field is treated + like a simple boolean, and the ordering information is + discarded. However, if the root file system is + checked, it is checked before all the other + file systems. + + See + systemd.mount5 + and + systemd.swap5 + for more information about special + /etc/fstab mount options this + generator understands. + + systemd-fstab-generator + implements the generator + specification. + + + + Kernel Command Line + + systemd-fstab-generator understands + the following kernel command line parameters: + + + + + fstab= + rd.fstab= + + Takes a boolean + argument. Defaults to + yes. If + no, causes the + generator to ignore any mounts or swaps + configured in + /etc/fstab. rd.fstab= + is honored only by initial RAM disk + (initrd) while + fstab= is + honored by both the main system and + the initrd. + + + + + + + See Also + + systemd1, + fstab5, + systemd.mount5, + systemd.swap5, + systemd-cryptsetup-generator8 + + + + diff --git a/man/systemd-getty-generator.xml b/man/systemd-getty-generator.xml new file mode 100644 index 0000000..2f3d124 --- /dev/null +++ b/man/systemd-getty-generator.xml @@ -0,0 +1,101 @@ + + + + + + + + systemd-getty-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-getty-generator + 8 + + + + systemd-getty-generator + Generator for enabling getty instances on + the console + + + + /usr/lib/systemd/system-generators/systemd-getty-generator + + + + Description + + systemd-getty-generator is + a generator that automatically instantiates + serial-getty@.service on the + kernel console /dev/console if + that is not directed to the virtual console + subsystem. It will also instantiate + serial-getty@.service instances + for virtualizer consoles, if execution in a + virtualized environment is detected. Finally, it will + instantiate + container-getty@.service + instances for additional container pseudo TTYs as + requested by the container manager (see Container Interface). This + should ensure that the user is shown a login prompt at + the right place, regardless of which environment the + system is started in. For example, it is sufficient to + redirect the kernel console with a kernel command line + argument such as console= to get + both kernel messages and a getty prompt on a serial + TTY. See kernel-parameters.txt + for more information on the + console= kernel parameter. + + systemd-getty-generator + implements the generator + specification. + + Further information about configuration of + gettys you may find in systemd + for Administrators, Part XVI: Gettys on Serial + Consoles (and Elsewhere). + + + + See Also + + systemd1, + agetty8 + + + + diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml new file mode 100644 index 0000000..95c0c35 --- /dev/null +++ b/man/systemd-gpt-auto-generator.xml @@ -0,0 +1,104 @@ + + + + + + + + systemd-gpt-auto-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-gpt-auto-generator + 8 + + + + systemd-gpt-auto-generator + Generator for automatically discovering + and mounting /home as well as + discovering and enabling swap partitions, based on GPT + partition type GUIDs. + + + + /usr/lib/systemd/system-generators/systemd-gpt-auto-generator + + + + Description + + systemd-gpt-auto-generator + is a generator that automatically discovers + /home and swap partitions and + creates mount and swap units for them, based on the + the partition type GUIDs of GUID partition tables + (GPT). Note that this generator will execute no + operation on non-GPT systems, on systems where the + units are explicitly configured (for example, listed + in + fstab5) + or where the mount point is non-empty. + + This generator will only look for partitions on + the same physical disk the root file system is stored + on. This generator has no effect on systems where the + root file system is distributed on multiple disks, for + example via btrfs RAID. + + This generator is useful for centralizing file + system configuration in the partition table and making + manual configuration in + /etc/fstab or suchlike + unnecessary. + + This generator looks for swap partitions using + GPT type 0657fd6d-a4ab-43c4-84e50933c84b4f4f. It looks + for /home partitions using GPT + type 933ac7e1-2eb4-4f13-b8440e14e2aef915. + + systemd-gpt-auto-generator + implements the generator + specification. + + + + See Also + + systemd1, + systemd.mount5, + systemd.swap5, + systemd-efi-boot-generator8, + fstab5 + + + + diff --git a/man/systemd-halt.service.xml b/man/systemd-halt.service.xml new file mode 100644 index 0000000..552dbdf --- /dev/null +++ b/man/systemd-halt.service.xml @@ -0,0 +1,125 @@ + + + + + + + + + systemd-halt.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-halt.service + 8 + + + + systemd-halt.service + systemd-poweroff.service + systemd-reboot.service + systemd-kexec.service + systemd-shutdown + System shutdown logic + + + + systemd-halt.service + systemd-poweroff.service + systemd-reboot.service + systemd-kexec.service + /usr/lib/systemd/systemd-shutdown + + + + Description + + systemd-halt.service is a + system service that is pulled in by + halt.target and is responsible + for the actual system halt. Similarly, + systemd-poweroff.service is + pulled in by poweroff.target, + systemd-reboot.service by + reboot.target and + systemd-kexec.service by + kexec.target to execute the + respective actions. + + When these services are run, they ensure that PID + 1 is replaced by the + /usr/lib/systemd/systemd-shutdown + tool which is then responsible for the actual + shutdown. Before shutting down, this binary will try to + unmount all remaining file systems, disable all + remaining swap devices, detach all remaining storage + devices and kill all remaining processes. + + It is necessary to have this code in a separate binary + because otherwise rebooting after an upgrade might be broken — + the running PID 1 could still depend on libraries which are not + available any more, thus keeping the file system busy, which + then cannot be re-mounted read-only. + + Immediately before executing the actual system + halt/poweroff/reboot/kexec + systemd-shutdown will run all + executables in + /usr/lib/systemd/system-shutdown/ + and pass one arguments to them: either + halt, + poweroff, + reboot or + kexec, depending on the chosen + action. All executables in this directory are executed + in parallel, and execution of the action is not + continued before all executables finished. + + Note that + systemd-halt.service (and the + related units) should never be executed + directly. Instead, trigger system shutdown with a + command such as systemctl halt or + suchlike. + + + + See Also + + systemd1, + systemctl1, + systemd.special7, + reboot2, + systemd-suspend.service8 + + + + diff --git a/man/systemd-hostnamed.service.xml b/man/systemd-hostnamed.service.xml new file mode 100644 index 0000000..bdd3a51 --- /dev/null +++ b/man/systemd-hostnamed.service.xml @@ -0,0 +1,87 @@ + + + + + + + + + systemd-hostnamed.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-hostnamed.service + 8 + + + + systemd-hostnamed.service + systemd-hostnamed + Host name bus mechanism + + + + systemd-hostnamed.service + /usr/lib/systemd/systemd-hostnamed + + + + Description + + systemd-hostnamed is a system + service that may be used as a mechanism to change the + system's hostname. systemd-hostnamed is + automatically activated on request and terminates + itself when it is unused. + + The tool + hostnamectl1 + is a command-line client to this service. + + See the + developer documentation for information about + the APIs systemd-hostnamed + provides. + + + + See Also + + systemd1, + hostname5, + machine-info5, + hostnamectl1, + sethostname2 + + + + diff --git a/man/systemd-inhibit.xml b/man/systemd-inhibit.xml new file mode 100644 index 0000000..555c541 --- /dev/null +++ b/man/systemd-inhibit.xml @@ -0,0 +1,194 @@ + + + + + + + + + systemd-inhibit + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-inhibit + 1 + + + + systemd-inhibit + Execute a program with an inhibition lock taken + + + + + systemd-inhibit OPTIONS COMMAND ARGUMENTS + + + systemd-inhibit OPTIONS --list + + + + + Description + + systemd-inhibit may be used + to execute a program with a shutdown, sleep or idle + inhibitor lock taken. The lock will be acquired before + the specified command line is executed and released + afterwards. + + Inhibitor locks may be used to block or delay + system sleep and shutdown requests from the user, as well + as automatic idle handling of the OS. This is useful + to avoid system suspends while an optical disc is + being recorded, or similar operations that should not + be interrupted. + + For more information see the Inhibitor + Lock Developer Documentation. + + + + Options + + The following options are understood: + + + + + + Takes a colon-separated + list of one or more + operations to inhibit: + shutdown, + sleep, + idle, + handle-power-key, + handle-suspend-key, + handle-hibernate-key, + handle-lid-switch, + for inhibiting + reboot/power-off/halt/kexec, + suspending/hibernating, the automatic + idle detection, or the low-level + handling of the power/sleep key and + the lid switch, respectively. If omitted, + defaults to + idle:sleep:shutdown. + + + + + + Takes a short, + human-readable descriptive string for the + program taking the lock. If not passed, + defaults to the command line + string. + + + + + + Takes a short, + human-readable descriptive string for the + reason for taking the lock. Defaults + to "Unknown reason". + + + + + + Takes either + block or + delay and describes + how the lock is applied. If + block is used (the + default), the lock prohibits any of + the requested operations without time + limit, and only privileged users may + override it. If + delay is used, the + lock can only delay the requested + operations for a limited time. If the + time elapses, the lock is ignored and + the operation executed. The time limit + may be specified in + logind.conf5. Note + that delay is only + available for sleep + and + shutdown. + + + + + + Lists all active + inhibition locks instead of acquiring + one. + + + + + + + + + + Exit status + + Returns the exit status of the executed program. + + + + Example + + # systemd-inhibit wodim foobar.iso + + This burns the ISO image + foobar.iso on a CD using + wodim1, + and inhibits system sleeping, shutdown and idle while + doing so. + + + + See Also + + systemd1, + logind.conf5 + + + + diff --git a/man/systemd-initctl.service.xml b/man/systemd-initctl.service.xml new file mode 100644 index 0000000..eda6459 --- /dev/null +++ b/man/systemd-initctl.service.xml @@ -0,0 +1,76 @@ + + + + + + + + + systemd-initctl.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-initctl.service + 8 + + + + systemd-initctl.service + systemd-initctl.socket + systemd-initctl + /dev/initctl compatibility + + + + systemd-initctl.service + systemd-initctl.socket + /usr/lib/systemd/systemd-initctl + + + + Description + + systemd-initctl is a system + service that implements compatibility with the + /dev/initctl FIFO file system + object, as implemented by the SysV init system. systemd-initctl is + automatically activated on request and terminates + itself when it is unused. + + + + See Also + + systemd1 + + + + diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml new file mode 100644 index 0000000..01b2552 --- /dev/null +++ b/man/systemd-journal-gatewayd.service.xml @@ -0,0 +1,302 @@ + + + + + + + + + systemd-journal-gatewayd.service + systemd + + + + Developer + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + systemd-journal-gatewayd.service + 8 + + + + systemd-journal-gatewayd.service + systemd-journal-gatewayd.socket + systemd-journal-gatewayd + HTTP server for journal events + + + + systemd-journal-gatewayd.service + systemd-journal-gatewayd.socket + + /usr/lib/systemd/systemd-journal-gatewayd + OPTIONS + + + + + Description + + systemd-journal-gatewayd serves journal + events over the network. Clients must connect using + HTTP. The server listens on port 19531 by default. + If is specified, the server expects + HTTPS connections. + + The program is started by + systemd1 + and expects to receive a single socket. Use + systemctl start systemd-journal-gatewayd.socket to start + the service, and systemctl enable systemd-journal-gatewayd.socket + to have it started on boot. + + + + Options + + The following options are understood: + + + + + + Specify the path to a file containing a server + certificate in PEM format. This option switches + systemd-journal-gatewayd into HTTPS mode + and must be used together with + . + + + + + + Specify the path to a file containing a server + key in PEM format corresponding to the certificate specified + with . + + + + + + + + + Supported URLs + + The following URLs are recognized: + + + + /browse + + Interactive browsing. + + + + /entries[?option1&option2=value...] + + Retrieval of events in various formats. + + The part of the HTTP header + determines the format. Supported values are described below. + + + The part of the HTTP header + determines the range of events returned. Supported values are + described below. + + + GET parameters can be used to modify what events are + returned. Supported parameters are described below. + + + + + /machine + + Return a JSON structure describing the machine. + + Example: + { "machine_id" : "8cf7ed9d451ea194b77a9f118f3dc446", + "boot_id" : "3d3c9efaf556496a9b04259ee35df7f7", + "hostname" : "fedora", + "os_pretty_name" : "Fedora 19 (Rawhide)", + "virtualization" : "kvm", + ...} + + + + + + /fields/FIELD_NAME + + Return a list of values of this field present in the logs. + + + + + + + Accept header + + + + + + Recognized formats: + + + + text/plain + + The default. Plaintext syslog-like output, + one line per journal entry + (like journalctl --output short). + + + + + application/json + + Entries are formatted as JSON data structures, + one per line + (like journalctl --output json). + See Journal + JSON Format for more information. + + + + + application/event-stream + + Entries are formatted as JSON data structures, + wrapped in a format suitable for + Server-Sent Events + (like journalctl --output json-sse). + + + + + + application/vnd.fdo.journal + + Entries are serialized into a binary (but + mostly text-based) stream suitable for backups and network + transfer + (like journalctl --output export). + See Journal + Export Format for more information. + + + + + + + Range header + + + + + + where + is a cursor string, + is an integer, + is an unsigned integer. + + + Range defaults to all available events. + + + + URL GET parameters + + Following parameters can be used as part of the URL: + + + + follow + + wait for new events + (like journalctl --follow, except that + the number of events returned is not limited). + + + + + discrete + + Test that the specified cursor refers to an + entry in the journal. Returns just this entry. + + + + + boot + + Limit events to the current boot of the system + (like journalctl --this--boot). + + + + KEY=match + + Match journal fields. See + systemd.journal-fields7. + + + + + + + Examples + Retrieve events from this boot from local journal + in Journal + Export Format: + curl --silent -H'Accept: application/vnd.fdo.journal' \ + 'http://localhost:19531/entries?boot' + + + Listen for core dumps: + curl 'http://localhost:19531/entries?follow&MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1' + + + + See Also + + systemd1, + journalctl1, + systemd-journald.service8, + systemd.journal-fields7, + + + + diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml new file mode 100644 index 0000000..4d2cb40 --- /dev/null +++ b/man/systemd-journald.service.xml @@ -0,0 +1,253 @@ + + + + + + + + + systemd-journald.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-journald.service + 8 + + + + systemd-journald.service + systemd-journald.socket + systemd-journald + Journal service + + + + systemd-journald.service + systemd-journald.socket + /usr/lib/systemd/systemd-journald + + + + Description + + systemd-journald is a + system service that collects and stores logging data. + It creates and maintains structured, indexed journals + based on logging information that is received from the + kernel, from user processes via the libc + syslog3 + call, from standard input and standard error of system + services or via its native API. It will implicitly + collect numerous metadata fields for each log + messages in a secure and unfakeable way. See + systemd.journal-fields7 + for more information about the collected metadata. + + + Log data collected by the journal is primarily + text-based but can also include binary data where + necessary. All objects stored in the journal can be up + to 2^64-1 bytes in size. + + By default, the journal stores log data in + /run/log/journal/. Since + /run/ is volatile, log data is + lost at reboot. To make the data persistent, it + is sufficient to create + /var/log/journal/ where + systemd-journald will then store + the data. + + systemd-journald will + forward all received log messages to the AF_UNIX + SOCK_DGRAM socket + /run/systemd/journal/syslog, if it exists, which + may be used by Unix syslog daemons to process the data + further. + + See + journald.conf5 + for information about the configuration of this + service. + + + + Signals + + + + SIGUSR1 + + Request that journal + data from /run/ + is flushed to + /var/ in order to + make it persistent (if this is + enabled). This must be used after + /var/ is mounted, + as otherwise log data from + /run is never + flushed to /var + regardless of the + configuration. + + + + SIGUSR2 + + Request immediate + rotation of the journal + files. + + + + + + Kernel Command Line + + A few configuration parameters from + journald.conf may be overridden on + the kernel command line: + + + + systemd.journald.forward_to_syslog= + systemd.journald.forward_to_kmsg= + systemd.journald.forward_to_console= + + Enables/disables + forwarding of collected log messages + to syslog, the kernel log buffer or + the system console. + + + See + journald.conf5 + for information about these settings. + + + + + + + + Access Control + + Journal files are, by default, owned and readable + by the systemd-journal system group + but are not writable. Adding a user to this group thus + enables her/him to read the journal files. + + By default, each logged in user will get her/his + own set of journal files in + /var/log/journal/. These files + will not be owned by the user, however, in order to + avoid that the user can write to them + directly. Instead, file system ACLs are used to ensure + the user gets read access only. + + Additional users and groups may be granted + access to journal files via file system access control + lists (ACL). Distributions and administrators may + choose to grant read access to all members of the + wheel and adm + system groups with a command such as the + following: + + # setfacl -Rnm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal/ + + Note that this command will update the ACLs both + for existing journal files and for future journal + files created in the + /var/log/journal/ + directory. + + + + Files + + + + /etc/systemd/journald.conf + + Configure + systemd-journald + behaviour. See + journald.conf5. + + + + + /run/log/journal/machine-id/*.journal + /run/log/journal/machine-id/*.journal~ + /var/log/journal/machine-id/*.journal + /var/log/journal/machine-id/*.journal~ + + systemd-journald + writes entries to files in + /run/log/journal/machine-id/ + or + /var/log/journal/machine-id/ + with the .journal + suffix. If the daemon is stopped + uncleanly, or if the files are found + to be corrupted, they are renamed + using the .journal~ + suffix, and + systemd-journald + starts writing to a new + file. /run is + used when + /var/log/journal + is not available, or when + is + set in the + journald.conf5 + configuration file. + + + + + + + See Also + + systemd1, + journalctl1, + journald.conf5, + systemd.journal-fields7, + sd-journal3, + setfacl1, + pydoc systemd.journal. + + + + diff --git a/man/systemd-localed.service.xml b/man/systemd-localed.service.xml new file mode 100644 index 0000000..1551e6a --- /dev/null +++ b/man/systemd-localed.service.xml @@ -0,0 +1,89 @@ + + + + + + + + + systemd-localed.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-localed.service + 8 + + + + systemd-localed.service + systemd-localed + Locale bus mechanism + + + + systemd-localed.service + /usr/lib/systemd/systemd-localed + + + + Description + + systemd-localed is a system + service that may be used as mechanism to change the + system locale settings, as well as the console key + mapping and default X11 key + mapping. systemd-localed is + automatically activated on request and terminates + itself when it is unused. + + The tool + localectl1 + is a command line client to this service. + + See the + developer documentation for information about + the APIs systemd-localed + provides. + + + + See Also + + systemd1, + locale.conf5, + vconsole.conf5, + localectl1, + loadkeys1 + + + + diff --git a/man/systemd-loginctl.xml b/man/systemd-loginctl.xml deleted file mode 100644 index 6a28276..0000000 --- a/man/systemd-loginctl.xml +++ /dev/null @@ -1,457 +0,0 @@ - - - - - - - - - systemd-loginctl - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd-loginctl - 1 - - - - systemd-loginctl - Control the systemd login manager - - - - - systemd-loginctl OPTIONS COMMAND NAME - - - - - Description - - systemd-loginctl may be used to - introspect and control the state of the - systemd1 - login manager. - - - - Options - - The following options are understood: - - - - - - - Prints a short help - text and exits. - - - - - - Prints a short version - string and exits. - - - - - - - When showing - session/user/ properties, limit - display to certain properties as - specified as argument. If not - specified all set properties are - shown. The argument should be a - property name, such as - Sessions. If - specified more than once all - properties with the specified names - are shown. - - - - - - - When showing - unit/job/manager properties, show all - properties regardless whether they are - set or not. - - - - - - - Do not pipe output into a - pager. - - - - - - When used with - kill-session, - choose which processes to kill. Must - be one of , or - to select whether - to kill only the leader process of the - session or all processes of the - session. If omitted defaults to - . - - - - - - - When used with - kill-session or - kill-user, choose - which signal to send to selected - processes. Must be one of the well - known signal specifiers such as - SIGTERM, SIGINT or SIGSTOP. If omitted - defaults to - . - - - - - - - Execute operation - remotely. Specify a hostname, or - username and hostname separated by @, - to connect to. This will use SSH to - talk to the remote login manager - instance. - - - - - - - Acquire privileges via - PolicyKit before executing the - operation. - - - - The following commands are understood: - - - - list-sessions - - List current sessions. - - - - session-status [ID...] - - Show terse runtime - status information about one or more - sessions. This function is intended to - generate human-readable output. If you - are looking for computer-parsable - output, use - show-session - instead. - - - - show-session [ID...] - - Show properties of one - or more sessions or the manager - itself. If no argument is specified - properties of the manager will be - shown. If a session ID is specified - properties of the session is shown. By - default, empty properties are - suppressed. Use - to show those too. To select specific - properties to show use - . This - command is intended to be used - whenever computer-parsable output is - required. Use - session-status if - you are looking for formatted - human-readable - output. - - - - activate [ID...] - - Activate one or more - sessions. This brings one or more - sessions into the foreground, if - another session is currently in the - foreground on the respective - seat. - - - - lock-session [ID...] - unlock-session [ID...] - - Activates/deactivates - the screen lock on one or more - sessions, if the session supports it. - - - - terminate-session [ID...] - - Terminates a - session. This kills all processes of - the session and deallocates all - resources attached to the - session. - - - - kill-session [ID...] - - Send a signal to one - or more processes of the session. Use - to select - which process to kill. Use - to select - the signal to send. - - - - list-users - - List currently logged - in users. - - - - user-status [USER...] - - Show terse runtime - status information about one or more - logged in users. This function is - intended to generate human-readable - output. If you are looking for - computer-parsable output, use - show-user - instead. Users may be specified by - their usernames or numeric user - IDs. - - - - show-user [USER...] - - Show properties of one - or more users or the manager - itself. If no argument is specified - properties of the manager will be - shown. If a user is specified - properties of the user is shown. By - default, empty properties are - suppressed. Use - to show those too. To select specific - properties to show use - . This - command is intended to be used - whenever computer-parsable output is - required. Use - user-status if - you are looking for formatted - human-readable - output. - - - - enable-linger [USER...] - disable-linger [USER...] - - Enable/disable user - lingering for one or more users. If - enabled for a specific user a user - manager is spawned for him/her at - boot, and kept around after - logouts. This allows users who aren't - logged in to run long-running - services. - - - - terminate-user [USER...] - - Terminates all - sessions of a user. This kills all - processes of all sessions of the user - and deallocates all runtime resources - attached to the - user. - - - - kill-user [USER...] - - Send a signal to all - processes of a user. Use - to select - the signal to send. - - - - list-seats - - List currently - available seats on the local - system. - - - - seat-status [NAME...] - - Show terse runtime - status information about one or more - seats. This function is - intended to generate human-readable - output. If you are looking for - computer-parsable output, use - show-seat - instead. - - - - show-seat [NAME...] - - Show properties of one - or more seats or the manager - itself. If no argument is specified - properties of the manager will be - shown. If a seat is specified - properties of the seat are shown. By - default, empty properties are - suppressed. Use - to show those too. To select specific - properties to show use - . This - command is intended to be used - whenever computer-parsable output is - required. Use - seat-status if you - are looking for formatted - human-readable - output. - - - - attach [NAME] [DEVICE...] - - Attach one or more - devices to a seat. The devices should - be specified via device paths in the - /sys file - system. To create a new seat attach at - least one graphics card to a - previously unused seat names. seat - names may consist only of a-z, A-Z, - 0-9, "-" and "_" and must be prefixed - with "seat". To drop assignment of a - device to a specific seat just - reassign it to a different seat, or - use - flush-devices. - - - - flush-devices - - Removes all device - assignments previously created with - attach. After this - call only automatically generated - seats will remain and all seat - hardware is assigned to - them. - - - - terminate-seat [NAME...] - - Terminates all - sessions on a seat. This kills all - processes of all sessions on a seat and - deallocates all runtime resources - attached to them. - - - - - - - Exit status - - On success 0 is returned, a non-zero failure - code otherwise. - - - - Environment - - - - $SYSTEMD_PAGER - Pager to use when - is not given; - overrides $PAGER. Setting - this to an empty string or the value - cat is equivalent to passing - . - - - - - - See Also - - systemd1, - systemctl1, - systemd-logind.conf5 - - - - diff --git a/man/systemd-logind.conf.xml b/man/systemd-logind.conf.xml deleted file mode 100644 index c7e277f..0000000 --- a/man/systemd-logind.conf.xml +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - systemd-logind.conf - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd-logind.conf - 5 - - - - systemd-logind.conf - login manager configuration file - - - - systemd-login.conf - - - - Description - - This files configures various parameters of the systemd login manager. - - - - - Options - - All options are configured in the - [Login] section: - - - - - NAutoVTs= - - Takes a positive - integer. How many virtual terminals to - allocate by default and when switched - to autospawn autovt - services on (if they are otherwise - unused). These services are - instantiated from a template of - autovt@.service - with the virtual terminal TTY name, - e.g. autovt@tty4.service. By - default - autovt@.service - is linked to - getty@.service, - i.e. login prompts are started - dynamically as the user switches to - unused virtual terminals, and this - parameter hence controls how many - gettys are available on the virtual - terminals. Defaults to 6. When set to - 0, automatic spawning of - autovt services is - disabled. - - - - KillUserProcesses= - - Takes a boolean - argument. Configures whether the - processes of a user should be killed - when she or he completely logs out (i.e. after - her/his last session ended). Defaults to - no. - - - - KillOnlyUsers= - KillExcludeUsers= - - These settings take - space separated lists of user names - that influence the effect of - KillUserProcesses=. If - not empty only processes of users - listed in - KillOnlyUsers will - be killed when they log out - entirely. Processes of users listed in - KillExcludeUsers= - are excluded from being - killed. KillExcludeUsers= - defaults to root - and takes precedence over - KillOnlyUsers= - which defaults to the empty list. - - - - Controllers= - ResetControllers= - - These settings control - the default control group hierarchies - users logging are added to. When - logging in users will get private - control groups in all hierarchies - listed in - Controllers= and be - reset to the root control group in all - hierarchies listed in - ResetControllers=. Controllers= - defaults to the empty list, - ResetControllers= - defaults to - cpu. - - - - Note that setting - KillUserProcesses=1 will break tools - like - screen1. - - Note that KillUserProcesses=1 - is a weaker version of - kill-session-processes=1 which may - be configured per-service for - pam_systemd8. The - latter kills processes of a session as soon as it - ends, the former kills processes as soon as the last - session of the user ends. - - - - See Also - - systemd1, - systemd-loginctl1, - systemd.conf5 - - - - diff --git a/man/systemd-logind.service.xml b/man/systemd-logind.service.xml new file mode 100644 index 0000000..c0c3d1a --- /dev/null +++ b/man/systemd-logind.service.xml @@ -0,0 +1,131 @@ + + + + + + + + + systemd-logind.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-logind.service + 8 + + + + systemd-logind.service + systemd-logind + Login manager + + + + systemd-logind.service + /usr/lib/systemd/systemd-logind + + + + Description + + systemd-logind is a system + service that manages user logins. It is responsible + for: + + + Keeping track of users and + sessions, their processes and their idle + state + + Providing PolicyKit-based access + for users to operations such as system + shutdown or sleep + + Implementing a shutdown/sleep + inhibition logic for + applications + + Handling of power/sleep + hardware keys + + Multi-seat + management + + Session + switch management + + Device access management for + users + + Automatic spawning of text + logins (gettys) on virtual console activation + and user runtime directory + management + + + User sessions are registered in logind via the + pam_systemd8 + PAM module. + + See + logind.conf5 + for information about the configuration of this + service. + + See Multi-Seat + on Linux for an introduction into basic + concepts of logind such as users, sessions and seats. + + See the + logind D-Bus API Documentation for information about + the APIs systemd-logind + provides. + + For more information on the inhibition logic see + the Inhibitor + Lock Developer Documentation. + + + + See Also + + systemd1, + systemd-user-sessions.service8, + loginctl1, + logind.conf5, + pam_systemd8 + + + + diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml new file mode 100644 index 0000000..5c34b34 --- /dev/null +++ b/man/systemd-machine-id-setup.xml @@ -0,0 +1,121 @@ + + + + + + + + + systemd-machine-id-setup + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-machine-id-setup + 1 + + + + systemd-machine-id-setup + Initialize the machine ID in /etc/machine-id + + + + + systemd-machine-id-setup + + + + + Description + + systemd-machine-id-setup may + be used by system installer tools to initialize the + machine ID stored in + /etc/machine-id at install time + with a randomly generated ID. See + machine-id5 + for more information about this file. + + This tool will execute no operation if + /etc/machine-id is already + initialized. + + If a valid D-Bus machine ID is already + configured for the system, the D-Bus machine ID is + copied and used to initialize the machine ID in + /etc/machine-id. + + If run inside a KVM virtual machine and a UUID + is passed via the option, this + UUID is used to initialize the machine ID instead of a + randomly generated one. The caller must ensure that the + UUID passed is sufficiently unique and is different + for every booted instanced of the VM. + + Similarly, if run inside a Linux container + environment and a UUID is set for the container this + is used to initialize the machine ID. For details see + the documentation of the Container + Interface. + + + + + Options + + The following options are understood: + + + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + machine-id5, + dbus-uuidgen1 + + + + diff --git a/man/systemd-machined.service.xml b/man/systemd-machined.service.xml new file mode 100644 index 0000000..352b4a0 --- /dev/null +++ b/man/systemd-machined.service.xml @@ -0,0 +1,85 @@ + + + + + + + + + systemd-machined.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-machined.service + 8 + + + + systemd-machined.service + systemd-machined + Virtual machine and container registration manager + + + + systemd-machined.service + /usr/lib/systemd/systemd-machined + + + + Description + + systemd-machined is a + system service that keeps track of virtual machines + and containers, and processes belonging to + them. + + See + systemd-nspawn1 + for some examples on how to start a container the systemd + way. + + See the + machined D-Bus API Documentation for information about + the APIs systemd-machined + provides. + + + + See Also + + systemd1, + machinectl1, + systemd.special7. + + + + diff --git a/man/systemd-modules-load.service.xml b/man/systemd-modules-load.service.xml new file mode 100644 index 0000000..28dd8ec --- /dev/null +++ b/man/systemd-modules-load.service.xml @@ -0,0 +1,100 @@ + + + + + + + + systemd-modules-load.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-modules-load.service + 8 + + + + systemd-modules-load.service + systemd-modules-load + Configure kernel modules to load at boot + + + + systemd-modules-load.service + /usr/lib/systemd/systemd-modules-load + + + + Description + + systemd-modules-load.service + is an early-boot service that loads kernel modules + from static configuration. + + See + modules-load.d5 + for information about the configuration of this + service. + + + + + Kernel Command Line + + systemd-modules-load.service understands + the following kernel command line parameters: + + + + + modules-load= + rd.modules-load= + + Takes a comma-separated + list of kernel modules to + statically load during early boot. The + option prefixed with + rd. is read by the + initial RAM disk + only. + + + + + + + See Also + + systemd1, + modules-load.d5, + + + + diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml new file mode 100644 index 0000000..2517efc --- /dev/null +++ b/man/systemd-networkd.service.xml @@ -0,0 +1,435 @@ + + + + + + + + + systemd-networkd.service + systemd + + + + Developer + Tom + Gundersen + teg@jklm.no + + + + + + systemd-networkd.service + 8 + + + + systemd-networkd.service + systemd-networkd + Network manager + + + + systemd-networkd.service + /usr/lib/systemd/systemd-networkd + + + + Description + + systemd-networkd is a system + service that manages networks. It detects and configures + network devices as they appear, as well as creating virtual + network devices. + + To configure low-level link settings independently of + networks, see + udev7 + . + + Network configurations applied before networkd is started + are not removed, and static configuration applied by networkd + is not removed when networkd exits. This ensures restarting + networkd does not cut the network connection, and, in particular, + that it is safe to transition between the initrd and the real root, + and back. + + + Configuration Files + The configuration files are read from the files located in the + system network directory /usr/lib/systemd/network, + the volatile runtime network directory + /run/systemd/network and the local administration + network directory /etc/systemd/network. + 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 + /etc have the highest priority, files in + /run take precedence over files with the same + name in /usr/lib. This can be used to override a + system-supplied configuration file with a local file if needed; a symlink in + /etc with the same name as a configuration file in + /usr/lib, pointing to /dev/null, + disables the configuration file entirely. + + Virtual Network Devices + Virtual Network Device files must have the extension + .netdev; other extensions are ignored. Virtual + network devices are created as soon as networkd is started. + + A virtual network device is only created if the + [Match] section matches the current + environment, or if the section is empty. The following keys are accepted: + + + + Host= + + Matches against the hostname or machine ID of the + host. See ConditionHost= in + systemd.unit5 + for details. + + + + + Virtualization= + + Checks whether the system is executed in a virtualized + environment and optionally test whether it is a specific + implementation. See ConditionVirtualization= in + systemd.unit5 + for details. + + + + + KernelCommandLine= + + Checks whether a specific kernel command line option is + set (or if prefixed with the exclamation mark unset). See + ConditionKernelCommandLine= in + systemd.unit5 + for details. + + + + + Architecture= + + Checks whether the system is running on a specific + architecture. See ConditionArchitecture= in + systemd.unit5 + for details. + + + + + + The [NetDev] section accepts the following + keys: + + + + Name= + + The interface name used when creating the + netdev. This option is compulsory. + + + + Kind= + + The netdev kind. Currently, bridge, + bond and vlan + are supported. This option is compulsory. + + + + + The [VLAN] section only applies for netdevs of kind vlan, + and accepts the following key: + + + + Id= + + The VLAN ID to use. An integer in the range 0–4094. + This option is compulsory. + + + + + + + Networks + Network files must have the extension .network; + other extensions are ignored. Networks are applied to links whenever the links + appear. + + The network file contains a [Match] section, + which determines if a given network file may be applied to a given device; + and a [Network] section specifying how the device should + be configured. The first (in lexical order) of the network files that + matches a given device is applied. + + A network file is said to match a device if each of the entries in the + [Match] section matches, or if the section is empty. + The following keys are accepted: + + + + MACAddress= + + The hardware address. + + + + Path= + + The persistent path, as exposed by the udev + property ID_PATH. May contain shell + style globs. + + + + Driver= + + The driver currently bound to the device, as + exposed by the udev property DRIVER + of its parent device, or if that is not set the driver + as exposed by ethtool -i of the + device itself. + + + + Type= + + The device type, as exposed by the udev property + DEVTYPE. + + + + Name= + + The device name, as exposed by the udev property + INTERFACE. May contain shell style + globs. + + + + Host= + + Matches against the hostname or machine ID of the + host. See ConditionHost= in + systemd.unit5 + for details. + + + + + Virtualization= + + Checks whether the system is executed in a virtualized + environment and optionally test whether it is a specific + implementation. See ConditionVirtualization= in + systemd.unit5 + for details. + + + + + KernelCommandLine= + + Checks whether a specific kernel command line option is + set (or if prefixed with the exclamation mark unset). See + ConditionKernelCommandLine= in + systemd.unit5 + for details. + + + + + Architecture= + + Checks whether the system is running on a specific + architecture. See ConditionArchitecture= in + systemd.unit5 + for details. + + + + + + The [Network] section accepts the following keys: + + + + Description= + + A description of the device. This is only used for + presentation purposes. + + + + DHCP= + + A boolean. When true, enables basic DHCPv4 support. + + + + Address= + + A static IPv4 or IPv6 address and its prefix length, + separated by a / character. The format of the address must + be as described in + inet_pton3 + . This is a short-hand for an [Address] section only containing an Address key (see below). + + + + Gateway= + + The gateway address, which must be in the format described in + inet_pton3 + . This is a short-hand for a [Route] section only containing a Gateway key. + + + + DNS= + + A DNS server address, which must be in the format described in + inet_pton3 + . + + + + Bridge= + + The name of the bridge to add the link to. + + + + Bond= + + The name of the bond to add the link to. + + + + VLAN= + + The name of a VLAN to create on the link. This option + may be specified more than once. + + + + + The [Address] section accepts the following keys: + + + + Address= + + As in the [Network] section. This key is mandatory. + + + + Broadcast= + + The broadcast address, which must be in the format described in + inet_pton3 + . This key only applies to IPv4 addresses. If it is not given, it is + derived from the Address key. + + + + Label= + + An address label. + + + + + The [Route] section accepts the following keys: + + + + Gateway= + + As in the [Network] section. This key is mandatory. + + + + Destination= + + The destination prefix of the route. Possibly followed by a slash and the + prefixlength, if ommitted a full-length host route is assumed. + + + + + The [DHCPv4] section accepts the following keys: + + + + UseDNS= + + When true (the default), the DNS servers received from the DHCP server will + be used and take precedence over any statically configured ones. + + + + UseMTU= + + When true, the interface maximum transmission unit from the DHCP server will + be used on the current link. Defaults to false. + + + + UseHostname= + + When true (the default), the hostname received from the DHCP server + will be used as the transient hostname. + + + + CriticalConnection= + + When true, the connection will never be torn down even if the DHCP lease + expires. This is contrary to the DHCP specification, but may be the best choice + if, say, the root filesystem relies on this connection. Defaults to false. + + + + + + + + + See Also + + systemd1, + udev7 + + + + diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 59d6b2f..69baae0 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd-notify @@ -44,7 +45,7 @@ systemd-notify - Notify init system about start-up completion and other daemon status changes + Notify service manager about start-up completion and other daemon status changes @@ -87,14 +88,6 @@ - - - - Prints a short help - text and exits. - - - Inform the init system @@ -112,7 +105,7 @@ Inform the init system about the main PID of the daemon. Takes a PID as argument. If - the argument is omitted the PID of the + the argument is omitted, the PID of the process that invoked systemd-notify is used. This is equivalent to @@ -141,10 +134,10 @@ Returns 0 if the system was booted up with systemd, non-zero otherwise. If this option is - passed no message is sent. This option + passed, no message is sent. This option is hence unrelated to the other options. For details about the - semantics of this option see + semantics of this option, see sd_booted3. @@ -158,6 +151,9 @@ about the semantics of this option see sd_readahead3. + + + @@ -165,7 +161,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index d5f8465..0a661c9 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd-nspawn @@ -49,7 +50,17 @@ - systemd-nspawn OPTIONS COMMAND ARGS + systemd-nspawn + OPTIONS + COMMAND + ARGS + + + + systemd-nspawn + -b + OPTIONS + ARGS @@ -87,15 +98,18 @@ involved with boot and systems management. In contrast to - chroot1 - systemd-nspawn may be used to boot - full Linux-based operating systems in a - container. + chroot1 systemd-nspawn + may be used to boot full Linux-based operating systems + in a container. Use a tool like - debootstrap8 or mock1 + yum8, + debootstrap8, + or + pacman8 to set up an OS directory tree suitable as file system - hierarchy for systemd-nspawn containers. + hierarchy for systemd-nspawn + containers. Note that systemd-nspawn will mount file systems private to the container to @@ -110,40 +124,71 @@ see each other. The PID namespace separation of the two containers is complete and the containers will share very few runtime objects except for the - underlying file system. + underlying file system. Use + machinectl1's + login command to request an + additional login prompt in a running container. + + systemd-nspawn implements the + Container + Interface specification. + + As a safety check + systemd-nspawn will verify the + existence of /etc/os-release in + the container tree before starting the container (see + os-release5). It + might be necessary to add this file to the container + tree manually if the OS of the container is too old to + contain this file out-of-the-box. Options - If no arguments are passed the container is set - up and a shell started in it, otherwise the passed - command and arguments are executed in it. The - following options are understood: - - - - - + If option is specified, the + arguments are used as arguments for the init + binary. Otherwise, COMMAND + specifies the program to launch in the container, and + the remaining arguments are used as arguments for this + program. If is not used and no + arguments are specifed, a shell is launched in the + container. - Prints a short help - text and exits. - + The following options are understood: + - + Directory to use as file system root for the namespace - container. If omitted the current + container. If omitted, the current directory will be used. - + + + + Automatically search + for an init binary and invoke it + instead of a shell or a user supplied + program. If this option is used, + arguments specified on the command + line are used as arguments for the + init binary. This option may not be + combined with + . + + + + + Run the command under specified user, create home @@ -155,15 +200,372 @@ + + + + Sets the machine name + for this container. This name may be + used to identify this container on the + host, and is used to initialize the + container's hostname (which the + container can choose to override, + however). If not specified, the last + component of the root directory of the + container is used. + + + + + + Set the specified UUID + for the container. The init system + will initialize + /etc/machine-id + from this if this file is not set yet. + + + + + + + Make the container + part of the specified slice, instead + of the default + machine.slice. + + + + - Turn off networking in - the container. This makes all network - interfaces unavailable in the - container, with the exception of the - loopback device. + Disconnect networking + of the container from the host. This + makes all network interfaces + unavailable in the container, with the + exception of the loopback device and + those specified with + + and configured with + . If + this option is specified, the + CAP_NET_ADMIN capability will be added + to the set of capabilities the + container retains. The latter may be + disabled by using + . + + + + + + Assign the specified + network interface to the + container. This will move the + specified interface from the calling + namespace and place it in the + container. When the container + terminates, it is moved back to the + host namespace. Note that + + implies + . This + option may be used more than once to + add multiple network interfaces to the + container. + + + + + + Create a virtual + Ethernet link between host and + container. The host side of the + Ethernet link will be available as a + network interface named after the + container's name (as specified with + ), prefixed + with ve-. The + container side of the the Ethernet + link will be named + host0. Note that + + implies + . + + + + + + Adds the host side of + the Ethernet link created with + to the + specified bridge. Note that + + implies + . If + this option is used the host side of + the Ethernet link will use the + vb- prefix instead + of ve-. + + + + + + + Sets the SELinux + security context to be used to label + processes in the container. + + + + + + + + Sets the SELinux security + context to be used to label files in + the virtual API file systems in the + container. + + + + + + + List one or more + additional capabilities to grant the + container. Takes a comma-separated + list of capability names, see + capabilities7 + for more information. Note that the + following capabilities will be granted + in any way: CAP_CHOWN, + CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, + CAP_FOWNER, CAP_FSETID, CAP_IPC_OWNER, + CAP_KILL, CAP_LEASE, + CAP_LINUX_IMMUTABLE, + CAP_NET_BIND_SERVICE, + CAP_NET_BROADCAST, CAP_NET_RAW, + CAP_SETGID, CAP_SETFCAP, CAP_SETPCAP, + CAP_SETUID, CAP_SYS_ADMIN, + CAP_SYS_CHROOT, CAP_SYS_NICE, + CAP_SYS_PTRACE, CAP_SYS_TTY_CONFIG, + CAP_SYS_RESOURCE, CAP_SYS_BOOT, + CAP_AUDIT_WRITE, + CAP_AUDIT_CONTROL. Also CAP_NET_ADMIN + is retained if + is + specified. If the special value + all is passed, all + capabilities are + retained. + + + + + + Specify one or more + additional capabilities to drop for + the container. This allows running the + container with fewer capabilities than + the default (see above). + + + + + + 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 + no, + host, + guest, + auto. If + no, the journal is + not linked. If host, + the journal files are stored on the + host file system (beneath + /var/log/journal/machine-id) + and the subdirectory is bind-mounted + into the container at the same + location. If guest, + the journal files are stored on the + guest file system (beneath + /var/log/journal/machine-id) + and the subdirectory is symlinked into the host + at the same location. If + auto (the default), + and the right subdirectory of + /var/log/journal + 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 + guest or + host will link the + journal persistently if further on + the default of auto + is used. + + + + + + Equivalent to + . + + + + + + Mount the root file + system read-only for the + container. + + + + + + + Bind mount a file or + directory from the host into the + container. Either takes a path + argument -- in which case the + specified path will be mounted from + the host to the same path in the + container --, or a colon-separated + pair of paths -- in which case the + first specified path is the source in + the host, and the second path is the + destination in the container. The + option + creates read-only bind + mounts. + + + + + + Specifies an + environment variable assignment to + pass to the init process in the + container, in the format + NAME=VALUE. This + may be used to override the default + variables or to set additional + variables. This parameter may be used + more than once. + + + + + + Allows the container + to share certain system facilities + with the host. More specifically, this + turns off PID namespacing, UTS + namespacing and IPC namespacing, and + thus allows the guest to see and + interact more easily with processes + outside of the container. Note that + using this option makes it impossible + to start up a full Operating System in + the container, as an init system + cannot operate in this mode. It is + only useful to run specific programs + or applications this way, without + involving an init system in the + container. This option implies + . This + option may not be combined with + . + + + + + + Controls whether the + container is registered with + systemd-machined8. Takes + a boolean argument, defaults to + yes. This option + should be enabled when the container + runs a full Operating System (more + specifically: an init system), and is + useful to ensure that the container is + accessible via + machinectl1 + and shown by tools such as + ps1. If + the container does not run an init + system, it is recommended to set this + option to no. Note + that + implies + . + + + + + + + Instead of creating a + transient scope unit to run the + container in, simply register the + service or scope unit + systemd-nspawn has + been invoked in with + systemd-machined8. This + has no effect if + is + used. This switch should be used if + systemd-nspawn is + invoked from within a service unit, + and the service unit's sole purpose + is to run a single + systemd-nspawn + container. This option is not + available if run from a user + session. + + + + + + Control the + architecture ("personality") reported + by + uname2 + in the container. Currently, only + x86 and + x86-64 are + supported. This is useful when running + a 32bit container on a 64bit + host. If this setting is not used + the personality reported in the + container is the same as the one + reported on the + host. + + + + + + + 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. + + @@ -171,28 +573,67 @@ Example 1 - # debootstrap --arch=amd64 unstable debian-tree/ -# systemd-nspawn -D debian-tree/ + # yum -y --releasever=19 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal +# systemd-nspawn -bD /srv/mycontainer + + This installs a minimal Fedora distribution into + the directory /srv/mycontainer/ and + then boots an OS in a namespace container in + it. + + + + Example 2 + + # debootstrap --arch=amd64 unstable ~/debian-tree/ +# systemd-nspawn -D ~/debian-tree/ This installs a minimal Debian unstable distribution into the directory - debian-tree/ and then spawns a + ~/debian-tree/ and then spawns a shell in a namespace container in it. + + + + Example 3 + # pacstrap -c -d ~/arch-tree/ base +# systemd-nspawn -bD ~/arch-tree/ + + This installs a mimimal Arch Linux distribution into + the directory ~/arch-tree/ and then + boots an OS in a namespace container in it. - Example 2 + Example 4 - # mock --init -# systemd-nspawn -D /var/lib/mock/fedora-rawhide-x86_64/root/ /bin/systemd systemd.log_level=debug + # mv ~/arch-tree /var/lib/container/arch +# systemctl enable systemd-nspawn@arch.service +# systemctl start systemd-nspawn@arch.service - This installs a minimal Fedora distribution into - a subdirectory of /var/lib/mock/ - and then boots an OS in a namespace container in it, - with systemd as init system, configured for debug - logging. + This makes the Arch Linux container part of the + multi-user.target on the host. + + + + + Example 5 + + # btrfs subvolume snapshot / /.tmp +# systemd-nspawn --private-network -D /.tmp -b + + This runs a copy of the host system in a + btrfs snapshot. + + + + Example 6 + + # chcon system_u:object_r:svirt_sandbox_file_t:s0:c0,c1 -R /srv/container +# systemd-nspawn -L system_u:object_r:svirt_sandbox_file_t:s0:c0,c1 -Z system_u:system_r:svirt_lxc_net_t:s0:c0,c1 -D /srv/container /bin/sh + This runs a container with SELinux sandbox security contexts. @@ -207,8 +648,11 @@ systemd1, chroot1, + yum8, debootstrap8, - mock1 + pacman8, + systemd.slice5, + machinectl1 diff --git a/man/systemd-quotacheck.service.xml b/man/systemd-quotacheck.service.xml new file mode 100644 index 0000000..ff04e58 --- /dev/null +++ b/man/systemd-quotacheck.service.xml @@ -0,0 +1,102 @@ + + + + + + + + systemd-quotacheck.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-quotacheck.service + 8 + + + + systemd-quotacheck.service + systemd-quotacheck + File system quota checker logic + + + + systemd-quotacheck.service + /usr/lib/systemd/systemd-quotacheck + + + + Description + + systemd-quotacheck.service + is a service responsible for file system quota + checks. It is run once at boot after all necessary + file systems are mounted. It is pulled in only if at + least one file system has quotas enabled. + + + + Kernel Command Line + + systemd-quotacheck understands + one kernel command line parameter: + + + + quotacheck.mode= + + One of + auto, + force, + skip. Controls the + mode of operation. The default is + auto, and ensures + that file system quota checks are done + when the file system quota checker + deems them + necessary. force + unconditionally results in full file + system quota + checks. skip skips + any file system quota + checks. + + + + + + See Also + + systemd1, + quotacheck8, + systemd-fsck@.service8 + + + + diff --git a/man/systemd-random-seed.service.xml b/man/systemd-random-seed.service.xml new file mode 100644 index 0000000..e5cd037 --- /dev/null +++ b/man/systemd-random-seed.service.xml @@ -0,0 +1,75 @@ + + + + + + + + systemd-random-seed.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-random-seed.service + 8 + + + + systemd-random-seed.service + systemd-random-seed + Load and save the system random seed at boot and shutdown + + + + systemd-random-seed.service + /usr/lib/systemd/systemd-random-seed + + + + Description + + systemd-random-seed.service + is a service that restores the random seed of the + system at early-boot and saves it at shutdown. See + random4 + for details. Saving/restoring the random seed across + boots increases the amount of available entropy early + at boot. On disk the random seed is stored in + /var/lib/systemd/random-seed. + + + + See Also + + systemd1, + random4 + + + + diff --git a/man/systemd-readahead-replay.service.xml b/man/systemd-readahead-replay.service.xml new file mode 100644 index 0000000..67b41f5 --- /dev/null +++ b/man/systemd-readahead-replay.service.xml @@ -0,0 +1,203 @@ + + + + + + + + + systemd-readahead-replay.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-readahead-replay.service + 8 + + + + systemd-readahead-replay.service + systemd-readahead-collect.service + systemd-readahead-done.service + systemd-readahead-done.timer + systemd-readahead + Disk read ahead logic + + + + systemd-readahead-replay.service + systemd-readahead-collect.service + systemd-readahead-done.service + systemd-readahead-done.timer + + /usr/lib/systemd/systemd-readahead/systemd-readahead + OPTIONS + COMMAND + DIRECTORY | FILE + + + + + Description + + systemd-readahead-collect.service + is a service that collects disk usage patterns at boot + time. systemd-readahead-replay.service + is a service that replays this access data collected + at the subsequent boot. Since disks tend to be + magnitudes slower than RAM, this is intended to improve + boot speeds by pre-loading early at boot all data on + disk that is known to be read for the complete boot + process. + + systemd-readahead-done.service + is executed a short while after boot completed and signals + systemd-readahead-collect.service + to end data collection. On this signal, this service + will then sort the collected disk accesses and store + information about them in + /.readahead. + + Normally, both + systemd-readahead-collect.service + and + systemd-readahead-replay.service + are activated at boot so that access patterns from the + preceding boot are replayed and new data collected + for the subsequent boot. However, on read-only media + where the collected data cannot be stored, it might + be a good idea to disable + systemd-readahead-collect.service. + + On rotating media, when replaying disk accesses + at early boot, + systemd-readahead-replay.service + will order read requests by their location on disk. On + non-rotating media, they will be ordered by their + original access timestamp. If the file system supports + it, + systemd-readahead-collect.service + will also defragment and rearrange files on disk to + optimize subsequent boot times. + + + + Options + + systemd-readahead understands + the following options: + + + + + + Maximum number of + files to read ahead. Only valid + for thes collect + command. + + + + + + Maximum size of files + in bytes to read ahead. Only valid + for the collect + and replay + commands. + + + + + + Maximum time in microseconds + to spend collecting data. Only valid + for the collect + command. + + + + + + + + + + Commands + + The following commands are understood by + systemd-readahead: + + collect + [DIRECTORY] + + Collect read-ahead data on + early boot. When terminating, it will + write out a pack file to the indicated + directory containing the read-ahead + data. + + + + + replay + [DIRECTORY] + + Perform read-ahead on the + specified directory tree. + + + + + analyze + [FILE] + + Dumps the content of the + read-ahead pack file to the + terminal. For each file, the + output lists approximately how + much will be read ahead by + the replay + command. + + + + + + + + See Also + + systemd1 + + + + diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml new file mode 100644 index 0000000..cf04713 --- /dev/null +++ b/man/systemd-remount-fs.service.xml @@ -0,0 +1,93 @@ + + + + + + + + systemd-remount-fs.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-remount-fs.service + 8 + + + + systemd-remount-fs.service + systemd-remount-fs + Remount root and kernel file systems + + + + systemd-remount-fs.service + /usr/lib/systemd/systemd-remount-fs + + + + Description + + systemd-remount-fs.service + is an early-boot service that applies mount options + listed in + fstab5 + to the root file system, the /usr + 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 + /etc/fstab. This service ignores + normal file systems and only changes the root file + system (i.e. /), + /usr and the virtual kernel API + file systems such as /proc, + /sys or + /dev. This service executes no + operation if /etc/fstab does not + exist or lists no entries for the mentioned file + systems. + + For a longer discussion of kernel API file + systems see API + File Systems. + + + + See Also + + systemd1, + fstab5, + mount8 + + + + diff --git a/man/systemd-rfkill@.service.xml b/man/systemd-rfkill@.service.xml new file mode 100644 index 0000000..987bbaa --- /dev/null +++ b/man/systemd-rfkill@.service.xml @@ -0,0 +1,92 @@ + + + + + + + + systemd-rfkill@.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-rfkill@.service + 8 + + + + systemd-rfkill@.service + systemd-rfkill + Load and save the RF kill switch state at boot and shutdown + + + + systemd-rfkill@.service + /usr/lib/systemd/systemd-rfkill + + + + Description + + systemd-rfkill@.service is + a service that restores the RF kill switch state at + early boot and saves it at shutdown. On disk, the RF + kill switch state is stored in + /var/lib/systemd/rfkill/. + + + + Kernel Command Line + + systemd-rfkill understands + the following kernel command line parameter: + + + + systemd.restore_state= + + Takes a boolean + argument. Defaults to + 1. If + 0, does not restore + the rfkill settings on boot. However, + settings will still be stored on shutdown. + + + + + + + See Also + + systemd1 + + + + diff --git a/man/systemd-run.xml b/man/systemd-run.xml new file mode 100644 index 0000000..064195a --- /dev/null +++ b/man/systemd-run.xml @@ -0,0 +1,204 @@ + + + + + + + + + systemd-run + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-run + 1 + + + + systemd-run + Run programs in transient scope or service units + + + + + systemd-run + OPTIONS + COMMAND + ARGS + + + + + + Description + + systemd-run may be used to create and start + a transient .service or a + .scope unit and run the specified + COMMAND in it. + + If a command is run as transient service unit, it will be + started and managed by the service manager like any other service, + and thus show up in the output of systemctl + list-units like any other unit. It will run in a clean + and detached execution environment. systemd-run + will start the service asynchronously in the background and + immediately return. + + If a command is run as transient scope unit, it will be + started directly by systemd-run and thus + inherit the execution environment of the caller. It is however + managed by the service manager similar to normal services, and + will also show up in the output of systemctl + list-units. Execution in this case is synchronous, and + execution will return only when the command finishes. + + + + Options + + The following options are understood: + + + + + + + Create a transient .scope unit instead of + the default transient .service unit. + + + + + + + + Use this unit name instead of an automatically + generated one. + + + + + + Provide description for the unit. If not + specified, the command itself will be used as a description. + See Description= in + systemd.unit5. + + + + + + + Make the new .service or + .scope unit part of the specified slice, + instead of the system.slice. + + + + + + + After the service's process has terminated, keep + the service around until it is explicitly stopped. This is + useful to collect runtime information about the service after + it finished running. Also see + RemainAfterExit= in + systemd.service5. + + + + + + + + When terminating the scope unit, send a SIGHUP + immediately after SIGTERM. This is useful to indicate to + shells and shell-like processes that the connection has been + severed. Also see SendSIGHUP= in + systemd.kill5. + + + + + + + + + + + + + + All command-line arguments after the first non-option + argument become part of the commandline of the launched + process. If a command is run as service unit, its first argument + needs to be an absolute binary path. + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + Example + + The following command will log the environment variables + provided by systemd to services: + + # systemd-run env +Running as unit run-19945.service. +# journalctl -u run-19945.service +Sep 08 07:37:21 bupkis systemd[1]: Starting /usr/bin/env... +Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env. +Sep 08 07:37:21 bupkis env[19948]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin +Sep 08 07:37:21 bupkis env[19948]: LANG=en_US.UTF-8 +Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.x86_64 + + + + See Also + + systemd1, + systemctl1, + systemd.unit5, + systemd.service5, + systemd.scope5, + systemd.slice5, + machinectl1 + + + + diff --git a/man/systemd-shutdownd.service.xml b/man/systemd-shutdownd.service.xml new file mode 100644 index 0000000..c1b8ef7 --- /dev/null +++ b/man/systemd-shutdownd.service.xml @@ -0,0 +1,77 @@ + + + + + + + + + systemd-shutdownd.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-shutdownd.service + 8 + + + + systemd-shutdownd.service + systemd-shutdownd.socket + systemd-shutdownd + Scheduled shutdown service + + + + systemd-shutdownd.service + systemd-shutdownd.socket + /usr/lib/systemd/systemd-shutdownd + + + + Description + + systemd-shutdownd.service is a + system service that implements scheduled shutdowns, as + exposed by + shutdown8. + systemd-shutdownd.service is automatically activated on request and terminates + itself when it is unused. + + + + See Also + + systemd1, + shutdown8 + + + + diff --git a/man/systemd-sleep.conf.xml b/man/systemd-sleep.conf.xml new file mode 100644 index 0000000..a917f4d --- /dev/null +++ b/man/systemd-sleep.conf.xml @@ -0,0 +1,179 @@ + + + + + + + + + systemd-sleep.conf + systemd + + + + Developer + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + systemd-sleep.conf + 5 + + + + systemd-sleep.conf + Suspend and hibernation configuration file + + + + /etc/systemd/sleep.conf + + + + Description + + systemd supports three general + power-saving modes: + + + + suspend + + a low-power state + where execution of the OS is paused, + and complete power loss might result + in lost data, and which is fast to + enter and exit. This corresponds to + suspend, standby, or freeze states as + understood by the kernel. + + + + + hibernate + + a low-power state + where execution of the OS is paused, + and complete power loss does not + result in lost data, and which might + be slow to enter and exit. This + corresponds to the hibernation as + understood by the kernel. + + + + + hybrid-sleep + + a low-power state + where execution of the OS is paused, + which might be slow to enter, and on + complete power loss does not result in + lost data but might be slower to exit + in that case. This mode is called + suspend-to-both by the kernel. + + + + + Settings in this file determine what strings + will be written to + /sys/power/disk and + /sys/power/state by + systemd-sleep8 + when + systemd1 + attempts to suspend or hibernate the machine. + + + + Options + + The following options can be configured in the + [Sleep] section of + /etc/systemd/sleep.conf: + + + + SuspendMode= + HibernateMode= + HybridSleepMode= + + The string to be written to + /sys/power/disk by, + respectively, + systemd-suspend.service8, + systemd-hibernate.service8, or + systemd-hybrid-sleep.service8. + More than one value can be specified by separating + multiple values with commas. They will be tried + in turn, until one is written without error. If + neither succeeds, the operation will be aborted. + + + + + SuspendState= + HibernateState= + HybridSleepState= + + The string to be written to + /sys/power/state by, + respectively, + systemd-suspend.service8, + systemd-hibernate.service8, or + systemd-hybrid-sleep.service8. + More than one value can be specified by separating + multiple values with commas. They will be tried + in turn, until one is written without error. If + neither succeeds, the operation will be aborted. + + + + + + + Example: freeze + + Example: to exploit the freeze mode added + in Linux 3.9, one can use systemctl suspend + with + [Sleep] +SuspendState=freeze + + + + See Also + + systemd-sleep8, + systemd-suspend.service8, + systemd-hibernate.service8, + systemd-hybrid-sleep.service8, + systemd1, + systemd.directives7 + + + + diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml new file mode 100644 index 0000000..ab80a2b --- /dev/null +++ b/man/systemd-socket-proxyd.xml @@ -0,0 +1,195 @@ + + + + + + + + systemd-socket-proxyd + systemd + + + Developer + David + Strauss + david@davidstrauss.net + + + + + systemd-socket-proxyd + 8 + + + systemd-socket-proxyd + Bidirectionally proxy local sockets to another (possibly remote) socket. + + + + systemd-socket-proxyd + OPTIONS + HOST:PORT + + + systemd-socket-proxyd + OPTIONS + UNIX-DOMAIN-SOCKET-PATH + + + + + Description + + systemd-socket-proxyd is a generic + socket-activated network socket forwarder proxy daemon + for IPv4, IPv6 and UNIX stream sockets. It may be used + to bi-directionally forward traffic from a local listening socket to a + local or remote destination socket. + + One use of this tool is to provide + socket activation support for services that do not + natively support socket activation. On behalf of the + service to activate, the proxy inherits the socket + from systemd, accepts each client connection, opens a + connection to a configured server for each client, and + then bidirectionally forwards data between the + two. + This utility's behavior is similar to + socat1. + The main differences for systemd-socket-proxyd + are support for socket activation with + Accept=false and an event-driven + design that scales better with the number of + connections. + + + Options + The following options are understood: + + + + + + + Exit status + On success, 0 is returned, a non-zero failure + code otherwise. + + + Examples + + Simple Example + Use two services with a dependency + and no namespace isolation. + + proxy-to-nginx.socket + + + + proxy-to-nginx.service + + + + nginx.conf + + + + + + Enabling the proxy + + + + + Namespace Example + Similar as above, but runs the socket + proxy and the main service in the same private + namespace, assuming that + nginx.service has + PrivateTmp= and + PrivateNetwork= set, + too. + + proxy-to-nginx.socket + + + + proxy-to-nginx.service + + + + nginx.conf + + + + Enabling the proxy + + + + + + See Also + + systemd1, + systemd.socket5, + systemd.service5, + systemctl1, + socat1, + nginx1, + curl1 + + + diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml new file mode 100644 index 0000000..690f961 --- /dev/null +++ b/man/systemd-suspend.service.xml @@ -0,0 +1,155 @@ + + + + + + + + + systemd-suspend.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-suspend.service + 8 + + + + systemd-suspend.service + systemd-hibernate.service + systemd-hybrid-sleep.service + systemd-sleep + System sleep state logic + + + + systemd-suspend.service + systemd-hibernate.service + systemd-hybrid-sleep.service + /usr/lib/systemd/systemd-sleep + + + + Description + + systemd-suspend.service is + a system service that is pulled in by + suspend.target and is responsible + for the actual system suspend. Similarly, + systemd-hibernate.service is + pulled in by hibernate.target to + execute the actual hibernation. Finally, + systemd-hybrid-sleep.service is + pulled in by hybrid-sleep.target + to execute hybrid hibernation with system + suspend. + + Immediately before entering system suspend + and/or hibernation + systemd-suspend.service (and the + other mentioned units, respectively) will run all + executables in + /usr/lib/systemd/system-sleep/ + and pass two arguments to them. The first argument + will be pre, the second either + suspend, + hibernate, or + hybrid-sleep depending on the + chosen action. Immediately after leaving system + suspend and/or hibernation the same executables are run, + but the first argument is now + post. All executables in this + directory are executed in parallel, and execution of + the action is not continued until all executables + have finished. + + Note that scripts or binaries dropped in + /usr/lib/systemd/system-sleep/ + are intended for local use only and should be + considered hacks. If applications want to be notified + of system suspend/hibernation and resume, there are + much nicer interfaces available. + + Note that + systemd-suspend.service, + systemd-hibernate.service, and + systemd-hybrid-sleep.service + should never be executed directly. Instead, trigger + system sleep states with a command such as + systemctl suspend or + similar. + + Internally, this service will echo a string like + mem into + /sys/power/state, to trigger the + actual system suspend. What exactly is written + where can be configured in the [Sleep] + section of /etc/systemd/sleep.conf. + See systemd-sleep.conf5. + + + + + Options + + systemd-sleep understands the + following commands: + + + + + + + + + + + Suspend, hibernate, or + put the system to hybrid sleep. + + + + + + + See Also + + systemd-sleep.conf5, + systemd1, + systemctl1, + systemd.special7, + systemd-halt.service8 + + + + diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml new file mode 100644 index 0000000..a9a4765 --- /dev/null +++ b/man/systemd-sysctl.service.xml @@ -0,0 +1,77 @@ + + + + + + + + systemd-sysctl.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-sysctl.service + 8 + + + + systemd-sysctl.service + systemd-sysctl + Configure kernel parameters at boot + + + + systemd-sysctl.service + /usr/lib/systemd/systemd-sysctl + + + + Description + + systemd-sysctl.service is + an early-boot service that configures + sysctl8 + kernel parameters. + + See + sysctl.d5 + for information about the configuration of this + service. + + + + See Also + + systemd1, + sysctl.d5, + sysctl8, + + + + diff --git a/man/systemd-system-update-generator.xml b/man/systemd-system-update-generator.xml new file mode 100644 index 0000000..18a23ed --- /dev/null +++ b/man/systemd-system-update-generator.xml @@ -0,0 +1,79 @@ + + + + + + + + systemd-system-update-generator + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-system-update-generator + 8 + + + + systemd-system-update-generator + Generator for redirecting boot to offline update mode + + + + /usr/lib/systemd/system-generators/systemd-system-update-generator + + + + Description + + systemd-system-update-generator + is a generator that automatically redirects the boot + process to system-update.target + if /system-update exists. This is + required to implement the logic explained in the + System + Updates Specification. + + + systemd-system-update-generator + implements the generator + specification. + + + + See Also + + systemd1, + systemd.special7 + + + + diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml new file mode 100644 index 0000000..f3a89ad --- /dev/null +++ b/man/systemd-system.conf.xml @@ -0,0 +1,388 @@ + + + + + + + + + systemd-system.conf + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-system.conf + 5 + + + + systemd-system.conf + systemd-user.conf + System and session service manager configuration file + + + + /etc/systemd/system.conf + /etc/systemd/user.conf + + + + Description + + When run as system instance systemd reads the + configuration file system.conf, + otherwise user.conf. These + configuration files contain a few settings controlling + basic manager operations. + + + + Options + + All options are configured in the + [Manager] section: + + + + + LogLevel= + LogTarget= + LogColor= + LogLocation= + DumpCore=yes + CrashShell=no + ShowStatus=yes + CrashChVT=1 + DefaultStandardOutput=journal + DefaultStandardError=inherit + + Configures various + parameters of basic manager + operation. These options may be + overridden by the respective command + line arguments. See + systemd1 + for details about these command line + arguments. + + + + CPUAffinity= + + Configures the initial + CPU affinity for the init + process. Takes a space-separated list + of CPU indices. + + + + JoinControllers=cpu,cpuacct net_cls,netprio + + Configures controllers + that shall be mounted in a single + hierarchy. By default, systemd will + mount all controllers which are + enabled in the kernel in individual + hierarchies, with the exception of + those listed in this setting. Takes a + space-separated list of comma-separated + controller names, in order + to allow multiple joined + hierarchies. Defaults to + 'cpu,cpuacct'. Pass an empty string to + ensure that systemd mounts all + controllers in separate + hierarchies. + + Note that this option is only + applied once, at very early boot. If + you use an initial RAM disk (initrd) + that uses systemd, it might hence be + necessary to rebuild the initrd if + this option is changed, and make sure + the new configuration file is included + in it. Otherwise, the initrd might + mount the controller hierarchies in a + different configuration than intended, + and the main system cannot remount + them anymore. + + + + RuntimeWatchdogSec= + ShutdownWatchdogSec= + + Configure the hardware + watchdog at runtime and at + reboot. Takes a timeout value in + seconds (or in other time units if + suffixed with ms, + min, + h, + d, + w). If + RuntimeWatchdogSec= + is set to a non-zero value, the + watchdog hardware + (/dev/watchdog) + will be programmed to automatically + reboot the system if it is not + contacted within the specified timeout + interval. The system manager will + ensure to contact it at least once in + half the specified timeout + interval. This feature requires a + hardware watchdog device to be + present, as it is commonly the case in + embedded and server systems. Not all + hardware watchdogs allow configuration + of the reboot timeout, in which case + the closest available timeout is + picked. ShutdownWatchdogSec= + may be used to configure the hardware + watchdog when the system is asked to + reboot. It works as a safety net to + ensure that the reboot takes place + even if a clean reboot attempt times + out. By default + RuntimeWatchdogSec= + defaults to 0 (off), and + ShutdownWatchdogSec= + to 10min. These settings have no + effect if a hardware watchdog is not + available. + + + + CapabilityBoundingSet= + + Controls which + capabilities to include in the + capability bounding set for PID 1 and + its children. See + capabilities7 + for details. Takes a whitespace-separated + list of capability names as read by + cap_from_name3. + Capabilities listed will be included + in the bounding set, all others are + removed. If the list of capabilities + is prefixed with ~, all but the listed + capabilities will be included, the + effect of the assignment + inverted. Note that this option also + affects the respective capabilities in + the effective, permitted and + inheritable capability sets. The + capability bounding set may also be + individually configured for units + using the + CapabilityBoundingSet= + directive for units, but note that + capabilities dropped for PID 1 cannot + be regained in individual units, they + are lost for good. + + + + SystemCallArchitectures= + + Takes a + space-separated list of architecture + identifiers. Selects from which + architectures system calls may be + invoked on this system. This may be + used as an effective way to disable + invocation of non-native binaries + system-wide, for example to prohibit + execution of 32-bit x86 binaries on + 64-bit x86-64 systems. This option + operates system-wide, and acts + similar to the + SystemCallArchitectures= + setting of unit files, see + systemd.exec5 + for details. This setting defaults to + the empty list, in which case no + filtering of system calls based on + architecture is applied. Known + architecture identifiers are + x86, + x86-64, + x32, + arm and the special + identifier + native. The latter + implicitly maps to the native + architecture of the system (or more + specifically, the architecture the + system manager was compiled for). Set + this setting to + native to prohibit + execution of any non-native + binaries. When a binary executes a + system call of an architecture that is + not listed in this setting, it will be + immediately terminated with the SIGSYS + signal. + + + + + TimerSlackNSec= + + Sets the timer slack + in nanoseconds for PID 1 which is then + inherited to all executed processes, + unless overridden individually, for + example with the + TimerSlackNSec= + setting in service units (for details + see + systemd.exec5). The + timer slack controls the accuracy of + wake-ups triggered by timers. See + prctl2 + for more information. Note that in + contrast to most other time span + definitions this parameter takes an + integer value in nano-seconds if no + unit is specified. The usual time + units are understood + too. + + + + DefaultTimeoutStartSec= + DefaultTimeoutStopSec= + DefaultRestartSec= + + Configures the default + timeouts for starting and stopping of + units, as well as the default time to + sleep between automatic restarts of + units, as configured per-unit in + TimeoutStartSec=, + TimeoutStopSec= and + RestartSec= (for + service units, see + systemd.service5 + for details on the per-unit + settings). For non-service units, + DefaultTimeoutStartSec= + sets the default + TimeoutSec= value. + + + + DefaultStartLimitInterval= + DefaultStartLimitBurst= + + Configure the default start rate + limiting, as configured per-service by + StartLimitInterval= and + StartLimitBurst=. See + systemd.service5 + for details on the per-service + settings). + + + + + DefaultEnvironment= + + Sets manager + environment variables passed to all + executed processes. Takes a + space-separated list of variable + assignments. See + environ7 + for details about environment + variables. + + Example: + + DefaultEnvironment="VAR1=word1 word2" VAR2=word3 "VAR3=word 5 6" + + Sets three variables + VAR1, + VAR2, + VAR3. + + + + DefaultLimitCPU= + DefaultLimitFSIZE= + DefaultLimitDATA= + DefaultLimitSTACK= + DefaultLimitCORE= + DefaultLimitRSS= + DefaultLimitNOFILE= + DefaultLimitAS= + DefaultLimitNPROC= + DefaultLimitMEMLOCK= + DefaultLimitLOCKS= + DefaultLimitSIGPENDING= + DefaultLimitMSGQUEUE= + DefaultLimitNICE= + DefaultLimitRTPRIO= + DefaultLimitRTTIME= + + These settings control + various default resource limits for + units. See + setrlimit2 + for details. Use the string + infinity to + configure no limit on a specific + resource. These settings may be + overridden in individual units + using the corresponding LimitXXX= + directives. Note that these resource + limits are only defaults for units, + they are not applied to PID 1 + itself. + + + + + + See Also + + systemd1, + systemd.directives7, + systemd.exec5, + systemd.service5, + environ7, + capabilities7 + + + + diff --git a/man/systemd-timedated.service.xml b/man/systemd-timedated.service.xml new file mode 100644 index 0000000..4f17bcc --- /dev/null +++ b/man/systemd-timedated.service.xml @@ -0,0 +1,88 @@ + + + + + + + + + systemd-timedated.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-timedated.service + 8 + + + + systemd-timedated.service + systemd-timedated + Time and date bus mechanism + + + + systemd-timedated.service + /usr/lib/systemd/systemd-timedated + + + + Description + + systemd-timedated is a + system service that may be used as a mechanism to change + the system clock and timezone, as well as to + enable/disable NTP time + synchronization. systemd-timedated + is automatically activated on request and terminates + itself when it is unused. + + The tool + timedatectl1 + is a command-line client to this service. + + See the + developer documentation for information about + the APIs systemd-timedated + provides. + + + + See Also + + systemd1, + timedatectl1, + localtime5, + hwclock8 + + + + diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index 08d5c73..0b62640 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd-tmpfiles @@ -44,32 +45,45 @@ systemd-tmpfiles + systemd-tmpfiles-setup.service + systemd-tmpfiles-setup-dev.service + systemd-tmpfiles-clean.service + systemd-tmpfiles-clean.timer Creates, deletes and cleans up volatile - and temporary files and directories. + and temporary files and directories - systemd-tmpfiles OPTIONS CONFIGURATION FILE + systemd-tmpfiles + OPTIONS + CONFIGFILE + + systemd-tmpfiles-setup.service + systemd-tmpfiles-setup-dev.service + systemd-tmpfiles-clean.service + systemd-tmpfiles-clean.timer Description systemd-tmpfiles creates, - deletes and cleans up volatile and temporary files and - directories, based on the configuration from - /etc/tmpfiles.d/. See + deletes, and cleans up volatile and temporary files and + directories, based on the configuration file format and + location specified in + tmpfiles.d5. + + + If invoked with no arguments, it applies all + directives from all configuration files. If one or + more filenames are passed on the command line, only + the directives in these files are applied. If only + the basename of a configuration file is specified, + all configuration directories as specified in tmpfiles.d5 - for more details on these files. - - If invoked with no arguments applies all - directives from all configuration files in - /etc/tmpfiles.d/*.conf. If one or - more absolute file names are passed on the command - line only the directives in these files are - applied. + are searched for a matching file. @@ -78,19 +92,33 @@ The following options are understood: - - If this option is passed all - files and directories marked with f, - F, d, D in the configuration files are - created. + If this option is + passed, all files and directories + marked with f, + F, + w, + d, + D, + p, + L, + c, + b, + m in the + configuration files are created or + written to. Files and directories + marked with z, + Z, + m have their + ownership, access mode and security + labels set. If this option is - passed all files and directories with + passed, all files and directories with an age parameter configured will be cleaned up. @@ -98,25 +126,35 @@ If this option is - passed all files and directories marked - with r, R in the configuration files - are removed. + passed, all files and directories + marked with r, + R in the + configuration files are + removed. + + + + Also execute lines + with an exclamation mark. + Only apply rules that apply to paths with the specified - prefix. + prefix. This option can be specified + multiple times. - - - - - Prints a short help - text and exits. + + Ignore rules that + apply to paths with the specified + prefix. This option can be specified + multiple times. + + It is possible to combine @@ -134,7 +172,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. @@ -142,8 +180,7 @@ See Also systemd1, - tmpfiles.d5, - tmpwatch8 + tmpfiles.d5 diff --git a/man/systemd-tty-ask-password-agent.xml b/man/systemd-tty-ask-password-agent.xml new file mode 100644 index 0000000..e0df87d --- /dev/null +++ b/man/systemd-tty-ask-password-agent.xml @@ -0,0 +1,154 @@ + + + + + + + + + systemd-tty-ask-password-agent + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-tty-ask-password-agent + 1 + + + + systemd-tty-ask-password-agent + List or process pending systemd password requests + + + + + systemd-tty-ask-password-agent OPTIONS VARIABLE=VALUE + + + + + Description + + systemd-tty-ask-password-agent + is a password agent that handles password + requests of the system, for example for hard disk + encryption passwords or SSL certificate passwords that + need to be queried at boot-time or during + runtime. + + systemd-tty-ask-password-agent + implements the Password + Agents Specification. + + + + + Options + + The following options are understood: + + + + + + Lists all currently pending system password requests. + + + + + + Process all currently + pending system password requests by + querying the user on the calling + TTY. + + + + + + Continuously process + password requests. + + + + + + Forward password + requests to + wall1 + instead of querying the user on the + calling TTY. + + + + + + Ask question with + plymouth8 + instead of querying the user on the + calling TTY. + + + + + + Ask question on + /dev/console + instead of querying the user on the + calling TTY. + + + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + systemctl1, + systemd-ask-password-console.service8, + wall1, + plymouth8 + + + + diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml new file mode 100644 index 0000000..f44b7a0 --- /dev/null +++ b/man/systemd-udevd.service.xml @@ -0,0 +1,195 @@ + + + + + + + + systemd-udevd.service + systemd + + + Developer + Kay + Sievers + kay@vrfy.org + + + + + + systemd-udevd.service + 8 + + + + + systemd-udevd.service + systemd-udevd-control.socket + systemd-udevd-kernel.socket + systemd-udevd + Device event managing daemon + + + + systemd-udevd.service + systemd-udevd-control.socket + systemd-udevd-kernel.socket + + + /usr/lib/systemd/systemd-udevd + + + + + + + + + + + + Description + systemd-udevd listens to kernel uevents. + For every event, systemd-udevd executes matching instructions + specified in udev rules. See + udev7 + . + The behavior of the running daemon can be changed with + udevadm control. + + + Options + + + + + Detach and run in the background. + + + + + + + Print debug messages to standard error. + + + + + + + Limit the number of events executed in parallel. + + + + + + + Delay the execution of RUN + instructions by the given number of seconds. This option + might be useful when debugging system crashes during + coldplug caused by loading non-working kernel + modules. + + + + + + + Specify when systemd-udevd should resolve names of users and groups. + When set to (the default), names will be + resolved when the rules are parsed. When set to + , names will be resolved for every event. + When set to , names will never be resolved + and all devices will be owned by root. + + + + + + + + + + + + + Environment + + + $UDEV_LOG= + + Set the logging priority. + + + + + + Kernel command line + + Parameters starting with "rd." will be read when + systemd-udevd is used in an initrd. + + udev.log-priority= + rd.udev.log-priority= + + Set the logging priority. + + + + udev.children-max= + rd.udev.children-max= + + Limit the number of events executed in parallel. + + + + udev.exec-delay= + rd.udev.exec-delay= + + Delay the execution of RUN instructions by the given + number of seconds. This option might be useful when + debugging system crashes during coldplug caused by loading + non-working kernel modules. + + + + net.ifnames= + + Network interfaces are renamed to give them predictable names + when possible. It is enabled by default; specifying 0 disables it. + + + + + + + Configuration file + udev expects its main configuration file at /etc/udev/udev.conf. + It consists of a set of variables allowing the user to override default udev values. All + empty lines or lines beginning with '#' are ignored. The following variables can be + set: + + + udev_log + + The logging priority. Valid values are the numerical syslog priorities + or their textual representations: , + and . + + + + + + + See Also + + udev7 + , + udevadm8 + + + diff --git a/man/systemd-update-utmp.service.xml b/man/systemd-update-utmp.service.xml new file mode 100644 index 0000000..846fc95 --- /dev/null +++ b/man/systemd-update-utmp.service.xml @@ -0,0 +1,76 @@ + + + + + + + + systemd-update-utmp.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-update-utmp.service + 8 + + + + systemd-update-utmp.service + systemd-update-utmp-runlevel.service + systemd-update-utmp + Write audit and utmp updates at bootup, runlevel + changes and shutdown + + + + systemd-update-utmp.service + systemd-update-utmp-runlevel.service + /usr/lib/systemd/systemd-update-utmp + + + + Description + + systemd-update-utmp-runlevel.service + is a service that writes SysV runlevel changes to utmp + and wtmp, as well as the audit logs, as they + occur. systemd-update-utmp.service + does the same for system reboots and shut-down requests. + + + + See Also + + systemd1, + utmp5, + auditd8 + + + + diff --git a/man/systemd-user-sessions.service.xml b/man/systemd-user-sessions.service.xml new file mode 100644 index 0000000..fc93e2d --- /dev/null +++ b/man/systemd-user-sessions.service.xml @@ -0,0 +1,77 @@ + + + + + + + + systemd-user-sessions.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-user-sessions.service + 8 + + + + systemd-user-sessions.service + systemd-user-sessions + Permit user logins after boot, prohibit user logins at shutdown + + + + systemd-user-sessions.service + /usr/lib/systemd/systemd-user-sessions + + + + Description + + systemd-user-sessions.service + is a service that controls user logins. After basic + system initialization is complete it removes + /run/nologin, thus permitting + logins. Before system shutdown it creates + /run/nologin, thus prohibiting + further logins. At the same time it also kills all + user processes, so that system shutdown may proceed + without any remaining user processes around. + + + + See Also + + systemd1, + systemd-logind.service8, + pam_nologin8 + + + + diff --git a/man/systemd-vconsole-setup.service.xml b/man/systemd-vconsole-setup.service.xml new file mode 100644 index 0000000..3c50799 --- /dev/null +++ b/man/systemd-vconsole-setup.service.xml @@ -0,0 +1,118 @@ + + + + + + + + systemd-vconsole-setup.service + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-vconsole-setup.service + 8 + + + + systemd-vconsole-setup.service + systemd-vconsole-setup + Configure the virtual console at boot + + + + systemd-vconsole-setup.service + /usr/lib/systemd/systemd-vconsole-setup + + + + Description + + systemd-vconsole-setup.service + is an early-boot service that configures the virtual + console font and console keymap. Internally it calls + loadkeys1 + and + setfont8. + + See + vconsole.conf5 + for information about the configuration files understood by this + service. + + + + + + Kernel Command Line + + A few configuration parameters from + vconsole.conf may be overridden on + the kernel command line: + + + + vconsole.keymap= + vconsole.keymap.toggle= + + Overrides the key + mapping table for the keyboard and the + second toggle keymap. + + + + vconsole.font= + vconsole.font.map= + vconsole.font.unimap= + + Configures the console + font, the console map, and the unicode + font map. + + + + + + See + vconsole.conf5 + for information about these settings. + + + + See Also + + systemd1, + vconsole.conf5, + loadkeys1, + setfont8, + systemd-localed.service8 + + + + diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml index 754d1e3..3410512 100644 --- a/man/systemd.automount.xml +++ b/man/systemd.automount.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.automount - systemd automount configuration files + Automount unit configuration - systemd.automount + automount.automount Description A unit configuration file whose name ends in - .automount encodes information + .automount encodes information about a file system automount point controlled and supervised by systemd. @@ -70,7 +70,7 @@ Automount units must be named after the automount directories they control. Example: the - automount point /home/lennart + automount point /home/lennart must be configured in a unit file home-lennart.automount. For details about the escaping logic used to convert a @@ -93,7 +93,7 @@ file systems. If an automount point is beneath another mount - point in the file system hierarchy a dependency + point in the file system hierarchy, a dependency between both units is created automatically. @@ -110,7 +110,7 @@ systemd.mount5. If an automount point is configured in both - /etc/fstab and a unit file the + /etc/fstab and a unit file, the configuration in the latter takes precedence. @@ -123,17 +123,17 @@ specific to the [Automount] section of automount units are the following: - + Where= Takes an absolute path of a directory of the automount - point. If the automount point is not - existing at time of the automount - point is installed it is created. This + point. If the automount point does not + exist at time that the automount + point is installed, it is created. This string must be reflected in the unit - file name. (See above.) This option is + filename. (See above.) This option is mandatory. @@ -160,7 +160,8 @@ systemd.unit5, systemd.mount5, mount8, - automount8 + automount8, + systemd.directives7 diff --git a/man/systemd.conf.xml b/man/systemd.conf.xml deleted file mode 100644 index 56490ef..0000000 --- a/man/systemd.conf.xml +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - - systemd.conf - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd.conf - 5 - - - - systemd.conf - systemd manager configuration file - - - - system.conf - user.conf - - - - Description - - When run as system instance systemd reads the - configuration file system.conf, - otherwise user.conf. These - configuration files contain a few settings controlling - basic manager operations. - - - - - Options - - All options are configured in the - [Manager] section: - - - - - LogLevel= - LogTarget= - LogColor= - LogLocation= - DumpCore=yes - CrashShell=no - ShowStatus=yes - SysVConsole=yes - CrashChVT=1 - DefaultStandardOutput=null - DefaultStandardError=inherit - - Configures various - parameters of basic manager - operation. These options may be - overridden by the respective command - line arguments. See - systemd1 - for details about these command line - arguments. - - - - CPUAffinity= - - Configures the initial - CPU affinity for the init - process. Takes a space-separated list - of CPU indexes. - - - - MountAuto=yes - SwapAuto=yes - - Configures whether - systemd should automatically activate - all swap or mounts listed in - /etc/fstab, or - whether this job is left to some other - system script. - - - - DefaultControllers=cpu - - Configures in which - cgroup controller hierarchies to - create per-service cgroups - automatically, in addition to the - name=systemd named hierarchy. Defaults - to 'cpu'. Takes a space separated list - of controller names. Pass an empty - string to ensure that systemd does not - touch any hierarchies but its - own. - - - - JoinControllers=cpu,cpuacct - - Configures controllers - that shall be mounted in a single - hierarchy. By default systemd will - mount all controllers which are - enabled in the kernel in individual - hierachies, with the exception of - those listed in this setting. Takes a - space separated list of comma - separated controller names, in order - to allow multiple joined - hierarchies. Defaults to - 'cpu,cpuacct'. Pass an empty string to - ensure that systemd mounts all - controllers in separate - hierarchies. - - - - - - See Also - - systemd1 - - - - diff --git a/man/systemd.device.xml b/man/systemd.device.xml index 63863be..619fe19 100644 --- a/man/systemd.device.xml +++ b/man/systemd.device.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.device - systemd device configuration files + Device unit configuration - systemd.device + device.device Description A unit configuration file whose name ends in - .device encodes information about + .device encodes information about a device unit as exposed in the sysfs/udev7 device tree. @@ -70,17 +70,20 @@ since no device-specific options may be configured. - systemd will automatically create dynamic device - units for all kernel devices that are marked with the - "systemd" udev tag (by default all block and network - devices, and a few others). This may be used to define - dependencies between devices and other - units. + systemd will dynamically create device units for + all kernel devices that are marked with the "systemd" + udev tag (by default all block and network devices, + and a few others). This may be used to define + dependencies between devices and other units. To tag a + udev device, use TAG+="systemd" in + the udev rules file, see + udev7 + for details. Device units are named after the /sys and /dev paths they control. Example: - the device /dev/sda5 is exposed + the device /dev/sda5 is exposed in systemd as dev-sda5.device. For details about the escaping logic used to convert a file system path to a unit name see @@ -93,24 +96,41 @@ The settings of device units may either be configured via unit files, or directly from the udev - database (which is recommended). The following udev + database (which is recommended). The following udev device properties are understood by systemd: - + SYSTEMD_WANTS= + SYSTEMD_USER_WANTS= Adds dependencies of - type Wants from - this unit to all listed units. This - may be used to activate arbitrary - units, when a specific device becomes - available. Note that this and the + type Wants from the + device unit to all listed units. The + first form is used by the system + systemd instance, the second by user + systemd instances. Those settings may + be used to activate arbitrary units + when a specific device becomes + available. + + Note that this and the other tags are not taken into account unless the device is tagged with the - "systemd" string in + systemd string in the udev database, because otherwise - the device is not exposed as systemd - unit. + the device is not exposed as a systemd + unit (see above). + + Note that systemd will only act + on Wants + dependencies when a device first + becomes active. It will not act on + them if they are added to devices that + are already active. Use + SYSTEMD_READY= (see + below) to influence on which udev + event to trigger the dependencies. + @@ -124,21 +144,27 @@ SYSTEMD_READY= - If set to 0 systemd + If set to 0, systemd will consider this device unplugged even if it shows up in the udev tree. If this property is unset or set - to 1 the device will be considered - plugged the moment it shows up in the + to 1, the device will be considered + plugged if it is visible in the udev tree. This property has no - influence on the behaviour when a + influence on the behavior when a device disappears from the udev - tree. This option is useful to support + tree. + + This option is useful to support devices that initially show up in an - uninitialized state in the tree, and for - which a changed event is generated the - moment they are fully set - up. + uninitialized state in the tree, and + for which a changed + event is generated the moment they are + fully set up. Note that + SYSTEMD_WANTS= (see + above) is not acted on as long as + SYSTEMD_READY=0 is + set for a device. @@ -161,7 +187,8 @@ systemd1, systemctl8, systemd.unit5, - udev7 + udev7, + systemd.directives7 diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 230c4a3..1983993 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1,4 +1,3 @@ - @@ -9,16 +8,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,21 +43,21 @@ systemd.exec - systemd execution environment configuration + Execution environment configuration - systemd.service, - systemd.socket, - systemd.mount, - systemd.swap + service.service, + socket.socket, + mount.mount, + swap.swap Description Unit configuration files for services, sockets, - mount points and swap devices share a subset of + mount points, and swap devices share a subset of configuration options which define the execution environment of spawned processes. @@ -69,28 +68,32 @@ files, and systemd.service5, systemd.socket5, - systemd.swap5 + systemd.swap5, and systemd.mount5 for more information on the specific unit configuration files. The execution specific configuration options are configured in the [Service], - [Socket], [Mount] resp. [Swap] section, depending on the unit + [Socket], [Mount], or [Swap] sections, depending on the unit type. Options - + WorkingDirectory= Takes an absolute directory path. Sets the working - directory for executed - processes. + directory for executed processes. If + not set, defaults to the root directory + when systemd is running as a system + instance and the respective user's + home directory if run as + user. @@ -101,7 +104,7 @@ directory for executed processes, with the chroot2 - system call. If this is used it must + system call. If this is used, it must be ensured that the process and all its auxiliary files are available in the chroot() @@ -113,10 +116,10 @@ Group= Sets the Unix user - resp. group the processes are executed - as. Takes a single user resp. group + or group that the processes are executed + as, respectively. Takes a single user or group name or ID as argument. If no group is - set the default group of the user is + set, the default group of the user is chosen. @@ -125,14 +128,19 @@ Sets the supplementary Unix groups the processes are executed - as. This takes a space separated list + as. This takes a space-separated list of group names or IDs. This option may be specified more than once in which case all listed groups are set as - supplementary groups. This option does - not override but extends the list of - supplementary groups configured in the - system group database for the + supplementary groups. When the empty + string is assigned the list of + supplementary groups is reset, and all + assignments prior to this one will + have no effect. In any way, this + option does not override, but extends + the list of supplementary groups + configured in the system group + database for the user. @@ -158,7 +166,7 @@ for this process) and 1000 (to make killing of this process under memory pressure very likely). See proc.txt + url="https://www.kernel.org/doc/Documentation/filesystems/proc.txt">proc.txt
for details. @@ -210,20 +218,22 @@ Sets the CPU scheduling priority for executed - processes. Takes an integer between 1 - (lowest priority) and 99 (highest - priority). The available priority + processes. The available priority range depends on the selected CPU - scheduling policy (see above). See - sched_setscheduler2 - for details. + scheduling policy (see above). For + real-time scheduling policies an + integer between 1 (lowest priority) + and 99 (highest priority) can be used. + See sched_setscheduler2 + for details. + CPUSchedulingResetOnFork= Takes a boolean - argument. If true elevated CPU + argument. If true, elevated CPU scheduling priorities and policies will be reset when the executed processes fork, and can hence not leak @@ -238,7 +248,13 @@ Controls the CPU affinity of the executed processes. Takes a space-separated - list of CPU indexes. See + list of CPU indices. This option may + be specified more than once in which + case the specificed CPU affinity masks + are merged. If the empty string is + assigned, the mask is reset, all + assignments prior to this will have no + effect. See sched_setaffinity2 for details. @@ -264,10 +280,32 @@ option may be specified more than once in which case all listed variables will be set. If the same variable is - set twice the later setting will - override the earlier setting. See + set twice, the later setting will + override the earlier setting. If the + empty string is assigned to this + option, the list of environment + variables is reset, all prior + assignments have no effect. + Variable expansion is not performed + inside the strings, however, specifier + expansion is possible. The $ character has + no special meaning. + If you need to assign a value containing spaces + to a variable, use double quotes (") + for the assignment. + + Example: + Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" + gives three variables VAR1, + VAR2, VAR3 + with the values word1 word2, + word3, $word 5 6. + + + + See environ7 - for details. + for details about environment variables. EnvironmentFile= @@ -275,31 +313,42 @@ Environment= but reads the environment variables from a text file. The text file should - contain new-line separated variable + contain new-line-separated variable assignments. Empty lines and lines starting with ; or # will be ignored, - which may be used for commenting. The - parser strips leading and - trailing whitespace from the values + which may be used for commenting. A line + ending with a backslash will be concatenated + with the following one, allowing multiline variable + definitions. The parser strips leading + and trailing whitespace from the values of assignments, unless you use - double quotes ("). - The - argument passed should be an absolute - file name, optionally prefixed with - "-", which indicates that if the file - does not exist it won't be read and no - error or warning message is - logged. The files listed with this + double quotes ("). + + The argument passed should be an + absolute filename or wildcard + expression, optionally prefixed with + -, which indicates + that if the file does not exist, it + will not be read and no error or warning + message is logged. This option may be + specified more than once in which case + all specified files are read. If the + empty string is assigned to this + option, the list of file to read is + reset, all prior assignments have no + effect. + + The files listed with this directive will be read shortly before the process is executed. Settings from these files override settings made with Environment=. If the same variable is set twice from - these files the files will be read in + these files, the files will be read in the order they are specified and the later setting will override the - earlier setting. + earlier setting. @@ -312,19 +361,19 @@ , or . If - is selected + is selected, standard input will be connected to /dev/null, i.e. all read attempts by the process will result in immediate EOF. If - is selected + is selected, standard input is connected to a TTY (as configured by TTYPath=, see below) and the executed process becomes the controlling process of the terminal. If the terminal is already - being controlled by another process the + being controlled by another process, the executed process waits until the current controlling process releases the terminal. @@ -346,7 +395,7 @@ file (see systemd.socket5 for details) specifies a single socket - only. If this option is set standard + only. If this option is set, standard input will be connected to the socket the service was activated from, which is primarily useful for compatibility @@ -366,22 +415,24 @@ , , , + , + , , - or + or . If set to - the file + , the file descriptor of standard input is duplicated for standard output. If set - to standard + to , standard output will be connected to /dev/null, i.e. everything written to it will be - lost. If set to + lost. If set to , standard output will be connected to a tty (as configured via TTYPath=, see below). If the TTY is used for output - only the executed process will not + only, the executed process will not become the controlling process of the terminal, and will not fail or wait for other processes to release the @@ -392,8 +443,17 @@ service. connects it with the kernel log buffer which is accessible via - dmesg1. - and work + dmesg1. + connects it with the journal which is + accessible via + journalctl1 + (Note that everything that is written + to syslog or kmsg is implicitly stored + in the journal as well, those options + are hence supersets of this + one). , + and + work similarly but copy the output to the system console as well. connects @@ -405,16 +465,16 @@ with in - systemd.conf5, + systemd-system.conf5, which defaults to - . + . StandardError= Controls where file - descriptor 2 (STDERR) of the executed - processes is connected to. The - available options are identical to + descriptor 2 (STDERR) of the + executed processes is connected to. + The available options are identical to those of StandardOutput=, with one exception: if set to @@ -424,15 +484,15 @@ setting defaults to the value set with in - systemd.conf5, + systemd-system.conf5, which defaults to . TTYPath= Sets the terminal - device node to use if standard input, - output or stderr are connected to a + device node to use if standard input, output, + or error are connected to a TTY (see above). Defaults to /dev/console. @@ -456,10 +516,10 @@ TTYVTDisallocate= - If the the terminal + If the terminal device specified with TTYPath= is a - virtual console terminal try to + virtual console terminal, try to deallocate the TTY before and after execution. This ensures that the screen and scrollback buffer is @@ -470,7 +530,7 @@ SyslogIdentifier= Sets the process name to prefix log lines sent to syslog or - the kernel log buffer with. If not set + the kernel log buffer with. If not set, defaults to the process name of the executed process. This option is only useful when @@ -540,7 +600,7 @@ prefixes may be disabled with SyslogLevelPrefix=, see below. For details see - sd-daemon7. + sd-daemon3. Defaults to . @@ -552,8 +612,9 @@ argument. If true and StandardOutput= or StandardError= are - set to or - log lines + set to , + or + , log lines written by the executed process that are prefixed with a log level will be passed on to syslog with this log @@ -562,7 +623,7 @@ these prefixes is disabled and the logged lines are passed on as-is. For details about this prefixing see - sd-daemon7. + sd-daemon3. Defaults to true. @@ -570,16 +631,17 @@ TimerSlackNSec= Sets the timer slack in nanoseconds for the executed - processes. The timer slack controls the - accuracy of wake-ups triggered by + processes. The timer slack controls + the accuracy of wake-ups triggered by timers. See prctl2 for more information. Note that in contrast to most other time span definitions this parameter takes an - integer value in nano-seconds and does - not understand any other - units. + integer value in nano-seconds if no + unit is specified. The usual time + units are understood + too. @@ -612,13 +674,13 @@ PAMName= Sets the PAM service - name to set up a session as. If set + name to set up a session as. If set, the executed process will be registered as a PAM session under the specified service name. This is only useful in conjunction with the User= setting. If - not set no PAM session will be opened + not set, no PAM session will be opened for the executed processes. See pam8 for details. @@ -627,21 +689,26 @@ TCPWrapName= If this is a - socket-activated service this sets the + socket-activated service, this sets the tcpwrap service name to check the permission for the current connection with. This is only useful in conjunction with socket-activated services, and stream sockets (TCP) in particular. It has no effect on other - socket types (e.g. datagram/UDP) and on processes - unrelated to socket-based + socket types (e.g. datagram/UDP) and + on processes unrelated to socket-based activation. If the tcpwrap - verification fails daemon start-up + verification fails, daemon start-up will fail and the connection is terminated. See tcpd8 - for details. + for details. Note that this option may + be used to do access control checks + only. Shell commands and commands + described in + hosts_options5 + are not supported. @@ -652,27 +719,40 @@ capability bounding set for the executed process. See capabilities7 - for details. Takes a whitespace - separated list of capability names as - read by - cap_from_name3. + for details. Takes a whitespace-separated + list of capability names as read by + cap_from_name3, + e.g. CAP_SYS_ADMIN, + CAP_DAC_OVERRIDE, + CAP_SYS_PTRACE. Capabilities listed will be included in the bounding set, all others are removed. If the list of capabilities - is prefixed with ~ all but the listed - capabilities will be included, the - effect of the assignment - inverted. Note that this option does - not actually set or unset any + is prefixed with ~, + all but the listed capabilities will + be included, the effect of the + assignment inverted. Note that this + option also affects the respective capabilities in the effective, - permitted or inherited capability - sets. That's what - Capabilities= is - for. If this option is not used the + permitted and inheritable capability + sets, on top of what + Capabilities= + does. If this option is not used, the capability bounding set is not modified on process execution, hence no limits on the capabilities of the - process are enforced. + process are enforced. This option may + appear more than once in which case + the bounding sets are merged. If the + empty string is assigned to this + option, the bounding set is reset to + the empty capability set, and all + prior settings have no effect. If set + to ~ (without any + further argument), the bounding set is + reset to the full set of available + capabilities, also undoing any + previous settings. @@ -686,8 +766,12 @@ , , and/or - . - + . This + option may appear more than once in + which case the secure bits are + ORed. If the empty string is assigned + to this option, the bits are reset to + 0. @@ -709,233 +793,15 @@ - ControlGroup= - - Controls the control - groups the executed processes shall be - made members of. Takes a - space-separated list of cgroup - identifiers. A cgroup identifier has a - format like - cpu:/foo/bar, - where "cpu" identifies the kernel - control group controller used, and - /foo/bar is the - control group path. The controller - name and ":" may be omitted in which - case the named systemd control group - hierarchy is implied. Alternatively, - the path and ":" may be omitted, in - which case the default control group - path for this unit is implied. This - option may be used to place executed - processes in arbitrary groups in - arbitrary hierarchies -- which can be - configured externally with additional - execution limits. By default systemd - will place all executed processes in - separate per-unit control groups - (named after the unit) in the systemd - named hierarchy. Since every process - can be in one group per hierarchy only - overriding the control group path in - the named systemd hierarchy will - disable automatic placement in the - default group. This option is - primarily intended to place executed - processes in specific paths in - specific kernel controller - hierarchies. It is however not - recommended to manipulate the service - control group path in the systemd - named hierarchy. For details about - control groups see cgroups.txt. - - - - ControlGroupModify= - Takes a boolean - argument. If true, the control groups - created for this unit will be owned by - the user specified with - User= (and the - appropriate group), and he/she can create - subgroups as well as add processes to - the group. - - - - ControlGroupAttribute= - - Set a specific control - group attribute for executed - processes, and (if needed) add the the - executed processes to a cgroup in the - hierarchy of the controller the - attribute belongs to. Takes two - space-separated arguments: the - attribute name (syntax is - cpu.shares where - cpu refers to a - specific controller and - shares to the - attribute name), and the attribute - value. Example: - ControlGroupAttribute=cpu.shares - 512. If this option is used - for an attribute that belongs to a - kernel controller hierarchy the unit - is not already configured to be added - to (for example via the - ControlGroup= - option) then the unit will be added to - the controller and the default unit - cgroup path is implied. Thus, using - ControlGroupAttribute= - is in most case sufficient to make use - of control group enforcements, - explicit - ControlGroup= are - only necessary in case the implied - default control group path for a - service is not desirable. For details - about control group attributes see - cgroups.txt. This - option may appear more than once, in - order to set multiple control group - attributes. - - - - CPUShares= - - Assign the specified - overall CPU time shares to the - processes executed. Takes an integer - value. This controls the - cpu.shares control - group attribute, which defaults to - 1024. For details about this control - group attribute see sched-design-CFS.txt. - - - - MemoryLimit= - MemorySoftLimit= - - Limit the overall memory usage - of the executed processes to a certain - size. Takes a memory size in bytes. If - the value is suffixed with K, M, G or - T the specified memory size is parsed - as Kilobytes, Megabytes, Gigabytes, - resp. Terabytes (to the base - 1024). This controls the - memory.limit_in_bytes - and - memory.soft_limit_in_bytes - control group attributes. For details - about these control group attributes - see memory.txt. - - - - DeviceAllow= - DeviceDeny= - - Control access to - specific device nodes by the executed processes. Takes two - space separated strings: a device node - path (such as - /dev/null) - followed by a combination of r, w, m - to control reading, writing resp. - creating of the specific device node - by the unit. This controls the - devices.allow - and - devices.deny - control group attributes. For details - about these control group attributes - see devices.txt. - - - - BlockIOWeight= - - Set the default or - per-device overall block IO weight - value for the executed - processes. Takes either a single - weight value (between 10 and 1000) to - set the default block IO weight, or a - space separated pair of a file path - and a weight value to specify the - device specific weight value (Example: - "/dev/sda 500"). The file path may be - specified as path to a block device - node or as any other file in which - case the backing block device of the - file system of the file is - determined. This controls the - blkio.weight and - blkio.weight_device - control group attributes, which - default to 1000. Use this option - multiple times to set weights for - multiple devices. For details about - these control group attributes see - blkio-controller.txt. - - - - BlockIOReadBandwidth= - BlockIOWriteBandwidth= - - Set the per-device - overall block IO bandwith limit for - the executed processes. Takes a space - separated pair of a file path and a - bandwith value (in bytes per second) - to specify the device specific - bandwidth. The file path may be - specified as path to a block device - node or as any other file in which - case the backing block device of the - file system of the file is determined. - If the bandwith is suffixed with K, M, - G, or T the specified bandwith is - parsed as Kilobytes, Megabytes, - Gigabytes, resp. Terabytes (Example: - "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 - 5M"). This controls the - blkio.read_bps_device - and - blkio.write_bps_device - control group attributes. Use this - option multiple times to set bandwith - limits for multiple devices. For - details about these control group - attributes see blkio-controller.txt. - - - ReadWriteDirectories= ReadOnlyDirectories= InaccessibleDirectories= Sets up a new - file-system name space for executed + file system namespace for executed processes. These options may be used to limit access a process might have - to the main file-system + to the main file system hierarchy. Each setting takes a space-separated list of absolute directory paths. Directories listed in @@ -949,44 +815,67 @@ usual file access controls would permit this. Directories listed in InaccessibleDirectories= - will be made inaccessible for processes - inside the namespace. Note that - restricting access with these options - does not extend to submounts of a - directory. You must list submounts - separately in these settings to - ensure the same limited access. These - options may be specified more than - once in which case all directories - listed will have limited access from - within the - namespace. + will be made inaccessible for + processes inside the namespace. Note + that restricting access with these + options does not extend to submounts + of a directory. You must list + submounts separately in these settings + to ensure the same limited + access. These options may be specified + more than once in which case all + directories listed will have limited + access from within the namespace. If + the empty string is assigned to this + option, the specific list is reset, and + all prior assignments have no + effect. + Paths in + ReadOnlyDirectories= + and + InaccessibleDirectories= + may be prefixed with + -, in which case + they will be ignored when they do not + exist. PrivateTmp= Takes a boolean - argument. If true sets up a new file + argument. If true, sets up a new file system namespace for the executed - processes and mounts a private - /tmp directory - inside it, that is not shared by - processes outside of the + processes and mounts private + /tmp and + /var/tmp + directories inside it that is not + shared by processes outside of the namespace. This is useful to secure access to temporary files of the process, but makes sharing between processes via - /tmp - impossible. Defaults to - false. + /tmp or + /var/tmp + impossible. All temporary data created + by service will be removed after + the service is stopped. Defaults to + false. Note that it is possible to run + two or more units within the same + private /tmp and + /var/tmp + namespace by using the + JoinsNamespaceOf= + directive, see + systemd.unit5 + for details. PrivateNetwork= Takes a boolean - argument. If true sets up a new + argument. If true, sets up a new network namespace for the executed processes and configures only the loopback network device @@ -995,6 +884,30 @@ available to the executed process. This is useful to securely turn off network access by the executed + process. Defaults to false. Note that + it is possible to run two or more + units within the same private network + namespace by using the + JoinsNamespaceOf= + directive, see + systemd.unit5 + for details. + + + + PrivateDevices= + + Takes a boolean + argument. If true, sets up a new /dev + namespace for the executed processes + and only adds API pseudo devices such + as /dev/null, + /dev/zero or + /dev/random to + it, but no physical devices such as + /dev/sda. This is + useful to securely turn off physical + device access by the executed process. Defaults to false. @@ -1007,26 +920,19 @@ , or , which - control whether namespaces set up with - ReadWriteDirectories=, - ReadOnlyDirectories= - and - InaccessibleDirectories= - receive or propagate new mounts - from/to the main namespace. See - mount1 - for details. Defaults to - , i.e. the new - namespace will both receive new mount - points from the main namespace as well - as propagate new mounts to - it. + control whether the file system + namespace set up for this unit's + processes will receive or propagate + new mounts. See + mount2 + for details. Default to + . UtmpIdentifier= - Takes a a four + Takes a four character identifier string for an utmp/wtmp entry for this service. This should only be set for services such @@ -1035,7 +941,7 @@ entries must be created and cleared before and after execution. If the configured string is longer than four - characters it is truncated and the + characters, it is truncated and the terminal four characters are used. This setting interprets %I style string replacements. This setting is @@ -1044,7 +950,335 @@ this service. + + SELinuxContext= + + Set the SELinux + security context of the executed + process. If set, this will override + the automated domain + transition. However, the policy still + needs to autorize the transition. This + directive is ignored if SELinux is + disabled. If prefixed by + -, all errors will + be ignored. See + setexeccon3 + for details. + + + + AppArmorProfile= + + Take a profile name as argument. + The process executed by the unit will switch to + this profile when started. Profiles must already + be loaded in the kernel, or the unit will fail. + This result in a non operation if AppArmor is not + enabled. If prefixed by -, all errors + will be ignored. + + + + + IgnoreSIGPIPE= + + Takes a boolean + argument. If true, causes SIGPIPE to be + ignored in the executed + process. Defaults to true because + SIGPIPE generally is useful only in + shell pipelines. + + + + NoNewPrivileges= + + Takes a boolean + argument. If true, ensures that the + service process and all its children + can never gain new privileges. This + option is more powerful than the respective + secure bits flags (see above), as it + also prohibits UID changes of any + kind. This is the simplest, most + effective way to ensure that a process + and its children can never elevate + privileges again. + + + + SystemCallFilter= + + Takes a space-separated + list of system call + names. If this setting is used, all + system calls executed by the unit + processes except for the listed ones + will result in immediate process + termination with the + SIGSYS signal + (whitelisting). If the first character + of the list is ~, + the effect is inverted: only the + listed system calls will result in + immediate process termination + (blacklisting). If this option is used, + NoNewPrivileges=yes + is implied. This feature makes use of + the Secure Computing Mode 2 interfaces + of the kernel ('seccomp filtering') + and is useful for enforcing a minimal + sandboxing environment. Note that the + execve, + rt_sigreturn, + sigreturn, + exit_group, + exit system calls + are implicitly whitelisted and do not + need to be listed explicitly. This + option may be specified more than once + in which case the filter masks are + merged. If the empty string is + assigned, the filter is reset, all + prior assignments will have no + effect. + + If you specify both types of + this option (i.e. whitelisting and + blacklisting), the first encountered + will take precedence and will dictate + the default action (termination or + approval of a system call). Then the + next occurrences of this option will + add or delete the listed system calls + from the set of the filtered system + calls, depending of its type and the + default action. (For example, if you have started + with a whitelisting of + read and + write, and right + after it add a blacklisting of + write, then + write will be + removed from the set.) + + + + + SystemCallErrorNumber= + + Takes an + errno error number + name to return when the system call + filter configured with + SystemCallFilter= + is triggered, instead of terminating + the process immediately. Takes an + error name such as + EPERM, + EACCES or + EUCLEAN. When this + setting is not used, or when the empty + string is assigned, the process will be + terminated immediately when the filter + is triggered. + + + + SystemCallArchitectures= + + Takes a space + separated list of architecture + identifiers to include in the system + call filter. The known architecture + identifiers are + x86, + x86-64, + x32, + arm as well as the + special identifier + native. Only system + calls of the specified architectures + will be permitted to processes of this + unit. This is an effective way to + disable compatibility with non-native + architectures for processes, for + example to prohibit execution of + 32-bit x86 binaries on 64-bit x86-64 + systems. The special + native identifier + implicitly maps to the native + architecture of the system (or more + strictly: to the architecture the + system manager is compiled for). Note + that setting this option to a + non-empty list implies that + native is included + too. By default, this option is set to + the empty list, i.e. no architecture + system call filtering is + applied. + + + + Personality= + + Controls which + kernel architecture + uname2 + shall report, when invoked by unit + processes. Takes one of + x86 and + x86-64. This is + useful when running 32bit services on + a 64bit host system. If not specified + the personality is left unmodified and + thus reflects the personality of the + host system's + kernel. + + + + + + Environment variables in spawned processes + + Processes started by the system are executed in + a clean environment in which select variables + listed below are set. System processes started by systemd + do not inherit variables from PID 1, but processes + started by user systemd instances inherit all + environment variables from the user systemd instance. + + + + + $PATH + + Colon-separated list + of directiories to use when launching + executables. Systemd uses a fixed + value of + /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin. + + + + + $LANG + + Locale. Can be set in + locale.conf5 + or on the kernel command line (see + systemd1 + and + kernel-command-line7). + + + + + $USER + $LOGNAME + $HOME + $SHELL + + User name (twice), home + directory, and the login shell. + The variables are set for the units that + have User= set, + which includes user + systemd instances. + See + passwd5. + + + + + $XDG_RUNTIME_DIR + + The directory for volatile + state. Set for the user systemd + instance, and also in user sessions. + See + pam_systemd8. + + + + + $XDG_SESSION_ID + $XDG_SEAT + $XDG_VTNR + + The identifier of the + session, the seat name, and + virtual terminal of the session. Set + by + pam_systemd8 + for login sessions. + $XDG_SEAT and + $XDG_VTNR will + only be set when attached to a seat and a + tty. + + + + $MAINPID + + The PID of the units + main process if it is known. This is + only set for control processes as + invoked by + ExecReload= and + similar. + + + + $MANAGERPID + + The PID of the user + systemd instance, + set for processes spawned by it. + + + + + $LISTEN_FDS + $LISTEN_PID + + Information about file + descriptors passed to a service for + socket activation. See + sd_listen_fds3. + + + + + $TERM + + Terminal type, set + only for units connected to a terminal + (StandardInput=tty, + StandardOutput=tty, + or + StandardError=tty). + See + termcap5. + + + + Additional variables may be configured by the + following means: for processes spawned in specific + units, use the Environment= and + EnvironmentFile= options above; to + specify variables globally, use + DefaultEnvironment= (see + systemd-system.conf5) + or the kernel option + systemd.setenv= (see + systemd1). Additional + variables may also be set through PAM, + c.f. pam_env8. @@ -1052,11 +1286,16 @@ systemd1, systemctl8, + journalctl8, systemd.unit5, systemd.service5, systemd.socket5, systemd.swap5, - systemd.mount5 + systemd.mount5, + systemd.kill5, + systemd.resource-control5, + systemd.directives7, + exec3 diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml new file mode 100644 index 0000000..d77e6eb --- /dev/null +++ b/man/systemd.journal-fields.xml @@ -0,0 +1,602 @@ + + + + + + + + + systemd.journal-fields + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.journal-fields + 7 + + + + systemd.journal-fields + Special journal fields + + + + Description + + Entries in the journal resemble an environment + block in their syntax but with fields that can + include binary data. Primarily, fields are formatted + UTF-8 text strings, and binary formatting is used only + where formatting as UTF-8 text strings makes little + sense. New fields may freely be defined by + applications, but a few fields have special + meaning. All fields with special meanings are + optional. In some cases, fields may appear more than + once per entry. + + + + User Journal Fields + + User fields are fields that are directly passed + from clients and stored in the journal. + + + + MESSAGE= + + The human-readable + message string for this + entry. This is supposed to be + the primary text shown to the + user. It is usually not + translated (but might be in + some cases), and is not + supposed to be parsed for meta + data. + + + + + MESSAGE_ID= + + A 128-bit message + identifier ID for recognizing + certain message types, if this + is desirable. This should + contain a 128-bit ID formatted + as a lower-case hexadecimal + string, without any separating + dashes or suchlike. This is + recommended to be a + UUID-compatible ID, but this is not + enforced, and formatted + differently. Developers can + generate a new ID for this + purpose with journalctl + . + + + + + + PRIORITY= + + A priority value between + 0 (emerg) + and 7 + (debug) + formatted as a decimal + string. This field is + compatible with syslog's + priority concept. + + + + + CODE_FILE= + CODE_LINE= + CODE_FUNC= + + The code location + generating this message, if + known. Contains the source + filename, the line number and + the function name. + + + + + ERRNO= + + The low-level Unix error + number causing this entry, if + any. Contains the numeric + value of + errno3 + formatted as a decimal + string. + + + + + SYSLOG_FACILITY= + SYSLOG_IDENTIFIER= + SYSLOG_PID= + + Syslog compatibility + fields containing the facility + (formatted as decimal string), + the identifier string + (i.e. "tag"), and the client + PID. + + + + + + + + Trusted Journal Fields + + Fields prefixed with an underscore are trusted + fields, i.e. fields that are implicitly added by the + journal and cannot be altered by client code. + + + + _PID= + _UID= + _GID= + + The process, user, and + group ID of the process the + journal entry originates from + formatted as a decimal + string. + + + + + _COMM= + _EXE= + _CMDLINE= + + The name, the executable + path, and the command line of + the process the journal entry + originates from. + + + + + _CAP_EFFECTIVE= + + The effective capabilities7 of + the process the journal entry + originates from. + + + + + _AUDIT_SESSION= + _AUDIT_LOGINUID= + + The session and login + UID of the process the journal + entry originates from, as + maintained by the kernel audit + subsystem. + + + + + _SYSTEMD_CGROUP= + _SYSTEMD_SESSION= + _SYSTEMD_UNIT= + _SYSTEMD_USER_UNIT= + _SYSTEMD_OWNER_UID= + _SYSTEMD_SLICE= + + + The control group path + in the systemd hierarchy, the + systemd session ID (if any), + the systemd unit name (if + any), the systemd user session + unit name (if any), the owner + UID of the systemd session (if + any) and the systemd slice + unit of the process the + journal entry originates + from. + + + + + _SELINUX_CONTEXT= + + The SELinux security + context (label) of the process + the journal entry originates + from. + + + + + _SOURCE_REALTIME_TIMESTAMP= + + The earliest trusted + timestamp of the message, if + any is known that is different + from the reception time of the + journal. This is the time in + microseconds since the epoch UTC, + formatted as a decimal + string. + + + + + _BOOT_ID= + + The kernel boot ID for + the boot the message was + generated in, formatted as + a 128-bit hexadecimal + string. + + + + + _MACHINE_ID= + + The machine ID of the + originating host, as available + in + machine-id5. + + + + + _HOSTNAME= + + The name of the + originating host. + + + + + _TRANSPORT= + + How the entry was + received by the journal + service. Valid transports are: + + + + + + + + for + internally + generated + messages + + + + + + + + + + for those + received via the + local syslog + socket with the + syslog protocol + + + + + + + + + + for those + received via the + native journal + protocol + + + + + + + + + + for those + read from a + service's + standard output + or error output + + + + + + + + + + for those + read from the + kernel + + + + + + + + + + + Kernel Journal Fields + + Kernel fields are fields that are used by + messages originating in the kernel and stored in the + journal. + + + + _KERNEL_DEVICE= + + The kernel device + name. If the entry is + associated to a block device, + the major and minor of the + device node, separated by : + and prefixed by b. Similar + for character devices but + prefixed by c. For network + devices, this is the interface index + prefixed by n. For all other + devices, this is the subsystem name + prefixed by +, followed by + :, followed by the kernel + device name. + + + + _KERNEL_SUBSYSTEM= + + The kernel subsystem name. + + + + _UDEV_SYSNAME= + + The kernel device name + as it shows up in the device + tree below + /sys. + + + + _UDEV_DEVNODE= + + The device node path of + this device in + /dev. + + + + _UDEV_DEVLINK= + + Additional symlink names + pointing to the device node in + /dev. This + field is frequently set more + than once per entry. + + + + + + + Fields to log on behalf of a different program + + Fields in this section are used by programs + to specify that they are logging on behalf of another + program or unit. + + + Fields used by the systemd-coredump + coredump kernel helper: + + + + + COREDUMP_UNIT= + COREDUMP_USER_UNIT= + + Used to annotate + messages containing coredumps from + system and session units. + See + systemd-coredumpctl1. + + + + + + Priviledged programs (currently UID 0) may + attach OBJECT_PID= to a + message. This will instruct + systemd-journald to attach + additional fields on behalf of the caller: + + + + OBJECT_PID=PID + + PID of the program that this + message pertains to. + + + + + + OBJECT_UID= + OBJECT_GID= + OBJECT_COMM= + OBJECT_EXE= + OBJECT_CMDLINE= + OBJECT_AUDIT_SESSION= + OBJECT_AUDIT_LOGINUID= + OBJECT_SYSTEMD_CGROUP= + OBJECT_SYSTEMD_SESSION= + OBJECT_SYSTEMD_OWNER_UID= + OBJECT_SYSTEMD_UNIT= + OBJECT_SYSTEMD_USER_UNIT= + + These are additional fields added automatically + by systemd-journald. + Their meaning is the same as + _UID=, + _GID=, + _COMM=, + _EXE=, + _CMDLINE=, + _AUDIT_SESSION=, + _AUDIT_LOGINUID=, + _SYSTEMD_CGROUP=, + _SYSTEMD_SESSION=, + _SYSTEMD_UNIT=, + _SYSTEMD_USER_UNIT=, and + _SYSTEMD_OWNER_UID= + as described above, except that the + process identified by PID + is described, instead of the process + which logged the message. + + + + + + + + + Address Fields + + During serialization into external formats, such + as the Journal + Export Format or the Journal + JSON Format, the addresses of journal entries + are serialized into fields prefixed with double + underscores. Note that these are not proper fields when + stored in the journal but for addressing metadata of + entries. They cannot be written as part of structured + log entries via calls such as + sd_journal_send3. They + may also not be used as matches for + sd_journal_add_match3 + + + + __CURSOR= + + The cursor for the + entry. A cursor is an opaque + text string that uniquely + describes the position of an + entry in the journal and is + portable across machines, + platforms and journal files. + + + + + + __REALTIME_TIMESTAMP= + + The wallclock time + (CLOCK_REALTIME) + at the point in time the entry + was received by the journal, + in microseconds since the epoch + UTC, formatted as a decimal + string. This has different + properties from + _SOURCE_REALTIME_TIMESTAMP=, + as it is usually a bit later + but more likely to be monotonic. + + + + + + __MONOTONIC_TIMESTAMP= + + The monotonic time + (CLOCK_MONOTONIC) + at the point in time the entry + was received by the journal in + microseconds, formatted as a decimal + string. To be useful as an + address for the entry, this + should be combined with with the + boot ID in _BOOT_ID=. + + + + + + + + See Also + + systemd1, + journalctl1, + journald.conf5, + sd-journal3, + systemd-coredumpctl1, + systemd.directives7 + + + + diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml new file mode 100644 index 0000000..3979647 --- /dev/null +++ b/man/systemd.kill.xml @@ -0,0 +1,216 @@ + + + + + + + + + systemd.kill + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.kill + 5 + + + + systemd.kill + Process killing procedure + configuration + + + + service.service, + socket.socket, + mount.mount, + swap.swap, + scope.scope + + + + Description + + Unit configuration files for services, sockets, + mount points, swap devices and scopes share a subset + of configuration options which define the + killing procedure of processes belonging to the unit. + + This man page lists the configuration options + shared by these five unit types. See + systemd.unit5 + for the common options shared by all unit + configuration files, and + systemd.service5, + systemd.socket5, + systemd.swap5, + systemd.mount5 + and + systemd.scope5 + for more information on the configuration file options + specific to each unit type. + + The kill procedure + configuration options are configured in the [Service], + [Socket], [Mount] or [Swap] section, depending on the + unit type. + + + + Options + + + + + KillMode= + Specifies how + processes of this unit shall be + killed. One of + , + , + , + . + + If set to + , all + remaining processes in the control + group of this unit will be killed on + unit stop (for services: after the + stop command is executed, as + configured with + ExecStop=). If set + to , only the + main process itself is killed. If set + to , the + SIGTERM signal + (see below) is sent to the main + process while the subsequent + SIGKILL signal + (see below) is sent to all remaining + processes of the unit's control + group. If set to + , no process is + killed. In this case, only the stop + command will be executed on unit stop, + but no process be killed + otherwise. Processes remaining alive + after stop are left in their control + group and the control group continues + to exist after stop unless it is + empty. + + Processes will first be + terminated via + SIGTERM (unless + the signal to send is changed via + KillSignal=). Optionally, + this is immediately followed by a + SIGHUP (if + enabled with + SendSIGHUP=). If + then, after a delay (configured via the + TimeoutStopSec= option), + processes still remain, the + termination request is repeated with + the SIGKILL + signal (unless this is disabled via + the SendSIGKILL= + option). See + kill2 + for more + information. + + Defaults to + . + + + + KillSignal= + Specifies which signal + to use when killing a service. This + controls the signal that is sent as + first step of shutting down a unit + (see above), and is usually followed + by SIGKILL (see + above and below). For a list of valid + signals, see + signal7. Defaults + to SIGTERM. + + + + + SendSIGHUP= + Specifies whether to + send SIGHUP to + remaining processes immediately after + sending the signal configured with + KillSignal=. This + is useful to indicate to shells and + shell-like programs that their + connection has been severed. Takes a + boolean value. Defaults to "no". + + + + + SendSIGKILL= + Specifies whether to + send SIGKILL to remaining processes + after a timeout, if the normal + shutdown procedure left processes of + the service around. Takes a boolean + value. Defaults to "yes". + + + + + + + + See Also + + systemd1, + systemctl8, + journalctl8, + systemd.unit5, + systemd.service5, + systemd.socket5, + systemd.swap5, + systemd.mount5, + systemd.exec5, + systemd.directives7, + kill2, + signal7 + + + + diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index d397c89..657cf11 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.mount - systemd mount configuration files + Mount unit configuration - systemd.mount + mount.mount Description A unit configuration file whose name ends in - .mount encodes information about + .mount encodes information about a file system mount point controlled and supervised by systemd. @@ -72,15 +72,29 @@ systemd.exec5, which define the execution environment the mount8 - binary is executed in. + binary is executed in, and in + systemd.kill5, + which define the way the processes are terminated, and + in + systemd.resource-control5, + which configure resource control settings for the + processes of the service. Note that the User= and + Group= options are not particularly useful for mount + units specifying a Type= option or + using configuration not specified in + /etc/fstab; + mount8 + will refuse options that are not listed in + /etc/fstab if it is not run as + UID 0. Mount units must be named after the mount point directories they control. Example: the mount point - /home/lennart must be configured + /home/lennart must be configured in a unit file home-lennart.mount. For details about the escaping logic used to convert a file system - path to a unit name see + path to a unit name, see systemd.unit5. Optionally, a mount unit may be accompanied by @@ -88,42 +102,92 @@ mounting. See systemd.automount5. - If an mount point is beneath another mount point + If a mount point is beneath another mount point in the file system hierarchy, a dependency between both units is created automatically. - Mount points created at runtime independent on - unit files or /etc/fstab will be + Mount points created at runtime (independently of + unit files or /etc/fstab) will be monitored by systemd and appear like any other mount - unit in systemd. + unit in systemd. + See /proc/self/mountinfo description + in proc5. + + + Some file systems have special semantics as API + file systems for kernel-to-userspace and + userspace-to-userpace interfaces. Some of them may not + be changed via mount units, and cannot be disabled. + For a longer discussion see API + File Systems. - <filename>fstab</filename> + <filename>/etc/fstab</filename> Mount units may either be configured via unit files, or via /etc/fstab (see fstab5 - for details). + for details). Mounts listed in + /etc/fstab will be converted into + native units dynamically at boot and when the + configuration of the system manager is reloaded. In + general, configuring mount points through + /etc/fstab is the preferred + approach. See + systemd-fstab-generator8 + for details about the conversion. When reading /etc/fstab a few special mount options are understood by systemd which influence how dependencies are created for mount - points from /etc/fstab. If - is specified as - mount option, then systemd will create a dependency of - type from either + points from /etc/fstab. systemd + will create a dependency of type + from either local-fs.target or remote-fs.target, depending whether the file system is local or remote. If - is set, an - automount unit will be created for the file system. See + is set, an + automount unit will be created for the file + system. See systemd.automount5 - for details. + for details. If + is + specified, it may be used to configure how long systemd + should wait for a device to show up before giving up + on an entry from + /etc/fstab. Specify a time in + seconds or explicitly specify a unit as + s, min, + h, ms. + + If is given, this mount + will be only wanted, not required, by the + local-fs.target. This means that + the boot will continue even if this mount point is not + mounted successfully. Option has + the opposite meaning and is the default. + + If is given, this mount + will not be added as a dependency for + local-fs.target. This means that + it will not be mounted automatically during boot, + unless it is pulled in by some other unit. Option + has the opposite meaning and is + the default. If a mount point is configured in both - /etc/fstab and a unit file, the - configuration in the latter takes precedence. + /etc/fstab and a unit file that + is stored below /usr, the former + will take precedence. If the unit file is stored below + /etc, it will take + precedence. This means: native unit files take + precedence over traditional configuration files, but + this is superseded by the rule that configuration in + /etc will always take precedence + over configuration in + /usr. @@ -134,11 +198,13 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Mount] section of mount units are the following: - + What= @@ -159,17 +225,17 @@ Where= Takes an absolute path of a directory of the mount point. If - the mount point is not existing at + the mount point does not exist at the time of mounting, it is created. This string must be reflected in the unit - file name. (See above.) This option is + filename. (See above.) This option is mandatory. Type= Takes a string for the - filesystem type. See + file system type. See mount8 for details. This setting is optional. @@ -179,8 +245,8 @@ Options= Mount options to use - when mounting. This takes a comma - separated list of options. This + when mounting. This takes a + comma-separated list of options. This setting is optional. @@ -201,55 +267,27 @@ Configures the time to wait for the mount command to finish. If a command does not exit - within the configured time the mount + within the configured time, the mount will be considered failed and be shut down again. All commands still running will be terminated forcibly via - SIGTERM, and after another delay of - this time with SIGKILL. (See - below.) + SIGTERM, and after another delay of + this time with SIGKILL. (See + in + systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout - logic. Defaults to - 90s. - - - - KillMode= - Specifies how - processes of this mount shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - mount. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the mount around. Takes a boolean - value. Defaults to "yes". - + logic. The default value is set from the manager configuration + file's DefaultTimeoutStart= variable. + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. @@ -259,8 +297,14 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.kill5, + systemd.resource-control5, + systemd.service5, systemd.device5, - mount8 + proc5, + mount8, + systemd-fstab-generator8, + systemd.directives7 diff --git a/man/systemd.path.xml b/man/systemd.path.xml index 10d8f73..8d86fca 100644 --- a/man/systemd.path.xml +++ b/man/systemd.path.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.path - systemd path configuration files + Path unit configuration - systemd.path + path.path Description A unit configuration file whose name ends in - .path encodes information about + .path encodes information about a path monitored by systemd, for path-based activation. @@ -84,20 +84,19 @@ used to monitor files or directories changed by other machines on remote NFS file systems. - If an path unit is beneath another mount + If a path unit is beneath another mount point in the file system hierarchy, a dependency between both units is created automatically. - Unless DefaultDependencies= - is set to , path units will - implicitly have dependencies of type - Conflicts= and + Unless DefaultDependencies=false + is used, path units will implicitly have dependencies of + type Conflicts= and Before= on shutdown.target. These ensure that path units are terminated cleanly prior to system shutdown. Only path units involved with early boot or - late system shutdown should disable this - option. + late system shutdown should disable this option. + @@ -108,11 +107,12 @@ monitors. The options specific to the [Path] section of path units are the following: - + PathExists= PathExistsGlob= PathChanged= + PathModified= DirectoryNotEmpty= Defines paths to @@ -120,17 +120,25 @@ PathExists= may be used to watch the mere existence of a file or directory. If the file - specified exists the configured unit + specified exists, the configured unit is activated. PathExistsGlob= works similar, but checks for the - existance of at least one file + existence of at least one file matching the globbing pattern specified. PathChanged= may be used to watch a file or directory and activate the configured - unit whenever it changes or is - modified. DirectoryNotEmpty= + unit whenever it changes. It is not + activated on every write to the + watched file but it is activated if + the file which was open for writing + gets + closed. PathModified= + is similar, but additionally it is + activated also on simple writes to the + watched file. + DirectoryNotEmpty= may be used to watch a directory and activate the configured unit whenever it contains at least one file. @@ -141,9 +149,14 @@ Multiple directives may be combined, of the same and of different - types, to watch multiple paths. - - If a path is already existing + types, to watch multiple paths. If the + empty string is assigned to any of + these options, the list of paths to + watch is reset, and any prior + assignments of these options will not + have any effect. + + If a path already exists (in case of PathExists= and PathExistsGlob=) or @@ -154,11 +167,15 @@ activated, then the configured unit is immediately activated as well. Something similar does not apply - to - PathChanged=. The - latter is not activated on simple - writes but only if files with were - opened for writing are closed. + to PathChanged= and + PathModified=. + + If the path itself or any of the + containing directories are not + accessible, systemd + will watch for permission changes and + notice that conditions are satisfied + when permissions allow that. @@ -168,7 +185,7 @@ when any of the configured paths changes. The argument is a unit name, whose suffix is not - .path. If not + .path. If not specified, this value defaults to a service that has the same name as the path unit, except for the suffix. (See @@ -182,7 +199,7 @@ MakeDirectory= Takes a boolean - argument. If true the directories to + argument. If true, the directories to watch are created before watching. This option is ignored for PathExists= @@ -194,7 +211,7 @@ If MakeDirectory= is - enabled use the mode specified here to + enabled, use the mode specified here to create the directories in question. Takes an access mode in octal notation. Defaults to @@ -210,7 +227,8 @@ systemctl8, systemd.unit5, systemd.service5, - inotify7 + inotify7, + systemd.directives7 diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml new file mode 100644 index 0000000..55cb4de --- /dev/null +++ b/man/systemd.preset.xml @@ -0,0 +1,203 @@ + + + + + + + + systemd.preset + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.preset + 5 + + + + systemd.preset + Service enablement presets + + + + /etc/systemd/system-preset/*.preset + /run/systemd/system-preset/*.preset + /usr/lib/systemd/system-preset/*.preset + /etc/systemd/user-preset/*.preset + /run/systemd/user-preset/*.preset + /usr/lib/systemd/user-preset/*.preset + + + + Description + + Preset files may be used to encode policy which + units shall be enabled by default and which ones + shall be disabled. They are read by systemctl + preset (for more information see + systemctl1) + which uses this information to enable or disable a + unit according to preset policy. systemctl + preset is used by the post install + scriptlets of RPM packages (or other OS package formats), + to enable/disable specific units by default on package + installation, enforcing distribution, spin or + administrator preset policy. This allows choosing a certain + set of units to be enabled/disabled even before + installing the actual package. + + For more information on the preset logic please + have a look at the Presets + document. + + It is not recommended to ship preset files + within the respective software packages implementing + the units, but rather centralize them in a + distribution or spin default policy, which can be + amended by administrator policy. + + If no preset files exist, systemctl + preset will enable all units that are + installed by default. If this is not desired and all + units shall rather be disabled, it is necessary to ship + a preset file with a single, catchall + "disable *" line. (See example 1, + below.) + + + + Preset File Format + + The preset files contain a list of + directives consisting of either the word + enable or + disable followed by a space and a + unit name (possibly with shell style wildcards), + separated by newlines. Empty lines and lines whose + first non-whitespace character is # or ; are + ignored. + + Two different directives are understood: + enable may be used to enable units + by default, disable to disable + units by default. + + If multiple lines apply to a unit name, the + first matching one takes precedence over all + others. + + Each preset file shall be named in the style of + <priority>-<program>.conf. + Files in /etc/ override files + with the same name in /usr/lib/ + and /run/. Files in + /run/ override files with the + same name in /usr/lib/. Packages + should install their preset files in + /usr/lib/. Files in + /etc/ are reserved for the local + administrator, who may use this logic to override the + preset files installed by vendor packages. All preset + files are sorted by their filename in lexicographic + order, regardless of which of the directories they + reside in. If multiple files specify the same unit name, + the entry in the file with the lexicographically earliest + name will be applied. It is recommended to prefix all + filenames with a two-digit number and a dash, to simplify + the ordering of the files. + + If the administrator wants to disable a preset + file supplied by the vendor, the recommended way is to + place a symlink to /dev/null in + /etc/systemd/system-preset/ + bearing the same filename. + + + + Example + + + Default off example <filename>/usr/lib/systemd/system-preset/99-default.preset</filename>: + + disable * + + + This disables all units. Due to the filename + prefix 99-, it will be read last and + hence can easily be overridden by spin or + administrator preset policy or suchlike. + + + A GNOME spin example <filename>/usr/lib/systemd/system-preset/50-gnome.preset</filename>: + + enable gdm.service +enable colord.service +enable accounts-daemon.service +enable avahi-daemon.* + + + + This enables the three mentioned units, plus all + avahi-daemon regardless of which + unit type. A file like this could be useful for + inclusion in a GNOME spin of a distribution. It will + ensure that the units necessary for GNOME are properly + enabled as they are installed. It leaves all other + units untouched, and subject to other (later) preset + files, for example like the one from the first example + above. + + + Administrator policy <filename>/etc/systemd/system-preset/00-lennart.preset</filename>: + + enable httpd.service +enable sshd.service +enable postfix.service +disable * + + + This enables three specific services and + disables all others. This is useful for administrators + to specifically select the units to enable, and + disable all others. Due to the filename prefix + 00- it will be read early and hence + overrides all other preset policy files. + + + + See Also + + systemd1, + systemctl1, + systemd-delta1 + + + + diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml new file mode 100644 index 0000000..e923b6d --- /dev/null +++ b/man/systemd.resource-control.xml @@ -0,0 +1,368 @@ + + + + + + + + + systemd.resource-control + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.resource-control + 5 + + + + systemd.resource-control + Resource control unit settings + + + + + slice.slice, + scope.scope, + service.service, + socket.socket, + mount.mount, + swap.swap + + + + + Description + + Unit configuration files for services, slices, scopes, + sockets, mount points, and swap devices share a subset of + configuration options for resource control of spawned + processes. Internally, this relies on the Control Groups + kernel concept for organizing processes in a hierarchial tree of + named groups for the purpose of resource management. + + This man page lists the configuration options shared by + those six unit types. See + systemd.unit5 + for the common options of all unit configuration files, and + systemd.slice5, + systemd.scope5, + systemd.service5, + systemd.socket5, + systemd.mount5, + and + systemd.swap5 + for more information on the specific unit configuration files. The + resource control configuration options are configured in the + [Slice], [Scope], [Service], [Socket], [Mount], or [Swap] + sections, depending on the unit type. + + See the New + Control Group Interfaces for an introduction on how to make + use of resource control APIs from programs. + + + + Options + + Units of the types listed above can have settings + for resource control configuration: + + + + + CPUAccounting= + + + Turn on CPU usage accounting for this unit. Takes a + boolean argument. Note that turning on CPU accounting for + one unit might also implicitly turn it on for all units + contained in the same slice and for all its parent slices and + the units contained therein. + + + + + CPUShares=weight + + + Assign the specified overall CPU time share weight to + the processes executed. Takes an integer value. This + controls the cpu.shares control group + attribute, which defaults to 1024. For details about this + control group attribute, see sched-design-CFS.txt. + + Implies CPUAccounting=true. + + + + + MemoryAccounting= + + + Turn on process and kernel memory accounting for this + unit. Takes a boolean argument. Note that turning on memory + accounting for one unit might also implicitly turn it on for + all units contained in the same slice and for all its parent + slices and the units contained therein. + + + + + MemoryLimit=bytes + + + Specify the limit on maximum memory usage of the + executed processes. The limit specifies how much process and + kernel memory can be used by tasks in this unit. Takes a + memory size in bytes. If the value is suffixed with K, M, G + or T, the specified memory size is parsed as Kilobytes, + Megabytes, Gigabytes, or Terabytes (with the base 1024), + respectively. This controls the + memory.limit_in_bytes control group + attribute. For details about this control group attribute, + see memory.txt. + + Implies MemoryAccounting=true. + + + + + BlockIOAccounting= + + + Turn on Block IO accounting for this unit. Takes a + boolean argument. Note that turning on block IO accounting + for one unit might also implicitly turn it on for all units + contained in the same slice and all for its parent slices and + the units contained therein. + + + + + BlockIOWeight=weight + + Set the default + overall block IO weight for the + executed processes. Takes a single + weight value (between 10 and 1000) to + set the default block IO weight. This + controls the + blkio.weight + control group attribute, which + defaults to 1000. For details about + this control group attribute, see + blkio-controller.txt. + + Implies + BlockIOAccounting=true. + + + + + BlockIODeviceWeight=device weight + + + Set the per-device overall block IO weight for the + executed processes. Takes a space-separated pair of a file + path and a weight value to specify the device specific + weight value, between 10 and 1000. (Example: "/dev/sda + 500"). The file path may be specified as path to a block + device node or as any other file, in which case the backing + block device of the file system of the file is + determined. This controls the + blkio.weight_device control group + attribute, which defaults to 1000. Use this option multiple + times to set weights for multiple devices. For details about + this control group attribute, see blkio-controller.txt. + + Implies + BlockIOAccounting=true. + + + + + BlockIOReadBandwidth=device bytes + BlockIOWriteBandwidth=device bytes + + + Set the per-device overall block IO bandwidth limit + for the executed processes. Takes a space-separated pair of + a file path and a bandwidth value (in bytes per second) to + specify the device specific bandwidth. The file path may be + a path to a block device node, or as any other file in which + case the backing block device of the file system of the file + is used. If the bandwidth is suffixed with K, M, G, or T, + the specified bandwidth is parsed as Kilobytes, Megabytes, + Gigabytes, or Terabytes, respectively, to the base of + 1000. (Example: + "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This + controls the blkio.read_bps_device and + blkio.write_bps_device control group + attributes. Use this option multiple times to set bandwidth + limits for multiple devices. For details about these control + group attributes, see blkio-controller.txt. + + + Implies + BlockIOAccounting=true. + + + + + DeviceAllow= + + + Control access to specific device nodes by the + executed processes. Takes two space-separated strings: a + device node specifier followed by a combination of + r, w, + m to control + reading, writing, + or creation of the specific device node(s) by the unit + (mknod), respectively. This controls + the devices.allow and + devices.deny control group + attributes. For details about these control group + attributes, see devices.txt. + + The device node specifier is either a path to a device + node in the file system, starting with + /dev/, or a string starting with either + char- or block- + followed by a device group name, as listed in + /proc/devices. The latter is useful to + whitelist all current and future devices belonging to a + specific device group at once. Examples: + /dev/sda5 is a path to a device node, + referring to an ATA or SCSI block + device. char-pts and + char-alsa are specifiers for all pseudo + TTYs and all ALSA sound devices, respectively. + + + + + DevicePolicy=auto|closed|strict + + + + Control the policy for allowing device access: + + + + + + means to only allow types of access that are + explicitly specified. + + + + + + + in addition, allows access to standard pseudo + devices including + /dev/null, + /dev/zero, + /dev/full, + /dev/random, and + /dev/urandom. + + + + + + + + + in addition, allows access to all devices if no + explicit DeviceAllow= is present. + This is the default. + + + + + + + + + Slice= + + + The name of the slice unit to place the unit + in. Defaults to system.slice for all + non-instantiated units of all unit types (except for slice + units themselves see below). Instance units are by default + placed in a subslice of system.slice + that is named after the template name. + + This option may be used to arrange systemd units in a + hierarchy of slices each of which might have resource + settings applied. + + For units of type slice, the only accepted value for + this setting is the parent slice. Since the name of a slice + unit implies the parent slice, it is hence redundant to ever + set this parameter directly for slice units. + + + + + + + + See Also + + systemd1, + systemd.unit5, + systemd.service5, + systemd.slice5, + systemd.scope5, + systemd.socket5, + systemd.mount5, + systemd.swap5, + systemd.directives7, + systemd.special7, + The documentation for control groups and specific controllers in the Linux kernel: + cgroups.txt, + cpuacct.txt, + memory.txt, + blkio-controller.txt. + + + diff --git a/man/systemd.scope.xml b/man/systemd.scope.xml new file mode 100644 index 0000000..e047f4b --- /dev/null +++ b/man/systemd.scope.xml @@ -0,0 +1,100 @@ + + + + + + + + + systemd.scope + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.scope + 5 + + + + systemd.scope + Scope unit configuration + + + + scope.scope + + + + Description + + Scope units are not configured via unit configuration files, + but are only created programmatically using the bus interfaces of + systemd. They are named similar to filenames. A unit whose name + ends in .scope refers to a scope unit. Scopes + units manage a set of system processes. Unlike service units, scope + units manage externally created processes, and do not fork off + processes on its own. + + The main purpose of scope units is grouping worker processes + of a system service for organization and for managing resources. + + systemd-run may + be used to easily launch a command in a new scope unit from the + command line. + + See the New + Control Group Interfaces for an introduction on how to make + use of scope units from programs. + + Unless DefaultDependencies=false + is used, scope units will implicitly have dependencies of + type Conflicts= and + Before= on + shutdown.target. These ensure + that scope units are removed prior to system + shutdown. Only scope units involved with early boot or + late system shutdown should disable this option. + + + + + See Also + + systemd1, + systemd-run1, + systemd.unit5, + systemd.resource-control5, + systemd.service5, + systemd.directives7. + + + + diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 7b6f12d..5b3afb8 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,11 +44,11 @@ systemd.service - systemd service configuration files + Service unit configuration - systemd.service + service.service @@ -72,7 +72,13 @@ Additional options are listed in systemd.exec5, which define the execution environment the commands - are executed in. + are executed in, and in + systemd.kill5, + which define the way the processes of the service are + terminated, and in + systemd.resource-control5, + which configure resource control settings for the + processes of the service. Unless DefaultDependencies= is set to , service units will @@ -95,7 +101,12 @@ .service suffix removed) and dynamically creates a service unit from that script. This is useful for compatibility with - SysV. + SysV. Note that this compatibility is quite + comprehensive but not 100%. For details about the + incompatibilities, see the Incompatibilities + with SysV document. + @@ -107,11 +118,13 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Service] section of service units are the following: - + Type= @@ -121,17 +134,21 @@ , , , - . + or + . If set to (the default - value) it is expected that the process - configured with + value if neither + Type= nor + BusName= are + specified), it is expected that the + process configured with ExecStart= is the main process of the service. In this mode, if the process offers functionality to other processes on - the system its communication channels + the system, its communication channels should be installed before the daemon is started up (e.g. sockets set up by systemd, via socket activation), as @@ -139,68 +156,84 @@ starting follow-up units. If set to - it is + , it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication - channels set up. The child continues + channels are set up. The child continues to run as the main daemon - process. This is the behaviour of + process. This is the behavior of traditional UNIX daemons. If this setting is used, it is recommended to also use the PIDFile= option, so that systemd can identify the main process of the daemon. systemd will - proceed starting follow-up units as - soon as the parent process + proceed with starting follow-up units + as soon as the parent process exits. - Behaviour of + Behavior of is similar - to , however + to ; however, it is expected that the process has to exit before systemd starts follow-up units. RemainAfterExit= is particularly useful for this type of service. - Behaviour of + Behavior of is similar to - , however it is + ; however, it is expected that the daemon acquires a name on the D-Bus bus, as configured by BusName=. systemd - will proceed starting follow-up units - after the D-Bus bus name has been + will proceed with starting follow-up + units after the D-Bus bus name has been acquired. Service units with this option configured implicitly gain dependencies on the dbus.socket - unit. + unit. This type is the default if + BusName= is + specified. - Behaviour of + Behavior of is similar to - , however it is + ; however, it is expected that the daemon sends a notification message via sd_notify3 - or an equivalent call when it finished - starting up. systemd will proceed + or an equivalent call when it has finished + starting up. systemd will proceed with starting follow-up units after this notification message has been sent. If - this option is used + this option is used, NotifyAccess= (see below) should be set to open access to the notification socket provided by systemd. If - NotifyAccess= is not - set, it will implicitly be set to - . + NotifyAccess= is + not set, it will be implicitly set to + . Note that + currently + Type= + will not work if used in combination with + PrivateNetwork=. + + Behavior of + is very similar + to ; however, + actual execution of the service + binary is delayed until all jobs are + dispatched. This may be used to avoid + interleaving of output of shell + services with the status output on the + console. @@ -221,17 +254,17 @@ Takes a boolean value that specifies whether systemd should try to guess the main PID of a service - should if it cannot be determined + if it cannot be determined reliably. This option is ignored unless is set and is unset because for the other types or with an explicitly configured PID - file the main PID is always known. The + file, the main PID is always known. The guessing algorithm might come to incorrect conclusions if a daemon consists of more than one process. If - the main PID cannot be determined + the main PID cannot be determined, failure detection and automatic restarting of a service will not work reliably. Defaults to @@ -259,106 +292,209 @@ BusName= Takes a D-Bus bus - name, where this service is reachable + name that this service is reachable as. This option is mandatory for services where Type= is set to , but its use - is otherwise recommended as well if - the process takes a name on the D-Bus - bus. + is otherwise recommended if the process + takes a name on the D-Bus bus. ExecStart= - Takes a command line - that is executed when this service - shall be started up. The first token - of the command line must be an - absolute file name, then followed by - arguments for the process. It is - mandatory to set this option for all - services. This option may not be - specified more than once, except when + Commands with their + arguments that are executed when this + service is started. For each of the + specified commands, the first argument + must be an absolute and literal path + to an executable. + + When Type is + not , only one + command may be given. When Type=oneshot is - used in which case more than one - ExecStart= line is - accepted which are then invoked one by - one, sequentially in the order they - appear in the unit file. + used, more than one command may be + specified. Multiple command lines may + be concatenated in a single directive + by separating them with semicolons + (these semicolons must be passed as + separate words). Alternatively, this + directive may be specified more than + once with the same effect. + Lone semicolons may be escaped as + \;. If the empty + string is assigned to this option, the + list of commands to start is reset, + prior assignments of this option will + have no effect. - Optionally, if the absolute file - name is prefixed with - @, the second token - will be passed as - argv[0] to the - executed process, followed by the - further arguments specified. If the - first token is prefixed with - - an exit code of - the command normally considered a - failure (i.e. non-zero exit status or - abnormal exit due to signal) is ignored - and considered success. If both - - and - @ are used for the - same command the former must precede - the latter. Unless + Each command line is split on + whitespace, with the first item being + the command to execute, and the + subsequent items being the arguments. + Double quotes ("...") and single + quotes ('...') may be used, in which + case everything until the next + matching quote becomes part of the + same argument. Quotes themselves are + removed after parsing. In addition, a + trailing backslash + (\) may be used to + merge lines. This syntax is intended + to be very similar to shell syntax, + but only the meta-characters and + expansions described in the following + paragraphs are understood. + Specifically, redirection using + <, + <<, + >, and + >>, pipes + using |, and + running programs in the background + using & + and other elements of shell + syntax are not supported. + + + If more than one command is + specified, the commands are invoked + sequentially in the order they appear + in the unit file. If one of the + commands fails (and is not prefixed + with -), other lines + are not executed, and the unit is + considered failed. + + Unless Type=forking is set, the process started via this command line will be considered the - main process of the daemon. The - command line accepts % specifiers as + main process of the daemon. + + The command line accepts + % specifiers as described in - systemd.unit5. + systemd.unit5. + Note that the first argument of the + command line (i.e. the program to + execute) may not include + specifiers. - On top of that basic environment - variable substitution is - supported. Use + Basic environment variable + substitution is supported. Use ${FOO} as part of a - word, or as word of its own on the + word, or as a word of its own, on the command line, in which case it will be replaced by the value of the environment variable including all whitespace it contains, resulting in a - single argument. Use + single argument. Use $FOO as a separate word on the command line, in which case it will be replaced by the value - of the environment variable split up - at whitespace, resulting in no or more - arguments. Note that the first - argument (i.e. the program to execute) - may not be a variable, and must be a - literal and absolute path - name. + of the environment variable split at + whitespace, resulting in zero or more + arguments. To pass a literal dollar + sign, use $$. + Variables whose value is not known at + expansion time are treated as empty + strings. Note that the first argument + (i.e. the program to execute) may not + be a variable. + + Variables to be used in this + fashion may be defined through + Environment= and + EnvironmentFile=. + In addition, variables listed in the + section "Environment variables in + spawned processes" in + systemd.exec5, + which are considered "static + configuration", may be used (this includes + e.g. $USER, but not + $TERM). + + Optionally, if the absolute file + name is prefixed with + @, the second token + will be passed as + argv[0] to the + executed process, followed by the + further arguments specified. If the + absolute filename is prefixed with + -, an exit code of + the command normally considered a + failure (i.e. non-zero exit status or + abnormal exit due to signal) is ignored + and considered success. If both + - and + @ are used, they + can appear in either order. + + Note that this setting does not + directly support shell command + lines. If shell command lines are to + be used, they need to be passed + explicitly to a shell implementation + of some kind. Example: + ExecStart=/bin/sh -c 'dmesg | tac' + Example: + ExecStart=/bin/echo one ; /bin/echo "two two" + This will execute + /bin/echo two + times, each time with one argument: + one and + two two, + respectively. Because two commands are + specified, + Type=oneshot must + be used. + + Example: + ExecStart=/bin/echo / >/dev/null & \; \ +/bin/ls + This will execute + /bin/echo with five + arguments: /, + >/dev/null, + &, + ;, and + /bin/ls. + + Example: + Environment="ONE=one" 'TWO=two two' +ExecStart=/bin/echo $ONE $TWO ${TWO} + This will execute + /bin/echo with four + arguments: one, + two, + two, and + two two. + ExecStartPre= ExecStartPost= Additional commands - that are executed before (resp. after) + that are executed before or after the command in - ExecStart=. Multiple - command lines may be concatenated in a - single directive, by separating them - by semicolons (these semicolons must - be passed as separate words). In that - case, the commands are executed one - after the other, - serially. Alternatively, these - directives may be specified more than - once with the same effect. However, - the latter syntax is not recommended - for compatibility with parsers - suitable for XDG - .desktop files. - Use of these settings is - optional. Specifier and environment - variable substitution is - supported. + ExecStart=, respectively. + Syntax is the same as for + ExecStart=, except + that multiple command lines are allowed + and the commands are executed one + after the other, serially. + + If any of those commands (not + prefixed with -) + fail, the rest are not executed and + the unit is considered failed. + @@ -367,20 +503,23 @@ trigger a configuration reload in the service. This argument takes multiple command lines, following the same - scheme as pointed out for - ExecStartPre= + scheme as described for + ExecStart= above. Use of this setting is optional. Specifier and environment variable substitution is supported here following the same scheme as for - ExecStart=. One - special environment variable is set: - if known $MAINPID is - set to the main process of the - daemon, and may be used for command - lines like the following: - /bin/kill -HUP - $MAINPID. + ExecStart=. + + One additional, special + environment variable is set: if known, + $MAINPID is set to + the main process of the daemon, and + may be used for command lines like the + following: + + /bin/kill -HUP $MAINPID + @@ -389,22 +528,22 @@ stop the service started via ExecStart=. This argument takes multiple command lines, - following the same scheme as pointed - out for - ExecStartPre= + following the same scheme as described + for ExecStart= above. Use of this setting is - optional. All processes remaining for - a service after the commands - configured in this option are run are + optional. After the commands configured + in this option are run, all processes + remaining for a service are terminated according to the KillMode= setting - (see below). If this option is not - specified the process is terminated - right-away when service stop is - requested. Specifier and environment - variable substitution is supported - (including - $MAINPID, see + (see + systemd.kill5). If + this option is not specified, the + process is terminated immediately when + service stop is requested. Specifier + and environment variable substitution + is supported (including + $MAINPID, see above). @@ -412,13 +551,15 @@ ExecStopPost= Additional commands that are executed after the service - was stopped using the commands - configured in - ExecStop=. This + was stopped. This includes cases where + the commands configured in + ExecStop= were used, + where the service does not have any + ExecStop= defined, or + where the service exited unexpectedly. This argument takes multiple command lines, - following the same scheme as pointed - out for - ExecStartPre. Use + following the same scheme as described + for ExecStart. Use of these settings is optional. Specifier and environment variable substitution is @@ -438,75 +579,248 @@ - TimeoutSec= + TimeoutStartSec= Configures the time to - wait for start-up and stop. If a + wait for start-up. If a daemon service does not signal start-up completion within the - configured time the service will be - considered failed and be shut down - again. If a service is asked to stop - but does not terminate in the - specified time it will be terminated - forcibly via SIGTERM, and after - another delay of this time with - SIGKILL. (See + configured time, the service will be + considered failed and will be shut + down again. + Takes a unit-less value in seconds, or a + time span value such as "5min + 20s". Pass 0 to + disable the timeout logic. Defaults to + TimeoutStartSec= from + the manager configuration file, except + when Type=oneshot is + used, in which case the timeout + is disabled by default. + + + + + TimeoutStopSec= + Configures the time to + wait for stop. If a service is asked + to stop, but does not terminate in the + specified time, it will be terminated + forcibly via SIGTERM, + and after another timeout of equal duration + with SIGKILL (see KillMode= - below.) Takes a unit-less value in seconds, or a + in systemd.kill5). + Takes a unit-less value in seconds, or a time span value such as "5min - 20s". Pass 0 to disable the timeout - logic. Defaults to - 90s. + 20s". Pass 0 to disable + the timeout logic. Defaults to + TimeoutStartSec= from the + manager configuration file. + + + + + TimeoutSec= + A shorthand for configuring + both TimeoutStartSec= + and TimeoutStopSec= + to the specified value. + + + + + WatchdogSec= + Configures the + watchdog timeout for a service. The + watchdog is activated when the start-up is + completed. The service must call + sd_notify3 + regularly with WATCHDOG=1 + (i.e. the "keep-alive ping"). If the time + between two such calls is larger than + the configured time, then the service + is placed in a failed state. By + setting Restart= to + or + , the service + will be automatically restarted. The + time configured here will be passed to + the executed service process in the + WATCHDOG_USEC= + environment variable. This allows + daemons to automatically enable the + keep-alive pinging logic if watchdog + support is enabled for the service. If + this option is used, + NotifyAccess= (see + below) should be set to open access to + the notification socket provided by + systemd. If + NotifyAccess= is + not set, it will be implicitly set to + . Defaults to 0, + which disables this + feature. Restart= Configures whether the - main service process shall be - restarted when it exits. Takes one of + service shall be restarted when the + service process exits, is killed, + or a timeout is reached. The service + process may be the main service + process, but it may also be one of the + processes specified with + ExecStartPre=, + ExecStartPost=, + ExecStop=, + ExecStopPost=, or + ExecReload=. + When the death of the process is a + result of systemd operation (e.g. service + stop or restart), the service will not be + restarted. Timeouts include missing + the watchdog "keep-alive ping" + deadline and a service start, reload, + and stop operation timeouts. + + Takes one of , , , - or + , + , or . If set to - (the default) the - service will not be restarted when it - exits. If set to - it will be - restarted only when it exited cleanly, - i.e. terminated with an exit code of - 0. If set to - it will be - restarted only when it exited with an - exit code not equalling 0, or when - terminated by a signal. If set to - it will be - restarted only if it exits due to - reception of an uncaught signal. If - set to the - service will be restarted regardless - whether it exited cleanly or not, or - got terminated abnormally by a - signal. + (the default), the + service will not be restarted. If set to + , it will be + restarted only when the service process + exits cleanly. + In this context, a clean exit means + an exit code of 0, or one of the signals + SIGHUP, + SIGINT, + SIGTERM, + or SIGPIPE, and + additionally, exit statuses and signals + specified in SuccessExitStatus=. + If set to , + the service will be restarted when the + process exits with a non-zero exit code, + is terminated by a signal (including on + core dump), when an operation (such as + service reload) times out, and when the + configured watchdog timeout is triggered. + If set to + , the service + will be restarted only if the service + process exits due to an uncaught + signal not specified as a clean exit + status. + If set to + , the service + will be restarted only if the watchdog + timeout for the service expires. + If set to + , the service + will be restarted regardless of whether + it exited cleanly or not, got + terminated abnormally by a signal, or + hit a timeout. + + In addition to the above settings, + the service will not be restarted if the + exit code or signal is specified in + RestartPreventExitStatus= + (see below). + + + + SuccessExitStatus= + Takes a list of exit + status definitions that when returned + by the main service process will be + considered successful termination, in + addition to the normal successful exit + code 0 and the signals SIGHUP, SIGINT, + SIGTERM, and SIGPIPE. Exit status + definitions can either be numeric exit + codes or termination signal names, + separated by spaces. For example: + SuccessExitStatus=1 2 8 SIGKILL + ensures that exit codes 1, 2, 8 and + the termination signal + SIGKILL are + considered clean service terminations. + + + Note that if a process has a + signal handler installed and exits by + calling + _exit2 + in response to a signal, the + information about the signal is lost. + Programs should instead perform cleanup and kill themselves with the same signal instead. See + Proper handling of SIGINT/SIGQUIT — How to be a proper program. + + This option may appear more than once, + in which case the list of successful + exit statuses is merged. If the empty + string is assigned to this option, the + list is reset, all prior assignments + of this option will have no + effect. + + + + RestartPreventExitStatus= + 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 + Restart=. 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. Example: + RestartPreventExitStatus=1 6 + SIGABRT, ensures that exit + codes 1 and 6 and the termination + signal SIGABRT will + not result in automatic service + restarting. This + option may appear more than once, in + which case the list of restart-preventing + statuses is merged. If the empty + string is assigned to this option, the + list is reset and all prior assignments + of this option will have no + effect. PermissionsStartOnly= Takes a boolean - argument. If true, the permission - related execution options as + argument. If true, the permission-related + execution options, as configured with User= and similar options (see systemd.exec5 - for more information) are only applied + for more information), are only applied to the process started with ExecStart=, and not to the various other ExecStartPre=, ExecStartPost=, ExecReload=, - ExecStop=, + ExecStop=, and ExecStopPost= commands. If false, the setting is applied to all configured commands the @@ -517,19 +831,19 @@ RootDirectoryStartOnly= Takes a boolean - argument. If true, the root directory + argument. If true, the root directory, as configured with the RootDirectory= option (see systemd.exec5 - for more information) is only applied + for more information), is only applied to the process started with ExecStart=, and not to the various other ExecStartPre=, ExecStartPost=, ExecReload=, - ExecStop=, + ExecStop=, and ExecStopPost= commands. If false, the setting is applied to all configured commands the @@ -538,102 +852,15 @@ - SysVStartPriority= - Set the SysV start - priority to use to order this service - in relation to SysV services lacking - LSB headers. This option is only - necessary to fix ordering in relation - to legacy SysV services, that have no - ordering information encoded in the - script headers. As such it should only - be used as temporary compatibility - option, and not be used in new unit - files. Almost always it is a better - choice to add explicit ordering - directives via - After= or - Before=, - instead. For more details see - systemd.unit5. If - used, pass an integer value in the - range 0-99. - - - - KillMode= - Specifies how - processes of this service shall be - killed. One of - , - , - . - - If set to - all - remaining processes in the control - group of this service will be - terminated on service stop, after the - stop command (as configured with - ExecStop=) is - executed. If set to - only the main - process itself is killed. If set to - no process is - killed. In this case only the stop - command will be executed on service - stop, but no process be killed - otherwise. Processes remaining alive - after stop are left in their control - group and the control group continues - to exist after stop unless it is - empty. Defaults to - . - - Processes will first be - terminated via SIGTERM (unless the - signal to send is changed via - KillSignal=). If - then after a delay (configured via the - TimeoutSec= option) - processes still remain, the - termination request is repeated with - the SIGKILL signal (unless this is - disabled via the - SendSIGKILL= - option). See - kill2 - for more - information. - - - - KillSignal= - Specifies which signal - to use when killing a - service. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the service around. Takes a boolean - value. Defaults to "yes". - - - - NonBlocking= - Set O_NONBLOCK flag + Set the + O_NONBLOCK flag for all file descriptors passed via socket-based activation. If true, all file descriptors >= 3 (i.e. all except - STDIN/STDOUT/STDERR) will have - the O_NONBLOCK flag set and hence are in + stdin, stdout, and stderr) will have + the O_NONBLOCK flag + set and hence are in non-blocking mode. This option is only useful in conjunction with a socket unit, as described in @@ -651,19 +878,25 @@ (the default), or . If - no daemon status + , no daemon status updates are accepted from the service processes, all status update messages - are ignored. If + are ignored. If , only service updates sent from the main process of the service are - accepted. If all + accepted. If , all services updates from all members of the service's control group are - accepted. This option must be set to + accepted. This option should be set to open access to the notification socket when using - Type=notify (see above). + Type=notify or + WatchdogSec= (see + above). If those options are used but + NotifyAccess= is not + configured, it will be implicitly set + to + . @@ -671,11 +904,11 @@ Specifies the name of the socket units this service shall inherit the sockets from when the - service (ignoring the different suffix - of course) is started. Normally it + service is started. Normally it should not be necessary to use this setting as all sockets whose unit shares the same name as the service + (ignoring the different suffix of course) are passed to the spawned process. @@ -683,43 +916,148 @@ passed to multiple processes at the same time. Also note that a different service may be activated on incoming - traffic than inherits the sockets. Or - in other words: The + traffic than that which inherits the + sockets. Or in other words: the Service= setting of .socket units - doesn't have to match the inverse of the - Sockets= setting of - the .service it - refers to. + does not have to match the inverse of + the Sockets= + setting of the + .service it + refers to. + + This option may appear more than + once, in which case the list of socket + units is merged. If the empty string + is assigned to this option, the list of + sockets is reset, and all prior uses of + this setting will have no + effect. + + + + StartLimitInterval= + StartLimitBurst= + + Configure service + start rate limiting. By default, + services which are started more + than 5 times within 10 seconds are not + permitted to start any more times + until the 10 second interval ends. With + these two options, this rate limiting + may be modified. Use + StartLimitInterval= + to configure the checking interval (defaults to + DefaultStartLimitInterval= in + manager configuration file, set to 0 to disable + any kind of rate limiting). Use + StartLimitBurst= to + configure how many starts per interval + are allowed (defaults to + DefaultStartLimitBurst= in + manager configuration file). These + configuration options are particularly + useful in conjunction with + Restart=; however, + they apply to all kinds of starts + (including manual), not just those + triggered by the + Restart= logic. + Note that units which are configured + for Restart= and + which reach the start limit are not + attempted to be restarted anymore; + however, they may still be restarted + manually at a later point, from which + point on, the restart logic is again + activated. Note that + systemctl + reset-failed will cause the + restart rate counter for a service to + be flushed, which is useful if the + administrator wants to manually start + a service and the start limit + interferes with + that. + + + + StartLimitAction= + + Configure the action + to take if the rate limit configured + with + StartLimitInterval= + and + StartLimitBurst= is + hit. Takes one of + , + , + , or + . If + is set, + hitting the rate limit will trigger no + action besides that the start will not + be permitted. + causes a reboot following the normal + shutdown procedure (i.e. equivalent to + systemctl reboot). + causes + a forced reboot which will terminate + all processes forcibly but should + cause no dirty file systems on reboot + (i.e. equivalent to systemctl + reboot -f) and + + causes immediate execution of the + reboot2 + system call, which might result in + data loss. Defaults to + . + + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. + + + + + Compatibility Options + + The following options are also available in the + [Service] section, but exist purely + for compatibility reasons and should not be used in + newly written service files. + + - FsckPassNo= - Set the fsck passno + SysVStartPriority= + Set the SysV start priority to use to order this service - in relation to other file system - checking services. This option is only + in relation to SysV services lacking + LSB headers. This option is only necessary to fix ordering in relation - to fsck jobs automatically created for - all /etc/fstab - entries with a value in the fs_passno - column > 0. As such it should only be - used as option for fsck - services. Almost always it is a better + to legacy SysV services that have no + ordering information encoded in the + script headers. As such, it should only + be used as a temporary compatibility + option and should not be used in new unit + files. Almost always, it is a better choice to add explicit ordering directives via After= or Before=, - instead. For more details see - systemd.unit5. If - used, pass an integer value in the - same range as - /etc/fstab's - fs_passno column. See - fstab5 - for details. + instead. For more details, see + systemd.unit5. + If used, pass an integer value in the + range 0-99. - @@ -729,7 +1067,10 @@ systemd1, systemctl8, systemd.unit5, - systemd.exec5 + systemd.exec5, + systemd.resource-control5, + systemd.kill5, + systemd.directives7 diff --git a/man/systemd.slice.xml b/man/systemd.slice.xml new file mode 100644 index 0000000..4d27ddf --- /dev/null +++ b/man/systemd.slice.xml @@ -0,0 +1,121 @@ + + + + + + + + + systemd.slice + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.slice + 5 + + + + systemd.slice + Slice unit configuration + + + + slice.slice + + + + Description + + A unit configuration file whose name ends in + .slice encodes information about a slice which + is a concept for hierarchially managing resources of a group of + processes. This management is performed by creating a node in the + Linux Control Group (cgroup) tree. Units that manage processes + (primarilly scope and service units) may be assigned to a specific + slice. For each slice, certain resource limits may the be set that + apply to all processes of all units contained in that + slice. Slices are organized hierarchially in a tree. The name of + the slice encodes the location in the tree. The name consists of a + dash-separated series of names, which describes the path to the + slice from the root slice. The root slice is named, + -.slice. Example: + foo-bar.slice is a slice that is located + within foo.slice, which in turn is located in + the root slice -.slice. + + + By default, service and scope units are placed in + system.slice, virtual machines and containers + registered with + systemd-machined1 + are found in machine.slice, and user sessions + handled by + systemd-logind1 + in user.slice. See + systemd.special5 + for more information. + + See + systemd.unit5 + for the common options of all unit configuration + files. The common configuration items are configured + in the generic [Unit] and [Install] sections. The + slice specific configuration options are configured in + the [Slice] section. Currently, only generic resource control settings + as described in + systemd.resource-control7 are allowed. + + + Unless DefaultDependencies=false + is used, slice units will implicitly have dependencies of + type Conflicts= and + Before= on + shutdown.target. These ensure + that slice units are removed prior to system + shutdown. Only slice units involved with early boot or + late system shutdown should disable this option. + + + + + See Also + + systemd1, + systemd.unit5, + systemd.resource-control5, + systemd.service5, + systemd.scope5, + systemd.special7, + systemd.directives7 + + + + diff --git a/man/systemd.snapshot.xml b/man/systemd.snapshot.xml index a3e2322..1bb074a 100644 --- a/man/systemd.snapshot.xml +++ b/man/systemd.snapshot.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,11 +44,11 @@ systemd.snapshot - systemd snapshot units + Snapshot unit configuration - systemd.snapshot + snapshot.snapshot @@ -56,8 +56,8 @@ Snapshot units are not configured via unit configuration files. Nonetheless they are named - similar to filenames. A unit name whose name ends in - .snapshot refers to a dynamic + similar to filenames. A unit whose name ends in + .snapshot refers to a dynamic snapshot of the systemd runtime state. Snapshots are not configured on disk but created @@ -80,7 +80,8 @@ systemd1, systemctl8, - systemd.unit5 + systemd.unit5, + systemd.directives7 diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 28c8dc4..d645de4 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.socket - systemd socket configuration files + Socket unit configuration - systemd.socket + socket.socket Description A unit configuration file whose name ends in - .socket encodes information about + .socket encodes information about an IPC or network socket or a file system FIFO controlled and supervised by systemd, for socket-based activation. @@ -75,25 +75,36 @@ , , and - commands are executed - in. - - For each socket file a matching service file - (see + commands are executed + in, and in + systemd.kill5, + which define the way the processes are terminated, and + in + systemd.resource-control5, + which configure resource control settings for the + processes of the socket. + + For each socket file, a matching service file + must exist, describing the service to start on + incoming traffic on the socket (see systemd.service5 - for details) must exist, describing the service to - start on incoming traffic on the socket. Depending on - the setting of (see below), - this must either be named like the socket unit, but - with the suffix replaced; or it must be a template - file named the same way. Example: a socket file + for more information about .service files). The name + of the .service unit is by default the same as the + name of the .socket unit, but can be altered with the + option described below. + Depending on the setting of the + option described below, this .service unit must either + be named like the .socket unit, but with the suffix + replaced, unless overridden with + ; or it must be a template + unit named the same way. Example: a socket file foo.socket needs a matching service foo.service if is set. If - is set a service template - file foo@.service must exist from - which services are instantiated for each incoming - connection. + is set, a service + template file foo@.service must + exist from which services are instantiated for each + incoming connection. Unless DefaultDependencies= is set to , socket units will @@ -110,9 +121,21 @@ boot or late system shutdown should disable this option. + Socket units will have a + Before= dependency on the service + which they trigger added implicitly. No implicit + WantedBy= or + RequiredBy= dependency from the + socket to the service is added. This means that the + service may be started without the socket, in which + case it must be able to open sockets by itself. To + prevent this, an explicit Requires= + dependency may be added. + Socket units may be used to implement on-demand starting of services, as well as parallelized starting - of services. + of services. See the blog stories linked at the end + for an introduction. Note that the daemon software configured for socket activation with socket units needs to be able @@ -121,8 +144,8 @@ sd_listen_fds3 for details) or via the traditional inetd8-style - socket passing (i.e. sockets passed in via STDIN and - STDOUT, using StandardInput=socket + socket passing (i.e. sockets passed in via standard input and + output, using StandardInput=socket in the service file). @@ -134,75 +157,105 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Socket] section of socket units are the following: - + ListenStream= ListenDatagram= ListenSequentialPacket= Specifies an address to listen on for a stream - (SOCK_STREAM), datagram (SOCK_DGRAM) - resp. sequential packet - (SOCK_SEQPACKET) socket. The address + (SOCK_STREAM), datagram (SOCK_DGRAM), + or sequential packet + (SOCK_SEQPACKET) socket, respectively. The address can be written in various formats: If the address starts with a - slash (/), it is read as file system - socket in the AF_UNIX socket + slash (/), it is read as file system + socket in the AF_UNIX socket family. - If the address starts with an - ampersand (@) it is read as abstract - namespace socket in the AF_UNIX - family. The @ is replaced with a NUL - character before binding. For details - see + If the address starts with an at + symbol (@), it is read as abstract + namespace socket in the + AF_UNIX + family. The @ is + replaced with a + NUL character + before binding. For details, see unix7. If the address string is a - single number it is read as port - number to listen on for both IPv4 and - IPv6. + single number, it is read as port + number to listen on via + IPv6. Depending on the value of + BindIPv6Only= (see below) this + might result in the service being + available via both IPv6 and IPv4 (default) or + just via IPv6. + If the address string is a - string in the format v.w.x.y:z it is + string in the format v.w.x.y:z, it is read as IPv4 specifier for listening on an address v.w.x.y on a port z. If the address string is a - string in the format [x]:y it is read - as IPv6 address x on a port y. - - Note that SOCK_SEQPACKET + string in the format [x]:y, it is read + as IPv6 address x on a port y. Note + that this might make the service + available via IPv4, too, depending on + the BindIPv6Only= + setting (see below). + + + Note that SOCK_SEQPACKET (i.e. ListenSequentialPacket=) - is only available for AF_UNIX - sockets. SOCK_STREAM + is only available for AF_UNIX + sockets. SOCK_STREAM (i.e. ListenStream=) when used for IP sockets refers to TCP - sockets, SOCK_DGRAM + sockets, SOCK_DGRAM (i.e. ListenDatagram=) to UDP. These options may be specified more than once in which case incoming - traffic on any of the sockets will trigger - service activation, and all listed - sockets will be passed to the service, - regardless whether there is incoming - traffic on them or not. - - If an IP address is used here, it - is often desirable to listen on it + traffic on any of the sockets will + trigger service activation, and all + listed sockets will be passed to the + service, regardless of whether there is + incoming traffic on them or not. If + the empty string is assigned to any of + these options, the list of addresses + to listen on is reset, all prior uses + of any of these options will have no + effect. + + It is also possible to have more + than one socket unit for the same + service when using + Service=, and the + service will receive all the sockets + configured in all the socket units. + Sockets configured in one unit are + passed in the order of configuration, + but no ordering between socket units + is specified. + + If an IP address is used here, + it is often desirable to listen on it before the interface it is configured on is up and running, and even - regardless whether it will be up and - running ever at all. To deal with this it is - recommended to set the + regardless of whether it will be up and + running at any point. To deal with this, + it is recommended to set the FreeBind= option described below. @@ -212,7 +265,7 @@ Specifies a file system FIFO to listen on. This expects an absolute file system path as - argument. Behaviour otherwise is very + argument. Behavior otherwise is very similar to the ListenDatagram= directive above. @@ -223,7 +276,7 @@ Specifies a special file in the file system to listen on. This expects an absolute file - system path as argument. Behaviour + system path as argument. Behavior otherwise is very similar to the ListenFIFO= directive above. Use this to open @@ -238,12 +291,12 @@ Specifies a Netlink family to create a socket for to listen on. This expects a short string - referring to the AF_NETLINK family + referring to the AF_NETLINK family name (such as audit or kobject-uevent) as argument, optionally suffixed by a whitespace followed by a multicast - group integer. Behaviour otherwise is + group integer. Behavior otherwise is very similar to the ListenDatagram= directive above. @@ -254,7 +307,7 @@ Specifies a POSIX message queue name to listen on. This expects a valid message queue name - (i.e. beginning with /). Behaviour + (i.e. beginning with /). Behavior otherwise is very similar to the ListenFIFO= directive above. On Linux message @@ -278,10 +331,13 @@ , they will be accessible via IPv6 only. If (which is the - default, surprise!) the system wide + default, surprise!), the system wide default setting is used, as controlled by - /proc/sys/net/ipv6/bindv6only. + /proc/sys/net/ipv6/bindv6only, + which in turn defaults to the + equivalent of + . @@ -302,7 +358,7 @@ BindToDevice= Specifies a network interface name to bind this socket - to. If set traffic will only be + to. If set, traffic will only be accepted from the specified network interfaces. This controls the SO_BINDTODEVICE socket option (see @@ -318,7 +374,7 @@ DirectoryMode= If listening on a file - system socket of FIFO, the parent + system socket or FIFO, the parent directories are automatically created if needed. This option specifies the file system access mode used when @@ -331,7 +387,7 @@ SocketMode= If listening on a file - system socket of FIFO, this option + system socket or FIFO, this option specifies the file system access mode used when creating the file node. Takes an access mode in octal @@ -351,17 +407,30 @@ and only one service unit is spawned for all connections (also see above). This value is ignored for - datagram sockets and FIFOs where - a single service unit unconditionally + datagram sockets and FIFOs where a + single service unit unconditionally handles all incoming traffic. Defaults to . For performance reasons, it is recommended to write new daemons only in a way that is suitable for - . This - option is mostly useful to allow - daemons designed for usage with - inetd8, + . A + daemon listening on an AF_UNIX socket + may, but does not need to, call + close2 + on the received socket before + exiting. However, it must not unlink + the socket from a file system. It + should not invoke + shutdown2 + on sockets it got with + Accept=false, but + it may do so for sockets it got with + Accept=true set. + Setting Accept=true + is mostly useful to allow daemons + designed for usage with + inetd8 to work unmodified with systemd socket activation. @@ -376,8 +445,8 @@ are coming in, they will be refused until at least one existing connection is terminated. This setting has no - effect for sockets configured with - or datagram + effect on sockets configured with + or datagram sockets. Defaults to 64. @@ -415,12 +484,15 @@ ReceiveBuffer= SendBuffer= Takes an integer - argument controlling the receive - resp. send buffer sizes of this - socket. This controls the SO_RCVBUF - resp. SO_SNDBUF socket options (see + argument controlling the receive or + send buffer sizes of this socket, + respectively. This controls the + SO_RCVBUF and SO_SNDBUF socket options + (see socket7 - for details.). + for details.). The usual suffixes K, + M, G are supported and are understood + to the base of 1024. @@ -467,13 +539,46 @@ + ReusePort= + Takes a boolean + value. If true, allows multiple bind2s + to this TCP or UDP port. This + controls the SO_REUSEPORT socket + option. See + socket7 + for details. + + + + SmackLabel= + SmackLabelIPIn= + SmackLabelIPOut= + Takes a string + value. Controls the extended + attributes + security.SMACK64, + security.SMACK64IPIN + and + security.SMACK64IPOUT, + respectively, i.e. the security label + of the FIFO, or the security label for + the incoming or outgoing connections + of the socket, respectively. See + Smack.txt + for details. + + + PipeSize= - Takes an integer - value. Controls the pipe buffer size + Takes an size in + bytes. Controls the pipe buffer size of FIFOs configured in this socket - unit. See + unit. See fcntl2 - for details. + for details. The usual suffixes K, M, + G are supported and are understood to + the base of 1024. @@ -481,7 +586,7 @@ MessageQueueMessageSize= These two settings take integer values and control the - mq_maxmsg resp. mq_msgsize field when + mq_maxmsg field or the mq_msgsize field, respectively, when creating the message queue. Note that either none or both of these variables need to be set. See @@ -510,7 +615,7 @@ Transparent= Takes a boolean value. Controls the IP_TRANSPARENT - option. Defaults to + socket option. Defaults to . @@ -518,13 +623,35 @@ Broadcast= Takes a boolean value. This controls the SO_BROADCAST - option, which allows broadcast + socket option, which allows broadcast datagrams to be sent from this socket. Defaults to . + PassCredentials= + Takes a boolean + value. This controls the SO_PASSCRED + socket option, which allows AF_UNIX sockets to + receive the credentials of the sending + process in an ancillary message. + Defaults to + . + + + + PassSecurity= + Takes a boolean + value. This controls the SO_PASSSEC + socket option, which allows AF_UNIX + sockets to receive the security + context of the sending process in an + ancillary message. Defaults to + . + + + TCPCongestion= Takes a string value. Controls the TCP congestion @@ -541,10 +668,10 @@ ExecStartPost= Takes one or more command lines, which are executed - before (resp. after) the listening + before or after the listening sockets/FIFOs are created and - bound. The first token of the command - line must be an absolute file name, + bound, respectively. The first token of the command + line must be an absolute filename, then followed by arguments for the process. Multiple command lines may be specified following the same scheme as @@ -557,9 +684,9 @@ ExecStopPre= ExecStopPost= Additional commands - that are executed before (resp. after) + that are executed before or after the listening sockets/FIFOs are closed - and removed. Multiple command lines + and removed, respectively. Multiple command lines may be specified following the same scheme as used for ExecStartPre= of @@ -579,63 +706,38 @@ will be considered failed and be shut down again. All commands still running, will be terminated forcibly via - SIGTERM, and after another delay of - this time with SIGKILL. (See - below.) + SIGTERM, and after another delay of + this time with SIGKILL. (See + in systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout - logic. Defaults to - 90s. - - - - KillMode= - Specifies how - processes of this socket unit shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - socket. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the socket around. Takes a boolean - value. Defaults to "yes". - + logic. Defaults to TimeoutStartSec= from the + manager configuration file. Service= Specifies the service unit name to activate on incoming - traffic. This defaults to the service - that bears the same name as the socket - (ignoring the different suffixes). In - most cases it should not be necessary - to use this option. + traffic. This setting is only allowed + for sockets with + Accept=no. It + defaults to the service that bears the + same name as the socket (with the + suffix replaced). In most cases, it + should not be necessary to use this + option. + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. + @@ -645,7 +747,18 @@ systemctl8, systemd.unit5, systemd.exec5, - systemd.service5 + systemd.kill5, + systemd.resource-control5, + systemd.service5, + systemd.directives7 + + + + For more extensive descriptions see the "systemd for Developers" series: + Socket Activation, + Socket Activation, part II, + Converting inetd Services, + Socket Activated Internet Services and OS Containers. diff --git a/man/systemd.special.xml b/man/systemd.special.xml new file mode 100644 index 0000000..8ccccc2 --- /dev/null +++ b/man/systemd.special.xml @@ -0,0 +1,1100 @@ + + + + + + + + + systemd.special + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.special + 7 + + + + systemd.special + Special systemd units + + + + basic.target, + bluetooth.target, + ctrl-alt-del.target, + cryptsetup.target, + dbus.service, + dbus.socket, + default.target, + display-manager.service, + emergency.target, + exit.target, + final.target, + getty.target, + graphical.target, + halt.target, + hibernate.target, + hybrid-sleep.target, + initrd-fs.target, + kbrequest.target, + kexec.target, + local-fs.target, + local-fs-pre.target, + multi-user.target, + network.target, + network-online.target, + nss-lookup.target, + nss-user-lookup.target, + paths.target, + poweroff.target, + printer.target, + reboot.target, + remote-fs.target, + remote-fs-pre.target, + rescue.target, + initrd-root-fs.target, + rpcbind.target, + runlevel2.target, + runlevel3.target, + runlevel4.target, + runlevel5.target, + shutdown.target, + sigpwr.target, + sleep.target, + smartcard.target, + sockets.target, + sound.target, + suspend.target, + swap.target, + sysinit.target, + syslog.socket, + system-update.target, + time-sync.target, + timers.target, + umount.target, + -.slice, + system.slice, + user.slice, + machine.slice + + + + Description + + A few units are treated specially by + systemd. They have special internal semantics and + cannot be renamed. + + + + Special System Units + + + + basic.target + + A special target unit + covering basic boot-up. + systemd automatically + adds dependencies of the types + Requires= + and After= + for this target unit to all + services (except for those + with + DefaultDependencies=no). + + Usually this should + pull-in all mount points, swap + devices, sockets, timers, and + path units and other basic + initialization necessary for + general purpose + daemons. + + + + ctrl-alt-del.target + + systemd starts this + target whenever + Control+Alt+Del is pressed on + the console. Usually this + should be aliased (symlinked) + to + reboot.target. + + + + cryptsetup.target + + A target that pulls in + setup services for all + encrypted block + devices. + + + + dbus.service + + A special unit for the + D-Bus bus daemon. As soon as + this service is fully started + up systemd will connect to it + and register its + service. + + + + dbus.socket + + A special unit for the + D-Bus system bus socket. All + units with + Type=dbus + automatically gain a + dependency on this + unit. + + + + default.target + + The default unit systemd + starts at bootup. Usually this + should be aliased (symlinked) + to + multi-user.target + or + graphical.target. + + The default unit systemd + starts at bootup can be + overridden with the + systemd.unit= + kernel command line option. + + + + display-manager.service + + The display manager + service. Usually this should + be aliased (symlinked) to + gdm.service + or a similar display manager + service. + + + + emergency.target + + A special target unit + that starts an emergency + shell on the main + console. This unit is supposed + to be used with the kernel + command line option + systemd.unit= + and has otherwise little use. + + + + + final.target + + A special target unit + that is used during the + shutdown logic and may be used + to pull in late services after + all normal services are + already terminated and all + mounts unmounted. + + + + + getty.target + + A special target unit + that pulls in statically + configured local TTY + getty + instances. + + + + + graphical.target + + A special target unit + for setting up a graphical + login screen. This pulls in + multi-user.target. + + Units that are needed + for graphical logins shall add + Wants= + dependencies for their unit to + this unit (or + multi-user.target) + during installation. This is + best configured via + WantedBy=graphical.target + in the unit's + [Install] + section. + + + + hibernate.target + + A special target unit + for hibernating the + system. This pulls in + sleep.target. + + + + hybrid-sleep.target + + A special target unit + for hibernating and suspending the + system at the same time. This pulls in + sleep.target. + + + + halt.target + + A special target unit + for shutting down and halting + the system. Note that this + target is distinct from + poweroff.target + in that it generally really + just halts the system rather + than powering it down. + + Applications wanting to + halt the system should start + this unit. + + + + initrd-fs.target + + systemd-fstab-generator3 + automatically adds + dependencies of type + Before= to + sysroot-usr.mount + and all mount points found in + /etc/fstab + that have the + and + + mount options set. + + + + + kbrequest.target + + systemd starts this + target whenever Alt+ArrowUp is + pressed on the console. This + is a good candidate to be + aliased (symlinked) to + rescue.target. + + + + kexec.target + + A special target unit + for shutting down and rebooting the system via kexec. + + Applications wanting to + reboot the system with kexec should start + this unit. + + + + local-fs.target + + systemd-fstab-generator3 + automatically adds + dependencies of type + Before= to + all mount units that refer to + local mount points for this + target unit. In addition, it + adds dependencies of type + Wants= to + this target unit for those + mounts listed in + /etc/fstab + that have the + mount + option set. + + + + multi-user.target + + A special target unit + for setting up a multi-user + system (non-graphical). This + is pulled in by + graphical.target. + + Units that are needed + for a multi-user system shall + add Wants= + dependencies for their unit to + this unit during + installation. This is best + configured via + WantedBy=multi-user.target + in the unit's + [Install] + section. + + + + network-online.target + + Units that strictly + require a configured network + connection should pull in + network-online.target + (via a + Wants= type + dependency) and order + themselves after it. This + target unit is intended to + pull in a service that delays + further execution until the + network is sufficiently set + up. What precisely this + requires is left to the + implementation of the network + managing service. + + Note the distinction + between this unit and + network.target. This + unit is an active unit + (i.e. pulled in by the + consumer rather than the + provider of this + functionality) and pulls in a + service which possibly adds + substantial delays to further + execution. In contrast, + network.target + is a passive unit (i.e. pulled + in by the provider of the + functionality, rather than the + consumer) that usually does + not delay execution + much. Usually, + network.target + is part of the boot of most + systems, while + network-online.target + is not, except when at least + one unit requires it. Also see + Running + Services After the Network is + up for more + information. + + All mount units for + remote network file systems + automatically pull in this + unit, and order themselves + after it. Note that networking + daemons that simply provide + functionality to other hosts + generally do not need to pull + this in. + + + + paths.target + + A special target unit + that sets up all path units + (see + systemd.path5 + for details) that shall be + active after boot. + + It is recommended that + path units installed by + applications get pulled in via + Wants= + dependencies from this + unit. This is best configured + via a + WantedBy=paths.target + in the path unit's + [Install] + section. + + + + poweroff.target + + A special target unit + for shutting down and powering off the system. + + Applications wanting to + power off the system should start + this unit. + + runlevel0.target + is an alias for this target + unit, for compatibility with SysV. + + + + reboot.target + + A special target unit + for shutting down and rebooting the system. + + Applications wanting to + reboot the system should start + this unit. + + runlevel6.target + is an alias for this target + unit, for compatibility with SysV. + + + + remote-fs.target + + Similar to + local-fs.target, + but for remote mount + points. + + systemd automatically + adds dependencies of type + After= for + this target unit to all SysV + init script service units with + an LSB header referring to the + $remote_fs + facility. + + + + rescue.target + + A special target unit + for setting up the base system + and a rescue shell. + + runlevel1.target + is an alias for this target + unit, for compatibility with SysV. + + + + initrd-root-fs.target + + systemd-fstab-generator3 + automatically adds + dependencies of type + Before= to + the + sysroot.mount + unit, which is generated from + the kernel command line. + + + + + runlevel2.target + runlevel3.target + runlevel4.target + runlevel5.target + + These are targets that + are called whenever the SysV + compatibility code asks for + runlevel 2, 3, 4, 5, + respectively. It is a good + idea to make this an alias for + (i.e. symlink to) + multi-user.target + (for runlevel 2) or + graphical.target + (the others). + + + + shutdown.target + + A special target unit + that terminates the services + on system shutdown. + + Services that shall be + terminated on system shutdown + shall add Conflicts= + dependencies to this unit for + their service unit, which is + implicitly done when + DefaultDependencies=yes + is set (the default). + + + + sigpwr.target + + A special target that is + started when systemd receives + the SIGPWR process signal, + which is normally sent by the + kernel or UPS daemons when + power fails. + + + + sleep.target + + A special target unit + that is pulled in by + suspend.target, + hibernate.target + and + hybrid-sleep.target + and may be used to hook units + into the sleep state + logic. + + + + sockets.target + + A special target unit + that sets up all socket + units.(see + systemd.socket5 + for details) that shall be + active after boot. + + Services that can be + socket-activated shall add + Wants= + dependencies to this unit for + their socket unit during + installation. This is best + configured via a + WantedBy=sockets.target + in the socket unit's + [Install] + section. + + + + suspend.target + + A special target unit + for suspending the + system. This pulls in + sleep.target. + + + + swap.target + + Similar to + local-fs.target, but for swap + partitions and swap + files. + + + + sysinit.target + + A special target unit + covering early boot-up scripts. + + + + syslog.socket + + The socket unit + syslog implementations should + listen on. All userspace log + messages will be made + available on this socket. For + more information about syslog + integration, please consult + the Syslog + Interface + document. + + + + system-update.target + + A special target unit + that is used for off-line + system updates. + systemd-system-update-generator8 + will redirect the boot process + to this target if + /system-update + exists. For more information + see the System + Updates + Specification. + + + + timers.target + + A special target unit + that sets up all timer + units (see + systemd.timer5 + for details) that shall be + active after boot. + + It is recommended that + timer units installed by + applications get pulled in via + Wants= + dependencies from this + unit. This is best configured + via + WantedBy=timers.target + in the timer unit's + [Install] + section. + + + + umount.target + + A special target unit + that umounts all mount and + automount points on system + shutdown. + + Mounts that shall be + unmounted on system shutdown + shall add Conflicts + dependencies to this unit for + their mount unit, which is + implicitly done when + DefaultDependencies=yes + is set (the default). + + + + + + + + Special System Units for Devices + + Some target units are automatically pulled in as + devices of certain kinds show up in the system. These + may be used to automatically activate various services + based on the specific type of the available + hardware. + + + + bluetooth.target + + This target is started + automatically as soon as a + Bluetooth controller is + plugged in or becomes + available at boot. + + This may be used to pull + in Bluetooth management + daemons dynamically when + Bluetooth hardware is + found. + + + + printer.target + + This target is started + automatically as soon as a + printer is plugged in or + becomes available at + boot. + + This may be used to pull + in printer management + daemons dynamically when + printer hardware is + found. + + + + smartcard.target + + This target is started + automatically as soon as a + smartcard controller is + plugged in or becomes + available at boot. + + This may be used to pull + in smartcard management + daemons dynamically when + smartcard hardware is + found. + + + + sound.target + + This target is started + automatically as soon as a + sound card is plugged in or + becomes available at + boot. + + This may be used to pull + in audio management daemons + dynamically when audio + hardware is found. + + + + + + + Special Passive System Units + + A number of special system targets are defined + that can be used to properly order boot-up of optional + services. These targets are generally not part of the + initial boot transaction, unless they are explicitly + pulled in by one of the implementing services. Note + specifically that these passive + target units are generally not pulled in by the + consumer of a service, but by the provider of the + service. This means: a consuming service should order + itself after these targets (as appropriate), but not + pull it in. A providing service should order itself + before these targets (as appropriate) and pull it in + (via a Wants= type + dependency). + + Note that these passive units cannot be started + manually, i.e. systemctl start + time-sync.target will fail with an + error. They can only be pulled in by dependency. This + is enforced since they exist for ordering purposes + only and thus are not useful as only unit within a + transaction. + + + + local-fs-pre.target + + This target unit is + automatically ordered before + all local mount points marked + with + (see above). It can be used to + execute certain units before + all local mounts. + + + + network.target + + This unit is supposed to + indicate when network + functionality is available, + but it is only very weakly + defined what that is supposed + to mean, with one exception: + at shutdown, a unit that is + ordered after + network.target + will be stopped before the + network -- to whatever level + it might be set up then -- is + shut down. Also see Running + Services After the Network is + up for more + information. Also see + network-online.target + described above. + + systemd automatically + adds dependencies of type + After= for + this target unit to all SysV + init script service units with + an LSB header referring to the + $network + facility. + + + + + nss-lookup.target + + A target that should be + used as synchronization point + for all host/network name + service lookups. Note that + this is independent of + user/group name lookups for + which + nss-user-lookup.target + should be used. systemd + automatically adds + dependencies of type + After= for + this target unit to all SysV + init script service units with + an LSB header referring to the + $named + facility. + + + + nss-user-lookup.target + + A target that should be + used as synchronization point + for all user/group name + service lookups. Note that + this is independent of + host/network name lookups for + which + nss-lookup.target + should be used. + + + + remote-fs-pre.target + + This target unit is + automatically ordered before + all remote mount point units + (see above). It can be used to + run certain units before the + remote mounts are + established. Note that this + unit is generally not part of + the initial transaction, + unless the unit that wants to + be ordered before all remote + mounts pulls it in via a + Wants= type + dependency. If the unit wants + to be pulled in by the first + remote mount showing up, it + should use + network-online.target + (see above). + + Again, this target unit + is not + suitable for pulling in other + units, it is only useful for + ordering. + + + + rpcbind.target + + systemd automatically + adds dependencies of type + After= for + this target unit to all SysV + init script service units with + an LSB header referring to the + $portmap + facility. + + + + time-sync.target + + systemd automatically + adds dependencies of type + After= for + this target unit to all SysV + init script service units with + an LSB header referring to the + $time + facility. + + + + + + + Special User Units + + When systemd runs as a user instance, the + following special units are available, which have + similar definitions as their system counterparts: + default.target, + shutdown.target, + sockets.target, + timers.target, + paths.target, + bluetooth.target, + printer.target, + smartcard.target, + sound.target. + + In addition, the following special unit is + understood only when systemd runs as service instance: + + + + exit.target + + A special service unit + for shutting down the + user service manager. + + Applications wanting to + terminate the user service + manager should start this + unit. If systemd receives + SIGTERM or SIGINT when running + as user service daemon, it will + start this unit. + + Normally, this pulls in + shutdown.target + which in turn should be + conflicted by all units that + want to be shut down on + user service manager exit. + + + + + + + Special Slice Units + + There are four .slice units + which form the basis of the hierarchy for assignment + of resources for services, users, and virtual machines + or containers. + + + + -.slice + + The root slice is the + root of the hierarchy. It + usually does not contain units + directly, but may be used to + set defaults for the whole + tree. + + + + + system.slice + + By default, all services + services started by + systemd are + found in this slice. + + + + + user.slice + + By default, all user + processes and services started + on behalf of the user, + including the per-user systemd + instance are found in this + slice. + + + + + machine.slice + + By defalt, all virtual + machines and containers + registered with + systemd-machined + are found in this slice. + + + + + + + + See Also + + systemd1, + systemd.unit5, + systemd.service5, + systemd.socket5, + systemd.target5, + systemd.slice5, + bootup7, + systemd-fstab-generator8 + + + + diff --git a/man/systemd.special.xml.in b/man/systemd.special.xml.in deleted file mode 100644 index 116a43c..0000000 --- a/man/systemd.special.xml.in +++ /dev/null @@ -1,725 +0,0 @@ - - - - - - - - - systemd.special - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd.special - 7 - - - - systemd.special - special systemd units - - - - basic.target, - ctrl-alt-del.target, - dbus.service, - default.target, - display-manager.service, - emergency.target, - exit.service, - graphical.target, - halt.target, - kbrequest.target, - local-fs.target, - local-fs-pre.target, - mail-transfer-agent.target, - multi-user.target, - network.target, - nss-lookup.target, - poweroff.target, - reboot.target, - remote-fs.target, - remote-fs-pre.target, - rescue.target, - rpcbind.target, - runlevel2.target, - runlevel3.target, - runlevel4.target, - runlevel5.target, - shutdown.target, - sigpwr.target, - sockets.target, - swap.target, - sysinit.target, - syslog.target, - systemd-initctl.service, - systemd-initctl.socket, - systemd-stdout-syslog-bridge.service, - systemd-stdout-syslog-bridge.socket, - time-sync.target, - umount.target - - - - Description - - A few units are treated specially by - systemd. They have special internal semantics and - cannot be renamed. - - - - Special System Units - - - - basic.target - - A special target unit - covering early boot-up. - systemd automatically - adds dependencies of the types - Requires and After for this - target unit to all SysV - service units configured for - runlevel 1 to 5. - Usually this should pull-in - all sockets, mount points, - swap devices and other basic - initialization necessary for - the general purpose - daemons. Most normal daemons - should have dependencies of - type After and Requires on - this unit. - - - - ctrl-alt-del.target - - systemd starts this - target whenever - Control+Alt+Del is pressed on - the console. Usually this - should be aliased (symlinked) - to - reboot.target. - - - - dbus.service - - A special unit for the - D-Bus system bus. As soon as - this service is fully started - up systemd will connect to it - and register its - service. - - - - default.target - - The default unit systemd - starts at bootup. Usually this - should be aliased (symlinked) - to - multi-user.target - or - graphical.target. - The default unit systemd - starts at bootup can be - overridden with the - systemd.unit= - kernel command line option. - - - - display-manager.service - - The display manager - service. Usually this should - be aliased (symlinked) to - xdm.service - or a similar display manager - service. - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with a LSB header - referring to the - $x-display-manager - facility, for compatibility - with Debian. - - - - emergency.target - - A special target unit - that starts an emergency - shell on the main - console. This unit is supposed - to be used with the kernel - command line option - systemd.unit= - and has otherwise little use. - - - - - graphical.target - - A special target unit - for setting up a graphical - login screen. This pulls in - multi-user.target. - - Units that are needed - for graphical login shall add - Wants dependencies for their - unit to this unit (or - multi-user.target) - during installation. - - - - halt.target - - A special target unit - for shutting down and halting the system. - - Applications wanting to - halt the system should start - this unit. - - - - kbrequest.target - - systemd starts this - target whenever Alt+ArrowUp is - pressed on the console. This - is a good candidate to be - aliased (symlinked) to - rescue.target. - - - - local-fs.target - - systemd automatically - adds dependencies of type - After to all mount units that - refer to local mount points - for this target unit. In - addition, systemd adds - dependencies of type Wants to - this target unit for those - mounts listed in - /etc/fstab - that have the - and - - mount options set. - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $local_fs - facility. - - - - local-fs-pre.target - - This target unit is - automatically ordered before - all local mount points marked - with - (see above). It can be used to - execute certain units before - all local mounts. - - - - mail-transfer-agent.target - - The mail transfer agent - (MTA) service. Usually this - should pull-in all units - necessary for - sending/receiving mails on the - local host. - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $mail-transfer-agent - or - $mail-transport-agent - facilities, for compatibility - with Debian. - - - - multi-user.target - - A special target unit - for setting up a multi-user - system (non-graphical). This - is pulled in by - graphical.target. - - Units that are needed - for a multi-user system shall - add Wants dependencies to - this unit for their unit during - installation. - - - - network.target - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $network - facility. - - - - nss-lookup.target - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $named - facility. - - - - poweroff.target - - A special target unit - for shutting down and powering off the system. - - Applications wanting to - power off the system should start - this unit. - - runlevel0.target - is an alias for this target - unit, for compatibility with SysV. - - - - reboot.target - - A special target unit - for shutting down and rebooting the system. - - Applications wanting to - reboot the system should start - this unit. - - runlevel6.target - is an alias for this target - unit, for compatibility with SysV. - - - - remote-fs.target - - Similar to - local-fs.target, - but for remote mount - points. - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $remote_fs - facility. - - - - remote-fs-pre.target - - This target unit is - automatically ordered before - all remote mount points marked - with - (see above). It can be used to - execute certain units before - all remote mounts. - - - - rescue.target - - A special target unit - for setting up the base system - and a rescue shell. - - runlevel1.target - is an alias for this target - unit, for compatibility with SysV. - - - - rpcbind.target - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $rpcbind - facility. - - - - runlevel2.target - - This is a target that is - called whenever the SysV - compatibility code asks for - runlevel 2. It is a good idea - to make this an alias for - (i.e. symlink to) - multi-user.target. - - - - runlevel3.target - - This is a target that is - called whenever the SysV - compatibility code asks for - runlevel 3. It is a good idea - to make this an alias for - (i.e. symlink to) - multi-user.target - or - graphical.target. - - - - runlevel4.target - - This is a target that is - called whenever the SysV - compatibility code asks for - runlevel 4. It is a good idea - to make this an alias for - (i.e. symlink to) - multi-user.target - or - graphical.target. - - - - runlevel5.target - - This is a target that is - called whenever the SysV - compatibility code asks for - runlevel 5. It is a good idea - to make this an alias for - (i.e. symlink to) - multi-user.target - or - graphical.target. - - - - shutdown.target - - A special target unit - that terminates the services - on system shutdown. - - Services that shall be - terminated on system shutdown - shall add Conflicts - dependencies to this unit for - their service unit, which is - implicitly done when - DefaultDependencies=yes - is set (the default). - - systemd automatically - adds dependencies of type - Conflicts to this target unit - for all SysV init script - service units that shall be - terminated in SysV runlevels 0 - or 6. - - - - sigpwr.target - - A special target that is - started when systemd receives - the SIGPWR process signal, - which is normally sent by the - kernel or UPS daemons when - power fails. - - - - sockets.target - - A special target unit - that sets up all service - sockets. - - Services that can be - socket-activated shall add - Wants dependencies to this - unit for their socket unit - during installation. - - - - swap.target - - Similar to - local-fs.target, but for swap - partitions and swap - files. - - - - sysinit.target - - A special target unit - covering early boot-up scripts. - systemd automatically - adds dependencies of the types - Wants and After for all - SysV service units configured - for runlevels that are not 0 - to 6 to this target unit. - This covers the special - boot-up runlevels some - distributions have, such as S - or b. - - - - syslog.target - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $syslog - facility. - - - - systemd-initctl.service - - This provides - compatibility with the SysV - /dev/initctl file system FIFO - for communication with the - init system. - This is a - socket-activated service, see - system-initctl.socket. - - - - systemd-initctl.socket - - Socket activation unit - for - system-initctl.service. - - - - systemd-stdout-syslog-bridge.service - - This is internally used - by systemd to provide syslog - logging to the processes it - maintains. - This is a - socket-activated service, see - system-stdout-syslog-bridge.socket. - - - - systemd-stdout-syslog-bridge.socket - - Socket activation unit - for - system-stdout-syslog-bridge.service. systemd - will automatically add - dependencies of types Requires - and After to all units that - have been configured for - stdout or stderr to be - connected to syslog or the - kernel log buffer. - - - - systemd-shutdownd.service - - This is internally used - by - shutdown8 - to implement delayed shutdowns. - This is a - socket-activated service, see - system-shutdownd.socket. - - - - systemd-shutdownd.socket - - Socket activation unit - for - system-shutdownd.service. - - - - time-sync.target - - systemd automatically - adds dependencies of type - After for this target unit to - all SysV init script service - units with an LSB header - referring to the - $time - facility. - - - - umount.target - - A special target unit - that umounts all mount and - automount points on system - shutdown. - - Mounts that shall be - unmounted on system shutdown - shall add Conflicts - dependencies to this unit for - their mount unit, which is - implicitly done when - DefaultDependencies=yes - is set (the default). - - - - - - - Special User Units - - When systemd runs as a user instance, the - following special units are available, which have - similar definitions as their system counterparts: - default.target, - local-fs.target, - remote-fs.target, - shutdown.target, - sockets.target, - swap.target. - - In addition the following special unit is - understood only when systemd runs as service instance: - - - - exit.service - - A special service unit - for shutting down the - user service manager. - - Applications wanting to - terminate the user service - manager should start this - unit. If systemd receives - SIGTERM or SIGINT when running - as user service daemon it will - start this unit. - - Normally, this pulls in - shutdown.target - which in turn should be - conflicted by all units that - want to be shut down on - user service manager exit. - - - - - - - See Also - - systemd.unit5, - systemd.service5, - systemd.socket5, - systemd.target5 - - - - diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index ab00f9f..492309e 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.swap - systemd swap configuration files + Swap unit configuration - systemd.swap + swap.swap Description A unit configuration file whose name ends in - .swap encodes information about a + .swap encodes information about a swap device or file for memory paging controlled and supervised by systemd. @@ -68,17 +68,29 @@ specific configuration options are configured in the [Swap] section. + Additional options are listed in + systemd.exec5, + which define the execution environment the + swapon8 + binary is executed in, and in + systemd.kill5, + which define the way the processes are + terminated, and in + systemd.resource-control5, + which configure resource control settings for the + processes of the service. + Swap units must be named after the devices - (resp. files) they control. Example: the swap device - /dev/sda5 must be configured in a + or files they control. Example: the swap device + /dev/sda5 must be configured in a unit file dev-sda5.swap. For details about the escaping logic used to convert a - file system path to a unit name see + file system path to a unit name, see systemd.unit5. All swap units automatically get the appropriate - dependencies on the devices (resp. on the mount points - of the files) they are activated from. + dependencies on the devices or on the mount points + of the files they are activated from. Swap units with DefaultDependencies= enabled @@ -93,10 +105,16 @@ Swap units may either be configured via unit files, or via /etc/fstab (see fstab5 - for details). + for details). Swaps listed in + /etc/fstab will be converted into + native units dynamically at boot and when the + configuration of the system manager is + reloaded. See + systemd-fstab-generator8 + for details about the conversion. If a swap device or file is configured in both - /etc/fstab and a unit file the + /etc/fstab and a unit file, the configuration in the latter takes precedence. Unless the option is set @@ -115,11 +133,13 @@ supervises. A number of options that may be used in this section are shared with other unit types. These options are documented in - systemd.exec5. The + systemd.exec5 + and + systemd.kill5. The options specific to the [Swap] section of swap units are the following: - + What= @@ -155,55 +175,27 @@ Configures the time to wait for the swapon command to finish. If a command does not exit - within the configured time the swap + within the configured time, the swap will be considered failed and be shut down again. All commands still running will be terminated forcibly via - SIGTERM, and after another delay of - this time with SIGKILL. (See - below.) + SIGTERM, and after another delay of + this time with SIGKILL. (See + in + systemd.kill5.) Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout - logic. Defaults to - 90s. - - - - KillMode= - Specifies how - processes of this swap shall be - killed. One of - , - , - . - - This option is mostly equivalent - to the - option of service files. See - systemd.service5 - for details. - - - - KillSignal= - Specifies which signal - to use when killing a process of this - swap. Defaults to SIGTERM. - - - - - SendSIGKILL= - Specifies whether to - send SIGKILL to remaining processes - after a timeout, if the normal - shutdown procedure left processes of - the swap around. Takes a boolean - value. Defaults to "yes". - + logic. Defaults to TimeoutStartSec= from the + manager configuration file. + + Check + systemd.exec5 + and + systemd.kill5 + for more settings. @@ -213,9 +205,13 @@ systemctl8, systemd.unit5, systemd.exec5, + systemd.kill5, + systemd.resource-control5, systemd.device5, systemd.mount5, - swapon8 + swapon8, + systemd-fstab-generator8, + systemd.directives7 diff --git a/man/systemd.target.xml b/man/systemd.target.xml index 6b1dbfb..15662a5 100644 --- a/man/systemd.target.xml +++ b/man/systemd.target.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.target - systemd target configuration files + Target unit configuration - systemd.target + target.target Description A unit configuration file whose name ends in - .target encodes information about + .target encodes information about a target unit of systemd, which is used for grouping units and as well-known synchronization points during start-up. @@ -101,7 +101,8 @@ systemd1, systemctl8, systemd.unit5, - systemd.special7 + systemd.special7, + systemd.directives7 diff --git a/man/systemd.time.xml b/man/systemd.time.xml new file mode 100644 index 0000000..a837f23 --- /dev/null +++ b/man/systemd.time.xml @@ -0,0 +1,293 @@ + + + + + + + + + systemd.time + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd.time + 7 + + + + systemd.time + Time and date specifications + + + + Description + + In systemd, timestamps, time spans, and calendar + events are displayed and may be specified in closely + related syntaxes. + + + + Displaying Time Spans + + Time spans refer to time durations. On display, + systemd will present time spans as a space-separated + series of time values each suffixed by a time + unit. + + 2h 30min + + All specified time values are meant to be added + up. The above hence refers to 150 minutes. + + + + Parsing Time Spans + + When parsing, systemd will accept the same + time span syntax. Separating spaces may be omitted. The + following time units are understood: + + + usec, us + msec, ms + seconds, second, sec, s + minutes, minute, min, m + hours, hour, hr, h + days, day, d + weeks, week, w + months, month + years, year, y + + + If no time unit is specified, generally seconds + are assumed, but some exceptions exist and are marked + as such. In a few cases ns, + nsec is accepted too, where the + granularity of the time span allows for this. + + Examples for valid time span specifications: + + 2 h +2hours +48hr +1y 12month +55s500ms +300ms20s 5day + + + + Displaying Timestamps + + Timestamps refer to specific, unique points in + time. On display, systemd will format these in the + local timezone as follows: + + Fri 2012-11-23 23:02:15 CET + + The weekday is printed according to the locale + choice of the user. + + + + Parsing Timestamps + + When parsing systemd will accept a similar + timestamp syntax, but excluding any timezone + specification (this limitation might be removed + eventually). The weekday specification is optional, + but when the weekday is specified it must either be + in the abbreviated (Wed) or + non-abbreviated (Wednesday) English + language form (case does not matter), and is not + subject to the locale choice of the user. Either the + date, or the time part may be omitted, in which case + the current date or 00:00:00, resp., is assumed. The + seconds component of the time may also be omitted, in + which case ":00" is assumed. Year numbers may be + specified in full or may be abbreviated (omitting the + century). + + A timestamp is considered invalid if a weekday + is specified and the date does not actually match the + specified day of the week. + + When parsing, systemd will also accept a few + special placeholders instead of timestamps: + now may be used to refer to the + current time (or of the invocation of the command + that is currently executed). today, + yesterday, + tomorrow refer to 00:00:00 of the + current day, the day before or the next day, + respectively. + + When parsing, systemd will also accept relative + time specifications. A time span (see above) that is + prefixed with + is evaluated to the + current time plus the specified + time span. Correspondingly, a time span that is prefixed + with - is evaluated to the current + time minus the specified time span. Instead of + prefixing the time span with -, it + may also be suffixed with a space and the word + ago. + + Examples for valid timestamps and their + normalized form (assuming the current time was + 2012-11-23 18:15:22): + + Fri 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13 + 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13 + 2012-11-23 → Fri 2012-11-23 00:00:00 + 12-11-23 → Fri 2012-11-23 00:00:00 + 11:12:13 → Fri 2012-11-23 11:12:13 + 11:12 → Fri 2012-11-23 11:12:00 + now → Fri 2012-11-23 18:15:22 + today → Fri 2012-11-23 00:00:00 + yesterday → Fri 2012-11-22 00:00:00 + tomorrow → Fri 2012-11-24 00:00:00 + +3h30min → Fri 2012-11-23 21:45:22 + -5s → Fri 2012-11-23 18:15:17 + 11min ago → Fri 2012-11-23 18:04:22 + + Note that timestamps printed by systemd will not + be parsed correctly by systemd, as the timezone + specification is not accepted, and printing timestamps + is subject to locale settings for the weekday while + parsing only accepts English weekday names. + + In some cases, systemd will display a relative + timestamp (relative to the current time, or the time + of invocation of the command) instead or in addition + to an absolute timestamp as described above. A + relative timestamp is formatted as follows: + + 2 months 5 days ago + + Note that any relative timestamp will also parse + correctly where a timestamp is expected. (see above) + + + + Calendar Events + + Calendar events may be used to refer to one or + more points in time in a single expression. They form + a superset of the absolute timestamps explained above: + + Thu,Fri 2012-*-1,5 11:12:13 + + The above refers to 11:12:13 of the first or + fifth day of any month of the year 2012, given that it + is a Thursday or Friday. + + The weekday specification is optional. If + specified, it should consist of one or more English + language weekday names, either in the abbreviated + (Wed) or non-abbreviated (Wednesday) form (case does + not matter), separated by commas. Specifying two + weekdays separated by - refers to a + range of continuous weekdays. , and + - may be combined freely. + + In the date and time specifications, any + component may be specified as * in + which case any value will match. Alternatively, each + component can be specified as a list of values separated + by commas. Values may also be suffixed with + / and a repetition value, which + indicates that the value and all values plus multiples + of the repetition value are matched. + + Either time or date specification may be + omitted, in which case the current day and 00:00:00 is + implied, respectively. If the second component is not + specified, :00 is assumed. + + Timezone names may not be specified. + + The special expressions + hourly, daily, + monthly and weekly + may be used as calendar events which refer to + *-*-* *:00:00, *-*-* + 00:00:00, *-*-01 00:00:00 and + Mon *-*-* 00:00:00, + respectively. + + Examples for valid timestamps and their + normalized form: + + Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00 + Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00 + Wed *-1 → Wed *-*-01 00:00:00 + Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00 + Wed, 17:48 → Wed *-*-* 17:48:00 +Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 + *-*-7 0:0:0 → *-*-07 00:00:00 + 10-15 → *-10-15 00:00:00 + monday *-12-* 17:00 → Mon *-12-* 17:00:00 + Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45 + 12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00 + mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45 + 03-05 08:05:40 → *-03-05 08:05:40 + 08:05:40 → *-*-* 08:05:40 + 05:40 → *-*-* 05:40:00 + Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40 + Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 + 2003-03-05 05:40 → 2003-03-05 05:40:00 + 2003-03-05 → 2003-03-05 00:00:00 + 03-05 → *-03-05 00:00:00 + hourly → *-*-* *:00:00 + daily → *-*-* 00:00:00 + monthly → *-*-01 00:00:00 + weekly → Mon *-*-* 00:00:00 + *:2/3 → *-*-* *:02/3:00 + + Calendar events are used by timer units, see + systemd.timer5 + for details. + + + + + See Also + + systemd1, + journalctl1, + systemd.timer5, + systemd.unit5, + systemd.directives7 + + + + diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 9b6b486..98d4f7b 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -9,16 +9,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -44,18 +44,18 @@ systemd.timer - systemd timer configuration files + Timer unit configuration - systemd.timer + timer.timer Description A unit configuration file whose name ends in - .timer encodes information about + .timer encodes information about a timer controlled and supervised by systemd, for timer-based activation. @@ -97,7 +97,7 @@ defines. The options specific to the [Timer] section of timer units are the following: - + OnActiveSec= OnBootSec= @@ -105,7 +105,7 @@ OnUnitActiveSec= OnUnitInactiveSec= - Defines timers + Defines monotonic timers relative to different starting points: OnActiveSec= defines a timer relative to the moment the timer @@ -115,7 +115,7 @@ machine was booted up. OnStartupSec= defines a timer relative to when - systemd was + systemd was first started. OnUnitActiveSec= defines a timer relative to when the unit the timer is activating was last @@ -128,7 +128,7 @@ combined of the same and of different types. For example, by combining OnBootSec= and - OnUnitActiveSec= it is + OnUnitActiveSec=, it is possible to define a timer that elapses in regular intervals and activates a specific service each @@ -139,9 +139,9 @@ seconds. Example: "OnBootSec=50" means 50s after boot-up. The argument may also include time units. Example: - "OnBootSec=5h 30min" means 5 hours and 30 - minutes after boot-up. For details - about the syntax of time spans see + "OnBootSec=5h 30min" means 5 hours and + 30 minutes after boot-up. For details + about the syntax of time spans, see systemd.unit5. If a timer configured with @@ -152,13 +152,86 @@ elapse and the configured unit is started. This is not the case for timers defined in the other - directives. + directives. These are monotonic timers, independent of wall-clock time and timezones. If the computer is temporarily suspended, the monotonic clock stops too. + 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. + + Note that timers do not + necessarily expire at the precise + time configured with these settings, + as they are subject to the + AccuracySec= + setting below. + + + + + OnCalendar= + + Defines realtime + (i.e. wallclock) timers with calendar + event expressions. See + systemd.time7 + for more information on the syntax of + calendar event expressions. Otherwise, + the semantics are similar to + OnActiveSec= and + related settings. + + Note that timers do not + necessarily expire at the precise + time configured with this setting, + as it is subject to the + AccuracySec= + setting below. + + + + AccuracySec= + + Specify the accuracy + the timer shall elapse with. Defaults + to 1min. The timer is scheduled to + elapse within a time window starting + with the time specified in + OnCalendar=, + OnActiveSec=, + OnBootSec=, + OnStartupSec=, + OnUnitActiveSec= or + OnUnitInactiveSec= + and ending the time configured with + AccuracySec= + later. Within this time window, the + expiry time will be placed at a + host-specific, randomized but stable + position that is synchronized between + all local timer units. This is done in + order to distribute the wake-up time + in networked installations, as well as + optimizing power consumption to + suppress unnecessary CPU wake-ups. To + get best accuracy, set this option to + 1us. Note that the timer is still + subject to the timer slack configured + via + systemd-system.conf5's + TimerSlackNSec= + setting. See + prctl2 + for details. To optimize power + consumption, make sure to set this + value as high as possible and as low + as necessary. Unit= @@ -166,7 +239,7 @@ The unit to activate when this timer elapses. The argument is a unit name, whose suffix is not - .timer. If not + .timer. If not specified, this value defaults to a service that has the same name as the timer unit, except for the @@ -185,7 +258,11 @@ systemd1, systemctl8, systemd.unit5, - systemd.service5 + systemd.service5, + systemd.time7, + systemd.directives7, + systemd-system.conf5, + prctl2 diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 897f99f..07a73fd 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1,6 +1,9 @@ + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ + +%entities; +]> @@ -44,20 +47,35 @@ systemd.unit - systemd unit configuration files + Unit configuration - systemd.service, - systemd.socket, - systemd.device, - systemd.mount, - systemd.automount, - systemd.swap, - systemd.target, - systemd.path, - systemd.timer, - systemd.snapshot + service.service, + socket.socket, + device.device, + mount.mount, + automount.automount, + swap.swap, + target.target, + path.path, + timer.timer, + snapshot.snapshot, + slice.slice, + scope.scope + + /etc/systemd/system/* +/run/systemd/system/* +/usr/lib/systemd/system/* +... + + + $HOME/.config/systemd/user/* +/etc/systemd/user/* +/run/systemd/user/* +/usr/lib/systemd/user/* +... + @@ -66,31 +84,62 @@ A unit configuration file encodes information about a service, a socket, a device, a mount point, an automount point, a swap file or partition, a start-up - target, a file system path or a timer controlled and - supervised by - systemd1. The - syntax is inspired by systemd1, + a temporary system state snapshot, a resource + management slice or a group of externally created + processes. The syntax is inspired by XDG - Desktop Entry Specification .desktop files, which are in turn + Desktop Entry Specification + .desktop files, which are in turn inspired by Microsoft Windows .ini files. - This man pages lists the common configuration + This man page lists the common configuration options of all the unit types. These options need to - be configured in the [Unit] resp. [Install] - section of the unit files. + be configured in the [Unit] or [Install] + sections of the unit files. In addition to the generic [Unit] and [Install] - sections described here, each unit should have a + sections described here, each unit may have a type-specific section, e.g. [Service] for a service unit. See the respective man pages for more - information. + information: + systemd.service5, + systemd.socket5, + systemd.device5, + systemd.mount5, + systemd.automount5, + systemd.swap5, + systemd.target5, + systemd.path5, + systemd.timer5, + systemd.snapshot5. + systemd.slice5. + systemd.scope5. + + + Various settings are allowed to be specified + more than once, in which case the interpretation + depends on the setting. Often, multiple settings form + a list, and setting to an empty value "resets", which + means that previous assignments are ignored. When this + is allowed, it is mentioned in the description of the + setting. Note that using multiple assignments to the + same value makes the unit file incompatible with + parsers for the XDG .desktop file + format. + + Unit files are loaded from a set of paths + determined during compilation, described in the next section. + Unit files may contain additional options on top of those listed here. If systemd encounters an unknown - option it will write a warning log message but + option, it will write a warning log message but continue loading the unit. If an option is prefixed - with it is ignored completely by + with , it is ignored completely by systemd. Applications may use this to include additional information in the unit files. @@ -98,7 +147,7 @@ written in various formats. For positive settings the strings , , and are - equivalent. For negative settings the strings + equivalent. For negative settings, the strings , , and are equivalent. @@ -106,12 +155,14 @@ Time span values encoded in unit files can be written in various formats. A stand-alone number specifies a time in seconds. If suffixed with a time - unit, the unit is honored. A concatenation of - multiple values with units is supported, in which case - the values are added up. Example: "50" refers to 50 + unit, the unit is honored. A concatenation of multiple + values with units is supported, in which case the + values are added up. Example: "50" refers to 50 seconds; "2min 200ms" refers to 2 minutes plus 200 milliseconds, i.e. 120200ms. The following time units - are understood: s, min, h, d, w, ms, us. + are understood: s, min, h, d, w, ms, us. For details + see + systemd.time7. Empty lines and lines starting with # or ; are ignored. This may be used for commenting. Lines ending @@ -119,47 +170,50 @@ line while reading and the backslash is replaced by a space character. This may be used to wrap long lines. - If a line starts with - followed by a file name, the specified file will be - parsed at this point. Make sure that the file that is - included has the appropiate section headers before - any directives. - Along with a unit file - foo.service a directory + foo.service, the directory foo.service.wants/ may exist. All - units symlinked from such a directory are implicitly - added as dependencies of type + unit files symlinked from such a directory are + implicitly added as dependencies of type Wanted= to the unit. This is useful to hook units into the start-up of other units, - without having to modify their unit configuration - files. For details about the semantics of - Wanted= see below. The preferred - way to create symlinks in the - .wants/ directory of a service is - with the enable command of the + without having to modify their unit files. For details + about the semantics of Wanted=, see + below. The preferred way to create symlinks in the + .wants/ directory of a unit file + is with the enable command of the systemctl1 tool which reads information from the [Install] - section of unit files. (See below.) A similar + section of unit files (see below). A similar functionality exists for Requires= type dependencies as well, the directory suffix is .requires/ in this case. + Along with a unit file + foo.service, a directory + foo.service.d/ may exist. All + files with the suffix .conf from + this directory will be parsed after the file itself is + parsed. This is useful to alter or add configuration + settings to a unit, without having to modify their + unit files. Make sure that the file that is included + has the appropriate section headers before any + directive. + Note that while systemd offers a flexible dependency system between units it is recommended to - use this functionality only sparsely and instead rely + use this functionality only sparingly and instead rely on techniques such as bus-based or socket-based - activation which makes dependencies implicit, which - both results in a simpler and more flexible - system. + activation which make dependencies implicit, resulting + in a both simpler and more flexible system. Some unit names reflect paths existing in the - file system name space. Example: a device unit + file system namespace. Example: a device unit dev-sda.device refers to a device - with the device node /dev/sda in - the file system namespace. If this applies a special + with the device node /dev/sda in + the file system namespace. If this applies, a special way to escape the path name is used, so that the - result is usable as part of a file name. Basically, + result is usable as part of a filename. Basically, given a path, "/" is replaced by "-", and all unprintable characters and the "-" are replaced by C-style "\x20" escapes. The root directory "/" is @@ -170,12 +224,12 @@ Optionally, units may be instantiated from a template file at runtime. This allows creation of multiple units from a single configuration file. If - systemd looks for a unit configuration file it will + systemd looks for a unit configuration file, it will first search for the literal unit name in the - filesystem. If that yields no success and the unit - name contains an @ character, systemd will look for a + file system. If that yields no success and the unit + name contains an @ character, systemd will look for a unit template that shares the same name but with the - instance string (i.e. the part between the @ character + instance string (i.e. the part between the @ character and the suffix) removed. Example: if a service getty@tty3.service is requested and no file by that name is found, systemd will look @@ -186,104 +240,123 @@ To refer to the instance string from within the configuration file you may use the special %i specifier in many of the - configuration options. Other specifiers exist, the - full list is: + configuration options. See below for details. + + If a unit file is empty (i.e. has the file size + 0) or is symlinked to /dev/null, + its configuration will not be loaded and it appears + with a load state of masked, and + cannot be activated. Use this as an effective way to + fully disable a unit, making it impossible to start it + even manually. + + The unit file format is covered by the + Interface + Stability Promise. + + + + + Unit Load Path + + Unit files are loaded from a set of paths + determined during compilation, described in the two + tables below. Unit files found in directories listed + earlier override files with the same name in + directories lower in the list. + + When systemd is running in user mode + () and the variable + $SYSTEMD_UNIT_PATH is set, this + contents of this variable overrides the unit load + path. + - Specifiers available in unit files - - - - + + Load path when running in system mode (<option>--system</option>). + + + + + - Specifier - Meaning - Details + Path + Description - %n - Full unit name - - - - %N - Unescaped full unit name - - - - %p - Prefix name - This refers to the string before the @, i.e. "getty" in the example above, where "tty3" is the instance name. - - - %P - Unescaped prefix name - + /etc/systemd/system + Local configuration - %i - Instance name - This is the string between the @ character and the suffix. + /run/systemd/system + Runtime units - %I - Unescaped instance name - + /usr/lib/systemd/system + Units of installed packages + + +
+ + + + Load path when running in user mode (<option>--user</option>). + + + + + + - %f - Unescaped file name - This is either the unescaped instance name (if set) with / prepended (if necessary), or the prefix name similarly prepended with /. + Path + Description + + - %c - Control group path of the unit - + $HOME/.config/systemd/user + User configuration - %r - Root control group path of systemd - + /etc/systemd/user + Local configuration - %R - Parent directory of the root control group path of systemd - + /run/systemd/user + Runtime units - %t - Runtime socket dir - This is either /run (for the system manager) or $XDG_RUNTIME_DIR (for user managers). + /usr/lib/systemd/user + Units of installed packages
- If a unit file is empty (i.e. has the file size - 0) or is symlinked to /dev/null - its configuration will not be loaded and it appears - with a load state of masked, and - cannot be activated. Use this as an effective way to - fully disable a unit, making it impossible to start it - even manually. - - The unit file format is covered by the + Additional units might be loaded into systemd + ("linked") from directories not on the unit load + path. See the link command for + systemctl1. Also, + some units are dynamically created via generators Interface - Stability Promise. + url="http://www.freedesktop.org/wiki/Software/systemd/Generators/">Generators. +
- Options + [Unit] Section Options Unit file may include a [Unit] section, which carries generic information about the unit that is not dependent on the type of unit: - + Description= @@ -291,7 +364,45 @@ describing the unit. This is intended for use in UIs to show descriptive information along with the unit - name. + name. The description should contain a name + that means something to the end user. + Apache2 Web Server is a good + example. Bad examples are + high-performance light-weight HTTP + server (too generic) or + Apache2 (too specific and + meaningless for people who do not know + Apache). + + + + Documentation= + A space-separated list + of URIs referencing documentation for + this unit or its + configuration. Accepted are only URIs + of the types + http://, + https://, + file:, + info:, + man:. For more + information about the syntax of these + URIs, see + uri7. The + URIs should be listed in order of + relevance, starting with the most + relevant. It is a good idea to first + reference documentation that explains + what the unit's purpose is, followed + by how it is configured, followed by + any other related documentation. This + option may be specified more than once, + in which case the specified list of + URIs is merged. If the empty string is + assigned to this option, the list is + reset and all prior assignments will + have no effect. @@ -304,10 +415,12 @@ of the other units gets deactivated or its activation fails, this unit will be deactivated. This option may be - specified more than once, in which - case requirement dependencies for all - listed names are created. Note that - requirement dependencies do not + specified more than once or multiple + space-separated units may be specified + in one option in which case + requirement dependencies for all + listed names will be created. Note + that requirement dependencies do not influence the order in which services are started or stopped. This has to be configured independently with the @@ -331,7 +444,15 @@ Requires= in order to achieve a system that is more robust when dealing with failing - services. + services. + + Note that dependencies of this + type may also be configured outside of + the unit configuration file by + adding a symlink to a + .requires/ directory + accompanying the unit file. For + details see above. @@ -347,7 +468,7 @@ the start-up was pulled in indirectly by some dependency or automatic start-up of units that is not - requested by the user this dependency + requested by the user, this dependency must be fulfilled and otherwise the transaction fails. Hence, this option may be used to configure dependencies @@ -362,43 +483,46 @@ RequisiteOverridable= Similar to - Requires= - resp. RequiresOverridable=. However, - if a unit listed here is not started - already it will not be started and the - transaction fails - immediately. + Requires= and + RequiresOverridable=, + respectively. However, if the units + listed here are not started already, + they will not be started and the + transaction will fail immediately. + Wants= A weaker version of - Requires=. A unit + Requires=. Units listed in this option will be started if the configuring unit is. However, - if the listed unit fails to start up - or cannot be added to the transaction + if the listed units fail to start + or cannot be added to the transaction, this has no impact on the validity of the transaction as a whole. This is the recommended way to hook start-up of one unit to the start-up of another - unit. Note that dependencies of this + unit. + + Note that dependencies of this type may also be configured outside of - the unit configuration file by - adding a symlink to a + the unit configuration file by adding + symlinks to a .wants/ directory accompanying the unit file. For - details see above. + details, see above. - BindTo= + BindsTo= Configures requirement dependencies, very similar in style to Requires=, however - in addition to this behaviour it also + in addition to this behavior, it also declares that this unit is stopped when any of the units listed suddenly disappears. Units can suddenly, @@ -410,14 +534,29 @@ + PartOf= + + Configures dependencies + similar to Requires=, + but limited to stopping and restarting + of units. When systemd stops or restarts + the units listed here, the action is + propagated to this unit. + Note that this is a one-way dependency — + changes to this unit do not affect the + listed units. + + + + Conflicts= - Configures negative + A space-separated list + of unit names. Configures negative requirement dependencies. If a unit - has a - Conflicts= setting - on another unit, starting the former - will stop the latter and vice + has a Conflicts= + setting on another unit, starting the + former will stop the latter and vice versa. Note that this setting is independent of and orthogonal to the After= and @@ -432,9 +571,9 @@ be modified to be fixed (in case one or both jobs are not a required part of the transaction). In the latter - case the job that is not the required + case, the job that is not the required will be removed, or in case both are - not required the unit that conflicts + not required, the unit that conflicts will be started and the unit that is conflicted is stopped. @@ -444,7 +583,8 @@ Before= After= - Configures ordering + A space-separated list + of unit names. Configures ordering dependencies between units. If a unit foo.service contains a setting @@ -460,7 +600,7 @@ a common pattern to include a unit name in both the After= and - Requires= option in + Requires= option, in which case the unit listed will be started before the unit that is configured with these options. This @@ -488,48 +628,118 @@ dependency on another unit is shut down while the latter is started up, the shut down is ordered before the - start-up regardless whether the + start-up regardless of whether the ordering dependency is actually of type After= or Before=. If two units have no ordering dependencies - between them they are shut down - resp. started up simultaneously, and - no ordering takes + between them, they are shut down or + started up simultaneously, and no + ordering takes place. OnFailure= - Lists one or more - units that are activated when this - unit enters the - 'failed' + A space-separated list + of one or more units that are + activated when this unit enters the + failed state. - OnFailureIsolate= + PropagatesReloadTo= + ReloadPropagatedFrom= + + A space-separated list + of one or more units where reload + requests on this unit will be + propagated to, or reload requests on + the other unit will be propagated to + this unit, respectively. Issuing a + reload request on a unit will + automatically also enqueue a reload + request on all units that the reload + request shall be propagated to via + these two settings. + - Takes a boolean - argument. If the - unit listed in + + JoinsNamespaceOf= + + 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 + PrivateNetwork= and + PrivateTmp= + directives (see + systemd.exec5 + for details). If a unit that has this + setting set is started, its processes + will see the same + /tmp, + /tmp/var 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 + PrivateNetwork= + and/or PrivateTmp= + is enabled for both the unit that + joins the namespace and the unit whose + namespace is joined. + + + + RequiresMountsFor= + + Takes a space-separated + list of absolute paths. Automatically + adds dependencies of type + Requires= and + After= for all + mount units required to access the + specified path. + + + + OnFailureJobMode= + + Takes a value of + fail, + replace, + replace-irreversibly, + isolate, + flush, + ignore-dependencies + or + ignore-requirements. Defaults + to + replace. Specifies + how the units listed in OnFailure= will be - enqueued in isolation mode, i.e. all - units that are not its dependency will - be stopped. If this is set only a + enqueued. See + systemctl1's + option + for details on the possible values. If + this is set to + isolate, only a single unit may be listed in - OnFailure=. Defaults - to - . + OnFailure=.. IgnoreOnIsolate= Takes a boolean - argument. If + argument. If , this unit will not be stopped when isolating another unit. Defaults to . @@ -539,7 +749,7 @@ IgnoreOnSnapshot= Takes a boolean - argument. If + argument. If , this unit will not be included in snapshots. Defaults to for device and @@ -551,7 +761,7 @@ StopWhenUnneeded= Takes a boolean - argument. If + argument. If , this unit will be stopped when it is no longer used. Note that in order to minimize the work to be executed, @@ -570,15 +780,15 @@ RefuseManualStop= Takes a boolean - argument. If + argument. If , this unit can only be activated - (resp. deactivated) indirectly. In - this case explicit start-up - (resp. termination) requested by the + or deactivated indirectly. In + this case, explicit start-up + or termination requested by the user is denied, however if it is - started (resp. stopped) as a + started or stopped as a dependency of another unit, start-up - (resp. termination) will succeed. This + or termination will succeed. This is mostly a safety feature to ensure that the user does not accidentally activate units that are not intended @@ -593,10 +803,10 @@ AllowIsolate= Takes a boolean - argument. If + argument. If , this unit may be used with the systemctl isolate - command. Otherwise this will be + command. Otherwise, this will be refused. It probably is a good idea to leave this disabled except for target units that shall be used similar to @@ -610,7 +820,7 @@ DefaultDependencies= Takes a boolean - argument. If + argument. If , (the default), a few default dependencies will implicitly be created for the unit. The actual @@ -628,7 +838,7 @@ highly recommended to leave this option enabled for the majority of common units. If set to - this option + , this option does not disable all implicit dependencies, just non-essential ones. @@ -640,10 +850,10 @@ When clients are waiting for a job of this unit to complete, time out after the specified - time. If this time limit is reached + time. If this time limit is reached, the job will be cancelled, the unit however will not change state or even - enter the 'failed' + enter the failed mode. This value defaults to 0 (job timeouts disabled), except for device units. NB: this timeout is independent @@ -663,85 +873,78 @@ + ConditionArchitecture= + ConditionVirtualization= + ConditionHost= + ConditionKernelCommandLine= + ConditionSecurity= + ConditionCapability= + ConditionACPower= ConditionPathExists= ConditionPathExistsGlob= ConditionPathIsDirectory= ConditionPathIsSymbolicLink= ConditionPathIsMountPoint= + ConditionPathIsReadWrite= ConditionDirectoryNotEmpty= + ConditionFileNotEmpty= ConditionFileIsExecutable= - ConditionKernelCommandLine= - ConditionVirtualization= - ConditionSecurity= - ConditionCapability= ConditionNull= Before starting a unit verify that the specified condition is - true. With - ConditionPathExists= - a file existence condition can be - checked before a unit is started. If - the specified absolute path name does - not exist, startup of a unit will not - actually happen, however the unit is - still useful for ordering purposes in - this case. The condition is checked at - the time the queued start job is to be - executed. If the absolute path name - passed to - ConditionPathExists= - is prefixed with an exclamation mark - (!), the test is negated, and the unit - is only started if the path does not - exist. - ConditionPathExistsGlob= - works in a similar way, but checks for - the existence of at least one file or - directory matching the specified - globbing - pattern. ConditionPathIsDirectory= - is similar to - ConditionPathExists= - but verifies whether a certain path - exists and is a - directory. ConditionPathIsSymbolicLink= - is similar to - ConditionPathExists= - but verifies whether a certain path - exists and is a symbolic - link. ConditionPathIsMountPoint= - is similar to - ConditionPathExists= - but verifies whether a certain path - exists and is a mount - point. ConditionFileIsExecutable= - is similar to - ConditionPathExists= - but verifies whether a certain path - exists, is a regular file and marked - executable. - ConditionDirectoryNotEmpty= - is similar to - ConditionPathExists= - but verifies whether a certain path - exists and is a non-empty - directory. Similarly - ConditionKernelCommandLine= - may be used to check whether a - specific kernel command line option is - set (or if prefixed with the - exclamation mark unset). The argument - must either be a single word, or an - assignment (i.e. two words, separated - by the equality sign). In the former - case the kernel command line is - searched for the word appearing as is, - or as left hand side of an - assignment. In the latter case the - exact assignment is looked for with - right and left hand side - matching. ConditionVirtualization= + true. If it is not true, the starting + of the unit will be skipped, however + all ordering dependencies of it are + still respected. A failing condition + will not result in the unit being + moved into a failure state. The + condition is checked at the time the + queued start job is to be + executed. + + ConditionArchitecture= + may be used to check whether the + system is running on a specific + architecture. Takes one of + x86, + x86-64, + ppc, + ppc64, + ia64, + parisc, + parisc64, + s390, + s390x, + sparc, + sparc64, + mips, + mips64, + alpha, + arm, + arm-be, + arm64, + arm64-be, + sh, + sh64, + m86k to test + against a specific architecture. The + architecture is determined from the + information returned by + uname2 + and is thus subject to + personality2. Note + that a Personality= + setting in the same unit file has no + effect on this condition. A special + architecture name + native is mapped to + the architecture the system manager + itself is compiled for. The test may + be negated by prepending an + exclamation mark. + + ConditionVirtualization= may be used to check whether the system is executed in a virtualized environment and optionally test @@ -751,7 +954,7 @@ any virtualized environment, or one of vm and container to test - against a specific type of + against a generic type of virtualization solution, or one of qemu, kvm, @@ -761,23 +964,61 @@ xen, bochs, chroot, + uml, openvz, lxc, - systemd-nspawn, - pidns to test - against a specific implementation. If - multiple virtualization technologies - are nested only the innermost is - considered. The test may be negated by - prepending an exclamation mark. - ConditionSecurity= + lxc-libvirt, + systemd-nspawn to + test against a specific + implementation. If multiple + virtualization technologies are nested, + only the innermost is considered. The + test may be negated by prepending an + exclamation mark. + + ConditionHost= + may be used to match against the + hostname or machine ID of the + host. This either takes a hostname + string (optionally with shell style + globs) which is tested against the + locally set hostname as returned by + gethostname2, + or a machine ID formatted as string + (see + machine-id5). + The test may be negated by prepending + an exclamation mark. + + ConditionKernelCommandLine= + may be used to check whether a + specific kernel command line option is + set (or if prefixed with the + exclamation mark unset). The argument + must either be a single word, or an + assignment (i.e. two words, separated + =). In the former + case the kernel command line is + searched for the word appearing as is, + or as left hand side of an + assignment. In the latter case the + exact assignment is looked for with + right and left hand side + matching. + + ConditionSecurity= may be used to check whether the given security module is enabled on the - system. Currently the only recognized - value is selinux. + system. Currently the recognized values + values are selinux, + apparmor, + ima and + smack. The test may be negated by prepending an exclamation - mark. ConditionCapability= + mark. + + ConditionCapability= may be used to check whether the given capability exists in the capability bounding set of the service manager @@ -788,64 +1029,149 @@ for details). Pass a capability name such as CAP_MKNOD, possibly prefixed with an exclamation - mark to negate the check. Finally, + mark to negate the check. + + ConditionACPower= + 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 + true, 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 false, the + condition will hold only if there is + at least one AC connector known and + all AC connectors are disconnected + from a power source. + + With + ConditionPathExists= + a file existence condition is + checked before a unit is started. If + the specified absolute path name does + not exist, the condition will + fail. If the absolute path name passed + to + ConditionPathExists= + is prefixed with an exclamation mark + (!), the test is negated, and the unit + is only started if the path does not + exist. + + ConditionPathExistsGlob= + is similar to + ConditionPathExists=, + but checks for the existence of at + least one file or directory matching + the specified globbing pattern. + + ConditionPathIsDirectory= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists and is a + directory. + + ConditionPathIsSymbolicLink= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists and is a symbolic + link. + + ConditionPathIsMountPoint= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists and is a mount + point. + + ConditionPathIsReadWrite= + is similar to + ConditionPathExists= + but verifies whether the underlying + file system is readable and writable + (i.e. not mounted + read-only). + + ConditionDirectoryNotEmpty= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists and is a non-empty + directory. + + ConditionFileNotEmpty= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists and refers to a regular file + with a non-zero size. + + ConditionFileIsExecutable= + is similar to + ConditionPathExists= + but verifies whether a certain path + exists, is a regular file and marked + executable. + + Finally, ConditionNull= may be used to add a constant condition check value to the unit. It takes a boolean argument. If set to - false the condition + false, the condition will always fail, otherwise - succeed. If multiple conditions are - specified the unit will be executed if + succeed. + + If multiple conditions are + specified, the unit will be executed if all of them apply (i.e. a logical AND is applied). Condition checks can be prefixed with a pipe symbol (|) in which case a condition becomes a triggering condition. If at least one triggering condition is defined for a - unit then the unit will be executed if + unit, then the unit will be executed if at least one of the triggering conditions apply and all of the non-triggering conditions. If you prefix an argument with the pipe - symbol and an exclamation mark the + symbol and an exclamation mark, the pipe symbol must be passed first, the exclamation second. Except for ConditionPathIsSymbolicLink=, - all path checks follow - symlinks. + all path checks follow symlinks. If + any of these options is assigned the + empty string, the list of conditions is + reset completely, all previous + condition settings (of any kind) will + have no effect. - Names= - - Additional names for - this unit. The names listed here must - have the same suffix (i.e. type) as - the unit file name. This option may be - specified more than once, in which - case all listed names are used. Note - that this option is different from the - Alias= option from - the [Install] section mentioned - below. See below for details. Note - that in almost all cases this option - is not what you want. A symlink alias - in the file system is generally - preferable since it can be used as - lookup key. If a unit with a symlinked - alias name is not loaded and needs to - be it is easily found via the - symlink. However, if a unit with an - alias name configured with this - setting is not loaded it will not be - discovered. This settings' only use is - in conjunction with service - instances. - + SourcePath= + A path to a + configuration file this unit has been + generated from. This is primarily + useful for implementation of generator + tools that convert configuration from + an external configuration file format + into native unit files. Thus + functionality should not be used in + normal units. + + + + [Install] Section Options + Unit file may include a [Install] section, which carries installation information for the unit. This section is not interpreted by @@ -856,78 +1182,224 @@ systemctl1 tool during installation of a unit: - + Alias= - Additional names this - unit shall be installed under. The - names listed here must have the same - suffix (i.e. type) as the unit file - name. This option may be specified - more than once, in which case all - listed names are used. At installation - time, - systemctl enable - will create symlinks from these names - to the unit file name. Note that this - is different from the - Names= option from - the [Unit] section mentioned above: - The names from - Names= apply - unconditionally if the unit is - loaded. The names from - Alias= apply only - if the unit has actually been - installed with the - systemctl enable - command. Also, if systemd searches for a - unit, it will discover symlinked alias - names as configured with - Alias=, but not - names configured with - Names= only. It is - a common pattern to list a name in - both options. In this case, a unit - will be active under all names if - installed, but also if not installed - but requested explicitly under its - main name. + A space-seperated list + of additional names this unit shall be + installed under. The names listed here + must have the same suffix (i.e. type) + as the unit file name. This option may + be specified more than once, in which + case all listed names are used. At + installation time, systemctl + enable will create symlinks + from these names to the unit + filename. WantedBy= - - Installs a symlink in - the .wants/ - subdirectory for a unit. This has the - effect that when the listed unit name - is activated the unit listing it is - activated - too. WantedBy=foo.service + RequiredBy= + + This option may be + used more than once, or a + space-separated list of unit names may + be given. A symbolic link is created + in the .wants/ or + .requires/ + directory of each of the listed units + when this unit is installed by + systemctl enable. + This has the effect that a dependency + of type Wants= or + Requires= is added + from the listed unit to the current + unit. The primary result is that the + current unit will be started when the + listed unit is started. See the + description of + Wants= and + Requires= in the + [Unit] section for details. + + WantedBy=foo.service in a service bar.service is mostly equivalent to Alias=foo.service.wants/bar.service - in the same file. + in the same file. In case of template + units, systemctl enable + must be called with an instance name, and + this instance will be added to the + .wants/ or + .requires/ list + of the listed unit. + E.g. WantedBy=getty.target + in a service + getty@.service + will result in systemctl + enable getty@tty2.service + creating a + getty.target.wants/getty@tty2.service + link to getty@.service. + Also= Additional units to - install when this unit is - installed. If the user requests - installation of a unit with this - option configured, + install/deinstall when this unit is + installed/deinstalled. If the user + requests installation/deinstallation + of a unit with this option configured, systemctl enable - will automatically install units - listed in this option as - well. + and systemctl + disable will automatically + install/uninstall units listed in this option as + well. + + This option may be used more + than once, or a space-separated list + of unit names may be + given. + The following specifiers are interpreted in the + Install section: %n, %N, %p, %i, %U, %u, %m, %H, %b, %v. + For their meaning see the next section. + + + + + Specifiers + + Many settings resolve specifiers which may be + used to write generic unit files referring to runtime + or unit parameters that are replaced when the unit + files are loaded. The following specifiers are + understood: + + + Specifiers available in unit files + + + + + + + Specifier + Meaning + Details + + + + + %n + Full unit name + + + + %N + Unescaped full unit name + Same as %n, but with escaping undone + + + %p + Prefix name + For instantiated units, this refers to the string before the @ character of the unit name. For non-instantiated units, this refers to the name of the unit with the type suffix removed. + + + %P + Unescaped prefix name + Same as %p, but with escaping undone + + + %i + Instance name + For instantiated units: this is the string between the @ character and the suffix of the unit name. + + + %I + Unescaped instance name + Same as %i, but with escaping undone + + + %f + Unescaped filename + This is either the unescaped instance name (if applicable) with / prepended (if applicable), or the prefix name prepended with /. + + + %c + Control group path of the unit + This path does not include the /sys/fs/cgroup/systemd/ prefix. + + + %r + Control group path of the slice the unit is placed in + This usually maps to the parent cgroup path of %c. + + + %R + Root control group path below which slices and units are placed + For system instances, this resolves to /, except in containers, where this maps to the container's root control group path. + + + %t + Runtime directory + This is either /run (for the system manager) or the path $XDG_RUNTIME_DIR resolves to (for user managers). + + + %u + User name + This is the name of the configured user of the unit, or (if none is set) the user running the systemd instance. + + + %U + User UID + This is the numeric UID of the configured user of the unit, or (if none is set) the user running the systemd user instance. Note that this specifier is not available for units run by the systemd system instance (as opposed to those run by a systemd user instance), unless the user has been configured as a numeric UID in the first place or the configured user is the root user. + + + %h + User home directory + This is the home directory of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to %U, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user. + + + %s + User shell + This is the shell of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to %U, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user. + + + %m + Machine ID + The machine ID of the running system, formatted as string. See machine-id5 for more information. + + + %b + Boot ID + The boot ID of the running system, formatted as string. See random4 for more information. + + + %H + Host name + The hostname of the running system at the point in time the unit configuation is loaded. + + + %v + Kernel release + Identical to uname -r output + + + %% + Single percent sign + Use %% in place of % to specify a single percent sign. + + + +
@@ -946,7 +1418,12 @@ systemd.path5, systemd.timer5, systemd.snapshot5, - capabilities7 + systemd.scope5, + systemd.slice5, + systemd.time7, + capabilities7, + systemd.directives7, + uname1 diff --git a/man/systemd.xml b/man/systemd.xml index a8a6967..331e6c2 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + systemd @@ -45,7 +46,7 @@ systemd init - systemd System and Service Manager + systemd system and service manager @@ -78,7 +79,7 @@ the configuration file system.conf, otherwise user.conf. See - systemd.conf5 + systemd-system.conf5 for more information. @@ -89,13 +90,6 @@ - - - - Prints a short help - text and exits. - - Determine startup @@ -113,24 +107,10 @@ definition files. - - - Extract D-Bus - interface introspection data. This is - mostly useful at install time - to generate data suitable for the - D-Bus interfaces - repository. Optionally the interface - name for the introspection data may be - specified. If omitted, the - introspection data for all interfaces - is dumped. - - Set default unit to - activate on startup. If not specified + activate on startup. If not specified, defaults to default.target. @@ -138,11 +118,13 @@ - Tell systemd to run a - system instance (resp. user - instance), even if the process ID is - not 1 (resp. is 1), i.e. systemd is - not (resp. is) run as init process. + For , + tell systemd to run a + system instance, even if the process ID is + not 1, i.e. systemd is not run as init process. + does the opposite, + running a user instance even if the process + ID is 1. Normally it should not be necessary to pass these options, as systemd automatically detects the mode it is @@ -192,25 +174,15 @@ . - - - Controls whether - output of SysV init scripts will be - directed to the console. This switch - has no effect when run as user - instance. Takes a boolean argument - which may be omitted which is - interpreted as - . - - Set log target. Argument must be one of , + , , , + , , . @@ -235,7 +207,7 @@ Highlight important log messages. Argument is a boolean - value. If the argument is omitted it + value. If the argument is omitted, it defaults to . @@ -255,29 +227,34 @@ Sets the default - output resp. error output for all - services and sockets, i.e. controls + output or error output for all + services and sockets, respectively. That is, controls the default for - resp. + and (see systemd.exec5 for details). Takes one of , , , + , + , , , , . If the argument is omitted - defaults to + defaults to and to . + + + @@ -285,25 +262,27 @@ Concepts systemd provides a dependency system between - various entities called "units". Units encapsulate - various objects that are relevant for system boot-up - and maintenance. The majority of units are configured - in unit configuration files, whose syntax and basic - set of options is described in + various entities called "units" of 12 different + types. Units encapsulate various objects that are + relevant for system boot-up and maintenance. The + majority of units are configured in unit configuration + files, whose syntax and basic set of options is + described in systemd.unit5, however some are created automatically from other - configuration or dynamically from system state. Units - may be 'active' (meaning started, bound, plugged in, - ... depending on the unit type, see below), or - 'inactive' (meaning stopped, unbound, unplugged, ...), - as well as in the process of being activated or - deactivated, i.e. between the two states (these states - are called 'activating', 'deactivating'). A special - 'failed' state is available as well which is very - similar to 'inactive' and is entered when the service - failed in some way (process returned error code on - exit, or crashed, or an operation timed out). If this - state is entered the cause will be logged, for later + configuration, dynamically from system state or + programmatically at runtime. Units may be "active" + (meaning started, bound, plugged in, ..., depending on + the unit type, see below), or "inactive" (meaning + stopped, unbound, unplugged, ...), as well as in the + process of being activated or deactivated, + i.e. between the two states (these states are called + "activating", "deactivating"). A special "failed" + state is available as well, which is very similar to + "inactive" and is entered when the service failed in + some way (process returned error code on exit, or + crashed, or an operation timed out). If this state is + entered, the cause will be logged, for later reference. Note that the various unit types may have a number of additional substates, which are mapped to the five generalized unit states described @@ -312,7 +291,7 @@ The following unit types are available: - Service units, which control + Service units, which start and control daemons and the processes they consist of. For details see systemd.service5. @@ -369,6 +348,18 @@ objects change or are modified. See systemd.path5. + Slice units may be used to + group units which manage system processes + (such as service and scope units) in a + hierarchical tree for resource management + purposes. See + systemd.slice5. + + Scope units are similar to + service units, but manage foreign processes + instead of starting them as well. See + systemd.scope5. + Units are named as their configuration @@ -393,7 +384,7 @@ and ordering dependencies are placed between two units. Also note that the majority of dependencies are implicitly created and maintained by systemd. In most - cases it should be unnecessary to declare additional + cases, it should be unnecessary to declare additional dependencies manually, however it is possible to do this. @@ -415,7 +406,7 @@ multi-user.target (for limited console-only boots for use in embedded or server environments, or similar; a subset of - graphical.target). However it is at the discretion of + graphical.target). However, it is at the discretion of the administrator to configure it as an alias to any other target unit. See systemd.special7 @@ -425,7 +416,7 @@ individual Linux control groups named after the unit which they belong to in the private systemd hierarchy. (see cgroups.txt + url="https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt">cgroups.txt for more information about control groups, or short "cgroups"). systemd uses this to effectively keep track of processes. Control group information is @@ -473,14 +464,14 @@ Systemd contains native implementations of various tasks that need to be executed as part of the - boot process. For example, it sets the host name or + boot process. For example, it sets the hostname or configures the loopback network device. It also sets up and mounts various API file systems, such as /sys or /proc. For more information about the concepts and - ideas behind systemd please refer to the Original Design Document. @@ -488,6 +479,21 @@ by systemd are covered by the Interface Stability Promise. + + Units may be generated dynamically at boot and + system manager reload time, for example based on other + configuration files or parameters passed on the kernel + command line. For details see the Generators + Specification. + + Systems which invoke systemd in a container + or initrd environment should implement the + Container + Interface or initrd + Interface specifications, respectively. @@ -520,7 +526,9 @@ disable commands of the systemctl1 - tool. + tool. Full list of directories is provided in + systemd.unit5. +
@@ -549,7 +557,9 @@ tool can handle both global (i.e. for all users) and private (for one user) enabling/disabling of - units. + units. Full list of directories is provided in + systemd.unit5. + @@ -592,7 +602,7 @@ - SIGTERM + SIGTERM Upon receiving this signal the systemd system manager @@ -612,7 +622,7 @@ - SIGINT + SIGINT Upon receiving this signal the systemd system manager will @@ -624,11 +634,11 @@ systemd user managers treat this signal the same way as - SIGTERM. + SIGTERM. - SIGWINCH + SIGWINCH When this signal is received the systemd system manager @@ -644,7 +654,7 @@ - SIGPWR + SIGPWR When this signal is received the systemd manager @@ -656,7 +666,7 @@ - SIGUSR1 + SIGUSR1 When this signal is received the systemd manager will try @@ -665,7 +675,7 @@ - SIGUSR2 + SIGUSR2 When this signal is received the systemd manager will log @@ -676,7 +686,7 @@ - SIGHUP + SIGHUP Reloads the complete daemon configuration. This is mostly @@ -685,7 +695,7 @@ - SIGRTMIN+0 + SIGRTMIN+0 Enters default mode, starts the default.target @@ -695,7 +705,7 @@ - SIGRTMIN+1 + SIGRTMIN+1 Enters rescue mode, starts the @@ -706,7 +716,7 @@ - SIGRTMIN+2 + SIGRTMIN+2 Enters emergency mode, starts the @@ -717,7 +727,7 @@ - SIGRTMIN+3 + SIGRTMIN+3 Halts the machine, starts the @@ -728,7 +738,7 @@ - SIGRTMIN+4 + SIGRTMIN+4 Powers off the machine, starts the @@ -739,7 +749,7 @@ - SIGRTMIN+5 + SIGRTMIN+5 Reboots the machine, starts the @@ -750,7 +760,7 @@ - SIGRTMIN+6 + SIGRTMIN+6 Reboots the machine via kexec, starts the @@ -761,31 +771,31 @@ - SIGRTMIN+13 + SIGRTMIN+13 Immediately halts the machine. - SIGRTMIN+14 + SIGRTMIN+14 Immediately powers off the machine. - SIGRTMIN+15 + SIGRTMIN+15 Immediately reboots the machine. - SIGRTMIN+16 + SIGRTMIN+16 Immediately reboots the machine with kexec. - SIGRTMIN+20 + SIGRTMIN+20 Enables display of status messages on the console, as @@ -796,7 +806,7 @@ - SIGRTMIN+21 + SIGRTMIN+21 Disables display of status messages on the console, as @@ -807,39 +817,52 @@ - SIGRTMIN+22 - SIGRTMIN+23 + SIGRTMIN+22 + SIGRTMIN+23 Sets the log level to debug - (resp. info on - SIGRTMIN+32), as + (or info on + SIGRTMIN+23), as controlled via systemd.log_level=debug - (resp. systemd.log_level=info - on SIGRTMIN+23) on + (or systemd.log_level=info + on SIGRTMIN+23) on the kernel command line. - SIGRTMIN+27 - SIGRTMIN+28 - SIGRTMIN+29 + SIGRTMIN+24 + + Immediately exits the + manager (only available for --user + instances). + + + + SIGRTMIN+26 + SIGRTMIN+27 + SIGRTMIN+28 + SIGRTMIN+29 Sets the log level to - console - (resp. kmsg on - SIGRTMIN+28; - resp. syslog-or-kmsg - on SIGRTMIN+29), as + journal-or-kmsg + (or console on + SIGRTMIN+27, + kmsg on + SIGRTMIN+28, + or syslog-or-kmsg + on SIGRTMIN+29), as controlled via - systemd.log_target=console - (resp. systemd.log_target=kmsg - on SIGRTMIN+28; - resp + systemd.log_target=journal-or-kmsg + (or systemd.log_target=console + on SIGRTMIN+27, + systemd.log_target=kmsg + on SIGRTMIN+28, + or systemd.log_target=syslog-or-kmsg - on SIGRTMIN+29) on + on SIGRTMIN+29) on the kernel command line. @@ -849,7 +872,7 @@ Environment - + $SYSTEMD_LOG_LEVEL systemd reads the @@ -948,11 +971,21 @@ Kernel Command Line - When run as system instance systemd parses a few kernel command line arguments: + When run as system instance systemd parses a + number of kernel command line + argumentsIf run inside a Linux + container these arguments may be passed as command + line arguments to systemd itself, next to any of the + command line options listed in the Options section + above. If run outside of Linux containers, these + arguments are parsed from + /proc/cmdline + instead.: - + systemd.unit= + rd.systemd.unit= Overrides the unit to activate on boot. Defaults to @@ -962,17 +995,21 @@ rescue.target or emergency.service. See systemd.special7 - for details about these - units. + for details about these units. The + option prefixed with + rd. is honored + only in the initial RAM disk (initrd), + while the one that is not prefixed only + in the main system. systemd.dump_core= Takes a boolean - argument. If + argument. If , systemd dumps core when it - crashes. Otherwise no core dump is + crashes. Otherwise, no core dump is created. Defaults to . @@ -981,9 +1018,9 @@ systemd.crash_shell= Takes a boolean - argument. If + argument. If , systemd spawns a shell when it - crashes. Otherwise no shell is + crashes. Otherwise, no shell is spawned. Defaults to , for security reasons, as the shell is not protected @@ -998,14 +1035,14 @@ argument. If positive systemd activates the specified virtual terminal when it crashes. Defaults to - -1. + -1. systemd.confirm_spawn= Takes a boolean - argument. If + argument. If , asks for confirmation when spawning processes. Defaults to . @@ -1015,24 +1052,20 @@ systemd.show_status= Takes a boolean - argument. If - shows terse service status updates on - the console during bootup. Defaults to - . - - - - systemd.sysv_console= - - Takes a boolean - argument. If - output of SysV init scripts will be - directed to the console. Defaults to + argument or the constant + auto. If + , shows terse + service status updates on the console + during bootup. + auto behaves like + until a service + fails or there is a significant delay + in boot. Defaults to , unless is passed as kernel command line option in which case it defaults to - . + auto. @@ -1051,15 +1084,127 @@ systemd.default_standard_output= systemd.default_standard_error= Controls default - standard output/error output for + standard output and error output for services, with the same effect as the - resp. + and command line arguments described - above. + above, respectively. + + systemd.setenv= + + Takes a string + argument in the form VARIABLE=VALUE. + May be used to set default environment + variables to add to forked child processes. + May be used more than once to set multiple + variables. + + + + quiet + + Turn off + status output at boot, much like + systemd.show_status=false + would. Note that this option is also + read by the kernel itself and disables + kernel log output. Passing this option + hence turns off the usual output from + both the system manager and the kernel. + + + + + debug + + Turn on debugging + output. This is equivalent to + systemd.log_level=debug. + Note that this option is also read by + the kernel itself and enables kernel + debug output. Passing this option + hence turns on the debug output from + both the system manager and the + kernel. + + + + -b + emergency + + Boot into emergency + mode. This is equivalent to + systemd.unit=emergency.target + and provided for compatibility + reasons and to be easier to type. + + + + single + s + S + 1 + + Boot into rescue + mode. This is equivalent to + systemd.unit=rescue.target + and provided for compatibility reasons + and to be easier to + type. + + + + 2 + 3 + 4 + 5 + + Boot into the + specified legacy SysV runlevel. These + are equivalent to + systemd.unit=runlevel2.target, + systemd.unit=runlevel3.target, + systemd.unit=runlevel4.target, + and systemd.unit=runlevel5.target, respectively, + and provided for compatibility reasons + and to be easier to + type. + + + + locale.LANG= + locale.LANGUAGE= + locale.LC_CTYPE= + locale.LC_NUMERIC= + locale.LC_TIME= + locale.LC_COLLATE= + locale.LC_MONETARY= + locale.LC_MESSAGES= + locale.LC_PAPER= + locale.LC_NAME= + locale.LC_ADDRESS= + locale.LC_TELEPHONE= + locale.LC_MEASUREMENT= + locale.LC_IDENTIFICATION= + + Set the system locale + to use. This overrides the settings in + /etc/locale.conf. For + more information see + locale.conf5 + and + locale7. + + + + For other kernel command line parameters + understood by components of the core OS, please refer + to + kernel-command-line7. @@ -1071,7 +1216,7 @@ Daemon status notification socket. This is an - AF_UNIX datagram socket and is used to + AF_UNIX datagram socket and is used to implement the daemon notification logic as implemented by sd_notify3. @@ -1079,25 +1224,12 @@ - /run/systemd/stdout-syslog-bridge - - Used internally by the - systemd-stdout-syslog-bridge.service - unit to connect STDOUT and/or STDERR - of spawned processes to - syslog3 - or the kernel log buffer. This is an - AF_UNIX stream - socket. - - - /run/systemd/shutdownd Used internally by the shutdown8 tool to implement delayed - shutdowns. This is an AF_UNIX datagram + shutdowns. This is an AF_UNIX datagram socket. @@ -1108,7 +1240,7 @@ communication channel between systemctl1 and the systemd process. This is an - AF_UNIX stream socket. This interface + AF_UNIX stream socket. This interface is private to systemd and should not be used in external projects. @@ -1132,14 +1264,20 @@ See Also + The systemd Homepage, + systemd-system.conf5, + locale.conf5, systemctl1, - systemadm1, + journalctl1, systemd-notify1, daemon7, - sd-daemon7, + sd-daemon3, systemd.unit5, systemd.special5, - pkg-config1 + pkg-config1, + kernel-command-line7, + bootup7, + systemd.directives7 diff --git a/man/telinit.xml b/man/telinit.xml index fec059a..1949c95 100644 --- a/man/telinit.xml +++ b/man/telinit.xml @@ -8,20 +8,21 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + telinit @@ -73,14 +74,13 @@ - Prints a short help - text and exits. + - Don't send wall + Do not send wall message before reboot/halt/power-off. @@ -171,7 +171,7 @@ Exit status - On success 0 is returned, a non-zero failure + On success, 0 is returned, a non-zero failure code otherwise. diff --git a/man/timedatectl.xml b/man/timedatectl.xml new file mode 100644 index 0000000..ee75d42 --- /dev/null +++ b/man/timedatectl.xml @@ -0,0 +1,247 @@ + + + + + + + + + timedatectl + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + timedatectl + 1 + + + + timedatectl + Control the system time and date + + + + + timedatectl OPTIONS COMMAND + + + + + Description + + timedatectl may be used to + query and change the system clock and its + settings. + + + + Options + + The following options are understood: + + + + + + Do not query the user + for authentication for privileged + operations. + + + + + + If + set-local-rtc is + invoked and this option is passed, the + system clock is synchronized from the + RTC again, taking the new setting into + account. Otherwise, the RTC is + synchronized from the system + clock. + + + + + + + + + + + The following commands are understood: + + + + status + + Show current settings + of the system clock and + RTC. + + + + set-time [TIME] + + Set the system clock + to the specified time. This will also + update the RTC time accordingly. The time + may be specified in the format + "2012-10-30 + 18:17:16". + + + + set-timezone [TIMEZONE] + + Set the system time + zone to the specified value. Available + timezones can be listed with + list-timezones. If + the RTC is configured to be in the + local time, this will also update the + RTC time. This call will alter the + /etc/localtime + symlink. See + localtime5 + for more + information. + + + + list-timezones + + List available time + zones, one per line. Entries from the + list can be set as the system + timezone with + set-timezone. + + + + set-local-rtc [BOOL] + + Takes a boolean + argument. If 0, the + system is configured to maintain the + RTC in universal time. If + 1, it will maintain + the RTC in local time instead. Note + that maintaining the RTC in the local + timezone is not fully supported and + will create various problems with time + zone changes and daylight saving + adjustments. If at all possible, keep the + RTC in UTC mode. Note that invoking this + will also synchronize the RTC from the + system clock, unless + is + passed (see above). This command will + change the 3rd line of + /etc/adjtime, as + documented in + hwclock8. + + + + set-ntp [BOOL] + + Takes a boolean + argument. Controls whether NTP based + network time synchronization is + enabled (if + available). + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + + + Examples + Show current settings: + $ timedatectl + Local time: Fri, 2012-11-02 09:26:46 CET + Universal time: Fri, 2012-11-02 08:26:46 UTC + RTC time: Fri, 2012-11-02 08:26:45 + Timezone: Europe/Warsaw + UTC offset: +0100 + NTP enabled: no +NTP synchronized: no + RTC in local TZ: no + DST active: no + Last DST change: CEST → CET, DST became inactive + Sun, 2012-10-28 02:59:59 CEST + Sun, 2012-10-28 02:00:00 CET + Next DST change: CET → CEST, DST will become active + the clock will jump one hour forward + Sun, 2013-03-31 01:59:59 CET + Sun, 2013-03-31 03:00:00 CEST + + + Enable an NTP daemon (chronyd): + $ timedatectl set-ntp true +==== AUTHENTICATING FOR org.freedesktop.timedate1.set-ntp === +Authentication is required to control whether network time synchronization shall be enabled. +Authenticating as: user +Password: ******** +==== AUTHENTICATION COMPLETE === + + $ systemctl status chronyd.service +chronyd.service - NTP client/server + Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled) + Active: active (running) since Fri, 2012-11-02 09:36:25 CET; 5s ago +... + + + + + See Also + + systemd1, + hwclock8, + date1, + localtime5, + systemctl1, + systemd-timedated.service8 + + + + diff --git a/man/timezone.xml b/man/timezone.xml deleted file mode 100644 index 4e33279..0000000 --- a/man/timezone.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - /etc/timezone - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - timezone - 5 - - - - timezone - Local time zone configuration file - - - - /etc/timezone - - - - Description - - The /etc/timezone file - configures the system-wide time zone of the local - system that is used by applications for presentation - to the user. It should contain a single - newline-terminated line consisting of a time zone - identifier such as - Europe/Berlin. The file - /etc/localtime corresponds with - /etc/timezone and contains the - binary time zone data for the time zone. These files - should always be changed simultaneously and kept in - sync. - - The time zone may be overridden for individual - programs by using the TZ environment variable. See - environ7. - - - - History - - The simple configuration file format of - /etc/timezone originates from - Debian GNU/Linux. - - - - See Also - - systemd1 - - - - diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 7f4c45c..812129f 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -7,16 +7,16 @@ Copyright 2010 Brandon Philips systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> @@ -47,74 +47,134 @@ - /usr/lib/tmpfiles.d/*.conf /etc/tmpfiles.d/*.conf /run/tmpfiles.d/*.conf + /usr/lib/tmpfiles.d/*.conf Description - systemd-tmpfiles uses the - configuration files from the above directories to describe the - creation, cleaning and removal of volatile and - temporary files and directories which usually reside - in directories such as /run - or /tmp. + systemd-tmpfiles uses the + configuration files from the above directories to describe the + creation, cleaning and removal of volatile and + temporary files and directories which usually reside + in directories such as /run + or /tmp. - Configuration Format - - Each configuration file is named in the style of - <program>.conf. - Files in /etc/ overwrite - files with the same name in /usr/lib/. - Files in /run overwrite files with - the same name in /etc/ and - /usr/lib/. Packages should install their - configuration files in /usr/lib/, files - in /etc/ are reserved for the local - administration, which possibly decides to overwrite the - configurations installed from packages. All files are sorted - by filename in alphabetical order, regardless in which of the - directories they reside, to ensure that a specific - configuration file takes precedence over another file with - an alphabetically later name. - - The configuration format is one line per path - containing action, mode, ownership and age - fields: - - Type Path Mode UID GID Age -d /run/user 0755 root root 10d + Configuration Format + + Each configuration file shall be named in the + style of + package.conf + or + package-part.conf. + The second variant should be used when it is desirable + to make it easy to override just this part of + configuration. + + Files in /etc/tmpfiles.d + override files with the same name in + /usr/lib/tmpfiles.d and + /run/tmpfiles.d. Files in + /run/tmpfiles.d override files + with the same name in + /usr/lib/tmpfiles.d. Packages + should install their configuration files in + /usr/lib/tmpfiles.d. Files in + /etc/tmpfiles.d 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 the directories they reside in. If multiple files + specify the same path, the entry in the file with the + lexicographically earliest name will be applied, all + all other conflicting entries logged as errors. + + If the administrator wants to disable a + configuration file supplied by the vendor, the + recommended way is to place a symlink to + /dev/null in + /etc/tmpfiles.d/ bearing the + same filename. + + The configuration format is one line per path + containing type, path, mode, ownership, age, and argument + fields: + + #Type Path Mode UID GID Age Argument +d /run/user 0755 root root 10d - +L /tmp/foobar - - - - /dev/null Type + + The type consists of a single letter and + optionally an exclamation mark. + + The following line types are understood: + f - Create a file if it doesn't exist yet + Create a file if it does not exist yet. If the argument parameter is given, it will be written to the file. F - Create or truncate a file + Create or truncate a file. If the argument parameter is given, it will be written to the file. + + + + w + Write the argument parameter to a file, if the file exists. + Lines of this type accept shell-style globs in place of normal path + names. The argument parameter will be written without a trailing + newline. C-style backslash escapes are interpreted. d - Create a directory if it doesn't exist yet + Create a directory if it does not exist yet. D - Create or empty a directory + Create or empty a directory. p - Create a named pipe (FIFO) if it doesn't exist yet + Create a named pipe (FIFO) if it does not exist yet. + + + + L + Create a symlink if it does not exist yet. + + + + c + Create a character device node if it does not exist yet. + + + + b + Create a block device node if it does not exist yet. + + + + m + If the + specified file path exists, + adjust its access mode, group + and user to the specified + values and reset the SELinux + security context. If it does not exist, do + nothing. @@ -125,23 +185,45 @@ d /run/user 0755 root root 10d as controlled with the Age parameter. Note that lines of this type do not influence the - effect of r or R lines. Lines - of this type accept + effect of r + or R lines. + Lines of this type accept shell-style globs in place of - of normal path - names. + normal path names. + + + + + X + Ignore a path + during cleaning. Use this type + to exclude paths from clean-up + as controlled with the Age + parameter. Unlike + x, this + parameter will not exclude the + content if path is a + directory, but only directory + itself. Note that lines of + this type do not influence the + effect of r + or R lines. + Lines of this type accept + shell-style globs in place of + normal path names. + r Remove a file - or directory if it - exists. This may not be used - to remove non-empty - directories, use R for - that. Lines of this type - accept shell-style globs in - place of normal path + or directory if it exists. + This may not be used to remove + non-empty directories, use + R for that. + Lines of this type accept + shell-style globs in place of + normal path names. @@ -155,7 +237,104 @@ d /run/user 0755 root root 10d place of normal path names. + + + z + Restore + SELinux security context + and set ownership and access + mode of a file or directory if + it exists. Lines of this type + accept shell-style globs in + place of normal path names. + + + + + Z + Recursively + restore SELinux security + context and set + ownership and access mode of a + path and all its + subdirectories (if it is a + directory). Lines of this type + accept shell-style globs in + place of normal path + names. + + + If the exclamation mark is used, this + line is only safe of execute during boot, and + can break a running system. Lines without the + exclamation mark are presumed to be safe to + execute at any time, e.g. on package upgrades. + systemd-tmpfiles will + execute line with an exclamation mark only if + option is given. + + + For example: + # Make sure these are created by default so that nobody else can +d /tmp/.X11-unix 1777 root root 10d + +# Unlink the X11 lock files +r! /tmp/.X[0-9]*-lock + The second line in contrast to the first one + would break a running system, and will only be + executed with . + + + + Path + + The file system path specification supports simple specifier + expansion. The following expansions are + understood: + + + Specifiers available + + + + + + + Specifier + Meaning + Details + + + + + %m + Machine ID + The machine ID of the running system, formatted as string. See machine-id5 for more information. + + + %b + Boot ID + The boot ID of the running system, formatted as string. See random4 for more information. + + + %H + Host name + The hostname of the running system. + + + %v + Kernel release + Identical to uname -r output. + + + %% + Escaped % + Single percent sign. + + + +
@@ -163,9 +342,15 @@ d /run/user 0755 root root 10d The file access mode to use when creating this file or directory. If omitted or - when set to - the default is used: 0755 for - directories, 0644 for files. This parameter is - ignored for x, r, R lines. + when set to -, the default is used: 0755 for + directories, 0644 for all other file objects. + For z, Z + lines, if omitted or when set to + -, the file access mode + will not be modified. This parameter is + ignored for x, + r, R, + L lines. @@ -174,9 +359,15 @@ d /run/user 0755 root root 10d The user and group to use for this file or directory. This may either be a numeric user/group ID or a user or group name. If - omitted or when set to - the default 0 (root) - is used. . These parameters are ignored for x, - r, R lines. + omitted or when set to -, + the default 0 (root) is used. For + z, Z + lines, when omitted or when set to -, the file + ownership will not be modified. These + parameters are ignored for + x, r, + R, L + lines. @@ -184,7 +375,7 @@ d /run/user 0755 root root 10d The date field, when set, is used to decide what files to delete when cleaning. If a file or directory is older than the current - time minus the age field it is deleted. The + time minus the age field, it is deleted. The field format is a series of integers each followed by one of the following postfixes for the respective time units: @@ -201,12 +392,45 @@ d /run/user 0755 root root 10d us
- If multiple integers and units are specified the time - values are summed up. + If multiple integers and units are specified, the time + values are summed up. If an integer is given without a unit, + s is assumed. + + + When the age is set to zero, the files are cleaned + unconditionally. + + The age field only applies to lines + starting with d, + D, and + x. If omitted or set to + -, no automatic clean-up is + done. + + If the age field starts with a tilde + character ~, the clean-up + is only applied to files and directories one + level inside the directory specified, but not + the files and directories immediately inside + it. + - The age field only applies to lines starting with - d, D and x. If omitted or set to - no automatic clean-up - is done. + + Argument + + For L lines + determines the destination path of the + symlink. For c, + b determines the + major/minor of the device node, with major and + minor formatted as integers, separated by + :, e.g. + 1:3. For + f, F, + and w may be used to + specify a short string that is written to the + file, suffixed by a newline. Ignored for all + other lines. @@ -217,16 +441,24 @@ d /run/user 0755 root root 10d /etc/tmpfiles.d/screen.conf example screen needs two directories created at boot with specific modes and ownership. - d /var/run/screens 1777 root root 10d + d /var/run/screens 1777 root root 10d d /var/run/uscreens 0755 root root 10d12h + + /etc/tmpfiles.d/abrt.conf example + abrt needs a directory created at boot with specific mode and ownership and its content should be preserved. + + d /var/tmp/abrt 0755 abrt abrt +x /var/tmp/abrt/* + See Also systemd1, - systemd-tmpfiles8 + systemd-tmpfiles8, + systemd-delta1 diff --git a/man/udev.xml b/man/udev.xml new file mode 100644 index 0000000..95b37fd --- /dev/null +++ b/man/udev.xml @@ -0,0 +1,1051 @@ + + + + + + + udev + systemd + + + Developer + Greg + Kroah-Hartmann + greg@kroah.com + + + Developer + Kay + Sievers + kay@vrfy.org + + + + + + udev + 7 + + + + udev + Dynamic device management + + + Description + udev supplies the system software with device events, manages permissions + of device nodes and may create additional symlinks in the /dev + directory, or renames network interfaces. The kernel usually just assigns unpredictable + device names based on the order of discovery. Meaningful symlinks or network device + names provide a way to reliably identify devices based on their properties or + current configuration. + + The udev daemon, systemd-udevd.service + 8, receives device uevents directly from + the kernel whenever a device is added or removed from the system, or it changes its + state. When udev receives a device event, it matches its configured set of rules + against various device attributes to identify the device. Rules that match may + provide additional device information to be stored in the udev database or + to be used to create meaningful symlink names. + + All device information udev processes is stored in the udev database and + sent out to possible event subscribers. Access to all stored data and the event + sources is provided by the library libudev. + + + Rules Files + The udev rules are read from the files located in the + system rules directory /usr/lib/udev/rules.d, + the volatile runtime directory /run/udev/rules.d + and the local administration directory /etc/udev/rules.d. + 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 /etc + have the highest priority, files in /run take precedence + over files with the same name in /usr/lib. This can be + used to override a system-supplied rules file with a local file if needed; + a symlink in /etc with the same name as a rules file in + /usr/lib, pointing to /dev/null, + disables the rules file entirely. Rule files must have the extension + .rules; other extensions are ignored. + + Every line in the rules file contains at least one key-value pair. + Except for empty lines or lines beginning with #, which are ignored. + There are two kinds of keys: match and assignment. + If all match keys match against their values, the rule gets applied and the + assignment keys get the specified values assigned. + + A matching rule may rename a network interface, add symlinks + pointing to the device node, or run a specified program as part of + the event handling. + + A rule consists of a comma-separated list of one or more key-value pairs. + Each key has a distinct operation, depending on the used operator. Valid + operators are: + + + == + + Compare for equality. + + + + + != + + Compare for inequality. + + + + + = + + Assign a value to a key. Keys that represent a list are reset + and only this single value is assigned. + + + + + += + + Add the value to a key that holds a list of entries. + + + + + := + + Assign a value to a key finally; disallow any later changes. + + + + + The following key names can be used to match against device properties. + Some of the keys also match against properties of the parent devices in sysfs, + not only the device that has generated the event. If multiple keys that match + a parent device are specified in a single rule, all these keys must match at + one and the same parent device. + + + ACTION + + Match the name of the event action. + + + + + DEVPATH + + Match the devpath of the event device. + + + + + KERNEL + + Match the name of the event device. + + + + + NAME + + Match the name of a network interface. It can be used once the + NAME key has been set in one of the preceding rules. + + + + + SYMLINK + + Match the name of a symlink targeting the node. It can + be used once a SYMLINK key has been set in one of the preceding + rules. There may be multiple symlinks; only one needs to match. + + + + + + SUBSYSTEM + + Match the subsystem of the event device. + + + + DRIVER + + Match the driver name of the event device. Only set this key for devices + which are bound to a driver at the time the event is generated. + + + + ATTR{filename} + + Match sysfs attribute values of the event device. Trailing + whitespace in the attribute values is ignored unless the specified match + value itself contains trailing whitespace. + + + + + + KERNELS + + Search the devpath upwards for a matching device name. + + + + + SUBSYSTEMS + + Search the devpath upwards for a matching device subsystem name. + + + + + DRIVERS + + Search the devpath upwards for a matching device driver name. + + + + + ATTRS{filename} + + Search the devpath upwards for a device with matching sysfs attribute values. + If multiple ATTRS matches are specified, all of them + must match on the same device. Trailing whitespace in the attribute values is ignored + unless the specified match value itself contains trailing whitespace. + + + + + TAGS + + Search the devpath upwards for a device with matching tag. + + + + + ENV{key} + + Match against a device property value. + + + + + TAG + + Match against a device tag. + + + + + TEST{octal mode mask} + + Test the existence of a file. An octal mode mask can be specified + if needed. + + + + + PROGRAM + + Execute a program to determine whether there + is a match; the key is true if the program returns + successfully. The device properties are made available to the + executed program in the environment. The program's standard ouput + is available in the RESULT key. + This can only be used for very short-running foreground tasks. For details, + see RUN. + + + + + RESULT + + Match the returned string of the last PROGRAM call. + This key can be used in the same or in any later rule after a + PROGRAM call. + + + + + Most of the fields support shell glob pattern matching. The following + pattern characters are supported: + + + * + + Matches zero or more characters. + + + + ? + + Matches any single character. + + + + [] + + Matches any single character specified within the brackets. For + example, the pattern string tty[SR] + would match either ttyS or ttyR. + Ranges are also supported via the - character. + For example, to match on the range of all digits, the pattern + [0-9] could be used. If the first character + following the [ is a !, + any characters not enclosed are matched. + + + + + The following keys can get values assigned: + + + NAME + + The name to use for a network interface. The name of a device node + cannot be changed by udev, only additional symlinks can be created. + + + + + SYMLINK + + The name of a symlink targeting the node. Every matching rule adds + this value to the list of symlinks to be created. + The set of characters to name a symlink is limited. Allowed + characters are 0-9A-Za-z#+-.:=@_/, valid UTF-8 character + sequences, and \x00 hex encoding. All other + characters are replaced by a _ character. + Multiple symlinks may be specified by separating the names by the + space character. In case multiple devices claim the same name, the link + always points to the device with the highest link_priority. If the current + device goes away, the links are re-evaluated and the device with the + next highest link_priority becomes the owner of the link. If no + link_priority is specified, the order of the devices (and which one of + them owns the link) is undefined. + Symlink names must never conflict with the kernel's default device + node names, as that would result in unpredictable behavior. + + + + + + OWNER, GROUP, MODE + + The permissions for the device node. Every specified value overrides + the compiled-in default value. + + + + + SECLABEL{module} + + Applies the specified Linux Security Module label to the device node. + + + + + ATTR{key} + + The value that should be written to a sysfs attribute of the + event device. + + + + + ENV{key} + + Set a device property value. Property names with a leading . + are neither stored in the database nor exported to events or + external tools (run by, for example, the PROGRAM + match key). + + + + + TAG + + Attach a tag to a device. This is used to filter events for users + of libudev's monitor functionality, or to enumerate a group of tagged + devices. The implementation can only work efficiently if only a few + tags are attached to a device. It is only meant to be used in + contexts with specific device filter requirements, and not as a + general-purpose flag. Excessive use might result in inefficient event + handling. + + + + + RUN{type} + + Add a program to the list of programs to be executed after + processing all the rules for a specific event, depending on + type: + + + program + + Execute an external program specified as the assigned + value. If no absolute path is given, the program is expected + to live in /usr/lib/udev; otherwise, the + absolute path must be specified. + This is the default if no type + is specified. + + + + builtin + + As program, but use one of the + built-in programs rather than an external one. + + + + The program name and following arguments are separated by spaces. + Single quotes can be used to specify arguments with spaces. + This can only be used for very short-running foreground tasks. Running an + event process for a long period of time may block all further events for + this or a dependent device. + Starting daemons or other long-running processes is not appropriate + for udev; the forked processes, detached or not, will be unconditionally + killed after the event handling has finished. + + + + + LABEL + + A named label to which a GOTO may jump. + + + + + GOTO + + Jumps to the next LABEL with a matching name. + + + + + IMPORT{type} + + Import a set of variables as device properties, + depending on type: + + + program + + Execute an external program specified as the assigned value and + import its output, which must be in environment key + format. Path specification, command/argument separation, + and quoting work like in RUN. + + + + builtin + + Similar to program, but use one of the + built-in programs rather than an external one. + + + + file + + Import a text file specified as the assigned value, the content + of which must be in environment key format. + + + + db + + Import a single property specified as the assigned value from the + current device database. This works only if the database is already populated + by an earlier event. + + + + cmdline + + Import a single property from the kernel command line. For simple flags + the value of the property is set to 1. + + + + parent + + Import the stored keys from the parent device by reading + the database entry of the parent device. The value assigned to + is used as a filter of key names + to import (with the same shell glob pattern matching used for + comparisons). + + + + This can only be used for very short-running foreground tasks. For details + see . + + + + + WAIT_FOR + + Wait for a file to become available or until a timeout of + 10 seconds expires. The path is relative to the sysfs device; + if no path is specified, this waits for an attribute to appear. + + + + + OPTIONS + + Rule and device options: + + + + + Specify the priority of the created symlinks. Devices with higher + priorities overwrite existing symlinks of other devices. The default is 0. + + + + + + Number of seconds an event waits for operations to finish before + giving up and terminating itself. + + + + + + Usually control and other possibly unsafe characters are replaced + in strings used for device naming. The mode of replacement can be specified + with this option. + + + + + + Apply the permissions specified in this rule to the + static device node with the specified name. Also, for every + tag specified in this rule, create a symlink + in the directory + /run/udev/static_node-tags/tag + pointing at the static device node with the specified name. + Static device node creation is performed by systemd-tmpfiles + before systemd-udevd is started. The static nodes might not + have a corresponding kernel device; they are used to trigger + automatic kernel module loading when they are accessed. + + + + + + Watch the device node with inotify; when the node is + closed after being opened for writing, a change uevent is + synthesized. + + + + + + Disable the watching of a device node with inotify. + + + + + + + + The NAME, SYMLINK, + PROGRAM, OWNER, + GROUP, MODE, and + RUN fields support simple string substitutions. + The RUN substitutions are performed after all rules + have been processed, right before the program is executed, allowing for + the use of device properties set by earlier matching rules. For all other + fields, substitutions are performed while the individual rule is being + processed. The available substitutions are: + + + , + + The kernel name for this device. + + + + + , + + The kernel number for this device. For example, + sda3 has kernel number 3. + + + + + + , + + The devpath of the device. + + + + + , + + The name of the device matched while searching the devpath + upwards for , , + , and . + + + + + + + + The driver name of the device matched while searching the + devpath upwards for , + , , and + . + + + + + + , + + The value of a sysfs attribute found at the device where + all keys of the rule have matched. If the matching device does not + have such an attribute, and a previous , + , , or + test selected a parent device, then the + attribute from that parent device is used. + + If the attribute is a symlink, the last element of the + symlink target is returned as the value. + + + + + + , + + A device property value. + + + + + , + + The kernel major number for the device. + + + + + , + + The kernel minor number for the device. + + + + + , + + The string returned by the external program requested with + PROGRAM. + A single part of the string, separated by a space character, may be selected + by specifying the part number as an attribute: %c{N}. + If the number is followed by the + character, this part plus all remaining parts + of the result string are substituted: %c{N+}. + + + + + , + + The node name of the parent device. + + + + + + + The current name of the device. If not changed by a rule, it is the + name of the kernel device. + + + + + + + A space-separated list of the current symlinks. The value is + only set during a remove event or if an earlier rule assigned a value. + + + + + , + + The udev_root value. + + + + + , + + The sysfs mount point. + + + + + , + + The name of the device node. + + + + + + + The % character itself. + + + + + + + The $ character itself. + + + + + + Hardware Database Files + The hwdb files are read from the files located in the + system hwdb directory /usr/lib/udev/hwdb.d, + the volatile runtime directory /run/udev/hwdb.d + and the local administration directory /etc/udev/hwdb.d. + All hwdb files are collectively sorted and processed in lexical order, + regardless of the directories in which they live. However, files with + identical filenames replace each other. Files in /etc + have the highest priority, files in /run take precedence + over files with the same name in /usr/lib. This can be + used to override a system-supplied hwdb file with a local file if needed; + a symlink in /etc with the same name as a hwdb file in + /usr/lib, pointing to /dev/null, + disables the hwdb file entirely. hwdb files must have the extension + .hwdb; other extensions are ignored. + + The hwdb file contains data records consisting of matches and + associated key-value pairs. Every record in the hwdb starts with one or + more match string, specifying a shell glob to compare the database + lookup string against. Multiple match lines are specified in additional + consecutive lines. Every match line is compared indivdually, they are + combined by OR. Every match line must start at the first character of + the line. + + The match lines are followed by one or more key-value pair lines, which + are recognized by a leading space character. The key name and value are separated + by =. An empty line signifies the end + of a record. Lines beginning with # are ignored. + + The content of all hwdb files is read by + udevadm8 + and compiled to a binary database located at /etc/udev/hwdb.bin. + During runtime only the binary database is used. + + + Network Link Configuration + Network link configuration is performed by the net_setup_link + udev builtin. + + The link files are read from the files located in the + system network directory /usr/lib/systemd/network, + the volatile runtime network directory /run/systemd/network + and the local administration network directory /etc/systemd/network. + Link files must have the extension .link; other extensions are ignored. + All link files are collectively sorted and processed in lexical order, + regardless of the directories in which they live. However, files with + identical filenames replace each other. Files in /etc + have the highest priority, files in /run take precedence + over files with the same name in /usr/lib. This can be + used to override a system-supplied link file with a local file if needed; + a symlink in /etc with the same name as a link file in + /usr/lib, pointing to /dev/null, + disables the link file entirely. + + The link file contains a [Match] section, which + determines if a given link file may be applied to a given device; and a + [Link] section specifying how the device should be + configured. The first (in lexical order) of the link files that matches + a given device is applied. + + A link file is said to match a device if each of the entries in the + [Match] section matches, or if the section is empty. + The following keys are accepted: + + + + MACAddress= + + The hardware address. + + + + + Path= + + The persistent path, as exposed by the udev property ID_PATH. + May contain shell style globs. + + + + Driver= + + The driver currently bound to the device, as exposed by the + udev property DRIVER of its parent device, or if + that is not set the driver as exposed by ethtool -i + of the device itself. + + + + Type= + + The device type, as exposed by the udev property DEVTYPE. + + + + Host= + + Matches against the hostname or machine ID of the + host. See ConditionHost= in + systemd.unit5 + for details. + + + + Virtualization= + + Checks whether the system is executed in a virtualized + environment and optionally test whether it is a specific + implementation. See ConditionVirtualization= in + systemd.unit5 + for details. + + + + KernelCommandLine= + + Checks whether a specific kernel command line option is + set (or if prefixed with the exclamation mark unset). See + ConditionKernelCommandLine= in + systemd.unit5 + for details. + + + + Architecture= + + Checks whether the system is running on a specific + architecture. See ConditionArchitecture= in + systemd.unit5 + for details. + + + + + The [Link] section accepts the following keys: + + + + Description= + + A description of the device. + + + + Alias= + + The ifalias is set to this value. + + + + MACAddressPolicy= + + The policy by which the MAC address should be set. The + available policies are: + + + + persistent + + If the hardware has a persistent MAC address, as most + hardware should, and this is used by the kernel, nothing is + done. Otherwise, a new MAC address is generated which is + guaranteed to be the same on every boot for the given + machine and the given device, but which is otherwise random. + + + + + random + + If the kernel is using a random MAC address, nothing is + done. Otherwise, a new address is randomly generated each + time the device appears, typically at boot. + + + + + + + + MACAddress= + + The MAC address to use, if no MACAddressPolicy= + is specified. + + + + + NamePolicy= + + An ordered, space-separated list of policies by which the + interface name should be set. NamePolicy may + be disabled by specifying net.ifnames=0 on the + kernel commandline. 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 ID_NET_NAME, + which is, by default, used by a udev rule to set + NAME. The available policies are: + + + + database + + The name is set based on entries in the Hardware + Database with the key + ID_NET_NAME_FROM_DATABASE. + + + + + onboard + + The name is set based on information given by the + firmware for on-board devices, as exported by the udev + property ID_NET_NAME_ONBOARD. + + + + + slot + + The name is set based on information given by the + firmware for hot-plug devices, as exported by the udev + property ID_NET_NAME_SLOT. + + + + + path + + The name is set based on the device's physical location, + as exported by the udev property + ID_NET_NAME_PATH. + + + + + mac + + The name is set based on the device's persistent MAC + address, as exported by the udev property + ID_NET_NAME_MAC. + + + + + + + + Name= + + The interface name to use in case all the policies specified + in NamePolicy= fail, or in case + NamePolicy= is missing or disabled. + + + + + MTUBytes= + + The maximum transmission unit in bytes to set for + the device. The usual suffixes K, M, G, are supported and + are understood to the base of 1024. + + + + BitsPerSecond= + + The speed to set for the device, the value is + rounded down to the nearest Mbps. The usual suffixes K, M, + G, are supported and are understood to the base of + 1000. + + + + Duplex= + + The duplex mode to set for the device. The accepted values + are half and full. + + + + + WakeOnLan= + + The Wake-on-LAN policy to set for the device. The supported + values are: + + + + phy + + Wake on PHY activity. + + + + magic + + Wake on receipt of a magic packet. + + + + off + + Never wake. + + + + + + + + + + See Also + + + systemd-udevd.service8 + , + + udevadm8 + + + + diff --git a/man/udevadm.xml b/man/udevadm.xml new file mode 100644 index 0000000..a3f8d54 --- /dev/null +++ b/man/udevadm.xml @@ -0,0 +1,602 @@ + + + + + + + udevadm + systemd + + + Developer + Kay + Sievers + kay@vrfy.org + + + + + + udevadm + 8 + + + + + udevadmudev management tool + + + + + udevadm + + + + + + udevadm info options + + + udevadm trigger options + + + udevadm settle options + + + udevadm control command + + + udevadm monitor options + + + udevadm hwdb options + + + udevadm test options devpath + + + udevadm test-builtin options command devpath + + + + Description + udevadm expects a command and command + specific options. It controls the runtime behavior of + systemd-udevd, requests kernel events, manages + the event queue, and provides simple debugging mechanisms. + + + OPTIONS + + + + + Print debug messages to standard error. + + + + + + Print version number. + + + + + + + Print help text. + + + + + udevadm info <optional><replaceable>OPTIONS</replaceable></optional> <optional><replaceable>DEVPATH</replaceable>|<replaceable>FILE</replaceable></optional> + Queries the udev database for device information + stored in the udev database. It can also query the properties + of a device from its sysfs representation to help creating udev + rules that match this device. + + + + + + Query the database for the specified type of device + data. It needs the or + to identify the specified device. + Valid TYPEs are: + name, symlink, + path, property, + all. + + + + + + + The /sys path of the device to + query, e.g. + /sys/class/block/sda. + Note that this option usually is not very useful, since + udev can guess the type of the + argument, so udevadm + --devpath=/class/block/sda is equivalent to + udevadm /sys/class/block/sda. + + + + + + + The name of the device node or a symlink to query, + e.g. /dev/sda. + Note that this option usually is not very useful, since + udev can guess the type of the + argument, so udevadm --name=sda is + equivalent to udevadm /dev/sda. + + + + + + + Print absolute paths in name or symlink + query. + + + + + + + Print all sysfs properties of the specified device that can be used + in udev rules to match the specified device. It prints all devices + along the chain, up to the root of sysfs that can be used in udev rules. + + + + + + + Print output as key/value pairs. Values are enclosed in single quotes. + + + + + + + Add a prefix to the key name of exported values. + + + + + + + Print major/minor numbers of the underlying device, where the file + lives on. + + + + + + + Export the content of the udev database. + + + + + + + Cleanup the udev database. + + + + + + Print version. + + + + + + + Print help text. + + + + + + udevadm trigger <optional>options</optional> + Request device events from the kernel. Primarily used to replay events at system coldplug time. + + + + + + Print the list of devices which will be triggered. + + + + + + + Do not actually trigger the event. + + + + + + + Trigger a specific type of devices. Valid types are: + devices, subsystems. + The default value is devices. + + + + + + + Type of event to be triggered. The default value is + change. + + + + + + + Trigger events for devices which belong to a + matching subsystem. This option can be specified multiple + times and supports shell style pattern matching. + + + + + + + Do not trigger events for devices which belong to a matching subsystem. This option + can be specified multiple times and supports shell style pattern matching. + + + + + + + Trigger events for devices with a matching sysfs + attribute. If a value is specified along with the + attribute name, the content of the attribute is matched + against the given value using shell style pattern + matching. If no value is specified, the existence of the + sysfs attribute is checked. This option can be specified + multiple times. + + + + + + + Do not trigger events for devices with a matching + sysfs attribute. If a value is specified along with the + attribute name, the content of the attribute is matched + against the given value using shell style pattern + matching. If no value is specified, the existence of the + sysfs attribute is checked. This option can be specified + multiple times. + + + + + + + Trigger events for devices with a matching property + value. This option can be specified multiple times and + supports shell style pattern matching. + + + + + + + Trigger events for devices with a matching tag. This + option can be specified multiple times. + + + + + + + Trigger events for devices with a matching sys + device name. This option can be specified multiple times + and supports shell style pattern matching. + + + + + + + Trigger events for all children of a given + device. + + + + + + + Print help text. + + + + + + udevadm settle <optional>options</optional> + Watches the udev event queue, and exits if all current events are handled. + + + + + + Maximum number of seconds to wait for the event + queue to become empty. The default value is 120 seconds. A + value of 0 will check if the queue is empty and always + return immediately. + + + + + + + Wait only for events after the given sequence + number. + + + + + + + Wait only for events before the given sequence number. + + + + + + + Stop waiting if file exists. + + + + + + + Do not print any output, like the remaining queue entries when reaching the timeout. + + + + + + + Print help text. + + + + + + udevadm control <replaceable>command</replaceable> + Modify the internal state of the running udev daemon. + + + + + + Signal and wait for systemd-udevd to exit. + + + + + + + Set the internal log level of systemd-udevd. Valid values are the numerical + syslog priorities or their textual representations: , + and . + + + + + + + Signal systemd-udevd to stop executing new events. Incoming events + will be queued. + + + + + + + Signal systemd-udevd to enable the execution of events. + + + + + + + Signal systemd-udevd to reload the rules files and other databases like the kernel + module index. Reloading rules and databases does not apply any changes to already + existing devices; the new configuration will only be applied to new events. + + + + + + + Set a global property for all events. + + + + + value + + Set the maximum number of events, systemd-udevd will handle at the + same time. + + + + seconds + + The maximum number of seconds to wait for a reply from systemd-udevd. + + + + + + + Print help text. + + + + + + udevadm monitor <optional>options</optional> + Listens to the kernel uevents and events sent out by a udev rule + and prints the devpath of the event to the console. It can be used to analyze the + event timing, by comparing the timestamps of the kernel uevent and the udev event. + + + + + + + Print the kernel uevents. + + + + + + + Print the udev event after the rule processing. + + + + + + + Also print the properties of the event. + + + + + + + Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass. + + + + + + + Filter events by property. Only udev events with a given tag attached will pass. + + + + + + + Print help text. + + + + + + udevadm hwdb <optional>options</optional> + Maintain the hardware database index in /etc/udev/hwdb.bin. + + + + + + Compile the hardware database information located in /usr/lib/udev/hwdb.d/, + /etc/udev/hwdb.d/ and store it in /etc/udev/hwdb.bin. This should be done after + any update to the source files; it will not be called automatically. The running + udev daemon will detect a new database on its own and does not need to be + notified about it. + + + + + + + Query the database with a modalias string, and print the + retrieved properties. + + + + + + + Alternative root path in the file system for reading and writing files. + + + + + + + Print help text. + + + + + + udevadm test <optional>options</optional> <replaceable>devpath</replaceable> + Simulate a udev event run for the given device, and print debug output. + + + + + + The action string. + + + + + + + Specify when udevadm should resolve names of users + and groups. When set to early (the + default), names will be resolved when the rules are + parsed. When set to late, names will + be resolved for every event. When set to + never, names will never be resolved + and all devices will be owned by root. + + + + + + + Print help text. + + + + + + udevadm test-builtin <optional>options</optional> <replaceable>COMMAND</replaceable> <replaceable>DEVPATH</replaceable> + Run a built-in command COMMAND + for device DEVPATH, and print debug + output. + + + + + + Print help text. + + + + + + + + See Also + + udev7 + + + systemd-udevd.service8 + + + diff --git a/man/user-system-options.xml b/man/user-system-options.xml new file mode 100644 index 0000000..cca5c79 --- /dev/null +++ b/man/user-system-options.xml @@ -0,0 +1,45 @@ + + + + + + + + + Talk to the service manager of the calling user, + rather than the service manager of the system. + + + + + + + + Talk to the service manager of the system. This is the + implied default. + + + + + + + + + Execute the operation remotely. Specify a hostname, or + username and hostname separated by @, to + connect to. This will use SSH to talk to the remote machine + manager instance. + + + + + + + + + Execute operation on a local container. Specify a + container name to connect to. + + + diff --git a/man/vconsole.conf.xml b/man/vconsole.conf.xml index a73db00..09a4776 100644 --- a/man/vconsole.conf.xml +++ b/man/vconsole.conf.xml @@ -9,20 +9,20 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + 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. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . --> - + vconsole.conf systemd @@ -44,7 +44,7 @@ vconsole.conf - configuration file for the virtual console + Configuration file for the virtual console @@ -56,11 +56,12 @@ The /etc/vconsole.conf file configures the virtual console, i.e. keyboard mapping - and console font. + and console font. It is applied at boot by + systemd-vconsole-setup.service8. The basic file format of the vconsole.conf is a - newline-separated list environment-like + newline-separated list of environment-like shell-compatible variable assignments. It is possible to source the configuration from shell scripts, however, beyond mere variable assignments no shell @@ -94,12 +95,12 @@ KEYMAP_TOGGLE= Configures the key - mapping table of for they + mapping table for the keyboard. KEYMAP= defaults to us if not set. The KEYMAP_TOGGLE= can - be used to configured a second toggle + be used to configure a second toggle keymap and is by default unset. @@ -111,9 +112,7 @@ Configures the console font, the console map and the unicode - font map. FONT= - defaults to - latarcyrheb-sun16. + font map. @@ -125,7 +124,7 @@ German keyboard and console - /etc/vconsole.conf: + /etc/vconsole.conf: KEYMAP=de-latin1 FONT=latarcyrheb-sun16 @@ -137,9 +136,11 @@ FONT=latarcyrheb-sun16 See Also systemd1, + systemd-vconsole-setup.service8, loadkeys1, setfont8, - locale.conf5 + locale.conf5, + systemd-localed.service8 diff --git a/network/80-container-host0.network b/network/80-container-host0.network new file mode 100644 index 0000000..d49fba0 --- /dev/null +++ b/network/80-container-host0.network @@ -0,0 +1,6 @@ +[Match] +Virtualization=container +Name=host0 + +[Network] +DHCP=yes diff --git a/network/99-default.link b/network/99-default.link new file mode 100644 index 0000000..53215f6 --- /dev/null +++ b/network/99-default.link @@ -0,0 +1,3 @@ +[Link] +NamePolicy=database onboard slot path +MACAddressPolicy=persistent diff --git a/packaging/apply-conf.sh b/packaging/apply-conf.sh new file mode 100644 index 0000000..1bafa64 --- /dev/null +++ b/packaging/apply-conf.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +SRC=$1 +TAR=$2 + +ORIGIFS=$IFS +IFS= +for line in `cat $SRC`; do + CHANGE=$(echo $line | awk -F= '$1 ~ /^([a-zA-Z0-9 ])/ { print $1"=" }') +done + +IFS=$ORIGIFS +for line in `echo $CHANGE`; do + sed -i s/"$(grep $line $TAR)"/"$(grep $line $SRC)"/g $TAR +done + diff --git a/packaging/systemd.manifest b/packaging/systemd.manifest new file mode 100644 index 0000000..ede5999 --- /dev/null +++ b/packaging/systemd.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packaging/systemd.spec b/packaging/systemd.spec index c73b502..7622e03 100644 --- a/packaging/systemd.spec +++ b/packaging/systemd.spec @@ -1,103 +1,606 @@ -#sbs-git:slp/pkgs/s/systemd systemd 37 8ba5df3f1f236e059a9bd77314ed3ca0b4ffcde7 -Name: systemd -Summary: Systemd System and Service Manager -Version: 37 -Release: 2 -Group: System/Base -License: GPLv2 -Source0: %{name}-%{version}.tar.gz -BuildRequires: pkgconfig(dbus-1) >= 1.3.2 -BuildRequires: pkgconfig(gio-unix-2.0) -BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(libudev) >= 160 +%global _hardened_build 1 + +# We ship a .pc file but don't want to have a dep on pkg-config. We +# strip the automatically generated dep here and instead co-own the +# directory. +%global __requires_exclude pkg-config + +%define WITH_BASH_COMPLETION 0 +%define WITH_BLACKLIGHT 0 +%define WITH_COREDUMP 0 +%define WITH_PAM 0 +%define WITH_RANDOMSEED 0 + +%define WITH_LOGIND 0 +%define WITH_TIMEDATED 0 + +%define WITH_COMPAT_LIBS 1 + +Name: systemd +Url: http://www.freedesktop.org/wiki/Software/systemd +Version: 210 +Release: 1 +License: LGPL-2.1+ and MIT and GPL-2.0+ +Summary: A System and Service Manager +Source0: http://www.freedesktop.org/software/systemd/%{name}-%{version}.tar.xz +Source1: apply-conf.sh +Source11: tizen-system-mobile.conf +Source12: tizen-system-wearable.conf +Source13: tizen-journald.conf +Source14: tizen-bootchart.conf +Source1001: systemd.manifest +# The base number of patch for systemd is 101. + +# The base number of patch for udev is 201. + +BuildRequires: glib2-devel +BuildRequires: kmod-devel >= 15 +BuildRequires: hwdata + +BuildRequires: libacl-devel +BuildRequires: pkgconfig +BuildRequires: pkgconfig(dbus-1) >= 1.4.0 BuildRequires: libcap-devel +BuildRequires: libblkid-devel >= 2.20 +BuildRequires: pkgconfig(libkmod) >= 5 +BuildRequires: pam-devel +BuildRequires: dbus-devel BuildRequires: libacl-devel -BuildRequires: intltool -BuildRequires: fdupes +BuildRequires: glib2-devel +BuildRequires: libblkid-devel +BuildRequires: xz-devel +BuildRequires: kmod-devel +BuildRequires: libgcrypt-devel +BuildRequires: libxslt +BuildRequires: intltool >= 0.40.0 BuildRequires: gperf +BuildRequires: gawk +BuildRequires: automake +BuildRequires: autoconf +BuildRequires: libtool +BuildRequires: smack-devel +Requires: dbus +Requires: %{name}-libs = %{version}-%{release} + +Provides: /bin/systemctl +Provides: /sbin/shutdown +Provides: syslog +Provides: systemd-units = %{version}-%{release} +Provides: udev = %{version} +Obsoletes: udev < 183 +Obsoletes: system-setup-keyboard < 0.9 +Provides: system-setup-keyboard = 0.9 +Obsoletes: nss-myhostname < 0.4 +Provides: nss-myhostname = 0.4 +Obsoletes: systemd < 204-10 +Obsoletes: systemd-analyze < 198 +Provides: systemd-analyze = 198 + %description -system and service manager systemd is a replacement for sysvinit. -It is dependency-based and able to read the LSB init script headers -in addition to parsing rcN.d links as hints. . It also provides -process supervision using cgroups and the ability to not only depend -on other init script being started, but also availability of a given -mount point or dbus service. +systemd is a system and service manager for Linux, compatible with +SysV and LSB init scripts. systemd provides aggressive parallelization +capabilities, uses socket and D-Bus activation for starting services, +offers on-demand starting of daemons, keeps track of processes using +Linux cgroups, supports snapshotting and restoring of the system +state, maintains mount and automount points and implements an +elaborate transactional dependency-based service control logic. It can +work as a drop-in replacement for sysvinit. + +%package libs +Summary: systemd libraries +License: GPL-2.0+ +Provides: libudev +Obsoletes: systemd < 185-4 +Conflicts: systemd < 185-4 + +%description libs +Libraries for systemd and udev, as well as the systemd PAM module. %package devel -Summary: systemd development files -Requires: %{name} = %{version} -Group: Development/Libraries +Summary: Development headers for systemd +License: GPL-2.0+ +Requires: %{name} = %{version}-%{release} +Provides: pkgconfig(libudev) +Provides: libudev-devel = %{version} +Obsoletes: libudev-devel < 183 %description devel -Headers and static libraries for systemd (Development) +Development headers and auxiliary files for developing applications for systemd. + +%package -n libgudev1 +Summary: Libraries for adding libudev support to applications that use glib +License: GPL-2.0+ +Requires: %{name} = %{version}-%{release} + +%description -n libgudev1 +This package contains the libraries that make it easier to use libudev +functionality from applications that use glib. + +%package -n libgudev1-devel +Summary: Header files for adding libudev support to applications that use glib +Requires: libgudev1 = %{version}-%{release} +License: GPL-2.0+ + +%description -n libgudev1-devel +This package contains the header and pkg-config files for developing +glib-based applications using libudev functionality. + +%package journal-gateway +Summary: Gateway for serving journal events over the network using HTTP +Requires: %{name} = %{version}-%{release} +License: LGPL-2.1+ +Requires(pre): /usr/bin/getent +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description journal-gateway +systemd-journal-gatewayd serves journal events over the network using HTTP. %prep -%setup -q +%setup -q -n %{name}-%{version} %build +cp %{SOURCE1001} . + +export CFLAGS+=" -g -O0 -DCONFIG_TIZEN -DCONFIG_TIZEN_WIP" +autoreconf -fiv +%configure \ + --disable-static \ + --with-sysvinit-path= \ + --with-sysvrcnd-path= \ + --disable-gtk-doc-html \ + --disable-selinux \ + --disable-ima \ + --disable-tcpwrap \ + --enable-split-usr \ + --disable-nls \ + --disable-manpages \ + --disable-efi \ +%if %{WITH_PAM} + --with-pamlibdir="/%{_libdir}/security" \ +%else + --disable-pam \ +%endif + --with-firmware-path="/%{_libdir}/firmware" \ + --with-zshcompletiondir="" \ + --disable-hostnamed \ + --disable-machined \ + --disable-binfmt \ + --disable-vconsole \ + --disable-quotacheck \ + --disable-localed \ + --disable-polkit \ + --disable-myhostname \ + --without-python \ +%if "%{?tizen_profile_name}" == "wearable" + --disable-xz \ +%endif +%if ! %{WITH_RANDOMSEED} + --disable-randomseed \ +%endif +%if ! %{WITH_COREDUMP} + --disable-coredump \ +%endif +%if ! %{WITH_BLACKLIGHT} + --disable-backlight \ +%endif +%if ! %{WITH_LOGIND} + --disable-logind \ +%endif +%if ! %{WITH_TIMEDATED} + --disable-timedated \ +%endif +%if %{WITH_COMPAT_LIBS} + --enable-compat-libs \ +%endif -DH_OPTIONS='-Nlibpam-systemd -Nsystemd-gui' -export DH_OPTIONS - -libtoolize -c --force -intltoolize -c -f -aclocal -I m4 -autoconf -Wall -autoheader -automake --copy --foreign --add-missing - -./configure --prefix=/usr --disable-static \ - --disable-docs \ - --with-rootdir=/ \ - --with-rootlibdir=/lib \ - --with-udevrulesdir=/lib/udev/rules.d \ - --disable-gtk \ - --disable-libcryptsetup \ - --disable-audit \ - --disable-pam \ - --disable-tcpwrap \ - --disable-selinux \ - --with-distro=slp - -make %{?jobs:-j%jobs} +make %{?_smp_mflags} %install -rm -rf %{buildroot} %make_install -mkdir -p $RPM_BUILD_ROOT/usr/include -mkdir -p $RPM_BUILD_ROOT/usr/lib -cp src/sd-daemon.h $RPM_BUILD_ROOT/usr/include -#cp .libs/libsystemd-daemon.a $RPM_BUILD_ROOT/usr/lib +rm -f %{buildroot}/usr/bin/kernel-install +rm -rf %{buildroot}/usr/lib/kernel +rm -f %{buildroot}/usr/bin/systemd-detect-virt +find %{buildroot} \( -name '*.a' -o -name '*.la' \) -delete + +# udev links +mkdir -p %{buildroot}/%{_sbindir} +mkdir -p %{buildroot}/sbin +ln -sf ../bin/udevadm %{buildroot}%{_sbindir}/udevadm + +# Create SysV compatibility symlinks. systemctl/systemd are smart +# enough to detect in which way they are called. +ln -s ../lib/systemd/systemd %{buildroot}%{_sbindir}/init +ln -s /usr/lib/systemd/systemd %{buildroot}/sbin/init +ln -s ../lib/systemd/systemd %{buildroot}%{_bindir}/systemd +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/reboot +ln -s /usr/bin/systemctl %{buildroot}/sbin/reboot +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/halt +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/poweroff +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/shutdown +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/telinit +ln -s ../bin/systemctl %{buildroot}%{_sbindir}/runlevel +ln -s /usr/lib/systemd/systemd-udevd %{buildroot}/%{_sbindir}/udevd +ln -s /lib/firmware %{buildroot}%{_libdir}/firmware + +# We create all wants links manually at installation time to make sure +# they are not owned and hence overriden by rpm after the user deleted +# them. +rm -r %{buildroot}%{_sysconfdir}/systemd/system/*.target.wants + +# Make sure these directories are properly owned +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/basic.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/default.target.wants +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/dbus.target.wants + +# Make sure the user generators dir exists too +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-generators +mkdir -p %{buildroot}%{_prefix}/lib/systemd/user-generators + +# Create new-style configuration files so that we can ghost-own them +touch %{buildroot}%{_sysconfdir}/hostname +touch %{buildroot}%{_sysconfdir}/locale.conf +touch %{buildroot}%{_sysconfdir}/machine-id +touch %{buildroot}%{_sysconfdir}/machine-info +touch %{buildroot}%{_sysconfdir}/localtime +mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d +touch %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/00-keyboard.conf + +# Make sure the shutdown/sleep drop-in dirs exist +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-shutdown/ +mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep/ + +# Make sure directories in /var exist +%if %{WITH_COREDUMP} +mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/coredump +%endif +mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/catalog +mkdir -p %{buildroot}%{_localstatedir}/log/journal +touch %{buildroot}%{_localstatedir}/lib/systemd/catalog/database +touch %{buildroot}%{_sysconfdir}/udev/hwdb.bin + +# To avoid making life hard for Rawhide-using developers, don't package the +# kernel.core_pattern setting until systemd-coredump is a part of an actual +# systemd release and it's made clear how to get the core dumps out of the +# journal. +rm -f %{buildroot}%{_prefix}/lib/sysctl.d/50-coredump.conf + +rm -rf %{buildroot}%{_prefix}/lib/udev/hwdb.d/ + +# These rules doesn't make much sense on Tizen right now. +rm -f %{buildroot}%{_libdir}/udev/rules.d/42-usb-hid-pm.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/60-persistent-storage-tape.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/60-cdrom_id.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/60-keyboard.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/61-accelerometer.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/64-btrfs.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/70-power-switch.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/75-net-description.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/75-probe_mtd.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/75-tty-description.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/80-net-name-slot.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/95-keyboard-force-release.rules +rm -f %{buildroot}%{_libdir}/udev/rules.d/95-keymap.rules + +%if ! %{WITH_BASH_COMPLETION} +# Hmm, bash completion also removed :( +rm -f %{buildroot}%{_datadir}/bash-completion/completions/busctl +rm -f %{buildroot}%{_datadir}/bash-completion/completions/journalctl +rm -f %{buildroot}%{_datadir}/bash-completion/completions/kernel-install +%if %{WITH_LOGIND} +rm -f %{buildroot}%{_datadir}/bash-completion/completions/loginctl +%endif +%if %{WITH_TIMEDATED} +rm -f %{buildroot}%{_datadir}/bash-completion/completions/timedatectl +%endif +rm -f %{buildroot}%{_datadir}/bash-completion/completions/systemctl +%if %{WITH_COREDUMP} +rm -f %{buildroot}%{_datadir}/bash-completion/completions/systemd-coredumpctl +%endif +rm -f %{buildroot}%{_datadir}/bash-completion/completions/systemd-delta +rm -f %{buildroot}%{_datadir}/bash-completion/completions/systemd-run +rm -f %{buildroot}%{_datadir}/bash-completion/completions/udevadm +rm -f %{buildroot}%{_datadir}/bash-completion/completions/systemd-analyze +%endif + +# This will be done by tizen specific init script. +rm -f %{buildroot}%{_libdir}/systemd/system/local-fs.target.wants/systemd-fsck-root.service + +# We will just use systemd just as system, user not yet. Until that that service will be disabled. +%if ! %{WITH_LOGIND} +rm -f %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/systemd-logind.service +%endif + +# Make sure default extra dependencies ignore unit directory exist +mkdir -p %{buildroot}%{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d +%if %{WITH_TIMEDATED} +install -m644 %{_builddir}/%{name}-%{version}/src/timedate/org.freedesktop.timedate1.service %{buildroot}%{_prefix}/share/dbus-1/system-services/ +%endif + +# Apply Tizen configs +chmod +x %{SOURCE1} +%if "%{?tizen_profile_name}" == "mobile" +%{SOURCE1} %{SOURCE11} %{buildroot}%{_sysconfdir}/systemd/system.conf +%elseif "%{?tizen_profile_name}" == "wearable" +%{SOURCE1} %{SOURCE12} %{buildroot}%{_sysconfdir}/systemd/system.conf +%endif +%{SOURCE1} %{SOURCE13} %{buildroot}%{_sysconfdir}/systemd/journald.conf +%{SOURCE1} %{SOURCE14} %{buildroot}%{_sysconfdir}/systemd/bootchart.conf + +# All of licenses should be manifested in /usr/share/license. +mkdir -p %{buildroot}%{_datadir}/license +cat LICENSE.LGPL2.1 > %{buildroot}%{_datadir}/license/systemd +cat LICENSE.LGPL2.1 > %{buildroot}%{_datadir}/license/systemd-libs +cat LICENSE.LGPL2.1 > %{buildroot}%{_datadir}/license/libgudev1 %remove_docs +%pre +getent group cdrom >/dev/null 2>&1 || groupadd -r -g 11 cdrom >/dev/null 2>&1 || : +getent group tape >/dev/null 2>&1 || groupadd -r -g 33 tape >/dev/null 2>&1 || : +getent group dialout >/dev/null 2>&1 || groupadd -r -g 18 dialout >/dev/null 2>&1 || : +getent group floppy >/dev/null 2>&1 || groupadd -r -g 19 floppy >/dev/null 2>&1 || : +getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || : + +systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service >/dev/null 2>&1 || : + +%post +systemd-machine-id-setup >/dev/null 2>&1 || : +%if %{WITH_RANDOMSEED} +/usr/lib/systemd/systemd-random-seed save >/dev/null 2>&1 || : +%endif +systemctl daemon-reexec >/dev/null 2>&1 || : +systemctl start systemd-udevd.service >/dev/null 2>&1 || : +udevadm hwdb --update >/dev/null 2>&1 || : +journalctl --update-catalog >/dev/null 2>&1 || : + +# Stop-gap until rsyslog.rpm does this on its own. (This is supposed +# to fail when the link already exists) +ln -s /usr/lib/systemd/system/rsyslog.service /etc/systemd/system/syslog.service >/dev/null 2>&1 || : +%if %{WITH_TIMEDATED} +ln -s ../system-services/org.freedesktop.timedate1.service %{_datadir}/dbus-1/services/org.freedesktop.timedate1.service +%endif +# Masked unnecessary units in tizen. +ln -s /dev/null /etc/systemd/system/systemd-tmpfiles-clean.timer +ln -s /dev/null /etc/systemd/system/systemd-remount-fs.service +ln -s /dev/null /etc/systemd/system/systemd-journal-flush.service +ln -s /dev/null /etc/systemd/system/systemd-update-utmp.service +ln -s /dev/null /etc/systemd/system/kmod-static-nodes.service + +# Tizen is not supporting /usr/lib/macros.d yet. +# To avoid this, the macro will be copied to origin macro dir. +if [ -f %{_libdir}/rpm/macros.d/macros.systemd ]; then + mkdir -p %{_sysconfdir}/rpm + cp %{_libdir}/rpm/macros.d/macros.systemd %{_sysconfdir}/rpm +fi + +%postun +if [ $1 -ge 1 ] ; then + systemctl daemon-reload > /dev/null 2>&1 || : +%if %{WITH_LOGIND} + systemctl try-restart systemd-logind.service >/dev/null 2>&1 || : +%endif +fi + +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig + +%post -n libgudev1 -p /sbin/ldconfig +%postun -n libgudev1 -p /sbin/ldconfig + %files %defattr(-,root,root,-) -/bin/* -/etc/dbus-1/system.d/* -/lib/* -/lib/systemd/system-generators/systemd-getty-generator -/lib/systemd/system/* -/lib/systemd/system/*/* -/lib/udev/rules.d/* -/usr/bin/* -/usr/etc/* -/usr/etc/*/* -/usr/etc/*/*/* -/usr/lib/libsystemd-daemon.so -/usr/lib/libsystemd-login.so -/usr/lib/systemd/user/* -/usr/lib/tmpfiles.d/* -/usr/share/dbus-1/interfaces/*.xml -/usr/share/dbus-1/services/org.freedesktop.systemd1.service -/usr/share/dbus-1/system-services/* -/usr/share/polkit-1/actions/* -/usr/share/systemd/kbd-model-map +%{_datadir}/license/systemd +%dir %{_sysconfdir}/systemd +%dir %{_sysconfdir}/systemd/system +%dir %{_sysconfdir}/systemd/user +%dir %{_sysconfdir}/tmpfiles.d +%dir %{_sysconfdir}/sysctl.d +%dir %{_sysconfdir}/modules-load.d +%dir %{_sysconfdir}/udev +%dir %{_sysconfdir}/udev/rules.d +%dir %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d +%dir %{_prefix}/lib/systemd +%dir %{_prefix}/lib/systemd/system-generators +%dir %{_prefix}/lib/systemd/user-generators +%dir %{_prefix}/lib/systemd/system-shutdown +%dir %{_prefix}/lib/systemd/system-sleep +%dir %{_prefix}/lib/systemd/catalog +%dir %{_prefix}/lib/tmpfiles.d +%dir %{_prefix}/lib/sysctl.d +%dir %{_prefix}/lib/modules-load.d +%{_prefix}/lib/firmware +%dir %{_datadir}/systemd +%dir %{_datadir}/pkgconfig +%dir %{_localstatedir}/log/journal +%dir %{_localstatedir}/lib/systemd +%dir %{_localstatedir}/lib/systemd/catalog +%if %{WITH_COREDUMP} +%dir %{_localstatedir}/lib/systemd/coredump +%endif +%if %{WITH_TIMEDATED} +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.timedate1.conf +%endif +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.systemd1.conf +%if %{WITH_LOGIND} +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.login1.conf +%endif +%config(noreplace) %{_sysconfdir}/systemd/system.conf +%config(noreplace) %{_sysconfdir}/systemd/user.conf +%if %{WITH_LOGIND} +%config(noreplace) %{_sysconfdir}/systemd/logind.conf +%endif +%config(noreplace) %{_sysconfdir}/systemd/journald.conf +%config(noreplace) %{_sysconfdir}/systemd/bootchart.conf +%config(noreplace) %{_sysconfdir}/udev/udev.conf +%ghost %{_sysconfdir}/udev/hwdb.bin +%{_libdir}/rpm/macros.d/macros.systemd +%if %{WITH_PAM} +%config(noreplace) %{_sysconfdir}/pam.d/systemd-user +%endif +%{_sysconfdir}/xdg/systemd +%ghost %config(noreplace) %{_sysconfdir}/hostname +%ghost %config(noreplace) %{_sysconfdir}/localtime +%ghost %config(noreplace) %{_sysconfdir}/locale.conf +%ghost %config(noreplace) %{_sysconfdir}/machine-id +%ghost %config(noreplace) %{_sysconfdir}/machine-info +%ghost %config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/00-keyboard.conf +%ghost %{_localstatedir}/lib/systemd/catalog/database +%{_bindir}/systemd +%{_bindir}/systemctl +%{_bindir}/systemd-run +%{_bindir}/systemd-notify +%{_bindir}/systemd-analyze +%{_bindir}/systemd-ask-password +%{_bindir}/systemd-tty-ask-password-agent +%{_bindir}/systemd-machine-id-setup +%{_bindir}/busctl +%if %{WITH_LOGIND} +%{_bindir}/loginctl +%endif +%if %{WITH_TIMEDATED} +%{_bindir}/timedatectl +%endif +%{_bindir}/journalctl +%{_bindir}/systemd-tmpfiles +%{_bindir}/systemd-nspawn +%{_bindir}/systemd-stdio-bridge +%{_bindir}/systemd-cat +%{_bindir}/systemd-cgls +%{_bindir}/systemd-cgtop +%{_bindir}/systemd-delta +%if %{WITH_LOGIND} +%{_bindir}/systemd-inhibit +%endif +%if %{WITH_COREDUMP} +%{_bindir}/systemd-coredumpctl +%endif +%{_bindir}/udevadm +%{_prefix}/lib/systemd/systemd +%{_prefix}/lib/systemd/system +%{_prefix}/lib/systemd/user +%{_prefix}/lib/systemd/systemd-* +%{_prefix}/lib/udev +%{_prefix}/lib/systemd/system-generators/systemd-getty-generator +%{_prefix}/lib/systemd/system-generators/systemd-fstab-generator +%exclude %{_prefix}/lib/systemd/system-generators/systemd-system-update-generator +%exclude %{_prefix}/lib/systemd/system-generators/systemd-gpt-auto-generator +%{_prefix}/lib/tmpfiles.d/systemd.conf +%{_prefix}/lib/tmpfiles.d/systemd-nologin.conf +%{_prefix}/lib/tmpfiles.d/x11.conf +%{_prefix}/lib/tmpfiles.d/tmp.conf +%{_prefix}/lib/sysctl.d/50-default.conf +%{_prefix}/lib/systemd/catalog/systemd.catalog +%{_prefix}/lib/systemd/catalog/systemd.fr.catalog +%{_prefix}/lib/systemd/catalog/systemd.it.catalog +%{_prefix}/lib/systemd/catalog/systemd.ru.catalog +%{_prefix}/lib/systemd/network/80-container-host0.network +%{_prefix}/lib/systemd/network/99-default.link +%{_sbindir}/init +/sbin/init +%{_sbindir}/reboot +/sbin/reboot +%{_sbindir}/halt +%{_sbindir}/poweroff +%{_sbindir}/shutdown +%{_sbindir}/telinit +%{_sbindir}/runlevel +%{_sbindir}/udevd +%{_sbindir}/udevadm +%{_datadir}/dbus-1/services/org.freedesktop.systemd1.service +%if %{WITH_TIMEDATED} +%{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service +%endif +%{_datadir}/dbus-1/system-services/org.freedesktop.systemd1.service +%if %{WITH_LOGIND} +%{_datadir}/dbus-1/system-services/org.freedesktop.login1.service +%endif +%if %{WITH_TIMEDATED} +%{_datadir}/dbus-1/interfaces/org.freedesktop.timedate1.xml +%endif +%{_datadir}/pkgconfig/systemd.pc +%{_datadir}/pkgconfig/udev.pc +%if %{WITH_BASH_COMPLETION} +%{_datadir}/bash-completion/completions/buxctl +%{_datadir}/bash-completion/completions/journalctl +%{_datadir}/bash-completion/completions/kernel-install +%if %{WITH_LOGIND} +%{_datadir}/bash-completion/completions/loginctl +%endif +%if %{WITH_TIMEDATED} +%{_datadir}/bash-completion/completions/timedatectl +%endif +%{_datadir}/bash-completion/completions/systemctl +%if %{WITH_COREDUMP} +%{_datadir}/bash-completion/completions/systemd-coredumpctl +%endif +%{_datadir}/bash-completion/completions/systemd-delta +%{_datadir}/bash-completion/completions/systemd-run +%{_datadir}/bash-completion/completions/udevadm +%{_datadir}/bash-completion/completions/systemd-analyze +%endif +%manifest systemd.manifest + +%files libs +%defattr(-,root,root,-) +%{_datadir}/license/systemd-libs +%if %{WITH_PAM} +%{_libdir}/security/pam_systemd.so +%endif +%{_libdir}/libsystemd.so.* +%if %{WITH_COMPAT_LIBS} +%{_libdir}/libsystemd-daemon.so.* +%{_libdir}/libsystemd-journal.so.* +%{_libdir}/libsystemd-id128.so.* +%{_libdir}/libsystemd-login.so.* +%endif +%{_libdir}/libudev.so.* +%manifest systemd.manifest %files devel -/usr/include/*.h -/usr/include/*/*.h -/usr/lib/pkgconfig/* -/usr/share/pkgconfig/systemd.pc +%defattr(-,root,root,-) +%dir %{_includedir}/systemd +%{_libdir}/libsystemd.so +%if %{WITH_COMPAT_LIBS} +%{_libdir}/libsystemd-daemon.so +%{_libdir}/libsystemd-journal.so +%{_libdir}/libsystemd-id128.so +%{_libdir}/libsystemd-login.so +%endif +%{_libdir}/libudev.so +%{_includedir}/systemd/_sd-common.h +%{_includedir}/systemd/sd-daemon.h +##%if %{WITH_LOGIND} +%{_includedir}/systemd/sd-login.h +##%endif +%{_includedir}/systemd/sd-journal.h +%{_includedir}/systemd/sd-id128.h +%{_includedir}/systemd/sd-messages.h +%{_includedir}/libudev.h +%{_libdir}/pkgconfig/libsystemd.pc +%if %{WITH_COMPAT_LIBS} +%{_libdir}/pkgconfig/libsystemd-daemon.pc +%{_libdir}/pkgconfig/libsystemd-journal.pc +%{_libdir}/pkgconfig/libsystemd-id128.pc +%{_libdir}/pkgconfig/libsystemd-login.pc +%endif +%{_libdir}/pkgconfig/libudev.pc +%manifest systemd.manifest + +%files -n libgudev1 +%defattr(-,root,root,-) +%{_datadir}/license/libgudev1 +%{_libdir}/libgudev-1.0.so.* +%manifest systemd.manifest + +%files -n libgudev1-devel +%defattr(-,root,root,-) +%{_libdir}/libgudev-1.0.so +%dir %{_includedir}/gudev-1.0 +%dir %{_includedir}/gudev-1.0/gudev +%{_includedir}/gudev-1.0/gudev/*.h +%{_libdir}/pkgconfig/gudev-1.0* +%manifest systemd.manifest diff --git a/packaging/tizen-bootchart.conf b/packaging/tizen-bootchart.conf new file mode 100644 index 0000000..5b3ab44 --- /dev/null +++ b/packaging/tizen-bootchart.conf @@ -0,0 +1,21 @@ +# 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. +# +# See bootchart.conf(5) for details + +[Bootchart] +Samples=750 +#Frequency=25 +#Relative=no +Filter=no +#Output= +#Init=/path/to/init-binary +#PlotMemoryUsage=no +#PlotEntropyGraph=no +#ScaleX=100 +#ScaleY=20 +ControlGroup=yes diff --git a/packaging/tizen-journald.conf b/packaging/tizen-journald.conf new file mode 100644 index 0000000..f844c1e --- /dev/null +++ b/packaging/tizen-journald.conf @@ -0,0 +1,33 @@ +# 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. +# +# See journald.conf(5) for details + +[Journal] +Storage=persistent +#Compress=yes +#Seal=yes +#SplitMode=login +#SyncIntervalSec=5m +#RateLimitInterval=30s +#RateLimitBurst=1000 +SystemMaxUse=8M +#SystemKeepFree= +#SystemMaxFileSize= +RuntimeMaxUse=8M +#RuntimeKeepFree= +#RuntimeMaxFileSize= +#MaxRetentionSec= +#MaxFileSec=1month +ForwardToSyslog=no +#ForwardToKMsg=no +#ForwardToConsole=no +#TTYPath=/dev/console +#MaxLevelStore=debug +#MaxLevelSyslog=debug +#MaxLevelKMsg=notice +#MaxLevelConsole=info diff --git a/packaging/tizen-system-mobile.conf b/packaging/tizen-system-mobile.conf new file mode 100644 index 0000000..90b204f --- /dev/null +++ b/packaging/tizen-system-mobile.conf @@ -0,0 +1,50 @@ +# 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. +# +# See systemd-system.conf(5) for details + +[Manager] +#LogLevel=info +LogTarget=journal +#LogColor=yes +#LogLocation=no +#DumpCore=yes +#CrashShell=no +#ShowStatus=yes +#CrashChVT=1 +#CPUAffinity=1 2 +#JoinControllers=cpu,cpuacct net_cls,net_prio +#RuntimeWatchdogSec=0 +#ShutdownWatchdogSec=10min +#CapabilityBoundingSet= +#SystemCallArchitectures= +#TimerSlackNSec= +DefaultStandardOutput=null +DefaultStandardError=null +#DefaultTimeoutStartSec=90s +#DefaultTimeoutStopSec=90s +#DefaultRestartSec=100ms +#DefaultStartLimitInterval=10s +#DefaultStartLimitBurst=5 +DefaultEnvironment="DISPLAY=:0" LD_HWCAP_MASK= +DefaultExtraDependencies="boot-animation.service" "tizen-readahead-collect-stop.service" +#DefaultLimitCPU= +#DefaultLimitFSIZE= +#DefaultLimitDATA= +#DefaultLimitSTACK= +DefaultLimitCORE=536870912 +#DefaultLimitRSS= +#DefaultLimitNOFILE= +#DefaultLimitAS= +#DefaultLimitNPROC= +#DefaultLimitMEMLOCK= +#DefaultLimitLOCKS= +#DefaultLimitSIGPENDING= +#DefaultLimitMSGQUEUE= +#DefaultLimitNICE= +#DefaultLimitRTPRIO= +#DefaultLimitRTTIME= diff --git a/packaging/tizen-system-wearable.conf b/packaging/tizen-system-wearable.conf new file mode 100644 index 0000000..78d1eb1 --- /dev/null +++ b/packaging/tizen-system-wearable.conf @@ -0,0 +1,44 @@ +# 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. +# +# See systemd-system.conf(5) for details + +[Manager] +#LogLevel=info +LogTarget=journal +#LogColor=yes +#LogLocation=no +#DumpCore=yes +#CrashShell=no +#ShowStatus=yes +#CrashChVT=1 +#CPUAffinity=1 2 +DefaultStandardOutput=null +DefaultStandardError=null +#JoinControllers=cpu,cpuacct,cpuset net_cls,net_prio +#RuntimeWatchdogSec=0 +#ShutdownWatchdogSec=10min +#CapabilityBoundingSet= +#TimerSlackNSec= +DefaultEnvironment="DISPLAY=:0" LD_HWCAP_MASK= +DefaultExtraDependencies="boot-animation.service" "tizen-readahead-collect-stop.service" +#DefaultLimitCPU= +#DefaultLimitFSIZE= +#DefaultLimitDATA= +#DefaultLimitSTACK= +DefaultLimitCORE=536870912 +#DefaultLimitRSS= +#DefaultLimitNOFILE= +#DefaultLimitAS= +#DefaultLimitNPROC= +#DefaultLimitMEMLOCK= +#DefaultLimitLOCKS= +#DefaultLimitSIGPENDING= +#DefaultLimitMSGQUEUE= +#DefaultLimitNICE= +#DefaultLimitRTPRIO= +#DefaultLimitRTTIME= diff --git a/po/.gitignore b/po/.gitignore index 251edd4..0d1d4b0 100644 --- a/po/.gitignore +++ b/po/.gitignore @@ -1,3 +1,6 @@ POTFILES Makefile.in.in .intltool-merge-cache +Makefile +systemd.pot +/*.gmo diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..0301751 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,4 @@ +fr +pl +ru +it diff --git a/po/Makefile.in.in b/po/Makefile.in.in new file mode 100644 index 0000000..06a8cfe --- /dev/null +++ b/po/Makefile.in.in @@ -0,0 +1,222 @@ +# Makefile for program source directory in GNU NLS utilities package. +# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper +# Copyright (C) 2004-2008 Rodney Dawes +# +# This file may be copied and used freely without restrictions. It may +# be used in projects which are not available under a GNU Public License, +# but which still want to provide support for the GNU gettext functionality. +# +# - Modified by Owen Taylor to use GETTEXT_PACKAGE +# instead of PACKAGE and to look for po2tbl in ./ not in intl/ +# +# - Modified by jacob berkman to install +# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize +# +# - Modified by Rodney Dawes for use with intltool +# +# We have the following line for use by intltoolize: +# INTLTOOL_MAKEFILE + +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +datarootdir = @datarootdir@ +libdir = @libdir@ +DATADIRNAME = @DATADIRNAME@ +itlocaledir = $(prefix)/$(DATADIRNAME)/locale +subdir = po +install_sh = @install_sh@ +# Automake >= 1.8 provides @mkdir_p@. +# Until it can be supposed, use the safe fallback: +mkdir_p = $(install_sh) -d + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist +GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot + +ALL_LINGUAS = @ALL_LINGUAS@ + +PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) + +USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) + +USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) + +POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) + +DISTFILES = Makefile.in.in POTFILES.in $(POFILES) +EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS + +POTFILES = \ +# This comment gets stripped out + +CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) + +.SUFFIXES: +.SUFFIXES: .po .pox .gmo .mo .msg .cat + +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) +INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) +INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; + +.po.pox: + $(MAKE) $(GETTEXT_PACKAGE).pot + $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox + +.po.mo: + $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< + +.po.gmo: + $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ + && rm -f $$file && $(GMSGFMT) -o $$file $< + +.po.cat: + sed -f ../intl/po2msg.sed < $< > $*.msg \ + && rm -f $@ && gencat $@ $*.msg + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +$(GETTEXT_PACKAGE).pot: $(POTFILES) + $(GENPOT) + +install: install-data +install-data: install-data-@USE_NLS@ +install-data-no: all +install-data-yes: all + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $$dir; \ + if test -r $$lang.gmo; then \ + $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $(srcdir)/$$lang.gmo as" \ + "$$dir/$(GETTEXT_PACKAGE).mo"; \ + fi; \ + if test -r $$lang.gmo.m; then \ + $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + if test -r $(srcdir)/$$lang.gmo.m ; then \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ + $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $(srcdir)/$$lang.gmo.m as" \ + "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + true; \ + fi; \ + fi; \ + done + +# Empty stubs to satisfy archaic automake needs +dvi info ctags tags CTAGS TAGS ID: + +# Define this as empty until I found a useful application. +install-exec installcheck: + +uninstall: + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + done + +check: all $(GETTEXT_PACKAGE).pot + rm -f missing notexist + srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m + if [ -r missing -o -r notexist ]; then \ + exit 1; \ + fi + +mostlyclean: + rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp + rm -f .intltool-merge-cache + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES stamp-it + rm -f *.mo *.msg *.cat *.cat.m *.gmo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f Makefile.in.in + +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: $(DISTFILES) + dists="$(DISTFILES)"; \ + extra_dists="$(EXTRA_DISTFILES)"; \ + for file in $$extra_dists; do \ + test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ + done; \ + for file in $$dists; do \ + test -f $$file || file="$(srcdir)/$$file"; \ + ln $$file $(distdir) 2> /dev/null \ + || cp -p $$file $(distdir); \ + done + +update-po: Makefile + $(MAKE) $(GETTEXT_PACKAGE).pot + tmpdir=`pwd`; \ + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + echo "$$lang:"; \ + result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ + if $$result; then \ + if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.gmo failed!"; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi; \ + done + +Makefile POTFILES: stamp-it + @if test ! -f $@; then \ + rm -f stamp-it; \ + $(MAKE) stamp-it; \ + fi + +stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ + $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/po/POTFILES.in b/po/POTFILES.in index 29be44e..2829c87 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,5 @@ -src/org.freedesktop.hostname1.policy.in -src/org.freedesktop.locale1.policy.in -src/org.freedesktop.login1.policy.in -src/org.freedesktop.timedate1.policy.in +src/hostname/org.freedesktop.hostname1.policy.in +src/locale/org.freedesktop.locale1.policy.in +src/login/org.freedesktop.login1.policy.in +src/timedate/org.freedesktop.timedate1.policy.in +src/core/org.freedesktop.systemd1.policy.in.in diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 192f3b6..b552029 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -1,19 +1,22 @@ -src/dbus-automount.c -src/dbus-device.c -src/dbus-job.c -src/dbus-manager.c -src/dbus-mount.c -src/dbus-path.c -src/dbus-service.c -src/dbus-snapshot.c -src/dbus-socket.c -src/dbus-swap.c -src/dbus-target.c -src/dbus-timer.c -src/dbus-unit.c -src/hostnamed.c -src/localed.c -src/org.freedesktop.systemd1.policy.in.in -src/timedated.c +src/core/dbus-automount.c +src/core/dbus-device.c +src/core/dbus-job.c +src/core/dbus-manager.c +src/core/dbus-mount.c +src/core/dbus-path.c +src/core/dbus-service.c +src/core/dbus-slice.c +src/core/dbus-snapshot.c +src/core/dbus-socket.c +src/core/dbus-swap.c +src/core/dbus-target.c +src/core/dbus-timer.c +src/core/dbus-unit.c +src/core/dbus-scope.c +src/hostname/hostnamed.c +src/locale/localed.c +src/core/org.freedesktop.systemd1.policy.in +src/timedate/timedated.c units/systemd-readahead-done.service.in units/user@.service.in +units/debug-shell.service.in diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..ed8a686 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,397 @@ +# French translations for systemd package +# Traductions françaises du paquet systemd. +# This file is distributed under the same license as the systemd package. +# Sylvain Plantefève , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-11-14 17:49+0100\n" +"PO-Revision-Date: 2013-11-14 17:57+0100\n" +"Last-Translator: Sylvain Plantefève \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "Définir le nom d'hôte" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 +msgid "Authentication is required to set the local host name." +msgstr "Authentification requise pour définir le nom d'hôte local." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "Définir le nom d'hôte statique" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 +msgid "" +"Authentication is required to set the statically configured local host name, " +"as well as the pretty host name." +msgstr "" +"Authentification requise pour définir le nom d'hôte local de manière statique, " +"tout comme le nom d'hôte familier." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 +msgid "Set machine information" +msgstr "Définir les informations sur la machine" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "" +"Authentification requise pour définir les informations sur la machine locale." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "Définir la langue du système" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 +msgid "Authentication is required to set the system locale." +msgstr "Authentification requise pour définir la langue du système." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "Définir les paramètres de clavier du système" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "Authentification requise pour définir les paramètres de clavier du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "Permet aux applications d'empêcher l'arrêt du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "" +"Authentication is required to allow an application to inhibit system " +"shutdown." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher l'arrêt " +"du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "Permet aux applications de retarder l'arrêt du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "" +"Authentication is required to allow an application to delay system shutdown." +msgstr "" +"Authentification requise pour permettre à une application de retarder l'arrêt " +"du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "Permet aux applications d'empêcher la mise en veille du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:6 +msgid "" +"Authentication is required to allow an application to inhibit system sleep." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher la mise " +"en veille du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "Permet aux applications de retarder la mise en veille du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "" +"Authentication is required to allow an application to delay system sleep." +msgstr "" +"Authentification requise pour permettre à une application de retarder la mise " +"en veille du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "Permet aux applications d'empêcher l'hibernation automatique du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:10 +msgid "" +"Authentication is required to allow an application to inhibit automatic " +"system suspend." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher " +"l'hibernation automatique du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "Permet aux applications d'empêcher la gestion du bouton d'alimentation " +" du système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:12 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the power key." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher la " +"gestion du bouton d'alimentation du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" +"Permet aux applications d'empêcher la gestion du bouton de mise en veille du " +"système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the suspend key." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher la gestion " +"du bouton de mise en veille du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "" +"Permet aux applications d'empêcher la gestion du bouton d'hibernation du " +"système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:16 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the hibernate key." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher la gestion " +"du bouton d'hibernation du système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" +"Permet aux applications d'empêcher la gestion par le système du rabat de " +"l'écran" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the lid switch." +msgstr "" +"Authentification requise pour permettre à une application d'empêcher la " +"gestion par le système du rabat de l'écran." + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "Permet aux utilisateurs non connectés d'exécuter des programmes" + +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "" +"Authentication is required to allow a non-logged-in user to run programs." +msgstr "" +"Authentification requise pour permettre aux utilisateurs non connectés " +"d'exécuter des programmes." + +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "Permet d'associer des périphériques à des postes (seats)" + +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "Authentification requise pour associer un périphérique à un poste (seat)." + +#: ../src/login/org.freedesktop.login1.policy.in.h:23 +msgid "Flush device to seat attachments" +msgstr "Révoquer les associations de périphériques aux postes (seats)" + +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "" +"Authentication is required for resetting how devices are attached to seats." +msgstr "" +"Authentification requise pour révoquer les associations de périphériques " +"aux postes (seats)." + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 +msgid "Power off the system" +msgstr "Éteindre le système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "Authentification requise pour éteindre le système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" +msgstr "Éteindre le système alors que d'autres utilisateurs sont connectés" + +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "" +"Authentication is required for powering off the system while other users are " +"logged in." +msgstr "" +"Authentification requise pour éteindre le système alors que d'autres " +"utilisateurs sont connectés." + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "Éteindre le système alors qu'une application a demandé de l'empêcher" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "" +"Authentication is required for powering off the system while an application " +"asked to inhibit it." +msgstr "" +"Authentification requise pour éteindre le système alors qu'une application " +"a demandé de l'empêcher." + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 +msgid "Reboot the system" +msgstr "Redémarrer le système" + +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "Authentification requise pour redémarrer le système." + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" +msgstr "Redémarrer le système alors que d'autres utilisateurs sont connectés" + +#: ../src/login/org.freedesktop.login1.policy.in.h:34 +msgid "" +"Authentication is required for rebooting the system while other users are " +"logged in." +msgstr "" +"Authentification requise pour redémarrer le système alors que d'autres " +"utilisateurs sont connectés." + +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "Redémarrer le système alors qu'une application a demandé de l'empêcher" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 +msgid "" +"Authentication is required for rebooting the system while an application " +"asked to inhibit it." +msgstr "" +"Authentification requise pour redémarrer le système alors qu'une application " +" a demandé de l'empêcher." + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "Mettre le système en veille" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "Authentification requise pour mettre le système en veille." + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "Mettre le système en veille alors que d'autres utilisateurs sont connectés" + +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "" +"Authentication is required for suspending the system while other users are " +"logged in." +msgstr "" +"Authentification requise pour mettre le système en veille alors que " +"d'autres utilisateurs sont connectés." + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "Mettre le système en veille alors qu'une application a demandé de l'empêcher" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "" +"Authentication is required for suspending the system while an application " +"asked to inhibit it." +msgstr "" +"Authentification requise pour mettre le système en veille alors qu'une " +"application a demandé de l'empêcher." + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "Mettre le système en hibernation" + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "Authentification requise pour mettre le système en hibernation." + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "Mettre le système en hibernation alors que d'autres utilisateurs sont connectés" + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "" +"Authentication is required for hibernating the system while other users are " +"logged in." +msgstr "" +"Authentification requise pour mettre le système en hibernation alors que " +"d'autres utilisateurs sont connectés." + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "" +"Mettre le système en hibernation alors qu'une application a demandé de " +"l'empêcher" + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "" +"Authentication is required for hibernating the system while an application " +"asked to inhibit it." +msgstr "" +"Authentification requise pour mettre le système en hibernation alors qu'une " +"application a demandé de l'empêcher." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "Définir l'heure du système" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 +msgid "Authentication is required to set the system time." +msgstr "Authentification requise pour définir l'heure du système." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "Définir le fuseau horaire du système" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 +msgid "Authentication is required to set the system timezone." +msgstr "Authentification requise pour définir le fuseau horaire du système." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 +msgid "Set RTC to local timezone or UTC" +msgstr "" +"Positionner l'horloge matérielle à l'heure locale ou sur le temps universel " +"coordonné (UTC)" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" +"Authentification requise pour positionner l'horloge matérielle à l'heure locale " +"ou sur le temps universel coordonné (UTC)." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 +msgid "Turn network time synchronization on or off" +msgstr "Activer ou désactiver la synchronisation de l'heure avec le réseau" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" +"Authentification requise pour activer ou désactiver la synchronisation " +"de l'heure avec le réseau." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "Renvoyer la phrase secrète au système" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" +"Authentification requise pour renvoyer la phrase secrète au système." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Privileged system and service manager access" +msgstr "Accès privilégié au gestionnaire du système et des services" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to access the system and service manager." +msgstr "" +"Authentification requise pour accéder au gestionnaire du système et des " +"services." diff --git a/po/it.po b/po/it.po new file mode 100644 index 0000000..e459f8b --- /dev/null +++ b/po/it.po @@ -0,0 +1,379 @@ +# Italian translations for systemd package +# Traduzione in italiano per il pacchetto systemd +# This file is distributed under the same license as the systemd package. +# Daniele Medri , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-11-22 17:49+0100\n" +"PO-Revision-Date: 2013-11-22 17:57+0100\n" +"Last-Translator: Daniele Medri \n" +"Language-Team: Italian\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "Configura il nome host" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 +msgid "Authentication is required to set the local host name." +msgstr "Autenticazione richiesta per configurare il nome host locale." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "Configura il nome host statico" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 +msgid "" +"Authentication is required to set the statically configured local host name, " +"as well as the pretty host name." +msgstr "" +"Autenticazione richiesta per configurare staticamente il nome host locale " +"e il nome host descrittivo." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 +msgid "Set machine information" +msgstr "Configura le informazioni sulla macchina" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "Autenticazione richiesta per configurare le informazioni sulla macchina locale." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "Configura le impostazioni regionali di sistema" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 +msgid "Authentication is required to set the system locale." +msgstr "Autenticazione richiesta per configurare le impostazioni regionali di sistema." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "Configura la tastiera di sistema" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "Autenticazione richiesta per configurare la tastiera di sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "Consenti alle applicazioni di inibire lo spegnimento del sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "" +"Authentication is required to allow an application to inhibit system " +"shutdown." +msgstr "" +"Autenticazione richiesta per consentire alle applicazione di inibire " +"lo spegnimento del sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "Consenti alle applicazioni di ritardare lo spegnimento del sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "" +"Authentication is required to allow an application to delay system shutdown." +msgstr "" +"Autenticazione richiesta per consentire alle applicazione di ritardare lo spegnimento del sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "Consenti alle applicazioni di inibire il sistema in pausa" + +#: ../src/login/org.freedesktop.login1.policy.in.h:6 +msgid "" +"Authentication is required to allow an application to inhibit system sleep." +msgstr "" +"Autenticazione richiesta per consentire alle applicazioni di inibire il sistema in pausa." + +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "Consenti alle applicazioni di ritardare il sistema in pausa" + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "" +"Authentication is required to allow an application to delay system sleep." +msgstr "" +"Autenticazione richiesta per consentire alle applicazioni di ritardare il sistema in pausa." + +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "Consenti alle applicazioni di inibire la sospesione automatica del sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:10 +msgid "" +"Authentication is required to allow an application to inhibit automatic " +"system suspend." +msgstr "" +"Autenticazione richiesta per consentire alle applicazioni di inibire " +"la sospensione automatica del sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "Consenti alle applicazioni di inibire al sistema la gestione del tasto di accensione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:12 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the power key." +msgstr "" +"Autenticazione richiesta per consentire alle applicazioni di inibire al sistema la gestione " +"del tasto di accensione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "Consenti alle applicazioni di inibire al sistema la gestione del tasto di sospensione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the suspend key." +msgstr "" +"Autenticazione richiesta per consentire ad un'applicazione di inibire al sistema la gestione " +"del tasto di sospensione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "Consenti alle applicazioni di inibire al sistema la gestione del tasto di ibernazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:16 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the hibernate key." +msgstr "" +"Autenticazione richiesta per consentire ad un'applicazione di inibire " +"al sistema la gestione del tasto di ibernazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "Consenti alle applicazioni di inibire al sistema la gestione degli eventi " +"relativi alla chiusura del portatile" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the lid switch." +msgstr "" +"Autenticazione richiesta per consentire alle applicazioni di inibire " +"al sistema la gestione degli eventi relativi alla chiusura del portatile." + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "Consenti agli utenti non connessi di eseguire programmi" + +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "" +"Authentication is required to allow a non-logged-in user to run programs." +msgstr "" +"Autenticazione richiesta per consentire agli utenti non connessi di eseguire programmi." + +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "Consenti di collegare dispositivi alle postazioni" + +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "Autenticazione richiesta per collegare un dispositivo alla postazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:23 +msgid "Flush device to seat attachments" +msgstr "Scollega i dispositivi dalla postazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "" +"Authentication is required for resetting how devices are attached to seats." +msgstr "" +"Autenticazione richiesta per scollegare i dispositivi dalla postazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 +msgid "Power off the system" +msgstr "Spegnere il sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "Autenticazione richiesta per spegnere il sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" +msgstr "Spegnere il sistema mentre altri utenti sono connessi" + +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "" +"Authentication is required for powering off the system while other users are " +"logged in." +msgstr "" +"Autenticazione richiesta per spegnere il sistema mentre altri utenti " +"sono connessi." + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "Spegnere il sistema nonostante l'inibizione di una applicazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "" +"Authentication is required for powering off the system while an application " +"asked to inhibit it." +msgstr "" +"Autenticazione richiesta per spegnere il sistema nonostante l'inibizione " +"di una applicazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 +msgid "Reboot the system" +msgstr "Riavviare il sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "Autenticazione richiesta per riavviare il sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" +msgstr "Riavviare il sistema mentre altri utenti sono connessi" + +#: ../src/login/org.freedesktop.login1.policy.in.h:34 +msgid "" +"Authentication is required for rebooting the system while other users are " +"logged in." +msgstr "" +"Autenticazione richiesta per riavviare il sistema mentre altri utenti " +"sono connessi." + +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "Riavviare il sistema nonostante l'inibizione di una applicazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 +msgid "" +"Authentication is required for rebooting the system while an application " +"asked to inhibit it." +msgstr "" +"Autenticazione richiesta per riavviare il sistema nonostante l'inibizione " +"di una applicazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "Sospendere il sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "Autenticazione richiesta per sospendere il sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "Sospendere il sistema mentre altri utenti sono connessi" + +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "" +"Authentication is required for suspending the system while other users are " +"logged in." +msgstr "" +"Autenticazione richiesta per sospendere il sistema mentre altri utenti " +"sono connessi." + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "Sospendere il sistema nonostante l'inibizione di una applicazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "" +"Authentication is required for suspending the system while an application " +"asked to inhibit it." +msgstr "" +"Autenticazione richiesta per sospendere il sistema nonostante l'inibizione " +"di una applicazione." + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "Ibernare il sistema" + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "Autenticazione richiesta per ibernare il sistema." + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "Ibernare il sistema mentre altri utenti sono connessi" + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "" +"Authentication is required for hibernating the system while other users are " +"logged in." +msgstr "" +"Autenticazione richiesta per ibernare il sistema mentre altri utenti " +"sono connessi." + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "Ibernare il sistema nonostante l'inibizione di una applicazione" + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "" +"Authentication is required for hibernating the system while an application " +"asked to inhibit it." +msgstr "" +"Autenticazione richiesta per ibernare il sistema nonostante l'inibizione " +"di una applicazione." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "Configura l'orario di sistema" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 +msgid "Authentication is required to set the system time." +msgstr "Autenticazione richiesta per configurare l'orario di sistema." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "Configura il fuso orario di sistema" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 +msgid "Authentication is required to set the system timezone." +msgstr "Autenticazione richiesta per configurare il fuso orario di sistema." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 +msgid "Set RTC to local timezone or UTC" +msgstr "Configura l'orologio di sistema (RTC) al fuso orario locale o al tempo civile (UTC)" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" +"Autenticazione richiesta per verificare se l'orologio di sistema (RTC) " +"è configurato all'orario locale o al tempo civile (UTC)." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 +msgid "Turn network time synchronization on or off" +msgstr "Abilita o meno la sincronizzazione dell'orario in rete" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" +"Autenticazione richiesta per verificare se la sincronizzazione dell'orario " +"in rete debba essere attivata." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "Inviare la frase segreta (passphrase) al sistema" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" +"Autenticazione richiesta per inviare la frase segreta (passphrase) al sistema." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Privileged system and service manager access" +msgstr "Accesso privilegiato per la gestione del sistema e dei servizi" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to access the system and service manager." +msgstr "Autenticazione richiesta per la gestione del sistema e dei servizi." diff --git a/po/pl.po b/po/pl.po index 3816864..6a95d2f 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1,12 +1,13 @@ # translation of pl.po to Polish -# Piotr Drąg , 2011. +# Piotr Drąg , 2011, 2013. +# Zbigniew Jędrzejewski-Szmek , 2011. # msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-08-22 15:43+0200\n" -"PO-Revision-Date: 2011-08-22 15:45+0200\n" +"POT-Creation-Date: 2013-01-12 19:29+0100\n" +"PO-Revision-Date: 2013-01-12 19:30+0100\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "Language: pl\n" @@ -14,16 +15,19 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../src/org.freedesktop.hostname1.policy.in.h:1 -msgid "Authentication is required to set local machine information." -msgstr "" -"Wymagane jest uwierzytelnienie, aby ustawić informacje o lokalnym komputerze." +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "Ustawienie nazwy komputera" -#: ../src/org.freedesktop.hostname1.policy.in.h:2 +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 msgid "Authentication is required to set the local host name." msgstr "Wymagane jest uwierzytelnienie, aby ustawić nazwę lokalnego komputera." -#: ../src/org.freedesktop.hostname1.policy.in.h:3 +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "Ustawienie statycznej nazwy komputera" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 msgid "" "Authentication is required to set the statically configured local host name, " "as well as the pretty host name." @@ -31,136 +35,357 @@ msgstr "" "Wymagane jest uwierzytelnienie, aby ustawić statycznie skonfigurowaną nazwę " "lokalnego komputera, a także jego ładną nazwę." -#: ../src/org.freedesktop.hostname1.policy.in.h:4 -msgid "Set host name" -msgstr "Ustawienie nazwy komputera" - -#: ../src/org.freedesktop.hostname1.policy.in.h:5 +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 msgid "Set machine information" msgstr "Ustawienie informacji o komputerze" -#: ../src/org.freedesktop.hostname1.policy.in.h:6 -msgid "Set static host name" -msgstr "Ustawienie statycznej nazwy komputera" +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "" +"Wymagane jest uwierzytelnienie, aby ustawić informacje o lokalnym komputerze." -#: ../src/org.freedesktop.locale1.policy.in.h:1 +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "Ustawienie lokalizacji systemu" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 msgid "Authentication is required to set the system locale." msgstr "Wymagane jest uwierzytelnienie, aby ustawić lokalizację systemu." -#: ../src/org.freedesktop.locale1.policy.in.h:2 -msgid "Set system locale" -msgstr "Ustawienie lokalizacji systemu" +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "Ustawienie klawiatury systemu" -#: ../src/org.freedesktop.login1.policy.in.h:1 -msgid "Allow attaching devices to seats" -msgstr "Zezwolenie na podłączanie urządzeń do stanowisk" +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "Wymagane jest uwierzytelnienie, aby ustawić klawiaturę systemu." -#: ../src/org.freedesktop.login1.policy.in.h:2 -msgid "Allow non-logged-in users to run programs" -msgstr "Zezwolenie niezalogowanym użytkownikom na uruchamianie programów" +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "Zezwolenie programom na wstrzymywanie wyłączenia systemu" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "" +"Authentication is required to allow an application to inhibit system " +"shutdown." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"wyłączenia systemu." + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "Zezwolenie programom na opóźnienie wyłączenia systemu" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "" +"Authentication is required to allow an application to delay system shutdown." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na opóźnienie " +"wyłączenia systemu." + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "Zezwolenie programom na wstrzymanie uśpienia systemu" -#: ../src/org.freedesktop.login1.policy.in.h:3 +#: ../src/login/org.freedesktop.login1.policy.in.h:6 msgid "" -"Authentication is required to allow a non-logged-in user to run programs" +"Authentication is required to allow an application to inhibit system sleep." msgstr "" -"Wymagane jest uwierzytelnienie, aby ustawić zezwolić niezalogowanym " -"użytkownikom na uruchamianie programów" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"uśpienia systemu." -#: ../src/org.freedesktop.login1.policy.in.h:4 -msgid "Authentication is required to allow attaching a device to a seat" +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "Zezwolenie programom na opóźnienie uśpienia systemu" + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "" +"Authentication is required to allow an application to delay system sleep." msgstr "" -"Wymagane jest uwierzytelnienie, aby zezwolić na podłączenie urządzenia do " -"stanowiska" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na opóźnienie " +"uśpienia systemu." -#: ../src/org.freedesktop.login1.policy.in.h:5 -msgid "Authentication is required to allow powering off the system" -msgstr "Wymagane jest uwierzytelnienie, aby zezwolić na wyłączanie systemu" +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "Zezwolenie programom na wstrzymanie automatycznego uśpienia systemu" -#: ../src/org.freedesktop.login1.policy.in.h:6 +#: ../src/login/org.freedesktop.login1.policy.in.h:10 msgid "" -"Authentication is required to allow powering off the system while other " -"users are logged in" +"Authentication is required to allow an application to inhibit automatic " +"system suspend." msgstr "" -"Wymagane jest uwierzytelnienie, aby zezwolić na wyłączanie systemu, kiedy są " -"zalogowani inni użytkownicy" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"automatycznego uśpienia systemu." -#: ../src/org.freedesktop.login1.policy.in.h:7 -msgid "Authentication is required to allow rebooting the system" +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" msgstr "" -"Wymagane jest uwierzytelnienie, aby zezwolić na ponowne uruchamianie systemu" +"Zezwolenie programom na wstrzymanie obsługi klawisza zasilania przez system" -#: ../src/org.freedesktop.login1.policy.in.h:8 +#: ../src/login/org.freedesktop.login1.policy.in.h:12 msgid "" -"Authentication is required to allow rebooting the system while other users " -"are logged in" +"Authentication is required to allow an application to inhibit system " +"handling of the power key." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"obsługi klawisza zasilania przez system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" +"Zezwolenie programom na wstrzymanie obsługi klawisza uśpienia przez system" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the suspend key." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"obsługi klawisza uśpienia przez system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" msgstr "" -"Wymagane jest uwierzytelnienie, aby zezwolić na ponowne uruchamianie " -"systemu, kiedy są zalogowani inni użytkownicy" +"Zezwolenie programom na wstrzymanie obsługi klawisza hibernacji przez system" -#: ../src/org.freedesktop.login1.policy.in.h:9 +#: ../src/login/org.freedesktop.login1.policy.in.h:16 msgid "" -"Authentication is required to allow resetting how devices are attached to " -"seats" +"Authentication is required to allow an application to inhibit system " +"handling of the hibernate key." msgstr "" -"Wymagane jest uwierzytelnienie, aby zezwolić na ponowne ustawianie sposobu " -"podłączenia urządzeń do stanowisk" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"obsługi klawisza hibernacji przez system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" +"Zezwolenie programom na wstrzymanie obsługi przełącznika pokrywy przez system" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +msgid "" +"Authentication is required to allow an application to inhibit system " +"handling of the lid switch." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić programowi na wstrzymanie " +"obsługi przełącznika pokrywy przez system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "Zezwolenie niezalogowanym użytkownikom na uruchamianie programów" -#: ../src/org.freedesktop.login1.policy.in.h:10 +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "" +"Authentication is required to allow a non-logged-in user to run programs." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zezwolić niezalogowanemu użytkownikowi " +"na uruchamianie programów." + +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "Zezwolenie na podłączanie urządzeń do stanowisk" + +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "" +"Wymagane jest uwierzytelnienie, aby podłączyć urządzenie do stanowiska." + +#: ../src/login/org.freedesktop.login1.policy.in.h:23 msgid "Flush device to seat attachments" msgstr "Usunięcie podłączenia urządzeń do stanowisk" -#: ../src/org.freedesktop.login1.policy.in.h:11 +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "" +"Authentication is required for resetting how devices are attached to seats." +msgstr "" +"Wymagane jest uwierzytelnienie, aby ponownie ustawić sposób podłączenia " +"urządzeń do stanowisk." + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 msgid "Power off the system" msgstr "Wyłączenie systemu" -#: ../src/org.freedesktop.login1.policy.in.h:12 -msgid "Power off the system when other users are logged in" +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "Wymagane jest uwierzytelnienie, aby wyłączyć system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" msgstr "Wyłączenie systemu, kiedy są zalogowani inni użytkownicy" -#: ../src/org.freedesktop.login1.policy.in.h:13 +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "" +"Authentication is required for powering off the system while other users are " +"logged in." +msgstr "" +"Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy są zalogowani " +"inni użytkownicy." + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "Wyłączenie systemu, kiedy program zażądał jego wstrzymania" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "" +"Authentication is required for powering off the system while an application " +"asked to inhibit it." +msgstr "" +"Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy program zażądał " +"jego wstrzymania." + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 msgid "Reboot the system" msgstr "Ponowne uruchomienie systemu" -#: ../src/org.freedesktop.login1.policy.in.h:14 -msgid "Reboot the system when other users are logged in" +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" msgstr "Ponowne uruchomienie systemu, kiedy są zalogowani inni użytkownicy" -#: ../src/org.freedesktop.timedate1.policy.in.h:1 +#: ../src/login/org.freedesktop.login1.policy.in.h:34 msgid "" -"Authentication is required to control whether network time synchronization " -"shall be enabled." +"Authentication is required for rebooting the system while other users are " +"logged in." msgstr "" -"Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację " -"czasu przez sieć." +"Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy są " +"zalogowani inni użytkownicy." -#: ../src/org.freedesktop.timedate1.policy.in.h:2 +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "" +"Ponowne uruchomienie systemu, kiedy program poprosił o jego wstrzymanie" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 msgid "" -"Authentication is required to control whether the RTC stores the local or " -"UTC time." +"Authentication is required for rebooting the system while an application " +"asked to inhibit it." msgstr "" -"Wymagane jest uwierzytelnienie, aby kontrolować, czy RTC przechowuje czas " -"lokalny lub czas UTC." +"Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy program " +"zażądał jego wstrzymania." + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "Uśpienie systemu" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "Wymagane jest uwierzytelnienie, aby uśpić system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "Uśpienie systemu, kiedy są zalogowani inni użytkownicy" -#: ../src/org.freedesktop.timedate1.policy.in.h:3 +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "" +"Authentication is required for suspending the system while other users are " +"logged in." +msgstr "" +"Wymagane jest uwierzytelnienie, aby uśpić system, kiedy są zalogowani inni " +"użytkownicy." + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "Uśpienie systemu, kiedy program poprosił o jego wstrzymanie" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "" +"Authentication is required for suspending the system while an application " +"asked to inhibit it." +msgstr "" +"Wymagane jest uwierzytelnienie, aby uśpić system, kiedy program zażądał jego " +"wstrzymania." + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "Hibernacja systemu" + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "Wymagane jest uwierzytelnienie, aby zahibernować system." + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "Hibernacja systemu, kiedy są zalogowani inni użytkownicy" + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "" +"Authentication is required for hibernating the system while other users are " +"logged in." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy są zalogowani " +"inni użytkownicy." + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "Hibernacja systemu, kiedy program zażądał jej wstrzymania" + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "" +"Authentication is required for hibernating the system while an application " +"asked to inhibit it." +msgstr "" +"Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program " +"zażądał jej wstrzymania." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "Ustawienie czasu systemu" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 msgid "Authentication is required to set the system time." msgstr "Wymagane jest uwierzytelnienie, aby ustawić czas systemu." -#: ../src/org.freedesktop.timedate1.policy.in.h:4 +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "Ustawienie strefy czasowej systemu" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 msgid "Authentication is required to set the system timezone." msgstr "Wymagane jest uwierzytelnienie, aby ustawić strefę czasową systemu." -#: ../src/org.freedesktop.timedate1.policy.in.h:5 +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 msgid "Set RTC to local timezone or UTC" msgstr "Ustawienie RTC na lokalną strefę czasową lub strefę UTC" -#: ../src/org.freedesktop.timedate1.policy.in.h:6 -msgid "Set system time" -msgstr "Ustawienie czasu systemu" - -#: ../src/org.freedesktop.timedate1.policy.in.h:7 -msgid "Set system timezone" -msgstr "Ustawienie strefy czasowej systemu" +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" +"Wymagane jest uwierzytelnienie, aby kontrolować, czy RTC przechowuje czas " +"lokalny lub czas UTC." -#: ../src/org.freedesktop.timedate1.policy.in.h:8 +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 msgid "Turn network time synchronization on or off" msgstr "Włączenie lub wyłączenie synchronizacji czasu przez sieć" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" +"Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację " +"czasu przez sieć." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "Wysłanie hasła z powrotem do systemu" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" +"Wymagane jest uwierzytelnienie, aby wysłać podane hasło z powrotem do " +"systemu." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Privileged system and service manager access" +msgstr "Uprawniony dostęp do menedżera systemu i usług" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to access the system and service manager." +msgstr "" +"Wymagane jest uwierzytelnienie, aby uzyskać dostęp do menedżera systemu i " +"usług." diff --git a/po/ru.po b/po/ru.po new file mode 100644 index 0000000..1ad4efb --- /dev/null +++ b/po/ru.po @@ -0,0 +1,295 @@ +# translation of ru.po to Rissian +# Julia Dronova , 2013. +# Sergey Ptashnick <0comffdiz@inbox.ru>, 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: 0comffdiz@inbox.ru\n" +"POT-Creation-Date: 2013-03-24 19:22+0300\n" +"PO-Revision-Date: 2013-11-18 02:18+0400\n" +"Last-Translator: Sergey Ptashnick <0comffdiz@inbox.ru>\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "Настроить имя компьютера" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 +msgid "Authentication is required to set the local host name." +msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "Настроить статическое имя компьютера" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 +msgid "Authentication is required to set the statically configured local host name, as well as the pretty host name." +msgstr "Чтобы настроить статическое имя компьютера, а также его «красивое» имя, необходимо пройти аутентификацию." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 +msgid "Set machine information" +msgstr "Настроить информацию о компьютере" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "Чтобы настроить информацию о компьютере, необходимо пройти аутентификацию." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "Настроить системную локаль" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 +msgid "Authentication is required to set the system locale." +msgstr "Чтобы настроить системную локаль, необходимо пройти аутентификацию." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "Настроить параметры клавиатуры" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "Чтобы настроить параметры клавиатуры, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "Разрешить приложениям устанавливать блокировку на выключение системы" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "Authentication is required to allow an application to inhibit system shutdown." +msgstr "Чтобы разрешить приложениям устанавливать блокировку на выключение системы, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "Разрешить приложениям устанавливать задержку на выключение системы" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "Authentication is required to allow an application to delay system shutdown." +msgstr "Чтобы разрешить приложениям устанавливать задержку на выключение системы, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "Разрешить приложениям устанавливать блокировку на засыпание системы" + +#: ../src/login/org.freedesktop.login1.policy.in.h:6 +msgid "Authentication is required to allow an application to inhibit system sleep." +msgstr "Чтобы разрешить приложениям устанавливать блокировку на засыпание системы, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "Разрешить приложениям устанавливать задержку на засыпание системы" + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "Authentication is required to allow an application to delay system sleep." +msgstr "Чтобы разрешить приложениям устанавливать задержку на засыпание системы, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "Разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим" + +#: ../src/login/org.freedesktop.login1.policy.in.h:10 +msgid "Authentication is required to allow an application to inhibit automatic system suspend." +msgstr "Чтобы разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения" + +#: ../src/login/org.freedesktop.login1.policy.in.h:12 +msgid "Authentication is required to allow an application to inhibit system handling of the power key." +msgstr "Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "Authentication is required to allow an application to inhibit system handling of the suspend key." +msgstr "Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим" + +#: ../src/login/org.freedesktop.login1.policy.in.h:16 +msgid "Authentication is required to allow an application to inhibit system handling of the hibernate key." +msgstr "Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "Разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +msgid "Authentication is required to allow an application to inhibit system handling of the lid switch." +msgstr "Чтобы разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "Разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса" + +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "Authentication is required to allow a non-logged-in user to run programs." +msgstr "Чтобы разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "Разрешить подключение устройств к рабочим местам" + +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "Чтобы разрешить подключение устройств к рабочим местам, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:23 +msgid "Flush device to seat attachments" +msgstr "Сбросить привязки устройств к рабочим местам" + +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "Authentication is required for resetting how devices are attached to seats." +msgstr "Чтобы сбросить привязки устройств к рабочим местам, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 +msgid "Power off the system" +msgstr "Выключить систему" + +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "Чтобы выключить систему, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" +msgstr "Выключить систему, несмотря на то, что в ней работают другие пользователи" + +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "Authentication is required for powering off the system while other users are logged in." +msgstr "Чтобы выключить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "Выключить систему, несмотря на то, что приложение запросило блокировку выключения" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "Authentication is required for powering off the system while an application asked to inhibit it." +msgstr "Чтобы выключить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 +msgid "Reboot the system" +msgstr "Перезагрузить систему" + +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "Чтобы перезагрузить систему, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" +msgstr "Перезагрузить систему, несмотря на то, что в ней работают другие пользователи" + +#: ../src/login/org.freedesktop.login1.policy.in.h:34 +msgid "Authentication is required for rebooting the system while other users are logged in." +msgstr "Чтобы перезагрузить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "Перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 +msgid "Authentication is required for rebooting the system while an application asked to inhibit it." +msgstr "Чтобы перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "Перевести систему в ждущий режим" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "Чтобы перевести систему в ждущий режим, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "Перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи" + +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "Authentication is required for suspending the system while other users are logged in." +msgstr "Чтобы перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "Перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "Authentication is required for suspending the system while an application asked to inhibit it." +msgstr "Чтобы перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "Перевести систему в спящий режим" + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "Чтобы перевести систему в спящий режим, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "Перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи" + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "Authentication is required for hibernating the system while other users are logged in." +msgstr "Чтобы перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "Перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку" + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "Authentication is required for hibernating the system while an application asked to inhibit it." +msgstr "Чтобы перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "Настроить системное время" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 +msgid "Authentication is required to set the system time." +msgstr "Чтобы настроить системное время, необходимо пройти аутентификацию." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "Настроить часовой пояс" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 +msgid "Authentication is required to set the system timezone." +msgstr "Чтобы настроить часовой пояс, необходимо пройти аутентификацию." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 +msgid "Set RTC to local timezone or UTC" +msgstr "Установить аппаратные часы по местному времени или по Гринвичу" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "Authentication is required to control whether the RTC stores the local or UTC time." +msgstr "Чтобы контролировать, установлены аппаратные часы по местному времени или по Гринвичу, необходимо пройти аутентификацию." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 +msgid "Turn network time synchronization on or off" +msgstr "Включить или выключить синхронизацию времени по сети" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "Authentication is required to control whether network time synchronization shall be enabled." +msgstr "Чтобы включить или выключить синхронизацию времени по сети, необходимо пройти аутентификацию." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "Отправить пароль системе" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "Authentication is required to send the entered passphrase back to the system." +msgstr "Чтобы отправить пароль системе, необходимо пройти аутентификацию." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Privileged system and service manager access" +msgstr "Привилегированный доступ к системному менеджеру" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to access the system and service manager." +msgstr "Для привилегированного доступа к системному менеджеру необходимо пройти аутентификацию." diff --git a/rules/.gitignore b/rules/.gitignore new file mode 100644 index 0000000..93a50dd --- /dev/null +++ b/rules/.gitignore @@ -0,0 +1 @@ +/99-systemd.rules diff --git a/rules/42-usb-hid-pm.rules b/rules/42-usb-hid-pm.rules new file mode 100644 index 0000000..3fd6e8a --- /dev/null +++ b/rules/42-usb-hid-pm.rules @@ -0,0 +1,39 @@ +# do not edit this file, it will be overwritten on update +# +# Enable autosuspend for qemu emulated usb hid devices + +# Note that there are buggy qemu versions which advertise remote +# wakeup support but don't actually implement it correctly. This +# is the reason why we need a match for the serial number here. +# The serial number "42" is used to tag the implementations where +# remote wakeup is working. +ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Mouse", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto" +ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Tablet", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto" +ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Keyboard", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto" + +# Catch-all for Avocent HID devices. Keyed off interface in order to only +# trigger on HID class devices. +ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="0624", ATTR{bInterfaceClass}=="03", TEST=="../power/control", ATTR{../power/control}="auto" + +# Dell DRAC 4 +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="2500", TEST=="power/control", ATTR{power/control}="auto" + +# Dell DRAC 5 +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="0000", TEST=="power/control", ATTR{power/control}="auto" + +# IBM remote access +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4001", TEST=="power/control", ATTR{power/control}="auto" +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4002", TEST=="power/control", ATTR{power/control}="auto" +ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="04b3", ATTR{idProduct}=="4012", TEST=="power/control", ATTR{power/control}="auto" + +# Raritan Computer, Inc KVM. +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="14dd", ATTR{idProduct}=="0002", TEST=="power/control", ATTR{power/control}="auto" + +# USB HID devices that are internal to the machine should also be safe to autosuspend + +ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTRS{removable}=="removable", GOTO="usb_hid_pm_end" +ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTRS{removable}=="unknown", GOTO="usb_hid_pm_end" + +ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="03", ATTRS{removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto" + +LABEL="usb_hid_pm_end" diff --git a/rules/50-firmware.rules b/rules/50-firmware.rules new file mode 100644 index 0000000..f0ae684 --- /dev/null +++ b/rules/50-firmware.rules @@ -0,0 +1,3 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM=="firmware", ACTION=="add", RUN{builtin}="firmware" diff --git a/rules/50-udev-default.rules b/rules/50-udev-default.rules new file mode 100644 index 0000000..679dfdf --- /dev/null +++ b/rules/50-udev-default.rules @@ -0,0 +1,69 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM=="virtio-ports", KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}" + +# select "system RTC" or just use the first one +SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc" +SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100" + +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" +SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id" +ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}" + +ACTION!="add", GOTO="default_permissions_end" + +SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666" +SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666" +SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620" +SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty" +KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout" + +SUBSYSTEM=="mem", KERNEL=="mem|kmem|port", GROUP="kmem", MODE="0640" + +SUBSYSTEM=="input", KERNEL=="js[0-9]*", MODE="0664" + +SUBSYSTEM=="video4linux", GROUP="video" +SUBSYSTEM=="misc", KERNEL=="agpgart", GROUP="video" +SUBSYSTEM=="graphics", GROUP="video" +SUBSYSTEM=="drm", GROUP="video" +SUBSYSTEM=="dvb", GROUP="video" + +SUBSYSTEM=="sound", GROUP="audio", \ + OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer" + +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664" + +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", GROUP="video" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", GROUP="video" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", GROUP="video" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", GROUP="video" + +KERNEL=="parport[0-9]*", GROUP="lp" +SUBSYSTEM=="printer", KERNEL=="lp*", GROUP="lp" +SUBSYSTEM=="ppdev", GROUP="lp" +KERNEL=="lp[0-9]*", GROUP="lp" +KERNEL=="irlpt[0-9]*", GROUP="lp" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", GROUP="lp" + +SUBSYSTEM=="block", GROUP="disk" +SUBSYSTEM=="block", KERNEL=="fd[0-9]", GROUP="floppy" +SUBSYSTEM=="block", KERNEL=="sr[0-9]*", GROUP="cdrom" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", GROUP="cdrom" +KERNEL=="sch[0-9]*", GROUP="cdrom" +KERNEL=="pktcdvd[0-9]*", GROUP="cdrom" +KERNEL=="pktcdvd", GROUP="cdrom" + +SUBSYSTEM=="scsi_generic|scsi_tape", SUBSYSTEMS=="scsi", ATTRS{type}=="1|8", GROUP="tape" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="0", GROUP="disk" +KERNEL=="qft[0-9]*|nqft[0-9]*|zqft[0-9]*|nzqft[0-9]*|rawqft[0-9]*|nrawqft[0-9]*", GROUP="disk" +KERNEL=="rawctl", GROUP="disk" +SUBSYSTEM=="raw", KERNEL=="raw[0-9]*", GROUP="disk" +SUBSYSTEM=="aoe", GROUP="disk", MODE="0220" +SUBSYSTEM=="aoe", KERNEL=="err", MODE="0440" + +KERNEL=="rfkill", MODE="0664" +KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun" + +KERNEL=="fuse", MODE="0666", OPTIONS+="static_node=fuse" + +LABEL="default_permissions_end" diff --git a/rules/60-cdrom_id.rules b/rules/60-cdrom_id.rules new file mode 100644 index 0000000..6eaf76a --- /dev/null +++ b/rules/60-cdrom_id.rules @@ -0,0 +1,20 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="cdrom_end" +SUBSYSTEM!="block", GOTO="cdrom_end" +KERNEL!="sr[0-9]*|xvd*", GOTO="cdrom_end" +ENV{DEVTYPE}!="disk", GOTO="cdrom_end" + +# unconditionally tag device as CDROM +KERNEL=="sr[0-9]*", ENV{ID_CDROM}="1" + +# media eject button pressed +ENV{DISK_EJECT_REQUEST}=="?*", RUN+="cdrom_id --eject-media $devnode", GOTO="cdrom_end" + +# import device and media properties and lock tray to +# enable the receiving of media eject button events +IMPORT{program}="cdrom_id --lock-media $devnode" + +KERNEL=="sr0", SYMLINK+="cdrom", OPTIONS+="link_priority=-100" + +LABEL="cdrom_end" diff --git a/rules/60-drm.rules b/rules/60-drm.rules new file mode 100644 index 0000000..1ed3e44 --- /dev/null +++ b/rules/60-drm.rules @@ -0,0 +1,3 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="remove", SUBSYSTEM=="drm", SUBSYSTEMS=="pci|usb|platform", IMPORT{builtin}="path_id" diff --git a/rules/60-keyboard.rules b/rules/60-keyboard.rules new file mode 100644 index 0000000..4e0f366 --- /dev/null +++ b/rules/60-keyboard.rules @@ -0,0 +1,22 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add", GOTO="keyboard_end" +KERNEL!="event*", GOTO="keyboard_end" +ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end" + +# ignore all bluetooth devices +SUBSYSTEMS=="bluetooth", GOTO="keyboard_end" + +# import key mapping for USB device +SUBSYSTEMS=="usb", IMPORT{builtin}="hwdb --subsystem=usb --lookup-prefix=keyboard:", \ + RUN{builtin}+="keyboard", GOTO="keyboard_end" + +# import key mapping for AT keyboard from DMI data +DRIVERS=="atkbd", IMPORT{builtin}="hwdb 'keyboard:$attr{[dmi/id]modalias}'", \ + RUN{builtin}+="keyboard", GOTO="keyboard_end" + +# import key mapping for platform input device +KERNELS=="input*", IMPORT{builtin}="hwdb 'keyboard:name:$attr{name}:$attr{[dmi/id]modalias}'", \ + RUN{builtin}+="keyboard", GOTO="keyboard_end" + +LABEL="keyboard_end" diff --git a/rules/60-persistent-alsa.rules b/rules/60-persistent-alsa.rules new file mode 100644 index 0000000..8154e2d --- /dev/null +++ b/rules/60-persistent-alsa.rules @@ -0,0 +1,14 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="persistent_alsa_end" +SUBSYSTEM!="sound", GOTO="persistent_alsa_end" +KERNEL!="controlC[0-9]*", GOTO="persistent_alsa_end" + +SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id" +ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}" +ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}" + +IMPORT{builtin}="path_id" +ENV{ID_PATH}=="?*", SYMLINK+="snd/by-path/$env{ID_PATH}" + +LABEL="persistent_alsa_end" diff --git a/rules/60-persistent-input.rules b/rules/60-persistent-input.rules new file mode 100644 index 0000000..0e33e68 --- /dev/null +++ b/rules/60-persistent-input.rules @@ -0,0 +1,38 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="persistent_input_end" +SUBSYSTEM!="input", GOTO="persistent_input_end" +SUBSYSTEMS=="bluetooth", GOTO="persistent_input_end" + +SUBSYSTEMS=="usb", ENV{ID_BUS}=="", IMPORT{builtin}="usb_id" + +# determine class name for persistent symlinks +ENV{ID_INPUT_KEYBOARD}=="?*", ENV{.INPUT_CLASS}="kbd" +ENV{ID_INPUT_MOUSE}=="?*", ENV{.INPUT_CLASS}="mouse" +ENV{ID_INPUT_TOUCHPAD}=="?*", ENV{.INPUT_CLASS}="mouse" +ENV{ID_INPUT_TABLET}=="?*", ENV{.INPUT_CLASS}="mouse" +ENV{ID_INPUT_JOYSTICK}=="?*", ENV{.INPUT_CLASS}="joystick" +DRIVERS=="pcspkr", ENV{.INPUT_CLASS}="spkr" +ATTRS{name}=="*dvb*|*DVB*|* IR *", ENV{.INPUT_CLASS}="ir" + +# fill empty serial number +ENV{.INPUT_CLASS}=="?*", ENV{ID_SERIAL}=="", ENV{ID_SERIAL}="noserial" + +# by-id links +KERNEL=="mouse*|js*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="|00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{.INPUT_CLASS}" +KERNEL=="mouse*|js*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="?*", ATTRS{bInterfaceNumber}!="00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$attr{bInterfaceNumber}-$env{.INPUT_CLASS}" +KERNEL=="event*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="|00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-event-$env{.INPUT_CLASS}" +KERNEL=="event*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="?*", ATTRS{bInterfaceNumber}!="00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$attr{bInterfaceNumber}-event-$env{.INPUT_CLASS}" +# allow empty class for USB devices, by appending the interface number +SUBSYSTEMS=="usb", ENV{ID_BUS}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", ATTRS{bInterfaceNumber}=="?*", \ + SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-event-if$attr{bInterfaceNumber}" + +# by-path +SUBSYSTEMS=="pci|usb|platform|acpi", IMPORT{builtin}="path_id" +ENV{ID_PATH}=="?*", KERNEL=="mouse*|js*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-$env{.INPUT_CLASS}" +ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-event-$env{.INPUT_CLASS}" +# allow empty class for platform and usb devices; platform supports only a single interface that way +SUBSYSTEMS=="usb|platform", ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", \ + SYMLINK+="input/by-path/$env{ID_PATH}-event" + +LABEL="persistent_input_end" diff --git a/rules/60-persistent-serial.rules b/rules/60-persistent-serial.rules new file mode 100644 index 0000000..2948200 --- /dev/null +++ b/rules/60-persistent-serial.rules @@ -0,0 +1,20 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="persistent_serial_end" +SUBSYSTEM!="tty", GOTO="persistent_serial_end" +KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="persistent_serial_end" + +SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}" + +IMPORT{builtin}="path_id" +ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", SYMLINK+="serial/by-path/$env{ID_PATH}" +ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-path/$env{ID_PATH}-port$env{.ID_PORT}" + +IMPORT{builtin}="usb_id" +ENV{ID_SERIAL}=="", GOTO="persistent_serial_end" +SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACE_NUM}="$attr{bInterfaceNumber}" +ENV{ID_USB_INTERFACE_NUM}=="", GOTO="persistent_serial_end" +ENV{.ID_PORT}=="", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}" +ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}-port$env{.ID_PORT}" + +LABEL="persistent_serial_end" diff --git a/rules/60-persistent-storage-tape.rules b/rules/60-persistent-storage-tape.rules new file mode 100644 index 0000000..f2eabd9 --- /dev/null +++ b/rules/60-persistent-storage-tape.rules @@ -0,0 +1,25 @@ +# do not edit this file, it will be overwritten on update + +# persistent storage links: /dev/tape/{by-id,by-path} + +ACTION=="remove", GOTO="persistent_storage_tape_end" + +# type 8 devices are "Medium Changers" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \ + SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL}" + +SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end" + +KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394" +KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" +KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", ENV{.BSG_DEV}="$root/bsg/$id" +KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --whitelisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi" +KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}" +KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst" + +# by-path (parent device path) +KERNEL=="st*[0-9]|nst*[0-9]", IMPORT{builtin}="path_id" +KERNEL=="st*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}" +KERNEL=="nst*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}-nst" + +LABEL="persistent_storage_tape_end" diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules new file mode 100644 index 0000000..4f7163d --- /dev/null +++ b/rules/60-persistent-storage.rules @@ -0,0 +1,87 @@ +# do not edit this file, it will be overwritten on update + +# persistent storage links: /dev/disk/{by-id,by-uuid,by-label,by-path} +# scheme based on "Linux persistent device names", 2004, Hannes Reinecke + +# forward scsi device event to corresponding block device +ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change" + +ACTION=="remove", GOTO="persistent_storage_end" + +# enable in-kernel media-presence polling +ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", ATTR{parameters/events_dfl_poll_msecs}="2000" + +SUBSYSTEM!="block", GOTO="persistent_storage_end" + +# skip rules for inappropriate block devices +KERNEL=="fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*|zram*", GOTO="persistent_storage_end" + +# ignore partitions that span the entire disk +TEST=="whole_disk", GOTO="persistent_storage_end" + +# for partitions import parent information +ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" + +# virtio-blk +KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" +KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n" + +# ATA devices using the "scsi" subsystem +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode" +# ATA/ATAPI devices (SPC-3 or later) using the "scsi" subsystem +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode" + +# Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures) +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode" +# Otherwise, fall back to using usb_id for USB devices +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" + +# scsi devices +KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi" +KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss" +KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}" +KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n" + +# firewire +KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}" +KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n" + +KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}" +KERNEL=="mmcblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n" +KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}" +KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n" + +# by-path (parent device path) +ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id" +ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}" +ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n" + +# skip unpartitioned removable media devices from drivers which do not send "change" events +ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end" + +# probe filesystem metadata of optical drives which have a media inserted +KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \ + IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" +# single-session CDs do not have ID_CDROM_MEDIA_SESSION_LAST_OFFSET +KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="", \ + IMPORT{builtin}="blkid --noraid" + +# probe filesystem metadata of disks +KERNEL!="sr*", IMPORT{builtin}="blkid" + +# watch metadata changes by tools closing the device after writing +KERNEL!="sr*", OPTIONS+="watch" + +# by-label/by-uuid links (filesystem metadata) +ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}" +ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}" + +# by-id (World Wide Name) +ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}" +ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}-part%n" + +# by-partlabel/by-partuuid links (partition metadata) +ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}" +ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}" + +LABEL="persistent_storage_end" diff --git a/rules/60-persistent-v4l.rules b/rules/60-persistent-v4l.rules new file mode 100644 index 0000000..bb69f2c --- /dev/null +++ b/rules/60-persistent-v4l.rules @@ -0,0 +1,21 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="persistent_v4l_end" +SUBSYSTEM!="video4linux", GOTO="persistent_v4l_end" +ENV{MAJOR}=="", GOTO="persistent_v4l_end" + +# tizen will not use video for linux on mobile product. +#IMPORT{program}="v4l_id $devnode" + +SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" +KERNEL=="video*", ENV{ID_SERIAL}=="?*", SYMLINK+="v4l/by-id/$env{ID_BUS}-$env{ID_SERIAL}-video-index$attr{index}" + +# check for valid "index" number +TEST!="index", GOTO="persistent_v4l_end" +ATTR{index}!="?*", GOTO="persistent_v4l_end" + +IMPORT{builtin}="path_id" +ENV{ID_PATH}=="?*", KERNEL=="video*|vbi*", SYMLINK+="v4l/by-path/$env{ID_PATH}-video-index$attr{index}" +ENV{ID_PATH}=="?*", KERNEL=="audio*", SYMLINK+="v4l/by-path/$env{ID_PATH}-audio-index$attr{index}" + +LABEL="persistent_v4l_end" diff --git a/rules/61-accelerometer.rules b/rules/61-accelerometer.rules new file mode 100644 index 0000000..a6a2bfd --- /dev/null +++ b/rules/61-accelerometer.rules @@ -0,0 +1,3 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM=="input", ACTION!="remove", ENV{ID_INPUT_ACCELEROMETER}=="1", IMPORT{program}="accelerometer %p" diff --git a/rules/64-btrfs.rules b/rules/64-btrfs.rules new file mode 100644 index 0000000..fe01001 --- /dev/null +++ b/rules/64-btrfs.rules @@ -0,0 +1,13 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM!="block", GOTO="btrfs_end" +ACTION=="remove", GOTO="btrfs_end" +ENV{ID_FS_TYPE}!="btrfs", GOTO="btrfs_end" + +# let the kernel know about this btrfs filesystem, and check if it is complete +IMPORT{builtin}="btrfs ready $devnode" + +# mark the device as not ready to be used by the system +ENV{ID_BTRFS_READY}=="0", ENV{SYSTEMD_READY}="0" + +LABEL="btrfs_end" diff --git a/rules/75-net-description.rules b/rules/75-net-description.rules new file mode 100644 index 0000000..7e62f8b --- /dev/null +++ b/rules/75-net-description.rules @@ -0,0 +1,14 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="net_end" +SUBSYSTEM!="net", GOTO="net_end" + +IMPORT{builtin}="net_id" + +SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" +SUBSYSTEMS=="usb", GOTO="net_end" + +SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}" +SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" + +LABEL="net_end" diff --git a/rules/75-probe_mtd.rules b/rules/75-probe_mtd.rules new file mode 100644 index 0000000..8848aee --- /dev/null +++ b/rules/75-probe_mtd.rules @@ -0,0 +1,7 @@ +# do not edit this file, it will be overwritten on update + +ACTION!="add", GOTO="mtd_probe_end" + +KERNEL=="mtd*ro", IMPORT{program}="mtd_probe $devnode" + +LABEL="mtd_probe_end" diff --git a/rules/75-tty-description.rules b/rules/75-tty-description.rules new file mode 100644 index 0000000..11277b7 --- /dev/null +++ b/rules/75-tty-description.rules @@ -0,0 +1,12 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="tty_end" +SUBSYSTEM!="tty", GOTO="tty_end" + +SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" +SUBSYSTEMS=="usb", GOTO="tty_end" + +SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}" +SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" + +LABEL="tty_end" diff --git a/rules/78-sound-card.rules b/rules/78-sound-card.rules new file mode 100644 index 0000000..295f490 --- /dev/null +++ b/rules/78-sound-card.rules @@ -0,0 +1,86 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM!="sound", GOTO="sound_end" + +ACTION=="add|change", KERNEL=="controlC*", ATTR{../uevent}="change" +ACTION!="change", GOTO="sound_end" + +# Ok, we probably need a little explanation here for what the two lines above +# are good for. +# +# The story goes like this: when ALSA registers a new sound card it emits a +# series of 'add' events to userspace, for the main card device and for all the +# child device nodes that belong to it. udev relays those to applications, +# however only maintains the order between father and child, but not between +# the siblings. The control device node creation can be used as synchronization +# point. All other devices that belong to a card are created in the kernel +# before it. However unfortunately due to the fact that siblings are forwarded +# out of order by udev this fact is lost to applications. +# +# OTOH before an application can open a device it needs to make sure that all +# its device nodes are completely created and set up. +# +# As a workaround for this issue we have added the udev rule above which will +# generate a 'change' event on the main card device from the 'add' event of the +# card's control device. Due to the ordering semantics of udev this event will +# only be relayed after all child devices have finished processing properly. +# When an application needs to listen for appearing devices it can hence look +# for 'change' events only, and ignore the actual 'add' events. +# +# When the application is initialized at the same time as a device is plugged +# in it may need to figure out if the 'change' event has already been triggered +# or not for a card. To find that out we store the flag environment variable +# SOUND_INITIALIZED on the device which simply tells us if the card 'change' +# event has already been processed. + +KERNEL!="card*", GOTO="sound_end" + +ENV{SOUND_INITIALIZED}="1" + +IMPORT{builtin}="hwdb" +SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" +SUBSYSTEMS=="usb", GOTO="skip_pci" + +SUBSYSTEMS=="firewire", ATTRS{vendor_name}=="?*", ATTRS{model_name}=="?*", \ + ENV{ID_BUS}="firewire", ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}" +SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", ENV{ID_ID}="firewire-$attr{guid}" +SUBSYSTEMS=="firewire", GOTO="skip_pci" + +SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}" +LABEL="skip_pci" + +ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}-$attr{id}" +ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$attr{id}" + +IMPORT{builtin}="path_id" + +# The values used here for $SOUND_FORM_FACTOR and $SOUND_CLASS should be kept +# in sync with those defined for PulseAudio's src/pulse/proplist.h +# PA_PROP_DEVICE_FORM_FACTOR, PA_PROP_DEVICE_CLASS properties. + +# If the first PCM device of this card has the pcm class 'modem', then the card is a modem +ATTR{pcmC%nD0p/pcm_class}=="modem", ENV{SOUND_CLASS}="modem", GOTO="sound_end" + +# Identify cards on the internal PCI bus as internal +SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:??.?/sound/*", ENV{SOUND_FORM_FACTOR}="internal", GOTO="sound_end" + +# Devices that also support Image/Video interfaces are most likely webcams +SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACES}=="*:0e????:*", ENV{SOUND_FORM_FACTOR}="webcam", GOTO="sound_end" + +# Matching on the model strings is a bit ugly, I admit +ENV{ID_MODEL}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end" +ENV{ID_MODEL_FROM_DATABASE}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end" + +ENV{ID_MODEL}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end" +ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end" + +ENV{ID_MODEL}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end" +ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end" + +ENV{ID_MODEL}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end" +ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end" + +ENV{ID_MODEL}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end" +ENV{ID_MODEL_FROM_DATABASE}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end" + +LABEL="sound_end" diff --git a/rules/80-drivers.rules b/rules/80-drivers.rules new file mode 100644 index 0000000..8551f47 --- /dev/null +++ b/rules/80-drivers.rules @@ -0,0 +1,13 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="drivers_end" + +ENV{MODALIAS}=="?*", RUN{builtin}+="kmod load $env{MODALIAS}" +SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", RUN{builtin}+="kmod load tifm_sd" +SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", RUN{builtin}+="kmod load tifm_ms" +SUBSYSTEM=="memstick", RUN{builtin}+="kmod load ms_block mspro_block" +SUBSYSTEM=="i2o", RUN{builtin}+="kmod load i2o_block" +SUBSYSTEM=="module", KERNEL=="parport_pc", RUN{builtin}+="kmod load ppdev" +KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", RUN{builtin}+="kmod load sm_ftl" + +LABEL="drivers_end" diff --git a/rules/80-net-setup-link.rules b/rules/80-net-setup-link.rules new file mode 100644 index 0000000..f390fcb --- /dev/null +++ b/rules/80-net-setup-link.rules @@ -0,0 +1,15 @@ +# do not edit this file, it will be overwritten on update + +SUBSYSTEM!="net", GOTO="net_setup_link_end" + +IMPORT{builtin}="path_id" + +ACTION=="move", IMPORT{db}="ID_NET_DRIVER" + +ACTION!="add", GOTO="net_setup_link_end" + +IMPORT{builtin}="net_setup_link" + +NAME=="", ENV{ID_NET_NAME}!="", NAME="$env{ID_NET_NAME}" + +LABEL="net_setup_link_end" diff --git a/rules/95-udev-late.rules b/rules/95-udev-late.rules new file mode 100644 index 0000000..eca0faa --- /dev/null +++ b/rules/95-udev-late.rules @@ -0,0 +1,4 @@ +# do not edit this file, it will be overwritten on update + +# run a command on remove events +ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}" diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in new file mode 100644 index 0000000..021359a --- /dev/null +++ b/rules/99-systemd.rules.in @@ -0,0 +1,70 @@ +# 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. + +ACTION=="remove", GOTO="systemd_end" + +SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*", TAG+="systemd" + +KERNEL=="vport*", TAG+="systemd" + +SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" +SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" + +# Ignore encrypted devices with no identified superblock on it, since +# we are probably still calling mke2fs or mkswap on it. +SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" + +# Ignore raid devices that are not yet assembled and started +SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0" +SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0" + +# Ignore nbd devices in the "add" event, with "change" the nbd is ready +ACTION=="add", SUBSYSTEM=="block", KERNEL=="nbd*", ENV{SYSTEMD_READY}="0" + +# We need a hardware independent way to identify network devices. We +# use the /sys/subsystem path for this. Current vanilla kernels don't +# actually support that hierarchy right now, however upcoming kernels +# will. HAL and udev internally support /sys/subsystem already, hence +# it should be safe to use this here, too. This is mostly just an +# identification string for systemd, so whether the path actually is +# accessible or not does not matter as long as it is unique and in the +# filesystem namespace. +# +# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n922 + +SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name" +SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k" + +SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}+="bluetooth.target" +ENV{ID_SMARTCARD_READER}=="*?", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target" +SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target" + +SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target" +SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target" + +# Apply sysctl variables to network devices (and only to those) as they appear. + +ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name" + +# Pull in backlight save/restore for all backlight devices and +# keyboard backlights + +SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@backlight:$name.service" +SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@leds:$name.service" + +# Pull in rfkill save/restore for all rfkill devices + +SUBSYSTEM=="rfkill", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-rfkill@$name.service" + +# Asynchronously mount file systems implemented by these modules as +# soon as they are loaded. + +SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount" +SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount" + +LABEL="systemd_end" diff --git a/rules/Makefile b/rules/Makefile new file mode 120000 index 0000000..bd10475 --- /dev/null +++ b/rules/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/shell-completion/bash/bootctl b/shell-completion/bash/bootctl new file mode 100644 index 0000000..c86ec7e --- /dev/null +++ b/shell-completion/bash/bootctl @@ -0,0 +1,60 @@ +# bootctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2014 Thomas H.P. Andersen +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +_bootctl() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local -A OPTS=( + [STANDALONE]='-h --help --version' + ) + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [STANDALONE]='status' + ) + + for ((i=0; i < COMP_CWORD; i++)); do + if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; 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 _bootctl bootctl diff --git a/shell-completion/bash/busctl b/shell-completion/bash/busctl new file mode 100644 index 0000000..06d5d93 --- /dev/null +++ b/shell-completion/bash/busctl @@ -0,0 +1,89 @@ +# busctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2013 Zbigniew Jędrzejewski-Szmek +# Copyright 2014 Thomas H.P. Andersen +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__get_machines() { + local a b + machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; }; +} + +__get_endpoints() { + local a b + busctl list --no-legend --no-pager | { while read a b; do echo " $a"; done; }; +} + +_busctl() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local -A OPTS=( + [STANDALONE]='-h --help --version --no-pager --no-legend --system --user + --show-machine --unique --acquired --activatable' + [ARG]='-H --host -M --machine --address --match' + ) + + if __contains_word "$prev" ${OPTS[ARG]}; then + case $prev in + --host|-H) + comps=$(compgen -A hostname) + ;; + --machine|-M) + comps=$( __get_machines ) + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [STANDALONE]='list help' + [ENDPOINT]='monitor status' + ) + + 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='' + elif __contains_word "$verb" ${VERBS[ENDPOINT]}; then + comps=$( __get_endpoints ) + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _busctl busctl diff --git a/shell-completion/bash/hostnamectl b/shell-completion/bash/hostnamectl new file mode 100644 index 0000000..9c75da9 --- /dev/null +++ b/shell-completion/bash/hostnamectl @@ -0,0 +1,61 @@ +# hostnamectl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +_hostnamectl() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --transient --static --pretty + --no-ask-password -H --host' + + if [[ $cur = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [STANDALONE]='status' + [ICONS]='set-icon-name' + [NAME]='set-hostname' + ) + + for ((i=0; i < COMP_CWORD; i++)); do + if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; then + verb=${COMP_WORDS[i]} + break + fi + done + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[ICONS]} ${VERBS[NAME]}; then + comps='' + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _hostnamectl hostnamectl diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl new file mode 100644 index 0000000..e4b2f4a --- /dev/null +++ b/shell-completion/bash/journalctl @@ -0,0 +1,114 @@ +# journalctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__journal_fields=(MESSAGE{,_ID} PRIORITY CODE_{FILE,LINE,FUNC} + ERRNO SYSLOG_{FACILITY,IDENTIFIER,PID} COREDUMP_EXE + _{P,U,G}ID _COMM _EXE _CMDLINE + _AUDIT_{SESSION,LOGINUID} + _SYSTEMD_{CGROUP,SESSION,UNIT,OWNER_UID} + _SELINUX_CONTEXT _SOURCE_REALTIME_TIMESTAMP + _{BOOT,MACHINE}_ID _HOSTNAME _TRANSPORT + _KERNEL_{DEVICE,SUBSYSTEM} + _UDEV_{SYSNAME,DEVNODE,DEVLINK} + __CURSOR __{REALTIME,MONOTONIC}_TIMESTAMP) + +_journalctl() { + local field_vals= cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local -A OPTS=( + [STANDALONE]='-a --all --full --system --user + --disk-usage -f --follow --header + -h --help -l --local --new-id128 -m --merge --no-pager + --no-tail -q --quiet --setup-keys --this-boot --verify + --version --list-catalog --update-catalog --list-boots' + [ARG]='-b --boot --this-boot -D --directory --file -F --field + -o --output -u --unit --user-unit' + [ARGUNKNOWN]='-c --cursor --interval -n --lines -p --priority --since --until + --verify-key' + ) + + if __contains_word "$prev" ${OPTS[ARG]} ${OPTS[ARGUNKNOWN]}; then + case $prev in + --boot|--this-boot|-b) + comps=$(journalctl -F '_BOOT_ID' 2>/dev/null) + ;; + --directory|-D) + comps=$(compgen -d -- "$cur") + compopt -o filenames + ;; + --file) + comps=$(compgen -f -- "$cur") + compopt -o filenames + ;; + --output|-o) + comps='short short-monotonic verbose export json cat' + ;; + --field|-F) + comps=${__journal_fields[*]} + ;; + --unit|-u) + comps=$(journalctl -F '_SYSTEMD_UNIT' 2>/dev/null) + ;; + --user-unit) + comps=$(journalctl -F '_SYSTEMD_USER_UNIT' 2>/dev/null) + ;; + *) + return 0 + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ $cur = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + elif [[ $cur = *=* ]]; then + mapfile -t field_vals < <(journalctl -F "${prev%=}" 2>/dev/null) + COMPREPLY=( $(compgen -W '${field_vals[*]}' -- "${cur#=}") ) + elif [[ $cur = /dev* ]]; then + compopt -o filenames + COMPREPLY=( $(compgen -f -- "${cur}") ) + elif [[ $cur = /* ]]; then + # Append /dev/ to the list of completions, so that + # after typing / the user sees /dev/ as one + # of the alternatives. Later on the rule above will + # take care of showing device files in /dev/. + mapfile -t field_vals < <(journalctl -F "_EXE" 2>/dev/null; echo '/dev/') + COMPREPLY=( $(compgen -W '${field_vals[*]}' -- "${cur}") ) + if [[ "${COMPREPLY[@]}" = '/dev/' ]]; then + compopt -o filenames + COMPREPLY=( $(compgen -f -- "${cur}") ) + fi + elif [[ $prev = '=' ]]; then + mapfile -t field_vals < <(journalctl -F "${COMP_WORDS[COMP_CWORD-2]}" 2>/dev/null) + COMPREPLY=( $(compgen -W '${field_vals[*]}' -- "$cur") ) + else + compopt -o nospace + COMPREPLY=( $(compgen -W '${__journal_fields[*]}' -S= -- "$cur") ) + fi +} + +complete -F _journalctl journalctl diff --git a/shell-completion/bash/kernel-install b/shell-completion/bash/kernel-install new file mode 100644 index 0000000..7cd2494 --- /dev/null +++ b/shell-completion/bash/kernel-install @@ -0,0 +1,50 @@ +# kernel-install(8) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2013 Kay Sievers +# Copyright 2013 Harald Hoyer +# +# 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 . + +_kernel_install() { + local comps + local MACHINE_ID + local cur=${COMP_WORDS[COMP_CWORD]} + + case $COMP_CWORD in + 1) + comps="add remove" + ;; + 2) + comps=$(cd /lib/modules; echo [0-9]*) + if [[ ${COMP_WORDS[1]} == "remove" ]] && [[ -f /etc/machine-id ]]; then + read MACHINE_ID < /etc/machine-id + if [[ $MACHINE_ID ]] && ( [[ -d /boot/$MACHINE_ID ]] || [[ -L /boot/$MACHINE_ID ]] ); then + comps=$(cd "/boot/$MACHINE_ID"; echo [0-9]*) + fi + fi + ;; + 3) + [[ "$cur" ]] || cur=/boot/vmlinuz-${COMP_WORDS[2]} + comps=$(compgen -f -- "$cur") + compopt -o filenames + ;; + esac + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _kernel_install kernel-install diff --git a/shell-completion/bash/localectl b/shell-completion/bash/localectl new file mode 100644 index 0000000..c9e22af --- /dev/null +++ b/shell-completion/bash/localectl @@ -0,0 +1,92 @@ +# localectl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__locale_fields=( LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME \ + LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER \ + LC_NAME LC_ADDRESS LC_TELEPHONE \ + LC_MEASUREMENT LC_IDENTIFICATION ) +# LC_ALL is omitted on purpose + +_localectl() { + local i verb comps locale_vals + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --no-convert --no-pager --no-ask-password + -H --host' + + if __contains_word "$prev" $OPTS; then + case $prev in + --host|-H) + comps='' + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ $cur = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [STANDALONE]='status list-locales list-keymaps' + [LOCALES]='set-locale' + [KEYMAPS]='set-keymap' + [X11]='set-x11-keymap' + ) + + for ((i=0; i < COMP_CWORD; i++)); do + if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; then + verb=${COMP_WORDS[i]} + break + fi + done + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + elif __contains_word "$verb" ${VERBS[LOCALES]}; then + if [[ $cur = *=* ]]; then + mapfile -t locale_vals < <(command localectl list-locales 2>/dev/null) + COMPREPLY=( $(compgen -W '${locale_vals[*]}' -- "${cur#=}") ) + elif [[ $prev = "=" ]]; then + mapfile -t locale_vals < <(command localectl list-locales 2>/dev/null) + COMPREPLY=( $(compgen -W '${locale_vals[*]}' -- "$cur") ) + else + compopt -o nospace + COMPREPLY=( $(compgen -W '${__locale_fields[*]}' -S= -- "$cur") ) + fi + return 0 + elif __contains_word "$verb" ${VERBS[KEYMAPS]}; then + comps=$(command localectl list-keymaps) + elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[X11]}; then + comps='' + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _localectl localectl diff --git a/shell-completion/bash/loginctl b/shell-completion/bash/loginctl new file mode 100644 index 0000000..e7adb93 --- /dev/null +++ b/shell-completion/bash/loginctl @@ -0,0 +1,109 @@ +# loginctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__get_all_sessions () { loginctl --no-legend list-sessions | { while read -r a b; do printf "%s\n" "$a"; done; } ; } +__get_all_users () { loginctl --no-legend list-users | { while read -r a b; do printf "%s\n" "$b"; done; } ; } +__get_all_seats () { loginctl --no-legend list-seats | { while read -r a b; do printf "%s\n" "$a"; done; } ; } + +_loginctl () { + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local i verb comps + + local -A OPTS=( + [STANDALONE]='--all -a --help -h --no-pager --privileged -P --version' + [ARG]='--host -H --kill-who --property -p --signal -s' + ) + + if __contains_word "$prev" ${OPTS[ARG]}; then + case $prev in + --signal|-s) + comps=$(compgen -A signal) + ;; + --kill-who) + comps='all leader' + ;; + --host|-H) + comps=$(compgen -A hostname) + ;; + --property|-p) + comps='' + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [SESSIONS]='session-status show-session activate lock-session unlock-session terminate-session kill-session' + [USERS]='user-status show-user enable-linger disable-linger terminate-user kill-user' + [SEATS]='seat-status show-seat terminate-seat' + [STANDALONE]='list-sessions list-users list-seats flush-devices' + [ATTACH]='attach' + ) + + 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[SESSIONS]}; then + comps=$( __get_all_sessions ) + + elif __contains_word "$verb" ${VERBS[USERS]}; then + comps=$( __get_all_users ) + + elif __contains_word "$verb" ${VERBS[SEATS]}; then + comps=$( __get_all_seats ) + + elif __contains_word "$verb" ${VERBS[STANDALONE]}; then + comps='' + + elif __contains_word "$verb" ${VERBS[ATTACH]}; then + if [[ $prev = $verb ]]; then + comps=$( __get_all_seats ) + else + comps=$(compgen -A file -- "$cur" ) + compopt -o filenames + fi + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _loginctl loginctl diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl new file mode 100644 index 0000000..3789492 --- /dev/null +++ b/shell-completion/bash/machinectl @@ -0,0 +1,97 @@ +# machinectl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2014 Thomas H.P. Andersen +# +# 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 . + +__contains_word() { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__get_machines() { + local a b + machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; }; +} + +_machinectl() { + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local i verb comps + + local -A OPTS=( + [STANDALONE]='--all -a --full --help -h --no-ask-password --no-legend --no-pager --version' + [ARG]='--host -H --kill-who -M --machine --property -p --signal -s' + ) + + local -A VERBS=( + [STANDALONE]='list' + [MACHINES]='status show terminate kill reboot login' + ) + + _init_completion || return + + 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 __contains_word "$prev" ${OPTS[ARG]}; then + case $prev in + --signal|-s) + comps=$(compgen -A signal) + ;; + --kill-who) + comps='all leader' + ;; + --host|-H) + comps=$(compgen -A hostname) + ;; + --machine|-M) + comps=$( __get_machines ) + ;; + --property|-p) + comps='' + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + + elif __contains_word "$verb" ${VERBS[STANDALONE]}; then + comps='' + + elif __contains_word "$verb" ${VERBS[MACHINES]}; then + comps=$( __get_machines ) + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _machinectl machinectl diff --git a/shell-completion/bash/systemctl b/shell-completion/bash/systemctl new file mode 100644 index 0000000..dc7ef66 --- /dev/null +++ b/shell-completion/bash/systemctl @@ -0,0 +1,229 @@ +# systemctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__systemctl() { + local mode=$1; shift 1 + systemctl $mode --full --no-legend "$@" +} + +__systemd_properties() { + local mode=$1 + { __systemctl -a $mode show; + systemd --dump-configuration-items; } | + while IFS='=' read -r key value; do + [[ $value ]] && echo "$key" + done +} + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__filter_units_by_property () { + local mode=$1 property=$2 value=$3 ; shift 3 + local units=("$@") + local props + IFS=$'\n' read -rd '' -a props < \ + <(__systemctl $mode show --property "$property" -- "${units[@]}") + for ((i=0; $i < ${#units[*]}; i++)); do + if [[ "${props[i]}" = "$property=$value" ]]; then + echo " ${units[i]}" + fi + done +} + +__get_all_units () { __systemctl $1 list-units --all \ + | { while read -r a b; do echo " $a"; done; }; } +__get_active_units () { __systemctl $1 list-units \ + | { while read -r a b; do echo " $a"; done; }; } +__get_startable_units () { __systemctl $1 list-units --all -t service,timer,socket,mount,automount,path,snapshot,swap \ + | { while read -r a b c d; do [[ $c == "inactive" || $c == "failed " ]] && echo " $a"; done; }; } +__get_failed_units () { __systemctl $1 list-units \ + | { while read -r a b c d; do [[ $c == "failed" ]] && echo " $a"; done; }; } +__get_enabled_units () { __systemctl $1 list-unit-files \ + | { while read -r a b c ; do [[ $b == "enabled" ]] && echo " $a"; done; }; } +__get_disabled_units () { __systemctl $1 list-unit-files \ + | { while read -r a b c ; do [[ $b == "disabled" ]] && echo " $a"; done; }; } +__get_masked_units () { __systemctl $1 list-unit-files \ + | { while read -r a b c ; do [[ $b == "masked" ]] && echo " $a"; done; }; } + +_systemctl () { + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local i verb comps mode + + local -A OPTS=( + [STANDALONE]='--all -a --reverse --after --before --defaults --fail --ignore-dependencies --failed --force -f --full -l --global + --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall + --quiet -q --privileged -P --system --user --version --runtime' + [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t --state --root' + ) + + if __contains_word "--user" ${COMP_WORDS[*]}; then + mode=--user + else + mode=--system + fi + + if __contains_word "$prev" ${OPTS[ARG]}; then + case $prev in + --signal|-s) + comps=$(compgen -A signal) + ;; + --type|-t) + comps='automount device mount path service snapshot socket swap target timer' + ;; + --state) + comps='loaded not-found stub + active inactive + dead elapsed exited listening mounted plugged running waiting' + ;; + --kill-who) + comps='all control main' + ;; + --kill-mode) + comps='control-group process' + ;; + --root) + comps=$(compgen -A directory -- "$cur" ) + compopt -o filenames + ;; + --host|-H) + comps=$(compgen -A hostname) + ;; + --property|-p) + comps=$(__systemd_properties $mode) + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [ALL_UNITS]='is-active is-failed is-enabled status show cat mask preset help list-dependencies' + [ENABLED_UNITS]='disable' + [DISABLED_UNITS]='enable' + [REENABLABLE_UNITS]='reenable' + [FAILED_UNITS]='reset-failed' + [STARTABLE_UNITS]='start' + [STOPPABLE_UNITS]='stop condstop kill try-restart condrestart' + [ISOLATABLE_UNITS]='isolate' + [RELOADABLE_UNITS]='reload condreload reload-or-try-restart force-reload' + [RESTARTABLE_UNITS]='restart reload-or-restart' + [MASKED_UNITS]='unmask' + [JOBS]='cancel' + [SNAPSHOTS]='delete' + [ENVS]='set-environment unset-environment' + [STANDALONE]='daemon-reexec daemon-reload default + emergency exit halt hibernate hybrid-sleep kexec list-jobs + list-sockets list-timers list-units list-unit-files poweroff + reboot rescue show-environment suspend get-default' + [NAME]='snapshot' + [FILE]='link' + [TARGETS]='set-default' + ) + + 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[ALL_UNITS]}; then + comps=$( __get_all_units $mode ) + + elif __contains_word "$verb" ${VERBS[ENABLED_UNITS]}; then + comps=$( __get_enabled_units $mode ) + + elif __contains_word "$verb" ${VERBS[DISABLED_UNITS]}; then + comps=$( __get_disabled_units $mode ) + + elif __contains_word "$verb" ${VERBS[REENABLABLE_UNITS]}; then + comps=$( __get_disabled_units $mode; + __get_enabled_units $mode ) + + elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then + comps=$( __filter_units_by_property $mode CanStart yes \ + $( __get_startable_units $mode)) + + elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then + comps=$( __filter_units_by_property $mode CanStart yes \ + $( __get_all_units $mode \ + | while read -r line; do \ + [[ "$line" =~ \.(device|snapshot|socket|timer)$ ]] || echo " $line"; \ + done )) + + elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then + comps=$( __filter_units_by_property $mode CanStop yes \ + $( __get_active_units $mode ) ) + + elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then + comps=$( __filter_units_by_property $mode CanReload yes \ + $( __get_active_units $mode ) ) + + elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then + comps=$( __filter_units_by_property $mode AllowIsolate yes \ + $( __get_all_units $mode ) ) + + elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then + comps=$( __get_failed_units $mode ) + + elif __contains_word "$verb" ${VERBS[MASKED_UNITS]}; then + comps=$( __get_masked_units $mode ) + + elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then + comps='' + + elif __contains_word "$verb" ${VERBS[JOBS]}; then + comps=$( __systemctl $mode list-jobs | { while read -r a b; do echo " $a"; done; } ) + + elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then + comps=$( __systemctl $mode list-units --type snapshot --full --all \ + | { while read -r a b; do echo " $a"; done; } ) + + elif __contains_word "$verb" ${VERBS[ENVS]}; then + comps=$( __systemctl $mode show-environment \ + | while read -r line; do echo " ${line%%=*}=";done ) + compopt -o nospace + + elif __contains_word "$verb" ${VERBS[FILE]}; then + comps=$( compgen -A file -- "$cur" ) + compopt -o filenames + elif __contains_word "$verb" ${VERBS[TARGETS]}; then + comps=$( __systemctl $mode list-unit-files --type target --full --all \ + | { while read -r a b; do echo " $a"; done; } ) + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _systemctl systemctl diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze new file mode 100644 index 0000000..6afcd96 --- /dev/null +++ b/shell-completion/bash/systemd-analyze @@ -0,0 +1,86 @@ +# systemd-analyze(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# Copyright 2013 Harald Hoyer +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +_systemd_analyze() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='--help --version --system --user --from-pattern --to-pattern --order --require' + + local -A VERBS=( + [STANDALONE]='time blame plot dump' + [CRITICAL_CHAIN]='critical-chain' + [DOT]='dot' + [LOG_LEVEL]='set-log-level' + ) + + _init_completion || return + + 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 && $cur = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + + elif __contains_word "$verb" ${VERBS[STANDALONE]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user' + fi + + elif __contains_word "$verb" ${VERBS[CRITICAL_CHAIN]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user --fuzz' + fi + + elif __contains_word "$verb" ${VERBS[DOT]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user --from-pattern --to-pattern --order --require' + fi + + elif __contains_word "$verb" ${VERBS[LOG_LEVEL]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user' + else + comps='debug info notice warning err crit alert emerg' + fi + + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _systemd_analyze systemd-analyze diff --git a/shell-completion/bash/systemd-coredumpctl b/shell-completion/bash/systemd-coredumpctl new file mode 100644 index 0000000..805e848 --- /dev/null +++ b/shell-completion/bash/systemd-coredumpctl @@ -0,0 +1,85 @@ +# systemd-coredumpctl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__journal_fields=(MESSAGE{,_ID} PRIORITY CODE_{FILE,LINE,FUNC} + ERRNO SYSLOG_{FACILITY,IDENTIFIER,PID} COREDUMP_EXE + _{P,U,G}ID _COMM _EXE _CMDLINE + _AUDIT_{SESSION,LOGINUID} + _SYSTEMD_{CGROUP,SESSION,UNIT,OWNER_UID} + _SELINUX_CONTEXT _SOURCE_REALTIME_TIMESTAMP + _{BOOT,MACHINE}_ID _HOSTNAME _TRANSPORT + _KERNEL_{DEVICE,SUBSYSTEM} + _UDEV_{SYSNAME,DEVNODE,DEVLINK} + __CURSOR __{REALTIME,MONOTONIC}_TIMESTAMP) +_coredumpctl() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --no-pager --no-legend -o --output -F --field' + + local -A VERBS=( + [LIST]='list' + [DUMP]='dump gdb' + ) + + if __contains_word "$prev" '--output -o'; then + comps=$( compgen -A file -- "$cur" ) + compopt -o filenames + elif __contains_word "$prev" '--FIELD -F'; then + comps=$( compgen -W '${__journal_fields[*]}' -- "$cur" ) + elif [[ $cur = -* ]]; then + comps=${OPTS} + elif __contains_word "$prev" ${VERBS[*]} && + ! __contains_word ${COMP_WORDS[COMP_CWORD-2]} '--output -o -F --field'; then + compopt -o nospace + COMPREPLY=( $(compgen -W '${__journal_fields[*]}' -S= -- "$cur") ) + return 0 + elif [[ $cur = *=* ]]; then + mapfile -t field_vals < <(systemd-coredumpctl -F "${prev%=}" 2>/dev/null) + COMPREPLY=( $(compgen -W '${field_vals[*]}' -- "${cur#=}") ) + return 0 + elif [[ $prev = '=' ]]; then + mapfile -t field_vals < <(systemd-coredumpctl -F "${COMP_WORDS[COMP_CWORD-2]}" 2>/dev/null) + comps=${field_vals[*]} + else + for ((i=0; i <= COMP_CWORD; i++)); do + if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; then + verb=${COMP_WORDS[i]} + break + fi + done + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + elif __contains_word "$verb" ${VERBS[LIST]} ${VERBS[DUMP]}; then + comps='' + fi + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _coredumpctl systemd-coredumpctl diff --git a/shell-completion/bash/systemd-delta b/shell-completion/bash/systemd-delta new file mode 100644 index 0000000..cb17328 --- /dev/null +++ b/shell-completion/bash/systemd-delta @@ -0,0 +1,61 @@ +# systemd-delta(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2014 Thomas H.P. Andersen +# +# 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 . + +__contains_word() { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +_systemd-delta() { + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local comps + + local -A OPTS=( + [STANDALONE]='--help -h --no-pager --version' + [ARG]='--diff --type -t' + ) + + _init_completion || return + + + if __contains_word "$prev" ${OPTS[ARG]}; then + case $prev in + --diff) + comps='yes no' + ;; + --type|-t) + comps='masked equivalent redirected overridden unchanged extended default' + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ "$cur" = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _systemd-delta systemd-delta diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run new file mode 100644 index 0000000..ab55274 --- /dev/null +++ b/shell-completion/bash/systemd-run @@ -0,0 +1,63 @@ +# systemd-run(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2013 Zbigniew Jędrzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# 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 . + +__systemctl() { + local mode=$1; shift 1 + systemctl $mode --full --no-legend "$@" +} + +__get_slice_units () { __systemctl $1 list-units --all -t slice \ + | { while read -r a b c d; do echo " $a"; done; }; } + +_systemd_run() { + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --user --scope --unit --description --slice -r --remain-after-exit --send-sighup' + + local mode=--system + local i + for (( i=1; i <= COMP_CWORD; i++ )); do + if [[ ${COMP_WORDS[i]} != -* ]]; then + local root_command=${COMP_WORDS[i]} + _command_offset $i + return + fi + + [[ ${COMP_WORDS[i]} == "--user" ]] && mode=--user + + [[ $i -lt $COMP_CWORD && ${COMP_WORDS[i]} == @(--unit|--description|--slice) ]] && ((i++)) + done + + case "$prev" in + --unit|--description) + # argument required but no completions available + return + ;; + --slice) + local comps=$(__get_slice_units $mode) + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + ;; + esac + + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 +} + +complete -F _systemd_run systemd-run diff --git a/shell-completion/bash/timedatectl b/shell-completion/bash/timedatectl new file mode 100644 index 0000000..1a0acc6 --- /dev/null +++ b/shell-completion/bash/timedatectl @@ -0,0 +1,76 @@ +# timedatectl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +_timedatectl() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --adjust-system-clock --no-pager + --no-ask-password -H --host' + + if __contains_word "$prev" $OPTS; then + case $prev in + --host|-H) + comps='' + ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + fi + + if [[ $cur = -* ]]; then + COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) + return 0 + fi + + local -A VERBS=( + [BOOLEAN]='set-local-rtc set-ntp' + [STANDALONE]='status set-time list-timezones' + [TIMEZONES]='set-timezone' + [TIME]='set-time' + ) + + for ((i=0; i < COMP_CWORD; i++)); do + if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]}; then + verb=${COMP_WORDS[i]} + break + fi + done + + if [[ -z $verb ]]; then + comps=${VERBS[*]} + elif __contains_word "$verb" ${VERBS[BOOLEAN]}; then + comps='true false' + elif __contains_word "$verb" ${VERBS[TIMEZONES]}; then + comps=$(command timedatectl list-timezones) + elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[TIME]}; then + comps='' + fi + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _timedatectl timedatectl diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm new file mode 100644 index 0000000..b828b8d --- /dev/null +++ b/shell-completion/bash/udevadm @@ -0,0 +1,97 @@ +# udevadm(8) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2010 Ran Benita +# +# 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 . + +__contains_word () { + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done +} + +__get_all_sysdevs() { + local -a devs=(/sys/bus/*/devices/*/ /sys/class/*/*/) + printf '%s\n' "${devs[@]%/}" +} + +_udevadm() { + local i verb comps + local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} + local OPTS='-h --help --version --debug' + + local verbs=(info trigger settle control monitor hwdb test-builtin test) + + 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 + COMPREPLY=( $(compgen -W '${OPTS[*]} ${verbs[*]}' -- "$cur") ) + return 0 + fi + + case $verb in + 'info') + if [[ $cur = -* ]]; then + comps='--help --query= --path= --name= --root --attribute-walk --export-db --cleanup-db' + else + comps=$( __get_all_sysdevs ) + fi + ;; + 'trigger') + comps='--help --verbose --dry-run --type= --action= --subsystem-match= + --subsystem-nomatch= --attr-match= --attr-nomatch= --property-match= + --tag-match= --sysname-match= --parent-match=' + ;; + 'settle') + comps='--help --timeout= --seq-start= --seq-end= --exit-if-exists= --quiet' + ;; + 'control') + comps='--help --exit --log-priority= --stop-exec-queue --start-exec-queue + --reload --property= --children-max= --timeout=' + ;; + 'monitor') + comps='--help --kernel --udev --property --subsystem-match= --tag-match=' + ;; + 'hwdb') + comps='--help --update --test=' + ;; + 'test') + if [[ $cur = -* ]]; then + comps='--help --action=' + else + comps=$( __get_all_sysdevs ) + fi + ;; + 'test-builtin') + comps='blkid btrfs hwdb input_id keyboard kmod net_id net_setup_link path_id usb_id uaccess' + ;; + *) + comps=${VERBS[*]} + ;; + esac + + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +} + +complete -F _udevadm udevadm diff --git a/shell-completion/zsh/_bootctl b/shell-completion/zsh/_bootctl new file mode 100644 index 0000000..7d2453c --- /dev/null +++ b/shell-completion/zsh/_bootctl @@ -0,0 +1,25 @@ +#compdef bootctl + +(( $+functions[_bootctl_command] )) || _bootctl_command() +{ + local -a _bootctl_cmds + _bootctl_cmds=( + "status:Show current firmware and boot settings" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'bootctl command' _bootctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_bootctl_cmds[(r)$words[1]:*]%%:*}}" + if (( $+functions[_bootctl_$cmd] )); then + _bootctl_$cmd + else + _message "no more options" + fi + fi +} + +_arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + '*::bootctl command:_bootctl_command' diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl new file mode 100644 index 0000000..7c01564 --- /dev/null +++ b/shell-completion/zsh/_busctl @@ -0,0 +1,54 @@ +#compdef busctl + +# hostnamectl(1) completion -*- shell-script -*- +# +# This file is part of systemd. +# +# Copyright 2013 Zbigniew Jędrzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# 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 . + +(( $+functions[_busctl_command] )) || _busctl_command() +{ + local -a _busctl_cmds + _busctl_cmds=( + "list:List bus names" + "monitor:Show bus traffic" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'busctl command' _busctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_busctl_cmds[(r)$words[1]:*]%%:*}}" + if (( $+functions[_busctl_$cmd] )); then + _busctl_$cmd + else + _message "no more options" + fi + fi +} + +_arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--system[Connect to system manager]' \ + '--user[Connect to user service manager]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ + '--address=[Connect to the bus specified by address]:address' \ + '--no-unique[Only show well-known names]' \ + '--no-machine[Do not show machine IDs]' \ + '--match=[Only show matching messages]:match' \ + '*::busctl command:_busctl_command' diff --git a/shell-completion/zsh/_hostnamectl b/shell-completion/zsh/_hostnamectl new file mode 100644 index 0000000..45b9597 --- /dev/null +++ b/shell-completion/zsh/_hostnamectl @@ -0,0 +1,32 @@ +#compdef hostnamectl + +_hostnamectl_command() { + local -a _hostnamectl_cmds + _hostnamectl_cmds=( + "status:Show current hostname settings" + "set-hostname:Set system hostname" + "set-icon-name:Set icon name for host" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'hostnamectl commands' _hostnamectl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_hostnamectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + [[ $cmd == status ]] && msg="no options" || msg="options for $cmd" + _message "$msg" + else + _message "unknown hostnamectl command: $words[1]" + fi + fi +} + +_arguments -s \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--transient[Only set transient hostname]' \ + '--static[Only set static hostname]' \ + '--pretty[Only set pretty hostname]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + '*::hostnamectl commands:_hostnamectl_command' diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl new file mode 100644 index 0000000..0d16a26 --- /dev/null +++ b/shell-completion/zsh/_journalctl @@ -0,0 +1,93 @@ +#compdef journalctl + +_list_fields() { + local -a journal_fields + journal_fields=(MESSAGE{,_ID} PRIORITY CODE_{FILE,LINE,FUNC} + ERRNO SYSLOG_{FACILITY,IDENTIFIER,PID} + _{P,U,G}ID _COMM _EXE _CMDLINE + _AUDIT_{SESSION,LOGINUID} + _SYSTEMD_{CGROUP,SESSION,UNIT,OWNER_UID} + _SYSTEMD_USER_UNIT USER_UNIT + _SELINUX_CONTEXT _SOURCE_REALTIME_TIMESTAMP + _{BOOT,MACHINE}_ID _HOSTNAME _TRANSPORT + _KERNEL_{DEVICE,SUBSYSTEM} + _UDEV_{SYSNAME,DEVNODE,DEVLINK} + __CURSOR __{REALTIME,MONOTONIC}_TIMESTAMP) + case $_jrnl_none in + yes) _values -s '=' 'possible fields' \ + "${journal_fields[@]}:value:_journal_fields ${words[CURRENT]%%=*}" ;; + *) _describe 'possible fields' journal_fields ;; + esac +} + +_journal_none() { + local -a _commands _files _jrnl_none + # Setting use-cache will slow this down considerably + _commands=( ${"$(_call_program commands "$service" -F _EXE 2>/dev/null)"} ) + _jrnl_none='yes' + _alternative : \ + 'files:/dev files:_files -W /dev -P /dev/' \ + "commands:commands:($_commands[@])" \ + 'fields:fields:_list_fields' +} + +_journal_fields() { + local -a _fields cmd + cmd=("journalctl" "-F ${@[-1]}" "2>/dev/null" ) + _fields=( ${(f)"$(_call_program fields $cmd[@])"} ) + typeset -U _fields + _describe 'possible values' _fields +} + +_journal_boots() { + local -a _bootid _previousboots + _bootid=( ${(fao)"$(_call_program bootid "$service -F _BOOT_ID")"} ) + _previousboots=( -{1..${#_bootid}} ) + _alternative : \ + "offsets:boot offsets:(${_previousboots[1,-2]})" \ + "bootid:boot ids:(${_bootid[@]})" +} + +_arguments -s \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--no-pager[Do not pipe output into a pager]' \ + {-l,--full}'[Show long fields in full]' \ + {-a,--all}'[Show all fields, including long and unprintable]' \ + {-f,--follow}'[Follow journal]' \ + {-e,--pager-end}'[Jump to the end of the journal in the pager]' \ + {-n+,--lines=}'[Number of journal entries to show]:integer' \ + '--no-tail[Show all lines, even in follow mode]' \ + {-r,--reverse}'[Reverse output]' \ + {-o+,--output=}'[Change journal output mode]:output modes:_sd_outputmodes' \ + {-x,--catalog}'[Show explanatory texts with each log line]' \ + {-q,--quiet}"[Don't show privilege warning]" \ + {-m,--merge}'[Show entries from all available journals]' \ + {-b+,--boot=}'[Show data only from the specified boot or offset]:boot id or offset:_journal_boots' \ + '--list-boots[List boots ordered by time]' \ + {-k,--dmesg}'[Show only kernel messages from the current boot]' \ + {-u+,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \ + '--user-unit=[Show data only from the specified user session unit]:units:_journal_fields USER_UNIT' \ + {-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journal_fields PRIORITY' \ + {-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journal_fields __CURSORS' \ + '--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journal_fields __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' \ + {-F,--field=}'[List all values a certain field takes]:Fields:_list_fields' \ + '--system[Show system and kernel messages]' \ + '--user[Show messages from user services]' \ + {-D+,--directory=}'[Show journal files from directory]:directories:_directories' \ + '--file=[Operate on specified journal files]:file:_files' \ + '--root=[Operate on catalog hierarchy under specified directory]:directories:_directories' \ + '--new-id128[Generate a new 128 Bit ID]' \ + '--header[Show journal header information]' \ + '--disk-usage[Show total disk usage]' \ + '--list-catalog[List messages in catalog]' \ + '--dump-catalog[Dump messages in catalog]' \ + '--update-catalog[Update binary catalog database]' \ + '--setup-keys[Generate a new FSS key pair]' \ + '--force[Force recreation of the FSS keys]' \ + '--interval=[Time interval for changing the FSS sealing key]:time interval' \ + '--verify[Verify journal file consistency]' \ + '--verify-key=[Specify FSS verification key]:FSS key' \ + '*::default: _journal_none' diff --git a/shell-completion/zsh/_kernel-install b/shell-completion/zsh/_kernel-install new file mode 100644 index 0000000..4fdd3a4 --- /dev/null +++ b/shell-completion/zsh/_kernel-install @@ -0,0 +1,26 @@ +#compdef kernel-install + +_images(){ + if [[ "$words[2]" == "remove" ]]; then + _message 'No more options' + else + _path_files -W /boot/ -P /boot/ -g "vmlinuz-*" + fi +} + +_kernels(){ + read _MACHINE_ID < /etc/machine-id + _kernel=( /lib/modules/[0-9]* ) + if [[ "$cmd" == "remove" && -n "$_MACHINE_ID" ]]; then + _kernel=( "/boot/$_MACHINE_ID"/[0-9]* ) + fi + _kernel=( ${_kernel##*/} ) + _describe "installed kernels" _kernel +} + +_arguments \ + '1::add or remove:(add remove)' \ + '2::kernel versions:_kernels' \ + '3::kernel images:_images' + +#vim: set ft=zsh sw=4 ts=4 et diff --git a/shell-completion/zsh/_localectl b/shell-completion/zsh/_localectl new file mode 100644 index 0000000..c04f4f3 --- /dev/null +++ b/shell-completion/zsh/_localectl @@ -0,0 +1,88 @@ +#compdef localectl + +_localectl_set-locale() { + local -a _locales locale_fields + locale_fields=(LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME \ + LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER \ + LC_NAME LC_ADDRESS LC_TELEPHONE \ + LC_MEASUREMENT LC_IDENTIFICATION) + # LC_ALL is omitted on purpose + + local expl suf + _locales=( ${(f)"$(_call_program locales "$service" list-locales)"} ) + compset -P1 '*=' + if [[ -prefix 1 *\= ]]; then + local conf=${PREFIX%%\=*} + _wanted locales expl "locales configs" \ + _combination localeconfs confs=$conf locales "$@" - + else + compadd -S '=' $locale_fields + fi +} + +_localectl_set-keymap() { + local -a _keymaps + _keymaps=( ${(f)"$(_call_program locales "$service" list-keymaps)"} ) + if (( CURRENT <= 3 )); then + _describe keymaps _keymaps + else + _message "no more options" + fi +} + +_localectl_set-x11-keymap() { + if (( $+commands[pkg-config] )); then + local -a _file _layout _model _variant _options + local _xorg_lst + _xorg_lst=${"$($commands[pkg-config] xkeyboard-config --variable=xkb_base)"} + _file=( ${(ps:\n\!:)"$(<$_xorg_lst/rules/xorg.lst)"} ) + _layout=( ${${${(M)${(f)_file[1]}:# *}# }%% *} ) + _model=( ${${${(M)${(f)_file[2]}:# *}# }%% *} ) + _variant=( ${${${(M)${(f)_file[3]}:# *}# }%% *} ) + _options=( ${${${(M)${(f)_file[4]}:# *}# }%% *} ) + #_layout=( ${(f)"$( echo $_file[1] | awk '/^ / {print $1}' )"} ) + #_model=( ${(f)"$(echo $_file[2] | awk '/^ / {print $1}')"} ) + #_variant=( ${(f)"$(echo $_file[3] | awk '/^ / {print $1}')"} ) + #_options=( ${(f)"$(echo ${_file[4]//:/\\:} | awk '/^ / {print $1}')"} ) + + case $CURRENT in + 2) _describe layouts _layout ;; + 3) _describe models _model;; + 4) _describe variants _variant;; + 5) _describe options _options;; + *) _message "no more options" + esac + fi +} + +_localectl_command() { + local -a _localectl_cmds + _localectl_cmds=( + 'status:Show current locale settings' + 'set-locale:Set system locale' + 'list-locales:Show known locales' + 'set-keymap:Set virtual console keyboard mapping' + 'list-keymaps:Show known virtual console keyboard mappings' + 'set-x11-keymap:Set X11 keyboard mapping' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'localectl command' _localectl_cmds + else + local curcontext="$curcontext" + cmd="${${_localectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $+functions[_localectl_$cmd] )); then + _localectl_$cmd + else + _message "no more options" + fi + fi +} + +_arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + "--no-convert[Don't convert keyboard mappings]" \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + '*::localectl commands:_localectl_command' diff --git a/shell-completion/zsh/_loginctl b/shell-completion/zsh/_loginctl new file mode 100644 index 0000000..740629d --- /dev/null +++ b/shell-completion/zsh/_loginctl @@ -0,0 +1,106 @@ +#compdef loginctl + +_loginctl_all_sessions(){_sys_all_sessions=($(loginctl --no-legend list-sessions | { while read a b; do echo " $a"; done; }) )} +_loginctl_all_users() {_sys_all_users=( $(loginctl --no-legend list-users | { while read a b; do echo " $a"; done; }) )} +_loginctl_all_seats() {_sys_all_seats=( $(loginctl --no-legend list-seats | { while read a b; do echo " $a"; done; }) )} + +# Completion functions for SESSIONS +for fun in session-status show-session activate lock-session unlock-session terminate-session kill-session ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { + _loginctl_all_sessions + compadd "$@" -a - _sys_all_sessions + } +done + +# Completion functions for USERS +for fun in user-status show-user enable-linger disable-linger terminate-user kill-user ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { + _loginctl_all_users + compadd "$@" -a - _sys_all_users + } +done + +# Completion functions for SEATS +(( $+functions[_loginctl_seats] )) || _loginctl_seats() +{ + _loginctl_all_seats + compadd "$@" -a - _sys_all_seats +} +for fun in seat-status show-seat terminate-seat ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { _loginctl_seats } +done + +# Completion functions for ATTACH +(( $+functions[_loginctl_attach] )) || _loginctl_attach() +{ + _loginctl_all_seats + + _arguments -w -C -S -s \ + ':seat:_loginctl_seats' \ + '*:device:_files' +} + +# no loginctl completion for: +# [STANDALONE]='list-sessions list-users list-seats flush-devices' + +(( $+functions[_loginctl_command] )) || _loginctl_command() +{ + local -a _loginctl_cmds + _loginctl_cmds=( + "list-sessions:List sessions" + "session-status:Show session status" + "show-session:Show properties of one or more sessions" + "activate:Activate a session" + "lock-session:Screen lock one or more sessions" + "unlock-session:Screen unlock one or more sessions" + "terminate-session:Terminate one or more sessions" + "kill-session:Send signal to processes of a session" + "list-users:List users" + "user-status:Show user status" + "show-user:Show properties of one or more users" + "enable-linger:Enable linger state of one or more users" + "disable-linger:Disable linger state of one or more users" + "terminate-user:Terminate all sessions of one or more users" + "kill-user:Send signal to processes of a user" + "list-seats:List seats" + "seat-status:Show seat status" + "show-seat:Show properties of one or more seats" + "attach:Attach one or more devices to a seat" + "flush-devices:Flush all device associations" + "terminate-seat:Terminate all sessions on one or more seats" + ) + + if (( CURRENT == 1 )); then + _describe -t commands 'loginctl command' _loginctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + + cmd="${${_loginctl_cmds[(r)$words[1]:*]%%:*}}" + + if (( $#cmd )); then + curcontext="${curcontext%:*:*}:loginctl-${cmd}:" + + _call_function ret _loginctl_$cmd || _message 'no more arguments' + else + _message "unknown loginctl command: $words[1]" + fi + return ret + fi +} + + +_arguments -s \ + {-h,--help}'[Show help]' \ + '--version[Show package version]' \ + \*{-p+,--property=}'[Show only properties by this name]:unit property' \ + {-a,--all}'[Show all properties, including empty ones]' \ + '--kill-who=[Who to send signal to]:killwho:(main control all)' \ + {-s+,--signal=}'[Which signal to send]:signal:_signals' \ + '--no-ask-password[Do not ask for system passwords]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + '--no-pager[Do not pipe output into a pager]' \ + '*::loginctl command:_loginctl_command' diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl new file mode 100644 index 0000000..15c149f --- /dev/null +++ b/shell-completion/zsh/_machinectl @@ -0,0 +1,42 @@ +#compdef machinectl + +(( $+functions[_machinectl_command] )) || _machinectl_command() +{ + local -a _machinectl_cmds + _machinectl_cmds=( + "list:List currently running VMs/containers" + "status:Show VM/container status" + "show:Show properties of one or more VMs/containers" + "terminate:Terminate one or more VMs/containers" + "kill:Send signal to process or a VM/container" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'machinectl command' _machinectl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_machinectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + case $cmd in + list) msg="no options" ;; + *) + _sd_machines + esac + else + _message "no more options" + fi + fi +} + +_arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + \*{-p+,--property=}'[Limit output to specified property.]:property:(Name Id Timestamp TimestampMonotonic Service Scope Leader Class State RootDirectory)' \ + {-a,--all}'[Show all proerties]' \ + (-l,--full)'[Do not ellipsize cgroup members]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not ask for system passwords]' \ + '--kill-who=[Who to send signal to]:killwho:(leader all)' \ + {-s+,--signal=}'[Which signal to send]:signal:_signals' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + '*::machinectl command:_machinectl_command' diff --git a/shell-completion/zsh/_sd_hosts_or_user_at_host b/shell-completion/zsh/_sd_hosts_or_user_at_host new file mode 100644 index 0000000..282f732 --- /dev/null +++ b/shell-completion/zsh/_sd_hosts_or_user_at_host @@ -0,0 +1,5 @@ +#autoload + +_alternative \ + 'users-hosts:: _user_at_host' \ + 'hosts:: _hosts' diff --git a/shell-completion/zsh/_sd_machines b/shell-completion/zsh/_sd_machines new file mode 100644 index 0000000..1d64d13 --- /dev/null +++ b/shell-completion/zsh/_sd_machines @@ -0,0 +1,13 @@ +#autoload +__get_machines () { + machinectl --full --no-pager list | {while read -r a b; do echo $a; done;}; +} + +local -a _machines +_machines=("${(fo)$(__get_machines)}") +typeset -U _machines +if [[ -n "$_machines" ]]; then + _describe 'machines' _machines +else + _message 'no machines' +fi diff --git a/shell-completion/zsh/_sd_outputmodes b/shell-completion/zsh/_sd_outputmodes new file mode 100644 index 0000000..dae8a5c --- /dev/null +++ b/shell-completion/zsh/_sd_outputmodes @@ -0,0 +1,5 @@ +#autoload + +local -a _output_opts +_output_opts=(short short-monotonic verbose export json json-pretty json-see cat) +_describe -t output 'output mode' _output_opts || compadd "$@" diff --git a/shell-completion/zsh/_systemctl b/shell-completion/zsh/_systemctl new file mode 100644 index 0000000..b6cf664 --- /dev/null +++ b/shell-completion/zsh/_systemctl @@ -0,0 +1,341 @@ +#compdef systemctl + +(( $+functions[_systemctl_command] )) || _systemctl_command() +{ + local -a _systemctl_cmds + _systemctl_cmds=( + "list-sockets:List sockets" + "list-timers:List timers" + "list-units:List units" + "start:Start (activate) one or more units" + "stop:Stop (deactivate) one or more units" + "reload:Reload one or more units" + "restart:Start or restart one or more units" + "condrestart:Restart one or more units if active" + "try-restart:Restart one or more units if active" + "reload-or-restart:Reload one or more units if possible, otherwise start or restart" + "force-reload:Reload one or more units if possible, otherwise restart if active" + "hibernate:Hibernate the system" + "hybrid-sleep:Hibernate and suspend the system" + "reload-or-try-restart:Reload one or more units if possible, otherwise restart if active" + "isolate:Start one unit and stop all others" + "kill:Send signal to processes of a unit" + "is-active:Check whether units are active" + "is-failed:Check whether units are failed" + "status:Show runtime status of one or more units" + "show:Show properties of one or more units/jobs or the manager" + "cat:Show the source unit files and drop-ins" + "reset-failed:Reset failed state for all, one, or more units" + "list-unit-files:List installed unit files" + "enable:Enable one or more unit files" + "disable:Disable one or more unit files" + "reenable:Reenable one or more unit files" + "preset:Enable/disable one or more unit files based on preset configuration" + "help:Show documentation for specified units" + "list-dependencies:Show unit dependency tree" + "mask:Mask one or more units" + "unmask:Unmask one or more units" + "link:Link one or more units files into the search path" + "is-enabled:Check whether unit files are enabled" + "list-jobs:List jobs" + "cancel:Cancel all, one, or more jobs" + "snapshot:Create a snapshot" + "delete:Remove one or more snapshots" + "show-environment:Dump environment" + "set-environment:Set one or more environment variables" + "unset-environment:Unset one or more environment variables" + "daemon-reload:Reload systemd manager configuration" + "daemon-reexec:Reexecute systemd manager" + "default:Enter system default mode" + "rescue:Enter system rescue mode" + "emergency:Enter system emergency mode" + "halt:Shut down and halt the system" + "suspend:Suspend the system" + "poweroff:Shut down and power-off the system" + "reboot:Shut down and reboot the system" + "kexec:Shut down and reboot the system with kexec" + "exit:Ask for user instance termination" + ) + + if (( CURRENT == 1 )); then + _describe -t commands 'systemctl command' _systemctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + + cmd="${${_systemctl_cmds[(r)$words[1]:*]%%:*}}" + # Deal with any aliases + case $cmd in + condrestart) cmd="try-restart";; + force-reload) cmd="reload-or-try-restart";; + esac + + if (( $#cmd )); then + curcontext="${curcontext%:*:*}:systemctl-${cmd}:" + + local update_policy + zstyle -s ":completion:${curcontext}:" cache-policy update_policy + if [[ -z "$update_policy" ]]; then + zstyle ":completion:${curcontext}:" cache-policy _systemctl_caching_policy + fi + + _call_function ret _systemctl_$cmd || _message 'no more arguments' + else + _message "unknown systemctl command: $words[1]" + fi + return ret + fi +} + +__systemctl() +{ + local -a _modes + _modes=("--user" "--system") + systemctl ${words:*_modes} --full --no-legend --no-pager "$@" +} + + +# Fills the unit list +_systemctl_all_units() +{ + if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS ) && + ! _retrieve_cache SYS_ALL_UNITS; + then + _sys_all_units=( $(__systemctl list-units --all | { while read a b; do echo " $a"; done; }) ) + _store_cache SYS_ALL_UNITS _sys_all_units + fi +} + +# Fills the unit list including all file units +_systemctl_really_all_units() +{ + local -a all_unit_files; + local -a really_all_units; + if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS ) && + ! _retrieve_cache SYS_REALLY_ALL_UNITS; + then + all_unit_files=( $(__systemctl list-unit-files | { while read a b; do echo " $a"; done; }) ) + _systemctl_all_units + really_all_units=($_sys_all_units $all_unit_files) + _sys_really_all_units=(${(u)really_all_units}) + _store_cache SYS_REALLY_ALL_UNITS _sys_really_all_units + fi +} + +_filter_units_by_property() { + local property=$1 value=$2 ; shift ; shift + local -a units ; units=($*) + local prop unit + for ((i=1; $i <= ${#units[*]}; i++)); do + # FIXME: "Failed to issue method call: Unknown unit" errors are ignored for + # now (related to DBUS_ERROR_UNKNOWN_OBJECT). in the future, we need to + # revert to calling 'systemctl show' once for all units, which is way + # faster + unit=${units[i]} + prop=${(f)"$(_call_program units "$service show --no-pager --property="$property" ${unit} 2>/dev/null")"} + if [[ "${prop}" = "$property=$value" ]]; then + echo " ${unit}" + fi + done +} + +_systemctl_active_units() {_sys_active_units=( $(__systemctl list-units | { while read a b; do echo " $a"; done; }) )} +_systemctl_inactive_units(){_sys_inactive_units=($(__systemctl list-units --all | { while read a b c d; do [[ $c == "inactive" || $c == "failed" ]] && echo " $a"; done; }) )} +_systemctl_failed_units() {_sys_failed_units=( $(__systemctl list-units --failed | { while read a b; do echo " $a"; done; }) )} +_systemctl_enabled_units() {_sys_enabled_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "enabled" ]] && echo " $a"; done; }) )} +_systemctl_disabled_units(){_sys_disabled_units=($(__systemctl list-unit-files | { while read a b; do [[ $b == "disabled" ]] && echo " $a"; done; }) )} +_systemctl_masked_units() {_sys_masked_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "masked" ]] && echo " $a"; done; }) )} + +# Completion functions for ALL_UNITS +for fun in is-active is-failed is-enabled status show cat mask preset help list-dependencies ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_really_all_units + compadd "$@" -a - _sys_really_all_units + } +done + +# Completion functions for ENABLED_UNITS +for fun in disable reenable ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_enabled_units + _systemctl_disabled_units + compadd "$@" -a - _sys_enabled_units _sys_disabled_units + } +done + +# Completion functions for DISABLED_UNITS +(( $+functions[_systemctl_enable] )) || _systemctl_enable() +{ + _systemctl_disabled_units + compadd "$@" -a - _sys_disabled_units +} + +# Completion functions for FAILED_UNITS +(( $+functions[_systemctl_reset-failed] )) || _systemctl_reset-failed() +{ + _systemctl_failed_units + compadd "$@" -a - _sys_failed_units || _message "no failed unit found" +} + +# Completion functions for STARTABLE_UNITS +(( $+functions[_systemctl_start] )) || _systemctl_start() +{ + _systemctl_inactive_units + compadd "$@" -a - _sys_inactive_units +} + +# Completion functions for STOPPABLE_UNITS +for fun in stop kill try-restart condrestart ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_active_units + compadd "$@" - $( _filter_units_by_property CanStop yes \ + ${_sys_active_units[*]} ) + } +done + +# Completion functions for ISOLATABLE_UNITS +(( $+functions[_systemctl_isolate] )) || _systemctl_isolate() +{ + _systemctl_all_units + compadd "$@" - $( _filter_units_by_property AllowIsolate yes \ + ${_sys_all_units[*]} ) +} + +# Completion functions for RELOADABLE_UNITS +for fun in reload reload-or-try-restart force-reload ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_active_units + compadd "$@" - $( _filter_units_by_property CanReload yes \ + ${_sys_active_units[*]} ) + } +done + +# Completion functions for RESTARTABLE_UNITS +for fun in restart reload-or-restart ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_all_units + compadd "$@" - $( _filter_units_by_property CanStart yes \ + ${_sys_all_units[*]} | while read line; do \ + [[ "$line" =~ \.device$ ]] || echo " $line"; \ + done ) + } +done + +# Completion functions for MASKED_UNITS +(( $+functions[_systemctl_unmask] )) || _systemctl_unmask() +{ + _systemctl_masked_units + compadd "$@" -a - _sys_masked_units || _message "no masked unit found" +} + +# Completion functions for JOBS +(( $+functions[_systemctl_cancel] )) || _systemctl_cancel() +{ + compadd "$@" - $(__systemctl list-jobs \ + | cut -d' ' -f1 2>/dev/null ) || _message "no job found" +} + +# Completion functions for SNAPSHOTS +(( $+functions[_systemctl_delete] )) || _systemctl_delete() +{ + compadd "$@" - $(__systemctl list-units --type snapshot --all \ + | cut -d' ' -f1 2>/dev/null ) || _message "no snapshot found" +} + +# Completion functions for ENVS +for fun in set-environment unset-environment ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + local fun=$0 ; fun=${fun##_systemctl_} + local suf + if [[ "${fun}" = "set-environment" ]]; then + suf='-S=' + fi + + compadd "$@" ${suf} - $(systemctl show-environment \ + | while read line; do echo " ${line%%\=}";done ) + } +done + +(( $+functions[_systemctl_link] )) || _systemctl_link() { _files } + +# no systemctl completion for: +# [STANDALONE]='daemon-reexec daemon-reload default +# emergency exit halt kexec list-jobs list-units +# list-unit-files poweroff reboot rescue show-environment' +# [NAME]='snapshot' + +_systemctl_caching_policy() +{ + local _sysunits + local -a oldcache + + # rebuild if cache is more than a day old + oldcache=( "$1"(mh+1) ) + (( $#oldcache )) && return 0 + + _sysunits=($(__systemctl --all | cut -d' ' -f1)) + + if (( $#_sysunits )); then + for unit in $_sysunits; do + [[ "$unit" -nt "$1" ]] && return 0 + done + fi + + return 1 +} + +_unit_states() { + local -a _states + _states=(loaded failed active inactive not-found listening running waiting plugged mounted exited dead masked) + _values -s , "${_states[@]}" +} + +_unit_types() { + local -a _types + _types=(automount device mount path service snapshot socket swap target timer) + _values -s , "${_types[@]}" +} + +_arguments -s \ + {-h,--help}'[Show help]' \ + '--version[Show package version]' \ + {-t+,--type=}'[List only units of a particular type]:unit type:_unit_types' \ + '--state=[Display units in the specifyied state]:unit state:_unit_states' \ + \*{-p+,--property=}'[Show only properties by specific name]:unit property' \ + {-a,--all}'[Show all units/properties, including dead/empty ones]' \ + '--reverse[Show reverse dependencies]' \ + '--after[Show units ordered after]' \ + '--before[Show units ordered before]' \ + '--failed[Show only failed units]' \ + {-l,--full}"[Don't ellipsize unit names on output]" \ + '--fail[When queueing a new job, fail if conflicting jobs are pending]' \ + '--show-types[When showing sockets, show socket type]' \ + '--irreversible[Mark transactions as irreversible]' \ + '--ignore-dependencies[When queueing a new job, ignore all its dependencies]' \ + {-i,--ignore-inhibitors}'[When executing a job, ignore jobs dependencies]' \ + {-q,--quiet}'[Suppress output]' \ + '--no-block[Do not wait until operation finished]' \ + '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--system[Connect to system manager]' \ + '--user[Connect to user service manager]' \ + "--no-wall[Don't send wall message before halt/power-off/reboot]" \ + '--global[Enable/disable unit files globally]' \ + "--no-reload[When enabling/disabling unit files, don't reload daemon configuration]" \ + '--no-ask-password[Do not ask for system passwords]' \ + '--kill-who=[Who to send signal to]:killwho:(main control all)' \ + {-s+,--signal=}'[Which signal to send]:signal:_signals' \ + {-f,--force}'[When enabling unit files, override existing symlinks. When shutting down, execute action immediately]' \ + '--root=[Enable unit files in the specified root directory]:directory:_directories' \ + '--runtime[Enable unit files only temporarily until next reboot]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + {-n+,--lines=}'[Journal entries to show]:number of entries' \ + {-o+,--output=}'[Change journal output mode]:modes:_sd_outputmodes' \ + '--plain[When used with list-dependencies, print output as a list]' \ + '*::systemctl command:_systemctl_command' diff --git a/shell-completion/zsh/_systemd b/shell-completion/zsh/_systemd new file mode 100644 index 0000000..06f03bd --- /dev/null +++ b/shell-completion/zsh/_systemd @@ -0,0 +1,83 @@ +#compdef systemd-cat systemd-ask-password systemd-cgls systemd-cgtop systemd-detect-virt systemd-machine-id-setup systemd-notify systemd-tty-ask-password-agent + +local curcontext="$curcontext" state lstate line +case "$service" in + systemd-ask-password) + _arguments \ + {-h,--help}'[Show this help]' \ + '--icon=[Icon name]' \ + '--timeout=[Timeout in sec]' \ + '--no-tty[Ask question via agent even on TTY]' \ + '--accept-cached[Accept cached passwords]' \ + '--multiple[List multiple passwords if available]' + ;; + systemd-cat) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version.]' \ + {-t+,--identifier=}'[Set syslog identifier.]' \ + {-p+,--priority=}'[Set priority value.]:value:({0..7})' \ + '--level-prefix=[Control whether level prefix shall be parsed.]:boolean:(1 0)' \ + ':Message' + ;; + systemd-cgls) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--no-pager[Do not pipe output into a pager]' \ + {-a,--all}'[Show all groups, including empty]' \ + '-k[Include kernel threads in output]' \ + ':cgroups:(cpuset cpu cpuacct memory devices freezer net_cls blkio)' + ;; + systemd-cgtop) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Print version and exit]' \ + '(-c -m -i -t)-p[Order by path]' \ + '(-c -p -m -i)-t[Order by number of tasks]' \ + '(-m -p -i -t)-c[Order by CPU load]' \ + '(-c -p -i -t)-m[Order by memory load]' \ + '(-c -m -p -t)-i[Order by IO load]' \ + {-d+,--delay=}'[Specify delay]' \ + {-n+,--iterations=}'[Run for N iterations before exiting]' \ + {-b,--batch}'[Run in batch mode, accepting no input]' \ + '--depth=[Maximum traversal depth]' + ;; + systemd-detect-virt) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + {-c,--container}'[Only detect whether we are run in a container]' \ + {-v,--vm}'[Only detect whether we are run in a VM]' \ + {-q,--quiet}"[Don't output anything, just set return value]" + ;; + systemd-machine-id-setup) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' + ;; + systemd-notify) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--ready[Inform the init system about service start-up completion.]' \ + '--pid=[Inform the init system about the main PID of the daemon]' \ + '--status=[Send a free-form status string for the daemon to the init systemd]' \ + '--booted[Returns 0 if the system was booted up with systemd]' \ + '--readahead=[Controls disk read-ahead operations]:arguments:(cancel done noreply)' + ;; + systemd-tty-ask-password-agent) + _arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + '--list[Lists all currently pending system password requests.]' \ + '--query[Process all currently pending system password requests by querying the user on the calling TTY.]' \ + '--watch[Continuously process password requests.]' \ + '--wall[Forward password requests to wall(1).]' \ + '--plymouth[Ask question with plymouth(8).]' \ + '--console[Ask question on /dev/console.]' + ;; + *) _message 'eh?' ;; +esac + +#vim: set ft=zsh sw=4 ts=4 et diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze new file mode 100644 index 0000000..2eda5fe --- /dev/null +++ b/shell-completion/zsh/_systemd-analyze @@ -0,0 +1,44 @@ +#compdef systemd-analyze + +_systemd_analyze_set-log-level() { + local -a _levels + _levels=(debug info notice warning err crit alert emerg) + _describe -t level 'logging level' _levels || compadd "$@" +} + +_systemd_analyze_command(){ + local -a _systemd_analyze_cmds + # Descriptions taken from systemd-analyze --help. + _systemd_analyze_cmds=( + 'time:Print time spent in the kernel before reaching userspace' + 'blame:Print list of running units ordered by time to init' + 'critical-chain:Print a tree of the time critical chain of units' + 'plot:Output SVG graphic showing service initialization' + 'dot:Dump dependency graph (in dot(1) format)' + 'dump:Dump server status' + 'set-log-level:Set systemd log threshold' + ) + + if (( CURRENT == 1 )); then + _describe "options" _systemd_analyze_cmds + else + local curcontext="$curcontext" + cmd="${${_systemd_analyze_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + if (( $+functions[_systemd_analyze_$cmd] )) && (( CURRENT == 2 )); then + _systemd_analyze_$cmd + else + _message "no more options" + fi + else + _message "unknown systemd-analyze command: $words[1]" + fi + fi +} + +_arguments \ + {-h,--help}'[Show help text.]' \ + '--user[Shows performance data of user sessions instead of the system manager.]' \ + '--order[When generating graph for dot, show only order]' \ + '--require[When generating graph for dot, show only requirement]' \ + '*::systemd-analyze commands:_systemd_analyze_command' diff --git a/shell-completion/zsh/_systemd-coredumpctl b/shell-completion/zsh/_systemd-coredumpctl new file mode 100644 index 0000000..94b1e92 --- /dev/null +++ b/shell-completion/zsh/_systemd-coredumpctl @@ -0,0 +1,36 @@ +#compdef systemd-coredumpctl + +_systemd-coredumpctl_command(){ + local -a _systemd_coredumpctl_cmds + _systemd_coredumpctl_cmds=( + 'list:List available coredumps' + 'dump:Print coredump to stdout' + 'gdb:Start gdb on a coredump' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'systemd-coredumpctl command' _systemd_coredumpctl_cmds + else + local curcontext="$curcontext" + local -a _dumps + cmd="${${_systemd_coredumpctl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + # user can set zstyle ':completion:*:*:systemd-coredumpctl:*' sort no for coredumps to be ordered by date, otherwise they get ordered by pid + _dumps=( "${(foa)$(systemd-coredumpctl list | awk 'BEGIN{OFS=":"} /^\s/ {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" ) + if [[ -n "$_dumps" ]]; then + _describe -t pids 'coredumps' _dumps + else + _message "no coredumps" + fi + else + _message "no more options" + fi + fi +} + +_arguments \ + {-o+,--output=}'[Write output to FILE]:output file:_files' \ + {-F+,--field=}'[Show field in list output]:field' \ + '--no-pager[Do not pipe output into a pager]' \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '*::systemd-coredumpctl commands:_systemd-coredumpctl_command' diff --git a/shell-completion/zsh/_systemd-delta b/shell-completion/zsh/_systemd-delta new file mode 100644 index 0000000..757f1b6 --- /dev/null +++ b/shell-completion/zsh/_systemd-delta @@ -0,0 +1,15 @@ +#compdef systemd-delta + +_delta_type() { + local -a _delta_types + _delta_types=(masked equivalent redirected overridden unchanged) + _values -s , "${_delta_types[@]}" +} + +_arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--diff=[Show a diff when overridden files differ]:boolean:(1 0)' \ + {-t+,--type=}'[Only display a selected set of override types]:types:_delta_type' \ + ':SUFFIX:(tmpfiles.d sysctl.d systemd/system)' diff --git a/shell-completion/zsh/_systemd-inhibit b/shell-completion/zsh/_systemd-inhibit new file mode 100644 index 0000000..1ecb6dc --- /dev/null +++ b/shell-completion/zsh/_systemd-inhibit @@ -0,0 +1,33 @@ +#compdef systemd-inhibit + +_systemd_inhibit_command(){ + if (( CURRENT == 1 )); then + compset -q + _normal + else + local n=${words[(b:2:i)[^-]*]} + if (( n <= CURRENT )); then + compset -n $n + _alternative \ + 'files:file:_files' \ + 'commands:command:_normal' && return 0 + fi + _default + fi +} + +_inhibit_what() { + local _inhibit + _inhibit=(shutdown sleep idle handle-power-key handle-suspend-key handle-hibernate-key handle-lid-switch) + _values -s : "${_inhibit[@]}" +} + +_arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--what=[Operations to inhibit]:options:_inhibit_what' \ + '--who=[A descriptive string who is inhibiting]' \ + '--why=[A descriptive string why is being inhibited]' \ + '--mode=[One of block or delay]' \ + '--list[List active inhibitors]' \ + '*:commands:_systemd_inhibit_command' diff --git a/shell-completion/zsh/_systemd-nspawn b/shell-completion/zsh/_systemd-nspawn new file mode 100644 index 0000000..a8c2411 --- /dev/null +++ b/shell-completion/zsh/_systemd-nspawn @@ -0,0 +1,24 @@ +#compdef systemd-nspawn + +_nspawn-caps(){ + local -a _caps + _caps=( CAP_CHOWN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH + CAP_FOWNER CAP_FSETID CAP_IPC_OWNER CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE + CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETGID CAP_SETFCAP CAP_SETPCAP + CAP_SETUID CAP_SYS_ADMIN CAP_SYS_CHROOT CAP_SYS_NICE CAP_SYS_PTRACE CAP_SYS_TTY_CONFIG + CAP_SYS_RESOURCE CAP_SYS_BOOT ) + _values -s , 'capabilities' "$_caps[@]" +} + +_arguments \ + {-h,--help}'[Show this help]' \ + {--directory=,-D+}'[Directory to use as file system root for the namespace container. If omitted the current directory will be used.]:directories:_directories' \ + {--boot,-b+}'[Automatically search for an init binary and invoke it instead of a shell or a user supplied program.]' \ + {--user=,-u+}'[Run the command under specified user, create home directory and cd into it.]' \ + '--uuid=[Set the specified uuid for the container.]' \ + {--controllers=,-C+}'[Makes the container appear in other hierarchies than the name=systemd:/ one. Takes a comma-separated list of controllers.]' \ + '--private-network[Turn off networking in the container. This makes all network interfaces unavailable in the container, with the exception of the loopback device.]' \ + '--read-only[Mount the root file system read only for the container.]' \ + '--capability=[List one or more additional capabilities to grant the container.]:capabilities:_nspawn-caps' \ + "--link-journal=[Control whether the container's journal shall be made visible to the host system.]:options:(no, host, guest, auto)" \ + '-j[Equivalent to --link-journal=guest.]' diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run new file mode 100644 index 0000000..9bb7700 --- /dev/null +++ b/shell-completion/zsh/_systemd-run @@ -0,0 +1,33 @@ +#compdef systemd-run + +__systemctl() { + local -a _modes + _modes=("--user" "--system") + systemctl ${words:*_modes} --full --no-legend --no-pager "$@" 2>/dev/null +} + +__get_slices () { + __systemctl list-units --all -t slice \ + | { while read -r a b; do echo $a; done; }; +} + +__slices () { + local -a _slices + _slices=(${(fo)"$(__get_slices)"}) + typeset -U _slices + _describe 'slices' _slices +} + +_arguments \ + {-h,--help}'[Show help message]' \ + '--version[Show package version]' \ + '--user[Run as user unit]' \ + {-H+,--host=}'[Operate on remote host]:[user@]host:_sd_hosts_or_user_at_host' \ + {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ + '--scope[Run this as scope rather than service]' \ + '--unit=[Run under the specified unit name]:unit name' \ + '--description=[Description for unit]:description' \ + '--slice=[Run in the specified slice]:slices:__slices' \ + {-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \ + '--send-sighup[Send SIGHUP when terminating]' \ + '*::command:_command' diff --git a/shell-completion/zsh/_systemd-tmpfiles b/shell-completion/zsh/_systemd-tmpfiles new file mode 100644 index 0000000..4913ded --- /dev/null +++ b/shell-completion/zsh/_systemd-tmpfiles @@ -0,0 +1,10 @@ +#compdef systemd-tmpfiles + +_arguments \ + '--create[Create, set ownership/permissions based on the config files.]' \ + '--clean[Clean up all files and directories with an age parameter configured.]' \ + '--remove[All files and directories marked with r, R in the configuration files are removed.]' \ + '--prefix=[Only apply rules that apply to paths with the specified prefix.]' \ + '--exclude-prefix=[Ignore rules that apply to paths with the specified prefix.]' \ + '--help[Prints a short help text and exits.]' \ + '*::files:_files' diff --git a/shell-completion/zsh/_timedatectl b/shell-completion/zsh/_timedatectl new file mode 100644 index 0000000..987c2de --- /dev/null +++ b/shell-completion/zsh/_timedatectl @@ -0,0 +1,65 @@ +#compdef timedatectl + +_timedatectl_set-timezone(){ + local -a _timezones + _timezones=( ${(f)"$(_call_program timezones "${service}" list-timezones)"} ) + compadd "$_timezones[@]" +} + +_timedatectl_set-time(){ + _message "YYYY-MM-DD HH:MM:SS" +} + +_timedatectl_set-local-rtc(){ + local -a _options + _options=( + '0:Maintain RTC in universal time' + '1:Maintain RTC in local time' + ) + _describe options _options +} + +_timedatectl_set-ntp(){ + local -a _options + _options=( + '0:Disable NTP based network time configuration' + '1:Enable NTP based network time configuration' + ) + _describe options _options +} + +_timedatectl_command(){ + local -a _timedatectl_cmds + _timedatectl_cmds=( + 'status:Show current time settings' + 'set-time:Set system time' + 'set-timezone:Set system timezone' + 'list-timezones:Show known timezones' + 'set-local-rtc:Control whether RTC is in local time' + 'set-ntp:Control whether NTP is enabled' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'timedatectl command' _timedatectl_cmds + else + local curcontext="$curcontext" + cmd="${${_timedatectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + if (( $+functions[_timedatectl_$cmd] )); then + _timedatectl_$cmd + else + _message "no more options" + fi + else + _message "unknown timedatectl command: $words[1]" + fi + fi +} + +_arguments -s \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--adjust-system-clock[Adjust system clock when changing local RTC mode]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \ + '*::timedatectl commands:_timedatectl_command' diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm new file mode 100644 index 0000000..e5d252c --- /dev/null +++ b/shell-completion/zsh/_udevadm @@ -0,0 +1,141 @@ +#compdef udevadm + +_udevadm_info(){ + _arguments \ + '--query=[Query the database for specified type of device data. It needs the --path or --name to identify the specified device.]:type:(name symlink path property all)' \ + '--path=[The devpath of the device to query.]:sys files:_files -P /sys/ -W /sys' \ + '--name=[The name of the device node or a symlink to query]:device files:_files -P /dev/ -W /dev' \ + '--root[Print absolute paths in name or symlink query.]' \ + '--attribute-walk[Print all sysfs properties of the specified device that can be used in udev rules to match the specified device]' \ + '--export[Print output as key/value pairs.]' \ + '--export-prefix=[Add a prefix to the key name of exported values.]:prefix' \ + '--device-id-of-file=[Print major/minor numbers of the underlying device, where the file lives on.]:files:_udevadm_mounts' \ + '--export-db[Export the content of the udev database.]' \ + '--cleanup-db[Cleanup the udev database.]' +} + +_udevadm_trigger(){ + _arguments \ + '--verbose[Print the list of devices which will be triggered.]' \ + '--dry-run[Do not actually trigger the event.]' \ + '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \ + '--action=[Type of event to be triggered.]:actions:(add change remove)' \ + '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ + '--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \ + '--attr-match=attribute=[Trigger events for devices with a matching sysfs attribute.]' \ + '--attr-nomatch=attribute=[Do not trigger events for devices with a matching sysfs attribute.]' \ + '--property-match=[Trigger events for devices with a matching property value.]' \ + '--tag-match=property[Trigger events for devices with a matching tag.]' \ + '--sysname-match=[Trigger events for devices with a matching sys device name.]' \ + '--parent-match=[Trigger events for all children of a given device.]' +} + +_udevadm_settle(){ + _arguments \ + '--timeout=[Maximum number of seconds to wait for the event queue to become empty.]' \ + '--seq-start=[Wait only for events after the given sequence number.]' \ + '--seq-end=[Wait only for events before the given sequence number.]' \ + '--exit-if-exists=[Stop waiting if file exists.]:files:_files' \ + '--quiet[Do not print any output, like the remaining queue entries when reaching the timeout.]' \ + '--help[Print help text.]' +} + +_udevadm_control(){ + _arguments \ + '--exit[Signal and wait for systemd-udevd to exit.]' \ + '--log-priority=[Set the internal log level of systemd-udevd.]:priorities:(err info debug)' \ + '--stop-exec-queue[Signal systemd-udevd to stop executing new events. Incoming events will be queued.]' \ + '--start-exec-queue[Signal systemd-udevd to enable the execution of events.]' \ + '--reload[Signal systemd-udevd to reload the rules files and other databases like the kernel module index.]' \ + '--property=[Set a global property for all events.]' \ + '--children-max=[Set the maximum number of events.]' \ + '--timeout=[The maximum number of seconds to wait for a reply from systemd-udevd.]' \ + '--help[Print help text.]' +} + +_udevadm_monitor(){ + _arguments \ + '--kernel[Print the kernel uevents.]' \ + '--udev[Print the udev event after the rule processing.]' \ + '--property[Also print the properties of the event.]' \ + '--subsystem-match=[Filter events by subsystem/\[devtype\].]' \ + '--tag-match=[Filter events by property.]' \ + '--help[Print help text.]' +} + +_udevadm_test(){ + _arguments \ + '--action=[The action string.]:actions:(add change remove)' \ + '--subsystem=[The subsystem string.]' \ + '--help[Print help text.]' \ + '*::devpath:_files -P /sys/ -W /sys' +} + +_udevadm_test-builtin(){ + if (( CURRENT == 2 )); then + _arguments \ + '--help[Print help text]' \ + '*::builtins:(blkid btrfs hwdb input_id net_id net_setup_link kmod path_id usb_id uaccess)' + elif (( CURRENT == 3 )); then + _arguments \ + '--help[Print help text]' \ + '*::syspath:_files -P /sys -W /sys' + else + _arguments \ + '--help[Print help text]' + fi +} + +_udevadm_mounts(){ + local dev_tmp dpath_tmp mp_tmp mline + + tmp=( "${(@f)$(< /etc/mtab)}" ) + dev_tmp=( "${(@)${(@)tmp%% *}:#none}" ) + mp_tmp=( "${(@)${(@)tmp#* }%% *}" ) + + local MATCH + mp_tmp=("${(@q)mp_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}") + dpath_tmp=( "${(@Mq)dev_tmp:#/*}" ) + dev_tmp=( "${(@q)dev_tmp:#/*}" ) + + _alternative \ + 'device-paths: device path:compadd -a dpath_tmp' \ + 'directories:mount point:compadd -a mp_tmp' +} + + +_udevadm_command(){ + local -a _udevadm_cmds + _udevadm_cmds=( + 'info:query sysfs or the udev database' + 'trigger:request events from the kernel' + 'settle:wait for the event queue to finish' + 'control:control the udev daemon' + 'monitor:listen to kernel and udev events' + 'test:test an event run' + 'test-builtin:test a built-in command' + ) + + if ((CURRENT == 1)); then + _describe -t commands 'udevadm commands' _udevadm_cmds + else + local curcontext="$curcontext" + cmd="${${_udevadm_cmds[(r)$words[1]:*]%%:*}}" + if (($#cmd)); then + if (( $+functions[_udevadm_$cmd] )); then + _udevadm_$cmd + else + _message "no options for $cmd" + fi + else + _message "no more options" + fi + fi +} + + +_arguments \ + '--debug[Print debug messages to stderr]' \ + '--version[Print version number]' \ + '--help[Print help text]' \ + '*::udevadm commands:_udevadm_command' diff --git a/src/.gitignore b/src/.gitignore index cafff82..e6ac2d7 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,15 +1,8 @@ load-fragment-gperf-nulstr.c load-fragment-gperf.c load-fragment-gperf.gperf -logind-gperf.c org.freedesktop.systemd1.policy.in -99-systemd.rules -org.freedesktop.hostname1.policy -org.freedesktop.locale1.policy -org.freedesktop.login1.policy -org.freedesktop.timedate1.policy org.freedesktop.systemd1.policy -gnome-ask-password-agent.c -systemd-interfaces.c -systemadm.c -73-seat-late.rules +99-systemd.rules +*.gcno +*.gcda diff --git a/src/70-uaccess.rules b/src/70-uaccess.rules deleted file mode 100644 index 6932492..0000000 --- a/src/70-uaccess.rules +++ /dev/null @@ -1,72 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="uaccess_end" -ENV{MAJOR}=="", GOTO="uaccess_end" - -# PTP/MTP protocol devices, cameras, portable media players -SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p" -SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess" - -# Digicams with proprietary protocol -ENV{ID_GPHOTO2}=="*?", TAG+="uaccess" - -# SCSI and USB scanners -ENV{libsane_matched}=="yes", TAG+="uaccess" - -# HPLIP devices (necessary for ink level check and HP tool maintenance) -ENV{ID_HPLIP}=="1", TAG+="uaccess" - -# optical drives -SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess" -SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess" - -# Sound devices -SUBSYSTEM=="sound", TAG+="uaccess" - -# ffado is an userspace driver for firewire sound cards -SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess" - -# Webcams, frame grabber, TV cards -SUBSYSTEM=="video4linux", TAG+="uaccess" -SUBSYSTEM=="dvb", TAG+="uaccess" - -# IIDC devices: industrial cameras and some webcams -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess" -SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" -# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" - -# DRI video devices -SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess" - -# KVM -SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" - -# smart-card readers -ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess" - -# PDA devices -ENV{ID_PDA}=="*?", TAG+="uaccess" - -# Programmable remote control -ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess" - -# joysticks -SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess" - -# color measurement devices -ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess" - -# DDC/CI device, usually high-end monitors such as the DreamColor -ENV{DDC_DEVICE}=="*?", TAG+="uaccess" - -# media player raw devices (for user-mode drivers, Android SDK, etc.) -SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" - -LABEL="uaccess_end" diff --git a/src/71-seat.rules b/src/71-seat.rules deleted file mode 100644 index 99425ad..0000000 --- a/src/71-seat.rules +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="seat_end" - -TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" -SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" -SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" -SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" -SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" - -# 'Plugable' USB hub, sound, network, graphics adapter -SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" - -TAG=="seat", ENV{ID_PATH}=="", IMPORT{program}="path_id %p" -TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}" - -LABEL="seat_end" diff --git a/src/73-seat-late.rules.in b/src/73-seat-late.rules.in deleted file mode 100644 index 0847932..0000000 --- a/src/73-seat-late.rules.in +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="seat_late_end" - -ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" -ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" - -ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" - -TAG=="uaccess", ENV{MAJOR}!="", RUN+="@rootlibexecdir@/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}" - -LABEL="seat_late_end" diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in deleted file mode 100644 index 913373b..0000000 --- a/src/99-systemd.rules.in +++ /dev/null @@ -1,55 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="systemd_end" - -SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd" -SUBSYSTEM=="tty", KERNEL=="tty[aS][0-9]*", TAG+="systemd" - -KERNEL=="vport*", TAG+="systemd" - -SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd" -SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" - -# Ignore encrypted devices with no identified superblock on it, since -# we are probably still calling mke2fs or mkswap on it. - -SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" - -# We need a hardware independent way to identify network devices. We -# use the /sys/subsystem path for this. Current vanilla kernels don't -# actually support that hierarchy right now, however upcoming kernels -# will. HAL and udev internally support /sys/subsystem already, hence -# it should be safe to use this here, too. This is mostly just an -# identification string for systemd, so whether the path actually is -# accessible or not does not matter as long as it is unique and in the -# filesystem namespace. -# -# http://git.kernel.org/?p=linux/hotplug/udev.git;a=blob;f=libudev/libudev-enumerate.c;h=da831449dcaf5e936a14409e8e68ab12d30a98e2;hb=HEAD#l742 - -SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/$name" -SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/bluetooth/devices/%k" - -SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}="bluetooth.target" -ENV{ID_SMARTCARD_READER}=="*?", TAG+="systemd", ENV{SYSTEMD_WANTS}="smartcard.target" -SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}="sound.target" - -SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" -SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" - -# Apply sysctl variables to network devices (and only to those) as they appear. - -SUBSYSTEM=="net", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name" - -# Asynchronously mount file systems implemented by these modules as -# soon as they are loaded. - -SUBSYSTEM=="module", KERNEL=="fuse", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-fs-fuse-connections.mount" -SUBSYSTEM=="module", KERNEL=="configfs", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-kernel-config.mount" - -LABEL="systemd_end" diff --git a/src/Makefile b/src/Makefile index bc7e9fa..9d07505 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,16 +3,16 @@ # Copyright 2010 Lennart Poettering # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. +# Lesser General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Lesser General Public License # along with systemd; If not, see . # This file is a dirty trick to simplify compilation from within diff --git a/src/ac-power.c b/src/ac-power.c deleted file mode 100644 index 24a68e7..0000000 --- a/src/ac-power.c +++ /dev/null @@ -1,111 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "util.h" - -static int on_ac_power(void) { - int r; - - struct udev *udev; - struct udev_enumerate *e = NULL; - struct udev_list_entry *item = NULL, *first = NULL; - bool found_offline = false, found_online = false; - - if (!(udev = udev_new())) { - r = -ENOMEM; - goto finish; - } - - if (!(e = udev_enumerate_new(udev))) { - r = -ENOMEM; - goto finish; - } - - if (udev_enumerate_add_match_subsystem(e, "power_supply") < 0) { - r = -EIO; - goto finish; - } - - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; - goto finish; - } - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - struct udev_device *d; - const char *type, *online; - - if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) { - r = -ENOMEM; - goto finish; - } - - if (!(type = udev_device_get_sysattr_value(d, "type"))) - goto next; - - if (!streq(type, "Mains")) - goto next; - - if (!(online = udev_device_get_sysattr_value(d, "online"))) - goto next; - - if (streq(online, "1")) { - found_online = true; - break; - } else if (streq(online, "0")) - found_offline = true; - - next: - udev_device_unref(d); - } - - r = found_online || !found_offline; - -finish: - if (e) - udev_enumerate_unref(e); - - if (udev) - udev_unref(udev); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - - /* This is mostly intended to be used for scripts which want - * to detect whether AC power is plugged in or not. */ - - if ((r = on_ac_power()) < 0) { - log_error("Failed to read AC status: %s", strerror(-r)); - return EXIT_FAILURE; - } - - return r == 0; -} diff --git a/src/ac-power/Makefile b/src/ac-power/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/ac-power/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c new file mode 100644 index 0000000..bd1b6ec --- /dev/null +++ b/src/ac-power/ac-power.c @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +int main(int argc, char *argv[]) { + int r; + + /* This is mostly intended to be used for scripts which want + * to detect whether AC power is plugged in or not. */ + + r = on_ac_power(); + if (r < 0) { + log_error("Failed to read AC status: %s", strerror(-r)); + return EXIT_FAILURE; + } + + return r != 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/activate/Makefile b/src/activate/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/activate/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/activate/activate.c b/src/activate/activate.c new file mode 100644 index 0000000..23c484c --- /dev/null +++ b/src/activate/activate.c @@ -0,0 +1,434 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "socket-util.h" +#include "build.h" +#include "log.h" +#include "strv.h" +#include "macro.h" + +static char** arg_listen = NULL; +static bool arg_accept = false; +static char** arg_args = NULL; +static char** arg_setenv = NULL; + +static int add_epoll(int epoll_fd, int fd) { + struct epoll_event ev = { + .events = EPOLLIN + }; + int r; + + assert(epoll_fd >= 0); + assert(fd >= 0); + + ev.data.fd = fd; + r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); + if (r < 0) { + log_error("Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd); + return -errno; + } + + return 0; +} + +static int make_socket_fd(const char* address, int flags) { + SocketAddress a; + int fd, r; + + r = socket_address_parse(&a, address); + if (r < 0) { + log_error("Failed to parse socket: %s", strerror(-r)); + return r; + } + + fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, 0755, 0644, NULL); + if (fd < 0) { + log_error("Failed to listen: %s", strerror(-r)); + return fd; + } + + return fd; +} + +static int open_sockets(int *epoll_fd, bool accept) { + char **address; + int n, fd, r; + int count = 0; + + n = sd_listen_fds(true); + if (n < 0) { + log_error("Failed to read listening file descriptors from environment: %s", + strerror(-n)); + return n; + } + if (n > 0) { + log_info("Received %i descriptors via the environment.", n); + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + r = fd_cloexec(fd, arg_accept); + if (r < 0) + return r; + + count ++; + } + } + + /* Close logging and all other descriptors */ + if (arg_listen) { + int except[3 + n]; + + for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++) + except[fd] = fd; + + log_close(); + close_all_fds(except, 3 + n); + } + + /** Note: we leak some fd's on error here. I doesn't matter + * much, since the program will exit immediately anyway, but + * would be a pain to fix. + */ + + STRV_FOREACH(address, arg_listen) { + + fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC)); + if (fd < 0) { + log_open(); + log_error("Failed to open '%s': %s", *address, strerror(-fd)); + return fd; + } + + assert(fd == SD_LISTEN_FDS_START + count); + count ++; + } + + if (arg_listen) + log_open(); + + *epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (*epoll_fd < 0) { + log_error("Failed to create epoll object: %m"); + return -errno; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) { + _cleanup_free_ char *name = NULL; + + getsockname_pretty(fd, &name); + log_info("Listening on %s as %i.", strna(name), fd); + + r = add_epoll(*epoll_fd, fd); + if (r < 0) + return r; + } + + return count; +} + +static int launch(char* name, char **argv, char **env, int fds) { + + static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="}; + _cleanup_strv_free_ char **envp = NULL; + _cleanup_free_ char *tmp = NULL; + unsigned n_env = 0, length; + char **s; + unsigned i; + + length = strv_length(arg_setenv); + + /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */ + envp = new0(char *, length + 7); + if (!envp) + return log_oom(); + + STRV_FOREACH(s, arg_setenv) { + if (strchr(*s, '=')) + envp[n_env++] = *s; + else { + _cleanup_free_ char *p = strappend(*s, "="); + if (!p) + return log_oom(); + envp[n_env] = strv_find_prefix(env, p); + if (envp[n_env]) + n_env ++; + } + } + + for (i = 0; i < ELEMENTSOF(tocopy); i++) { + envp[n_env] = strv_find_prefix(env, tocopy[i]); + if (envp[n_env]) + n_env ++; + } + + if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) || + (asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0)) + return log_oom(); + + tmp = strv_join(argv, " "); + if (!tmp) + return log_oom(); + + log_info("Execing %s (%s)", name, tmp); + execvpe(name, argv, envp); + log_error("Failed to execp %s (%s): %m", name, tmp); + + return -errno; +} + +static int launch1(const char* child, char** argv, char **env, int fd) { + _cleanup_free_ char *tmp = NULL; + pid_t parent_pid, child_pid; + int r; + + tmp = strv_join(argv, " "); + if (!tmp) + return log_oom(); + + parent_pid = getpid(); + + child_pid = fork(); + if (child_pid < 0) { + log_error("Failed to fork: %m"); + return -errno; + } + + /* In the child */ + if (child_pid == 0) { + r = dup2(fd, STDIN_FILENO); + if (r < 0) { + log_error("Failed to dup connection to stdin: %m"); + _exit(EXIT_FAILURE); + } + + r = dup2(fd, STDOUT_FILENO); + if (r < 0) { + log_error("Failed to dup connection to stdout: %m"); + _exit(EXIT_FAILURE); + } + + r = close(fd); + if (r < 0) { + log_error("Failed to close dupped connection: %m"); + _exit(EXIT_FAILURE); + } + + /* Make sure the child goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Check whether our parent died before we were able + * to set the death signal */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + execvp(child, argv); + log_error("Failed to exec child %s: %m", child); + _exit(EXIT_FAILURE); + } + + log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid); + + return 0; +} + +static int do_accept(const char* name, char **argv, char **envp, int fd) { + _cleanup_free_ char *local = NULL, *peer = NULL; + int fd2; + + fd2 = accept(fd, NULL, NULL); + if (fd2 < 0) { + log_error("Failed to accept connection on fd:%d: %m", fd); + return fd2; + } + + getsockname_pretty(fd2, &local); + getpeername_pretty(fd2, &peer); + log_info("Connection from %s to %s", strna(peer), strna(local)); + + return launch1(name, argv, envp, fd2); +} + +/* SIGCHLD handler. */ +static void sigchld_hdl(int sig, siginfo_t *t, void *data) { + PROTECT_ERRNO; + + log_info("Child %d died with code %d", t->si_pid, t->si_status); + /* Wait for a dead child. */ + waitpid(t->si_pid, NULL, 0); +} + +static int install_chld_handler(void) { + int r; + struct sigaction act = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = sigchld_hdl, + }; + + r = sigaction(SIGCHLD, &act, 0); + if (r < 0) + log_error("Failed to install SIGCHLD handler: %m"); + return r; +} + +static int help(void) { + printf("%s [OPTIONS...]\n\n" + "Listen on sockets and launch child on connection.\n\n" + "Options:\n" + " -l --listen=ADDR Listen for raw connections at ADDR\n" + " -a --accept Spawn separate child for each connection\n" + " -h --help Show this help and exit\n" + " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" + " --version Print version string and exit\n" + "\n" + "Note: file descriptors from sd_listen_fds() will be passed through.\n" + , program_invocation_short_name + ); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "listen", required_argument, NULL, 'l' }, + { "accept", no_argument, NULL, 'a' }, + { "setenv", required_argument, NULL, 'E' }, + { "environment", required_argument, NULL, 'E' }, /* alias */ + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+hl:aE:", options, NULL)) >= 0) + switch(c) { + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0 /* done */; + + case 'l': { + int r = strv_extend(&arg_listen, optarg); + if (r < 0) + return r; + + break; + } + + case 'a': + arg_accept = true; + break; + + case 'E': { + int r = strv_extend(&arg_setenv, optarg); + if (r < 0) + return r; + + break; + } + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (optind == argc) { + log_error("Usage: %s [OPTION...] PROGRAM [OPTION...]", + program_invocation_short_name); + return -EINVAL; + } + + arg_args = argv + optind; + + return 1 /* work to do */; +} + +int main(int argc, char **argv, char **envp) { + int r, n; + int epoll_fd = -1; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + + r = install_chld_handler(); + if (r < 0) + return EXIT_FAILURE; + + n = open_sockets(&epoll_fd, arg_accept); + if (n < 0) + return EXIT_FAILURE; + if (n == 0) { + log_error("No sockets to listen on specified or passed in."); + return EXIT_FAILURE; + } + + for (;;) { + struct epoll_event event; + + r = epoll_wait(epoll_fd, &event, 1, -1); + if (r < 0) { + if (errno == EINTR) + continue; + + log_error("epoll_wait() failed: %m"); + return EXIT_FAILURE; + } + + log_info("Communication attempt on fd %i.", event.data.fd); + if (arg_accept) { + r = do_accept(argv[optind], argv + optind, envp, + event.data.fd); + if (r < 0) + return EXIT_FAILURE; + } else + break; + } + + launch(argv[optind], argv + optind, envp, n); + + return EXIT_SUCCESS; +} diff --git a/src/analyze/.gitignore b/src/analyze/.gitignore new file mode 100644 index 0000000..752ea23 --- /dev/null +++ b/src/analyze/.gitignore @@ -0,0 +1 @@ +/systemd-analyze diff --git a/src/analyze/Makefile b/src/analyze/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/analyze/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c new file mode 100644 index 0000000..3d2d08f --- /dev/null +++ b/src/analyze/analyze.c @@ -0,0 +1,1307 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2013 Lennart Poettering + Copyright 2013 Simon Peeters + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "install.h" +#include "log.h" +#include "build.h" +#include "util.h" +#include "strxcpyx.h" +#include "fileio.h" +#include "strv.h" +#include "unit-name.h" +#include "special.h" +#include "hashmap.h" +#include "pager.h" + +#define SCALE_X (0.1 / 1000.0) /* pixels per us */ +#define SCALE_Y 20.0 + +#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0)) + +#define svg(...) printf(__VA_ARGS__) + +#define svg_bar(class, x1, x2, y) \ + svg(" \n", \ + (class), \ + SCALE_X * (x1), SCALE_Y * (y), \ + SCALE_X * ((x2) - (x1)), SCALE_Y - 1.0) + +#define svg_text(b, x, y, format, ...) \ + do { \ + svg(" ", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \ + svg(format, ## __VA_ARGS__); \ + svg("\n"); \ + } while(false) + +static enum dot { + DEP_ALL, + DEP_ORDER, + DEP_REQUIRE +} arg_dot = DEP_ALL; +static char** arg_dot_from_patterns = NULL; +static char** arg_dot_to_patterns = NULL; +static usec_t arg_fuzz = 0; +static bool arg_no_pager = false; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_user = false; + +struct boot_times { + usec_t firmware_time; + usec_t loader_time; + usec_t kernel_time; + usec_t kernel_done_time; + usec_t initrd_time; + usec_t userspace_time; + usec_t finish_time; + usec_t security_start_time; + usec_t security_finish_time; + usec_t generators_start_time; + usec_t generators_finish_time; + usec_t unitsload_start_time; + usec_t unitsload_finish_time; +}; + +struct unit_times { + char *name; + usec_t activating; + usec_t activated; + usec_t deactivated; + usec_t deactivating; + usec_t time; +}; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(property); + assert(val); + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.systemd1", + path, + interface, + property, + &error, + 't', val); + + if (r < 0) { + log_error("Failed to parse reply: %s", bus_error_message(&error, -r)); + return r; + } + + return 0; +} + +static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(path); + assert(property); + assert(strv); + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + property, + &error, + strv); + if (r < 0) { + log_error("Failed to get unit property %s: %s", property, bus_error_message(&error, -r)); + return r; + } + + return 0; +} + +static int compare_unit_time(const void *a, const void *b) { + return compare(((struct unit_times *)b)->time, + ((struct unit_times *)a)->time); +} + +static int compare_unit_start(const void *a, const void *b) { + return compare(((struct unit_times *)a)->activating, + ((struct unit_times *)b)->activating); +} + +static int get_os_name(char **_n) { + char *n = NULL; + int r; + + r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &n, NULL); + if (r < 0) + return r; + + if (!n) + return -ENOENT; + + *_n = n; + return 0; +} + +static void free_unit_times(struct unit_times *t, unsigned n) { + struct unit_times *p; + + for (p = t; p < t + n; p++) + free(p->name); + + free(t); +} + +static int acquire_time_data(sd_bus *bus, struct unit_times **out) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r, c = 0; + struct unit_times *unit_times = NULL; + size_t size = 0; + UnitInfo u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits", + &error, &reply, + NULL); + if (r < 0) { + log_error("Failed to list units: %s", bus_error_message(&error, -r)); + goto fail; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); + if (r < 0) { + bus_log_parse_error(r); + goto fail; + } + + while ((r = bus_parse_unit_info(reply, &u)) > 0) { + struct unit_times *t; + + if (!GREEDY_REALLOC(unit_times, size, c+1)) { + r = log_oom(); + goto fail; + } + + t = unit_times+c; + t->name = NULL; + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + if (bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "InactiveExitTimestampMonotonic", + &t->activating) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "ActiveEnterTimestampMonotonic", + &t->activated) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "ActiveExitTimestampMonotonic", + &t->deactivating) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "InactiveEnterTimestampMonotonic", + &t->deactivated) < 0) { + r = -EIO; + goto fail; + } + + if (t->activated >= t->activating) + t->time = t->activated - t->activating; + else if (t->deactivated >= t->activating) + t->time = t->deactivated - t->activating; + else + t->time = 0; + + if (t->activating == 0) + continue; + + t->name = strdup(u.id); + if (t->name == NULL) { + r = log_oom(); + goto fail; + } + c++; + } + if (r < 0) { + bus_log_parse_error(r); + goto fail; + } + + *out = unit_times; + return c; + +fail: + free_unit_times(unit_times, (unsigned) c); + return r; +} + +static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) { + static struct boot_times times; + static bool cached = false; + + if (cached) + goto finish; + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + if (bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "FirmwareTimestampMonotonic", + ×.firmware_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "LoaderTimestampMonotonic", + ×.loader_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KernelTimestamp", + ×.kernel_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "InitRDTimestampMonotonic", + ×.initrd_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UserspaceTimestampMonotonic", + ×.userspace_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "FinishTimestampMonotonic", + ×.finish_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SecurityStartTimestampMonotonic", + ×.security_start_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SecurityFinishTimestampMonotonic", + ×.security_finish_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GeneratorsStartTimestampMonotonic", + ×.generators_start_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GeneratorsFinishTimestampMonotonic", + ×.generators_finish_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitsLoadStartTimestampMonotonic", + ×.unitsload_start_time) < 0 || + bus_get_uint64_property(bus, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitsLoadFinishTimestampMonotonic", + ×.unitsload_finish_time) < 0) + return -EIO; + + if (times.finish_time <= 0) { + log_error("Bootup is not yet finished. Please try again later."); + return -EINPROGRESS; + } + + if (times.initrd_time) + times.kernel_done_time = times.initrd_time; + else + times.kernel_done_time = times.userspace_time; + + cached = true; + +finish: + *bt = × + return 0; +} + +static int pretty_boot_time(sd_bus *bus, char **_buf) { + char ts[FORMAT_TIMESPAN_MAX]; + struct boot_times *t; + static char buf[4096]; + size_t size; + char *ptr; + int r; + + r = acquire_boot_times(bus, &t); + if (r < 0) + return r; + + ptr = buf; + size = sizeof(buf); + + size = strpcpyf(&ptr, size, "Startup finished in "); + if (t->firmware_time) + size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC)); + if (t->loader_time) + size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC)); + if (t->kernel_time) + size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC)); + if (t->initrd_time > 0) + size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC)); + + size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); + if (t->kernel_time > 0) + strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC)); + else + strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); + + ptr = strdup(buf); + if (!ptr) + return log_oom(); + + *_buf = ptr; + return 0; +} + +static void svg_graph_box(double height, double begin, double end) { + long long i; + + /* outside box, fill */ + svg("\n", + SCALE_X * (end - begin), SCALE_Y * height); + + for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) { + /* lines for each second */ + if (i % 5000000 == 0) + svg(" \n" + " %.01fs\n", + SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i); + else if (i % 1000000 == 0) + svg(" \n" + " %.01fs\n", + SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i); + else + svg(" \n", + SCALE_X * i, SCALE_X * i, SCALE_Y * height); + } +} + +static int analyze_plot(sd_bus *bus) { + struct unit_times *times; + struct boot_times *boot; + struct utsname name; + int n, m = 1, y=0; + double width; + _cleanup_free_ char *pretty_times = NULL, *osname = NULL; + struct unit_times *u; + + n = acquire_boot_times(bus, &boot); + if (n < 0) + return n; + + n = pretty_boot_time(bus, &pretty_times); + if (n < 0) + return n; + + get_os_name(&osname); + assert_se(uname(&name) >= 0); + + n = acquire_time_data(bus, ×); + if (n <= 0) + return n; + + qsort(times, n, sizeof(struct unit_times), compare_unit_start); + + width = SCALE_X * (boot->firmware_time + boot->finish_time); + if (width < 800.0) + width = 800.0; + + if (boot->firmware_time > boot->loader_time) + m++; + if (boot->loader_time) { + m++; + if (width < 1000.0) + width = 1000.0; + } + if (boot->initrd_time) + m++; + if (boot->kernel_time) + m++; + + for (u = times; u < times + n; u++) { + double text_start, text_width; + + if (u->activating < boot->userspace_time || + u->activating > boot->finish_time) { + free(u->name); + u->name = NULL; + continue; + } + + /* If the text cannot fit on the left side then + * increase the svg width so it fits on the right. + * TODO: calculate the text width more accurately */ + text_width = 8.0 * strlen(u->name); + text_start = (boot->firmware_time + u->activating) * SCALE_X; + if (text_width > text_start && text_width + text_start > width) + width = text_width + text_start; + + if (u->deactivated > u->activating && u->deactivated <= boot->finish_time + && u->activated == 0 && u->deactivating == 0) + u->activated = u->deactivating = u->deactivated; + if (u->activated < u->activating || u->activated > boot->finish_time) + u->activated = boot->finish_time; + if (u->deactivating < u->activated || u->activated > boot->finish_time) + u->deactivating = boot->finish_time; + if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time) + u->deactivated = boot->finish_time; + m++; + } + + svg("\n" + "\n"); + + svg("\n\n", + 80.0 + width, 150.0 + (m * SCALE_Y) + + 5 * SCALE_Y /* legend */); + + /* write some basic info as a comment, including some help */ + svg("\n" + "\n" + "\n" + "\n" + "\n\n" + "\n\n", VERSION); + + /* style sheet */ + svg("\n \n\n\n"); + + svg("\n"); + svg("%s", pretty_times); + svg("%s %s (%s %s) %s", + isempty(osname) ? "Linux" : osname, + name.nodename, name.release, name.version, name.machine); + + svg("\n", 20.0 + (SCALE_X * boot->firmware_time)); + svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time); + + if (boot->firmware_time) { + svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y); + svg_text(true, -(double) boot->firmware_time, y, "firmware"); + y++; + } + if (boot->loader_time) { + svg_bar("loader", -(double) boot->loader_time, 0, y); + svg_text(true, -(double) boot->loader_time, y, "loader"); + y++; + } + if (boot->kernel_time) { + svg_bar("kernel", 0, boot->kernel_done_time, y); + svg_text(true, 0, y, "kernel"); + y++; + } + if (boot->initrd_time) { + svg_bar("initrd", boot->initrd_time, boot->userspace_time, y); + svg_text(true, boot->initrd_time, y, "initrd"); + y++; + } + svg_bar("active", boot->userspace_time, boot->finish_time, y); + svg_bar("security", boot->security_start_time, boot->security_finish_time, y); + svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y); + svg_bar("unitsload", boot->unitsload_start_time, boot->unitsload_finish_time, y); + svg_text(true, boot->userspace_time, y, "systemd"); + y++; + + for (u = times; u < times + n; u++) { + char ts[FORMAT_TIMESPAN_MAX]; + bool b; + + if (!u->name) + continue; + + svg_bar("activating", u->activating, u->activated, y); + svg_bar("active", u->activated, u->deactivating, y); + svg_bar("deactivating", u->deactivating, u->deactivated, y); + + /* place the text on the left if we have passed the half of the svg width */ + b = u->activating * SCALE_X < width / 2; + if (u->time) + svg_text(b, u->activating, y, "%s (%s)", + u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC)); + else + svg_text(b, u->activating, y, "%s", u->name); + y++; + } + + svg("\n"); + + /* Legend */ + svg("\n"); + y++; + svg_bar("activating", 0, 300000, y); + svg_text(true, 400000, y, "Activating"); + y++; + svg_bar("active", 0, 300000, y); + svg_text(true, 400000, y, "Active"); + y++; + svg_bar("deactivating", 0, 300000, y); + svg_text(true, 400000, y, "Deactivating"); + y++; + svg_bar("security", 0, 300000, y); + svg_text(true, 400000, y, "Setting up security module"); + y++; + svg_bar("generators", 0, 300000, y); + svg_text(true, 400000, y, "Generators"); + y++; + svg_bar("unitsload", 0, 300000, y); + svg_text(true, 400000, y, "Loading unit files"); + y++; + + svg("\n\n"); + + svg("\n"); + + free_unit_times(times, (unsigned) n); + + return 0; +} + +static int list_dependencies_print(const char *name, unsigned int level, unsigned int branches, + bool last, struct unit_times *times, struct boot_times *boot) { + unsigned int i; + char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX]; + + for (i = level; i != 0; i--) + printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERT : DRAW_TREE_SPACE)); + + printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + + if (times) { + if (times->time) + printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name, + format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC), + format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF); + else if (times->activated > boot->userspace_time) + printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); + else + printf("%s", name); + } else + printf("%s", name); + printf("\n"); + + return 0; +} + +static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) { + _cleanup_free_ char *path = NULL; + + assert(bus); + assert(name); + assert(deps); + + path = unit_dbus_path_from_name(name); + if (path == NULL) + return -ENOMEM; + + return bus_get_unit_property_strv(bus, path, "After", deps); +} + +static Hashmap *unit_times_hashmap; + +static int list_dependencies_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + usec_t usa = 0, usb = 0; + struct unit_times *times; + + times = hashmap_get(unit_times_hashmap, *a); + if (times) + usa = times->activated; + times = hashmap_get(unit_times_hashmap, *b); + if (times) + usb = times->activated; + + return usb - usa; +} + +static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units, + unsigned int branches) { + _cleanup_strv_free_ char **deps = NULL; + char **c; + int r = 0; + usec_t service_longest = 0; + int to_print = 0; + struct unit_times *times; + struct boot_times *boot; + + if (strv_extend(units, name)) + return log_oom(); + + r = list_dependencies_get_dependencies(bus, name, &deps); + if (r < 0) + return r; + + qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare); + + r = acquire_boot_times(bus, &boot); + if (r < 0) + return r; + + STRV_FOREACH(c, deps) { + times = hashmap_get(unit_times_hashmap, *c); + if (times + && times->activated + && times->activated <= boot->finish_time + && (times->activated >= service_longest + || service_longest == 0)) { + service_longest = times->activated; + break; + } + } + + if (service_longest == 0 ) + return r; + + STRV_FOREACH(c, deps) { + times = hashmap_get(unit_times_hashmap, *c); + if (times && times->activated + && times->activated <= boot->finish_time + && (service_longest - times->activated) <= arg_fuzz) { + to_print++; + } + } + + if (!to_print) + return r; + + STRV_FOREACH(c, deps) { + times = hashmap_get(unit_times_hashmap, *c); + if (!times + || !times->activated + || times->activated > boot->finish_time + || service_longest - times->activated > arg_fuzz) + continue; + + to_print--; + + r = list_dependencies_print(*c, level, branches, to_print == 0, times, boot); + if (r < 0) + return r; + + if (strv_contains(*units, *c)) { + r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0), + true, NULL, boot); + if (r < 0) + return r; + continue; + } + + r = list_dependencies_one(bus, *c, level + 1, units, + (branches << 1) | (to_print ? 1 : 0)); + if (r < 0) + return r; + + if (!to_print) + break; + } + return 0; +} + +static int list_dependencies(sd_bus *bus, const char *name) { + _cleanup_strv_free_ char **units = NULL; + char ts[FORMAT_TIMESPAN_MAX]; + struct unit_times *times; + int r; + const char *path, *id; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct boot_times *boot; + + assert(bus); + + path = unit_dbus_path_from_name(name); + if (path == NULL) + return -ENOMEM; + + r = sd_bus_get_property( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "Id", + &error, + &reply, + "s"); + if (r < 0) { + log_error("Failed to get ID: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &id); + if (r < 0) + return bus_log_parse_error(r); + + times = hashmap_get(unit_times_hashmap, id); + + r = acquire_boot_times(bus, &boot); + if (r < 0) + return r; + + if (times) { + if (times->time) + printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED_ON, id, + format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF); + else if (times->activated > boot->userspace_time) + printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); + else + printf("%s\n", id); + } + + return list_dependencies_one(bus, name, 0, &units, 0); +} + +static int analyze_critical_chain(sd_bus *bus, char *names[]) { + struct unit_times *times; + unsigned int i; + Hashmap *h; + int n, r; + + n = acquire_time_data(bus, ×); + if (n <= 0) + return n; + + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return -ENOMEM; + + for (i = 0; i < (unsigned)n; i++) { + r = hashmap_put(h, times[i].name, ×[i]); + if (r < 0) + return r; + } + unit_times_hashmap = h; + + pager_open_if_enabled(); + + 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"); + + if (!strv_isempty(names)) { + char **name; + STRV_FOREACH(name, names) + list_dependencies(bus, *name); + } else + list_dependencies(bus, SPECIAL_DEFAULT_TARGET); + + hashmap_free(h); + free_unit_times(times, (unsigned) n); + return 0; +} + +static int analyze_blame(sd_bus *bus) { + struct unit_times *times; + unsigned i; + int n; + + n = acquire_time_data(bus, ×); + if (n <= 0) + return n; + + qsort(times, n, sizeof(struct unit_times), compare_unit_time); + + pager_open_if_enabled(); + + for (i = 0; i < (unsigned) n; i++) { + char ts[FORMAT_TIMESPAN_MAX]; + + if (times[i].time > 0) + printf("%16s %s\n", format_timespan(ts, sizeof(ts), times[i].time, USEC_PER_MSEC), times[i].name); + } + + free_unit_times(times, (unsigned) n); + return 0; +} + +static int analyze_time(sd_bus *bus) { + _cleanup_free_ char *buf = NULL; + int r; + + r = pretty_boot_time(bus, &buf); + if (r < 0) + return r; + + puts(buf); + return 0; +} + +static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, const char *color, char* patterns[]) { + _cleanup_strv_free_ char **units = NULL; + char **unit; + int r; + + assert(u); + assert(prop); + assert(color); + + r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units); + if (r < 0) + return r; + + STRV_FOREACH(unit, units) { + char **p; + bool match_found; + + if (!strv_isempty(arg_dot_from_patterns)) { + match_found = false; + + STRV_FOREACH(p, arg_dot_from_patterns) + if (fnmatch(*p, u->id, 0) == 0) { + match_found = true; + break; + } + + if (!match_found) + continue; + } + + if (!strv_isempty(arg_dot_to_patterns)) { + match_found = false; + + STRV_FOREACH(p, arg_dot_to_patterns) + if (fnmatch(*p, *unit, 0) == 0) { + match_found = true; + break; + } + + if (!match_found) + continue; + } + + if (!strv_isempty(patterns)) { + match_found = false; + + STRV_FOREACH(p, patterns) + if (fnmatch(*p, u->id, 0) == 0 || fnmatch(*p, *unit, 0) == 0) { + match_found = true; + break; + } + if (!match_found) + continue; + } + + printf("\t\"%s\"->\"%s\" [color=\"%s\"];\n", u->id, *unit, color); + } + + return 0; +} + +static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[]) { + int r; + + assert(bus); + assert(u); + + if (arg_dot == DEP_ORDER ||arg_dot == DEP_ALL) { + r = graph_one_property(bus, u, "After", "green", patterns); + if (r < 0) + return r; + } + + if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) { + r = graph_one_property(bus, u, "Requires", "black", patterns); + if (r < 0) + return r; + r = graph_one_property(bus, u, "RequiresOverridable", "black", patterns); + if (r < 0) + return r; + r = graph_one_property(bus, u, "RequisiteOverridable", "darkblue", patterns); + if (r < 0) + return r; + r = graph_one_property(bus, u, "Wants", "grey66", patterns); + if (r < 0) + return r; + r = graph_one_property(bus, u, "Conflicts", "red", patterns); + if (r < 0) + return r; + r = graph_one_property(bus, u, "ConflictedBy", "red", patterns); + if (r < 0) + return r; + } + + return 0; +} + +static int dot(sd_bus *bus, char* patterns[]) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + UnitInfo u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits", + &error, + &reply, + ""); + if (r < 0) { + log_error("Failed to list units: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); + if (r < 0) + return bus_log_parse_error(r); + + printf("digraph systemd {\n"); + + while ((r = bus_parse_unit_info(reply, &u)) > 0) { + + r = graph_one(bus, &u, patterns); + if (r < 0) + return r; + } + if (r < 0) + return bus_log_parse_error(r); + + printf("}\n"); + + log_info(" Color legend: black = Requires\n" + " dark blue = Requisite\n" + " dark grey = Wants\n" + " red = Conflicts\n" + " green = After\n"); + + if (on_tty()) + log_notice("-- You probably want to process this output with graphviz' dot tool.\n" + "-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n"); + + return 0; +} + +static int dump(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *text = NULL; + int r; + + if (!strv_isempty(args)) { + log_error("Too many arguments."); + return -E2BIG; + } + + pager_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Dump", + &error, + &reply, + ""); + if (r < 0) { + log_error("Failed issue method call: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &text); + if (r < 0) + return bus_log_parse_error(r); + + fputs(text, stdout); + return 0; +} + +static int set_log_level(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(args); + + if (strv_length(args) != 1) { + log_error("This command expects one argument only."); + return -E2BIG; + } + + r = sd_bus_set_property( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "LogLevel", + &error, + "s", + args[0]); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + return -EIO; + } + + return 0; +} + +static int help(void) { + + pager_open_if_enabled(); + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Process systemd profiling information.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --system Connect to system manager\n" + " --user Connect to user manager\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --order When generating a dependency graph, show only order\n" + " --require When generating a dependency graph, show only requirement\n" + " --from-pattern=GLOB, --to-pattern=GLOB\n" + " When generating a dependency graph, filter only origins\n" + " or destinations, respectively\n" + " --fuzz=TIMESPAN When printing the tree of the critical chain, print also\n" + " services, which finished TIMESPAN earlier, than the\n" + " latest in the branch. The unit of TIMESPAN is seconds\n" + " unless specified with a different unit, i.e. 50ms\n\n" + "Commands:\n" + " time Print time spent in the kernel before reaching userspace\n" + " blame Print list of running units ordered by time to init\n" + " critical-chain Print a tree of the time critical chain of units\n" + " plot Output SVG graphic showing service initialization\n" + " dot Output dependency graph in dot(1) format\n" + " set-log-level LEVEL Set logging threshold for systemd\n" + " dump Output state serialization of service manager\n", + program_invocation_short_name); + + /* When updating this list, including descriptions, apply + * changes to shell-completion/bash/systemd and + * shell-completion/systemd-zsh-completion.zsh too. */ + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_ORDER, + ARG_REQUIRE, + ARG_USER, + ARG_SYSTEM, + ARG_DOT_FROM_PATTERN, + ARG_DOT_TO_PATTERN, + ARG_FUZZ, + ARG_NO_PAGER + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "order", no_argument, NULL, ARG_ORDER }, + { "require", no_argument, NULL, ARG_REQUIRE }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN }, + { "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN }, + { "fuzz", required_argument, NULL, ARG_FUZZ }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + {} + }; + + int r, c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_USER: + arg_user = true; + break; + + case ARG_SYSTEM: + arg_user = false; + break; + + case ARG_ORDER: + arg_dot = DEP_ORDER; + break; + + case ARG_REQUIRE: + arg_dot = DEP_REQUIRE; + break; + + case ARG_DOT_FROM_PATTERN: + if (strv_extend(&arg_dot_from_patterns, optarg) < 0) + return log_oom(); + + break; + + case ARG_DOT_TO_PATTERN: + if (strv_extend(&arg_dot_to_patterns, optarg) < 0) + return log_oom(); + + break; + + case ARG_FUZZ: + r = parse_sec(optarg, &arg_fuzz); + if (r < 0) + return r; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */ + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, arg_user, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + if (!argv[optind] || streq(argv[optind], "time")) + r = analyze_time(bus); + else if (streq(argv[optind], "blame")) + r = analyze_blame(bus); + else if (streq(argv[optind], "critical-chain")) + r = analyze_critical_chain(bus, argv+optind+1); + else if (streq(argv[optind], "plot")) + r = analyze_plot(bus); + else if (streq(argv[optind], "dot")) + r = dot(bus, argv+optind+1); + else if (streq(argv[optind], "dump")) + r = dump(bus, argv+optind+1); + else if (streq(argv[optind], "set-log-level")) + r = set_log_level(bus, argv+optind+1); + else + log_error("Unknown operation '%s'.", argv[optind]); + +finish: + pager_close(); + + strv_free(arg_dot_from_patterns); + strv_free(arg_dot_to_patterns); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/ask-password-api.c b/src/ask-password-api.c deleted file mode 100644 index f57105c..0000000 --- a/src/ask-password-api.c +++ /dev/null @@ -1,576 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" - -#include "ask-password-api.h" - -static void backspace_chars(int ttyfd, size_t p) { - - if (ttyfd < 0) - return; - - while (p > 0) { - p--; - - loop_write(ttyfd, "\b \b", 3, false); - } -} - -int ask_password_tty( - const char *message, - usec_t until, - const char *flag_file, - char **_passphrase) { - - struct termios old_termios, new_termios; - char passphrase[LINE_MAX]; - size_t p = 0; - int r, ttyfd = -1, notify = -1; - struct pollfd pollfd[2]; - bool reset_tty = false; - bool silent_mode = false; - bool dirty = false; - enum { - POLL_TTY, - POLL_INOTIFY - }; - - assert(message); - assert(_passphrase); - - if (flag_file) { - if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { - r = -errno; - goto finish; - } - - if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { - r = -errno; - goto finish; - } - } - - if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) { - - if (tcgetattr(ttyfd, &old_termios) < 0) { - r = -errno; - goto finish; - } - - loop_write(ttyfd, "\x1B[1m", 4, false); - loop_write(ttyfd, message, strlen(message), false); - loop_write(ttyfd, " ", 1, false); - loop_write(ttyfd, "\x1B[0m", 4, false); - - new_termios = old_termios; - new_termios.c_lflag &= ~(ICANON|ECHO); - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) { - r = -errno; - goto finish; - } - - reset_tty = true; - } - - zero(pollfd); - - pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO; - pollfd[POLL_TTY].events = POLLIN; - pollfd[POLL_INOTIFY].fd = notify; - pollfd[POLL_INOTIFY].events = POLLIN; - - for (;;) { - char c; - int sleep_for = -1, k; - ssize_t n; - - if (until > 0) { - usec_t y; - - y = now(CLOCK_MONOTONIC); - - if (y > until) { - r = -ETIME; - goto finish; - } - - sleep_for = (int) ((until - y) / USEC_PER_MSEC); - } - - if (flag_file) - if (access(flag_file, F_OK) < 0) { - r = -errno; - goto finish; - } - - if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - goto finish; - } else if (k == 0) { - r = -ETIME; - goto finish; - } - - if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) - flush_fd(notify); - - if (pollfd[POLL_TTY].revents == 0) - continue; - - if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - r = -errno; - goto finish; - - } else if (n == 0) - break; - - if (c == '\n') - break; - else if (c == 21) { /* C-u */ - - if (!silent_mode) - backspace_chars(ttyfd, p); - p = 0; - - } else if (c == '\b' || c == 127) { - - if (p > 0) { - - if (!silent_mode) - backspace_chars(ttyfd, 1); - - p--; - } else if (!dirty && !silent_mode) { - - silent_mode = true; - - /* There are two ways to enter silent - * mode. Either by pressing backspace - * as first key (and only as first key), - * or ... */ - if (ttyfd >= 0) - loop_write(ttyfd, "(no echo) ", 10, false); - - } else if (ttyfd >= 0) - loop_write(ttyfd, "\a", 1, false); - - } else if (c == '\t' && !silent_mode) { - - backspace_chars(ttyfd, p); - silent_mode = true; - - /* ... or by pressing TAB at any time. */ - - if (ttyfd >= 0) - loop_write(ttyfd, "(no echo) ", 10, false); - } else { - passphrase[p++] = c; - - if (!silent_mode && ttyfd >= 0) - loop_write(ttyfd, "*", 1, false); - - dirty = true; - } - } - - passphrase[p] = 0; - - if (!(*_passphrase = strdup(passphrase))) { - r = -ENOMEM; - goto finish; - } - - r = 0; - -finish: - if (notify >= 0) - close_nointr_nofail(notify); - - if (ttyfd >= 0) { - - if (reset_tty) { - loop_write(ttyfd, "\n", 1, false); - tcsetattr(ttyfd, TCSADRAIN, &old_termios); - } - - close_nointr_nofail(ttyfd); - } - - return r; -} - -static int create_socket(char **name) { - int fd; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - int one = 1, r; - char *c; - mode_t u; - - assert(name); - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("socket() failed: %m"); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%llu", random_ull()); - - u = umask(0177); - r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); - umask(u); - - if (r < 0) { - r = -errno; - log_error("bind() failed: %m"); - goto fail; - } - - if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - r = -errno; - log_error("SO_PASSCRED failed: %m"); - goto fail; - } - - if (!(c = strdup(sa.un.sun_path))) { - r = -ENOMEM; - log_error("Out of memory"); - goto fail; - } - - *name = c; - return fd; - -fail: - close_nointr_nofail(fd); - - return r; -} - -int ask_password_agent( - const char *message, - const char *icon, - usec_t until, - bool accept_cached, - char ***_passphrases) { - - enum { - FD_SOCKET, - FD_SIGNAL, - _FD_MAX - }; - - char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; - char final[sizeof(temp)] = ""; - int fd = -1, r; - FILE *f = NULL; - char *socket_name = NULL; - int socket_fd = -1, signal_fd = -1; - sigset_t mask, oldmask; - struct pollfd pollfd[_FD_MAX]; - mode_t u; - - assert(_passphrases); - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); - - mkdir_p("/run/systemd/ask-password", 0755); - - u = umask(0022); - fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY); - umask(u); - - if (fd < 0) { - log_error("Failed to create password file: %m"); - r = -errno; - goto finish; - } - - fchmod(fd, 0644); - - if (!(f = fdopen(fd, "w"))) { - log_error("Failed to allocate FILE: %m"); - r = -errno; - goto finish; - } - - fd = -1; - - if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - if ((socket_fd = create_socket(&socket_name)) < 0) { - r = socket_fd; - goto finish; - } - - fprintf(f, - "[Ask]\n" - "PID=%lu\n" - "Socket=%s\n" - "AcceptCached=%i\n" - "NotAfter=%llu\n", - (unsigned long) getpid(), - socket_name, - accept_cached ? 1 : 0, - (unsigned long long) until); - - if (message) - fprintf(f, "Message=%s\n", message); - - if (icon) - fprintf(f, "Icon=%s\n", icon); - - fflush(f); - - if (ferror(f)) { - log_error("Failed to write query file: %m"); - r = -errno; - goto finish; - } - - memcpy(final, temp, sizeof(temp)); - - final[sizeof(final)-11] = 'a'; - final[sizeof(final)-10] = 's'; - final[sizeof(final)-9] = 'k'; - - if (rename(temp, final) < 0) { - log_error("Failed to rename query file: %m"); - r = -errno; - goto finish; - } - - zero(pollfd); - pollfd[FD_SOCKET].fd = socket_fd; - pollfd[FD_SOCKET].events = POLLIN; - pollfd[FD_SIGNAL].fd = signal_fd; - pollfd[FD_SIGNAL].events = POLLIN; - - for (;;) { - char passphrase[LINE_MAX+1]; - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - ssize_t n; - int k; - usec_t t; - - t = now(CLOCK_MONOTONIC); - - if (until > 0 && until <= t) { - log_notice("Timed out"); - r = -ETIME; - goto finish; - } - - if ((k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1)) < 0) { - - if (errno == EINTR) - continue; - - log_error("poll() failed: %m"); - r = -errno; - goto finish; - } - - if (k <= 0) { - log_notice("Timed out"); - r = -ETIME; - goto finish; - } - - if (pollfd[FD_SIGNAL].revents & POLLIN) { - r = -EINTR; - goto finish; - } - - if (pollfd[FD_SOCKET].revents != POLLIN) { - log_error("Unexpected poll() event."); - r = -EIO; - goto finish; - } - - zero(iovec); - iovec.iov_base = passphrase; - iovec.iov_len = sizeof(passphrase); - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) { - - if (errno == EAGAIN || - errno == EINTR) - continue; - - log_error("recvmsg() failed: %m"); - r = -errno; - goto finish; - } - - if (n <= 0) { - log_error("Message too short"); - continue; - } - - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - control.cmsghdr.cmsg_level != SOL_SOCKET || - control.cmsghdr.cmsg_type != SCM_CREDENTIALS || - control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received message without credentials. Ignoring."); - continue; - } - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - if (ucred->uid != 0) { - log_warning("Got request from unprivileged user. Ignoring."); - continue; - } - - if (passphrase[0] == '+') { - char **l; - - if (n == 1) - l = strv_new("", NULL); - else - l = strv_parse_nulstr(passphrase+1, n-1); - /* An empty message refers to the empty password */ - - if (!l) { - r = -ENOMEM; - goto finish; - } - - if (strv_length(l) <= 0) { - strv_free(l); - log_error("Invalid packet"); - continue; - } - - *_passphrases = l; - - } else if (passphrase[0] == '-') { - r = -ECANCELED; - goto finish; - } else { - log_error("Invalid packet"); - continue; - } - - break; - } - - r = 0; - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - if (socket_name) { - unlink(socket_name); - free(socket_name); - } - - if (socket_fd >= 0) - close_nointr_nofail(socket_fd); - - if (signal_fd >= 0) - close_nointr_nofail(signal_fd); - - if (f) - fclose(f); - - unlink(temp); - - if (final[0]) - unlink(final); - - assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); - - return r; -} - -int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) { - assert(message); - assert(_passphrases); - - if (isatty(STDIN_FILENO)) { - int r; - char *s = NULL, **l = NULL; - - if ((r = ask_password_tty(message, until, NULL, &s)) < 0) - return r; - - l = strv_new(s, NULL); - free(s); - - if (!l) - return -ENOMEM; - - *_passphrases = l; - return r; - - } else - return ask_password_agent(message, icon, until, accept_cached, _passphrases); -} diff --git a/src/ask-password-api.h b/src/ask-password-api.h deleted file mode 100644 index fec8625..0000000 --- a/src/ask-password-api.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooaskpasswordapihfoo -#define fooaskpasswordapihfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "util.h" - -int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase); - -int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); - -int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); - -#endif diff --git a/src/ask-password.c b/src/ask-password.c deleted file mode 100644 index 5162f62..0000000 --- a/src/ask-password.c +++ /dev/null @@ -1,184 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "macro.h" -#include "util.h" -#include "strv.h" -#include "ask-password-api.h" -#include "def.h" - -static const char *arg_icon = NULL; -static const char *arg_message = NULL; -static bool arg_use_tty = true; -static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; -static bool arg_accept_cached = false; -static bool arg_multiple = false; - -static int help(void) { - - printf("%s [OPTIONS...] MESSAGE\n\n" - "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" - " -h --help Show this help\n" - " --icon=NAME Icon name\n" - " --timeout=SEC Timeout in sec\n" - " --no-tty Ask question via agent even on TTY\n" - " --accept-cached Accept cached passwords\n" - " --multiple List multiple passwords if available\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_ICON = 0x100, - ARG_TIMEOUT, - ARG_NO_TTY, - ARG_ACCEPT_CACHED, - ARG_MULTIPLE - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "icon", required_argument, NULL, ARG_ICON }, - { "timeout", required_argument, NULL, ARG_TIMEOUT }, - { "no-tty", no_argument, NULL, ARG_NO_TTY }, - { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, - { "multiple", no_argument, NULL, ARG_MULTIPLE }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_ICON: - arg_icon = optarg; - break; - - case ARG_TIMEOUT: - if (parse_usec(optarg, &arg_timeout) < 0) { - log_error("Failed to parse --timeout parameter %s", optarg); - return -EINVAL; - } - break; - - case ARG_NO_TTY: - arg_use_tty = false; - break; - - case ARG_ACCEPT_CACHED: - arg_accept_cached = true; - break; - - case ARG_MULTIPLE: - arg_multiple = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind != argc-1) { - help(); - return -EINVAL; - } - - arg_message = argv[optind]; - return 1; -} - -int main(int argc, char *argv[]) { - int r; - usec_t timeout; - - log_parse_environment(); - log_open(); - - if ((r = parse_argv(argc, argv)) <= 0) - goto finish; - - if (arg_timeout > 0) - timeout = now(CLOCK_MONOTONIC) + arg_timeout; - else - timeout = 0; - - if (arg_use_tty && isatty(STDIN_FILENO)) { - char *password = NULL; - - if ((r = ask_password_tty(arg_message, timeout, NULL, &password)) >= 0) { - puts(password); - free(password); - } - - } else { - char **l; - - if ((r = ask_password_agent(arg_message, arg_icon, timeout, arg_accept_cached, &l)) >= 0) { - char **p; - - STRV_FOREACH(p, l) { - puts(*p); - - if (!arg_multiple) - break; - } - - strv_free(l); - } - } - -finish: - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/ask-password/Makefile b/src/ask-password/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/ask-password/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c new file mode 100644 index 0000000..ea0c623 --- /dev/null +++ b/src/ask-password/ask-password.c @@ -0,0 +1,182 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" +#include "strv.h" +#include "ask-password-api.h" +#include "def.h" + +static const char *arg_icon = NULL; +static const char *arg_message = NULL; +static bool arg_use_tty = true; +static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; +static bool arg_accept_cached = false; +static bool arg_multiple = false; + +static int help(void) { + + printf("%s [OPTIONS...] MESSAGE\n\n" + "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" + " -h --help Show this help\n" + " --icon=NAME Icon name\n" + " --timeout=SEC Timeout in sec\n" + " --no-tty Ask question via agent even on TTY\n" + " --accept-cached Accept cached passwords\n" + " --multiple List multiple passwords if available\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_ICON = 0x100, + ARG_TIMEOUT, + ARG_NO_TTY, + ARG_ACCEPT_CACHED, + ARG_MULTIPLE + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "icon", required_argument, NULL, ARG_ICON }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, + { "no-tty", no_argument, NULL, ARG_NO_TTY }, + { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, + { "multiple", no_argument, NULL, ARG_MULTIPLE }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_ICON: + arg_icon = optarg; + break; + + case ARG_TIMEOUT: + if (parse_sec(optarg, &arg_timeout) < 0) { + log_error("Failed to parse --timeout parameter %s", optarg); + return -EINVAL; + } + break; + + case ARG_NO_TTY: + arg_use_tty = false; + break; + + case ARG_ACCEPT_CACHED: + arg_accept_cached = true; + break; + + case ARG_MULTIPLE: + arg_multiple = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind != argc-1) { + help(); + return -EINVAL; + } + + arg_message = argv[optind]; + return 1; +} + +int main(int argc, char *argv[]) { + int r; + usec_t timeout; + + log_parse_environment(); + log_open(); + + if ((r = parse_argv(argc, argv)) <= 0) + goto finish; + + if (arg_timeout > 0) + timeout = now(CLOCK_MONOTONIC) + arg_timeout; + else + timeout = 0; + + if (arg_use_tty && isatty(STDIN_FILENO)) { + char *password = NULL; + + if ((r = ask_password_tty(arg_message, timeout, NULL, &password)) >= 0) { + puts(password); + free(password); + } + + } else { + char **l; + + if ((r = ask_password_agent(arg_message, arg_icon, timeout, arg_accept_cached, &l)) >= 0) { + char **p; + + STRV_FOREACH(p, l) { + puts(*p); + + if (!arg_multiple) + break; + } + + strv_free(l); + } + } + +finish: + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/automount.c b/src/automount.c deleted file mode 100644 index 29b807d..0000000 --- a/src/automount.c +++ /dev/null @@ -1,869 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "unit.h" -#include "automount.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "unit-name.h" -#include "dbus-automount.h" -#include "bus-errors.h" -#include "special.h" -#include "label.h" - -static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { - [AUTOMOUNT_DEAD] = UNIT_INACTIVE, - [AUTOMOUNT_WAITING] = UNIT_ACTIVE, - [AUTOMOUNT_RUNNING] = UNIT_ACTIVE, - [AUTOMOUNT_FAILED] = UNIT_FAILED -}; - -static int open_dev_autofs(Manager *m); - -static void automount_init(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - a->pipe_watch.fd = a->pipe_fd = -1; - a->pipe_watch.type = WATCH_INVALID; - - a->directory_mode = 0755; - - a->meta.ignore_on_isolate = true; -} - -static void repeat_unmout(const char *path) { - assert(path); - - for (;;) { - /* If there are multiple mounts on a mount point, this - * removes them all */ - - if (umount2(path, MNT_DETACH) >= 0) - continue; - - if (errno != EINVAL) - log_error("Failed to unmount: %m"); - - break; - } -} - -static void unmount_autofs(Automount *a) { - assert(a); - - if (a->pipe_fd < 0) - return; - - automount_send_ready(a, -EHOSTDOWN); - - unit_unwatch_fd(UNIT(a), &a->pipe_watch); - close_nointr_nofail(a->pipe_fd); - a->pipe_fd = -1; - - /* If we reload/reexecute things we keep the mount point - * around */ - if (a->where && - (a->meta.manager->exit_code != MANAGER_RELOAD && - a->meta.manager->exit_code != MANAGER_REEXECUTE)) - repeat_unmout(a->where); -} - -static void automount_done(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - unmount_autofs(a); - a->mount = NULL; - - free(a->where); - a->where = NULL; - - set_free(a->tokens); - a->tokens = NULL; -} - -int automount_add_one_mount_link(Automount *a, Mount *m) { - int r; - - assert(a); - assert(m); - - if (a->meta.load_state != UNIT_LOADED || - m->meta.load_state != UNIT_LOADED) - return 0; - - if (!path_startswith(a->where, m->where)) - return 0; - - if (path_equal(a->where, m->where)) - return 0; - - if ((r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - - return 0; -} - -static int automount_add_mount_links(Automount *a) { - Meta *other; - int r; - - assert(a); - - LIST_FOREACH(units_by_type, other, a->meta.manager->units_by_type[UNIT_MOUNT]) - if ((r = automount_add_one_mount_link(a, (Mount*) other)) < 0) - return r; - - return 0; -} - -static int automount_add_default_dependencies(Automount *a) { - int r; - - assert(a); - - if (a->meta.manager->running_as == MANAGER_SYSTEM) { - - if ((r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0) - return r; - - if ((r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0) - return r; - } - - return 0; -} - -static int automount_verify(Automount *a) { - bool b; - char *e; - assert(a); - - if (a->meta.load_state != UNIT_LOADED) - return 0; - - if (path_equal(a->where, "/")) { - log_error("Cannot have an automount unit for the root directory. Refusing."); - return -EINVAL; - } - - if (!(e = unit_name_from_path(a->where, ".automount"))) - return -ENOMEM; - - b = unit_has_name(UNIT(a), e); - free(e); - - if (!b) { - log_error("%s's Where setting doesn't match unit name. Refusing.", a->meta.id); - return -EINVAL; - } - - return 0; -} - -static int automount_load(Unit *u) { - int r; - Automount *a = AUTOMOUNT(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - /* Load a .automount file */ - if ((r = unit_load_fragment_and_dropin_optional(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_LOADED) { - - if (!a->where) - if (!(a->where = unit_name_to_path(u->meta.id))) - return -ENOMEM; - - path_kill_slashes(a->where); - - if ((r = automount_add_mount_links(a)) < 0) - return r; - - if ((r = unit_load_related_unit(u, ".mount", (Unit**) &a->mount)) < 0) - return r; - - if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(a->mount), true)) < 0) - return r; - - if (a->meta.default_dependencies) - if ((r = automount_add_default_dependencies(a)) < 0) - return r; - } - - return automount_verify(a); -} - -static void automount_set_state(Automount *a, AutomountState state) { - AutomountState old_state; - assert(a); - - old_state = a->state; - a->state = state; - - if (state != AUTOMOUNT_WAITING && - state != AUTOMOUNT_RUNNING) - unmount_autofs(a); - - if (state != old_state) - log_debug("%s changed %s -> %s", - a->meta.id, - automount_state_to_string(old_state), - automount_state_to_string(state)); - - unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true); -} - -static int automount_coldplug(Unit *u) { - Automount *a = AUTOMOUNT(u); - int r; - - assert(a); - assert(a->state == AUTOMOUNT_DEAD); - - if (a->deserialized_state != a->state) { - - if ((r = open_dev_autofs(u->meta.manager)) < 0) - return r; - - if (a->deserialized_state == AUTOMOUNT_WAITING || - a->deserialized_state == AUTOMOUNT_RUNNING) { - - assert(a->pipe_fd >= 0); - - if ((r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch)) < 0) - return r; - } - - automount_set_state(a, a->deserialized_state); - } - - return 0; -} - -static void automount_dump(Unit *u, FILE *f, const char *prefix) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - fprintf(f, - "%sAutomount State: %s\n" - "%sWhere: %s\n" - "%sDirectoryMode: %04o\n", - prefix, automount_state_to_string(a->state), - prefix, a->where, - prefix, a->directory_mode); -} - -static void automount_enter_dead(Automount *a, bool success) { - assert(a); - - if (!success) - a->failure = true; - - automount_set_state(a, a->failure ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD); -} - -static int open_dev_autofs(Manager *m) { - struct autofs_dev_ioctl param; - - assert(m); - - if (m->dev_autofs_fd >= 0) - return m->dev_autofs_fd; - - label_fix("/dev/autofs", false); - - if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) { - log_error("Failed to open /dev/autofs: %s", strerror(errno)); - return -errno; - } - - init_autofs_dev_ioctl(¶m); - if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, ¶m) < 0) { - close_nointr_nofail(m->dev_autofs_fd); - m->dev_autofs_fd = -1; - return -errno; - } - - log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor); - - return m->dev_autofs_fd; -} - -static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) { - struct autofs_dev_ioctl *param; - size_t l; - int r; - - assert(dev_autofs_fd >= 0); - assert(where); - - l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1; - - if (!(param = malloc(l))) - return -ENOMEM; - - init_autofs_dev_ioctl(param); - param->size = l; - param->ioctlfd = -1; - param->openmount.devid = devid; - strcpy(param->path, where); - - if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) { - r = -errno; - goto finish; - } - - if (param->ioctlfd < 0) { - r = -EIO; - goto finish; - } - - fd_cloexec(param->ioctlfd, true); - r = param->ioctlfd; - -finish: - free(param); - return r; -} - -static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) { - uint32_t major, minor; - struct autofs_dev_ioctl param; - - assert(dev_autofs_fd >= 0); - assert(ioctl_fd >= 0); - - init_autofs_dev_ioctl(¶m); - param.ioctlfd = ioctl_fd; - - if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, ¶m) < 0) - return -errno; - - major = param.protover.version; - - init_autofs_dev_ioctl(¶m); - param.ioctlfd = ioctl_fd; - - if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, ¶m) < 0) - return -errno; - - minor = param.protosubver.sub_version; - - log_debug("Autofs protocol version %i.%i", major, minor); - return 0; -} - -static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) { - struct autofs_dev_ioctl param; - - assert(dev_autofs_fd >= 0); - assert(ioctl_fd >= 0); - - init_autofs_dev_ioctl(¶m); - param.ioctlfd = ioctl_fd; - param.timeout.timeout = sec; - - if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) < 0) - return -errno; - - return 0; -} - -static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) { - struct autofs_dev_ioctl param; - - assert(dev_autofs_fd >= 0); - assert(ioctl_fd >= 0); - - init_autofs_dev_ioctl(¶m); - param.ioctlfd = ioctl_fd; - - if (status) { - param.fail.token = token; - param.fail.status = status; - } else - param.ready.token = token; - - if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, ¶m) < 0) - return -errno; - - return 0; -} - -int automount_send_ready(Automount *a, int status) { - int ioctl_fd, r; - unsigned token; - - assert(a); - assert(status <= 0); - - if (set_isempty(a->tokens)) - return 0; - - if ((ioctl_fd = open_ioctl_fd(a->meta.manager->dev_autofs_fd, a->where, a->dev_id)) < 0) { - r = ioctl_fd; - goto fail; - } - - if (status) - log_debug("Sending failure: %s", strerror(-status)); - else - log_debug("Sending success."); - - r = 0; - - /* Autofs thankfully does not hand out 0 as a token */ - while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) { - int k; - - /* Autofs fun fact II: - * - * if you pass a positive status code here, the kernel will - * freeze! Yay! */ - - if ((k = autofs_send_ready(a->meta.manager->dev_autofs_fd, - ioctl_fd, - token, - status)) < 0) - r = k; - } - -fail: - if (ioctl_fd >= 0) - close_nointr_nofail(ioctl_fd); - - return r; -} - -static void automount_enter_waiting(Automount *a) { - int p[2] = { -1, -1 }; - char name[32], options[128]; - bool mounted = false; - int r, ioctl_fd = -1, dev_autofs_fd; - struct stat st; - - assert(a); - assert(a->pipe_fd < 0); - assert(a->where); - - if (a->tokens) - set_clear(a->tokens); - - if ((dev_autofs_fd = open_dev_autofs(a->meta.manager)) < 0) { - r = dev_autofs_fd; - goto fail; - } - - /* We knowingly ignore the results of this call */ - mkdir_p(a->where, 0555); - - if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) { - r = -errno; - goto fail; - } - - snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp()); - char_array_0(options); - - snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid()); - char_array_0(name); - - if (mount(name, a->where, "autofs", 0, options) < 0) { - r = -errno; - goto fail; - } - - mounted = true; - - close_nointr_nofail(p[1]); - p[1] = -1; - - if (stat(a->where, &st) < 0) { - r = -errno; - goto fail; - } - - if ((ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev)) < 0) { - r = ioctl_fd; - goto fail; - } - - if ((r = autofs_protocol(dev_autofs_fd, ioctl_fd)) < 0) - goto fail; - - if ((r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300)) < 0) - goto fail; - - /* Autofs fun fact: - * - * Unless we close the ioctl fd here, for some weird reason - * the direct mount will not receive events from the - * kernel. */ - - close_nointr_nofail(ioctl_fd); - ioctl_fd = -1; - - if ((r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch)) < 0) - goto fail; - - a->pipe_fd = p[0]; - a->dev_id = st.st_dev; - - automount_set_state(a, AUTOMOUNT_WAITING); - - return; - -fail: - assert_se(close_pipe(p) == 0); - - if (ioctl_fd >= 0) - close_nointr_nofail(ioctl_fd); - - if (mounted) - repeat_unmout(a->where); - - log_error("Failed to initialize automounter: %s", strerror(-r)); - automount_enter_dead(a, false); -} - -static void automount_enter_runnning(Automount *a) { - int r; - struct stat st; - DBusError error; - - assert(a); - assert(a->mount); - - dbus_error_init(&error); - - /* We don't take mount requests anymore if we are supposed to - * shut down anyway */ - if (unit_pending_inactive(UNIT(a))) { - log_debug("Suppressing automount request on %s since unit stop is scheduled.", a->meta.id); - automount_send_ready(a, -EHOSTDOWN); - return; - } - - mkdir_p(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) { - log_warning("%s failed to stat automount point: %m", a->meta.id); - goto fail; - } - - if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) - log_info("%s's automount point already active?", a->meta.id); - else if ((r = manager_add_job(a->meta.manager, JOB_START, UNIT(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) { - log_warning("%s failed to queue mount startup job: %s", a->meta.id, bus_error(&error, r)); - goto fail; - } - - automount_set_state(a, AUTOMOUNT_RUNNING); - return; - -fail: - automount_enter_dead(a, false); - dbus_error_free(&error); -} - -static int automount_start(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); - - if (path_is_mount_point(a->where, false)) { - log_error("Path %s is already a mount point, refusing start for %s", a->where, u->meta.id); - return -EEXIST; - } - - if (a->mount->meta.load_state != UNIT_LOADED) - return -ENOENT; - - a->failure = false; - automount_enter_waiting(a); - return 0; -} - -static int automount_stop(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING); - - automount_enter_dead(a, true); - return 0; -} - -static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { - Automount *a = AUTOMOUNT(u); - void *p; - Iterator i; - - assert(a); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", automount_state_to_string(a->state)); - unit_serialize_item(u, f, "failure", yes_no(a->failure)); - unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id); - - SET_FOREACH(p, a->tokens, i) - unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p)); - - if (a->pipe_fd >= 0) { - int copy; - - if ((copy = fdset_put_dup(fds, a->pipe_fd)) < 0) - return copy; - - unit_serialize_item_format(u, f, "pipe-fd", "%i", copy); - } - - return 0; -} - -static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Automount *a = AUTOMOUNT(u); - int r; - - assert(a); - assert(fds); - - if (streq(key, "state")) { - AutomountState state; - - if ((state = automount_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - a->deserialized_state = state; - } else if (streq(key, "failure")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse failure value %s", value); - else - a->failure = b || a->failure; - } else if (streq(key, "dev-id")) { - unsigned d; - - if (safe_atou(value, &d) < 0) - log_debug("Failed to parse dev-id value %s", value); - else - a->dev_id = (unsigned) d; - } else if (streq(key, "token")) { - unsigned token; - - if (safe_atou(value, &token) < 0) - log_debug("Failed to parse token value %s", value); - else { - if (!a->tokens) - if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - if ((r = set_put(a->tokens, UINT_TO_PTR(token))) < 0) - return r; - } - } else if (streq(key, "pipe-fd")) { - int fd; - - if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse pipe-fd value %s", value); - else { - if (a->pipe_fd >= 0) - close_nointr_nofail(a->pipe_fd); - - a->pipe_fd = fdset_remove(fds, fd); - } - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState automount_active_state(Unit *u) { - assert(u); - - return state_translation_table[AUTOMOUNT(u)->state]; -} - -static const char *automount_sub_state_to_string(Unit *u) { - assert(u); - - return automount_state_to_string(AUTOMOUNT(u)->state); -} - -static bool automount_check_gc(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - if (!a->mount) - return false; - - return UNIT_VTABLE(UNIT(a->mount))->check_gc(UNIT(a->mount)); -} - -static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Automount *a = AUTOMOUNT(u); - union autofs_v5_packet_union packet; - ssize_t l; - int r; - - assert(a); - assert(fd == a->pipe_fd); - - if (events != EPOLLIN) { - log_error("Got invalid poll event on pipe."); - goto fail; - } - - if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet), true)) != sizeof(packet)) { - log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); - goto fail; - } - - switch (packet.hdr.type) { - - case autofs_ptype_missing_direct: - - if (packet.v5_packet.pid > 0) { - char *p = NULL; - - get_process_name(packet.v5_packet.pid, &p); - log_debug("Got direct mount request for %s, triggered by %lu (%s)", packet.v5_packet.name, (unsigned long) packet.v5_packet.pid, strna(p)); - free(p); - - } else - log_debug("Got direct mount request for %s", packet.v5_packet.name); - - if (!a->tokens) - if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) { - log_error("Failed to allocate token set."); - goto fail; - } - - if ((r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token))) < 0) { - log_error("Failed to remember token: %s", strerror(-r)); - goto fail; - } - - automount_enter_runnning(a); - break; - - default: - log_error("Received unknown automount request %i", packet.hdr.type); - break; - } - - return; - -fail: - automount_enter_dead(a, false); -} - -static void automount_shutdown(Manager *m) { - assert(m); - - if (m->dev_autofs_fd >= 0) - close_nointr_nofail(m->dev_autofs_fd); -} - -static void automount_reset_failed(Unit *u) { - Automount *a = AUTOMOUNT(u); - - assert(a); - - if (a->state == AUTOMOUNT_FAILED) - automount_set_state(a, AUTOMOUNT_DEAD); - - a->failure = false; -} - -static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { - [AUTOMOUNT_DEAD] = "dead", - [AUTOMOUNT_WAITING] = "waiting", - [AUTOMOUNT_RUNNING] = "running", - [AUTOMOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); - -const UnitVTable automount_vtable = { - .suffix = ".automount", - .sections = - "Unit\0" - "Automount\0" - "Install\0", - - .no_alias = true, - .no_instances = true, - - .init = automount_init, - .load = automount_load, - .done = automount_done, - - .coldplug = automount_coldplug, - - .dump = automount_dump, - - .start = automount_start, - .stop = automount_stop, - - .serialize = automount_serialize, - .deserialize_item = automount_deserialize_item, - - .active_state = automount_active_state, - .sub_state_to_string = automount_sub_state_to_string, - - .check_gc = automount_check_gc, - - .fd_event = automount_fd_event, - - .reset_failed = automount_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Automount", - .bus_message_handler = bus_automount_message_handler, - - .shutdown = automount_shutdown -}; diff --git a/src/automount.h b/src/automount.h deleted file mode 100644 index 1a6cc98..0000000 --- a/src/automount.h +++ /dev/null @@ -1,67 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooautomounthfoo -#define fooautomounthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Automount Automount; - -#include "unit.h" - -typedef enum AutomountState { - AUTOMOUNT_DEAD, - AUTOMOUNT_WAITING, - AUTOMOUNT_RUNNING, - AUTOMOUNT_FAILED, - _AUTOMOUNT_STATE_MAX, - _AUTOMOUNT_STATE_INVALID = -1 -} AutomountState; - -struct Automount { - Meta meta; - - AutomountState state, deserialized_state; - - char *where; - - Mount *mount; - - int pipe_fd; - mode_t directory_mode; - Watch pipe_watch; - dev_t dev_id; - - - Set *tokens; - - bool failure:1; -}; - -extern const UnitVTable automount_vtable; - -int automount_send_ready(Automount *a, int status); - -int automount_add_one_mount_link(Automount *a, Mount *m); - -const char* automount_state_to_string(AutomountState i); -AutomountState automount_state_from_string(const char *s); - -#endif diff --git a/src/backlight/Makefile b/src/backlight/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/backlight/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c new file mode 100644 index 0000000..86f10cc --- /dev/null +++ b/src/backlight/backlight.c @@ -0,0 +1,341 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "mkdir.h" +#include "fileio.h" +#include "libudev.h" +#include "udev-util.h" + +static struct udev_device *find_pci_or_platform_parent(struct udev_device *device) { + struct udev_device *parent; + const char *subsystem, *sysname; + + assert(device); + + parent = udev_device_get_parent(device); + if (!parent) + return NULL; + + subsystem = udev_device_get_subsystem(parent); + if (!subsystem) + return NULL; + + sysname = udev_device_get_sysname(parent); + if (!sysname) + return NULL; + + if (streq(subsystem, "drm")) { + const char *c; + + c = startswith(sysname, "card"); + if (!c) + return NULL; + + c += strspn(c, "0123456789"); + if (*c == '-') { + /* A connector DRM device, let's ignore all but LVDS and eDP! */ + + if (!startswith(c, "-LVDS-") && + !startswith(c, "-Embedded DisplayPort-")) + return NULL; + } + + } else if (streq(subsystem, "pci")) { + const char *value; + + value = udev_device_get_sysattr_value(parent, "class"); + if (value) { + unsigned long class = 0; + + if (safe_atolu(value, &class) < 0) { + log_warning("Cannot parse PCI class %s of device %s:%s.", value, subsystem, sysname); + return NULL; + } + + /* Graphics card */ + if (class == 0x30000) + return parent; + } + + } else if (streq(subsystem, "platform")) + return parent; + + return find_pci_or_platform_parent(parent); +} + +static bool same_device(struct udev_device *a, struct udev_device *b) { + assert(a); + assert(b); + + if (!streq_ptr(udev_device_get_subsystem(a), udev_device_get_subsystem(b))) + return false; + + if (!streq_ptr(udev_device_get_sysname(a), udev_device_get_sysname(b))) + return false; + + return true; +} + +static bool validate_device(struct udev *udev, struct udev_device *device) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *enumerate = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + struct udev_device *parent; + const char *v, *subsystem; + int r; + + assert(udev); + assert(device); + + /* Verify whether we should actually care for a specific + * backlight device. For backlight devices there might be + * multiple ways to access the same control: "firmware" + * (i.e. ACPI), "platform" (i.e. via the machine's EC) and + * "raw" (via the graphics card). In general we should prefer + * "firmware" (i.e. ACPI) or "platform" access over "raw" + * access, in order not to confuse the BIOS/EC, and + * compatibility with possible low-level hotkey handling of + * screen brightness. The kernel will already make sure to + * expose only one of "firmware" and "platform" for the same + * device to userspace. However, we still need to make sure + * that we use "raw" only if no "firmware" or "platform" + * device for the same device exists. */ + + subsystem = udev_device_get_subsystem(device); + if (!streq_ptr(subsystem, "backlight")) + return true; + + v = udev_device_get_sysattr_value(device, "type"); + if (!streq_ptr(v, "raw")) + return true; + + parent = find_pci_or_platform_parent(device); + if (!parent) + return true; + + subsystem = udev_device_get_subsystem(parent); + if (!subsystem) + return true; + + enumerate = udev_enumerate_new(udev); + if (!enumerate) + return true; + + r = udev_enumerate_add_match_subsystem(enumerate, "backlight"); + if (r < 0) + return true; + + r = udev_enumerate_scan_devices(enumerate); + if (r < 0) + return true; + + first = udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *other; + struct udev_device *other_parent; + const char *other_subsystem; + + other = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); + if (!other) + return true; + + if (same_device(device, other)) + continue; + + v = udev_device_get_sysattr_value(other, "type"); + if (!streq_ptr(v, "platform") && !streq_ptr(v, "firmware")) + continue; + + /* OK, so there's another backlight device, and it's a + * platform or firmware device, so, let's see if we + * can verify it belongs to the same device as + * ours. */ + other_parent = find_pci_or_platform_parent(other); + if (!other_parent) + continue; + + if (same_device(parent, other_parent)) { + /* Both have the same PCI parent, that means + * we are out. */ + log_debug("Skipping backlight device %s, since backlight device %s is on same PCI device and, takes precedence.", udev_device_get_sysname(device), udev_device_get_sysname(other)); + return false; + } + + other_subsystem = udev_device_get_subsystem(other_parent); + if (streq_ptr(other_subsystem, "platform") && streq_ptr(subsystem, "pci")) { + /* The other is connected to the platform bus + * and we are a PCI device, that also means we + * are out. */ + log_debug("Skipping backlight device %s, since backlight device %s is a platform device and takes precedence.", udev_device_get_sysname(device), udev_device_get_sysname(other)); + return false; + } + } + + return true; +} + +int main(int argc, char *argv[]) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + _cleanup_free_ char *saved = NULL, *ss = NULL, *escaped_ss = NULL, *escaped_sysname = NULL, *escaped_path_id = NULL; + const char *sysname, *path_id; + int r; + + if (argc != 3) { + log_error("This program requires two arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + r = mkdir_p("/var/lib/systemd/backlight", 0755); + if (r < 0) { + log_error("Failed to create backlight directory: %s", strerror(-r)); + return EXIT_FAILURE; + } + + udev = udev_new(); + if (!udev) { + log_oom(); + return EXIT_FAILURE; + } + + sysname = strchr(argv[2], ':'); + if (!sysname) { + log_error("Requires pair of subsystem and sysname for specifying backlight device."); + return EXIT_FAILURE; + } + + ss = strndup(argv[2], sysname - argv[2]); + if (!ss) { + log_oom(); + return EXIT_FAILURE; + } + + sysname++; + + if (!streq(ss, "backlight") && !streq(ss, "leds")) { + log_error("Not a backlight or LED device: '%s:%s'", ss, sysname); + return EXIT_FAILURE; + } + + errno = 0; + device = udev_device_new_from_subsystem_sysname(udev, ss, sysname); + if (!device) { + if (errno != 0) + log_error("Failed to get backlight or LED device '%s:%s': %m", ss, sysname); + else + log_oom(); + + return EXIT_FAILURE; + } + + escaped_ss = cescape(ss); + if (!escaped_ss) { + log_oom(); + return EXIT_FAILURE; + } + + escaped_sysname = cescape(sysname); + if (!escaped_sysname) { + log_oom(); + return EXIT_FAILURE; + } + + path_id = udev_device_get_property_value(device, "ID_PATH"); + if (path_id) { + escaped_path_id = cescape(path_id); + if (!escaped_path_id) { + log_oom(); + return EXIT_FAILURE; + } + + saved = strjoin("/var/lib/systemd/backlight/", escaped_path_id, ":", escaped_ss, ":", escaped_sysname, NULL); + } else + saved = strjoin("/var/lib/systemd/backlight/", escaped_ss, ":", escaped_sysname, NULL); + + if (!saved) { + log_oom(); + return EXIT_FAILURE; + } + + /* If there are multiple conflicting backlight devices, then + * their probing at boot-time might happen in any order. This + * means the validity checking of the device then is not + * reliable, since it might not see other devices conflicting + * with a specific backlight. To deal with this, we will + * actively delete backlight state files at shutdown (where + * device probing should be complete), so that the validity + * check at boot time doesn't have to be reliable. */ + + if (streq(argv[1], "load") && shall_restore_state()) { + _cleanup_free_ char *value = NULL; + + if (!validate_device(udev, device)) + return EXIT_SUCCESS; + + r = read_one_line_file(saved, &value); + if (r < 0) { + + if (r == -ENOENT) + return EXIT_SUCCESS; + + log_error("Failed to read %s: %s", saved, strerror(-r)); + return EXIT_FAILURE; + } + + r = udev_device_set_sysattr_value(device, "brightness", value); + if (r < 0) { + log_error("Failed to write system attribute: %s", strerror(-r)); + return EXIT_FAILURE; + } + + } else if (streq(argv[1], "save")) { + const char *value; + + if (!validate_device(udev, device)) { + unlink(saved); + return EXIT_SUCCESS; + } + + value = udev_device_get_sysattr_value(device, "brightness"); + if (!value) { + log_error("Failed to read system attribute: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = write_string_file(saved, value); + if (r < 0) { + log_error("Failed to write %s: %s", saved, strerror(-r)); + return EXIT_FAILURE; + } + + } else { + log_error("Unknown verb %s.", argv[1]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/binfmt.c b/src/binfmt.c deleted file mode 100644 index e8d6524..0000000 --- a/src/binfmt.c +++ /dev/null @@ -1,164 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "hashmap.h" -#include "strv.h" -#include "util.h" - -static int delete_rule(const char *rule) { - char *x, *fn = NULL, *e; - int r; - - assert(rule[0]); - - if (!(x = strdup(rule))) - return -ENOMEM; - - e = strchrnul(x+1, x[0]); - *e = 0; - - asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1); - free(x); - - if (!fn) - return -ENOMEM; - - r = write_one_line_file(fn, "-1"); - free(fn); - - return r; -} - -static int apply_rule(const char *rule) { - int r; - - delete_rule(rule); - - if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) { - log_error("Failed to add binary format: %s", strerror(-r)); - return r; - } - - return 0; -} - -static int apply_file(const char *path, bool ignore_enoent) { - FILE *f; - int r = 0; - - assert(path); - - if (!(f = fopen(path, "re"))) { - if (ignore_enoent && errno == ENOENT) - return 0; - - log_error("Failed to open file '%s', ignoring: %m", path); - return -errno; - } - - log_debug("apply: %s\n", path); - while (!feof(f)) { - char l[LINE_MAX], *p; - int k; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - log_error("Failed to read file '%s', ignoring: %m", path); - r = -errno; - goto finish; - } - - p = strstrip(l); - - if (!*p) - continue; - - if (strchr(COMMENTS, *p)) - continue; - - if ((k = apply_rule(p)) < 0 && r == 0) - r = k; - } - -finish: - fclose(f); - - return r; -} - -int main(int argc, char *argv[]) { - int r = 0; - - if (argc > 2) { - log_error("This program expects one or no arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc > 1) { - r = apply_file(argv[1], false); - } else { - char **files, **f; - - /* Flush out all rules */ - write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1"); - - r = conf_files_list(&files, ".conf", - "/run/binfmt.d", - "/etc/binfmt.d", - "/usr/local/lib/binfmt.d", - "/usr/lib/binfmt.d", - NULL); - - if (r < 0) { - log_error("Failed to enumerate binfmt.d files: %s", strerror(-r)); - goto finish; - } - - STRV_FOREACH(f, files) { - int k; - - k = apply_file(*f, true); - if (k < 0 && r == 0) - r = k; - } - - strv_free(files); - } -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/binfmt/Makefile b/src/binfmt/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/binfmt/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c new file mode 100644 index 0000000..a1877c4 --- /dev/null +++ b/src/binfmt/binfmt.c @@ -0,0 +1,221 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "hashmap.h" +#include "strv.h" +#include "util.h" +#include "conf-files.h" +#include "fileio.h" +#include "build.h" + +static const char conf_file_dirs[] = + "/etc/binfmt.d\0" + "/run/binfmt.d\0" + "/usr/local/lib/binfmt.d\0" + "/usr/lib/binfmt.d\0" +#ifdef HAVE_SPLIT_USR + "/lib/binfmt.d\0" +#endif + ; + +static int delete_rule(const char *rule) { + _cleanup_free_ char *x = NULL, *fn = NULL; + char *e; + + assert(rule[0]); + + x = strdup(rule); + if (!x) + return log_oom(); + + e = strchrnul(x+1, x[0]); + *e = 0; + + fn = strappend("/proc/sys/fs/binfmt_misc/", x+1); + if (!fn) + return log_oom(); + + return write_string_file(fn, "-1"); +} + +static int apply_rule(const char *rule) { + int r; + + delete_rule(rule); + + r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule); + if (r < 0) { + log_error("Failed to add binary format: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int apply_file(const char *path, bool ignore_enoent) { + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(path); + + r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f); + if (r < 0) { + if (ignore_enoent && r == -ENOENT) + return 0; + + log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r)); + return r; + } + + log_debug("apply: %s", path); + for (;;) { + char l[LINE_MAX], *p; + int k; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + log_error("Failed to read file '%s', ignoring: %m", path); + return -errno; + } + + p = strstrip(l); + if (!*p) + continue; + if (strchr(COMMENTS "\n", *p)) + continue; + + k = apply_rule(p); + if (k < 0 && r == 0) + r = k; + } + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" + "Registers binary formats.\n\n" + " -h --help Show this help\n" + " --version Show package version\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r, k; + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + r = 0; + + if (argc > optind) { + int i; + + for (i = optind; i < argc; i++) { + k = apply_file(argv[i], false); + if (k < 0 && r == 0) + r = k; + } + } else { + _cleanup_strv_free_ char **files = NULL; + char **f; + + r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); + if (r < 0) { + log_error("Failed to enumerate binfmt.d files: %s", strerror(-r)); + goto finish; + } + + /* Flush out all rules */ + write_string_file("/proc/sys/fs/binfmt_misc/status", "-1"); + + STRV_FOREACH(f, files) { + k = apply_file(*f, true); + if (k < 0 && r == 0) + r = k; + } + } + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/boot/Makefile b/src/boot/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/boot/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/boot/boot-efi.c b/src/boot/boot-efi.c new file mode 100644 index 0000000..bd0c59b --- /dev/null +++ b/src/boot/boot-efi.c @@ -0,0 +1,190 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "boot.h" +#include "boot-loader.h" +#include "build.h" +#include "util.h" +#include "strv.h" +#include "efivars.h" +#include "conf-files.h" + +static char *tilt_slashes(char *s) { + char *p; + + if (!s) + return NULL; + + for (p = s; *p; p++) + if (*p == '\\') + *p = '/'; + return s; +} + +static int get_boot_entries(struct boot_info *info) { + uint16_t *list = NULL; + int i, n; + int err = 0; + + n = efi_get_boot_options(&list); + if (n < 0) + return n; + + for (i = 0; i < n; i++) { + struct boot_info_entry *e; + + e = realloc(info->fw_entries, (info->fw_entries_count+1) * sizeof(struct boot_info_entry)); + if (!e) { + err = -ENOMEM; + break; + } + info->fw_entries = e; + + e = &info->fw_entries[info->fw_entries_count]; + memzero(e, sizeof(struct boot_info_entry)); + e->order = -1; + + err = efi_get_boot_option(list[i], &e->title, &e->part_uuid, &e->path); + if (err < 0) + continue; + + if (isempty(e->title)) { + free(e->title); + e->title = NULL; + } + tilt_slashes(e->path); + + e->id = list[i]; + info->fw_entries_count++; + } + + free(list); + return err; +} + +static int find_active_entry(struct boot_info *info) { + uint16_t boot_cur; + void *buf; + size_t l; + size_t i; + int err; + + err = efi_get_variable(EFI_VENDOR_GLOBAL, "BootCurrent", NULL, &buf, &l); + if (err < 0) + return err; + + memcpy(&boot_cur, buf, sizeof(uint16_t)); + for (i = 0; i < info->fw_entries_count; i++) { + if (info->fw_entries[i].id != boot_cur) + continue; + info->fw_entry_active = i; + err = 0; + break; + } + free(buf); + return err; +} + +static int get_boot_order(struct boot_info *info) { + size_t i, k; + int r; + + r = efi_get_boot_order(&info->fw_entries_order); + if (r < 0) + return r; + + info->fw_entries_order_count = r; + + for (i = 0; i < info->fw_entries_order_count; i++) { + for (k = 0; k < info->fw_entries_count; k++) { + if (info->fw_entries[k].id != info->fw_entries_order[i]) + continue; + info->fw_entries[k].order = i; + break; + } + } + + return 0; +} + +static int entry_cmp(const void *a, const void *b) { + const struct boot_info_entry *e1 = a; + const struct boot_info_entry *e2 = b; + + /* boot order of active entries */ + if (e1->order > 0 && e2->order > 0) + return e1->order - e2->order; + + /* sort active entries before inactive ones */ + if (e1->order > 0) + return 1; + if (e2->order > 0) + return -1; + + /* order of inactive entries */ + return e1->id - e2->id; +} + +int boot_info_query(struct boot_info *info) { + char str[64]; + char buf[64]; + char *loader_active = NULL; + + info->fw_secure_boot = is_efi_secure_boot(); + info->fw_secure_boot_setup_mode = is_efi_secure_boot_setup_mode(); + + efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info->loader); + + get_boot_entries(info); + if (info->fw_entries_count > 0) { + get_boot_order(info); + qsort(info->fw_entries, info->fw_entries_count, sizeof(struct boot_info_entry), entry_cmp); + find_active_entry(info); + } + + efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &info->fw_type); + efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &info->fw_info); + efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &info->loader_image_path); + tilt_slashes(info->loader_image_path); + efi_loader_get_device_part_uuid(&info->loader_part_uuid); + + boot_loader_read_entries(info); + efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntrySelected", &loader_active); + if (loader_active) { + boot_loader_find_active_entry(info, loader_active); + free(loader_active); + } + + snprintf(str, sizeof(str), "LoaderEntryOptions-%s", sd_id128_to_string(info->machine_id, buf)); + efi_get_variable_string(EFI_VENDOR_LOADER, str, &info->loader_options_added); + + return 0; +} diff --git a/src/boot/boot-loader.c b/src/boot/boot-loader.c new file mode 100644 index 0000000..d44fdb3 --- /dev/null +++ b/src/boot/boot-loader.c @@ -0,0 +1,132 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "boot.h" +#include "boot-loader.h" +#include "build.h" +#include "util.h" +#include "strv.h" +#include "conf-files.h" + +static char *loader_fragment_read_title(const char *fragment) { + FILE *f; + char line[LINE_MAX]; + char *title = NULL; + + f = fopen(fragment, "re"); + if (!f) + return NULL; + + while (fgets(line, sizeof(line), f) != NULL) { + char *s; + size_t l; + + l = strlen(line); + if (l < 1) + continue; + if (line[l-1] == '\n') + line[l-1] = '\0'; + + s = line; + while (isspace(s[0])) + s++; + + if (s[0] == '#') + continue; + + if (!startswith(s, "title")) + continue; + + s += strlen("title"); + if (!isspace(s[0])) + continue; + while (isspace(s[0])) + s++; + + title = strdup(s); + break; + } + + fclose(f); + return title; +} + +int boot_loader_read_entries(struct boot_info *info) { + _cleanup_strv_free_ char **files = NULL; + static const char *loader_dir[] = { "/boot/loader/entries", NULL}; + unsigned int count; + unsigned int i; + int err; + + err = conf_files_list_strv(&files, ".conf", NULL, loader_dir); + if (err < 0) + return err; + + count = strv_length(files); + info->loader_entries = new0(struct boot_info_entry, count); + if (!info->loader_entries) + return -ENOMEM; + + for (i = 0; i < count; i++) { + info->loader_entries[i].title = loader_fragment_read_title(files[i]); + info->loader_entries[i].path = strdup(files[i]); + if (!info->loader_entries[i].title || !info->loader_entries[i].path) { + free(info->loader_entries[i].title); + free(info->loader_entries[i].path); + return -ENOMEM; + } + info->loader_entries_count++; + } + + return 0; +} + +int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active) { + char *fn; + unsigned int i; + + if (!loader_active) + return -ENOENT; + if (info->loader_entries_count == 0) + return -ENOENT; + + if (asprintf(&fn, "/boot/loader/entries/%s.conf", loader_active) < 0) + return -ENOMEM; + + for (i = 0; i < info->loader_entries_count; i++) { + if (streq(fn, info->loader_entries[i].path)) { + info->loader_entry_active = i; + break; + } + } + + free(fn); + return 0; +} diff --git a/src/boot/boot-loader.h b/src/boot/boot-loader.h new file mode 100644 index 0000000..08827c3 --- /dev/null +++ b/src/boot/boot-loader.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int boot_loader_read_entries(struct boot_info *info); +int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active); diff --git a/src/boot/boot.h b/src/boot/boot.h new file mode 100644 index 0000000..bd8dc69 --- /dev/null +++ b/src/boot/boot.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-id128.h" + +/* + * Firmware and boot manager information to be filled in + * by the platform. + * + * This is partly EFI specific, if you add things, keep this + * as generic as possible to be able to re-use it on other + * platforms. + */ + +struct boot_info_entry { + uint16_t id; + uint16_t order; + char *title; + sd_id128_t part_uuid; + char *path; +}; + +struct boot_info { + sd_id128_t machine_id; + sd_id128_t boot_id; + char *fw_type; + char *fw_info; + int fw_secure_boot; + int fw_secure_boot_setup_mode; + struct boot_info_entry *fw_entries; + size_t fw_entries_count; + uint16_t *fw_entries_order; + size_t fw_entries_order_count; + ssize_t fw_entry_active; + char *loader; + char *loader_image_path; + sd_id128_t loader_part_uuid; + struct boot_info_entry *loader_entries; + size_t loader_entries_count; + ssize_t loader_entry_active; + char *loader_options_added; +}; + +int boot_info_query(struct boot_info *info); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c new file mode 100644 index 0000000..359e273 --- /dev/null +++ b/src/boot/bootctl.c @@ -0,0 +1,288 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "boot.h" +#include "build.h" +#include "util.h" +#include "utf8.h" + +static int help(void) { + + printf("%s [OPTIONS...] COMMAND ...\n\n" + "Query or change firmware and boot manager settings.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + "Commands:\n" + " status Show current boot settings\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int boot_info_new(struct boot_info **info) { + struct boot_info *in; + int err; + + in = new0(struct boot_info, 1); + if (!in) + return -ENOMEM; + + err = sd_id128_get_machine(&in->machine_id); + if (err < 0) + goto err; + + err = sd_id128_get_boot(&in->boot_id); + if (err < 0) + goto err; + + in->fw_entry_active = -1; + in->loader_entry_active = -1; + + *info = in; + return 0; +err: + free(in); + return err; +} + +static void boot_info_entries_free(struct boot_info_entry *entries, size_t n) { + size_t i; + + for (i = 0; i < n; i++) { + free(entries[i].title); + free(entries[i].path); + } + free(entries); +} + +static void boot_info_free(struct boot_info *info) { + free(info->fw_type); + free(info->fw_info); + boot_info_entries_free(info->fw_entries, info->fw_entries_count); + free(info->fw_entries_order); + free(info->loader); + free(info->loader_image_path); + free(info->loader_options_added); + boot_info_entries_free(info->loader_entries, info->loader_entries_count); + free(info); +} + +static int show_status(char **args, unsigned n) { + char buf[64]; + struct boot_info *info; + int err; + + err = boot_info_new(&info); + if (err < 0) + return -ENOMEM; + + err = boot_info_query(info); + + printf("System:\n"); + printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf)); + printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf)); + if (info->fw_type) + printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info)); + if (info->fw_secure_boot >= 0) + printf(" Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled"); + if (info->fw_secure_boot_setup_mode >= 0) + printf(" Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user"); + printf("\n"); + + if (info->fw_entry_active >= 0) { + printf("Selected Firmware Entry:\n"); + printf(" Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title)); + if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL)) + printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + SD_ID128_FORMAT_VAL(info->fw_entries[info->fw_entry_active].part_uuid)); + else + printf(" Partition: n/a\n"); + if (info->fw_entries[info->fw_entry_active].path) + printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), info->fw_entries[info->fw_entry_active].path); + } + printf("\n"); + + if (info->loader) { + printf("Boot Loader:\n"); + printf(" Product: %s\n", info->loader); + if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL)) + printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + SD_ID128_FORMAT_VAL(info->loader_part_uuid)); + else + printf(" Partition: n/a\n"); + printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(info->loader_image_path)); + printf("\n"); + + if (info->loader_entry_active >= 0) { + printf("Selected Boot Loader Entry:\n"); + printf(" Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title)); + printf(" File: %s\n", info->loader_entries[info->loader_entry_active].path); + if (info->loader_options_added) + printf(" Options: %s\n", info->loader_options_added); + } + } else + printf("No suitable data is provided by the boot manager. See:\n" + " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n" + " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n" + "for details.\n"); + printf("\n"); + + boot_info_free(info); + return err; +} + +static int bootctl_main(int argc, char *argv[]) { + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(char **args, unsigned n); + } verbs[] = { + { "status", LESS, 1, show_status }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "status" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(argv + optind, left); +} + +int main(int argc, char *argv[]) { + int r, retval = EXIT_FAILURE; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r < 0) + goto finish; + else if (r == 0) { + retval = EXIT_SUCCESS; + goto finish; + } + + r = bootctl_main(argc, argv); + retval = r < 0 ? EXIT_FAILURE : r; +finish: + return retval; +} diff --git a/src/bootchart/Makefile b/src/bootchart/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/bootchart/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c new file mode 100644 index 0000000..77f3d19 --- /dev/null +++ b/src/bootchart/bootchart.c @@ -0,0 +1,507 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +/*** + + Many thanks to those who contributed ideas and code: + - Ziga Mahkovec - Original bootchart author + - Anders Norgaard - PyBootchartgui + - Michael Meeks - bootchart2 + - Scott James Remnant - Ubuntu C-based logger + - Arjan van der Ven - for the idea to merge bootgraph.pl functionality + + ***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "fileio.h" +#include "macro.h" +#include "conf-parser.h" +#include "strxcpyx.h" +#include "path-util.h" +#include "store.h" +#include "svg.h" +#include "bootchart.h" +#include "list.h" + +double graph_start; +double log_start; +struct ps_struct *ps_first; +int pscount; +int cpus; +double interval; +FILE *of = NULL; +int overrun = 0; +static int exiting = 0; +int sysfd=-1; + +#define DEFAULT_SAMPLES_LEN 500 +#define DEFAULT_HZ 25.0 +#define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */ +#define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */ +#define DEFAULT_INIT "/sbin/init" +#define DEFAULT_OUTPUT "/run/log" + +/* graph defaults */ +bool arg_entropy = false; +bool initcall = true; +bool arg_relative = false; +bool arg_filter = true; +bool arg_show_cmdline = false; +bool arg_show_cgroup = false; +bool arg_pss = false; +int samples; +int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */ +double arg_hz = DEFAULT_HZ; +double arg_scale_x = DEFAULT_SCALE_X; +double arg_scale_y = DEFAULT_SCALE_Y; +static struct list_sample_data *sampledata; +struct list_sample_data *head; + +char arg_init_path[PATH_MAX] = DEFAULT_INIT; +char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT; + +static void signal_handler(int sig) { + if (sig++) + sig--; + exiting = 1; +} + +#define BOOTCHART_CONF "/etc/systemd/bootchart.conf" + +#define BOOTCHART_MAX (16*1024*1024) + +static void parse_conf(void) { + char *init = NULL, *output = NULL; + const ConfigTableItem items[] = { + { "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len }, + { "Bootchart", "Frequency", config_parse_double, 0, &arg_hz }, + { "Bootchart", "Relative", config_parse_bool, 0, &arg_relative }, + { "Bootchart", "Filter", config_parse_bool, 0, &arg_filter }, + { "Bootchart", "Output", config_parse_path, 0, &output }, + { "Bootchart", "Init", config_parse_path, 0, &init }, + { "Bootchart", "PlotMemoryUsage", config_parse_bool, 0, &arg_pss }, + { "Bootchart", "PlotEntropyGraph", config_parse_bool, 0, &arg_entropy }, + { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x }, + { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y }, + { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup }, + { NULL, NULL, NULL, 0, NULL } + }; + _cleanup_fclose_ FILE *f; + int r; + + f = fopen(BOOTCHART_CONF, "re"); + if (!f) + return; + + r = config_parse(NULL, BOOTCHART_CONF, f, + NULL, config_item_table_lookup, (void*) items, true, false, NULL); + if (r < 0) + log_warning("Failed to parse configuration file: %s", strerror(-r)); + + if (init != NULL) + strscpy(arg_init_path, sizeof(arg_init_path), init); + if (output != NULL) + strscpy(arg_output_path, sizeof(arg_output_path), output); +} + +static void help(void) { + fprintf(stdout, + "Usage: %s [OPTIONS]\n\n" + "Options:\n" + " -r, --rel Record time relative to recording\n" + " -f, --freq=FREQ Sample frequency [%g]\n" + " -n, --samples=N Stop sampling at [%d] samples\n" + " -x, --scale-x=N Scale the graph horizontally [%g] \n" + " -y, --scale-y=N Scale the graph vertically [%g] \n" + " -p, --pss Enable PSS graph (CPU intensive)\n" + " -e, --entropy Enable the entropy_avail graph\n" + " -o, --output=PATH Path to output files [%s]\n" + " -i, --init=PATH Path to init executable [%s]\n" + " -F, --no-filter Disable filtering of unimportant or ephemeral processes\n" + " -C, --cmdline Display full command lines with arguments\n" + " -c, --control-group Display process control group\n" + " -h, --help Display this message\n\n" + "See bootchart.conf for more information.\n", + program_invocation_short_name, + DEFAULT_HZ, + DEFAULT_SAMPLES_LEN, + DEFAULT_SCALE_X, + DEFAULT_SCALE_Y, + DEFAULT_OUTPUT, + DEFAULT_INIT); +} + +static int parse_args(int argc, char *argv[]) { + static struct option options[] = { + {"rel", no_argument, NULL, 'r'}, + {"freq", required_argument, NULL, 'f'}, + {"samples", required_argument, NULL, 'n'}, + {"pss", no_argument, NULL, 'p'}, + {"output", required_argument, NULL, 'o'}, + {"init", required_argument, NULL, 'i'}, + {"no-filter", no_argument, NULL, 'F'}, + {"cmdline", no_argument, NULL, 'C'}, + {"control-group", no_argument, NULL, 'c'}, + {"help", no_argument, NULL, 'h'}, + {"scale-x", required_argument, NULL, 'x'}, + {"scale-y", required_argument, NULL, 'y'}, + {"entropy", no_argument, NULL, 'e'}, + {NULL, 0, NULL, 0} + }; + int c; + + while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0) { + int r; + + switch (c) { + case 'r': + arg_relative = true; + break; + case 'f': + r = safe_atod(optarg, &arg_hz); + if (r < 0) + log_warning("failed to parse --freq/-f argument '%s': %s", + optarg, strerror(-r)); + break; + case 'F': + arg_filter = false; + break; + case 'C': + arg_show_cmdline = true; + break; + case 'c': + arg_show_cgroup = true; + break; + case 'n': + r = safe_atoi(optarg, &arg_samples_len); + if (r < 0) + log_warning("failed to parse --samples/-n argument '%s': %s", + optarg, strerror(-r)); + break; + case 'o': + path_kill_slashes(optarg); + strscpy(arg_output_path, sizeof(arg_output_path), optarg); + break; + case 'i': + path_kill_slashes(optarg); + strscpy(arg_init_path, sizeof(arg_init_path), optarg); + break; + case 'p': + arg_pss = true; + break; + case 'x': + r = safe_atod(optarg, &arg_scale_x); + if (r < 0) + log_warning("failed to parse --scale-x/-x argument '%s': %s", + optarg, strerror(-r)); + break; + case 'y': + r = safe_atod(optarg, &arg_scale_y); + if (r < 0) + log_warning("failed to parse --scale-y/-y argument '%s': %s", + optarg, strerror(-r)); + break; + case 'e': + arg_entropy = true; + break; + case 'h': + help(); + exit (EXIT_SUCCESS); + break; + default: + break; + } + } + + if (arg_hz <= 0.0) { + fprintf(stderr, "Error: Frequency needs to be > 0\n"); + return -EINVAL; + } + + return 0; +} + +static void do_journal_append(char *file) { + struct iovec iovec[5]; + int r, f, j = 0; + ssize_t n; + _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL, + *p = NULL; + + bootchart_file = strappend("BOOTCHART_FILE=", file); + if (bootchart_file) + IOVEC_SET_STRING(iovec[j++], bootchart_file); + + IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); + IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); + bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); + if (bootchart_message) + IOVEC_SET_STRING(iovec[j++], bootchart_message); + + p = malloc(9 + BOOTCHART_MAX); + if (!p) { + log_oom(); + return; + } + + memcpy(p, "BOOTCHART=", 10); + + f = open(file, O_RDONLY|O_CLOEXEC); + if (f < 0) { + log_error("Failed to read bootchart data: %m"); + return; + } + n = loop_read(f, p + 10, BOOTCHART_MAX, false); + if (n < 0) { + log_error("Failed to read bootchart data: %s", strerror(-n)); + close(f); + return; + } + close(f); + + iovec[j].iov_base = p; + iovec[j].iov_len = 10 + n; + j++; + + r = sd_journal_sendv(iovec, j); + if (r < 0) + log_error("Failed to send bootchart: %s", strerror(-r)); +} + +int main(int argc, char *argv[]) { + _cleanup_free_ char *build = NULL; + struct sigaction sig = { + .sa_handler = signal_handler, + }; + struct ps_struct *ps; + char output_file[PATH_MAX]; + char datestr[200]; + time_t t = 0; + int r; + struct rlimit rlim; + + parse_conf(); + + r = parse_args(argc, argv); + if (r < 0) + return EXIT_FAILURE; + + /* + * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then + * fork: + * - parent execs executable specified via init_path[] (/sbin/init by default) as pid=1 + * - child logs data + */ + if (getpid() == 1) { + if (fork()) { + /* parent */ + execl(arg_init_path, arg_init_path, NULL); + } + } + argv[0][0] = '@'; + + rlim.rlim_cur = 4096; + rlim.rlim_max = 4096; + (void) setrlimit(RLIMIT_NOFILE, &rlim); + + /* start with empty ps LL */ + ps_first = new0(struct ps_struct, 1); + if (!ps_first) { + log_oom(); + return EXIT_FAILURE; + } + + /* handle TERM/INT nicely */ + sigaction(SIGHUP, &sig, NULL); + + interval = (1.0 / arg_hz) * 1000000000.0; + + log_uptime(); + + LIST_HEAD_INIT(head); + + /* main program loop */ + for (samples = 0; !exiting && samples < arg_samples_len; samples++) { + int res; + double sample_stop; + struct timespec req; + time_t newint_s; + long newint_ns; + double elapsed; + double timeleft; + + sampledata = new0(struct list_sample_data, 1); + if (sampledata == NULL) { + log_error("Failed to allocate memory for a node: %m"); + return -1; + } + + sampledata->sampletime = gettime_ns(); + sampledata->counter = samples; + + if (!of && (access(arg_output_path, R_OK|W_OK|X_OK) == 0)) { + t = time(NULL); + strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); + snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); + of = fopen(output_file, "we"); + } + + if (sysfd < 0) + sysfd = open("/sys", O_RDONLY|O_CLOEXEC); + + if (!build) + parse_env_file("/etc/os-release", NEWLINE, + "PRETTY_NAME", &build, + NULL); + + /* wait for /proc to become available, discarding samples */ + if (graph_start <= 0.0) + log_uptime(); + else + log_sample(samples, &sampledata); + + sample_stop = gettime_ns(); + + elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0; + timeleft = interval - elapsed; + + newint_s = (time_t)(timeleft / 1000000000.0); + newint_ns = (long)(timeleft - (newint_s * 1000000000.0)); + + /* + * check if we have not consumed our entire timeslice. If we + * do, don't sleep and take a new sample right away. + * we'll lose all the missed samples and overrun our total + * time + */ + if (newint_ns > 0 || newint_s > 0) { + req.tv_sec = newint_s; + req.tv_nsec = newint_ns; + + res = nanosleep(&req, NULL); + if (res) { + if (errno == EINTR) { + /* caught signal, probably HUP! */ + break; + } + log_error("nanosleep() failed: %m"); + exit(EXIT_FAILURE); + } + } else { + overrun++; + /* calculate how many samples we lost and scrap them */ + arg_samples_len -= (int)(newint_ns / interval); + } + LIST_PREPEND(link, head, sampledata); + } + + /* do some cleanup, close fd's */ + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (ps->schedstat) + close(ps->schedstat); + if (ps->sched) + close(ps->sched); + if (ps->smaps) + fclose(ps->smaps); + } + + if (!of) { + t = time(NULL); + strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t)); + snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr); + of = fopen(output_file, "we"); + } + + if (!of) { + fprintf(stderr, "opening output file '%s': %m\n", output_file); + exit (EXIT_FAILURE); + } + + svg_do(build); + + fprintf(stderr, "systemd-bootchart wrote %s\n", output_file); + + do_journal_append(output_file); + + if (of) + fclose(of); + + closedir(proc); + if (sysfd >= 0) + close(sysfd); + + /* nitpic cleanups */ + ps = ps_first->next_ps; + while (ps->next_ps) { + struct ps_struct *old; + + old = ps; + old->sample = ps->first; + ps = ps->next_ps; + while (old->sample->next) { + struct ps_sched_struct *oldsample = old->sample; + + old->sample = old->sample->next; + free(oldsample); + } + free(old->cgroup); + free(old->sample); + free(old); + } + free(ps->cgroup); + free(ps->sample); + free(ps); + + sampledata = head; + while (sampledata->link_prev) { + struct list_sample_data *old_sampledata = sampledata; + sampledata = sampledata->link_prev; + free(old_sampledata); + } + free(sampledata); + /* don't complain when overrun once, happens most commonly on 1st sample */ + if (overrun > 1) + fprintf(stderr, "systemd-boochart: Warning: sample time overrun %i times\n", overrun); + + return 0; +} diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf new file mode 100644 index 0000000..d7e0dab --- /dev/null +++ b/src/bootchart/bootchart.conf @@ -0,0 +1,21 @@ +# 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. +# +# See bootchart.conf(5) for details + +[Bootchart] +#Samples=500 +#Frequency=25 +#Relative=no +#Filter=yes +#Output= +#Init=/path/to/init-binary +#PlotMemoryUsage=no +#PlotEntropyGraph=no +#ScaleX=100 +#ScaleY=20 +#ControlGroup=no diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h new file mode 100644 index 0000000..2c37835 --- /dev/null +++ b/src/bootchart/bootchart.h @@ -0,0 +1,135 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include "list.h" + +#define MAXCPUS 16 +#define MAXPIDS 65535 + +struct block_stat_struct { + /* /proc/vmstat pgpgin & pgpgout */ + int bi; + int bo; +}; + +struct cpu_stat_sample_struct { + /* /proc/schedstat fields 10 & 11 (after name) */ + double runtime; + double waittime; +}; + +/* per process, per sample data we will log */ +struct ps_sched_struct { + /* /proc//schedstat fields 1 & 2 */ + double runtime; + double waittime; + int pss; + struct list_sample_data *sampledata; + struct ps_sched_struct *next; + struct ps_sched_struct *prev; + struct ps_sched_struct *cross; /* cross pointer */ + struct ps_struct *ps_new; +}; + +struct list_sample_data { + double runtime[MAXCPUS]; + double waittime[MAXCPUS]; + double sampletime; + int entropy_avail; + struct block_stat_struct blockstat; + LIST_FIELDS(struct list_sample_data, link); /* DLL */ + int counter; +}; + +/* process info */ +struct ps_struct { + struct ps_struct *next_ps; /* SLL pointer */ + struct ps_struct *parent; /* ppid ref */ + struct ps_struct *children; /* children */ + struct ps_struct *next; /* siblings */ + + /* must match - otherwise it's a new process with same PID */ + char name[256]; + int pid; + int ppid; + char *cgroup; + + /* cache fd's */ + int sched; + int schedstat; + FILE *smaps; + + /* pointers to first/last seen timestamps */ + struct ps_sched_struct *first; + struct ps_sched_struct *last; + + /* records actual start time, may be way before bootchart runs */ + double starttime; + + /* record human readable total cpu time */ + double total; + + /* largest PSS size found */ + int pss_max; + + /* for drawing connection lines later */ + double pos_x; + double pos_y; + + struct ps_sched_struct *sample; +}; + +extern int entropy_avail[]; + +extern double graph_start; +extern double log_start; +extern double sampletime[]; +extern struct ps_struct *ps_first; +extern struct block_stat_struct blockstat[]; +extern int pscount; +extern bool arg_relative; +extern bool arg_filter; +extern bool arg_show_cmdline; +extern bool arg_show_cgroup; +extern bool arg_pss; +extern bool arg_entropy; +extern bool initcall; +extern int samples; +extern int cpus; +extern int arg_samples_len; +extern double arg_hz; +extern double arg_scale_x; +extern double arg_scale_y; +extern int overrun; +extern double interval; + +extern char arg_output_path[PATH_MAX]; +extern char arg_init_path[PATH_MAX]; + +extern FILE *of; +extern int sysfd; diff --git a/src/bootchart/store.c b/src/bootchart/store.c new file mode 100644 index 0000000..e071983 --- /dev/null +++ b/src/bootchart/store.c @@ -0,0 +1,508 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "strxcpyx.h" +#include "store.h" +#include "bootchart.h" +#include "cgroup-util.h" + +/* + * Alloc a static 4k buffer for stdio - primarily used to increase + * PSS buffering from the default 1k stdin buffer to reduce + * read() overhead. + */ +static char smaps_buf[4096]; +static int skip = 0; +DIR *proc; +int procfd = -1; + +double gettime_ns(void) { + struct timespec n; + + clock_gettime(CLOCK_MONOTONIC, &n); + + return (n.tv_sec + (n.tv_nsec / 1000000000.0)); +} + +void log_uptime(void) { + _cleanup_fclose_ FILE *f = NULL; + char str[32]; + double uptime; + + f = fopen("/proc/uptime", "re"); + + if (!f) + return; + if (!fscanf(f, "%s %*s", str)) + return; + + uptime = strtod(str, NULL); + + log_start = gettime_ns(); + + /* start graph at kernel boot time */ + if (arg_relative) + graph_start = log_start; + else + graph_start = log_start - uptime; +} + +static char *bufgetline(char *buf) { + char *c; + + if (!buf) + return NULL; + + c = strchr(buf, '\n'); + if (c) + c++; + return c; +} + +static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) { + char filename[PATH_MAX]; + _cleanup_close_ int fd=-1; + ssize_t n; + + sprintf(filename, "%d/cmdline", pid); + fd = openat(procfd, filename, O_RDONLY); + if (fd < 0) + return -errno; + + n = read(fd, buffer, buf_len-1); + if (n > 0) { + int i; + for (i = 0; i < n; i++) + if (buffer[i] == '\0') + buffer[i] = ' '; + buffer[n] = '\0'; + } + return 0; +} + +void log_sample(int sample, struct list_sample_data **ptr) { + static int vmstat; + static int schedstat; + char buf[4096]; + char key[256]; + char val[256]; + char rt[256]; + char wt[256]; + char *m; + int c; + int p; + int mod; + static int e_fd; + ssize_t s; + ssize_t n; + struct dirent *ent; + int fd; + struct list_sample_data *sampledata; + struct ps_sched_struct *ps_prev = NULL; + + sampledata = *ptr; + + /* all the per-process stuff goes here */ + if (!proc) { + /* find all processes */ + proc = opendir("/proc"); + if (!proc) + return; + procfd = dirfd(proc); + } else { + rewinddir(proc); + } + + if (!vmstat) { + /* block stuff */ + vmstat = openat(procfd, "vmstat", O_RDONLY); + if (vmstat == -1) { + log_error("Failed to open /proc/vmstat: %m"); + exit(EXIT_FAILURE); + } + } + + n = pread(vmstat, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(vmstat); + return; + } + buf[n] = '\0'; + + m = buf; + while (m) { + if (sscanf(m, "%s %s", key, val) < 2) + goto vmstat_next; + if (streq(key, "pgpgin")) + sampledata->blockstat.bi = atoi(val); + if (streq(key, "pgpgout")) { + sampledata->blockstat.bo = atoi(val); + break; + } +vmstat_next: + m = bufgetline(m); + if (!m) + break; + } + + if (!schedstat) { + /* overall CPU utilization */ + schedstat = openat(procfd, "schedstat", O_RDONLY); + if (schedstat == -1) { + log_error("Failed to open /proc/schedstat: %m"); + exit(EXIT_FAILURE); + } + } + + n = pread(schedstat, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(schedstat); + return; + } + buf[n] = '\0'; + + m = buf; + while (m) { + if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) + goto schedstat_next; + + if (strstr(key, "cpu")) { + c = atoi((const char*)(key+3)); + if (c > MAXCPUS) + /* Oops, we only have room for MAXCPUS data */ + break; + sampledata->runtime[c] = atoll(rt); + sampledata->waittime[c] = atoll(wt); + + if (c == cpus) + cpus = c + 1; + } +schedstat_next: + m = bufgetline(m); + if (!m) + break; + } + + if (arg_entropy) { + if (!e_fd) { + e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY); + } + + if (e_fd) { + n = pread(e_fd, buf, sizeof(buf) - 1, 0); + if (n > 0) { + buf[n] = '\0'; + sampledata->entropy_avail = atoi(buf); + } + } + } + + while ((ent = readdir(proc)) != NULL) { + char filename[PATH_MAX]; + int pid; + struct ps_struct *ps; + + if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) + continue; + + pid = atoi(ent->d_name); + + if (pid >= MAXPIDS) + continue; + + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (ps->pid == pid) + break; + } + + /* end of our LL? then append a new record */ + if (ps->pid != pid) { + _cleanup_fclose_ FILE *st = NULL; + char t[32]; + struct ps_struct *parent; + + ps->next_ps = new0(struct ps_struct, 1); + if (!ps->next_ps) { + log_oom(); + exit (EXIT_FAILURE); + } + ps = ps->next_ps; + ps->pid = pid; + + ps->sample = new0(struct ps_sched_struct, 1); + if (!ps->sample) { + log_oom(); + exit (EXIT_FAILURE); + } + ps->sample->sampledata = sampledata; + + pscount++; + + /* mark our first sample */ + ps->first = ps->last = ps->sample; + ps->sample->runtime = atoll(rt); + ps->sample->waittime = atoll(wt); + + /* get name, start time */ + if (!ps->sched) { + sprintf(filename, "%d/sched", pid); + ps->sched = openat(procfd, filename, O_RDONLY); + if (ps->sched == -1) + continue; + } + + s = pread(ps->sched, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + close(ps->sched); + continue; + } + buf[s] = '\0'; + + if (!sscanf(buf, "%s %*s %*s", key)) + continue; + + strscpy(ps->name, sizeof(ps->name), key); + + /* cmdline */ + if (arg_show_cmdline) + pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid); + + /* discard line 2 */ + m = bufgetline(buf); + if (!m) + continue; + + m = bufgetline(m); + if (!m) + continue; + + if (!sscanf(m, "%*s %*s %s", t)) + continue; + + ps->starttime = strtod(t, NULL) / 1000.0; + + if (arg_show_cgroup) + /* if this fails, that's OK */ + cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, + ps->pid, &ps->cgroup); + + /* ppid */ + sprintf(filename, "%d/stat", pid); + fd = openat(procfd, filename, O_RDONLY); + st = fdopen(fd, "r"); + if (!st) + continue; + if (!fscanf(st, "%*s %*s %*s %i", &p)) { + continue; + } + ps->ppid = p; + + /* + * setup child pointers + * + * these are used to paint the tree coherently later + * each parent has a LL of children, and a LL of siblings + */ + if (pid == 1) + continue; /* nothing to do for init atm */ + + /* kthreadd has ppid=0, which breaks our tree ordering */ + if (ps->ppid == 0) + ps->ppid = 1; + + parent = ps_first; + while ((parent->next_ps && parent->pid != ps->ppid)) + parent = parent->next_ps; + + if (parent->pid != ps->ppid) { + /* orphan */ + ps->ppid = 1; + parent = ps_first->next_ps; + } + + ps->parent = parent; + + if (!parent->children) { + /* it's the first child */ + parent->children = ps; + } else { + /* walk all children and append */ + struct ps_struct *children; + children = parent->children; + while (children->next) + children = children->next; + children->next = ps; + } + } + + /* else -> found pid, append data in ps */ + + /* below here is all continuous logging parts - we get here on every + * iteration */ + + /* rt, wt */ + if (!ps->schedstat) { + sprintf(filename, "%d/schedstat", pid); + ps->schedstat = openat(procfd, filename, O_RDONLY); + if (ps->schedstat == -1) + continue; + } + s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + /* clean up our file descriptors - assume that the process exited */ + close(ps->schedstat); + if (ps->sched) + close(ps->sched); + //if (ps->smaps) + // fclose(ps->smaps); + continue; + } + buf[s] = '\0'; + + if (!sscanf(buf, "%s %s %*s", rt, wt)) + continue; + + ps->sample->next = new0(struct ps_sched_struct, 1); + if (!ps->sample) { + log_oom(); + exit(EXIT_FAILURE); + } + ps->sample->next->prev = ps->sample; + ps->sample = ps->sample->next; + ps->last = ps->sample; + ps->sample->runtime = atoll(rt); + ps->sample->waittime = atoll(wt); + ps->sample->sampledata = sampledata; + ps->sample->ps_new = ps; + if (ps_prev) { + ps_prev->cross = ps->sample; + } + ps_prev = ps->sample; + ps->total = (ps->last->runtime - ps->first->runtime) + / 1000000000.0; + + if (!arg_pss) + goto catch_rename; + + /* Pss */ + if (!ps->smaps) { + sprintf(filename, "%d/smaps", pid); + fd = openat(procfd, filename, O_RDONLY); + ps->smaps = fdopen(fd, "r"); + if (!ps->smaps) + continue; + setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf)); + } + else { + rewind(ps->smaps); + } + /* test to see if we need to skip another field */ + if (skip == 0) { + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { + continue; + } + if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) { + continue; + } + if (buf[392] == 'V') { + skip = 2; + } + else { + skip = 1; + } + rewind(ps->smaps); + } + while (1) { + int pss_kb; + + /* skip one line, this contains the object mapped. */ + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { + break; + } + /* then there's a 28 char 14 line block */ + if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) { + break; + } + pss_kb = atoi(&buf[61]); + ps->sample->pss += pss_kb; + + /* skip one more line if this is a newer kernel */ + if (skip == 2) { + if (fgets(buf, sizeof(buf), ps->smaps) == NULL) + break; + } + } + if (ps->sample->pss > ps->pss_max) + ps->pss_max = ps->sample->pss; + +catch_rename: + /* catch process rename, try to randomize time */ + mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0); + if (((samples - ps->pid) + pid) % (int)(mod) == 0) { + + /* re-fetch name */ + /* get name, start time */ + if (!ps->sched) { + sprintf(filename, "%d/sched", pid); + ps->sched = openat(procfd, filename, O_RDONLY); + if (ps->sched == -1) + continue; + } + s = pread(ps->sched, buf, sizeof(buf) - 1, 0); + if (s <= 0) { + /* clean up file descriptors */ + close(ps->sched); + if (ps->schedstat) + close(ps->schedstat); + //if (ps->smaps) + // fclose(ps->smaps); + continue; + } + buf[s] = '\0'; + + if (!sscanf(buf, "%s %*s %*s", key)) + continue; + + strscpy(ps->name, sizeof(ps->name), key); + + /* cmdline */ + if (arg_show_cmdline) + pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid); + } + } +} diff --git a/src/bootchart/store.h b/src/bootchart/store.h new file mode 100644 index 0000000..f211b6f --- /dev/null +++ b/src/bootchart/store.h @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "bootchart.h" + +extern DIR *proc; +extern int procfd; + +double gettime_ns(void); +void log_uptime(void); +void log_sample(int sample, struct list_sample_data **ptr); diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c new file mode 100644 index 0000000..a53f98a --- /dev/null +++ b/src/bootchart/svg.c @@ -0,0 +1,1326 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "store.h" +#include "svg.h" +#include "bootchart.h" +#include "list.h" + +#define time_to_graph(t) ((t) * arg_scale_x) +#define ps_to_graph(n) ((n) * arg_scale_y) +#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001) +#define to_color(n) (192.0 - ((n) * 192.0)) + +static char str[8092]; + +#define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0) + +static const char * const colorwheel[12] = { + "rgb(255,32,32)", // red + "rgb(32,192,192)", // cyan + "rgb(255,128,32)", // orange + "rgb(128,32,192)", // blue-violet + "rgb(255,255,32)", // yellow + "rgb(192,32,128)", // red-violet + "rgb(32,255,32)", // green + "rgb(255,64,32)", // red-orange + "rgb(32,32,255)", // blue + "rgb(255,192,32)", // yellow-orange + "rgb(192,32,192)", // violet + "rgb(32,192,32)" // yellow-green +}; + +static double idletime = -1.0; +static int pfiltered = 0; +static int pcount = 0; +static int kcount = 0; +static double psize = 0; +static double ksize = 0; +static double esize = 0; +static struct list_sample_data *sampledata; +static struct list_sample_data *prev_sampledata; +extern struct list_sample_data *head; + +static void svg_header(void) { + double w; + double h; + struct list_sample_data *sampledata_last; + + sampledata = head; + LIST_FIND_TAIL(link, sampledata, head); + sampledata_last = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + sampledata_last = sampledata; + } + + /* min width is about 1600px due to the label */ + w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start); + w = ((w < 1600.0) ? 1600.0 : w); + + /* height is variable based on pss, psize, ksize */ + h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */ + + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */ + + psize + ksize + esize; + + svg("\n"); + svg("\n"); + + //svg("\n", 1000 + 150 + (pcount * 20)); + svg("\n\n"); + + /* write some basic info as a comment, including some help */ + svg("\n"); + svg("\n"); + svg("\n"); + svg("\n"); + svg("\n\n"); + + svg("\n", VERSION); + svg("\n", arg_hz, arg_samples_len); + svg("\n", arg_scale_x, arg_scale_y); + svg("\n", arg_relative, arg_filter); + svg("\n", arg_pss, arg_entropy); + svg("\n\n", arg_output_path, arg_init_path); + + /* style sheet */ + svg("\n \n\n\n"); +} + +static void svg_title(const char *build) { + char cmdline[256] = ""; + char filename[PATH_MAX]; + char buf[256]; + char rootbdev[16] = "Unknown"; + char model[256] = "Unknown"; + char date[256] = "Unknown"; + char cpu[256] = "Unknown"; + char *c; + FILE *f; + time_t t; + int fd; + struct utsname uts; + + /* grab /proc/cmdline */ + fd = openat(procfd, "cmdline", O_RDONLY); + f = fdopen(fd, "r"); + if (f) { + if (!fgets(cmdline, 255, f)) + sprintf(cmdline, "Unknown"); + fclose(f); + } + + /* extract root fs so we can find disk model name in sysfs */ + /* FIXME: this works only in the simple case */ + c = strstr(cmdline, "root=/dev/"); + if (c) { + strncpy(rootbdev, &c[10], 3); + rootbdev[3] = '\0'; + sprintf(filename, "block/%s/device/model", rootbdev); + fd = openat(sysfd, filename, O_RDONLY); + f = fdopen(fd, "r"); + if (f) { + if (!fgets(model, 255, f)) + fprintf(stderr, "Error reading disk model for %s\n", rootbdev); + fclose(f); + } + } + + /* various utsname parameters */ + if (uname(&uts)) + fprintf(stderr, "Error getting uname info\n"); + + /* date */ + t = time(NULL); + strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); + + /* CPU type */ + fd = openat(procfd, "cpuinfo", O_RDONLY); + f = fdopen(fd, "r"); + if (f) { + while (fgets(buf, 255, f)) { + if (strstr(buf, "model name")) { + strncpy(cpu, &buf[13], 255); + break; + } + } + fclose(f); + } + + svg("Bootchart for %s - %s\n", + uts.nodename, date); + svg("System: %s %s %s %s\n", + uts.sysname, uts.release, uts.version, uts.machine); + svg("CPU: %s\n", + cpu); + svg("Disk: %s\n", + model); + svg("Boot options: %s\n", + cmdline); + svg("Build: %s\n", + build); + svg("Log start time: %.03fs\n", log_start); + svg("Idle time: "); + + if (idletime >= 0.0) + svg("%.03fs", idletime); + else + svg("Not detected"); + svg("\n"); + svg("Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered\n", + arg_hz, arg_samples_len, overrun, pscount, pfiltered); +} + +static void svg_graph_box(int height) { + double d = 0.0; + int i = 0; + double finalsample = 0.0; + struct list_sample_data *sampledata_last; + + sampledata_last = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + sampledata_last = sampledata; + } + + finalsample = sampledata_last->sampletime; + + /* outside box, fill */ + svg("\n", + time_to_graph(0.0), + time_to_graph(finalsample - graph_start), + ps_to_graph(height)); + + for (d = graph_start; d <= finalsample; + d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) { + /* lines for each second */ + if (i % 50 == 0) + svg(" \n", + time_to_graph(d - graph_start), + time_to_graph(d - graph_start), + ps_to_graph(height)); + else if (i % 10 == 0) + svg(" \n", + time_to_graph(d - graph_start), + time_to_graph(d - graph_start), + ps_to_graph(height)); + else + svg(" \n", + time_to_graph(d - graph_start), + time_to_graph(d - graph_start), + ps_to_graph(height)); + + /* time label */ + if (i % 10 == 0) + svg(" %.01fs\n", + time_to_graph(d - graph_start), + -5.0, + d - graph_start); + + i++; + } +} + +/* xml comments must not contain "--" */ +static char* xml_comment_encode(const char* name) { + char *enc_name, *p; + + enc_name = strdup(name); + if (!enc_name) + return NULL; + + for (p = enc_name; *p; p++) + if (p[0] == '-' && p[1] == '-') + p[1] = '_'; + + return enc_name; +} + +static void svg_pss_graph(void) { + struct ps_struct *ps; + int i; + struct list_sample_data *sampledata_last; + + sampledata_last = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + sampledata_last = sampledata; + } + + + svg("\n\n\n"); + + svg("\n Memory allocation - Pss\n"); + + /* vsize 1000 == 1000mb */ + svg_graph_box(100); + /* draw some hlines for usable memory sizes */ + for (i = 100000; i < 1000000; i += 100000) { + svg(" \n", + time_to_graph(.0), + kb_to_graph(i), + time_to_graph(sampledata_last->sampletime - graph_start), + kb_to_graph(i)); + svg(" %dM\n", + time_to_graph(sampledata_last->sampletime - graph_start) + 5, + kb_to_graph(i), (1000000 - i) / 1000); + } + svg("\n"); + + /* now plot the graph itself */ + i = 1; + prev_sampledata = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int bottom; + int top; + struct ps_sched_struct *cross_place; + + bottom = 0; + top = 0; + + /* put all the small pss blocks into the bottom */ + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (!ps) + continue; + ps->sample = ps->first; + while (ps->sample->next) { + ps->sample = ps->sample->next; + if (ps->sample->sampledata == sampledata) + break; + } + if (ps->sample->sampledata == sampledata) { + if (ps->sample->pss <= (100 * arg_scale_y)) + top += ps->sample->pss; + break; + } + } + while (ps->sample->cross) { + cross_place = ps->sample->cross; + ps = ps->sample->cross->ps_new; + ps->sample = cross_place; + if (ps->sample->pss <= (100 * arg_scale_y)) + top += ps->sample->pss; + } + + svg(" \n", + "rgb(64,64,64)", + time_to_graph(prev_sampledata->sampletime - graph_start), + kb_to_graph(1000000.0 - top), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + kb_to_graph(top - bottom)); + bottom = top; + + /* now plot the ones that are of significant size */ + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (!ps) + continue; + ps->sample = ps->first; + while (ps->sample->next) { + ps->sample = ps->sample->next; + if (ps->sample->sampledata == sampledata) + break; + } + /* don't draw anything smaller than 2mb */ + if (ps->sample->sampledata == sampledata) { + if (ps->sample->pss > (100 * arg_scale_y)) { + top = bottom + ps->sample->pss; + svg(" \n", + colorwheel[ps->pid % 12], + time_to_graph(prev_sampledata->sampletime - graph_start), + kb_to_graph(1000000.0 - top), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + kb_to_graph(top - bottom)); + bottom = top; + } + break; + } + } + while ((cross_place = ps->sample->cross)) { + ps = ps->sample->cross->ps_new; + ps->sample = cross_place; + if (ps->sample->pss > (100 * arg_scale_y)) { + top = bottom + ps->sample->pss; + svg(" \n", + colorwheel[ps->pid % 12], + time_to_graph(prev_sampledata->sampletime - graph_start), + kb_to_graph(1000000.0 - top), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + kb_to_graph(top - bottom)); + bottom = top; + } + } + prev_sampledata = sampledata; + i++; + } + + /* overlay all the text labels */ + i = 1; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int bottom; + int top = 0; + struct ps_sched_struct *prev_sample; + struct ps_sched_struct *cross_place; + + /* put all the small pss blocks into the bottom */ + ps = ps_first->next_ps; + while (ps->next_ps) { + ps = ps->next_ps; + if (!ps) + continue; + ps->sample = ps->first; + while (ps->sample->next) { + ps->sample = ps->sample->next; + if (ps->sample->sampledata == sampledata) + break; + } + if (ps->sample->sampledata == sampledata) { + if (ps->sample->pss <= (100 * arg_scale_y)) + top += ps->sample->pss; + break; + } + } + while ((cross_place = ps->sample->cross)) { + ps = ps->sample->cross->ps_new; + ps->sample = cross_place; + if (ps->sample->pss <= (100 * arg_scale_y)) + top += ps->sample->pss; + } + bottom = top; + + /* now plot the ones that are of significant size */ + ps = ps_first; + while (ps->next_ps) { + prev_sample = ps->sample; + ps = ps->next_ps; + if (!ps) + continue; + ps->sample = ps->first; + while (ps->sample->next) { + prev_sample = ps->sample; + ps->sample = ps->sample->next; + if (ps->sample->sampledata == sampledata) + break; + } + /* don't draw anything smaller than 2mb */ + if (ps->sample->sampledata == sampledata) { + if (ps->sample->pss > (100 * arg_scale_y)) { + top = bottom + ps->sample->pss; + /* draw a label with the process / PID */ + if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) + svg(" %s [%i]\n", + time_to_graph(sampledata->sampletime - graph_start), + kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), + ps->name, + ps->pid); + bottom = top; + } + break; + } + } + while ((cross_place = ps->sample->cross)) { + ps = ps->sample->cross->ps_new; + ps->sample = cross_place; + prev_sample = ps->sample->prev; + if (ps->sample->pss > (100 * arg_scale_y)) { + top = bottom + ps->sample->pss; + /* draw a label with the process / PID */ + if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) + svg(" %s [%i]\n", + time_to_graph(sampledata->sampletime - graph_start), + kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), + ps->name, + ps->pid); + bottom = top; + } + } + i++; + } + + /* debug output - full data dump */ + svg("\n\n\n"); + ps = ps_first; + while (ps->next_ps) { + _cleanup_free_ char *enc_name = NULL; + ps = ps->next_ps; + if (!ps) + continue; + + enc_name = xml_comment_encode(ps->name); + if (!enc_name) + continue; + + svg("\n"); + } + +} + +static void svg_io_bi_bar(void) { + double max = 0.0; + double range; + int max_here = 0; + int i; + int k; + struct list_sample_data *start_sampledata; + struct list_sample_data *stop_sampledata; + + svg("\n"); + + svg("IO utilization - read\n"); + + /* + * calculate rounding range + * + * We need to round IO data since IO block data is not updated on + * each poll. Applying a smoothing function loses some burst data, + * so keep the smoothing range short. + */ + range = 0.25 / (1.0 / arg_hz); + if (range < 2.0) + range = 2.0; /* no smoothing */ + + /* surrounding box */ + svg_graph_box(5); + + /* find the max IO first */ + i = 1; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int start; + int stop; + int diff; + double tot; + + start = MAX(i - ((range / 2) - 1), 0); + stop = MIN(i + (range / 2), samples - 1); + diff = (stop - start); + + start_sampledata = sampledata; + stop_sampledata = sampledata; + + for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++) + start_sampledata = start_sampledata->link_next; + for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++) + stop_sampledata = stop_sampledata->link_prev; + + tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) + / diff; + + if (tot > max) { + max = tot; + max_here = i; + } + + tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) + / diff; + + if (tot > max) + max = tot; + + i++; + } + + /* plot bi */ + i = 1; + prev_sampledata = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int start; + int stop; + int diff; + double tot; + double pbi = 0; + + start = MAX(i - ((range / 2) - 1), 0); + stop = MIN(i + (range / 2), samples); + diff = (stop - start); + + start_sampledata = sampledata; + stop_sampledata = sampledata; + + for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++) + start_sampledata = start_sampledata->link_next; + for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++) + stop_sampledata = stop_sampledata->link_prev; + + tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) + / diff; + + if (max > 0) + pbi = tot / max; + + if (pbi > 0.001) + svg("\n", + time_to_graph(prev_sampledata->sampletime - graph_start), + (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + pbi * (arg_scale_y * 5)); + + /* labels around highest value */ + if (i == max_here) { + svg(" %0.2fmb/sec\n", + time_to_graph(sampledata->sampletime - graph_start) + 5, + ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15, + max / 1024.0 / (interval / 1000000000.0)); + } + i++; + prev_sampledata = sampledata; + } +} + +static void svg_io_bo_bar(void) { + double max = 0.0; + double range; + int max_here = 0; + int i; + int k; + struct list_sample_data *start_sampledata; + struct list_sample_data *stop_sampledata; + + svg("\n"); + + svg("IO utilization - write\n"); + + /* + * calculate rounding range + * + * We need to round IO data since IO block data is not updated on + * each poll. Applying a smoothing function loses some burst data, + * so keep the smoothing range short. + */ + range = 0.25 / (1.0 / arg_hz); + if (range < 2.0) + range = 2.0; /* no smoothing */ + + /* surrounding box */ + svg_graph_box(5); + + /* find the max IO first */ + i = 0; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int start; + int stop; + int diff; + double tot; + + start = MAX(i - ((range / 2) - 1), 0); + stop = MIN(i + (range / 2), samples - 1); + diff = (stop - start); + + start_sampledata = sampledata; + stop_sampledata = sampledata; + + for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++) + start_sampledata = start_sampledata->link_next; + for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++) + stop_sampledata = stop_sampledata->link_prev; + + tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) + / diff; + if (tot > max) + max = tot; + tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) + / diff; + if (tot > max) { + max = tot; + max_here = i; + } + i++; + } + + /* plot bo */ + prev_sampledata = head; + i=1; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int start; + int stop; + int diff; + double tot; + double pbo; + + pbo = 0; + + start = MAX(i - ((range / 2) - 1), 0); + stop = MIN(i + (range / 2), samples); + diff = (stop - start); + + start_sampledata = sampledata; + stop_sampledata = sampledata; + + for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++) + start_sampledata = start_sampledata->link_next; + for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++) + stop_sampledata = stop_sampledata->link_prev; + + tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) + / diff; + + if (max > 0) + pbo = tot / max; + + if (pbo > 0.001) + svg("\n", + time_to_graph(prev_sampledata->sampletime - graph_start), + (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + pbo * (arg_scale_y * 5)); + + /* labels around highest bo value */ + if (i == max_here) { + svg(" %0.2fmb/sec\n", + time_to_graph(sampledata->sampletime - graph_start) + 5, + ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))), + max / 1024.0 / (interval / 1000000000.0)); + } + i++; + prev_sampledata = sampledata; + } +} + +static void svg_cpu_bar(void) { + + svg("\n"); + + svg("CPU utilization\n"); + /* surrounding box */ + svg_graph_box(5); + + /* bars for each sample, proportional to the CPU util. */ + prev_sampledata = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int c; + double trt; + double ptrt; + + ptrt = trt = 0.0; + + for (c = 0; c < cpus; c++) + trt += sampledata->runtime[c] - prev_sampledata->runtime[c]; + + trt = trt / 1000000000.0; + + trt = trt / (double)cpus; + + if (trt > 0.0) + ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime); + + if (ptrt > 1.0) + ptrt = 1.0; + + if (ptrt > 0.001) { + svg("\n", + time_to_graph(prev_sampledata->sampletime - graph_start), + (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + ptrt * (arg_scale_y * 5)); + } + prev_sampledata = sampledata; + } +} + +static void svg_wait_bar(void) { + + svg("\n"); + + svg("CPU wait\n"); + + /* surrounding box */ + svg_graph_box(5); + + /* bars for each sample, proportional to the CPU util. */ + prev_sampledata = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + int c; + double twt; + double ptwt; + + ptwt = twt = 0.0; + + for (c = 0; c < cpus; c++) + twt += sampledata->waittime[c] - prev_sampledata->waittime[c]; + + twt = twt / 1000000000.0; + + twt = twt / (double)cpus; + + if (twt > 0.0) + ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime); + + if (ptwt > 1.0) + ptwt = 1.0; + + if (ptwt > 0.001) { + svg("\n", + time_to_graph(prev_sampledata->sampletime - graph_start), + ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + ptwt * (arg_scale_y * 5)); + } + prev_sampledata = sampledata; + } +} + + +static void svg_entropy_bar(void) { + + svg("\n"); + + svg("Entropy pool size\n"); + /* surrounding box */ + svg_graph_box(5); + + /* bars for each sample, scale 0-4096 */ + prev_sampledata = head; + LIST_FOREACH_BEFORE(link, sampledata, head) { + /* svg("\n", sampletime[i], entropy_avail[i]); */ + svg("\n", + time_to_graph(prev_sampledata->sampletime - graph_start), + ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))), + time_to_graph(sampledata->sampletime - prev_sampledata->sampletime), + (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5)); + prev_sampledata = sampledata; + } +} + +static struct ps_struct *get_next_ps(struct ps_struct *ps) { + /* + * walk the list of processes and return the next one to be + * painted + */ + if (ps == ps_first) + return ps->next_ps; + + /* go deep */ + if (ps->children) + return ps->children; + + /* find siblings */ + if (ps->next) + return ps->next; + + /* go back for parent siblings */ + while (1) { + if (ps->parent) + if (ps->parent->next) + return ps->parent->next; + ps = ps->parent; + if (!ps) + return ps; + } + + return NULL; +} + +static int ps_filter(struct ps_struct *ps) { + if (!arg_filter) + return 0; + + /* can't draw data when there is only 1 sample (need start + stop) */ + if (ps->first == ps->last) + return -1; + + /* don't filter kthreadd */ + if (ps->pid == 2) + return 0; + + /* drop stuff that doesn't use any real CPU time */ + if (ps->total <= 0.001) + return -1; + + return 0; +} + +static void svg_do_initcall(int count_only) { + _cleanup_pclose_ FILE *f = NULL; + double t; + char func[256]; + int ret; + int usecs; + + /* can't plot initcall when disabled or in relative mode */ + if (!initcall || arg_relative) { + kcount = 0; + return; + } + + if (!count_only) { + svg("\n"); + + svg("Kernel init threads\n"); + /* surrounding box */ + svg_graph_box(kcount); + } + + kcount = 0; + + /* + * Initcall graphing - parses dmesg buffer and displays kernel threads + * This somewhat uses the same methods and scaling to show processes + * but looks a lot simpler. It's overlaid entirely onto the PS graph + * when appropriate. + */ + + f = popen("dmesg", "r"); + if (!f) + return; + + while (!feof(f)) { + int c; + int z = 0; + char l[256]; + + if (fgets(l, sizeof(l) - 1, f) == NULL) + continue; + + c = sscanf(l, "[%lf] initcall %s %*s %d %*s %d %*s", + &t, func, &ret, &usecs); + if (c != 4) { + /* also parse initcalls done by module loading */ + c = sscanf(l, "[%lf] initcall %s %*s %*s %d %*s %d %*s", + &t, func, &ret, &usecs); + if (c != 4) + continue; + } + + /* chop the +0xXX/0xXX stuff */ + while(func[z] != '+') + z++; + func[z] = 0; + + if (count_only) { + /* filter out irrelevant stuff */ + if (usecs >= 1000) + kcount++; + continue; + } + + svg("\n", + func, t, usecs, ret); + + if (usecs < 1000) + continue; + + /* rect */ + svg(" \n", + time_to_graph(t - (usecs / 1000000.0)), + ps_to_graph(kcount), + time_to_graph(usecs / 1000000.0), + ps_to_graph(1)); + + /* label */ + svg(" %s %.03fs\n", + time_to_graph(t - (usecs / 1000000.0)) + 5, + ps_to_graph(kcount) + 15, + func, + usecs / 1000000.0); + + kcount++; + } +} + +static void svg_ps_bars(void) { + struct ps_struct *ps; + int i = 0; + int j = 0; + int pid; + double w = 0.0; + + svg("\n"); + + svg("Processes\n"); + + /* surrounding box */ + svg_graph_box(pcount); + + /* pass 2 - ps boxes */ + ps = ps_first; + while ((ps = get_next_ps(ps))) { + _cleanup_free_ char *enc_name = NULL; + double endtime; + double starttime; + int t; + + enc_name = xml_comment_encode(ps->name); + if (!enc_name) + continue; + + /* leave some trace of what we actually filtered etc. */ + svg("\n", enc_name, ps->pid, + ps->ppid, ps->total); + + starttime = ps->first->sampledata->sampletime; + + if (!ps_filter(ps)) { + /* remember where _to_ our children need to draw a line */ + ps->pos_x = time_to_graph(starttime - graph_start); + ps->pos_y = ps_to_graph(j+1); /* bottom left corner */ + } else if (ps->parent){ + /* hook children to our parent coords instead */ + ps->pos_x = ps->parent->pos_x; + ps->pos_y = ps->parent->pos_y; + + /* if this is the last child, we might still need to draw a connecting line */ + if ((!ps->next) && (ps->parent)) + svg(" \n", + ps->parent->pos_x, + ps_to_graph(j-1) + 10.0, /* whee, use the last value here */ + ps->parent->pos_x, + ps->parent->pos_y); + continue; + } + + endtime = ps->last->sampledata->sampletime; + svg(" \n", + time_to_graph(starttime - graph_start), + ps_to_graph(j), + time_to_graph(ps->last->sampledata->sampletime - starttime), + ps_to_graph(1)); + + /* paint cpu load over these */ + ps->sample = ps->first; + t = 1; + while (ps->sample->next) { + double rt, prt; + double wt, wrt; + struct ps_sched_struct *prev; + + prev = ps->sample; + ps->sample = ps->sample->next; + + /* calculate over interval */ + rt = ps->sample->runtime - prev->runtime; + wt = ps->sample->waittime - prev->waittime; + + prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); + wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); + + /* this can happen if timekeeping isn't accurate enough */ + if (prt > 1.0) + prt = 1.0; + if (wrt > 1.0) + wrt = 1.0; + + if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */ + continue; + + svg(" \n", + time_to_graph(prev->sampledata->sampletime - graph_start), + ps_to_graph(j), + time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), + ps_to_graph(wrt)); + + /* draw cpu over wait - TODO figure out how/why run + wait > interval */ + svg(" \n", + time_to_graph(prev->sampledata->sampletime - graph_start), + ps_to_graph(j + (1.0 - prt)), + time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime), + ps_to_graph(prt)); + t++; + } + + /* determine where to display the process name */ + if ((endtime - starttime) < 1.5) + /* too small to fit label inside the box */ + w = endtime; + else + w = starttime; + + /* text label of process name */ + svg(" %s [%i]%.03fs %s\n", + time_to_graph(w - graph_start) + 5.0, + ps_to_graph(j) + 14.0, + ps->name, + ps->pid, + (ps->last->runtime - ps->first->runtime) / 1000000000.0, + arg_show_cgroup ? ps->cgroup : ""); + /* paint lines to the parent process */ + if (ps->parent) { + /* horizontal part */ + svg(" \n", + time_to_graph(starttime - graph_start), + ps_to_graph(j) + 10.0, + ps->parent->pos_x, + ps_to_graph(j) + 10.0); + + /* one vertical line connecting all the horizontal ones up */ + if (!ps->next) + svg(" \n", + ps->parent->pos_x, + ps_to_graph(j) + 10.0, + ps->parent->pos_x, + ps->parent->pos_y); + } + + j++; /* count boxes */ + + svg("\n"); + } + + /* last pass - determine when idle */ + pid = getpid(); + /* make sure we start counting from the point where we actually have + * data: assume that bootchart's first sample is when data started + */ + + ps = ps_first; + while (ps->next_ps) { + ps = ps->next_ps; + if (ps->pid == pid) + break; + } + + /* need to know last node first */ + ps->sample = ps->first; + i = ps->sample->next->sampledata->counter; + + while (ps->sample->next && i<(samples-(arg_hz/2))) { + double crt; + double brt; + int c; + int ii; + struct ps_sched_struct *sample_hz; + + ps->sample = ps->sample->next; + sample_hz = ps->sample; + for (ii=0;((ii<(int)arg_hz/2)&&(ps->sample->next));ii++) + sample_hz = sample_hz->next; + + /* subtract bootchart cpu utilization from total */ + crt = 0.0; + for (c = 0; c < cpus; c++) + crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c]; + brt = sample_hz->runtime - ps->sample->runtime; + /* + * our definition of "idle": + * + * if for (hz / 2) we've used less CPU than (interval / 2) ... + * defaults to 4.0%, which experimentally, is where atom idles + */ + if ((crt - brt) < (interval / 2.0)) { + idletime = ps->sample->sampledata->sampletime - graph_start; + svg("\n\n", + idletime); + svg("\n", + time_to_graph(idletime), + -arg_scale_y, + time_to_graph(idletime), + ps_to_graph(pcount) + arg_scale_y); + svg("%.01fs\n", + time_to_graph(idletime) + 5.0, + ps_to_graph(pcount) + arg_scale_y, + idletime); + break; + } + i++; + } +} + +static void svg_top_ten_cpu(void) { + struct ps_struct *top[10]; + struct ps_struct emptyps = {}; + struct ps_struct *ps; + int n, m; + + for (n = 0; n < (int) ELEMENTSOF(top); n++) + top[n] = &emptyps; + + /* walk all ps's and setup ptrs */ + ps = ps_first; + while ((ps = get_next_ps(ps))) { + for (n = 0; n < 10; n++) { + if (ps->total <= top[n]->total) + continue; + /* cascade insert */ + for (m = 9; m > n; m--) + top[m] = top[m-1]; + top[n] = ps; + break; + } + } + + svg("Top CPU consumers:\n"); + for (n = 0; n < 10; n++) + svg("%3.03fs - %s [%d]\n", + 20 + (n * 13), + top[n]->total, + top[n]->name, + top[n]->pid); +} + +static void svg_top_ten_pss(void) { + struct ps_struct *top[10]; + struct ps_struct emptyps = {}; + struct ps_struct *ps; + int n, m; + + for (n = 0; n < (int) ELEMENTSOF(top); n++) + top[n] = &emptyps; + + /* walk all ps's and setup ptrs */ + ps = ps_first; + while ((ps = get_next_ps(ps))) { + for (n = 0; n < 10; n++) { + if (ps->pss_max <= top[n]->pss_max) + continue; + /* cascade insert */ + for (m = 9; m > n; m--) + top[m] = top[m-1]; + top[n] = ps; + break; + } + } + + svg("Top PSS consumers:\n"); + for (n = 0; n < 10; n++) + svg("%dK - %s [%d]\n", + 20 + (n * 13), + top[n]->pss_max, + top[n]->name, + top[n]->pid); +} + +void svg_do(const char *build) { + struct ps_struct *ps; + + memzero(&str, sizeof(str)); + + ps = ps_first; + + /* count initcall thread count first */ + svg_do_initcall(1); + ksize = (kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0); + + /* then count processes */ + while ((ps = get_next_ps(ps))) { + if (!ps_filter(ps)) + pcount++; + else + pfiltered++; + } + psize = ps_to_graph(pcount) + (arg_scale_y * 2); + + esize = (arg_entropy ? arg_scale_y * 7 : 0); + + /* after this, we can draw the header with proper sizing */ + svg_header(); + + svg("\n"); + svg_io_bi_bar(); + svg("\n\n"); + + svg("\n", 400.0 + (arg_scale_y * 7.0)); + svg_io_bo_bar(); + svg("\n\n"); + + svg("\n", 400.0 + (arg_scale_y * 14.0)); + svg_cpu_bar(); + svg("\n\n"); + + svg("\n", 400.0 + (arg_scale_y * 21.0)); + svg_wait_bar(); + svg("\n\n"); + + if (kcount) { + svg("\n", 400.0 + (arg_scale_y * 28.0)); + svg_do_initcall(0); + svg("\n\n"); + } + + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize); + svg_ps_bars(); + svg("\n\n"); + + svg("\n"); + svg_title(build); + svg("\n\n"); + + svg("\n"); + svg_top_ten_cpu(); + svg("\n\n"); + + if (arg_entropy) { + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize + psize); + svg_entropy_bar(); + svg("\n\n"); + } + + if (arg_pss) { + svg("\n", 400.0 + (arg_scale_y * 28.0) + ksize + psize + esize); + svg_pss_graph(); + svg("\n\n"); + + svg("\n"); + svg_top_ten_pss(); + svg("\n\n"); + } + + /* svg footer */ + svg("\n\n"); +} diff --git a/src/bootchart/svg.h b/src/bootchart/svg.h new file mode 100644 index 0000000..df3a7bf --- /dev/null +++ b/src/bootchart/svg.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2009-2013 Intel Corporation + + Authors: + Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +void svg_do(const char *build); diff --git a/src/bridge.c b/src/bridge.c deleted file mode 100644 index 878856c..0000000 --- a/src/bridge.c +++ /dev/null @@ -1,367 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "socket-util.h" - -#define BUFFER_SIZE (64*1024) -#define EXTRA_SIZE 16 - -static bool initial_nul = false; -static bool auth_over = false; - -static void format_uid(char *buf, size_t l) { - char text[20 + 1]; /* enough space for a 64bit integer plus NUL */ - unsigned j; - - assert(l > 0); - - snprintf(text, sizeof(text)-1, "%llu", (unsigned long long) geteuid()); - text[sizeof(text)-1] = 0; - - memset(buf, 0, l); - - for (j = 0; text[j] && j*2+2 < l; j++) { - buf[j*2] = hexchar(text[j] >> 4); - buf[j*2+1] = hexchar(text[j] & 0xF); - } - - buf[j*2] = 0; -} - -static size_t patch_in_line(char *line, size_t l, size_t left) { - size_t r; - - if (line[0] == 0 && !initial_nul) { - initial_nul = true; - line += 1; - l -= 1; - r = 1; - } else - r = 0; - - if (l == 5 && strncmp(line, "BEGIN", 5) == 0) { - r += l; - auth_over = true; - - } else if (l == 17 && strncmp(line, "NEGOTIATE_UNIX_FD", 17) == 0) { - memmove(line + 13, line + 17, left); - memcpy(line, "NEGOTIATE_NOP", 13); - r += 13; - - } else if (l >= 14 && strncmp(line, "AUTH EXTERNAL ", 14) == 0) { - char uid[20*2 + 1]; - size_t len; - - format_uid(uid, sizeof(uid)); - len = strlen(uid); - assert(len <= EXTRA_SIZE); - - memmove(line + 14 + len, line + l, left); - memcpy(line + 14, uid, len); - - r += 14 + len; - } else - r += l; - - return r; -} - -static size_t patch_in_buffer(char* in_buffer, size_t *in_buffer_full) { - size_t i, good = 0; - - if (*in_buffer_full <= 0) - return *in_buffer_full; - - /* If authentication is done, we don't touch anything anymore */ - if (auth_over) - return *in_buffer_full; - - if (*in_buffer_full < 2) - return 0; - - for (i = 0; i <= *in_buffer_full - 2; i ++) { - - /* Fully lines can be send on */ - if (in_buffer[i] == '\r' && in_buffer[i+1] == '\n') { - if (i > good) { - size_t old_length, new_length; - - old_length = i - good; - new_length = patch_in_line(in_buffer+good, old_length, *in_buffer_full - i); - *in_buffer_full = *in_buffer_full + new_length - old_length; - - good += new_length + 2; - - } else - good = i+2; - } - - if (auth_over) - break; - } - - return good; -} - -int main(int argc, char *argv[]) { - int r = EXIT_FAILURE, fd = -1, ep = -1; - union sockaddr_union sa; - char in_buffer[BUFFER_SIZE+EXTRA_SIZE], out_buffer[BUFFER_SIZE+EXTRA_SIZE]; - size_t in_buffer_full = 0, out_buffer_full = 0; - struct epoll_event stdin_ev, stdout_ev, fd_ev; - bool stdin_readable = false, stdout_writable = false, fd_readable = false, fd_writable = false; - bool stdin_rhup = false, stdout_whup = false, fd_rhup = false, fd_whup = false; - - if (argc > 1) { - log_error("This program takes no argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("Failed to create socket: %s", strerror(errno)); - goto finish; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/dbus/system_bus_socket", sizeof(sa.un.sun_path)); - - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { - log_error("Failed to connect: %m"); - goto finish; - } - - fd_nonblock(STDIN_FILENO, 1); - fd_nonblock(STDOUT_FILENO, 1); - - if ((ep = epoll_create1(EPOLL_CLOEXEC)) < 0) { - log_error("Failed to create epoll: %m"); - goto finish; - } - - zero(stdin_ev); - stdin_ev.events = EPOLLIN|EPOLLET; - stdin_ev.data.fd = STDIN_FILENO; - - zero(stdout_ev); - stdout_ev.events = EPOLLOUT|EPOLLET; - stdout_ev.data.fd = STDOUT_FILENO; - - zero(fd_ev); - fd_ev.events = EPOLLIN|EPOLLOUT|EPOLLET; - fd_ev.data.fd = fd; - - if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 || - epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 || - epoll_ctl(ep, EPOLL_CTL_ADD, fd, &fd_ev) < 0) { - log_error("Failed to regiser fds in epoll: %m"); - goto finish; - } - - do { - struct epoll_event ev[16]; - ssize_t k; - int i, nfds; - - if ((nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1)) < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - log_error("epoll_wait(): %m"); - goto finish; - } - - assert(nfds >= 1); - - for (i = 0; i < nfds; i++) { - if (ev[i].data.fd == STDIN_FILENO) { - - if (!stdin_rhup && (ev[i].events & (EPOLLHUP|EPOLLIN))) - stdin_readable = true; - - } else if (ev[i].data.fd == STDOUT_FILENO) { - - if (ev[i].events & EPOLLHUP) { - stdout_writable = false; - stdout_whup = true; - } - - if (!stdout_whup && (ev[i].events & EPOLLOUT)) - stdout_writable = true; - - } else if (ev[i].data.fd == fd) { - - if (ev[i].events & EPOLLHUP) { - fd_writable = false; - fd_whup = true; - } - - if (!fd_rhup && (ev[i].events & (EPOLLHUP|EPOLLIN))) - fd_readable = true; - - if (!fd_whup && (ev[i].events & EPOLLOUT)) - fd_writable = true; - } - } - - while ((stdin_readable && in_buffer_full <= 0) || - (fd_writable && patch_in_buffer(in_buffer, &in_buffer_full) > 0) || - (fd_readable && out_buffer_full <= 0) || - (stdout_writable && out_buffer_full > 0)) { - - size_t in_buffer_good = 0; - - if (stdin_readable && in_buffer_full < BUFFER_SIZE) { - - if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, BUFFER_SIZE - in_buffer_full)) < 0) { - - if (errno == EAGAIN) - stdin_readable = false; - else if (errno == EPIPE || errno == ECONNRESET) - k = 0; - else { - log_error("read(): %m"); - goto finish; - } - } else - in_buffer_full += (size_t) k; - - if (k == 0) { - stdin_rhup = true; - stdin_readable = false; - shutdown(STDIN_FILENO, SHUT_RD); - close_nointr_nofail(STDIN_FILENO); - } - } - - in_buffer_good = patch_in_buffer(in_buffer, &in_buffer_full); - - if (fd_writable && in_buffer_good > 0) { - - if ((k = write(fd, in_buffer, in_buffer_good)) < 0) { - - if (errno == EAGAIN) - fd_writable = false; - else if (errno == EPIPE || errno == ECONNRESET) { - fd_whup = true; - fd_writable = false; - shutdown(fd, SHUT_WR); - } else { - log_error("write(): %m"); - goto finish; - } - - } else { - assert(in_buffer_full >= (size_t) k); - memmove(in_buffer, in_buffer + k, in_buffer_full - k); - in_buffer_full -= k; - } - } - - if (fd_readable && out_buffer_full < BUFFER_SIZE) { - - if ((k = read(fd, out_buffer + out_buffer_full, BUFFER_SIZE - out_buffer_full)) < 0) { - - if (errno == EAGAIN) - fd_readable = false; - else if (errno == EPIPE || errno == ECONNRESET) - k = 0; - else { - log_error("read(): %m"); - goto finish; - } - } else - out_buffer_full += (size_t) k; - - if (k == 0) { - fd_rhup = true; - fd_readable = false; - shutdown(fd, SHUT_RD); - } - } - - if (stdout_writable && out_buffer_full > 0) { - - if ((k = write(STDOUT_FILENO, out_buffer, out_buffer_full)) < 0) { - - if (errno == EAGAIN) - stdout_writable = false; - else if (errno == EPIPE || errno == ECONNRESET) { - stdout_whup = true; - stdout_writable = false; - shutdown(STDOUT_FILENO, SHUT_WR); - close_nointr(STDOUT_FILENO); - } else { - log_error("write(): %m"); - goto finish; - } - - } else { - assert(out_buffer_full >= (size_t) k); - memmove(out_buffer, out_buffer + k, out_buffer_full - k); - out_buffer_full -= k; - } - } - } - - if (stdin_rhup && in_buffer_full <= 0 && !fd_whup) { - fd_whup = true; - fd_writable = false; - shutdown(fd, SHUT_WR); - } - - if (fd_rhup && out_buffer_full <= 0 && !stdout_whup) { - stdout_whup = true; - stdout_writable = false; - shutdown(STDOUT_FILENO, SHUT_WR); - close_nointr(STDOUT_FILENO); - } - - } while (!stdout_whup || !fd_whup); - - r = EXIT_SUCCESS; - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - if (ep >= 0) - close_nointr_nofail(ep); - - return r; -} diff --git a/src/build.h b/src/build.h deleted file mode 100644 index 50cd79d..0000000 --- a/src/build.h +++ /dev/null @@ -1,63 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foobuildhfoo -#define foobuildhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#ifdef HAVE_PAM -#define _PAM_FEATURE_ "+PAM" -#else -#define _PAM_FEATURE_ "-PAM" -#endif - -#ifdef HAVE_LIBWRAP -#define _LIBWRAP_FEATURE_ "+LIBWRAP" -#else -#define _LIBWRAP_FEATURE_ "-LIBWRAP" -#endif - -#ifdef HAVE_AUDIT -#define _AUDIT_FEATURE_ "+AUDIT" -#else -#define _AUDIT_FEATURE_ "-AUDIT" -#endif - -#ifdef HAVE_SELINUX -#define _SELINUX_FEATURE_ "+SELINUX" -#else -#define _SELINUX_FEATURE_ "-SELINUX" -#endif - -#ifdef HAVE_SYSV_COMPAT -#define _SYSVINIT_FEATURE_ "+SYSVINIT" -#else -#define _SYSVINIT_FEATURE_ "-SYSVINIT" -#endif - -#ifdef HAVE_LIBCRYPTSETUP -#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" -#else -#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" -#endif - -#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ - -#endif diff --git a/src/bus-driverd/Makefile b/src/bus-driverd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/bus-driverd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/bus-driverd/bus-driverd.c b/src/bus-driverd/bus-driverd.c new file mode 100644 index 0000000..5405960 --- /dev/null +++ b/src/bus-driverd/bus-driverd.c @@ -0,0 +1,957 @@ +/*** + This file is part of systemd. + + Copyright 2013 Daniel Mack + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdbus.h" +#include "sd-bus.h" +#include "bus-internal.h" +#include "sd-daemon.h" +#include "sd-event.h" +#include "event-util.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-message.h" +#include "bus-kernel.h" +#include "socket-util.h" +#include "util.h" +#include "build.h" +#include "strv.h" +#include "sd-id128.h" +#include "async.h" +#include "hashmap.h" +#include "def.h" +#include "unit-name.h" +#include "bus-control.h" +#include "cgroup-util.h" + +#define CLIENTS_MAX 1024 +#define MATCHES_MAX 1024 + +typedef struct Match Match; +typedef struct Client Client; +typedef struct Context Context; + +struct Match { + Client *client; + char *match; + uint64_t cookie; + LIST_FIELDS(Match, matches); +}; + +struct Client { + Context *context; + uint64_t id; + uint64_t next_cookie; + Hashmap *matches; + unsigned n_matches; + char *watch; +}; + +struct Context { + sd_bus *bus; + sd_event *event; + Hashmap *clients; +}; + +static void match_free(Match *m) { + + if (!m) + return; + + if (m->client) { + Match *first; + + first = hashmap_get(m->client->matches, m->match); + LIST_REMOVE(matches, first, m); + if (first) + assert_se(hashmap_replace(m->client->matches, first->match, first) >= 0); + else + hashmap_remove(m->client->matches, m->match); + + m->client->n_matches--; + } + + free(m->match); + free(m); +} + +static int match_new(Client *c, struct bus_match_component *components, unsigned n_components, Match **_m) { + Match *m, *first; + int r; + + assert(c); + assert(_m); + + r = hashmap_ensure_allocated(&c->matches, string_hash_func, string_compare_func); + if (r < 0) + return r; + + m = new0(Match, 1); + if (!m) + return -ENOMEM; + + m->match = bus_match_to_string(components, n_components); + if (!m->match) { + r = -ENOMEM; + goto fail; + } + + m->cookie = ++c->next_cookie; + + first = hashmap_get(c->matches, m->match); + LIST_PREPEND(matches, first, m); + r = hashmap_replace(c->matches, m->match, first); + if (r < 0) { + LIST_REMOVE(matches, first, m); + goto fail; + } + + m->client = c; + c->n_matches++; + + *_m = m; + m = NULL; + + return 0; + +fail: + match_free(m); + return r; +} + +static int on_name_owner_changed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error); + +static void client_free(Client *c) { + Match *m; + + if (!c) + return; + + if (c->context) { + if (c->watch) + sd_bus_remove_match(c->context->bus, c->watch, on_name_owner_changed, c); + + assert_se(hashmap_remove(c->context->clients, &c->id) == c); + } + + while ((m = hashmap_first(c->matches))) + match_free(m); + + hashmap_free(c->matches); + free(c->watch); + + free(c); +} + +static int on_name_owner_changed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Client *c = userdata; + + assert(bus); + assert(m); + + client_free(c); + return 0; +} + +static int client_acquire(Context *context, uint64_t id, Client **_c) { + char *watch = NULL; + Client *c; + int r; + + assert(context); + assert(_c); + + c = hashmap_get(context->clients, &id); + if (c) { + *_c = c; + return 0; + } + + if (hashmap_size(context->clients) >= CLIENTS_MAX) + return -ENOBUFS; + + r = hashmap_ensure_allocated(&context->clients, uint64_hash_func, uint64_compare_func); + if (r < 0) + return r; + + c = new0(Client, 1); + if (!c) + return -ENOMEM; + + c->id = id; + + r = hashmap_put(context->clients, &c->id, c); + if (r < 0) + goto fail; + + c->context = context; + + if (asprintf(&watch, + "type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg0=':1.%llu'", (unsigned long long) id) < 0) { + r = -ENOMEM; + goto fail; + } + + r = sd_bus_add_match(context->bus, watch, on_name_owner_changed, c); + if (r < 0) { + free(watch); + goto fail; + } + + c->watch = watch; + + *_c = c; + return 0; + +fail: + client_free(c); + return r; +} + +static int driver_add_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + + struct bus_match_component *components = NULL; + Context *context = userdata; + unsigned n_components = 0; + Match *m = NULL; + Client *c = NULL; + char *arg0; + uint64_t id; + int r; + + assert(bus); + assert(message); + assert(context); + + r = sd_bus_message_read(message, "s", &arg0); + if (r < 0) + return r; + + r = bus_kernel_parse_unique_name(message->sender, &id); + if (r < 0) + return r; + + r = client_acquire(context, id, &c); + if (r == -ENOBUFS) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u clients", CLIENTS_MAX); + if (r < 0) + return r; + + if (c->n_matches >= MATCHES_MAX) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u matches per client", MATCHES_MAX); + goto fail; + } + + r = bus_match_parse(arg0, &components, &n_components); + if (r < 0) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0); + goto fail; + } + + r = match_new(c, components, n_components, &m); + if (r < 0) + goto fail; + + r = bus_add_match_internal_kernel(bus, id, components, n_components, m->cookie); + if (r < 0) + goto fail; + + bus_match_parse_free(components, n_components); + + return sd_bus_reply_method_return(message, NULL); + +fail: + bus_match_parse_free(components, n_components); + + match_free(m); + + if (c->n_matches <= 0) + client_free(c); + + return r; +} + +static int driver_remove_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + + struct bus_match_component *components = NULL; + _cleanup_free_ char *normalized = NULL; + Context *context = userdata; + unsigned n_components = 0; + Client *c = NULL; + Match *m = NULL; + char *arg0; + uint64_t id; + int r; + + assert(bus); + assert(message); + assert(context); + + r = sd_bus_message_read(message, "s", &arg0); + if (r < 0) + return r; + + r = bus_kernel_parse_unique_name(message->sender, &id); + if (r < 0) + return r; + + c = hashmap_get(context->clients, &id); + if (!c) + return sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "You have not registered any matches."); + + r = bus_match_parse(arg0, &components, &n_components); + if (r < 0) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0); + goto finish; + } + + normalized = bus_match_to_string(components, n_components); + if (!normalized) { + r = -ENOMEM; + goto finish; + } + + m = hashmap_get(c->matches, normalized); + if (!m) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule \"%s\" not found.", normalized); + goto finish; + } + + bus_remove_match_internal_kernel(bus, id, m->cookie); + match_free(m); + + r = sd_bus_reply_method_return(message, NULL); + +finish: + bus_match_parse_free(components, n_components); + + if (c->n_matches <= 0) + client_free(c); + + return r; +} + +static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + int r; + + assert(bus); + assert(name); + assert(_creds); + + assert_return(service_name_is_valid(name), -EINVAL); + + r = sd_bus_get_owner(bus, name, mask, &c); + if (r == -ENOENT || r == -ENXIO) + return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name); + if (r < 0) + return r; + + if ((c->mask & mask) != mask) + return -ENOTSUP; + + *_creds = c; + c = NULL; + + return 0; +} + + +static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { + const char *name; + int r; + + assert(bus); + assert(m); + assert(_creds); + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + + return get_creds_by_name(bus, name, mask, _creds, error); +} + +static int driver_get_security_context(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + int r; + + r = get_creds_by_message(bus, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, error); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label)); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + int r; + + r = get_creds_by_message(bus, m, SD_BUS_CREDS_PID, &creds, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "u", (uint32_t) creds->pid); +} + +static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + int r; + + r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "u", (uint32_t) creds->uid); +} + +static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + const char *name; + int r; + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + + /* Here's a special exception for compatibility with dbus1: + * the bus name of the driver is owned by itself, not by a + * unique ID. */ + if (streq(name, "org.freedesktop.DBus")) + return sd_bus_reply_method_return(m, "s", "org.freedesktop.DBus"); + + r = get_creds_by_name(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "s", creds->unique_name); +} + +static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + sd_id128_t server_id; + char buf[SD_ID128_STRING_MAX]; + int r; + + r = sd_bus_get_server_id(bus, &server_id); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf)); +} + +static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + return sd_bus_reply_method_return(m, "s", m->sender); +} + +static int return_strv(sd_bus *bus, sd_bus_message *m, char **l) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(reply, l); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **names = NULL; + int r; + + r = sd_bus_list_names(bus, &names, NULL); + if (r < 0) + return r; + + /* Let's sort the names list to make it stable */ + strv_sort(names); + + return return_strv(bus, m, names); +} + +static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **names = NULL; + int r; + + r = sd_bus_list_names(bus, NULL, &names); + if (r < 0) + return r; + + /* Let's sort the names list to make it stable */ + strv_sort(names); + + return return_strv(bus, m, names); +} + +static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + struct kdbus_cmd_name_list cmd = {}; + struct kdbus_name_list *name_list; + struct kdbus_cmd_name *name; + _cleanup_strv_free_ char **owners = NULL; + char *arg0; + int r; + + r = sd_bus_message_read(m, "s", &arg0); + if (r < 0) + return r; + + assert_return(service_name_is_valid(arg0), -EINVAL); + + cmd.flags = KDBUS_NAME_LIST_QUEUED; + + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd); + if (r < 0) + return -errno; + + name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); + + KDBUS_ITEM_FOREACH(name, name_list, names) { + char *n; + + if (name->size <= sizeof(*name)) + continue; + + if (!streq(name->name, arg0)) + continue; + + if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) + return -ENOMEM; + + r = strv_push(&owners, n); + if (r < 0) { + free(n); + return -ENOMEM; + } + } + + r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset); + if (r < 0) + return -errno; + + return return_strv(bus, m, owners); +} + +static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + const char *name; + int r; + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + + assert_return(service_name_is_valid(name), -EINVAL); + + r = sd_bus_get_owner(bus, name, 0, NULL); + if (r < 0 && r != -ENOENT && r != -ENXIO) + return r; + + return sd_bus_reply_method_return(m, "b", r >= 0); +} + +static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + struct kdbus_cmd_name *n; + uint32_t flags; + size_t size, l; + uint64_t id; + const char *name; + int r; + + r = sd_bus_message_read(m, "su", &name, &flags); + if (r < 0) + return r; + + assert_return(service_name_is_valid(name), -EINVAL); + assert_return((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) == 0, -EINVAL); + + l = strlen(name); + size = offsetof(struct kdbus_cmd_name, name) + l + 1; + n = alloca0(size); + n->size = size; + memcpy(n->name, name, l+1); + kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); + + /* This function is open-coded because we request the name 'on behalf' + * of the requesting connection */ + r = bus_kernel_parse_unique_name(m->sender, &id); + if (r < 0) + return r; + + n->owner_id = id; + + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n); + if (r < 0) { + if (errno == EEXIST) + return sd_bus_reply_method_return(m, "u", BUS_NAME_EXISTS); + if (errno == EALREADY) + return sd_bus_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER); + + return -errno; + } + + if (n->flags & KDBUS_NAME_IN_QUEUE) + return sd_bus_reply_method_return(m, "u", BUS_NAME_IN_QUEUE); + + return sd_bus_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER); +} + +static int driver_release_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + struct kdbus_cmd_name *n; + const char *name; + size_t l, size; + uint64_t id; + int r; + + r = sd_bus_message_read(m, "s", &name); + if (r < 0) + return r; + + assert_return(service_name_is_valid(name), -EINVAL); + + l = strlen(name); + size = offsetof(struct kdbus_cmd_name, name) + l + 1; + n = alloca0(size); + n->size = size; + memcpy(n->name, name, l+1); + + /* This function is open-coded because we request the name 'on behalf' + * of the requesting connection */ + r = bus_kernel_parse_unique_name(m->sender, &id); + if (r < 0) + return r; + + n->owner_id = id; + + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n); + if (r < 0) { + if (errno == ESRCH) + return sd_bus_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); + if (errno == EADDRINUSE) + return sd_bus_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); + return -errno; + } + + return sd_bus_reply_method_return(m, "u", BUS_NAME_RELEASED); +} + +static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **t = NULL; + _cleanup_free_ char *path = NULL; + uint32_t flags; + char *name, *u; + int r; + + r = sd_bus_message_read(m, "su", &name, &flags); + if (r < 0) + return r; + + assert_return(service_name_is_valid(name), -EINVAL); + assert_return(flags == 0, -ENOTSUP); + + r = sd_bus_get_owner(bus, name, 0, NULL); + if (r >= 0) + return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING); + if (r != -ENOENT) + return r; + + u = strappenda(name, ".busname"); + + path = unit_dbus_path_from_name(u); + if (!path) + return -ENOMEM; + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "Triggers", + error, + &t); + if (r < 0) + return r; + + if (!t || !t[0] || t[1]) + return sd_bus_error_setf(error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Bus name %s not found.", name); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + error, + &reply, + "ss", + t[0], + "replace"); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS); +} + +static int driver_update_environment(sd_bus*bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; + _cleanup_strv_free_ char **args = NULL; + int r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) { + _cleanup_free_ char *s = NULL; + const char *key; + const char *value; + + r = sd_bus_message_read(m, "ss", &key, &value); + if (r < 0) + return r; + + s = strjoin(key, "=", value, NULL); + if (!s) + return ENOMEM; + + r = strv_extend(&args, s); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (!args) + return -EINVAL; + + r = sd_bus_message_new_method_call( + bus, + &msg, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetEnvironment"); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(msg, args); + if (r < 0) + return r; + + r = sd_bus_call(bus, msg, 0, NULL, NULL); + if (r < 0) + return r; + + return sd_bus_reply_method_return(m, NULL); +} + +static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m)); +} + +static const sd_bus_vtable driver_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_context, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Hello", NULL, "s", driver_hello, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReleaseName", "s", "u", driver_release_name, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, SD_BUS_VTABLE_DEPRECATED), + SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_update_environment, 0), + SD_BUS_SIGNAL("NameAcquired", "s", SD_BUS_VTABLE_DEPRECATED), + SD_BUS_SIGNAL("NameLost", "s", SD_BUS_VTABLE_DEPRECATED), + SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0), + SD_BUS_VTABLE_END +}; + +static int find_object( + sd_bus *bus, + const char *path, + const char *interface, + void *userdata, + void **ret_found, + sd_bus_error *ret_error) { + + /* We support the driver interface on exactly two different + * paths: the root and the entry point object. This is a bit + * different from the original dbus-daemon which supported it + * on any path. */ + + if (streq_ptr(path, "/")) + return 1; + + if (streq_ptr(path, "/org/freedesktop/DBus")) + return 1; + + return 0; +} + +static int node_enumerator( + sd_bus *bus, + const char *path, + void *userdata, + char ***ret_nodes, + sd_bus_error *ret_error) { + + char **l; + + l = strv_new("/", "/org/freedesktop/DBus", NULL); + if (!l) + return -ENOMEM; + + *ret_nodes = l; + return 0; +} + +static int connect_bus(Context *c) { + int r; + + assert(c); + + r = sd_bus_default(&c->bus); + if (r < 0) { + log_error("Failed to create bus: %s", strerror(-r)); + return r; + } + + if (!c->bus->is_kernel) { + log_error("Not running on kdbus"); + return -EPERM; + } + + r = sd_bus_add_fallback_vtable(c->bus, "/", "org.freedesktop.DBus", driver_vtable, find_object, c); + if (r < 0) { + log_error("Failed to add manager object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(c->bus, "/", node_enumerator, c); + if (r < 0) { + log_error("Failed to add node enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_request_name(c->bus, "org.freedesktop.DBus", 0); + if (r < 0) { + log_error("Unable to request name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(c->bus, c->event, 0); + if (r < 0) { + log_error("Error while adding bus to event loop: %s", strerror(-r)); + return r; + } + + return 0; +} + +static bool check_idle(void *userdata) { + Context *c = userdata; + assert(c); + + return hashmap_isempty(c->clients); +} + +int main(int argc, char *argv[]) { + Context context = {}; + Client *c; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + r = sd_event_default(&context.event); + if (r < 0) { + log_error("Failed to allocate event loop: %s", strerror(-r)); + goto finish; + } + + sd_event_set_watchdog(context.event, true); + + r = connect_bus(&context); + if (r < 0) + goto finish; + + r = bus_event_loop_with_idle(context.event, context.bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC, check_idle, &context); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + goto finish; + } + +finish: + while ((c = hashmap_first(context.clients))) + client_free(c); + + sd_bus_unref(context.bus); + sd_event_unref(context.event); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/bus-errors.h b/src/bus-errors.h deleted file mode 100644 index 82d4e99..0000000 --- a/src/bus-errors.h +++ /dev/null @@ -1,58 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foobuserrorshfoo -#define foobuserrorshfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" -#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" -#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" -#define BUS_ERROR_INVALID_PATH "org.freedesktop.systemd1.InvalidPath" -#define BUS_ERROR_INVALID_NAME "org.freedesktop.systemd1.InvalidName" -#define BUS_ERROR_UNIT_TYPE_MISMATCH "org.freedesktop.systemd1.UnitTypeMismatch" -#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" -#define BUS_ERROR_NOT_SUPPORTED "org.freedesktop.systemd1.NotSupported" -#define BUS_ERROR_INVALID_JOB_MODE "org.freedesktop.systemd1.InvalidJobMode" -#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" -#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" -#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" -#define BUS_ERROR_MASKED "org.freedesktop.systemd1.Masked" -#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" -#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" -#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting" -#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" -#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" -#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" - -static inline const char *bus_error(const DBusError *e, int r) { - if (e && e->message) - return e->message; - - if (r >= 0) - return strerror(r); - - return strerror(-r); -} - -#endif diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/bus-proxyd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c new file mode 100644 index 0000000..b9e4d9d --- /dev/null +++ b/src/bus-proxyd/bus-proxyd.c @@ -0,0 +1,784 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "socket-util.h" +#include "sd-daemon.h" +#include "sd-bus.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-util.h" +#include "build.h" +#include "strv.h" +#include "def.h" + +static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH; +static char *arg_command_line_buffer = NULL; + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Connect STDIO or a socket to a given bus address.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --address=ADDRESS Connect to the bus specified by ADDRESS\n" + " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_ADDRESS, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "address", required_argument, NULL, ARG_ADDRESS }, + { NULL, 0, NULL, 0 } + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_ADDRESS: + arg_address = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + /* If the first command line argument is only "x" characters + * we'll write who we are talking to into it, so that "ps" is + * explanatory */ + arg_command_line_buffer = argv[optind]; + if (argc > optind + 1 || + (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) { + log_error("Too many arguments"); + return -EINVAL; + } + + return 1; +} + +static int rename_service(sd_bus *a, sd_bus *b) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_free_ char *p = NULL, *name = NULL; + const char *comm; + char **cmdline; + uid_t uid; + pid_t pid; + int r; + + assert(a); + assert(b); + + r = sd_bus_get_peer_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + r = sd_bus_creds_get_cmdline(creds, &cmdline); + if (r < 0) + return r; + + r = sd_bus_creds_get_comm(creds, &comm); + if (r < 0) + return r; + + name = uid_to_name(uid); + if (!name) + return -ENOMEM; + + p = strv_join(cmdline, " "); + if (!p) + return -ENOMEM; + + /* The status string gets the full command line ... */ + sd_notifyf(false, + "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", + pid, p, + uid, name); + + /* ... and the argv line only the short comm */ + if (arg_command_line_buffer) { + size_t m, w; + + m = strlen(arg_command_line_buffer); + w = snprintf(arg_command_line_buffer, m, + "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", + pid, comm, + uid, name); + + if (m > w) + memzero(arg_command_line_buffer + w, m - w); + } + + log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", + pid, p, + uid, name, + a->unique_name); + ; + return 0; +} + +static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) { + _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + const char *name, *old_owner, *new_owner; + int r; + + assert(a); + assert(b); + assert(m); + + /* If we get NameOwnerChanged for our own name, we need to + * synthesize NameLost/NameAcquired, since socket clients need + * that, even though it is obsoleted on kdbus */ + + if (!a->is_kernel) + return 0; + + if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") || + !streq_ptr(m->path, "/org/freedesktop/DBus") || + !streq_ptr(m->sender, "org.freedesktop.DBus")) + return 0; + + r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner); + if (r < 0) + return r; + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + if (streq(old_owner, a->unique_name)) { + + r = sd_bus_message_new_signal( + b, + &n, + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "NameLost"); + + } else if (streq(new_owner, a->unique_name)) { + + r = sd_bus_message_new_signal( + b, + &n, + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "NameAcquired"); + } else + return 0; + + if (r < 0) + return r; + + r = sd_bus_message_append(n, "s", name); + if (r < 0) + return r; + + r = bus_message_append_sender(n, "org.freedesktop.DBus"); + if (r < 0) + return r; + + r = bus_seal_synthetic_message(b, n); + if (r < 0) + return r; + + return sd_bus_send(b, n, NULL); +} + +static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) { + _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + int r; + + assert(a); + assert(b); + assert(m); + + if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) + return 0; + + if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave")) + return 0; + + r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid"); + if (r < 0) + return r; + + r = bus_message_append_sender(n, "org.freedesktop.DBus"); + if (r < 0) { + log_error("Failed to append sender to gdm reply: %s", strerror(-r)); + return r; + } + + r = bus_seal_synthetic_message(b, n); + if (r < 0) { + log_error("Failed to seal gdm reply: %s", strerror(-r)); + return r; + } + + r = sd_bus_send(b, n, NULL); + if (r < 0) { + log_error("Failed to send gdm reply: %s", strerror(-r)); + return r; + } + + return 1; +} + +static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) { + _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + bool is_hello; + int r; + + assert(a); + assert(b); + assert(m); + assert(got_hello); + + /* As reaction to hello we need to respond with two messages: + * the callback reply and the NameAcquired for the unique + * name, since hello is otherwise obsolete on kdbus. */ + + is_hello = + sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && + streq_ptr(m->destination, "org.freedesktop.DBus"); + + if (!is_hello) { + + if (*got_hello) + return 0; + + log_error("First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member); + return -EIO; + } + + if (*got_hello) { + log_error("Got duplicate hello, aborting."); + return -EIO; + } + + *got_hello = true; + + if (!a->is_kernel) + return 0; + + r = sd_bus_message_new_method_return(m, &n); + if (r < 0) { + log_error("Failed to generate HELLO reply: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_append(n, "s", a->unique_name); + if (r < 0) { + log_error("Failed to append unique name to HELLO reply: %s", strerror(-r)); + return r; + } + + r = bus_message_append_sender(n, "org.freedesktop.DBus"); + if (r < 0) { + log_error("Failed to append sender to HELLO reply: %s", strerror(-r)); + return r; + } + + r = bus_seal_synthetic_message(b, n); + if (r < 0) { + log_error("Failed to seal HELLO reply: %s", strerror(-r)); + return r; + } + + r = sd_bus_send(b, n, NULL); + if (r < 0) { + log_error("Failed to send HELLO reply: %s", strerror(-r)); + return r; + } + + n = sd_bus_message_unref(n); + r = sd_bus_message_new_signal( + b, + &n, + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "NameAcquired"); + if (r < 0) { + log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_append(n, "s", a->unique_name); + if (r < 0) { + log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r)); + return r; + } + + r = bus_message_append_sender(n, "org.freedesktop.DBus"); + if (r < 0) { + log_error("Failed to append sender to NameAcquired message: %s", strerror(-r)); + return r; + } + + r = bus_seal_synthetic_message(b, n); + if (r < 0) { + log_error("Failed to seal NameAcquired message: %s", strerror(-r)); + return r; + } + + r = sd_bus_send(b, n, NULL); + if (r < 0) { + log_error("Failed to send NameAcquired message: %s", strerror(-r)); + return r; + } + + return 1; +} + +static int patch_sender(sd_bus *a, sd_bus_message *m) { + char **well_known = NULL; + sd_bus_creds *c; + int r; + + assert(a); + assert(m); + + if (!a->is_kernel) + return 0; + + /* We will change the sender of messages from the bus driver + * so that they originate from the bus driver. This is a + * speciality originating from dbus1, where the bus driver did + * not have a unique id, but only the well-known name. */ + + c = sd_bus_message_get_creds(m); + if (!c) + return 0; + + r = sd_bus_creds_get_well_known_names(c, &well_known); + if (r < 0) + return r; + + if (strv_contains(well_known, "org.freedesktop.DBus")) + m->sender = "org.freedesktop.DBus"; + + return 0; +} + +int main(int argc, char *argv[]) { + + _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL; + sd_id128_t server_id; + int r, in_fd, out_fd; + bool got_hello = false; + bool is_unix; + struct ucred ucred = {}; + _cleanup_free_ char *peersec = NULL; + + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = sd_listen_fds(0); + if (r == 0) { + in_fd = STDIN_FILENO; + out_fd = STDOUT_FILENO; + } 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"); + goto finish; + } + + is_unix = + sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && + sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; + + if (is_unix) { + getpeercred(in_fd, &ucred); + getpeersec(in_fd, &peersec); + } + + r = sd_bus_new(&a); + if (r < 0) { + log_error("Failed to allocate bus: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_name(a, "sd-proxy"); + if (r < 0) { + log_error("Failed to set bus name: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_address(a, arg_address); + if (r < 0) { + log_error("Failed to set address to connect to: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_negotiate_fds(a, is_unix); + if (r < 0) { + log_error("Failed to set FD negotiation: %s", strerror(-r)); + goto finish; + } + + if (ucred.pid > 0) { + a->fake_creds.pid = ucred.pid; + a->fake_creds.uid = ucred.uid; + a->fake_creds.gid = ucred.gid; + a->fake_creds_valid = true; + } + + if (peersec) { + a->fake_label = peersec; + peersec = NULL; + } + + a->manual_peer_interface = true; + + r = sd_bus_start(a); + if (r < 0) { + log_error("Failed to start bus client: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_get_server_id(a, &server_id); + if (r < 0) { + log_error("Failed to get server ID: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_new(&b); + if (r < 0) { + log_error("Failed to allocate bus: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_fd(b, in_fd, out_fd); + if (r < 0) { + log_error("Failed to set fds: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_server(b, 1, server_id); + if (r < 0) { + log_error("Failed to set server mode: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_negotiate_fds(b, is_unix); + if (r < 0) { + log_error("Failed to set FD negotiation: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_anonymous(b, true); + if (r < 0) { + log_error("Failed to set anonymous authentication: %s", strerror(-r)); + goto finish; + } + + b->manual_peer_interface = true; + + r = sd_bus_start(b); + if (r < 0) { + log_error("Failed to start bus client: %s", strerror(-r)); + goto finish; + } + + r = rename_service(a, b); + if (r < 0) + log_debug("Failed to rename process: %s", strerror(-r)); + + if (a->is_kernel) { + _cleanup_free_ char *match = NULL; + const char *unique; + + r = sd_bus_get_unique_name(a, &unique); + if (r < 0) { + log_error("Failed to get unique name: %s", strerror(-r)); + goto finish; + } + + match = strjoin("type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg1='", + unique, + "'", + NULL); + if (!match) { + log_oom(); + goto finish; + } + + r = sd_bus_add_match(a, match, NULL, NULL); + if (r < 0) { + log_error("Failed to add match for NameLost: %s", strerror(-r)); + goto finish; + } + + free(match); + match = strjoin("type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg2='", + unique, + "'", + NULL); + if (!match) { + log_oom(); + goto finish; + } + + r = sd_bus_add_match(a, match, NULL, NULL); + if (r < 0) { + log_error("Failed to add match for NameAcquired: %s", strerror(-r)); + goto finish; + } + } + + for (;;) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int events_a, events_b, fd; + uint64_t timeout_a, timeout_b, t; + struct timespec _ts, *ts; + struct pollfd *pollfd; + int k; + + if (got_hello) { + r = sd_bus_process(a, &m); + if (r < 0) { + /* treat 'connection reset by peer' as clean exit condition */ + if (r == -ECONNRESET) + r = 0; + else + log_error("Failed to process bus a: %s", strerror(-r)); + + goto finish; + } + + if (m) { + /* We officially got EOF, let's quit */ + if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) { + r = 0; + goto finish; + } + + k = synthesize_name_acquired(a, b, m); + if (k < 0) { + r = k; + log_error("Failed to synthesize message: %s", strerror(-r)); + goto finish; + } + + patch_sender(a, m); + + k = sd_bus_send(b, m, NULL); + if (k < 0) { + if (k == -ECONNRESET) + r = 0; + else { + r = k; + log_error("Failed to send message: %s", strerror(-r)); + } + + goto finish; + } + } + + if (r > 0) + continue; + } + + r = sd_bus_process(b, &m); + if (r < 0) { + /* treat 'connection reset by peer' as clean exit condition */ + if (r == -ECONNRESET) + r = 0; + else + log_error("Failed to process bus b: %s", strerror(-r)); + + goto finish; + } + + if (m) { + /* We officially got EOF, let's quit */ + if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) { + r = 0; + goto finish; + } + + k = process_hello(a, b, m, &got_hello); + if (k < 0) { + r = k; + log_error("Failed to process HELLO: %s", strerror(-r)); + goto finish; + } + + if (k > 0) + r = k; + else { + k = process_policy(a, b, m); + if (k < 0) { + r = k; + log_error("Failed to process policy: %s", strerror(-r)); + goto finish; + } + + k = sd_bus_send(a, m, NULL); + if (k < 0) { + if (r == -ECONNRESET) + r = 0; + else { + r = k; + log_error("Failed to send message: %s", strerror(-r)); + } + + goto finish; + } + } + } + + if (r > 0) + continue; + + fd = sd_bus_get_fd(a); + if (fd < 0) { + log_error("Failed to get fd: %s", strerror(-r)); + goto finish; + } + + events_a = sd_bus_get_events(a); + if (events_a < 0) { + log_error("Failed to get events mask: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_get_timeout(a, &timeout_a); + if (r < 0) { + log_error("Failed to get timeout: %s", strerror(-r)); + goto finish; + } + + events_b = sd_bus_get_events(b); + if (events_b < 0) { + log_error("Failed to get events mask: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_get_timeout(b, &timeout_b); + if (r < 0) { + log_error("Failed to get timeout: %s", strerror(-r)); + goto finish; + } + + t = timeout_a; + if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) + t = timeout_b; + + if (t == (uint64_t) -1) + ts = NULL; + else { + usec_t nw; + + nw = now(CLOCK_MONOTONIC); + if (t > nw) + t -= nw; + else + t = 0; + + ts = timespec_store(&_ts, t); + } + + pollfd = (struct pollfd[3]) { + {.fd = fd, .events = events_a, }, + {.fd = in_fd, .events = events_b & POLLIN, }, + {.fd = out_fd, .events = events_b & POLLOUT, } + }; + + r = ppoll(pollfd, 3, ts, NULL); + if (r < 0) { + log_error("ppoll() failed: %m"); + goto finish; + } + } + + r = 0; + +finish: + sd_bus_flush(a); + sd_bus_flush(b); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/cgls.c b/src/cgls.c deleted file mode 100644 index 20d6531..0000000 --- a/src/cgls.c +++ /dev/null @@ -1,154 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "cgroup-show.h" -#include "cgroup-util.h" -#include "log.h" -#include "util.h" -#include "pager.h" - -static bool arg_no_pager = false; - -static void help(void) { - - printf("%s [OPTIONS...] [CGROUP...]\n\n" - "Recursively show control group contents.\n\n" - " -h --help Show this help\n" - " --no-pager Do not pipe output into a pager\n", - program_invocation_short_name); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_NO_PAGER = 0x100 - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 1); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_NO_PAGER: - arg_no_pager = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r = 0, retval = EXIT_FAILURE; - - log_parse_environment(); - log_open(); - - if ((r = parse_argv(argc, argv)) < 0) - goto finish; - else if (r == 0) { - retval = EXIT_SUCCESS; - goto finish; - } - - if (!arg_no_pager) - pager_open(); - - if (optind < argc) { - unsigned i; - - for (i = (unsigned) optind; i < (unsigned) argc; i++) { - int q; - printf("%s:\n", argv[i]); - - if ((q = show_cgroup_by_path(argv[i], NULL, 0)) < 0) - r = q; - } - - } else { - char *p; - - if (!(p = get_current_dir_name())) { - log_error("Cannot determine current working directory: %m"); - goto finish; - } - - if (path_startswith(p, "/sys/fs/cgroup")) { - printf("Working Directory %s:\n", p); - r = show_cgroup_by_path(p, NULL, 0); - } else { - char *root = NULL; - const char *t = NULL; - - if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root)) < 0) - t = "/"; - else { - if (endswith(root, "/system")) - root[strlen(root)-7] = 0; - - t = root[0] ? root : "/"; - } - - r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0); - free(root); - } - - free(p); - } - - if (r < 0) - log_error("Failed to list cgroup tree: %s", strerror(-r)); - - retval = EXIT_SUCCESS; - -finish: - pager_close(); - - return retval; -} diff --git a/src/cgls/Makefile b/src/cgls/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/cgls/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c new file mode 100644 index 0000000..b8e275d --- /dev/null +++ b/src/cgls/cgls.c @@ -0,0 +1,217 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "log.h" +#include "path-util.h" +#include "util.h" +#include "pager.h" +#include "build.h" +#include "output-mode.h" +#include "fileio.h" + +static bool arg_no_pager = false; +static bool arg_kernel_threads = false; +static bool arg_all = false; +static int arg_full = -1; +static char* arg_machine = NULL; + +static int help(void) { + + printf("%s [OPTIONS...] [CGROUP...]\n\n" + "Recursively show control group contents.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " -a --all Show all groups, including empty\n" + " -l --full Do not ellipsize output\n" + " -k Include kernel threads in output\n" + " -M --machine Show container\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_NO_PAGER = 0x100, + ARG_VERSION, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "all", no_argument, NULL, 'a' }, + { "full", no_argument, NULL, 'l' }, + { "machine", required_argument, NULL, 'M' }, + {} + }; + + int c; + + assert(argc >= 1); + assert(argv); + + while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case 'a': + arg_all = true; + break; + + case 'l': + arg_full = true; + break; + + case 'k': + arg_kernel_threads = true; + break; + + case 'M': + arg_machine = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r = 0, retval = EXIT_FAILURE; + int output_flags; + char _cleanup_free_ *root = NULL; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r < 0) + goto finish; + else if (r == 0) { + retval = EXIT_SUCCESS; + goto finish; + } + + if (!arg_no_pager) { + r = pager_open(false); + if (r > 0) { + if (arg_full == -1) + arg_full = true; + } + } + + output_flags = + arg_all * OUTPUT_SHOW_ALL | + (arg_full > 0) * OUTPUT_FULL_WIDTH; + + if (optind < argc) { + int i; + + for (i = optind; i < argc; i++) { + int q; + + fprintf(stdout, "%s:\n", argv[i]); + fflush(stdout); + + if (arg_machine) + root = strjoin("machine/", arg_machine, "/", argv[i], NULL); + else + root = strdup(argv[i]); + if (!root) + return log_oom(); + + q = show_cgroup_by_path(root, NULL, 0, + arg_kernel_threads, output_flags); + if (q < 0) + r = q; + } + + } else { + _cleanup_free_ char *p; + + p = get_current_dir_name(); + if (!p) { + log_error("Cannot determine current working directory: %m"); + goto finish; + } + + if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) { + printf("Working Directory %s:\n", p); + r = show_cgroup_by_path(p, NULL, 0, + arg_kernel_threads, output_flags); + } else { + if (arg_machine) { + char *m; + m = strappenda("/run/systemd/machines/", arg_machine); + r = parse_env_file(m, NEWLINE, "CGROUP", &root, NULL); + } else + r = cg_get_root_path(&root); + if (r < 0) { + log_error("Failed to get %s path: %s", + arg_machine ? "machine" : "root", strerror(-r)); + goto finish; + } + + r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, + arg_kernel_threads, output_flags); + } + } + + if (r < 0) { + log_error("Failed to list cgroup tree %s: %s", root, strerror(-r)); + retval = EXIT_FAILURE; + } else + retval = EXIT_SUCCESS; + +finish: + pager_close(); + + return retval; +} diff --git a/src/cgroup-attr.c b/src/cgroup-attr.c deleted file mode 100644 index 474a686..0000000 --- a/src/cgroup-attr.c +++ /dev/null @@ -1,102 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "cgroup-attr.h" -#include "cgroup-util.h" -#include "list.h" - -int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) { - int r; - char *path = NULL; - char *v = NULL; - - assert(a); - - b = cgroup_bonding_find_list(b, a->controller); - if (!b) - return 0; - - if (a->map_callback) { - r = a->map_callback(a->controller, a->name, a->value, &v); - if (r < 0) - return r; - } - - r = cg_get_path(a->controller, b->path, a->name, &path); - if (r < 0) { - free(v); - return r; - } - - r = write_one_line_file(path, v ? v : a->value); - if (r < 0) - log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r)); - - free(path); - free(v); - - return r; -} - -int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b) { - CGroupAttribute *a; - int r = 0; - - LIST_FOREACH(by_unit, a, first) { - int k; - - k = cgroup_attribute_apply(a, b); - if (r == 0) - r = k; - } - - return r; -} - -CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name) { - CGroupAttribute *a; - - assert(controller); - assert(name); - - LIST_FOREACH(by_unit, a, first) - if (streq(a->controller, controller) && - streq(a->name, name)) - return a; - - return NULL; -} - -static void cgroup_attribute_free(CGroupAttribute *a) { - assert(a); - - free(a->controller); - free(a->name); - free(a->value); - free(a); -} - -void cgroup_attribute_free_list(CGroupAttribute *first) { - CGroupAttribute *a, *n; - - LIST_FOREACH_SAFE(by_unit, a, n, first) - cgroup_attribute_free(a); -} diff --git a/src/cgroup-attr.h b/src/cgroup-attr.h deleted file mode 100644 index 63a73b8..0000000 --- a/src/cgroup-attr.h +++ /dev/null @@ -1,49 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocgroupattrhfoo -#define foocgroupattrhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct CGroupAttribute CGroupAttribute; - -typedef int (*CGroupAttributeMapCallback)(const char *controller, const char*name, const char *value, char **ret); - -#include "unit.h" -#include "cgroup.h" - -struct CGroupAttribute { - char *controller; - char *name; - char *value; - - CGroupAttributeMapCallback map_callback; - - LIST_FIELDS(CGroupAttribute, by_unit); -}; - -int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b); -int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b); - -CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name); - -void cgroup_attribute_free_list(CGroupAttribute *first); - -#endif diff --git a/src/cgroup-show.c b/src/cgroup-show.c deleted file mode 100644 index bc9c216..0000000 --- a/src/cgroup-show.c +++ /dev/null @@ -1,257 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "macro.h" -#include "cgroup-util.h" -#include "cgroup-show.h" - -static int compare(const void *a, const void *b) { - const pid_t *p = a, *q = b; - - if (*p < *q) - return -1; - if (*p > *q) - return 1; - return 0; -} - -static unsigned ilog10(unsigned long ul) { - int n = 0; - - while (ul > 0) { - n++; - ul /= 10; - } - - return n; -} - -static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more) { - char *fn; - FILE *f; - size_t n = 0, n_allocated = 0; - pid_t *pids = NULL; - char *p; - pid_t pid, biggest = 0; - int r; - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - if ((r = cg_fix_path(path, &p)) < 0) - return r; - - r = asprintf(&fn, "%s/cgroup.procs", p); - free(p); - - if (r < 0) - return -ENOMEM; - - f = fopen(fn, "re"); - free(fn); - - if (!f) - return -errno; - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (n >= n_allocated) { - pid_t *npids; - - n_allocated = MAX(16U, n*2U); - - if (!(npids = realloc(pids, sizeof(pid_t) * n_allocated))) { - r = -ENOMEM; - goto finish; - } - - pids = npids; - } - - assert(n < n_allocated); - pids[n++] = pid; - - if (pid > biggest) - biggest = pid; - } - - if (r < 0) - goto finish; - - if (n > 0) { - unsigned i, m; - - /* Filter duplicates */ - m = 0; - for (i = 0; i < n; i++) { - unsigned j; - - for (j = i+1; j < n; j++) - if (pids[i] == pids[j]) - break; - - if (j >= n) - pids[m++] = pids[i]; - } - n = m; - - /* And sort */ - qsort(pids, n, sizeof(pid_t), compare); - - if (n_columns > 8) - n_columns -= 8; - else - n_columns = 20; - - for (i = 0; i < n; i++) { - char *t = NULL; - - get_process_cmdline(pids[i], n_columns, &t); - - printf("%s%s %*lu %s\n", - prefix, - (more || i < n-1) ? "\342\224\234" : "\342\224\224", - (int) ilog10(biggest), - (unsigned long) pids[i], - strna(t)); - - free(t); - } - } - - r = 0; - -finish: - free(pids); - - if (f) - fclose(f); - - return r; -} - -int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns) { - DIR *d; - char *last = NULL; - char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL; - bool shown_pids = false; - int r; - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - if ((r = cg_fix_path(path, &fn)) < 0) - return r; - - if (!(d = opendir(fn))) { - free(fn); - return -errno; - } - - while ((r = cg_read_subgroup(d, &gn)) > 0) { - - if (!shown_pids) { - show_cgroup_one_by_path(path, prefix, n_columns, true); - shown_pids = true; - } - - if (last) { - printf("%s\342\224\234 %s\n", prefix, file_name_from_path(last)); - - if (!p1) - if (!(p1 = strappend(prefix, "\342\224\202 "))) { - r = -ENOMEM; - goto finish; - } - - show_cgroup_by_path(last, p1, n_columns-2); - - free(last); - last = NULL; - } - - r = asprintf(&last, "%s/%s", fn, gn); - free(gn); - - if (r < 0) { - r = -ENOMEM; - goto finish; - } - } - - if (r < 0) - goto finish; - - if (!shown_pids) - show_cgroup_one_by_path(path, prefix, n_columns, !!last); - - if (last) { - printf("%s\342\224\224 %s\n", prefix, file_name_from_path(last)); - - if (!p2) - if (!(p2 = strappend(prefix, " "))) { - r = -ENOMEM; - goto finish; - } - - show_cgroup_by_path(last, p2, n_columns-2); - } - - r = 0; - -finish: - free(p1); - free(p2); - free(last); - free(fn); - - closedir(d); - - return r; -} - -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns) { - char *p; - int r; - - assert(controller); - assert(path); - - if ((r = cg_get_path(controller, path, NULL, &p)) < 0) - return r; - - r = show_cgroup_by_path(p, prefix, n_columns); - free(p); - - return r; -} diff --git a/src/cgroup-show.h b/src/cgroup-show.h deleted file mode 100644 index ae5b13b..0000000 --- a/src/cgroup-show.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocgroupshowhfoo -#define foocgroupshowhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns); -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns); - -#endif diff --git a/src/cgroup-util.c b/src/cgroup-util.c deleted file mode 100644 index f74280f..0000000 --- a/src/cgroup-util.c +++ /dev/null @@ -1,1076 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cgroup-util.h" -#include "log.h" -#include "set.h" -#include "macro.h" -#include "util.h" - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { - char *fs; - int r; - FILE *f; - - assert(controller); - assert(path); - assert(_f); - - if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0) - return r; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return -errno; - - *_f = f; - return 0; -} - -int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) { - char *fs; - int r; - FILE *f; - - assert(controller); - assert(path); - assert(_f); - - if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0) - return r; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return -errno; - - *_f = f; - return 0; -} - -int cg_read_pid(FILE *f, pid_t *_pid) { - unsigned long ul; - - /* Note that the cgroup.procs might contain duplicates! See - * cgroups.txt for details. */ - - errno = 0; - if (fscanf(f, "%lu", &ul) != 1) { - - if (feof(f)) - return 0; - - return errno ? -errno : -EIO; - } - - if (ul <= 0) - return -EIO; - - *_pid = (pid_t) ul; - return 1; -} - -int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { - char *fs; - int r; - DIR *d; - - assert(controller); - assert(path); - assert(_d); - - /* This is not recursive! */ - - if ((r = cg_get_path(controller, path, NULL, &fs)) < 0) - return r; - - d = opendir(fs); - free(fs); - - if (!d) - return -errno; - - *_d = d; - return 0; -} - -int cg_read_subgroup(DIR *d, char **fn) { - struct dirent *de; - - assert(d); - - errno = 0; - while ((de = readdir(d))) { - char *b; - - if (de->d_type != DT_DIR) - continue; - - if (streq(de->d_name, ".") || - streq(de->d_name, "..")) - continue; - - if (!(b = strdup(de->d_name))) - return -ENOMEM; - - *fn = b; - return 1; - } - - if (errno) - return -errno; - - return 0; -} - -int cg_rmdir(const char *controller, const char *path, bool honour_sticky) { - char *p; - int r; - - r = cg_get_path(controller, path, NULL, &p); - if (r < 0) - return r; - - if (honour_sticky) { - char *tasks; - - /* If the sticky bit is set don't remove the directory */ - - tasks = strappend(p, "/tasks"); - if (!tasks) { - free(p); - return -ENOMEM; - } - - r = file_is_sticky(tasks); - free(tasks); - - if (r > 0) { - free(p); - return 0; - } - } - - r = rmdir(p); - free(p); - - return (r < 0 && errno != ENOENT) ? -errno : 0; -} - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { - bool done = false; - int r, ret = 0; - pid_t my_pid; - FILE *f = NULL; - Set *allocated_set = NULL; - - assert(controller); - assert(path); - assert(sig >= 0); - - /* This goes through the tasks list and kills them all. This - * is repeated until no further processes are added to the - * tasks list, to properly handle forking processes */ - - if (!s) - if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - my_pid = getpid(); - - do { - pid_t pid = 0; - done = true; - - if ((r = cg_enumerate_processes(controller, path, &f)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (pid == my_pid && ignore_self) - continue; - - if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) - continue; - - /* If we haven't killed this process yet, kill - * it */ - if (kill(pid, sig) < 0) { - if (ret >= 0 && errno != ESRCH) - ret = -errno; - } else if (ret == 0) { - - if (sigcont) - kill(pid, SIGCONT); - - ret = 1; - } - - done = false; - - if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - } - - if (r < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - - fclose(f); - f = NULL; - - /* To avoid racing against processes which fork - * quicker than we can kill them we repeat this until - * no new pids need to be killed. */ - - } while (!done); - -finish: - if (allocated_set) - set_free(allocated_set); - - if (f) - fclose(f); - - return ret; -} - -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) { - int r, ret = 0; - DIR *d = NULL; - char *fn; - Set *allocated_set = NULL; - - assert(path); - assert(controller); - assert(sig >= 0); - - if (!s) - if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - ret = cg_kill(controller, path, sig, sigcont, ignore_self, s); - - if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", path, fn); - free(fn); - - if (r < 0) { - if (ret >= 0) - ret = -ENOMEM; - - goto finish; - } - - r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s); - free(p); - - if (r != 0 && ret >= 0) - ret = r; - } - - if (r < 0 && ret >= 0) - ret = r; - - if (rem) - if ((r = cg_rmdir(controller, path, true)) < 0) { - if (ret >= 0 && - r != -ENOENT && - r != -EBUSY) - ret = r; - } - -finish: - if (d) - closedir(d); - - if (allocated_set) - set_free(allocated_set); - - return ret; -} - -int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) { - unsigned i; - - assert(path); - assert(controller); - - /* This safely kills all processes; first it sends a SIGTERM, - * then checks 8 times after 200ms whether the group is now - * empty, then kills everything that is left with SIGKILL and - * finally checks 5 times after 200ms each whether the group - * is finally empty. */ - - for (i = 0; i < 15; i++) { - int sig, r; - - if (i <= 0) - sig = SIGTERM; - else if (i == 9) - sig = SIGKILL; - else - sig = 0; - - if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0) - return r; - - usleep(200 * USEC_PER_MSEC); - } - - return 0; -} - -int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) { - bool done = false; - Set *s; - int r, ret = 0; - pid_t my_pid; - FILE *f = NULL; - - assert(controller); - assert(from); - assert(to); - - if (!(s = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - my_pid = getpid(); - - do { - pid_t pid = 0; - done = true; - - if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_pid(f, &pid)) > 0) { - - /* This might do weird stuff if we aren't a - * single-threaded program. However, we - * luckily know we are not */ - if (pid == my_pid && ignore_self) - continue; - - if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) - continue; - - if ((r = cg_attach(controller, to, pid)) < 0) { - if (ret >= 0 && r != -ESRCH) - ret = r; - } else if (ret == 0) - ret = 1; - - done = false; - - if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - } - - if (r < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - - fclose(f); - f = NULL; - - } while (!done); - -finish: - set_free(s); - - if (f) - fclose(f); - - return ret; -} - -int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) { - int r, ret = 0; - DIR *d = NULL; - char *fn; - - assert(controller); - assert(from); - assert(to); - - ret = cg_migrate(controller, from, to, ignore_self); - - if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - goto finish; - } - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", from, fn); - free(fn); - - if (r < 0) { - if (ret >= 0) - ret = -ENOMEM; - - goto finish; - } - - r = cg_migrate_recursive(controller, p, to, ignore_self, rem); - free(p); - - if (r != 0 && ret >= 0) - ret = r; - } - - if (r < 0 && ret >= 0) - ret = r; - - if (rem) - if ((r = cg_rmdir(controller, from, true)) < 0) { - if (ret >= 0 && - r != -ENOENT && - r != -EBUSY) - ret = r; - } - -finish: - if (d) - closedir(d); - - return ret; -} - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { - const char *p; - char *t; - static __thread bool good = false; - - assert(controller); - assert(fs); - - if (_unlikely_(!good)) { - int r; - - r = path_is_mount_point("/sys/fs/cgroup", false); - if (r <= 0) - return r < 0 ? r : -ENOENT; - - /* Cache this to save a few stat()s */ - good = true; - } - - if (isempty(controller)) - return -EINVAL; - - /* This is a very minimal lookup from controller names to - * paths. Since we have mounted most hierarchies ourselves - * should be kinda safe, but eventually we might want to - * extend this to have a fallback to actually check - * /proc/mounts. Might need caching then. */ - - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - p = "systemd"; - else if (startswith(controller, "name=")) - p = controller + 5; - else - p = controller; - - if (path && suffix) - t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL); - else if (path) - t = join("/sys/fs/cgroup/", p, "/", path, NULL); - else if (suffix) - t = join("/sys/fs/cgroup/", p, "/", suffix, NULL); - else - t = join("/sys/fs/cgroup/", p, NULL); - - if (!t) - return -ENOMEM; - - path_kill_slashes(t); - - *fs = t; - return 0; -} - -static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { - char *p; - bool is_sticky; - - if (typeflag != FTW_DP) - return 0; - - if (ftwbuf->level < 1) - return 0; - - p = strappend(path, "/tasks"); - if (!p) { - errno = ENOMEM; - return 1; - } - - is_sticky = file_is_sticky(p) > 0; - free(p); - - if (is_sticky) - return 0; - - rmdir(path); - return 0; -} - -int cg_trim(const char *controller, const char *path, bool delete_root) { - char *fs; - int r = 0; - - assert(controller); - assert(path); - - r = cg_get_path(controller, path, NULL, &fs); - if (r < 0) - return r; - - errno = 0; - if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0) - r = errno ? -errno : -EIO; - - if (delete_root) { - bool is_sticky; - char *p; - - p = strappend(fs, "/tasks"); - if (!p) { - free(fs); - return -ENOMEM; - } - - is_sticky = file_is_sticky(p) > 0; - free(p); - - if (!is_sticky) - if (rmdir(fs) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - } - } - - free(fs); - - return r; -} - -int cg_delete(const char *controller, const char *path) { - char *parent; - int r; - - assert(controller); - assert(path); - - if ((r = parent_of_path(path, &parent)) < 0) - return r; - - r = cg_migrate_recursive(controller, path, parent, false, true); - free(parent); - - return r == -ENOENT ? 0 : r; -} - -int cg_create(const char *controller, const char *path) { - char *fs; - int r; - - assert(controller); - assert(path); - - if ((r = cg_get_path(controller, path, NULL, &fs)) < 0) - return r; - - r = mkdir_parents(fs, 0755); - - if (r >= 0) { - if (mkdir(fs, 0755) >= 0) - r = 1; - else if (errno == EEXIST) - r = 0; - else - r = -errno; - } - - free(fs); - - return r; -} - -int cg_attach(const char *controller, const char *path, pid_t pid) { - char *fs; - int r; - char c[32]; - - assert(controller); - assert(path); - assert(pid >= 0); - - if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0) - return r; - - if (pid == 0) - pid = getpid(); - - snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid); - char_array_0(c); - - r = write_one_line_file(fs, c); - free(fs); - - return r; -} - -int cg_create_and_attach(const char *controller, const char *path, pid_t pid) { - int r, q; - - assert(controller); - assert(path); - assert(pid >= 0); - - if ((r = cg_create(controller, path)) < 0) - return r; - - if ((q = cg_attach(controller, path, pid)) < 0) - return q; - - /* This does not remove the cgroup on failure */ - - return r; -} - -int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) { - char *fs; - int r; - - assert(controller); - assert(path); - - if ((r = cg_get_path(controller, path, NULL, &fs)) < 0) - return r; - - r = chmod_and_chown(fs, mode, uid, gid); - free(fs); - - return r; -} - -int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) { - char *fs; - int r; - - assert(controller); - assert(path); - - if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0) - return r; - - r = chmod_and_chown(fs, mode, uid, gid); - free(fs); - - return r; -} - -int cg_get_by_pid(const char *controller, pid_t pid, char **path) { - int r; - char *p = NULL; - FILE *f; - char *fs; - size_t cs; - - assert(controller); - assert(path); - assert(pid >= 0); - - if (pid == 0) - pid = getpid(); - - if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return errno == ENOENT ? -ESRCH : -errno; - - cs = strlen(controller); - - while (!feof(f)) { - char line[LINE_MAX]; - char *l; - - errno = 0; - if (!(fgets(line, sizeof(line), f))) { - if (feof(f)) - break; - - r = errno ? -errno : -EIO; - goto finish; - } - - truncate_nl(line); - - if (!(l = strchr(line, ':'))) - continue; - - l++; - if (strncmp(l, controller, cs) != 0) - continue; - - if (l[cs] != ':') - continue; - - if (!(p = strdup(l + cs + 1))) { - r = -ENOMEM; - goto finish; - } - - *path = p; - r = 0; - goto finish; - } - - r = -ENOENT; - -finish: - fclose(f); - - return r; -} - -int cg_install_release_agent(const char *controller, const char *agent) { - char *fs = NULL, *contents = NULL, *line = NULL, *sc; - int r; - - assert(controller); - assert(agent); - - if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0) - return r; - - if ((r = read_one_line_file(fs, &contents)) < 0) - goto finish; - - sc = strstrip(contents); - if (sc[0] == 0) { - - if (asprintf(&line, "%s\n", agent) < 0) { - r = -ENOMEM; - goto finish; - } - - if ((r = write_one_line_file(fs, line)) < 0) - goto finish; - - } else if (!streq(sc, agent)) { - r = -EEXIST; - goto finish; - } - - free(fs); - fs = NULL; - if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) - goto finish; - - free(contents); - contents = NULL; - if ((r = read_one_line_file(fs, &contents)) < 0) - goto finish; - - sc = strstrip(contents); - - if (streq(sc, "0")) { - if ((r = write_one_line_file(fs, "1\n")) < 0) - goto finish; - - r = 1; - } else if (!streq(sc, "1")) { - r = -EIO; - goto finish; - } else - r = 0; - -finish: - free(fs); - free(contents); - free(line); - - return r; -} - -int cg_is_empty(const char *controller, const char *path, bool ignore_self) { - pid_t pid = 0; - int r; - FILE *f = NULL; - bool found = false; - - assert(controller); - assert(path); - - if ((r = cg_enumerate_tasks(controller, path, &f)) < 0) - return r == -ENOENT ? 1 : r; - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (ignore_self && pid == getpid()) - continue; - - found = true; - break; - } - - fclose(f); - - if (r < 0) - return r; - - return !found; -} - -int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) { - int r; - DIR *d = NULL; - char *fn; - - assert(controller); - assert(path); - - if ((r = cg_is_empty(controller, path, ignore_self)) <= 0) - return r; - - if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) - return r == -ENOENT ? 1 : r; - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", path, fn); - free(fn); - - if (r < 0) { - r = -ENOMEM; - goto finish; - } - - r = cg_is_empty_recursive(controller, p, ignore_self); - free(p); - - if (r <= 0) - goto finish; - } - - if (r >= 0) - r = 1; - -finish: - - if (d) - closedir(d); - - return r; -} - -int cg_split_spec(const char *spec, char **controller, char **path) { - const char *e; - char *t = NULL, *u = NULL; - - assert(spec); - assert(controller || path); - - if (*spec == '/') { - - if (path) { - if (!(t = strdup(spec))) - return -ENOMEM; - - *path = t; - } - - if (controller) - *controller = NULL; - - return 0; - } - - if (!(e = strchr(spec, ':'))) { - - if (strchr(spec, '/') || spec[0] == 0) - return -EINVAL; - - if (controller) { - if (!(t = strdup(spec))) - return -ENOMEM; - - *controller = t; - } - - if (path) - *path = NULL; - - return 0; - } - - if (e[1] != '/' || - e == spec || - memchr(spec, '/', e-spec)) - return -EINVAL; - - if (controller) - if (!(t = strndup(spec, e-spec))) - return -ENOMEM; - - if (path) - if (!(u = strdup(e+1))) { - free(t); - return -ENOMEM; - } - - if (controller) - *controller = t; - - if (path) - *path = u; - - return 0; -} - -int cg_join_spec(const char *controller, const char *path, char **spec) { - assert(controller); - assert(path); - - if (!path_is_absolute(path) || - controller[0] == 0 || - strchr(controller, ':') || - strchr(controller, '/')) - return -EINVAL; - - if (asprintf(spec, "%s:%s", controller, path) < 0) - return -ENOMEM; - - return 0; -} - -int cg_fix_path(const char *path, char **result) { - char *t, *c, *p; - int r; - - assert(path); - assert(result); - - /* First check if it already is a filesystem path */ - if (path_is_absolute(path) && - path_startswith(path, "/sys/fs/cgroup") && - access(path, F_OK) >= 0) { - - if (!(t = strdup(path))) - return -ENOMEM; - - *result = t; - return 0; - } - - /* Otherwise treat it as cg spec */ - if ((r = cg_split_spec(path, &c, &p)) < 0) - return r; - - r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result); - free(c); - free(p); - - return r; -} - -int cg_get_user_path(char **path) { - char *root, *p; - - assert(path); - - /* Figure out the place to put user cgroups below. We use the - * same as PID 1 has but with the "/system" suffix replaced by - * "/user" */ - - if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0) - p = strdup("/user"); - else { - if (endswith(root, "/system")) - root[strlen(root) - 7] = 0; - else if (streq(root, "/")) - root[0] = 0; - - p = strappend(root, "/user"); - free(root); - } - - if (!p) - return -ENOMEM; - - *path = p; - return 0; -} diff --git a/src/cgroup-util.h b/src/cgroup-util.h deleted file mode 100644 index f09373b..0000000 --- a/src/cgroup-util.h +++ /dev/null @@ -1,72 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocgrouputilhfoo -#define foocgrouputilhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "set.h" -#include "def.h" - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); -int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f); -int cg_read_pid(FILE *f, pid_t *_pid); - -int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); -int cg_read_subgroup(DIR *d, char **fn); - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool remove, Set *s); -int cg_kill_recursive_and_wait(const char *controller, const char *path, bool remove); - -int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self); -int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool remove); - -int cg_split_spec(const char *spec, char **controller, char **path); -int cg_join_spec(const char *controller, const char *path, char **spec); -int cg_fix_path(const char *path, char **result); - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs); -int cg_get_by_pid(const char *controller, pid_t pid, char **path); - -int cg_trim(const char *controller, const char *path, bool delete_root); - -int cg_rmdir(const char *controller, const char *path, bool honour_sticky); -int cg_delete(const char *controller, const char *path); - -int cg_create(const char *controller, const char *path); -int cg_attach(const char *controller, const char *path, pid_t pid); -int cg_create_and_attach(const char *controller, const char *path, pid_t pid); - -int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); -int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); - -int cg_install_release_agent(const char *controller, const char *agent); - -int cg_is_empty(const char *controller, const char *path, bool ignore_self); -int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self); - -int cg_get_user_path(char **path); - -#endif diff --git a/src/cgroup.c b/src/cgroup.c deleted file mode 100644 index dcf2c2f..0000000 --- a/src/cgroup.c +++ /dev/null @@ -1,515 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "cgroup.h" -#include "cgroup-util.h" -#include "log.h" - -int cgroup_bonding_realize(CGroupBonding *b) { - int r; - - assert(b); - assert(b->path); - assert(b->controller); - - if (b->realized) - return 0; - - r = cg_create(b->controller, b->path); - if (r < 0) { - log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r)); - return r; - } - - b->realized = true; - - return 0; -} - -int cgroup_bonding_realize_list(CGroupBonding *first) { - CGroupBonding *b; - int r; - - LIST_FOREACH(by_unit, b, first) - if ((r = cgroup_bonding_realize(b)) < 0 && b->essential) - return r; - - return 0; -} - -void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim) { - assert(b); - - if (b->unit) { - CGroupBonding *f; - - LIST_REMOVE(CGroupBonding, by_unit, b->unit->meta.cgroup_bondings, b); - - if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) { - assert_se(f = hashmap_get(b->unit->meta.manager->cgroup_bondings, b->path)); - LIST_REMOVE(CGroupBonding, by_path, f, b); - - if (f) - hashmap_replace(b->unit->meta.manager->cgroup_bondings, b->path, f); - else - hashmap_remove(b->unit->meta.manager->cgroup_bondings, b->path); - } - } - - if (b->realized && b->ours && remove_or_trim) { - - if (cgroup_bonding_is_empty(b) > 0) - cg_delete(b->controller, b->path); - else - cg_trim(b->controller, b->path, false); - } - - free(b->controller); - free(b->path); - free(b); -} - -void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) { - CGroupBonding *b, *n; - - LIST_FOREACH_SAFE(by_unit, b, n, first) - cgroup_bonding_free(b, remove_or_trim); -} - -void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) { - assert(b); - - if (b->realized && b->ours) - cg_trim(b->controller, b->path, delete_root); -} - -void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) { - CGroupBonding *b; - - LIST_FOREACH(by_unit, b, first) - cgroup_bonding_trim(b, delete_root); -} - -int cgroup_bonding_install(CGroupBonding *b, pid_t pid) { - int r; - - assert(b); - assert(pid >= 0); - - if ((r = cg_create_and_attach(b->controller, b->path, pid)) < 0) - return r; - - b->realized = true; - return 0; -} - -int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid) { - CGroupBonding *b; - int r; - - LIST_FOREACH(by_unit, b, first) - if ((r = cgroup_bonding_install(b, pid)) < 0 && b->essential) - return r; - - return 0; -} - -int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) { - assert(b); - - if (!b->realized) - return -EINVAL; - - return cg_set_group_access(b->controller, b->path, mode, uid, gid); -} - -int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) { - CGroupBonding *b; - int r; - - LIST_FOREACH(by_unit, b, first) { - r = cgroup_bonding_set_group_access(b, mode, uid, gid); - if (r < 0) - return r; - } - - return 0; -} - -int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) { - assert(b); - - if (!b->realized) - return -EINVAL; - - return cg_set_task_access(b->controller, b->path, mode, uid, gid); -} - -int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) { - CGroupBonding *b; - int r; - - LIST_FOREACH(by_unit, b, first) { - r = cgroup_bonding_set_task_access(b, mode, uid, gid); - if (r < 0) - return r; - } - - return 0; -} - -int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s) { - assert(b); - assert(sig >= 0); - - /* Don't kill cgroups that aren't ours */ - if (!b->ours) - return 0; - - return cg_kill_recursive(b->controller, b->path, sig, sigcont, true, false, s); -} - -int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s) { - CGroupBonding *b; - Set *allocated_set = NULL; - int ret = -EAGAIN, r; - - if (!s) - if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - LIST_FOREACH(by_unit, b, first) { - if ((r = cgroup_bonding_kill(b, sig, sigcont, s)) < 0) { - if (r == -EAGAIN || r == -ESRCH) - continue; - - ret = r; - goto finish; - } - - if (ret < 0 || r > 0) - ret = r; - } - -finish: - if (allocated_set) - set_free(allocated_set); - - return ret; -} - -/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we - * cannot know */ -int cgroup_bonding_is_empty(CGroupBonding *b) { - int r; - - assert(b); - - if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0) - return r; - - /* If it is empty it is empty */ - if (r > 0) - return 1; - - /* It's not only us using this cgroup, so we just don't know */ - return b->ours ? 0 : -EAGAIN; -} - -int cgroup_bonding_is_empty_list(CGroupBonding *first) { - CGroupBonding *b; - - LIST_FOREACH(by_unit, b, first) { - int r; - - if ((r = cgroup_bonding_is_empty(b)) < 0) { - /* If this returned -EAGAIN, then we don't know if the - * group is empty, so let's see if another group can - * tell us */ - - if (r != -EAGAIN) - return r; - } else - return r; - } - - return -EAGAIN; -} - -int manager_setup_cgroup(Manager *m) { - char *current = NULL, *path = NULL; - int r; - char suffix[32]; - - assert(m); - - /* 0. Be nice to Ingo Molnar #628004 */ - if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) { - log_warning("No control group support available, not creating root group."); - return 0; - } - - /* 1. Determine hierarchy */ - if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0) { - log_error("Cannot determine cgroup we are running in: %s", strerror(-r)); - goto finish; - } - - if (m->running_as == MANAGER_SYSTEM) - strcpy(suffix, "/system"); - else { - snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid()); - char_array_0(suffix); - } - - free(m->cgroup_hierarchy); - if (endswith(current, suffix)) { - /* We probably got reexecuted and can continue to use our root cgroup */ - m->cgroup_hierarchy = current; - current = NULL; - - } else { - /* We need a new root cgroup */ - m->cgroup_hierarchy = NULL; - if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - } - - /* 2. Show data */ - if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) { - log_error("Cannot find cgroup mount point: %s", strerror(-r)); - goto finish; - } - - log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path); - - /* 3. Install agent */ - if ((r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH)) < 0) - log_warning("Failed to install release agent, ignoring: %s", strerror(-r)); - else if (r > 0) - log_debug("Installed release agent."); - else - log_debug("Release agent already installed."); - - /* 4. Realize the group */ - if ((r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0)) < 0) { - log_error("Failed to create root cgroup hierarchy: %s", strerror(-r)); - goto finish; - } - - /* 5. And pin it, so that it cannot be unmounted */ - if (m->pin_cgroupfs_fd >= 0) - close_nointr_nofail(m->pin_cgroupfs_fd); - - if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) { - log_error("Failed to open pin file: %m"); - r = -errno; - goto finish; - } - - log_debug("Created root group."); - -finish: - free(current); - free(path); - - return r; -} - -void manager_shutdown_cgroup(Manager *m, bool delete) { - assert(m); - - if (delete && m->cgroup_hierarchy) - cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy); - - if (m->pin_cgroupfs_fd >= 0) { - close_nointr_nofail(m->pin_cgroupfs_fd); - m->pin_cgroupfs_fd = -1; - } - - free(m->cgroup_hierarchy); - m->cgroup_hierarchy = NULL; -} - -int cgroup_notify_empty(Manager *m, const char *group) { - CGroupBonding *l, *b; - - assert(m); - assert(group); - - if (!(l = hashmap_get(m->cgroup_bondings, group))) - return 0; - - LIST_FOREACH(by_path, b, l) { - int t; - - if (!b->unit) - continue; - - if ((t = cgroup_bonding_is_empty_list(b)) < 0) { - - /* If we don't know, we don't know */ - if (t != -EAGAIN) - log_warning("Failed to check whether cgroup is empty: %s", strerror(errno)); - - continue; - } - - if (t > 0) - if (UNIT_VTABLE(b->unit)->cgroup_notify_empty) - UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit); - } - - return 0; -} - -Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) { - CGroupBonding *l, *b; - char *group = NULL; - - assert(m); - - if (pid <= 1) - return NULL; - - if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0) - return NULL; - - l = hashmap_get(m->cgroup_bondings, group); - - if (!l) { - char *slash; - - while ((slash = strrchr(group, '/'))) { - if (slash == group) - break; - - *slash = 0; - - if ((l = hashmap_get(m->cgroup_bondings, group))) - break; - } - } - - free(group); - - LIST_FOREACH(by_path, b, l) { - - if (!b->unit) - continue; - - if (b->ours) - return b->unit; - } - - return NULL; -} - -CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) { - CGroupBonding *b; - - assert(controller); - - LIST_FOREACH(by_unit, b, first) - if (streq(b->controller, controller)) - return b; - - return NULL; -} - -char *cgroup_bonding_to_string(CGroupBonding *b) { - char *r; - - assert(b); - - if (asprintf(&r, "%s:%s", b->controller, b->path) < 0) - return NULL; - - return r; -} - -pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) { - FILE *f; - pid_t pid = 0, npid, mypid; - - assert(b); - - if (!b->ours) - return 0; - - if (cg_enumerate_processes(b->controller, b->path, &f) < 0) - return 0; - - mypid = getpid(); - - while (cg_read_pid(f, &npid) > 0) { - pid_t ppid; - - if (npid == pid) - continue; - - /* Ignore processes that aren't our kids */ - if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid) - continue; - - if (pid != 0) { - /* Dang, there's more than one daemonized PID - in this group, so we don't know what process - is the main process. */ - pid = 0; - break; - } - - pid = npid; - } - - fclose(f); - - return pid; -} - -pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) { - CGroupBonding *b; - pid_t pid; - - /* Try to find a main pid from this cgroup, but checking if - * there's only one PID in the cgroup and returning it. Later - * on we might want to add additional, smarter heuristics - * here. */ - - LIST_FOREACH(by_unit, b, first) - if ((pid = cgroup_bonding_search_main_pid(b)) != 0) - return pid; - - return 0; - -} diff --git a/src/cgroup.h b/src/cgroup.h deleted file mode 100644 index f33d844..0000000 --- a/src/cgroup.h +++ /dev/null @@ -1,93 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocgrouphfoo -#define foocgrouphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct CGroupBonding CGroupBonding; - -#include "unit.h" - -/* Binds a cgroup to a name */ -struct CGroupBonding { - char *controller; - char *path; - - Unit *unit; - - /* For the Unit::cgroup_bondings list */ - LIST_FIELDS(CGroupBonding, by_unit); - - /* For the Manager::cgroup_bondings hashmap */ - LIST_FIELDS(CGroupBonding, by_path); - - /* When shutting down, remove cgroup? Are our own tasks the - * only ones in this group?*/ - bool ours:1; - - /* If we cannot create this group, or add a process to it, is this fatal? */ - bool essential:1; - - /* This cgroup is realized */ - bool realized:1; -}; - -int cgroup_bonding_realize(CGroupBonding *b); -int cgroup_bonding_realize_list(CGroupBonding *first); - -void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim); -void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim); - -int cgroup_bonding_install(CGroupBonding *b, pid_t pid); -int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid); - -int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid); -int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid); - -int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid); -int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid); - -int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, Set *s); -int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, Set *s); - -void cgroup_bonding_trim(CGroupBonding *first, bool delete_root); -void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root); - -int cgroup_bonding_is_empty(CGroupBonding *b); -int cgroup_bonding_is_empty_list(CGroupBonding *first); - -CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller); - -char *cgroup_bonding_to_string(CGroupBonding *b); - -pid_t cgroup_bonding_search_main_pid(CGroupBonding *b); -pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b); - -#include "manager.h" - -int manager_setup_cgroup(Manager *m); -void manager_shutdown_cgroup(Manager *m, bool delete); - -int cgroup_notify_empty(Manager *m, const char *group); - -Unit* cgroup_unit_by_pid(Manager *m, pid_t pid); - -#endif diff --git a/src/cgroups-agent.c b/src/cgroups-agent.c deleted file mode 100644 index 7f001e6..0000000 --- a/src/cgroups-agent.c +++ /dev/null @@ -1,101 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include - -#include "log.h" -#include "dbus-common.h" - -int main(int argc, char *argv[]) { - DBusError error; - DBusConnection *bus = NULL; - DBusMessage *m = NULL; - int r = EXIT_FAILURE; - - dbus_error_init(&error); - - if (argc != 2) { - log_error("Incorrect number of arguments."); - goto finish; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - /* We send this event to the private D-Bus socket and then the - * system instance will forward this to the system bus. We do - * this to avoid an activation loop when we start dbus when we - * are called when the dbus service is shut down. */ - - if (!(bus = dbus_connection_open_private("unix:path=/run/systemd/private", &error))) { -#ifndef LEGACY - dbus_error_free(&error); - - /* Retry with the pre v21 socket name, to ease upgrades */ - if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", &error))) { -#endif - log_error("Failed to get D-Bus connection: %s", bus_error_message(&error)); - goto finish; - } -#ifndef LEGACY - } -#endif - - if (bus_check_peercred(bus) < 0) { - log_error("Bus owner not root."); - goto finish; - } - - if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1/agent", "org.freedesktop.systemd1.Agent", "Released"))) { - log_error("Could not allocate signal message."); - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &argv[1], - DBUS_TYPE_INVALID)) { - log_error("Could not attach group information to signal message."); - goto finish; - } - - if (!dbus_connection_send(bus, m, NULL)) { - log_error("Failed to send signal message on private connection."); - goto finish; - } - - r = EXIT_SUCCESS; - -finish: - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - return r; -} diff --git a/src/cgroups-agent/Makefile b/src/cgroups-agent/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/cgroups-agent/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c new file mode 100644 index 0000000..d1d843b --- /dev/null +++ b/src/cgroups-agent/cgroups-agent.c @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" +#include "log.h" +#include "bus-util.h" + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + if (argc != 2) { + log_error("Incorrect number of arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + /* We send this event to the private D-Bus socket and then the + * system instance will forward this to the system bus. We do + * this to avoid an activation loop when we start dbus when we + * are called when the dbus service is shut down. */ + + r = bus_open_system_systemd(&bus); + if (r < 0) { + /* If we couldn't connect we assume this was triggered + * while systemd got restarted/transitioned from + * initrd to the system, so let's ignore this */ + log_debug("Failed to get D-Bus connection: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = sd_bus_emit_signal(bus, + "/org/freedesktop/systemd1/agent", + "org.freedesktop.systemd1.Agent", + "Released", + "s", argv[1]); + if (r < 0) { + log_debug("Failed to send signal message on private connection: %s", strerror(-r)); + return EXIT_FAILURE; + } + + sd_bus_flush(bus); + + return EXIT_SUCCESS; +} diff --git a/src/cgtop/Makefile b/src/cgtop/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/cgtop/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c new file mode 100644 index 0000000..fd0023b --- /dev/null +++ b/src/cgtop/cgtop.c @@ -0,0 +1,851 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include +#include + +#include "path-util.h" +#include "util.h" +#include "hashmap.h" +#include "cgroup-util.h" +#include "build.h" +#include "fileio.h" + +typedef struct Group { + char *path; + + bool n_tasks_valid:1; + bool cpu_valid:1; + bool memory_valid:1; + bool io_valid:1; + + unsigned n_tasks; + + unsigned cpu_iteration; + uint64_t cpu_usage; + struct timespec cpu_timestamp; + double cpu_fraction; + + uint64_t memory; + + unsigned io_iteration; + uint64_t io_input, io_output; + struct timespec io_timestamp; + uint64_t io_input_bps, io_output_bps; +} Group; + +static unsigned arg_depth = 3; +static unsigned arg_iterations = 0; +static bool arg_batch = false; +static usec_t arg_delay = 1*USEC_PER_SEC; + +static enum { + ORDER_PATH, + ORDER_TASKS, + ORDER_CPU, + ORDER_MEMORY, + ORDER_IO +} arg_order = ORDER_CPU; + +static enum { + CPU_PERCENT, + CPU_TIME, +} arg_cpu_type = CPU_PERCENT; + +static void group_free(Group *g) { + assert(g); + + free(g->path); + free(g); +} + +static void group_hashmap_clear(Hashmap *h) { + Group *g; + + while ((g = hashmap_steal_first(h))) + group_free(g); +} + +static void group_hashmap_free(Hashmap *h) { + group_hashmap_clear(h); + hashmap_free(h); +} + +static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) { + Group *g; + int r; + FILE *f = NULL; + pid_t pid; + unsigned n; + + assert(controller); + assert(path); + assert(a); + + g = hashmap_get(a, path); + if (!g) { + g = hashmap_get(b, path); + if (!g) { + g = new0(Group, 1); + if (!g) + return -ENOMEM; + + g->path = strdup(path); + if (!g->path) { + group_free(g); + return -ENOMEM; + } + + r = hashmap_put(a, g->path, g); + if (r < 0) { + group_free(g); + return r; + } + } else { + assert_se(hashmap_move_one(a, b, path) == 0); + g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false; + } + } + + /* Regardless which controller, let's find the maximum number + * of processes in any of it */ + + r = cg_enumerate_processes(controller, path, &f); + if (r < 0) + return r; + + n = 0; + while (cg_read_pid(f, &pid) > 0) + n++; + fclose(f); + + if (n > 0) { + if (g->n_tasks_valid) + g->n_tasks = MAX(g->n_tasks, n); + else + g->n_tasks = n; + + g->n_tasks_valid = true; + } + + if (streq(controller, "cpuacct")) { + uint64_t new_usage; + char *p, *v; + struct timespec ts; + + r = cg_get_path(controller, path, "cpuacct.usage", &p); + if (r < 0) + return r; + + r = read_one_line_file(p, &v); + free(p); + if (r < 0) + return r; + + r = safe_atou64(v, &new_usage); + free(v); + if (r < 0) + return r; + + assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + + if (g->cpu_iteration == iteration - 1) { + uint64_t x, y; + + x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) - + ((uint64_t) g->cpu_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->cpu_timestamp.tv_nsec); + + y = new_usage - g->cpu_usage; + + if (y > 0) { + g->cpu_fraction = (double) y / (double) x; + g->cpu_valid = true; + } + } + + g->cpu_usage = new_usage; + g->cpu_timestamp = ts; + g->cpu_iteration = iteration; + + } else if (streq(controller, "memory")) { + char *p, *v; + + r = cg_get_path(controller, path, "memory.usage_in_bytes", &p); + if (r < 0) + return r; + + r = read_one_line_file(p, &v); + free(p); + if (r < 0) + return r; + + r = safe_atou64(v, &g->memory); + free(v); + if (r < 0) + return r; + + if (g->memory > 0) + g->memory_valid = true; + + } else if (streq(controller, "blkio")) { + char *p; + uint64_t wr = 0, rd = 0; + struct timespec ts; + + r = cg_get_path(controller, path, "blkio.io_service_bytes", &p); + if (r < 0) + return r; + + f = fopen(p, "re"); + free(p); + + if (!f) + return -errno; + + for (;;) { + char line[LINE_MAX], *l; + uint64_t k, *q; + + if (!fgets(line, sizeof(line), f)) + break; + + l = strstrip(line); + l += strcspn(l, WHITESPACE); + l += strspn(l, WHITESPACE); + + if (first_word(l, "Read")) { + l += 4; + q = &rd; + } else if (first_word(l, "Write")) { + l += 5; + q = ≀ + } else + continue; + + l += strspn(l, WHITESPACE); + r = safe_atou64(l, &k); + if (r < 0) + continue; + + *q += k; + } + + fclose(f); + + assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + + if (g->io_iteration == iteration - 1) { + uint64_t x, yr, yw; + + x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) - + ((uint64_t) g->io_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->io_timestamp.tv_nsec); + + yr = rd - g->io_input; + yw = wr - g->io_output; + + if (yr > 0 || yw > 0) { + g->io_input_bps = (yr * 1000000000ULL) / x; + g->io_output_bps = (yw * 1000000000ULL) / x; + g->io_valid = true; + + } + } + + g->io_input = rd; + g->io_output = wr; + g->io_timestamp = ts; + g->io_iteration = iteration; + } + + return 0; +} + +static int refresh_one( + const char *controller, + const char *path, + Hashmap *a, + Hashmap *b, + unsigned iteration, + unsigned depth) { + + DIR *d = NULL; + int r; + + assert(controller); + assert(path); + assert(a); + + if (depth > arg_depth) + return 0; + + r = process(controller, path, a, b, iteration); + if (r < 0) + return r; + + r = cg_enumerate_subgroups(controller, path, &d); + if (r < 0) { + if (r == -ENOENT) + return 0; + + return r; + } + + for (;;) { + char *fn, *p; + + r = cg_read_subgroup(d, &fn); + if (r <= 0) + goto finish; + + p = strjoin(path, "/", fn, NULL); + free(fn); + + if (!p) { + r = -ENOMEM; + goto finish; + } + + path_kill_slashes(p); + + r = refresh_one(controller, p, a, b, iteration, depth + 1); + free(p); + + if (r < 0) + goto finish; + } + +finish: + if (d) + closedir(d); + + return r; +} + +static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) { + int r; + + assert(a); + + r = refresh_one("name=systemd", "/", a, b, iteration, 0); + if (r < 0) + if (r != -ENOENT) + return r; + r = refresh_one("cpuacct", "/", a, b, iteration, 0); + if (r < 0) + if (r != -ENOENT) + return r; + r = refresh_one("memory", "/", a, b, iteration, 0); + if (r < 0) + if (r != -ENOENT) + return r; + + r = refresh_one("blkio", "/", a, b, iteration, 0); + if (r < 0) + if (r != -ENOENT) + return r; + return 0; +} + +static int group_compare(const void*a, const void *b) { + const Group *x = *(Group**)a, *y = *(Group**)b; + + if (path_startswith(y->path, x->path)) + return -1; + if (path_startswith(x->path, y->path)) + return 1; + + if (arg_order == ORDER_CPU) { + if (arg_cpu_type == CPU_PERCENT) { + if (x->cpu_valid && y->cpu_valid) { + if (x->cpu_fraction > y->cpu_fraction) + return -1; + else if (x->cpu_fraction < y->cpu_fraction) + return 1; + } else if (x->cpu_valid) + return -1; + else if (y->cpu_valid) + return 1; + } else { + if (x->cpu_usage > y->cpu_usage) + return -1; + else if (x->cpu_usage < y->cpu_usage) + return 1; + } + } + + if (arg_order == ORDER_TASKS) { + + if (x->n_tasks_valid && y->n_tasks_valid) { + if (x->n_tasks > y->n_tasks) + return -1; + else if (x->n_tasks < y->n_tasks) + return 1; + } else if (x->n_tasks_valid) + return -1; + else if (y->n_tasks_valid) + return 1; + } + + if (arg_order == ORDER_MEMORY) { + if (x->memory_valid && y->memory_valid) { + if (x->memory > y->memory) + return -1; + else if (x->memory < y->memory) + return 1; + } else if (x->memory_valid) + return -1; + else if (y->memory_valid) + return 1; + } + + if (arg_order == ORDER_IO) { + if (x->io_valid && y->io_valid) { + if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps) + return -1; + else if (x->io_input_bps + x->io_output_bps < y->io_input_bps + y->io_output_bps) + return 1; + } else if (x->io_valid) + return -1; + else if (y->io_valid) + return 1; + } + + return strcmp(x->path, y->path); +} + +#define ON ANSI_HIGHLIGHT_ON +#define OFF ANSI_HIGHLIGHT_OFF + +static int display(Hashmap *a) { + Iterator i; + Group *g; + Group **array; + signed path_columns; + unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 0; + char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)]; + + assert(a); + + /* Set cursor to top left corner and clear screen */ + if (on_tty()) + fputs("\033[H" + "\033[2J", stdout); + + array = alloca(sizeof(Group*) * hashmap_size(a)); + + HASHMAP_FOREACH(g, a, i) + if (g->n_tasks_valid || g->cpu_valid || g->memory_valid || g->io_valid) + array[n++] = g; + + qsort_safe(array, n, sizeof(Group*), group_compare); + + /* Find the longest names in one run */ + for (j = 0; j < n; j++) { + unsigned cputlen, pathtlen; + + format_timespan(buffer, sizeof(buffer), (nsec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0); + cputlen = strlen(buffer); + maxtcpu = MAX(maxtcpu, cputlen); + pathtlen = strlen(array[j]->path); + maxtpath = MAX(maxtpath, pathtlen); + } + + if (arg_cpu_type == CPU_PERCENT) + snprintf(buffer, sizeof(buffer), "%6s", "%CPU"); + else + snprintf(buffer, sizeof(buffer), "%*s", maxtcpu, "CPU Time"); + + rows = lines(); + if (rows <= 10) + rows = 10; + + if (on_tty()) { + path_columns = columns() - 36 - strlen(buffer); + if (path_columns < 10) + path_columns = 10; + + printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n", + arg_order == ORDER_PATH ? ON : "", path_columns, "Path", + arg_order == ORDER_PATH ? OFF : "", + arg_order == ORDER_TASKS ? ON : "", "Tasks", + arg_order == ORDER_TASKS ? OFF : "", + arg_order == ORDER_CPU ? ON : "", buffer, + arg_order == ORDER_CPU ? OFF : "", + arg_order == ORDER_MEMORY ? ON : "", "Memory", + arg_order == ORDER_MEMORY ? OFF : "", + arg_order == ORDER_IO ? ON : "", "Input/s", + arg_order == ORDER_IO ? OFF : "", + arg_order == ORDER_IO ? ON : "", "Output/s", + arg_order == ORDER_IO ? OFF : ""); + } else + path_columns = maxtpath; + + for (j = 0; j < n; j++) { + char *p; + + if (on_tty() && j + 5 > rows) + break; + + g = array[j]; + + p = ellipsize(g->path, path_columns, 33); + printf("%-*s", path_columns, p ? p : g->path); + free(p); + + if (g->n_tasks_valid) + printf(" %7u", g->n_tasks); + else + fputs(" -", stdout); + + if (arg_cpu_type == CPU_PERCENT) { + if (g->cpu_valid) + printf(" %6.1f", g->cpu_fraction*100); + else + fputs(" -", stdout); + } else + printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (nsec_t) (g->cpu_usage / NSEC_PER_USEC), 0)); + + if (g->memory_valid) + printf(" %8s", format_bytes(buffer, sizeof(buffer), g->memory)); + else + fputs(" -", stdout); + + if (g->io_valid) { + printf(" %8s", + format_bytes(buffer, sizeof(buffer), g->io_input_bps)); + printf(" %8s", + format_bytes(buffer, sizeof(buffer), g->io_output_bps)); + } else + fputs(" - -", stdout); + + putchar('\n'); + } + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Show top control groups by their resource usage.\n\n" + " -h --help Show this help\n" + " --version Print version and exit\n" + " -p Order by path\n" + " -t Order by number of tasks\n" + " -c Order by CPU load\n" + " -m Order by memory load\n" + " -i Order by IO load\n" + " --cpu[=TYPE] Show CPU usage as time or percentage (default)\n" + " -d --delay=DELAY Delay between updates\n" + " -n --iterations=N Run for N iterations before exiting\n" + " -b --batch Run in batch mode, accepting no input\n" + " --depth=DEPTH Maximum traversal depth (default: %u)\n", + program_invocation_short_name, arg_depth); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_DEPTH, + ARG_CPU_TYPE + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "delay", required_argument, NULL, 'd' }, + { "iterations", required_argument, NULL, 'n' }, + { "batch", no_argument, NULL, 'b' }, + { "depth", required_argument, NULL, ARG_DEPTH }, + { "cpu", optional_argument, NULL, ARG_CPU_TYPE}, + {} + }; + + int c; + int r; + + assert(argc >= 1); + assert(argv); + + while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_CPU_TYPE: + if (optarg) { + if (strcmp(optarg, "time") == 0) + arg_cpu_type = CPU_TIME; + else if (strcmp(optarg, "percentage") == 0) + arg_cpu_type = CPU_PERCENT; + else + return -EINVAL; + } + break; + + case ARG_DEPTH: + r = safe_atou(optarg, &arg_depth); + if (r < 0) { + log_error("Failed to parse depth parameter."); + return -EINVAL; + } + + break; + + case 'd': + r = parse_sec(optarg, &arg_delay); + if (r < 0 || arg_delay <= 0) { + log_error("Failed to parse delay parameter."); + return -EINVAL; + } + + break; + + case 'n': + r = safe_atou(optarg, &arg_iterations); + if (r < 0) { + log_error("Failed to parse iterations parameter."); + return -EINVAL; + } + + break; + + case 'b': + arg_batch = true; + break; + + case 'p': + arg_order = ORDER_PATH; + break; + + case 't': + arg_order = ORDER_TASKS; + break; + + case 'c': + arg_order = ORDER_CPU; + break; + + case 'm': + arg_order = ORDER_MEMORY; + break; + + case 'i': + arg_order = ORDER_IO; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind < argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + Hashmap *a = NULL, *b = NULL; + unsigned iteration = 0; + usec_t last_refresh = 0; + bool quit = false, immediate_refresh = false; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + a = hashmap_new(string_hash_func, string_compare_func); + b = hashmap_new(string_hash_func, string_compare_func); + if (!a || !b) { + r = log_oom(); + goto finish; + } + + signal(SIGWINCH, columns_lines_cache_reset); + + if (!on_tty()) + arg_iterations = 1; + + while (!quit) { + Hashmap *c; + usec_t t; + char key; + char h[FORMAT_TIMESPAN_MAX]; + + t = now(CLOCK_MONOTONIC); + + if (t >= last_refresh + arg_delay || immediate_refresh) { + + r = refresh(a, b, iteration++); + if (r < 0) + goto finish; + + group_hashmap_clear(b); + + c = a; + a = b; + b = c; + + last_refresh = t; + immediate_refresh = false; + } + + r = display(b); + if (r < 0) + goto finish; + + if (arg_iterations && iteration >= arg_iterations) + break; + + if (arg_batch) { + usleep(last_refresh + arg_delay - t); + } else { + r = read_one_char(stdin, &key, + last_refresh + arg_delay - t, NULL); + if (r == -ETIMEDOUT) + continue; + if (r < 0) { + log_error("Couldn't read key: %s", strerror(-r)); + goto finish; + } + } + + fputs("\r \r", stdout); + fflush(stdout); + + if (arg_batch) + continue; + + switch (key) { + + case ' ': + immediate_refresh = true; + break; + + case 'q': + quit = true; + break; + + case 'p': + arg_order = ORDER_PATH; + break; + + case 't': + arg_order = ORDER_TASKS; + break; + + case 'c': + arg_order = ORDER_CPU; + break; + + case 'm': + arg_order = ORDER_MEMORY; + break; + + case 'i': + arg_order = ORDER_IO; + break; + + case '%': + arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME; + break; + + case '+': + if (arg_delay < USEC_PER_SEC) + arg_delay += USEC_PER_MSEC*250; + else + arg_delay += USEC_PER_SEC; + + fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); + fflush(stdout); + sleep(1); + break; + + case '-': + if (arg_delay <= USEC_PER_MSEC*500) + arg_delay = USEC_PER_MSEC*250; + else if (arg_delay < USEC_PER_MSEC*1250) + arg_delay -= USEC_PER_MSEC*250; + else + arg_delay -= USEC_PER_SEC; + + fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); + fflush(stdout); + sleep(1); + break; + + case '?': + case 'h': + fprintf(stdout, + "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" + "\t<" ON "+" OFF "> Increase delay; <" ON "-" OFF "> Decrease delay; <" ON "%%" OFF "> Toggle time\n" + "\t<" ON "q" OFF "> Quit; <" ON "SPACE" OFF "> Refresh"); + fflush(stdout); + sleep(3); + break; + + default: + fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key); + fflush(stdout); + sleep(1); + break; + } + } + + r = 0; + +finish: + group_hashmap_free(a); + group_hashmap_free(b); + + if (r < 0) { + log_error("Exiting with failure: %s", strerror(-r)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/compat-libs/.gitignore b/src/compat-libs/.gitignore new file mode 100644 index 0000000..662c154 --- /dev/null +++ b/src/compat-libs/.gitignore @@ -0,0 +1 @@ +/libsystemd-*.pc diff --git a/src/compat-libs/libsystemd-daemon.pc.in b/src/compat-libs/libsystemd-daemon.pc.in new file mode 100644 index 0000000..847afc9 --- /dev/null +++ b/src/compat-libs/libsystemd-daemon.pc.in @@ -0,0 +1,19 @@ +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Daemon Utility Library - deprecated +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd +Cflags: -I${includedir} diff --git a/src/libsystemd-daemon.sym b/src/compat-libs/libsystemd-daemon.sym similarity index 100% rename from src/libsystemd-daemon.sym rename to src/compat-libs/libsystemd-daemon.sym diff --git a/src/compat-libs/libsystemd-id128.pc.in b/src/compat-libs/libsystemd-id128.pc.in new file mode 100644 index 0000000..80f8fee --- /dev/null +++ b/src/compat-libs/libsystemd-id128.pc.in @@ -0,0 +1,18 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd 128 Bit ID Utility Library - deprecated +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd +Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-id128.sym b/src/compat-libs/libsystemd-id128.sym new file mode 100644 index 0000000..604c002 --- /dev/null +++ b/src/compat-libs/libsystemd-id128.sym @@ -0,0 +1,21 @@ +/*** + 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. +***/ + +/* Original symbols from systemd v38 */ + +LIBSYSTEMD_ID128_38 { +global: + sd_id128_to_string; + sd_id128_from_string; + sd_id128_randomize; + sd_id128_get_machine; + sd_id128_get_boot; +local: + *; +}; diff --git a/src/compat-libs/libsystemd-journal.pc.in b/src/compat-libs/libsystemd-journal.pc.in new file mode 100644 index 0000000..395f710 --- /dev/null +++ b/src/compat-libs/libsystemd-journal.pc.in @@ -0,0 +1,19 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Journal Utility Library - deprecated +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Requires: libsystemd = @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd +Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-journal.sym b/src/compat-libs/libsystemd-journal.sym new file mode 100644 index 0000000..4eb1591 --- /dev/null +++ b/src/compat-libs/libsystemd-journal.sym @@ -0,0 +1,111 @@ +/*** + 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. +***/ + +/* Original symbols from systemd v38 */ + +LIBSYSTEMD_JOURNAL_38 { +global: + sd_journal_print; + sd_journal_printv; + sd_journal_send; + sd_journal_sendv; + sd_journal_stream_fd; + sd_journal_open; + sd_journal_close; + sd_journal_previous; + sd_journal_next; + sd_journal_previous_skip; + sd_journal_next_skip; + sd_journal_get_realtime_usec; + sd_journal_get_monotonic_usec; + sd_journal_get_data; + sd_journal_enumerate_data; + sd_journal_restart_data; + sd_journal_add_match; + sd_journal_flush_matches; + sd_journal_seek_head; + sd_journal_seek_tail; + sd_journal_seek_monotonic_usec; + sd_journal_seek_realtime_usec; + sd_journal_seek_cursor; + sd_journal_get_cursor; + sd_journal_get_fd; + sd_journal_process; +local: + *; +}; + +LIBSYSTEMD_JOURNAL_183 { +global: + sd_journal_print_with_location; + sd_journal_printv_with_location; + sd_journal_send_with_location; + sd_journal_sendv_with_location; +} LIBSYSTEMD_JOURNAL_38; + +LIBSYSTEMD_JOURNAL_184 { +global: + sd_journal_get_cutoff_realtime_usec; + sd_journal_get_cutoff_monotonic_usec; +} LIBSYSTEMD_JOURNAL_183; + +LIBSYSTEMD_JOURNAL_187 { +global: + sd_journal_wait; + sd_journal_open_directory; + sd_journal_add_disjunction; +} LIBSYSTEMD_JOURNAL_184; + +LIBSYSTEMD_JOURNAL_188 { +global: + sd_journal_perror; + sd_journal_perror_with_location; +} LIBSYSTEMD_JOURNAL_187; + +LIBSYSTEMD_JOURNAL_190 { +global: + sd_journal_get_usage; +} LIBSYSTEMD_JOURNAL_188; + +LIBSYSTEMD_JOURNAL_195 { +global: + sd_journal_test_cursor; + sd_journal_query_unique; + sd_journal_enumerate_unique; + sd_journal_restart_unique; +} LIBSYSTEMD_JOURNAL_190; + +LIBSYSTEMD_JOURNAL_196 { +global: + sd_journal_get_catalog; + sd_journal_get_catalog_for_message_id; + sd_journal_set_data_threshold; + sd_journal_get_data_threshold; +} LIBSYSTEMD_JOURNAL_195; + +LIBSYSTEMD_JOURNAL_198 { +global: + sd_journal_reliable_fd; +} LIBSYSTEMD_JOURNAL_196; + +LIBSYSTEMD_JOURNAL_201 { +global: + sd_journal_get_events; + sd_journal_get_timeout; +} LIBSYSTEMD_JOURNAL_198; + +LIBSYSTEMD_JOURNAL_202 { +global: + sd_journal_add_conjunction; +} LIBSYSTEMD_JOURNAL_201; + +LIBSYSTEMD_JOURNAL_205 { +global: + sd_journal_open_files; +} LIBSYSTEMD_JOURNAL_202; diff --git a/src/compat-libs/libsystemd-login.pc.in b/src/compat-libs/libsystemd-login.pc.in new file mode 100644 index 0000000..db3f79c --- /dev/null +++ b/src/compat-libs/libsystemd-login.pc.in @@ -0,0 +1,18 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Login Utility Library - deprecated +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd +Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-login.sym b/src/compat-libs/libsystemd-login.sym new file mode 100644 index 0000000..54aa91c --- /dev/null +++ b/src/compat-libs/libsystemd-login.sym @@ -0,0 +1,87 @@ +/*** + 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. +***/ + +/* Original symbols from systemd v31 */ + +LIBSYSTEMD_LOGIN_31 { +global: + sd_get_seats; + sd_get_sessions; + sd_get_uids; + sd_login_monitor_flush; + sd_login_monitor_get_fd; + sd_login_monitor_new; + sd_login_monitor_unref; + sd_pid_get_owner_uid; + sd_pid_get_session; + sd_seat_can_multi_session; + sd_seat_get_active; + sd_seat_get_sessions; + sd_session_get_seat; + sd_session_get_uid; + sd_session_is_active; + sd_uid_get_seats; + sd_uid_get_sessions; + sd_uid_get_state; + sd_uid_is_on_seat; +local: + *; +}; + +LIBSYSTEMD_LOGIN_38 { +global: + sd_pid_get_unit; + sd_session_get_service; +} LIBSYSTEMD_LOGIN_31; + +LIBSYSTEMD_LOGIN_43 { +global: + sd_session_get_type; + sd_session_get_class; + sd_session_get_display; +} LIBSYSTEMD_LOGIN_38; + +LIBSYSTEMD_LOGIN_186 { +global: + sd_session_get_state; + sd_seat_can_tty; + sd_seat_can_graphical; +} LIBSYSTEMD_LOGIN_43; + +LIBSYSTEMD_LOGIN_198 { +global: + sd_session_get_tty; +} LIBSYSTEMD_LOGIN_186; + +LIBSYSTEMD_LOGIN_201 { +global: + sd_login_monitor_get_events; + sd_login_monitor_get_timeout; +} LIBSYSTEMD_LOGIN_198; + +LIBSYSTEMD_LOGIN_202 { +global: + sd_pid_get_user_unit; + sd_pid_get_machine_name; +} LIBSYSTEMD_LOGIN_201; + +LIBSYSTEMD_LOGIN_203 { +global: + sd_get_machine_names; +} LIBSYSTEMD_LOGIN_202; + +LIBSYSTEMD_LOGIN_205 { +global: + sd_pid_get_slice; +} LIBSYSTEMD_LOGIN_203; + +LIBSYSTEMD_LOGIN_207 { +global: + sd_session_get_vt; +} LIBSYSTEMD_LOGIN_205; diff --git a/src/compat-libs/linkwarning.h b/src/compat-libs/linkwarning.h new file mode 100644 index 0000000..a2e9534 --- /dev/null +++ b/src/compat-libs/linkwarning.h @@ -0,0 +1,33 @@ +/*** + This file is part of systemd, but is heavily based on + glibc's libc-symbols.h. + + Copyright (C) 1995-1998,2000-2006,2008,2009 Free Software Foundation, Inc + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define __make_section_unallocated(section_string) \ + asm (".section " section_string "\n\t.previous"); + +#define __sec_comment "\n#APP\n\t#" + +#define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." #symbol) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \ + = msg + +#define obsolete_lib(name, lib) \ + link_warning(name, #name " was moved to libsystemd. Do not use " #lib ".") diff --git a/src/condition.c b/src/condition.c deleted file mode 100644 index f18c454..0000000 --- a/src/condition.c +++ /dev/null @@ -1,321 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#ifdef HAVE_SELINUX -#include -#endif - -#include "util.h" -#include "condition.h" -#include "virt.h" - -Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { - Condition *c; - - assert(type < _CONDITION_TYPE_MAX); - - c = new0(Condition, 1); - if (!c) - return NULL; - - c->type = type; - c->trigger = trigger; - c->negate = negate; - - if (parameter) { - c->parameter = strdup(parameter); - if (!c->parameter) { - free(c); - return NULL; - } - } - - return c; -} - -void condition_free(Condition *c) { - assert(c); - - free(c->parameter); - free(c); -} - -void condition_free_list(Condition *first) { - Condition *c, *n; - - LIST_FOREACH_SAFE(conditions, c, n, first) - condition_free(c); -} - -static bool test_kernel_command_line(const char *parameter) { - char *line, *w, *state, *word = NULL; - bool equal; - int r; - size_t l, pl; - bool found = false; - - assert(parameter); - - if (detect_container(NULL) > 0) - return false; - - r = read_one_line_file("/proc/cmdline", &line); - if (r < 0) { - log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); - return false; - } - - equal = !!strchr(parameter, '='); - pl = strlen(parameter); - - FOREACH_WORD_QUOTED(w, l, line, state) { - - free(word); - word = strndup(w, l); - if (!word) - break; - - if (equal) { - if (streq(word, parameter)) { - found = true; - break; - } - } else { - if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) { - found = true; - break; - } - } - - } - - free(word); - free(line); - - return found; -} - -static bool test_virtualization(const char *parameter) { - int b; - Virtualization v; - const char *id; - - assert(parameter); - - v = detect_virtualization(&id); - if (v < 0) { - log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v)); - return false; - } - - /* First, compare with yes/no */ - b = parse_boolean(parameter); - - if (v > 0 && b > 0) - return true; - - if (v == 0 && b == 0) - return true; - - /* Then, compare categorization */ - if (v == VIRTUALIZATION_VM && streq(parameter, "vm")) - return true; - - if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container")) - return true; - - /* Finally compare id */ - return v > 0 && streq(parameter, id); -} - -static bool test_security(const char *parameter) { -#ifdef HAVE_SELINUX - if (streq(parameter, "selinux")) - return is_selinux_enabled() > 0; -#endif - return false; -} - -static bool test_capability(const char *parameter) { - cap_value_t value; - FILE *f; - char line[LINE_MAX]; - unsigned long long capabilities = (unsigned long long) -1; - - /* If it's an invalid capability, we don't have it */ - - if (cap_from_name(parameter, &value) < 0) - return false; - - /* If it's a valid capability we default to assume - * that we have it */ - - f = fopen("/proc/self/status", "re"); - if (!f) - return true; - - while (fgets(line, sizeof(line), f)) { - truncate_nl(line); - - if (startswith(line, "CapBnd:")) { - (void) sscanf(line+7, "%llx", &capabilities); - break; - } - } - - return !!(capabilities & (1ULL << value)); -} - -bool condition_test(Condition *c) { - assert(c); - - switch(c->type) { - - case CONDITION_PATH_EXISTS: - return (access(c->parameter, F_OK) >= 0) == !c->negate; - - case CONDITION_PATH_EXISTS_GLOB: - return (glob_exists(c->parameter) > 0) == !c->negate; - - case CONDITION_PATH_IS_DIRECTORY: { - struct stat st; - - if (stat(c->parameter, &st) < 0) - return c->negate; - return S_ISDIR(st.st_mode) == !c->negate; - } - - case CONDITION_PATH_IS_SYMBOLIC_LINK: { - struct stat st; - - if (lstat(c->parameter, &st) < 0) - return c->negate; - return S_ISLNK(st.st_mode) == !c->negate; - } - - case CONDITION_PATH_IS_MOUNT_POINT: - return (path_is_mount_point(c->parameter, true) > 0) == !c->negate; - - case CONDITION_DIRECTORY_NOT_EMPTY: { - int k; - - k = dir_is_empty(c->parameter); - return !(k == -ENOENT || k > 0) == !c->negate; - } - - case CONDITION_FILE_IS_EXECUTABLE: { - struct stat st; - - if (stat(c->parameter, &st) < 0) - return c->negate; - - return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate; - } - - case CONDITION_KERNEL_COMMAND_LINE: - return test_kernel_command_line(c->parameter) == !c->negate; - - case CONDITION_VIRTUALIZATION: - return test_virtualization(c->parameter) == !c->negate; - - case CONDITION_SECURITY: - return test_security(c->parameter) == !c->negate; - - case CONDITION_CAPABILITY: - return test_capability(c->parameter) == !c->negate; - - case CONDITION_NULL: - return !c->negate; - - default: - assert_not_reached("Invalid condition type."); - } -} - -bool condition_test_list(Condition *first) { - Condition *c; - int triggered = -1; - - /* 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) { - bool b; - - b = condition_test(c); - - if (!c->trigger && !b) - return false; - - if (c->trigger && triggered <= 0) - triggered = b; - } - - return triggered != 0; -} - -void condition_dump(Condition *c, FILE *f, const char *prefix) { - assert(c); - assert(f); - - if (!prefix) - prefix = ""; - - fprintf(f, - "%s\t%s: %s%s%s\n", - prefix, - condition_type_to_string(c->type), - c->trigger ? "|" : "", - c->negate ? "!" : "", - c->parameter); -} - -void condition_dump_list(Condition *first, FILE *f, const char *prefix) { - Condition *c; - - LIST_FOREACH(conditions, c, first) - condition_dump(c, f, prefix); -} - -static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { - [CONDITION_PATH_EXISTS] = "ConditionPathExists", - [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob", - [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory", - [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink", - [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint", - [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty", - [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", - [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", - [CONDITION_SECURITY] = "ConditionSecurity", - [CONDITION_NULL] = "ConditionNull" -}; - -DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType); diff --git a/src/condition.h b/src/condition.h deleted file mode 100644 index 71b1c67..0000000 --- a/src/condition.h +++ /dev/null @@ -1,69 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooconditionhfoo -#define fooconditionhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "list.h" - -typedef enum ConditionType { - CONDITION_PATH_EXISTS, - CONDITION_PATH_EXISTS_GLOB, - CONDITION_PATH_IS_DIRECTORY, - CONDITION_PATH_IS_SYMBOLIC_LINK, - CONDITION_PATH_IS_MOUNT_POINT, - CONDITION_DIRECTORY_NOT_EMPTY, - CONDITION_FILE_IS_EXECUTABLE, - CONDITION_KERNEL_COMMAND_LINE, - CONDITION_VIRTUALIZATION, - CONDITION_SECURITY, - CONDITION_CAPABILITY, - CONDITION_NULL, - _CONDITION_TYPE_MAX, - _CONDITION_TYPE_INVALID = -1 -} ConditionType; - -typedef struct Condition { - ConditionType type; - char *parameter; - - bool trigger:1; - bool negate:1; - - LIST_FIELDS(struct Condition, conditions); -} Condition; - -Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate); -void condition_free(Condition *c); -void condition_free_list(Condition *c); - -bool condition_test(Condition *c); -bool condition_test_list(Condition *c); - -void condition_dump(Condition *c, FILE *f, const char *prefix); -void condition_dump_list(Condition *c, FILE *f, const char *prefix); - -const char* condition_type_to_string(ConditionType t); -int condition_type_from_string(const char *s); - -#endif diff --git a/src/conf-parser.c b/src/conf-parser.c deleted file mode 100644 index a71dcd0..0000000 --- a/src/conf-parser.c +++ /dev/null @@ -1,754 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "conf-parser.h" -#include "util.h" -#include "macro.h" -#include "strv.h" -#include "log.h" - -int config_item_table_lookup( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata) { - - ConfigTableItem *t; - - assert(table); - assert(lvalue); - assert(func); - assert(ltype); - assert(data); - - for (t = table; t->lvalue; t++) { - - if (!streq(lvalue, t->lvalue)) - continue; - - if (!streq_ptr(section, t->section)) - continue; - - *func = t->parse; - *ltype = t->ltype; - *data = t->data; - return 1; - } - - return 0; -} - -int config_item_perf_lookup( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata) { - - ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; - const ConfigPerfItem *p; - - assert(table); - assert(lvalue); - assert(func); - assert(ltype); - assert(data); - - if (!section) - p = lookup(lvalue, strlen(lvalue)); - else { - char *key; - - key = join(section, ".", lvalue, NULL); - if (!key) - return -ENOMEM; - - p = lookup(key, strlen(key)); - free(key); - } - - if (!p) - return 0; - - *func = p->parse; - *ltype = p->ltype; - *data = (uint8_t*) userdata + p->offset; - return 1; -} - -/* Run the user supplied parser for an assignment */ -static int next_assignment( - const char *filename, - unsigned line, - ConfigItemLookup lookup, - void *table, - const char *section, - const char *lvalue, - const char *rvalue, - bool relaxed, - void *userdata) { - - ConfigParserCallback func = NULL; - int ltype = 0; - void *data = NULL; - int r; - - assert(filename); - assert(line > 0); - assert(lookup); - assert(lvalue); - assert(rvalue); - - r = lookup(table, section, lvalue, &func, <ype, &data, userdata); - if (r < 0) - return r; - - if (r > 0) { - if (func) - return func(filename, line, section, lvalue, ltype, rvalue, data, userdata); - - return 0; - } - - /* Warn about unknown non-extension fields. */ - if (!relaxed && !startswith(lvalue, "X-")) - log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section); - - return 0; -} - -/* Parse a variable assignment line */ -static int parse_line( - const char *filename, - unsigned line, - const char *sections, - ConfigItemLookup lookup, - void *table, - bool relaxed, - char **section, - char *l, - void *userdata) { - - char *e; - - assert(filename); - assert(line > 0); - assert(lookup); - assert(l); - - l = strstrip(l); - - if (!*l) - return 0; - - if (strchr(COMMENTS, *l)) - return 0; - - if (startswith(l, ".include ")) { - char *fn; - int r; - - fn = file_in_same_dir(filename, strstrip(l+9)); - if (!fn) - return -ENOMEM; - - r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata); - free(fn); - - return r; - } - - if (*l == '[') { - size_t k; - char *n; - - k = strlen(l); - assert(k > 0); - - if (l[k-1] != ']') { - log_error("[%s:%u] Invalid section header.", filename, line); - return -EBADMSG; - } - - n = strndup(l+1, k-2); - if (!n) - return -ENOMEM; - - if (sections && !nulstr_contains(sections, n)) { - - if (!relaxed) - log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); - - free(n); - *section = NULL; - } else { - free(*section); - *section = n; - } - - return 0; - } - - if (sections && !*section) - return 0; - - e = strchr(l, '='); - if (!e) { - log_error("[%s:%u] Missing '='.", filename, line); - return -EBADMSG; - } - - *e = 0; - e++; - - return next_assignment( - filename, - line, - lookup, - table, - *section, - strstrip(l), - strstrip(e), - relaxed, - userdata); -} - -/* Go through the file and parse each line */ -int config_parse( - const char *filename, - FILE *f, - const char *sections, - ConfigItemLookup lookup, - void *table, - bool relaxed, - void *userdata) { - - unsigned line = 0; - char *section = NULL; - int r; - bool ours = false; - char *continuation = NULL; - - assert(filename); - assert(lookup); - - if (!f) { - f = fopen(filename, "re"); - if (!f) { - r = -errno; - log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); - goto finish; - } - - ours = true; - } - - while (!feof(f)) { - char l[LINE_MAX], *p, *c = NULL, *e; - bool escaped = false; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - log_error("Failed to read configuration file '%s': %s", filename, strerror(-r)); - goto finish; - } - - truncate_nl(l); - - if (continuation) { - c = strappend(continuation, l); - if (!c) { - r = -ENOMEM; - goto finish; - } - - free(continuation); - continuation = NULL; - p = c; - } else - p = l; - - for (e = p; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - } - - if (escaped) { - *(e-1) = ' '; - - if (c) - continuation = c; - else { - continuation = strdup(l); - if (!continuation) { - r = -ENOMEM; - goto finish; - } - } - - continue; - } - - r = parse_line(filename, - ++line, - sections, - lookup, - table, - relaxed, - §ion, - p, - userdata); - free(c); - - if (r < 0) - goto finish; - } - - r = 0; - -finish: - free(section); - free(continuation); - - if (f && ours) - fclose(f); - - return r; -} - -int config_parse_int( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *i = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atoi(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_long( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - long *i = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atoli(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_uint64( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - uint64_t *u = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou64(rvalue, u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_unsigned( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - unsigned *u = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou(rvalue, u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; - } - - return 0; -} - -int config_parse_size( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - size_t *sz = data; - unsigned u; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou(rvalue, &u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *sz = (size_t) u; - return 0; -} - -int config_parse_bool( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int k; - bool *b = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((k = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *b = !!k; - return 0; -} - -int config_parse_string( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (*rvalue) { - if (!(n = strdup(rvalue))) - return -ENOMEM; - } else - n = NULL; - - free(*s); - *s = n; - - return 0; -} - -int config_parse_path( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (!(n = strdup(rvalue))) - return -ENOMEM; - - path_kill_slashes(n); - - free(*s); - *s = n; - - return 0; -} - -int config_parse_strv( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char*** sv = data; - char **n; - char *w; - unsigned k; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - k = strv_length(*sv); - FOREACH_WORD_QUOTED(w, l, rvalue, state) - k++; - - if (!(n = new(char*, k+1))) - return -ENOMEM; - - if (*sv) - for (k = 0; (*sv)[k]; k++) - n[k] = (*sv)[k]; - else - k = 0; - - FOREACH_WORD_QUOTED(w, l, rvalue, state) - if (!(n[k++] = cunescape_length(w, l))) - goto fail; - - n[k] = NULL; - free(*sv); - *sv = n; - - return 0; - -fail: - for (; k > 0; k--) - free(n[k-1]); - free(n); - - return -ENOMEM; -} - -int config_parse_path_strv( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char*** sv = data; - char **n; - char *w; - unsigned k; - size_t l; - char *state; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - k = strv_length(*sv); - FOREACH_WORD_QUOTED(w, l, rvalue, state) - k++; - - if (!(n = new(char*, k+1))) - return -ENOMEM; - - k = 0; - if (*sv) - for (; (*sv)[k]; k++) - n[k] = (*sv)[k]; - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (!(n[k] = cunescape_length(w, l))) { - r = -ENOMEM; - goto fail; - } - - if (!path_is_absolute(n[k])) { - log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); - free(n[k]); - continue; - } - - path_kill_slashes(n[k]); - - k++; - } - - n[k] = NULL; - free(*sv); - *sv = n; - - return 0; - -fail: - free(n[k]); - for (; k > 0; k--) - free(n[k-1]); - free(n); - - return r; -} - -int config_parse_usec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - usec_t *usec = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_usec(rvalue, usec) < 0) { - log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_mode( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - mode_t *m = data; - long l; - char *x = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - errno = 0; - l = strtol(rvalue, &x, 8); - if (!x || *x || errno) { - log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (l < 0000 || l > 07777) { - log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); - return 0; - } - - *m = (mode_t) l; - return 0; -} diff --git a/src/conf-parser.h b/src/conf-parser.h deleted file mode 100644 index cbb4235..0000000 --- a/src/conf-parser.h +++ /dev/null @@ -1,133 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooconfparserhfoo -#define fooconfparserhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -/* An abstract parser for simple, line based, shallow configuration - * files consisting of variable assignments only. */ - -/* Prototype for a parser for a specific configuration setting */ -typedef int (*ConfigParserCallback)( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -/* Wraps information for parsing a specific configuration variable, to - * be stored in a simple array */ -typedef struct ConfigTableItem { - const char *section; /* Section */ - const char *lvalue; /* Name of the variable */ - ConfigParserCallback parse; /* Function that is called to parse the variable's value */ - int ltype; /* Distinguish different variables passed to the same callback */ - void *data; /* Where to store the variable's data */ -} ConfigTableItem; - -/* Wraps information for parsing a specific configuration variable, to - * ve srored in a gperf perfect hashtable */ -typedef struct ConfigPerfItem { - const char *section_and_lvalue; /* Section + "." + name of the variable */ - ConfigParserCallback parse; /* Function that is called to parse the variable's value */ - int ltype; /* Distinguish different variables passed to the same callback */ - size_t offset; /* Offset where to store data, from the beginning of userdata */ -} ConfigPerfItem; - -/* Prototype for a low-level gperf lookup function */ -typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length); - -/* Prototype for a generic high-level lookup function */ -typedef int (*ConfigItemLookup)( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata); - -/* Linear table search implementation of ConfigItemLookup, based on - * ConfigTableItem arrays */ -int config_item_table_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); - -/* gperf implementation of ConfigItemLookup, based on gperf - * ConfigPerfItem tables */ -int config_item_perf_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); - -int config_parse( - const char *filename, - FILE *f, - const char *sections, /* nulstr */ - ConfigItemLookup lookup, - void *table, - bool relaxed, - void *userdata); - -/* Generic parsers */ -int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_long(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_usec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ - int function( \ - const char *filename, \ - unsigned line, \ - const char *section, \ - const char *lvalue, \ - int ltype, \ - const char *rvalue, \ - void *data, \ - void *userdata) { \ - \ - type *i = data, x; \ - \ - assert(filename); \ - assert(lvalue); \ - assert(rvalue); \ - assert(data); \ - \ - if ((x = name##_from_string(rvalue)) < 0) { \ - log_error("[%s:%u] " msg ", ignoring: %s", filename, line, rvalue); \ - return 0; \ - } \ - \ - *i = x; \ - \ - return 0; \ - } - -#endif diff --git a/src/core/.gitignore b/src/core/.gitignore new file mode 100644 index 0000000..f293bbd --- /dev/null +++ b/src/core/.gitignore @@ -0,0 +1,2 @@ +/macros.systemd +/systemd.pc diff --git a/src/core/Makefile b/src/core/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/core/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/core/async.c b/src/core/async.c new file mode 100644 index 0000000..af527be --- /dev/null +++ b/src/core/async.c @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "async.h" +#include "log.h" + +int asynchronous_job(void* (*func)(void *p), void *arg) { + pthread_attr_t a; + pthread_t t; + int r; + + /* It kinda sucks that we have to resort to threads to + * implement an asynchronous sync(), but well, such is + * life. + * + * Note that issuing this command right before exiting a + * process will cause the process to wait for the sync() to + * complete. This function hence is nicely asynchronous really + * only in long running processes. */ + + r = pthread_attr_init(&a); + if (r != 0) + return -r; + + r = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); + if (r != 0) { + r = -r; + goto finish; + } + + r = pthread_create(&t, &a, func, arg); + if (r != 0) { + r = -r; + goto finish; + } + +finish: + pthread_attr_destroy(&a); + return r; +} + +static void *sync_thread(void *p) { + sync(); + return NULL; +} + +int asynchronous_sync(void) { + log_debug("Spawning new thread for sync"); + + return asynchronous_job(sync_thread, NULL); +} diff --git a/src/core/async.h b/src/core/async.h new file mode 100644 index 0000000..6601b4d --- /dev/null +++ b/src/core/async.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int asynchronous_job(void* (*func)(void *p), void *arg); +int asynchronous_sync(void); diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c new file mode 100644 index 0000000..5955bd8 --- /dev/null +++ b/src/core/audit-fd.c @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + + +#include +#include "audit-fd.h" + +#ifdef HAVE_AUDIT + +#include +#include + +#include "log.h" +#include "util.h" + +static bool initialized = false; +static int audit_fd; + +int get_audit_fd(void) { + + if (!initialized) { + audit_fd = audit_open(); + + if (audit_fd < 0) { + if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) + log_error("Failed to connect to audit log: %m"); + + audit_fd = errno ? -errno : -EINVAL; + } + + initialized = true; + } + + return audit_fd; +} + +void close_audit_fd(void) { + + if (initialized && audit_fd >= 0) + close_nointr_nofail(audit_fd); + + initialized = true; + audit_fd = -ECONNRESET; +} + +#else + +int get_audit_fd(void) { + return -EAFNOSUPPORT; +} + +void close_audit_fd(void) { +} + +#endif diff --git a/src/core/audit-fd.h b/src/core/audit-fd.h new file mode 100644 index 0000000..8b58289 --- /dev/null +++ b/src/core/audit-fd.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int get_audit_fd(void); +void close_audit_fd(void); diff --git a/src/core/automount.c b/src/core/automount.c new file mode 100644 index 0000000..889b20e --- /dev/null +++ b/src/core/automount.c @@ -0,0 +1,891 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "unit.h" +#include "automount.h" +#include "mount.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "unit-name.h" +#include "special.h" +#include "label.h" +#include "mkdir.h" +#include "path-util.h" +#include "dbus-automount.h" +#include "bus-util.h" +#include "bus-error.h" + +static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = UNIT_INACTIVE, + [AUTOMOUNT_WAITING] = UNIT_ACTIVE, + [AUTOMOUNT_RUNNING] = UNIT_ACTIVE, + [AUTOMOUNT_FAILED] = UNIT_FAILED +}; + +static int open_dev_autofs(Manager *m); +static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata); + +static void automount_init(Unit *u) { + Automount *a = AUTOMOUNT(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + a->pipe_fd = -1; + a->directory_mode = 0755; + UNIT(a)->ignore_on_isolate = true; +} + +static void repeat_unmount(const char *path) { + assert(path); + + for (;;) { + /* If there are multiple mounts on a mount point, this + * removes them all */ + + if (umount2(path, MNT_DETACH) >= 0) + continue; + + if (errno != EINVAL) + log_error("Failed to unmount: %m"); + + break; + } +} + +static void unmount_autofs(Automount *a) { + assert(a); + + if (a->pipe_fd < 0) + return; + + automount_send_ready(a, -EHOSTDOWN); + + a->pipe_event_source = sd_event_source_unref(a->pipe_event_source); + + close_nointr_nofail(a->pipe_fd); + a->pipe_fd = -1; + + /* If we reload/reexecute things we keep the mount point + * around */ + if (a->where && + (UNIT(a)->manager->exit_code != MANAGER_RELOAD && + UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) + repeat_unmount(a->where); +} + +static void automount_done(Unit *u) { + Automount *a = AUTOMOUNT(u); + + assert(a); + + unmount_autofs(a); + + free(a->where); + a->where = NULL; + + set_free(a->tokens); + a->tokens = NULL; +} + +static int automount_add_mount_links(Automount *a) { + _cleanup_free_ char *parent = NULL; + int r; + + assert(a); + + r = path_get_parent(a->where, &parent); + if (r < 0) + return r; + + return unit_require_mounts_for(UNIT(a), parent); +} + +static int automount_add_default_dependencies(Automount *a) { + int r; + + assert(a); + + if (UNIT(a)->manager->running_as != SYSTEMD_SYSTEM) + return 0; + + r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + if (r < 0) + return r; + + return 0; +} + +static int automount_verify(Automount *a) { + bool b; + char *e; + assert(a); + + if (UNIT(a)->load_state != UNIT_LOADED) + return 0; + + if (path_equal(a->where, "/")) { + log_error_unit(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing."); + return -EINVAL; + } + + e = unit_name_from_path(a->where, ".automount"); + if (!e) + return -ENOMEM; + + b = unit_has_name(UNIT(a), e); + free(e); + + if (!b) { + log_error_unit(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id); + return -EINVAL; + } + + return 0; +} + +static int automount_load(Unit *u) { + Automount *a = AUTOMOUNT(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + /* Load a .automount file */ + r = unit_load_fragment_and_dropin_optional(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + Unit *x; + + if (!a->where) { + a->where = unit_name_to_path(u->id); + if (!a->where) + return -ENOMEM; + } + + path_kill_slashes(a->where); + + r = unit_load_related_unit(u, ".mount", &x); + if (r < 0) + return r; + + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); + if (r < 0) + return r; + + r = automount_add_mount_links(a); + if (r < 0) + return r; + + if (UNIT(a)->default_dependencies) { + r = automount_add_default_dependencies(a); + if (r < 0) + return r; + } + } + + return automount_verify(a); +} + +static void automount_set_state(Automount *a, AutomountState state) { + AutomountState old_state; + assert(a); + + old_state = a->state; + a->state = state; + + if (state != AUTOMOUNT_WAITING && + state != AUTOMOUNT_RUNNING) + unmount_autofs(a); + + if (state != old_state) + log_debug_unit(UNIT(a)->id, + "%s changed %s -> %s", + UNIT(a)->id, + automount_state_to_string(old_state), + automount_state_to_string(state)); + + unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true); +} + +static int automount_coldplug(Unit *u) { + Automount *a = AUTOMOUNT(u); + int r; + + assert(a); + assert(a->state == AUTOMOUNT_DEAD); + + if (a->deserialized_state != a->state) { + + r = open_dev_autofs(u->manager); + if (r < 0) + return r; + + if (a->deserialized_state == AUTOMOUNT_WAITING || + a->deserialized_state == AUTOMOUNT_RUNNING) { + + assert(a->pipe_fd >= 0); + + r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u); + if (r < 0) + return r; + } + + automount_set_state(a, a->deserialized_state); + } + + return 0; +} + +static void automount_dump(Unit *u, FILE *f, const char *prefix) { + Automount *a = AUTOMOUNT(u); + + assert(a); + + fprintf(f, + "%sAutomount State: %s\n" + "%sResult: %s\n" + "%sWhere: %s\n" + "%sDirectoryMode: %04o\n", + prefix, automount_state_to_string(a->state), + prefix, automount_result_to_string(a->result), + prefix, a->where, + prefix, a->directory_mode); +} + +static void automount_enter_dead(Automount *a, AutomountResult f) { + assert(a); + + if (f != AUTOMOUNT_SUCCESS) + a->result = f; + + automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD); +} + +static int open_dev_autofs(Manager *m) { + struct autofs_dev_ioctl param; + + assert(m); + + if (m->dev_autofs_fd >= 0) + return m->dev_autofs_fd; + + label_fix("/dev/autofs", false, false); + + m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY); + if (m->dev_autofs_fd < 0) { + log_error("Failed to open /dev/autofs: %m"); + return -errno; + } + + init_autofs_dev_ioctl(¶m); + if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, ¶m) < 0) { + close_nointr_nofail(m->dev_autofs_fd); + m->dev_autofs_fd = -1; + return -errno; + } + + log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor); + + return m->dev_autofs_fd; +} + +static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) { + struct autofs_dev_ioctl *param; + size_t l; + + assert(dev_autofs_fd >= 0); + assert(where); + + l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1; + param = alloca(l); + + init_autofs_dev_ioctl(param); + param->size = l; + param->ioctlfd = -1; + param->openmount.devid = devid; + strcpy(param->path, where); + + if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) + return -errno; + + if (param->ioctlfd < 0) + return -EIO; + + fd_cloexec(param->ioctlfd, true); + return param->ioctlfd; +} + +static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) { + uint32_t major, minor; + struct autofs_dev_ioctl param; + + assert(dev_autofs_fd >= 0); + assert(ioctl_fd >= 0); + + init_autofs_dev_ioctl(¶m); + param.ioctlfd = ioctl_fd; + + if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, ¶m) < 0) + return -errno; + + major = param.protover.version; + + init_autofs_dev_ioctl(¶m); + param.ioctlfd = ioctl_fd; + + if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, ¶m) < 0) + return -errno; + + minor = param.protosubver.sub_version; + + log_debug("Autofs protocol version %i.%i", major, minor); + return 0; +} + +static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) { + struct autofs_dev_ioctl param; + + assert(dev_autofs_fd >= 0); + assert(ioctl_fd >= 0); + + init_autofs_dev_ioctl(¶m); + param.ioctlfd = ioctl_fd; + param.timeout.timeout = sec; + + if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) < 0) + return -errno; + + return 0; +} + +static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) { + struct autofs_dev_ioctl param; + + assert(dev_autofs_fd >= 0); + assert(ioctl_fd >= 0); + + init_autofs_dev_ioctl(¶m); + param.ioctlfd = ioctl_fd; + + if (status) { + param.fail.token = token; + param.fail.status = status; + } else + param.ready.token = token; + + if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, ¶m) < 0) + return -errno; + + return 0; +} + +int automount_send_ready(Automount *a, int status) { + int ioctl_fd, r; + unsigned token; + + assert(a); + assert(status <= 0); + + if (set_isempty(a->tokens)) + return 0; + + ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id); + if (ioctl_fd < 0) { + r = ioctl_fd; + goto fail; + } + + if (status) + log_debug_unit(UNIT(a)->id, "Sending failure: %s", strerror(-status)); + else + log_debug_unit(UNIT(a)->id, "Sending success."); + + r = 0; + + /* Autofs thankfully does not hand out 0 as a token */ + while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) { + int k; + + /* Autofs fun fact II: + * + * if you pass a positive status code here, the kernel will + * freeze! Yay! */ + + k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd, + ioctl_fd, + token, + status); + if (k < 0) + r = k; + } + +fail: + if (ioctl_fd >= 0) + close_nointr_nofail(ioctl_fd); + + return r; +} + +static void automount_enter_waiting(Automount *a) { + int p[2] = { -1, -1 }; + char name[32], options[128]; + bool mounted = false; + int r, ioctl_fd = -1, dev_autofs_fd; + struct stat st; + + assert(a); + assert(a->pipe_fd < 0); + assert(a->where); + + if (a->tokens) + set_clear(a->tokens); + + dev_autofs_fd = open_dev_autofs(UNIT(a)->manager); + if (dev_autofs_fd < 0) { + r = dev_autofs_fd; + goto fail; + } + + /* We knowingly ignore the results of this call */ + mkdir_p_label(a->where, 0555); + + warn_if_dir_nonempty(a->meta.id, a->where); + + if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) { + r = -errno; + goto fail; + } + + snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp()); + char_array_0(options); + + snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid()); + char_array_0(name); + + if (mount(name, a->where, "autofs", 0, options) < 0) { + r = -errno; + goto fail; + } + + mounted = true; + + close_nointr_nofail(p[1]); + p[1] = -1; + + if (stat(a->where, &st) < 0) { + r = -errno; + goto fail; + } + + ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev); + if (ioctl_fd < 0) { + r = ioctl_fd; + goto fail; + } + + r = autofs_protocol(dev_autofs_fd, ioctl_fd); + if (r < 0) + goto fail; + + r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300); + if (r < 0) + goto fail; + + /* Autofs fun fact: + * + * Unless we close the ioctl fd here, for some weird reason + * the direct mount will not receive events from the + * kernel. */ + + close_nointr_nofail(ioctl_fd); + ioctl_fd = -1; + + r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a); + if (r < 0) + goto fail; + + a->pipe_fd = p[0]; + a->dev_id = st.st_dev; + + automount_set_state(a, AUTOMOUNT_WAITING); + + return; + +fail: + assert_se(close_pipe(p) == 0); + + if (ioctl_fd >= 0) + close_nointr_nofail(ioctl_fd); + + if (mounted) + repeat_unmount(a->where); + + log_error_unit(UNIT(a)->id, + "Failed to initialize automounter: %s", strerror(-r)); + automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); +} + +static void automount_enter_runnning(Automount *a) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct stat st; + int r; + + assert(a); + + /* We don't take mount requests anymore if we are supposed to + * shut down anyway */ + if (unit_stop_pending(UNIT(a))) { + log_debug_unit(UNIT(a)->id, + "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id); + automount_send_ready(a, -EHOSTDOWN); + return; + } + + 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) { + log_warning_unit(UNIT(a)->id, + "%s failed to stat automount point: %m", UNIT(a)->id); + goto fail; + } + + if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) + log_info_unit(UNIT(a)->id, + "%s's automount point already active?", UNIT(a)->id); + else { + r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), + JOB_REPLACE, true, &error, NULL); + if (r < 0) { + log_warning_unit(UNIT(a)->id, + "%s failed to queue mount startup job: %s", + UNIT(a)->id, bus_error_message(&error, r)); + goto fail; + } + } + + automount_set_state(a, AUTOMOUNT_RUNNING); + return; + +fail: + automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); +} + +static int automount_start(Unit *u) { + Automount *a = AUTOMOUNT(u); + + assert(a); + assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); + + if (path_is_mount_point(a->where, false)) { + log_error_unit(u->id, + "Path %s is already a mount point, refusing start for %s", + a->where, u->id); + return -EEXIST; + } + + if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + return -ENOENT; + + a->result = AUTOMOUNT_SUCCESS; + automount_enter_waiting(a); + return 0; +} + +static int automount_stop(Unit *u) { + Automount *a = AUTOMOUNT(u); + + assert(a); + assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING); + + automount_enter_dead(a, AUTOMOUNT_SUCCESS); + return 0; +} + +static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { + Automount *a = AUTOMOUNT(u); + void *p; + Iterator i; + + assert(a); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", automount_state_to_string(a->state)); + unit_serialize_item(u, f, "result", automount_result_to_string(a->result)); + unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id); + + SET_FOREACH(p, a->tokens, i) + unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p)); + + if (a->pipe_fd >= 0) { + int copy; + + copy = fdset_put_dup(fds, a->pipe_fd); + if (copy < 0) + return copy; + + unit_serialize_item_format(u, f, "pipe-fd", "%i", copy); + } + + return 0; +} + +static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Automount *a = AUTOMOUNT(u); + int r; + + assert(a); + assert(fds); + + if (streq(key, "state")) { + AutomountState state; + + state = automount_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + a->deserialized_state = state; + } else if (streq(key, "result")) { + AutomountResult f; + + f = automount_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != AUTOMOUNT_SUCCESS) + a->result = f; + + } else if (streq(key, "dev-id")) { + unsigned d; + + if (safe_atou(value, &d) < 0) + log_debug_unit(u->id, "Failed to parse dev-id value %s", value); + else + a->dev_id = (unsigned) d; + } else if (streq(key, "token")) { + unsigned token; + + if (safe_atou(value, &token) < 0) + log_debug_unit(u->id, "Failed to parse token value %s", value); + else { + if (!a->tokens) + if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) + return -ENOMEM; + + r = set_put(a->tokens, UINT_TO_PTR(token)); + if (r < 0) + return r; + } + } else if (streq(key, "pipe-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse pipe-fd value %s", value); + else { + if (a->pipe_fd >= 0) + close_nointr_nofail(a->pipe_fd); + + a->pipe_fd = fdset_remove(fds, fd); + } + } else + log_debug_unit(u->id, "Unknown serialization key '%s'", key); + + return 0; +} + +static UnitActiveState automount_active_state(Unit *u) { + assert(u); + + return state_translation_table[AUTOMOUNT(u)->state]; +} + +static const char *automount_sub_state_to_string(Unit *u) { + assert(u); + + return automount_state_to_string(AUTOMOUNT(u)->state); +} + +static bool automount_check_gc(Unit *u) { + assert(u); + + if (!UNIT_TRIGGER(u)) + return false; + + return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u)); +} + +static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { + union autofs_v5_packet_union packet; + Automount *a = AUTOMOUNT(userdata); + ssize_t l; + int r; + + assert(a); + assert(fd == a->pipe_fd); + + if (events != EPOLLIN) { + log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe."); + goto fail; + } + + l = loop_read(a->pipe_fd, &packet, sizeof(packet), true); + if (l != sizeof(packet)) { + log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); + goto fail; + } + + switch (packet.hdr.type) { + + case autofs_ptype_missing_direct: + + if (packet.v5_packet.pid > 0) { + _cleanup_free_ char *p = NULL; + + get_process_comm(packet.v5_packet.pid, &p); + log_info_unit(UNIT(a)->id, + "Got automount request for %s, triggered by "PID_FMT" (%s)", + a->where, packet.v5_packet.pid, strna(p)); + } else + log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where); + + r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func); + if (r < 0) { + log_error_unit(UNIT(a)->id, "Failed to allocate token set."); + goto fail; + } + + r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token)); + if (r < 0) { + log_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r)); + goto fail; + } + + automount_enter_runnning(a); + break; + + default: + log_error_unit(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type); + break; + } + + return 0; + +fail: + automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); + return 0; +} + +static void automount_shutdown(Manager *m) { + assert(m); + + if (m->dev_autofs_fd >= 0) + close_nointr_nofail(m->dev_autofs_fd); +} + +static void automount_reset_failed(Unit *u) { + Automount *a = AUTOMOUNT(u); + + assert(a); + + if (a->state == AUTOMOUNT_FAILED) + automount_set_state(a, AUTOMOUNT_DEAD); + + a->result = AUTOMOUNT_SUCCESS; +} + +static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = "dead", + [AUTOMOUNT_WAITING] = "waiting", + [AUTOMOUNT_RUNNING] = "running", + [AUTOMOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); + +static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { + [AUTOMOUNT_SUCCESS] = "success", + [AUTOMOUNT_FAILURE_RESOURCES] = "resources" +}; + +DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); + +const UnitVTable automount_vtable = { + .object_size = sizeof(Automount), + + .sections = + "Unit\0" + "Automount\0" + "Install\0", + + .no_alias = true, + .no_instances = true, + + .init = automount_init, + .load = automount_load, + .done = automount_done, + + .coldplug = automount_coldplug, + + .dump = automount_dump, + + .start = automount_start, + .stop = automount_stop, + + .serialize = automount_serialize, + .deserialize_item = automount_deserialize_item, + + .active_state = automount_active_state, + .sub_state_to_string = automount_sub_state_to_string, + + .check_gc = automount_check_gc, + + .reset_failed = automount_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.Automount", + .bus_vtable = bus_automount_vtable, + + .shutdown = automount_shutdown, + + .status_message_formats = { + .finished_start_job = { + [JOB_DONE] = "Set up automount %s.", + [JOB_FAILED] = "Failed to set up automount %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Unset automount %s.", + [JOB_FAILED] = "Failed to unset automount %s.", + }, + }, +}; diff --git a/src/core/automount.h b/src/core/automount.h new file mode 100644 index 0000000..60f5522 --- /dev/null +++ b/src/core/automount.h @@ -0,0 +1,69 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Automount Automount; + +#include "unit.h" + +typedef enum AutomountState { + AUTOMOUNT_DEAD, + AUTOMOUNT_WAITING, + AUTOMOUNT_RUNNING, + AUTOMOUNT_FAILED, + _AUTOMOUNT_STATE_MAX, + _AUTOMOUNT_STATE_INVALID = -1 +} AutomountState; + +typedef enum AutomountResult { + AUTOMOUNT_SUCCESS, + AUTOMOUNT_FAILURE_RESOURCES, + _AUTOMOUNT_RESULT_MAX, + _AUTOMOUNT_RESULT_INVALID = -1 +} AutomountResult; + +struct Automount { + Unit meta; + + AutomountState state, deserialized_state; + + char *where; + + int pipe_fd; + sd_event_source *pipe_event_source; + mode_t directory_mode; + dev_t dev_id; + + Set *tokens; + + AutomountResult result; +}; + +extern const UnitVTable automount_vtable; + +int automount_send_ready(Automount *a, int status); + +const char* automount_state_to_string(AutomountState i) _const_; +AutomountState automount_state_from_string(const char *s) _pure_; + +const char* automount_result_to_string(AutomountResult i) _const_; +AutomountResult automount_result_from_string(const char *s) _pure_; diff --git a/src/core/build.h b/src/core/build.h new file mode 100644 index 0000000..3d7cd3e --- /dev/null +++ b/src/core/build.h @@ -0,0 +1,96 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifdef HAVE_PAM +#define _PAM_FEATURE_ "+PAM" +#else +#define _PAM_FEATURE_ "-PAM" +#endif + +#ifdef HAVE_LIBWRAP +#define _LIBWRAP_FEATURE_ "+LIBWRAP" +#else +#define _LIBWRAP_FEATURE_ "-LIBWRAP" +#endif + +#ifdef HAVE_AUDIT +#define _AUDIT_FEATURE_ "+AUDIT" +#else +#define _AUDIT_FEATURE_ "-AUDIT" +#endif + +#ifdef HAVE_SELINUX +#define _SELINUX_FEATURE_ "+SELINUX" +#else +#define _SELINUX_FEATURE_ "-SELINUX" +#endif + +#ifdef HAVE_APPARMOR +#define _APPARMOR_FEATURE_ "+APPARMOR" +#else +#define _APPARMOR_FEATURE_ "-APPARMOR" +#endif + +#ifdef HAVE_IMA +#define _IMA_FEATURE_ "+IMA" +#else +#define _IMA_FEATURE_ "-IMA" +#endif + +#ifdef HAVE_SYSV_COMPAT +#define _SYSVINIT_FEATURE_ "+SYSVINIT" +#else +#define _SYSVINIT_FEATURE_ "-SYSVINIT" +#endif + +#ifdef HAVE_LIBCRYPTSETUP +#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" +#else +#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" +#endif + +#ifdef HAVE_GCRYPT +#define _GCRYPT_FEATURE_ "+GCRYPT" +#else +#define _GCRYPT_FEATURE_ "-GCRYPT" +#endif + +#ifdef HAVE_ACL +#define _ACL_FEATURE_ "+ACL" +#else +#define _ACL_FEATURE_ "-ACL" +#endif + +#ifdef HAVE_XZ +#define _XZ_FEATURE_ "+XZ" +#else +#define _XZ_FEATURE_ "-XZ" +#endif + +#ifdef HAVE_SECCOMP +#define _SECCOMP_FEATURE_ "+SECCOMP" +#else +#define _SECCOMP_FEATURE_ "-SECCOMP" +#endif + +#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ " " _SECCOMP_FEATURE_ " " _APPARMOR_FEATURE_ diff --git a/src/core/busname.c b/src/core/busname.c new file mode 100644 index 0000000..4c34538 --- /dev/null +++ b/src/core/busname.c @@ -0,0 +1,601 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "special.h" +#include "bus-kernel.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "service.h" +#include "dbus-busname.h" +#include "busname.h" + +static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = UNIT_INACTIVE, + [BUSNAME_LISTENING] = UNIT_ACTIVE, + [BUSNAME_RUNNING] = UNIT_ACTIVE, + [BUSNAME_FAILED] = UNIT_FAILED +}; + +static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +static void busname_init(Unit *u) { + BusName *n = BUSNAME(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + n->starter_fd = -1; +} + +static void busname_done(Unit *u) { + BusName *n = BUSNAME(u); + + assert(u); + + free(n->name); + n->name = NULL; + + unit_ref_unset(&n->service); + + n->event_source = sd_event_source_unref(n->event_source); + + if (n->starter_fd >= 0) { + close_nointr_nofail(n->starter_fd); + n->starter_fd = -1; + } +} + +static int busname_add_default_default_dependencies(BusName *n) { + int r; + + assert(n); + + r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true); + if (r < 0) + return r; + + if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + if (r < 0) + return r; + } + + return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); +} + +static int busname_add_extras(BusName *n) { + Unit *u = UNIT(n); + int r; + + assert(n); + + if (!n->name) { + n->name = unit_name_to_prefix(u->id); + if (!n->name) + return -ENOMEM; + } + + if (!u->description) { + r = unit_set_description(u, n->name); + if (r < 0) + return r; + } + + if (!UNIT_DEREF(n->service)) { + Unit *x; + + r = unit_load_related_unit(u, ".service", &x); + if (r < 0) + return r; + + unit_ref_set(&n->service, x); + } + + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true); + if (r < 0) + return r; + + if (u->default_dependencies) { + r = busname_add_default_default_dependencies(n); + if (r < 0) + return r; + } + + return 0; +} + + + +static int busname_verify(BusName *n) { + char *e; + + assert(n); + + if (UNIT(n)->load_state != UNIT_LOADED) + return 0; + + if (!service_name_is_valid(n->name)) { + log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id); + return -EINVAL; + } + + e = strappenda(n->name, ".busname"); + if (!unit_has_name(UNIT(n), e)) { + log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id); + return -EINVAL; + } + + return 0; +} + +static int busname_load(Unit *u) { + BusName *n = BUSNAME(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + /* This is a new unit? Then let's add in some extras */ + r = busname_add_extras(n); + if (r < 0) + return r; + } + + return busname_verify(n); +} + +static void busname_dump(Unit *u, FILE *f, const char *prefix) { + BusName *n = BUSNAME(u); + + assert(n); + assert(f); + + fprintf(f, + "%sBus Name State: %s\n" + "%sResult: %s\n" + "%sName: %s\n", + prefix, busname_state_to_string(n->state), + prefix, busname_result_to_string(n->result), + prefix, n->name); +} + +static void busname_unwatch_fd(BusName *n) { + int r; + + assert(n); + + if (n->event_source) { + r = sd_event_source_set_enabled(n->event_source, SD_EVENT_OFF); + if (r < 0) + log_debug_unit(UNIT(n)->id, "Failed to disable event source."); + } +} + +static void busname_close_fd(BusName *n) { + assert(n); + + busname_unwatch_fd(n); + + if (n->starter_fd <= 0) + return; + + close_nointr_nofail(n->starter_fd); + n->starter_fd = -1; +} + +static int busname_watch_fd(BusName *n) { + int r; + + assert(n); + + if (n->starter_fd < 0) + return 0; + + if (n->event_source) + r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON); + else + r = sd_event_add_io(UNIT(n)->manager->event, &n->event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n); + if (r < 0) { + log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r)); + busname_unwatch_fd(n); + return r; + } + + return 0; +} + +static int busname_open_fd(BusName *n) { + assert(n); + + if (n->starter_fd >= 0) + return 0; + + n->starter_fd = bus_kernel_create_starter(UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user", n->name); + if (n->starter_fd < 0) { + log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd)); + return n->starter_fd; + } + + return 0; +} + +static void busname_set_state(BusName *n, BusNameState state) { + BusNameState old_state; + assert(n); + + old_state = n->state; + n->state = state; + + if (state != BUSNAME_LISTENING) + busname_unwatch_fd(n); + + if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_RUNNING)) + busname_close_fd(n); + + if (state != old_state) + log_debug_unit(UNIT(n)->id, "%s changed %s -> %s", + UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state)); + + unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true); +} + +static int busname_coldplug(Unit *u) { + BusName *n = BUSNAME(u); + int r; + + assert(n); + assert(n->state == BUSNAME_DEAD); + + if (n->deserialized_state == n->state) + return 0; + + if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_RUNNING)) { + r = busname_open_fd(n); + if (r < 0) + return r; + } + + if (n->deserialized_state == BUSNAME_LISTENING) { + r = busname_watch_fd(n); + if (r < 0) + return r; + } + + busname_set_state(n, n->deserialized_state); + return 0; +} + +static void busname_enter_dead(BusName *n, BusNameResult f) { + assert(n); + + if (f != BUSNAME_SUCCESS) + n->result = f; + + busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD); +} + +static void busname_enter_listening(BusName *n) { + int r; + + assert(n); + + r = busname_open_fd(n); + if (r < 0) { + log_warning_unit(UNIT(n)->id, "%s failed to listen on bus names: %s", UNIT(n)->id, strerror(-r)); + goto fail; + } + + r = busname_watch_fd(n); + if (r < 0) { + log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r)); + goto fail; + } + + busname_set_state(n, BUSNAME_LISTENING); + return; + +fail: + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); +} + +static void busname_enter_running(BusName *n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + bool pending = false; + Unit *other; + Iterator i; + int r; + + assert(n); + + /* We don't take conenctions anymore if we are supposed to + * shut down anyway */ + + if (unit_stop_pending(UNIT(n))) { + log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id); + + /* Flush all queued activation reqeuest by closing and reopening the connection */ + bus_kernel_drop_one(n->starter_fd); + + busname_enter_listening(n); + return; + } + + /* If there's already a start pending don't bother to do + * anything */ + SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i) + if (unit_active_or_pending(other)) { + pending = true; + break; + } + + if (!pending) { + r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + } + + busname_set_state(n, BUSNAME_RUNNING); + return; + +fail: + log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r)); + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); +} + +static int busname_start(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + if (UNIT_ISSET(n->service)) { + Service *service; + + service = SERVICE(UNIT_DEREF(n->service)); + + if (UNIT(service)->load_state != UNIT_LOADED) { + log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id); + return -ENOENT; + } + } + + assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED)); + + n->result = BUSNAME_SUCCESS; + busname_enter_listening(n); + + return 0; +} + +static int busname_stop(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + assert(n->state == BUSNAME_LISTENING || n->state == BUSNAME_RUNNING); + + busname_enter_dead(n, BUSNAME_SUCCESS); + return 0; +} + +static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { + BusName *n = BUSNAME(u); + + assert(n); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", busname_state_to_string(n->state)); + unit_serialize_item(u, f, "result", busname_result_to_string(n->result)); + + if (n->starter_fd >= 0) { + int copy; + + copy = fdset_put_dup(fds, n->starter_fd); + if (copy < 0) + return copy; + + unit_serialize_item_format(u, f, "starter-fd", "%i", copy); + } + + return 0; +} + +static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + BusName *n = BUSNAME(u); + + assert(n); + assert(key); + assert(value); + + if (streq(key, "state")) { + BusNameState state; + + state = busname_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + n->deserialized_state = state; + + } else if (streq(key, "result")) { + BusNameResult f; + + f = busname_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != BUSNAME_SUCCESS) + n->result = f; + + } else if (streq(key, "starter-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse starter fd value %s", value); + else { + if (n->starter_fd >= 0) + close_nointr_nofail(n->starter_fd); + n->starter_fd = fdset_remove(fds, fd); + } + } else + log_debug_unit(u->id, "Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState busname_active_state(Unit *u) { + assert(u); + + return state_translation_table[BUSNAME(u)->state]; +} + +_pure_ static const char *busname_sub_state_to_string(Unit *u) { + assert(u); + + return busname_state_to_string(BUSNAME(u)->state); +} + +static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + BusName *n = userdata; + + assert(n); + assert(fd >= 0); + + if (n->state != BUSNAME_LISTENING) + return 0; + + log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id); + + if (revents != EPOLLIN) { + log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.", + UNIT(n)->id, revents); + goto fail; + } + + busname_enter_running(n); + return 0; +fail: + + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); + return 0; +} + +static void busname_reset_failed(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + if (n->state == BUSNAME_FAILED) + busname_set_state(n, BUSNAME_DEAD); + + n->result = BUSNAME_SUCCESS; +} + +static void busname_trigger_notify(Unit *u, Unit *other) { + BusName *n = BUSNAME(u); + Service *s; + + assert(n); + assert(other); + + if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING)) + return; + + if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) + return; + + s = SERVICE(other); + + if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT) + busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT); + else if (IN_SET(s->state, + SERVICE_DEAD, SERVICE_FAILED, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, + SERVICE_AUTO_RESTART)) + busname_enter_listening(n); +} + +static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = "dead", + [BUSNAME_LISTENING] = "listening", + [BUSNAME_RUNNING] = "running", + [BUSNAME_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + +static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { + [BUSNAME_SUCCESS] = "success", + [BUSNAME_FAILURE_RESOURCES] = "resources", +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult); + +const UnitVTable busname_vtable = { + .object_size = sizeof(BusName), + + .sections = + "Unit\0" + "BusName\0" + "Install\0", + .private_section = "BusName", + + .init = busname_init, + .done = busname_done, + .load = busname_load, + + .coldplug = busname_coldplug, + + .dump = busname_dump, + + .start = busname_start, + .stop = busname_stop, + + .serialize = busname_serialize, + .deserialize_item = busname_deserialize_item, + + .active_state = busname_active_state, + .sub_state_to_string = busname_sub_state_to_string, + + .trigger_notify = busname_trigger_notify, + + .reset_failed = busname_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.BusName", + .bus_vtable = bus_busname_vtable, + + .status_message_formats = { + .finished_start_job = { + [JOB_DONE] = "Listening on %s.", + [JOB_FAILED] = "Failed to listen on %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_TIMEOUT] = "Timed out starting %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Closed %s.", + [JOB_FAILED] = "Failed stopping %s.", + [JOB_TIMEOUT] = "Timed out stopping %s.", + }, + }, +}; diff --git a/src/core/busname.h b/src/core/busname.h new file mode 100644 index 0000000..6debd48 --- /dev/null +++ b/src/core/busname.h @@ -0,0 +1,65 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct BusName BusName; + +#include "unit.h" + +typedef enum BusNameState { + BUSNAME_DEAD, + BUSNAME_LISTENING, + BUSNAME_RUNNING, + BUSNAME_FAILED, + _BUSNAME_STATE_MAX, + _BUSNAME_STATE_INVALID = -1 +} BusNameState; + +typedef enum BusNameResult { + BUSNAME_SUCCESS, + BUSNAME_FAILURE_RESOURCES, + BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT, + _BUSNAME_RESULT_MAX, + _BUSNAME_RESULT_INVALID = -1 +} BusNameResult; + +struct BusName { + Unit meta; + + char *name; + int starter_fd; + + UnitRef service; + + BusNameState state, deserialized_state; + BusNameResult result; + + sd_event_source *event_source; +}; + +extern const UnitVTable busname_vtable; + +const char* busname_state_to_string(BusNameState i) _const_; +BusNameState busname_state_from_string(const char *s) _pure_; + +const char* busname_result_to_string(BusNameResult i) _const_; +BusNameResult busname_result_from_string(const char *s) _pure_; diff --git a/src/core/cgroup.c b/src/core/cgroup.c new file mode 100644 index 0000000..1327486 --- /dev/null +++ b/src/core/cgroup.c @@ -0,0 +1,968 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "path-util.h" +#include "special.h" +#include "cgroup-util.h" +#include "cgroup.h" + +void cgroup_context_init(CGroupContext *c) { + assert(c); + + /* Initialize everything to the kernel defaults, assuming the + * structure is preinitialized to 0 */ + + c->cpu_shares = 1024; + c->memory_limit = (uint64_t) -1; + c->blockio_weight = 1000; +} + +void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { + assert(c); + assert(a); + + LIST_REMOVE(device_allow, c->device_allow, a); + free(a->path); + free(a); +} + +void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) { + assert(c); + assert(w); + + LIST_REMOVE(device_weights, c->blockio_device_weights, w); + free(w->path); + free(w); +} + +void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) { + assert(c); + assert(b); + + LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b); + free(b->path); + free(b); +} + +void cgroup_context_done(CGroupContext *c) { + assert(c); + + while (c->blockio_device_weights) + cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); + + while (c->blockio_device_bandwidths) + cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths); + + while (c->device_allow) + cgroup_context_free_device_allow(c, c->device_allow); +} + +void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + CGroupBlockIODeviceBandwidth *b; + CGroupBlockIODeviceWeight *w; + CGroupDeviceAllow *a; + + assert(c); + assert(f); + + prefix = strempty(prefix); + + fprintf(f, + "%sCPUAccounting=%s\n" + "%sBlockIOAccounting=%s\n" + "%sMemoryAccounting=%s\n" + "%sCPUShares=%lu\n" + "%sBlockIOWeight=%lu\n" + "%sMemoryLimit=%" PRIu64 "\n" + "%sDevicePolicy=%s\n", + prefix, yes_no(c->cpu_accounting), + prefix, yes_no(c->blockio_accounting), + prefix, yes_no(c->memory_accounting), + prefix, c->cpu_shares, + prefix, c->blockio_weight, + prefix, c->memory_limit, + prefix, cgroup_device_policy_to_string(c->device_policy)); + + LIST_FOREACH(device_allow, a, c->device_allow) + fprintf(f, + "%sDeviceAllow=%s %s%s%s\n", + prefix, + a->path, + a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); + + LIST_FOREACH(device_weights, w, c->blockio_device_weights) + fprintf(f, + "%sBlockIODeviceWeight=%s %lu", + prefix, + w->path, + w->weight); + + LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + char buf[FORMAT_BYTES_MAX]; + + fprintf(f, + "%s%s=%s %s\n", + prefix, + b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth", + b->path, + format_bytes(buf, sizeof(buf), b->bandwidth)); + } +} + +static int lookup_blkio_device(const char *p, dev_t *dev) { + struct stat st; + int r; + + assert(p); + assert(dev); + + r = stat(p, &st); + if (r < 0) { + log_warning("Couldn't stat device %s: %m", p); + return -errno; + } + + if (S_ISBLK(st.st_mode)) + *dev = st.st_rdev; + else if (major(st.st_dev) != 0) { + /* If this is not a device node then find the block + * device this file is stored on */ + *dev = st.st_dev; + + /* If this is a partition, try to get the originating + * block device */ + block_get_whole_disk(*dev, dev); + } else { + log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p); + return -ENODEV; + } + + return 0; +} + +static int whitelist_device(const char *path, const char *node, const char *acc) { + char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4]; + struct stat st; + int r; + + assert(path); + assert(acc); + + if (stat(node, &st) < 0) { + log_warning("Couldn't stat device %s", node); + return -errno; + } + + if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { + log_warning("%s is not a device.", node); + return -ENODEV; + } + + sprintf(buf, + "%c %u:%u %s", + S_ISCHR(st.st_mode) ? 'c' : 'b', + major(st.st_rdev), minor(st.st_rdev), + acc); + + r = cg_set_attribute("devices", path, "devices.allow", buf); + if (r < 0) + log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r)); + + return r; +} + +static int whitelist_major(const char *path, const char *name, char type, const char *acc) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + bool good = false; + int r; + + assert(path); + assert(acc); + assert(type == 'b' || type == 'c'); + + f = fopen("/proc/devices", "re"); + if (!f) { + log_warning("Cannot open /proc/devices to resolve %s (%c): %m", name, type); + return -errno; + } + + FOREACH_LINE(line, f, goto fail) { + char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w; + unsigned maj; + + truncate_nl(line); + + if (type == 'c' && streq(line, "Character devices:")) { + good = true; + continue; + } + + if (type == 'b' && streq(line, "Block devices:")) { + good = true; + continue; + } + + if (isempty(line)) { + good = false; + continue; + } + + if (!good) + continue; + + p = strstrip(line); + + w = strpbrk(p, WHITESPACE); + if (!w) + continue; + *w = 0; + + r = safe_atou(p, &maj); + if (r < 0) + continue; + if (maj <= 0) + continue; + + w++; + w += strspn(w, WHITESPACE); + if (!streq(w, name)) + continue; + + sprintf(buf, + "%c %u:* %s", + type, + maj, + acc); + + r = cg_set_attribute("devices", path, "devices.allow", buf); + if (r < 0) + log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r)); + } + + return 0; + +fail: + log_warning("Failed to read /proc/devices: %m"); + return -errno; +} + +void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) { + bool is_root; + int r; + + assert(c); + assert(path); + + if (mask == 0) + return; + + /* Some cgroup attributes are not support on the root cgroup, + * hence silently ignore */ + is_root = isempty(path) || path_equal(path, "/"); + + if ((mask & CGROUP_CPU) && !is_root) { + char buf[DECIMAL_STR_MAX(unsigned long) + 1]; + + sprintf(buf, "%lu\n", c->cpu_shares); + r = cg_set_attribute("cpu", path, "cpu.shares", buf); + if (r < 0) + log_warning("Failed to set cpu.shares on %s: %s", path, strerror(-r)); + } + + if (mask & CGROUP_BLKIO) { + char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1, + DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1, + DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; + CGroupBlockIODeviceWeight *w; + CGroupBlockIODeviceBandwidth *b; + + if (!is_root) { + sprintf(buf, "%lu\n", c->blockio_weight); + r = cg_set_attribute("blkio", path, "blkio.weight", buf); + if (r < 0) + log_warning("Failed to set blkio.weight on %s: %s", path, strerror(-r)); + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->blockio_device_weights) { + dev_t dev; + + r = lookup_blkio_device(w->path, &dev); + if (r < 0) + continue; + + sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight); + r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); + if (r < 0) + log_error("Failed to set blkio.weight_device on %s: %s", path, strerror(-r)); + } + } + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + const char *a; + dev_t dev; + + r = lookup_blkio_device(b->path, &dev); + if (r < 0) + continue; + + a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device"; + + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth); + r = cg_set_attribute("blkio", path, a, buf); + if (r < 0) + log_error("Failed to set %s on %s: %s", a, path, strerror(-r)); + } + } + + if (mask & CGROUP_MEMORY) { + if (c->memory_limit != (uint64_t) -1) { + char buf[DECIMAL_STR_MAX(uint64_t) + 1]; + + sprintf(buf, "%" PRIu64 "\n", c->memory_limit); + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); + } else + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1"); + + if (r < 0) + log_error("Failed to set memory.limit_in_bytes on %s: %s", path, strerror(-r)); + } + + if ((mask & CGROUP_DEVICE) && !is_root) { + CGroupDeviceAllow *a; + + if (c->device_allow || c->device_policy != CGROUP_AUTO) + r = cg_set_attribute("devices", path, "devices.deny", "a"); + else + r = cg_set_attribute("devices", path, "devices.allow", "a"); + if (r < 0) + log_warning("Failed to reset devices.list on %s: %s", path, strerror(-r)); + + if (c->device_policy == CGROUP_CLOSED || + (c->device_policy == CGROUP_AUTO && c->device_allow)) { + static const char auto_devices[] = + "/dev/null\0" "rw\0" + "/dev/zero\0" "rw\0" + "/dev/full\0" "rw\0" + "/dev/random\0" "rw\0" + "/dev/urandom\0" "rw\0"; + + const char *x, *y; + + NULSTR_FOREACH_PAIR(x, y, auto_devices) + whitelist_device(path, x, y); + } + + LIST_FOREACH(device_allow, a, c->device_allow) { + char acc[4]; + unsigned k = 0; + + if (a->r) + acc[k++] = 'r'; + if (a->w) + acc[k++] = 'w'; + if (a->m) + acc[k++] = 'm'; + + if (k == 0) + continue; + + acc[k++] = 0; + + if (startswith(a->path, "/dev/")) + whitelist_device(path, a->path, acc); + else if (startswith(a->path, "block-")) + whitelist_major(path, a->path + 6, 'b', acc); + else if (startswith(a->path, "char-")) + whitelist_major(path, a->path + 5, 'c', acc); + else + log_debug("Ignoring device %s while writing cgroup attribute.", a->path); + } + } +} + +CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) { + CGroupControllerMask mask = 0; + + /* Figure out which controllers we need */ + + if (c->cpu_accounting || c->cpu_shares != 1024) + mask |= CGROUP_CPUACCT | CGROUP_CPU; + + if (c->blockio_accounting || + c->blockio_weight != 1000 || + c->blockio_device_weights || + c->blockio_device_bandwidths) + mask |= CGROUP_BLKIO; + + if (c->memory_accounting || + c->memory_limit != (uint64_t) -1) + mask |= CGROUP_MEMORY; + + if (c->device_allow || c->device_policy != CGROUP_AUTO) + mask |= CGROUP_DEVICE; + + return mask; +} + +CGroupControllerMask unit_get_cgroup_mask(Unit *u) { + CGroupContext *c; + + c = unit_get_cgroup_context(u); + if (!c) + return 0; + + return cgroup_context_get_mask(c); +} + +CGroupControllerMask unit_get_members_mask(Unit *u) { + assert(u); + + if (u->cgroup_members_mask_valid) + return u->cgroup_members_mask; + + u->cgroup_members_mask = 0; + + if (u->type == UNIT_SLICE) { + Unit *member; + Iterator i; + + SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) { + + if (member == u) + continue; + + if (UNIT_DEREF(member->slice) != u) + continue; + + u->cgroup_members_mask |= + unit_get_cgroup_mask(member) | + unit_get_members_mask(member); + } + } + + u->cgroup_members_mask_valid = true; + return u->cgroup_members_mask; +} + +CGroupControllerMask unit_get_siblings_mask(Unit *u) { + CGroupControllerMask m; + + assert(u); + + if (UNIT_ISSET(u->slice)) + m = unit_get_members_mask(UNIT_DEREF(u->slice)); + else + m = unit_get_cgroup_mask(u) | unit_get_members_mask(u); + + /* Sibling propagation is only relevant for weight-based + * controllers, so let's mask out everything else */ + return m & (CGROUP_CPU|CGROUP_BLKIO|CGROUP_CPUACCT); +} + +CGroupControllerMask unit_get_target_mask(Unit *u) { + CGroupControllerMask mask; + + mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u); + mask &= u->manager->cgroup_supported; + + return mask; +} + +/* Recurse from a unit up through its containing slices, propagating + * mask bits upward. A unit is also member of itself. */ +void unit_update_cgroup_members_masks(Unit *u) { + CGroupControllerMask m; + bool more; + + assert(u); + + /* Calculate subtree mask */ + m = unit_get_cgroup_mask(u) | unit_get_members_mask(u); + + /* See if anything changed from the previous invocation. If + * not, we're done. */ + if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask) + return; + + more = + u->cgroup_subtree_mask_valid && + ((m & ~u->cgroup_subtree_mask) != 0) && + ((~m & u->cgroup_subtree_mask) == 0); + + u->cgroup_subtree_mask = m; + u->cgroup_subtree_mask_valid = true; + + if (UNIT_ISSET(u->slice)) { + Unit *s = UNIT_DEREF(u->slice); + + if (more) + /* There's more set now than before. We + * propagate the new mask to the parent's mask + * (not caring if it actually was valid or + * not). */ + + s->cgroup_members_mask |= m; + + else + /* There's less set now than before (or we + * don't know), we need to recalculate + * everything, so let's invalidate the + * parent's members mask */ + + s->cgroup_members_mask_valid = false; + + /* And now make sure that this change also hits our + * grandparents */ + unit_update_cgroup_members_masks(s); + } +} + +static const char *migrate_callback(CGroupControllerMask mask, void *userdata) { + Unit *u = userdata; + + assert(mask != 0); + assert(u); + + while (u) { + if (u->cgroup_path && + u->cgroup_realized && + (u->cgroup_realized_mask & mask) == mask) + return u->cgroup_path; + + u = UNIT_DEREF(u->slice); + } + + return NULL; +} + +static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) { + _cleanup_free_ char *path = NULL; + int r; + + assert(u); + + path = unit_default_cgroup_path(u); + if (!path) + return log_oom(); + + r = hashmap_put(u->manager->cgroup_unit, path, u); + if (r < 0) { + log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r)); + return r; + } + if (r > 0) { + u->cgroup_path = path; + path = NULL; + } + + /* First, create our own group */ + r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path); + if (r < 0) { + log_error("Failed to create cgroup %s: %s", u->cgroup_path, strerror(-r)); + return r; + } + + /* Keep track that this is now realized */ + u->cgroup_realized = true; + u->cgroup_realized_mask = mask; + + /* Then, possibly move things over */ + r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u); + if (r < 0) + log_warning("Failed to migrate cgroup from to %s: %s", u->cgroup_path, strerror(-r)); + + return 0; +} + +static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) { + assert(u); + + return u->cgroup_realized && u->cgroup_realized_mask == mask; +} + +/* Check if necessary controllers and attributes for a unit are in place. + * + * If so, do nothing. + * If not, create paths, move processes over, and set attributes. + * + * Returns 0 on success and < 0 on failure. */ +static int unit_realize_cgroup_now(Unit *u) { + CGroupControllerMask mask; + int r; + + assert(u); + + if (u->in_cgroup_queue) { + LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u); + u->in_cgroup_queue = false; + } + + mask = unit_get_target_mask(u); + + if (unit_has_mask_realized(u, mask)) + return 0; + + /* First, realize parents */ + if (UNIT_ISSET(u->slice)) { + r = unit_realize_cgroup_now(UNIT_DEREF(u->slice)); + if (r < 0) + return r; + } + + /* And then do the real work */ + r = unit_create_cgroups(u, mask); + if (r < 0) + return r; + + /* Finally, apply the necessary attributes. */ + cgroup_context_apply(unit_get_cgroup_context(u), mask, u->cgroup_path); + + return 0; +} + +static void unit_add_to_cgroup_queue(Unit *u) { + + if (u->in_cgroup_queue) + return; + + LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u); + u->in_cgroup_queue = true; +} + +unsigned manager_dispatch_cgroup_queue(Manager *m) { + Unit *i; + unsigned n = 0; + int r; + + while ((i = m->cgroup_queue)) { + assert(i->in_cgroup_queue); + + r = unit_realize_cgroup_now(i); + if (r < 0) + log_warning("Failed to realize cgroups for queued unit %s: %s", i->id, strerror(-r)); + + n++; + } + + return n; +} + +static void unit_queue_siblings(Unit *u) { + Unit *slice; + + /* This adds the siblings of the specified unit and the + * siblings of all parent units to the cgroup queue. (But + * neither the specified unit itself nor the parents.) */ + + while ((slice = UNIT_DEREF(u->slice))) { + Iterator i; + Unit *m; + + SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) { + if (m == u) + continue; + + /* Skip units that have a dependency on the slice + * but aren't actually in it. */ + if (UNIT_DEREF(m->slice) != slice) + continue; + + /* No point in doing cgroup application for units + * without active processes. */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m))) + continue; + + /* If the unit doesn't need any new controllers + * and has current ones realized, it doesn't need + * any changes. */ + if (unit_has_mask_realized(m, unit_get_target_mask(m))) + continue; + + unit_add_to_cgroup_queue(m); + } + + u = slice; + } +} + +int unit_realize_cgroup(Unit *u) { + CGroupContext *c; + + assert(u); + + c = unit_get_cgroup_context(u); + if (!c) + return 0; + + /* So, here's the deal: when realizing the cgroups for this + * unit, we need to first create all parents, but there's more + * actually: for the weight-based controllers we also need to + * make sure that all our siblings (i.e. units that are in the + * same slice as we are) have cgroups, too. Otherwise, things + * would become very uneven as each of their processes would + * get as much resources as all our group together. This call + * will synchronously create the parent cgroups, but will + * defer work on the siblings to the next event loop + * iteration. */ + + /* Add all sibling slices to the cgroup queue. */ + unit_queue_siblings(u); + + /* And realize this one now (and apply the values) */ + return unit_realize_cgroup_now(u); +} + +void unit_destroy_cgroup(Unit *u) { + int r; + + assert(u); + + if (!u->cgroup_path) + return; + + r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE)); + if (r < 0) + log_debug("Failed to destroy cgroup %s: %s", u->cgroup_path, strerror(-r)); + + hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); + + free(u->cgroup_path); + u->cgroup_path = NULL; + u->cgroup_realized = false; + u->cgroup_realized_mask = 0; + +} + +pid_t unit_search_main_pid(Unit *u) { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid = 0, npid, mypid; + + assert(u); + + if (!u->cgroup_path) + return 0; + + if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f) < 0) + return 0; + + mypid = getpid(); + while (cg_read_pid(f, &npid) > 0) { + pid_t ppid; + + if (npid == pid) + continue; + + /* Ignore processes that aren't our kids */ + if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid) + continue; + + if (pid != 0) { + /* Dang, there's more than one daemonized PID + in this group, so we don't know what process + is the main process. */ + pid = 0; + break; + } + + pid = npid; + } + + return pid; +} + +int manager_setup_cgroup(Manager *m) { + _cleanup_free_ char *path = NULL; + char *e; + int r; + + assert(m); + + /* 0. Be nice to Ingo Molnar #628004 */ + if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) { + log_warning("No control group support available, not creating root group."); + return 0; + } + + /* 1. Determine hierarchy */ + free(m->cgroup_root); + m->cgroup_root = NULL; + + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root); + if (r < 0) { + log_error("Cannot determine cgroup we are running in: %s", strerror(-r)); + return r; + } + + /* LEGACY: Already in /system.slice? If so, let's cut this + * off. This is to support live upgrades from older systemd + * versions where PID 1 was moved there. */ + if (m->running_as == SYSTEMD_SYSTEM) { + e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE); + if (!e) + e = endswith(m->cgroup_root, "/system"); + if (e) + *e = 0; + } + + /* And make sure to store away the root value without trailing + * slash, even for the root dir, so that we can easily prepend + * it everywhere. */ + if (streq(m->cgroup_root, "/")) + m->cgroup_root[0] = 0; + + /* 2. Show data */ + r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path); + if (r < 0) { + log_error("Cannot find cgroup mount point: %s", strerror(-r)); + return r; + } + + log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path); + + /* 3. Install agent */ + if (m->running_as == SYSTEMD_SYSTEM) { + r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH); + if (r < 0) + log_warning("Failed to install release agent, ignoring: %s", strerror(-r)); + else if (r > 0) + log_debug("Installed release agent."); + else + log_debug("Release agent already installed."); + } + + /* 4. Make sure we are in the root cgroup */ + r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0); + if (r < 0) { + log_error("Failed to create root cgroup hierarchy: %s", strerror(-r)); + return r; + } + + /* 5. And pin it, so that it cannot be unmounted */ + if (m->pin_cgroupfs_fd >= 0) + close_nointr_nofail(m->pin_cgroupfs_fd); + + m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK); + if (r < 0) { + log_error("Failed to open pin file: %m"); + return -errno; + } + + /* 6. Figure out which controllers are supported */ + m->cgroup_supported = cg_mask_supported(); + + /* 7. Always enable hierarchial support if it exists... */ + cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); + + return 0; +} + +void manager_shutdown_cgroup(Manager *m, bool delete) { + assert(m); + + /* We can't really delete the group, since we are in it. But + * let's trim it. */ + if (delete && m->cgroup_root) + cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false); + + if (m->pin_cgroupfs_fd >= 0) { + close_nointr_nofail(m->pin_cgroupfs_fd); + m->pin_cgroupfs_fd = -1; + } + + free(m->cgroup_root); + m->cgroup_root = NULL; +} + +Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) { + char *p; + Unit *u; + + assert(m); + assert(cgroup); + + u = hashmap_get(m->cgroup_unit, cgroup); + if (u) + return u; + + p = strdupa(cgroup); + for (;;) { + char *e; + + e = strrchr(p, '/'); + if (e == p || !e) + return NULL; + + *e = 0; + + u = hashmap_get(m->cgroup_unit, p); + if (u) + return u; + } +} + +Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(m); + + if (pid <= 1) + return NULL; + + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup); + if (r < 0) + return NULL; + + return manager_get_unit_by_cgroup(m, cgroup); +} + +int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { + Unit *u; + int r; + + assert(m); + assert(cgroup); + + u = manager_get_unit_by_cgroup(m, cgroup); + if (u) { + r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); + if (r > 0) { + if (UNIT_VTABLE(u)->notify_cgroup_empty) + UNIT_VTABLE(u)->notify_cgroup_empty(u); + + unit_add_to_gc_queue(u); + } + } + + return 0; +} + +static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { + [CGROUP_AUTO] = "auto", + [CGROUP_CLOSED] = "closed", + [CGROUP_STRICT] = "strict", +}; + +DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy); diff --git a/src/core/cgroup.h b/src/core/cgroup.h new file mode 100644 index 0000000..be717ad --- /dev/null +++ b/src/core/cgroup.h @@ -0,0 +1,122 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "list.h" + +typedef struct CGroupContext CGroupContext; +typedef struct CGroupDeviceAllow CGroupDeviceAllow; +typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight; +typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth; + +typedef enum CGroupDevicePolicy { + + /* When devices listed, will allow those, plus built-in ones, + if none are listed will allow everything. */ + CGROUP_AUTO, + + /* Everything forbidden, except built-in ones and listed ones. */ + CGROUP_CLOSED, + + /* Everythings forbidden, except for the listed devices */ + CGROUP_STRICT, + + _CGROUP_DEVICE_POLICY_MAX, + _CGROUP_DEVICE_POLICY_INVALID = -1 +} CGroupDevicePolicy; + +struct CGroupDeviceAllow { + LIST_FIELDS(CGroupDeviceAllow, device_allow); + char *path; + bool r:1; + bool w:1; + bool m:1; +}; + +struct CGroupBlockIODeviceWeight { + LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights); + char *path; + unsigned long weight; +}; + +struct CGroupBlockIODeviceBandwidth { + LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths); + char *path; + uint64_t bandwidth; + bool read; +}; + +struct CGroupContext { + bool cpu_accounting; + bool blockio_accounting; + bool memory_accounting; + + unsigned long cpu_shares; + + unsigned long blockio_weight; + LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights); + LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths); + + uint64_t memory_limit; + + CGroupDevicePolicy device_policy; + LIST_HEAD(CGroupDeviceAllow, device_allow); +}; + +#include "unit.h" +#include "manager.h" +#include "cgroup-util.h" + +void cgroup_context_init(CGroupContext *c); +void cgroup_context_done(CGroupContext *c); +void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix); +void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path); + +CGroupControllerMask cgroup_context_get_mask(CGroupContext *c); + +void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a); +void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w); +void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b); + +CGroupControllerMask unit_get_cgroup_mask(Unit *u); +CGroupControllerMask unit_get_siblings_mask(Unit *u); +CGroupControllerMask unit_get_members_mask(Unit *u); +CGroupControllerMask unit_get_target_mask(Unit *u); + +void unit_update_cgroup_members_masks(Unit *u); +int unit_realize_cgroup(Unit *u); +void unit_destroy_cgroup(Unit *u); + +int manager_setup_cgroup(Manager *m); +void manager_shutdown_cgroup(Manager *m, bool delete); + +unsigned manager_dispatch_cgroup_queue(Manager *m); + +Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup); +Unit* manager_get_unit_by_pid(Manager *m, pid_t pid); + +pid_t unit_search_main_pid(Unit *u); + +int manager_notify_cgroup_empty(Manager *m, const char *group); + +const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_; +CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_; diff --git a/src/core/condition.c b/src/core/condition.c new file mode 100644 index 0000000..1448fa1 --- /dev/null +++ b/src/core/condition.c @@ -0,0 +1,215 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "util.h" +#include "condition.h" +#include "virt.h" +#include "path-util.h" +#include "fileio.h" +#include "unit.h" +#include "smack-util.h" +#include "apparmor-util.h" +#include "ima-util.h" +#include "selinux-util.h" + +static bool condition_test_security(Condition *c) { + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_SECURITY); + + if (streq(c->parameter, "selinux")) + return use_selinux() == !c->negate; + if (streq(c->parameter, "apparmor")) + return use_apparmor() == !c->negate; + if (streq(c->parameter, "ima")) + return use_ima() == !c->negate; + if (streq(c->parameter, "smack")) + return use_smack() == !c->negate; + return c->negate; +} + +static bool condition_test_capability(Condition *c) { + cap_value_t value; + FILE *f; + char line[LINE_MAX]; + unsigned long long capabilities = (unsigned long long) -1; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_CAPABILITY); + + /* If it's an invalid capability, we don't have it */ + + if (cap_from_name(c->parameter, &value) < 0) + return c->negate; + + /* If it's a valid capability we default to assume + * that we have it */ + + f = fopen("/proc/self/status", "re"); + if (!f) + return !c->negate; + + while (fgets(line, sizeof(line), f)) { + truncate_nl(line); + + if (startswith(line, "CapBnd:")) { + (void) sscanf(line+7, "%llx", &capabilities); + break; + } + } + + fclose(f); + + return !!(capabilities & (1ULL << value)) == !c->negate; +} + +static bool condition_test(Condition *c) { + assert(c); + + switch(c->type) { + + case CONDITION_PATH_EXISTS: + return (access(c->parameter, F_OK) >= 0) == !c->negate; + + case CONDITION_PATH_EXISTS_GLOB: + return (glob_exists(c->parameter) > 0) == !c->negate; + + case CONDITION_PATH_IS_DIRECTORY: { + struct stat st; + + if (stat(c->parameter, &st) < 0) + return c->negate; + return S_ISDIR(st.st_mode) == !c->negate; + } + + case CONDITION_PATH_IS_SYMBOLIC_LINK: { + struct stat st; + + if (lstat(c->parameter, &st) < 0) + return c->negate; + return S_ISLNK(st.st_mode) == !c->negate; + } + + case CONDITION_PATH_IS_MOUNT_POINT: + return (path_is_mount_point(c->parameter, true) > 0) == !c->negate; + + case CONDITION_PATH_IS_READ_WRITE: + return (path_is_read_only_fs(c->parameter) > 0) == c->negate; + + case CONDITION_DIRECTORY_NOT_EMPTY: { + int k; + + k = dir_is_empty(c->parameter); + return !(k == -ENOENT || k > 0) == !c->negate; + } + + case CONDITION_FILE_NOT_EMPTY: { + struct stat st; + + if (stat(c->parameter, &st) < 0) + return c->negate; + + return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate; + } + + case CONDITION_FILE_IS_EXECUTABLE: { + struct stat st; + + if (stat(c->parameter, &st) < 0) + return c->negate; + + return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate; + } + + case CONDITION_KERNEL_COMMAND_LINE: + return condition_test_kernel_command_line(c); + + case CONDITION_VIRTUALIZATION: + return condition_test_virtualization(c); + + case CONDITION_SECURITY: + return condition_test_security(c); + + case CONDITION_CAPABILITY: + return condition_test_capability(c); + + case CONDITION_HOST: + return condition_test_host(c); + + case CONDITION_AC_POWER: + return condition_test_ac_power(c); + + case CONDITION_ARCHITECTURE: + return condition_test_architecture(c); + + case CONDITION_NULL: + return !c->negate; + + default: + assert_not_reached("Invalid condition type."); + } +} + +bool condition_test_list(const char *unit, Condition *first) { + Condition *c; + int triggered = -1; + + /* 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) { + bool b; + + b = condition_test(c); + if (unit) + log_debug_unit(unit, + "%s=%s%s%s %s for %s.", + condition_type_to_string(c->type), + c->trigger ? "|" : "", + c->negate ? "!" : "", + c->parameter, + b ? "succeeded" : "failed", + unit); + c->state = b ? 1 : -1; + + if (!c->trigger && !b) + return false; + + if (c->trigger && triggered <= 0) + triggered = b; + } + + return triggered != 0; +} diff --git a/src/core/condition.h b/src/core/condition.h new file mode 100644 index 0000000..6dd77bb --- /dev/null +++ b/src/core/condition.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "condition-util.h" + +bool condition_test_list(const char *unit, Condition *c); diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c new file mode 100644 index 0000000..b2a510a --- /dev/null +++ b/src/core/dbus-automount.c @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "automount.h" +#include "dbus-unit.h" +#include "dbus-automount.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult); + +const sd_bus_vtable bus_automount_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h new file mode 100644 index 0000000..1bec953 --- /dev/null +++ b/src/core/dbus-automount.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +extern const sd_bus_vtable bus_automount_vtable[]; diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c new file mode 100644 index 0000000..854491b --- /dev/null +++ b/src/core/dbus-busname.c @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "busname.h" +#include "dbus-unit.h" +#include "dbus-busname.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult); + +const sd_bus_vtable bus_busname_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Name", "s", NULL, offsetof(BusName, name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(BusName, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-busname.h b/src/core/dbus-busname.h new file mode 100644 index 0000000..b5eed37 --- /dev/null +++ b/src/core/dbus-busname.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_busname_vtable[]; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c new file mode 100644 index 0000000..775825b --- /dev/null +++ b/src/core/dbus-cgroup.c @@ -0,0 +1,530 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-util.h" +#include "path-util.h" +#include "cgroup-util.h" +#include "cgroup.h" +#include "dbus-cgroup.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); + +static int property_get_blockio_device_weight( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupBlockIODeviceWeight *w; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + LIST_FOREACH(device_weights, w, c->blockio_device_weights) { + r = sd_bus_message_append(reply, "(st)", w->path, w->weight); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_blockio_device_bandwidths( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupBlockIODeviceBandwidth *b; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + + if (streq(property, "BlockIOReadBandwidth") != b->read) + continue; + + r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_device_allow( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupDeviceAllow *a; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; + + LIST_FOREACH(device_allow, a, c->device_allow) { + unsigned k = 0; + char rwm[4]; + + if (a->r) + rwm[k++] = 'r'; + if (a->w) + rwm[k++] = 'w'; + if (a->m) + rwm[k++] = 'm'; + + rwm[k] = 0; + + r = sd_bus_message_append(reply, "(ss)", a->path, rwm); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), + SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0), + SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), + SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0), + SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0), + SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), + SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), + SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), + SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), + SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), + SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), + SD_BUS_VTABLE_END +}; + +int bus_cgroup_set_property( + Unit *u, + CGroupContext *c, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(u); + assert(c); + assert(name); + assert(message); + + if (streq(name, "CPUAccounting")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->cpu_accounting = b; + unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no"); + } + + return 1; + + } else if (streq(name, "CPUShares")) { + uint64_t u64; + unsigned long ul; + + r = sd_bus_message_read(message, "t", &u64); + if (r < 0) + return r; + + ul = (unsigned long) u64; + if (ul <= 0 || (uint64_t) ul != u64) + return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); + + if (mode != UNIT_CHECK) { + c->cpu_shares = ul; + unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul); + } + + return 1; + + } else if (streq(name, "BlockIOAccounting")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->blockio_accounting = b; + unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no"); + } + + return 1; + + } else if (streq(name, "BlockIOWeight")) { + uint64_t u64; + unsigned long ul; + + r = sd_bus_message_read(message, "t", &u64); + if (r < 0) + return r; + + ul = (unsigned long) u64; + if (ul < 10 || ul > 1000) + return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); + + if (mode != UNIT_CHECK) { + c->blockio_weight = ul; + unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul); + } + + return 1; + + } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) { + const char *path; + bool read = true; + unsigned n = 0; + uint64_t u64; + + if (streq(name, "BlockIOWriteBandwidth")) + read = false; + + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { + + if (mode != UNIT_CHECK) { + CGroupBlockIODeviceBandwidth *a = NULL, *b; + + LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + if (path_equal(path, b->path) && read == b->read) { + a = b; + break; + } + } + + if (!a) { + a = new0(CGroupBlockIODeviceBandwidth, 1); + if (!a) + return -ENOMEM; + + a->read = read; + a->path = strdup(path); + if (!a->path) { + free(a); + return -ENOMEM; + } + + LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); + } + + a->bandwidth = u64; + } + + n++; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + CGroupBlockIODeviceBandwidth *a, *next; + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + size_t size = 0; + + if (n == 0) { + LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths) + if (a->read == read) + cgroup_context_free_blockio_device_bandwidth(c, a); + } + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + if (read) { + fputs("BlockIOReadBandwidth=\n", f); + LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) + if (a->read) + fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); + } else { + fputs("BlockIOWriteBandwidth=\n", f); + LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) + if (!a->read) + fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); + } + + fflush(f); + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + + } else if (streq(name, "BlockIODeviceWeight")) { + const char *path; + uint64_t u64; + unsigned n = 0; + + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { + unsigned long ul = u64; + + if (ul < 10 || ul > 1000) + return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); + + if (mode != UNIT_CHECK) { + CGroupBlockIODeviceWeight *a = NULL, *b; + + LIST_FOREACH(device_weights, b, c->blockio_device_weights) { + if (path_equal(b->path, path)) { + a = b; + break; + } + } + + if (!a) { + a = new0(CGroupBlockIODeviceWeight, 1); + if (!a) + return -ENOMEM; + + a->path = strdup(path); + if (!a->path) { + free(a); + return -ENOMEM; + } + LIST_PREPEND(device_weights,c->blockio_device_weights, a); + } + + a->weight = ul; + } + + n++; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + CGroupBlockIODeviceWeight *a; + size_t size = 0; + + if (n == 0) { + while (c->blockio_device_weights) + cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); + } + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + fputs("BlockIODeviceWeight=\n", f); + LIST_FOREACH(device_weights, a, c->blockio_device_weights) + fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight); + + fflush(f); + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + + } else if (streq(name, "MemoryAccounting")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->memory_accounting = b; + unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no"); + } + + return 1; + + } else if (streq(name, "MemoryLimit")) { + uint64_t limit; + + r = sd_bus_message_read(message, "t", &limit); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->memory_limit = limit; + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit); + } + + return 1; + + } else if (streq(name, "DevicePolicy")) { + const char *policy; + CGroupDevicePolicy p; + + r = sd_bus_message_read(message, "s", &policy); + if (r < 0) + return r; + + p = cgroup_device_policy_from_string(policy); + if (p < 0) + return -EINVAL; + + if (mode != UNIT_CHECK) { + char *buf; + + c->device_policy = p; + + buf = strappenda("DevicePolicy=", policy); + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + + } else if (streq(name, "DeviceAllow")) { + const char *path, *rwm; + unsigned n = 0; + + r = sd_bus_message_enter_container(message, 'a', "(ss)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) { + + if ((!startswith(path, "/dev/") && + !startswith(path, "block-") && + !startswith(path, "char-")) || + strpbrk(path, WHITESPACE)) + return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node"); + + if (isempty(rwm)) + rwm = "rwm"; + + if (!in_charset(rwm, "rwm")) + return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags"); + + if (mode != UNIT_CHECK) { + CGroupDeviceAllow *a = NULL, *b; + + LIST_FOREACH(device_allow, b, c->device_allow) { + if (path_equal(b->path, path)) { + a = b; + break; + } + } + + if (!a) { + a = new0(CGroupDeviceAllow, 1); + if (!a) + return -ENOMEM; + + a->path = strdup(path); + if (!a->path) { + free(a); + return -ENOMEM; + } + + LIST_PREPEND(device_allow, c->device_allow, a); + } + + a->r = !!strchr(rwm, 'r'); + a->w = !!strchr(rwm, 'w'); + a->m = !!strchr(rwm, 'm'); + } + + n++; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + CGroupDeviceAllow *a; + size_t size = 0; + + if (n == 0) { + while (c->device_allow) + cgroup_context_free_device_allow(c, c->device_allow); + } + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + fputs("DeviceAllow=\n", f); + LIST_FOREACH(device_allow, a, c->device_allow) + fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); + + fflush(f); + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + } + + return 0; +} diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h new file mode 100644 index 0000000..c2a3910 --- /dev/null +++ b/src/core/dbus-cgroup.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "cgroup.h" + +extern const sd_bus_vtable bus_cgroup_vtable[]; + +int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); diff --git a/src/core/dbus-client-track.c b/src/core/dbus-client-track.c new file mode 100644 index 0000000..07dfea4 --- /dev/null +++ b/src/core/dbus-client-track.c @@ -0,0 +1,251 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-util.h" +#include "dbus-client-track.h" + +static unsigned long tracked_client_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { + const BusTrackedClient *x = a; + + return string_hash_func(x->name, hash_key) ^ trivial_hash_func(x->bus, hash_key); +} + +static int tracked_client_compare(const void *a, const void *b) { + const BusTrackedClient *x = a, *y = b; + int r; + + r = strcmp(x->name, y->name); + if (r != 0) + return r; + + if (x->bus < y->bus) + return -1; + if (x->bus > y->bus) + return 1; + + return 0; +} + +static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + BusTrackedClient *c = userdata; + const char *name, *old, *new; + int r; + + assert(bus); + assert(message); + + r = sd_bus_message_read(message, "sss", &name, &old, &new); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + bus_client_untrack(c->set, bus, name); + return 0; +} + +static char *build_match(const char *name) { + + return strjoin("type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg0='", name, "'", NULL); +} + +int bus_client_track(Set **s, sd_bus *bus, const char *name) { + BusTrackedClient *c, *found; + size_t l; + int r; + + assert(s); + assert(bus); + + r = set_ensure_allocated(s, tracked_client_hash, tracked_client_compare); + if (r < 0) + return r; + + name = strempty(name); + + l = strlen(name); + + c = alloca(offsetof(BusTrackedClient, name) + l + 1); + c->set = *s; + c->bus = bus; + strcpy(c->name, name); + + found = set_get(*s, c); + if (found) + return 0; + + c = memdup(c, offsetof(BusTrackedClient, name) + l + 1); + if (!c) + return -ENOMEM; + + r = set_put(*s, c); + if (r < 0) { + free(c); + return r; + } + + if (!isempty(name)) { + _cleanup_free_ char *match = NULL; + + match = build_match(name); + if (!match) { + set_remove(*s, c); + free(c); + return -ENOMEM; + } + + r = sd_bus_add_match(bus, match, on_name_owner_changed, c); + if (r < 0) { + set_remove(*s, c); + free(c); + return r; + } + } + + sd_bus_ref(c->bus); + return 1; +} + +static void bus_client_free_one(Set *s, BusTrackedClient *c) { + assert(s); + assert(c); + + if (!isempty(c->name)) { + _cleanup_free_ char *match = NULL; + + match = build_match(c->name); + if (match) + sd_bus_remove_match(c->bus, match, on_name_owner_changed, c); + } + + sd_bus_unref(c->bus); + set_remove(s, c); + free(c); +} + +int bus_client_untrack(Set *s, sd_bus *bus, const char *name) { + BusTrackedClient *c, *found; + size_t l; + + assert(bus); + assert(s); + assert(name); + + name = strempty(name); + + l = strlen(name); + + c = alloca(offsetof(BusTrackedClient, name) + l + 1); + c->bus = bus; + strcpy(c->name, name); + + found = set_get(s, c); + if (!found) + return 0; + + bus_client_free_one(s, found); + return 1; +} + +void bus_client_track_free(Set *s) { + BusTrackedClient *c; + + while ((c = set_first(s))) + bus_client_free_one(s, c); + + set_free(s); +} + +int bus_client_untrack_bus(Set *s, sd_bus *bus) { + BusTrackedClient *c; + Iterator i; + int r = 0; + + SET_FOREACH(c, s, i) + if (c->bus == bus) { + bus_client_free_one(s, c); + r++; + } + + return r; +} + +void bus_client_track_serialize(Manager *m, FILE *f, Set *s) { + BusTrackedClient *c; + Iterator i; + + assert(m); + assert(f); + + SET_FOREACH(c, s, i) { + if (c->bus == m->api_bus) + fprintf(f, "subscribed=%s\n", isempty(c->name) ? "*" : c->name); + else + fprintf(f, "subscribed=%p %s\n", c->bus, isempty(c->name) ? "*" : c->name); + } +} + +int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line) { + const char *e, *q, *name; + sd_bus *bus; + void *p; + int r; + + e = startswith(line, "subscribed="); + if (!e) + return 0; + + q = strpbrk(e, WHITESPACE); + if (!q) { + if (m->api_bus) { + bus = m->api_bus; + name = e; + goto finish; + } + + return 1; + } + + if (sscanf(e, "%p", &p) != 1) { + log_debug("Failed to parse subscription pointer."); + return -EINVAL; + } + + bus = set_get(m->private_buses, p); + if (!bus) + return 1; + + name = q + strspn(q, WHITESPACE); + +finish: + r = bus_client_track(s, bus, streq(name, "*") ? NULL : name); + if (r < 0) { + log_debug("Failed to deserialize client subscription: %s", strerror(-r)); + return r; + } + + return 1; +} diff --git a/src/core/dbus-client-track.h b/src/core/dbus-client-track.h new file mode 100644 index 0000000..0167647 --- /dev/null +++ b/src/core/dbus-client-track.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "set.h" +#include "manager.h" + +typedef struct BusTrackedClient { + Set *set; + sd_bus *bus; + char name[0]; +} BusTrackedClient; + +int bus_client_track(Set **s, sd_bus *bus, const char *name); + +int bus_client_untrack(Set *s, sd_bus *bus, const char *name); +int bus_client_untrack_bus(Set *s, sd_bus *bus); + +void bus_client_track_free(Set *s); + +void bus_client_track_serialize(Manager *m, FILE *f, Set *s); +int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line); diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c new file mode 100644 index 0000000..f556536 --- /dev/null +++ b/src/core/dbus-device.c @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "device.h" +#include "dbus-unit.h" +#include "dbus-device.h" + +const sd_bus_vtable bus_device_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("SysFSPath", "s", NULL, offsetof(Device, sysfs), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h new file mode 100644 index 0000000..4aff226 --- /dev/null +++ b/src/core/dbus-device.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_device_vtable[]; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c new file mode 100644 index 0000000..935c62b --- /dev/null +++ b/src/core/dbus-execute.c @@ -0,0 +1,802 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#ifdef HAVE_SECCOMP +#include +#endif + +#include "bus-util.h" +#include "missing.h" +#include "ioprio.h" +#include "strv.h" +#include "fileio.h" +#include "execute.h" +#include "dbus-execute.h" +#include "capability.h" +#include "env-util.h" + +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif + +BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput); + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput); + +static int property_get_environment_files( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + char **j; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(sb)"); + if (r < 0) + return r; + + STRV_FOREACH(j, c->environment_files) { + const char *fn = *j; + + r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-'); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_rlimit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + struct rlimit *rl; + uint64_t u; + + assert(bus); + assert(reply); + assert(userdata); + + rl = *(struct rlimit**) userdata; + if (rl) + u = (uint64_t) rl->rlim_max; + else { + struct rlimit buf = {}; + int z; + + z = rlimit_from_string(property); + assert(z >= 0); + + getrlimit(z, &buf); + + u = (uint64_t) buf.rlim_max; + } + + return sd_bus_message_append(reply, "t", u); +} + +static int property_get_oom_score_adjust( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + + ExecContext *c = userdata; + int32_t n; + + assert(bus); + assert(reply); + assert(c); + + if (c->oom_score_adjust_set) + n = c->oom_score_adjust; + else { + _cleanup_free_ char *t = NULL; + + n = 0; + if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) + safe_atoi(t, &n); + } + + return sd_bus_message_append(reply, "i", n); +} + +static int property_get_nice( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + + ExecContext *c = userdata; + int32_t n; + + assert(bus); + assert(reply); + assert(c); + + if (c->nice_set) + n = c->nice; + else { + errno = 0; + n = getpriority(PRIO_PROCESS, 0); + if (errno != 0) + n = 0; + } + + return sd_bus_message_append(reply, "i", n); +} + +static int property_get_ioprio( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + + ExecContext *c = userdata; + int32_t n; + + assert(bus); + assert(reply); + assert(c); + + if (c->ioprio_set) + n = c->ioprio; + else { + n = ioprio_get(IOPRIO_WHO_PROCESS, 0); + if (n < 0) + n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4); + } + + return sd_bus_message_append(reply, "i", n); +} + +static int property_get_cpu_sched_policy( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + int32_t n; + + assert(bus); + assert(reply); + assert(c); + + if (c->cpu_sched_set) + n = c->cpu_sched_policy; + else { + n = sched_getscheduler(0); + if (n < 0) + n = SCHED_OTHER; + } + + return sd_bus_message_append(reply, "i", n); +} + +static int property_get_cpu_sched_priority( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + int32_t n; + + assert(bus); + assert(reply); + assert(c); + + if (c->cpu_sched_set) + n = c->cpu_sched_priority; + else { + struct sched_param p = {}; + + if (sched_getparam(0, &p) >= 0) + n = p.sched_priority; + else + n = 0; + } + + return sd_bus_message_append(reply, "i", n); +} + +static int property_get_cpu_affinity( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + if (c->cpuset) + return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus)); + else + return sd_bus_message_append_array(reply, 'y', NULL, 0); +} + +static int property_get_timer_slack_nsec( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + uint64_t u; + + assert(bus); + assert(reply); + assert(c); + + if (c->timer_slack_nsec != (nsec_t) -1) + u = (uint64_t) c->timer_slack_nsec; + else + u = (uint64_t) prctl(PR_GET_TIMERSLACK); + + return sd_bus_message_append(reply, "t", u); +} + +static int property_get_capability_bounding_set( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + /* We store this negated internally, to match the kernel, but + * we expose it normalized. */ + return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop); +} + +static int property_get_capabilities( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + _cleanup_cap_free_charp_ char *t = NULL; + const char *s; + + assert(bus); + assert(reply); + assert(c); + + if (c->capabilities) + s = t = cap_to_text(c->capabilities, NULL); + else + s = ""; + + if (!s) + return -ENOMEM; + + return sd_bus_message_append(reply, "s", s); +} + +static int property_get_syscall_filter( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + _cleanup_strv_free_ char **l = NULL; + int r; + +#ifdef HAVE_SECCOMP + Iterator i; + void *id; +#endif + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'r', "bas"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "b", c->syscall_whitelist); + if (r < 0) + return r; + +#ifdef HAVE_SECCOMP + SET_FOREACH(id, c->syscall_filter, i) { + char *name; + + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); + if (!name) + continue; + + r = strv_push(&l, name); + if (r < 0) { + free(name); + return -ENOMEM; + } + } +#endif + + strv_sort(l); + + r = sd_bus_message_append_strv(reply, l); + if (r < 0) + return r; + + return sd_bus_message_close_container(reply); +} + +static int property_get_syscall_archs( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + _cleanup_strv_free_ char **l = NULL; + int r; + +#ifdef HAVE_SECCOMP + Iterator i; + void *id; +#endif + + assert(bus); + assert(reply); + assert(c); + +#ifdef HAVE_SECCOMP + SET_FOREACH(id, c->syscall_archs, i) { + const char *name; + + name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1); + if (!name) + continue; + + r = strv_extend(&l, name); + if (r < 0) + return -ENOMEM; + } +#endif + + strv_sort(l); + + r = sd_bus_message_append_strv(reply, l); + if (r < 0) + return r; + + return 0; +} + +static int property_get_syscall_errno( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno); +} + +static int property_get_selinux_context( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context); +} + +static int property_get_apparmor_profile( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile); +} + +static int property_get_personality( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "s", personality_to_string(c->personality)); +} + +const sd_bus_vtable bus_exec_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; + +static int append_exec_command(sd_bus_message *reply, ExecCommand *c) { + int r; + + assert(reply); + assert(c); + + if (!c->path) + return 0; + + r = sd_bus_message_open_container(reply, 'r', "sasbttttuii"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", c->path); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(reply, c->argv); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "bttttuii", + c->ignore, + c->exec_status.start_timestamp.realtime, + c->exec_status.start_timestamp.monotonic, + c->exec_status.exit_timestamp.realtime, + c->exec_status.exit_timestamp.monotonic, + (uint32_t) c->exec_status.pid, + (int32_t) c->exec_status.code, + (int32_t) c->exec_status.status); + if (r < 0) + return r; + + return sd_bus_message_close_container(reply); +} + +int bus_property_get_exec_command( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *ret_error) { + + ExecCommand *c = (ExecCommand*) userdata; + int r; + + assert(bus); + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)"); + if (r < 0) + return r; + + r = append_exec_command(reply, c); + if (r < 0) + return r; + + return sd_bus_message_close_container(reply); +} + +int bus_property_get_exec_command_list( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *ret_error) { + + ExecCommand *c = *(ExecCommand**) userdata; + int r; + + assert(bus); + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)"); + if (r < 0) + return r; + + LIST_FOREACH(command, c, c) { + r = append_exec_command(reply, c); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +int bus_exec_context_set_transient_property( + Unit *u, + ExecContext *c, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(u); + assert(c); + assert(name); + assert(message); + + if (streq(name, "User")) { + const char *uu; + + r = sd_bus_message_read(message, "s", &uu); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + + if (isempty(uu)) { + free(c->user); + c->user = NULL; + } else { + char *t; + + t = strdup(uu); + if (!t) + return -ENOMEM; + + free(c->user); + c->user = t; + } + + unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu); + } + + return 1; + + } else if (streq(name, "Group")) { + const char *gg; + + r = sd_bus_message_read(message, "s", &gg); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + + if (isempty(gg)) { + free(c->group); + c->group = NULL; + } else { + char *t; + + t = strdup(gg); + if (!t) + return -ENOMEM; + + free(c->group); + c->group = t; + } + + unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg); + } + + return 1; + + } else if (streq(name, "Nice")) { + int n; + + r = sd_bus_message_read(message, "i", &n); + if (r < 0) + return r; + + if (n < PRIO_MIN || n >= PRIO_MAX) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range"); + + if (mode != UNIT_CHECK) { + c->nice = n; + unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n); + } + + return 1; + + } else if (streq(name, "Environment")) { + + _cleanup_strv_free_ char **l = NULL; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + if (!strv_env_is_valid(l)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block."); + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + char **e; + + e = strv_env_merge(2, c->environment, l); + if (!e) + return -ENOMEM; + + strv_free(c->environment); + c->environment = e; + + joined = strv_join(c->environment, " "); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + } + + return 1; + } + + return 0; +} diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h new file mode 100644 index 0000000..e4c2d5d --- /dev/null +++ b/src/core/dbus-execute.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "execute.h" + +#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \ + BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \ + BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \ + SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \ + SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \ + SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags) + +#define BUS_EXEC_COMMAND_VTABLE(name, offset, flags) \ + SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command, offset, flags) + +#define BUS_EXEC_COMMAND_LIST_VTABLE(name, offset, flags) \ + SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command_list, offset, flags) + +extern const sd_bus_vtable bus_exec_vtable[]; + +int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); +int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); +int bus_property_get_exec_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); + +int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c new file mode 100644 index 0000000..a8eae47 --- /dev/null +++ b/src/core/dbus-job.c @@ -0,0 +1,224 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "log.h" +#include "sd-bus.h" +#include "selinux-access.h" +#include "job.h" +#include "dbus-job.h" +#include "dbus-client-track.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState); + +static int property_get_unit( + 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 *p = NULL; + Job *j = userdata; + + assert(bus); + assert(reply); + assert(j); + + p = unit_dbus_path(j->unit); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(so)", j->unit->id, p); +} + +static int method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Job *j = userdata; + int r; + + assert(bus); + assert(message); + assert(j); + + r = selinux_unit_access_check(j->unit, bus, message, "stop", error); + if (r < 0) + return r; + + job_finish_and_invalidate(j, JOB_CANCELED, true); + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable bus_job_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Cancel", NULL, NULL, method_cancel, 0), + SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; + +static int foreach_client(Job *j, int (*send_message)(sd_bus *bus, const char *name, Job *j)) { + BusTrackedClient *one_destination = NULL; + Iterator i; + sd_bus *b; + unsigned n, m; + int r, ret; + + assert(j); + assert(send_message); + + n = set_size(j->manager->subscribed); + m = set_size(j->subscribed); + + if (n <= 0 && m <= 0) + return 0; + + if (n == 1 && m == 0) + one_destination = set_first(j->manager->subscribed); + else if (n == 0 && m == 1) + one_destination = set_first(j->subscribed); + else + one_destination = NULL; + + if (one_destination) + return send_message(one_destination->bus, isempty(one_destination->name) ? NULL : one_destination->name, j); + + ret = 0; + + /* Send to everybody */ + SET_FOREACH(b, j->manager->private_buses, i) { + r = send_message(b, NULL, j); + if (r < 0) + ret = r; + } + + if (j->manager->api_bus) { + r = send_message(j->manager->api_bus, NULL, j); + if (r < 0) + ret = r; + } + + return ret; +} + +static int send_new_signal(sd_bus *bus, const char *destination, Job *j) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(bus); + assert(j); + + p = job_dbus_path(j); + if (!p) + return -ENOMEM; + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "JobNew"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "uos", j->id, p, j->unit->id); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); +} + +static int send_changed_signal(sd_bus *bus, const char *destination, Job *j) { + _cleanup_free_ char *p = NULL; + + assert(bus); + assert(j); + + p = job_dbus_path(j); + if (!p) + return -ENOMEM; + + return sd_bus_emit_properties_changed(bus, p, "org.freedesktop.systemd1.Job", "State", NULL); +} + +void bus_job_send_change_signal(Job *j) { + int r; + + assert(j); + + if (j->in_dbus_queue) { + LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j); + j->in_dbus_queue = false; + } + + r = foreach_client(j, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal); + if (r < 0) + log_debug("Failed to send job change signal for %u: %s", j->id, strerror(-r)); + + j->sent_dbus_new_signal = true; +} + +static int send_removed_signal(sd_bus *bus, const char *destination, Job *j) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(bus); + assert(j); + + p = job_dbus_path(j); + if (!p) + return -ENOMEM; + + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "JobRemoved"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "uoss", j->id, p, j->unit->id, job_result_to_string(j->result)); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); +} + +void bus_job_send_removed_signal(Job *j) { + int r; + + assert(j); + + if (!j->sent_dbus_new_signal) + bus_job_send_change_signal(j); + + r = foreach_client(j, send_removed_signal); + if (r < 0) + log_debug("Failed to send job remove signal for %u: %s", j->id, strerror(-r)); +} diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h new file mode 100644 index 0000000..d1d0f6d --- /dev/null +++ b/src/core/dbus-job.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "job.h" + +extern const sd_bus_vtable bus_job_vtable[]; + +void bus_job_send_change_signal(Job *j); +void bus_job_send_removed_signal(Job *j); diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c new file mode 100644 index 0000000..fb29e14 --- /dev/null +++ b/src/core/dbus-kill.c @@ -0,0 +1,123 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "kill.h" +#include "dbus-kill.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode); + +const sd_bus_vtable bus_kill_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; + +int bus_kill_context_set_transient_property( + Unit *u, + KillContext *c, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(u); + assert(c); + assert(name); + assert(message); + + if (streq(name, "KillMode")) { + const char *m; + KillMode k; + + r = sd_bus_message_read(message, "s", &m); + if (r < 0) + return r; + + k = kill_mode_from_string(m); + if (k < 0) + return -EINVAL; + + if (mode != UNIT_CHECK) { + c->kill_mode = k; + + unit_write_drop_in_private_format(u, mode, name, "KillMode=%s\n", kill_mode_to_string(k)); + } + + return 1; + + } else if (streq(name, "KillSignal")) { + int sig; + + r = sd_bus_message_read(message, "i", &sig); + if (r < 0) + return r; + + if (sig <= 0 || sig >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig); + + if (mode != UNIT_CHECK) { + c->kill_signal = sig; + + unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s\n", signal_to_string(sig)); + } + + return 1; + + } else if (streq(name, "SendSIGHUP")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->send_sighup = b; + + unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b)); + } + + return 1; + + } else if (streq(name, "SendSIGKILL")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->send_sigkill = b; + + unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b)); + } + + return 1; + + } + + return 0; +} diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h new file mode 100644 index 0000000..7c15f3a --- /dev/null +++ b/src/core/dbus-kill.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" +#include "kill.h" + +extern const sd_bus_vtable bus_kill_vtable[]; + +int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c new file mode 100644 index 0000000..86816f6 --- /dev/null +++ b/src/core/dbus-manager.c @@ -0,0 +1,1740 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "log.h" +#include "strv.h" +#include "build.h" +#include "install.h" +#include "selinux-access.h" +#include "watchdog.h" +#include "hwclock.h" +#include "path-util.h" +#include "virt.h" +#include "env-util.h" +#include "dbus.h" +#include "dbus-manager.h" +#include "dbus-unit.h" +#include "dbus-snapshot.h" +#include "dbus-client-track.h" +#include "dbus-execute.h" +#include "bus-errors.h" + +static int property_get_version( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "s", PACKAGE_VERSION); +} + +static int property_get_features( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "s", SYSTEMD_FEATURES); +} + +static int property_get_virtualization( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + const char *id = NULL; + + assert(bus); + assert(reply); + + detect_virtualization(&id); + + return sd_bus_message_append(reply, "s", id); +} + +static int property_get_tainted( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf; + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + + assert(bus); + assert(reply); + assert(m); + + if (m->taint_usr) + e = stpcpy(e, "split-usr:"); + + if (readlink_malloc("/etc/mtab", &p) < 0) + e = stpcpy(e, "mtab-not-symlink:"); + + if (access("/proc/cgroups", F_OK) < 0) + e = stpcpy(e, "cgroups-missing:"); + + if (hwclock_is_localtime() > 0) + e = stpcpy(e, "local-hwclock:"); + + /* remove the last ':' */ + if (e != buf) + e[-1] = 0; + + return sd_bus_message_append(reply, "s", buf); +} + +static int property_get_log_target( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "s", log_target_to_string(log_get_target())); +} + +static int property_set_log_target( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + void *userdata, + sd_bus_error *error) { + + const char *t; + int r; + + assert(bus); + assert(value); + + r = sd_bus_message_read(value, "s", &t); + if (r < 0) + return r; + + return log_set_target_from_string(t); +} + +static int property_get_log_level( + 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 *t = NULL; + int r; + + assert(bus); + assert(reply); + + r = log_level_to_string_alloc(log_get_max_level(), &t); + if (r < 0) + return r; + + return sd_bus_message_append(reply, "s", t); +} + +static int property_set_log_level( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + void *userdata, + sd_bus_error *error) { + + const char *t; + int r; + + assert(bus); + assert(value); + + r = sd_bus_message_read(value, "s", &t); + if (r < 0) + return r; + + return log_set_max_level_from_string(t); +} + +static int property_get_n_names( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units)); +} + +static int property_get_n_jobs( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs)); +} + +static int property_get_progress( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + double d; + + assert(bus); + assert(reply); + assert(m); + + if (dual_timestamp_is_set(&m->finish_timestamp)) + d = 1.0; + else + d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs); + + return sd_bus_message_append(reply, "d", d); +} + +static int property_set_runtime_watchdog( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + void *userdata, + sd_bus_error *error) { + + usec_t *t = userdata; + int r; + + assert(bus); + assert(value); + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + r = sd_bus_message_read(value, "t", t); + if (r < 0) + return r; + + return watchdog_set_timeout(t); +} + +static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name); + + r = selinux_unit_access_check(u, bus, 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); +} + +static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + pid_t pid; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + + r = sd_bus_message_read(message, "u", &pid); + if (r < 0) + return r; + + if (pid == 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + } + + u = manager_get_unit_by_pid(m, pid); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID %u does not belong to any loaded unit.", pid); + + r = selinux_unit_access_check(u, bus, 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); +} + +static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = selinux_unit_access_check(u, bus, 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); +} + +static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) { + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible, error); +} + +static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_START, false, error); +} + +static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_STOP, false, error); +} + +static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false, error); +} + +static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false, error); +} + +static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false, error); +} + +static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true, error); +} + +static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true, error); +} + +static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *old_name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &old_name); + if (r < 0) + return r; + + u = manager_get_unit(m, old_name); + if (!u || !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 method_start_unit_generic(bus, message, m, JOB_START, false, error); +} + +static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + + return bus_unit_method_kill(bus, message, u, error); +} + +static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + + return bus_unit_method_reset_failed(bus, message, u, error); +} + +static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + + return bus_unit_method_set_properties(bus, message, u, error); +} + +static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *name, *smode; + Manager *m = userdata; + JobMode mode; + UnitType t; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ss", &name, &smode); + if (r < 0) + return r; + + t = unit_name_to_type(name); + if (t < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type."); + + if (!unit_vtable[t]->can_transient) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); + + mode = job_mode_from_string(smode); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode); + + r = selinux_access_check(bus, message, "start", error); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + + /* OK, the unit failed to load and is unreferenced, now let's + * fill in the transient data instead */ + r = unit_make_transient(u); + if (r < 0) + return r; + + /* Set our properties */ + r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, error); + if (r < 0) + return r; + + /* And load this stub fully */ + r = unit_load(u); + if (r < 0) + return r; + + manager_dispatch_load_queue(m); + + /* Finally, start it */ + return bus_unit_queue_job(bus, message, u, JOB_START, mode, false, error); +} + +static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + uint32_t id; + Job *j; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "u", &id); + if (r < 0) + return r; + + j = manager_get_job(m, id); + if (!j) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); + + r = selinux_unit_access_check(j->unit, bus, message, "status", error); + if (r < 0) + return r; + + path = job_dbus_path(j); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", path); +} + +static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + uint32_t id; + Job *j; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "u", &id); + if (r < 0) + return r; + + j = manager_get_job(m, id); + if (!j) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); + + r = selinux_unit_access_check(j->unit, bus, message, "stop", error); + if (r < 0) + return r; + + job_finish_and_invalidate(j, JOB_CANCELED, true); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reboot", error); + if (r < 0) + return r; + + manager_clear_jobs(m); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + manager_reset_failed(m); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + const char *k; + Iterator i; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)"); + if (r < 0) + return r; + + HASHMAP_FOREACH_KEY(u, k, m->units, i) { + _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + Unit *following; + + if (k != u->id) + continue; + + following = unit_following(u); + + unit_path = unit_dbus_path(u); + if (!unit_path) + return -ENOMEM; + + if (u->job) { + job_path = job_dbus_path(u->job); + if (!job_path) + return -ENOMEM; + } + + r = sd_bus_message_append( + reply, "(ssssssouso)", + u->id, + unit_description(u), + unit_load_state_to_string(u->load_state), + unit_active_state_to_string(unit_active_state(u)), + unit_sub_state_to_string(u), + following ? following->id : "", + unit_path, + u->job ? u->job->id : 0, + u->job ? job_type_to_string(u->job->type) : "", + job_path ? job_path : "/"); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Iterator i; + Job *j; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(usssoo)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(j, m->jobs, i) { + _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + + job_path = job_dbus_path(j); + if (!job_path) + return -ENOMEM; + + unit_path = unit_dbus_path(j->unit); + if (!unit_path) + return -ENOMEM; + + r = sd_bus_message_append( + reply, "(usssoo)", + j->id, + j->unit->id, + job_type_to_string(j->type), + job_state_to_string(j->state), + job_path, + unit_path); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = bus_client_track(&m->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed."); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = bus_client_untrack(m->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed."); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *dump = NULL; + _cleanup_fclose_ FILE *f = NULL; + Manager *m = userdata; + size_t size; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + f = open_memstream(&dump, &size); + if (!f) + return -ENOMEM; + + manager_dump_units(m, f, NULL); + manager_dump_jobs(m, f, NULL); + + fflush(f); + + if (ferror(f)) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "s", dump); +} + +static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + Manager *m = userdata; + const char *name; + int cleanup; + Snapshot *s = NULL; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "start", error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "sb", &name, &cleanup); + if (r < 0) + return r; + + if (isempty(name)) + name = NULL; + + r = snapshot_create(m, name, cleanup, error, &s); + if (r < 0) + return r; + + path = unit_dbus_path(UNIT(s)); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", path); +} + +static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "stop", error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + u = manager_get_unit(m, name); + if (!u) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name); + + if (u->type != UNIT_SNAPSHOT) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name); + + return bus_snapshot_method_remove(bus, message, u, error); +} + +static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + /* Instead of sending the reply back right away, we just + * remember that we need to and then send it after the reload + * is finished. That way the caller knows when the reload + * finished. */ + + assert(!m->queued_message); + r = sd_bus_message_new_method_return(message, &m->queued_message); + if (r < 0) + return r; + + m->queued_message_bus = sd_bus_ref(bus); + m->exit_code = MANAGER_RELOAD; + + return 1; +} + +static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + /* We don't send a reply back here, the client should + * just wait for us disconnecting. */ + + m->exit_code = MANAGER_REEXECUTE; + return 1; +} + +static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "halt", error); + if (r < 0) + return r; + + if (m->running_as == SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); + + m->exit_code = MANAGER_EXIT; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reboot", error); + if (r < 0) + return r; + + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); + + m->exit_code = MANAGER_REBOOT; + + return sd_bus_reply_method_return(message, NULL); +} + + +static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "halt", error); + if (r < 0) + return r; + + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); + + m->exit_code = MANAGER_POWEROFF; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "halt", error); + if (r < 0) + return r; + + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers."); + + m->exit_code = MANAGER_HALT; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reboot", error); + if (r < 0) + return r; + + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); + + m->exit_code = MANAGER_KEXEC; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + char *ri = NULL, *rt = NULL; + const char *root, *init; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reboot", error); + if (r < 0) + return r; + + if (m->running_as != SYSTEMD_SYSTEM) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); + + r = sd_bus_message_read(message, "ss", &root, &init); + if (r < 0) + return r; + + if (path_equal(root, "/") || !path_is_absolute(root)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root); + + /* Safety check */ + if (isempty(init)) { + if (! path_is_os_tree(root)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. /etc/os-release is missing.", root); + } else { + _cleanup_free_ char *p = NULL; + + if (!path_is_absolute(init)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init); + + p = strappend(root, init); + if (!p) + return -ENOMEM; + + if (access(p, X_OK) < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p); + } + + rt = strdup(root); + if (!rt) + return -ENOMEM; + + if (!isempty(init)) { + ri = strdup(init); + if (!ri) { + free(rt); + return -ENOMEM; + } + } + + free(m->switch_root); + m->switch_root = rt; + + free(m->switch_root_init); + m->switch_root_init = ri; + + m->exit_code = MANAGER_SWITCH_ROOT; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **plus = NULL; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &plus); + if (r < 0) + return r; + if (!strv_env_is_valid(plus)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + + r = manager_environment_add(m, NULL, plus); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **minus = NULL; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &minus); + if (r < 0) + return r; + + if (!strv_env_name_or_assignment_is_valid(minus)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + + r = manager_environment_add(m, minus, NULL); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **minus = NULL, **plus = NULL; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "reload", error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &plus); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &minus); + if (r < 0) + return r; + + if (!strv_env_is_valid(plus)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + if (!strv_env_name_or_assignment_is_valid(minus)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + + r = manager_environment_add(m, minus, plus); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + UnitFileList *item; + Hashmap *h; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return -ENOMEM; + + r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h); + if (r < 0) + goto fail; + + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + goto fail; + + HASHMAP_FOREACH(item, h, i) { + + r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state)); + if (r < 0) + goto fail; + } + + unit_file_list_free(h); + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); + +fail: + unit_file_list_free(h); + return r; +} + +static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + UnitFileState state; + UnitFileScope scope; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + state = unit_file_get_state(scope, NULL, name); + if (state < 0) + return state; + + return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state)); +} + +static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *default_target = NULL; + Manager *m = userdata; + UnitFileScope scope; + int r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "status", error); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = unit_file_get_default(scope, NULL, &default_target); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, "s", default_target); +} + +static int send_unit_files_changed(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + int r; + + assert(bus); + + r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged"); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +static int reply_unit_file_changes_and_free( + Manager *m, + sd_bus *bus, + sd_bus_message *message, + int carries_install_info, + UnitFileChange *changes, + unsigned n_changes) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + unsigned i; + int r; + + if (n_changes > 0) + bus_manager_foreach_client(m, send_unit_files_changed, NULL); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + goto fail; + + if (carries_install_info >= 0) { + r = sd_bus_message_append(reply, "b", carries_install_info); + if (r < 0) + goto fail; + } + + r = sd_bus_message_open_container(reply, 'a', "(sss)"); + if (r < 0) + goto fail; + + for (i = 0; i < n_changes; i++) { + r = sd_bus_message_append( + reply, "(sss)", + unit_file_change_type_to_string(changes[i].type), + changes[i].path, + changes[i].source); + if (r < 0) + goto fail; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + goto fail; + + return sd_bus_send(bus, reply, NULL); + +fail: + unit_file_changes_free(changes, n_changes); + return r; +} + +static int method_enable_unit_files_generic( + sd_bus *bus, + sd_bus_message *message, + Manager *m, const + char *verb, + int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes), + bool carries_install_info, + sd_bus_error *error) { + + _cleanup_strv_free_ char **l = NULL; +#ifdef HAVE_SELINUX + char **i; +#endif + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileScope scope; + int runtime, force, r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + +#ifdef HAVE_SELINUX + STRV_FOREACH(i, l) { + Unit *u; + + u = manager_get_unit(m, *i); + if (u) { + r = selinux_unit_access_check(u, bus, message, verb, error); + if (r < 0) + return r; + } + } +#endif + + r = sd_bus_message_read(message, "bb", &runtime, &force); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = call(scope, runtime, NULL, l, force, &changes, &n_changes); + if (r < 0) + return r; + + return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes); +} + +static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true, error); +} + +static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true, error); +} + +static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false, error); +} + +static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset, true, error); +} + +static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false, error); +} + +static int method_disable_unit_files_generic( + sd_bus *bus, + sd_bus_message *message, + Manager *m, const + char *verb, + int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), + sd_bus_error *error) { + + _cleanup_strv_free_ char **l = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileScope scope; + int r, runtime; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, verb, error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "b", &runtime); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = call(scope, runtime, NULL, l, &changes, &n_changes); + if (r < 0) + return r; + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); +} + +static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable, error); +} + +static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask, error); +} + +static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + Manager *m = userdata; + UnitFileScope scope; + const char *name; + int force, r; + + assert(bus); + assert(message); + assert(m); + + r = selinux_access_check(bus, message, "enable", error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "sb", &name, &force); + if (r < 0) + return r; + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes); + if (r < 0) + return r; + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); +} + +const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Version", "s", property_get_version, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Features", "s", property_get_features, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, kernel_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0), + SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0), + SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0), + SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0), + SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0), + SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0), + SD_BUS_PROPERTY("Progress", "d", property_get_progress, 0, 0), + SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0), + SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), + + SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("LoadUnit", "s", "o", method_load_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("StartUnit", "ss", "o", method_start_unit, 0), + SD_BUS_METHOD("StartUnitReplace", "sss", "o", method_start_unit_replace, 0), + SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, 0), + SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, 0), + SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, 0), + SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, 0), + SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, 0), + SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, 0), + SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, 0), + SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, 0), + SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, 0), + SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, 0), + SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, 0), + SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, 0), + SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0), + SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0), + SD_BUS_METHOD("Reload", NULL, NULL, method_reload, 0), + SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, 0), + SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0), + SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)), + SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)), + SD_BUS_METHOD("Halt", NULL, NULL, method_halt, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)), + SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)), + SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)), + SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, 0), + SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, 0), + SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, 0), + SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, 0), + SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, 0), + SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, 0), + SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, 0), + SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, 0), + SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, 0), + SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, 0), + SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, 0), + SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_SIGNAL("UnitNew", "so", 0), + SD_BUS_SIGNAL("UnitRemoved", "so", 0), + SD_BUS_SIGNAL("JobNew", "uos", 0), + SD_BUS_SIGNAL("JobRemoved", "uoss", 0), + SD_BUS_SIGNAL("StartupFinished", "tttttt", 0), + SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0), + SD_BUS_SIGNAL("Reloading", "b", 0), + + SD_BUS_VTABLE_END +}; + +int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata) { + Iterator i; + sd_bus *b; + unsigned n; + int r, ret; + + n = set_size(m->subscribed); + if (n <= 0) + return 0; + if (n == 1) { + BusTrackedClient *d; + + assert_se(d = set_first(m->subscribed)); + return send_message(d->bus, isempty(d->name) ? NULL : d->name, userdata); + } + + ret = 0; + + /* Send to everybody */ + SET_FOREACH(b, m->private_buses, i) { + r = send_message(b, NULL, userdata); + if (r < 0) + ret = r; + } + + if (m->api_bus) { + r = send_message(m->api_bus, NULL, userdata); + if (r < 0) + ret = r; + } + + return ret; +} + +static int send_finished(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + usec_t *times = userdata; + int r; + + assert(bus); + assert(times); + + r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished"); + if (r < 0) + return r; + + r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +void bus_manager_send_finished( + Manager *m, + usec_t firmware_usec, + usec_t loader_usec, + usec_t kernel_usec, + usec_t initrd_usec, + usec_t userspace_usec, + usec_t total_usec) { + + int r; + + assert(m); + + r = bus_manager_foreach_client(m, send_finished, + (usec_t[6]) { firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec }); + if (r < 0) + log_debug("Failed to send finished signal: %s", strerror(-r)); +} + +static int send_reloading(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + int r; + + assert(bus); + + r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading"); + if (r < 0) + return r; + + r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata)); + if (r < 0) + return r; + + return sd_bus_send_to(bus, message, destination, NULL); +} + +void bus_manager_send_reloading(Manager *m, bool active) { + int r; + + assert(m); + + r = bus_manager_foreach_client(m, send_reloading, INT_TO_PTR(active)); + if (r < 0) + log_debug("Failed to send reloading signal: %s", strerror(-r)); + +} diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h new file mode 100644 index 0000000..0ef99fa --- /dev/null +++ b/src/core/dbus-manager.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "manager.h" + +extern const sd_bus_vtable bus_manager_vtable[]; + +int bus_manager_foreach_client(Manager *m, int (*send_message)(sd_bus *bus, const char *destination, void *userdata), void *userdata); + +void bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); +void bus_manager_send_reloading(Manager *m, bool active); diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c new file mode 100644 index 0000000..e64d3ea --- /dev/null +++ b/src/core/dbus-mount.c @@ -0,0 +1,150 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "mount.h" +#include "dbus-unit.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" +#include "dbus-mount.h" +#include "bus-util.h" + +static int property_get_what( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Mount *m = userdata; + const char *d; + + assert(bus); + assert(reply); + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what) + d = m->parameters_proc_self_mountinfo.what; + else if (m->from_fragment && m->parameters_fragment.what) + d = m->parameters_fragment.what; + else + d = ""; + + return sd_bus_message_append(reply, "s", d); +} + +static int property_get_options( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Mount *m = userdata; + const char *d; + + assert(bus); + assert(reply); + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options) + d = m->parameters_proc_self_mountinfo.options; + else if (m->from_fragment && m->parameters_fragment.options) + d = m->parameters_fragment.options; + else + d = ""; + + return sd_bus_message_append(reply, "s", d); +} + +static int property_get_type( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Mount *m = userdata; + const char *d; + + assert(bus); + assert(reply); + assert(m); + + if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) + d = m->parameters_proc_self_mountinfo.fstype; + else if (m->from_fragment && m->parameters_fragment.fstype) + d = m->parameters_fragment.fstype; + else + d = ""; + + return sd_bus_message_append(reply, "s", d); +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult); + +const sd_bus_vtable bus_mount_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Mount, where), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("What", "s", property_get_what, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Options","s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Type", "s", property_get_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Mount, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_VTABLE_END +}; + +int bus_mount_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Mount *m = MOUNT(u); + + assert(m); + assert(name); + assert(message); + + return bus_cgroup_set_property(u, &m->cgroup_context, name, message, mode, error); +} + +int bus_mount_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h new file mode 100644 index 0000000..f7004d2 --- /dev/null +++ b/src/core/dbus-mount.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_mount_vtable[]; + +int bus_mount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_mount_commit_properties(Unit *u); diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c new file mode 100644 index 0000000..b5e8941 --- /dev/null +++ b/src/core/dbus-path.c @@ -0,0 +1,88 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "path.h" +#include "dbus-unit.h" +#include "dbus-path.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult); + +static int property_get_paths( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Path *p = userdata; + PathSpec *k; + int r; + + assert(bus); + assert(reply); + assert(p); + + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; + + LIST_FOREACH(spec, k, p->specs) { + r = sd_bus_message_append(reply, "(ss)", path_type_to_string(k->type), k->path); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_unit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *p = userdata, *trigger; + + assert(bus); + assert(reply); + assert(p); + + trigger = UNIT_TRIGGER(p); + + return sd_bus_message_append(reply, "s", trigger ? trigger->id : ""); +} + +const sd_bus_vtable bus_path_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Unit", "s", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Paths", "a(ss)", property_get_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MakeDirectory", "b", bus_property_get_bool, offsetof(Path, make_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Path, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h new file mode 100644 index 0000000..667da05 --- /dev/null +++ b/src/core/dbus-path.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + + +#include "sd-bus.h" + +extern const sd_bus_vtable bus_path_vtable[]; diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c new file mode 100644 index 0000000..b9e3be4 --- /dev/null +++ b/src/core/dbus-scope.c @@ -0,0 +1,220 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "scope.h" +#include "dbus-unit.h" +#include "dbus-cgroup.h" +#include "dbus-kill.h" +#include "dbus-scope.h" +#include "bus-util.h" +#include "bus-internal.h" +#include "bus-errors.h" + +static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Scope *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = scope_abandon(s); + if (sd_bus_error_is_set(error)) + return r; + + if (r == -ESTALE) + return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id); + + return sd_bus_reply_method_return(message, NULL); +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult); + +const sd_bus_vtable bus_scope_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_SIGNAL("RequestStop", NULL, 0), + SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, 0), + SD_BUS_VTABLE_END +}; + +static int bus_scope_set_transient_property( + Scope *s, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(s); + assert(name); + assert(message); + + if (streq(name, "PIDs")) { + unsigned n = 0; + uint32_t pid; + + r = sd_bus_message_enter_container(message, 'a', "u"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "u", &pid)) > 0) { + + if (pid <= 1) + return -EINVAL; + + if (mode != UNIT_CHECK) { + r = unit_watch_pid(UNIT(s), pid); + if (r < 0 && r != -EEXIST) + return r; + } + + n++; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (n <= 0) + return -EINVAL; + + return 1; + + } else if (streq(name, "Controller")) { + const char *controller; + char *c; + + r = sd_bus_message_read(message, "s", &controller); + if (r < 0) + return r; + + if (!isempty(controller) && !service_name_is_valid(controller)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller); + + if (mode != UNIT_CHECK) { + if (isempty(controller)) + c = NULL; + else { + c = strdup(controller); + if (!c) + return -ENOMEM; + } + + free(s->controller); + s->controller = c; + } + + return 1; + + } else if (streq(name, "TimeoutStopUSec")) { + + if (mode != UNIT_CHECK) { + r = sd_bus_message_read(message, "t", &s->timeout_stop_usec); + if (r < 0) + return r; + + unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) s->timeout_stop_usec); + } else { + r = sd_bus_message_skip(message, "t"); + if (r < 0) + return r; + } + + return 1; + } + + return 0; +} + +int bus_scope_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Scope *s = SCOPE(u); + int r; + + assert(s); + assert(name); + assert(message); + + r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); + if (r != 0) + return r; + + if (u->load_state == UNIT_STUB) { + /* While we are created we still accept PIDs */ + + r = bus_scope_set_transient_property(s, name, message, mode, error); + if (r != 0) + return r; + + r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error); + if (r != 0) + return r; + } + + return 0; +} + +int bus_scope_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} + +int bus_scope_send_request_stop(Scope *s) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(s); + + if (!s->controller) + return 0; + + p = unit_dbus_path(UNIT(s)); + if (!p) + return -ENOMEM; + + r = sd_bus_message_new_signal( + UNIT(s)->manager->api_bus, + &m, + p, + "org.freedesktop.systemd1.Scope", + "RequestStop"); + if (r < 0) + return r; + + return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL); +} diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h new file mode 100644 index 0000000..33beda4 --- /dev/null +++ b/src/core/dbus-scope.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_scope_vtable[]; + +int bus_scope_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_scope_commit_properties(Unit *u); + +int bus_scope_send_request_stop(Scope *s); diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c new file mode 100644 index 0000000..0451790 --- /dev/null +++ b/src/core/dbus-service.c @@ -0,0 +1,265 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "strv.h" +#include "path-util.h" +#include "unit.h" +#include "service.h" +#include "dbus-unit.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" +#include "dbus-service.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_start_limit_action, start_limit_action, StartLimitAction); + +const sd_bus_vtable bus_service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_start_limit_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, offsetof(Service, guess_main_pid), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_VTABLE_END +}; + +static int bus_service_set_transient_property( + Service *s, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(s); + assert(name); + assert(message); + + if (streq(name, "RemainAfterExit")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + s->remain_after_exit = b; + unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b)); + } + + return 1; + + } else if (streq(name, "Type")) { + const char *t; + ServiceType k; + + r = sd_bus_message_read(message, "s", &t); + if (r < 0) + return r; + + k = service_type_from_string(t); + if (k < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t); + + if (mode != UNIT_CHECK) { + s->type = k; + unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type)); + } + + return 1; + + } else if (streq(name, "ExecStart")) { + unsigned n = 0; + + r = sd_bus_message_enter_container(message, 'a', "(sasb)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) { + _cleanup_strv_free_ char **argv = NULL; + const char *path; + int b; + + r = sd_bus_message_read(message, "s", &path); + if (r < 0) + return r; + + if (!path_is_absolute(path)) + return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path); + + r = sd_bus_message_read_strv(message, &argv); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + ExecCommand *c; + + c = new0(ExecCommand, 1); + if (!c) + return -ENOMEM; + + c->path = strdup(path); + if (!c->path) { + free(c); + return -ENOMEM; + } + + c->argv = argv; + argv = NULL; + + c->ignore = b; + + path_kill_slashes(c->path); + exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c); + } + + n++; + } + + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + ExecCommand *c; + size_t size = 0; + + if (n == 0) { + exec_command_free_list(s->exec_command[SERVICE_EXEC_START]); + s->exec_command[SERVICE_EXEC_START] = NULL; + } + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + fputs("ExecStart=\n", f); + + LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) { + _cleanup_free_ char *a; + + a = strv_join_quoted(c->argv); + if (!a) + return -ENOMEM; + + fprintf(f, "ExecStart=%s@%s %s\n", + c->ignore ? "-" : "", + c->path, + a); + } + + fflush(f); + unit_write_drop_in_private(UNIT(s), mode, name, buf); + } + + return 1; + } + + return 0; +} + +int bus_service_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Service *s = SERVICE(u); + int r; + + assert(s); + assert(name); + assert(message); + + r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); + if (r != 0) + return r; + + if (u->transient && u->load_state == UNIT_STUB) { + /* This is a transient unit, let's load a little more */ + + r = bus_service_set_transient_property(s, name, message, mode, error); + if (r != 0) + return r; + + r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error); + if (r != 0) + return r; + + r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error); + if (r != 0) + return r; + } + + return 0; +} + +int bus_service_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h new file mode 100644 index 0000000..aab9f7a --- /dev/null +++ b/src/core/dbus-service.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_service_vtable[]; + +int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_service_commit_properties(Unit *u); diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c new file mode 100644 index 0000000..8bc90b1 --- /dev/null +++ b/src/core/dbus-slice.c @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "slice.h" +#include "dbus-unit.h" +#include "dbus-cgroup.h" +#include "dbus-slice.h" + +const sd_bus_vtable bus_slice_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_VTABLE_END +}; + +int bus_slice_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Slice *s = SLICE(u); + + assert(name); + assert(u); + + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); +} + +int bus_slice_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h new file mode 100644 index 0000000..eadc3b1 --- /dev/null +++ b/src/core/dbus-slice.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_slice_vtable[]; + +int bus_slice_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_slice_commit_properties(Unit *u); diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c new file mode 100644 index 0000000..053e35c --- /dev/null +++ b/src/core/dbus-snapshot.c @@ -0,0 +1,50 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "selinux-access.h" +#include "unit.h" +#include "snapshot.h" +#include "dbus-unit.h" +#include "dbus-snapshot.h" + +int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Snapshot *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = selinux_unit_access_check(UNIT(s), bus, message, "stop", error); + if (r < 0) + return r; + + snapshot_remove(s); + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable bus_snapshot_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, 0), + SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h new file mode 100644 index 0000000..d7551cb --- /dev/null +++ b/src/core/dbus-snapshot.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +extern const sd_bus_vtable bus_snapshot_vtable[]; + +int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c new file mode 100644 index 0000000..67a5627 --- /dev/null +++ b/src/core/dbus-socket.c @@ -0,0 +1,152 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "socket.h" +#include "dbus-unit.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" +#include "dbus-socket.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); + +static int property_get_listen( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + + Socket *s = SOCKET(userdata); + SocketPort *p; + int r; + + assert(bus); + assert(reply); + assert(s); + + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; + + LIST_FOREACH(port, p, s->ports) { + _cleanup_free_ char *address = NULL; + const char *a; + + switch (p->type) { + case SOCKET_SOCKET: { + r = socket_address_print(&p->address, &address); + if (r) + return r; + + a = address; + break; + } + + case SOCKET_SPECIAL: + case SOCKET_MQUEUE: + case SOCKET_FIFO: + a = p->path; + break; + + default: + assert_not_reached("Unknown socket type"); + } + + r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), a); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +const sd_bus_vtable bus_socket_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Backlog", "u", bus_property_get_unsigned, offsetof(Socket, backlog), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Socket, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("BindToDevice", "s", NULL, offsetof(Socket, bind_to_device), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Priority", "i", bus_property_get_int, offsetof(Socket, priority), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReceiveBuffer", "t", bus_property_get_size, offsetof(Socket, receive_buffer), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SendBuffer", "t", bus_property_get_size, offsetof(Socket, send_buffer), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IPTOS", "i", bus_property_get_int, offsetof(Socket, ip_tos), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IPTTL", "i", bus_property_get_int, offsetof(Socket, ip_ttl), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PipeSize", "t", bus_property_get_size, offsetof(Socket, pipe_size), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FreeBind", "b", bus_property_get_bool, offsetof(Socket, free_bind), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Transparent", "b", bus_property_get_bool, offsetof(Socket, transparent), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SmackLabelIPOut", "s", NULL, offsetof(Socket, smack_ip_out), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Socket, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0), + SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_VTABLE_END +}; + +int bus_socket_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Socket *s = SOCKET(u); + + assert(s); + assert(name); + assert(message); + + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); +} + +int bus_socket_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h new file mode 100644 index 0000000..17164d9 --- /dev/null +++ b/src/core/dbus-socket.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_socket_vtable[]; + +int bus_socket_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_socket_commit_properties(Unit *u); diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c new file mode 100644 index 0000000..93eae53 --- /dev/null +++ b/src/core/dbus-swap.c @@ -0,0 +1,95 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Maarten Lankhorst + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "swap.h" +#include "dbus-unit.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" +#include "dbus-swap.h" +#include "bus-util.h" + +static int property_get_priority( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Swap *s = SWAP(userdata); + int p; + + assert(bus); + assert(reply); + assert(s); + + if (s->from_proc_swaps) + p = s->parameters_proc_swaps.priority; + else if (s->from_fragment) + p = s->parameters_fragment.priority; + else + p = -1; + + return sd_bus_message_append(reply, "i", p); +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); + +const sd_bus_vtable bus_swap_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_EXEC_COMMAND_VTABLE("ExecActivate", offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + BUS_EXEC_COMMAND_VTABLE("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_VTABLE_END +}; + +int bus_swap_set_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + Swap *s = SWAP(u); + + assert(s); + assert(name); + assert(message); + + return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error); +} + +int bus_swap_commit_properties(Unit *u) { + assert(u); + + unit_update_cgroup_members_masks(u); + unit_realize_cgroup(u); + + return 0; +} diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h new file mode 100644 index 0000000..9469f68 --- /dev/null +++ b/src/core/dbus-swap.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Maarten Lankhorst + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_swap_vtable[]; + +int bus_swap_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); +int bus_swap_commit_properties(Unit *u); diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c new file mode 100644 index 0000000..205d1c4 --- /dev/null +++ b/src/core/dbus-target.c @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "target.h" +#include "dbus-unit.h" +#include "dbus-target.h" + +const sd_bus_vtable bus_target_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h new file mode 100644 index 0000000..6be9c9f --- /dev/null +++ b/src/core/dbus-target.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +extern const sd_bus_vtable bus_target_vtable[]; diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c new file mode 100644 index 0000000..9d54b94 --- /dev/null +++ b/src/core/dbus-timer.c @@ -0,0 +1,148 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" +#include "timer.h" +#include "dbus-unit.h" +#include "dbus-timer.h" +#include "bus-util.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult); + +static int property_get_monotonic_timers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Timer *t = userdata; + TimerValue *v; + int r; + + assert(bus); + assert(reply); + assert(t); + + r = sd_bus_message_open_container(reply, 'a', "(stt)"); + if (r < 0) + return r; + + LIST_FOREACH(value, v, t->values) { + _cleanup_free_ char *buf = NULL; + const char *s; + size_t l; + + if (v->base == TIMER_CALENDAR) + continue; + + s = timer_base_to_string(v->base); + assert(endswith(s, "Sec")); + + /* s/Sec/USec/ */ + l = strlen(s); + buf = new(char, l+2); + if (!buf) + return -ENOMEM; + + memcpy(buf, s, l-3); + memcpy(buf+l-3, "USec", 5); + + r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_calendar_timers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Timer *t = userdata; + TimerValue *v; + int r; + + assert(bus); + assert(reply); + assert(t); + + r = sd_bus_message_open_container(reply, 'a', "(sst)"); + if (r < 0) + return r; + + LIST_FOREACH(value, v, t->values) { + _cleanup_free_ char *buf = NULL; + + if (v->base != TIMER_CALENDAR) + continue; + + r = calendar_spec_to_string(v->calendar_spec, &buf); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_unit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata, *trigger; + + assert(bus); + assert(reply); + assert(u); + + trigger = UNIT_TRIGGER(u); + + return sd_bus_message_append(reply, "s", trigger ? trigger->id : ""); +} + +const sd_bus_vtable bus_timer_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Unit", "s", property_get_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("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", bus_property_get_usec, offsetof(Timer, next_elapse_monotonic), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h new file mode 100644 index 0000000..cfff88e --- /dev/null +++ b/src/core/dbus-timer.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +extern const sd_bus_vtable bus_timer_vtable[]; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c new file mode 100644 index 0000000..24d8a59 --- /dev/null +++ b/src/core/dbus-unit.c @@ -0,0 +1,979 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "log.h" +#include "selinux-access.h" +#include "cgroup-util.h" +#include "strv.h" +#include "path-util.h" +#include "fileio.h" +#include "dbus-unit.h" +#include "dbus-manager.h" +#include "bus-errors.h" +#include "dbus-client-track.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); + +static int property_get_names( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + Iterator i; + const char *t; + int r; + + assert(bus); + assert(reply); + assert(u); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + SET_FOREACH(t, u->names, i) { + r = sd_bus_message_append(reply, "s", t); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_following( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata, *f; + + assert(bus); + assert(reply); + assert(u); + + f = unit_following(u); + return sd_bus_message_append(reply, "s", f ? f->id : ""); +} + +static int property_get_dependencies( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Set *s = *(Set**) userdata; + Iterator j; + Unit *u; + int r; + + assert(bus); + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + SET_FOREACH(u, s, j) { + r = sd_bus_message_append(reply, "s", u->id); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_description( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", unit_description(u)); +} + +static int property_get_active_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); +} + +static int property_get_sub_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); +} + +static int property_get_unit_file_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); +} + +static int property_get_can_start( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); +} + +static int property_get_can_stop( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + /* On the lower levels we assume that every unit we can start + * we can also stop */ + + return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_stop); +} + +static int property_get_can_reload( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "b", unit_can_reload(u)); +} + +static int property_get_can_isolate( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start); +} + +static int property_get_job( + 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 *p = NULL; + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + if (!u->job) + return sd_bus_message_append(reply, "(uo)", 0, "/"); + + p = job_dbus_path(u->job); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(uo)", u->job->id, p); +} + +static int property_get_need_daemon_reload( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u)); +} + +static int property_get_conditions( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + Condition *c; + int r; + + assert(bus); + assert(reply); + assert(u); + + r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); + if (r < 0) + return r; + + LIST_FOREACH(conditions, c, u->conditions) { + r = sd_bus_message_append(reply, "(sbbsi)", + condition_type_to_string(c->type), + c->trigger, c->negate, + c->parameter, c->state); + if (r < 0) + return r; + + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_load_error( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + if (u->load_error != 0) + sd_bus_error_set_errno(&e, u->load_error); + + return sd_bus_message_append(reply, "(ss)", e.name, e.message); +} + +int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) { + const char *smode; + JobMode mode; + int r; + + assert(bus); + assert(message); + assert(u); + assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); + + r = sd_bus_message_read(message, "s", &smode); + if (r < 0) + return r; + + 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); + + return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error); +} + +static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error); +} + +static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error); +} + +static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error); +} + +static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error); +} + +static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error); +} + +static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error); +} + +static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error); +} + +int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Unit *u = userdata; + const char *swho; + int32_t signo; + KillWho who; + int r; + + assert(bus); + assert(message); + assert(u); + + r = sd_bus_message_read(message, "si", &swho, &signo); + if (r < 0) + return r; + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); + } + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); + + r = selinux_unit_access_check(u, bus, message, "stop", error); + if (r < 0) + return r; + + r = unit_kill(u, who, signo, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Unit *u = userdata; + int r; + + assert(bus); + assert(message); + assert(u); + + r = selinux_unit_access_check(u, bus, message, "reload", error); + if (r < 0) + return r; + + unit_reset_failed(u); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Unit *u = userdata; + int runtime, r; + + assert(bus); + assert(message); + assert(u); + + r = sd_bus_message_read(message, "b", &runtime); + if (r < 0) + return r; + + r = selinux_unit_access_check(u, bus, message, "start", error); + if (r < 0) + return r; + + r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable bus_unit_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), + SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), + BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0), + SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), + + SD_BUS_METHOD("Start", "s", "o", method_start, 0), + SD_BUS_METHOD("Stop", "s", "o", method_stop, 0), + SD_BUS_METHOD("Reload", "s", "o", method_reload, 0), + SD_BUS_METHOD("Restart", "s", "o", method_restart, 0), + SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0), + SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0), + SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0), + SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0), + SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0), + SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0), + + SD_BUS_VTABLE_END +}; + +static int property_get_slice( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Unit *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", unit_slice_name(u)); +} + +const sd_bus_vtable bus_unit_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), + SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0), + SD_BUS_VTABLE_END +}; + +static int send_new_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; + + assert(bus); + assert(u); + + p = unit_dbus_path(u); + if (!u) + return -ENOMEM; + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitNew"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "so", u->id, p); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); +} + +static int send_changed_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; + + assert(bus); + assert(u); + + p = unit_dbus_path(u); + if (!p) + return -ENOMEM; + + /* Send a properties changed signal. First for the specific + * type, then for the generic unit. The clients may rely on + * this order to get atomic behavior if needed. */ + + r = sd_bus_emit_properties_changed_strv( + bus, p, + UNIT_VTABLE(u)->bus_interface, + NULL); + if (r < 0) { + log_warning("Failed to send out specific PropertiesChanged signal for %s: %s", u->id, strerror(-r)); + return r; + } + + r = sd_bus_emit_properties_changed_strv( + bus, p, + "org.freedesktop.systemd1.Unit", + NULL); + if (r < 0) { + log_warning("Failed to send out generic PropertiesChanged signal for %s: %s", u->id, strerror(-r)); + return r; + } + + return 0; +} + +void bus_unit_send_change_signal(Unit *u) { + int r; + assert(u); + + if (u->in_dbus_queue) { + LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); + u->in_dbus_queue = false; + } + + if (!u->id) + return; + + r = bus_manager_foreach_client(u->manager, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u); + if (r < 0) + log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r)); + + u->sent_dbus_new_signal = true; +} + +static int send_removed_signal(sd_bus *bus, const char *destination, void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + int r; + + assert(bus); + assert(u); + + p = unit_dbus_path(u); + if (!u) + return -ENOMEM; + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitRemoved"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "so", u->id, p); + if (r < 0) + return r; + + return sd_bus_send_to(bus, m, destination, NULL); +} + +void bus_unit_send_removed_signal(Unit *u) { + int r; + assert(u); + + if (!u->sent_dbus_new_signal) + bus_unit_send_change_signal(u); + + if (!u->id) + return; + + r = bus_manager_foreach_client(u->manager, send_removed_signal, u); + if (r < 0) + log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r)); +} + +int bus_unit_queue_job( + sd_bus *bus, + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + bool reload_if_possible, + sd_bus_error *error) { + + _cleanup_free_ char *path = NULL; + Job *j; + int r; + + assert(bus); + assert(message); + assert(u); + assert(type >= 0 && type < _JOB_TYPE_MAX); + assert(mode >= 0 && mode < _JOB_MODE_MAX); + + if (reload_if_possible && unit_can_reload(u)) { + if (type == JOB_RESTART) + type = JOB_RELOAD_OR_START; + else if (type == JOB_TRY_RESTART) + type = JOB_RELOAD; + } + + r = selinux_unit_access_check( + u, bus, message, + (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" : + type == JOB_STOP ? "stop" : "reload", error); + if (r < 0) + return r; + + if (type == JOB_STOP && + (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && + unit_active_state(u) == UNIT_INACTIVE) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); + + if ((type == JOB_START && u->refuse_manual_start) || + (type == JOB_STOP && u->refuse_manual_stop) || + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) + return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); + + r = manager_add_job(u->manager, type, u, mode, true, error, &j); + if (r < 0) + return r; + + r = bus_client_track(&j->subscribed, bus, sd_bus_message_get_sender(message)); + if (r < 0) + return r; + + path = job_dbus_path(j); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", path); +} + +static int bus_unit_set_transient_property( + Unit *u, + const char *name, + sd_bus_message *message, + UnitSetPropertiesMode mode, + sd_bus_error *error) { + + int r; + + assert(u); + assert(name); + assert(message); + + if (streq(name, "Description")) { + const char *d; + + r = sd_bus_message_read(message, "s", &d); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + r = unit_set_description(u, d); + if (r < 0) + return r; + + unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d); + } + + return 1; + + } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) { + const char *s; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice")) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s); + + if (isempty(s)) { + if (mode != UNIT_CHECK) { + unit_ref_unset(&u->slice); + unit_remove_drop_in(u, mode, name); + } + } else { + Unit *slice; + + r = manager_load_unit(u->manager, s, NULL, error, &slice); + if (r < 0) + return r; + + if (slice->type != UNIT_SLICE) + return -EINVAL; + + if (mode != UNIT_CHECK) { + unit_ref_set(&u->slice, slice); + unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s); + } + } + + return 1; + + } else if (streq(name, "Requires") || + streq(name, "RequiresOverridable") || + streq(name, "Requisite") || + streq(name, "RequisiteOverridable") || + streq(name, "Wants") || + streq(name, "BindsTo") || + streq(name, "Conflicts") || + streq(name, "Before") || + streq(name, "After") || + streq(name, "OnFailure") || + streq(name, "PropagatesReloadTo") || + streq(name, "ReloadPropagatedFrom") || + streq(name, "PartOf")) { + + UnitDependency d; + const char *other; + + d = unit_dependency_from_string(name); + if (d < 0) + return -EINVAL; + + r = sd_bus_message_enter_container(message, 'a', "s"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "s", &other)) > 0) { + if (!unit_name_is_valid(other, TEMPLATE_INVALID)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *label = NULL; + + r = unit_add_dependency_by_name(u, d, other, NULL, true); + if (r < 0) + return r; + + label = strjoin(name, "-", other, NULL); + if (!label) + return -ENOMEM; + + unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other); + } + + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + return 1; + } + + return 0; +} + +int bus_unit_set_properties( + Unit *u, + sd_bus_message *message, + UnitSetPropertiesMode mode, + bool commit, + sd_bus_error *error) { + + bool for_real = false; + unsigned n = 0; + int r; + + assert(u); + assert(message); + + /* We iterate through the array twice. First run we just check + * if all passed data is valid, second run actually applies + * it. This is to implement transaction-like behaviour without + * actually providing full transactions. */ + + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) + return r; + + for (;;) { + const char *name; + + r = sd_bus_message_enter_container(message, 'r', "sv"); + if (r < 0) + return r; + if (r == 0) { + if (for_real || mode == UNIT_CHECK) + break; + + /* Reached EOF. Let's try again, and this time for realz... */ + r = sd_bus_message_rewind(message, false); + if (r < 0) + return r; + + for_real = true; + continue; + } + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + if (!UNIT_VTABLE(u)->bus_set_property) + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); + + r = sd_bus_message_enter_container(message, 'v', NULL); + if (r < 0) + return r; + + r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); + if (r == 0 && u->transient && u->load_state == UNIT_STUB) + r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + n += for_real; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) + UNIT_VTABLE(u)->bus_commit_properties(u); + + return n; +} diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h new file mode 100644 index 0000000..57a5e19 --- /dev/null +++ b/src/core/dbus-unit.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "unit.h" + +extern const sd_bus_vtable bus_unit_vtable[]; +extern const sd_bus_vtable bus_unit_cgroup_vtable[]; + +void bus_unit_send_change_signal(Unit *u); +void bus_unit_send_removed_signal(Unit *u); + +int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error); +int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); + +int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); +int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); +int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/core/dbus.c b/src/core/dbus.c new file mode 100644 index 0000000..1059415 --- /dev/null +++ b/src/core/dbus.c @@ -0,0 +1,1141 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "sd-bus.h" +#include "log.h" +#include "strv.h" +#include "mkdir.h" +#include "missing.h" +#include "dbus-unit.h" +#include "dbus-job.h" +#include "dbus-manager.h" +#include "dbus-execute.h" +#include "dbus-kill.h" +#include "dbus-cgroup.h" +#include "special.h" +#include "dbus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-errors.h" +#include "strxcpyx.h" +#include "dbus-client-track.h" +#include "bus-internal.h" +#include "selinux-access.h" + +#define CONNECTIONS_MAX 512 + +static void destroy_bus(Manager *m, sd_bus **bus); + +int bus_send_queued_message(Manager *m) { + int r; + + assert(m); + + if (!m->queued_message) + return 0; + + assert(m->queued_message_bus); + + /* If we cannot get rid of this message we won't dispatch any + * D-Bus messages, so that we won't end up wanting to queue + * another message. */ + + r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL); + if (r < 0) + log_warning("Failed to send queued message: %s", strerror(-r)); + + m->queued_message = sd_bus_message_unref(m->queued_message); + m->queued_message_bus = sd_bus_unref(m->queued_message_bus); + + return 0; +} + +static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *cgroup; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &cgroup); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + manager_notify_cgroup_empty(m, cgroup); + + if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) { + /* If we are running as system manager, forward the + * message to the system bus */ + + r = sd_bus_send(m->system_bus, message, NULL); + if (r < 0) + log_warning("Failed to forward Released message: %s", strerror(-r)); + } + + return 0; +} + +static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + assert(bus); + assert(message); + assert(m); + + if (bus == m->api_bus) + destroy_bus(m, &m->api_bus); + if (bus == m->system_bus) + destroy_bus(m, &m->system_bus); + if (set_remove(m->private_buses, bus)) { + log_debug("Got disconnect on private connection."); + destroy_bus(m, &bus); + } + + return 0; +} + +static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *name, *old_owner, *new_owner; + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + manager_dispatch_bus_name_owner_changed( + m, name, + isempty(old_owner) ? NULL : old_owner, + isempty(new_owner) ? NULL : new_owner); + + return 0; +} + +static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) || + manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) { + r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down."); + goto failed; + } + + r = manager_load_unit(m, name, NULL, &error, &u); + if (r < 0) + goto failed; + + if (u->refuse_manual_start) { + r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id); + goto failed; + } + + r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto failed; + + /* Successfully queued, that's it for us */ + return 0; + +failed: + if (!sd_bus_error_is_set(&error)) + sd_bus_error_set_errno(&error, r); + + log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r)); + + r = sd_bus_message_new_signal(bus, &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"); + if (r < 0) { + bus_log_create_error(r); + return 0; + } + + r = sd_bus_message_append(reply, "sss", name, error.name, error.message); + if (r < 0) { + bus_log_create_error(r); + return 0; + } + + r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL); + if (r < 0) { + log_error("Failed to respond with to bus activation request: %s", strerror(-r)); + return r; + } + + return 0; +} + +#ifdef HAVE_SELINUX +static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *verb, *path; + Unit *u = NULL; + Job *j; + int r; + + assert(bus); + assert(message); + + /* Our own method calls are all protected individually with + * selinux checks, but the built-in interfaces need to be + * protected too. */ + + if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set")) + verb = "reload"; + else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) || + sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) || + sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) || + sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL)) + verb = "status"; + else + return 0; + + path = sd_bus_message_get_path(message); + + if (object_path_startswith("/org/freedesktop/systemd1", path)) { + + r = selinux_access_check(bus, message, verb, error); + if (r < 0) + return r; + + return 0; + } + + if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + pid_t pid; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return 0; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return 0; + + u = manager_get_unit_by_pid(m, pid); + } else { + r = manager_get_job_from_dbus_path(m, path, &j); + if (r >= 0) + u = j->unit; + else + manager_load_unit_from_dbus_path(m, path, NULL, &u); + } + + if (!u) + return 0; + + r = selinux_unit_access_check(u, bus, message, verb, error); + if (r < 0) + return r; + + return 0; +} +#endif + +static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Job *j; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = manager_get_job_from_dbus_path(m, path, &j); + if (r < 0) + return 0; + + *found = j; + return 1; +} + +static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) { + Unit *u; + int r; + + assert(m); + assert(bus); + assert(path); + + if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_bus_message *message; + pid_t pid; + + message = sd_bus_get_current(bus); + if (!message) + return 0; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + u = manager_get_unit_by_pid(m, pid); + } else { + r = manager_load_unit_from_dbus_path(m, path, error, &u); + if (r < 0) + return 0; + } + + if (!u) + return 0; + + *unit = u; + return 1; +} + +static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + return find_unit(m, bus, path, (Unit**) found, error); +} + +static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Unit *u; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = find_unit(m, bus, path, &u, error); + if (r <= 0) + return r; + + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; + + *found = u; + return 1; +} + +static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Unit *u; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = find_unit(m, bus, path, &u, error); + if (r <= 0) + return r; + + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; + + if (!unit_get_cgroup_context(u)) + return 0; + + *found = u; + return 1; +} + +static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + CGroupContext *c; + Unit *u; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = find_unit(m, bus, path, &u, error); + if (r <= 0) + return r; + + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; + + c = unit_get_cgroup_context(u); + if (!c) + return 0; + + *found = c; + return 1; +} + +static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + ExecContext *c; + Unit *u; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = find_unit(m, bus, path, &u, error); + if (r <= 0) + return r; + + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; + + c = unit_get_exec_context(u); + if (!c) + return 0; + + *found = c; + return 1; +} + +static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + KillContext *c; + Unit *u; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = find_unit(m, bus, path, &u, error); + if (r <= 0) + return r; + + if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + return 0; + + c = unit_get_kill_context(u); + if (!c) + return 0; + + *found = c; + return 1; +} + +static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_free_ char **l = NULL; + Manager *m = userdata; + unsigned k = 0; + Iterator i; + Job *j; + + l = new0(char*, hashmap_size(m->jobs)+1); + if (!l) + return -ENOMEM; + + HASHMAP_FOREACH(j, m->jobs, i) { + l[k] = job_dbus_path(j); + if (!l[k]) + return -ENOMEM; + + k++; + } + + assert(hashmap_size(m->jobs) == k); + + *nodes = l; + l = NULL; + + return k; +} + +static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_free_ char **l = NULL; + Manager *m = userdata; + unsigned k = 0; + Iterator i; + Unit *u; + + l = new0(char*, hashmap_size(m->units)+1); + if (!l) + return -ENOMEM; + + HASHMAP_FOREACH(u, m->units, i) { + l[k] = unit_dbus_path(u); + if (!l[k]) + return -ENOMEM; + + k++; + } + + *nodes = l; + l = NULL; + + return k; +} + +static int bus_setup_api_vtables(Manager *m, sd_bus *bus) { + UnitType t; + int r; + + assert(m); + assert(bus); + +#ifdef HAVE_SELINUX + r = sd_bus_add_filter(bus, selinux_filter, m); + if (r < 0) { + log_error("Failed to add SELinux access filter: %s", strerror(-r)); + return r; + } +#endif + + r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m); + if (r < 0) { + log_error("Failed to register Manager vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m); + if (r < 0) { + log_error("Failed to register Job vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m); + if (r < 0) { + log_error("Failed to add job enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m); + if (r < 0) { + log_error("Failed to register Unit vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m); + if (r < 0) { + log_error("Failed to add job enumerator: %s", strerror(-r)); + return r; + } + + for (t = 0; t < _UNIT_TYPE_MAX; t++) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m); + if (r < 0) { + log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + + if (unit_vtable[t]->cgroup_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m); + if (r < 0) { + log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m); + if (r < 0) { + log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + } + + if (unit_vtable[t]->exec_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m); + if (r < 0) { + log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + } + + if (unit_vtable[t]->kill_context_offset > 0) { + r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m); + if (r < 0) { + log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r)); + return r; + } + } + } + + return 0; +} + +static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) { + int r; + + assert(m); + assert(bus); + + r = sd_bus_add_match( + bus, + "sender='org.freedesktop.DBus.Local'," + "type='signal'," + "path='/org/freedesktop/DBus/Local'," + "interface='org.freedesktop.DBus.Local'," + "member='Disconnected'", + signal_disconnected, m); + + if (r < 0) { + log_error("Failed to register match for Disconnected message: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_close_ int nfd = -1; + Manager *m = userdata; + sd_id128_t id; + int r; + + assert(s); + assert(m); + + nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (nfd < 0) { + log_warning("Failed to accept private connection, ignoring: %m"); + return 0; + } + + if (set_size(m->private_buses) >= CONNECTIONS_MAX) { + log_warning("Too many concurrent connections, refusing"); + return 0; + } + + r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func); + if (r < 0) { + log_oom(); + return 0; + } + + r = sd_bus_new(&bus); + if (r < 0) { + log_warning("Failed to allocate new private connection bus: %s", strerror(-r)); + return 0; + } + + r = sd_bus_set_fd(bus, nfd, nfd); + if (r < 0) { + log_warning("Failed to set fd on new connection bus: %s", strerror(-r)); + return 0; + } + + nfd = -1; + + r = bus_check_peercred(bus); + if (r < 0) { + log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r)); + return 0; + } + + assert_se(sd_id128_randomize(&id) >= 0); + + r = sd_bus_set_server(bus, 1, id); + if (r < 0) { + log_warning("Failed to enable server support for new connection bus: %s", strerror(-r)); + return 0; + } + + r = sd_bus_start(bus); + if (r < 0) { + log_warning("Failed to start new connection bus: %s", strerror(-r)); + return 0; + } + + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r)); + return 0; + } + + if (m->running_as == SYSTEMD_SYSTEM) { + /* When we run as system instance we get the Released + * signal via a direct connection */ + + r = sd_bus_add_match( + bus, + "type='signal'," + "interface='org.freedesktop.systemd1.Agent'," + "member='Released'," + "path='/org/freedesktop/systemd1/agent'", + signal_agent_released, m); + + if (r < 0) { + log_warning("Failed to register Released match on new connection bus: %s", strerror(-r)); + return 0; + } + } + + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; + + r = bus_setup_api_vtables(m, bus); + if (r < 0) { + log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r)); + return 0; + } + + r = set_put(m->private_buses, bus); + if (r < 0) { + log_warning("Failed to add new conenction bus to set: %s", strerror(-r)); + return 0; + } + + bus = NULL; + + log_debug("Accepted new private connection."); + + return 0; +} + +static int bus_list_names(Manager *m, sd_bus *bus) { + _cleanup_strv_free_ char **names = NULL; + char **i; + int r; + + assert(m); + assert(bus); + + r = sd_bus_list_names(bus, &names, NULL); + if (r < 0) { + log_error("Failed to get initial list of names: %s", strerror(-r)); + return r; + } + + /* This is a bit hacky, we say the owner of the name is the + * name itself, because we don't want the extra traffic to + * figure out the real owner. */ + STRV_FOREACH(i, names) + manager_dispatch_bus_name_owner_changed(m, *i, NULL, *i); + + return 0; +} + +static int bus_setup_api(Manager *m, sd_bus *bus) { + int r; + + assert(m); + assert(bus); + + r = bus_setup_api_vtables(m, bus); + if (r < 0) + return r; + + r = sd_bus_add_match( + bus, + "type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'", + signal_name_owner_changed, m); + if (r < 0) + log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r)); + + r = sd_bus_add_match( + bus, + "type='signal'," + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.systemd1.Activator'," + "member='ActivationRequest'", + signal_activation_request, m); + if (r < 0) + log_warning("Failed to subscribe to activation signal: %s", strerror(-r)); + + /* Allow replacing of our name, to ease implementation of + * reexecution, where we keep the old connection open until + * after the new connection is set up and the name installed + * to allow clients to synchronously wait for reexecution to + * finish */ + r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + bus_list_names(m, bus); + + log_debug("Successfully connected to API bus."); + return 0; +} + +static int bus_init_api(Manager *m) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + if (m->api_bus) + return 0; + + /* The API and system bus is the same if we are running in system mode */ + if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) + bus = sd_bus_ref(m->system_bus); + else { + if (m->running_as == SYSTEMD_SYSTEM) + r = sd_bus_open_system(&bus); + else + r = sd_bus_open_user(&bus); + + if (r < 0) { + log_debug("Failed to connect to API bus, retrying later..."); + return 0; + } + + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_error("Failed to attach API bus to event loop: %s", strerror(-r)); + return 0; + } + + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; + } + + r = bus_setup_api(m, bus); + if (r < 0) { + log_error("Failed to set up API bus: %s", strerror(-r)); + return 0; + } + + m->api_bus = bus; + bus = NULL; + + return 0; +} + +static int bus_setup_system(Manager *m, sd_bus *bus) { + int r; + + assert(m); + assert(bus); + + if (m->running_as == SYSTEMD_SYSTEM) + return 0; + + /* If we are a user instance we get the Released message via + * the system bus */ + r = sd_bus_add_match( + bus, + "type='signal'," + "interface='org.freedesktop.systemd1.Agent'," + "member='Released'," + "path='/org/freedesktop/systemd1/agent'", + signal_agent_released, m); + + if (r < 0) + log_warning("Failed to register Released match on system bus: %s", strerror(-r)); + + log_debug("Successfully connected to system bus."); + return 0; +} + +static int bus_init_system(Manager *m) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + if (m->system_bus) + return 0; + + /* The API and system bus is the same if we are running in system mode */ + if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) { + m->system_bus = sd_bus_ref(m->api_bus); + return 0; + } + + r = sd_bus_open_system(&bus); + if (r < 0) { + log_debug("Failed to connect to system bus, retrying later..."); + return 0; + } + + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; + + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + log_error("Failed to attach system bus to event loop: %s", strerror(-r)); + return 0; + } + + r = bus_setup_system(m, bus); + if (r < 0) { + log_error("Fauiled to set up system bus: %s", strerror(-r)); + return 0; + } + + m->system_bus = bus; + bus = NULL; + + return 0; +} + +static int bus_init_private(Manager *m) { + _cleanup_close_ int fd = -1; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX + }; + sd_event_source *s; + socklen_t salen; + int r; + + assert(m); + + if (m->private_listen_fd >= 0) + return 0; + + /* We don't need the private socket if we have kdbus */ + if (m->kdbus_fd >= 0) + return 0; + + if (m->running_as == SYSTEMD_SYSTEM) { + + /* We want the private bus only when running as init */ + if (getpid() != 1) + return 0; + + strcpy(sa.un.sun_path, "/run/systemd/private"); + salen = offsetof(union sockaddr_union, un.sun_path) + sizeof("/run/systemd/private") - 1; + } else { + size_t left = sizeof(sa.un.sun_path); + char *p = sa.un.sun_path; + const char *e; + + e = secure_getenv("XDG_RUNTIME_DIR"); + if (!e) { + log_error("Failed to determine XDG_RUNTIME_DIR"); + return -EHOSTDOWN; + } + + left = strpcpy(&p, left, e); + left = strpcpy(&p, left, "/systemd/private"); + + salen = sizeof(sa.un) - left; + + mkdir_parents_label(sa.un.sun_path, 0755); + } + + unlink(sa.un.sun_path); + + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) { + log_error("Failed to allocate private socket: %m"); + return -errno; + } + + r = bind(fd, &sa.sa, salen); + if (r < 0) { + log_error("Failed to bind private socket: %m"); + return -errno; + } + + r = listen(fd, SOMAXCONN); + if (r < 0) { + log_error("Failed to make private socket listening: %m"); + return -errno; + } + + r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m); + if (r < 0) { + log_error("Failed to allocate event source: %s", strerror(-r)); + return r; + } + + m->private_listen_fd = fd; + m->private_listen_event_source = s; + fd = -1; + + log_debug("Successfully created private D-Bus server."); + + return 0; +} + +int bus_init(Manager *m, bool try_bus_connect) { + int r; + + if (try_bus_connect) { + r = bus_init_system(m); + if (r < 0) + return r; + + r = bus_init_api(m); + if (r < 0) + return r; + } + + r = bus_init_private(m); + if (r < 0) + return r; + + return 0; +} + +static void destroy_bus(Manager *m, sd_bus **bus) { + Iterator i; + Job *j; + + assert(m); + assert(bus); + + if (!*bus) + return; + + /* Get rid of tracked clients on this bus */ + bus_client_untrack_bus(m->subscribed, *bus); + HASHMAP_FOREACH(j, m->jobs, i) + bus_client_untrack_bus(j->subscribed, *bus); + + /* Get rid of queued message on this bus */ + if (m->queued_message_bus == *bus) { + m->queued_message_bus = sd_bus_unref(m->queued_message_bus); + + if (m->queued_message) + m->queued_message = sd_bus_message_unref(m->queued_message); + } + + /* Possibly flush unwritten data, but only if we are + * unprivileged, since we don't want to sync here */ + if (m->running_as != SYSTEMD_SYSTEM) + sd_bus_flush(*bus); + + /* And destroy the object */ + sd_bus_close(*bus); + *bus = sd_bus_unref(*bus); +} + +void bus_done(Manager *m) { + sd_bus *b; + + assert(m); + + if (m->api_bus) + destroy_bus(m, &m->api_bus); + if (m->system_bus) + destroy_bus(m, &m->system_bus); + while ((b = set_steal_first(m->private_buses))) + destroy_bus(m, &b); + + set_free(m->private_buses); + set_free(m->subscribed); + + if (m->private_listen_event_source) + m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source); + + if (m->private_listen_fd >= 0) { + close_nointr_nofail(m->private_listen_fd); + m->private_listen_fd = -1; + } +} + +int bus_fdset_add_all(Manager *m, FDSet *fds) { + Iterator i; + sd_bus *b; + int fd; + + assert(m); + assert(fds); + + /* When we are about to reexecute we add all D-Bus fds to the + * set to pass over to the newly executed systemd. They won't + * be used there however, except thatt they are closed at the + * very end of deserialization, those making it possible for + * clients to synchronously wait for systemd to reexec by + * simply waiting for disconnection */ + + if (m->api_bus) { + fd = sd_bus_get_fd(m->api_bus); + if (fd >= 0) { + fd = fdset_put_dup(fds, fd); + if (fd < 0) + return fd; + } + } + + SET_FOREACH(b, m->private_buses, i) { + fd = sd_bus_get_fd(b); + if (fd >= 0) { + fd = fdset_put_dup(fds, fd); + if (fd < 0) + return fd; + } + } + + /* We don't offer any APIs on the system bus (well, unless it + * is the same as the API bus) hence we don't bother with it + * here */ + + return 0; +} + +void bus_serialize(Manager *m, FILE *f) { + assert(m); + assert(f); + + bus_client_track_serialize(m, f, m->subscribed); +} + +int bus_deserialize_item(Manager *m, const char *line) { + assert(m); + assert(line); + + return bus_client_track_deserialize_item(m, &m->subscribed, line); +} diff --git a/src/core/dbus.h b/src/core/dbus.h new file mode 100644 index 0000000..a3bef47 --- /dev/null +++ b/src/core/dbus.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "manager.h" + +int bus_send_queued_message(Manager *m); + +int bus_init(Manager *m, bool try_bus_connect); +void bus_done(Manager *m); + +int bus_fdset_add_all(Manager *m, FDSet *fds); + +void bus_serialize(Manager *m, FILE *f); +int bus_deserialize_item(Manager *m, const char *line); diff --git a/src/core/device.c b/src/core/device.c new file mode 100644 index 0000000..d17b2df --- /dev/null +++ b/src/core/device.c @@ -0,0 +1,673 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "strv.h" +#include "log.h" +#include "unit-name.h" +#include "dbus-device.h" +#include "def.h" +#include "path-util.h" +#include "udev-util.h" +#include "unit.h" +#include "swap.h" +#include "device.h" + +static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = UNIT_INACTIVE, + [DEVICE_PLUGGED] = UNIT_ACTIVE +}; + +static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +static void device_unset_sysfs(Device *d) { + Hashmap *devices; + Device *first; + + assert(d); + + if (!d->sysfs) + return; + + /* Remove this unit from the chain of devices which share the + * same sysfs path. */ + devices = UNIT(d)->manager->devices_by_sysfs; + first = hashmap_get(devices, d->sysfs); + LIST_REMOVE(same_sysfs, first, d); + + if (first) + hashmap_remove_and_replace(devices, d->sysfs, first->sysfs, first); + else + hashmap_remove(devices, d->sysfs); + + free(d->sysfs); + d->sysfs = NULL; +} + +static void device_init(Unit *u) { + Device *d = DEVICE(u); + + assert(d); + assert(UNIT(d)->load_state == UNIT_STUB); + + /* In contrast to all other unit types we timeout jobs waiting + * for devices by default. This is because they otherwise wait + * indefinitely for plugged in devices, something which cannot + * happen for the other units since their operations time out + * anyway. */ + u->job_timeout = u->manager->default_timeout_start_usec; + + u->ignore_on_isolate = true; + u->ignore_on_snapshot = true; +} + +static void device_done(Unit *u) { + Device *d = DEVICE(u); + + assert(d); + + device_unset_sysfs(d); +} + +static void device_set_state(Device *d, DeviceState state) { + DeviceState old_state; + assert(d); + + old_state = d->state; + d->state = state; + + if (state != old_state) + log_debug_unit(UNIT(d)->id, + "%s changed %s -> %s", UNIT(d)->id, + device_state_to_string(old_state), + device_state_to_string(state)); + + unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true); +} + +static int device_coldplug(Unit *u) { + Device *d = DEVICE(u); + + assert(d); + assert(d->state == DEVICE_DEAD); + + if (d->sysfs) + device_set_state(d, DEVICE_PLUGGED); + + return 0; +} + +static void device_dump(Unit *u, FILE *f, const char *prefix) { + Device *d = DEVICE(u); + + assert(d); + + fprintf(f, + "%sDevice State: %s\n" + "%sSysfs Path: %s\n", + prefix, device_state_to_string(d->state), + prefix, strna(d->sysfs)); +} + +_pure_ static UnitActiveState device_active_state(Unit *u) { + assert(u); + + return state_translation_table[DEVICE(u)->state]; +} + +_pure_ static const char *device_sub_state_to_string(Unit *u) { + assert(u); + + return device_state_to_string(DEVICE(u)->state); +} + +static int device_add_escaped_name(Unit *u, const char *dn) { + _cleanup_free_ char *e = NULL; + int r; + + assert(u); + assert(dn); + assert(dn[0] == '/'); + + e = unit_name_from_path(dn, ".device"); + if (!e) + return -ENOMEM; + + r = unit_add_name(u, e); + if (r < 0 && r != -EEXIST) + return r; + + return 0; +} + +static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { + _cleanup_free_ char *e = NULL; + Unit *u; + + assert(m); + assert(dn); + assert(dn[0] == '/'); + assert(_u); + + e = unit_name_from_path(dn, ".device"); + if (!e) + return -ENOMEM; + + u = manager_get_unit(m, e); + if (u) { + *_u = u; + return 1; + } + + return 0; +} + +static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { + const char *sysfs, *model; + Unit *u = NULL; + int r; + bool delete; + + assert(m); + + sysfs = udev_device_get_syspath(dev); + if (!sysfs) + return 0; + + r = device_find_escape_name(m, path, &u); + if (r < 0) + return r; + + if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs)) + return -EEXIST; + + if (!u) { + delete = true; + + u = unit_new(m, sizeof(Device)); + if (!u) + return log_oom(); + + r = device_add_escaped_name(u, path); + if (r < 0) + goto fail; + + unit_add_to_load_queue(u); + } else + delete = false; + + /* If this was created via some dependency and has not + * actually been seen yet ->sysfs will not be + * initialized. Hence initialize it if necessary. */ + + if (!DEVICE(u)->sysfs) { + Device *first; + + DEVICE(u)->sysfs = strdup(sysfs); + if (!DEVICE(u)->sysfs) { + r = -ENOMEM; + goto fail; + } + + r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func); + if (r < 0) + goto fail; + + first = hashmap_get(m->devices_by_sysfs, sysfs); + LIST_PREPEND(same_sysfs, first, DEVICE(u)); + + r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first); + if (r < 0) + goto fail; + } + + if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || + (model = udev_device_get_property_value(dev, "ID_MODEL"))) + r = unit_set_description(u, model); + else + r = unit_set_description(u, path); + if (r < 0) + goto fail; + + if (main) { + const char *wants; + + /* The additional systemd udev properties we only + * interpret for the main object */ + + wants = udev_device_get_property_value(dev, m->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS"); + if (wants) { + char *state, *w; + size_t l; + + FOREACH_WORD_QUOTED(w, l, wants, state) { + _cleanup_free_ char *n = NULL; + char e[l+1]; + + memcpy(e, w, l); + e[l] = 0; + + n = unit_name_mangle(e, MANGLE_NOGLOB); + if (!n) { + r = -ENOMEM; + goto fail; + } + + r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true); + if (r < 0) + goto fail; + } + } + } + + /* Note that this won't dispatch the load queue, the caller + * has to do that if needed and appropriate */ + + unit_add_to_dbus_queue(u); + return 0; + +fail: + log_warning("Failed to load device unit: %s", strerror(-r)); + + if (delete && u) + unit_free(u); + + return r; +} + +static int device_process_new_device(Manager *m, struct udev_device *dev) { + const char *sysfs, *dn, *alias; + struct udev_list_entry *item = NULL, *first = NULL; + int r; + + assert(m); + + sysfs = udev_device_get_syspath(dev); + if (!sysfs) + return 0; + + /* Add the main unit named after the sysfs path */ + r = device_update_unit(m, dev, sysfs, true); + if (r < 0) + return r; + + /* Add an additional unit for the device node */ + dn = udev_device_get_devnode(dev); + if (dn) + device_update_unit(m, dev, dn, false); + + /* Add additional units for all symlinks */ + first = udev_device_get_devlinks_list_entry(dev); + udev_list_entry_foreach(item, first) { + const char *p; + struct stat st; + + /* Don't bother with the /dev/block links */ + p = udev_list_entry_get_name(item); + + if (path_startswith(p, "/dev/block/") || + path_startswith(p, "/dev/char/")) + continue; + + /* Verify that the symlink in the FS actually belongs + * to this device. This is useful to deal with + * conflicting devices, e.g. when two disks want the + * same /dev/disk/by-label/xxx link because they have + * the same label. We want to make sure that the same + * device that won the symlink wins in systemd, so we + * check the device node major/minor*/ + if (stat(p, &st) >= 0) + if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) || + st.st_rdev != udev_device_get_devnum(dev)) + continue; + + device_update_unit(m, dev, p, false); + } + + /* Add additional units for all explicitly configured + * aliases */ + alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS"); + if (alias) { + char *state, *w; + size_t l; + + FOREACH_WORD_QUOTED(w, l, alias, state) { + char e[l+1]; + + memcpy(e, w, l); + e[l] = 0; + + if (path_is_absolute(e)) + device_update_unit(m, dev, e, false); + else + log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e); + } + } + + return 0; +} + +static void device_set_path_plugged(Manager *m, struct udev_device *dev) { + const char *sysfs; + Device *d, *l; + + assert(m); + assert(dev); + + sysfs = udev_device_get_syspath(dev); + if (!sysfs) + return; + + l = hashmap_get(m->devices_by_sysfs, sysfs); + LIST_FOREACH(same_sysfs, d, l) + device_set_state(d, DEVICE_PLUGGED); +} + +static int device_process_removed_device(Manager *m, struct udev_device *dev) { + const char *sysfs; + Device *d; + + assert(m); + assert(dev); + + sysfs = udev_device_get_syspath(dev); + if (!sysfs) + return -ENOMEM; + + /* Remove all units of this sysfs path */ + while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) { + device_unset_sysfs(d); + device_set_state(d, DEVICE_DEAD); + } + + return 0; +} + +static bool device_is_ready(struct udev_device *dev) { + const char *ready; + + assert(dev); + + ready = udev_device_get_property_value(dev, "SYSTEMD_READY"); + if (!ready) + return true; + + return parse_boolean(ready) != 0; +} + +static int device_process_new_path(Manager *m, const char *path) { + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; + + assert(m); + assert(path); + + dev = udev_device_new_from_syspath(m->udev, path); + if (!dev) + return log_oom(); + + if (!device_is_ready(dev)) + return 0; + + return device_process_new_device(m, dev); +} + +static Unit *device_following(Unit *u) { + Device *d = DEVICE(u); + Device *other, *first = NULL; + + assert(d); + + if (startswith(u->id, "sys-")) + return NULL; + + /* Make everybody follow the unit that's named after the sysfs path */ + for (other = d->same_sysfs_next; other; other = other->same_sysfs_next) + if (startswith(UNIT(other)->id, "sys-")) + return UNIT(other); + + for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) { + if (startswith(UNIT(other)->id, "sys-")) + return UNIT(other); + + first = other; + } + + return UNIT(first); +} + +static int device_following_set(Unit *u, Set **_set) { + Device *d = DEVICE(u), *other; + Set *set; + int r; + + assert(d); + assert(_set); + + if (LIST_JUST_US(same_sysfs, d)) { + *_set = NULL; + return 0; + } + + set = set_new(NULL, NULL); + if (!set) + return -ENOMEM; + + LIST_FOREACH_AFTER(same_sysfs, other, d) { + r = set_put(set, other); + if (r < 0) + goto fail; + } + + LIST_FOREACH_BEFORE(same_sysfs, other, d) { + r = set_put(set, other); + if (r < 0) + goto fail; + } + + *_set = set; + return 1; + +fail: + set_free(set); + return r; +} + +static void device_shutdown(Manager *m) { + assert(m); + + m->udev_event_source = sd_event_source_unref(m->udev_event_source); + + if (m->udev_monitor) { + udev_monitor_unref(m->udev_monitor); + m->udev_monitor = NULL; + } + + hashmap_free(m->devices_by_sysfs); + m->devices_by_sysfs = NULL; +} + +static int device_enumerate(Manager *m) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + int r; + + assert(m); + + if (!m->udev_monitor) { + m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_monitor) { + r = -ENOMEM; + goto fail; + } + + /* This will fail if we are unprivileged, but that + * should not matter much, as user instances won't run + * during boot. */ + udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024); + + r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd"); + if (r < 0) + goto fail; + + r = udev_monitor_enable_receiving(m->udev_monitor); + if (r < 0) + goto fail; + + r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m); + if (r < 0) + goto fail; + } + + e = udev_enumerate_new(m->udev); + if (!e) { + r = -ENOMEM; + goto fail; + } + + r = udev_enumerate_add_match_tag(e, "systemd"); + if (r < 0) + goto fail; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + goto fail; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + goto fail; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) + device_process_new_path(m, udev_list_entry_get_name(item)); + + return 0; + +fail: + device_shutdown(m); + return r; +} + +static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; + Manager *m = userdata; + const char *action; + int r; + + assert(m); + + if (revents != EPOLLIN) { + static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5); + + if (!ratelimit_test(&limit)) + log_error("Failed to get udev event: %m"); + if (!(revents & EPOLLIN)) + return 0; + } + + /* + * libudev might filter-out devices which pass the bloom + * filter, so getting NULL here is not necessarily an error. + */ + dev = udev_monitor_receive_device(m->udev_monitor); + if (!dev) + return 0; + + action = udev_device_get_action(dev); + if (!action) { + log_error("Failed to get udev action string."); + return 0; + } + + if (streq(action, "remove") || !device_is_ready(dev)) { + r = device_process_removed_device(m, dev); + if (r < 0) + log_error("Failed to process device remove event: %s", strerror(-r)); + + r = swap_process_removed_device(m, dev); + if (r < 0) + log_error("Failed to process swap device remove event: %s", strerror(-r)); + + } else { + r = device_process_new_device(m, dev); + if (r < 0) + log_error("Failed to process device new event: %s", strerror(-r)); + + r = swap_process_new_device(m, dev); + if (r < 0) + log_error("Failed to process swap device new event: %s", strerror(-r)); + + manager_dispatch_load_queue(m); + + device_set_path_plugged(m, dev); + } + + return 0; +} + +static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_PLUGGED] = "plugged" +}; + +DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); + +const UnitVTable device_vtable = { + .object_size = sizeof(Device), + .sections = + "Unit\0" + "Device\0" + "Install\0", + + .no_instances = true, + + .init = device_init, + .done = device_done, + .load = unit_load_fragment_and_dropin_optional, + + .coldplug = device_coldplug, + + .dump = device_dump, + + .active_state = device_active_state, + .sub_state_to_string = device_sub_state_to_string, + + .bus_interface = "org.freedesktop.systemd1.Device", + .bus_vtable = bus_device_vtable, + + .following = device_following, + .following_set = device_following_set, + + .enumerate = device_enumerate, + .shutdown = device_shutdown, + + .status_message_formats = { + .starting_stopping = { + [0] = "Expecting device %s...", + }, + .finished_start_job = { + [JOB_DONE] = "Found device %s.", + [JOB_TIMEOUT] = "Timed out waiting for device %s.", + }, + }, +}; diff --git a/src/core/device.h b/src/core/device.h new file mode 100644 index 0000000..bb7ae07 --- /dev/null +++ b/src/core/device.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Device Device; + +#include "unit.h" + +/* We simply watch devices, we cannot plug/unplug them. That + * simplifies the state engine greatly */ +typedef enum DeviceState { + DEVICE_DEAD, + DEVICE_PLUGGED, + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 +} DeviceState; + +struct Device { + Unit meta; + + char *sysfs; + + /* In order to be able to distinguish dependencies on + different device nodes we might end up creating multiple + devices for the same sysfs path. We chain them up here. */ + + LIST_FIELDS(struct Device, same_sysfs); + + DeviceState state; +}; + +extern const UnitVTable device_vtable; + +const char* device_state_to_string(DeviceState i) _const_; +DeviceState device_state_from_string(const char *s) _pure_; diff --git a/src/core/execute.c b/src/core/execute.c new file mode 100644 index 0000000..a328fc2 --- /dev/null +++ b/src/core/execute.c @@ -0,0 +1,2627 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef basename + +#ifdef HAVE_PAM +#include +#endif + +#ifdef HAVE_SELINUX +#include +#endif + +#ifdef HAVE_SECCOMP +#include +#endif + +#ifdef HAVE_APPARMOR +#include +#endif + +#include "execute.h" +#include "strv.h" +#include "macro.h" +#include "capability.h" +#include "util.h" +#include "log.h" +#include "sd-messages.h" +#include "ioprio.h" +#include "securebits.h" +#include "namespace.h" +#include "tcpwrap.h" +#include "exit-status.h" +#include "missing.h" +#include "utmp-wtmp.h" +#include "def.h" +#include "path-util.h" +#include "env-util.h" +#include "fileio.h" +#include "unit.h" +#include "async.h" +#include "selinux-util.h" +#include "errno-list.h" +#include "apparmor-util.h" + +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif + +#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) +#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC) + +/* This assumes there is a 'tty' group */ +#define TTY_MODE 0620 + +#define SNDBUF_SIZE (8*1024*1024) + +static int shift_fds(int fds[], unsigned n_fds) { + int start, restart_from; + + if (n_fds <= 0) + return 0; + + /* Modifies the fds array! (sorts it) */ + + assert(fds); + + start = 0; + for (;;) { + int i; + + restart_from = -1; + + for (i = start; i < (int) n_fds; i++) { + int nfd; + + /* Already at right index? */ + if (fds[i] == i+3) + continue; + + if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0) + return -errno; + + close_nointr_nofail(fds[i]); + fds[i] = nfd; + + /* Hmm, the fd we wanted isn't free? Then + * let's remember that and try again from here*/ + if (nfd != i+3 && restart_from < 0) + restart_from = i; + } + + if (restart_from < 0) + break; + + start = restart_from; + } + + return 0; +} + +static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) { + unsigned i; + int r; + + if (n_fds <= 0) + return 0; + + assert(fds); + + /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */ + + for (i = 0; i < n_fds; i++) { + + if ((r = fd_nonblock(fds[i], nonblock)) < 0) + return r; + + /* We unconditionally drop FD_CLOEXEC from the fds, + * since after all we want to pass these fds to our + * children */ + + if ((r = fd_cloexec(fds[i], false)) < 0) + return r; + } + + return 0; +} + +_pure_ static const char *tty_path(const ExecContext *context) { + assert(context); + + if (context->tty_path) + return context->tty_path; + + return "/dev/console"; +} + +static void exec_context_tty_reset(const ExecContext *context) { + assert(context); + + if (context->tty_vhangup) + terminal_vhangup(tty_path(context)); + + if (context->tty_reset) + reset_terminal(tty_path(context)); + + if (context->tty_vt_disallocate && context->tty_path) + vt_disallocate(context->tty_path); +} + +static bool is_terminal_output(ExecOutput o) { + return + o == EXEC_OUTPUT_TTY || + o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || + o == EXEC_OUTPUT_KMSG_AND_CONSOLE || + o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE; +} + +static int open_null_as(int flags, int nfd) { + int fd, r; + + assert(nfd >= 0); + + fd = open("/dev/null", flags|O_NOCTTY); + if (fd < 0) + return -errno; + + if (fd != nfd) { + r = dup2(fd, nfd) < 0 ? -errno : nfd; + close_nointr_nofail(fd); + } else + r = nfd; + + return r; +} + +static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) { + int fd, r; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/stdout", + }; + + assert(context); + assert(output < _EXEC_OUTPUT_MAX); + assert(ident); + assert(nfd >= 0); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return -errno; + + r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (shutdown(fd, SHUT_RD) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + fd_inc_sndbuf(fd, SNDBUF_SIZE); + + dprintf(fd, + "%s\n" + "%s\n" + "%i\n" + "%i\n" + "%i\n" + "%i\n" + "%i\n", + context->syslog_identifier ? context->syslog_identifier : ident, + unit_id, + context->syslog_priority, + !!context->syslog_level_prefix, + output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE, + output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE, + is_terminal_output(output)); + + if (fd != nfd) { + r = dup2(fd, nfd) < 0 ? -errno : nfd; + close_nointr_nofail(fd); + } else + r = nfd; + + return r; +} +static int open_terminal_as(const char *path, mode_t mode, int nfd) { + int fd, r; + + assert(path); + assert(nfd >= 0); + + if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0) + return fd; + + if (fd != nfd) { + r = dup2(fd, nfd) < 0 ? -errno : nfd; + close_nointr_nofail(fd); + } else + r = nfd; + + return r; +} + +static bool is_terminal_input(ExecInput i) { + return + i == EXEC_INPUT_TTY || + i == EXEC_INPUT_TTY_FORCE || + i == EXEC_INPUT_TTY_FAIL; +} + +static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) { + + if (is_terminal_input(std_input) && !apply_tty_stdin) + return EXEC_INPUT_NULL; + + if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0) + return EXEC_INPUT_NULL; + + return std_input; +} + +static int fixup_output(ExecOutput std_output, int socket_fd) { + + if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0) + return EXEC_OUTPUT_INHERIT; + + return std_output; +} + +static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) { + ExecInput i; + + assert(context); + + i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + + switch (i) { + + case EXEC_INPUT_NULL: + return open_null_as(O_RDONLY, STDIN_FILENO); + + case EXEC_INPUT_TTY: + case EXEC_INPUT_TTY_FORCE: + case EXEC_INPUT_TTY_FAIL: { + int fd, r; + + fd = acquire_terminal(tty_path(context), + i == EXEC_INPUT_TTY_FAIL, + i == EXEC_INPUT_TTY_FORCE, + false, + (usec_t) -1); + if (fd < 0) + return fd; + + if (fd != STDIN_FILENO) { + r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO; + close_nointr_nofail(fd); + } else + r = STDIN_FILENO; + + return r; + } + + case EXEC_INPUT_SOCKET: + return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO; + + default: + assert_not_reached("Unknown input type"); + } +} + +static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) { + ExecOutput o; + ExecInput i; + int r; + + assert(context); + assert(ident); + + i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + o = fixup_output(context->std_output, socket_fd); + + if (fileno == STDERR_FILENO) { + ExecOutput e; + e = fixup_output(context->std_error, socket_fd); + + /* This expects the input and output are already set up */ + + /* Don't change the stderr file descriptor if we inherit all + * the way and are not on a tty */ + if (e == EXEC_OUTPUT_INHERIT && + o == EXEC_OUTPUT_INHERIT && + i == EXEC_INPUT_NULL && + !is_terminal_input(context->std_input) && + getppid () != 1) + return fileno; + + /* Duplicate from stdout if possible */ + if (e == o || e == EXEC_OUTPUT_INHERIT) + return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno; + + o = e; + + } else if (o == EXEC_OUTPUT_INHERIT) { + /* If input got downgraded, inherit the original value */ + if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) + return open_terminal_as(tty_path(context), O_WRONLY, fileno); + + /* If the input is connected to anything that's not a /dev/null, inherit that... */ + if (i != EXEC_INPUT_NULL) + return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno; + + /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ + if (getppid() != 1) + return fileno; + + /* We need to open /dev/null here anew, to get the right access mode. */ + return open_null_as(O_WRONLY, fileno); + } + + switch (o) { + + case EXEC_OUTPUT_NULL: + return open_null_as(O_WRONLY, fileno); + + case EXEC_OUTPUT_TTY: + if (is_terminal_input(i)) + return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno; + + /* We don't reset the terminal if this is just about output */ + return open_terminal_as(tty_path(context), O_WRONLY, fileno); + + case EXEC_OUTPUT_SYSLOG: + case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: + case EXEC_OUTPUT_KMSG: + case EXEC_OUTPUT_KMSG_AND_CONSOLE: + case EXEC_OUTPUT_JOURNAL: + case EXEC_OUTPUT_JOURNAL_AND_CONSOLE: + r = connect_logger_as(context, o, ident, unit_id, fileno); + if (r < 0) { + log_struct_unit(LOG_CRIT, unit_id, + "MESSAGE=Failed to connect std%s of %s to the journal socket: %s", + fileno == STDOUT_FILENO ? "out" : "err", + unit_id, strerror(-r), + "ERRNO=%d", -r, + NULL); + r = open_null_as(O_WRONLY, fileno); + } + return r; + + case EXEC_OUTPUT_SOCKET: + assert(socket_fd >= 0); + return dup2(socket_fd, fileno) < 0 ? -errno : fileno; + + default: + assert_not_reached("Unknown error type"); + } +} + +static int chown_terminal(int fd, uid_t uid) { + struct stat st; + + assert(fd >= 0); + + /* This might fail. What matters are the results. */ + (void) fchown(fd, uid, -1); + (void) fchmod(fd, TTY_MODE); + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE) + return -EPERM; + + return 0; +} + +static int setup_confirm_stdio(int *_saved_stdin, + int *_saved_stdout) { + int fd = -1, saved_stdin, saved_stdout = -1, r; + + assert(_saved_stdin); + assert(_saved_stdout); + + saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3); + if (saved_stdin < 0) + return -errno; + + saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3); + if (saved_stdout < 0) { + r = errno; + goto fail; + } + + fd = acquire_terminal( + "/dev/console", + false, + false, + false, + DEFAULT_CONFIRM_USEC); + if (fd < 0) { + r = fd; + goto fail; + } + + r = chown_terminal(fd, getuid()); + if (r < 0) + goto fail; + + if (dup2(fd, STDIN_FILENO) < 0) { + r = -errno; + goto fail; + } + + if (dup2(fd, STDOUT_FILENO) < 0) { + r = -errno; + goto fail; + } + + if (fd >= 2) + close_nointr_nofail(fd); + + *_saved_stdin = saved_stdin; + *_saved_stdout = saved_stdout; + + return 0; + +fail: + if (saved_stdout >= 0) + close_nointr_nofail(saved_stdout); + + if (saved_stdin >= 0) + close_nointr_nofail(saved_stdin); + + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +_printf_(1, 2) static int write_confirm_message(const char *format, ...) { + int fd; + va_list ap; + + assert(format); + + fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + va_start(ap, format); + vdprintf(fd, format, ap); + va_end(ap); + + close_nointr_nofail(fd); + + return 0; +} + +static int restore_confirm_stdio(int *saved_stdin, + int *saved_stdout) { + + int r = 0; + + assert(saved_stdin); + assert(saved_stdout); + + release_terminal(); + + if (*saved_stdin >= 0) + if (dup2(*saved_stdin, STDIN_FILENO) < 0) + r = -errno; + + if (*saved_stdout >= 0) + if (dup2(*saved_stdout, STDOUT_FILENO) < 0) + r = -errno; + + if (*saved_stdin >= 0) + close_nointr_nofail(*saved_stdin); + + if (*saved_stdout >= 0) + close_nointr_nofail(*saved_stdout); + + return r; +} + +static int ask_for_confirmation(char *response, char **argv) { + int saved_stdout = -1, saved_stdin = -1, r; + char *line; + + r = setup_confirm_stdio(&saved_stdin, &saved_stdout); + if (r < 0) + return r; + + line = exec_command_line(argv); + if (!line) + return -ENOMEM; + + r = ask(response, "yns", "Execute %s? [Yes, No, Skip] ", line); + free(line); + + restore_confirm_stdio(&saved_stdin, &saved_stdout); + + return r; +} + +static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) { + bool keep_groups = false; + int r; + + assert(context); + + /* Lookup and set GID and supplementary group list. Here too + * we avoid NSS lookups for gid=0. */ + + if (context->group || username) { + + if (context->group) { + const char *g = context->group; + + if ((r = get_group_creds(&g, &gid)) < 0) + return r; + } + + /* First step, initialize groups from /etc/groups */ + if (username && gid != 0) { + if (initgroups(username, gid) < 0) + return -errno; + + keep_groups = true; + } + + /* Second step, set our gids */ + if (setresgid(gid, gid, gid) < 0) + return -errno; + } + + if (context->supplementary_groups) { + int ngroups_max, k; + gid_t *gids; + char **i; + + /* Final step, initialize any manually set supplementary groups */ + assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0); + + if (!(gids = new(gid_t, ngroups_max))) + return -ENOMEM; + + if (keep_groups) { + if ((k = getgroups(ngroups_max, gids)) < 0) { + free(gids); + return -errno; + } + } else + k = 0; + + STRV_FOREACH(i, context->supplementary_groups) { + const char *g; + + if (k >= ngroups_max) { + free(gids); + return -E2BIG; + } + + g = *i; + r = get_group_creds(&g, gids+k); + if (r < 0) { + free(gids); + return r; + } + + k++; + } + + if (setgroups(k, gids) < 0) { + free(gids); + return -errno; + } + + free(gids); + } + + return 0; +} + +static int enforce_user(const ExecContext *context, uid_t uid) { + assert(context); + + /* Sets (but doesn't lookup) the uid and make sure we keep the + * capabilities while doing so. */ + + if (context->capabilities) { + _cleanup_cap_free_ cap_t d = NULL; + static const cap_value_t bits[] = { + CAP_SETUID, /* Necessary so that we can run setresuid() below */ + CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ + }; + + /* First step: If we need to keep capabilities but + * drop privileges we need to make sure we keep our + * caps, while we drop privileges. */ + if (uid != 0) { + int sb = context->secure_bits | 1<capabilities); + if (!d) + return -errno; + + if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || + cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) + return -errno; + + if (cap_set_proc(d) < 0) + return -errno; + } + + /* Third step: actually set the uids */ + if (setresuid(uid, uid, uid) < 0) + return -errno; + + /* At this point we should have all necessary capabilities but + are otherwise a normal user. However, the caps might got + corrupted due to the setresuid() so we need clean them up + later. This is done outside of this call. */ + + return 0; +} + +#ifdef HAVE_PAM + +static int null_conv( + int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) { + + /* We don't support conversations */ + + return PAM_CONV_ERR; +} + +static int setup_pam( + const char *name, + const char *user, + uid_t uid, + const char *tty, + char ***pam_env, + int fds[], unsigned n_fds) { + + static const struct pam_conv conv = { + .conv = null_conv, + .appdata_ptr = NULL + }; + + pam_handle_t *handle = NULL; + sigset_t ss, old_ss; + int pam_code = PAM_SUCCESS; + int err; + char **e = NULL; + bool close_session = false; + pid_t pam_pid = 0, parent_pid; + int flags = 0; + + assert(name); + assert(user); + assert(pam_env); + + /* We set up PAM in the parent process, then fork. The child + * will then stay around until killed via PR_GET_PDEATHSIG or + * systemd via the cgroup logic. It will then remove the PAM + * session again. The parent process will exec() the actual + * daemon. We do things this way to ensure that the main PID + * of the daemon is the one we initially fork()ed. */ + + if (log_get_max_level() < LOG_PRI(LOG_DEBUG)) + flags |= PAM_SILENT; + + pam_code = pam_start(name, user, &conv, &handle); + if (pam_code != PAM_SUCCESS) { + handle = NULL; + goto fail; + } + + if (tty) { + pam_code = pam_set_item(handle, PAM_TTY, tty); + if (pam_code != PAM_SUCCESS) + goto fail; + } + + pam_code = pam_acct_mgmt(handle, flags); + if (pam_code != PAM_SUCCESS) + goto fail; + + pam_code = pam_open_session(handle, flags); + if (pam_code != PAM_SUCCESS) + goto fail; + + close_session = true; + + e = pam_getenvlist(handle); + if (!e) { + pam_code = PAM_BUF_ERR; + goto fail; + } + + /* Block SIGTERM, so that we know that it won't get lost in + * the child */ + if (sigemptyset(&ss) < 0 || + sigaddset(&ss, SIGTERM) < 0 || + sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0) + goto fail; + + parent_pid = getpid(); + + pam_pid = fork(); + if (pam_pid < 0) + goto fail; + + if (pam_pid == 0) { + int sig; + int r = EXIT_PAM; + + /* The child's job is to reset the PAM session on + * termination */ + + /* This string must fit in 10 chars (i.e. the length + * of "/sbin/init"), to look pretty in /bin/ps */ + rename_process("(sd-pam)"); + + /* Make sure we don't keep open the passed fds in this + child. We assume that otherwise only those fds are + open here that have been opened by PAM. */ + close_many(fds, n_fds); + + /* Drop privileges - we don't need any to pam_close_session + * and this will make PR_SET_PDEATHSIG work in most cases. + * If this fails, ignore the error - but expect sd-pam threads + * to fail to exit normally */ + if (setresuid(uid, uid, uid) < 0) + log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r)); + + /* Wait until our parent died. This will only work if + * the above setresuid() succeeds, otherwise the kernel + * will not allow unprivileged parents kill their privileged + * children this way. We rely on the control groups kill logic + * to do the rest for us. */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + goto child_finish; + + /* Check if our parent process might already have + * died? */ + if (getppid() == parent_pid) { + for (;;) { + if (sigwait(&ss, &sig) < 0) { + if (errno == EINTR) + continue; + + goto child_finish; + } + + assert(sig == SIGTERM); + break; + } + } + + /* If our parent died we'll end the session */ + if (getppid() != parent_pid) { + pam_code = pam_close_session(handle, flags); + if (pam_code != PAM_SUCCESS) + goto child_finish; + } + + r = 0; + + child_finish: + pam_end(handle, pam_code | flags); + _exit(r); + } + + /* If the child was forked off successfully it will do all the + * cleanups, so forget about the handle here. */ + handle = NULL; + + /* Unblock SIGTERM again in the parent */ + if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0) + goto fail; + + /* We close the log explicitly here, since the PAM modules + * might have opened it, but we don't want this fd around. */ + closelog(); + + *pam_env = e; + e = NULL; + + return 0; + +fail: + if (pam_code != PAM_SUCCESS) { + log_error("PAM failed: %s", pam_strerror(handle, pam_code)); + err = -EPERM; /* PAM errors do not map to errno */ + } else { + log_error("PAM failed: %m"); + err = -errno; + } + + if (handle) { + if (close_session) + pam_code = pam_close_session(handle, flags); + + pam_end(handle, pam_code | flags); + } + + strv_free(e); + + closelog(); + + if (pam_pid > 1) { + kill(pam_pid, SIGTERM); + kill(pam_pid, SIGCONT); + } + + return err; +} +#endif + +static void rename_process_from_path(const char *path) { + char process_name[11]; + const char *p; + size_t l; + + /* This resulting string must fit in 10 chars (i.e. the length + * of "/sbin/init") to look pretty in /bin/ps */ + + p = basename(path); + if (isempty(p)) { + rename_process("(...)"); + return; + } + + l = strlen(p); + if (l > 8) { + /* The end of the process name is usually more + * interesting, since the first bit might just be + * "systemd-" */ + p = p + l - 8; + l = 8; + } + + process_name[0] = '('; + memcpy(process_name+1, p, l); + process_name[1+l] = ')'; + process_name[1+l+1] = 0; + + rename_process(process_name); +} + +#ifdef HAVE_SECCOMP + +static int apply_seccomp(ExecContext *c) { + uint32_t negative_action, action; + scmp_filter_ctx *seccomp; + Iterator i; + void *id; + int r; + + assert(c); + + negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno); + + seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + + if (c->syscall_archs) { + + SET_FOREACH(id, c->syscall_archs, i) { + r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1); + if (r == -EEXIST) + continue; + if (r < 0) { + seccomp_release(seccomp); + return r; + } + } + } else { + + r = seccomp_add_secondary_archs(seccomp); + if (r < 0) { + seccomp_release(seccomp); + return r; + } + } + + action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action; + SET_FOREACH(id, c->syscall_filter, i) { + r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0); + if (r < 0) { + seccomp_release(seccomp); + return r; + } + } + + r = seccomp_load(seccomp); + seccomp_release(seccomp); + + return r; +} +#endif + +static void do_idle_pipe_dance(int idle_pipe[4]) { + assert(idle_pipe); + + if (idle_pipe[1] >= 0) + close_nointr_nofail(idle_pipe[1]); + if (idle_pipe[2] >= 0) + close_nointr_nofail(idle_pipe[2]); + + if (idle_pipe[0] >= 0) { + int r; + + r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC); + + if (idle_pipe[3] >= 0 && r == 0 /* timeout */) { + /* Signal systemd that we are bored and want to continue. */ + write(idle_pipe[3], "x", 1); + + /* Wait for systemd to react to the signal above. */ + fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC); + } + + close_nointr_nofail(idle_pipe[0]); + + } + + if (idle_pipe[3] >= 0) + close_nointr_nofail(idle_pipe[3]); +} + +static int build_environment( + ExecContext *c, + unsigned n_fds, + usec_t watchdog_usec, + const char *home, + const char *username, + const char *shell, + char ***ret) { + + _cleanup_strv_free_ char **our_env = NULL; + unsigned n_env = 0; + char *x; + + assert(c); + assert(ret); + + our_env = new0(char*, 10); + if (!our_env) + return -ENOMEM; + + if (n_fds > 0) { + if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0) + return -ENOMEM; + our_env[n_env++] = x; + + if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0) + return -ENOMEM; + our_env[n_env++] = x; + } + + if (watchdog_usec > 0) { + if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0) + return -ENOMEM; + our_env[n_env++] = x; + + if (asprintf(&x, "WATCHDOG_USEC=%llu", (unsigned long long) watchdog_usec) < 0) + return -ENOMEM; + our_env[n_env++] = x; + } + + if (home) { + x = strappend("HOME=", home); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; + } + + if (username) { + x = strappend("LOGNAME=", username); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; + + x = strappend("USER=", username); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; + } + + if (shell) { + x = strappend("SHELL=", shell); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; + } + + if (is_terminal_input(c->std_input) || + c->std_output == EXEC_OUTPUT_TTY || + c->std_error == EXEC_OUTPUT_TTY || + c->tty_path) { + + x = strdup(default_term_for_tty(tty_path(c))); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; + } + + our_env[n_env++] = NULL; + assert(n_env <= 10); + + *ret = our_env; + our_env = NULL; + + return 0; +} + +int exec_spawn(ExecCommand *command, + char **argv, + ExecContext *context, + int fds[], unsigned n_fds, + char **environment, + bool apply_permissions, + bool apply_chroot, + bool apply_tty_stdin, + bool confirm_spawn, + CGroupControllerMask cgroup_supported, + const char *cgroup_path, + const char *unit_id, + usec_t watchdog_usec, + int idle_pipe[4], + ExecRuntime *runtime, + pid_t *ret) { + + _cleanup_strv_free_ char **files_env = NULL; + int socket_fd; + char *line; + pid_t pid; + int r; + + assert(command); + assert(context); + assert(ret); + assert(fds || n_fds <= 0); + + if (context->std_input == EXEC_INPUT_SOCKET || + context->std_output == EXEC_OUTPUT_SOCKET || + context->std_error == EXEC_OUTPUT_SOCKET) { + + if (n_fds != 1) + return -EINVAL; + + socket_fd = fds[0]; + + fds = NULL; + n_fds = 0; + } else + socket_fd = -1; + + r = exec_context_load_environment(context, &files_env); + if (r < 0) { + log_struct_unit(LOG_ERR, + unit_id, + "MESSAGE=Failed to load environment files: %s", strerror(-r), + "ERRNO=%d", -r, + NULL); + return r; + } + + if (!argv) + argv = command->argv; + + line = exec_command_line(argv); + if (!line) + return log_oom(); + + log_struct_unit(LOG_DEBUG, + unit_id, + "EXECUTABLE=%s", command->path, + "MESSAGE=About to execute: %s", line, + NULL); + free(line); + + pid = fork(); + if (pid < 0) + return -errno; + + if (pid == 0) { + _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; + const char *username = NULL, *home = NULL, *shell = NULL; + unsigned n_dont_close = 0; + int dont_close[n_fds + 3]; + uid_t uid = (uid_t) -1; + gid_t gid = (gid_t) -1; + sigset_t ss; + int i, err; + + /* child */ + + rename_process_from_path(command->path); + + /* We reset exactly these signals, since they are the + * only ones we set to SIG_IGN in the main daemon. All + * others we leave untouched because we set them to + * SIG_DFL or a valid handler initially, both of which + * will be demoted to SIG_DFL. */ + default_signals(SIGNALS_CRASH_HANDLER, + SIGNALS_IGNORE, -1); + + if (context->ignore_sigpipe) + ignore_signals(SIGPIPE, -1); + + assert_se(sigemptyset(&ss) == 0); + if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) { + err = -errno; + r = EXIT_SIGNAL_MASK; + goto fail_child; + } + + if (idle_pipe) + do_idle_pipe_dance(idle_pipe); + + /* Close sockets very early to make sure we don't + * block init reexecution because it cannot bind its + * sockets */ + log_forget_fds(); + + if (socket_fd >= 0) + dont_close[n_dont_close++] = socket_fd; + if (n_fds > 0) { + memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); + n_dont_close += n_fds; + } + if (runtime) { + if (runtime->netns_storage_socket[0] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; + if (runtime->netns_storage_socket[1] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; + } + + err = close_all_fds(dont_close, n_dont_close); + if (err < 0) { + r = EXIT_FDS; + goto fail_child; + } + + if (!context->same_pgrp) + if (setsid() < 0) { + err = -errno; + r = EXIT_SETSID; + goto fail_child; + } + + if (context->tcpwrap_name) { + if (socket_fd >= 0) + if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) { + err = -EACCES; + r = EXIT_TCPWRAP; + goto fail_child; + } + + for (i = 0; i < (int) n_fds; i++) { + if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) { + err = -EACCES; + r = EXIT_TCPWRAP; + goto fail_child; + } + } + } + + exec_context_tty_reset(context); + + if (confirm_spawn) { + char response; + + err = ask_for_confirmation(&response, argv); + if (err == -ETIMEDOUT) + write_confirm_message("Confirmation question timed out, assuming positive response.\n"); + else if (err < 0) + write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err)); + else if (response == 's') { + write_confirm_message("Skipping execution.\n"); + err = -ECANCELED; + r = EXIT_CONFIRM; + goto fail_child; + } else if (response == 'n') { + write_confirm_message("Failing execution.\n"); + err = r = 0; + goto fail_child; + } + } + + /* If a socket is connected to STDIN/STDOUT/STDERR, we + * must sure to drop O_NONBLOCK */ + if (socket_fd >= 0) + fd_nonblock(socket_fd, false); + + err = setup_input(context, socket_fd, apply_tty_stdin); + if (err < 0) { + r = EXIT_STDIN; + goto fail_child; + } + + err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin); + if (err < 0) { + r = EXIT_STDOUT; + goto fail_child; + } + + err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin); + if (err < 0) { + r = EXIT_STDERR; + goto fail_child; + } + + if (cgroup_path) { + err = cg_attach_everywhere(cgroup_supported, cgroup_path, 0); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; + } + } + + if (context->oom_score_adjust_set) { + char t[16]; + + snprintf(t, sizeof(t), "%i", context->oom_score_adjust); + char_array_0(t); + + if (write_string_file("/proc/self/oom_score_adj", t) < 0) { + err = -errno; + r = EXIT_OOM_ADJUST; + goto fail_child; + } + } + + if (context->nice_set) + if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { + err = -errno; + r = EXIT_NICE; + goto fail_child; + } + + if (context->cpu_sched_set) { + struct sched_param param = { + .sched_priority = context->cpu_sched_priority, + }; + + r = sched_setscheduler(0, + context->cpu_sched_policy | + (context->cpu_sched_reset_on_fork ? + SCHED_RESET_ON_FORK : 0), + ¶m); + if (r < 0) { + err = -errno; + r = EXIT_SETSCHEDULER; + goto fail_child; + } + } + + if (context->cpuset) + if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) { + err = -errno; + r = EXIT_CPUAFFINITY; + goto fail_child; + } + + if (context->ioprio_set) + if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { + err = -errno; + r = EXIT_IOPRIO; + goto fail_child; + } + + if (context->timer_slack_nsec != (nsec_t) -1) + if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { + err = -errno; + r = EXIT_TIMERSLACK; + goto fail_child; + } + + if (context->personality != 0xffffffffUL) + if (personality(context->personality) < 0) { + err = -errno; + r = EXIT_PERSONALITY; + goto fail_child; + } + + if (context->utmp_id) + utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path); + + if (context->user) { + username = context->user; + err = get_user_creds(&username, &uid, &gid, &home, &shell); + if (err < 0) { + r = EXIT_USER; + goto fail_child; + } + + if (is_terminal_input(context->std_input)) { + err = chown_terminal(STDIN_FILENO, uid); + if (err < 0) { + r = EXIT_STDIN; + goto fail_child; + } + } + } + +#ifdef HAVE_PAM + if (cgroup_path && context->user && context->pam_name) { + err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0644, uid, gid); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; + } + + + err = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0755, uid, gid); + if (err < 0) { + r = EXIT_CGROUP; + goto fail_child; + } + } +#endif + + if (apply_permissions) { + err = enforce_groups(context, username, gid); + if (err < 0) { + r = EXIT_GROUP; + goto fail_child; + } + } + + umask(context->umask); + +#ifdef HAVE_PAM + if (apply_permissions && context->pam_name && username) { + err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds); + if (err < 0) { + r = EXIT_PAM; + goto fail_child; + } + } +#endif + if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) { + err = setup_netns(runtime->netns_storage_socket); + if (err < 0) { + r = EXIT_NETWORK; + goto fail_child; + } + } + + if (!strv_isempty(context->read_write_dirs) || + !strv_isempty(context->read_only_dirs) || + !strv_isempty(context->inaccessible_dirs) || + context->mount_flags != 0 || + (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) || + context->private_devices) { + + char *tmp = NULL, *var = NULL; + + /* The runtime struct only contains the parent + * of the private /tmp, which is + * non-accessible to world users. Inside of it + * there's a /tmp that is sticky, and that's + * the one we want to use here. */ + + if (context->private_tmp && runtime) { + if (runtime->tmp_dir) + tmp = strappenda(runtime->tmp_dir, "/tmp"); + if (runtime->var_tmp_dir) + var = strappenda(runtime->var_tmp_dir, "/tmp"); + } + + err = setup_namespace( + context->read_write_dirs, + context->read_only_dirs, + context->inaccessible_dirs, + tmp, + var, + context->private_devices, + context->mount_flags); + + if (err < 0) { + r = EXIT_NAMESPACE; + goto fail_child; + } + } + + if (apply_chroot) { + if (context->root_directory) + if (chroot(context->root_directory) < 0) { + err = -errno; + r = EXIT_CHROOT; + goto fail_child; + } + + if (chdir(context->working_directory ? context->working_directory : "/") < 0) { + err = -errno; + r = EXIT_CHDIR; + goto fail_child; + } + } else { + _cleanup_free_ char *d = NULL; + + if (asprintf(&d, "%s/%s", + context->root_directory ? context->root_directory : "", + context->working_directory ? context->working_directory : "") < 0) { + err = -ENOMEM; + r = EXIT_MEMORY; + goto fail_child; + } + + if (chdir(d) < 0) { + err = -errno; + r = EXIT_CHDIR; + goto fail_child; + } + } + + /* We repeat the fd closing here, to make sure that + * nothing is leaked from the PAM modules */ + err = close_all_fds(fds, n_fds); + if (err >= 0) + err = shift_fds(fds, n_fds); + if (err >= 0) + err = flags_fds(fds, n_fds, context->non_blocking); + if (err < 0) { + r = EXIT_FDS; + goto fail_child; + } + + if (apply_permissions) { + + for (i = 0; i < RLIMIT_NLIMITS; i++) { + if (!context->rlimit[i]) + continue; + + if (setrlimit_closest(i, context->rlimit[i]) < 0) { + err = -errno; + r = EXIT_LIMITS; + goto fail_child; + } + } + + if (context->capability_bounding_set_drop) { + err = capability_bounding_set_drop(context->capability_bounding_set_drop, false); + if (err < 0) { + r = EXIT_CAPABILITIES; + goto fail_child; + } + } + + if (context->user) { + err = enforce_user(context, uid); + if (err < 0) { + r = EXIT_USER; + goto fail_child; + } + } + + /* PR_GET_SECUREBITS is not privileged, while + * PR_SET_SECUREBITS is. So to suppress + * potential EPERMs we'll try not to call + * PR_SET_SECUREBITS unless necessary. */ + if (prctl(PR_GET_SECUREBITS) != context->secure_bits) + if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { + err = -errno; + r = EXIT_SECUREBITS; + goto fail_child; + } + + if (context->capabilities) + if (cap_set_proc(context->capabilities) < 0) { + err = -errno; + r = EXIT_CAPABILITIES; + goto fail_child; + } + + if (context->no_new_privileges) + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + err = -errno; + r = EXIT_NO_NEW_PRIVILEGES; + goto fail_child; + } + +#ifdef HAVE_SECCOMP + if (context->syscall_filter || context->syscall_archs) { + err = apply_seccomp(context); + if (err < 0) { + r = EXIT_SECCOMP; + goto fail_child; + } + } +#endif + +#ifdef HAVE_SELINUX + if (context->selinux_context && use_selinux()) { + err = setexeccon(context->selinux_context); + if (err < 0 && !context->selinux_context_ignore) { + r = EXIT_SELINUX_CONTEXT; + goto fail_child; + } + } +#endif + +#ifdef HAVE_APPARMOR + if (context->apparmor_profile && use_apparmor()) { + err = aa_change_onexec(context->apparmor_profile); + if (err < 0 && !context->apparmor_profile_ignore) { + r = EXIT_APPARMOR_PROFILE; + goto fail_child; + } + } +#endif + } + + err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); + if (r < 0) { + r = EXIT_MEMORY; + goto fail_child; + } + + final_env = strv_env_merge(5, + environment, + our_env, + context->environment, + files_env, + pam_env, + NULL); + if (!final_env) { + err = -ENOMEM; + r = EXIT_MEMORY; + goto fail_child; + } + + final_argv = replace_env_argv(argv, final_env); + if (!final_argv) { + err = -ENOMEM; + r = EXIT_MEMORY; + goto fail_child; + } + + final_env = strv_env_clean(final_env); + + if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + line = exec_command_line(final_argv); + if (line) { + log_open(); + log_struct_unit(LOG_DEBUG, + unit_id, + "EXECUTABLE=%s", command->path, + "MESSAGE=Executing: %s", line, + NULL); + log_close(); + free(line); + line = NULL; + } + } + execve(command->path, final_argv, final_env); + err = -errno; + r = EXIT_EXEC; + + fail_child: + if (r != 0) { + log_open(); + log_struct(LOG_ERR, MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED), + "EXECUTABLE=%s", command->path, + "MESSAGE=Failed at step %s spawning %s: %s", + exit_status_to_string(r, EXIT_STATUS_SYSTEMD), + command->path, strerror(-err), + "ERRNO=%d", -err, + NULL); + log_close(); + } + + _exit(r); + } + + log_struct_unit(LOG_DEBUG, + unit_id, + "MESSAGE=Forked %s as "PID_FMT, + command->path, pid, + NULL); + + /* We add the new process to the cgroup both in the child (so + * that we can be sure that no user code is ever executed + * outside of the cgroup) and in the parent (so that we can be + * sure that when we kill the cgroup the process will be + * killed too). */ + if (cgroup_path) + cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, pid); + + exec_status_start(&command->exec_status, pid); + + *ret = pid; + return 0; +} + +void exec_context_init(ExecContext *c) { + assert(c); + + c->umask = 0022; + c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0); + c->cpu_sched_policy = SCHED_OTHER; + c->syslog_priority = LOG_DAEMON|LOG_INFO; + c->syslog_level_prefix = true; + c->ignore_sigpipe = true; + c->timer_slack_nsec = (nsec_t) -1; + c->personality = 0xffffffffUL; +} + +void exec_context_done(ExecContext *c) { + unsigned l; + + assert(c); + + strv_free(c->environment); + c->environment = NULL; + + strv_free(c->environment_files); + c->environment_files = NULL; + + for (l = 0; l < ELEMENTSOF(c->rlimit); l++) { + free(c->rlimit[l]); + c->rlimit[l] = NULL; + } + + free(c->working_directory); + c->working_directory = NULL; + free(c->root_directory); + c->root_directory = NULL; + + free(c->tty_path); + c->tty_path = NULL; + + free(c->tcpwrap_name); + c->tcpwrap_name = NULL; + + free(c->syslog_identifier); + c->syslog_identifier = NULL; + + free(c->user); + c->user = NULL; + + free(c->group); + c->group = NULL; + + strv_free(c->supplementary_groups); + c->supplementary_groups = NULL; + + free(c->pam_name); + c->pam_name = NULL; + + if (c->capabilities) { + cap_free(c->capabilities); + c->capabilities = NULL; + } + + strv_free(c->read_only_dirs); + c->read_only_dirs = NULL; + + strv_free(c->read_write_dirs); + c->read_write_dirs = NULL; + + strv_free(c->inaccessible_dirs); + c->inaccessible_dirs = NULL; + + if (c->cpuset) + CPU_FREE(c->cpuset); + + free(c->utmp_id); + c->utmp_id = NULL; + + free(c->selinux_context); + c->selinux_context = NULL; + + free(c->apparmor_profile); + c->apparmor_profile = NULL; + +#ifdef HAVE_SECCOMP + set_free(c->syscall_filter); + c->syscall_filter = NULL; + + set_free(c->syscall_archs); + c->syscall_archs = NULL; +#endif +} + +void exec_command_done(ExecCommand *c) { + assert(c); + + free(c->path); + c->path = NULL; + + strv_free(c->argv); + c->argv = NULL; +} + +void exec_command_done_array(ExecCommand *c, unsigned n) { + unsigned i; + + for (i = 0; i < n; i++) + exec_command_done(c+i); +} + +void exec_command_free_list(ExecCommand *c) { + ExecCommand *i; + + while ((i = c)) { + LIST_REMOVE(command, c, i); + exec_command_done(i); + free(i); + } +} + +void exec_command_free_array(ExecCommand **c, unsigned n) { + unsigned i; + + for (i = 0; i < n; i++) { + exec_command_free_list(c[i]); + c[i] = NULL; + } +} + +int exec_context_load_environment(const ExecContext *c, char ***l) { + char **i, **r = NULL; + + assert(c); + assert(l); + + STRV_FOREACH(i, c->environment_files) { + char *fn; + int k; + bool ignore = false; + char **p; + _cleanup_globfree_ glob_t pglob = {}; + int count, n; + + fn = *i; + + if (fn[0] == '-') { + ignore = true; + fn ++; + } + + if (!path_is_absolute(fn)) { + if (ignore) + continue; + + strv_free(r); + return -EINVAL; + } + + /* Filename supports globbing, take all matching files */ + errno = 0; + if (glob(fn, 0, NULL, &pglob) != 0) { + if (ignore) + continue; + + strv_free(r); + return errno ? -errno : -EINVAL; + } + count = pglob.gl_pathc; + if (count == 0) { + if (ignore) + continue; + + strv_free(r); + return -EINVAL; + } + for (n = 0; n < count; n++) { + k = load_env_file(pglob.gl_pathv[n], NULL, &p); + if (k < 0) { + if (ignore) + continue; + + strv_free(r); + return k; + } + /* Log invalid environment variables with filename */ + if (p) + p = strv_env_clean_log(p, pglob.gl_pathv[n]); + + if (r == NULL) + r = p; + else { + char **m; + + m = strv_env_merge(2, r, p); + strv_free(r); + strv_free(p); + if (!m) + return -ENOMEM; + + r = m; + } + } + } + + *l = r; + + return 0; +} + +static bool tty_may_match_dev_console(const char *tty) { + char *active = NULL, *console; + bool b; + + if (startswith(tty, "/dev/")) + tty += 5; + + /* trivial identity? */ + if (streq(tty, "console")) + return true; + + console = resolve_dev_console(&active); + /* if we could not resolve, assume it may */ + if (!console) + return true; + + /* "tty0" means the active VC, so it may be the same sometimes */ + b = streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty)); + free(active); + + return b; +} + +bool exec_context_may_touch_console(ExecContext *ec) { + return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate || + is_terminal_input(ec->std_input) || + is_terminal_output(ec->std_output) || + is_terminal_output(ec->std_error)) && + tty_may_match_dev_console(tty_path(ec)); +} + +static void strv_fprintf(FILE *f, char **l) { + char **g; + + assert(f); + + STRV_FOREACH(g, l) + fprintf(f, " %s", *g); +} + +void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + char **e; + unsigned i; + + assert(c); + assert(f); + + prefix = strempty(prefix); + + fprintf(f, + "%sUMask: %04o\n" + "%sWorkingDirectory: %s\n" + "%sRootDirectory: %s\n" + "%sNonBlocking: %s\n" + "%sPrivateTmp: %s\n" + "%sPrivateNetwork: %s\n" + "%sPrivateDevices: %s\n" + "%sIgnoreSIGPIPE: %s\n", + prefix, c->umask, + prefix, c->working_directory ? c->working_directory : "/", + prefix, c->root_directory ? c->root_directory : "/", + prefix, yes_no(c->non_blocking), + prefix, yes_no(c->private_tmp), + prefix, yes_no(c->private_network), + prefix, yes_no(c->private_devices), + prefix, yes_no(c->ignore_sigpipe)); + + STRV_FOREACH(e, c->environment) + fprintf(f, "%sEnvironment: %s\n", prefix, *e); + + STRV_FOREACH(e, c->environment_files) + fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e); + + if (c->tcpwrap_name) + fprintf(f, + "%sTCPWrapName: %s\n", + prefix, c->tcpwrap_name); + + if (c->nice_set) + fprintf(f, + "%sNice: %i\n", + prefix, c->nice); + + if (c->oom_score_adjust_set) + fprintf(f, + "%sOOMScoreAdjust: %i\n", + prefix, c->oom_score_adjust); + + for (i = 0; i < RLIM_NLIMITS; i++) + if (c->rlimit[i]) + fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max); + + if (c->ioprio_set) { + _cleanup_free_ char *class_str = NULL; + + ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str); + fprintf(f, + "%sIOSchedulingClass: %s\n" + "%sIOPriority: %i\n", + prefix, strna(class_str), + prefix, (int) IOPRIO_PRIO_DATA(c->ioprio)); + } + + if (c->cpu_sched_set) { + _cleanup_free_ char *policy_str = NULL; + + sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str); + fprintf(f, + "%sCPUSchedulingPolicy: %s\n" + "%sCPUSchedulingPriority: %i\n" + "%sCPUSchedulingResetOnFork: %s\n", + prefix, strna(policy_str), + prefix, c->cpu_sched_priority, + prefix, yes_no(c->cpu_sched_reset_on_fork)); + } + + if (c->cpuset) { + fprintf(f, "%sCPUAffinity:", prefix); + for (i = 0; i < c->cpuset_ncpus; i++) + if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset)) + fprintf(f, " %u", i); + fputs("\n", f); + } + + if (c->timer_slack_nsec != (nsec_t) -1) + fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec); + + fprintf(f, + "%sStandardInput: %s\n" + "%sStandardOutput: %s\n" + "%sStandardError: %s\n", + prefix, exec_input_to_string(c->std_input), + prefix, exec_output_to_string(c->std_output), + prefix, exec_output_to_string(c->std_error)); + + if (c->tty_path) + fprintf(f, + "%sTTYPath: %s\n" + "%sTTYReset: %s\n" + "%sTTYVHangup: %s\n" + "%sTTYVTDisallocate: %s\n", + prefix, c->tty_path, + prefix, yes_no(c->tty_reset), + prefix, yes_no(c->tty_vhangup), + prefix, yes_no(c->tty_vt_disallocate)); + + if (c->std_output == EXEC_OUTPUT_SYSLOG || + c->std_output == EXEC_OUTPUT_KMSG || + c->std_output == EXEC_OUTPUT_JOURNAL || + c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || + c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || + c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE || + c->std_error == EXEC_OUTPUT_SYSLOG || + c->std_error == EXEC_OUTPUT_KMSG || + c->std_error == EXEC_OUTPUT_JOURNAL || + c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || + c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE || + c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE) { + + _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL; + + log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str); + log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str); + + fprintf(f, + "%sSyslogFacility: %s\n" + "%sSyslogLevel: %s\n", + prefix, strna(fac_str), + prefix, strna(lvl_str)); + } + + if (c->capabilities) { + _cleanup_cap_free_charp_ char *t; + + t = cap_to_text(c->capabilities, NULL); + if (t) + fprintf(f, "%sCapabilities: %s\n", prefix, t); + } + + if (c->secure_bits) + fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n", + prefix, + (c->secure_bits & 1<secure_bits & 1<secure_bits & 1<secure_bits & 1<secure_bits & 1<secure_bits & 1<capability_bounding_set_drop) { + unsigned long l; + fprintf(f, "%sCapabilityBoundingSet:", prefix); + + for (l = 0; l <= cap_last_cap(); l++) + if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) { + _cleanup_cap_free_charp_ char *t; + + t = cap_to_name(l); + if (t) + fprintf(f, " %s", t); + } + + fputs("\n", f); + } + + if (c->user) + fprintf(f, "%sUser: %s\n", prefix, c->user); + if (c->group) + fprintf(f, "%sGroup: %s\n", prefix, c->group); + + if (strv_length(c->supplementary_groups) > 0) { + fprintf(f, "%sSupplementaryGroups:", prefix); + strv_fprintf(f, c->supplementary_groups); + fputs("\n", f); + } + + if (c->pam_name) + fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); + + if (strv_length(c->read_write_dirs) > 0) { + fprintf(f, "%sReadWriteDirs:", prefix); + strv_fprintf(f, c->read_write_dirs); + fputs("\n", f); + } + + if (strv_length(c->read_only_dirs) > 0) { + fprintf(f, "%sReadOnlyDirs:", prefix); + strv_fprintf(f, c->read_only_dirs); + fputs("\n", f); + } + + if (strv_length(c->inaccessible_dirs) > 0) { + fprintf(f, "%sInaccessibleDirs:", prefix); + strv_fprintf(f, c->inaccessible_dirs); + fputs("\n", f); + } + + if (c->utmp_id) + fprintf(f, + "%sUtmpIdentifier: %s\n", + prefix, c->utmp_id); + + if (c->selinux_context) + fprintf(f, + "%sSELinuxContext: %s%s\n", + prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context); + + if (c->personality != 0xffffffffUL) + fprintf(f, + "%sPersonality: %s\n", + prefix, strna(personality_to_string(c->personality))); + + if (c->syscall_filter) { +#ifdef HAVE_SECCOMP + Iterator j; + void *id; + bool first = true; +#endif + + fprintf(f, + "%sSystemCallFilter: ", + prefix); + + if (!c->syscall_whitelist) + fputc('~', f); + +#ifdef HAVE_SECCOMP + SET_FOREACH(id, c->syscall_filter, j) { + _cleanup_free_ char *name = NULL; + + if (first) + first = false; + else + fputc(' ', f); + + name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1); + fputs(strna(name), f); + } +#endif + + fputc('\n', f); + } + + if (c->syscall_archs) { +#ifdef HAVE_SECCOMP + Iterator j; + void *id; +#endif + + fprintf(f, + "%sSystemCallArchitectures:", + prefix); + +#ifdef HAVE_SECCOMP + SET_FOREACH(id, c->syscall_archs, j) + fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1))); +#endif + fputc('\n', f); + } + + if (c->syscall_errno != 0) + fprintf(f, + "%sSystemCallErrorNumber: %s\n", + prefix, strna(errno_to_name(c->syscall_errno))); + + if (c->apparmor_profile) + fprintf(f, + "%sAppArmorProfile: %s%s\n", + prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile); +} + +void exec_status_start(ExecStatus *s, pid_t pid) { + assert(s); + + zero(*s); + s->pid = pid; + dual_timestamp_get(&s->start_timestamp); +} + +void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) { + assert(s); + + if (s->pid && s->pid != pid) + zero(*s); + + s->pid = pid; + dual_timestamp_get(&s->exit_timestamp); + + s->code = code; + s->status = status; + + if (context) { + if (context->utmp_id) + utmp_put_dead_process(context->utmp_id, pid, code, status); + + exec_context_tty_reset(context); + } +} + +void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) { + char buf[FORMAT_TIMESTAMP_MAX]; + + assert(s); + assert(f); + + if (!prefix) + prefix = ""; + + if (s->pid <= 0) + return; + + fprintf(f, + "%sPID: "PID_FMT"\n", + prefix, s->pid); + + if (s->start_timestamp.realtime > 0) + fprintf(f, + "%sStart Timestamp: %s\n", + prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime)); + + if (s->exit_timestamp.realtime > 0) + fprintf(f, + "%sExit Timestamp: %s\n" + "%sExit Code: %s\n" + "%sExit Status: %i\n", + prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime), + prefix, sigchld_code_to_string(s->code), + prefix, s->status); +} + +char *exec_command_line(char **argv) { + size_t k; + char *n, *p, **a; + bool first = true; + + assert(argv); + + k = 1; + STRV_FOREACH(a, argv) + k += strlen(*a)+3; + + if (!(n = new(char, k))) + return NULL; + + p = n; + STRV_FOREACH(a, argv) { + + if (!first) + *(p++) = ' '; + else + first = false; + + if (strpbrk(*a, WHITESPACE)) { + *(p++) = '\''; + p = stpcpy(p, *a); + *(p++) = '\''; + } else + p = stpcpy(p, *a); + + } + + *p = 0; + + /* FIXME: this doesn't really handle arguments that have + * spaces and ticks in them */ + + return n; +} + +void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) { + char *p2; + const char *prefix2; + + char *cmd; + + assert(c); + assert(f); + + if (!prefix) + prefix = ""; + p2 = strappend(prefix, "\t"); + prefix2 = p2 ? p2 : prefix; + + cmd = exec_command_line(c->argv); + + fprintf(f, + "%sCommand Line: %s\n", + prefix, cmd ? cmd : strerror(ENOMEM)); + + free(cmd); + + exec_status_dump(&c->exec_status, f, prefix2); + + free(p2); +} + +void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) { + assert(f); + + if (!prefix) + prefix = ""; + + LIST_FOREACH(command, c, c) + exec_command_dump(c, f, prefix); +} + +void exec_command_append_list(ExecCommand **l, ExecCommand *e) { + ExecCommand *end; + + assert(l); + assert(e); + + if (*l) { + /* It's kind of important, that we keep the order here */ + LIST_FIND_TAIL(command, *l, end); + LIST_INSERT_AFTER(command, *l, end, e); + } else + *l = e; +} + +int exec_command_set(ExecCommand *c, const char *path, ...) { + va_list ap; + char **l, *p; + + assert(c); + assert(path); + + va_start(ap, path); + l = strv_new_ap(path, ap); + va_end(ap); + + if (!l) + return -ENOMEM; + + p = strdup(path); + if (!p) { + strv_free(l); + return -ENOMEM; + } + + free(c->path); + c->path = p; + + strv_free(c->argv); + c->argv = l; + + return 0; +} + +static int exec_runtime_allocate(ExecRuntime **rt) { + + if (*rt) + return 0; + + *rt = new0(ExecRuntime, 1); + if (!*rt) + return -ENOMEM; + + (*rt)->n_ref = 1; + (*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1; + + return 0; +} + +int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) { + int r; + + assert(rt); + assert(c); + assert(id); + + if (*rt) + return 1; + + if (!c->private_network && !c->private_tmp) + return 0; + + r = exec_runtime_allocate(rt); + if (r < 0) + return r; + + if (c->private_network && (*rt)->netns_storage_socket[0] < 0) { + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (*rt)->netns_storage_socket) < 0) + return -errno; + } + + if (c->private_tmp && !(*rt)->tmp_dir) { + r = setup_tmp_dirs(id, &(*rt)->tmp_dir, &(*rt)->var_tmp_dir); + if (r < 0) + return r; + } + + return 1; +} + +ExecRuntime *exec_runtime_ref(ExecRuntime *r) { + assert(r); + assert(r->n_ref > 0); + + r->n_ref++; + return r; +} + +ExecRuntime *exec_runtime_unref(ExecRuntime *r) { + + if (!r) + return NULL; + + assert(r->n_ref > 0); + + r->n_ref--; + if (r->n_ref <= 0) { + free(r->tmp_dir); + free(r->var_tmp_dir); + close_pipe(r->netns_storage_socket); + free(r); + } + + return NULL; +} + +int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds) { + assert(u); + assert(f); + assert(fds); + + if (!rt) + return 0; + + if (rt->tmp_dir) + unit_serialize_item(u, f, "tmp-dir", rt->tmp_dir); + + if (rt->var_tmp_dir) + unit_serialize_item(u, f, "var-tmp-dir", rt->var_tmp_dir); + + if (rt->netns_storage_socket[0] >= 0) { + int copy; + + copy = fdset_put_dup(fds, rt->netns_storage_socket[0]); + if (copy < 0) + return copy; + + unit_serialize_item_format(u, f, "netns-socket-0", "%i", copy); + } + + if (rt->netns_storage_socket[1] >= 0) { + int copy; + + copy = fdset_put_dup(fds, rt->netns_storage_socket[1]); + if (copy < 0) + return copy; + + unit_serialize_item_format(u, f, "netns-socket-1", "%i", copy); + } + + return 0; +} + +int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds) { + int r; + + assert(rt); + assert(key); + assert(value); + + if (streq(key, "tmp-dir")) { + char *copy; + + r = exec_runtime_allocate(rt); + if (r < 0) + return r; + + copy = strdup(value); + if (!copy) + return log_oom(); + + free((*rt)->tmp_dir); + (*rt)->tmp_dir = copy; + + } else if (streq(key, "var-tmp-dir")) { + char *copy; + + r = exec_runtime_allocate(rt); + if (r < 0) + return r; + + copy = strdup(value); + if (!copy) + return log_oom(); + + free((*rt)->var_tmp_dir); + (*rt)->var_tmp_dir = copy; + + } else if (streq(key, "netns-socket-0")) { + int fd; + + r = exec_runtime_allocate(rt); + if (r < 0) + return r; + + if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse netns socket value %s", value); + else { + if ((*rt)->netns_storage_socket[0] >= 0) + close_nointr_nofail((*rt)->netns_storage_socket[0]); + + (*rt)->netns_storage_socket[0] = fdset_remove(fds, fd); + } + } else if (streq(key, "netns-socket-1")) { + int fd; + + r = exec_runtime_allocate(rt); + if (r < 0) + return r; + + if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse netns socket value %s", value); + else { + if ((*rt)->netns_storage_socket[1] >= 0) + close_nointr_nofail((*rt)->netns_storage_socket[1]); + + (*rt)->netns_storage_socket[1] = fdset_remove(fds, fd); + } + } else + return 0; + + return 1; +} + +static void *remove_tmpdir_thread(void *p) { + _cleanup_free_ char *path = p; + + rm_rf_dangerous(path, false, true, false); + return NULL; +} + +void exec_runtime_destroy(ExecRuntime *rt) { + if (!rt) + return; + + /* If there are multiple users of this, let's leave the stuff around */ + if (rt->n_ref > 1) + return; + + if (rt->tmp_dir) { + log_debug("Spawning thread to nuke %s", rt->tmp_dir); + asynchronous_job(remove_tmpdir_thread, rt->tmp_dir); + rt->tmp_dir = NULL; + } + + if (rt->var_tmp_dir) { + log_debug("Spawning thread to nuke %s", rt->var_tmp_dir); + asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir); + rt->var_tmp_dir = NULL; + } + + close_pipe(rt->netns_storage_socket); +} + +static const char* const exec_input_table[_EXEC_INPUT_MAX] = { + [EXEC_INPUT_NULL] = "null", + [EXEC_INPUT_TTY] = "tty", + [EXEC_INPUT_TTY_FORCE] = "tty-force", + [EXEC_INPUT_TTY_FAIL] = "tty-fail", + [EXEC_INPUT_SOCKET] = "socket" +}; + +DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput); + +static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { + [EXEC_OUTPUT_INHERIT] = "inherit", + [EXEC_OUTPUT_NULL] = "null", + [EXEC_OUTPUT_TTY] = "tty", + [EXEC_OUTPUT_SYSLOG] = "syslog", + [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console", + [EXEC_OUTPUT_KMSG] = "kmsg", + [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console", + [EXEC_OUTPUT_JOURNAL] = "journal", + [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console", + [EXEC_OUTPUT_SOCKET] = "socket" +}; + +DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput); diff --git a/src/core/execute.h b/src/core/execute.h new file mode 100644 index 0000000..2bfe227 --- /dev/null +++ b/src/core/execute.h @@ -0,0 +1,244 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct ExecStatus ExecStatus; +typedef struct ExecCommand ExecCommand; +typedef struct ExecContext ExecContext; +typedef struct ExecRuntime ExecRuntime; + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SECCOMP +#include + +#include "set.h" +#endif + +#include "list.h" +#include "util.h" +#include "fdset.h" + +typedef enum ExecInput { + EXEC_INPUT_NULL, + EXEC_INPUT_TTY, + EXEC_INPUT_TTY_FORCE, + EXEC_INPUT_TTY_FAIL, + EXEC_INPUT_SOCKET, + _EXEC_INPUT_MAX, + _EXEC_INPUT_INVALID = -1 +} ExecInput; + +typedef enum ExecOutput { + EXEC_OUTPUT_INHERIT, + EXEC_OUTPUT_NULL, + EXEC_OUTPUT_TTY, + EXEC_OUTPUT_SYSLOG, + EXEC_OUTPUT_SYSLOG_AND_CONSOLE, + EXEC_OUTPUT_KMSG, + EXEC_OUTPUT_KMSG_AND_CONSOLE, + EXEC_OUTPUT_JOURNAL, + EXEC_OUTPUT_JOURNAL_AND_CONSOLE, + EXEC_OUTPUT_SOCKET, + _EXEC_OUTPUT_MAX, + _EXEC_OUTPUT_INVALID = -1 +} ExecOutput; + +struct ExecStatus { + 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 */ +}; + +struct ExecCommand { + char *path; + char **argv; + ExecStatus exec_status; + LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ + bool ignore; +}; + +struct ExecRuntime { + int n_ref; + + char *tmp_dir; + char *var_tmp_dir; + + int netns_storage_socket[2]; +}; + +struct ExecContext { + char **environment; + char **environment_files; + + struct rlimit *rlimit[RLIMIT_NLIMITS]; + char *working_directory, *root_directory; + + mode_t umask; + int oom_score_adjust; + int nice; + int ioprio; + int cpu_sched_policy; + int cpu_sched_priority; + + cpu_set_t *cpuset; + unsigned cpuset_ncpus; + + ExecInput std_input; + ExecOutput std_output; + ExecOutput std_error; + + nsec_t timer_slack_nsec; + + char *tcpwrap_name; + + char *tty_path; + + bool tty_reset; + bool tty_vhangup; + bool tty_vt_disallocate; + + bool ignore_sigpipe; + + /* Since resolving these names might might involve socket + * connections and we don't want to deadlock ourselves these + * names are resolved on execution only and in the child + * process. */ + char *user; + char *group; + char **supplementary_groups; + + char *pam_name; + + char *utmp_id; + + bool selinux_context_ignore; + char *selinux_context; + + bool apparmor_profile_ignore; + char *apparmor_profile; + + char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; + unsigned long mount_flags; + + uint64_t capability_bounding_set_drop; + + cap_t capabilities; + int secure_bits; + + int syslog_priority; + char *syslog_identifier; + bool syslog_level_prefix; + + bool cpu_sched_reset_on_fork; + bool non_blocking; + bool private_tmp; + bool private_network; + bool private_devices; + + bool no_new_privileges; + + /* This is not exposed to the user but available + * internally. We need it to make sure that whenever we spawn + * /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; + + unsigned long personality; + + Set *syscall_filter; + Set *syscall_archs; + int syscall_errno; + bool syscall_whitelist:1; + + bool oom_score_adjust_set:1; + bool nice_set:1; + bool ioprio_set:1; + bool cpu_sched_set:1; +}; + +#include "cgroup.h" + +int exec_spawn(ExecCommand *command, + char **argv, + ExecContext *context, + int fds[], unsigned n_fds, + char **environment, + bool apply_permissions, + bool apply_chroot, + bool apply_tty_stdin, + bool confirm_spawn, + CGroupControllerMask cgroup_mask, + const char *cgroup_path, + const char *unit_id, + usec_t watchdog_usec, + int pipe_fd[2], + ExecRuntime *runtime, + pid_t *ret); + +void exec_command_done(ExecCommand *c); +void exec_command_done_array(ExecCommand *c, unsigned n); + +void exec_command_free_list(ExecCommand *c); +void exec_command_free_array(ExecCommand **c, unsigned n); + +char *exec_command_line(char **argv); + +void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix); +void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix); +void exec_command_append_list(ExecCommand **l, ExecCommand *e); +int exec_command_set(ExecCommand *c, const char *path, ...); + +void exec_context_init(ExecContext *c); +void exec_context_done(ExecContext *c); +void exec_context_dump(ExecContext *c, FILE* f, const char *prefix); + +int exec_context_load_environment(const ExecContext *c, char ***l); + +bool exec_context_may_touch_console(ExecContext *c); + +void exec_status_start(ExecStatus *s, pid_t pid); +void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status); +void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix); + +int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id); +ExecRuntime *exec_runtime_ref(ExecRuntime *r); +ExecRuntime *exec_runtime_unref(ExecRuntime *r); + +int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds); +int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds); + +void exec_runtime_destroy(ExecRuntime *rt); + +const char* exec_output_to_string(ExecOutput i) _const_; +ExecOutput exec_output_from_string(const char *s) _pure_; + +const char* exec_input_to_string(ExecInput i) _const_; +ExecInput exec_input_from_string(const char *s) _pure_; diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c new file mode 100644 index 0000000..8aa1cff --- /dev/null +++ b/src/core/hostname-setup.c @@ -0,0 +1,92 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "hostname-setup.h" +#include "macro.h" +#include "util.h" +#include "log.h" +#include "fileio.h" + +static int read_and_strip_hostname(const char *path, char **hn) { + char *s; + int r; + + assert(path); + assert(hn); + + r = read_one_line_file(path, &s); + if (r < 0) + return r; + + hostname_cleanup(s, false); + + if (isempty(s)) { + free(s); + return -ENOENT; + } + + *hn = s; + return 0; +} + +int hostname_setup(void) { + int r; + _cleanup_free_ char *b = NULL; + const char *hn; + bool enoent = false; + + r = read_and_strip_hostname("/etc/hostname", &b); + if (r < 0) { + if (r == -ENOENT) + enoent = true; + else + log_warning("Failed to read configured hostname: %s", strerror(-r)); + + hn = NULL; + } else + hn = b; + + if (isempty(hn)) { + /* Don't override the hostname if it is already set + * and not explicitly configured */ + if (hostname_is_set()) + return 0; + + if (enoent) + log_info("No hostname configured."); + + hn = "localhost"; + } + + if (sethostname(hn, strlen(hn)) < 0) { + log_warning("Failed to set hostname to <%s>: %m", hn); + return -errno; + } + + log_info("Set hostname to <%s>.", hn); + return 0; +} diff --git a/src/core/hostname-setup.h b/src/core/hostname-setup.h new file mode 100644 index 0000000..8dc3a9e --- /dev/null +++ b/src/core/hostname-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int hostname_setup(void); diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c new file mode 100644 index 0000000..7f8ec23 --- /dev/null +++ b/src/core/ima-setup.c @@ -0,0 +1,110 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy + TORSEC group -- http://security.polito.it + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ima-setup.h" +#include "mount-setup.h" +#include "macro.h" +#include "util.h" +#include "log.h" +#include "label.h" + +#define IMA_SECFS_DIR "/sys/kernel/security/ima" +#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy" +#define IMA_POLICY_PATH "/etc/ima/ima-policy" + +int ima_setup(void) { + +#ifdef HAVE_IMA + struct stat st; + ssize_t policy_size = 0, written = 0; + char *policy; + int policyfd = -1, imafd = -1; + int result = 0; + + if (stat(IMA_POLICY_PATH, &st) < 0) + return 0; + + policy_size = st.st_size; + if (stat(IMA_SECFS_DIR, &st) < 0) { + log_debug("IMA support is disabled in the kernel, ignoring."); + return 0; + } + + if (stat(IMA_SECFS_POLICY, &st) < 0) { + log_error("Another IMA custom policy has already been loaded, " + "ignoring."); + return 0; + } + + policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC); + if (policyfd < 0) { + log_error("Failed to open the IMA custom policy file %s (%m), " + "ignoring.", IMA_POLICY_PATH); + return 0; + } + + imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC); + if (imafd < 0) { + log_error("Failed to open the IMA kernel interface %s (%m), " + "ignoring.", IMA_SECFS_POLICY); + goto out; + } + + policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0); + if (policy == MAP_FAILED) { + log_error("mmap() failed (%m), freezing"); + result = -errno; + goto out; + } + + written = loop_write(imafd, policy, (size_t)policy_size, false); + if (written != policy_size) { + log_error("Failed to load the IMA custom policy file %s (%m), " + "ignoring.", IMA_POLICY_PATH); + goto out_mmap; + } + + log_info("Successfully loaded the IMA custom policy %s.", + IMA_POLICY_PATH); +out_mmap: + munmap(policy, policy_size); +out: + if (policyfd >= 0) + close_nointr_nofail(policyfd); + if (imafd >= 0) + close_nointr_nofail(imafd); + if (result) + return result; +#endif /* HAVE_IMA */ + + return 0; +} diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h new file mode 100644 index 0000000..14b56d1 --- /dev/null +++ b/src/core/ima-setup.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy + TORSEC group -- http://security.polito.it + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int ima_setup(void); diff --git a/src/core/job.c b/src/core/job.c new file mode 100644 index 0000000..0cd4397 --- /dev/null +++ b/src/core/job.c @@ -0,0 +1,1166 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "set.h" +#include "unit.h" +#include "macro.h" +#include "strv.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "log.h" +#include "dbus-job.h" +#include "special.h" +#include "async.h" +#include "virt.h" +#include "dbus-client-track.h" + +Job* job_new_raw(Unit *unit) { + Job *j; + + /* used for deserialization */ + + assert(unit); + + j = new0(Job, 1); + if (!j) + return NULL; + + j->manager = unit->manager; + j->unit = unit; + j->type = _JOB_TYPE_INVALID; + + return j; +} + +Job* job_new(Unit *unit, JobType type) { + Job *j; + + assert(type < _JOB_TYPE_MAX); + + j = job_new_raw(unit); + if (!j) + return NULL; + + j->id = j->manager->current_job_id++; + j->type = type; + + /* We don't link it here, that's what job_dependency() is for */ + + return j; +} + +void job_free(Job *j) { + assert(j); + assert(!j->installed); + assert(!j->transaction_prev); + assert(!j->transaction_next); + assert(!j->subject_list); + assert(!j->object_list); + + if (j->in_run_queue) + LIST_REMOVE(run_queue, j->manager->run_queue, j); + + if (j->in_dbus_queue) + LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j); + + sd_event_source_unref(j->timer_event_source); + + bus_client_track_free(j->subscribed); + + free(j); +} + +void job_uninstall(Job *j) { + Job **pj; + + assert(j->installed); + + pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; + assert(*pj == j); + + /* Detach from next 'bigger' objects */ + + /* daemon-reload should be transparent to job observers */ + if (j->manager->n_reloading <= 0) + bus_job_send_removed_signal(j); + + *pj = NULL; + + unit_add_to_gc_queue(j->unit); + + hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); + j->installed = false; +} + +static bool job_type_allows_late_merge(JobType t) { + /* Tells whether it is OK to merge a job of type 't' with an already + * running job. + * Reloads cannot be merged this way. Think of the sequence: + * 1. Reload of a daemon is in progress; the daemon has already loaded + * its config file, but hasn't completed the reload operation yet. + * 2. Edit foo's config file. + * 3. Trigger another reload to have the daemon use the new config. + * Should the second reload job be merged into the first one, the daemon + * would not know about the new config. + * JOB_RESTART jobs on the other hand can be merged, because they get + * patched into JOB_START after stopping the unit. So if we see a + * JOB_RESTART running, it means the unit hasn't stopped yet and at + * this time the merge is still allowed. */ + return t != JOB_RELOAD; +} + +static void job_merge_into_installed(Job *j, Job *other) { + assert(j->installed); + assert(j->unit == other->unit); + + if (j->type != JOB_NOP) + job_type_merge_and_collapse(&j->type, other->type, j->unit); + else + assert(other->type == JOB_NOP); + + j->override = j->override || other->override; + j->irreversible = j->irreversible || other->irreversible; + j->ignore_order = j->ignore_order || other->ignore_order; +} + +Job* job_install(Job *j) { + Job **pj; + Job *uj; + + assert(!j->installed); + assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); + + pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; + uj = *pj; + + if (uj) { + if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type)) + job_finish_and_invalidate(uj, JOB_CANCELED, false); + else { + /* not conflicting, i.e. mergeable */ + + if (j->type == JOB_NOP || uj->state == JOB_WAITING || + (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) { + job_merge_into_installed(uj, j); + log_debug_unit(uj->unit->id, + "Merged into installed job %s/%s as %u", + uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + return uj; + } else { + /* already running and not safe to merge into */ + /* Patch uj to become a merged job and re-run it. */ + /* XXX It should be safer to queue j to run after uj finishes, but it is + * not currently possible to have more than one installed job per unit. */ + job_merge_into_installed(uj, j); + log_debug_unit(uj->unit->id, + "Merged into running job, re-running: %s/%s as %u", + uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + uj->state = JOB_WAITING; + uj->manager->n_running_jobs--; + return uj; + } + } + } + + /* Install the job */ + *pj = j; + j->installed = true; + j->manager->n_installed_jobs ++; + log_debug_unit(j->unit->id, + "Installed new job %s/%s as %u", + j->unit->id, job_type_to_string(j->type), (unsigned) j->id); + return j; +} + +int job_install_deserialized(Job *j) { + Job **pj; + + assert(!j->installed); + + if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) { + log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type))); + return -EINVAL; + } + + pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; + + if (*pj) { + log_debug_unit(j->unit->id, + "Unit %s already has a job installed. Not installing deserialized job.", + j->unit->id); + return -EEXIST; + } + *pj = j; + j->installed = true; + log_debug_unit(j->unit->id, + "Reinstalled deserialized job %s/%s as %u", + j->unit->id, job_type_to_string(j->type), (unsigned) j->id); + return 0; +} + +JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { + JobDependency *l; + + assert(object); + + /* Adds a new job link, which encodes that the 'subject' job + * needs the 'object' job in some way. If 'subject' is NULL + * this means the 'anchor' job (i.e. the one the user + * explicitly asked for) is the requester. */ + + if (!(l = new0(JobDependency, 1))) + return NULL; + + l->subject = subject; + l->object = object; + l->matters = matters; + l->conflicts = conflicts; + + if (subject) + LIST_PREPEND(subject, subject->subject_list, l); + + LIST_PREPEND(object, object->object_list, l); + + return l; +} + +void job_dependency_free(JobDependency *l) { + assert(l); + + if (l->subject) + LIST_REMOVE(subject, l->subject->subject_list, l); + + LIST_REMOVE(object, l->object->object_list, l); + + free(l); +} + +void job_dump(Job *j, FILE*f, const char *prefix) { + assert(j); + assert(f); + + if (!prefix) + prefix = ""; + + fprintf(f, + "%s-> Job %u:\n" + "%s\tAction: %s -> %s\n" + "%s\tState: %s\n" + "%s\tForced: %s\n" + "%s\tIrreversible: %s\n", + prefix, j->id, + prefix, j->unit->id, job_type_to_string(j->type), + prefix, job_state_to_string(j->state), + prefix, yes_no(j->override), + prefix, yes_no(j->irreversible)); +} + +/* + * Merging is commutative, so imagine the matrix as symmetric. We store only + * its lower triangle to avoid duplication. We don't store the main diagonal, + * because A merged with A is simply A. + * + * If the resulting type is collapsed immediately afterwards (to get rid of + * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain), + * the following properties hold: + * + * Merging is associative! A merged with B merged with C is the same as + * A merged with C merged with B. + * + * Mergeability is transitive! If A can be merged with B and B with C then + * A also with C. + * + * Also, if A merged with B cannot be merged with C, then either A or B cannot + * be merged with C either. + */ +static const JobType job_merging_table[] = { +/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */ +/*********************************************************************************/ +/*JOB_START */ +/*JOB_VERIFY_ACTIVE */ JOB_START, +/*JOB_STOP */ -1, -1, +/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1, +/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, +}; + +JobType job_type_lookup_merge(JobType a, JobType b) { + assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2); + assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING); + assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING); + + if (a == b) + return a; + + if (a < b) { + JobType tmp = a; + a = b; + b = tmp; + } + + return job_merging_table[(a - 1) * a / 2 + b]; +} + +bool job_type_is_redundant(JobType a, UnitActiveState b) { + switch (a) { + + case JOB_START: + return + b == UNIT_ACTIVE || + b == UNIT_RELOADING; + + case JOB_STOP: + return + b == UNIT_INACTIVE || + b == UNIT_FAILED; + + case JOB_VERIFY_ACTIVE: + return + b == UNIT_ACTIVE || + b == UNIT_RELOADING; + + case JOB_RELOAD: + return + b == UNIT_RELOADING; + + case JOB_RESTART: + return + b == UNIT_ACTIVATING; + + default: + assert_not_reached("Invalid job type"); + } +} + +void job_type_collapse(JobType *t, Unit *u) { + UnitActiveState s; + + switch (*t) { + + case JOB_TRY_RESTART: + s = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) + *t = JOB_NOP; + else + *t = JOB_RESTART; + break; + + case JOB_RELOAD_OR_START: + s = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) + *t = JOB_START; + else + *t = JOB_RELOAD; + break; + + default: + ; + } +} + +int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) { + JobType t = job_type_lookup_merge(*a, b); + if (t < 0) + return -EEXIST; + *a = t; + job_type_collapse(a, u); + return 0; +} + +static bool job_is_runnable(Job *j) { + Iterator i; + Unit *other; + + assert(j); + assert(j->installed); + + /* Checks whether there is any job running for the units this + * job needs to be running after (in the case of a 'positive' + * job type) or before (in the case of a 'negative' job + * type. */ + + /* Note that unit types have a say in what is runnable, + * too. For example, if they return -EAGAIN from + * unit_start() they can indicate they are not + * runnable yet. */ + + /* First check if there is an override */ + if (j->ignore_order) + return true; + + if (j->type == JOB_NOP) + return true; + + if (j->type == JOB_START || + j->type == JOB_VERIFY_ACTIVE || + j->type == JOB_RELOAD) { + + /* Immediate result is that the job is or might be + * started. In this case lets wait for the + * dependencies, regardless whether they are + * starting or stopping something. */ + + SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) + if (other->job) + return false; + } + + /* Also, if something else is being stopped and we should + * change state after it, then lets wait. */ + + SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) + if (other->job && + (other->job->type == JOB_STOP || + other->job->type == JOB_RESTART)) + return false; + + /* This means that for a service a and a service b where b + * shall be started after a: + * + * start a + start b → 1st step start a, 2nd step start b + * start a + stop b → 1st step stop b, 2nd step start a + * stop a + start b → 1st step stop a, 2nd step start b + * stop a + stop b → 1st step stop b, 2nd step stop a + * + * This has the side effect that restarts are properly + * synchronized too. */ + + return true; +} + +static void job_change_type(Job *j, JobType newtype) { + log_debug_unit(j->unit->id, + "Converting job %s/%s -> %s/%s", + j->unit->id, job_type_to_string(j->type), + j->unit->id, job_type_to_string(newtype)); + + j->type = newtype; +} + +int job_run_and_invalidate(Job *j) { + int r; + uint32_t id; + Manager *m = j->manager; + + assert(j); + assert(j->installed); + assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); + assert(j->in_run_queue); + + LIST_REMOVE(run_queue, j->manager->run_queue, j); + j->in_run_queue = false; + + if (j->state != JOB_WAITING) + return 0; + + if (!job_is_runnable(j)) + return -EAGAIN; + + j->state = JOB_RUNNING; + m->n_running_jobs++; + job_add_to_dbus_queue(j); + + /* While we execute this operation the job might go away (for + * example: because it is replaced by a new, conflicting + * job.) To make sure we don't access a freed job later on we + * store the id here, so that we can verify the job is still + * valid. */ + id = j->id; + + switch (j->type) { + + case JOB_START: + r = unit_start(j->unit); + + /* If this unit cannot be started, then simply wait */ + if (r == -EBADR) + r = 0; + break; + + case JOB_VERIFY_ACTIVE: { + UnitActiveState t = unit_active_state(j->unit); + if (UNIT_IS_ACTIVE_OR_RELOADING(t)) + r = -EALREADY; + else if (t == UNIT_ACTIVATING) + r = -EAGAIN; + else + r = -EBADR; + break; + } + + case JOB_STOP: + case JOB_RESTART: + r = unit_stop(j->unit); + + /* If this unit cannot stopped, then simply wait. */ + if (r == -EBADR) + r = 0; + break; + + case JOB_RELOAD: + r = unit_reload(j->unit); + break; + + case JOB_NOP: + r = -EALREADY; + break; + + default: + assert_not_reached("Unknown job type"); + } + + j = manager_get_job(m, id); + if (j) { + if (r == -EALREADY) + r = job_finish_and_invalidate(j, JOB_DONE, true); + else if (r == -EBADR) + r = job_finish_and_invalidate(j, JOB_SKIPPED, true); + else if (r == -ENOEXEC) + r = job_finish_and_invalidate(j, JOB_INVALID, true); + else if (r == -EAGAIN) { + j->state = JOB_WAITING; + m->n_running_jobs--; + } else if (r < 0) + r = job_finish_and_invalidate(j, JOB_FAILED, true); + } + + return r; +} + +_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) { + const UnitStatusMessageFormats *format_table; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + format_table = &UNIT_VTABLE(u)->status_message_formats; + if (!format_table) + return NULL; + + if (t == JOB_START) + return format_table->finished_start_job[result]; + else if (t == JOB_STOP || t == JOB_RESTART) + return format_table->finished_stop_job[result]; + + return NULL; +} + +_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) { + const char *format; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + format = job_get_status_message_format(u, t, result); + if (format) + return format; + + /* Return generic strings */ + if (t == JOB_START) { + if (result == JOB_DONE) + return "Started %s."; + else if (result == JOB_FAILED) + return "Failed to start %s."; + else if (result == JOB_DEPENDENCY) + return "Dependency failed for %s."; + else if (result == JOB_TIMEOUT) + return "Timed out starting %s."; + } else if (t == JOB_STOP || t == JOB_RESTART) { + if (result == JOB_DONE) + return "Stopped %s."; + else if (result == JOB_FAILED) + return "Stopped (with error) %s."; + else if (result == JOB_TIMEOUT) + return "Timed out stoppping %s."; + } else if (t == JOB_RELOAD) { + if (result == JOB_DONE) + return "Reloaded %s."; + else if (result == JOB_FAILED) + return "Reload failed for %s."; + else if (result == JOB_TIMEOUT) + return "Timed out reloading %s."; + } + + return NULL; +} + +static void job_print_status_message(Unit *u, JobType t, JobResult result) { + const char *format; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + DISABLE_WARNING_FORMAT_NONLITERAL; + + if (t == JOB_START) { + format = job_get_status_message_format(u, t, result); + if (!format) + return; + + switch (result) { + + case JOB_DONE: + if (u->condition_result) + unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format); + break; + + case JOB_FAILED: + manager_flip_auto_status(u->manager, true); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format); + manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id); + break; + + case JOB_DEPENDENCY: + manager_flip_auto_status(u->manager, true); + unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format); + break; + + case JOB_TIMEOUT: + manager_flip_auto_status(u->manager, true); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format); + break; + + default: + ; + } + + } else if (t == JOB_STOP || t == JOB_RESTART) { + + format = job_get_status_message_format(u, t, result); + if (!format) + return; + + switch (result) { + + case JOB_TIMEOUT: + manager_flip_auto_status(u->manager, true); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format); + break; + + case JOB_DONE: + case JOB_FAILED: + unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format); + break; + + default: + ; + } + + } else if (t == JOB_VERIFY_ACTIVE) { + + /* When verify-active detects the unit is inactive, report it. + * Most likely a DEPEND warning from a requisiting unit will + * occur next and it's nice to see what was requisited. */ + if (result == JOB_SKIPPED) + unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active."); + } + + REENABLE_WARNING; +} + +static void job_log_status_message(Unit *u, JobType t, JobResult result) { + const char *format; + char buf[LINE_MAX]; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + /* Skip this if it goes to the console. since we already print + * to the console anyway... */ + + if (log_on_console()) + return; + + format = job_get_status_message_format_try_harder(u, t, result); + if (!format) + return; + + DISABLE_WARNING_FORMAT_NONLITERAL; + snprintf(buf, sizeof(buf), format, unit_description(u)); + char_array_0(buf); + REENABLE_WARNING; + + if (t == JOB_START) { + sd_id128_t mid; + + mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED; + log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR, + u->id, + MESSAGE_ID(mid), + "RESULT=%s", job_result_to_string(result), + "MESSAGE=%s", buf, + NULL); + + } else if (t == JOB_STOP) + log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR, + u->id, + MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED), + "RESULT=%s", job_result_to_string(result), + "MESSAGE=%s", buf, + NULL); + + else if (t == JOB_RELOAD) + log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR, + u->id, + MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED), + "RESULT=%s", job_result_to_string(result), + "MESSAGE=%s", buf, + NULL); +} + +int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + Unit *u; + Unit *other; + JobType t; + Iterator i; + + assert(j); + assert(j->installed); + assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION); + + u = j->unit; + t = j->type; + + j->result = result; + + if (j->state == JOB_RUNNING) + j->manager->n_running_jobs--; + + log_debug_unit(u->id, "Job %s/%s finished, result=%s", + u->id, job_type_to_string(t), job_result_to_string(result)); + + job_print_status_message(u, t, result); + job_log_status_message(u, t, result); + + job_add_to_dbus_queue(j); + + /* Patch restart jobs so that they become normal start jobs */ + if (result == JOB_DONE && t == JOB_RESTART) { + + job_change_type(j, JOB_START); + j->state = JOB_WAITING; + + job_add_to_run_queue(j); + + goto finish; + } + + if (result == JOB_FAILED || result == JOB_INVALID) + j->manager->n_failed_jobs ++; + + job_uninstall(j); + job_free(j); + + /* Fail depending jobs on failure */ + if (result != JOB_DONE && recursive) { + + if (t == JOB_START || + t == JOB_VERIFY_ACTIVE) { + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) + job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); + + SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) + job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) + if (other->job && + !other->job->override && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) + job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); + + } else if (t == JOB_STOP) { + + SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i) + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) + job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); + } + } + + /* 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 + * unit itself. */ + if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) { + log_struct_unit(LOG_NOTICE, + u->id, + "JOB_TYPE=%s", job_type_to_string(t), + "JOB_RESULT=%s", job_result_to_string(result), + "Job %s/%s failed with result '%s'.", + u->id, + job_type_to_string(t), + job_result_to_string(result), + NULL); + + unit_start_on_failure(u); + } + + unit_trigger_notify(u); + +finish: + /* Try to start the next jobs that can be started */ + SET_FOREACH(other, u->dependencies[UNIT_AFTER], i) + if (other->job) + job_add_to_run_queue(other->job); + SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i) + if (other->job) + job_add_to_run_queue(other->job); + + manager_check_finished(u->manager); + + return 0; +} + +static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) { + Job *j = userdata; + + assert(j); + assert(s == j->timer_event_source); + + log_warning_unit(j->unit->id, "Job %s/%s timed out.", + j->unit->id, job_type_to_string(j->type)); + + job_finish_and_invalidate(j, JOB_TIMEOUT, true); + return 0; +} + +int job_start_timer(Job *j) { + int r; + + if (j->timer_event_source) + return 0; + + j->begin_usec = now(CLOCK_MONOTONIC); + + if (j->unit->job_timeout <= 0) + return 0; + + r = sd_event_add_monotonic(j->manager->event, &j->timer_event_source, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j); + if (r < 0) + return r; + + return 0; +} + +void job_add_to_run_queue(Job *j) { + assert(j); + assert(j->installed); + + if (j->in_run_queue) + return; + + if (!j->manager->run_queue) + sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT); + + LIST_PREPEND(run_queue, j->manager->run_queue, j); + j->in_run_queue = true; +} + +void job_add_to_dbus_queue(Job *j) { + assert(j); + assert(j->installed); + + if (j->in_dbus_queue) + return; + + /* We don't check if anybody is subscribed here, since this + * job might just have been created and not yet assigned to a + * connection/client. */ + + LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j); + j->in_dbus_queue = true; +} + +char *job_dbus_path(Job *j) { + char *p; + + assert(j); + + if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0) + return NULL; + + return p; +} + +int job_serialize(Job *j, FILE *f, FDSet *fds) { + fprintf(f, "job-id=%u\n", j->id); + fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); + fprintf(f, "job-state=%s\n", job_state_to_string(j->state)); + fprintf(f, "job-override=%s\n", yes_no(j->override)); + fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible)); + fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal)); + fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order)); + + if (j->begin_usec > 0) + fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec); + + bus_client_track_serialize(j->manager, f, j->subscribed); + + /* End marker */ + fputc('\n', f); + return 0; +} + +int job_deserialize(Job *j, FILE *f, FDSet *fds) { + assert(j); + + for (;;) { + char line[LINE_MAX], *l, *v; + size_t k; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + return 0; + return -errno; + } + + char_array_0(line); + l = strstrip(line); + + /* End marker */ + if (l[0] == 0) + return 0; + + k = strcspn(l, "="); + + if (l[k] == '=') { + l[k] = 0; + v = l+k+1; + } else + v = l+k; + + if (streq(l, "job-id")) { + + if (safe_atou32(v, &j->id) < 0) + log_debug("Failed to parse job id value %s", v); + + } else if (streq(l, "job-type")) { + JobType t; + + t = job_type_from_string(v); + if (t < 0) + log_debug("Failed to parse job type %s", v); + else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION) + log_debug("Cannot deserialize job of type %s", v); + else + j->type = t; + + } else if (streq(l, "job-state")) { + JobState s; + + s = job_state_from_string(v); + if (s < 0) + log_debug("Failed to parse job state %s", v); + else + j->state = s; + + } else if (streq(l, "job-override")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse job override flag %s", v); + else + j->override = j->override || b; + + } else if (streq(l, "job-irreversible")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse job irreversible flag %s", v); + else + j->irreversible = j->irreversible || b; + + } else if (streq(l, "job-sent-dbus-new-signal")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse job sent_dbus_new_signal flag %s", v); + else + j->sent_dbus_new_signal = j->sent_dbus_new_signal || b; + + } else if (streq(l, "job-ignore-order")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse job ignore_order flag %s", v); + else + j->ignore_order = j->ignore_order || b; + + } else if (streq(l, "job-begin")) { + unsigned long long ull; + + if (sscanf(v, "%llu", &ull) != 1) + log_debug("Failed to parse job-begin value %s", v); + else + j->begin_usec = ull; + + } else { + char t[strlen(l) + 1 + strlen(v) + 1]; + + strcpy(stpcpy(stpcpy(t, l), "="), v); + + if (bus_client_track_deserialize_item(j->manager, &j->subscribed, t) == 0) + log_debug("Unknown deserialization key '%s'", l); + } + } +} + +int job_coldplug(Job *j) { + int r; + + assert(j); + + if (j->begin_usec == 0 || j->unit->job_timeout == 0) + return 0; + + if (j->timer_event_source) + j->timer_event_source = sd_event_source_unref(j->timer_event_source); + + r = sd_event_add_monotonic(j->manager->event, &j->timer_event_source, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j); + if (r < 0) + log_debug("Failed to restart timeout for job: %s", strerror(-r)); + + return r; +} + +void job_shutdown_magic(Job *j) { + assert(j); + + /* The shutdown target gets some special treatment here: we + * tell the kernel to begin with flushing its disk caches, to + * optimize shutdown time a bit. Ideally we wouldn't hardcode + * this magic into PID 1. However all other processes aren't + * options either since they'd exit much sooner than PID 1 and + * asynchronous sync() would cause their exit to be + * delayed. */ + + if (j->type != JOB_START) + return; + + if (j->unit->manager->running_as != SYSTEMD_SYSTEM) + return; + + if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET)) + return; + + /* In case messages on console has been disabled on boot */ + j->unit->manager->no_console_output = false; + + if (detect_container(NULL) > 0) + return; + + asynchronous_sync(); +} + +int job_get_timeout(Job *j, uint64_t *timeout) { + Unit *u = j->unit; + uint64_t x = -1, y = -1; + int r = 0, q = 0; + + assert(u); + + if (j->timer_event_source) { + r = sd_event_source_get_time(j->timer_event_source, &x); + if (r < 0) + return r; + r = 1; + } + + if (UNIT_VTABLE(u)->get_timeout) { + q = UNIT_VTABLE(u)->get_timeout(u, &y); + if (q < 0) + return q; + } + + if (r == 0 && q == 0) + return 0; + + *timeout = MIN(x, y); + + return 1; +} + +static const char* const job_state_table[_JOB_STATE_MAX] = { + [JOB_WAITING] = "waiting", + [JOB_RUNNING] = "running" +}; + +DEFINE_STRING_TABLE_LOOKUP(job_state, JobState); + +static const char* const job_type_table[_JOB_TYPE_MAX] = { + [JOB_START] = "start", + [JOB_VERIFY_ACTIVE] = "verify-active", + [JOB_STOP] = "stop", + [JOB_RELOAD] = "reload", + [JOB_RELOAD_OR_START] = "reload-or-start", + [JOB_RESTART] = "restart", + [JOB_TRY_RESTART] = "try-restart", + [JOB_NOP] = "nop", +}; + +DEFINE_STRING_TABLE_LOOKUP(job_type, JobType); + +static const char* const job_mode_table[_JOB_MODE_MAX] = { + [JOB_FAIL] = "fail", + [JOB_REPLACE] = "replace", + [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly", + [JOB_ISOLATE] = "isolate", + [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies", + [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements", + [JOB_FLUSH] = "flush", +}; + +DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode); + +static const char* const job_result_table[_JOB_RESULT_MAX] = { + [JOB_DONE] = "done", + [JOB_CANCELED] = "canceled", + [JOB_TIMEOUT] = "timeout", + [JOB_FAILED] = "failed", + [JOB_DEPENDENCY] = "dependency", + [JOB_SKIPPED] = "skipped", + [JOB_INVALID] = "invalid", +}; + +DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult); diff --git a/src/core/job.h b/src/core/job.h new file mode 100644 index 0000000..8cc3a02 --- /dev/null +++ b/src/core/job.h @@ -0,0 +1,226 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +typedef struct Job Job; +typedef struct JobDependency JobDependency; +typedef enum JobType JobType; +typedef enum JobState JobState; +typedef enum JobMode JobMode; +typedef enum JobResult JobResult; + +/* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */ +enum JobType { + JOB_START, /* if a unit does not support being started, we'll just wait until it becomes active */ + JOB_VERIFY_ACTIVE, + + JOB_STOP, + + JOB_RELOAD, /* if running, reload */ + + /* Note that restarts are first treated like JOB_STOP, but + * then instead of finishing are patched to become + * JOB_START. */ + JOB_RESTART, /* If running, stop. Then start unconditionally. */ + + _JOB_TYPE_MAX_MERGING, + + /* JOB_NOP can enter into a transaction, but as it won't pull in + * any dependencies, it won't have to merge with anything. + * job_install() avoids the problem of merging JOB_NOP too (it's + * special-cased, only merges with other JOB_NOPs). */ + JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */ + + _JOB_TYPE_MAX_IN_TRANSACTION, + + /* JOB_TRY_RESTART can never appear in a transaction, because + * it always collapses into JOB_RESTART or JOB_NOP before entering. + * Thus we never need to merge it with anything. */ + JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */ + + /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result + * from transaction merging (there's no way for JOB_RELOAD and + * JOB_START to meet in one transaction). It can result from a merge + * during job installation, but then it will immediately collapse into + * one of the two simpler types. */ + JOB_RELOAD_OR_START, /* if running, reload, otherwise start */ + + _JOB_TYPE_MAX, + _JOB_TYPE_INVALID = -1 +}; + +enum JobState { + JOB_WAITING, + JOB_RUNNING, + _JOB_STATE_MAX, + _JOB_STATE_INVALID = -1 +}; + +enum JobMode { + JOB_FAIL, /* Fail if a conflicting job is already queued */ + JOB_REPLACE, /* Replace an existing conflicting job */ + JOB_REPLACE_IRREVERSIBLY,/* Like JOB_REPLACE + produce irreversible jobs */ + JOB_ISOLATE, /* Start a unit, and stop all others */ + JOB_FLUSH, /* Flush out all other queued jobs when queing this one */ + JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */ + JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */ + _JOB_MODE_MAX, + _JOB_MODE_INVALID = -1 +}; + +enum JobResult { + JOB_DONE, /* Job completed successfully */ + JOB_CANCELED, /* Job canceled by a conflicting job installation or by explicit cancel request */ + JOB_TIMEOUT, /* JobTimeout elapsed */ + JOB_FAILED, /* Job failed */ + JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */ + JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE */ + JOB_INVALID, /* JOB_RELOAD of inactive unit */ + _JOB_RESULT_MAX, + _JOB_RESULT_INVALID = -1 +}; + +#include "sd-event.h" +#include "manager.h" +#include "unit.h" +#include "hashmap.h" +#include "list.h" + +struct JobDependency { + /* Encodes that the 'subject' job needs the 'object' job in + * some way. This structure is used only while building a transaction. */ + Job *subject; + Job *object; + + LIST_FIELDS(JobDependency, subject); + LIST_FIELDS(JobDependency, object); + + bool matters; + bool conflicts; +}; + +struct Job { + Manager *manager; + Unit *unit; + + LIST_FIELDS(Job, transaction); + LIST_FIELDS(Job, run_queue); + LIST_FIELDS(Job, dbus_queue); + + LIST_HEAD(JobDependency, subject_list); + LIST_HEAD(JobDependency, object_list); + + /* Used for graph algs as a "I have been here" marker */ + Job* marker; + unsigned generation; + + uint32_t id; + + JobType type; + JobState state; + + sd_event_source *timer_event_source; + usec_t begin_usec; + + /* There can be more than one client, because of job merging. */ + Set *subscribed; + + JobResult result; + + bool installed:1; + bool in_run_queue:1; + bool matters_to_anchor:1; + bool override:1; + bool in_dbus_queue:1; + bool sent_dbus_new_signal:1; + bool ignore_order:1; + bool irreversible:1; +}; + +Job* job_new(Unit *unit, JobType type); +Job* job_new_raw(Unit *unit); +void job_free(Job *job); +Job* job_install(Job *j); +int job_install_deserialized(Job *j); +void job_uninstall(Job *j); +void job_dump(Job *j, FILE*f, const char *prefix); +int job_serialize(Job *j, FILE *f, FDSet *fds); +int job_deserialize(Job *j, FILE *f, FDSet *fds); +int job_coldplug(Job *j); + +JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); +void job_dependency_free(JobDependency *l); + +int job_merge(Job *j, Job *other); + +JobType job_type_lookup_merge(JobType a, JobType b) _pure_; + +_pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) { + return job_type_lookup_merge(a, b) >= 0; +} + +_pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) { + return !job_type_is_mergeable(a, b); +} + +_pure_ static inline bool job_type_is_superset(JobType a, JobType b) { + /* Checks whether operation a is a "superset" of b in its actions */ + return a == job_type_lookup_merge(a, b); +} + +bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_; + +/* Collapses a state-dependent job type into a simpler type by observing + * the state of the unit which it is going to be applied to. */ +void job_type_collapse(JobType *t, Unit *u); + +int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u); + +void job_add_to_run_queue(Job *j); +void job_add_to_dbus_queue(Job *j); + +int job_start_timer(Job *j); + +int job_run_and_invalidate(Job *j); +int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); + +char *job_dbus_path(Job *j); + +void job_shutdown_magic(Job *j); + +const char* job_type_to_string(JobType t) _const_; +JobType job_type_from_string(const char *s) _pure_; + +const char* job_state_to_string(JobState t) _const_; +JobState job_state_from_string(const char *s) _pure_; + +const char* job_mode_to_string(JobMode t) _const_; +JobMode job_mode_from_string(const char *s) _pure_; + +const char* job_result_to_string(JobResult t) _const_; +JobResult job_result_from_string(const char *s) _pure_; + +int job_get_timeout(Job *j, uint64_t *timeout) _pure_; diff --git a/src/core/kill.c b/src/core/kill.c new file mode 100644 index 0000000..4271346 --- /dev/null +++ b/src/core/kill.c @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "kill.h" +#include "util.h" + +void kill_context_init(KillContext *c) { + assert(c); + + c->kill_signal = SIGTERM; + c->send_sigkill = true; + c->send_sighup = false; +} + +void kill_context_dump(KillContext *c, FILE *f, const char *prefix) { + assert(c); + + if (!prefix) + prefix = ""; + + fprintf(f, + "%sKillMode: %s\n" + "%sKillSignal: SIG%s\n" + "%sSendSIGKILL: %s\n" + "%sSendSIGHUP: %s\n", + prefix, kill_mode_to_string(c->kill_mode), + prefix, signal_to_string(c->kill_signal), + prefix, yes_no(c->send_sigkill), + prefix, yes_no(c->send_sighup)); +} + +static const char* const kill_mode_table[_KILL_MODE_MAX] = { + [KILL_CONTROL_GROUP] = "control-group", + [KILL_PROCESS] = "process", + [KILL_MIXED] = "mixed", + [KILL_NONE] = "none" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode); + +static const char* const kill_who_table[_KILL_WHO_MAX] = { + [KILL_MAIN] = "main", + [KILL_CONTROL] = "control", + [KILL_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/core/kill.h b/src/core/kill.h new file mode 100644 index 0000000..d5f125f --- /dev/null +++ b/src/core/kill.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct KillContext KillContext; + +#include +#include + +#include "macro.h" + +typedef enum KillMode { + /* The kill mode is a property of a unit. */ + KILL_CONTROL_GROUP = 0, + KILL_PROCESS, + KILL_MIXED, + KILL_NONE, + _KILL_MODE_MAX, + _KILL_MODE_INVALID = -1 +} KillMode; + +struct KillContext { + KillMode kill_mode; + int kill_signal; + bool send_sigkill; + bool send_sighup; +}; + +typedef enum KillWho { + /* Kill who is a property of an operation */ + KILL_MAIN, + KILL_CONTROL, + KILL_ALL, + _KILL_WHO_MAX, + _KILL_WHO_INVALID = -1 +} KillWho; + +void kill_context_init(KillContext *c); +void kill_context_dump(KillContext *c, FILE *f, const char *prefix); + +const char *kill_mode_to_string(KillMode k) _const_; +KillMode kill_mode_from_string(const char *s) _pure_; + +const char *kill_who_to_string(KillWho k) _const_; +KillWho kill_who_from_string(const char *s) _pure_; diff --git a/src/core/killall.c b/src/core/killall.c new file mode 100644 index 0000000..57ed41c --- /dev/null +++ b/src/core/killall.c @@ -0,0 +1,228 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 ProFUSION embedded systems + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "def.h" +#include "killall.h" +#include "set.h" + +#define TIMEOUT_USEC (10 * USEC_PER_SEC) + +static bool ignore_proc(pid_t pid) { + _cleanup_fclose_ FILE *f = NULL; + char c; + const char *p; + size_t count; + uid_t uid; + int r; + + /* We are PID 1, let's not commit suicide */ + if (pid == 1) + return true; + + r = get_process_uid(pid, &uid); + if (r < 0) + return true; /* not really, but better safe than sorry */ + + /* Non-root processes otherwise are always subject to be killed */ + if (uid != 0) + return false; + + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); + if (!f) + return true; /* not really, but has the desired effect */ + + count = fread(&c, 1, 1, f); + + /* Kernel threads have an empty cmdline */ + if (count <= 0) + return true; + + /* Processes with argv[0][0] = '@' we ignore from the killing + * spree. + * + * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */ + if (count == 1 && c == '@') + return true; + + return false; +} + +static void wait_for_children(Set *pids, sigset_t *mask) { + usec_t until; + + assert(mask); + + if (set_isempty(pids)) + return; + + until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC; + for (;;) { + struct timespec ts; + int k; + usec_t n; + void *p; + Iterator i; + + /* First, let the kernel inform us about killed + * children. Most processes will probably be our + * children, but some are not (might be our + * grandchildren instead...). */ + for (;;) { + pid_t pid; + + pid = waitpid(-1, NULL, WNOHANG); + if (pid == 0) + break; + if (pid < 0) { + if (errno == ECHILD) + break; + + log_error("waitpid() failed: %m"); + return; + } + + set_remove(pids, ULONG_TO_PTR(pid)); + } + + /* Now explicitly check who might be remaining, who + * might not be our child. */ + SET_FOREACH(p, pids, i) { + + /* We misuse getpgid as a check whether a + * process still exists. */ + if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0) + continue; + + if (errno != ESRCH) + continue; + + set_remove(pids, p); + } + + if (set_isempty(pids)) + return; + + n = now(CLOCK_MONOTONIC); + if (n >= until) + return; + + timespec_store(&ts, until - n); + k = sigtimedwait(mask, NULL, &ts); + if (k != SIGCHLD) { + + if (k < 0 && errno != EAGAIN) { + log_error("sigtimedwait() failed: %m"); + return; + } + + if (k >= 0) + log_warning("sigtimedwait() returned unexpected signal."); + } + } +} + +static int killall(int sig, Set *pids, bool send_sighup) { + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *d; + + dir = opendir("/proc"); + if (!dir) + return -errno; + + while ((d = readdir(dir))) { + pid_t pid; + + if (d->d_type != DT_DIR && + d->d_type != DT_UNKNOWN) + continue; + + if (parse_pid(d->d_name, &pid) < 0) + continue; + + if (ignore_proc(pid)) + continue; + + if (sig == SIGKILL) { + _cleanup_free_ char *s; + + get_process_comm(pid, &s); + log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s)); + } + + if (kill(pid, sig) >= 0) { + if (pids) + set_put(pids, ULONG_TO_PTR(pid)); + } else if (errno != ENOENT) + log_warning("Could not kill %d: %m", pid); + + if (send_sighup) { + /* Optionally, also send a SIGHUP signal, but + only if the process has a controlling + tty. This is useful to allow handling of + shells which ignore SIGTERM but react to + SIGHUP. We do not send this to processes that + have no controlling TTY since we don't want to + trigger reloads of daemon processes. Also we + make sure to only send this after SIGTERM so + that SIGTERM is always first in the queue. */ + + + if (get_ctty_devnr(pid, NULL) >= 0) + kill(pid, SIGHUP); + } + } + + return set_size(pids); +} + +void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) { + sigset_t mask, oldmask; + Set *pids = NULL; + + if (wait_for_exit) + pids = set_new(trivial_hash_func, trivial_compare_func); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); + assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); + + if (kill(-1, SIGSTOP) < 0 && errno != ESRCH) + log_warning("kill(-1, SIGSTOP) failed: %m"); + + killall(sig, pids, send_sighup); + + if (kill(-1, SIGCONT) < 0 && errno != ESRCH) + log_warning("kill(-1, SIGCONT) failed: %m"); + + if (wait_for_exit) + wait_for_children(pids, &mask); + + assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); + + set_free(pids); +} diff --git a/src/core/killall.h b/src/core/killall.h new file mode 100644 index 0000000..986cf43 --- /dev/null +++ b/src/core/killall.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup); diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c new file mode 100644 index 0000000..0791ae8 --- /dev/null +++ b/src/core/kmod-setup.c @@ -0,0 +1,123 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "macro.h" +#include "execute.h" + +#include "kmod-setup.h" + +static void systemd_kmod_log( + void *data, + int priority, + const char *file, int line, + const char *fn, + const char *format, + va_list args) { + + /* library logging is enabled at debug only */ + DISABLE_WARNING_FORMAT_NONLITERAL; + log_metav(LOG_DEBUG, file, line, fn, format, args); + REENABLE_WARNING; +} + +static bool cmdline_check_kdbus(void) { + _cleanup_free_ char *line = NULL; + + if (proc_cmdline(&line) <= 0) + return false; + + return strstr(line, "kdbus") != NULL; +} + +int kmod_setup(void) { + static const struct { + const char *module; + const char *path; + bool warn; + bool (*condition_fn)(void); + } kmod_table[] = { + /* auto-loading on use doesn't work before udev is up */ + { "autofs4", "/sys/class/misc/autofs", true, NULL }, + + /* early configure of ::1 on the loopback device */ + { "ipv6", "/sys/module/ipv6", true, NULL }, + + /* this should never be a module */ + { "unix", "/proc/net/unix", true, NULL }, + + /* IPC is needed before we bring up any other services */ + { "kdbus", "/sys/bus/kdbus", false, cmdline_check_kdbus }, + }; + struct kmod_ctx *ctx = NULL; + unsigned int i; + int r; + + for (i = 0; i < ELEMENTSOF(kmod_table); i++) { + struct kmod_module *mod; + + if (kmod_table[i].path && access(kmod_table[i].path, F_OK) >= 0) + continue; + + if (kmod_table[i].condition_fn && !kmod_table[i].condition_fn()) + continue; + + if (kmod_table[i].warn) + log_debug("Your kernel apparently lacks built-in %s support. Might be " + "a good idea to compile it in. We'll now try to work around " + "this by loading the module...", kmod_table[i].module); + + if (!ctx) { + ctx = kmod_new(NULL, NULL); + if (!ctx) + return log_oom(); + + kmod_set_log_fn(ctx, systemd_kmod_log, NULL); + kmod_load_resources(ctx); + } + + r = kmod_module_new_from_name(ctx, kmod_table[i].module, &mod); + if (r < 0) { + log_error("Failed to lookup module '%s'", kmod_table[i].module); + continue; + } + + r = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL); + if (r == 0) + log_info("Inserted module '%s'", kmod_module_get_name(mod)); + else if (r == KMOD_PROBE_APPLY_BLACKLIST) + log_info("Module '%s' is blacklisted", kmod_module_get_name(mod)); + else if (kmod_table[i].warn) + log_error("Failed to insert module '%s'", kmod_module_get_name(mod)); + + kmod_module_unref(mod); + } + + if (ctx) + kmod_unref(ctx); + + return 0; +} diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h new file mode 100644 index 0000000..24dcddd --- /dev/null +++ b/src/core/kmod-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int kmod_setup(void); diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c new file mode 100644 index 0000000..546e560 --- /dev/null +++ b/src/core/load-dropin.c @@ -0,0 +1,214 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "unit.h" +#include "load-dropin.h" +#include "log.h" +#include "strv.h" +#include "unit-name.h" +#include "conf-parser.h" +#include "load-fragment.h" +#include "conf-files.h" + +static int iterate_dir( + Unit *u, + const char *path, + UnitDependency dependency, + char ***strv) { + + _cleanup_closedir_ DIR *d = NULL; + int r; + + assert(u); + assert(path); + + /* The config directories are special, since the order of the + * drop-ins matters */ + if (dependency < 0) { + r = strv_extend(strv, path); + if (r < 0) + return log_oom(); + + return 0; + } + + d = opendir(path); + if (!d) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + for (;;) { + struct dirent *de; + _cleanup_free_ char *f = NULL; + int k; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + k = errno; + log_error("Failed to read directory %s: %s", path, strerror(k)); + return -k; + } + + if (!de) + break; + + if (ignore_file(de->d_name)) + continue; + + f = strjoin(path, "/", de->d_name, NULL); + if (!f) + return log_oom(); + + r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true); + if (r < 0) + log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r)); + } + + return 0; +} + +static int process_dir( + Unit *u, + const char *unit_path, + const char *name, + const char *suffix, + UnitDependency dependency, + char ***strv) { + + _cleanup_free_ char *path = NULL; + int r; + + assert(u); + assert(unit_path); + assert(name); + assert(suffix); + + path = strjoin(unit_path, "/", name, suffix, NULL); + if (!path) + return log_oom(); + + if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, path)) { + r = iterate_dir(u, path, dependency, strv); + if (r < 0) + return r; + } + + if (u->instance) { + _cleanup_free_ char *template = NULL, *p = NULL; + /* Also try the template dir */ + + template = unit_name_template(name); + if (!template) + return log_oom(); + + p = strjoin(unit_path, "/", template, suffix, NULL); + if (!p) + return log_oom(); + + if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, p)) { + r = iterate_dir(u, p, dependency, strv); + if (r < 0) + return r; + } + } + + return 0; +} + +char **unit_find_dropin_paths(Unit *u) { + _cleanup_strv_free_ char **strv = NULL; + char **configs = NULL; + Iterator i; + char *t; + int r; + + assert(u); + + SET_FOREACH(t, u->names, i) { + char **p; + + STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { + /* This loads the drop-in config snippets */ + r = process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv); + if (r < 0) + return NULL; + } + } + + if (strv_isempty(strv)) + return NULL; + + r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv); + if (r < 0) { + log_error("Failed to get list of configuration files: %s", strerror(-r)); + strv_free(configs); + return NULL; + } + + return configs; +} + +int unit_load_dropin(Unit *u) { + Iterator i; + char *t, **f; + int r; + + assert(u); + + /* Load dependencies from supplementary drop-in directories */ + + SET_FOREACH(t, u->names, i) { + char **p; + + STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { + r = process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL); + if (r < 0) + return r; + + r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL); + if (r < 0) + return r; + } + } + + u->dropin_paths = unit_find_dropin_paths(u); + if (! u->dropin_paths) + return 0; + + STRV_FOREACH(f, u->dropin_paths) { + r = config_parse(u->id, *f, NULL, + UNIT_VTABLE(u)->sections, config_item_perf_lookup, + (void*) load_fragment_gperf_lookup, false, false, u); + if (r < 0) + return r; + } + + u->dropin_mtime = now(CLOCK_REALTIME); + + return 0; +} diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h new file mode 100644 index 0000000..fd55117 --- /dev/null +++ b/src/core/load-dropin.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" + +/* Read service data supplementary drop-in directories */ + +char **unit_find_dropin_paths(Unit *u); +int unit_load_dropin(Unit *u); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 new file mode 100644 index 0000000..26146b1 --- /dev/null +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -0,0 +1,299 @@ +%{ +#include +#include "conf-parser.h" +#include "load-fragment.h" +#include "missing.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name load_fragment_gperf_hash +%define lookup-function-name load_fragment_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +m4_dnl Define the context options only once +m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', +`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) +$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) +$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) +$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) +$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups) +$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context) +$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context) +$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context) +$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context) +$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context) +$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context) +$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork) +$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context) +$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) +$1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment) +$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) +$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) +$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) +$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) +$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path) +$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset) +$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup) +$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate) +$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier) +$1.SyslogFacility, config_parse_facility, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevel, config_parse_level, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) +$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) +$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) +$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) +$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) +$1.NoNewPrivileges, config_parse_bool, 0, offsetof($1, exec_context.no_new_privileges) +m4_ifdef(`HAVE_SECCOMP', +`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context) +$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs) +$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)', +`$1.SystemCallFilter, config_parse_warn_compat, 0, 0 +$1.SystemCallArchitectures, config_parse_warn_compat, 0, 0 +$1.SystemCallErrorNumber, config_parse_warn_compat, 0, 0') +$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) +$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) +$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs) +$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs) +$1.InaccessibleDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) +$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) +$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) +$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) +$1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality) +m4_ifdef(`HAVE_LIBWRAP', +`$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name)', +`$1.TCPWrapName, config_parse_warn_compat, 0, 0') +m4_ifdef(`HAVE_PAM', +`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)', +`$1.PAMName, config_parse_warn_compat, 0, 0') +$1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe) +$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) +m4_ifdef(`HAVE_SELINUX', +`$1.SELinuxContext, config_parse_exec_selinux_context, 0, offsetof($1, exec_context)', +`$1.SELinuxContext, config_parse_warn_compat, 0, 0') +m4_ifdef(`HAVE_APPARMOR', +`$1.AppArmorProfile, config_parse_exec_apparmor_profile,0, offsetof($1, exec_context)', +`$1.AppArmorProfile, config_parse_warn_compat, 0, 0')' +)m4_dnl +m4_define(`KILL_CONTEXT_CONFIG_ITEMS', +`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill) +$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup) +$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode) +$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)' +)m4_dnl +m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS', +`$1.Slice, config_parse_unit_slice, 0, 0 +$1.CPUAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.cpu_accounting) +$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context) +$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) +$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context) +$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy) +$1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting) +$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context) +$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context) +$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) +$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)' +)m4_dnl +Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) +Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) +Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path) +Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 +Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 +Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 +Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 +Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 +Unit.BindsTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 +Unit.BindTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 +Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0 +Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0 +Unit.After, config_parse_unit_deps, UNIT_AFTER, 0 +Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 +Unit.PropagatesReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0 +Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0 +Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 +Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 +Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0 +Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0 +Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0 +Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) +Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) +Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) +Unit.AllowIsolate, config_parse_bool, 0, offsetof(Unit, allow_isolate) +Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Unit, default_dependencies) +Unit.OnFailureJobMode, config_parse_job_mode, 0, offsetof(Unit, on_failure_job_mode) +Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode) +Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) +Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot) +Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout) +Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 +Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 +Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 +Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0 +Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0 +Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, 0 +Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 +Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, 0 +Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 +Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 +Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, 0 +Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 +Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 +Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 +Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0 +Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, 0 +Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 +m4_dnl +Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) +Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) +Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command) +Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command) +Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command) +Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) +Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) +Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec) +Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) +Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) +Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec) +Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec) +Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval) +Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) +Service.StartLimitAction, config_parse_start_limit_action, 0, offsetof(Service, start_limit_action) +Service.Type, config_parse_service_type, 0, offsetof(Service, type) +Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) +Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) +Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only) +Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit) +Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid) +Service.RestartPreventExitStatus, config_parse_set_status, 0, offsetof(Service, restart_ignore_status) +Service.SuccessExitStatus, config_parse_set_status, 0, offsetof(Service, success_status) +m4_ifdef(`HAVE_SYSV_COMPAT', +`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)', +`Service.SysVStartPriority, config_parse_warn_compat, 0, 0') +Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking) +Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name) +Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) +Service.Sockets, config_parse_service_sockets, 0, 0 +EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +m4_dnl +Socket.ListenStream, config_parse_socket_listen, SOCKET_SOCKET, 0 +Socket.ListenDatagram, config_parse_socket_listen, SOCKET_SOCKET, 0 +Socket.ListenSequentialPacket, config_parse_socket_listen, SOCKET_SOCKET, 0 +Socket.ListenFIFO, config_parse_socket_listen, SOCKET_FIFO, 0 +Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCKET, 0 +Socket.ListenSpecial, config_parse_socket_listen, SOCKET_SPECIAL, 0 +Socket.ListenMessageQueue, config_parse_socket_listen, SOCKET_MQUEUE, 0 +Socket.BindIPv6Only, config_parse_socket_bind, 0, 0, +Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog) +Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0 +Socket.ExecStartPre, config_parse_exec, SOCKET_EXEC_START_PRE, offsetof(Socket, exec_command) +Socket.ExecStartPost, config_parse_exec, SOCKET_EXEC_START_POST, offsetof(Socket, exec_command) +Socket.ExecStopPre, config_parse_exec, SOCKET_EXEC_STOP_PRE, offsetof(Socket, exec_command) +Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC_STOP_POST, offsetof(Socket, exec_command) +Socket.TimeoutSec, config_parse_sec, 0, offsetof(Socket, timeout_usec) +Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) +Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) +Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) +Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) +Socket.Priority, config_parse_int, 0, offsetof(Socket, priority) +Socket.ReceiveBuffer, config_parse_iec_size, 0, offsetof(Socket, receive_buffer) +Socket.SendBuffer, config_parse_iec_size, 0, offsetof(Socket, send_buffer) +Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos) +Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl) +Socket.Mark, config_parse_int, 0, offsetof(Socket, mark) +Socket.PipeSize, config_parse_iec_size, 0, offsetof(Socket, pipe_size) +Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind) +Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) +Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) +Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred) +Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec) +Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) +Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port) +Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) +Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) +Socket.Service, config_parse_socket_service, 0, 0 +m4_ifdef(`HAVE_SMACK', +`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) +Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in) +Socket.SmackLabelIPOut, config_parse_string, 0, offsetof(Socket, smack_ip_out)', +`Socket.SmackLabel, config_parse_warn_compat, 0, 0 +Socket.SmackLabelIPIn, config_parse_warn_compat, 0, 0 +Socket.SmackLabelIPOut, config_parse_warn_compat, 0, 0') +EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +m4_dnl +BusName.Name, config_parse_string, 0, offsetof(BusName, name) +BusName.Service, config_parse_busname_service, 0, 0 +m4_dnl +Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) +Mount.Where, config_parse_path, 0, offsetof(Mount, where) +Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) +Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) +Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec) +Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) +EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +m4_dnl +Automount.Where, config_parse_path, 0, offsetof(Automount, where) +Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) +m4_dnl +Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) +Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) +Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec) +EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +m4_dnl +Timer.OnCalendar, config_parse_timer, 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.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) +Timer.Unit, config_parse_trigger_unit, 0, 0 +m4_dnl +Path.PathExists, config_parse_path_spec, 0, 0 +Path.PathExistsGlob, config_parse_path_spec, 0, 0 +Path.PathChanged, config_parse_path_spec, 0, 0 +Path.PathModified, config_parse_path_spec, 0, 0 +Path.DirectoryNotEmpty, config_parse_path_spec, 0, 0 +Path.Unit, config_parse_trigger_unit, 0, 0 +Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory) +Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode) +m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Slice)m4_dnl +m4_dnl +CGROUP_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl +KILL_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl +Scope.TimeoutStopSec, config_parse_sec, 0, offsetof(Scope, timeout_stop_usec) +m4_dnl The [Install] section is ignored here. +Install.Alias, NULL, 0, 0 +Install.WantedBy, NULL, 0, 0 +Install.RequiredBy, NULL, 0, 0 +Install.Also, NULL, 0, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c new file mode 100644 index 0000000..82aed1e --- /dev/null +++ b/src/core/load-fragment.c @@ -0,0 +1,3079 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2012 Holger Hans Peter Freyther + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SECCOMP +#include +#endif + +#include "sd-messages.h" +#include "unit.h" +#include "strv.h" +#include "conf-parser.h" +#include "load-fragment.h" +#include "log.h" +#include "ioprio.h" +#include "securebits.h" +#include "missing.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "utf8.h" +#include "path-util.h" +#include "env-util.h" +#include "cgroup.h" +#include "bus-util.h" +#include "bus-error.h" +#include "errno-list.h" + +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif + +#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR) +int config_parse_warn_compat( + 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) { + + log_syntax(unit, LOG_DEBUG, filename, line, EINVAL, + "Support for option %s= has been disabled at compile time and is ignored", + lvalue); + return 0; +} +#endif + +int config_parse_unit_deps(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) { + + UnitDependency d = ltype; + Unit *u = userdata; + char *w; + size_t l; + char *state; + + assert(filename); + assert(lvalue); + assert(rvalue); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *t = NULL, *k = NULL; + int r; + + t = strndup(w, l); + if (!t) + return log_oom(); + + r = unit_name_printf(u, t, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + continue; + } + + r = unit_add_dependency_by_name(u, d, k, NULL, true); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to add dependency on %s, ignoring: %s", k, strerror(-r)); + } + + return 0; +} + +int config_parse_unit_string_printf(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + _cleanup_free_ char *k = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + + return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, + k ? k : rvalue, data, userdata); +} + +int config_parse_unit_strv_printf(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + _cleanup_free_ char *k = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + + return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, + k ? k : rvalue, data, userdata); +} + +int config_parse_unit_path_printf(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + _cleanup_free_ char *k = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + + return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, + k ? k : rvalue, data, userdata); +} + +int config_parse_socket_listen(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + SocketPort *p, *tail; + Socket *s; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + s = SOCKET(data); + + if (isempty(rvalue)) { + /* An empty assignment removes all ports */ + socket_free_ports(s); + return 0; + } + + p = new0(SocketPort, 1); + if (!p) + return log_oom(); + + if (ltype != SOCKET_SOCKET) { + + p->type = ltype; + r = unit_full_printf(UNIT(s), rvalue, &p->path); + if (r < 0) { + p->path = strdup(rvalue); + if (!p->path) { + free(p); + return log_oom(); + } else + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + } + + path_kill_slashes(p->path); + + } else if (streq(lvalue, "ListenNetlink")) { + _cleanup_free_ char *k = NULL; + + p->type = SOCKET_SOCKET; + r = unit_full_printf(UNIT(s), rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + + r = socket_address_parse_netlink(&p->address, k ? k : rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse address value, ignoring: %s", rvalue); + free(p); + return 0; + } + + } else { + _cleanup_free_ char *k = NULL; + + p->type = SOCKET_SOCKET; + r = unit_full_printf(UNIT(s), rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + + r = socket_address_parse(&p->address, k ? k : rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse address value, ignoring: %s", rvalue); + free(p); + return 0; + } + + if (streq(lvalue, "ListenStream")) + p->address.type = SOCK_STREAM; + else if (streq(lvalue, "ListenDatagram")) + p->address.type = SOCK_DGRAM; + else { + assert(streq(lvalue, "ListenSequentialPacket")); + p->address.type = SOCK_SEQPACKET; + } + + if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) { + log_syntax(unit, LOG_ERR, filename, line, ENOTSUP, + "Address family not supported, ignoring: %s", rvalue); + free(p); + return 0; + } + } + + p->fd = -1; + p->socket = s; + + if (s->ports) { + LIST_FIND_TAIL(port, s->ports, tail); + LIST_INSERT_AFTER(port, s->ports, tail, p); + } else + LIST_PREPEND(port, s->ports, p); + + return 0; +} + +int config_parse_socket_bind(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Socket *s; + SocketAddressBindIPv6Only b; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + s = SOCKET(data); + + b = socket_address_bind_ipv6_only_from_string(rvalue); + if (b < 0) { + int r; + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse bind IPv6 only value, ignoring: %s", rvalue); + return 0; + } + + s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH; + } else + s->bind_ipv6_only = b; + + return 0; +} + +int config_parse_exec_nice(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int priority, r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atoi(rvalue, &priority); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse nice priority, ignoring: %s. ", rvalue); + return 0; + } + + if (priority < PRIO_MIN || priority >= PRIO_MAX) { + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "Nice priority out of range, ignoring: %s", rvalue); + return 0; + } + + c->nice = priority; + c->nice_set = true; + + return 0; +} + +int config_parse_exec_oom_score_adjust(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int oa, r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atoi(rvalue, &oa); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); + return 0; + } + + if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) { + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "OOM score adjust value out of range, ignoring: %s", rvalue); + return 0; + } + + c->oom_score_adjust = oa; + c->oom_score_adjust_set = true; + + return 0; +} + +int config_parse_exec(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) { + + ExecCommand **e = data, *nce; + char *path, **n; + unsigned k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(e); + + e += ltype; + + if (isempty(rvalue)) { + /* An empty assignment resets the list */ + exec_command_free_list(*e); + *e = NULL; + return 0; + } + + /* We accept an absolute path as first argument, or + * alternatively an absolute prefixed with @ to allow + * overriding of argv[0]. */ + for (;;) { + int i; + char *w; + size_t l; + char *state; + bool honour_argv0 = false, ignore = false; + + path = NULL; + nce = NULL; + n = NULL; + + rvalue += strspn(rvalue, WHITESPACE); + + if (rvalue[0] == 0) + break; + + for (i = 0; i < 2; i++) { + if (rvalue[0] == '-' && !ignore) { + ignore = true; + rvalue ++; + } + + if (rvalue[0] == '@' && !honour_argv0) { + honour_argv0 = true; + rvalue ++; + } + } + + if (*rvalue != '/') { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Executable path is not absolute, ignoring: %s", rvalue); + return 0; + } + + k = 0; + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + if (strneq(w, ";", MAX(l, 1U))) + break; + + k++; + } + + n = new(char*, k + !honour_argv0); + if (!n) + return log_oom(); + + k = 0; + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + if (strneq(w, ";", MAX(l, 1U))) + break; + else if (strneq(w, "\\;", MAX(l, 1U))) + w ++; + + if (honour_argv0 && w == rvalue) { + assert(!path); + + path = strndup(w, l); + if (!path) { + r = log_oom(); + goto fail; + } + + if (!utf8_is_valid(path)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not UTF-8 clean, ignoring assignment: %s", + rvalue); + r = 0; + goto fail; + } + + } else { + char *c; + + c = n[k++] = cunescape_length(w, l); + if (!c) { + r = log_oom(); + goto fail; + } + + if (!utf8_is_valid(c)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not UTF-8 clean, ignoring assignment: %s", + rvalue); + r = 0; + goto fail; + } + } + } + + n[k] = NULL; + + if (!n[0]) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid command line, ignoring: %s", rvalue); + r = 0; + goto fail; + } + + if (!path) { + path = strdup(n[0]); + if (!path) { + r = log_oom(); + goto fail; + } + } + + assert(path_is_absolute(path)); + + nce = new0(ExecCommand, 1); + if (!nce) { + r = log_oom(); + goto fail; + } + + nce->argv = n; + nce->path = path; + nce->ignore = ignore; + + path_kill_slashes(nce->path); + + exec_command_append_list(e, nce); + + rvalue = state; + } + + return 0; + +fail: + n[k] = NULL; + strv_free(n); + free(path); + free(nce); + + return r; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); + +int config_parse_socket_bindtodevice(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Socket *s = data; + char *n; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (rvalue[0] && !streq(rvalue, "*")) { + n = strdup(rvalue); + if (!n) + return log_oom(); + } else + n = NULL; + + free(s->bind_to_device); + s->bind_to_device = n; + + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier"); + +int config_parse_exec_io_class(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + x = ioprio_class_from_string(rvalue); + if (x < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse IO scheduling class, ignoring: %s", rvalue); + return 0; + } + + c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio)); + c->ioprio_set = true; + + return 0; +} + +int config_parse_exec_io_priority(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int i, r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atoi(rvalue, &i); + if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse IO priority, ignoring: %s", rvalue); + return 0; + } + + c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i); + c->ioprio_set = true; + + return 0; +} + +int config_parse_exec_cpu_sched_policy(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + + ExecContext *c = data; + int x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + x = sched_policy_from_string(rvalue); + if (x < 0) { + log_syntax(unit, LOG_ERR, filename, line, -x, + "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + return 0; + } + + c->cpu_sched_policy = x; + /* Moving to or from real-time policy? We need to adjust the priority */ + c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x)); + c->cpu_sched_set = true; + + return 0; +} + +int config_parse_exec_cpu_sched_prio(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int i, min, max, r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atoi(rvalue, &i); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + return 0; + } + + /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */ + min = sched_get_priority_min(c->cpu_sched_policy); + max = sched_get_priority_max(c->cpu_sched_policy); + + if (i < min || i > max) { + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "CPU scheduling priority is out of range, ignoring: %s", rvalue); + return 0; + } + + c->cpu_sched_priority = i; + c->cpu_sched_set = true; + + return 0; +} + +int config_parse_exec_cpu_affinity(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + char *w; + size_t l; + char *state; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* An empty assignment resets the CPU list */ + if (c->cpuset) + CPU_FREE(c->cpuset); + c->cpuset = NULL; + return 0; + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *t = NULL; + int r; + unsigned cpu; + + t = strndup(w, l); + if (!t) + return log_oom(); + + r = safe_atou(t, &cpu); + + if (!c->cpuset) { + c->cpuset = cpu_set_malloc(&c->cpuset_ncpus); + if (!c->cpuset) + return log_oom(); + } + + if (r < 0 || cpu >= c->cpuset_ncpus) { + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue); + return 0; + } + + CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset); + } + + return 0; +} + +int config_parse_exec_capabilities(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + cap_t cap; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + cap = cap_from_text(rvalue); + if (!cap) { + log_syntax(unit, LOG_ERR, filename, line, errno, + "Failed to parse capabilities, ignoring: %s", rvalue); + return 0; + } + + if (c->capabilities) + cap_free(c->capabilities); + c->capabilities = cap; + + return 0; +} + +int config_parse_exec_secure_bits(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + char *w; + size_t l; + char *state; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* An empty assignment resets the field */ + c->secure_bits = 0; + return 0; + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + if (first_word(w, "keep-caps")) + c->secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<secure_bits |= 1<rlim_cur = (*rl)->rlim_max = (rlim_t) u; + return 0; +} + +#ifdef HAVE_SYSV_COMPAT +int config_parse_sysv_priority(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + int *priority = data; + int i, r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atoi(rvalue, &i); + if (r < 0 || i < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse SysV start priority, ignoring: %s", rvalue); + return 0; + } + + *priority = (int) i; + return 0; +} +#endif + +DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode"); + +int config_parse_kill_signal(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + int *sig = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(sig); + + r = signal_from_string_try_harder(rvalue); + if (r <= 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse kill signal, ignoring: %s", rvalue); + return 0; + } + + *sig = r; + return 0; +} + +int config_parse_exec_mount_flags(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + char *w; + size_t l; + char *state; + unsigned long flags = 0; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) { + _cleanup_free_ char *t; + + t = strndup(w, l); + if (!t) + return log_oom(); + + if (streq(t, "shared")) + flags |= MS_SHARED; + else if (streq(t, "slave")) + flags |= MS_SLAVE; + else if (streq(w, "private")) + flags |= MS_PRIVATE; + else { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse mount flag %s, ignoring: %s", + t, rvalue); + return 0; + } + } + + c->mount_flags = flags; + return 0; +} + +int config_parse_exec_selinux_context( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool ignore; + char *k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + free(c->selinux_context); + c->selinux_context = NULL; + c->selinux_context_ignore = false; + return 0; + } + + if (rvalue[0] == '-') { + ignore = true; + rvalue++; + } else + ignore = false; + + r = unit_name_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + return 0; + } + + free(c->selinux_context); + c->selinux_context = k; + c->selinux_context_ignore = ignore; + + return 0; +} + +int config_parse_exec_apparmor_profile( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool ignore; + char *k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + free(c->apparmor_profile); + c->apparmor_profile = NULL; + c->apparmor_profile_ignore = false; + return 0; + } + + if (rvalue[0] == '-') { + ignore = true; + rvalue++; + } else + ignore = false; + + r = unit_name_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + return 0; + } + + free(c->apparmor_profile); + c->apparmor_profile = k; + c->apparmor_profile_ignore = ignore; + + 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) { + + Timer *t = data; + usec_t u = 0; + TimerValue *v; + TimerBase b; + CalendarSpec *c = NULL; + clockid_t id; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets list */ + timer_free_values(t); + return 0; + } + + b = timer_base_from_string(lvalue); + if (b < 0) { + log_syntax(unit, LOG_ERR, filename, line, -b, + "Failed to parse timer base, ignoring: %s", lvalue); + return 0; + } + + if (b == TIMER_CALENDAR) { + if (calendar_spec_from_string(rvalue, &c) < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse calendar specification, ignoring: %s", + rvalue); + return 0; + } + + id = CLOCK_REALTIME; + } else { + if (parse_sec(rvalue, &u) < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse timer value, ignoring: %s", + rvalue); + return 0; + } + + id = CLOCK_MONOTONIC; + } + + v = new0(TimerValue, 1); + if (!v) + return log_oom(); + + v->base = b; + v->clock_id = id; + v->value = u; + v->calendar_spec = c; + + LIST_PREPEND(value, t->values, v); + + return 0; +} + +int config_parse_trigger_unit( + 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 *p = NULL; + Unit *u = data; + UnitType type; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Multiple units to trigger specified, ignoring: %s", rvalue); + return 0; + } + + r = unit_name_printf(u, rvalue, &p); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + + type = unit_name_to_type(p ?: rvalue); + if (type < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Unit type not valid, ignoring: %s", rvalue); + return 0; + } + + if (type == u->type) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Trigger cannot be of same type, ignoring: %s", rvalue); + return 0; + } + + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r)); + return 0; + } + + return 0; +} + +int config_parse_path_spec(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) { + + Path *p = data; + PathSpec *s; + PathType b; + _cleanup_free_ char *k = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment clears list */ + path_free_specs(p); + return 0; + } + + b = path_type_from_string(lvalue); + if (b < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse path type, ignoring: %s", lvalue); + return 0; + } + + r = unit_full_printf(UNIT(p), rvalue, &k); + if (r < 0) { + k = strdup(rvalue); + if (!k) + return log_oom(); + else + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s. Ignoring.", + rvalue); + } + + if (!path_is_absolute(k)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not absolute, ignoring: %s", k); + return 0; + } + + s = new0(PathSpec, 1); + if (!s) + return log_oom(); + + s->unit = UNIT(p); + s->path = path_kill_slashes(k); + k = NULL; + s->type = b; + s->inotify_fd = -1; + + LIST_PREPEND(spec, p->specs, s); + + return 0; +} + +int config_parse_socket_service(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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + Socket *s = data; + int r; + Unit *x; + _cleanup_free_ char *p = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = unit_name_printf(UNIT(s), rvalue, &p); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } + + if (!endswith(p, ".service")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue); + return 0; + } + + r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + return 0; + } + + unit_ref_set(&s->service, x); + + return 0; +} + +int config_parse_service_sockets(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Service *s = data; + int r; + char *state, *w; + size_t l; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *t = NULL, *k = NULL; + + t = strndup(w, l); + if (!t) + return log_oom(); + + r = unit_name_printf(UNIT(s), t, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + + if (!endswith(k ?: t, ".socket")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Unit must be of type socket, ignoring: %s", k ?: t); + continue; + } + + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to add dependency on %s, ignoring: %s", + k ?: t, strerror(-r)); + + r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true); + if (r < 0) + return r; + } + + return 0; +} + +int config_parse_service_timeout(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Service *s = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(s); + + r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype, + rvalue, data, userdata); + if (r < 0) + return r; + + if (streq(lvalue, "TimeoutSec")) { + s->start_timeout_defined = true; + s->timeout_stop_usec = s->timeout_start_usec; + } else if (streq(lvalue, "TimeoutStartSec")) + s->start_timeout_defined = true; + + return 0; +} + +int config_parse_busname_service( + 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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + BusName *n = data; + int r; + Unit *x; + _cleanup_free_ char *p = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = unit_name_printf(UNIT(n), rvalue, &p); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } + + if (!endswith(p, ".service")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue); + return 0; + } + + r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + return 0; + } + + unit_ref_set(&n->service, x); + + return 0; +} + +int config_parse_unit_env_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) { + + char ***env = data; + Unit *u = userdata; + _cleanup_free_ char *n = NULL; + const char *s; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment frees the list */ + strv_free(*env); + *env = NULL; + return 0; + } + + r = unit_full_printf(u, rvalue, &n); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to resolve specifiers, ignoring: %s", rvalue); + + s = n ?: rvalue; + if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path '%s' is not absolute, ignoring.", s); + return 0; + } + + r = strv_extend(env, s); + if (r < 0) + return log_oom(); + + return 0; +} + +int config_parse_environ(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) { + + Unit *u = userdata; + char*** env = data, *w, *state; + size_t l; + _cleanup_free_ char *k = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + strv_free(*env); + *env = NULL; + return 0; + } + + if (u) { + r = unit_full_printf(u, rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", rvalue); + } + + if (!k) + k = strdup(rvalue); + if (!k) + return log_oom(); + + FOREACH_WORD_QUOTED(w, l, k, state) { + _cleanup_free_ char *n; + char **x; + + n = cunescape_length(w, l); + if (!n) + return log_oom(); + + if (!env_assignment_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid environment assignment, ignoring: %s", rvalue); + continue; + } + + x = strv_env_set(*env, n); + if (!x) + return log_oom(); + + strv_free(*env); + *env = x; + } + + return 0; +} + +int config_parse_ip_tos(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 *ip_tos = data, x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + x = ip_tos_from_string(rvalue); + if (x < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse IP TOS value, ignoring: %s", rvalue); + return 0; + } + + *ip_tos = x; + return 0; +} + +int config_parse_unit_condition_path(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) { + + ConditionType cond = ltype; + Unit *u = data; + bool trigger, negate; + Condition *c; + _cleanup_free_ char *p = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + condition_free_list(u->conditions); + u->conditions = NULL; + return 0; + } + + trigger = rvalue[0] == '|'; + if (trigger) + rvalue++; + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + r = unit_full_printf(u, rvalue, &p); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", rvalue); + if (!p) { + p = strdup(rvalue); + if (!p) + return log_oom(); + } + + if (!path_is_absolute(p)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path in condition not absolute, ignoring: %s", p); + return 0; + } + + c = condition_new(cond, p, trigger, negate); + if (!c) + return log_oom(); + + LIST_PREPEND(conditions, u->conditions, c); + return 0; +} + +int config_parse_unit_condition_string(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) { + + ConditionType cond = ltype; + Unit *u = data; + bool trigger, negate; + Condition *c; + _cleanup_free_ char *s = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + condition_free_list(u->conditions); + u->conditions = NULL; + return 0; + } + + trigger = rvalue[0] == '|'; + if (trigger) + rvalue++; + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + r = unit_full_printf(u, rvalue, &s); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve specifiers, ignoring: %s", rvalue); + if (!s) { + s = strdup(rvalue); + if (!s) + return log_oom(); + } + + c = condition_new(cond, s, trigger, negate); + if (!c) + return log_oom(); + + LIST_PREPEND(conditions, u->conditions, c); + return 0; +} + +int config_parse_unit_condition_null(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) { + + Unit *u = data; + Condition *c; + bool trigger, negate; + int b; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + condition_free_list(u->conditions); + u->conditions = NULL; + return 0; + } + + trigger = rvalue[0] == '|'; + if (trigger) + rvalue++; + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + b = parse_boolean(rvalue); + if (b < 0) { + log_syntax(unit, LOG_ERR, filename, line, -b, + "Failed to parse boolean value in condition, ignoring: %s", + rvalue); + return 0; + } + + if (!b) + negate = !negate; + + c = condition_new(CONDITION_NULL, NULL, trigger, negate); + if (!c) + return log_oom(); + + LIST_PREPEND(conditions, u->conditions, c); + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier"); + +int config_parse_unit_requires_mounts_for( + 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) { + + Unit *u = userdata; + char *state; + size_t l; + char *w; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + int r; + _cleanup_free_ char *n; + + n = strndup(w, l); + if (!n) + return log_oom(); + + if (!utf8_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not UTF-8 clean, ignoring assignment: %s", rvalue); + continue; + } + + r = unit_require_mounts_for(u, n); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to add required mount for, ignoring: %s", rvalue); + continue; + } + } + + return 0; +} + +int config_parse_documentation(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + int r; + char **a, **b; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + strv_free(u->documentation); + u->documentation = NULL; + return 0; + } + + r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype, + rvalue, data, userdata); + if (r < 0) + return r; + + for (a = b = u->documentation; a && *a; a++) { + + if (is_valid_documentation_url(*a)) + *(b++) = *a; + else { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid URL, ignoring: %s", *a); + free(*a); + } + } + if (b) + *b = NULL; + + return r; +} + +#ifdef HAVE_SECCOMP +int config_parse_syscall_filter( + 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 const char default_syscalls[] = + "execve\0" + "exit\0" + "exit_group\0" + "rt_sigreturn\0" + "sigreturn\0"; + + ExecContext *c = data; + Unit *u = userdata; + bool invert = false; + char *w, *state; + size_t l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + set_free(c->syscall_filter); + c->syscall_filter = NULL; + c->syscall_whitelist = false; + return 0; + } + + if (rvalue[0] == '~') { + invert = true; + rvalue++; + } + + if (!c->syscall_filter) { + c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func); + if (!c->syscall_filter) + return log_oom(); + + if (invert) + /* Allow everything but the ones listed */ + c->syscall_whitelist = false; + else { + const char *i; + + /* Allow nothing but the ones listed */ + c->syscall_whitelist = true; + + /* Accept default syscalls if we are on a whitelist */ + NULSTR_FOREACH(i, default_syscalls) { + int id; + + id = seccomp_syscall_resolve_name(i); + if (id < 0) + continue; + + r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); + if (r == -EEXIST) + continue; + if (r < 0) + return log_oom(); + } + } + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *t = NULL; + int id; + + t = strndup(w, l); + if (!t) + return log_oom(); + + id = seccomp_syscall_resolve_name(t); + if (id < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t); + continue; + } + + /* If we previously wanted to forbid a syscall and now + * we want to allow it, then remove it from the list + */ + if (!invert == c->syscall_whitelist) { + r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); + if (r == -EEXIST) + continue; + if (r < 0) + return log_oom(); + } else + set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + } + + c->no_new_privileges = true; + + return 0; +} + +int config_parse_syscall_archs( + 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) { + + Set **archs = data; + char *w, *state; + size_t l; + int r; + + if (isempty(rvalue)) { + set_free(*archs); + *archs = NULL; + return 0; + } + + r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func); + if (r < 0) + return log_oom(); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *t = NULL; + uint32_t a; + + t = strndup(w, l); + if (!t) + return log_oom(); + + r = seccomp_arch_from_string(t, &a); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t); + continue; + } + + r = set_put(*archs, UINT32_TO_PTR(a + 1)); + if (r == -EEXIST) + continue; + if (r < 0) + return log_oom(); + } + + return 0; +} + +int config_parse_syscall_errno( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int e; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + /* Empty assignment resets to KILL */ + c->syscall_errno = 0; + return 0; + } + + e = errno_from_name(rvalue); + if (e < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue); + return 0; + } + + c->syscall_errno = e; + return 0; +} +#endif + +int config_parse_unit_slice( + 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 *k = NULL; + Unit *u = userdata, *slice; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(u); + + r = unit_name_printf(u, rvalue, &k); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s. Ignoring.", rvalue); + if (!k) { + k = strdup(rvalue); + if (!k) + return log_oom(); + } + + r = manager_load_unit(u->manager, k, NULL, NULL, &slice); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to load slice unit %s. Ignoring.", k); + return 0; + } + + if (slice->type != UNIT_SLICE) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Slice unit %s is not a slice. Ignoring.", k); + return 0; + } + + unit_ref_set(&u->slice, slice); + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy"); + +int config_parse_cpu_shares( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + unsigned long lu; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + c->cpu_shares = 1024; + return 0; + } + + r = safe_atolu(rvalue, &lu); + if (r < 0 || lu <= 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "CPU shares '%s' invalid. Ignoring.", rvalue); + return 0; + } + + c->cpu_shares = lu; + return 0; +} + +int config_parse_memory_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + off_t bytes; + int r; + + if (isempty(rvalue)) { + c->memory_limit = (uint64_t) -1; + return 0; + } + + assert_cc(sizeof(uint64_t) == sizeof(off_t)); + + r = parse_size(rvalue, 1024, &bytes); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + + c->memory_limit = (uint64_t) bytes; + return 0; +} + +int config_parse_device_allow( + 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; + CGroupContext *c = data; + CGroupDeviceAllow *a; + const char *m; + size_t n; + + if (isempty(rvalue)) { + while (c->device_allow) + cgroup_context_free_device_allow(c, c->device_allow); + + return 0; + } + + n = strcspn(rvalue, WHITESPACE); + path = strndup(rvalue, n); + if (!path) + return log_oom(); + + if (!startswith(path, "/dev/") && + !startswith(path, "block-") && + !startswith(path, "char-")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + + m = rvalue + n + strspn(rvalue + n, WHITESPACE); + if (isempty(m)) + m = "rwm"; + + if (!in_charset(m, "rwm")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m); + return 0; + } + + a = new0(CGroupDeviceAllow, 1); + if (!a) + return log_oom(); + + a->path = path; + path = NULL; + a->r = !!strchr(m, 'r'); + a->w = !!strchr(m, 'w'); + a->m = !!strchr(m, 'm'); + + LIST_PREPEND(device_allow, c->device_allow, a); + return 0; +} + +int config_parse_blockio_weight( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + unsigned long lu; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + c->blockio_weight = 1000; + return 0; + } + + r = safe_atolu(rvalue, &lu); + if (r < 0 || lu < 10 || lu > 1000) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Block IO weight '%s' invalid. Ignoring.", rvalue); + return 0; + } + + c->blockio_weight = lu; + + return 0; +} + +int config_parse_blockio_device_weight( + 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; + CGroupBlockIODeviceWeight *w; + CGroupContext *c = data; + unsigned long lu; + const char *weight; + size_t n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + while (c->blockio_device_weights) + cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); + + return 0; + } + + n = strcspn(rvalue, WHITESPACE); + weight = rvalue + n; + if (!*weight) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Expected block device and device weight. Ignoring."); + return 0; + } + + path = strndup(rvalue, n); + if (!path) + return log_oom(); + + if (!path_startswith(path, "/dev")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + + weight += strspn(weight, WHITESPACE); + r = safe_atolu(weight, &lu); + if (r < 0 || lu < 10 || lu > 1000) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Block IO weight '%s' invalid. Ignoring.", rvalue); + return 0; + } + + + w = new0(CGroupBlockIODeviceWeight, 1); + if (!w) + return log_oom(); + + w->path = path; + path = NULL; + + w->weight = lu; + + LIST_PREPEND(device_weights, c->blockio_device_weights, w); + return 0; +} + +int config_parse_blockio_bandwidth( + 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; + CGroupBlockIODeviceBandwidth *b; + CGroupContext *c = data; + const char *bandwidth; + off_t bytes; + bool read; + size_t n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + read = streq("BlockIOReadBandwidth", lvalue); + + if (isempty(rvalue)) { + CGroupBlockIODeviceBandwidth *next; + + LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths) + if (b->read == read) + cgroup_context_free_blockio_device_bandwidth(c, b); + + return 0; + } + + n = strcspn(rvalue, WHITESPACE); + bandwidth = rvalue + n; + bandwidth += strspn(bandwidth, WHITESPACE); + + if (!*bandwidth) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Expected space separated pair of device node and bandwidth. Ignoring."); + return 0; + } + + path = strndup(rvalue, n); + if (!path) + return log_oom(); + + if (!path_startswith(path, "/dev")) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + + r = parse_size(bandwidth, 1000, &bytes); + if (r < 0 || bytes <= 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); + return 0; + } + + b = new0(CGroupBlockIODeviceBandwidth, 1); + if (!b) + return log_oom(); + + b->path = path; + path = NULL; + b->bandwidth = (uint64_t) bytes; + b->read = read; + + LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b); + + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode"); + +int config_parse_job_mode_isolate( + 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) { + + JobMode *m = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue); + return 0; + } + + *m = r ? JOB_ISOLATE : JOB_REPLACE; + return 0; +} + +int config_parse_personality( + 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) { + + unsigned long *personality = data, p; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(personality); + + p = personality_from_string(rvalue); + if (p == 0xffffffffUL) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse personality, ignoring: %s", rvalue); + return 0; + } + + *personality = p; + return 0; +} + +#define FOLLOW_MAX 8 + +static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { + unsigned c = 0; + int fd, r; + FILE *f; + char *id = NULL; + + assert(filename); + assert(*filename); + assert(_f); + assert(names); + + /* This will update the filename pointer if the loaded file is + * reached by a symlink. The old string will be freed. */ + + for (;;) { + char *target, *name; + + if (c++ >= FOLLOW_MAX) + return -ELOOP; + + path_kill_slashes(*filename); + + /* Add the file name we are currently looking at to + * the names of this unit, but only if it is a valid + * unit name. */ + name = basename(*filename); + + if (unit_name_is_valid(name, TEMPLATE_VALID)) { + + id = set_get(names, name); + if (!id) { + id = strdup(name); + if (!id) + return -ENOMEM; + + r = set_consume(names, id); + if (r < 0) + return r; + } + } + + /* Try to open the file name, but don't if its a symlink */ + fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd >= 0) + break; + + if (errno != ELOOP) + return -errno; + + /* Hmm, so this is a symlink. Let's read the name, and follow it manually */ + r = readlink_and_make_absolute(*filename, &target); + if (r < 0) + return r; + + free(*filename); + *filename = target; + } + + f = fdopen(fd, "re"); + if (!f) { + r = -errno; + close_nointr_nofail(fd); + return r; + } + + *_f = f; + *_final = id; + return 0; +} + +static int merge_by_names(Unit **u, Set *names, const char *id) { + char *k; + int r; + + assert(u); + assert(*u); + assert(names); + + /* Let's try to add in all symlink names we found */ + while ((k = set_steal_first(names))) { + + /* First try to merge in the other name into our + * unit */ + r = unit_merge_by_name(*u, k); + if (r < 0) { + Unit *other; + + /* Hmm, we couldn't merge the other unit into + * ours? Then let's try it the other way + * round */ + + other = manager_get_unit((*u)->manager, k); + free(k); + + if (other) { + r = unit_merge(other, *u); + if (r >= 0) { + *u = other; + return merge_by_names(u, names, NULL); + } + } + + return r; + } + + if (id == k) + unit_choose_id(*u, id); + + free(k); + } + + return 0; +} + +static int load_from_path(Unit *u, const char *path) { + int r; + _cleanup_set_free_free_ Set *symlink_names = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *filename = NULL; + char *id = NULL; + Unit *merged; + struct stat st; + + assert(u); + assert(path); + + symlink_names = set_new(string_hash_func, string_compare_func); + if (!symlink_names) + return -ENOMEM; + + if (path_is_absolute(path)) { + + filename = strdup(path); + if (!filename) + return -ENOMEM; + + r = open_follow(&filename, &f, symlink_names, &id); + if (r < 0) { + free(filename); + filename = NULL; + + if (r != -ENOENT) + return r; + } + + } else { + char **p; + + STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { + + /* Instead of opening the path right away, we manually + * follow all symlinks and add their name to our unit + * name set while doing so */ + filename = path_make_absolute(path, *p); + if (!filename) + return -ENOMEM; + + if (u->manager->unit_path_cache && + !set_get(u->manager->unit_path_cache, filename)) + r = -ENOENT; + else + r = open_follow(&filename, &f, symlink_names, &id); + + if (r < 0) { + free(filename); + filename = NULL; + + if (r != -ENOENT) + return r; + + /* Empty the symlink names for the next run */ + set_clear_free(symlink_names); + continue; + } + + break; + } + } + + if (!filename) + /* Hmm, no suitable file found? */ + return 0; + + merged = u; + r = merge_by_names(&merged, symlink_names, id); + if (r < 0) + return r; + + if (merged != u) { + u->load_state = UNIT_MERGED; + return 0; + } + + if (fstat(fileno(f), &st) < 0) + return -errno; + + if (null_or_empty(&st)) + u->load_state = UNIT_MASKED; + else { + u->load_state = UNIT_LOADED; + + /* Now, parse the file contents */ + r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections, + config_item_perf_lookup, + (void*) load_fragment_gperf_lookup, false, true, u); + if (r < 0) + return r; + } + + free(u->fragment_path); + u->fragment_path = filename; + filename = NULL; + + u->fragment_mtime = timespec_load(&st.st_mtim); + + if (u->source_path) { + if (stat(u->source_path, &st) >= 0) + u->source_mtime = timespec_load(&st.st_mtim); + else + u->source_mtime = 0; + } + + return 0; +} + +int unit_load_fragment(Unit *u) { + int r; + Iterator i; + const char *t; + + assert(u); + assert(u->load_state == UNIT_STUB); + assert(u->id); + + /* First, try to find the unit under its id. We always look + * for unit files in the default directories, to make it easy + * to override things by placing things in /etc/systemd/system */ + r = load_from_path(u, u->id); + if (r < 0) + return r; + + /* Try to find an alias we can load this with */ + if (u->load_state == UNIT_STUB) + SET_FOREACH(t, u->names, i) { + + if (t == u->id) + continue; + + r = load_from_path(u, t); + if (r < 0) + return r; + + if (u->load_state != UNIT_STUB) + break; + } + + /* And now, try looking for it under the suggested (originally linked) path */ + if (u->load_state == UNIT_STUB && u->fragment_path) { + + r = load_from_path(u, u->fragment_path); + if (r < 0) + return r; + + if (u->load_state == UNIT_STUB) { + /* Hmm, this didn't work? Then let's get rid + * of the fragment path stored for us, so that + * we don't point to an invalid location. */ + free(u->fragment_path); + u->fragment_path = NULL; + } + } + + /* Look for a template */ + if (u->load_state == UNIT_STUB && u->instance) { + _cleanup_free_ char *k; + + k = unit_name_template(u->id); + if (!k) + return -ENOMEM; + + r = load_from_path(u, k); + if (r < 0) + return r; + + if (u->load_state == UNIT_STUB) + SET_FOREACH(t, u->names, i) { + _cleanup_free_ char *z = NULL; + + if (t == u->id) + continue; + + z = unit_name_template(t); + if (!z) + return -ENOMEM; + + r = load_from_path(u, z); + if (r < 0) + return r; + + if (u->load_state != UNIT_STUB) + break; + } + } + + return 0; +} + +void unit_dump_config_items(FILE *f) { + static const struct { + const ConfigParserCallback callback; + const char *rvalue; + } table[] = { +#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR) + { config_parse_warn_compat, "NOTSUPPORTED" }, +#endif + { config_parse_int, "INTEGER" }, + { config_parse_unsigned, "UNSIGNED" }, + { config_parse_iec_size, "SIZE" }, + { config_parse_iec_off, "SIZE" }, + { config_parse_si_size, "SIZE" }, + { config_parse_bool, "BOOLEAN" }, + { config_parse_string, "STRING" }, + { config_parse_path, "PATH" }, + { config_parse_unit_path_printf, "PATH" }, + { config_parse_strv, "STRING [...]" }, + { config_parse_exec_nice, "NICE" }, + { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" }, + { config_parse_exec_io_class, "IOCLASS" }, + { config_parse_exec_io_priority, "IOPRIORITY" }, + { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" }, + { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" }, + { config_parse_exec_cpu_affinity, "CPUAFFINITY" }, + { config_parse_mode, "MODE" }, + { config_parse_unit_env_file, "FILE" }, + { config_parse_output, "OUTPUT" }, + { config_parse_input, "INPUT" }, + { config_parse_facility, "FACILITY" }, + { config_parse_level, "LEVEL" }, + { config_parse_exec_capabilities, "CAPABILITIES" }, + { config_parse_exec_secure_bits, "SECUREBITS" }, + { config_parse_bounding_set, "BOUNDINGSET" }, + { config_parse_limit, "LIMIT" }, + { config_parse_unit_deps, "UNIT [...]" }, + { config_parse_exec, "PATH [ARGUMENT [...]]" }, + { config_parse_service_type, "SERVICETYPE" }, + { config_parse_service_restart, "SERVICERESTART" }, +#ifdef HAVE_SYSV_COMPAT + { config_parse_sysv_priority, "SYSVPRIORITY" }, +#endif + { config_parse_kill_mode, "KILLMODE" }, + { config_parse_kill_signal, "SIGNAL" }, + { config_parse_socket_listen, "SOCKET [...]" }, + { config_parse_socket_bind, "SOCKETBIND" }, + { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, + { config_parse_sec, "SECONDS" }, + { config_parse_nsec, "NANOSECONDS" }, + { config_parse_path_strv, "PATH [...]" }, + { config_parse_unit_requires_mounts_for, "PATH [...]" }, + { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, + { config_parse_unit_string_printf, "STRING" }, + { config_parse_trigger_unit, "UNIT" }, + { config_parse_timer, "TIMER" }, + { config_parse_path_spec, "PATH" }, + { config_parse_notify_access, "ACCESS" }, + { config_parse_ip_tos, "TOS" }, + { config_parse_unit_condition_path, "CONDITION" }, + { config_parse_unit_condition_string, "CONDITION" }, + { config_parse_unit_condition_null, "CONDITION" }, + { config_parse_unit_slice, "SLICE" }, + { config_parse_documentation, "URL" }, + { config_parse_service_timeout, "SECONDS" }, + { config_parse_start_limit_action, "ACTION" }, + { config_parse_set_status, "STATUS" }, + { config_parse_service_sockets, "SOCKETS" }, + { config_parse_environ, "ENVIRON" }, +#ifdef HAVE_SECCOMP + { config_parse_syscall_filter, "SYSCALLS" }, + { config_parse_syscall_archs, "ARCHS" }, + { config_parse_syscall_errno, "ERRNO" }, +#endif + { config_parse_cpu_shares, "SHARES" }, + { config_parse_memory_limit, "LIMIT" }, + { config_parse_device_allow, "DEVICE" }, + { config_parse_device_policy, "POLICY" }, + { config_parse_blockio_bandwidth, "BANDWIDTH" }, + { config_parse_blockio_weight, "WEIGHT" }, + { config_parse_blockio_device_weight, "DEVICEWEIGHT" }, + { config_parse_long, "LONG" }, + { config_parse_socket_service, "SERVICE" }, +#ifdef HAVE_SELINUX + { config_parse_exec_selinux_context, "LABEL" }, +#endif + { config_parse_job_mode, "MODE" }, + { config_parse_job_mode_isolate, "BOOLEAN" }, + }; + + const char *prev = NULL; + const char *i; + + assert(f); + + NULSTR_FOREACH(i, load_fragment_gperf_nulstr) { + const char *rvalue = "OTHER", *lvalue; + unsigned j; + size_t prefix_len; + const char *dot; + const ConfigPerfItem *p; + + assert_se(p = load_fragment_gperf_lookup(i, strlen(i))); + + dot = strchr(i, '.'); + lvalue = dot ? dot + 1 : i; + prefix_len = dot-i; + + if (dot) + if (!prev || !strneq(prev, i, prefix_len+1)) { + if (prev) + fputc('\n', f); + + fprintf(f, "[%.*s]\n", (int) prefix_len, i); + } + + for (j = 0; j < ELEMENTSOF(table); j++) + if (p->parse == table[j].callback) { + rvalue = table[j].rvalue; + break; + } + + fprintf(f, "%s=%s\n", lvalue, rvalue); + prev = i; + } +} diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h new file mode 100644 index 0000000..4a5ec35 --- /dev/null +++ b/src/core/load-fragment.h @@ -0,0 +1,96 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" + +/* Read service data from .desktop file style configuration fragments */ + +int unit_load_fragment(Unit *u); + +void unit_dump_config_items(FILE *f); + +int config_parse_warn_compat(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_unit_deps(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_unit_string_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_path_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_nice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_timeout(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_restart(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_bindtodevice(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_output(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_input(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_io_class(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_io_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_sched_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_affinity(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_capabilities(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +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_trigger_unit(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_path_spec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_service(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_sockets(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_busname_service(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_unit_env_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); +int config_parse_ip_tos(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_unit_condition_path(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_unit_condition_string(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_unit_condition_null(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_kill_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_notify_access(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_start_limit_action(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_unit_requires_mounts_for(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_syscall_filter(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_syscall_archs(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_syscall_errno(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_environ(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_unit_slice(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_cpu_shares(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_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_device_policy(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_device_allow(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_blockio_weight(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_blockio_device_weight(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_blockio_bandwidth(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_job_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_job_mode_isolate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_selinux_context(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_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +/* gperf prototypes */ +const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); +extern const char load_fragment_gperf_nulstr[]; diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c new file mode 100644 index 0000000..276deb9 --- /dev/null +++ b/src/core/locale-setup.c @@ -0,0 +1,165 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "locale-setup.h" +#include "util.h" +#include "macro.h" +#include "virt.h" +#include "fileio.h" +#include "strv.h" +#include "env-util.h" + +enum { + /* We don't list LC_ALL here on purpose. People should be + * using LANG instead. */ + + VARIABLE_LANG, + VARIABLE_LANGUAGE, + VARIABLE_LC_CTYPE, + VARIABLE_LC_NUMERIC, + VARIABLE_LC_TIME, + VARIABLE_LC_COLLATE, + VARIABLE_LC_MONETARY, + VARIABLE_LC_MESSAGES, + VARIABLE_LC_PAPER, + VARIABLE_LC_NAME, + VARIABLE_LC_ADDRESS, + VARIABLE_LC_TELEPHONE, + VARIABLE_LC_MEASUREMENT, + VARIABLE_LC_IDENTIFICATION, + _VARIABLE_MAX +}; + +static const char * const variable_names[_VARIABLE_MAX] = { + [VARIABLE_LANG] = "LANG", + [VARIABLE_LANGUAGE] = "LANGUAGE", + [VARIABLE_LC_CTYPE] = "LC_CTYPE", + [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", + [VARIABLE_LC_TIME] = "LC_TIME", + [VARIABLE_LC_COLLATE] = "LC_COLLATE", + [VARIABLE_LC_MONETARY] = "LC_MONETARY", + [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", + [VARIABLE_LC_PAPER] = "LC_PAPER", + [VARIABLE_LC_NAME] = "LC_NAME", + [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", + [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", + [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +}; + +int locale_setup(char ***environment) { + char **add; + char *variables[_VARIABLE_MAX] = {}; + int r = 0, i; + + if (detect_container(NULL) <= 0) { + r = parse_env_file("/proc/cmdline", WHITESPACE, + "locale.LANG", &variables[VARIABLE_LANG], + "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], + "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "locale.LC_TIME", &variables[VARIABLE_LC_TIME], + "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], + "locale.LC_NAME", &variables[VARIABLE_LC_NAME], + "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); + } + + /* Hmm, nothing set on the kernel cmd line? Then let's + * try /etc/locale.conf */ + if (r <= 0) { + r = parse_env_file("/etc/locale.conf", NEWLINE, + "LANG", &variables[VARIABLE_LANG], + "LANGUAGE", &variables[VARIABLE_LANGUAGE], + "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], + "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], + "LC_TIME", &variables[VARIABLE_LC_TIME], + "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], + "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], + "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], + "LC_PAPER", &variables[VARIABLE_LC_PAPER], + "LC_NAME", &variables[VARIABLE_LC_NAME], + "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], + "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], + "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/locale.conf: %s", strerror(-r)); + } + + add = NULL; + for (i = 0; i < _VARIABLE_MAX; i++) { + char *s; + + if (!variables[i]) + continue; + + s = strjoin(variable_names[i], "=", variables[i], NULL); + if (!s) { + r = -ENOMEM; + goto finish; + } + + if (strv_push(&add, s) < 0) { + free(s); + r = -ENOMEM; + goto finish; + } + } + + if (!strv_isempty(add)) { + char **e; + + e = strv_env_merge(2, *environment, add); + if (!e) { + r = -ENOMEM; + goto finish; + } + + strv_free(*environment); + *environment = e; + } + + r = 0; + +finish: + strv_free(add); + + for (i = 0; i < _VARIABLE_MAX; i++) + free(variables[i]); + + return r; +} diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h new file mode 100644 index 0000000..62c654c --- /dev/null +++ b/src/core/locale-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int locale_setup(char ***environment); diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c new file mode 100644 index 0000000..d0156f2 --- /dev/null +++ b/src/core/loopback-setup.c @@ -0,0 +1,205 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "loopback-setup.h" +#include "socket-util.h" +#include "sd-rtnl.h" +#include "rtnl-util.h" + +static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + int *counter = userdata; + int r; + + (*counter) --; + + r = sd_rtnl_message_get_errno(m); + + return r == -EEXIST ? 0 : r; +} + +static int add_addresses(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *ipv4 = NULL, *ipv6 = NULL; + int r; + + r = sd_rtnl_message_new_addr(rtnl, &ipv4, RTM_NEWADDR, if_loopback, AF_INET); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_prefixlen(ipv4, 8); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_flags(ipv4, IFA_F_PERMANENT); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_scope(ipv4, RT_SCOPE_HOST); + if (r < 0) + return r; + + r = sd_rtnl_message_append_in_addr(ipv4, IFA_LOCAL, ipv4_address); + if (r < 0) + return r; + + r = sd_rtnl_call_async(rtnl, ipv4, &pipe_handler, counter, 0, NULL); + if (r < 0) + return r; + + (*counter) ++; + + if (!socket_ipv6_is_supported()) + return 0; + + r = sd_rtnl_message_new_addr(rtnl, &ipv6, RTM_NEWADDR, if_loopback, AF_INET6); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_prefixlen(ipv6, 128); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_flags(ipv6, IFA_F_PERMANENT); + if (r < 0) + return r; + + r = sd_rtnl_message_addr_set_scope(ipv6, RT_SCOPE_HOST); + if (r < 0) + return r; + + r = sd_rtnl_message_append_in6_addr(ipv6, IFA_LOCAL, &in6addr_loopback); + if (r < 0) + return r; + + r = sd_rtnl_call_async(rtnl, ipv6, &pipe_handler, counter, 0, NULL); + if (r < 0) + return r; + + (*counter) ++; + + return 0; +} + +static int start_interface(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, if_loopback); + if (r < 0) + return r; + + r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP); + if (r < 0) + return r; + + r = sd_rtnl_call_async(rtnl, req, &pipe_handler, counter, 0, NULL); + if (r < 0) + return r; + + (*counter) ++; + + return 0; +} + +static int check_loopback(void) { + int r; + _cleanup_close_ int fd = -1; + union { + struct sockaddr sa; + struct sockaddr_in in; + } sa = { + .in.sin_family = AF_INET, + .in.sin_addr.s_addr = INADDR_LOOPBACK, + }; + + /* If we failed to set up the loop back device, check whether + * it might already be set up */ + + fd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + if (bind(fd, &sa.sa, sizeof(sa.in)) >= 0) + r = 1; + else + r = errno == EADDRNOTAVAIL ? 0 : -errno; + + return r; +} + +int loopback_setup(void) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + int r, if_loopback, counter = 0; + bool eperm = false; + struct in_addr ipv4_address; + + errno = 0; + if_loopback = (int) if_nametoindex("lo"); + if (if_loopback <= 0) + return errno ? -errno : -ENODEV; + + ipv4_address.s_addr = htonl(INADDR_LOOPBACK); + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) + return r; + + r = add_addresses(rtnl, if_loopback, &ipv4_address, &counter); + if (r < 0) + return r; + + r = start_interface(rtnl, if_loopback, &ipv4_address, &counter); + if (r < 0) + return r; + + while (counter > 0) { + r = sd_rtnl_wait(rtnl, 0); + if (r < 0) + return r; + + r = sd_rtnl_process(rtnl, 0); + if (r < 0) { + if (r == -EPERM) + eperm = true; + else { + log_warning("Failed to configure loopback device: %s", strerror(-r)); + return r; + } + } + } + + if (eperm && check_loopback() < 0) { + log_warning("Failed to configure loopback device: %s", strerror(EPERM)); + return -EPERM; + } + + return 0; +} diff --git a/src/core/loopback-setup.h b/src/core/loopback-setup.h new file mode 100644 index 0000000..dd83cf1 --- /dev/null +++ b/src/core/loopback-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int loopback_setup(void); diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c new file mode 100644 index 0000000..1b55da7 --- /dev/null +++ b/src/core/machine-id-setup.c @@ -0,0 +1,237 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "machine-id-setup.h" +#include "macro.h" +#include "util.h" +#include "mkdir.h" +#include "log.h" +#include "virt.h" +#include "fileio.h" + +static int shorten_uuid(char destination[36], const char *source) { + unsigned i, j; + + for (i = 0, j = 0; i < 36 && j < 32; i++) { + int t; + + t = unhexchar(source[i]); + if (t < 0) + continue; + + destination[j++] = hexchar(t); + } + + if (i == 36 && j == 32) { + destination[32] = '\n'; + destination[33] = 0; + return 0; + } + + return -EINVAL; +} + +static int generate(char id[34]) { + int fd, r; + unsigned char *p; + sd_id128_t buf; + char *q; + ssize_t k; + const char *vm_id; + + assert(id); + + /* First, try reading the D-Bus machine id, unless it is a symlink */ + fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd >= 0) { + k = loop_read(fd, id, 33, false); + close_nointr_nofail(fd); + + if (k == 33 && id[32] == '\n') { + + id[32] = 0; + if (id128_is_valid(id)) { + id[32] = '\n'; + id[33] = 0; + + log_info("Initializing machine ID from D-Bus machine ID."); + return 0; + } + } + } + + /* If that didn't work, see if we are running in qemu/kvm and a + * machine ID was passed in via -uuid on the qemu/kvm command + * line */ + + r = detect_vm(&vm_id); + if (r > 0 && streq(vm_id, "kvm")) { + char uuid[37]; + + fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd >= 0) { + k = loop_read(fd, uuid, 36, false); + close_nointr_nofail(fd); + + if (k >= 36) { + r = shorten_uuid(id, uuid); + if (r >= 0) { + log_info("Initializing machine ID from KVM UUID."); + return 0; + } + } + } + } + + /* If that didn't work either, see if we are running in a + * container, and a machine ID was passed in via + * $container_uuid the way libvirt/LXC does it */ + r = detect_container(NULL); + if (r > 0) { + _cleanup_free_ char *e = NULL; + + r = getenv_for_pid(1, "container_uuid", &e); + if (r > 0) { + if (strlen(e) >= 36) { + r = shorten_uuid(id, e); + if (r >= 0) { + log_info("Initializing machine ID from container UUID."); + return 0; + } + } + } + } + + /* If that didn't work, generate a random machine id */ + r = sd_id128_randomize(&buf); + if (r < 0) { + log_error("Failed to open /dev/urandom: %s", strerror(-r)); + return r; + } + + for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) { + q[0] = hexchar(*p >> 4); + q[1] = hexchar(*p & 15); + } + + id[32] = '\n'; + id[33] = 0; + + log_info("Initializing machine ID from random generator."); + + return 0; +} + +int machine_id_setup(void) { + _cleanup_close_ int fd = -1; + int r; + bool writable = false; + struct stat st; + char id[34]; /* 32 + \n + \0 */ + + RUN_WITH_UMASK(0000) { + /* We create this 0444, to indicate that this isn't really + * something you should ever modify. Of course, since the file + * will be owned by root it doesn't matter much, but maybe + * people look. */ + + fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); + if (fd >= 0) + writable = true; + else { + fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + log_error("Cannot open /etc/machine-id: %m"); + return -errno; + } + + writable = false; + } + } + + if (fstat(fd, &st) < 0) { + log_error("fstat() failed: %m"); + return -errno; + } + + if (S_ISREG(st.st_mode)) + if (loop_read(fd, id, 33, false) == 33 && id[32] == '\n') { + id[32] = 0; + + if (id128_is_valid(id)) + return 0; + } + + /* Hmm, so, the id currently stored is not useful, then let's + * generate one */ + + r = generate(id); + if (r < 0) + return r; + + if (S_ISREG(st.st_mode) && writable) { + lseek(fd, 0, SEEK_SET); + + if (loop_write(fd, id, 33, false) == 33) + return 0; + } + + close_nointr_nofail(fd); + fd = -1; + + /* Hmm, we couldn't write it? So let's write it to + * /run/machine-id as a replacement */ + + RUN_WITH_UMASK(0022) { + r = write_string_file("/run/machine-id", id); + } + if (r < 0) { + log_error("Cannot write /run/machine-id: %s", strerror(-r)); + unlink("/run/machine-id"); + return r; + } + + /* And now, let's mount it over */ + r = mount("/run/machine-id", "/etc/machine-id", NULL, MS_BIND, NULL); + if (r < 0) { + log_error("Failed to mount /etc/machine-id: %m"); + unlink_noerrno("/run/machine-id"); + return -errno; + } + + log_info("Installed transient /etc/machine-id file."); + + /* Mark the mount read-only */ + if (mount(NULL, "/etc/machine-id", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0) + log_warning("Failed to make transient /etc/machine-id read-only: %m"); + + return 0; +} diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h new file mode 100644 index 0000000..b9e6b4d --- /dev/null +++ b/src/core/machine-id-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int machine_id_setup(void); diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in new file mode 100644 index 0000000..89b4825 --- /dev/null +++ b/src/core/macros.systemd.in @@ -0,0 +1,78 @@ +# -*- Mode: makefile; indent-tabs-mode: t -*- */ +# +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +# RPM macros for packages installing systemd unit files + +%_unitdir @systemunitdir@ +%_userunitdir @userunitdir@ +%_presetdir @systempresetdir@ +%_udevhwdbdir @udevhwdbdir@ +%_udevrulesdir @udevrulesdir@ +%_journalcatalogdir @catalogdir@ +%_tmpfilesdir @tmpfilesdir@ +%_sysctldir @sysctldir@ + +%systemd_requires \ +Requires(post): systemd \ +Requires(preun): systemd \ +Requires(postun): systemd \ +%{nil} + +%systemd_post() \ +if [ $1 -eq 1 ] ; then \ + # Initial installation \ + @rootbindir@/systemctl preset %{?*} >/dev/null 2>&1 || : \ +fi \ +%{nil} + +%systemd_preun() \ +if [ $1 -eq 0 ] ; then \ + # Package removal, not upgrade \ + @rootbindir@/systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \ + @rootbindir@/systemctl stop %{?*} > /dev/null 2>&1 || : \ +fi \ +%{nil} + +%systemd_postun() \ +@rootbindir@/systemctl daemon-reload >/dev/null 2>&1 || : \ +%{nil} + +%systemd_postun_with_restart() \ +@rootbindir@/systemctl daemon-reload >/dev/null 2>&1 || : \ +if [ $1 -ge 1 ] ; then \ + # Package upgrade, not uninstall \ + @rootbindir@/systemctl try-restart %{?*} >/dev/null 2>&1 || : \ +fi \ +%{nil} + +%udev_hwdb_update() \ +@rootbindir@/udevadm hwdb --update >/dev/null 2>&1 || : \ +%{nil} + +%udev_rules_update() \ +@rootbindir@/udevadm control --reload >/dev/null 2>&1 || : \ +%{nil} + +%journal_catalog_update() \ +@rootbindir@/journalctl --update-catalog >/dev/null 2>&1 || : \ +%{nil} + +%tmpfiles_create() \ +@rootbindir@/systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : \ +%{nil} diff --git a/src/core/main.c b/src/core/main.c new file mode 100644 index 0000000..f468481 --- /dev/null +++ b/src/core/main.c @@ -0,0 +1,1996 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_VALGRIND_VALGRIND_H +#include +#endif + +#include "sd-daemon.h" +#include "sd-messages.h" +#include "sd-bus.h" +#include "manager.h" +#include "log.h" +#include "load-fragment.h" +#include "fdset.h" +#include "special.h" +#include "conf-parser.h" +#include "missing.h" +#include "label.h" +#include "build.h" +#include "strv.h" +#include "def.h" +#include "virt.h" +#include "architecture.h" +#include "watchdog.h" +#include "path-util.h" +#include "switch-root.h" +#include "capability.h" +#include "killall.h" +#include "env-util.h" +#include "hwclock.h" +#include "fileio.h" +#include "dbus-manager.h" +#include "bus-error.h" +#include "bus-util.h" + +#include "mount-setup.h" +#include "loopback-setup.h" +#include "hostname-setup.h" +#include "machine-id-setup.h" +#include "selinux-setup.h" +#include "ima-setup.h" +#include "smack-setup.h" +#ifdef HAVE_KMOD +#include "kmod-setup.h" +#endif + +static enum { + ACTION_RUN, + ACTION_HELP, + ACTION_VERSION, + ACTION_TEST, + ACTION_DUMP_CONFIGURATION_ITEMS, + ACTION_DONE +} arg_action = ACTION_RUN; +static char *arg_default_unit = NULL; +static SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID; +static bool arg_dump_core = true; +static bool arg_crash_shell = false; +static int arg_crash_chvt = -1; +static bool arg_confirm_spawn = false; +static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; +static bool arg_switched_root = false; +static char ***arg_join_controllers = NULL; +static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; +static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; +static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC; +static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC; +static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC; +static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL; +static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST; +static usec_t arg_runtime_watchdog = 0; +static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; +static char **arg_default_environment = NULL; +#ifdef CONFIG_TIZEN +static char **arg_default_extra_dependencies = NULL; +#endif +static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {}; +static uint64_t arg_capability_bounding_set_drop = 0; +static nsec_t arg_timer_slack_nsec = (nsec_t) -1; +static Set* arg_syscall_archs = NULL; +static FILE* arg_serialization = NULL; + +static void nop_handler(int sig) {} + +noreturn static void crash(int sig) { + + if (getpid() != 1) + /* Pass this on immediately, if this is not PID 1 */ + raise(sig); + else if (!arg_dump_core) + log_error("Caught <%s>, not dumping core.", signal_to_string(sig)); + else { + struct sigaction sa = { + .sa_handler = nop_handler, + .sa_flags = SA_NOCLDSTOP|SA_RESTART, + }; + pid_t pid; + + /* We want to wait for the core process, hence let's enable SIGCHLD */ + sigaction(SIGCHLD, &sa, NULL); + + pid = fork(); + if (pid < 0) + log_error("Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); + + else if (pid == 0) { + struct rlimit rl = {}; + + /* Enable default signal handler for core dump */ + zero(sa); + sa.sa_handler = SIG_DFL; + sigaction(sig, &sa, NULL); + + /* Don't limit the core dump size */ + rl.rlim_cur = RLIM_INFINITY; + rl.rlim_max = RLIM_INFINITY; + setrlimit(RLIMIT_CORE, &rl); + + /* Just to be sure... */ + chdir("/"); + + /* Raise the signal again */ + raise(sig); + + assert_not_reached("We shouldn't be here..."); + _exit(1); + + } else { + siginfo_t status; + int r; + + /* Order things nicely. */ + r = wait_for_terminate(pid, &status); + if (r < 0) + log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r)); + else if (status.si_code != CLD_DUMPED) + log_error("Caught <%s>, core dump failed.", signal_to_string(sig)); + else + log_error("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid); + } + } + + if (arg_crash_chvt) + chvt(arg_crash_chvt); + + if (arg_crash_shell) { + struct sigaction sa = { + .sa_handler = SIG_IGN, + .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, + }; + pid_t pid; + + log_info("Executing crash shell in 10s..."); + sleep(10); + + /* Let the kernel reap children for us */ + assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + + pid = fork(); + if (pid < 0) + log_error("Failed to fork off crash shell: %m"); + else if (pid == 0) { + make_console_stdio(); + execl("/bin/sh", "/bin/sh", NULL); + + log_error("execl() failed: %m"); + _exit(1); + } + + log_info("Successfully spawned crash shell as pid "PID_FMT".", pid); + } + + log_info("Freezing execution."); + freeze(); +} + +static void install_crash_handler(void) { + struct sigaction sa = { + .sa_handler = crash, + .sa_flags = SA_NODEFER, + }; + + sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1); +} + +static int console_setup(bool do_reset) { + int tty_fd, r; + + /* If we are init, we connect stdin/stdout/stderr to /dev/null + * and make sure we don't have a controlling tty. */ + + release_terminal(); + + if (!do_reset) + return 0; + + tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (tty_fd < 0) { + log_error("Failed to open /dev/console: %s", strerror(-tty_fd)); + return -tty_fd; + } + + /* We don't want to force text mode. + * plymouth may be showing pictures already from initrd. */ + r = reset_terminal_fd(tty_fd, false); + if (r < 0) + log_error("Failed to reset /dev/console: %s", strerror(-r)); + + close_nointr_nofail(tty_fd); + return r; +} + +static int set_default_unit(const char *u) { + char *c; + + assert(u); + + c = strdup(u); + if (!c) + return -ENOMEM; + + free(arg_default_unit); + arg_default_unit = c; + + return 0; +} + +static int parse_proc_cmdline_word(const char *word) { + + static const char * const rlmap[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "-b", SPECIAL_EMERGENCY_TARGET, + "single", SPECIAL_RESCUE_TARGET, + "-s", SPECIAL_RESCUE_TARGET, + "s", SPECIAL_RESCUE_TARGET, + "S", SPECIAL_RESCUE_TARGET, + "1", SPECIAL_RESCUE_TARGET, + "2", SPECIAL_RUNLEVEL2_TARGET, + "3", SPECIAL_RUNLEVEL3_TARGET, + "4", SPECIAL_RUNLEVEL4_TARGET, + "5", SPECIAL_RUNLEVEL5_TARGET, + }; + + assert(word); + + if (startswith(word, "systemd.unit=")) { + + if (!in_initrd()) + return set_default_unit(word + 13); + + } else if (startswith(word, "rd.systemd.unit=")) { + + if (in_initrd()) + return set_default_unit(word + 16); + + } else if (startswith(word, "systemd.log_target=")) { + + if (log_set_target_from_string(word + 19) < 0) + log_warning("Failed to parse log target %s. Ignoring.", word + 19); + + } else if (startswith(word, "systemd.log_level=")) { + + if (log_set_max_level_from_string(word + 18) < 0) + log_warning("Failed to parse log level %s. Ignoring.", word + 18); + + } else if (startswith(word, "systemd.log_color=")) { + + if (log_show_color_from_string(word + 18) < 0) + log_warning("Failed to parse log color setting %s. Ignoring.", word + 18); + + } else if (startswith(word, "systemd.log_location=")) { + + if (log_show_location_from_string(word + 21) < 0) + log_warning("Failed to parse log location setting %s. Ignoring.", word + 21); + + } else if (startswith(word, "systemd.dump_core=")) { + int r; + + r = parse_boolean(word + 18); + if (r < 0) + log_warning("Failed to parse dump core switch %s. Ignoring.", word + 18); + else + arg_dump_core = r; + + } else if (startswith(word, "systemd.crash_shell=")) { + int r; + + r = parse_boolean(word + 20); + if (r < 0) + log_warning("Failed to parse crash shell switch %s. Ignoring.", word + 20); + else + arg_crash_shell = r; + + } else if (startswith(word, "systemd.confirm_spawn=")) { + int r; + + r = parse_boolean(word + 22); + if (r < 0) + log_warning("Failed to parse confirm spawn switch %s. Ignoring.", word + 22); + else + arg_confirm_spawn = r; + + } else if (startswith(word, "systemd.crash_chvt=")) { + int k; + + if (safe_atoi(word + 19, &k) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", word + 19); + else + arg_crash_chvt = k; + + } else if (startswith(word, "systemd.show_status=")) { + int r; + + r = parse_show_status(word + 20, &arg_show_status); + if (r < 0) + log_warning("Failed to parse show status switch %s. Ignoring.", word + 20); + } else if (startswith(word, "systemd.default_standard_output=")) { + int r; + + r = exec_output_from_string(word + 32); + if (r < 0) + log_warning("Failed to parse default standard output switch %s. Ignoring.", word + 32); + else + arg_default_std_output = r; + } else if (startswith(word, "systemd.default_standard_error=")) { + int r; + + r = exec_output_from_string(word + 31); + if (r < 0) + log_warning("Failed to parse default standard error switch %s. Ignoring.", word + 31); + else + arg_default_std_error = r; + } else if (startswith(word, "systemd.setenv=")) { + const char *cenv = word + 15; + + if (env_assignment_is_valid(cenv)) { + char **env; + + env = strv_env_set(arg_default_environment, cenv); + if (env) + arg_default_environment = env; + else + log_warning("Setting environment variable '%s' failed, ignoring: %s", + cenv, strerror(ENOMEM)); + } else + log_warning("Environment variable name '%s' is not valid. Ignoring.", cenv); + + } else if (startswith(word, "systemd.") || + (in_initrd() && startswith(word, "rd.systemd."))) { + + const char *c; + + /* Ignore systemd.journald.xyz and friends */ + c = word; + if (startswith(c, "rd.")) + c += 3; + if (startswith(c, "systemd.")) + c += 8; + if (c[strcspn(c, ".=")] != '.') { + + log_warning("Unknown kernel switch %s. Ignoring.", word); + + log_info("Supported kernel switches:\n" + "systemd.unit=UNIT Default unit to start\n" + "rd.systemd.unit=UNIT Default unit to start when run in initrd\n" + "systemd.dump_core=0|1 Dump core on crash\n" + "systemd.crash_shell=0|1 Run shell on crash\n" + "systemd.crash_chvt=N Change to VT #N on crash\n" + "systemd.confirm_spawn=0|1 Confirm every process spawn\n" + "systemd.show_status=0|1|auto Show status updates on the console during bootup\n" + "systemd.log_target=console|kmsg|journal|journal-or-kmsg|syslog|syslog-or-kmsg|null\n" + " Log target\n" + "systemd.log_level=LEVEL Log level\n" + "systemd.log_color=0|1 Highlight important log messages\n" + "systemd.log_location=0|1 Include code location in log messages\n" + "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n" + " Set default log output for services\n" + "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n" + " Set default log error output for services\n" + "systemd.setenv=ASSIGNMENT Set an environment variable for all spawned processes\n"); + } + + } else if (streq(word, "quiet")) { + if (arg_show_status == _SHOW_STATUS_UNSET) + arg_show_status = SHOW_STATUS_AUTO; + } else if (streq(word, "debug")) { + /* Log to kmsg, the journal socket will fill up before the + * journal is started and tools running during that time + * will block with every log message for for 60 seconds, + * before they give up. */ + log_set_max_level(LOG_DEBUG); + log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_KMSG); + } else if (!in_initrd()) { + unsigned i; + + /* SysV compatibility */ + for (i = 0; i < ELEMENTSOF(rlmap); i += 2) + if (streq(word, rlmap[i])) + return set_default_unit(rlmap[i+1]); + } + + return 0; +} + +#define DEFINE_SETTER(name, func, descr) \ + static int 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) { \ + \ + int r; \ + \ + assert(filename); \ + assert(lvalue); \ + assert(rvalue); \ + \ + r = func(rvalue); \ + if (r < 0) \ + log_syntax(unit, LOG_ERR, filename, line, -r, \ + "Invalid " descr "'%s': %s", \ + rvalue, strerror(-r)); \ + \ + return 0; \ + } + +DEFINE_SETTER(config_parse_level2, log_set_max_level_from_string, "log level") +DEFINE_SETTER(config_parse_target, log_set_target_from_string, "target") +DEFINE_SETTER(config_parse_color, log_show_color_from_string, "color" ) +DEFINE_SETTER(config_parse_location, log_show_location_from_string, "location") + +static int config_parse_cpu_affinity2(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) { + + char *w; + size_t l; + char *state; + cpu_set_t *c = NULL; + unsigned ncpus = 0; + + assert(filename); + assert(lvalue); + assert(rvalue); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + char *t; + int r; + unsigned cpu; + + if (!(t = strndup(w, l))) + return log_oom(); + + r = safe_atou(t, &cpu); + free(t); + + if (!c) + if (!(c = cpu_set_malloc(&ncpus))) + return log_oom(); + + if (r < 0 || cpu >= ncpus) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to parse CPU affinity '%s'", rvalue); + CPU_FREE(c); + return -EBADMSG; + } + + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + } + + if (c) { + if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) + log_warning_unit(unit, "Failed to set CPU affinity: %m"); + + CPU_FREE(c); + } + + return 0; +} + +static void strv_free_free(char ***l) { + char ***i; + + if (!l) + return; + + for (i = l; *i; i++) + strv_free(*i); + + free(l); +} + +static void free_join_controllers(void) { + strv_free_free(arg_join_controllers); + arg_join_controllers = NULL; +} + +static int config_parse_join_controllers(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) { + + unsigned n = 0; + char *state, *w; + size_t length; + + assert(filename); + assert(lvalue); + assert(rvalue); + + free_join_controllers(); + + FOREACH_WORD_QUOTED(w, length, rvalue, state) { + char *s, **l; + + s = strndup(w, length); + if (!s) + return log_oom(); + + l = strv_split(s, ","); + free(s); + + strv_uniq(l); + + if (strv_length(l) <= 1) { + strv_free(l); + continue; + } + + if (!arg_join_controllers) { + arg_join_controllers = new(char**, 2); + if (!arg_join_controllers) { + strv_free(l); + return log_oom(); + } + + arg_join_controllers[0] = l; + arg_join_controllers[1] = NULL; + + n = 1; + } else { + char ***a; + char ***t; + + t = new0(char**, n+2); + if (!t) { + strv_free(l); + return log_oom(); + } + + n = 0; + + for (a = arg_join_controllers; *a; a++) { + + if (strv_overlap(*a, l)) { + if (strv_extend_strv(&l, *a) < 0) { + strv_free(l); + strv_free_free(t); + return log_oom(); + } + + } else { + char **c; + + c = strv_copy(*a); + if (!c) { + strv_free(l); + strv_free_free(t); + return log_oom(); + } + + t[n++] = c; + } + } + + t[n++] = strv_uniq(l); + + strv_free_free(arg_join_controllers); + arg_join_controllers = t; + } + } + + return 0; +} + +static int parse_config_file(void) { + + const ConfigTableItem items[] = { + { "Manager", "LogLevel", config_parse_level2, 0, NULL }, + { "Manager", "LogTarget", config_parse_target, 0, NULL }, + { "Manager", "LogColor", config_parse_color, 0, NULL }, + { "Manager", "LogLocation", config_parse_location, 0, NULL }, + { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, + { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, + { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, + { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, + { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, + { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog }, + { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop }, +#ifdef HAVE_SECCOMP + { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs }, +#endif + { "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec }, + { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output }, + { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error }, + { "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec }, + { "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec }, + { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec }, + { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, + { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, + { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, +#ifdef CONFIG_TIZEN + { "Manager", "DefaultExtraDependencies", config_parse_strv, 0, &arg_default_extra_dependencies }, +#endif + { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, + { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, + { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, + { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, + { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, + { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, + { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, + { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, + { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, + { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, + { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, + { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, + { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, + { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, + { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, + { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, + {} + }; + + _cleanup_fclose_ FILE *f; + const char *fn; + int r; + + fn = arg_running_as == SYSTEMD_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf"; + f = fopen(fn, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_warning("Failed to open configuration file '%s': %m", fn); + return 0; + } + + r = config_parse(NULL, fn, f, "Manager\0", config_item_table_lookup, (void*) items, false, false, NULL); + if (r < 0) + log_warning("Failed to parse configuration file: %s", strerror(-r)); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_LOG_LEVEL = 0x100, + ARG_LOG_TARGET, + ARG_LOG_COLOR, + ARG_LOG_LOCATION, + ARG_UNIT, + ARG_SYSTEM, + ARG_USER, + ARG_TEST, + ARG_VERSION, + ARG_DUMP_CONFIGURATION_ITEMS, + ARG_DUMP_CORE, + ARG_CRASH_SHELL, + ARG_CONFIRM_SPAWN, + ARG_SHOW_STATUS, + ARG_DESERIALIZE, + ARG_SWITCHED_ROOT, + ARG_DEFAULT_STD_OUTPUT, + ARG_DEFAULT_STD_ERROR + }; + + static const struct option options[] = { + { "log-level", required_argument, NULL, ARG_LOG_LEVEL }, + { "log-target", required_argument, NULL, ARG_LOG_TARGET }, + { "log-color", optional_argument, NULL, ARG_LOG_COLOR }, + { "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, + { "unit", required_argument, NULL, ARG_UNIT }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "user", no_argument, NULL, ARG_USER }, + { "test", no_argument, NULL, ARG_TEST }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, + { "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, + { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, + { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, + { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, + { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, + { "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT }, + { "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, }, + { "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, }, + {} + }; + + int c, r; + + assert(argc >= 1); + assert(argv); + + if (getpid() == 1) + opterr = 0; + + while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0) + + switch (c) { + + case ARG_LOG_LEVEL: + r = log_set_max_level_from_string(optarg); + if (r < 0) { + log_error("Failed to parse log level %s.", optarg); + return r; + } + + break; + + case ARG_LOG_TARGET: + r = log_set_target_from_string(optarg); + if (r < 0) { + log_error("Failed to parse log target %s.", optarg); + return r; + } + + break; + + case ARG_LOG_COLOR: + + if (optarg) { + r = log_show_color_from_string(optarg); + if (r < 0) { + log_error("Failed to parse log color setting %s.", optarg); + return r; + } + } else + log_show_color(true); + + break; + + case ARG_LOG_LOCATION: + if (optarg) { + r = log_show_location_from_string(optarg); + if (r < 0) { + log_error("Failed to parse log location setting %s.", optarg); + return r; + } + } else + log_show_location(true); + + break; + + case ARG_DEFAULT_STD_OUTPUT: + r = exec_output_from_string(optarg); + if (r < 0) { + log_error("Failed to parse default standard output setting %s.", optarg); + return r; + } else + arg_default_std_output = r; + break; + + case ARG_DEFAULT_STD_ERROR: + r = exec_output_from_string(optarg); + if (r < 0) { + log_error("Failed to parse default standard error output setting %s.", optarg); + return r; + } else + arg_default_std_error = r; + break; + + case ARG_UNIT: + + r = set_default_unit(optarg); + if (r < 0) { + log_error("Failed to set default unit %s: %s", optarg, strerror(-r)); + return r; + } + + break; + + case ARG_SYSTEM: + arg_running_as = SYSTEMD_SYSTEM; + break; + + case ARG_USER: + arg_running_as = SYSTEMD_USER; + break; + + case ARG_TEST: + arg_action = ACTION_TEST; + break; + + case ARG_VERSION: + arg_action = ACTION_VERSION; + break; + + case ARG_DUMP_CONFIGURATION_ITEMS: + arg_action = ACTION_DUMP_CONFIGURATION_ITEMS; + break; + + case ARG_DUMP_CORE: + r = optarg ? parse_boolean(optarg) : 1; + if (r < 0) { + log_error("Failed to parse dump core boolean %s.", optarg); + return r; + } + arg_dump_core = r; + break; + + case ARG_CRASH_SHELL: + r = optarg ? parse_boolean(optarg) : 1; + if (r < 0) { + log_error("Failed to parse crash shell boolean %s.", optarg); + return r; + } + arg_crash_shell = r; + break; + + case ARG_CONFIRM_SPAWN: + r = optarg ? parse_boolean(optarg) : 1; + if (r < 0) { + log_error("Failed to parse confirm spawn boolean %s.", optarg); + return r; + } + arg_confirm_spawn = r; + break; + + case ARG_SHOW_STATUS: + if (optarg) { + r = parse_show_status(optarg, &arg_show_status); + if (r < 0) { + log_error("Failed to parse show status boolean %s.", optarg); + return r; + } + } else + arg_show_status = SHOW_STATUS_YES; + break; + + case ARG_DESERIALIZE: { + int fd; + FILE *f; + + r = safe_atoi(optarg, &fd); + if (r < 0 || fd < 0) { + log_error("Failed to parse deserialize option %s.", optarg); + return r < 0 ? r : -EINVAL; + } + + fd_cloexec(fd, true); + + f = fdopen(fd, "r"); + if (!f) { + log_error("Failed to open serialization fd: %m"); + return -errno; + } + + if (arg_serialization) + fclose(arg_serialization); + + arg_serialization = f; + + break; + } + + case ARG_SWITCHED_ROOT: + arg_switched_root = true; + break; + + case 'h': + arg_action = ACTION_HELP; + break; + + case 'D': + log_set_max_level(LOG_DEBUG); + break; + + case 'b': + case 's': + case 'z': + /* Just to eat away the sysvinit kernel + * cmdline args without getopt() error + * messages that we'll parse in + * parse_proc_cmdline_word() or ignore. */ + + case '?': + default: + if (getpid() != 1) { + log_error("Unknown option code %c", c); + return -EINVAL; + } + + break; + } + + if (optind < argc && getpid() != 1) { + /* Hmm, when we aren't run as init system + * let's complain about excess arguments */ + + log_error("Excess arguments."); + return -EINVAL; + } + + if (detect_container(NULL) > 0) { + char **a; + + /* All /proc/cmdline arguments the kernel didn't + * understand it passed to us. We're not really + * interested in that usually since /proc/cmdline is + * more interesting and complete. With one exception: + * if we are run in a container /proc/cmdline is not + * relevant for the container, hence we rely on argv[] + * instead. */ + + for (a = argv; a < argv + argc; a++) { + r = parse_proc_cmdline_word(*a); + if (r < 0) { + log_error("Failed on cmdline argument %s: %s", *a, strerror(-r)); + return r; + } + } + } + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Starts up and maintains the system or user services.\n\n" + " -h --help Show this help\n" + " --test Determine startup sequence, dump it and exit\n" + " --dump-configuration-items Dump understood unit configuration items\n" + " --unit=UNIT Set default unit\n" + " --system Run a system instance, even if PID != 1\n" + " --user Run a user instance\n" + " --dump-core[=0|1] Dump core on crash\n" + " --crash-shell[=0|1] Run shell on crash\n" + " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n" + " --show-status[=0|1] Show status updates on the console during bootup\n" + " --log-target=TARGET Set log target (console, journal, syslog, kmsg, journal-or-kmsg, syslog-or-kmsg, null)\n" + " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" + " --log-color[=0|1] Highlight important log messages\n" + " --log-location[=0|1] Include code location in log messages\n" + " --default-standard-output= Set default standard output for services\n" + " --default-standard-error= Set default standard error output for services\n", + program_invocation_short_name); + + return 0; +} + +static int version(void) { + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + + return 0; +} + +static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) { + FILE *f = NULL; + FDSet *fds = NULL; + int r; + + assert(m); + assert(_f); + assert(_fds); + + r = manager_open_serialization(m, &f); + if (r < 0) { + log_error("Failed to create serialization file: %s", strerror(-r)); + goto fail; + } + + /* Make sure nothing is really destructed when we shut down */ + m->n_reloading ++; + bus_manager_send_reloading(m, true); + + fds = fdset_new(); + if (!fds) { + r = -ENOMEM; + log_error("Failed to allocate fd set: %s", strerror(-r)); + goto fail; + } + + r = manager_serialize(m, f, fds, switching_root); + if (r < 0) { + log_error("Failed to serialize state: %s", strerror(-r)); + goto fail; + } + + if (fseeko(f, 0, SEEK_SET) < 0) { + log_error("Failed to rewind serialization fd: %m"); + goto fail; + } + + r = fd_cloexec(fileno(f), false); + if (r < 0) { + log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r)); + goto fail; + } + + r = fdset_cloexec(fds, false); + if (r < 0) { + log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r)); + goto fail; + } + + *_f = f; + *_fds = fds; + + return 0; + +fail: + fdset_free(fds); + + if (f) + fclose(f); + + return r; +} + +static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { + struct rlimit nl; + int r; + + assert(saved_rlimit); + + /* Save the original RLIMIT_NOFILE so that we can reset it + * later when transitioning from the initrd to the main + * systemd or suchlike. */ + if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0) { + log_error("Reading RLIMIT_NOFILE failed: %m"); + return -errno; + } + + /* Make sure forked processes get the default kernel setting */ + if (!arg_default_rlimit[RLIMIT_NOFILE]) { + struct rlimit *rl; + + rl = newdup(struct rlimit, saved_rlimit, 1); + if (!rl) + return log_oom(); + + arg_default_rlimit[RLIMIT_NOFILE] = rl; + } + + /* Bump up the resource limit for ourselves substantially */ + nl.rlim_cur = nl.rlim_max = 64*1024; + r = setrlimit_closest(RLIMIT_NOFILE, &nl); + if (r < 0) { + log_error("Setting RLIMIT_NOFILE failed: %s", strerror(-r)); + return r; + } + + return 0; +} + +static void test_mtab(void) { + char *p; + + /* Check that /etc/mtab is a symlink */ + + if (readlink_malloc("/etc/mtab", &p) >= 0) { + bool b; + + b = streq(p, "/proc/self/mounts") || streq(p, "/proc/mounts"); + free(p); + + if (b) + return; + } + + log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " + "This is not supported anymore. " + "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); +} + +static void test_usr(void) { + + /* Check that /usr is not a separate fs */ + + if (dir_is_empty("/usr") <= 0) + return; + + log_warning("/usr appears to be on its own filesytem and is not already mounted. This is not a supported setup. " + "Some things will probably break (sometimes even silently) in mysterious ways. " + "Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information."); +} + +static void test_cgroups(void) { + + if (access("/proc/cgroups", F_OK) >= 0) + return; + + log_warning("CONFIG_CGROUPS was not set when your kernel was compiled. " + "Systems without control groups are not supported. " + "We will now sleep for 10s, and then continue boot-up. " + "Expect breakage and please do not file bugs. " + "Instead fix your kernel and enable CONFIG_CGROUPS. " + "Consult http://0pointer.de/blog/projects/cgroups-vs-cgroups.html for more information."); + + sleep(10); +} + +static int initialize_join_controllers(void) { + /* By default, mount "cpu" + "cpuacct" together, and "net_cls" + * + "net_prio". We'd like to add "cpuset" to the mix, but + * "cpuset" does't really work for groups with no initialized + * attributes. */ + + arg_join_controllers = new(char**, 3); + if (!arg_join_controllers) + return -ENOMEM; + + arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL); + arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); + arg_join_controllers[2] = NULL; + + if (!arg_join_controllers[0] || !arg_join_controllers[1]) { + free_join_controllers(); + return -ENOMEM; + } + + return 0; +} + +static int enforce_syscall_archs(Set *archs) { +#ifdef HAVE_SECCOMP + scmp_filter_ctx *seccomp; + Iterator i; + void *id; + int r; + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return log_oom(); + + SET_FOREACH(id, arg_syscall_archs, i) { + r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1); + if (r == -EEXIST) + continue; + if (r < 0) { + log_error("Failed to add architecture to seccomp: %s", strerror(-r)); + goto finish; + } + } + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) { + log_error("Failed to unset NO_NEW_PRIVS: %s", strerror(-r)); + goto finish; + } + + r = seccomp_load(seccomp); + if (r < 0) + log_error("Failed to add install architecture seccomp: %s", strerror(-r)); + +finish: + seccomp_release(seccomp); + return r; +#else + return 0; +#endif +} + +static int status_welcome(void) { + _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; + int r; + + r = parse_env_file("/etc/os-release", NEWLINE, + "PRETTY_NAME", &pretty_name, + "ANSI_COLOR", &ansi_color, + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/os-release: %s", strerror(-r)); + + return status_printf(NULL, false, false, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", + isempty(ansi_color) ? "1" : ansi_color, + isempty(pretty_name) ? "Linux" : pretty_name); +} + +int main(int argc, char *argv[]) { + Manager *m = NULL; + int r, retval = EXIT_FAILURE; + usec_t before_startup, after_startup; + char timespan[FORMAT_TIMESPAN_MAX]; + FDSet *fds = NULL; + bool reexecute = false; + const char *shutdown_verb = NULL; + dual_timestamp initrd_timestamp = { 0ULL, 0ULL }; + dual_timestamp userspace_timestamp = { 0ULL, 0ULL }; + dual_timestamp kernel_timestamp = { 0ULL, 0ULL }; + dual_timestamp security_start_timestamp = { 0ULL, 0ULL }; + dual_timestamp security_finish_timestamp = { 0ULL, 0ULL }; + static char systemd[] = "systemd"; + bool skip_setup = false; + unsigned j; + bool loaded_policy = false; + bool arm_reboot_watchdog = false; + bool queue_default_job = false; + char *switch_root_dir = NULL, *switch_root_init = NULL; + static struct rlimit saved_rlimit_nofile = { 0, 0 }; + +#ifdef HAVE_SYSV_COMPAT + if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { + /* This is compatibility support for SysV, where + * calling init as a user is identical to telinit. */ + + errno = -ENOENT; + execv(SYSTEMCTL_BINARY_PATH, argv); + log_error("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m"); + return 1; + } +#endif + + dual_timestamp_from_monotonic(&kernel_timestamp, 0); + dual_timestamp_get(&userspace_timestamp); + + /* Determine if this is a reexecution or normal bootup. We do + * the full command line parsing much later, so let's just + * have a quick peek here. */ + if (strv_find(argv+1, "--deserialize")) + skip_setup = true; + + /* If we have switched root, do all the special setup + * things */ + if (strv_find(argv+1, "--switched-root")) + skip_setup = false; + + /* If we get started via the /sbin/init symlink then we are + called 'init'. After a subsequent reexecution we are then + called 'systemd'. That is confusing, hence let's call us + systemd right-away. */ + program_invocation_short_name = systemd; + prctl(PR_SET_NAME, systemd); + + saved_argv = argv; + saved_argc = argc; + + log_show_color(isatty(STDERR_FILENO) > 0); + + /* Disable the umask logic */ + if (getpid() == 1) + umask(0); + + if (getpid() == 1 && detect_container(NULL) <= 0) { + + /* Running outside of a container as PID 1 */ + arg_running_as = SYSTEMD_SYSTEM; + make_null_stdio(); + log_set_target(LOG_TARGET_KMSG); + log_open(); + + if (in_initrd()) + initrd_timestamp = userspace_timestamp; + + if (!skip_setup) { + mount_setup_early(); + dual_timestamp_get(&security_start_timestamp); + if (selinux_setup(&loaded_policy) < 0) + goto finish; + if (ima_setup() < 0) + goto finish; +#ifndef CONFIG_TIZEN_WIP + /* FIXME */ + /* smack_setup is temporary blocked. Now Tizen + * is using newest feature of smack. Invalid + * argument will occur in fflush by dual + * permission field. Until smack_setup cover + * the new feature it will be blocked. When + * the smack_setup can cover the dual + * permission field then smack.service should + * be removed. */ + if (smack_setup(&loaded_policy) < 0) + goto finish; +#endif + dual_timestamp_get(&security_finish_timestamp); + } + + if (label_init(NULL) < 0) + goto finish; + + if (!skip_setup) { + if (hwclock_is_localtime() > 0) { + int min; + + /* The first-time call to settimeofday() does a time warp in the kernel */ + r = hwclock_set_timezone(&min); + if (r < 0) + log_error("Failed to apply local time delta, ignoring: %s", strerror(-r)); + else + log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); + } else if (!in_initrd()) { + /* + * Do dummy first-time call to seal the kernel's time warp magic + * + * Do not call this this from inside the initrd. The initrd might not + * carry /etc/adjtime with LOCAL, but the real system could be set up + * that way. In such case, we need to delay the time-warp or the sealing + * until we reach the real system. + */ + hwclock_reset_timezone(); + + /* Tell the kernel our timezone */ + r = hwclock_set_timezone(NULL); + if (r < 0) + log_error("Failed to set the kernel's timezone, ignoring: %s", strerror(-r)); + } + } + + /* Set the default for later on, but don't actually + * open the logs like this for now. Note that if we + * are transitioning from the initrd there might still + * be journal fd open, and we shouldn't attempt + * opening that before we parsed /proc/cmdline which + * might redirect output elsewhere. */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + + } else if (getpid() == 1) { + /* Running inside a container, as PID 1 */ + arg_running_as = SYSTEMD_SYSTEM; + log_set_target(LOG_TARGET_CONSOLE); + log_close_console(); /* force reopen of /dev/console */ + log_open(); + + /* For the later on, see above... */ + log_set_target(LOG_TARGET_JOURNAL); + + /* clear the kernel timestamp, + * because we are in a container */ + kernel_timestamp.monotonic = 0ULL; + kernel_timestamp.realtime = 0ULL; + + } else { + /* Running as user instance */ + arg_running_as = SYSTEMD_USER; + log_set_target(LOG_TARGET_AUTO); + log_open(); + + /* clear the kernel timestamp, + * because we are not PID 1 */ + kernel_timestamp.monotonic = 0ULL; + kernel_timestamp.realtime = 0ULL; + } + + /* Initialize default unit */ + r = set_default_unit(SPECIAL_DEFAULT_TARGET); + if (r < 0) { + log_error("Failed to set default unit %s: %s", SPECIAL_DEFAULT_TARGET, strerror(-r)); + goto finish; + } + + r = initialize_join_controllers(); + if (r < 0) + goto finish; + + /* Mount /proc, /sys and friends, so that /proc/cmdline and + * /proc/$PID/fd is available. */ + if (getpid() == 1) { + r = mount_setup(loaded_policy); + if (r < 0) + goto finish; + } + + /* Reset all signal handlers. */ + assert_se(reset_all_signal_handlers() == 0); + + ignore_signals(SIGNALS_IGNORE, -1); + + if (parse_config_file() < 0) + goto finish; + + if (arg_running_as == SYSTEMD_SYSTEM) + if (parse_proc_cmdline(parse_proc_cmdline_word) < 0) + goto finish; + + log_parse_environment(); + + if (parse_argv(argc, argv) < 0) + goto finish; + + if (arg_action == ACTION_TEST && + geteuid() == 0) { + log_error("Don't run test mode as root."); + goto finish; + } + + if (arg_running_as == SYSTEMD_USER && + arg_action == ACTION_RUN && + sd_booted() <= 0) { + log_error("Trying to run as user instance, but the system has not been booted with systemd."); + goto finish; + } + + if (arg_running_as == SYSTEMD_SYSTEM && + arg_action == ACTION_RUN && + running_in_chroot() > 0) { + log_error("Cannot be run in a chroot() environment."); + goto finish; + } + + if (arg_action == ACTION_HELP) { + retval = help(); + goto finish; + } else if (arg_action == ACTION_VERSION) { + retval = version(); + goto finish; + } else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) { + unit_dump_config_items(stdout); + retval = EXIT_SUCCESS; + goto finish; + } else if (arg_action == ACTION_DONE) { + retval = EXIT_SUCCESS; + goto finish; + } + + if (arg_running_as == SYSTEMD_USER && + !getenv("XDG_RUNTIME_DIR")) { + log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set."); + goto finish; + } + + assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST); + + /* Close logging fds, in order not to confuse fdset below */ + log_close(); + + /* Remember open file descriptors for later deserialization */ + r = fdset_new_fill(&fds); + if (r < 0) { + log_error("Failed to allocate fd set: %s", strerror(-r)); + goto finish; + } else + fdset_cloexec(fds, true); + + if (arg_serialization) + assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0); + + if (arg_running_as == SYSTEMD_SYSTEM) + /* Become a session leader if we aren't one yet. */ + setsid(); + + /* Move out of the way, so that we won't block unmounts */ + assert_se(chdir("/") == 0); + + /* Reset the console, but only if this is really init and we + * are freshly booted */ + if (arg_running_as == SYSTEMD_SYSTEM && arg_action == ACTION_RUN) + console_setup(getpid() == 1 && !skip_setup); + + /* Open the logging devices, if possible and necessary */ + log_open(); + + if (arg_show_status == _SHOW_STATUS_UNSET) + arg_show_status = SHOW_STATUS_YES; + + /* Make sure we leave a core dump without panicing the + * kernel. */ + if (getpid() == 1) { + install_crash_handler(); + + r = mount_cgroup_controllers(arg_join_controllers); + if (r < 0) + goto finish; + } + + if (arg_running_as == SYSTEMD_SYSTEM) { + const char *virtualization = NULL; + + log_info(PACKAGE_STRING " running in system mode. (" SYSTEMD_FEATURES ")"); + + detect_virtualization(&virtualization); + if (virtualization) + log_info("Detected virtualization '%s'.", virtualization); + + log_info("Detected architecture '%s'.", architecture_to_string(uname_architecture())); + + if (in_initrd()) + log_info("Running in initial RAM disk."); + + } else { + _cleanup_free_ char *t = uid_to_name(getuid()); + log_debug(PACKAGE_STRING " running in user mode for user "PID_FMT"/%s. (" SYSTEMD_FEATURES ")", + getuid(), t); + } + + if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) { + if (arg_show_status > 0 || plymouth_running()) + status_welcome(); + +#ifdef HAVE_KMOD + if (detect_container(NULL) <= 0) + kmod_setup(); +#endif + hostname_setup(); + machine_id_setup(); + loopback_setup(); + + test_mtab(); + test_usr(); + test_cgroups(); + } + + if (arg_running_as == SYSTEMD_SYSTEM && arg_runtime_watchdog > 0) + watchdog_set_timeout(&arg_runtime_watchdog); + + if (arg_timer_slack_nsec != (nsec_t) -1) + if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) + log_error("Failed to adjust timer slack: %m"); + + if (arg_capability_bounding_set_drop) { + r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop); + if (r < 0) { + log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r)); + goto finish; + } + r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true); + if (r < 0) { + log_error("Failed to drop capability bounding set: %s", strerror(-r)); + goto finish; + } + } + + if (arg_syscall_archs) { + r = enforce_syscall_archs(arg_syscall_archs); + if (r < 0) + goto finish; + } + + if (arg_running_as == SYSTEMD_USER) { + /* Become reaper of our children */ + if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) { + log_warning("Failed to make us a subreaper: %m"); + if (errno == EINVAL) + log_info("Perhaps the kernel version is too old (< 3.4?)"); + } + } + + if (arg_running_as == SYSTEMD_SYSTEM) + bump_rlimit_nofile(&saved_rlimit_nofile); + + r = manager_new(arg_running_as, &m); + if (r < 0) { + log_error("Failed to allocate manager object: %s", strerror(-r)); + goto finish; + } + + m->confirm_spawn = arg_confirm_spawn; + m->default_std_output = arg_default_std_output; + m->default_std_error = arg_default_std_error; + m->default_restart_usec = arg_default_restart_usec; + m->default_timeout_start_usec = arg_default_timeout_start_usec; + m->default_timeout_stop_usec = arg_default_timeout_stop_usec; + m->default_start_limit_interval = arg_default_start_limit_interval; + m->default_start_limit_burst = arg_default_start_limit_burst; + m->runtime_watchdog = arg_runtime_watchdog; + m->shutdown_watchdog = arg_shutdown_watchdog; + m->userspace_timestamp = userspace_timestamp; + m->kernel_timestamp = kernel_timestamp; + m->initrd_timestamp = initrd_timestamp; + m->security_start_timestamp = security_start_timestamp; + m->security_finish_timestamp = security_finish_timestamp; + + manager_set_default_rlimits(m, arg_default_rlimit); + manager_environment_add(m, NULL, arg_default_environment); +#ifdef CONFIG_TIZEN + if (arg_running_as == SYSTEMD_SYSTEM && arg_default_extra_dependencies) + manager_set_default_extra_dependencies(m, arg_default_extra_dependencies); +#endif + manager_set_show_status(m, arg_show_status); + + /* Remember whether we should queue the default job */ + queue_default_job = !arg_serialization || arg_switched_root; + + before_startup = now(CLOCK_MONOTONIC); + + r = manager_startup(m, arg_serialization, fds); + if (r < 0) + log_error("Failed to fully start up daemon: %s", strerror(-r)); + + /* This will close all file descriptors that were opened, but + * not claimed by any unit. */ + fdset_free(fds); + fds = NULL; + + if (arg_serialization) { + fclose(arg_serialization); + arg_serialization = NULL; + } + + if (queue_default_job) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + Unit *target = NULL; + Job *default_unit_job; + + log_debug("Activating default unit: %s", arg_default_unit); + + r = manager_load_unit(m, arg_default_unit, NULL, &error, &target); + if (r < 0) + log_error("Failed to load default target: %s", bus_error_message(&error, r)); + else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) + log_error("Failed to load default target: %s", strerror(-target->load_error)); + else if (target->load_state == UNIT_MASKED) + log_error("Default target masked."); + + if (!target || target->load_state != UNIT_LOADED) { + log_info("Trying to load rescue target..."); + + r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target); + if (r < 0) { + log_error("Failed to load rescue target: %s", bus_error_message(&error, r)); + goto finish; + } else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) { + log_error("Failed to load rescue target: %s", strerror(-target->load_error)); + goto finish; + } else if (target->load_state == UNIT_MASKED) { + log_error("Rescue target masked."); + goto finish; + } + } + + assert(target->load_state == UNIT_LOADED); + + if (arg_action == ACTION_TEST) { + printf("-> By units:\n"); + manager_dump_units(m, stdout, "\t"); + } + + r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job); + if (r == -EPERM) { + log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r)); + + r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job); + if (r < 0) { + log_error("Failed to start default target: %s", bus_error_message(&error, r)); + goto finish; + } + } else if (r < 0) { + log_error("Failed to isolate default target: %s", bus_error_message(&error, r)); + goto finish; + } + + m->default_unit_job_id = default_unit_job->id; + + after_startup = now(CLOCK_MONOTONIC); + log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG, + "Loaded units and determined initial transaction in %s.", + format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 0)); + + if (arg_action == ACTION_TEST) { + printf("-> By jobs:\n"); + manager_dump_jobs(m, stdout, "\t"); + retval = EXIT_SUCCESS; + goto finish; + } + } + + for (;;) { + r = manager_loop(m); + if (r < 0) { + log_error("Failed to run mainloop: %s", strerror(-r)); + goto finish; + } + + switch (m->exit_code) { + + case MANAGER_EXIT: + retval = EXIT_SUCCESS; + log_debug("Exit."); + goto finish; + + case MANAGER_RELOAD: + log_info("Reloading."); + r = manager_reload(m); + if (r < 0) + log_error("Failed to reload: %s", strerror(-r)); + break; + + case MANAGER_REEXECUTE: + + if (prepare_reexecute(m, &arg_serialization, &fds, false) < 0) + goto finish; + + reexecute = true; + log_notice("Reexecuting."); + goto finish; + + case MANAGER_SWITCH_ROOT: + /* Steal the switch root parameters */ + switch_root_dir = m->switch_root; + switch_root_init = m->switch_root_init; + m->switch_root = m->switch_root_init = NULL; + + if (!switch_root_init) + if (prepare_reexecute(m, &arg_serialization, &fds, true) < 0) + goto finish; + + reexecute = true; + log_notice("Switching root."); + goto finish; + + case MANAGER_REBOOT: + case MANAGER_POWEROFF: + case MANAGER_HALT: + case MANAGER_KEXEC: { + static const char * const table[_MANAGER_EXIT_CODE_MAX] = { + [MANAGER_REBOOT] = "reboot", + [MANAGER_POWEROFF] = "poweroff", + [MANAGER_HALT] = "halt", + [MANAGER_KEXEC] = "kexec" + }; + + assert_se(shutdown_verb = table[m->exit_code]); + arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT; + + log_notice("Shutting down."); + goto finish; + } + + default: + assert_not_reached("Unknown exit code."); + } + } + +finish: + if (m) { + manager_free(m); + m = NULL; + } + + for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) { + free(arg_default_rlimit[j]); + arg_default_rlimit[j] = NULL; + } + + free(arg_default_unit); + arg_default_unit = NULL; + + free_join_controllers(); + + strv_free(arg_default_environment); + arg_default_environment = NULL; + + set_free(arg_syscall_archs); + arg_syscall_archs = NULL; + + label_finish(); + + if (reexecute) { + const char **args; + unsigned i, args_size; + + /* Close and disarm the watchdog, so that the new + * instance can reinitialize it, but doesn't get + * rebooted while we do that */ + watchdog_close(true); + + /* Reset the RLIMIT_NOFILE to the kernel default, so + * that the new systemd can pass the kernel default to + * its child processes */ + if (saved_rlimit_nofile.rlim_cur > 0) + setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); + + if (switch_root_dir) { + /* Kill all remaining processes from the + * initrd, but don't wait for them, so that we + * can handle the SIGCHLD for them after + * deserializing. */ + broadcast_signal(SIGTERM, false, true); + + /* And switch root */ + r = switch_root(switch_root_dir); + if (r < 0) + log_error("Failed to switch root, ignoring: %s", strerror(-r)); + } + + args_size = MAX(6, argc+1); + args = newa(const char*, args_size); + + if (!switch_root_init) { + char sfd[16]; + + /* First try to spawn ourselves with the right + * path, and with full serialization. We do + * this only if the user didn't specify an + * explicit init to spawn. */ + + assert(arg_serialization); + assert(fds); + + snprintf(sfd, sizeof(sfd), "%i", fileno(arg_serialization)); + char_array_0(sfd); + + i = 0; + args[i++] = SYSTEMD_BINARY_PATH; + if (switch_root_dir) + args[i++] = "--switched-root"; + args[i++] = arg_running_as == SYSTEMD_SYSTEM ? "--system" : "--user"; + args[i++] = "--deserialize"; + args[i++] = sfd; + args[i++] = NULL; + + /* do not pass along the environment we inherit from the kernel or initrd */ + if (switch_root_dir) + clearenv(); + + assert(i <= args_size); + execv(args[0], (char* const*) args); + } + + /* Try the fallback, if there is any, without any + * serialization. We pass the original argv[] and + * envp[]. (Well, modulo the ordering changes due to + * getopt() in argv[], and some cleanups in envp[], + * but let's hope that doesn't matter.) */ + + if (arg_serialization) { + fclose(arg_serialization); + arg_serialization = NULL; + } + + if (fds) { + fdset_free(fds); + fds = NULL; + } + + /* Reopen the console */ + make_console_stdio(); + + for (j = 1, i = 1; j < (unsigned) argc; j++) + args[i++] = argv[j]; + args[i++] = NULL; + assert(i <= args_size); + + if (switch_root_init) { + args[0] = switch_root_init; + execv(args[0], (char* const*) args); + log_warning("Failed to execute configured init, trying fallback: %m"); + } + + args[0] = "/sbin/init"; + execv(args[0], (char* const*) args); + + if (errno == ENOENT) { + log_warning("No /sbin/init, trying fallback"); + + args[0] = "/bin/sh"; + args[1] = NULL; + execv(args[0], (char* const*) args); + log_error("Failed to execute /bin/sh, giving up: %m"); + } else + log_warning("Failed to execute /sbin/init, giving up: %m"); + } + + if (arg_serialization) { + fclose(arg_serialization); + arg_serialization = NULL; + } + + if (fds) { + fdset_free(fds); + fds = NULL; + } + +#ifdef HAVE_VALGRIND_VALGRIND_H + /* If we are PID 1 and running under valgrind, then let's exit + * here explicitly. valgrind will only generate nice output on + * exit(), not on exec(), hence let's do the former not the + * latter here. */ + if (getpid() == 1 && RUNNING_ON_VALGRIND) + return 0; +#endif + + if (shutdown_verb) { + char log_level[DECIMAL_STR_MAX(int) + 1]; + const char* command_line[9] = { + SYSTEMD_SHUTDOWN_BINARY_PATH, + shutdown_verb, + "--log-level", log_level, + "--log-target", + }; + unsigned pos = 5; + _cleanup_strv_free_ char **env_block = NULL; + + assert(command_line[pos] == NULL); + env_block = strv_copy(environ); + + snprintf(log_level, sizeof(log_level), "%d", log_get_max_level()); + + switch (log_get_target()) { + case LOG_TARGET_KMSG: + case LOG_TARGET_JOURNAL_OR_KMSG: + case LOG_TARGET_SYSLOG_OR_KMSG: + command_line[pos++] = "kmsg"; + break; + + case LOG_TARGET_CONSOLE: + default: + command_line[pos++] = "console"; + break; + }; + + if (log_get_show_color()) + command_line[pos++] = "--log-color"; + + if (log_get_show_location()) + command_line[pos++] = "--log-location"; + + assert(pos + 1 < ELEMENTSOF(command_line)); + + if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { + char *e; + + /* If we reboot let's set the shutdown + * watchdog and tell the shutdown binary to + * repeatedly ping it */ + watchdog_set_timeout(&arg_shutdown_watchdog); + watchdog_close(false); + + /* Tell the binary how often to ping, ignore failure */ + if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0) + strv_push(&env_block, e); + } else + watchdog_close(true); + + /* Avoid the creation of new processes forked by the + * kernel; at this point, we will not listen to the + * signals anyway */ + if (detect_container(NULL) <= 0) + cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER); + + execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block); + log_error("Failed to execute shutdown binary, %s: %m", + getpid() == 1 ? "freezing" : "quitting"); + } + + if (getpid() == 1) + freeze(); + + return retval; +} diff --git a/src/core/manager.c b/src/core/manager.c new file mode 100644 index 0000000..13cc645 --- /dev/null +++ b/src/core/manager.c @@ -0,0 +1,2940 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_AUDIT +#include +#endif + +#include "sd-daemon.h" +#include "sd-id128.h" +#include "sd-messages.h" + +#include "manager.h" +#include "transaction.h" +#include "hashmap.h" +#include "macro.h" +#include "strv.h" +#include "log.h" +#include "util.h" +#include "mkdir.h" +#include "ratelimit.h" +#include "locale-setup.h" +#include "mount-setup.h" +#include "unit-name.h" +#include "missing.h" +#include "path-lookup.h" +#include "special.h" +#include "exit-status.h" +#include "virt.h" +#include "watchdog.h" +#include "cgroup-util.h" +#include "path-util.h" +#include "audit-fd.h" +#include "boot-timestamps.h" +#include "env-util.h" +#include "bus-errors.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dbus.h" +#include "dbus-unit.h" +#include "dbus-job.h" +#include "dbus-manager.h" +#include "bus-kernel.h" + +/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */ +#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC) + +/* Initial delay and the interval for printing status messages about running jobs */ +#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) +#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3) +#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 + +/* Where clients shall send notification messages to */ +#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify" + +#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) + +static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata); +static int manager_dispatch_run_queue(sd_event_source *source, void *userdata); + +static int manager_watch_jobs_in_progress(Manager *m) { + usec_t next; + + assert(m); + + if (m->jobs_in_progress_event_source) + return 0; + + next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC; + return sd_event_add_monotonic(m->event, &m->jobs_in_progress_event_source, next, 0, manager_dispatch_jobs_in_progress, m); +} + +#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1)) + +static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) { + char *p = buffer; + + assert(buflen >= CYLON_BUFFER_EXTRA + width + 1); + assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */ + + if (pos > 1) { + if (pos > 2) + p = mempset(p, ' ', pos-2); + p = stpcpy(p, ANSI_RED_ON); + *p++ = '*'; + } + + if (pos > 0 && pos <= width) { + p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON); + *p++ = '*'; + } + + p = stpcpy(p, ANSI_HIGHLIGHT_OFF); + + if (pos < width) { + p = stpcpy(p, ANSI_RED_ON); + *p++ = '*'; + if (pos < width-1) + p = mempset(p, ' ', width-1-pos); + strcpy(p, ANSI_HIGHLIGHT_OFF); + } +} + +void manager_flip_auto_status(Manager *m, bool enable) { + if (enable) { + if (m->show_status == SHOW_STATUS_AUTO) + manager_set_show_status(m, SHOW_STATUS_TEMPORARY); + } else { + if (m->show_status == SHOW_STATUS_TEMPORARY) + manager_set_show_status(m, SHOW_STATUS_AUTO); + } +} + +static void manager_print_jobs_in_progress(Manager *m) { + _cleanup_free_ char *job_of_n = NULL; + Iterator i; + Job *j; + unsigned counter = 0, print_nr; + char cylon[6 + CYLON_BUFFER_EXTRA + 1]; + unsigned cylon_pos; + char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit"; + uint64_t x; + + assert(m); + + manager_flip_auto_status(m, true); + + print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs; + + HASHMAP_FOREACH(j, m->jobs, i) + if (j->state == JOB_RUNNING && counter++ == print_nr) + break; + + /* m->n_running_jobs must be consistent with the contents of m->jobs, + * so the above loop must have succeeded in finding j. */ + assert(counter == print_nr + 1); + assert(j); + + cylon_pos = m->jobs_in_progress_iteration % 14; + if (cylon_pos >= 8) + cylon_pos = 14 - cylon_pos; + draw_cylon(cylon, sizeof(cylon), 6, cylon_pos); + + m->jobs_in_progress_iteration++; + + if (m->n_running_jobs > 1) + if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0) + job_of_n = NULL; + + format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC); + if (job_get_timeout(j, &x) > 0) + format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC); + + manager_status_printf(m, true, cylon, + "%sA %s job is running for %s (%s / %s)", + strempty(job_of_n), + job_type_to_string(j->type), + unit_description(j->unit), + time, limit); + +} + +static int manager_watch_idle_pipe(Manager *m) { + int r; + + assert(m); + + if (m->idle_pipe_event_source) + return 0; + + if (m->idle_pipe[2] < 0) + return 0; + + r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m); + if (r < 0) { + log_error("Failed to watch idle pipe: %s", strerror(-r)); + return r; + } + + return 0; +} + +static void manager_close_idle_pipe(Manager *m) { + assert(m); + + close_pipe(m->idle_pipe); + close_pipe(m->idle_pipe + 2); +} + +static int manager_setup_time_change(Manager *m) { + int r; + + /* We only care for the cancellation event, hence we set the + * timeout to the latest possible value. */ + struct itimerspec its = { + .it_value.tv_sec = TIME_T_MAX, + }; + + assert(m); + assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX)); + + /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever + * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */ + + m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (m->time_change_fd < 0) { + log_error("Failed to create timerfd: %m"); + return -errno; + } + + if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) { + log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m"); + close_nointr_nofail(m->time_change_fd); + m->time_change_fd = -1; + return 0; + } + + r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m); + if (r < 0) { + log_error("Failed to create time change event source: %s", strerror(-r)); + return r; + } + + log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd."); + + return 0; +} + +static int enable_special_signals(Manager *m) { + _cleanup_close_ int fd = -1; + + assert(m); + + /* Enable that we get SIGINT on control-alt-del. In containers + * this will fail with EPERM (older) or EINVAL (newer), so + * ignore that. */ + if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL) + log_warning("Failed to enable ctrl-alt-del handling: %m"); + + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) { + /* Support systems without virtual console */ + if (fd != -ENOENT) + log_warning("Failed to open /dev/tty0: %m"); + } else { + /* Enable that we get SIGWINCH on kbrequest */ + if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0) + log_warning("Failed to enable kbrequest handling: %m"); + } + + return 0; +} + +static int manager_setup_signals(Manager *m) { + struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_NOCLDSTOP|SA_RESTART, + }; + sigset_t mask; + int r; + + assert(m); + + /* We are not interested in SIGSTOP and friends. */ + assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + + assert_se(sigemptyset(&mask) == 0); + + sigset_add_many(&mask, + SIGCHLD, /* Child died */ + SIGTERM, /* Reexecute daemon */ + SIGHUP, /* Reload configuration */ + SIGUSR1, /* systemd/upstart: reconnect to D-Bus */ + SIGUSR2, /* systemd: dump status */ + SIGINT, /* Kernel sends us this on control-alt-del */ + SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */ + SIGPWR, /* Some kernel drivers and upsd send us this on power failure */ + SIGRTMIN+0, /* systemd: start default.target */ + SIGRTMIN+1, /* systemd: isolate rescue.target */ + SIGRTMIN+2, /* systemd: isolate emergency.target */ + SIGRTMIN+3, /* systemd: start halt.target */ + SIGRTMIN+4, /* systemd: start poweroff.target */ + SIGRTMIN+5, /* systemd: start reboot.target */ + SIGRTMIN+6, /* systemd: start kexec.target */ + SIGRTMIN+13, /* systemd: Immediate halt */ + SIGRTMIN+14, /* systemd: Immediate poweroff */ + SIGRTMIN+15, /* systemd: Immediate reboot */ + SIGRTMIN+16, /* systemd: Immediate kexec */ + SIGRTMIN+20, /* systemd: enable status messages */ + SIGRTMIN+21, /* systemd: disable status messages */ + SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */ + SIGRTMIN+23, /* systemd: set log level to LOG_INFO */ + SIGRTMIN+24, /* systemd: Immediate exit (--user only) */ + SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */ + SIGRTMIN+27, /* systemd: set log target to console */ + SIGRTMIN+28, /* systemd: set log target to kmsg */ + SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */ + -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (m->signal_fd < 0) + return -errno; + + r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m); + if (r < 0) + return r; + + /* Process signals a bit earlier than the rest of things, but + * later that notify_fd processing, so that the notify + * processing can still figure out to which process/service a + * message belongs, before we reap the process. */ + r = sd_event_source_set_priority(m->signal_event_source, -5); + if (r < 0) + return r; + + if (m->running_as == SYSTEMD_SYSTEM) + return enable_special_signals(m); + + return 0; +} + +static void manager_clean_environment(Manager *m) { + assert(m); + + /* Let's remove some environment variables that we + * need ourselves to communicate with our clients */ + strv_env_unset_many( + m->environment, + "NOTIFY_SOCKET", + "MAINPID", + "MANAGERPID", + "LISTEN_PID", + "LISTEN_FDS", + "WATCHDOG_PID", + "WATCHDOG_USEC", + NULL); +} + +static int manager_default_environment(Manager *m) { + assert(m); + + if (m->running_as == SYSTEMD_SYSTEM) { + /* The system manager always starts with a clean + * environment for its children. It does not import + * the kernel or the parents exported variables. + * + * The initial passed environ is untouched to keep + * /proc/self/environ valid; it is used for tagging + * the init process inside containers. */ + m->environment = strv_new("PATH=" DEFAULT_PATH, + NULL); + + /* Import locale variables LC_*= from configuration */ + locale_setup(&m->environment); + } else { + /* The user manager passes its own environment + * along to its children. */ + m->environment = strv_copy(environ); + } + + if (!m->environment) + return -ENOMEM; + + manager_clean_environment(m); + strv_sort(m->environment); + + return 0; +} + +int manager_new(SystemdRunningAs running_as, Manager **_m) { + Manager *m; + int r; + + assert(_m); + assert(running_as >= 0); + assert(running_as < _SYSTEMD_RUNNING_AS_MAX); + + m = new0(Manager, 1); + if (!m) + return -ENOMEM; + +#ifdef ENABLE_EFI + if (detect_container(NULL) <= 0) + boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp); +#endif + + m->running_as = running_as; + m->exit_code = _MANAGER_EXIT_CODE_INVALID; + + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; + + m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = -1; + m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ + + r = manager_default_environment(m); + if (r < 0) + goto fail; + + r = hashmap_ensure_allocated(&m->units, string_hash_func, string_compare_func); + if (r < 0) + goto fail; + + r = hashmap_ensure_allocated(&m->jobs, trivial_hash_func, trivial_compare_func); + if (r < 0) + goto fail; + + r = hashmap_ensure_allocated(&m->cgroup_unit, string_hash_func, string_compare_func); + if (r < 0) + goto fail; + + r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func); + if (r < 0) + goto fail; + + r = sd_event_default(&m->event); + if (r < 0) + goto fail; + + r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m); + if (r < 0) + goto fail; + +#ifdef CONFIG_TIZEN + m->dep_ignore_list = set_new(string_hash_func, string_compare_func); + if (!m->dep_ignore_list) + goto fail; +#endif + + r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + goto fail; + + r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF); + if (r < 0) + goto fail; + + r = manager_setup_signals(m); + if (r < 0) + goto fail; + + r = manager_setup_cgroup(m); + if (r < 0) + goto fail; + + r = manager_setup_time_change(m); + if (r < 0) + goto fail; + + m->udev = udev_new(); + if (!m->udev) { + r = -ENOMEM; + goto fail; + } + + /* Note that we set up neither kdbus, nor the notify fd + * here. We do that after deserialization, since they might + * have gotten serialized across the reexec. */ + + m->taint_usr = dir_is_empty("/usr") > 0; + + *_m = m; + return 0; + +fail: + manager_free(m); + return r; +} + +static int manager_setup_notify(Manager *m) { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa = { + .sa.sa_family = AF_UNIX, + }; + int one = 1, r; + + if (m->notify_fd < 0) { + _cleanup_close_ int fd = -1; + + /* First free all secondary fields */ + free(m->notify_socket); + m->notify_socket = NULL; + m->notify_event_source = sd_event_source_unref(m->notify_event_source); + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) { + log_error("Failed to allocate notification socket: %m"); + return -errno; + } + + if (getpid() != 1 || detect_container(NULL) > 0) + snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%" PRIx64, random_u64()); + else + strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path)); + sa.un.sun_path[0] = 0; + + r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); + if (r < 0) { + log_error("bind() failed: %m"); + return -errno; + } + + r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + if (r < 0) { + log_error("SO_PASSCRED failed: %m"); + return -errno; + } + + sa.un.sun_path[0] = '@'; + m->notify_socket = strdup(sa.un.sun_path); + if (!m->notify_socket) + return log_oom(); + + m->notify_fd = fd; + fd = -1; + + log_debug("Using notification socket %s", m->notify_socket); + } + + if (!m->notify_event_source) { + r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m); + if (r < 0) { + log_error("Failed to allocate notify event source: %s", strerror(-r)); + return -errno; + } + + /* Process signals a bit earlier than SIGCHLD, so that we can + * still identify to which service an exit message belongs */ + r = sd_event_source_set_priority(m->notify_event_source, -7); + if (r < 0) { + log_error("Failed to set priority of notify event source: %s", strerror(-r)); + return r; + } + } + + return 0; +} + +static int manager_setup_kdbus(Manager *m) { +#ifdef ENABLE_KDBUS + _cleanup_free_ char *p = NULL; +#endif + +#ifdef ENABLE_KDBUS + assert(m); + + if (m->kdbus_fd >= 0) + return 0; + + m->kdbus_fd = bus_kernel_create_bus(m->running_as == SYSTEMD_SYSTEM ? "system" : "user", m->running_as == SYSTEMD_SYSTEM, &p); + if (m->kdbus_fd < 0) { + log_debug("Failed to set up kdbus: %s", strerror(-m->kdbus_fd)); + return m->kdbus_fd; + } + + log_debug("Successfully set up kdbus on %s", p); + + /* Create the namespace directory here, so that the contents + * of that directory is not visible to non-root users. This is + * necessary to ensure that users cannot get access to busses + * of virtualized users when no UID namespacing is used. */ + if (m->running_as == SYSTEMD_SYSTEM) + mkdir_p_label("/dev/kdbus/domain", 0700); +#endif + + return 0; +} + +static int manager_connect_bus(Manager *m, bool reexecuting) { + bool try_bus_connect; + + assert(m); + + try_bus_connect = + m->kdbus_fd >= 0 || + reexecuting || + (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")); + + /* Try to connect to the busses, if possible. */ + return bus_init(m, try_bus_connect); +} + +static unsigned manager_dispatch_cleanup_queue(Manager *m) { + Unit *u; + unsigned n = 0; + + assert(m); + + while ((u = m->cleanup_queue)) { + assert(u->in_cleanup_queue); + + unit_free(u); + n++; + } + + return n; +} + +enum { + GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */ + GC_OFFSET_UNSURE, /* No clue */ + GC_OFFSET_GOOD, /* We still need this unit */ + GC_OFFSET_BAD, /* We don't need this unit anymore */ + _GC_OFFSET_MAX +}; + +static void unit_gc_sweep(Unit *u, unsigned gc_marker) { + Iterator i; + Unit *other; + bool is_bad; + + assert(u); + + if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || + u->gc_marker == gc_marker + GC_OFFSET_BAD || + u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) + return; + + if (u->in_cleanup_queue) + goto bad; + + if (unit_check_gc(u)) + goto good; + + u->gc_marker = gc_marker + GC_OFFSET_IN_PATH; + + is_bad = true; + + SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) { + unit_gc_sweep(other, gc_marker); + + if (other->gc_marker == gc_marker + GC_OFFSET_GOOD) + goto good; + + if (other->gc_marker != gc_marker + GC_OFFSET_BAD) + is_bad = false; + } + + if (is_bad) + goto bad; + + /* We were unable to find anything out about this entry, so + * let's investigate it later */ + u->gc_marker = gc_marker + GC_OFFSET_UNSURE; + unit_add_to_gc_queue(u); + return; + +bad: + /* We definitely know that this one is not useful anymore, so + * let's mark it for deletion */ + u->gc_marker = gc_marker + GC_OFFSET_BAD; + unit_add_to_cleanup_queue(u); + return; + +good: + u->gc_marker = gc_marker + GC_OFFSET_GOOD; +} + +static unsigned manager_dispatch_gc_queue(Manager *m) { + Unit *u; + unsigned n = 0; + unsigned gc_marker; + + assert(m); + + /* log_debug("Running GC..."); */ + + m->gc_marker += _GC_OFFSET_MAX; + if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX) + m->gc_marker = 1; + + gc_marker = m->gc_marker; + + while ((u = m->gc_queue)) { + assert(u->in_gc_queue); + + unit_gc_sweep(u, gc_marker); + + LIST_REMOVE(gc_queue, m->gc_queue, u); + u->in_gc_queue = false; + + n++; + + if (u->gc_marker == gc_marker + GC_OFFSET_BAD || + u->gc_marker == gc_marker + GC_OFFSET_UNSURE) { + log_debug_unit(u->id, "Collecting %s", u->id); + u->gc_marker = gc_marker + GC_OFFSET_BAD; + unit_add_to_cleanup_queue(u); + } + } + + m->n_in_gc_queue = 0; + + return n; +} + +static void manager_clear_jobs_and_units(Manager *m) { + Unit *u; + + assert(m); + + while ((u = hashmap_first(m->units))) + unit_free(u); + + manager_dispatch_cleanup_queue(m); + + assert(!m->load_queue); + assert(!m->run_queue); + assert(!m->dbus_unit_queue); + assert(!m->dbus_job_queue); + assert(!m->cleanup_queue); + assert(!m->gc_queue); + + assert(hashmap_isempty(m->jobs)); + assert(hashmap_isempty(m->units)); + + m->n_on_console = 0; + m->n_running_jobs = 0; +} + +void manager_free(Manager *m) { + UnitType c; + int i; + + assert(m); + + manager_clear_jobs_and_units(m); + + for (c = 0; c < _UNIT_TYPE_MAX; c++) + if (unit_vtable[c]->shutdown) + unit_vtable[c]->shutdown(m); + + /* If we reexecute ourselves, we keep the root cgroup + * around */ + manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE); + + manager_undo_generators(m); + + bus_done(m); + + hashmap_free(m->units); + hashmap_free(m->jobs); + hashmap_free(m->watch_pids1); + hashmap_free(m->watch_pids2); + hashmap_free(m->watch_bus); +#ifdef CONFIG_TIZEN + set_free_free(m->dep_ignore_list); +#endif + + sd_event_source_unref(m->signal_event_source); + sd_event_source_unref(m->notify_event_source); + sd_event_source_unref(m->time_change_event_source); + sd_event_source_unref(m->jobs_in_progress_event_source); + sd_event_source_unref(m->idle_pipe_event_source); + sd_event_source_unref(m->run_queue_event_source); + + if (m->signal_fd >= 0) + close_nointr_nofail(m->signal_fd); + if (m->notify_fd >= 0) + close_nointr_nofail(m->notify_fd); + if (m->time_change_fd >= 0) + close_nointr_nofail(m->time_change_fd); + if (m->kdbus_fd >= 0) + close_nointr_nofail(m->kdbus_fd); + + manager_close_idle_pipe(m); + + udev_unref(m->udev); + sd_event_unref(m->event); + + free(m->notify_socket); + + lookup_paths_free(&m->lookup_paths); + strv_free(m->environment); + + hashmap_free(m->cgroup_unit); + set_free_free(m->unit_path_cache); + + free(m->switch_root); + free(m->switch_root_init); + + for (i = 0; i < RLIMIT_NLIMITS; i++) + free(m->rlimit[i]); + + assert(hashmap_isempty(m->units_requiring_mounts_for)); + hashmap_free(m->units_requiring_mounts_for); + + free(m); +} + +int manager_enumerate(Manager *m) { + int r = 0, q; + UnitType c; + + assert(m); + + /* Let's ask every type to load all units from disk/kernel + * that it might know */ + for (c = 0; c < _UNIT_TYPE_MAX; c++) + if (unit_vtable[c]->enumerate) { + q = unit_vtable[c]->enumerate(m); + if (q < 0) + r = q; + } + + manager_dispatch_load_queue(m); + return r; +} + +static int manager_coldplug(Manager *m) { + int r = 0, q; + Iterator i; + Unit *u; + char *k; + + assert(m); + + /* Then, let's set up their initial state. */ + HASHMAP_FOREACH_KEY(u, k, m->units, i) { + + /* ignore aliases */ + if (u->id != k) + continue; + + if ((q = unit_coldplug(u)) < 0) + r = q; + } + + return r; +} + +static void manager_build_unit_path_cache(Manager *m) { + char **i; + _cleanup_free_ DIR *d = NULL; + int r; + + assert(m); + + set_free_free(m->unit_path_cache); + + m->unit_path_cache = set_new(string_hash_func, string_compare_func); + if (!m->unit_path_cache) { + log_error("Failed to allocate unit path cache."); + return; + } + + /* This simply builds a list of files we know exist, so that + * we don't always have to go to disk */ + + STRV_FOREACH(i, m->lookup_paths.unit_path) { + struct dirent *de; + + d = opendir(*i); + if (!d) { + if (errno != ENOENT) + log_error("Failed to open directory %s: %m", *i); + continue; + } + + while ((de = readdir(d))) { + char *p; + + if (ignore_file(de->d_name)) + continue; + + p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); + if (!p) { + r = -ENOMEM; + goto fail; + } + + r = set_consume(m->unit_path_cache, p); + if (r < 0) + goto fail; + } + + closedir(d); + d = NULL; + } + + return; + +fail: + log_error("Failed to build unit path cache: %s", strerror(-r)); + + set_free_free(m->unit_path_cache); + m->unit_path_cache = NULL; +} + + +static int manager_distribute_fds(Manager *m, FDSet *fds) { + Unit *u; + Iterator i; + int r; + + assert(m); + + HASHMAP_FOREACH(u, m->units, i) { + + if (fdset_size(fds) <= 0) + break; + + if (UNIT_VTABLE(u)->distribute_fds) { + r = UNIT_VTABLE(u)->distribute_fds(u, fds); + if (r < 0) + return r; + } + } + + return 0; +} + +int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + int r, q; + + assert(m); + + dual_timestamp_get(&m->generators_start_timestamp); + manager_run_generators(m); + dual_timestamp_get(&m->generators_finish_timestamp); + + r = lookup_paths_init( + &m->lookup_paths, m->running_as, true, + m->generator_unit_path, + m->generator_unit_path_early, + m->generator_unit_path_late); + if (r < 0) + return r; + + manager_build_unit_path_cache(m); + + /* If we will deserialize make sure that during enumeration + * this is already known, so we increase the counter here + * already */ + if (serialization) + m->n_reloading ++; + + /* First, enumerate what we can from all config files */ + dual_timestamp_get(&m->units_load_start_timestamp); + r = manager_enumerate(m); + dual_timestamp_get(&m->units_load_finish_timestamp); + + /* Second, deserialize if there is something to deserialize */ + if (serialization) { + q = manager_deserialize(m, serialization, fds); + if (q < 0) + r = q; + } + + /* Any fds left? Find some unit which wants them. This is + * useful to allow container managers to pass some file + * descriptors to us pre-initialized. This enables + * socket-based activation of entire containers. */ + if (fdset_size(fds) > 0) { + q = manager_distribute_fds(m, fds); + if (q < 0) + r = q; + } + + /* We might have deserialized the notify fd, but if we didn't + * then let's create the bus now */ + manager_setup_notify(m); + + /* We might have deserialized the kdbus control fd, but if we + * didn't, then let's create the bus now. */ + manager_setup_kdbus(m); + manager_connect_bus(m, !!serialization); + + /* Third, fire things up! */ + q = manager_coldplug(m); + if (q < 0) + r = q; + + if (serialization) { + assert(m->n_reloading > 0); + m->n_reloading --; + + /* Let's wait for the UnitNew/JobNew messages being + * sent, before we notify that the reload is + * finished */ + m->send_reloading_done = true; + } + + return r; +} + +int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { + int r; + Transaction *tr; + + assert(m); + assert(type < _JOB_TYPE_MAX); + assert(unit); + assert(mode < _JOB_MODE_MAX); + + if (mode == JOB_ISOLATE && type != JOB_START) { + sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start."); + return -EINVAL; + } + + if (mode == JOB_ISOLATE && !unit->allow_isolate) { + sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated."); + return -EPERM; + } + + log_debug_unit(unit->id, + "Trying to enqueue job %s/%s/%s", unit->id, + job_type_to_string(type), job_mode_to_string(mode)); + + job_type_collapse(&type, unit); + + tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY); + if (!tr) + return -ENOMEM; + + r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false, + mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, + mode == JOB_IGNORE_DEPENDENCIES, e); + if (r < 0) + goto tr_abort; + + if (mode == JOB_ISOLATE) { + r = transaction_add_isolate_jobs(tr, m); + if (r < 0) + goto tr_abort; + } + + r = transaction_activate(tr, m, mode, e); + if (r < 0) + goto tr_abort; + + log_debug_unit(unit->id, + "Enqueued job %s/%s as %u", unit->id, + job_type_to_string(type), (unsigned) tr->anchor_job->id); + + if (_ret) + *_ret = tr->anchor_job; + + transaction_free(tr); + return 0; + +tr_abort: + transaction_abort(tr); + transaction_free(tr); + return r; +} + +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { + Unit *unit; + int r; + + assert(m); + assert(type < _JOB_TYPE_MAX); + assert(name); + assert(mode < _JOB_MODE_MAX); + + r = manager_load_unit(m, name, NULL, NULL, &unit); + if (r < 0) + return r; + + return manager_add_job(m, type, unit, mode, override, e, _ret); +} + +Job *manager_get_job(Manager *m, uint32_t id) { + assert(m); + + return hashmap_get(m->jobs, UINT32_TO_PTR(id)); +} + +Unit *manager_get_unit(Manager *m, const char *name) { + assert(m); + assert(name); + + return hashmap_get(m->units, name); +} + +unsigned manager_dispatch_load_queue(Manager *m) { + Unit *u; + unsigned n = 0; + + assert(m); + + /* Make sure we are not run recursively */ + if (m->dispatching_load_queue) + return 0; + + m->dispatching_load_queue = true; + + /* Dispatches the load queue. Takes a unit from the queue and + * tries to load its data until the queue is empty */ + + while ((u = m->load_queue)) { + assert(u->in_load_queue); + + unit_load(u); + n++; + } + + m->dispatching_load_queue = false; + return n; +} + +int manager_load_unit_prepare( + Manager *m, + const char *name, + const char *path, + sd_bus_error *e, + Unit **_ret) { + + Unit *ret; + UnitType t; + int r; + + assert(m); + assert(name || path); + + /* This will prepare the unit for loading, but not actually + * load anything from disk. */ + + if (path && !is_path(path)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path); + + if (!name) + name = basename(path); + + t = unit_name_to_type(name); + + if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + ret = manager_get_unit(m, name); + if (ret) { + *_ret = ret; + return 1; + } + + ret = unit_new(m, unit_vtable[t]->object_size); + if (!ret) + return -ENOMEM; + + if (path) { + ret->fragment_path = strdup(path); + if (!ret->fragment_path) { + unit_free(ret); + return -ENOMEM; + } + } + + r = unit_add_name(ret, name); + if (r < 0) { + unit_free(ret); + return r; + } + + unit_add_to_load_queue(ret); + unit_add_to_dbus_queue(ret); + unit_add_to_gc_queue(ret); + + if (_ret) + *_ret = ret; + + return 0; +} + +int manager_load_unit( + Manager *m, + const char *name, + const char *path, + sd_bus_error *e, + Unit **_ret) { + + int r; + + assert(m); + + /* This will load the service information files, but not actually + * start any services or anything. */ + + r = manager_load_unit_prepare(m, name, path, e, _ret); + if (r != 0) + return r; + + manager_dispatch_load_queue(m); + + if (_ret) + *_ret = unit_follow_merge(*_ret); + + return 0; +} + +void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) { + Iterator i; + Job *j; + + assert(s); + assert(f); + + HASHMAP_FOREACH(j, s->jobs, i) + job_dump(j, f, prefix); +} + +void manager_dump_units(Manager *s, FILE *f, const char *prefix) { + Iterator i; + Unit *u; + const char *t; + + assert(s); + assert(f); + + HASHMAP_FOREACH_KEY(u, t, s->units, i) + if (u->id == t) + unit_dump(u, f, prefix); +} + +void manager_clear_jobs(Manager *m) { + Job *j; + + assert(m); + + while ((j = hashmap_first(m->jobs))) + /* No need to recurse. We're cancelling all jobs. */ + job_finish_and_invalidate(j, JOB_CANCELED, false); +} + +static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { + Manager *m = userdata; + Job *j; + + assert(source); + assert(m); + + while ((j = m->run_queue)) { + assert(j->installed); + assert(j->in_run_queue); + + job_run_and_invalidate(j); + } + + if (m->n_running_jobs > 0) + manager_watch_jobs_in_progress(m); + + if (m->n_on_console > 0) + manager_watch_idle_pipe(m); + + return 1; +} + +static unsigned manager_dispatch_dbus_queue(Manager *m) { + Job *j; + Unit *u; + unsigned n = 0; + + assert(m); + + if (m->dispatching_dbus_queue) + return 0; + + m->dispatching_dbus_queue = true; + + while ((u = m->dbus_unit_queue)) { + assert(u->in_dbus_queue); + + bus_unit_send_change_signal(u); + n++; + } + + while ((j = m->dbus_job_queue)) { + assert(j->in_dbus_queue); + + bus_job_send_change_signal(j); + n++; + } + + m->dispatching_dbus_queue = false; + + if (m->send_reloading_done) { + m->send_reloading_done = false; + + bus_manager_send_reloading(m, false); + } + + if (m->queued_message) + bus_send_queued_message(m); + + return n; +} + +static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n) { + _cleanup_strv_free_ char **tags = NULL; + + assert(m); + assert(u); + assert(buf); + assert(n > 0); + + tags = strv_split(buf, "\n\r"); + if (!tags) { + log_oom(); + return; + } + + log_debug_unit(u->id, "Got notification message for unit %s", u->id); + + if (UNIT_VTABLE(u)->notify_message) + UNIT_VTABLE(u)->notify_message(u, pid, tags); +} + +static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + ssize_t n; + + assert(m); + assert(m->notify_fd == fd); + + if (revents != EPOLLIN) { + log_warning("Got unexpected poll event for notify fd."); + return 0; + } + + for (;;) { + char buf[4096]; + struct iovec iovec = { + .iov_base = buf, + .iov_len = sizeof(buf)-1, + }; + bool found = false; + + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control = {}; + + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct ucred *ucred; + Unit *u; + + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT); + if (n <= 0) { + if (n == 0) + return -EIO; + + if (errno == EAGAIN || errno == EINTR) + break; + + return -errno; + } + + if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || + control.cmsghdr.cmsg_level != SOL_SOCKET || + control.cmsghdr.cmsg_type != SCM_CREDENTIALS || + control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { + log_warning("Received notify message without credentials. Ignoring."); + continue; + } + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + + assert((size_t) n < sizeof(buf)); + buf[n] = 0; + + u = manager_get_unit_by_pid(m, ucred->pid); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } + + u = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } + + u = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } + + if (!found) + log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + } + + return 0; +} + +static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + assert(m); + assert(u); + assert(si); + + log_debug_unit(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); + + unit_unwatch_pid(u, si->si_pid); + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); +} + +static int manager_dispatch_sigchld(Manager *m) { + assert(m); + + for (;;) { + siginfo_t si = {}; + + /* First we call waitd() for a PID and do not reap the + * zombie. That way we can still access /proc/$PID for + * it while it is a zombie. */ + if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) { + + if (errno == ECHILD) + break; + + if (errno == EINTR) + continue; + + return -errno; + } + + if (si.si_pid <= 0) + break; + + if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) { + _cleanup_free_ char *name = NULL; + Unit *u; + + get_process_comm(si.si_pid, &name); + + log_debug("Child "PID_FMT" (%s) died (code=%s, status=%i/%s)", + si.si_pid, strna(name), + sigchld_code_to_string(si.si_code), + si.si_status, + strna(si.si_code == CLD_EXITED + ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL) + : signal_to_string(si.si_status))); + + /* And now figure out the unit this belongs + * to, it might be multiple... */ + u = manager_get_unit_by_pid(m, si.si_pid); + if (u) + invoke_sigchld_event(m, u, &si); + u = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid)); + if (u) + invoke_sigchld_event(m, u, &si); + u = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid)); + if (u) + invoke_sigchld_event(m, u, &si); + } + + /* And now, we actually reap the zombie. */ + if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) { + if (errno == EINTR) + continue; + + return -errno; + } + } + + return 0; +} + +static int manager_start_target(Manager *m, const char *name, JobMode mode) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + log_debug_unit(name, "Activating special unit %s", name); + + r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL); + if (r < 0) + log_error_unit(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r)); + + return r; +} + +static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + ssize_t n; + struct signalfd_siginfo sfsi; + bool sigchld = false; + + assert(m); + assert(m->signal_fd == fd); + + if (revents != EPOLLIN) { + log_warning("Got unexpected events from signal file descriptor."); + return 0; + } + + for (;;) { + n = read(m->signal_fd, &sfsi, sizeof(sfsi)); + if (n != sizeof(sfsi)) { + + if (n >= 0) + return -EIO; + + if (errno == EINTR || errno == EAGAIN) + break; + + return -errno; + } + + log_received_signal(sfsi.ssi_signo == SIGCHLD || + (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER) + ? LOG_DEBUG : LOG_INFO, + &sfsi); + + switch (sfsi.ssi_signo) { + + case SIGCHLD: + sigchld = true; + break; + + case SIGTERM: + if (m->running_as == SYSTEMD_SYSTEM) { + /* This is for compatibility with the + * original sysvinit */ + m->exit_code = MANAGER_REEXECUTE; + break; + } + + /* Fall through */ + + case SIGINT: + if (m->running_as == SYSTEMD_SYSTEM) { + manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); + break; + } + + /* Run the exit target if there is one, if not, just exit. */ + if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) { + m->exit_code = MANAGER_EXIT; + return 0; + } + + break; + + case SIGWINCH: + if (m->running_as == SYSTEMD_SYSTEM) + manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE); + + /* This is a nop on non-init */ + break; + + case SIGPWR: + if (m->running_as == SYSTEMD_SYSTEM) + manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE); + + /* This is a nop on non-init */ + break; + + case SIGUSR1: { + Unit *u; + + u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); + + if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) { + log_info("Trying to reconnect to bus..."); + bus_init(m, true); + } + + if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) { + log_info("Loading D-Bus service..."); + manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE); + } + + break; + } + + case SIGUSR2: { + _cleanup_free_ char *dump = NULL; + _cleanup_fclose_ FILE *f = NULL; + size_t size; + + f = open_memstream(&dump, &size); + if (!f) { + log_warning("Failed to allocate memory stream."); + break; + } + + manager_dump_units(m, f, "\t"); + manager_dump_jobs(m, f, "\t"); + + if (ferror(f)) { + log_warning("Failed to write status stream"); + break; + } + + log_dump(LOG_INFO, dump); + break; + } + + case SIGHUP: + m->exit_code = MANAGER_RELOAD; + break; + + default: { + + /* Starting SIGRTMIN+0 */ + static const char * const target_table[] = { + [0] = SPECIAL_DEFAULT_TARGET, + [1] = SPECIAL_RESCUE_TARGET, + [2] = SPECIAL_EMERGENCY_TARGET, + [3] = SPECIAL_HALT_TARGET, + [4] = SPECIAL_POWEROFF_TARGET, + [5] = SPECIAL_REBOOT_TARGET, + [6] = SPECIAL_KEXEC_TARGET + }; + + /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */ + static const ManagerExitCode code_table[] = { + [0] = MANAGER_HALT, + [1] = MANAGER_POWEROFF, + [2] = MANAGER_REBOOT, + [3] = MANAGER_KEXEC + }; + + if ((int) sfsi.ssi_signo >= SIGRTMIN+0 && + (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) { + int idx = (int) sfsi.ssi_signo - SIGRTMIN; + manager_start_target(m, target_table[idx], + (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE); + break; + } + + if ((int) sfsi.ssi_signo >= SIGRTMIN+13 && + (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) { + m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13]; + break; + } + + switch (sfsi.ssi_signo - SIGRTMIN) { + + case 20: + log_debug("Enabling showing of status."); + manager_set_show_status(m, SHOW_STATUS_YES); + break; + + case 21: + log_debug("Disabling showing of status."); + manager_set_show_status(m, SHOW_STATUS_NO); + break; + + case 22: + log_set_max_level(LOG_DEBUG); + log_notice("Setting log level to debug."); + break; + + case 23: + log_set_max_level(LOG_INFO); + log_notice("Setting log level to info."); + break; + + case 24: + if (m->running_as == SYSTEMD_USER) { + m->exit_code = MANAGER_EXIT; + return 0; + } + + /* This is a nop on init */ + break; + + case 26: + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_notice("Setting log target to journal-or-kmsg."); + break; + + case 27: + log_set_target(LOG_TARGET_CONSOLE); + log_notice("Setting log target to console."); + break; + + case 28: + log_set_target(LOG_TARGET_KMSG); + log_notice("Setting log target to kmsg."); + break; + + case 29: + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_notice("Setting log target to syslog-or-kmsg."); + break; + + default: + log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo)); + } + } + } + } + + if (sigchld) + manager_dispatch_sigchld(m); + + return 0; +} + +static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + Iterator i; + Unit *u; + + assert(m); + assert(m->time_change_fd == fd); + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), + "MESSAGE=Time has been changed", + NULL); + + /* Restart the watch */ + m->time_change_event_source = sd_event_source_unref(m->time_change_event_source); + + close_nointr_nofail(m->time_change_fd); + m->time_change_fd = -1; + + manager_setup_time_change(m); + + HASHMAP_FOREACH(u, m->units, i) + if (UNIT_VTABLE(u)->time_change) + UNIT_VTABLE(u)->time_change(u); + + return 0; +} + +static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + + assert(m); + assert(m->idle_pipe[2] == fd); + + m->no_console_output = m->n_on_console > 0; + + m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); + manager_close_idle_pipe(m); + + return 0; +} + +static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) { + Manager *m = userdata; + int r; + uint64_t next; + + assert(m); + assert(source); + + manager_print_jobs_in_progress(m); + + next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_PERIOD_USEC; + r = sd_event_source_set_time(source, next); + if (r < 0) + return r; + + return sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); +} + +int manager_loop(Manager *m) { + int r; + + RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000); + + assert(m); + m->exit_code = MANAGER_RUNNING; + + /* Release the path cache */ + set_free_free(m->unit_path_cache); + m->unit_path_cache = NULL; + + manager_check_finished(m); + + /* There might still be some zombies hanging around from + * before we were exec()'ed. Let's reap them. */ + r = manager_dispatch_sigchld(m); + if (r < 0) + return r; + + while (m->exit_code == MANAGER_RUNNING) { + usec_t wait_usec; + + if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) + watchdog_ping(); + + if (!ratelimit_test(&rl)) { + /* Yay, something is going seriously wrong, pause a little */ + log_warning("Looping too fast. Throttling execution a little."); + sleep(1); + continue; + } + + if (manager_dispatch_load_queue(m) > 0) + continue; + + if (manager_dispatch_gc_queue(m) > 0) + continue; + + if (manager_dispatch_cleanup_queue(m) > 0) + continue; + + if (manager_dispatch_cgroup_queue(m) > 0) + continue; + + if (manager_dispatch_dbus_queue(m) > 0) + continue; + + /* Sleep for half the watchdog time */ + if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) { + wait_usec = m->runtime_watchdog / 2; + if (wait_usec <= 0) + wait_usec = 1; + } else + wait_usec = (usec_t) -1; + + r = sd_event_run(m->event, wait_usec); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + return r; + } + } + + return m->exit_code; +} + +int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) { + _cleanup_free_ char *n = NULL; + Unit *u; + int r; + + assert(m); + assert(s); + assert(_u); + + r = unit_name_from_dbus_path(s, &n); + if (r < 0) + return r; + + r = manager_load_unit(m, n, NULL, e, &u); + if (r < 0) + return r; + + *_u = u; + + return 0; +} + +int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) { + const char *p; + unsigned id; + Job *j; + int r; + + assert(m); + assert(s); + assert(_j); + + p = startswith(s, "/org/freedesktop/systemd1/job/"); + if (!p) + return -EINVAL; + + r = safe_atou(p, &id); + if (r < 0) + return r; + + j = manager_get_job(m, id); + if (!j) + return -ENOENT; + + *_j = j; + + return 0; +} + +void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { + +#ifdef HAVE_AUDIT + _cleanup_free_ char *p = NULL; + int audit_fd; + + audit_fd = get_audit_fd(); + if (audit_fd < 0) + return; + + /* Don't generate audit events if the service was already + * started and we're just deserializing */ + if (m->n_reloading > 0) + return; + + if (m->running_as != SYSTEMD_SYSTEM) + return; + + if (u->type != UNIT_SERVICE) + return; + + p = unit_name_to_prefix_and_instance(u->id); + if (!p) { + log_error_unit(u->id, + "Failed to allocate unit name for audit message: %s", strerror(ENOMEM)); + return; + } + + if (audit_log_user_comm_message(audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) { + if (errno == EPERM) { + /* We aren't allowed to send audit messages? + * Then let's not retry again. */ + close_audit_fd(); + } else + log_warning("Failed to send audit message: %m"); + } +#endif + +} + +void manager_send_unit_plymouth(Manager *m, Unit *u) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "\0/org/freedesktop/plymouthd", + }; + + int n = 0; + _cleanup_free_ char *message = NULL; + _cleanup_close_ int fd = -1; + + /* Don't generate plymouth events if the service was already + * started and we're just deserializing */ + if (m->n_reloading > 0) + return; + + if (m->running_as != SYSTEMD_SYSTEM) + return; + + if (detect_container(NULL) > 0) + return; + + if (u->type != UNIT_SERVICE && + u->type != UNIT_MOUNT && + u->type != UNIT_SWAP) + return; + + /* We set SOCK_NONBLOCK here so that we rather drop the + * message then wait for plymouth */ + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) { + log_error("socket() failed: %m"); + return; + } + + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + + if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) + log_error("connect() failed: %m"); + return; + } + + if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) { + log_oom(); + return; + } + + errno = 0; + if (write(fd, message, n + 1) != n + 1) + if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) + log_error("Failed to write Plymouth message: %m"); +} + +void manager_dispatch_bus_name_owner_changed( + Manager *m, + const char *name, + const char* old_owner, + const char *new_owner) { + + Unit *u; + + assert(m); + assert(name); + + u = hashmap_get(m->watch_bus, name); + if (!u) + return; + + UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner); +} + +int manager_open_serialization(Manager *m, FILE **_f) { + const char *path; + int fd = -1; + FILE *f; + + assert(_f); + + path = m->running_as == SYSTEMD_SYSTEM ? "/run/systemd" : "/tmp"; + fd = open_tmpfile(path, O_RDWR|O_CLOEXEC); + if (fd < 0) + return -errno; + + log_debug("Serializing state to %s", path); + + f = fdopen(fd, "w+"); + if (!f) { + close_nointr_nofail(fd); + return -errno; + } + + *_f = f; + + return 0; +} + +int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { + Iterator i; + Unit *u; + const char *t; + char **e; + int r; + + assert(m); + assert(f); + assert(fds); + + m->n_reloading ++; + + fprintf(f, "current-job-id=%i\n", m->current_job_id); + fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); + fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs); + fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs); + + dual_timestamp_serialize(f, "firmware-timestamp", &m->firmware_timestamp); + dual_timestamp_serialize(f, "loader-timestamp", &m->loader_timestamp); + dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp); + dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp); + + if (!in_initrd()) { + dual_timestamp_serialize(f, "userspace-timestamp", &m->userspace_timestamp); + dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); + dual_timestamp_serialize(f, "security-start-timestamp", &m->security_start_timestamp); + dual_timestamp_serialize(f, "security-finish-timestamp", &m->security_finish_timestamp); + dual_timestamp_serialize(f, "generators-start-timestamp", &m->generators_start_timestamp); + dual_timestamp_serialize(f, "generators-finish-timestamp", &m->generators_finish_timestamp); + dual_timestamp_serialize(f, "units-load-start-timestamp", &m->units_load_start_timestamp); + dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp); + } + + if (!switching_root) { + STRV_FOREACH(e, m->environment) { + _cleanup_free_ char *ce; + + ce = cescape(*e); + if (!ce) + return -ENOMEM; + + fprintf(f, "env=%s\n", *e); + } + } + + if (m->notify_fd >= 0) { + int copy; + + copy = fdset_put_dup(fds, m->notify_fd); + if (copy < 0) + return copy; + + fprintf(f, "notify-fd=%i\n", copy); + fprintf(f, "notify-socket=%s\n", m->notify_socket); + } + + if (m->kdbus_fd >= 0) { + int copy; + + copy = fdset_put_dup(fds, m->kdbus_fd); + if (copy < 0) + return copy; + + fprintf(f, "kdbus-fd=%i\n", copy); + } + + bus_serialize(m, f); + + fputc('\n', f); + + HASHMAP_FOREACH_KEY(u, t, m->units, i) { + if (u->id != t) + continue; + + if (!unit_can_serialize(u)) + continue; + + /* Start marker */ + fputs(u->id, f); + fputc('\n', f); + + r = unit_serialize(u, f, fds, !switching_root); + if (r < 0) { + m->n_reloading --; + return r; + } + } + + assert(m->n_reloading > 0); + m->n_reloading --; + + if (ferror(f)) + return -EIO; + + r = bus_fdset_add_all(m, fds); + if (r < 0) + return r; + + return 0; +} + +int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + int r = 0; + + assert(m); + assert(f); + + log_debug("Deserializing state..."); + + m->n_reloading ++; + + for (;;) { + char line[LINE_MAX], *l; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + r = 0; + else + r = -errno; + + goto finish; + } + + char_array_0(line); + l = strstrip(line); + + if (l[0] == 0) + break; + + if (startswith(l, "current-job-id=")) { + uint32_t id; + + if (safe_atou32(l+15, &id) < 0) + log_debug("Failed to parse current job id value %s", l+15); + else + m->current_job_id = MAX(m->current_job_id, id); + + } else if (startswith(l, "n-installed-jobs=")) { + uint32_t n; + + if (safe_atou32(l+17, &n) < 0) + log_debug("Failed to parse installed jobs counter %s", l+17); + else + m->n_installed_jobs += n; + + } else if (startswith(l, "n-failed-jobs=")) { + uint32_t n; + + if (safe_atou32(l+14, &n) < 0) + log_debug("Failed to parse failed jobs counter %s", l+14); + else + m->n_failed_jobs += n; + + } else if (startswith(l, "taint-usr=")) { + int b; + + b = parse_boolean(l+10); + if (b < 0) + log_debug("Failed to parse taint /usr flag %s", l+10); + else + m->taint_usr = m->taint_usr || b; + + } else if (startswith(l, "firmware-timestamp=")) + dual_timestamp_deserialize(l+19, &m->firmware_timestamp); + else if (startswith(l, "loader-timestamp=")) + dual_timestamp_deserialize(l+17, &m->loader_timestamp); + else if (startswith(l, "kernel-timestamp=")) + dual_timestamp_deserialize(l+17, &m->kernel_timestamp); + else if (startswith(l, "initrd-timestamp=")) + dual_timestamp_deserialize(l+17, &m->initrd_timestamp); + else if (startswith(l, "userspace-timestamp=")) + dual_timestamp_deserialize(l+20, &m->userspace_timestamp); + else if (startswith(l, "finish-timestamp=")) + dual_timestamp_deserialize(l+17, &m->finish_timestamp); + else if (startswith(l, "security-start-timestamp=")) + dual_timestamp_deserialize(l+25, &m->security_start_timestamp); + else if (startswith(l, "security-finish-timestamp=")) + dual_timestamp_deserialize(l+26, &m->security_finish_timestamp); + else if (startswith(l, "generators-start-timestamp=")) + dual_timestamp_deserialize(l+27, &m->generators_start_timestamp); + else if (startswith(l, "generators-finish-timestamp=")) + dual_timestamp_deserialize(l+28, &m->generators_finish_timestamp); + else if (startswith(l, "units-load-start-timestamp=")) + dual_timestamp_deserialize(l+27, &m->units_load_start_timestamp); + else if (startswith(l, "units-load-finish-timestamp=")) + dual_timestamp_deserialize(l+28, &m->units_load_finish_timestamp); + else if (startswith(l, "env=")) { + _cleanup_free_ char *uce = NULL; + char **e; + + uce = cunescape(l+4); + if (!uce) { + r = -ENOMEM; + goto finish; + } + + e = strv_env_set(m->environment, uce); + if (!e) { + r = -ENOMEM; + goto finish; + } + + strv_free(m->environment); + m->environment = e; + + } else if (startswith(l, "notify-fd=")) { + int fd; + + if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug("Failed to parse notify fd: %s", l + 10); + else { + if (m->notify_fd >= 0) { + m->notify_event_source = sd_event_source_unref(m->notify_event_source); + close_nointr_nofail(m->notify_fd); + } + + m->notify_fd = fdset_remove(fds, fd); + } + + } else if (startswith(l, "notify-socket=")) { + char *n; + + n = strdup(l+14); + if (!n) { + r = -ENOMEM; + goto finish; + } + + free(m->notify_socket); + m->notify_socket = n; + + } else if (startswith(l, "kdbus-fd=")) { + int fd; + + if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug("Failed to parse kdbus fd: %s", l + 9); + else { + if (m->kdbus_fd >= 0) + close_nointr_nofail(m->kdbus_fd); + + m->kdbus_fd = fdset_remove(fds, fd); + } + + } else if (bus_deserialize_item(m, l) == 0) + log_debug("Unknown serialization item '%s'", l); + } + + for (;;) { + Unit *u; + char name[UNIT_NAME_MAX+2]; + + /* Start marker */ + if (!fgets(name, sizeof(name), f)) { + if (feof(f)) + r = 0; + else + r = -errno; + + goto finish; + } + + char_array_0(name); + + r = manager_load_unit(m, strstrip(name), NULL, NULL, &u); + if (r < 0) + goto finish; + + r = unit_deserialize(u, f, fds); + if (r < 0) + goto finish; + } + +finish: + if (ferror(f)) + r = -EIO; + + assert(m->n_reloading > 0); + m->n_reloading --; + + return r; +} + +int manager_reload(Manager *m) { + int r, q; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_fdset_free_ FDSet *fds = NULL; + + assert(m); + + r = manager_open_serialization(m, &f); + if (r < 0) + return r; + + m->n_reloading ++; + bus_manager_send_reloading(m, true); + + fds = fdset_new(); + if (!fds) { + m->n_reloading --; + return -ENOMEM; + } + + r = manager_serialize(m, f, fds, false); + if (r < 0) { + m->n_reloading --; + return r; + } + + if (fseeko(f, 0, SEEK_SET) < 0) { + m->n_reloading --; + return -errno; + } + + /* From here on there is no way back. */ + manager_clear_jobs_and_units(m); + manager_undo_generators(m); + lookup_paths_free(&m->lookup_paths); + + /* Find new unit paths */ + manager_run_generators(m); + + q = lookup_paths_init( + &m->lookup_paths, m->running_as, true, + m->generator_unit_path, + m->generator_unit_path_early, + m->generator_unit_path_late); + if (q < 0) + r = q; + + manager_build_unit_path_cache(m); + + /* First, enumerate what we can from all config files */ + q = manager_enumerate(m); + if (q < 0) + r = q; + + /* Second, deserialize our stored data */ + q = manager_deserialize(m, f, fds); + if (q < 0) + r = q; + + fclose(f); + f = NULL; + + /* Re-register notify_fd as event source */ + q = manager_setup_notify(m); + if (q < 0) + r = q; + + /* Third, fire things up! */ + q = manager_coldplug(m); + if (q < 0) + r = q; + + assert(m->n_reloading > 0); + m->n_reloading--; + + m->send_reloading_done = true; + + return r; +} + +static bool manager_is_booting_or_shutting_down(Manager *m) { + Unit *u; + + assert(m); + + /* Is the initial job still around? */ + if (manager_get_job(m, m->default_unit_job_id)) + return true; + + /* Is there a job for the shutdown target? */ + u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); + if (u) + return !!u->job; + + return false; +} + +bool manager_is_reloading_or_reexecuting(Manager *m) { + assert(m); + + return m->n_reloading != 0; +} + +void manager_reset_failed(Manager *m) { + Unit *u; + Iterator i; + + assert(m); + + HASHMAP_FOREACH(u, m->units, i) + unit_reset_failed(u); +} + +bool manager_unit_inactive_or_pending(Manager *m, const char *name) { + Unit *u; + + assert(m); + assert(name); + + /* Returns true if the unit is inactive or going down */ + u = manager_get_unit(m, name); + if (!u) + return true; + + return unit_inactive_or_pending(u); +} + +void manager_check_finished(Manager *m) { + char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX]; + usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec; + + assert(m); + + if (m->n_running_jobs == 0) + m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source); + + if (hashmap_size(m->jobs) > 0) { + if (m->jobs_in_progress_event_source) { + uint64_t next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC; + sd_event_source_set_time(m->jobs_in_progress_event_source, next); + } + return; + } + + manager_flip_auto_status(m, false); + + /* Notify Type=idle units that we are done now */ + m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source); + manager_close_idle_pipe(m); + + /* Turn off confirm spawn now */ + m->confirm_spawn = false; + + if (dual_timestamp_is_set(&m->finish_timestamp)) + return; + + dual_timestamp_get(&m->finish_timestamp); + + if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) { + + /* Note that m->kernel_usec.monotonic is always at 0, + * and m->firmware_usec.monotonic and + * m->loader_usec.monotonic should be considered + * negative values. */ + + firmware_usec = m->firmware_timestamp.monotonic - m->loader_timestamp.monotonic; + loader_usec = m->loader_timestamp.monotonic - m->kernel_timestamp.monotonic; + userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic; + total_usec = m->firmware_timestamp.monotonic + m->finish_timestamp.monotonic; + + if (dual_timestamp_is_set(&m->initrd_timestamp)) { + + kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic; + initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic; + + if (!log_on_console()) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), + "KERNEL_USEC="USEC_FMT, kernel_usec, + "INITRD_USEC="USEC_FMT, initrd_usec, + "USERSPACE_USEC="USEC_FMT, userspace_usec, + "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", + format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), + format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC), + format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), + NULL); + } else { + kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic; + initrd_usec = 0; + + if (!log_on_console()) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), + "KERNEL_USEC="USEC_FMT, kernel_usec, + "USERSPACE_USEC="USEC_FMT, userspace_usec, + "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.", + format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC), + format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC), + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), + NULL); + } + } else { + firmware_usec = loader_usec = initrd_usec = kernel_usec = 0; + total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic; + + if (!log_on_console()) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED), + "USERSPACE_USEC="USEC_FMT, userspace_usec, + "MESSAGE=Startup finished in %s.", + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC), + NULL); + } + + bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec); + + sd_notifyf(false, + "READY=1\nSTATUS=Startup finished in %s.", + format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)); +} + +static int create_generator_dir(Manager *m, char **generator, const char *name) { + char *p; + int r; + + assert(m); + assert(generator); + assert(name); + + if (*generator) + return 0; + + if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) { + /* systemd --system, not running --test */ + + p = strappend("/run/systemd/", name); + if (!p) + return log_oom(); + + r = mkdir_p_label(p, 0755); + if (r < 0) { + log_error("Failed to create generator directory %s: %s", + p, strerror(-r)); + free(p); + return r; + } + } else if (m->running_as == SYSTEMD_USER) { + const char *s = NULL; + + s = getenv("XDG_RUNTIME_DIR"); + if (!s) + return -EINVAL; + p = strjoin(s, "/systemd/", name, NULL); + if (!p) + return log_oom(); + + r = mkdir_p_label(p, 0755); + if (r < 0) { + log_error("Failed to create generator directory %s: %s", + p, strerror(-r)); + free(p); + return r; + } + } else { + /* systemd --system --test */ + + p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL); + if (!p) + return log_oom(); + + if (!mkdtemp(p)) { + log_error("Failed to create generator directory %s: %m", + p); + free(p); + return -errno; + } + } + + *generator = p; + return 0; +} + +static void trim_generator_dir(Manager *m, char **generator) { + assert(m); + assert(generator); + + if (!*generator) + return; + + if (rmdir(*generator) >= 0) { + free(*generator); + *generator = NULL; + } + + return; +} + +void manager_run_generators(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + const char *generator_path; + const char *argv[5]; + int r; + + assert(m); + + generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH; + d = opendir(generator_path); + if (!d) { + if (errno == ENOENT) + return; + + log_error("Failed to enumerate generator directory %s: %m", + generator_path); + return; + } + + r = create_generator_dir(m, &m->generator_unit_path, "generator"); + if (r < 0) + goto finish; + + r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early"); + if (r < 0) + goto finish; + + r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late"); + if (r < 0) + goto finish; + + argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */ + argv[1] = m->generator_unit_path; + argv[2] = m->generator_unit_path_early; + argv[3] = m->generator_unit_path_late; + argv[4] = NULL; + + RUN_WITH_UMASK(0022) + execute_directory(generator_path, d, (char**) argv); + +finish: + trim_generator_dir(m, &m->generator_unit_path); + trim_generator_dir(m, &m->generator_unit_path_early); + trim_generator_dir(m, &m->generator_unit_path_late); +} + +static void remove_generator_dir(Manager *m, char **generator) { + assert(m); + assert(generator); + + if (!*generator) + return; + + strv_remove(m->lookup_paths.unit_path, *generator); + rm_rf(*generator, false, true, false); + + free(*generator); + *generator = NULL; +} + +void manager_undo_generators(Manager *m) { + assert(m); + + remove_generator_dir(m, &m->generator_unit_path); + remove_generator_dir(m, &m->generator_unit_path_early); + remove_generator_dir(m, &m->generator_unit_path_late); +} + +int manager_environment_add(Manager *m, char **minus, char **plus) { + char **a = NULL, **b = NULL, **l; + assert(m); + + l = m->environment; + + if (!strv_isempty(minus)) { + a = strv_env_delete(l, 1, minus); + if (!a) + return -ENOMEM; + + l = a; + } + + if (!strv_isempty(plus)) { + b = strv_env_merge(2, l, plus); + if (!b) + return -ENOMEM; + + l = b; + } + + if (m->environment != l) + strv_free(m->environment); + if (a != l) + strv_free(a); + if (b != l) + strv_free(b); + + m->environment = l; + manager_clean_environment(m); + strv_sort(m->environment); + + return 0; +} + +#ifdef CONFIG_TIZEN +int manager_set_default_extra_dependencies(Manager *m, char **dependencies) { + _cleanup_free_ char *buf = NULL; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *de; + char *state, *word, *name, **d = NULL; + size_t len; + int r = 0; + + assert(m); + + if (strv_extend_strv(&m->dependencies, dependencies) < 0) { + strv_free(m->dependencies); + return log_oom(); + } + + STRV_FOREACH(d, m->dependencies) { + name = strdup(*d); + r = set_put(m->dep_ignore_list, name); + if (r < 0) + return r; + } + + r = read_full_file(PKGSYSCONFDIR "/default-extra-dependencies/ignore-units", + &buf, NULL); + if (r < 0) + goto dir; + + FOREACH_WORD_SEPARATOR(word, len, buf, NEWLINE, state) { + _cleanup_free_ char *copy; + + copy = strndup(word, len); + if (!copy) + return -ENOMEM; + + if (len <= 0) + continue; + + name = strdup(copy); + r = set_put(m->dep_ignore_list, name); + if (r < 0) + return r; + } + +dir: + dir = opendir(PKGSYSCONFDIR "/default-extra-dependencies/ignore-units.d"); + if (!dir) + return 0; + + FOREACH_DIRENT(de, dir, return -errno) { + _cleanup_free_ char *src = NULL, *dst = NULL; + + if (de->d_type != DT_LNK) + continue; + + src = strappend(PKGSYSCONFDIR "/default-extra-dependencies/ignore-units.d/", + de->d_name); + if (!src) { + r = -ENOMEM; + return r; + } + + r = readlink_and_canonicalize(src, &dst); + if (r < 0) + continue; + + if (access(dst, F_OK) < 0) { + log_debug("Failed to add extra dependency for unit %s, ignoring: %m", dst); + continue; + } + + name = strdup(basename(dst)); + r = set_put(m->dep_ignore_list, name); + if (r < 0) + return r; + } + + return 0; +} +#endif + +int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { + int i; + + assert(m); + + for (i = 0; i < RLIMIT_NLIMITS; i++) { + if (!default_rlimit[i]) + continue; + + m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1); + if (!m->rlimit[i]) + return -ENOMEM; + } + + return 0; +} + +void manager_recheck_journal(Manager *m) { + Unit *u; + + assert(m); + + if (m->running_as != SYSTEMD_SYSTEM) + return; + + u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET); + if (u && SOCKET(u)->state != SOCKET_RUNNING) { + log_close_journal(); + return; + } + + u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE); + if (u && SERVICE(u)->state != SERVICE_RUNNING) { + log_close_journal(); + return; + } + + /* Hmm, OK, so the socket is fully up and the service is up + * too, then let's make use of the thing. */ + log_open(); +} + +void manager_set_show_status(Manager *m, ShowStatus mode) { + assert(m); + assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY)); + + if (m->running_as != SYSTEMD_SYSTEM) + return; + + m->show_status = mode; + + if (mode > 0) + touch("/run/systemd/show-status"); + else + unlink("/run/systemd/show-status"); +} + +static bool manager_get_show_status(Manager *m) { + assert(m); + + if (m->running_as != SYSTEMD_SYSTEM) + return false; + + if (m->no_console_output) + return false; + + if (m->show_status > 0) + return true; + + /* If Plymouth is running make sure we show the status, so + * that there's something nice to see when people press Esc */ + + return plymouth_running(); +} + +void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) { + va_list ap; + + if (!manager_get_show_status(m)) + return; + + /* XXX We should totally drop the check for ephemeral here + * and thus effectively make 'Type=idle' pointless. */ + if (ephemeral && m->n_on_console > 0) + return; + + if (!manager_is_booting_or_shutting_down(m)) + return; + + va_start(ap, format); + status_vprintf(status, true, ephemeral, format, ap); + va_end(ap); +} + +int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) { + _cleanup_free_ char *p = NULL; + Unit *found; + + assert(m); + assert(path); + assert(suffix); + assert(_found); + + p = unit_name_from_path(path, suffix); + if (!p) + return -ENOMEM; + + found = manager_get_unit(m, p); + if (!found) { + *_found = NULL; + return 0; + } + + *_found = found; + return 1; +} + +Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { + char p[strlen(path)+1]; + + assert(m); + assert(path); + + strcpy(p, path); + path_kill_slashes(p); + + return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p); +} diff --git a/src/core/manager.h b/src/core/manager.h new file mode 100644 index 0000000..15b43d6 --- /dev/null +++ b/src/core/manager.h @@ -0,0 +1,318 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-bus.h" +#include "sd-event.h" +#include "fdset.h" +#include "cgroup-util.h" + +/* Enforce upper limit how many names we allow */ +#define MANAGER_MAX_NAMES 131072 /* 128K */ + +typedef struct Manager Manager; + +typedef enum ManagerExitCode { + MANAGER_RUNNING, + MANAGER_EXIT, + MANAGER_RELOAD, + MANAGER_REEXECUTE, + MANAGER_REBOOT, + MANAGER_POWEROFF, + MANAGER_HALT, + MANAGER_KEXEC, + MANAGER_SWITCH_ROOT, + _MANAGER_EXIT_CODE_MAX, + _MANAGER_EXIT_CODE_INVALID = -1 +} ManagerExitCode; + +#include "unit.h" +#include "job.h" +#include "hashmap.h" +#include "list.h" +#include "set.h" +#include "path-lookup.h" +#include "execute.h" +#include "unit-name.h" +#include "exit-status.h" + +struct Manager { + /* Note that the set of units we know of is allowed to be + * inconsistent. However the subset of it that is loaded may + * not, and the list of jobs may neither. */ + + /* Active jobs and units */ + Hashmap *units; /* name string => Unit object n:1 */ + Hashmap *jobs; /* job id => Job object 1:1 */ + + /* To make it easy to iterate through the units of a specific + * type we maintain a per type linked list */ + LIST_HEAD(Unit, units_by_type[_UNIT_TYPE_MAX]); + + /* Units that need to be loaded */ + LIST_HEAD(Unit, load_queue); /* this is actually more a stack than a queue, but uh. */ + + /* Jobs that need to be run */ + LIST_HEAD(Job, run_queue); /* more a stack than a queue, too */ + + /* Units and jobs that have not yet been announced via + * D-Bus. When something about a job changes it is added here + * if it is not in there yet. This allows easy coalescing of + * D-Bus change signals. */ + LIST_HEAD(Unit, dbus_unit_queue); + LIST_HEAD(Job, dbus_job_queue); + + /* Units to remove */ + LIST_HEAD(Unit, cleanup_queue); + + /* Units to check when doing GC */ + LIST_HEAD(Unit, gc_queue); + + /* Units that should be realized */ + LIST_HEAD(Unit, cgroup_queue); + + sd_event *event; + + /* We use two hash tables here, since the same PID might be + * watched by two different units: once the unit that forked + * it off, and possibly a different unit to which it was + * joined as cgroup member. Since we know that it is either + * one or two units for each PID we just use to hashmaps + * here. */ + Hashmap *watch_pids1; /* pid => Unit object n:1 */ + Hashmap *watch_pids2; /* pid => Unit object n:1 */ + + sd_event_source *run_queue_event_source; + + char *notify_socket; + int notify_fd; + sd_event_source *notify_event_source; + + int signal_fd; + sd_event_source *signal_event_source; + + int time_change_fd; + sd_event_source *time_change_event_source; + + sd_event_source *jobs_in_progress_event_source; + + unsigned n_snapshots; + + LookupPaths lookup_paths; + Set *unit_path_cache; + + char **environment; +#ifdef CONFIG_TIZEN + char **dependencies; + Set *dep_ignore_list; +#endif + + usec_t runtime_watchdog; + usec_t shutdown_watchdog; + + dual_timestamp firmware_timestamp; + dual_timestamp loader_timestamp; + dual_timestamp kernel_timestamp; + dual_timestamp initrd_timestamp; + dual_timestamp userspace_timestamp; + dual_timestamp finish_timestamp; + dual_timestamp security_start_timestamp; + dual_timestamp security_finish_timestamp; + dual_timestamp generators_start_timestamp; + dual_timestamp generators_finish_timestamp; + dual_timestamp units_load_start_timestamp; + dual_timestamp units_load_finish_timestamp; + + char *generator_unit_path; + char *generator_unit_path_early; + char *generator_unit_path_late; + + struct udev* udev; + + /* Data specific to the device subsystem */ + struct udev_monitor* udev_monitor; + sd_event_source *udev_event_source; + Hashmap *devices_by_sysfs; + + /* Data specific to the mount subsystem */ + FILE *proc_self_mountinfo; + sd_event_source *mount_event_source; + + /* Data specific to the swap filesystem */ + FILE *proc_swaps; + sd_event_source *swap_event_source; + Hashmap *swaps_by_devnode; + + /* Data specific to the D-Bus subsystem */ + sd_bus *api_bus, *system_bus; + Set *private_buses; + int private_listen_fd; + sd_event_source *private_listen_event_source; + Set *subscribed; + + sd_bus_message *queued_message; /* This is used during reloading: + * before the reload we queue the + * reply message here, and + * afterwards we send it */ + sd_bus *queued_message_bus; /* The connection to send the queued message on */ + + Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */ + + bool send_reloading_done; + + uint32_t current_job_id; + uint32_t default_unit_job_id; + + /* Data specific to the Automount subsystem */ + int dev_autofs_fd; + + /* Data specific to the cgroup subsystem */ + Hashmap *cgroup_unit; + CGroupControllerMask cgroup_supported; + char *cgroup_root; + + int gc_marker; + unsigned n_in_gc_queue; + + /* Make sure the user cannot accidentally unmount our cgroup + * file system */ + int pin_cgroupfs_fd; + + /* Flags */ + SystemdRunningAs running_as; + ManagerExitCode exit_code:5; + + bool dispatching_load_queue:1; + bool dispatching_dbus_queue:1; + + bool taint_usr:1; + + ShowStatus show_status; + bool confirm_spawn; + bool no_console_output; + + ExecOutput default_std_output, default_std_error; + + usec_t default_restart_usec, default_timeout_start_usec, + default_timeout_stop_usec; + + usec_t default_start_limit_interval; + unsigned default_start_limit_burst; + + struct rlimit *rlimit[RLIMIT_NLIMITS]; + + /* non-zero if we are reloading or reexecuting, */ + int n_reloading; + + unsigned n_installed_jobs; + unsigned n_failed_jobs; + + /* Jobs in progress watching */ + unsigned n_running_jobs; + unsigned n_on_console; + unsigned jobs_in_progress_iteration; + + /* Type=idle pipes */ + int idle_pipe[4]; + sd_event_source *idle_pipe_event_source; + + char *switch_root; + char *switch_root_init; + + /* This maps all possible path prefixes to the units needing + * them. It's a hashmap with a path string as key and a Set as + * value where Unit objects are contained. */ + Hashmap *units_requiring_mounts_for; + + /* Reference to the kdbus bus control fd */ + int kdbus_fd; +}; + +int manager_new(SystemdRunningAs running_as, Manager **m); +void manager_free(Manager *m); + +int manager_enumerate(Manager *m); +int manager_startup(Manager *m, FILE *serialization, FDSet *fds); + +Job *manager_get_job(Manager *m, uint32_t id); +Unit *manager_get_unit(Manager *m, const char *name); + +int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found); + +int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); + +int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); +int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, 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, bool force, sd_bus_error *e, Job **_ret); +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret); + +void manager_dump_units(Manager *s, FILE *f, const char *prefix); +void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); + +void manager_clear_jobs(Manager *m); + +unsigned manager_dispatch_load_queue(Manager *m); + +int manager_environment_add(Manager *m, char **minus, char **plus); +#ifdef CONFIG_TIZEN +int manager_set_default_extra_dependencies(Manager *m, char **dependencies); +#endif +int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit); + +int manager_loop(Manager *m); + +void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner); + +int manager_open_serialization(Manager *m, FILE **_f); + +int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root); +int manager_deserialize(Manager *m, FILE *f, FDSet *fds); + +int manager_reload(Manager *m); + +bool manager_is_reloading_or_reexecuting(Manager *m) _pure_; + +void manager_reset_failed(Manager *m); + +void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success); +void manager_send_unit_plymouth(Manager *m, Unit *u); + +bool manager_unit_inactive_or_pending(Manager *m, const char *name); + +void manager_check_finished(Manager *m); + +void manager_run_generators(Manager *m); +void manager_undo_generators(Manager *m); + +void manager_recheck_journal(Manager *m); + +void manager_set_show_status(Manager *m, ShowStatus mode); +void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_(4,5); +void manager_flip_auto_status(Manager *m, bool enable); + +Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c new file mode 100644 index 0000000..6265730 --- /dev/null +++ b/src/core/mount-setup.c @@ -0,0 +1,416 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mount-setup.h" +#include "dev-setup.h" +#include "log.h" +#include "macro.h" +#include "util.h" +#include "label.h" +#include "set.h" +#include "strv.h" +#include "mkdir.h" +#include "path-util.h" +#include "missing.h" +#include "virt.h" +#include "efivars.h" +#include "smack-util.h" +#include "def.h" + +typedef enum MountMode { + MNT_NONE = 0, + MNT_FATAL = 1 << 0, + MNT_IN_CONTAINER = 1 << 1, +} MountMode; + +typedef struct MountPoint { + const char *what; + const char *where; + const char *type; + const char *options; + unsigned long flags; + bool (*condition_fn)(void); + MountMode mode; +} MountPoint; + +/* The first three entries we might need before SELinux is up. The + * fourth (securityfs) is needed by IMA to load a custom policy. The + * other ones we can delay until SELinux and IMA are loaded. */ +#define N_EARLY_MOUNT 5 + +static const MountPoint mount_table[] = { + { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_NONE }, +#ifdef HAVE_SMACK + { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, + use_smack, MNT_FATAL }, + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + use_smack, MNT_FATAL }, +#endif + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, + NULL, MNT_IN_CONTAINER }, +#ifdef HAVE_SMACK + { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + use_smack, MNT_FATAL }, +#endif + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, + NULL, MNT_IN_CONTAINER }, +#ifdef HAVE_XATTR + { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_IN_CONTAINER }, +#endif + { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_IN_CONTAINER }, + { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + NULL, MNT_NONE }, +#ifdef ENABLE_EFI + { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + is_efi_boot, MNT_NONE }, +#endif +}; + +/* These are API file systems that might be mounted by other software, + * we just list them here so that we know that we should ignore them */ + +static const char ignore_paths[] = + /* SELinux file systems */ + "/sys/fs/selinux\0" + "/selinux\0" + /* Legacy cgroup mount points */ + "/dev/cgroup\0" + "/cgroup\0" + /* Legacy kernel file system */ + "/proc/bus/usb\0" + /* Container bind mounts */ + "/proc/sys\0" + "/dev/console\0" + "/proc/kmsg\0"; + +bool mount_point_is_api(const char *path) { + unsigned i; + + /* Checks if this mount point is considered "API", and hence + * should be ignored */ + + for (i = 0; i < ELEMENTSOF(mount_table); i ++) + if (path_equal(path, mount_table[i].where)) + return true; + + return path_startswith(path, "/sys/fs/cgroup/"); +} + +bool mount_point_ignore(const char *path) { + const char *i; + + NULSTR_FOREACH(i, ignore_paths) + if (path_equal(path, i)) + return true; + + return false; +} + +static int mount_one(const MountPoint *p, bool relabel) { + int r; + + assert(p); + + if (p->condition_fn && !p->condition_fn()) + return 0; + + /* Relabel first, just in case */ + if (relabel) + label_fix(p->where, true, true); + + r = path_is_mount_point(p->where, true); + if (r < 0) + return r; + + if (r > 0) + return 0; + + /* Skip securityfs in a container */ + if (!(p->mode & MNT_IN_CONTAINER) && detect_container(NULL) > 0) + return 0; + + /* The access mode here doesn't really matter too much, since + * the mounted file system will take precedence anyway. */ + if (relabel) + mkdir_p_label(p->where, 0755); + else + mkdir_p(p->where, 0755); + + log_debug("Mounting %s to %s of type %s with options %s.", + p->what, + p->where, + p->type, + strna(p->options)); + + if (mount(p->what, + p->where, + p->type, + p->flags, + p->options) < 0) { + log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s: %m", p->where); + return (p->mode & MNT_FATAL) ? -errno : 0; + } + + /* Relabel again, since we now mounted something fresh here */ + if (relabel) + label_fix(p->where, false, false); + + return 1; +} + +int mount_setup_early(void) { + unsigned i; + int r = 0; + + assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table)); + + /* Do a minimal mount of /proc and friends to enable the most + * basic stuff, such as SELinux */ + for (i = 0; i < N_EARLY_MOUNT; i ++) { + int j; + + j = mount_one(mount_table + i, false); + if (r == 0) + r = j; + } + + return r; +} + +int mount_cgroup_controllers(char ***join_controllers) { + int r; + char buf[LINE_MAX]; + _cleanup_set_free_free_ Set *controllers = NULL; + _cleanup_fclose_ FILE *f; + + /* Mount all available cgroup controllers that are built into the kernel. */ + + f = fopen("/proc/cgroups", "re"); + if (!f) { + log_error("Failed to enumerate cgroup controllers: %m"); + return 0; + } + + controllers = set_new(string_hash_func, string_compare_func); + if (!controllers) + return log_oom(); + + /* Ignore the header line */ + (void) fgets(buf, sizeof(buf), f); + + for (;;) { + char *controller; + int enabled = 0; + + if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) { + + if (feof(f)) + break; + + log_error("Failed to parse /proc/cgroups."); + return -EIO; + } + + if (!enabled) { + free(controller); + continue; + } + + r = set_consume(controllers, controller); + if (r < 0) { + log_error("Failed to add controller to set."); + return r; + } + } + + for (;;) { + MountPoint p = { + .what = "cgroup", + .type = "cgroup", + .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV, + .mode = MNT_IN_CONTAINER, + }; + char ***k = NULL; + _cleanup_free_ char *options = NULL, *controller; + + controller = set_steal_first(controllers); + if (!controller) + break; + + if (join_controllers) + for (k = join_controllers; *k; k++) + if (strv_find(*k, controller)) + break; + + if (k && *k) { + char **i, **j; + + for (i = *k, j = *k; *i; i++) { + + if (!streq(*i, controller)) { + char _cleanup_free_ *t; + + t = set_remove(controllers, *i); + if (!t) { + free(*i); + continue; + } + } + + *(j++) = *i; + } + + *j = NULL; + + options = strv_join(*k, ","); + if (!options) + return log_oom(); + } else { + options = controller; + controller = NULL; + } + + p.where = strappenda("/sys/fs/cgroup/", options); + p.options = options; + + r = mount_one(&p, true); + if (r < 0) + return r; + + if (r > 0 && k && *k) { + char **i; + + for (i = *k; *i; i++) { + char *t = strappenda("/sys/fs/cgroup/", *i); + + r = symlink(options, t); + if (r < 0 && errno != EEXIST) { + log_error("Failed to create symlink %s: %m", t); + return -errno; + } + } + } + } + + return 0; +} + +static int nftw_cb( + const char *fpath, + const struct stat *sb, + int tflag, + struct FTW *ftwbuf) { + + /* No need to label /dev twice in a row... */ + if (_unlikely_(ftwbuf->level == 0)) + return FTW_CONTINUE; + + label_fix(fpath, false, false); + + /* /run/initramfs is static data and big, no need to + * dynamically relabel its contents at boot... */ + if (_unlikely_(ftwbuf->level == 1 && + tflag == FTW_D && + streq(fpath, "/run/initramfs"))) + return FTW_SKIP_SUBTREE; + + return FTW_CONTINUE; +}; + +int mount_setup(bool loaded_policy) { + int r; + unsigned i; + + for (i = 0; i < ELEMENTSOF(mount_table); i ++) { + r = mount_one(mount_table + i, true); + + if (r < 0) + return r; + } + + /* Nodes in devtmpfs and /run need to be manually updated for + * the appropriate labels, after mounting. The other virtual + * API file systems like /sys and /proc do not need that, they + * use the same label for all their files. */ + if (loaded_policy) { + usec_t before_relabel, after_relabel; + char timespan[FORMAT_TIMESPAN_MAX]; + + before_relabel = now(CLOCK_MONOTONIC); + + nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); + nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); + + after_relabel = now(CLOCK_MONOTONIC); + + log_info("Relabelled /dev and /run in %s.", + format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0)); + } + + /* Create a few default symlinks, which are normally created + * by udevd, but some scripts might need them before we start + * udevd. */ + dev_setup(NULL); + + /* Mark the root directory as shared in regards to mount + * propagation. The kernel defaults to "private", but we think + * it makes more sense to have a default of "shared" so that + * nspawn and the container tools work out of the box. If + * specific setups need other settings they can reset the + * propagation mode to private if needed. */ + if (detect_container(NULL) <= 0) + if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0) + log_warning("Failed to set up the root directory for shared mount propagation: %m"); + + /* Create a few directories we always want around, Note that + * sd_booted() checks for /run/systemd/system, so this mkdir + * really needs to stay for good, otherwise software that + * copied sd-daemon.c into their sources will misdetect + * systemd. */ + mkdir_label("/run/systemd", 0755); + mkdir_label("/run/systemd/system", 0755); + mkdir_label("/run/systemd/inaccessible", 0000); + + return 0; +} diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h new file mode 100644 index 0000000..4b521ad --- /dev/null +++ b/src/core/mount-setup.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int mount_setup_early(void); + +int mount_setup(bool loaded_policy); + +int mount_cgroup_controllers(char ***join_controllers); + +bool mount_point_is_api(const char *path); +bool mount_point_ignore(const char *path); diff --git a/src/core/mount.c b/src/core/mount.c new file mode 100644 index 0000000..a0cea1e --- /dev/null +++ b/src/core/mount.c @@ -0,0 +1,1841 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "manager.h" +#include "unit.h" +#include "mount.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "log.h" +#include "sd-messages.h" +#include "strv.h" +#include "mkdir.h" +#include "path-util.h" +#include "mount-setup.h" +#include "unit-name.h" +#include "dbus-mount.h" +#include "special.h" +#include "bus-errors.h" +#include "exit-status.h" +#include "def.h" + +static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = UNIT_INACTIVE, + [MOUNT_MOUNTING] = UNIT_ACTIVATING, + [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE, + [MOUNT_MOUNTED] = UNIT_ACTIVE, + [MOUNT_REMOUNTING] = UNIT_RELOADING, + [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, + [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING, + [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING, + [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING, + [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING, + [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING, + [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING, + [MOUNT_FAILED] = UNIT_FAILED +}; + +static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +static char* mount_test_option(const char *haystack, const char *needle) { + struct mntent me = { .mnt_opts = (char*) haystack }; + + assert(needle); + + /* Like glibc's hasmntopt(), but works on a string, not a + * struct mntent */ + + if (!haystack) + return NULL; + + return hasmntopt(&me, needle); +} + +static bool mount_is_network(MountParameters *p) { + assert(p); + + if (mount_test_option(p->options, "_netdev")) + return true; + + if (p->fstype && fstype_is_network(p->fstype)) + return true; + + return false; +} + +static bool mount_is_bind(MountParameters *p) { + assert(p); + + if (mount_test_option(p->options, "bind")) + return true; + + if (p->fstype && streq(p->fstype, "bind")) + return true; + + if (mount_test_option(p->options, "rbind")) + return true; + + if (p->fstype && streq(p->fstype, "rbind")) + return true; + + return false; +} + +static bool mount_is_auto(MountParameters *p) { + assert(p); + + return !mount_test_option(p->options, "noauto"); +} + +static bool needs_quota(MountParameters *p) { + assert(p); + + if (mount_is_network(p)) + return false; + + if (mount_is_bind(p)) + return false; + + return mount_test_option(p->options, "usrquota") || + mount_test_option(p->options, "grpquota") || + mount_test_option(p->options, "quota") || + mount_test_option(p->options, "usrjquota") || + mount_test_option(p->options, "grpjquota"); +} + +static void mount_init(Unit *u) { + Mount *m = MOUNT(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + m->timeout_usec = u->manager->default_timeout_start_usec; + m->directory_mode = 0755; + + exec_context_init(&m->exec_context); + kill_context_init(&m->kill_context); + cgroup_context_init(&m->cgroup_context); + + if (unit_has_name(u, "-.mount")) { + /* Don't allow start/stop for root directory */ + u->refuse_manual_start = true; + u->refuse_manual_stop = true; + } else { + /* The stdio/kmsg bridge socket is on /, in order to avoid a + * dep loop, don't use kmsg logging for -.mount */ + m->exec_context.std_output = u->manager->default_std_output; + m->exec_context.std_error = u->manager->default_std_error; + } + + /* We need to make sure that /bin/mount is always called in + * the same process group as us, so that the autofs kernel + * side doesn't send us another mount request while we are + * already trying to comply its last one. */ + m->exec_context.same_pgrp = true; + + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + + u->ignore_on_isolate = true; +} + +static int mount_arm_timer(Mount *m) { + int r; + + assert(m); + + if (m->timeout_usec <= 0) { + m->timer_event_source = sd_event_source_unref(m->timer_event_source); + return 0; + } + + if (m->timer_event_source) { + r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(m)->manager->event, &m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec, 0, mount_dispatch_timer, m); +} + +static void mount_unwatch_control_pid(Mount *m) { + assert(m); + + if (m->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(m), m->control_pid); + m->control_pid = 0; +} + +static void mount_parameters_done(MountParameters *p) { + assert(p); + + free(p->what); + free(p->options); + free(p->fstype); + + p->what = p->options = p->fstype = NULL; +} + +static void mount_done(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + free(m->where); + m->where = NULL; + + mount_parameters_done(&m->parameters_proc_self_mountinfo); + mount_parameters_done(&m->parameters_fragment); + + cgroup_context_done(&m->cgroup_context); + exec_context_done(&m->exec_context); + m->exec_runtime = exec_runtime_unref(m->exec_runtime); + exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX); + m->control_command = NULL; + + mount_unwatch_control_pid(m); + + m->timer_event_source = sd_event_source_unref(m->timer_event_source); +} + +_pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) { + assert(m); + + if (m->from_fragment) + return &m->parameters_fragment; + + return NULL; +} + +_pure_ static MountParameters* get_mount_parameters(Mount *m) { + assert(m); + + if (m->from_proc_self_mountinfo) + return &m->parameters_proc_self_mountinfo; + + return get_mount_parameters_fragment(m); +} + +static int mount_add_mount_links(Mount *m) { + _cleanup_free_ char *parent = NULL; + MountParameters *pm; + Unit *other; + Iterator i; + Set *s; + int r; + + assert(m); + + if (!path_equal(m->where, "/")) { + /* Adds in links to other mount points that might lie further + * up in the hierarchy */ + r = path_get_parent(m->where, &parent); + if (r < 0) + return r; + + r = unit_require_mounts_for(UNIT(m), parent); + if (r < 0) + return r; + } + + /* Adds in links to other mount points that might be needed + * for the source path (if this is a bind mount) to be + * available. */ + pm = get_mount_parameters_fragment(m); + if (pm && pm->what && + path_is_absolute(pm->what) && + !mount_is_network(pm)) { + + r = unit_require_mounts_for(UNIT(m), pm->what); + if (r < 0) + return r; + } + + /* Adds in links to other units that use this path or paths + * further down in the hierarchy */ + s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where); + SET_FOREACH(other, s, i) { + + if (other->load_state != UNIT_LOADED) + continue; + + if (other == UNIT(m)) + continue; + + r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true); + if (r < 0) + return r; + + if (UNIT(m)->fragment_path) { + /* If we have fragment configuration, then make this dependency required */ + r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true); + if (r < 0) + return r; + } + } + + return 0; +} + +static int mount_add_device_links(Mount *m) { + MountParameters *p; + bool device_wants_mount = false; + int r; + + assert(m); + + p = get_mount_parameters_fragment(m); + if (!p) + return 0; + + if (!p->what) + return 0; + + if (mount_is_bind(p)) + return 0; + + if (!is_device_path(p->what)) + return 0; + + if (path_equal(m->where, "/")) + return 0; + + if (mount_is_auto(p) && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) + device_wants_mount = true; + + r = unit_add_node_link(UNIT(m), p->what, device_wants_mount); + if (r < 0) + return r; + + return 0; +} + +static int mount_add_quota_links(Mount *m) { + int r; + MountParameters *p; + + assert(m); + + if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM) + return 0; + + p = get_mount_parameters_fragment(m); + if (!p) + return 0; + + if (!needs_quota(p)) + return 0; + + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true); + if (r < 0) + return r; + + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true); + if (r < 0) + return r; + + return 0; +} + +static bool should_umount(Mount *m) { + MountParameters *p; + + if (path_equal(m->where, "/") || + path_equal(m->where, "/usr")) + return false; + + p = get_mount_parameters(m); + if (p && mount_test_option(p->options, "x-initrd.mount") && + !in_initrd()) + return false; + + return true; +} + +static int mount_add_default_dependencies(Mount *m) { + const char *after, *after2, *online; + MountParameters *p; + int r; + + assert(m); + + if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM) + return 0; + + p = get_mount_parameters(m); + + if (!p) + return 0; + + if (path_equal(m->where, "/")) + return 0; + + if (mount_is_network(p)) { + after = SPECIAL_REMOTE_FS_PRE_TARGET; + after2 = SPECIAL_NETWORK_TARGET; + online = SPECIAL_NETWORK_ONLINE_TARGET; + } else { + after = SPECIAL_LOCAL_FS_PRE_TARGET; + after2 = NULL; + online = NULL; + } + + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true); + if (r < 0) + return r; + + if (after2) { + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true); + if (r < 0) + return r; + } + + if (online) { + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, online, NULL, true); + if (r < 0) + return r; + } + + if (should_umount(m)) { + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + if (r < 0) + return r; + } + + return 0; +} + +static int mount_fix_timeouts(Mount *m) { + MountParameters *p; + const char *timeout = NULL; + Unit *other; + Iterator i; + usec_t u; + char *t; + int r; + + assert(m); + + p = get_mount_parameters_fragment(m); + if (!p) + return 0; + + /* Allow configuration how long we wait for a device that + * backs a mount point to show up. This is useful to support + * endless device timeouts for devices that show up only after + * user input, like crypto devices. */ + + if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout"))) + timeout += 31; + else if ((timeout = mount_test_option(p->options, "x-systemd.device-timeout"))) + timeout += 25; + else + return 0; + + t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE)); + if (!t) + return -ENOMEM; + + r = parse_sec(t, &u); + free(t); + + if (r < 0) { + log_warning_unit(UNIT(m)->id, + "Failed to parse timeout for %s, ignoring: %s", + m->where, timeout); + return r; + } + + SET_FOREACH(other, UNIT(m)->dependencies[UNIT_AFTER], i) { + if (other->type != UNIT_DEVICE) + continue; + + other->job_timeout = u; + } + + return 0; +} + +static int mount_verify(Mount *m) { + _cleanup_free_ char *e = NULL; + bool b; + + assert(m); + + if (UNIT(m)->load_state != UNIT_LOADED) + return 0; + + if (!m->from_fragment && !m->from_proc_self_mountinfo) + return -ENOENT; + + e = unit_name_from_path(m->where, ".mount"); + if (!e) + return -ENOMEM; + + b = unit_has_name(UNIT(m), e); + if (!b) { + log_error_unit(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id); + return -EINVAL; + } + + if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) { + log_error_unit(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where); + return -EINVAL; + } + + if (UNIT(m)->fragment_path && !m->parameters_fragment.what) { + log_error_unit(UNIT(m)->id, "%s's What setting is missing. Refusing.", UNIT(m)->id); + return -EBADMSG; + } + + if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) { + log_error_unit(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id); + return -EINVAL; + } + + return 0; +} + +static int mount_add_extras(Mount *m) { + Unit *u = UNIT(m); + int r; + + assert(m); + + if (u->fragment_path) + m->from_fragment = true; + + if (!m->where) { + m->where = unit_name_to_path(u->id); + if (!m->where) + return -ENOMEM; + } + + path_kill_slashes(m->where); + + r = unit_add_exec_dependencies(u, &m->exec_context); + if (r < 0) + return r; + + if (!u->description) { + r = unit_set_description(u, m->where); + if (r < 0) + return r; + } + + r = mount_add_device_links(m); + if (r < 0) + return r; + + r = mount_add_mount_links(m); + if (r < 0) + return r; + + r = mount_add_quota_links(m); + if (r < 0) + return r; + + if (u->default_dependencies) { + r = mount_add_default_dependencies(m); + if (r < 0) + return r; + } + + r = unit_add_default_slice(u); + if (r < 0) + return r; + + r = mount_fix_timeouts(m); + if (r < 0) + return r; + + r = unit_exec_context_defaults(u, &m->exec_context); + if (r < 0) + return r; + + return 0; +} + +static int mount_load(Unit *u) { + Mount *m = MOUNT(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + if (m->from_proc_self_mountinfo) + r = unit_load_fragment_and_dropin_optional(u); + else + r = unit_load_fragment_and_dropin(u); + + if (r < 0) + return r; + + /* This is a new unit? Then let's add in some extras */ + if (u->load_state == UNIT_LOADED) { + r = mount_add_extras(m); + if (r < 0) + return r; + } + + return mount_verify(m); +} + +static int mount_notify_automount(Mount *m, int status) { + Unit *p; + int r; + Iterator i; + + assert(m); + + SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i) + if (p->type == UNIT_AUTOMOUNT) { + r = automount_send_ready(AUTOMOUNT(p), status); + if (r < 0) + return r; + } + + return 0; +} + +static void mount_set_state(Mount *m, MountState state) { + MountState old_state; + assert(m); + + old_state = m->state; + m->state = state; + + if (state != MOUNT_MOUNTING && + state != MOUNT_MOUNTING_DONE && + state != MOUNT_REMOUNTING && + state != MOUNT_UNMOUNTING && + state != MOUNT_MOUNTING_SIGTERM && + state != MOUNT_MOUNTING_SIGKILL && + state != MOUNT_UNMOUNTING_SIGTERM && + state != MOUNT_UNMOUNTING_SIGKILL && + state != MOUNT_REMOUNTING_SIGTERM && + state != MOUNT_REMOUNTING_SIGKILL) { + m->timer_event_source = sd_event_source_unref(m->timer_event_source); + mount_unwatch_control_pid(m); + m->control_command = NULL; + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + } + + if (state == MOUNT_MOUNTED || + state == MOUNT_REMOUNTING) + mount_notify_automount(m, 0); + else if (state == MOUNT_DEAD || + state == MOUNT_UNMOUNTING || + state == MOUNT_MOUNTING_SIGTERM || + state == MOUNT_MOUNTING_SIGKILL || + state == MOUNT_REMOUNTING_SIGTERM || + state == MOUNT_REMOUNTING_SIGKILL || + state == MOUNT_UNMOUNTING_SIGTERM || + state == MOUNT_UNMOUNTING_SIGKILL || + state == MOUNT_FAILED) { + if (state != old_state) + mount_notify_automount(m, -ENODEV); + } + + if (state != old_state) + log_debug_unit(UNIT(m)->id, + "%s changed %s -> %s", + UNIT(m)->id, + mount_state_to_string(old_state), + mount_state_to_string(state)); + + unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS); + m->reload_result = MOUNT_SUCCESS; +} + +static int mount_coldplug(Unit *u) { + Mount *m = MOUNT(u); + MountState new_state = MOUNT_DEAD; + int r; + + assert(m); + assert(m->state == MOUNT_DEAD); + + if (m->deserialized_state != m->state) + new_state = m->deserialized_state; + else if (m->from_proc_self_mountinfo) + new_state = MOUNT_MOUNTED; + + if (new_state == m->state) + return 0; + + if (new_state == MOUNT_MOUNTING || + new_state == MOUNT_MOUNTING_DONE || + new_state == MOUNT_REMOUNTING || + new_state == MOUNT_UNMOUNTING || + new_state == MOUNT_MOUNTING_SIGTERM || + new_state == MOUNT_MOUNTING_SIGKILL || + new_state == MOUNT_UNMOUNTING_SIGTERM || + new_state == MOUNT_UNMOUNTING_SIGKILL || + new_state == MOUNT_REMOUNTING_SIGTERM || + new_state == MOUNT_REMOUNTING_SIGKILL) { + + if (m->control_pid <= 0) + return -EBADMSG; + + r = unit_watch_pid(UNIT(m), m->control_pid); + if (r < 0) + return r; + + r = mount_arm_timer(m); + if (r < 0) + return r; + } + + mount_set_state(m, new_state); + return 0; +} + +static void mount_dump(Unit *u, FILE *f, const char *prefix) { + Mount *m = MOUNT(u); + MountParameters *p; + + assert(m); + assert(f); + + p = get_mount_parameters(m); + + fprintf(f, + "%sMount State: %s\n" + "%sResult: %s\n" + "%sWhere: %s\n" + "%sWhat: %s\n" + "%sFile System Type: %s\n" + "%sOptions: %s\n" + "%sFrom /proc/self/mountinfo: %s\n" + "%sFrom fragment: %s\n" + "%sDirectoryMode: %04o\n", + prefix, mount_state_to_string(m->state), + prefix, mount_result_to_string(m->result), + prefix, m->where, + prefix, p ? strna(p->what) : "n/a", + prefix, p ? strna(p->fstype) : "n/a", + prefix, p ? strna(p->options) : "n/a", + prefix, yes_no(m->from_proc_self_mountinfo), + prefix, yes_no(m->from_fragment), + prefix, m->directory_mode); + + if (m->control_pid > 0) + fprintf(f, + "%sControl PID: "PID_FMT"\n", + prefix, m->control_pid); + + exec_context_dump(&m->exec_context, f, prefix); + kill_context_dump(&m->kill_context, f, prefix); +} + +static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { + pid_t pid; + int r; + + assert(m); + assert(c); + assert(_pid); + + unit_realize_cgroup(UNIT(m)); + + r = unit_setup_exec_runtime(UNIT(m)); + if (r < 0) + goto fail; + + r = mount_arm_timer(m); + if (r < 0) + goto fail; + + r = exec_spawn(c, + NULL, + &m->exec_context, + NULL, 0, + UNIT(m)->manager->environment, + true, + true, + true, + UNIT(m)->manager->confirm_spawn, + UNIT(m)->manager->cgroup_supported, + UNIT(m)->cgroup_path, + UNIT(m)->id, + 0, + NULL, + m->exec_runtime, + &pid); + if (r < 0) + goto fail; + + r = unit_watch_pid(UNIT(m), pid); + if (r < 0) + /* FIXME: we need to do something here */ + goto fail; + + *_pid = pid; + + return 0; + +fail: + m->timer_event_source = sd_event_source_unref(m->timer_event_source); + + return r; +} + +static void mount_enter_dead(Mount *m, MountResult f) { + assert(m); + + if (f != MOUNT_SUCCESS) + m->result = f; + + exec_runtime_destroy(m->exec_runtime); + m->exec_runtime = exec_runtime_unref(m->exec_runtime); + + mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD); +} + +static void mount_enter_mounted(Mount *m, MountResult f) { + assert(m); + + if (f != MOUNT_SUCCESS) + m->result = f; + + mount_set_state(m, MOUNT_MOUNTED); +} + +static void mount_enter_signal(Mount *m, MountState state, MountResult f) { + int r; + + assert(m); + + if (f != MOUNT_SUCCESS) + m->result = f; + + r = unit_kill_context( + UNIT(m), + &m->kill_context, + state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM, + -1, + m->control_pid, + false); + if (r < 0) + goto fail; + + if (r > 0) { + r = mount_arm_timer(m); + if (r < 0) + goto fail; + + mount_set_state(m, state); + } else if (state == MOUNT_REMOUNTING_SIGTERM) + mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS); + else if (state == MOUNT_REMOUNTING_SIGKILL) + mount_enter_mounted(m, MOUNT_SUCCESS); + else if (state == MOUNT_MOUNTING_SIGTERM) + mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_SUCCESS); + else if (state == MOUNT_UNMOUNTING_SIGTERM) + mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS); + else + mount_enter_dead(m, MOUNT_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(m)->id, + "%s failed to kill processes: %s", UNIT(m)->id, strerror(-r)); + + if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL) + mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); + else + mount_enter_dead(m, MOUNT_FAILURE_RESOURCES); +} + +void warn_if_dir_nonempty(const char *unit, const char* where) { + assert(unit); + assert(where); + + if (dir_is_empty(where) > 0) + return; + + log_struct_unit(LOG_NOTICE, + unit, + "MESSAGE=%s: Directory %s to mount over is not empty, mounting anyway.", + unit, where, + "WHERE=%s", where, + MESSAGE_ID(SD_MESSAGE_OVERMOUNTING), + NULL); +} + +static void mount_enter_unmounting(Mount *m) { + int r; + + assert(m); + + m->control_command_id = MOUNT_EXEC_UNMOUNT; + m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; + + if ((r = exec_command_set( + m->control_command, + "/bin/umount", + m->where, + NULL)) < 0) + goto fail; + + mount_unwatch_control_pid(m); + + if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) + goto fail; + + mount_set_state(m, MOUNT_UNMOUNTING); + + return; + +fail: + log_warning_unit(UNIT(m)->id, + "%s failed to run 'umount' task: %s", + UNIT(m)->id, strerror(-r)); + mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); +} + +static void mount_enter_mounting(Mount *m) { + int r; + MountParameters *p; + + assert(m); + + m->control_command_id = MOUNT_EXEC_MOUNT; + m->control_command = m->exec_command + MOUNT_EXEC_MOUNT; + + mkdir_p_label(m->where, m->directory_mode); + + warn_if_dir_nonempty(m->meta.id, m->where); + + /* Create the source directory for bind-mounts if needed */ + p = get_mount_parameters_fragment(m); + if (p && mount_is_bind(p)) + mkdir_p_label(p->what, m->directory_mode); + + if (m->from_fragment) + r = exec_command_set( + m->control_command, + "/bin/mount", + m->parameters_fragment.what, + m->where, + "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", + m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options, + NULL); + else + r = -ENOENT; + + if (r < 0) + goto fail; + + mount_unwatch_control_pid(m); + + r = mount_spawn(m, m->control_command, &m->control_pid); + if (r < 0) + goto fail; + + mount_set_state(m, MOUNT_MOUNTING); + + return; + +fail: + log_warning_unit(UNIT(m)->id, + "%s failed to run 'mount' task: %s", + UNIT(m)->id, strerror(-r)); + mount_enter_dead(m, MOUNT_FAILURE_RESOURCES); +} + +static void mount_enter_remounting(Mount *m) { + int r; + + assert(m); + + m->control_command_id = MOUNT_EXEC_REMOUNT; + m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT; + + if (m->from_fragment) { + const char *o; + + if (m->parameters_fragment.options) + o = strappenda("remount,", m->parameters_fragment.options); + else + o = "remount"; + + r = exec_command_set( + m->control_command, + "/bin/mount", + m->parameters_fragment.what, + m->where, + "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", + "-o", o, + NULL); + } else + r = -ENOENT; + + if (r < 0) + goto fail; + + mount_unwatch_control_pid(m); + + r = mount_spawn(m, m->control_command, &m->control_pid); + if (r < 0) + goto fail; + + mount_set_state(m, MOUNT_REMOUNTING); + + return; + +fail: + log_warning_unit(UNIT(m)->id, + "%s failed to run 'remount' task: %s", + UNIT(m)->id, strerror(-r)); + m->reload_result = MOUNT_FAILURE_RESOURCES; + mount_enter_mounted(m, MOUNT_SUCCESS); +} + +static int mount_start(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + /* We cannot fulfill this request right now, try again later + * please! */ + if (m->state == MOUNT_UNMOUNTING || + m->state == MOUNT_UNMOUNTING_SIGTERM || + m->state == MOUNT_UNMOUNTING_SIGKILL || + m->state == MOUNT_MOUNTING_SIGTERM || + m->state == MOUNT_MOUNTING_SIGKILL) + return -EAGAIN; + + /* Already on it! */ + if (m->state == MOUNT_MOUNTING) + return 0; + + assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED); + + m->result = MOUNT_SUCCESS; + m->reload_result = MOUNT_SUCCESS; + + mount_enter_mounting(m); + return 0; +} + +static int mount_stop(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + /* Already on it */ + if (m->state == MOUNT_UNMOUNTING || + m->state == MOUNT_UNMOUNTING_SIGKILL || + m->state == MOUNT_UNMOUNTING_SIGTERM || + m->state == MOUNT_MOUNTING_SIGTERM || + m->state == MOUNT_MOUNTING_SIGKILL) + return 0; + + assert(m->state == MOUNT_MOUNTING || + m->state == MOUNT_MOUNTING_DONE || + m->state == MOUNT_MOUNTED || + m->state == MOUNT_REMOUNTING || + m->state == MOUNT_REMOUNTING_SIGTERM || + m->state == MOUNT_REMOUNTING_SIGKILL); + + mount_enter_unmounting(m); + return 0; +} + +static int mount_reload(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + if (m->state == MOUNT_MOUNTING_DONE) + return -EAGAIN; + + assert(m->state == MOUNT_MOUNTED); + + mount_enter_remounting(m); + return 0; +} + +static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { + Mount *m = MOUNT(u); + + assert(m); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", mount_state_to_string(m->state)); + unit_serialize_item(u, f, "result", mount_result_to_string(m->result)); + unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result)); + + if (m->control_pid > 0) + unit_serialize_item_format(u, f, "control-pid", PID_FMT, m->control_pid); + + if (m->control_command_id >= 0) + unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id)); + + return 0; +} + +static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Mount *m = MOUNT(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + MountState state; + + if ((state = mount_state_from_string(value)) < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + m->deserialized_state = state; + } else if (streq(key, "result")) { + MountResult f; + + f = mount_result_from_string(value); + if (f < 0) + log_debug_unit(UNIT(m)->id, + "Failed to parse result value %s", value); + else if (f != MOUNT_SUCCESS) + m->result = f; + + } else if (streq(key, "reload-result")) { + MountResult f; + + f = mount_result_from_string(value); + if (f < 0) + log_debug_unit(UNIT(m)->id, + "Failed to parse reload result value %s", value); + else if (f != MOUNT_SUCCESS) + m->reload_result = f; + + } else if (streq(key, "control-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(UNIT(m)->id, + "Failed to parse control-pid value %s", value); + else + m->control_pid = pid; + } else if (streq(key, "control-command")) { + MountExecCommand id; + + if ((id = mount_exec_command_from_string(value)) < 0) + log_debug_unit(UNIT(m)->id, + "Failed to parse exec-command value %s", value); + else { + m->control_command_id = id; + m->control_command = m->exec_command + id; + } + } else + log_debug_unit(UNIT(m)->id, + "Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState mount_active_state(Unit *u) { + assert(u); + + return state_translation_table[MOUNT(u)->state]; +} + +_pure_ static const char *mount_sub_state_to_string(Unit *u) { + assert(u); + + return mount_state_to_string(MOUNT(u)->state); +} + +_pure_ static bool mount_check_gc(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + return m->from_proc_self_mountinfo; +} + +static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { + Mount *m = MOUNT(u); + MountResult f; + + assert(m); + assert(pid >= 0); + + if (pid != m->control_pid) + return; + + m->control_pid = 0; + + if (is_clean_exit(code, status, NULL)) + f = MOUNT_SUCCESS; + else if (code == CLD_EXITED) + f = MOUNT_FAILURE_EXIT_CODE; + else if (code == CLD_KILLED) + f = MOUNT_FAILURE_SIGNAL; + else if (code == CLD_DUMPED) + f = MOUNT_FAILURE_CORE_DUMP; + else + assert_not_reached("Unknown code"); + + if (f != MOUNT_SUCCESS) + m->result = f; + + if (m->control_command) { + exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status); + + m->control_command = NULL; + m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + } + + log_full_unit(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, u->id, + "%s mount process exited, code=%s status=%i", + u->id, sigchld_code_to_string(code), status); + + /* Note that mount(8) returning and the kernel sending us a + * mount table change event might happen out-of-order. If an + * operation succeed we assume the kernel will follow soon too + * and already change into the resulting state. If it fails + * we check if the kernel still knows about the mount. and + * change state accordingly. */ + + switch (m->state) { + + case MOUNT_MOUNTING: + case MOUNT_MOUNTING_DONE: + case MOUNT_MOUNTING_SIGKILL: + case MOUNT_MOUNTING_SIGTERM: + + if (f == MOUNT_SUCCESS) + mount_enter_mounted(m, f); + else if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, f); + else + mount_enter_dead(m, f); + break; + + case MOUNT_REMOUNTING: + case MOUNT_REMOUNTING_SIGKILL: + case MOUNT_REMOUNTING_SIGTERM: + + m->reload_result = f; + if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, MOUNT_SUCCESS); + else + mount_enter_dead(m, MOUNT_SUCCESS); + + break; + + case MOUNT_UNMOUNTING: + case MOUNT_UNMOUNTING_SIGKILL: + case MOUNT_UNMOUNTING_SIGTERM: + + if (f == MOUNT_SUCCESS) + mount_enter_dead(m, f); + else if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, f); + else + mount_enter_dead(m, f); + break; + + default: + assert_not_reached("Uh, control process died at wrong time."); + } + + /* Notify clients about changed exit status */ + unit_add_to_dbus_queue(u); +} + +static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Mount *m = MOUNT(userdata); + + assert(m); + assert(m->timer_event_source == source); + + switch (m->state) { + + case MOUNT_MOUNTING: + case MOUNT_MOUNTING_DONE: + log_warning_unit(UNIT(m)->id, + "%s mounting timed out. Stopping.", UNIT(m)->id); + mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); + break; + + case MOUNT_REMOUNTING: + log_warning_unit(UNIT(m)->id, + "%s remounting timed out. Stopping.", UNIT(m)->id); + m->reload_result = MOUNT_FAILURE_TIMEOUT; + mount_enter_mounted(m, MOUNT_SUCCESS); + break; + + case MOUNT_UNMOUNTING: + log_warning_unit(UNIT(m)->id, + "%s unmounting timed out. Stopping.", UNIT(m)->id); + mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT); + break; + + case MOUNT_MOUNTING_SIGTERM: + if (m->kill_context.send_sigkill) { + log_warning_unit(UNIT(m)->id, + "%s mounting timed out. Killing.", UNIT(m)->id); + mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(m)->id, + "%s mounting timed out. Skipping SIGKILL. Ignoring.", + UNIT(m)->id); + + if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); + else + mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT); + } + break; + + case MOUNT_REMOUNTING_SIGTERM: + if (m->kill_context.send_sigkill) { + log_warning_unit(UNIT(m)->id, + "%s remounting timed out. Killing.", UNIT(m)->id); + mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(m)->id, + "%s remounting timed out. Skipping SIGKILL. Ignoring.", + UNIT(m)->id); + + if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); + else + mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT); + } + break; + + case MOUNT_UNMOUNTING_SIGTERM: + if (m->kill_context.send_sigkill) { + log_warning_unit(UNIT(m)->id, + "%s unmounting timed out. Killing.", UNIT(m)->id); + mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(m)->id, + "%s unmounting timed out. Skipping SIGKILL. Ignoring.", + UNIT(m)->id); + + if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); + else + mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT); + } + break; + + case MOUNT_MOUNTING_SIGKILL: + case MOUNT_REMOUNTING_SIGKILL: + case MOUNT_UNMOUNTING_SIGKILL: + log_warning_unit(UNIT(m)->id, + "%s mount process still around after SIGKILL. Ignoring.", + UNIT(m)->id); + + if (m->from_proc_self_mountinfo) + mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT); + else + mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +static int mount_add_one( + Manager *m, + const char *what, + const char *where, + const char *options, + const char *fstype, + bool set_flags) { + + _cleanup_free_ char *e = NULL, *w = NULL, *o = NULL, *f = NULL; + bool load_extras = false; + MountParameters *p; + bool delete; + Unit *u; + int r; + + assert(m); + assert(what); + assert(where); + assert(options); + assert(fstype); + + /* Ignore API mount points. They should never be referenced in + * dependencies ever. */ + if (mount_point_is_api(where) || mount_point_ignore(where)) + return 0; + + if (streq(fstype, "autofs")) + return 0; + + /* probably some kind of swap, ignore */ + if (!is_path(where)) + return 0; + + e = unit_name_from_path(where, ".mount"); + if (!e) + return -ENOMEM; + + u = manager_get_unit(m, e); + if (!u) { + delete = true; + + u = unit_new(m, sizeof(Mount)); + if (!u) + return -ENOMEM; + + r = unit_add_name(u, e); + if (r < 0) + goto fail; + + MOUNT(u)->where = strdup(where); + if (!MOUNT(u)->where) { + r = -ENOMEM; + goto fail; + } + + u->source_path = strdup("/proc/self/mountinfo"); + if (!u->source_path) { + r = -ENOMEM; + goto fail; + } + + + if (m->running_as == SYSTEMD_SYSTEM) { + const char* target; + + target = fstype_is_network(fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET; + + r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true); + if (r < 0) + goto fail; + + if (should_umount(MOUNT(u))) { + r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + if (r < 0) + goto fail; + } + } + + unit_add_to_load_queue(u); + } else { + delete = false; + + if (!MOUNT(u)->where) { + MOUNT(u)->where = strdup(where); + if (!MOUNT(u)->where) { + r = -ENOMEM; + goto fail; + } + } + + if (u->load_state == UNIT_NOT_FOUND) { + u->load_state = UNIT_LOADED; + u->load_error = 0; + + /* Load in the extras later on, after we + * finished initialization of the unit */ + load_extras = true; + } + } + + if (!(w = strdup(what)) || + !(o = strdup(options)) || + !(f = strdup(fstype))) { + r = -ENOMEM; + goto fail; + } + + p = &MOUNT(u)->parameters_proc_self_mountinfo; + if (set_flags) { + MOUNT(u)->is_mounted = true; + MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo; + MOUNT(u)->just_changed = !streq_ptr(p->options, o); + } + + MOUNT(u)->from_proc_self_mountinfo = true; + + free(p->what); + p->what = w; + w = NULL; + + free(p->options); + p->options = o; + o = NULL; + + free(p->fstype); + p->fstype = f; + f = NULL; + + if (load_extras) { + r = mount_add_extras(MOUNT(u)); + if (r < 0) + goto fail; + } + + unit_add_to_dbus_queue(u); + + return 0; + +fail: + if (delete && u) + unit_free(u); + + return r; +} + +static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + int r = 0; + unsigned i; + + assert(m); + + rewind(m->proc_self_mountinfo); + + for (i = 1;; i++) { + _cleanup_free_ char *device = NULL, *path = NULL, *options = NULL, *options2 = NULL, *fstype = NULL, *d = NULL, *p = NULL, *o = NULL; + int k; + + k = fscanf(m->proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%ms" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%ms " /* (9) file system type */ + "%ms" /* (10) mount source */ + "%ms" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path, + &options, + &fstype, + &device, + &options2); + + if (k == EOF) + break; + + if (k != 5) { + log_warning("Failed to parse /proc/self/mountinfo:%u.", i); + continue; + } + + o = strjoin(options, ",", options2, NULL); + if (!o) + return log_oom(); + + d = cunescape(device); + p = cunescape(path); + if (!d || !p) + return log_oom(); + + k = mount_add_one(m, d, p, o, fstype, set_flags); + if (k < 0) + r = k; + } + + return r; +} + +static void mount_shutdown(Manager *m) { + assert(m); + + m->mount_event_source = sd_event_source_unref(m->mount_event_source); + + if (m->proc_self_mountinfo) { + fclose(m->proc_self_mountinfo); + m->proc_self_mountinfo = NULL; + } +} + +static int mount_get_timeout(Unit *u, uint64_t *timeout) { + Mount *m = MOUNT(u); + int r; + + if (!m->timer_event_source) + return 0; + + r = sd_event_source_get_time(m->timer_event_source, timeout); + if (r < 0) + return r; + + return 1; +} + +static int mount_enumerate(Manager *m) { + int r; + assert(m); + + if (!m->proc_self_mountinfo) { + m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!m->proc_self_mountinfo) + return -errno; + + r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m); + if (r < 0) + goto fail; + + /* Dispatch this before we dispatch SIGCHLD, so that + * we always get the events from /proc/self/mountinfo + * before the SIGCHLD of /bin/mount. */ + r = sd_event_source_set_priority(m->mount_event_source, -10); + if (r < 0) + goto fail; + } + + r = mount_load_proc_self_mountinfo(m, false); + if (r < 0) + goto fail; + + return 0; + +fail: + mount_shutdown(m); + return r; +} + +static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + Unit *u; + int r; + + assert(m); + assert(revents & EPOLLPRI); + + /* The manager calls this for every fd event happening on the + * /proc/self/mountinfo file, which informs us about mounting + * table changes */ + + r = mount_load_proc_self_mountinfo(m, true); + if (r < 0) { + log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r)); + + /* Reset flags, just in case, for later calls */ + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) { + Mount *mount = MOUNT(u); + + mount->is_mounted = mount->just_mounted = mount->just_changed = false; + } + + return 0; + } + + manager_dispatch_load_queue(m); + + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) { + Mount *mount = MOUNT(u); + + if (!mount->is_mounted) { + /* This has just been unmounted. */ + + mount->from_proc_self_mountinfo = false; + + switch (mount->state) { + + case MOUNT_MOUNTED: + mount_enter_dead(mount, MOUNT_SUCCESS); + break; + + default: + mount_set_state(mount, mount->state); + break; + + } + + } else if (mount->just_mounted || mount->just_changed) { + + /* New or changed mount entry */ + + switch (mount->state) { + + case MOUNT_DEAD: + case MOUNT_FAILED: + mount_enter_mounted(mount, MOUNT_SUCCESS); + break; + + case MOUNT_MOUNTING: + mount_set_state(mount, MOUNT_MOUNTING_DONE); + break; + + default: + /* Nothing really changed, but let's + * issue an notification call + * nonetheless, in case somebody is + * waiting for this. (e.g. file system + * ro/rw remounts.) */ + mount_set_state(mount, mount->state); + break; + } + } + + /* Reset the flags for later calls */ + mount->is_mounted = mount->just_mounted = mount->just_changed = false; + } + + return 0; +} + +static void mount_reset_failed(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + if (m->state == MOUNT_FAILED) + mount_set_state(m, MOUNT_DEAD); + + m->result = MOUNT_SUCCESS; + m->reload_result = MOUNT_SUCCESS; +} + +static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); +} + +static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTING_DONE] = "mounting-done", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_REMOUNTING] = "remounting", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", + [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", + [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", + [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", + [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", + [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + +static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { + [MOUNT_EXEC_MOUNT] = "ExecMount", + [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", + [MOUNT_EXEC_REMOUNT] = "ExecRemount", +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand); + +static const char* const mount_result_table[_MOUNT_RESULT_MAX] = { + [MOUNT_SUCCESS] = "success", + [MOUNT_FAILURE_RESOURCES] = "resources", + [MOUNT_FAILURE_TIMEOUT] = "timeout", + [MOUNT_FAILURE_EXIT_CODE] = "exit-code", + [MOUNT_FAILURE_SIGNAL] = "signal", + [MOUNT_FAILURE_CORE_DUMP] = "core-dump" +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult); + +const UnitVTable mount_vtable = { + .object_size = sizeof(Mount), + .exec_context_offset = offsetof(Mount, exec_context), + .cgroup_context_offset = offsetof(Mount, cgroup_context), + .kill_context_offset = offsetof(Mount, kill_context), + .exec_runtime_offset = offsetof(Mount, exec_runtime), + + .sections = + "Unit\0" + "Mount\0" + "Install\0", + .private_section = "Mount", + + .no_alias = true, + .no_instances = true, + + .init = mount_init, + .load = mount_load, + .done = mount_done, + + .coldplug = mount_coldplug, + + .dump = mount_dump, + + .start = mount_start, + .stop = mount_stop, + .reload = mount_reload, + + .kill = mount_kill, + + .serialize = mount_serialize, + .deserialize_item = mount_deserialize_item, + + .active_state = mount_active_state, + .sub_state_to_string = mount_sub_state_to_string, + + .check_gc = mount_check_gc, + + .sigchld_event = mount_sigchld_event, + + .reset_failed = mount_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.Mount", + .bus_vtable = bus_mount_vtable, + .bus_set_property = bus_mount_set_property, + .bus_commit_properties = bus_mount_commit_properties, + + .get_timeout = mount_get_timeout, + + .enumerate = mount_enumerate, + .shutdown = mount_shutdown, + + .status_message_formats = { + .starting_stopping = { + [0] = "Mounting %s...", + [1] = "Unmounting %s...", + }, + .finished_start_job = { + [JOB_DONE] = "Mounted %s.", + [JOB_FAILED] = "Failed to mount %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_TIMEOUT] = "Timed out mounting %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Unmounted %s.", + [JOB_FAILED] = "Failed unmounting %s.", + [JOB_TIMEOUT] = "Timed out unmounting %s.", + }, + }, +}; diff --git a/src/core/mount.h b/src/core/mount.h new file mode 100644 index 0000000..a53423c --- /dev/null +++ b/src/core/mount.h @@ -0,0 +1,128 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Mount Mount; + +#include "unit.h" +#include "kill.h" +#include "execute.h" +#include "cgroup.h" + +typedef enum MountState { + MOUNT_DEAD, + MOUNT_MOUNTING, /* /bin/mount is running, but the mount is not done yet. */ + MOUNT_MOUNTING_DONE, /* /bin/mount is running, and the mount is done. */ + MOUNT_MOUNTED, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED, + _MOUNT_STATE_MAX, + _MOUNT_STATE_INVALID = -1 +} MountState; + +typedef enum MountExecCommand { + MOUNT_EXEC_MOUNT, + MOUNT_EXEC_UNMOUNT, + MOUNT_EXEC_REMOUNT, + _MOUNT_EXEC_COMMAND_MAX, + _MOUNT_EXEC_COMMAND_INVALID = -1 +} MountExecCommand; + +typedef enum MountResult { + MOUNT_SUCCESS, + MOUNT_FAILURE_RESOURCES, + MOUNT_FAILURE_TIMEOUT, + MOUNT_FAILURE_EXIT_CODE, + MOUNT_FAILURE_SIGNAL, + MOUNT_FAILURE_CORE_DUMP, + _MOUNT_RESULT_MAX, + _MOUNT_RESULT_INVALID = -1 +} MountResult; + +typedef struct MountParameters { + char *what; + char *options; + char *fstype; +} MountParameters; + +struct Mount { + Unit meta; + + char *where; + + MountParameters parameters_proc_self_mountinfo; + MountParameters parameters_fragment; + + bool from_proc_self_mountinfo:1; + bool from_fragment:1; + + /* Used while looking for mount points that vanished or got + * added from/to /proc/self/mountinfo */ + bool is_mounted:1; + bool just_mounted:1; + bool just_changed:1; + + MountResult result; + MountResult reload_result; + + mode_t directory_mode; + + usec_t timeout_usec; + + ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX]; + + ExecContext exec_context; + KillContext kill_context; + CGroupContext cgroup_context; + + ExecRuntime *exec_runtime; + + MountState state, deserialized_state; + + ExecCommand* control_command; + MountExecCommand control_command_id; + pid_t control_pid; + + sd_event_source *timer_event_source; +}; + +extern const UnitVTable mount_vtable; + +void mount_fd_event(Manager *m, int events); + +const char* mount_state_to_string(MountState i) _const_; +MountState mount_state_from_string(const char *s) _pure_; + +const char* mount_exec_command_to_string(MountExecCommand i) _const_; +MountExecCommand mount_exec_command_from_string(const char *s) _pure_; + +const char* mount_result_to_string(MountResult i) _const_; +MountResult mount_result_from_string(const char *s) _pure_; + +void warn_if_dir_nonempty(const char *unit, const char* where); diff --git a/src/core/namespace.c b/src/core/namespace.c new file mode 100644 index 0000000..c034bfd --- /dev/null +++ b/src/core/namespace.c @@ -0,0 +1,519 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "strv.h" +#include "util.h" +#include "path-util.h" +#include "namespace.h" +#include "missing.h" +#include "execute.h" +#include "loopback-setup.h" +#include "mkdir.h" +#include "dev-setup.h" +#include "def.h" + +typedef enum MountMode { + /* This is ordered by priority! */ + INACCESSIBLE, + READONLY, + PRIVATE_TMP, + PRIVATE_VAR_TMP, + PRIVATE_DEV, + READWRITE +} MountMode; + +typedef struct BindMount { + const char *path; + MountMode mode; + bool done; + bool ignore; +} BindMount; + +static int append_mounts(BindMount **p, char **strv, MountMode mode) { + char **i; + + assert(p); + + STRV_FOREACH(i, strv) { + + (*p)->ignore = false; + + if ((mode == INACCESSIBLE || mode == READONLY) && (*i)[0] == '-') { + (*p)->ignore = true; + (*i)++; + } + + if (!path_is_absolute(*i)) + return -EINVAL; + + (*p)->path = *i; + (*p)->mode = mode; + (*p)++; + } + + return 0; +} + +static int mount_path_compare(const void *a, const void *b) { + const BindMount *p = a, *q = b; + + if (path_equal(p->path, q->path)) { + + /* If the paths are equal, check the mode */ + if (p->mode < q->mode) + return -1; + + if (p->mode > q->mode) + return 1; + + return 0; + } + + /* If the paths are not equal, then order prefixes first */ + if (path_startswith(p->path, q->path)) + return 1; + + if (path_startswith(q->path, p->path)) + return -1; + + return 0; +} + +static void drop_duplicates(BindMount *m, unsigned *n) { + BindMount *f, *t, *previous; + + assert(m); + assert(n); + + for (f = m, t = m, previous = NULL; f < m+*n; f++) { + + /* The first one wins */ + if (previous && path_equal(f->path, previous->path)) + continue; + + t->path = f->path; + t->mode = f->mode; + + previous = t; + + t++; + } + + *n = t - m; +} + +static int mount_dev(BindMount *m) { + static const char devnodes[] = + "/dev/null\0" + "/dev/zero\0" + "/dev/full\0" + "/dev/random\0" + "/dev/urandom\0" + "/dev/tty\0"; + + struct stat devnodes_stat[6] = {}; + const char *d; + unsigned n = 0; + _cleanup_umask_ mode_t u; + int r; + + assert(m); + + u = umask(0000); + + /* First: record device mode_t and dev_t */ + NULSTR_FOREACH(d, devnodes) { + r = stat(d, &devnodes_stat[n]); + if (r < 0) { + if (errno != ENOENT) + return -errno; + } else { + if (!S_ISBLK(devnodes_stat[n].st_mode) && + !S_ISCHR(devnodes_stat[n].st_mode)) + return -EINVAL; + } + + n++; + } + + assert(n == ELEMENTSOF(devnodes_stat)); + + r = mount("tmpfs", "/dev", "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755"); + if (r < 0) + return m->ignore ? 0 : -errno; + + + mkdir_p("/dev/pts", 0755); + + r = mount("devpts", "/dev/pts", "devpts", MS_NOSUID|MS_NOEXEC, "newinstance,ptmxmode=0666,mode=620,gid=" STRINGIFY(TTY_GID)); + if (r < 0) + return m->ignore ? 0 : -errno; + + mkdir_p("/dev/shm", 0755); + + r = mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID|MS_NODEV|MS_STRICTATIME, "mode=1777"); + if (r < 0) + return m->ignore ? 0 : -errno; + + /* Second: actually create it */ + n = 0; + NULSTR_FOREACH(d, devnodes) { + if (devnodes_stat[n].st_rdev == 0) + continue; + + r = mknod(d, devnodes_stat[n].st_mode, devnodes_stat[n].st_rdev); + if (r < 0) + return m->ignore ? 0 : -errno; + + n++; + } + + dev_setup(NULL); + + return 0; +} + +static int apply_mount( + BindMount *m, + const char *tmp_dir, + const char *var_tmp_dir) { + + const char *what; + int r; + + assert(m); + + switch (m->mode) { + + case PRIVATE_DEV: + return mount_dev(m); + + case INACCESSIBLE: + what = "/run/systemd/inaccessible"; + break; + + case READONLY: + case READWRITE: + what = m->path; + break; + + case PRIVATE_TMP: + what = tmp_dir; + break; + + case PRIVATE_VAR_TMP: + what = var_tmp_dir; + break; + + default: + assert_not_reached("Unknown mode"); + } + + assert(what); + + r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL); + if (r >= 0) + log_debug("Successfully mounted %s to %s", what, m->path); + else if (m->ignore && errno == ENOENT) + r = 0; + + return r; +} + +static int make_read_only(BindMount *m) { + int r; + + assert(m); + + if (m->mode != INACCESSIBLE && m->mode != READONLY) + return 0; + + r = mount(NULL, m->path, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL); + if (r < 0 && !(m->ignore && errno == ENOENT)) + return -errno; + + return 0; +} + +int setup_namespace( + char** read_write_dirs, + char** read_only_dirs, + char** inaccessible_dirs, + char* tmp_dir, + char* var_tmp_dir, + bool private_dev, + unsigned mount_flags) { + + BindMount *m, *mounts = NULL; + unsigned n; + int r = 0; + + if (mount_flags == 0) + mount_flags = MS_SHARED; + + if (unshare(CLONE_NEWNS) < 0) + return -errno; + + n = !!tmp_dir + !!var_tmp_dir + + strv_length(read_write_dirs) + + strv_length(read_only_dirs) + + strv_length(inaccessible_dirs) + + private_dev; + + if (n > 0) { + m = mounts = (BindMount *) alloca(n * sizeof(BindMount)); + r = append_mounts(&m, read_write_dirs, READWRITE); + if (r < 0) + return r; + + r = append_mounts(&m, read_only_dirs, READONLY); + if (r < 0) + return r; + + r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE); + if (r < 0) + return r; + + if (tmp_dir) { + m->path = "/tmp"; + m->mode = PRIVATE_TMP; + m++; + } + + if (var_tmp_dir) { + m->path = "/var/tmp"; + m->mode = PRIVATE_VAR_TMP; + m++; + } + + if (private_dev) { + m->path = "/dev"; + m->mode = PRIVATE_DEV; + m++; + } + + assert(mounts + n == m); + + qsort(mounts, n, sizeof(BindMount), mount_path_compare); + drop_duplicates(mounts, &n); + } + + /* Remount / as SLAVE so that nothing now mounted in the namespace + shows up in the parent */ + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) + return -errno; + + for (m = mounts; m < mounts + n; ++m) { + r = apply_mount(m, tmp_dir, var_tmp_dir); + if (r < 0) + goto fail; + } + + for (m = mounts; m < mounts + n; ++m) { + r = make_read_only(m); + if (r < 0) + goto fail; + } + + /* Remount / as the desired mode */ + if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + for (m = mounts; m < mounts + n; ++m) + if (m->done) + umount2(m->path, MNT_DETACH); + + return r; +} + +static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) { + _cleanup_free_ char *x = NULL; + char bid[SD_ID128_STRING_MAX]; + sd_id128_t boot_id; + int r; + + assert(id); + assert(prefix); + assert(path); + + /* We include the boot id in the directory so that after a + * reboot we can easily identify obsolete directories. */ + + r = sd_id128_get_boot(&boot_id); + if (r < 0) + return r; + + x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL); + if (!x) + return -ENOMEM; + + RUN_WITH_UMASK(0077) + if (!mkdtemp(x)) + return -errno; + + RUN_WITH_UMASK(0000) { + char *y; + + y = strappenda(x, "/tmp"); + + if (mkdir(y, 0777 | S_ISVTX) < 0) + return -errno; + } + + *path = x; + x = NULL; + + return 0; +} + +int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) { + char *a, *b; + int r; + + assert(id); + assert(tmp_dir); + assert(var_tmp_dir); + + r = setup_one_tmp_dir(id, "/tmp", &a); + if (r < 0) + return r; + + r = setup_one_tmp_dir(id, "/var/tmp", &b); + if (r < 0) { + char *t; + + t = strappenda(a, "/tmp"); + rmdir(t); + rmdir(a); + + free(a); + return r; + } + + *tmp_dir = a; + *var_tmp_dir = b; + + return 0; +} + +int setup_netns(int netns_storage_socket[2]) { + _cleanup_close_ int netns = -1; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + int r; + + assert(netns_storage_socket); + assert(netns_storage_socket[0] >= 0); + assert(netns_storage_socket[1] >= 0); + + /* We use the passed socketpair as a storage buffer for our + * namespace reference fd. Whatever process runs this first + * shall create a new namespace, all others should just join + * it. To serialize that we use a file lock on the socket + * pair. + * + * It's a bit crazy, but hey, works great! */ + + if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0) + return -errno; + + if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) { + if (errno != EAGAIN) { + r = -errno; + goto fail; + } + + /* Nothing stored yet, so let's create a new namespace */ + + if (unshare(CLONE_NEWNET) < 0) { + r = -errno; + goto fail; + } + + loopback_setup(); + + netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (netns < 0) { + r = -errno; + goto fail; + } + + r = 1; + } else { + /* Yay, found something, so let's join the namespace */ + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); + netns = *(int*) CMSG_DATA(cmsg); + } + } + + if (setns(netns, CLONE_NEWNET) < 0) { + r = -errno; + goto fail; + } + + r = 0; + } + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &netns, sizeof(int)); + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) { + r = -errno; + goto fail; + } + +fail: + lockf(netns_storage_socket[0], F_ULOCK, 0); + + return r; +} diff --git a/src/core/namespace.h b/src/core/namespace.h new file mode 100644 index 0000000..fb1fc6e --- /dev/null +++ b/src/core/namespace.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int setup_namespace(char **read_write_dirs, + char **read_only_dirs, + char **inaccessible_dirs, + char *tmp_dir, + char *var_tmp_dir, + bool private_dev, + unsigned mount_flags); + +int setup_tmp_dirs(const char *id, + char **tmp_dir, + char **var_tmp_dir); + +int setup_netns(int netns_storage_socket[2]); diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf new file mode 100644 index 0000000..a375dce --- /dev/null +++ b/src/core/org.freedesktop.systemd1.conf @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/core/org.freedesktop.systemd1.policy.in.in b/src/core/org.freedesktop.systemd1.policy.in.in new file mode 100644 index 0000000..51bdafa --- /dev/null +++ b/src/core/org.freedesktop.systemd1.policy.in.in @@ -0,0 +1,41 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Send passphrase back to system + <_message>Authentication is required to send the entered passphrase back to the system. + + no + no + auth_admin_keep + + @rootlibexecdir@/systemd-reply-password + + + + <_description>Privileged system and service manager access + <_message>Authentication is required to access the system and service manager. + + no + no + auth_admin_keep + + @bindir@/systemd-stdio-bridge + + + diff --git a/src/core/org.freedesktop.systemd1.service b/src/core/org.freedesktop.systemd1.service new file mode 100644 index 0000000..d4df3e9 --- /dev/null +++ b/src/core/org.freedesktop.systemd1.service @@ -0,0 +1,11 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.systemd1 +Exec=/bin/false +User=root diff --git a/src/core/path.c b/src/core/path.c new file mode 100644 index 0000000..1d6c6cc --- /dev/null +++ b/src/core/path.c @@ -0,0 +1,809 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "unit.h" +#include "unit-name.h" +#include "path.h" +#include "mkdir.h" +#include "dbus-path.h" +#include "special.h" +#include "path-util.h" +#include "macro.h" +#include "bus-util.h" +#include "bus-error.h" + +static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = UNIT_INACTIVE, + [PATH_WAITING] = UNIT_ACTIVE, + [PATH_RUNNING] = UNIT_ACTIVE, + [PATH_FAILED] = UNIT_FAILED +}; + +static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) { + + static const int flags_table[_PATH_TYPE_MAX] = { + [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB, + [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB, + [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO, + [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY, + [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO + }; + + bool exists = false; + char *slash, *oldslash = NULL; + int r; + + assert(s); + assert(s->unit); + assert(handler); + + path_spec_unwatch(s); + + s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (s->inotify_fd < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s); + if (r < 0) + goto fail; + + /* This assumes the path was passed through path_kill_slashes()! */ + + for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) { + char *cut = NULL; + int flags; + char tmp; + + if (slash) { + cut = slash + (slash == s->path); + tmp = *cut; + *cut = '\0'; + + flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO; + } else + flags = flags_table[s->type]; + + r = inotify_add_watch(s->inotify_fd, s->path, flags); + if (r < 0) { + if (errno == EACCES || errno == ENOENT) { + if (cut) + *cut = tmp; + break; + } + + log_warning("Failed to add watch on %s: %m", s->path); + r = -errno; + if (cut) + *cut = tmp; + goto fail; + } else { + exists = true; + + /* Path exists, we don't need to watch parent + too closely. */ + if (oldslash) { + char *cut2 = oldslash + (oldslash == s->path); + char tmp2 = *cut2; + *cut2 = '\0'; + + inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF); + /* Error is ignored, the worst can happen is + we get spurious events. */ + + *cut2 = tmp2; + } + } + + if (cut) + *cut = tmp; + + if (slash) + oldslash = slash; + else { + /* whole path has been iterated over */ + s->primary_wd = r; + break; + } + } + + if (!exists) { + log_error("Failed to add watch on any of the components of %s: %m", + s->path); + r = -errno; /* either EACCESS or ENOENT */ + goto fail; + } + + return 0; + +fail: + path_spec_unwatch(s); + return r; +} + +void path_spec_unwatch(PathSpec *s) { + assert(s); + + s->event_source = sd_event_source_unref(s->event_source); + + if (s->inotify_fd >= 0) { + close_nointr_nofail(s->inotify_fd); + s->inotify_fd = -1; + } +} + +int path_spec_fd_event(PathSpec *s, uint32_t revents) { + _cleanup_free_ uint8_t *buf = NULL; + struct inotify_event *e; + ssize_t k; + int l; + int r = 0; + + if (revents != EPOLLIN) { + log_error("Got invalid poll event on inotify."); + return -EINVAL; + } + + if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) { + log_error("FIONREAD failed: %m"); + return -errno; + } + + assert(l > 0); + + buf = malloc(l); + if (!buf) + return log_oom(); + + k = read(s->inotify_fd, buf, l); + if (k < 0) { + log_error("Failed to read inotify event: %m"); + return -errno; + } + + e = (struct inotify_event*) buf; + + while (k > 0) { + size_t step; + + if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) && + s->primary_wd == e->wd) + r = 1; + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) k); + + e = (struct inotify_event*) ((uint8_t*) e + step); + k -= step; + } + + return r; +} + +static bool path_spec_check_good(PathSpec *s, bool initial) { + bool good = false; + + switch (s->type) { + + case PATH_EXISTS: + good = access(s->path, F_OK) >= 0; + break; + + case PATH_EXISTS_GLOB: + good = glob_exists(s->path) > 0; + break; + + case PATH_DIRECTORY_NOT_EMPTY: { + int k; + + k = dir_is_empty(s->path); + good = !(k == -ENOENT || k > 0); + break; + } + + case PATH_CHANGED: + case PATH_MODIFIED: { + bool b; + + b = access(s->path, F_OK) >= 0; + good = !initial && b != s->previous_exists; + s->previous_exists = b; + break; + } + + default: + ; + } + + return good; +} + +static void path_spec_mkdir(PathSpec *s, mode_t mode) { + int r; + + if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB) + return; + + r = mkdir_p_label(s->path, mode); + if (r < 0) + log_warning("mkdir(%s) failed: %s", s->path, strerror(-r)); +} + +static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) { + fprintf(f, + "%s%s: %s\n", + prefix, + path_type_to_string(s->type), + s->path); +} + +void path_spec_done(PathSpec *s) { + assert(s); + assert(s->inotify_fd == -1); + + free(s->path); +} + +static void path_init(Unit *u) { + Path *p = PATH(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + p->directory_mode = 0755; +} + +void path_free_specs(Path *p) { + PathSpec *s; + + assert(p); + + while ((s = p->specs)) { + path_spec_unwatch(s); + LIST_REMOVE(spec, p->specs, s); + path_spec_done(s); + free(s); + } +} + +static void path_done(Unit *u) { + Path *p = PATH(u); + + assert(p); + + path_free_specs(p); +} + +static int path_add_mount_links(Path *p) { + PathSpec *s; + int r; + + assert(p); + + LIST_FOREACH(spec, s, p->specs) { + r = unit_require_mounts_for(UNIT(p), s->path); + if (r < 0) + return r; + } + + return 0; +} + +static int path_verify(Path *p) { + assert(p); + + if (UNIT(p)->load_state != UNIT_LOADED) + return 0; + + if (!p->specs) { + log_error_unit(UNIT(p)->id, + "%s lacks path setting. Refusing.", UNIT(p)->id); + return -EINVAL; + } + + return 0; +} + +static int path_add_default_dependencies(Path *p) { + int r; + + assert(p); + + r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, + SPECIAL_PATHS_TARGET, NULL, true); + if (r < 0) + return r; + + if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, + SPECIAL_SYSINIT_TARGET, NULL, true); + if (r < 0) + return r; + } + + return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, + SPECIAL_SHUTDOWN_TARGET, NULL, true); +} + +static int path_load(Unit *u) { + Path *p = PATH(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + + if (set_isempty(u->dependencies[UNIT_TRIGGERS])) { + Unit *x; + + r = unit_load_related_unit(u, ".service", &x); + if (r < 0) + return r; + + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); + if (r < 0) + return r; + } + + r = path_add_mount_links(p); + if (r < 0) + return r; + + if (UNIT(p)->default_dependencies) { + r = path_add_default_dependencies(p); + if (r < 0) + return r; + } + } + + return path_verify(p); +} + +static void path_dump(Unit *u, FILE *f, const char *prefix) { + Path *p = PATH(u); + Unit *trigger; + PathSpec *s; + + assert(p); + assert(f); + + trigger = UNIT_TRIGGER(u); + + fprintf(f, + "%sPath State: %s\n" + "%sResult: %s\n" + "%sUnit: %s\n" + "%sMakeDirectory: %s\n" + "%sDirectoryMode: %04o\n", + prefix, path_state_to_string(p->state), + prefix, path_result_to_string(p->result), + prefix, trigger ? trigger->id : "n/a", + prefix, yes_no(p->make_directory), + prefix, p->directory_mode); + + LIST_FOREACH(spec, s, p->specs) + path_spec_dump(s, f, prefix); +} + +static void path_unwatch(Path *p) { + PathSpec *s; + + assert(p); + + LIST_FOREACH(spec, s, p->specs) + path_spec_unwatch(s); +} + +static int path_watch(Path *p) { + int r; + PathSpec *s; + + assert(p); + + LIST_FOREACH(spec, s, p->specs) { + r = path_spec_watch(s, path_dispatch_io); + if (r < 0) + return r; + } + + return 0; +} + +static void path_set_state(Path *p, PathState state) { + PathState old_state; + assert(p); + + old_state = p->state; + p->state = state; + + if (state != PATH_WAITING && + (state != PATH_RUNNING || p->inotify_triggered)) + path_unwatch(p); + + if (state != old_state) + log_debug("%s changed %s -> %s", + UNIT(p)->id, + path_state_to_string(old_state), + path_state_to_string(state)); + + unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true); +} + +static void path_enter_waiting(Path *p, bool initial, bool recheck); + +static int path_coldplug(Unit *u) { + Path *p = PATH(u); + + assert(p); + assert(p->state == PATH_DEAD); + + if (p->deserialized_state != p->state) { + + if (p->deserialized_state == PATH_WAITING || + p->deserialized_state == PATH_RUNNING) + path_enter_waiting(p, true, true); + else + path_set_state(p, p->deserialized_state); + } + + return 0; +} + +static void path_enter_dead(Path *p, PathResult f) { + assert(p); + + if (f != PATH_SUCCESS) + p->result = f; + + path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD); +} + +static void path_enter_running(Path *p) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(p); + + /* Don't start job if we are supposed to go down */ + if (unit_stop_pending(UNIT(p))) + return; + + r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), + JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + + p->inotify_triggered = false; + + r = path_watch(p); + if (r < 0) + goto fail; + + path_set_state(p, PATH_RUNNING); + return; + +fail: + log_warning("%s failed to queue unit startup job: %s", + UNIT(p)->id, bus_error_message(&error, r)); + path_enter_dead(p, PATH_FAILURE_RESOURCES); +} + +static bool path_check_good(Path *p, bool initial) { + PathSpec *s; + bool good = false; + + assert(p); + + LIST_FOREACH(spec, s, p->specs) { + good = path_spec_check_good(s, initial); + + if (good) + break; + } + + return good; +} + +static void path_enter_waiting(Path *p, bool initial, bool recheck) { + int r; + + if (recheck) + if (path_check_good(p, initial)) { + log_debug("%s got triggered.", UNIT(p)->id); + path_enter_running(p); + return; + } + + r = path_watch(p); + if (r < 0) + goto fail; + + /* Hmm, so now we have created inotify watches, but the file + * might have appeared/been removed by now, so we must + * recheck */ + + if (recheck) + if (path_check_good(p, false)) { + log_debug("%s got triggered.", UNIT(p)->id); + path_enter_running(p); + return; + } + + path_set_state(p, PATH_WAITING); + return; + +fail: + log_warning("%s failed to enter waiting state: %s", + UNIT(p)->id, strerror(-r)); + path_enter_dead(p, PATH_FAILURE_RESOURCES); +} + +static void path_mkdir(Path *p) { + PathSpec *s; + + assert(p); + + if (!p->make_directory) + return; + + LIST_FOREACH(spec, s, p->specs) + path_spec_mkdir(s, p->directory_mode); +} + +static int path_start(Unit *u) { + Path *p = PATH(u); + + assert(p); + assert(p->state == PATH_DEAD || p->state == PATH_FAILED); + + if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + return -ENOENT; + + path_mkdir(p); + + p->result = PATH_SUCCESS; + path_enter_waiting(p, true, true); + + return 0; +} + +static int path_stop(Unit *u) { + Path *p = PATH(u); + + assert(p); + assert(p->state == PATH_WAITING || p->state == PATH_RUNNING); + + path_enter_dead(p, PATH_SUCCESS); + return 0; +} + +static int path_serialize(Unit *u, FILE *f, FDSet *fds) { + Path *p = PATH(u); + + assert(u); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", path_state_to_string(p->state)); + unit_serialize_item(u, f, "result", path_result_to_string(p->result)); + + return 0; +} + +static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Path *p = PATH(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + PathState state; + + state = path_state_from_string(value); + if (state < 0) + log_debug("Failed to parse state value %s", value); + else + p->deserialized_state = state; + + } else if (streq(key, "result")) { + PathResult f; + + f = path_result_from_string(value); + if (f < 0) + log_debug("Failed to parse result value %s", value); + else if (f != PATH_SUCCESS) + p->result = f; + + } else + log_debug("Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState path_active_state(Unit *u) { + assert(u); + + return state_translation_table[PATH(u)->state]; +} + +_pure_ static const char *path_sub_state_to_string(Unit *u) { + assert(u); + + return path_state_to_string(PATH(u)->state); +} + +static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + PathSpec *s = userdata; + Path *p; + int changed; + + assert(s); + assert(s->unit); + assert(fd >= 0); + + p = PATH(s->unit); + + if (p->state != PATH_WAITING && + p->state != PATH_RUNNING) + return 0; + + /* log_debug("inotify wakeup on %s.", u->id); */ + + LIST_FOREACH(spec, s, p->specs) + if (path_spec_owns_inotify_fd(s, fd)) + break; + + if (!s) { + log_error("Got event on unknown fd."); + goto fail; + } + + changed = path_spec_fd_event(s, revents); + if (changed < 0) + goto fail; + + /* If we are already running, then remember that one event was + * dispatched so that we restart the service only if something + * actually changed on disk */ + p->inotify_triggered = true; + + if (changed) + path_enter_running(p); + else + path_enter_waiting(p, false, true); + + return 0; + +fail: + path_enter_dead(p, PATH_FAILURE_RESOURCES); + return 0; +} + +static void path_trigger_notify(Unit *u, Unit *other) { + Path *p = PATH(u); + + assert(u); + assert(other); + + /* Invoked whenever the unit we trigger changes state or gains + * or loses a job */ + + if (other->load_state != UNIT_LOADED) + return; + + if (p->state == PATH_RUNNING && + UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { + log_debug_unit(UNIT(p)->id, + "%s got notified about unit deactivation.", + UNIT(p)->id); + + /* Hmm, so inotify was triggered since the + * last activation, so I guess we need to + * recheck what is going on. */ + path_enter_waiting(p, false, p->inotify_triggered); + } +} + +static void path_reset_failed(Unit *u) { + Path *p = PATH(u); + + assert(p); + + if (p->state == PATH_FAILED) + path_set_state(p, PATH_DEAD); + + p->result = PATH_SUCCESS; +} + +static const char* const path_state_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = "dead", + [PATH_WAITING] = "waiting", + [PATH_RUNNING] = "running", + [PATH_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); + +static const char* const path_type_table[_PATH_TYPE_MAX] = { + [PATH_EXISTS] = "PathExists", + [PATH_EXISTS_GLOB] = "PathExistsGlob", + [PATH_CHANGED] = "PathChanged", + [PATH_MODIFIED] = "PathModified", + [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); + +static const char* const path_result_table[_PATH_RESULT_MAX] = { + [PATH_SUCCESS] = "success", + [PATH_FAILURE_RESOURCES] = "resources" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); + +const UnitVTable path_vtable = { + .object_size = sizeof(Path), + + .sections = + "Unit\0" + "Path\0" + "Install\0", + + .init = path_init, + .done = path_done, + .load = path_load, + + .coldplug = path_coldplug, + + .dump = path_dump, + + .start = path_start, + .stop = path_stop, + + .serialize = path_serialize, + .deserialize_item = path_deserialize_item, + + .active_state = path_active_state, + .sub_state_to_string = path_sub_state_to_string, + + .trigger_notify = path_trigger_notify, + + .reset_failed = path_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.Path", + .bus_vtable = bus_path_vtable +}; diff --git a/src/core/path.h b/src/core/path.h new file mode 100644 index 0000000..d2e91d7 --- /dev/null +++ b/src/core/path.h @@ -0,0 +1,106 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Path Path; + +#include "unit.h" +#include "mount.h" + +typedef enum PathState { + PATH_DEAD, + PATH_WAITING, + PATH_RUNNING, + PATH_FAILED, + _PATH_STATE_MAX, + _PATH_STATE_INVALID = -1 +} PathState; + +typedef enum PathType { + PATH_EXISTS, + PATH_EXISTS_GLOB, + PATH_DIRECTORY_NOT_EMPTY, + PATH_CHANGED, + PATH_MODIFIED, + _PATH_TYPE_MAX, + _PATH_TYPE_INVALID = -1 +} PathType; + +typedef struct PathSpec { + Unit *unit; + + char *path; + + sd_event_source *event_source; + + LIST_FIELDS(struct PathSpec, spec); + + PathType type; + int inotify_fd; + int primary_wd; + + bool previous_exists; +} PathSpec; + +int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler); +void path_spec_unwatch(PathSpec *s); +int path_spec_fd_event(PathSpec *s, uint32_t events); +void path_spec_done(PathSpec *s); + +static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) { + return s->inotify_fd == fd; +} + +typedef enum PathResult { + PATH_SUCCESS, + PATH_FAILURE_RESOURCES, + _PATH_RESULT_MAX, + _PATH_RESULT_INVALID = -1 +} PathResult; + +struct Path { + Unit meta; + + LIST_HEAD(PathSpec, specs); + + PathState state, deserialized_state; + + bool inotify_triggered; + + bool make_directory; + mode_t directory_mode; + + PathResult result; +}; + +void path_free_specs(Path *p); + +extern const UnitVTable path_vtable; + +const char* path_state_to_string(PathState i) _const_; +PathState path_state_from_string(const char *s) _pure_; + +const char* path_type_to_string(PathType i) _const_; +PathType path_type_from_string(const char *s) _pure_; + +const char* path_result_to_string(PathResult i) _const_; +PathResult path_result_from_string(const char *s) _pure_; diff --git a/src/core/scope.c b/src/core/scope.c new file mode 100644 index 0000000..16758fe --- /dev/null +++ b/src/core/scope.c @@ -0,0 +1,563 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "unit.h" +#include "scope.h" +#include "load-fragment.h" +#include "log.h" +#include "dbus-scope.h" +#include "special.h" +#include "unit-name.h" +#include "load-dropin.h" + +static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = UNIT_INACTIVE, + [SCOPE_RUNNING] = UNIT_ACTIVE, + [SCOPE_ABANDONED] = UNIT_ACTIVE, + [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING, + [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING, + [SCOPE_FAILED] = UNIT_FAILED +}; + +static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + +static void scope_init(Unit *u) { + Scope *s = SCOPE(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + s->timeout_stop_usec = u->manager->default_timeout_stop_usec; + + cgroup_context_init(&s->cgroup_context); + kill_context_init(&s->kill_context); + + UNIT(s)->ignore_on_isolate = true; + UNIT(s)->ignore_on_snapshot = true; +} + +static void scope_done(Unit *u) { + Scope *s = SCOPE(u); + + assert(u); + + cgroup_context_done(&s->cgroup_context); + + free(s->controller); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int scope_arm_timer(Scope *s) { + int r; + + assert(s); + + if (s->timeout_stop_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0, scope_dispatch_timer, s); +} + +static void scope_set_state(Scope *s, ScopeState state) { + ScopeState old_state; + assert(s); + + old_state = s->state; + s->state = state; + + if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL)) + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED)) + unit_unwatch_all_pids(UNIT(s)); + + if (state != old_state) + log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state)); + + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); +} + +static int scope_add_default_dependencies(Scope *s) { + int r; + + assert(s); + + /* Make sure scopes are unloaded on shutdown */ + r = unit_add_two_dependencies_by_name( + UNIT(s), + UNIT_BEFORE, UNIT_CONFLICTS, + SPECIAL_SHUTDOWN_TARGET, NULL, true); + if (r < 0) + return r; + + return 0; +} + +static int scope_verify(Scope *s) { + assert(s); + + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + + if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) { + log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + return 0; +} + +static int scope_load(Unit *u) { + Scope *s = SCOPE(u); + int r; + + assert(s); + assert(u->load_state == UNIT_STUB); + + if (!u->transient && UNIT(s)->manager->n_reloading <= 0) + return -ENOENT; + + u->load_state = UNIT_LOADED; + + r = unit_load_dropin(u); + if (r < 0) + return r; + + r = unit_add_default_slice(u); + if (r < 0) + return r; + + if (u->default_dependencies) { + r = scope_add_default_dependencies(s); + if (r < 0) + return r; + } + + return scope_verify(s); +} + +static int scope_coldplug(Unit *u) { + Scope *s = SCOPE(u); + int r; + + assert(s); + assert(s->state == SCOPE_DEAD); + + if (s->deserialized_state != s->state) { + + if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) { + r = scope_arm_timer(s); + if (r < 0) + return r; + } + + if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED)) + unit_watch_all_pids(UNIT(s)); + + scope_set_state(s, s->deserialized_state); + } + + return 0; +} + +static void scope_dump(Unit *u, FILE *f, const char *prefix) { + Scope *s = SCOPE(u); + + assert(s); + assert(f); + + fprintf(f, + "%sScope State: %s\n" + "%sResult: %s\n", + prefix, scope_state_to_string(s->state), + prefix, scope_result_to_string(s->result)); + + cgroup_context_dump(&s->cgroup_context, f, prefix); + kill_context_dump(&s->kill_context, f, prefix); +} + +static void scope_enter_dead(Scope *s, ScopeResult f) { + assert(s); + + if (f != SCOPE_SUCCESS) + s->result = f; + + scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD); +} + +static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { + bool skip_signal = false; + int r; + + assert(s); + + if (f != SCOPE_SUCCESS) + s->result = f; + + unit_watch_all_pids(UNIT(s)); + + /* If we have a controller set let's ask the controller nicely + * to terminate the scope, instead of us going directly into + * SIGTERM beserk mode */ + if (state == SCOPE_STOP_SIGTERM) + skip_signal = bus_scope_send_request_stop(s) > 0; + + if (!skip_signal) { + r = unit_kill_context( + UNIT(s), + &s->kill_context, + state != SCOPE_STOP_SIGTERM, + -1, -1, false); + if (r < 0) + goto fail; + } else + r = 1; + + if (r > 0) { + r = scope_arm_timer(s); + if (r < 0) + goto fail; + + scope_set_state(s, state); + } else if (state == SCOPE_STOP_SIGTERM) + scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS); + else + scope_enter_dead(s, SCOPE_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); + + scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); +} + +static int scope_start(Unit *u) { + Scope *s = SCOPE(u); + int r; + + assert(s); + + if (s->state == SCOPE_FAILED) + return -EPERM; + + if (s->state == SCOPE_STOP_SIGTERM || + s->state == SCOPE_STOP_SIGKILL) + return -EAGAIN; + + assert(s->state == SCOPE_DEAD); + + if (!u->transient && UNIT(s)->manager->n_reloading <= 0) + return -ENOENT; + + r = unit_realize_cgroup(u); + if (r < 0) { + log_error("Failed to realize cgroup: %s", strerror(-r)); + return r; + } + + r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, UNIT(s)->pids); + if (r < 0) + return r; + + s->result = SCOPE_SUCCESS; + + scope_set_state(s, SCOPE_RUNNING); + return 0; +} + +static int scope_stop(Unit *u) { + Scope *s = SCOPE(u); + + assert(s); + + if (s->state == SCOPE_STOP_SIGTERM || + s->state == SCOPE_STOP_SIGKILL) + return 0; + + assert(s->state == SCOPE_RUNNING || + s->state == SCOPE_ABANDONED); + + scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS); + return 0; +} + +static void scope_reset_failed(Unit *u) { + Scope *s = SCOPE(u); + + assert(s); + + if (s->state == SCOPE_FAILED) + scope_set_state(s, SCOPE_DEAD); + + s->result = SCOPE_SUCCESS; +} + +static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, -1, error); +} + +static int scope_get_timeout(Unit *u, uint64_t *timeout) { + Scope *s = SCOPE(u); + int r; + + if (!s->timer_event_source) + return 0; + + r = sd_event_source_get_time(s->timer_event_source, timeout); + if (r < 0) + return r; + + return 1; +} + +static int scope_serialize(Unit *u, FILE *f, FDSet *fds) { + Scope *s = SCOPE(u); + + assert(s); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", scope_state_to_string(s->state)); + return 0; +} + +static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Scope *s = SCOPE(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + ScopeState state; + + state = scope_state_from_string(value); + if (state < 0) + log_debug("Failed to parse state value %s", value); + else + s->deserialized_state = state; + + } else + log_debug("Unknown serialization key '%s'", key); + + return 0; +} + +static bool scope_check_gc(Unit *u) { + Scope *s = SCOPE(u); + int r; + + assert(s); + + /* Never clean up scopes that still have a process around, + * even if the scope is formally dead. */ + + if (u->cgroup_path) { + r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); + if (r <= 0) + return true; + } + + return false; +} + +static void scope_notify_cgroup_empty_event(Unit *u) { + Scope *s = SCOPE(u); + assert(u); + + log_debug_unit(u->id, "%s: cgroup is empty", u->id); + + if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL)) + scope_enter_dead(s, SCOPE_SUCCESS); +} + +static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) { + + /* 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. */ + + unit_tidy_watch_pids(u, 0, 0); + unit_watch_all_pids(u); + + /* If the PID set is empty now, then let's finish this off */ + if (set_isempty(u->pids)) + scope_notify_cgroup_empty_event(u); +} + +static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Scope *s = SCOPE(userdata); + + assert(s); + assert(s->timer_event_source == source); + + switch (s->state) { + + case SCOPE_STOP_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id); + scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id); + scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT); + } + + break; + + case SCOPE_STOP_SIGKILL: + log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); + scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +int scope_abandon(Scope *s) { + assert(s); + + if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED)) + return -ESTALE; + + free(s->controller); + s->controller = NULL; + + /* The client is no longer watching the remaining processes, + * so let's step in here, under the assumption that the + * remaining processes will be sooner or later reassigned to + * us as parent. */ + + unit_tidy_watch_pids(UNIT(s), 0, 0); + unit_watch_all_pids(UNIT(s)); + + /* If the PID set is empty now, then let's finish this off */ + if (set_isempty(UNIT(s)->pids)) + scope_notify_cgroup_empty_event(UNIT(s)); + else + scope_set_state(s, SCOPE_ABANDONED); + + return 0; +} + +_pure_ static UnitActiveState scope_active_state(Unit *u) { + assert(u); + + return state_translation_table[SCOPE(u)->state]; +} + +_pure_ static const char *scope_sub_state_to_string(Unit *u) { + assert(u); + + return scope_state_to_string(SCOPE(u)->state); +} + +static const char* const scope_state_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = "dead", + [SCOPE_RUNNING] = "running", + [SCOPE_ABANDONED] = "abandoned", + [SCOPE_STOP_SIGTERM] = "stop-sigterm", + [SCOPE_STOP_SIGKILL] = "stop-sigkill", + [SCOPE_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); + +static const char* const scope_result_table[_SCOPE_RESULT_MAX] = { + [SCOPE_SUCCESS] = "success", + [SCOPE_FAILURE_RESOURCES] = "resources", + [SCOPE_FAILURE_TIMEOUT] = "timeout", +}; + +DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult); + +const UnitVTable scope_vtable = { + .object_size = sizeof(Scope), + .cgroup_context_offset = offsetof(Scope, cgroup_context), + .kill_context_offset = offsetof(Scope, kill_context), + + .sections = + "Unit\0" + "Scope\0" + "Install\0", + .private_section = "Scope", + + .no_alias = true, + .no_instances = true, + + .init = scope_init, + .load = scope_load, + .done = scope_done, + + .coldplug = scope_coldplug, + + .dump = scope_dump, + + .start = scope_start, + .stop = scope_stop, + + .kill = scope_kill, + + .get_timeout = scope_get_timeout, + + .serialize = scope_serialize, + .deserialize_item = scope_deserialize_item, + + .active_state = scope_active_state, + .sub_state_to_string = scope_sub_state_to_string, + + .check_gc = scope_check_gc, + + .sigchld_event = scope_sigchld_event, + + .reset_failed = scope_reset_failed, + + .notify_cgroup_empty = scope_notify_cgroup_empty_event, + + .bus_interface = "org.freedesktop.systemd1.Scope", + .bus_vtable = bus_scope_vtable, + .bus_set_property = bus_scope_set_property, + .bus_commit_properties = bus_scope_commit_properties, + + .can_transient = true +}; diff --git a/src/core/scope.h b/src/core/scope.h new file mode 100644 index 0000000..6c59126 --- /dev/null +++ b/src/core/scope.h @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Scope Scope; + +#include "unit.h" +#include "kill.h" + +typedef enum ScopeState { + SCOPE_DEAD, + SCOPE_RUNNING, + SCOPE_ABANDONED, + SCOPE_STOP_SIGTERM, + SCOPE_STOP_SIGKILL, + SCOPE_FAILED, + _SCOPE_STATE_MAX, + _SCOPE_STATE_INVALID = -1 +} ScopeState; + +typedef enum ScopeResult { + SCOPE_SUCCESS, + SCOPE_FAILURE_RESOURCES, + SCOPE_FAILURE_TIMEOUT, + _SCOPE_RESULT_MAX, + _SCOPE_RESULT_INVALID = -1 +} ScopeResult; + +struct Scope { + Unit meta; + + CGroupContext cgroup_context; + KillContext kill_context; + + ScopeState state, deserialized_state; + ScopeResult result; + + usec_t timeout_stop_usec; + + char *controller; + + sd_event_source *timer_event_source; +}; + +extern const UnitVTable scope_vtable; + +int scope_abandon(Scope *s); + +const char* scope_state_to_string(ScopeState i) _const_; +ScopeState scope_state_from_string(const char *s) _pure_; + +const char* scope_result_to_string(ScopeResult i) _const_; +ScopeResult scope_result_from_string(const char *s) _pure_; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c new file mode 100644 index 0000000..21c7a8c --- /dev/null +++ b/src/core/selinux-access.c @@ -0,0 +1,270 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Dan Walsh + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "selinux-access.h" + +#ifdef HAVE_SELINUX + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_AUDIT +#include +#endif + +#include "sd-bus.h" +#include "bus-util.h" +#include "util.h" +#include "log.h" +#include "audit.h" +#include "selinux-util.h" +#include "audit-fd.h" +#include "strv.h" + +static bool initialized = false; + +struct audit_info { + sd_bus_creds *creds; + const char *path; + const char *cmdline; +}; + +/* + Any time an access gets denied this callback will be called + with the aduit data. We then need to just copy the audit data into the msgbuf. +*/ +static int audit_callback( + void *auditdata, + security_class_t cls, + char *msgbuf, + size_t msgbufsize) { + + const struct audit_info *audit = auditdata; + uid_t uid = 0, login_uid = 0; + gid_t gid = 0; + + sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid); + sd_bus_creds_get_uid(audit->creds, &uid); + sd_bus_creds_get_gid(audit->creds, &gid); + + snprintf(msgbuf, msgbufsize, + "auid=%d uid=%d gid=%d%s%s%s%s%s%s", + login_uid, uid, gid, + audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "", + audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : ""); + + msgbuf[msgbufsize-1] = 0; + + return 0; +} + +/* + Any time an access gets denied this callback will be called + code copied from dbus. If audit is turned on the messages will go as + user_avc's into the /var/log/audit/audit.log, otherwise they will be + sent to syslog. +*/ +_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { + va_list ap; + +#ifdef HAVE_AUDIT + if (get_audit_fd() >= 0) { + _cleanup_free_ char *buf = NULL; + int r; + + va_start(ap, fmt); + r = vasprintf(&buf, fmt, ap); + va_end(ap); + + if (r >= 0) { + audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0); + return 0; + } + } +#endif + + va_start(ap, fmt); + log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap); + va_end(ap); + + return 0; +} + +/* + Function must be called once to initialize the SELinux AVC environment. + Sets up callbacks. + If you want to cleanup memory you should need to call selinux_access_finish. +*/ +static int access_init(void) { + int r = 0; + + if (avc_open(NULL, 0)) { + log_error("avc_open() failed: %m"); + return -errno; + } + + selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); + selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); + + if (security_getenforce() < 0){ + r = -errno; + avc_destroy(); + } + + return r; +} + +static int selinux_access_init(sd_bus_error *error) { + int r; + + if (initialized) + return 0; + + if (!use_selinux()) + return 0; + + r = access_init(); + if (r < 0) + return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux."); + + initialized = true; + return 0; +} + +void selinux_access_free(void) { + + if (!initialized) + return; + + avc_destroy(); + initialized = false; +} + +/* + This function communicates with the kernel to check whether or not it should + allow the access. + If the machine is in permissive mode it will return ok. Audit messages will + still be generated if the access would be denied in enforcing mode. +*/ +int selinux_generic_access_check( + sd_bus *bus, + sd_bus_message *message, + const char *path, + const char *permission, + sd_bus_error *error) { + + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + const char *tclass = NULL, *scon = NULL; + struct audit_info audit_info = {}; + _cleanup_free_ char *cl = NULL; + security_context_t fcon = NULL; + char **cmdline = NULL; + int r = 0; + + assert(bus); + assert(message); + assert(permission); + assert(error); + + if (!use_selinux()) + return 0; + + r = selinux_access_init(error); + if (r < 0) + return r; + + r = sd_bus_query_sender_creds( + message, + SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID| + SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID| + SD_BUS_CREDS_SELINUX_CONTEXT, + &creds); + if (r < 0) + goto finish; + + r = sd_bus_creds_get_selinux_context(creds, &scon); + if (r < 0) + goto finish; + + if (path) { + /* Get the file context of the unit file */ + + r = getfilecon(path, &fcon); + if (r < 0) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); + goto finish; + } + + tclass = "service"; + } else { + r = getcon(&fcon); + if (r < 0) { + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); + goto finish; + } + + tclass = "system"; + } + + sd_bus_creds_get_cmdline(creds, &cmdline); + cl = strv_join(cmdline, " "); + + audit_info.creds = creds; + audit_info.path = path; + audit_info.cmdline = cl; + + r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info); + if (r < 0) + r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); + + log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r); + +finish: + freecon(fcon); + + if (r < 0 && security_getenforce() != 1) { + sd_bus_error_free(error); + r = 0; + } + + return r; +} + +#else + +int selinux_generic_access_check( + sd_bus *bus, + sd_bus_message *message, + const char *path, + const char *permission, + sd_bus_error *error) { + + return 0; +} + +void selinux_access_free(void) { +} + +#endif diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h new file mode 100644 index 0000000..9e89064 --- /dev/null +++ b/src/core/selinux-access.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Dan Walsh + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-util.h" + +void selinux_access_free(void); + +int selinux_generic_access_check(sd_bus *bus, sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error); + +#ifdef HAVE_SELINUX + +#define selinux_access_check(bus, message, permission, error) \ + selinux_generic_access_check(bus, message, NULL, permission, error) +#define selinux_unit_access_check(unit, bus, message, permission, error) \ + ({ Unit *_unit = (unit); selinux_generic_access_check(bus, message, _unit->fragment_path ?: _unit->fragment_path, permission, error); }) + +#else + +#define selinux_access_check(bus, message, permission, error) 0 +#define selinux_unit_access_check(unit, bus, message, permission, error) 0 + +#endif diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c new file mode 100644 index 0000000..9a5d6b2 --- /dev/null +++ b/src/core/selinux-setup.c @@ -0,0 +1,127 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#ifdef HAVE_SELINUX +#include +#endif + +#include "selinux-setup.h" +#include "selinux-util.h" +#include "label.h" +#include "mount-setup.h" +#include "macro.h" +#include "util.h" +#include "log.h" + +#ifdef HAVE_SELINUX +static int null_log(int type, const char *fmt, ...) { + return 0; +} +#endif + +int selinux_setup(bool *loaded_policy) { + +#ifdef HAVE_SELINUX + int enforce = 0; + usec_t before_load, after_load; + security_context_t con; + int r; + union selinux_callback cb; + + assert(loaded_policy); + + /* Turn off all of SELinux' own logging, we want to do that */ + cb.func_log = null_log; + selinux_set_callback(SELINUX_CB_LOG, cb); + + /* Don't load policy in the initrd if we don't appear to have + * it. For the real root, we check below if we've already + * loaded policy, and return gracefully. + */ + if (in_initrd() && access(selinux_path(), F_OK) < 0) + return 0; + + /* Already initialized by somebody else? */ + r = getcon_raw(&con); + if (r == 0) { + bool initialized; + + initialized = !streq(con, "kernel"); + freecon(con); + + if (initialized) + return 0; + } + + /* Make sure we have no fds open while loading the policy and + * transitioning */ + log_close(); + + /* Now load the policy */ + before_load = now(CLOCK_MONOTONIC); + r = selinux_init_load_policy(&enforce); + if (r == 0) { + char timespan[FORMAT_TIMESPAN_MAX]; + char *label; + + retest_selinux(); + + /* Transition to the new context */ + r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); + if (r < 0 || label == NULL) { + log_open(); + log_error("Failed to compute init label, ignoring."); + } else { + r = setcon(label); + + log_open(); + if (r < 0) + log_error("Failed to transition into init label '%s', ignoring.", label); + + label_free(label); + } + + after_load = now(CLOCK_MONOTONIC); + + log_info("Successfully loaded SELinux policy in %s.", + format_timespan(timespan, sizeof(timespan), after_load - before_load, 0)); + + *loaded_policy = true; + + } else { + log_open(); + + if (enforce > 0) { + log_error("Failed to load SELinux policy. Freezing."); + return -EIO; + } else + log_debug("Unable to load SELinux policy. Ignoring."); + } +#endif + + return 0; +} diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h new file mode 100644 index 0000000..39e2bc2 --- /dev/null +++ b/src/core/selinux-setup.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int selinux_setup(bool *loaded_policy); diff --git a/src/core/service.c b/src/core/service.c new file mode 100644 index 0000000..242f3f9 --- /dev/null +++ b/src/core/service.c @@ -0,0 +1,3937 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "manager.h" +#include "unit.h" +#include "service.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "log.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "dbus-service.h" +#include "special.h" +#include "exit-status.h" +#include "def.h" +#include "path-util.h" +#include "util.h" +#include "utf8.h" +#include "env-util.h" +#include "fileio.h" +#include "bus-error.h" +#include "bus-util.h" + +#ifdef HAVE_SYSV_COMPAT + +#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE) + +typedef enum RunlevelType { + RUNLEVEL_UP, + RUNLEVEL_DOWN +} RunlevelType; + +static const struct { + const char *path; + const char *target; + const RunlevelType type; +} rcnd_table[] = { + /* Standard SysV runlevels for start-up */ + { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP }, + { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP }, + { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP }, + { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP }, + { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP }, + + /* Standard SysV runlevels for shutdown */ + { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN }, + { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN } + + /* Note that the order here matters, as we read the + directories in this order, and we want to make sure that + sysv_start_priority is known when we first load the + unit. And that value we only know from S links. Hence + UP must be read before DOWN */ +}; + +#define RUNLEVELS_UP "12345" +#endif + +static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = UNIT_INACTIVE, + [SERVICE_START_PRE] = UNIT_ACTIVATING, + [SERVICE_START] = UNIT_ACTIVATING, + [SERVICE_START_POST] = UNIT_ACTIVATING, + [SERVICE_RUNNING] = UNIT_ACTIVE, + [SERVICE_EXITED] = UNIT_ACTIVE, + [SERVICE_RELOAD] = UNIT_RELOADING, + [SERVICE_STOP] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_STOP_POST] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_FAILED] = UNIT_FAILED, + [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING +}; + +/* For Type=idle we never want to delay any other jobs, hence we + * consider idle jobs active as soon as we start working on them */ +static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = UNIT_INACTIVE, + [SERVICE_START_PRE] = UNIT_ACTIVE, + [SERVICE_START] = UNIT_ACTIVE, + [SERVICE_START_POST] = UNIT_ACTIVE, + [SERVICE_RUNNING] = UNIT_ACTIVE, + [SERVICE_EXITED] = UNIT_ACTIVE, + [SERVICE_RELOAD] = UNIT_RELOADING, + [SERVICE_STOP] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_STOP_POST] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, + [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, + [SERVICE_FAILED] = UNIT_FAILED, + [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING +}; + +static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata); +static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata); + +static void service_enter_signal(Service *s, ServiceState state, ServiceResult f); + +static void service_init(Unit *u) { + Service *s = SERVICE(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + s->timeout_start_usec = u->manager->default_timeout_start_usec; + s->timeout_stop_usec = u->manager->default_timeout_stop_usec; + s->restart_usec = u->manager->default_restart_usec; + s->type = _SERVICE_TYPE_INVALID; + +#ifdef HAVE_SYSV_COMPAT + s->sysv_start_priority = -1; + s->sysv_start_priority_from_rcnd = -1; +#endif + s->socket_fd = -1; + s->guess_main_pid = true; + + exec_context_init(&s->exec_context); + kill_context_init(&s->kill_context); + cgroup_context_init(&s->cgroup_context); + + RATELIMIT_INIT(s->start_limit, + u->manager->default_start_limit_interval, + u->manager->default_start_limit_burst); + + s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; +} + +static void service_unwatch_control_pid(Service *s) { + assert(s); + + if (s->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(s), s->control_pid); + s->control_pid = 0; +} + +static void service_unwatch_main_pid(Service *s) { + assert(s); + + if (s->main_pid <= 0) + return; + + unit_unwatch_pid(UNIT(s), s->main_pid); + s->main_pid = 0; +} + +static void service_unwatch_pid_file(Service *s) { + if (!s->pid_file_pathspec) + return; + + log_debug_unit(UNIT(s)->id, "Stopping watch for %s's PID file %s", + UNIT(s)->id, s->pid_file_pathspec->path); + path_spec_unwatch(s->pid_file_pathspec); + path_spec_done(s->pid_file_pathspec); + free(s->pid_file_pathspec); + s->pid_file_pathspec = NULL; +} + +static int service_set_main_pid(Service *s, pid_t pid) { + pid_t ppid; + + assert(s); + + if (pid <= 1) + return -EINVAL; + + if (pid == getpid()) + return -EINVAL; + + if (s->main_pid == pid && s->main_pid_known) + return 0; + + if (s->main_pid != pid) { + service_unwatch_main_pid(s); + exec_status_start(&s->main_exec_status, pid); + } + + s->main_pid = pid; + s->main_pid_known = true; + + if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { + log_warning_unit(UNIT(s)->id, + "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", + UNIT(s)->id, pid); + + s->main_pid_alien = true; + } else + s->main_pid_alien = false; + + return 0; +} + +static void service_close_socket_fd(Service *s) { + assert(s); + + if (s->socket_fd < 0) + return; + + close_nointr_nofail(s->socket_fd); + s->socket_fd = -1; +} + +static void service_connection_unref(Service *s) { + assert(s); + + if (!UNIT_ISSET(s->accept_socket)) + return; + + socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); + unit_ref_unset(&s->accept_socket); +} + +static void service_stop_watchdog(Service *s) { + assert(s); + + s->watchdog_event_source = sd_event_source_unref(s->watchdog_event_source); + s->watchdog_timestamp = DUAL_TIMESTAMP_NULL; +} + +static void service_start_watchdog(Service *s) { + int r; + + assert(s); + + if (s->watchdog_usec <= 0) + return; + + if (s->watchdog_event_source) { + r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to reset watchdog timer: %s", UNIT(s)->id, strerror(-r)); + return; + } + + r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ONESHOT); + } else { + r = sd_event_add_monotonic(UNIT(s)->manager->event, &s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec, 0, service_dispatch_watchdog, s); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to add watchdog timer: %s", UNIT(s)->id, strerror(-r)); + return; + } + + /* Let's process everything else which might be a sign + * of living before we consider a service died. */ + r = sd_event_source_set_priority(s->watchdog_event_source, SD_EVENT_PRIORITY_IDLE); + } + + if (r < 0) + log_warning_unit(UNIT(s)->id, "%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r)); +} + +static void service_reset_watchdog(Service *s) { + assert(s); + + dual_timestamp_get(&s->watchdog_timestamp); + service_start_watchdog(s); +} + +static void service_done(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + free(s->pid_file); + s->pid_file = NULL; + +#ifdef HAVE_SYSV_COMPAT + free(s->sysv_runlevels); + s->sysv_runlevels = NULL; +#endif + + free(s->status_text); + s->status_text = NULL; + + cgroup_context_done(&s->cgroup_context); + exec_context_done(&s->exec_context); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX); + s->control_command = NULL; + s->main_command = NULL; + + set_free(s->restart_ignore_status.code); + s->restart_ignore_status.code = NULL; + set_free(s->restart_ignore_status.signal); + s->restart_ignore_status.signal = NULL; + + set_free(s->success_status.code); + s->success_status.code = NULL; + set_free(s->success_status.signal); + s->success_status.signal = NULL; + + /* This will leak a process, but at least no memory or any of + * our resources */ + service_unwatch_main_pid(s); + service_unwatch_control_pid(s); + service_unwatch_pid_file(s); + + if (s->bus_name) { + unit_unwatch_bus_name(u, s->bus_name); + free(s->bus_name); + s->bus_name = NULL; + } + + service_close_socket_fd(s); + service_connection_unref(s); + + unit_ref_unset(&s->accept_socket); + + service_stop_watchdog(s); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int service_arm_timer(Service *s, usec_t usec) { + int r; + + assert(s); + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + usec, 0, service_dispatch_timer, s); +} + +#ifdef HAVE_SYSV_COMPAT +static char *sysv_translate_name(const char *name) { + char *r; + + r = new(char, strlen(name) + sizeof(".service")); + if (!r) + return NULL; + + if (endswith(name, ".sh")) + /* Drop .sh suffix */ + strcpy(stpcpy(r, name) - 3, ".service"); + else + /* Normal init script name */ + strcpy(stpcpy(r, name), ".service"); + + return r; +} + +static int sysv_translate_facility(const char *name, const char *filename, char **_r) { + + /* We silently ignore the $ prefix here. According to the LSB + * spec it simply indicates whether something is a + * standardized name or a distribution-specific one. Since we + * just follow what already exists and do not introduce new + * uses or names we don't care who introduced a new name. */ + + static const char * const table[] = { + /* LSB defined facilities */ + "local_fs", NULL, + "network", SPECIAL_NETWORK_TARGET, + "named", SPECIAL_NSS_LOOKUP_TARGET, + "portmap", SPECIAL_RPCBIND_TARGET, + "remote_fs", SPECIAL_REMOTE_FS_TARGET, + "syslog", NULL, + "time", SPECIAL_TIME_SYNC_TARGET, + }; + + unsigned i; + char *r; + const char *n; + + assert(name); + assert(_r); + + n = *name == '$' ? name + 1 : name; + + for (i = 0; i < ELEMENTSOF(table); i += 2) { + + if (!streq(table[i], n)) + continue; + + if (!table[i+1]) + return 0; + + r = strdup(table[i+1]); + if (!r) + return log_oom(); + + goto finish; + } + + /* If we don't know this name, fallback heuristics to figure + * out whether something is a target or a service alias. */ + + if (*name == '$') { + if (!unit_prefix_is_valid(n)) + return -EINVAL; + + /* Facilities starting with $ are most likely targets */ + r = unit_name_build(n, NULL, ".target"); + } else if (filename && streq(name, filename)) + /* Names equaling the file name of the services are redundant */ + return 0; + else + /* Everything else we assume to be normal service names */ + r = sysv_translate_name(n); + + if (!r) + return -ENOMEM; + +finish: + *_r = r; + + return 1; +} + +static int sysv_fix_order(Service *s) { + Unit *other; + int r; + + assert(s); + + if (s->sysv_start_priority < 0) + return 0; + + /* For each pair of services where at least one lacks a LSB + * header, we use the start priority value to order things. */ + + LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) { + Service *t; + UnitDependency d; + bool special_s, special_t; + + t = SERVICE(other); + + if (s == t) + continue; + + if (UNIT(t)->load_state != UNIT_LOADED) + continue; + + if (t->sysv_start_priority < 0) + continue; + + /* If both units have modern headers we don't care + * about the priorities */ + if ((UNIT(s)->fragment_path || s->sysv_has_lsb) && + (UNIT(t)->fragment_path || t->sysv_has_lsb)) + continue; + + special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels); + special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels); + + if (special_t && !special_s) + d = UNIT_AFTER; + else if (special_s && !special_t) + d = UNIT_BEFORE; + else if (t->sysv_start_priority < s->sysv_start_priority) + d = UNIT_AFTER; + else if (t->sysv_start_priority > s->sysv_start_priority) + d = UNIT_BEFORE; + else + continue; + + /* FIXME: Maybe we should compare the name here lexicographically? */ + + if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) + return r; + } + + return 0; +} + +static ExecCommand *exec_command_new(const char *path, const char *arg1) { + ExecCommand *c; + + if (!(c = new0(ExecCommand, 1))) + return NULL; + + if (!(c->path = strdup(path))) { + free(c); + return NULL; + } + + if (!(c->argv = strv_new(path, arg1, NULL))) { + free(c->path); + free(c); + return NULL; + } + + return c; +} + +static int sysv_exec_commands(Service *s, const bool supports_reload) { + ExecCommand *c; + + assert(s); + assert(s->is_sysv); + assert(UNIT(s)->source_path); + + c = exec_command_new(UNIT(s)->source_path, "start"); + if (!c) + return -ENOMEM; + exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c); + + c = exec_command_new(UNIT(s)->source_path, "stop"); + if (!c) + return -ENOMEM; + exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c); + + if (supports_reload) { + c = exec_command_new(UNIT(s)->source_path, "reload"); + if (!c) + return -ENOMEM; + exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c); + } + + return 0; +} + +static bool usage_contains_reload(const char *line) { + return (strcasestr(line, "{reload|") || + strcasestr(line, "{reload}") || + strcasestr(line, "{reload\"") || + strcasestr(line, "|reload|") || + strcasestr(line, "|reload}") || + strcasestr(line, "|reload\"")); +} + +static int service_load_sysv_path(Service *s, const char *path) { + FILE *f; + Unit *u; + unsigned line = 0; + int r; + enum { + NORMAL, + DESCRIPTION, + LSB, + LSB_DESCRIPTION, + USAGE_CONTINUATION + } state = NORMAL; + char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description; + struct stat st; + bool supports_reload = false; + + assert(s); + assert(path); + + u = UNIT(s); + + f = fopen(path, "re"); + if (!f) { + r = errno == ENOENT ? 0 : -errno; + goto finish; + } + + if (fstat(fileno(f), &st) < 0) { + r = -errno; + goto finish; + } + + free(u->source_path); + u->source_path = strdup(path); + if (!u->source_path) { + r = -ENOMEM; + goto finish; + } + u->source_mtime = timespec_load(&st.st_mtim); + + if (null_or_empty(&st)) { + u->load_state = UNIT_MASKED; + r = 0; + goto finish; + } + + s->is_sysv = true; + + while (!feof(f)) { + char l[LINE_MAX], *t; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + r = -errno; + log_error_unit(u->id, + "Failed to read configuration file '%s': %s", + path, strerror(-r)); + goto finish; + } + + line++; + + t = strstrip(l); + if (*t != '#') { + /* Try to figure out whether this init script supports + * the reload operation. This heuristic looks for + * "Usage" lines which include the reload option. */ + if ( state == USAGE_CONTINUATION || + (state == NORMAL && strcasestr(t, "usage"))) { + if (usage_contains_reload(t)) { + supports_reload = true; + state = NORMAL; + } else if (t[strlen(t)-1] == '\\') + state = USAGE_CONTINUATION; + else + state = NORMAL; + } + + continue; + } + + if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) { + state = LSB; + s->sysv_has_lsb = true; + continue; + } + + if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) { + state = NORMAL; + continue; + } + + t++; + t += strspn(t, WHITESPACE); + + if (state == NORMAL) { + + /* Try to parse Red Hat style chkconfig headers */ + + if (startswith_no_case(t, "chkconfig:")) { + int start_priority; + char runlevels[16], *k; + + state = NORMAL; + + if (sscanf(t+10, "%15s %i %*i", + runlevels, + &start_priority) != 2) { + + log_warning_unit(u->id, + "[%s:%u] Failed to parse chkconfig line. Ignoring.", + path, line); + continue; + } + + /* A start priority gathered from the + * symlink farms is preferred over the + * data from the LSB header. */ + if (start_priority < 0 || start_priority > 99) + log_warning_unit(u->id, + "[%s:%u] Start priority out of range. Ignoring.", + path, line); + else + s->sysv_start_priority = start_priority; + + char_array_0(runlevels); + k = delete_chars(runlevels, WHITESPACE "-"); + + if (k[0]) { + char *d; + + if (!(d = strdup(k))) { + r = -ENOMEM; + goto finish; + } + + free(s->sysv_runlevels); + s->sysv_runlevels = d; + } + + } else if (startswith_no_case(t, "description:")) { + + size_t k = strlen(t); + char *d; + const char *j; + + if (t[k-1] == '\\') { + state = DESCRIPTION; + t[k-1] = 0; + } + + if ((j = strstrip(t+12)) && *j) { + if (!(d = strdup(j))) { + r = -ENOMEM; + goto finish; + } + } else + d = NULL; + + free(chkconfig_description); + chkconfig_description = d; + + } else if (startswith_no_case(t, "pidfile:")) { + + char *fn; + + state = NORMAL; + + fn = strstrip(t+8); + if (!path_is_absolute(fn)) { + log_warning_unit(u->id, + "[%s:%u] PID file not absolute. Ignoring.", + path, line); + continue; + } + + if (!(fn = strdup(fn))) { + r = -ENOMEM; + goto finish; + } + + free(s->pid_file); + s->pid_file = fn; + } + + } else if (state == DESCRIPTION) { + + /* Try to parse Red Hat style description + * continuation */ + + size_t k = strlen(t); + char *j; + + if (t[k-1] == '\\') + t[k-1] = 0; + else + state = NORMAL; + + if ((j = strstrip(t)) && *j) { + char *d = NULL; + + if (chkconfig_description) + d = strjoin(chkconfig_description, " ", j, NULL); + else + d = strdup(j); + + if (!d) { + r = -ENOMEM; + goto finish; + } + + free(chkconfig_description); + chkconfig_description = d; + } + + } else if (state == LSB || state == LSB_DESCRIPTION) { + + if (startswith_no_case(t, "Provides:")) { + char *i, *w; + size_t z; + + state = LSB; + + FOREACH_WORD_QUOTED(w, z, t+9, i) { + char *n, *m; + + if (!(n = strndup(w, z))) { + r = -ENOMEM; + goto finish; + } + + r = sysv_translate_facility(n, basename(path), &m); + free(n); + + if (r < 0) + goto finish; + + if (r == 0) + continue; + + if (unit_name_to_type(m) == UNIT_SERVICE) + r = unit_merge_by_name(u, m); + else + /* NB: SysV targets + * which are provided + * by a service are + * pulled in by the + * services, as an + * indication that the + * generic service is + * now available. This + * is strictly + * one-way. The + * targets do NOT pull + * in the SysV + * services! */ + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true); + + if (r < 0) + log_error_unit(u->id, + "[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", + path, line, m, strerror(-r)); + + free(m); + } + + } else if (startswith_no_case(t, "Required-Start:") || + startswith_no_case(t, "Should-Start:") || + startswith_no_case(t, "X-Start-Before:") || + startswith_no_case(t, "X-Start-After:")) { + char *i, *w; + size_t z; + + state = LSB; + + FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) { + char *n, *m; + + if (!(n = strndup(w, z))) { + r = -ENOMEM; + goto finish; + } + + r = sysv_translate_facility(n, basename(path), &m); + if (r < 0) { + log_error_unit(u->id, + "[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", + path, line, n, strerror(-r)); + free(n); + continue; + } + + free(n); + + if (r == 0) + continue; + + r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true); + + if (r < 0) + log_error_unit(u->id, "[%s:%u] Failed to add dependency on %s, ignoring: %s", + path, line, m, strerror(-r)); + + free(m); + } + } else if (startswith_no_case(t, "Default-Start:")) { + char *k, *d; + + state = LSB; + + k = delete_chars(t+14, WHITESPACE "-"); + + if (k[0] != 0) { + if (!(d = strdup(k))) { + r = -ENOMEM; + goto finish; + } + + free(s->sysv_runlevels); + s->sysv_runlevels = d; + } + + } else if (startswith_no_case(t, "Description:")) { + char *d, *j; + + state = LSB_DESCRIPTION; + + if ((j = strstrip(t+12)) && *j) { + if (!(d = strdup(j))) { + r = -ENOMEM; + goto finish; + } + } else + d = NULL; + + free(long_description); + long_description = d; + + } else if (startswith_no_case(t, "Short-Description:")) { + char *d, *j; + + state = LSB; + + if ((j = strstrip(t+18)) && *j) { + if (!(d = strdup(j))) { + r = -ENOMEM; + goto finish; + } + } else + d = NULL; + + free(short_description); + short_description = d; + + } else if (state == LSB_DESCRIPTION) { + + if (startswith(l, "#\t") || startswith(l, "# ")) { + char *j; + + if ((j = strstrip(t)) && *j) { + char *d = NULL; + + if (long_description) + d = strjoin(long_description, " ", t, NULL); + else + d = strdup(j); + + if (!d) { + r = -ENOMEM; + goto finish; + } + + free(long_description); + long_description = d; + } + + } else + state = LSB; + } + } + } + + if ((r = sysv_exec_commands(s, supports_reload)) < 0) + goto finish; + + if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) { + /* If there a runlevels configured for this service + * but none of the standard ones, then we assume this + * is some special kind of service (which might be + * needed for early boot) and don't create any links + * to it. */ + + UNIT(s)->default_dependencies = false; + + /* Don't timeout special services during boot (like fsck) */ + s->timeout_start_usec = 0; + s->timeout_stop_usec = 0; + } else { + s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC; + s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC; + } + + /* Special setting for all SysV services */ + s->type = SERVICE_FORKING; + s->remain_after_exit = !s->pid_file; + s->guess_main_pid = false; + s->restart = SERVICE_RESTART_NO; + s->exec_context.ignore_sigpipe = false; + s->kill_context.kill_mode = KILL_PROCESS; + + /* We use the long description only if + * no short description is set. */ + + if (short_description) + description = short_description; + else if (chkconfig_description) + description = chkconfig_description; + else if (long_description) + description = long_description; + else + description = NULL; + + if (description) { + char *d; + + if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) { + r = -ENOMEM; + goto finish; + } + + u->description = d; + } + + /* The priority that has been set in /etc/rcN.d/ hierarchies + * takes precedence over what is stored as default in the LSB + * header */ + if (s->sysv_start_priority_from_rcnd >= 0) + s->sysv_start_priority = s->sysv_start_priority_from_rcnd; + + u->load_state = UNIT_LOADED; + r = 0; + +finish: + + if (f) + fclose(f); + + free(short_description); + free(long_description); + free(chkconfig_description); + + return r; +} + +static int service_load_sysv_name(Service *s, const char *name) { + char **p; + + assert(s); + assert(name); + + /* For SysV services we strip the *.sh suffixes. */ + if (endswith(name, ".sh.service")) + return -ENOENT; + + STRV_FOREACH(p, UNIT(s)->manager->lookup_paths.sysvinit_path) { + char *path; + int r; + + path = strjoin(*p, "/", name, NULL); + if (!path) + return -ENOMEM; + + assert(endswith(path, ".service")); + path[strlen(path)-8] = 0; + + r = service_load_sysv_path(s, path); + + if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) { + /* Try *.sh source'able init scripts */ + strcat(path, ".sh"); + r = service_load_sysv_path(s, path); + } + free(path); + + if (r < 0) + return r; + + if (UNIT(s)->load_state != UNIT_STUB) + break; + } + + return 0; +} + +static int service_load_sysv(Service *s) { + const char *t; + Iterator i; + int r; + + assert(s); + + /* Load service data from SysV init scripts, preferably with + * LSB headers ... */ + + if (strv_isempty(UNIT(s)->manager->lookup_paths.sysvinit_path)) + return 0; + + if ((t = UNIT(s)->id)) + if ((r = service_load_sysv_name(s, t)) < 0) + return r; + + if (UNIT(s)->load_state == UNIT_STUB) + SET_FOREACH(t, UNIT(s)->names, i) { + if (t == UNIT(s)->id) + continue; + + if ((r = service_load_sysv_name(s, t)) < 0) + return r; + + if (UNIT(s)->load_state != UNIT_STUB) + break; + } + + return 0; +} +#endif + +static int service_verify(Service *s) { + assert(s); + + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + + if (!s->exec_command[SERVICE_EXEC_START]) { + log_error_unit(UNIT(s)->id, "%s lacks ExecStart setting. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->type != SERVICE_ONESHOT && + s->exec_command[SERVICE_EXEC_START]->command_next) { + log_error_unit(UNIT(s)->id, "%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) { + log_error_unit(UNIT(s)->id, "%s has Restart setting other than no, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->type == SERVICE_DBUS && !s->bus_name) { + log_error_unit(UNIT(s)->id, "%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->bus_name && s->type != SERVICE_DBUS) + log_warning_unit(UNIT(s)->id, "%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id); + + if (s->exec_context.pam_name && !(s->kill_context.kill_mode == KILL_CONTROL_GROUP || s->kill_context.kill_mode == KILL_MIXED)) { + log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_TIZEN +static int service_add_default_extra_dependencies(Service *s) { + char *t = NULL; + char **d; + int r; + bool ignore; + + if (!(UNIT(s)->manager->dependencies)) + return 0; + + /* Do NOT add dependencies for systemd unit files */ + if (startswith(UNIT(s)->id, "systemd-") + || startswith(UNIT(s)->id, "serial-getty")) + return 0; + + t = unit_name_template(UNIT(s)->id); + if (!t) + return -ENOMEM; + + ignore = set_contains(UNIT(s)->manager->dep_ignore_list, t); + free(t); + if (ignore) + return 0; + + STRV_FOREACH(d, UNIT(s)->manager->dependencies) { + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, *d, NULL, true); + if (r < 0) + return r; + } + return 0; +} +#endif + +static int service_add_default_dependencies(Service *s) { + int r; + + assert(s); + + /* Add a number of automatic dependencies useful for the + * majority of services. */ + + /* First, pull in base system */ + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, + SPECIAL_BASIC_TARGET, NULL, true); + if (r < 0) + return r; + +#ifdef CONFIG_TIZEN + r = service_add_default_extra_dependencies(s); + if (r < 0) + return r; +#endif + + /* Second, activate normal shutdown */ + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, + SPECIAL_SHUTDOWN_TARGET, NULL, true); + return r; +} + +static void service_fix_output(Service *s) { + assert(s); + + /* If nothing has been explicitly configured, patch default + * output in. If input is socket/tty we avoid this however, + * since in that case we want output to default to the same + * place as we read input from. */ + + if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT && + s->exec_context.std_output == EXEC_OUTPUT_INHERIT && + s->exec_context.std_input == EXEC_INPUT_NULL) + s->exec_context.std_error = UNIT(s)->manager->default_std_error; + + if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT && + s->exec_context.std_input == EXEC_INPUT_NULL) + s->exec_context.std_output = UNIT(s)->manager->default_std_output; +} + +static int service_load(Unit *u) { + int r; + Service *s = SERVICE(u); + + assert(s); + + /* Load a .service file */ + r = unit_load_fragment(u); + if (r < 0) + return r; + +#ifdef HAVE_SYSV_COMPAT + /* Load a classic init script as a fallback, if we couldn't find anything */ + if (u->load_state == UNIT_STUB) { + r = service_load_sysv(s); + if (r < 0) + return r; + } +#endif + + /* Still nothing found? Then let's give up */ + if (u->load_state == UNIT_STUB) + return -ENOENT; + + /* This is a new unit? Then let's add in some extras */ + if (u->load_state == UNIT_LOADED) { + + /* We were able to load something, then let's add in + * the dropin directories. */ + r = unit_load_dropin(u); + if (r < 0) + return r; + + if (s->type == _SERVICE_TYPE_INVALID) + s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE; + + /* Oneshot services have disabled start timeout by default */ + if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) + s->timeout_start_usec = 0; + + service_fix_output(s); + + r = unit_add_exec_dependencies(u, &s->exec_context); + if (r < 0) + return r; + + r = unit_add_default_slice(u); + if (r < 0) + return r; + +#ifdef HAVE_SYSV_COMPAT + r = sysv_fix_order(s); + if (r < 0) + return r; +#endif + + if (s->bus_name) { + r = unit_watch_bus_name(u, s->bus_name); + if (r < 0) + return r; + } + + if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE) + s->notify_access = NOTIFY_MAIN; + + if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE) + s->notify_access = NOTIFY_MAIN; + + if (UNIT(s)->default_dependencies) { + r = service_add_default_dependencies(s); + if (r < 0) + return r; + } + + r = unit_exec_context_defaults(u, &s->exec_context); + if (r < 0) + return r; + } + + return service_verify(s); +} + +static void service_dump(Unit *u, FILE *f, const char *prefix) { + + ServiceExecCommand c; + Service *s = SERVICE(u); + const char *prefix2; + _cleanup_free_ char *p2 = NULL; + + assert(s); + + p2 = strappend(prefix, "\t"); + prefix2 = p2 ? p2 : prefix; + + fprintf(f, + "%sService State: %s\n" + "%sResult: %s\n" + "%sReload Result: %s\n" + "%sPermissionsStartOnly: %s\n" + "%sRootDirectoryStartOnly: %s\n" + "%sRemainAfterExit: %s\n" + "%sGuessMainPID: %s\n" + "%sType: %s\n" + "%sRestart: %s\n" + "%sNotifyAccess: %s\n", + prefix, service_state_to_string(s->state), + prefix, service_result_to_string(s->result), + prefix, service_result_to_string(s->reload_result), + prefix, yes_no(s->permissions_start_only), + prefix, yes_no(s->root_directory_start_only), + prefix, yes_no(s->remain_after_exit), + prefix, yes_no(s->guess_main_pid), + prefix, service_type_to_string(s->type), + prefix, service_restart_to_string(s->restart), + prefix, notify_access_to_string(s->notify_access)); + + if (s->control_pid > 0) + fprintf(f, + "%sControl PID: "PID_FMT"\n", + prefix, s->control_pid); + + if (s->main_pid > 0) + fprintf(f, + "%sMain PID: "PID_FMT"\n" + "%sMain PID Known: %s\n" + "%sMain PID Alien: %s\n", + prefix, s->main_pid, + prefix, yes_no(s->main_pid_known), + prefix, yes_no(s->main_pid_alien)); + + if (s->pid_file) + fprintf(f, + "%sPIDFile: %s\n", + prefix, s->pid_file); + + if (s->bus_name) + fprintf(f, + "%sBusName: %s\n" + "%sBus Name Good: %s\n", + prefix, s->bus_name, + prefix, yes_no(s->bus_name_good)); + + kill_context_dump(&s->kill_context, f, prefix); + exec_context_dump(&s->exec_context, f, prefix); + + for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) { + + if (!s->exec_command[c]) + continue; + + fprintf(f, "%s-> %s:\n", + prefix, service_exec_command_to_string(c)); + + exec_command_dump_list(s->exec_command[c], f, prefix2); + } + +#ifdef HAVE_SYSV_COMPAT + if (s->is_sysv) + fprintf(f, + "%sSysV Init Script has LSB Header: %s\n" + "%sSysVEnabled: %s\n", + prefix, yes_no(s->sysv_has_lsb), + prefix, yes_no(s->sysv_enabled)); + + if (s->sysv_start_priority >= 0) + fprintf(f, + "%sSysVStartPriority: %i\n", + prefix, s->sysv_start_priority); + + if (s->sysv_runlevels) + fprintf(f, "%sSysVRunLevels: %s\n", + prefix, s->sysv_runlevels); +#endif + + if (s->status_text) + fprintf(f, "%sStatus Text: %s\n", + prefix, s->status_text); +} + +static int service_load_pid_file(Service *s, bool may_warn) { + _cleanup_free_ char *k = NULL; + int r; + pid_t pid; + + assert(s); + + if (!s->pid_file) + return -ENOENT; + + r = read_one_line_file(s->pid_file, &k); + if (r < 0) { + if (may_warn) + log_info_unit(UNIT(s)->id, + "PID file %s not readable (yet?) after %s.", + s->pid_file, service_state_to_string(s->state)); + return r; + } + + r = parse_pid(k, &pid); + if (r < 0) { + if (may_warn) + log_info_unit(UNIT(s)->id, + "Failed to read PID from file %s: %s", + s->pid_file, strerror(-r)); + return r; + } + + if (!pid_is_alive(pid)) { + if (may_warn) + log_info_unit(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file); + + return -ESRCH; + } + + if (s->main_pid_known) { + if (pid == s->main_pid) + return 0; + + log_debug_unit(UNIT(s)->id, + "Main PID changing: "PID_FMT" -> "PID_FMT, + s->main_pid, pid); + service_unwatch_main_pid(s); + s->main_pid_known = false; + } else + log_debug_unit(UNIT(s)->id, + "Main PID loaded: "PID_FMT, pid); + + r = service_set_main_pid(s, pid); + if (r < 0) + return r; + + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) { + /* FIXME: we need to do something here */ + log_warning_unit(UNIT(s)->id, + "Failed to watch PID "PID_FMT" from service %s", + pid, UNIT(s)->id); + return r; + } + + return 0; +} + +static int service_search_main_pid(Service *s) { + pid_t pid; + int r; + + assert(s); + + /* If we know it anyway, don't ever fallback to unreliable + * heuristics */ + if (s->main_pid_known) + return 0; + + if (!s->guess_main_pid) + return 0; + + assert(s->main_pid <= 0); + + pid = unit_search_main_pid(UNIT(s)); + if (pid <= 0) + return -ENOENT; + + log_debug_unit(UNIT(s)->id, + "Main PID guessed: "PID_FMT, pid); + r = service_set_main_pid(s, pid); + if (r < 0) + return r; + + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) + /* FIXME: we need to do something here */ + log_warning_unit(UNIT(s)->id, + "Failed to watch PID "PID_FMT" from service %s", + pid, UNIT(s)->id); + return r; + + return 0; +} + +static void service_set_state(Service *s, ServiceState state) { + ServiceState old_state; + const UnitActiveState *table; + + assert(s); + + table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table; + + old_state = s->state; + s->state = state; + + service_unwatch_pid_file(s); + + if (!IN_SET(state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, + SERVICE_AUTO_RESTART)) + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + if (!IN_SET(state, + SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + service_unwatch_main_pid(s); + s->main_command = NULL; + } + + if (!IN_SET(state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + service_unwatch_control_pid(s); + s->control_command = NULL; + s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; + } + + if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) + unit_unwatch_all_pids(UNIT(s)); + + if (!IN_SET(state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) && + !(state == SERVICE_DEAD && UNIT(s)->job)) { + service_close_socket_fd(s); + service_connection_unref(s); + } + + if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) + service_stop_watchdog(s); + + /* For the inactive states unit_notify() will trim the cgroup, + * but for exit we have to do that ourselves... */ + if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0) + unit_destroy_cgroup(UNIT(s)); + + /* For remain_after_exit services, let's see if we can "release" the + * hold on the console, since unit_notify() only does that in case of + * change of state */ + if (state == SERVICE_EXITED && s->remain_after_exit && + UNIT(s)->manager->n_on_console > 0) { + ExecContext *ec = unit_get_exec_context(UNIT(s)); + if (ec && exec_context_may_touch_console(ec)) { + Manager *m = UNIT(s)->manager; + + m->n_on_console --; + if (m->n_on_console == 0) + /* unset no_console_output flag, since the console is free */ + m->no_console_output = false; + } + } + + if (old_state != state) + log_debug_unit(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state)); + + unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); + s->reload_result = SERVICE_SUCCESS; +} + +static int service_coldplug(Unit *u) { + Service *s = SERVICE(u); + int r; + + assert(s); + assert(s->state == SERVICE_DEAD); + + if (s->deserialized_state != s->state) { + + if (IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + + usec_t k; + + k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; + + /* For the start/stop timeouts 0 means off */ + if (k > 0) { + r = service_arm_timer(s, k); + if (r < 0) + return r; + } + } + + if (s->deserialized_state == SERVICE_AUTO_RESTART) { + + /* The restart timeouts 0 means immediately */ + r = service_arm_timer(s, s->restart_usec); + if (r < 0) + return r; + } + + if (pid_is_unwaited(s->main_pid) && + ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) || + IN_SET(s->deserialized_state, + SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { + r = unit_watch_pid(UNIT(s), s->main_pid); + if (r < 0) + return r; + } + + if (pid_is_unwaited(s->control_pid) && + IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + r = unit_watch_pid(UNIT(s), s->control_pid); + if (r < 0) + return r; + } + + if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) + unit_watch_all_pids(UNIT(s)); + + if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) + service_start_watchdog(s); + + service_set_state(s, s->deserialized_state); + } + + return 0; +} + +static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { + Iterator i; + int r; + int *rfds = NULL; + unsigned rn_fds = 0; + Unit *u; + + assert(s); + assert(fds); + assert(n_fds); + + if (s->socket_fd >= 0) + return 0; + + SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { + int *cfds; + unsigned cn_fds; + Socket *sock; + + if (u->type != UNIT_SOCKET) + continue; + + sock = SOCKET(u); + + r = socket_collect_fds(sock, &cfds, &cn_fds); + if (r < 0) + goto fail; + + if (!cfds) + continue; + + if (!rfds) { + rfds = cfds; + rn_fds = cn_fds; + } else { + int *t; + + t = new(int, rn_fds+cn_fds); + if (!t) { + free(cfds); + r = -ENOMEM; + goto fail; + } + + memcpy(t, rfds, rn_fds * sizeof(int)); + memcpy(t+rn_fds, cfds, cn_fds * sizeof(int)); + free(rfds); + free(cfds); + + rfds = t; + rn_fds = rn_fds+cn_fds; + } + } + + *fds = rfds; + *n_fds = rn_fds; + + return 0; + +fail: + free(rfds); + + return r; +} + +static int service_spawn( + Service *s, + ExecCommand *c, + bool timeout, + bool pass_fds, + bool apply_permissions, + bool apply_chroot, + bool apply_tty_stdin, + bool set_notify_socket, + bool is_control, + pid_t *_pid) { + + pid_t pid; + int r; + int *fds = NULL; + _cleanup_free_ int *fdsbuf = NULL; + unsigned n_fds = 0, n_env = 0; + _cleanup_strv_free_ char + **argv = NULL, **final_env = NULL, **our_env = NULL; + const char *path; + + assert(s); + assert(c); + assert(_pid); + + unit_realize_cgroup(UNIT(s)); + + r = unit_setup_exec_runtime(UNIT(s)); + if (r < 0) + goto fail; + + if (pass_fds || + s->exec_context.std_input == EXEC_INPUT_SOCKET || + s->exec_context.std_output == EXEC_OUTPUT_SOCKET || + s->exec_context.std_error == EXEC_OUTPUT_SOCKET) { + + if (s->socket_fd >= 0) { + fds = &s->socket_fd; + n_fds = 1; + } else { + r = service_collect_fds(s, &fdsbuf, &n_fds); + if (r < 0) + goto fail; + + fds = fdsbuf; + } + } + + if (timeout && s->timeout_start_usec > 0) { + r = service_arm_timer(s, s->timeout_start_usec); + if (r < 0) + goto fail; + } else + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + r = unit_full_printf_strv(UNIT(s), c->argv, &argv); + if (r < 0) + goto fail; + + our_env = new0(char*, 4); + if (!our_env) { + r = -ENOMEM; + goto fail; + } + + if (set_notify_socket) + if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) { + r = -ENOMEM; + goto fail; + } + + if (s->main_pid > 0) + if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) { + r = -ENOMEM; + goto fail; + } + + if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM) + if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) { + r = -ENOMEM; + goto fail; + } + + final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); + if (!final_env) { + r = -ENOMEM; + goto fail; + } + + if (is_control && UNIT(s)->cgroup_path) { + path = strappenda(UNIT(s)->cgroup_path, "/control"); + cg_create(SYSTEMD_CGROUP_CONTROLLER, path); + } else + path = UNIT(s)->cgroup_path; + + r = exec_spawn(c, + argv, + &s->exec_context, + fds, n_fds, + final_env, + apply_permissions, + apply_chroot, + apply_tty_stdin, + UNIT(s)->manager->confirm_spawn, + UNIT(s)->manager->cgroup_supported, + path, + UNIT(s)->id, + s->watchdog_usec, + s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL, + s->exec_runtime, + &pid); + if (r < 0) + goto fail; + + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) + /* FIXME: we need to do something here */ + goto fail; + + *_pid = pid; + + return 0; + +fail: + if (timeout) + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + return r; +} + +static int main_pid_good(Service *s) { + assert(s); + + /* Returns 0 if the pid is dead, 1 if it is good, -1 if we + * don't know */ + + /* If we know the pid file, then lets just check if it is + * still valid */ + if (s->main_pid_known) { + + /* If it's an alien child let's check if it is still + * alive ... */ + if (s->main_pid_alien && s->main_pid > 0) + return pid_is_alive(s->main_pid); + + /* .. otherwise assume we'll get a SIGCHLD for it, + * which we really should wait for to collect exit + * status and code */ + return s->main_pid > 0; + } + + /* We don't know the pid */ + return -EAGAIN; +} + +_pure_ static int control_pid_good(Service *s) { + assert(s); + + return s->control_pid > 0; +} + +static int cgroup_good(Service *s) { + int r; + + assert(s); + + if (!UNIT(s)->cgroup_path) + return 0; + + r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true); + if (r < 0) + return r; + + return !r; +} + +static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) { + int r; + assert(s); + + if (f != SERVICE_SUCCESS) + s->result = f; + + service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD); + + if (allow_restart && + !s->forbid_restart && + (s->restart == SERVICE_RESTART_ALWAYS || + (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) || + (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) || + (s->restart == SERVICE_RESTART_ON_WATCHDOG && s->result == SERVICE_FAILURE_WATCHDOG) || + (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL || + s->result == SERVICE_FAILURE_CORE_DUMP))) && + (s->result != SERVICE_FAILURE_EXIT_CODE || + !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) && + (s->result != SERVICE_FAILURE_SIGNAL || + !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status)))) { + + r = service_arm_timer(s, s->restart_usec); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_AUTO_RESTART); + } + + s->forbid_restart = false; + + /* we want fresh tmpdirs in case service is started again immediately */ + exec_runtime_destroy(s->exec_runtime); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + + /* Try to delete the pid file. At this point it will be + * out-of-date, and some software might be confused by it, so + * let's remove it. */ + if (s->pid_file) + unlink_noerrno(s->pid_file); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run install restart timer: %s", + UNIT(s)->id, strerror(-r)); + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false); +} + +static void service_enter_stop_post(Service *s, ServiceResult f) { + int r; + assert(s); + + if (f != SERVICE_SUCCESS) + s->result = f; + + service_unwatch_control_pid(s); + unit_watch_all_pids(UNIT(s)); + + s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST]; + if (s->control_command) { + s->control_command_id = SERVICE_EXEC_STOP_POST; + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + true, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_STOP_POST); + } else + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'stop-post' task: %s", + UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); +} + +static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) { + int r; + + assert(s); + + if (f != SERVICE_SUCCESS) + s->result = f; + + unit_watch_all_pids(UNIT(s)); + + r = unit_kill_context( + UNIT(s), + &s->kill_context, + state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM, + s->main_pid, + s->control_pid, + s->main_pid_alien); + + if (r < 0) + goto fail; + + if (r > 0) { + if (s->timeout_stop_usec > 0) { + r = service_arm_timer(s, s->timeout_stop_usec); + if (r < 0) + goto fail; + } + + service_set_state(s, state); + } else if (state == SERVICE_STOP_SIGTERM) + service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS); + else if (state == SERVICE_STOP_SIGKILL) + service_enter_stop_post(s, SERVICE_SUCCESS); + else if (state == SERVICE_FINAL_SIGTERM) + service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS); + else + service_enter_dead(s, SERVICE_SUCCESS, true); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); + + if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) + service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES); + else + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); +} + +static void service_enter_stop(Service *s, ServiceResult f) { + int r; + + assert(s); + + if (f != SERVICE_SUCCESS) + s->result = f; + + service_unwatch_control_pid(s); + unit_watch_all_pids(UNIT(s)); + + s->control_command = s->exec_command[SERVICE_EXEC_STOP]; + if (s->control_command) { + s->control_command_id = SERVICE_EXEC_STOP; + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + false, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_STOP); + } else + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); +} + +static void service_enter_running(Service *s, ServiceResult f) { + int main_pid_ok, cgroup_ok; + assert(s); + + if (f != SERVICE_SUCCESS) + s->result = f; + + main_pid_ok = main_pid_good(s); + cgroup_ok = cgroup_good(s); + + if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) && + (s->bus_name_good || s->type != SERVICE_DBUS)) + service_set_state(s, SERVICE_RUNNING); + else if (s->remain_after_exit) + service_set_state(s, SERVICE_EXITED); + else + service_enter_stop(s, SERVICE_SUCCESS); +} + +static void service_enter_start_post(Service *s) { + int r; + assert(s); + + service_unwatch_control_pid(s); + service_reset_watchdog(s); + + s->control_command = s->exec_command[SERVICE_EXEC_START_POST]; + if (s->control_command) { + s->control_command_id = SERVICE_EXEC_START_POST; + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + false, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_START_POST); + } else + service_enter_running(s, SERVICE_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); +} + +static void service_kill_control_processes(Service *s) { + char *p; + + if (!UNIT(s)->cgroup_path) + return; + + p = strappenda(UNIT(s)->cgroup_path, "/control"); + cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, true, true, true, NULL); +} + +static void service_enter_start(Service *s) { + ExecCommand *c; + pid_t pid; + int r; + + assert(s); + + assert(s->exec_command[SERVICE_EXEC_START]); + assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT); + + service_unwatch_control_pid(s); + service_unwatch_main_pid(s); + + /* We want to ensure that nobody leaks processes from + * START_PRE here, so let's go on a killing spree, People + * should not spawn long running processes from START_PRE. */ + service_kill_control_processes(s); + + if (s->type == SERVICE_FORKING) { + s->control_command_id = SERVICE_EXEC_START; + c = s->control_command = s->exec_command[SERVICE_EXEC_START]; + + s->main_command = NULL; + } else { + s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; + s->control_command = NULL; + + c = s->main_command = s->exec_command[SERVICE_EXEC_START]; + } + + r = service_spawn(s, + c, + s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || + s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT, + true, + true, + true, + true, + s->notify_access != NOTIFY_NONE, + false, + &pid); + if (r < 0) + goto fail; + + if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) { + /* For simple services we immediately start + * the START_POST binaries. */ + + service_set_main_pid(s, pid); + service_enter_start_post(s); + + } else if (s->type == SERVICE_FORKING) { + + /* For forking services we wait until the start + * process exited. */ + + s->control_pid = pid; + service_set_state(s, SERVICE_START); + + } else if (s->type == SERVICE_ONESHOT || + s->type == SERVICE_DBUS || + s->type == SERVICE_NOTIFY) { + + /* For oneshot services we wait until the start + * process exited, too, but it is our main process. */ + + /* For D-Bus services we know the main pid right away, + * but wait for the bus name to appear on the + * bus. Notify services are similar. */ + + service_set_main_pid(s, pid); + service_set_state(s, SERVICE_START); + } else + assert_not_reached("Unknown service type"); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); +} + +static void service_enter_start_pre(Service *s) { + int r; + + assert(s); + + service_unwatch_control_pid(s); + + s->control_command = s->exec_command[SERVICE_EXEC_START_PRE]; + if (s->control_command) { + /* Before we start anything, let's clear up what might + * be left from previous runs. */ + service_kill_control_processes(s); + + s->control_command_id = SERVICE_EXEC_START_PRE; + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + true, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_START_PRE); + } else + service_enter_start(s); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r)); + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); +} + +static void service_enter_restart(Service *s) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(s); + + if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) { + /* Don't restart things if we are going down anyway */ + log_info_unit(UNIT(s)->id, + "Stop job pending for unit, delaying automatic restart."); + + r = service_arm_timer(s, s->restart_usec); + if (r < 0) + goto fail; + + return; + } + + /* Any units that are bound to this service must also be + * 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_FAIL, false, &error, NULL); + if (r < 0) + goto fail; + + /* Note that we stay in the SERVICE_AUTO_RESTART state here, + * it will be canceled as part of the service_stop() call that + * is executed as part of JOB_RESTART. */ + + log_debug_unit(UNIT(s)->id, + "%s scheduled restart job.", UNIT(s)->id); + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to schedule restart job: %s", + UNIT(s)->id, bus_error_message(&error, -r)); + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false); +} + +static void service_enter_reload(Service *s) { + int r; + + assert(s); + + service_unwatch_control_pid(s); + + s->control_command = s->exec_command[SERVICE_EXEC_RELOAD]; + if (s->control_command) { + s->control_command_id = SERVICE_EXEC_RELOAD; + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + false, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + service_set_state(s, SERVICE_RELOAD); + } else + service_enter_running(s, SERVICE_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'reload' task: %s", + UNIT(s)->id, strerror(-r)); + s->reload_result = SERVICE_FAILURE_RESOURCES; + service_enter_running(s, SERVICE_SUCCESS); +} + +static void service_run_next_control(Service *s) { + int r; + + assert(s); + assert(s->control_command); + assert(s->control_command->command_next); + + assert(s->control_command_id != SERVICE_EXEC_START); + + s->control_command = s->control_command->command_next; + service_unwatch_control_pid(s); + + r = service_spawn(s, + s->control_command, + true, + false, + !s->permissions_start_only, + !s->root_directory_start_only, + s->control_command_id == SERVICE_EXEC_START_PRE || + s->control_command_id == SERVICE_EXEC_STOP_POST, + false, + true, + &s->control_pid); + if (r < 0) + goto fail; + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run next control task: %s", + UNIT(s)->id, strerror(-r)); + + if (s->state == SERVICE_START_PRE) + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + else if (s->state == SERVICE_STOP) + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); + else if (s->state == SERVICE_STOP_POST) + service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true); + else if (s->state == SERVICE_RELOAD) { + s->reload_result = SERVICE_FAILURE_RESOURCES; + service_enter_running(s, SERVICE_SUCCESS); + } else + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); +} + +static void service_run_next_main(Service *s) { + pid_t pid; + int r; + + assert(s); + assert(s->main_command); + assert(s->main_command->command_next); + assert(s->type == SERVICE_ONESHOT); + + s->main_command = s->main_command->command_next; + service_unwatch_main_pid(s); + + r = service_spawn(s, + s->main_command, + true, + true, + true, + true, + true, + s->notify_access != NOTIFY_NONE, + false, + &pid); + if (r < 0) + goto fail; + + service_set_main_pid(s, pid); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run next main task: %s", UNIT(s)->id, strerror(-r)); + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); +} + +static int service_start_limit_test(Service *s) { + assert(s); + + if (ratelimit_test(&s->start_limit)) + return 0; + + switch (s->start_limit_action) { + + case SERVICE_START_LIMIT_NONE: + log_warning_unit(UNIT(s)->id, + "%s start request repeated too quickly, refusing to start.", + UNIT(s)->id); + break; + + case SERVICE_START_LIMIT_REBOOT: { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + log_warning_unit(UNIT(s)->id, + "%s start request repeated too quickly, rebooting.", UNIT(s)->id); + + r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, + SPECIAL_REBOOT_TARGET, JOB_REPLACE, + true, &error, NULL); + if (r < 0) + log_error_unit(UNIT(s)->id, + "Failed to reboot: %s.", bus_error_message(&error, r)); + + break; + } + + case SERVICE_START_LIMIT_REBOOT_FORCE: + log_warning_unit(UNIT(s)->id, + "%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id); + UNIT(s)->manager->exit_code = MANAGER_REBOOT; + break; + + case SERVICE_START_LIMIT_REBOOT_IMMEDIATE: + log_warning_unit(UNIT(s)->id, + "%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id); + sync(); + reboot(RB_AUTOBOOT); + break; + + default: + log_error_unit(UNIT(s)->id, + "start limit action=%i", s->start_limit_action); + assert_not_reached("Unknown StartLimitAction."); + } + + return -ECANCELED; +} + +static int service_start(Unit *u) { + Service *s = SERVICE(u); + int r; + + assert(s); + + /* We cannot fulfill this request right now, try again later + * please! */ + if (s->state == SERVICE_STOP || + s->state == SERVICE_STOP_SIGTERM || + s->state == SERVICE_STOP_SIGKILL || + s->state == SERVICE_STOP_POST || + s->state == SERVICE_FINAL_SIGTERM || + s->state == SERVICE_FINAL_SIGKILL) + return -EAGAIN; + + /* Already on it! */ + if (s->state == SERVICE_START_PRE || + s->state == SERVICE_START || + s->state == SERVICE_START_POST) + return 0; + + /* A service that will be restarted must be stopped first to + * trigger BindsTo and/or OnFailure dependencies. If a user + * does not want to wait for the holdoff time to elapse, the + * service should be manually restarted, not started. We + * simply return EAGAIN here, so that any start jobs stay + * queued, and assume that the auto restart timer will + * eventually trigger the restart. */ + if (s->state == SERVICE_AUTO_RESTART) + return -EAGAIN; + + assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED); + + /* Make sure we don't enter a busy loop of some kind. */ + r = service_start_limit_test(s); + if (r < 0) { + service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false); + return r; + } + + s->result = SERVICE_SUCCESS; + s->reload_result = SERVICE_SUCCESS; + s->main_pid_known = false; + s->main_pid_alien = false; + s->forbid_restart = false; + + service_enter_start_pre(s); + return 0; +} + +static int service_stop(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + /* Don't create restart jobs from here. */ + s->forbid_restart = true; + + /* Already on it */ + if (s->state == SERVICE_STOP || + s->state == SERVICE_STOP_SIGTERM || + s->state == SERVICE_STOP_SIGKILL || + s->state == SERVICE_STOP_POST || + s->state == SERVICE_FINAL_SIGTERM || + s->state == SERVICE_FINAL_SIGKILL) + return 0; + + /* A restart will be scheduled or is in progress. */ + if (s->state == SERVICE_AUTO_RESTART) { + service_set_state(s, SERVICE_DEAD); + return 0; + } + + /* If there's already something running we go directly into + * kill mode. */ + if (s->state == SERVICE_START_PRE || + s->state == SERVICE_START || + s->state == SERVICE_START_POST || + s->state == SERVICE_RELOAD) { + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS); + return 0; + } + + assert(s->state == SERVICE_RUNNING || + s->state == SERVICE_EXITED); + + service_enter_stop(s, SERVICE_SUCCESS); + return 0; +} + +static int service_reload(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED); + + service_enter_reload(s); + return 0; +} + +_pure_ static bool service_can_reload(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + return !!s->exec_command[SERVICE_EXEC_RELOAD]; +} + +static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + Service *s = SERVICE(u); + + assert(u); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", service_state_to_string(s->state)); + unit_serialize_item(u, f, "result", service_result_to_string(s->result)); + unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result)); + + if (s->control_pid > 0) + unit_serialize_item_format(u, f, "control-pid", PID_FMT, + s->control_pid); + + if (s->main_pid_known && s->main_pid > 0) + unit_serialize_item_format(u, f, "main-pid", PID_FMT, s->main_pid); + + unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); + + if (s->status_text) + unit_serialize_item(u, f, "status-text", s->status_text); + + /* FIXME: There's a minor uncleanliness here: if there are + * multiple commands attached here, we will start from the + * first one again */ + if (s->control_command_id >= 0) + unit_serialize_item(u, f, "control-command", + service_exec_command_to_string(s->control_command_id)); + + if (s->socket_fd >= 0) { + int copy; + + if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0) + return copy; + + unit_serialize_item_format(u, f, "socket-fd", "%i", copy); + } + + if (s->main_exec_status.pid > 0) { + unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT, + s->main_exec_status.pid); + dual_timestamp_serialize(f, "main-exec-status-start", + &s->main_exec_status.start_timestamp); + dual_timestamp_serialize(f, "main-exec-status-exit", + &s->main_exec_status.exit_timestamp); + + if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) { + unit_serialize_item_format(u, f, "main-exec-status-code", "%i", + s->main_exec_status.code); + unit_serialize_item_format(u, f, "main-exec-status-status", "%i", + s->main_exec_status.status); + } + } + if (dual_timestamp_is_set(&s->watchdog_timestamp)) + dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); + + if (s->forbid_restart) + unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + + return 0; +} + +static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Service *s = SERVICE(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + ServiceState state; + + state = service_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + s->deserialized_state = state; + } else if (streq(key, "result")) { + ServiceResult f; + + f = service_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != SERVICE_SUCCESS) + s->result = f; + + } else if (streq(key, "reload-result")) { + ServiceResult f; + + f = service_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse reload result value %s", value); + else if (f != SERVICE_SUCCESS) + s->reload_result = f; + + } else if (streq(key, "control-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(u->id, "Failed to parse control-pid value %s", value); + else + s->control_pid = pid; + } else if (streq(key, "main-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(u->id, "Failed to parse main-pid value %s", value); + else { + service_set_main_pid(s, pid); + unit_watch_pid(UNIT(s), pid); + } + } else if (streq(key, "main-pid-known")) { + int b; + + b = parse_boolean(value); + if (b < 0) + log_debug_unit(u->id, "Failed to parse main-pid-known value %s", value); + else + s->main_pid_known = b; + } else if (streq(key, "status-text")) { + char *t; + + t = strdup(value); + if (!t) + log_oom(); + else { + free(s->status_text); + s->status_text = t; + } + + } else if (streq(key, "control-command")) { + ServiceExecCommand id; + + id = service_exec_command_from_string(value); + if (id < 0) + log_debug_unit(u->id, "Failed to parse exec-command value %s", value); + else { + s->control_command_id = id; + s->control_command = s->exec_command[id]; + } + } else if (streq(key, "socket-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse socket-fd value %s", value); + else { + + if (s->socket_fd >= 0) + close_nointr_nofail(s->socket_fd); + s->socket_fd = fdset_remove(fds, fd); + } + } else if (streq(key, "main-exec-status-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(u->id, "Failed to parse main-exec-status-pid value %s", value); + else + s->main_exec_status.pid = pid; + } else if (streq(key, "main-exec-status-code")) { + int i; + + if (safe_atoi(value, &i) < 0) + log_debug_unit(u->id, "Failed to parse main-exec-status-code value %s", value); + else + s->main_exec_status.code = i; + } else if (streq(key, "main-exec-status-status")) { + int i; + + if (safe_atoi(value, &i) < 0) + log_debug_unit(u->id, "Failed to parse main-exec-status-status value %s", value); + else + s->main_exec_status.status = i; + } else if (streq(key, "main-exec-status-start")) + dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp); + else if (streq(key, "main-exec-status-exit")) + dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp); + else if (streq(key, "watchdog-timestamp")) + dual_timestamp_deserialize(value, &s->watchdog_timestamp); + else if (streq(key, "forbid-restart")) { + int b; + + b = parse_boolean(value); + if (b < 0) + log_debug_unit(u->id, "Failed to parse forbid-restart value %s", value); + else + s->forbid_restart = b; + } else + log_debug_unit(u->id, "Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState service_active_state(Unit *u) { + const UnitActiveState *table; + + assert(u); + + table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table; + + return table[SERVICE(u)->state]; +} + +static const char *service_sub_state_to_string(Unit *u) { + assert(u); + + return service_state_to_string(SERVICE(u)->state); +} + +static bool service_check_gc(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + /* Never clean up services that still have a process around, + * even if the service is formally dead. */ + if (cgroup_good(s) > 0 || + main_pid_good(s) > 0 || + control_pid_good(s) > 0) + return true; + +#ifdef HAVE_SYSV_COMPAT + if (s->is_sysv) + return true; +#endif + + return false; +} + +_pure_ static bool service_check_snapshot(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + return (s->socket_fd < 0); +} + +static int service_retry_pid_file(Service *s) { + int r; + + assert(s->pid_file); + assert(s->state == SERVICE_START || s->state == SERVICE_START_POST); + + r = service_load_pid_file(s, false); + if (r < 0) + return r; + + service_unwatch_pid_file(s); + + service_enter_running(s, SERVICE_SUCCESS); + return 0; +} + +static int service_watch_pid_file(Service *s) { + int r; + + log_debug_unit(UNIT(s)->id, + "Setting watch for %s's PID file %s", + UNIT(s)->id, s->pid_file_pathspec->path); + r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io); + if (r < 0) + goto fail; + + /* the pidfile might have appeared just before we set the watch */ + log_debug_unit(UNIT(s)->id, + "Trying to read %s's PID file %s in case it changed", + UNIT(s)->id, s->pid_file_pathspec->path); + service_retry_pid_file(s); + + return 0; +fail: + log_error_unit(UNIT(s)->id, + "Failed to set a watch for %s's PID file %s: %s", + UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r)); + service_unwatch_pid_file(s); + return r; +} + +static int service_demand_pid_file(Service *s) { + PathSpec *ps; + + assert(s->pid_file); + assert(!s->pid_file_pathspec); + + ps = new0(PathSpec, 1); + if (!ps) + return -ENOMEM; + + ps->unit = UNIT(s); + ps->path = strdup(s->pid_file); + if (!ps->path) { + free(ps); + return -ENOMEM; + } + + path_kill_slashes(ps->path); + + /* PATH_CHANGED would not be enough. There are daemons (sendmail) that + * keep their PID file open all the time. */ + ps->type = PATH_MODIFIED; + ps->inotify_fd = -1; + + s->pid_file_pathspec = ps; + + return service_watch_pid_file(s); +} + +static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata) { + PathSpec *p = userdata; + Service *s; + + assert(p); + + s = SERVICE(p->unit); + + assert(s); + assert(fd >= 0); + assert(s->state == SERVICE_START || s->state == SERVICE_START_POST); + assert(s->pid_file_pathspec); + assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd)); + + log_debug_unit(UNIT(s)->id, "inotify event for %s", UNIT(s)->id); + + if (path_spec_fd_event(p, events) < 0) + goto fail; + + if (service_retry_pid_file(s) == 0) + return 0; + + if (service_watch_pid_file(s) < 0) + goto fail; + + return 0; + +fail: + service_unwatch_pid_file(s); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES); + return 0; +} + +static void service_notify_cgroup_empty_event(Unit *u) { + Service *s = SERVICE(u); + + assert(u); + + log_debug_unit(u->id, "%s: cgroup is empty", u->id); + + switch (s->state) { + + /* Waiting for SIGCHLD is usually more interesting, + * because it includes return codes/signals. Which is + * why we ignore the cgroup events for most cases, + * except when we don't know pid which to expect the + * SIGCHLD for. */ + + case SERVICE_START: + case SERVICE_START_POST: + /* If we were hoping for the daemon to write its PID file, + * we can give up now. */ + if (s->pid_file_pathspec) { + log_warning_unit(u->id, + "%s never wrote its PID file. Failing.", UNIT(s)->id); + service_unwatch_pid_file(s); + if (s->state == SERVICE_START) + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + else + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); + } + break; + + case SERVICE_RUNNING: + /* service_enter_running() will figure out what to do */ + service_enter_running(s, SERVICE_SUCCESS); + break; + + case SERVICE_STOP_SIGTERM: + case SERVICE_STOP_SIGKILL: + + if (main_pid_good(s) <= 0 && !control_pid_good(s)) + service_enter_stop_post(s, SERVICE_SUCCESS); + + break; + + case SERVICE_STOP_POST: + case SERVICE_FINAL_SIGTERM: + case SERVICE_FINAL_SIGKILL: + if (main_pid_good(s) <= 0 && !control_pid_good(s)) + service_enter_dead(s, SERVICE_SUCCESS, true); + + break; + + default: + ; + } +} + +static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + Service *s = SERVICE(u); + ServiceResult f; + + assert(s); + assert(pid >= 0); + + if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) : + is_clean_exit_lsb(code, status, &s->success_status)) + f = SERVICE_SUCCESS; + else if (code == CLD_EXITED) + f = SERVICE_FAILURE_EXIT_CODE; + else if (code == CLD_KILLED) + f = SERVICE_FAILURE_SIGNAL; + else if (code == CLD_DUMPED) + f = SERVICE_FAILURE_CORE_DUMP; + else + assert_not_reached("Unknown code"); + + if (s->main_pid == pid) { + /* Forking services may occasionally move to a new PID. + * As long as they update the PID file before exiting the old + * PID, they're fine. */ + if (service_load_pid_file(s, false) == 0) + return; + + s->main_pid = 0; + exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status); + + if (s->main_command) { + /* If this is not a forking service than the + * main process got started and hence we copy + * the exit status so that it is recorded both + * as main and as control process exit + * status */ + + s->main_command->exec_status = s->main_exec_status; + + if (s->main_command->ignore) + f = SERVICE_SUCCESS; + } else if (s->exec_command[SERVICE_EXEC_START]) { + + /* If this is a forked process, then we should + * ignore the return value if this was + * configured for the starter process */ + + if (s->exec_command[SERVICE_EXEC_START]->ignore) + f = SERVICE_SUCCESS; + } + + log_struct_unit(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, + u->id, + "MESSAGE=%s: main process exited, code=%s, status=%i/%s", + u->id, sigchld_code_to_string(code), status, + strna(code == CLD_EXITED + ? exit_status_to_string(status, EXIT_STATUS_FULL) + : signal_to_string(status)), + "EXIT_CODE=%s", sigchld_code_to_string(code), + "EXIT_STATUS=%i", status, + NULL); + + if (f != SERVICE_SUCCESS) + s->result = f; + + if (s->main_command && + s->main_command->command_next && + f == SERVICE_SUCCESS) { + + /* There is another command to * + * execute, so let's do that. */ + + log_debug_unit(u->id, + "%s running next main command for state %s", + u->id, service_state_to_string(s->state)); + service_run_next_main(s); + + } else { + + /* The service exited, so the service is officially + * gone. */ + s->main_command = NULL; + + switch (s->state) { + + case SERVICE_START_POST: + case SERVICE_RELOAD: + case SERVICE_STOP: + /* Need to wait until the operation is + * done */ + break; + + case SERVICE_START: + if (s->type == SERVICE_ONESHOT) { + /* This was our main goal, so let's go on */ + if (f == SERVICE_SUCCESS) + service_enter_start_post(s); + else + service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + break; + } + + /* Fall through */ + + case SERVICE_RUNNING: + service_enter_running(s, f); + break; + + case SERVICE_STOP_SIGTERM: + case SERVICE_STOP_SIGKILL: + + if (!control_pid_good(s)) + service_enter_stop_post(s, f); + + /* If there is still a control process, wait for that first */ + break; + + case SERVICE_STOP_POST: + case SERVICE_FINAL_SIGTERM: + case SERVICE_FINAL_SIGKILL: + + if (!control_pid_good(s)) + service_enter_dead(s, f, true); + break; + + default: + assert_not_reached("Uh, main process died at wrong time."); + } + } + + } else if (s->control_pid == pid) { + s->control_pid = 0; + + if (s->control_command) { + exec_status_exit(&s->control_command->exec_status, + &s->exec_context, pid, code, status); + + if (s->control_command->ignore) + f = SERVICE_SUCCESS; + } + + log_full_unit(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, u->id, + "%s: control process exited, code=%s status=%i", + u->id, sigchld_code_to_string(code), status); + + if (f != SERVICE_SUCCESS) + s->result = f; + + /* Immediately get rid of the cgroup, so that the + * kernel doesn't delay the cgroup empty messages for + * the service cgroup any longer than necessary */ + service_kill_control_processes(s); + + if (s->control_command && + s->control_command->command_next && + f == SERVICE_SUCCESS) { + + /* There is another command to * + * execute, so let's do that. */ + + log_debug_unit(u->id, + "%s running next control command for state %s", + u->id, service_state_to_string(s->state)); + service_run_next_control(s); + + } else { + /* No further commands for this step, so let's + * figure out what to do next */ + + s->control_command = NULL; + s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; + + log_debug_unit(u->id, + "%s got final SIGCHLD for state %s", + u->id, service_state_to_string(s->state)); + + switch (s->state) { + + case SERVICE_START_PRE: + if (f == SERVICE_SUCCESS) + service_enter_start(s); + else + service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + break; + + case SERVICE_START: + if (s->type != SERVICE_FORKING) + /* Maybe spurious event due to a reload that changed the type? */ + break; + + if (f != SERVICE_SUCCESS) { + service_enter_signal(s, SERVICE_FINAL_SIGTERM, f); + break; + } + + if (s->pid_file) { + bool has_start_post; + int r; + + /* Let's try to load the pid file here if we can. + * The PID file might actually be created by a START_POST + * script. In that case don't worry if the loading fails. */ + + has_start_post = !!s->exec_command[SERVICE_EXEC_START_POST]; + r = service_load_pid_file(s, !has_start_post); + if (!has_start_post && r < 0) { + r = service_demand_pid_file(s); + if (r < 0 || !cgroup_good(s)) + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES); + break; + } + } else + service_search_main_pid(s); + + service_enter_start_post(s); + break; + + case SERVICE_START_POST: + if (f != SERVICE_SUCCESS) { + service_enter_stop(s, f); + break; + } + + if (s->pid_file) { + int r; + + r = service_load_pid_file(s, true); + if (r < 0) { + r = service_demand_pid_file(s); + if (r < 0 || !cgroup_good(s)) + service_enter_stop(s, SERVICE_FAILURE_RESOURCES); + break; + } + } else + service_search_main_pid(s); + + service_enter_running(s, SERVICE_SUCCESS); + break; + + case SERVICE_RELOAD: + if (f == SERVICE_SUCCESS) { + service_load_pid_file(s, true); + service_search_main_pid(s); + } + + s->reload_result = f; + service_enter_running(s, SERVICE_SUCCESS); + break; + + case SERVICE_STOP: + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); + break; + + case SERVICE_STOP_SIGTERM: + case SERVICE_STOP_SIGKILL: + if (main_pid_good(s) <= 0) + service_enter_stop_post(s, f); + + /* If there is still a service + * process around, wait until + * that one quit, too */ + break; + + case SERVICE_STOP_POST: + case SERVICE_FINAL_SIGTERM: + case SERVICE_FINAL_SIGKILL: + if (main_pid_good(s) <= 0) + service_enter_dead(s, f, true); + break; + + default: + assert_not_reached("Uh, control process died at wrong time."); + } + } + } + + /* Notify clients about changed exit status */ + unit_add_to_dbus_queue(u); + + /* We got one SIGCHLD for the service, let's watch all + * processes that are now running of the service, and watch + * that. Among the PIDs we then watch will be children + * reassigned to us, which hopefully allows us to identify + * when all children are gone */ + unit_tidy_watch_pids(u, s->main_pid, s->control_pid); + unit_watch_all_pids(u); + + /* If the PID set is empty now, then let's finish this off */ + if (set_isempty(u->pids)) + service_notify_cgroup_empty_event(u); +} + +static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Service *s = SERVICE(userdata); + + assert(s); + assert(source == s->timer_event_source); + + switch (s->state) { + + case SERVICE_START_PRE: + case SERVICE_START: + log_warning_unit(UNIT(s)->id, + "%s %s operation timed out. Terminating.", + UNIT(s)->id, + s->state == SERVICE_START ? "start" : "start-pre"); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_START_POST: + log_warning_unit(UNIT(s)->id, + "%s start-post operation timed out. Stopping.", UNIT(s)->id); + service_enter_stop(s, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_RELOAD: + log_warning_unit(UNIT(s)->id, + "%s reload operation timed out. Stopping.", UNIT(s)->id); + s->reload_result = SERVICE_FAILURE_TIMEOUT; + service_enter_running(s, SERVICE_SUCCESS); + break; + + case SERVICE_STOP: + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Terminating.", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_STOP_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, + "%s stop-sigterm timed out. Killing.", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, + "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id); + service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); + } + + break; + + case SERVICE_STOP_SIGKILL: + /* Uh, we sent a SIGKILL and it is still not gone? + * Must be something we cannot kill, so let's just be + * weirded out and continue */ + + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); + service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_STOP_POST: + log_warning_unit(UNIT(s)->id, + "%s stop-post timed out. Terminating.", UNIT(s)->id); + service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_FINAL_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, + "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id); + service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, + "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", + UNIT(s)->id); + service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false); + } + + break; + + case SERVICE_FINAL_SIGKILL: + log_warning_unit(UNIT(s)->id, + "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id); + service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true); + break; + + case SERVICE_AUTO_RESTART: + log_info_unit(UNIT(s)->id, + s->restart_usec > 0 ? + "%s holdoff time over, scheduling restart." : + "%s has no holdoff time, scheduling restart.", + UNIT(s)->id); + service_enter_restart(s); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) { + Service *s = SERVICE(userdata); + + assert(s); + assert(source == s->watchdog_event_source); + + log_error_unit(UNIT(s)->id, "%s watchdog timeout!", UNIT(s)->id); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_WATCHDOG); + + return 0; +} + +static void service_notify_message(Unit *u, pid_t pid, char **tags) { + Service *s = SERVICE(u); + const char *e; + bool notify_dbus = false; + + assert(u); + + log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT" (%s...)", + u->id, pid, tags && *tags ? tags[0] : "(empty)"); + + if (s->notify_access == NOTIFY_NONE) { + log_warning_unit(u->id, + "%s: Got notification message from PID "PID_FMT", but reception is disabled.", + u->id, pid); + return; + } + + if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) { + + if (s->main_pid != 0) + log_warning_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, u->id, pid, s->main_pid); + else + log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", u->id, pid); + return; + } + + /* Interpret MAINPID= */ + if ((e = strv_find_prefix(tags, "MAINPID=")) && + (s->state == SERVICE_START || + s->state == SERVICE_START_POST || + s->state == SERVICE_RUNNING || + s->state == SERVICE_RELOAD)) { + + if (parse_pid(e + 8, &pid) < 0) + log_warning_unit(u->id, "Failed to parse notification message %s", e); + else { + log_debug_unit(u->id, "%s: got %s", u->id, e); + service_set_main_pid(s, pid); + unit_watch_pid(UNIT(s), pid); + notify_dbus = true; + } + } + + /* Interpret READY= */ + if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START && strv_find(tags, "READY=1")) { + log_debug_unit(u->id, "%s: got READY=1", u->id); + service_enter_start_post(s); + notify_dbus = true; + } + + /* Interpret STATUS= */ + e = strv_find_prefix(tags, "STATUS="); + if (e) { + char *t; + + if (e[7]) { + if (!utf8_is_valid(e+7)) { + log_warning_unit(u->id, "Status message in notification is not UTF-8 clean."); + return; + } + + log_debug_unit(u->id, "%s: got %s", u->id, e); + + t = strdup(e+7); + if (!t) { + log_oom(); + return; + } + + } else + t = NULL; + + if (!streq_ptr(s->status_text, t)) { + free(s->status_text); + s->status_text = t; + notify_dbus = true; + } else + free(t); + } + + /* Interpet WATCHDOG= */ + if (strv_find(tags, "WATCHDOG=1")) { + log_debug_unit(u->id, "%s: got WATCHDOG=1", u->id); + service_reset_watchdog(s); + } + + /* Notify clients about changed status or main pid */ + if (notify_dbus) + unit_add_to_dbus_queue(u); +} + +static int service_get_timeout(Unit *u, uint64_t *timeout) { + Service *s = SERVICE(u); + int r; + + if (!s->timer_event_source) + return 0; + + r = sd_event_source_get_time(s->timer_event_source, timeout); + if (r < 0) + return r; + + return 1; +} + +#ifdef HAVE_SYSV_COMPAT + +static int service_enumerate(Manager *m) { + char **p; + unsigned i; + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *path = NULL, *fpath = NULL, *name = NULL; + Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; + _cleanup_set_free_ Set *shutdown_services = NULL; + Unit *service; + Iterator j; + int r; + + assert(m); + + if (m->running_as != SYSTEMD_SYSTEM) + return 0; + + STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path) + for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { + struct dirent *de; + + free(path); + path = strjoin(*p, "/", rcnd_table[i].path, NULL); + if (!path) { + r = -ENOMEM; + goto finish; + } + + if (d) + closedir(d); + + d = opendir(path); + if (!d) { + if (errno != ENOENT) + log_warning("opendir(%s) failed: %m", path); + + continue; + } + + while ((de = readdir(d))) { + int a, b; + + if (ignore_file(de->d_name)) + continue; + + if (de->d_name[0] != 'S' && de->d_name[0] != 'K') + continue; + + if (strlen(de->d_name) < 4) + continue; + + a = undecchar(de->d_name[1]); + b = undecchar(de->d_name[2]); + + if (a < 0 || b < 0) + continue; + + free(fpath); + fpath = strjoin(path, "/", de->d_name, NULL); + if (!fpath) { + r = -ENOMEM; + goto finish; + } + + if (access(fpath, X_OK) < 0) { + + if (errno != ENOENT) + log_warning("access() failed on %s: %m", fpath); + + continue; + } + + free(name); + name = sysv_translate_name(de->d_name + 3); + if (!name) { + r = log_oom(); + goto finish; + } + + r = manager_load_unit_prepare(m, name, NULL, NULL, &service); + if (r < 0) { + log_warning("Failed to prepare unit %s: %s", name, strerror(-r)); + continue; + } + + if (de->d_name[0] == 'S') { + + if (rcnd_table[i].type == RUNLEVEL_UP) { + SERVICE(service)->sysv_start_priority_from_rcnd = + MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd); + + SERVICE(service)->sysv_enabled = true; + } + + r = set_ensure_allocated(&runlevel_services[i], + trivial_hash_func, trivial_compare_func); + if (r < 0) + goto finish; + + r = set_put(runlevel_services[i], service); + if (r < 0) + goto finish; + + } else if (de->d_name[0] == 'K' && + (rcnd_table[i].type == RUNLEVEL_DOWN)) { + + r = set_ensure_allocated(&shutdown_services, + trivial_hash_func, trivial_compare_func); + if (r < 0) + goto finish; + + r = set_put(shutdown_services, service); + if (r < 0) + goto finish; + } + } + } + + /* Now we loaded all stubs and are aware of the lowest + start-up priority for all services, not let's actually load + the services, this will also tell us which services are + actually native now */ + manager_dispatch_load_queue(m); + + /* If this is a native service, rely on native ways to pull in + * a service, don't pull it in via sysv rcN.d links. */ + for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) + SET_FOREACH(service, runlevel_services[i], j) { + service = unit_follow_merge(service); + + if (service->fragment_path) + continue; + + r = unit_add_two_dependencies_by_name_inverse( + service, UNIT_AFTER, UNIT_WANTS, + rcnd_table[i].target, NULL, true); + if (r < 0) + goto finish; + } + + /* We honour K links only for halt/reboot. For the normal + * runlevels we assume the stop jobs will be implicitly added + * by the core logic. Also, we don't really distinguish here + * between the runlevels 0 and 6 and just add them to the + * special shutdown target. */ + SET_FOREACH(service, shutdown_services, j) { + service = unit_follow_merge(service); + + if (service->fragment_path) + continue; + + r = unit_add_two_dependencies_by_name( + service, UNIT_BEFORE, UNIT_CONFLICTS, + SPECIAL_SHUTDOWN_TARGET, NULL, true); + if (r < 0) + goto finish; + } + + r = 0; + +finish: + + for (i = 0; i < ELEMENTSOF(rcnd_table); i++) + set_free(runlevel_services[i]); + + return r; +} +#endif + +static void service_bus_name_owner_change( + Unit *u, + const char *name, + const char *old_owner, + const char *new_owner) { + + Service *s = SERVICE(u); + int r; + + assert(s); + assert(name); + + assert(streq(s->bus_name, name)); + assert(old_owner || new_owner); + + if (old_owner && new_owner) + log_debug_unit(u->id, + "%s's D-Bus name %s changed owner from %s to %s", + u->id, name, old_owner, new_owner); + else if (old_owner) + log_debug_unit(u->id, + "%s's D-Bus name %s no longer registered by %s", + u->id, name, old_owner); + else + log_debug_unit(u->id, + "%s's D-Bus name %s now registered by %s", + u->id, name, new_owner); + + s->bus_name_good = !!new_owner; + + if (s->type == SERVICE_DBUS) { + + /* service_enter_running() will figure out what to + * do */ + if (s->state == SERVICE_RUNNING) + service_enter_running(s, SERVICE_SUCCESS); + else if (s->state == SERVICE_START && new_owner) + service_enter_start_post(s); + + } else if (new_owner && + s->main_pid <= 0 && + (s->state == SERVICE_START || + s->state == SERVICE_START_POST || + s->state == SERVICE_RUNNING || + s->state == SERVICE_RELOAD)) { + + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + pid_t pid; + + /* Try to acquire PID from bus service */ + + r = sd_bus_get_owner(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds); + if (r >= 0) + r = sd_bus_creds_get_pid(creds, &pid); + if (r >= 0) { + log_debug_unit(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid); + + service_set_main_pid(s, pid); + unit_watch_pid(UNIT(s), pid); + } + } +} + +int service_set_socket_fd(Service *s, int fd, Socket *sock) { + _cleanup_free_ char *peer = NULL; + int r; + + assert(s); + assert(fd >= 0); + + /* This is called by the socket code when instantiating a new + * service for a stream socket and the socket needs to be + * configured. */ + + if (UNIT(s)->load_state != UNIT_LOADED) + return -EINVAL; + + if (s->socket_fd >= 0) + return -EBUSY; + + if (s->state != SERVICE_DEAD) + return -EAGAIN; + + if (getpeername_pretty(fd, &peer) >= 0) { + + if (UNIT(s)->description) { + _cleanup_free_ char *a; + + a = strjoin(UNIT(s)->description, " (", peer, ")", NULL); + if (!a) + return -ENOMEM; + + r = unit_set_description(UNIT(s), a); + } else + r = unit_set_description(UNIT(s), peer); + + if (r < 0) + return r; + } + + s->socket_fd = fd; + + unit_ref_set(&s->accept_socket, UNIT(sock)); + + return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); +} + +static void service_reset_failed(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + if (s->state == SERVICE_FAILED) + service_set_state(s, SERVICE_DEAD); + + s->result = SERVICE_SUCCESS; + s->reload_result = SERVICE_SUCCESS; + + RATELIMIT_RESET(s->start_limit); +} + +static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + Service *s = SERVICE(u); + + return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error); +} + +static const char* const service_state_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = "dead", + [SERVICE_START_PRE] = "start-pre", + [SERVICE_START] = "start", + [SERVICE_START_POST] = "start-post", + [SERVICE_RUNNING] = "running", + [SERVICE_EXITED] = "exited", + [SERVICE_RELOAD] = "reload", + [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGTERM] = "stop-sigterm", + [SERVICE_STOP_SIGKILL] = "stop-sigkill", + [SERVICE_STOP_POST] = "stop-post", + [SERVICE_FINAL_SIGTERM] = "final-sigterm", + [SERVICE_FINAL_SIGKILL] = "final-sigkill", + [SERVICE_FAILED] = "failed", + [SERVICE_AUTO_RESTART] = "auto-restart", +}; + +DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + +static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { + [SERVICE_RESTART_NO] = "no", + [SERVICE_RESTART_ON_SUCCESS] = "on-success", + [SERVICE_RESTART_ON_FAILURE] = "on-failure", + [SERVICE_RESTART_ON_WATCHDOG] = "on-watchdog", + [SERVICE_RESTART_ON_ABORT] = "on-abort", + [SERVICE_RESTART_ALWAYS] = "always" +}; + +DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart); + +static const char* const service_type_table[_SERVICE_TYPE_MAX] = { + [SERVICE_SIMPLE] = "simple", + [SERVICE_FORKING] = "forking", + [SERVICE_ONESHOT] = "oneshot", + [SERVICE_DBUS] = "dbus", + [SERVICE_NOTIFY] = "notify", + [SERVICE_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType); + +static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = { + [SERVICE_EXEC_START_PRE] = "ExecStartPre", + [SERVICE_EXEC_START] = "ExecStart", + [SERVICE_EXEC_START_POST] = "ExecStartPost", + [SERVICE_EXEC_RELOAD] = "ExecReload", + [SERVICE_EXEC_STOP] = "ExecStop", + [SERVICE_EXEC_STOP_POST] = "ExecStopPost", +}; + +DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand); + +static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { + [NOTIFY_NONE] = "none", + [NOTIFY_MAIN] = "main", + [NOTIFY_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); + +static const char* const service_result_table[_SERVICE_RESULT_MAX] = { + [SERVICE_SUCCESS] = "success", + [SERVICE_FAILURE_RESOURCES] = "resources", + [SERVICE_FAILURE_TIMEOUT] = "timeout", + [SERVICE_FAILURE_EXIT_CODE] = "exit-code", + [SERVICE_FAILURE_SIGNAL] = "signal", + [SERVICE_FAILURE_CORE_DUMP] = "core-dump", + [SERVICE_FAILURE_WATCHDOG] = "watchdog", + [SERVICE_FAILURE_START_LIMIT] = "start-limit" +}; + +DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); + +static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = { + [SERVICE_START_LIMIT_NONE] = "none", + [SERVICE_START_LIMIT_REBOOT] = "reboot", + [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force", + [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate" +}; +DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction); + +const UnitVTable service_vtable = { + .object_size = sizeof(Service), + .exec_context_offset = offsetof(Service, exec_context), + .cgroup_context_offset = offsetof(Service, cgroup_context), + .kill_context_offset = offsetof(Service, kill_context), + .exec_runtime_offset = offsetof(Service, exec_runtime), + + .sections = + "Unit\0" + "Service\0" + "Install\0", + .private_section = "Service", + + .init = service_init, + .done = service_done, + .load = service_load, + + .coldplug = service_coldplug, + + .dump = service_dump, + + .start = service_start, + .stop = service_stop, + .reload = service_reload, + + .can_reload = service_can_reload, + + .kill = service_kill, + + .serialize = service_serialize, + .deserialize_item = service_deserialize_item, + + .active_state = service_active_state, + .sub_state_to_string = service_sub_state_to_string, + + .check_gc = service_check_gc, + .check_snapshot = service_check_snapshot, + + .sigchld_event = service_sigchld_event, + + .reset_failed = service_reset_failed, + + .notify_cgroup_empty = service_notify_cgroup_empty_event, + .notify_message = service_notify_message, + + .bus_name_owner_change = service_bus_name_owner_change, + + .bus_interface = "org.freedesktop.systemd1.Service", + .bus_vtable = bus_service_vtable, + .bus_set_property = bus_service_set_property, + .bus_commit_properties = bus_service_commit_properties, + + .get_timeout = service_get_timeout, + +#ifdef HAVE_SYSV_COMPAT + .enumerate = service_enumerate, +#endif + + .can_transient = true, + + .status_message_formats = { + .starting_stopping = { + [0] = "Starting %s...", + [1] = "Stopping %s...", + }, + .finished_start_job = { + [JOB_DONE] = "Started %s.", + [JOB_FAILED] = "Failed to start %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_TIMEOUT] = "Timed out starting %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Stopped %s.", + [JOB_FAILED] = "Stopped (with error) %s.", + [JOB_TIMEOUT] = "Timed out stopping %s.", + }, + }, +}; diff --git a/src/core/service.h b/src/core/service.h new file mode 100644 index 0000000..1992926 --- /dev/null +++ b/src/core/service.h @@ -0,0 +1,226 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Service Service; + +#include "unit.h" +#include "path.h" +#include "ratelimit.h" +#include "kill.h" +#include "exit-status.h" + +typedef enum ServiceState { + SERVICE_DEAD, + SERVICE_START_PRE, + SERVICE_START, + SERVICE_START_POST, + SERVICE_RUNNING, + SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ + SERVICE_RELOAD, + SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ + SERVICE_STOP_SIGTERM, + SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ + SERVICE_FINAL_SIGKILL, + SERVICE_FAILED, + SERVICE_AUTO_RESTART, + _SERVICE_STATE_MAX, + _SERVICE_STATE_INVALID = -1 +} ServiceState; + +typedef enum ServiceRestart { + SERVICE_RESTART_NO, + SERVICE_RESTART_ON_SUCCESS, + SERVICE_RESTART_ON_FAILURE, + SERVICE_RESTART_ON_WATCHDOG, + SERVICE_RESTART_ON_ABORT, + SERVICE_RESTART_ALWAYS, + _SERVICE_RESTART_MAX, + _SERVICE_RESTART_INVALID = -1 +} ServiceRestart; + +typedef enum ServiceType { + SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */ + SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */ + SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */ + SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */ + SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */ + SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */ + _SERVICE_TYPE_MAX, + _SERVICE_TYPE_INVALID = -1 +} ServiceType; + +typedef enum ServiceExecCommand { + SERVICE_EXEC_START_PRE, + SERVICE_EXEC_START, + SERVICE_EXEC_START_POST, + SERVICE_EXEC_RELOAD, + SERVICE_EXEC_STOP, + SERVICE_EXEC_STOP_POST, + _SERVICE_EXEC_COMMAND_MAX, + _SERVICE_EXEC_COMMAND_INVALID = -1 +} ServiceExecCommand; + +typedef enum NotifyAccess { + NOTIFY_NONE, + NOTIFY_ALL, + NOTIFY_MAIN, + _NOTIFY_ACCESS_MAX, + _NOTIFY_ACCESS_INVALID = -1 +} NotifyAccess; + +typedef enum ServiceResult { + SERVICE_SUCCESS, + SERVICE_FAILURE_RESOURCES, + SERVICE_FAILURE_TIMEOUT, + SERVICE_FAILURE_EXIT_CODE, + SERVICE_FAILURE_SIGNAL, + SERVICE_FAILURE_CORE_DUMP, + SERVICE_FAILURE_WATCHDOG, + SERVICE_FAILURE_START_LIMIT, + _SERVICE_RESULT_MAX, + _SERVICE_RESULT_INVALID = -1 +} ServiceResult; + +typedef enum StartLimitAction { + SERVICE_START_LIMIT_NONE, + SERVICE_START_LIMIT_REBOOT, + SERVICE_START_LIMIT_REBOOT_FORCE, + SERVICE_START_LIMIT_REBOOT_IMMEDIATE, + _SERVICE_START_LIMIT_MAX, + _SERVICE_START_LIMIT_INVALID = -1 +} StartLimitAction; + +struct Service { + Unit meta; + + ServiceType type; + ServiceRestart restart; + ExitStatusSet restart_ignore_status; + ExitStatusSet success_status; + + /* If set we'll read the main daemon PID from this file */ + char *pid_file; + + usec_t restart_usec; + usec_t timeout_start_usec; + usec_t timeout_stop_usec; + + dual_timestamp watchdog_timestamp; + usec_t watchdog_usec; + sd_event_source *watchdog_event_source; + + ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; + + ExecContext exec_context; + KillContext kill_context; + CGroupContext cgroup_context; + + ServiceState state, deserialized_state; + + /* The exit status of the real main process */ + ExecStatus main_exec_status; + + /* The currently executed control process */ + ExecCommand *control_command; + + /* The currently executed main process, which may be NULL if + * the main process got started via forking mode and not by + * us */ + ExecCommand *main_command; + + /* The ID of the control command currently being executed */ + ServiceExecCommand control_command_id; + + /* Runtime data of the execution context */ + ExecRuntime *exec_runtime; + + pid_t main_pid, control_pid; + int socket_fd; + + bool permissions_start_only; + bool root_directory_start_only; + bool remain_after_exit; + bool guess_main_pid; + + /* If we shut down, remember why */ + ServiceResult result; + ServiceResult reload_result; + + bool main_pid_known:1; + bool main_pid_alien:1; + bool bus_name_good:1; + bool forbid_restart:1; + bool start_timeout_defined:1; +#ifdef HAVE_SYSV_COMPAT + bool is_sysv:1; + bool sysv_has_lsb:1; + bool sysv_enabled:1; + int sysv_start_priority_from_rcnd; + int sysv_start_priority; + + char *sysv_runlevels; +#endif + + char *bus_name; + + char *status_text; + + RateLimit start_limit; + StartLimitAction start_limit_action; + + UnitRef accept_socket; + + sd_event_source *timer_event_source; + PathSpec *pid_file_pathspec; + + NotifyAccess notify_access; +}; + +extern const UnitVTable service_vtable; + +struct Socket; + +int service_set_socket_fd(Service *s, int fd, struct Socket *socket); + +const char* service_state_to_string(ServiceState i) _const_; +ServiceState service_state_from_string(const char *s) _pure_; + +const char* service_restart_to_string(ServiceRestart i) _const_; +ServiceRestart service_restart_from_string(const char *s) _pure_; + +const char* service_type_to_string(ServiceType i) _const_; +ServiceType service_type_from_string(const char *s) _pure_; + +const char* service_exec_command_to_string(ServiceExecCommand i) _const_; +ServiceExecCommand service_exec_command_from_string(const char *s) _pure_; + +const char* notify_access_to_string(NotifyAccess i) _const_; +NotifyAccess notify_access_from_string(const char *s) _pure_; + +const char* service_result_to_string(ServiceResult i) _const_; +ServiceResult service_result_from_string(const char *s) _pure_; + +const char* start_limit_action_to_string(StartLimitAction i) _const_; +StartLimitAction start_limit_action_from_string(const char *s) _pure_; diff --git a/src/core/shutdown.c b/src/core/shutdown.c new file mode 100644 index 0000000..c751030 --- /dev/null +++ b/src/core/shutdown.c @@ -0,0 +1,467 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 ProFUSION embedded systems + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "missing.h" +#include "log.h" +#include "fileio.h" +#include "umount.h" +#include "util.h" +#include "mkdir.h" +#include "virt.h" +#include "watchdog.h" +#include "killall.h" +#include "cgroup-util.h" +#include "def.h" + +#define FINALIZE_ATTEMPTS 50 + +static char* arg_verb; + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_LOG_LEVEL = 0x100, + ARG_LOG_TARGET, + ARG_LOG_COLOR, + ARG_LOG_LOCATION, + }; + + static const struct option options[] = { + { "log-level", required_argument, NULL, ARG_LOG_LEVEL }, + { "log-target", required_argument, NULL, ARG_LOG_TARGET }, + { "log-color", optional_argument, NULL, ARG_LOG_COLOR }, + { "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, + {} + }; + + int c, r; + + assert(argc >= 1); + assert(argv); + + opterr = 0; + + while ((c = getopt_long(argc, argv, ":", options, NULL)) >= 0) + switch (c) { + + case ARG_LOG_LEVEL: + r = log_set_max_level_from_string(optarg); + if (r < 0) + log_error("Failed to parse log level %s, ignoring.", optarg); + + break; + + case ARG_LOG_TARGET: + r = log_set_target_from_string(optarg); + if (r < 0) + log_error("Failed to parse log target %s, ignoring", optarg); + + break; + + case ARG_LOG_COLOR: + + if (optarg) { + r = log_show_color_from_string(optarg); + if (r < 0) + log_error("Failed to parse log color setting %s, ignoring", optarg); + } else + log_show_color(true); + + break; + + case ARG_LOG_LOCATION: + if (optarg) { + r = log_show_location_from_string(optarg); + if (r < 0) + log_error("Failed to parse log location setting %s, ignoring", optarg); + } else + log_show_location(true); + + break; + + case '?': + log_error("Unknown option %s.", argv[optind-1]); + return -EINVAL; + + case ':': + log_error("Missing argument to %s.", argv[optind-1]); + return -EINVAL; + + default: + assert_not_reached("Unhandled option code."); + } + + if (optind >= argc) { + log_error("Verb argument missing."); + return -EINVAL; + } + + arg_verb = argv[optind]; + + if (optind + 1 < argc) + log_error("Excess arguments, ignoring"); + return 0; +} + +static int prepare_new_root(void) { + static const char dirs[] = + "/run/initramfs/oldroot\0" + "/run/initramfs/proc\0" + "/run/initramfs/sys\0" + "/run/initramfs/dev\0" + "/run/initramfs/run\0"; + + const char *dir; + + if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m"); + return -errno; + } + + if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) { + log_error("Failed to make /run/initramfs private mount: %m"); + return -errno; + } + + NULSTR_FOREACH(dir, dirs) + if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) { + log_error("Failed to mkdir %s: %m", dir); + return -errno; + } + + if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /sys on /run/initramfs/sys: %m"); + return -errno; + } + + if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /proc on /run/initramfs/proc: %m"); + return -errno; + } + + if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /dev on /run/initramfs/dev: %m"); + return -errno; + } + + if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) { + log_error("Failed to mount bind /run on /run/initramfs/run: %m"); + return -errno; + } + + return 0; +} + +static int pivot_to_new_root(void) { + + if (chdir("/run/initramfs") < 0) { + log_error("Failed to change directory to /run/initramfs: %m"); + return -errno; + } + + /* Work-around for a kernel bug: for some reason the kernel + * refuses switching root if any file systems are mounted + * MS_SHARED. Hence remount them MS_PRIVATE here as a + * work-around. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ + if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) + log_warning("Failed to make \"/\" private mount: %m"); + + if (pivot_root(".", "oldroot") < 0) { + log_error("pivot failed: %m"); + /* only chroot if pivot root succeeded */ + return -errno; + } + + chroot("."); + + setsid(); + make_console_stdio(); + + log_info("Successfully changed into root pivot."); + + return 0; +} + +int main(int argc, char *argv[]) { + bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; + bool in_container, use_watchdog = false; + _cleanup_free_ char *cgroup = NULL; + char *arguments[3]; + unsigned retries; + int cmd, r; + + log_parse_environment(); + r = parse_argv(argc, argv); + if (r < 0) + goto error; + + /* journald will die if not gone yet. The log target defaults + * to console, but may have been changed by commandline options. */ + + log_close_console(); /* force reopen of /dev/console */ + log_open(); + + umask(0022); + + if (getpid() != 1) { + log_error("Not executed by init (PID 1)."); + r = -EPERM; + goto error; + } + + in_container = detect_container(NULL) > 0; + + if (streq(arg_verb, "reboot")) + cmd = RB_AUTOBOOT; + else if (streq(arg_verb, "poweroff")) + cmd = RB_POWER_OFF; + else if (streq(arg_verb, "halt")) + cmd = RB_HALT_SYSTEM; + else if (streq(arg_verb, "kexec")) + cmd = LINUX_REBOOT_CMD_KEXEC; + else { + r = -EINVAL; + log_error("Unknown action '%s'.", arg_verb); + goto error; + } + + cg_get_root_path(&cgroup); + + use_watchdog = !!getenv("WATCHDOG_USEC"); + + /* lock us into memory */ + mlockall(MCL_CURRENT|MCL_FUTURE); + + log_info("Sending SIGTERM to remaining processes..."); + broadcast_signal(SIGTERM, true, true); + + log_info("Sending SIGKILL to remaining processes..."); + broadcast_signal(SIGKILL, true, false); + + if (in_container) { + need_swapoff = false; + need_dm_detach = false; + need_loop_detach = false; + } + + /* Unmount all mountpoints, swaps, and loopback devices */ + for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { + bool changed = false; + + if (use_watchdog) + 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); + + if (need_umount) { + log_info("Unmounting file systems."); + r = umount_all(&changed); + if (r == 0) { + need_umount = false; + log_info("All filesystems unmounted."); + } else if (r > 0) + log_info("Not all file systems unmounted, %d left.", r); + else + log_error("Failed to unmount file systems: %s", strerror(-r)); + } + + if (need_swapoff) { + log_info("Deactivating swaps."); + r = swapoff_all(&changed); + if (r == 0) { + need_swapoff = false; + log_info("All swaps deactivated."); + } else if (r > 0) + log_info("Not all swaps deactivated, %d left.", r); + else + log_error("Failed to deactivate swaps: %s", strerror(-r)); + } + + if (need_loop_detach) { + log_info("Detaching loop devices."); + r = loopback_detach_all(&changed); + if (r == 0) { + need_loop_detach = false; + log_info("All loop devices detached."); + } else if (r > 0) + log_info("Not all loop devices detached, %d left.", r); + else + log_error("Failed to detach loop devices: %s", strerror(-r)); + } + + if (need_dm_detach) { + log_info("Detaching DM devices."); + r = dm_detach_all(&changed); + if (r == 0) { + need_dm_detach = false; + log_info("All DM devices detached."); + } else if (r > 0) + log_info("Not all DM devices detached, %d left.", r); + else + log_error("Failed to detach DM devices: %s", strerror(-r)); + } + + if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { + if (retries > 0) + log_info("All filesystems, swaps, loop devices, DM devices detached."); + /* Yay, done */ + break; + } + + /* If in this iteration we didn't manage to + * unmount/deactivate anything, we simply give up */ + if (!changed) { + log_error("Cannot finalize remaining file systems and devices, giving up."); + break; + } + + log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1); + } + + if (retries >= FINALIZE_ATTEMPTS) + log_error("Too many iterations, giving up."); + else + log_info("Storage is finalized."); + + arguments[0] = NULL; + arguments[1] = arg_verb; + arguments[2] = NULL; + execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments); + + if (!in_container && !in_initrd() && + access("/run/initramfs/shutdown", X_OK) == 0) { + + if (prepare_new_root() >= 0 && + pivot_to_new_root() >= 0) { + arguments[0] = (char*) "/shutdown"; + + log_info("Returning to initrd..."); + + execv("/shutdown", arguments); + log_error("Failed to execute shutdown binary: %m"); + } + } + + /* The kernel will automaticall flush ATA disks and suchlike + * on reboot(), but the file systems need to be synce'd + * explicitly in advance. So let's do this here, but not + * needlessly slow down containers. */ + if (!in_container) + sync(); + + switch (cmd) { + + case LINUX_REBOOT_CMD_KEXEC: + + if (!in_container) { + /* We cheat and exec kexec to avoid doing all its work */ + pid_t pid; + + log_info("Rebooting with kexec."); + + pid = fork(); + if (pid < 0) + log_error("Failed to fork: %m"); + else if (pid == 0) { + + const char * const args[] = { + KEXEC, "-e", NULL + }; + + /* Child */ + + execv(args[0], (char * const *) args); + _exit(EXIT_FAILURE); + } else + wait_for_terminate_and_warn("kexec", pid); + } + + cmd = RB_AUTOBOOT; + /* Fall through */ + + case RB_AUTOBOOT: + + if (!in_container) { + _cleanup_free_ char *param = NULL; + + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + log_info("Rebooting with argument '%s'.", param); + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, param); + } + } + + log_info("Rebooting."); + break; + + case RB_POWER_OFF: + log_info("Powering off."); + break; + + case RB_HALT_SYSTEM: + log_info("Halting system."); + break; + + default: + assert_not_reached("Unknown magic"); + } + + reboot(cmd); + if (errno == EPERM && in_container) { + /* If we are in a container, and we lacked + * CAP_SYS_BOOT just exit, this will kill our + * container for good. */ + log_info("Exiting container."); + exit(0); + } + + log_error("Failed to invoke reboot(): %m"); + r = -errno; + + error: + log_error("Critical error while doing system shutdown: %s", strerror(-r)); + + freeze(); +} diff --git a/src/core/slice.c b/src/core/slice.c new file mode 100644 index 0000000..1e42df2 --- /dev/null +++ b/src/core/slice.c @@ -0,0 +1,322 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "unit.h" +#include "slice.h" +#include "load-fragment.h" +#include "log.h" +#include "dbus-slice.h" +#include "special.h" +#include "unit-name.h" + +static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = UNIT_INACTIVE, + [SLICE_ACTIVE] = UNIT_ACTIVE +}; + +static void slice_init(Unit *u) { + Slice *s = SLICE(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + cgroup_context_init(&s->cgroup_context); +} + +static void slice_done(Unit *u) { + Slice *s = SLICE(u); + + assert(u); + + cgroup_context_done(&s->cgroup_context); +} + +static void slice_set_state(Slice *t, SliceState state) { + SliceState old_state; + assert(t); + + old_state = t->state; + t->state = state; + + if (state != old_state) + log_debug("%s changed %s -> %s", + UNIT(t)->id, + slice_state_to_string(old_state), + slice_state_to_string(state)); + + unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); +} + +static int slice_add_parent_slice(Slice *s) { + char *a, *dash; + Unit *parent; + int r; + + assert(s); + + if (UNIT_ISSET(UNIT(s)->slice)) + return 0; + + if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE)) + return 0; + + a = strdupa(UNIT(s)->id); + dash = strrchr(a, '-'); + if (dash) + strcpy(dash, ".slice"); + else + a = (char*) SPECIAL_ROOT_SLICE; + + r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent); + if (r < 0) + return r; + + unit_ref_set(&UNIT(s)->slice, parent); + return 0; +} + +static int slice_add_default_dependencies(Slice *s) { + int r; + + assert(s); + + /* Make sure slices are unloaded on shutdown */ + r = unit_add_two_dependencies_by_name( + UNIT(s), + UNIT_BEFORE, UNIT_CONFLICTS, + SPECIAL_SHUTDOWN_TARGET, NULL, true); + if (r < 0) + return r; + + return 0; +} + +static int slice_verify(Slice *s) { + assert(s); + + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + + if (UNIT_DEREF(UNIT(s)->slice)) { + char *a, *dash; + + a = strdupa(UNIT(s)->id); + dash = strrchr(a, '-'); + if (dash) + strcpy(dash, ".slice"); + else + a = (char*) SPECIAL_ROOT_SLICE; + + if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) { + log_error_unit(UNIT(s)->id, + "%s located outside its parent slice. Refusing.", UNIT(s)->id); + return -EINVAL; + } + } + + return 0; +} + +static int slice_load(Unit *u) { + Slice *s = SLICE(u); + int r; + + assert(s); + + r = unit_load_fragment_and_dropin_optional(u); + if (r < 0) + return r; + + /* This is a new unit? Then let's add in some extras */ + if (u->load_state == UNIT_LOADED) { + + r = slice_add_parent_slice(s); + if (r < 0) + return r; + + if (u->default_dependencies) { + r = slice_add_default_dependencies(s); + if (r < 0) + return r; + } + } + + return slice_verify(s); +} + +static int slice_coldplug(Unit *u) { + Slice *t = SLICE(u); + + assert(t); + assert(t->state == SLICE_DEAD); + + if (t->deserialized_state != t->state) + slice_set_state(t, t->deserialized_state); + + return 0; +} + +static void slice_dump(Unit *u, FILE *f, const char *prefix) { + Slice *t = SLICE(u); + + assert(t); + assert(f); + + fprintf(f, + "%sSlice State: %s\n", + prefix, slice_state_to_string(t->state)); + + cgroup_context_dump(&t->cgroup_context, f, prefix); +} + +static int slice_start(Unit *u) { + Slice *t = SLICE(u); + + assert(t); + assert(t->state == SLICE_DEAD); + + unit_realize_cgroup(u); + + slice_set_state(t, SLICE_ACTIVE); + return 0; +} + +static int slice_stop(Unit *u) { + Slice *t = SLICE(u); + + assert(t); + assert(t->state == SLICE_ACTIVE); + + /* We do not need to destroy the cgroup explicitly, + * unit_notify() will do that for us anyway. */ + + slice_set_state(t, SLICE_DEAD); + return 0; +} + +static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, -1, error); +} + +static int slice_serialize(Unit *u, FILE *f, FDSet *fds) { + Slice *s = SLICE(u); + + assert(s); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", slice_state_to_string(s->state)); + return 0; +} + +static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Slice *s = SLICE(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + SliceState state; + + state = slice_state_from_string(value); + if (state < 0) + log_debug("Failed to parse state value %s", value); + else + s->deserialized_state = state; + + } else + log_debug("Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState slice_active_state(Unit *u) { + assert(u); + + return state_translation_table[SLICE(u)->state]; +} + +_pure_ static const char *slice_sub_state_to_string(Unit *u) { + assert(u); + + return slice_state_to_string(SLICE(u)->state); +} + +static const char* const slice_state_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = "dead", + [SLICE_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); + +const UnitVTable slice_vtable = { + .object_size = sizeof(Slice), + .cgroup_context_offset = offsetof(Slice, cgroup_context), + + .sections = + "Unit\0" + "Slice\0" + "Install\0", + .private_section = "Slice", + + .no_alias = true, + .no_instances = true, + + .init = slice_init, + .load = slice_load, + .done = slice_done, + + .coldplug = slice_coldplug, + + .dump = slice_dump, + + .start = slice_start, + .stop = slice_stop, + + .kill = slice_kill, + + .serialize = slice_serialize, + .deserialize_item = slice_deserialize_item, + + .active_state = slice_active_state, + .sub_state_to_string = slice_sub_state_to_string, + + .bus_interface = "org.freedesktop.systemd1.Slice", + .bus_vtable = bus_slice_vtable, + .bus_set_property = bus_slice_set_property, + .bus_commit_properties = bus_slice_commit_properties, + + .status_message_formats = { + .finished_start_job = { + [JOB_DONE] = "Created slice %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Removed slice %s.", + }, + }, +}; diff --git a/src/core/slice.h b/src/core/slice.h new file mode 100644 index 0000000..ad0c639 --- /dev/null +++ b/src/core/slice.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Slice Slice; + +#include "unit.h" + +typedef enum SliceState { + SLICE_DEAD, + SLICE_ACTIVE, + _SLICE_STATE_MAX, + _SLICE_STATE_INVALID = -1 +} SliceState; + +struct Slice { + Unit meta; + + SliceState state, deserialized_state; + + CGroupContext cgroup_context; +}; + +extern const UnitVTable slice_vtable; + +const char* slice_state_to_string(SliceState i) _const_; +SliceState slice_state_from_string(const char *s) _pure_; diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c new file mode 100644 index 0000000..a68605c --- /dev/null +++ b/src/core/smack-setup.c @@ -0,0 +1,173 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation + Authors: + Nathaniel Chen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "smack-setup.h" +#include "util.h" +#include "fileio.h" +#include "log.h" +#include "label.h" + +#define SMACK_CONFIG "/etc/smack/accesses.d/" +#define CIPSO_CONFIG "/etc/smack/cipso.d/" + +#ifdef HAVE_SMACK + +static int write_rules(const char* dstpath, const char* srcdir) { + _cleanup_fclose_ FILE *dst = NULL; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *entry; + char buf[NAME_MAX]; + int dfd = -1; + int r = 0; + + dst = fopen(dstpath, "we"); + if (!dst) { + if (errno != ENOENT) + log_warning("Failed to open %s: %m", dstpath); + return -errno; /* negative error */ + } + + /* write rules to dst from every file in the directory */ + dir = opendir(srcdir); + if (!dir) { + if (errno != ENOENT) + log_warning("Failed to opendir %s: %m", srcdir); + return errno; /* positive on purpose */ + } + + dfd = dirfd(dir); + assert(dfd >= 0); + + FOREACH_DIRENT(entry, dir, return 0) { + int fd; + _cleanup_fclose_ FILE *policy = NULL; + + fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + if (r == 0) + r = -errno; + log_warning("Failed to open %s: %m", entry->d_name); + continue; + } + + policy = fdopen(fd, "re"); + if (!policy) { + if (r == 0) + r = -errno; + close_nointr_nofail(fd); + log_error("Failed to open %s: %m", entry->d_name); + continue; + } + + /* load2 write rules in the kernel require a line buffered stream */ + FOREACH_LINE(buf, policy, + log_error("Failed to read line from %s: %m", + entry->d_name)) { + if (!fputs(buf, dst)) { + if (r == 0) + r = -EINVAL; + log_error("Failed to write line to %s", dstpath); + break; + } + if (fflush(dst)) { + if (r == 0) + r = -errno; + log_error("Failed to flush writes to %s: %m", dstpath); + break; + } + } + } + + return r; +} + +#endif + +int smack_setup(bool *loaded_policy) { + +#ifdef HAVE_SMACK + + int r; + + assert(loaded_policy); + + r = write_rules("/sys/fs/smackfs/load2", SMACK_CONFIG); + switch(r) { + case -ENOENT: + log_debug("Smack is not enabled in the kernel."); + return 0; + case ENOENT: + log_debug("Smack access rules directory " SMACK_CONFIG " not found"); + return 0; + case 0: + log_info("Successfully loaded Smack policies."); + break; + default: + log_warning("Failed to load Smack access rules: %s, ignoring.", + strerror(abs(r))); + return 0; + } + +#ifdef SMACK_RUN_LABEL + r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL); + if (r) + log_warning("Failed to set SMACK label \"%s\" on self: %s", + SMACK_RUN_LABEL, strerror(-r)); +#endif + + r = write_rules("/sys/fs/smackfs/cipso2", CIPSO_CONFIG); + switch(r) { + case -ENOENT: + log_debug("Smack/CIPSO is not enabled in the kernel."); + return 0; + case ENOENT: + log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found"); + return 0; + case 0: + log_info("Successfully loaded Smack/CIPSO policies."); + return 0; + default: + log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.", + strerror(abs(r))); + return 0; + } + + *loaded_policy = true; + +#endif + + return 0; +} diff --git a/src/core/smack-setup.h b/src/core/smack-setup.h new file mode 100644 index 0000000..8927096 --- /dev/null +++ b/src/core/smack-setup.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation + Authors: + Nathaniel Chen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int smack_setup(bool *loaded_policy); diff --git a/src/core/snapshot.c b/src/core/snapshot.c new file mode 100644 index 0000000..d914af2 --- /dev/null +++ b/src/core/snapshot.c @@ -0,0 +1,307 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "unit.h" +#include "snapshot.h" +#include "unit-name.h" +#include "dbus-snapshot.h" +#include "bus-errors.h" + +static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = UNIT_INACTIVE, + [SNAPSHOT_ACTIVE] = UNIT_ACTIVE +}; + +static void snapshot_init(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(UNIT(s)->load_state == UNIT_STUB); + + UNIT(s)->ignore_on_isolate = true; + UNIT(s)->ignore_on_snapshot = true; + UNIT(s)->allow_isolate = true; +} + +static void snapshot_set_state(Snapshot *s, SnapshotState state) { + SnapshotState old_state; + assert(s); + + old_state = s->state; + s->state = state; + + if (state != old_state) + log_debug("%s changed %s -> %s", + UNIT(s)->id, + snapshot_state_to_string(old_state), + snapshot_state_to_string(state)); + + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); +} + +static int snapshot_load(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + /* Make sure that only snapshots created via snapshot_create() + * can be loaded */ + if (!u->transient && UNIT(s)->manager->n_reloading <= 0) + return -ENOENT; + + u->load_state = UNIT_LOADED; + return 0; +} + +static int snapshot_coldplug(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(s->state == SNAPSHOT_DEAD); + + if (s->deserialized_state != s->state) + snapshot_set_state(s, s->deserialized_state); + + return 0; +} + +static void snapshot_dump(Unit *u, FILE *f, const char *prefix) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(f); + + fprintf(f, + "%sSnapshot State: %s\n" + "%sClean Up: %s\n", + prefix, snapshot_state_to_string(s->state), + prefix, yes_no(s->cleanup)); +} + +static int snapshot_start(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(s->state == SNAPSHOT_DEAD); + + snapshot_set_state(s, SNAPSHOT_ACTIVE); + + if (s->cleanup) + unit_add_to_cleanup_queue(u); + + return 0; +} + +static int snapshot_stop(Unit *u) { + Snapshot *s = SNAPSHOT(u); + + assert(s); + assert(s->state == SNAPSHOT_ACTIVE); + + snapshot_set_state(s, SNAPSHOT_DEAD); + return 0; +} + +static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) { + Snapshot *s = SNAPSHOT(u); + Unit *other; + Iterator i; + + assert(s); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state)); + unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup)); + SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) + unit_serialize_item(u, f, "wants", other->id); + + return 0; +} + +static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Snapshot *s = SNAPSHOT(u); + int r; + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + SnapshotState state; + + state = snapshot_state_from_string(value); + if (state < 0) + log_debug("Failed to parse state value %s", value); + else + s->deserialized_state = state; + + } else if (streq(key, "cleanup")) { + + r = parse_boolean(value); + if (r < 0) + log_debug("Failed to parse cleanup value %s", value); + else + s->cleanup = r; + + } else if (streq(key, "wants")) { + + r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true); + if (r < 0) + return r; + } else + log_debug("Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState snapshot_active_state(Unit *u) { + assert(u); + + return state_translation_table[SNAPSHOT(u)->state]; +} + +_pure_ static const char *snapshot_sub_state_to_string(Unit *u) { + assert(u); + + return snapshot_state_to_string(SNAPSHOT(u)->state); +} + +int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) { + _cleanup_free_ char *n = NULL; + Unit *other, *u = NULL; + Iterator i; + int r; + const char *k; + + assert(m); + assert(_s); + + if (name) { + if (!unit_name_is_valid(name, TEMPLATE_INVALID)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + if (unit_name_to_type(name) != UNIT_SNAPSHOT) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name); + + if (manager_get_unit(m, name)) + sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); + + } else { + + for (;;) { + if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0) + return -ENOMEM; + + if (!manager_get_unit(m, n)) { + name = n; + break; + } + + free(n); + n = NULL; + } + } + + r = manager_load_unit_prepare(m, name, NULL, e, &u); + if (r < 0) + goto fail; + + u->transient = true; + manager_dispatch_load_queue(m); + assert(u->load_state == UNIT_LOADED); + + HASHMAP_FOREACH_KEY(other, k, m->units, i) { + + if (other->ignore_on_snapshot || + other->transient) + continue; + + if (k != other->id) + continue; + + if (UNIT_VTABLE(other)->check_snapshot) + if (!UNIT_VTABLE(other)->check_snapshot(other)) + continue; + + if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) + continue; + + r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true); + if (r < 0) + goto fail; + } + + SNAPSHOT(u)->cleanup = cleanup; + *_s = SNAPSHOT(u); + + return 0; + +fail: + if (u) + unit_add_to_cleanup_queue(u); + + return r; +} + +void snapshot_remove(Snapshot *s) { + assert(s); + + unit_add_to_cleanup_queue(UNIT(s)); +} + +static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = "dead", + [SNAPSHOT_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); + +const UnitVTable snapshot_vtable = { + .object_size = sizeof(Snapshot), + + .no_alias = true, + .no_instances = true, + .no_gc = true, + + .init = snapshot_init, + .load = snapshot_load, + + .coldplug = snapshot_coldplug, + + .dump = snapshot_dump, + + .start = snapshot_start, + .stop = snapshot_stop, + + .serialize = snapshot_serialize, + .deserialize_item = snapshot_deserialize_item, + + .active_state = snapshot_active_state, + .sub_state_to_string = snapshot_sub_state_to_string, + + .bus_interface = "org.freedesktop.systemd1.Snapshot", + .bus_vtable = bus_snapshot_vtable +}; diff --git a/src/core/snapshot.h b/src/core/snapshot.h new file mode 100644 index 0000000..e6dc661 --- /dev/null +++ b/src/core/snapshot.h @@ -0,0 +1,49 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Snapshot Snapshot; + +#include "unit.h" + +typedef enum SnapshotState { + SNAPSHOT_DEAD, + SNAPSHOT_ACTIVE, + _SNAPSHOT_STATE_MAX, + _SNAPSHOT_STATE_INVALID = -1 +} SnapshotState; + +struct Snapshot { + Unit meta; + + SnapshotState state, deserialized_state; + + bool cleanup; +}; + +extern const UnitVTable snapshot_vtable; + +int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s); +void snapshot_remove(Snapshot *s); + +const char* snapshot_state_to_string(SnapshotState i) _const_; +SnapshotState snapshot_state_from_string(const char *s) _pure_; diff --git a/src/core/socket.c b/src/core/socket.c new file mode 100644 index 0000000..0ccda2f --- /dev/null +++ b/src/core/socket.c @@ -0,0 +1,2468 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_XATTR +#include +#endif + +#include "sd-event.h" +#include "log.h" +#include "load-dropin.h" +#include "load-fragment.h" +#include "strv.h" +#include "mkdir.h" +#include "path-util.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "missing.h" +#include "special.h" +#include "label.h" +#include "exit-status.h" +#include "def.h" +#include "smack-util.h" +#include "bus-util.h" +#include "bus-error.h" +#include "dbus-socket.h" +#include "unit.h" +#include "socket.h" + +static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = UNIT_INACTIVE, + [SOCKET_START_PRE] = UNIT_ACTIVATING, + [SOCKET_START_POST] = UNIT_ACTIVATING, + [SOCKET_LISTENING] = UNIT_ACTIVE, + [SOCKET_RUNNING] = UNIT_ACTIVE, + [SOCKET_STOP_PRE] = UNIT_DEACTIVATING, + [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING, + [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING, + [SOCKET_STOP_POST] = UNIT_DEACTIVATING, + [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING, + [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING, + [SOCKET_FAILED] = UNIT_FAILED +}; + +static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + +static void socket_init(Unit *u) { + Socket *s = SOCKET(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + s->backlog = SOMAXCONN; + s->timeout_usec = u->manager->default_timeout_start_usec; + s->directory_mode = 0755; + s->socket_mode = 0666; + + s->max_connections = 64; + + s->priority = -1; + s->ip_tos = -1; + s->ip_ttl = -1; + s->mark = -1; + + exec_context_init(&s->exec_context); + s->exec_context.std_output = u->manager->default_std_output; + s->exec_context.std_error = u->manager->default_std_error; + kill_context_init(&s->kill_context); + cgroup_context_init(&s->cgroup_context); + + s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; +} + +static void socket_unwatch_control_pid(Socket *s) { + assert(s); + + if (s->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(s), s->control_pid); + s->control_pid = 0; +} + +void socket_free_ports(Socket *s) { + SocketPort *p; + + assert(s); + + while ((p = s->ports)) { + LIST_REMOVE(port, s->ports, p); + + sd_event_source_unref(p->event_source); + + if (p->fd >= 0) + close_nointr_nofail(p->fd); + + free(p->path); + free(p); + } +} + +static void socket_done(Unit *u) { + Socket *s = SOCKET(u); + + assert(s); + + socket_free_ports(s); + + cgroup_context_done(&s->cgroup_context); + exec_context_done(&s->exec_context); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX); + s->control_command = NULL; + + socket_unwatch_control_pid(s); + + unit_ref_unset(&s->service); + + free(s->tcp_congestion); + s->tcp_congestion = NULL; + + free(s->bind_to_device); + s->bind_to_device = NULL; + + free(s->smack); + free(s->smack_ip_in); + free(s->smack_ip_out); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int socket_arm_timer(Socket *s) { + int r; + + assert(s); + + if (s->timeout_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec, 0, socket_dispatch_timer, s); +} + +static int socket_instantiate_service(Socket *s) { + _cleanup_free_ char *prefix = NULL; + _cleanup_free_ char *name = NULL; + int r; + Unit *u; + + assert(s); + + /* This fills in s->service if it isn't filled in yet. For + * Accept=yes sockets we create the next connection service + * here. For Accept=no this is mostly a NOP since the service + * is figured out at load time anyway. */ + + if (UNIT_DEREF(s->service)) + return 0; + + assert(s->accept); + + if (!(prefix = unit_name_to_prefix(UNIT(s)->id))) + return -ENOMEM; + + r = asprintf(&name, "%s@%u.service", prefix, s->n_accepted); + + if (r < 0) + return -ENOMEM; + + r = manager_load_unit(UNIT(s)->manager, name, NULL, NULL, &u); + + if (r < 0) + return r; + +#ifdef HAVE_SYSV_COMPAT + if (SERVICE(u)->is_sysv) { + log_error("Using SysV services for socket activation is not supported. Refusing."); + return -ENOENT; + } +#endif + + u->no_gc = true; + unit_ref_set(&s->service, u); + + return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false); +} + +static bool have_non_accept_socket(Socket *s) { + SocketPort *p; + + assert(s); + + if (!s->accept) + return true; + + LIST_FOREACH(port, p, s->ports) { + + if (p->type != SOCKET_SOCKET) + return true; + + if (!socket_address_can_accept(&p->address)) + return true; + } + + return false; +} + +static int socket_add_mount_links(Socket *s) { + SocketPort *p; + int r; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + const char *path = NULL; + + if (p->type == SOCKET_SOCKET) + path = socket_address_get_path(&p->address); + else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) + path = p->path; + + if (!path) + continue; + + r = unit_require_mounts_for(UNIT(s), path); + if (r < 0) + return r; + } + + return 0; +} + +static int socket_add_device_link(Socket *s) { + char *t; + + assert(s); + + if (!s->bind_to_device || streq(s->bind_to_device, "lo")) + return 0; + + t = strappenda("/sys/subsystem/net/devices/", s->bind_to_device); + return unit_add_node_link(UNIT(s), t, false); +} + +static int socket_add_default_dependencies(Socket *s) { + int r; + assert(s); + + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true); + if (r < 0) + return r; + + if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + if (r < 0) + return r; + } + + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); +} + +_pure_ static bool socket_has_exec(Socket *s) { + unsigned i; + assert(s); + + for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++) + if (s->exec_command[i]) + return true; + + return false; +} + +static int socket_add_extras(Socket *s) { + Unit *u = UNIT(s); + int r; + + assert(s); + + if (have_non_accept_socket(s)) { + + if (!UNIT_DEREF(s->service)) { + Unit *x; + + r = unit_load_related_unit(u, ".service", &x); + if (r < 0) + return r; + + unit_ref_set(&s->service, x); + } + + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true); + if (r < 0) + return r; + } + + r = socket_add_mount_links(s); + if (r < 0) + return r; + + r = socket_add_device_link(s); + if (r < 0) + return r; + + r = unit_exec_context_defaults(u, &s->exec_context); + if (r < 0) + return r; + + if (socket_has_exec(s)) { + r = unit_add_exec_dependencies(u, &s->exec_context); + if (r < 0) + return r; + + r = unit_add_default_slice(u); + if (r < 0) + return r; + } + + if (u->default_dependencies) { + r = socket_add_default_dependencies(s); + if (r < 0) + return r; + } + + return 0; +} + +static int socket_verify(Socket *s) { + assert(s); + + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + + if (!s->ports) { + log_error_unit(UNIT(s)->id, "%s lacks Listen setting. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->accept && have_non_accept_socket(s)) { + log_error_unit(UNIT(s)->id, "%s configured for accepting sockets, but sockets are non-accepting. Refusing.", + UNIT(s)->id); + return -EINVAL; + } + + if (s->accept && s->max_connections <= 0) { + log_error_unit(UNIT(s)->id, "%s's MaxConnection setting too small. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->accept && UNIT_DEREF(s->service)) { + log_error_unit(UNIT(s)->id, "Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { + log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id); + return -EINVAL; + } + + return 0; +} + +static int socket_load(Unit *u) { + Socket *s = SOCKET(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + /* This is a new unit? Then let's add in some extras */ + r = socket_add_extras(s); + if (r < 0) + return r; + } + + return socket_verify(s); +} + +_const_ static const char* listen_lookup(int family, int type) { + + if (family == AF_NETLINK) + return "ListenNetlink"; + + if (type == SOCK_STREAM) + return "ListenStream"; + else if (type == SOCK_DGRAM) + return "ListenDatagram"; + else if (type == SOCK_SEQPACKET) + return "ListenSequentialPacket"; + + assert_not_reached("Unknown socket type"); + return NULL; +} + +static void socket_dump(Unit *u, FILE *f, const char *prefix) { + SocketExecCommand c; + Socket *s = SOCKET(u); + SocketPort *p; + const char *prefix2; + + assert(s); + assert(f); + + prefix2 = strappenda(prefix, "\t"); + + fprintf(f, + "%sSocket State: %s\n" + "%sResult: %s\n" + "%sBindIPv6Only: %s\n" + "%sBacklog: %u\n" + "%sSocketMode: %04o\n" + "%sDirectoryMode: %04o\n" + "%sKeepAlive: %s\n" + "%sFreeBind: %s\n" + "%sTransparent: %s\n" + "%sBroadcast: %s\n" + "%sPassCredentials: %s\n" + "%sPassSecurity: %s\n" + "%sTCPCongestion: %s\n", + prefix, socket_state_to_string(s->state), + prefix, socket_result_to_string(s->result), + prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), + prefix, s->backlog, + prefix, s->socket_mode, + prefix, s->directory_mode, + prefix, yes_no(s->keep_alive), + prefix, yes_no(s->free_bind), + prefix, yes_no(s->transparent), + prefix, yes_no(s->broadcast), + prefix, yes_no(s->pass_cred), + prefix, yes_no(s->pass_sec), + prefix, strna(s->tcp_congestion)); + + if (s->control_pid > 0) + fprintf(f, + "%sControl PID: %lu\n", + prefix, (unsigned long) s->control_pid); + + if (s->bind_to_device) + fprintf(f, + "%sBindToDevice: %s\n", + prefix, s->bind_to_device); + + if (s->accept) + fprintf(f, + "%sAccepted: %u\n" + "%sNConnections: %u\n" + "%sMaxConnections: %u\n", + prefix, s->n_accepted, + prefix, s->n_connections, + prefix, s->max_connections); + + if (s->priority >= 0) + fprintf(f, + "%sPriority: %i\n", + prefix, s->priority); + + if (s->receive_buffer > 0) + fprintf(f, + "%sReceiveBuffer: %zu\n", + prefix, s->receive_buffer); + + if (s->send_buffer > 0) + fprintf(f, + "%sSendBuffer: %zu\n", + prefix, s->send_buffer); + + if (s->ip_tos >= 0) + fprintf(f, + "%sIPTOS: %i\n", + prefix, s->ip_tos); + + if (s->ip_ttl >= 0) + fprintf(f, + "%sIPTTL: %i\n", + prefix, s->ip_ttl); + + if (s->pipe_size > 0) + fprintf(f, + "%sPipeSize: %zu\n", + prefix, s->pipe_size); + + if (s->mark >= 0) + fprintf(f, + "%sMark: %i\n", + prefix, s->mark); + + if (s->mq_maxmsg > 0) + fprintf(f, + "%sMessageQueueMaxMessages: %li\n", + prefix, s->mq_maxmsg); + + if (s->mq_msgsize > 0) + fprintf(f, + "%sMessageQueueMessageSize: %li\n", + prefix, s->mq_msgsize); + + if (s->reuse_port) + fprintf(f, + "%sReusePort: %s\n", + prefix, yes_no(s->reuse_port)); + + if (s->smack) + fprintf(f, + "%sSmackLabel: %s\n", + prefix, s->smack); + + if (s->smack_ip_in) + fprintf(f, + "%sSmackLabelIPIn: %s\n", + prefix, s->smack_ip_in); + + if (s->smack_ip_out) + fprintf(f, + "%sSmackLabelIPOut: %s\n", + prefix, s->smack_ip_out); + + LIST_FOREACH(port, p, s->ports) { + + if (p->type == SOCKET_SOCKET) { + const char *t; + int r; + char *k = NULL; + + if ((r = socket_address_print(&p->address, &k)) < 0) + t = strerror(-r); + else + t = k; + + fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t); + free(k); + } else if (p->type == SOCKET_SPECIAL) + fprintf(f, "%sListenSpecial: %s\n", prefix, p->path); + else if (p->type == SOCKET_MQUEUE) + fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path); + else + fprintf(f, "%sListenFIFO: %s\n", prefix, p->path); + } + + exec_context_dump(&s->exec_context, f, prefix); + kill_context_dump(&s->kill_context, f, prefix); + + for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) { + if (!s->exec_command[c]) + continue; + + fprintf(f, "%s-> %s:\n", + prefix, socket_exec_command_to_string(c)); + + exec_command_dump_list(s->exec_command[c], f, prefix2); + } +} + +static int instance_from_socket(int fd, unsigned nr, char **instance) { + socklen_t l; + char *r; + union { + struct sockaddr sa; + struct sockaddr_un un; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_storage storage; + } local, remote; + + assert(fd >= 0); + assert(instance); + + l = sizeof(local); + if (getsockname(fd, &local.sa, &l) < 0) + return -errno; + + l = sizeof(remote); + if (getpeername(fd, &remote.sa, &l) < 0) + return -errno; + + switch (local.sa.sa_family) { + + case AF_INET: { + uint32_t + a = ntohl(local.in.sin_addr.s_addr), + b = ntohl(remote.in.sin_addr.s_addr); + + if (asprintf(&r, + "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", + nr, + a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, + ntohs(local.in.sin_port), + b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF, + ntohs(remote.in.sin_port)) < 0) + return -ENOMEM; + + break; + } + + case AF_INET6: { + static const unsigned char ipv4_prefix[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF + }; + + if (memcmp(&local.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0 && + memcmp(&remote.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) { + const uint8_t + *a = local.in6.sin6_addr.s6_addr+12, + *b = remote.in6.sin6_addr.s6_addr+12; + + if (asprintf(&r, + "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", + nr, + a[0], a[1], a[2], a[3], + ntohs(local.in6.sin6_port), + b[0], b[1], b[2], b[3], + ntohs(remote.in6.sin6_port)) < 0) + return -ENOMEM; + } else { + char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN]; + + if (asprintf(&r, + "%u-%s:%u-%s:%u", + nr, + inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)), + ntohs(local.in6.sin6_port), + inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)), + ntohs(remote.in6.sin6_port)) < 0) + return -ENOMEM; + } + + break; + } + + case AF_UNIX: { + struct ucred ucred; + int k; + + k = getpeercred(fd, &ucred); + if (k < 0) + return k; + + if (asprintf(&r, + "%u-%lu-%lu", + nr, + (unsigned long) ucred.pid, + (unsigned long) ucred.uid) < 0) + return -ENOMEM; + + break; + } + + default: + assert_not_reached("Unhandled socket type."); + } + + *instance = r; + return 0; +} + +static void socket_close_fds(Socket *s) { + SocketPort *p; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + + p->event_source = sd_event_source_unref(p->event_source); + + if (p->fd < 0) + continue; + + close_nointr_nofail(p->fd); + + /* One little note: we should never delete any sockets + * in the file system here! After all some other + * process we spawned might still have a reference of + * this fd and wants to continue to use it. Therefore + * we delete sockets in the file system before we + * create a new one, not after we stopped using + * one! */ + + p->fd = -1; + } +} + +static void socket_apply_socket_options(Socket *s, int fd) { + assert(s); + assert(fd >= 0); + + if (s->keep_alive) { + int b = s->keep_alive; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0) + log_warning_unit(UNIT(s)->id, "SO_KEEPALIVE failed: %m"); + } + + if (s->broadcast) { + int one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) + log_warning_unit(UNIT(s)->id, "SO_BROADCAST failed: %m"); + } + + if (s->pass_cred) { + int one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) + log_warning_unit(UNIT(s)->id, "SO_PASSCRED failed: %m"); + } + + if (s->pass_sec) { + int one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0) + log_warning_unit(UNIT(s)->id, "SO_PASSSEC failed: %m"); + } + + if (s->priority >= 0) + if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0) + log_warning_unit(UNIT(s)->id, "SO_PRIORITY failed: %m"); + + if (s->receive_buffer > 0) { + int value = (int) s->receive_buffer; + + /* We first try with SO_RCVBUFFORCE, in case we have the perms for that */ + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) + log_warning_unit(UNIT(s)->id, "SO_RCVBUF failed: %m"); + } + + if (s->send_buffer > 0) { + int value = (int) s->send_buffer; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) + log_warning_unit(UNIT(s)->id, "SO_SNDBUF failed: %m"); + } + + if (s->mark >= 0) + if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0) + log_warning_unit(UNIT(s)->id, "SO_MARK failed: %m"); + + if (s->ip_tos >= 0) + if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0) + log_warning_unit(UNIT(s)->id, "IP_TOS failed: %m"); + + if (s->ip_ttl >= 0) { + int r, x; + + r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl)); + + if (socket_ipv6_is_supported()) + x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl)); + else { + x = -1; + errno = EAFNOSUPPORT; + } + + if (r < 0 && x < 0) + log_warning_unit(UNIT(s)->id, + "IP_TTL/IPV6_UNICAST_HOPS failed: %m"); + } + + if (s->tcp_congestion) + if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) + log_warning_unit(UNIT(s)->id, "TCP_CONGESTION failed: %m"); + + if (s->reuse_port) { + int b = s->reuse_port; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0) + log_warning_unit(UNIT(s)->id, "SO_REUSEPORT failed: %m"); + } + + if (s->smack_ip_in) + if (smack_label_ip_in_fd(fd, s->smack_ip_in) < 0) + log_error_unit(UNIT(s)->id, "smack_label_ip_in_fd: %m"); + + if (s->smack_ip_out) + if (smack_label_ip_out_fd(fd, s->smack_ip_out) < 0) + log_error_unit(UNIT(s)->id, "smack_label_ip_out_fd: %m"); +} + +static void socket_apply_fifo_options(Socket *s, int fd) { + assert(s); + assert(fd >= 0); + + if (s->pipe_size > 0) + if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0) + log_warning_unit(UNIT(s)->id, + "F_SETPIPE_SZ: %m"); + + if (s->smack) + if (smack_label_fd(fd, s->smack) < 0) + log_error_unit(UNIT(s)->id, "smack_label_fd: %m"); +} + +static int fifo_address_create( + const char *path, + mode_t directory_mode, + mode_t socket_mode, + int *_fd) { + + int fd = -1, r = 0; + struct stat st; + mode_t old_mask; + + assert(path); + assert(_fd); + + mkdir_parents_label(path, directory_mode); + + r = label_context_set(path, S_IFIFO); + if (r < 0) + goto fail; + + /* Enforce the right access mode for the fifo */ + old_mask = umask(~ socket_mode); + + /* Include the original umask in our mask */ + umask(~socket_mode | old_mask); + + r = mkfifo(path, socket_mode); + umask(old_mask); + + if (r < 0 && errno != EEXIST) { + r = -errno; + goto fail; + } + + if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + r = -errno; + goto fail; + } + + label_context_clear(); + + if (fstat(fd, &st) < 0) { + r = -errno; + goto fail; + } + + if (!S_ISFIFO(st.st_mode) || + (st.st_mode & 0777) != (socket_mode & ~old_mask) || + st.st_uid != getuid() || + st.st_gid != getgid()) { + + r = -EEXIST; + goto fail; + } + + *_fd = fd; + return 0; + +fail: + label_context_clear(); + + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +static int special_address_create( + const char *path, + int *_fd) { + + int fd = -1, r = 0; + struct stat st; + + assert(path); + assert(_fd); + + if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + r = -errno; + goto fail; + } + + if (fstat(fd, &st) < 0) { + r = -errno; + goto fail; + } + + /* Check whether this is a /proc, /sys or /dev file or char device */ + if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { + r = -EEXIST; + goto fail; + } + + *_fd = fd; + return 0; + +fail: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +static int mq_address_create( + const char *path, + mode_t mq_mode, + long maxmsg, + long msgsize, + int *_fd) { + + int fd = -1, r = 0; + struct stat st; + mode_t old_mask; + struct mq_attr _attr, *attr = NULL; + + assert(path); + assert(_fd); + + if (maxmsg > 0 && msgsize > 0) { + zero(_attr); + _attr.mq_flags = O_NONBLOCK; + _attr.mq_maxmsg = maxmsg; + _attr.mq_msgsize = msgsize; + attr = &_attr; + } + + /* Enforce the right access mode for the mq */ + old_mask = umask(~ mq_mode); + + /* Include the original umask in our mask */ + umask(~mq_mode | old_mask); + + fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); + umask(old_mask); + + if (fd < 0) { + r = -errno; + goto fail; + } + + if (fstat(fd, &st) < 0) { + r = -errno; + goto fail; + } + + if ((st.st_mode & 0777) != (mq_mode & ~old_mask) || + st.st_uid != getuid() || + st.st_gid != getgid()) { + + r = -EEXIST; + goto fail; + } + + *_fd = fd; + return 0; + +fail: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +static int socket_open_fds(Socket *s) { + SocketPort *p; + int r; + char *label = NULL; + bool know_label = false; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + + if (p->fd >= 0) + continue; + + if (p->type == SOCKET_SOCKET) { + + if (!know_label) { + + if ((r = socket_instantiate_service(s)) < 0) + return r; + + if (UNIT_ISSET(s->service) && + SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) { + r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label); + + if (r < 0) { + if (r != -EPERM) + return r; + } + } + + know_label = true; + } + + r = socket_address_listen( + &p->address, + SOCK_CLOEXEC|SOCK_NONBLOCK, + s->backlog, + s->bind_ipv6_only, + s->bind_to_device, + s->free_bind, + s->transparent, + s->directory_mode, + s->socket_mode, + label); + if (r < 0) + goto rollback; + + p->fd = r; + socket_apply_socket_options(s, p->fd); + + } else if (p->type == SOCKET_SPECIAL) { + + r = special_address_create( + p->path, + &p->fd); + if (r < 0) + goto rollback; + + } else if (p->type == SOCKET_FIFO) { + + r = fifo_address_create( + p->path, + s->directory_mode, + s->socket_mode, + &p->fd); + if (r < 0) + goto rollback; + + socket_apply_fifo_options(s, p->fd); + } else if (p->type == SOCKET_MQUEUE) { + + r = mq_address_create( + p->path, + s->socket_mode, + s->mq_maxmsg, + s->mq_msgsize, + &p->fd); + if (r < 0) + goto rollback; + } else + assert_not_reached("Unknown port type"); + } + + label_free(label); + return 0; + +rollback: + socket_close_fds(s); + label_free(label); + return r; +} + +static void socket_unwatch_fds(Socket *s) { + SocketPort *p; + int r; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + if (p->fd < 0) + continue; + + if (p->event_source) { + r = sd_event_source_set_enabled(p->event_source, SD_EVENT_OFF); + if (r < 0) + log_debug_unit(UNIT(s)->id, "Failed to disable event source."); + } + } +} + +static int socket_watch_fds(Socket *s) { + SocketPort *p; + int r; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + if (p->fd < 0) + continue; + + if (p->event_source) + r = sd_event_source_set_enabled(p->event_source, SD_EVENT_ON); + else + r = sd_event_add_io(UNIT(s)->manager->event, &p->event_source, p->fd, EPOLLIN, socket_dispatch_io, p); + + if (r < 0) { + log_warning_unit(UNIT(s)->id, "Failed to watch listening fds: %s", strerror(-r)); + goto fail; + } + } + + return 0; + +fail: + socket_unwatch_fds(s); + return r; +} + +static void socket_set_state(Socket *s, SocketState state) { + SocketState old_state; + assert(s); + + old_state = s->state; + s->state = state; + + if (state != SOCKET_START_PRE && + state != SOCKET_START_POST && + state != SOCKET_STOP_PRE && + state != SOCKET_STOP_PRE_SIGTERM && + state != SOCKET_STOP_PRE_SIGKILL && + state != SOCKET_STOP_POST && + state != SOCKET_FINAL_SIGTERM && + state != SOCKET_FINAL_SIGKILL) { + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + socket_unwatch_control_pid(s); + s->control_command = NULL; + s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + } + + if (state != SOCKET_LISTENING) + socket_unwatch_fds(s); + + if (state != SOCKET_START_POST && + state != SOCKET_LISTENING && + state != SOCKET_RUNNING && + state != SOCKET_STOP_PRE && + state != SOCKET_STOP_PRE_SIGTERM && + state != SOCKET_STOP_PRE_SIGKILL) + socket_close_fds(s); + + if (state != old_state) + log_debug_unit(UNIT(s)->id, "%s changed %s -> %s", + UNIT(s)->id, socket_state_to_string(old_state), socket_state_to_string(state)); + + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); +} + +static int socket_coldplug(Unit *u) { + Socket *s = SOCKET(u); + int r; + + assert(s); + assert(s->state == SOCKET_DEAD); + + if (s->deserialized_state == s->state) + return 0; + + if (s->deserialized_state == SOCKET_START_PRE || + s->deserialized_state == SOCKET_START_POST || + s->deserialized_state == SOCKET_STOP_PRE || + s->deserialized_state == SOCKET_STOP_PRE_SIGTERM || + s->deserialized_state == SOCKET_STOP_PRE_SIGKILL || + s->deserialized_state == SOCKET_STOP_POST || + s->deserialized_state == SOCKET_FINAL_SIGTERM || + s->deserialized_state == SOCKET_FINAL_SIGKILL) { + + if (s->control_pid <= 0) + return -EBADMSG; + + r = unit_watch_pid(UNIT(s), s->control_pid); + if (r < 0) + return r; + + r = socket_arm_timer(s); + if (r < 0) + return r; + } + + if (s->deserialized_state == SOCKET_START_POST || + s->deserialized_state == SOCKET_LISTENING || + s->deserialized_state == SOCKET_RUNNING || + s->deserialized_state == SOCKET_STOP_PRE || + s->deserialized_state == SOCKET_STOP_PRE_SIGTERM || + s->deserialized_state == SOCKET_STOP_PRE_SIGKILL) { + r = socket_open_fds(s); + if (r < 0) + return r; + } + + if (s->deserialized_state == SOCKET_LISTENING) { + r = socket_watch_fds(s); + if (r < 0) + return r; + } + + socket_set_state(s, s->deserialized_state); + return 0; +} + +static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { + pid_t pid; + int r; + char **argv; + + assert(s); + assert(c); + assert(_pid); + + unit_realize_cgroup(UNIT(s)); + + r = unit_setup_exec_runtime(UNIT(s)); + if (r < 0) + goto fail; + + r = socket_arm_timer(s); + if (r < 0) + goto fail; + + r = unit_full_printf_strv(UNIT(s), c->argv, &argv); + if (r < 0) + goto fail; + + r = exec_spawn(c, + argv, + &s->exec_context, + NULL, 0, + UNIT(s)->manager->environment, + true, + true, + true, + UNIT(s)->manager->confirm_spawn, + UNIT(s)->manager->cgroup_supported, + UNIT(s)->cgroup_path, + UNIT(s)->id, + 0, + NULL, + s->exec_runtime, + &pid); + + strv_free(argv); + if (r < 0) + goto fail; + + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) + /* FIXME: we need to do something here */ + goto fail; + + *_pid = pid; + + return 0; + +fail: + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + return r; +} + +static void socket_enter_dead(Socket *s, SocketResult f) { + assert(s); + + if (f != SOCKET_SUCCESS) + s->result = f; + + exec_runtime_destroy(s->exec_runtime); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + + socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD); +} + +static void socket_enter_signal(Socket *s, SocketState state, SocketResult f); + +static void socket_enter_stop_post(Socket *s, SocketResult f) { + int r; + assert(s); + + if (f != SOCKET_SUCCESS) + s->result = f; + + socket_unwatch_control_pid(s); + + s->control_command_id = SOCKET_EXEC_STOP_POST; + + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) + goto fail; + + socket_set_state(s, SOCKET_STOP_POST); + } else + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'stop-post' task: %s", + UNIT(s)->id, strerror(-r)); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) { + int r; + + assert(s); + + if (f != SOCKET_SUCCESS) + s->result = f; + + r = unit_kill_context( + UNIT(s), + &s->kill_context, + state != SOCKET_STOP_PRE_SIGTERM && state != SOCKET_FINAL_SIGTERM, + -1, + s->control_pid, + false); + if (r < 0) + goto fail; + + if (r > 0) { + r = socket_arm_timer(s); + if (r < 0) + goto fail; + + socket_set_state(s, state); + } else if (state == SOCKET_STOP_PRE_SIGTERM) + socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_SUCCESS); + else if (state == SOCKET_STOP_PRE_SIGKILL) + socket_enter_stop_post(s, SOCKET_SUCCESS); + else if (state == SOCKET_FINAL_SIGTERM) + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_SUCCESS); + else + socket_enter_dead(s, SOCKET_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); + + if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL) + socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES); + else + socket_enter_dead(s, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_stop_pre(Socket *s, SocketResult f) { + int r; + assert(s); + + if (f != SOCKET_SUCCESS) + s->result = f; + + socket_unwatch_control_pid(s); + + s->control_command_id = SOCKET_EXEC_STOP_PRE; + + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) { + if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) + goto fail; + + socket_set_state(s, SOCKET_STOP_PRE); + } else + socket_enter_stop_post(s, SOCKET_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, "%s failed to run 'stop-pre' task: %s", UNIT(s)->id, strerror(-r)); + socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_listening(Socket *s) { + int r; + assert(s); + + r = socket_watch_fds(s); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r)); + goto fail; + } + + socket_set_state(s, SOCKET_LISTENING); + return; + +fail: + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_start_post(Socket *s) { + int r; + assert(s); + + r = socket_open_fds(s); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to listen on sockets: %s", UNIT(s)->id, strerror(-r)); + goto fail; + } + + socket_unwatch_control_pid(s); + + s->control_command_id = SOCKET_EXEC_START_POST; + + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) { + r = socket_spawn(s, s->control_command, &s->control_pid); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r)); + goto fail; + } + + socket_set_state(s, SOCKET_START_POST); + } else + socket_enter_listening(s); + + return; + +fail: + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_start_pre(Socket *s) { + int r; + assert(s); + + socket_unwatch_control_pid(s); + + s->control_command_id = SOCKET_EXEC_START_PRE; + + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) { + r = socket_spawn(s, s->control_command, &s->control_pid); + if (r < 0) + goto fail; + + socket_set_state(s, SOCKET_START_PRE); + } else + socket_enter_start_post(s); + + return; + +fail: + log_warning_unit(UNIT(s)->id, "%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r)); + socket_enter_dead(s, SOCKET_FAILURE_RESOURCES); +} + +static void socket_enter_running(Socket *s, int cfd) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(s); + + /* We don't take connections anymore if we are supposed to + * shut down anyway */ + if (unit_stop_pending(UNIT(s))) { + + log_debug_unit(UNIT(s)->id, "Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id); + + if (cfd >= 0) + close_nointr_nofail(cfd); + else { + /* Flush all sockets by closing and reopening them */ + socket_close_fds(s); + + r = socket_open_fds(s); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to listen on sockets: %s", UNIT(s)->id, strerror(-r)); + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); + return; + } + + r = socket_watch_fds(s); + if (r < 0) { + log_warning_unit(UNIT(s)->id, "%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r)); + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); + } + } + + return; + } + + if (cfd < 0) { + Iterator i; + Unit *other; + bool pending = false; + + /* If there's already a start pending don't bother to + * do anything */ + SET_FOREACH(other, UNIT(s)->dependencies[UNIT_TRIGGERS], i) + if (unit_active_or_pending(other)) { + pending = true; + break; + } + + if (!pending) { + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + } + + socket_set_state(s, SOCKET_RUNNING); + } else { + _cleanup_free_ char *prefix = NULL, *instance = NULL, *name = NULL; + Service *service; + + if (s->n_connections >= s->max_connections) { + log_warning_unit(UNIT(s)->id, "%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections); + close_nointr_nofail(cfd); + return; + } + + r = socket_instantiate_service(s); + if (r < 0) + goto fail; + + r = instance_from_socket(cfd, s->n_accepted, &instance); + if (r < 0) { + if (r != -ENOTCONN) + goto fail; + + /* ENOTCONN is legitimate if TCP RST was received. + * This connection is over, but the socket unit lives on. */ + close_nointr_nofail(cfd); + return; + } + + prefix = unit_name_to_prefix(UNIT(s)->id); + if (!prefix) { + r = -ENOMEM; + goto fail; + } + + name = unit_name_build(prefix, instance, ".service"); + if (!name) { + r = -ENOMEM; + goto fail; + } + + r = unit_add_name(UNIT_DEREF(s->service), name); + if (r < 0) + goto fail; + + service = SERVICE(UNIT_DEREF(s->service)); + unit_ref_unset(&s->service); + s->n_accepted ++; + + UNIT(service)->no_gc = false; + + unit_choose_id(UNIT(service), name); + + r = service_set_socket_fd(service, cfd, s); + if (r < 0) + goto fail; + + cfd = -1; + s->n_connections ++; + + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + + /* Notify clients about changed counters */ + unit_add_to_dbus_queue(UNIT(s)); + } + + return; + +fail: + log_warning_unit(UNIT(s)->id, "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s", + UNIT(s)->id, cfd >= 0 ? "template" : "non-template", + bus_error_message(&error, r)); + + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); + + if (cfd >= 0) + close_nointr_nofail(cfd); +} + +static void socket_run_next(Socket *s) { + int r; + + assert(s); + assert(s->control_command); + assert(s->control_command->command_next); + + socket_unwatch_control_pid(s); + + s->control_command = s->control_command->command_next; + + r = socket_spawn(s, s->control_command, &s->control_pid); + if (r < 0) + goto fail; + + return; + +fail: + log_warning_unit(UNIT(s)->id, "%s failed to run next task: %s", UNIT(s)->id, strerror(-r)); + + if (s->state == SOCKET_START_POST) + socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); + else if (s->state == SOCKET_STOP_POST) + socket_enter_dead(s, SOCKET_FAILURE_RESOURCES); + else + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES); +} + +static int socket_start(Unit *u) { + Socket *s = SOCKET(u); + + assert(s); + + /* We cannot fulfill this request right now, try again later + * please! */ + if (s->state == SOCKET_STOP_PRE || + s->state == SOCKET_STOP_PRE_SIGKILL || + s->state == SOCKET_STOP_PRE_SIGTERM || + s->state == SOCKET_STOP_POST || + s->state == SOCKET_FINAL_SIGTERM || + s->state == SOCKET_FINAL_SIGKILL) + return -EAGAIN; + + if (s->state == SOCKET_START_PRE || + s->state == SOCKET_START_POST) + return 0; + + /* Cannot run this without the service being around */ + if (UNIT_ISSET(s->service)) { + Service *service; + + service = SERVICE(UNIT_DEREF(s->service)); + + if (UNIT(service)->load_state != UNIT_LOADED) { + log_error_unit(u->id, "Socket service %s not loaded, refusing.", UNIT(service)->id); + return -ENOENT; + } + + /* If the service is already active we cannot start the + * socket */ + if (service->state != SERVICE_DEAD && + service->state != SERVICE_FAILED && + service->state != SERVICE_AUTO_RESTART) { + log_error_unit(u->id, "Socket service %s already active, refusing.", UNIT(service)->id); + return -EBUSY; + } + +#ifdef HAVE_SYSV_COMPAT + if (service->is_sysv) { + log_error_unit(u->id, + "Using SysV services for socket activation is not supported. Refusing."); + return -ENOENT; + } +#endif + } + + assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED); + + s->result = SOCKET_SUCCESS; + socket_enter_start_pre(s); + + return 0; +} + +static int socket_stop(Unit *u) { + Socket *s = SOCKET(u); + + assert(s); + + /* Already on it */ + if (s->state == SOCKET_STOP_PRE || + s->state == SOCKET_STOP_PRE_SIGTERM || + s->state == SOCKET_STOP_PRE_SIGKILL || + s->state == SOCKET_STOP_POST || + s->state == SOCKET_FINAL_SIGTERM || + s->state == SOCKET_FINAL_SIGKILL) + return 0; + + /* If there's already something running we go directly into + * kill mode. */ + if (s->state == SOCKET_START_PRE || + s->state == SOCKET_START_POST) { + socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_SUCCESS); + return -EAGAIN; + } + + assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING); + + socket_enter_stop_pre(s, SOCKET_SUCCESS); + return 0; +} + +static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { + Socket *s = SOCKET(u); + SocketPort *p; + int r; + + assert(u); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", socket_state_to_string(s->state)); + unit_serialize_item(u, f, "result", socket_result_to_string(s->result)); + unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted); + + if (s->control_pid > 0) + unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); + + if (s->control_command_id >= 0) + unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id)); + + LIST_FOREACH(port, p, s->ports) { + int copy; + + if (p->fd < 0) + continue; + + copy = fdset_put_dup(fds, p->fd); + if (copy < 0) + return copy; + + if (p->type == SOCKET_SOCKET) { + _cleanup_free_ char *t = NULL; + + r = socket_address_print(&p->address, &t); + if (r < 0) + return r; + + if (socket_address_family(&p->address) == AF_NETLINK) + unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t); + else + unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t); + + } else if (p->type == SOCKET_SPECIAL) + unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path); + else if (p->type == SOCKET_MQUEUE) + unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path); + else { + assert(p->type == SOCKET_FIFO); + unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path); + } + } + + return 0; +} + +static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Socket *s = SOCKET(u); + + assert(u); + assert(key); + assert(value); + + if (streq(key, "state")) { + SocketState state; + + state = socket_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + s->deserialized_state = state; + } else if (streq(key, "result")) { + SocketResult f; + + f = socket_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != SOCKET_SUCCESS) + s->result = f; + + } else if (streq(key, "n-accepted")) { + unsigned k; + + if (safe_atou(value, &k) < 0) + log_debug_unit(u->id, "Failed to parse n-accepted value %s", value); + else + s->n_accepted += k; + } else if (streq(key, "control-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(u->id, "Failed to parse control-pid value %s", value); + else + s->control_pid = pid; + } else if (streq(key, "control-command")) { + SocketExecCommand id; + + id = socket_exec_command_from_string(value); + if (id < 0) + log_debug_unit(u->id, "Failed to parse exec-command value %s", value); + else { + s->control_command_id = id; + s->control_command = s->exec_command[id]; + } + } else if (streq(key, "fifo")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse fifo value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_FIFO && + streq_ptr(p->path, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + + } else if (streq(key, "special")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse special value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_SPECIAL && + streq_ptr(p->path, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + + } else if (streq(key, "mqueue")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse mqueue value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_MQUEUE && + streq_ptr(p->path, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + + } else if (streq(key, "socket")) { + int fd, type, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse socket value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (socket_address_is(&p->address, value+skip, type)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + + } else if (streq(key, "netlink")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug_unit(u->id, "Failed to parse socket value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (socket_address_is_netlink(&p->address, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + } else + log_debug_unit(UNIT(s)->id, "Unknown serialization key '%s'", key); + + return 0; +} + +static int socket_distribute_fds(Unit *u, FDSet *fds) { + Socket *s = SOCKET(u); + SocketPort *p; + + assert(u); + + LIST_FOREACH(port, p, s->ports) { + Iterator i; + int fd; + + if (p->type != SOCKET_SOCKET) + continue; + + if (p->fd >= 0) + continue; + + FDSET_FOREACH(fd, fds, i) { + if (socket_address_matches_fd(&p->address, fd)) { + p->fd = fdset_remove(fds, fd); + s->deserialized_state = SOCKET_LISTENING; + break; + } + } + } + + return 0; +} + +_pure_ static UnitActiveState socket_active_state(Unit *u) { + assert(u); + + return state_translation_table[SOCKET(u)->state]; +} + +_pure_ static const char *socket_sub_state_to_string(Unit *u) { + assert(u); + + return socket_state_to_string(SOCKET(u)->state); +} + +const char* socket_port_type_to_string(SocketPort *p) { + + assert(p); + + switch (p->type) { + + case SOCKET_SOCKET: + + switch (p->address.type) { + + case SOCK_STREAM: + return "Stream"; + + case SOCK_DGRAM: + return "Datagram"; + + case SOCK_SEQPACKET: + return "SequentialPacket"; + + case SOCK_RAW: + if (socket_address_family(&p->address) == AF_NETLINK) + return "Netlink"; + + default: + return NULL; + } + + case SOCKET_SPECIAL: + return "Special"; + + case SOCKET_MQUEUE: + return "MessageQueue"; + + case SOCKET_FIFO: + return "FIFO"; + + default: + return NULL; + } +} + +_pure_ static bool socket_check_gc(Unit *u) { + Socket *s = SOCKET(u); + + assert(u); + + return s->n_connections > 0; +} + +static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + SocketPort *p = userdata; + int cfd = -1; + + assert(p); + assert(fd >= 0); + + if (p->socket->state != SOCKET_LISTENING) + return 0; + + log_debug_unit(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id); + + if (revents != EPOLLIN) { + + if (revents & EPOLLHUP) + log_error_unit(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", + UNIT(p->socket)->id); + else + log_error_unit(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.", + UNIT(p->socket)->id, revents); + + goto fail; + } + + if (p->socket->accept && + p->type == SOCKET_SOCKET && + socket_address_can_accept(&p->address)) { + + for (;;) { + + cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK); + if (cfd < 0) { + + if (errno == EINTR) + continue; + + log_error_unit(UNIT(p->socket)->id, + "Failed to accept socket: %m"); + goto fail; + } + + break; + } + + socket_apply_socket_options(p->socket, cfd); + } + + socket_enter_running(p->socket, cfd); + return 0; + +fail: + socket_enter_stop_pre(p->socket, SOCKET_FAILURE_RESOURCES); + return 0; +} + +static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { + Socket *s = SOCKET(u); + SocketResult f; + + assert(s); + assert(pid >= 0); + + if (pid != s->control_pid) + return; + + s->control_pid = 0; + + if (is_clean_exit(code, status, NULL)) + f = SOCKET_SUCCESS; + else if (code == CLD_EXITED) + f = SOCKET_FAILURE_EXIT_CODE; + else if (code == CLD_KILLED) + f = SOCKET_FAILURE_SIGNAL; + else if (code == CLD_DUMPED) + f = SOCKET_FAILURE_CORE_DUMP; + else + assert_not_reached("Unknown code"); + + if (s->control_command) { + exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); + + if (s->control_command->ignore) + f = SOCKET_SUCCESS; + } + + log_full_unit(f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE, + u->id, + "%s control process exited, code=%s status=%i", + u->id, sigchld_code_to_string(code), status); + + if (f != SOCKET_SUCCESS) + s->result = f; + + if (s->control_command && + s->control_command->command_next && + f == SOCKET_SUCCESS) { + + log_debug_unit(u->id, + "%s running next command for state %s", + u->id, socket_state_to_string(s->state)); + socket_run_next(s); + } else { + s->control_command = NULL; + s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + + /* No further commands for this step, so let's figure + * out what to do next */ + + log_debug_unit(u->id, + "%s got final SIGCHLD for state %s", + u->id, socket_state_to_string(s->state)); + + switch (s->state) { + + case SOCKET_START_PRE: + if (f == SOCKET_SUCCESS) + socket_enter_start_post(s); + else + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, f); + break; + + case SOCKET_START_POST: + if (f == SOCKET_SUCCESS) + socket_enter_listening(s); + else + socket_enter_stop_pre(s, f); + break; + + case SOCKET_STOP_PRE: + case SOCKET_STOP_PRE_SIGTERM: + case SOCKET_STOP_PRE_SIGKILL: + socket_enter_stop_post(s, f); + break; + + case SOCKET_STOP_POST: + case SOCKET_FINAL_SIGTERM: + case SOCKET_FINAL_SIGKILL: + socket_enter_dead(s, f); + break; + + default: + assert_not_reached("Uh, control process died at wrong time."); + } + } + + /* Notify clients about changed exit status */ + unit_add_to_dbus_queue(u); +} + +static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Socket *s = SOCKET(userdata); + + assert(s); + assert(s->timer_event_source == source); + + switch (s->state) { + + case SOCKET_START_PRE: + log_warning_unit(UNIT(s)->id, + "%s starting timed out. Terminating.", UNIT(s)->id); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT); + break; + + case SOCKET_START_POST: + log_warning_unit(UNIT(s)->id, + "%s starting timed out. Stopping.", UNIT(s)->id); + socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT); + break; + + case SOCKET_STOP_PRE: + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Terminating.", UNIT(s)->id); + socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT); + break; + + case SOCKET_STOP_PRE_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Killing.", UNIT(s)->id); + socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, + "%s stopping timed out. Skipping SIGKILL. Ignoring.", + UNIT(s)->id); + socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT); + } + break; + + case SOCKET_STOP_PRE_SIGKILL: + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL. Ignoring.", UNIT(s)->id); + socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT); + break; + + case SOCKET_STOP_POST: + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Terminating.", UNIT(s)->id); + socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT); + break; + + case SOCKET_FINAL_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Killing.", UNIT(s)->id); + socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, + "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", + UNIT(s)->id); + socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); + } + break; + + case SOCKET_FINAL_SIGKILL: + log_warning_unit(UNIT(s)->id, + "%s still around after SIGKILL (2). Entering failed mode.", + UNIT(s)->id); + socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { + int *rfds; + unsigned rn_fds, k; + SocketPort *p; + + assert(s); + assert(fds); + assert(n_fds); + + /* Called from the service code for requesting our fds */ + + rn_fds = 0; + LIST_FOREACH(port, p, s->ports) + if (p->fd >= 0) + rn_fds++; + + if (rn_fds <= 0) { + *fds = NULL; + *n_fds = 0; + return 0; + } + + if (!(rfds = new(int, rn_fds))) + return -ENOMEM; + + k = 0; + LIST_FOREACH(port, p, s->ports) + if (p->fd >= 0) + rfds[k++] = p->fd; + + assert(k == rn_fds); + + *fds = rfds; + *n_fds = rn_fds; + + return 0; +} + +static void socket_reset_failed(Unit *u) { + Socket *s = SOCKET(u); + + assert(s); + + if (s->state == SOCKET_FAILED) + socket_set_state(s, SOCKET_DEAD); + + s->result = SOCKET_SUCCESS; +} + +static void socket_notify_service_dead(Socket *s, bool failed_permanent) { + assert(s); + + /* The service is dead. Dang! + * + * This is strictly for one-instance-for-all-connections + * services. */ + + if (s->state == SOCKET_RUNNING) { + log_debug_unit(UNIT(s)->id, "%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent)); + if (failed_permanent) + socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT); + else + socket_enter_listening(s); + } +} + +void socket_connection_unref(Socket *s) { + assert(s); + + /* The service is dead. Yay! + * + * This is strictly for one-instance-per-connection + * services. */ + + assert(s->n_connections > 0); + s->n_connections--; + + log_debug_unit(UNIT(s)->id, "%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections); +} + +static void socket_trigger_notify(Unit *u, Unit *other) { + Socket *s = SOCKET(u); + Service *se; + + assert(u); + assert(other); + + /* Don't propagate state changes from the service if we are + already down or accepting connections */ + if ((s->state != SOCKET_RUNNING && + s->state != SOCKET_LISTENING) || + s->accept) + return; + + if (other->load_state != UNIT_LOADED || + other->type != UNIT_SERVICE) + return; + + se = SERVICE(other); + + if (se->state == SERVICE_FAILED) + socket_notify_service_dead(s, se->result == SERVICE_FAILURE_START_LIMIT); + + if (se->state == SERVICE_DEAD || + se->state == SERVICE_STOP || + se->state == SERVICE_STOP_SIGTERM || + se->state == SERVICE_STOP_SIGKILL || + se->state == SERVICE_STOP_POST || + se->state == SERVICE_FINAL_SIGTERM || + se->state == SERVICE_FINAL_SIGKILL || + se->state == SERVICE_AUTO_RESTART) + socket_notify_service_dead(s, false); + + if (se->state == SERVICE_RUNNING) + socket_set_state(s, SOCKET_RUNNING); +} + +static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error); +} + +static int socket_get_timeout(Unit *u, uint64_t *timeout) { + Socket *s = SOCKET(u); + int r; + + if (!s->timer_event_source) + return 0; + + r = sd_event_source_get_time(s->timer_event_source, timeout); + if (r < 0) + return r; + + return 1; +} + +static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = "dead", + [SOCKET_START_PRE] = "start-pre", + [SOCKET_START_POST] = "start-post", + [SOCKET_LISTENING] = "listening", + [SOCKET_RUNNING] = "running", + [SOCKET_STOP_PRE] = "stop-pre", + [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", + [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", + [SOCKET_STOP_POST] = "stop-post", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", + [SOCKET_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + +static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { + [SOCKET_EXEC_START_PRE] = "StartPre", + [SOCKET_EXEC_START_POST] = "StartPost", + [SOCKET_EXEC_STOP_PRE] = "StopPre", + [SOCKET_EXEC_STOP_POST] = "StopPost" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); + +static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { + [SOCKET_SUCCESS] = "success", + [SOCKET_FAILURE_RESOURCES] = "resources", + [SOCKET_FAILURE_TIMEOUT] = "timeout", + [SOCKET_FAILURE_EXIT_CODE] = "exit-code", + [SOCKET_FAILURE_SIGNAL] = "signal", + [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); + +const UnitVTable socket_vtable = { + .object_size = sizeof(Socket), + .exec_context_offset = offsetof(Socket, exec_context), + .cgroup_context_offset = offsetof(Socket, cgroup_context), + .kill_context_offset = offsetof(Socket, kill_context), + .exec_runtime_offset = offsetof(Socket, exec_runtime), + + .sections = + "Unit\0" + "Socket\0" + "Install\0", + .private_section = "Socket", + + .init = socket_init, + .done = socket_done, + .load = socket_load, + + .coldplug = socket_coldplug, + + .dump = socket_dump, + + .start = socket_start, + .stop = socket_stop, + + .kill = socket_kill, + + .get_timeout = socket_get_timeout, + + .serialize = socket_serialize, + .deserialize_item = socket_deserialize_item, + .distribute_fds = socket_distribute_fds, + + .active_state = socket_active_state, + .sub_state_to_string = socket_sub_state_to_string, + + .check_gc = socket_check_gc, + + .sigchld_event = socket_sigchld_event, + + .trigger_notify = socket_trigger_notify, + + .reset_failed = socket_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.Socket", + .bus_vtable = bus_socket_vtable, + .bus_set_property = bus_socket_set_property, + .bus_commit_properties = bus_socket_commit_properties, + + .status_message_formats = { + /*.starting_stopping = { + [0] = "Starting socket %s...", + [1] = "Stopping socket %s...", + },*/ + .finished_start_job = { + [JOB_DONE] = "Listening on %s.", + [JOB_FAILED] = "Failed to listen on %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_TIMEOUT] = "Timed out starting %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Closed %s.", + [JOB_FAILED] = "Failed stopping %s.", + [JOB_TIMEOUT] = "Timed out stopping %s.", + }, + }, +}; diff --git a/src/core/socket.h b/src/core/socket.h new file mode 100644 index 0000000..076a183 --- /dev/null +++ b/src/core/socket.h @@ -0,0 +1,178 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Socket Socket; + +#include "manager.h" +#include "unit.h" +#include "socket-util.h" +#include "mount.h" +#include "service.h" + +typedef enum SocketState { + SOCKET_DEAD, + SOCKET_START_PRE, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL, + SOCKET_FAILED, + _SOCKET_STATE_MAX, + _SOCKET_STATE_INVALID = -1 +} SocketState; + +typedef enum SocketExecCommand { + SOCKET_EXEC_START_PRE, + SOCKET_EXEC_START_POST, + SOCKET_EXEC_STOP_PRE, + SOCKET_EXEC_STOP_POST, + _SOCKET_EXEC_COMMAND_MAX, + _SOCKET_EXEC_COMMAND_INVALID = -1 +} SocketExecCommand; + +typedef enum SocketType { + SOCKET_SOCKET, + SOCKET_FIFO, + SOCKET_SPECIAL, + SOCKET_MQUEUE, + _SOCKET_FIFO_MAX, + _SOCKET_FIFO_INVALID = -1 +} SocketType; + +typedef enum SocketResult { + SOCKET_SUCCESS, + SOCKET_FAILURE_RESOURCES, + SOCKET_FAILURE_TIMEOUT, + SOCKET_FAILURE_EXIT_CODE, + SOCKET_FAILURE_SIGNAL, + SOCKET_FAILURE_CORE_DUMP, + SOCKET_FAILURE_SERVICE_FAILED_PERMANENT, + _SOCKET_RESULT_MAX, + _SOCKET_RESULT_INVALID = -1 +} SocketResult; + +typedef struct SocketPort { + Socket *socket; + + SocketType type; + int fd; + + SocketAddress address; + char *path; + sd_event_source *event_source; + + LIST_FIELDS(struct SocketPort, port); +} SocketPort; + +struct Socket { + Unit meta; + + LIST_HEAD(SocketPort, ports); + + unsigned n_accepted; + unsigned n_connections; + unsigned max_connections; + + unsigned backlog; + usec_t timeout_usec; + + ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX]; + ExecContext exec_context; + KillContext kill_context; + CGroupContext cgroup_context; + ExecRuntime *exec_runtime; + + /* For Accept=no sockets refers to the one service we'll + activate. For Accept=yes sockets is either NULL, or filled + when the next service we spawn. */ + UnitRef service; + + SocketState state, deserialized_state; + + sd_event_source *timer_event_source; + + ExecCommand* control_command; + SocketExecCommand control_command_id; + pid_t control_pid; + + mode_t directory_mode; + mode_t socket_mode; + + SocketResult result; + + bool accept; + + /* Socket options */ + bool keep_alive; + bool free_bind; + bool transparent; + bool broadcast; + bool pass_cred; + bool pass_sec; + + /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */ + SocketAddressBindIPv6Only bind_ipv6_only; + + int priority; + int mark; + size_t receive_buffer; + size_t send_buffer; + int ip_tos; + int ip_ttl; + size_t pipe_size; + char *bind_to_device; + char *tcp_congestion; + bool reuse_port; + long mq_maxmsg; + long mq_msgsize; + + char *smack; + char *smack_ip_in; + char *smack_ip_out; +}; + +/* Called from the service code when collecting fds */ +int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds); + +/* Called from the service code when a per-connection service ended */ +void socket_connection_unref(Socket *s); + +void socket_free_ports(Socket *s); + +extern const UnitVTable socket_vtable; + +const char* socket_state_to_string(SocketState i) _const_; +SocketState socket_state_from_string(const char *s) _pure_; + +const char* socket_exec_command_to_string(SocketExecCommand i) _const_; +SocketExecCommand socket_exec_command_from_string(const char *s) _pure_; + +const char* socket_result_to_string(SocketResult i) _const_; +SocketResult socket_result_from_string(const char *s) _pure_; + +const char* socket_port_type_to_string(SocketPort *p) _pure_; diff --git a/src/core/swap.c b/src/core/swap.c new file mode 100644 index 0000000..24c4611 --- /dev/null +++ b/src/core/swap.c @@ -0,0 +1,1492 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "unit.h" +#include "swap.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "unit-name.h" +#include "dbus-swap.h" +#include "special.h" +#include "bus-errors.h" +#include "exit-status.h" +#include "def.h" +#include "path-util.h" +#include "virt.h" +#include "udev-util.h" + +static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = UNIT_INACTIVE, + [SWAP_ACTIVATING] = UNIT_ACTIVATING, + [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE, + [SWAP_ACTIVE] = UNIT_ACTIVE, + [SWAP_DEACTIVATING] = UNIT_DEACTIVATING, + [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING, + [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING, + [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING, + [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING, + [SWAP_FAILED] = UNIT_FAILED +}; + +static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); + +static void swap_unset_proc_swaps(Swap *s) { + assert(s); + + if (!s->from_proc_swaps) + return; + + free(s->parameters_proc_swaps.what); + s->parameters_proc_swaps.what = NULL; + + s->from_proc_swaps = false; +} + +static int swap_set_devnode(Swap *s, const char *devnode) { + Hashmap *swaps; + Swap *first; + int r; + + assert(s); + + r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, string_hash_func, string_compare_func); + if (r < 0) + return r; + + swaps = UNIT(s)->manager->swaps_by_devnode; + + if (s->devnode) { + first = hashmap_get(swaps, s->devnode); + + LIST_REMOVE(same_devnode, first, s); + if (first) + hashmap_replace(swaps, first->devnode, first); + else + hashmap_remove(swaps, s->devnode); + + free(s->devnode); + s->devnode = NULL; + } + + if (devnode) { + s->devnode = strdup(devnode); + if (!s->devnode) + return -ENOMEM; + + first = hashmap_get(swaps, s->devnode); + LIST_PREPEND(same_devnode, first, s); + + return hashmap_replace(swaps, first->devnode, first); + } + + return 0; +} + +static void swap_init(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + assert(UNIT(s)->load_state == UNIT_STUB); + + s->timeout_usec = u->manager->default_timeout_start_usec; + + exec_context_init(&s->exec_context); + s->exec_context.std_output = u->manager->default_std_output; + s->exec_context.std_error = u->manager->default_std_error; + kill_context_init(&s->kill_context); + cgroup_context_init(&s->cgroup_context); + + s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1; + + s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; + + u->ignore_on_isolate = true; +} + +static void swap_unwatch_control_pid(Swap *s) { + assert(s); + + if (s->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(s), s->control_pid); + s->control_pid = 0; +} + +static void swap_done(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + swap_unset_proc_swaps(s); + swap_set_devnode(s, NULL); + + free(s->what); + s->what = NULL; + + free(s->parameters_fragment.what); + s->parameters_fragment.what = NULL; + + cgroup_context_done(&s->cgroup_context); + exec_context_done(&s->exec_context); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); + s->control_command = NULL; + + swap_unwatch_control_pid(s); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); +} + +static int swap_arm_timer(Swap *s) { + int r; + + assert(s); + + if (s->timeout_usec <= 0) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + return 0; + } + + if (s->timer_event_source) { + r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); + } + + return sd_event_add_monotonic(UNIT(s)->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec, 0, swap_dispatch_timer, s); +} + +static int swap_add_device_links(Swap *s) { + SwapParameters *p; + + assert(s); + + if (!s->what) + return 0; + + if (s->from_fragment) + p = &s->parameters_fragment; + else + return 0; + + if (is_device_path(s->what)) + return unit_add_node_link(UNIT(s), s->what, !p->noauto && UNIT(s)->manager->running_as == SYSTEMD_SYSTEM); + else + /* File based swap devices need to be ordered after + * systemd-remount-fs.service, since they might need a + * writable file system. */ + return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true); +} + +static int swap_add_default_dependencies(Swap *s) { + bool nofail = false, noauto = false; + int r; + + assert(s); + + if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM) + return 0; + + if (detect_container(NULL) > 0) + return 0; + + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + if (r < 0) + return r; + + if (s->from_fragment) { + SwapParameters *p = &s->parameters_fragment; + + nofail = p->nofail; + noauto = p->noauto; + } + + if (!noauto) { + if (nofail) + r = unit_add_dependency_by_name_inverse(UNIT(s), UNIT_WANTS, SPECIAL_SWAP_TARGET, NULL, true); + else + r = unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true); + if (r < 0) + return r; + } + + return 0; +} + +static int swap_verify(Swap *s) { + bool b; + _cleanup_free_ char *e = NULL; + + if (UNIT(s)->load_state != UNIT_LOADED) + return 0; + + e = unit_name_from_path(s->what, ".swap"); + if (!e) + return log_oom(); + + b = unit_has_name(UNIT(s), e); + if (!b) { + log_error_unit(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id); + return -EINVAL; + } + + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { + log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id); + return -EINVAL; + } + + return 0; +} + +static int swap_load_devnode(Swap *s) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct stat st; + const char *p; + + assert(s); + + if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode)) + return 0; + + d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev); + if (!d) + return 0; + + p = udev_device_get_devnode(d); + if (!p) + return 0; + + return swap_set_devnode(s, p); +} + +static int swap_load(Unit *u) { + int r; + Swap *s = SWAP(u); + + assert(s); + assert(u->load_state == UNIT_STUB); + + /* Load a .swap file */ + r = unit_load_fragment_and_dropin_optional(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + r = unit_add_exec_dependencies(u, &s->exec_context); + if (r < 0) + return r; + + if (UNIT(s)->fragment_path) + s->from_fragment = true; + + if (!s->what) { + if (s->parameters_fragment.what) + s->what = strdup(s->parameters_fragment.what); + else if (s->parameters_proc_swaps.what) + s->what = strdup(s->parameters_proc_swaps.what); + else + s->what = unit_name_to_path(u->id); + + if (!s->what) + return -ENOMEM; + } + + path_kill_slashes(s->what); + + if (!UNIT(s)->description) { + r = unit_set_description(u, s->what); + if (r < 0) + return r; + } + + r = unit_require_mounts_for(UNIT(s), s->what); + if (r < 0) + return r; + + r = swap_add_device_links(s); + if (r < 0) + return r; + + r = swap_load_devnode(s); + if (r < 0) + return r; + + r = unit_add_default_slice(u); + if (r < 0) + return r; + + if (UNIT(s)->default_dependencies) { + r = swap_add_default_dependencies(s); + if (r < 0) + return r; + } + + r = unit_exec_context_defaults(u, &s->exec_context); + if (r < 0) + return r; + } + + return swap_verify(s); +} + +static int swap_add_one( + Manager *m, + const char *what, + const char *what_proc_swaps, + int priority, + bool noauto, + bool nofail, + bool set_flags) { + + _cleanup_free_ char *e = NULL; + bool delete = false; + Unit *u = NULL; + int r; + SwapParameters *p; + + assert(m); + assert(what); + assert(what_proc_swaps); + + e = unit_name_from_path(what, ".swap"); + if (!e) + return log_oom(); + + u = manager_get_unit(m, e); + + if (u && + SWAP(u)->from_proc_swaps && + !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) + return -EEXIST; + + if (!u) { + delete = true; + + u = unit_new(m, sizeof(Swap)); + if (!u) + return log_oom(); + + r = unit_add_name(u, e); + if (r < 0) + goto fail; + + SWAP(u)->what = strdup(what); + if (!SWAP(u)->what) { + r = log_oom(); + goto fail; + } + + unit_add_to_load_queue(u); + } else + delete = false; + + p = &SWAP(u)->parameters_proc_swaps; + + if (!p->what) { + p->what = strdup(what_proc_swaps); + if (!p->what) { + r = -ENOMEM; + goto fail; + } + } + + if (set_flags) { + SWAP(u)->is_active = true; + SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps; + } + + SWAP(u)->from_proc_swaps = true; + + p->priority = priority; + p->noauto = noauto; + p->nofail = nofail; + + unit_add_to_dbus_queue(u); + + return 0; + +fail: + log_warning_unit(e, "Failed to load swap unit: %s", strerror(-r)); + + if (delete && u) + unit_free(u); + + return r; +} + +static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + const char *dn; + struct stat st; + int r; + + assert(m); + + r = swap_add_one(m, device, device, prio, false, false, set_flags); + if (r < 0) + return r; + + /* If this is a block device, then let's add duplicates for + * all other names of this block device */ + if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode)) + return 0; + + d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev); + if (!d) + return 0; + + /* Add the main device node */ + dn = udev_device_get_devnode(d); + if (dn && !streq(dn, device)) + swap_add_one(m, dn, device, prio, false, false, set_flags); + + /* Add additional units for all symlinks */ + first = udev_device_get_devlinks_list_entry(d); + udev_list_entry_foreach(item, first) { + const char *p; + + /* Don't bother with the /dev/block links */ + p = udev_list_entry_get_name(item); + + if (streq(p, device)) + continue; + + if (path_startswith(p, "/dev/block/")) + continue; + + if (stat(p, &st) >= 0) + if (!S_ISBLK(st.st_mode) || + st.st_rdev != udev_device_get_devnum(d)) + continue; + + swap_add_one(m, p, device, prio, false, false, set_flags); + } + + return r; +} + +static void swap_set_state(Swap *s, SwapState state) { + SwapState old_state; + + assert(s); + + old_state = s->state; + s->state = state; + + if (state != SWAP_ACTIVATING && + state != SWAP_ACTIVATING_SIGTERM && + state != SWAP_ACTIVATING_SIGKILL && + state != SWAP_ACTIVATING_DONE && + state != SWAP_DEACTIVATING && + state != SWAP_DEACTIVATING_SIGTERM && + state != SWAP_DEACTIVATING_SIGKILL) { + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + swap_unwatch_control_pid(s); + s->control_command = NULL; + s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; + } + + if (state != old_state) + log_debug_unit(UNIT(s)->id, + "%s changed %s -> %s", + UNIT(s)->id, + swap_state_to_string(old_state), + swap_state_to_string(state)); + + unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); +} + +static int swap_coldplug(Unit *u) { + Swap *s = SWAP(u); + SwapState new_state = SWAP_DEAD; + int r; + + assert(s); + assert(s->state == SWAP_DEAD); + + if (s->deserialized_state != s->state) + new_state = s->deserialized_state; + else if (s->from_proc_swaps) + new_state = SWAP_ACTIVE; + + if (new_state == s->state) + return 0; + + if (new_state == SWAP_ACTIVATING || + new_state == SWAP_ACTIVATING_SIGTERM || + new_state == SWAP_ACTIVATING_SIGKILL || + new_state == SWAP_ACTIVATING_DONE || + new_state == SWAP_DEACTIVATING || + new_state == SWAP_DEACTIVATING_SIGTERM || + new_state == SWAP_DEACTIVATING_SIGKILL) { + + if (s->control_pid <= 0) + return -EBADMSG; + + r = unit_watch_pid(UNIT(s), s->control_pid); + if (r < 0) + return r; + + r = swap_arm_timer(s); + if (r < 0) + return r; + } + + swap_set_state(s, new_state); + return 0; +} + +static void swap_dump(Unit *u, FILE *f, const char *prefix) { + Swap *s = SWAP(u); + SwapParameters *p; + + assert(s); + assert(f); + + if (s->from_proc_swaps) + p = &s->parameters_proc_swaps; + else if (s->from_fragment) + p = &s->parameters_fragment; + else + p = NULL; + + fprintf(f, + "%sSwap State: %s\n" + "%sResult: %s\n" + "%sWhat: %s\n" + "%sFrom /proc/swaps: %s\n" + "%sFrom fragment: %s\n", + prefix, swap_state_to_string(s->state), + prefix, swap_result_to_string(s->result), + prefix, s->what, + prefix, yes_no(s->from_proc_swaps), + prefix, yes_no(s->from_fragment)); + + if (s->devnode) + fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode); + + if (p) + fprintf(f, + "%sPriority: %i\n" + "%sNoAuto: %s\n" + "%sNoFail: %s\n", + prefix, p->priority, + prefix, yes_no(p->noauto), + prefix, yes_no(p->nofail)); + + if (s->control_pid > 0) + fprintf(f, + "%sControl PID: %lu\n", + prefix, (unsigned long) s->control_pid); + + exec_context_dump(&s->exec_context, f, prefix); + kill_context_dump(&s->kill_context, f, prefix); +} + +static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { + pid_t pid; + int r; + + assert(s); + assert(c); + assert(_pid); + + unit_realize_cgroup(UNIT(s)); + + r = unit_setup_exec_runtime(UNIT(s)); + if (r < 0) + goto fail; + + r = swap_arm_timer(s); + if (r < 0) + goto fail; + + r = exec_spawn(c, + NULL, + &s->exec_context, + NULL, 0, + UNIT(s)->manager->environment, + true, + true, + true, + UNIT(s)->manager->confirm_spawn, + UNIT(s)->manager->cgroup_supported, + UNIT(s)->cgroup_path, + UNIT(s)->id, + 0, + NULL, + s->exec_runtime, + &pid); + if (r < 0) + goto fail; + + r = unit_watch_pid(UNIT(s), pid); + if (r < 0) + /* FIXME: we need to do something here */ + goto fail; + + *_pid = pid; + + return 0; + +fail: + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + return r; +} + +static void swap_enter_dead(Swap *s, SwapResult f) { + assert(s); + + if (f != SWAP_SUCCESS) + s->result = f; + + exec_runtime_destroy(s->exec_runtime); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); + + swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD); +} + +static void swap_enter_active(Swap *s, SwapResult f) { + assert(s); + + if (f != SWAP_SUCCESS) + s->result = f; + + swap_set_state(s, SWAP_ACTIVE); +} + +static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { + int r; + + assert(s); + + if (f != SWAP_SUCCESS) + s->result = f; + + r = unit_kill_context( + UNIT(s), + &s->kill_context, + state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM, + -1, + s->control_pid, + false); + if (r < 0) + goto fail; + + if (r > 0) { + r = swap_arm_timer(s); + if (r < 0) + goto fail; + + swap_set_state(s, state); + } else if (state == SWAP_ACTIVATING_SIGTERM) + swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS); + else if (state == SWAP_DEACTIVATING_SIGTERM) + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS); + else + swap_enter_dead(s, SWAP_SUCCESS); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); + + swap_enter_dead(s, SWAP_FAILURE_RESOURCES); +} + +static void swap_enter_activating(Swap *s) { + int r, priority; + + assert(s); + + s->control_command_id = SWAP_EXEC_ACTIVATE; + s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE; + + if (s->from_fragment) + priority = s->parameters_fragment.priority; + else + priority = -1; + + if (priority >= 0) { + char p[DECIMAL_STR_MAX(int)]; + + sprintf(p, "%i", priority); + + r = exec_command_set( + s->control_command, + "/sbin/swapon", + "-p", + p, + s->what, + NULL); + } else + r = exec_command_set( + s->control_command, + "/sbin/swapon", + s->what, + NULL); + + if (r < 0) + goto fail; + + swap_unwatch_control_pid(s); + + r = swap_spawn(s, s->control_command, &s->control_pid); + if (r < 0) + goto fail; + + swap_set_state(s, SWAP_ACTIVATING); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'swapon' task: %s", + UNIT(s)->id, strerror(-r)); + swap_enter_dead(s, SWAP_FAILURE_RESOURCES); +} + +static void swap_enter_deactivating(Swap *s) { + int r; + + assert(s); + + s->control_command_id = SWAP_EXEC_DEACTIVATE; + s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE; + + r = exec_command_set(s->control_command, + "/sbin/swapoff", + s->what, + NULL); + if (r < 0) + goto fail; + + swap_unwatch_control_pid(s); + + r = swap_spawn(s, s->control_command, &s->control_pid); + if (r < 0) + goto fail; + + swap_set_state(s, SWAP_DEACTIVATING); + + return; + +fail: + log_warning_unit(UNIT(s)->id, + "%s failed to run 'swapoff' task: %s", + UNIT(s)->id, strerror(-r)); + swap_enter_active(s, SWAP_FAILURE_RESOURCES); +} + +static int swap_start(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + /* We cannot fulfill this request right now, try again later + * please! */ + + if (s->state == SWAP_DEACTIVATING || + s->state == SWAP_DEACTIVATING_SIGTERM || + s->state == SWAP_DEACTIVATING_SIGKILL || + s->state == SWAP_ACTIVATING_SIGTERM || + s->state == SWAP_ACTIVATING_SIGKILL) + return -EAGAIN; + + if (s->state == SWAP_ACTIVATING) + return 0; + + assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED); + + if (detect_container(NULL) > 0) + return -EPERM; + + s->result = SWAP_SUCCESS; + swap_enter_activating(s); + return 0; +} + +static int swap_stop(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + if (s->state == SWAP_DEACTIVATING || + s->state == SWAP_DEACTIVATING_SIGTERM || + s->state == SWAP_DEACTIVATING_SIGKILL || + s->state == SWAP_ACTIVATING_SIGTERM || + s->state == SWAP_ACTIVATING_SIGKILL) + return 0; + + assert(s->state == SWAP_ACTIVATING || + s->state == SWAP_ACTIVATING_DONE || + s->state == SWAP_ACTIVE); + + if (detect_container(NULL) > 0) + return -EPERM; + + swap_enter_deactivating(s); + return 0; +} + +static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { + Swap *s = SWAP(u); + + assert(s); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", swap_state_to_string(s->state)); + unit_serialize_item(u, f, "result", swap_result_to_string(s->result)); + + if (s->control_pid > 0) + unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); + + if (s->control_command_id >= 0) + unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id)); + + return 0; +} + +static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Swap *s = SWAP(u); + + assert(s); + assert(fds); + + if (streq(key, "state")) { + SwapState state; + + state = swap_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + s->deserialized_state = state; + } else if (streq(key, "result")) { + SwapResult f; + + f = swap_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != SWAP_SUCCESS) + s->result = f; + } else if (streq(key, "control-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_debug_unit(u->id, "Failed to parse control-pid value %s", value); + else + s->control_pid = pid; + + } else if (streq(key, "control-command")) { + SwapExecCommand id; + + id = swap_exec_command_from_string(value); + if (id < 0) + log_debug_unit(u->id, "Failed to parse exec-command value %s", value); + else { + s->control_command_id = id; + s->control_command = s->exec_command + id; + } + } else + log_debug_unit(u->id, "Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState swap_active_state(Unit *u) { + assert(u); + + return state_translation_table[SWAP(u)->state]; +} + +_pure_ static const char *swap_sub_state_to_string(Unit *u) { + assert(u); + + return swap_state_to_string(SWAP(u)->state); +} + +_pure_ static bool swap_check_gc(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + return s->from_proc_swaps; +} + +static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { + Swap *s = SWAP(u); + SwapResult f; + + assert(s); + assert(pid >= 0); + + if (pid != s->control_pid) + return; + + s->control_pid = 0; + + if (is_clean_exit(code, status, NULL)) + f = SWAP_SUCCESS; + else if (code == CLD_EXITED) + f = SWAP_FAILURE_EXIT_CODE; + else if (code == CLD_KILLED) + f = SWAP_FAILURE_SIGNAL; + else if (code == CLD_DUMPED) + f = SWAP_FAILURE_CORE_DUMP; + else + assert_not_reached("Unknown code"); + + if (f != SWAP_SUCCESS) + s->result = f; + + if (s->control_command) { + exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); + + s->control_command = NULL; + s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; + } + + log_full_unit(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE, + u->id, + "%s swap process exited, code=%s status=%i", + u->id, sigchld_code_to_string(code), status); + + switch (s->state) { + + case SWAP_ACTIVATING: + case SWAP_ACTIVATING_DONE: + case SWAP_ACTIVATING_SIGTERM: + case SWAP_ACTIVATING_SIGKILL: + + if (f == SWAP_SUCCESS) + swap_enter_active(s, f); + else + swap_enter_dead(s, f); + break; + + case SWAP_DEACTIVATING: + case SWAP_DEACTIVATING_SIGKILL: + case SWAP_DEACTIVATING_SIGTERM: + + swap_enter_dead(s, f); + break; + + default: + assert_not_reached("Uh, control process died at wrong time."); + } + + /* Notify clients about changed exit status */ + unit_add_to_dbus_queue(u); +} + +static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + Swap *s = SWAP(userdata); + + assert(s); + assert(s->timer_event_source == source); + + switch (s->state) { + + case SWAP_ACTIVATING: + case SWAP_ACTIVATING_DONE: + log_warning_unit(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id); + swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); + break; + + case SWAP_DEACTIVATING: + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id); + swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); + break; + + case SWAP_ACTIVATING_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id); + swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); + swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); + } + break; + + case SWAP_DEACTIVATING_SIGTERM: + if (s->kill_context.send_sigkill) { + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id); + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); + } else { + log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); + swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); + } + break; + + case SWAP_ACTIVATING_SIGKILL: + case SWAP_DEACTIVATING_SIGKILL: + log_warning_unit(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id); + swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +static int swap_load_proc_swaps(Manager *m, bool set_flags) { + unsigned i; + int r = 0; + + assert(m); + + rewind(m->proc_swaps); + + (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n"); + + for (i = 1;; i++) { + _cleanup_free_ char *dev = NULL, *d = NULL; + int prio = 0, k; + + k = fscanf(m->proc_swaps, + "%ms " /* device/file */ + "%*s " /* type of swap */ + "%*s " /* swap size */ + "%*s " /* used */ + "%i\n", /* priority */ + &dev, &prio); + if (k != 2) { + if (k == EOF) + break; + + log_warning("Failed to parse /proc/swaps:%u", i); + continue; + } + + d = cunescape(dev); + if (!d) + return -ENOMEM; + + k = swap_process_new_swap(m, d, prio, set_flags); + if (k < 0) + r = k; + } + + return r; +} + +static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + Unit *u; + int r; + + assert(m); + assert(revents & EPOLLPRI); + + r = swap_load_proc_swaps(m, true); + if (r < 0) { + log_error("Failed to reread /proc/swaps: %s", strerror(-r)); + + /* Reset flags, just in case, for late calls */ + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) { + Swap *swap = SWAP(u); + + swap->is_active = swap->just_activated = false; + } + + return 0; + } + + manager_dispatch_load_queue(m); + + LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) { + Swap *swap = SWAP(u); + + if (!swap->is_active) { + /* This has just been deactivated */ + + swap_unset_proc_swaps(swap); + + switch (swap->state) { + + case SWAP_ACTIVE: + swap_enter_dead(swap, SWAP_SUCCESS); + break; + + default: + /* Fire again */ + swap_set_state(swap, swap->state); + break; + } + + } else if (swap->just_activated) { + + /* New swap entry */ + + switch (swap->state) { + + case SWAP_DEAD: + case SWAP_FAILED: + swap_enter_active(swap, SWAP_SUCCESS); + break; + + case SWAP_ACTIVATING: + swap_set_state(swap, SWAP_ACTIVATING_DONE); + break; + + default: + /* Nothing really changed, but let's + * issue an notification call + * nonetheless, in case somebody is + * waiting for this. */ + swap_set_state(swap, swap->state); + break; + } + } + + /* Reset the flags for later calls */ + swap->is_active = swap->just_activated = false; + } + + return 1; +} + +static Unit *swap_following(Unit *u) { + Swap *s = SWAP(u); + Swap *other, *first = NULL; + + assert(s); + + if (streq_ptr(s->what, s->devnode)) + return NULL; + + /* Make everybody follow the unit that's named after the swap + * device in the kernel */ + + LIST_FOREACH_AFTER(same_devnode, other, s) + if (streq_ptr(other->what, other->devnode)) + return UNIT(other); + + LIST_FOREACH_BEFORE(same_devnode, other, s) { + if (streq_ptr(other->what, other->devnode)) + return UNIT(other); + + first = other; + } + + return UNIT(first); +} + +static int swap_following_set(Unit *u, Set **_set) { + Swap *s = SWAP(u), *other; + Set *set; + int r; + + assert(s); + assert(_set); + + if (LIST_JUST_US(same_devnode, s)) { + *_set = NULL; + return 0; + } + + set = set_new(NULL, NULL); + if (!set) + return -ENOMEM; + + LIST_FOREACH_AFTER(same_devnode, other, s) { + r = set_put(set, other); + if (r < 0) + goto fail; + } + + LIST_FOREACH_BEFORE(same_devnode, other, s) { + r = set_put(set, other); + if (r < 0) + goto fail; + } + + *_set = set; + return 1; + +fail: + set_free(set); + return r; +} + +static void swap_shutdown(Manager *m) { + assert(m); + + m->swap_event_source = sd_event_source_unref(m->swap_event_source); + + if (m->proc_swaps) { + fclose(m->proc_swaps); + m->proc_swaps = NULL; + } + + hashmap_free(m->swaps_by_devnode); + m->swaps_by_devnode = NULL; +} + +static int swap_enumerate(Manager *m) { + int r; + + assert(m); + + if (!m->proc_swaps) { + m->proc_swaps = fopen("/proc/swaps", "re"); + if (!m->proc_swaps) + return errno == ENOENT ? 0 : -errno; + + r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m); + if (r < 0) + goto fail; + + /* Dispatch this before we dispatch SIGCHLD, so that + * we always get the events from /proc/swaps before + * the SIGCHLD of /sbin/swapon. */ + r = sd_event_source_set_priority(m->swap_event_source, -10); + if (r < 0) + goto fail; + } + + r = swap_load_proc_swaps(m, false); + if (r < 0) + goto fail; + + return 0; + +fail: + swap_shutdown(m); + return r; +} + +int swap_process_new_device(Manager *m, struct udev_device *dev) { + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_free_ char *e = NULL; + const char *dn; + Swap *s; + int r = 0; + + assert(m); + assert(dev); + + dn = udev_device_get_devnode(dev); + if (!dn) + return 0; + + e = unit_name_from_path(dn, ".swap"); + if (!e) + return -ENOMEM; + + s = hashmap_get(m->units, e); + if (s) + r = swap_set_devnode(s, dn); + + first = udev_device_get_devlinks_list_entry(dev); + udev_list_entry_foreach(item, first) { + _cleanup_free_ char *n = NULL; + + n = unit_name_from_path(udev_list_entry_get_name(item), ".swap"); + if (!n) + return -ENOMEM; + + s = hashmap_get(m->units, n); + if (s) { + int q; + + q = swap_set_devnode(s, dn); + if (q < 0) + r = q; + } + } + + return r; +} + +int swap_process_removed_device(Manager *m, struct udev_device *dev) { + const char *dn; + int r = 0; + Swap *s; + + dn = udev_device_get_devnode(dev); + if (!dn) + return 0; + + while ((s = hashmap_get(m->swaps_by_devnode, dn))) { + int q; + + q = swap_set_devnode(s, NULL); + if (q < 0) + r = q; + } + + return r; +} + +static void swap_reset_failed(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + if (s->state == SWAP_FAILED) + swap_set_state(s, SWAP_DEAD); + + s->result = SWAP_SUCCESS; +} + +static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error); +} + +static int swap_get_timeout(Unit *u, uint64_t *timeout) { + Swap *s = SWAP(u); + int r; + + if (!s->timer_event_source) + return 0; + + r = sd_event_source_get_time(s->timer_event_source, timeout); + if (r < 0) + return r; + + return 1; +} + +static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = "dead", + [SWAP_ACTIVATING] = "activating", + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", + [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", + [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + +static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { + [SWAP_EXEC_ACTIVATE] = "ExecActivate", + [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand); + +static const char* const swap_result_table[_SWAP_RESULT_MAX] = { + [SWAP_SUCCESS] = "success", + [SWAP_FAILURE_RESOURCES] = "resources", + [SWAP_FAILURE_TIMEOUT] = "timeout", + [SWAP_FAILURE_EXIT_CODE] = "exit-code", + [SWAP_FAILURE_SIGNAL] = "signal", + [SWAP_FAILURE_CORE_DUMP] = "core-dump" +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult); + +const UnitVTable swap_vtable = { + .object_size = sizeof(Swap), + .exec_context_offset = offsetof(Swap, exec_context), + .cgroup_context_offset = offsetof(Swap, cgroup_context), + .kill_context_offset = offsetof(Swap, kill_context), + .exec_runtime_offset = offsetof(Swap, exec_runtime), + + .sections = + "Unit\0" + "Swap\0" + "Install\0", + .private_section = "Swap", + + .no_alias = true, + .no_instances = true, + + .init = swap_init, + .load = swap_load, + .done = swap_done, + + .coldplug = swap_coldplug, + + .dump = swap_dump, + + .start = swap_start, + .stop = swap_stop, + + .kill = swap_kill, + + .get_timeout = swap_get_timeout, + + .serialize = swap_serialize, + .deserialize_item = swap_deserialize_item, + + .active_state = swap_active_state, + .sub_state_to_string = swap_sub_state_to_string, + + .check_gc = swap_check_gc, + + .sigchld_event = swap_sigchld_event, + + .reset_failed = swap_reset_failed, + + .bus_interface = "org.freedesktop.systemd1.Swap", + .bus_vtable = bus_swap_vtable, + .bus_set_property = bus_swap_set_property, + .bus_commit_properties = bus_swap_commit_properties, + + .following = swap_following, + .following_set = swap_following_set, + + .enumerate = swap_enumerate, + .shutdown = swap_shutdown, + + .status_message_formats = { + .starting_stopping = { + [0] = "Activating swap %s...", + [1] = "Deactivating swap %s...", + }, + .finished_start_job = { + [JOB_DONE] = "Activated swap %s.", + [JOB_FAILED] = "Failed to activate swap %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_TIMEOUT] = "Timed out activating swap %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Deactivated swap %s.", + [JOB_FAILED] = "Failed deactivating swap %s.", + [JOB_TIMEOUT] = "Timed out deactivating swap %s.", + }, + }, +}; diff --git a/src/core/swap.h b/src/core/swap.h new file mode 100644 index 0000000..f2ae49b --- /dev/null +++ b/src/core/swap.h @@ -0,0 +1,130 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Maarten Lankhorst + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +typedef struct Swap Swap; + +#include "unit.h" + +typedef enum SwapState { + SWAP_DEAD, + SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, + _SWAP_STATE_MAX, + _SWAP_STATE_INVALID = -1 +} SwapState; + +typedef enum SwapExecCommand { + SWAP_EXEC_ACTIVATE, + SWAP_EXEC_DEACTIVATE, + _SWAP_EXEC_COMMAND_MAX, + _SWAP_EXEC_COMMAND_INVALID = -1 +} SwapExecCommand; + +typedef enum SwapResult { + SWAP_SUCCESS, + SWAP_FAILURE_RESOURCES, + SWAP_FAILURE_TIMEOUT, + SWAP_FAILURE_EXIT_CODE, + SWAP_FAILURE_SIGNAL, + SWAP_FAILURE_CORE_DUMP, + _SWAP_RESULT_MAX, + _SWAP_RESULT_INVALID = -1 +} SwapResult; + +typedef struct SwapParameters { + char *what; + int priority; + bool noauto:1; + bool nofail:1; +} SwapParameters; + +struct Swap { + Unit meta; + + char *what; + + /* If the device has already shown up, this is the device + * node, which might be different from what, due to + * symlinks */ + char *devnode; + + SwapParameters parameters_proc_swaps; + SwapParameters parameters_fragment; + + bool from_proc_swaps:1; + bool from_fragment:1; + + /* Used while looking for swaps that vanished or got added + * from/to /proc/swaps */ + bool is_active:1; + bool just_activated:1; + + SwapResult result; + + usec_t timeout_usec; + + ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX]; + ExecContext exec_context; + KillContext kill_context; + CGroupContext cgroup_context; + + ExecRuntime *exec_runtime; + + SwapState state, deserialized_state; + + ExecCommand* control_command; + SwapExecCommand control_command_id; + pid_t control_pid; + + sd_event_source *timer_event_source; + + /* In order to be able to distinguish dependencies on + different device nodes we might end up creating multiple + devices for the same swap. We chain them up here. */ + + LIST_FIELDS(struct Swap, same_devnode); +}; + +extern const UnitVTable swap_vtable; + +int swap_process_new_device(Manager *m, struct udev_device *dev); +int swap_process_removed_device(Manager *m, struct udev_device *dev); + +const char* swap_state_to_string(SwapState i) _const_; +SwapState swap_state_from_string(const char *s) _pure_; + +const char* swap_exec_command_to_string(SwapExecCommand i) _const_; +SwapExecCommand swap_exec_command_from_string(const char *s) _pure_; + +const char* swap_result_to_string(SwapResult i) _const_; +SwapResult swap_result_from_string(const char *s) _pure_; diff --git a/src/core/switch-root.c b/src/core/switch-root.c new file mode 100644 index 0000000..ce0e41d --- /dev/null +++ b/src/core/switch-root.c @@ -0,0 +1,167 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Harald Hoyer, Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "path-util.h" +#include "switch-root.h" +#include "missing.h" + +int switch_root(const char *new_root) { + + /* Don't try to unmount/move the old "/", there's no way to do it. */ + static const char move_mounts[] = + "/dev\0" + "/proc\0" + "/sys\0" + "/run\0"; + + int r, old_root_fd = -1; + struct stat new_root_stat; + bool old_root_remove; + const char *i; + _cleanup_free_ char *temporary_old_root = NULL; + + if (path_equal(new_root, "/")) + return 0; + + /* When using pivot_root() we assume that /mnt exists as place + * we can temporarily move the old root to. As we immediately + * unmount it from there it doesn't matter much which + * directory we choose for this, but it should be more likely + * than not that /mnt exists and is suitable as mount point + * and is on the same fs as the old root dir */ + temporary_old_root = strappend(new_root, "/mnt"); + if (!temporary_old_root) + return -ENOMEM; + + old_root_remove = in_initrd(); + + if (stat(new_root, &new_root_stat) < 0) { + r = -errno; + log_error("Failed to stat directory %s: %m", new_root); + goto fail; + } + + /* Work-around for a kernel bug: for some reason the kernel + * refuses switching root if any file systems are mounted + * MS_SHARED. Hence remount them MS_PRIVATE here as a + * work-around. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ + if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) + log_warning("Failed to make \"/\" private mount: %m"); + + NULSTR_FOREACH(i, move_mounts) { + char new_mount[PATH_MAX]; + struct stat sb; + + snprintf(new_mount, sizeof(new_mount), "%s%s", new_root, i); + char_array_0(new_mount); + + if ((stat(new_mount, &sb) < 0) || + sb.st_dev != new_root_stat.st_dev) { + + /* Mount point seems to be mounted already or + * stat failed. Unmount the old mount + * point. */ + if (umount2(i, MNT_DETACH) < 0) + log_warning("Failed to unmount %s: %m", i); + continue; + } + + if (mount(i, new_mount, NULL, MS_MOVE, NULL) < 0) { + log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount); + + if (umount2(i, MNT_FORCE) < 0) + log_warning("Failed to unmount %s: %m", i); + } + } + + if (chdir(new_root) < 0) { + r = -errno; + log_error("Failed to change directory to %s: %m", new_root); + goto fail; + } + + if (old_root_remove) { + old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY); + if (old_root_fd < 0) + log_warning("Failed to open root directory: %m"); + } + + /* We first try a pivot_root() so that we can umount the old + * root dir. In many cases (i.e. where rootfs is /), that's + * not possible however, and hence we simply overmount root */ + if (pivot_root(new_root, temporary_old_root) >= 0) { + + /* Immediately get rid of the old root. Since we are + * running off it we need to do this lazily. */ + if (umount2(temporary_old_root, MNT_DETACH) < 0) { + r = -errno; + log_error("Failed to umount old root dir %s: %m", temporary_old_root); + goto fail; + } + + } else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) { + r = -errno; + log_error("Failed to mount moving %s to /: %m", new_root); + goto fail; + } + + if (chroot(".") < 0) { + r = -errno; + log_error("Failed to change root: %m"); + goto fail; + } + + if (chdir("/") < 0) { + r = -errno; + log_error("Failed to change directory: %m"); + goto fail; + } + + if (old_root_fd >= 0) { + struct stat rb; + + if (fstat(old_root_fd, &rb) < 0) + log_warning("Failed to stat old root directory, leaving: %m"); + else { + rm_rf_children(old_root_fd, false, false, &rb); + old_root_fd = -1; + } + } + + r = 0; + +fail: + if (old_root_fd >= 0) + close_nointr_nofail(old_root_fd); + + return r; +} diff --git a/src/core/switch-root.h b/src/core/switch-root.h new file mode 100644 index 0000000..ab493b5 --- /dev/null +++ b/src/core/switch-root.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Harald Hoyer, Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int switch_root(const char *switch_root); diff --git a/src/core/sysfs-show.h b/src/core/sysfs-show.h new file mode 100644 index 0000000..9ffd129 --- /dev/null +++ b/src/core/sysfs-show.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int show_sysfs(const char *seat, const char *prefix, unsigned columns); diff --git a/src/core/system.conf b/src/core/system.conf new file mode 100644 index 0000000..158919d --- /dev/null +++ b/src/core/system.conf @@ -0,0 +1,50 @@ +# 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. +# +# See systemd-system.conf(5) for details + +[Manager] +#LogLevel=info +#LogTarget=journal-or-kmsg +#LogColor=yes +#LogLocation=no +#DumpCore=yes +#CrashShell=no +#ShowStatus=yes +#CrashChVT=1 +#CPUAffinity=1 2 +#JoinControllers=cpu,cpuacct net_cls,net_prio +#RuntimeWatchdogSec=0 +#ShutdownWatchdogSec=10min +#CapabilityBoundingSet= +#SystemCallArchitectures= +#TimerSlackNSec= +#DefaultStandardOutput=journal +#DefaultStandardError=inherit +#DefaultTimeoutStartSec=90s +#DefaultTimeoutStopSec=90s +#DefaultRestartSec=100ms +#DefaultStartLimitInterval=10s +#DefaultStartLimitBurst=5 +#DefaultEnvironment= +#DefaultExtraDependencies= +#DefaultLimitCPU= +#DefaultLimitFSIZE= +#DefaultLimitDATA= +#DefaultLimitSTACK= +#DefaultLimitCORE= +#DefaultLimitRSS= +#DefaultLimitNOFILE= +#DefaultLimitAS= +#DefaultLimitNPROC= +#DefaultLimitMEMLOCK= +#DefaultLimitLOCKS= +#DefaultLimitSIGPENDING= +#DefaultLimitMSGQUEUE= +#DefaultLimitNICE= +#DefaultLimitRTPRIO= +#DefaultLimitRTTIME= diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in new file mode 100644 index 0000000..de0f649 --- /dev/null +++ b/src/core/systemd.pc.in @@ -0,0 +1,26 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +systemdutildir=@rootlibexecdir@ +systemdsystemunitdir=@systemunitdir@ +systemdsystempresetdir=@systempresetdir@ +systemduserunitdir=@userunitdir@ +systemduserpresetdir=@userpresetdir@ +systemdsystemconfdir=@pkgsysconfdir@/system +systemduserconfdir=@pkgsysconfdir@/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@ +catalogdir=@catalogdir@ + +Name: systemd +Description: systemd System and Service Manager +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ diff --git a/src/core/target.c b/src/core/target.c new file mode 100644 index 0000000..68be22b --- /dev/null +++ b/src/core/target.c @@ -0,0 +1,240 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "unit.h" +#include "target.h" +#include "load-fragment.h" +#include "log.h" +#include "dbus-target.h" +#include "special.h" +#include "unit-name.h" + +static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = UNIT_INACTIVE, + [TARGET_ACTIVE] = UNIT_ACTIVE +}; + +static void target_set_state(Target *t, TargetState state) { + TargetState old_state; + assert(t); + + old_state = t->state; + t->state = state; + + if (state != old_state) + log_debug("%s changed %s -> %s", + UNIT(t)->id, + target_state_to_string(old_state), + target_state_to_string(state)); + + unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); +} + +static int target_add_default_dependencies(Target *t) { + + static const UnitDependency deps[] = { + UNIT_REQUIRES, + UNIT_REQUIRES_OVERRIDABLE, + UNIT_REQUISITE, + UNIT_REQUISITE_OVERRIDABLE, + UNIT_WANTS, + UNIT_BINDS_TO, + UNIT_PART_OF + }; + + Iterator i; + Unit *other; + int r; + unsigned k; + + assert(t); + + /* Imply ordering for requirement dependencies on target + * units. Note that when the user created a contradicting + * ordering manually we won't add anything in here to make + * sure we don't create a loop. */ + + for (k = 0; k < ELEMENTSOF(deps); k++) + SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) { + r = unit_add_default_target_dependency(other, UNIT(t)); + if (r < 0) + return r; + } + + /* Make sure targets are unloaded on shutdown */ + return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); +} + +static int target_load(Unit *u) { + Target *t = TARGET(u); + int r; + + assert(t); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + /* This is a new unit? Then let's add in some extras */ + if (u->load_state == UNIT_LOADED && u->default_dependencies) { + r = target_add_default_dependencies(t); + if (r < 0) + return r; + } + + return 0; +} + +static int target_coldplug(Unit *u) { + Target *t = TARGET(u); + + assert(t); + assert(t->state == TARGET_DEAD); + + if (t->deserialized_state != t->state) + target_set_state(t, t->deserialized_state); + + return 0; +} + +static void target_dump(Unit *u, FILE *f, const char *prefix) { + Target *t = TARGET(u); + + assert(t); + assert(f); + + fprintf(f, + "%sTarget State: %s\n", + prefix, target_state_to_string(t->state)); +} + +static int target_start(Unit *u) { + Target *t = TARGET(u); + + assert(t); + assert(t->state == TARGET_DEAD); + + target_set_state(t, TARGET_ACTIVE); + return 0; +} + +static int target_stop(Unit *u) { + Target *t = TARGET(u); + + assert(t); + assert(t->state == TARGET_ACTIVE); + + target_set_state(t, TARGET_DEAD); + return 0; +} + +static int target_serialize(Unit *u, FILE *f, FDSet *fds) { + Target *s = TARGET(u); + + assert(s); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", target_state_to_string(s->state)); + return 0; +} + +static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Target *s = TARGET(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + TargetState state; + + state = target_state_from_string(value); + if (state < 0) + log_debug("Failed to parse state value %s", value); + else + s->deserialized_state = state; + + } else + log_debug("Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState target_active_state(Unit *u) { + assert(u); + + return state_translation_table[TARGET(u)->state]; +} + +_pure_ static const char *target_sub_state_to_string(Unit *u) { + assert(u); + + return target_state_to_string(TARGET(u)->state); +} + +static const char* const target_state_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = "dead", + [TARGET_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); + +const UnitVTable target_vtable = { + .object_size = sizeof(Target), + + .sections = + "Unit\0" + "Target\0" + "Install\0", + + .load = target_load, + .coldplug = target_coldplug, + + .dump = target_dump, + + .start = target_start, + .stop = target_stop, + + .serialize = target_serialize, + .deserialize_item = target_deserialize_item, + + .active_state = target_active_state, + .sub_state_to_string = target_sub_state_to_string, + + .bus_interface = "org.freedesktop.systemd1.Target", + .bus_vtable = bus_target_vtable, + + .status_message_formats = { + .finished_start_job = { + [JOB_DONE] = "Reached target %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Stopped target %s.", + }, + }, +}; diff --git a/src/core/target.h b/src/core/target.h new file mode 100644 index 0000000..a5398d9 --- /dev/null +++ b/src/core/target.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Target Target; + +#include "unit.h" + +typedef enum TargetState { + TARGET_DEAD, + TARGET_ACTIVE, + _TARGET_STATE_MAX, + _TARGET_STATE_INVALID = -1 +} TargetState; + +struct Target { + Unit meta; + + TargetState state, deserialized_state; +}; + +extern const UnitVTable target_vtable; + +const char* target_state_to_string(TargetState i) _const_; +TargetState target_state_from_string(const char *s) _pure_; diff --git a/src/core/tcpwrap.c b/src/core/tcpwrap.c new file mode 100644 index 0000000..6c630fa --- /dev/null +++ b/src/core/tcpwrap.c @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#ifdef HAVE_LIBWRAP +#include +#endif + +#include "tcpwrap.h" +#include "log.h" + +bool socket_tcpwrap(int fd, const char *name) { +#ifdef HAVE_LIBWRAP + struct request_info req; + union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_storage storage; + } sa_union; + socklen_t l = sizeof(sa_union); + + if (getsockname(fd, &sa_union.sa, &l) < 0) + return true; + + if (sa_union.sa.sa_family != AF_INET && + sa_union.sa.sa_family != AF_INET6) + return true; + + request_init(&req, + RQ_DAEMON, name, + RQ_FILE, fd, + NULL); + + fromhost(&req); + + if (!hosts_access(&req)) { + log_warning("Connection refused by tcpwrap."); + return false; + } + + log_debug("Connection accepted by tcpwrap."); +#endif + return true; +} diff --git a/src/core/tcpwrap.h b/src/core/tcpwrap.h new file mode 100644 index 0000000..3353b65 --- /dev/null +++ b/src/core/tcpwrap.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +bool socket_tcpwrap(int fd, const char *name); diff --git a/src/core/timer.c b/src/core/timer.c new file mode 100644 index 0000000..1c3ab29 --- /dev/null +++ b/src/core/timer.c @@ -0,0 +1,649 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "unit.h" +#include "unit-name.h" +#include "timer.h" +#include "dbus-timer.h" +#include "special.h" +#include "bus-util.h" +#include "bus-error.h" + +static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = UNIT_INACTIVE, + [TIMER_WAITING] = UNIT_ACTIVE, + [TIMER_RUNNING] = UNIT_ACTIVE, + [TIMER_ELAPSED] = UNIT_ACTIVE, + [TIMER_FAILED] = UNIT_FAILED +}; + +static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata); + +static void timer_init(Unit *u) { + Timer *t = TIMER(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + t->next_elapse_monotonic = (usec_t) -1; + t->next_elapse_realtime = (usec_t) -1; + t->accuracy_usec = USEC_PER_MINUTE; +} + +void timer_free_values(Timer *t) { + TimerValue *v; + + assert(t); + + while ((v = t->values)) { + LIST_REMOVE(value, t->values, v); + + if (v->calendar_spec) + calendar_spec_free(v->calendar_spec); + + free(v); + } +} + +static void timer_done(Unit *u) { + Timer *t = TIMER(u); + + assert(t); + + timer_free_values(t); + + t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source); + t->realtime_event_source = sd_event_source_unref(t->realtime_event_source); +} + +static int timer_verify(Timer *t) { + assert(t); + + if (UNIT(t)->load_state != UNIT_LOADED) + return 0; + + if (!t->values) { + log_error_unit(UNIT(t)->id, + "%s lacks value setting. Refusing.", UNIT(t)->id); + return -EINVAL; + } + + return 0; +} + +static int timer_add_default_dependencies(Timer *t) { + int r; + + assert(t); + + r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true); + if (r < 0) + return r; + + if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + if (r < 0) + return r; + } + + return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); +} + +static int timer_load(Unit *u) { + Timer *t = TIMER(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + + if (set_isempty(u->dependencies[UNIT_TRIGGERS])) { + Unit *x; + + r = unit_load_related_unit(u, ".service", &x); + if (r < 0) + return r; + + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); + if (r < 0) + return r; + } + + if (UNIT(t)->default_dependencies) { + r = timer_add_default_dependencies(t); + if (r < 0) + return r; + } + } + + return timer_verify(t); +} + +static void timer_dump(Unit *u, FILE *f, const char *prefix) { + char buf[FORMAT_TIMESPAN_MAX]; + Timer *t = TIMER(u); + Unit *trigger; + TimerValue *v; + + trigger = UNIT_TRIGGER(u); + + fprintf(f, + "%sTimer State: %s\n" + "%sResult: %s\n" + "%sUnit: %s\n" + "%sAccuracy: %s\n", + prefix, timer_state_to_string(t->state), + prefix, timer_result_to_string(t->result), + prefix, trigger ? trigger->id : "n/a", + prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1)); + + LIST_FOREACH(value, v, t->values) { + + if (v->base == TIMER_CALENDAR) { + _cleanup_free_ char *p = NULL; + + calendar_spec_to_string(v->calendar_spec, &p); + + fprintf(f, + "%s%s: %s\n", + prefix, + timer_base_to_string(v->base), + strna(p)); + } else { + char timespan1[FORMAT_TIMESPAN_MAX]; + + fprintf(f, + "%s%s: %s\n", + prefix, + timer_base_to_string(v->base), + strna(format_timespan(timespan1, sizeof(timespan1), v->value, 0))); + } + } +} + +static void timer_set_state(Timer *t, TimerState state) { + TimerState old_state; + assert(t); + + old_state = t->state; + t->state = state; + + if (state != TIMER_WAITING) { + t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source); + t->realtime_event_source = sd_event_source_unref(t->realtime_event_source); + } + + if (state != old_state) + log_debug_unit(UNIT(t)->id, + "%s changed %s -> %s", UNIT(t)->id, + timer_state_to_string(old_state), + timer_state_to_string(state)); + + unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); +} + +static void timer_enter_waiting(Timer *t, bool initial); + +static int timer_coldplug(Unit *u) { + Timer *t = TIMER(u); + + assert(t); + assert(t->state == TIMER_DEAD); + + if (t->deserialized_state != t->state) { + + if (t->deserialized_state == TIMER_WAITING) + timer_enter_waiting(t, false); + else + timer_set_state(t, t->deserialized_state); + } + + return 0; +} + +static void timer_enter_dead(Timer *t, TimerResult f) { + assert(t); + + if (f != TIMER_SUCCESS) + t->result = f; + + timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD); +} + + +static void timer_enter_waiting(Timer *t, bool initial) { + TimerValue *v; + usec_t base = 0; + dual_timestamp ts; + bool found_monotonic = false, found_realtime = false; + int r; + + dual_timestamp_get(&ts); + t->next_elapse_monotonic = t->next_elapse_realtime = 0; + + LIST_FOREACH(value, v, t->values) { + + if (v->disabled) + continue; + + if (v->base == TIMER_CALENDAR) { + + r = calendar_spec_next_usec(v->calendar_spec, ts.realtime, &v->next_elapse); + if (r < 0) + continue; + + if (!found_realtime) + t->next_elapse_realtime = v->next_elapse; + else + t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse); + + found_realtime = true; + + } else { + switch (v->base) { + + case TIMER_ACTIVE: + if (state_translation_table[t->state] == UNIT_ACTIVE) + base = UNIT(t)->inactive_exit_timestamp.monotonic; + else + base = ts.monotonic; + break; + + case TIMER_BOOT: + /* CLOCK_MONOTONIC equals the uptime on Linux */ + base = 0; + break; + + case TIMER_STARTUP: + base = UNIT(t)->manager->userspace_timestamp.monotonic; + break; + + case TIMER_UNIT_ACTIVE: + + base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic; + + if (base <= 0) + base = t->last_trigger_monotonic; + + if (base <= 0) + continue; + + break; + + case TIMER_UNIT_INACTIVE: + + base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic; + + if (base <= 0) + base = t->last_trigger_monotonic; + + if (base <= 0) + continue; + + break; + + default: + assert_not_reached("Unknown timer base"); + } + + v->next_elapse = base + v->value; + + if (!initial && + v->next_elapse < ts.monotonic && + (v->base == TIMER_ACTIVE || v->base == TIMER_BOOT || v->base == TIMER_STARTUP)) { + /* This is a one time trigger, disable it now */ + v->disabled = true; + continue; + } + + if (!found_monotonic) + t->next_elapse_monotonic = v->next_elapse; + else + t->next_elapse_monotonic = MIN(t->next_elapse_monotonic, v->next_elapse); + + found_monotonic = true; + } + } + + if (!found_monotonic && !found_realtime) { + log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id); + timer_set_state(t, TIMER_ELAPSED); + return; + } + + if (found_monotonic) { + char buf[FORMAT_TIMESPAN_MAX]; + log_debug_unit(UNIT(t)->id, + "%s: Monotonic timer elapses in %s.", + UNIT(t)->id, + format_timespan(buf, sizeof(buf), t->next_elapse_monotonic > ts.monotonic ? t->next_elapse_monotonic - ts.monotonic : 0, 0)); + + if (t->monotonic_event_source) { + r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic); + if (r < 0) + goto fail; + + r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT); + } else + r = sd_event_add_monotonic(UNIT(t)->manager->event, &t->monotonic_event_source, t->next_elapse_monotonic, t->accuracy_usec, timer_dispatch, t); + + if (r < 0) + goto fail; + + } else if (t->monotonic_event_source) { + r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF); + + if (r < 0) + goto fail; + } + + if (found_realtime) { + char buf[FORMAT_TIMESTAMP_MAX]; + log_debug_unit(UNIT(t)->id, + "%s: Realtime timer elapses at %s.", + UNIT(t)->id, + format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); + + if (t->realtime_event_source) { + r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime); + if (r < 0) + goto fail; + + r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT); + } else + r = sd_event_add_realtime(UNIT(t)->manager->event, &t->realtime_event_source, t->next_elapse_realtime, t->accuracy_usec, timer_dispatch, t); + + if (r < 0) + goto fail; + + } else if (t->realtime_event_source) { + r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF); + + if (r < 0) + goto fail; + } + + timer_set_state(t, TIMER_WAITING); + return; + +fail: + log_warning_unit(UNIT(t)->id, + "%s failed to enter waiting state: %s", + UNIT(t)->id, strerror(-r)); + timer_enter_dead(t, TIMER_FAILURE_RESOURCES); +} + +static void timer_enter_running(Timer *t) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(t); + + /* Don't start job if we are supposed to go down */ + if (unit_stop_pending(UNIT(t))) + return; + + r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), + JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + + t->last_trigger_monotonic = now(CLOCK_MONOTONIC); + + timer_set_state(t, TIMER_RUNNING); + return; + +fail: + log_warning_unit(UNIT(t)->id, + "%s failed to queue unit startup job: %s", + UNIT(t)->id, bus_error_message(&error, r)); + timer_enter_dead(t, TIMER_FAILURE_RESOURCES); +} + +static int timer_start(Unit *u) { + Timer *t = TIMER(u); + + assert(t); + assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); + + if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + return -ENOENT; + + t->result = TIMER_SUCCESS; + timer_enter_waiting(t, true); + return 0; +} + +static int timer_stop(Unit *u) { + Timer *t = TIMER(u); + + assert(t); + assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED); + + timer_enter_dead(t, TIMER_SUCCESS); + return 0; +} + +static int timer_serialize(Unit *u, FILE *f, FDSet *fds) { + Timer *t = TIMER(u); + + assert(u); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", timer_state_to_string(t->state)); + unit_serialize_item(u, f, "result", timer_result_to_string(t->result)); + + return 0; +} + +static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Timer *t = TIMER(u); + + assert(u); + assert(key); + assert(value); + assert(fds); + + if (streq(key, "state")) { + TimerState state; + + state = timer_state_from_string(value); + if (state < 0) + log_debug_unit(u->id, "Failed to parse state value %s", value); + else + t->deserialized_state = state; + } else if (streq(key, "result")) { + TimerResult f; + + f = timer_result_from_string(value); + if (f < 0) + log_debug_unit(u->id, "Failed to parse result value %s", value); + else if (f != TIMER_SUCCESS) + t->result = f; + + } else + log_debug_unit(u->id, "Unknown serialization key '%s'", key); + + return 0; +} + +_pure_ static UnitActiveState timer_active_state(Unit *u) { + assert(u); + + return state_translation_table[TIMER(u)->state]; +} + +_pure_ static const char *timer_sub_state_to_string(Unit *u) { + assert(u); + + return timer_state_to_string(TIMER(u)->state); +} + +static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) { + Timer *t = TIMER(userdata); + + assert(t); + + if (t->state != TIMER_WAITING) + return 0; + + log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id); + timer_enter_running(t); + return 0; +} + +static void timer_trigger_notify(Unit *u, Unit *other) { + Timer *t = TIMER(u); + TimerValue *v; + + assert(u); + assert(other); + + if (other->load_state != UNIT_LOADED) + return; + + /* Reenable all timers that depend on unit state */ + LIST_FOREACH(value, v, t->values) + if (v->base == TIMER_UNIT_ACTIVE || + v->base == TIMER_UNIT_INACTIVE) + v->disabled = false; + + switch (t->state) { + + case TIMER_WAITING: + case TIMER_ELAPSED: + + /* Recalculate sleep time */ + timer_enter_waiting(t, false); + break; + + case TIMER_RUNNING: + + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { + log_debug_unit(UNIT(t)->id, + "%s got notified about unit deactivation.", + UNIT(t)->id); + timer_enter_waiting(t, false); + } + break; + + case TIMER_DEAD: + case TIMER_FAILED: + break; + + default: + assert_not_reached("Unknown timer state"); + } +} + +static void timer_reset_failed(Unit *u) { + Timer *t = TIMER(u); + + assert(t); + + if (t->state == TIMER_FAILED) + timer_set_state(t, TIMER_DEAD); + + t->result = TIMER_SUCCESS; +} + +static void timer_time_change(Unit *u) { + Timer *t = TIMER(u); + + assert(u); + + if (t->state != TIMER_WAITING) + return; + + log_debug_unit(u->id, + "%s: time change, recalculating next elapse.", u->id); + timer_enter_waiting(t, false); +} + +static const char* const timer_state_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = "dead", + [TIMER_WAITING] = "waiting", + [TIMER_RUNNING] = "running", + [TIMER_ELAPSED] = "elapsed", + [TIMER_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); + +static const char* const timer_base_table[_TIMER_BASE_MAX] = { + [TIMER_ACTIVE] = "OnActiveSec", + [TIMER_BOOT] = "OnBootSec", + [TIMER_STARTUP] = "OnStartupSec", + [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec", + [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec", + [TIMER_CALENDAR] = "OnCalendar" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); + +static const char* const timer_result_table[_TIMER_RESULT_MAX] = { + [TIMER_SUCCESS] = "success", + [TIMER_FAILURE_RESOURCES] = "resources" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); + +const UnitVTable timer_vtable = { + .object_size = sizeof(Timer), + + .sections = + "Unit\0" + "Timer\0" + "Install\0", + + .init = timer_init, + .done = timer_done, + .load = timer_load, + + .coldplug = timer_coldplug, + + .dump = timer_dump, + + .start = timer_start, + .stop = timer_stop, + + .serialize = timer_serialize, + .deserialize_item = timer_deserialize_item, + + .active_state = timer_active_state, + .sub_state_to_string = timer_sub_state_to_string, + + .trigger_notify = timer_trigger_notify, + + .reset_failed = timer_reset_failed, + .time_change = timer_time_change, + + .bus_interface = "org.freedesktop.systemd1.Timer", + .bus_vtable = bus_timer_vtable, +}; diff --git a/src/core/timer.h b/src/core/timer.h new file mode 100644 index 0000000..3e7efa4 --- /dev/null +++ b/src/core/timer.h @@ -0,0 +1,99 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Timer Timer; + +#include "unit.h" +#include "calendarspec.h" + +typedef enum TimerState { + TIMER_DEAD, + TIMER_WAITING, + TIMER_RUNNING, + TIMER_ELAPSED, + TIMER_FAILED, + _TIMER_STATE_MAX, + _TIMER_STATE_INVALID = -1 +} TimerState; + +typedef enum TimerBase { + TIMER_ACTIVE, + TIMER_BOOT, + TIMER_STARTUP, + TIMER_UNIT_ACTIVE, + TIMER_UNIT_INACTIVE, + TIMER_CALENDAR, + _TIMER_BASE_MAX, + _TIMER_BASE_INVALID = -1 +} TimerBase; + +typedef struct TimerValue { + TimerBase base; + bool disabled; + clockid_t clock_id; + + usec_t value; /* only for monotonic events */ + CalendarSpec *calendar_spec; /* only for calendar events */ + usec_t next_elapse; + + LIST_FIELDS(struct TimerValue, value); +} TimerValue; + +typedef enum TimerResult { + TIMER_SUCCESS, + TIMER_FAILURE_RESOURCES, + _TIMER_RESULT_MAX, + _TIMER_RESULT_INVALID = -1 +} TimerResult; + +struct Timer { + Unit meta; + + usec_t accuracy_usec; + + LIST_HEAD(TimerValue, values); + usec_t next_elapse_monotonic; + usec_t next_elapse_realtime; + + TimerState state, deserialized_state; + + sd_event_source *monotonic_event_source; + sd_event_source *realtime_event_source; + + TimerResult result; + + usec_t last_trigger_monotonic; +}; + +void timer_free_values(Timer *t); + +extern const UnitVTable timer_vtable; + +const char *timer_state_to_string(TimerState i) _const_; +TimerState timer_state_from_string(const char *s) _pure_; + +const char *timer_base_to_string(TimerBase i) _const_; +TimerBase timer_base_from_string(const char *s) _pure_; + +const char* timer_result_to_string(TimerResult i) _const_; +TimerResult timer_result_from_string(const char *s) _pure_; diff --git a/src/core/transaction.c b/src/core/transaction.c new file mode 100644 index 0000000..d00f427 --- /dev/null +++ b/src/core/transaction.c @@ -0,0 +1,1148 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "bus-errors.h" +#include "bus-util.h" +#include "bus-error.h" +#include "transaction.h" + +static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); + +static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) { + assert(tr); + assert(j); + + /* Deletes one job from the transaction */ + + transaction_unlink_job(tr, j, delete_dependencies); + + job_free(j); +} + +static void transaction_delete_unit(Transaction *tr, Unit *u) { + Job *j; + + /* Deletes all jobs associated with a certain unit from the + * transaction */ + + while ((j = hashmap_get(tr->jobs, u))) + transaction_delete_job(tr, j, true); +} + +void transaction_abort(Transaction *tr) { + Job *j; + + assert(tr); + + while ((j = hashmap_first(tr->jobs))) + transaction_delete_job(tr, j, false); + + assert(hashmap_isempty(tr->jobs)); +} + +static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) { + JobDependency *l; + + /* A recursive sweep through the graph that marks all units + * that matter to the anchor job, i.e. are directly or + * indirectly a dependency of the anchor job via paths that + * are fully marked as mattering. */ + + j->matters_to_anchor = true; + j->generation = generation; + + LIST_FOREACH(subject, l, j->subject_list) { + + /* This link does not matter */ + if (!l->matters) + continue; + + /* This unit has already been marked */ + if (l->object->generation == generation) + continue; + + transaction_find_jobs_that_matter_to_anchor(l->object, generation); + } +} + +static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) { + JobDependency *l, *last; + + assert(j); + assert(other); + assert(j->unit == other->unit); + assert(!j->installed); + + /* Merges 'other' into 'j' and then deletes 'other'. */ + + j->type = t; + j->state = JOB_WAITING; + j->override = j->override || other->override; + j->irreversible = j->irreversible || other->irreversible; + + j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor; + + /* Patch us in as new owner of the JobDependency objects */ + last = NULL; + LIST_FOREACH(subject, l, other->subject_list) { + assert(l->subject == other); + l->subject = j; + last = l; + } + + /* Merge both lists */ + if (last) { + last->subject_next = j->subject_list; + if (j->subject_list) + j->subject_list->subject_prev = last; + j->subject_list = other->subject_list; + } + + /* Patch us in as new owner of the JobDependency objects */ + last = NULL; + LIST_FOREACH(object, l, other->object_list) { + assert(l->object == other); + l->object = j; + last = l; + } + + /* Merge both lists */ + if (last) { + last->object_next = j->object_list; + if (j->object_list) + j->object_list->object_prev = last; + j->object_list = other->object_list; + } + + /* Kill the other job */ + other->subject_list = NULL; + other->object_list = NULL; + transaction_delete_job(tr, other, true); +} + +_pure_ static bool job_is_conflicted_by(Job *j) { + JobDependency *l; + + assert(j); + + /* Returns true if this job is pulled in by a least one + * ConflictedBy dependency. */ + + LIST_FOREACH(object, l, j->object_list) + if (l->conflicts) + return true; + + return false; +} + +static int delete_one_unmergeable_job(Transaction *tr, Job *j) { + Job *k; + + assert(j); + + /* Tries to delete one item in the linked list + * j->transaction_next->transaction_next->... that conflicts + * with another one, in an attempt to make an inconsistent + * transaction work. */ + + /* We rely here on the fact that if a merged with b does not + * merge with c, either a or b merge with c neither */ + LIST_FOREACH(transaction, j, j) + LIST_FOREACH(transaction, k, j->transaction_next) { + Job *d; + + /* Is this one mergeable? Then skip it */ + if (job_type_is_mergeable(j->type, k->type)) + continue; + + /* Ok, we found two that conflict, let's see if we can + * drop one of them */ + if (!j->matters_to_anchor && !k->matters_to_anchor) { + + /* Both jobs don't matter, so let's + * find the one that is smarter to + * remove. Let's think positive and + * rather remove stops then starts -- + * except if something is being + * stopped because it is conflicted by + * another unit in which case we + * rather remove the start. */ + + log_debug_unit(j->unit->id, + "Looking at job %s/%s conflicted_by=%s", + j->unit->id, job_type_to_string(j->type), + yes_no(j->type == JOB_STOP && job_is_conflicted_by(j))); + log_debug_unit(k->unit->id, + "Looking at job %s/%s conflicted_by=%s", + k->unit->id, job_type_to_string(k->type), + yes_no(k->type == JOB_STOP && job_is_conflicted_by(k))); + + if (j->type == JOB_STOP) { + + if (job_is_conflicted_by(j)) + d = k; + else + d = j; + + } else if (k->type == JOB_STOP) { + + if (job_is_conflicted_by(k)) + d = j; + else + d = k; + } else + d = j; + + } else if (!j->matters_to_anchor) + d = j; + else if (!k->matters_to_anchor) + d = k; + else + return -ENOEXEC; + + /* Ok, we can drop one, so let's do so. */ + log_debug_unit(d->unit->id, + "Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s", + j->unit->id, job_type_to_string(j->type), + k->unit->id, job_type_to_string(k->type), + d->unit->id, job_type_to_string(d->type)); + transaction_delete_job(tr, d, true); + return 0; + } + + return -EINVAL; +} + +static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) { + Job *j; + Iterator i; + int r; + + assert(tr); + + /* First step, check whether any of the jobs for one specific + * task conflict. If so, try to drop one of them. */ + HASHMAP_FOREACH(j, tr->jobs, i) { + JobType t; + Job *k; + + t = j->type; + LIST_FOREACH(transaction, k, j->transaction_next) { + if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0) + continue; + + /* OK, we could not merge all jobs for this + * action. Let's see if we can get rid of one + * of them */ + + r = delete_one_unmergeable_job(tr, j); + if (r >= 0) + /* Ok, we managed to drop one, now + * let's ask our callers to call us + * again after garbage collecting */ + return -EAGAIN; + + /* We couldn't merge anything. Failure */ + sd_bus_error_setf( + e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", + job_type_to_string(t), job_type_to_string(k->type), k->unit->id); + return r; + } + } + + /* Second step, merge the jobs. */ + HASHMAP_FOREACH(j, tr->jobs, i) { + JobType t = j->type; + Job *k; + + /* Merge all transaction jobs for j->unit */ + LIST_FOREACH(transaction, k, j->transaction_next) + assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0); + + while ((k = j->transaction_next)) { + if (tr->anchor_job == k) { + transaction_merge_and_delete_job(tr, k, j, t); + j = k; + } else + transaction_merge_and_delete_job(tr, j, k, t); + } + + assert(!j->transaction_next); + assert(!j->transaction_prev); + } + + return 0; +} + +static void transaction_drop_redundant(Transaction *tr) { + Job *j; + Iterator i; + + /* 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; + + 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))) + goto next_unit; + } + + /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */ + transaction_delete_job(tr, j, false); + goto rescan; + next_unit:; + } +} + +_pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) { + assert(u); + assert(!j->transaction_prev); + + /* Checks whether at least one of the jobs for this unit + * matters to the anchor. */ + + LIST_FOREACH(transaction, j, j) + if (j->matters_to_anchor) + return true; + + return false; +} + +static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) { + Iterator i; + Unit *u; + int r; + + assert(tr); + assert(j); + assert(!j->transaction_prev); + + /* Does a recursive sweep through the ordering graph, looking + * for a cycle. If we find a cycle we try to break it. */ + + /* Have we seen this before? */ + if (j->generation == generation) { + Job *k, *delete; + + /* If the marker is NULL we have been here already and + * decided the job was loop-free from here. Hence + * shortcut things and return right-away. */ + if (!j->marker) + return 0; + + /* So, the marker is not NULL and we already have been + * here. We have a cycle. Let's try to break it. We go + * backwards in our path and try to find a suitable + * job to remove. We use the marker to find our way + * back, since smart how we are we stored our way back + * in there. */ + log_warning_unit(j->unit->id, + "Found ordering cycle on %s/%s", + j->unit->id, job_type_to_string(j->type)); + + delete = NULL; + for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { + + /* logging for j not k here here to provide consistent narrative */ + log_info_unit(j->unit->id, + "Found dependency on %s/%s", + k->unit->id, job_type_to_string(k->type)); + + if (!delete && + !unit_matters_to_anchor(k->unit, k)) { + /* Ok, we can drop this one, so let's + * do so. */ + delete = k; + } + + /* Check if this in fact was the beginning of + * the cycle */ + if (k == j) + break; + } + + + if (delete) { + /* logging for j not k here here to provide consistent narrative */ + log_warning_unit(j->unit->id, + "Breaking ordering cycle by deleting job %s/%s", + delete->unit->id, job_type_to_string(delete->type)); + log_error_unit(delete->unit->id, + "Job %s/%s deleted to break ordering cycle starting with %s/%s", + delete->unit->id, job_type_to_string(delete->type), + j->unit->id, job_type_to_string(j->type)); + unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF, + "Ordering cycle found, skipping %s"); + transaction_delete_unit(tr, delete->unit); + return -EAGAIN; + } + + log_error("Unable to break cycle"); + + sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, + "Transaction order is cyclic. See system logs for details."); + return -ENOEXEC; + } + + /* Make the marker point to where we come from, so that we can + * find our way backwards if we want to break a cycle. We use + * a special marker for the beginning: we point to + * ourselves. */ + j->marker = from ? from : j; + j->generation = generation; + + /* We assume that the dependencies are bidirectional, and + * hence can ignore UNIT_AFTER */ + SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) { + Job *o; + + /* Is there a job for this unit? */ + o = hashmap_get(tr->jobs, u); + if (!o) { + /* Ok, there is no job for this in the + * transaction, but maybe there is already one + * running? */ + o = u->job; + if (!o) + continue; + } + + r = transaction_verify_order_one(tr, o, j, generation, e); + if (r < 0) + return r; + } + + /* Ok, let's backtrack, and remember that this entry is not on + * our path anymore. */ + j->marker = NULL; + + return 0; +} + +static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) { + Job *j; + int r; + Iterator i; + unsigned g; + + assert(tr); + assert(generation); + + /* Check if the ordering graph is cyclic. If it is, try to fix + * that up by dropping one of the jobs. */ + + g = (*generation)++; + + HASHMAP_FOREACH(j, tr->jobs, i) + if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0) + return r; + + return 0; +} + +static void transaction_collect_garbage(Transaction *tr) { + Iterator i; + Job *j; + + assert(tr); + + /* Drop jobs that are not required by any other job */ + +rescan: + HASHMAP_FOREACH(j, tr->jobs, i) { + if (tr->anchor_job == j || j->object_list) { + /* log_debug("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_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */ + transaction_delete_job(tr, j, true); + goto rescan; + } +} + +static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) { + Iterator i; + Job *j; + + assert(tr); + + /* Checks whether applying this transaction means that + * existing jobs would be replaced */ + + HASHMAP_FOREACH(j, tr->jobs, i) { + + /* Assume merged */ + assert(!j->transaction_prev); + assert(!j->transaction_next); + + if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) && + !job_type_is_superset(j->type, j->unit->job->type)) { + + sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); + return -EEXIST; + } + } + + return 0; +} + +static void transaction_minimize_impact(Transaction *tr) { + Job *j; + Iterator i; + + assert(tr); + + /* Drops all unnecessary jobs that reverse already active jobs + * or that stop a running service. */ + +rescan: + HASHMAP_FOREACH(j, tr->jobs, i) { + LIST_FOREACH(transaction, j, j) { + bool stops_running_service, changes_existing_job; + + /* If it matters, we shouldn't drop it */ + if (j->matters_to_anchor) + continue; + + /* Would this stop a running service? + * Would this change an existing job? + * If so, let's drop this entry */ + + stops_running_service = + j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); + + changes_existing_job = + j->unit->job && + job_type_is_conflicting(j->type, j->unit->job->type); + + if (!stops_running_service && !changes_existing_job) + continue; + + if (stops_running_service) + log_debug_unit(j->unit->id, + "%s/%s would stop a running service.", + j->unit->id, job_type_to_string(j->type)); + + if (changes_existing_job) + log_debug_unit(j->unit->id, + "%s/%s would change existing job.", + j->unit->id, job_type_to_string(j->type)); + + /* Ok, let's get rid of this */ + log_debug_unit(j->unit->id, + "Deleting %s/%s to minimize impact.", + j->unit->id, job_type_to_string(j->type)); + + transaction_delete_job(tr, j, true); + goto rescan; + } + } +} + +static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { + Iterator i; + Job *j; + int r; + + /* Moves the transaction jobs to the set of active jobs */ + + if (mode == JOB_ISOLATE || mode == JOB_FLUSH) { + + /* When isolating first kill all installed jobs which + * aren't part of the new transaction */ + HASHMAP_FOREACH(j, m->jobs, i) { + assert(j->installed); + + if (hashmap_get(tr->jobs, j->unit)) + continue; + + /* Not invalidating recursively. Avoids triggering + * OnFailure= actions of dependent jobs. Also avoids + * invalidating our iterator. */ + job_finish_and_invalidate(j, JOB_CANCELED, false); + } + } + + HASHMAP_FOREACH(j, tr->jobs, i) { + /* Assume merged */ + assert(!j->transaction_prev); + assert(!j->transaction_next); + + r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); + if (r < 0) + goto rollback; + } + + while ((j = hashmap_steal_first(tr->jobs))) { + Job *installed_job; + + /* Clean the job dependencies */ + transaction_unlink_job(tr, j, false); + + installed_job = job_install(j); + if (installed_job != j) { + /* j has been merged into a previously installed job */ + if (tr->anchor_job == j) + tr->anchor_job = installed_job; + hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); + job_free(j); + j = installed_job; + } + + job_add_to_run_queue(j); + job_add_to_dbus_queue(j); + job_start_timer(j); + job_shutdown_magic(j); + } + + return 0; + +rollback: + + HASHMAP_FOREACH(j, tr->jobs, i) + hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); + + return r; +} + +int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) { + Iterator i; + Job *j; + int r; + unsigned generation = 1; + + assert(tr); + + /* This applies the changes recorded in tr->jobs to + * the actual list of jobs, if possible. */ + + /* Reset the generation counter of all installed jobs. The detection of cycles + * looks at installed jobs. If they had a non-zero generation from some previous + * walk of the graph, the algorithm would break. */ + HASHMAP_FOREACH(j, m->jobs, i) + j->generation = 0; + + /* First step: figure out which jobs matter */ + transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++); + + /* Second step: Try not to stop any running services if + * we don't have to. Don't try to reverse running + * jobs if we don't have to. */ + if (mode == JOB_FAIL) + transaction_minimize_impact(tr); + + /* Third step: Drop redundant jobs */ + transaction_drop_redundant(tr); + + for (;;) { + /* Fourth step: Let's remove unneeded jobs that might + * be lurking. */ + if (mode != JOB_ISOLATE) + transaction_collect_garbage(tr); + + /* Fifth step: verify order makes sense and correct + * cycles if necessary and possible */ + r = transaction_verify_order(tr, &generation, e); + if (r >= 0) + break; + + if (r != -EAGAIN) { + log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r)); + return r; + } + + /* Let's see if the resulting transaction ordering + * graph is still cyclic... */ + } + + for (;;) { + /* Sixth step: let's drop unmergeable entries if + * necessary and possible, merge entries we can + * merge */ + r = transaction_merge_jobs(tr, e); + if (r >= 0) + break; + + if (r != -EAGAIN) { + log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r)); + return r; + } + + /* Seventh step: an entry got dropped, let's garbage + * collect its dependencies. */ + if (mode != JOB_ISOLATE) + transaction_collect_garbage(tr); + + /* Let's see if the resulting transaction still has + * unmergeable entries ... */ + } + + /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */ + transaction_drop_redundant(tr); + + /* Ninth step: check whether we can actually apply this */ + r = transaction_is_destructive(tr, mode, e); + if (r < 0) { + log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r)); + return r; + } + + /* Tenth step: apply changes */ + r = transaction_apply(tr, m, mode); + if (r < 0) { + log_warning("Failed to apply transaction: %s", strerror(-r)); + return r; + } + + assert(hashmap_isempty(tr->jobs)); + + if (!hashmap_isempty(m->jobs)) { + /* Are there any jobs now? Then make sure we have the + * idle pipe around. We don't really care too much + * whether this works or not, as the idle pipe is a + * feature for cosmetics, not actually useful for + * anything beyond that. */ + + if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 && + m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) { + pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC); + pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC); + } + } + + return 0; +} + +static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) { + Job *j, *f; + + assert(tr); + assert(unit); + + /* Looks for an existing prospective job and returns that. If + * it doesn't exist it is created and added to the prospective + * jobs list. */ + + f = hashmap_get(tr->jobs, unit); + + LIST_FOREACH(transaction, j, f) { + assert(j->unit == unit); + + if (j->type == type) { + if (is_new) + *is_new = false; + return j; + } + } + + j = job_new(unit, type); + if (!j) + return NULL; + + j->generation = 0; + j->marker = NULL; + j->matters_to_anchor = false; + j->override = override; + j->irreversible = tr->irreversible; + + LIST_PREPEND(transaction, f, j); + + if (hashmap_replace(tr->jobs, unit, f) < 0) { + LIST_REMOVE(transaction, f, j); + job_free(j); + return NULL; + } + + if (is_new) + *is_new = true; + + /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */ + + return j; +} + +static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { + assert(tr); + assert(j); + + if (j->transaction_prev) + j->transaction_prev->transaction_next = j->transaction_next; + else if (j->transaction_next) + hashmap_replace(tr->jobs, j->unit, j->transaction_next); + else + hashmap_remove_value(tr->jobs, j->unit, j); + + if (j->transaction_next) + j->transaction_next->transaction_prev = j->transaction_prev; + + j->transaction_prev = j->transaction_next = NULL; + + while (j->subject_list) + job_dependency_free(j->subject_list); + + while (j->object_list) { + Job *other = j->object_list->matters ? j->object_list->subject : NULL; + + job_dependency_free(j->object_list); + + if (other && delete_dependencies) { + log_debug_unit(other->unit->id, + "Deleting job %s/%s as dependency of job %s/%s", + other->unit->id, job_type_to_string(other->type), + j->unit->id, job_type_to_string(j->type)); + transaction_delete_job(tr, other, delete_dependencies); + } + } +} + +int transaction_add_job_and_dependencies( + Transaction *tr, + JobType type, + Unit *unit, + Job *by, + bool matters, + bool override, + bool conflicts, + bool ignore_requirements, + bool ignore_order, + sd_bus_error *e) { + Job *ret; + Iterator i; + Unit *dep; + int r; + bool is_new; + + assert(tr); + assert(type < _JOB_TYPE_MAX); + assert(type < _JOB_TYPE_MAX_IN_TRANSACTION); + assert(unit); + + /* log_debug("Pulling in %s/%s from %s/%s", */ + /* unit->id, job_type_to_string(type), */ + /* by ? by->unit->id : "NA", */ + /* by ? job_type_to_string(by->type) : "NA"); */ + + if (unit->load_state != UNIT_LOADED && + unit->load_state != UNIT_ERROR && + unit->load_state != UNIT_NOT_FOUND && + unit->load_state != UNIT_MASKED) { + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); + return -EINVAL; + } + + if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, + "Unit %s failed to load: %s. " + "See system logs and 'systemctl status %s' for details.", + unit->id, + strerror(-unit->load_error), + unit->id); + return -EINVAL; + } + + if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) { + sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, + "Unit %s failed to load: %s.", + unit->id, + strerror(-unit->load_error)); + return -EINVAL; + } + + if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { + sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", unit->id); + return -EADDRNOTAVAIL; + } + + if (!unit_job_is_applicable(unit, type)) { + sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id); + return -EBADR; + } + + /* First add the job. */ + ret = transaction_add_one_job(tr, type, unit, override, &is_new); + if (!ret) + return -ENOMEM; + + ret->ignore_order = ret->ignore_order || ignore_order; + + /* Then, add a link to the job. */ + if (by) { + if (!job_dependency_new(by, ret, matters, conflicts)) + return -ENOMEM; + } else { + /* If the job has no parent job, it is the anchor job. */ + assert(!tr->anchor_job); + tr->anchor_job = ret; + } + + if (is_new && !ignore_requirements && type != JOB_NOP) { + Set *following; + + /* If we are following some other unit, make sure we + * add all dependencies of everybody following. */ + if (unit_following_set(ret->unit, &following) > 0) { + SET_FOREACH(dep, following, i) { + r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e); + if (r < 0) { + log_warning_unit(dep->id, + "Cannot add dependency job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + + set_free(following); + } + + /* Finally, recursively add in all dependencies. */ + if (type == JOB_START || type == JOB_RESTART) { + SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e); + if (r < 0) { + log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, + "Cannot add dependency job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e); + if (r < 0) { + log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, + "Cannot add dependency job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { + r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { + r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e); + if (r < 0) { + log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id, + "Cannot add dependency job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e); + if (r < 0) { + log_warning_unit(dep->id, + "Cannot add dependency job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + + } + + if (type == JOB_STOP || type == JOB_RESTART) { + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) { + r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) { + r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) { + r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e); + if (r < 0) { + if (r != -EBADR) + goto fail; + + if (e) + sd_bus_error_free(e); + } + } + + } + + if (type == JOB_RELOAD) { + + SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { + r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e); + if (r < 0) { + log_warning_unit(dep->id, + "Cannot add dependency reload job for unit %s, ignoring: %s", + dep->id, bus_error_message(e, r)); + + if (e) + sd_bus_error_free(e); + } + } + } + + /* JOB_VERIFY_STARTED require no dependency handling */ + } + + return 0; + +fail: + return r; +} + +int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { + Iterator i; + Unit *u; + char *k; + int r; + + assert(tr); + assert(m); + + HASHMAP_FOREACH_KEY(u, k, m->units, i) { + + /* ignore aliases */ + if (u->id != k) + continue; + + if (u->ignore_on_isolate) + continue; + + /* No need to stop inactive jobs */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job) + continue; + + /* Is there already something listed for this? */ + if (hashmap_get(tr->jobs, u)) + continue; + + r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL); + if (r < 0) + log_warning_unit(u->id, + "Cannot add isolate job for unit %s, ignoring: %s", + u->id, strerror(-r)); + } + + return 0; +} + +Transaction *transaction_new(bool irreversible) { + Transaction *tr; + + tr = new0(Transaction, 1); + if (!tr) + return NULL; + + tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func); + if (!tr->jobs) { + free(tr); + return NULL; + } + + tr->irreversible = irreversible; + + return tr; +} + +void transaction_free(Transaction *tr) { + assert(hashmap_isempty(tr->jobs)); + hashmap_free(tr->jobs); + free(tr); +} diff --git a/src/core/transaction.h b/src/core/transaction.h new file mode 100644 index 0000000..d949b21 --- /dev/null +++ b/src/core/transaction.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Transaction Transaction; + +#include "unit.h" +#include "manager.h" +#include "job.h" +#include "hashmap.h" + +struct Transaction { + /* Jobs to be added */ + Hashmap *jobs; /* Unit object => Job object list 1:1 */ + Job *anchor_job; /* the job the user asked for */ + bool irreversible; +}; + +Transaction *transaction_new(bool irreversible); +void transaction_free(Transaction *tr); + +int transaction_add_job_and_dependencies( + Transaction *tr, + JobType type, + Unit *unit, + Job *by, + bool matters, + bool override, + bool conflicts, + 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_add_isolate_jobs(Transaction *tr, Manager *m); +void transaction_abort(Transaction *tr); diff --git a/src/core/umount.c b/src/core/umount.c new file mode 100644 index 0000000..2d166c1 --- /dev/null +++ b/src/core/umount.c @@ -0,0 +1,608 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 ProFUSION embedded systems + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "list.h" +#include "mount-setup.h" +#include "umount.h" +#include "path-util.h" +#include "util.h" +#include "virt.h" +#include "libudev.h" +#include "udev-util.h" + +typedef struct MountPoint { + char *path; + dev_t devnum; + LIST_FIELDS(struct MountPoint, mount_point); +} MountPoint; + +static void mount_point_free(MountPoint **head, MountPoint *m) { + assert(head); + assert(m); + + LIST_REMOVE(mount_point, *head, m); + + free(m->path); + free(m); +} + +static void mount_points_list_free(MountPoint **head) { + assert(head); + + while (*head) + mount_point_free(head, *head); +} + +static int mount_points_list_get(MountPoint **head) { + FILE *proc_self_mountinfo; + char *path, *p; + unsigned int i; + int r; + + assert(head); + + if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"))) + return -errno; + + for (i = 1;; i++) { + int k; + MountPoint *m; + + path = p = NULL; + + if ((k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path)) != 1) { + if (k == EOF) + break; + + log_warning("Failed to parse /proc/self/mountinfo:%u.", i); + + free(path); + continue; + } + + p = cunescape(path); + free(path); + + if (!p) { + r = -ENOMEM; + goto finish; + } + + /* Ignore mount points we can't unmount because they + * are API or because we are keeping them open (like + * /dev/console) */ + if (mount_point_is_api(p) || + mount_point_ignore(p) || + path_equal(p, "/dev/console")) { + free(p); + continue; + } + + if (!(m = new0(MountPoint, 1))) { + free(p); + r = -ENOMEM; + goto finish; + } + + m->path = p; + LIST_PREPEND(mount_point, *head, m); + } + + r = 0; + +finish: + fclose(proc_self_mountinfo); + + return r; +} + +static int swap_list_get(MountPoint **head) { + FILE *proc_swaps; + unsigned int i; + int r; + + assert(head); + + if (!(proc_swaps = fopen("/proc/swaps", "re"))) + return (errno == ENOENT) ? 0 : -errno; + + (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n"); + + for (i = 2;; i++) { + MountPoint *swap; + char *dev = NULL, *d; + int k; + + if ((k = fscanf(proc_swaps, + "%ms " /* device/file */ + "%*s " /* type of swap */ + "%*s " /* swap size */ + "%*s " /* used */ + "%*s\n", /* priority */ + &dev)) != 1) { + + if (k == EOF) + break; + + log_warning("Failed to parse /proc/swaps:%u.", i); + + free(dev); + continue; + } + + if (endswith(dev, " (deleted)")) { + free(dev); + continue; + } + + d = cunescape(dev); + free(dev); + + if (!d) { + r = -ENOMEM; + goto finish; + } + + if (!(swap = new0(MountPoint, 1))) { + free(d); + r = -ENOMEM; + goto finish; + } + + swap->path = d; + LIST_PREPEND(mount_point, *head, swap); + } + + r = 0; + +finish: + fclose(proc_swaps); + + return r; +} + +static int loopback_list_get(MountPoint **head) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + int r; + + assert(head); + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + e = udev_enumerate_new(udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_subsystem(e, "block"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_sysname(e, "loop*"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + MountPoint *lb; + _cleanup_udev_device_unref_ struct udev_device *d; + char *loop; + const char *dn; + + d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + dn = udev_device_get_devnode(d); + if (!dn) + continue; + + loop = strdup(dn); + if (!loop) + return -ENOMEM; + + lb = new0(MountPoint, 1); + if (!lb) { + free(loop); + return -ENOMEM; + } + + lb->path = loop; + LIST_PREPEND(mount_point, *head, lb); + } + + return 0; +} + +static int dm_list_get(MountPoint **head) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + int r; + + assert(head); + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + e = udev_enumerate_new(udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_subsystem(e, "block"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_sysname(e, "dm-*"); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + MountPoint *m; + _cleanup_udev_device_unref_ struct udev_device *d; + dev_t devnum; + char *node; + const char *dn; + + d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + devnum = udev_device_get_devnum(d); + dn = udev_device_get_devnode(d); + if (major(devnum) == 0 || !dn) + continue; + + node = strdup(dn); + if (!node) + return -ENOMEM; + + m = new(MountPoint, 1); + if (!m) { + free(node); + return -ENOMEM; + } + + m->path = node; + m->devnum = devnum; + LIST_PREPEND(mount_point, *head, m); + } + + return 0; +} + +static int delete_loopback(const char *device) { + int fd, r; + + if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0) + return errno == ENOENT ? 0 : -errno; + + r = ioctl(fd, LOOP_CLR_FD, 0); + close_nointr_nofail(fd); + + if (r >= 0) + return 1; + + /* ENXIO: not bound, so no error */ + if (errno == ENXIO) + return 0; + + return -errno; +} + +static int delete_dm(dev_t devnum) { + _cleanup_close_ int fd = -1; + int r; + struct dm_ioctl dm = { + .version = {DM_VERSION_MAJOR, + DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL}, + .data_size = sizeof(dm), + .dev = devnum, + }; + + assert(major(devnum) != 0); + + fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC); + if (fd < 0) + return -errno; + + r = ioctl(fd, DM_DEV_REMOVE, &dm); + return r >= 0 ? 0 : -errno; +} + +static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) { + MountPoint *m, *n; + int n_failed = 0; + + assert(head); + + LIST_FOREACH_SAFE(mount_point, m, n, *head) { + + /* If we are in a container, don't attempt to + read-only mount anything as that brings no real + benefits, but might confuse the host, as we remount + the superblock here, not the bind mound. */ + if (detect_container(NULL) <= 0) { + /* We always try to remount directories + * read-only first, before we go on and umount + * them. + * + * Mount points can be stacked. If a mount + * point is stacked below / or /usr, we + * cannot umount or remount it directly, + * since there is no way to refer to the + * underlying mount. There's nothing we can do + * about it for the general case, but we can + * do something about it if it is aliased + * somehwere else via a bind mount. If we + * explicitly remount the super block of that + * alias read-only we hence should be + * relatively safe regarding keeping the fs we + * can otherwise not see dirty. */ + mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL); + } + + /* Skip / and /usr since we cannot unmount that + * anyway, since we are running from it. They have + * already been remounted ro. */ + if (path_equal(m->path, "/") +#ifndef HAVE_SPLIT_USR + || path_equal(m->path, "/usr") +#endif + ) + continue; + + /* Trying to umount. We don't force here since we rely + * on busy NFS and FUSE file systems to return EBUSY + * until we closed everything on top of them. */ + log_info("Unmounting %s.", m->path); + if (umount2(m->path, 0) == 0) { + if (changed) + *changed = true; + + mount_point_free(head, m); + } else if (log_error) { + log_warning("Could not unmount %s: %m", m->path); + n_failed++; + } + } + + return n_failed; +} + +static int swap_points_list_off(MountPoint **head, bool *changed) { + MountPoint *m, *n; + int n_failed = 0; + + assert(head); + + LIST_FOREACH_SAFE(mount_point, m, n, *head) { + log_info("Deactivating swap %s.", m->path); + if (swapoff(m->path) == 0) { + if (changed) + *changed = true; + + mount_point_free(head, m); + } else { + log_warning("Could not deactivate swap %s: %m", m->path); + n_failed++; + } + } + + return n_failed; +} + +static int loopback_points_list_detach(MountPoint **head, bool *changed) { + MountPoint *m, *n; + int n_failed = 0, k; + struct stat root_st; + + assert(head); + + k = lstat("/", &root_st); + + LIST_FOREACH_SAFE(mount_point, m, n, *head) { + int r; + struct stat loopback_st; + + if (k >= 0 && + major(root_st.st_dev) != 0 && + lstat(m->path, &loopback_st) >= 0 && + root_st.st_dev == loopback_st.st_rdev) { + n_failed ++; + continue; + } + + log_info("Detaching loopback %s.", m->path); + r = delete_loopback(m->path); + if (r >= 0) { + if (r > 0 && changed) + *changed = true; + + mount_point_free(head, m); + } else { + log_warning("Could not detach loopback %s: %m", m->path); + n_failed++; + } + } + + return n_failed; +} + +static int dm_points_list_detach(MountPoint **head, bool *changed) { + MountPoint *m, *n; + int n_failed = 0, k; + struct stat root_st; + + assert(head); + + k = lstat("/", &root_st); + + LIST_FOREACH_SAFE(mount_point, m, n, *head) { + int r; + + if (k >= 0 && + major(root_st.st_dev) != 0 && + root_st.st_dev == m->devnum) { + n_failed ++; + continue; + } + + log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum)); + r = delete_dm(m->devnum); + if (r >= 0) { + if (changed) + *changed = true; + + mount_point_free(head, m); + } else { + log_warning("Could not detach DM %s: %m", m->path); + n_failed++; + } + } + + return n_failed; +} + +int umount_all(bool *changed) { + int r; + bool umount_changed; + LIST_HEAD(MountPoint, mp_list_head); + + LIST_HEAD_INIT(mp_list_head); + r = mount_points_list_get(&mp_list_head); + if (r < 0) + goto end; + + /* retry umount, until nothing can be umounted anymore */ + do { + umount_changed = false; + + mount_points_list_umount(&mp_list_head, &umount_changed, false); + if (umount_changed) + *changed = true; + + } while (umount_changed); + + /* umount one more time with logging enabled */ + r = mount_points_list_umount(&mp_list_head, &umount_changed, true); + if (r <= 0) + goto end; + + end: + mount_points_list_free(&mp_list_head); + + return r; +} + +int swapoff_all(bool *changed) { + int r; + LIST_HEAD(MountPoint, swap_list_head); + + LIST_HEAD_INIT(swap_list_head); + + r = swap_list_get(&swap_list_head); + if (r < 0) + goto end; + + r = swap_points_list_off(&swap_list_head, changed); + + end: + mount_points_list_free(&swap_list_head); + + return r; +} + +int loopback_detach_all(bool *changed) { + int r; + LIST_HEAD(MountPoint, loopback_list_head); + + LIST_HEAD_INIT(loopback_list_head); + + r = loopback_list_get(&loopback_list_head); + if (r < 0) + goto end; + + r = loopback_points_list_detach(&loopback_list_head, changed); + + end: + mount_points_list_free(&loopback_list_head); + + return r; +} + +int dm_detach_all(bool *changed) { + int r; + LIST_HEAD(MountPoint, dm_list_head); + + LIST_HEAD_INIT(dm_list_head); + + r = dm_list_get(&dm_list_head); + if (r < 0) + goto end; + + r = dm_points_list_detach(&dm_list_head, changed); + + end: + mount_points_list_free(&dm_list_head); + + return r; +} diff --git a/src/core/umount.h b/src/core/umount.h new file mode 100644 index 0000000..8439ffe --- /dev/null +++ b/src/core/umount.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 ProFUSION embedded systems + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int umount_all(bool *changed); + +int swapoff_all(bool *changed); + +int loopback_detach_all(bool *changed); + +int dm_detach_all(bool *changed); diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c new file mode 100644 index 0000000..4e18afa --- /dev/null +++ b/src/core/unit-printf.c @@ -0,0 +1,449 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "systemd/sd-id128.h" +#include "unit.h" +#include "specifier.h" +#include "path-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "macro.h" +#include "cgroup-util.h" +#include "special.h" + +static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + char *n; + + assert(u); + + n = unit_name_to_prefix_and_instance(u->id); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + char *n; + + assert(u); + + n = unit_name_to_prefix(u->id); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + _cleanup_free_ char *p = NULL; + char *n; + + assert(u); + + p = unit_name_to_prefix(u->id); + if (!p) + return -ENOMEM; + + n = unit_name_unescape(p); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + char *n; + + assert(u); + + if (!u->instance) + return -ENOTSUP; + + n = unit_name_unescape(u->instance); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + char *n; + + assert(u); + + if (u->instance) + n = unit_name_path_unescape(u->instance); + else + n = unit_name_to_path(u->id); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + char *n; + + assert(u); + + if (u->cgroup_path) + n = strdup(u->cgroup_path); + else + n = unit_default_cgroup_path(u); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + const char *slice; + char *n; + int r; + + assert(u); + + slice = unit_slice_name(u); + if (specifier == 'R' || !slice) + n = strdup(u->manager->cgroup_root); + else { + _cleanup_free_ char *p = NULL; + + r = cg_slice_to_path(slice, &p); + if (r < 0) + return r; + + n = strjoin(u->manager->cgroup_root, "/", p, NULL); + if (!n) + return -ENOMEM; + } + + *ret = n; + return 0; +} + +static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + const char *e; + char *n = NULL; + + assert(u); + + if (u->manager->running_as == SYSTEMD_SYSTEM) + e = "/run"; + else { + e = getenv("XDG_RUNTIME_DIR"); + if (!e) + return -ENOTSUP; + } + + n = strdup(e); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { + char *printed = NULL; + Unit *u = userdata; + ExecContext *c; + int r; + + assert(u); + + c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; + + if (u->manager->running_as == SYSTEMD_SYSTEM) { + + /* We cannot use NSS from PID 1, hence try to make the + * best of it in that case, and fail if we can't help + * it */ + + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + printed = strdup(specifier == 'u' ? "root" : "0"); + else { + if (specifier == 'u') + printed = strdup(c->user); + else { + uid_t uid; + + r = parse_uid(c->user, &uid); + if (r < 0) + return -ENODATA; + + asprintf(&printed, "%lu", (unsigned long) uid); + } + } + + } else { + _cleanup_free_ char *tmp = NULL; + const char *username = NULL; + uid_t uid; + + if (c->user) + username = c->user; + else + /* get USER env from env or our own uid */ + username = tmp = getusername_malloc(); + + /* fish username from passwd */ + r = get_user_creds(&username, &uid, NULL, NULL, NULL); + if (r < 0) + return r; + + if (specifier == 'u') + printed = strdup(username); + else + asprintf(&printed, "%lu", (unsigned long) uid); + } + + if (!printed) + return -ENOMEM; + + *ret = printed; + return 0; +} + +static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + ExecContext *c; + char *n; + int r; + + assert(u); + + c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; + + if (u->manager->running_as == SYSTEMD_SYSTEM) { + + /* We cannot use NSS from PID 1, hence try to make the + * best of it if we can, but fail if we can't */ + + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + n = strdup("/root"); + else + return -ENOTSUP; + + } else { + + /* return HOME if set, otherwise from passwd */ + if (!c || !c->user) { + r = get_home_dir(&n); + if (r < 0) + return r; + } else { + const char *username, *home; + + username = c->user; + r = get_user_creds(&username, NULL, NULL, &home, NULL); + if (r < 0) + return r; + + n = strdup(home); + } + } + + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { + Unit *u = userdata; + ExecContext *c; + char *n; + int r; + + assert(u); + + c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; + + if (u->manager->running_as == SYSTEMD_SYSTEM) { + + /* We cannot use NSS from PID 1, hence try to make the + * best of it if we can, but fail if we can't */ + + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + n = strdup("/bin/sh"); + else + return -ENOTSUP; + + } else { + + /* return /bin/sh for root, otherwise the value from passwd */ + if (!c->user) { + r = get_shell(&n); + if (r < 0) + return r; + } else { + const char *username, *shell; + + username = c->user; + r = get_user_creds(&username, NULL, NULL, NULL, &shell); + if (r < 0) + return r; + + n = strdup(shell); + } + } + + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int unit_name_printf(Unit *u, const char* format, char **ret) { + + /* + * This will use the passed string as format string and + * replace the following specifiers: + * + * %n: the full id of the unit (foo@bar.waldo) + * %N: the id of the unit without the suffix (foo@bar) + * %p: the prefix (foo) + * %i: the instance (bar) + */ + + const Specifier table[] = { + { 'n', specifier_string, u->id }, + { 'N', specifier_prefix_and_instance, NULL }, + { 'p', specifier_prefix, NULL }, + { 'i', specifier_string, u->instance }, + { 0, NULL, NULL } + }; + + assert(u); + assert(format); + assert(ret); + + return specifier_printf(format, table, u, ret); +} + +int unit_full_printf(Unit *u, const char *format, char **ret) { + + /* This is similar to unit_name_printf() but also supports + * unescaping. Also, adds a couple of additional codes: + * + * %f the the instance if set, otherwise the id + * %c cgroup path of unit + * %r where units in this slice are placed in the cgroup tree + * %R the root of this systemd's instance tree + * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) + * %U the UID of the configured user or running user + * %u the username of the configured user or running user + * %h the homedir of the configured user or running user + * %s the shell of the configured user or running user + * %m the machine ID of the running system + * %H the host name of the running system + * %b the boot ID of the running system + * %v `uname -r` of the running system + */ + + const Specifier table[] = { + { 'n', specifier_string, u->id }, + { 'N', specifier_prefix_and_instance, NULL }, + { 'p', specifier_prefix, NULL }, + { 'P', specifier_prefix_unescaped, NULL }, + { 'i', specifier_string, u->instance }, + { 'I', specifier_instance_unescaped, NULL }, + + { 'f', specifier_filename, NULL }, + { 'c', specifier_cgroup, NULL }, + { 'r', specifier_cgroup_root, NULL }, + { 'R', specifier_cgroup_root, NULL }, + { 't', specifier_runtime, NULL }, + { 'U', specifier_user_name, NULL }, + { 'u', specifier_user_name, NULL }, + { 'h', specifier_user_home, NULL }, + { 's', specifier_user_shell, NULL }, + + { 'm', specifier_machine_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'b', specifier_boot_id, NULL }, + { 'v', specifier_kernel_release, NULL }, + {} + }; + + assert(u); + assert(format); + assert(ret); + + return specifier_printf(format, table, u, ret); +} + +int unit_full_printf_strv(Unit *u, char **l, char ***ret) { + size_t n; + char **r, **i, **j; + int q; + + /* Applies unit_full_printf to every entry in l */ + + assert(u); + + n = strv_length(l); + r = new(char*, n+1); + if (!r) + return -ENOMEM; + + for (i = l, j = r; *i; i++, j++) { + q = unit_full_printf(u, *i, j); + if (q < 0) + goto fail; + } + + *j = NULL; + *ret = r; + return 0; + +fail: + for (j--; j >= r; j--) + free(*j); + + free(r); + return q; +} diff --git a/src/core/unit-printf.h b/src/core/unit-printf.h new file mode 100644 index 0000000..51acad6 --- /dev/null +++ b/src/core/unit-printf.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "unit.h" + +int unit_name_printf(Unit *u, const char* text, char **ret); +int unit_full_printf(Unit *u, const char *text, char **ret); +int unit_full_printf_strv(Unit *u, char **l, char ***ret); diff --git a/src/core/unit.c b/src/core/unit.c new file mode 100644 index 0000000..1bbcb39 --- /dev/null +++ b/src/core/unit.c @@ -0,0 +1,3268 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "set.h" +#include "unit.h" +#include "macro.h" +#include "strv.h" +#include "path-util.h" +#include "load-fragment.h" +#include "load-dropin.h" +#include "log.h" +#include "unit-name.h" +#include "dbus-unit.h" +#include "special.h" +#include "cgroup-util.h" +#include "missing.h" +#include "mkdir.h" +#include "label.h" +#include "fileio-label.h" +#include "bus-errors.h" +#include "dbus.h" +#include "execute.h" +#include "virt.h" + +const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = &service_vtable, + [UNIT_SOCKET] = &socket_vtable, + [UNIT_BUSNAME] = &busname_vtable, + [UNIT_TARGET] = &target_vtable, + [UNIT_SNAPSHOT] = &snapshot_vtable, + [UNIT_DEVICE] = &device_vtable, + [UNIT_MOUNT] = &mount_vtable, + [UNIT_AUTOMOUNT] = &automount_vtable, + [UNIT_SWAP] = &swap_vtable, + [UNIT_TIMER] = &timer_vtable, + [UNIT_PATH] = &path_vtable, + [UNIT_SLICE] = &slice_vtable, + [UNIT_SCOPE] = &scope_vtable +}; + +Unit *unit_new(Manager *m, size_t size) { + Unit *u; + + assert(m); + assert(size >= sizeof(Unit)); + + u = malloc0(size); + if (!u) + return NULL; + + u->names = set_new(string_hash_func, string_compare_func); + if (!u->names) { + free(u); + return NULL; + } + + u->manager = m; + u->type = _UNIT_TYPE_INVALID; + u->deserialized_job = _JOB_TYPE_INVALID; + u->default_dependencies = true; + u->unit_file_state = _UNIT_FILE_STATE_INVALID; + u->on_failure_job_mode = JOB_REPLACE; + + return u; +} + +bool unit_has_name(Unit *u, const char *name) { + assert(u); + assert(name); + + return !!set_get(u->names, (char*) name); +} + +int unit_add_name(Unit *u, const char *text) { + UnitType t; + char *s, *i = NULL; + int r; + + assert(u); + assert(text); + + if (unit_name_is_template(text)) { + if (!u->instance) + return -EINVAL; + + s = unit_name_replace_instance(text, u->instance); + } else + s = strdup(text); + + if (!s) + return -ENOMEM; + + if (!unit_name_is_valid(s, TEMPLATE_INVALID)) { + r = -EINVAL; + goto fail; + } + + assert_se((t = unit_name_to_type(s)) >= 0); + + if (u->type != _UNIT_TYPE_INVALID && t != u->type) { + r = -EINVAL; + goto fail; + } + + r = unit_name_to_instance(s, &i); + if (r < 0) + goto fail; + + if (i && unit_vtable[t]->no_instances) { + r = -EINVAL; + goto fail; + } + + /* Ensure that this unit is either instanced or not instanced, + * but not both. */ + if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) { + r = -EINVAL; + goto fail; + } + + if (unit_vtable[t]->no_alias && + !set_isempty(u->names) && + !set_get(u->names, s)) { + r = -EEXIST; + goto fail; + } + + if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) { + r = -E2BIG; + goto fail; + } + + r = set_put(u->names, s); + if (r < 0) { + if (r == -EEXIST) + r = 0; + goto fail; + } + + r = hashmap_put(u->manager->units, s, u); + if (r < 0) { + set_remove(u->names, s); + goto fail; + } + + if (u->type == _UNIT_TYPE_INVALID) { + + u->type = t; + u->id = s; + u->instance = i; + + LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u); + + if (UNIT_VTABLE(u)->init) + UNIT_VTABLE(u)->init(u); + } else + free(i); + + unit_add_to_dbus_queue(u); + return 0; + +fail: + free(s); + free(i); + + return r; +} + +int unit_choose_id(Unit *u, const char *name) { + char *s, *i; + _cleanup_free_ char *t = NULL; + int r; + + assert(u); + assert(name); + + if (unit_name_is_template(name)) { + + if (!u->instance) + return -EINVAL; + + t = unit_name_replace_instance(name, u->instance); + if (!t) + return -ENOMEM; + + name = t; + } + + /* Selects one of the names of this unit as the id */ + s = set_get(u->names, (char*) name); + + if (!s) + return -ENOENT; + + r = unit_name_to_instance(s, &i); + if (r < 0) + return r; + + u->id = s; + + free(u->instance); + u->instance = i; + + unit_add_to_dbus_queue(u); + + return 0; +} + +int unit_set_description(Unit *u, const char *description) { + char *s; + + assert(u); + + if (isempty(description)) + s = NULL; + else { + s = strdup(description); + if (!s) + return -ENOMEM; + } + + free(u->description); + u->description = s; + + unit_add_to_dbus_queue(u); + return 0; +} + +bool unit_check_gc(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->no_gc) + return true; + + if (u->no_gc) + return true; + + if (u->job) + return true; + + if (u->nop_job) + return true; + + if (unit_active_state(u) != UNIT_INACTIVE) + return true; + + if (u->refs) + return true; + + if (UNIT_VTABLE(u)->check_gc) + if (UNIT_VTABLE(u)->check_gc(u)) + return true; + + return false; +} + +void unit_add_to_load_queue(Unit *u) { + assert(u); + assert(u->type != _UNIT_TYPE_INVALID); + + if (u->load_state != UNIT_STUB || u->in_load_queue) + return; + + LIST_PREPEND(load_queue, u->manager->load_queue, u); + u->in_load_queue = true; +} + +void unit_add_to_cleanup_queue(Unit *u) { + assert(u); + + if (u->in_cleanup_queue) + return; + + LIST_PREPEND(cleanup_queue, u->manager->cleanup_queue, u); + u->in_cleanup_queue = true; +} + +void unit_add_to_gc_queue(Unit *u) { + assert(u); + + if (u->in_gc_queue || u->in_cleanup_queue) + return; + + if (unit_check_gc(u)) + return; + + LIST_PREPEND(gc_queue, u->manager->gc_queue, u); + u->in_gc_queue = true; + + u->manager->n_in_gc_queue ++; +} + +void unit_add_to_dbus_queue(Unit *u) { + assert(u); + assert(u->type != _UNIT_TYPE_INVALID); + + if (u->load_state == UNIT_STUB || u->in_dbus_queue) + return; + + /* Shortcut things if nobody cares */ + if (set_isempty(u->manager->subscribed)) { + u->sent_dbus_new_signal = true; + return; + } + + LIST_PREPEND(dbus_queue, u->manager->dbus_unit_queue, u); + u->in_dbus_queue = true; +} + +static void bidi_set_free(Unit *u, Set *s) { + Iterator i; + Unit *other; + + assert(u); + + /* Frees the set and makes sure we are dropped from the + * inverse pointers */ + + SET_FOREACH(other, s, i) { + UnitDependency d; + + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) + set_remove(other->dependencies[d], u); + + unit_add_to_gc_queue(other); + } + + set_free(s); +} + +static void unit_remove_transient(Unit *u) { + char **i; + + assert(u); + + if (!u->transient) + return; + + if (u->fragment_path) + unlink(u->fragment_path); + + STRV_FOREACH(i, u->dropin_paths) { + _cleanup_free_ char *p = NULL; + int r; + + unlink(*i); + + r = path_get_parent(*i, &p); + if (r >= 0) + rmdir(p); + } +} + +static void unit_free_requires_mounts_for(Unit *u) { + char **j; + + STRV_FOREACH(j, u->requires_mounts_for) { + char s[strlen(*j) + 1]; + + PATH_FOREACH_PREFIX_MORE(s, *j) { + char *y; + Set *x; + + x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); + if (!x) + continue; + + set_remove(x, u); + + if (set_isempty(x)) { + hashmap_remove(u->manager->units_requiring_mounts_for, y); + free(y); + set_free(x); + } + } + } + + strv_free(u->requires_mounts_for); + u->requires_mounts_for = NULL; +} + +void unit_free(Unit *u) { + UnitDependency d; + Iterator i; + char *t; + + assert(u); + + if (u->manager->n_reloading <= 0) + unit_remove_transient(u); + + bus_unit_send_removed_signal(u); + + if (u->load_state != UNIT_STUB) + if (UNIT_VTABLE(u)->done) + UNIT_VTABLE(u)->done(u); + + unit_free_requires_mounts_for(u); + + SET_FOREACH(t, u->names, i) + hashmap_remove_value(u->manager->units, t, u); + + if (u->job) { + Job *j = u->job; + job_uninstall(j); + job_free(j); + } + + if (u->nop_job) { + Job *j = u->nop_job; + job_uninstall(j); + job_free(j); + } + + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) + bidi_set_free(u, u->dependencies[d]); + + if (u->type != _UNIT_TYPE_INVALID) + LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u); + + if (u->in_load_queue) + LIST_REMOVE(load_queue, u->manager->load_queue, u); + + if (u->in_dbus_queue) + LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); + + if (u->in_cleanup_queue) + LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u); + + if (u->in_gc_queue) { + LIST_REMOVE(gc_queue, u->manager->gc_queue, u); + u->manager->n_in_gc_queue--; + } + + if (u->in_cgroup_queue) + LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u); + + if (u->cgroup_path) { + hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); + free(u->cgroup_path); + } + + free(u->description); + strv_free(u->documentation); + free(u->fragment_path); + free(u->source_path); + strv_free(u->dropin_paths); + free(u->instance); + + set_free_free(u->names); + + unit_unwatch_all_pids(u); + + condition_free_list(u->conditions); + + unit_ref_unset(&u->slice); + + while (u->refs) + unit_ref_unset(u->refs); + + free(u); +} + +UnitActiveState unit_active_state(Unit *u) { + assert(u); + + if (u->load_state == UNIT_MERGED) + return unit_active_state(unit_follow_merge(u)); + + /* After a reload it might happen that a unit is not correctly + * loaded but still has a process around. That's why we won't + * shortcut failed loading to UNIT_INACTIVE_FAILED. */ + + return UNIT_VTABLE(u)->active_state(u); +} + +const char* unit_sub_state_to_string(Unit *u) { + assert(u); + + return UNIT_VTABLE(u)->sub_state_to_string(u); +} + +static void complete_move(Set **s, Set **other) { + assert(s); + assert(other); + + if (!*other) + return; + + if (*s) + set_move(*s, *other); + else { + *s = *other; + *other = NULL; + } +} + +static void merge_names(Unit *u, Unit *other) { + char *t; + Iterator i; + + assert(u); + assert(other); + + complete_move(&u->names, &other->names); + + set_free_free(other->names); + other->names = NULL; + other->id = NULL; + + SET_FOREACH(t, u->names, i) + assert_se(hashmap_replace(u->manager->units, t, u) == 0); +} + +static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) { + Iterator i; + Unit *back; + int r; + + assert(u); + assert(other); + assert(d < _UNIT_DEPENDENCY_MAX); + + /* Fix backwards pointers */ + SET_FOREACH(back, other->dependencies[d], i) { + UnitDependency k; + + for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) { + r = set_remove_and_put(back->dependencies[k], other, u); + if (r == -EEXIST) + set_remove(back->dependencies[k], other); + else + assert(r >= 0 || r == -ENOENT); + } + } + + complete_move(&u->dependencies[d], &other->dependencies[d]); + + set_free(other->dependencies[d]); + other->dependencies[d] = NULL; +} + +int unit_merge(Unit *u, Unit *other) { + UnitDependency d; + + assert(u); + assert(other); + assert(u->manager == other->manager); + assert(u->type != _UNIT_TYPE_INVALID); + + other = unit_follow_merge(other); + + if (other == u) + return 0; + + if (u->type != other->type) + return -EINVAL; + + if (!u->instance != !other->instance) + return -EINVAL; + + if (other->load_state != UNIT_STUB && + other->load_state != UNIT_NOT_FOUND) + return -EEXIST; + + if (other->job) + return -EEXIST; + + if (other->nop_job) + return -EEXIST; + + if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) + return -EEXIST; + + /* Merge names */ + merge_names(u, other); + + /* Redirect all references */ + while (other->refs) + unit_ref_set(other->refs, u); + + /* Merge dependencies */ + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) + merge_dependencies(u, other, d); + + other->load_state = UNIT_MERGED; + other->merged_into = u; + + /* If there is still some data attached to the other node, we + * don't need it anymore, and can free it. */ + if (other->load_state != UNIT_STUB) + if (UNIT_VTABLE(other)->done) + UNIT_VTABLE(other)->done(other); + + unit_add_to_dbus_queue(u); + unit_add_to_cleanup_queue(other); + + return 0; +} + +int unit_merge_by_name(Unit *u, const char *name) { + Unit *other; + int r; + _cleanup_free_ char *s = NULL; + + assert(u); + assert(name); + + if (unit_name_is_template(name)) { + if (!u->instance) + return -EINVAL; + + s = unit_name_replace_instance(name, u->instance); + if (!s) + return -ENOMEM; + + name = s; + } + + other = manager_get_unit(u->manager, name); + if (!other) + r = unit_add_name(u, name); + else + r = unit_merge(u, other); + + return r; +} + +Unit* unit_follow_merge(Unit *u) { + assert(u); + + while (u->load_state == UNIT_MERGED) + assert_se(u = u->merged_into); + + return u; +} + +int unit_add_exec_dependencies(Unit *u, ExecContext *c) { + int r; + + assert(u); + assert(c); + + if (c->working_directory) { + r = unit_require_mounts_for(u, c->working_directory); + if (r < 0) + return r; + } + + if (c->root_directory) { + r = unit_require_mounts_for(u, c->root_directory); + if (r < 0) + return r; + } + + if (c->std_output != EXEC_OUTPUT_KMSG && + c->std_output != EXEC_OUTPUT_SYSLOG && + c->std_output != EXEC_OUTPUT_JOURNAL && + c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE && + c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE && + c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE && + c->std_error != EXEC_OUTPUT_KMSG && + c->std_error != EXEC_OUTPUT_SYSLOG && + c->std_error != EXEC_OUTPUT_JOURNAL && + c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE && + c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE && + c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE) + return 0; + + /* If syslog or kernel logging is requested, make sure our own + * logging daemon is run first. */ + + if (u->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true); + if (r < 0) + return r; + } + + return 0; +} + +const char *unit_description(Unit *u) { + assert(u); + + if (u->description) + return u->description; + + return strna(u->id); +} + +void unit_dump(Unit *u, FILE *f, const char *prefix) { + char *t, **j; + UnitDependency d; + Iterator i; + _cleanup_free_ char *p2 = NULL; + const char *prefix2; + char + timestamp1[FORMAT_TIMESTAMP_MAX], + timestamp2[FORMAT_TIMESTAMP_MAX], + timestamp3[FORMAT_TIMESTAMP_MAX], + timestamp4[FORMAT_TIMESTAMP_MAX], + timespan[FORMAT_TIMESPAN_MAX]; + Unit *following; + _cleanup_set_free_ Set *following_set = NULL; + int r; + + assert(u); + assert(u->type >= 0); + + if (!prefix) + prefix = ""; + p2 = strappend(prefix, "\t"); + prefix2 = p2 ? p2 : prefix; + + fprintf(f, + "%s-> Unit %s:\n" + "%s\tDescription: %s\n" + "%s\tInstance: %s\n" + "%s\tUnit Load State: %s\n" + "%s\tUnit Active State: %s\n" + "%s\tInactive Exit Timestamp: %s\n" + "%s\tActive Enter Timestamp: %s\n" + "%s\tActive Exit Timestamp: %s\n" + "%s\tInactive Enter Timestamp: %s\n" + "%s\tGC Check Good: %s\n" + "%s\tNeed Daemon Reload: %s\n" + "%s\tTransient: %s\n" + "%s\tSlice: %s\n" + "%s\tCGroup: %s\n" + "%s\tCGroup realized: %s\n" + "%s\tCGroup mask: 0x%x\n" + "%s\tCGroup members mask: 0x%x\n", + prefix, u->id, + prefix, unit_description(u), + prefix, strna(u->instance), + prefix, unit_load_state_to_string(u->load_state), + prefix, unit_active_state_to_string(unit_active_state(u)), + prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)), + prefix, yes_no(unit_check_gc(u)), + prefix, yes_no(unit_need_daemon_reload(u)), + prefix, yes_no(u->transient), + prefix, strna(unit_slice_name(u)), + prefix, strna(u->cgroup_path), + prefix, yes_no(u->cgroup_realized), + prefix, u->cgroup_realized_mask, + prefix, u->cgroup_members_mask); + + SET_FOREACH(t, u->names, i) + fprintf(f, "%s\tName: %s\n", prefix, t); + + STRV_FOREACH(j, u->documentation) + fprintf(f, "%s\tDocumentation: %s\n", prefix, *j); + + following = unit_following(u); + if (following) + fprintf(f, "%s\tFollowing: %s\n", prefix, following->id); + + r = unit_following_set(u, &following_set); + if (r >= 0) { + Unit *other; + + SET_FOREACH(other, following_set, i) + fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id); + } + + if (u->fragment_path) + fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path); + + if (u->source_path) + fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path); + + STRV_FOREACH(j, u->dropin_paths) + fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j); + + if (u->job_timeout > 0) + fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); + + condition_dump_list(u->conditions, f, prefix); + + if (dual_timestamp_is_set(&u->condition_timestamp)) + fprintf(f, + "%s\tCondition Timestamp: %s\n" + "%s\tCondition Result: %s\n", + prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)), + prefix, yes_no(u->condition_result)); + + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { + Unit *other; + + SET_FOREACH(other, u->dependencies[d], i) + fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id); + } + + if (!strv_isempty(u->requires_mounts_for)) { + fprintf(f, + "%s\tRequiresMountsFor:", prefix); + + STRV_FOREACH(j, u->requires_mounts_for) + fprintf(f, " %s", *j); + + fputs("\n", f); + } + + if (u->load_state == UNIT_LOADED) { + + fprintf(f, + "%s\tStopWhenUnneeded: %s\n" + "%s\tRefuseManualStart: %s\n" + "%s\tRefuseManualStop: %s\n" + "%s\tDefaultDependencies: %s\n" + "%s\tOnFailureJobMode: %s\n" + "%s\tIgnoreOnIsolate: %s\n" + "%s\tIgnoreOnSnapshot: %s\n", + prefix, yes_no(u->stop_when_unneeded), + prefix, yes_no(u->refuse_manual_start), + prefix, yes_no(u->refuse_manual_stop), + prefix, yes_no(u->default_dependencies), + prefix, job_mode_to_string(u->on_failure_job_mode), + prefix, yes_no(u->ignore_on_isolate), + prefix, yes_no(u->ignore_on_snapshot)); + + if (UNIT_VTABLE(u)->dump) + UNIT_VTABLE(u)->dump(u, f, prefix2); + + } else if (u->load_state == UNIT_MERGED) + fprintf(f, + "%s\tMerged into: %s\n", + prefix, u->merged_into->id); + else if (u->load_state == UNIT_ERROR) + fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error)); + + + if (u->job) + job_dump(u->job, f, prefix2); + + if (u->nop_job) + job_dump(u->nop_job, f, prefix2); + +} + +/* Common implementation for multiple backends */ +int unit_load_fragment_and_dropin(Unit *u) { + int r; + + assert(u); + + /* Load a .{service,socket,...} file */ + r = unit_load_fragment(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_STUB) + return -ENOENT; + + /* Load drop-in directory data */ + r = unit_load_dropin(unit_follow_merge(u)); + if (r < 0) + return r; + + return 0; +} + +/* Common implementation for multiple backends */ +int unit_load_fragment_and_dropin_optional(Unit *u) { + int r; + + assert(u); + + /* Same as unit_load_fragment_and_dropin(), but whether + * something can be loaded or not doesn't matter. */ + + /* Load a .service file */ + r = unit_load_fragment(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_STUB) + u->load_state = UNIT_LOADED; + + /* Load drop-in directory data */ + r = unit_load_dropin(unit_follow_merge(u)); + if (r < 0) + return r; + + return 0; +} + +int unit_add_default_target_dependency(Unit *u, Unit *target) { + assert(u); + assert(target); + + if (target->type != UNIT_TARGET) + return 0; + + /* Only add the dependency if both units are loaded, so that + * that loop check below is reliable */ + if (u->load_state != UNIT_LOADED || + target->load_state != UNIT_LOADED) + return 0; + + /* If either side wants no automatic dependencies, then let's + * skip this */ + if (!u->default_dependencies || + !target->default_dependencies) + return 0; + + /* Don't create loops */ + if (set_get(target->dependencies[UNIT_BEFORE], u)) + return 0; + + return unit_add_dependency(target, UNIT_AFTER, u, true); +} + +static int unit_add_target_dependencies(Unit *u) { + + static const UnitDependency deps[] = { + UNIT_REQUIRED_BY, + UNIT_REQUIRED_BY_OVERRIDABLE, + UNIT_WANTED_BY, + UNIT_BOUND_BY + }; + + Unit *target; + Iterator i; + unsigned k; + int r = 0; + + assert(u); + + for (k = 0; k < ELEMENTSOF(deps); k++) + SET_FOREACH(target, u->dependencies[deps[k]], i) { + r = unit_add_default_target_dependency(u, target); + if (r < 0) + return r; + } + + return r; +} + +static int unit_add_slice_dependencies(Unit *u) { + assert(u); + + if (!unit_get_cgroup_context(u)) + return 0; + + if (UNIT_ISSET(u->slice)) + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true); + + return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true); +} + +static int unit_add_mount_dependencies(Unit *u) { + char **i; + int r; + + assert(u); + + STRV_FOREACH(i, u->requires_mounts_for) { + char prefix[strlen(*i) + 1]; + + PATH_FOREACH_PREFIX_MORE(prefix, *i) { + Unit *m; + + r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m); + if (r < 0) + return r; + if (r == 0) + continue; + if (m == u) + continue; + + if (m->load_state != UNIT_LOADED) + continue; + + r = unit_add_dependency(u, UNIT_AFTER, m, true); + if (r < 0) + return r; + + if (m->fragment_path) { + r = unit_add_dependency(u, UNIT_REQUIRES, m, true); + if (r < 0) + return r; + } + } + } + + return 0; +} + +int unit_load(Unit *u) { + int r; + + assert(u); + + if (u->in_load_queue) { + LIST_REMOVE(load_queue, u->manager->load_queue, u); + u->in_load_queue = false; + } + + if (u->type == _UNIT_TYPE_INVALID) + return -EINVAL; + + if (u->load_state != UNIT_STUB) + return 0; + + if (UNIT_VTABLE(u)->load) { + r = UNIT_VTABLE(u)->load(u); + if (r < 0) + goto fail; + } + + if (u->load_state == UNIT_STUB) { + r = -ENOENT; + goto fail; + } + + if (u->load_state == UNIT_LOADED) { + + r = unit_add_target_dependencies(u); + if (r < 0) + goto fail; + + r = unit_add_slice_dependencies(u); + if (r < 0) + goto fail; + + r = unit_add_mount_dependencies(u); + if (r < 0) + goto fail; + + if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { + log_error_unit(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id); + r = -EINVAL; + goto fail; + } + + unit_update_cgroup_members_masks(u); + } + + assert((u->load_state != UNIT_MERGED) == !u->merged_into); + + unit_add_to_dbus_queue(unit_follow_merge(u)); + unit_add_to_gc_queue(u); + + return 0; + +fail: + u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND : UNIT_ERROR; + u->load_error = r; + unit_add_to_dbus_queue(u); + unit_add_to_gc_queue(u); + + log_debug_unit(u->id, "Failed to load configuration for %s: %s", + u->id, strerror(-r)); + + return r; +} + +static bool unit_condition_test(Unit *u) { + assert(u); + + dual_timestamp_get(&u->condition_timestamp); + u->condition_result = condition_test_list(u->id, u->conditions); + + return u->condition_result; +} + +_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) { + const UnitStatusMessageFormats *format_table; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + if (t != JOB_START && t != JOB_STOP) + return NULL; + + format_table = &UNIT_VTABLE(u)->status_message_formats; + if (!format_table) + return NULL; + + return format_table->starting_stopping[t == JOB_STOP]; +} + +_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) { + const char *format; + + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + format = unit_get_status_message_format(u, t); + if (format) + return format; + + /* Return generic strings */ + if (t == JOB_START) + return "Starting %s."; + else if (t == JOB_STOP) + return "Stopping %s."; + else if (t == JOB_RELOAD) + return "Reloading %s."; + + return NULL; +} + +static void unit_status_print_starting_stopping(Unit *u, JobType t) { + const char *format; + + assert(u); + + /* We only print status messages for selected units on + * selected operations. */ + + format = unit_get_status_message_format(u, t); + if (!format) + return; + + DISABLE_WARNING_FORMAT_NONLITERAL; + unit_status_printf(u, "", format); + REENABLE_WARNING; +} + +static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { + const char *format; + char buf[LINE_MAX]; + sd_id128_t mid; + + assert(u); + + if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD) + return; + + if (log_on_console()) + return; + + /* We log status messages for all units and all operations. */ + + format = unit_get_status_message_format_try_harder(u, t); + if (!format) + return; + + DISABLE_WARNING_FORMAT_NONLITERAL; + snprintf(buf, sizeof(buf), format, unit_description(u)); + char_array_0(buf); + REENABLE_WARNING; + + mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING : + t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING : + SD_MESSAGE_UNIT_RELOADING; + + log_struct_unit(LOG_INFO, + u->id, + MESSAGE_ID(mid), + "MESSAGE=%s", buf, + NULL); +} + +/* Errors: + * -EBADR: This unit type does not support starting. + * -EALREADY: Unit is already started. + * -EAGAIN: An operation is already in progress. Retry later. + * -ECANCELED: Too many requests for now. + */ +int unit_start(Unit *u) { + UnitActiveState state; + Unit *following; + + assert(u); + + if (u->load_state != UNIT_LOADED) + return -EINVAL; + + /* If this is already started, then this will succeed. Note + * that this will even succeed if this unit is not startable + * by the user. This is relied on to detect when we need to + * wait for units and when waiting is finished. */ + state = unit_active_state(u); + if (UNIT_IS_ACTIVE_OR_RELOADING(state)) + return -EALREADY; + + /* 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_debug_unit(u->id, "Starting of %s requested but condition failed. Ignoring.", u->id); + return -EALREADY; + } + + /* Forward to the main object, if we aren't it. */ + following = unit_following(u); + if (following) { + log_debug_unit(u->id, "Redirecting start request from %s to %s.", + u->id, following->id); + return unit_start(following); + } + + unit_status_log_starting_stopping_reloading(u, JOB_START); + unit_status_print_starting_stopping(u, JOB_START); + + /* If it is stopped, but we cannot start it, then fail */ + 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. */ + + unit_add_to_dbus_queue(u); + + return UNIT_VTABLE(u)->start(u); +} + +bool unit_can_start(Unit *u) { + assert(u); + + return !!UNIT_VTABLE(u)->start; +} + +bool unit_can_isolate(Unit *u) { + assert(u); + + return unit_can_start(u) && + u->allow_isolate; +} + +/* Errors: + * -EBADR: This unit type does not support stopping. + * -EALREADY: Unit is already stopped. + * -EAGAIN: An operation is already in progress. Retry later. + */ +int unit_stop(Unit *u) { + UnitActiveState state; + Unit *following; + + assert(u); + + state = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_FAILED(state)) + return -EALREADY; + + if ((following = unit_following(u))) { + log_debug_unit(u->id, "Redirecting stop request from %s to %s.", + u->id, following->id); + return unit_stop(following); + } + + unit_status_log_starting_stopping_reloading(u, JOB_STOP); + unit_status_print_starting_stopping(u, JOB_STOP); + + if (!UNIT_VTABLE(u)->stop) + return -EBADR; + + unit_add_to_dbus_queue(u); + + return UNIT_VTABLE(u)->stop(u); +} + +/* Errors: + * -EBADR: This unit type does not support reloading. + * -ENOEXEC: Unit is not started. + * -EAGAIN: An operation is already in progress. Retry later. + */ +int unit_reload(Unit *u) { + UnitActiveState state; + Unit *following; + + assert(u); + + if (u->load_state != UNIT_LOADED) + return -EINVAL; + + if (!unit_can_reload(u)) + return -EBADR; + + state = unit_active_state(u); + if (state == UNIT_RELOADING) + return -EALREADY; + + if (state != UNIT_ACTIVE) { + log_warning_unit(u->id, "Unit %s cannot be reloaded because it is inactive.", + u->id); + return -ENOEXEC; + } + + following = unit_following(u); + if (following) { + log_debug_unit(u->id, "Redirecting reload request from %s to %s.", + u->id, following->id); + return unit_reload(following); + } + + unit_status_log_starting_stopping_reloading(u, JOB_RELOAD); + + unit_add_to_dbus_queue(u); + return UNIT_VTABLE(u)->reload(u); +} + +bool unit_can_reload(Unit *u) { + assert(u); + + if (!UNIT_VTABLE(u)->reload) + return false; + + if (!UNIT_VTABLE(u)->can_reload) + return true; + + return UNIT_VTABLE(u)->can_reload(u); +} + +static void unit_check_unneeded(Unit *u) { + Iterator i; + Unit *other; + + assert(u); + + /* If this service shall be shut down when unneeded then do + * so. */ + + if (!u->stop_when_unneeded) + return; + + if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) + return; + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) + if (unit_active_or_pending(other)) + return; + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) + if (unit_active_or_pending(other)) + return; + + SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i) + if (unit_active_or_pending(other)) + return; + + SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + if (unit_active_or_pending(other)) + return; + + log_info_unit(u->id, "Service %s is not needed anymore. Stopping.", u->id); + + /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ + manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); +} + +static void retroactively_start_dependencies(Unit *u) { + Iterator i; + Unit *other; + + assert(u); + assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))); + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) + if (!set_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, true, NULL, NULL); + + SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) + if (!set_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, true, NULL, NULL); + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) + if (!set_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, false, NULL, NULL); + + SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) + if (!set_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, false, NULL, NULL); + + SET_FOREACH(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, true, NULL, NULL); + + SET_FOREACH(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, true, NULL, NULL); +} + +static void retroactively_stop_dependencies(Unit *u) { + Iterator i; + Unit *other; + + assert(u); + assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); + + /* Pull down units which are bound to us recursively if enabled */ + SET_FOREACH(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, true, NULL, NULL); +} + +static void check_unneeded_dependencies(Unit *u) { + Iterator i; + Unit *other; + + assert(u); + assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); + + /* Garbage collect services that might not be needed anymore, if enabled */ + SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); + SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); + SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); + SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); + SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); + SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) + if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) + unit_check_unneeded(other); +} + +void unit_start_on_failure(Unit *u) { + Unit *other; + Iterator i; + + assert(u); + + if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0) + return; + + log_info_unit(u->id, "Triggering OnFailure= dependencies of %s.", u->id); + + SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) { + int r; + + r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL); + if (r < 0) + log_error_unit(u->id, "Failed to enqueue OnFailure= job: %s", strerror(-r)); + } +} + +void unit_trigger_notify(Unit *u) { + Unit *other; + Iterator i; + + assert(u); + + SET_FOREACH(other, u->dependencies[UNIT_TRIGGERED_BY], i) + if (UNIT_VTABLE(other)->trigger_notify) + UNIT_VTABLE(other)->trigger_notify(other, u); +} + +void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) { + Manager *m; + bool unexpected; + + assert(u); + assert(os < _UNIT_ACTIVE_STATE_MAX); + assert(ns < _UNIT_ACTIVE_STATE_MAX); + + /* Note that this is called for all low-level state changes, + * even if they might map to the same high-level + * UnitActiveState! That means that ns == os is OK an expected + * behavior here. For example: if a mount point is remounted + * this function will be called too! */ + + m = u->manager; + + if (m->n_reloading <= 0) { + dual_timestamp ts; + + dual_timestamp_get(&ts); + + if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns)) + u->inactive_exit_timestamp = ts; + else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns)) + u->inactive_enter_timestamp = ts; + + if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) + u->active_enter_timestamp = ts; + else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) + u->active_exit_timestamp = ts; + } + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + unit_destroy_cgroup(u); + + /* Note that this doesn't apply to RemainAfterExit services exiting + * sucessfully, since there's no change of state in that case. Which is + * why it is handled in service_set_state() */ + if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) { + ExecContext *ec; + + ec = unit_get_exec_context(u); + if (ec && exec_context_may_touch_console(ec)) { + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { + m->n_on_console --; + + if (m->n_on_console == 0) + /* unset no_console_output flag, since the console is free */ + m->no_console_output = false; + } else + m->n_on_console ++; + } + } + + if (u->job) { + unexpected = false; + + if (u->job->state == JOB_WAITING) + + /* So we reached a different state for this + * job. Let's see if we can run it now if it + * failed previously due to EAGAIN. */ + job_add_to_run_queue(u->job); + + /* Let's check whether this state change constitutes a + * finished job, or maybe contradicts a running job and + * hence needs to invalidate jobs. */ + + switch (u->job->type) { + + case JOB_START: + case JOB_VERIFY_ACTIVE: + + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) + job_finish_and_invalidate(u->job, JOB_DONE, true); + else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); + } + + break; + + case JOB_RELOAD: + case JOB_RELOAD_OR_START: + + if (u->job->state == JOB_RUNNING) { + if (ns == UNIT_ACTIVE) + job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true); + else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); + } + } + + break; + + case JOB_STOP: + case JOB_RESTART: + case JOB_TRY_RESTART: + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + job_finish_and_invalidate(u->job, JOB_DONE, true); + else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { + unexpected = true; + job_finish_and_invalidate(u->job, JOB_FAILED, true); + } + + break; + + default: + assert_not_reached("Job type unknown"); + } + + } else + unexpected = true; + + if (m->n_reloading <= 0) { + + /* If this state change happened without being + * requested by a job, then let's retroactively start + * or stop dependencies. We skip that step when + * deserializing, since we don't want to create any + * additional jobs just because something is already + * activated. */ + + if (unexpected) { + if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) + retroactively_start_dependencies(u); + else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) + retroactively_stop_dependencies(u); + } + + /* stop unneeded units regardless if going down was expected or not */ + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) + check_unneeded_dependencies(u); + + if (ns != os && ns == UNIT_FAILED) { + log_notice_unit(u->id, "Unit %s entered failed state.", u->id); + unit_start_on_failure(u); + } + } + + /* Some names are special */ + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) { + + if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) + /* The bus just might have become available, + * hence try to connect to it, if we aren't + * yet connected. */ + bus_init(m, true); + + if (u->type == UNIT_SERVICE && + !UNIT_IS_ACTIVE_OR_RELOADING(os) && + m->n_reloading <= 0) { + /* Write audit record if we have just finished starting up */ + manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true); + u->in_audit = true; + } + + if (!UNIT_IS_ACTIVE_OR_RELOADING(os)) + manager_send_unit_plymouth(m, u); + + } else { + + /* We don't care about D-Bus here, since we'll get an + * asynchronous notification for it anyway. */ + + if (u->type == UNIT_SERVICE && + UNIT_IS_INACTIVE_OR_FAILED(ns) && + !UNIT_IS_INACTIVE_OR_FAILED(os) && + m->n_reloading <= 0) { + + /* Hmm, if there was no start record written + * write it now, so that we always have a nice + * pair */ + if (!u->in_audit) { + manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE); + + if (ns == UNIT_INACTIVE) + manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true); + } else + /* Write audit record if we have just finished shutting down */ + manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE); + + u->in_audit = false; + } + } + + manager_recheck_journal(m); + unit_trigger_notify(u); + + /* Maybe we finished startup and are now ready for being + * stopped because unneeded? */ + if (u->manager->n_reloading <= 0) + unit_check_unneeded(u); + + unit_add_to_dbus_queue(u); + unit_add_to_gc_queue(u); +} + +int unit_watch_pid(Unit *u, pid_t pid) { + int q, r; + + assert(u); + assert(pid >= 1); + + /* Watch a specific PID. We only support one or two units + * watching each PID for now, not more. */ + + r = hashmap_ensure_allocated(&u->manager->watch_pids1, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + r = set_ensure_allocated(&u->pids, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + r = hashmap_put(u->manager->watch_pids1, LONG_TO_PTR(pid), u); + if (r == -EEXIST) { + r = hashmap_ensure_allocated(&u->manager->watch_pids2, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + r = hashmap_put(u->manager->watch_pids2, LONG_TO_PTR(pid), u); + } + + q = set_put(u->pids, LONG_TO_PTR(pid)); + if (q < 0) + return q; + + return r; +} + +void unit_unwatch_pid(Unit *u, pid_t pid) { + assert(u); + assert(pid >= 1); + + hashmap_remove_value(u->manager->watch_pids1, LONG_TO_PTR(pid), u); + hashmap_remove_value(u->manager->watch_pids2, LONG_TO_PTR(pid), u); + set_remove(u->pids, LONG_TO_PTR(pid)); +} + +static int watch_pids_in_path(Unit *u, const char *path) { + _cleanup_closedir_ DIR *d = NULL; + _cleanup_fclose_ FILE *f = NULL; + int ret = 0, r; + + assert(u); + assert(path); + + /* Adds all PIDs from a specific cgroup path to the set of PIDs we watch. */ + + r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, path, &f); + if (r >= 0) { + pid_t pid; + + while ((r = cg_read_pid(f, &pid)) > 0) { + r = unit_watch_pid(u, pid); + if (r < 0 && ret >= 0) + ret = r; + } + if (r < 0 && ret >= 0) + ret = r; + + } else if (ret >= 0) + ret = r; + + r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d); + if (r >= 0) { + char *fn; + + while ((r = cg_read_subgroup(d, &fn)) > 0) { + _cleanup_free_ char *p = NULL; + + p = strjoin(path, "/", fn, NULL); + free(fn); + + if (!p) + return -ENOMEM; + + r = watch_pids_in_path(u, p); + if (r < 0 && ret >= 0) + ret = r; + } + if (r < 0 && ret >= 0) + ret = r; + + } else if (ret >= 0) + ret = r; + + return ret; +} + + +int unit_watch_all_pids(Unit *u) { + assert(u); + + if (!u->cgroup_path) + return -ENOENT; + + /* Adds all PIDs from our cgroup to the set of PIDs we watch */ + + return watch_pids_in_path(u, u->cgroup_path); +} + +void unit_unwatch_all_pids(Unit *u) { + Iterator i; + void *e; + + assert(u); + + SET_FOREACH(e, u->pids, i) { + hashmap_remove_value(u->manager->watch_pids1, e, u); + hashmap_remove_value(u->manager->watch_pids2, e, u); + } + + set_free(u->pids); + u->pids = NULL; +} + +void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) { + Iterator i; + void *e; + + assert(u); + + /* Cleans dead PIDs from our list */ + + SET_FOREACH(e, u->pids, i) { + pid_t pid = PTR_TO_LONG(e); + + if (pid == except1 || pid == except2) + continue; + + if (!pid_is_unwaited(pid)) + set_remove(u->pids, e); + } +} + +bool unit_job_is_applicable(Unit *u, JobType j) { + assert(u); + assert(j >= 0 && j < _JOB_TYPE_MAX); + + switch (j) { + + case JOB_VERIFY_ACTIVE: + case JOB_START: + case JOB_STOP: + case JOB_NOP: + return true; + + case JOB_RESTART: + case JOB_TRY_RESTART: + return unit_can_start(u); + + case JOB_RELOAD: + return unit_can_reload(u); + + case JOB_RELOAD_OR_START: + return unit_can_reload(u) && unit_can_start(u); + + default: + assert_not_reached("Invalid job type"); + } +} + +int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) { + + static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = { + [UNIT_REQUIRES] = UNIT_REQUIRED_BY, + [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, + [UNIT_WANTS] = UNIT_WANTED_BY, + [UNIT_REQUISITE] = UNIT_REQUIRED_BY, + [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, + [UNIT_BINDS_TO] = UNIT_BOUND_BY, + [UNIT_PART_OF] = UNIT_CONSISTS_OF, + [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID, + [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID, + [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID, + [UNIT_BOUND_BY] = UNIT_BINDS_TO, + [UNIT_CONSISTS_OF] = UNIT_PART_OF, + [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY, + [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS, + [UNIT_BEFORE] = UNIT_AFTER, + [UNIT_AFTER] = UNIT_BEFORE, + [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID, + [UNIT_REFERENCES] = UNIT_REFERENCED_BY, + [UNIT_REFERENCED_BY] = UNIT_REFERENCES, + [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY, + [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS, + [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM, + [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO, + [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF, + }; + int r, q = 0, v = 0, w = 0; + + assert(u); + assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX); + assert(other); + + u = unit_follow_merge(u); + other = unit_follow_merge(other); + + /* We won't allow dependencies on ourselves. We will not + * consider them an error however. */ + if (u == other) + return 0; + + r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) { + r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + } + + if (add_reference) { + r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + } + + q = set_put(u->dependencies[d], other); + if (q < 0) + return q; + + if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) { + v = set_put(other->dependencies[inverse_table[d]], u); + if (v < 0) { + r = v; + goto fail; + } + } + + if (add_reference) { + w = set_put(u->dependencies[UNIT_REFERENCES], other); + if (w < 0) { + r = w; + goto fail; + } + + r = set_put(other->dependencies[UNIT_REFERENCED_BY], u); + if (r < 0) + goto fail; + } + + unit_add_to_dbus_queue(u); + return 0; + +fail: + if (q > 0) + set_remove(u->dependencies[d], other); + + if (v > 0) + set_remove(other->dependencies[inverse_table[d]], u); + + if (w > 0) + set_remove(u->dependencies[UNIT_REFERENCES], other); + + return r; +} + +int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) { + int r; + + assert(u); + + if ((r = unit_add_dependency(u, d, other, add_reference)) < 0) + return r; + + if ((r = unit_add_dependency(u, e, other, add_reference)) < 0) + return r; + + return 0; +} + +static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) { + char *s; + + assert(u); + assert(name || path); + assert(p); + + if (!name) + name = basename(path); + + if (!unit_name_is_template(name)) { + *p = NULL; + return name; + } + + if (u->instance) + s = unit_name_replace_instance(name, u->instance); + else { + _cleanup_free_ char *i = NULL; + + i = unit_name_to_prefix(u->id); + if (!i) + return NULL; + + s = unit_name_replace_instance(name, i); + } + + if (!s) + return NULL; + + *p = s; + return s; +} + +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { + Unit *other; + int r; + _cleanup_free_ char *s = NULL; + + assert(u); + assert(name || path); + + name = resolve_template(u, name, path, &s); + if (!name) + return -ENOMEM; + + r = manager_load_unit(u->manager, name, path, NULL, &other); + if (r < 0) + return r; + + return unit_add_dependency(u, d, other, add_reference); +} + +int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { + Unit *other; + int r; + _cleanup_free_ char *s = NULL; + + assert(u); + assert(name || path); + + if (!(name = resolve_template(u, name, path, &s))) + return -ENOMEM; + + if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0) + return r; + + r = unit_add_two_dependencies(u, d, e, other, add_reference); + + return r; +} + +int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { + Unit *other; + int r; + _cleanup_free_ char *s = NULL; + + assert(u); + assert(name || path); + + if (!(name = resolve_template(u, name, path, &s))) + return -ENOMEM; + + if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0) + return r; + + r = unit_add_dependency(other, d, u, add_reference); + + return r; +} + +int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { + Unit *other; + int r; + _cleanup_free_ char *s = NULL; + + assert(u); + assert(name || path); + + if (!(name = resolve_template(u, name, path, &s))) + return -ENOMEM; + + if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0) + return r; + + if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0) + return r; + + return r; +} + +int set_unit_path(const char *p) { + _cleanup_free_ char *c = NULL; + + /* This is mostly for debug purposes */ + c = path_make_absolute_cwd(p); + if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) + return -errno; + + return 0; +} + +char *unit_dbus_path(Unit *u) { + assert(u); + + if (!u->id) + return NULL; + + return unit_dbus_path_from_name(u->id); +} + +char *unit_default_cgroup_path(Unit *u) { + _cleanup_free_ char *escaped = NULL, *slice = NULL; + int r; + + assert(u); + + if (unit_has_name(u, SPECIAL_ROOT_SLICE)) + return strdup(u->manager->cgroup_root); + + if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) { + r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice); + if (r < 0) + return NULL; + } + + escaped = cg_escape(u->id); + if (!escaped) + return NULL; + + if (slice) + return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL); + else + return strjoin(u->manager->cgroup_root, "/", escaped, NULL); +} + +int unit_add_default_slice(Unit *u) { + _cleanup_free_ char *b = NULL; + const char *slice_name; + Unit *slice; + int r; + + assert(u); + + if (UNIT_ISSET(u->slice)) + return 0; + + if (!unit_get_cgroup_context(u)) + return 0; + + if (u->instance) { + _cleanup_free_ char *prefix = NULL, *escaped = NULL; + + /* Implicitly place all instantiated units in their + * own per-template slice */ + + prefix = unit_name_to_prefix(u->id); + if (!prefix) + return -ENOMEM; + + /* The prefix is already escaped, but it might include + * "-" which has a special meaning for slice units, + * hence escape it here extra. */ + escaped = strreplace(prefix, "-", "\\x2d"); + if (!escaped) + return -ENOMEM; + + if (u->manager->running_as == SYSTEMD_SYSTEM) + b = strjoin("system-", escaped, ".slice", NULL); + else + b = strappend(escaped, ".slice"); + if (!b) + return -ENOMEM; + + slice_name = b; + } else + slice_name = + u->manager->running_as == SYSTEMD_SYSTEM + ? SPECIAL_SYSTEM_SLICE + : SPECIAL_ROOT_SLICE; + + r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice); + if (r < 0) + return r; + + unit_ref_set(&u->slice, slice); + return 0; +} + +const char *unit_slice_name(Unit *u) { + assert(u); + + if (!UNIT_ISSET(u->slice)) + return NULL; + + return UNIT_DEREF(u->slice)->id; +} + +int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { + _cleanup_free_ char *t = NULL; + int r; + + assert(u); + assert(type); + assert(_found); + + t = unit_name_change_suffix(u->id, type); + if (!t) + return -ENOMEM; + + assert(!unit_has_name(u, t)); + + r = manager_load_unit(u->manager, t, NULL, NULL, _found); + assert(r < 0 || *_found != u); + return r; +} + +int unit_watch_bus_name(Unit *u, const char *name) { + assert(u); + assert(name); + + /* Watch a specific name on the bus. We only support one unit + * watching each name for now. */ + + return hashmap_put(u->manager->watch_bus, name, u); +} + +void unit_unwatch_bus_name(Unit *u, const char *name) { + assert(u); + assert(name); + + hashmap_remove_value(u->manager->watch_bus, name, u); +} + +bool unit_can_serialize(Unit *u) { + assert(u); + + return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; +} + +int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { + ExecRuntime *rt; + int r; + + assert(u); + assert(f); + assert(fds); + + if (!unit_can_serialize(u)) + return 0; + + r = UNIT_VTABLE(u)->serialize(u, f, fds); + if (r < 0) + return r; + + rt = unit_get_exec_runtime(u); + if (rt) { + r = exec_runtime_serialize(rt, u, f, fds); + if (r < 0) + return r; + } + + dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); + dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp); + dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp); + dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); + dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp); + + if (dual_timestamp_is_set(&u->condition_timestamp)) + unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result)); + + unit_serialize_item(u, f, "transient", yes_no(u->transient)); + + if (u->cgroup_path) + unit_serialize_item(u, f, "cgroup", u->cgroup_path); + + if (serialize_jobs) { + if (u->job) { + fprintf(f, "job\n"); + job_serialize(u->job, f, fds); + } + + if (u->nop_job) { + fprintf(f, "job\n"); + job_serialize(u->nop_job, f, fds); + } + } + + /* End marker */ + fputc('\n', f); + return 0; +} + +void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { + va_list ap; + + assert(u); + assert(f); + assert(key); + assert(format); + + fputs(key, f); + fputc('=', f); + + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); + + fputc('\n', f); +} + +void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { + assert(u); + assert(f); + assert(key); + assert(value); + + fprintf(f, "%s=%s\n", key, value); +} + +int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + size_t offset; + ExecRuntime **rt = NULL; + int r; + + assert(u); + assert(f); + assert(fds); + + if (!unit_can_serialize(u)) + return 0; + + offset = UNIT_VTABLE(u)->exec_runtime_offset; + if (offset > 0) + rt = (ExecRuntime**) ((uint8_t*) u + offset); + + for (;;) { + char line[LINE_MAX], *l, *v; + size_t k; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + return 0; + return -errno; + } + + char_array_0(line); + l = strstrip(line); + + /* End marker */ + if (l[0] == 0) + return 0; + + k = strcspn(l, "="); + + if (l[k] == '=') { + l[k] = 0; + v = l+k+1; + } else + v = l+k; + + if (streq(l, "job")) { + if (v[0] == '\0') { + /* new-style serialized job */ + Job *j = job_new_raw(u); + if (!j) + return -ENOMEM; + + r = job_deserialize(j, f, fds); + if (r < 0) { + job_free(j); + return r; + } + + r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j); + if (r < 0) { + job_free(j); + return r; + } + + r = job_install_deserialized(j); + if (r < 0) { + hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id)); + job_free(j); + return r; + } + + if (j->state == JOB_RUNNING) + u->manager->n_running_jobs++; + } else { + /* legacy */ + JobType type = job_type_from_string(v); + if (type < 0) + log_debug("Failed to parse job type value %s", v); + else + u->deserialized_job = type; + } + continue; + } else if (streq(l, "inactive-exit-timestamp")) { + dual_timestamp_deserialize(v, &u->inactive_exit_timestamp); + continue; + } else if (streq(l, "active-enter-timestamp")) { + dual_timestamp_deserialize(v, &u->active_enter_timestamp); + continue; + } else if (streq(l, "active-exit-timestamp")) { + dual_timestamp_deserialize(v, &u->active_exit_timestamp); + continue; + } else if (streq(l, "inactive-enter-timestamp")) { + dual_timestamp_deserialize(v, &u->inactive_enter_timestamp); + continue; + } else if (streq(l, "condition-timestamp")) { + dual_timestamp_deserialize(v, &u->condition_timestamp); + continue; + } else if (streq(l, "condition-result")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse condition result value %s", v); + else + u->condition_result = b; + + continue; + + } else if (streq(l, "transient")) { + int b; + + b = parse_boolean(v); + if (b < 0) + log_debug("Failed to parse transient bool %s", v); + else + u->transient = b; + + continue; + } else if (streq(l, "cgroup")) { + char *s; + + s = strdup(v); + if (!s) + return -ENOMEM; + + free(u->cgroup_path); + u->cgroup_path = s; + + assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1); + continue; + } + + if (rt) { + r = exec_runtime_deserialize_item(rt, u, l, v, fds); + if (r < 0) + return r; + if (r > 0) + continue; + } + + r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds); + if (r < 0) + return r; + } +} + +int unit_add_node_link(Unit *u, const char *what, bool wants) { + Unit *device; + _cleanup_free_ char *e = NULL; + int r; + + assert(u); + + if (!what) + return 0; + + /* Adds in links to the device node that this unit is based on */ + + if (!is_device_path(what)) + return 0; + + e = unit_name_from_path(what, ".device"); + if (!e) + return -ENOMEM; + + r = manager_load_unit(u->manager, e, NULL, NULL, &device); + + if (r < 0) + return r; + + r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true); + if (r < 0) + return r; + + if (wants) { + r = unit_add_dependency(device, UNIT_WANTS, u, false); + if (r < 0) + return r; + } + + return 0; +} + +int unit_coldplug(Unit *u) { + int r; + + assert(u); + + if (UNIT_VTABLE(u)->coldplug) + if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) + return r; + + if (u->job) { + r = job_coldplug(u->job); + if (r < 0) + return r; + } else if (u->deserialized_job >= 0) { + /* legacy */ + r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL); + if (r < 0) + return r; + + u->deserialized_job = _JOB_TYPE_INVALID; + } + + return 0; +} + +void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) { + DISABLE_WARNING_FORMAT_NONLITERAL; + manager_status_printf(u->manager, false, status, unit_status_msg_format, unit_description(u)); + REENABLE_WARNING; +} + +bool unit_need_daemon_reload(Unit *u) { + _cleanup_strv_free_ char **t = NULL; + char **path; + struct stat st; + unsigned loaded_cnt, current_cnt; + + assert(u); + + if (u->fragment_path) { + zero(st); + if (stat(u->fragment_path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + if (u->fragment_mtime > 0 && + timespec_load(&st.st_mtim) != u->fragment_mtime) + return true; + } + + if (u->source_path) { + zero(st); + if (stat(u->source_path, &st) < 0) + return true; + + if (u->source_mtime > 0 && + timespec_load(&st.st_mtim) != u->source_mtime) + return true; + } + + t = unit_find_dropin_paths(u); + loaded_cnt = strv_length(t); + current_cnt = strv_length(u->dropin_paths); + + if (loaded_cnt == current_cnt) { + if (loaded_cnt == 0) + return false; + + if (strv_overlap(u->dropin_paths, t)) { + STRV_FOREACH(path, u->dropin_paths) { + zero(st); + if (stat(*path, &st) < 0) + return true; + + if (u->dropin_mtime > 0 && + timespec_load(&st.st_mtim) > u->dropin_mtime) + return true; + } + + return false; + } else + return true; + } else + return true; +} + +void unit_reset_failed(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->reset_failed) + UNIT_VTABLE(u)->reset_failed(u); +} + +Unit *unit_following(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->following) + return UNIT_VTABLE(u)->following(u); + + return NULL; +} + +bool unit_stop_pending(Unit *u) { + assert(u); + + /* This call does check the current state of the unit. It's + * hence useful to be called from state change calls of the + * unit itself, where the state isn't updated yet. This is + * different from unit_inactive_or_pending() which checks both + * the current state and for a queued job. */ + + return u->job && u->job->type == JOB_STOP; +} + +bool unit_inactive_or_pending(Unit *u) { + assert(u); + + /* Returns true if the unit is inactive or going down */ + + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))) + return true; + + if (unit_stop_pending(u)) + return true; + + return false; +} + +bool unit_active_or_pending(Unit *u) { + assert(u); + + /* Returns true if the unit is active or going up */ + + if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) + return true; + + if (u->job && + (u->job->type == JOB_START || + u->job->type == JOB_RELOAD_OR_START || + u->job->type == JOB_RESTART)) + return true; + + return false; +} + +int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) { + assert(u); + assert(w >= 0 && w < _KILL_WHO_MAX); + assert(signo > 0); + assert(signo < _NSIG); + + if (!UNIT_VTABLE(u)->kill) + return -ENOTSUP; + + return UNIT_VTABLE(u)->kill(u, w, signo, error); +} + +static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) { + Set *pid_set; + int r; + + pid_set = set_new(trivial_hash_func, trivial_compare_func); + if (!pid_set) + return NULL; + + /* Exclude the main/control pids from being killed via the cgroup */ + if (main_pid > 0) { + r = set_put(pid_set, LONG_TO_PTR(main_pid)); + if (r < 0) + goto fail; + } + + if (control_pid > 0) { + r = set_put(pid_set, LONG_TO_PTR(control_pid)); + if (r < 0) + goto fail; + } + + return pid_set; + +fail: + set_free(pid_set); + return NULL; +} + +int unit_kill_common( + Unit *u, + KillWho who, + int signo, + pid_t main_pid, + pid_t control_pid, + sd_bus_error *error) { + + int r = 0; + + if (who == KILL_MAIN && main_pid <= 0) { + if (main_pid < 0) + sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type)); + else + sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); + return -ESRCH; + } + + if (who == KILL_CONTROL && control_pid <= 0) { + if (control_pid < 0) + sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type)); + else + sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); + return -ESRCH; + } + + if (who == KILL_CONTROL || who == KILL_ALL) + if (control_pid > 0) + if (kill(control_pid, signo) < 0) + r = -errno; + + if (who == KILL_MAIN || who == KILL_ALL) + if (main_pid > 0) + if (kill(main_pid, signo) < 0) + r = -errno; + + if (who == KILL_ALL && u->cgroup_path) { + _cleanup_set_free_ Set *pid_set = NULL; + int q; + + /* Exclude the main/control pids from being killed via the cgroup */ + pid_set = unit_pid_set(main_pid, control_pid); + if (!pid_set) + return -ENOMEM; + + q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set); + if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT) + r = q; + } + + return r; +} + +int unit_following_set(Unit *u, Set **s) { + assert(u); + assert(s); + + if (UNIT_VTABLE(u)->following_set) + return UNIT_VTABLE(u)->following_set(u, s); + + *s = NULL; + return 0; +} + +UnitFileState unit_get_unit_file_state(Unit *u) { + assert(u); + + if (u->unit_file_state < 0 && u->fragment_path) + u->unit_file_state = unit_file_get_state( + u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, + NULL, basename(u->fragment_path)); + + return u->unit_file_state; +} + +Unit* unit_ref_set(UnitRef *ref, Unit *u) { + assert(ref); + assert(u); + + if (ref->unit) + unit_ref_unset(ref); + + ref->unit = u; + LIST_PREPEND(refs, u->refs, ref); + return u; +} + +void unit_ref_unset(UnitRef *ref) { + assert(ref); + + if (!ref->unit) + return; + + LIST_REMOVE(refs, ref->unit->refs, ref); + ref->unit = NULL; +} + +int unit_exec_context_defaults(Unit *u, ExecContext *c) { + unsigned i; + int r; + + assert(u); + assert(c); + + /* This only copies in the ones that need memory */ + for (i = 0; i < RLIMIT_NLIMITS; i++) + if (u->manager->rlimit[i] && !c->rlimit[i]) { + c->rlimit[i] = newdup(struct rlimit, u->manager->rlimit[i], 1); + if (!c->rlimit[i]) + return -ENOMEM; + } + + if (u->manager->running_as == SYSTEMD_USER && + !c->working_directory) { + + r = get_home_dir(&c->working_directory); + if (r < 0) + return r; + } + + return 0; +} + +ExecContext *unit_get_exec_context(Unit *u) { + size_t offset; + assert(u); + + offset = UNIT_VTABLE(u)->exec_context_offset; + if (offset <= 0) + return NULL; + + return (ExecContext*) ((uint8_t*) u + offset); +} + +KillContext *unit_get_kill_context(Unit *u) { + size_t offset; + assert(u); + + offset = UNIT_VTABLE(u)->kill_context_offset; + if (offset <= 0) + return NULL; + + return (KillContext*) ((uint8_t*) u + offset); +} + +CGroupContext *unit_get_cgroup_context(Unit *u) { + size_t offset; + + offset = UNIT_VTABLE(u)->cgroup_context_offset; + if (offset <= 0) + return NULL; + + return (CGroupContext*) ((uint8_t*) u + offset); +} + +ExecRuntime *unit_get_exec_runtime(Unit *u) { + size_t offset; + + offset = UNIT_VTABLE(u)->exec_runtime_offset; + if (offset <= 0) + return NULL; + + return *(ExecRuntime**) ((uint8_t*) u + offset); +} + +static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **_p, char **_q) { + _cleanup_free_ char *b = NULL; + char *p, *q; + int r; + + assert(u); + assert(name); + assert(_p); + assert(_q); + + b = xescape(name, "/."); + if (!b) + return -ENOMEM; + + if (!filename_is_safe(b)) + return -EINVAL; + + if (u->manager->running_as == SYSTEMD_USER) { + _cleanup_free_ char *c = NULL; + + r = user_config_home(&c); + if (r < 0) + return r; + if (r == 0) + return -ENOENT; + + p = strjoin(c, "/", u->id, ".d", NULL); + } else if (mode == UNIT_PERSISTENT && !u->transient) + p = strjoin("/etc/systemd/system/", u->id, ".d", NULL); + else + p = strjoin("/run/systemd/system/", u->id, ".d", NULL); + if (!p) + return -ENOMEM; + + q = strjoin(p, "/90-", b, ".conf", NULL); + if (!q) { + free(p); + return -ENOMEM; + } + + *_p = p; + *_q = q; + return 0; +} + +int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { + _cleanup_free_ char *p = NULL, *q = NULL; + int r; + + assert(u); + assert(name); + assert(data); + + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) + return 0; + + r = drop_in_file(u, mode, name, &p, &q); + if (r < 0) + return r; + + mkdir_p(p, 0755); + return write_string_file_atomic_label(q, data); +} + +int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) { + _cleanup_free_ char *p = NULL; + va_list ap; + int r; + + assert(u); + assert(name); + assert(format); + + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) + return 0; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0) + return -ENOMEM; + + return unit_write_drop_in(u, mode, name, p); +} + +int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { + _cleanup_free_ char *ndata = NULL; + + assert(u); + assert(name); + assert(data); + + if (!UNIT_VTABLE(u)->private_section) + return -EINVAL; + + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) + return 0; + + ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); + if (!ndata) + return -ENOMEM; + + return unit_write_drop_in(u, mode, name, ndata); +} + +int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) { + _cleanup_free_ char *p = NULL; + va_list ap; + int r; + + assert(u); + assert(name); + assert(format); + + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) + return 0; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0) + return -ENOMEM; + + return unit_write_drop_in_private(u, mode, name, p); +} + +int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) { + _cleanup_free_ char *p = NULL, *q = NULL; + int r; + + assert(u); + + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) + return 0; + + r = drop_in_file(u, mode, name, &p, &q); + if (r < 0) + return r; + + if (unlink(q) < 0) + r = errno == ENOENT ? 0 : -errno; + else + r = 1; + + rmdir(p); + return r; +} + +int unit_make_transient(Unit *u) { + int r; + + assert(u); + + u->load_state = UNIT_STUB; + u->load_error = 0; + u->transient = true; + + free(u->fragment_path); + u->fragment_path = NULL; + + if (u->manager->running_as == SYSTEMD_USER) { + _cleanup_free_ char *c = NULL; + + r = user_config_home(&c); + if (r < 0) + return r; + if (r == 0) + return -ENOENT; + + u->fragment_path = strjoin(c, "/", u->id, NULL); + if (!u->fragment_path) + return -ENOMEM; + + mkdir_p(c, 0755); + } else { + u->fragment_path = strappend("/run/systemd/system/", u->id); + if (!u->fragment_path) + return -ENOMEM; + + mkdir_p("/run/systemd/system", 0755); + } + + return write_string_file_atomic_label(u->fragment_path, "# Transient stub"); +} + +int unit_kill_context( + Unit *u, + KillContext *c, + bool sigkill, + pid_t main_pid, + pid_t control_pid, + bool main_pid_alien) { + + int sig, wait_for_exit = false, r; + + assert(u); + assert(c); + + if (c->kill_mode == KILL_NONE) + return 0; + + sig = sigkill ? SIGKILL : c->kill_signal; + + if (main_pid > 0) { + r = kill_and_sigcont(main_pid, sig); + + if (r < 0 && r != -ESRCH) { + _cleanup_free_ char *comm = NULL; + get_process_comm(main_pid, &comm); + + log_warning_unit(u->id, "Failed to kill main process " PID_FMT " (%s): %s", main_pid, strna(comm), strerror(-r)); + } else { + if (!main_pid_alien) + wait_for_exit = true; + + if (c->send_sighup && !sigkill) + kill(main_pid, SIGHUP); + } + } + + if (control_pid > 0) { + r = kill_and_sigcont(control_pid, sig); + + if (r < 0 && r != -ESRCH) { + _cleanup_free_ char *comm = NULL; + get_process_comm(control_pid, &comm); + + log_warning_unit(u->id, "Failed to kill control process " PID_FMT " (%s): %s", control_pid, strna(comm), strerror(-r)); + } else { + wait_for_exit = true; + + if (c->send_sighup && !sigkill) + kill(control_pid, SIGHUP); + } + } + + if ((c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && sigkill)) && u->cgroup_path) { + _cleanup_set_free_ Set *pid_set = NULL; + + /* Exclude the main/control pids from being killed via the cgroup */ + pid_set = unit_pid_set(main_pid, control_pid); + if (!pid_set) + return -ENOMEM; + + r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set); + if (r < 0) { + if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) + log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r)); + } else if (r > 0) { + + /* FIXME: For now, we will not wait for the + * cgroup members to die, simply because + * cgroup notification is unreliable. It + * doesn't work at all in containers, and + * outside of containers it can be confused + * easily by leaving directories in the + * cgroup. */ + + /* wait_for_exit = true; */ + + if (c->send_sighup && !sigkill) { + set_free(pid_set); + + pid_set = unit_pid_set(main_pid, control_pid); + if (!pid_set) + return -ENOMEM; + + cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, false, true, false, pid_set); + } + } + } + + return wait_for_exit; +} + +int unit_require_mounts_for(Unit *u, const char *path) { + char prefix[strlen(path) + 1], *p; + int r; + + assert(u); + assert(path); + + /* Registers a unit for requiring a certain path and all its + * prefixes. We keep a simple array of these paths in the + * unit, since its usually short. However, we build a prefix + * table for all possible prefixes so that new appearing mount + * units can easily determine which units to make themselves a + * dependency of. */ + + if (!path_is_absolute(path)) + return -EINVAL; + + p = strdup(path); + if (!p) + return -ENOMEM; + + path_kill_slashes(p); + + if (!path_is_safe(p)) { + free(p); + return -EPERM; + } + + if (strv_contains(u->requires_mounts_for, p)) { + free(p); + return 0; + } + + r = strv_push(&u->requires_mounts_for, p); + if (r < 0) { + free(p); + return r; + } + + PATH_FOREACH_PREFIX_MORE(prefix, p) { + Set *x; + + x = hashmap_get(u->manager->units_requiring_mounts_for, prefix); + if (!x) { + char *q; + + if (!u->manager->units_requiring_mounts_for) { + u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func); + if (!u->manager->units_requiring_mounts_for) + return -ENOMEM; + } + + q = strdup(prefix); + if (!q) + return -ENOMEM; + + x = set_new(NULL, NULL); + if (!x) { + free(q); + return -ENOMEM; + } + + r = hashmap_put(u->manager->units_requiring_mounts_for, q, x); + if (r < 0) { + free(q); + set_free(x); + return r; + } + } + + r = set_put(x, u); + if (r < 0) + return r; + } + + return 0; +} + +int unit_setup_exec_runtime(Unit *u) { + ExecRuntime **rt; + size_t offset; + Iterator i; + Unit *other; + + offset = UNIT_VTABLE(u)->exec_runtime_offset; + assert(offset > 0); + + /* Check if ther already is an ExecRuntime for this unit? */ + rt = (ExecRuntime**) ((uint8_t*) u + offset); + if (*rt) + return 0; + + /* Try to get it from somebody else */ + SET_FOREACH(other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) { + + *rt = unit_get_exec_runtime(other); + if (*rt) { + exec_runtime_ref(*rt); + return 0; + } + } + + return exec_runtime_make(rt, unit_get_exec_context(u), u->id); +} + +static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", + [UNIT_INACTIVE] = "inactive", + [UNIT_FAILED] = "failed", + [UNIT_ACTIVATING] = "activating", + [UNIT_DEACTIVATING] = "deactivating" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); + +static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { + [UNIT_REQUIRES] = "Requires", + [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", + [UNIT_REQUISITE] = "Requisite", + [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable", + [UNIT_WANTS] = "Wants", + [UNIT_BINDS_TO] = "BindsTo", + [UNIT_PART_OF] = "PartOf", + [UNIT_REQUIRED_BY] = "RequiredBy", + [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", + [UNIT_WANTED_BY] = "WantedBy", + [UNIT_BOUND_BY] = "BoundBy", + [UNIT_CONSISTS_OF] = "ConsistsOf", + [UNIT_CONFLICTS] = "Conflicts", + [UNIT_CONFLICTED_BY] = "ConflictedBy", + [UNIT_BEFORE] = "Before", + [UNIT_AFTER] = "After", + [UNIT_ON_FAILURE] = "OnFailure", + [UNIT_TRIGGERS] = "Triggers", + [UNIT_TRIGGERED_BY] = "TriggeredBy", + [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo", + [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom", + [UNIT_REFERENCES] = "References", + [UNIT_REFERENCED_BY] = "ReferencedBy", + [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); diff --git a/src/core/unit.h b/src/core/unit.h new file mode 100644 index 0000000..808929e --- /dev/null +++ b/src/core/unit.h @@ -0,0 +1,643 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +typedef struct Unit Unit; +typedef struct UnitVTable UnitVTable; +typedef enum UnitActiveState UnitActiveState; +typedef enum UnitDependency UnitDependency; +typedef struct UnitRef UnitRef; +typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; + +#include "sd-event.h" +#include "set.h" +#include "util.h" +#include "list.h" +#include "socket-util.h" +#include "execute.h" +#include "cgroup.h" +#include "condition.h" +#include "install.h" +#include "unit-name.h" + +enum UnitActiveState { + UNIT_ACTIVE, + UNIT_RELOADING, + UNIT_INACTIVE, + UNIT_FAILED, + UNIT_ACTIVATING, + UNIT_DEACTIVATING, + _UNIT_ACTIVE_STATE_MAX, + _UNIT_ACTIVE_STATE_INVALID = -1 +}; + +static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) { + return t == UNIT_ACTIVE || t == UNIT_RELOADING; +} + +static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) { + return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING; +} + +static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) { + return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING; +} + +static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) { + return t == UNIT_INACTIVE || t == UNIT_FAILED; +} + +enum UnitDependency { + /* Positive dependencies */ + UNIT_REQUIRES, + UNIT_REQUIRES_OVERRIDABLE, + UNIT_REQUISITE, + UNIT_REQUISITE_OVERRIDABLE, + UNIT_WANTS, + UNIT_BINDS_TO, + UNIT_PART_OF, + + /* Inverse of the above */ + UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ + UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ + UNIT_WANTED_BY, /* inverse of 'wants' */ + UNIT_BOUND_BY, /* inverse of 'binds_to' */ + UNIT_CONSISTS_OF, /* inverse of 'part_of' */ + + /* Negative dependencies */ + UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ + UNIT_CONFLICTED_BY, + + /* Order */ + UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */ + UNIT_AFTER, + + /* On Failure */ + UNIT_ON_FAILURE, + + /* Triggers (i.e. a socket triggers a service) */ + UNIT_TRIGGERS, + UNIT_TRIGGERED_BY, + + /* Propagate reloads */ + UNIT_PROPAGATES_RELOAD_TO, + UNIT_RELOAD_PROPAGATED_FROM, + + /* Joins namespace of */ + UNIT_JOINS_NAMESPACE_OF, + + /* Reference information for GC logic */ + UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ + UNIT_REFERENCED_BY, + + _UNIT_DEPENDENCY_MAX, + _UNIT_DEPENDENCY_INVALID = -1 +}; + +#include "manager.h" +#include "job.h" + +struct UnitRef { + /* Keeps tracks of references to a unit. This is useful so + * that we can merge two units if necessary and correct all + * references to them */ + + Unit* unit; + LIST_FIELDS(UnitRef, refs); +}; + +struct Unit { + Manager *manager; + + UnitType type; + UnitLoadState load_state; + Unit *merged_into; + + char *id; /* One name is special because we use it for identification. Points to an entry in the names set */ + char *instance; + + Set *names; + Set *dependencies[_UNIT_DEPENDENCY_MAX]; + + char **requires_mounts_for; + + char *description; + char **documentation; + + char *fragment_path; /* if loaded from a config file this is the primary path to it */ + char *source_path; /* if converted, the source file */ + char **dropin_paths; + usec_t fragment_mtime; + usec_t source_mtime; + usec_t dropin_mtime; + + /* If there is something to do with this unit, then this is the installed job for it */ + Job *job; + + /* JOB_NOP jobs are special and can be installed without disturbing the real job. */ + Job *nop_job; + + usec_t job_timeout; + + /* References to this */ + LIST_HEAD(UnitRef, refs); + + /* Conditions to check */ + LIST_HEAD(Condition, conditions); + + dual_timestamp condition_timestamp; + + dual_timestamp inactive_exit_timestamp; + dual_timestamp active_enter_timestamp; + dual_timestamp active_exit_timestamp; + dual_timestamp inactive_enter_timestamp; + + /* Counterparts in the cgroup filesystem */ + char *cgroup_path; + CGroupControllerMask cgroup_realized_mask; + CGroupControllerMask cgroup_subtree_mask; + CGroupControllerMask cgroup_members_mask; + + UnitRef slice; + + /* Per type list */ + LIST_FIELDS(Unit, units_by_type); + + /* All units which have requires_mounts_for set */ + LIST_FIELDS(Unit, has_requires_mounts_for); + + /* Load queue */ + LIST_FIELDS(Unit, load_queue); + + /* D-Bus queue */ + LIST_FIELDS(Unit, dbus_queue); + + /* Cleanup queue */ + LIST_FIELDS(Unit, cleanup_queue); + + /* GC queue */ + LIST_FIELDS(Unit, gc_queue); + + /* CGroup realize members queue */ + LIST_FIELDS(Unit, cgroup_queue); + + /* PIDs we keep an eye on. Note that a unit might have many + * more, but these are the ones we care enough about to + * process SIGCHLD for */ + Set *pids; + + /* Used during GC sweeps */ + unsigned gc_marker; + + /* When deserializing, temporarily store the job type for this + * unit here, if there was a job scheduled. + * Only for deserializing from a legacy version. New style uses full + * serialized jobs. */ + int deserialized_job; /* This is actually of type JobType */ + + /* Error code when we didn't manage to load the unit (negative) */ + int load_error; + + /* Cached unit file state */ + UnitFileState unit_file_state; + + /* Garbage collect us we nobody wants or requires us anymore */ + bool stop_when_unneeded; + + /* Create default dependencies */ + bool default_dependencies; + + /* Refuse manual starting, allow starting only indirectly via dependency. */ + bool refuse_manual_start; + + /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */ + bool refuse_manual_stop; + + /* Allow isolation requests */ + bool allow_isolate; + + /* How to start OnFailure units */ + JobMode on_failure_job_mode; + + /* Ignore this unit when isolating */ + bool ignore_on_isolate; + + /* Ignore this unit when snapshotting */ + bool ignore_on_snapshot; + + /* Did the last condition check succeed? */ + bool condition_result; + + /* Is this a transient unit? */ + bool transient; + + bool in_load_queue:1; + bool in_dbus_queue:1; + bool in_cleanup_queue:1; + bool in_gc_queue:1; + bool in_cgroup_queue:1; + + bool sent_dbus_new_signal:1; + + bool no_gc:1; + + bool in_audit:1; + + bool cgroup_realized:1; + bool cgroup_members_mask_valid:1; + bool cgroup_subtree_mask_valid:1; +}; + +struct UnitStatusMessageFormats { + const char *starting_stopping[2]; + const char *finished_start_job[_JOB_RESULT_MAX]; + const char *finished_stop_job[_JOB_RESULT_MAX]; +}; + +typedef enum UnitSetPropertiesMode { + UNIT_CHECK = 0, + UNIT_RUNTIME = 1, + UNIT_PERSISTENT = 2, +} UnitSetPropertiesMode; + +#include "service.h" +#include "socket.h" +#include "busname.h" +#include "target.h" +#include "snapshot.h" +#include "device.h" +#include "mount.h" +#include "automount.h" +#include "swap.h" +#include "timer.h" +#include "path.h" +#include "slice.h" +#include "scope.h" + +struct UnitVTable { + /* How much memory does an object of this unit type need */ + size_t object_size; + + /* If greater than 0, the offset into the object where + * ExecContext is found, if the unit type has that */ + size_t exec_context_offset; + + /* If greater than 0, the offset into the object where + * CGroupContext is found, if the unit type has that */ + size_t cgroup_context_offset; + + /* If greater than 0, the offset into the object where + * KillContext is found, if the unit type has that */ + size_t kill_context_offset; + + /* If greater than 0, the offset into the object where the + * pointer to ExecRuntime is found, if the unit type has + * that */ + size_t exec_runtime_offset; + + /* The name of the configuration file section with the private settings of this unit*/ + const char *private_section; + + /* Config file sections this unit type understands, separated + * by NUL chars */ + const char *sections; + + /* This should reset all type-specific variables. This should + * not allocate memory, and is called with zero-initialized + * data. It should hence only initialize variables that need + * to be set != 0. */ + void (*init)(Unit *u); + + /* This should free all type-specific variables. It should be + * idempotent. */ + void (*done)(Unit *u); + + /* Actually load data from disk. This may fail, and should set + * load_state to UNIT_LOADED, UNIT_MERGED or leave it at + * UNIT_STUB if no configuration could be found. */ + int (*load)(Unit *u); + + /* If a lot of units got created via enumerate(), this is + * where to actually set the state and call unit_notify(). */ + int (*coldplug)(Unit *u); + + void (*dump)(Unit *u, FILE *f, const char *prefix); + + int (*start)(Unit *u); + int (*stop)(Unit *u); + int (*reload)(Unit *u); + + int (*kill)(Unit *u, KillWho w, int signo, sd_bus_error *error); + + bool (*can_reload)(Unit *u); + + /* Write all data that cannot be restored from other sources + * away using unit_serialize_item() */ + int (*serialize)(Unit *u, FILE *f, FDSet *fds); + + /* Restore one item from the serialization */ + int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds); + + /* Try to match up fds with what we need for this unit */ + int (*distribute_fds)(Unit *u, FDSet *fds); + + /* Boils down the more complex internal state of this unit to + * a simpler one that the engine can understand */ + UnitActiveState (*active_state)(Unit *u); + + /* Returns the substate specific to this unit type as + * string. This is purely information so that we can give the + * user a more fine grained explanation in which actual state a + * unit is in. */ + const char* (*sub_state_to_string)(Unit *u); + + /* Return true when there is reason to keep this entry around + * even nothing references it and it isn't active in any + * way */ + bool (*check_gc)(Unit *u); + + /* Return true when this unit is suitable for snapshotting */ + bool (*check_snapshot)(Unit *u); + + /* Invoked on every child that died */ + void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); + + /* Reset failed state if we are in failed state */ + void (*reset_failed)(Unit *u); + + /* Called whenever any of the cgroups this unit watches for + * ran empty */ + void (*notify_cgroup_empty)(Unit *u); + + /* Called whenever a process of this unit sends us a message */ + void (*notify_message)(Unit *u, pid_t pid, char **tags); + + /* Called whenever a name this Unit registered for comes or + * goes away. */ + void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner); + + /* Called for each property that is being set */ + int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error); + + /* Called after at least one property got changed to apply the necessary change */ + int (*bus_commit_properties)(Unit *u); + + /* Return the unit this unit is following */ + Unit *(*following)(Unit *u); + + /* Return the set of units that are following each other */ + int (*following_set)(Unit *u, Set **s); + + /* Invoked each time a unit this unit is triggering changes + * state or gains/loses a job */ + void (*trigger_notify)(Unit *u, Unit *trigger); + + /* Called whenever CLOCK_REALTIME made a jump */ + void (*time_change)(Unit *u); + + int (*get_timeout)(Unit *u, uint64_t *timeout); + + /* This is called for each unit type and should be used to + * enumerate existing devices and load them. However, + * everything that is loaded here should still stay in + * inactive state. It is the job of the coldplug() call above + * to put the units into the initial state. */ + int (*enumerate)(Manager *m); + + /* Type specific cleanups. */ + void (*shutdown)(Manager *m); + + /* The interface name */ + const char *bus_interface; + + /* The bus vtable */ + const sd_bus_vtable *bus_vtable; + + /* The strings to print in status messages */ + UnitStatusMessageFormats status_message_formats; + + /* Can units of this type have multiple names? */ + bool no_alias:1; + + /* Instances make no sense for this type */ + bool no_instances:1; + + /* Exclude from automatic gc */ + bool no_gc:1; + + /* True if transient units of this type are OK */ + bool can_transient:1; +}; + +extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX]; + +#define UNIT_VTABLE(u) unit_vtable[(u)->type] + +/* For casting a unit into the various unit types */ +#define DEFINE_CAST(UPPERCASE, MixedCase) \ + static inline MixedCase* UPPERCASE(Unit *u) { \ + if (_unlikely_(!u || u->type != UNIT_##UPPERCASE)) \ + return NULL; \ + \ + return (MixedCase*) u; \ + } + +/* For casting the various unit types into a unit */ +#define UNIT(u) (&(u)->meta) + +#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS])) + +DEFINE_CAST(SERVICE, Service); +DEFINE_CAST(SOCKET, Socket); +DEFINE_CAST(BUSNAME, BusName); +DEFINE_CAST(TARGET, Target); +DEFINE_CAST(SNAPSHOT, Snapshot); +DEFINE_CAST(DEVICE, Device); +DEFINE_CAST(MOUNT, Mount); +DEFINE_CAST(AUTOMOUNT, Automount); +DEFINE_CAST(SWAP, Swap); +DEFINE_CAST(TIMER, Timer); +DEFINE_CAST(PATH, Path); +DEFINE_CAST(SLICE, Slice); +DEFINE_CAST(SCOPE, Scope); + +Unit *unit_new(Manager *m, size_t size); +void unit_free(Unit *u); + +int unit_add_name(Unit *u, const char *name); + +int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference); +int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference); + +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); +int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); + +int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); +int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); + +int unit_add_exec_dependencies(Unit *u, ExecContext *c); + +int unit_choose_id(Unit *u, const char *name); +int unit_set_description(Unit *u, const char *description); + +bool unit_check_gc(Unit *u); + +void unit_add_to_load_queue(Unit *u); +void unit_add_to_dbus_queue(Unit *u); +void unit_add_to_cleanup_queue(Unit *u); +void unit_add_to_gc_queue(Unit *u); + +int unit_merge(Unit *u, Unit *other); +int unit_merge_by_name(Unit *u, const char *other); + +Unit *unit_follow_merge(Unit *u) _pure_; + +int unit_load_fragment_and_dropin(Unit *u); +int unit_load_fragment_and_dropin_optional(Unit *u); +int unit_load(Unit *unit); + +int unit_add_default_slice(Unit *u); + +const char *unit_description(Unit *u) _pure_; + +bool unit_has_name(Unit *u, const char *name); + +UnitActiveState unit_active_state(Unit *u); + +const char* unit_sub_state_to_string(Unit *u); + +void unit_dump(Unit *u, FILE *f, const char *prefix); + +bool unit_can_reload(Unit *u) _pure_; +bool unit_can_start(Unit *u) _pure_; +bool unit_can_isolate(Unit *u) _pure_; + +int unit_start(Unit *u); +int unit_stop(Unit *u); +int unit_reload(Unit *u); + +int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error); +int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t control_pid, sd_bus_error *error); + +void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success); + +int unit_watch_pid(Unit *u, pid_t pid); +void unit_unwatch_pid(Unit *u, pid_t pid); +int unit_watch_all_pids(Unit *u); +void unit_unwatch_all_pids(Unit *u); + +void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2); + +int unit_watch_bus_name(Unit *u, const char *name); +void unit_unwatch_bus_name(Unit *u, const char *name); + +bool unit_job_is_applicable(Unit *u, JobType j); + +int set_unit_path(const char *p); + +char *unit_dbus_path(Unit *u); + +int unit_load_related_unit(Unit *u, const char *type, Unit **_found); + +bool unit_can_serialize(Unit *u) _pure_; +int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); +void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); +void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); +int unit_deserialize(Unit *u, FILE *f, FDSet *fds); + +int unit_add_node_link(Unit *u, const char *what, bool wants); + +int unit_coldplug(Unit *u); + +void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0); + +bool unit_need_daemon_reload(Unit *u); + +void unit_reset_failed(Unit *u); + +Unit *unit_following(Unit *u); +int unit_following_set(Unit *u, Set **s); + +const char *unit_slice_name(Unit *u); + +bool unit_stop_pending(Unit *u) _pure_; +bool unit_inactive_or_pending(Unit *u) _pure_; +bool unit_active_or_pending(Unit *u); + +int unit_add_default_target_dependency(Unit *u, Unit *target); + +char *unit_default_cgroup_path(Unit *u); + +void unit_start_on_failure(Unit *u); +void unit_trigger_notify(Unit *u); + +UnitFileState unit_get_unit_file_state(Unit *u); + +Unit* unit_ref_set(UnitRef *ref, Unit *u); +void unit_ref_unset(UnitRef *ref); + +#define UNIT_DEREF(ref) ((ref).unit) +#define UNIT_ISSET(ref) (!!(ref).unit) + +int unit_exec_context_defaults(Unit *u, ExecContext *c); + +ExecContext *unit_get_exec_context(Unit *u) _pure_; +KillContext *unit_get_kill_context(Unit *u) _pure_; +CGroupContext *unit_get_cgroup_context(Unit *u) _pure_; +ExecRuntime *unit_get_exec_runtime(Unit *u) _pure_; + +int unit_setup_exec_runtime(Unit *u); + +int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data); +int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5); + +int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data); +int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5); + +int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name); + +int unit_kill_context(Unit *u, KillContext *c, bool sigkill, pid_t main_pid, pid_t control_pid, bool main_pid_alien); + +int unit_make_transient(Unit *u); + +int unit_require_mounts_for(Unit *u, const char *path); + +const char *unit_active_state_to_string(UnitActiveState i) _const_; +UnitActiveState unit_active_state_from_string(const char *s) _pure_; + +const char *unit_dependency_to_string(UnitDependency i) _const_; +UnitDependency unit_dependency_from_string(const char *s) _pure_; + +/* Macros which append UNIT= or USER_UNIT= to the message */ + +#define log_full_unit(level, unit, ...) log_meta_object(level, __FILE__, __LINE__, __func__, getpid() == 1 ? "UNIT=" : "USER_UNIT=", unit, __VA_ARGS__) +#define log_debug_unit(unit, ...) log_full_unit(LOG_DEBUG, unit, __VA_ARGS__) +#define log_info_unit(unit, ...) log_full_unit(LOG_INFO, unit, __VA_ARGS__) +#define log_notice_unit(unit, ...) log_full_unit(LOG_NOTICE, unit, __VA_ARGS__) +#define log_warning_unit(unit, ...) log_full_unit(LOG_WARNING, unit, __VA_ARGS__) +#define log_error_unit(unit, ...) log_full_unit(LOG_ERR, unit, __VA_ARGS__) + +#define log_struct_unit(level, unit, ...) log_struct(level, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__) diff --git a/src/core/user.conf b/src/core/user.conf new file mode 100644 index 0000000..f19ac75 --- /dev/null +++ b/src/core/user.conf @@ -0,0 +1,40 @@ +# 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. +# +# See systemd-user.conf(5) for details + +[Manager] +#LogLevel=info +#LogTarget=console +#LogColor=yes +#LogLocation=no +#SystemCallArchitectures= +#TimerSlackNSec= +#DefaultStandardOutput=inherit +#DefaultStandardError=inherit +#DefaultTimeoutStartSec=90s +#DefaultTimeoutStopSec=90s +#DefaultRestartSec=100ms +#DefaultStartLimitInterval=10s +#DefaultStartLimitBurst=5 +#DefaultEnvironment= +#DefaultLimitCPU= +#DefaultLimitFSIZE= +#DefaultLimitDATA= +#DefaultLimitSTACK= +#DefaultLimitCORE= +#DefaultLimitRSS= +#DefaultLimitNOFILE= +#DefaultLimitAS= +#DefaultLimitNPROC= +#DefaultLimitMEMLOCK= +#DefaultLimitLOCKS= +#DefaultLimitSIGPENDING= +#DefaultLimitMSGQUEUE= +#DefaultLimitNICE= +#DefaultLimitRTPRIO= +#DefaultLimitRTTIME= diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c deleted file mode 100644 index 6f3aa78..0000000 --- a/src/cryptsetup-generator.c +++ /dev/null @@ -1,296 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "unit-name.h" - -const char *arg_dest = "/tmp"; - -static bool has_option(const char *haystack, const char *needle) { - const char *f = haystack; - size_t l; - - assert(needle); - - if (!haystack) - return false; - - l = strlen(needle); - - while ((f = strstr(f, needle))) { - - if (f > haystack && f[-1] != ',') { - f++; - continue; - } - - if (f[l] != 0 && f[l] != ',') { - f++; - continue; - } - - return true; - } - - return false; -} - -static int create_disk( - const char *name, - const char *device, - const char *password, - const char *options) { - - char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL; - int r; - FILE *f = NULL; - bool noauto, nofail; - - assert(name); - assert(device); - - noauto = has_option(options, "noauto"); - nofail = has_option(options, "nofail"); - - if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) { - r = -ENOMEM; - log_error("Failed to allocate unit name."); - goto fail; - } - - if (asprintf(&p, "%s/%s", arg_dest, n) < 0) { - r = -ENOMEM; - log_error("Failed to allocate unit file name."); - goto fail; - } - - if (!(u = fstab_node_to_udev_node(device))) { - r = -ENOMEM; - log_error("Failed to allocate device node."); - goto fail; - } - - if (!(d = unit_name_from_path(u, ".device"))) { - r = -ENOMEM; - log_error("Failed to allocate device name."); - goto fail; - } - - if (!(f = fopen(p, "wxe"))) { - r = -errno; - log_error("Failed to create unit file: %m"); - goto fail; - } - - fprintf(f, - "[Unit]\n" - "Description=Cryptography Setup for %%I\n" - "Conflicts=umount.target\n" - "DefaultDependencies=no\n" - "BindTo=%s dev-mapper-%%i.device\n" - "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n" - "Before=umount.target\n" - "Before=local-fs.target\n", - d, d); - - if (!nofail) - fprintf(f, - "Before=cryptsetup.target\n"); - - if (password && (streq(password, "/dev/urandom") || - streq(password, "/dev/random") || - streq(password, "/dev/hw_random"))) - fprintf(f, - "After=systemd-random-seed-load.service\n"); - - fprintf(f, - "\n[Service]\n" - "Type=oneshot\n" - "RemainAfterExit=yes\n" - "TimeoutSec=0\n" /* the binary handles timeouts anyway */ - "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n" - "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n", - name, u, strempty(password), strempty(options), - name); - - if (has_option(options, "tmp")) - fprintf(f, - "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n", - name); - - if (has_option(options, "swap")) - fprintf(f, - "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n", - name); - - fflush(f); - - if (ferror(f)) { - r = -errno; - log_error("Failed to write file: %m"); - goto fail; - } - - if (asprintf(&from, "../%s", n) < 0) { - r = -ENOMEM; - goto fail; - } - - if (!noauto) { - - if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) { - r = -ENOMEM; - goto fail; - } - - mkdir_parents(to, 0755); - - if (symlink(from, to) < 0) { - log_error("Failed to create symlink '%s' to '%s': %m", from, to); - r = -errno; - goto fail; - } - - free(to); - to = NULL; - - if (!nofail) - asprintf(&to, "%s/cryptsetup.target.requires/%s", arg_dest, n); - else - asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n); - - if (!to) { - r = -ENOMEM; - goto fail; - } - - mkdir_parents(to, 0755); - - if (symlink(from, to) < 0) { - log_error("Failed to create symlink '%s' to '%s': %m", from, to); - r = -errno; - goto fail; - } - } - - free(to); - to = NULL; - - e = unit_name_escape(name); - if (asprintf(&to, "%s/dev-mapper-%s.device.requires/%s", arg_dest, e, n) < 0) { - r = -ENOMEM; - goto fail; - } - - mkdir_parents(to, 0755); - - if (symlink(from, to) < 0) { - log_error("Failed to create symlink '%s' to '%s': %m", from, to); - r = -errno; - goto fail; - } - - r = 0; - -fail: - free(p); - free(n); - free(d); - free(e); - - free(from); - free(to); - - if (f) - fclose(f); - - return r; -} - -int main(int argc, char *argv[]) { - FILE *f; - int r = EXIT_SUCCESS; - unsigned n = 0; - - if (argc > 2) { - log_error("This program takes one or no arguments."); - return EXIT_FAILURE; - } - - if (argc > 1) - arg_dest = argv[1]; - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if (!(f = fopen("/etc/crypttab", "re"))) { - - if (errno == ENOENT) - r = EXIT_SUCCESS; - else { - r = EXIT_FAILURE; - log_error("Failed to open /etc/crypttab: %m"); - } - - goto finish; - } - - for (;;) { - char line[LINE_MAX], *l; - char *name = NULL, *device = NULL, *password = NULL, *options = NULL; - int k; - - if (!(fgets(line, sizeof(line), f))) - break; - - n++; - - l = strstrip(line); - if (*l == '#' || *l == 0) - continue; - - if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) { - log_error("Failed to parse /etc/crypttab:%u, ignoring.", n); - r = EXIT_FAILURE; - goto next; - } - - if (create_disk(name, device, password, options) < 0) - r = EXIT_FAILURE; - - next: - free(name); - free(device); - free(password); - free(options); - } - -finish: - return r; -} diff --git a/src/cryptsetup.c b/src/cryptsetup.c deleted file mode 100644 index ac7b6d6..0000000 --- a/src/cryptsetup.c +++ /dev/null @@ -1,529 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include -#include - -#include "log.h" -#include "util.h" -#include "strv.h" -#include "ask-password-api.h" -#include "def.h" - -static const char *opt_type = NULL; /* LUKS1 or PLAIN */ -static char *opt_cipher = NULL; -static unsigned opt_key_size = 0; -static char *opt_hash = NULL; -static unsigned opt_tries = 0; -static bool opt_readonly = false; -static bool opt_verify = false; -static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC; - -/* Options Debian's crypttab knows we don't: - - offset= - skip= - precheck= - check= - checkargs= - noearly= - loud= - keyscript= -*/ - -static int parse_one_option(const char *option) { - assert(option); - - /* Handled outside of this tool */ - if (streq(option, "noauto")) - return 0; - - if (startswith(option, "cipher=")) { - char *t; - - if (!(t = strdup(option+7))) - return -ENOMEM; - - free(opt_cipher); - opt_cipher = t; - - } else if (startswith(option, "size=")) { - - if (safe_atou(option+5, &opt_key_size) < 0) { - log_error("size= parse failure, ignoring."); - return 0; - } - - } else if (startswith(option, "hash=")) { - char *t; - - if (!(t = strdup(option+5))) - return -ENOMEM; - - free(opt_hash); - opt_hash = t; - - } else if (startswith(option, "tries=")) { - - if (safe_atou(option+6, &opt_tries) < 0) { - log_error("tries= parse failure, ignoring."); - return 0; - } - - } else if (streq(option, "readonly")) - opt_readonly = true; - else if (streq(option, "verify")) - opt_verify = true; - else if (streq(option, "luks")) - opt_type = CRYPT_LUKS1; - else if (streq(option, "plain") || - streq(option, "swap") || - streq(option, "tmp")) - opt_type = CRYPT_PLAIN; - else if (startswith(option, "timeout=")) { - - if (parse_usec(option+8, &opt_timeout) < 0) { - log_error("timeout= parse failure, ignoring."); - return 0; - } - - } else if (!streq(option, "none")) - log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option); - - return 0; -} - -static int parse_options(const char *options) { - char *state; - char *w; - size_t l; - - assert(options); - - FOREACH_WORD_SEPARATOR(w, l, options, ",", state) { - char *o; - int r; - - if (!(o = strndup(w, l))) - return -ENOMEM; - - r = parse_one_option(o); - free(o); - - if (r < 0) - return r; - } - - return 0; -} - -static void log_glue(int level, const char *msg, void *usrptr) { - log_debug("%s", msg); -} - -static char *disk_description(const char *path) { - struct udev *udev = NULL; - struct udev_device *device = NULL; - struct stat st; - char *description = NULL; - const char *model; - - assert(path); - - if (stat(path, &st) < 0) - return NULL; - - if (!S_ISBLK(st.st_mode)) - return NULL; - - if (!(udev = udev_new())) - return NULL; - - if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev))) - goto finish; - - if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) || - (model = udev_device_get_property_value(device, "ID_MODEL")) || - (model = udev_device_get_property_value(device, "DM_NAME"))) - description = strdup(model); - -finish: - if (device) - udev_device_unref(device); - - if (udev) - udev_unref(udev); - - return description; -} - -static char *disk_mount_point(const char *label) { - char *mp = NULL, *device = NULL; - FILE *f = NULL; - struct mntent *m; - - /* Yeah, we don't support native systemd unit files here for now */ - - if (asprintf(&device, "/dev/mapper/%s", label) < 0) - goto finish; - - if (!(f = setmntent("/etc/fstab", "r"))) - goto finish; - - while ((m = getmntent(f))) - if (path_equal(m->mnt_fsname, device)) { - mp = strdup(m->mnt_dir); - break; - } - -finish: - if (f) - endmntent(f); - - free(device); - - return mp; -} - -static int help(void) { - - printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n" - "%s detach VOLUME\n\n" - "Attaches or detaches an encrypted block device.\n", - program_invocation_short_name, - program_invocation_short_name); - - return 0; -} - -int main(int argc, char *argv[]) { - int r = EXIT_FAILURE; - struct crypt_device *cd = NULL; - char **passwords = NULL, *truncated_cipher = NULL; - const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL; - char *description = NULL, *name_buffer = NULL, *mount_point = NULL; - unsigned keyfile_size = 0; - - if (argc <= 1) { - help(); - return EXIT_SUCCESS; - } - - if (argc < 3) { - log_error("This program requires at least two arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (streq(argv[1], "attach")) { - uint32_t flags = 0; - int k; - unsigned try; - const char *key_file = NULL; - usec_t until; - crypt_status_info status; - - /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */ - - if (argc < 4) { - log_error("attach requires at least two arguments."); - goto finish; - } - - if (argc >= 5 && - argv[4][0] && - !streq(argv[4], "-") && - !streq(argv[4], "none")) { - - if (!path_is_absolute(argv[4])) - log_error("Password file path %s is not absolute. Ignoring.", argv[4]); - else - key_file = argv[4]; - } - - if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) - parse_options(argv[5]); - - /* A delicious drop of snake oil */ - mlockall(MCL_FUTURE); - - description = disk_description(argv[3]); - mount_point = disk_mount_point(argv[2]); - - if (description && streq(argv[2], description)) { - /* If the description string is simply the - * volume name, then let's not show this - * twice */ - free(description); - description = NULL; - } - - if (mount_point && description) - asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point); - else if (mount_point) - asprintf(&name_buffer, "%s on %s", argv[2], mount_point); - else if (description) - asprintf(&name_buffer, "%s (%s)", description, argv[2]); - - name = name_buffer ? name_buffer : argv[2]; - - if ((k = crypt_init(&cd, argv[3]))) { - log_error("crypt_init() failed: %s", strerror(-k)); - goto finish; - } - - crypt_set_log_callback(cd, log_glue, NULL); - - status = crypt_status(cd, argv[2]); - if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) { - log_info("Volume %s already active.", argv[2]); - r = EXIT_SUCCESS; - goto finish; - } - - if (opt_readonly) - flags |= CRYPT_ACTIVATE_READONLY; - - if (opt_timeout > 0) - until = now(CLOCK_MONOTONIC) + opt_timeout; - else - until = 0; - - opt_tries = opt_tries > 0 ? opt_tries : 3; - opt_key_size = (opt_key_size > 0 ? opt_key_size : 256); - hash = opt_hash ? opt_hash : "ripemd160"; - - if (opt_cipher) { - size_t l; - - l = strcspn(opt_cipher, "-"); - - if (!(truncated_cipher = strndup(opt_cipher, l))) { - log_error("Out of memory"); - goto finish; - } - - cipher = truncated_cipher; - cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain"; - } else { - cipher = "aes"; - cipher_mode = "cbc-essiv:sha256"; - } - - for (try = 0; try < opt_tries; try++) { - bool pass_volume_key = false; - - strv_free(passwords); - passwords = NULL; - - if (!key_file) { - char *text; - char **p; - - if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) { - log_error("Out of memory"); - goto finish; - } - - k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords); - free(text); - - if (k < 0) { - log_error("Failed to query password: %s", strerror(-k)); - goto finish; - } - - if (opt_verify) { - char **passwords2 = NULL; - - assert(strv_length(passwords) == 1); - - if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) { - log_error("Out of memory"); - goto finish; - } - - k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2); - free(text); - - if (k < 0) { - log_error("Failed to query verification password: %s", strerror(-k)); - goto finish; - } - - assert(strv_length(passwords2) == 1); - - if (!streq(passwords[0], passwords2[0])) { - log_warning("Passwords did not match, retrying."); - strv_free(passwords2); - continue; - } - - strv_free(passwords2); - } - - strv_uniq(passwords); - - STRV_FOREACH(p, passwords) { - char *c; - - if (strlen(*p)+1 >= opt_key_size) - continue; - - /* Pad password if necessary */ - if (!(c = new(char, opt_key_size))) { - log_error("Out of memory."); - goto finish; - } - - strncpy(c, *p, opt_key_size); - free(*p); - *p = c; - } - } - - k = 0; - - if (!opt_type || streq(opt_type, CRYPT_LUKS1)) - k = crypt_load(cd, CRYPT_LUKS1, NULL); - - if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) { - struct crypt_params_plain params; - - zero(params); - params.hash = hash; - - /* In contrast to what the name - * crypt_setup() might suggest this - * doesn't actually format anything, - * it just configures encryption - * parameters when used for plain - * mode. */ - k = crypt_format(cd, CRYPT_PLAIN, - cipher, - cipher_mode, - NULL, - NULL, - opt_key_size / 8, - ¶ms); - - pass_volume_key = streq(hash, "plain"); - - /* for CRYPT_PLAIN limit reads - * from keyfile to key length */ - keyfile_size = opt_key_size / 8; - } - - if (k < 0) { - log_error("Loading of cryptographic parameters failed: %s", strerror(-k)); - goto finish; - } - - log_info("Set cipher %s, mode %s, key size %i bits for device %s.", - crypt_get_cipher(cd), - crypt_get_cipher_mode(cd), - crypt_get_volume_key_size(cd)*8, - argv[3]); - - if (key_file) - k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags); - else { - char **p; - - STRV_FOREACH(p, passwords) { - - if (pass_volume_key) - k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags); - else - k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags); - - if (k >= 0) - break; - } - } - - if (k >= 0) - break; - - if (k != -EPERM) { - log_error("Failed to activate: %s", strerror(-k)); - goto finish; - } - - log_warning("Invalid passphrase."); - } - - if (try >= opt_tries) { - log_error("Too many attempts."); - r = EXIT_FAILURE; - goto finish; - } - - } else if (streq(argv[1], "detach")) { - int k; - - if ((k = crypt_init_by_name(&cd, argv[2]))) { - log_error("crypt_init() failed: %s", strerror(-k)); - goto finish; - } - - crypt_set_log_callback(cd, log_glue, NULL); - - if ((k = crypt_deactivate(cd, argv[2])) < 0) { - log_error("Failed to deactivate: %s", strerror(-k)); - goto finish; - } - - } else { - log_error("Unknown verb %s.", argv[1]); - goto finish; - } - - r = EXIT_SUCCESS; - -finish: - - if (cd) - crypt_free(cd); - - free(opt_cipher); - free(opt_hash); - - free(truncated_cipher); - - strv_free(passwords); - - free(description); - free(mount_point); - free(name_buffer); - - return r; -} diff --git a/src/cryptsetup/Makefile b/src/cryptsetup/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/cryptsetup/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c new file mode 100644 index 0000000..38c746b --- /dev/null +++ b/src/cryptsetup/cryptsetup-generator.c @@ -0,0 +1,553 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "unit-name.h" +#include "mkdir.h" +#include "strv.h" +#include "fileio.h" + +static const char *arg_dest = "/tmp"; +static bool arg_enabled = true; +static bool arg_read_crypttab = true; + +static char **arg_disks; +static char **arg_options; +static char *arg_keyfile; + + +static bool has_option(const char *haystack, const char *needle) { + const char *f = haystack; + size_t l; + + assert(needle); + + if (!haystack) + return false; + + l = strlen(needle); + + while ((f = strstr(f, needle))) { + + if (f > haystack && f[-1] != ',') { + f++; + continue; + } + + if (f[l] != 0 && f[l] != ',') { + f++; + continue; + } + + return true; + } + + return false; +} + +static int create_disk( + const char *name, + const char *device, + const char *password, + const char *options) { + + _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL; + _cleanup_fclose_ FILE *f = NULL; + bool noauto, nofail, tmp, swap; + + assert(name); + assert(device); + + noauto = has_option(options, "noauto"); + nofail = has_option(options, "nofail"); + tmp = has_option(options, "tmp"); + swap = has_option(options, "swap"); + + if (tmp && swap) { + log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name); + return -EINVAL; + } + + n = unit_name_from_path_instance("systemd-cryptsetup", name, ".service"); + if (!n) + return log_oom(); + + p = strjoin(arg_dest, "/", n, NULL); + if (!p) + return log_oom(); + + u = fstab_node_to_udev_node(device); + if (!u) + return log_oom(); + + d = unit_name_from_path(u, ".device"); + if (!d) + return log_oom(); + + f = fopen(p, "wxe"); + if (!f) { + log_error("Failed to create unit file %s: %m", p); + return -errno; + } + + fputs( + "# Automatically generated by systemd-cryptsetup-generator\n\n" + "[Unit]\n" + "Description=Cryptography Setup for %I\n" + "Documentation=man:systemd-cryptsetup@.service(8) man:crypttab(5)\n" + "SourcePath=/etc/crypttab\n" + "Conflicts=umount.target\n" + "DefaultDependencies=no\n" + "BindsTo=dev-mapper-%i.device\n" + "IgnoreOnIsolate=true\n" + "After=systemd-readahead-collect.service systemd-readahead-replay.service\n", + f); + + if (!nofail) + fprintf(f, + "Before=cryptsetup.target\n"); + + if (password) { + if (streq(password, "/dev/urandom") || + streq(password, "/dev/random") || + streq(password, "/dev/hw_random")) + fputs("After=systemd-random-seed.service\n", f); + + else if (!streq(password, "-") && !streq(password, "none")) { + _cleanup_free_ char *uu = fstab_node_to_udev_node(password); + if (uu == NULL) + return log_oom(); + + if (is_device_path(uu)) { + _cleanup_free_ char *dd = unit_name_from_path(uu, ".device"); + if (dd == NULL) + return log_oom(); + + fprintf(f, "After=%1$s\nRequires=%1$s\n", dd); + } else + fprintf(f, "RequiresMountsFor=%s\n", password); + } + } + + if (is_device_path(u)) + fprintf(f, + "BindsTo=%s\n" + "After=%s\n" + "Before=umount.target\n", + d, d); + else + fprintf(f, + "RequiresMountsFor=%s\n", + u); + + fprintf(f, + "\n[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + "TimeoutSec=0\n" /* the binary handles timeouts anyway */ + "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n" + "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n", + name, u, strempty(password), strempty(options), + name); + + if (tmp) + fprintf(f, + "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n", + name); + + if (swap) + fprintf(f, + "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n", + name); + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write file %s: %m", p); + return -errno; + } + + if (asprintf(&from, "../%s", n) < 0) + return log_oom(); + + if (!noauto) { + + to = strjoin(arg_dest, "/", d, ".wants/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + free(to); + if (!nofail) + to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL); + else + to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + } + + e = unit_name_escape(name); + if (!e) + return log_oom(); + + free(to); + to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + if (!noauto && !nofail) { + int r; + free(p); + p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL); + if (!p) + return log_oom(); + + mkdir_parents_label(p, 0755); + + r = write_string_file(p, + "# Automatically generated by systemd-cryptsetup-generator\n\n" + "[Unit]\n" + "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */ + if (r) + return r; + } + + return 0; +} + +static int parse_proc_cmdline_word(const char *word) { + int r; + + if (startswith(word, "luks=")) { + r = parse_boolean(word + 5); + if (r < 0) + log_warning("Failed to parse luks switch %s. Ignoring.", word + 5); + else + arg_enabled = r; + + } else if (startswith(word, "rd.luks=")) { + + if (in_initrd()) { + r = parse_boolean(word + 8); + if (r < 0) + log_warning("Failed to parse luks switch %s. Ignoring.", word + 8); + else + arg_enabled = r; + } + + } else if (startswith(word, "luks.crypttab=")) { + r = parse_boolean(word + 14); + if (r < 0) + log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14); + else + arg_read_crypttab = r; + + } else if (startswith(word, "rd.luks.crypttab=")) { + + if (in_initrd()) { + r = parse_boolean(word + 17); + if (r < 0) + log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17); + else + arg_read_crypttab = r; + } + + } else if (startswith(word, "luks.uuid=")) { + if (strv_extend(&arg_disks, word + 10) < 0) + return log_oom(); + + } else if (startswith(word, "rd.luks.uuid=")) { + + if (in_initrd()) { + if (strv_extend(&arg_disks, word + 13) < 0) + return log_oom(); + } + + } else if (startswith(word, "luks.options=")) { + if (strv_extend(&arg_options, word + 13) < 0) + return log_oom(); + + } else if (startswith(word, "rd.luks.options=")) { + + if (in_initrd()) { + if (strv_extend(&arg_options, word + 16) < 0) + return log_oom(); + } + + } else if (startswith(word, "luks.key=")) { + free(arg_keyfile); + arg_keyfile = strdup(word + 9); + if (!arg_keyfile) + return log_oom(); + + } else if (startswith(word, "rd.luks.key=")) { + + if (in_initrd()) { + free(arg_keyfile); + arg_keyfile = strdup(word + 12); + if (!arg_keyfile) + return log_oom(); + } + + } else if (startswith(word, "luks.") || + (in_initrd() && startswith(word, "rd.luks."))) { + + log_warning("Unknown kernel switch %s. Ignoring.", word); + } + + return 0; +} + +int main(int argc, char *argv[]) { + _cleanup_strv_free_ char **disks_done = NULL; + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + int r = EXIT_FAILURE, r2 = EXIT_FAILURE; + char **i; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[1]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (parse_proc_cmdline(parse_proc_cmdline_word) < 0) + goto cleanup; + + if (!arg_enabled) { + r = r2 = EXIT_SUCCESS; + goto cleanup; + } + + strv_uniq(arg_disks); + + if (arg_read_crypttab) { + struct stat st; + + f = fopen("/etc/crypttab", "re"); + if (!f) { + if (errno == ENOENT) + r = EXIT_SUCCESS; + else + log_error("Failed to open /etc/crypttab: %m"); + + goto next; + } + + if (fstat(fileno(f), &st) < 0) { + log_error("Failed to stat /etc/crypttab: %m"); + goto next; + } + + /* If we readd support for specifying passphrases + * directly in crypttabe we should upgrade the warning + * below, though possibly only if a passphrase is + * specified directly. */ + if (st.st_mode & 0005) + log_debug("/etc/crypttab is world-readable. This is usually not a good idea."); + + for (;;) { + char line[LINE_MAX], *l; + _cleanup_free_ char *name = NULL, *device = NULL, *password = NULL, *options = NULL; + int k; + + if (!fgets(line, sizeof(line), f)) + break; + + n++; + + l = strstrip(line); + if (*l == '#' || *l == 0) + continue; + + k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options); + if (k < 2 || k > 4) { + log_error("Failed to parse /etc/crypttab:%u, ignoring.", n); + continue; + } + + /* + If options are specified on the kernel commandline, let them override + the ones from crypttab. + */ + STRV_FOREACH(i, arg_options) { + _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL; + const char *p = *i; + + k = sscanf(p, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options); + if (k == 2 && streq(proc_uuid, device + 5)) { + free(options); + options = strdup(p); + if (!proc_options) { + log_oom(); + goto cleanup; + } + } + } + + if (arg_disks) { + /* + If luks UUIDs are specified on the kernel command line, use them as a filter + for /etc/crypttab and only generate units for those. + */ + STRV_FOREACH(i, arg_disks) { + _cleanup_free_ char *proc_device = NULL, *proc_name = NULL; + const char *p = *i; + + if (startswith(p, "luks-")) + p += 5; + + proc_name = strappend("luks-", p); + proc_device = strappend("UUID=", p); + + if (!proc_name || !proc_device) { + log_oom(); + goto cleanup; + } + + if (streq(proc_device, device) || streq(proc_name, name)) { + if (create_disk(name, device, password, options) < 0) + goto cleanup; + + if (strv_extend(&disks_done, p) < 0) { + log_oom(); + goto cleanup; + } + } + } + } else if (create_disk(name, device, password, options) < 0) + goto cleanup; + + } + } + + r = EXIT_SUCCESS; + +next: + STRV_FOREACH(i, arg_disks) { + /* + Generate units for those UUIDs, which were specified + on the kernel command line and not yet written. + */ + + _cleanup_free_ char *name = NULL, *device = NULL, *options = NULL; + const char *p = *i; + + if (startswith(p, "luks-")) + p += 5; + + if (strv_contains(disks_done, p)) + continue; + + name = strappend("luks-", p); + device = strappend("UUID=", p); + + if (!name || !device) { + log_oom(); + goto cleanup; + } + + if (arg_options) { + /* + If options are specified on the kernel commandline, use them. + */ + char **j; + + STRV_FOREACH(j, arg_options) { + _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL; + const char *s = *j; + int k; + + k = sscanf(s, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options); + if (k == 2) { + if (streq(proc_uuid, device + 5)) { + if (options) + free(options); + options = strdup(proc_options); + if (!options) { + log_oom(); + goto cleanup; + } + } + } else if (!options) { + /* + Fall back to options without a specified UUID + */ + options = strdup(s); + if (!options) { + log_oom(); + goto cleanup; + }; + } + } + } + + if (!options) { + options = strdup("timeout=0"); + if (!options) { + log_oom(); + goto cleanup; + } + } + + if (create_disk(name, device, arg_keyfile, options) < 0) + goto cleanup; + } + + r2 = EXIT_SUCCESS; + +cleanup: + strv_free(arg_disks); + strv_free(arg_options); + free(arg_keyfile); + + return r != EXIT_SUCCESS ? r : r2; +} diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c new file mode 100644 index 0000000..033c0cd --- /dev/null +++ b/src/cryptsetup/cryptsetup.c @@ -0,0 +1,652 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include + +#include "fileio.h" +#include "log.h" +#include "util.h" +#include "path-util.h" +#include "strv.h" +#include "ask-password-api.h" +#include "def.h" +#include "libudev.h" +#include "udev-util.h" + +static const char *opt_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */ +static char *opt_cipher = NULL; +static unsigned opt_key_size = 0; +static int opt_key_slot = CRYPT_ANY_SLOT; +static unsigned opt_keyfile_size = 0; +static unsigned opt_keyfile_offset = 0; +static char *opt_hash = NULL; +static unsigned opt_tries = 3; +static bool opt_readonly = false; +static bool opt_verify = false; +static bool opt_discards = false; +static bool opt_tcrypt_hidden = false; +static bool opt_tcrypt_system = false; +static char **opt_tcrypt_keyfiles = NULL; +static usec_t opt_timeout = 0; + +/* Options Debian's crypttab knows we don't: + + offset= + skip= + precheck= + check= + checkargs= + noearly= + loud= + keyscript= +*/ + +static int parse_one_option(const char *option) { + assert(option); + + /* Handled outside of this tool */ + if (streq(option, "noauto") || streq(option, "nofail")) + return 0; + + if (startswith(option, "cipher=")) { + char *t; + + t = strdup(option+7); + if (!t) + return log_oom(); + + free(opt_cipher); + opt_cipher = t; + + } else if (startswith(option, "size=")) { + + if (safe_atou(option+5, &opt_key_size) < 0) { + log_error("size= parse failure, ignoring."); + return 0; + } + + } else if (startswith(option, "key-slot=")) { + + opt_type = CRYPT_LUKS1; + if (safe_atoi(option+9, &opt_key_slot) < 0) { + log_error("key-slot= parse failure, ignoring."); + return 0; + } + + } else if (startswith(option, "tcrypt-keyfile=")) { + + opt_type = CRYPT_TCRYPT; + if (path_is_absolute(option+15)) { + if (strv_extend(&opt_tcrypt_keyfiles, option + 15) < 0) + return log_oom(); + } else + log_error("Key file path '%s' is not absolute. Ignoring.", option+15); + + } else if (startswith(option, "keyfile-size=")) { + + if (safe_atou(option+13, &opt_keyfile_size) < 0) { + log_error("keyfile-size= parse failure, ignoring."); + return 0; + } + + } else if (startswith(option, "keyfile-offset=")) { + + if (safe_atou(option+15, &opt_keyfile_offset) < 0) { + log_error("keyfile-offset= parse failure, ignoring."); + return 0; + } + + } else if (startswith(option, "hash=")) { + char *t; + + t = strdup(option+5); + if (!t) + return log_oom(); + + free(opt_hash); + opt_hash = t; + + } else if (startswith(option, "tries=")) { + + if (safe_atou(option+6, &opt_tries) < 0) { + log_error("tries= parse failure, ignoring."); + return 0; + } + + } else if (streq(option, "readonly") || streq(option, "read-only")) + opt_readonly = true; + else if (streq(option, "verify")) + opt_verify = true; + else if (streq(option, "allow-discards") || streq(option, "discard")) + opt_discards = true; + else if (streq(option, "luks")) + opt_type = CRYPT_LUKS1; + else if (streq(option, "tcrypt")) + opt_type = CRYPT_TCRYPT; + else if (streq(option, "tcrypt-hidden")) { + opt_type = CRYPT_TCRYPT; + opt_tcrypt_hidden = true; + } else if (streq(option, "tcrypt-system")) { + opt_type = CRYPT_TCRYPT; + opt_tcrypt_system = true; + } else if (streq(option, "plain") || + streq(option, "swap") || + streq(option, "tmp")) + opt_type = CRYPT_PLAIN; + else if (startswith(option, "timeout=")) { + + if (parse_sec(option+8, &opt_timeout) < 0) { + log_error("timeout= parse failure, ignoring."); + return 0; + } + + } else if (!streq(option, "none")) + log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option); + + return 0; +} + +static int parse_options(const char *options) { + char *state, *w; + size_t l; + int r; + + assert(options); + + FOREACH_WORD_SEPARATOR(w, l, options, ",", state) { + _cleanup_free_ char *o; + + o = strndup(w, l); + if (!o) + return -ENOMEM; + r = parse_one_option(o); + if (r < 0) + return r; + } + + return 0; +} + +static void log_glue(int level, const char *msg, void *usrptr) { + log_debug("%s", msg); +} + +static char* disk_description(const char *path) { + + static const char name_fields[] = { + "ID_PART_ENTRY_NAME\0" + "DM_NAME\0" + "ID_MODEL_FROM_DATABASE\0" + "ID_MODEL\0" + }; + + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + struct stat st; + const char *i; + + assert(path); + + if (stat(path, &st) < 0) + return NULL; + + if (!S_ISBLK(st.st_mode)) + return NULL; + + udev = udev_new(); + if (!udev) + return NULL; + + device = udev_device_new_from_devnum(udev, 'b', st.st_rdev); + if (!device) + return NULL; + + NULSTR_FOREACH(i, name_fields) { + const char *name; + + name = udev_device_get_property_value(device, i); + if (!isempty(name)) + return strdup(name); + } + + return NULL; +} + +static char *disk_mount_point(const char *label) { + _cleanup_free_ char *device = NULL; + _cleanup_endmntent_ FILE *f = NULL; + struct mntent *m; + + /* Yeah, we don't support native systemd unit files here for now */ + + if (asprintf(&device, "/dev/mapper/%s", label) < 0) + return NULL; + + f = setmntent("/etc/fstab", "r"); + if (!f) + return NULL; + + while ((m = getmntent(f))) + if (path_equal(m->mnt_fsname, device)) + return strdup(m->mnt_dir); + + return NULL; +} + +static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) { + int r; + char **p; + _cleanup_free_ char *text = NULL; + + assert(name); + assert(passwords); + + if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) + return log_oom(); + + r = ask_password_auto(text, "drive-harddisk", until, accept_cached, passwords); + if (r < 0) { + log_error("Failed to query password: %s", strerror(-r)); + return r; + } + + if (opt_verify) { + _cleanup_strv_free_ char **passwords2 = NULL; + + assert(strv_length(*passwords) == 1); + + if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) + return log_oom(); + + r = ask_password_auto(text, "drive-harddisk", until, false, &passwords2); + if (r < 0) { + log_error("Failed to query verification password: %s", strerror(-r)); + return r; + } + + assert(strv_length(passwords2) == 1); + + if (!streq(*passwords[0], passwords2[0])) { + log_warning("Passwords did not match, retrying."); + return -EAGAIN; + } + } + + strv_uniq(*passwords); + + STRV_FOREACH(p, *passwords) { + char *c; + + if (strlen(*p)+1 >= opt_key_size) + continue; + + /* Pad password if necessary */ + if (!(c = new(char, opt_key_size))) + return log_oom(); + + strncpy(c, *p, opt_key_size); + free(*p); + *p = c; + } + + return 0; +} + +static int attach_tcrypt(struct crypt_device *cd, + const char *name, + const char *key_file, + char **passwords, + uint32_t flags) { + int r = 0; + _cleanup_free_ char *passphrase = NULL; + struct crypt_params_tcrypt params = { + .flags = CRYPT_TCRYPT_LEGACY_MODES, + .keyfiles = (const char **)opt_tcrypt_keyfiles, + .keyfiles_count = strv_length(opt_tcrypt_keyfiles) + }; + + assert(cd); + assert(name); + assert(key_file || passwords); + + if (opt_tcrypt_hidden) + params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER; + + if (opt_tcrypt_system) + params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER; + + if (key_file) { + r = read_one_line_file(key_file, &passphrase); + if (r < 0) { + log_error("Failed to read password file '%s': %s", key_file, strerror(-r)); + return -EAGAIN; + } + + params.passphrase = passphrase; + } else + params.passphrase = passwords[0]; + params.passphrase_size = strlen(params.passphrase); + + r = crypt_load(cd, CRYPT_TCRYPT, ¶ms); + if (r < 0) { + if (key_file && r == -EPERM) { + log_error("Failed to activate using password file '%s'.", key_file); + return -EAGAIN; + } + return r; + } + + return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);; +} + +static int attach_luks_or_plain(struct crypt_device *cd, + const char *name, + const char *key_file, + char **passwords, + uint32_t flags) { + int r = 0; + bool pass_volume_key = false; + + assert(cd); + assert(name); + assert(key_file || passwords); + + if (!opt_type || streq(opt_type, CRYPT_LUKS1)) + r = crypt_load(cd, CRYPT_LUKS1, NULL); + + if ((!opt_type && r < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) { + struct crypt_params_plain params = {}; + const char *cipher, *cipher_mode; + _cleanup_free_ char *truncated_cipher = NULL; + + if (opt_hash) { + /* plain isn't a real hash type. it just means "use no hash" */ + if (!streq(opt_hash, "plain")) + params.hash = opt_hash; + } else + params.hash = "ripemd160"; + + if (opt_cipher) { + size_t l; + + l = strcspn(opt_cipher, "-"); + truncated_cipher = strndup(opt_cipher, l); + if (!truncated_cipher) + return log_oom(); + + cipher = truncated_cipher; + cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain"; + } else { + cipher = "aes"; + cipher_mode = "cbc-essiv:sha256"; + } + + /* for CRYPT_PLAIN limit reads + * from keyfile to key length, and + * ignore keyfile-size */ + opt_keyfile_size = opt_key_size / 8; + + /* In contrast to what the name + * crypt_setup() might suggest this + * doesn't actually format anything, + * it just configures encryption + * parameters when used for plain + * mode. */ + r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, + NULL, NULL, opt_keyfile_size, ¶ms); + + /* hash == NULL implies the user passed "plain" */ + pass_volume_key = (params.hash == NULL); + } + + if (r < 0) { + log_error("Loading of cryptographic parameters failed: %s", strerror(-r)); + return r; + } + + log_info("Set cipher %s, mode %s, key size %i bits for device %s.", + crypt_get_cipher(cd), + crypt_get_cipher_mode(cd), + crypt_get_volume_key_size(cd)*8, + crypt_get_device_name(cd)); + + if (key_file) { + r = crypt_activate_by_keyfile_offset(cd, name, opt_key_slot, + key_file, opt_keyfile_size, + opt_keyfile_offset, flags); + if (r < 0) { + log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r)); + return -EAGAIN; + } + } else { + char **p; + + STRV_FOREACH(p, passwords) { + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, *p, opt_key_size, flags); + else + r = crypt_activate_by_passphrase(cd, name, opt_key_slot, *p, strlen(*p), flags); + + if (r >= 0) + break; + } + } + + return r; +} + +static int help(void) { + + printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n" + "%s detach VOLUME\n\n" + "Attaches or detaches an encrypted block device.\n", + program_invocation_short_name, + program_invocation_short_name); + + return 0; +} + +int main(int argc, char *argv[]) { + int r = EXIT_FAILURE; + struct crypt_device *cd = NULL; + + if (argc <= 1) { + help(); + return EXIT_SUCCESS; + } + + if (argc < 3) { + log_error("This program requires at least two arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (streq(argv[1], "attach")) { + uint32_t flags = 0; + int k; + unsigned tries; + usec_t until; + crypt_status_info status; + const char *key_file = NULL, *name = NULL; + _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL; + + /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */ + + if (argc < 4) { + log_error("attach requires at least two arguments."); + goto finish; + } + + if (argc >= 5 && + argv[4][0] && + !streq(argv[4], "-") && + !streq(argv[4], "none")) { + + if (!path_is_absolute(argv[4])) + log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]); + else + key_file = argv[4]; + } + + if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) { + if (parse_options(argv[5]) < 0) + goto finish; + } + + /* A delicious drop of snake oil */ + mlockall(MCL_FUTURE); + + description = disk_description(argv[3]); + mount_point = disk_mount_point(argv[2]); + + if (description && streq(argv[2], description)) { + /* If the description string is simply the + * volume name, then let's not show this + * twice */ + free(description); + description = NULL; + } + + if (mount_point && description) + asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point); + else if (mount_point) + asprintf(&name_buffer, "%s on %s", argv[2], mount_point); + else if (description) + asprintf(&name_buffer, "%s (%s)", description, argv[2]); + + name = name_buffer ? name_buffer : argv[2]; + + k = crypt_init(&cd, argv[3]); + if (k) { + log_error("crypt_init() failed: %s", strerror(-k)); + goto finish; + } + + crypt_set_log_callback(cd, log_glue, NULL); + + status = crypt_status(cd, argv[2]); + if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) { + log_info("Volume %s already active.", argv[2]); + r = EXIT_SUCCESS; + goto finish; + } + + if (opt_readonly) + flags |= CRYPT_ACTIVATE_READONLY; + + if (opt_discards) + flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + + if (opt_timeout > 0) + until = now(CLOCK_MONOTONIC) + opt_timeout; + else + until = 0; + + opt_key_size = (opt_key_size > 0 ? opt_key_size : 256); + + if (key_file) { + struct stat st; + + /* Ideally we'd do this on the open fd, but since this is just a + * warning it's OK to do this in two steps. */ + if (stat(key_file, &st) >= 0 && (st.st_mode & 0005)) + log_warning("Key file %s is world-readable. This is not a good idea!", key_file); + } + + for (tries = 0; opt_tries == 0 || tries < opt_tries; tries++) { + _cleanup_strv_free_ char **passwords = NULL; + + if (!key_file) { + k = get_password(name, until, tries == 0 && !opt_verify, &passwords); + if (k == -EAGAIN) + continue; + else if (k < 0) + goto finish; + } + + if (streq_ptr(opt_type, CRYPT_TCRYPT)) + k = attach_tcrypt(cd, argv[2], key_file, passwords, flags); + else + k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags); + if (k >= 0) + break; + else if (k == -EAGAIN) { + key_file = NULL; + continue; + } else if (k != -EPERM) { + log_error("Failed to activate: %s", strerror(-k)); + goto finish; + } + + log_warning("Invalid passphrase."); + } + + if (opt_tries != 0 && tries >= opt_tries) { + log_error("Too many attempts; giving up."); + r = EXIT_FAILURE; + goto finish; + } + + } else if (streq(argv[1], "detach")) { + int k; + + k = crypt_init_by_name(&cd, argv[2]); + if (k) { + log_error("crypt_init() failed: %s", strerror(-k)); + goto finish; + } + + crypt_set_log_callback(cd, log_glue, NULL); + + k = crypt_deactivate(cd, argv[2]); + if (k < 0) { + log_error("Failed to deactivate: %s", strerror(-k)); + goto finish; + } + + } else { + log_error("Unknown verb %s.", argv[1]); + goto finish; + } + + r = EXIT_SUCCESS; + +finish: + + if (cd) + crypt_free(cd); + + free(opt_cipher); + free(opt_hash); + strv_free(opt_tcrypt_keyfiles); + + return r; +} diff --git a/src/dbus-automount.c b/src/dbus-automount.c deleted file mode 100644 index 8268425..0000000 --- a/src/dbus-automount.c +++ /dev/null @@ -1,57 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "dbus-unit.h" -#include "dbus-automount.h" -#include "dbus-common.h" - -#define BUS_AUTOMOUNT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_AUTOMOUNT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Automount\0" - -const char bus_automount_interface[] _introspect_("Automount") = BUS_AUTOMOUNT_INTERFACE; - -DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Automount", "Where", bus_property_append_string, "s", u->automount.where }, - { "org.freedesktop.systemd1.Automount", "DirectoryMode", bus_property_append_mode, "u", &u->automount.directory_mode }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-automount.h b/src/dbus-automount.h deleted file mode 100644 index 84b573c..0000000 --- a/src/dbus-automount.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusautomounthfoo -#define foodbusautomounthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_automount_interface[]; - -#endif diff --git a/src/dbus-common.c b/src/dbus-common.c deleted file mode 100644 index 40754e1..0000000 --- a/src/dbus-common.c +++ /dev/null @@ -1,1047 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "dbus-common.h" -#include "util.h" -#include "def.h" -#include "strv.h" - -int bus_check_peercred(DBusConnection *c) { - int fd; - struct ucred ucred; - socklen_t l; - - assert(c); - - assert_se(dbus_connection_get_unix_fd(c, &fd)); - - l = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) { - log_error("SO_PEERCRED failed: %m"); - return -errno; - } - - if (l != sizeof(struct ucred)) { - log_error("SO_PEERCRED returned wrong size."); - return -E2BIG; - } - - if (ucred.uid != 0 && ucred.uid != geteuid()) - return -EPERM; - - return 1; -} - -static int sync_auth(DBusConnection *bus, DBusError *error) { - usec_t begin, tstamp; - - assert(bus); - - /* This complexity should probably move into D-Bus itself: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */ - - begin = tstamp = now(CLOCK_MONOTONIC); - for (;;) { - - if (tstamp > begin + DEFAULT_TIMEOUT_USEC) - break; - - if (dbus_connection_get_is_authenticated(bus)) - break; - - if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC)) - break; - - tstamp = now(CLOCK_MONOTONIC); - } - - if (!dbus_connection_get_is_connected(bus)) { - dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication."); - return -ECONNREFUSED; - } - - if (!dbus_connection_get_is_authenticated(bus)) { - dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time."); - return -EACCES; - } - - return 0; -} - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) { - DBusConnection *bus = NULL; - int r; - bool private = true; - - assert(_bus); - - if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) { - /* If we are root, then let's talk directly to the - * system instance, instead of going via the bus */ - - bus = dbus_connection_open_private("unix:path=/run/systemd/private", error); - if (!bus) - return -EIO; - - } else { - if (t == DBUS_BUS_SESSION) { - const char *e; - - /* If we are supposed to talk to the instance, - * try via XDG_RUNTIME_DIR first, then - * fallback to normal bus access */ - - e = getenv("XDG_RUNTIME_DIR"); - if (e) { - char *p; - - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) - return -ENOMEM; - - bus = dbus_connection_open_private(p, NULL); - free(p); - } - } - - if (!bus) { - bus = dbus_bus_get_private(t, error); - if (!bus) - return -EIO; - - private = false; - } - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (private) { - if (bus_check_peercred(bus) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus."); - return -EACCES; - } - } - - r = sync_auth(bus, error); - if (r < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (_private) - *_private = private; - - *_bus = bus; - return 0; -} - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - char *p = NULL; - int r; - - assert(_bus); - assert(user || host); - - if (user && host) - asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host); - else if (user) - asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user); - else if (host) - asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host); - - if (!p) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return -ENOMEM; - } - - bus = dbus_connection_open_private(p, error); - free(p); - - if (!bus) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if ((r = sync_auth(bus, error)) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - int r; - - assert(_bus); - - /* Don't bother with PolicyKit if we are root */ - if (geteuid() == 0) - return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error); - - if (!(bus = dbus_connection_open_private("exec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error))) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if ((r = sync_auth(bus, error)) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -const char *bus_error_message(const DBusError *error) { - assert(error); - - /* Sometimes the D-Bus server is a little bit too verbose with - * its error messages, so let's override them here */ - if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED)) - return "Access denied"; - - return error->message; -} - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusProperty *properties) { - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(c); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) { - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) { - const char *interface, *property; - const BusProperty *p; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - for (p = properties; p->property; p++) - if (streq(p->interface, interface) && streq(p->property, property)) - break; - - if (p->property) { - DBusMessageIter iter, sub; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub)) - goto oom; - - if ((r = p->append(&sub, property, (void*) p->data)) < 0) { - - if (r == -ENOMEM) - goto oom; - - dbus_message_unref(reply); - return bus_send_error_reply(c, message, NULL, r); - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - } else { - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) { - const char *interface; - const BusProperty *p; - DBusMessageIter iter, sub, sub2, sub3; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - if (interface[0] && !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub)) - goto oom; - - for (p = properties; p->property; p++) { - if (interface[0] && !streq(p->interface, interface)) - continue; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3)) - goto oom; - - if ((r = p->append(&sub3, p->property, (void*) p->data)) < 0) { - - if (r == -ENOMEM) - goto oom; - - dbus_message_unref(reply); - return bus_send_error_reply(c, message, NULL, r); - } - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && properties) { - const char *interface, *property; - DBusMessageIter iter; - const BusProperty *p; - - if (!dbus_message_iter_init(message, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &interface); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &property); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT || - dbus_message_iter_has_next(&iter)) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - for (p = properties; p->property; p++) - if (streq(p->interface, interface) && streq(p->property, property)) - break; - - if (p->set) { - DBusMessageIter sub; - char *sig; - - dbus_message_iter_recurse(&iter, &sub); - - if (!(sig = dbus_message_iter_get_signature(&sub))) - goto oom; - - if (!streq(sig, p->signature)) { - dbus_free(sig); - return bus_send_error_reply(c, message, NULL, -EINVAL); - } - - dbus_free(sig); - - if ((r = p->set(&sub, property)) < 0) { - if (r == -ENOMEM) - goto oom; - return bus_send_error_reply(c, message, NULL, r); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - } else { - if (p->property) - dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only"); - else if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - } else { - const char *interface = dbus_message_get_interface(message); - - if (!interface || !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - } - - if (reply) { - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) { - const char *t = data; - - assert(i); - assert(property); - - if (!t) - t = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) { - char **t = data; - - assert(i); - assert(property); - - return bus_append_strv_iter(i, t); -} - -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) { - bool *b = data; - dbus_bool_t db; - - assert(i); - assert(property); - assert(b); - - db = *b; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that usec_t is actually 64bit, and hence this - * function can be used for usec_t */ - assert_cc(sizeof(uint64_t) == sizeof(usec_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually - * 32bit, and hence this function can be used for - * pid_t/mode_t/uid_t/gid_t */ - assert_cc(sizeof(uint32_t) == sizeof(pid_t)); - assert_cc(sizeof(uint32_t) == sizeof(mode_t)); - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - assert_cc(sizeof(uint32_t) == sizeof(uid_t)); - assert_cc(sizeof(uint32_t) == sizeof(gid_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - assert_cc(sizeof(int32_t) == sizeof(int)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(size_t*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(unsigned long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) { - int64_t l; - - assert(i); - assert(property); - assert(data); - - l = (int64_t) *(long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l)) - return -ENOMEM; - - return 0; -} - -const char *bus_errno_to_dbus(int error) { - - switch(error) { - - case -EINVAL: - return DBUS_ERROR_INVALID_ARGS; - - case -ENOMEM: - return DBUS_ERROR_NO_MEMORY; - - case -EPERM: - case -EACCES: - return DBUS_ERROR_ACCESS_DENIED; - - case -ESRCH: - return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN; - - case -ENOENT: - return DBUS_ERROR_FILE_NOT_FOUND; - - case -EEXIST: - return DBUS_ERROR_FILE_EXISTS; - - case -ETIMEDOUT: - case -ETIME: - return DBUS_ERROR_TIMEOUT; - - case -EIO: - return DBUS_ERROR_IO_ERROR; - - case -ENETRESET: - case -ECONNABORTED: - case -ECONNRESET: - return DBUS_ERROR_DISCONNECTED; - } - - return DBUS_ERROR_FAILED; -} - -DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) { - DBusMessage *reply = NULL; - const char *name, *text; - - if (berror && dbus_error_is_set(berror)) { - name = berror->name; - text = berror->message; - } else { - name = bus_errno_to_dbus(error); - text = strerror(-error); - } - - if (!(reply = dbus_message_new_error(message, name, text))) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) { - DBusMessage *m; - DBusMessageIter iter, sub; - const char *i; - - assert(interface); - assert(properties); - - if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"))) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - NULSTR_FOREACH(i, properties) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} - -uint32_t bus_flags_to_events(DBusWatch *bus_watch) { - unsigned flags; - uint32_t events = 0; - - assert(bus_watch); - - /* no watch flags for disabled watches */ - if (!dbus_watch_get_enabled(bus_watch)) - return 0; - - flags = dbus_watch_get_flags(bus_watch); - - if (flags & DBUS_WATCH_READABLE) - events |= EPOLLIN; - if (flags & DBUS_WATCH_WRITABLE) - events |= EPOLLOUT; - - return events | EPOLLHUP | EPOLLERR; -} - -unsigned bus_events_to_flags(uint32_t events) { - unsigned flags = 0; - - if (events & EPOLLIN) - flags |= DBUS_WATCH_READABLE; - if (events & EPOLLOUT) - flags |= DBUS_WATCH_WRITABLE; - if (events & EPOLLHUP) - flags |= DBUS_WATCH_HANGUP; - if (events & EPOLLERR) - flags |= DBUS_WATCH_ERROR; - - return flags; -} - -int bus_parse_strv(DBusMessage *m, char ***_l) { - DBusMessageIter iter; - - assert(m); - assert(_l); - - if (!dbus_message_iter_init(m, &iter)) - return -EINVAL; - - return bus_parse_strv_iter(&iter, _l); -} - -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) { - DBusMessageIter sub; - unsigned n = 0, i = 0; - char **l; - - assert(iter); - assert(_l); - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - n++; - dbus_message_iter_next(&sub); - } - - if (!(l = new(char*, n+1))) - return -ENOMEM; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - - if (!(l[i++] = strdup(s))) { - strv_free(l); - return -ENOMEM; - } - - dbus_message_iter_next(&sub); - } - - assert(i == n); - l[i] = NULL; - - if (_l) - *_l = l; - - return 0; -} - -int bus_append_strv_iter(DBusMessageIter *iter, char **l) { - DBusMessageIter sub; - - assert(iter); - - if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - STRV_FOREACH(l, l) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(iter, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) { - - assert(iter); - assert(data); - - if (dbus_message_iter_get_arg_type(iter) != type) - return -EIO; - - dbus_message_iter_get_basic(iter, data); - - if (!dbus_message_iter_next(iter) != !next) - return -EIO; - - return 0; -} - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { - assert(name); - assert(iter); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - dbus_message_iter_get_basic(iter, &s); - - if (all || !isempty(s)) - printf("%s=%s\n", name, s); - - return 1; - } - - case DBUS_TYPE_BOOLEAN: { - dbus_bool_t b; - - dbus_message_iter_get_basic(iter, &b); - printf("%s=%s\n", name, yes_no(b)); - - return 1; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - dbus_message_iter_get_basic(iter, &u); - - /* Yes, heuristics! But we can change this check - * should it turn out to not be sufficient */ - - if (endswith(name, "Timestamp")) { - char timestamp[FORMAT_TIMESTAMP_MAX], *t; - - t = format_timestamp(timestamp, sizeof(timestamp), u); - if (t || all) - printf("%s=%s\n", name, strempty(t)); - - } else if (strstr(name, "USec")) { - char timespan[FORMAT_TIMESPAN_MAX]; - - printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u)); - } else - printf("%s=%llu\n", name, (unsigned long long) u); - - return 1; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - dbus_message_iter_get_basic(iter, &u); - - if (strstr(name, "UMask") || strstr(name, "Mode")) - printf("%s=%04o\n", name, u); - else - printf("%s=%u\n", name, (unsigned) u); - - return 1; - } - - case DBUS_TYPE_INT32: { - int32_t i; - dbus_message_iter_get_basic(iter, &i); - - printf("%s=%i\n", name, (int) i); - return 1; - } - - case DBUS_TYPE_DOUBLE: { - double d; - dbus_message_iter_get_basic(iter, &d); - - printf("%s=%g\n", name, d); - return 1; - } - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { - DBusMessageIter sub; - bool space = false; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - printf("%s%s", space ? " " : "", s); - - space = true; - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - uint8_t u; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE); - dbus_message_iter_get_basic(&sub, &u); - printf("%02x", u); - - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - } - - break; - } - - return 0; -} - -static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusConnection *bus = userdata; - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - dbus_message_unref(reply); - - dbus_connection_close(bus); -} - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) { - DBusMessage *m = NULL; - DBusPendingCall *pending = NULL; - - assert(bus); - - /* We unregister the name here, but we continue to process - * requests, until we get the response for it, so that all - * requests are guaranteed to be processed. */ - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "ReleaseName"); - if (!m) - goto oom; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, - &name, - DBUS_TYPE_INVALID)) - goto oom; - - if (!dbus_connection_send_with_reply(bus, m, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL)) - goto oom; - - dbus_message_unref(m); - dbus_pending_call_unref(pending); - - return; - -oom: - log_error("Out of memory"); - - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } - - if (m) - dbus_message_unref(m); -} - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) { - usec_t *remain_until = userdata; - - assert(bus); - assert(m); - assert(remain_until); - - /* Everytime we get a new message we reset out timeout */ - *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - - if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) - dbus_connection_close(bus); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} diff --git a/src/dbus-common.h b/src/dbus-common.h deleted file mode 100644 index acd9208..0000000 --- a/src/dbus-common.h +++ /dev/null @@ -1,174 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbuscommonhfoo -#define foodbuscommonhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#ifndef DBUS_ERROR_UNKNOWN_OBJECT -#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_INTERFACE -#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_PROPERTY -#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" -#endif - -#ifndef DBUS_ERROR_PROPERTY_READ_ONLY -#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" -#endif - -#define BUS_PROPERTIES_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_INTROSPECTABLE_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_PEER_INTERFACE \ - "\n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - "\n" - -#define BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.DBus.Properties\0" \ - "org.freedesktop.DBus.Introspectable\0" \ - "org.freedesktop.DBus.Peer\0" - -int bus_check_peercred(DBusConnection *c); - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error); - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error); -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error); - -const char *bus_error_message(const DBusError *error); - -typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data); -typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property); - -typedef struct BusProperty { - const char *interface; /* interface of the property */ - const char *property; /* name of the property */ - BusPropertyCallback append; /* Function that is called to serialize this property */ - const char *signature; - const void *data; /* The data of this property */ - BusPropertySetCallback set; /* Optional: Function that is called to set this property */ -} BusProperty; - -DBusHandlerResult bus_send_error_reply( - DBusConnection *c, - DBusMessage *message, - DBusError *bus_error, - int error); - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusProperty *properties); - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data); - -#define bus_property_append_int bus_property_append_int32 -#define bus_property_append_pid bus_property_append_uint32 -#define bus_property_append_uid bus_property_append_uint32 -#define bus_property_append_gid bus_property_append_uint32 -#define bus_property_append_mode bus_property_append_uint32 -#define bus_property_append_unsigned bus_property_append_uint32 -#define bus_property_append_usec bus_property_append_uint64 - -#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \ - int function(DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type *field = data; \ - \ - assert(i); \ - assert(property); \ - \ - value = name##_to_string(*field); \ - \ - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \ - return -ENOMEM; \ - \ - return 0; \ - } - -const char *bus_errno_to_dbus(int error); - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties); - -uint32_t bus_flags_to_events(DBusWatch *bus_watch); -unsigned bus_events_to_flags(uint32_t events); - -int bus_parse_strv(DBusMessage *m, char ***_l); -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l); - -int bus_append_strv_iter(DBusMessageIter *iter, char **l); - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next); - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all); - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name); - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata); - -#endif diff --git a/src/dbus-device.c b/src/dbus-device.c deleted file mode 100644 index f85ad2d..0000000 --- a/src/dbus-device.c +++ /dev/null @@ -1,58 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "dbus-unit.h" -#include "dbus-device.h" -#include "dbus-common.h" - -#define BUS_DEVICE_INTERFACE \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_DEVICE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Device\0" - -const char bus_device_interface[] _introspect_("Device") = BUS_DEVICE_INTERFACE; - -const char bus_device_invalidating_properties[] = - "SysFSPath\0"; - -DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Device", "SysFSPath", bus_property_append_string, "s", u->device.sysfs }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-device.h b/src/dbus-device.h deleted file mode 100644 index fba270b..0000000 --- a/src/dbus-device.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusdevicehfoo -#define foodbusdevicehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_device_interface[]; -extern const char bus_device_invalidating_properties[]; - -#endif diff --git a/src/dbus-execute.c b/src/dbus-execute.c deleted file mode 100644 index 201f6b5..0000000 --- a/src/dbus-execute.c +++ /dev/null @@ -1,357 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "dbus-execute.h" -#include "missing.h" -#include "ioprio.h" -#include "strv.h" -#include "dbus-common.h" - -DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode); - -DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput); -DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput); - -int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) { - char **env_files = data, **j; - DBusMessageIter sub, sub2; - - assert(i); - assert(property); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub)) - return -ENOMEM; - - STRV_FOREACH(j, env_files) { - dbus_bool_t b = false; - char *fn = *j; - - if (fn[0] == '-') { - b = true; - fn++; - } - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int32_t n; - - assert(i); - assert(property); - assert(c); - - if (c->oom_score_adjust_set) - n = c->oom_score_adjust; - else { - char *t; - - n = 0; - if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) { - safe_atoi(t, &n); - free(t); - } else if (read_one_line_file("/proc/self/oom_adj", &t) >= 0) { - safe_atoi(t, &n); - free(t); - - if (n == OOM_ADJUST_MAX) - n = OOM_SCORE_ADJ_MAX; - else - n = (n * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; - } - } - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int32_t n; - - assert(i); - assert(property); - assert(c); - - if (c->nice_set) - n = c->nice; - else - n = getpriority(PRIO_PROCESS, 0); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int32_t n; - - assert(i); - assert(property); - assert(c); - - if (c->ioprio_set) - n = c->ioprio; - else - n = ioprio_get(IOPRIO_WHO_PROCESS, 0); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int32_t n; - - assert(i); - assert(property); - assert(c); - - if (c->cpu_sched_set) - n = c->cpu_sched_policy; - else - n = sched_getscheduler(0); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int32_t n; - - assert(i); - assert(property); - assert(c); - - if (c->cpu_sched_set) - n = c->cpu_sched_priority; - else { - struct sched_param p; - n = 0; - - zero(p); - if (sched_getparam(0, &p) >= 0) - n = p.sched_priority; - } - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - dbus_bool_t b; - DBusMessageIter sub; - - assert(i); - assert(property); - assert(c); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub)) - return -ENOMEM; - - if (c->cpuset) - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus)); - else - b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0); - - if (!b) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - uint64_t u; - - assert(i); - assert(property); - assert(c); - - if (c->timer_slack_nsec_set) - u = (uint64_t) c->timer_slack_nsec; - else - u = (uint64_t) prctl(PR_GET_TIMERSLACK); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - uint64_t normal, inverted; - - assert(i); - assert(property); - assert(c); - - /* We store this negated internally, to match the kernel, but - * we expose it normalized. */ - - normal = *(uint64_t*) data; - inverted = ~normal; - - return bus_property_append_uint64(i, property, &inverted); -} - -int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - char *t = NULL; - const char *s; - dbus_bool_t b; - - assert(i); - assert(property); - assert(c); - - if (c->capabilities) - s = t = cap_to_text(c->capabilities, NULL); - else - s = ""; - - if (!s) - return -ENOMEM; - - b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s); - - if (t) - cap_free(t); - - if (!b) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) { - ExecContext *c = data; - int r; - uint64_t u; - - assert(i); - assert(property); - assert(c); - - assert_se((r = rlimit_from_string(property)) >= 0); - - if (c->rlimit[r]) - u = (uint64_t) c->rlimit[r]->rlim_max; - else { - struct rlimit rl; - - zero(rl); - getrlimit(r, &rl); - - u = (uint64_t) rl.rlim_max; - } - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) { - ExecCommand *c = data; - DBusMessageIter sub, sub2, sub3; - - assert(i); - assert(property); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub)) - return -ENOMEM; - - LIST_FOREACH(command, c, c) { - char **l; - uint32_t pid; - int32_t code, status; - dbus_bool_t b; - - if (!c->path) - continue; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3)) - return -ENOMEM; - - STRV_FOREACH(l, c->argv) - if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l)) - return -ENOMEM; - - pid = (uint32_t) c->exec_status.pid; - code = (int32_t) c->exec_status.code; - status = (int32_t) c->exec_status.status; - - b = !!c->ignore; - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} diff --git a/src/dbus-execute.h b/src/dbus-execute.h deleted file mode 100644 index 2e30679..0000000 --- a/src/dbus-execute.h +++ /dev/null @@ -1,190 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusexecutehfoo -#define foodbusexecutehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "manager.h" - -#define BUS_EXEC_STATUS_INTERFACE(prefix) \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_EXEC_CONTEXT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_EXEC_COMMAND_INTERFACE(name) \ - " \n" - -#define BUS_EXEC_CONTEXT_PROPERTIES(interface, context) \ - { interface, "Environment", bus_property_append_strv, "as", (context).environment }, \ - { interface, "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", (context).environment_files }, \ - { interface, "UMask", bus_property_append_mode, "u", &(context).umask }, \ - { interface, "LimitCPU", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitFSIZE", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitDATA", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitSTACK", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitCORE", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitRSS", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitNOFILE", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitAS", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitNPROC", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitMEMLOCK", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitLOCKS", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitSIGPENDING", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitMSGQUEUE", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitNICE", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitRTPRIO", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "LimitRTTIME", bus_execute_append_rlimits, "t", &(context) }, \ - { interface, "WorkingDirectory", bus_property_append_string, "s", (context).working_directory }, \ - { interface, "RootDirectory", bus_property_append_string, "s", (context).root_directory }, \ - { interface, "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", &(context) }, \ - { interface, "Nice", bus_execute_append_nice, "i", &(context) }, \ - { interface, "IOScheduling", bus_execute_append_ioprio, "i", &(context) }, \ - { interface, "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", &(context) }, \ - { interface, "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", &(context) }, \ - { interface, "CPUAffinity", bus_execute_append_affinity,"ay", &(context) }, \ - { interface, "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", &(context) }, \ - { interface, "CPUSchedulingResetOnFork", bus_property_append_bool, "b", &(context).cpu_sched_reset_on_fork }, \ - { interface, "NonBlocking", bus_property_append_bool, "b", &(context).non_blocking }, \ - { interface, "StandardInput", bus_execute_append_input, "s", &(context).std_input }, \ - { interface, "StandardOutput", bus_execute_append_output, "s", &(context).std_output }, \ - { interface, "StandardError", bus_execute_append_output, "s", &(context).std_error }, \ - { interface, "TTYPath", bus_property_append_string, "s", (context).tty_path }, \ - { interface, "TTYReset", bus_property_append_bool, "b", &(context).tty_reset }, \ - { interface, "TTYVHangup", bus_property_append_bool, "b", &(context).tty_vhangup }, \ - { interface, "TTYVTDisallocate", bus_property_append_bool, "b", &(context).tty_vt_disallocate }, \ - { interface, "SyslogPriority", bus_property_append_int, "i", &(context).syslog_priority }, \ - { interface, "SyslogIdentifier", bus_property_append_string, "s", (context).syslog_identifier }, \ - { interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \ - { interface, "Capabilities", bus_execute_append_capabilities, "s",&(context) }, \ - { interface, "SecureBits", bus_property_append_int, "i", &(context).secure_bits }, \ - { interface, "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", &(context).capability_bounding_set_drop }, \ - { interface, "User", bus_property_append_string, "s", (context).user }, \ - { interface, "Group", bus_property_append_string, "s", (context).group }, \ - { interface, "SupplementaryGroups", bus_property_append_strv, "as", (context).supplementary_groups }, \ - { interface, "TCPWrapName", bus_property_append_string, "s", (context).tcpwrap_name }, \ - { interface, "PAMName", bus_property_append_string, "s", (context).pam_name }, \ - { interface, "ReadWriteDirectories", bus_property_append_strv, "as", (context).read_write_dirs }, \ - { interface, "ReadOnlyDirectories", bus_property_append_strv, "as", (context).read_only_dirs }, \ - { interface, "InaccessibleDirectories", bus_property_append_strv, "as", (context).inaccessible_dirs }, \ - { interface, "MountFlags", bus_property_append_ul, "t", &(context).mount_flags }, \ - { interface, "PrivateTmp", bus_property_append_bool, "b", &(context).private_tmp }, \ - { interface, "PrivateNetwork", bus_property_append_bool, "b", &(context).private_network }, \ - { interface, "SameProcessGroup", bus_property_append_bool, "b", &(context).same_pgrp }, \ - { interface, "KillMode", bus_execute_append_kill_mode, "s", &(context).kill_mode }, \ - { interface, "KillSignal", bus_property_append_int, "i", &(context).kill_signal }, \ - { interface, "UtmpIdentifier", bus_property_append_string, "s", (context).utmp_id }, \ - { interface, "ControlGroupModify", bus_property_append_bool, "b", &(context).control_group_modify } - -#define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix) \ - { interface, prefix "StartTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \ - { interface, prefix "StartTimestampMonotonic",bus_property_append_usec, "t", &(estatus).start_timestamp.monotonic }, \ - { interface, prefix "ExitTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \ - { interface, prefix "ExitTimestampMonotonic", bus_property_append_usec, "t", &(estatus).start_timestamp.monotonic }, \ - { interface, prefix "PID", bus_property_append_pid, "u", &(estatus).pid }, \ - { interface, prefix "Code", bus_property_append_int, "i", &(estatus).code }, \ - { interface, prefix "Status", bus_property_append_int, "i", &(estatus).status } - -#define BUS_EXEC_COMMAND_PROPERTY(interface, command, name) \ - { interface, name, bus_execute_append_command, "a(sasbttttuii)", (command) } - -int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); -int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data); - -#endif diff --git a/src/dbus-job.c b/src/dbus-job.c deleted file mode 100644 index 2308be3..0000000 --- a/src/dbus-job.c +++ /dev/null @@ -1,349 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus.h" -#include "log.h" -#include "dbus-job.h" -#include "dbus-common.h" - -#define BUS_JOB_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_JOB_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE; - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Job\0" - -#define INVALIDATING_PROPERTIES \ - "State\0" - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType); - -static int bus_job_append_unit(DBusMessageIter *i, const char *property, void *data) { - Job *j = data; - DBusMessageIter sub; - char *p; - - assert(i); - assert(property); - assert(j); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (!(p = unit_dbus_path(j->unit))) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->meta.id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) { - const BusProperty properties[] = { - { "org.freedesktop.systemd1.Job", "Id", bus_property_append_uint32, "u", &j->id }, - { "org.freedesktop.systemd1.Job", "State", bus_job_append_state, "s", &j->state }, - { "org.freedesktop.systemd1.Job", "JobType", bus_job_append_type, "s", &j->type }, - { "org.freedesktop.systemd1.Job", "Unit", bus_job_append_unit, "(so)", j }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL; - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) { - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - job_finish_and_invalidate(j, JOB_CANCELED); - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - Job *j; - int r; - DBusMessage *reply; - - assert(connection); - assert(message); - assert(m); - - if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) { - /* Be nice to gdbus and return introspection data for our mid-level paths */ - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; - FILE *f; - Iterator i; - size_t size; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ - - if (!(f = open_memstream(&introspection, &size))) - goto oom; - - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", f); - - fputs(BUS_INTROSPECTABLE_INTERFACE, f); - fputs(BUS_PEER_INTERFACE, f); - - HASHMAP_FOREACH(j, m->jobs, i) - fprintf(f, "", (unsigned long) j->id); - - fputs("\n", f); - - if (ferror(f)) { - fclose(f); - free(introspection); - goto oom; - } - - fclose(f); - - if (!introspection) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); - goto oom; - } - - free(introspection); - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if ((r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j)) < 0) { - - if (r == -ENOMEM) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job"); - return bus_send_error_reply(connection, message, &e, r); - } - - return bus_send_error_reply(connection, message, NULL, r); - } - - return bus_job_message_dispatch(j, connection, message); - -oom: - if (reply) - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -const DBusObjectPathVTable bus_job_vtable = { - .message_function = bus_job_message_handler -}; - -static int job_send_message(Job *j, DBusMessage *m) { - int r; - - assert(j); - assert(m); - - if (bus_has_subscriber(j->manager)) { - if ((r = bus_broadcast(j->manager, m)) < 0) - return r; - - } else if (j->bus_client) { - /* If nobody is subscribed, we just send the message - * to the client which created the job */ - - assert(j->bus); - - if (!dbus_message_set_destination(m, j->bus_client)) - return -ENOMEM; - - if (!dbus_connection_send(j->bus, m, NULL)) - return -ENOMEM; - } - - return 0; -} - -void bus_job_send_change_signal(Job *j) { - char *p = NULL; - DBusMessage *m = NULL; - - assert(j); - - if (j->in_dbus_queue) { - LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j); - j->in_dbus_queue = false; - } - - if (!bus_has_subscriber(j->manager) && !j->bus_client) { - j->sent_dbus_new_signal = true; - return; - } - - if (!(p = job_dbus_path(j))) - goto oom; - - if (j->sent_dbus_new_signal) { - /* Send a properties changed signal */ - - if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES))) - goto oom; - - } else { - /* Send a new signal */ - - if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew"))) - goto oom; - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &j->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto oom; - } - - if (job_send_message(j, m) < 0) - goto oom; - - free(p); - dbus_message_unref(m); - - j->sent_dbus_new_signal = true; - - return; - -oom: - free(p); - - if (m) - dbus_message_unref(m); - - log_error("Failed to allocate job change signal."); -} - -void bus_job_send_removed_signal(Job *j) { - char *p = NULL; - DBusMessage *m = NULL; - const char *r; - - assert(j); - - if (!bus_has_subscriber(j->manager) && !j->bus_client) - return; - - if (!j->sent_dbus_new_signal) - bus_job_send_change_signal(j); - - if (!(p = job_dbus_path(j))) - goto oom; - - if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved"))) - goto oom; - - r = job_result_to_string(j->result); - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &j->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_STRING, &r, - DBUS_TYPE_INVALID)) - goto oom; - - if (job_send_message(j, m) < 0) - goto oom; - - free(p); - dbus_message_unref(m); - - return; - -oom: - free(p); - - if (m) - dbus_message_unref(m); - - log_error("Failed to allocate job remove signal."); -} diff --git a/src/dbus-job.h b/src/dbus-job.h deleted file mode 100644 index 103c2ff..0000000 --- a/src/dbus-job.h +++ /dev/null @@ -1,36 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusjobhfoo -#define foodbusjobhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "job.h" - -void bus_job_send_change_signal(Job *j); -void bus_job_send_removed_signal(Job *j); - -extern const DBusObjectPathVTable bus_job_vtable; - -extern const char bus_job_interface[]; - -#endif diff --git a/src/dbus-loop.c b/src/dbus-loop.c deleted file mode 100644 index 8eb1d17..0000000 --- a/src/dbus-loop.c +++ /dev/null @@ -1,263 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "dbus-loop.h" -#include "dbus-common.h" -#include "util.h" - -/* Minimal implementation of the dbus loop which integrates all dbus - * events into a single epoll fd which we can triviall integrate with - * other loops. Note that this is not used in the main systemd daemon - * since we run a more elaborate mainloop there. */ - -typedef struct EpollData { - int fd; - void *object; - bool is_timeout:1; - bool fd_is_dupped:1; -} EpollData; - -static dbus_bool_t add_watch(DBusWatch *watch, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(watch); - - e = new0(EpollData, 1); - if (!e) - return FALSE; - - e->fd = dbus_watch_get_unix_fd(watch); - e->object = watch; - e->is_timeout = false; - - zero(ev); - ev.events = bus_flags_to_events(watch); - ev.data.ptr = e; - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) { - - if (errno != EEXIST) { - free(e); - return FALSE; - } - - /* Hmm, bloody D-Bus creates multiple watches on the - * same fd. epoll() does not like that. As a dirty - * hack we simply dup() the fd and hence get a second - * one we can safely add to the epoll(). */ - - e->fd = dup(e->fd); - if (e->fd < 0) { - free(e); - return FALSE; - } - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) { - close_nointr_nofail(e->fd); - free(e); - return FALSE; - } - - e->fd_is_dupped = true; - } - - dbus_watch_set_data(watch, e, NULL); - - return TRUE; -} - -static void remove_watch(DBusWatch *watch, void *data) { - EpollData *e; - - assert(watch); - - e = dbus_watch_get_data(watch); - if (!e) - return; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0); - - if (e->fd_is_dupped) - close_nointr_nofail(e->fd); - - free(e); -} - -static void toggle_watch(DBusWatch *watch, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(watch); - - e = dbus_watch_get_data(watch); - if (!e) - return; - - zero(ev); - ev.events = bus_flags_to_events(watch); - ev.data.ptr = e; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_MOD, e->fd, &ev) == 0); -} - -static int timeout_arm(EpollData *e) { - struct itimerspec its; - - assert(e); - assert(e->is_timeout); - - zero(its); - - if (dbus_timeout_get_enabled(e->object)) { - timespec_store(&its.it_value, dbus_timeout_get_interval(e->object) * USEC_PER_MSEC); - its.it_interval = its.it_value; - } - - if (timerfd_settime(e->fd, 0, &its, NULL) < 0) - return -errno; - - return 0; -} - -static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(timeout); - - e = new0(EpollData, 1); - if (!e) - return FALSE; - - e->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); - if (e->fd < 0) - goto fail; - - e->object = timeout; - e->is_timeout = true; - - if (timeout_arm(e) < 0) - goto fail; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = e; - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) - goto fail; - - dbus_timeout_set_data(timeout, e, NULL); - - return TRUE; - -fail: - if (e->fd >= 0) - close_nointr_nofail(e->fd); - - free(e); - return FALSE; -} - -static void remove_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - - assert(timeout); - - e = dbus_timeout_get_data(timeout); - if (!e) - return; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0); - close_nointr_nofail(e->fd); - free(e); -} - -static void toggle_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - int r; - - assert(timeout); - - e = dbus_timeout_get_data(timeout); - if (!e) - return; - - r = timeout_arm(e); - if (r < 0) - log_error("Failed to rearm timer: %s", strerror(-r)); -} - -int bus_loop_open(DBusConnection *c) { - int fd; - - assert(c); - - fd = epoll_create1(EPOLL_CLOEXEC); - if (fd < 0) - return -errno; - - if (!dbus_connection_set_watch_functions(c, add_watch, remove_watch, toggle_watch, INT_TO_PTR(fd), NULL) || - !dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, toggle_timeout, INT_TO_PTR(fd), NULL)) { - close_nointr_nofail(fd); - return -ENOMEM; - } - - return fd; -} - -int bus_loop_dispatch(int fd) { - int n; - struct epoll_event event; - EpollData *d; - - assert(fd >= 0); - - zero(event); - - n = epoll_wait(fd, &event, 1, 0); - if (n < 0) - return errno == EAGAIN || errno == EINTR ? 0 : -errno; - - assert_se(d = event.data.ptr); - - if (d->is_timeout) { - DBusTimeout *t = d->object; - - if (dbus_timeout_get_enabled(t)) - dbus_timeout_handle(t); - } else { - DBusWatch *w = d->object; - - if (dbus_watch_get_enabled(w)) - dbus_watch_handle(w, bus_events_to_flags(event.events)); - } - - return 0; -} diff --git a/src/dbus-loop.h b/src/dbus-loop.h deleted file mode 100644 index 0bbdfe5..0000000 --- a/src/dbus-loop.h +++ /dev/null @@ -1,30 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusloophfoo -#define foodbusloophfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -int bus_loop_open(DBusConnection *c); -int bus_loop_dispatch(int fd); - -#endif diff --git a/src/dbus-manager.c b/src/dbus-manager.c deleted file mode 100644 index 7b68156..0000000 --- a/src/dbus-manager.c +++ /dev/null @@ -1,1525 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "dbus.h" -#include "log.h" -#include "dbus-manager.h" -#include "strv.h" -#include "bus-errors.h" -#include "build.h" -#include "dbus-common.h" -#include "install.h" - -#define BUS_MANAGER_INTERFACE_BEGIN \ - " \n" - -#define BUS_MANAGER_INTERFACE_METHODS \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_MANAGER_INTERFACE_SIGNALS \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " " \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " " \ - " \n" - -#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#ifdef HAVE_SYSV_COMPAT -#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \ - " \n" \ - " \n" \ - " \n" -#else -#define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV -#endif - -#define BUS_MANAGER_INTERFACE_END \ - " \n" - -#define BUS_MANAGER_INTERFACE \ - BUS_MANAGER_INTERFACE_BEGIN \ - BUS_MANAGER_INTERFACE_METHODS \ - BUS_MANAGER_INTERFACE_SIGNALS \ - BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \ - BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \ - BUS_MANAGER_INTERFACE_END - -#define INTROSPECTION_BEGIN \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_MANAGER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE - -#define INTROSPECTION_END \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Manager\0" - -const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput); - -static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) { - const char *t; - Manager *m = data; - char buf[LINE_MAX] = "", *e = buf, *p = NULL; - - assert(i); - assert(property); - assert(m); - - if (m->taint_usr) - e = stpcpy(e, "usr-separate-fs "); - - if (readlink_malloc("/etc/mtab", &p) < 0) - e = stpcpy(e, "etc-mtab-not-symlink "); - else - free(p); - - if (access("/proc/cgroups", F_OK) < 0) - stpcpy(e, "cgroups-missing "); - - t = strstrip(buf); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) { - const char *t; - - assert(i); - assert(property); - - t = log_target_to_string(log_get_target()); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_set_log_target(DBusMessageIter *i, const char *property) { - const char *t; - - assert(i); - assert(property); - - dbus_message_iter_get_basic(i, &t); - - return log_set_target_from_string(t); -} - -static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) { - const char *t; - - assert(i); - assert(property); - - t = log_level_to_string(log_get_max_level()); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_set_log_level(DBusMessageIter *i, const char *property) { - const char *t; - - assert(i); - assert(property); - - dbus_message_iter_get_basic(i, &t); - - return log_set_max_level_from_string(t); -} - -static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - uint32_t u; - - assert(i); - assert(property); - assert(m); - - u = hashmap_size(m->units); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - uint32_t u; - - assert(i); - assert(property); - assert(m); - - u = hashmap_size(m->jobs); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) { - double d; - Manager *m = data; - - assert(i); - assert(property); - assert(m); - - if (dual_timestamp_is_set(&m->finish_timestamp)) - d = 1.0; - else - d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d)) - return -ENOMEM; - - return 0; -} - -static const char *message_get_sender_with_fallback(DBusMessage *m) { - const char *s; - - assert(m); - - if ((s = dbus_message_get_sender(m))) - return s; - - /* When the message came in from a direct connection the - * message will have no sender. We fix that here. */ - - return ":no-sender"; -} - -static DBusMessage *message_from_file_changes( - DBusMessage *m, - UnitFileChange *changes, - unsigned n_changes, - int carries_install_info) { - - DBusMessageIter iter, sub, sub2; - DBusMessage *reply; - unsigned i; - - reply = dbus_message_new_method_return(m); - if (!reply) - return NULL; - - dbus_message_iter_init_append(reply, &iter); - - if (carries_install_info >= 0) { - dbus_bool_t b; - - b = !!carries_install_info; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) - goto oom; - } - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub)) - goto oom; - - for (i = 0; i < n_changes; i++) { - const char *type, *path, *source; - - type = unit_file_change_type_to_string(changes[i].type); - path = strempty(changes[i].path); - source = strempty(changes[i].source); - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return reply; - -oom: - dbus_message_unref(reply); - return NULL; -} - -static int bus_manager_send_unit_files_changed(Manager *m) { - DBusMessage *s; - int r; - - s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged"); - if (!s) - return -ENOMEM; - - r = bus_broadcast(m, s); - dbus_message_unref(s); - - return r; -} - -static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - - const BusProperty properties[] = { - { "org.freedesktop.systemd1.Manager", "Version", bus_property_append_string, "s", PACKAGE_STRING }, - { "org.freedesktop.systemd1.Manager", "Distribution", bus_property_append_string, "s", DISTRIBUTION }, - { "org.freedesktop.systemd1.Manager", "Features", bus_property_append_string, "s", SYSTEMD_FEATURES }, - { "org.freedesktop.systemd1.Manager", "RunningAs", bus_manager_append_running_as, "s", &m->running_as }, - { "org.freedesktop.systemd1.Manager", "Tainted", bus_manager_append_tainted, "s", m }, - { "org.freedesktop.systemd1.Manager", "InitRDTimestamp", bus_property_append_uint64, "t", &m->initrd_timestamp.realtime }, - { "org.freedesktop.systemd1.Manager", "InitRDTimestampMonotonic", bus_property_append_uint64, "t", &m->initrd_timestamp.monotonic }, - { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t", &m->startup_timestamp.realtime }, - { "org.freedesktop.systemd1.Manager", "StartupTimestampMonotonic", bus_property_append_uint64, "t", &m->startup_timestamp.monotonic }, - { "org.freedesktop.systemd1.Manager", "FinishTimestamp", bus_property_append_uint64, "t", &m->finish_timestamp.realtime }, - { "org.freedesktop.systemd1.Manager", "FinishTimestampMonotonic", bus_property_append_uint64, "t",&m->finish_timestamp.monotonic }, - { "org.freedesktop.systemd1.Manager", "LogLevel", bus_manager_append_log_level, "s", m, bus_manager_set_log_level }, - { "org.freedesktop.systemd1.Manager", "LogTarget", bus_manager_append_log_target, "s", m, bus_manager_set_log_target }, - { "org.freedesktop.systemd1.Manager", "NNames", bus_manager_append_n_names, "u", m }, - { "org.freedesktop.systemd1.Manager", "NJobs", bus_manager_append_n_jobs, "u", m }, - { "org.freedesktop.systemd1.Manager", "NInstalledJobs",bus_property_append_uint32, "u", &m->n_installed_jobs }, - { "org.freedesktop.systemd1.Manager", "NFailedJobs", bus_property_append_uint32, "u", &m->n_failed_jobs }, - { "org.freedesktop.systemd1.Manager", "Progress", bus_manager_append_progress, "d", m }, - { "org.freedesktop.systemd1.Manager", "Environment", bus_property_append_strv, "as", m->environment }, - { "org.freedesktop.systemd1.Manager", "ConfirmSpawn", bus_property_append_bool, "b", &m->confirm_spawn }, - { "org.freedesktop.systemd1.Manager", "ShowStatus", bus_property_append_bool, "b", &m->show_status }, - { "org.freedesktop.systemd1.Manager", "UnitPath", bus_property_append_strv, "as", m->lookup_paths.unit_path }, - { "org.freedesktop.systemd1.Manager", "NotifySocket", bus_property_append_string, "s", m->notify_socket }, - { "org.freedesktop.systemd1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_hierarchy }, - { "org.freedesktop.systemd1.Manager", "MountAuto", bus_property_append_bool, "b", &m->mount_auto }, - { "org.freedesktop.systemd1.Manager", "SwapAuto", bus_property_append_bool, "b", &m->swap_auto }, - { "org.freedesktop.systemd1.Manager", "DefaultControllers", bus_property_append_strv, "as", m->default_controllers }, - { "org.freedesktop.systemd1.Manager", "DefaultStandardOutput", bus_manager_append_exec_output, "s", &m->default_std_output }, - { "org.freedesktop.systemd1.Manager", "DefaultStandardError", bus_manager_append_exec_output, "s", &m->default_std_error }, -#ifdef HAVE_SYSV_COMPAT - { "org.freedesktop.systemd1.Manager", "SysVConsole", bus_property_append_bool, "b", &m->sysv_console }, - { "org.freedesktop.systemd1.Manager", "SysVInitPath", bus_property_append_strv, "as", m->lookup_paths.sysvinit_path }, - { "org.freedesktop.systemd1.Manager", "SysVRcndPath", bus_property_append_strv, "as", m->lookup_paths.sysvrcnd_path }, -#endif - { NULL, NULL, NULL, NULL, NULL } - }; - - int r; - DBusError error; - DBusMessage *reply = NULL; - char * path = NULL; - JobType job_type = _JOB_TYPE_INVALID; - bool reload_if_possible = false; - const char *member; - - assert(connection); - assert(message); - assert(m); - - dbus_error_init(&error); - - member = dbus_message_get_member(message); - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) { - const char *name; - Unit *u; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!(u = manager_get_unit(m, name))) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = unit_dbus_path(u))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) { - Unit *u; - uint32_t pid; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = unit_dbus_path(u))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) { - const char *name; - Unit *u; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = unit_dbus_path(u))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit")) - job_type = JOB_STOP; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit")) - job_type = JOB_RELOAD; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit")) - job_type = JOB_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit")) - job_type = JOB_TRY_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) { - reload_if_possible = true; - job_type = JOB_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) { - reload_if_possible = true; - job_type = JOB_TRY_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) { - const char *name, *swho, *smode; - int32_t signo; - Unit *u; - KillMode mode; - KillWho who; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (isempty(smode)) - mode = KILL_CONTROL_GROUP; - else { - mode = kill_mode_from_string(smode); - if (mode < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!(u = manager_get_unit(m, name))) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - if ((r = unit_kill(u, who, mode, signo, &error)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) { - uint32_t id; - Job *j; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!(j = manager_get_job(m, id))) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = job_dbus_path(j))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) { - - manager_clear_jobs(m); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) { - - manager_reset_failed(m); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) { - const char *name; - Unit *u; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!(u = manager_get_unit(m, name))) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - unit_reset_failed(u); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) { - DBusMessageIter iter, sub; - Iterator i; - Unit *u; - const char *k; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub)) - goto oom; - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *u_path, *j_path; - const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following; - DBusMessageIter sub2; - uint32_t job_id; - Unit *f; - - if (k != u->meta.id) - continue; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - description = unit_description(u); - load_state = unit_load_state_to_string(u->meta.load_state); - active_state = unit_active_state_to_string(unit_active_state(u)); - sub_state = unit_sub_state_to_string(u); - - f = unit_following(u); - following = f ? f->meta.id : ""; - - if (!(u_path = unit_dbus_path(u))) - goto oom; - - if (u->meta.job) { - job_id = (uint32_t) u->meta.job->id; - - if (!(j_path = job_dbus_path(u->meta.job))) { - free(u_path); - goto oom; - } - - sjob_type = job_type_to_string(u->meta.job->type); - } else { - job_id = 0; - j_path = u_path; - sjob_type = ""; - } - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) { - free(u_path); - if (u->meta.job) - free(j_path); - goto oom; - } - - free(u_path); - if (u->meta.job) - free(j_path); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) { - DBusMessageIter iter, sub; - Iterator i; - Job *j; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub)) - goto oom; - - HASHMAP_FOREACH(j, m->jobs, i) { - char *u_path, *j_path; - const char *state, *type; - uint32_t id; - DBusMessageIter sub2; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - id = (uint32_t) j->id; - state = job_state_to_string(j->state); - type = job_type_to_string(j->type); - - if (!(j_path = job_dbus_path(j))) - goto oom; - - if (!(u_path = unit_dbus_path(j->unit))) { - free(j_path); - goto oom; - } - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) { - free(j_path); - free(u_path); - goto oom; - } - - free(j_path); - free(u_path); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) { - char *client; - Set *s; - - if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) { - if (!(s = set_new(string_hash_func, string_compare_func))) - goto oom; - - if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) { - set_free(s); - goto oom; - } - } - - if (!(client = strdup(message_get_sender_with_fallback(message)))) - goto oom; - - if ((r = set_put(s, client)) < 0) { - free(client); - return bus_send_error_reply(connection, message, NULL, r); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) { - char *client; - - if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) { - dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed."); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - free(client); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) { - FILE *f; - char *dump = NULL; - size_t size; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(f = open_memstream(&dump, &size))) - goto oom; - - manager_dump_units(m, f, NULL); - manager_dump_jobs(m, f, NULL); - - if (ferror(f)) { - fclose(f); - free(dump); - goto oom; - } - - fclose(f); - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) { - free(dump); - goto oom; - } - - free(dump); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) { - const char *name; - dbus_bool_t cleanup; - Snapshot *s; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &cleanup, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (name && name[0] == 0) - name = NULL; - - if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = unit_dbus_path(UNIT(s)))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; - FILE *f; - Iterator i; - Unit *u; - Job *j; - const char *k; - size_t size; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ - - if (!(f = open_memstream(&introspection, &size))) - goto oom; - - fputs(INTROSPECTION_BEGIN, f); - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *p; - - if (k != u->meta.id) - continue; - - if (!(p = bus_path_escape(k))) { - fclose(f); - free(introspection); - goto oom; - } - - fprintf(f, "", p); - free(p); - } - - HASHMAP_FOREACH(j, m->jobs, i) - fprintf(f, "", (unsigned long) j->id); - - fputs(INTROSPECTION_END, f); - - if (ferror(f)) { - fclose(f); - free(introspection); - goto oom; - } - - fclose(f); - - if (!introspection) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); - goto oom; - } - - free(introspection); - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) { - - assert(!m->queued_message); - - /* Instead of sending the reply back right away, we - * just remember that we need to and then send it - * after the reload is finished. That way the caller - * knows when the reload finished. */ - - if (!(m->queued_message = dbus_message_new_method_return(message))) - goto oom; - - m->queued_message_connection = connection; - m->exit_code = MANAGER_RELOAD; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) { - - /* We don't send a reply back here, the client should - * just wait for us disconnecting. */ - - m->exit_code = MANAGER_REEXECUTE; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) { - - if (m->running_as == MANAGER_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - m->exit_code = MANAGER_EXIT; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) { - - if (m->running_as != MANAGER_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - m->exit_code = MANAGER_REBOOT; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) { - - if (m->running_as != MANAGER_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - m->exit_code = MANAGER_POWEROFF; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) { - - if (m->running_as != MANAGER_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - m->exit_code = MANAGER_HALT; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) { - - if (m->running_as != MANAGER_SYSTEM) { - dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers."); - return bus_send_error_reply(connection, message, &error, -ENOTSUP); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - m->exit_code = MANAGER_KEXEC; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { - char **l = NULL, **e = NULL; - - if ((r = bus_parse_strv(message, &l)) < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - e = strv_env_merge(2, m->environment, l); - strv_free(l); - - if (!e) - goto oom; - - if (!(reply = dbus_message_new_method_return(message))) { - strv_free(e); - goto oom; - } - - strv_free(m->environment); - m->environment = e; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) { - char **l = NULL, **e = NULL; - - if ((r = bus_parse_strv(message, &l)) < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - e = strv_env_delete(m->environment, 1, l); - strv_free(l); - - if (!e) - goto oom; - - if (!(reply = dbus_message_new_method_return(message))) { - strv_free(e); - goto oom; - } - - strv_free(m->environment); - m->environment = e; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) { - char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL; - DBusMessageIter iter; - - if (!dbus_message_iter_init(message, &iter)) - goto oom; - - r = bus_parse_strv_iter(&iter, &l_unset); - if (r < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - if (!dbus_message_iter_next(&iter)) { - strv_free(l_unset); - return bus_send_error_reply(connection, message, NULL, -EINVAL); - } - - r = bus_parse_strv_iter(&iter, &l_set); - if (r < 0) { - strv_free(l_unset); - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - e = strv_env_delete(m->environment, 1, l_unset); - strv_free(l_unset); - - if (!e) { - strv_free(l_set); - goto oom; - } - - f = strv_env_merge(2, e, l_set); - strv_free(l_set); - strv_free(e); - - if (!f) - goto oom; - - if (!(reply = dbus_message_new_method_return(message))) { - strv_free(f); - goto oom; - } - - strv_free(m->environment); - m->environment = f; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) { - DBusMessageIter iter, sub, sub2; - Hashmap *h; - Iterator i; - UnitFileList *item; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - h = hashmap_new(string_hash_func, string_compare_func); - if (!h) - goto oom; - - r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h); - if (r < 0) { - unit_file_list_free(h); - dbus_message_unref(reply); - return bus_send_error_reply(connection, message, NULL, r); - } - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) { - unit_file_list_free(h); - goto oom; - } - - HASHMAP_FOREACH(item, h, i) { - const char *state; - - state = unit_file_state_to_string(item->state); - assert(state); - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) || - !dbus_message_iter_close_container(&sub, &sub2)) { - unit_file_list_free(h); - goto oom; - } - } - - unit_file_list_free(h); - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) { - const char *name; - UnitFileState state; - const char *s; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name); - if (state < 0) - return bus_send_error_reply(connection, message, NULL, state); - - s = unit_file_state_to_string(state); - assert(s); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_STRING, &s, - DBUS_TYPE_INVALID)) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) { - - char **l = NULL; - DBusMessageIter iter; - UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - dbus_bool_t runtime, force; - int carries_install_info = -1; - - if (!dbus_message_iter_init(message, &iter)) - goto oom; - - r = bus_parse_strv_iter(&iter, &l); - if (r < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - if (!dbus_message_iter_next(&iter) || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EIO); - } - - if (streq(member, "EnableUnitFiles")) { - r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "ReenableUnitFiles")) { - r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "LinkUnitFiles")) - r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes); - else if (streq(member, "PresetUnitFiles")) { - r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(member, "MaskUnitFiles")) - r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes); - else - assert_not_reached("Uh? Wrong method"); - - strv_free(l); - bus_manager_send_unit_files_changed(m); - - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return bus_send_error_reply(connection, message, NULL, r); - } - - reply = message_from_file_changes(message, changes, n_changes, carries_install_info); - unit_file_changes_free(changes, n_changes); - - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) { - - char **l = NULL; - DBusMessageIter iter; - UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - dbus_bool_t runtime; - - if (!dbus_message_iter_init(message, &iter)) - goto oom; - - r = bus_parse_strv_iter(&iter, &l); - if (r < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - if (!dbus_message_iter_next(&iter) || - bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EIO); - } - - if (streq(member, "DisableUnitFiles")) - r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes); - else if (streq(member, "UnmaskUnitFiles")) - r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes); - else - assert_not_reached("Uh? Wrong method"); - - strv_free(l); - bus_manager_send_unit_files_changed(m); - - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return bus_send_error_reply(connection, message, NULL, r); - } - - reply = message_from_file_changes(message, changes, n_changes, -1); - unit_file_changes_free(changes, n_changes); - - if (!reply) - goto oom; - - } else - return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties); - - if (job_type != _JOB_TYPE_INVALID) { - const char *name, *smode, *old_name = NULL; - JobMode mode; - Job *j; - Unit *u; - bool b; - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace")) - b = dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &old_name, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID); - else - b = dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID); - - if (!b) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (old_name) - if (!(u = manager_get_unit(m, old_name)) || - !u->meta.job || - u->meta.job->type != JOB_START) { - dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name); - return bus_send_error_reply(connection, message, &error, -ENOENT); - } - - - if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) { - dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (reload_if_possible && unit_can_reload(u)) { - if (job_type == JOB_RESTART) - job_type = JOB_RELOAD_OR_START; - else if (job_type == JOB_TRY_RESTART) - job_type = JOB_RELOAD; - } - - if ((job_type == JOB_START && u->meta.refuse_manual_start) || - (job_type == JOB_STOP && u->meta.refuse_manual_stop) || - ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) && - (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) { - dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only."); - return bus_send_error_reply(connection, message, &error, -EPERM); - } - - if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(j->bus_client = strdup(message_get_sender_with_fallback(message)))) - goto oom; - - j->bus = connection; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = job_dbus_path(j))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - free(path); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - free(path); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -const DBusObjectPathVTable bus_manager_vtable = { - .message_function = bus_manager_message_handler -}; diff --git a/src/dbus-manager.h b/src/dbus-manager.h deleted file mode 100644 index 2eb2fbb..0000000 --- a/src/dbus-manager.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusmanagerhfoo -#define foodbusmanagerhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -extern const DBusObjectPathVTable bus_manager_vtable; - -extern const char bus_manager_interface[]; - -#endif diff --git a/src/dbus-mount.c b/src/dbus-mount.c deleted file mode 100644 index cfbfd45..0000000 --- a/src/dbus-mount.c +++ /dev/null @@ -1,157 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-mount.h" -#include "dbus-execute.h" -#include "dbus-common.h" - -#define BUS_MOUNT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - BUS_EXEC_COMMAND_INTERFACE("ExecMount") \ - BUS_EXEC_COMMAND_INTERFACE("ExecUnmount") \ - BUS_EXEC_COMMAND_INTERFACE("ExecRemount") \ - BUS_EXEC_CONTEXT_INTERFACE \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_MOUNT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Mount\0" - -const char bus_mount_interface[] _introspect_("Mount") = BUS_MOUNT_INTERFACE; - -const char bus_mount_invalidating_properties[] = - "What\0" - "Options\0" - "Type\0" - "ExecMount\0" - "ExecUnmount\0" - "ExecRemount\0" - "ControlPID\0"; - -static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; - const char *d; - - assert(i); - assert(property); - assert(m); - - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.what) - d = m->parameters_proc_self_mountinfo.what; - else if (m->from_fragment && m->parameters_fragment.what) - d = m->parameters_fragment.what; - else if (m->from_etc_fstab && m->parameters_etc_fstab.what) - d = m->parameters_etc_fstab.what; - else - d = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; -} - -static int bus_mount_append_options(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; - const char *d; - - assert(i); - assert(property); - assert(m); - - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.options) - d = m->parameters_proc_self_mountinfo.options; - else if (m->from_fragment && m->parameters_fragment.options) - d = m->parameters_fragment.options; - else if (m->from_etc_fstab && m->parameters_etc_fstab.options) - d = m->parameters_etc_fstab.options; - else - d = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; -} - -static int bus_mount_append_type(DBusMessageIter *i, const char *property, void *data) { - Mount *m = data; - const char *d; - - assert(i); - assert(property); - assert(m); - - if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) - d = m->parameters_proc_self_mountinfo.fstype; - else if (m->from_fragment && m->parameters_fragment.fstype) - d = m->parameters_fragment.fstype; - else if (m->from_etc_fstab && m->parameters_etc_fstab.fstype) - d = m->parameters_etc_fstab.fstype; - else - d = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; -} - -DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Mount", "Where", bus_property_append_string, "s", u->mount.where }, - { "org.freedesktop.systemd1.Mount", "What", bus_mount_append_what, "s", u }, - { "org.freedesktop.systemd1.Mount", "Options", bus_mount_append_options, "s", u }, - { "org.freedesktop.systemd1.Mount", "Type", bus_mount_append_type, "s", u }, - { "org.freedesktop.systemd1.Mount", "TimeoutUSec", bus_property_append_usec, "t", &u->mount.timeout_usec }, - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_MOUNT, "ExecMount"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_UNMOUNT, "ExecUnmount"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Mount", u->mount.exec_command+MOUNT_EXEC_REMOUNT, "ExecRemount"), - BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Mount", u->mount.exec_context), - { "org.freedesktop.systemd1.Mount", "ControlPID", bus_property_append_pid, "u", &u->mount.control_pid }, - { "org.freedesktop.systemd1.Mount", "DirectoryMode", bus_property_append_mode, "u", &u->mount.directory_mode }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-mount.h b/src/dbus-mount.h deleted file mode 100644 index b5613fa..0000000 --- a/src/dbus-mount.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusmounthfoo -#define foodbusmounthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_mount_interface[]; -extern const char bus_mount_invalidating_properties[]; - -#endif diff --git a/src/dbus-path.c b/src/dbus-path.c deleted file mode 100644 index 1523879..0000000 --- a/src/dbus-path.c +++ /dev/null @@ -1,105 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-path.h" -#include "dbus-execute.h" -#include "dbus-common.h" - -#define BUS_PATH_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_PATH_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Path\0" - -const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE; - -static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) { - Path *p = data; - DBusMessageIter sub, sub2; - PathSpec *k; - - assert(i); - assert(property); - assert(p); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub)) - return -ENOMEM; - - LIST_FOREACH(spec, k, p->specs) { - const char *t = path_type_to_string(k->type); - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) || - !dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *t; - - assert(i); - assert(property); - assert(u); - - t = u->path.unit ? u->path.unit->meta.id : ""; - - return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM; -} - -DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Path", "Unit", bus_path_append_unit, "s", u }, - { "org.freedesktop.systemd1.Path", "Paths", bus_path_append_paths, "a(ss)", u }, - { "org.freedesktop.systemd1.Path", "MakeDirectory", bus_property_append_bool, "b", &u->path.make_directory }, - { "org.freedesktop.systemd1.Path", "DirectoryMode", bus_property_append_mode, "u", &u->path.directory_mode }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-path.h b/src/dbus-path.h deleted file mode 100644 index f825e13..0000000 --- a/src/dbus-path.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbuspathhfoo -#define foodbuspathhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_path_interface[]; - -#endif diff --git a/src/dbus-service.c b/src/dbus-service.c deleted file mode 100644 index 3486623..0000000 --- a/src/dbus-service.c +++ /dev/null @@ -1,134 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-execute.h" -#include "dbus-service.h" -#include "dbus-common.h" - -#ifdef HAVE_SYSV_COMPAT -#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \ - " \n" \ - " \n" \ - " \n" -#else -#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT "" -#endif - -#define BUS_SERVICE_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStart") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \ - BUS_EXEC_COMMAND_INTERFACE("ExecReload") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStop") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ - BUS_EXEC_CONTEXT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - BUS_EXEC_STATUS_INTERFACE("ExecMain") \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_SERVICE_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Service\0" - -const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE; - -const char bus_service_invalidating_properties[] = - "ExecStartPre\0" - "ExecStart\0" - "ExecStartPost\0" - "ExecReload\0" - "ExecStop\0" - "ExecStopPost\0" - "ExecMain\0" - "MainPID\0" - "ControlPID\0" - "StatusText\0"; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart); -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess); - -DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Service", "Type", bus_service_append_type, "s", &u->service.type }, - { "org.freedesktop.systemd1.Service", "Restart", bus_service_append_restart, "s", &u->service.restart }, - { "org.freedesktop.systemd1.Service", "PIDFile", bus_property_append_string, "s", u->service.pid_file }, - { "org.freedesktop.systemd1.Service", "NotifyAccess", bus_service_append_notify_access, "s", &u->service.notify_access }, - { "org.freedesktop.systemd1.Service", "RestartUSec", bus_property_append_usec, "t", &u->service.restart_usec }, - { "org.freedesktop.systemd1.Service", "TimeoutUSec", bus_property_append_usec, "t", &u->service.timeout_usec }, - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START_PRE], "ExecStartPre"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START], "ExecStart"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_START_POST], "ExecStartPost"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_RELOAD], "ExecReload"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_STOP], "ExecStop"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Service", u->service.exec_command[SERVICE_EXEC_STOP_POST], "ExecStopPost"), - BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context), - { "org.freedesktop.systemd1.Service", "PermissionsStartOnly", bus_property_append_bool, "b", &u->service.permissions_start_only }, - { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool, "b", &u->service.root_directory_start_only }, - { "org.freedesktop.systemd1.Service", "RemainAfterExit", bus_property_append_bool, "b", &u->service.remain_after_exit }, - { "org.freedesktop.systemd1.Service", "GuessMainPID", bus_property_append_bool, "b", &u->service.guess_main_pid }, - BUS_EXEC_STATUS_PROPERTIES("org.freedesktop.systemd1.Service", u->service.main_exec_status, "ExecMain"), - { "org.freedesktop.systemd1.Service", "MainPID", bus_property_append_pid, "u", &u->service.main_pid }, - { "org.freedesktop.systemd1.Service", "ControlPID", bus_property_append_pid, "u", &u->service.control_pid }, - { "org.freedesktop.systemd1.Service", "BusName", bus_property_append_string, "s", u->service.bus_name }, - { "org.freedesktop.systemd1.Service", "StatusText", bus_property_append_string, "s", u->service.status_text }, - { "org.freedesktop.systemd1.Service", "Sockets", bus_unit_append_dependencies, "as", u->service.configured_sockets }, -#ifdef HAVE_SYSV_COMPAT - { "org.freedesktop.systemd1.Service", "SysVRunLevels", bus_property_append_string, "s", u->service.sysv_runlevels }, - { "org.freedesktop.systemd1.Service", "SysVStartPriority", bus_property_append_int, "i", &u->service.sysv_start_priority }, - { "org.freedesktop.systemd1.Service", "SysVPath", bus_property_append_string, "s", u->service.sysv_path }, -#endif - { "org.freedesktop.systemd1.Service", "FsckPassNo", bus_property_append_int, "i", &u->service.fsck_passno }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-service.h b/src/dbus-service.h deleted file mode 100644 index d6eab65..0000000 --- a/src/dbus-service.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusservicehfoo -#define foodbusservicehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_service_interface[]; -extern const char bus_service_invalidating_properties[]; - -#endif diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c deleted file mode 100644 index 0c2f349..0000000 --- a/src/dbus-snapshot.c +++ /dev/null @@ -1,87 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "dbus-unit.h" -#include "dbus-snapshot.h" -#include "dbus-common.h" - -#define BUS_SNAPSHOT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_SNAPSHOT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Snapshot\0" - -const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE; - -DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Snapshot", "Cleanup", bus_property_append_bool, "b", &u->snapshot.cleanup }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL; - DBusError error; - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Snapshot", "Remove")) { - - snapshot_remove(SNAPSHOT(u)); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} diff --git a/src/dbus-snapshot.h b/src/dbus-snapshot.h deleted file mode 100644 index 0b82279..0000000 --- a/src/dbus-snapshot.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbussnapshothfoo -#define foodbussnapshothfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_snapshot_interface[]; - -#endif diff --git a/src/dbus-socket.c b/src/dbus-socket.c deleted file mode 100644 index 2a1a17d..0000000 --- a/src/dbus-socket.c +++ /dev/null @@ -1,126 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-socket.h" -#include "dbus-execute.h" -#include "dbus-common.h" - -#define BUS_SOCKET_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPre") \ - BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \ - BUS_EXEC_CONTEXT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_SOCKET_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Socket\0" - -const char bus_socket_interface[] _introspect_("Socket") = BUS_SOCKET_INTERFACE; - -const char bus_socket_invalidating_properties[] = - "ExecStartPre\0" - "ExecStartPost\0" - "ExecStopPre\0" - "ExecStopPost\0" - "ControlPID\0" - "NAccepted\0" - "NConnections\0"; - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); - -DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Socket", "BindIPv6Only", bus_socket_append_bind_ipv6_only, "s", &u->socket.bind_ipv6_only }, - { "org.freedesktop.systemd1.Socket", "Backlog", bus_property_append_unsigned, "u", &u->socket.backlog }, - { "org.freedesktop.systemd1.Socket", "TimeoutUSec", bus_property_append_usec, "t", &u->socket.timeout_usec }, - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_START_PRE], "ExecStartPre"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_START_POST], "ExecStartPost"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_STOP_PRE], "ExecStopPre"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Socket", u->service.exec_command[SOCKET_EXEC_STOP_POST], "ExecStopPost"), - BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Socket", u->socket.exec_context), - { "org.freedesktop.systemd1.Socket", "ControlPID", bus_property_append_pid, "u", &u->socket.control_pid }, - { "org.freedesktop.systemd1.Socket", "BindToDevice", bus_property_append_string, "s", u->socket.bind_to_device }, - { "org.freedesktop.systemd1.Socket", "DirectoryMode", bus_property_append_mode, "u", &u->socket.directory_mode }, - { "org.freedesktop.systemd1.Socket", "SocketMode", bus_property_append_mode, "u", &u->socket.socket_mode }, - { "org.freedesktop.systemd1.Socket", "Accept", bus_property_append_bool, "b", &u->socket.accept }, - { "org.freedesktop.systemd1.Socket", "KeepAlive", bus_property_append_bool, "b", &u->socket.keep_alive }, - { "org.freedesktop.systemd1.Socket", "Priority", bus_property_append_int, "i", &u->socket.priority }, - { "org.freedesktop.systemd1.Socket", "ReceiveBuffer", bus_property_append_size, "t", &u->socket.receive_buffer }, - { "org.freedesktop.systemd1.Socket", "SendBuffer", bus_property_append_size, "t", &u->socket.send_buffer }, - { "org.freedesktop.systemd1.Socket", "IPTOS", bus_property_append_int, "i", &u->socket.ip_tos }, - { "org.freedesktop.systemd1.Socket", "IPTTL", bus_property_append_int, "i", &u->socket.ip_ttl }, - { "org.freedesktop.systemd1.Socket", "PipeSize", bus_property_append_size, "t", &u->socket.pipe_size }, - { "org.freedesktop.systemd1.Socket", "FreeBind", bus_property_append_bool, "b", &u->socket.free_bind }, - { "org.freedesktop.systemd1.Socket", "Transparent", bus_property_append_bool, "b", &u->socket.transparent }, - { "org.freedesktop.systemd1.Socket", "Broadcast", bus_property_append_bool, "b", &u->socket.broadcast }, - { "org.freedesktop.systemd1.Socket", "Mark", bus_property_append_int, "i", &u->socket.mark }, - { "org.freedesktop.systemd1.Socket", "MaxConnections", bus_property_append_unsigned, "u", &u->socket.max_connections }, - { "org.freedesktop.systemd1.Socket", "NConnections", bus_property_append_unsigned, "u", &u->socket.n_connections }, - { "org.freedesktop.systemd1.Socket", "NAccepted", bus_property_append_unsigned, "u", &u->socket.n_accepted }, - { "org.freedesktop.systemd1.Socket", "MessageQueueMaxMessages", bus_property_append_long,"x", &u->socket.mq_maxmsg }, - { "org.freedesktop.systemd1.Socket", "MessageQueueMessageSize", bus_property_append_long,"x", &u->socket.mq_msgsize }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-socket.h b/src/dbus-socket.h deleted file mode 100644 index 069a2f5..0000000 --- a/src/dbus-socket.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbussockethfoo -#define foodbussockethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_socket_interface[]; -extern const char bus_socket_invalidating_properties[]; - -#endif diff --git a/src/dbus-swap.c b/src/dbus-swap.c deleted file mode 100644 index 988ca58..0000000 --- a/src/dbus-swap.c +++ /dev/null @@ -1,100 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2010 Maarten Lankhorst - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-swap.h" -#include "dbus-execute.h" -#include "dbus-common.h" - -#define BUS_SWAP_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - BUS_EXEC_COMMAND_INTERFACE("ExecActivate") \ - BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate") \ - BUS_EXEC_CONTEXT_INTERFACE \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_SWAP_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Swap\0" - -const char bus_swap_interface[] _introspect_("Swap") = BUS_SWAP_INTERFACE; - -const char bus_swap_invalidating_properties[] = - "What\0" - "Priority\0" - "ExecActivate\0" - "ExecDeactivate\0" - "ControlPID\0"; - -static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) { - Swap *s = data; - dbus_int32_t j; - - assert(i); - assert(property); - assert(s); - - if (s->from_proc_swaps) - j = s->parameters_proc_swaps.priority; - else if (s->from_fragment) - j = s->parameters_fragment.priority; - else if (s->from_etc_fstab) - j = s->parameters_etc_fstab.priority; - else - j = -1; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &j)) - return -ENOMEM; - - return 0; -} - -DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Swap", "What", bus_property_append_string, "s", u->swap.what }, - { "org.freedesktop.systemd1.Swap", "Priority", bus_swap_append_priority, "i", u }, - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Swap", u->swap.exec_command+SWAP_EXEC_ACTIVATE, "ExecActivate"), - BUS_EXEC_COMMAND_PROPERTY("org.freedesktop.systemd1.Swap", u->swap.exec_command+SWAP_EXEC_DEACTIVATE, "ExecDeactivate"), - BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Swap", u->swap.exec_context), - { "org.freedesktop.systemd1.Swap", "ControlPID", bus_property_append_pid, "u", &u->swap.control_pid }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-swap.h b/src/dbus-swap.h deleted file mode 100644 index 15b9147..0000000 --- a/src/dbus-swap.h +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusswaphfoo -#define foodbusswaphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2010 Maarten Lankhorst - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_swap_interface[]; -extern const char bus_swap_invalidating_properties[]; - -#endif diff --git a/src/dbus-target.c b/src/dbus-target.c deleted file mode 100644 index 1e00f2d..0000000 --- a/src/dbus-target.c +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-target.h" -#include "dbus-common.h" - -#define BUS_TARGET_INTERFACE \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_TARGET_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Target\0" - -const char bus_target_interface[] _introspect_("Target") = BUS_TARGET_INTERFACE; - -DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-target.h b/src/dbus-target.h deleted file mode 100644 index 13d3876..0000000 --- a/src/dbus-target.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbustargethfoo -#define foodbustargethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_target_interface[]; - -#endif diff --git a/src/dbus-timer.c b/src/dbus-timer.c deleted file mode 100644 index abcbe6f..0000000 --- a/src/dbus-timer.c +++ /dev/null @@ -1,125 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus-unit.h" -#include "dbus-timer.h" -#include "dbus-execute.h" -#include "dbus-common.h" - -#define BUS_TIMER_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_UNIT_INTERFACE \ - BUS_TIMER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_UNIT_INTERFACES_LIST \ - "org.freedesktop.systemd1.Timer\0" - -const char bus_timer_interface[] _introspect_("Timer") = BUS_TIMER_INTERFACE; - -const char bus_timer_invalidating_properties[] = - "Timers\0" - "NextElapseUSec\0"; - -static int bus_timer_append_timers(DBusMessageIter *i, const char *property, void *data) { - Timer *p = data; - DBusMessageIter sub, sub2; - TimerValue *k; - - assert(i); - assert(property); - assert(p); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub)) - return -ENOMEM; - - LIST_FOREACH(value, k, p->values) { - char *buf; - const char *t; - size_t l; - bool b; - - t = timer_base_to_string(k->base); - assert(endswith(t, "Sec")); - - /* s/Sec/USec/ */ - l = strlen(t); - if (!(buf = new(char, l+2))) - return -ENOMEM; - - memcpy(buf, t, l-3); - memcpy(buf+l-3, "USec", 5); - - b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) && - dbus_message_iter_close_container(&sub, &sub2); - - free(buf); - if (!b) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *t; - - assert(i); - assert(property); - assert(u); - - t = u->timer.unit ? u->timer.unit->meta.id : ""; - - return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM; -} - -DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { - const BusProperty properties[] = { - BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Timer", "Unit", bus_timer_append_unit, "s", u }, - { "org.freedesktop.systemd1.Timer", "Timers", bus_timer_append_timers, "a(stt)", u }, - { "org.freedesktop.systemd1.Timer", "NextElapseUSec", bus_property_append_usec, "t", &u->timer.next_elapse }, - { NULL, NULL, NULL, NULL, NULL } - }; - - return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); -} diff --git a/src/dbus-timer.h b/src/dbus-timer.h deleted file mode 100644 index e692e12..0000000 --- a/src/dbus-timer.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbustimerhfoo -#define foodbustimerhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" - -DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message); - -extern const char bus_timer_interface[]; -extern const char bus_timer_invalidating_properties[]; - -#endif diff --git a/src/dbus-unit.c b/src/dbus-unit.c deleted file mode 100644 index 611a120..0000000 --- a/src/dbus-unit.c +++ /dev/null @@ -1,788 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "dbus.h" -#include "log.h" -#include "dbus-unit.h" -#include "bus-errors.h" -#include "dbus-common.h" - -const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; - -#define INVALIDATING_PROPERTIES \ - "LoadState\0" \ - "ActiveState\0" \ - "SubState\0" \ - "InactiveExitTimestamp\0" \ - "ActiveEnterTimestamp\0" \ - "ActiveExitTimestamp\0" \ - "InactiveEnterTimestamp\0" \ - "Job\0" \ - "NeedDaemonReload\0" - -int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data) { - char *t; - Iterator j; - DBusMessageIter sub; - Unit *u = data; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - SET_FOREACH(t, u->meta.names, j) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data, *f; - const char *d; - - assert(i); - assert(property); - assert(u); - - f = unit_following(u); - d = f ? f->meta.id : ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) { - Unit *u; - Iterator j; - DBusMessageIter sub; - Set *s = data; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - SET_FOREACH(u, s, j) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->meta.id)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *d; - - assert(i); - assert(property); - assert(u); - - d = unit_description(u); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d)) - return -ENOMEM; - - return 0; -} - -DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState); - -int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; - - assert(i); - assert(property); - assert(u); - - state = unit_active_state_to_string(unit_active_state(u)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; - - assert(i); - assert(property); - assert(u); - - state = unit_sub_state_to_string(u); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *state; - - assert(i); - assert(property); - assert(u); - - state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u))); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - b = unit_can_start(u) && - !u->meta.refuse_manual_start; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - /* On the lower levels we assume that every unit we can start - * we can also stop */ - - b = unit_can_start(u) && - !u->meta.refuse_manual_stop; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - b = unit_can_reload(u); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - b = unit_can_isolate(u) && - !u->meta.refuse_manual_start; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - DBusMessageIter sub; - char *p; - - assert(i); - assert(property); - assert(u); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (u->meta.job) { - - if (!(p = job_dbus_path(u->meta.job))) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->meta.job->id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - } else { - uint32_t id = 0; - - /* No job, so let's fill in some placeholder - * data. Since we need to fill in a valid path we - * simple point to ourselves. */ - - if (!(p = unit_dbus_path(u))) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - char *t; - CGroupBonding *cgb; - bool success; - - assert(i); - assert(property); - assert(u); - - if ((cgb = unit_get_default_cgroup(u))) { - if (!(t = cgroup_bonding_to_string(cgb))) - return -ENOMEM; - } else - t = (char*) ""; - - success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t); - - if (cgb) - free(t); - - return success ? 0 : -ENOMEM; -} - -int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - CGroupBonding *cgb; - DBusMessageIter sub; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - LIST_FOREACH(by_unit, cgb, u->meta.cgroup_bondings) { - char *t; - bool success; - - if (!(t = cgroup_bonding_to_string(cgb))) - return -ENOMEM; - - success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t); - free(t); - - if (!success) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - CGroupAttribute *a; - DBusMessageIter sub, sub2; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub)) - return -ENOMEM; - - LIST_FOREACH(by_unit, a, u->meta.cgroup_attributes) { - char *v = NULL; - bool success; - - if (a->map_callback) - a->map_callback(a->controller, a->name, a->value, &v); - - success = - dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) && - dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) && - dbus_message_iter_close_container(&sub, &sub2); - - free(v); - - if (!success) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - b = unit_need_daemon_reload(u); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) { - Unit *u = data; - const char *name, *message; - DBusMessageIter sub; - - assert(i); - assert(property); - assert(u); - - if (u->meta.load_error != 0) { - name = bus_errno_to_dbus(u->meta.load_error); - message = strempty(strerror(-u->meta.load_error)); - } else - name = message = ""; - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &message) || - !dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) { - DBusMessage *reply = NULL; - Manager *m = u->meta.manager; - DBusError error; - JobType job_type = _JOB_TYPE_INVALID; - char *path = NULL; - bool reload_if_possible = false; - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start")) - job_type = JOB_START; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop")) - job_type = JOB_STOP; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload")) - job_type = JOB_RELOAD; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart")) - job_type = JOB_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart")) - job_type = JOB_TRY_RESTART; - else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) { - reload_if_possible = true; - job_type = JOB_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) { - reload_if_possible = true; - job_type = JOB_TRY_RESTART; - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) { - const char *swho, *smode; - int32_t signo; - KillMode mode; - KillWho who; - int r; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (isempty(smode)) - mode = KILL_CONTROL_GROUP; - else { - mode = kill_mode_from_string(smode); - if (mode < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if ((r = unit_kill(u, who, mode, signo, &error)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) { - - unit_reset_failed(u); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - } else if (UNIT_VTABLE(u)->bus_message_handler) - return UNIT_VTABLE(u)->bus_message_handler(u, connection, message); - else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (job_type != _JOB_TYPE_INVALID) { - const char *smode; - JobMode mode; - Job *j; - int r; - - if ((job_type == JOB_START && u->meta.refuse_manual_start) || - (job_type == JOB_STOP && u->meta.refuse_manual_stop) || - ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) && - (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) { - dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only."); - return bus_send_error_reply(connection, message, &error, -EPERM); - } - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &smode, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (reload_if_possible && unit_can_reload(u)) { - if (job_type == JOB_RESTART) - job_type = JOB_RELOAD_OR_START; - else if (job_type == JOB_TRY_RESTART) - job_type = JOB_RELOAD; - } - - if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) { - dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!(path = job_dbus_path(j))) - goto oom; - - if (!dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto oom; - } - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - free(path); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - free(path); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - Unit *u; - int r; - DBusMessage *reply; - - assert(connection); - assert(message); - assert(m); - - if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) { - /* Be nice to gdbus and return introspection data for our mid-level paths */ - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; - FILE *f; - Iterator i; - const char *k; - size_t size; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ - - if (!(f = open_memstream(&introspection, &size))) - goto oom; - - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", f); - - fputs(BUS_INTROSPECTABLE_INTERFACE, f); - fputs(BUS_PEER_INTERFACE, f); - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *p; - - if (k != u->meta.id) - continue; - - if (!(p = bus_path_escape(k))) { - fclose(f); - free(introspection); - goto oom; - } - - fprintf(f, "", p); - free(p); - } - - fputs("\n", f); - - if (ferror(f)) { - fclose(f); - free(introspection); - goto oom; - } - - fclose(f); - - if (!introspection) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); - goto oom; - } - - free(introspection); - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if ((r = manager_get_unit_from_dbus_path(m, dbus_message_get_path(message), &u)) < 0) { - - if (r == -ENOMEM) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown unit"); - return bus_send_error_reply(connection, message, &e, r); - } - - return bus_send_error_reply(connection, message, NULL, r); - } - - return bus_unit_message_dispatch(u, connection, message); - -oom: - if (reply) - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -const DBusObjectPathVTable bus_unit_vtable = { - .message_function = bus_unit_message_handler -}; - -void bus_unit_send_change_signal(Unit *u) { - char *p = NULL; - DBusMessage *m = NULL; - - assert(u); - - if (u->meta.in_dbus_queue) { - LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); - u->meta.in_dbus_queue = false; - } - - if (!u->meta.id) - return; - - if (!bus_has_subscriber(u->meta.manager)) { - u->meta.sent_dbus_new_signal = true; - return; - } - - if (!(p = unit_dbus_path(u))) - goto oom; - - if (u->meta.sent_dbus_new_signal) { - /* Send a properties changed signal. First for the - * specific type, then for the generic unit. The - * clients may rely on this order to get atomic - * behaviour if needed. */ - - if (UNIT_VTABLE(u)->bus_invalidating_properties) { - - if (!(m = bus_properties_changed_new(p, - UNIT_VTABLE(u)->bus_interface, - UNIT_VTABLE(u)->bus_invalidating_properties))) - goto oom; - - if (bus_broadcast(u->meta.manager, m) < 0) - goto oom; - - dbus_message_unref(m); - } - - if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES))) - goto oom; - - } else { - /* Send a new signal */ - - if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew"))) - goto oom; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &u->meta.id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto oom; - } - - if (bus_broadcast(u->meta.manager, m) < 0) - goto oom; - - free(p); - dbus_message_unref(m); - - u->meta.sent_dbus_new_signal = true; - - return; - -oom: - free(p); - - if (m) - dbus_message_unref(m); - - log_error("Failed to allocate unit change/new signal."); -} - -void bus_unit_send_removed_signal(Unit *u) { - char *p = NULL; - DBusMessage *m = NULL; - - assert(u); - - if (!bus_has_subscriber(u->meta.manager)) - return; - - if (!u->meta.sent_dbus_new_signal) - bus_unit_send_change_signal(u); - - if (!u->meta.id) - return; - - if (!(p = unit_dbus_path(u))) - goto oom; - - if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved"))) - goto oom; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &u->meta.id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto oom; - - if (bus_broadcast(u->meta.manager, m) < 0) - goto oom; - - free(p); - dbus_message_unref(m); - - return; - -oom: - free(p); - - if (m) - dbus_message_unref(m); - - log_error("Failed to allocate unit remove signal."); -} diff --git a/src/dbus-unit.h b/src/dbus-unit.h deleted file mode 100644 index 9fed6d7..0000000 --- a/src/dbus-unit.h +++ /dev/null @@ -1,207 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbusunithfoo -#define foodbusunithfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "manager.h" - -#define BUS_UNIT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define BUS_UNIT_INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.systemd1.Unit\0" - -#define BUS_UNIT_PROPERTIES \ - { "org.freedesktop.systemd1.Unit", "Id", bus_property_append_string, "s", u->meta.id }, \ - { "org.freedesktop.systemd1.Unit", "Names", bus_unit_append_names, "as", u }, \ - { "org.freedesktop.systemd1.Unit", "Following", bus_unit_append_following, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "Requires", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRES] }, \ - { "org.freedesktop.systemd1.Unit", "RequiresOverridable", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE] }, \ - { "org.freedesktop.systemd1.Unit", "Requisite", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUISITE] }, \ - { "org.freedesktop.systemd1.Unit", "RequisiteOverridable", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE] }, \ - { "org.freedesktop.systemd1.Unit", "Wants", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_WANTS] }, \ - { "org.freedesktop.systemd1.Unit", "BindTo", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BIND_TO] }, \ - { "org.freedesktop.systemd1.Unit", "RequiredBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRED_BY] }, \ - { "org.freedesktop.systemd1.Unit", "RequiredByOverridable",bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE] }, \ - { "org.freedesktop.systemd1.Unit", "WantedBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_WANTED_BY] }, \ - { "org.freedesktop.systemd1.Unit", "BoundBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BOUND_BY] }, \ - { "org.freedesktop.systemd1.Unit", "Conflicts", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_CONFLICTS] }, \ - { "org.freedesktop.systemd1.Unit", "ConflictedBy", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_CONFLICTED_BY] }, \ - { "org.freedesktop.systemd1.Unit", "Before", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_BEFORE] }, \ - { "org.freedesktop.systemd1.Unit", "After", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_AFTER] }, \ - { "org.freedesktop.systemd1.Unit", "OnFailure", bus_unit_append_dependencies, "as", u->meta.dependencies[UNIT_ON_FAILURE] }, \ - { "org.freedesktop.systemd1.Unit", "Description", bus_unit_append_description, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "LoadState", bus_unit_append_load_state, "s", &u->meta.load_state }, \ - { "org.freedesktop.systemd1.Unit", "ActiveState", bus_unit_append_active_state, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "SubState", bus_unit_append_sub_state, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "FragmentPath", bus_property_append_string, "s", u->meta.fragment_path }, \ - { "org.freedesktop.systemd1.Unit", "UnitFileState", bus_unit_append_file_state, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "InactiveExitTimestampMonotonic",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.monotonic }, \ - { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestampMonotonic", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.monotonic }, \ - { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "ActiveExitTimestampMonotonic", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.monotonic }, \ - { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_usec, "t", &u->meta.inactive_enter_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestampMonotonic",bus_property_append_usec,"t", &u->meta.inactive_enter_timestamp.monotonic }, \ - { "org.freedesktop.systemd1.Unit", "CanStart", bus_unit_append_can_start, "b", u }, \ - { "org.freedesktop.systemd1.Unit", "CanStop", bus_unit_append_can_stop, "b", u }, \ - { "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u }, \ - { "org.freedesktop.systemd1.Unit", "CanIsolate", bus_unit_append_can_isolate, "b", u }, \ - { "org.freedesktop.systemd1.Unit", "Job", bus_unit_append_job, "(uo)", u }, \ - { "org.freedesktop.systemd1.Unit", "StopWhenUnneeded", bus_property_append_bool, "b", &u->meta.stop_when_unneeded }, \ - { "org.freedesktop.systemd1.Unit", "RefuseManualStart", bus_property_append_bool, "b", &u->meta.refuse_manual_start }, \ - { "org.freedesktop.systemd1.Unit", "RefuseManualStop", bus_property_append_bool, "b", &u->meta.refuse_manual_stop }, \ - { "org.freedesktop.systemd1.Unit", "AllowIsolate", bus_property_append_bool, "b", &u->meta.allow_isolate }, \ - { "org.freedesktop.systemd1.Unit", "DefaultDependencies", bus_property_append_bool, "b", &u->meta.default_dependencies }, \ - { "org.freedesktop.systemd1.Unit", "OnFailureIsolate", bus_property_append_bool, "b", &u->meta.on_failure_isolate }, \ - { "org.freedesktop.systemd1.Unit", "IgnoreOnIsolate", bus_property_append_bool, "b", &u->meta.ignore_on_isolate }, \ - { "org.freedesktop.systemd1.Unit", "IgnoreOnSnapshot", bus_property_append_bool, "b", &u->meta.ignore_on_snapshot }, \ - { "org.freedesktop.systemd1.Unit", "DefaultControlGroup", bus_unit_append_default_cgroup, "s", u }, \ - { "org.freedesktop.systemd1.Unit", "ControlGroup", bus_unit_append_cgroups, "as", u }, \ - { "org.freedesktop.systemd1.Unit", "ControlGroupAttributes", bus_unit_append_cgroup_attrs, "a(sss)", u }, \ - { "org.freedesktop.systemd1.Unit", "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", u }, \ - { "org.freedesktop.systemd1.Unit", "JobTimeoutUSec", bus_property_append_usec, "t", &u->meta.job_timeout }, \ - { "org.freedesktop.systemd1.Unit", "ConditionTimestamp", bus_property_append_usec, "t", &u->meta.condition_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "ConditionTimestampMonotonic", bus_property_append_usec,"t", &u->meta.condition_timestamp.monotonic }, \ - { "org.freedesktop.systemd1.Unit", "ConditionResult", bus_property_append_bool, "b", &u->meta.condition_result }, \ - { "org.freedesktop.systemd1.Unit", "LoadError", bus_unit_append_load_error, "(ss)", u } - -int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_load_state(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data); - -void bus_unit_send_change_signal(Unit *u); -void bus_unit_send_removed_signal(Unit *u); - -extern const DBusObjectPathVTable bus_unit_vtable; - -extern const char bus_unit_interface[]; - -#endif diff --git a/src/dbus.c b/src/dbus.c deleted file mode 100644 index daa2c84..0000000 --- a/src/dbus.c +++ /dev/null @@ -1,1338 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "dbus.h" -#include "log.h" -#include "strv.h" -#include "cgroup.h" -#include "dbus-unit.h" -#include "dbus-job.h" -#include "dbus-manager.h" -#include "dbus-service.h" -#include "dbus-socket.h" -#include "dbus-target.h" -#include "dbus-device.h" -#include "dbus-mount.h" -#include "dbus-automount.h" -#include "dbus-snapshot.h" -#include "dbus-swap.h" -#include "dbus-timer.h" -#include "dbus-path.h" -#include "bus-errors.h" -#include "special.h" -#include "dbus-common.h" - -#define CONNECTIONS_MAX 52 - -static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE; -static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE; - -const char *const bus_interface_table[] = { - "org.freedesktop.DBus.Properties", bus_properties_interface, - "org.freedesktop.DBus.Introspectable", bus_introspectable_interface, - "org.freedesktop.systemd1.Manager", bus_manager_interface, - "org.freedesktop.systemd1.Job", bus_job_interface, - "org.freedesktop.systemd1.Unit", bus_unit_interface, - "org.freedesktop.systemd1.Service", bus_service_interface, - "org.freedesktop.systemd1.Socket", bus_socket_interface, - "org.freedesktop.systemd1.Target", bus_target_interface, - "org.freedesktop.systemd1.Device", bus_device_interface, - "org.freedesktop.systemd1.Mount", bus_mount_interface, - "org.freedesktop.systemd1.Automount", bus_automount_interface, - "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface, - "org.freedesktop.systemd1.Swap", bus_swap_interface, - "org.freedesktop.systemd1.Timer", bus_timer_interface, - "org.freedesktop.systemd1.Path", bus_path_interface, - NULL -}; - -static void bus_done_api(Manager *m); -static void bus_done_system(Manager *m); -static void bus_done_private(Manager *m); -static void shutdown_connection(Manager *m, DBusConnection *c); - -static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) { - Manager *m = data; - - assert(bus); - assert(m); - - /* We maintain two sets, one for those connections where we - * requested a dispatch, and another where we didn't. And then, - * we move the connections between the two sets. */ - - if (status == DBUS_DISPATCH_COMPLETE) - set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus); - else - set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus); -} - -void bus_watch_event(Manager *m, Watch *w, int events) { - assert(m); - assert(w); - - /* This is called by the event loop whenever there is - * something happening on D-Bus' file handles. */ - - if (!dbus_watch_get_enabled(w->data.bus_watch)) - return; - - dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events)); -} - -static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; - - assert(bus_watch); - assert(m); - - if (!(w = new0(Watch, 1))) - return FALSE; - - w->fd = dbus_watch_get_unix_fd(bus_watch); - w->type = WATCH_DBUS_WATCH; - w->data.bus_watch = bus_watch; - - zero(ev); - ev.events = bus_flags_to_events(bus_watch); - ev.data.ptr = w; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) { - - if (errno != EEXIST) { - free(w); - return FALSE; - } - - /* Hmm, bloody D-Bus creates multiple watches on the - * same fd. epoll() does not like that. As a dirty - * hack we simply dup() the fd and hence get a second - * one we can safely add to the epoll(). */ - - if ((w->fd = dup(w->fd)) < 0) { - free(w); - return FALSE; - } - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) { - close_nointr_nofail(w->fd); - free(w); - return FALSE; - } - - w->fd_is_dupped = true; - } - - dbus_watch_set_data(bus_watch, w, NULL); - - return TRUE; -} - -static void bus_remove_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; - - assert(bus_watch); - assert(m); - - w = dbus_watch_get_data(bus_watch); - if (!w) - return; - - assert(w->type == WATCH_DBUS_WATCH); - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - - if (w->fd_is_dupped) - close_nointr_nofail(w->fd); - - free(w); -} - -static void bus_toggle_watch(DBusWatch *bus_watch, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; - - assert(bus_watch); - assert(m); - - w = dbus_watch_get_data(bus_watch); - if (!w) - return; - - assert(w->type == WATCH_DBUS_WATCH); - - zero(ev); - ev.events = bus_flags_to_events(bus_watch); - ev.data.ptr = w; - - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0); -} - -static int bus_timeout_arm(Manager *m, Watch *w) { - struct itimerspec its; - - assert(m); - assert(w); - - zero(its); - - if (dbus_timeout_get_enabled(w->data.bus_timeout)) { - timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC); - its.it_interval = its.it_value; - } - - if (timerfd_settime(w->fd, 0, &its, NULL) < 0) - return -errno; - - return 0; -} - -void bus_timeout_event(Manager *m, Watch *w, int events) { - assert(m); - assert(w); - - /* This is called by the event loop whenever there is - * something happening on D-Bus' file handles. */ - - if (!(dbus_timeout_get_enabled(w->data.bus_timeout))) - return; - - dbus_timeout_handle(w->data.bus_timeout); -} - -static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; - struct epoll_event ev; - - assert(timeout); - assert(m); - - if (!(w = new0(Watch, 1))) - return FALSE; - - if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) - goto fail; - - w->type = WATCH_DBUS_TIMEOUT; - w->data.bus_timeout = timeout; - - if (bus_timeout_arm(m, w) < 0) - goto fail; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = w; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) - goto fail; - - dbus_timeout_set_data(timeout, w, NULL); - - return TRUE; - -fail: - if (w->fd >= 0) - close_nointr_nofail(w->fd); - - free(w); - return FALSE; -} - -static void bus_remove_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; - - assert(timeout); - assert(m); - - w = dbus_timeout_get_data(timeout); - if (!w) - return; - - assert(w->type == WATCH_DBUS_TIMEOUT); - - assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - close_nointr_nofail(w->fd); - free(w); -} - -static void bus_toggle_timeout(DBusTimeout *timeout, void *data) { - Manager *m = data; - Watch *w; - int r; - - assert(timeout); - assert(m); - - w = dbus_timeout_get_data(timeout); - if (!w) - return; - - assert(w->type == WATCH_DBUS_TIMEOUT); - - if ((r = bus_timeout_arm(m, w)) < 0) - log_error("Failed to rearm timer: %s", strerror(-r)); -} - -static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; - DBusMessage *reply = NULL; - - assert(connection); - assert(message); - assert(m); - - dbus_error_init(&error); - - if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) - log_debug("Got D-Bus request: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); - - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - log_debug("API D-Bus connection terminated."); - bus_done_api(m); - - } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { - const char *name, *old_owner, *new_owner; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &old_owner, - DBUS_TYPE_STRING, &new_owner, - DBUS_TYPE_INVALID)) - log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error)); - else { - if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name)) - log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection))); - - if (old_owner[0] == 0) - old_owner = NULL; - - if (new_owner[0] == 0) - new_owner = NULL; - - manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner); - } - } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) { - const char *name; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error)); - else { - int r; - Unit *u; - - log_debug("Got D-Bus activation request for %s", name); - - if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) || - manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) { - r = -EADDRNOTAVAIL; - dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down."); - } else { - r = manager_load_unit(m, name, NULL, &error, &u); - - if (r >= 0 && u->meta.refuse_manual_start) - r = -EPERM; - - if (r >= 0) - r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL); - } - - if (r < 0) { - const char *id, *text; - - log_debug("D-Bus activation failed for %s: %s", name, strerror(-r)); - - if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"))) - goto oom; - - id = error.name ? error.name : bus_errno_to_dbus(r); - text = bus_error(&error, r); - - if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) || - !dbus_message_append_args(reply, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &id, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) - goto oom; - } - - /* On success we don't do anything, the service will be spawned now */ - } - } - - dbus_error_free(&error); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; - - assert(connection); - assert(message); - assert(m); - - dbus_error_init(&error); - - if (m->api_bus != m->system_bus && - (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)) - log_debug("Got D-Bus request on system bus: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); - - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - log_debug("System D-Bus connection terminated."); - bus_done_system(m); - - } else if (m->running_as != MANAGER_SYSTEM && - dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { - - const char *cgroup; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &cgroup, - DBUS_TYPE_INVALID)) - log_error("Failed to parse Released message: %s", bus_error_message(&error)); - else - cgroup_notify_empty(m, cgroup); - } - - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) { - Manager *m = data; - DBusError error; - - assert(connection); - assert(message); - assert(m); - - dbus_error_init(&error); - - if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL || - dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) - log_debug("Got D-Bus request: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); - - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) - shutdown_connection(m, connection); - else if (m->running_as == MANAGER_SYSTEM && - dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { - - const char *cgroup; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &cgroup, - DBUS_TYPE_INVALID)) - log_error("Failed to parse Released message: %s", bus_error_message(&error)); - else - cgroup_notify_empty(m, cgroup); - - /* Forward the message to the system bus, so that user - * instances are notified as well */ - - if (m->system_bus) - dbus_connection_send(m->system_bus, message, NULL); - } - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -unsigned bus_dispatch(Manager *m) { - DBusConnection *c; - - assert(m); - - if (m->queued_message) { - /* If we cannot get rid of this message we won't - * dispatch any D-Bus messages, so that we won't end - * up wanting to queue another message. */ - - if (m->queued_message_connection) - if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL)) - return 0; - - dbus_message_unref(m->queued_message); - m->queued_message = NULL; - m->queued_message_connection = NULL; - } - - if ((c = set_first(m->bus_connections_for_dispatch))) { - if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE) - set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c); - - return 1; - } - - return 0; -} - -static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusError error; - - dbus_error_init(&error); - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - - switch (dbus_message_get_type(reply)) { - - case DBUS_MESSAGE_TYPE_ERROR: - - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("RequestName() failed: %s", bus_error_message(&error)); - break; - - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - uint32_t r; - - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_UINT32, &r, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error)); - break; - } - - if (r == 1) - log_debug("Successfully acquired name."); - else - log_error("Name already owned."); - - break; - } - - default: - assert_not_reached("Invalid reply message"); - } - - dbus_message_unref(reply); - dbus_error_free(&error); -} - -static int request_name(Manager *m) { - const char *name = "org.freedesktop.systemd1"; - /* Allow replacing of our name, to ease implementation of - * reexecution, where we keep the old connection open until - * after the new connection is set up and the name installed - * to allow clients to synchronously wait for reexecution to - * finish */ - uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING; - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName"))) - goto oom; - - if (!dbus_message_append_args( - message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &flags, - DBUS_TYPE_INVALID)) - goto oom; - - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL)) - goto oom; - - dbus_message_unref(message); - dbus_pending_call_unref(pending); - - /* We simple ask for the name and don't wait for it. Sooner or - * later we'll have it. */ - - return 0; - -oom: - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } - - if (message) - dbus_message_unref(message); - - return -ENOMEM; -} - -static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusError error; - Manager *m = userdata; - - assert(m); - - dbus_error_init(&error); - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - - switch (dbus_message_get_type(reply)) { - - case DBUS_MESSAGE_TYPE_ERROR: - - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("ListNames() failed: %s", bus_error_message(&error)); - break; - - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - int r; - char **l; - - if ((r = bus_parse_strv(reply, &l)) < 0) - log_warning("Failed to parse ListNames() reply: %s", strerror(-r)); - else { - char **t; - - STRV_FOREACH(t, l) - /* This is a bit hacky, we say the - * owner of the name is the name - * itself, because we don't want the - * extra traffic to figure out the - * real owner. */ - manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t); - - strv_free(l); - } - - break; - } - - default: - assert_not_reached("Invalid reply message"); - } - - dbus_message_unref(reply); - dbus_error_free(&error); -} - -static int query_name_list(Manager *m) { - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - - /* Asks for the currently installed bus names */ - - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "ListNames"))) - goto oom; - - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL)) - goto oom; - - dbus_message_unref(message); - dbus_pending_call_unref(pending); - - /* We simple ask for the list and don't wait for it. Sooner or - * later we'll get it. */ - - return 0; - -oom: - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } - - if (message) - dbus_message_unref(message); - - return -ENOMEM; -} - -static int bus_setup_loop(Manager *m, DBusConnection *bus) { - assert(m); - assert(bus); - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) || - !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) { - log_error("Not enough memory"); - return -ENOMEM; - } - - if (set_put(m->bus_connections_for_dispatch, bus) < 0) { - log_error("Not enough memory"); - return -ENOMEM; - } - - dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL); - return 0; -} - -static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) { - return uid == 0 || uid == geteuid(); -} - -static void bus_new_connection( - DBusServer *server, - DBusConnection *new_connection, - void *data) { - - Manager *m = data; - - assert(m); - - if (set_size(m->bus_connections) >= CONNECTIONS_MAX) { - log_error("Too many concurrent connections."); - return; - } - - dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL); - - if (bus_setup_loop(m, new_connection) < 0) - return; - - if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) || - !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) || - !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) || - !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) { - log_error("Not enough memory."); - return; - } - - log_debug("Accepted connection on private bus."); - - dbus_connection_ref(new_connection); -} - -static int bus_init_system(Manager *m) { - DBusError error; - int r; - - assert(m); - - dbus_error_init(&error); - - if (m->system_bus) - return 0; - - if (m->running_as == MANAGER_SYSTEM && m->api_bus) - m->system_bus = m->api_bus; - else { - if (!(m->system_bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) { - log_debug("Failed to get system D-Bus connection, retrying later: %s", bus_error_message(&error)); - r = 0; - goto fail; - } - - if ((r = bus_setup_loop(m, m->system_bus)) < 0) - goto fail; - } - - if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - if (m->running_as != MANAGER_SYSTEM) { - dbus_bus_add_match(m->system_bus, - "type='signal'," - "interface='org.freedesktop.systemd1.Agent'," - "member='Released'," - "path='/org/freedesktop/systemd1/agent'", - &error); - - if (dbus_error_is_set(&error)) { - log_error("Failed to register match: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - } - - if (m->api_bus != m->system_bus) { - char *id; - log_debug("Successfully connected to system D-Bus bus %s as %s", - strnull((id = dbus_connection_get_server_id(m->system_bus))), - strnull(dbus_bus_get_unique_name(m->system_bus))); - dbus_free(id); - } - - return 0; - -fail: - bus_done_system(m); - dbus_error_free(&error); - - return r; -} - -static int bus_init_api(Manager *m) { - DBusError error; - int r; - - assert(m); - - dbus_error_init(&error); - - if (m->api_bus) - return 0; - - if (m->running_as == MANAGER_SYSTEM && m->system_bus) - m->api_bus = m->system_bus; - else { - if (!(m->api_bus = dbus_bus_get_private(m->running_as == MANAGER_USER ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) { - log_debug("Failed to get API D-Bus connection, retrying later: %s", bus_error_message(&error)); - r = 0; - goto fail; - } - - if ((r = bus_setup_loop(m, m->api_bus)) < 0) - goto fail; - } - - if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) || - !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) || - !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) || - !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - /* Get NameOwnerChange messages */ - dbus_bus_add_match(m->api_bus, - "type='signal'," - "sender='"DBUS_SERVICE_DBUS"'," - "interface='"DBUS_INTERFACE_DBUS"'," - "member='NameOwnerChanged'," - "path='"DBUS_PATH_DBUS"'", - &error); - - if (dbus_error_is_set(&error)) { - log_error("Failed to register match: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - - /* Get activation requests */ - dbus_bus_add_match(m->api_bus, - "type='signal'," - "sender='"DBUS_SERVICE_DBUS"'," - "interface='org.freedesktop.systemd1.Activator'," - "member='ActivationRequest'," - "path='"DBUS_PATH_DBUS"'", - &error); - - if (dbus_error_is_set(&error)) { - log_error("Failed to register match: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - - if ((r = request_name(m)) < 0) - goto fail; - - if ((r = query_name_list(m)) < 0) - goto fail; - - if (m->api_bus != m->system_bus) { - char *id; - log_debug("Successfully connected to API D-Bus bus %s as %s", - strnull((id = dbus_connection_get_server_id(m->api_bus))), - strnull(dbus_bus_get_unique_name(m->api_bus))); - dbus_free(id); - } - - return 0; - -fail: - bus_done_api(m); - dbus_error_free(&error); - - return r; -} - -static int bus_init_private(Manager *m) { - DBusError error; - int r; - const char *const external_only[] = { - "EXTERNAL", - NULL - }; - - assert(m); - - dbus_error_init(&error); - - if (m->private_bus) - return 0; - - if (m->running_as == MANAGER_SYSTEM) { - - /* We want the private bus only when running as init */ - if (getpid() != 1) - return 0; - - unlink("/run/systemd/private"); - m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error); - } else { - const char *e; - char *p; - - e = getenv("XDG_RUNTIME_DIR"); - if (!e) - return 0; - - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - mkdir_parents(p+10, 0755); - unlink(p+10); - m->private_bus = dbus_server_listen(p, &error); - free(p); - } - - if (!m->private_bus) { - log_error("Failed to create private D-Bus server: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - - if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) || - !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) || - !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL); - - log_debug("Successfully created private D-Bus server."); - - return 0; - -fail: - bus_done_private(m); - dbus_error_free(&error); - - return r; -} - -int bus_init(Manager *m, bool try_bus_connect) { - int r; - - if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 || - set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0) { - log_error("Not enough memory"); - return -ENOMEM; - } - - if (m->name_data_slot < 0) - if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot)) { - log_error("Not enough memory"); - return -ENOMEM; - } - - if (m->subscribed_data_slot < 0) - if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot)) { - log_error("Not enough memory"); - return -ENOMEM; - } - - if (try_bus_connect) { - if ((r = bus_init_system(m)) < 0 || - (r = bus_init_api(m)) < 0) - return r; - } - - if ((r = bus_init_private(m)) < 0) - return r; - - return 0; -} - -static void shutdown_connection(Manager *m, DBusConnection *c) { - Set *s; - Job *j; - Iterator i; - - HASHMAP_FOREACH(j, m->jobs, i) - if (j->bus == c) { - free(j->bus_client); - j->bus_client = NULL; - - j->bus = NULL; - } - - set_remove(m->bus_connections, c); - set_remove(m->bus_connections_for_dispatch, c); - - if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) { - char *t; - - while ((t = set_steal_first(s))) - free(t); - - set_free(s); - } - - if (m->queued_message_connection == c) { - m->queued_message_connection = NULL; - - if (m->queued_message) { - dbus_message_unref(m->queued_message); - m->queued_message = NULL; - } - } - - dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL); - dbus_connection_flush(c); - dbus_connection_close(c); - dbus_connection_unref(c); -} - -static void bus_done_api(Manager *m) { - assert(m); - - if (m->api_bus) { - if (m->system_bus == m->api_bus) - m->system_bus = NULL; - - shutdown_connection(m, m->api_bus); - m->api_bus = NULL; - } - - - if (m->queued_message) { - dbus_message_unref(m->queued_message); - m->queued_message = NULL; - } -} - -static void bus_done_system(Manager *m) { - assert(m); - - if (m->system_bus == m->api_bus) - bus_done_api(m); - - if (m->system_bus) { - shutdown_connection(m, m->system_bus); - m->system_bus = NULL; - } -} - -static void bus_done_private(Manager *m) { - - if (m->private_bus) { - dbus_server_disconnect(m->private_bus); - dbus_server_unref(m->private_bus); - m->private_bus = NULL; - } -} - -void bus_done(Manager *m) { - DBusConnection *c; - - bus_done_api(m); - bus_done_system(m); - bus_done_private(m); - - while ((c = set_steal_first(m->bus_connections))) - shutdown_connection(m, c); - - while ((c = set_steal_first(m->bus_connections_for_dispatch))) - shutdown_connection(m, c); - - set_free(m->bus_connections); - set_free(m->bus_connections_for_dispatch); - - if (m->name_data_slot >= 0) - dbus_pending_call_free_data_slot(&m->name_data_slot); - - if (m->subscribed_data_slot >= 0) - dbus_connection_free_data_slot(&m->subscribed_data_slot); -} - -static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) { - Manager *m = userdata; - DBusMessage *reply; - DBusError error; - const char *name; - - dbus_error_init(&error); - - assert_se(name = BUS_PENDING_CALL_NAME(m, pending)); - assert_se(reply = dbus_pending_call_steal_reply(pending)); - - switch (dbus_message_get_type(reply)) { - - case DBUS_MESSAGE_TYPE_ERROR: - - assert_se(dbus_set_error_from_message(&error, reply)); - log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error)); - break; - - case DBUS_MESSAGE_TYPE_METHOD_RETURN: { - uint32_t r; - - if (!dbus_message_get_args(reply, - &error, - DBUS_TYPE_UINT32, &r, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error)); - break; - } - - manager_dispatch_bus_query_pid_done(m, name, (pid_t) r); - break; - } - - default: - assert_not_reached("Invalid reply message"); - } - - dbus_message_unref(reply); - dbus_error_free(&error); -} - -int bus_query_pid(Manager *m, const char *name) { - DBusMessage *message = NULL; - DBusPendingCall *pending = NULL; - char *n = NULL; - - assert(m); - assert(name); - - if (!(message = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID"))) - goto oom; - - if (!(dbus_message_append_args( - message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID))) - goto oom; - - if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1)) - goto oom; - - if (!(n = strdup(name))) - goto oom; - - if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free)) - goto oom; - - n = NULL; - - if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL)) - goto oom; - - dbus_message_unref(message); - dbus_pending_call_unref(pending); - - return 0; - -oom: - free(n); - - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } - - if (message) - dbus_message_unref(message); - - return -ENOMEM; -} - -int bus_broadcast(Manager *m, DBusMessage *message) { - bool oom = false; - Iterator i; - DBusConnection *c; - - assert(m); - assert(message); - - SET_FOREACH(c, m->bus_connections_for_dispatch, i) - if (c != m->system_bus || m->running_as == MANAGER_SYSTEM) - oom = !dbus_connection_send(c, message, NULL); - - SET_FOREACH(c, m->bus_connections, i) - if (c != m->system_bus || m->running_as == MANAGER_SYSTEM) - oom = !dbus_connection_send(c, message, NULL); - - return oom ? -ENOMEM : 0; -} - -bool bus_has_subscriber(Manager *m) { - Iterator i; - DBusConnection *c; - - assert(m); - - SET_FOREACH(c, m->bus_connections_for_dispatch, i) - if (bus_connection_has_subscriber(m, c)) - return true; - - SET_FOREACH(c, m->bus_connections, i) - if (bus_connection_has_subscriber(m, c)) - return true; - - return false; -} - -bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) { - assert(m); - assert(c); - - return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c)); -} - -int bus_fdset_add_all(Manager *m, FDSet *fds) { - Iterator i; - DBusConnection *c; - - assert(m); - assert(fds); - - /* When we are about to reexecute we add all D-Bus fds to the - * set to pass over to the newly executed systemd. They won't - * be used there however, except that they are closed at the - * very end of deserialization, those making it possible for - * clients to synchronously wait for systemd to reexec by - * simply waiting for disconnection */ - - SET_FOREACH(c, m->bus_connections_for_dispatch, i) { - int fd; - - if (dbus_connection_get_unix_fd(c, &fd)) { - fd = fdset_put_dup(fds, fd); - - if (fd < 0) - return fd; - } - } - - SET_FOREACH(c, m->bus_connections, i) { - int fd; - - if (dbus_connection_get_unix_fd(c, &fd)) { - fd = fdset_put_dup(fds, fd); - - if (fd < 0) - return fd; - } - } - - return 0; -} - -void bus_broadcast_finished( - Manager *m, - usec_t kernel_usec, - usec_t initrd_usec, - usec_t userspace_usec, - usec_t total_usec) { - - DBusMessage *message; - - assert(m); - - message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished"); - if (!message) { - log_error("Out of memory."); - return; - } - - assert_cc(sizeof(usec_t) == sizeof(uint64_t)); - if (!dbus_message_append_args(message, - DBUS_TYPE_UINT64, &kernel_usec, - DBUS_TYPE_UINT64, &initrd_usec, - DBUS_TYPE_UINT64, &userspace_usec, - DBUS_TYPE_UINT64, &total_usec, - DBUS_TYPE_INVALID)) { - log_error("Out of memory."); - goto finish; - } - - - if (bus_broadcast(m, message) < 0) { - log_error("Out of memory."); - goto finish; - } - -finish: - if (message) - dbus_message_unref(message); -} diff --git a/src/dbus.h b/src/dbus.h deleted file mode 100644 index bd539d0..0000000 --- a/src/dbus.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodbushfoo -#define foodbushfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "manager.h" - -int bus_init(Manager *m, bool try_bus_connect); -void bus_done(Manager *m); - -unsigned bus_dispatch(Manager *m); - -void bus_watch_event(Manager *m, Watch *w, int events); -void bus_timeout_event(Manager *m, Watch *w, int events); - -int bus_query_pid(Manager *m, const char *name); - -int bus_broadcast(Manager *m, DBusMessage *message); - -bool bus_has_subscriber(Manager *m); -bool bus_connection_has_subscriber(Manager *m, DBusConnection *c); - -int bus_fdset_add_all(Manager *m, FDSet *fds); - -void bus_broadcast_finished(Manager *m, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); - -#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot) -#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot) - -extern const char * const bus_interface_table[]; - -#endif diff --git a/src/dbus1-generator/Makefile b/src/dbus1-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/dbus1-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c new file mode 100644 index 0000000..b1c94c2 --- /dev/null +++ b/src/dbus1-generator/dbus1-generator.c @@ -0,0 +1,354 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "conf-parser.h" +#include "special.h" +#include "mkdir.h" +#include "bus-util.h" +#include "bus-internal.h" +#include "unit-name.h" +#include "cgroup-util.h" + +static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; + +static int create_dbus_files( + const char *path, + const char *name, + const char *service, + const char *exec, + const char *user, + const char *type) { + + _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; + + assert(path); + assert(name); + assert(service || exec); + + if (!service) { + _cleanup_free_ char *a = NULL; + + s = strjoin("dbus-", name, ".service", NULL); + if (!s) + return log_oom(); + + a = strjoin(arg_dest_late, "/", s, NULL); + if (!a) + return log_oom(); + + f = fopen(a, "wxe"); + if (!f) { + log_error("Failed to create %s: %m", a); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n" + "Description=DBUS1: %s\n\n" + "[Service]\n" + "ExecStart=%s\n" + "Type=dbus\n" + "BusName=%s\n", + path, + name, + exec, + name); + + if (user) + fprintf(f, "User=%s\n", user); + + + if (type) { + fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type); + + if (streq(type, "system")) + fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n"); + else if (streq(type, "session")) { + char *run; + + run = getenv("XDG_RUNTIME_DIR"); + if (!run) { + log_error("XDG_RUNTIME_DIR not set."); + return -EINVAL; + } + + fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n", + (unsigned long) getuid(), run); + } + } + + fflush(f); + if (ferror(f)) { + log_error("Failed to write %s: %m", a); + return -errno; + } + + service = s; + } + + b = strjoin(arg_dest_late, "/", name, ".busname", NULL); + if (!b) + return log_oom(); + + f = fopen(b, "wxe"); + if (!f) { + log_error("Failed to create %s: %m", b); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n" + "Description=DBUS1: %s\n\n" + "[BusName]\n" + "Name=%s\n" + "Service=%s\n", + path, + name, + name, + service); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write %s: %m", b); + return -errno; + } + + lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(b, lnk)) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + + return 0; +} + +static int add_dbus(const char *path, const char *fname, const char *type) { + _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; + + ConfigTableItem table[] = { + { "D-BUS Service", "Name", config_parse_string, 0, &name }, + { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, + { "D-BUS Service", "User", config_parse_string, 0, &user }, + { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, + }; + + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(path); + assert(fname); + + p = strjoin(path, "/", fname, NULL); + if (!p) + return log_oom(); + + f = fopen(p, "re"); + if (!f) { + if (errno == -ENOENT) + return 0; + + log_error("Failed to read %s: %m", p); + return -errno; + } + + r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL); + if (r < 0) + return r; + + if (!name) { + log_warning("Activation file %s lacks name setting, ignoring.", p); + return 0; + } + + if (!service_name_is_valid(name)) { + log_warning("Bus service name %s is not valid, ignoring.", name); + return 0; + } + + if (streq(name, "org.freedesktop.systemd1")) { + log_debug("Skipping %s, identified as systemd.", p); + return 0; + } + + if (service) { + if (!unit_name_is_valid(service, TEMPLATE_INVALID)) { + log_warning("Unit name %s is not valid, ignoring.", service); + return 0; + } + if (!endswith(service, ".service")) { + log_warning("Bus names can only activate services, ignoring %s.", p); + return 0; + } + } else { + if (streq(exec, "/bin/false") || !exec) { + log_warning("Neither service name nor binary path specified, ignoring %s.", p); + return 0; + } + + if (exec[0] != '/') { + log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); + return 0; + } + } + + return create_dbus_files(p, name, service, exec, user, type); +} + +static int parse_dbus_fragments(const char *path, const char *type) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r; + + assert(path); + assert(type); + + d = opendir(path); + if (!d) { + if (errno == -ENOENT) + return 0; + + log_error("Failed to enumerate D-Bus activated services: %m"); + return -errno; + } + + r = 0; + FOREACH_DIRENT(de, d, goto fail) { + int q; + + if (!endswith(de->d_name, ".service")) + continue; + + q = add_dbus(path, de->d_name, type); + if (q < 0) + r = q; + } + + return r; + +fail: + log_error("Failed to read D-Bus services directory: %m"); + return -errno; +} + +static int link_busnames_target(const char *units) { + const char *f, *t; + + f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET); + t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET); + + mkdir_parents_label(t, 0755); + if (symlink(f, t) < 0) { + log_error("Failed to create symlink %s: %m", t); + return -errno; + } + + return 0; +} + +static int link_compatibility(const char *units) { + const char *f, *t; + + f = strappenda(units, "/systemd-bus-proxyd.socket"); + t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET); + mkdir_parents_label(t, 0755); + if (symlink(f, t) < 0) { + log_error("Failed to create symlink %s: %m", t); + return -errno; + } + + f = strappenda(units, "/systemd-bus-proxyd.socket"); + t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket"); + mkdir_parents_label(t, 0755); + if (symlink(f, t) < 0) { + log_error("Failed to create symlink %s: %m", t); + return -errno; + } + + t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE); + if (symlink("/dev/null", t) < 0) { + log_error("Failed to mask %s: %m", t); + return -errno; + } + + return 0; +} + +int main(int argc, char *argv[]) { + const char *path, *type, *units; + int r, q; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) { + arg_dest = argv[1]; + arg_dest_late = argv[3]; + } + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (access("/dev/kdbus/control", F_OK) < 0) + return 0; + + r = cg_pid_get_owner_uid(0, NULL); + if (r >= 0) { + path = "/usr/share/dbus-1/services"; + type = "session"; + units = USER_DATA_UNIT_PATH; + } else if (r == -ENOENT) { + path = "/usr/share/dbus-1/system-services"; + type = "system"; + units = SYSTEM_DATA_UNIT_PATH; + } else { + log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r)); + return r; + } + + r = parse_dbus_fragments(path, type); + + /* FIXME: One day this should just be pulled in statically from basic.target */ + q = link_busnames_target(units); + if (q < 0) + r = q; + + q = link_compatibility(units); + if (q < 0) + r = q; + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/def.h b/src/def.h deleted file mode 100644 index 20aaa7c..0000000 --- a/src/def.h +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodefhfoo -#define foodefhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "util.h" - -#define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC) -#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) - -#define DEFAULT_EXIT_USEC (5*USEC_PER_MINUTE) - -#define SYSTEMD_CGROUP_CONTROLLER "name=systemd" - -#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT -#define SIGNALS_IGNORE SIGKILL,SIGPIPE - -#endif diff --git a/src/delta/Makefile b/src/delta/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/delta/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/delta/delta.c b/src/delta/delta.c new file mode 100644 index 0000000..369f8f8 --- /dev/null +++ b/src/delta/delta.c @@ -0,0 +1,636 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "hashmap.h" +#include "util.h" +#include "path-util.h" +#include "log.h" +#include "pager.h" +#include "build.h" +#include "strv.h" + +static const char prefixes[] = + "/etc\0" + "/run\0" + "/usr/local/lib\0" + "/usr/local/share\0" + "/usr/lib\0" + "/usr/share\0" +#ifdef HAVE_SPLIT_USR + "/lib\0" +#endif + ; + +static const char suffixes[] = + "sysctl.d\0" + "tmpfiles.d\0" + "modules-load.d\0" + "binfmt.d\0" + "systemd/system\0" + "systemd/user\0" + "systemd/system-preset\0" + "systemd/user-preset\0" + "udev/rules.d\0" + "modprobe.d\0"; + +static const char have_dropins[] = + "systemd/system\0" + "systemd/user\0"; + +static bool arg_no_pager = false; +static int arg_diff = -1; + +static enum { + SHOW_MASKED = 1 << 0, + SHOW_EQUIVALENT = 1 << 1, + SHOW_REDIRECTED = 1 << 2, + SHOW_OVERRIDDEN = 1 << 3, + SHOW_UNCHANGED = 1 << 4, + SHOW_EXTENDED = 1 << 5, + + SHOW_DEFAULTS = + (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED) +} arg_flags = 0; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static int equivalent(const char *a, const char *b) { + _cleanup_free_ char *x = NULL, *y = NULL; + + x = canonicalize_file_name(a); + if (!x) + return -errno; + + y = canonicalize_file_name(b); + if (!y) + return -errno; + + return path_equal(x, y); +} + +static int notify_override_masked(const char *top, const char *bottom) { + if (!(arg_flags & SHOW_MASKED)) + return 0; + + printf("%s%s%s %s → %s\n", + ansi_highlight_red(), "[MASKED]", ansi_highlight_off(), top, bottom); + return 1; +} + +static int notify_override_equivalent(const char *top, const char *bottom) { + if (!(arg_flags & SHOW_EQUIVALENT)) + return 0; + + printf("%s%s%s %s → %s\n", + ansi_highlight_green(), "[EQUIVALENT]", ansi_highlight_off(), top, bottom); + return 1; +} + +static int notify_override_redirected(const char *top, const char *bottom) { + if (!(arg_flags & SHOW_REDIRECTED)) + return 0; + + printf("%s%s%s %s → %s\n", + ansi_highlight(), "[REDIRECTED]", ansi_highlight_off(), top, bottom); + return 1; +} + +static int notify_override_overridden(const char *top, const char *bottom) { + if (!(arg_flags & SHOW_OVERRIDDEN)) + return 0; + + printf("%s%s%s %s → %s\n", + ansi_highlight(), "[OVERRIDDEN]", ansi_highlight_off(), top, bottom); + return 1; +} + +static int notify_override_extended(const char *top, const char *bottom) { + if (!(arg_flags & SHOW_EXTENDED)) + return 0; + + printf("%s%s%s %s → %s\n", + ansi_highlight(), "[EXTENDED]", ansi_highlight_off(), top, bottom); + return 1; +} + +static int notify_override_unchanged(const char *f) { + if (!(arg_flags & SHOW_UNCHANGED)) + return 0; + + printf("[UNCHANGED] %s\n", f); + return 1; +} + +static int found_override(const char *top, const char *bottom) { + _cleanup_free_ char *dest = NULL; + int k; + pid_t pid; + + assert(top); + assert(bottom); + + if (null_or_empty_path(top) > 0) + return notify_override_masked(top, bottom); + + k = readlink_malloc(top, &dest); + if (k >= 0) { + if (equivalent(dest, bottom) > 0) + return notify_override_equivalent(top, bottom); + else + return notify_override_redirected(top, bottom); + } + + k = notify_override_overridden(top, bottom); + if (!arg_diff) + return k; + + putchar('\n'); + + fflush(stdout); + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork off diff: %m"); + return -errno; + } else if (pid == 0) { + execlp("diff", "diff", "-us", "--", bottom, top, NULL); + log_error("Failed to execute diff: %m"); + _exit(1); + } + + wait_for_terminate(pid, NULL); + + putchar('\n'); + + return k; +} + +static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *toppath, const char *drop) { + _cleanup_free_ char *unit = NULL; + _cleanup_free_ char *path = NULL; + _cleanup_strv_free_ char **list = NULL; + char **file; + char *c; + int r; + + assert(!endswith(drop, "/")); + + path = strjoin(toppath, "/", drop, NULL); + if (!path) + return -ENOMEM; + + log_debug("Looking at %s", path); + + unit = strdup(drop); + if (!unit) + return -ENOMEM; + + c = strrchr(unit, '.'); + if (!c) + return -EINVAL; + *c = 0; + + r = get_files_in_directory(path, &list); + if (r < 0){ + log_error("Failed to enumerate %s: %s", path, strerror(-r)); + return r; + } + + STRV_FOREACH(file, list) { + Hashmap *h; + int k; + char *p; + char *d; + + if (!endswith(*file, ".conf")) + continue; + + p = strjoin(path, "/", *file, NULL); + if (!p) + return -ENOMEM; + d = p + strlen(toppath) + 1; + + log_debug("Adding at top: %s → %s", d, p); + k = hashmap_put(top, d, p); + if (k >= 0) { + p = strdup(p); + if (!p) + return -ENOMEM; + d = p + strlen(toppath) + 1; + } else if (k != -EEXIST) { + free(p); + return k; + } + + log_debug("Adding at bottom: %s → %s", d, p); + free(hashmap_remove(bottom, d)); + k = hashmap_put(bottom, d, p); + if (k < 0) { + free(p); + return k; + } + + h = hashmap_get(drops, unit); + if (!h) { + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return -ENOMEM; + hashmap_put(drops, unit, h); + unit = strdup(unit); + if (!unit) + return -ENOMEM; + } + + p = strdup(p); + if (!p) + return -ENOMEM; + + log_debug("Adding to drops: %s → %s → %s", unit, basename(p), p); + k = hashmap_put(h, basename(p), p); + if (k < 0) { + free(p); + if (k != -EEXIST) + return k; + } + } + return 0; +} + +static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *path, bool dropins) { + _cleanup_closedir_ DIR *d; + + assert(top); + assert(bottom); + assert(drops); + assert(path); + + log_debug("Looking at %s", path); + + d = opendir(path); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open %s: %m", path); + return -errno; + } + + for (;;) { + struct dirent *de; + int k; + char *p; + + errno = 0; + de = readdir(d); + if (!de) + return -errno; + + dirent_ensure_type(d, de); + + if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d")) + enumerate_dir_d(top, bottom, drops, path, de->d_name); + + if (!dirent_is_file(de)) + continue; + + p = strjoin(path, "/", de->d_name, NULL); + if (!p) + return -ENOMEM; + + log_debug("Adding at top: %s → %s", basename(p), p); + k = hashmap_put(top, basename(p), p); + if (k >= 0) { + p = strdup(p); + if (!p) + return -ENOMEM; + } else if (k != -EEXIST) { + free(p); + return k; + } + + log_debug("Adding at bottom: %s → %s", basename(p), p); + free(hashmap_remove(bottom, basename(p))); + k = hashmap_put(bottom, basename(p), p); + if (k < 0) { + free(p); + return k; + } + } +} + +static int process_suffix(const char *suffix, const char *onlyprefix) { + const char *p; + char *f; + Hashmap *top, *bottom, *drops; + Hashmap *h; + char *key; + int r = 0, k; + Iterator i, j; + int n_found = 0; + bool dropins; + + assert(suffix); + assert(!startswith(suffix, "/")); + assert(!strstr(suffix, "//")); + + dropins = nulstr_contains(have_dropins, suffix); + + top = hashmap_new(string_hash_func, string_compare_func); + bottom = hashmap_new(string_hash_func, string_compare_func); + drops = hashmap_new(string_hash_func, string_compare_func); + if (!top || !bottom || !drops) { + r = -ENOMEM; + goto finish; + } + + NULSTR_FOREACH(p, prefixes) { + _cleanup_free_ char *t = NULL; + + t = strjoin(p, "/", suffix, NULL); + if (!t) { + r = -ENOMEM; + goto finish; + } + + k = enumerate_dir(top, bottom, drops, t, dropins); + if (r == 0) + r = k; + } + + HASHMAP_FOREACH_KEY(f, key, top, i) { + char *o; + + o = hashmap_get(bottom, key); + assert(o); + + if (!onlyprefix || startswith(o, onlyprefix)) { + if (path_equal(o, f)) { + notify_override_unchanged(f); + } else { + k = found_override(f, o); + if (k < 0) + r = k; + else + n_found += k; + } + } + + h = hashmap_get(drops, key); + if (h) + HASHMAP_FOREACH(o, h, j) + if (!onlyprefix || startswith(o, onlyprefix)) + n_found += notify_override_extended(f, o); + } + +finish: + if (top) + hashmap_free_free(top); + if (bottom) + hashmap_free_free(bottom); + if (drops) { + HASHMAP_FOREACH_KEY(h, key, drops, i){ + hashmap_free_free(hashmap_remove(drops, key)); + hashmap_remove(drops, key); + free(key); + } + hashmap_free(drops); + } + return r < 0 ? r : n_found; +} + +static int process_suffixes(const char *onlyprefix) { + const char *n; + int n_found = 0, r; + + NULSTR_FOREACH(n, suffixes) { + r = process_suffix(n, onlyprefix); + if (r < 0) + return r; + else + n_found += r; + } + return n_found; +} + +static int process_suffix_chop(const char *arg) { + const char *p; + + assert(arg); + + if (!path_is_absolute(arg)) + return process_suffix(arg, NULL); + + /* Strip prefix from the suffix */ + NULSTR_FOREACH(p, prefixes) { + const char *suffix = startswith(arg, p); + if (suffix) { + suffix += strspn(suffix, "/"); + if (*suffix) + return process_suffix(suffix, NULL); + else + return process_suffixes(arg); + } + } + + log_error("Invalid suffix specification %s.", arg); + return -EINVAL; +} + +static int help(void) { + + printf("%s [OPTIONS...] [SUFFIX...]\n\n" + "Find overridden configuration files.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --diff[=1|0] Show a diff when overridden files differ\n" + " -t --type=LIST... Only display a selected set of override types\n", + program_invocation_short_name); + + return 0; +} + +static int parse_flags(const char *flag_str, int flags) { + char *w, *state; + size_t l; + + FOREACH_WORD(w, l, flag_str, state) { + if (strneq("masked", w, l)) + flags |= SHOW_MASKED; + else if (strneq ("equivalent", w, l)) + flags |= SHOW_EQUIVALENT; + else if (strneq("redirected", w, l)) + flags |= SHOW_REDIRECTED; + else if (strneq("overridden", w, l)) + flags |= SHOW_OVERRIDDEN; + else if (strneq("unchanged", w, l)) + flags |= SHOW_UNCHANGED; + else if (strneq("extended", w, l)) + flags |= SHOW_EXTENDED; + else if (strneq("default", w, l)) + flags |= SHOW_DEFAULTS; + else + return -EINVAL; + } + return flags; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_NO_PAGER = 0x100, + ARG_DIFF, + ARG_VERSION + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "diff", optional_argument, NULL, ARG_DIFF }, + { "type", required_argument, NULL, 't' }, + {} + }; + + int c; + + assert(argc >= 1); + assert(argv); + + while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case 't': { + int f; + f = parse_flags(optarg, arg_flags); + if (f < 0) { + log_error("Failed to parse flags field."); + return -EINVAL; + } + arg_flags = f; + break; + } + + case ARG_DIFF: + if (!optarg) + arg_diff = 1; + else { + int b; + + b = parse_boolean(optarg); + if (b < 0) { + log_error("Failed to parse diff boolean."); + return -EINVAL; + } else if (b) + arg_diff = 1; + else + arg_diff = 0; + } + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r = 0, k; + int n_found = 0; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + if (arg_flags == 0) + arg_flags = SHOW_DEFAULTS; + + if (arg_diff < 0) + arg_diff = !!(arg_flags & SHOW_OVERRIDDEN); + else if (arg_diff) + arg_flags |= SHOW_OVERRIDDEN; + + pager_open_if_enabled(); + + if (optind < argc) { + int i; + + for (i = optind; i < argc; i++) { + path_kill_slashes(argv[i]); + k = process_suffix_chop(argv[i]); + if (k < 0) + r = k; + else + n_found += k; + } + + } else { + k = process_suffixes(NULL); + if (k < 0) + r = k; + else + n_found += k; + } + + if (r >= 0) + printf("%s%i overridden configuration files found.\n", + n_found ? "\n" : "", n_found); + +finish: + pager_close(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/detect-virt.c b/src/detect-virt.c deleted file mode 100644 index 79cad5d..0000000 --- a/src/detect-virt.c +++ /dev/null @@ -1,48 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "virt.h" - -int main(int argc, char *argv[]) { - Virtualization r; - const char *id; - - /* This is mostly intended to be used for scripts which want - * to detect whether we are being run in a virtualized - * environment or not */ - - r = detect_virtualization(&id); - if (r < 0) { - log_error("Failed to check for virtualization: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (r > 0) - puts(id); - - return r > 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/src/detect-virt/Makefile b/src/detect-virt/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/detect-virt/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c new file mode 100644 index 0000000..8cf8dcf --- /dev/null +++ b/src/detect-virt/detect-virt.c @@ -0,0 +1,169 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "virt.h" +#include "build.h" + +static bool arg_quiet = false; +static enum { + ANY_VIRTUALIZATION, + ONLY_VM, + ONLY_CONTAINER +} arg_mode = ANY_VIRTUALIZATION; + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Detect execution in a virtualized environment.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " -c --container Only detect whether we are run in a container\n" + " -v --vm Only detect whether we are run in a VM\n" + " -q --quiet Don't output anything, just set return value\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100 + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "container", no_argument, NULL, 'c' }, + { "vm", optional_argument, NULL, 'v' }, + { "quiet", no_argument, NULL, 'q' }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'q': + arg_quiet = true; + break; + + case 'c': + arg_mode = ONLY_CONTAINER; + break; + + case 'v': + arg_mode = ONLY_VM; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind < argc) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + const char *id = NULL; + int retval = EXIT_SUCCESS; + int r; + + /* This is mostly intended to be used for scripts which want + * to detect whether we are being run in a virtualized + * environment or not */ + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + switch (arg_mode) { + + case ANY_VIRTUALIZATION: { + int v; + + v = detect_virtualization(&id); + if (v < 0) { + log_error("Failed to check for virtualization: %s", strerror(-v)); + return EXIT_FAILURE; + } + + retval = v != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE; + break; + } + + case ONLY_CONTAINER: + r = detect_container(&id); + if (r < 0) { + log_error("Failed to check for container: %s", strerror(-r)); + return EXIT_FAILURE; + } + + retval = r > 0 ? EXIT_SUCCESS : EXIT_FAILURE; + break; + + case ONLY_VM: + r = detect_vm(&id); + if (r < 0) { + log_error("Failed to check for vm: %s", strerror(-r)); + return EXIT_FAILURE; + } + + retval = r > 0 ? EXIT_SUCCESS : EXIT_FAILURE; + break; + } + + if (!arg_quiet) + puts(id ? id : "none"); + + return retval; +} diff --git a/src/device.c b/src/device.c deleted file mode 100644 index bffeca0..0000000 --- a/src/device.c +++ /dev/null @@ -1,613 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "unit.h" -#include "device.h" -#include "strv.h" -#include "log.h" -#include "unit-name.h" -#include "dbus-device.h" -#include "def.h" - -static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { - [DEVICE_DEAD] = UNIT_INACTIVE, - [DEVICE_PLUGGED] = UNIT_ACTIVE -}; - -static void device_unset_sysfs(Device *d) { - Device *first; - - assert(d); - - if (!d->sysfs) - return; - - /* Remove this unit from the chain of devices which share the - * same sysfs path. */ - first = hashmap_get(d->meta.manager->devices_by_sysfs, d->sysfs); - LIST_REMOVE(Device, same_sysfs, first, d); - - if (first) - hashmap_remove_and_replace(d->meta.manager->devices_by_sysfs, d->sysfs, first->sysfs, first); - else - hashmap_remove(d->meta.manager->devices_by_sysfs, d->sysfs); - - free(d->sysfs); - d->sysfs = NULL; -} - -static void device_init(Unit *u) { - Device *d = DEVICE(u); - - assert(d); - assert(d->meta.load_state == UNIT_STUB); - - /* In contrast to all other unit types we timeout jobs waiting - * for devices by default. This is because they otherwise wait - * indefinitely for plugged in devices, something which cannot - * happen for the other units since their operations time out - * anyway. */ - d->meta.job_timeout = DEFAULT_TIMEOUT_USEC; - - d->meta.ignore_on_isolate = true; - d->meta.ignore_on_snapshot = true; -} - -static void device_done(Unit *u) { - Device *d = DEVICE(u); - - assert(d); - - device_unset_sysfs(d); -} - -static void device_set_state(Device *d, DeviceState state) { - DeviceState old_state; - assert(d); - - old_state = d->state; - d->state = state; - - if (state != old_state) - log_debug("%s changed %s -> %s", - d->meta.id, - device_state_to_string(old_state), - device_state_to_string(state)); - - unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true); -} - -static int device_coldplug(Unit *u) { - Device *d = DEVICE(u); - - assert(d); - assert(d->state == DEVICE_DEAD); - - if (d->sysfs) - device_set_state(d, DEVICE_PLUGGED); - - return 0; -} - -static void device_dump(Unit *u, FILE *f, const char *prefix) { - Device *d = DEVICE(u); - - assert(d); - - fprintf(f, - "%sDevice State: %s\n" - "%sSysfs Path: %s\n", - prefix, device_state_to_string(d->state), - prefix, strna(d->sysfs)); -} - -static UnitActiveState device_active_state(Unit *u) { - assert(u); - - return state_translation_table[DEVICE(u)->state]; -} - -static const char *device_sub_state_to_string(Unit *u) { - assert(u); - - return device_state_to_string(DEVICE(u)->state); -} - -static int device_add_escaped_name(Unit *u, const char *dn) { - char *e; - int r; - - assert(u); - assert(dn); - assert(dn[0] == '/'); - - if (!(e = unit_name_from_path(dn, ".device"))) - return -ENOMEM; - - r = unit_add_name(u, e); - free(e); - - if (r < 0 && r != -EEXIST) - return r; - - return 0; -} - -static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) { - char *e; - Unit *u; - - assert(m); - assert(dn); - assert(dn[0] == '/'); - assert(_u); - - if (!(e = unit_name_from_path(dn, ".device"))) - return -ENOMEM; - - u = manager_get_unit(m, e); - free(e); - - if (u) { - *_u = u; - return 1; - } - - return 0; -} - -static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { - const char *sysfs, *model; - Unit *u = NULL; - int r; - bool delete; - - assert(m); - - if (!(sysfs = udev_device_get_syspath(dev))) - return -ENOMEM; - - if ((r = device_find_escape_name(m, path, &u)) < 0) - return r; - - if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs)) - return -EEXIST; - - if (!u) { - delete = true; - - if (!(u = unit_new(m))) - return -ENOMEM; - - if ((r = device_add_escaped_name(u, path)) < 0) - goto fail; - - unit_add_to_load_queue(u); - } else - delete = false; - - /* If this was created via some dependency and has not - * actually been seen yet ->sysfs will not be - * initialized. Hence initialize it if necessary. */ - - if (!DEVICE(u)->sysfs) { - Device *first; - - if (!(DEVICE(u)->sysfs = strdup(sysfs))) { - r = -ENOMEM; - goto fail; - } - - if (!m->devices_by_sysfs) - if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) { - r = -ENOMEM; - goto fail; - } - - first = hashmap_get(m->devices_by_sysfs, sysfs); - LIST_PREPEND(Device, same_sysfs, first, DEVICE(u)); - - if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 0) - goto fail; - } - - if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) || - (model = udev_device_get_property_value(dev, "ID_MODEL"))) { - if ((r = unit_set_description(u, model)) < 0) - goto fail; - } else - if ((r = unit_set_description(u, path)) < 0) - goto fail; - - if (main) { - /* The additional systemd udev properties we only - * interpret for the main object */ - const char *wants, *alias; - - if ((alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS"))) { - if (!is_path(alias)) - log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, alias); - else { - if ((r = device_add_escaped_name(u, alias)) < 0) - goto fail; - } - } - - if ((wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS"))) { - char *state, *w; - size_t l; - - FOREACH_WORD_QUOTED(w, l, wants, state) { - char *e; - - if (!(e = strndup(w, l))) { - r = -ENOMEM; - goto fail; - } - - r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true); - free(e); - - if (r < 0) - goto fail; - } - } - } - - unit_add_to_dbus_queue(u); - return 0; - -fail: - log_warning("Failed to load device unit: %s", strerror(-r)); - - if (delete && u) - unit_free(u); - - return r; -} - -static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) { - const char *sysfs, *dn; - struct udev_list_entry *item = NULL, *first = NULL; - - assert(m); - - if (!(sysfs = udev_device_get_syspath(dev))) - return -ENOMEM; - - /* Add the main unit named after the sysfs path */ - device_update_unit(m, dev, sysfs, true); - - /* Add an additional unit for the device node */ - if ((dn = udev_device_get_devnode(dev))) - device_update_unit(m, dev, dn, false); - - /* Add additional units for all symlinks */ - first = udev_device_get_devlinks_list_entry(dev); - udev_list_entry_foreach(item, first) { - const char *p; - struct stat st; - - /* Don't bother with the /dev/block links */ - p = udev_list_entry_get_name(item); - - if (path_startswith(p, "/dev/block/") || - path_startswith(p, "/dev/char/")) - continue; - - /* Verify that the symlink in the FS actually belongs - * to this device. This is useful to deal with - * conflicting devices, e.g. when two disks want the - * same /dev/disk/by-label/xxx link because they have - * the same label. We want to make sure that the same - * device that won the symlink wins in systemd, so we - * check the device node major/minor*/ - if (stat(p, &st) >= 0) - if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) || - st.st_rdev != udev_device_get_devnum(dev)) - continue; - - device_update_unit(m, dev, p, false); - } - - if (update_state) { - Device *d, *l; - - manager_dispatch_load_queue(m); - - l = hashmap_get(m->devices_by_sysfs, sysfs); - LIST_FOREACH(same_sysfs, d, l) - device_set_state(d, DEVICE_PLUGGED); - } - - return 0; -} - -static int device_process_path(Manager *m, const char *path, bool update_state) { - int r; - struct udev_device *dev; - - assert(m); - assert(path); - - if (!(dev = udev_device_new_from_syspath(m->udev, path))) { - log_warning("Failed to get udev device object from udev for path %s.", path); - return -ENOMEM; - } - - r = device_process_new_device(m, dev, update_state); - udev_device_unref(dev); - return r; -} - -static int device_process_removed_device(Manager *m, struct udev_device *dev) { - const char *sysfs; - Device *d; - - assert(m); - assert(dev); - - if (!(sysfs = udev_device_get_syspath(dev))) - return -ENOMEM; - - /* Remove all units of this sysfs path */ - while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) { - device_unset_sysfs(d); - device_set_state(d, DEVICE_DEAD); - } - - return 0; -} - -static Unit *device_following(Unit *u) { - Device *d = DEVICE(u); - Device *other, *first = NULL; - - assert(d); - - if (startswith(u->meta.id, "sys-")) - return NULL; - - /* Make everybody follow the unit that's named after the sysfs path */ - for (other = d->same_sysfs_next; other; other = other->same_sysfs_next) - if (startswith(other->meta.id, "sys-")) - return UNIT(other); - - for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) { - if (startswith(other->meta.id, "sys-")) - return UNIT(other); - - first = other; - } - - return UNIT(first); -} - -static int device_following_set(Unit *u, Set **_s) { - Device *d = DEVICE(u); - Device *other; - Set *s; - int r; - - assert(d); - assert(_s); - - if (!d->same_sysfs_prev && !d->same_sysfs_next) { - *_s = NULL; - return 0; - } - - if (!(s = set_new(NULL, NULL))) - return -ENOMEM; - - for (other = d->same_sysfs_next; other; other = other->same_sysfs_next) - if ((r = set_put(s, other)) < 0) - goto fail; - - for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) - if ((r = set_put(s, other)) < 0) - goto fail; - - *_s = s; - return 1; - -fail: - set_free(s); - return r; -} - -static void device_shutdown(Manager *m) { - assert(m); - - if (m->udev_monitor) { - udev_monitor_unref(m->udev_monitor); - m->udev_monitor = NULL; - } - - if (m->udev) { - udev_unref(m->udev); - m->udev = NULL; - } - - hashmap_free(m->devices_by_sysfs); - m->devices_by_sysfs = NULL; -} - -static int device_enumerate(Manager *m) { - struct epoll_event ev; - int r; - struct udev_enumerate *e = NULL; - struct udev_list_entry *item = NULL, *first = NULL; - - assert(m); - - if (!m->udev) { - if (!(m->udev = udev_new())) - return -ENOMEM; - - if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) { - r = -ENOMEM; - goto fail; - } - - /* This will fail if we are unprivileged, but that - * should not matter much, as user instances won't run - * during boot. */ - udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024); - - if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) { - r = -ENOMEM; - goto fail; - } - - if (udev_monitor_enable_receiving(m->udev_monitor) < 0) { - r = -EIO; - goto fail; - } - - m->udev_watch.type = WATCH_UDEV; - m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor); - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = &m->udev_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0) - return -errno; - } - - if (!(e = udev_enumerate_new(m->udev))) { - r = -ENOMEM; - goto fail; - } - if (udev_enumerate_add_match_tag(e, "systemd") < 0) { - r = -EIO; - goto fail; - } - - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; - goto fail; - } - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) - device_process_path(m, udev_list_entry_get_name(item), false); - - udev_enumerate_unref(e); - return 0; - -fail: - if (e) - udev_enumerate_unref(e); - - device_shutdown(m); - return r; -} - -void device_fd_event(Manager *m, int events) { - struct udev_device *dev; - int r; - const char *action, *ready; - - assert(m); - - if (events != EPOLLIN) { - static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5); - - if (!ratelimit_test(&limit)) - log_error("Failed to get udev event: %m"); - if (!(events & EPOLLIN)) - return; - } - - if (!(dev = udev_monitor_receive_device(m->udev_monitor))) { - /* - * libudev might filter-out devices which pass the bloom filter, - * so getting NULL here is not necessarily an error - */ - return; - } - - if (!(action = udev_device_get_action(dev))) { - log_error("Failed to get udev action string."); - goto fail; - } - - ready = udev_device_get_property_value(dev, "SYSTEMD_READY"); - - if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) { - if ((r = device_process_removed_device(m, dev)) < 0) { - log_error("Failed to process udev device event: %s", strerror(-r)); - goto fail; - } - } else { - if ((r = device_process_new_device(m, dev, true)) < 0) { - log_error("Failed to process udev device event: %s", strerror(-r)); - goto fail; - } - } - -fail: - udev_device_unref(dev); -} - -static const char* const device_state_table[_DEVICE_STATE_MAX] = { - [DEVICE_DEAD] = "dead", - [DEVICE_PLUGGED] = "plugged" -}; - -DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); - -const UnitVTable device_vtable = { - .suffix = ".device", - .sections = - "Unit\0" - "Device\0" - "Install\0", - - .no_instances = true, - - .init = device_init, - - .load = unit_load_fragment_and_dropin_optional, - .done = device_done, - .coldplug = device_coldplug, - - .dump = device_dump, - - .active_state = device_active_state, - .sub_state_to_string = device_sub_state_to_string, - - .bus_interface = "org.freedesktop.systemd1.Device", - .bus_message_handler = bus_device_message_handler, - .bus_invalidating_properties = bus_device_invalidating_properties, - - .following = device_following, - .following_set = device_following_set, - - .enumerate = device_enumerate, - .shutdown = device_shutdown -}; diff --git a/src/device.h b/src/device.h deleted file mode 100644 index 9a56a52..0000000 --- a/src/device.h +++ /dev/null @@ -1,59 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foodevicehfoo -#define foodevicehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Device Device; - -#include "unit.h" - -/* We simply watch devices, we cannot plug/unplug them. That - * simplifies the state engine greatly */ -typedef enum DeviceState { - DEVICE_DEAD, - DEVICE_PLUGGED, - _DEVICE_STATE_MAX, - _DEVICE_STATE_INVALID = -1 -} DeviceState; - -struct Device { - Meta meta; - - char *sysfs; - - /* In order to be able to distinguish dependencies on - different device nodes we might end up creating multiple - devices for the same sysfs path. We chain them up here. */ - - LIST_FIELDS(struct Device, same_sysfs); - - DeviceState state; -}; - -extern const UnitVTable device_vtable; - -void device_fd_event(Manager *m, int events); - -const char* device_state_to_string(DeviceState i); -DeviceState device_state_from_string(const char *s); - -#endif diff --git a/src/efi-boot-generator/Makefile b/src/efi-boot-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/efi-boot-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/efi-boot-generator/efi-boot-generator.c b/src/efi-boot-generator/efi-boot-generator.c new file mode 100644 index 0000000..606d35b --- /dev/null +++ b/src/efi-boot-generator/efi-boot-generator.c @@ -0,0 +1,124 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "efivars.h" +#include "path-util.h" +#include "util.h" +#include "mkdir.h" +#include "unit-name.h" + +static const char *arg_dest = "/tmp"; + +int main(int argc, char *argv[]) { + int r = EXIT_SUCCESS; + sd_id128_t id; + _cleanup_free_ char *what = NULL, *fsck = NULL; + char *name; + _cleanup_fclose_ FILE *f = NULL, *f2 = NULL; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[3]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (!is_efi_boot()) + return EXIT_SUCCESS; + + if (dir_is_empty("/boot") <= 0) + return EXIT_SUCCESS; + + r = efi_loader_get_device_part_uuid(&id); + if (r == -ENOENT) + return EXIT_SUCCESS; + if (r < 0) { + log_error("Failed to read ESP partition UUID: %s", strerror(-r)); + return EXIT_FAILURE; + } + + name = strappenda(arg_dest, "/boot.mount"); + f = fopen(name, "wxe"); + if (!f) { + log_error("Failed to create mount unit file %s: %m", name); + return EXIT_FAILURE; + } + + r = asprintf(&what, + "/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + SD_ID128_FORMAT_VAL(id)); + if (r < 0) { + log_oom(); + return EXIT_FAILURE; + } + + fsck = unit_name_from_path_instance("systemd-fsck", what, ".service"); + if (!fsck) { + log_oom(); + return EXIT_FAILURE; + } + + fprintf(f, + "# Automatially generated by systemd-efi-boot-generator\n\n" + "[Unit]\n" + "Description=EFI System Partition\n" + "Requires=%s\n" + "After=%s\n" + "\n" + "[Mount]\n" + "Where=/boot\n" + "What=%s\n" + "Options=umask=0077,noauto\n", + fsck, fsck, what); + + name = strappenda(arg_dest, "/boot.automount"); + f2 = fopen(name, "wxe"); + if (!f2) { + log_error("Failed to create automount unit file %s: %m", name); + return EXIT_FAILURE; + } + + fputs("# Automatially generated by systemd-efi-boot-generator\n\n" + "[Unit]\n" + "Description=EFI System Partition Automount\n\n" + "[Automount]\n" + "Where=/boot\n", f2); + + name = strappenda(arg_dest, "/local-fs.target.wants/boot.automount"); + mkdir_parents(name, 0755); + + if (symlink("../boot.automount", name) < 0) { + log_error("Failed to create symlink %s: %m", name); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/execute.c b/src/execute.c deleted file mode 100644 index 53e7e77..0000000 --- a/src/execute.c +++ /dev/null @@ -1,1997 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PAM -#include -#endif - -#include "execute.h" -#include "strv.h" -#include "macro.h" -#include "util.h" -#include "log.h" -#include "ioprio.h" -#include "securebits.h" -#include "cgroup.h" -#include "namespace.h" -#include "tcpwrap.h" -#include "exit-status.h" -#include "missing.h" -#include "utmp-wtmp.h" -#include "def.h" -#include "loopback-setup.h" - -/* This assumes there is a 'tty' group */ -#define TTY_MODE 0620 - -static int shift_fds(int fds[], unsigned n_fds) { - int start, restart_from; - - if (n_fds <= 0) - return 0; - - /* Modifies the fds array! (sorts it) */ - - assert(fds); - - start = 0; - for (;;) { - int i; - - restart_from = -1; - - for (i = start; i < (int) n_fds; i++) { - int nfd; - - /* Already at right index? */ - if (fds[i] == i+3) - continue; - - if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0) - return -errno; - - close_nointr_nofail(fds[i]); - fds[i] = nfd; - - /* Hmm, the fd we wanted isn't free? Then - * let's remember that and try again from here*/ - if (nfd != i+3 && restart_from < 0) - restart_from = i; - } - - if (restart_from < 0) - break; - - start = restart_from; - } - - return 0; -} - -static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) { - unsigned i; - int r; - - if (n_fds <= 0) - return 0; - - assert(fds); - - /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */ - - for (i = 0; i < n_fds; i++) { - - if ((r = fd_nonblock(fds[i], nonblock)) < 0) - return r; - - /* We unconditionally drop FD_CLOEXEC from the fds, - * since after all we want to pass these fds to our - * children */ - - if ((r = fd_cloexec(fds[i], false)) < 0) - return r; - } - - return 0; -} - -static const char *tty_path(const ExecContext *context) { - assert(context); - - if (context->tty_path) - return context->tty_path; - - return "/dev/console"; -} - -void exec_context_tty_reset(const ExecContext *context) { - assert(context); - - if (context->tty_vhangup) - terminal_vhangup(tty_path(context)); - - if (context->tty_reset) - reset_terminal(tty_path(context)); - - if (context->tty_vt_disallocate && context->tty_path) - vt_disallocate(context->tty_path); -} - -static int open_null_as(int flags, int nfd) { - int fd, r; - - assert(nfd >= 0); - - if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0) - return -errno; - - if (fd != nfd) { - r = dup2(fd, nfd) < 0 ? -errno : nfd; - close_nointr_nofail(fd); - } else - r = nfd; - - return r; -} - -static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) { - int fd, r; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - - assert(context); - assert(output < _EXEC_OUTPUT_MAX); - assert(ident); - assert(nfd >= 0); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -errno; - - zero(sa); - sa.sa.sa_family = AF_UNIX; - strncpy(sa.un.sun_path, STDOUT_SYSLOG_BRIDGE_SOCKET, sizeof(sa.un.sun_path)); - - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + sizeof(STDOUT_SYSLOG_BRIDGE_SOCKET) - 1) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - if (shutdown(fd, SHUT_RD) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - /* We speak a very simple protocol between log server - * and client: one line for the log destination (kmsg - * or syslog), followed by the priority field, - * followed by the process name. Since we replaced - * stdin/stderr we simple use stdio to write to - * it. Note that we use stderr, to minimize buffer - * flushing issues. */ - - dprintf(fd, - "%s\n" - "%i\n" - "%s\n" - "%i\n", - output == EXEC_OUTPUT_KMSG ? "kmsg" : - output == EXEC_OUTPUT_KMSG_AND_CONSOLE ? "kmsg+console" : - output == EXEC_OUTPUT_SYSLOG ? "syslog" : - "syslog+console", - context->syslog_priority, - context->syslog_identifier ? context->syslog_identifier : ident, - context->syslog_level_prefix); - - if (fd != nfd) { - r = dup2(fd, nfd) < 0 ? -errno : nfd; - close_nointr_nofail(fd); - } else - r = nfd; - - return r; -} -static int open_terminal_as(const char *path, mode_t mode, int nfd) { - int fd, r; - - assert(path); - assert(nfd >= 0); - - if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0) - return fd; - - if (fd != nfd) { - r = dup2(fd, nfd) < 0 ? -errno : nfd; - close_nointr_nofail(fd); - } else - r = nfd; - - return r; -} - -static bool is_terminal_input(ExecInput i) { - return - i == EXEC_INPUT_TTY || - i == EXEC_INPUT_TTY_FORCE || - i == EXEC_INPUT_TTY_FAIL; -} - -static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) { - - if (is_terminal_input(std_input) && !apply_tty_stdin) - return EXEC_INPUT_NULL; - - if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0) - return EXEC_INPUT_NULL; - - return std_input; -} - -static int fixup_output(ExecOutput std_output, int socket_fd) { - - if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0) - return EXEC_OUTPUT_INHERIT; - - return std_output; -} - -static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) { - ExecInput i; - - assert(context); - - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); - - switch (i) { - - case EXEC_INPUT_NULL: - return open_null_as(O_RDONLY, STDIN_FILENO); - - case EXEC_INPUT_TTY: - case EXEC_INPUT_TTY_FORCE: - case EXEC_INPUT_TTY_FAIL: { - int fd, r; - - if ((fd = acquire_terminal( - tty_path(context), - i == EXEC_INPUT_TTY_FAIL, - i == EXEC_INPUT_TTY_FORCE, - false)) < 0) - return fd; - - if (fd != STDIN_FILENO) { - r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO; - close_nointr_nofail(fd); - } else - r = STDIN_FILENO; - - return r; - } - - case EXEC_INPUT_SOCKET: - return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO; - - default: - assert_not_reached("Unknown input type"); - } -} - -static int setup_output(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) { - ExecOutput o; - ExecInput i; - - assert(context); - assert(ident); - - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); - o = fixup_output(context->std_output, socket_fd); - - /* This expects the input is already set up */ - - switch (o) { - - case EXEC_OUTPUT_INHERIT: - - /* If input got downgraded, inherit the original value */ - if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) - return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO); - - /* If the input is connected to anything that's not a /dev/null, inherit that... */ - if (i != EXEC_INPUT_NULL) - return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; - - /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ - if (getppid() != 1) - return STDOUT_FILENO; - - /* We need to open /dev/null here anew, to get the - * right access mode. So we fall through */ - - case EXEC_OUTPUT_NULL: - return open_null_as(O_WRONLY, STDOUT_FILENO); - - case EXEC_OUTPUT_TTY: - if (is_terminal_input(i)) - return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; - - /* We don't reset the terminal if this is just about output */ - return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO); - - case EXEC_OUTPUT_SYSLOG: - case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: - case EXEC_OUTPUT_KMSG: - case EXEC_OUTPUT_KMSG_AND_CONSOLE: - return connect_logger_as(context, o, ident, STDOUT_FILENO); - - case EXEC_OUTPUT_SOCKET: - assert(socket_fd >= 0); - return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO; - - default: - assert_not_reached("Unknown output type"); - } -} - -static int setup_error(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) { - ExecOutput o, e; - ExecInput i; - - assert(context); - assert(ident); - - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); - o = fixup_output(context->std_output, socket_fd); - e = fixup_output(context->std_error, socket_fd); - - /* This expects the input and output are already set up */ - - /* Don't change the stderr file descriptor if we inherit all - * the way and are not on a tty */ - if (e == EXEC_OUTPUT_INHERIT && - o == EXEC_OUTPUT_INHERIT && - i == EXEC_INPUT_NULL && - !is_terminal_input(context->std_input) && - getppid () != 1) - return STDERR_FILENO; - - /* Duplicate from stdout if possible */ - if (e == o || e == EXEC_OUTPUT_INHERIT) - return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; - - switch (e) { - - case EXEC_OUTPUT_NULL: - return open_null_as(O_WRONLY, STDERR_FILENO); - - case EXEC_OUTPUT_TTY: - if (is_terminal_input(i)) - return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; - - /* We don't reset the terminal if this is just about output */ - return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO); - - case EXEC_OUTPUT_SYSLOG: - case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: - case EXEC_OUTPUT_KMSG: - case EXEC_OUTPUT_KMSG_AND_CONSOLE: - return connect_logger_as(context, e, ident, STDERR_FILENO); - - case EXEC_OUTPUT_SOCKET: - assert(socket_fd >= 0); - return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; - - default: - assert_not_reached("Unknown error type"); - } -} - -static int chown_terminal(int fd, uid_t uid) { - struct stat st; - - assert(fd >= 0); - - /* This might fail. What matters are the results. */ - (void) fchown(fd, uid, -1); - (void) fchmod(fd, TTY_MODE); - - if (fstat(fd, &st) < 0) - return -errno; - - if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE) - return -EPERM; - - return 0; -} - -static int setup_confirm_stdio(const ExecContext *context, - int *_saved_stdin, - int *_saved_stdout) { - int fd = -1, saved_stdin, saved_stdout = -1, r; - - assert(context); - assert(_saved_stdin); - assert(_saved_stdout); - - /* This returns positive EXIT_xxx return values instead of - * negative errno style values! */ - - if ((saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3)) < 0) - return EXIT_STDIN; - - if ((saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3)) < 0) { - r = EXIT_STDOUT; - goto fail; - } - - if ((fd = acquire_terminal( - tty_path(context), - context->std_input == EXEC_INPUT_TTY_FAIL, - context->std_input == EXEC_INPUT_TTY_FORCE, - false)) < 0) { - r = EXIT_STDIN; - goto fail; - } - - if (chown_terminal(fd, getuid()) < 0) { - r = EXIT_STDIN; - goto fail; - } - - if (dup2(fd, STDIN_FILENO) < 0) { - r = EXIT_STDIN; - goto fail; - } - - if (dup2(fd, STDOUT_FILENO) < 0) { - r = EXIT_STDOUT; - goto fail; - } - - if (fd >= 2) - close_nointr_nofail(fd); - - *_saved_stdin = saved_stdin; - *_saved_stdout = saved_stdout; - - return 0; - -fail: - if (saved_stdout >= 0) - close_nointr_nofail(saved_stdout); - - if (saved_stdin >= 0) - close_nointr_nofail(saved_stdin); - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int restore_confirm_stdio(const ExecContext *context, - int *saved_stdin, - int *saved_stdout, - bool *keep_stdin, - bool *keep_stdout) { - - assert(context); - assert(saved_stdin); - assert(*saved_stdin >= 0); - assert(saved_stdout); - assert(*saved_stdout >= 0); - - /* This returns positive EXIT_xxx return values instead of - * negative errno style values! */ - - if (is_terminal_input(context->std_input)) { - - /* The service wants terminal input. */ - - *keep_stdin = true; - *keep_stdout = - context->std_output == EXEC_OUTPUT_INHERIT || - context->std_output == EXEC_OUTPUT_TTY; - - } else { - /* If the service doesn't want a controlling terminal, - * then we need to get rid entirely of what we have - * already. */ - - if (release_terminal() < 0) - return EXIT_STDIN; - - if (dup2(*saved_stdin, STDIN_FILENO) < 0) - return EXIT_STDIN; - - if (dup2(*saved_stdout, STDOUT_FILENO) < 0) - return EXIT_STDOUT; - - *keep_stdout = *keep_stdin = false; - } - - return 0; -} - -static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) { - bool keep_groups = false; - int r; - - assert(context); - - /* Lookup and set GID and supplementary group list. Here too - * we avoid NSS lookups for gid=0. */ - - if (context->group || username) { - - if (context->group) { - const char *g = context->group; - - if ((r = get_group_creds(&g, &gid)) < 0) - return r; - } - - /* First step, initialize groups from /etc/groups */ - if (username && gid != 0) { - if (initgroups(username, gid) < 0) - return -errno; - - keep_groups = true; - } - - /* Second step, set our gids */ - if (setresgid(gid, gid, gid) < 0) - return -errno; - } - - if (context->supplementary_groups) { - int ngroups_max, k; - gid_t *gids; - char **i; - - /* Final step, initialize any manually set supplementary groups */ - assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0); - - if (!(gids = new(gid_t, ngroups_max))) - return -ENOMEM; - - if (keep_groups) { - if ((k = getgroups(ngroups_max, gids)) < 0) { - free(gids); - return -errno; - } - } else - k = 0; - - STRV_FOREACH(i, context->supplementary_groups) { - const char *g; - - if (k >= ngroups_max) { - free(gids); - return -E2BIG; - } - - g = *i; - r = get_group_creds(&g, gids+k); - if (r < 0) { - free(gids); - return r; - } - - k++; - } - - if (setgroups(k, gids) < 0) { - free(gids); - return -errno; - } - - free(gids); - } - - return 0; -} - -static int enforce_user(const ExecContext *context, uid_t uid) { - int r; - assert(context); - - /* Sets (but doesn't lookup) the uid and make sure we keep the - * capabilities while doing so. */ - - if (context->capabilities) { - cap_t d; - static const cap_value_t bits[] = { - CAP_SETUID, /* Necessary so that we can run setresuid() below */ - CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ - }; - - /* First step: If we need to keep capabilities but - * drop privileges we need to make sure we keep our - * caps, whiel we drop privileges. */ - if (uid != 0) { - int sb = context->secure_bits|SECURE_KEEP_CAPS; - - if (prctl(PR_GET_SECUREBITS) != sb) - if (prctl(PR_SET_SECUREBITS, sb) < 0) - return -errno; - } - - /* Second step: set the capabilities. This will reduce - * the capabilities to the minimum we need. */ - - if (!(d = cap_dup(context->capabilities))) - return -errno; - - if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || - cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) { - r = -errno; - cap_free(d); - return r; - } - - if (cap_set_proc(d) < 0) { - r = -errno; - cap_free(d); - return r; - } - - cap_free(d); - } - - /* Third step: actually set the uids */ - if (setresuid(uid, uid, uid) < 0) - return -errno; - - /* At this point we should have all necessary capabilities but - are otherwise a normal user. However, the caps might got - corrupted due to the setresuid() so we need clean them up - later. This is done outside of this call. */ - - return 0; -} - -#ifdef HAVE_PAM - -static int null_conv( - int num_msg, - const struct pam_message **msg, - struct pam_response **resp, - void *appdata_ptr) { - - /* We don't support conversations */ - - return PAM_CONV_ERR; -} - -static int setup_pam( - const char *name, - const char *user, - const char *tty, - char ***pam_env, - int fds[], unsigned n_fds) { - - static const struct pam_conv conv = { - .conv = null_conv, - .appdata_ptr = NULL - }; - - pam_handle_t *handle = NULL; - sigset_t ss, old_ss; - int pam_code = PAM_SUCCESS; - char **e = NULL; - bool close_session = false; - pid_t pam_pid = 0, parent_pid; - - assert(name); - assert(user); - assert(pam_env); - - /* We set up PAM in the parent process, then fork. The child - * will then stay around until killed via PR_GET_PDEATHSIG or - * systemd via the cgroup logic. It will then remove the PAM - * session again. The parent process will exec() the actual - * daemon. We do things this way to ensure that the main PID - * of the daemon is the one we initially fork()ed. */ - - if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) { - handle = NULL; - goto fail; - } - - if (tty) - if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS) - goto fail; - - if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS) - goto fail; - - if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS) - goto fail; - - close_session = true; - - if ((!(e = pam_getenvlist(handle)))) { - pam_code = PAM_BUF_ERR; - goto fail; - } - - /* Block SIGTERM, so that we know that it won't get lost in - * the child */ - if (sigemptyset(&ss) < 0 || - sigaddset(&ss, SIGTERM) < 0 || - sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0) - goto fail; - - parent_pid = getpid(); - - if ((pam_pid = fork()) < 0) - goto fail; - - if (pam_pid == 0) { - int sig; - int r = EXIT_PAM; - - /* The child's job is to reset the PAM session on - * termination */ - - /* This string must fit in 10 chars (i.e. the length - * of "/sbin/init") */ - rename_process("sd(PAM)"); - - /* Make sure we don't keep open the passed fds in this - child. We assume that otherwise only those fds are - open here that have been opened by PAM. */ - close_many(fds, n_fds); - - /* Wait until our parent died. This will most likely - * not work since the kernel does not allow - * unprivileged parents kill their privileged children - * this way. We rely on the control groups kill logic - * to do the rest for us. */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - goto child_finish; - - /* Check if our parent process might already have - * died? */ - if (getppid() == parent_pid) { - for (;;) { - if (sigwait(&ss, &sig) < 0) { - if (errno == EINTR) - continue; - - goto child_finish; - } - - assert(sig == SIGTERM); - break; - } - } - - /* If our parent died we'll end the session */ - if (getppid() != parent_pid) - if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS) - goto child_finish; - - r = 0; - - child_finish: - pam_end(handle, pam_code | PAM_DATA_SILENT); - _exit(r); - } - - /* If the child was forked off successfully it will do all the - * cleanups, so forget about the handle here. */ - handle = NULL; - - /* Unblock SIGTERM again in the parent */ - if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0) - goto fail; - - /* We close the log explicitly here, since the PAM modules - * might have opened it, but we don't want this fd around. */ - closelog(); - - *pam_env = e; - e = NULL; - - return 0; - -fail: - if (handle) { - if (close_session) - pam_code = pam_close_session(handle, PAM_DATA_SILENT); - - pam_end(handle, pam_code | PAM_DATA_SILENT); - } - - strv_free(e); - - closelog(); - - if (pam_pid > 1) { - kill(pam_pid, SIGTERM); - kill(pam_pid, SIGCONT); - } - - return EXIT_PAM; -} -#endif - -static int do_capability_bounding_set_drop(uint64_t drop) { - unsigned long i; - cap_t old_cap = NULL, new_cap = NULL; - cap_flag_value_t fv; - int r; - - /* If we are run as PID 1 we will lack CAP_SETPCAP by default - * in the effective set (yes, the kernel drops that when - * executing init!), so get it back temporarily so that we can - * call PR_CAPBSET_DROP. */ - - old_cap = cap_get_proc(); - if (!old_cap) - return -errno; - - if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { - r = -errno; - goto finish; - } - - if (fv != CAP_SET) { - static const cap_value_t v = CAP_SETPCAP; - - new_cap = cap_dup(old_cap); - if (!new_cap) { - r = -errno; - goto finish; - } - - if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { - r = -errno; - goto finish; - } - - if (cap_set_proc(new_cap) < 0) { - r = -errno; - goto finish; - } - } - - for (i = 0; i <= MAX(63LU, (unsigned long) CAP_LAST_CAP); i++) - if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { - if (prctl(PR_CAPBSET_DROP, i) < 0) { - if (errno == EINVAL) - break; - - r = -errno; - goto finish; - } - } - - r = 0; - -finish: - if (new_cap) - cap_free(new_cap); - - if (old_cap) { - cap_set_proc(old_cap); - cap_free(old_cap); - } - - return r; -} - -int exec_spawn(ExecCommand *command, - char **argv, - const ExecContext *context, - int fds[], unsigned n_fds, - char **environment, - bool apply_permissions, - bool apply_chroot, - bool apply_tty_stdin, - bool confirm_spawn, - CGroupBonding *cgroup_bondings, - CGroupAttribute *cgroup_attributes, - pid_t *ret) { - - pid_t pid; - int r; - char *line; - int socket_fd; - char **files_env = NULL; - - assert(command); - assert(context); - assert(ret); - assert(fds || n_fds <= 0); - - if (context->std_input == EXEC_INPUT_SOCKET || - context->std_output == EXEC_OUTPUT_SOCKET || - context->std_error == EXEC_OUTPUT_SOCKET) { - - if (n_fds != 1) - return -EINVAL; - - socket_fd = fds[0]; - - fds = NULL; - n_fds = 0; - } else - socket_fd = -1; - - if ((r = exec_context_load_environment(context, &files_env)) < 0) { - log_error("Failed to load environment files: %s", strerror(-r)); - return r; - } - - if (!argv) - argv = command->argv; - - if (!(line = exec_command_line(argv))) { - r = -ENOMEM; - goto fail_parent; - } - - log_debug("About to execute: %s", line); - free(line); - - r = cgroup_bonding_realize_list(cgroup_bondings); - if (r < 0) - goto fail_parent; - - cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings); - - if ((pid = fork()) < 0) { - r = -errno; - goto fail_parent; - } - - if (pid == 0) { - int i; - sigset_t ss; - const char *username = NULL, *home = NULL; - uid_t uid = (uid_t) -1; - gid_t gid = (gid_t) -1; - char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; - unsigned n_env = 0; - int saved_stdout = -1, saved_stdin = -1; - bool keep_stdout = false, keep_stdin = false; - - /* child */ - - /* This string must fit in 10 chars (i.e. the length - * of "/sbin/init") */ - rename_process("sd(EXEC)"); - - /* We reset exactly these signals, since they are the - * only ones we set to SIG_IGN in the main daemon. All - * others we leave untouched because we set them to - * SIG_DFL or a valid handler initially, both of which - * will be demoted to SIG_DFL. */ - default_signals(SIGNALS_CRASH_HANDLER, - SIGNALS_IGNORE, -1); - - if (sigemptyset(&ss) < 0 || - sigprocmask(SIG_SETMASK, &ss, NULL) < 0) { - r = EXIT_SIGNAL_MASK; - goto fail_child; - } - - /* Close sockets very early to make sure we don't - * block init reexecution because it cannot bind its - * sockets */ - if (close_all_fds(socket_fd >= 0 ? &socket_fd : fds, - socket_fd >= 0 ? 1 : n_fds) < 0) { - r = EXIT_FDS; - goto fail_child; - } - - if (!context->same_pgrp) - if (setsid() < 0) { - r = EXIT_SETSID; - goto fail_child; - } - - if (context->tcpwrap_name) { - if (socket_fd >= 0) - if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) { - r = EXIT_TCPWRAP; - goto fail_child; - } - - for (i = 0; i < (int) n_fds; i++) { - if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) { - r = EXIT_TCPWRAP; - goto fail_child; - } - } - } - - exec_context_tty_reset(context); - - /* We skip the confirmation step if we shall not apply the TTY */ - if (confirm_spawn && - (!is_terminal_input(context->std_input) || apply_tty_stdin)) { - char response; - - /* Set up terminal for the question */ - if ((r = setup_confirm_stdio(context, - &saved_stdin, &saved_stdout))) - goto fail_child; - - /* Now ask the question. */ - if (!(line = exec_command_line(argv))) { - r = EXIT_MEMORY; - goto fail_child; - } - - r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line); - free(line); - - if (r < 0 || response == 'n') { - r = EXIT_CONFIRM; - goto fail_child; - } else if (response == 's') { - r = 0; - goto fail_child; - } - - /* Release terminal for the question */ - if ((r = restore_confirm_stdio(context, - &saved_stdin, &saved_stdout, - &keep_stdin, &keep_stdout))) - goto fail_child; - } - - /* If a socket is connected to STDIN/STDOUT/STDERR, we - * must sure to drop O_NONBLOCK */ - if (socket_fd >= 0) - fd_nonblock(socket_fd, false); - - if (!keep_stdin) - if (setup_input(context, socket_fd, apply_tty_stdin) < 0) { - r = EXIT_STDIN; - goto fail_child; - } - - if (!keep_stdout) - if (setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) { - r = EXIT_STDOUT; - goto fail_child; - } - - if (setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) { - r = EXIT_STDERR; - goto fail_child; - } - - if (cgroup_bondings) - if (cgroup_bonding_install_list(cgroup_bondings, 0) < 0) { - r = EXIT_CGROUP; - goto fail_child; - } - - if (context->oom_score_adjust_set) { - char t[16]; - - snprintf(t, sizeof(t), "%i", context->oom_score_adjust); - char_array_0(t); - - if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) { - /* Compatibility with Linux <= 2.6.35 */ - - int adj; - - adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX; - adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX); - - snprintf(t, sizeof(t), "%i", adj); - char_array_0(t); - - if (write_one_line_file("/proc/self/oom_adj", t) < 0 - && errno != EACCES) { - r = EXIT_OOM_ADJUST; - goto fail_child; - } - } - } - - if (context->nice_set) - if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { - r = EXIT_NICE; - goto fail_child; - } - - if (context->cpu_sched_set) { - struct sched_param param; - - zero(param); - param.sched_priority = context->cpu_sched_priority; - - if (sched_setscheduler(0, context->cpu_sched_policy | - (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), ¶m) < 0) { - r = EXIT_SETSCHEDULER; - goto fail_child; - } - } - - if (context->cpuset) - if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) { - r = EXIT_CPUAFFINITY; - goto fail_child; - } - - if (context->ioprio_set) - if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { - r = EXIT_IOPRIO; - goto fail_child; - } - - if (context->timer_slack_nsec_set) - if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { - r = EXIT_TIMERSLACK; - goto fail_child; - } - - if (context->utmp_id) - utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path); - - if (context->user) { - username = context->user; - if (get_user_creds(&username, &uid, &gid, &home) < 0) { - r = EXIT_USER; - goto fail_child; - } - - if (is_terminal_input(context->std_input)) - if (chown_terminal(STDIN_FILENO, uid) < 0) { - r = EXIT_STDIN; - goto fail_child; - } - - if (cgroup_bondings && context->control_group_modify) - if (cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid) < 0 || - cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid) < 0) { - r = EXIT_CGROUP; - goto fail_child; - } - } - - if (apply_permissions) - if (enforce_groups(context, username, gid) < 0) { - r = EXIT_GROUP; - goto fail_child; - } - - umask(context->umask); - -#ifdef HAVE_PAM - if (context->pam_name && username) { - if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) != 0) { - r = EXIT_PAM; - goto fail_child; - } - } -#endif - if (context->private_network) { - if (unshare(CLONE_NEWNET) < 0) { - r = EXIT_NETWORK; - goto fail_child; - } - - loopback_setup(); - } - - if (strv_length(context->read_write_dirs) > 0 || - strv_length(context->read_only_dirs) > 0 || - strv_length(context->inaccessible_dirs) > 0 || - context->mount_flags != MS_SHARED || - context->private_tmp) - if ((r = setup_namespace( - context->read_write_dirs, - context->read_only_dirs, - context->inaccessible_dirs, - context->private_tmp, - context->mount_flags)) < 0) - goto fail_child; - - if (apply_chroot) { - if (context->root_directory) - if (chroot(context->root_directory) < 0) { - r = EXIT_CHROOT; - goto fail_child; - } - - if (chdir(context->working_directory ? context->working_directory : "/") < 0) { - r = EXIT_CHDIR; - goto fail_child; - } - } else { - - char *d; - - if (asprintf(&d, "%s/%s", - context->root_directory ? context->root_directory : "", - context->working_directory ? context->working_directory : "") < 0) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (chdir(d) < 0) { - free(d); - r = EXIT_CHDIR; - goto fail_child; - } - - free(d); - } - - /* We repeat the fd closing here, to make sure that - * nothing is leaked from the PAM modules */ - if (close_all_fds(fds, n_fds) < 0 || - shift_fds(fds, n_fds) < 0 || - flags_fds(fds, n_fds, context->non_blocking) < 0) { - r = EXIT_FDS; - goto fail_child; - } - - if (apply_permissions) { - - for (i = 0; i < RLIMIT_NLIMITS; i++) { - if (!context->rlimit[i]) - continue; - - if (setrlimit(i, context->rlimit[i]) < 0) { - r = EXIT_LIMITS; - goto fail_child; - } - } - - if (context->capability_bounding_set_drop) - if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) { - r = EXIT_CAPABILITIES; - goto fail_child; - } - - if (context->user) - if (enforce_user(context, uid) < 0) { - r = EXIT_USER; - goto fail_child; - } - - /* PR_GET_SECUREBITS is not privileged, while - * PR_SET_SECUREBITS is. So to suppress - * potential EPERMs we'll try not to call - * PR_SET_SECUREBITS unless necessary. */ - if (prctl(PR_GET_SECUREBITS) != context->secure_bits) - if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { - r = EXIT_SECUREBITS; - goto fail_child; - } - - if (context->capabilities) - if (cap_set_proc(context->capabilities) < 0) { - r = EXIT_CAPABILITIES; - goto fail_child; - } - } - - if (!(our_env = new0(char*, 7))) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (n_fds > 0) - if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 || - asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (home) - if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (username) - if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 || - asprintf(our_env + n_env++, "USER=%s", username) < 0) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (is_terminal_input(context->std_input) || - context->std_output == EXEC_OUTPUT_TTY || - context->std_error == EXEC_OUTPUT_TTY) - if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) { - r = EXIT_MEMORY; - goto fail_child; - } - - assert(n_env <= 7); - - if (!(final_env = strv_env_merge( - 5, - environment, - our_env, - context->environment, - files_env, - pam_env, - NULL))) { - r = EXIT_MEMORY; - goto fail_child; - } - - if (!(final_argv = replace_env_argv(argv, final_env))) { - r = EXIT_MEMORY; - goto fail_child; - } - - final_env = strv_env_clean(final_env); - - execve(command->path, final_argv, final_env); - r = EXIT_EXEC; - - fail_child: - strv_free(our_env); - strv_free(final_env); - strv_free(pam_env); - strv_free(files_env); - strv_free(final_argv); - - if (saved_stdin >= 0) - close_nointr_nofail(saved_stdin); - - if (saved_stdout >= 0) - close_nointr_nofail(saved_stdout); - - _exit(r); - } - - strv_free(files_env); - - /* We add the new process to the cgroup both in the child (so - * that we can be sure that no user code is ever executed - * outside of the cgroup) and in the parent (so that we can be - * sure that when we kill the cgroup the process will be - * killed too). */ - if (cgroup_bondings) - cgroup_bonding_install_list(cgroup_bondings, pid); - - log_debug("Forked %s as %lu", command->path, (unsigned long) pid); - - exec_status_start(&command->exec_status, pid); - - *ret = pid; - return 0; - -fail_parent: - strv_free(files_env); - - return r; -} - -void exec_context_init(ExecContext *c) { - assert(c); - - c->umask = 0022; - c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0); - c->cpu_sched_policy = SCHED_OTHER; - c->syslog_priority = LOG_DAEMON|LOG_INFO; - c->syslog_level_prefix = true; - c->mount_flags = MS_SHARED; - c->kill_signal = SIGTERM; - c->send_sigkill = true; -} - -void exec_context_done(ExecContext *c) { - unsigned l; - - assert(c); - - strv_free(c->environment); - c->environment = NULL; - - strv_free(c->environment_files); - c->environment_files = NULL; - - for (l = 0; l < ELEMENTSOF(c->rlimit); l++) { - free(c->rlimit[l]); - c->rlimit[l] = NULL; - } - - free(c->working_directory); - c->working_directory = NULL; - free(c->root_directory); - c->root_directory = NULL; - - free(c->tty_path); - c->tty_path = NULL; - - free(c->tcpwrap_name); - c->tcpwrap_name = NULL; - - free(c->syslog_identifier); - c->syslog_identifier = NULL; - - free(c->user); - c->user = NULL; - - free(c->group); - c->group = NULL; - - strv_free(c->supplementary_groups); - c->supplementary_groups = NULL; - - free(c->pam_name); - c->pam_name = NULL; - - if (c->capabilities) { - cap_free(c->capabilities); - c->capabilities = NULL; - } - - strv_free(c->read_only_dirs); - c->read_only_dirs = NULL; - - strv_free(c->read_write_dirs); - c->read_write_dirs = NULL; - - strv_free(c->inaccessible_dirs); - c->inaccessible_dirs = NULL; - - if (c->cpuset) - CPU_FREE(c->cpuset); - - free(c->utmp_id); - c->utmp_id = NULL; -} - -void exec_command_done(ExecCommand *c) { - assert(c); - - free(c->path); - c->path = NULL; - - strv_free(c->argv); - c->argv = NULL; -} - -void exec_command_done_array(ExecCommand *c, unsigned n) { - unsigned i; - - for (i = 0; i < n; i++) - exec_command_done(c+i); -} - -void exec_command_free_list(ExecCommand *c) { - ExecCommand *i; - - while ((i = c)) { - LIST_REMOVE(ExecCommand, command, c, i); - exec_command_done(i); - free(i); - } -} - -void exec_command_free_array(ExecCommand **c, unsigned n) { - unsigned i; - - for (i = 0; i < n; i++) { - exec_command_free_list(c[i]); - c[i] = NULL; - } -} - -int exec_context_load_environment(const ExecContext *c, char ***l) { - char **i, **r = NULL; - - assert(c); - assert(l); - - STRV_FOREACH(i, c->environment_files) { - char *fn; - int k; - bool ignore = false; - char **p; - - fn = *i; - - if (fn[0] == '-') { - ignore = true; - fn ++; - } - - if (!path_is_absolute(fn)) { - - if (ignore) - continue; - - strv_free(r); - return -EINVAL; - } - - if ((k = load_env_file(fn, &p)) < 0) { - - if (ignore) - continue; - - strv_free(r); - return k; - } - - if (r == NULL) - r = p; - else { - char **m; - - m = strv_env_merge(2, r, p); - strv_free(r); - strv_free(p); - - if (!m) - return -ENOMEM; - - r = m; - } - } - - *l = r; - - return 0; -} - -static void strv_fprintf(FILE *f, char **l) { - char **g; - - assert(f); - - STRV_FOREACH(g, l) - fprintf(f, " %s", *g); -} - -void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { - char ** e; - unsigned i; - - assert(c); - assert(f); - - if (!prefix) - prefix = ""; - - fprintf(f, - "%sUMask: %04o\n" - "%sWorkingDirectory: %s\n" - "%sRootDirectory: %s\n" - "%sNonBlocking: %s\n" - "%sPrivateTmp: %s\n" - "%sControlGroupModify: %s\n" - "%sPrivateNetwork: %s\n", - prefix, c->umask, - prefix, c->working_directory ? c->working_directory : "/", - prefix, c->root_directory ? c->root_directory : "/", - prefix, yes_no(c->non_blocking), - prefix, yes_no(c->private_tmp), - prefix, yes_no(c->control_group_modify), - prefix, yes_no(c->private_network)); - - STRV_FOREACH(e, c->environment) - fprintf(f, "%sEnvironment: %s\n", prefix, *e); - - STRV_FOREACH(e, c->environment_files) - fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e); - - if (c->tcpwrap_name) - fprintf(f, - "%sTCPWrapName: %s\n", - prefix, c->tcpwrap_name); - - if (c->nice_set) - fprintf(f, - "%sNice: %i\n", - prefix, c->nice); - - if (c->oom_score_adjust_set) - fprintf(f, - "%sOOMScoreAdjust: %i\n", - prefix, c->oom_score_adjust); - - for (i = 0; i < RLIM_NLIMITS; i++) - if (c->rlimit[i]) - fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max); - - if (c->ioprio_set) - fprintf(f, - "%sIOSchedulingClass: %s\n" - "%sIOPriority: %i\n", - prefix, ioprio_class_to_string(IOPRIO_PRIO_CLASS(c->ioprio)), - prefix, (int) IOPRIO_PRIO_DATA(c->ioprio)); - - if (c->cpu_sched_set) - fprintf(f, - "%sCPUSchedulingPolicy: %s\n" - "%sCPUSchedulingPriority: %i\n" - "%sCPUSchedulingResetOnFork: %s\n", - prefix, sched_policy_to_string(c->cpu_sched_policy), - prefix, c->cpu_sched_priority, - prefix, yes_no(c->cpu_sched_reset_on_fork)); - - if (c->cpuset) { - fprintf(f, "%sCPUAffinity:", prefix); - for (i = 0; i < c->cpuset_ncpus; i++) - if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset)) - fprintf(f, " %i", i); - fputs("\n", f); - } - - if (c->timer_slack_nsec_set) - fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec); - - fprintf(f, - "%sStandardInput: %s\n" - "%sStandardOutput: %s\n" - "%sStandardError: %s\n", - prefix, exec_input_to_string(c->std_input), - prefix, exec_output_to_string(c->std_output), - prefix, exec_output_to_string(c->std_error)); - - if (c->tty_path) - fprintf(f, - "%sTTYPath: %s\n" - "%sTTYReset: %s\n" - "%sTTYVHangup: %s\n" - "%sTTYVTDisallocate: %s\n", - prefix, c->tty_path, - prefix, yes_no(c->tty_reset), - prefix, yes_no(c->tty_vhangup), - prefix, yes_no(c->tty_vt_disallocate)); - - if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG || - c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE || - c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG || - c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE) - fprintf(f, - "%sSyslogFacility: %s\n" - "%sSyslogLevel: %s\n", - prefix, log_facility_unshifted_to_string(c->syslog_priority >> 3), - prefix, log_level_to_string(LOG_PRI(c->syslog_priority))); - - if (c->capabilities) { - char *t; - if ((t = cap_to_text(c->capabilities, NULL))) { - fprintf(f, "%sCapabilities: %s\n", - prefix, t); - cap_free(t); - } - } - - if (c->secure_bits) - fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n", - prefix, - (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "", - (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "", - (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "", - (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "", - (c->secure_bits & SECURE_NOROOT) ? " noroot" : "", - (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : ""); - - if (c->capability_bounding_set_drop) { - unsigned long l; - fprintf(f, "%sCapabilityBoundingSet:", prefix); - - for (l = 0; l <= (unsigned long) CAP_LAST_CAP; l++) - if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) { - char *t; - - if ((t = cap_to_name(l))) { - fprintf(f, " %s", t); - cap_free(t); - } - } - - fputs("\n", f); - } - - if (c->user) - fprintf(f, "%sUser: %s\n", prefix, c->user); - if (c->group) - fprintf(f, "%sGroup: %s\n", prefix, c->group); - - if (strv_length(c->supplementary_groups) > 0) { - fprintf(f, "%sSupplementaryGroups:", prefix); - strv_fprintf(f, c->supplementary_groups); - fputs("\n", f); - } - - if (c->pam_name) - fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); - - if (strv_length(c->read_write_dirs) > 0) { - fprintf(f, "%sReadWriteDirs:", prefix); - strv_fprintf(f, c->read_write_dirs); - fputs("\n", f); - } - - if (strv_length(c->read_only_dirs) > 0) { - fprintf(f, "%sReadOnlyDirs:", prefix); - strv_fprintf(f, c->read_only_dirs); - fputs("\n", f); - } - - if (strv_length(c->inaccessible_dirs) > 0) { - fprintf(f, "%sInaccessibleDirs:", prefix); - strv_fprintf(f, c->inaccessible_dirs); - fputs("\n", f); - } - - fprintf(f, - "%sKillMode: %s\n" - "%sKillSignal: SIG%s\n" - "%sSendSIGKILL: %s\n", - prefix, kill_mode_to_string(c->kill_mode), - prefix, signal_to_string(c->kill_signal), - prefix, yes_no(c->send_sigkill)); - - if (c->utmp_id) - fprintf(f, - "%sUtmpIdentifier: %s\n", - prefix, c->utmp_id); -} - -void exec_status_start(ExecStatus *s, pid_t pid) { - assert(s); - - zero(*s); - s->pid = pid; - dual_timestamp_get(&s->start_timestamp); -} - -void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) { - assert(s); - - if ((s->pid && s->pid != pid) || - !s->start_timestamp.realtime <= 0) - zero(*s); - - s->pid = pid; - dual_timestamp_get(&s->exit_timestamp); - - s->code = code; - s->status = status; - - if (context) { - if (context->utmp_id) - utmp_put_dead_process(context->utmp_id, pid, code, status); - - exec_context_tty_reset(context); - } -} - -void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) { - char buf[FORMAT_TIMESTAMP_MAX]; - - assert(s); - assert(f); - - if (!prefix) - prefix = ""; - - if (s->pid <= 0) - return; - - fprintf(f, - "%sPID: %lu\n", - prefix, (unsigned long) s->pid); - - if (s->start_timestamp.realtime > 0) - fprintf(f, - "%sStart Timestamp: %s\n", - prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime)); - - if (s->exit_timestamp.realtime > 0) - fprintf(f, - "%sExit Timestamp: %s\n" - "%sExit Code: %s\n" - "%sExit Status: %i\n", - prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime), - prefix, sigchld_code_to_string(s->code), - prefix, s->status); -} - -char *exec_command_line(char **argv) { - size_t k; - char *n, *p, **a; - bool first = true; - - assert(argv); - - k = 1; - STRV_FOREACH(a, argv) - k += strlen(*a)+3; - - if (!(n = new(char, k))) - return NULL; - - p = n; - STRV_FOREACH(a, argv) { - - if (!first) - *(p++) = ' '; - else - first = false; - - if (strpbrk(*a, WHITESPACE)) { - *(p++) = '\''; - p = stpcpy(p, *a); - *(p++) = '\''; - } else - p = stpcpy(p, *a); - - } - - *p = 0; - - /* FIXME: this doesn't really handle arguments that have - * spaces and ticks in them */ - - return n; -} - -void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) { - char *p2; - const char *prefix2; - - char *cmd; - - assert(c); - assert(f); - - if (!prefix) - prefix = ""; - p2 = strappend(prefix, "\t"); - prefix2 = p2 ? p2 : prefix; - - cmd = exec_command_line(c->argv); - - fprintf(f, - "%sCommand Line: %s\n", - prefix, cmd ? cmd : strerror(ENOMEM)); - - free(cmd); - - exec_status_dump(&c->exec_status, f, prefix2); - - free(p2); -} - -void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) { - assert(f); - - if (!prefix) - prefix = ""; - - LIST_FOREACH(command, c, c) - exec_command_dump(c, f, prefix); -} - -void exec_command_append_list(ExecCommand **l, ExecCommand *e) { - ExecCommand *end; - - assert(l); - assert(e); - - if (*l) { - /* It's kind of important, that we keep the order here */ - LIST_FIND_TAIL(ExecCommand, command, *l, end); - LIST_INSERT_AFTER(ExecCommand, command, *l, end, e); - } else - *l = e; -} - -int exec_command_set(ExecCommand *c, const char *path, ...) { - va_list ap; - char **l, *p; - - assert(c); - assert(path); - - va_start(ap, path); - l = strv_new_ap(path, ap); - va_end(ap); - - if (!l) - return -ENOMEM; - - if (!(p = strdup(path))) { - strv_free(l); - return -ENOMEM; - } - - free(c->path); - c->path = p; - - strv_free(c->argv); - c->argv = l; - - return 0; -} - -static const char* const exec_input_table[_EXEC_INPUT_MAX] = { - [EXEC_INPUT_NULL] = "null", - [EXEC_INPUT_TTY] = "tty", - [EXEC_INPUT_TTY_FORCE] = "tty-force", - [EXEC_INPUT_TTY_FAIL] = "tty-fail", - [EXEC_INPUT_SOCKET] = "socket" -}; - -DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput); - -static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { - [EXEC_OUTPUT_INHERIT] = "inherit", - [EXEC_OUTPUT_NULL] = "null", - [EXEC_OUTPUT_TTY] = "tty", - [EXEC_OUTPUT_SYSLOG] = "syslog", - [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console", - [EXEC_OUTPUT_KMSG] = "kmsg", - [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console", - [EXEC_OUTPUT_SOCKET] = "socket" -}; - -DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput); - -static const char* const kill_mode_table[_KILL_MODE_MAX] = { - [KILL_CONTROL_GROUP] = "control-group", - [KILL_PROCESS] = "process", - [KILL_NONE] = "none" -}; - -DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode); - -static const char* const kill_who_table[_KILL_WHO_MAX] = { - [KILL_MAIN] = "main", - [KILL_CONTROL] = "control", - [KILL_ALL] = "all" -}; - -DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/execute.h b/src/execute.h deleted file mode 100644 index 77a2257..0000000 --- a/src/execute.h +++ /dev/null @@ -1,230 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooexecutehfoo -#define fooexecutehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct ExecStatus ExecStatus; -typedef struct ExecCommand ExecCommand; -typedef struct ExecContext ExecContext; - -#include -#include -#include -#include -#include -#include -#include - -struct CGroupBonding; -struct CGroupAttribute; - -#include "list.h" -#include "util.h" - -#define STDOUT_SYSLOG_BRIDGE_SOCKET "/run/systemd/stdout-syslog-bridge" - -typedef enum KillMode { - KILL_CONTROL_GROUP = 0, - KILL_PROCESS, - KILL_NONE, - _KILL_MODE_MAX, - _KILL_MODE_INVALID = -1 -} KillMode; - -typedef enum KillWho { - KILL_MAIN, - KILL_CONTROL, - KILL_ALL, - _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 -} KillWho; - -typedef enum ExecInput { - EXEC_INPUT_NULL, - EXEC_INPUT_TTY, - EXEC_INPUT_TTY_FORCE, - EXEC_INPUT_TTY_FAIL, - EXEC_INPUT_SOCKET, - _EXEC_INPUT_MAX, - _EXEC_INPUT_INVALID = -1 -} ExecInput; - -typedef enum ExecOutput { - EXEC_OUTPUT_INHERIT, - EXEC_OUTPUT_NULL, - EXEC_OUTPUT_TTY, - EXEC_OUTPUT_SYSLOG, - EXEC_OUTPUT_SYSLOG_AND_CONSOLE, - EXEC_OUTPUT_KMSG, - EXEC_OUTPUT_KMSG_AND_CONSOLE, - EXEC_OUTPUT_SOCKET, - _EXEC_OUTPUT_MAX, - _EXEC_OUTPUT_INVALID = -1 -} ExecOutput; - -struct ExecStatus { - 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 */ -}; - -struct ExecCommand { - char *path; - char **argv; - ExecStatus exec_status; - LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ - bool ignore; -}; - -struct ExecContext { - char **environment; - char **environment_files; - - struct rlimit *rlimit[RLIMIT_NLIMITS]; - char *working_directory, *root_directory; - - mode_t umask; - int oom_score_adjust; - int nice; - int ioprio; - int cpu_sched_policy; - int cpu_sched_priority; - - cpu_set_t *cpuset; - unsigned cpuset_ncpus; - - ExecInput std_input; - ExecOutput std_output; - ExecOutput std_error; - - unsigned long timer_slack_nsec; - - char *tcpwrap_name; - - char *tty_path; - - bool tty_reset; - bool tty_vhangup; - bool tty_vt_disallocate; - - /* Since resolving these names might might involve socket - * connections and we don't want to deadlock ourselves these - * names are resolved on execution only and in the child - * process. */ - char *user; - char *group; - char **supplementary_groups; - - char *pam_name; - - char *utmp_id; - - char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; - unsigned long mount_flags; - - uint64_t capability_bounding_set_drop; - - /* Not relevant for spawning processes, just for killing */ - KillMode kill_mode; - int kill_signal; - bool send_sigkill; - - cap_t capabilities; - int secure_bits; - - int syslog_priority; - char *syslog_identifier; - bool syslog_level_prefix; - - bool cpu_sched_reset_on_fork; - bool non_blocking; - bool private_tmp; - bool private_network; - - bool control_group_modify; - - /* This is not exposed to the user but available - * internally. We need it to make sure that whenever we spawn - * /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 oom_score_adjust_set:1; - bool nice_set:1; - bool ioprio_set:1; - bool cpu_sched_set:1; - bool timer_slack_nsec_set:1; -}; - -int exec_spawn(ExecCommand *command, - char **argv, - const ExecContext *context, - int fds[], unsigned n_fds, - char **environment, - bool apply_permissions, - bool apply_chroot, - bool apply_tty_stdin, - bool confirm_spawn, - struct CGroupBonding *cgroup_bondings, - struct CGroupAttribute *cgroup_attributes, - pid_t *ret); - -void exec_command_done(ExecCommand *c); -void exec_command_done_array(ExecCommand *c, unsigned n); - -void exec_command_free_list(ExecCommand *c); -void exec_command_free_array(ExecCommand **c, unsigned n); - -char *exec_command_line(char **argv); - -void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix); -void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix); -void exec_command_append_list(ExecCommand **l, ExecCommand *e); -int exec_command_set(ExecCommand *c, const char *path, ...); - -void exec_context_init(ExecContext *c); -void exec_context_done(ExecContext *c); -void exec_context_dump(ExecContext *c, FILE* f, const char *prefix); -void exec_context_tty_reset(const ExecContext *context); - -int exec_context_load_environment(const ExecContext *c, char ***l); - -void exec_status_start(ExecStatus *s, pid_t pid); -void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status); -void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix); - -const char* exec_output_to_string(ExecOutput i); -ExecOutput exec_output_from_string(const char *s); - -const char* exec_input_to_string(ExecInput i); -ExecInput exec_input_from_string(const char *s); - -const char *kill_mode_to_string(KillMode k); -KillMode kill_mode_from_string(const char *s); - -const char *kill_who_to_string(KillWho k); -KillWho kill_who_from_string(const char *s); - -#endif diff --git a/src/exit-status.c b/src/exit-status.c deleted file mode 100644 index 8ed1a0e..0000000 --- a/src/exit-status.c +++ /dev/null @@ -1,177 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "exit-status.h" - -const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { - - /* We cast to int here, so that -Wenum doesn't complain that - * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */ - - switch ((int) status) { - - case EXIT_SUCCESS: - return "SUCCESS"; - - case EXIT_FAILURE: - return "FAILURE"; - } - - - if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) { - switch ((int) status) { - - case EXIT_CHDIR: - return "CHDIR"; - - case EXIT_NICE: - return "NICE"; - - case EXIT_FDS: - return "FDS"; - - case EXIT_EXEC: - return "EXEC"; - - case EXIT_MEMORY: - return "MEMORY"; - - case EXIT_LIMITS: - return "LIMITS"; - - case EXIT_OOM_ADJUST: - return "OOM_ADJUST"; - - case EXIT_SIGNAL_MASK: - return "SIGNAL_MASK"; - - case EXIT_STDIN: - return "STDIN"; - - case EXIT_STDOUT: - return "STDOUT"; - - case EXIT_CHROOT: - return "CHROOT"; - - case EXIT_IOPRIO: - return "IOPRIO"; - - case EXIT_TIMERSLACK: - return "TIMERSLACK"; - - case EXIT_SECUREBITS: - return "SECUREBITS"; - - case EXIT_SETSCHEDULER: - return "SETSCHEDULER"; - - case EXIT_CPUAFFINITY: - return "CPUAFFINITY"; - - case EXIT_GROUP: - return "GROUP"; - - case EXIT_USER: - return "USER"; - - case EXIT_CAPABILITIES: - return "CAPABILITIES"; - - case EXIT_CGROUP: - return "CGROUP"; - - case EXIT_SETSID: - return "SETSID"; - - case EXIT_CONFIRM: - return "CONFIRM"; - - case EXIT_STDERR: - return "STDERR"; - - case EXIT_TCPWRAP: - return "TCPWRAP"; - - case EXIT_PAM: - return "PAM"; - - case EXIT_NETWORK: - return "NETWORK"; - } - } - - if (level == EXIT_STATUS_LSB) { - switch ((int) status) { - - case EXIT_INVALIDARGUMENT: - return "INVALIDARGUMENT"; - - case EXIT_NOTIMPLEMENTED: - return "NOTIMPLEMENTED"; - - case EXIT_NOPERMISSION: - return "NOPERMISSION"; - - case EXIT_NOTINSTALLED: - return "NOTINSSTALLED"; - - case EXIT_NOTCONFIGURED: - return "NOTCONFIGURED"; - - case EXIT_NOTRUNNING: - return "NOTRUNNING"; - } - } - - return NULL; -} - - -bool is_clean_exit(int code, int status) { - - if (code == CLD_EXITED) - return status == 0; - - /* If a daemon does not implement handlers for some of the - * signals that's not considered an unclean shutdown */ - if (code == CLD_KILLED) - return - status == SIGHUP || - status == SIGINT || - status == SIGTERM || - status == SIGPIPE; - - return false; -} - -bool is_clean_exit_lsb(int code, int status) { - - if (is_clean_exit(code, status)) - return true; - - return - code == CLD_EXITED && - (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED); -} diff --git a/src/exit-status.h b/src/exit-status.h deleted file mode 100644 index 3e977b1..0000000 --- a/src/exit-status.h +++ /dev/null @@ -1,84 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooexitstatushfoo -#define fooexitstatushfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -typedef enum ExitStatus { - /* EXIT_SUCCESS defined by libc */ - /* EXIT_FAILURE defined by libc */ - EXIT_INVALIDARGUMENT = 2, - EXIT_NOTIMPLEMENTED = 3, - EXIT_NOPERMISSION = 4, - EXIT_NOTINSTALLED = 5, - EXIT_NOTCONFIGURED = 6, - EXIT_NOTRUNNING = 7, - - /* The LSB suggests that error codes >= 200 are "reserved". We - * use them here under the assumption that they hence are - * unused by init scripts. - * - * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ - - EXIT_CHDIR = 200, - EXIT_NICE, - EXIT_FDS, - EXIT_EXEC, - EXIT_MEMORY, - EXIT_LIMITS, - EXIT_OOM_ADJUST, - EXIT_SIGNAL_MASK, - EXIT_STDIN, - EXIT_STDOUT, - EXIT_CHROOT, /* 210 */ - EXIT_IOPRIO, - EXIT_TIMERSLACK, - EXIT_SECUREBITS, - EXIT_SETSCHEDULER, - EXIT_CPUAFFINITY, - EXIT_GROUP, - EXIT_USER, - EXIT_CAPABILITIES, - EXIT_CGROUP, - EXIT_SETSID, /* 220 */ - EXIT_CONFIRM, - EXIT_STDERR, - EXIT_TCPWRAP, - EXIT_PAM, - EXIT_NETWORK - -} ExitStatus; - -typedef enum ExitStatusLevel { - EXIT_STATUS_MINIMAL, - EXIT_STATUS_SYSTEMD, - EXIT_STATUS_LSB, - EXIT_STATUS_FULL = EXIT_STATUS_LSB -} ExitStatusLevel; - -const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level); - -bool is_clean_exit(int code, int status); -bool is_clean_exit_lsb(int code, int status); - -#endif diff --git a/src/fdset.c b/src/fdset.c deleted file mode 100644 index e67fe6f..0000000 --- a/src/fdset.c +++ /dev/null @@ -1,167 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "set.h" -#include "util.h" -#include "macro.h" -#include "fdset.h" - -#define MAKE_SET(s) ((Set*) s) -#define MAKE_FDSET(s) ((FDSet*) s) - -/* Make sure we can distuingish fd 0 and NULL */ -#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) -#define PTR_TO_FD(p) (PTR_TO_INT(p)-1) - -FDSet *fdset_new(void) { - return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func)); -} - -void fdset_free(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)); - } - - set_free(MAKE_SET(s)); -} - -int fdset_put(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return set_put(MAKE_SET(s), FD_TO_PTR(fd)); -} - -int fdset_put_dup(FDSet *s, int fd) { - int copy, r; - - assert(s); - assert(fd >= 0); - - if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0) - return -errno; - - if ((r = fdset_put(s, copy)) < 0) { - close_nointr_nofail(copy); - return r; - } - - return copy; -} - -bool fdset_contains(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); -} - -int fdset_remove(FDSet *s, int fd) { - assert(s); - assert(fd >= 0); - - return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; -} - -int fdset_new_fill(FDSet **_s) { - DIR *d; - struct dirent *de; - int r = 0; - FDSet *s; - - assert(_s); - - /* Creates an fdsets and fills in all currently open file - * descriptors. */ - - if (!(d = opendir("/proc/self/fd"))) - return -errno; - - if (!(s = fdset_new())) { - r = -ENOMEM; - goto finish; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (ignore_file(de->d_name)) - continue; - - if ((r = safe_atoi(de->d_name, &fd)) < 0) - goto finish; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if ((r = fdset_put(s, fd)) < 0) - goto finish; - } - - r = 0; - *_s = s; - s = NULL; - -finish: - closedir(d); - - /* We won't close the fds here! */ - if (s) - set_free(MAKE_SET(s)); - - return r; -} - -int fdset_cloexec(FDSet *fds, bool b) { - Iterator i; - void *p; - int r; - - assert(fds); - - SET_FOREACH(p, MAKE_SET(fds), i) - if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0) - return r; - - return 0; -} diff --git a/src/fdset.h b/src/fdset.h deleted file mode 100644 index 044a9e6..0000000 --- a/src/fdset.h +++ /dev/null @@ -1,40 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foofdsethfoo -#define foofdsethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct FDSet FDSet; - -FDSet* fdset_new(void); -void fdset_free(FDSet *s); - -int fdset_put(FDSet *s, int fd); -int fdset_put_dup(FDSet *s, int fd); - -bool fdset_contains(FDSet *s, int fd); -int fdset_remove(FDSet *s, int fd); - -int fdset_new_fill(FDSet **_s); - -int fdset_cloexec(FDSet *fds, bool b); - -#endif diff --git a/src/fsck.c b/src/fsck.c deleted file mode 100644 index c5088ad..0000000 --- a/src/fsck.c +++ /dev/null @@ -1,406 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "util.h" -#include "dbus-common.h" -#include "special.h" -#include "bus-errors.h" -#include "virt.h" - -static bool arg_skip = false; -static bool arg_force = false; -static bool arg_show_progress = false; - -static void start_target(const char *target, bool isolate) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - const char *mode, *basic_target = "basic.target"; - DBusConnection *bus = NULL; - - assert(target); - - dbus_error_init(&error); - - if (bus_connect(DBUS_BUS_SYSTEM, &bus, NULL, &error) < 0) { - log_error("Failed to get D-Bus connection: %s", bus_error_message(&error)); - goto finish; - } - - if (isolate) - mode = "isolate"; - else - mode = "replace"; - - log_info("Running request %s/start/%s", target, mode); - - if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnitReplace"))) { - log_error("Could not allocate message."); - goto finish; - } - - /* Start these units only if we can replace base.target with it */ - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &basic_target, - DBUS_TYPE_STRING, &target, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not attach target and flag information to message."); - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - /* Don't print a waring if we aren't called during - * startup */ - if (!dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB)) - log_error("Failed to start unit: %s", bus_error_message(&error)); - - goto finish; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - dbus_error_free(&error); -} - -static int parse_proc_cmdline(void) { - char *line, *w, *state; - int r; - size_t l; - - if (detect_container(NULL) > 0) - return 0; - - if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) { - log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); - return 0; - } - - FOREACH_WORD_QUOTED(w, l, line, state) { - - if (strneq(w, "fsck.mode=auto", l)) - arg_force = arg_skip = false; - else if (strneq(w, "fsck.mode=force", l)) - arg_force = true; - else if (strneq(w, "fsck.mode=skip", l)) - arg_skip = true; - else if (startswith(w, "fsck.mode")) - log_warning("Invalid fsck.mode= parameter. Ignoring."); -#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) - else if (strneq(w, "fastboot", l)) - arg_skip = true; - else if (strneq(w, "forcefsck", l)) - arg_force = true; -#endif - } - - free(line); - return 0; -} - -static void test_files(void) { - if (access("/fastboot", F_OK) >= 0) - arg_skip = true; - - if (access("/forcefsck", F_OK) >= 0) - arg_force = true; - - if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running()) - arg_show_progress = true; -} - -static double percent(int pass, unsigned long cur, unsigned long max) { - /* Values stolen from e2fsck */ - - static const int pass_table[] = { - 0, 70, 90, 92, 95, 100 - }; - - if (pass <= 0) - return 0.0; - - if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) - return 100.0; - - return (double) pass_table[pass-1] + - ((double) pass_table[pass] - (double) pass_table[pass-1]) * - (double) cur / (double) max; -} - -static int process_progress(int fd) { - FILE *f, *console; - usec_t last = 0; - bool locked = false; - int clear = 0; - - f = fdopen(fd, "r"); - if (!f) { - close_nointr_nofail(fd); - return -errno; - } - - console = fopen("/dev/console", "w"); - if (!console) { - fclose(f); - return -ENOMEM; - } - - while (!feof(f)) { - int pass, m; - unsigned long cur, max; - char *device; - double p; - usec_t t; - - if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) - break; - - /* Only show one progress counter at max */ - if (!locked) { - if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0) { - free(device); - continue; - } - - locked = true; - } - - /* Only update once every 50ms */ - t = now(CLOCK_MONOTONIC); - if (last + 50 * USEC_PER_MSEC > t) { - free(device); - continue; - } - - last = t; - - p = percent(pass, cur, max); - fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m); - fflush(console); - - free(device); - - if (m > clear) - clear = m; - } - - if (clear > 0) { - unsigned j; - - fputc('\r', console); - for (j = 0; j < (unsigned) clear; j++) - fputc(' ', console); - fputc('\r', console); - fflush(console); - } - - fclose(f); - fclose(console); - return 0; -} - -int main(int argc, char *argv[]) { - const char *cmdline[9]; - int i = 0, r = EXIT_FAILURE, q; - pid_t pid; - siginfo_t status; - struct udev *udev = NULL; - struct udev_device *udev_device = NULL; - const char *device; - bool root_directory; - int progress_pipe[2] = { -1, -1 }; - char dash_c[2+10+1]; - - if (argc > 2) { - log_error("This program expects one or no arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - parse_proc_cmdline(); - test_files(); - - if (!arg_force && arg_skip) - return 0; - - if (argc > 1) { - device = argv[1]; - root_directory = false; - } else { - struct stat st; - struct timespec times[2]; - - /* Find root device */ - - if (stat("/", &st) < 0) { - log_error("Failed to stat() the root directory: %m"); - goto finish; - } - - /* Virtual root devices don't need an fsck */ - if (major(st.st_dev) == 0) - return 0; - - /* check if we are already writable */ - times[0] = st.st_atim; - times[1] = st.st_mtim; - if (utimensat(AT_FDCWD, "/", times, 0) == 0) { - log_info("Root directory is writable, skipping check."); - return 0; - } - - if (!(udev = udev_new())) { - log_error("Out of memory"); - goto finish; - } - - if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev))) { - log_error("Failed to detect root device."); - goto finish; - } - - if (!(device = udev_device_get_devnode(udev_device))) { - log_error("Failed to detect device node of root directory."); - goto finish; - } - - root_directory = true; - } - - if (arg_show_progress) - if (pipe(progress_pipe) < 0) { - log_error("pipe(): %m"); - goto finish; - } - - cmdline[i++] = "/sbin/fsck"; - cmdline[i++] = "-a"; - cmdline[i++] = "-T"; - cmdline[i++] = "-l"; - - if (!root_directory) - cmdline[i++] = "-M"; - - if (arg_force) - cmdline[i++] = "-f"; - - if (progress_pipe[1] >= 0) { - snprintf(dash_c, sizeof(dash_c), "-C%i", progress_pipe[1]); - char_array_0(dash_c); - cmdline[i++] = dash_c; - } - - cmdline[i++] = device; - cmdline[i++] = NULL; - - pid = fork(); - if (pid < 0) { - log_error("fork(): %m"); - goto finish; - } else if (pid == 0) { - /* Child */ - if (progress_pipe[0] >= 0) - close_nointr_nofail(progress_pipe[0]); - execv(cmdline[0], (char**) cmdline); - _exit(8); /* Operational error */ - } - - if (progress_pipe[1] >= 0) { - close_nointr_nofail(progress_pipe[1]); - progress_pipe[1] = -1; - } - - if (progress_pipe[0] >= 0) { - process_progress(progress_pipe[0]); - progress_pipe[0] = -1; - } - - q = wait_for_terminate(pid, &status); - if (q < 0) { - log_error("waitid(): %s", strerror(-q)); - goto finish; - } - - if (status.si_code != CLD_EXITED || (status.si_status & ~1)) { - - if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED) - log_error("fsck terminated by signal %s.", signal_to_string(status.si_status)); - else if (status.si_code == CLD_EXITED) - log_error("fsck failed with error code %i.", status.si_status); - else - log_error("fsck failed due to unknown reason."); - - if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory) - /* System should be rebooted. */ - start_target(SPECIAL_REBOOT_TARGET, false); - else if (status.si_code == CLD_EXITED && (status.si_status & 6)) - /* Some other problem */ - start_target(SPECIAL_EMERGENCY_TARGET, true); - else { - r = EXIT_SUCCESS; - log_warning("Ignoring error."); - } - - } else - r = EXIT_SUCCESS; - - if (status.si_code == CLD_EXITED && (status.si_status & 1)) - touch("/run/systemd/quotacheck"); - -finish: - if (udev_device) - udev_device_unref(udev_device); - - if (udev) - udev_unref(udev); - - close_pipe(progress_pipe); - - return r; -} diff --git a/src/fsck/Makefile b/src/fsck/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/fsck/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c new file mode 100644 index 0000000..4a5f6b1 --- /dev/null +++ b/src/fsck/fsck.c @@ -0,0 +1,378 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "libudev.h" + +#include "util.h" +#include "special.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-errors.h" +#include "fileio.h" +#include "udev-util.h" + +static bool arg_skip = false; +static bool arg_force = false; +static bool arg_show_progress = false; + +static void start_target(const char *target) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + assert(target); + + r = bus_open_system_systemd(&bus); + if (r < 0) { + log_error("Failed to get D-Bus connection: %s", strerror(-r)); + return; + } + + log_info("Running request %s/start/replace", target); + + /* Start these units only if we can replace base.target with it */ + r = sd_bus_call_method(bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnitReplace", + &error, + NULL, + "sss", "basic.target", target, "replace"); + + /* Don't print a warning if we aren't called during startup */ + if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB)) + log_error("Failed to start unit: %s", bus_error_message(&error, -r)); +} + +static int parse_proc_cmdline_word(const char *w) { + if (streq(w, "fsck.mode=auto")) + arg_force = arg_skip = false; + else if (streq(w, "fsck.mode=force")) + arg_force = true; + else if (streq(w, "fsck.mode=skip")) + arg_skip = true; + else if (startswith(w, "fsck")) + log_warning("Invalid fsck parameter. Ignoring."); +#ifdef HAVE_SYSV_COMPAT + else if (streq(w, "fastboot")) { + log_error("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line."); + arg_skip = true; + } else if (streq(w, "forcefsck")) { + log_error("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line."); + arg_force = true; + } +#endif + + return 0; +} + +static void test_files(void) { +#ifdef HAVE_SYSV_COMPAT + if (access("/fastboot", F_OK) >= 0) { + log_error("Please pass 'fsck.mode=skip' on the kernel command line rather than creating /fastboot on the root file system."); + arg_skip = true; + } + + if (access("/forcefsck", F_OK) >= 0) { + log_error("Please pass 'fsck.mode=force' on the kernel command line rather than creating /forcefsck on the root file system."); + arg_force = true; + } +#endif + + if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running()) + arg_show_progress = true; +} + +static double percent(int pass, unsigned long cur, unsigned long max) { + /* Values stolen from e2fsck */ + + static const int pass_table[] = { + 0, 70, 90, 92, 95, 100 + }; + + if (pass <= 0) + return 0.0; + + if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) + return 100.0; + + return (double) pass_table[pass-1] + + ((double) pass_table[pass] - (double) pass_table[pass-1]) * + (double) cur / (double) max; +} + +static int process_progress(int fd) { + _cleanup_fclose_ FILE *console = NULL, *f = NULL; + usec_t last = 0; + bool locked = false; + int clear = 0; + + f = fdopen(fd, "r"); + if (!f) { + close_nointr_nofail(fd); + return -errno; + } + + console = fopen("/dev/console", "we"); + if (!console) + return -ENOMEM; + + while (!feof(f)) { + int pass, m; + unsigned long cur, max; + _cleanup_free_ char *device = NULL; + double p; + usec_t t; + + if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) + break; + + /* Only show one progress counter at max */ + if (!locked) { + if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0) + continue; + + locked = true; + } + + /* Only update once every 50ms */ + t = now(CLOCK_MONOTONIC); + if (last + 50 * USEC_PER_MSEC > t) + continue; + + last = t; + + p = percent(pass, cur, max); + fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m); + fflush(console); + + if (m > clear) + clear = m; + } + + if (clear > 0) { + unsigned j; + + fputc('\r', console); + for (j = 0; j < (unsigned) clear; j++) + fputc(' ', console); + fputc('\r', console); + fflush(console); + } + + return 0; +} + +int main(int argc, char *argv[]) { + const char *cmdline[9]; + int i = 0, r = EXIT_FAILURE, q; + pid_t pid; + siginfo_t status; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; + const char *device, *type; + bool root_directory; + int progress_pipe[2] = { -1, -1 }; + char dash_c[2+10+1]; + struct stat st; + + if (argc > 2) { + log_error("This program expects one or no arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + parse_proc_cmdline(parse_proc_cmdline_word); + test_files(); + + if (!arg_force && arg_skip) + return 0; + + udev = udev_new(); + if (!udev) { + log_oom(); + return EXIT_FAILURE; + } + + if (argc > 1) { + device = argv[1]; + root_directory = false; + + if (stat(device, &st) < 0) { + log_error("Failed to stat '%s': %m", device); + return EXIT_FAILURE; + } + + udev_device = udev_device_new_from_devnum(udev, 'b', st.st_rdev); + if (!udev_device) { + log_error("Failed to detect device %s", device); + return EXIT_FAILURE; + } + } else { + struct timespec times[2]; + + /* Find root device */ + + if (stat("/", &st) < 0) { + log_error("Failed to stat() the root directory: %m"); + return EXIT_FAILURE; + } + + /* Virtual root devices don't need an fsck */ + if (major(st.st_dev) == 0) + return EXIT_SUCCESS; + + /* check if we are already writable */ + times[0] = st.st_atim; + times[1] = st.st_mtim; + if (utimensat(AT_FDCWD, "/", times, 0) == 0) { + log_info("Root directory is writable, skipping check."); + return EXIT_SUCCESS; + } + + udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); + if (!udev_device) { + log_error("Failed to detect root device."); + return EXIT_FAILURE; + } + + device = udev_device_get_devnode(udev_device); + if (!device) { + log_error("Failed to detect device node of root directory."); + return EXIT_FAILURE; + } + + root_directory = true; + } + + type = udev_device_get_property_value(udev_device, "ID_FS_TYPE"); + if (type) { + const char *checker = strappenda("/sbin/fsck.", type); + r = access(checker, X_OK); + if (r < 0) { + if (errno == ENOENT) { + log_info("%s doesn't exist, not checking file system.", checker); + return EXIT_SUCCESS; + } else + log_warning("%s cannot be used: %m", checker); + } + } + + if (arg_show_progress) + if (pipe(progress_pipe) < 0) { + log_error("pipe(): %m"); + return EXIT_FAILURE; + } + + cmdline[i++] = "/sbin/fsck"; + cmdline[i++] = "-a"; + cmdline[i++] = "-T"; + cmdline[i++] = "-l"; + + if (!root_directory) + cmdline[i++] = "-M"; + + if (arg_force) + cmdline[i++] = "-f"; + + if (progress_pipe[1] >= 0) { + snprintf(dash_c, sizeof(dash_c), "-C%i", progress_pipe[1]); + char_array_0(dash_c); + cmdline[i++] = dash_c; + } + + cmdline[i++] = device; + cmdline[i++] = NULL; + + pid = fork(); + if (pid < 0) { + log_error("fork(): %m"); + goto finish; + } else if (pid == 0) { + /* Child */ + if (progress_pipe[0] >= 0) + close_nointr_nofail(progress_pipe[0]); + execv(cmdline[0], (char**) cmdline); + _exit(8); /* Operational error */ + } + + if (progress_pipe[1] >= 0) { + close_nointr_nofail(progress_pipe[1]); + progress_pipe[1] = -1; + } + + if (progress_pipe[0] >= 0) { + process_progress(progress_pipe[0]); + progress_pipe[0] = -1; + } + + q = wait_for_terminate(pid, &status); + if (q < 0) { + log_error("waitid(): %s", strerror(-q)); + goto finish; + } + + if (status.si_code != CLD_EXITED || (status.si_status & ~1)) { + + if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED) + log_error("fsck terminated by signal %s.", signal_to_string(status.si_status)); + else if (status.si_code == CLD_EXITED) + log_error("fsck failed with error code %i.", status.si_status); + else + log_error("fsck failed due to unknown reason."); + + if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory) + /* System should be rebooted. */ + start_target(SPECIAL_REBOOT_TARGET); + else if (status.si_code == CLD_EXITED && (status.si_status & 6)) + /* Some other problem */ + start_target(SPECIAL_EMERGENCY_TARGET); + else { + r = EXIT_SUCCESS; + log_warning("Ignoring error."); + } + + } else + r = EXIT_SUCCESS; + + if (status.si_code == CLD_EXITED && (status.si_status & 1)) + touch("/run/systemd/quotacheck"); + +finish: + close_pipe(progress_pipe); + + return r; +} diff --git a/src/fstab-generator/Makefile b/src/fstab-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/fstab-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c new file mode 100644 index 0000000..a8824df --- /dev/null +++ b/src/fstab-generator/fstab-generator.c @@ -0,0 +1,656 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "unit-name.h" +#include "path-util.h" +#include "mount-setup.h" +#include "special.h" +#include "mkdir.h" +#include "fileio.h" + +static const char *arg_dest = "/tmp"; +static bool arg_enabled = true; + +#ifdef CONFIG_TIZEN_WIP +#define COMMENT_HASFS "comment=havefs-" + +static bool hasfs_comment( + const char *mntopts, + char **comment_start, + char **comment_end, + char **opt_start, + char **fs_new) { + char *comment, *fs, *opt, *end; + + /* comment=havefs-foo-opt=1 */ + + comment = strstr(mntopts, COMMENT_HASFS); + if (!comment) + return false; + + if (comment_start) + *comment_start = comment; + + end = index(comment, ','); + + if (comment_end) + *comment_end = end ? end + 1 : comment + strlen(comment); + + fs = comment + strlen(COMMENT_HASFS); + + opt = index(fs, '-'); + if (!opt) + goto err_nofs; + + opt += 1; + + if (opt_start) + *opt_start = opt; + + if (fs_new) + *fs_new = strndup(fs, opt - fs - 1); + + return true; + +err_nofs: + *fs_new = NULL; + *opt_start = NULL; + + return true; +} +#endif + +static int mount_find_pri(struct mntent *me, int *ret) { + char *end, *pri; + unsigned long r; + + assert(me); + assert(ret); + + pri = hasmntopt(me, "pri"); + if (!pri) + return 0; + + pri += 4; + + errno = 0; + r = strtoul(pri, &end, 10); + if (errno > 0) + return -errno; + + if (end == pri || (*end != ',' && *end != 0)) + return -EINVAL; + + *ret = (int) r; + return 1; +} + +static int add_swap(const char *what, struct mntent *me) { + _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; + bool noauto; + int r, pri = -1; + + assert(what); + assert(me); + + r = mount_find_pri(me, &pri); + if (r < 0) { + log_error("Failed to parse priority"); + return pri; + } + + noauto = !!hasmntopt(me, "noauto"); + + name = unit_name_from_path(what, ".swap"); + if (!name) + return log_oom(); + + unit = strjoin(arg_dest, "/", name, NULL); + if (!unit) + return log_oom(); + + f = fopen(unit, "wxe"); + if (!f) { + if (errno == EEXIST) + log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); + else + log_error("Failed to create unit file %s: %m", unit); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-fstab-generator\n\n" + "[Unit]\n" + "SourcePath=/etc/fstab\n\n" + "[Swap]\n" + "What=%s\n", + what); + + if (pri >= 0) + fprintf(f, + "Priority=%i\n", + pri); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write unit file %s: %m", unit); + return -errno; + } + + if (!noauto) { + lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(unit, lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + } + + return 0; +} + +static bool mount_is_network(struct mntent *me) { + assert(me); + + return + hasmntopt(me, "_netdev") || + fstype_is_network(me->mnt_type); +} + +static bool mount_in_initrd(struct mntent *me) { + assert(me); + + return + hasmntopt(me, "x-initrd.mount") || + streq(me->mnt_dir, "/usr"); +} + +static int add_fsck(FILE *f, const char *what, const char *where, const char *type, int passno) { + assert(f); + + if (passno == 0) + return 0; + + if (!is_device_path(what)) { + log_warning("Checking was requested for \"%s\", but it is not a device.", what); + return 0; + } + + if (type && !streq(type, "auto")) { + int r; + const char *checker; + + checker = strappenda("/sbin/fsck.", type); + r = access(checker, X_OK); + if (r < 0) { + log_warning("Checking was requested for %s, but %s cannot be used: %m", what, checker); + + /* treat missing check as essentially OK */ + return errno == ENOENT ? 0 : -errno; + } + } + + if (streq(where, "/")) { + char *lnk; + + lnk = strappenda(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); + mkdir_parents_label(lnk, 0755); + if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + } else { + _cleanup_free_ char *fsck = NULL; + + fsck = unit_name_from_path_instance("systemd-fsck", what, ".service"); + if (!fsck) + return log_oom(); + + fprintf(f, + "RequiresOverridable=%s\n" + "After=%s\n", + fsck, + fsck); + } + + return 0; +} + +static int add_mount( + const char *what, + const char *where, + const char *type, + const char *opts, + int passno, + bool noauto, + bool nofail, + bool automount, + const char *post, + const char *source) { + _cleanup_free_ char + *name = NULL, *unit = NULL, *lnk = NULL, + *automount_name = NULL, *automount_unit = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(what); + assert(where); + assert(type); + assert(opts); + assert(source); + + if (streq(type, "autofs")) + return 0; + + if (!is_path(where)) { + log_warning("Mount point %s is not a valid path, ignoring.", where); + return 0; + } + + if (mount_point_is_api(where) || + mount_point_ignore(where)) + return 0; + + name = unit_name_from_path(where, ".mount"); + if (!name) + return log_oom(); + + unit = strjoin(arg_dest, "/", name, NULL); + if (!unit) + return log_oom(); + + f = fopen(unit, "wxe"); + if (!f) { + if (errno == EEXIST) + log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); + else + log_error("Failed to create unit file %s: %m", unit); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-fstab-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n", + source); + + if (post && !noauto && !nofail && !automount) + fprintf(f, + "Before=%s\n", + post); + + r = add_fsck(f, what, where, type, passno); + if (r < 0) + return r; + + fprintf(f, + "\n" + "[Mount]\n" + "What=%s\n" + "Where=%s\n" + "Type=%s\n", + what, + where, + type); + + if (!isempty(opts) && + !streq(opts, "defaults")) + fprintf(f, + "Options=%s\n", + opts); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write unit file %s: %m", unit); + return -errno; + } + + if (!noauto) { + if (post) { + lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(unit, lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + } + } + + if (automount && !path_equal(where, "/")) { + automount_name = unit_name_from_path(where, ".automount"); + if (!automount_name) + return log_oom(); + + automount_unit = strjoin(arg_dest, "/", automount_name, NULL); + if (!automount_unit) + return log_oom(); + + fclose(f); + f = fopen(automount_unit, "wxe"); + if (!f) { + log_error("Failed to create unit file %s: %m", automount_unit); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-fstab-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n", + source); + + if (post) + fprintf(f, + "Before= %s\n", + post); + + fprintf(f, + "[Automount]\n" + "Where=%s\n", + where); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write unit file %s: %m", automount_unit); + return -errno; + } + + free(lnk); + lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(automount_unit, lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + } + + return 0; +} + +static int parse_fstab(const char *prefix, bool initrd) { + char *fstab_path; + _cleanup_endmntent_ FILE *f; + int r = 0; + struct mntent *me; + + fstab_path = strappenda(strempty(prefix), "/etc/fstab"); + f = setmntent(fstab_path, "r"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open %s/etc/fstab: %m", strempty(prefix)); + return -errno; + } + + while ((me = getmntent(f))) { + _cleanup_free_ char *where = NULL, *what = NULL; + int k; + + if (initrd && !mount_in_initrd(me)) + continue; + + what = fstab_node_to_udev_node(me->mnt_fsname); + where = strjoin(strempty(prefix), me->mnt_dir, NULL); + if (!what || !where) + return log_oom(); + + if (is_path(where)) + path_kill_slashes(where); + + log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type); + + if (streq(me->mnt_type, "swap")) + k = add_swap(what, me); + else { + bool noauto, nofail, automount; + const char *post; +#ifdef CONFIG_TIZEN_WIP + _cleanup_free_ char *opts = NULL; +#endif + + noauto = !!hasmntopt(me, "noauto"); + nofail = !!hasmntopt(me, "nofail"); + automount = + hasmntopt(me, "comment=systemd.automount") || + hasmntopt(me, "x-systemd.automount"); + +#ifdef CONFIG_TIZEN_WIP + /* TODO */ + /* Tizen is now using switch-able smack + * feature. On feature enabled, different + * mount option is needed for tmpfs. This + * problematic problem is solved in recent + * util-linux. But we are not using mount of + * util-linux. So to compat the both case, the + * smackfsroot=* option will be conditionally + * be parsed by fstab. + */ + if (me->mnt_opts) { + _cleanup_free_ char *fs_new = NULL; + char *comment_start, *comment_end, *opt; + int n; + + opts = strdup(me->mnt_opts); + assert(opts); + + if (hasfs_comment(opts, &comment_start, &comment_end, &opt, &fs_new)) { + if (fs_new && use_smack()) + memmove(comment_start, opt, strlen(opt) + 1); + else + memmove(comment_start, comment_end, strlen(comment_end) + 1); + + n = strlen(opts); + if (n > 0 && opts[n - 1] == ',') + opts[n - 1] = '\0'; + } + } else + opts = strdup(""); +#endif + + if (initrd) { + post = SPECIAL_INITRD_FS_TARGET; + } else if (mount_in_initrd(me)) { + post = SPECIAL_INITRD_ROOT_FS_TARGET; + } else if (mount_is_network(me)) { + post = SPECIAL_REMOTE_FS_TARGET; + } else { + post = SPECIAL_LOCAL_FS_TARGET; + } + +#ifdef CONFIG_TIZEN_WIP + k = add_mount(what, where, me->mnt_type, opts, + me->mnt_passno, noauto, nofail, automount, + post, fstab_path); +#else + k = add_mount(what, where, me->mnt_type, me->mnt_opts, + me->mnt_passno, noauto, nofail, automount, + post, fstab_path); +#endif + } + + if (k < 0) + r = k; + } + + return r; +} + +static int parse_new_root_from_proc_cmdline(void) { + _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL; + bool noauto, nofail; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return 0; + + opts = strdup("ro"); + type = strdup("auto"); + if (!opts || !type) + return log_oom(); + + /* root= and roofstype= may occur more than once, the last instance should take precedence. + * In the case of multiple rootflags= the arguments should be concatenated */ + FOREACH_WORD_QUOTED(w, l, line, state) { + _cleanup_free_ char *word; + + word = strndup(w, l); + if (!word) + return log_oom(); + + else if (startswith(word, "root=")) { + free(what); + what = fstab_node_to_udev_node(word+5); + if (!what) + return log_oom(); + + } else if (startswith(word, "rootfstype=")) { + free(type); + type = strdup(word + 11); + if (!type) + return log_oom(); + + } else if (startswith(word, "rootflags=")) { + char *o; + + o = strjoin(opts, ",", word + 10, NULL); + if (!o) + return log_oom(); + + free(opts); + opts = o; + + } else if (streq(word, "ro") || streq(word, "rw")) { + char *o; + + o = strjoin(opts, ",", word, NULL); + if (!o) + return log_oom(); + + free(opts); + opts = o; + } + } + + noauto = !!strstr(opts, "noauto"); + nofail = !!strstr(opts, "nofail"); + + if (!what) { + log_debug("Could not find a root= entry on the kernel commandline."); + return 0; + } + + if (what[0] != '/') { + log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type); + return 0; + } + + log_debug("Found entry what=%s where=/sysroot type=%s", what, type); + r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false, + SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline"); + + return (r < 0) ? r : 0; +} + +static int parse_proc_cmdline_word(const char *word) { + int r; + + if (startswith(word, "fstab=")) { + r = parse_boolean(word + 6); + if (r < 0) + log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6); + else + arg_enabled = r; + + } else if (startswith(word, "rd.fstab=")) { + + if (in_initrd()) { + r = parse_boolean(word + 9); + if (r < 0) + log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9); + else + arg_enabled = r; + } + + } else if (startswith(word, "fstab.") || + (in_initrd() && startswith(word, "rd.fstab."))) { + + log_warning("Unknown kernel switch %s. Ignoring.", word); + } + + return 0; +} + +int main(int argc, char *argv[]) { + int r = 0, k, l = 0; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[1]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (parse_proc_cmdline(parse_proc_cmdline_word) < 0) + return EXIT_FAILURE; + + if (in_initrd()) + r = parse_new_root_from_proc_cmdline(); + + if (!arg_enabled) + return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS; + + k = parse_fstab(NULL, false); + + if (in_initrd()) + l = parse_fstab("/sysroot", true); + + return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/generate-kbd-model-map b/src/generate-kbd-model-map deleted file mode 100755 index 624c517..0000000 --- a/src/generate-kbd-model-map +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/python - -import sys -import system_config_keyboard.keyboard_models - -def strdash(s): - return s.strip() or '-' - -def tab_extend(s, n=1): - s = strdash(s) - k = len(s) // 8 - - if k >= n: - f = 1 - else: - f = n - k - - return s + '\t'*f - - -models = system_config_keyboard.keyboard_models.KeyboardModels().get_models() - -print "# Generated from system-config-keyboard's model list" -print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions" - -for key, value in reversed(models.items()): - options = "terminate:ctrl_alt_bksp" - if value[4]: - options += ',' + value[4] - - print ''.join((tab_extend(key, 3), tab_extend(value[1]), - tab_extend(value[2], 2), tab_extend(value[3], 2), - options)) diff --git a/src/getty-generator.c b/src/getty-generator.c deleted file mode 100644 index 6b5b254..0000000 --- a/src/getty-generator.c +++ /dev/null @@ -1,182 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "unit-name.h" -#include "virt.h" - -const char *arg_dest = "/tmp"; - -static int add_symlink(const char *fservice, const char *tservice) { - char *from = NULL, *to = NULL; - int r; - - assert(fservice); - assert(tservice); - - asprintf(&from, SYSTEM_DATA_UNIT_PATH "/%s", fservice); - asprintf(&to, "%s/getty.target.wants/%s", arg_dest, tservice); - - if (!from || !to) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - mkdir_parents(to, 0755); - - r = symlink(from, to); - if (r < 0) { - if (errno == EEXIST) - /* In case console=hvc0 is passed this will very likely result in EEXIST */ - r = 0; - else { - log_error("Failed to create symlink from %s to %s: %m", from, to); - r = -errno; - } - } - -finish: - - free(from); - free(to); - - return r; -} - -static int add_serial_getty(const char *tty) { - char *n; - int r; - - assert(tty); - - log_debug("Automatically adding serial getty for /dev/%s.", tty); - - n = unit_name_replace_instance("serial-getty@.service", tty); - if (!n) { - log_error("Out of memory"); - return -ENOMEM; - } - - r = add_symlink("serial-getty@.service", n); - free(n); - - return r; -} - -int main(int argc, char *argv[]) { - - static const char virtualization_consoles[] = - "hvc0\0" - "xvc0\0" - "hvsi0\0"; - - int r = EXIT_SUCCESS; - char *active; - const char *j; - - if (argc > 2) { - log_error("This program takes one or no arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc > 1) - arg_dest = argv[1]; - - if (detect_container(NULL) > 0) { - log_debug("Automatically adding console shell."); - - if (add_symlink("console-shell.service", "console-shell.service") < 0) - r = EXIT_FAILURE; - - /* Don't add any further magic if we are in a container */ - goto finish; - } - - if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { - const char *tty; - - tty = strrchr(active, ' '); - if (tty) - tty ++; - else - tty = active; - - /* Automatically add in a serial getty on the kernel - * console */ - if (tty_is_vc(tty)) - free(active); - else { - int k; - - /* We assume that gettys on virtual terminals are - * started via manual configuration and do this magic - * only for non-VC terminals. */ - - k = add_serial_getty(tty); - free(active); - - if (k < 0) { - r = EXIT_FAILURE; - goto finish; - } - } - } - - /* Automatically add in a serial getty on the first - * virtualizer console */ - NULSTR_FOREACH(j, virtualization_consoles) { - char *p; - int k; - - if (asprintf(&p, "/sys/class/tty/%s", j) < 0) { - log_error("Out of memory"); - r = EXIT_FAILURE; - goto finish; - } - - k = access(p, F_OK); - free(p); - - if (k < 0) - continue; - - k = add_serial_getty(j); - if (k < 0) { - r = EXIT_FAILURE; - goto finish; - } - } - -finish: - return r; -} diff --git a/src/getty-generator/Makefile b/src/getty-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/getty-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c new file mode 100644 index 0000000..08b3b1e --- /dev/null +++ b/src/getty-generator/getty-generator.c @@ -0,0 +1,239 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "mkdir.h" +#include "unit-name.h" +#include "virt.h" +#include "fileio.h" +#include "path-util.h" + +static const char *arg_dest = "/tmp"; + +static int add_symlink(const char *fservice, const char *tservice) { + _cleanup_free_ char *from = NULL, *to = NULL; + int r; + + assert(fservice); + assert(tservice); + + from = strappend(SYSTEM_DATA_UNIT_PATH "/", fservice); + if (!from) + return log_oom(); + + to = strjoin(arg_dest,"/getty.target.wants/", tservice, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + + r = symlink(from, to); + if (r < 0) { + if (errno == EEXIST) + /* In case console=hvc0 is passed this will very likely result in EEXIST */ + return 0; + else { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + } + + return 0; +} + +static int add_serial_getty(const char *tty) { + _cleanup_free_ char *n = NULL; + + assert(tty); + + log_debug("Automatically adding serial getty for /dev/%s.", tty); + + n = unit_name_replace_instance("serial-getty@.service", tty); + if (!n) + return log_oom(); + + return add_symlink("serial-getty@.service", n); +} + +static int add_container_getty(const char *tty) { + _cleanup_free_ char *n = NULL; + + assert(tty); + + log_debug("Automatically adding container getty for /dev/pts/%s.", tty); + + n = unit_name_replace_instance("container-getty@.service", tty); + if (!n) + return log_oom(); + + return add_symlink("container-getty@.service", n); +} + +static int verify_tty(const char *name) { + _cleanup_close_ int fd = -1; + const char *p; + + /* Some TTYs are weird and have been enumerated but don't work + * when you try to use them, such as classic ttyS0 and + * friends. Let's check that and open the device and run + * isatty() on it. */ + + p = strappenda("/dev/", name); + + /* O_NONBLOCK is essential here, to make sure we don't wait + * for DCD */ + fd = open(p, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) + return -errno; + + errno = 0; + if (isatty(fd) <= 0) + return errno ? -errno : -EIO; + + return 0; +} + +int main(int argc, char *argv[]) { + + static const char virtualization_consoles[] = + "hvc0\0" + "xvc0\0" + "hvsi0\0" + "sclp_line0\0" + "ttysclp0\0"; + + _cleanup_free_ char *active = NULL; + const char *j; + int r; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[1]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (detect_container(NULL) > 0) { + _cleanup_free_ char *container_ttys = NULL; + + log_debug("Automatically adding console shell."); + + if (add_symlink("console-getty.service", "console-getty.service") < 0) + return EXIT_FAILURE; + + /* When $container_ttys is set for PID 1, spawn + * gettys on all ptys named therein. Note that despite + * the variable name we only support ptys here. */ + + r = getenv_for_pid(1, "container_ttys", &container_ttys); + if (r > 0) { + char *w, *state; + size_t l; + + FOREACH_WORD(w, l, container_ttys, state) { + const char *t; + char tty[l + 1]; + + memcpy(tty, w, l); + tty[l] = 0; + + /* First strip off /dev/ if it is specified */ + t = path_startswith(tty, "/dev/"); + if (!t) + t = tty; + + /* Then, make sure it's actually a pty */ + t = path_startswith(t, "pts/"); + if (!t) + continue; + + if (add_container_getty(t) < 0) + return EXIT_FAILURE; + } + } + + /* Don't add any further magic if we are in a container */ + return EXIT_SUCCESS; + } + + if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { + char *w, *state; + size_t l; + + /* Automatically add in a serial getty on all active + * kernel consoles */ + FOREACH_WORD(w, l, active, state) { + _cleanup_free_ char *tty = NULL; + + tty = strndup(w, l); + if (!tty) { + log_oom(); + return EXIT_FAILURE; + } + + if (isempty(tty) || tty_is_vc(tty)) + continue; + + if (verify_tty(tty) < 0) + continue; + + /* We assume that gettys on virtual terminals are + * started via manual configuration and do this magic + * only for non-VC terminals. */ + + if (add_serial_getty(tty) < 0) + return EXIT_FAILURE; + } + } + + /* Automatically add in a serial getty on the first + * virtualizer console */ + NULSTR_FOREACH(j, virtualization_consoles) { + _cleanup_free_ char *p = NULL; + + p = strappend("/sys/class/tty/", j); + if (!p) { + log_oom(); + return EXIT_FAILURE; + } + + if (access(p, F_OK) < 0) + continue; + + if (add_serial_getty(j) < 0) + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala deleted file mode 100644 index c31c07e..0000000 --- a/src/gnome-ask-password-agent.vala +++ /dev/null @@ -1,276 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -using Gtk; -using GLib; -using Linux; -using Posix; -using Notify; - -[CCode (cheader_filename = "time.h")] -extern int clock_gettime(int id, out timespec ts); - -public class PasswordDialog : Dialog { - - public Entry entry; - - public PasswordDialog(string message, string icon) { - set_title("System Password"); - set_has_separator(false); - set_border_width(8); - set_default_response(ResponseType.OK); - set_icon_name(icon); - -#if LIBNOTIFY07 - add_button(Stock.CANCEL, ResponseType.CANCEL); - add_button(Stock.OK, ResponseType.OK); -#else - add_button(STOCK_CANCEL, ResponseType.CANCEL); - add_button(STOCK_OK, ResponseType.OK); -#endif - - Container content = (Container) get_content_area(); - - Box hbox = new HBox(false, 16); - hbox.set_border_width(8); - content.add(hbox); - - Image image = new Image.from_icon_name(icon, IconSize.DIALOG); - hbox.pack_start(image, false, false); - - Box vbox = new VBox(false, 8); - hbox.pack_start(vbox, true, true); - - Label label = new Label(message); - vbox.pack_start(label, false, false); - - entry = new Entry(); - entry.set_visibility(false); - entry.set_activates_default(true); - vbox.pack_start(entry, false, false); - - entry.activate.connect(on_entry_activated); - - show_all(); - } - - public void on_entry_activated() { - response(ResponseType.OK); - } -} - -public class MyStatusIcon : StatusIcon { - - File directory; - File current; - FileMonitor file_monitor; - - string message; - string icon; - string socket; - - PasswordDialog password_dialog; - - public MyStatusIcon() throws GLib.Error { - GLib.Object(icon_name : "dialog-password"); - set_title("System Password Request"); - - directory = File.new_for_path("/run/systemd/ask-password/"); - file_monitor = directory.monitor_directory(0); - file_monitor.changed.connect(file_monitor_changed); - - current = null; - look_for_password(); - - activate.connect(status_icon_activate); - } - - void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) { - - if (!file.get_basename().has_prefix("ask.")) - return; - - if (event_type == FileMonitorEvent.CREATED || - event_type == FileMonitorEvent.DELETED) { - try { - look_for_password(); - } catch (Error e) { - show_error(e.message); - } - } - } - - void look_for_password() throws GLib.Error { - - if (current != null) { - if (!current.query_exists()) { - current = null; - if (password_dialog != null) - password_dialog.response(ResponseType.REJECT); - } - } - - if (current == null) { - FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - - FileInfo i; - while ((i = enumerator.next_file()) != null) { - if (!i.get_name().has_prefix("ask.")) - continue; - - current = directory.get_child(i.get_name()); - - if (load_password()) - break; - - current = null; - } - } - - if (current == null) - set_visible(false); - } - - bool load_password() throws GLib.Error { - - KeyFile key_file = new KeyFile(); - - try { - timespec ts; - - key_file.load_from_file(current.get_path(), KeyFileFlags.NONE); - - string not_after_as_string = key_file.get_string("Ask", "NotAfter"); - - clock_gettime(1, out ts); - uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); - - uint64 not_after; - if (not_after_as_string.scanf("%llu", out not_after) != 1) - return false; - - if (not_after > 0 && not_after < now) - return false; - - socket = key_file.get_string("Ask", "Socket"); - } catch (GLib.Error e) { - return false; - } - - try { - message = key_file.get_string("Ask", "Message").compress(); - } catch (GLib.Error e) { - message = "Please Enter System Password!"; - } - - set_tooltip_text(message); - - try { - icon = key_file.get_string("Ask", "Icon"); - } catch (GLib.Error e) { - icon = "dialog-password"; - } - set_from_icon_name(icon); - - set_visible(true); - -#if LIBNOTIFY07 - Notification n = new Notification(title, message, icon); -#else - Notification n = new Notification(title, message, icon, null); - n.attach_to_status_icon(this); -#endif - n.set_timeout(5000); - n.show(); - - return true; - } - - void status_icon_activate() { - - if (current == null) - return; - - if (password_dialog != null) { - password_dialog.present(); - return; - } - - password_dialog = new PasswordDialog(message, icon); - - int result = password_dialog.run(); - string password = password_dialog.entry.get_text(); - - password_dialog.destroy(); - password_dialog = null; - - if (result == ResponseType.REJECT || - result == ResponseType.DELETE_EVENT) - return; - - int to_process; - - try { - Process.spawn_async_with_pipes( - null, - { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket }, - null, - 0, - null, - null, - out to_process, - null, - null); - - OutputStream stream = new UnixOutputStream(to_process, true); -#if VALA_0_12 - stream.write(password.data, null); -#else - stream.write(password, password.length, null); -#endif - } catch (Error e) { - show_error(e.message); - } - } -} - -static const OptionEntry entries[] = { - { null } -}; - -void show_error(string e) { - var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e); - m.run(); - m.destroy(); -} - -int main(string[] args) { - try { - Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent"); - Notify.init("Password Agent"); - - MyStatusIcon i = new MyStatusIcon(); - Gtk.main(); - - } catch (GLib.Error e) { - show_error(e.message); - } - - return 0; -} diff --git a/src/gpt-auto-generator/Makefile b/src/gpt-auto-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/gpt-auto-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c new file mode 100644 index 0000000..05934da --- /dev/null +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -0,0 +1,492 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LINUX_BTRFS_H +#include +#endif + +#include "path-util.h" +#include "util.h" +#include "mkdir.h" +#include "missing.h" +#include "sd-id128.h" +#include "libudev.h" +#include "udev-util.h" +#include "special.h" +#include "unit-name.h" +#include "virt.h" + +/* TODO: + * + * - Properly handle cryptsetup partitions + * - Define new partition type for encrypted swap + * - Make /home automount rather than mount + * + */ + +#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) + +static const char *arg_dest = "/tmp"; + +DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe); +#define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep) + +static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) { + _cleanup_blkid_freep_probe_ blkid_probe b = NULL; + const char *v; + int r; + + errno = 0; + b = blkid_new_probe_from_filename(node); + if (!b) + return errno != 0 ? -errno : -ENOMEM; + + blkid_probe_enable_superblocks(b, 1); + blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); + 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 || r == 1) /* no result or uncertain */ + return -EBADSLT; + else if (r != 0) + return errno ? -errno : -EIO; + + errno = 0; + r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL); + if (r != 0) + /* return 0 if we're not on GPT */ + return errno ? -errno : 0; + + if (strcmp(v, "gpt") != 0) + return 0; + + if (type) { + errno = 0; + r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); + if (r != 0) + return errno ? -errno : -EIO; + + r = sd_id128_from_string(v, type); + if (r < 0) + return r; + } + + if (nr) { + errno = 0; + r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); + if (r != 0) + return errno ? -errno : -EIO; + + r = safe_atou(v, nr); + if (r < 0) + return r; + } + + + if (fstype) { + errno = 0; + r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); + if (r != 0) + *fstype = NULL; + else { + char *fst; + + fst = strdup(v); + if (!fst) + return -ENOMEM; + + *fstype = fst; + } + } + + return 1; +} + +static int add_swap(const char *path, const char *fstype) { + _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; + + log_debug("Adding swap: %s %s", path, fstype); + + name = unit_name_from_path(path, ".swap"); + if (!name) + return log_oom(); + + unit = strjoin(arg_dest, "/", name, NULL); + if (!unit) + return log_oom(); + + f = fopen(unit, "wxe"); + if (!f) { + log_error("Failed to create unit file %s: %m", unit); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-gpt-auto-generator\n\n" + "[Unit]\n" + "DefaultDependencies=no\n" + "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" + "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n" + "[Swap]\n" + "What=%s\n", + path); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write unit file %s: %m", unit); + return -errno; + } + + lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(unit, lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + + return 0; +} + +static int add_home(const char *path, const char *fstype) { + _cleanup_free_ char *unit = NULL, *lnk = NULL, *fsck = NULL; + _cleanup_fclose_ FILE *f = NULL; + + if (dir_is_empty("/home") <= 0) + return 0; + + log_debug("Adding home: %s %s", path, fstype); + + unit = strappend(arg_dest, "/home.mount"); + if (!unit) + return log_oom(); + + f = fopen(unit, "wxe"); + if (!f) { + log_error("Failed to create unit file %s: %m", unit); + return -errno; + } + + fsck = unit_name_from_path_instance("systemd-fsck", path, ".service"); + if (!fsck) + return log_oom(); + + fprintf(f, + "# Automatically generated by systemd-gpt-auto-generator\n\n" + "[Unit]\n" + "DefaultDependencies=no\n" + "Requires=%s\n" + "After=" SPECIAL_LOCAL_FS_PRE_TARGET " %s\n" + "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" + "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n" + "[Mount]\n" + "What=%s\n" + "Where=/home\n" + "Type=%s\n", + fsck, fsck, path, fstype); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write unit file %s: %m", unit); + return -errno; + } + + lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(unit, lnk) < 0) { + log_error("Failed to create symlink %s: %m", lnk); + return -errno; + } + + return 0; +} + +static int enumerate_partitions(struct udev *udev, dev_t dev) { + struct udev_device *parent = NULL; + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct udev_list_entry *first, *item; + unsigned home_nr = (unsigned) -1; + _cleanup_free_ char *home = NULL, *home_fstype = NULL; + int r; + + e = udev_enumerate_new(udev); + if (!e) + return log_oom(); + + d = udev_device_new_from_devnum(udev, 'b', dev); + if (!d) + return log_oom(); + + parent = udev_device_get_parent(d); + if (!parent) + return log_oom(); + + r = udev_enumerate_add_match_parent(e, parent); + if (r < 0) + return log_oom(); + + r = udev_enumerate_add_match_subsystem(e, "block"); + if (r < 0) + return log_oom(); + + r = udev_enumerate_scan_devices(e); + if (r < 0) { + log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", + major(dev), minor(dev), strerror(-r)); + return r; + } + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_free_ char *fstype = NULL; + const char *node = NULL; + _cleanup_udev_device_unref_ struct udev_device *q; + sd_id128_t type_id; + unsigned nr; + + q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); + if (!q) + return log_oom(); + + if (udev_device_get_devnum(q) == udev_device_get_devnum(d)) + continue; + + if (udev_device_get_devnum(q) == udev_device_get_devnum(parent)) + continue; + + node = udev_device_get_devnode(q); + if (!node) + return log_oom(); + + r = verify_gpt_partition(node, &type_id, &nr, &fstype); + if (r < 0) { + /* skip child devices which are not detected properly */ + if (r == -EBADSLT) + continue; + log_error("Failed to verify GPT partition %s: %s", + node, strerror(-r)); + return r; + } + if (r == 0) + continue; + + if (sd_id128_equal(type_id, GPT_SWAP)) + add_swap(node, fstype); + else if (sd_id128_equal(type_id, GPT_HOME)) { + if (!home || nr < home_nr) { + free(home); + home = strdup(node); + if (!home) + return log_oom(); + + home_nr = nr; + + free(home_fstype); + home_fstype = fstype; + fstype = NULL; + } + } + } + + if (home && home_fstype) + add_home(home, home_fstype); + + return r; +} + +static int get_btrfs_block_device(const char *path, dev_t *dev) { + struct btrfs_ioctl_fs_info_args fsi = {}; + _cleanup_close_ int fd = -1; + uint64_t id; + + assert(path); + assert(dev); + + fd = open(path, O_DIRECTORY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0) + return -errno; + + /* We won't do this for btrfs RAID */ + if (fsi.num_devices != 1) + return 0; + + for (id = 1; id <= fsi.max_id; id++) { + struct btrfs_ioctl_dev_info_args di = { + .devid = id, + }; + struct stat st; + + if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) { + if (errno == ENODEV) + continue; + + return -errno; + } + + if (stat((char*) di.path, &st) < 0) + return -errno; + + if (!S_ISBLK(st.st_mode)) + return -ENODEV; + + if (major(st.st_rdev) == 0) + return -ENODEV; + + *dev = st.st_rdev; + return 1; + } + + return -ENODEV; +} + +static int get_block_device(const char *path, dev_t *dev) { + struct stat st; + struct statfs sfs; + + assert(path); + assert(dev); + + if (lstat("/", &st)) + return -errno; + + if (major(st.st_dev) != 0) { + *dev = st.st_dev; + return 1; + } + + if (statfs("/", &sfs) < 0) + return -errno; + + if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) + return get_btrfs_block_device(path, dev); + + return 0; +} + +static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) { + _cleanup_udev_device_unref_ struct udev_device *d; + const char *t; + char *n; + + d = udev_device_new_from_devnum(udev, 'b', devno); + if (!d) + return log_oom(); + + t = udev_device_get_devnode(d); + if (!t) + return -ENODEV; + + n = strdup(t); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int main(int argc, char *argv[]) { + _cleanup_free_ char *node = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + dev_t devno; + int r = 0; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + r = -EINVAL; + goto finish; + } + + if (argc > 1) + arg_dest = argv[3]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (in_initrd()) { + log_debug("In initrd, exiting."); + goto finish; + } + + if (detect_container(NULL) > 0) { + log_debug("In a container, exiting."); + goto finish; + } + + r = get_block_device("/", &devno); + if (r < 0) { + log_error("Failed to determine block device of root file system: %s", strerror(-r)); + goto finish; + } + if (r == 0) { + log_debug("Root file system not on a (single) block device."); + goto finish; + } + + udev = udev_new(); + if (!udev) { + r = log_oom(); + goto finish; + } + + r = devno_to_devnode(udev, devno, &node); + if (r < 0) { + log_error("Failed to determine block device node from major/minor: %s", strerror(-r)); + goto finish; + } + + log_debug("Root device %s.", node); + + r = verify_gpt_partition(node, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to verify GPT partition %s: %s", node, strerror(-r)); + goto finish; + } + if (r == 0) + goto finish; + + r = enumerate_partitions(udev, devno); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/gudev/.gitignore b/src/gudev/.gitignore new file mode 100644 index 0000000..4577903 --- /dev/null +++ b/src/gudev/.gitignore @@ -0,0 +1,7 @@ +gudev-1.0.pc +gudevenumtypes.c +gudevenumtypes.h +gudevmarshal.c +gudevmarshal.h +GUdev-1.0.gir +GUdev-1.0.typelib diff --git a/src/gudev/Makefile b/src/gudev/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/gudev/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/gudev/gjs-example.js b/src/gudev/gjs-example.js new file mode 100755 index 0000000..5586fd6 --- /dev/null +++ b/src/gudev/gjs-example.js @@ -0,0 +1,75 @@ +#!/usr/bin/env gjs-console + +// This currently depends on the following patches to gjs +// +// http://bugzilla.gnome.org/show_bug.cgi?id=584558 +// http://bugzilla.gnome.org/show_bug.cgi?id=584560 +// http://bugzilla.gnome.org/show_bug.cgi?id=584568 + +const GUdev = imports.gi.GUdev; +const Mainloop = imports.mainloop; + +function print_device (device) { + print (" subsystem: " + device.get_subsystem ()); + print (" devtype: " + device.get_devtype ()); + print (" name: " + device.get_name ()); + print (" number: " + device.get_number ()); + print (" sysfs_path: " + device.get_sysfs_path ()); + print (" driver: " + device.get_driver ()); + print (" action: " + device.get_action ()); + print (" seqnum: " + device.get_seqnum ()); + print (" device type: " + device.get_device_type ()); + print (" device number: " + device.get_device_number ()); + print (" device file: " + device.get_device_file ()); + print (" device file symlinks: " + device.get_device_file_symlinks ()); + print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); + var keys = device.get_property_keys (); + for (var n = 0; n < keys.length; n++) { + print (" " + keys[n] + "=" + device.get_property (keys[n])); + } +} + +function on_uevent (client, action, device) { + print ("action " + action + " on device " + device.get_sysfs_path()); + print_device (device); + print (""); +} + +var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); +client.connect ("uevent", on_uevent); + +var block_devices = client.query_by_subsystem ("block"); +for (var n = 0; n < block_devices.length; n++) { + print ("block device: " + block_devices[n].get_device_file ()); +} + +var d; + +d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); +if (d == null) { + print ("query_by_device_number 0x810 -> null"); +} else { + print ("query_by_device_number 0x810 -> " + d.get_device_file ()); + var dd = d.get_parent_with_subsystem ("usb", null); + print_device (dd); + print ("--------------------------------------------------------------------------"); + while (d != null) { + print_device (d); + print (""); + d = d.get_parent (); + } +} + +d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); +print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); + +d = client.query_by_subsystem_and_name ("block", "sda2"); +print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/sda"); +print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/block/8:0"); +print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); + +Mainloop.run('udev-example'); diff --git a/src/gudev/gudev-1.0.pc.in b/src/gudev/gudev-1.0.pc.in new file mode 100644 index 0000000..058262d --- /dev/null +++ b/src/gudev/gudev-1.0.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gudev-1.0 +Description: GObject bindings for libudev +Version: @VERSION@ +Requires: glib-2.0, gobject-2.0 +Libs: -L${libdir} -lgudev-1.0 +Cflags: -I${includedir}/gudev-1.0 diff --git a/src/gudev/gudev.h b/src/gudev/gudev.h new file mode 100644 index 0000000..1dc42b1 --- /dev/null +++ b/src/gudev/gudev.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __G_UDEV_H__ +#define __G_UDEV_H__ + +#define _GUDEV_INSIDE_GUDEV_H +#include +#include +#include +#include +#include +#include +#undef _GUDEV_INSIDE_GUDEV_H + +#endif /* __G_UDEV_H__ */ diff --git a/src/gudev/gudevclient.c b/src/gudev/gudevclient.c new file mode 100644 index 0000000..a151b50 --- /dev/null +++ b/src/gudev/gudevclient.c @@ -0,0 +1,525 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "gudevclient.h" +#include "gudevdevice.h" +#include "gudevmarshal.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevclient + * @short_description: Query devices and listen to uevents + * + * #GUdevClient is used to query information about devices on a Linux + * system from the Linux kernel and the udev device + * manager. + * + * Device information is retrieved from the kernel (through the + * sysfs filesystem) and the udev daemon (through a + * tmpfs filesystem) and presented through + * #GUdevDevice objects. This means that no blocking IO ever happens + * (in both cases, we are essentially just reading data from kernel + * memory) and as such there are no asynchronous versions of the + * provided methods. + * + * To get #GUdevDevice objects, use + * g_udev_client_query_by_subsystem(), + * g_udev_client_query_by_device_number(), + * g_udev_client_query_by_device_file(), + * g_udev_client_query_by_sysfs_path(), + * g_udev_client_query_by_subsystem_and_name() + * or the #GUdevEnumerator type. + * + * To listen to uevents, connect to the #GUdevClient::uevent signal. + */ + +struct _GUdevClientPrivate +{ + GSource *watch_source; + struct udev *udev; + struct udev_monitor *monitor; + + gchar **subsystems; +}; + +enum +{ + PROP_0, + PROP_SUBSYSTEMS, +}; + +enum +{ + UEVENT_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT) + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +monitor_event (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + GUdevClient *client = (GUdevClient *) data; + GUdevDevice *device; + struct udev_device *udevice; + + if (client->priv->monitor == NULL) + goto out; + udevice = udev_monitor_receive_device (client->priv->monitor); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + g_signal_emit (client, + signals[UEVENT_SIGNAL], + 0, + g_udev_device_get_action (device), + device); + g_object_unref (device); + + out: + return TRUE; +} + +static void +g_udev_client_finalize (GObject *object) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + if (client->priv->watch_source != NULL) + { + g_source_destroy (client->priv->watch_source); + client->priv->watch_source = NULL; + } + + if (client->priv->monitor != NULL) + { + udev_monitor_unref (client->priv->monitor); + client->priv->monitor = NULL; + } + + if (client->priv->udev != NULL) + { + udev_unref (client->priv->udev); + client->priv->udev = NULL; + } + + g_strfreev (client->priv->subsystems); + + if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object); +} + +static void +g_udev_client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + switch (prop_id) + { + case PROP_SUBSYSTEMS: + if (client->priv->subsystems != NULL) + g_strfreev (client->priv->subsystems); + client->priv->subsystems = g_strdupv (g_value_get_boxed (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + + switch (prop_id) + { + case PROP_SUBSYSTEMS: + g_value_set_boxed (value, client->priv->subsystems); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_client_constructed (GObject *object) +{ + GUdevClient *client = G_UDEV_CLIENT (object); + GIOChannel *channel; + guint n; + + client->priv->udev = udev_new (); + + /* connect to event source */ + client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev"); + + //g_debug ("ss = %p", client->priv->subsystems); + + if (client->priv->subsystems != NULL) + { + /* install subsystem filters to only wake up for certain events */ + for (n = 0; client->priv->subsystems[n] != NULL; n++) + { + gchar *subsystem; + gchar *devtype; + gchar *s; + + subsystem = g_strdup (client->priv->subsystems[n]); + devtype = NULL; + + //g_debug ("s = '%s'", subsystem); + + s = strstr (subsystem, "/"); + if (s != NULL) + { + devtype = s + 1; + *s = '\0'; + } + + if (client->priv->monitor != NULL) + udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype); + + g_free (subsystem); + } + + /* listen to events, and buffer them */ + if (client->priv->monitor != NULL) + { + udev_monitor_enable_receiving (client->priv->monitor); + channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor)); + client->priv->watch_source = g_io_create_watch (channel, G_IO_IN); + g_io_channel_unref (channel); + g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL); + g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ()); + g_source_unref (client->priv->watch_source); + } + else + { + client->priv->watch_source = NULL; + } + } + + if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL) + G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object); +} + + +static void +g_udev_client_class_init (GUdevClientClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->constructed = g_udev_client_constructed; + gobject_class->set_property = g_udev_client_set_property; + gobject_class->get_property = g_udev_client_get_property; + gobject_class->finalize = g_udev_client_finalize; + + /** + * GUdevClient:subsystems: + * + * The subsystems to listen for uevents on. + * + * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use + * "subsystem/devtype". For example, to only listen for uevents + * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use + * "usb/usb_interface". + * + * If this property is %NULL, then no events will be reported. If + * it's the empty array, events from all subsystems will be + * reported. + */ + g_object_class_install_property (gobject_class, + PROP_SUBSYSTEMS, + g_param_spec_boxed ("subsystems", + "The subsystems to listen for changes on", + "The subsystems to listen for changes on", + G_TYPE_STRV, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); + + /** + * GUdevClient::uevent: + * @client: The #GUdevClient receiving the event. + * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc. + * @device: Details about the #GUdevDevice the event is for. + * + * Emitted when @client receives an uevent. + * + * This signal is emitted in the + * thread-default main loop + * of the thread that @client was created in. + */ + signals[UEVENT_SIGNAL] = g_signal_new ("uevent", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GUdevClientClass, uevent), + NULL, + NULL, + g_udev_marshal_VOID__STRING_OBJECT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_UDEV_TYPE_DEVICE); + + g_type_class_add_private (klass, sizeof (GUdevClientPrivate)); +} + +static void +g_udev_client_init (GUdevClient *client) +{ + client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, + G_UDEV_TYPE_CLIENT, + GUdevClientPrivate); +} + +/** + * g_udev_client_new: + * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter. + * + * Constructs a #GUdevClient object that can be used to query + * information about devices. Connect to the #GUdevClient::uevent + * signal to listen for uevents. Note that signals are emitted in the + * thread-default main loop + * of the thread that you call this constructor from. + * + * Returns: A new #GUdevClient object. Free with g_object_unref(). + */ +GUdevClient * +g_udev_client_new (const gchar * const *subsystems) +{ + return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL)); +} + +/** + * g_udev_client_query_by_subsystem: + * @client: A #GUdevClient. + * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices. + * + * Gets all devices belonging to @subsystem. + * + * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. + */ +GList * +g_udev_client_query_by_subsystem (GUdevClient *client, + const gchar *subsystem) +{ + struct udev_enumerate *enumerate; + struct udev_list_entry *l, *devices; + GList *ret; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + + ret = NULL; + + /* prepare a device scan */ + enumerate = udev_enumerate_new (client->priv->udev); + + /* filter for subsystem */ + if (subsystem != NULL) + udev_enumerate_add_match_subsystem (enumerate, subsystem); + /* retrieve the list */ + udev_enumerate_scan_devices (enumerate); + + /* add devices to the list */ + devices = udev_enumerate_get_list_entry (enumerate); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) + { + struct udev_device *udevice; + GUdevDevice *device; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), + udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + ret = g_list_prepend (ret, device); + } + udev_enumerate_unref (enumerate); + + ret = g_list_reverse (ret); + + return ret; +} + +/** + * g_udev_client_query_by_device_number: + * @client: A #GUdevClient. + * @type: A value from the #GUdevDeviceType enumeration. + * @number: A device number. + * + * Looks up a device for a type and device number. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_device_number (GUdevClient *client, + GUdevDeviceType type, + GUdevDeviceNumber number) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + + device = NULL; + udevice = udev_device_new_from_devnum (client->priv->udev, type, number); + + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +/** + * g_udev_client_query_by_device_file: + * @client: A #GUdevClient. + * @device_file: A device file. + * + * Looks up a device for a device file. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_device_file (GUdevClient *client, + const gchar *device_file) +{ + struct stat stat_buf; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (device_file != NULL, NULL); + + device = NULL; + + if (stat (device_file, &stat_buf) != 0) + goto out; + + if (stat_buf.st_rdev == 0) + goto out; + + if (S_ISBLK (stat_buf.st_mode)) + device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev); + else if (S_ISCHR (stat_buf.st_mode)) + device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev); + + out: + return device; +} + +/** + * g_udev_client_query_by_sysfs_path: + * @client: A #GUdevClient. + * @sysfs_path: A sysfs path. + * + * Looks up a device for a sysfs path. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_sysfs_path (GUdevClient *client, + const gchar *sysfs_path) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (sysfs_path != NULL, NULL); + + device = NULL; + udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +/** + * g_udev_client_query_by_subsystem_and_name: + * @client: A #GUdevClient. + * @subsystem: A subsystem name. + * @name: The name of the device. + * + * Looks up a device for a subsystem and name. + * + * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_client_query_by_subsystem_and_name (GUdevClient *client, + const gchar *subsystem, + const gchar *name) +{ + struct udev_device *udevice; + GUdevDevice *device; + + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + device = NULL; + udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name); + if (udevice == NULL) + goto out; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + + out: + return device; +} + +struct udev * +_g_udev_client_get_udev (GUdevClient *client) +{ + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + return client->priv->udev; +} diff --git a/src/gudev/gudevclient.h b/src/gudev/gudevclient.h new file mode 100644 index 0000000..23bfce6 --- /dev/null +++ b/src/gudev/gudevclient.h @@ -0,0 +1,99 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_CLIENT_H__ +#define __G_UDEV_CLIENT_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ()) +#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient)) +#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass)) +#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT)) +#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT)) +#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass)) + +typedef struct _GUdevClientClass GUdevClientClass; +typedef struct _GUdevClientPrivate GUdevClientPrivate; + +/** + * GUdevClient: + * + * The #GUdevClient struct is opaque and should not be accessed directly. + */ +struct _GUdevClient +{ + GObject parent; + + /*< private >*/ + GUdevClientPrivate *priv; +}; + +/** + * GUdevClientClass: + * @parent_class: Parent class. + * @uevent: Signal class handler for the #GUdevClient::uevent signal. + * + * Class structure for #GUdevClient. + */ +struct _GUdevClientClass +{ + GObjectClass parent_class; + + /* signals */ + void (*uevent) (GUdevClient *client, + const gchar *action, + GUdevDevice *device); + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_client_get_type (void) G_GNUC_CONST; +GUdevClient *g_udev_client_new (const gchar* const *subsystems); +GList *g_udev_client_query_by_subsystem (GUdevClient *client, + const gchar *subsystem); +GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client, + GUdevDeviceType type, + GUdevDeviceNumber number); +GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client, + const gchar *device_file); +GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client, + const gchar *sysfs_path); +GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client, + const gchar *subsystem, + const gchar *name); + +G_END_DECLS + +#endif /* __G_UDEV_CLIENT_H__ */ diff --git a/src/gudev/gudevdevice.c b/src/gudev/gudevdevice.c new file mode 100644 index 0000000..2c768b7 --- /dev/null +++ b/src/gudev/gudevdevice.c @@ -0,0 +1,1014 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "gudevdevice.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevdevice + * @short_description: Get information about a device + * + * The #GUdevDevice class is used to get information about a specific + * device. Note that you cannot instantiate a #GUdevDevice object + * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice + * objects. + * + * To get basic information about a device, use + * g_udev_device_get_subsystem(), g_udev_device_get_devtype(), + * g_udev_device_get_name(), g_udev_device_get_number(), + * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(), + * g_udev_device_get_action(), g_udev_device_get_seqnum(), + * g_udev_device_get_device_type(), g_udev_device_get_device_number(), + * g_udev_device_get_device_file(), + * g_udev_device_get_device_file_symlinks(). + * + * To navigate the device tree, use g_udev_device_get_parent() and + * g_udev_device_get_parent_with_subsystem(). + * + * To access udev properties for the device, use + * g_udev_device_get_property_keys(), + * g_udev_device_has_property(), + * g_udev_device_get_property(), + * g_udev_device_get_property_as_int(), + * g_udev_device_get_property_as_uint64(), + * g_udev_device_get_property_as_double(), + * g_udev_device_get_property_as_boolean() and + * g_udev_device_get_property_as_strv(). + * + * To access sysfs attributes for the device, use + * g_udev_device_get_sysfs_attr_keys(), + * g_udev_device_has_sysfs_attr(), + * g_udev_device_get_sysfs_attr(), + * g_udev_device_get_sysfs_attr_as_int(), + * g_udev_device_get_sysfs_attr_as_uint64(), + * g_udev_device_get_sysfs_attr_as_double(), + * g_udev_device_get_sysfs_attr_as_boolean() and + * g_udev_device_get_sysfs_attr_as_strv(). + * + * Note that all getters on #GUdevDevice are non-reffing – returned + * values are owned by the object, should not be freed and are only + * valid as long as the object is alive. + * + * By design, #GUdevDevice will not react to changes for a device – it + * only contains a snapshot of information when the #GUdevDevice + * object was created. To work with changes, you typically connect to + * the #GUdevClient::uevent signal on a #GUdevClient and get a new + * #GUdevDevice whenever an event happens. + */ + +struct _GUdevDevicePrivate +{ + struct udev_device *udevice; + + /* computed ondemand and cached */ + gchar **device_file_symlinks; + gchar **property_keys; + gchar **sysfs_attr_keys; + gchar **tags; + GHashTable *prop_strvs; + GHashTable *sysfs_attr_strvs; +}; + +G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT) + +static void +g_udev_device_finalize (GObject *object) +{ + GUdevDevice *device = G_UDEV_DEVICE (object); + + g_strfreev (device->priv->device_file_symlinks); + g_strfreev (device->priv->property_keys); + g_strfreev (device->priv->sysfs_attr_keys); + g_strfreev (device->priv->tags); + + if (device->priv->udevice != NULL) + udev_device_unref (device->priv->udevice); + + if (device->priv->prop_strvs != NULL) + g_hash_table_unref (device->priv->prop_strvs); + + if (device->priv->sysfs_attr_strvs != NULL) + g_hash_table_unref (device->priv->sysfs_attr_strvs); + + if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL) + (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object); +} + +static void +g_udev_device_class_init (GUdevDeviceClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = g_udev_device_finalize; + + g_type_class_add_private (klass, sizeof (GUdevDevicePrivate)); +} + +static void +g_udev_device_init (GUdevDevice *device) +{ + device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, + G_UDEV_TYPE_DEVICE, + GUdevDevicePrivate); +} + + +GUdevDevice * +_g_udev_device_new (struct udev_device *udevice) +{ + GUdevDevice *device; + + device = G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL)); + device->priv->udevice = udev_device_ref (udevice); + + return device; +} + +/** + * g_udev_device_get_subsystem: + * @device: A #GUdevDevice. + * + * Gets the subsystem for @device. + * + * Returns: The subsystem for @device. + */ +const gchar * +g_udev_device_get_subsystem (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_subsystem (device->priv->udevice); +} + +/** + * g_udev_device_get_devtype: + * @device: A #GUdevDevice. + * + * Gets the device type for @device. + * + * Returns: The devtype for @device. + */ +const gchar * +g_udev_device_get_devtype (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_devtype (device->priv->udevice); +} + +/** + * g_udev_device_get_name: + * @device: A #GUdevDevice. + * + * Gets the name of @device, e.g. "sda3". + * + * Returns: The name of @device. + */ +const gchar * +g_udev_device_get_name (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_sysname (device->priv->udevice); +} + +/** + * g_udev_device_get_number: + * @device: A #GUdevDevice. + * + * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3". + * + * Returns: The number of @device. + */ +const gchar * +g_udev_device_get_number (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_sysnum (device->priv->udevice); +} + +/** + * g_udev_device_get_sysfs_path: + * @device: A #GUdevDevice. + * + * Gets the sysfs path for @device. + * + * Returns: The sysfs path for @device. + */ +const gchar * +g_udev_device_get_sysfs_path (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_syspath (device->priv->udevice); +} + +/** + * g_udev_device_get_driver: + * @device: A #GUdevDevice. + * + * Gets the name of the driver used for @device. + * + * Returns: The name of the driver for @device or %NULL if unknown. + */ +const gchar * +g_udev_device_get_driver (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_driver (device->priv->udevice); +} + +/** + * g_udev_device_get_action: + * @device: A #GUdevDevice. + * + * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device. + * + * Returns: An action string. + */ +const gchar * +g_udev_device_get_action (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_action (device->priv->udevice); +} + +/** + * g_udev_device_get_seqnum: + * @device: A #GUdevDevice. + * + * Gets the most recent sequence number for @device. + * + * Returns: A sequence number. + */ +guint64 +g_udev_device_get_seqnum (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + return udev_device_get_seqnum (device->priv->udevice); +} + +/** + * g_udev_device_get_device_type: + * @device: A #GUdevDevice. + * + * Gets the type of the device file, if any, for @device. + * + * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file. + */ +GUdevDeviceType +g_udev_device_get_device_type (GUdevDevice *device) +{ + struct stat stat_buf; + const gchar *device_file; + GUdevDeviceType type; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE); + + type = G_UDEV_DEVICE_TYPE_NONE; + + /* TODO: would be better to have support for this in libudev... */ + + device_file = g_udev_device_get_device_file (device); + if (device_file == NULL) + goto out; + + if (stat (device_file, &stat_buf) != 0) + goto out; + + if (S_ISBLK (stat_buf.st_mode)) + type = G_UDEV_DEVICE_TYPE_BLOCK; + else if (S_ISCHR (stat_buf.st_mode)) + type = G_UDEV_DEVICE_TYPE_CHAR; + + out: + return type; +} + +/** + * g_udev_device_get_device_number: + * @device: A #GUdevDevice. + * + * Gets the device number, if any, for @device. + * + * Returns: The device number for @device or 0 if unknown. + */ +GUdevDeviceNumber +g_udev_device_get_device_number (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + return udev_device_get_devnum (device->priv->udevice); +} + +/** + * g_udev_device_get_device_file: + * @device: A #GUdevDevice. + * + * Gets the device file for @device. + * + * Returns: The device file for @device or %NULL if no device file + * exists. + */ +const gchar * +g_udev_device_get_device_file (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + return udev_device_get_devnode (device->priv->udevice); +} + +/** + * g_udev_device_get_device_file_symlinks: + * @device: A #GUdevDevice. + * + * Gets a list of symlinks (in /dev) that points to + * the device file for @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller. + */ +const gchar * const * +g_udev_device_get_device_file_symlinks (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->device_file_symlinks != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->device_file_symlinks; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_parent: + * @device: A #GUdevDevice. + * + * Gets the immediate parent of @device, if any. + * + * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_device_get_parent (GUdevDevice *device) +{ + GUdevDevice *ret; + struct udev_device *udevice; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + ret = NULL; + + udevice = udev_device_get_parent (device->priv->udevice); + if (udevice == NULL) + goto out; + + ret = _g_udev_device_new (udevice); + + out: + return ret; +} + +/** + * g_udev_device_get_parent_with_subsystem: + * @device: A #GUdevDevice. + * @subsystem: The subsystem of the parent to get. + * @devtype: (allow-none): The devtype of the parent to get or %NULL. + * + * Walks up the chain of parents of @device and returns the first + * device encountered where @subsystem and @devtype matches, if any. + * + * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref(). + */ +GUdevDevice * +g_udev_device_get_parent_with_subsystem (GUdevDevice *device, + const gchar *subsystem, + const gchar *devtype) +{ + GUdevDevice *ret; + struct udev_device *udevice; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + + ret = NULL; + + udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice, + subsystem, + devtype); + if (udevice == NULL) + goto out; + + ret = _g_udev_device_new (udevice); + + out: + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_property_keys: + * @device: A #GUdevDevice. + * + * Gets all keys for properties on @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller. + */ +const gchar* const * +g_udev_device_get_property_keys (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->property_keys != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->property_keys; +} + + +/** + * g_udev_device_has_property: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Check if a the property with the given key exists. + * + * Returns: %TRUE only if the value for @key exist. + */ +gboolean +g_udev_device_has_property (GUdevDevice *device, + const gchar *key) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + return udev_device_get_property_value (device->priv->udevice, key) != NULL; +} + +/** + * g_udev_device_get_property: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device. + * + * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device. + */ +const gchar * +g_udev_device_get_property (GUdevDevice *device, + const gchar *key) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (key != NULL, NULL); + return udev_device_get_property_value (device->priv->udevice, key); +} + +/** + * g_udev_device_get_property_as_int: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an integer + * using strtol(). + * + * Returns: The value for @key or 0 if @key doesn't exist or + * isn't an integer. + */ +gint +g_udev_device_get_property_as_int (GUdevDevice *device, + const gchar *key) +{ + gint result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (key != NULL, 0); + + result = 0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = strtol (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_property_as_uint64: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an unsigned + * 64-bit integer using g_ascii_strtoull(). + * + * Returns: The value for @key or 0 if @key doesn't exist or isn't a + * #guint64. + */ +guint64 +g_udev_device_get_property_as_uint64 (GUdevDevice *device, + const gchar *key) +{ + guint64 result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (key != NULL, 0); + + result = 0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = g_ascii_strtoull (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_property_as_double: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to a double + * precision floating point number using strtod(). + * + * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a + * #gdouble. + */ +gdouble +g_udev_device_get_property_as_double (GUdevDevice *device, + const gchar *key) +{ + gdouble result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); + g_return_val_if_fail (key != NULL, 0.0); + + result = 0.0; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = strtod (s, NULL); +out: + return result; +} + +/** + * g_udev_device_get_property_as_boolean: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and convert it to an + * boolean. This is done by doing a case-insensitive string comparison + * on the string value against "1" and "true". + * + * Returns: The value for @key or %FALSE if @key doesn't exist or + * isn't a #gboolean. + */ +gboolean +g_udev_device_get_property_as_boolean (GUdevDevice *device, + const gchar *key) +{ + gboolean result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + result = FALSE; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) + result = TRUE; + out: + return result; +} + +static gchar ** +split_at_whitespace (const gchar *s) +{ + gchar **result; + guint n; + guint m; + + result = g_strsplit_set (s, " \v\t\r\n", 0); + + /* remove empty strings, thanks GLib */ + for (n = 0; result[n] != NULL; n++) + { + if (strlen (result[n]) == 0) + { + g_free (result[n]); + for (m = n; result[m] != NULL; m++) + result[m] = result[m + 1]; + n--; + } + } + + return result; +} + +/** + * g_udev_device_get_property_as_strv: + * @device: A #GUdevDevice. + * @key: Name of property. + * + * Look up the value for @key on @device and return the result of + * splitting it into non-empty tokens split at white space (only space + * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'), + * horizontal tab ('\t'), and vertical tab ('\v') are considered; the + * locale is not taken into account). + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller. + */ +const gchar* const * +g_udev_device_get_property_as_strv (GUdevDevice *device, + const gchar *key) +{ + gchar **result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (device->priv->prop_strvs != NULL) + { + result = g_hash_table_lookup (device->priv->prop_strvs, key); + if (result != NULL) + goto out; + } + + result = NULL; + s = g_udev_device_get_property (device, key); + if (s == NULL) + goto out; + + result = split_at_whitespace (s); + if (result == NULL) + goto out; + + if (device->priv->prop_strvs == NULL) + device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); + g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result); + +out: + return (const gchar* const *) result; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_udev_device_get_sysfs_attr_keys: + * @device: A #GUdevDevice. + * + * Gets all keys for sysfs attributes on @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of sysfs attribute keys. This array is owned by @device and should not be freed by the caller. + */ +const gchar * const * +g_udev_device_get_sysfs_attr_keys (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->sysfs_attr_keys != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_sysattr_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->sysfs_attr_keys = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->sysfs_attr_keys; +} + +/** + * g_udev_device_has_sysfs_attr: + * @device: A #GUdevDevice. + * @key: Name of sysfs attribute. + * + * Check if a the sysfs attribute with the given key exists. + * + * Returns: %TRUE only if the value for @key exist. + */ +gboolean +g_udev_device_has_sysfs_attr (GUdevDevice *device, + const gchar *key) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + return udev_device_get_sysattr_value (device->priv->udevice, key) != NULL; +} + +/** + * g_udev_device_get_sysfs_attr: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device. + * + * Returns: The value of the sysfs attribute or %NULL if there is no + * such attribute. Do not free this string, it is owned by @device. + */ +const gchar * +g_udev_device_get_sysfs_attr (GUdevDevice *device, + const gchar *name) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (name != NULL, NULL); + return udev_device_get_sysattr_value (device->priv->udevice, name); +} + +/** + * g_udev_device_get_sysfs_attr_as_int: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device and convert it to an integer + * using strtol(). + * + * Returns: The value of the sysfs attribute or 0 if there is no such + * attribute. + */ +gint +g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device, + const gchar *name) +{ + gint result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (name != NULL, 0); + + result = 0; + s = g_udev_device_get_sysfs_attr (device, name); + if (s == NULL) + goto out; + + result = strtol (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_sysfs_attr_as_uint64: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device and convert it to an unsigned + * 64-bit integer using g_ascii_strtoull(). + * + * Returns: The value of the sysfs attribute or 0 if there is no such + * attribute. + */ +guint64 +g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device, + const gchar *name) +{ + guint64 result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + g_return_val_if_fail (name != NULL, 0); + + result = 0; + s = g_udev_device_get_sysfs_attr (device, name); + if (s == NULL) + goto out; + + result = g_ascii_strtoull (s, NULL, 0); +out: + return result; +} + +/** + * g_udev_device_get_sysfs_attr_as_double: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device and convert it to a double + * precision floating point number using strtod(). + * + * Returns: The value of the sysfs attribute or 0.0 if there is no such + * attribute. + */ +gdouble +g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device, + const gchar *name) +{ + gdouble result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); + g_return_val_if_fail (name != NULL, 0.0); + + result = 0.0; + s = g_udev_device_get_sysfs_attr (device, name); + if (s == NULL) + goto out; + + result = strtod (s, NULL); +out: + return result; +} + +/** + * g_udev_device_get_sysfs_attr_as_boolean: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device and convert it to an + * boolean. This is done by doing a case-insensitive string comparison + * on the string value against "1" and "true". + * + * Returns: The value of the sysfs attribute or %FALSE if there is no such + * attribute. + */ +gboolean +g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device, + const gchar *name) +{ + gboolean result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + result = FALSE; + s = g_udev_device_get_sysfs_attr (device, name); + if (s == NULL) + goto out; + + if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) + result = TRUE; + out: + return result; +} + +/** + * g_udev_device_get_sysfs_attr_as_strv: + * @device: A #GUdevDevice. + * @name: Name of the sysfs attribute. + * + * Look up the sysfs attribute with @name on @device and return the result of + * splitting it into non-empty tokens split at white space (only space (' '), + * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal + * tab ('\t'), and vertical tab ('\v') are considered; the locale is + * not taken into account). + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of the sysfs attribute split into tokens or %NULL if there is no such attribute. This array is owned by @device and should not be freed by the caller. + */ +const gchar * const * +g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device, + const gchar *name) +{ + gchar **result; + const gchar *s; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + g_return_val_if_fail (name != NULL, NULL); + + if (device->priv->sysfs_attr_strvs != NULL) + { + result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name); + if (result != NULL) + goto out; + } + + result = NULL; + s = g_udev_device_get_sysfs_attr (device, name); + if (s == NULL) + goto out; + + result = split_at_whitespace (s); + if (result == NULL) + goto out; + + if (device->priv->sysfs_attr_strvs == NULL) + device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); + g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result); + +out: + return (const gchar* const *) result; +} + +/** + * g_udev_device_get_tags: + * @device: A #GUdevDevice. + * + * Gets all tags for @device. + * + * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of tags. This array is owned by @device and should not be freed by the caller. + * + * Since: 165 + */ +const gchar* const * +g_udev_device_get_tags (GUdevDevice *device) +{ + struct udev_list_entry *l; + GPtrArray *p; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + if (device->priv->tags != NULL) + goto out; + + p = g_ptr_array_new (); + for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) + { + g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); + } + g_ptr_array_add (p, NULL); + device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE); + + out: + return (const gchar * const *) device->priv->tags; +} + +/** + * g_udev_device_get_is_initialized: + * @device: A #GUdevDevice. + * + * Gets whether @device has been initalized. + * + * Returns: Whether @device has been initialized. + * + * Since: 165 + */ +gboolean +g_udev_device_get_is_initialized (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + return udev_device_get_is_initialized (device->priv->udevice); +} + +/** + * g_udev_device_get_usec_since_initialized: + * @device: A #GUdevDevice. + * + * Gets number of micro-seconds since @device was initialized. + * + * This only works for devices with properties in the udev + * database. All other devices return 0. + * + * Returns: Number of micro-seconds since @device was initialized or 0 if unknown. + * + * Since: 165 + */ +guint64 +g_udev_device_get_usec_since_initialized (GUdevDevice *device) +{ + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); + return udev_device_get_usec_since_initialized (device->priv->udevice); +} diff --git a/src/gudev/gudevdevice.h b/src/gudev/gudevdevice.h new file mode 100644 index 0000000..72ec180 --- /dev/null +++ b/src/gudev/gudevdevice.h @@ -0,0 +1,130 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_DEVICE_H__ +#define __G_UDEV_DEVICE_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ()) +#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice)) +#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) +#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE)) +#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE)) +#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) + +typedef struct _GUdevDeviceClass GUdevDeviceClass; +typedef struct _GUdevDevicePrivate GUdevDevicePrivate; + +/** + * GUdevDevice: + * + * The #GUdevDevice struct is opaque and should not be accessed directly. + */ +struct _GUdevDevice +{ + GObject parent; + + /*< private >*/ + GUdevDevicePrivate *priv; +}; + +/** + * GUdevDeviceClass: + * @parent_class: Parent class. + * + * Class structure for #GUdevDevice. + */ +struct _GUdevDeviceClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_device_get_type (void) G_GNUC_CONST; +gboolean g_udev_device_get_is_initialized (GUdevDevice *device); +guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device); +const gchar *g_udev_device_get_subsystem (GUdevDevice *device); +const gchar *g_udev_device_get_devtype (GUdevDevice *device); +const gchar *g_udev_device_get_name (GUdevDevice *device); +const gchar *g_udev_device_get_number (GUdevDevice *device); +const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device); +const gchar *g_udev_device_get_driver (GUdevDevice *device); +const gchar *g_udev_device_get_action (GUdevDevice *device); +guint64 g_udev_device_get_seqnum (GUdevDevice *device); +GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device); +GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device); +const gchar *g_udev_device_get_device_file (GUdevDevice *device); +const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device); +GUdevDevice *g_udev_device_get_parent (GUdevDevice *device); +GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device, + const gchar *subsystem, + const gchar *devtype); +const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device); +gboolean g_udev_device_has_property (GUdevDevice *device, + const gchar *key); +const gchar *g_udev_device_get_property (GUdevDevice *device, + const gchar *key); +gint g_udev_device_get_property_as_int (GUdevDevice *device, + const gchar *key); +guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device, + const gchar *key); +gdouble g_udev_device_get_property_as_double (GUdevDevice *device, + const gchar *key); +gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device, + const gchar *key); +const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device, + const gchar *key); + +const gchar* const *g_udev_device_get_sysfs_attr_keys (GUdevDevice *device); +gboolean g_udev_device_has_sysfs_attr (GUdevDevice *device, + const gchar *key); +const gchar *g_udev_device_get_sysfs_attr (GUdevDevice *device, + const gchar *name); +gint g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device, + const gchar *name); +guint64 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device, + const gchar *name); +gdouble g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device, + const gchar *name); +gboolean g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device, + const gchar *name); +const gchar* const *g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device, + const gchar *name); +const gchar* const *g_udev_device_get_tags (GUdevDevice *device); + +G_END_DECLS + +#endif /* __G_UDEV_DEVICE_H__ */ diff --git a/src/gudev/gudevenumerator.c b/src/gudev/gudevenumerator.c new file mode 100644 index 0000000..1fb3098 --- /dev/null +++ b/src/gudev/gudevenumerator.c @@ -0,0 +1,429 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "gudevclient.h" +#include "gudevenumerator.h" +#include "gudevdevice.h" +#include "gudevmarshal.h" +#include "gudevprivate.h" + +/** + * SECTION:gudevenumerator + * @short_description: Lookup and sort devices + * + * #GUdevEnumerator is used to lookup and sort devices. + * + * Since: 165 + */ + +struct _GUdevEnumeratorPrivate +{ + GUdevClient *client; + struct udev_enumerate *e; +}; + +enum +{ + PROP_0, + PROP_CLIENT, +}; + +G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT) + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +g_udev_enumerator_finalize (GObject *object) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + if (enumerator->priv->client != NULL) + { + g_object_unref (enumerator->priv->client); + enumerator->priv->client = NULL; + } + + if (enumerator->priv->e != NULL) + { + udev_enumerate_unref (enumerator->priv->e); + enumerator->priv->e = NULL; + } + + if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL) + G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object); +} + +static void +g_udev_enumerator_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + switch (prop_id) + { + case PROP_CLIENT: + if (enumerator->priv->client != NULL) + g_object_unref (enumerator->priv->client); + enumerator->priv->client = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_enumerator_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + switch (prop_id) + { + case PROP_CLIENT: + g_value_set_object (value, enumerator->priv->client); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_udev_enumerator_constructed (GObject *object) +{ + GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); + + g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client)); + + enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client)); + + if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL) + G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object); +} + +static void +g_udev_enumerator_class_init (GUdevEnumeratorClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = g_udev_enumerator_finalize; + gobject_class->set_property = g_udev_enumerator_set_property; + gobject_class->get_property = g_udev_enumerator_get_property; + gobject_class->constructed = g_udev_enumerator_constructed; + + /** + * GUdevEnumerator:client: + * + * The #GUdevClient to enumerate devices from. + * + * Since: 165 + */ + g_object_class_install_property (gobject_class, + PROP_CLIENT, + g_param_spec_object ("client", + "The client to enumerate devices from", + "The client to enumerate devices from", + G_UDEV_TYPE_CLIENT, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); + + g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate)); +} + +static void +g_udev_enumerator_init (GUdevEnumerator *enumerator) +{ + enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator, + G_UDEV_TYPE_ENUMERATOR, + GUdevEnumeratorPrivate); +} + +/** + * g_udev_enumerator_new: + * @client: A #GUdevClient to enumerate devices from. + * + * Constructs a #GUdevEnumerator object that can be used to enumerate + * and sort devices. Use the add_match_*() and add_nomatch_*() methods + * and execute the query to get a list of devices with + * g_udev_enumerator_execute(). + * + * Returns: A new #GUdevEnumerator object. Free with g_object_unref(). + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_new (GUdevClient *client) +{ + g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); + return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL)); +} + + +/** + * g_udev_enumerator_add_match_subsystem: + * @enumerator: A #GUdevEnumerator. + * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. + * + * All returned devices will match the given @subsystem. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem); + return enumerator; +} + +/** + * g_udev_enumerator_add_nomatch_subsystem: + * @enumerator: A #GUdevEnumerator. + * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. + * + * All returned devices will not match the given @subsystem. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (subsystem != NULL, NULL); + udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_sysfs_attr: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for sysfs attribute key. + * @value: Wildcard filter for sysfs attribute value. + * + * All returned devices will have a sysfs attribute matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_nomatch_sysfs_attr: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for sysfs attribute key. + * @value: Wildcard filter for sysfs attribute value. + * + * All returned devices will not have a sysfs attribute matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_property: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for property name. + * @value: Wildcard filter for property value. + * + * All returned devices will have a property matching the given @name and @value. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + udev_enumerate_add_match_property (enumerator->priv->e, name, value); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_name: + * @enumerator: A #GUdevEnumerator. + * @name: Wildcard filter for kernel name e.g. "sda*". + * + * All returned devices will match the given @name. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, + const gchar *name) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (name != NULL, NULL); + udev_enumerate_add_match_sysname (enumerator->priv->e, name); + return enumerator; +} + +/** + * g_udev_enumerator_add_sysfs_path: + * @enumerator: A #GUdevEnumerator. + * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda" + * + * Add a device to the list of devices, to retrieve it back sorted in dependency order. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, + const gchar *sysfs_path) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (sysfs_path != NULL, NULL); + udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_tag: + * @enumerator: A #GUdevEnumerator. + * @tag: A udev tag e.g. "udev-acl". + * + * All returned devices will match the given @tag. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, + const gchar *tag) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + g_return_val_if_fail (tag != NULL, NULL); + udev_enumerate_add_match_tag (enumerator->priv->e, tag); + return enumerator; +} + +/** + * g_udev_enumerator_add_match_is_initialized: + * @enumerator: A #GUdevEnumerator. + * + * All returned devices will be initialized. + * + * Returns: (transfer none): The passed in @enumerator. + * + * Since: 165 + */ +GUdevEnumerator * +g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator) +{ + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + udev_enumerate_add_match_is_initialized (enumerator->priv->e); + return enumerator; +} + +/** + * g_udev_enumerator_execute: + * @enumerator: A #GUdevEnumerator. + * + * Executes the query in @enumerator. + * + * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. + * + * Since: 165 + */ +GList * +g_udev_enumerator_execute (GUdevEnumerator *enumerator) +{ + GList *ret; + struct udev_list_entry *l, *devices; + + g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); + + ret = NULL; + + /* retrieve the list */ + udev_enumerate_scan_devices (enumerator->priv->e); + + devices = udev_enumerate_get_list_entry (enumerator->priv->e); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) + { + struct udev_device *udevice; + GUdevDevice *device; + + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e), + udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; + + device = _g_udev_device_new (udevice); + udev_device_unref (udevice); + ret = g_list_prepend (ret, device); + } + + ret = g_list_reverse (ret); + + return ret; +} diff --git a/src/gudev/gudevenumerator.h b/src/gudev/gudevenumerator.h new file mode 100644 index 0000000..e1dbcf1 --- /dev/null +++ b/src/gudev/gudevenumerator.h @@ -0,0 +1,106 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008-2010 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_ENUMERATOR_H__ +#define __G_UDEV_ENUMERATOR_H__ + +#include + +G_BEGIN_DECLS + +#define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ()) +#define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator)) +#define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) +#define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR)) +#define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR)) +#define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) + +typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass; +typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate; + +/** + * GUdevEnumerator: + * + * The #GUdevEnumerator struct is opaque and should not be accessed directly. + * + * Since: 165 + */ +struct _GUdevEnumerator +{ + GObject parent; + + /*< private >*/ + GUdevEnumeratorPrivate *priv; +}; + +/** + * GUdevEnumeratorClass: + * @parent_class: Parent class. + * + * Class structure for #GUdevEnumerator. + * + * Since: 165 + */ +struct _GUdevEnumeratorClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*reserved1) (void); + void (*reserved2) (void); + void (*reserved3) (void); + void (*reserved4) (void); + void (*reserved5) (void); + void (*reserved6) (void); + void (*reserved7) (void); + void (*reserved8) (void); +}; + +GType g_udev_enumerator_get_type (void) G_GNUC_CONST; +GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client); +GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem); +GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, + const gchar *subsystem); +GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, + const gchar *name, + const gchar *value); +GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, + const gchar *name); +GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, + const gchar *tag); +GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator); +GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, + const gchar *sysfs_path); +GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator); + +G_END_DECLS + +#endif /* __G_UDEV_ENUMERATOR_H__ */ diff --git a/src/gudev/gudevenums.h b/src/gudev/gudevenums.h new file mode 100644 index 0000000..467e93b --- /dev/null +++ b/src/gudev/gudevenums.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_ENUMS_H__ +#define __G_UDEV_ENUMS_H__ + +#include + +G_BEGIN_DECLS + +/** + * GUdevDeviceType: + * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file. + * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device. + * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device. + * + * Enumeration used to specify a the type of a device. + */ +typedef enum +{ + G_UDEV_DEVICE_TYPE_NONE = 0, + G_UDEV_DEVICE_TYPE_BLOCK = 'b', + G_UDEV_DEVICE_TYPE_CHAR = 'c', +} GUdevDeviceType; + +G_END_DECLS + +#endif /* __G_UDEV_ENUMS_H__ */ diff --git a/src/gudev/gudevenumtypes.c.template b/src/gudev/gudevenumtypes.c.template new file mode 100644 index 0000000..fc30b39 --- /dev/null +++ b/src/gudev/gudevenumtypes.c.template @@ -0,0 +1,39 @@ +/*** BEGIN file-header ***/ +#include + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/*** END value-tail ***/ + +/*** BEGIN file-tail ***/ +/*** END file-tail ***/ diff --git a/src/gudev/gudevenumtypes.h.template b/src/gudev/gudevenumtypes.h.template new file mode 100644 index 0000000..d0ab339 --- /dev/null +++ b/src/gudev/gudevenumtypes.h.template @@ -0,0 +1,24 @@ +/*** BEGIN file-header ***/ +#ifndef __GUDEV_ENUM_TYPES_H__ +#define __GUDEV_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* __GUDEV_ENUM_TYPES_H__ */ +/*** END file-tail ***/ diff --git a/src/gudev/gudevmarshal.list b/src/gudev/gudevmarshal.list new file mode 100644 index 0000000..7e66599 --- /dev/null +++ b/src/gudev/gudevmarshal.list @@ -0,0 +1 @@ +VOID:STRING,OBJECT diff --git a/src/gudev/gudevprivate.h b/src/gudev/gudevprivate.h new file mode 100644 index 0000000..52e272b --- /dev/null +++ b/src/gudev/gudevprivate.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_PRIVATE_H__ +#define __G_UDEV_PRIVATE_H__ + +#include + +#include + +G_BEGIN_DECLS + +GUdevDevice * +_g_udev_device_new (struct udev_device *udevice); + +struct udev *_g_udev_client_get_udev (GUdevClient *client); + +G_END_DECLS + +#endif /* __G_UDEV_PRIVATE_H__ */ diff --git a/src/gudev/gudevtypes.h b/src/gudev/gudevtypes.h new file mode 100644 index 0000000..e2f688f --- /dev/null +++ b/src/gudev/gudevtypes.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef __G_UDEV_TYPES_H__ +#define __G_UDEV_TYPES_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GUdevClient GUdevClient; +typedef struct _GUdevDevice GUdevDevice; +typedef struct _GUdevEnumerator GUdevEnumerator; + +/** + * GUdevDeviceNumber: + * + * Corresponds to the standard #dev_t type as defined by POSIX (Until + * bug 584517 is resolved this work-around is needed). + */ +#ifdef _GUDEV_WORK_AROUND_DEV_T_BUG +typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */ +#else +typedef dev_t GUdevDeviceNumber; +#endif + +G_END_DECLS + +#endif /* __G_UDEV_TYPES_H__ */ diff --git a/src/gudev/seed-example-enum.js b/src/gudev/seed-example-enum.js new file mode 100755 index 0000000..66206ad --- /dev/null +++ b/src/gudev/seed-example-enum.js @@ -0,0 +1,38 @@ +#!/usr/bin/env seed + +const GLib = imports.gi.GLib; +const GUdev = imports.gi.GUdev; + +function print_device(device) { + print(" initialized: " + device.get_is_initialized()); + print(" usec since initialized: " + device.get_usec_since_initialized()); + print(" subsystem: " + device.get_subsystem()); + print(" devtype: " + device.get_devtype()); + print(" name: " + device.get_name()); + print(" number: " + device.get_number()); + print(" sysfs_path: " + device.get_sysfs_path()); + print(" driver: " + device.get_driver()); + print(" action: " + device.get_action()); + print(" seqnum: " + device.get_seqnum()); + print(" device type: " + device.get_device_type()); + print(" device number: " + device.get_device_number()); + print(" device file: " + device.get_device_file()); + print(" device file symlinks: " + device.get_device_file_symlinks()); + print(" tags: " + device.get_tags()); + var keys = device.get_property_keys(); + for (var n = 0; n < keys.length; n++) { + print(" " + keys[n] + "=" + device.get_property(keys[n])); + } +} + +var client = new GUdev.Client({subsystems: []}); +var enumerator = new GUdev.Enumerator({client: client}); +enumerator.add_match_subsystem('b*') + +var devices = enumerator.execute(); + +for (var n=0; n < devices.length; n++) { + var device = devices[n]; + print_device(device); + print(""); +} diff --git a/src/gudev/seed-example.js b/src/gudev/seed-example.js new file mode 100755 index 0000000..e2ac324 --- /dev/null +++ b/src/gudev/seed-example.js @@ -0,0 +1,72 @@ +#!/usr/bin/env seed + +// seed example + +const GLib = imports.gi.GLib; +const GUdev = imports.gi.GUdev; + +function print_device (device) { + print (" subsystem: " + device.get_subsystem ()); + print (" devtype: " + device.get_devtype ()); + print (" name: " + device.get_name ()); + print (" number: " + device.get_number ()); + print (" sysfs_path: " + device.get_sysfs_path ()); + print (" driver: " + device.get_driver ()); + print (" action: " + device.get_action ()); + print (" seqnum: " + device.get_seqnum ()); + print (" device type: " + device.get_device_type ()); + print (" device number: " + device.get_device_number ()); + print (" device file: " + device.get_device_file ()); + print (" device file symlinks: " + device.get_device_file_symlinks ()); + print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); + var keys = device.get_property_keys (); + for (var n = 0; n < keys.length; n++) { + print (" " + keys[n] + "=" + device.get_property (keys[n])); + } +} + +function on_uevent (client, action, device) { + print ("action " + action + " on device " + device.get_sysfs_path()); + print_device (device); + print (""); +} + +var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); +client.signal.connect ("uevent", on_uevent); + +var block_devices = client.query_by_subsystem ("block"); +for (var n = 0; n < block_devices.length; n++) { + print ("block device: " + block_devices[n].get_device_file ()); +} + +var d; + +d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); +if (d == null) { + print ("query_by_device_number 0x810 -> null"); +} else { + print ("query_by_device_number 0x810 -> " + d.get_device_file ()); + dd = d.get_parent_with_subsystem ("usb", null); + print_device (dd); + print ("--------------------------------------------------------------------------"); + while (d != null) { + print_device (d); + print (""); + d = d.get_parent (); + } +} + +d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); +print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); + +d = client.query_by_subsystem_and_name ("block", "sda2"); +print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/sda"); +print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); + +d = client.query_by_device_file ("/dev/block/8:0"); +print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); + +var mainloop = GLib.main_loop_new (); +GLib.main_loop_run (mainloop); diff --git a/src/hashmap.c b/src/hashmap.c deleted file mode 100644 index 95ea45d..0000000 --- a/src/hashmap.c +++ /dev/null @@ -1,720 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "hashmap.h" -#include "macro.h" - -#define NBUCKETS 127 - -struct hashmap_entry { - const void *key; - void *value; - struct hashmap_entry *bucket_next, *bucket_previous; - struct hashmap_entry *iterate_next, *iterate_previous; -}; - -struct Hashmap { - hash_func_t hash_func; - compare_func_t compare_func; - - struct hashmap_entry *iterate_list_head, *iterate_list_tail; - unsigned n_entries; - - bool from_pool; -}; - -#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap)))) - -struct pool { - struct pool *next; - unsigned n_tiles; - unsigned n_used; -}; - -struct pool *first_hashmap_pool = NULL; -static void *first_hashmap_tile = NULL; - -struct pool *first_entry_pool = NULL; -static void *first_entry_tile = NULL; - -static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size) { - unsigned i; - - if (*first_tile) { - void *r; - - r = *first_tile; - *first_tile = * (void**) (*first_tile); - return r; - } - - if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) { - unsigned n; - size_t size; - struct pool *p; - - n = *first_pool ? (*first_pool)->n_tiles : 0; - n = MAX(512U, n * 2); - size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); - n = (size - ALIGN(sizeof(struct pool))) / tile_size; - - p = malloc(size); - if (!p) - return NULL; - - p->next = *first_pool; - p->n_tiles = n; - p->n_used = 0; - - *first_pool = p; - } - - i = (*first_pool)->n_used++; - - return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size; -} - -static void deallocate_tile(void **first_tile, void *p) { - * (void**) p = *first_tile; - *first_tile = p; -} - -#ifndef __OPTIMIZE__ - -static void drop_pool(struct pool *p) { - while (p) { - struct pool *n; - n = p->next; - free(p); - p = n; - } -} - -__attribute__((destructor)) static void cleanup_pool(void) { - /* Be nice to valgrind */ - - drop_pool(first_hashmap_pool); - drop_pool(first_entry_pool); -} - -#endif - -unsigned string_hash_func(const void *p) { - unsigned hash = 5381; - const signed char *c; - - /* DJB's hash function */ - - for (c = p; *c; c++) - hash = (hash << 5) + hash + (unsigned) *c; - - return hash; -} - -int string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -unsigned trivial_hash_func(const void *p) { - return PTR_TO_UINT(p); -} - -int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); -} - -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { - bool b; - Hashmap *h; - size_t size; - - b = is_main_thread(); - - size = ALIGN(sizeof(Hashmap)) + NBUCKETS * sizeof(struct hashmap_entry*); - - if (b) { - h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size); - if (!h) - return NULL; - - memset(h, 0, size); - } else { - h = malloc0(size); - - if (!h) - return NULL; - } - - h->hash_func = hash_func ? hash_func : trivial_hash_func; - h->compare_func = compare_func ? compare_func : trivial_compare_func; - - h->n_entries = 0; - h->iterate_list_head = h->iterate_list_tail = NULL; - - h->from_pool = b; - - return h; -} - -int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) { - assert(h); - - if (*h) - return 0; - - if (!(*h = hashmap_new(hash_func, compare_func))) - return -ENOMEM; - - return 0; -} - -static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Insert into hash table */ - e->bucket_next = BY_HASH(h)[hash]; - e->bucket_previous = NULL; - if (BY_HASH(h)[hash]) - BY_HASH(h)[hash]->bucket_previous = e; - BY_HASH(h)[hash] = e; - - /* Insert into iteration list */ - e->iterate_previous = h->iterate_list_tail; - e->iterate_next = NULL; - if (h->iterate_list_tail) { - assert(h->iterate_list_head); - h->iterate_list_tail->iterate_next = e; - } else { - assert(!h->iterate_list_head); - h->iterate_list_head = e; - } - h->iterate_list_tail = e; - - h->n_entries++; - assert(h->n_entries >= 1); -} - -static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Remove from iteration list */ - if (e->iterate_next) - e->iterate_next->iterate_previous = e->iterate_previous; - else - h->iterate_list_tail = e->iterate_previous; - - if (e->iterate_previous) - e->iterate_previous->iterate_next = e->iterate_next; - else - h->iterate_list_head = e->iterate_next; - - /* Remove from hash table bucket list */ - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else - BY_HASH(h)[hash] = e->bucket_next; - - assert(h->n_entries >= 1); - h->n_entries--; -} - -static void remove_entry(Hashmap *h, struct hashmap_entry *e) { - unsigned hash; - - assert(h); - assert(e); - - hash = h->hash_func(e->key) % NBUCKETS; - - unlink_entry(h, e, hash); - - if (h->from_pool) - deallocate_tile(&first_entry_tile, e); - else - free(e); -} - -void hashmap_free(Hashmap*h) { - - if (!h) - return; - - hashmap_clear(h); - - if (h->from_pool) - deallocate_tile(&first_hashmap_tile, h); - else - free(h); -} - -void hashmap_free_free(Hashmap *h) { - void *p; - - while ((p = hashmap_steal_first(h))) - free(p); - - hashmap_free(h); -} - -void hashmap_clear(Hashmap *h) { - if (!h) - return; - - while (h->iterate_list_head) - remove_entry(h, h->iterate_list_head); -} - -static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - assert(h); - assert(hash < NBUCKETS); - - for (e = BY_HASH(h)[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int hashmap_put(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); - - hash = h->hash_func(key) % NBUCKETS; - - if ((e = hash_scan(h, hash, key))) { - - if (e->value == value) - return 0; - - return -EEXIST; - } - - if (h->from_pool) - e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry)); - else - e = new(struct hashmap_entry, 1); - - if (!e) - return -ENOMEM; - - e->key = key; - e->value = value; - - link_entry(h, e, hash); - - return 1; -} - -int hashmap_replace(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); - - hash = h->hash_func(key) % NBUCKETS; - - if ((e = hash_scan(h, hash, key))) { - e->key = key; - e->value = value; - return 0; - } - - return hashmap_put(h, key, value); -} - -void* hashmap_get(Hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - return e->value; -} - -void* hashmap_remove(Hashmap *h, const void *key) { - struct hashmap_entry *e; - unsigned hash; - void *data; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - data = e->value; - remove_entry(h, e); - - return data; -} - -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct hashmap_entry *e; - unsigned old_hash, new_hash; - - if (!h) - return -ENOENT; - - old_hash = h->hash_func(old_key) % NBUCKETS; - if (!(e = hash_scan(h, old_hash, old_key))) - return -ENOENT; - - new_hash = h->hash_func(new_key) % NBUCKETS; - if (hash_scan(h, new_hash, new_key)) - return -EEXIST; - - unlink_entry(h, e, old_hash); - - e->key = new_key; - e->value = value; - - link_entry(h, e, new_hash); - - return 0; -} - -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct hashmap_entry *e, *k; - unsigned old_hash, new_hash; - - if (!h) - return -ENOENT; - - old_hash = h->hash_func(old_key) % NBUCKETS; - if (!(e = hash_scan(h, old_hash, old_key))) - return -ENOENT; - - new_hash = h->hash_func(new_key) % NBUCKETS; - - if ((k = hash_scan(h, new_hash, new_key))) - if (e != k) - remove_entry(h, k); - - unlink_entry(h, e, old_hash); - - e->key = new_key; - e->value = value; - - link_entry(h, e, new_hash); - - return 0; -} - -void* hashmap_remove_value(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - if (e->value != value) - return NULL; - - remove_entry(h, e); - - return value; -} - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_end; - - if (*i == ITERATOR_LAST) - goto at_end; - - if (*i == ITERATOR_FIRST && !h->iterate_list_head) - goto at_end; - - e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i; - - if (e->iterate_next) - *i = (Iterator) e->iterate_next; - else - *i = ITERATOR_LAST; - - if (key) - *key = e->key; - - return e->value; - -at_end: - *i = ITERATOR_LAST; - - if (key) - *key = NULL; - - return NULL; -} - -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_beginning; - - if (*i == ITERATOR_FIRST) - goto at_beginning; - - if (*i == ITERATOR_LAST && !h->iterate_list_tail) - goto at_beginning; - - e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; - - if (e->iterate_previous) - *i = (Iterator) e->iterate_previous; - else - *i = ITERATOR_FIRST; - - if (key) - *key = e->key; - - return e->value; - -at_beginning: - *i = ITERATOR_FIRST; - - if (key) - *key = NULL; - - return NULL; -} - -void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - *i = (Iterator) e; - - return e->value; -} - -void* hashmap_first(Hashmap *h) { - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - return h->iterate_list_head->value; -} - -void* hashmap_last(Hashmap *h) { - - if (!h) - return NULL; - - if (!h->iterate_list_tail) - return NULL; - - return h->iterate_list_tail->value; -} - -void* hashmap_steal_first(Hashmap *h) { - void *data; - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - data = h->iterate_list_head->value; - remove_entry(h, h->iterate_list_head); - - return data; -} - -void* hashmap_steal_first_key(Hashmap *h) { - void *key; - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - key = (void*) h->iterate_list_head->key; - remove_entry(h, h->iterate_list_head); - - return key; -} - -unsigned hashmap_size(Hashmap *h) { - - if (!h) - return 0; - - return h->n_entries; -} - -bool hashmap_isempty(Hashmap *h) { - - if (!h) - return true; - - return h->n_entries == 0; -} - -int hashmap_merge(Hashmap *h, Hashmap *other) { - struct hashmap_entry *e; - - assert(h); - - if (!other) - return 0; - - for (e = other->iterate_list_head; e; e = e->iterate_next) { - int r; - - if ((r = hashmap_put(h, e->key, e->value)) < 0) - if (r != -EEXIST) - return r; - } - - return 0; -} - -void hashmap_move(Hashmap *h, Hashmap *other) { - struct hashmap_entry *e, *n; - - assert(h); - - /* The same as hashmap_merge(), but every new item from other - * is moved to h. This function is guaranteed to succeed. */ - - if (!other) - return; - - for (e = other->iterate_list_head; e; e = n) { - unsigned h_hash, other_hash; - - n = e->iterate_next; - - h_hash = h->hash_func(e->key) % NBUCKETS; - - if (hash_scan(h, h_hash, e->key)) - continue; - - other_hash = other->hash_func(e->key) % NBUCKETS; - - unlink_entry(other, e, other_hash); - link_entry(h, e, h_hash); - } -} - -int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { - unsigned h_hash, other_hash; - struct hashmap_entry *e; - - if (!other) - return 0; - - assert(h); - - h_hash = h->hash_func(key) % NBUCKETS; - if (hash_scan(h, h_hash, key)) - return -EEXIST; - - other_hash = other->hash_func(key) % NBUCKETS; - if (!(e = hash_scan(other, other_hash, key))) - return -ENOENT; - - unlink_entry(other, e, other_hash); - link_entry(h, e, h_hash); - - return 0; -} - -Hashmap *hashmap_copy(Hashmap *h) { - Hashmap *copy; - - assert(h); - - if (!(copy = hashmap_new(h->hash_func, h->compare_func))) - return NULL; - - if (hashmap_merge(copy, h) < 0) { - hashmap_free(copy); - return NULL; - } - - return copy; -} - -char **hashmap_get_strv(Hashmap *h) { - char **sv; - Iterator it; - char *item; - int n; - - sv = new(char*, h->n_entries+1); - if (!sv) - return NULL; - - n = 0; - HASHMAP_FOREACH(item, h, it) - sv[n++] = item; - sv[n] = NULL; - - return sv; -} diff --git a/src/hashmap.h b/src/hashmap.h deleted file mode 100644 index 16ffbd3..0000000 --- a/src/hashmap.h +++ /dev/null @@ -1,90 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foohashmaphfoo -#define foohashmaphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -/* Pretty straightforward hash table implementation. As a minor - * optimization a NULL hashmap object will be treated as empty hashmap - * for all read operations. That way it is not necessary to - * instantiate an object for each Hashmap use. */ - -typedef struct Hashmap Hashmap; -typedef struct _IteratorStruct _IteratorStruct; -typedef _IteratorStruct* Iterator; - -#define ITERATOR_FIRST ((Iterator) 0) -#define ITERATOR_LAST ((Iterator) -1) - -typedef unsigned (*hash_func_t)(const void *p); -typedef int (*compare_func_t)(const void *a, const void *b); - -unsigned string_hash_func(const void *p); -int string_compare_func(const void *a, const void *b); - -unsigned trivial_hash_func(const void *p); -int trivial_compare_func(const void *a, const void *b); - -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); -void hashmap_free(Hashmap *h); -void hashmap_free_free(Hashmap *h); -Hashmap *hashmap_copy(Hashmap *h); -int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func); - -int hashmap_put(Hashmap *h, const void *key, void *value); -int hashmap_replace(Hashmap *h, const void *key, void *value); -void* hashmap_get(Hashmap *h, const void *key); -void* hashmap_remove(Hashmap *h, const void *key); -void* hashmap_remove_value(Hashmap *h, const void *key, void *value); -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); - -int hashmap_merge(Hashmap *h, Hashmap *other); -void hashmap_move(Hashmap *h, Hashmap *other); -int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key); - -unsigned hashmap_size(Hashmap *h); -bool hashmap_isempty(Hashmap *h); - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i); - -void hashmap_clear(Hashmap *h); -void *hashmap_steal_first(Hashmap *h); -void *hashmap_steal_first_key(Hashmap *h); -void* hashmap_first(Hashmap *h); -void* hashmap_last(Hashmap *h); - -char **hashmap_get_strv(Hashmap *h); - -#define HASHMAP_FOREACH(e, h, i) \ - for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) - -#define HASHMAP_FOREACH_KEY(e, k, h, i) \ - for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k))) - -#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \ - for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL)) - -#endif diff --git a/src/hostname-setup.c b/src/hostname-setup.c deleted file mode 100644 index 7216b75..0000000 --- a/src/hostname-setup.c +++ /dev/null @@ -1,187 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "hostname-setup.h" -#include "macro.h" -#include "util.h" -#include "log.h" - -#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) -#define FILENAME "/etc/sysconfig/network" -#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) -#define FILENAME "/etc/HOSTNAME" -#elif defined(TARGET_ARCH) -#define FILENAME "/etc/rc.conf" -#elif defined(TARGET_GENTOO) -#define FILENAME "/etc/conf.d/hostname" -#endif - -static int read_and_strip_hostname(const char *path, char **hn) { - char *s; - int r; - - assert(path); - assert(hn); - - if ((r = read_one_line_file(path, &s)) < 0) - return r; - - hostname_cleanup(s); - - if (isempty(s)) { - free(s); - return -ENOENT; - } - - *hn = s; - - return 0; -} - -static int read_distro_hostname(char **hn) { - -#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) - int r; - FILE *f; - - assert(hn); - - if (!(f = fopen(FILENAME, "re"))) - return -errno; - - for (;;) { - char line[LINE_MAX]; - char *s, *k; - - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - break; - - r = -errno; - goto finish; - } - - s = strstrip(line); - - if (!startswith_no_case(s, "HOSTNAME=")) - continue; - - if (!(k = strdup(s+9))) { - r = -ENOMEM; - goto finish; - } - - hostname_cleanup(k); - - if (isempty(k)) { - free(k); - r = -ENOENT; - goto finish; - } - - *hn = k; - r = 0; - goto finish; - } - - r = -ENOENT; - -finish: - fclose(f); - return r; - -#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) - return read_and_strip_hostname(FILENAME, hn); -#else - return -ENOENT; -#endif -} - -static int read_hostname(char **hn) { - int r; - - assert(hn); - - /* First, try to load the generic hostname configuration file, - * that we support on all distributions */ - - if ((r = read_and_strip_hostname("/etc/hostname", hn)) < 0) { - - if (r == -ENOENT) - return read_distro_hostname(hn); - - return r; - } - - return 0; -} - -int hostname_setup(void) { - int r; - char *b = NULL; - const char *hn = NULL; - - if ((r = read_hostname(&b)) < 0) { - if (r == -ENOENT) - log_info("No hostname configured."); - else - log_warning("Failed to read configured hostname: %s", strerror(-r)); - - hn = NULL; - } else - hn = b; - - if (!hn) { - /* Don't override the hostname if it is unset and not - * explicitly configured */ - - char *old_hostname = NULL; - - if ((old_hostname = gethostname_malloc())) { - bool already_set; - - already_set = old_hostname[0] != 0; - free(old_hostname); - - if (already_set) - goto finish; - } - - hn = "localhost"; - } - - if (sethostname(hn, strlen(hn)) < 0) { - log_warning("Failed to set hostname to <%s>: %m", hn); - r = -errno; - } else - log_info("Set hostname to <%s>.", hn); - -finish: - free(b); - - return r; -} diff --git a/src/hostname-setup.h b/src/hostname-setup.h deleted file mode 100644 index ff11df9..0000000 --- a/src/hostname-setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foohostnamesetuphfoo -#define foohostnamesetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int hostname_setup(void); - -#endif diff --git a/src/hostname/.gitignore b/src/hostname/.gitignore new file mode 100644 index 0000000..1ff281b --- /dev/null +++ b/src/hostname/.gitignore @@ -0,0 +1 @@ +org.freedesktop.hostname1.policy diff --git a/src/hostname/Makefile b/src/hostname/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/hostname/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c new file mode 100644 index 0000000..e455249 --- /dev/null +++ b/src/hostname/hostnamectl.c @@ -0,0 +1,492 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" + +#include "bus-util.h" +#include "bus-error.h" +#include "util.h" +#include "spawn-polkit-agent.h" +#include "build.h" +#include "hwclock.h" +#include "strv.h" +#include "sd-id128.h" +#include "virt.h" +#include "architecture.h" +#include "fileio.h" + +static bool arg_ask_password = true; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_transient = false; +static bool arg_pretty = false; +static bool arg_static = false; + +static void polkit_agent_open_if_enabled(void) { + + /* Open the polkit agent as a child process if necessary */ + if (!arg_ask_password) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + polkit_agent_open(); +} + +typedef struct StatusInfo { + char *hostname; + char *static_hostname; + char *pretty_hostname; + char *icon_name; + char *chassis; +} StatusInfo; + +static void print_status_info(StatusInfo *i) { + sd_id128_t mid = {}, bid = {}; + int r; + const char *id = NULL; + _cleanup_free_ char *pretty_name = NULL, *cpe_name = NULL; + struct utsname u; + + assert(i); + + printf(" Static hostname: %s\n", + strna(i->static_hostname)); + + if (!isempty(i->pretty_hostname) && + !streq_ptr(i->pretty_hostname, i->static_hostname)) + printf(" Pretty hostname: %s\n", + strna(i->pretty_hostname)); + + if (!isempty(i->hostname) && + !streq_ptr(i->hostname, i->static_hostname)) + printf("Transient hostname: %s\n", + strna(i->hostname)); + + printf(" Icon name: %s\n" + " Chassis: %s\n", + strna(i->icon_name), + strna(i->chassis)); + + r = sd_id128_get_machine(&mid); + if (r >= 0) + printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid)); + + r = sd_id128_get_boot(&bid); + if (r >= 0) + printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid)); + + if (detect_virtualization(&id) > 0) + printf(" Virtualization: %s\n", id); + + r = parse_env_file("/etc/os-release", NEWLINE, + "PRETTY_NAME", &pretty_name, + "CPE_NAME", &cpe_name, + NULL); + if (r < 0) + log_warning("Failed to read /etc/os-release: %s", strerror(-r)); + + if (!isempty(pretty_name)) + printf(" Operating System: %s\n", pretty_name); + + if (!isempty(cpe_name)) + printf(" CPE OS Name: %s\n", cpe_name); + + assert_se(uname(&u) >= 0); + printf(" Kernel: %s %s\n" + " Architecture: %s\n", + u.sysname, u.release, + architecture_to_string(uname_architecture())); + +} + +static int show_one_name(sd_bus *bus, const char* attr) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *s; + int r; + + r = sd_bus_get_property( + bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + attr, + &error, &reply, "s"); + if (r < 0) { + log_error("Could not get property: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &s); + if (r < 0) + return bus_log_parse_error(r); + + printf("%s\n", s); + + return 0; +} + +static int show_all_names(sd_bus *bus) { + StatusInfo info = {}; + static const struct bus_properties_map map[] = { + { "Hostname", "s", NULL, offsetof(StatusInfo, hostname) }, + { "StaticHostname", "s", NULL, offsetof(StatusInfo, static_hostname) }, + { "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) }, + { "IconName", "s", NULL, offsetof(StatusInfo, icon_name) }, + { "Chassis", "s", NULL, offsetof(StatusInfo, chassis) }, + {} + }; + int r; + + r = bus_map_all_properties(bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + map, + &info); + if (r < 0) + goto fail; + + print_status_info(&info); + +fail: + free(info.hostname); + free(info.static_hostname); + free(info.pretty_hostname); + free(info.icon_name); + free(info.chassis); + return 0; +} + +static int show_status(sd_bus *bus, char **args, unsigned n) { + assert(args); + + if (arg_pretty || arg_static || arg_transient) { + const char *attr; + + if (!!arg_static + !!arg_pretty + !!arg_transient > 1) { + log_error("Cannot query more than one name type at a time"); + return -EINVAL; + } + + attr = arg_pretty ? "PrettyHostname" : + arg_static ? "StaticHostname" : "Hostname"; + + return show_one_name(bus, attr); + } else + return show_all_names(bus); +} + +static int set_simple_string(sd_bus *bus, const char *method, const char *value) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; + + polkit_agent_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + method, + &error, NULL, + "sb", value, arg_ask_password); + if (r < 0) + log_error("Could not set property: %s", bus_error_message(&error, -r)); + return r; +} + +static int set_hostname(sd_bus *bus, char **args, unsigned n) { + _cleanup_free_ char *h = NULL; + const char *hostname = args[1]; + int r; + + assert(args); + assert(n == 2); + + if (!arg_pretty && !arg_static && !arg_transient) + arg_pretty = arg_static = arg_transient = true; + + if (arg_pretty) { + const char *p; + + /* If the passed hostname is already valid, then + * assume the user doesn't know anything about pretty + * hostnames, so let's unset the pretty hostname, and + * just set the passed hostname as static/dynamic + * hostname. */ + + h = strdup(hostname); + if (!h) + return log_oom(); + + hostname_cleanup(h, true); + + if (arg_static && streq(h, hostname)) + p = ""; + else { + p = hostname; + hostname = h; + } + + r = set_simple_string(bus, "SetPrettyHostname", p); + if (r < 0) + return r; + } + + if (arg_static) { + r = set_simple_string(bus, "SetStaticHostname", hostname); + if (r < 0) + return r; + } + + if (arg_transient) { + r = set_simple_string(bus, "SetHostname", hostname); + if (r < 0) + return r; + } + + return 0; +} + +static int set_icon_name(sd_bus *bus, char **args, unsigned n) { + assert(args); + assert(n == 2); + + return set_simple_string(bus, "SetIconName", args[1]); +} + +static int set_chassis(sd_bus *bus, char **args, unsigned n) { + assert(args); + assert(n == 2); + + return set_simple_string(bus, "SetChassis", args[1]); +} + +static int help(void) { + + printf("%s [OPTIONS...] COMMAND ...\n\n" + "Query or change system hostname.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-ask-password Do not prompt for password\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --transient Only set transient hostname\n" + " --static Only set static hostname\n" + " --pretty Only set pretty hostname\n\n" + "Commands:\n" + " status Show current hostname settings\n" + " set-hostname NAME Set system hostname\n" + " set-icon-name NAME Set icon name for host\n" + " set-chassis NAME Set chassis type for host\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_ASK_PASSWORD, + ARG_TRANSIENT, + ARG_STATIC, + ARG_PRETTY + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "transient", no_argument, NULL, ARG_TRANSIENT }, + { "static", no_argument, NULL, ARG_STATIC }, + { "pretty", no_argument, NULL, ARG_PRETTY }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case ARG_TRANSIENT: + arg_transient = true; + break; + + case ARG_PRETTY: + arg_pretty = true; + break; + + case ARG_STATIC: + arg_static = true; + break; + + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args, unsigned n); + } verbs[] = { + { "status", LESS, 1, show_status }, + { "set-hostname", EQUAL, 2, set_hostname }, + { "set-icon-name", EQUAL, 2, set_icon_name }, + { "set-chassis", EQUAL, 2, set_chassis }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "status" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(bus, argv + optind, left); +} + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, false, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + r = hostnamectl_main(bus, argc, argv); + +finish: + return r < 0 ? EXIT_FAILURE : r; +} diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c new file mode 100644 index 0000000..6aa08ca --- /dev/null +++ b/src/hostname/hostnamed.c @@ -0,0 +1,652 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" +#include "def.h" +#include "virt.h" +#include "env-util.h" +#include "fileio-label.h" +#include "label.h" +#include "bus-util.h" +#include "event-util.h" + +enum { + PROP_HOSTNAME, + PROP_STATIC_HOSTNAME, + PROP_PRETTY_HOSTNAME, + PROP_ICON_NAME, + PROP_CHASSIS, + _PROP_MAX +}; + +typedef struct Context { + char *data[_PROP_MAX]; + Hashmap *polkit_registry; +} Context; + +static void context_reset(Context *c) { + int p; + + assert(c); + + for (p = 0; p < _PROP_MAX; p++) { + free(c->data[p]); + c->data[p] = NULL; + } +} + +static void context_free(Context *c, sd_bus *bus) { + assert(c); + + context_reset(c); + bus_verify_polkit_async_registry_free(bus, c->polkit_registry); +} + +static int context_read_data(Context *c) { + int r; + + assert(c); + + context_reset(c); + + c->data[PROP_HOSTNAME] = gethostname_malloc(); + if (!c->data[PROP_HOSTNAME]) + return -ENOMEM; + + r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]); + if (r < 0 && r != -ENOENT) + return r; + + r = parse_env_file("/etc/machine-info", NEWLINE, + "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], + "ICON_NAME", &c->data[PROP_ICON_NAME], + "CHASSIS", &c->data[PROP_CHASSIS], + NULL); + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static bool check_nss(void) { + void *dl; + + dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY); + if (dl) { + dlclose(dl); + return true; + } + + return false; +} + +static bool valid_chassis(const char *chassis) { + + assert(chassis); + + return nulstr_contains( + "vm\0" + "container\0" + "desktop\0" + "laptop\0" + "server\0" + "tablet\0" + "handset\0", + chassis); +} + +static const char* fallback_chassis(void) { + int r; + char *type; + unsigned t; + int v; + + v = detect_virtualization(NULL); + + if (v == VIRTUALIZATION_VM) + return "vm"; + if (v == VIRTUALIZATION_CONTAINER) + return "container"; + + r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type); + if (r < 0) + goto try_dmi; + + r = safe_atou(type, &t); + free(type); + if (r < 0) + goto try_dmi; + + /* We only list the really obvious cases here as the ACPI data + * is not really super reliable. + * + * See the ACPI 5.0 Spec Section 5.2.9.1 for details: + * + * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf + */ + + switch(t) { + + case 1: + case 3: + case 6: + return "desktop"; + + case 2: + return "laptop"; + + case 4: + case 5: + case 7: + return "server"; + + case 8: + return "tablet"; + } + +try_dmi: + r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); + if (r < 0) + return NULL; + + r = safe_atou(type, &t); + free(type); + if (r < 0) + return NULL; + + /* We only list the really obvious cases here. The DMI data is + unreliable enough, so let's not do any additional guesswork + on top of that. + + See the SMBIOS Specification 2.7.1 section 7.4.1 for + details about the values listed here: + + http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf + */ + + switch (t) { + + case 0x3: + case 0x4: + case 0x6: + case 0x7: + return "desktop"; + + case 0x8: + case 0x9: + case 0xA: + case 0xE: + return "laptop"; + + case 0xB: + return "handset"; + + case 0x11: + case 0x1C: + return "server"; + } + + return NULL; +} + +static char* context_fallback_icon_name(Context *c) { + const char *chassis; + + assert(c); + + if (!isempty(c->data[PROP_CHASSIS])) + return strappend("computer-", c->data[PROP_CHASSIS]); + + chassis = fallback_chassis(); + if (chassis) + return strappend("computer-", chassis); + + return strdup("computer"); +} + +static int context_write_data_hostname(Context *c) { + const char *hn; + + assert(c); + + if (isempty(c->data[PROP_HOSTNAME])) + hn = "localhost"; + else + hn = c->data[PROP_HOSTNAME]; + + if (sethostname(hn, strlen(hn)) < 0) + return -errno; + + return 0; +} + +static int context_write_data_static_hostname(Context *c) { + + assert(c); + + if (isempty(c->data[PROP_STATIC_HOSTNAME])) { + + if (unlink("/etc/hostname") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]); +} + +static int context_write_data_other(Context *c) { + + static const char * const name[_PROP_MAX] = { + [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", + [PROP_ICON_NAME] = "ICON_NAME", + [PROP_CHASSIS] = "CHASSIS" + }; + + _cleanup_strv_free_ char **l = NULL; + int r, p; + + assert(c); + + r = load_env_file("/etc/machine-info", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 2; p < _PROP_MAX; p++) { + char *t, **u; + + assert(name[p]); + + if (isempty(c->data[p])) { + strv_env_unset(l, name[p]); + continue; + } + + if (asprintf(&t, "%s=%s", name[p], strempty(c->data[p])) < 0) + return -ENOMEM; + + u = strv_env_set(l, t); + free(t); + + if (!u) + return -ENOMEM; + + strv_free(l); + l = u; + } + + if (strv_isempty(l)) { + + if (unlink("/etc/machine-info") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + return write_env_file_label("/etc/machine-info", l); +} + +static int property_get_icon_name( + 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 *n = NULL; + Context *c = userdata; + const char *name; + + if (isempty(c->data[PROP_ICON_NAME])) + name = n = context_fallback_icon_name(c); + else + name = c->data[PROP_ICON_NAME]; + + if (!name) + return -ENOMEM; + + return sd_bus_message_append(reply, "s", name); +} + +static int property_get_chassis( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Context *c = userdata; + const char *name; + + if (isempty(c->data[PROP_CHASSIS])) + name = fallback_chassis(); + else + name = c->data[PROP_CHASSIS]; + + return sd_bus_message_append(reply, "s", name); +} + +static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + const char *name; + int interactive; + char *h; + int r; + + r = sd_bus_message_read(m, "sb", &name, &interactive); + if (r < 0) + return r; + + if (isempty(name)) + name = c->data[PROP_STATIC_HOSTNAME]; + + if (isempty(name)) + name = "localhost"; + + if (!hostname_is_valid(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name); + + if (streq_ptr(name, c->data[PROP_HOSTNAME])) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c); + 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 */ + + h = strdup(name); + if (!h) + return -ENOMEM; + + free(c->data[PROP_HOSTNAME]); + c->data[PROP_HOSTNAME] = h; + + r = context_write_data_hostname(c); + if (r < 0) { + log_error("Failed to set host name: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r)); + } + + log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME])); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + const char *name; + int interactive; + int r; + + r = sd_bus_message_read(m, "sb", &name, &interactive); + if (r < 0) + return r; + + if (isempty(name)) + name = NULL; + + if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME])) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c); + 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 (isempty(name)) { + free(c->data[PROP_STATIC_HOSTNAME]); + c->data[PROP_STATIC_HOSTNAME] = NULL; + } else { + char *h; + + if (!hostname_is_valid(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name); + + h = strdup(name); + if (!h) + return -ENOMEM; + + free(c->data[PROP_STATIC_HOSTNAME]); + c->data[PROP_STATIC_HOSTNAME] = h; + } + + r = context_write_data_static_hostname(c); + if (r < 0) { + log_error("Failed to write static host name: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r)); + } + + log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME])); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) { + int interactive; + const char *name; + int r; + + assert(c); + assert(bus); + assert(m); + + r = sd_bus_message_read(m, "sb", &name, &interactive); + if (r < 0) + return r; + + if (isempty(name)) + name = NULL; + + if (streq_ptr(name, c->data[prop])) + return sd_bus_reply_method_return(m, NULL); + + /* Since the pretty hostname should always be changed at the + * same time as the static one, use the same policy action for + * both... */ + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ? + "org.freedesktop.hostname1.set-static-hostname" : + "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c); + 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 (isempty(name)) { + free(c->data[prop]); + c->data[prop] = NULL; + } else { + char *h; + + /* The icon name might ultimately be used as file + * name, so better be safe than sorry */ + + if (prop == PROP_ICON_NAME && !filename_is_safe(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name); + if (prop == PROP_PRETTY_HOSTNAME && + (string_has_cc(name) || chars_intersect(name, "\t"))) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name); + if (prop == PROP_CHASSIS && !valid_chassis(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name); + + h = strdup(name); + if (!h) + return -ENOMEM; + + free(c->data[prop]); + c->data[prop] = h; + } + + r = context_write_data_other(c); + if (r < 0) { + log_error("Failed to write machine info: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r)); + } + + log_info("Changed %s to '%s'", + prop == PROP_PRETTY_HOSTNAME ? "pretty host name" : + prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop])); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", + prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" : + prop == PROP_CHASSIS ? "Chassis" : "IconName", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error); +} + +static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error); +} + +static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error); +} + +static const sd_bus_vtable hostname_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0), + SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + assert(c); + assert(event); + assert(_bus); + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to get system bus connection: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_object_vtable(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c); + if (r < 0) { + log_error("Failed to register object: %s", strerror(-r)); + return r; + } + + r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(bus, event, 0); + if (r < 0) { + log_error("Failed to attach bus to event loop: %s", strerror(-r)); + return r; + } + + *_bus = bus; + bus = NULL; + + return 0; +} + +int main(int argc, char *argv[]) { + Context context = {}; + + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + label_init("/etc"); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + if (!check_nss()) + log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!"); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + r = sd_event_default(&event); + if (r < 0) { + log_error("Failed to allocate event loop: %s", strerror(-r)); + goto finish; + } + + sd_event_set_watchdog(event, true); + + r = connect_bus(&context, event, &bus); + if (r < 0) + goto finish; + + r = context_read_data(&context); + if (r < 0) { + log_error("Failed to read hostname and machine information: %s", strerror(-r)); + goto finish; + } + + r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + goto finish; + } + +finish: + context_free(&context, bus); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/hostname/org.freedesktop.hostname1.conf b/src/hostname/org.freedesktop.hostname1.conf new file mode 100644 index 0000000..46b4aad --- /dev/null +++ b/src/hostname/org.freedesktop.hostname1.conf @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/hostname/org.freedesktop.hostname1.policy.in b/src/hostname/org.freedesktop.hostname1.policy.in new file mode 100644 index 0000000..c32c1d4 --- /dev/null +++ b/src/hostname/org.freedesktop.hostname1.policy.in @@ -0,0 +1,50 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Set host name + <_message>Authentication is required to set the local host name. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Set static host name + <_message>Authentication is required to set the statically configured local host name, as well as the pretty host name. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.hostname1.set-hostname org.freedesktop.hostname1.set-machine-info + + + + <_description>Set machine information + <_message>Authentication is required to set local machine information. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + diff --git a/src/hostname/org.freedesktop.hostname1.service b/src/hostname/org.freedesktop.hostname1.service new file mode 100644 index 0000000..6041ed6 --- /dev/null +++ b/src/hostname/org.freedesktop.hostname1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.hostname1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.hostname1.service diff --git a/src/hostnamed.c b/src/hostnamed.c deleted file mode 100644 index f3b2c94..0000000 --- a/src/hostnamed.c +++ /dev/null @@ -1,623 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" -#include "dbus-common.h" -#include "polkit.h" -#include "def.h" -#include "virt.h" - -#define INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - BUS_PEER_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.hostname1\0" - -const char hostname_interface[] _introspect_("hostname1") = INTERFACE; - -enum { - PROP_HOSTNAME, - PROP_STATIC_HOSTNAME, - PROP_PRETTY_HOSTNAME, - PROP_ICON_NAME, - _PROP_MAX -}; - -static char *data[_PROP_MAX] = { - NULL, - NULL, - NULL, - NULL -}; - -static usec_t remain_until = 0; - -static void free_data(void) { - int p; - - for (p = 0; p < _PROP_MAX; p++) { - free(data[p]); - data[p] = NULL; - } -} - -static int read_data(void) { - int r; - - free_data(); - - data[PROP_HOSTNAME] = gethostname_malloc(); - if (!data[PROP_HOSTNAME]) - return -ENOMEM; - - r = read_one_line_file("/etc/hostname", &data[PROP_STATIC_HOSTNAME]); - if (r < 0 && r != -ENOENT) - return r; - - r = parse_env_file("/etc/machine-info", NEWLINE, - "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME], - "ICON_NAME", &data[PROP_ICON_NAME], - NULL); - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static bool check_nss(void) { - - void *dl; - - if ((dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY))) { - dlclose(dl); - return true; - } - - return false; -} - -static const char* fallback_icon_name(void) { - -#if defined(__i386__) || defined(__x86_64__) - int r; - char *type; - unsigned t; -#endif - - if (detect_virtualization(NULL) > 0) - return "computer-vm"; - -#if defined(__i386__) || defined(__x86_64__) - r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); - if (r < 0) - return NULL; - - r = safe_atou(type, &t); - free(type); - - if (r < 0) - return NULL; - - /* We only list the really obvious cases here. The DMI data is - unreliable enough, so let's not do any additional guesswork - on top of that. - - See the SMBIOS Specification 2.7.1 section 7.4.1 for - details about the values listed here: - - http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf - */ - - switch (t) { - - case 0x3: - case 0x4: - case 0x6: - case 0x7: - return "computer-desktop"; - - case 0x9: - case 0xA: - case 0xE: - return "computer-laptop"; - - case 0x11: - case 0x1C: - return "computer-server"; - } - -#endif - return NULL; -} - -static int write_data_hostname(void) { - const char *hn; - - if (isempty(data[PROP_HOSTNAME])) - hn = "localhost"; - else - hn = data[PROP_HOSTNAME]; - - if (sethostname(hn, strlen(hn)) < 0) - return -errno; - - return 0; -} - -static int write_data_static_hostname(void) { - - if (isempty(data[PROP_STATIC_HOSTNAME])) { - - if (unlink("/etc/hostname") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - return write_one_line_file_atomic("/etc/hostname", data[PROP_STATIC_HOSTNAME]); -} - -static int write_data_other(void) { - - static const char * const name[_PROP_MAX] = { - [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", - [PROP_ICON_NAME] = "ICON_NAME" - }; - - char **l = NULL; - int r, p; - - r = load_env_file("/etc/machine-info", &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 2; p < _PROP_MAX; p++) { - char *t, **u; - - assert(name[p]); - - if (isempty(data[p])) { - strv_env_unset(l, name[p]); - continue; - } - - if (asprintf(&t, "%s=%s", name[p], strempty(data[p])) < 0) { - strv_free(l); - return -ENOMEM; - } - - u = strv_env_set(l, t); - free(t); - strv_free(l); - - if (!u) - return -ENOMEM; - l = u; - } - - if (strv_isempty(l)) { - - if (unlink("/etc/machine-info") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file("/etc/machine-info", l); - strv_free(l); - - return r; -} - -static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) { - const char *name; - - assert(i); - assert(property); - - if (isempty(data[PROP_ICON_NAME])) - name = fallback_icon_name(); - else - name = data[PROP_ICON_NAME]; - - return bus_property_append_string(i, property, (void*) name); -} - -static DBusHandlerResult hostname_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - const BusProperty properties[] = { - { "org.freedesktop.hostname1", "Hostname", bus_property_append_string, "s", data[PROP_HOSTNAME]}, - { "org.freedesktop.hostname1", "StaticHostname", bus_property_append_string, "s", data[PROP_STATIC_HOSTNAME]}, - { "org.freedesktop.hostname1", "PrettyHostname", bus_property_append_string, "s", data[PROP_PRETTY_HOSTNAME]}, - { "org.freedesktop.hostname1", "IconName", bus_hostname_append_icon_name, "s", data[PROP_ICON_NAME]}, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL, *changed = NULL; - DBusError error; - int r; - - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetHostname")) { - const char *name; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = data[PROP_STATIC_HOSTNAME]; - - if (isempty(name)) - name = "localhost"; - - if (!hostname_is_valid(name)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - if (!streq_ptr(name, data[PROP_HOSTNAME])) { - char *h; - - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - h = strdup(name); - if (!h) - goto oom; - - free(data[PROP_HOSTNAME]); - data[PROP_HOSTNAME] = h; - - r = write_data_hostname(); - if (r < 0) { - log_error("Failed to set host name: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed host name to '%s'", strempty(data[PROP_HOSTNAME])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - "Hostname\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetStaticHostname")) { - const char *name; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = NULL; - - if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) { - - r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (isempty(name)) { - free(data[PROP_STATIC_HOSTNAME]); - data[PROP_STATIC_HOSTNAME] = NULL; - } else { - char *h; - - if (!hostname_is_valid(name)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - h = strdup(name); - if (!h) - goto oom; - - free(data[PROP_STATIC_HOSTNAME]); - data[PROP_STATIC_HOSTNAME] = h; - } - - r = write_data_static_hostname(); - if (r < 0) { - log_error("Failed to write static host name: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed static host name to '%s'", strempty(data[PROP_STATIC_HOSTNAME])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - "StaticHostname\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") || - dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) { - - const char *name; - dbus_bool_t interactive; - int k; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(name)) - name = NULL; - - k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME; - - if (!streq_ptr(name, data[k])) { - - /* Since the pretty hostname should always be - * changed at the same time as the static one, - * use the same policy action for both... */ - - r = verify_polkit(connection, message, k == PROP_PRETTY_HOSTNAME ? - "org.freedesktop.hostname1.set-static-hostname" : - "org.freedesktop.hostname1.set-machine-info", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (isempty(name)) { - free(data[k]); - data[k] = NULL; - } else { - char *h; - - h = strdup(name); - if (!h) - goto oom; - - free(data[k]); - data[k] = h; - } - - r = write_data_other(); - if (r < 0) { - log_error("Failed to write machine info: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k])); - - changed = bus_properties_changed_new( - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", - k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0"); - if (!changed) - goto oom; - } - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - reply = NULL; - - if (changed) { - - if (!dbus_connection_send(connection, changed, NULL)) - goto oom; - - dbus_message_unref(changed); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (changed) - dbus_message_unref(changed); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static int connect_bus(DBusConnection **_bus) { - static const DBusObjectPathVTable hostname_vtable = { - .message_function = hostname_message_handler - }; - DBusError error; - DBusConnection *bus = NULL; - int r; - - assert(_bus); - - dbus_error_init(&error); - - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!bus) { - log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); - r = -ECONNREFUSED; - goto fail; - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL) || - !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - r = dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); - if (dbus_error_is_set(&error)) { - log_error("Failed to register name on bus: %s", bus_error_message(&error)); - r = -EEXIST; - goto fail; - } - - if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - log_error("Failed to acquire name."); - r = -EEXIST; - goto fail; - } - - if (_bus) - *_bus = bus; - - return 0; - -fail: - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_error_free(&error); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - DBusConnection *bus = NULL; - bool exiting = false; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc == 2 && streq(argv[1], "--introspect")) { - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", stdout); - fputs(hostname_interface, stdout); - fputs("\n", stdout); - return 0; - } - - if (argc != 1) { - log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; - } - - if (!check_nss()) - log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!"); - - r = read_data(); - if (r < 0) { - log_error("Failed to read hostname data: %s", strerror(-r)); - goto finish; - } - - r = connect_bus(&bus); - if (r < 0) - goto finish; - - remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - for (;;) { - - if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) - break; - - if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { - exiting = true; - bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); - } - } - - r = 0; - -finish: - free_data(); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/initctl.c b/src/initctl.c deleted file mode 100644 index eaa717a..0000000 --- a/src/initctl.c +++ /dev/null @@ -1,442 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "util.h" -#include "log.h" -#include "list.h" -#include "initreq.h" -#include "special.h" -#include "sd-daemon.h" -#include "dbus-common.h" -#include "def.h" - -#define SERVER_FD_MAX 16 -#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) - -typedef struct Fifo Fifo; - -typedef struct Server { - int epoll_fd; - - LIST_HEAD(Fifo, fifos); - unsigned n_fifos; - - DBusConnection *bus; -} Server; - -struct Fifo { - Server *server; - - int fd; - - struct init_request buffer; - size_t bytes_read; - - LIST_FIELDS(Fifo, fifo); -}; - -static const char *translate_runlevel(int runlevel, bool *isolate) { - static const struct { - const int runlevel; - const char *special; - bool isolate; - } table[] = { - { '0', SPECIAL_POWEROFF_TARGET, false }, - { '1', SPECIAL_RESCUE_TARGET, true }, - { 's', SPECIAL_RESCUE_TARGET, true }, - { 'S', SPECIAL_RESCUE_TARGET, true }, - { '2', SPECIAL_RUNLEVEL2_TARGET, true }, - { '3', SPECIAL_RUNLEVEL3_TARGET, true }, - { '4', SPECIAL_RUNLEVEL4_TARGET, true }, - { '5', SPECIAL_RUNLEVEL5_TARGET, true }, - { '6', SPECIAL_REBOOT_TARGET, false }, - }; - - unsigned i; - - assert(isolate); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (table[i].runlevel == runlevel) { - *isolate = table[i].isolate; - if (runlevel == '6' && kexec_loaded()) - return SPECIAL_KEXEC_TARGET; - return table[i].special; - } - - return NULL; -} - -static void change_runlevel(Server *s, int runlevel) { - const char *target; - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - const char *mode; - bool isolate = false; - - assert(s); - - dbus_error_init(&error); - - if (!(target = translate_runlevel(runlevel, &isolate))) { - log_warning("Got request for unknown runlevel %c, ignoring.", runlevel); - goto finish; - } - - if (isolate) - mode = "isolate"; - else - mode = "replace"; - - log_debug("Running request %s/start/%s", target, mode); - - if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) { - log_error("Could not allocate message."); - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &target, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not attach target and flag information to message."); - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) { - log_error("Failed to start unit: %s", bus_error_message(&error)); - goto finish; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); -} - -static void request_process(Server *s, const struct init_request *req) { - assert(s); - assert(req); - - if (req->magic != INIT_MAGIC) { - log_error("Got initctl request with invalid magic. Ignoring."); - return; - } - - switch (req->cmd) { - - case INIT_CMD_RUNLVL: - if (!isprint(req->runlevel)) - log_error("Got invalid runlevel. Ignoring."); - else - switch (req->runlevel) { - - /* we are async anyway, so just use kill for reexec/reload */ - case 'u': - case 'U': - if (kill(1, SIGTERM) < 0) - log_error("kill() failed: %m"); - break; - - case 'q': - case 'Q': - if (kill(1, SIGHUP) < 0) - log_error("kill() failed: %m"); - break; - - default: - change_runlevel(s, req->runlevel); - } - return; - - case INIT_CMD_POWERFAIL: - case INIT_CMD_POWERFAILNOW: - case INIT_CMD_POWEROK: - log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!"); - return; - - case INIT_CMD_CHANGECONS: - log_warning("Received console change initctl request. This is not implemented in systemd."); - return; - - case INIT_CMD_SETENV: - case INIT_CMD_UNSETENV: - log_warning("Received environment initctl request. This is not implemented in systemd."); - return; - - default: - log_warning("Received unknown initctl request. Ignoring."); - return; - } -} - -static int fifo_process(Fifo *f) { - ssize_t l; - - assert(f); - - errno = EIO; - if ((l = read(f->fd, ((uint8_t*) &f->buffer) + f->bytes_read, sizeof(f->buffer) - f->bytes_read)) <= 0) { - - if (errno == EAGAIN) - return 0; - - log_warning("Failed to read from fifo: %s", strerror(errno)); - return -1; - } - - f->bytes_read += l; - assert(f->bytes_read <= sizeof(f->buffer)); - - if (f->bytes_read == sizeof(f->buffer)) { - request_process(f->server, &f->buffer); - f->bytes_read = 0; - } - - return 0; -} - -static void fifo_free(Fifo *f) { - assert(f); - - if (f->server) { - assert(f->server->n_fifos > 0); - f->server->n_fifos--; - LIST_REMOVE(Fifo, fifo, f->server->fifos, f); - } - - if (f->fd >= 0) { - if (f->server) - epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL); - - close_nointr_nofail(f->fd); - } - - free(f); -} - -static void server_done(Server *s) { - assert(s); - - while (s->fifos) - fifo_free(s->fifos); - - if (s->epoll_fd >= 0) - close_nointr_nofail(s->epoll_fd); - - if (s->bus) { - dbus_connection_flush(s->bus); - dbus_connection_close(s->bus); - dbus_connection_unref(s->bus); - } -} - -static int server_init(Server *s, unsigned n_sockets) { - int r; - unsigned i; - DBusError error; - - assert(s); - assert(n_sockets > 0); - - dbus_error_init(&error); - - zero(*s); - - if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) { - r = -errno; - log_error("Failed to create epoll object: %s", strerror(errno)); - goto fail; - } - - for (i = 0; i < n_sockets; i++) { - struct epoll_event ev; - Fifo *f; - int fd; - - fd = SD_LISTEN_FDS_START+i; - - if ((r = sd_is_fifo(fd, NULL)) < 0) { - log_error("Failed to determine file descriptor type: %s", strerror(-r)); - goto fail; - } - - if (!r) { - log_error("Wrong file descriptor type."); - r = -EINVAL; - goto fail; - } - - if (!(f = new0(Fifo, 1))) { - r = -ENOMEM; - log_error("Failed to create fifo object: %s", strerror(errno)); - goto fail; - } - - f->fd = -1; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = f; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - fifo_free(f); - log_error("Failed to add fifo fd to epoll object: %s", strerror(errno)); - goto fail; - } - - f->fd = fd; - LIST_PREPEND(Fifo, fifo, s->fifos, f); - f->server = s; - s->n_fifos ++; - } - - if (bus_connect(DBUS_BUS_SYSTEM, &s->bus, NULL, &error) < 0) { - log_error("Failed to get D-Bus connection: %s", bus_error_message(&error)); - goto fail; - } - - return 0; - -fail: - server_done(s); - - dbus_error_free(&error); - return r; -} - -static int process_event(Server *s, struct epoll_event *ev) { - int r; - Fifo *f; - - assert(s); - - if (!(ev->events & EPOLLIN)) { - log_info("Got invalid event from epoll. (3)"); - return -EIO; - } - - f = (Fifo*) ev->data.ptr; - - if ((r = fifo_process(f)) < 0) { - log_info("Got error on fifo: %s", strerror(-r)); - fifo_free(f); - return r; - } - - return 0; -} - -int main(int argc, char *argv[]) { - Server server; - int r = EXIT_FAILURE, n; - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc > 1) { - log_error("This program does not take arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((n = sd_listen_fds(true)) < 0) { - log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (n <= 0 || n > SERVER_FD_MAX) { - log_error("No or too many file descriptors passed."); - return EXIT_FAILURE; - } - - if (server_init(&server, (unsigned) n) < 0) - return EXIT_FAILURE; - - log_debug("systemd-initctl running as pid %lu", (unsigned long) getpid()); - - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - - for (;;) { - struct epoll_event event; - int k; - - if ((k = epoll_wait(server.epoll_fd, - &event, 1, - TIMEOUT_MSEC)) < 0) { - - if (errno == EINTR) - continue; - - log_error("epoll_wait() failed: %s", strerror(errno)); - goto fail; - } - - if (k <= 0) - break; - - if (process_event(&server, &event) < 0) - goto fail; - } - - r = EXIT_SUCCESS; - - log_debug("systemd-initctl stopped as pid %lu", (unsigned long) getpid()); - -fail: - sd_notify(false, - "STATUS=Shutting down..."); - - server_done(&server); - - dbus_shutdown(); - - return r; -} diff --git a/src/initctl/Makefile b/src/initctl/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/initctl/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c new file mode 100644 index 0000000..468df35 --- /dev/null +++ b/src/initctl/initctl.c @@ -0,0 +1,439 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" +#include "sd-bus.h" + +#include "util.h" +#include "log.h" +#include "list.h" +#include "initreq.h" +#include "special.h" +#include "bus-util.h" +#include "bus-error.h" +#include "def.h" + +#define SERVER_FD_MAX 16 +#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) + +typedef struct Fifo Fifo; + +typedef struct Server { + int epoll_fd; + + LIST_HEAD(Fifo, fifos); + unsigned n_fifos; + + sd_bus *bus; + + bool quit; +} Server; + +struct Fifo { + Server *server; + + int fd; + + struct init_request buffer; + size_t bytes_read; + + LIST_FIELDS(Fifo, fifo); +}; + +static const char *translate_runlevel(int runlevel, bool *isolate) { + static const struct { + const int runlevel; + const char *special; + bool isolate; + } table[] = { + { '0', SPECIAL_POWEROFF_TARGET, false }, + { '1', SPECIAL_RESCUE_TARGET, true }, + { 's', SPECIAL_RESCUE_TARGET, true }, + { 'S', SPECIAL_RESCUE_TARGET, true }, + { '2', SPECIAL_RUNLEVEL2_TARGET, true }, + { '3', SPECIAL_RUNLEVEL3_TARGET, true }, + { '4', SPECIAL_RUNLEVEL4_TARGET, true }, + { '5', SPECIAL_RUNLEVEL5_TARGET, true }, + { '6', SPECIAL_REBOOT_TARGET, false }, + }; + + unsigned i; + + assert(isolate); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (table[i].runlevel == runlevel) { + *isolate = table[i].isolate; + if (runlevel == '6' && kexec_loaded()) + return SPECIAL_KEXEC_TARGET; + return table[i].special; + } + + return NULL; +} + +static void change_runlevel(Server *s, int runlevel) { + const char *target; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *mode; + bool isolate = false; + int r; + + assert(s); + + target = translate_runlevel(runlevel, &isolate); + if (!target) { + log_warning("Got request for unknown runlevel %c, ignoring.", runlevel); + return; + } + + if (isolate) + mode = "isolate"; + else + mode = "replace-irreversibly"; + + log_debug("Running request %s/start/%s", target, mode); + + r = sd_bus_call_method( + s->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + &error, + NULL, + "ss", target, mode); + if (r < 0) { + log_error("Failed to change runlevel: %s", bus_error_message(&error, -r)); + return; + } +} + +static void request_process(Server *s, const struct init_request *req) { + assert(s); + assert(req); + + if (req->magic != INIT_MAGIC) { + log_error("Got initctl request with invalid magic. Ignoring."); + return; + } + + switch (req->cmd) { + + case INIT_CMD_RUNLVL: + if (!isprint(req->runlevel)) + log_error("Got invalid runlevel. Ignoring."); + else + switch (req->runlevel) { + + /* we are async anyway, so just use kill for reexec/reload */ + case 'u': + case 'U': + if (kill(1, SIGTERM) < 0) + log_error("kill() failed: %m"); + + /* The bus connection will be + * terminated if PID 1 is reexecuted, + * hence let's just exit here, and + * rely on that we'll be restarted on + * the next request */ + s->quit = true; + break; + + case 'q': + case 'Q': + if (kill(1, SIGHUP) < 0) + log_error("kill() failed: %m"); + break; + + default: + change_runlevel(s, req->runlevel); + } + return; + + case INIT_CMD_POWERFAIL: + case INIT_CMD_POWERFAILNOW: + case INIT_CMD_POWEROK: + log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!"); + return; + + case INIT_CMD_CHANGECONS: + log_warning("Received console change initctl request. This is not implemented in systemd."); + return; + + case INIT_CMD_SETENV: + case INIT_CMD_UNSETENV: + log_warning("Received environment initctl request. This is not implemented in systemd."); + return; + + default: + log_warning("Received unknown initctl request. Ignoring."); + return; + } +} + +static int fifo_process(Fifo *f) { + ssize_t l; + + assert(f); + + errno = EIO; + l = read(f->fd, + ((uint8_t*) &f->buffer) + f->bytes_read, + sizeof(f->buffer) - f->bytes_read); + if (l <= 0) { + if (errno == EAGAIN) + return 0; + + log_warning("Failed to read from fifo: %m"); + return -1; + } + + f->bytes_read += l; + assert(f->bytes_read <= sizeof(f->buffer)); + + if (f->bytes_read == sizeof(f->buffer)) { + request_process(f->server, &f->buffer); + f->bytes_read = 0; + } + + return 0; +} + +static void fifo_free(Fifo *f) { + assert(f); + + if (f->server) { + assert(f->server->n_fifos > 0); + f->server->n_fifos--; + LIST_REMOVE(fifo, f->server->fifos, f); + } + + if (f->fd >= 0) { + if (f->server) + epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL); + + close_nointr_nofail(f->fd); + } + + free(f); +} + +static void server_done(Server *s) { + assert(s); + + while (s->fifos) + fifo_free(s->fifos); + + if (s->epoll_fd >= 0) + close_nointr_nofail(s->epoll_fd); + + if (s->bus) { + sd_bus_flush(s->bus); + sd_bus_unref(s->bus); + } +} + +static int server_init(Server *s, unsigned n_sockets) { + int r; + unsigned i; + + assert(s); + assert(n_sockets > 0); + + zero(*s); + + s->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (s->epoll_fd < 0) { + r = -errno; + log_error("Failed to create epoll object: %m"); + goto fail; + } + + for (i = 0; i < n_sockets; i++) { + struct epoll_event ev; + Fifo *f; + int fd; + + fd = SD_LISTEN_FDS_START+i; + + r = sd_is_fifo(fd, NULL); + if (r < 0) { + log_error("Failed to determine file descriptor type: %s", + strerror(-r)); + goto fail; + } + + if (!r) { + log_error("Wrong file descriptor type."); + r = -EINVAL; + goto fail; + } + + f = new0(Fifo, 1); + if (!f) { + r = -ENOMEM; + log_error("Failed to create fifo object: %m"); + goto fail; + } + + f->fd = -1; + + zero(ev); + ev.events = EPOLLIN; + ev.data.ptr = f; + if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { + r = -errno; + fifo_free(f); + log_error("Failed to add fifo fd to epoll object: %m"); + goto fail; + } + + f->fd = fd; + LIST_PREPEND(fifo, s->fifos, f); + f->server = s; + s->n_fifos ++; + } + + r = bus_open_system_systemd(&s->bus); + if (r < 0) { + log_error("Failed to get D-Bus connection: %s", strerror(-r)); + r = -EIO; + goto fail; + } + + return 0; + +fail: + server_done(s); + + return r; +} + +static int process_event(Server *s, struct epoll_event *ev) { + int r; + Fifo *f; + + assert(s); + + if (!(ev->events & EPOLLIN)) { + log_info("Got invalid event from epoll. (3)"); + return -EIO; + } + + f = (Fifo*) ev->data.ptr; + r = fifo_process(f); + if (r < 0) { + log_info("Got error on fifo: %s", strerror(-r)); + fifo_free(f); + return r; + } + + return 0; +} + +int main(int argc, char *argv[]) { + Server server; + int r = EXIT_FAILURE, n; + + if (getppid() != 1) { + log_error("This program should be invoked by init only."); + return EXIT_FAILURE; + } + + if (argc > 1) { + log_error("This program does not take arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if ((n = sd_listen_fds(true)) < 0) { + log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); + return EXIT_FAILURE; + } + + if (n <= 0 || n > SERVER_FD_MAX) { + log_error("No or too many file descriptors passed."); + return EXIT_FAILURE; + } + + if (server_init(&server, (unsigned) n) < 0) + return EXIT_FAILURE; + + log_debug("systemd-initctl running as pid %lu", (unsigned long) getpid()); + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + while (!server.quit) { + struct epoll_event event; + int k; + + if ((k = epoll_wait(server.epoll_fd, + &event, 1, + TIMEOUT_MSEC)) < 0) { + + if (errno == EINTR) + continue; + + log_error("epoll_wait() failed: %m"); + goto fail; + } + + if (k <= 0) + break; + + if (process_event(&server, &event) < 0) + goto fail; + } + + r = EXIT_SUCCESS; + + log_debug("systemd-initctl stopped as pid %lu", (unsigned long) getpid()); + +fail: + sd_notify(false, + "STATUS=Shutting down..."); + + server_done(&server); + + return r; +} diff --git a/src/initreq.h b/src/initreq.h deleted file mode 100644 index 859042c..0000000 --- a/src/initreq.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * initreq.h Interface to talk to init through /dev/initctl. - * - * Copyright (C) 1995-2004 Miquel van Smoorenburg - * - * This library 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 of the License, or (at your option) any later version. - * - * Version: @(#)initreq.h 1.28 31-Mar-2004 MvS - * - */ -#ifndef _INITREQ_H -#define _INITREQ_H - -#include - -#if defined(__FreeBSD_kernel__) -# define INIT_FIFO "/etc/.initctl" -#else -# define INIT_FIFO "/dev/initctl" -#endif - -#define INIT_MAGIC 0x03091969 -#define INIT_CMD_START 0 -#define INIT_CMD_RUNLVL 1 -#define INIT_CMD_POWERFAIL 2 -#define INIT_CMD_POWERFAILNOW 3 -#define INIT_CMD_POWEROK 4 -#define INIT_CMD_BSD 5 -#define INIT_CMD_SETENV 6 -#define INIT_CMD_UNSETENV 7 - -#define INIT_CMD_CHANGECONS 12345 - -#ifdef MAXHOSTNAMELEN -# define INITRQ_HLEN MAXHOSTNAMELEN -#else -# define INITRQ_HLEN 64 -#endif - -/* - * This is what BSD 4.4 uses when talking to init. - * Linux doesn't use this right now. - */ -struct init_request_bsd { - char gen_id[8]; /* Beats me.. telnetd uses "fe" */ - char tty_id[16]; /* Tty name minus /dev/tty */ - char host[INITRQ_HLEN]; /* Hostname */ - char term_type[16]; /* Terminal type */ - int signal; /* Signal to send */ - int pid; /* Process to send to */ - char exec_name[128]; /* Program to execute */ - char reserved[128]; /* For future expansion. */ -}; - - -/* - * Because of legacy interfaces, "runlevel" and "sleeptime" - * aren't in a separate struct in the union. - * - * The weird sizes are because init expects the whole - * struct to be 384 bytes. - */ -struct init_request { - int magic; /* Magic number */ - int cmd; /* What kind of request */ - int runlevel; /* Runlevel to change to */ - int sleeptime; /* Time between TERM and KILL */ - union { - struct init_request_bsd bsd; - char data[368]; - } i; -}; - -#endif diff --git a/src/install.c b/src/install.c deleted file mode 100644 index cfbd50e..0000000 --- a/src/install.c +++ /dev/null @@ -1,1954 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty . -***/ - -#include -#include -#include -#include -#include - -#include "util.h" -#include "hashmap.h" -#include "set.h" -#include "path-lookup.h" -#include "strv.h" -#include "unit-name.h" -#include "install.h" -#include "conf-parser.h" - -typedef struct { - char *name; - char *path; - - char **aliases; - char **wanted_by; -} InstallInfo; - -typedef struct { - Hashmap *will_install; - Hashmap *have_installed; -} InstallContext; - -static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) { - assert(paths); - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(*paths); - - return lookup_paths_init(paths, - scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER, - scope == UNIT_FILE_USER); -} - -static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { - char *p = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(ret); - - switch (scope) { - - case UNIT_FILE_SYSTEM: - - if (root_dir && runtime) - return -EINVAL; - - if (runtime) - p = strdup("/run/systemd/system"); - else if (root_dir) - asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH); - else - p = strdup(SYSTEM_CONFIG_UNIT_PATH); - - break; - - case UNIT_FILE_GLOBAL: - - if (root_dir) - return -EINVAL; - - if (runtime) - p = strdup("/run/systemd/user"); - else - p = strdup(USER_CONFIG_UNIT_PATH); - break; - - case UNIT_FILE_USER: - - if (root_dir || runtime) - return -EINVAL; - - r = user_config_home(&p); - if (r <= 0) - return r < 0 ? r : -ENOENT; - - break; - - default: - assert_not_reached("Bad scope"); - } - - if (!p) - return -ENOMEM; - - *ret = p; - return 0; -} - -static int add_file_change( - UnitFileChange **changes, - unsigned *n_changes, - UnitFileChangeType type, - const char *path, - const char *source) { - - UnitFileChange *c; - unsigned i; - - assert(path); - assert(!changes == !n_changes); - - if (!changes) - return 0; - - c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); - if (!c) - return -ENOMEM; - - *changes = c; - i = *n_changes; - - c[i].type = type; - c[i].path = strdup(path); - if (!c[i].path) - return -ENOMEM; - - if (source) { - c[i].source = strdup(source); - if (!c[i].source) { - free(c[i].path); - return -ENOMEM; - } - } else - c[i].source = NULL; - - *n_changes = i+1; - return 0; -} - -static int mark_symlink_for_removal( - Set **remove_symlinks_to, - const char *p) { - - char *n; - int r; - - assert(p); - - r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func); - if (r < 0) - return r; - - n = strdup(p); - if (!n) - return -ENOMEM; - - path_kill_slashes(n); - - r = set_put(*remove_symlinks_to, n); - if (r < 0) { - free(n); - return r == -EEXIST ? 0 : r; - } - - return 0; -} - -static int remove_marked_symlinks_fd( - Set *remove_symlinks_to, - int fd, - const char *path, - const char *config_path, - bool *deleted, - UnitFileChange **changes, - unsigned *n_changes) { - - int r = 0; - DIR *d; - struct dirent buffer, *de; - - assert(remove_symlinks_to); - assert(fd >= 0); - assert(path); - assert(config_path); - assert(deleted); - - d = fdopendir(fd); - if (!d) { - close_nointr_nofail(fd); - return -errno; - } - - rewinddir(d); - - for (;;) { - int k; - - k = readdir_r(d, &buffer, &de); - if (k != 0) { - r = -errno; - break; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - dirent_ensure_type(d, de); - - if (de->d_type == DT_DIR) { - int nfd, q; - char *p; - - nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (nfd < 0) { - if (errno == ENOENT) - continue; - - if (r == 0) - r = -errno; - continue; - } - - p = path_make_absolute(de->d_name, path); - if (!p) { - close_nointr_nofail(nfd); - r = -ENOMEM; - break; - } - - /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes); - free(p); - - if (r == 0) - r = q; - - } else if (de->d_type == DT_LNK) { - char *p, *dest; - int q; - bool found; - - p = path_make_absolute(de->d_name, path); - if (!p) { - r = -ENOMEM; - break; - } - - q = readlink_and_canonicalize(p, &dest); - if (q < 0) { - free(p); - - if (q == -ENOENT) - continue; - - if (r == 0) - r = q; - continue; - } - - found = - set_get(remove_symlinks_to, dest) || - set_get(remove_symlinks_to, file_name_from_path(dest)); - - if (found) { - - if (unlink(p) < 0 && errno != ENOENT) { - - if (r == 0) - r = -errno; - } else { - rmdir_parents(p, config_path); - path_kill_slashes(p); - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); - - if (!set_get(remove_symlinks_to, p)) { - - q = mark_symlink_for_removal(&remove_symlinks_to, p); - if (q < 0) { - if (r == 0) - r = q; - } else - *deleted = true; - } - } - } - - free(p); - free(dest); - } - } - - closedir(d); - - return r; -} - -static int remove_marked_symlinks( - Set *remove_symlinks_to, - const char *config_path, - UnitFileChange **changes, - unsigned *n_changes) { - - int fd, r = 0; - bool deleted; - - assert(config_path); - - if (set_size(remove_symlinks_to) <= 0) - return 0; - - fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (fd < 0) - return -errno; - - do { - int q, cfd; - deleted = false; - - cfd = dup(fd); - if (cfd < 0) { - r = -errno; - break; - } - - /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes); - if (r == 0) - r = q; - } while (deleted); - - close_nointr_nofail(fd); - - return r; -} - -static int find_symlinks_fd( - const char *name, - int fd, - const char *path, - const char *config_path, - bool *same_name_link) { - - int r = 0; - DIR *d; - struct dirent buffer, *de; - - assert(name); - assert(fd >= 0); - assert(path); - assert(config_path); - assert(same_name_link); - - d = fdopendir(fd); - if (!d) { - close_nointr_nofail(fd); - return -errno; - } - - for (;;) { - int k; - - k = readdir_r(d, &buffer, &de); - if (k != 0) { - r = -errno; - break; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - dirent_ensure_type(d, de); - - if (de->d_type == DT_DIR) { - int nfd, q; - char *p; - - nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (nfd < 0) { - if (errno == ENOENT) - continue; - - if (r == 0) - r = -errno; - continue; - } - - p = path_make_absolute(de->d_name, path); - if (!p) { - close_nointr_nofail(nfd); - r = -ENOMEM; - break; - } - - /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); - free(p); - - if (q > 0) { - r = 1; - break; - } - - if (r == 0) - r = q; - - } else if (de->d_type == DT_LNK) { - char *p, *dest; - bool found_path, found_dest, b = false; - int q; - - /* Acquire symlink name */ - p = path_make_absolute(de->d_name, path); - if (!p) { - r = -ENOMEM; - break; - } - - /* Acquire symlink destination */ - q = readlink_and_canonicalize(p, &dest); - if (q < 0) { - free(p); - - if (q == -ENOENT) - continue; - - if (r == 0) - r = q; - continue; - } - - /* Check if the symlink itself matches what we - * are looking for */ - if (path_is_absolute(name)) - found_path = path_equal(p, name); - else - found_path = streq(de->d_name, name); - - /* Check if what the symlink points to - * matches what we are looking for */ - if (path_is_absolute(name)) - found_dest = path_equal(dest, name); - else - found_dest = streq(file_name_from_path(dest), name); - - free(dest); - - if (found_path && found_dest) { - char *t; - - /* Filter out same name links in the main - * config path */ - t = path_make_absolute(name, config_path); - if (!t) { - free(p); - r = -ENOMEM; - break; - } - - b = path_equal(t, p); - free(t); - } - - free(p); - - if (b) - *same_name_link = true; - else if (found_path || found_dest) { - r = 1; - break; - } - } - } - - closedir(d); - - return r; -} - -static int find_symlinks( - const char *name, - const char *config_path, - bool *same_name_link) { - - int fd; - - assert(name); - assert(config_path); - assert(same_name_link); - - fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (fd < 0) - return -errno; - - /* This takes possession of fd and closes it */ - return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); -} - -static int find_symlinks_in_scope( - UnitFileScope scope, - const char *root_dir, - const char *name, - UnitFileState *state) { - - int r; - char *path; - bool same_name_link_runtime = false, same_name_link = false; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) { - - /* First look in runtime config path */ - r = get_config_path(scope, true, root_dir, &path); - if (r < 0) - return r; - - r = find_symlinks(name, path, &same_name_link_runtime); - free(path); - - if (r < 0) - return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED_RUNTIME; - return r; - } - } - - /* Then look in the normal config path */ - r = get_config_path(scope, false, root_dir, &path); - if (r < 0) - return r; - - r = find_symlinks(name, path, &same_name_link); - free(path); - - if (r < 0) - return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED; - return r; - } - - /* Hmm, we didn't find it, but maybe we found the same name - * link? */ - if (same_name_link_runtime) { - *state = UNIT_FILE_LINKED_RUNTIME; - return 1; - } else if (same_name_link) { - *state = UNIT_FILE_LINKED; - return 1; - } - - return 0; -} - -int unit_file_mask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **i, *prefix; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &prefix); - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - char *path; - - if (!unit_name_is_valid_no_type(*i, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, prefix); - if (!path) { - r = -ENOMEM; - break; - } - - if (symlink("/dev/null", path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - - free(path); - continue; - } - - if (errno == EEXIST) { - - if (null_or_empty_path(path) > 0) { - free(path); - continue; - } - - if (force) { - unlink(path); - - if (symlink("/dev/null", path) >= 0) { - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - - free(path); - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - - free(path); - } - - free(prefix); - - return r; -} - -int unit_file_unmask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - UnitFileChange **changes, - unsigned *n_changes) { - - char **i, *config_path = NULL; - int r, q; - Set *remove_symlinks_to = NULL; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - char *path; - - if (!unit_name_is_valid_no_type(*i, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, config_path); - if (!path) { - r = -ENOMEM; - break; - } - - q = null_or_empty_path(path); - if (q > 0) { - if (unlink(path) >= 0) { - mark_symlink_for_removal(&remove_symlinks_to, path); - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - - free(path); - continue; - } - - q = -errno; - } - - if (q != -ENOENT && r == 0) - r = q; - - free(path); - } - - -finish: - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); - if (r == 0) - r = q; - - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_link( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - char **i, *config_path = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - char *path, *fn; - struct stat st; - - fn = file_name_from_path(*i); - - if (!path_is_absolute(*i) || - !unit_name_is_valid_no_type(fn, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - if (lstat(*i, &st) < 0) { - if (r == 0) - r = -errno; - continue; - } - - if (!S_ISREG(st.st_mode)) { - r = -ENOENT; - continue; - } - - q = in_search_path(*i, paths.unit_path); - if (q < 0) { - r = q; - break; - } - - if (q > 0) - continue; - - path = path_make_absolute(fn, config_path); - if (!path) { - r = -ENOMEM; - break; - } - - if (symlink(*i, path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - - free(path); - continue; - } - - if (errno == EEXIST) { - char *dest = NULL; - - q = readlink_and_make_absolute(path, &dest); - - if (q < 0 && errno != ENOENT) { - free(path); - - if (r == 0) - r = q; - - continue; - } - - if (q >= 0 && path_equal(dest, *i)) { - free(dest); - free(path); - continue; - } - - free(dest); - - if (force) { - unlink(path); - - if (symlink(*i, path) >= 0) { - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - - free(path); - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - - free(path); - } - - finish: - lookup_paths_free(&paths); - free(config_path); - - return r; -} - -void unit_file_list_free(Hashmap *h) { - UnitFileList *i; - - while ((i = hashmap_steal_first(h))) { - free(i->path); - free(i); - } - - hashmap_free(h); -} - -void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { - unsigned i; - - assert(changes || n_changes == 0); - - if (!changes) - return; - - for (i = 0; i < n_changes; i++) { - free(changes[i].path); - free(changes[i].source); - } - - free(changes); -} - -static void install_info_free(InstallInfo *i) { - assert(i); - - free(i->name); - free(i->path); - strv_free(i->aliases); - strv_free(i->wanted_by); - free(i); -} - -static void install_info_hashmap_free(Hashmap *m) { - InstallInfo *i; - - if (!m) - return; - - while ((i = hashmap_steal_first(m))) - install_info_free(i); - - hashmap_free(m); -} - -static void install_context_done(InstallContext *c) { - assert(c); - - install_info_hashmap_free(c->will_install); - install_info_hashmap_free(c->have_installed); - - c->will_install = c->have_installed = NULL; -} - -static int install_info_add( - InstallContext *c, - const char *name, - const char *path) { - InstallInfo *i = NULL; - int r; - - assert(c); - assert(name || path); - - if (!name) - name = file_name_from_path(path); - - if (!unit_name_is_valid_no_type(name, true)) - return -EINVAL; - - if (hashmap_get(c->have_installed, name) || - hashmap_get(c->will_install, name)) - return 0; - - r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func); - if (r < 0) - return r; - - i = new0(InstallInfo, 1); - if (!i) - return -ENOMEM; - - i->name = strdup(name); - if (!i->name) { - r = -ENOMEM; - goto fail; - } - - if (path) { - i->path = strdup(path); - if (!i->path) { - r = -ENOMEM; - goto fail; - } - } - - r = hashmap_put(c->will_install, i->name, i); - if (r < 0) - goto fail; - - return 0; - -fail: - if (i) - install_info_free(i); - - return r; -} - -static int install_info_add_auto( - InstallContext *c, - const char *name_or_path) { - - assert(c); - assert(name_or_path); - - if (path_is_absolute(name_or_path)) - return install_info_add(c, NULL, name_or_path); - else - return install_info_add(c, name_or_path, NULL); -} - -static int config_parse_also( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char *w; - size_t l; - char *state; - InstallContext *c = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *n; - int r; - - n = strndup(w, l); - if (!n) - return -ENOMEM; - - r = install_info_add(c, n, NULL); - if (r < 0) { - free(n); - return r; - } - - free(n); - } - - return 0; -} - -static int unit_file_load( - InstallContext *c, - InstallInfo *info, - const char *path, - bool allow_symlink) { - - const ConfigTableItem items[] = { - { "Install", "Alias", config_parse_strv, 0, &info->aliases }, - { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, - { "Install", "Also", config_parse_also, 0, c }, - { NULL, NULL, NULL, 0, NULL } - }; - - int fd; - FILE *f; - int r; - - assert(c); - assert(info); - assert(path); - - fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); - if (fd < 0) - return -errno; - - f = fdopen(fd, "re"); - if (!f) { - close_nointr_nofail(fd); - return -ENOMEM; - } - - r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info); - fclose(f); - if (r < 0) - return r; - - return strv_length(info->aliases) + strv_length(info->wanted_by); -} - -static int unit_file_search( - InstallContext *c, - InstallInfo *info, - LookupPaths *paths, - const char *root_dir, - bool allow_symlink) { - - char **p; - int r; - - assert(c); - assert(info); - assert(paths); - - if (info->path) - return unit_file_load(c, info, info->path, allow_symlink); - - assert(info->name); - - STRV_FOREACH(p, paths->unit_path) { - char *path = NULL; - - if (isempty(root_dir)) - asprintf(&path, "%s/%s", *p, info->name); - else - asprintf(&path, "%s/%s/%s", root_dir, *p, info->name); - - if (!path) - return -ENOMEM; - - r = unit_file_load(c, info, path, allow_symlink); - - if (r >= 0) - info->path = path; - else - free(path); - - if (r != -ENOENT && r != -ELOOP) - return r; - } - - return -ENOENT; -} - -static int unit_file_can_install( - LookupPaths *paths, - const char *root_dir, - const char *name, - bool allow_symlink) { - - InstallContext c; - InstallInfo *i; - int r; - - assert(paths); - assert(name); - - zero(c); - - r = install_info_add_auto(&c, name); - if (r < 0) - return r; - - assert_se(i = hashmap_first(c.will_install)); - - r = unit_file_search(&c, i, paths, root_dir, allow_symlink); - - if (r >= 0) - r = strv_length(i->aliases) + strv_length(i->wanted_by); - - install_context_done(&c); - - return r; -} - -static int create_symlink( - const char *old_path, - const char *new_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char *dest; - int r; - - assert(old_path); - assert(new_path); - - mkdir_parents(new_path, 0755); - - if (symlink(old_path, new_path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; - } - - if (errno != EEXIST) - return -errno; - - r = readlink_and_make_absolute(new_path, &dest); - if (r < 0) - return r; - - if (path_equal(dest, old_path)) { - free(dest); - return 0; - } - - free(dest); - - if (force) - return -EEXIST; - - unlink(new_path); - - if (symlink(old_path, new_path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; - } - - return -errno; -} - -static int install_info_symlink_alias( - InstallInfo *i, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **s; - int r = 0, q; - - assert(i); - assert(config_path); - - STRV_FOREACH(s, i->aliases) { - char *alias_path; - - alias_path = path_make_absolute(*s, config_path); - - if (!alias_path) - return -ENOMEM; - - q = create_symlink(i->path, alias_path, force, changes, n_changes); - free(alias_path); - - if (r == 0) - r = q; - } - - return r; -} - -static int install_info_symlink_wants( - InstallInfo *i, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **s; - int r = 0, q; - - assert(i); - assert(config_path); - - STRV_FOREACH(s, i->wanted_by) { - char *path; - - if (!unit_name_is_valid_no_type(*s, true)) { - r = -EINVAL; - continue; - } - - if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) - return -ENOMEM; - - q = create_symlink(i->path, path, force, changes, n_changes); - free(path); - - if (r == 0) - r = q; - } - - return r; -} - -static int install_info_symlink_link( - InstallInfo *i, - LookupPaths *paths, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - int r; - char *path; - - assert(i); - assert(paths); - assert(config_path); - assert(i->path); - - r = in_search_path(i->path, paths->unit_path); - if (r != 0) - return r; - - if (asprintf(&path, "%s/%s", config_path, i->name) < 0) - return -ENOMEM; - - r = create_symlink(i->path, path, force, changes, n_changes); - free(path); - - return r; -} - -static int install_info_apply( - InstallInfo *i, - LookupPaths *paths, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - int r, q; - - assert(i); - assert(paths); - assert(config_path); - - r = install_info_symlink_alias(i, config_path, force, changes, n_changes); - - q = install_info_symlink_wants(i, config_path, force, changes, n_changes); - if (r == 0) - r = q; - - q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); - if (r == 0) - r = q; - - return r; -} - -static int install_context_apply( - InstallContext *c, - LookupPaths *paths, - const char *config_path, - const char *root_dir, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - InstallInfo *i; - int r = 0, q; - - assert(c); - assert(paths); - assert(config_path); - - while ((i = hashmap_first(c->will_install))) { - - q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); - if (q < 0) - return q; - - assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); - - q = unit_file_search(c, i, paths, root_dir, false); - if (q < 0) { - if (r >= 0) - r = q; - - return r; - } else if (r >= 0) - r += q; - - q = install_info_apply(i, paths, config_path, force, changes, n_changes); - if (r >= 0 && q < 0) - r = q; - } - - return r; -} - -static int install_context_mark_for_removal( - InstallContext *c, - LookupPaths *paths, - Set **remove_symlinks_to, - const char *config_path, - const char *root_dir) { - - InstallInfo *i; - int r = 0, q; - - assert(c); - assert(paths); - assert(config_path); - - /* Marks all items for removal */ - - while ((i = hashmap_first(c->will_install))) { - - q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); - if (q < 0) - return q; - - assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); - - q = unit_file_search(c, i, paths, root_dir, false); - if (q < 0) { - if (r >= 0) - r = q; - - return r; - } else if (r >= 0) - r += q; - - q = mark_symlink_for_removal(remove_symlinks_to, i->name); - if (r >= 0 && q < 0) - r = q; - } - - return r; -} - -int unit_file_enable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - /* This will return the number of symlink rules that were - supposed to be created, not the ones actually created. This is - useful to determine whether the passed files hat any - installation data at all. */ - r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); - -finish: - install_context_done(&c); - lookup_paths_free(&paths); - free(config_path); - - return r; -} - -int unit_file_disable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); - if (r == 0) - r = q; - -finish: - install_context_done(&c); - lookup_paths_free(&paths); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_reenable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = mark_symlink_for_removal(&remove_symlinks_to, *i); - if (r < 0) - goto finish; - - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); - - /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - -finish: - lookup_paths_free(&paths); - install_context_done(&c); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -UnitFileState unit_file_get_state( - UnitFileScope scope, - const char *root_dir, - const char *name) { - - LookupPaths paths; - UnitFileState state = _UNIT_FILE_STATE_INVALID; - char **i, *path = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - zero(paths); - - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - if (!unit_name_is_valid_no_type(name, true)) - return -EINVAL; - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - STRV_FOREACH(i, paths.unit_path) { - struct stat st; - - free(path); - path = NULL; - - if (root_dir) - asprintf(&path, "%s/%s/%s", root_dir, *i, name); - else - asprintf(&path, "%s/%s", *i, name); - - if (!path) { - r = -ENOMEM; - goto finish; - } - - if (lstat(path, &st) < 0) { - if (errno == ENOENT) - continue; - - r = -errno; - goto finish; - } - - if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { - r = -ENOENT; - goto finish; - } - - r = null_or_empty_path(path); - if (r < 0 && r != -ENOENT) - goto finish; - else if (r > 0) { - state = path_startswith(*i, "/run") ? - UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - r = 0; - goto finish; - } - - r = find_symlinks_in_scope(scope, root_dir, name, &state); - if (r < 0) { - goto finish; - } else if (r > 0) { - r = 0; - goto finish; - } - - r = unit_file_can_install(&paths, root_dir, path, true); - if (r < 0 && errno != -ENOENT) - goto finish; - else if (r > 0) { - state = UNIT_FILE_DISABLED; - r = 0; - goto finish; - } else if (r == 0) { - state = UNIT_FILE_STATIC; - r = 0; - goto finish; - } - } - -finish: - lookup_paths_free(&paths); - free(path); - - return r < 0 ? r : state; -} - -int unit_file_query_preset(UnitFileScope scope, const char *name) { - char **files, **i; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (scope == UNIT_FILE_SYSTEM) - r = conf_files_list(&files, ".preset", - "/etc/systemd/system.preset", - "/usr/local/lib/systemd/system.preset", - "/usr/lib/systemd/system.preset", - "/lib/systemd/system.preset", - NULL); - else if (scope == UNIT_FILE_GLOBAL) - r = conf_files_list(&files, ".preset", - "/etc/systemd/user.preset", - "/usr/local/lib/systemd/user.preset", - "/usr/lib/systemd/user.preset", - NULL); - else - return 1; - - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - FILE *f; - - f = fopen(*i, "re"); - if (!f) { - if (errno == ENOENT) - continue; - - r = -errno; - goto finish; - } - - for (;;) { - char line[LINE_MAX], *l; - - if (!fgets(line, sizeof(line), f)) - break; - - l = strstrip(line); - if (!*l) - continue; - - if (strchr(COMMENTS, *l)) - continue; - - if (first_word(l, "enable")) { - l += 6; - l += strspn(l, WHITESPACE); - - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { - r = 1; - fclose(f); - goto finish; - } - } else if (first_word(l, "disable")) { - l += 7; - l += strspn(l, WHITESPACE); - - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { - r = 0; - fclose(f); - goto finish; - } - } else - log_debug("Couldn't parse line '%s'", l); - } - - fclose(f); - } - - /* Default is "enable" */ - r = 1; - -finish: - strv_free(files); - - return r; -} - -int unit_file_preset( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext plus, minus; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(plus); - zero(minus); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - - if (!unit_name_is_valid_no_type(*i, true)) { - r = -EINVAL; - goto finish; - } - - r = unit_file_query_preset(scope, *i); - if (r < 0) - goto finish; - - if (r) - r = install_info_add_auto(&plus, *i); - else - r = install_info_add_auto(&minus, *i); - - if (r < 0) - goto finish; - } - - r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); - if (r == 0) - r = q; - - /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - -finish: - lookup_paths_free(&paths); - install_context_done(&plus); - install_context_done(&minus); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_get_list( - UnitFileScope scope, - const char *root_dir, - Hashmap *h) { - - LookupPaths paths; - char **i, *buf = NULL; - DIR *d = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(h); - - zero(paths); - - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - STRV_FOREACH(i, paths.unit_path) { - struct dirent buffer, *de; - const char *units_dir; - - free(buf); - buf = NULL; - - if (root_dir) { - if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) { - r = -ENOMEM; - goto finish; - } - units_dir = buf; - } else - units_dir = *i; - - if (d) - closedir(d); - - d = opendir(units_dir); - if (!d) { - if (errno == ENOENT) - continue; - - r = -errno; - goto finish; - } - - for (;;) { - UnitFileList *f; - - r = readdir_r(d, &buffer, &de); - if (r != 0) { - r = -r; - goto finish; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - if (!unit_name_is_valid_no_type(de->d_name, true)) - continue; - - if (hashmap_get(h, de->d_name)) - continue; - - r = dirent_ensure_type(d, de); - if (r < 0) { - if (errno == ENOENT) - continue; - - goto finish; - } - - if (de->d_type != DT_LNK && de->d_type != DT_REG) - continue; - - f = new0(UnitFileList, 1); - if (!f) { - r = -ENOMEM; - goto finish; - } - - f->path = path_make_absolute(de->d_name, units_dir); - if (!f->path) { - free(f); - r = -ENOMEM; - goto finish; - } - - r = null_or_empty_path(f->path); - if (r < 0 && r != -ENOENT) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) { - f->state = - path_startswith(*i, "/run") ? - UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - goto found; - } - - r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); - if (r < 0) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) - goto found; - - r = unit_file_can_install(&paths, root_dir, f->path, true); - if (r < 0) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) { - f->state = UNIT_FILE_DISABLED; - goto found; - } else { - f->state = UNIT_FILE_STATIC; - goto found; - } - - free(f->path); - free(f); - continue; - - found: - r = hashmap_put(h, file_name_from_path(f->path), f); - if (r < 0) { - free(f->path); - free(f); - goto finish; - } - } - } - -finish: - lookup_paths_free(&paths); - free(buf); - - if (d) - closedir(d); - - return r; -} - -static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { - [UNIT_FILE_ENABLED] = "enabled", - [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtie", - [UNIT_FILE_LINKED] = "linked", - [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime", - [UNIT_FILE_MASKED] = "masked", - [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime", - [UNIT_FILE_STATIC] = "static", - [UNIT_FILE_DISABLED] = "disabled" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); - -static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { - [UNIT_FILE_SYMLINK] = "symlink", - [UNIT_FILE_UNLINK] = "unlink", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/install.h b/src/install.h deleted file mode 100644 index 0505a82..0000000 --- a/src/install.h +++ /dev/null @@ -1,89 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooinstallhfoo -#define fooinstallhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "hashmap.h" - -typedef enum UnitFileScope { - UNIT_FILE_SYSTEM, - UNIT_FILE_GLOBAL, - UNIT_FILE_USER, - _UNIT_FILE_SCOPE_MAX, - _UNIT_FILE_SCOPE_INVALID = -1 -} UnitFileScope; - -typedef enum UnitFileState { - UNIT_FILE_ENABLED, - UNIT_FILE_ENABLED_RUNTIME, - UNIT_FILE_LINKED, - UNIT_FILE_LINKED_RUNTIME, - UNIT_FILE_MASKED, - UNIT_FILE_MASKED_RUNTIME, - UNIT_FILE_STATIC, - UNIT_FILE_DISABLED, - _UNIT_FILE_STATE_MAX, - _UNIT_FILE_STATE_INVALID = -1 -} UnitFileState; - -typedef enum UnitFileChangeType { - UNIT_FILE_SYMLINK, - UNIT_FILE_UNLINK, - _UNIT_FILE_CHANGE_TYPE_MAX, - _UNIT_FILE_CHANGE_TYPE_INVALID = -1 -} UnitFileChangeType; - -typedef struct UnitFileChange { - UnitFileChangeType type; - char *path; - char *source; -} UnitFileChange; - -typedef struct UnitFileList { - char *path; - UnitFileState state; -} UnitFileList; - -int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes); -int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes); - -UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename); - -int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); - -void unit_file_list_free(Hashmap *h); -void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); - -int unit_file_query_preset(UnitFileScope scope, const char *name); - -const char *unit_file_state_to_string(UnitFileState s); -UnitFileState unit_file_state_from_string(const char *s); - -const char *unit_file_change_type_to_string(UnitFileChangeType s); -UnitFileChangeType unit_file_change_type_from_string(const char *s); - -#endif diff --git a/src/ioprio.h b/src/ioprio.h deleted file mode 100644 index 9800fc2..0000000 --- a/src/ioprio.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef IOPRIO_H -#define IOPRIO_H - -/* This is minimal version of Linux' linux/ioprio.h header file, which - * is licensed GPL2 */ - -#include -#include - -/* - * Gives us 8 prio classes with 13-bits of data for each class - */ -#define IOPRIO_BITS (16) -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) - -#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -/* - * 8 best effort priority levels are supported - */ -#define IOPRIO_BE_NR (8) - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -static inline int ioprio_set(int which, int who, int ioprio) -{ - return syscall(__NR_ioprio_set, which, who, ioprio); -} - -static inline int ioprio_get(int which, int who) -{ - return syscall(__NR_ioprio_get, which, who); -} - -#endif diff --git a/src/job.c b/src/job.c deleted file mode 100644 index 5c0913b..0000000 --- a/src/job.c +++ /dev/null @@ -1,762 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "set.h" -#include "unit.h" -#include "macro.h" -#include "strv.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "dbus-job.h" - -Job* job_new(Manager *m, JobType type, Unit *unit) { - Job *j; - - assert(m); - assert(type < _JOB_TYPE_MAX); - assert(unit); - - if (!(j = new0(Job, 1))) - return NULL; - - j->manager = m; - j->id = m->current_job_id++; - j->type = type; - j->unit = unit; - - j->timer_watch.type = WATCH_INVALID; - - /* We don't link it here, that's what job_dependency() is for */ - - return j; -} - -void job_free(Job *j) { - assert(j); - - /* Detach from next 'bigger' objects */ - if (j->installed) { - bus_job_send_removed_signal(j); - - if (j->unit->meta.job == j) { - j->unit->meta.job = NULL; - unit_add_to_gc_queue(j->unit); - } - - hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); - j->installed = false; - } - - /* Detach from next 'smaller' objects */ - manager_transaction_unlink_job(j->manager, j, true); - - if (j->in_run_queue) - LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); - - if (j->in_dbus_queue) - LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j); - - if (j->timer_watch.type != WATCH_INVALID) { - assert(j->timer_watch.type == WATCH_JOB_TIMER); - assert(j->timer_watch.data.job == j); - assert(j->timer_watch.fd >= 0); - - assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0); - close_nointr_nofail(j->timer_watch.fd); - } - - free(j->bus_client); - free(j); -} - -JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { - JobDependency *l; - - assert(object); - - /* Adds a new job link, which encodes that the 'subject' job - * needs the 'object' job in some way. If 'subject' is NULL - * this means the 'anchor' job (i.e. the one the user - * explicitly asked for) is the requester. */ - - if (!(l = new0(JobDependency, 1))) - return NULL; - - l->subject = subject; - l->object = object; - l->matters = matters; - l->conflicts = conflicts; - - if (subject) - LIST_PREPEND(JobDependency, subject, subject->subject_list, l); - else - LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l); - - LIST_PREPEND(JobDependency, object, object->object_list, l); - - return l; -} - -void job_dependency_free(JobDependency *l) { - assert(l); - - if (l->subject) - LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l); - else - LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l); - - LIST_REMOVE(JobDependency, object, l->object->object_list, l); - - free(l); -} - -void job_dump(Job *j, FILE*f, const char *prefix) { - assert(j); - assert(f); - - if (!prefix) - prefix = ""; - - fprintf(f, - "%s-> Job %u:\n" - "%s\tAction: %s -> %s\n" - "%s\tState: %s\n" - "%s\tForced: %s\n", - prefix, j->id, - prefix, j->unit->meta.id, job_type_to_string(j->type), - prefix, job_state_to_string(j->state), - prefix, yes_no(j->override)); -} - -bool job_is_anchor(Job *j) { - JobDependency *l; - - assert(j); - - LIST_FOREACH(object, l, j->object_list) - if (!l->subject) - return true; - - return false; -} - -static bool types_match(JobType a, JobType b, JobType c, JobType d) { - return - (a == c && b == d) || - (a == d && b == c); -} - -int job_type_merge(JobType *a, JobType b) { - if (*a == b) - return 0; - - /* Merging is associative! a merged with b merged with c is - * the same as a merged with c merged with b. */ - - /* Mergeability is transitive! if a can be merged with b and b - * with c then a also with c */ - - /* Also, if a merged with b cannot be merged with c, then - * either a or b cannot be merged with c either */ - - if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE)) - *a = JOB_START; - else if (types_match(*a, b, JOB_START, JOB_RELOAD) || - types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) || - types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) || - types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START)) - *a = JOB_RELOAD_OR_START; - else if (types_match(*a, b, JOB_START, JOB_RESTART) || - types_match(*a, b, JOB_START, JOB_TRY_RESTART) || - types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) || - types_match(*a, b, JOB_RELOAD, JOB_RESTART) || - types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) || - types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) || - types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART)) - *a = JOB_RESTART; - else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD)) - *a = JOB_RELOAD; - else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) || - types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART)) - *a = JOB_TRY_RESTART; - else - return -EEXIST; - - return 0; -} - -bool job_type_is_mergeable(JobType a, JobType b) { - return job_type_merge(&a, b) >= 0; -} - -bool job_type_is_superset(JobType a, JobType b) { - - /* Checks whether operation a is a "superset" of b in its - * actions */ - - if (a == b) - return true; - - switch (a) { - case JOB_START: - return b == JOB_VERIFY_ACTIVE; - - case JOB_RELOAD: - return - b == JOB_VERIFY_ACTIVE; - - case JOB_RELOAD_OR_START: - return - b == JOB_RELOAD || - b == JOB_START || - b == JOB_VERIFY_ACTIVE; - - case JOB_RESTART: - return - b == JOB_START || - b == JOB_VERIFY_ACTIVE || - b == JOB_RELOAD || - b == JOB_RELOAD_OR_START || - b == JOB_TRY_RESTART; - - case JOB_TRY_RESTART: - return - b == JOB_VERIFY_ACTIVE || - b == JOB_RELOAD; - default: - return false; - - } -} - -bool job_type_is_conflicting(JobType a, JobType b) { - assert(a >= 0 && a < _JOB_TYPE_MAX); - assert(b >= 0 && b < _JOB_TYPE_MAX); - - return (a == JOB_STOP) != (b == JOB_STOP); -} - -bool job_type_is_redundant(JobType a, UnitActiveState b) { - switch (a) { - - case JOB_START: - return - b == UNIT_ACTIVE || - b == UNIT_RELOADING; - - case JOB_STOP: - return - b == UNIT_INACTIVE || - b == UNIT_FAILED; - - case JOB_VERIFY_ACTIVE: - return - b == UNIT_ACTIVE || - b == UNIT_RELOADING; - - case JOB_RELOAD: - return - b == UNIT_RELOADING; - - case JOB_RELOAD_OR_START: - return - b == UNIT_ACTIVATING || - b == UNIT_RELOADING; - - case JOB_RESTART: - return - b == UNIT_ACTIVATING; - - case JOB_TRY_RESTART: - return - b == UNIT_ACTIVATING; - - default: - assert_not_reached("Invalid job type"); - } -} - -bool job_is_runnable(Job *j) { - Iterator i; - Unit *other; - - assert(j); - assert(j->installed); - - /* Checks whether there is any job running for the units this - * job needs to be running after (in the case of a 'positive' - * job type) or before (in the case of a 'negative' job - * type. */ - - /* First check if there is an override */ - if (j->ignore_order) - return true; - - if (j->type == JOB_START || - j->type == JOB_VERIFY_ACTIVE || - j->type == JOB_RELOAD || - j->type == JOB_RELOAD_OR_START) { - - /* Immediate result is that the job is or might be - * started. In this case lets wait for the - * dependencies, regardless whether they are - * starting or stopping something. */ - - SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i) - if (other->meta.job) - return false; - } - - /* Also, if something else is being stopped and we should - * change state after it, then lets wait. */ - - SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i) - if (other->meta.job && - (other->meta.job->type == JOB_STOP || - other->meta.job->type == JOB_RESTART || - other->meta.job->type == JOB_TRY_RESTART)) - return false; - - /* This means that for a service a and a service b where b - * shall be started after a: - * - * start a + start b → 1st step start a, 2nd step start b - * start a + stop b → 1st step stop b, 2nd step start a - * stop a + start b → 1st step stop a, 2nd step start b - * stop a + stop b → 1st step stop b, 2nd step stop a - * - * This has the side effect that restarts are properly - * synchronized too. */ - - return true; -} - -int job_run_and_invalidate(Job *j) { - int r; - uint32_t id; - Manager *m; - - assert(j); - assert(j->installed); - - if (j->in_run_queue) { - LIST_REMOVE(Job, run_queue, j->manager->run_queue, j); - j->in_run_queue = false; - } - - if (j->state != JOB_WAITING) - return 0; - - if (!job_is_runnable(j)) - return -EAGAIN; - - j->state = JOB_RUNNING; - job_add_to_dbus_queue(j); - - /* While we execute this operation the job might go away (for - * example: because it is replaced by a new, conflicting - * job.) To make sure we don't access a freed job later on we - * store the id here, so that we can verify the job is still - * valid. */ - id = j->id; - m = j->manager; - - switch (j->type) { - - case JOB_START: - r = unit_start(j->unit); - - /* If this unit cannot be started, then simply - * wait */ - if (r == -EBADR) - r = 0; - - break; - - case JOB_VERIFY_ACTIVE: { - UnitActiveState t = unit_active_state(j->unit); - if (UNIT_IS_ACTIVE_OR_RELOADING(t)) - r = -EALREADY; - else if (t == UNIT_ACTIVATING) - r = -EAGAIN; - else - r = -ENOEXEC; - break; - } - - case JOB_STOP: - r = unit_stop(j->unit); - - /* If this unit cannot stopped, then simply - * wait. */ - if (r == -EBADR) - r = 0; - break; - - case JOB_RELOAD: - r = unit_reload(j->unit); - break; - - case JOB_RELOAD_OR_START: - if (unit_active_state(j->unit) == UNIT_ACTIVE) { - j->type = JOB_RELOAD; - r = unit_reload(j->unit); - } else { - j->type = JOB_START; - r = unit_start(j->unit); - - if (r == -EBADR) - r = 0; - } - break; - - case JOB_RESTART: { - UnitActiveState t = unit_active_state(j->unit); - if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_ACTIVATING) { - j->type = JOB_START; - r = unit_start(j->unit); - } else - r = unit_stop(j->unit); - break; - } - - case JOB_TRY_RESTART: { - UnitActiveState t = unit_active_state(j->unit); - if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING) - r = -ENOEXEC; - else if (t == UNIT_ACTIVATING) { - j->type = JOB_START; - r = unit_start(j->unit); - } else { - j->type = JOB_RESTART; - r = unit_stop(j->unit); - } - break; - } - - default: - assert_not_reached("Unknown job type"); - } - - if ((j = manager_get_job(m, id))) { - if (r == -EALREADY) - r = job_finish_and_invalidate(j, JOB_DONE); - else if (r == -ENOEXEC) - r = job_finish_and_invalidate(j, JOB_SKIPPED); - else if (r == -EAGAIN) - j->state = JOB_WAITING; - else if (r < 0) - r = job_finish_and_invalidate(j, JOB_FAILED); - } - - return r; -} - -static void job_print_status_message(Unit *u, JobType t, JobResult result) { - assert(u); - - if (t == JOB_START) { - - switch (result) { - - case JOB_DONE: - unit_status_printf(u, "Started %s.\n", unit_description(u)); - break; - - case JOB_FAILED: - unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ", see 'systemctl status %s' for details.\n", unit_description(u), u->meta.id); - break; - - case JOB_DEPENDENCY: - unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "aborted" ANSI_HIGHLIGHT_OFF " because a dependency failed.\n", unit_description(u)); - break; - - case JOB_TIMEOUT: - unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); - break; - - default: - ; - } - - } else if (t == JOB_STOP) { - - switch (result) { - - case JOB_TIMEOUT: - unit_status_printf(u, "Stopping %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); - break; - - case JOB_DONE: - case JOB_FAILED: - unit_status_printf(u, "Stopped %s.\n", unit_description(u)); - break; - - default: - ; - } - } -} - -int job_finish_and_invalidate(Job *j, JobResult result) { - Unit *u; - Unit *other; - JobType t; - Iterator i; - - assert(j); - assert(j->installed); - - job_add_to_dbus_queue(j); - - /* Patch restart jobs so that they become normal start jobs */ - if (result == JOB_DONE && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) { - - log_debug("Converting job %s/%s -> %s/%s", - j->unit->meta.id, job_type_to_string(j->type), - j->unit->meta.id, job_type_to_string(JOB_START)); - - j->state = JOB_WAITING; - j->type = JOB_START; - - job_add_to_run_queue(j); - - u = j->unit; - goto finish; - } - - j->result = result; - - log_debug("Job %s/%s finished, result=%s", j->unit->meta.id, job_type_to_string(j->type), job_result_to_string(result)); - - if (result == JOB_FAILED) - j->manager->n_failed_jobs ++; - - u = j->unit; - t = j->type; - job_free(j); - - job_print_status_message(u, t, result); - - /* Fail depending jobs on failure */ - if (result != JOB_DONE) { - - if (t == JOB_START || - t == JOB_VERIFY_ACTIVE || - t == JOB_RELOAD_OR_START) { - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i) - if (other->meta.job && - (other->meta.job->type == JOB_START || - other->meta.job->type == JOB_VERIFY_ACTIVE || - other->meta.job->type == JOB_RELOAD_OR_START)) - job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY); - - SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i) - if (other->meta.job && - (other->meta.job->type == JOB_START || - other->meta.job->type == JOB_VERIFY_ACTIVE || - other->meta.job->type == JOB_RELOAD_OR_START)) - job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY); - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) - if (other->meta.job && - !other->meta.job->override && - (other->meta.job->type == JOB_START || - other->meta.job->type == JOB_VERIFY_ACTIVE || - other->meta.job->type == JOB_RELOAD_OR_START)) - job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY); - - } else if (t == JOB_STOP) { - - SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTED_BY], i) - if (other->meta.job && - (other->meta.job->type == JOB_START || - other->meta.job->type == JOB_VERIFY_ACTIVE || - other->meta.job->type == JOB_RELOAD_OR_START)) - job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY); - } - } - - /* Trigger OnFailure dependencies that are not generated by - * the unit itself. We don't tread JOB_CANCELED as failure in - * this context. And JOB_FAILURE is already handled by the - * unit itself. */ - if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) { - log_notice("Job %s/%s failed with result '%s'.", - u->meta.id, - job_type_to_string(t), - job_result_to_string(result)); - - unit_trigger_on_failure(u); - } - -finish: - /* Try to start the next jobs that can be started */ - SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i) - if (other->meta.job) - job_add_to_run_queue(other->meta.job); - SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i) - if (other->meta.job) - job_add_to_run_queue(other->meta.job); - - manager_check_finished(u->meta.manager); - - return 0; -} - -int job_start_timer(Job *j) { - struct itimerspec its; - struct epoll_event ev; - int fd, r; - assert(j); - - if (j->unit->meta.job_timeout <= 0 || - j->timer_watch.type == WATCH_JOB_TIMER) - return 0; - - assert(j->timer_watch.type == WATCH_INVALID); - - if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) { - r = -errno; - goto fail; - } - - zero(its); - timespec_store(&its.it_value, j->unit->meta.job_timeout); - - if (timerfd_settime(fd, 0, &its, NULL) < 0) { - r = -errno; - goto fail; - } - - zero(ev); - ev.data.ptr = &j->timer_watch; - ev.events = EPOLLIN; - - if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - goto fail; - } - - j->timer_watch.type = WATCH_JOB_TIMER; - j->timer_watch.fd = fd; - j->timer_watch.data.job = j; - - return 0; - -fail: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -void job_add_to_run_queue(Job *j) { - assert(j); - assert(j->installed); - - if (j->in_run_queue) - return; - - LIST_PREPEND(Job, run_queue, j->manager->run_queue, j); - j->in_run_queue = true; -} - -void job_add_to_dbus_queue(Job *j) { - assert(j); - assert(j->installed); - - if (j->in_dbus_queue) - return; - - /* We don't check if anybody is subscribed here, since this - * job might just have been created and not yet assigned to a - * connection/client. */ - - LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j); - j->in_dbus_queue = true; -} - -char *job_dbus_path(Job *j) { - char *p; - - assert(j); - - if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0) - return NULL; - - return p; -} - -void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) { - assert(j); - assert(w == &j->timer_watch); - - log_warning("Job %s/%s timed out.", j->unit->meta.id, job_type_to_string(j->type)); - job_finish_and_invalidate(j, JOB_TIMEOUT); -} - -static const char* const job_state_table[_JOB_STATE_MAX] = { - [JOB_WAITING] = "waiting", - [JOB_RUNNING] = "running" -}; - -DEFINE_STRING_TABLE_LOOKUP(job_state, JobState); - -static const char* const job_type_table[_JOB_TYPE_MAX] = { - [JOB_START] = "start", - [JOB_VERIFY_ACTIVE] = "verify-active", - [JOB_STOP] = "stop", - [JOB_RELOAD] = "reload", - [JOB_RELOAD_OR_START] = "reload-or-start", - [JOB_RESTART] = "restart", - [JOB_TRY_RESTART] = "try-restart", -}; - -DEFINE_STRING_TABLE_LOOKUP(job_type, JobType); - -static const char* const job_mode_table[_JOB_MODE_MAX] = { - [JOB_FAIL] = "fail", - [JOB_REPLACE] = "replace", - [JOB_ISOLATE] = "isolate", - [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies", - [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements" -}; - -DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode); - -static const char* const job_result_table[_JOB_RESULT_MAX] = { - [JOB_DONE] = "done", - [JOB_CANCELED] = "canceled", - [JOB_TIMEOUT] = "timeout", - [JOB_FAILED] = "failed", - [JOB_DEPENDENCY] = "dependency", - [JOB_SKIPPED] = "skipped" -}; - -DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult); diff --git a/src/job.h b/src/job.h deleted file mode 100644 index 2121426..0000000 --- a/src/job.h +++ /dev/null @@ -1,179 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foojobhfoo -#define foojobhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -typedef struct Job Job; -typedef struct JobDependency JobDependency; -typedef enum JobType JobType; -typedef enum JobState JobState; -typedef enum JobMode JobMode; -typedef enum JobResult JobResult; - -#include "manager.h" -#include "unit.h" -#include "hashmap.h" -#include "list.h" - -enum JobType { - JOB_START, /* if a unit does not support being started, we'll just wait until it becomes active */ - JOB_VERIFY_ACTIVE, - - JOB_STOP, - - JOB_RELOAD, /* if running reload */ - JOB_RELOAD_OR_START, /* if running reload, if not running start */ - - /* Note that restarts are first treated like JOB_STOP, but - * then instead of finishing are patched to become - * JOB_START. */ - JOB_RESTART, /* if running stop, then start unconditionally */ - JOB_TRY_RESTART, /* if running stop and then start */ - - _JOB_TYPE_MAX, - _JOB_TYPE_INVALID = -1 -}; - -enum JobState { - JOB_WAITING, - JOB_RUNNING, - _JOB_STATE_MAX, - _JOB_STATE_INVALID = -1 -}; - -enum JobMode { - JOB_FAIL, /* Fail if a conflicting job is already queued */ - JOB_REPLACE, /* Replace an existing conflicting job */ - JOB_ISOLATE, /* Start a unit, and stop all others */ - JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */ - JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */ - _JOB_MODE_MAX, - _JOB_MODE_INVALID = -1 -}; - -enum JobResult { - JOB_DONE, - JOB_CANCELED, - JOB_TIMEOUT, - JOB_FAILED, - JOB_DEPENDENCY, - JOB_SKIPPED, - _JOB_RESULT_MAX, - _JOB_RESULT_INVALID = -1 -}; - -struct JobDependency { - /* Encodes that the 'subject' job needs the 'object' job in - * some way. This structure is used only while building a transaction. */ - Job *subject; - Job *object; - - LIST_FIELDS(JobDependency, subject); - LIST_FIELDS(JobDependency, object); - - bool matters; - bool conflicts; -}; - -struct Job { - Manager *manager; - Unit *unit; - - LIST_FIELDS(Job, transaction); - LIST_FIELDS(Job, run_queue); - LIST_FIELDS(Job, dbus_queue); - - LIST_HEAD(JobDependency, subject_list); - LIST_HEAD(JobDependency, object_list); - - /* Used for graph algs as a "I have been here" marker */ - Job* marker; - unsigned generation; - - uint32_t id; - - JobType type; - JobState state; - - Watch timer_watch; - - /* Note that this bus object is not ref counted here. */ - DBusConnection *bus; - char *bus_client; - - JobResult result; - - bool installed:1; - bool in_run_queue:1; - bool matters_to_anchor:1; - bool override:1; - bool in_dbus_queue:1; - bool sent_dbus_new_signal:1; - bool ignore_order:1; -}; - -Job* job_new(Manager *m, JobType type, Unit *unit); -void job_free(Job *job); -void job_dump(Job *j, FILE*f, const char *prefix); - -JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); -void job_dependency_free(JobDependency *l); - -bool job_is_anchor(Job *j); - -int job_merge(Job *j, Job *other); - -int job_type_merge(JobType *a, JobType b); -bool job_type_is_mergeable(JobType a, JobType b); -bool job_type_is_superset(JobType a, JobType b); -bool job_type_is_conflicting(JobType a, JobType b); -bool job_type_is_redundant(JobType a, UnitActiveState b); - -bool job_is_runnable(Job *j); - -void job_add_to_run_queue(Job *j); -void job_add_to_dbus_queue(Job *j); - -int job_start_timer(Job *j); -void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w); - -int job_run_and_invalidate(Job *j); -int job_finish_and_invalidate(Job *j, JobResult result); - -char *job_dbus_path(Job *j); - -const char* job_type_to_string(JobType t); -JobType job_type_from_string(const char *s); - -const char* job_state_to_string(JobState t); -JobState job_state_from_string(const char *s); - -const char* job_mode_to_string(JobMode t); -JobMode job_mode_from_string(const char *s); - -const char* job_result_to_string(JobResult t); -JobResult job_result_from_string(const char *s); - -#endif diff --git a/src/journal/.gitignore b/src/journal/.gitignore new file mode 100644 index 0000000..d6a7946 --- /dev/null +++ b/src/journal/.gitignore @@ -0,0 +1,2 @@ +/journald-gperf.c +/libsystemd-journal.pc diff --git a/src/journal/Makefile b/src/journal/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/journal/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/journal/browse.html b/src/journal/browse.html new file mode 100644 index 0000000..3594f70 --- /dev/null +++ b/src/journal/browse.html @@ -0,0 +1,544 @@ + + + + Journal + + + + + + + +

+ +
+
+
+
+
+
+ +
+ +      + Only current boot +
+ +
+ +
+ +
+ + + + +      + + +
+ +
+ g: First Page      + ←, k, BACKSPACE: Previous Page      + →, j, SPACE: Next Page      + G: Last Page      + +: More entries      + -: Fewer entries +
+ + + + diff --git a/src/journal/cat.c b/src/journal/cat.c new file mode 100644 index 0000000..02b7564 --- /dev/null +++ b/src/journal/cat.c @@ -0,0 +1,180 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "util.h" +#include "build.h" + +static char *arg_identifier = NULL; +static int arg_priority = LOG_INFO; +static bool arg_level_prefix = true; + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Execute process with stdout/stderr connected to the journal.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " -t --identifier=STRING Set syslog identifier\n" + " -p --priority=PRIORITY Set priority value (0..7)\n" + " --level-prefix=BOOL Control whether level prefix shall be parsed\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_LEVEL_PREFIX + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "identifier", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 't': + free(arg_identifier); + if (isempty(optarg)) + arg_identifier = NULL; + else { + arg_identifier = strdup(optarg); + if (!arg_identifier) + return log_oom(); + } + break; + + case 'p': + arg_priority = log_level_from_string(optarg); + if (arg_priority < 0) { + log_error("Failed to parse priority value."); + return arg_priority; + } + break; + + case ARG_LEVEL_PREFIX: { + int k; + + k = parse_boolean(optarg); + if (k < 0) { + log_error("Failed to parse level prefix value."); + return k; + } + arg_level_prefix = k; + break; + } + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r, fd = -1, saved_stderr = -1; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); + if (fd < 0) { + log_error("Failed to create stream fd: %s", strerror(-fd)); + r = fd; + goto finish; + } + + saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); + + if (dup3(fd, STDOUT_FILENO, 0) < 0 || + dup3(fd, STDERR_FILENO, 0) < 0) { + log_error("Failed to duplicate fd: %m"); + r = -errno; + goto finish; + } + + if (fd >= 3) + close_nointr_nofail(fd); + + fd = -1; + + if (argc <= optind) + execl("/bin/cat", "/bin/cat", NULL); + else + execvp(argv[optind], argv + optind); + + r = -errno; + + /* Let's try to restore a working stderr, so we can print the error message */ + if (saved_stderr >= 0) + dup3(saved_stderr, STDERR_FILENO, 0); + + log_error("Failed to execute process: %s", strerror(-r)); + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + if (saved_stderr >= 0) + close_nointr_nofail(saved_stderr); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/journal/catalog.c b/src/journal/catalog.c new file mode 100644 index 0000000..2823232 --- /dev/null +++ b/src/journal/catalog.c @@ -0,0 +1,690 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "sparse-endian.h" +#include "sd-id128.h" +#include "hashmap.h" +#include "strv.h" +#include "strbuf.h" +#include "strxcpyx.h" +#include "conf-files.h" +#include "mkdir.h" +#include "catalog.h" +#include "siphash24.h" + +const char * const catalog_file_dirs[] = { + "/usr/local/lib/systemd/catalog/", + "/usr/lib/systemd/catalog/", + NULL +}; + +#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' } + +typedef struct CatalogHeader { + uint8_t signature[8]; /* "RHHHKSLP" */ + le32_t compatible_flags; + le32_t incompatible_flags; + le64_t header_size; + le64_t n_items; + le64_t catalog_item_size; +} CatalogHeader; + +typedef struct CatalogItem { + sd_id128_t id; + char language[32]; + le64_t offset; +} CatalogItem; + +unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + const CatalogItem *i = p; + uint64_t u; + size_t l, sz; + void *v; + + l = strlen(i->language); + sz = sizeof(i->id) + l; + v = alloca(sz); + + memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l); + + siphash24((uint8_t*) &u, v, sz, hash_key); + + return (unsigned long) u; +} + +int catalog_compare_func(const void *a, const void *b) { + const CatalogItem *i = a, *j = b; + unsigned k; + + for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) { + if (i->id.bytes[k] < j->id.bytes[k]) + return -1; + if (i->id.bytes[k] > j->id.bytes[k]) + return 1; + } + + return strcmp(i->language, j->language); +} + +static int finish_item( + Hashmap *h, + struct strbuf *sb, + sd_id128_t id, + const char *language, + const char *payload) { + + ssize_t offset; + CatalogItem *i; + int r; + + assert(h); + assert(sb); + assert(payload); + + offset = strbuf_add_string(sb, payload, strlen(payload)); + if (offset < 0) + return log_oom(); + + i = new0(CatalogItem, 1); + if (!i) + return log_oom(); + + i->id = id; + if (language) { + assert(strlen(language) > 1 && strlen(language) < 32); + strcpy(i->language, language); + } + i->offset = htole64((uint64_t) offset); + + r = hashmap_put(h, i, i); + if (r == EEXIST) { + log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.", + SD_ID128_FORMAT_VAL(id), language ? language : "C"); + free(i); + return 0; + } + + return 0; +} + +int catalog_file_lang(const char* filename, char **lang) { + char *beg, *end, *_lang; + + end = endswith(filename, ".catalog"); + if (!end) + return 0; + + beg = end - 1; + while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32) + beg --; + + if (*beg != '.' || end <= beg + 1) + return 0; + + _lang = strndup(beg + 1, end - beg - 1); + if (!_lang) + return -ENOMEM; + + *lang = _lang; + return 1; +} + +int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *payload = NULL; + unsigned n = 0; + sd_id128_t id; + _cleanup_free_ char *deflang = NULL, *lang = NULL; + bool got_id = false, empty_line = true; + int r; + + assert(h); + assert(sb); + assert(path); + + f = fopen(path, "re"); + if (!f) { + log_error("Failed to open file %s: %m", path); + return -errno; + } + + r = catalog_file_lang(path, &deflang); + if (r < 0) + log_error("Failed to determine language for file %s: %m", path); + if (r == 1) + log_debug("File %s has language %s.", path, deflang); + + for (;;) { + char line[LINE_MAX]; + size_t a, b, c; + char *t; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + break; + + log_error("Failed to read file %s: %m", path); + return -errno; + } + + n++; + + truncate_nl(line); + + if (line[0] == 0) { + empty_line = true; + continue; + } + + if (strchr(COMMENTS "\n", line[0])) + continue; + + if (empty_line && + strlen(line) >= 2+1+32 && + line[0] == '-' && + line[1] == '-' && + line[2] == ' ' && + (line[2+1+32] == ' ' || line[2+1+32] == '\0')) { + + bool with_language; + sd_id128_t jd; + + /* New entry */ + + with_language = line[2+1+32] != '\0'; + line[2+1+32] = '\0'; + + if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { + + if (got_id) { + r = finish_item(h, sb, id, lang ?: deflang, payload); + if (r < 0) + return r; + + free(lang); + lang = NULL; + } + + if (with_language) { + t = strstrip(line + 2 + 1 + 32 + 1); + + c = strlen(t); + if (c <= 0) { + log_error("[%s:%u] Language too short.", path, n); + return -EINVAL; + } + if (c > 31) { + log_error("[%s:%u] language too long.", path, n); + return -EINVAL; + } + + if (deflang) { + log_warning("[%s:%u] language %s", path, n, + streq(t, deflang) ? + "specified unnecessarily" : + "differs from default for file"); + lang = strdup(t); + if (!lang) + return -ENOMEM; + } + } + + got_id = true; + empty_line = false; + id = jd; + + if (payload) + payload[0] = '\0'; + + continue; + } + } + + /* Payload */ + if (!got_id) { + log_error("[%s:%u] Got payload before ID.", path, n); + return -EINVAL; + } + + a = payload ? strlen(payload) : 0; + b = strlen(line); + + c = a + (empty_line ? 1 : 0) + b + 1 + 1; + t = realloc(payload, c); + if (!t) + return log_oom(); + + if (empty_line) { + t[a] = '\n'; + memcpy(t + a + 1, line, b); + t[a+b+1] = '\n'; + t[a+b+2] = 0; + } else { + memcpy(t + a, line, b); + t[a+b] = '\n'; + t[a+b+1] = 0; + } + + payload = t; + empty_line = false; + } + + if (got_id) { + r = finish_item(h, sb, id, lang ?: deflang, payload); + if (r < 0) + return r; + } + + return 0; +} + +static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, + CatalogItem *items, size_t n) { + CatalogHeader header; + _cleanup_fclose_ FILE *w = NULL; + int r; + _cleanup_free_ char *d, *p = NULL; + size_t k; + + d = dirname_malloc(database); + if (!d) + return log_oom(); + + r = mkdir_p(d, 0775); + if (r < 0) { + log_error("Recursive mkdir %s: %s", d, strerror(-r)); + return r; + } + + r = fopen_temporary(database, &w, &p); + if (r < 0) { + log_error("Failed to open database for writing: %s: %s", + database, strerror(-r)); + return r; + } + + 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(hashmap_size(h)); + + r = -EIO; + + k = fwrite(&header, 1, sizeof(header), w); + if (k != sizeof(header)) { + log_error("%s: failed to write header.", p); + goto error; + } + + k = fwrite(items, 1, n * sizeof(CatalogItem), w); + if (k != n * sizeof(CatalogItem)) { + log_error("%s: failed to write database.", p); + goto error; + } + + k = fwrite(sb->buf, 1, sb->len, w); + if (k != sb->len) { + log_error("%s: failed to write strings.", p); + goto error; + } + + fflush(w); + + if (ferror(w)) { + log_error("%s: failed to write database.", p); + goto error; + } + + fchmod(fileno(w), 0644); + + if (rename(p, database) < 0) { + log_error("rename (%s -> %s) failed: %m", p, database); + r = -errno; + goto error; + } + + return ftell(w); + +error: + unlink(p); + return r; +} + +int catalog_update(const char* database, const char* root, const char* const* dirs) { + _cleanup_strv_free_ char **files = NULL; + char **f; + Hashmap *h; + struct strbuf *sb = NULL; + _cleanup_free_ CatalogItem *items = NULL; + CatalogItem *i; + Iterator j; + unsigned n; + long r; + + h = hashmap_new(catalog_hash_func, catalog_compare_func); + sb = strbuf_new(); + + if (!h || !sb) { + r = log_oom(); + goto finish; + } + + r = conf_files_list_strv(&files, ".catalog", root, dirs); + if (r < 0) { + log_error("Failed to get catalog files: %s", strerror(-r)); + goto finish; + } + + STRV_FOREACH(f, files) { + log_debug("reading file '%s'", *f); + catalog_import_file(h, sb, *f); + } + + if (hashmap_size(h) <= 0) { + log_info("No items in catalog."); + r = 0; + goto finish; + } else + log_debug("Found %u items in catalog.", hashmap_size(h)); + + strbuf_complete(sb); + + items = new(CatalogItem, hashmap_size(h)); + if (!items) { + r = log_oom(); + goto finish; + } + + n = 0; + HASHMAP_FOREACH(i, h, j) { + log_debug("Found " SD_ID128_FORMAT_STR ", language %s", + SD_ID128_FORMAT_VAL(i->id), + isempty(i->language) ? "C" : i->language); + items[n++] = *i; + } + + assert(n == hashmap_size(h)); + qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func); + + r = write_catalog(database, h, sb, items, n); + if (r < 0) + log_error("Failed to write %s: %s", database, strerror(-r)); + else + log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.", + database, n, sb->len, r); + + r = 0; + +finish: + if (h) + hashmap_free_free(h); + if (sb) + strbuf_cleanup(sb); + + return r < 0 ? r : 0; +} + +static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) { + const CatalogHeader *h; + int fd; + void *p; + struct stat st; + + assert(_fd); + assert(_st); + assert(_p); + + fd = open(database, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (fstat(fd, &st) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (st.st_size < (off_t) sizeof(CatalogHeader)) { + close_nointr_nofail(fd); + return -EINVAL; + } + + p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) { + close_nointr_nofail(fd); + return -errno; + } + + h = p; + if (memcmp(h->signature, 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))) { + close_nointr_nofail(fd); + munmap(p, st.st_size); + return -EBADMSG; + } + + *_fd = fd; + *_st = st; + *_p = p; + + return 0; +} + +static const char *find_id(void *p, sd_id128_t id) { + CatalogItem key, *f = NULL; + const CatalogHeader *h = p; + const char *loc; + + zero(key); + key.id = id; + + loc = setlocale(LC_MESSAGES, NULL); + if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) { + strncpy(key.language, loc, sizeof(key.language)); + key.language[strcspn(key.language, ".@")] = 0; + + f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); + if (!f) { + char *e; + + e = strchr(key.language, '_'); + if (e) { + *e = 0; + f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); + } + } + } + + if (!f) { + zero(key.language); + f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func); + } + + if (!f) + return NULL; + + return (const char*) p + + le64toh(h->header_size) + + le64toh(h->n_items) * le64toh(h->catalog_item_size) + + le64toh(f->offset); +} + +int catalog_get(const char* database, sd_id128_t id, char **_text) { + _cleanup_close_ int fd = -1; + void *p = NULL; + struct stat st; + char *text = NULL; + int r; + const char *s; + + assert(_text); + + r = open_mmap(database, &fd, &st, &p); + if (r < 0) + return r; + + s = find_id(p, id); + if (!s) { + r = -ENOENT; + goto finish; + } + + text = strdup(s); + if (!text) { + r = -ENOMEM; + goto finish; + } + + *_text = text; + r = 0; + +finish: + if (p) + munmap(p, st.st_size); + + return r; +} + +static char *find_header(const char *s, const char *header) { + + for (;;) { + const char *v, *e; + + v = startswith(s, header); + if (v) { + v += strspn(v, WHITESPACE); + return strndup(v, strcspn(v, NEWLINE)); + } + + /* End of text */ + e = strchr(s, '\n'); + if (!e) + return NULL; + + /* End of header */ + if (e == s) + return NULL; + + s = e + 1; + } +} + +static void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) { + if (oneline) { + _cleanup_free_ char *subject = NULL, *defined_by = NULL; + + subject = find_header(s, "Subject:"); + defined_by = find_header(s, "Defined-By:"); + + fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n", + SD_ID128_FORMAT_VAL(id), + strna(defined_by), strna(subject)); + } else + fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n", + SD_ID128_FORMAT_VAL(id), s); +} + + +int catalog_list(FILE *f, const char *database, bool oneline) { + _cleanup_close_ int fd = -1; + void *p = NULL; + struct stat st; + const CatalogHeader *h; + const CatalogItem *items; + int r; + unsigned n; + sd_id128_t last_id; + bool last_id_set = false; + + r = open_mmap(database, &fd, &st, &p); + if (r < 0) + return r; + + h = p; + items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size)); + + for (n = 0; n < le64toh(h->n_items); n++) { + const char *s; + + if (last_id_set && sd_id128_equal(last_id, items[n].id)) + continue; + + assert_se(s = find_id(p, items[n].id)); + + dump_catalog_entry(f, items[n].id, s, oneline); + + last_id_set = true; + last_id = items[n].id; + } + + munmap(p, st.st_size); + + return 0; +} + +int catalog_list_items(FILE *f, const char *database, bool oneline, char **items) { + char **item; + int r = 0; + + STRV_FOREACH(item, items) { + sd_id128_t id; + int k; + _cleanup_free_ char *msg = NULL; + + k = sd_id128_from_string(*item, &id); + if (k < 0) { + log_error("Failed to parse id128 '%s': %s", + *item, strerror(-k)); + if (r == 0) + r = k; + continue; + } + + k = catalog_get(database, id, &msg); + if (k < 0) { + log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR, + "Failed to retrieve catalog entry for '%s': %s", + *item, strerror(-k)); + if (r == 0) + r = k; + continue; + } + + dump_catalog_entry(f, id, msg, oneline); + } + + return r; +} diff --git a/src/journal/catalog.h b/src/journal/catalog.h new file mode 100644 index 0000000..fdde67a --- /dev/null +++ b/src/journal/catalog.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-id128.h" +#include "hashmap.h" +#include "strbuf.h" + +int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path); +unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +int catalog_compare_func(const void *a, const void *b) _pure_; +int catalog_update(const char* database, const char* root, const char* const* dirs); +int catalog_get(const char* database, sd_id128_t id, char **data); +int catalog_list(FILE *f, const char* database, bool oneline); +int catalog_list_items(FILE *f, const char* database, bool oneline, char **items); +int catalog_file_lang(const char *filename, char **lang); +extern const char * const catalog_file_dirs[]; diff --git a/src/journal/compress.c b/src/journal/compress.c new file mode 100644 index 0000000..a4427be --- /dev/null +++ b/src/journal/compress.c @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "macro.h" +#include "compress.h" + +bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) { + lzma_stream s = LZMA_STREAM_INIT; + lzma_ret ret; + bool b = false; + + assert(src); + assert(src_size > 0); + assert(dst); + assert(dst_size); + + /* Returns false if we couldn't compress the data or the + * compressed result is longer than the original */ + + ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE); + if (ret != LZMA_OK) + return false; + + s.next_in = src; + s.avail_in = src_size; + s.next_out = dst; + s.avail_out = src_size; + + /* Does it fit? */ + if (lzma_code(&s, LZMA_FINISH) != LZMA_STREAM_END) + goto fail; + + /* Is it actually shorter? */ + if (s.avail_out == 0) + goto fail; + + *dst_size = src_size - s.avail_out; + b = true; + +fail: + lzma_end(&s); + + return b; +} + +bool uncompress_blob(const void *src, uint64_t src_size, + void **dst, uint64_t *dst_alloc_size, uint64_t* dst_size, uint64_t dst_max) { + + lzma_stream s = LZMA_STREAM_INIT; + lzma_ret ret; + uint64_t space; + bool b = false; + + assert(src); + assert(src_size > 0); + assert(dst); + assert(dst_alloc_size); + assert(dst_size); + assert(*dst_alloc_size == 0 || *dst); + + ret = lzma_stream_decoder(&s, UINT64_MAX, 0); + if (ret != LZMA_OK) + return false; + + if (*dst_alloc_size <= src_size) { + void *p; + + p = realloc(*dst, src_size*2); + if (!p) + return false; + + *dst = p; + *dst_alloc_size = src_size*2; + } + + s.next_in = src; + s.avail_in = src_size; + + s.next_out = *dst; + space = dst_max > 0 ? MIN(*dst_alloc_size, dst_max) : *dst_alloc_size; + s.avail_out = space; + + for (;;) { + void *p; + + ret = lzma_code(&s, LZMA_FINISH); + + if (ret == LZMA_STREAM_END) + break; + + if (ret != LZMA_OK) + goto fail; + + if (dst_max > 0 && (space - s.avail_out) >= dst_max) + break; + + p = realloc(*dst, space*2); + if (!p) + goto fail; + + s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *dst); + s.avail_out += space; + + space *= 2; + + *dst = p; + *dst_alloc_size = space; + } + + *dst_size = space - s.avail_out; + b = true; + +fail: + lzma_end(&s); + + return b; +} + +bool uncompress_startswith(const void *src, uint64_t src_size, + void **buffer, uint64_t *buffer_size, + const void *prefix, uint64_t prefix_len, + uint8_t extra) { + + lzma_stream s = LZMA_STREAM_INIT; + lzma_ret ret; + bool b = false; + + /* Checks whether the uncompressed blob starts with the + * mentioned prefix. The byte extra needs to follow the + * prefix */ + + assert(src); + assert(src_size > 0); + assert(buffer); + assert(buffer_size); + assert(prefix); + assert(*buffer_size == 0 || *buffer); + + ret = lzma_stream_decoder(&s, UINT64_MAX, 0); + if (ret != LZMA_OK) + return false; + + if (*buffer_size <= prefix_len) { + void *p; + + p = realloc(*buffer, prefix_len*2); + if (!p) + return false; + + *buffer = p; + *buffer_size = prefix_len*2; + } + + s.next_in = src; + s.avail_in = src_size; + + s.next_out = *buffer; + s.avail_out = *buffer_size; + + for (;;) { + void *p; + + ret = lzma_code(&s, LZMA_FINISH); + + if (ret != LZMA_STREAM_END && ret != LZMA_OK) + goto fail; + + if ((*buffer_size - s.avail_out > prefix_len) && + memcmp(*buffer, prefix, prefix_len) == 0 && + ((const uint8_t*) *buffer)[prefix_len] == extra) + break; + + if (ret == LZMA_STREAM_END) + goto fail; + + p = realloc(*buffer, *buffer_size*2); + if (!p) + goto fail; + + s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *buffer); + s.avail_out += *buffer_size; + + *buffer = p; + *buffer_size *= 2; + } + + b = true; + +fail: + lzma_end(&s); + + return b; +} diff --git a/src/journal/compress.h b/src/journal/compress.h new file mode 100644 index 0000000..2b87e73 --- /dev/null +++ b/src/journal/compress.h @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size); + +bool uncompress_blob(const void *src, uint64_t src_size, + void **dst, uint64_t *dst_alloc_size, uint64_t* dst_size, uint64_t dst_max); + +bool uncompress_startswith(const void *src, uint64_t src_size, + void **buffer, uint64_t *buffer_size, + const void *prefix, uint64_t prefix_len, + uint8_t extra); diff --git a/src/journal/coredump.c b/src/journal/coredump.c new file mode 100644 index 0000000..733373b --- /dev/null +++ b/src/journal/coredump.c @@ -0,0 +1,284 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include + +#ifdef HAVE_LOGIND +#include +#endif + +#include "log.h" +#include "util.h" +#include "macro.h" +#include "mkdir.h" +#include "special.h" +#include "cgroup-util.h" + +/* Few programs have less than 3MiB resident */ +#define COREDUMP_MIN_START (3*1024*1024) +/* Make sure to not make this larger than the maximum journal entry + * size. See ENTRY_SIZE_MAX in journald-native.c. */ +#define COREDUMP_MAX (767*1024*1024) + +enum { + ARG_PID = 1, + ARG_UID, + ARG_GID, + ARG_SIGNAL, + ARG_TIMESTAMP, + ARG_COMM, + _ARG_MAX +}; + +static int divert_coredump(void) { + _cleanup_fclose_ FILE *f = NULL; + + log_info("Detected coredump of the journal daemon itself, diverting coredump to /var/lib/systemd/coredump/."); + + mkdir_p_label("/var/lib/systemd/coredump", 0755); + + f = fopen("/var/lib/systemd/coredump/core.systemd-journald", "we"); + if (!f) { + log_error("Failed to create coredump file: %m"); + return -errno; + } + + for (;;) { + uint8_t buffer[4096]; + size_t l, q; + + l = fread(buffer, 1, sizeof(buffer), stdin); + if (l <= 0) { + if (ferror(f)) { + log_error("Failed to read coredump: %m"); + return -errno; + } + + break; + } + + q = fwrite(buffer, 1, l, f); + if (q != l) { + log_error("Failed to write coredump: %m"); + return -errno; + } + } + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write coredump: %m"); + return -errno; + } + + return 0; +} + +int main(int argc, char* argv[]) { + int r, j = 0; + char *t; + ssize_t n; + pid_t pid; + uid_t uid; + gid_t gid; + struct iovec iovec[14]; + size_t coredump_bufsize, coredump_size; + _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, + *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, + *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL; + + prctl(PR_SET_DUMPABLE, 0); + + if (argc != _ARG_MAX) { + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + + log_error("Invalid number of arguments passed from kernel."); + r = -EINVAL; + goto finish; + } + + r = parse_pid(argv[ARG_PID], &pid); + if (r < 0) { + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + + log_error("Failed to parse PID."); + goto finish; + } + + if (cg_pid_get_unit(pid, &t) >= 0) { + + if (streq(t, SPECIAL_JOURNALD_SERVICE)) { + /* Make sure we don't make use of the journal, + * if it's the journal which is crashing */ + log_set_target(LOG_TARGET_KMSG); + log_open(); + + r = divert_coredump(); + goto finish; + } + + core_unit = strappend("COREDUMP_UNIT=", t); + } else if (cg_pid_get_user_unit(pid, &t) >= 0) + core_unit = strappend("COREDUMP_USER_UNIT=", t); + + if (core_unit) + IOVEC_SET_STRING(iovec[j++], core_unit); + + /* OK, now we know it's not the journal, hence make use of + * it */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + + r = parse_uid(argv[ARG_UID], &uid); + if (r < 0) { + log_error("Failed to parse UID."); + goto finish; + } + + r = parse_gid(argv[ARG_GID], &gid); + if (r < 0) { + log_error("Failed to parse GID."); + goto finish; + } + + core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); + if (core_pid) + IOVEC_SET_STRING(iovec[j++], core_pid); + + core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); + if (core_uid) + IOVEC_SET_STRING(iovec[j++], core_uid); + + core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); + if (core_gid) + IOVEC_SET_STRING(iovec[j++], core_gid); + + core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); + if (core_signal) + IOVEC_SET_STRING(iovec[j++], core_signal); + + core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); + if (core_comm) + IOVEC_SET_STRING(iovec[j++], core_comm); + +#ifdef HAVE_LOGIND + if (sd_pid_get_session(pid, &t) >= 0) { + core_session = strappend("COREDUMP_SESSION=", t); + free(t); + + if (core_session) + IOVEC_SET_STRING(iovec[j++], core_session); + } + +#endif + + if (get_process_exe(pid, &t) >= 0) { + core_exe = strappend("COREDUMP_EXE=", t); + free(t); + + if (core_exe) + IOVEC_SET_STRING(iovec[j++], core_exe); + } + + if (get_process_cmdline(pid, 0, false, &t) >= 0) { + core_cmdline = strappend("COREDUMP_CMDLINE=", t); + free(t); + + if (core_cmdline) + IOVEC_SET_STRING(iovec[j++], core_cmdline); + } + + core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); + if (core_timestamp) + IOVEC_SET_STRING(iovec[j++], core_timestamp); + + IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); + IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); + + core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); + if (core_message) + IOVEC_SET_STRING(iovec[j++], core_message); + + /* Now, let's drop privileges to become the user who owns the + * segfaulted process and allocate the coredump memory under + * his uid. This also ensures that the credentials journald + * will see are the ones of the coredumping user, thus making + * sure the user himself gets access to the core dump. */ + + if (setresgid(gid, gid, gid) < 0 || + setresuid(uid, uid, uid) < 0) { + log_error("Failed to drop privileges: %m"); + r = -errno; + goto finish; + } + + coredump_bufsize = COREDUMP_MIN_START; + coredump_data = malloc(coredump_bufsize); + if (!coredump_data) { + log_warning("Failed to allocate memory for core, core will not be stored."); + goto finalize; + } + + memcpy(coredump_data, "COREDUMP=", 9); + coredump_size = 9; + + for (;;) { + n = loop_read(STDIN_FILENO, coredump_data + coredump_size, + coredump_bufsize - coredump_size, false); + if (n < 0) { + log_error("Failed to read core data: %s", strerror(-n)); + r = (int) n; + goto finish; + } else if (n == 0) + break; + + coredump_size += n; + + if (coredump_size > COREDUMP_MAX) { + log_error("Core too large, core will not be stored."); + goto finalize; + } + + if (!GREEDY_REALLOC(coredump_data, coredump_bufsize, coredump_size + 1)) { + log_warning("Failed to allocate memory for core, core will not be stored."); + goto finalize; + } + } + + iovec[j].iov_base = coredump_data; + iovec[j].iov_len = coredump_size; + j++; + +finalize: + r = sd_journal_sendv(iovec, j); + if (r < 0) + log_error("Failed to log coredump: %s", strerror(-r)); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c new file mode 100644 index 0000000..3bceb48 --- /dev/null +++ b/src/journal/coredumpctl.c @@ -0,0 +1,595 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "build.h" +#include "set.h" +#include "util.h" +#include "log.h" +#include "path-util.h" +#include "pager.h" +#include "macro.h" +#include "journal-internal.h" + +static enum { + ACTION_NONE, + ACTION_LIST, + ACTION_DUMP, + ACTION_GDB, +} arg_action = ACTION_LIST; + +static FILE* output = NULL; +static char* field = NULL; + +static int arg_no_pager = false; +static int arg_no_legend = false; + +static Set *new_matches(void) { + Set *set; + char *tmp; + int r; + + set = set_new(trivial_hash_func, trivial_compare_func); + if (!set) { + log_oom(); + return NULL; + } + + tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); + if (!tmp) { + log_oom(); + set_free(set); + return NULL; + } + + r = set_consume(set, tmp); + if (r < 0) { + log_error("failed to add to set: %s", strerror(-r)); + set_free(set); + return NULL; + } + + return set; +} + +static int help(void) { + printf("%s [OPTIONS...] [MATCHES...]\n\n" + "List or retrieve coredumps from the journal.\n\n" + "Flags:\n" + " -o --output=FILE Write output to FILE\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not print the column headers.\n\n" + + "Commands:\n" + " -h --help Show this help\n" + " --version Print version string\n" + " -F --field=FIELD List all values a certain field takes\n" + " gdb Start gdb for the first matching coredump\n" + " list List available coredumps\n" + " dump PID Print coredump to stdout\n" + " dump PATH Print coredump to stdout\n" + , program_invocation_short_name); + + return 0; +} + +static int add_match(Set *set, const char *match) { + int r = -ENOMEM; + unsigned pid; + const char* prefix; + char *pattern = NULL; + _cleanup_free_ char *p = NULL; + + if (strchr(match, '=')) + prefix = ""; + else if (strchr(match, '/')) { + p = path_make_absolute_cwd(match); + if (!p) + goto fail; + + match = p; + prefix = "COREDUMP_EXE="; + } + else if (safe_atou(match, &pid) == 0) + prefix = "COREDUMP_PID="; + else + prefix = "COREDUMP_COMM="; + + pattern = strjoin(prefix, match, NULL); + if (!pattern) + goto fail; + + log_debug("Adding pattern: %s", pattern); + r = set_put(set, pattern); + if (r < 0) { + log_error("Failed to add pattern '%s': %s", + pattern, strerror(-r)); + free(pattern); + goto fail; + } + + return 0; +fail: + log_error("Failed to add match: %s", strerror(-r)); + return r; +} + +static int parse_argv(int argc, char *argv[], Set *matches) { + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, + }; + + int r, c; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "output", required_argument, NULL, 'o' }, + { "field", required_argument, NULL, 'F' }, + {} + }; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "ho:F:", options, NULL)) >= 0) + switch(c) { + + case 'h': + arg_action = ACTION_NONE; + return help(); + + case ARG_VERSION: + arg_action = ACTION_NONE; + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_LEGEND: + arg_no_legend = true; + break; + + case 'o': + if (output) { + log_error("cannot set output more than once"); + return -EINVAL; + } + + output = fopen(optarg, "we"); + if (!output) { + log_error("writing to '%s': %m", optarg); + return -errno; + } + + break; + + case 'F': + if (field) { + log_error("cannot use --field/-F more than once"); + return -EINVAL; + } + + field = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (optind < argc) { + const char *cmd = argv[optind++]; + if (streq(cmd, "list")) + arg_action = ACTION_LIST; + else if (streq(cmd, "dump")) + arg_action = ACTION_DUMP; + else if (streq(cmd, "gdb")) + arg_action = ACTION_GDB; + else { + log_error("Unknown action '%s'", cmd); + return -EINVAL; + } + } + + if (field && arg_action != ACTION_LIST) { + log_error("Option --field/-F only makes sense with list"); + return -EINVAL; + } + + while (optind < argc) { + r = add_match(matches, argv[optind]); + if (r != 0) + return r; + optind++; + } + + return 0; +} + +static int retrieve(const void *data, + size_t len, + const char *name, + const char **var) { + + size_t ident; + + ident = strlen(name) + 1; /* name + "=" */ + + if (len < ident) + return 0; + + if (memcmp(data, name, ident - 1) != 0) + return 0; + + if (((const char*) data)[ident - 1] != '=') + return 0; + + *var = strndup((const char*)data + ident, len - ident); + if (!*var) + return log_oom(); + + return 0; +} + +static void print_field(FILE* file, sd_journal *j) { + _cleanup_free_ const char *value = NULL; + const void *d; + size_t l; + + assert(field); + + SD_JOURNAL_FOREACH_DATA(j, d, l) + retrieve(d, l, field, &value); + if (value) + fprintf(file, "%s\n", value); +} + +static int print_entry(FILE* file, sd_journal *j, int had_legend) { + _cleanup_free_ const char + *pid = NULL, *uid = NULL, *gid = NULL, + *sgnl = NULL, *exe = NULL; + const void *d; + size_t l; + usec_t t; + char buf[FORMAT_TIMESTAMP_MAX]; + int r; + + SD_JOURNAL_FOREACH_DATA(j, d, l) { + retrieve(d, l, "COREDUMP_PID", &pid); + retrieve(d, l, "COREDUMP_PID", &pid); + retrieve(d, l, "COREDUMP_UID", &uid); + retrieve(d, l, "COREDUMP_GID", &gid); + retrieve(d, l, "COREDUMP_SIGNAL", &sgnl); + retrieve(d, l, "COREDUMP_EXE", &exe); + if (!exe) + retrieve(d, l, "COREDUMP_COMM", &exe); + if (!exe) + retrieve(d, l, "COREDUMP_CMDLINE", &exe); + } + + if (!pid && !uid && !gid && !sgnl && !exe) { + log_warning("Empty coredump log entry"); + return -EINVAL; + } + + r = sd_journal_get_realtime_usec(j, &t); + if (r < 0) { + log_error("Failed to get realtime timestamp: %s", strerror(-r)); + return r; + } + + format_timestamp(buf, sizeof(buf), t); + + if (!had_legend && !arg_no_legend) + fprintf(file, "%-*s %*s %*s %*s %*s %s\n", + FORMAT_TIMESTAMP_MAX-1, "TIME", + 6, "PID", + 5, "UID", + 5, "GID", + 3, "SIG", + "EXE"); + + fprintf(file, "%*s %*s %*s %*s %*s %s\n", + FORMAT_TIMESTAMP_MAX-1, buf, + 6, pid, + 5, uid, + 5, gid, + 3, sgnl, + exe); + + return 0; +} + +static int dump_list(sd_journal *j) { + int found = 0; + + assert(j); + + /* The coredumps are likely to compressed, and for just + * listing them we don't need to decompress them, so let's + * pick a fairly low data threshold here */ + sd_journal_set_data_threshold(j, 4096); + + SD_JOURNAL_FOREACH(j) { + if (field) + print_field(stdout, j); + else + print_entry(stdout, j, found++); + } + + if (!field && !found) { + log_notice("No coredumps found"); + return -ESRCH; + } + + return 0; +} + +static int focus(sd_journal *j) { + int r; + + r = sd_journal_seek_tail(j); + if (r == 0) + r = sd_journal_previous(j); + if (r < 0) { + log_error("Failed to search journal: %s", strerror(-r)); + return r; + } + if (r == 0) { + log_error("No match found"); + return -ESRCH; + } + return r; +} + +static int dump_core(sd_journal* j) { + const void *data; + size_t len, ret; + int r; + + assert(j); + + /* We want full data, nothing truncated. */ + sd_journal_set_data_threshold(j, 0); + + r = focus(j); + if (r < 0) + return r; + + print_entry(output ? stdout : stderr, j, false); + + if (on_tty() && !output) { + log_error("Refusing to dump core to tty"); + return -ENOTTY; + } + + r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); + if (r < 0) { + log_error("Failed to retrieve COREDUMP field: %s", strerror(-r)); + return r; + } + + assert(len >= 9); + data = (const uint8_t*) data + 9; + len -= 9; + + ret = fwrite(data, len, 1, output ? output : stdout); + if (ret != 1) { + log_error("dumping coredump: %m (%zu)", ret); + return -errno; + } + + r = sd_journal_previous(j); + if (r >= 0) + log_warning("More than one entry matches, ignoring rest."); + + return 0; +} + +static int run_gdb(sd_journal *j) { + char path[] = "/var/tmp/coredump-XXXXXX"; + const void *data; + size_t len; + ssize_t sz; + pid_t pid; + _cleanup_free_ char *exe = NULL; + int r; + _cleanup_close_ int fd = -1; + siginfo_t st; + + assert(j); + + sd_journal_set_data_threshold(j, 0); + + r = focus(j); + if (r < 0) + return r; + + print_entry(stdout, j, false); + + r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len); + if (r < 0) { + log_error("Failed to retrieve COREDUMP_EXE field: %s", strerror(-r)); + return r; + } + + assert(len >= 13); + data = (const uint8_t*) data + 13; + len -= 13; + + exe = strndup(data, len); + if (!exe) + return log_oom(); + + if (endswith(exe, " (deleted)")) { + log_error("Binary already deleted."); + return -ENOENT; + } + + r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len); + if (r < 0) { + log_error("Failed to retrieve COREDUMP field: %s", strerror(-r)); + return r; + } + + assert(len >= 9); + data = (const uint8_t*) data + 9; + len -= 9; + + fd = mkostemp_safe(path, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to create temporary file: %m"); + return -errno; + } + + sz = write(fd, data, len); + if (sz < 0) { + log_error("Failed to write temporary file: %m"); + r = -errno; + goto finish; + } + if (sz != (ssize_t) len) { + log_error("Short write to temporary file."); + r = -EIO; + goto finish; + } + + close_nointr_nofail(fd); + fd = -1; + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork(): %m"); + r = -errno; + goto finish; + } + if (pid == 0) { + execlp("gdb", "gdb", exe, path, NULL); + log_error("Failed to invoke gdb: %m"); + _exit(1); + } + + r = wait_for_terminate(pid, &st); + if (r < 0) { + log_error("Failed to wait for gdb: %m"); + goto finish; + } + + r = st.si_code == CLD_EXITED ? st.si_status : 255; + +finish: + unlink(path); + return r; +} + +int main(int argc, char *argv[]) { + _cleanup_journal_close_ sd_journal*j = NULL; + const char* match; + Iterator it; + int r = 0; + _cleanup_set_free_free_ Set *matches = NULL; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + matches = new_matches(); + if (!matches) { + r = -ENOMEM; + goto end; + } + + r = parse_argv(argc, argv, matches); + if (r < 0) + goto end; + + if (arg_action == ACTION_NONE) + goto end; + + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + log_error("Failed to open journal: %s", strerror(-r)); + goto end; + } + + SET_FOREACH(match, matches, it) { + r = sd_journal_add_match(j, match, strlen(match)); + if (r != 0) { + log_error("Failed to add match '%s': %s", + match, strerror(-r)); + goto end; + } + } + + if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + _cleanup_free_ char *filter; + + filter = journal_make_match_string(j); + log_debug("Journal filter: %s", filter); + } + + switch(arg_action) { + + case ACTION_LIST: + if (!arg_no_pager) + pager_open(false); + + r = dump_list(j); + break; + + case ACTION_DUMP: + r = dump_core(j); + break; + + case ACTION_GDB: + r = run_gdb(j); + break; + + default: + assert_not_reached("Shouldn't be here"); + } + +end: + pager_close(); + + if (output) + fclose(output); + + return r >= 0 ? r : EXIT_FAILURE; +} diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c new file mode 100644 index 0000000..5c8d6d6 --- /dev/null +++ b/src/journal/fsprg.c @@ -0,0 +1,390 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/* + * fsprg v0.1 - (seekable) forward-secure pseudorandom generator + * Copyright (C) 2012 B. Poettering + * Contact: fsprg@point-at-infinity.org + * + * This library 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. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* + * See "Practical Secure Logging: Seekable Sequential Key Generators" + * by G. A. Marson, B. Poettering for details: + * + * http://eprint.iacr.org/2013/397 + */ + +#include +#include +#include + +#include "fsprg.h" + +#define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384)) +#define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar)); + +#define RND_HASH GCRY_MD_SHA256 +#define RND_GEN_P 0x01 +#define RND_GEN_Q 0x02 +#define RND_GEN_X 0x03 + +/******************************************************************************/ + +static void mpi_export(void *buf, size_t buflen, const gcry_mpi_t x) { + unsigned len; + size_t nwritten; + + assert(gcry_mpi_cmp_ui(x, 0) >= 0); + len = (gcry_mpi_get_nbits(x) + 7) / 8; + assert(len <= buflen); + memzero(buf, buflen); + gcry_mpi_print(GCRYMPI_FMT_USG, buf + (buflen - len), len, &nwritten, x); + assert(nwritten == len); +} + +static gcry_mpi_t mpi_import(const void *buf, size_t buflen) { + gcry_mpi_t h; + unsigned len; + + gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL); + len = (gcry_mpi_get_nbits(h) + 7) / 8; + assert(len <= buflen); + assert(gcry_mpi_cmp_ui(h, 0) >= 0); + + return h; +} + +static void uint64_export(void *buf, size_t buflen, uint64_t x) { + assert(buflen == 8); + ((uint8_t*) buf)[0] = (x >> 56) & 0xff; + ((uint8_t*) buf)[1] = (x >> 48) & 0xff; + ((uint8_t*) buf)[2] = (x >> 40) & 0xff; + ((uint8_t*) buf)[3] = (x >> 32) & 0xff; + ((uint8_t*) buf)[4] = (x >> 24) & 0xff; + ((uint8_t*) buf)[5] = (x >> 16) & 0xff; + ((uint8_t*) buf)[6] = (x >> 8) & 0xff; + ((uint8_t*) buf)[7] = (x >> 0) & 0xff; +} + +_pure_ static uint64_t uint64_import(const void *buf, size_t buflen) { + assert(buflen == 8); + return + (uint64_t)(((uint8_t*) buf)[0]) << 56 | + (uint64_t)(((uint8_t*) buf)[1]) << 48 | + (uint64_t)(((uint8_t*) buf)[2]) << 40 | + (uint64_t)(((uint8_t*) buf)[3]) << 32 | + (uint64_t)(((uint8_t*) buf)[4]) << 24 | + (uint64_t)(((uint8_t*) buf)[5]) << 16 | + (uint64_t)(((uint8_t*) buf)[6]) << 8 | + (uint64_t)(((uint8_t*) buf)[7]) << 0; +} + +/* deterministically generate from seed/idx a string of buflen pseudorandom bytes */ +static void det_randomize(void *buf, size_t buflen, const void *seed, size_t seedlen, uint32_t idx) { + gcry_md_hd_t hd, hd2; + size_t olen, cpylen; + uint32_t ctr; + + olen = gcry_md_get_algo_dlen(RND_HASH); + gcry_md_open(&hd, RND_HASH, 0); + gcry_md_write(hd, seed, seedlen); + gcry_md_putc(hd, (idx >> 24) & 0xff); + gcry_md_putc(hd, (idx >> 16) & 0xff); + gcry_md_putc(hd, (idx >> 8) & 0xff); + gcry_md_putc(hd, (idx >> 0) & 0xff); + + for (ctr = 0; buflen; ctr++) { + gcry_md_copy(&hd2, hd); + gcry_md_putc(hd2, (ctr >> 24) & 0xff); + gcry_md_putc(hd2, (ctr >> 16) & 0xff); + gcry_md_putc(hd2, (ctr >> 8) & 0xff); + gcry_md_putc(hd2, (ctr >> 0) & 0xff); + gcry_md_final(hd2); + cpylen = (buflen < olen) ? buflen : olen; + memcpy(buf, gcry_md_read(hd2, RND_HASH), cpylen); + gcry_md_close(hd2); + buf += cpylen; + buflen -= cpylen; + } + gcry_md_close(hd); +} + +/* deterministically generate from seed/idx a prime of length `bits' that is 3 (mod 4) */ +static gcry_mpi_t genprime3mod4(int bits, const void *seed, size_t seedlen, uint32_t idx) { + size_t buflen = bits / 8; + uint8_t buf[buflen]; + gcry_mpi_t p; + + assert(bits % 8 == 0); + assert(buflen > 0); + + det_randomize(buf, buflen, seed, seedlen, idx); + buf[0] |= 0xc0; /* set upper two bits, so that n=pq has maximum size */ + buf[buflen - 1] |= 0x03; /* set lower two bits, to have result 3 (mod 4) */ + + p = mpi_import(buf, buflen); + while (gcry_prime_check(p, 0)) + gcry_mpi_add_ui(p, p, 4); + + return p; +} + +/* deterministically generate from seed/idx a quadratic residue (mod n) */ +static gcry_mpi_t gensquare(const gcry_mpi_t n, const void *seed, size_t seedlen, uint32_t idx, unsigned secpar) { + size_t buflen = secpar / 8; + uint8_t buf[buflen]; + gcry_mpi_t x; + + det_randomize(buf, buflen, seed, seedlen, idx); + buf[0] &= 0x7f; /* clear upper bit, so that we have x < n */ + x = mpi_import(buf, buflen); + assert(gcry_mpi_cmp(x, n) < 0); + gcry_mpi_mulm(x, x, x, n); + return x; +} + +/* compute 2^m (mod phi(p)), for a prime p */ +static gcry_mpi_t twopowmodphi(uint64_t m, const gcry_mpi_t p) { + gcry_mpi_t phi, r; + int n; + + phi = gcry_mpi_new(0); + gcry_mpi_sub_ui(phi, p, 1); + + /* count number of used bits in m */ + for (n = 0; (1ULL << n) <= m; n++) + ; + + r = gcry_mpi_new(0); + gcry_mpi_set_ui(r, 1); + while (n) { /* square and multiply algorithm for fast exponentiation */ + n--; + gcry_mpi_mulm(r, r, r, phi); + if (m & ((uint64_t)1 << n)) { + gcry_mpi_add(r, r, r); + if (gcry_mpi_cmp(r, phi) >= 0) + gcry_mpi_sub(r, r, phi); + } + } + + gcry_mpi_release(phi); + return r; +} + +/* Decompose $x \in Z_n$ into $(xp,xq) \in Z_p \times Z_q$ using Chinese Remainder Theorem */ +static void CRT_decompose(gcry_mpi_t *xp, gcry_mpi_t *xq, const gcry_mpi_t x, const gcry_mpi_t p, const gcry_mpi_t q) { + *xp = gcry_mpi_new(0); + *xq = gcry_mpi_new(0); + gcry_mpi_mod(*xp, x, p); + gcry_mpi_mod(*xq, x, q); +} + +/* Compose $(xp,xq) \in Z_p \times Z_q$ into $x \in Z_n$ using Chinese Remainder Theorem */ +static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, const gcry_mpi_t p, const gcry_mpi_t q) { + gcry_mpi_t a, u; + + a = gcry_mpi_new(0); + u = gcry_mpi_new(0); + *x = gcry_mpi_new(0); + gcry_mpi_subm(a, xq, xp, q); + gcry_mpi_invm(u, p, q); + gcry_mpi_mulm(a, a, u, q); /* a = (xq - xp) / p (mod q) */ + gcry_mpi_mul(*x, p, a); + gcry_mpi_add(*x, *x, xp); /* x = p * ((xq - xp) / p mod q) + xp */ + gcry_mpi_release(a); + gcry_mpi_release(u); +} + +static void initialize_libgcrypt(void) { + const char *p; + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + /* Turn off "secmem". Clients which whish to make use of this + * feature should initialize the library manually */ + gcry_control(GCRYCTL_DISABLE_SECMEM); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +/******************************************************************************/ + +size_t FSPRG_mskinbytes(unsigned _secpar) { + VALIDATE_SECPAR(_secpar); + return 2 + 2 * (_secpar / 2) / 8; /* to store header,p,q */ +} + +size_t FSPRG_mpkinbytes(unsigned _secpar) { + VALIDATE_SECPAR(_secpar); + return 2 + _secpar / 8; /* to store header,n */ +} + +size_t FSPRG_stateinbytes(unsigned _secpar) { + VALIDATE_SECPAR(_secpar); + return 2 + 2 * _secpar / 8 + 8; /* to store header,n,x,epoch */ +} + +static void store_secpar(void *buf, uint16_t secpar) { + secpar = secpar / 16 - 1; + ((uint8_t*) buf)[0] = (secpar >> 8) & 0xff; + ((uint8_t*) buf)[1] = (secpar >> 0) & 0xff; +} + +static uint16_t read_secpar(const void *buf) { + uint16_t secpar; + secpar = + (uint16_t)(((uint8_t*) buf)[0]) << 8 | + (uint16_t)(((uint8_t*) buf)[1]) << 0; + return 16 * (secpar + 1); +} + +void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned _secpar) { + uint8_t iseed[FSPRG_RECOMMENDED_SEEDLEN]; + gcry_mpi_t n, p, q; + uint16_t secpar; + + VALIDATE_SECPAR(_secpar); + secpar = _secpar; + + initialize_libgcrypt(); + + if (!seed) { + gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM); + seed = iseed; + seedlen = FSPRG_RECOMMENDED_SEEDLEN; + } + + p = genprime3mod4(secpar / 2, seed, seedlen, RND_GEN_P); + q = genprime3mod4(secpar / 2, seed, seedlen, RND_GEN_Q); + + if (msk) { + store_secpar(msk + 0, secpar); + mpi_export(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8, p); + mpi_export(msk + 2 + 1 * (secpar / 2) / 8, (secpar / 2) / 8, q); + } + + if (mpk) { + n = gcry_mpi_new(0); + gcry_mpi_mul(n, p, q); + assert(gcry_mpi_get_nbits(n) == secpar); + + store_secpar(mpk + 0, secpar); + mpi_export(mpk + 2, secpar / 8, n); + + gcry_mpi_release(n); + } + + gcry_mpi_release(p); + gcry_mpi_release(q); +} + +void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen) { + gcry_mpi_t n, x; + uint16_t secpar; + + initialize_libgcrypt(); + + secpar = read_secpar(mpk + 0); + n = mpi_import(mpk + 2, secpar / 8); + x = gensquare(n, seed, seedlen, RND_GEN_X, secpar); + + memcpy(state, mpk, 2 + secpar / 8); + mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x); + memzero(state + 2 + 2 * secpar / 8, 8); + + gcry_mpi_release(n); + gcry_mpi_release(x); +} + +void FSPRG_Evolve(void *state) { + gcry_mpi_t n, x; + uint16_t secpar; + uint64_t epoch; + + initialize_libgcrypt(); + + secpar = read_secpar(state + 0); + n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8); + x = mpi_import(state + 2 + 1 * secpar / 8, secpar / 8); + epoch = uint64_import(state + 2 + 2 * secpar / 8, 8); + + gcry_mpi_mulm(x, x, x, n); + epoch++; + + mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x); + uint64_export(state + 2 + 2 * secpar / 8, 8, epoch); + + gcry_mpi_release(n); + gcry_mpi_release(x); +} + +uint64_t FSPRG_GetEpoch(const void *state) { + uint16_t secpar; + secpar = read_secpar(state + 0); + return uint64_import(state + 2 + 2 * secpar / 8, 8); +} + +void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen) { + gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm; + uint16_t secpar; + + initialize_libgcrypt(); + + secpar = read_secpar(msk + 0); + p = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8); + q = mpi_import(msk + 2 + 1 * (secpar / 2) / 8, (secpar / 2) / 8); + + n = gcry_mpi_new(0); + gcry_mpi_mul(n, p, q); + + x = gensquare(n, seed, seedlen, RND_GEN_X, secpar); + CRT_decompose(&xp, &xq, x, p, q); /* split (mod n) into (mod p) and (mod q) using CRT */ + + kp = twopowmodphi(epoch, p); /* compute 2^epoch (mod phi(p)) */ + kq = twopowmodphi(epoch, q); /* compute 2^epoch (mod phi(q)) */ + + gcry_mpi_powm(xp, xp, kp, p); /* compute x^(2^epoch) (mod p) */ + gcry_mpi_powm(xq, xq, kq, q); /* compute x^(2^epoch) (mod q) */ + + CRT_compose(&xm, xp, xq, p, q); /* combine (mod p) and (mod q) to (mod n) using CRT */ + + store_secpar(state + 0, secpar); + mpi_export(state + 2 + 0 * secpar / 8, secpar / 8, n); + mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, xm); + uint64_export(state + 2 + 2 * secpar / 8, 8, epoch); + + gcry_mpi_release(p); + gcry_mpi_release(q); + gcry_mpi_release(n); + gcry_mpi_release(x); + gcry_mpi_release(xp); + gcry_mpi_release(xq); + gcry_mpi_release(kp); + gcry_mpi_release(kq); + gcry_mpi_release(xm); +} + +void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) { + uint16_t secpar; + + initialize_libgcrypt(); + + secpar = read_secpar(state + 0); + det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx); +} diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h new file mode 100644 index 0000000..150d034 --- /dev/null +++ b/src/journal/fsprg.h @@ -0,0 +1,66 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef __fsprgh__ +#define __fsprgh__ + +/* + * fsprg v0.1 - (seekable) forward-secure pseudorandom generator + * Copyright (C) 2012 B. Poettering + * Contact: fsprg@point-at-infinity.org + * + * This library 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. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "macro.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FSPRG_RECOMMENDED_SECPAR 1536 +#define FSPRG_RECOMMENDED_SEEDLEN (96/8) + +size_t FSPRG_mskinbytes(unsigned secpar) _const_; +size_t FSPRG_mpkinbytes(unsigned secpar) _const_; +size_t FSPRG_stateinbytes(unsigned secpar) _const_; + +/* Setup msk and mpk. Providing seed != NULL makes this algorithm deterministic. */ +void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned secpar); + +/* Initialize state deterministically in dependence on seed. */ +/* Note: in case one wants to run only one GenState0 per GenMK it is safe to use + the same seed for both GenMK and GenState0. +*/ +void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen); + +void FSPRG_Evolve(void *state); + +uint64_t FSPRG_GetEpoch(const void *state) _pure_; + +/* Seek to any arbitrary state (by providing msk together with seed from GenState0). */ +void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen); + +void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c new file mode 100644 index 0000000..f416b79 --- /dev/null +++ b/src/journal/journal-authenticate.c @@ -0,0 +1,563 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "journal-def.h" +#include "journal-file.h" +#include "journal-authenticate.h" +#include "fsprg.h" + +static uint64_t journal_file_tag_seqnum(JournalFile *f) { + uint64_t r; + + assert(f); + + r = le64toh(f->header->n_tags) + 1; + f->header->n_tags = htole64(r); + + return r; +} + +int journal_file_append_tag(JournalFile *f) { + Object *o; + uint64_t p; + int r; + + assert(f); + + if (!f->seal) + return 0; + + if (!f->hmac_running) + return 0; + + assert(f->hmac); + + r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p); + if (r < 0) + return r; + + o->tag.seqnum = htole64(journal_file_tag_seqnum(f)); + o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state)); + + log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"", + le64toh(o->tag.seqnum), + FSPRG_GetEpoch(f->fsprg_state)); + + /* Add the tag object itself, so that we can protect its + * header. This will exclude the actual hash value in it */ + r = journal_file_hmac_put_object(f, OBJECT_TAG, o, p); + if (r < 0) + return r; + + /* Get the HMAC tag and store it in the object */ + memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH); + f->hmac_running = false; + + return 0; +} + +int journal_file_hmac_start(JournalFile *f) { + uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */ + assert(f); + + if (!f->seal) + return 0; + + if (f->hmac_running) + return 0; + + /* Prepare HMAC for next cycle */ + gcry_md_reset(f->hmac); + FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0); + gcry_md_setkey(f->hmac, key, sizeof(key)); + + f->hmac_running = true; + + return 0; +} + +static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) { + uint64_t t; + + assert(f); + assert(epoch); + assert(f->seal); + + if (f->fss_start_usec == 0 || + f->fss_interval_usec == 0) + return -ENOTSUP; + + if (realtime < f->fss_start_usec) + return -ESTALE; + + t = realtime - f->fss_start_usec; + t = t / f->fss_interval_usec; + + *epoch = t; + return 0; +} + +static int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) { + uint64_t goal, epoch; + int r; + assert(f); + + if (!f->seal) + return 0; + + r = journal_file_get_epoch(f, realtime, &goal); + if (r < 0) + return r; + + epoch = FSPRG_GetEpoch(f->fsprg_state); + if (epoch > goal) + return -ESTALE; + + return epoch != goal; +} + +int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) { + uint64_t goal, epoch; + int r; + + assert(f); + + if (!f->seal) + return 0; + + r = journal_file_get_epoch(f, realtime, &goal); + if (r < 0) + return r; + + epoch = FSPRG_GetEpoch(f->fsprg_state); + if (epoch < goal) + log_debug("Evolving FSPRG key from epoch %"PRIu64" to %"PRIu64".", epoch, goal); + + for (;;) { + if (epoch > goal) + return -ESTALE; + if (epoch == goal) + return 0; + + FSPRG_Evolve(f->fsprg_state); + epoch = FSPRG_GetEpoch(f->fsprg_state); + } +} + +int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) { + void *msk; + uint64_t epoch; + + assert(f); + + if (!f->seal) + return 0; + + assert(f->fsprg_seed); + + if (f->fsprg_state) { + /* Cheaper... */ + + epoch = FSPRG_GetEpoch(f->fsprg_state); + if (goal == epoch) + return 0; + + if (goal == epoch+1) { + FSPRG_Evolve(f->fsprg_state); + return 0; + } + } else { + f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR); + f->fsprg_state = malloc(f->fsprg_state_size); + + if (!f->fsprg_state) + return -ENOMEM; + } + + log_debug("Seeking FSPRG key to %"PRIu64".", goal); + + msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR)); + FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR); + FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size); + return 0; +} + +int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { + int r; + + assert(f); + + if (!f->seal) + return 0; + + if (realtime <= 0) + realtime = now(CLOCK_REALTIME); + + r = journal_file_fsprg_need_evolve(f, realtime); + if (r <= 0) + return 0; + + r = journal_file_append_tag(f); + if (r < 0) + return r; + + r = journal_file_fsprg_evolve(f, realtime); + if (r < 0) + return r; + + return 0; +} + +int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) { + int r; + + assert(f); + + if (!f->seal) + return 0; + + r = journal_file_hmac_start(f); + if (r < 0) + return r; + + if (!o) { + r = journal_file_move_to_object(f, type, p, &o); + if (r < 0) + return r; + } else { + if (type >= 0 && o->object.type != type) + return -EBADMSG; + } + + gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload)); + + switch (o->object.type) { + + case OBJECT_DATA: + /* All but hash and payload are mutable */ + gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash)); + gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload)); + break; + + case OBJECT_FIELD: + /* Same here */ + gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash)); + gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(FieldObject, payload)); + break; + + case OBJECT_ENTRY: + /* All */ + gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum)); + break; + + case OBJECT_FIELD_HASH_TABLE: + case OBJECT_DATA_HASH_TABLE: + case OBJECT_ENTRY_ARRAY: + /* Nothing: everything is mutable */ + break; + + case OBJECT_TAG: + /* All but the tag itself */ + gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum)); + gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch)); + break; + default: + return -EINVAL; + } + + return 0; +} + +int journal_file_hmac_put_header(JournalFile *f) { + int r; + + assert(f); + + if (!f->seal) + return 0; + + r = journal_file_hmac_start(f); + if (r < 0) + return r; + + /* All but state+reserved, boot_id, arena_size, + * tail_object_offset, n_objects, n_entries, + * tail_entry_seqnum, head_entry_seqnum, entry_array_offset, + * head_entry_realtime, tail_entry_realtime, + * tail_entry_monotonic, n_data, n_fields, n_tags, + * n_entry_arrays. */ + + gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature)); + gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id)); + gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id)); + gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset)); + + return 0; +} + +int journal_file_fss_load(JournalFile *f) { + int r, fd = -1; + char *p = NULL; + struct stat st; + FSSHeader *m = NULL; + sd_id128_t machine; + + assert(f); + + if (!f->seal) + return 0; + + r = sd_id128_get_machine(&machine); + if (r < 0) + return r; + + if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss", + SD_ID128_FORMAT_VAL(machine)) < 0) + return -ENOMEM; + + fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); + if (fd < 0) { + if (errno != ENOENT) + log_error("Failed to open %s: %m", p); + + r = -errno; + goto finish; + } + + if (fstat(fd, &st) < 0) { + r = -errno; + goto finish; + } + + if (st.st_size < (off_t) sizeof(FSSHeader)) { + r = -ENODATA; + goto finish; + } + + m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0); + if (m == MAP_FAILED) { + m = NULL; + r = -errno; + goto finish; + } + + if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) { + r = -EBADMSG; + goto finish; + } + + if (m->incompatible_flags != 0) { + r = -EPROTONOSUPPORT; + goto finish; + } + + if (le64toh(m->header_size) < sizeof(FSSHeader)) { + r = -EBADMSG; + goto finish; + } + + if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) { + r = -EBADMSG; + goto finish; + } + + f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size); + if ((uint64_t) st.st_size < f->fss_file_size) { + r = -ENODATA; + goto finish; + } + + if (!sd_id128_equal(machine, m->machine_id)) { + r = -EHOSTDOWN; + goto finish; + } + + if (le64toh(m->start_usec) <= 0 || + le64toh(m->interval_usec) <= 0) { + r = -EBADMSG; + goto finish; + } + + f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (f->fss_file == MAP_FAILED) { + f->fss_file = NULL; + r = -errno; + goto finish; + } + + f->fss_start_usec = le64toh(f->fss_file->start_usec); + f->fss_interval_usec = le64toh(f->fss_file->interval_usec); + + f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size); + f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size); + + r = 0; + +finish: + if (m) + munmap(m, PAGE_ALIGN(sizeof(FSSHeader))); + + if (fd >= 0) + close_nointr_nofail(fd); + + free(p); + return r; +} + +static void initialize_libgcrypt(void) { + const char *p; + + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +int journal_file_hmac_setup(JournalFile *f) { + gcry_error_t e; + + if (!f->seal) + return 0; + + initialize_libgcrypt(); + + e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (e != 0) + return -ENOTSUP; + + return 0; +} + +int journal_file_append_first_tag(JournalFile *f) { + int r; + uint64_t p; + + if (!f->seal) + return 0; + + log_debug("Calculating first tag..."); + + r = journal_file_hmac_put_header(f); + if (r < 0) + return r; + + p = le64toh(f->header->field_hash_table_offset); + if (p < offsetof(Object, hash_table.items)) + return -EINVAL; + p -= offsetof(Object, hash_table.items); + + r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, NULL, p); + if (r < 0) + return r; + + p = le64toh(f->header->data_hash_table_offset); + if (p < offsetof(Object, hash_table.items)) + return -EINVAL; + p -= offsetof(Object, hash_table.items); + + r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, NULL, p); + if (r < 0) + return r; + + r = journal_file_append_tag(f); + if (r < 0) + return r; + + return 0; +} + +int journal_file_parse_verification_key(JournalFile *f, const char *key) { + uint8_t *seed; + size_t seed_size, c; + const char *k; + int r; + unsigned long long start, interval; + + seed_size = FSPRG_RECOMMENDED_SEEDLEN; + seed = malloc(seed_size); + if (!seed) + return -ENOMEM; + + k = key; + for (c = 0; c < seed_size; c++) { + int x, y; + + while (*k == '-') + k++; + + x = unhexchar(*k); + if (x < 0) { + free(seed); + return -EINVAL; + } + k++; + y = unhexchar(*k); + if (y < 0) { + free(seed); + return -EINVAL; + } + k++; + + seed[c] = (uint8_t) (x * 16 + y); + } + + if (*k != '/') { + free(seed); + return -EINVAL; + } + k++; + + r = sscanf(k, "%llx-%llx", &start, &interval); + if (r != 2) { + free(seed); + return -EINVAL; + } + + f->fsprg_seed = seed; + f->fsprg_seed_size = seed_size; + + f->fss_start_usec = start * interval; + f->fss_interval_usec = interval; + + return 0; +} + +bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) { + uint64_t epoch; + + assert(f); + assert(u); + + if (!f->seal) + return false; + + epoch = FSPRG_GetEpoch(f->fsprg_state); + + *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec); + + return true; +} diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h new file mode 100644 index 0000000..0aaf836 --- /dev/null +++ b/src/journal/journal-authenticate.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "journal-file.h" + +int journal_file_append_tag(JournalFile *f); +int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime); +int journal_file_append_first_tag(JournalFile *f); + +int journal_file_hmac_setup(JournalFile *f); +int journal_file_hmac_start(JournalFile *f); +int journal_file_hmac_put_header(JournalFile *f); +int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p); + +int journal_file_fss_load(JournalFile *f); +int journal_file_parse_verification_key(JournalFile *f, const char *key); + +int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime); +int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); + +bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u); diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h new file mode 100644 index 0000000..7e407a4 --- /dev/null +++ b/src/journal/journal-def.h @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sparse-endian.h" + +#include + +#include "macro.h" + +/* + * If you change this file you probably should also change its documentation: + * + * http://www.freedesktop.org/wiki/Software/systemd/journal-files + * + */ + +typedef struct Header Header; + +typedef struct ObjectHeader ObjectHeader; +typedef union Object Object; + +typedef struct DataObject DataObject; +typedef struct FieldObject FieldObject; +typedef struct EntryObject EntryObject; +typedef struct HashTableObject HashTableObject; +typedef struct EntryArrayObject EntryArrayObject; +typedef struct TagObject TagObject; + +typedef struct EntryItem EntryItem; +typedef struct HashItem HashItem; + +typedef struct FSSHeader FSSHeader; + +/* Object types */ +enum { + OBJECT_UNUSED, + OBJECT_DATA, + OBJECT_FIELD, + OBJECT_ENTRY, + OBJECT_DATA_HASH_TABLE, + OBJECT_FIELD_HASH_TABLE, + OBJECT_ENTRY_ARRAY, + OBJECT_TAG, + _OBJECT_TYPE_MAX +}; + +/* Object flags */ +enum { + OBJECT_COMPRESSED = 1 +}; + +struct ObjectHeader { + uint8_t type; + uint8_t flags; + uint8_t reserved[6]; + le64_t size; + uint8_t payload[]; +} _packed_; + +struct DataObject { + ObjectHeader object; + le64_t hash; + le64_t next_hash_offset; + le64_t next_field_offset; + le64_t entry_offset; /* the first array entry we store inline */ + le64_t entry_array_offset; + le64_t n_entries; + uint8_t payload[]; +} _packed_; + +struct FieldObject { + ObjectHeader object; + le64_t hash; + le64_t next_hash_offset; + le64_t head_data_offset; + uint8_t payload[]; +} _packed_; + +struct EntryItem { + le64_t object_offset; + le64_t hash; +} _packed_; + +struct EntryObject { + ObjectHeader object; + le64_t seqnum; + le64_t realtime; + le64_t monotonic; + sd_id128_t boot_id; + le64_t xor_hash; + EntryItem items[]; +} _packed_; + +struct HashItem { + le64_t head_hash_offset; + le64_t tail_hash_offset; +} _packed_; + +struct HashTableObject { + ObjectHeader object; + HashItem items[]; +} _packed_; + +struct EntryArrayObject { + ObjectHeader object; + le64_t next_entry_array_offset; + le64_t items[]; +} _packed_; + +#define TAG_LENGTH (256/8) + +struct TagObject { + ObjectHeader object; + le64_t seqnum; + le64_t epoch; + uint8_t tag[TAG_LENGTH]; /* SHA-256 HMAC */ +} _packed_; + +union Object { + ObjectHeader object; + DataObject data; + FieldObject field; + EntryObject entry; + HashTableObject hash_table; + EntryArrayObject entry_array; + TagObject tag; +}; + +enum { + STATE_OFFLINE = 0, + STATE_ONLINE = 1, + STATE_ARCHIVED = 2, + _STATE_MAX +}; + +/* Header flags */ +enum { + HEADER_INCOMPATIBLE_COMPRESSED = 1 +}; + +enum { + HEADER_COMPATIBLE_SEALED = 1 +}; + +#define HEADER_SIGNATURE ((char[]) { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' }) + +struct Header { + uint8_t signature[8]; /* "LPKSHHRH" */ + le32_t compatible_flags; + le32_t incompatible_flags; + uint8_t state; + uint8_t reserved[7]; + sd_id128_t file_id; + sd_id128_t machine_id; + sd_id128_t boot_id; /* last writer */ + sd_id128_t seqnum_id; + le64_t header_size; + le64_t arena_size; + le64_t data_hash_table_offset; + le64_t data_hash_table_size; + le64_t field_hash_table_offset; + le64_t field_hash_table_size; + le64_t tail_object_offset; + le64_t n_objects; + le64_t n_entries; + le64_t tail_entry_seqnum; + le64_t head_entry_seqnum; + le64_t entry_array_offset; + le64_t head_entry_realtime; + le64_t tail_entry_realtime; + le64_t tail_entry_monotonic; + /* Added in 187 */ + le64_t n_data; + le64_t n_fields; + /* Added in 189 */ + le64_t n_tags; + le64_t n_entry_arrays; + + /* Size: 224 */ +} _packed_; + +#define FSS_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }) + +struct FSSHeader { + uint8_t signature[8]; /* "KSHHRHLP" */ + le32_t compatible_flags; + le32_t incompatible_flags; + sd_id128_t machine_id; + sd_id128_t boot_id; /* last writer */ + le64_t header_size; + le64_t start_usec; + le64_t interval_usec; + le16_t fsprg_secpar; + le16_t reserved[3]; + le64_t fsprg_state_size; +} _packed_; diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c new file mode 100644 index 0000000..a2cc697 --- /dev/null +++ b/src/journal/journal-file.c @@ -0,0 +1,2991 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_XATTR +#include +#endif + +#include "journal-def.h" +#include "journal-file.h" +#include "journal-authenticate.h" +#include "lookup3.h" +#include "compress.h" +#include "fsprg.h" + +#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem)) +#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem)) + +#define COMPRESSION_SIZE_THRESHOLD (512ULL) + +/* This is the minimum journal file size */ +#ifdef CONFIG_TIZEN +#define JOURNAL_FILE_SIZE_MIN (512ULL*1024ULL) /* 512 KiB */ +#else +#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL) /* 4 MiB */ +#endif + +/* These are the lower and upper bounds if we deduce the max_use value + * from the file system size */ +#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */ +#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ + +/* This is the upper bound if we deduce max_size from max_use */ +#define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */ + +/* This is the upper bound if we deduce the keep_free value from the + * file system size */ +#define DEFAULT_KEEP_FREE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ + +/* This is the keep_free value when we can't determine the system + * size */ +#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */ + +/* n_data was the first entry we added after the initial file format design */ +#define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data)) + +/* How many entries to keep in the entry array chain cache at max */ +#define CHAIN_CACHE_MAX 20 + +/* How much to increase the journal file size at once each time we allocate something new. */ +#ifdef CONFIG_TIZEN +#define FILE_SIZE_INCREASE (JOURNAL_FILE_SIZE_MIN) +#else +#define FILE_SIZE_INCREASE (8ULL*1024ULL*1024ULL) /* 8MB */ +#endif + +static int journal_file_set_online(JournalFile *f) { + assert(f); + + if (!f->writable) + return -EPERM; + + if (!(f->fd >= 0 && f->header)) + return -EINVAL; + + switch(f->header->state) { + case STATE_ONLINE: + return 0; + + case STATE_OFFLINE: + f->header->state = STATE_ONLINE; + fsync(f->fd); + return 0; + + default: + return -EINVAL; + } +} + +int journal_file_set_offline(JournalFile *f) { + assert(f); + + if (!f->writable) + return -EPERM; + + if (!(f->fd >= 0 && f->header)) + return -EINVAL; + + if (f->header->state != STATE_ONLINE) + return 0; + + fsync(f->fd); + + f->header->state = STATE_OFFLINE; + + fsync(f->fd); + + return 0; +} + +void journal_file_close(JournalFile *f) { + assert(f); + +#ifdef HAVE_GCRYPT + /* Write the final tag */ + if (f->seal && f->writable) + journal_file_append_tag(f); +#endif + + /* Sync everything to disk, before we mark the file offline */ + if (f->mmap && f->fd >= 0) + mmap_cache_close_fd(f->mmap, f->fd); + + journal_file_set_offline(f); + + if (f->header) + munmap(f->header, PAGE_ALIGN(sizeof(Header))); + + if (f->fd >= 0) + close_nointr_nofail(f->fd); + + free(f->path); + + if (f->mmap) + mmap_cache_unref(f->mmap); + + hashmap_free_free(f->chain_cache); + +#ifdef HAVE_XZ + free(f->compress_buffer); +#endif + +#ifdef HAVE_GCRYPT + if (f->fss_file) + munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size)); + else if (f->fsprg_state) + free(f->fsprg_state); + + free(f->fsprg_seed); + + if (f->hmac) + gcry_md_close(f->hmac); +#endif + + free(f); +} + +static int journal_file_init_header(JournalFile *f, JournalFile *template) { + Header h; + ssize_t k; + int r; + + assert(f); + + zero(h); + memcpy(h.signature, HEADER_SIGNATURE, 8); + h.header_size = htole64(ALIGN64(sizeof(h))); + + h.incompatible_flags = + htole32(f->compress ? HEADER_INCOMPATIBLE_COMPRESSED : 0); + + h.compatible_flags = + htole32(f->seal ? HEADER_COMPATIBLE_SEALED : 0); + + r = sd_id128_randomize(&h.file_id); + if (r < 0) + return r; + + if (template) { + h.seqnum_id = template->header->seqnum_id; + h.tail_entry_seqnum = template->header->tail_entry_seqnum; + } else + h.seqnum_id = h.file_id; + + k = pwrite(f->fd, &h, sizeof(h), 0); + if (k < 0) + return -errno; + + if (k != sizeof(h)) + return -EIO; + + return 0; +} + +static int journal_file_refresh_header(JournalFile *f) { + int r; + sd_id128_t boot_id; + + assert(f); + + r = sd_id128_get_machine(&f->header->machine_id); + if (r < 0) + return r; + + r = sd_id128_get_boot(&boot_id); + if (r < 0) + return r; + + if (sd_id128_equal(boot_id, f->header->boot_id)) + f->tail_entry_monotonic_valid = true; + + f->header->boot_id = boot_id; + + journal_file_set_online(f); + + /* Sync the online state to disk */ + fsync(f->fd); + + return 0; +} + +static int journal_file_verify_header(JournalFile *f) { + assert(f); + + if (memcmp(f->header->signature, HEADER_SIGNATURE, 8)) + return -EBADMSG; + + /* In both read and write mode we refuse to open files with + * incompatible flags we don't know */ +#ifdef HAVE_XZ + if ((le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) != 0) + return -EPROTONOSUPPORT; +#else + if (f->header->incompatible_flags != 0) + return -EPROTONOSUPPORT; +#endif + + /* When open for writing we refuse to open files with + * compatible flags, too */ + if (f->writable) { +#ifdef HAVE_GCRYPT + if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0) + return -EPROTONOSUPPORT; +#else + if (f->header->compatible_flags != 0) + return -EPROTONOSUPPORT; +#endif + } + + if (f->header->state >= _STATE_MAX) + return -EBADMSG; + + /* The first addition was n_data, so check that we are at least this large */ + if (le64toh(f->header->header_size) < HEADER_SIZE_MIN) + return -EBADMSG; + + if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays)) + return -EBADMSG; + + if ((le64toh(f->header->header_size) + le64toh(f->header->arena_size)) > (uint64_t) f->last_stat.st_size) + return -ENODATA; + + if (le64toh(f->header->tail_object_offset) > (le64toh(f->header->header_size) + le64toh(f->header->arena_size))) + return -ENODATA; + + if (!VALID64(le64toh(f->header->data_hash_table_offset)) || + !VALID64(le64toh(f->header->field_hash_table_offset)) || + !VALID64(le64toh(f->header->tail_object_offset)) || + !VALID64(le64toh(f->header->entry_array_offset))) + return -ENODATA; + + if (le64toh(f->header->data_hash_table_offset) < le64toh(f->header->header_size) || + le64toh(f->header->field_hash_table_offset) < le64toh(f->header->header_size) || + le64toh(f->header->tail_object_offset) < le64toh(f->header->header_size) || + le64toh(f->header->entry_array_offset) < le64toh(f->header->header_size)) + return -ENODATA; + + if (f->writable) { + uint8_t state; + sd_id128_t machine_id; + int r; + + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + if (!sd_id128_equal(machine_id, f->header->machine_id)) + return -EHOSTDOWN; + + state = f->header->state; + + if (state == STATE_ONLINE) { + log_debug("Journal file %s is already online. Assuming unclean closing.", f->path); + return -EBUSY; + } else if (state == STATE_ARCHIVED) + return -ESHUTDOWN; + else if (state != STATE_OFFLINE) { + log_debug("Journal file %s has unknown state %u.", f->path, state); + return -EBUSY; + } + } + + f->compress = JOURNAL_HEADER_COMPRESSED(f->header); + + f->seal = JOURNAL_HEADER_SEALED(f->header); + + return 0; +} + +static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) { + uint64_t old_size, new_size; + int r; + + assert(f); + + /* We assume that this file is not sparse, and we know that + * for sure, since we always call posix_fallocate() + * ourselves */ + + old_size = + le64toh(f->header->header_size) + + le64toh(f->header->arena_size); + + new_size = PAGE_ALIGN(offset + size); + if (new_size < le64toh(f->header->header_size)) + new_size = le64toh(f->header->header_size); + + if (new_size <= old_size) + return 0; + + if (f->metrics.max_size > 0 && new_size > f->metrics.max_size) + return -E2BIG; + + if (new_size > f->metrics.min_size && f->metrics.keep_free > 0) { + struct statvfs svfs; + + if (fstatvfs(f->fd, &svfs) >= 0) { + uint64_t available; + + available = svfs.f_bfree * svfs.f_bsize; + + if (available >= f->metrics.keep_free) + available -= f->metrics.keep_free; + else + available = 0; + + if (new_size - old_size > available) + return -E2BIG; + } + } + + /* Increase by larger blocks at once */ + new_size = ((new_size+FILE_SIZE_INCREASE-1) / FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE; + if (f->metrics.max_size > 0 && new_size > f->metrics.max_size) + new_size = f->metrics.max_size; + + /* Note that the glibc fallocate() fallback is very + inefficient, hence we try to minimize the allocation area + as we can. */ + r = posix_fallocate(f->fd, old_size, new_size - old_size); + if (r != 0) + return -r; + + if (fstat(f->fd, &f->last_stat) < 0) + return -errno; + + f->header->arena_size = htole64(new_size - le64toh(f->header->header_size)); + + return 0; +} + +static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) { + assert(f); + assert(ret); + + if (size <= 0) + return -EINVAL; + + /* Avoid SIGBUS on invalid accesses */ + if (offset + size > (uint64_t) f->last_stat.st_size) { + /* Hmm, out of range? Let's refresh the fstat() data + * first, before we trust that check. */ + + if (fstat(f->fd, &f->last_stat) < 0 || + offset + size > (uint64_t) f->last_stat.st_size) + return -EADDRNOTAVAIL; + } + + return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret); +} + +static uint64_t minimum_header_size(Object *o) { + + static const uint64_t table[] = { + [OBJECT_DATA] = sizeof(DataObject), + [OBJECT_FIELD] = sizeof(FieldObject), + [OBJECT_ENTRY] = sizeof(EntryObject), + [OBJECT_DATA_HASH_TABLE] = sizeof(HashTableObject), + [OBJECT_FIELD_HASH_TABLE] = sizeof(HashTableObject), + [OBJECT_ENTRY_ARRAY] = sizeof(EntryArrayObject), + [OBJECT_TAG] = sizeof(TagObject), + }; + + if (o->object.type >= ELEMENTSOF(table) || table[o->object.type] <= 0) + return sizeof(ObjectHeader); + + return table[o->object.type]; +} + +int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) { + int r; + void *t; + Object *o; + uint64_t s; + + assert(f); + assert(ret); + + /* Objects may only be located at multiple of 64 bit */ + if (!VALID64(offset)) + return -EFAULT; + + + r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t); + if (r < 0) + return r; + + o = (Object*) t; + s = le64toh(o->object.size); + + if (s < sizeof(ObjectHeader)) + return -EBADMSG; + + if (o->object.type <= OBJECT_UNUSED) + return -EBADMSG; + + if (s < minimum_header_size(o)) + return -EBADMSG; + + if (type > 0 && o->object.type != type) + return -EBADMSG; + + if (s > sizeof(ObjectHeader)) { + r = journal_file_move_to(f, o->object.type, false, offset, s, &t); + if (r < 0) + return r; + + o = (Object*) t; + } + + *ret = o; + return 0; +} + +static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { + uint64_t r; + + assert(f); + + r = le64toh(f->header->tail_entry_seqnum) + 1; + + if (seqnum) { + /* If an external seqnum counter was passed, we update + * both the local and the external one, and set it to + * the maximum of both */ + + if (*seqnum + 1 > r) + r = *seqnum + 1; + + *seqnum = r; + } + + f->header->tail_entry_seqnum = htole64(r); + + if (f->header->head_entry_seqnum == 0) + f->header->head_entry_seqnum = htole64(r); + + return r; +} + +int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) { + int r; + uint64_t p; + Object *tail, *o; + void *t; + + assert(f); + assert(type > 0 && type < _OBJECT_TYPE_MAX); + assert(size >= sizeof(ObjectHeader)); + assert(offset); + assert(ret); + + r = journal_file_set_online(f); + if (r < 0) + return r; + + p = le64toh(f->header->tail_object_offset); + if (p == 0) + p = le64toh(f->header->header_size); + else { + r = journal_file_move_to_object(f, -1, p, &tail); + if (r < 0) + return r; + + p += ALIGN64(le64toh(tail->object.size)); + } + + r = journal_file_allocate(f, p, size); + if (r < 0) + return r; + + r = journal_file_move_to(f, type, false, p, size, &t); + if (r < 0) + return r; + + o = (Object*) t; + + zero(o->object); + o->object.type = type; + o->object.size = htole64(size); + + f->header->tail_object_offset = htole64(p); + f->header->n_objects = htole64(le64toh(f->header->n_objects) + 1); + + *ret = o; + *offset = p; + + return 0; +} + +static int journal_file_setup_data_hash_table(JournalFile *f) { + uint64_t s, p; + Object *o; + int r; + + assert(f); + + /* We estimate that we need 1 hash table entry per 768 of + journal file and we want to make sure we never get beyond + 75% fill level. Calculate the hash table size for the + maximum file size based on these metrics. */ + + s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem); + if (s < DEFAULT_DATA_HASH_TABLE_SIZE) + s = DEFAULT_DATA_HASH_TABLE_SIZE; + + log_debug("Reserving %"PRIu64" entries in hash table.", s / sizeof(HashItem)); + + r = journal_file_append_object(f, + OBJECT_DATA_HASH_TABLE, + offsetof(Object, hash_table.items) + s, + &o, &p); + if (r < 0) + return r; + + memzero(o->hash_table.items, s); + + f->header->data_hash_table_offset = htole64(p + offsetof(Object, hash_table.items)); + f->header->data_hash_table_size = htole64(s); + + return 0; +} + +static int journal_file_setup_field_hash_table(JournalFile *f) { + uint64_t s, p; + Object *o; + int r; + + assert(f); + + /* We use a fixed size hash table for the fields as this + * number should grow very slowly only */ + + s = DEFAULT_FIELD_HASH_TABLE_SIZE; + r = journal_file_append_object(f, + OBJECT_FIELD_HASH_TABLE, + offsetof(Object, hash_table.items) + s, + &o, &p); + if (r < 0) + return r; + + memzero(o->hash_table.items, s); + + f->header->field_hash_table_offset = htole64(p + offsetof(Object, hash_table.items)); + f->header->field_hash_table_size = htole64(s); + + return 0; +} + +static int journal_file_map_data_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + + p = le64toh(f->header->data_hash_table_offset); + s = le64toh(f->header->data_hash_table_size); + + r = journal_file_move_to(f, + OBJECT_DATA_HASH_TABLE, + true, + p, s, + &t); + if (r < 0) + return r; + + f->data_hash_table = t; + return 0; +} + +static int journal_file_map_field_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + + p = le64toh(f->header->field_hash_table_offset); + s = le64toh(f->header->field_hash_table_size); + + r = journal_file_move_to(f, + OBJECT_FIELD_HASH_TABLE, + true, + p, s, + &t); + if (r < 0) + return r; + + f->field_hash_table = t; + return 0; +} + +static int journal_file_link_field( + JournalFile *f, + Object *o, + uint64_t offset, + uint64_t hash) { + + uint64_t p, h; + int r; + + assert(f); + assert(o); + assert(offset > 0); + + if (o->object.type != OBJECT_FIELD) + return -EINVAL; + + /* This might alter the window we are looking at */ + + o->field.next_hash_offset = o->field.head_data_offset = 0; + + h = hash % (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)); + p = le64toh(f->field_hash_table[h].tail_hash_offset); + if (p == 0) + f->field_hash_table[h].head_hash_offset = htole64(offset); + else { + r = journal_file_move_to_object(f, OBJECT_FIELD, p, &o); + if (r < 0) + return r; + + o->field.next_hash_offset = htole64(offset); + } + + f->field_hash_table[h].tail_hash_offset = htole64(offset); + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields)) + f->header->n_fields = htole64(le64toh(f->header->n_fields) + 1); + + return 0; +} + +static int journal_file_link_data( + JournalFile *f, + Object *o, + uint64_t offset, + uint64_t hash) { + + uint64_t p, h; + int r; + + assert(f); + assert(o); + assert(offset > 0); + + if (o->object.type != OBJECT_DATA) + return -EINVAL; + + /* This might alter the window we are looking at */ + + o->data.next_hash_offset = o->data.next_field_offset = 0; + o->data.entry_offset = o->data.entry_array_offset = 0; + o->data.n_entries = 0; + + h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)); + p = le64toh(f->data_hash_table[h].tail_hash_offset); + if (p == 0) + /* Only entry in the hash table is easy */ + f->data_hash_table[h].head_hash_offset = htole64(offset); + else { + /* Move back to the previous data object, to patch in + * pointer */ + + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + o->data.next_hash_offset = htole64(offset); + } + + f->data_hash_table[h].tail_hash_offset = htole64(offset); + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data)) + f->header->n_data = htole64(le64toh(f->header->n_data) + 1); + + return 0; +} + +int journal_file_find_field_object_with_hash( + JournalFile *f, + const void *field, uint64_t size, uint64_t hash, + Object **ret, uint64_t *offset) { + + uint64_t p, osize, h; + int r; + + assert(f); + assert(field && size > 0); + + osize = offsetof(Object, field.payload) + size; + + if (f->header->field_hash_table_size == 0) + return -EBADMSG; + + h = hash % (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)); + p = le64toh(f->field_hash_table[h].head_hash_offset); + + while (p > 0) { + Object *o; + + r = journal_file_move_to_object(f, OBJECT_FIELD, p, &o); + if (r < 0) + return r; + + if (le64toh(o->field.hash) == hash && + le64toh(o->object.size) == osize && + memcmp(o->field.payload, field, size) == 0) { + + if (ret) + *ret = o; + if (offset) + *offset = p; + + return 1; + } + + p = le64toh(o->field.next_hash_offset); + } + + return 0; +} + +int journal_file_find_field_object( + JournalFile *f, + const void *field, uint64_t size, + Object **ret, uint64_t *offset) { + + uint64_t hash; + + assert(f); + assert(field && size > 0); + + hash = hash64(field, size); + + return journal_file_find_field_object_with_hash(f, + field, size, hash, + ret, offset); +} + +int journal_file_find_data_object_with_hash( + JournalFile *f, + const void *data, uint64_t size, uint64_t hash, + Object **ret, uint64_t *offset) { + + uint64_t p, osize, h; + int r; + + assert(f); + assert(data || size == 0); + + osize = offsetof(Object, data.payload) + size; + + if (f->header->data_hash_table_size == 0) + return -EBADMSG; + + h = hash % (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)); + p = le64toh(f->data_hash_table[h].head_hash_offset); + + while (p > 0) { + Object *o; + + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + if (le64toh(o->data.hash) != hash) + goto next; + + if (o->object.flags & OBJECT_COMPRESSED) { +#ifdef HAVE_XZ + uint64_t l, rsize; + + l = le64toh(o->object.size); + if (l <= offsetof(Object, data.payload)) + return -EBADMSG; + + l -= offsetof(Object, data.payload); + + if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, 0)) + return -EBADMSG; + + if (rsize == size && + memcmp(f->compress_buffer, data, size) == 0) { + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 1; + } +#else + return -EPROTONOSUPPORT; +#endif + + } else if (le64toh(o->object.size) == osize && + memcmp(o->data.payload, data, size) == 0) { + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 1; + } + + next: + p = le64toh(o->data.next_hash_offset); + } + + return 0; +} + +int journal_file_find_data_object( + JournalFile *f, + const void *data, uint64_t size, + Object **ret, uint64_t *offset) { + + uint64_t hash; + + assert(f); + assert(data || size == 0); + + hash = hash64(data, size); + + return journal_file_find_data_object_with_hash(f, + data, size, hash, + ret, offset); +} + +static int journal_file_append_field( + JournalFile *f, + const void *field, uint64_t size, + Object **ret, uint64_t *offset) { + + uint64_t hash, p; + uint64_t osize; + Object *o; + int r; + + assert(f); + assert(field && size > 0); + + hash = hash64(field, size); + + r = journal_file_find_field_object_with_hash(f, field, size, hash, &o, &p); + if (r < 0) + return r; + else if (r > 0) { + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 0; + } + + osize = offsetof(Object, field.payload) + size; + r = journal_file_append_object(f, OBJECT_FIELD, osize, &o, &p); + if (r < 0) + return r; + + o->field.hash = htole64(hash); + memcpy(o->field.payload, field, size); + + r = journal_file_link_field(f, o, p, hash); + if (r < 0) + return r; + + /* The linking might have altered the window, so let's + * refresh our pointer */ + r = journal_file_move_to_object(f, OBJECT_FIELD, p, &o); + if (r < 0) + return r; + +#ifdef HAVE_GCRYPT + r = journal_file_hmac_put_object(f, OBJECT_FIELD, o, p); + if (r < 0) + return r; +#endif + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 0; +} + +static int journal_file_append_data( + JournalFile *f, + const void *data, uint64_t size, + Object **ret, uint64_t *offset) { + + uint64_t hash, p; + uint64_t osize; + Object *o; + int r; + bool compressed = false; + const void *eq; + + assert(f); + assert(data || size == 0); + + hash = hash64(data, size); + + r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); + if (r < 0) + return r; + else if (r > 0) { + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 0; + } + + osize = offsetof(Object, data.payload) + size; + r = journal_file_append_object(f, OBJECT_DATA, osize, &o, &p); + if (r < 0) + return r; + + o->data.hash = htole64(hash); + +#ifdef HAVE_XZ + if (f->compress && + size >= COMPRESSION_SIZE_THRESHOLD) { + uint64_t rsize; + + compressed = compress_blob(data, size, o->data.payload, &rsize); + + if (compressed) { + o->object.size = htole64(offsetof(Object, data.payload) + rsize); + o->object.flags |= OBJECT_COMPRESSED; + + log_debug("Compressed data object %"PRIu64" -> %"PRIu64, size, rsize); + } + } +#endif + + if (!compressed && size > 0) + memcpy(o->data.payload, data, size); + + r = journal_file_link_data(f, o, p, hash); + if (r < 0) + return r; + + /* The linking might have altered the window, so let's + * refresh our pointer */ + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + if (!data) + eq = NULL; + else + eq = memchr(data, '=', size); + if (eq && eq > data) { + Object *fo = NULL; + uint64_t fp; + + /* Create field object ... */ + r = journal_file_append_field(f, data, (uint8_t*) eq - (uint8_t*) data, &fo, &fp); + if (r < 0) + return r; + + /* ... and link it in. */ + o->data.next_field_offset = fo->field.head_data_offset; + fo->field.head_data_offset = le64toh(p); + } + +#ifdef HAVE_GCRYPT + r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p); + if (r < 0) + return r; +#endif + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 0; +} + +uint64_t journal_file_entry_n_items(Object *o) { + assert(o); + + if (o->object.type != OBJECT_ENTRY) + return 0; + + return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem); +} + +uint64_t journal_file_entry_array_n_items(Object *o) { + assert(o); + + if (o->object.type != OBJECT_ENTRY_ARRAY) + return 0; + + return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t); +} + +uint64_t journal_file_hash_table_n_items(Object *o) { + assert(o); + + if (o->object.type != OBJECT_DATA_HASH_TABLE && + o->object.type != OBJECT_FIELD_HASH_TABLE) + return 0; + + return (le64toh(o->object.size) - offsetof(Object, hash_table.items)) / sizeof(HashItem); +} + +static int link_entry_into_array(JournalFile *f, + le64_t *first, + le64_t *idx, + uint64_t p) { + int r; + uint64_t n = 0, ap = 0, q, i, a, hidx; + Object *o; + + assert(f); + assert(first); + assert(idx); + assert(p > 0); + + a = le64toh(*first); + i = hidx = le64toh(*idx); + while (a > 0) { + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + n = journal_file_entry_array_n_items(o); + if (i < n) { + o->entry_array.items[i] = htole64(p); + *idx = htole64(hidx + 1); + return 0; + } + + i -= n; + ap = a; + a = le64toh(o->entry_array.next_entry_array_offset); + } + + if (hidx > n) + n = (hidx+1) * 2; + else + n = n * 2; + + if (n < 4) + n = 4; + + r = journal_file_append_object(f, OBJECT_ENTRY_ARRAY, + offsetof(Object, entry_array.items) + n * sizeof(uint64_t), + &o, &q); + if (r < 0) + return r; + +#ifdef HAVE_GCRYPT + r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, o, q); + if (r < 0) + return r; +#endif + + o->entry_array.items[i] = htole64(p); + + if (ap == 0) + *first = htole64(q); + else { + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, ap, &o); + if (r < 0) + return r; + + o->entry_array.next_entry_array_offset = htole64(q); + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays)) + f->header->n_entry_arrays = htole64(le64toh(f->header->n_entry_arrays) + 1); + + *idx = htole64(hidx + 1); + + return 0; +} + +static int link_entry_into_array_plus_one(JournalFile *f, + le64_t *extra, + le64_t *first, + le64_t *idx, + uint64_t p) { + + int r; + + assert(f); + assert(extra); + assert(first); + assert(idx); + assert(p > 0); + + if (*idx == 0) + *extra = htole64(p); + else { + le64_t i; + + i = htole64(le64toh(*idx) - 1); + r = link_entry_into_array(f, first, &i, p); + if (r < 0) + return r; + } + + *idx = htole64(le64toh(*idx) + 1); + return 0; +} + +static int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) { + uint64_t p; + int r; + assert(f); + assert(o); + assert(offset > 0); + + p = le64toh(o->entry.items[i].object_offset); + if (p == 0) + return -EINVAL; + + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + return link_entry_into_array_plus_one(f, + &o->data.entry_offset, + &o->data.entry_array_offset, + &o->data.n_entries, + offset); +} + +static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) { + uint64_t n, i; + int r; + + assert(f); + assert(o); + assert(offset > 0); + + if (o->object.type != OBJECT_ENTRY) + return -EINVAL; + + __sync_synchronize(); + + /* Link up the entry itself */ + r = link_entry_into_array(f, + &f->header->entry_array_offset, + &f->header->n_entries, + offset); + if (r < 0) + return r; + + /* log_debug("=> %s seqnr=%"PRIu64" n_entries=%"PRIu64, f->path, o->entry.seqnum, f->header->n_entries); */ + + if (f->header->head_entry_realtime == 0) + f->header->head_entry_realtime = o->entry.realtime; + + f->header->tail_entry_realtime = o->entry.realtime; + f->header->tail_entry_monotonic = o->entry.monotonic; + + f->tail_entry_monotonic_valid = true; + + /* Link up the items */ + n = journal_file_entry_n_items(o); + for (i = 0; i < n; i++) { + r = journal_file_link_entry_item(f, o, offset, i); + if (r < 0) + return r; + } + + return 0; +} + +static int journal_file_append_entry_internal( + JournalFile *f, + const dual_timestamp *ts, + uint64_t xor_hash, + const EntryItem items[], unsigned n_items, + uint64_t *seqnum, + Object **ret, uint64_t *offset) { + uint64_t np; + uint64_t osize; + Object *o; + int r; + + assert(f); + assert(items || n_items == 0); + assert(ts); + + osize = offsetof(Object, entry.items) + (n_items * sizeof(EntryItem)); + + r = journal_file_append_object(f, OBJECT_ENTRY, osize, &o, &np); + if (r < 0) + return r; + + o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum)); + memcpy(o->entry.items, items, n_items * sizeof(EntryItem)); + o->entry.realtime = htole64(ts->realtime); + o->entry.monotonic = htole64(ts->monotonic); + o->entry.xor_hash = htole64(xor_hash); + o->entry.boot_id = f->header->boot_id; + +#ifdef HAVE_GCRYPT + r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np); + if (r < 0) + return r; +#endif + + r = journal_file_link_entry(f, o, np); + if (r < 0) + return r; + + if (ret) + *ret = o; + + if (offset) + *offset = np; + + return 0; +} + +void journal_file_post_change(JournalFile *f) { + assert(f); + + /* inotify() does not receive IN_MODIFY events from file + * accesses done via mmap(). After each access we hence + * trigger IN_MODIFY by truncating the journal file to its + * current size which triggers IN_MODIFY. */ + + __sync_synchronize(); + + if (ftruncate(f->fd, f->last_stat.st_size) < 0) + log_error("Failed to truncate file to its own size: %m"); +} + +static int entry_item_cmp(const void *_a, const void *_b) { + const EntryItem *a = _a, *b = _b; + + if (le64toh(a->object_offset) < le64toh(b->object_offset)) + return -1; + if (le64toh(a->object_offset) > le64toh(b->object_offset)) + return 1; + return 0; +} + +int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqnum, Object **ret, uint64_t *offset) { + unsigned i; + EntryItem *items; + int r; + uint64_t xor_hash = 0; + struct dual_timestamp _ts; + + assert(f); + assert(iovec || n_iovec == 0); + + if (!ts) { + dual_timestamp_get(&_ts); + ts = &_ts; + } + + if (f->tail_entry_monotonic_valid && + ts->monotonic < le64toh(f->header->tail_entry_monotonic)) + return -EINVAL; + +#ifdef HAVE_GCRYPT + r = journal_file_maybe_append_tag(f, ts->realtime); + if (r < 0) + return r; +#endif + + /* alloca() can't take 0, hence let's allocate at least one */ + items = alloca(sizeof(EntryItem) * MAX(1u, n_iovec)); + + for (i = 0; i < n_iovec; i++) { + uint64_t p; + Object *o; + + r = journal_file_append_data(f, iovec[i].iov_base, iovec[i].iov_len, &o, &p); + if (r < 0) + return r; + + xor_hash ^= le64toh(o->data.hash); + items[i].object_offset = htole64(p); + items[i].hash = o->data.hash; + } + + /* Order by the position on disk, in order to improve seek + * times for rotating media. */ + qsort_safe(items, n_iovec, sizeof(EntryItem), entry_item_cmp); + + r = journal_file_append_entry_internal(f, ts, xor_hash, items, n_iovec, seqnum, ret, offset); + + journal_file_post_change(f); + + return r; +} + +typedef struct ChainCacheItem { + uint64_t first; /* the array at the begin of the chain */ + uint64_t array; /* the cached array */ + uint64_t begin; /* the first item in the cached array */ + uint64_t total; /* the total number of items in all arrays before this one in the chain */ + uint64_t last_index; /* the last index we looked at, to optimize locality when bisecting */ +} ChainCacheItem; + +static void chain_cache_put( + Hashmap *h, + ChainCacheItem *ci, + uint64_t first, + uint64_t array, + uint64_t begin, + uint64_t total, + uint64_t last_index) { + + if (!ci) { + /* If the chain item to cache for this chain is the + * first one it's not worth caching anything */ + if (array == first) + return; + + if (hashmap_size(h) >= CHAIN_CACHE_MAX) + ci = hashmap_steal_first(h); + else { + ci = new(ChainCacheItem, 1); + if (!ci) + return; + } + + ci->first = first; + + if (hashmap_put(h, &ci->first, ci) < 0) { + free(ci); + return; + } + } else + assert(ci->first == first); + + ci->array = array; + ci->begin = begin; + ci->total = total; + ci->last_index = last_index; +} + +static int generic_array_get( + JournalFile *f, + uint64_t first, + uint64_t i, + Object **ret, uint64_t *offset) { + + Object *o; + uint64_t p = 0, a, t = 0; + int r; + ChainCacheItem *ci; + + assert(f); + + a = first; + + /* Try the chain cache first */ + ci = hashmap_get(f->chain_cache, &first); + if (ci && i > ci->total) { + a = ci->array; + i -= ci->total; + t = ci->total; + } + + while (a > 0) { + uint64_t k; + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + k = journal_file_entry_array_n_items(o); + if (i < k) { + p = le64toh(o->entry_array.items[i]); + goto found; + } + + i -= k; + t += k; + a = le64toh(o->entry_array.next_entry_array_offset); + } + + return 0; + +found: + /* Let's cache this item for the next invocation */ + chain_cache_put(f->chain_cache, ci, first, a, le64toh(o->entry_array.items[0]), t, i); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + return 1; +} + +static int generic_array_get_plus_one( + JournalFile *f, + uint64_t extra, + uint64_t first, + uint64_t i, + Object **ret, uint64_t *offset) { + + Object *o; + + assert(f); + + if (i == 0) { + int r; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o); + if (r < 0) + return r; + + if (ret) + *ret = o; + + if (offset) + *offset = extra; + + return 1; + } + + return generic_array_get(f, first, i-1, ret, offset); +} + +enum { + TEST_FOUND, + TEST_LEFT, + TEST_RIGHT +}; + +static int generic_array_bisect( + JournalFile *f, + uint64_t first, + uint64_t n, + uint64_t needle, + int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle), + direction_t direction, + Object **ret, + uint64_t *offset, + uint64_t *idx) { + + uint64_t a, p, t = 0, i = 0, last_p = 0, last_index = (uint64_t) -1; + bool subtract_one = false; + Object *o, *array = NULL; + int r; + ChainCacheItem *ci; + + assert(f); + assert(test_object); + + /* Start with the first array in the chain */ + a = first; + + ci = hashmap_get(f->chain_cache, &first); + if (ci && n > ci->total) { + /* Ah, we have iterated this bisection array chain + * previously! Let's see if we can skip ahead in the + * chain, as far as the last time. But we can't jump + * backwards in the chain, so let's check that + * first. */ + + r = test_object(f, ci->begin, needle); + if (r < 0) + return r; + + if (r == TEST_LEFT) { + /* OK, what we are looking for is right of the + * begin of this EntryArray, so let's jump + * straight to previously cached array in the + * chain */ + + a = ci->array; + n -= ci->total; + t = ci->total; + last_index = ci->last_index; + } + } + + while (a > 0) { + uint64_t left, right, k, lp; + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array); + if (r < 0) + return r; + + k = journal_file_entry_array_n_items(array); + right = MIN(k, n); + if (right <= 0) + return 0; + + i = right - 1; + lp = p = le64toh(array->entry_array.items[i]); + if (p <= 0) + return -EBADMSG; + + r = test_object(f, p, needle); + if (r < 0) + return r; + + if (r == TEST_FOUND) + r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT; + + if (r == TEST_RIGHT) { + left = 0; + right -= 1; + + if (last_index != (uint64_t) -1) { + assert(last_index <= right); + + /* If we cached the last index we + * looked at, let's try to not to jump + * too wildly around and see if we can + * limit the range to look at early to + * the immediate neighbors of the last + * index we looked at. */ + + if (last_index > 0) { + uint64_t x = last_index - 1; + + p = le64toh(array->entry_array.items[x]); + if (p <= 0) + return -EBADMSG; + + r = test_object(f, p, needle); + if (r < 0) + return r; + + if (r == TEST_FOUND) + r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT; + + if (r == TEST_RIGHT) + right = x; + else + left = x + 1; + } + + if (last_index < right) { + uint64_t y = last_index + 1; + + p = le64toh(array->entry_array.items[y]); + if (p <= 0) + return -EBADMSG; + + r = test_object(f, p, needle); + if (r < 0) + return r; + + if (r == TEST_FOUND) + r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT; + + if (r == TEST_RIGHT) + right = y; + else + left = y + 1; + } + } + + for (;;) { + if (left == right) { + if (direction == DIRECTION_UP) + subtract_one = true; + + i = left; + goto found; + } + + assert(left < right); + i = (left + right) / 2; + + p = le64toh(array->entry_array.items[i]); + if (p <= 0) + return -EBADMSG; + + r = test_object(f, p, needle); + if (r < 0) + return r; + + if (r == TEST_FOUND) + r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT; + + if (r == TEST_RIGHT) + right = i; + else + left = i + 1; + } + } + + if (k > n) { + if (direction == DIRECTION_UP) { + i = n; + subtract_one = true; + goto found; + } + + return 0; + } + + last_p = lp; + + n -= k; + t += k; + last_index = (uint64_t) -1; + a = le64toh(array->entry_array.next_entry_array_offset); + } + + return 0; + +found: + if (subtract_one && t == 0 && i == 0) + return 0; + + /* Let's cache this item for the next invocation */ + chain_cache_put(f->chain_cache, ci, first, a, le64toh(array->entry_array.items[0]), t, subtract_one ? (i > 0 ? i-1 : (uint64_t) -1) : i); + + if (subtract_one && i == 0) + p = last_p; + else if (subtract_one) + p = le64toh(array->entry_array.items[i-1]); + else + p = le64toh(array->entry_array.items[i]); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + if (ret) + *ret = o; + + if (offset) + *offset = p; + + if (idx) + *idx = t + i + (subtract_one ? -1 : 0); + + return 1; +} + + +static int generic_array_bisect_plus_one( + JournalFile *f, + uint64_t extra, + uint64_t first, + uint64_t n, + uint64_t needle, + int (*test_object)(JournalFile *f, uint64_t p, uint64_t needle), + direction_t direction, + Object **ret, + uint64_t *offset, + uint64_t *idx) { + + int r; + bool step_back = false; + Object *o; + + assert(f); + assert(test_object); + + if (n <= 0) + return 0; + + /* This bisects the array in object 'first', but first checks + * an extra */ + r = test_object(f, extra, needle); + if (r < 0) + return r; + + if (r == TEST_FOUND) + r = direction == DIRECTION_DOWN ? TEST_RIGHT : TEST_LEFT; + + /* if we are looking with DIRECTION_UP then we need to first + see if in the actual array there is a matching entry, and + return the last one of that. But if there isn't any we need + to return this one. Hence remember this, and return it + below. */ + if (r == TEST_LEFT) + step_back = direction == DIRECTION_UP; + + if (r == TEST_RIGHT) { + if (direction == DIRECTION_DOWN) + goto found; + else + return 0; + } + + r = generic_array_bisect(f, first, n-1, needle, test_object, direction, ret, offset, idx); + + if (r == 0 && step_back) + goto found; + + if (r > 0 && idx) + (*idx) ++; + + return r; + +found: + r = journal_file_move_to_object(f, OBJECT_ENTRY, extra, &o); + if (r < 0) + return r; + + if (ret) + *ret = o; + + if (offset) + *offset = extra; + + if (idx) + *idx = 0; + + return 1; +} + +_pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle) { + assert(f); + assert(p > 0); + + if (p == needle) + return TEST_FOUND; + else if (p < needle) + return TEST_LEFT; + else + return TEST_RIGHT; +} + +int journal_file_move_to_entry_by_offset( + JournalFile *f, + uint64_t p, + direction_t direction, + Object **ret, + uint64_t *offset) { + + return generic_array_bisect(f, + le64toh(f->header->entry_array_offset), + le64toh(f->header->n_entries), + p, + test_object_offset, + direction, + ret, offset, NULL); +} + + +static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) { + Object *o; + int r; + + assert(f); + assert(p > 0); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + if (le64toh(o->entry.seqnum) == needle) + return TEST_FOUND; + else if (le64toh(o->entry.seqnum) < needle) + return TEST_LEFT; + else + return TEST_RIGHT; +} + +int journal_file_move_to_entry_by_seqnum( + JournalFile *f, + uint64_t seqnum, + direction_t direction, + Object **ret, + uint64_t *offset) { + + return generic_array_bisect(f, + le64toh(f->header->entry_array_offset), + le64toh(f->header->n_entries), + seqnum, + test_object_seqnum, + direction, + ret, offset, NULL); +} + +static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) { + Object *o; + int r; + + assert(f); + assert(p > 0); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + if (le64toh(o->entry.realtime) == needle) + return TEST_FOUND; + else if (le64toh(o->entry.realtime) < needle) + return TEST_LEFT; + else + return TEST_RIGHT; +} + +int journal_file_move_to_entry_by_realtime( + JournalFile *f, + uint64_t realtime, + direction_t direction, + Object **ret, + uint64_t *offset) { + + return generic_array_bisect(f, + le64toh(f->header->entry_array_offset), + le64toh(f->header->n_entries), + realtime, + test_object_realtime, + direction, + ret, offset, NULL); +} + +static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) { + Object *o; + int r; + + assert(f); + assert(p > 0); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + if (le64toh(o->entry.monotonic) == needle) + return TEST_FOUND; + else if (le64toh(o->entry.monotonic) < needle) + return TEST_LEFT; + else + return TEST_RIGHT; +} + +static inline int find_data_object_by_boot_id( + JournalFile *f, + sd_id128_t boot_id, + Object **o, + uint64_t *b) { + char t[sizeof("_BOOT_ID=")-1 + 32 + 1] = "_BOOT_ID="; + + sd_id128_to_string(boot_id, t + 9); + return journal_file_find_data_object(f, t, sizeof(t) - 1, o, b); +} + +int journal_file_move_to_entry_by_monotonic( + JournalFile *f, + sd_id128_t boot_id, + uint64_t monotonic, + direction_t direction, + Object **ret, + uint64_t *offset) { + + Object *o; + int r; + + assert(f); + + r = find_data_object_by_boot_id(f, boot_id, &o, NULL); + if (r < 0) + return r; + if (r == 0) + return -ENOENT; + + return generic_array_bisect_plus_one(f, + le64toh(o->data.entry_offset), + le64toh(o->data.entry_array_offset), + le64toh(o->data.n_entries), + monotonic, + test_object_monotonic, + direction, + ret, offset, NULL); +} + +int journal_file_next_entry( + JournalFile *f, + Object *o, uint64_t p, + direction_t direction, + Object **ret, uint64_t *offset) { + + uint64_t i, n; + int r; + + assert(f); + assert(p > 0 || !o); + + n = le64toh(f->header->n_entries); + if (n <= 0) + return 0; + + if (!o) + i = direction == DIRECTION_DOWN ? 0 : n - 1; + else { + if (o->object.type != OBJECT_ENTRY) + return -EINVAL; + + r = generic_array_bisect(f, + le64toh(f->header->entry_array_offset), + le64toh(f->header->n_entries), + p, + test_object_offset, + DIRECTION_DOWN, + NULL, NULL, + &i); + if (r <= 0) + return r; + + if (direction == DIRECTION_DOWN) { + if (i >= n - 1) + return 0; + + i++; + } else { + if (i <= 0) + return 0; + + i--; + } + } + + /* And jump to it */ + return generic_array_get(f, + le64toh(f->header->entry_array_offset), + i, + ret, offset); +} + +int journal_file_skip_entry( + JournalFile *f, + Object *o, uint64_t p, + int64_t skip, + Object **ret, uint64_t *offset) { + + uint64_t i, n; + int r; + + assert(f); + assert(o); + assert(p > 0); + + if (o->object.type != OBJECT_ENTRY) + return -EINVAL; + + r = generic_array_bisect(f, + le64toh(f->header->entry_array_offset), + le64toh(f->header->n_entries), + p, + test_object_offset, + DIRECTION_DOWN, + NULL, NULL, + &i); + if (r <= 0) + return r; + + /* Calculate new index */ + if (skip < 0) { + if ((uint64_t) -skip >= i) + i = 0; + else + i = i - (uint64_t) -skip; + } else + i += (uint64_t) skip; + + n = le64toh(f->header->n_entries); + if (n <= 0) + return -EBADMSG; + + if (i >= n) + i = n-1; + + return generic_array_get(f, + le64toh(f->header->entry_array_offset), + i, + ret, offset); +} + +int journal_file_next_entry_for_data( + JournalFile *f, + Object *o, uint64_t p, + uint64_t data_offset, + direction_t direction, + Object **ret, uint64_t *offset) { + + uint64_t n, i; + int r; + Object *d; + + assert(f); + assert(p > 0 || !o); + + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); + if (r < 0) + return r; + + n = le64toh(d->data.n_entries); + if (n <= 0) + return n; + + if (!o) + i = direction == DIRECTION_DOWN ? 0 : n - 1; + else { + if (o->object.type != OBJECT_ENTRY) + return -EINVAL; + + r = generic_array_bisect_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + le64toh(d->data.n_entries), + p, + test_object_offset, + DIRECTION_DOWN, + NULL, NULL, + &i); + + if (r <= 0) + return r; + + if (direction == DIRECTION_DOWN) { + if (i >= n - 1) + return 0; + + i++; + } else { + if (i <= 0) + return 0; + + i--; + } + + } + + return generic_array_get_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + i, + ret, offset); +} + +int journal_file_move_to_entry_by_offset_for_data( + JournalFile *f, + uint64_t data_offset, + uint64_t p, + direction_t direction, + Object **ret, uint64_t *offset) { + + int r; + Object *d; + + assert(f); + + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); + if (r < 0) + return r; + + return generic_array_bisect_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + le64toh(d->data.n_entries), + p, + test_object_offset, + direction, + ret, offset, NULL); +} + +int journal_file_move_to_entry_by_monotonic_for_data( + JournalFile *f, + uint64_t data_offset, + sd_id128_t boot_id, + uint64_t monotonic, + direction_t direction, + Object **ret, uint64_t *offset) { + + Object *o, *d; + int r; + uint64_t b, z; + + assert(f); + + /* First, seek by time */ + r = find_data_object_by_boot_id(f, boot_id, &o, &b); + if (r < 0) + return r; + if (r == 0) + return -ENOENT; + + r = generic_array_bisect_plus_one(f, + le64toh(o->data.entry_offset), + le64toh(o->data.entry_array_offset), + le64toh(o->data.n_entries), + monotonic, + test_object_monotonic, + direction, + NULL, &z, NULL); + if (r <= 0) + return r; + + /* And now, continue seeking until we find an entry that + * exists in both bisection arrays */ + + for (;;) { + Object *qo; + uint64_t p, q; + + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); + if (r < 0) + return r; + + r = generic_array_bisect_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + le64toh(d->data.n_entries), + z, + test_object_offset, + direction, + NULL, &p, NULL); + if (r <= 0) + return r; + + r = journal_file_move_to_object(f, OBJECT_DATA, b, &o); + if (r < 0) + return r; + + r = generic_array_bisect_plus_one(f, + le64toh(o->data.entry_offset), + le64toh(o->data.entry_array_offset), + le64toh(o->data.n_entries), + p, + test_object_offset, + direction, + &qo, &q, NULL); + + if (r <= 0) + return r; + + if (p == q) { + if (ret) + *ret = qo; + if (offset) + *offset = q; + + return 1; + } + + z = q; + } + + return 0; +} + +int journal_file_move_to_entry_by_seqnum_for_data( + JournalFile *f, + uint64_t data_offset, + uint64_t seqnum, + direction_t direction, + Object **ret, uint64_t *offset) { + + Object *d; + int r; + + assert(f); + + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); + if (r < 0) + return r; + + return generic_array_bisect_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + le64toh(d->data.n_entries), + seqnum, + test_object_seqnum, + direction, + ret, offset, NULL); +} + +int journal_file_move_to_entry_by_realtime_for_data( + JournalFile *f, + uint64_t data_offset, + uint64_t realtime, + direction_t direction, + Object **ret, uint64_t *offset) { + + Object *d; + int r; + + assert(f); + + r = journal_file_move_to_object(f, OBJECT_DATA, data_offset, &d); + if (r < 0) + return r; + + return generic_array_bisect_plus_one(f, + le64toh(d->data.entry_offset), + le64toh(d->data.entry_array_offset), + le64toh(d->data.n_entries), + realtime, + test_object_realtime, + direction, + ret, offset, NULL); +} + +void journal_file_dump(JournalFile *f) { + Object *o; + int r; + uint64_t p; + + assert(f); + + journal_file_print_header(f); + + p = le64toh(f->header->header_size); + while (p != 0) { + r = journal_file_move_to_object(f, -1, p, &o); + if (r < 0) + goto fail; + + switch (o->object.type) { + + case OBJECT_UNUSED: + printf("Type: OBJECT_UNUSED\n"); + break; + + case OBJECT_DATA: + printf("Type: OBJECT_DATA\n"); + break; + + case OBJECT_FIELD: + printf("Type: OBJECT_FIELD\n"); + break; + + case OBJECT_ENTRY: + printf("Type: OBJECT_ENTRY seqnum=%"PRIu64" monotonic=%"PRIu64" realtime=%"PRIu64"\n", + le64toh(o->entry.seqnum), + le64toh(o->entry.monotonic), + le64toh(o->entry.realtime)); + break; + + case OBJECT_FIELD_HASH_TABLE: + printf("Type: OBJECT_FIELD_HASH_TABLE\n"); + break; + + case OBJECT_DATA_HASH_TABLE: + printf("Type: OBJECT_DATA_HASH_TABLE\n"); + break; + + case OBJECT_ENTRY_ARRAY: + printf("Type: OBJECT_ENTRY_ARRAY\n"); + break; + + case OBJECT_TAG: + printf("Type: OBJECT_TAG seqnum=%"PRIu64" epoch=%"PRIu64"\n", + le64toh(o->tag.seqnum), + le64toh(o->tag.epoch)); + break; + + default: + printf("Type: unknown (%u)\n", o->object.type); + break; + } + + if (o->object.flags & OBJECT_COMPRESSED) + printf("Flags: COMPRESSED\n"); + + if (p == le64toh(f->header->tail_object_offset)) + p = 0; + else + p = p + ALIGN64(le64toh(o->object.size)); + } + + return; +fail: + log_error("File corrupt"); +} + +static const char* format_timestamp_safe(char *buf, size_t l, usec_t t) { + const char *x; + + x = format_timestamp(buf, l, t); + if (x) + return x; + return " --- "; +} + +void journal_file_print_header(JournalFile *f) { + char a[33], b[33], c[33], d[33]; + char x[FORMAT_TIMESTAMP_MAX], y[FORMAT_TIMESTAMP_MAX], z[FORMAT_TIMESTAMP_MAX]; + struct stat st; + char bytes[FORMAT_BYTES_MAX]; + + assert(f); + + printf("File Path: %s\n" + "File ID: %s\n" + "Machine ID: %s\n" + "Boot ID: %s\n" + "Sequential Number ID: %s\n" + "State: %s\n" + "Compatible Flags:%s%s\n" + "Incompatible Flags:%s%s\n" + "Header size: %"PRIu64"\n" + "Arena size: %"PRIu64"\n" + "Data Hash Table Size: %"PRIu64"\n" + "Field Hash Table Size: %"PRIu64"\n" + "Rotate Suggested: %s\n" + "Head Sequential Number: %"PRIu64"\n" + "Tail Sequential Number: %"PRIu64"\n" + "Head Realtime Timestamp: %s\n" + "Tail Realtime Timestamp: %s\n" + "Tail Monotonic Timestamp: %s\n" + "Objects: %"PRIu64"\n" + "Entry Objects: %"PRIu64"\n", + f->path, + sd_id128_to_string(f->header->file_id, a), + sd_id128_to_string(f->header->machine_id, b), + sd_id128_to_string(f->header->boot_id, c), + sd_id128_to_string(f->header->seqnum_id, d), + f->header->state == STATE_OFFLINE ? "OFFLINE" : + f->header->state == STATE_ONLINE ? "ONLINE" : + f->header->state == STATE_ARCHIVED ? "ARCHIVED" : "UNKNOWN", + JOURNAL_HEADER_SEALED(f->header) ? " SEALED" : "", + (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) ? " ???" : "", + JOURNAL_HEADER_COMPRESSED(f->header) ? " COMPRESSED" : "", + (le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "", + le64toh(f->header->header_size), + le64toh(f->header->arena_size), + le64toh(f->header->data_hash_table_size) / sizeof(HashItem), + le64toh(f->header->field_hash_table_size) / sizeof(HashItem), + yes_no(journal_file_rotate_suggested(f, 0)), + le64toh(f->header->head_entry_seqnum), + le64toh(f->header->tail_entry_seqnum), + format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), + format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), + format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), + le64toh(f->header->n_objects), + le64toh(f->header->n_entries)); + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data)) + printf("Data Objects: %"PRIu64"\n" + "Data Hash Table Fill: %.1f%%\n", + le64toh(f->header->n_data), + 100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)))); + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields)) + printf("Field Objects: %"PRIu64"\n" + "Field Hash Table Fill: %.1f%%\n", + le64toh(f->header->n_fields), + 100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)))); + + if (JOURNAL_HEADER_CONTAINS(f->header, n_tags)) + printf("Tag Objects: %"PRIu64"\n", + le64toh(f->header->n_tags)); + if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays)) + printf("Entry Array Objects: %"PRIu64"\n", + le64toh(f->header->n_entry_arrays)); + + if (fstat(f->fd, &st) >= 0) + printf("Disk usage: %s\n", format_bytes(bytes, sizeof(bytes), (off_t) st.st_blocks * 512ULL)); +} + +int journal_file_open( + const char *fname, + int flags, + mode_t mode, + bool compress, + bool seal, + JournalMetrics *metrics, + MMapCache *mmap_cache, + JournalFile *template, + JournalFile **ret) { + + JournalFile *f; + int r; + bool newly_created = false; + + assert(fname); + assert(ret); + + if ((flags & O_ACCMODE) != O_RDONLY && + (flags & O_ACCMODE) != O_RDWR) + return -EINVAL; + + if (!endswith(fname, ".journal") && + !endswith(fname, ".journal~")) + return -EINVAL; + + f = new0(JournalFile, 1); + if (!f) + return -ENOMEM; + + f->fd = -1; + f->mode = mode; + + f->flags = flags; + f->prot = prot_from_flags(flags); + f->writable = (flags & O_ACCMODE) != O_RDONLY; +#ifdef HAVE_XZ + f->compress = compress; +#endif +#ifdef HAVE_GCRYPT + f->seal = seal; +#endif + + if (mmap_cache) + f->mmap = mmap_cache_ref(mmap_cache); + else { + f->mmap = mmap_cache_new(); + if (!f->mmap) { + r = -ENOMEM; + goto fail; + } + } + + f->path = strdup(fname); + if (!f->path) { + r = -ENOMEM; + goto fail; + } + + f->chain_cache = hashmap_new(uint64_hash_func, uint64_compare_func); + if (!f->chain_cache) { + r = -ENOMEM; + goto fail; + } + + f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode); + if (f->fd < 0) { + r = -errno; + goto fail; + } + + if (fstat(f->fd, &f->last_stat) < 0) { + r = -errno; + goto fail; + } + + if (f->last_stat.st_size == 0 && f->writable) { +#ifdef HAVE_XATTR + uint64_t crtime; + + /* Let's attach the creation time to the journal file, + * so that the vacuuming code knows the age of this + * file even if the file might end up corrupted one + * day... Ideally we'd just use the creation time many + * file systems maintain for each file, but there is + * currently no usable API to query this, hence let's + * emulate this via extended attributes. If extended + * attributes are not supported we'll just skip this, + * and rely solely on mtime/atime/ctime of the file.*/ + + crtime = htole64((uint64_t) now(CLOCK_REALTIME)); + fsetxattr(f->fd, "user.crtime_usec", &crtime, sizeof(crtime), XATTR_CREATE); +#endif + +#ifdef HAVE_GCRYPT + /* Try to load the FSPRG state, and if we can't, then + * just don't do sealing */ + if (f->seal) { + r = journal_file_fss_load(f); + if (r < 0) + f->seal = false; + } +#endif + + r = journal_file_init_header(f, template); + if (r < 0) + goto fail; + + if (fstat(f->fd, &f->last_stat) < 0) { + r = -errno; + goto fail; + } + + newly_created = true; + } + + if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) { + r = -EIO; + goto fail; + } + + f->header = mmap(NULL, PAGE_ALIGN(sizeof(Header)), prot_from_flags(flags), MAP_SHARED, f->fd, 0); + if (f->header == MAP_FAILED) { + f->header = NULL; + r = -errno; + goto fail; + } + + if (!newly_created) { + r = journal_file_verify_header(f); + if (r < 0) + goto fail; + } + +#ifdef HAVE_GCRYPT + if (!newly_created && f->writable) { + r = journal_file_fss_load(f); + if (r < 0) + goto fail; + } +#endif + + if (f->writable) { + if (metrics) { + journal_default_metrics(metrics, f->fd); + f->metrics = *metrics; + } else if (template) + f->metrics = template->metrics; + + r = journal_file_refresh_header(f); + if (r < 0) + goto fail; + } + +#ifdef HAVE_GCRYPT + r = journal_file_hmac_setup(f); + if (r < 0) + goto fail; +#endif + + if (newly_created) { + r = journal_file_setup_field_hash_table(f); + if (r < 0) + goto fail; + + r = journal_file_setup_data_hash_table(f); + if (r < 0) + goto fail; + +#ifdef HAVE_GCRYPT + r = journal_file_append_first_tag(f); + if (r < 0) + goto fail; +#endif + } + + r = journal_file_map_field_hash_table(f); + if (r < 0) + goto fail; + + r = journal_file_map_data_hash_table(f); + if (r < 0) + goto fail; + + *ret = f; + return 0; + +fail: + journal_file_close(f); + + return r; +} + +int journal_file_rotate(JournalFile **f, bool compress, bool seal) { + _cleanup_free_ char *p = NULL; + size_t l; + JournalFile *old_file, *new_file = NULL; + int r; + + assert(f); + assert(*f); + + old_file = *f; + + if (!old_file->writable) + return -EINVAL; + + if (!endswith(old_file->path, ".journal")) + return -EINVAL; + + l = strlen(old_file->path); + r = asprintf(&p, "%.*s@" SD_ID128_FORMAT_STR "-%016"PRIx64"-%016"PRIx64".journal", + (int) l - 8, old_file->path, + SD_ID128_FORMAT_VAL(old_file->header->seqnum_id), + le64toh((*f)->header->head_entry_seqnum), + le64toh((*f)->header->head_entry_realtime)); + if (r < 0) + return -ENOMEM; + + r = rename(old_file->path, p); + if (r < 0) + return -errno; + + old_file->header->state = STATE_ARCHIVED; + + r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file); + journal_file_close(old_file); + + *f = new_file; + return r; +} + +int journal_file_open_reliably( + const char *fname, + int flags, + mode_t mode, + bool compress, + bool seal, + JournalMetrics *metrics, + MMapCache *mmap_cache, + JournalFile *template, + JournalFile **ret) { + + int r; + size_t l; + _cleanup_free_ char *p = NULL; + + r = journal_file_open(fname, flags, mode, compress, seal, + metrics, mmap_cache, template, ret); + if (r != -EBADMSG && /* corrupted */ + r != -ENODATA && /* truncated */ + r != -EHOSTDOWN && /* other machine */ + r != -EPROTONOSUPPORT && /* incompatible feature */ + r != -EBUSY && /* unclean shutdown */ + r != -ESHUTDOWN /* already archived */) + return r; + + if ((flags & O_ACCMODE) == O_RDONLY) + return r; + + if (!(flags & O_CREAT)) + return r; + + if (!endswith(fname, ".journal")) + return r; + + /* The file is corrupted. Rotate it away and try it again (but only once) */ + + l = strlen(fname); + if (asprintf(&p, "%.*s@%016llx-%016" PRIx64 ".journal~", + (int) l - 8, fname, + (unsigned long long) now(CLOCK_REALTIME), + random_u64()) < 0) + return -ENOMEM; + + r = rename(fname, p); + if (r < 0) + return -errno; + + log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname); + + return journal_file_open(fname, flags, mode, compress, seal, + metrics, mmap_cache, template, ret); +} + +int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) { + uint64_t i, n; + uint64_t q, xor_hash = 0; + int r; + EntryItem *items; + dual_timestamp ts; + + assert(from); + assert(to); + assert(o); + assert(p); + + if (!to->writable) + return -EPERM; + + ts.monotonic = le64toh(o->entry.monotonic); + ts.realtime = le64toh(o->entry.realtime); + + n = journal_file_entry_n_items(o); + /* alloca() can't take 0, hence let's allocate at least one */ + items = alloca(sizeof(EntryItem) * MAX(1u, n)); + + for (i = 0; i < n; i++) { + uint64_t l, h; + le64_t le_hash; + size_t t; + void *data; + Object *u; + + q = le64toh(o->entry.items[i].object_offset); + le_hash = o->entry.items[i].hash; + + r = journal_file_move_to_object(from, OBJECT_DATA, q, &o); + if (r < 0) + return r; + + if (le_hash != o->data.hash) + return -EBADMSG; + + l = le64toh(o->object.size) - offsetof(Object, data.payload); + t = (size_t) l; + + /* We hit the limit on 32bit machines */ + if ((uint64_t) t != l) + return -E2BIG; + + if (o->object.flags & OBJECT_COMPRESSED) { +#ifdef HAVE_XZ + uint64_t rsize; + + if (!uncompress_blob(o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize, 0)) + return -EBADMSG; + + data = from->compress_buffer; + l = rsize; +#else + return -EPROTONOSUPPORT; +#endif + } else + data = o->data.payload; + + r = journal_file_append_data(to, data, l, &u, &h); + if (r < 0) + return r; + + xor_hash ^= le64toh(u->data.hash); + items[i].object_offset = htole64(h); + items[i].hash = u->data.hash; + + r = journal_file_move_to_object(from, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + } + + return journal_file_append_entry_internal(to, &ts, xor_hash, items, n, seqnum, ret, offset); +} + +void journal_default_metrics(JournalMetrics *m, int fd) { + uint64_t fs_size = 0; + struct statvfs ss; + char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX]; + + assert(m); + assert(fd >= 0); + + if (fstatvfs(fd, &ss) >= 0) + fs_size = ss.f_frsize * ss.f_blocks; + + if (m->max_use == (uint64_t) -1) { + + if (fs_size > 0) { + m->max_use = PAGE_ALIGN(fs_size / 10); /* 10% of file system size */ + + if (m->max_use > DEFAULT_MAX_USE_UPPER) + m->max_use = DEFAULT_MAX_USE_UPPER; + + if (m->max_use < DEFAULT_MAX_USE_LOWER) + m->max_use = DEFAULT_MAX_USE_LOWER; + } else + m->max_use = DEFAULT_MAX_USE_LOWER; + } else { + m->max_use = PAGE_ALIGN(m->max_use); + + if (m->max_use < JOURNAL_FILE_SIZE_MIN*2) + m->max_use = JOURNAL_FILE_SIZE_MIN*2; + } + + if (m->max_size == (uint64_t) -1) { + m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */ + + if (m->max_size > DEFAULT_MAX_SIZE_UPPER) + m->max_size = DEFAULT_MAX_SIZE_UPPER; + } else + m->max_size = PAGE_ALIGN(m->max_size); + + if (m->max_size < JOURNAL_FILE_SIZE_MIN) + m->max_size = JOURNAL_FILE_SIZE_MIN; + + if (m->max_size*2 > m->max_use) + m->max_use = m->max_size*2; + + if (m->min_size == (uint64_t) -1) + m->min_size = JOURNAL_FILE_SIZE_MIN; + else { + m->min_size = PAGE_ALIGN(m->min_size); + + if (m->min_size < JOURNAL_FILE_SIZE_MIN) + m->min_size = JOURNAL_FILE_SIZE_MIN; + + if (m->min_size > m->max_size) + m->max_size = m->min_size; + } + + if (m->keep_free == (uint64_t) -1) { + + if (fs_size > 0) { + m->keep_free = PAGE_ALIGN(fs_size * 3 / 20); /* 15% of file system size */ + + if (m->keep_free > DEFAULT_KEEP_FREE_UPPER) + m->keep_free = DEFAULT_KEEP_FREE_UPPER; + + } else + m->keep_free = DEFAULT_KEEP_FREE; + } + + log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s", + format_bytes(a, sizeof(a), m->max_use), + format_bytes(b, sizeof(b), m->max_size), + format_bytes(c, sizeof(c), m->min_size), + format_bytes(d, sizeof(d), m->keep_free)); +} + +int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) { + assert(f); + assert(from || to); + + if (from) { + if (f->header->head_entry_realtime == 0) + return -ENOENT; + + *from = le64toh(f->header->head_entry_realtime); + } + + if (to) { + if (f->header->tail_entry_realtime == 0) + return -ENOENT; + + *to = le64toh(f->header->tail_entry_realtime); + } + + return 1; +} + +int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, usec_t *from, usec_t *to) { + Object *o; + uint64_t p; + int r; + + assert(f); + assert(from || to); + + r = find_data_object_by_boot_id(f, boot_id, &o, &p); + if (r <= 0) + return r; + + if (le64toh(o->data.n_entries) <= 0) + return 0; + + if (from) { + r = journal_file_move_to_object(f, OBJECT_ENTRY, le64toh(o->data.entry_offset), &o); + if (r < 0) + return r; + + *from = le64toh(o->entry.monotonic); + } + + if (to) { + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + r = generic_array_get_plus_one(f, + le64toh(o->data.entry_offset), + le64toh(o->data.entry_array_offset), + le64toh(o->data.n_entries)-1, + &o, NULL); + if (r <= 0) + return r; + + *to = le64toh(o->entry.monotonic); + } + + return 1; +} + +bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) { + assert(f); + + /* If we gained new header fields we gained new features, + * hence suggest a rotation */ + if (le64toh(f->header->header_size) < sizeof(Header)) { + log_debug("%s uses an outdated header, suggesting rotation.", f->path); + return true; + } + + /* Let's check if the hash tables grew over a certain fill + * level (75%, borrowing this value from Java's hash table + * implementation), and if so suggest a rotation. To calculate + * the fill level we need the n_data field, which only exists + * in newer versions. */ + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data)) + if (le64toh(f->header->n_data) * 4ULL > (le64toh(f->header->data_hash_table_size) / sizeof(HashItem)) * 3ULL) { + log_debug("Data hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items, %llu file size, %"PRIu64" bytes per hash table item), suggesting rotation.", + f->path, + 100.0 * (double) le64toh(f->header->n_data) / ((double) (le64toh(f->header->data_hash_table_size) / sizeof(HashItem))), + le64toh(f->header->n_data), + le64toh(f->header->data_hash_table_size) / sizeof(HashItem), + (unsigned long long) f->last_stat.st_size, + f->last_stat.st_size / le64toh(f->header->n_data)); + return true; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields)) + if (le64toh(f->header->n_fields) * 4ULL > (le64toh(f->header->field_hash_table_size) / sizeof(HashItem)) * 3ULL) { + log_debug("Field hash table of %s has a fill level at %.1f (%"PRIu64" of %"PRIu64" items), suggesting rotation.", + f->path, + 100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))), + le64toh(f->header->n_fields), + le64toh(f->header->field_hash_table_size) / sizeof(HashItem)); + return true; + } + + /* Are the data objects properly indexed by field objects? */ + if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && + JOURNAL_HEADER_CONTAINS(f->header, n_fields) && + le64toh(f->header->n_data) > 0 && + le64toh(f->header->n_fields) == 0) + return true; + + if (max_file_usec > 0) { + usec_t t, h; + + h = le64toh(f->header->head_entry_realtime); + t = now(CLOCK_REALTIME); + + if (h > 0 && t > h + max_file_usec) + return true; + } + + return false; +} diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h new file mode 100644 index 0000000..50dbe29 --- /dev/null +++ b/src/journal/journal-file.h @@ -0,0 +1,223 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#ifdef HAVE_GCRYPT +#include +#endif + +#include + +#include "sparse-endian.h" +#include "journal-def.h" +#include "util.h" +#include "mmap-cache.h" +#include "hashmap.h" + +typedef struct JournalMetrics { + uint64_t max_use; + uint64_t use; + uint64_t max_size; + uint64_t min_size; + uint64_t keep_free; +} JournalMetrics; + +typedef enum direction { + DIRECTION_UP, + DIRECTION_DOWN +} direction_t; + +typedef struct JournalFile { + int fd; + + mode_t mode; + + int flags; + int prot; + bool writable:1; + bool compress:1; + bool seal:1; + + bool tail_entry_monotonic_valid:1; + + direction_t last_direction; + + char *path; + struct stat last_stat; + + Header *header; + HashItem *data_hash_table; + HashItem *field_hash_table; + + uint64_t current_offset; + + JournalMetrics metrics; + MMapCache *mmap; + + Hashmap *chain_cache; + +#ifdef HAVE_XZ + void *compress_buffer; + uint64_t compress_buffer_size; +#endif + +#ifdef HAVE_GCRYPT + gcry_md_hd_t hmac; + bool hmac_running; + + FSSHeader *fss_file; + size_t fss_file_size; + + uint64_t fss_start_usec; + uint64_t fss_interval_usec; + + void *fsprg_state; + size_t fsprg_state_size; + + void *fsprg_seed; + size_t fsprg_seed_size; +#endif +} JournalFile; + +int journal_file_open( + const char *fname, + int flags, + mode_t mode, + bool compress, + bool seal, + JournalMetrics *metrics, + MMapCache *mmap_cache, + JournalFile *template, + JournalFile **ret); + +int journal_file_set_offline(JournalFile *f); +void journal_file_close(JournalFile *j); + +int journal_file_open_reliably( + const char *fname, + int flags, + mode_t mode, + bool compress, + bool seal, + JournalMetrics *metrics, + MMapCache *mmap_cache, + JournalFile *template, + JournalFile **ret); + +#define ALIGN64(x) (((x) + 7ULL) & ~7ULL) +#define VALID64(x) (((x) & 7ULL) == 0ULL) + +/* Use six characters to cover the offsets common in smallish journal + * files without adding too many zeros. */ +#define OFSfmt "%06"PRIx64 + +static inline bool VALID_REALTIME(uint64_t u) { + /* This considers timestamps until the year 3112 valid. That should be plenty room... */ + return u > 0 && u < (1ULL << 55); +} + +static inline bool VALID_MONOTONIC(uint64_t u) { + /* This considers timestamps until 1142 years of runtime valid. */ + return u < (1ULL << 55); +} + +static inline bool VALID_EPOCH(uint64_t u) { + /* This allows changing the key for 1142 years, every usec. */ + return u < (1ULL << 55); +} + +#define JOURNAL_HEADER_CONTAINS(h, field) \ + (le64toh((h)->header_size) >= offsetof(Header, field) + sizeof((h)->field)) + +#define JOURNAL_HEADER_SEALED(h) \ + (!!(le32toh((h)->compatible_flags) & HEADER_COMPATIBLE_SEALED)) + +#define JOURNAL_HEADER_COMPRESSED(h) \ + (!!(le32toh((h)->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) + +int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret); + +uint64_t journal_file_entry_n_items(Object *o) _pure_; +uint64_t journal_file_entry_array_n_items(Object *o) _pure_; +uint64_t journal_file_hash_table_n_items(Object *o) _pure_; + +int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset); +int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqno, Object **ret, uint64_t *offset); + +int journal_file_find_data_object(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset); +int journal_file_find_data_object_with_hash(JournalFile *f, const void *data, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset); + +int journal_file_find_field_object(JournalFile *f, const void *field, uint64_t size, Object **ret, uint64_t *offset); +int journal_file_find_field_object_with_hash(JournalFile *f, const void *field, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset); + +int journal_file_next_entry(JournalFile *f, Object *o, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_skip_entry(JournalFile *f, Object *o, uint64_t p, int64_t skip, Object **ret, uint64_t *offset); + +int journal_file_next_entry_for_data(JournalFile *f, Object *o, uint64_t p, uint64_t data_offset, direction_t direction, Object **ret, uint64_t *offset); + +int journal_file_move_to_entry_by_offset(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_seqnum(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_realtime(JournalFile *f, uint64_t realtime, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_monotonic(JournalFile *f, sd_id128_t boot_id, uint64_t monotonic, direction_t direction, Object **ret, uint64_t *offset); + +int journal_file_move_to_entry_by_offset_for_data(JournalFile *f, uint64_t data_offset, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_seqnum_for_data(JournalFile *f, uint64_t data_offset, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_realtime_for_data(JournalFile *f, uint64_t data_offset, uint64_t realtime, direction_t direction, Object **ret, uint64_t *offset); +int journal_file_move_to_entry_by_monotonic_for_data(JournalFile *f, uint64_t data_offset, sd_id128_t boot_id, uint64_t monotonic, direction_t direction, Object **ret, uint64_t *offset); + +int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset); + +void journal_file_dump(JournalFile *f); +void journal_file_print_header(JournalFile *f); + +int journal_file_rotate(JournalFile **f, bool compress, bool seal); + +void journal_file_post_change(JournalFile *f); + +void journal_default_metrics(JournalMetrics *m, int fd); + +int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to); +int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); + +bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); + + +static unsigned type_to_context(int type) { + /* One context for each type, plus one catch-all for the rest */ + return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0; +} + +static inline int journal_file_object_keep(JournalFile *f, Object *o, uint64_t offset) { + unsigned context = type_to_context(o->object.type); + + return mmap_cache_get(f->mmap, f->fd, f->prot, context, true, + offset, o->object.size, &f->last_stat, NULL); +} + +static inline int journal_file_object_release(JournalFile *f, Object *o, uint64_t offset) { + unsigned context = type_to_context(o->object.type); + + return mmap_cache_release(f->mmap, f->fd, f->prot, context, + offset, o->object.size); +} diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c new file mode 100644 index 0000000..7e97a35 --- /dev/null +++ b/src/journal/journal-gatewayd.c @@ -0,0 +1,1058 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include + +#include "log.h" +#include "util.h" +#include "sd-journal.h" +#include "sd-daemon.h" +#include "sd-bus.h" +#include "bus-util.h" +#include "logs-show.h" +#include "microhttpd-util.h" +#include "build.h" +#include "fileio.h" + +typedef struct RequestMeta { + sd_journal *journal; + + OutputMode mode; + + char *cursor; + int64_t n_skip; + uint64_t n_entries; + bool n_entries_set; + + FILE *tmp; + uint64_t delta, size; + + int argument_parse_error; + + bool follow; + bool discrete; + + uint64_t n_fields; + bool n_fields_set; +} RequestMeta; + +static const char* const mime_types[_OUTPUT_MODE_MAX] = { + [OUTPUT_SHORT] = "text/plain", + [OUTPUT_JSON] = "application/json", + [OUTPUT_JSON_SSE] = "text/event-stream", + [OUTPUT_EXPORT] = "application/vnd.fdo.journal", +}; + +static RequestMeta *request_meta(void **connection_cls) { + RequestMeta *m; + + if (*connection_cls) + return *connection_cls; + + m = new0(RequestMeta, 1); + if (!m) + return NULL; + + *connection_cls = m; + return m; +} + +static void request_meta_free( + void *cls, + struct MHD_Connection *connection, + void **connection_cls, + enum MHD_RequestTerminationCode toe) { + + RequestMeta *m = *connection_cls; + + if (!m) + return; + + if (m->journal) + sd_journal_close(m->journal); + + if (m->tmp) + fclose(m->tmp); + + free(m->cursor); + free(m); +} + +static int open_journal(RequestMeta *m) { + assert(m); + + if (m->journal) + return 0; + + return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM); +} + +static int respond_oom_internal(struct MHD_Connection *connection) { + struct MHD_Response *response; + const char m[] = "Out of memory.\n"; + int ret; + + assert(connection); + + response = MHD_create_response_from_buffer(sizeof(m)-1, (char*) m, MHD_RESPMEM_PERSISTENT); + if (!response) + return MHD_NO; + + MHD_add_response_header(response, "Content-Type", "text/plain"); + ret = MHD_queue_response(connection, MHD_HTTP_SERVICE_UNAVAILABLE, response); + MHD_destroy_response(response); + + return ret; +} + +#define respond_oom(connection) log_oom(), respond_oom_internal(connection) + +_printf_(3,4) +static int respond_error( + struct MHD_Connection *connection, + unsigned code, + const char *format, ...) { + + struct MHD_Response *response; + char *m; + int r; + va_list ap; + + assert(connection); + assert(format); + + va_start(ap, format); + r = vasprintf(&m, format, ap); + va_end(ap); + + if (r < 0) + return respond_oom(connection); + + response = MHD_create_response_from_buffer(strlen(m), m, MHD_RESPMEM_MUST_FREE); + if (!response) { + free(m); + return respond_oom(connection); + } + + MHD_add_response_header(response, "Content-Type", "text/plain"); + r = MHD_queue_response(connection, code, response); + MHD_destroy_response(response); + + return r; +} + +static ssize_t request_reader_entries( + void *cls, + uint64_t pos, + char *buf, + size_t max) { + + RequestMeta *m = cls; + int r; + size_t n, k; + + assert(m); + assert(buf); + assert(max > 0); + assert(pos >= m->delta); + + pos -= m->delta; + + while (pos >= m->size) { + off_t sz; + + /* End of this entry, so let's serialize the next + * one */ + + if (m->n_entries_set && + m->n_entries <= 0) + return MHD_CONTENT_READER_END_OF_STREAM; + + if (m->n_skip < 0) + r = sd_journal_previous_skip(m->journal, (uint64_t) -m->n_skip + 1); + else if (m->n_skip > 0) + r = sd_journal_next_skip(m->journal, (uint64_t) m->n_skip + 1); + else + r = sd_journal_next(m->journal); + + if (r < 0) { + log_error("Failed to advance journal pointer: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } else if (r == 0) { + + if (m->follow) { + r = sd_journal_wait(m->journal, (uint64_t) -1); + if (r < 0) { + log_error("Couldn't wait for journal event: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + continue; + } + + return MHD_CONTENT_READER_END_OF_STREAM; + } + + if (m->discrete) { + assert(m->cursor); + + r = sd_journal_test_cursor(m->journal, m->cursor); + if (r < 0) { + log_error("Failed to test cursor: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + if (r == 0) + return MHD_CONTENT_READER_END_OF_STREAM; + } + + pos -= m->size; + m->delta += m->size; + + if (m->n_entries_set) + m->n_entries -= 1; + + m->n_skip = 0; + + if (m->tmp) + rewind(m->tmp); + else { + m->tmp = tmpfile(); + if (!m->tmp) { + log_error("Failed to create temporary file: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + } + + r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, NULL); + if (r < 0) { + log_error("Failed to serialize item: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + sz = ftello(m->tmp); + if (sz == (off_t) -1) { + log_error("Failed to retrieve file position: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + m->size = (uint64_t) sz; + } + + if (fseeko(m->tmp, pos, SEEK_SET) < 0) { + log_error("Failed to seek to position: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + n = m->size - pos; + if (n > max) + n = max; + + errno = 0; + k = fread(buf, 1, n, m->tmp); + if (k != n) { + log_error("Failed to read from file: %s", errno ? strerror(errno) : "Premature EOF"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + return (ssize_t) k; +} + +static int request_parse_accept( + RequestMeta *m, + struct MHD_Connection *connection) { + + const char *header; + + assert(m); + assert(connection); + + header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Accept"); + if (!header) + return 0; + + if (streq(header, mime_types[OUTPUT_JSON])) + m->mode = OUTPUT_JSON; + else if (streq(header, mime_types[OUTPUT_JSON_SSE])) + m->mode = OUTPUT_JSON_SSE; + else if (streq(header, mime_types[OUTPUT_EXPORT])) + m->mode = OUTPUT_EXPORT; + else + m->mode = OUTPUT_SHORT; + + return 0; +} + +static int request_parse_range( + RequestMeta *m, + struct MHD_Connection *connection) { + + const char *range, *colon, *colon2; + int r; + + assert(m); + assert(connection); + + range = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range"); + if (!range) + return 0; + + if (!startswith(range, "entries=")) + return 0; + + range += 8; + range += strspn(range, WHITESPACE); + + colon = strchr(range, ':'); + if (!colon) + m->cursor = strdup(range); + else { + const char *p; + + colon2 = strchr(colon + 1, ':'); + if (colon2) { + _cleanup_free_ char *t; + + t = strndup(colon + 1, colon2 - colon - 1); + if (!t) + return -ENOMEM; + + r = safe_atoi64(t, &m->n_skip); + if (r < 0) + return r; + } + + p = (colon2 ? colon2 : colon) + 1; + if (*p) { + r = safe_atou64(p, &m->n_entries); + if (r < 0) + return r; + + if (m->n_entries <= 0) + return -EINVAL; + + m->n_entries_set = true; + } + + m->cursor = strndup(range, colon - range); + } + + if (!m->cursor) + return -ENOMEM; + + m->cursor[strcspn(m->cursor, WHITESPACE)] = 0; + if (isempty(m->cursor)) { + free(m->cursor); + m->cursor = NULL; + } + + return 0; +} + +static int request_parse_arguments_iterator( + void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value) { + + RequestMeta *m = cls; + _cleanup_free_ char *p = NULL; + int r; + + assert(m); + + if (isempty(key)) { + m->argument_parse_error = -EINVAL; + return MHD_NO; + } + + if (streq(key, "follow")) { + if (isempty(value)) { + m->follow = true; + return MHD_YES; + } + + r = parse_boolean(value); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + + m->follow = r; + return MHD_YES; + } + + if (streq(key, "discrete")) { + if (isempty(value)) { + m->discrete = true; + return MHD_YES; + } + + r = parse_boolean(value); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + + m->discrete = r; + return MHD_YES; + } + + if (streq(key, "boot")) { + if (isempty(value)) + r = true; + else { + r = parse_boolean(value); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + } + + if (r) { + char match[9 + 32 + 1] = "_BOOT_ID="; + sd_id128_t bid; + + r = sd_id128_get_boot(&bid); + if (r < 0) { + log_error("Failed to get boot ID: %s", strerror(-r)); + return MHD_NO; + } + + sd_id128_to_string(bid, match + 9); + r = sd_journal_add_match(m->journal, match, sizeof(match)-1); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + } + + return MHD_YES; + } + + p = strjoin(key, "=", strempty(value), NULL); + if (!p) { + m->argument_parse_error = log_oom(); + return MHD_NO; + } + + r = sd_journal_add_match(m->journal, p, 0); + if (r < 0) { + m->argument_parse_error = r; + return MHD_NO; + } + + return MHD_YES; +} + +static int request_parse_arguments( + RequestMeta *m, + struct MHD_Connection *connection) { + + assert(m); + assert(connection); + + m->argument_parse_error = 0; + MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, request_parse_arguments_iterator, m); + + return m->argument_parse_error; +} + +static int request_handler_entries( + struct MHD_Connection *connection, + void *connection_cls) { + + struct MHD_Response *response; + RequestMeta *m = connection_cls; + int r; + + assert(connection); + assert(m); + + r = open_journal(m); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r)); + + if (request_parse_accept(m, connection) < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse Accept header.\n"); + + if (request_parse_range(m, connection) < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse Range header.\n"); + + if (request_parse_arguments(m, connection) < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse URL arguments.\n"); + + if (m->discrete) { + if (!m->cursor) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Discrete seeks require a cursor specification.\n"); + + m->n_entries = 1; + m->n_entries_set = true; + } + + if (m->cursor) + r = sd_journal_seek_cursor(m->journal, m->cursor); + else if (m->n_skip >= 0) + r = sd_journal_seek_head(m->journal); + else if (m->n_skip < 0) + r = sd_journal_seek_tail(m->journal); + if (r < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to seek in journal.\n"); + + response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_entries, m, NULL); + if (!response) + return respond_oom(connection); + + MHD_add_response_header(response, "Content-Type", mime_types[m->mode]); + + r = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_destroy_response(response); + + return r; +} + +static int output_field(FILE *f, OutputMode m, const char *d, size_t l) { + const char *eq; + size_t j; + + eq = memchr(d, '=', l); + if (!eq) + return -EINVAL; + + j = l - (eq - d + 1); + + if (m == OUTPUT_JSON) { + fprintf(f, "{ \"%.*s\" : ", (int) (eq - d), d); + json_escape(f, eq+1, j, OUTPUT_FULL_WIDTH); + fputs(" }\n", f); + } else { + fwrite(eq+1, 1, j, f); + fputc('\n', f); + } + + return 0; +} + +static ssize_t request_reader_fields( + void *cls, + uint64_t pos, + char *buf, + size_t max) { + + RequestMeta *m = cls; + int r; + size_t n, k; + + assert(m); + assert(buf); + assert(max > 0); + assert(pos >= m->delta); + + pos -= m->delta; + + while (pos >= m->size) { + off_t sz; + const void *d; + size_t l; + + /* End of this field, so let's serialize the next + * one */ + + if (m->n_fields_set && + m->n_fields <= 0) + return MHD_CONTENT_READER_END_OF_STREAM; + + r = sd_journal_enumerate_unique(m->journal, &d, &l); + if (r < 0) { + log_error("Failed to advance field index: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } else if (r == 0) + return MHD_CONTENT_READER_END_OF_STREAM; + + pos -= m->size; + m->delta += m->size; + + if (m->n_fields_set) + m->n_fields -= 1; + + if (m->tmp) + rewind(m->tmp); + else { + m->tmp = tmpfile(); + if (!m->tmp) { + log_error("Failed to create temporary file: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + } + + r = output_field(m->tmp, m->mode, d, l); + if (r < 0) { + log_error("Failed to serialize item: %s", strerror(-r)); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + sz = ftello(m->tmp); + if (sz == (off_t) -1) { + log_error("Failed to retrieve file position: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + m->size = (uint64_t) sz; + } + + if (fseeko(m->tmp, pos, SEEK_SET) < 0) { + log_error("Failed to seek to position: %m"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + n = m->size - pos; + if (n > max) + n = max; + + errno = 0; + k = fread(buf, 1, n, m->tmp); + if (k != n) { + log_error("Failed to read from file: %s", errno ? strerror(errno) : "Premature EOF"); + return MHD_CONTENT_READER_END_WITH_ERROR; + } + + return (ssize_t) k; +} + +static int request_handler_fields( + struct MHD_Connection *connection, + const char *field, + void *connection_cls) { + + struct MHD_Response *response; + RequestMeta *m = connection_cls; + int r; + + assert(connection); + assert(m); + + r = open_journal(m); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r)); + + if (request_parse_accept(m, connection) < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to parse Accept header.\n"); + + r = sd_journal_query_unique(m->journal, field); + if (r < 0) + return respond_error(connection, MHD_HTTP_BAD_REQUEST, "Failed to query unique fields.\n"); + + response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_fields, m, NULL); + if (!response) + return respond_oom(connection); + + MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]); + + r = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_destroy_response(response); + + return r; +} + +static int request_handler_redirect( + struct MHD_Connection *connection, + const char *target) { + + char *page; + struct MHD_Response *response; + int ret; + + assert(connection); + assert(target); + + if (asprintf(&page, "Please continue to the journal browser.", target) < 0) + return respond_oom(connection); + + response = MHD_create_response_from_buffer(strlen(page), page, MHD_RESPMEM_MUST_FREE); + if (!response) { + free(page); + return respond_oom(connection); + } + + MHD_add_response_header(response, "Content-Type", "text/html"); + MHD_add_response_header(response, "Location", target); + + ret = MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); + MHD_destroy_response(response); + + return ret; +} + +static int request_handler_file( + struct MHD_Connection *connection, + const char *path, + const char *mime_type) { + + struct MHD_Response *response; + int ret; + _cleanup_close_ int fd = -1; + struct stat st; + + assert(connection); + assert(path); + assert(mime_type); + + fd = open(path, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return respond_error(connection, MHD_HTTP_NOT_FOUND, "Failed to open file %s: %m\n", path); + + if (fstat(fd, &st) < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to stat file: %m\n"); + + response = MHD_create_response_from_fd_at_offset(st.st_size, fd, 0); + if (!response) + return respond_oom(connection); + + fd = -1; + + MHD_add_response_header(response, "Content-Type", mime_type); + + ret = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_destroy_response(response); + + return ret; +} + +static int get_virtualization(char **v) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + char *b = NULL; + int r; + + r = sd_bus_default_system(&bus); + if (r < 0) + return r; + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Virtualization", + NULL, + &b); + if (r < 0) + return r; + + if (isempty(b)) { + free(b); + *v = NULL; + return 0; + } + + *v = b; + return 1; +} + +static int request_handler_machine( + struct MHD_Connection *connection, + void *connection_cls) { + + struct MHD_Response *response; + RequestMeta *m = connection_cls; + int r; + _cleanup_free_ char* hostname = NULL, *os_name = NULL; + uint64_t cutoff_from = 0, cutoff_to = 0, usage; + char *json; + sd_id128_t mid, bid; + _cleanup_free_ char *v = NULL; + + assert(connection); + assert(m); + + r = open_journal(m); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to open journal: %s\n", strerror(-r)); + + r = sd_id128_get_machine(&mid); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine machine ID: %s\n", strerror(-r)); + + r = sd_id128_get_boot(&bid); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine boot ID: %s\n", strerror(-r)); + + hostname = gethostname_malloc(); + if (!hostname) + return respond_oom(connection); + + r = sd_journal_get_usage(m->journal, &usage); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r)); + + r = sd_journal_get_cutoff_realtime_usec(m->journal, &cutoff_from, &cutoff_to); + if (r < 0) + return respond_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r)); + + parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL); + + get_virtualization(&v); + + r = asprintf(&json, + "{ \"machine_id\" : \"" SD_ID128_FORMAT_STR "\"," + "\"boot_id\" : \"" SD_ID128_FORMAT_STR "\"," + "\"hostname\" : \"%s\"," + "\"os_pretty_name\" : \"%s\"," + "\"virtualization\" : \"%s\"," + "\"usage\" : \"%"PRIu64"\"," + "\"cutoff_from_realtime\" : \"%"PRIu64"\"," + "\"cutoff_to_realtime\" : \"%"PRIu64"\" }\n", + SD_ID128_FORMAT_VAL(mid), + SD_ID128_FORMAT_VAL(bid), + hostname_cleanup(hostname, false), + os_name ? os_name : "Linux", + v ? v : "bare", + usage, + cutoff_from, + cutoff_to); + + if (r < 0) + return respond_oom(connection); + + response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); + if (!response) { + free(json); + return respond_oom(connection); + } + + MHD_add_response_header(response, "Content-Type", "application/json"); + r = MHD_queue_response(connection, MHD_HTTP_OK, response); + MHD_destroy_response(response); + + return r; +} + +static int request_handler( + void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **connection_cls) { + + assert(connection); + assert(connection_cls); + assert(url); + assert(method); + + if (!streq(method, "GET")) + return respond_error(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE, + "Unsupported method.\n"); + + + if (!*connection_cls) { + if (!request_meta(connection_cls)) + return respond_oom(connection); + return MHD_YES; + } + + if (streq(url, "/")) + return request_handler_redirect(connection, "/browse"); + + if (streq(url, "/entries")) + return request_handler_entries(connection, *connection_cls); + + if (startswith(url, "/fields/")) + return request_handler_fields(connection, url + 8, *connection_cls); + + if (streq(url, "/browse")) + return request_handler_file(connection, DOCUMENT_ROOT "/browse.html", "text/html"); + + if (streq(url, "/machine")) + return request_handler_machine(connection, *connection_cls); + + return respond_error(connection, MHD_HTTP_NOT_FOUND, "Not found.\n"); +} + +static int help(void) { + + printf("%s [OPTIONS...] ...\n\n" + "HTTP server for journal events.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --cert=CERT.PEM Specify server certificate in PEM format\n" + " --key=KEY.PEM Specify server key in PEM format\n", + program_invocation_short_name); + + return 0; +} + +static char *key_pem = NULL; +static char *cert_pem = NULL; + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_KEY, + ARG_CERT, + }; + + int r, c; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "key", required_argument, NULL, ARG_KEY }, + { "cert", required_argument, NULL, ARG_CERT }, + {} + }; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + + switch(c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_KEY: + if (key_pem) { + log_error("Key file specified twice"); + return -EINVAL; + } + r = read_full_file(optarg, &key_pem, NULL); + if (r < 0) { + log_error("Failed to read key file: %s", strerror(-r)); + return r; + } + assert(key_pem); + break; + + case ARG_CERT: + if (cert_pem) { + log_error("Certificate file specified twice"); + return -EINVAL; + } + r = read_full_file(optarg, &cert_pem, NULL); + if (r < 0) { + log_error("Failed to read certificate file: %s", strerror(-r)); + return r; + } + assert(cert_pem); + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (optind < argc) { + log_error("This program does not take arguments."); + return -EINVAL; + } + + if (!!key_pem != !!cert_pem) { + log_error("Certificate and key files must be specified together"); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + struct MHD_Daemon *d = NULL; + int r, n; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r < 0) + return EXIT_FAILURE; + if (r == 0) + return EXIT_SUCCESS; + + n = sd_listen_fds(1); + if (n < 0) { + log_error("Failed to determine passed sockets: %s", strerror(-n)); + goto finish; + } else if (n > 1) { + log_error("Can't listen on more than one socket."); + goto finish; + } else { + struct MHD_OptionItem opts[] = { + { MHD_OPTION_NOTIFY_COMPLETED, + (intptr_t) request_meta_free, NULL }, + { MHD_OPTION_EXTERNAL_LOGGER, + (intptr_t) microhttpd_logger, NULL }, + { MHD_OPTION_END, 0, NULL }, + { MHD_OPTION_END, 0, NULL }, + { MHD_OPTION_END, 0, NULL }, + { MHD_OPTION_END, 0, NULL }}; + int opts_pos = 2; + int flags = MHD_USE_THREAD_PER_CONNECTION|MHD_USE_POLL|MHD_USE_DEBUG; + + if (n > 0) + opts[opts_pos++] = (struct MHD_OptionItem) + {MHD_OPTION_LISTEN_SOCKET, SD_LISTEN_FDS_START}; + if (key_pem) { + assert(cert_pem); + opts[opts_pos++] = (struct MHD_OptionItem) + {MHD_OPTION_HTTPS_MEM_KEY, 0, key_pem}; + opts[opts_pos++] = (struct MHD_OptionItem) + {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem}; + flags |= MHD_USE_SSL; + } + + d = MHD_start_daemon(flags, 19531, + NULL, NULL, + request_handler, NULL, + MHD_OPTION_ARRAY, opts, + MHD_OPTION_END); + } + + if (!d) { + log_error("Failed to start daemon!"); + goto finish; + } + + pause(); + + r = EXIT_SUCCESS; + +finish: + if (d) + MHD_stop_daemon(d); + + return r; +} diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h new file mode 100644 index 0000000..2c401e3 --- /dev/null +++ b/src/journal/journal-internal.h @@ -0,0 +1,143 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include + +#include "journal-def.h" +#include "list.h" +#include "hashmap.h" +#include "set.h" +#include "journal-file.h" + +typedef struct Match Match; +typedef struct Location Location; +typedef struct Directory Directory; + +typedef enum MatchType { + MATCH_DISCRETE, + MATCH_OR_TERM, + MATCH_AND_TERM +} MatchType; + +struct Match { + MatchType type; + Match *parent; + LIST_FIELDS(Match, matches); + + /* For concrete matches */ + char *data; + size_t size; + le64_t le_hash; + + /* For terms */ + LIST_HEAD(Match, matches); +}; + +typedef enum LocationType { + /* The first and last entries, resp. */ + LOCATION_HEAD, + LOCATION_TAIL, + + /* We already read the entry we currently point to, and the + * next one to read should probably not be this one again. */ + LOCATION_DISCRETE, + + /* We should seek to the precise location specified, and + * return it, as we haven't read it yet. */ + LOCATION_SEEK +} LocationType; + +struct Location { + LocationType type; + + bool seqnum_set; + bool realtime_set; + bool monotonic_set; + bool xor_hash_set; + + uint64_t seqnum; + sd_id128_t seqnum_id; + + uint64_t realtime; + + uint64_t monotonic; + sd_id128_t boot_id; + + uint64_t xor_hash; +}; + +struct Directory { + char *path; + int wd; + bool is_root; +}; + +struct sd_journal { + char *path; + char *prefix; + + Hashmap *files; + MMapCache *mmap; + + Location current_location; + + JournalFile *current_file; + uint64_t current_field; + + Match *level0, *level1, *level2; + + pid_t original_pid; + + int inotify_fd; + unsigned current_invalidate_counter, last_invalidate_counter; + usec_t last_process_usec; + + char *unique_field; + JournalFile *unique_file; + uint64_t unique_offset; + + int flags; + + bool on_network; + bool no_new_files; + + size_t data_threshold; + + Hashmap *directories_by_path; + Hashmap *directories_by_wd; + + Set *errors; +}; + +char *journal_make_match_string(sd_journal *j); +void journal_print_header(sd_journal *j); + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_journal*, sd_journal_close); +#define _cleanup_journal_close_ _cleanup_(sd_journal_closep) + +#define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval) \ + for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; ) diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c new file mode 100644 index 0000000..1db66e8 --- /dev/null +++ b/src/journal/journal-qrcode.c @@ -0,0 +1,138 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include + +#include "journal-qrcode.h" + +#define WHITE_ON_BLACK "\033[40;37;1m" +#define NORMAL "\033[0m" + +static void print_border(FILE *output, unsigned width) { + unsigned x, y; + + /* Four rows of border */ + for (y = 0; y < 4; y += 2) { + fputs(WHITE_ON_BLACK, output); + + for (x = 0; x < 4 + width + 4; x++) + fputs("\342\226\210", output); + + fputs(NORMAL "\n", output); + } +} + +int print_qr_code( + FILE *output, + const void *seed, + size_t seed_size, + uint64_t start, + uint64_t interval, + const char *hn, + sd_id128_t machine) { + + FILE *f; + char *url = NULL; + size_t url_size = 0, i; + QRcode* qr; + unsigned x, y; + + assert(seed); + assert(seed_size > 0); + + f = open_memstream(&url, &url_size); + if (!f) + return -ENOMEM; + + fputs("fss://", f); + + for (i = 0; i < seed_size; i++) { + if (i > 0 && i % 3 == 0) + fputc('-', f); + fprintf(f, "%02x", ((uint8_t*) seed)[i]); + } + + fprintf(f, "/%"PRIx64"-%"PRIx64"?machine=" SD_ID128_FORMAT_STR, + start, + interval, + SD_ID128_FORMAT_VAL(machine)); + + if (hn) + fprintf(f, ";hostname=%s", hn); + + if (ferror(f)) { + fclose(f); + free(url); + return -ENOMEM; + } + + fclose(f); + + qr = QRcode_encodeString(url, 0, QR_ECLEVEL_L, QR_MODE_8, 1); + free(url); + + if (!qr) + return -ENOMEM; + + print_border(output, qr->width); + + for (y = 0; y < (unsigned) qr->width; y += 2) { + const uint8_t *row1, *row2; + + row1 = qr->data + qr->width * y; + row2 = row1 + qr->width; + + fputs(WHITE_ON_BLACK, output); + for (x = 0; x < 4; x++) + fputs("\342\226\210", output); + + for (x = 0; x < (unsigned) qr->width; x ++) { + bool a, b; + + a = row1[x] & 1; + b = (y+1) < (unsigned) qr->width ? (row2[x] & 1) : false; + + if (a && b) + fputc(' ', output); + else if (a) + fputs("\342\226\204", output); + else if (b) + fputs("\342\226\200", output); + else + fputs("\342\226\210", output); + } + + for (x = 0; x < 4; x++) + fputs("\342\226\210", output); + fputs(NORMAL "\n", output); + } + + print_border(output, qr->width); + + QRcode_free(qr); + return 0; +} diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h new file mode 100644 index 0000000..da6244c --- /dev/null +++ b/src/journal/journal-qrcode.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include + +int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine); diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c new file mode 100644 index 0000000..ca9199f --- /dev/null +++ b/src/journal/journal-send.c @@ -0,0 +1,572 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#define SD_JOURNAL_SUPPRESS_LOCATION + +#include "sd-journal.h" +#include "util.h" +#include "socket-util.h" + +#define SNDBUF_SIZE (8*1024*1024) + +#define ALLOCA_CODE_FUNC(f, func) \ + do { \ + size_t _fl; \ + const char *_func = (func); \ + char **_f = &(f); \ + _fl = strlen(_func) + 1; \ + *_f = alloca(_fl + 10); \ + memcpy(*_f, "CODE_FUNC=", 10); \ + memcpy(*_f + 10, _func, _fl); \ + } while(false) + +/* We open a single fd, and we'll share it with the current process, + * all its threads, and all its subprocesses. This means we need to + * initialize it atomically, and need to operate on it atomically + * never assuming we are the only user */ + +static int journal_fd(void) { + int fd; + static int fd_plus_one = 0; + +retry: + if (fd_plus_one > 0) + return fd_plus_one - 1; + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + fd_inc_sndbuf(fd, SNDBUF_SIZE); + + if (!__sync_bool_compare_and_swap(&fd_plus_one, 0, fd+1)) { + close_nointr_nofail(fd); + goto retry; + } + + return fd; +} + +_public_ int sd_journal_print(int priority, const char *format, ...) { + int r; + va_list ap; + + va_start(ap, format); + r = sd_journal_printv(priority, format, ap); + va_end(ap); + + return r; +} + +_public_ int sd_journal_printv(int priority, const char *format, va_list ap) { + + /* FIXME: Instead of limiting things to LINE_MAX we could do a + C99 variable-length array on the stack here in a loop. */ + + char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2]; + + assert_return(priority >= 0, -EINVAL); + assert_return(priority <= 7, -EINVAL); + assert_return(format, -EINVAL); + + snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK); + char_array_0(p); + + memcpy(buffer, "MESSAGE=", 8); + vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); + char_array_0(buffer); + + zero(iov); + IOVEC_SET_STRING(iov[0], buffer); + IOVEC_SET_STRING(iov[1], p); + + return sd_journal_sendv(iov, 2); +} + +_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) { + PROTECT_ERRNO; + int r, n = 0, i = 0, j; + struct iovec *iov = NULL; + + assert(_iov); + + if (extra > 0) { + n = MAX(extra * 2, extra + 4); + iov = malloc0(n * sizeof(struct iovec)); + if (!iov) { + r = -ENOMEM; + goto fail; + } + + i = extra; + } + + while (format) { + struct iovec *c; + char *buffer; + va_list aq; + + if (i >= n) { + n = MAX(i*2, 4); + c = realloc(iov, n * sizeof(struct iovec)); + if (!c) { + r = -ENOMEM; + goto fail; + } + + iov = c; + } + + va_copy(aq, ap); + if (vasprintf(&buffer, format, aq) < 0) { + va_end(aq); + r = -ENOMEM; + goto fail; + } + va_end(aq); + + VA_FORMAT_ADVANCE(format, ap); + + IOVEC_SET_STRING(iov[i++], buffer); + + format = va_arg(ap, char *); + } + + *_iov = iov; + + return i; + +fail: + for (j = 0; j < i; j++) + free(iov[j].iov_base); + + free(iov); + + return r; +} + +_public_ int sd_journal_send(const char *format, ...) { + int r, i, j; + va_list ap; + struct iovec *iov = NULL; + + va_start(ap, format); + i = fill_iovec_sprintf(format, ap, 0, &iov); + va_end(ap); + + if (_unlikely_(i < 0)) { + r = i; + goto finish; + } + + r = sd_journal_sendv(iov, i); + +finish: + for (j = 0; j < i; j++) + free(iov[j].iov_base); + + free(iov); + + return r; +} + +_public_ int sd_journal_sendv(const struct iovec *iov, int n) { + PROTECT_ERRNO; + int fd, buffer_fd; + struct iovec *w; + uint64_t *l; + int i, j = 0; + struct sockaddr_un sa = { + .sun_family = AF_UNIX, + .sun_path = "/run/systemd/journal/socket", + }; + struct msghdr mh = { + .msg_name = &sa, + .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path), + }; + ssize_t k; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control; + struct cmsghdr *cmsg; + bool have_syslog_identifier = false; + + assert_return(iov, -EINVAL); + assert_return(n > 0, -EINVAL); + + w = alloca(sizeof(struct iovec) * n * 5 + 3); + l = alloca(sizeof(uint64_t) * n); + + for (i = 0; i < n; i++) { + char *c, *nl; + + if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) + return -EINVAL; + + c = memchr(iov[i].iov_base, '=', iov[i].iov_len); + if (_unlikely_(!c || c == iov[i].iov_base)) + return -EINVAL; + + have_syslog_identifier = have_syslog_identifier || + (c == (char *) iov[i].iov_base + 17 && + startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER")); + + nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); + if (nl) { + if (_unlikely_(nl < c)) + return -EINVAL; + + /* Already includes a newline? Bummer, then + * let's write the variable name, then a + * newline, then the size (64bit LE), followed + * by the data and a final newline */ + + w[j].iov_base = iov[i].iov_base; + w[j].iov_len = c - (char*) iov[i].iov_base; + j++; + + IOVEC_SET_STRING(w[j++], "\n"); + + l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); + w[j].iov_base = &l[i]; + w[j].iov_len = sizeof(uint64_t); + j++; + + w[j].iov_base = c + 1; + w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1; + j++; + + } else + /* Nothing special? Then just add the line and + * append a newline */ + w[j++] = iov[i]; + + IOVEC_SET_STRING(w[j++], "\n"); + } + + if (!have_syslog_identifier && + string_is_safe(program_invocation_short_name)) { + + /* Implicitly add program_invocation_short_name, if it + * is not set explicitly. We only do this for + * program_invocation_short_name, and nothing else + * since everything else is much nicer to retrieve + * from the outside. */ + + IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER="); + IOVEC_SET_STRING(w[j++], program_invocation_short_name); + IOVEC_SET_STRING(w[j++], "\n"); + } + + fd = journal_fd(); + if (_unlikely_(fd < 0)) + return fd; + + mh.msg_iov = w; + mh.msg_iovlen = j; + + k = sendmsg(fd, &mh, MSG_NOSIGNAL); + if (k >= 0) + return 0; + + /* Fail silently if the journal is not available */ + if (errno == ENOENT) + return 0; + + if (errno != EMSGSIZE && errno != ENOBUFS) + return -errno; + + /* Message doesn't fit... Let's dump the data in a temporary + * file and just pass a file descriptor of it to the other + * side. + * + * We use /dev/shm instead of /tmp here, since we want this to + * be a tmpfs, and one that is available from early boot on + * and where unprivileged users can create files. */ + buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC); + if (buffer_fd < 0) + return buffer_fd; + + n = writev(buffer_fd, w, j); + if (n < 0) { + close_nointr_nofail(buffer_fd); + return -errno; + } + + mh.msg_iov = NULL; + mh.msg_iovlen = 0; + + zero(control); + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + k = sendmsg(fd, &mh, MSG_NOSIGNAL); + close_nointr_nofail(buffer_fd); + + if (k < 0) + return -errno; + + return 0; +} + +static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { + PROTECT_ERRNO; + size_t n, k; + + k = isempty(message) ? 0 : strlen(message) + 2; + n = 8 + k + 256 + 1; + + for (;;) { + char buffer[n]; + char* j; + + errno = 0; + j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k); + if (errno == 0) { + char error[6 + 10 + 1]; /* for a 32bit value */ + + if (j != buffer + 8 + k) + memmove(buffer + 8 + k, j, strlen(j)+1); + + memcpy(buffer, "MESSAGE=", 8); + + if (k > 0) { + memcpy(buffer + 8, message, k - 2); + memcpy(buffer + 8 + k - 2, ": ", 2); + } + + snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_); + char_array_0(error); + + IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3"); + IOVEC_SET_STRING(iov[skip+1], buffer); + IOVEC_SET_STRING(iov[skip+2], error); + + return sd_journal_sendv(iov, skip + 3); + } + + if (errno != ERANGE) + return -errno; + + n *= 2; + } +} + +_public_ int sd_journal_perror(const char *message) { + struct iovec iovec[3]; + + return fill_iovec_perror_and_send(message, 0, iovec); +} + +_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/stdout", + }; + int fd; + char *header; + size_t l; + ssize_t r; + + assert_return(priority >= 0, -EINVAL); + assert_return(priority <= 7, -EINVAL); + + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (shutdown(fd, SHUT_RD) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + fd_inc_sndbuf(fd, SNDBUF_SIZE); + + if (!identifier) + identifier = ""; + + l = strlen(identifier); + header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2); + + memcpy(header, identifier, l); + header[l++] = '\n'; + header[l++] = '\n'; /* unit id */ + header[l++] = '0' + priority; + header[l++] = '\n'; + header[l++] = '0' + !!level_prefix; + header[l++] = '\n'; + header[l++] = '0'; + header[l++] = '\n'; + header[l++] = '0'; + header[l++] = '\n'; + header[l++] = '0'; + header[l++] = '\n'; + + r = loop_write(fd, header, l, false); + if (r < 0) { + close_nointr_nofail(fd); + return (int) r; + } + + if ((size_t) r != l) { + close_nointr_nofail(fd); + return -errno; + } + + return fd; +} + +_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) { + int r; + va_list ap; + + va_start(ap, format); + r = sd_journal_printv_with_location(priority, file, line, func, format, ap); + va_end(ap); + + return r; +} + +_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) { + char buffer[8 + LINE_MAX], p[11]; + struct iovec iov[5]; + char *f; + + assert_return(priority >= 0, -EINVAL); + assert_return(priority <= 7, -EINVAL); + assert_return(format, -EINVAL); + + snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK); + char_array_0(p); + + memcpy(buffer, "MESSAGE=", 8); + vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); + char_array_0(buffer); + + /* func is initialized from __func__ which is not a macro, but + * a static const char[], hence cannot easily be prefixed with + * CODE_FUNC=, hence let's do it manually here. */ + ALLOCA_CODE_FUNC(f, func); + + zero(iov); + IOVEC_SET_STRING(iov[0], buffer); + IOVEC_SET_STRING(iov[1], p); + IOVEC_SET_STRING(iov[2], file); + IOVEC_SET_STRING(iov[3], line); + IOVEC_SET_STRING(iov[4], f); + + return sd_journal_sendv(iov, ELEMENTSOF(iov)); +} + +_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) { + int r, i, j; + va_list ap; + struct iovec *iov = NULL; + char *f; + + va_start(ap, format); + i = fill_iovec_sprintf(format, ap, 3, &iov); + va_end(ap); + + if (_unlikely_(i < 0)) { + r = i; + goto finish; + } + + ALLOCA_CODE_FUNC(f, func); + + IOVEC_SET_STRING(iov[0], file); + IOVEC_SET_STRING(iov[1], line); + IOVEC_SET_STRING(iov[2], f); + + r = sd_journal_sendv(iov, i); + +finish: + for (j = 3; j < i; j++) + free(iov[j].iov_base); + + free(iov); + + return r; +} + +_public_ int sd_journal_sendv_with_location( + const char *file, const char *line, + const char *func, + const struct iovec *iov, int n) { + + struct iovec *niov; + char *f; + + assert_return(iov, -EINVAL); + assert_return(n > 0, -EINVAL); + + niov = alloca(sizeof(struct iovec) * (n + 3)); + memcpy(niov, iov, sizeof(struct iovec) * n); + + ALLOCA_CODE_FUNC(f, func); + + IOVEC_SET_STRING(niov[n++], file); + IOVEC_SET_STRING(niov[n++], line); + IOVEC_SET_STRING(niov[n++], f); + + return sd_journal_sendv(niov, n); +} + +_public_ int sd_journal_perror_with_location( + const char *file, const char *line, + const char *func, + const char *message) { + + struct iovec iov[6]; + char *f; + + ALLOCA_CODE_FUNC(f, func); + + IOVEC_SET_STRING(iov[0], file); + IOVEC_SET_STRING(iov[1], line); + IOVEC_SET_STRING(iov[2], f); + + return fill_iovec_perror_and_send(message, 3, iov); +} diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c new file mode 100644 index 0000000..ebe5e42 --- /dev/null +++ b/src/journal/journal-vacuum.c @@ -0,0 +1,339 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#ifdef HAVE_XATTR +#include +#endif + +#include "journal-def.h" +#include "journal-file.h" +#include "journal-vacuum.h" +#include "sd-id128.h" +#include "util.h" + +struct vacuum_info { + uint64_t usage; + char *filename; + + uint64_t realtime; + sd_id128_t seqnum_id; + uint64_t seqnum; + + bool have_seqnum; +}; + +static int vacuum_compare(const void *_a, const void *_b) { + const struct vacuum_info *a, *b; + + a = _a; + b = _b; + + if (a->have_seqnum && b->have_seqnum && + sd_id128_equal(a->seqnum_id, b->seqnum_id)) { + if (a->seqnum < b->seqnum) + return -1; + else if (a->seqnum > b->seqnum) + return 1; + else + return 0; + } + + if (a->realtime < b->realtime) + return -1; + else if (a->realtime > b->realtime) + return 1; + else if (a->have_seqnum && b->have_seqnum) + return memcmp(&a->seqnum_id, &b->seqnum_id, 16); + else + return strcmp(a->filename, b->filename); +} + +static void patch_realtime( + const char *dir, + const char *fn, + const struct stat *st, + unsigned long long *realtime) { + + usec_t x; + +#ifdef HAVE_XATTR + uint64_t crtime; + _cleanup_free_ const char *path = NULL; +#endif + + /* The timestamp was determined by the file name, but let's + * see if the file might actually be older than the file name + * suggested... */ + + assert(dir); + assert(fn); + assert(st); + assert(realtime); + + x = timespec_load(&st->st_ctim); + if (x > 0 && x != (usec_t) -1 && x < *realtime) + *realtime = x; + + x = timespec_load(&st->st_atim); + if (x > 0 && x != (usec_t) -1 && x < *realtime) + *realtime = x; + + x = timespec_load(&st->st_mtim); + if (x > 0 && x != (usec_t) -1 && x < *realtime) + *realtime = x; + +#ifdef HAVE_XATTR + /* Let's read the original creation time, if possible. Ideally + * we'd just query the creation time the FS might provide, but + * unfortunately there's currently no sane API to query + * it. Hence let's implement this manually... */ + + /* Unfortunately there is is not fgetxattrat(), so we need to + * go via path here. :-( */ + + path = strjoin(dir, "/", fn, NULL); + if (!path) + return; + + if (getxattr(path, "user.crtime_usec", &crtime, sizeof(crtime)) == sizeof(crtime)) { + crtime = le64toh(crtime); + + if (crtime > 0 && crtime != (uint64_t) -1 && crtime < *realtime) + *realtime = crtime; + } +#endif +} + +static int journal_file_empty(int dir_fd, const char *name) { + int r; + le64_t n_entries; + _cleanup_close_ int fd; + + fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + if (fd < 0) + return -errno; + + if (lseek(fd, offsetof(Header, n_entries), SEEK_SET) < 0) + return -errno; + + r = read(fd, &n_entries, sizeof(n_entries)); + if (r != sizeof(n_entries)) + return r == 0 ? -EINVAL : -errno; + + return le64toh(n_entries) == 0; +} + +int journal_directory_vacuum( + const char *directory, + uint64_t max_use, + usec_t max_retention_usec, + usec_t *oldest_usec) { + + _cleanup_closedir_ DIR *d = NULL; + int r = 0; + struct vacuum_info *list = NULL; + unsigned n_list = 0, i; + size_t n_allocated = 0; + uint64_t sum = 0, freed = 0; + usec_t retention_limit = 0; + + assert(directory); + + if (max_use <= 0 && max_retention_usec <= 0) + return 0; + + if (max_retention_usec > 0) { + retention_limit = now(CLOCK_REALTIME); + if (retention_limit > max_retention_usec) + retention_limit -= max_retention_usec; + else + max_retention_usec = retention_limit = 0; + } + + d = opendir(directory); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + size_t q; + struct stat st; + char *p; + unsigned long long seqnum = 0, realtime; + sd_id128_t seqnum_id; + bool have_seqnum; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + goto finish; + } + + if (!de) + break; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + continue; + + if (!S_ISREG(st.st_mode)) + continue; + + q = strlen(de->d_name); + + if (endswith(de->d_name, ".journal")) { + + /* Vacuum archived files */ + + if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) + continue; + + if (de->d_name[q-8-16-1] != '-' || + de->d_name[q-8-16-1-16-1] != '-' || + de->d_name[q-8-16-1-16-1-32-1] != '@') + continue; + + p = strdup(de->d_name); + if (!p) { + r = -ENOMEM; + goto finish; + } + + de->d_name[q-8-16-1-16-1] = 0; + if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { + free(p); + continue; + } + + if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { + free(p); + continue; + } + + have_seqnum = true; + + } else if (endswith(de->d_name, ".journal~")) { + unsigned long long tmp; + + /* Vacuum corrupted files */ + + if (q < 1 + 16 + 1 + 16 + 8 + 1) + continue; + + if (de->d_name[q-1-8-16-1] != '-' || + de->d_name[q-1-8-16-1-16-1] != '@') + continue; + + p = strdup(de->d_name); + if (!p) { + r = -ENOMEM; + goto finish; + } + + if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { + free(p); + continue; + } + + have_seqnum = false; + } else + /* We do not vacuum active files or unknown files! */ + continue; + + if (journal_file_empty(dirfd(d), p)) { + /* Always vacuum empty non-online files. */ + + uint64_t size = 512UL * (uint64_t) st.st_blocks; + + if (unlinkat(dirfd(d), p, 0) >= 0) { + log_info("Deleted empty journal %s/%s (%"PRIu64" bytes).", + directory, p, size); + freed += size; + } else if (errno != ENOENT) + log_warning("Failed to delete %s/%s: %m", directory, p); + + free(p); + + continue; + } + + patch_realtime(directory, p, &st, &realtime); + + GREEDY_REALLOC(list, n_allocated, n_list + 1); + + list[n_list].filename = p; + list[n_list].usage = 512UL * (uint64_t) st.st_blocks; + list[n_list].seqnum = seqnum; + list[n_list].realtime = realtime; + list[n_list].seqnum_id = seqnum_id; + list[n_list].have_seqnum = have_seqnum; + + sum += list[n_list].usage; + + n_list ++; + } + + qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare); + + for (i = 0; i < n_list; i++) { + struct statvfs ss; + + if (fstatvfs(dirfd(d), &ss) < 0) { + r = -errno; + goto finish; + } + + if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && + (max_use <= 0 || sum <= max_use)) + break; + + if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { + log_debug("Deleted archived journal %s/%s (%"PRIu64" bytes).", + directory, list[i].filename, list[i].usage); + freed += list[i].usage; + + if (list[i].usage < sum) + sum -= list[i].usage; + else + sum = 0; + + } else if (errno != ENOENT) + log_warning("Failed to delete %s/%s: %m", directory, list[i].filename); + } + + if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec)) + *oldest_usec = list[i].realtime; + +finish: + for (i = 0; i < n_list; i++) + free(list[i].filename); + free(list); + + log_debug("Vacuuming done, freed %"PRIu64" bytes", freed); + + return r; +} diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h new file mode 100644 index 0000000..bc30c3a --- /dev/null +++ b/src/journal/journal-vacuum.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c new file mode 100644 index 0000000..9434cc9 --- /dev/null +++ b/src/journal/journal-verify.c @@ -0,0 +1,1264 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "journal-def.h" +#include "journal-file.h" +#include "journal-authenticate.h" +#include "journal-verify.h" +#include "lookup3.h" +#include "compress.h" +#include "fsprg.h" + +static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) { + uint64_t i; + + assert(f); + assert(offset); + assert(o); + + /* This does various superficial tests about the length an + * possible field values. It does not follow any references to + * other objects. */ + + if ((o->object.flags & OBJECT_COMPRESSED) && + o->object.type != OBJECT_DATA) + return -EBADMSG; + + switch (o->object.type) { + + case OBJECT_DATA: { + uint64_t h1, h2; + + if (le64toh(o->data.entry_offset) == 0) + log_warning(OFSfmt": unused data (entry_offset==0)", offset); + + if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) { + log_error(OFSfmt": bad n_entries: %"PRIu64, offset, o->data.n_entries); + return -EBADMSG; + } + + if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) { + log_error(OFSfmt": bad object size (<= %zu): %"PRIu64, + offset, + offsetof(DataObject, payload), + le64toh(o->object.size)); + return -EBADMSG; + } + + h1 = le64toh(o->data.hash); + + if (o->object.flags & OBJECT_COMPRESSED) { +#ifdef HAVE_XZ + void *b = NULL; + uint64_t alloc = 0, b_size; + + if (!uncompress_blob(o->data.payload, + le64toh(o->object.size) - offsetof(Object, data.payload), + &b, &alloc, &b_size, 0)) { + log_error(OFSfmt": uncompression failed", offset); + return -EBADMSG; + } + + h2 = hash64(b, b_size); + free(b); +#else + log_error("Compression is not supported"); + return -EPROTONOSUPPORT; +#endif + } else + h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload)); + + if (h1 != h2) { + log_error(OFSfmt": invalid hash (%08"PRIx64" vs. %08"PRIx64, offset, h1, h2); + return -EBADMSG; + } + + if (!VALID64(o->data.next_hash_offset) || + !VALID64(o->data.next_field_offset) || + !VALID64(o->data.entry_offset) || + !VALID64(o->data.entry_array_offset)) { + log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, + offset, + o->data.next_hash_offset, + o->data.next_field_offset, + o->data.entry_offset, + o->data.entry_array_offset); + return -EBADMSG; + } + + break; + } + + case OBJECT_FIELD: + if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) { + log_error(OFSfmt": bad field size (<= %zu): %"PRIu64, + offset, + offsetof(FieldObject, payload), + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID64(o->field.next_hash_offset) || + !VALID64(o->field.head_data_offset)) { + log_error(OFSfmt": invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, + offset, + o->field.next_hash_offset, + o->field.head_data_offset); + return -EBADMSG; + } + break; + + case OBJECT_ENTRY: + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) { + log_error(OFSfmt": bad entry size (<= %zu): %"PRIu64, + offset, + offsetof(EntryObject, items), + le64toh(o->object.size)); + return -EBADMSG; + } + + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) { + log_error(OFSfmt": invalid number items in entry: %"PRIu64, + offset, + (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem)); + return -EBADMSG; + } + + if (le64toh(o->entry.seqnum) <= 0) { + log_error(OFSfmt": invalid entry seqnum: %"PRIx64, + offset, + le64toh(o->entry.seqnum)); + return -EBADMSG; + } + + if (!VALID_REALTIME(le64toh(o->entry.realtime))) { + log_error(OFSfmt": invalid entry realtime timestamp: %"PRIu64, + offset, + le64toh(o->entry.realtime)); + return -EBADMSG; + } + + if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) { + log_error(OFSfmt": invalid entry monotonic timestamp: %"PRIu64, + offset, + le64toh(o->entry.monotonic)); + return -EBADMSG; + } + + for (i = 0; i < journal_file_entry_n_items(o); i++) { + if (o->entry.items[i].object_offset == 0 || + !VALID64(o->entry.items[i].object_offset)) { + log_error(OFSfmt": invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, + offset, + i, journal_file_entry_n_items(o), + o->entry.items[i].object_offset); + return -EBADMSG; + } + } + + break; + + case OBJECT_DATA_HASH_TABLE: + case OBJECT_FIELD_HASH_TABLE: + if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 || + (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) { + log_error(OFSfmt": invalid %s hash table size: %"PRIu64, + offset, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + le64toh(o->object.size)); + return -EBADMSG; + } + + for (i = 0; i < journal_file_hash_table_n_items(o); i++) { + if (o->hash_table.items[i].head_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) { + log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, + offset, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset)); + return -EBADMSG; + } + if (o->hash_table.items[i].tail_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) { + log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, + offset, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].tail_hash_offset)); + return -EBADMSG; + } + + if ((o->hash_table.items[i].head_hash_offset != 0) != + (o->hash_table.items[i].tail_hash_offset != 0)) { + log_error(OFSfmt": invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, + offset, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset), + le64toh(o->hash_table.items[i].tail_hash_offset)); + return -EBADMSG; + } + } + + break; + + case OBJECT_ENTRY_ARRAY: + if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 || + (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) { + log_error(OFSfmt": invalid object entry array size: %"PRIu64, + offset, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID64(o->entry_array.next_entry_array_offset)) { + log_error(OFSfmt": invalid object entry array next_entry_array_offset: "OFSfmt, + offset, + o->entry_array.next_entry_array_offset); + return -EBADMSG; + } + + for (i = 0; i < journal_file_entry_array_n_items(o); i++) + if (le64toh(o->entry_array.items[i]) != 0 && + !VALID64(le64toh(o->entry_array.items[i]))) { + log_error(OFSfmt": invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, + offset, + i, journal_file_entry_array_n_items(o), + le64toh(o->entry_array.items[i])); + return -EBADMSG; + } + + break; + + case OBJECT_TAG: + if (le64toh(o->object.size) != sizeof(TagObject)) { + log_error(OFSfmt": invalid object tag size: %"PRIu64, + offset, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID_EPOCH(o->tag.epoch)) { + log_error(OFSfmt": invalid object tag epoch: %"PRIu64, + offset, + o->tag.epoch); + return -EBADMSG; + } + + break; + } + + return 0; +} + +static void draw_progress(uint64_t p, usec_t *last_usec) { + unsigned n, i, j, k; + usec_t z, x; + + if (!on_tty()) + return; + + z = now(CLOCK_MONOTONIC); + x = *last_usec; + + if (x != 0 && x + 40 * USEC_PER_MSEC > z) + return; + + *last_usec = z; + + n = (3 * columns()) / 4; + j = (n * (unsigned) p) / 65535ULL; + k = n - j; + + fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout); + + for (i = 0; i < j; i++) + fputs("\xe2\x96\x88", stdout); + + fputs(ANSI_HIGHLIGHT_OFF, stdout); + + for (i = 0; i < k; i++) + fputs("\xe2\x96\x91", stdout); + + printf(" %3"PRIu64"%%", 100U * p / 65535U); + + fputs("\r\x1B[?25h", stdout); + fflush(stdout); +} + +static void flush_progress(void) { + unsigned n, i; + + if (!on_tty()) + return; + + n = (3 * columns()) / 4; + + putchar('\r'); + + for (i = 0; i < n + 5; i++) + putchar(' '); + + putchar('\r'); + fflush(stdout); +} + +static int write_uint64(int fd, uint64_t p) { + ssize_t k; + + k = write(fd, &p, sizeof(p)); + if (k < 0) + return -errno; + if (k != sizeof(p)) + return -EIO; + + return 0; +} + +static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) { + uint64_t a, b; + int r; + + assert(m); + assert(fd >= 0); + + /* Bisection ... */ + + a = 0; b = n; + while (a < b) { + uint64_t c, *z; + + c = (a + b) / 2; + + r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z); + if (r < 0) + return r; + + if (*z == p) + return 1; + + if (a + 1 >= b) + return 0; + + if (p < *z) + b = c; + else + a = c; + } + + return 0; +} + +static int entry_points_to_data( + JournalFile *f, + int entry_fd, + uint64_t n_entries, + uint64_t entry_p, + uint64_t data_p) { + + int r; + uint64_t i, n, a; + Object *o; + bool found = false; + + assert(f); + assert(entry_fd >= 0); + + if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) { + log_error("Data object references invalid entry at %"PRIu64, data_p); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o); + if (r < 0) + return r; + + n = journal_file_entry_n_items(o); + for (i = 0; i < n; i++) + if (le64toh(o->entry.items[i].object_offset) == data_p) { + found = true; + break; + } + + if (!found) { + log_error("Data object not referenced by linked entry at %"PRIu64, data_p); + return -EBADMSG; + } + + /* Check if this entry is also in main entry array. Since the + * main entry array has already been verified we can rely on + * its consistency.*/ + + i = 0; + n = le64toh(f->header->n_entries); + a = le64toh(f->header->entry_array_offset); + + while (i < n) { + uint64_t m, u; + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + m = journal_file_entry_array_n_items(o); + u = MIN(n - i, m); + + if (entry_p <= le64toh(o->entry_array.items[u-1])) { + uint64_t x, y, z; + + x = 0; + y = u; + + while (x < y) { + z = (x + y) / 2; + + if (le64toh(o->entry_array.items[z]) == entry_p) + return 0; + + if (x + 1 >= y) + break; + + if (entry_p < le64toh(o->entry_array.items[z])) + y = z; + else + x = z; + } + + log_error("Entry object doesn't exist in main entry array at %"PRIu64, entry_p); + return -EBADMSG; + } + + i += u; + a = le64toh(o->entry_array.next_entry_array_offset); + } + + return 0; +} + +static int verify_data( + JournalFile *f, + Object *o, uint64_t p, + int entry_fd, uint64_t n_entries, + int entry_array_fd, uint64_t n_entry_arrays) { + + uint64_t i, n, a, last, q; + int r; + + assert(f); + assert(o); + assert(entry_fd >= 0); + assert(entry_array_fd >= 0); + + n = le64toh(o->data.n_entries); + a = le64toh(o->data.entry_array_offset); + + /* Entry array means at least two objects */ + if (a && n < 2) { + log_error("Entry array present (entry_array_offset=%"PRIu64", but n_entries=%"PRIu64, + a, n); + return -EBADMSG; + } + + if (n == 0) + return 0; + + /* We already checked that earlier */ + assert(o->data.entry_offset); + + last = q = le64toh(o->data.entry_offset); + r = entry_points_to_data(f, entry_fd, n_entries, q, p); + if (r < 0) + return r; + + i = 1; + while (i < n) { + uint64_t next, m, j; + + if (a == 0) { + log_error("Array chain too short at %"PRIu64, p); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { + log_error("Invalid array at %"PRIu64, p); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { + log_error("Array chain has cycle at %"PRIu64, p); + return -EBADMSG; + } + + m = journal_file_entry_array_n_items(o); + for (j = 0; i < n && j < m; i++, j++) { + + q = le64toh(o->entry_array.items[j]); + if (q <= last) { + log_error("Data object's entry array not sorted at %"PRIu64, p); + return -EBADMSG; + } + last = q; + + r = entry_points_to_data(f, entry_fd, n_entries, q, p); + if (r < 0) + return r; + + /* Pointer might have moved, reposition */ + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + } + + a = next; + } + + return 0; +} + +static int verify_hash_table( + JournalFile *f, + int data_fd, uint64_t n_data, + int entry_fd, uint64_t n_entries, + int entry_array_fd, uint64_t n_entry_arrays, + usec_t *last_usec, + bool show_progress) { + + uint64_t i, n; + int r; + + assert(f); + assert(data_fd >= 0); + assert(entry_fd >= 0); + assert(entry_array_fd >= 0); + assert(last_usec); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); + for (i = 0; i < n; i++) { + uint64_t last = 0, p; + + if (show_progress) + draw_progress(0xC000 + (0x3FFF * i / n), last_usec); + + p = le64toh(f->data_hash_table[i].head_hash_offset); + while (p != 0) { + Object *o; + uint64_t next; + + if (!contains_uint64(f->mmap, data_fd, n_data, p)) { + log_error("Invalid data object at hash entry %"PRIu64" of %"PRIu64, + i, n); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + next = le64toh(o->data.next_hash_offset); + if (next != 0 && next <= p) { + log_error("Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, + i, n); + return -EBADMSG; + } + + if (le64toh(o->data.hash) % n != i) { + log_error("Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, + i, n); + return -EBADMSG; + } + + r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays); + if (r < 0) + return r; + + last = p; + p = next; + } + + if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) { + log_error("Tail hash pointer mismatch in hash table"); + return -EBADMSG; + } + } + + return 0; +} + +static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) { + uint64_t n, h, q; + int r; + assert(f); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); + h = hash % n; + + q = le64toh(f->data_hash_table[h].head_hash_offset); + while (q != 0) { + Object *o; + + if (p == q) + return 1; + + r = journal_file_move_to_object(f, OBJECT_DATA, q, &o); + if (r < 0) + return r; + + q = le64toh(o->data.next_hash_offset); + } + + return 0; +} + +static int verify_entry( + JournalFile *f, + Object *o, uint64_t p, + int data_fd, uint64_t n_data) { + + uint64_t i, n; + int r; + + assert(f); + assert(o); + assert(data_fd >= 0); + + n = journal_file_entry_n_items(o); + for (i = 0; i < n; i++) { + uint64_t q, h; + Object *u; + + q = le64toh(o->entry.items[i].object_offset); + h = le64toh(o->entry.items[i].hash); + + if (!contains_uint64(f->mmap, data_fd, n_data, q)) { + log_error("Invalid data object at entry %"PRIu64, p); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_DATA, q, &u); + if (r < 0) + return r; + + if (le64toh(u->data.hash) != h) { + log_error("Hash mismatch for data object at entry %"PRIu64, p); + return -EBADMSG; + } + + r = data_object_in_hash_table(f, h, q); + if (r < 0) + return r; + if (r == 0) { + log_error("Data object missing from hash at entry %"PRIu64, p); + return -EBADMSG; + } + } + + return 0; +} + +static int verify_entry_array( + JournalFile *f, + int data_fd, uint64_t n_data, + int entry_fd, uint64_t n_entries, + int entry_array_fd, uint64_t n_entry_arrays, + usec_t *last_usec, + bool show_progress) { + + uint64_t i = 0, a, n, last = 0; + int r; + + assert(f); + assert(data_fd >= 0); + assert(entry_fd >= 0); + assert(entry_array_fd >= 0); + assert(last_usec); + + n = le64toh(f->header->n_entries); + a = le64toh(f->header->entry_array_offset); + while (i < n) { + uint64_t next, m, j; + Object *o; + + if (show_progress) + draw_progress(0x8000 + (0x3FFF * i / n), last_usec); + + if (a == 0) { + log_error("Array chain too short at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { + log_error("Invalid array at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { + log_error("Array chain has cycle at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + m = journal_file_entry_array_n_items(o); + for (j = 0; i < n && j < m; i++, j++) { + uint64_t p; + + p = le64toh(o->entry_array.items[j]); + if (p <= last) { + log_error("Entry array not sorted at %"PRIu64" of %"PRIu64, + i, n); + return -EBADMSG; + } + last = p; + + if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) { + log_error("Invalid array entry at %"PRIu64" of %"PRIu64, + i, n); + return -EBADMSG; + } + + r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o); + if (r < 0) + return r; + + r = verify_entry(f, o, p, data_fd, n_data); + if (r < 0) + return r; + + /* Pointer might have moved, reposition */ + r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o); + if (r < 0) + return r; + } + + a = next; + } + + return 0; +} + +int journal_file_verify( + JournalFile *f, + const char *key, + usec_t *first_contained, usec_t *last_validated, usec_t *last_contained, + bool show_progress) { + int r; + Object *o; + uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0; + + uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0; + sd_id128_t entry_boot_id; + bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false; + uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0; + usec_t last_usec = 0; + int data_fd = -1, entry_fd = -1, entry_array_fd = -1; + unsigned i; + bool found_last; +#ifdef HAVE_GCRYPT + uint64_t last_tag = 0; +#endif + assert(f); + + if (key) { +#ifdef HAVE_GCRYPT + r = journal_file_parse_verification_key(f, key); + if (r < 0) { + log_error("Failed to parse seed."); + return r; + } +#else + return -ENOTSUP; +#endif + } else if (f->seal) + return -ENOKEY; + + data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + if (data_fd < 0) { + log_error("Failed to create data file: %m"); + r = -errno; + goto fail; + } + + entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + if (entry_fd < 0) { + log_error("Failed to create entry file: %m"); + r = -errno; + goto fail; + } + + entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + if (entry_array_fd < 0) { + log_error("Failed to create entry array file: %m"); + r = -errno; + goto fail; + } + +#ifdef HAVE_GCRYPT + if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0) +#else + if (f->header->compatible_flags != 0) +#endif + { + log_error("Cannot verify file with unknown extensions."); + r = -ENOTSUP; + goto fail; + } + + for (i = 0; i < sizeof(f->header->reserved); i++) + if (f->header->reserved[i] != 0) { + log_error("Reserved field in non-zero."); + r = -EBADMSG; + goto fail; + } + + /* First iteration: we go through all objects, verify the + * superficial structure, headers, hashes. */ + + p = le64toh(f->header->header_size); + while (p != 0) { + if (show_progress) + draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); + + r = journal_file_move_to_object(f, -1, p, &o); + if (r < 0) { + log_error("Invalid object at "OFSfmt, p); + goto fail; + } + + if (p > le64toh(f->header->tail_object_offset)) { + log_error("Invalid tail object pointer"); + r = -EBADMSG; + goto fail; + } + + if (p == le64toh(f->header->tail_object_offset)) + found_last = true; + + n_objects ++; + + r = journal_file_object_verify(f, p, o); + if (r < 0) { + log_error("Invalid object contents at "OFSfmt": %s", p, strerror(-r)); + goto fail; + } + + if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) { + log_error("Compressed object in file without compression at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + switch (o->object.type) { + + case OBJECT_DATA: + r = write_uint64(data_fd, p); + if (r < 0) + goto fail; + + n_data++; + break; + + case OBJECT_FIELD: + n_fields++; + break; + + case OBJECT_ENTRY: + if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) { + log_error("First entry before first tag at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + r = write_uint64(entry_fd, p); + if (r < 0) + goto fail; + + if (le64toh(o->entry.realtime) < last_tag_realtime) { + log_error("Older entry after newer tag at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (!entry_seqnum_set && + le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) { + log_error("Head entry sequence number incorrect at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum >= le64toh(o->entry.seqnum)) { + log_error("Entry sequence number out of synchronization at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + entry_seqnum = le64toh(o->entry.seqnum); + entry_seqnum_set = true; + + if (entry_monotonic_set && + sd_id128_equal(entry_boot_id, o->entry.boot_id) && + entry_monotonic > le64toh(o->entry.monotonic)) { + log_error("Entry timestamp out of synchronization at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + entry_monotonic = le64toh(o->entry.monotonic); + entry_boot_id = o->entry.boot_id; + entry_monotonic_set = true; + + if (!entry_realtime_set && + le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) { + log_error("Head entry realtime timestamp incorrect"); + r = -EBADMSG; + goto fail; + } + + entry_realtime = le64toh(o->entry.realtime); + entry_realtime_set = true; + + n_entries ++; + break; + + case OBJECT_DATA_HASH_TABLE: + if (n_data_hash_tables > 1) { + log_error("More than one data hash table at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) || + le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { + log_error("Header fields for data hash table invalid"); + r = -EBADMSG; + goto fail; + } + + n_data_hash_tables++; + break; + + case OBJECT_FIELD_HASH_TABLE: + if (n_field_hash_tables > 1) { + log_error("More than one field hash table at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) || + le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { + log_error("Header fields for field hash table invalid"); + r = -EBADMSG; + goto fail; + } + + n_field_hash_tables++; + break; + + case OBJECT_ENTRY_ARRAY: + r = write_uint64(entry_array_fd, p); + if (r < 0) + goto fail; + + if (p == le64toh(f->header->entry_array_offset)) { + if (found_main_entry_array) { + log_error("More than one main entry array at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + found_main_entry_array = true; + } + + n_entry_arrays++; + break; + + case OBJECT_TAG: + if (!JOURNAL_HEADER_SEALED(f->header)) { + log_error("Tag object in file without sealing at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.seqnum) != n_tags + 1) { + log_error("Tag sequence number out of synchronization at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.epoch) < last_epoch) { + log_error("Epoch sequence out of synchronization at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + +#ifdef HAVE_GCRYPT + if (f->seal) { + uint64_t q, rt; + + log_debug("Checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); + + rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; + if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) { + log_error("Tag/entry realtime timestamp out of synchronization at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + /* OK, now we know the epoch. So let's now set + * it, and calculate the HMAC for everything + * since the last tag. */ + r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch)); + if (r < 0) + goto fail; + + r = journal_file_hmac_start(f); + if (r < 0) + goto fail; + + if (last_tag == 0) { + r = journal_file_hmac_put_header(f); + if (r < 0) + goto fail; + + q = le64toh(f->header->header_size); + } else + q = last_tag; + + while (q <= p) { + r = journal_file_move_to_object(f, -1, q, &o); + if (r < 0) + goto fail; + + r = journal_file_hmac_put_object(f, -1, o, q); + if (r < 0) + goto fail; + + q = q + ALIGN64(le64toh(o->object.size)); + } + + /* Position might have changed, let's reposition things */ + r = journal_file_move_to_object(f, -1, p, &o); + if (r < 0) + goto fail; + + if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { + log_error("Tag failed verification at "OFSfmt, p); + r = -EBADMSG; + goto fail; + } + + f->hmac_running = false; + last_tag_realtime = rt; + last_sealed_realtime = entry_realtime; + } + + last_tag = p + ALIGN64(le64toh(o->object.size)); +#endif + + last_epoch = le64toh(o->tag.epoch); + + n_tags ++; + break; + + default: + n_weird ++; + } + + if (p == le64toh(f->header->tail_object_offset)) + p = 0; + else + p = p + ALIGN64(le64toh(o->object.size)); + } + + if (!found_last) { + log_error("Tail object pointer dead"); + r = -EBADMSG; + goto fail; + } + + if (n_objects != le64toh(f->header->n_objects)) { + log_error("Object number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (n_entries != le64toh(f->header->n_entries)) { + log_error("Entry number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && + n_data != le64toh(f->header->n_data)) { + log_error("Data number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) && + n_fields != le64toh(f->header->n_fields)) { + log_error("Field number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) && + n_tags != le64toh(f->header->n_tags)) { + log_error("Tag number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) && + n_entry_arrays != le64toh(f->header->n_entry_arrays)) { + log_error("Entry array number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (n_data_hash_tables != 1) { + log_error("Missing data hash table"); + r = -EBADMSG; + goto fail; + } + + if (n_field_hash_tables != 1) { + log_error("Missing field hash table"); + r = -EBADMSG; + goto fail; + } + + if (!found_main_entry_array) { + log_error("Missing entry array"); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum != le64toh(f->header->tail_entry_seqnum)) { + log_error("Invalid tail seqnum"); + r = -EBADMSG; + goto fail; + } + + if (entry_monotonic_set && + (!sd_id128_equal(entry_boot_id, f->header->boot_id) || + entry_monotonic != le64toh(f->header->tail_entry_monotonic))) { + log_error("Invalid tail monotonic timestamp"); + r = -EBADMSG; + goto fail; + } + + if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) { + log_error("Invalid tail realtime timestamp"); + r = -EBADMSG; + goto fail; + } + + /* Second iteration: we follow all objects referenced from the + * two entry points: the object hash table and the entry + * array. We also check that everything referenced (directly + * or indirectly) in the data hash table also exists in the + * entry array, and vice versa. Note that we do not care for + * unreferenced objects. We only care that everything that is + * referenced is consistent. */ + + r = verify_entry_array(f, + data_fd, n_data, + entry_fd, n_entries, + entry_array_fd, n_entry_arrays, + &last_usec, + show_progress); + if (r < 0) + goto fail; + + r = verify_hash_table(f, + data_fd, n_data, + entry_fd, n_entries, + entry_array_fd, n_entry_arrays, + &last_usec, + show_progress); + if (r < 0) + goto fail; + + if (show_progress) + flush_progress(); + + mmap_cache_close_fd(f->mmap, data_fd); + mmap_cache_close_fd(f->mmap, entry_fd); + mmap_cache_close_fd(f->mmap, entry_array_fd); + + close_nointr_nofail(data_fd); + close_nointr_nofail(entry_fd); + close_nointr_nofail(entry_array_fd); + + if (first_contained) + *first_contained = le64toh(f->header->head_entry_realtime); + if (last_validated) + *last_validated = last_sealed_realtime; + if (last_contained) + *last_contained = le64toh(f->header->tail_entry_realtime); + + return 0; + +fail: + if (show_progress) + flush_progress(); + + log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).", + f->path, + p, + (unsigned long long) f->last_stat.st_size, + 100 * p / f->last_stat.st_size); + + if (data_fd >= 0) { + mmap_cache_close_fd(f->mmap, data_fd); + close_nointr_nofail(data_fd); + } + + if (entry_fd >= 0) { + mmap_cache_close_fd(f->mmap, entry_fd); + close_nointr_nofail(entry_fd); + } + + if (entry_array_fd >= 0) { + mmap_cache_close_fd(f->mmap, entry_array_fd); + close_nointr_nofail(entry_array_fd); + } + + return r; +} diff --git a/src/journal/journal-verify.h b/src/journal/journal-verify.h new file mode 100644 index 0000000..e392ab6 --- /dev/null +++ b/src/journal/journal-verify.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journal-file.h" + +int journal_file_verify(JournalFile *f, const char *key, usec_t *first_contained, usec_t *last_validated, usec_t *last_contained, bool show_progress); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c new file mode 100644 index 0000000..a328ba1 --- /dev/null +++ b/src/journal/journalctl.c @@ -0,0 +1,1937 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ACL +#include +#include "acl-util.h" +#endif + +#include + +#include "log.h" +#include "logs-show.h" +#include "util.h" +#include "path-util.h" +#include "fileio.h" +#include "build.h" +#include "pager.h" +#include "strv.h" +#include "set.h" +#include "journal-internal.h" +#include "journal-def.h" +#include "journal-verify.h" +#include "journal-authenticate.h" +#include "journal-qrcode.h" +#include "fsprg.h" +#include "unit-name.h" +#include "catalog.h" + +#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) + +static OutputMode arg_output = OUTPUT_SHORT; +static bool arg_pager_end = false; +static bool arg_follow = false; +static bool arg_full = true; +static bool arg_all = false; +static bool arg_no_pager = false; +static int arg_lines = -1; +static bool arg_no_tail = false; +static bool arg_quiet = false; +static bool arg_merge = false; +static bool arg_boot = false; +static sd_id128_t arg_boot_id = {}; +static int arg_boot_offset = 0; +static bool arg_dmesg = false; +static const char *arg_cursor = NULL; +static const char *arg_after_cursor = NULL; +static bool arg_show_cursor = false; +static const char *arg_directory = NULL; +static char **arg_file = NULL; +static int arg_priorities = 0xFF; +static const char *arg_verify_key = NULL; +#ifdef HAVE_GCRYPT +static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; +static bool arg_force = false; +#endif +static usec_t arg_since, arg_until; +static bool arg_since_set = false, arg_until_set = false; +static char **arg_system_units = NULL; +static char **arg_user_units = NULL; +static const char *arg_field = NULL; +static bool arg_catalog = false; +static bool arg_reverse = false; +static int arg_journal_type = 0; +static const char *arg_root = NULL; +static const char *arg_machine = NULL; + +static enum { + ACTION_SHOW, + ACTION_NEW_ID128, + ACTION_PRINT_HEADER, + ACTION_SETUP_KEYS, + ACTION_VERIFY, + ACTION_DISK_USAGE, + ACTION_LIST_CATALOG, + ACTION_DUMP_CATALOG, + ACTION_UPDATE_CATALOG, + ACTION_LIST_BOOTS, +} arg_action = ACTION_SHOW; + +typedef struct boot_id_t { + sd_id128_t id; + uint64_t first; + uint64_t last; +} boot_id_t; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(arg_pager_end); +} + +static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) { + sd_id128_t id = SD_ID128_NULL; + int off = 0, r; + + if (strlen(x) >= 32) { + char *t; + + t = strndupa(x, 32); + r = sd_id128_from_string(t, &id); + if (r >= 0) + x += 32; + + if (*x != '-' && *x != '+' && *x != 0) + return -EINVAL; + + if (*x != 0) { + r = safe_atoi(x, &off); + if (r < 0) + return r; + } + } else { + r = safe_atoi(x, &off); + if (r < 0) + return r; + } + + if (boot_id) + *boot_id = id; + + if (offset) + *offset = off; + + return 0; +} + +static int help(void) { + + pager_open_if_enabled(); + + printf("%s [OPTIONS...] [MATCHES...]\n\n" + "Query the journal.\n\n" + "Flags:\n" + " --system Show only the system journal\n" + " --user Show only the user journal for the current user\n" + " -M --machine=CONTAINER Operate on local container\n" + " --since=DATE Start showing entries on or newer than the specified date\n" + " --until=DATE Stop showing entries on or older than the specified date\n" + " -c --cursor=CURSOR Start showing entries from the specified cursor\n" + " --after-cursor=CURSOR Start showing entries from after the specified cursor\n" + " --show-cursor Print the cursor after all the entries\n" + " -b --boot[=ID] Show data only from ID or, if unspecified, the current boot\n" + " --list-boots Show terse information about recorded boots\n" + " -k --dmesg Show kernel message log from the current boot\n" + " -u --unit=UNIT Show data only from the specified unit\n" + " --user-unit=UNIT Show data only from the specified user session unit\n" + " -p --priority=RANGE Show only messages within the specified priority range\n" + " -e --pager-end Immediately jump to end of the journal in the pager\n" + " -f --follow Follow the journal\n" + " -n --lines[=INTEGER] Number of journal entries to show\n" + " --no-tail Show all lines, even in follow mode\n" + " -r --reverse Show the newest entries first\n" + " -o --output=STRING Change journal output mode (short, short-iso,\n" + " short-precise, short-monotonic, verbose,\n" + " export, json, json-pretty, json-sse, cat)\n" + " -x --catalog Add message explanations where available\n" + " --no-full Ellipsize fields\n" + " -a --all Show all fields, including long and unprintable\n" + " -q --quiet Do not show privilege warning\n" + " --no-pager Do not pipe output into a pager\n" + " -m --merge Show entries from all available journals\n" + " -D --directory=PATH Show journal files from directory\n" + " --file=PATH Show journal file\n" + " --root=ROOT Operate on catalog files underneath the root ROOT\n" +#ifdef HAVE_GCRYPT + " --interval=TIME Time interval for changing the FSS sealing key\n" + " --verify-key=KEY Specify FSS verification key\n" + " --force Force overriding of the FSS key pair with --setup-keys\n" +#endif + "\nCommands:\n" + " -h --help Show this help text\n" + " --version Show package version\n" + " --new-id128 Generate a new 128-bit ID\n" + " --header Show journal header information\n" + " --disk-usage Show total disk usage of all journal files\n" + " -F --field=FIELD List all values that a specified field takes\n" + " --list-catalog Show message IDs of all entries in the message catalog\n" + " --dump-catalog Show entries in the message catalog\n" + " --update-catalog Update the message catalog database\n" +#ifdef HAVE_GCRYPT + " --setup-keys Generate a new FSS key pair\n" + " --verify Verify journal file consistency\n" +#endif + , program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_FULL, + ARG_NO_TAIL, + ARG_NEW_ID128, + ARG_LIST_BOOTS, + ARG_USER, + ARG_SYSTEM, + ARG_ROOT, + ARG_HEADER, + ARG_SETUP_KEYS, + ARG_FILE, + ARG_INTERVAL, + ARG_VERIFY, + ARG_VERIFY_KEY, + ARG_DISK_USAGE, + ARG_SINCE, + ARG_UNTIL, + ARG_AFTER_CURSOR, + ARG_SHOW_CURSOR, + ARG_USER_UNIT, + ARG_LIST_CATALOG, + ARG_DUMP_CATALOG, + ARG_UPDATE_CATALOG, + ARG_FORCE, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "pager-end", no_argument, NULL, 'e' }, + { "follow", no_argument, NULL, 'f' }, + { "force", no_argument, NULL, ARG_FORCE }, + { "output", required_argument, NULL, 'o' }, + { "all", no_argument, NULL, 'a' }, + { "full", no_argument, NULL, 'l' }, + { "no-full", no_argument, NULL, ARG_NO_FULL }, + { "lines", optional_argument, NULL, 'n' }, + { "no-tail", no_argument, NULL, ARG_NO_TAIL }, + { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, + { "quiet", no_argument, NULL, 'q' }, + { "merge", no_argument, NULL, 'm' }, + { "boot", optional_argument, NULL, 'b' }, + { "list-boots", no_argument, NULL, ARG_LIST_BOOTS }, + { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */ + { "dmesg", no_argument, NULL, 'k' }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "user", no_argument, NULL, ARG_USER }, + { "directory", required_argument, NULL, 'D' }, + { "file", required_argument, NULL, ARG_FILE }, + { "root", required_argument, NULL, ARG_ROOT }, + { "header", no_argument, NULL, ARG_HEADER }, + { "priority", required_argument, NULL, 'p' }, + { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, + { "interval", required_argument, NULL, ARG_INTERVAL }, + { "verify", no_argument, NULL, ARG_VERIFY }, + { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, + { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, + { "cursor", required_argument, NULL, 'c' }, + { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, + { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, + { "since", required_argument, NULL, ARG_SINCE }, + { "until", required_argument, NULL, ARG_UNTIL }, + { "unit", required_argument, NULL, 'u' }, + { "user-unit", required_argument, NULL, ARG_USER_UNIT }, + { "field", required_argument, NULL, 'F' }, + { "catalog", no_argument, NULL, 'x' }, + { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, + { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, + { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG }, + { "reverse", no_argument, NULL, 'r' }, + { "machine", required_argument, NULL, 'M' }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xrM:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case 'e': + arg_pager_end = true; + + if (arg_lines < 0) + arg_lines = 1000; + + break; + + case 'f': + arg_follow = true; + break; + + case 'o': + arg_output = output_mode_from_string(optarg); + if (arg_output < 0) { + log_error("Unknown output format '%s'.", optarg); + return -EINVAL; + } + + if (arg_output == OUTPUT_EXPORT || + arg_output == OUTPUT_JSON || + arg_output == OUTPUT_JSON_PRETTY || + arg_output == OUTPUT_JSON_SSE || + arg_output == OUTPUT_CAT) + arg_quiet = true; + + break; + + case 'l': + arg_full = true; + break; + + case ARG_NO_FULL: + arg_full = false; + break; + + case 'a': + arg_all = true; + break; + + case 'n': + if (optarg) { + r = safe_atoi(optarg, &arg_lines); + if (r < 0 || arg_lines < 0) { + log_error("Failed to parse lines '%s'", optarg); + return -EINVAL; + } + } else { + int n; + + /* 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 positive + * integer... */ + + if (optind < argc && + safe_atoi(argv[optind], &n) >= 0 && + n >= 0) { + + arg_lines = n; + optind++; + } else + arg_lines = 10; + } + + break; + + case ARG_NO_TAIL: + arg_no_tail = true; + break; + + case ARG_NEW_ID128: + arg_action = ACTION_NEW_ID128; + break; + + case 'q': + arg_quiet = true; + break; + + case 'm': + arg_merge = true; + break; + + case 'b': + arg_boot = true; + + 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 { + + /* 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... */ + + if (optind < argc && + parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0) + optind++; + } + + break; + + case ARG_LIST_BOOTS: + arg_action = ACTION_LIST_BOOTS; + break; + + case 'k': + arg_boot = arg_dmesg = true; + break; + + case ARG_SYSTEM: + arg_journal_type |= SD_JOURNAL_SYSTEM; + break; + + case ARG_USER: + arg_journal_type |= SD_JOURNAL_CURRENT_USER; + break; + + case 'M': + arg_machine = optarg; + break; + + case 'D': + arg_directory = optarg; + break; + + case ARG_FILE: + r = glob_extend(&arg_file, optarg); + if (r < 0) { + log_error("Failed to add paths: %s", strerror(-r)); + return r; + }; + break; + + case ARG_ROOT: + arg_root = optarg; + break; + + case 'c': + arg_cursor = optarg; + break; + + case ARG_AFTER_CURSOR: + arg_after_cursor = optarg; + break; + + case ARG_SHOW_CURSOR: + arg_show_cursor = true; + break; + + case ARG_HEADER: + arg_action = ACTION_PRINT_HEADER; + break; + + case ARG_VERIFY: + arg_action = ACTION_VERIFY; + break; + + case ARG_DISK_USAGE: + arg_action = ACTION_DISK_USAGE; + break; + +#ifdef HAVE_GCRYPT + case ARG_FORCE: + arg_force = true; + break; + + case ARG_SETUP_KEYS: + arg_action = ACTION_SETUP_KEYS; + break; + + + case ARG_VERIFY_KEY: + arg_action = ACTION_VERIFY; + arg_verify_key = optarg; + arg_merge = false; + break; + + case ARG_INTERVAL: + r = parse_sec(optarg, &arg_interval); + if (r < 0 || arg_interval <= 0) { + log_error("Failed to parse sealing key change interval: %s", optarg); + return -EINVAL; + } + break; +#else + case ARG_SETUP_KEYS: + case ARG_VERIFY_KEY: + case ARG_INTERVAL: + case ARG_FORCE: + log_error("Forward-secure sealing not available."); + return -ENOTSUP; +#endif + + case 'p': { + const char *dots; + + dots = strstr(optarg, ".."); + if (dots) { + char *a; + int from, to, i; + + /* a range */ + a = strndup(optarg, dots - optarg); + if (!a) + return log_oom(); + + from = log_level_from_string(a); + to = log_level_from_string(dots + 2); + free(a); + + if (from < 0 || to < 0) { + log_error("Failed to parse log level range %s", optarg); + return -EINVAL; + } + + arg_priorities = 0; + + if (from < to) { + for (i = from; i <= to; i++) + arg_priorities |= 1 << i; + } else { + for (i = to; i <= from; i++) + arg_priorities |= 1 << i; + } + + } else { + int p, i; + + p = log_level_from_string(optarg); + if (p < 0) { + log_error("Unknown log level %s", optarg); + return -EINVAL; + } + + arg_priorities = 0; + + for (i = 0; i <= p; i++) + arg_priorities |= 1 << i; + } + + break; + } + + case ARG_SINCE: + r = parse_timestamp(optarg, &arg_since); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); + return -EINVAL; + } + arg_since_set = true; + break; + + case ARG_UNTIL: + r = parse_timestamp(optarg, &arg_until); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); + return -EINVAL; + } + arg_until_set = true; + break; + + case 'u': + r = strv_extend(&arg_system_units, optarg); + if (r < 0) + return log_oom(); + break; + + case ARG_USER_UNIT: + r = strv_extend(&arg_user_units, optarg); + if (r < 0) + return log_oom(); + break; + + case 'F': + arg_field = optarg; + break; + + case 'x': + arg_catalog = true; + break; + + case ARG_LIST_CATALOG: + arg_action = ACTION_LIST_CATALOG; + break; + + case ARG_DUMP_CATALOG: + arg_action = ACTION_DUMP_CATALOG; + break; + + case ARG_UPDATE_CATALOG: + arg_action = ACTION_UPDATE_CATALOG; + break; + + case 'r': + arg_reverse = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (arg_follow && !arg_no_tail && arg_lines < 0) + arg_lines = 10; + + if (!!arg_directory + !!arg_file + !!arg_machine > 1) { + log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one."); + return -EINVAL; + } + + if (arg_since_set && arg_until_set && arg_since > arg_until) { + log_error("--since= must be before --until=."); + return -EINVAL; + } + + if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) { + log_error("Please specify only one of --since=, --cursor=, and --after-cursor."); + return -EINVAL; + } + + if (arg_follow && arg_reverse) { + log_error("Please specify either --reverse= or --follow=, not both."); + return -EINVAL; + } + + return 1; +} + +static int generate_new_id128(void) { + sd_id128_t id; + int r; + unsigned i; + + r = sd_id128_randomize(&id); + if (r < 0) { + log_error("Failed to generate ID: %s", strerror(-r)); + return r; + } + + printf("As string:\n" + SD_ID128_FORMAT_STR "\n\n" + "As UUID:\n" + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n" + "As macro:\n" + "#define MESSAGE_XYZ SD_ID128_MAKE(", + SD_ID128_FORMAT_VAL(id), + SD_ID128_FORMAT_VAL(id)); + for (i = 0; i < 16; i++) + printf("%02x%s", id.bytes[i], i != 15 ? "," : ""); + fputs(")\n\n", stdout); + + printf("As Python constant:\n" + ">>> import uuid\n" + ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n", + SD_ID128_FORMAT_VAL(id)); + + return 0; +} + +static int add_matches(sd_journal *j, char **args) { + char **i; + + assert(j); + + STRV_FOREACH(i, args) { + int r; + + if (streq(*i, "+")) + r = sd_journal_add_disjunction(j); + else if (path_is_absolute(*i)) { + _cleanup_free_ char *p, *t = NULL, *t2 = NULL; + const char *path; + _cleanup_free_ char *interpreter = NULL; + struct stat st; + + p = canonicalize_file_name(*i); + path = p ? p : *i; + + if (stat(path, &st) < 0) { + log_error("Couldn't stat file: %m"); + return -errno; + } + + if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) { + if (executable_is_script(path, &interpreter) > 0) { + _cleanup_free_ char *comm; + + comm = strndup(basename(path), 15); + if (!comm) + return log_oom(); + + t = strappend("_COMM=", comm); + + /* Append _EXE only if the interpreter is not a link. + Otherwise, it might be outdated often. */ + if (lstat(interpreter, &st) == 0 && + !S_ISLNK(st.st_mode)) { + t2 = strappend("_EXE=", interpreter); + if (!t2) + return log_oom(); + } + } else + t = strappend("_EXE=", path); + } else if (S_ISCHR(st.st_mode)) + asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev)); + else if (S_ISBLK(st.st_mode)) + asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev)); + else { + log_error("File is neither a device node, nor regular file, nor executable: %s", *i); + return -EINVAL; + } + + if (!t) + return log_oom(); + + r = sd_journal_add_match(j, t, 0); + if (t2) + r = sd_journal_add_match(j, t2, 0); + } else + r = sd_journal_add_match(j, *i, 0); + + if (r < 0) { + log_error("Failed to add match '%s': %s", *i, strerror(-r)); + return r; + } + } + + return 0; +} + +static int boot_id_cmp(const void *a, const void *b) { + uint64_t _a, _b; + + _a = ((const boot_id_t *)a)->first; + _b = ((const boot_id_t *)b)->first; + + return _a < _b ? -1 : (_a > _b ? 1 : 0); +} + +static int list_boots(sd_journal *j) { + int r; + const void *data; + unsigned int count = 0; + int w, i; + size_t length, allocated = 0; + boot_id_t *id; + _cleanup_free_ boot_id_t *all_ids = NULL; + + r = sd_journal_query_unique(j, "_BOOT_ID"); + if (r < 0) + return r; + + SD_JOURNAL_FOREACH_UNIQUE(j, data, length) { + if (length < strlen("_BOOT_ID=")) + continue; + + if (!GREEDY_REALLOC(all_ids, allocated, count + 1)) + return log_oom(); + + id = &all_ids[count]; + + r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id); + if (r < 0) + continue; + + r = sd_journal_add_match(j, data, length); + if (r < 0) + return r; + + r = sd_journal_seek_head(j); + if (r < 0) + return r; + + r = sd_journal_next(j); + if (r < 0) + return r; + else if (r == 0) + goto flush; + + r = sd_journal_get_realtime_usec(j, &id->first); + if (r < 0) + return r; + + r = sd_journal_seek_tail(j); + if (r < 0) + return r; + + r = sd_journal_previous(j); + if (r < 0) + return r; + else if (r == 0) + goto flush; + + r = sd_journal_get_realtime_usec(j, &id->last); + if (r < 0) + return r; + + count++; + flush: + sd_journal_flush_matches(j); + } + + qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp); + + /* numbers are one less, but we need an extra char for the sign */ + w = DECIMAL_STR_WIDTH(count - 1) + 1; + + for (id = all_ids, i = 0; id < all_ids + count; id++, i++) { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX]; + + printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", + w, i - count + 1, + SD_ID128_FORMAT_VAL(id->id), + format_timestamp(a, sizeof(a), id->first), + format_timestamp(b, sizeof(b), id->last)); + } + + return 0; +} + +static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) { + int r; + const void *data; + unsigned int count = 0; + size_t length, allocated = 0; + boot_id_t ref_boot_id = {SD_ID128_NULL}, *id; + _cleanup_free_ boot_id_t *all_ids = NULL; + + assert(j); + assert(boot_id); + + r = sd_journal_query_unique(j, "_BOOT_ID"); + if (r < 0) + return r; + + SD_JOURNAL_FOREACH_UNIQUE(j, data, length) { + if (length < strlen("_BOOT_ID=")) + continue; + + if (!GREEDY_REALLOC(all_ids, allocated, count + 1)) + return log_oom(); + + id = &all_ids[count]; + + r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id); + if (r < 0) + continue; + + r = sd_journal_add_match(j, data, length); + if (r < 0) + return r; + + r = sd_journal_seek_head(j); + if (r < 0) + return r; + + r = sd_journal_next(j); + if (r < 0) + return r; + else if (r == 0) + goto flush; + + r = sd_journal_get_realtime_usec(j, &id->first); + if (r < 0) + return r; + + if (sd_id128_equal(id->id, *boot_id)) + ref_boot_id = *id; + + count++; + flush: + sd_journal_flush_matches(j); + } + + qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp); + + if (sd_id128_equal(*boot_id, SD_ID128_NULL)) { + if (relative > (int) count || relative <= -(int)count) + return -EADDRNOTAVAIL; + + *boot_id = all_ids[(relative <= 0)*count + relative - 1].id; + } else { + id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp); + + if (!id || + relative <= 0 ? (id - all_ids) + relative < 0 : + (id - all_ids) + relative >= (int) count) + return -EADDRNOTAVAIL; + + *boot_id = (id + relative)->id; + } + + return 0; +} + +static int add_boot(sd_journal *j) { + char match[9+32+1] = "_BOOT_ID="; + int r; + + assert(j); + + if (!arg_boot) + return 0; + + if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL)) + return add_match_this_boot(j, arg_machine); + + r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset); + if (r < 0) { + if (sd_id128_equal(arg_boot_id, SD_ID128_NULL)) + log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r)); + else + log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", + SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r)); + return r; + } + + sd_id128_to_string(arg_boot_id, match + 9); + + r = sd_journal_add_match(j, match, sizeof(match) - 1); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + + r = sd_journal_add_conjunction(j); + if (r < 0) + return r; + + return 0; +} + +static int add_dmesg(sd_journal *j) { + int r; + assert(j); + + if (!arg_dmesg) + return 0; + + r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel")); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + + r = sd_journal_add_conjunction(j); + if (r < 0) + return r; + + return 0; +} + +static int get_possible_units(sd_journal *j, + const char *fields, + char **patterns, + Set **units) { + _cleanup_set_free_free_ Set *found; + const char *field; + int r; + + found = set_new(string_hash_func, string_compare_func); + if (!found) + return log_oom(); + + NULSTR_FOREACH(field, fields) { + const void *data; + size_t size; + + r = sd_journal_query_unique(j, field); + if (r < 0) + return r; + + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { + char **pattern, *eq; + size_t prefix; + _cleanup_free_ char *u = NULL; + + eq = memchr(data, '=', size); + if (eq) + prefix = eq - (char*) data + 1; + else + prefix = 0; + + u = strndup((char*) data + prefix, size - prefix); + if (!u) + return log_oom(); + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) { + log_debug("Matched %s with pattern %s=%s", u, field, *pattern); + + r = set_consume(found, u); + u = NULL; + if (r < 0 && r != -EEXIST) + return r; + + break; + } + } + } + + *units = found; + found = NULL; + return 0; +} + +/* This list is supposed to return the superset of unit names + * possibly matched by rules added with add_matches_for_unit... */ +#define SYSTEM_UNITS \ + "_SYSTEMD_UNIT\0" \ + "COREDUMP_UNIT\0" \ + "UNIT\0" \ + "OBJECT_SYSTEMD_UNIT\0" \ + "_SYSTEMD_SLICE\0" + +/* ... and add_matches_for_user_unit */ +#define USER_UNITS \ + "_SYSTEMD_USER_UNIT\0" \ + "USER_UNIT\0" \ + "COREDUMP_USER_UNIT\0" \ + "OBJECT_SYSTEMD_USER_UNIT\0" + +static int add_units(sd_journal *j) { + _cleanup_strv_free_ char **patterns = NULL; + int r, count = 0; + char **i; + + assert(j); + + STRV_FOREACH(i, arg_system_units) { + _cleanup_free_ char *u = NULL; + + u = unit_name_mangle(*i, MANGLE_GLOB); + if (!u) + return log_oom(); + + if (string_is_glob(u)) { + r = strv_push(&patterns, u); + if (r < 0) + return r; + u = NULL; + } else { + r = add_matches_for_unit(j, u); + if (r < 0) + return r; + r = sd_journal_add_disjunction(j); + if (r < 0) + return r; + count ++; + } + } + + if (!strv_isempty(patterns)) { + _cleanup_set_free_free_ Set *units = NULL; + Iterator it; + char *u; + + r = get_possible_units(j, SYSTEM_UNITS, patterns, &units); + if (r < 0) + return r; + + SET_FOREACH(u, units, it) { + r = add_matches_for_unit(j, u); + if (r < 0) + return r; + r = sd_journal_add_disjunction(j); + if (r < 0) + return r; + count ++; + } + } + + strv_free(patterns); + patterns = NULL; + + STRV_FOREACH(i, arg_user_units) { + _cleanup_free_ char *u = NULL; + + u = unit_name_mangle(*i, MANGLE_GLOB); + if (!u) + return log_oom(); + + if (string_is_glob(u)) { + r = strv_push(&patterns, u); + if (r < 0) + return r; + u = NULL; + } else { + r = add_matches_for_user_unit(j, u, getuid()); + if (r < 0) + return r; + r = sd_journal_add_disjunction(j); + if (r < 0) + return r; + count ++; + } + } + + if (!strv_isempty(patterns)) { + _cleanup_set_free_free_ Set *units = NULL; + Iterator it; + char *u; + + r = get_possible_units(j, USER_UNITS, patterns, &units); + if (r < 0) + return r; + + SET_FOREACH(u, units, it) { + r = add_matches_for_user_unit(j, u, getuid()); + if (r < 0) + return r; + r = sd_journal_add_disjunction(j); + if (r < 0) + return r; + count ++; + } + } + + /* Complain if the user request matches but nothing whatsoever was + * found, since otherwise everything would be matched. */ + if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0) + return -ENODATA; + + r = sd_journal_add_conjunction(j); + if (r < 0) + return r; + + return 0; +} + +static int add_priorities(sd_journal *j) { + char match[] = "PRIORITY=0"; + int i, r; + assert(j); + + if (arg_priorities == 0xFF) + return 0; + + for (i = LOG_EMERG; i <= LOG_DEBUG; i++) + if (arg_priorities & (1 << i)) { + match[sizeof(match)-2] = '0' + i; + + r = sd_journal_add_match(j, match, strlen(match)); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + } + + r = sd_journal_add_conjunction(j); + if (r < 0) + return r; + + return 0; +} + +static int setup_keys(void) { +#ifdef HAVE_GCRYPT + size_t mpk_size, seed_size, state_size, i; + uint8_t *mpk, *seed, *state; + ssize_t l; + int fd = -1, r, attr = 0; + sd_id128_t machine, boot; + char *p = NULL, *k = NULL; + struct FSSHeader h; + uint64_t n; + struct stat st; + + r = stat("/var/log/journal", &st); + if (r < 0 && errno != ENOENT && errno != ENOTDIR) { + log_error("stat(\"%s\") failed: %m", "/var/log/journal"); + return -errno; + } + + if (r < 0 || !S_ISDIR(st.st_mode)) { + log_error("%s is not a directory, must be using persistent logging for FSS.", + "/var/log/journal"); + return r < 0 ? -errno : -ENOTDIR; + } + + r = sd_id128_get_machine(&machine); + if (r < 0) { + log_error("Failed to get machine ID: %s", strerror(-r)); + return r; + } + + r = sd_id128_get_boot(&boot); + if (r < 0) { + log_error("Failed to get boot ID: %s", strerror(-r)); + return r; + } + + if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss", + SD_ID128_FORMAT_VAL(machine)) < 0) + return log_oom(); + + if (access(p, F_OK) >= 0) { + if (arg_force) { + r = unlink(p); + if (r < 0) { + log_error("unlink(\"%s\") failed: %m", p); + r = -errno; + goto finish; + } + } else { + log_error("Sealing key file %s exists already. (--force to recreate)", p); + r = -EEXIST; + goto finish; + } + } + + if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX", + SD_ID128_FORMAT_VAL(machine)) < 0) { + r = log_oom(); + goto finish; + } + + mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR); + mpk = alloca(mpk_size); + + seed_size = FSPRG_RECOMMENDED_SEEDLEN; + seed = alloca(seed_size); + + state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR); + state = alloca(state_size); + + fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + log_error("Failed to open /dev/random: %m"); + r = -errno; + goto finish; + } + + log_info("Generating seed..."); + l = loop_read(fd, seed, seed_size, true); + if (l < 0 || (size_t) l != seed_size) { + log_error("Failed to read random seed: %s", strerror(EIO)); + r = -EIO; + goto finish; + } + + log_info("Generating key pair..."); + FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR); + + log_info("Generating sealing key..."); + FSPRG_GenState0(state, mpk, seed, seed_size); + + assert(arg_interval > 0); + + n = now(CLOCK_REALTIME); + n /= arg_interval; + + close_nointr_nofail(fd); + fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to open %s: %m", k); + r = -errno; + goto finish; + } + + /* Enable secure remove, exclusion from dump, synchronous + * writing and in-place updating */ + if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0) + log_warning("FS_IOC_GETFLAGS failed: %m"); + + attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL; + + if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0) + log_warning("FS_IOC_SETFLAGS failed: %m"); + + zero(h); + memcpy(h.signature, "KSHHRHLP", 8); + h.machine_id = machine; + h.boot_id = boot; + h.header_size = htole64(sizeof(h)); + h.start_usec = htole64(n * arg_interval); + h.interval_usec = htole64(arg_interval); + h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR); + h.fsprg_state_size = htole64(state_size); + + l = loop_write(fd, &h, sizeof(h), false); + if (l < 0 || (size_t) l != sizeof(h)) { + log_error("Failed to write header: %s", strerror(EIO)); + r = -EIO; + goto finish; + } + + l = loop_write(fd, state, state_size, false); + if (l < 0 || (size_t) l != state_size) { + log_error("Failed to write state: %s", strerror(EIO)); + r = -EIO; + goto finish; + } + + if (link(k, p) < 0) { + log_error("Failed to link file: %m"); + r = -errno; + goto finish; + } + + if (on_tty()) { + fprintf(stderr, + "\n" + "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n" + "the following local file. This key file is automatically updated when the\n" + "sealing key is advanced. It should not be used on multiple hosts.\n" + "\n" + "\t%s\n" + "\n" + "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n" + "at a safe location and should not be saved locally on disk.\n" + "\n\t" ANSI_HIGHLIGHT_RED_ON, p); + fflush(stderr); + } + for (i = 0; i < seed_size; i++) { + if (i > 0 && i % 3 == 0) + putchar('-'); + printf("%02x", ((uint8_t*) seed)[i]); + } + + printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval); + + if (on_tty()) { + char tsb[FORMAT_TIMESPAN_MAX], *hn; + + fprintf(stderr, + ANSI_HIGHLIGHT_OFF "\n" + "The sealing key is automatically changed every %s.\n", + format_timespan(tsb, sizeof(tsb), arg_interval, 0)); + + hn = gethostname_malloc(); + + if (hn) { + hostname_cleanup(hn, false); + fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine)); + } else + fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine)); + +#ifdef HAVE_QRENCODE + /* If this is not an UTF-8 system don't print any QR codes */ + if (is_locale_utf8()) { + fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr); + print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine); + } +#endif + free(hn); + } + + r = 0; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + if (k) { + unlink(k); + free(k); + } + + free(p); + + return r; +#else + log_error("Forward-secure sealing not available."); + return -ENOTSUP; +#endif +} + +static int verify(sd_journal *j) { + int r = 0; + Iterator i; + JournalFile *f; + + assert(j); + + log_show_color(true); + + HASHMAP_FOREACH(f, j->files, i) { + int k; + usec_t first, validated, last; + +#ifdef HAVE_GCRYPT + if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) + log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path); +#endif + + k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true); + if (k == -EINVAL) { + /* If the key was invalid give up right-away. */ + return k; + } else if (k < 0) { + log_warning("FAIL: %s (%s)", f->path, strerror(-k)); + r = k; + } else { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX]; + log_info("PASS: %s", f->path); + + if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) { + if (validated > 0) { + log_info("=> Validated from %s to %s, final %s entries not sealed.", + format_timestamp(a, sizeof(a), first), + format_timestamp(b, sizeof(b), validated), + format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0)); + } else if (last > 0) + log_info("=> No sealing yet, %s of entries not sealed.", + format_timespan(c, sizeof(c), last - first, 0)); + else + log_info("=> No sealing yet, no entries in file."); + } + } + } + + return r; +} + +#ifdef HAVE_ACL +static int access_check_var_log_journal(sd_journal *j) { + _cleanup_strv_free_ char **g = NULL; + bool have_access; + int r; + + assert(j); + + have_access = in_group("systemd-journal") > 0; + + if (!have_access) { + /* Let's enumerate all groups from the default ACL of + * the directory, which generally should allow access + * to most journal files too */ + r = search_acl_groups(&g, "/var/log/journal/", &have_access); + if (r < 0) + return r; + } + + if (!have_access) { + + if (strv_isempty(g)) + log_notice("Hint: You are currently not seeing messages from other users and the system.\n" + " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" + " turn off this notice."); + else { + _cleanup_free_ char *s = NULL; + + r = strv_extend(&g, "systemd-journal"); + if (r < 0) + return log_oom(); + + strv_sort(g); + strv_uniq(g); + + s = strv_join(g, "', '"); + if (!s) + return log_oom(); + + log_notice("Hint: You are currently not seeing messages from other users and the system.\n" + " Users in the groups '%s' can see all messages.\n" + " Pass -q to turn off this notice.", s); + } + } + + return 0; +} +#endif + +static int access_check(sd_journal *j) { + Iterator it; + void *code; + int r = 0; + + assert(j); + + if (set_isempty(j->errors)) { + if (hashmap_isempty(j->files)) + log_notice("No journal files were found."); + return 0; + } + + if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { +#ifdef HAVE_ACL + /* If /var/log/journal doesn't even exist, + * unprivileged users have no access at all */ + if (access("/var/log/journal", F_OK) < 0 && + geteuid() != 0 && + in_group("systemd-journal") <= 0) { + log_error("Unprivileged users cannot access messages, unless persistent log storage is\n" + "enabled. Users in the 'systemd-journal' group may always access messages."); + return -EACCES; + } + + /* If /var/log/journal exists, try to pring a nice + notice if the user lacks access to it */ + if (!arg_quiet && geteuid() != 0) { + r = access_check_var_log_journal(j); + if (r < 0) + return r; + } +#else + if (geteuid() != 0 && in_group("systemd-journal") <= 0) { + log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n" + "group may access messages."); + return -EACCES; + } +#endif + + if (hashmap_isempty(j->files)) { + log_error("No journal files were opened due to insufficient permissions."); + r = -EACCES; + } + } + + SET_FOREACH(code, j->errors, it) { + int err; + + err = -PTR_TO_INT(code); + assert(err > 0); + + if (err != EACCES) + log_warning("Error was encountered while opening journal files: %s", + strerror(err)); + } + + return r; +} + +int main(int argc, char *argv[]) { + int r; + _cleanup_journal_close_ sd_journal *j = NULL; + bool need_seek = false; + sd_id128_t previous_boot_id; + bool previous_boot_id_valid = false, first_line = true; + int n_shown = 0; + bool ellipsized = false; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + signal(SIGWINCH, columns_lines_cache_reset); + + if (arg_action == ACTION_NEW_ID128) { + r = generate_new_id128(); + goto finish; + } + + if (arg_action == ACTION_SETUP_KEYS) { + r = setup_keys(); + goto finish; + } + + if (arg_action == ACTION_UPDATE_CATALOG || + arg_action == ACTION_LIST_CATALOG || + arg_action == ACTION_DUMP_CATALOG) { + + const char* database = CATALOG_DATABASE; + _cleanup_free_ char *copy = NULL; + if (arg_root) { + copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL); + if (!copy) { + r = log_oom(); + goto finish; + } + path_kill_slashes(copy); + database = copy; + } + + if (arg_action == ACTION_UPDATE_CATALOG) { + r = catalog_update(database, arg_root, catalog_file_dirs); + if (r < 0) + log_error("Failed to list catalog: %s", strerror(-r)); + } else { + bool oneline = arg_action == ACTION_LIST_CATALOG; + + if (optind < argc) + r = catalog_list_items(stdout, database, + oneline, argv + optind); + else + r = catalog_list(stdout, database, oneline); + if (r < 0) + log_error("Failed to list catalog: %s", strerror(-r)); + } + + goto finish; + } + + if (arg_directory) + r = sd_journal_open_directory(&j, arg_directory, arg_journal_type); + else if (arg_file) + r = sd_journal_open_files(&j, (const char**) arg_file, 0); + else if (arg_machine) + r = sd_journal_open_container(&j, arg_machine, 0); + else + r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); + if (r < 0) { + log_error("Failed to open %s: %s", + arg_directory ? arg_directory : arg_file ? "files" : "journal", + strerror(-r)); + return EXIT_FAILURE; + } + + r = access_check(j); + if (r < 0) + return EXIT_FAILURE; + + if (arg_action == ACTION_VERIFY) { + r = verify(j); + goto finish; + } + + if (arg_action == ACTION_PRINT_HEADER) { + journal_print_header(j); + return EXIT_SUCCESS; + } + + if (arg_action == ACTION_DISK_USAGE) { + uint64_t bytes = 0; + char sbytes[FORMAT_BYTES_MAX]; + + r = sd_journal_get_usage(j, &bytes); + if (r < 0) + return EXIT_FAILURE; + + printf("Journals take up %s on disk.\n", + format_bytes(sbytes, sizeof(sbytes), bytes)); + return EXIT_SUCCESS; + } + + if (arg_action == ACTION_LIST_BOOTS) { + r = list_boots(j); + goto finish; + } + + /* add_boot() must be called first! + * It may need to seek the journal to find parent boot IDs. */ + r = add_boot(j); + if (r < 0) + return EXIT_FAILURE; + + r = add_dmesg(j); + if (r < 0) + return EXIT_FAILURE; + + r = add_units(j); + strv_free(arg_system_units); + strv_free(arg_user_units); + + if (r < 0) { + log_error("Failed to add filter for units: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = add_priorities(j); + if (r < 0) { + log_error("Failed to add filter for priorities: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = add_matches(j, argv + optind); + if (r < 0) { + log_error("Failed to add filters: %s", strerror(-r)); + return EXIT_FAILURE; + } + + if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + _cleanup_free_ char *filter; + + filter = journal_make_match_string(j); + log_debug("Journal filter: %s", filter); + } + + if (arg_field) { + const void *data; + size_t size; + + r = sd_journal_set_data_threshold(j, 0); + if (r < 0) { + log_error("Failed to unset data size threshold"); + return EXIT_FAILURE; + } + + r = sd_journal_query_unique(j, arg_field); + if (r < 0) { + log_error("Failed to query unique data objects: %s", strerror(-r)); + return EXIT_FAILURE; + } + + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { + const void *eq; + + if (arg_lines >= 0 && n_shown >= arg_lines) + break; + + eq = memchr(data, '=', size); + if (eq) + printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1); + else + printf("%.*s\n", (int) size, (const char*) data); + + n_shown ++; + } + + return EXIT_SUCCESS; + } + + /* Opening the fd now means the first sd_journal_wait() will actually wait */ + if (arg_follow) { + r = sd_journal_get_fd(j); + if (r < 0) + return EXIT_FAILURE; + } + + if (arg_cursor || arg_after_cursor) { + r = sd_journal_seek_cursor(j, arg_cursor ? arg_cursor : arg_after_cursor); + if (r < 0) { + log_error("Failed to seek to cursor: %s", strerror(-r)); + return EXIT_FAILURE; + } + if (!arg_reverse) + r = sd_journal_next_skip(j, 1 + !!arg_after_cursor); + else + r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor); + + if (arg_after_cursor && r < 2 && !arg_follow) + /* We couldn't find the next entry after the cursor. */ + arg_lines = 0; + + } else if (arg_since_set && !arg_reverse) { + r = sd_journal_seek_realtime_usec(j, arg_since); + if (r < 0) { + log_error("Failed to seek to date: %s", strerror(-r)); + return EXIT_FAILURE; + } + r = sd_journal_next(j); + + } else if (arg_until_set && arg_reverse) { + r = sd_journal_seek_realtime_usec(j, arg_until); + if (r < 0) { + log_error("Failed to seek to date: %s", strerror(-r)); + return EXIT_FAILURE; + } + r = sd_journal_previous(j); + + } else if (arg_lines >= 0) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error("Failed to seek to tail: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = sd_journal_previous_skip(j, arg_lines); + + } else if (arg_reverse) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error("Failed to seek to tail: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = sd_journal_previous(j); + + } else { + r = sd_journal_seek_head(j); + if (r < 0) { + log_error("Failed to seek to head: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = sd_journal_next(j); + } + + if (r < 0) { + log_error("Failed to iterate through journal: %s", strerror(-r)); + return EXIT_FAILURE; + } + + if (!arg_follow) + pager_open_if_enabled(); + + if (!arg_quiet) { + usec_t start, end; + char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX]; + + r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); + if (r < 0) { + log_error("Failed to get cutoff: %s", strerror(-r)); + goto finish; + } + + if (r > 0) { + if (arg_follow) + printf("-- Logs begin at %s. --\n", + format_timestamp(start_buf, sizeof(start_buf), start)); + else + printf("-- Logs begin at %s, end at %s. --\n", + format_timestamp(start_buf, sizeof(start_buf), start), + format_timestamp(end_buf, sizeof(end_buf), end)); + } + } + + for (;;) { + while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) { + int flags; + + if (need_seek) { + if (!arg_reverse) + r = sd_journal_next(j); + else + r = sd_journal_previous(j); + if (r < 0) { + log_error("Failed to iterate through journal: %s", strerror(-r)); + goto finish; + } + if (r == 0) + break; + } + + if (arg_until_set && !arg_reverse) { + usec_t usec; + + r = sd_journal_get_realtime_usec(j, &usec); + if (r < 0) { + log_error("Failed to determine timestamp: %s", strerror(-r)); + goto finish; + } + if (usec > arg_until) + goto finish; + } + + if (arg_since_set && arg_reverse) { + usec_t usec; + + r = sd_journal_get_realtime_usec(j, &usec); + if (r < 0) { + log_error("Failed to determine timestamp: %s", strerror(-r)); + goto finish; + } + if (usec < arg_since) + goto finish; + } + + if (!arg_merge) { + sd_id128_t boot_id; + + r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); + if (r >= 0) { + if (previous_boot_id_valid && + !sd_id128_equal(boot_id, previous_boot_id)) + printf("%s-- Reboot --%s\n", + ansi_highlight(), ansi_highlight_off()); + + previous_boot_id = boot_id; + previous_boot_id_valid = true; + } + } + + flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR | + arg_catalog * OUTPUT_CATALOG; + + r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized); + need_seek = true; + if (r == -EADDRNOTAVAIL) + break; + else if (r < 0 || ferror(stdout)) + goto finish; + + n_shown++; + } + + if (!arg_follow) { + if (arg_show_cursor) { + _cleanup_free_ char *cursor = NULL; + + r = sd_journal_get_cursor(j, &cursor); + if (r < 0 && r != -EADDRNOTAVAIL) + log_error("Failed to get cursor: %s", strerror(-r)); + else if (r >= 0) + printf("-- cursor: %s\n", cursor); + } + + break; + } + + r = sd_journal_wait(j, (uint64_t) -1); + if (r < 0) { + log_error("Couldn't wait for journal event: %s", strerror(-r)); + goto finish; + } + + first_line = false; + } + +finish: + pager_close(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c new file mode 100644 index 0000000..35da52a --- /dev/null +++ b/src/journal/journald-console.c @@ -0,0 +1,111 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "fileio.h" +#include "journald-server.h" +#include "journald-console.h" + +static bool prefix_timestamp(void) { + + static int cached_printk_time = -1; + + if (_unlikely_(cached_printk_time < 0)) { + _cleanup_free_ char *p = NULL; + + cached_printk_time = + read_one_line_file("/sys/module/printk/parameters/time", &p) >= 0 + && parse_boolean(p) > 0; + } + + return cached_printk_time; +} + +void server_forward_console( + Server *s, + int priority, + const char *identifier, + const char *message, + struct ucred *ucred) { + + struct iovec iovec[5]; + char header_pid[16]; + struct timespec ts; + char tbuf[4 + DECIMAL_STR_MAX(ts.tv_sec) + DECIMAL_STR_MAX(ts.tv_nsec)-3 + 1]; + int n = 0, fd; + _cleanup_free_ char *ident_buf = NULL; + const char *tty; + + assert(s); + assert(message); + + if (LOG_PRI(priority) > s->max_level_console) + return; + + /* First: timestamp */ + if (prefix_timestamp()) { + assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + snprintf(tbuf, sizeof(tbuf), "[%5llu.%06llu] ", + (unsigned long long) ts.tv_sec, + (unsigned long long) ts.tv_nsec / 1000); + IOVEC_SET_STRING(iovec[n++], tbuf); + } + + /* Second: identifier and PID */ + if (ucred) { + if (!identifier) { + get_process_comm(ucred->pid, &ident_buf); + identifier = ident_buf; + } + + snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); + char_array_0(header_pid); + + if (identifier) + IOVEC_SET_STRING(iovec[n++], identifier); + + IOVEC_SET_STRING(iovec[n++], header_pid); + } else if (identifier) { + IOVEC_SET_STRING(iovec[n++], identifier); + IOVEC_SET_STRING(iovec[n++], ": "); + } + + /* Fourth: message */ + IOVEC_SET_STRING(iovec[n++], message); + IOVEC_SET_STRING(iovec[n++], "\n"); + + tty = s->tty_path ? s->tty_path : "/dev/console"; + + fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) { + log_debug("Failed to open %s for logging: %m", tty); + return; + } + + if (writev(fd, iovec, n) < 0) + log_debug("Failed to write to %s for logging: %m", tty); + + close_nointr_nofail(fd); +} diff --git a/src/journal/journald-console.h b/src/journal/journald-console.h new file mode 100644 index 0000000..aa8e657 --- /dev/null +++ b/src/journal/journald-console.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-server.h" + +void server_forward_console(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred); diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf new file mode 100644 index 0000000..84efee3 --- /dev/null +++ b/src/journal/journald-gperf.gperf @@ -0,0 +1,40 @@ +%{ +#include +#include +#include "conf-parser.h" +#include "journald-server.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name journald_gperf_hash +%define lookup-function-name journald_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Journal.Storage, config_parse_storage, 0, offsetof(Server, storage) +Journal.Compress, config_parse_bool, 0, offsetof(Server, compress) +Journal.Seal, config_parse_bool, 0, offsetof(Server, seal) +Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec) +Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval) +Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst) +Journal.SystemMaxUse, config_parse_iec_off, 0, offsetof(Server, system_metrics.max_use) +Journal.SystemMaxFileSize, config_parse_iec_off, 0, offsetof(Server, system_metrics.max_size) +Journal.SystemKeepFree, config_parse_iec_off, 0, offsetof(Server, system_metrics.keep_free) +Journal.RuntimeMaxUse, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.max_use) +Journal.RuntimeMaxFileSize, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.max_size) +Journal.RuntimeKeepFree, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.keep_free) +Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec) +Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec) +Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog) +Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Server, forward_to_kmsg) +Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Server, forward_to_console) +Journal.TTYPath, config_parse_path, 0, offsetof(Server, tty_path) +Journal.MaxLevelStore, config_parse_level, 0, offsetof(Server, max_level_store) +Journal.MaxLevelSyslog, config_parse_level, 0, offsetof(Server, max_level_syslog) +Journal.MaxLevelKMsg, config_parse_level, 0, offsetof(Server, max_level_kmsg) +Journal.MaxLevelConsole, config_parse_level, 0, offsetof(Server, max_level_console) +Journal.SplitMode, config_parse_split_mode,0, offsetof(Server, split_mode) diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c new file mode 100644 index 0000000..05b128f --- /dev/null +++ b/src/journal/journald-kmsg.c @@ -0,0 +1,475 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "journald-server.h" +#include "journald-kmsg.h" +#include "journald-syslog.h" + +void server_forward_kmsg( + Server *s, + int priority, + const char *identifier, + const char *message, + struct ucred *ucred) { + + struct iovec iovec[5]; + char header_priority[6], header_pid[16]; + int n = 0; + char *ident_buf = NULL; + + assert(s); + assert(priority >= 0); + assert(priority <= 999); + assert(message); + + if (_unlikely_(LOG_PRI(priority) > s->max_level_kmsg)) + return; + + if (_unlikely_(s->dev_kmsg_fd < 0)) + return; + + /* Never allow messages with kernel facility to be written to + * kmsg, regardless where the data comes from. */ + priority = syslog_fixup_facility(priority); + + /* First: priority field */ + snprintf(header_priority, sizeof(header_priority), "<%i>", priority); + char_array_0(header_priority); + IOVEC_SET_STRING(iovec[n++], header_priority); + + /* Second: identifier and PID */ + if (ucred) { + if (!identifier) { + get_process_comm(ucred->pid, &ident_buf); + identifier = ident_buf; + } + + snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); + char_array_0(header_pid); + + if (identifier) + IOVEC_SET_STRING(iovec[n++], identifier); + + IOVEC_SET_STRING(iovec[n++], header_pid); + } else if (identifier) { + IOVEC_SET_STRING(iovec[n++], identifier); + IOVEC_SET_STRING(iovec[n++], ": "); + } + + /* Fourth: message */ + IOVEC_SET_STRING(iovec[n++], message); + IOVEC_SET_STRING(iovec[n++], "\n"); + + if (writev(s->dev_kmsg_fd, iovec, n) < 0) + log_debug("Failed to write to /dev/kmsg for logging: %m"); + + free(ident_buf); +} + +static bool is_us(const char *pid) { + pid_t t; + + assert(pid); + + if (parse_pid(pid, &t) < 0) + return false; + + return t == getpid(); +} + +static void dev_kmsg_record(Server *s, char *p, size_t l) { + struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS]; + char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL; + int priority, r; + unsigned n = 0, z = 0, j; + unsigned long long usec; + char *identifier = NULL, *pid = NULL, *e, *f, *k; + uint64_t serial; + size_t pl; + char *kernel_device = NULL; + + assert(s); + assert(p); + + if (l <= 0) + return; + + e = memchr(p, ',', l); + if (!e) + return; + *e = 0; + + r = safe_atoi(p, &priority); + if (r < 0 || priority < 0 || priority > 999) + return; + + if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN) + return; + + l -= (e - p) + 1; + p = e + 1; + e = memchr(p, ',', l); + if (!e) + return; + *e = 0; + + r = safe_atou64(p, &serial); + if (r < 0) + return; + + if (s->kernel_seqnum) { + /* We already read this one? */ + if (serial < *s->kernel_seqnum) + return; + + /* Did we lose any? */ + if (serial > *s->kernel_seqnum) + server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %"PRIu64" kernel messages", + serial - *s->kernel_seqnum - 1); + + /* Make sure we never read this one again. Note that + * we always store the next message serial we expect + * here, simply because this makes handling the first + * message with serial 0 easy. */ + *s->kernel_seqnum = serial + 1; + } + + l -= (e - p) + 1; + p = e + 1; + f = memchr(p, ';', l); + if (!f) + return; + /* Kernel 3.6 has the flags field, kernel 3.5 lacks that */ + e = memchr(p, ',', l); + if (!e || f < e) + e = f; + *e = 0; + + r = safe_atollu(p, &usec); + if (r < 0) + return; + + l -= (f - p) + 1; + p = f + 1; + e = memchr(p, '\n', l); + if (!e) + return; + *e = 0; + + pl = e - p; + l -= (e - p) + 1; + k = e + 1; + + for (j = 0; l > 0 && j < N_IOVEC_KERNEL_FIELDS; j++) { + char *m; + /* Meta data fields attached */ + + if (*k != ' ') + break; + + k ++, l --; + + e = memchr(k, '\n', l); + if (!e) + return; + + *e = 0; + + m = cunescape_length_with_prefix(k, e - k, "_KERNEL_"); + if (!m) + break; + + if (startswith(m, "_KERNEL_DEVICE=")) + kernel_device = m + 15; + + IOVEC_SET_STRING(iovec[n++], m); + z++; + + l -= (e - k) + 1; + k = e + 1; + } + + if (kernel_device) { + struct udev_device *ud; + + ud = udev_device_new_from_device_id(s->udev, kernel_device); + if (ud) { + const char *g; + struct udev_list_entry *ll; + char *b; + + g = udev_device_get_devnode(ud); + if (g) { + b = strappend("_UDEV_DEVNODE=", g); + if (b) { + IOVEC_SET_STRING(iovec[n++], b); + z++; + } + } + + g = udev_device_get_sysname(ud); + if (g) { + b = strappend("_UDEV_SYSNAME=", g); + if (b) { + IOVEC_SET_STRING(iovec[n++], b); + z++; + } + } + + j = 0; + ll = udev_device_get_devlinks_list_entry(ud); + udev_list_entry_foreach(ll, ll) { + + if (j > N_IOVEC_UDEV_FIELDS) + break; + + g = udev_list_entry_get_name(ll); + if (g) { + b = strappend("_UDEV_DEVLINK=", g); + if (b) { + IOVEC_SET_STRING(iovec[n++], b); + z++; + } + } + + j++; + } + + udev_device_unref(ud); + } + } + + if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu", usec) >= 0) + IOVEC_SET_STRING(iovec[n++], source_time); + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel"); + + if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) + IOVEC_SET_STRING(iovec[n++], syslog_priority); + + if ((priority & LOG_FACMASK) == LOG_KERN) + IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel"); + else { + pl -= syslog_parse_identifier((const char**) &p, &identifier, &pid); + + /* Avoid any messages we generated ourselves via + * log_info() and friends. */ + if (pid && is_us(pid)) + goto finish; + + if (identifier) { + syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier); + if (syslog_identifier) + IOVEC_SET_STRING(iovec[n++], syslog_identifier); + } + + if (pid) { + syslog_pid = strappend("SYSLOG_PID=", pid); + if (syslog_pid) + IOVEC_SET_STRING(iovec[n++], syslog_pid); + } + + if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) + IOVEC_SET_STRING(iovec[n++], syslog_facility); + } + + message = cunescape_length_with_prefix(p, pl, "MESSAGE="); + if (message) + IOVEC_SET_STRING(iovec[n++], message); + + server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0); + +finish: + for (j = 0; j < z; j++) + free(iovec[j].iov_base); + + free(message); + free(syslog_priority); + free(syslog_identifier); + free(syslog_pid); + free(syslog_facility); + free(source_time); + free(identifier); + free(pid); +} + +static int server_read_dev_kmsg(Server *s) { + char buffer[8192+1]; /* the kernel-side limit per record is 8K currently */ + ssize_t l; + + assert(s); + assert(s->dev_kmsg_fd >= 0); + + l = read(s->dev_kmsg_fd, buffer, sizeof(buffer) - 1); + if (l == 0) + return 0; + if (l < 0) { + /* Old kernels who don't allow reading from /dev/kmsg + * return EINVAL when we try. So handle this cleanly, + * but don' try to ever read from it again. */ + if (errno == EINVAL) { + s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source); + return 0; + } + + if (errno == EAGAIN || errno == EINTR || errno == EPIPE) + return 0; + + log_error("Failed to read from kernel: %m"); + return -errno; + } + + dev_kmsg_record(s, buffer, l); + return 1; +} + +int server_flush_dev_kmsg(Server *s) { + int r; + + assert(s); + + if (s->dev_kmsg_fd < 0) + return 0; + + if (!s->dev_kmsg_readable) + return 0; + + log_debug("Flushing /dev/kmsg..."); + + for (;;) { + r = server_read_dev_kmsg(s); + if (r < 0) + return r; + + if (r == 0) + break; + } + + return 0; +} + +static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; + + assert(es); + assert(fd == s->dev_kmsg_fd); + assert(s); + + if (revents & EPOLLERR) + log_warning("/dev/kmsg buffer overrun, some messages lost."); + + if (!(revents & EPOLLIN)) + log_error("Got invalid event from epoll for /dev/kmsg: %"PRIx32, revents); + + return server_read_dev_kmsg(s); +} + +int server_open_dev_kmsg(Server *s) { + int r; + + assert(s); + + s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (s->dev_kmsg_fd < 0) { + log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + "Failed to open /dev/kmsg, ignoring: %m"); + return 0; + } + + r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s); + if (r < 0) { + + /* This will fail with EPERM on older kernels where + * /dev/kmsg is not readable. */ + if (r == -EPERM) { + r = 0; + goto fail; + } + + log_error("Failed to add /dev/kmsg fd to event loop: %s", strerror(-r)); + goto fail; + } + + r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10); + if (r < 0) { + log_error("Failed to adjust priority of kmsg event source: %s", strerror(-r)); + goto fail; + } + + s->dev_kmsg_readable = true; + + return 0; + +fail: + if (s->dev_kmsg_event_source) + s->dev_kmsg_event_source = sd_event_source_unref(s->dev_kmsg_event_source); + + if (s->dev_kmsg_fd >= 0) { + close_nointr_nofail(s->dev_kmsg_fd); + s->dev_kmsg_fd = -1; + } + + return r; +} + +int server_open_kernel_seqnum(Server *s) { + int fd; + uint64_t *p; + + assert(s); + + /* We store the seqnum we last read in an mmaped file. That + * way we can just use it like a variable, but it is + * persistent and automatically flushed at reboot. */ + + fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644); + if (fd < 0) { + log_error("Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m"); + return 0; + } + + if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) { + log_error("Failed to allocate sequential number file, ignoring: %m"); + close_nointr_nofail(fd); + return 0; + } + + p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) { + log_error("Failed to map sequential number file, ignoring: %m"); + close_nointr_nofail(fd); + return 0; + } + + close_nointr_nofail(fd); + s->kernel_seqnum = p; + + return 0; +} diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h new file mode 100644 index 0000000..f60f605 --- /dev/null +++ b/src/journal/journald-kmsg.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-server.h" + +int server_open_dev_kmsg(Server *s); +int server_flush_dev_kmsg(Server *s); + +void server_forward_kmsg(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred); + +int server_open_kernel_seqnum(Server *s); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c new file mode 100644 index 0000000..359d962 --- /dev/null +++ b/src/journal/journald-native.c @@ -0,0 +1,429 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "socket-util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "journald-server.h" +#include "journald-native.h" +#include "journald-kmsg.h" +#include "journald-console.h" +#include "journald-syslog.h" + +/* Make sure not to make this smaller than the maximum coredump + * size. See COREDUMP_MAX in coredump.c */ +#define ENTRY_SIZE_MAX (1024*1024*768) +#define DATA_SIZE_MAX (1024*1024*768) + +static bool valid_user_field(const char *p, size_t l) { + const char *a; + + /* We kinda enforce POSIX syntax recommendations for + environment variables here, but make a couple of additional + requirements. + + http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ + + /* No empty field names */ + if (l <= 0) + return false; + + /* Don't allow names longer than 64 chars */ + if (l > 64) + return false; + + /* Variables starting with an underscore are protected */ + if (p[0] == '_') + return false; + + /* Don't allow digits as first character */ + if (p[0] >= '0' && p[0] <= '9') + return false; + + /* Only allow A-Z0-9 and '_' */ + for (a = p; a < p + l; a++) + if (!((*a >= 'A' && *a <= 'Z') || + (*a >= '0' && *a <= '9') || + *a == '_')) + return false; + + return true; +} + +static bool allow_object_pid(struct ucred *ucred) { + return ucred && ucred->uid == 0; +} + +void server_process_native_message( + Server *s, + const void *buffer, size_t buffer_size, + struct ucred *ucred, + struct timeval *tv, + const char *label, size_t label_len) { + + struct iovec *iovec = NULL; + unsigned n = 0, j, tn = (unsigned) -1; + const char *p; + size_t remaining, m = 0; + int priority = LOG_INFO; + char *identifier = NULL, *message = NULL; + pid_t object_pid = 0; + + assert(s); + assert(buffer || buffer_size == 0); + + p = buffer; + remaining = buffer_size; + + while (remaining > 0) { + const char *e, *q; + + e = memchr(p, '\n', remaining); + + if (!e) { + /* Trailing noise, let's ignore it, and flush what we collected */ + log_debug("Received message with trailing noise, ignoring."); + break; + } + + if (e == p) { + /* Entry separator */ + server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid); + n = 0; + priority = LOG_INFO; + + p++; + remaining--; + continue; + } + + if (*p == '.' || *p == '#') { + /* Ignore control commands for now, and + * comments too. */ + remaining -= (e - p) + 1; + p = e + 1; + continue; + } + + /* A property follows */ + + /* n received properties, +1 for _TRANSPORT */ + if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + + !!object_pid * N_IOVEC_OBJECT_FIELDS)) { + log_oom(); + break; + } + + q = memchr(p, '=', e - p); + if (q) { + if (valid_user_field(p, q - p)) { + size_t l; + + l = e - p; + + /* If the field name starts with an + * underscore, skip the variable, + * since that indidates a trusted + * field */ + iovec[n].iov_base = (char*) p; + iovec[n].iov_len = l; + n++; + + /* We need to determine the priority + * of this entry for the rate limiting + * logic */ + if (l == 10 && + startswith(p, "PRIORITY=") && + p[9] >= '0' && p[9] <= '9') + priority = (priority & LOG_FACMASK) | (p[9] - '0'); + + else if (l == 17 && + startswith(p, "SYSLOG_FACILITY=") && + p[16] >= '0' && p[16] <= '9') + priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3); + + else if (l == 18 && + startswith(p, "SYSLOG_FACILITY=") && + p[16] >= '0' && p[16] <= '9' && + p[17] >= '0' && p[17] <= '9') + priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3); + + else if (l >= 19 && + startswith(p, "SYSLOG_IDENTIFIER=")) { + char *t; + + t = strndup(p + 18, l - 18); + if (t) { + free(identifier); + identifier = t; + } + } else if (l >= 8 && + startswith(p, "MESSAGE=")) { + char *t; + + t = strndup(p + 8, l - 8); + if (t) { + free(message); + message = t; + } + } else if (l > strlen("OBJECT_PID=") && + l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) && + startswith(p, "OBJECT_PID=") && + allow_object_pid(ucred)) { + char buf[DECIMAL_STR_MAX(pid_t)]; + memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID=")); + char_array_0(buf); + + /* ignore error */ + parse_pid(buf, &object_pid); + } + } + + remaining -= (e - p) + 1; + p = e + 1; + continue; + } else { + le64_t l_le; + uint64_t l; + char *k; + + if (remaining < e - p + 1 + sizeof(uint64_t) + 1) { + log_debug("Failed to parse message, ignoring."); + break; + } + + memcpy(&l_le, e + 1, sizeof(uint64_t)); + l = le64toh(l_le); + + if (l > DATA_SIZE_MAX) { + log_debug("Received binary data block too large, ignoring."); + break; + } + + if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || + e[1+sizeof(uint64_t)+l] != '\n') { + log_debug("Failed to parse message, ignoring."); + break; + } + + k = malloc((e - p) + 1 + l); + if (!k) { + log_oom(); + break; + } + + memcpy(k, p, e - p); + k[e - p] = '='; + memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); + + if (valid_user_field(p, e - p)) { + iovec[n].iov_base = k; + iovec[n].iov_len = (e - p) + 1 + l; + n++; + } else + free(k); + + remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1; + p = e + 1 + sizeof(uint64_t) + l + 1; + } + } + + if (n <= 0) + goto finish; + + tn = n++; + IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal"); + + if (message) { + if (s->forward_to_syslog) + server_forward_syslog(s, priority, identifier, message, ucred, tv); + + if (s->forward_to_kmsg) + server_forward_kmsg(s, priority, identifier, message, ucred); + + if (s->forward_to_console) + server_forward_console(s, priority, identifier, message, ucred); + } + + server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid); + +finish: + for (j = 0; j < n; j++) { + if (j == tn) + continue; + + if (iovec[j].iov_base < buffer || + (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size) + free(iovec[j].iov_base); + } + + free(iovec); + free(identifier); + free(message); +} + +void server_process_native_file( + Server *s, + int fd, + struct ucred *ucred, + struct timeval *tv, + const char *label, size_t label_len) { + + struct stat st; + _cleanup_free_ void *p = NULL; + ssize_t n; + int r; + + assert(s); + assert(fd >= 0); + + if (!ucred || ucred->uid != 0) { + _cleanup_free_ char *sl = NULL, *k = NULL; + const char *e; + + if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) { + log_oom(); + return; + } + + r = readlink_malloc(sl, &k); + if (r < 0) { + log_error("readlink(%s) failed: %m", sl); + return; + } + + e = path_startswith(k, "/dev/shm/"); + if (!e) + e = path_startswith(k, "/tmp/"); + if (!e) + e = path_startswith(k, "/var/tmp/"); + if (!e) { + log_error("Received file outside of allowed directories. Refusing."); + return; + } + + if (!filename_is_safe(e)) { + log_error("Received file in subdirectory of allowed directories. Refusing."); + return; + } + } + + /* Data is in the passed file, since it didn't fit in a + * datagram. We can't map the file here, since clients might + * then truncate it and trigger a SIGBUS for us. So let's + * stupidly read it */ + + if (fstat(fd, &st) < 0) { + log_error("Failed to stat passed file, ignoring: %m"); + return; + } + + if (!S_ISREG(st.st_mode)) { + log_error("File passed is not regular. Ignoring."); + return; + } + + if (st.st_size <= 0) + return; + + if (st.st_size > ENTRY_SIZE_MAX) { + log_error("File passed too large. Ignoring."); + return; + } + + p = malloc(st.st_size); + if (!p) { + log_oom(); + return; + } + + n = pread(fd, p, st.st_size, 0); + if (n < 0) + log_error("Failed to read file, ignoring: %s", strerror(-n)); + else if (n > 0) + server_process_native_message(s, p, n, ucred, tv, label, label_len); +} + +int server_open_native_socket(Server*s) { + union sockaddr_union sa; + int one, r; + + assert(s); + + if (s->native_fd < 0) { + + s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (s->native_fd < 0) { + log_error("socket() failed: %m"); + return -errno; + } + + zero(sa); + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path)); + + unlink(sa.un.sun_path); + + r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { + log_error("bind() failed: %m"); + return -errno; + } + + chmod(sa.un.sun_path, 0666); + } else + fd_nonblock(s->native_fd, 1); + + one = 1; + r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + if (r < 0) { + log_error("SO_PASSCRED failed: %m"); + return -errno; + } + +#ifdef HAVE_SELINUX + if (use_selinux()) { + one = 1; + r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); + if (r < 0) + log_warning("SO_PASSSEC failed: %m"); + } +#endif + + one = 1; + r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); + if (r < 0) { + log_error("SO_TIMESTAMP failed: %m"); + return -errno; + } + + r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s); + if (r < 0) { + log_error("Failed to add native server fd to event loop: %s", strerror(-r)); + return r; + } + + return 0; +} diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h new file mode 100644 index 0000000..16c09f5 --- /dev/null +++ b/src/journal/journald-native.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-server.h" + +void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len); + +void server_process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len); + +int server_open_native_socket(Server*s); diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c new file mode 100644 index 0000000..6d779d2 --- /dev/null +++ b/src/journal/journald-rate-limit.c @@ -0,0 +1,264 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "journald-rate-limit.h" +#include "list.h" +#include "util.h" +#include "hashmap.h" + +#define POOLS_MAX 5 +#define BUCKETS_MAX 127 +#define GROUPS_MAX 2047 + +static const int priority_map[] = { + [LOG_EMERG] = 0, + [LOG_ALERT] = 0, + [LOG_CRIT] = 0, + [LOG_ERR] = 1, + [LOG_WARNING] = 2, + [LOG_NOTICE] = 3, + [LOG_INFO] = 3, + [LOG_DEBUG] = 4 +}; + +typedef struct JournalRateLimitPool JournalRateLimitPool; +typedef struct JournalRateLimitGroup JournalRateLimitGroup; + +struct JournalRateLimitPool { + usec_t begin; + unsigned num; + unsigned suppressed; +}; + +struct JournalRateLimitGroup { + JournalRateLimit *parent; + + char *id; + JournalRateLimitPool pools[POOLS_MAX]; + unsigned long hash; + + LIST_FIELDS(JournalRateLimitGroup, bucket); + LIST_FIELDS(JournalRateLimitGroup, lru); +}; + +struct JournalRateLimit { + usec_t interval; + unsigned burst; + + JournalRateLimitGroup* buckets[BUCKETS_MAX]; + JournalRateLimitGroup *lru, *lru_tail; + + unsigned n_groups; + + uint8_t hash_key[16]; +}; + +JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst) { + JournalRateLimit *r; + + assert(interval > 0 || burst == 0); + + r = new0(JournalRateLimit, 1); + if (!r) + return NULL; + + r->interval = interval; + r->burst = burst; + + random_bytes(r->hash_key, sizeof(r->hash_key)); + + return r; +} + +static void journal_rate_limit_group_free(JournalRateLimitGroup *g) { + assert(g); + + if (g->parent) { + assert(g->parent->n_groups > 0); + + if (g->parent->lru_tail == g) + g->parent->lru_tail = g->lru_prev; + + LIST_REMOVE(lru, g->parent->lru, g); + LIST_REMOVE(bucket, g->parent->buckets[g->hash % BUCKETS_MAX], g); + + g->parent->n_groups --; + } + + free(g->id); + free(g); +} + +void journal_rate_limit_free(JournalRateLimit *r) { + assert(r); + + while (r->lru) + journal_rate_limit_group_free(r->lru); + + free(r); +} + +_pure_ static bool journal_rate_limit_group_expired(JournalRateLimitGroup *g, usec_t ts) { + unsigned i; + + assert(g); + + for (i = 0; i < POOLS_MAX; i++) + if (g->pools[i].begin + g->parent->interval >= ts) + return false; + + return true; +} + +static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) { + assert(r); + + /* Makes room for at least one new item, but drop all + * expored items too. */ + + while (r->n_groups >= GROUPS_MAX || + (r->lru_tail && journal_rate_limit_group_expired(r->lru_tail, ts))) + journal_rate_limit_group_free(r->lru_tail); +} + +static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) { + JournalRateLimitGroup *g; + + assert(r); + assert(id); + + g = new0(JournalRateLimitGroup, 1); + if (!g) + return NULL; + + g->id = strdup(id); + if (!g->id) + goto fail; + + g->hash = string_hash_func(g->id, r->hash_key); + + journal_rate_limit_vacuum(r, ts); + + LIST_PREPEND(bucket, r->buckets[g->hash % BUCKETS_MAX], g); + LIST_PREPEND(lru, r->lru, g); + if (!g->lru_next) + r->lru_tail = g; + r->n_groups ++; + + g->parent = r; + return g; + +fail: + journal_rate_limit_group_free(g); + return NULL; +} + +static unsigned burst_modulate(unsigned burst, uint64_t available) { + unsigned k; + + /* Modulates the burst rate a bit with the amount of available + * disk space */ + + k = u64log2(available); + + /* 1MB */ + if (k <= 20) + return burst; + + burst = (burst * (k-20)) / 4; + + /* + * Example: + * + * <= 1MB = rate * 1 + * 16MB = rate * 2 + * 256MB = rate * 3 + * 4GB = rate * 4 + * 64GB = rate * 5 + * 1TB = rate * 6 + */ + + return burst; +} + +int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) { + unsigned long h; + JournalRateLimitGroup *g; + JournalRateLimitPool *p; + unsigned burst; + usec_t ts; + + assert(id); + + if (!r) + return 1; + + if (r->interval == 0 || r->burst == 0) + return 1; + + burst = burst_modulate(r->burst, available); + + ts = now(CLOCK_MONOTONIC); + + h = string_hash_func(id, r->hash_key); + g = r->buckets[h % BUCKETS_MAX]; + + LIST_FOREACH(bucket, g, g) + if (streq(g->id, id)) + break; + + if (!g) { + g = journal_rate_limit_group_new(r, id, ts); + if (!g) + return -ENOMEM; + } + + p = &g->pools[priority_map[priority]]; + + if (p->begin <= 0) { + p->suppressed = 0; + p->num = 1; + p->begin = ts; + return 1; + } + + if (p->begin + r->interval < ts) { + unsigned s; + + s = p->suppressed; + p->suppressed = 0; + p->num = 1; + p->begin = ts; + + return 1 + s; + } + + if (p->num <= burst) { + p->num++; + return 1; + } + + p->suppressed++; + return 0; +} diff --git a/src/journal/journald-rate-limit.h b/src/journal/journald-rate-limit.h new file mode 100644 index 0000000..648ab22 --- /dev/null +++ b/src/journal/journald-rate-limit.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "macro.h" +#include "util.h" + +typedef struct JournalRateLimit JournalRateLimit; + +JournalRateLimit *journal_rate_limit_new(usec_t interval, unsigned burst); +void journal_rate_limit_free(JournalRateLimit *r); +int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c new file mode 100644 index 0000000..96ef66d --- /dev/null +++ b/src/journal/journald-server.c @@ -0,0 +1,1677 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "sd-journal.h" +#include "sd-messages.h" +#include "sd-daemon.h" +#include "fileio.h" +#include "mkdir.h" +#include "hashmap.h" +#include "journal-file.h" +#include "socket-util.h" +#include "cgroup-util.h" +#include "list.h" +#include "missing.h" +#include "conf-parser.h" +#include "selinux-util.h" +#include "journal-internal.h" +#include "journal-vacuum.h" +#include "journal-authenticate.h" +#include "journald-rate-limit.h" +#include "journald-kmsg.h" +#include "journald-syslog.h" +#include "journald-stream.h" +#include "journald-console.h" +#include "journald-native.h" +#include "journald-server.h" + +#ifdef HAVE_ACL +#include +#include +#include "acl-util.h" +#endif + +#ifdef HAVE_SELINUX +#include +#endif + +#define USER_JOURNALS_MAX 1024 + +#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE) +#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC) +#define DEFAULT_RATE_LIMIT_BURST 1000 + +#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) + +static const char* const storage_table[] = { + [STORAGE_AUTO] = "auto", + [STORAGE_VOLATILE] = "volatile", + [STORAGE_PERSISTENT] = "persistent", + [STORAGE_NONE] = "none" +}; + +DEFINE_STRING_TABLE_LOOKUP(storage, Storage); +DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting"); + +static const char* const split_mode_table[] = { + [SPLIT_NONE] = "none", + [SPLIT_UID] = "uid", + [SPLIT_LOGIN] = "login" +}; + +DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode); +DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting"); + +static uint64_t available_space(Server *s, bool verbose) { + char ids[33]; + _cleanup_free_ char *p = NULL; + sd_id128_t machine; + struct statvfs ss; + uint64_t sum = 0, ss_avail = 0, avail = 0; + int r; + _cleanup_closedir_ DIR *d = NULL; + usec_t ts; + const char *f; + JournalMetrics *m; + + ts = now(CLOCK_MONOTONIC); + + if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts + && !verbose) + return s->cached_available_space; + + r = sd_id128_get_machine(&machine); + if (r < 0) + return 0; + + if (s->system_journal) { + f = "/var/log/journal/"; + m = &s->system_metrics; + } else { + f = "/run/log/journal/"; + m = &s->runtime_metrics; + } + + assert(m); + + p = strappend(f, sd_id128_to_string(machine, ids)); + if (!p) + return 0; + + d = opendir(p); + if (!d) + return 0; + + if (fstatvfs(dirfd(d), &ss) < 0) + return 0; + + for (;;) { + struct stat st; + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return 0; + + if (!de) + break; + + if (!endswith(de->d_name, ".journal") && + !endswith(de->d_name, ".journal~")) + continue; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + continue; + + if (!S_ISREG(st.st_mode)) + continue; + + sum += (uint64_t) st.st_blocks * 512UL; + } + + ss_avail = ss.f_bsize * ss.f_bavail; + + /* If we reached a high mark, we will always allow this much + * again, unless usage goes above max_use. This watermark + * value is cached so that we don't give up space on pressure, + * but hover below the maximum usage. */ + + if (m->use < sum) + m->use = sum; + + avail = LESS_BY(ss_avail, m->keep_free); + + s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum); + s->cached_available_space_timestamp = ts; + + if (verbose) { + char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX], + fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX]; + + server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, + "%s journal is using %s (max allowed %s, " + "trying to leave %s free of %s available → current limit %s).", + s->system_journal ? "Permanent" : "Runtime", + format_bytes(fb1, sizeof(fb1), sum), + format_bytes(fb2, sizeof(fb2), m->max_use), + format_bytes(fb3, sizeof(fb3), m->keep_free), + format_bytes(fb4, sizeof(fb4), ss_avail), + format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum)); + } + + return s->cached_available_space; +} + +void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { + int r; +#ifdef HAVE_ACL + acl_t acl; + acl_entry_t entry; + acl_permset_t permset; +#endif + + assert(f); + + r = fchmod(f->fd, 0640); + if (r < 0) + log_warning("Failed to fix access mode on %s, ignoring: %s", f->path, strerror(-r)); + +#ifdef HAVE_ACL + if (uid <= 0) + return; + + acl = acl_get_fd(f->fd); + if (!acl) { + log_warning("Failed to read ACL on %s, ignoring: %m", f->path); + return; + } + + r = acl_find_uid(acl, uid, &entry); + if (r <= 0) { + + if (acl_create_entry(&acl, &entry) < 0 || + acl_set_tag_type(entry, ACL_USER) < 0 || + acl_set_qualifier(entry, &uid) < 0) { + log_warning("Failed to patch ACL on %s, ignoring: %m", f->path); + goto finish; + } + } + + /* We do not recalculate the mask unconditionally here, + * so that the fchmod() mask above stays intact. */ + if (acl_get_permset(entry, &permset) < 0 || + acl_add_perm(permset, ACL_READ) < 0 || + calc_acl_mask_if_needed(&acl) < 0) { + log_warning("Failed to patch ACL on %s, ignoring: %m", f->path); + goto finish; + } + + if (acl_set_fd(f->fd, acl) < 0) + log_warning("Failed to set ACL on %s, ignoring: %m", f->path); + +finish: + acl_free(acl); +#endif +} + +static JournalFile* find_journal(Server *s, uid_t uid) { + _cleanup_free_ char *p = NULL; + int r; + JournalFile *f; + sd_id128_t machine; + + assert(s); + + /* We split up user logs only on /var, not on /run. If the + * runtime file is open, we write to it exclusively, in order + * to guarantee proper order as soon as we flush /run to + * /var and close the runtime file. */ + + if (s->runtime_journal) + return s->runtime_journal; + + if (uid <= 0) + return s->system_journal; + + r = sd_id128_get_machine(&machine); + if (r < 0) + return s->system_journal; + + f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid)); + if (f) + return f; + + if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/user-%lu.journal", + SD_ID128_FORMAT_VAL(machine), (unsigned long) uid) < 0) + return s->system_journal; + + while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) { + /* Too many open? Then let's close one */ + f = hashmap_steal_first(s->user_journals); + assert(f); + journal_file_close(f); + } + + r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f); + if (r < 0) + return s->system_journal; + + server_fix_perms(s, f, uid); + + r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f); + if (r < 0) { + journal_file_close(f); + return s->system_journal; + } + + return f; +} + +void server_rotate(Server *s) { + JournalFile *f; + void *k; + Iterator i; + int r; + + log_debug("Rotating..."); + + if (s->runtime_journal) { + r = journal_file_rotate(&s->runtime_journal, s->compress, false); + if (r < 0) + if (s->runtime_journal) + log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r)); + else + log_error("Failed to create new runtime journal: %s", strerror(-r)); + else + server_fix_perms(s, s->runtime_journal, 0); + } + + if (s->system_journal) { + r = journal_file_rotate(&s->system_journal, s->compress, s->seal); + if (r < 0) + if (s->system_journal) + log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r)); + else + log_error("Failed to create new system journal: %s", strerror(-r)); + + else + server_fix_perms(s, s->system_journal, 0); + } + + HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { + r = journal_file_rotate(&f, s->compress, s->seal); + if (r < 0) + if (f) + log_error("Failed to rotate %s: %s", f->path, strerror(-r)); + else { + log_error("Failed to create user journal: %s", strerror(-r)); + hashmap_remove(s->user_journals, k); + } + else { + hashmap_replace(s->user_journals, k, f); + server_fix_perms(s, f, PTR_TO_UINT32(k)); + } + } +} + +void server_sync(Server *s) { + JournalFile *f; + void *k; + Iterator i; + int r; + + if (s->system_journal) { + r = journal_file_set_offline(s->system_journal); + if (r < 0) + log_error("Failed to sync system journal: %s", strerror(-r)); + } + + HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { + r = journal_file_set_offline(f); + if (r < 0) + log_error("Failed to sync user journal: %s", strerror(-r)); + } + + if (s->sync_event_source) { + r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF); + if (r < 0) + log_error("Failed to disable sync timer source: %s", strerror(-r)); + } + + s->sync_scheduled = false; +} + +void server_vacuum(Server *s) { + char ids[33]; + sd_id128_t machine; + int r; + + log_debug("Vacuuming..."); + + s->oldest_file_usec = 0; + + r = sd_id128_get_machine(&machine); + if (r < 0) { + log_error("Failed to get machine ID: %s", strerror(-r)); + return; + } + + sd_id128_to_string(machine, ids); + + if (s->system_journal) { + char *p = strappenda("/var/log/journal/", ids); + + r = journal_directory_vacuum(p, s->system_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + } + + if (s->runtime_journal) { + char *p = strappenda("/run/log/journal/", ids); + + r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->max_retention_usec, &s->oldest_file_usec); + if (r < 0 && r != -ENOENT) + log_error("Failed to vacuum %s: %s", p, strerror(-r)); + } + + s->cached_available_space_timestamp = 0; +} + +static void server_cache_machine_id(Server *s) { + sd_id128_t id; + int r; + + assert(s); + + r = sd_id128_get_machine(&id); + if (r < 0) + return; + + sd_id128_to_string(id, stpcpy(s->machine_id_field, "_MACHINE_ID=")); +} + +static void server_cache_boot_id(Server *s) { + sd_id128_t id; + int r; + + assert(s); + + r = sd_id128_get_boot(&id); + if (r < 0) + return; + + sd_id128_to_string(id, stpcpy(s->boot_id_field, "_BOOT_ID=")); +} + +static void server_cache_hostname(Server *s) { + _cleanup_free_ char *t = NULL; + char *x; + + assert(s); + + t = gethostname_malloc(); + if (!t) + return; + + x = strappend("_HOSTNAME=", t); + if (!x) + return; + + free(s->hostname_field); + s->hostname_field = x; +} + +bool shall_try_append_again(JournalFile *f, int r) { + + /* -E2BIG Hit configured limit + -EFBIG Hit fs limit + -EDQUOT Quota limit hit + -ENOSPC Disk full + -EHOSTDOWN Other machine + -EBUSY Unclean shutdown + -EPROTONOSUPPORT Unsupported feature + -EBADMSG Corrupted + -ENODATA Truncated + -ESHUTDOWN Already archived */ + + if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC) + log_debug("%s: Allocation limit reached, rotating.", f->path); + else if (r == -EHOSTDOWN) + log_info("%s: Journal file from other machine, rotating.", f->path); + else if (r == -EBUSY) + log_info("%s: Unclean shutdown, rotating.", f->path); + else if (r == -EPROTONOSUPPORT) + log_info("%s: Unsupported feature, rotating.", f->path); + else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN) + log_warning("%s: Journal file corrupted, rotating.", f->path); + else + return false; + + return true; +} + +static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) { + JournalFile *f; + bool vacuumed = false; + int r; + + assert(s); + assert(iovec); + assert(n > 0); + + f = find_journal(s, uid); + if (!f) + return; + + if (journal_file_rotate_suggested(f, s->max_file_usec)) { + log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path); + server_rotate(s); + server_vacuum(s); + vacuumed = true; + + f = find_journal(s, uid); + if (!f) + return; + } + + r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL); + if (r >= 0) { + server_schedule_sync(s, priority); + return; + } + + if (vacuumed || !shall_try_append_again(f, r)) { + size_t size = 0; + unsigned i; + for (i = 0; i < n; i++) + size += iovec[i].iov_len; + + log_error("Failed to write entry (%d items, %zu bytes), ignoring: %s", n, size, strerror(-r)); + return; + } + + server_rotate(s); + server_vacuum(s); + + f = find_journal(s, uid); + if (!f) + return; + + log_debug("Retrying write."); + r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL); + if (r < 0) { + size_t size = 0; + unsigned i; + for (i = 0; i < n; i++) + size += iovec[i].iov_len; + + log_error("Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %s", n, size, strerror(-r)); + } else + server_schedule_sync(s, priority); +} + +static void dispatch_message_real( + Server *s, + struct iovec *iovec, unsigned n, unsigned m, + struct ucred *ucred, + struct timeval *tv, + const char *label, size_t label_len, + const char *unit_id, + int priority, + pid_t object_pid) { + + char pid[sizeof("_PID=") + DECIMAL_STR_MAX(pid_t)], + uid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)], + gid[sizeof("_GID=") + DECIMAL_STR_MAX(gid_t)], + owner_uid[sizeof("_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)], + source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)], + o_uid[sizeof("OBJECT_UID=") + DECIMAL_STR_MAX(uid_t)], + o_gid[sizeof("OBJECT_GID=") + DECIMAL_STR_MAX(gid_t)], + o_owner_uid[sizeof("OBJECT_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)]; + uid_t object_uid; + gid_t object_gid; + char *x; + int r; + char *t, *c; + uid_t realuid = 0, owner = 0, journal_uid; + bool owner_valid = false; +#ifdef HAVE_AUDIT + char audit_session[sizeof("_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)], + audit_loginuid[sizeof("_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)], + o_audit_session[sizeof("OBJECT_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)], + o_audit_loginuid[sizeof("OBJECT_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)]; + + uint32_t audit; + uid_t loginuid; +#endif + + assert(s); + assert(iovec); + assert(n > 0); + assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m); + + if (ucred) { + realuid = ucred->uid; + + sprintf(pid, "_PID=%lu", (unsigned long) ucred->pid); + IOVEC_SET_STRING(iovec[n++], pid); + + sprintf(uid, "_UID=%lu", (unsigned long) ucred->uid); + IOVEC_SET_STRING(iovec[n++], uid); + + sprintf(gid, "_GID=%lu", (unsigned long) ucred->gid); + IOVEC_SET_STRING(iovec[n++], gid); + + r = get_process_comm(ucred->pid, &t); + if (r >= 0) { + x = strappenda("_COMM=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + r = get_process_exe(ucred->pid, &t); + if (r >= 0) { + x = strappenda("_EXE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + r = get_process_cmdline(ucred->pid, 0, false, &t); + if (r >= 0) { + x = strappenda("_CMDLINE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + r = get_process_capeff(ucred->pid, &t); + if (r >= 0) { + x = strappenda("_CAP_EFFECTIVE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + +#ifdef HAVE_AUDIT + r = audit_session_from_pid(ucred->pid, &audit); + if (r >= 0) { + sprintf(audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit); + IOVEC_SET_STRING(iovec[n++], audit_session); + } + + r = audit_loginuid_from_pid(ucred->pid, &loginuid); + if (r >= 0) { + sprintf(audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid); + IOVEC_SET_STRING(iovec[n++], audit_loginuid); + } +#endif + + r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &c); + if (r >= 0) { + char *session = NULL; + + x = strappenda("_SYSTEMD_CGROUP=", c); + IOVEC_SET_STRING(iovec[n++], x); + + r = cg_path_get_session(c, &t); + if (r >= 0) { + session = strappenda("_SYSTEMD_SESSION=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], session); + } + + if (cg_path_get_owner_uid(c, &owner) >= 0) { + owner_valid = true; + + sprintf(owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner); + IOVEC_SET_STRING(iovec[n++], owner_uid); + } + + if (cg_path_get_unit(c, &t) >= 0) { + x = strappenda("_SYSTEMD_UNIT=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } else if (unit_id && !session) { + x = strappenda("_SYSTEMD_UNIT=", unit_id); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_user_unit(c, &t) >= 0) { + x = strappenda("_SYSTEMD_USER_UNIT=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } else if (unit_id && session) { + x = strappenda("_SYSTEMD_USER_UNIT=", unit_id); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_slice(c, &t) >= 0) { + x = strappenda("_SYSTEMD_SLICE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + free(c); + } else if (unit_id) { + x = strappenda("_SYSTEMD_UNIT=", unit_id); + IOVEC_SET_STRING(iovec[n++], x); + } + +#ifdef HAVE_SELINUX + if (use_selinux()) { + if (label) { + x = alloca(sizeof("_SELINUX_CONTEXT=") + label_len); + + *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0; + IOVEC_SET_STRING(iovec[n++], x); + } else { + security_context_t con; + + if (getpidcon(ucred->pid, &con) >= 0) { + x = strappenda("_SELINUX_CONTEXT=", con); + + freecon(con); + IOVEC_SET_STRING(iovec[n++], x); + } + } + } +#endif + } + assert(n <= m); + + if (object_pid) { + r = get_process_uid(object_pid, &object_uid); + if (r >= 0) { + sprintf(o_uid, "OBJECT_UID=%lu", (unsigned long) object_uid); + IOVEC_SET_STRING(iovec[n++], o_uid); + } + + r = get_process_gid(object_pid, &object_gid); + if (r >= 0) { + sprintf(o_gid, "OBJECT_GID=%lu", (unsigned long) object_gid); + IOVEC_SET_STRING(iovec[n++], o_gid); + } + + r = get_process_comm(object_pid, &t); + if (r >= 0) { + x = strappenda("OBJECT_COMM=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + r = get_process_exe(object_pid, &t); + if (r >= 0) { + x = strappenda("OBJECT_EXE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + r = get_process_cmdline(object_pid, 0, false, &t); + if (r >= 0) { + x = strappenda("OBJECT_CMDLINE=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + +#ifdef HAVE_AUDIT + r = audit_session_from_pid(object_pid, &audit); + if (r >= 0) { + sprintf(o_audit_session, "OBJECT_AUDIT_SESSION=%lu", (unsigned long) audit); + IOVEC_SET_STRING(iovec[n++], o_audit_session); + } + + r = audit_loginuid_from_pid(object_pid, &loginuid); + if (r >= 0) { + sprintf(o_audit_loginuid, "OBJECT_AUDIT_LOGINUID=%lu", (unsigned long) loginuid); + IOVEC_SET_STRING(iovec[n++], o_audit_loginuid); + } +#endif + + r = cg_pid_get_path_shifted(object_pid, s->cgroup_root, &c); + if (r >= 0) { + x = strappenda("OBJECT_SYSTEMD_CGROUP=", c); + IOVEC_SET_STRING(iovec[n++], x); + + r = cg_path_get_session(c, &t); + if (r >= 0) { + x = strappenda("OBJECT_SYSTEMD_SESSION=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_owner_uid(c, &owner) >= 0) { + sprintf(o_owner_uid, "OBJECT_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner); + IOVEC_SET_STRING(iovec[n++], o_owner_uid); + } + + if (cg_path_get_unit(c, &t) >= 0) { + x = strappenda("OBJECT_SYSTEMD_UNIT=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + if (cg_path_get_user_unit(c, &t) >= 0) { + x = strappenda("OBJECT_SYSTEMD_USER_UNIT=", t); + free(t); + IOVEC_SET_STRING(iovec[n++], x); + } + + free(c); + } + } + assert(n <= m); + + if (tv) { + sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu", (unsigned long long) timeval_load(tv)); + IOVEC_SET_STRING(iovec[n++], source_time); + } + + /* Note that strictly speaking storing the boot id here is + * redundant since the entry includes this in-line + * anyway. However, we need this indexed, too. */ + if (!isempty(s->boot_id_field)) + IOVEC_SET_STRING(iovec[n++], s->boot_id_field); + + if (!isempty(s->machine_id_field)) + IOVEC_SET_STRING(iovec[n++], s->machine_id_field); + + if (!isempty(s->hostname_field)) + IOVEC_SET_STRING(iovec[n++], s->hostname_field); + + assert(n <= m); + + if (s->split_mode == SPLIT_UID && realuid > 0) + /* Split up strictly by any UID */ + journal_uid = realuid; + else if (s->split_mode == SPLIT_LOGIN && realuid > 0 && owner_valid && owner > 0) + /* Split up by login UIDs, this avoids creation of + * individual journals for system UIDs. We do this + * only if the realuid is not root, in order not to + * accidentally leak privileged information to the + * user that is logged by a privileged process that is + * part of an unprivileged session.*/ + journal_uid = owner; + else + journal_uid = 0; + + write_to_journal(s, journal_uid, iovec, n, priority); +} + +void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) { + char mid[11 + 32 + 1]; + char buffer[16 + LINE_MAX + 1]; + struct iovec iovec[N_IOVEC_META_FIELDS + 4]; + int n = 0; + va_list ap; + struct ucred ucred = {}; + + assert(s); + assert(format); + + IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver"); + + memcpy(buffer, "MESSAGE=", 8); + va_start(ap, format); + vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap); + va_end(ap); + char_array_0(buffer); + IOVEC_SET_STRING(iovec[n++], buffer); + + if (!sd_id128_equal(message_id, SD_ID128_NULL)) { + snprintf(mid, sizeof(mid), MESSAGE_ID(message_id)); + char_array_0(mid); + IOVEC_SET_STRING(iovec[n++], mid); + } + + ucred.pid = getpid(); + ucred.uid = getuid(); + ucred.gid = getgid(); + + dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0); +} + +void server_dispatch_message( + Server *s, + struct iovec *iovec, unsigned n, unsigned m, + struct ucred *ucred, + struct timeval *tv, + const char *label, size_t label_len, + const char *unit_id, + int priority, + pid_t object_pid) { + + int rl, r; + _cleanup_free_ char *path = NULL; + char *c; + + assert(s); + assert(iovec || n == 0); + + if (n == 0) + return; + + if (LOG_PRI(priority) > s->max_level_store) + return; + + /* Stop early in case the information will not be stored + * in a journal. */ + if (s->storage == STORAGE_NONE) + return; + + if (!ucred) + goto finish; + + r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &path); + if (r < 0) + goto finish; + + /* example: /user/lennart/3/foobar + * /system/dbus.service/foobar + * + * So let's cut of everything past the third /, since that is + * where user directories start */ + + c = strchr(path, '/'); + if (c) { + c = strchr(c+1, '/'); + if (c) { + c = strchr(c+1, '/'); + if (c) + *c = 0; + } + } + + rl = journal_rate_limit_test(s->rate_limit, path, + priority & LOG_PRIMASK, available_space(s, false)); + + if (rl == 0) + return; + + /* Write a suppression message if we suppressed something */ + if (rl > 1) + server_driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, + "Suppressed %u messages from %s", rl - 1, path); + +finish: + dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid); +} + + +static int system_journal_open(Server *s) { + int r; + char *fn; + sd_id128_t machine; + char ids[33]; + + r = sd_id128_get_machine(&machine); + if (r < 0) { + log_error("Failed to get machine id: %s", strerror(-r)); + return r; + } + + sd_id128_to_string(machine, ids); + + if (!s->system_journal && + (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && + access("/run/systemd/journal/flushed", F_OK) >= 0) { + + /* If in auto mode: first try to create the machine + * path, but not the prefix. + * + * If in persistent mode: create /var/log/journal and + * the machine path */ + + if (s->storage == STORAGE_PERSISTENT) + (void) mkdir("/var/log/journal/", 0755); + + fn = strappenda("/var/log/journal/", ids); + (void) mkdir(fn, 0755); + + fn = strappenda(fn, "/system.journal"); + r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); + + if (r >= 0) + server_fix_perms(s, s->system_journal, 0); + else if (r < 0) { + if (r != -ENOENT && r != -EROFS) + log_warning("Failed to open system journal: %s", strerror(-r)); + + r = 0; + } + } + + if (!s->runtime_journal && + (s->storage != STORAGE_NONE)) { + + fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL); + if (!fn) + return -ENOMEM; + + if (s->system_journal) { + + /* Try to open the runtime journal, but only + * if it already exists, so that we can flush + * it into the system journal */ + + r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); + free(fn); + + if (r < 0) { + if (r != -ENOENT) + log_warning("Failed to open runtime journal: %s", strerror(-r)); + + r = 0; + } + + } else { + + /* OK, we really need the runtime journal, so create + * it if necessary. */ + + (void) mkdir_parents(fn, 0755); + r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); + free(fn); + + if (r < 0) { + log_error("Failed to open runtime journal: %s", strerror(-r)); + return r; + } + } + + if (s->runtime_journal) + server_fix_perms(s, s->runtime_journal, 0); + } + + available_space(s, true); + + return r; +} + +int server_flush_to_var(Server *s) { + sd_id128_t machine; + sd_journal *j = NULL; + char ts[FORMAT_TIMESPAN_MAX]; + usec_t start; + unsigned n = 0; + int r; + + assert(s); + + if (s->storage != STORAGE_AUTO && + s->storage != STORAGE_PERSISTENT) + return 0; + + if (!s->runtime_journal) + return 0; + + system_journal_open(s); + + if (!s->system_journal) + return 0; + + log_debug("Flushing to /var..."); + + start = now(CLOCK_MONOTONIC); + + r = sd_id128_get_machine(&machine); + if (r < 0) + return r; + + r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY); + if (r < 0) { + log_error("Failed to read runtime journal: %s", strerror(-r)); + return r; + } + + sd_journal_set_data_threshold(j, 0); + + SD_JOURNAL_FOREACH(j) { + Object *o = NULL; + JournalFile *f; + + f = j->current_file; + assert(f && f->current_offset > 0); + + n++; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) { + log_error("Can't read entry: %s", strerror(-r)); + goto finish; + } + + r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL); + if (r >= 0) + continue; + + if (!shall_try_append_again(s->system_journal, r)) { + log_error("Can't write entry: %s", strerror(-r)); + goto finish; + } + + server_rotate(s); + server_vacuum(s); + + if (!s->system_journal) { + log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful."); + r = -EIO; + goto finish; + } + + log_debug("Retrying write."); + r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL); + if (r < 0) { + log_error("Can't write entry: %s", strerror(-r)); + goto finish; + } + } + +finish: + journal_file_post_change(s->system_journal); + + journal_file_close(s->runtime_journal); + s->runtime_journal = NULL; + + if (r >= 0) + rm_rf("/run/log/journal", false, true, false); + + sd_journal_close(j); + + server_driver_message(s, SD_ID128_NULL, "Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n); + + return r; +} + +int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; + + assert(s); + assert(fd == s->native_fd || fd == s->syslog_fd); + + if (revents != EPOLLIN) { + log_error("Got invalid event from epoll for datagram fd: %"PRIx32, revents); + return -EIO; + } + + for (;;) { + struct ucred *ucred = NULL; + struct timeval *tv = NULL; + struct cmsghdr *cmsg; + char *label = NULL; + size_t label_len = 0; + struct iovec iovec; + + union { + struct cmsghdr cmsghdr; + + /* We use NAME_MAX space for the + * SELinux label here. The kernel + * currently enforces no limit, but + * according to suggestions from the + * SELinux people this will change and + * it will probably be identical to + * NAME_MAX. For now we use that, but + * this should be updated one day when + * the final limit is known.*/ + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(struct timeval)) + + CMSG_SPACE(sizeof(int)) + /* fd */ + CMSG_SPACE(NAME_MAX)]; /* selinux label */ + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + + ssize_t n; + int v; + int *fds = NULL; + unsigned n_fds = 0; + + if (ioctl(fd, SIOCINQ, &v) < 0) { + log_error("SIOCINQ failed: %m"); + return -errno; + } + + if (!GREEDY_REALLOC(s->buffer, s->buffer_size, LINE_MAX + (size_t) v)) + return log_oom(); + + iovec.iov_base = s->buffer; + iovec.iov_len = s->buffer_size; + + n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { + if (errno == EINTR || errno == EAGAIN) + return 0; + + log_error("recvmsg() failed: %m"); + return -errno; + } + + for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) + ucred = (struct ucred*) CMSG_DATA(cmsg); + else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_SECURITY) { + label = (char*) CMSG_DATA(cmsg); + label_len = cmsg->cmsg_len - CMSG_LEN(0); + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMP && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + tv = (struct timeval*) CMSG_DATA(cmsg); + else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + } + } + + if (fd == s->syslog_fd) { + if (n > 0 && n_fds == 0) { + s->buffer[n] = 0; + server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); + } else if (n_fds > 0) + log_warning("Got file descriptors via syslog socket. Ignoring."); + + } else { + if (n > 0 && n_fds == 0) + server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); + else if (n == 0 && n_fds == 1) + server_process_native_file(s, fds[0], ucred, tv, label, label_len); + else if (n_fds > 0) + log_warning("Got too many file descriptors via native socket. Ignoring."); + } + + close_many(fds, n_fds); + } + + return 0; +} + +static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + + assert(s); + + log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + + touch("/run/systemd/journal/flushed"); + server_flush_to_var(s); + server_sync(s); + + return 0; +} + +static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + + assert(s); + + log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid); + server_rotate(s); + server_vacuum(s); + + return 0; +} + +static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + + assert(s); + + log_received_signal(LOG_INFO, si); + + sd_event_exit(s->event, 0); + return 0; +} + +static int setup_signals(Server *s) { + sigset_t mask; + int r; + + assert(s); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); + if (r < 0) + return r; + + r = sd_event_add_signal(s->event, &s->sigusr2_event_source, SIGUSR2, dispatch_sigusr2, s); + if (r < 0) + return r; + + r = sd_event_add_signal(s->event, &s->sigterm_event_source, SIGTERM, dispatch_sigterm, s); + if (r < 0) + return r; + + r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s); + if (r < 0) + return r; + + return 0; +} + +static int server_parse_proc_cmdline(Server *s) { + _cleanup_free_ char *line = NULL; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return 0; + + FOREACH_WORD_QUOTED(w, l, line, state) { + _cleanup_free_ char *word; + + word = strndup(w, l); + if (!word) + return -ENOMEM; + + if (startswith(word, "systemd.journald.forward_to_syslog=")) { + r = parse_boolean(word + 35); + if (r < 0) + log_warning("Failed to parse forward to syslog switch %s. Ignoring.", word + 35); + else + s->forward_to_syslog = r; + } else if (startswith(word, "systemd.journald.forward_to_kmsg=")) { + r = parse_boolean(word + 33); + if (r < 0) + log_warning("Failed to parse forward to kmsg switch %s. Ignoring.", word + 33); + else + s->forward_to_kmsg = r; + } else if (startswith(word, "systemd.journald.forward_to_console=")) { + r = parse_boolean(word + 36); + if (r < 0) + log_warning("Failed to parse forward to console switch %s. Ignoring.", word + 36); + else + s->forward_to_console = r; + } else if (startswith(word, "systemd.journald")) + log_warning("Invalid systemd.journald parameter. Ignoring."); + } + + return 0; +} + +static int server_parse_config_file(Server *s) { + static const char fn[] = "/etc/systemd/journald.conf"; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(s); + + f = fopen(fn, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_warning("Failed to open configuration file %s: %m", fn); + return -errno; + } + + r = config_parse(NULL, fn, f, "Journal\0", config_item_perf_lookup, + (void*) journald_gperf_lookup, false, false, s); + if (r < 0) + log_warning("Failed to parse configuration file: %s", strerror(-r)); + + return r; +} + +static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) { + Server *s = userdata; + + assert(s); + + server_sync(s); + return 0; +} + +int server_schedule_sync(Server *s, int priority) { + int r; + + assert(s); + + if (priority <= LOG_CRIT) { + /* Immediately sync to disk when this is of priority CRIT, ALERT, EMERG */ + server_sync(s); + return 0; + } + + if (s->sync_scheduled) + return 0; + + if (s->sync_interval_usec > 0) { + usec_t when; + + r = sd_event_get_now_monotonic(s->event, &when); + if (r < 0) + return r; + + when += s->sync_interval_usec; + + if (!s->sync_event_source) { + r = sd_event_add_monotonic(s->event, &s->sync_event_source, when, 0, server_dispatch_sync, s); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s->sync_event_source, SD_EVENT_PRIORITY_IMPORTANT); + } else { + r = sd_event_source_set_time(s->sync_event_source, when); + if (r < 0) + return r; + + r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_ONESHOT); + } + if (r < 0) + return r; + + s->sync_scheduled = true; + } + + return 0; +} + +static int dispatch_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; + + assert(s); + + server_cache_hostname(s); + return 0; +} + +static int server_open_hostname(Server *s) { + int r; + + assert(s); + + s->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY); + if (s->hostname_fd < 0) { + log_error("Failed to open /proc/sys/kernel/hostname: %m"); + return -errno; + } + + r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s); + if (r < 0) { + /* kernels prior to 3.2 don't support polling this file. Ignore + * the failure. */ + if (r == -EPERM) { + log_warning("Failed to register hostname fd in event loop: %s. Ignoring.", + strerror(-r)); + close_nointr_nofail(s->hostname_fd); + s->hostname_fd = -1; + return 0; + } + + log_error("Failed to register hostname fd in event loop: %s", strerror(-r)); + return r; + } + + r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10); + if (r < 0) { + log_error("Failed to adjust priority of host name event source: %s", strerror(-r)); + return r; + } + + return 0; +} + +int server_init(Server *s) { + int n, r, fd; + + assert(s); + + zero(*s); + s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->hostname_fd = -1; + s->compress = true; + s->seal = true; + + s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC; + s->sync_scheduled = false; + + s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL; + s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST; + + s->forward_to_syslog = true; + + s->max_level_store = LOG_DEBUG; + s->max_level_syslog = LOG_DEBUG; + s->max_level_kmsg = LOG_NOTICE; + s->max_level_console = LOG_INFO; + + memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics)); + memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics)); + + server_parse_config_file(s); + server_parse_proc_cmdline(s); + if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) { + log_debug("Setting both rate limit interval and burst from %llu,%u to 0,0", + (long long unsigned) s->rate_limit_interval, + s->rate_limit_burst); + s->rate_limit_interval = s->rate_limit_burst = 0; + } + + mkdir_p("/run/systemd/journal", 0755); + + s->user_journals = hashmap_new(trivial_hash_func, trivial_compare_func); + if (!s->user_journals) + return log_oom(); + + s->mmap = mmap_cache_new(); + if (!s->mmap) + return log_oom(); + + r = sd_event_default(&s->event); + if (r < 0) { + log_error("Failed to create event loop: %s", strerror(-r)); + return r; + } + + sd_event_set_watchdog(s->event, true); + + n = sd_listen_fds(true); + if (n < 0) { + log_error("Failed to read listening file descriptors from environment: %s", strerror(-n)); + return n; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + + if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/socket", 0) > 0) { + + if (s->native_fd >= 0) { + log_error("Too many native sockets passed."); + return -EINVAL; + } + + s->native_fd = fd; + + } else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, "/run/systemd/journal/stdout", 0) > 0) { + + if (s->stdout_fd >= 0) { + log_error("Too many stdout sockets passed."); + return -EINVAL; + } + + s->stdout_fd = fd; + + } else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0) { + + if (s->syslog_fd >= 0) { + log_error("Too many /dev/log sockets passed."); + return -EINVAL; + } + + s->syslog_fd = fd; + + } else { + log_error("Unknown socket passed."); + return -EINVAL; + } + } + + r = server_open_syslog_socket(s); + if (r < 0) + return r; + + r = server_open_native_socket(s); + if (r < 0) + return r; + + r = server_open_stdout_socket(s); + if (r < 0) + return r; + + r = server_open_dev_kmsg(s); + if (r < 0) + return r; + + r = server_open_kernel_seqnum(s); + if (r < 0) + return r; + + r = server_open_hostname(s); + if (r < 0) + return r; + + r = setup_signals(s); + if (r < 0) + return r; + + s->udev = udev_new(); + if (!s->udev) + return -ENOMEM; + + s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst); + if (!s->rate_limit) + return -ENOMEM; + + r = cg_get_root_path(&s->cgroup_root); + if (r < 0) + return r; + + server_cache_hostname(s); + server_cache_boot_id(s); + server_cache_machine_id(s); + + r = system_journal_open(s); + if (r < 0) + return r; + + return 0; +} + +void server_maybe_append_tags(Server *s) { +#ifdef HAVE_GCRYPT + JournalFile *f; + Iterator i; + usec_t n; + + n = now(CLOCK_REALTIME); + + if (s->system_journal) + journal_file_maybe_append_tag(s->system_journal, n); + + HASHMAP_FOREACH(f, s->user_journals, i) + journal_file_maybe_append_tag(f, n); +#endif +} + +void server_done(Server *s) { + JournalFile *f; + assert(s); + + while (s->stdout_streams) + stdout_stream_free(s->stdout_streams); + + if (s->system_journal) + journal_file_close(s->system_journal); + + if (s->runtime_journal) + journal_file_close(s->runtime_journal); + + while ((f = hashmap_steal_first(s->user_journals))) + journal_file_close(f); + + hashmap_free(s->user_journals); + + sd_event_source_unref(s->syslog_event_source); + sd_event_source_unref(s->native_event_source); + sd_event_source_unref(s->stdout_event_source); + sd_event_source_unref(s->dev_kmsg_event_source); + sd_event_source_unref(s->sync_event_source); + sd_event_source_unref(s->sigusr1_event_source); + sd_event_source_unref(s->sigusr2_event_source); + sd_event_source_unref(s->sigterm_event_source); + sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->hostname_event_source); + sd_event_unref(s->event); + + if (s->syslog_fd >= 0) + close_nointr_nofail(s->syslog_fd); + + if (s->native_fd >= 0) + close_nointr_nofail(s->native_fd); + + if (s->stdout_fd >= 0) + close_nointr_nofail(s->stdout_fd); + + if (s->dev_kmsg_fd >= 0) + close_nointr_nofail(s->dev_kmsg_fd); + + if (s->hostname_fd >= 0) + close_nointr_nofail(s->hostname_fd); + + if (s->rate_limit) + journal_rate_limit_free(s->rate_limit); + + if (s->kernel_seqnum) + munmap(s->kernel_seqnum, sizeof(uint64_t)); + + free(s->buffer); + free(s->tty_path); + free(s->cgroup_root); + + if (s->mmap) + mmap_cache_unref(s->mmap); + + if (s->udev) + udev_unref(s->udev); +} diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h new file mode 100644 index 0000000..2a81061 --- /dev/null +++ b/src/journal/journald-server.h @@ -0,0 +1,175 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "sd-event.h" +#include "journal-file.h" +#include "hashmap.h" +#include "util.h" +#include "audit.h" +#include "journald-rate-limit.h" +#include "list.h" + +typedef enum Storage { + STORAGE_AUTO, + STORAGE_VOLATILE, + STORAGE_PERSISTENT, + STORAGE_NONE, + _STORAGE_MAX, + _STORAGE_INVALID = -1 +} Storage; + +typedef enum SplitMode { + SPLIT_LOGIN, + SPLIT_UID, + SPLIT_NONE, + _SPLIT_MAX, + _SPLIT_INVALID = -1 +} SplitMode; + +typedef struct StdoutStream StdoutStream; + +typedef struct Server { + int syslog_fd; + int native_fd; + int stdout_fd; + int dev_kmsg_fd; + int hostname_fd; + + sd_event *event; + + sd_event_source *syslog_event_source; + sd_event_source *native_event_source; + sd_event_source *stdout_event_source; + sd_event_source *dev_kmsg_event_source; + sd_event_source *sync_event_source; + sd_event_source *sigusr1_event_source; + sd_event_source *sigusr2_event_source; + sd_event_source *sigterm_event_source; + sd_event_source *sigint_event_source; + sd_event_source *hostname_event_source; + + JournalFile *runtime_journal; + JournalFile *system_journal; + Hashmap *user_journals; + + uint64_t seqnum; + + char *buffer; + size_t buffer_size; + + JournalRateLimit *rate_limit; + usec_t sync_interval_usec; + usec_t rate_limit_interval; + unsigned rate_limit_burst; + + JournalMetrics runtime_metrics; + JournalMetrics system_metrics; + + bool compress; + bool seal; + + bool forward_to_kmsg; + bool forward_to_syslog; + bool forward_to_console; + + unsigned n_forward_syslog_missed; + usec_t last_warn_forward_syslog_missed; + + uint64_t cached_available_space; + usec_t cached_available_space_timestamp; + + uint64_t var_available_timestamp; + + usec_t max_retention_usec; + usec_t max_file_usec; + usec_t oldest_file_usec; + + LIST_HEAD(StdoutStream, stdout_streams); + unsigned n_stdout_streams; + + char *tty_path; + + int max_level_store; + int max_level_syslog; + int max_level_kmsg; + int max_level_console; + + Storage storage; + SplitMode split_mode; + + MMapCache *mmap; + + bool dev_kmsg_readable; + + uint64_t *kernel_seqnum; + + struct udev *udev; + + bool sync_scheduled; + + char machine_id_field[sizeof("_MACHINE_ID=") + 32]; + char boot_id_field[sizeof("_BOOT_ID=") + 32]; + char *hostname_field; + + /* Cached cgroup root, so that we don't have to query that all the time */ + char *cgroup_root; +} Server; + +#define N_IOVEC_META_FIELDS 20 +#define N_IOVEC_KERNEL_FIELDS 64 +#define N_IOVEC_UDEV_FIELDS 32 +#define N_IOVEC_OBJECT_FIELDS 11 + +void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); +void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4); + +/* gperf lookup function */ +const struct ConfigPerfItem* journald_gperf_lookup(const char *key, unsigned length); + +int config_parse_storage(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const char *storage_to_string(Storage s) _const_; +Storage storage_from_string(const char *s) _pure_; + +int config_parse_split_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const char *split_mode_to_string(SplitMode s) _const_; +SplitMode split_mode_from_string(const char *s) _pure_; + +void server_fix_perms(Server *s, JournalFile *f, uid_t uid); +bool shall_try_append_again(JournalFile *f, int r); +int server_init(Server *s); +void server_done(Server *s); +void server_sync(Server *s); +void server_vacuum(Server *s); +void server_rotate(Server *s); +int server_schedule_sync(Server *s, int priority); +int server_flush_to_var(Server *s); +void server_maybe_append_tags(Server *s); +int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c new file mode 100644 index 0000000..36fc755 --- /dev/null +++ b/src/journal/journald-stream.c @@ -0,0 +1,476 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#ifdef HAVE_SELINUX +#include +#endif + +#include "sd-event.h" +#include "socket-util.h" +#include "selinux-util.h" +#include "journald-server.h" +#include "journald-stream.h" +#include "journald-syslog.h" +#include "journald-kmsg.h" +#include "journald-console.h" + +#define STDOUT_STREAMS_MAX 4096 + +typedef enum StdoutStreamState { + STDOUT_STREAM_IDENTIFIER, + STDOUT_STREAM_UNIT_ID, + STDOUT_STREAM_PRIORITY, + STDOUT_STREAM_LEVEL_PREFIX, + STDOUT_STREAM_FORWARD_TO_SYSLOG, + STDOUT_STREAM_FORWARD_TO_KMSG, + STDOUT_STREAM_FORWARD_TO_CONSOLE, + STDOUT_STREAM_RUNNING +} StdoutStreamState; + +struct StdoutStream { + Server *server; + StdoutStreamState state; + + int fd; + + struct ucred ucred; +#ifdef HAVE_SELINUX + security_context_t security_context; +#endif + + char *identifier; + char *unit_id; + int priority; + bool level_prefix:1; + bool forward_to_syslog:1; + bool forward_to_kmsg:1; + bool forward_to_console:1; + + char buffer[LINE_MAX+1]; + size_t length; + + sd_event_source *event_source; + + LIST_FIELDS(StdoutStream, stdout_stream); +}; + +static int stdout_stream_log(StdoutStream *s, const char *p) { + struct iovec iovec[N_IOVEC_META_FIELDS + 5]; + int priority; + char syslog_priority[] = "PRIORITY=\0"; + char syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(priority)]; + _cleanup_free_ char *message = NULL, *syslog_identifier = NULL; + unsigned n = 0; + char *label = NULL; + size_t label_len = 0; + + assert(s); + assert(p); + + if (isempty(p)) + return 0; + + priority = s->priority; + + if (s->level_prefix) + syslog_parse_priority(&p, &priority, false); + + if (s->forward_to_syslog || s->server->forward_to_syslog) + server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); + + if (s->forward_to_kmsg || s->server->forward_to_kmsg) + server_forward_kmsg(s->server, priority, s->identifier, p, &s->ucred); + + if (s->forward_to_console || s->server->forward_to_console) + server_forward_console(s->server, priority, s->identifier, p, &s->ucred); + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout"); + + syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority); + IOVEC_SET_STRING(iovec[n++], syslog_priority); + + if (priority & LOG_FACMASK) { + snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority)); + IOVEC_SET_STRING(iovec[n++], syslog_facility); + } + + if (s->identifier) { + syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier); + if (syslog_identifier) + IOVEC_SET_STRING(iovec[n++], syslog_identifier); + } + + message = strappend("MESSAGE=", p); + if (message) + IOVEC_SET_STRING(iovec[n++], message); + +#ifdef HAVE_SELINUX + if (s->security_context) { + label = (char*) s->security_context; + label_len = strlen((char*) s->security_context); + } +#endif + + server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0); + return 0; +} + +static int stdout_stream_line(StdoutStream *s, char *p) { + int r; + + assert(s); + assert(p); + + p = strstrip(p); + + switch (s->state) { + + case STDOUT_STREAM_IDENTIFIER: + if (isempty(p)) + s->identifier = NULL; + else { + s->identifier = strdup(p); + if (!s->identifier) + return log_oom(); + } + + s->state = STDOUT_STREAM_UNIT_ID; + return 0; + + case STDOUT_STREAM_UNIT_ID: + if (s->ucred.uid == 0) { + if (isempty(p)) + s->unit_id = NULL; + else { + s->unit_id = strdup(p); + if (!s->unit_id) + return log_oom(); + } + } + + s->state = STDOUT_STREAM_PRIORITY; + return 0; + + case STDOUT_STREAM_PRIORITY: + r = safe_atoi(p, &s->priority); + if (r < 0 || s->priority < 0 || s->priority > 999) { + log_warning("Failed to parse log priority line."); + return -EINVAL; + } + + s->state = STDOUT_STREAM_LEVEL_PREFIX; + return 0; + + case STDOUT_STREAM_LEVEL_PREFIX: + r = parse_boolean(p); + if (r < 0) { + log_warning("Failed to parse level prefix line."); + return -EINVAL; + } + + s->level_prefix = !!r; + s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG; + return 0; + + case STDOUT_STREAM_FORWARD_TO_SYSLOG: + r = parse_boolean(p); + if (r < 0) { + log_warning("Failed to parse forward to syslog line."); + return -EINVAL; + } + + s->forward_to_syslog = !!r; + s->state = STDOUT_STREAM_FORWARD_TO_KMSG; + return 0; + + case STDOUT_STREAM_FORWARD_TO_KMSG: + r = parse_boolean(p); + if (r < 0) { + log_warning("Failed to parse copy to kmsg line."); + return -EINVAL; + } + + s->forward_to_kmsg = !!r; + s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE; + return 0; + + case STDOUT_STREAM_FORWARD_TO_CONSOLE: + r = parse_boolean(p); + if (r < 0) { + log_warning("Failed to parse copy to console line."); + return -EINVAL; + } + + s->forward_to_console = !!r; + s->state = STDOUT_STREAM_RUNNING; + return 0; + + case STDOUT_STREAM_RUNNING: + return stdout_stream_log(s, p); + } + + assert_not_reached("Unknown stream state"); +} + +static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + char *p; + size_t remaining; + int r; + + assert(s); + + p = s->buffer; + remaining = s->length; + for (;;) { + char *end; + size_t skip; + + end = memchr(p, '\n', remaining); + if (end) + skip = end - p + 1; + else if (remaining >= sizeof(s->buffer) - 1) { + end = p + sizeof(s->buffer) - 1; + skip = remaining; + } else + break; + + *end = 0; + + r = stdout_stream_line(s, p); + if (r < 0) + return r; + + remaining -= skip; + p += skip; + } + + if (force_flush && remaining > 0) { + p[remaining] = 0; + r = stdout_stream_line(s, p); + if (r < 0) + return r; + + p += remaining; + remaining = 0; + } + + if (p > s->buffer) { + memmove(s->buffer, p, remaining); + s->length = remaining; + } + + return 0; +} + +static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + StdoutStream *s = userdata; + ssize_t l; + int r; + + assert(s); + + if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) { + log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents); + goto terminate; + } + + l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length); + if (l < 0) { + + if (errno == EAGAIN) + return 0; + + log_warning("Failed to read from stream: %m"); + goto terminate; + } + + if (l == 0) { + stdout_stream_scan(s, true); + goto terminate; + } + + s->length += l; + r = stdout_stream_scan(s, false); + if (r < 0) + goto terminate; + + return 1; + +terminate: + stdout_stream_free(s); + return 0; +} + +void stdout_stream_free(StdoutStream *s) { + assert(s); + + if (s->server) { + assert(s->server->n_stdout_streams > 0); + s->server->n_stdout_streams --; + LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); + } + + if (s->event_source) { + sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF); + s->event_source = sd_event_source_unref(s->event_source); + } + + if (s->fd >= 0) + close_nointr_nofail(s->fd); + +#ifdef HAVE_SELINUX + if (s->security_context) + freecon(s->security_context); +#endif + + free(s->identifier); + free(s->unit_id); + free(s); +} + +static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) { + Server *s = userdata; + StdoutStream *stream; + int fd, r; + + assert(s); + + if (revents != EPOLLIN) { + log_error("Got invalid event from epoll for stdout server fd: %"PRIx32, revents); + return -EIO; + } + + fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (fd < 0) { + if (errno == EAGAIN) + return 0; + + log_error("Failed to accept stdout connection: %m"); + return -errno; + } + + if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { + log_warning("Too many stdout streams, refusing connection."); + close_nointr_nofail(fd); + return 0; + } + + stream = new0(StdoutStream, 1); + if (!stream) { + close_nointr_nofail(fd); + return log_oom(); + } + + stream->fd = fd; + + r = getpeercred(fd, &stream->ucred); + if (r < 0) { + log_error("Failed to determine peer credentials: %m"); + goto fail; + } + +#ifdef HAVE_SELINUX + if (use_selinux()) { + if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT) + log_error("Failed to determine peer security context: %m"); + } +#endif + + if (shutdown(fd, SHUT_WR) < 0) { + log_error("Failed to shutdown writing side of socket: %m"); + goto fail; + } + + r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream); + if (r < 0) { + log_error("Failed to add stream to event loop: %s", strerror(-r)); + goto fail; + } + + r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5); + if (r < 0) { + log_error("Failed to adjust stdout event source priority: %s", strerror(-r)); + goto fail; + } + + stream->server = s; + LIST_PREPEND(stdout_stream, s->stdout_streams, stream); + s->n_stdout_streams ++; + + return 0; + +fail: + stdout_stream_free(stream); + return 0; +} + +int server_open_stdout_socket(Server *s) { + int r; + + assert(s); + + if (s->stdout_fd < 0) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/stdout", + }; + + s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (s->stdout_fd < 0) { + log_error("socket() failed: %m"); + return -errno; + } + + unlink(sa.un.sun_path); + + r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { + log_error("bind() failed: %m"); + return -errno; + } + + chmod(sa.un.sun_path, 0666); + + if (listen(s->stdout_fd, SOMAXCONN) < 0) { + log_error("listen() failed: %m"); + return -errno; + } + } else + fd_nonblock(s->stdout_fd, 1); + + r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s); + if (r < 0) { + log_error("Failed to add stdout server fd to event source: %s", strerror(-r)); + return r; + } + + r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10); + if (r < 0) { + log_error("Failed to adjust priority of stdout server event source: %s", strerror(-r)); + return r; + } + + return 0; +} diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h new file mode 100644 index 0000000..8cad012 --- /dev/null +++ b/src/journal/journald-stream.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-server.h" + +int server_open_stdout_socket(Server *s); + +void stdout_stream_free(StdoutStream *s); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c new file mode 100644 index 0000000..241f7ed --- /dev/null +++ b/src/journal/journald-syslog.c @@ -0,0 +1,495 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "systemd/sd-messages.h" +#include "socket-util.h" +#include "selinux-util.h" +#include "journald-server.h" +#include "journald-syslog.h" +#include "journald-kmsg.h" +#include "journald-console.h" + +/* Warn once every 30s if we missed syslog message */ +#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC) + +static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) { + + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/syslog", + }; + struct msghdr msghdr = { + .msg_iov = (struct iovec *) iovec, + .msg_iovlen = n_iovec, + .msg_name = &sa, + .msg_namelen = offsetof(union sockaddr_union, un.sun_path) + + sizeof("/run/systemd/journal/syslog") - 1, + }; + struct cmsghdr *cmsg; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + + assert(s); + assert(iovec); + assert(n_iovec > 0); + + if (ucred) { + zero(control); + msghdr.msg_control = &control; + msghdr.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&msghdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred)); + msghdr.msg_controllen = cmsg->cmsg_len; + } + + /* Forward the syslog message we received via /dev/log to + * /run/systemd/syslog. Unfortunately we currently can't set + * the SO_TIMESTAMP auxiliary data, and hence we don't. */ + + if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) + return; + + /* The socket is full? I guess the syslog implementation is + * too slow, and we shouldn't wait for that... */ + if (errno == EAGAIN) { + s->n_forward_syslog_missed++; + return; + } + + if (ucred && errno == ESRCH) { + struct ucred u; + + /* Hmm, presumably the sender process vanished + * by now, so let's fix it as good as we + * can, and retry */ + + u = *ucred; + u.pid = getpid(); + memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred)); + + if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) + return; + + if (errno == EAGAIN) { + s->n_forward_syslog_missed++; + return; + } + } + + if (errno != ENOENT) + log_debug("Failed to forward syslog message: %m"); +} + +static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) { + struct iovec iovec; + + assert(s); + assert(buffer); + + if (LOG_PRI(priority) > s->max_level_syslog) + return; + + IOVEC_SET_STRING(iovec, buffer); + forward_syslog_iovec(s, &iovec, 1, ucred, tv); +} + +void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) { + struct iovec iovec[5]; + char header_priority[6], header_time[64], header_pid[16]; + int n = 0; + time_t t; + struct tm *tm; + char *ident_buf = NULL; + + assert(s); + assert(priority >= 0); + assert(priority <= 999); + assert(message); + + if (LOG_PRI(priority) > s->max_level_syslog) + return; + + /* First: priority field */ + snprintf(header_priority, sizeof(header_priority), "<%i>", priority); + char_array_0(header_priority); + IOVEC_SET_STRING(iovec[n++], header_priority); + + /* Second: timestamp */ + t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC)); + tm = localtime(&t); + if (!tm) + return; + if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) + return; + IOVEC_SET_STRING(iovec[n++], header_time); + + /* Third: identifier and PID */ + if (ucred) { + if (!identifier) { + get_process_comm(ucred->pid, &ident_buf); + identifier = ident_buf; + } + + snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); + char_array_0(header_pid); + + if (identifier) + IOVEC_SET_STRING(iovec[n++], identifier); + + IOVEC_SET_STRING(iovec[n++], header_pid); + } else if (identifier) { + IOVEC_SET_STRING(iovec[n++], identifier); + IOVEC_SET_STRING(iovec[n++], ": "); + } + + /* Fourth: message */ + IOVEC_SET_STRING(iovec[n++], message); + + forward_syslog_iovec(s, iovec, n, ucred, tv); + + free(ident_buf); +} + +int syslog_fixup_facility(int priority) { + + if ((priority & LOG_FACMASK) == 0) + return (priority & LOG_PRIMASK) | LOG_USER; + + return priority; +} + +size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) { + const char *p; + char *t; + size_t l, e; + + assert(buf); + assert(identifier); + assert(pid); + + p = *buf; + + p += strspn(p, WHITESPACE); + l = strcspn(p, WHITESPACE); + + if (l <= 0 || + p[l-1] != ':') + return 0; + + e = l; + l--; + + if (p[l-1] == ']') { + size_t k = l-1; + + for (;;) { + + if (p[k] == '[') { + t = strndup(p+k+1, l-k-2); + if (t) + *pid = t; + + l = k; + break; + } + + if (k == 0) + break; + + k--; + } + } + + t = strndup(p, l); + if (t) + *identifier = t; + + e += strspn(p + e, WHITESPACE); + *buf = p + e; + return e; +} + +void syslog_parse_priority(const char **p, int *priority, bool with_facility) { + int a = 0, b = 0, c = 0; + int k; + + assert(p); + assert(*p); + assert(priority); + + if ((*p)[0] != '<') + return; + + if (!strchr(*p, '>')) + return; + + if ((*p)[2] == '>') { + c = undecchar((*p)[1]); + k = 3; + } else if ((*p)[3] == '>') { + b = undecchar((*p)[1]); + c = undecchar((*p)[2]); + k = 4; + } else if ((*p)[4] == '>') { + a = undecchar((*p)[1]); + b = undecchar((*p)[2]); + c = undecchar((*p)[3]); + k = 5; + } else + return; + + if (a < 0 || b < 0 || c < 0 || + (!with_facility && (a || b || c > 7))) + return; + + if (with_facility) + *priority = a*100 + b*10 + c; + else + *priority = (*priority & LOG_FACMASK) | c; + *p += k; +} + +static void syslog_skip_date(char **buf) { + enum { + LETTER, + SPACE, + NUMBER, + SPACE_OR_NUMBER, + COLON + } sequence[] = { + LETTER, LETTER, LETTER, + SPACE, + SPACE_OR_NUMBER, NUMBER, + SPACE, + SPACE_OR_NUMBER, NUMBER, + COLON, + SPACE_OR_NUMBER, NUMBER, + COLON, + SPACE_OR_NUMBER, NUMBER, + SPACE + }; + + char *p; + unsigned i; + + assert(buf); + assert(*buf); + + p = *buf; + + for (i = 0; i < ELEMENTSOF(sequence); i++, p++) { + + if (!*p) + return; + + switch (sequence[i]) { + + case SPACE: + if (*p != ' ') + return; + break; + + case SPACE_OR_NUMBER: + if (*p == ' ') + break; + + /* fall through */ + + case NUMBER: + if (*p < '0' || *p > '9') + return; + + break; + + case LETTER: + if (!(*p >= 'A' && *p <= 'Z') && + !(*p >= 'a' && *p <= 'z')) + return; + + break; + + case COLON: + if (*p != ':') + return; + break; + + } + } + + *buf = p; +} + +void server_process_syslog_message( + Server *s, + const char *buf, + struct ucred *ucred, + struct timeval *tv, + const char *label, + size_t label_len) { + + char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; + struct iovec iovec[N_IOVEC_META_FIELDS + 6]; + unsigned n = 0; + int priority = LOG_USER | LOG_INFO; + char *identifier = NULL, *pid = NULL; + const char *orig; + + assert(s); + assert(buf); + + orig = buf; + syslog_parse_priority(&buf, &priority, true); + + if (s->forward_to_syslog) + forward_syslog_raw(s, priority, orig, ucred, tv); + + syslog_skip_date((char**) &buf); + syslog_parse_identifier(&buf, &identifier, &pid); + + if (s->forward_to_kmsg) + server_forward_kmsg(s, priority, identifier, buf, ucred); + + if (s->forward_to_console) + server_forward_console(s, priority, identifier, buf, ucred); + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog"); + + if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) + IOVEC_SET_STRING(iovec[n++], syslog_priority); + + if (priority & LOG_FACMASK) + if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) + IOVEC_SET_STRING(iovec[n++], syslog_facility); + + if (identifier) { + syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier); + if (syslog_identifier) + IOVEC_SET_STRING(iovec[n++], syslog_identifier); + } + + if (pid) { + syslog_pid = strappend("SYSLOG_PID=", pid); + if (syslog_pid) + IOVEC_SET_STRING(iovec[n++], syslog_pid); + } + + message = strappend("MESSAGE=", buf); + if (message) + IOVEC_SET_STRING(iovec[n++], message); + + server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0); + + free(message); + free(identifier); + free(pid); + free(syslog_priority); + free(syslog_facility); + free(syslog_identifier); + free(syslog_pid); +} + +int server_open_syslog_socket(Server *s) { + int one, r; + + assert(s); + + if (s->syslog_fd < 0) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/dev/log", + }; + + s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (s->syslog_fd < 0) { + log_error("socket() failed: %m"); + return -errno; + } + + unlink(sa.un.sun_path); + + r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + if (r < 0) { + log_error("bind() failed: %m"); + return -errno; + } + + chmod(sa.un.sun_path, 0666); + } else + fd_nonblock(s->syslog_fd, 1); + + one = 1; + r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + if (r < 0) { + log_error("SO_PASSCRED failed: %m"); + return -errno; + } + +#ifdef HAVE_SELINUX + if (use_selinux()) { + one = 1; + r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); + if (r < 0) + log_warning("SO_PASSSEC failed: %m"); + } +#endif + + one = 1; + r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); + if (r < 0) { + log_error("SO_TIMESTAMP failed: %m"); + return -errno; + } + + r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, process_datagram, s); + if (r < 0) { + log_error("Failed to add syslog server fd to event loop: %s", strerror(-r)); + return r; + } + + return 0; +} + +void server_maybe_warn_forward_syslog_missed(Server *s) { + usec_t n; + assert(s); + + if (s->n_forward_syslog_missed <= 0) + return; + + n = now(CLOCK_MONOTONIC); + if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n) + return; + + server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed); + + s->n_forward_syslog_missed = 0; + s->last_warn_forward_syslog_missed = n; +} diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h new file mode 100644 index 0000000..057ea79 --- /dev/null +++ b/src/journal/journald-syslog.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-server.h" + +int syslog_fixup_facility(int priority) _const_; + +void syslog_parse_priority(const char **p, int *priority, bool with_facility); +size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid); + +void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv); + +void server_process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len); +int server_open_syslog_socket(Server *s); + +void server_maybe_warn_forward_syslog_missed(Server *s); diff --git a/src/journal/journald.c b/src/journal/journald.c new file mode 100644 index 0000000..37896d0 --- /dev/null +++ b/src/journal/journald.c @@ -0,0 +1,130 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "journal-authenticate.h" +#include "journald-server.h" +#include "journald-kmsg.h" +#include "journald-syslog.h" + +int main(int argc, char *argv[]) { + Server server; + int r; + + /* if (getppid() != 1) { */ + /* log_error("This program should be invoked by init only."); */ + /* return EXIT_FAILURE; */ + /* } */ + + if (argc > 1) { + log_error("This program does not take arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_SAFE); + log_set_facility(LOG_SYSLOG); + log_parse_environment(); + log_open(); + + umask(0022); + + r = server_init(&server); + if (r < 0) + goto finish; + + server_vacuum(&server); + server_flush_to_var(&server); + server_flush_dev_kmsg(&server); + + log_debug("systemd-journald running as pid %lu", (unsigned long) getpid()); + server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + for (;;) { + usec_t t = (usec_t) -1, n; + + r = sd_event_get_state(server.event); + if (r < 0) + goto finish; + if (r == SD_EVENT_FINISHED) + break; + + n = now(CLOCK_REALTIME); + + if (server.max_retention_usec > 0 && server.oldest_file_usec > 0) { + + /* The retention time is reached, so let's vacuum! */ + if (server.oldest_file_usec + server.max_retention_usec < n) { + log_info("Retention time reached."); + server_rotate(&server); + server_vacuum(&server); + continue; + } + + /* Calculate when to rotate the next time */ + t = server.oldest_file_usec + server.max_retention_usec - n; + } + +#ifdef HAVE_GCRYPT + if (server.system_journal) { + usec_t u; + + if (journal_file_next_evolve_usec(server.system_journal, &u)) { + if (n >= u) + t = 0; + else + t = MIN(t, u - n); + } + } +#endif + + r = sd_event_run(server.event, t); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + r = -errno; + goto finish; + } + + server_maybe_append_tags(&server); + server_maybe_warn_forward_syslog_missed(&server); + } + + log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid()); + server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); + +finish: + sd_notify(false, "STATUS=Shutting down..."); + + server_done(&server); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/journal/journald.conf b/src/journal/journald.conf new file mode 100644 index 0000000..54f6833 --- /dev/null +++ b/src/journal/journald.conf @@ -0,0 +1,33 @@ +# 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. +# +# See journald.conf(5) for details + +[Journal] +#Storage=auto +#Compress=yes +#Seal=yes +#SplitMode=login +#SyncIntervalSec=5m +#RateLimitInterval=30s +#RateLimitBurst=1000 +#SystemMaxUse= +#SystemKeepFree= +#SystemMaxFileSize= +#RuntimeMaxUse= +#RuntimeKeepFree= +#RuntimeMaxFileSize= +#MaxRetentionSec= +#MaxFileSec=1month +#ForwardToSyslog=yes +#ForwardToKMsg=no +#ForwardToConsole=no +#TTYPath=/dev/console +#MaxLevelStore=debug +#MaxLevelSyslog=debug +#MaxLevelKMsg=notice +#MaxLevelConsole=info diff --git a/src/journal/lookup3.c b/src/journal/lookup3.c new file mode 100644 index 0000000..52ffdf7 --- /dev/null +++ b/src/journal/lookup3.c @@ -0,0 +1,1009 @@ +/* Slightly modified by Lennart Poettering, to avoid name clashes, and + * unexport a few functions. */ + +#include "lookup3.h" + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ +/* #define SELF_TEST 1 */ + +#include /* defines printf for tests */ +#include /* defines time_t for timings in the test */ +#include /* defines uint32_t etc */ +#include /* attempt to define endianness */ +#ifdef linux +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +-------------------------------------------------------------------- + This works on all machines. To be useful, it requires + -- that the key be an array of uint32_t's, and + -- that the length be the number of uint32_t's in the key + + The function hashword() is identical to hashlittle() on little-endian + machines, and identical to hashbig() on big-endian machines, + except that the length has to be measured in uint32_ts rather than in + bytes. hashlittle() is more complicated than hashword() only because + hashlittle() has to dance around fitting the key bytes into registers. +-------------------------------------------------------------------- +*/ +uint32_t jenkins_hashword( +const uint32_t *k, /* the key, an array of uint32_t values */ +size_t length, /* the length of the key, in uint32_ts */ +uint32_t initval) /* the previous hash, or an arbitrary value */ +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch(length) /* all the case statements fall through */ + { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + final(a,b,c); + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + return c; +} + + +/* +-------------------------------------------------------------------- +hashword2() -- same as hashword(), but take two seeds and return two +32-bit values. pc and pb must both be nonnull, and *pc and *pb must +both be initialized with seeds. If you pass in (*pb)==0, the output +(*pc) will be the same as the return value from hashword(). +-------------------------------------------------------------------- +*/ +void jenkins_hashword2 ( +const uint32_t *k, /* the key, an array of uint32_t values */ +size_t length, /* the length of the key, in uint32_ts */ +uint32_t *pc, /* IN: seed OUT: primary hash value */ +uint32_t *pb) /* IN: more seed OUT: secondary hash value */ +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc; + c += *pb; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch(length) /* all the case statements fall through */ + { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + final(a,b,c); + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + *pc=c; *pb=b; +} + + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + { + const uint8_t *k8 = (const uint8_t *) k; + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + +/* + * hashlittle2: return 2 32-bit hash values + * + * This is identical to hashlittle(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + */ +void jenkins_hashlittle2( + const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; + c += *pb; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + { + const uint8_t *k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + } + + final(a,b,c); + *pc=c; *pb=b; +} + + + +/* + * hashbig(): + * This is the same as hashword() on big-endian machines. It is different + * from hashlittle() on all machines. hashbig() takes advantage of + * big-endian byte ordering. + */ +uint32_t jenkins_hashbig( const void *key, size_t length, uint32_t initval) +{ + uint32_t a,b,c; + union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because the + * string is aligned, the illegal read is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; + case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; + case 5 : b+=k[1]&0xff000000; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff00; break; + case 2 : a+=k[0]&0xffff0000; break; + case 1 : a+=k[0]&0xff000000; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + { + const uint8_t *k8 = (const uint8_t *)k; + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ + case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ + case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ + case 1 : a+=((uint32_t)k8[0])<<24; break; + case 0 : return c; + } + } + +#endif /* !VALGRIND */ + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += ((uint32_t)k[0])<<24; + a += ((uint32_t)k[1])<<16; + a += ((uint32_t)k[2])<<8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4])<<24; + b += ((uint32_t)k[5])<<16; + b += ((uint32_t)k[6])<<8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8])<<24; + c += ((uint32_t)k[9])<<16; + c += ((uint32_t)k[10])<<8; + c += ((uint32_t)k[11]); + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[11]; + case 11: c+=((uint32_t)k[10])<<8; + case 10: c+=((uint32_t)k[9])<<16; + case 9 : c+=((uint32_t)k[8])<<24; + case 8 : b+=k[7]; + case 7 : b+=((uint32_t)k[6])<<8; + case 6 : b+=((uint32_t)k[5])<<16; + case 5 : b+=((uint32_t)k[4])<<24; + case 4 : a+=k[3]; + case 3 : a+=((uint32_t)k[2])<<8; + case 2 : a+=((uint32_t)k[1])<<16; + case 1 : a+=((uint32_t)k[0])<<24; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + +#ifdef SELF_TEST + +/* used for timings */ +void driver1() +{ + uint8_t buf[256]; + uint32_t i; + uint32_t h=0; + time_t a,z; + + time(&a); + for (i=0; i<256; ++i) buf[i] = 'x'; + for (i=0; i<1; ++i) + { + h = hashlittle(&buf[0],1,h); + } + time(&z); + if (z-a > 0) printf("time %d %.8x\n", z-a, h); +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 60 +#define MAXLEN 70 +void driver2() +{ + uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; + uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; + uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; + uint32_t x[HASHSTATE],y[HASHSTATE]; + uint32_t hlen; + + printf("No more than %d trials should ever be needed \n",MAXPAIR/2); + for (hlen=0; hlen < MAXLEN; ++hlen) + { + z=0; + for (i=0; i>(8-j)); + c[0] = hashlittle(a, hlen, m); + b[i] ^= ((k+1)<>(8-j)); + d[0] = hashlittle(b, hlen, m); + /* check every bit is 1, 0, set, and not set at least once */ + for (l=0; lz) z=k; + if (k==MAXPAIR) + { + printf("Some bit didn't change: "); + printf("%.8x %.8x %.8x %.8x %.8x %.8x ", + e[0],f[0],g[0],h[0],x[0],y[0]); + printf("i %d j %d m %d len %d\n", i, j, m, hlen); + } + if (z==MAXPAIR) goto done; + } + } + } + done: + if (z < MAXPAIR) + { + printf("Mix success %2d bytes %2d initvals ",i,m); + printf("required %d trials\n", z/2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +void driver3() +{ + uint8_t buf[MAXLEN+20], *b; + uint32_t len; + uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; + uint32_t h; + uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; + uint32_t i; + uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; + uint32_t j; + uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; + uint32_t ref,x,y; + uint8_t *p; + + printf("Endianness. These lines should all be the same (for values filled in):\n"); + printf("%.8x %.8x %.8x\n", + hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), + hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), + hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); + p = q; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qq[1]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqq[2]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqqq[3]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + printf("\n"); + + /* check that hashlittle2 and hashlittle produce the same results */ + i=47; j=0; + hashlittle2(q, sizeof(q), &i, &j); + if (hashlittle(q, sizeof(q), 47) != i) + printf("hashlittle2 and hashlittle mismatch\n"); + + /* check that hashword2 and hashword produce the same results */ + len = 0xdeadbeef; + i=47, j=0; + hashword2(&len, 1, &i, &j); + if (hashword(&len, 1, 47) != i) + printf("hashword2 and hashword mismatch %x %x\n", + i, hashword(&len, 1, 47)); + + /* check hashlittle doesn't read before or after the ends of the string */ + for (h=0, b=buf+1; h<8; ++h, ++b) + { + for (i=0; i +#include + +#include "macro.h" + +uint32_t jenkins_hashword(const uint32_t *k, size_t length, uint32_t initval) _pure_; +void jenkins_hashword2(const uint32_t *k, size_t length, uint32_t *pc, uint32_t *pb); + +uint32_t jenkins_hashlittle(const void *key, size_t length, uint32_t initval) _pure_; +void jenkins_hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb); + +uint32_t jenkins_hashbig(const void *key, size_t length, uint32_t initval) _pure_; + +static inline uint64_t hash64(const void *data, size_t length) { + uint32_t a = 0, b = 0; + + jenkins_hashlittle2(data, length, &a, &b); + + return ((uint64_t) a << 32ULL) | (uint64_t) b; +} diff --git a/src/journal/microhttpd-util.c b/src/journal/microhttpd-util.c new file mode 100644 index 0000000..3844f7a --- /dev/null +++ b/src/journal/microhttpd-util.c @@ -0,0 +1,41 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "microhttpd-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" + +void microhttpd_logger(void *arg, const char *fmt, va_list ap) { + _cleanup_free_ char *f = NULL; + + if (asprintf(&f, "microhttpd: %s", fmt) <= 0) { + log_oom(); + return; + } + + DISABLE_WARNING_FORMAT_NONLITERAL; + log_metav(LOG_INFO, NULL, 0, NULL, f, ap); + REENABLE_WARNING; +} diff --git a/src/journal/microhttpd-util.h b/src/journal/microhttpd-util.h new file mode 100644 index 0000000..74d1668 --- /dev/null +++ b/src/journal/microhttpd-util.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include + +#include "macro.h" + +void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0); diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c new file mode 100644 index 0000000..7dbbb5e --- /dev/null +++ b/src/journal/mmap-cache.c @@ -0,0 +1,636 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "hashmap.h" +#include "list.h" +#include "log.h" +#include "util.h" +#include "macro.h" +#include "mmap-cache.h" + +typedef struct Window Window; +typedef struct Context Context; +typedef struct FileDescriptor FileDescriptor; + +struct Window { + MMapCache *cache; + + unsigned keep_always; + bool in_unused; + + int prot; + void *ptr; + uint64_t offset; + size_t size; + + FileDescriptor *fd; + + LIST_FIELDS(Window, by_fd); + LIST_FIELDS(Window, unused); + + LIST_HEAD(Context, contexts); +}; + +struct Context { + MMapCache *cache; + unsigned id; + Window *window; + + LIST_FIELDS(Context, by_window); +}; + +struct FileDescriptor { + MMapCache *cache; + int fd; + LIST_HEAD(Window, windows); +}; + +struct MMapCache { + int n_ref; + unsigned n_windows; + + unsigned n_hit, n_missed; + + + Hashmap *fds; + Hashmap *contexts; + + LIST_HEAD(Window, unused); + Window *last_unused; +}; + +#define WINDOWS_MIN 64 +#define WINDOW_SIZE (8ULL*1024ULL*1024ULL) + +MMapCache* mmap_cache_new(void) { + MMapCache *m; + + m = new0(MMapCache, 1); + if (!m) + return NULL; + + m->n_ref = 1; + return m; +} + +MMapCache* mmap_cache_ref(MMapCache *m) { + assert(m); + assert(m->n_ref > 0); + + m->n_ref ++; + return m; +} + +static void window_unlink(Window *w) { + Context *c; + + assert(w); + + if (w->ptr) + munmap(w->ptr, w->size); + + if (w->fd) + LIST_REMOVE(by_fd, w->fd->windows, w); + + if (w->in_unused) { + if (w->cache->last_unused == w) + w->cache->last_unused = w->unused_prev; + + LIST_REMOVE(unused, w->cache->unused, w); + } + + LIST_FOREACH(by_window, c, w->contexts) { + assert(c->window == w); + c->window = NULL; + } +} + +static void window_free(Window *w) { + assert(w); + + window_unlink(w); + w->cache->n_windows--; + free(w); +} + +_pure_ static bool window_matches(Window *w, int fd, int prot, uint64_t offset, size_t size) { + assert(w); + assert(fd >= 0); + assert(size > 0); + + return + w->fd && + fd == w->fd->fd && + prot == w->prot && + offset >= w->offset && + offset + size <= w->offset + w->size; +} + +static Window *window_add(MMapCache *m) { + Window *w; + + assert(m); + + if (!m->last_unused || m->n_windows <= WINDOWS_MIN) { + + /* Allocate a new window */ + w = new0(Window, 1); + if (!w) + return NULL; + m->n_windows++; + } else { + + /* Reuse an existing one */ + w = m->last_unused; + window_unlink(w); + zero(*w); + } + + w->cache = m; + return w; +} + +static void context_detach_window(Context *c) { + Window *w; + + assert(c); + + if (!c->window) + return; + + w = c->window; + c->window = NULL; + LIST_REMOVE(by_window, w->contexts, c); + + if (!w->contexts && w->keep_always == 0) { + /* Not used anymore? */ + LIST_PREPEND(unused, c->cache->unused, w); + if (!c->cache->last_unused) + c->cache->last_unused = w; + + w->in_unused = true; + } +} + +static void context_attach_window(Context *c, Window *w) { + assert(c); + assert(w); + + if (c->window == w) + return; + + context_detach_window(c); + + if (w->in_unused) { + /* Used again? */ + LIST_REMOVE(unused, c->cache->unused, w); + if (c->cache->last_unused == w) + c->cache->last_unused = w->unused_prev; + + w->in_unused = false; + } + + c->window = w; + LIST_PREPEND(by_window, w->contexts, c); +} + +static Context *context_add(MMapCache *m, unsigned id) { + Context *c; + int r; + + assert(m); + + c = hashmap_get(m->contexts, UINT_TO_PTR(id + 1)); + if (c) + return c; + + r = hashmap_ensure_allocated(&m->contexts, trivial_hash_func, trivial_compare_func); + if (r < 0) + return NULL; + + c = new0(Context, 1); + if (!c) + return NULL; + + c->cache = m; + c->id = id; + + r = hashmap_put(m->contexts, UINT_TO_PTR(id + 1), c); + if (r < 0) { + free(c); + return NULL; + } + + return c; +} + +static void context_free(Context *c) { + assert(c); + + context_detach_window(c); + + if (c->cache) + assert_se(hashmap_remove(c->cache->contexts, UINT_TO_PTR(c->id + 1))); + + free(c); +} + +static void fd_free(FileDescriptor *f) { + assert(f); + + while (f->windows) + window_free(f->windows); + + if (f->cache) + assert_se(hashmap_remove(f->cache->fds, INT_TO_PTR(f->fd + 1))); + + free(f); +} + +static FileDescriptor* fd_add(MMapCache *m, int fd) { + FileDescriptor *f; + int r; + + assert(m); + assert(fd >= 0); + + f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + if (f) + return f; + + r = hashmap_ensure_allocated(&m->fds, trivial_hash_func, trivial_compare_func); + if (r < 0) + return NULL; + + f = new0(FileDescriptor, 1); + if (!f) + return NULL; + + f->cache = m; + f->fd = fd; + + r = hashmap_put(m->fds, UINT_TO_PTR(fd + 1), f); + if (r < 0) { + free(f); + return NULL; + } + + return f; +} + +static void mmap_cache_free(MMapCache *m) { + Context *c; + FileDescriptor *f; + + assert(m); + + while ((c = hashmap_first(m->contexts))) + context_free(c); + + hashmap_free(m->contexts); + + while ((f = hashmap_first(m->fds))) + fd_free(f); + + hashmap_free(m->fds); + + while (m->unused) + window_free(m->unused); + + free(m); +} + +MMapCache* mmap_cache_unref(MMapCache *m) { + assert(m); + assert(m->n_ref > 0); + + m->n_ref --; + if (m->n_ref == 0) + mmap_cache_free(m); + + return NULL; +} + +static int make_room(MMapCache *m) { + assert(m); + + if (!m->last_unused) + return 0; + + window_free(m->last_unused); + return 1; +} + +static int try_context( + MMapCache *m, + int fd, + int prot, + unsigned context, + bool keep_always, + uint64_t offset, + size_t size, + void **ret) { + + Context *c; + + assert(m); + assert(m->n_ref > 0); + assert(fd >= 0); + assert(size > 0); + + c = hashmap_get(m->contexts, UINT_TO_PTR(context+1)); + if (!c) + return 0; + + assert(c->id == context); + + if (!c->window) + return 0; + + if (!window_matches(c->window, fd, prot, offset, size)) { + + /* Drop the reference to the window, since it's unnecessary now */ + context_detach_window(c); + return 0; + } + + c->window->keep_always += keep_always; + + if (ret) + *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); + return 1; +} + +static int find_mmap( + MMapCache *m, + int fd, + int prot, + unsigned context, + bool keep_always, + uint64_t offset, + size_t size, + void **ret) { + + FileDescriptor *f; + Window *w; + Context *c; + + assert(m); + assert(m->n_ref > 0); + assert(fd >= 0); + assert(size > 0); + + f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + if (!f) + return 0; + + assert(f->fd == fd); + + LIST_FOREACH(by_fd, w, f->windows) + if (window_matches(w, fd, prot, offset, size)) + break; + + if (!w) + return 0; + + c = context_add(m, context); + if (!c) + return -ENOMEM; + + context_attach_window(c, w); + w->keep_always += keep_always; + + if (ret) + *ret = (uint8_t*) w->ptr + (offset - w->offset); + return 1; +} + +static int add_mmap( + MMapCache *m, + int fd, + int prot, + unsigned context, + bool keep_always, + uint64_t offset, + size_t size, + struct stat *st, + void **ret) { + + uint64_t woffset, wsize; + Context *c; + FileDescriptor *f; + Window *w; + void *d; + int r; + + assert(m); + assert(m->n_ref > 0); + assert(fd >= 0); + assert(size > 0); + + woffset = offset & ~((uint64_t) page_size() - 1ULL); + wsize = size + (offset - woffset); + wsize = PAGE_ALIGN(wsize); + + if (wsize < WINDOW_SIZE) { + uint64_t delta; + + delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2); + + if (delta > offset) + woffset = 0; + else + woffset -= delta; + + wsize = WINDOW_SIZE; + } + + if (st) { + /* Memory maps that are larger then the files + underneath have undefined behavior. Hence, clamp + things to the file size if we know it */ + + if (woffset >= (uint64_t) st->st_size) + return -EADDRNOTAVAIL; + + if (woffset + wsize > (uint64_t) st->st_size) + wsize = PAGE_ALIGN(st->st_size - woffset); + } + + for (;;) { + d = mmap(NULL, wsize, prot, MAP_SHARED, fd, woffset); + if (d != MAP_FAILED) + break; + if (errno != ENOMEM) + return -errno; + + r = make_room(m); + if (r < 0) + return r; + if (r == 0) + return -ENOMEM; + } + + c = context_add(m, context); + if (!c) + return -ENOMEM; + + f = fd_add(m, fd); + if (!f) + return -ENOMEM; + + w = window_add(m); + if (!w) + return -ENOMEM; + + w->keep_always = keep_always; + w->ptr = d; + w->offset = woffset; + w->prot = prot; + w->size = wsize; + w->fd = f; + + LIST_PREPEND(by_fd, f->windows, w); + + context_detach_window(c); + c->window = w; + LIST_PREPEND(by_window, w->contexts, c); + + if (ret) + *ret = (uint8_t*) w->ptr + (offset - w->offset); + return 1; +} + +int mmap_cache_get( + MMapCache *m, + int fd, + int prot, + unsigned context, + bool keep_always, + uint64_t offset, + size_t size, + struct stat *st, + void **ret) { + + int r; + + assert(m); + assert(m->n_ref > 0); + assert(fd >= 0); + assert(size > 0); + + /* Check whether the current context is the right one already */ + r = try_context(m, fd, prot, context, keep_always, offset, size, ret); + if (r != 0) { + m->n_hit ++; + return r; + } + + /* Search for a matching mmap */ + r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret); + if (r != 0) { + m->n_hit ++; + return r; + } + + m->n_missed++; + + /* Create a new mmap */ + return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret); +} + +int mmap_cache_release( + MMapCache *m, + int fd, + int prot, + unsigned context, + uint64_t offset, + size_t size) { + + FileDescriptor *f; + Window *w; + + assert(m); + assert(m->n_ref > 0); + assert(fd >= 0); + assert(size > 0); + + f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + if (!f) + return -EBADF; + + assert(f->fd == fd); + + LIST_FOREACH(by_fd, w, f->windows) + if (window_matches(w, fd, prot, offset, size)) + break; + + if (!w) + return -ENOENT; + + if (w->keep_always == 0) + return -ENOLCK; + + w->keep_always -= 1; + return 0; +} + +void mmap_cache_close_fd(MMapCache *m, int fd) { + FileDescriptor *f; + + assert(m); + assert(fd >= 0); + + f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + if (!f) + return; + + fd_free(f); +} + +void mmap_cache_close_context(MMapCache *m, unsigned context) { + Context *c; + + assert(m); + + c = hashmap_get(m->contexts, UINT_TO_PTR(context + 1)); + if (!c) + return; + + context_free(c); +} + +unsigned mmap_cache_get_hit(MMapCache *m) { + assert(m); + + return m->n_hit; +} + +unsigned mmap_cache_get_missed(MMapCache *m) { + assert(m); + + return m->n_missed; +} diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h new file mode 100644 index 0000000..647555a --- /dev/null +++ b/src/journal/mmap-cache.h @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +typedef struct MMapCache MMapCache; + +MMapCache* mmap_cache_new(void); +MMapCache* mmap_cache_ref(MMapCache *m); +MMapCache* mmap_cache_unref(MMapCache *m); + +int mmap_cache_get( + MMapCache *m, + int fd, + int prot, + unsigned context, + bool keep_always, + uint64_t offset, + size_t size, + struct stat *st, + void **ret); +int mmap_cache_release( + MMapCache *m, + int fd, + int prot, + unsigned context, + uint64_t offset, + size_t size); +void mmap_cache_close_fd(MMapCache *m, int fd); +void mmap_cache_close_context(MMapCache *m, unsigned context); + +unsigned mmap_cache_get_hit(MMapCache *m); +unsigned mmap_cache_get_missed(MMapCache *m); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c new file mode 100644 index 0000000..3740a9a --- /dev/null +++ b/src/journal/sd-journal.c @@ -0,0 +1,2693 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-journal.h" +#include "journal-def.h" +#include "journal-file.h" +#include "hashmap.h" +#include "list.h" +#include "strv.h" +#include "path-util.h" +#include "lookup3.h" +#include "compress.h" +#include "journal-internal.h" +#include "missing.h" +#include "catalog.h" +#include "replace-var.h" +#include "fileio.h" + +#define JOURNAL_FILES_MAX 1024 + +#define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC) + +#define REPLACE_VAR_MAX 256 + +#define DEFAULT_DATA_THRESHOLD (64*1024) + +static bool journal_pid_changed(sd_journal *j) { + assert(j); + + /* We don't support people creating a journal object and + * keeping it around over a fork(). Let's complain. */ + + return j->original_pid != getpid(); +} + +/* We return an error here only if we didn't manage to + memorize the real error. */ +static int set_put_error(sd_journal *j, int r) { + int k; + + if (r >= 0) + return r; + + k = set_ensure_allocated(&j->errors, trivial_hash_func, trivial_compare_func); + if (k < 0) + return k; + + return set_put(j->errors, INT_TO_PTR(r)); +} + +static void detach_location(sd_journal *j) { + Iterator i; + JournalFile *f; + + assert(j); + + j->current_file = NULL; + j->current_field = 0; + + HASHMAP_FOREACH(f, j->files, i) + f->current_offset = 0; +} + +static void reset_location(sd_journal *j) { + assert(j); + + detach_location(j); + zero(j->current_location); +} + +static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) { + assert(l); + assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK); + assert(f); + assert(o->object.type == OBJECT_ENTRY); + + l->type = type; + l->seqnum = le64toh(o->entry.seqnum); + l->seqnum_id = f->header->seqnum_id; + l->realtime = le64toh(o->entry.realtime); + l->monotonic = le64toh(o->entry.monotonic); + l->boot_id = o->entry.boot_id; + l->xor_hash = le64toh(o->entry.xor_hash); + + l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true; +} + +static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, + direction_t direction, uint64_t offset) { + assert(j); + assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK); + assert(f); + assert(o); + + init_location(&j->current_location, type, f, o); + + j->current_file = f; + j->current_field = 0; + + f->last_direction = direction; + f->current_offset = offset; +} + +static int match_is_valid(const void *data, size_t size) { + const char *b, *p; + + assert(data); + + if (size < 2) + return false; + + if (startswith(data, "__")) + return false; + + b = data; + for (p = b; p < b + size; p++) { + + if (*p == '=') + return p > b; + + if (*p == '_') + continue; + + if (*p >= 'A' && *p <= 'Z') + continue; + + if (*p >= '0' && *p <= '9') + continue; + + return false; + } + + return false; +} + +static bool same_field(const void *_a, size_t s, const void *_b, size_t t) { + const uint8_t *a = _a, *b = _b; + size_t j; + + for (j = 0; j < s && j < t; j++) { + + if (a[j] != b[j]) + return false; + + if (a[j] == '=') + return true; + } + + assert_not_reached("\"=\" not found"); +} + +static Match *match_new(Match *p, MatchType t) { + Match *m; + + m = new0(Match, 1); + if (!m) + return NULL; + + m->type = t; + + if (p) { + m->parent = p; + LIST_PREPEND(matches, p->matches, m); + } + + return m; +} + +static void match_free(Match *m) { + assert(m); + + while (m->matches) + match_free(m->matches); + + if (m->parent) + LIST_REMOVE(matches, m->parent->matches, m); + + free(m->data); + free(m); +} + +static void match_free_if_empty(Match *m) { + if (!m || m->matches) + return; + + match_free(m); +} + +_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) { + Match *l3, *l4, *add_here = NULL, *m; + le64_t le_hash; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(data, -EINVAL); + + if (size == 0) + size = strlen(data); + + assert_return(match_is_valid(data, size), -EINVAL); + + /* level 0: AND term + * level 1: OR terms + * level 2: AND terms + * level 3: OR terms + * level 4: concrete matches */ + + if (!j->level0) { + j->level0 = match_new(NULL, MATCH_AND_TERM); + if (!j->level0) + return -ENOMEM; + } + + if (!j->level1) { + j->level1 = match_new(j->level0, MATCH_OR_TERM); + if (!j->level1) + return -ENOMEM; + } + + if (!j->level2) { + j->level2 = match_new(j->level1, MATCH_AND_TERM); + if (!j->level2) + return -ENOMEM; + } + + assert(j->level0->type == MATCH_AND_TERM); + assert(j->level1->type == MATCH_OR_TERM); + assert(j->level2->type == MATCH_AND_TERM); + + le_hash = htole64(hash64(data, size)); + + LIST_FOREACH(matches, l3, j->level2->matches) { + assert(l3->type == MATCH_OR_TERM); + + LIST_FOREACH(matches, l4, l3->matches) { + assert(l4->type == MATCH_DISCRETE); + + /* Exactly the same match already? Then ignore + * this addition */ + if (l4->le_hash == le_hash && + l4->size == size && + memcmp(l4->data, data, size) == 0) + return 0; + + /* Same field? Then let's add this to this OR term */ + if (same_field(data, size, l4->data, l4->size)) { + add_here = l3; + break; + } + } + + if (add_here) + break; + } + + if (!add_here) { + add_here = match_new(j->level2, MATCH_OR_TERM); + if (!add_here) + goto fail; + } + + m = match_new(add_here, MATCH_DISCRETE); + if (!m) + goto fail; + + m->le_hash = le_hash; + m->size = size; + m->data = memdup(data, size); + if (!m->data) + goto fail; + + detach_location(j); + + return 0; + +fail: + match_free_if_empty(add_here); + match_free_if_empty(j->level2); + match_free_if_empty(j->level1); + match_free_if_empty(j->level0); + + return -ENOMEM; +} + +_public_ int sd_journal_add_conjunction(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + if (!j->level0) + return 0; + + if (!j->level1) + return 0; + + if (!j->level1->matches) + return 0; + + j->level1 = NULL; + j->level2 = NULL; + + return 0; +} + +_public_ int sd_journal_add_disjunction(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + if (!j->level0) + return 0; + + if (!j->level1) + return 0; + + if (!j->level2) + return 0; + + if (!j->level2->matches) + return 0; + + j->level2 = NULL; + return 0; +} + +static char *match_make_string(Match *m) { + char *p, *r; + Match *i; + bool enclose = false; + + if (!m) + return strdup("none"); + + if (m->type == MATCH_DISCRETE) + return strndup(m->data, m->size); + + p = NULL; + LIST_FOREACH(matches, i, m->matches) { + char *t, *k; + + t = match_make_string(i); + if (!t) { + free(p); + return NULL; + } + + if (p) { + k = strjoin(p, m->type == MATCH_OR_TERM ? " OR " : " AND ", t, NULL); + free(p); + free(t); + + if (!k) + return NULL; + + p = k; + + enclose = true; + } else + p = t; + } + + if (enclose) { + r = strjoin("(", p, ")", NULL); + free(p); + return r; + } + + return p; +} + +char *journal_make_match_string(sd_journal *j) { + assert(j); + + return match_make_string(j->level0); +} + +_public_ void sd_journal_flush_matches(sd_journal *j) { + if (!j) + return; + + if (j->level0) + match_free(j->level0); + + j->level0 = j->level1 = j->level2 = NULL; + + detach_location(j); +} + +static int compare_entry_order(JournalFile *af, Object *_ao, + JournalFile *bf, uint64_t bp) { + + uint64_t a, b; + Object *ao, *bo; + int r; + + assert(af); + assert(bf); + assert(_ao); + + /* The mmap cache might invalidate the object from the first + * file if we look at the one from the second file. Hence + * temporarily copy the header of the first one, and look at + * that only. */ + ao = alloca(offsetof(EntryObject, items)); + memcpy(ao, _ao, offsetof(EntryObject, items)); + + r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo); + if (r < 0) + return strcmp(af->path, bf->path); + + /* We operate on two different files here, hence we can access + * two objects at the same time, which we normally can't. + * + * If contents and timestamps match, these entries are + * identical, even if the seqnum does not match */ + + if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) && + ao->entry.monotonic == bo->entry.monotonic && + ao->entry.realtime == bo->entry.realtime && + ao->entry.xor_hash == bo->entry.xor_hash) + return 0; + + if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { + + /* If this is from the same seqnum source, compare + * seqnums */ + a = le64toh(ao->entry.seqnum); + b = le64toh(bo->entry.seqnum); + + if (a < b) + return -1; + if (a > b) + return 1; + + /* Wow! This is weird, different data but the same + * seqnums? Something is borked, but let's make the + * best of it and compare by time. */ + } + + if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { + + /* If the boot id matches, compare monotonic time */ + a = le64toh(ao->entry.monotonic); + b = le64toh(bo->entry.monotonic); + + if (a < b) + return -1; + if (a > b) + return 1; + } + + /* Otherwise, compare UTC time */ + a = le64toh(ao->entry.realtime); + b = le64toh(bo->entry.realtime); + + if (a < b) + return -1; + if (a > b) + return 1; + + /* Finally, compare by contents */ + a = le64toh(ao->entry.xor_hash); + b = le64toh(bo->entry.xor_hash); + + if (a < b) + return -1; + if (a > b) + return 1; + + return 0; +} + +_pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) { + uint64_t a; + + assert(af); + assert(ao); + assert(l); + assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK); + + if (l->monotonic_set && + sd_id128_equal(ao->entry.boot_id, l->boot_id) && + l->realtime_set && + le64toh(ao->entry.realtime) == l->realtime && + l->xor_hash_set && + le64toh(ao->entry.xor_hash) == l->xor_hash) + return 0; + + if (l->seqnum_set && + sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) { + + a = le64toh(ao->entry.seqnum); + + if (a < l->seqnum) + return -1; + if (a > l->seqnum) + return 1; + } + + if (l->monotonic_set && + sd_id128_equal(ao->entry.boot_id, l->boot_id)) { + + a = le64toh(ao->entry.monotonic); + + if (a < l->monotonic) + return -1; + if (a > l->monotonic) + return 1; + } + + if (l->realtime_set) { + + a = le64toh(ao->entry.realtime); + + if (a < l->realtime) + return -1; + if (a > l->realtime) + return 1; + } + + if (l->xor_hash_set) { + a = le64toh(ao->entry.xor_hash); + + if (a < l->xor_hash) + return -1; + if (a > l->xor_hash) + return 1; + } + + return 0; +} + +static int next_for_match( + sd_journal *j, + Match *m, + JournalFile *f, + uint64_t after_offset, + direction_t direction, + Object **ret, + uint64_t *offset) { + + int r; + uint64_t np = 0; + Object *n; + + assert(j); + assert(m); + assert(f); + + if (m->type == MATCH_DISCRETE) { + uint64_t dp; + + r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp); + if (r <= 0) + return r; + + return journal_file_move_to_entry_by_offset_for_data(f, dp, after_offset, direction, ret, offset); + + } else if (m->type == MATCH_OR_TERM) { + Match *i; + + /* Find the earliest match beyond after_offset */ + + LIST_FOREACH(matches, i, m->matches) { + uint64_t cp; + + r = next_for_match(j, i, f, after_offset, direction, NULL, &cp); + if (r < 0) + return r; + else if (r > 0) { + if (np == 0 || (direction == DIRECTION_DOWN ? cp < np : cp > np)) + np = cp; + } + } + + if (np == 0) + return 0; + + } else if (m->type == MATCH_AND_TERM) { + Match *i, *last_moved; + + /* Always jump to the next matching entry and repeat + * this until we find an offset that matches for all + * matches. */ + + if (!m->matches) + return 0; + + r = next_for_match(j, m->matches, f, after_offset, direction, NULL, &np); + if (r <= 0) + return r; + + assert(direction == DIRECTION_DOWN ? np >= after_offset : np <= after_offset); + last_moved = m->matches; + + LIST_LOOP_BUT_ONE(matches, i, m->matches, last_moved) { + uint64_t cp; + + r = next_for_match(j, i, f, np, direction, NULL, &cp); + if (r <= 0) + return r; + + assert(direction == DIRECTION_DOWN ? cp >= np : cp <= np); + if (direction == DIRECTION_DOWN ? cp > np : cp < np) { + np = cp; + last_moved = i; + } + } + } + + assert(np > 0); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n); + if (r < 0) + return r; + + if (ret) + *ret = n; + if (offset) + *offset = np; + + return 1; +} + +static int find_location_for_match( + sd_journal *j, + Match *m, + JournalFile *f, + direction_t direction, + Object **ret, + uint64_t *offset) { + + int r; + + assert(j); + assert(m); + assert(f); + + if (m->type == MATCH_DISCRETE) { + uint64_t dp; + + r = journal_file_find_data_object_with_hash(f, m->data, m->size, le64toh(m->le_hash), NULL, &dp); + if (r <= 0) + return r; + + /* FIXME: missing: find by monotonic */ + + if (j->current_location.type == LOCATION_HEAD) + return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset); + if (j->current_location.type == LOCATION_TAIL) + return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset); + if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) + return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset); + if (j->current_location.monotonic_set) { + r = journal_file_move_to_entry_by_monotonic_for_data(f, dp, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset); + if (r != -ENOENT) + return r; + } + if (j->current_location.realtime_set) + return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset); + + return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset); + + } else if (m->type == MATCH_OR_TERM) { + uint64_t np = 0; + Object *n; + Match *i; + + /* Find the earliest match */ + + LIST_FOREACH(matches, i, m->matches) { + uint64_t cp; + + r = find_location_for_match(j, i, f, direction, NULL, &cp); + if (r < 0) + return r; + else if (r > 0) { + if (np == 0 || (direction == DIRECTION_DOWN ? np > cp : np < cp)) + np = cp; + } + } + + if (np == 0) + return 0; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, np, &n); + if (r < 0) + return r; + + if (ret) + *ret = n; + if (offset) + *offset = np; + + return 1; + + } else { + Match *i; + uint64_t np = 0; + + assert(m->type == MATCH_AND_TERM); + + /* First jump to the last match, and then find the + * next one where all matches match */ + + if (!m->matches) + return 0; + + LIST_FOREACH(matches, i, m->matches) { + uint64_t cp; + + r = find_location_for_match(j, i, f, direction, NULL, &cp); + if (r <= 0) + return r; + + if (np == 0 || (direction == DIRECTION_DOWN ? cp > np : cp < np)) + np = cp; + } + + return next_for_match(j, m, f, np, direction, ret, offset); + } +} + +static int find_location_with_matches( + sd_journal *j, + JournalFile *f, + direction_t direction, + Object **ret, + uint64_t *offset) { + + int r; + + assert(j); + assert(f); + assert(ret); + assert(offset); + + if (!j->level0) { + /* No matches is simple */ + + if (j->current_location.type == LOCATION_HEAD) + return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset); + if (j->current_location.type == LOCATION_TAIL) + return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset); + if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) + return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset); + if (j->current_location.monotonic_set) { + r = journal_file_move_to_entry_by_monotonic(f, j->current_location.boot_id, j->current_location.monotonic, direction, ret, offset); + if (r != -ENOENT) + return r; + } + if (j->current_location.realtime_set) + return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset); + + return journal_file_next_entry(f, NULL, 0, direction, ret, offset); + } else + return find_location_for_match(j, j->level0, f, direction, ret, offset); +} + +static int next_with_matches( + sd_journal *j, + JournalFile *f, + direction_t direction, + Object **ret, + uint64_t *offset) { + + Object *c; + uint64_t cp; + + assert(j); + assert(f); + assert(ret); + assert(offset); + + c = *ret; + cp = *offset; + + /* No matches is easy. We simple advance the file + * pointer by one. */ + if (!j->level0) + return journal_file_next_entry(f, c, cp, direction, ret, offset); + + /* If we have a match then we look for the next matching entry + * with an offset at least one step larger */ + return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset); +} + +static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) { + Object *c; + uint64_t cp; + int r; + + assert(j); + assert(f); + + if (f->last_direction == direction && f->current_offset > 0) { + cp = f->current_offset; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c); + if (r < 0) + return r; + + r = next_with_matches(j, f, direction, &c, &cp); + if (r <= 0) + return r; + } else { + r = find_location_with_matches(j, f, direction, &c, &cp); + if (r <= 0) + return r; + } + + /* OK, we found the spot, now let's advance until an entry + * that is actually different from what we were previously + * looking at. This is necessary to handle entries which exist + * in two (or more) journal files, and which shall all be + * suppressed but one. */ + + for (;;) { + bool found; + + if (j->current_location.type == LOCATION_DISCRETE) { + int k; + + k = compare_with_location(f, c, &j->current_location); + if (direction == DIRECTION_DOWN) + found = k > 0; + else + found = k < 0; + } else + found = true; + + if (found) { + if (ret) + *ret = c; + if (offset) + *offset = cp; + return 1; + } + + r = next_with_matches(j, f, direction, &c, &cp); + if (r <= 0) + return r; + } +} + +static int real_journal_next(sd_journal *j, direction_t direction) { + JournalFile *f, *new_file = NULL; + uint64_t new_offset = 0; + uint64_t p = 0; + Iterator i; + Object *o; + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + HASHMAP_FOREACH(f, j->files, i) { + bool found; + + r = next_beyond_location(j, f, direction, &o, &p); + if (r < 0) { + log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r)); + continue; + } else if (r == 0) + continue; + + if (!new_file) + found = true; + else { + int k; + + k = compare_entry_order(f, o, new_file, new_offset); + + found = direction == DIRECTION_DOWN ? k < 0 : k > 0; + } + + if (found) { + new_file = f; + new_offset = p; + } + } + + if (!new_file) + return 0; + + r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o); + if (r < 0) + return r; + + set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset); + + return 1; +} + +_public_ int sd_journal_next(sd_journal *j) { + return real_journal_next(j, DIRECTION_DOWN); +} + +_public_ int sd_journal_previous(sd_journal *j) { + return real_journal_next(j, DIRECTION_UP); +} + +static int real_journal_next_skip(sd_journal *j, direction_t direction, uint64_t skip) { + int c = 0, r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + if (skip == 0) { + /* If this is not a discrete skip, then at least + * resolve the current location */ + if (j->current_location.type != LOCATION_DISCRETE) + return real_journal_next(j, direction); + + return 0; + } + + do { + r = real_journal_next(j, direction); + if (r < 0) + return r; + + if (r == 0) + return c; + + skip--; + c++; + } while (skip > 0); + + return c; +} + +_public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) { + return real_journal_next_skip(j, DIRECTION_DOWN, skip); +} + +_public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) { + return real_journal_next_skip(j, DIRECTION_UP, skip); +} + +_public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) { + Object *o; + int r; + char bid[33], sid[33]; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(cursor, -EINVAL); + + if (!j->current_file || j->current_file->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o); + if (r < 0) + return r; + + sd_id128_to_string(j->current_file->header->seqnum_id, sid); + sd_id128_to_string(o->entry.boot_id, bid); + + if (asprintf(cursor, + "s=%s;i=%"PRIx64";b=%s;m=%"PRIx64";t=%"PRIx64";x=%"PRIx64, + sid, le64toh(o->entry.seqnum), + bid, le64toh(o->entry.monotonic), + le64toh(o->entry.realtime), + le64toh(o->entry.xor_hash)) < 0) + return -ENOMEM; + + return 0; +} + +_public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { + char *w, *state; + size_t l; + unsigned long long seqnum, monotonic, realtime, xor_hash; + bool + seqnum_id_set = false, + seqnum_set = false, + boot_id_set = false, + monotonic_set = false, + realtime_set = false, + xor_hash_set = false; + sd_id128_t seqnum_id, boot_id; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!isempty(cursor), -EINVAL); + + FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { + char *item; + int k = 0; + + if (l < 2 || w[1] != '=') + return -EINVAL; + + item = strndup(w, l); + if (!item) + return -ENOMEM; + + switch (w[0]) { + + case 's': + seqnum_id_set = true; + k = sd_id128_from_string(item+2, &seqnum_id); + break; + + case 'i': + seqnum_set = true; + if (sscanf(item+2, "%llx", &seqnum) != 1) + k = -EINVAL; + break; + + case 'b': + boot_id_set = true; + k = sd_id128_from_string(item+2, &boot_id); + break; + + case 'm': + monotonic_set = true; + if (sscanf(item+2, "%llx", &monotonic) != 1) + k = -EINVAL; + break; + + case 't': + realtime_set = true; + if (sscanf(item+2, "%llx", &realtime) != 1) + k = -EINVAL; + break; + + case 'x': + xor_hash_set = true; + if (sscanf(item+2, "%llx", &xor_hash) != 1) + k = -EINVAL; + break; + } + + free(item); + + if (k < 0) + return k; + } + + if ((!seqnum_set || !seqnum_id_set) && + (!monotonic_set || !boot_id_set) && + !realtime_set) + return -EINVAL; + + reset_location(j); + + j->current_location.type = LOCATION_SEEK; + + if (realtime_set) { + j->current_location.realtime = (uint64_t) realtime; + j->current_location.realtime_set = true; + } + + if (seqnum_set && seqnum_id_set) { + j->current_location.seqnum = (uint64_t) seqnum; + j->current_location.seqnum_id = seqnum_id; + j->current_location.seqnum_set = true; + } + + if (monotonic_set && boot_id_set) { + j->current_location.monotonic = (uint64_t) monotonic; + j->current_location.boot_id = boot_id; + j->current_location.monotonic_set = true; + } + + if (xor_hash_set) { + j->current_location.xor_hash = (uint64_t) xor_hash; + j->current_location.xor_hash_set = true; + } + + return 0; +} + +_public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { + int r; + char *w, *state; + size_t l; + Object *o; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!isempty(cursor), -EINVAL); + + if (!j->current_file || j->current_file->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(j->current_file, OBJECT_ENTRY, j->current_file->current_offset, &o); + if (r < 0) + return r; + + FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) { + _cleanup_free_ char *item = NULL; + sd_id128_t id; + unsigned long long ll; + int k = 0; + + if (l < 2 || w[1] != '=') + return -EINVAL; + + item = strndup(w, l); + if (!item) + return -ENOMEM; + + switch (w[0]) { + + case 's': + k = sd_id128_from_string(item+2, &id); + if (k < 0) + return k; + if (!sd_id128_equal(id, j->current_file->header->seqnum_id)) + return 0; + break; + + case 'i': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.seqnum)) + return 0; + break; + + case 'b': + k = sd_id128_from_string(item+2, &id); + if (k < 0) + return k; + if (!sd_id128_equal(id, o->entry.boot_id)) + return 0; + break; + + case 'm': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.monotonic)) + return 0; + break; + + case 't': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.realtime)) + return 0; + break; + + case 'x': + if (sscanf(item+2, "%llx", &ll) != 1) + return -EINVAL; + if (ll != le64toh(o->entry.xor_hash)) + return 0; + break; + } + } + + return 1; +} + + +_public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + reset_location(j); + j->current_location.type = LOCATION_SEEK; + j->current_location.boot_id = boot_id; + j->current_location.monotonic = usec; + j->current_location.monotonic_set = true; + + return 0; +} + +_public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + reset_location(j); + j->current_location.type = LOCATION_SEEK; + j->current_location.realtime = usec; + j->current_location.realtime_set = true; + + return 0; +} + +_public_ int sd_journal_seek_head(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + reset_location(j); + j->current_location.type = LOCATION_HEAD; + + return 0; +} + +_public_ int sd_journal_seek_tail(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + reset_location(j); + j->current_location.type = LOCATION_TAIL; + + return 0; +} + +static void check_network(sd_journal *j, int fd) { + struct statfs sfs; + + assert(j); + + if (j->on_network) + return; + + if (fstatfs(fd, &sfs) < 0) + return; + + j->on_network = + F_TYPE_EQUAL(sfs.f_type, CIFS_MAGIC_NUMBER) || + F_TYPE_EQUAL(sfs.f_type, CODA_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, NCP_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, NFS_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, SMB_SUPER_MAGIC); +} + +static bool file_has_type_prefix(const char *prefix, const char *filename) { + const char *full, *tilded, *atted; + + full = strappenda(prefix, ".journal"); + tilded = strappenda(full, "~"); + atted = strappenda(prefix, "@"); + + return streq(filename, full) || + streq(filename, tilded) || + startswith(filename, atted); +} + +static bool file_type_wanted(int flags, const char *filename) { + if (!endswith(filename, ".journal") && !endswith(filename, ".journal~")) + return false; + + /* no flags set → every type is OK */ + if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER))) + return true; + + if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename)) + return true; + + if (flags & SD_JOURNAL_CURRENT_USER) { + char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1]; + + assert_se(snprintf(prefix, sizeof(prefix), "user-%lu", (unsigned long) getuid()) + < (int) sizeof(prefix)); + + if (file_has_type_prefix(prefix, filename)) + return true; + } + + return false; +} + +static int add_any_file(sd_journal *j, const char *path) { + JournalFile *f = NULL; + int r; + + assert(j); + assert(path); + + if (hashmap_get(j->files, path)) + return 0; + + if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) { + log_warning("Too many open journal files, not adding %s.", path); + return set_put_error(j, -ETOOMANYREFS); + } + + r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); + if (r < 0) + return r; + + /* journal_file_dump(f); */ + + r = hashmap_put(j->files, f->path, f); + if (r < 0) { + journal_file_close(f); + return r; + } + + log_debug("File %s added.", f->path); + + check_network(j, f->fd); + + j->current_invalidate_counter ++; + + return 0; +} + +static int add_file(sd_journal *j, const char *prefix, const char *filename) { + _cleanup_free_ char *path = NULL; + int r; + + assert(j); + assert(prefix); + assert(filename); + + if (j->no_new_files || + !file_type_wanted(j->flags, filename)) + return 0; + + path = strjoin(prefix, "/", filename, NULL); + if (!path) + return -ENOMEM; + + r = add_any_file(j, path); + if (r == -ENOENT) + return 0; + return 0; +} + +static int remove_file(sd_journal *j, const char *prefix, const char *filename) { + char *path; + JournalFile *f; + + assert(j); + assert(prefix); + assert(filename); + + path = strjoin(prefix, "/", filename, NULL); + if (!path) + return -ENOMEM; + + f = hashmap_get(j->files, path); + free(path); + if (!f) + return 0; + + hashmap_remove(j->files, f->path); + + log_debug("File %s removed.", f->path); + + if (j->current_file == f) { + j->current_file = NULL; + j->current_field = 0; + } + + if (j->unique_file == f) { + j->unique_file = NULL; + j->unique_offset = 0; + } + + journal_file_close(f); + + j->current_invalidate_counter ++; + + return 0; +} + +static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { + _cleanup_free_ char *path = NULL; + int r; + _cleanup_closedir_ DIR *d = NULL; + sd_id128_t id, mid; + Directory *m; + + assert(j); + assert(prefix); + assert(dirname); + + log_debug("Considering %s/%s.", prefix, dirname); + + if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && + (sd_id128_from_string(dirname, &id) < 0 || + sd_id128_get_machine(&mid) < 0 || + !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) + return 0; + + path = strjoin(prefix, "/", dirname, NULL); + if (!path) + return -ENOMEM; + + d = opendir(path); + if (!d) { + log_debug("Failed to open %s: %m", path); + if (errno == ENOENT) + return 0; + return -errno; + } + + m = hashmap_get(j->directories_by_path, path); + if (!m) { + m = new0(Directory, 1); + if (!m) + return -ENOMEM; + + m->is_root = false; + m->path = path; + + if (hashmap_put(j->directories_by_path, m->path, m) < 0) { + free(m); + return -ENOMEM; + } + + path = NULL; /* avoid freeing in cleanup */ + j->current_invalidate_counter ++; + + log_debug("Directory %s added.", m->path); + + } else if (m->is_root) + return 0; + + if (m->wd <= 0 && j->inotify_fd >= 0) { + + m->wd = inotify_add_watch(j->inotify_fd, m->path, + IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| + IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| + IN_ONLYDIR); + + if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0) + inotify_rm_watch(j->inotify_fd, m->wd); + } + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + log_debug("Failed to read directory %s: %s", + m->path, strerror(errno)); + return r; + } + if (!de) + break; + + if (dirent_is_file_with_suffix(de, ".journal") || + dirent_is_file_with_suffix(de, ".journal~")) { + r = add_file(j, m->path, de->d_name); + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + m->path, de->d_name, strerror(-r)); + r = set_put_error(j, r); + if (r < 0) + return r; + } + } + } + + check_network(j, dirfd(d)); + + return 0; +} + +static int add_root_directory(sd_journal *j, const char *p) { + _cleanup_closedir_ DIR *d = NULL; + Directory *m; + int r; + + assert(j); + assert(p); + + if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) && + !path_startswith(p, "/run")) + return -EINVAL; + + if (j->prefix) + p = strappenda(j->prefix, p); + + d = opendir(p); + if (!d) + return -errno; + + m = hashmap_get(j->directories_by_path, p); + if (!m) { + m = new0(Directory, 1); + if (!m) + return -ENOMEM; + + m->is_root = true; + m->path = strdup(p); + if (!m->path) { + free(m); + return -ENOMEM; + } + + if (hashmap_put(j->directories_by_path, m->path, m) < 0) { + free(m->path); + free(m); + return -ENOMEM; + } + + j->current_invalidate_counter ++; + + log_debug("Root directory %s added.", m->path); + + } else if (!m->is_root) + return 0; + + if (m->wd <= 0 && j->inotify_fd >= 0) { + + m->wd = inotify_add_watch(j->inotify_fd, m->path, + IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| + IN_ONLYDIR); + + if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0) + inotify_rm_watch(j->inotify_fd, m->wd); + } + + if (j->no_new_files) + return 0; + + for (;;) { + struct dirent *de; + sd_id128_t id; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + log_debug("Failed to read directory %s: %s", + m->path, strerror(errno)); + return r; + } + if (!de) + break; + + if (dirent_is_file_with_suffix(de, ".journal") || + dirent_is_file_with_suffix(de, ".journal~")) { + r = add_file(j, m->path, de->d_name); + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + m->path, de->d_name, strerror(-r)); + r = set_put_error(j, r); + if (r < 0) + return r; + } + } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && + sd_id128_from_string(de->d_name, &id) >= 0) { + + r = add_directory(j, m->path, de->d_name); + if (r < 0) + log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r)); + } + } + + check_network(j, dirfd(d)); + + return 0; +} + +static int remove_directory(sd_journal *j, Directory *d) { + assert(j); + + if (d->wd > 0) { + hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd)); + + if (j->inotify_fd >= 0) + inotify_rm_watch(j->inotify_fd, d->wd); + } + + hashmap_remove(j->directories_by_path, d->path); + + if (d->is_root) + log_debug("Root directory %s removed.", d->path); + else + log_debug("Directory %s removed.", d->path); + + free(d->path); + free(d); + + return 0; +} + +static int add_search_paths(sd_journal *j) { + int r; + const char search_paths[] = + "/run/log/journal\0" + "/var/log/journal\0"; + const char *p; + + assert(j); + + /* We ignore most errors here, since the idea is to only open + * what's actually accessible, and ignore the rest. */ + + NULSTR_FOREACH(p, search_paths) { + r = add_root_directory(j, p); + if (r < 0 && r != -ENOENT) { + r = set_put_error(j, r); + if (r < 0) + return r; + } + } + + return 0; +} + +static int add_current_paths(sd_journal *j) { + Iterator i; + JournalFile *f; + + assert(j); + assert(j->no_new_files); + + /* Simply adds all directories for files we have open as + * "root" directories. We don't expect errors here, so we + * treat them as fatal. */ + + HASHMAP_FOREACH(f, j->files, i) { + _cleanup_free_ char *dir; + int r; + + dir = dirname_malloc(f->path); + if (!dir) + return -ENOMEM; + + r = add_root_directory(j, dir); + if (r < 0) { + set_put_error(j, r); + return r; + } + } + + return 0; +} + + +static int allocate_inotify(sd_journal *j) { + assert(j); + + if (j->inotify_fd < 0) { + j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (j->inotify_fd < 0) + return -errno; + } + + if (!j->directories_by_wd) { + j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func); + if (!j->directories_by_wd) + return -ENOMEM; + } + + return 0; +} + +static sd_journal *journal_new(int flags, const char *path) { + sd_journal *j; + + j = new0(sd_journal, 1); + if (!j) + return NULL; + + j->original_pid = getpid(); + j->inotify_fd = -1; + j->flags = flags; + j->data_threshold = DEFAULT_DATA_THRESHOLD; + + if (path) { + j->path = strdup(path); + if (!j->path) + goto fail; + } + + j->files = hashmap_new(string_hash_func, string_compare_func); + j->directories_by_path = hashmap_new(string_hash_func, string_compare_func); + j->mmap = mmap_cache_new(); + if (!j->files || !j->directories_by_path || !j->mmap) + goto fail; + + return j; + +fail: + sd_journal_close(j); + return NULL; +} + +_public_ int sd_journal_open(sd_journal **ret, int flags) { + sd_journal *j; + int r; + + assert_return(ret, -EINVAL); + assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL); + + j = journal_new(flags, NULL); + if (!j) + return -ENOMEM; + + r = add_search_paths(j); + if (r < 0) + goto fail; + + *ret = j; + return 0; + +fail: + sd_journal_close(j); + + return r; +} + +_public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) { + _cleanup_free_ char *root = NULL, *class = NULL; + sd_journal *j; + char *p; + int r; + + assert_return(machine, -EINVAL); + assert_return(ret, -EINVAL); + assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL); + assert_return(filename_is_safe(machine), -EINVAL); + + p = strappenda("/run/systemd/machines/", machine); + r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL); + if (r == -ENOENT) + return -EHOSTDOWN; + if (r < 0) + return r; + if (!root) + return -ENODATA; + + if (!streq_ptr(class, "container")) + return -EIO; + + j = journal_new(flags, NULL); + if (!j) + return -ENOMEM; + + j->prefix = root; + root = NULL; + + r = add_search_paths(j); + if (r < 0) + goto fail; + + *ret = j; + return 0; + +fail: + sd_journal_close(j); + return r; +} + +_public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) { + sd_journal *j; + int r; + + assert_return(ret, -EINVAL); + assert_return(path, -EINVAL); + assert_return(flags == 0, -EINVAL); + + j = journal_new(flags, path); + if (!j) + return -ENOMEM; + + r = add_root_directory(j, path); + if (r < 0) { + set_put_error(j, r); + goto fail; + } + + *ret = j; + return 0; + +fail: + sd_journal_close(j); + + return r; +} + +_public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) { + sd_journal *j; + const char **path; + int r; + + assert_return(ret, -EINVAL); + assert_return(flags == 0, -EINVAL); + + j = journal_new(flags, NULL); + if (!j) + return -ENOMEM; + + STRV_FOREACH(path, paths) { + r = add_any_file(j, *path); + if (r < 0) { + log_error("Failed to open %s: %s", *path, strerror(-r)); + goto fail; + } + } + + j->no_new_files = true; + + *ret = j; + return 0; + +fail: + sd_journal_close(j); + + return r; +} + +_public_ void sd_journal_close(sd_journal *j) { + Directory *d; + JournalFile *f; + + if (!j) + return; + + sd_journal_flush_matches(j); + + while ((f = hashmap_steal_first(j->files))) + journal_file_close(f); + + hashmap_free(j->files); + + while ((d = hashmap_first(j->directories_by_path))) + remove_directory(j, d); + + while ((d = hashmap_first(j->directories_by_wd))) + remove_directory(j, d); + + hashmap_free(j->directories_by_path); + hashmap_free(j->directories_by_wd); + + if (j->inotify_fd >= 0) + close_nointr_nofail(j->inotify_fd); + + if (j->mmap) { + log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap)); + mmap_cache_unref(j->mmap); + } + + free(j->path); + free(j->prefix); + free(j->unique_field); + set_free(j->errors); + free(j); +} + +_public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) { + Object *o; + JournalFile *f; + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(ret, -EINVAL); + + f = j->current_file; + if (!f) + return -EADDRNOTAVAIL; + + if (f->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) + return r; + + *ret = le64toh(o->entry.realtime); + return 0; +} + +_public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) { + Object *o; + JournalFile *f; + int r; + sd_id128_t id; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + f = j->current_file; + if (!f) + return -EADDRNOTAVAIL; + + if (f->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) + return r; + + if (ret_boot_id) + *ret_boot_id = o->entry.boot_id; + else { + r = sd_id128_get_boot(&id); + if (r < 0) + return r; + + if (!sd_id128_equal(id, o->entry.boot_id)) + return -ESTALE; + } + + if (ret) + *ret = le64toh(o->entry.monotonic); + + return 0; +} + +static bool field_is_valid(const char *field) { + const char *p; + + assert(field); + + if (isempty(field)) + return false; + + if (startswith(field, "__")) + return false; + + for (p = field; *p; p++) { + + if (*p == '_') + continue; + + if (*p >= 'A' && *p <= 'Z') + continue; + + if (*p >= '0' && *p <= '9') + continue; + + return false; + } + + return true; +} + +_public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) { + JournalFile *f; + uint64_t i, n; + size_t field_length; + int r; + Object *o; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(field, -EINVAL); + assert_return(data, -EINVAL); + assert_return(size, -EINVAL); + assert_return(field_is_valid(field), -EINVAL); + + f = j->current_file; + if (!f) + return -EADDRNOTAVAIL; + + if (f->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) + return r; + + field_length = strlen(field); + + n = journal_file_entry_n_items(o); + for (i = 0; i < n; i++) { + uint64_t p, l; + le64_t le_hash; + size_t t; + + p = le64toh(o->entry.items[i].object_offset); + le_hash = o->entry.items[i].hash; + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + if (le_hash != o->data.hash) + return -EBADMSG; + + l = le64toh(o->object.size) - offsetof(Object, data.payload); + + if (o->object.flags & OBJECT_COMPRESSED) { + +#ifdef HAVE_XZ + if (uncompress_startswith(o->data.payload, l, + &f->compress_buffer, &f->compress_buffer_size, + field, field_length, '=')) { + + uint64_t rsize; + + if (!uncompress_blob(o->data.payload, l, + &f->compress_buffer, &f->compress_buffer_size, &rsize, + j->data_threshold)) + return -EBADMSG; + + *data = f->compress_buffer; + *size = (size_t) rsize; + + return 0; + } +#else + return -EPROTONOSUPPORT; +#endif + + } else if (l >= field_length+1 && + memcmp(o->data.payload, field, field_length) == 0 && + o->data.payload[field_length] == '=') { + + t = (size_t) l; + + if ((uint64_t) t != l) + return -E2BIG; + + *data = o->data.payload; + *size = t; + + return 0; + } + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) + return r; + } + + return -ENOENT; +} + +static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **data, size_t *size) { + size_t t; + uint64_t l; + + l = le64toh(o->object.size) - offsetof(Object, data.payload); + t = (size_t) l; + + /* We can't read objects larger than 4G on a 32bit machine */ + if ((uint64_t) t != l) + return -E2BIG; + + if (o->object.flags & OBJECT_COMPRESSED) { +#ifdef HAVE_XZ + uint64_t rsize; + + if (!uncompress_blob(o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, &rsize, j->data_threshold)) + return -EBADMSG; + + *data = f->compress_buffer; + *size = (size_t) rsize; +#else + return -EPROTONOSUPPORT; +#endif + } else { + *data = o->data.payload; + *size = t; + } + + return 0; +} + +_public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) { + JournalFile *f; + uint64_t p, n; + le64_t le_hash; + int r; + Object *o; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(data, -EINVAL); + assert_return(size, -EINVAL); + + f = j->current_file; + if (!f) + return -EADDRNOTAVAIL; + + if (f->current_offset <= 0) + return -EADDRNOTAVAIL; + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + if (r < 0) + return r; + + n = journal_file_entry_n_items(o); + if (j->current_field >= n) + return 0; + + p = le64toh(o->entry.items[j->current_field].object_offset); + le_hash = o->entry.items[j->current_field].hash; + r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); + if (r < 0) + return r; + + if (le_hash != o->data.hash) + return -EBADMSG; + + r = return_data(j, f, o, data, size); + if (r < 0) + return r; + + j->current_field ++; + + return 1; +} + +_public_ void sd_journal_restart_data(sd_journal *j) { + if (!j) + return; + + j->current_field = 0; +} + +_public_ int sd_journal_get_fd(sd_journal *j) { + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + if (j->inotify_fd >= 0) + return j->inotify_fd; + + r = allocate_inotify(j); + if (r < 0) + return r; + + /* Iterate through all dirs again, to add them to the + * inotify */ + if (j->no_new_files) + r = add_current_paths(j); + else if (j->path) + r = add_root_directory(j, j->path); + else + r = add_search_paths(j); + if (r < 0) + return r; + + return j->inotify_fd; +} + +_public_ int sd_journal_get_events(sd_journal *j) { + int fd; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + fd = sd_journal_get_fd(j); + if (fd < 0) + return fd; + + return POLLIN; +} + +_public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { + int fd; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(timeout_usec, -EINVAL); + + fd = sd_journal_get_fd(j); + if (fd < 0) + return fd; + + if (!j->on_network) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + /* If we are on the network we need to regularly check for + * changes manually */ + + *timeout_usec = j->last_process_usec + JOURNAL_FILES_RECHECK_USEC; + return 1; +} + +static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + Directory *d; + int r; + + assert(j); + assert(e); + + /* Is this a subdirectory we watch? */ + d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd)); + if (d) { + sd_id128_t id; + + if (!(e->mask & IN_ISDIR) && e->len > 0 && + (endswith(e->name, ".journal") || + endswith(e->name, ".journal~"))) { + + /* Event for a journal file */ + + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { + r = add_file(j, d->path, e->name); + if (r < 0) { + log_debug("Failed to add file %s/%s: %s", + d->path, e->name, strerror(-r)); + set_put_error(j, r); + } + + } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { + + r = remove_file(j, d->path, e->name); + if (r < 0) + log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r)); + } + + } else if (!d->is_root && e->len == 0) { + + /* Event for a subdirectory */ + + if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) { + r = remove_directory(j, d); + if (r < 0) + log_debug("Failed to remove directory %s: %s", d->path, strerror(-r)); + } + + + } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) { + + /* Event for root directory */ + + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { + r = add_directory(j, d->path, e->name); + if (r < 0) + log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r)); + } + } + + return; + } + + if (e->mask & IN_IGNORED) + return; + + log_warning("Unknown inotify event."); +} + +static int determine_change(sd_journal *j) { + bool b; + + assert(j); + + b = j->current_invalidate_counter != j->last_invalidate_counter; + j->last_invalidate_counter = j->current_invalidate_counter; + + return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND; +} + +_public_ int sd_journal_process(sd_journal *j) { + uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event); + bool got_something = false; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + j->last_process_usec = now(CLOCK_MONOTONIC); + + for (;;) { + struct inotify_event *e; + ssize_t l; + + l = read(j->inotify_fd, buffer, sizeof(buffer)); + if (l < 0) { + if (errno == EAGAIN || errno == EINTR) + return got_something ? determine_change(j) : SD_JOURNAL_NOP; + + return -errno; + } + + got_something = true; + + e = (struct inotify_event*) buffer; + while (l > 0) { + size_t step; + + process_inotify_event(j, e); + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) l); + + e = (struct inotify_event*) ((uint8_t*) e + step); + l -= step; + } + } + + return determine_change(j); +} + +_public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { + int r; + uint64_t t; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + if (j->inotify_fd < 0) { + + /* This is the first invocation, hence create the + * inotify watch */ + r = sd_journal_get_fd(j); + if (r < 0) + return r; + + /* The journal might have changed since the context + * object was created and we weren't watching before, + * hence don't wait for anything, and return + * immediately. */ + return determine_change(j); + } + + r = sd_journal_get_timeout(j, &t); + if (r < 0) + return r; + + if (t != (uint64_t) -1) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + t = t > n ? t - n : 0; + + if (timeout_usec == (uint64_t) -1 || timeout_usec > t) + timeout_usec = t; + } + + do { + r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec); + } while (r == -EINTR); + + if (r < 0) + return r; + + return sd_journal_process(j); +} + +_public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) { + Iterator i; + JournalFile *f; + bool first = true; + uint64_t fmin = 0, tmax = 0; + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(from || to, -EINVAL); + assert_return(from != to, -EINVAL); + + HASHMAP_FOREACH(f, j->files, i) { + usec_t fr, t; + + r = journal_file_get_cutoff_realtime_usec(f, &fr, &t); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + if (r == 0) + continue; + + if (first) { + fmin = fr; + tmax = t; + first = false; + } else { + fmin = MIN(fr, fmin); + tmax = MAX(t, tmax); + } + } + + if (from) + *from = fmin; + if (to) + *to = tmax; + + return first ? 0 : 1; +} + +_public_ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t *from, uint64_t *to) { + Iterator i; + JournalFile *f; + bool first = true; + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(from || to, -EINVAL); + assert_return(from != to, -EINVAL); + + HASHMAP_FOREACH(f, j->files, i) { + usec_t fr, t; + + r = journal_file_get_cutoff_monotonic_usec(f, boot_id, &fr, &t); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + if (r == 0) + continue; + + if (first) { + if (from) + *from = fr; + if (to) + *to = t; + first = false; + } else { + if (from) + *from = MIN(fr, *from); + if (to) + *to = MAX(t, *to); + } + } + + return first ? 0 : 1; +} + +void journal_print_header(sd_journal *j) { + Iterator i; + JournalFile *f; + bool newline = false; + + assert(j); + + HASHMAP_FOREACH(f, j->files, i) { + if (newline) + putchar('\n'); + else + newline = true; + + journal_file_print_header(f); + } +} + +_public_ int sd_journal_get_usage(sd_journal *j, uint64_t *bytes) { + Iterator i; + JournalFile *f; + uint64_t sum = 0; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(bytes, -EINVAL); + + HASHMAP_FOREACH(f, j->files, i) { + struct stat st; + + if (fstat(f->fd, &st) < 0) + return -errno; + + sum += (uint64_t) st.st_blocks * 512ULL; + } + + *bytes = sum; + return 0; +} + +_public_ int sd_journal_query_unique(sd_journal *j, const char *field) { + char *f; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(!isempty(field), -EINVAL); + assert_return(field_is_valid(field), -EINVAL); + + f = strdup(field); + if (!f) + return -ENOMEM; + + free(j->unique_field); + j->unique_field = f; + j->unique_file = NULL; + j->unique_offset = 0; + + return 0; +} + +_public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) { + size_t k; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(data, -EINVAL); + assert_return(l, -EINVAL); + assert_return(j->unique_field, -EINVAL); + + k = strlen(j->unique_field); + + if (!j->unique_file) { + j->unique_file = hashmap_first(j->files); + if (!j->unique_file) + return 0; + j->unique_offset = 0; + } + + for (;;) { + JournalFile *of; + Iterator i; + Object *o; + const void *odata; + size_t ol; + bool found; + int r; + + /* Proceed to next data object in the field's linked list */ + if (j->unique_offset == 0) { + r = journal_file_find_field_object(j->unique_file, j->unique_field, k, &o, NULL); + if (r < 0) + return r; + + j->unique_offset = r > 0 ? le64toh(o->field.head_data_offset) : 0; + } else { + r = journal_file_move_to_object(j->unique_file, OBJECT_DATA, j->unique_offset, &o); + if (r < 0) + return r; + + j->unique_offset = le64toh(o->data.next_field_offset); + } + + /* We reached the end of the list? Then start again, with the next file */ + if (j->unique_offset == 0) { + JournalFile *n; + + n = hashmap_next(j->files, j->unique_file->path); + if (!n) + return 0; + + j->unique_file = n; + continue; + } + + /* We do not use the type context here, but 0 instead, + * so that we can look at this data object at the same + * time as one on another file */ + r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o); + if (r < 0) + return r; + + /* Let's do the type check by hand, since we used 0 context above. */ + if (o->object.type != OBJECT_DATA) { + log_error("%s:offset " OFSfmt ": object has type %d, expected %d", + j->unique_file->path, j->unique_offset, + o->object.type, OBJECT_DATA); + return -EBADMSG; + } + + r = journal_file_object_keep(j->unique_file, o, j->unique_offset); + if (r < 0) + return r; + + r = return_data(j, j->unique_file, o, &odata, &ol); + if (r < 0) + return r; + + /* OK, now let's see if we already returned this data + * object by checking if it exists in the earlier + * traversed files. */ + found = false; + HASHMAP_FOREACH(of, j->files, i) { + Object *oo; + uint64_t op; + + if (of == j->unique_file) + break; + + /* Skip this file it didn't have any fields + * indexed */ + if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && + le64toh(of->header->n_fields) <= 0) + continue; + + r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op); + if (r < 0) + return r; + + if (r > 0) + found = true; + } + + if (found) + continue; + + r = journal_file_object_release(j->unique_file, o, j->unique_offset); + if (r < 0) + return r; + + r = return_data(j, j->unique_file, o, data, l); + if (r < 0) + return r; + + return 1; + } +} + +_public_ void sd_journal_restart_unique(sd_journal *j) { + if (!j) + return; + + j->unique_file = NULL; + j->unique_offset = 0; +} + +_public_ int sd_journal_reliable_fd(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + return !j->on_network; +} + +static char *lookup_field(const char *field, void *userdata) { + sd_journal *j = userdata; + const void *data; + size_t size, d; + int r; + + assert(field); + assert(j); + + r = sd_journal_get_data(j, field, &data, &size); + if (r < 0 || + size > REPLACE_VAR_MAX) + return strdup(field); + + d = strlen(field) + 1; + + return strndup((const char*) data + d, size - d); +} + +_public_ int sd_journal_get_catalog(sd_journal *j, char **ret) { + const void *data; + size_t size; + sd_id128_t id; + _cleanup_free_ char *text = NULL, *cid = NULL; + char *t; + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(ret, -EINVAL); + + r = sd_journal_get_data(j, "MESSAGE_ID", &data, &size); + if (r < 0) + return r; + + cid = strndup((const char*) data + 11, size - 11); + if (!cid) + return -ENOMEM; + + r = sd_id128_from_string(cid, &id); + if (r < 0) + return r; + + r = catalog_get(CATALOG_DATABASE, id, &text); + if (r < 0) + return r; + + t = replace_var(text, lookup_field, j); + if (!t) + return -ENOMEM; + + *ret = t; + return 0; +} + +_public_ int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **ret) { + assert_return(ret, -EINVAL); + + return catalog_get(CATALOG_DATABASE, id, ret); +} + +_public_ int sd_journal_set_data_threshold(sd_journal *j, size_t sz) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + + j->data_threshold = sz; + return 0; +} + +_public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(sz, -EINVAL); + + *sz = j->data_threshold; + return 0; +} diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c new file mode 100644 index 0000000..b087a8b --- /dev/null +++ b/src/journal/test-catalog.c @@ -0,0 +1,181 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "macro.h" +#include "sd-messages.h" +#include "catalog.h" + +static const char *catalog_dirs[] = { + CATALOG_DIR, + NULL, +}; + +static const char *no_catalog_dirs[] = { + "/bin/hopefully/with/no/catalog", + NULL +}; + +static void test_import(Hashmap *h, struct strbuf *sb, + const char* contents, ssize_t size, int code) { + int r; + char name[] = "/tmp/test-catalog.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(write(fd, contents, size) == size); + + r = catalog_import_file(h, sb, name); + assert(r == code); + + unlink(name); +} + +static void test_catalog_importing(void) { + Hashmap *h; + struct strbuf *sb; + + assert_se(h = hashmap_new(catalog_hash_func, catalog_compare_func)); + assert_se(sb = strbuf_new()); + +#define BUF "xxx" + test_import(h, sb, BUF, sizeof(BUF), -EINVAL); +#undef BUF + assert(hashmap_isempty(h)); + log_debug("----------------------------------------"); + +#define BUF \ +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededede\n" \ +"Subject: message\n" \ +"\n" \ +"payload\n" + test_import(h, sb, BUF, sizeof(BUF), -EINVAL); +#undef BUF + + log_debug("----------------------------------------"); + +#define BUF \ +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ +"Subject: message\n" \ +"\n" \ +"payload\n" + test_import(h, sb, BUF, sizeof(BUF), 0); +#undef BUF + + assert(hashmap_size(h) == 1); + + log_debug("----------------------------------------"); + + hashmap_free_free(h); + strbuf_cleanup(sb); +} + + +static const char* database = NULL; + +static void test_catalog_update(void) { + static char name[] = "/tmp/test-catalog.XXXXXX"; + int r; + + r = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(r >= 0); + + database = name; + + /* Test what happens if there are no files. */ + r = catalog_update(database, NULL, NULL); + assert(r >= 0); + + /* Test what happens if there are no files in the directory. */ + r = catalog_update(database, NULL, no_catalog_dirs); + assert(r >= 0); + + /* Make sure that we at least have some files loaded or the + catalog_list below will fail. */ + r = catalog_update(database, NULL, catalog_dirs); + assert(r >= 0); +} + +static void test_catalog_file_lang(void) { + _cleanup_free_ char *lang = NULL, *lang2 = NULL, *lang3 = NULL, *lang4 = NULL; + + assert_se(catalog_file_lang("systemd.de_DE.catalog", &lang) == 1); + assert_se(streq(lang, "de_DE")); + + assert_se(catalog_file_lang("systemd..catalog", &lang2) == 0); + assert_se(lang2 == NULL); + + assert_se(catalog_file_lang("systemd.fr.catalog", &lang2) == 1); + assert_se(streq(lang2, "fr")); + + assert_se(catalog_file_lang("systemd.fr.catalog.gz", &lang3) == 0); + assert_se(lang3 == NULL); + + assert_se(catalog_file_lang("systemd.01234567890123456789012345678901.catalog", &lang3) == 0); + assert_se(lang3 == NULL); + + assert_se(catalog_file_lang("systemd.0123456789012345678901234567890.catalog", &lang3) == 1); + assert_se(streq(lang3, "0123456789012345678901234567890")); + + assert_se(catalog_file_lang("/x/y/systemd.catalog", &lang4) == 0); + assert_se(lang4 == NULL); + + assert_se(catalog_file_lang("/x/y/systemd.ru_RU.catalog", &lang4) == 1); + assert_se(streq(lang4, "ru_RU")); +} + +int main(int argc, char *argv[]) { + _cleanup_free_ char *text = NULL; + int r; + + setlocale(LC_ALL, "de_DE.UTF-8"); + + log_set_max_level(LOG_DEBUG); + + test_catalog_file_lang(); + + test_catalog_importing(); + + test_catalog_update(); + + r = catalog_list(stdout, database, true); + assert_se(r >= 0); + + r = catalog_list(stdout, database, false); + assert_se(r >= 0); + + assert_se(catalog_get(database, SD_MESSAGE_COREDUMP, &text) >= 0); + printf(">>>%s<<<\n", text); + + if (database) + unlink(database); + + return 0; +} diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c new file mode 100644 index 0000000..980244e --- /dev/null +++ b/src/journal/test-journal-enum.c @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "log.h" +#include "sd-journal.h" +#include "macro.h" +#include "util.h" +#include "journal-internal.h" + +int main(int argc, char *argv[]) { + unsigned n = 0; + _cleanup_journal_close_ sd_journal*j = NULL; + + log_set_max_level(LOG_DEBUG); + + assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY) >= 0); + + assert_se(sd_journal_add_match(j, "_TRANSPORT=syslog", 0) >= 0); + assert_se(sd_journal_add_match(j, "_UID=0", 0) >= 0); + + SD_JOURNAL_FOREACH_BACKWARDS(j) { + const void *d; + size_t l; + + assert_se(sd_journal_get_data(j, "MESSAGE", &d, &l) >= 0); + + printf("%.*s\n", (int) l, (char*) d); + + n ++; + if (n >= 10) + break; + } + + return 0; +} diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c new file mode 100644 index 0000000..e61e87a --- /dev/null +++ b/src/journal/test-journal-flush.c @@ -0,0 +1,71 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-journal.h" +#include "journal-file.h" +#include "journal-internal.h" + +int main(int argc, char *argv[]) { + + char fn[sizeof("/var/tmp/test-journal-flush-")-1 + DECIMAL_STR_MAX(pid_t) + sizeof(".journal")]; + JournalFile *new_journal = NULL; + sd_journal *j = NULL; + unsigned n = 0; + int r; + + sprintf(fn, "/var/tmp/test-journal-flush-%lu.journal", (unsigned long) getpid()); + + r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal); + assert_se(r >= 0); + + unlink(fn); + + r = sd_journal_open(&j, 0); + assert_se(r >= 0); + + sd_journal_set_data_threshold(j, 0); + + SD_JOURNAL_FOREACH(j) { + Object *o; + JournalFile *f; + + f = j->current_file; + assert(f && f->current_offset > 0); + + r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); + assert(r >= 0); + + r = journal_file_copy_entry(f, new_journal, o, f->current_offset, NULL, NULL, NULL); + assert(r >= 0); + + n++; + if (n > 10000) + break; + } + + sd_journal_close(j); + + journal_file_close(new_journal); + + return 0; +} diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c new file mode 100644 index 0000000..58f260d --- /dev/null +++ b/src/journal/test-journal-init.c @@ -0,0 +1,60 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "log.h" +#include "util.h" + +int main(int argc, char *argv[]) { + sd_journal *j; + int r, i, I = 100; + char t[] = "/tmp/journal-stream-XXXXXX"; + + log_set_max_level(LOG_DEBUG); + + if (argc >= 2) + safe_atoi(argv[1], &I); + log_info("Running %d loops", I); + + assert_se(mkdtemp(t)); + + for (i = 0; i < I; i++) { + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + assert_se(r == 0); + + sd_journal_close(j); + + r = sd_journal_open_directory(&j, t, 0); + assert_se(r == 0); + + sd_journal_close(j); + + j = NULL; + r = sd_journal_open_directory(&j, t, SD_JOURNAL_LOCAL_ONLY); + assert_se(r == -EINVAL); + assert_se(j == NULL); + } + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + + return 0; +} diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c new file mode 100644 index 0000000..5c96044 --- /dev/null +++ b/src/journal/test-journal-interleaving.c @@ -0,0 +1,298 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Marius Vollmer + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include + +#include "journal-file.h" +#include "journal-internal.h" +#include "journal-vacuum.h" +#include "util.h" +#include "log.h" + +/* This program tests skipping around in a multi-file journal. + */ + +static bool arg_keep = false; + +noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) { + log_meta(LOG_CRIT, file, line, func, + "'%s' failed at %s:%u (%s): %s.", + text, file, line, func, strerror(eno)); + abort(); +} + +#define assert_ret(expr) \ + do { \ + int _r_ = (expr); \ + if (_unlikely_(_r_ < 0)) \ + log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +static JournalFile *test_open(const char *name) { + JournalFile *f; + assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f)); + return f; +} + +static void test_close(JournalFile *f) { + journal_file_close (f); +} + +static void append_number(JournalFile *f, int n, uint64_t *seqnum) { + char *p; + dual_timestamp ts; + struct iovec iovec[1]; + + dual_timestamp_get(&ts); + + assert_se(asprintf(&p, "NUMBER=%d", n) >= 0); + iovec[0].iov_base = p; + iovec[0].iov_len = strlen(p); + assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL)); + free(p); +} + +static void test_check_number (sd_journal *j, int n) { + const void *d; + _cleanup_free_ char *k; + size_t l; + int x; + + assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l)); + assert_se(k = strndup(d, l)); + printf("%s\n", k); + + assert_se(safe_atoi(k + 7, &x) >= 0); + assert_se(n == x); +} + +static void test_check_numbers_down (sd_journal *j, int count) { + int i; + + for (i = 1; i <= count; i++) { + int r; + test_check_number(j, i); + assert_ret(r = sd_journal_next(j)); + if (i == count) + assert_se(r == 0); + else + assert_se(r == 1); + } + +} + +static void test_check_numbers_up (sd_journal *j, int count) { + for (int i = count; i >= 1; i--) { + int r; + test_check_number(j, i); + assert_ret(r = sd_journal_previous(j)); + if (i == 1) + assert_se(r == 0); + else + assert_se(r == 1); + } + +} + +static void setup_sequential(void) { + JournalFile *one, *two; + one = test_open("one.journal"); + two = test_open("two.journal"); + append_number(one, 1, NULL); + append_number(one, 2, NULL); + append_number(two, 3, NULL); + append_number(two, 4, NULL); + test_close(one); + test_close(two); +} + +static void setup_interleaved(void) { + JournalFile *one, *two; + one = test_open("one.journal"); + two = test_open("two.journal"); + append_number(one, 1, NULL); + append_number(two, 2, NULL); + append_number(one, 3, NULL); + append_number(two, 4, NULL); + test_close(one); + test_close(two); +} + +static void test_skip(void (*setup)(void)) { + char t[] = "/tmp/journal-skip-XXXXXX"; + sd_journal *j; + int r; + + assert_se(mkdtemp(t)); + assert_se(chdir(t) >= 0); + + setup(); + + /* Seek to head, iterate down. + */ + assert_ret(sd_journal_open_directory(&j, t, 0)); + assert_ret(sd_journal_seek_head(j)); + assert_ret(sd_journal_next(j)); + test_check_numbers_down(j, 4); + sd_journal_close(j); + + /* Seek to tail, iterate up. + */ + assert_ret(sd_journal_open_directory(&j, t, 0)); + assert_ret(sd_journal_seek_tail(j)); + assert_ret(sd_journal_previous(j)); + test_check_numbers_up(j, 4); + sd_journal_close(j); + + /* Seek to tail, skip to head, iterate down. + */ + assert_ret(sd_journal_open_directory(&j, t, 0)); + assert_ret(sd_journal_seek_tail(j)); + assert_ret(r = sd_journal_previous_skip(j, 4)); + assert_se(r == 4); + test_check_numbers_down(j, 4); + sd_journal_close(j); + + /* Seek to head, skip to tail, iterate up. + */ + assert_ret(sd_journal_open_directory(&j, t, 0)); + assert_ret(sd_journal_seek_head(j)); + assert_ret(r = sd_journal_next_skip(j, 4)); + assert_se(r == 4); + test_check_numbers_up(j, 4); + sd_journal_close(j); + + log_info("Done..."); + + if (arg_keep) + log_info("Not removing %s", t); + else { + journal_directory_vacuum(".", 3000000, 0, NULL); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + } + + puts("------------------------------------------------------------"); +} + +static void test_sequence_numbers(void) { + + char t[] = "/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); + + assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644, + true, false, NULL, NULL, NULL, &one) == 0); + + append_number(one, 1, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 1); + append_number(one, 2, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 2); + + assert(one->header->state == STATE_ONLINE); + assert(!sd_id128_equal(one->header->file_id, one->header->machine_id)); + assert(!sd_id128_equal(one->header->file_id, one->header->boot_id)); + assert(sd_id128_equal(one->header->file_id, one->header->seqnum_id)); + + memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); + + assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644, + true, false, NULL, NULL, one, &two) == 0); + + assert(two->header->state == STATE_ONLINE); + assert(!sd_id128_equal(two->header->file_id, one->header->file_id)); + assert(sd_id128_equal(one->header->machine_id, one->header->machine_id)); + assert(sd_id128_equal(one->header->boot_id, one->header->boot_id)); + assert(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id)); + + append_number(two, 3, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 3); + append_number(two, 4, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 4); + + test_close(two); + + append_number(one, 5, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 5); + + append_number(one, 6, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 6); + + test_close(one); + + /* restart server */ + seqnum = 0; + + assert_se(journal_file_open("two.journal", O_RDWR, 0, + true, false, NULL, NULL, NULL, &two) == 0); + + assert(sd_id128_equal(two->header->seqnum_id, seqnum_id)); + + append_number(two, 7, &seqnum); + printf("seqnum=%"PRIu64"\n", seqnum); + assert(seqnum == 5); + + /* So..., here we have the same seqnum in two files with the + * same seqnum_id. */ + + test_close(two); + + log_info("Done..."); + + if (arg_keep) + log_info("Not removing %s", t); + else { + journal_directory_vacuum(".", 3000000, 0, NULL); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + } +} + +int main(int argc, char *argv[]) { + log_set_max_level(LOG_DEBUG); + + /* journal_file_open requires a valid machine id */ + if (access("/etc/machine-id", F_OK) != 0) + return EXIT_TEST_SKIP; + + arg_keep = argc > 1; + + test_skip(setup_sequential); + test_skip(setup_interleaved); + + test_sequence_numbers(); + + return 0; +} diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c new file mode 100644 index 0000000..37bffc1 --- /dev/null +++ b/src/journal/test-journal-match.c @@ -0,0 +1,76 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include + +#include "journal-internal.h" +#include "util.h" +#include "log.h" + +int main(int argc, char *argv[]) { + _cleanup_journal_close_ sd_journal*j; + _cleanup_free_ char *t; + + log_set_max_level(LOG_DEBUG); + + assert_se(sd_journal_open(&j, 0) >= 0); + + assert_se(sd_journal_add_match(j, "foobar", 0) < 0); + assert_se(sd_journal_add_match(j, "foobar=waldo", 0) < 0); + assert_se(sd_journal_add_match(j, "", 0) < 0); + assert_se(sd_journal_add_match(j, "=", 0) < 0); + assert_se(sd_journal_add_match(j, "=xxxxx", 0) < 0); + assert_se(sd_journal_add_match(j, "HALLO=WALDO", 0) >= 0); + assert_se(sd_journal_add_match(j, "QUUX=mmmm", 0) >= 0); + assert_se(sd_journal_add_match(j, "QUUX=xxxxx", 0) >= 0); + assert_se(sd_journal_add_match(j, "HALLO=", 0) >= 0); + assert_se(sd_journal_add_match(j, "QUUX=xxxxx", 0) >= 0); + assert_se(sd_journal_add_match(j, "QUUX=yyyyy", 0) >= 0); + assert_se(sd_journal_add_match(j, "PIFF=paff", 0) >= 0); + + assert_se(sd_journal_add_disjunction(j) >= 0); + + assert_se(sd_journal_add_match(j, "ONE=one", 0) >= 0); + assert_se(sd_journal_add_match(j, "ONE=two", 0) >= 0); + assert_se(sd_journal_add_match(j, "TWO=two", 0) >= 0); + + assert_se(sd_journal_add_conjunction(j) >= 0); + + assert_se(sd_journal_add_match(j, "L4_1=yes", 0) >= 0); + assert_se(sd_journal_add_match(j, "L4_1=ok", 0) >= 0); + assert_se(sd_journal_add_match(j, "L4_2=yes", 0) >= 0); + assert_se(sd_journal_add_match(j, "L4_2=ok", 0) >= 0); + + assert_se(sd_journal_add_disjunction(j) >= 0); + + assert_se(sd_journal_add_match(j, "L3=yes", 0) >= 0); + assert_se(sd_journal_add_match(j, "L3=ok", 0) >= 0); + + assert_se(t = journal_make_match_string(j)); + + printf("resulting match expression is: %s\n", t); + + assert_se(streq(t, "(((L3=ok OR L3=yes) OR ((L4_2=ok OR L4_2=yes) AND (L4_1=ok OR L4_1=yes))) AND ((TWO=two AND (ONE=two OR ONE=one)) OR (PIFF=paff AND (QUUX=yyyyy OR QUUX=xxxxx OR QUUX=mmmm) AND (HALLO= OR HALLO=WALDO))))")); + + return 0; +} diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c new file mode 100644 index 0000000..3e986ed --- /dev/null +++ b/src/journal/test-journal-send.c @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" + +int main(int argc, char *argv[]) { + char huge[4096*1024]; + + log_set_max_level(LOG_DEBUG); + + sd_journal_print(LOG_INFO, "piepapo"); + + sd_journal_send("MESSAGE=foobar", + "VALUE=%i", 7, + NULL); + + errno = ENOENT; + sd_journal_perror("Foobar"); + + sd_journal_perror(""); + + memset(huge, 'x', sizeof(huge)); + memcpy(huge, "HUGE=", 5); + char_array_0(huge); + + sd_journal_send("MESSAGE=Huge field attached", + huge, + NULL); + + sd_journal_send("MESSAGE=uiui", + "VALUE=A", + "VALUE=B", + "VALUE=C", + "SINGLETON=1", + "OTHERVALUE=X", + "OTHERVALUE=Y", + "WITH_BINARY=this is a binary value \a", + NULL); + + syslog(LOG_NOTICE, "Hello World!"); + + sd_journal_print(LOG_NOTICE, "Hello World"); + + sd_journal_send("MESSAGE=Hello World!", + "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555", + "PRIORITY=5", + "HOME=%s", getenv("HOME"), + "TERM=%s", getenv("TERM"), + "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE), + "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN), + NULL); + + sleep(10); + + return 0; +} diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c new file mode 100644 index 0000000..8e1d08d --- /dev/null +++ b/src/journal/test-journal-stream.c @@ -0,0 +1,185 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include + +#include "journal-file.h" +#include "journal-internal.h" +#include "util.h" +#include "log.h" + +#define N_ENTRIES 200 + +static void verify_contents(sd_journal *j, unsigned skip) { + unsigned i; + + assert(j); + + i = 0; + SD_JOURNAL_FOREACH(j) { + const void *d; + char *k, *c; + size_t l; + unsigned u; + + assert_se(sd_journal_get_cursor(j, &k) >= 0); + printf("cursor: %s\n", k); + free(k); + + assert_se(sd_journal_get_data(j, "MAGIC", &d, &l) >= 0); + printf("\t%.*s\n", (int) l, (const char*) d); + + assert_se(sd_journal_get_data(j, "NUMBER", &d, &l) >= 0); + assert_se(k = strndup(d, l)); + printf("\t%s\n", k); + + if (skip > 0) { + assert_se(safe_atou(k + 7, &u) >= 0); + assert_se(i == u); + i += skip; + } + + free(k); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + free(c); + } + + if (skip > 0) + assert_se(i == N_ENTRIES); +} + +int main(int argc, char *argv[]) { + JournalFile *one, *two, *three; + char t[] = "/tmp/journal-stream-XXXXXX"; + unsigned i; + _cleanup_journal_close_ sd_journal *j = NULL; + char *z; + const void *data; + size_t l; + + /* journal_file_open requires a valid machine id */ + if (access("/etc/machine-id", F_OK) != 0) + return EXIT_TEST_SKIP; + + log_set_max_level(LOG_DEBUG); + + assert_se(mkdtemp(t)); + assert_se(chdir(t) >= 0); + + assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0); + assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0); + assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0); + + for (i = 0; i < N_ENTRIES; i++) { + char *p, *q; + dual_timestamp ts; + struct iovec iovec[2]; + + dual_timestamp_get(&ts); + + assert_se(asprintf(&p, "NUMBER=%u", i) >= 0); + iovec[0].iov_base = p; + iovec[0].iov_len = strlen(p); + + assert_se(asprintf(&q, "MAGIC=%s", i % 5 == 0 ? "quux" : "waldo") >= 0); + + iovec[1].iov_base = q; + iovec[1].iov_len = strlen(q); + + if (i % 10 == 0) + assert_se(journal_file_append_entry(three, &ts, iovec, 2, NULL, NULL, NULL) == 0); + else { + if (i % 3 == 0) + assert_se(journal_file_append_entry(two, &ts, iovec, 2, NULL, NULL, NULL) == 0); + + assert_se(journal_file_append_entry(one, &ts, iovec, 2, NULL, NULL, NULL) == 0); + } + + free(p); + free(q); + } + + journal_file_close(one); + journal_file_close(two); + journal_file_close(three); + + assert_se(sd_journal_open_directory(&j, t, 0) >= 0); + + assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0); + SD_JOURNAL_FOREACH_BACKWARDS(j) { + _cleanup_free_ char *c; + + assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0); + printf("\t%.*s\n", (int) l, (const char*) data); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + } + + SD_JOURNAL_FOREACH(j) { + _cleanup_free_ char *c; + + assert_se(sd_journal_get_data(j, "NUMBER", &data, &l) >= 0); + printf("\t%.*s\n", (int) l, (const char*) data); + + assert_se(sd_journal_get_cursor(j, &c) >= 0); + assert_se(sd_journal_test_cursor(j, c) > 0); + } + + sd_journal_flush_matches(j); + + verify_contents(j, 1); + + printf("NEXT TEST\n"); + assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0); + + assert_se(z = journal_make_match_string(j)); + printf("resulting match expression is: %s\n", z); + free(z); + + verify_contents(j, 5); + + printf("NEXT TEST\n"); + sd_journal_flush_matches(j); + assert_se(sd_journal_add_match(j, "MAGIC=waldo", 0) >= 0); + assert_se(sd_journal_add_match(j, "NUMBER=10", 0) >= 0); + assert_se(sd_journal_add_match(j, "NUMBER=11", 0) >= 0); + assert_se(sd_journal_add_match(j, "NUMBER=12", 0) >= 0); + + assert_se(z = journal_make_match_string(j)); + printf("resulting match expression is: %s\n", z); + free(z); + + verify_contents(j, 0); + + assert_se(sd_journal_query_unique(j, "NUMBER") >= 0); + SD_JOURNAL_FOREACH_UNIQUE(j, data, l) + printf("%.*s\n", (int) l, (const char*) data); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + + return 0; +} diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c new file mode 100644 index 0000000..c4d4071 --- /dev/null +++ b/src/journal/test-journal-syslog.c @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "journald-syslog.h" +#include "macro.h" + +static void test_syslog_parse_identifier(const char* str, + const char *ident, const char*pid, int ret) { + const char *buf = str; + _cleanup_free_ char *ident2 = NULL, *pid2 = NULL; + int ret2; + + ret2 = syslog_parse_identifier(&buf, &ident2, &pid2); + + assert(ret == ret2); + assert(ident == ident2 || streq_ptr(ident, ident2)); + assert(pid == pid2 || streq_ptr(pid, pid2)); +} + +int main(void) { + test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", 11); + test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, 6); + test_syslog_parse_identifier("pidu xxx", NULL, NULL, 0); + + return 0; +} diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c new file mode 100644 index 0000000..0540074 --- /dev/null +++ b/src/journal/test-journal-verify.c @@ -0,0 +1,151 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "journal-file.h" +#include "journal-verify.h" +#include "journal-authenticate.h" + +#define N_ENTRIES 6000 +#define RANDOM_RANGE 77 + +static void bit_toggle(const char *fn, uint64_t p) { + uint8_t b; + ssize_t r; + int fd; + + fd = open(fn, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + + r = pread(fd, &b, 1, p/8); + assert(r == 1); + + b ^= 1 << (p % 8); + + r = pwrite(fd, &b, 1, p/8); + assert(r == 1); + + close_nointr_nofail(fd); +} + +static int raw_verify(const char *fn, const char *verification_key) { + JournalFile *f; + int r; + + r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f); + if (r < 0) + return r; + + r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false); + journal_file_close(f); + + return r; +} + +int main(int argc, char *argv[]) { + char t[] = "/tmp/journal-XXXXXX"; + unsigned n; + JournalFile *f; + const char *verification_key = argv[1]; + usec_t from = 0, to = 0, total = 0; + char a[FORMAT_TIMESTAMP_MAX]; + char b[FORMAT_TIMESTAMP_MAX]; + char c[FORMAT_TIMESPAN_MAX]; + struct stat st; + uint64_t p; + + /* journal_file_open requires a valid machine id */ + if (access("/etc/machine-id", F_OK) != 0) + return EXIT_TEST_SKIP; + + log_set_max_level(LOG_DEBUG); + + assert_se(mkdtemp(t)); + assert_se(chdir(t) >= 0); + + log_info("Generating..."); + + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + + for (n = 0; n < N_ENTRIES; n++) { + struct iovec iovec; + struct dual_timestamp ts; + char *test; + + dual_timestamp_get(&ts); + + assert_se(asprintf(&test, "RANDOM=%lu", random() % RANDOM_RANGE)); + + iovec.iov_base = (void*) test; + iovec.iov_len = strlen(test); + + assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); + + free(test); + } + + journal_file_close(f); + + log_info("Verifying..."); + + assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + /* journal_file_print_header(f); */ + journal_file_dump(f); + + assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0); + + if (verification_key && JOURNAL_HEADER_SEALED(f->header)) { + log_info("=> Validated from %s to %s, %s missing", + format_timestamp(a, sizeof(a), from), + format_timestamp(b, sizeof(b), to), + format_timespan(c, sizeof(c), total > to ? total - to : 0, 0)); + } + + journal_file_close(f); + + if (verification_key) { + log_info("Toggling bits..."); + + assert_se(stat("test.journal", &st) >= 0); + + for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) { + bit_toggle("test.journal", p); + + log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8); + + if (raw_verify("test.journal", verification_key) >= 0) + log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_HIGHLIGHT_OFF, p / 8, p % 8); + + bit_toggle("test.journal", p); + } + } + + log_info("Exiting..."); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + + return 0; +} diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c new file mode 100644 index 0000000..85b4cf7 --- /dev/null +++ b/src/journal/test-journal.c @@ -0,0 +1,190 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include + +#include "log.h" +#include "journal-file.h" +#include "journal-authenticate.h" +#include "journal-vacuum.h" + +static bool arg_keep = false; + +static void test_non_empty(void) { + dual_timestamp ts; + JournalFile *f; + struct iovec iovec; + static const char test[] = "TEST1=1", test2[] = "TEST2=2"; + Object *o; + uint64_t p; + char t[] = "/tmp/journal-XXXXXX"; + + log_set_max_level(LOG_DEBUG); + + assert_se(mkdtemp(t)); + assert_se(chdir(t) >= 0); + + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0); + + dual_timestamp_get(&ts); + + iovec.iov_base = (void*) test; + iovec.iov_len = strlen(test); + assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); + + iovec.iov_base = (void*) test2; + iovec.iov_len = strlen(test2); + assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); + + iovec.iov_base = (void*) test; + iovec.iov_len = strlen(test); + assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); + +#ifdef HAVE_GCRYPT + journal_file_append_tag(f); +#endif + journal_file_dump(f); + + assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 2); + + assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 3); + + assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 0); + + assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_skip_entry(f, o, p, 2, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 3); + + assert(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_find_data_object(f, test, strlen(test), NULL, &p) == 1); + assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 3); + + assert(journal_file_find_data_object(f, test2, strlen(test2), NULL, &p) == 1); + assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 2); + + assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 2); + + assert(journal_file_find_data_object(f, "quux", 4, NULL, &p) == 0); + + assert(journal_file_move_to_entry_by_seqnum(f, 1, DIRECTION_DOWN, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 1); + + assert(journal_file_move_to_entry_by_seqnum(f, 3, DIRECTION_DOWN, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 3); + + assert(journal_file_move_to_entry_by_seqnum(f, 2, DIRECTION_DOWN, &o, NULL) == 1); + assert(le64toh(o->entry.seqnum) == 2); + + assert(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0); + + journal_file_rotate(&f, true, true); + journal_file_rotate(&f, true, true); + + journal_file_close(f); + + log_info("Done..."); + + if (arg_keep) + log_info("Not removing %s", t); + else { + journal_directory_vacuum(".", 3000000, 0, NULL); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + } + + puts("------------------------------------------------------------"); +} + +static void test_empty(void) { + JournalFile *f1, *f2, *f3, *f4; + char t[] = "/tmp/journal-XXXXXX"; + + log_set_max_level(LOG_DEBUG); + + assert_se(mkdtemp(t)); + assert_se(chdir(t) >= 0); + + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0); + + assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0); + + assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0); + + assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0); + + journal_file_print_header(f1); + puts(""); + journal_file_print_header(f2); + puts(""); + journal_file_print_header(f3); + puts(""); + journal_file_print_header(f4); + puts(""); + + log_info("Done..."); + + if (arg_keep) + log_info("Not removing %s", t); + else { + journal_directory_vacuum(".", 3000000, 0, NULL); + + assert_se(rm_rf_dangerous(t, false, true, false) >= 0); + } + + journal_file_close(f1); + journal_file_close(f2); + journal_file_close(f3); + journal_file_close(f4); +} + +int main(int argc, char *argv[]) { + arg_keep = argc > 1; + + /* journal_file_open requires a valid machine id */ + if (access("/etc/machine-id", F_OK) != 0) + return EXIT_TEST_SKIP; + + test_non_empty(); + test_empty(); + + return 0; +} diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c new file mode 100644 index 0000000..7d03bfe --- /dev/null +++ b/src/journal/test-mmap-cache.c @@ -0,0 +1,80 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" +#include "mmap-cache.h" + +int main(int argc, char *argv[]) { + int x, y, z, r; + char px[] = "/tmp/testmmapXXXXXXX", py[] = "/tmp/testmmapYXXXXXX", pz[] = "/tmp/testmmapZXXXXXX"; + MMapCache *m; + void *p, *q; + + assert_se(m = mmap_cache_new()); + + x = mkostemp_safe(px, O_RDWR|O_CLOEXEC); + assert(x >= 0); + unlink(px); + + y = mkostemp_safe(py, O_RDWR|O_CLOEXEC); + assert(y >= 0); + unlink(py); + + z = mkostemp_safe(pz, O_RDWR|O_CLOEXEC); + assert(z >= 0); + unlink(pz); + + r = mmap_cache_get(m, x, PROT_READ, 0, false, 1, 2, NULL, &p); + assert(r >= 0); + + r = mmap_cache_get(m, x, PROT_READ, 0, false, 2, 2, NULL, &q); + assert(r >= 0); + + assert((uint8_t*) p + 1 == (uint8_t*) q); + + r = mmap_cache_get(m, x, PROT_READ, 1, false, 3, 2, NULL, &q); + assert(r >= 0); + + assert((uint8_t*) p + 2 == (uint8_t*) q); + + r = mmap_cache_get(m, x, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p); + assert(r >= 0); + + r = mmap_cache_get(m, x, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q); + assert(r >= 0); + + assert((uint8_t*) p + 1 == (uint8_t*) q); + + mmap_cache_unref(m); + + close_nointr_nofail(x); + close_nointr_nofail(y); + close_nointr_nofail(z); + + return 0; +} diff --git a/src/kbd-model-map b/src/kbd-model-map deleted file mode 100644 index a895880..0000000 --- a/src/kbd-model-map +++ /dev/null @@ -1,72 +0,0 @@ -# Generated from system-config-keyboard's model list -# consolelayout xlayout xmodel xvariant xoptions -sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp -nl nl pc105 - terminate:ctrl_alt_bksp -mk-utf mkd,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -trq tr pc105 - terminate:ctrl_alt_bksp -guj in,us pc105 guj terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -uk gb pc105 - terminate:ctrl_alt_bksp -is-latin1 is pc105 - terminate:ctrl_alt_bksp -de de pc105 - terminate:ctrl_alt_bksp -gur gur,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -la-latin1 latam pc105 - terminate:ctrl_alt_bksp -us us pc105+inet - terminate:ctrl_alt_bksp -ko kr pc105 - terminate:ctrl_alt_bksp -ro-std ro pc105 std terminate:ctrl_alt_bksp -de-latin1 de pc105 - terminate:ctrl_alt_bksp -tml-inscript in,us pc105 tam terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -slovene si pc105 - terminate:ctrl_alt_bksp -hu101 hu pc105 qwerty terminate:ctrl_alt_bksp -jp106 jp jp106 - terminate:ctrl_alt_bksp -croat hr pc105 - terminate:ctrl_alt_bksp -ben-probhat in,us pc105 ben_probhat terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -fi-latin1 fi pc105 - terminate:ctrl_alt_bksp -it2 it pc105 - terminate:ctrl_alt_bksp -hu hu pc105 - terminate:ctrl_alt_bksp -sr-latin rs pc105 latin terminate:ctrl_alt_bksp -fi fi pc105 - terminate:ctrl_alt_bksp -fr_CH ch pc105 fr terminate:ctrl_alt_bksp -dk-latin1 dk pc105 - terminate:ctrl_alt_bksp -fr fr pc105 - terminate:ctrl_alt_bksp -it it pc105 - terminate:ctrl_alt_bksp -tml-uni in,us pc105 tam_TAB terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -fr-latin1 fr pc105 - terminate:ctrl_alt_bksp -sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp -be-latin1 be pc105 - terminate:ctrl_alt_bksp -dk dk pc105 - terminate:ctrl_alt_bksp -fr-pc fr pc105 - terminate:ctrl_alt_bksp -bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -it-ibm it pc105 - terminate:ctrl_alt_bksp -cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -ar-digits ara,us pc105 digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -br-abnt2 br abnt2 - terminate:ctrl_alt_bksp -ro ro pc105 - terminate:ctrl_alt_bksp -us-acentos us pc105 intl terminate:ctrl_alt_bksp -pt-latin1 pt pc105 - terminate:ctrl_alt_bksp -ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp -tj tj pc105 - terminate:ctrl_alt_bksp -ar-qwerty ara,us pc105 qwerty terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -ar-azerty-digits ara,us pc105 azerty_digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -ben in,us pc105 ben terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp -no no pc105 - terminate:ctrl_alt_bksp -bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -dvorak us pc105 dvorak terminate:ctrl_alt_bksp -ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp -pl2 pl pc105 - terminate:ctrl_alt_bksp -es es pc105 - terminate:ctrl_alt_bksp -ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp -ie ie pc105 - terminate:ctrl_alt_bksp -ar-azerty ara,us pc105 azerty terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -ar-qwerty-digits ara,us pc105 qwerty_digits terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -et ee pc105 - terminate:ctrl_alt_bksp -sk-qwerty sk pc105 - terminate:ctrl_alt_bksp,qwerty -dev dev,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll -fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp -fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp -cf ca(fr) pc105 - terminate:ctrl_alt_bksp -sv-latin1 se pc105 - terminate:ctrl_alt_bksp -sr-cy rs pc105 - terminate:ctrl_alt_bksp -gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install new file mode 100644 index 0000000..68c24be --- /dev/null +++ b/src/kernel-install/50-depmod.install @@ -0,0 +1,8 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +[[ $1 == "add" ]] || exit 0 +[[ $2 ]] || exit 1 + +exec depmod -a "$2" diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install new file mode 100644 index 0000000..a6a8abc --- /dev/null +++ b/src/kernel-install/90-loaderentry.install @@ -0,0 +1,87 @@ +#!/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" +BOOT_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +if [[ -f /etc/machine-id ]]; then + read MACHINE_ID < /etc/machine-id +fi + +if ! [[ $MACHINE_ID ]]; then + exit 1 +fi + +BOOT_DIR="/$MACHINE_ID/$KERNEL_VERSION" +LOADER_ENTRY="/boot/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" + +if [[ $COMMAND == remove ]]; then + exec rm -f "$LOADER_ENTRY" +fi + +if ! [[ $COMMAND == add ]]; then + exit 1 +fi + +if ! [[ $KERNEL_IMAGE ]]; then + exit 1 +fi + +if [[ -f /etc/os-release ]]; then + . /etc/os-release +fi + +if ! [[ $PRETTY_NAME ]]; then + PRETTY_NAME="Linux $KERNEL_VERSION" +fi + +declare -a BOOT_OPTIONS + +if [[ -f /etc/kernel/cmdline ]]; then + readarray -t BOOT_OPTIONS < /etc/kernel/cmdline +fi + +if ! [[ ${BOOT_OPTIONS[*]} ]]; then + readarray -t line < /proc/cmdline + for i in ${line[*]}; do + if [[ "${i#initrd=*}" == "$i" ]]; then + BOOT_OPTIONS[${#BOOT_OPTIONS[@]}]="$i" + fi + done +fi + +if ! [[ ${BOOT_OPTIONS[*]} ]]; then + echo "Could not determine the kernel command line parameters." >&2 + echo "Please specify the kernel command line in /etc/kernel/cmdline!" >&2 + exit 1 +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 + exit 1 +} + +mkdir -p "${LOADER_ENTRY%/*}" || { + echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2 + exit 1 +} + +{ + echo "title $PRETTY_NAME" + echo "version $KERNEL_VERSION" + echo "machine-id $MACHINE_ID" + echo "options ${BOOT_OPTIONS[*]}" + echo "linux $BOOT_DIR/linux" + [[ -f $BOOT_DIR_ABS/initrd ]] && \ + echo "initrd $BOOT_DIR/initrd" + : +} > "$LOADER_ENTRY" || { + echo "Could not create loader entry '$LOADER_ENTRY'." >&2 + exit 1 +} +exit 0 diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install new file mode 100644 index 0000000..3ae1d77 --- /dev/null +++ b/src/kernel-install/kernel-install @@ -0,0 +1,136 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +# +# This file is part of systemd. +# +# Copyright 2013 Harald Hoyer +# +# 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 . + +usage() +{ + echo "Usage:" + echo " $0 add KERNEL-VERSION KERNEL-IMAGE" + echo " $0 remove KERNEL-VERSION" +} + +dropindirs_sort() +{ + local suffix=$1; shift + local -a files + local f d i + + readarray -t files < <( + for d in "$@"; do + for i in "$d/"*"$suffix"; do + if [[ -e "$i" ]]; then + echo "${i##*/}" + fi + done + done | sort -Vu + ) + + for f in "${files[@]}"; do + for d in "$@"; do + if [[ -e "$d/$f" ]]; then + echo "$d/$f" + continue 2 + fi + done + done +} + +export LC_COLLATE=C + +for i in "$@"; do + if [ "$i" == "--help" -o "$i" == "-h" ]; then + usage + exit 0 + fi +done + +if [[ "${0##*/}" == 'installkernel' ]]; then + COMMAND='add' +else + COMMAND="$1" + shift +fi + +KERNEL_VERSION="$1" +KERNEL_IMAGE="$2" + +if [[ -f /etc/machine-id ]]; then + read MACHINE_ID < /etc/machine-id +fi + +if ! [[ $MACHINE_ID ]]; then + echo "Could not determine your machine ID from /etc/machine-id." >&2 + echo "Please run 'systemd-machine-id-setup' as root. See man:machine-id(5)" >&2 + exit 1 +fi + +if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then + echo "Not enough arguments" >&2 + exit 1 +fi + +BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" +ret=0 + +readarray -t PLUGINS < <( + dropindirs_sort ".install" \ + "/etc/kernel/install.d" \ + "/usr/lib/kernel/install.d" +) + +case $COMMAND in + add) + if [[ ! "$KERNEL_IMAGE" ]]; then + echo "Command 'add' requires an argument" >&2 + exit 1 + fi + + mkdir -p "$BOOT_DIR_ABS" || { + echo "Could not create boot directory '$BOOT_DIR_ABS'." >&2 + exit 1 + } + + for f in "${PLUGINS[@]}"; do + if [[ -x $f ]]; then + "$f" add "$KERNEL_VERSION" "$BOOT_DIR_ABS" "$KERNEL_IMAGE" + ((ret+=$?)) + fi + done + ;; + + remove) + for f in "${PLUGINS[@]}"; do + if [[ -x $f ]]; then + "$f" remove "$KERNEL_VERSION" "$BOOT_DIR_ABS" + ((ret+=$?)) + fi + done + + rm -rf "$BOOT_DIR_ABS" + ((ret+=$?)) + ;; + + *) + echo "Unknown command '$COMMAND'" >&2 + exit 1 + ;; +esac + +exit $ret diff --git a/src/kmod-setup.c b/src/kmod-setup.c deleted file mode 100644 index 7bd7dcb..0000000 --- a/src/kmod-setup.c +++ /dev/null @@ -1,82 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "macro.h" -#include "execute.h" - -#include "kmod-setup.h" - -static const char * const kmod_table[] = { - "autofs4", "/sys/class/misc/autofs", - "ipv6", "/sys/module/ipv6", - "unix", "/proc/net/unix" -}; - -int kmod_setup(void) { - unsigned i, n = 0; - const char * cmdline[3 + ELEMENTSOF(kmod_table) + 1]; - ExecCommand command; - ExecContext context; - pid_t pid; - int r; - - for (i = 0; i < ELEMENTSOF(kmod_table); i += 2) { - - if (access(kmod_table[i+1], F_OK) >= 0) - continue; - - log_debug("Your kernel apparently lacks built-in %s support. Might be a good idea to compile it in. " - "We'll now try to work around this by calling '/sbin/modprobe %s'...", - kmod_table[i], kmod_table[i]); - - cmdline[3 + n++] = kmod_table[i]; - } - - if (n <= 0) - return 0; - - cmdline[0] = "/sbin/modprobe"; - cmdline[1] = "-qab"; - cmdline[2] = "--"; - cmdline[3 + n] = NULL; - - zero(command); - zero(context); - - command.path = (char*) cmdline[0]; - command.argv = (char**) cmdline; - - exec_context_init(&context); - r = exec_spawn(&command, NULL, &context, NULL, 0, NULL, false, false, false, false, NULL, NULL, &pid); - exec_context_done(&context); - - if (r < 0) { - log_error("Failed to spawn %s: %s", cmdline[0], strerror(-r)); - return r; - } - - return wait_for_terminate_and_warn(cmdline[0], pid); -} diff --git a/src/kmod-setup.h b/src/kmod-setup.h deleted file mode 100644 index 496aef3..0000000 --- a/src/kmod-setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fookmodsetuphfoo -#define fookmodsetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int kmod_setup(void); - -#endif diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c deleted file mode 100644 index 0901a0e..0000000 --- a/src/kmsg-syslogd.c +++ /dev/null @@ -1,513 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "log.h" -#include "sd-daemon.h" -#include "fdset.h" - -#define SERVER_FD_MAX 16 - -typedef struct Stream Stream; - -typedef struct Server { - FDSet *syslog_fds; - int kmsg_fd; - int epoll_fd; - int signal_fd; -} Server; - -static void server_done(Server *s) { - assert(s); - - if (s->epoll_fd >= 0) - close_nointr_nofail(s->epoll_fd); - - if (s->kmsg_fd >= 0) - close_nointr_nofail(s->kmsg_fd); - - if (s->signal_fd >= 0) - close_nointr_nofail(s->signal_fd); - - if (s->syslog_fds) - fdset_free(s->syslog_fds); -} - -static int server_init(Server *s, unsigned n_sockets) { - int r; - unsigned i; - struct epoll_event ev; - sigset_t mask; - - assert(s); - assert(n_sockets > 0); - - zero(*s); - - s->kmsg_fd = s->signal_fd = -1; - - if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) { - r = -errno; - log_error("Failed to create epoll object: %s", strerror(errno)); - goto fail; - } - - if (!(s->syslog_fds = fdset_new())) { - r = -ENOMEM; - log_error("Failed to allocate file descriptor set: %s", strerror(errno)); - goto fail; - } - - for (i = 0; i < n_sockets; i++) { - int fd, one = 1; - - fd = SD_LISTEN_FDS_START+i; - - if ((r = sd_is_socket(fd, AF_UNSPEC, SOCK_DGRAM, -1)) < 0) { - log_error("Failed to determine file descriptor type: %s", strerror(-r)); - goto fail; - } - - if (!r) { - log_error("Wrong file descriptor type."); - r = -EINVAL; - goto fail; - } - - if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) - log_error("SO_PASSCRED failed: %m"); - - zero(ev); - ev.events = EPOLLIN; - ev.data.fd = fd; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - log_error("Failed to add server fd to epoll object: %s", strerror(errno)); - goto fail; - } - - if ((r = fdset_put(s->syslog_fds, fd)) < 0) { - log_error("Failed to store file descriptor in set: %s", strerror(-r)); - goto fail; - } - } - - if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) { - log_error("Failed to open /dev/kmsg for logging: %m"); - return -errno; - } - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if ((s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - return -errno; - } - - zero(ev); - ev.events = EPOLLIN; - ev.data.fd = s->signal_fd; - - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->signal_fd, &ev) < 0) { - log_error("epoll_ctl(): %m"); - return -errno; - } - - return 0; - -fail: - server_done(s); - return r; -} - -static void skip_date(const char **buf) { - enum { - LETTER, - SPACE, - NUMBER, - SPACE_OR_NUMBER, - COLON - } sequence[] = { - LETTER, LETTER, LETTER, - SPACE, - SPACE_OR_NUMBER, NUMBER, - SPACE, - SPACE_OR_NUMBER, NUMBER, - COLON, - SPACE_OR_NUMBER, NUMBER, - COLON, - SPACE_OR_NUMBER, NUMBER, - SPACE - }; - - const char *p; - unsigned i; - - assert(buf); - assert(*buf); - - p = *buf; - - for (i = 0; i < ELEMENTSOF(sequence); i++, p++) { - - if (!*p) - return; - - switch (sequence[i]) { - - case SPACE: - if (*p != ' ') - return; - break; - - case SPACE_OR_NUMBER: - if (*p == ' ') - break; - - /* fall through */ - - case NUMBER: - if (*p < '0' || *p > '9') - return; - - break; - - case LETTER: - if (!(*p >= 'A' && *p <= 'Z') && - !(*p >= 'a' && *p <= 'z')) - return; - - break; - - case COLON: - if (*p != ':') - return; - break; - - } - } - - *buf = p; -} - -static int read_process(const char **buf, struct iovec *iovec) { - const char *p; - size_t l; - - assert(buf); - assert(*buf); - assert(iovec); - - p = *buf; - - p += strspn(p, WHITESPACE); - l = strcspn(p, WHITESPACE); - - if (l <= 0 || - p[l-1] != ':') - return 0; - - l--; - - if (p[l-1] == ']') { - size_t k = l-1; - - for (;;) { - - if (p[k] == '[') { - l = k; - break; - } - - if (k == 0) - break; - - k--; - } - } - - iovec->iov_base = (char*) p; - iovec->iov_len = l; - *buf = p + l; - return 1; -} - -static void skip_pid(const char **buf) { - const char *p; - - assert(buf); - assert(*buf); - - p = *buf; - - if (*p != '[') - return; - - p++; - p += strspn(p, "0123456789"); - - if (*p != ']') - return; - - p++; - - *buf = p; -} - -static int write_message(Server *s, const char *buf, struct ucred *ucred) { - ssize_t k; - char priority[6], pid[16]; - struct iovec iovec[5]; - unsigned i = 0; - char *process = NULL; - int r = 0; - int prio = LOG_USER | LOG_INFO; - - assert(s); - assert(buf); - - parse_syslog_priority((char**) &buf, &prio); - - if (*buf == 0) - return 0; - - if ((prio & LOG_FACMASK) == 0) - prio = LOG_USER | LOG_PRI(prio); - - /* First, set priority field */ - snprintf(priority, sizeof(priority), "<%i>", prio); - char_array_0(priority); - IOVEC_SET_STRING(iovec[i++], priority); - - /* Second, skip date */ - skip_date(&buf); - - /* Then, add process if set */ - if (read_process(&buf, &iovec[i]) > 0) - i++; - else if (ucred && - ucred->pid > 0 && - get_process_name(ucred->pid, &process) >= 0) - IOVEC_SET_STRING(iovec[i++], process); - - /* Skip the stored PID if we have a better one */ - if (ucred) { - snprintf(pid, sizeof(pid), "[%lu]: ", (unsigned long) ucred->pid); - char_array_0(pid); - IOVEC_SET_STRING(iovec[i++], pid); - - skip_pid(&buf); - - if (*buf == ':') - buf++; - - buf += strspn(buf, WHITESPACE); - } - - /* Is the remaining message empty? */ - if (*buf) { - - /* And the rest is the message */ - IOVEC_SET_STRING(iovec[i++], buf); - IOVEC_SET_STRING(iovec[i++], "\n"); - - if ((k = writev(s->kmsg_fd, iovec, i)) <= 0) { - log_error("Failed to write log message to kmsg: %s", k < 0 ? strerror(errno) : "short write"); - r = k < 0 ? -errno : -EIO; - } - } - - free(process); - - return r; -} - -static int process_event(Server *s, struct epoll_event *ev) { - assert(s); - - if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll."); - return -EIO; - } - - if (ev->data.fd == s->signal_fd) { - struct signalfd_siginfo sfsi; - ssize_t n; - - if ((n = read(s->signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { - - if (n >= 0) - return -EIO; - - if (errno == EINTR || errno == EAGAIN) - return 0; - - return -errno; - } - - log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo)); - return 0; - - } else { - for (;;) { - char buf[LINE_MAX+1]; - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - ssize_t n; - int k; - char *e; - - zero(iovec); - iovec.iov_base = buf; - iovec.iov_len = sizeof(buf)-1; - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT)) < 0) { - - if (errno == EINTR || errno == EAGAIN) - return 1; - - log_error("recvmsg() failed: %m"); - return -errno; - } - - if (msghdr.msg_controllen >= CMSG_LEN(sizeof(struct ucred)) && - control.cmsghdr.cmsg_level == SOL_SOCKET && - control.cmsghdr.cmsg_type == SCM_CREDENTIALS && - control.cmsghdr.cmsg_len == CMSG_LEN(sizeof(struct ucred))) - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - else - ucred = NULL; - - if ((e = memchr(buf, '\n', n))) - *e = 0; - else - buf[n] = 0; - - if ((k = write_message(s, strstrip(buf), ucred)) < 0) - return k; - } - } - - return 1; -} - -int main(int argc, char *argv[]) { - Server server; - int r = EXIT_FAILURE, n; - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc > 1) { - log_error("This program does not take arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((n = sd_listen_fds(true)) < 0) { - log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (n <= 0 || n > SERVER_FD_MAX) { - log_error("No or too many file descriptors passed."); - return EXIT_FAILURE; - } - - if (server_init(&server, (unsigned) n) < 0) - return EXIT_FAILURE; - - log_debug("systemd-kmsg-syslogd running as pid %lu", (unsigned long) getpid()); - - sd_notify(false, - "READY=1\n" - "STATUS=Processing messages..."); - - for (;;) { - struct epoll_event event; - int k; - - if ((k = epoll_wait(server.epoll_fd, &event, 1, -1)) < 0) { - - if (errno == EINTR) - continue; - - log_error("epoll_wait() failed: %m"); - goto fail; - } - - if (k <= 0) - break; - - if ((k = process_event(&server, &event)) < 0) - goto fail; - - if (k == 0) - break; - } - - r = EXIT_SUCCESS; - - log_debug("systemd-kmsg-syslogd stopped as pid %lu", (unsigned long) getpid()); - -fail: - sd_notify(false, - "STATUS=Shutting down..."); - - server_done(&server); - - return r; -} diff --git a/src/label.c b/src/label.c deleted file mode 100644 index d9d195b..0000000 --- a/src/label.c +++ /dev/null @@ -1,413 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "label.h" -#include "util.h" - -#ifdef HAVE_SELINUX -#include -#include - -static struct selabel_handle *label_hnd = NULL; - -static int use_selinux_cached = -1; - -static inline bool use_selinux(void) { - - if (use_selinux_cached < 0) - use_selinux_cached = is_selinux_enabled() > 0; - - return use_selinux_cached; -} - -void label_retest_selinux(void) { - use_selinux_cached = -1; -} - -#endif - -int label_init(void) { - int r = 0; - -#ifdef HAVE_SELINUX - usec_t before_timestamp, after_timestamp; - struct mallinfo before_mallinfo, after_mallinfo; - - if (!use_selinux()) - return 0; - - if (label_hnd) - return 0; - - before_mallinfo = mallinfo(); - before_timestamp = now(CLOCK_MONOTONIC); - - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - if (!label_hnd) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to initialize SELinux context: %m"); - r = security_getenforce() == 1 ? -errno : 0; - } else { - char timespan[FORMAT_TIMESPAN_MAX]; - int l; - - after_timestamp = now(CLOCK_MONOTONIC); - after_mallinfo = mallinfo(); - - l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; - - log_info("Successfully loaded SELinux database in %s, size on heap is %iK.", - format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp), - (l+1023)/1024); - } -#endif - - return r; -} - -int label_fix(const char *path, bool ignore_enoent) { - int r = 0; - -#ifdef HAVE_SELINUX - struct stat st; - security_context_t fcon; - - if (!use_selinux() || !label_hnd) - return 0; - - r = lstat(path, &st); - if (r == 0) { - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); - - /* If there's no label to set, then exit without warning */ - if (r < 0 && errno == ENOENT) - return 0; - - if (r == 0) { - r = setfilecon(path, fcon); - freecon(fcon); - - /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == ENOTSUP) - return 0; - } - } - - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) - return 0; - - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Unable to fix label of %s: %m", path); - r = security_getenforce() == 1 ? -errno : 0; - } -#endif - - return r; -} - -void label_finish(void) { - -#ifdef HAVE_SELINUX - if (use_selinux() && label_hnd) - selabel_close(label_hnd); -#endif -} - -int label_get_create_label_from_exe(const char *exe, char **label) { - - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t mycon = NULL, fcon = NULL; - security_class_t sclass; - - if (!use_selinux()) { - *label = NULL; - return 0; - } - - r = getcon(&mycon); - if (r < 0) - goto fail; - - r = getfilecon(exe, &fcon); - if (r < 0) - goto fail; - - sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); - if (r == 0) - log_debug("SELinux Socket context for %s will be set to %s", exe, *label); - -fail: - if (r < 0 && security_getenforce() == 1) - r = -errno; - - freecon(mycon); - freecon(fcon); -#endif - - return r; -} - -int label_fifofile_set(const char *path) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label_hnd) - return 0; - - r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFIFO); - if (r < 0) - r = -errno; - else if (r == 0) { - r = setfscreatecon(filecon); - if (r < 0) { - log_error("Failed to set SELinux file context on %s: %m", path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -int label_symlinkfile_set(const char *path) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label_hnd) - return 0; - - r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK); - if (r < 0) - r = -errno; - else if (r == 0) { - r = setfscreatecon(filecon); - if (r < 0) { - log_error("Failed to set SELinux file context on %s: %m", path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -int label_socket_set(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return 0; - - if (setsockcreatecon((security_context_t) label) < 0) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to set SELinux context (%s) on socket: %m", label); - - if (security_getenforce() == 1) - return -errno; - } -#endif - - return 0; -} - -void label_file_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setfscreatecon(NULL); -#endif -} - -void label_socket_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setsockcreatecon(NULL); -#endif -} - -void label_free(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - freecon((security_context_t) label); -#endif -} - -int label_mkdir(const char *path, mode_t mode) { - - /* Creates a directory and labels it according to the SELinux policy */ - -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - - if (!use_selinux() || !label_hnd) - goto skipped; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); - else { - char *newpath; - - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; - - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if (r < 0 && errno != ENOENT) { - log_error("Failed to set security context %s for %s: %m", fcon, path); - - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } - } - - r = mkdir(path, mode); - if (r < 0) - r = -errno; - -finish: - setfscreatecon(NULL); - freecon(fcon); - - return r; - -skipped: -#endif - return mkdir(path, mode) < 0 ? -errno : 0; -} - -int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { - - /* Binds a socket and label its file system object according to the SELinux policy */ - -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - const struct sockaddr_un *un; - char *path = NULL; - - assert(fd >= 0); - assert(addr); - assert(addrlen >= sizeof(sa_family_t)); - - if (!use_selinux() || !label_hnd) - goto skipped; - - /* Filter out non-local sockets */ - if (addr->sa_family != AF_UNIX) - goto skipped; - - /* Filter out anonymous sockets */ - if (addrlen < sizeof(sa_family_t) + 1) - goto skipped; - - /* Filter out abstract namespace sockets */ - un = (const struct sockaddr_un*) addr; - if (un->sun_path[0] == 0) - goto skipped; - - path = strndup(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path)); - if (!path) - return -ENOMEM; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); - else { - char *newpath; - - newpath = path_make_absolute_cwd(path); - - if (!newpath) { - free(path); - return -ENOMEM; - } - - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if (r < 0 && errno != ENOENT) { - log_error("Failed to set security context %s for %s: %m", fcon, path); - - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } - } - - r = bind(fd, addr, addrlen); - if (r < 0) - r = -errno; - -finish: - setfscreatecon(NULL); - freecon(fcon); - free(path); - - return r; - -skipped: -#endif - return bind(fd, addr, addrlen) < 0 ? -errno : 0; -} diff --git a/src/label.h b/src/label.h deleted file mode 100644 index ead4483..0000000 --- a/src/label.h +++ /dev/null @@ -1,51 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foolabelhfoo -#define foolabelhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -int label_init(void); -void label_finish(void); - -int label_fix(const char *path, bool ignore_enoent); - -int label_socket_set(const char *label); -void label_socket_clear(void); - -int label_fifofile_set(const char *path); -int label_symlinkfile_set(const char *path); -void label_file_clear(void); - -void label_free(const char *label); - -int label_get_create_label_from_exe(const char *exe, char **label); - -int label_mkdir(const char *path, mode_t mode); - -void label_retest_selinux(void); - -int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); - -#endif diff --git a/src/libsystemd-dhcp/Makefile b/src/libsystemd-dhcp/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/libsystemd-dhcp/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/libsystemd-dhcp/dhcp-internal.h b/src/libsystemd-dhcp/dhcp-internal.h new file mode 100644 index 0000000..ce83b81 --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-internal.h @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "socket-util.h" + +#include "dhcp-protocol.h" + +int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link); +int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port); +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, + const void *packet, size_t len); +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, + const void *packet, size_t len); + +int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code, + size_t optlen, const void *optval); + +typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, + const uint8_t *option, void *user_data); + +int dhcp_option_parse(DHCPMessage *message, size_t len, + dhcp_option_cb_t cb, void *user_data); + +int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, + uint8_t **opt, size_t *optlen); + +void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint16_t len); + +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); + +#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT: " fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-dhcp/dhcp-lease.c b/src/libsystemd-dhcp/dhcp-lease.c new file mode 100644 index 0000000..c1f76aa --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-lease.c @@ -0,0 +1,244 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "list.h" + +#include "dhcp-protocol.h" +#include "dhcp-internal.h" +#include "dhcp-lease.h" +#include "sd-dhcp-client.h" + +int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->address; + + return 0; +} + +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { + assert_return(lease, -EINVAL); + assert_return(mtu, -EINVAL); + + if (lease->mtu) + *mtu = lease->mtu; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(addr_size, -EINVAL); + + if (lease->dns_size) { + *addr_size = lease->dns_size; + *addr = lease->dns; + } else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { + assert_return(lease, -EINVAL); + assert_return(domainname, -EINVAL); + + if (lease->domainname) + *domainname = lease->domainname; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { + assert_return(lease, -EINVAL); + assert_return(hostname, -EINVAL); + + if (lease->hostname) + *hostname = lease->hostname; + else + return -ENOENT; + + return 0; +} + +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->router; + + return 0; +} + +int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + addr->s_addr = lease->subnet_mask; + + return 0; +} + +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { + if (lease) + assert_se(REFCNT_INC(lease->n_ref) >= 2); + + return lease; +} + +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { + if (lease && REFCNT_DEC(lease->n_ref) <= 0) { + free(lease->hostname); + free(lease->domainname); + free(lease->dns); + free(lease); + } + + return NULL; +} + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data) { + sd_dhcp_lease *lease = user_data; + be32_t val; + + switch(code) { + + case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->lifetime = be32toh(val); + } + + break; + + case DHCP_OPTION_SERVER_IDENTIFIER: + if (len >= 4) + memcpy(&lease->server_address, option, 4); + + break; + + case DHCP_OPTION_SUBNET_MASK: + if (len >= 4) + memcpy(&lease->subnet_mask, option, 4); + + break; + + case DHCP_OPTION_ROUTER: + if (len >= 4) + memcpy(&lease->router, option, 4); + + break; + + case DHCP_OPTION_DOMAIN_NAME_SERVER: + if (len && !(len % 4)) { + unsigned i; + + lease->dns_size = len / 4; + + free(lease->dns); + lease->dns = new0(struct in_addr, lease->dns_size); + if (!lease->dns) + return -ENOMEM; + + for (i = 0; i < lease->dns_size; i++) { + memcpy(&lease->dns[i].s_addr, option + 4 * i, 4); + } + } + + break; + + case DHCP_OPTION_INTERFACE_MTU: + if (len >= 2) { + be16_t mtu; + + memcpy(&mtu, option, 2); + lease->mtu = be16toh(mtu); + + if (lease->mtu < 68) + lease->mtu = 0; + } + + break; + + case DHCP_OPTION_DOMAIN_NAME: + if (len >= 1) { + free(lease->domainname); + lease->domainname = strndup((const char *)option, len); + } + + break; + + case DHCP_OPTION_HOST_NAME: + if (len >= 1) { + free(lease->hostname); + lease->hostname = strndup((const char *)option, len); + } + + break; + + case DHCP_OPTION_RENEWAL_T1_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t1 = be32toh(val); + } + + break; + + case DHCP_OPTION_REBINDING_T2_TIME: + if (len == 4) { + memcpy(&val, option, 4); + lease->t2 = be32toh(val); + } + + break; + } + + return 0; +} + +int dhcp_lease_new(sd_dhcp_lease **ret) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + + lease = new0(sd_dhcp_lease, 1); + if (!lease) + return -ENOMEM; + + lease->n_ref = REFCNT_INIT; + + *ret = lease; + lease = NULL; + + return 0; +} diff --git a/src/libsystemd-dhcp/dhcp-lease.h b/src/libsystemd-dhcp/dhcp-lease.h new file mode 100644 index 0000000..87323dc --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-lease.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "socket-util.h" +#include "refcnt.h" + +#include "dhcp-protocol.h" + +#include "sd-dhcp-client.h" + +struct sd_dhcp_lease { + RefCount n_ref; + + uint32_t t1; + uint32_t t2; + uint32_t lifetime; + be32_t address; + be32_t server_address; + be32_t subnet_mask; + be32_t router; + struct in_addr *dns; + size_t dns_size; + uint16_t mtu; + char *domainname; + char *hostname; +}; + +int dhcp_lease_new(sd_dhcp_lease **ret); +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data); + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); +#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/libsystemd-dhcp/dhcp-network.c b/src/libsystemd-dhcp/dhcp-network.c new file mode 100644 index 0000000..934e8bf --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-network.c @@ -0,0 +1,109 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket-util.h" + +#include "dhcp-internal.h" + +int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link) +{ + int s, one = 1; + + assert(index > 0); + assert(link); + + s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + htons(ETH_P_IP)); + if (s < 0) + return -errno; + + link->ll.sll_family = AF_PACKET; + link->ll.sll_protocol = htons(ETH_P_IP); + link->ll.sll_ifindex = index; + link->ll.sll_halen = ETH_ALEN; + memset(link->ll.sll_addr, 0xff, ETH_ALEN); + + if (setsockopt (s, SOL_PACKET, PACKET_AUXDATA, &one, sizeof(one)) < 0) + return -errno; + + if (bind(s, &link->sa, sizeof(link->ll)) < 0) { + close_nointr_nofail(s); + return -errno; + } + + return s; +} + +int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port) +{ + int s; + union sockaddr_union src = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(port), + .in.sin_addr.s_addr = address, + }; + + s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (s < 0) + return -errno; + + if (bind(s, &src.sa, sizeof(src.in)) < 0) { + close_nointr_nofail(s); + return -errno; + } + + return s; +} + +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, + const void *packet, size_t len) +{ + assert(link); + assert(packet); + assert(len); + + if (sendto(s, packet, len, 0, &link->sa, sizeof(link->ll)) < 0) + return -errno; + + return 0; +} + +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, + const void *packet, size_t len) +{ + union sockaddr_union dest = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(port), + .in.sin_addr.s_addr = address, + }; + + if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0) + return -errno; + + return 0; +} diff --git a/src/libsystemd-dhcp/dhcp-option.c b/src/libsystemd-dhcp/dhcp-option.c new file mode 100644 index 0000000..4d45b3b --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-option.c @@ -0,0 +1,184 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "dhcp-internal.h" + +int dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code, + size_t optlen, const void *optval) +{ + if (!buf || !buflen) + return -EINVAL; + + switch (code) { + + case DHCP_OPTION_PAD: + case DHCP_OPTION_END: + if (*buflen < 1) + return -ENOBUFS; + + (*buf)[0] = code; + *buf += 1; + *buflen -= 1; + break; + + default: + if (*buflen < optlen + 2) + return -ENOBUFS; + + if (!optval) + return -EINVAL; + + (*buf)[0] = code; + (*buf)[1] = optlen; + memcpy(&(*buf)[2], optval, optlen); + + *buf += optlen + 2; + *buflen -= (optlen + 2); + + break; + } + + return 0; +} + +static int parse_options(const uint8_t *buf, size_t buflen, uint8_t *overload, + uint8_t *message_type, dhcp_option_cb_t cb, + void *user_data) +{ + const uint8_t *code = buf; + const uint8_t *len; + + while (buflen > 0) { + switch (*code) { + case DHCP_OPTION_PAD: + buflen -= 1; + code++; + break; + + case DHCP_OPTION_END: + return 0; + + case DHCP_OPTION_MESSAGE_TYPE: + if (buflen < 3) + return -ENOBUFS; + buflen -= 3; + + len = code + 1; + if (*len != 1) + return -EINVAL; + + if (message_type) + *message_type = *(len + 1); + + code += 3; + + break; + + case DHCP_OPTION_OVERLOAD: + if (buflen < 3) + return -ENOBUFS; + buflen -= 3; + + len = code + 1; + if (*len != 1) + return -EINVAL; + + if (overload) + *overload = *(len + 1); + + code += 3; + + break; + + default: + if (buflen < 3) + return -ENOBUFS; + + len = code + 1; + + if (buflen < (size_t)*len + 2) + return -EINVAL; + buflen -= *len + 2; + + if (cb) + cb(*code, *len, len + 1, user_data); + + code += *len + 2; + + break; + } + } + + if (buflen) + return -EINVAL; + + return 0; +} + +int dhcp_option_parse(DHCPMessage *message, size_t len, + dhcp_option_cb_t cb, void *user_data) +{ + uint8_t overload = 0; + uint8_t message_type = 0; + uint8_t *opt = (uint8_t *)(message + 1); + int res; + + if (!message) + return -EINVAL; + + if (len < sizeof(DHCPMessage) + 4) + return -EINVAL; + + len -= sizeof(DHCPMessage) + 4; + + if (opt[0] != 0x63 && opt[1] != 0x82 && opt[2] != 0x53 && + opt[3] != 0x63) + return -EINVAL; + + res = parse_options(&opt[4], len, &overload, &message_type, + cb, user_data); + if (res < 0) + return res; + + if (overload & DHCP_OVERLOAD_FILE) { + res = parse_options(message->file, sizeof(message->file), + NULL, &message_type, cb, user_data); + if (res < 0) + return res; + } + + if (overload & DHCP_OVERLOAD_SNAME) { + res = parse_options(message->sname, sizeof(message->sname), + NULL, &message_type, cb, user_data); + if (res < 0) + return res; + } + + if (message_type) + return message_type; + + return -ENOMSG; +} diff --git a/src/libsystemd-dhcp/dhcp-packet.c b/src/libsystemd-dhcp/dhcp-packet.c new file mode 100644 index 0000000..8388e56 --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-packet.c @@ -0,0 +1,190 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "list.h" + +#include "dhcp-protocol.h" +#include "dhcp-lease.h" +#include "dhcp-internal.h" +#include "sd-dhcp-client.h" + +#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 + +int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, + uint8_t type, uint8_t **opt, size_t *optlen) { + int err; + + assert(op == BOOTREQUEST || op == BOOTREPLY); + + *opt = (uint8_t *)(message + 1); + + if (*optlen < 4) + return -ENOBUFS; + *optlen -= 4; + + message->op = op; + message->htype = ARPHRD_ETHER; + message->hlen = ETHER_ADDR_LEN; + message->xid = htobe32(xid); + + (*opt)[0] = 0x63; + (*opt)[1] = 0x82; + (*opt)[2] = 0x53; + (*opt)[3] = 0x63; + + *opt += 4; + + err = dhcp_option_append(opt, optlen, DHCP_OPTION_MESSAGE_TYPE, 1, + &type); + if (err < 0) + return err; + + return 0; +} + +static uint16_t dhcp_checksum(void *buf, int len) { + uint32_t sum; + uint16_t *check; + int i; + uint8_t *odd; + + sum = 0; + check = buf; + + for (i = 0; i < len / 2 ; i++) + sum += check[i]; + + if (len & 0x01) { + odd = buf; + sum += odd[len - 1]; + } + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint16_t len) { + packet->ip.version = IPVERSION; + packet->ip.ihl = DHCP_IP_SIZE / 4; + packet->ip.tot_len = htobe16(len); + + packet->ip.protocol = IPPROTO_UDP; + packet->ip.saddr = INADDR_ANY; + packet->ip.daddr = INADDR_BROADCAST; + + packet->udp.source = htobe16(DHCP_PORT_CLIENT); + packet->udp.dest = htobe16(DHCP_PORT_SERVER); + + packet->udp.len = htobe16(len - DHCP_IP_SIZE); + + packet->ip.check = packet->udp.len; + packet->udp.check = dhcp_checksum(&packet->ip.ttl, len - 8); + + packet->ip.ttl = IPDEFTTL; + packet->ip.check = 0; + packet->ip.check = dhcp_checksum(&packet->ip, DHCP_IP_SIZE); +} + +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { + size_t hdrlen; + + assert(packet); + + /* IP */ + + if (len < DHCP_IP_SIZE) { + log_dhcp_client(client, "ignoring packet: packet (%zu bytes) " + " smaller than IP header (%u bytes)", len, + DHCP_IP_SIZE); + return -EINVAL; + } + + if (packet->ip.ihl < 5) { + log_dhcp_client(client, "ignoring packet: IPv4 IHL (%u words) invalid", + packet->ip.ihl); + return -EINVAL; + } + + hdrlen = packet->ip.ihl * 4; + if (hdrlen < 20) { + log_dhcp_client(client, "ignoring packet: IPv4 IHL (%zu bytes) " + "smaller than minimum (20 bytes)", hdrlen); + return -EINVAL; + } + + if (len < hdrlen) { + log_dhcp_client(client, "ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by IP header", len, + hdrlen); + return -EINVAL; + } + + if (dhcp_checksum(&packet->ip, hdrlen)) { + log_dhcp_client(client, "ignoring packet: invalid IP checksum"); + return -EINVAL; + } + + /* UDP */ + + if (len < DHCP_IP_UDP_SIZE) { + log_dhcp_client(client, "ignoring packet: packet (%zu bytes) " + " smaller than IP+UDP header (%u bytes)", len, + DHCP_IP_UDP_SIZE); + return -EINVAL; + } + + if (len < hdrlen + be16toh(packet->udp.len)) { + log_dhcp_client(client, "ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by UDP header", len, + hdrlen + be16toh(packet->udp.len)); + return -EINVAL; + } + + if (checksum && packet->udp.check) { + packet->ip.check = packet->udp.len; + packet->ip.ttl = 0; + + if (dhcp_checksum(&packet->ip.ttl, + be16toh(packet->udp.len) + 12)) { + log_dhcp_client(client, "ignoring packet: invalid UDP checksum"); + return -EINVAL; + } + } + + if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { + log_dhcp_client(client, "ignoring packet: to port %u, which " + "is not the DHCP client port (%u)", + be16toh(packet->udp.dest), DHCP_PORT_CLIENT); + return -EINVAL; + } + + return 0; +} diff --git a/src/libsystemd-dhcp/dhcp-protocol.h b/src/libsystemd-dhcp/dhcp-protocol.h new file mode 100644 index 0000000..81d36ce --- /dev/null +++ b/src/libsystemd-dhcp/dhcp-protocol.h @@ -0,0 +1,121 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "macro.h" +#include "sparse-endian.h" + +struct DHCPMessage { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + be32_t xid; + be16_t secs; + be16_t flags; + be32_t ciaddr; + be32_t yiaddr; + be32_t siaddr; + be32_t giaddr; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; +} _packed_; + +typedef struct DHCPMessage DHCPMessage; + +struct DHCPPacket { + struct iphdr ip; + struct udphdr udp; + DHCPMessage dhcp; +} _packed_; + +typedef struct DHCPPacket DHCPPacket; + +#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) +#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) +#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) +#define DHCP_MIN_OPTIONS_SIZE 312 + +enum { + DHCP_PORT_SERVER = 67, + DHCP_PORT_CLIENT = 68, +}; + +enum DHCPState { + DHCP_STATE_INIT = 0, + DHCP_STATE_SELECTING = 1, + DHCP_STATE_INIT_REBOOT = 2, + DHCP_STATE_REBOOTING = 3, + DHCP_STATE_REQUESTING = 4, + DHCP_STATE_BOUND = 5, + DHCP_STATE_RENEWING = 6, + DHCP_STATE_REBINDING = 7, +}; + +typedef enum DHCPState DHCPState; + +enum { + BOOTREQUEST = 1, + BOOTREPLY = 2, +}; + +enum { + DHCP_DISCOVER = 1, + DHCP_OFFER = 2, + DHCP_REQUEST = 3, + DHCP_DECLINE = 4, + DHCP_ACK = 5, + DHCP_NAK = 6, + DHCP_RELEASE = 7, +}; + +enum { + DHCP_OVERLOAD_FILE = 1, + DHCP_OVERLOAD_SNAME = 2, +}; + +enum { + DHCP_OPTION_PAD = 0, + DHCP_OPTION_SUBNET_MASK = 1, + DHCP_OPTION_ROUTER = 3, + DHCP_OPTION_DOMAIN_NAME_SERVER = 6, + DHCP_OPTION_HOST_NAME = 12, + DHCP_OPTION_DOMAIN_NAME = 15, + DHCP_OPTION_INTERFACE_MTU = 26, + DHCP_OPTION_NTP_SERVER = 42, + DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, + DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, + DHCP_OPTION_OVERLOAD = 52, + DHCP_OPTION_MESSAGE_TYPE = 53, + DHCP_OPTION_SERVER_IDENTIFIER = 54, + DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, + DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, + DHCP_OPTION_RENEWAL_T1_TIME = 58, + DHCP_OPTION_REBINDING_T2_TIME = 59, + DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_END = 255, +}; diff --git a/src/libsystemd-dhcp/sd-dhcp-client.c b/src/libsystemd-dhcp/sd-dhcp-client.c new file mode 100644 index 0000000..0c82260 --- /dev/null +++ b/src/libsystemd-dhcp/sd-dhcp-client.c @@ -0,0 +1,1051 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "list.h" + +#include "dhcp-protocol.h" +#include "dhcp-lease.h" +#include "dhcp-internal.h" +#include "sd-dhcp-client.h" + +struct sd_dhcp_client { + DHCPState state; + sd_event *event; + int event_priority; + sd_event_source *timeout_resend; + int index; + int fd; + union sockaddr_union link; + sd_event_source *receive_message; + uint8_t *req_opts; + size_t req_opts_allocated; + size_t req_opts_size; + be32_t last_addr; + struct ether_addr mac_addr; + uint32_t xid; + usec_t start_time; + uint16_t secs; + unsigned int attempt; + usec_t request_sent; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; + sd_event_source *timeout_expire; + sd_dhcp_client_cb_t cb; + void *userdata; + sd_dhcp_lease *lease; +}; + +static const uint8_t default_req_opts[] = { + DHCP_OPTION_SUBNET_MASK, + DHCP_OPTION_ROUTER, + DHCP_OPTION_HOST_NAME, + DHCP_OPTION_DOMAIN_NAME, + DHCP_OPTION_DOMAIN_NAME_SERVER, + DHCP_OPTION_NTP_SERVER, +}; + +static int client_receive_message_raw(sd_event_source *s, int fd, + uint32_t revents, void *userdata); +static int client_receive_message_udp(sd_event_source *s, int fd, + uint32_t revents, void *userdata); + +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, + void *userdata) { + assert_return(client, -EINVAL); + + client->cb = cb; + client->userdata = userdata; + + return 0; +} + +int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { + size_t i; + + assert_return(client, -EINVAL); + assert_return (client->state == DHCP_STATE_INIT, -EBUSY); + + switch(option) { + case DHCP_OPTION_PAD: + case DHCP_OPTION_OVERLOAD: + case DHCP_OPTION_MESSAGE_TYPE: + case DHCP_OPTION_PARAMETER_REQUEST_LIST: + case DHCP_OPTION_END: + return -EINVAL; + + default: + break; + } + + for (i = 0; i < client->req_opts_size; i++) + if (client->req_opts[i] == option) + return -EEXIST; + + if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, + client->req_opts_size + 1)) + return -ENOMEM; + + client->req_opts[client->req_opts_size++] = option; + + return 0; +} + +int sd_dhcp_client_set_request_address(sd_dhcp_client *client, + const struct in_addr *last_addr) { + assert_return(client, -EINVAL); + assert_return(client->state == DHCP_STATE_INIT, -EBUSY); + + if (last_addr) + client->last_addr = last_addr->s_addr; + else + client->last_addr = INADDR_ANY; + + return 0; +} + +int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { + assert_return(client, -EINVAL); + assert_return(client->state == DHCP_STATE_INIT, -EBUSY); + assert_return(interface_index >= -1, -EINVAL); + + client->index = interface_index; + + return 0; +} + +int sd_dhcp_client_set_mac(sd_dhcp_client *client, + const struct ether_addr *addr) { + assert_return(client, -EINVAL); + assert_return(client->state == DHCP_STATE_INIT, -EBUSY); + + memcpy(&client->mac_addr, addr, ETH_ALEN); + + return 0; +} + +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { + assert_return(client, -EINVAL); + assert_return(ret, -EINVAL); + + if (client->state != DHCP_STATE_BOUND && + client->state != DHCP_STATE_RENEWING && + client->state != DHCP_STATE_REBINDING) + return -EADDRNOTAVAIL; + + *ret = sd_dhcp_lease_ref(client->lease); + + return 0; +} + +static int client_notify(sd_dhcp_client *client, int event) { + if (client->cb) + client->cb(client, event, client->userdata); + + return 0; +} + +static int client_stop(sd_dhcp_client *client, int error) { + assert_return(client, -EINVAL); + + client->receive_message = + sd_event_source_unref(client->receive_message); + + if (client->fd >= 0) + close(client->fd); + client->fd = -1; + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); + + client->attempt = 1; + + client_notify(client, error); + + client->start_time = 0; + client->secs = 0; + client->state = DHCP_STATE_INIT; + + if (client->lease) + client->lease = sd_dhcp_lease_unref(client->lease); + + log_dhcp_client(client, "STOPPED"); + + return 0; +} + +static int client_message_init(sd_dhcp_client *client, DHCPMessage *message, + uint8_t type, uint16_t secs, uint8_t **opt, + size_t *optlen) { + int r; + + assert(secs); + + r = dhcp_message_init(message, BOOTREQUEST, client->xid, type, opt, + optlen); + if (r < 0) + return r; + + /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers + refuse to issue an DHCP lease if 'secs' is set to zero */ + message->secs = htobe16(secs); + + memcpy(&message->chaddr, &client->mac_addr, ETH_ALEN); + + if (client->state == DHCP_STATE_RENEWING || + client->state == DHCP_STATE_REBINDING) + message->ciaddr = client->lease->address; + + /* Some DHCP servers will refuse to issue an DHCP lease if the Client + Identifier option is not set */ + r = dhcp_option_append(opt, optlen, DHCP_OPTION_CLIENT_IDENTIFIER, + ETH_ALEN, &client->mac_addr); + if (r < 0) + return r; + + if (type == DHCP_DISCOVER || type == DHCP_REQUEST) { + be16_t max_size; + + r = dhcp_option_append(opt, optlen, + DHCP_OPTION_PARAMETER_REQUEST_LIST, + client->req_opts_size, + client->req_opts); + if (r < 0) + return r; + + /* Some DHCP servers will send bigger DHCP packets than the + defined default size unless the Maximum Messge Size option + is explicitely set */ + max_size = htobe16(DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE + + DHCP_MIN_OPTIONS_SIZE); + r = dhcp_option_append(opt, optlen, + DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, + 2, &max_size); + if (r < 0) + return r; + } + + return 0; +} + +static int client_send_discover(sd_dhcp_client *client, uint16_t secs) { + int err = 0; + _cleanup_free_ DHCPPacket *discover; + size_t optlen, len; + uint8_t *opt; + + optlen = DHCP_MIN_OPTIONS_SIZE; + len = sizeof(DHCPPacket) + optlen; + + discover = malloc0(len); + + if (!discover) + return -ENOMEM; + + err = client_message_init(client, &discover->dhcp, DHCP_DISCOVER, + secs, &opt, &optlen); + if (err < 0) + return err; + + if (client->last_addr != INADDR_ANY) { + err = dhcp_option_append(&opt, &optlen, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->last_addr); + if (err < 0) + return err; + } + + err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); + if (err < 0) + return err; + + dhcp_packet_append_ip_headers(discover, len); + + err = dhcp_network_send_raw_socket(client->fd, &client->link, + discover, len); + + log_dhcp_client(client, "DISCOVER"); + + return err; +} + +static int client_send_request(sd_dhcp_client *client, uint16_t secs) { + _cleanup_free_ DHCPPacket *request; + size_t optlen, len; + int err; + uint8_t *opt; + + optlen = DHCP_MIN_OPTIONS_SIZE; + len = sizeof(DHCPPacket) + optlen; + + request = malloc0(len); + if (!request) + return -ENOMEM; + + err = client_message_init(client, &request->dhcp, DHCP_REQUEST, secs, + &opt, &optlen); + if (err < 0) + return err; + + if (client->state == DHCP_STATE_REQUESTING) { + err = dhcp_option_append(&opt, &optlen, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->lease->address); + if (err < 0) + return err; + + err = dhcp_option_append(&opt, &optlen, + DHCP_OPTION_SERVER_IDENTIFIER, + 4, &client->lease->server_address); + if (err < 0) + return err; + } + + err = dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL); + if (err < 0) + return err; + + if (client->state == DHCP_STATE_RENEWING) { + err = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &request->dhcp, + len - DHCP_IP_UDP_SIZE); + } else { + dhcp_packet_append_ip_headers(request, len); + + err = dhcp_network_send_raw_socket(client->fd, &client->link, + request, len); + } + + log_dhcp_client(client, "REQUEST"); + + return err; +} + +static uint16_t client_update_secs(sd_dhcp_client *client, usec_t time_now) +{ + client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; + + return client->secs; +} + +static int client_timeout_resend(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + usec_t next_timeout = 0; + uint32_t time_left; + int r = 0; + + assert(s); + assert(client); + assert(client->event); + + switch (client->state) { + case DHCP_STATE_RENEWING: + + time_left = (client->lease->t2 - client->lease->t1) / 2; + if (time_left < 60) + time_left = 60; + + next_timeout = usec + time_left * USEC_PER_SEC; + + break; + + case DHCP_STATE_REBINDING: + + time_left = (client->lease->lifetime - client->lease->t2) / 2; + if (time_left < 60) + time_left = 60; + + next_timeout = usec + time_left * USEC_PER_SEC; + break; + + case DHCP_STATE_INIT: + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_SELECTING: + case DHCP_STATE_REQUESTING: + case DHCP_STATE_BOUND: + + if (client->attempt < 64) + client->attempt *= 2; + + next_timeout = usec + (client->attempt - 1) * USEC_PER_SEC; + + break; + } + + next_timeout += (random_u32() & 0x1fffff); + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_resend, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + + switch (client->state) { + case DHCP_STATE_INIT: + + client_update_secs(client, usec); + + r = client_send_discover(client, client->secs); + if (r >= 0) { + client->state = DHCP_STATE_SELECTING; + client->attempt = 1; + } else { + if (client->attempt >= 64) + goto error; + } + + break; + + case DHCP_STATE_SELECTING: + client_update_secs(client, usec); + + r = client_send_discover(client, client->secs); + if (r < 0 && client->attempt >= 64) + goto error; + + break; + + case DHCP_STATE_REQUESTING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + r = client_send_request(client, client->secs); + if (r < 0 && client->attempt >= 64) + goto error; + + client->request_sent = usec; + + break; + + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_BOUND: + + break; + } + + return 0; + +error: + client_stop(client, r); + + /* Errors were dealt with when stopping the client, don't spill + errors into the event loop handler */ + return 0; +} + +static int client_initialize_events(sd_dhcp_client *client, + sd_event_io_handler_t io_callback, + usec_t usec) { + int r; + + assert(client); + assert(client->event); + + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, io_callback, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->receive_message, + client->event_priority); + if (r < 0) + goto error; + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + usec, 0, + client_timeout_resend, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + +error: + if (r < 0) + client_stop(client, r); + + return 0; + +} + +static int client_timeout_expire(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + + log_dhcp_client(client, "EXPIRED"); + + client_stop(client, DHCP_EVENT_EXPIRED); + + return 0; +} + +static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { + sd_dhcp_client *client = userdata; + int r; + + if (client->fd >= 0) { + client->receive_message = + sd_event_source_unref(client->receive_message); + close(client->fd); + client->fd = -1; + } + + client->state = DHCP_STATE_REBINDING; + client->attempt = 1; + + r = dhcp_network_bind_raw_socket(client->index, &client->link); + if (r < 0) { + client_stop(client, r); + return 0; + } + + client->fd = r; + + log_dhcp_client(client, "TIMEOUT T2"); + + return client_initialize_events(client, client_receive_message_raw, + usec); +} + +static int client_timeout_t1(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + int r; + + client->state = DHCP_STATE_RENEWING; + client->attempt = 1; + + r = dhcp_network_bind_udp_socket(client->index, + client->lease->address, + DHCP_PORT_CLIENT); + if (r < 0) { + client_stop(client, r); + return 0; + } + + client->fd = r; + + log_dhcp_client(client, "TIMEOUT T1"); + + return client_initialize_events(client, client_receive_message_udp, usec); +} + +static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, + size_t len) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + int r; + + r = dhcp_lease_new(&lease); + if (r < 0) + return r; + + r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); + if (r != DHCP_OFFER) + return -ENOMSG; + + lease->address = offer->yiaddr; + + if (lease->address == INADDR_ANY || + lease->server_address == INADDR_ANY || + lease->subnet_mask == INADDR_ANY || + lease->lifetime == 0) + return -ENOMSG; + + client->lease = lease; + lease = NULL; + + log_dhcp_client(client, "OFFER"); + + return 0; +} + +static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, + size_t len) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + int r; + + r = dhcp_lease_new(&lease); + if (r < 0) + return r; + + r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); + if (r == DHCP_NAK) { + log_dhcp_client(client, "NAK"); + return DHCP_EVENT_NO_LEASE; + } + + if (r != DHCP_ACK) + return -ENOMSG; + + lease->address = ack->yiaddr; + + if (lease->address == INADDR_ANY || + lease->server_address == INADDR_ANY || + lease->subnet_mask == INADDR_ANY || lease->lifetime == 0) + return -ENOMSG; + + r = DHCP_EVENT_IP_ACQUIRE; + if (client->lease) { + if (client->lease->address != lease->address || + client->lease->subnet_mask != lease->subnet_mask || + client->lease->router != lease->router) { + r = DHCP_EVENT_IP_CHANGE; + } + + client->lease = sd_dhcp_lease_unref(client->lease); + } + + client->lease = lease; + lease = NULL; + + log_dhcp_client(client, "ACK"); + + return r; +} + +static uint64_t client_compute_timeout(uint64_t request_sent, + uint32_t lifetime) { + return request_sent + (lifetime - 3) * USEC_PER_SEC + + + (random_u32() & 0x1fffff); +} + +static int client_set_lease_timeouts(sd_dhcp_client *client, uint64_t usec) { + uint64_t next_timeout; + int r; + + assert(client); + assert(client->event); + + if (client->lease->lifetime < 10) + return -EINVAL; + + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); + + if (!client->lease->t1) + client->lease->t1 = client->lease->lifetime / 2; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->t1); + if (next_timeout < usec) + return -EINVAL; + + r = sd_event_add_monotonic(client->event, + &client->timeout_t1, + next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_t1, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_t1, + client->event_priority); + if (r < 0) + return r; + + if (!client->lease->t2) + client->lease->t2 = client->lease->lifetime * 7 / 8; + + if (client->lease->t2 < client->lease->t1) + return -EINVAL; + + if (client->lease->lifetime < client->lease->t2) + return -EINVAL; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->t2); + if (next_timeout < usec) + return -EINVAL; + + r = sd_event_add_monotonic(client->event, + &client->timeout_t2, + next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_t2, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_t2, + client->event_priority); + if (r < 0) + return r; + + next_timeout = client_compute_timeout(client->request_sent, + client->lease->lifetime); + if (next_timeout < usec) + return -EINVAL; + + r = sd_event_add_monotonic(client->event, + &client->timeout_expire, next_timeout, + 10 * USEC_PER_MSEC, + client_timeout_expire, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_expire, + client->event_priority); + if (r < 0) + return r; + + return 0; +} + +static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, + int len, usec_t time_now) { + int r = 0, notify_event = 0; + + assert(client); + assert(client->event); + assert(message); + + if (len < DHCP_MESSAGE_SIZE) { + log_dhcp_client(client, "message too small (%d bytes): " + "ignoring", len); + return 0; + } + + if (message->op != BOOTREPLY) { + log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); + return 0; + } + + if (be32toh(message->xid) != client->xid) { + log_dhcp_client(client, "received xid (%u) does not match " + "expected (%u): ignoring", + be32toh(message->xid), client->xid); + return 0; + } + + if (memcmp(&message->chaddr[0], &client->mac_addr.ether_addr_octet, + ETHER_ADDR_LEN)) { + log_dhcp_client(client, "received chaddr does not match " + "expected: ignoring"); + return 0; + } + + switch (client->state) { + case DHCP_STATE_SELECTING: + + r = client_handle_offer(client, message, len); + if (r >= 0) { + + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + + client->state = DHCP_STATE_REQUESTING; + client->attempt = 1; + + r = sd_event_add_monotonic(client->event, + &client->timeout_resend, + time_now, 0, + client_timeout_resend, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + } + + break; + + case DHCP_STATE_REQUESTING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + + r = client_handle_ack(client, message, len); + + if (r == DHCP_EVENT_NO_LEASE) + goto error; + + if (r >= 0) { + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + + if (client->state == DHCP_STATE_REQUESTING) + notify_event = DHCP_EVENT_IP_ACQUIRE; + else if (r != DHCP_EVENT_IP_ACQUIRE) + notify_event = r; + + client->state = DHCP_STATE_BOUND; + client->attempt = 1; + + client->last_addr = client->lease->address; + + r = client_set_lease_timeouts(client, time_now); + if (r < 0) + goto error; + + if (notify_event) + client_notify(client, notify_event); + + client->receive_message = + sd_event_source_unref(client->receive_message); + close(client->fd); + client->fd = -1; + } + + r = 0; + + break; + + case DHCP_STATE_INIT: + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_BOUND: + + break; + } + +error: + if (r < 0 || r == DHCP_EVENT_NO_LEASE) + return client_stop(client, r); + + return 0; +} + +static int client_receive_message_udp(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + sd_dhcp_client *client = userdata; + _cleanup_free_ DHCPMessage *message = NULL; + int buflen = 0, len, r; + usec_t time_now; + + assert(s); + assert(client); + assert(client->event); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPMessage) + DHCP_MIN_OPTIONS_SIZE; + + message = malloc0(buflen); + if (!message) + return -ENOMEM; + + len = read(fd, message, buflen); + if (len < 0) + return 0; + + r = sd_event_get_now_monotonic(client->event, &time_now); + if (r < 0) + return client_stop(client, r); + + return client_handle_message(client, message, len, + time_now); +} + +static int client_receive_message_raw(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + sd_dhcp_client *client = userdata; + _cleanup_free_ DHCPPacket *packet = NULL; + usec_t time_now; + uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; + struct iovec iov = {}; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), + }; + struct cmsghdr *cmsg; + bool checksum = true; + int buflen = 0, len, r; + + assert(s); + assert(client); + assert(client->event); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE; + + packet = malloc0(buflen); + if (!packet) + return -ENOMEM; + + iov.iov_base = packet; + iov.iov_len = buflen; + + len = recvmsg(fd, &msg, 0); + if (len < 0) { + log_dhcp_client(client, "could not receive message from raw " + "socket: %s", strerror(errno)); + return 0; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_PACKET && cmsg->cmsg_type == PACKET_AUXDATA) { + struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); + + checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); + break; + } + } + + r = dhcp_packet_verify_headers(packet, len, checksum); + if (r < 0) + return 0; + + len -= DHCP_IP_UDP_SIZE; + + r = sd_event_get_now_monotonic(client->event, &time_now); + if (r < 0) + return client_stop(client, r); + + return client_handle_message(client, &packet->dhcp, len, time_now); +} + +int sd_dhcp_client_start(sd_dhcp_client *client) { + int r; + + assert_return(client, -EINVAL); + assert_return(client->event, -EINVAL); + assert_return(client->index > 0, -EINVAL); + assert_return(client->state == DHCP_STATE_INIT || + client->state == DHCP_STATE_INIT_REBOOT, -EBUSY); + + client->xid = random_u32(); + + r = dhcp_network_bind_raw_socket(client->index, &client->link); + + if (r < 0) { + client_stop(client, r); + return r; + } + + client->fd = r; + client->start_time = now(CLOCK_MONOTONIC); + client->secs = 0; + + log_dhcp_client(client, "STARTED"); + + return client_initialize_events(client, client_receive_message_raw, + client->start_time); +} + +int sd_dhcp_client_stop(sd_dhcp_client *client) { + return client_stop(client, DHCP_EVENT_STOP); +} + +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, + int priority) { + int r; + + assert_return(client, -EINVAL); + assert_return(!client->event, -EBUSY); + + if (event) + client->event = sd_event_ref(event); + else { + r = sd_event_default(&client->event); + if (r < 0) + return 0; + } + + client->event_priority = priority; + + return 0; +} + +int sd_dhcp_client_detach_event(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + + client->event = sd_event_unref(client->event); + + return 0; +} + +sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { + if (!client) + return NULL; + + return client->event; +} + +void sd_dhcp_client_free(sd_dhcp_client *client) { + if (!client) + return; + + sd_dhcp_client_stop(client); + sd_dhcp_client_detach_event(client); + + free(client->req_opts); + free(client); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_free); +#define _cleanup_dhcp_client_free_ _cleanup_(sd_dhcp_client_freep) + +int sd_dhcp_client_new(sd_dhcp_client **ret) { + _cleanup_dhcp_client_free_ sd_dhcp_client *client = NULL; + + assert_return(ret, -EINVAL); + + client = new0(sd_dhcp_client, 1); + if (!client) + return -ENOMEM; + + client->state = DHCP_STATE_INIT; + client->index = -1; + client->fd = -1; + client->attempt = 1; + + client->req_opts_size = ELEMENTSOF(default_req_opts); + + client->req_opts = memdup(default_req_opts, client->req_opts_size); + if (!client->req_opts) + return -ENOMEM; + + *ret = client; + client = NULL; + + return 0; +} diff --git a/src/libsystemd-dhcp/test-dhcp-client.c b/src/libsystemd-dhcp/test-dhcp-client.c new file mode 100644 index 0000000..8061e5f --- /dev/null +++ b/src/libsystemd-dhcp/test-dhcp-client.c @@ -0,0 +1,496 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "socket-util.h" + +#include "dhcp-protocol.h" +#include "dhcp-internal.h" +#include "sd-dhcp-client.h" + +static struct ether_addr mac_addr = { + .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} +}; + +typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp); + +static bool verbose = false; +static int test_fd[2]; +static test_callback_recv_t callback_recv; +static be32_t xid; + +static void test_request_basic(sd_event *e) +{ + int r; + + sd_dhcp_client *client; + + if (verbose) + printf("* %s\n", __FUNCTION__); + + r = sd_dhcp_client_new(&client); + + assert_se(r >= 0); + assert_se(client); + + r = sd_dhcp_client_attach_event(client, e, 0); + assert_se(r >= 0); + + assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL); + assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL); + assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL); + + assert_se(sd_dhcp_client_set_index(client, 15) == 0); + assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL); + assert_se(sd_dhcp_client_set_index(client, -1) == 0); + + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_SUBNET_MASK) == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_ROUTER) == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_HOST_NAME) == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_DOMAIN_NAME) == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_DOMAIN_NAME_SERVER) + == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_NTP_SERVER) == -EEXIST); + + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_PAD) == -EINVAL); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_END) == -EINVAL); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_MESSAGE_TYPE) == -EINVAL); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_OVERLOAD) == -EINVAL); + assert_se(sd_dhcp_client_set_request_option(client, + DHCP_OPTION_PARAMETER_REQUEST_LIST) + == -EINVAL); + + assert_se(sd_dhcp_client_set_request_option(client, 33) == 0); + assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST); + assert_se(sd_dhcp_client_set_request_option(client, 44) == 0); + assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST); +} + +static uint16_t client_checksum(void *buf, int len) +{ + uint32_t sum; + uint16_t *check; + int i; + uint8_t *odd; + + sum = 0; + check = buf; + + for (i = 0; i < len / 2 ; i++) + sum += check[i]; + + if (len & 0x01) { + odd = buf; + sum += odd[len - 1]; + } + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +static void test_checksum(void) +{ + uint8_t buf[20] = { + 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff + }; + + if (verbose) + printf("* %s\n", __FUNCTION__); + + assert_se(client_checksum(&buf, 20) == be16toh(0x78ae)); +} + +static int check_options(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data) +{ + return 0; +} + +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, + const void *packet, size_t len) +{ + size_t size; + _cleanup_free_ DHCPPacket *discover; + uint16_t ip_check, udp_check; + + assert_se(s >= 0); + assert_se(packet); + + size = sizeof(DHCPPacket) + 4; + assert_se(len > size); + + discover = memdup(packet, len); + + assert_se(discover->ip.ttl == IPDEFTTL); + assert_se(discover->ip.protocol == IPPROTO_UDP); + assert_se(discover->ip.saddr == INADDR_ANY); + assert_se(discover->ip.daddr == INADDR_BROADCAST); + assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT)); + assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER)); + + ip_check = discover->ip.check; + + discover->ip.ttl = 0; + discover->ip.check = discover->udp.len; + + udp_check = ~client_checksum(&discover->ip.ttl, len - 8); + assert_se(udp_check == 0xffff); + + discover->ip.ttl = IPDEFTTL; + discover->ip.check = ip_check; + + ip_check = ~client_checksum(&discover->ip, sizeof(discover->ip)); + assert_se(ip_check == 0xffff); + + assert_se(discover->dhcp.xid); + assert_se(memcmp(discover->dhcp.chaddr, + &mac_addr.ether_addr_octet, 6) == 0); + + size = len - sizeof(struct iphdr) - sizeof(struct udphdr); + + assert_se(callback_recv); + callback_recv(size, &discover->dhcp); + + return 575; +} + +int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link) +{ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0) + return -errno; + + return test_fd[0]; +} + +int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port) +{ + return 0; +} + +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, + const void *packet, size_t len) +{ + return 0; +} + +static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) +{ + int res; + + res = dhcp_option_parse(dhcp, size, check_options, NULL); + assert_se(res == DHCP_DISCOVER); + + if (verbose) + printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid)); + + return 0; +} + +static void test_discover_message(sd_event *e) +{ + sd_dhcp_client *client; + int res, r; + + if (verbose) + printf("* %s\n", __FUNCTION__); + + r = sd_dhcp_client_new(&client); + assert_se(r >= 0); + assert_se(client); + + r = sd_dhcp_client_attach_event(client, e, 0); + assert_se(r >= 0); + + assert_se(sd_dhcp_client_set_index(client, 42) >= 0); + assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0); + + assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0); + + callback_recv = test_discover_message_verify; + + res = sd_dhcp_client_start(client); + + assert_se(res == 0 || res == -EINPROGRESS); + + sd_event_run(e, (uint64_t) -1); + + sd_dhcp_client_stop(client); + sd_dhcp_client_free(client); + + close(test_fd[0]); + close(test_fd[1]); + + callback_recv = NULL; +} + +static uint8_t test_addr_acq_offer[] = { + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01, + 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44, + 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, + 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf, + 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36, + 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00, + 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff, + 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f, + 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74, + 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static uint8_t test_addr_acq_ack[] = { + 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01, + 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44, + 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf, + 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36, + 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00, + 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff, + 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f, + 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74, + 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static void test_addr_acq_acquired(sd_dhcp_client *client, int event, + void *userdata) +{ + sd_event *e = userdata; + sd_dhcp_lease *lease; + struct in_addr addr; + + assert_se(client); + assert_se(event == DHCP_EVENT_IP_ACQUIRE); + + assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0); + assert_se(lease); + + assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0); + assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44], + sizeof(addr.s_addr)) == 0); + + assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0); + 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); + + if (verbose) + printf(" DHCP address acquired\n"); + + sd_event_exit(e, 0); +} + +static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) +{ + uint16_t udp_check = 0; + int res; + + res = dhcp_option_parse(request, size, check_options, NULL); + assert_se(res == DHCP_REQUEST); + assert_se(xid == request->xid); + + if (verbose) + printf(" recv DHCP Request 0x%08x\n", be32toh(xid)); + + memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check)); + memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid)); + memcpy(&test_addr_acq_ack[56], &mac_addr.ether_addr_octet, + ETHER_ADDR_LEN); + + callback_recv = NULL; + + res = write(test_fd[1], test_addr_acq_ack, + sizeof(test_addr_acq_ack)); + assert_se(res == sizeof(test_addr_acq_ack)); + + if (verbose) + printf(" send DHCP Ack\n"); + + return 0; +}; + +static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) +{ + uint16_t udp_check = 0; + int res; + + res = dhcp_option_parse(discover, size, check_options, NULL); + assert_se(res == DHCP_DISCOVER); + + xid = discover->xid; + + if (verbose) + printf(" recv DHCP Discover 0x%08x\n", be32toh(xid)); + + memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check)); + memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid)); + memcpy(&test_addr_acq_offer[56], &mac_addr.ether_addr_octet, + ETHER_ADDR_LEN); + + callback_recv = test_addr_acq_recv_request; + + res = write(test_fd[1], test_addr_acq_offer, + sizeof(test_addr_acq_offer)); + assert_se(res == sizeof(test_addr_acq_offer)); + + if (verbose) + printf(" send DHCP Offer\n"); + + return 0; +} + +static void test_addr_acq(sd_event *e) +{ + sd_dhcp_client *client; + int res, r; + + if (verbose) + printf("* %s\n", __FUNCTION__); + + r = sd_dhcp_client_new(&client); + assert_se(r >= 0); + assert_se(client); + + r = sd_dhcp_client_attach_event(client, e, 0); + assert_se(r >= 0); + + assert_se(sd_dhcp_client_set_index(client, 42) >= 0); + assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0); + + assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) + >= 0); + + callback_recv = test_addr_acq_recv_discover; + + res = sd_dhcp_client_start(client); + assert_se(res == 0 || res == -EINPROGRESS); + + sd_event_loop(e); + + sd_dhcp_client_set_callback(client, NULL, NULL); + sd_dhcp_client_stop(client); + sd_dhcp_client_free(client); + + close(test_fd[0]); + close(test_fd[1]); + + callback_recv = NULL; + xid = 0; +} + +int main(int argc, char *argv[]) +{ + sd_event *e; + + assert_se(sd_event_new(&e) >= 0); + + test_request_basic(e); + test_checksum(); + + test_discover_message(e); + test_addr_acq(e); + + return 0; +} diff --git a/src/libsystemd-dhcp/test-dhcp-option.c b/src/libsystemd-dhcp/test-dhcp-option.c new file mode 100644 index 0000000..8659fd5 --- /dev/null +++ b/src/libsystemd-dhcp/test-dhcp-option.c @@ -0,0 +1,378 @@ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" + +#include "dhcp-protocol.h" +#include "dhcp-internal.h" + +struct option_desc { + uint8_t sname[64]; + int snamelen; + uint8_t file[128]; + int filelen; + uint8_t options[128]; + int len; + bool success; + int filepos; + int snamepos; + int pos; +}; + +static bool verbose = false; + +static struct option_desc option_tests[] = { + { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, }, + { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0, + DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, }, + { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, }, + { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8, + 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01, + 0x04, 0xff, 0xff, 0xff, 0x00, 0x03, 0x04, 0xc0, + 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + 40, true, }, + { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER, + 42, 3, 0, 0, 0 }, 8, true, }, + { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, }, + + { {}, 0, + { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8, + { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, }, + + { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9, + { 222, 3, 1, 2, 3 }, 5, + { DHCP_OPTION_OVERLOAD, 1, + DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, }, +}; + +static const char *dhcp_type(int type) +{ + switch(type) { + case DHCP_DISCOVER: + return "DHCPDISCOVER"; + case DHCP_OFFER: + return "DHCPOFFER"; + case DHCP_REQUEST: + return "DHCPREQUEST"; + case DHCP_DECLINE: + return "DHCPDECLINE"; + case DHCP_ACK: + return "DHCPACK"; + case DHCP_NAK: + return "DHCPNAK"; + case DHCP_RELEASE: + return "DHCPRELEASE"; + default: + return "unknown"; + } +} + +static void test_invalid_buffer_length(void) +{ + DHCPMessage message; + + assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL); + assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage), NULL, NULL) + == -EINVAL); +} + +static void test_cookie(void) +{ + _cleanup_free_ DHCPMessage *message; + size_t len = sizeof(DHCPMessage) + 4; + uint8_t *opt; + + message = malloc0(len); + + opt = (uint8_t *)(message + 1); + opt[0] = 0xff; + + assert_se(dhcp_option_parse(message, len, NULL, NULL) == -EINVAL); + + opt[0] = 99; + opt[1] = 130; + opt[2] = 83; + opt[3] = 99; + + assert_se(dhcp_option_parse(message, len, NULL, NULL) == -ENOMSG); +} + +static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, + uint8_t *file, uint8_t filelen, + uint8_t *sname, uint8_t snamelen) +{ + DHCPMessage *message; + size_t len = sizeof(DHCPMessage) + 4 + optlen; + uint8_t *opt; + + message = malloc0(len); + opt = (uint8_t *)(message + 1); + + opt[0] = 99; + opt[1] = 130; + opt[2] = 83; + opt[3] = 99; + + if (options && optlen) + memcpy(&opt[4], options, optlen); + + if (file && filelen <= 128) + memcpy(&message->file, file, filelen); + + if (sname && snamelen <= 64) + memcpy(&message->sname, sname, snamelen); + + return message; +} + +static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) +{ + while (*descpos < *desclen) { + switch(descoption[*descpos]) { + case DHCP_OPTION_PAD: + *descpos += 1; + break; + + case DHCP_OPTION_MESSAGE_TYPE: + case DHCP_OPTION_OVERLOAD: + *descpos += 3; + break; + + default: + return; + } + } +} + +static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option, + void *user_data) +{ + struct option_desc *desc = user_data; + uint8_t *descoption = NULL; + int *desclen = NULL, *descpos = NULL; + uint8_t optcode = 0; + uint8_t optlen = 0; + uint8_t i; + + assert_se((!desc && !code && !len) || desc); + + if (!desc) + return -EINVAL; + + assert_se(code != DHCP_OPTION_PAD); + assert_se(code != DHCP_OPTION_END); + assert_se(code != DHCP_OPTION_MESSAGE_TYPE); + assert_se(code != DHCP_OPTION_OVERLOAD); + + while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) { + + if (desc->pos >= 0) { + descoption = &desc->options[0]; + desclen = &desc->len; + descpos = &desc->pos; + } else if (desc->filepos >= 0) { + descoption = &desc->file[0]; + desclen = &desc->filelen; + descpos = &desc->filepos; + } else if (desc->snamepos >= 0) { + descoption = &desc->sname[0]; + desclen = &desc->snamelen; + descpos = &desc->snamepos; + } + + assert_se(descoption && desclen && descpos); + + if (*desclen) + test_ignore_opts(descoption, descpos, desclen); + + if (*descpos < *desclen) + break; + + if (*descpos == *desclen) + *descpos = -1; + } + + assert_se(descpos); + assert_se(*descpos != -1); + + optcode = descoption[*descpos]; + optlen = descoption[*descpos + 1]; + + if (verbose) + printf("DHCP code %2d(%2d) len %2d(%2d) ", code, optcode, + len, optlen); + + assert_se(code == optcode); + assert_se(len == optlen); + + for (i = 0; i < len; i++) { + + if (verbose) + printf("0x%02x(0x%02x) ", option[i], + descoption[*descpos + 2 + i]); + + assert_se(option[i] == descoption[*descpos + 2 + i]); + } + + if (verbose) + printf("\n"); + + *descpos += optlen + 2; + + test_ignore_opts(descoption, descpos, desclen); + + if (desc->pos != -1 && desc->pos == desc->len) + desc->pos = -1; + + if (desc->filepos != -1 && desc->filepos == desc->filelen) + desc->filepos = -1; + + if (desc->snamepos != -1 && desc->snamepos == desc->snamelen) + desc->snamepos = -1; + + return 0; +} + +static void test_options(struct option_desc *desc) +{ + uint8_t *options = NULL; + uint8_t *file = NULL; + uint8_t *sname = NULL; + int optlen = 0; + int filelen = 0; + int snamelen = 0; + int buflen = 0; + _cleanup_free_ DHCPMessage *message; + int res; + + if (desc) { + file = &desc->file[0]; + filelen = desc->filelen; + if (!filelen) + desc->filepos = -1; + + sname = &desc->sname[0]; + snamelen = desc->snamelen; + if (!snamelen) + desc->snamepos = -1; + + options = &desc->options[0]; + optlen = desc->len; + desc->pos = 0; + } + message = create_message(options, optlen, file, filelen, + sname, snamelen); + + buflen = sizeof(DHCPMessage) + 4 + optlen; + + if (!desc) { + assert_se((res = dhcp_option_parse(message, buflen, + test_options_cb, + NULL)) == -ENOMSG); + } else if (desc->success) { + assert_se((res = dhcp_option_parse(message, buflen, + test_options_cb, + desc)) >= 0); + assert_se(desc->pos == -1 && desc->filepos == -1 && + desc->snamepos == -1); + } else + assert_se((res = dhcp_option_parse(message, buflen, + test_options_cb, + desc)) < 0); + + if (verbose) + printf("DHCP type %s\n", dhcp_type(res)); +} + +static uint8_t result[64] = { + 'A', 'B', 'C', 'D', +}; + +static uint8_t options[64] = { + 'A', 'B', 'C', 'D', + 160, 2, 0x11, 0x12, + 0, + 31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0, + 55, 3, 0x51, 0x52, 0x53, + 17, 7, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 255 +}; + +static void test_option_set(void) +{ + size_t len, oldlen; + int pos, i; + uint8_t *opt; + + assert_se(dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL); + + len = 0; + opt = &result[0]; + assert_se(dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL); + assert_se(opt == &result[0] && len == 0); + + assert_se(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD, + 0, NULL) == -ENOBUFS); + assert_se(opt == &result[0] && len == 0); + + opt = &result[4]; + len = 1; + assert_se(dhcp_option_append(&opt, &len, DHCP_OPTION_PAD, + 0, NULL) >= 0); + assert_se(opt == &result[5] && len == 0); + + pos = 4; + len = 60; + while (pos < 64 && options[pos] != DHCP_OPTION_END) { + opt = &result[pos]; + oldlen = len; + + assert_se(dhcp_option_append(&opt, &len, options[pos], + options[pos + 1], + &options[pos + 2]) >= 0); + + if (options[pos] == DHCP_OPTION_PAD) { + assert_se(opt == &result[pos + 1]); + assert_se(len == oldlen - 1); + pos++; + } else { + assert_se(opt == &result[pos + 2 + options[pos + 1]]); + assert_se(len == oldlen - 2 - options[pos + 1]); + pos += 2 + options[pos + 1]; + } + } + + for (i = 0; i < pos; i++) { + if (verbose) + printf("%2d: 0x%02x(0x%02x)\n", i, result[i], + options[i]); + assert_se(result[i] == options[i]); + } + + if (verbose) + printf ("\n"); +} + +int main(int argc, char *argv[]) +{ + unsigned int i; + + test_invalid_buffer_length(); + test_cookie(); + + test_options(NULL); + + for (i = 0; i < ELEMENTSOF(option_tests); i++) + test_options(&option_tests[i]); + + test_option_set(); + + return 0; +} diff --git a/src/libsystemd-login.sym b/src/libsystemd-login.sym deleted file mode 100644 index 0d51fa7..0000000 --- a/src/libsystemd-login.sym +++ /dev/null @@ -1,35 +0,0 @@ -/*** - This file is part of systemd. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -***/ - -/* Original symbols from systemd v31 */ - -LIBSYSTEMD_LOGIN_31 { -global: - sd_get_seats; - sd_get_sessions; - sd_get_uids; - sd_login_monitor_flush; - sd_login_monitor_get_fd; - sd_login_monitor_new; - sd_login_monitor_unref; - sd_pid_get_owner_uid; - sd_pid_get_session; - sd_seat_can_multi_session; - sd_seat_get_active; - sd_seat_get_sessions; - sd_session_get_seat; - sd_session_get_uid; - sd_session_is_active; - sd_uid_get_seats; - sd_uid_get_sessions; - sd_uid_get_state; - sd_uid_is_on_seat; -local: - *; -}; diff --git a/src/libsystemd/.gitignore b/src/libsystemd/.gitignore new file mode 100644 index 0000000..d48e1cd --- /dev/null +++ b/src/libsystemd/.gitignore @@ -0,0 +1,2 @@ +/libsystemd.sym +/libsystemd.pc diff --git a/src/libsystemd/Makefile b/src/libsystemd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/libsystemd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/libsystemd/libsystemd.pc.in b/src/libsystemd/libsystemd.pc.in new file mode 100644 index 0000000..e8f7950 --- /dev/null +++ b/src/libsystemd/libsystemd.pc.in @@ -0,0 +1,18 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Library +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd +Cflags: -I${includedir} diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 new file mode 100644 index 0000000..8d34615 --- /dev/null +++ b/src/libsystemd/libsystemd.sym.m4 @@ -0,0 +1,382 @@ +/*** + 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. +***/ + +LIBSYSTEMD_209 { +global: + /* sd-journal */ + sd_journal_print; + sd_journal_printv; + sd_journal_send; + sd_journal_sendv; + sd_journal_stream_fd; + sd_journal_open; + sd_journal_close; + sd_journal_previous; + sd_journal_next; + sd_journal_previous_skip; + sd_journal_next_skip; + sd_journal_get_realtime_usec; + sd_journal_get_monotonic_usec; + sd_journal_get_data; + sd_journal_enumerate_data; + sd_journal_restart_data; + sd_journal_add_match; + sd_journal_flush_matches; + sd_journal_seek_head; + sd_journal_seek_tail; + sd_journal_seek_monotonic_usec; + sd_journal_seek_realtime_usec; + sd_journal_seek_cursor; + sd_journal_get_cursor; + sd_journal_get_fd; + sd_journal_process; + sd_journal_print_with_location; + sd_journal_printv_with_location; + sd_journal_send_with_location; + sd_journal_sendv_with_location; + sd_journal_get_cutoff_realtime_usec; + sd_journal_get_cutoff_monotonic_usec; + sd_journal_wait; + sd_journal_open_directory; + sd_journal_add_disjunction; + sd_journal_perror; + sd_journal_perror_with_location; + sd_journal_get_usage; + sd_journal_test_cursor; + sd_journal_query_unique; + sd_journal_enumerate_unique; + sd_journal_restart_unique; + sd_journal_get_catalog; + sd_journal_get_catalog_for_message_id; + sd_journal_set_data_threshold; + sd_journal_get_data_threshold; + sd_journal_reliable_fd; + sd_journal_get_events; + sd_journal_get_timeout; + sd_journal_add_conjunction; + sd_journal_open_files; + sd_journal_open_container; + + /* sd-dameon */ + sd_booted; + sd_is_fifo; + sd_is_mq; + sd_is_socket; + sd_is_socket_inet; + sd_is_socket_unix; + sd_is_special; + sd_listen_fds; + sd_notify; + sd_notifyf; + sd_watchdog_enabled; + + /* sd-id128 */ + sd_id128_to_string; + sd_id128_from_string; + sd_id128_randomize; + sd_id128_get_machine; + sd_id128_get_boot; + + /* sd-login */ + sd_get_seats; + sd_get_sessions; + sd_get_uids; + sd_login_monitor_flush; + sd_login_monitor_get_fd; + sd_login_monitor_new; + sd_login_monitor_unref; + sd_pid_get_owner_uid; + sd_pid_get_session; + sd_seat_can_multi_session; + sd_seat_get_active; + sd_seat_get_sessions; + sd_session_get_seat; + sd_session_get_uid; + sd_session_is_active; + sd_uid_get_seats; + sd_uid_get_sessions; + sd_uid_get_state; + sd_uid_is_on_seat; + sd_pid_get_unit; + sd_session_get_service; + sd_session_get_type; + sd_session_get_class; + sd_session_get_display; + sd_session_get_state; + sd_seat_can_tty; + sd_seat_can_graphical; + sd_session_get_tty; + sd_login_monitor_get_events; + sd_login_monitor_get_timeout; + sd_pid_get_user_unit; + sd_pid_get_machine_name; + sd_get_machine_names; + sd_pid_get_slice; + sd_session_get_vt; + sd_session_is_remote; + sd_session_get_remote_user; + sd_session_get_remote_host; + +m4_ifdef(`ENABLE_KDBUS', + /* sd-bus */ + sd_bus_default; + sd_bus_default_user; + sd_bus_default_system; + sd_bus_open; + sd_bus_open_user; + sd_bus_open_system; + sd_bus_open_system_remote; + sd_bus_open_system_container; + sd_bus_new; + sd_bus_set_address; + sd_bus_set_fd; + sd_bus_set_exec; + sd_bus_set_bus_client; + sd_bus_set_server; + sd_bus_set_anonymous; + sd_bus_set_trusted; + sd_bus_set_name; + sd_bus_negotiate_fds; + sd_bus_negotiate_timestamp; + sd_bus_negotiate_creds; + sd_bus_start; + sd_bus_close; + sd_bus_try_close; + sd_bus_ref; + sd_bus_unref; + sd_bus_is_open; + sd_bus_can_send; + sd_bus_get_server_id; + sd_bus_get_peer_creds; + sd_bus_get_name; + sd_bus_send; + sd_bus_send_to; + sd_bus_call; + sd_bus_call_async; + sd_bus_call_async_cancel; + sd_bus_get_fd; + sd_bus_get_events; + sd_bus_get_timeout; + sd_bus_process; + sd_bus_process_priority; + sd_bus_wait; + sd_bus_flush; + sd_bus_get_current; + sd_bus_get_tid; + sd_bus_attach_event; + sd_bus_detach_event; + sd_bus_get_event; + sd_bus_add_filter; + sd_bus_remove_filter; + sd_bus_add_match; + sd_bus_remove_match; + sd_bus_add_object; + sd_bus_remove_object; + sd_bus_add_fallback; + sd_bus_remove_fallback; + sd_bus_add_object_vtable; + sd_bus_remove_object_vtable; + sd_bus_add_fallback_vtable; + sd_bus_remove_fallback_vtable; + sd_bus_add_node_enumerator; + sd_bus_remove_node_enumerator; + sd_bus_add_object_manager; + sd_bus_remove_object_manager; + sd_bus_message_new_signal; + sd_bus_message_new_method_call; + sd_bus_message_new_method_return; + sd_bus_message_new_method_error; + sd_bus_message_new_method_errorf; + sd_bus_message_new_method_errno; + sd_bus_message_new_method_errnof; + sd_bus_message_ref; + sd_bus_message_unref; + sd_bus_message_get_bus; + sd_bus_message_get_type; + sd_bus_message_get_cookie; + sd_bus_message_get_reply_cookie; + sd_bus_message_get_expect_reply; + sd_bus_message_get_auto_start; + sd_bus_message_get_priority; + sd_bus_message_get_signature; + sd_bus_message_get_path; + sd_bus_message_get_interface; + sd_bus_message_get_member; + sd_bus_message_get_destination; + sd_bus_message_get_sender; + sd_bus_message_get_error; + sd_bus_message_get_errno; + sd_bus_message_get_monotonic_usec; + sd_bus_message_get_realtime_usec; + sd_bus_message_get_seqnum; + sd_bus_message_get_creds; + sd_bus_message_is_signal; + sd_bus_message_is_method_call; + sd_bus_message_is_method_error; + sd_bus_message_set_expect_reply; + sd_bus_message_set_auto_start; + sd_bus_message_set_destination; + sd_bus_message_set_priority; + sd_bus_message_append; + sd_bus_message_append_basic; + sd_bus_message_append_array; + sd_bus_message_append_array_space; + sd_bus_message_append_array_iovec; + sd_bus_message_append_array_memfd; + sd_bus_message_append_string_space; + sd_bus_message_append_string_iovec; + sd_bus_message_append_string_memfd; + sd_bus_message_append_strv; + sd_bus_message_open_container; + sd_bus_message_close_container; + sd_bus_message_copy; + sd_bus_message_read; + sd_bus_message_read_basic; + sd_bus_message_read_array; + sd_bus_message_read_strv; + sd_bus_message_skip; + sd_bus_message_enter_container; + sd_bus_message_exit_container; + sd_bus_message_peek_type; + sd_bus_message_verify_type; + sd_bus_message_at_end; + sd_bus_message_rewind; + sd_bus_get_unique_name; + sd_bus_request_name; + sd_bus_release_name; + sd_bus_list_names; + sd_bus_get_owner; + sd_bus_get_owner_machine_id; + sd_bus_call_method; + sd_bus_get_property; + sd_bus_get_property_trivial; + sd_bus_get_property_string; + sd_bus_get_property_strv; + sd_bus_set_property; + sd_bus_reply_method_return; + sd_bus_reply_method_error; + sd_bus_reply_method_errorf; + sd_bus_reply_method_errno; + sd_bus_reply_method_errnof; + sd_bus_emit_signal; + sd_bus_emit_properties_changed_strv; + sd_bus_emit_properties_changed; + sd_bus_emit_interfaces_added_strv; + sd_bus_emit_interfaces_added; + sd_bus_emit_interfaces_removed_strv; + sd_bus_emit_interfaces_removed; + sd_bus_query_sender_creds; + sd_bus_creds_new_from_pid; + sd_bus_creds_ref; + sd_bus_creds_unref; + sd_bus_creds_get_mask; + sd_bus_creds_get_uid; + sd_bus_creds_get_gid; + sd_bus_creds_get_pid; + sd_bus_creds_get_pid_starttime; + sd_bus_creds_get_tid; + sd_bus_creds_get_comm; + sd_bus_creds_get_tid_comm; + sd_bus_creds_get_exe; + sd_bus_creds_get_cmdline; + sd_bus_creds_get_cgroup; + sd_bus_creds_get_unit; + sd_bus_creds_get_user_unit; + sd_bus_creds_get_slice; + sd_bus_creds_get_session; + sd_bus_creds_get_owner_uid; + sd_bus_creds_has_effective_cap; + sd_bus_creds_has_permitted_cap; + sd_bus_creds_has_inheritable_cap; + sd_bus_creds_has_bounding_cap; + sd_bus_creds_get_selinux_context; + sd_bus_creds_get_audit_session_id; + sd_bus_creds_get_audit_login_uid; + sd_bus_creds_get_unique_name; + sd_bus_creds_get_well_known_names; + sd_bus_creds_get_connection_name; + sd_bus_error_free; + sd_bus_error_set; + sd_bus_error_setf; + sd_bus_error_set_const; + sd_bus_error_set_errno; + sd_bus_error_set_errnof; + sd_bus_error_get_errno; + sd_bus_error_copy; + sd_bus_error_is_set; + sd_bus_error_has_name; + sd_bus_label_escape; + sd_bus_label_unescape; + + /* sd-memfd */ + sd_memfd_new; + sd_memfd_new_and_map; + sd_memfd_free; + sd_memfd_get_fd; + sd_memfd_get_file; + sd_memfd_dup_fd; + sd_memfd_map; + sd_memfd_set_sealed; + sd_memfd_get_sealed; + sd_memfd_get_size; + sd_memfd_set_size; + sd_memfd_get_name; + + /* sd-event */ + sd_event_default; + sd_event_new; + sd_event_ref; + sd_event_unref; + sd_event_add_io; + sd_event_add_monotonic; + sd_event_add_realtime; + sd_event_add_signal; + sd_event_add_child; + sd_event_add_defer; + sd_event_add_exit; + sd_event_run; + sd_event_loop; + sd_event_exit; + sd_event_get_state; + sd_event_get_tid; + sd_event_get_exit_code; + sd_event_get_now_realtime; + sd_event_get_now_monotonic; + sd_event_set_watchdog; + sd_event_get_watchdog; + sd_event_source_ref; + sd_event_source_unref; + sd_event_source_set_prepare; + sd_event_source_get_pending; + sd_event_source_get_priority; + sd_event_source_set_priority; + sd_event_source_get_enabled; + sd_event_source_set_enabled; + sd_event_source_get_userdata; + sd_event_source_set_userdata; + sd_event_source_get_io_fd; + sd_event_source_set_io_fd; + sd_event_source_get_io_events; + sd_event_source_set_io_events; + sd_event_source_get_io_revents; + sd_event_source_get_time; + sd_event_source_set_time; + sd_event_source_set_time_accuracy; + sd_event_source_get_time_accuracy; + sd_event_source_get_signal; + sd_event_source_get_child_pid; + sd_event_source_get_event; + + /* sd-utf8 */ + sd_utf8_is_valid; + sd_ascii_is_valid; +) +local: + *; +}; diff --git a/src/libsystemd/sd-bus/.gitignore b/src/libsystemd/sd-bus/.gitignore new file mode 100644 index 0000000..d32542e --- /dev/null +++ b/src/libsystemd/sd-bus/.gitignore @@ -0,0 +1 @@ +/bus-error-mapping.c diff --git a/src/libsystemd/sd-bus/DIFFERENCES b/src/libsystemd/sd-bus/DIFFERENCES new file mode 100644 index 0000000..fd7506b --- /dev/null +++ b/src/libsystemd/sd-bus/DIFFERENCES @@ -0,0 +1,28 @@ +Known differences between dbus1 and kdbus: + +- NameAcquired/NameLost is gone entirely on kdbus backends if + libsystemd is used. It is still added in by systemd-bus-proxyd + for old dbus1 clients, and it is available if libsystemd is used + against the classic dbus1 daemon. If you want to write compatible + code with libsystem-bus you need to explicitly subscribe to + NameOwnerChanged signals and just ignore NameAcquired/NameLost + +- Applications have to deal with spurious signals they didn't expect, + due to the probabilistic bloom filters. They need to handle this + anyway, given that any client can send anything to arbitrary clients + anyway, even in dbus1, so not much changes. + +- clients of the system bus when kdbus is used must roll their own + security. Only legacy dbus1 clients get the old XML policy enforced, + which is implemented by systemd-bus-proxyd. + +- Serial numbers of synthesized messages are always (uint32_t) -1. + +- The org.freedesktop.DBus "driver" service is not special on + kdbus. It is a bus activated service like any other with its own + unique name. + +- NameOwnerChanged is a synthetic message, generated locally and not + by the driver. + +- There's no standard per-session bus anymore. Only a per-user bus. diff --git a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION new file mode 100644 index 0000000..5dffc25 --- /dev/null +++ b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION @@ -0,0 +1,63 @@ +How we use GVariant for serializing D-Bus messages +-------------------------------------------------- + +We stay as close to the original dbus1 framing as possible. dbus1 has +the following framing: + + 1. A fixed header of "yyyyuu" + 2. Additional header fields of "a(yv)" + 3. Padding with NUL bytes to pad up to next 8byte boundary + 4. The body + +Note that the body is not padded at the end, the complete message +hence might have a non-aligned size. Reading multiple messages at once +will hence result in possibly unaligned messages in memory. + +The header consists of the following: + + y Endianness, 'l' or 'B' + y Message Type + y Flags + y Protocol version, '1' + u Length of the body, i.e. the length of part 4 above + u Serial number + + = 12 bytes + +When using GVariant we keep the basic structure in place, only +slightly extend the header, and define protocol version '2'. The new +header: + + y Endianness, 'l' or 'B' + y Message Type + y Flags + y Protocol version, '2' + u Length of the body, i.e. the length of part 4 above + u Serial number + u Length of the additional header fields array + + = 16 bytes + +This has the nice benefit that the beginning of the additional header +fields array is aligned to an 8 byte boundary. Also, in dbus1 +marshalling arrays start with a length value of 32bit, which means in +both dbus1 and gvariant marshallings the size of the header fields +array will be at the same location between bytes 12 and 16. To +visualize that: + + 0 4 8 12 16 + Common: | E | T | F | V | Body Length | Serial | Fields Length | + + dbus1: | ... (as above) ... | Fields array ... + + gvariant: | ... (as above) ... | Fields Length | Fields array ... + +And that's already it. + +Note: on kdbus only native endian messages marshalled in gvariant may + be sent. If a client receives a message in non-native endianness + or in dbus1 marshalling it shall ignore the message. + +Note: The GVariant "MAYBE" type is not supported, so that messages can + be fully converted forth and back between dbus1 and gvariant + representations. diff --git a/src/libsystemd/sd-bus/Makefile b/src/libsystemd/sd-bus/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-bus/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-bus/PORTING-DBUS1 b/src/libsystemd/sd-bus/PORTING-DBUS1 new file mode 100644 index 0000000..90d184b --- /dev/null +++ b/src/libsystemd/sd-bus/PORTING-DBUS1 @@ -0,0 +1,575 @@ +A few hints on supporting kdbus as backend in your favorite D-Bus library. + +~~~ + +Before you read this, have a look at the DIFFERENCES and +GVARIANT_SERIALIZATION texts you find in the same directory where you +found this. + +We invite you to port your favorite D-Bus protocol implementation +over to kdbus. However, there are a couple of complexities +involved. On kdbus we only speak GVariant marshaling, kdbus clients +ignore traffic in dbus1 marshaling. Thus, you need to add a second, +GVariant compatible marshaler to your library first. + +After you have done that: here's the basic principle how kdbus works: + +You connect to a bus by opening its bus node in /dev/kdbus/. All +buses have a device node there, it starts with a numeric UID of the +owner of the bus, followed by a dash and a string identifying the +bus. The system bus is thus called /dev/kdbus/0-system, and for user +buses the device node is /dev/kdbus/1000-user (if 1000 is your user +id). + +(Before we proceed, please always keep a copy of libsystemd next +to you, ultimately that's where the details are, this document simply +is a rough overview to help you grok things.) + +CONNECTING + +To connect to a bus, simply open() its device node and issue the +KDBUS_CMD_HELLO call. That's it. Now you are connected. Do not send +Hello messages or so (as you would on dbus1), that does not exist for +kdbus. + +The structure you pass to the ioctl will contain a couple of +parameters that you need to know, to operate on the bus. + +There are two flags fields, one indicating features of the kdbus +kernel side ("conn_flags"), the other one ("bus_flags") indicating +features of the bus owner (i.e. systemd). Both flags fields are 64bit +in width. + +When calling into the ioctl, you need to place your own supported +feature bits into these fields. This tells the kernel about the +features you support. When the ioctl returns, it will contain the +features the kernel supports. + +If any of the higher 32bit are set on the two flags fields and your +client does not know what they mean, it must disconnect. The upper +32bit are used to indicate "incompatible" feature additions on the bus +system, the lower 32bit indicate "compatible" feature additions. A +client that does not support a "compatible" feature addition can go on +communicating with the bus, however a client that does not support an +"incompatible" feature must not proceed with the connection. When a +client encountes such an "incompatible" feature it should immediately +try the next bus address configured in the bus address string. + +The hello structure also contains another flags field "attach_flags" +which indicates metadata that is optionally attached to all incoming +messages. You probably want to set KDBUS_ATTACH_NAMES unconditionally +in it. This has the effect that all well-known names of a sender are +attached to all incoming messages. You need this information to +implement matches that match on a message sender name correctly. Of +course, you should only request the attachment of as little metadata +fields as you need. + +The kernel will return in the "id" field your unique id. This is a +simple numeric value. For compatibility with classic dbus1 simply +format this as string and prefix ":0.". + +The kernel will also return the bloom filter size and bloom filter +hash function number used for the signal broadcast bloom filter (see +below). + +The kernel will also return the bus ID of the bus in a 128bit field. + +The pool size field specifies the size of the memory mapped buffer. +After the calling the hello ioctl, you should memory map the kdbus +fd. In this memory mapped region, the kernel will place all your incoming +messages. + +SENDING MESSAGES + +Use the MSG_SEND ioctl to send a message to another peer. The ioctl +takes a structure that contains a variety of fields: + +The flags field corresponds closely to the old dbus1 message header +flags field, though the DONT_EXPECT_REPLY field got inverted into +EXPECT_REPLY. + +The dst_id/src_id field contains the unique id of the destination and +the sender. The sender field is overridden by the kernel usually, hence +you shouldn't fill it in. The destination field can also take the +special value KDBUS_DST_ID_BROADCAST for broadcast messages. For +messages intended to a well-known name set the field to +KDBUS_DST_ID_NAME, and attach the name in a special "items" entry to +the message (see below). + +The payload field indicates the payload. For all dbus traffic it +should carry the value 0x4442757344427573ULL. (Which encodes +'DBusDBus'). + +The cookie field corresponds with the "serial" field of classic +dbus1. We simply renamed it here (and extended it to 64bit) since we +didn't want to imply the monotonicity of the assignment the way the +word "serial" indicates it. + +When sending a message that expects a reply, you need to set the +EXPECT_REPLY flag in the message flag field. In this case you should +also fill out the "timeout_ns" value which indicates the timeout in +nsec for this call. If the peer does not respond in this time you will +get a notification of a timeout. Note that this is also used for +security purposes: a single reply messages is only allowed through the +bus as long as the timeout has not ended. With this timeout value you +hence "open a time window" in which the peer might respond to your +request and the policy allows the response to go through. + +When sending a message that is a reply, you need to fill in the +cookie_reply field, which is similar to the reply_serial field of +dbus1. Note that a message cannot have EXPECT_REPLY and a reply_serial +at the same time! + +This pretty much explains the ioctl header. The actual payload of the +data is now referenced in additional items that are attached to this +ioctl header structure at the end. When sending a message, you attach +items of the type PAYLOAD_VEC, PAYLOAD_MEMFD, FDS, BLOOM, DST_NAME to +it: + + KDBUS_ITEM_PAYLOAD_VEC: contains a pointer + length pair for + referencing arbitrary user memory. This is how you reference most + of your data. It's a lot like the good old iovec structure of glibc. + + KDBUS_ITEM_PAYLOAD_MEMFD: for large data blocks it is preferable + to send prepared "memfds" (see below) over. This item contains an + fd for a memfd plus a size. + + KDBUS_ITEM_PAYLOAD_FDS: for sending over fds attach an item of this + type with an array of fds. + + KDBUS_ITEM_BLOOM: the calculated bloom filter of this message, only + for undirected (broadcast) message. + + KDBUS_DST_NAME: for messages that are directed to a well-known name + (instead of a unique name), this item contains the well-known name + field. + +A single message may consists of no, one or more payload items of type +PAYLOAD_VEC or PAYLOAD_MEMFD. D-Bus protocol implementations should +treat them as a single block that just happens to be split up into +multiple items. Some restrictions apply however: + + The message header in its entirety must be contained in a single + PAYLOAD_VEC item. + + You may only split your message up right in front of each GVariant + contained in the payload, as well is immediately before framing of a + Gvariant, as well after as any padding bytes if there are any. The + padding bytes must be wholly contained in the preceding + PAYLOAD_VEC/PAYLOAD_MEMFD item. You may not split up simple types + nor arrays of trivial types. The latter is necessary to allow APIs + to return direct pointers to linear chunks of fixed size trivial + arrays. Examples: The simple types "u", "s", "t" have to be in the + same payload item. The array of simple types "ay", "ai" have to be + fully in contained in the same payload item. For an array "as" or + "a(si)" the only restriction however is to keep each string + individually in an uninterrupted item, to keep the framing of each + element and the array in a single uninterrupted item, however the + various strings might end up in different items. + +Note again, that splitting up messages into separate items is up to the +implementation. Also note that the kdbus kernel side might merge +separate items if it deems this to be useful. However, the order in +which items are contained in the message is left untouched. + +PAYLOAD_MEMFD items allow zero-copy data transfer (see below regarding +the memfd concept). Note however that the overhead of mapping these +makes them relatively expensive, and only worth the trouble for memory +blocks > 512K (this value appears to be quite universal across +architectures, as we tested). Thus we recommend sending PAYLOAD_VEC +items over for small messages and restore to PAYLOAD_MEMFD items for +messages > 512K. Since while building up the message you might not +know yet whether it will grow beyond this boundary a good approach is +to simply build the message unconditionally in a memfd +object. However, when the message is sealed to be sent away check for +the size limit. If the size of the message is < 512K, then simply send +the data as PAYLOAD_VEC and reuse the memfd. If it is >= 512K, seal +the memfd and send it as PAYLOAD_MEMFD, and allocate a new memfd for +the next message. + +RECEIVING MESSAGES + +Use the MSG_RECV ioctl to read a message from kdbus. This will return +an offset into the pool memory map, relative to its beginning. + +The received message structure more or less follows the structure of +the message originally sent. However, certain changes have been +made. In the header the src_id field will be filled in. + +The payload items might have gotten merged and PAYLOAD_VEC items are +not used. Instead, you will only find PAYLOAD_OFF and PAYLOAD_MEMFD +items. The former contain an offset and size into your memory mapped +pool where you find the payload. + +If during the HELLO ioctl you asked for getting metadata attached to +your message, you will find additional KDBUS_ITEM_CREDS, +KDBUS_ITEM_PID_COMM, KDBUS_ITEM_TID_COMM, KDBUS_ITEM_TIMESTAMP, +KDBUS_ITEM_EXE, KDBUS_ITEM_CMDLINE, KDBUS_ITEM_CGROUP, +KDBUS_ITEM_CAPS, KDBUS_ITEM_SECLABEL, KDBUS_ITEM_AUDIT items that +contain this metadata. This metadata will be gathered from the sender +at the point in time it sends the message. This information is +uncached, and since it is appended by the kernel, trustable. The +KDBUS_ITEM_SECLABEL item usually contains the SELinux security label, +if it is used. + +After processing the message you need to call the KDBUS_CMD_FREE +ioctl, which releases the message from the pool, and allows the kernel +to store another message there. Note that the memory used by the pool +is ordinary anonymous, swappable memory that is backed by tmpfs. Hence +there is no need to copy the message out of it quickly, instead you +can just leave it there as long as you need it and release it via the +FREE ioctl only after that's done. + +BLOOM FILTERS + +The kernel does not understand dbus marshaling, it will not look into +the message payload. To allow clients to subscribe to specific subsets +of the broadcast matches we employ bloom filters. + +When broadcasting messages, a bloom filter needs to be attached to the +message in a KDBUS_ITEM_BLOOM item (and only for broadcasting +messages!). If you don't know what bloom filters are, read up now on +Wikipedia. In short: they are a very efficient way how to +probabilistically check whether a certain word is contained in a +vocabulary. It knows no false negatives, but it does know false +positives. + +The parameters for the bloom filters that need to be included in +broadcast message is communicated to userspace as part of the hello +response structure (see above). By default it has the parameters m=512 +(bits in the filter), k=8 (nr of hash functions). Note however, that +this is subject to change in later versions, and userspace +implementations must be capable of handling m values between at least +m=8 and m=2^32, and k values between at least k=1 and k=32. The +underlying hash function is SipHash-2-4. It is used with a number of +constant (yet originally randomly generated) 128bit hash keys, more +specifically: + + b9,66,0b,f0,46,70,47,c1,88,75,c4,9c,54,b9,bd,15, + aa,a1,54,a2,e0,71,4b,39,bf,e1,dd,2e,9f,c5,4a,3b, + 63,fd,ae,be,cd,82,48,12,a1,6e,41,26,cb,fa,a0,c8, + 23,be,45,29,32,d2,46,2d,82,03,52,28,fe,37,17,f5, + 56,3b,bf,ee,5a,4f,43,39,af,aa,94,08,df,f0,fc,10, + 31,80,c8,73,c7,ea,46,d3,aa,25,75,0f,9e,4c,09,29, + 7d,f7,18,4b,7b,a4,44,d5,85,3c,06,e0,65,53,96,6d, + f2,77,e9,6f,93,b5,4e,71,9a,0c,34,88,39,25,bf,35 + +When calculating the first bit index into the bloom filter, the +SipHash-2-4 hash value is calculated for the input data and the first +16 bytes of the array above as hash key. Of the resulting 8 bytes of +output, as many full bytes are taken for the bit index as necessary, +starting from the output's first byte. For the second bit index the +same hash value is used, continuing with the next unused output byte, +and so on. Each time the bytes returned by the hash function are +depleted it is recalculated with the next 16 byte hash key from the +array above and the same input data. + +For each message to send across the bus we populate the bloom filter +with all possible matchable strings. If a client then wants to +subscribe to messages of this type, it simply tells the kernel to test +its own calculated bit mask against the bloom filter of each message. + +More specifically, the following strings are added to the bloom filter +of each message that is broadcasted: + + The string "interface:" suffixed by the interface name + + The string "member:" suffixed by the member name + + The string "path:" suffixed by the path name + + The string "path-slash-prefix:" suffixed with the path name, and + also all prefixes of the path name (cut off at "/"), also prefixed + with "path-slash-prefix". + + The string "message-type:" suffixed with the strings "signal", + "method_call", "error" or "method_return" for the respective message + type of the message. + + If the first argument of the message is a string, "arg0:" suffixed + with the first argument. + + If the first argument of the message is a string, "arg0-dot-prefix" + suffixed with the first argument, and also all prefixes of the + argument (cut off at "."), also prefixed with "arg0-dot-prefix". + + If the first argument of the message is a string, + "arg0-slash-prefix" suffixed with the first argument, and also all + prefixes of the argument (cut off at "/"), also prefixed with + "arg0-slash-prefix". + + Similar for all further arguments that are strings up to 63, for the + arguments and their "dot" and "slash" prefixes. On the first + argument that is not a string, addition to the bloom filter should be + stopped however. + +(Note that the bloom filter does not contain sender nor receiver +names!) + +When a client wants to subscribe to messages matching a certain +expression, it should calculate the bloom mask following the same +algorithm. The kernel will then simply test the mask against the +attached bloom filters. + +Note that bloom filters are probabilistic, which means that clients +might get messages they did not expect. Your bus protocol +implementation must be capable of dealing with these unexpected +messages (which it needs to anyway, given that transfers are +relatively unrestricted on kdbus and people can send you all kinds of +non-sense). + +If a client connects to a bus whose bloom filter metrics (i.e. filter +size and number of hash functions) are outside of the range the client +supports it must immediately disconnect and continue connection with +the next bus address of the bus connection string. + +INSTALLING MATCHES + +To install matches for broadcast messages, use the KDBUS_CMD_ADD_MATCH +ioctl. It takes a structure that contains an encoded match expression, +and that is followed by one or more items, which are combined in an +AND way. (Meaning: a message is matched exactly when all items +attached to the original ioctl struct match). + +To match against other user messages add a KDBUS_ITEM_BLOOM item in +the match (see above). Note that the bloom filter does not include +matches to the sender names. To additionally check against sender +names, use the KDBUS_ITEM_ID (for unique id matches) and +KDBUS_ITEM_NAME (for well-known name matches) item types. + +To match against kernel generated messages (see below) you should add +items of the same type as the kernel messages include, +i.e. KDBUS_ITEM_NAME_ADD, KDBUS_ITEM_NAME_REMOVE, +KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD, KDBUS_ITEM_ID_REMOVE and +fill them out. Note however, that you have some wildcards in this +case, for example the .id field of KDBUS_ITEM_ADD/KDBUS_ITEM_REMOVE +structures may be set to 0 to match against any id addition/removal. + +Note that dbus match strings do no map 1:1 to these ioctl() calls. In +many cases (where the match string is "underspecified") you might need +to issue up to six different ioctl() calls for the same match. For +example, the empty match (which matches against all messages), would +translate into one KDBUS_ITEM_BLOOM ioctl, one KDBUS_ITEM_NAME_ADD, +one KDBUS_ITEM_NAME_CHANGE, one KDBUS_ITEM_NAME_REMOVE, one +KDBUS_ITEM_ID_ADD and one KDBUS_ITEM_ID_REMOVE. + +When creating a match, you may attach a "cookie" value to them, which +is used for deleting this match again. The cookie can be selected freely +by the client. When issuing KDBUS_CMD_REMOVE_MATCH, simply pass the +same cookie as before and all matches matching the same "cookie" value +will be removed. This is particularly handy for the case where multiple +ioctl()s are added for a single match strings. + +MEMFDS + +The "memfd" concept is used for zero-copy data transfers (see +above). memfds are file descriptors to memory chunks of arbitrary +sizes. If you have a memfd you can mmap() it to get access to the data +it contains or write to it. They are comparable to file descriptors to +unlinked files on a tmpfs, or to anonymous memory that one may refer +to with an fd. They have one particular property: they can be +"sealed". A memfd that is "sealed" is protected from alteration. Only +memfds that are currently not mapped and to which a single fd refers +may be sealed (they may also be unsealed in that case). + +The concept of "sealing" makes memfds useful for using them as +transport for kdbus messages: only when the receiver knows that the +message it has received cannot change while looking at, it can safely +parse it without having to copy it to a safe memory area. memfds can also +be reused in multiple messages. A sender may send the same memfd to +multiple peers, and since it is sealed, it can be sure that the receiver +will not be able to modify it. "Sealing" hence provides both sides of +a transaction with the guarantee that the data stays constant and is +reusable. + +memfds are a generic concept that can be used outside of the immediate +kdbus usecase. You can send them across AF_UNIX sockets too, sealed or +unsealed. In kdbus themselves, they can be used to send zero-copy +payloads, but may also be sent as normal fds. + +memfds are allocated with the KDBUS_CMD_MEMFD_NEW ioctl. After allocation, +simply memory map them and write to them. To set their size, use +KDBUS_CMD_MEMFD_SIZE_SET. Note that memfds will be increased in size +automatically if you touch previously unallocated pages. However, the +size will only be increased in multiples of the page size in that +case. Thus, in almost all cases, an explicit KDBUS_CMD_MEMFD_SIZE_SET +is necessary, since it allows setting memfd sizes in finer +granularity. To seal a memfd use the KDBUS_CMD_MEMFD_SEAL_SET ioctl +call. It will only succeed if the caller has the only fd reference to +the memfd open, and if the memfd is currently unmapped. + +If memfds are shared, keep in mind that the file pointer used by +write/read/seek is shared too, only pread/pwrite are safe to use +in that case. + +memfds may be sent across kdbus via KDBUS_ITEM_PAYLOAD_MEMFD items +attached to messages. If this is done, the data included in the memfd +is considered part of the payload stream of a message, and are treated +the same way as KDBUS_ITEM_PAYLOAD_VEC by the receiving side. It is +possible to interleave KDBUS_ITEM_PAYLOAD_MEMFD and +KDBUS_ITEM_PAYLOAD_VEC items freely, by the reader they will be +considered a single stream of bytes in the order these items appear in +the message, that just happens to be split up at various places +(regarding rules how they may be split up, see above). The kernel will +refuse taking KDBUS_ITEM_PAYLOAD_MEMFD items that refer to memfds that +are not sealed. + +Note that sealed memfds may be unsealed again if they are not mapped +you have the only fd reference to them. + +Alternatively to sending memfds as KDBUS_ITEM_PAYLOAD_MEMFD items +(where they are just a part of the payload stream of a message) you can +also simply attach any memfd to a message using +KDBUS_ITEM_PAYLOAD_FDS. In this case, the memfd contents is not +considered part of the payload stream of the message, but simply fds +like any other, that happen to be attached to the message. + +MESSAGES FROM THE KERNEL + +A couple of messages previously generated by the dbus1 bus driver are +now generated by the kernel. Since the kernel does not understand the +payload marshaling, they are generated by the kernel in a different +format. This is indicated with the "payload type" field of the +messages set to 0. Library implementations should take these messages +and synthesize traditional driver messages for them on reception. + +More specifically: + + Instead of the NameOwnerChanged, NameLost, NameAcquired signals + there are kernel messages containing KDBUS_ITEM_NAME_ADD, + KDBUS_ITEM_NAME_REMOVE, KDBUS_ITEM_NAME_CHANGE, KDBUS_ITEM_ID_ADD, + KDBUS_ITEM_ID_REMOVE items are generated (each message will contain + exactly one of these items). Note that in libsystemd we have + obsoleted NameLost/NameAcquired messages, since they are entirely + redundant to NameOwnerChanged. This library will hence only + synthesize NameOwnerChanged messages from these kernel messages, + and never generate NameLost/NameAcquired. If your library needs to + stay compatible to the old dbus1 userspace, you possibly might need + to synthesize both a NameOwnerChanged and NameLost/NameAcquired + message from the same kernel message. + + When a method call times out, a KDBUS_ITEM_REPLY_TIMEOUT message is + generated. This should be synthesized into a method error reply + message to the original call. + + When a method call fails because the peer terminated the connection + before responding, a KDBUS_ITEM_REPLY_DEAD message is + generated. Similarly, it should be synthesized into a method error + reply message. + +For synthesized messages we recommend setting the cookie field to +(uint32_t) -1 (and not (uint64_t) -1!), so that the cookie is not 0 +(which the dbus1 spec does not allow), but clearly recognizable as +synthetic. + +Note that the KDBUS_ITEM_NAME_XYZ messages will actually inform you +about all kinds of names, including activatable ones. Classic dbus1 +NameOwnerChanged messages OTOH are only generated when a name is +really acquired on the bus and not just simply activatable. This means +you must explicitly check for the case where an activatable name +becomes acquired or an acquired name is lost and returns to be +activatable. + +NAME REGISTRY + +To acquire names on the bus, use the KDBUS_CMD_NAME_ACQUIRE ioctl(). It +takes a flags field similar to dbus1's RequestName() bus driver call, +however the NO_QUEUE flag got inverted into a QUEUE flag instead. + +To release a previously acquired name use the KDBUS_CMD_NAME_RELEASE +ioctl(). + +To list acquired names use the KDBUS_CMD_CONN_INFO ioctl. It may be +used to list unique names, well known names as well as activatable +names and clients currently queuing for ownership of a well-known +name. The ioctl will return an offset into the memory pool. After +reading all the data you need, you need to release this via the +KDBUS_CMD_FREE ioctl(), similar how you release a received message. + +CREDENTIALS + +kdbus can optionally attach various kinds of metadata about the sender at +the point of time of sending ("credentials") to messages, on request +of the receiver. This is both supported on directed and undirected +(broadcast) messages. The metadata to attach is selected at time of +the HELLO ioctl of the receiver via a flags field (see above). Note +that clients must be able to handle that messages contain more +metadata than they asked for themselves, to simplify implementation of +broadcasting in the kernel. The receiver should not rely on this data +to be around though, even though it will be correct if it happens to +be attached. In order to avoid programming errors in applications, we +recommend though not passing this data on to clients that did not +explicitly ask for it. + +Credentials may also be queried for a well-known or unique name. Use +the KDBUS_CMD_CONN_INFO for this. It will return an offset to the pool +area again, which will contain the same credential items as messages +have attached. Note that when issuing the ioctl, you can select a +different set of credentials to gather, than what was originally requested +for being attached to incoming messages. + +Credentials are always specific to the sender's domain that was +current at the time of sending, and of the process that opened the +bus connection at the time of opening it. Note that this latter data +is cached! + +POLICY + +The kernel enforces only very limited policy on names. It will not do +access filtering by userspace payload, and thus not by interface or +method name. + +This ultimately means that most fine-grained policy enforcement needs +to be done by the receiving process. We recommend using PolicyKit for +any more complex checks. However, libraries should make simple static +policy decisions regarding privileged/unprivileged method calls +easy. We recommend doing this by enabling KDBUS_ATTACH_CAPS and +KDBUS_ATTACH_CREDS for incoming messages, and then discerning client +access by some capability, or if sender and receiver UIDs match. + +BUS ADDRESSES + +When connecting to kdbus use the "kernel:" protocol prefix in DBus +address strings. The device node path is encoded in its "path=" +parameter. + +Client libraries should use the following connection string when +connecting to the system bus: + + kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket + +This will ensure that kdbus is preferred over the legacy AF_UNIX +socket, but compatibility is kept. For the user bus use: + + kernel:path=/dev/kdbus/$UID-user/bus;unix:path=$XDG_RUNTIME_DIR/bus + +With $UID replaced by the callers numer user ID, and $XDG_RUNTIME_DIR +following the XDG basedir spec. + +Of course the $DBUS_SYSTEM_BUS_ADDRESS and $DBUS_SESSION_BUS_ADDRESS +variables should still take precedence. + +DBUS SERVICE FILES + +Activatable services for kdbus may not use classic dbus1 service +activation files. Instead, programs should drop in native systemd +.service and .busname unit files, so that they are treated uniformly +with other types of units and activation of the system. + +Note that this results in a major difference to classic dbus1: +activatable bus names can be established at any time in the boot process. +This is unlike dbus1 where activatable names are unconditionally available +as long as dbus-daemon is running. Being able to control when +activatable names are established is essential to allow usage of kdbus +during early boot and in initrds, without the risk of triggering +services too early. + +DISCLAIMER + +This all is so far just the status quo. We are putting this together, because +we are quite confident that further API changes will be smaller, but +to make this very clear: this is all subject to change, still! + +We invite you to port over your favorite dbus library to this new +scheme, but please be prepared to make minor changes when we still +change these interfaces! diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c new file mode 100644 index 0000000..e154296 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-bloom.c @@ -0,0 +1,149 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "siphash24.h" +#include "bus-bloom.h" + +static inline void set_bit(uint64_t filter[], unsigned long b) { + filter[b >> 6] |= 1ULL << (b & 63); +} + +static const sd_id128_t hash_keys[] = { + SD_ID128_ARRAY(b9,66,0b,f0,46,70,47,c1,88,75,c4,9c,54,b9,bd,15), + SD_ID128_ARRAY(aa,a1,54,a2,e0,71,4b,39,bf,e1,dd,2e,9f,c5,4a,3b), + SD_ID128_ARRAY(63,fd,ae,be,cd,82,48,12,a1,6e,41,26,cb,fa,a0,c8), + SD_ID128_ARRAY(23,be,45,29,32,d2,46,2d,82,03,52,28,fe,37,17,f5), + SD_ID128_ARRAY(56,3b,bf,ee,5a,4f,43,39,af,aa,94,08,df,f0,fc,10), + SD_ID128_ARRAY(31,80,c8,73,c7,ea,46,d3,aa,25,75,0f,9e,4c,09,29), + SD_ID128_ARRAY(7d,f7,18,4b,7b,a4,44,d5,85,3c,06,e0,65,53,96,6d), + SD_ID128_ARRAY(f2,77,e9,6f,93,b5,4e,71,9a,0c,34,88,39,25,bf,35), +}; + +static void bloom_add_data( + uint64_t filter[], /* The filter bits */ + size_t size, /* Size of the filter in bytes */ + unsigned k, /* Number of hash functions */ + const void *data, /* Data to hash */ + size_t n) { /* Size of data to hash in bytes */ + + uint8_t h[8]; + uint64_t m; + unsigned w, i, c = 0; + + assert(size > 0); + assert(k > 0); + + /* Determine bits in filter */ + m = size * 8; + + /* Determine how many bytes we need to generate a bit index 0..m for this filter */ + w = (u64log2(m) + 7) / 8; + + assert(w <= sizeof(uint64_t)); + + /* Make sure we have enough hash keys to generate m * k bits + * of hash value. Note that SipHash24 generates 64 bits of + * hash value for each 128 bits of hash key. */ + assert(k * w <= ELEMENTSOF(hash_keys) * 8); + + for (i = 0; i < k; i++) { + uint64_t p = 0; + unsigned d; + + for (d = 0; d < w; d++) { + if (c <= 0) { + siphash24(h, data, n, hash_keys[i++].bytes); + c += 8; + } + + p = (p << 8ULL) | (uint64_t) h[8 - c]; + c--; + } + + p &= m - 1; + set_bit(filter, p); + } + + /* log_debug("bloom: adding <%.*s>", (int) n, (char*) data); */ +} + +void bloom_add_pair(uint64_t filter[], size_t size, unsigned k, const char *a, const char *b) { + size_t n; + char *c; + + assert(filter); + assert(a); + assert(b); + + n = strlen(a) + 1 + strlen(b); + c = alloca(n + 1); + strcpy(stpcpy(stpcpy(c, a), ":"), b); + + bloom_add_data(filter, size, k, c, n); +} + +void bloom_add_prefixes(uint64_t filter[], size_t size, unsigned k, const char *a, const char *b, char sep) { + size_t n; + char *c, *p; + + assert(filter); + assert(a); + assert(b); + + n = strlen(a) + 1 + strlen(b); + c = alloca(n + 1); + + p = stpcpy(stpcpy(c, a), ":"); + strcpy(p, b); + + for (;;) { + char *e; + + e = strrchr(p, sep); + if (!e || e == p) + break; + + *e = 0; + bloom_add_data(filter, size, k, c, e - c); + } +} + +bool bloom_validate_parameters(size_t size, unsigned k) { + uint64_t m; + unsigned w; + + if (size <= 0) + return false; + + if (k <= 0) + return false; + + m = size * 8; + w = (u64log2(m) + 7) / 8; + if (w > sizeof(uint64_t)) + return false; + + if (k * w > ELEMENTSOF(hash_keys) * 8) + return false; + + return true; +} diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h new file mode 100644 index 0000000..0dad5db --- /dev/null +++ b/src/libsystemd/sd-bus/bus-bloom.h @@ -0,0 +1,43 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +/* + * Our default bloom filter has the following parameters: + * + * m=512 (bits in the filter) + * k=8 (hash functions) + * + * We use SipHash24 as hash function with a number of (originally + * randomized) but fixed hash keys. + * + */ + +#define DEFAULT_BLOOM_SIZE (512/8) /* m: filter size */ +#define DEFAULT_BLOOM_N_HASH 8 /* k: number of hash functions */ + +void bloom_add_pair(uint64_t filter[], size_t size, unsigned n_hash, const char *a, const char *b); +void bloom_add_prefixes(uint64_t filter[], size_t size, unsigned n_hash, const char *a, const char *b, char sep); + +bool bloom_validate_parameters(size_t size, unsigned n_hash); diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c new file mode 100644 index 0000000..d330363 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-container.c @@ -0,0 +1,241 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "fileio.h" +#include "bus-internal.h" +#include "bus-socket.h" +#include "bus-container.h" + +int bus_container_connect_socket(sd_bus *b) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + pid_t leader, child; + siginfo_t si; + int r; + + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + + r = container_get_leader(b->machine, &leader); + if (r < 0) + return r; + + r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd); + if (r < 0) + return r; + + b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (b->input_fd < 0) + return -errno; + + b->output_fd = b->input_fd; + + bus_socket_setup(b); + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + pid_t grandchild; + + r = namespace_enter(pidnsfd, mntnsfd, rootfd); + if (r < 0) + _exit(255); + + /* We just changed PID namespace, however it will only + * take effect on the children we now fork. Hence, + * let's fork another time, and connect from this + * grandchild, so that SO_PEERCRED of our connection + * comes from a process from within the container, and + * not outside of it */ + + grandchild = fork(); + if (grandchild < 0) + _exit(255); + + if (grandchild == 0) { + + r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); + if (r < 0) { + if (errno == EINPROGRESS) + _exit(1); + + _exit(255); + } + + _exit(EXIT_SUCCESS); + } + + r = wait_for_terminate(grandchild, &si); + if (r < 0) + _exit(255); + + if (si.si_code != CLD_EXITED) + _exit(255); + + _exit(si.si_status); + } + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + + if (si.si_code != CLD_EXITED) + return -EIO; + + if (si.si_status == 1) + return 1; + + if (si.si_status != EXIT_SUCCESS) + return -EIO; + + return bus_socket_start_auth(b); +} + +int bus_container_connect_kernel(sd_bus *b) { + _cleanup_close_pipe_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + pid_t leader, child; + siginfo_t si; + int r; + _cleanup_close_ int fd = -1; + + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + + r = container_get_leader(b->machine, &leader); + if (r < 0) + return r; + + r = namespace_open(leader, &pidnsfd, &mntnsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + pid_t grandchild; + + close_nointr_nofail(pair[0]); + pair[0] = -1; + + r = namespace_enter(pidnsfd, mntnsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + /* We just changed PID namespace, however it will only + * take effect on the children we now fork. Hence, + * let's fork another time, and connect from this + * grandchild, so that kdbus only sees the credentials + * of this process which comes from within the + * container, and not outside of it */ + + grandchild = fork(); + if (grandchild < 0) + _exit(EXIT_FAILURE); + + if (grandchild == 0) { + + fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + _exit(EXIT_FAILURE); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + r = wait_for_terminate(grandchild, &si); + if (r < 0) + _exit(EXIT_FAILURE); + + if (si.si_code != CLD_EXITED) + _exit(EXIT_FAILURE); + + _exit(si.si_status); + } + + close_nointr_nofail(pair[1]); + pair[1] = -1; + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + + if (si.si_code != CLD_EXITED) + return -EIO; + + if (si.si_status != EXIT_SUCCESS) + return -EIO; + + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; + + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (n_fds != 1) { + close_many(fds, n_fds); + return -EIO; + } + + fd = fds[0]; + } + + b->input_fd = b->output_fd = fd; + fd = -1; + + return bus_kernel_take_fd(b); +} diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h new file mode 100644 index 0000000..c6f757a --- /dev/null +++ b/src/libsystemd/sd-bus/bus-container.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +int bus_container_connect_socket(sd_bus *b); +int bus_container_connect_kernel(sd_bus *b); diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c new file mode 100644 index 0000000..22b95d5 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-control.c @@ -0,0 +1,1231 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + +#include +#include + +#include "strv.h" +#include "sd-bus.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-control.h" +#include "bus-bloom.h" +#include "bus-util.h" +#include "cgroup-util.h" + +_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { + int r; + + assert_return(bus, -EINVAL); + assert_return(unique, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = bus_ensure_running(bus); + if (r < 0) + return r; + + *unique = bus->unique_name; + return 0; +} + +static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) { + struct kdbus_cmd_name *n; + size_t size, l; + int r; + + assert(bus); + assert(name); + + l = strlen(name); + size = offsetof(struct kdbus_cmd_name, name) + l + 1; + n = alloca0(size); + n->size = size; + kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags); + memcpy(n->name, name, l+1); + +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); +#endif + + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n); + if (r < 0) + return -errno; + + if (n->flags & KDBUS_NAME_IN_QUEUE) + return 0; + + return 1; +} + +static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + uint32_t ret, param = 0; + int r; + + assert(bus); + assert(name); + + if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) + param |= BUS_NAME_ALLOW_REPLACEMENT; + if (flags & SD_BUS_NAME_REPLACE_EXISTING) + param |= BUS_NAME_REPLACE_EXISTING; + if (!(flags & SD_BUS_NAME_QUEUE)) + param |= BUS_NAME_DO_NOT_QUEUE; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "RequestName", + NULL, + &reply, + "su", + name, + param); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &ret); + if (r < 0) + return r; + + if (ret == BUS_NAME_ALREADY_OWNER) + return -EALREADY; + else if (ret == BUS_NAME_EXISTS) + return -EEXIST; + else if (ret == BUS_NAME_IN_QUEUE) + return 0; + else if (ret == BUS_NAME_PRIMARY_OWNER) + return 1; + + return -EIO; +} + +_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) { + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(bus->bus_client, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL); + assert_return(service_name_is_valid(name), -EINVAL); + assert_return(name[0] != ':', -EINVAL); + + if (bus->is_kernel) + return bus_request_name_kernel(bus, name, flags); + else + return bus_request_name_dbus1(bus, name, flags); +} + +static int bus_release_name_kernel(sd_bus *bus, const char *name) { + struct kdbus_cmd_name *n; + size_t l; + int r; + + assert(bus); + assert(name); + + l = strlen(name); + n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1); + n->size = offsetof(struct kdbus_cmd_name, name) + l + 1; + memcpy(n->name, name, l+1); + +#ifdef HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(n, n->size); +#endif + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n); + if (r < 0) + return -errno; + + return n->flags; +} + +static int bus_release_name_dbus1(sd_bus *bus, const char *name) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + uint32_t ret; + int r; + + assert(bus); + assert(name); + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ReleaseName", + NULL, + &reply, + "s", + name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &ret); + if (r < 0) + return r; + if (ret == BUS_NAME_NON_EXISTENT) + return -ESRCH; + if (ret == BUS_NAME_NOT_OWNER) + return -EADDRINUSE; + if (ret == BUS_NAME_RELEASED) + return 0; + + return -EINVAL; +} + +_public_ int sd_bus_release_name(sd_bus *bus, const char *name) { + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(bus->bus_client, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(service_name_is_valid(name), -EINVAL); + assert_return(name[0] != ':', -EINVAL); + + if (bus->is_kernel) + return bus_release_name_kernel(bus, name); + else + return bus_release_name_dbus1(bus, name); +} + +static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { + struct kdbus_cmd_name_list cmd = {}; + struct kdbus_name_list *name_list; + struct kdbus_cmd_name *name; + uint64_t previous_id = 0; + int r; + + /* Caller will free half-constructed list on failure... */ + + cmd.flags = flags; + + r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd); + if (r < 0) + return -errno; + + name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); + + KDBUS_ITEM_FOREACH(name, name_list, names) { + + if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != previous_id) { + char *n; + + if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) + return -ENOMEM; + + r = strv_push(x, n); + if (r < 0) { + free(n); + return -ENOMEM; + } + + previous_id = name->owner_id; + } + + if (name->size > sizeof(*name) && service_name_is_valid(name->name)) { + r = strv_extend(x, name->name); + if (r < 0) + return -ENOMEM; + } + } + + r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset); + if (r < 0) + return -errno; + + return 0; +} + +static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) { + _cleanup_strv_free_ char **x = NULL, **y = NULL; + int r; + + if (acquired) { + r = kernel_get_list(bus, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES, &x); + if (r < 0) + return r; + } + + if (activatable) { + r = kernel_get_list(bus, KDBUS_NAME_LIST_ACTIVATORS, &y); + if (r < 0) + return r; + + *activatable = y; + y = NULL; + } + + if (acquired) { + *acquired = x; + x = NULL; + } + + return 0; +} + +static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **x = NULL, **y = NULL; + int r; + + if (acquired) { + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListNames", + NULL, + &reply, + NULL); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(reply, &x); + if (r < 0) + return r; + + reply = sd_bus_message_unref(reply); + } + + if (activatable) { + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListActivatableNames", + NULL, + &reply, + NULL); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(reply, &y); + if (r < 0) + return r; + + *activatable = y; + y = NULL; + } + + if (acquired) { + *acquired = x; + x = NULL; + } + + return 0; +} + +_public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable) { + assert_return(bus, -EINVAL); + assert_return(acquired || activatable, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (bus->is_kernel) + return bus_list_names_kernel(bus, acquired, activatable); + else + return bus_list_names_dbus1(bus, acquired, activatable); +} + +static int bus_get_owner_kdbus( + sd_bus *bus, + const char *name, + uint64_t mask, + sd_bus_creds **creds) { + + _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + struct kdbus_cmd_conn_info *cmd; + struct kdbus_conn_info *conn_info; + struct kdbus_item *item; + size_t size; + uint64_t m, id; + int r; + + r = bus_kernel_parse_unique_name(name, &id); + if (r < 0) + return r; + if (r > 0) { + size = offsetof(struct kdbus_cmd_conn_info, name); + cmd = alloca0(size); + cmd->id = id; + } else { + size = offsetof(struct kdbus_cmd_conn_info, name) + strlen(name) + 1; + cmd = alloca0(size); + strcpy(cmd->name, name); + } + + cmd->size = size; + kdbus_translate_attach_flags(mask, (uint64_t*) &cmd->flags); + + r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd); + if (r < 0) + return -errno; + + conn_info = (struct kdbus_conn_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset); + + /* Non-activated names are considered not available */ + if (conn_info->flags & KDBUS_HELLO_ACTIVATOR) + return name[0] == ':' ? -ENXIO : -ENOENT; + + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + if (mask & SD_BUS_CREDS_UNIQUE_NAME) { + if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) + return -ENOMEM; + + c->mask |= SD_BUS_CREDS_UNIQUE_NAME; + } + + KDBUS_ITEM_FOREACH(item, conn_info, items) { + + switch (item->type) { + + case KDBUS_ITEM_CREDS: + m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask; + + if (m) { + c->uid = (uid_t) item->creds.uid; + c->pid = (pid_t) item->creds.pid; + c->gid = (gid_t) item->creds.gid; + c->mask |= m; + } + + if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) { + c->tid = (pid_t) item->creds.tid; + c->mask |= SD_BUS_CREDS_TID; + } + + if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) { + c->pid_starttime = item->creds.starttime; + c->mask |= SD_BUS_CREDS_PID_STARTTIME; + } + + break; + + case KDBUS_ITEM_PID_COMM: + if (mask & SD_BUS_CREDS_COMM) { + c->comm = strdup(item->str); + if (!c->comm) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_COMM; + } + break; + + case KDBUS_ITEM_TID_COMM: + if (mask & SD_BUS_CREDS_TID_COMM) { + c->tid_comm = strdup(item->str); + if (!c->tid_comm) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_TID_COMM; + } + break; + + case KDBUS_ITEM_EXE: + if (mask & SD_BUS_CREDS_EXE) { + c->exe = strdup(item->str); + if (!c->exe) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_EXE; + } + break; + + case KDBUS_ITEM_CMDLINE: + if (mask & SD_BUS_CREDS_CMDLINE) { + c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE; + c->cmdline = memdup(item->data, c->cmdline_size); + if (!c->cmdline) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_CMDLINE; + } + break; + + case KDBUS_ITEM_CGROUP: + m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT | + SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE | + SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask; + + if (m) { + c->cgroup = strdup(item->str); + if (!c->cgroup) { + r = -ENOMEM; + goto fail; + } + + if (!bus->cgroup_root) { + r = cg_get_root_path(&bus->cgroup_root); + if (r < 0) + goto fail; + } + + c->cgroup_root = strdup(bus->cgroup_root); + if (!c->cgroup_root) { + r = -ENOMEM; + goto fail; + } + + c->mask |= m; + } + break; + + case KDBUS_ITEM_CAPS: + m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | + SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask; + + if (m) { + c->capability_size = item->size - KDBUS_ITEM_HEADER_SIZE; + c->capability = memdup(item->data, c->capability_size); + if (!c->capability) { + r = -ENOMEM; + goto fail; + } + + c->mask |= m; + } + break; + + case KDBUS_ITEM_SECLABEL: + if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { + c->label = strdup(item->str); + if (!c->label) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + break; + + case KDBUS_ITEM_AUDIT: + m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask; + + if (m) { + c->audit_session_id = item->audit.sessionid; + c->audit_login_uid = item->audit.loginuid; + c->mask |= m; + } + break; + + case KDBUS_ITEM_NAME: + if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) { + r = strv_extend(&c->well_known_names, item->name.name); + if (r < 0) + goto fail; + + c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES; + } + break; + + case KDBUS_ITEM_CONN_NAME: + if ((mask & SD_BUS_CREDS_CONNECTION_NAME)) { + c->conn_name = strdup(item->str); + if (!c->conn_name) { + r = -ENOMEM; + goto fail; + } + + c->mask |= SD_BUS_CREDS_CONNECTION_NAME; + } + break; + } + } + + if (creds) { + *creds = c; + c = NULL; + } + + r = 0; + +fail: + ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd->offset); + return r; +} + +static int bus_get_owner_dbus1( + sd_bus *bus, + const char *name, + uint64_t mask, + sd_bus_creds **creds) { + + _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL; + _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + const char *unique = NULL; + pid_t pid = 0; + int r; + + /* Only query the owner if the caller wants to know it or if + * the caller just wants to check whether a name exists */ + if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) { + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetNameOwner", + NULL, + &reply_unique, + "s", + name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply_unique, "s", &unique); + if (r < 0) + return r; + } + + if (mask != 0) { + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + if ((mask & SD_BUS_CREDS_UNIQUE_NAME) && unique) { + c->unique_name = strdup(unique); + if (!c->unique_name) + return -ENOMEM; + + c->mask |= SD_BUS_CREDS_UNIQUE_NAME; + } + + if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID| + SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| + SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| + SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| + SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) { + uint32_t u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + NULL, + &reply, + "s", + unique ? unique : name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; + + pid = u; + if (mask & SD_BUS_CREDS_PID) { + c->pid = u; + c->mask |= SD_BUS_CREDS_PID; + } + + reply = sd_bus_message_unref(reply); + } + + if (mask & SD_BUS_CREDS_UID) { + uint32_t u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixUser", + NULL, + &reply, + "s", + unique ? unique : name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; + + c->uid = u; + c->mask |= SD_BUS_CREDS_UID; + + reply = sd_bus_message_unref(reply); + } + + if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { + const void *p = NULL; + size_t sz = 0; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionSELinuxSecurityContext", + NULL, + &reply, + "s", + unique ? unique : name); + if (r < 0) + return r; + + r = sd_bus_message_read_array(reply, 'y', &p, &sz); + if (r < 0) + return r; + + c->label = strndup(p, sz); + if (!c->label) + return -ENOMEM; + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + + r = bus_creds_add_more(c, mask, pid, 0); + if (r < 0) + return r; + } + + if (creds) { + *creds = c; + c = NULL; + } + + return 0; +} + +_public_ int sd_bus_get_owner( + sd_bus *bus, + const char *name, + uint64_t mask, + sd_bus_creds **creds) { + + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP); + assert_return(mask == 0 || creds, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(service_name_is_valid(name), -EINVAL); + assert_return(bus->bus_client, -ENODATA); + + if (bus->is_kernel) + return bus_get_owner_kdbus(bus, name, mask, creds); + else + return bus_get_owner_dbus1(bus, name, mask, creds); +} + +static int add_name_change_match(sd_bus *bus, + uint64_t cookie, + const char *name, + const char *old_owner, + const char *new_owner) { + + uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0; + int is_name_id = -1, r; + struct kdbus_item *item; + + assert(bus); + + /* If we encounter a match that could match against + * NameOwnerChanged messages, then we need to create + * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and + * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly + * multiple if the match is underspecified. + * + * The NameOwnerChanged signals take three parameters with + * unique or well-known names, but only some forms actually + * exist: + * + * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD + * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE + * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE + * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD + * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE + * + * For the latter two the two unique names must be identical. + * + * */ + + if (name) { + is_name_id = bus_kernel_parse_unique_name(name, &name_id); + if (is_name_id < 0) + return 0; + } + + if (!isempty(old_owner)) { + r = bus_kernel_parse_unique_name(old_owner, &old_owner_id); + if (r < 0) + return 0; + if (r == 0) + return 0; + if (is_name_id > 0 && old_owner_id != name_id) + return 0; + } else + old_owner_id = KDBUS_MATCH_ID_ANY; + + if (!isempty(new_owner)) { + r = bus_kernel_parse_unique_name(new_owner, &new_owner_id); + if (r < 0) + return r; + if (r == 0) + return 0; + if (is_name_id > 0 && new_owner_id != name_id) + return 0; + } else + new_owner_id = KDBUS_MATCH_ID_ANY; + + if (is_name_id <= 0) { + struct kdbus_cmd_match *m; + size_t sz, l; + + /* If the name argument is missing or is a well-known + * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} + * matches for it */ + + l = name ? strlen(name) + 1 : 0; + + sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + + offsetof(struct kdbus_item, name_change) + + offsetof(struct kdbus_notify_name_change, name) + + l); + + m = alloca0(sz); + m->size = sz; + m->cookie = cookie; + + item = m->items; + item->size = + offsetof(struct kdbus_item, name_change) + + offsetof(struct kdbus_notify_name_change, name) + + l; + + item->name_change.old.id = old_owner_id; + item->name_change.new.id = new_owner_id; + + if (name) + memcpy(item->name_change.name, name, l); + + /* If the old name is unset or empty, then + * this can match against added names */ + if (!old_owner || old_owner[0] == 0) { + item->type = KDBUS_ITEM_NAME_ADD; + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + } + + /* If the new name is unset or empty, then + * this can match against removed names */ + if (!new_owner || new_owner[0] == 0) { + item->type = KDBUS_ITEM_NAME_REMOVE; + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + } + + /* The CHANGE match we need in either case, because + * what is reported as a name change by the kernel + * might just be an owner change between starter and + * normal clients. For userspace such a change should + * be considered a removal/addition, hence let's + * subscribe to this unconditionally. */ + item->type = KDBUS_ITEM_NAME_CHANGE; + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + } + + if (is_name_id != 0) { + struct kdbus_cmd_match *m; + uint64_t sz; + + /* If the name argument is missing or is a unique + * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches + * for it */ + + sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) + + offsetof(struct kdbus_item, id_change) + + sizeof(struct kdbus_notify_id_change)); + + m = alloca0(sz); + m->size = sz; + m->cookie = cookie; + + item = m->items; + item->size = + offsetof(struct kdbus_item, id_change) + + sizeof(struct kdbus_notify_id_change); + item->id_change.id = name_id; + + /* If the old name is unset or empty, then this can + * match against added ids */ + if (!old_owner || old_owner[0] == 0) { + item->type = KDBUS_ITEM_ID_ADD; + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + } + + /* If thew new name is unset or empty, then this can + * match against removed ids */ + if (!new_owner || new_owner[0] == 0) { + item->type = KDBUS_ITEM_ID_REMOVE; + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + } + } + + return 0; +} + +int bus_add_match_internal_kernel( + sd_bus *bus, + uint64_t id, + struct bus_match_component *components, + unsigned n_components, + uint64_t cookie) { + + struct kdbus_cmd_match *m; + struct kdbus_item *item; + uint64_t *bloom; + size_t sz; + const char *sender = NULL; + size_t sender_length = 0; + uint64_t src_id = KDBUS_MATCH_ID_ANY; + bool using_bloom = false; + unsigned i; + bool matches_name_change = true; + const char *name_change_arg[3] = {}; + int r; + + assert(bus); + + bloom = alloca0(bus->bloom_size); + + sz = ALIGN8(offsetof(struct kdbus_cmd_match, items)); + + for (i = 0; i < n_components; i++) { + struct bus_match_component *c = &components[i]; + + switch (c->type) { + + case BUS_MATCH_SENDER: + if (!streq(c->value_str, "org.freedesktop.DBus")) + matches_name_change = false; + + r = bus_kernel_parse_unique_name(c->value_str, &src_id); + if (r < 0) + return r; + else if (r > 0) + sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); + else { + sender = c->value_str; + sender_length = strlen(sender); + sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1); + } + + break; + + case BUS_MATCH_MESSAGE_TYPE: + if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL) + matches_name_change = false; + + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8)); + using_bloom = true; + break; + + case BUS_MATCH_INTERFACE: + if (!streq(c->value_str, "org.freedesktop.DBus")) + matches_name_change = false; + + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str); + using_bloom = true; + break; + + case BUS_MATCH_MEMBER: + if (!streq(c->value_str, "NameOwnerChanged")) + matches_name_change = false; + + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str); + using_bloom = true; + break; + + case BUS_MATCH_PATH: + if (!streq(c->value_str, "/org/freedesktop/DBus")) + matches_name_change = false; + + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str); + using_bloom = true; + break; + + case BUS_MATCH_PATH_NAMESPACE: + if (!streq(c->value_str, "/")) { + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str); + using_bloom = true; + } + break; + + case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: { + char buf[sizeof("arg")-1 + 2 + 1]; + + if (c->type - BUS_MATCH_ARG < 3) + name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str; + + snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: { + char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; + + snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { + char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; + + snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_DESTINATION: + /* The bloom filter does not include + the destination, since it is only + available for broadcast messages + which do not carry a destination + since they are undirected. */ + break; + + case BUS_MATCH_ROOT: + case BUS_MATCH_VALUE: + case BUS_MATCH_LEAF: + case _BUS_MATCH_NODE_TYPE_MAX: + case _BUS_MATCH_NODE_TYPE_INVALID: + assert_not_reached("Invalid match type?"); + } + } + + if (using_bloom) + sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size); + + m = alloca0(sz); + m->size = sz; + m->cookie = cookie; + m->owner_id = id; + + item = m->items; + + if (src_id != KDBUS_MATCH_ID_ANY) { + item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); + item->type = KDBUS_ITEM_ID; + item->id = src_id; + item = KDBUS_ITEM_NEXT(item); + } + + if (using_bloom) { + item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size; + item->type = KDBUS_ITEM_BLOOM_MASK; + memcpy(item->data64, bloom, bus->bloom_size); + item = KDBUS_ITEM_NEXT(item); + } + + if (sender) { + item->size = offsetof(struct kdbus_item, str) + sender_length + 1; + item->type = KDBUS_ITEM_NAME; + memcpy(item->str, sender, sender_length + 1); + } + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); + if (r < 0) + return -errno; + + if (matches_name_change) { + + /* If this match could theoretically match + * NameOwnerChanged messages, we need to + * install a second non-bloom filter explitly + * for it */ + + r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]); + if (r < 0) + return r; + } + + return 0; +} + +static int bus_add_match_internal_dbus1( + sd_bus *bus, + const char *match) { + + assert(bus); + assert(match); + + return sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "AddMatch", + NULL, + NULL, + "s", + match); +} + +int bus_add_match_internal( + sd_bus *bus, + const char *match, + struct bus_match_component *components, + unsigned n_components, + uint64_t cookie) { + + assert(bus); + assert(match); + + if (bus->is_kernel) + return bus_add_match_internal_kernel(bus, 0, components, n_components, cookie); + else + return bus_add_match_internal_dbus1(bus, match); +} + +int bus_remove_match_internal_kernel( + sd_bus *bus, + uint64_t id, + uint64_t cookie) { + + struct kdbus_cmd_match m; + int r; + + assert(bus); + + zero(m); + m.size = offsetof(struct kdbus_cmd_match, items); + m.cookie = cookie; + m.owner_id = id; + + r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m); + if (r < 0) + return -errno; + + return 0; +} + +static int bus_remove_match_internal_dbus1( + sd_bus *bus, + const char *match) { + + assert(bus); + assert(match); + + return sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "RemoveMatch", + NULL, + NULL, + "s", + match); +} + +int bus_remove_match_internal( + sd_bus *bus, + const char *match, + uint64_t cookie) { + + assert(bus); + assert(match); + + if (bus->is_kernel) + return bus_remove_match_internal_kernel(bus, 0, cookie); + else + return bus_remove_match_internal_dbus1(bus, match); +} + +_public_ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + const char *mid; + int r; + + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(machine, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(service_name_is_valid(name), -EINVAL); + + if (streq_ptr(name, bus->unique_name)) + return sd_id128_get_machine(machine); + + r = sd_bus_message_new_method_call( + bus, + &m, + name, + "/", + "org.freedesktop.DBus.Peer", + "GetMachineId"); + if (r < 0) + return r; + + r = sd_bus_message_set_auto_start(m, false); + if (r < 0) + return r; + + r = sd_bus_call(bus, m, 0, NULL, &reply); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "s", &mid); + if (r < 0) + return r; + + return sd_id128_from_string(mid, machine); +} diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h new file mode 100644 index 0000000..b610bef --- /dev/null +++ b/src/libsystemd/sd-bus/bus-control.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie); +int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie); + +int bus_add_match_internal_kernel(sd_bus *bus, uint64_t id, struct bus_match_component *components, unsigned n_components, uint64_t cookie); +int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t id, uint64_t cookie); diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c new file mode 100644 index 0000000..6e02ad3 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -0,0 +1,442 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-signature.h" +#include "bus-util.h" +#include "bus-type.h" + +_public_ int sd_bus_emit_signal( + sd_bus *bus, + const char *path, + const char *interface, + const char *member, + const char *types, ...) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_message_new_signal(bus, &m, path, interface, member); + if (r < 0) + return r; + + if (!isempty(types)) { + va_list ap; + + va_start(ap, types); + r = bus_message_append_ap(m, types, ap); + va_end(ap); + if (r < 0) + return r; + } + + return sd_bus_send(bus, m, NULL); +} + +_public_ int sd_bus_call_method( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + sd_bus_message **reply, + const char *types, ...) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member); + if (r < 0) + return r; + + if (!isempty(types)) { + va_list ap; + + va_start(ap, types); + r = bus_message_append_ap(m, types, ap); + va_end(ap); + if (r < 0) + return r; + } + + return sd_bus_call(bus, m, 0, error, reply); +} + +_public_ int sd_bus_reply_method_return( + sd_bus_message *call, + const char *types, ...) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + + r = sd_bus_message_new_method_return(call, &m); + if (r < 0) + return r; + + if (!isempty(types)) { + va_list ap; + + va_start(ap, types); + r = bus_message_append_ap(m, types, ap); + va_end(ap); + if (r < 0) + return r; + } + + return sd_bus_send(call->bus, m, NULL); +} + +_public_ int sd_bus_reply_method_error( + sd_bus_message *call, + const sd_bus_error *e) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(sd_bus_error_is_set(e), -EINVAL); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + + r = sd_bus_message_new_method_error(call, &m, e); + if (r < 0) + return r; + + return sd_bus_send(call->bus, m, NULL); +} + +_public_ int sd_bus_reply_method_errorf( + sd_bus_message *call, + const char *name, + const char *format, + ...) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + va_list ap; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + + va_start(ap, format); + bus_error_setfv(&error, name, format, ap); + va_end(ap); + + return sd_bus_reply_method_error(call, &error); +} + +_public_ int sd_bus_reply_method_errno( + sd_bus_message *call, + int error, + const sd_bus_error *p) { + + _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + + if (sd_bus_error_is_set(p)) + return sd_bus_reply_method_error(call, p); + + sd_bus_error_set_errno(&berror, error); + + return sd_bus_reply_method_error(call, &berror); +} + +_public_ int sd_bus_reply_method_errnof( + sd_bus_message *call, + int error, + const char *format, + ...) { + + _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + va_list ap; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 0; + + va_start(ap, format); + bus_error_set_errnofv(&berror, error, format, ap); + va_end(ap); + + return sd_bus_reply_method_error(call, &berror); +} + +_public_ int sd_bus_get_property( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + sd_bus_message **reply, + const char *type) { + + sd_bus_message *rep = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(reply, -EINVAL); + assert_return(signature_is_single(type, false), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(rep, 'v', type); + if (r < 0) { + sd_bus_message_unref(rep); + return r; + } + + *reply = rep; + return 0; +} + +_public_ int sd_bus_get_property_trivial( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + char type, void *ptr) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type)); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(reply, type, ptr); + if (r < 0) + return r; + + return 0; +} + +_public_ int sd_bus_get_property_string( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + char **ret) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *s; + char *n; + int r; + + assert_return(bus, -EINVAL); + assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(ret, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', "s"); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(reply, 's', &s); + if (r < 0) + return r; + + n = strdup(s); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +_public_ int sd_bus_get_property_strv( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + char ***ret) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(ret, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, 'v', NULL); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(reply, ret); + if (r < 0) + return r; + + return 0; +} + +_public_ int sd_bus_set_property( + sd_bus *bus, + const char *destination, + const char *path, + const char *interface, + const char *member, + sd_bus_error *error, + const char *type, ...) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + va_list ap; + int r; + + assert_return(bus, -EINVAL); + assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(signature_is_single(type, false), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "ss", strempty(interface), member); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'v', type); + if (r < 0) + return r; + + va_start(ap, type); + r = bus_message_append_ap(m, type, ap); + va_end(ap); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + return sd_bus_call(bus, m, 0, error, NULL); +} + +_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) { + sd_bus_creds *c; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + c = sd_bus_message_get_creds(call); + + /* All data we need? */ + if (c && (mask & ~c->mask) == 0) { + *creds = sd_bus_creds_ref(c); + return 0; + } + + /* No data passed? Or not enough data passed to retrieve the missing bits? */ + if (!c || !(c->mask & SD_BUS_CREDS_PID)) { + /* We couldn't read anything from the call, let's try + * to get it from the sender or peer */ + + if (call->sender) + return sd_bus_get_owner(call->bus, call->sender, mask, creds); + else + return sd_bus_get_peer_creds(call->bus, mask, creds); + } + + return bus_creds_extend_by_pid(c, mask, creds); +} diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c new file mode 100644 index 0000000..2d56f3c --- /dev/null +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -0,0 +1,925 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "cgroup-util.h" +#include "fileio.h" +#include "audit.h" +#include "bus-message.h" +#include "bus-util.h" +#include "time-util.h" +#include "strv.h" +#include "bus-creds.h" + +enum { + CAP_OFFSET_INHERITABLE = 0, + CAP_OFFSET_PERMITTED = 1, + CAP_OFFSET_EFFECTIVE = 2, + CAP_OFFSET_BOUNDING = 3 +}; + +void bus_creds_done(sd_bus_creds *c) { + assert(c); + + /* For internal bus cred structures that are allocated by + * something else */ + + free(c->session); + free(c->unit); + free(c->user_unit); + free(c->slice); + free(c->unescaped_conn_name); + + strv_free(c->cmdline_array); + strv_free(c->well_known_names); +} + +_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) { + assert_return(c, NULL); + + if (c->allocated) { + assert(c->n_ref > 0); + c->n_ref++; + } else { + sd_bus_message *m; + + /* If this is an embedded creds structure, then + * forward ref counting to the message */ + m = container_of(c, sd_bus_message, creds); + sd_bus_message_ref(m); + } + + return c; +} + +_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) { + + if (!c) + return NULL; + + if (c->allocated) { + assert(c->n_ref > 0); + c->n_ref--; + + if (c->n_ref == 0) { + bus_creds_done(c); + + free(c->comm); + free(c->tid_comm); + free(c->exe); + free(c->cmdline); + free(c->cgroup); + free(c->capability); + free(c->label); + free(c->unique_name); + free(c->cgroup_root); + free(c->conn_name); + free(c); + } + } else { + sd_bus_message *m; + + m = container_of(c, sd_bus_message, creds); + sd_bus_message_unref(m); + } + + + return NULL; +} + +_public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) { + assert_return(c, 0); + + return c->mask; +} + +sd_bus_creds* bus_creds_new(void) { + sd_bus_creds *c; + + c = new0(sd_bus_creds, 1); + if (!c) + return NULL; + + c->allocated = true; + c->n_ref = 1; + return c; +} + +_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) { + sd_bus_creds *c; + int r; + + assert_return(pid >= 0, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP); + assert_return(ret, -EINVAL); + + if (pid == 0) + pid = getpid(); + + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + r = bus_creds_add_more(c, mask, pid, 0); + if (r < 0) { + sd_bus_creds_unref(c); + return r; + } + + /* Check if the process existed at all, in case we haven't + * figured that out already */ + if (!pid_is_alive(pid)) { + sd_bus_creds_unref(c); + return -ESRCH; + } + + *ret = c; + return 0; +} + +_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) { + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_UID)) + return -ENODATA; + + *uid = c->uid; + return 0; +} + +_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) { + assert_return(c, -EINVAL); + assert_return(gid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_UID)) + return -ENODATA; + + *gid = c->gid; + return 0; +} + +_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) { + assert_return(c, -EINVAL); + assert_return(pid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_PID)) + return -ENODATA; + + assert(c->pid > 0); + *pid = c->pid; + return 0; +} + +_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) { + assert_return(c, -EINVAL); + assert_return(tid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_TID)) + return -ENODATA; + + assert(c->tid > 0); + *tid = c->tid; + return 0; +} + +_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) { + assert_return(c, -EINVAL); + assert_return(usec, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME)) + return -ENODATA; + + assert(c->pid_starttime > 0); + *usec = c->pid_starttime; + return 0; +} + +_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)) + return -ENODATA; + + assert(c->label); + *ret = c->label; + return 0; +} + +_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_COMM)) + return -ENODATA; + + assert(c->comm); + *ret = c->comm; + return 0; +} + +_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_TID_COMM)) + return -ENODATA; + + assert(c->tid_comm); + *ret = c->tid_comm; + return 0; +} + +_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_EXE)) + return -ENODATA; + + assert(c->exe); + *ret = c->exe; + return 0; +} + +_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_CGROUP)) + return -ENODATA; + + assert(c->cgroup); + *ret = c->cgroup; + return 0; +} + +_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_UNIT)) + return -ENODATA; + + assert(c->cgroup); + + if (!c->unit) { + const char *shifted; + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + r = cg_path_get_unit(shifted, (char**) &c->unit); + if (r < 0) + return r; + } + + *ret = c->unit; + return 0; +} + +_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_USER_UNIT)) + return -ENODATA; + + assert(c->cgroup); + + if (!c->user_unit) { + const char *shifted; + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + r = cg_path_get_user_unit(shifted, (char**) &c->user_unit); + if (r < 0) + return r; + } + + *ret = c->user_unit; + return 0; +} + +_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_SLICE)) + return -ENODATA; + + assert(c->cgroup); + + if (!c->slice) { + const char *shifted; + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + r = cg_path_get_slice(shifted, (char**) &c->slice); + if (r < 0) + return r; + } + + *ret = c->slice; + return 0; +} + +_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_SESSION)) + return -ENODATA; + + assert(c->cgroup); + + if (!c->session) { + const char *shifted; + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + r = cg_path_get_session(shifted, (char**) &c->session); + if (r < 0) + return r; + } + + *ret = c->session; + return 0; +} + +_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) { + const char *shifted; + int r; + + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_OWNER_UID)) + return -ENODATA; + + assert(c->cgroup); + + r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted); + if (r < 0) + return r; + + return cg_path_get_owner_uid(shifted, uid); +} + +_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) { + assert_return(c, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_CMDLINE)) + return -ENODATA; + + assert_return(c->cmdline, -ESRCH); + assert(c->cmdline); + + if (!c->cmdline_array) { + c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size); + if (!c->cmdline_array) + return -ENOMEM; + } + + *cmdline = c->cmdline_array; + return 0; +} + +_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) { + assert_return(c, -EINVAL); + assert_return(sessionid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID)) + return -ENODATA; + + *sessionid = c->audit_session_id; + return 0; +} + +_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) { + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID)) + return -ENODATA; + + *uid = c->audit_login_uid; + return 0; +} + +_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) { + assert_return(c, -EINVAL); + assert_return(unique_name, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME)) + return -ENODATA; + + *unique_name = c->unique_name; + return 0; +} + +_public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) { + assert_return(c, -EINVAL); + assert_return(well_known_names, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)) + return -ENODATA; + + *well_known_names = c->well_known_names; + return 0; +} + +_public_ int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_CONNECTION_NAME)) + return -ENODATA; + + assert(c->conn_name); + + if (!c->unescaped_conn_name) { + c->unescaped_conn_name = sd_bus_label_unescape(c->conn_name); + if (!c->unescaped_conn_name) + return -ENOMEM; + } + + *ret = c->unescaped_conn_name; + return 0; +} + +static int has_cap(sd_bus_creds *c, unsigned offset, int capability) { + size_t sz; + + assert(c); + assert(c->capability); + + sz = c->capability_size / 4; + if ((size_t) capability >= sz*8) + return 0; + + return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8))); +} + +_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS)) + return -ENODATA; + + return has_cap(c, CAP_OFFSET_EFFECTIVE, capability); +} + +_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS)) + return -ENODATA; + + return has_cap(c, CAP_OFFSET_PERMITTED, capability); +} + +_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS)) + return -ENODATA; + + return has_cap(c, CAP_OFFSET_INHERITABLE, capability); +} + +_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + + if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS)) + return -ENODATA; + + return has_cap(c, CAP_OFFSET_BOUNDING, capability); +} + +static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) { + size_t sz; + unsigned i; + + assert(c); + assert(p); + + p += strspn(p, WHITESPACE); + + sz = strlen(p); + if (sz % 2 != 0) + return -EINVAL; + + sz /= 2; + if (!c->capability) { + c->capability = new0(uint8_t, sz * 4); + if (!c->capability) + return -ENOMEM; + + c->capability_size = sz * 4; + } + + for (i = 0; i < sz; i ++) { + int x, y; + + x = unhexchar(p[i*2]); + y = unhexchar(p[i*2+1]); + + if (x < 0 || y < 0) + return -EINVAL; + + c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y; + } + + return 0; +} + +int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { + uint64_t missing; + int r; + + assert(c); + assert(c->allocated); + + missing = mask & ~c->mask; + if (missing == 0) + return 0; + + /* Try to retrieve PID from creds if it wasn't passed to us */ + if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID)) + pid = c->pid; + + if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) + tid = c->pid; + + /* Without pid we cannot do much... */ + if (pid <= 0) + return 0; + + if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | + SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS | + SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) { + + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + const char *p; + + p = procfs_file_alloca(pid, "status"); + + f = fopen(p, "re"); + if (!f) + return errno == ENOENT ? -ESRCH : -errno; + + FOREACH_LINE(line, f, return -errno) { + truncate_nl(line); + + if (missing & SD_BUS_CREDS_UID) { + p = startswith(line, "Uid:"); + if (p) { + unsigned long uid; + + p += strspn(p, WHITESPACE); + if (sscanf(p, "%lu", &uid) != 1) + return -EIO; + + c->uid = (uid_t) uid; + c->mask |= SD_BUS_CREDS_UID; + continue; + } + } + + if (missing & SD_BUS_CREDS_GID) { + p = startswith(line, "Gid:"); + if (p) { + unsigned long gid; + + p += strspn(p, WHITESPACE); + if (sscanf(p, "%lu", &gid) != 1) + return -EIO; + + c->gid = (uid_t) gid; + c->mask |= SD_BUS_CREDS_GID; + continue; + } + } + + if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) { + p = startswith(line, "CapEff:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_PERMITTED_CAPS) { + p = startswith(line, "CapPrm:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_PERMITTED, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_PERMITTED_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) { + p = startswith(line, "CapInh:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_INHERITABLE, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_BOUNDING_CAPS) { + p = startswith(line, "CapBnd:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_BOUNDING, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_BOUNDING_CAPS; + continue; + } + } + } + } + + if (missing & (SD_BUS_CREDS_PID_STARTTIME)) { + unsigned long long st; + + r = get_starttime_of_pid(pid, &st); + if (r < 0) + return r; + + c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK); + c->mask |= SD_BUS_CREDS_PID_STARTTIME; + } + + if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) { + const char *p; + + p = procfs_file_alloca(pid, "attr/current"); + r = read_one_line_file(p, &c->label); + if (r < 0 && r != -ENOENT && r != -EINVAL) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + + if (missing & SD_BUS_CREDS_COMM) { + r = get_process_comm(pid, &c->comm); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_COMM; + } + + if (missing & SD_BUS_CREDS_EXE) { + r = get_process_exe(pid, &c->exe); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_EXE; + } + + if (missing & SD_BUS_CREDS_CMDLINE) { + const char *p; + + p = procfs_file_alloca(pid, "cmdline"); + r = read_full_file(p, &c->cmdline, &c->cmdline_size); + if (r < 0) + return r; + + if (c->cmdline_size == 0) { + free(c->cmdline); + c->cmdline = NULL; + } else + c->mask |= SD_BUS_CREDS_CMDLINE; + } + + if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) { + _cleanup_free_ char *p = NULL; + + if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &c->tid_comm); + if (r < 0) + return r == -ENOENT ? -ESRCH : r; + + c->mask |= SD_BUS_CREDS_TID_COMM; + } + + if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) { + + r = cg_pid_get_path(NULL, pid, &c->cgroup); + if (r < 0) + return r; + + r = cg_get_root_path(&c->cgroup_root); + if (r < 0) + return r; + + c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID); + } + + if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { + r = audit_session_from_pid(pid, &c->audit_session_id); + if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; + } + + if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) { + r = audit_loginuid_from_pid(pid, &c->audit_login_uid); + if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; + } + + return 0; +} + +int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) { + _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL; + int r; + + assert(c); + assert(ret); + + if ((mask & ~c->mask) == 0) { + /* There's already all data we need. */ + + *ret = sd_bus_creds_ref(c); + return 0; + } + + n = bus_creds_new(); + if (!n) + return -ENOMEM; + + /* Copy the original data over */ + + if (c->mask & mask & SD_BUS_CREDS_UID) { + n->uid = c->uid; + n->mask |= SD_BUS_CREDS_UID; + } + + if (c->mask & mask & SD_BUS_CREDS_GID) { + n->gid = c->gid; + n->mask |= SD_BUS_CREDS_GID; + } + + if (c->mask & mask & SD_BUS_CREDS_PID) { + n->pid = c->pid; + n->mask |= SD_BUS_CREDS_PID; + } + + if (c->mask & mask & SD_BUS_CREDS_TID) { + n->tid = c->tid; + n->mask |= SD_BUS_CREDS_TID; + } + + if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) { + n->pid_starttime = c->pid_starttime; + n->mask |= SD_BUS_CREDS_PID_STARTTIME; + } + + if (c->mask & mask & SD_BUS_CREDS_COMM) { + n->comm = strdup(c->comm); + if (!n->comm) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_COMM; + } + + if (c->mask & mask & SD_BUS_CREDS_TID_COMM) { + n->tid_comm = strdup(c->tid_comm); + if (!n->tid_comm) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_TID_COMM; + } + + if (c->mask & mask & SD_BUS_CREDS_EXE) { + n->exe = strdup(c->exe); + if (!n->exe) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_EXE; + } + + if (c->mask & mask & SD_BUS_CREDS_CMDLINE) { + n->cmdline = memdup(c->cmdline, c->cmdline_size); + if (!n->cmdline) + return -ENOMEM; + + n->cmdline_size = c->cmdline_size; + n->mask |= SD_BUS_CREDS_CMDLINE; + } + + if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) { + n->cgroup = strdup(c->cgroup); + if (!n->cgroup) + return -ENOMEM; + + n->cgroup_root = strdup(c->cgroup_root); + if (!n->cgroup_root) + return -ENOMEM; + + n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID); + } + + if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) { + n->capability = memdup(c->capability, c->capability_size); + if (!n->capability) + return -ENOMEM; + + n->capability_size = c->capability_size; + n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS); + } + + if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) { + n->audit_session_id = c->audit_session_id; + n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; + } + + if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) { + n->audit_login_uid = c->audit_login_uid; + n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; + } + + if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) { + n->unique_name = strdup(c->unique_name); + if (!n->unique_name) + return -ENOMEM; + } + + if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { + n->well_known_names = strv_copy(c->well_known_names); + if (!n->well_known_names) + return -ENOMEM; + } + + /* Get more data */ + + r = bus_creds_add_more(n, mask, + c->mask & SD_BUS_CREDS_PID ? c->pid : 0, + c->mask & SD_BUS_CREDS_TID ? c->tid : 0); + if (r < 0) + return r; + + *ret = n; + n = NULL; + return 0; +} diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h new file mode 100644 index 0000000..81b852a --- /dev/null +++ b/src/libsystemd/sd-bus/bus-creds.h @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" +#include "time-util.h" + +struct sd_bus_creds { + bool allocated; + unsigned n_ref; + uint64_t mask; + + uid_t uid; + gid_t gid; + pid_t pid; + usec_t pid_starttime; + pid_t tid; + + char *comm; + char *tid_comm; + char *exe; + + char *cmdline; + size_t cmdline_size; + char **cmdline_array; + + char *cgroup; + char *session; + char *unit; + char *user_unit; + char *slice; + + uint8_t *capability; + size_t capability_size; + + uint32_t audit_session_id; + uid_t audit_login_uid; + + char *label; + + char *unique_name; + + char **well_known_names; + + char *cgroup_root; + + char *conn_name, *unescaped_conn_name; +}; + +sd_bus_creds* bus_creds_new(void); + +void bus_creds_done(sd_bus_creds *c); + +int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid); + +int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret); diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c new file mode 100644 index 0000000..0e41549 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -0,0 +1,426 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "capability.h" +#include "strv.h" +#include "audit.h" + +#include "bus-message.h" +#include "bus-internal.h" +#include "bus-type.h" +#include "bus-dump.h" + +static char *indent(unsigned level) { + char *p; + + p = new(char, 2 + level + 1); + if (!p) + return NULL; + + p[0] = p[1] = ' '; + memset(p + 2, '\t', level); + p[2 + level] = 0; + + return p; +} + +int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { + unsigned level = 1; + int r; + + assert(m); + + if (!f) + f = stdout; + + if (with_header) { + fprintf(f, + "%s%s%sType=%s%s%s Endian=%c Flags=%u Version=%u Priority=%lli", + m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : + m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() : + m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(), + ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(), + m->header->endian, + m->header->flags, + m->header->version, + (long long) m->priority); + + /* Display synthetic message serial number in a more readable + * format than (uint32_t) -1 */ + if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL) + fprintf(f, " Cookie=-1"); + else + fprintf(f, " Cookie=%lu", (unsigned long) BUS_MESSAGE_COOKIE(m)); + + if (m->reply_cookie != 0) + fprintf(f, " ReplyCookie=%lu", (unsigned long) m->reply_cookie); + + fputs("\n", f); + + if (m->sender) + fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off()); + if (m->destination) + fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off()); + if (m->path) + fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off()); + if (m->interface) + fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off()); + if (m->member) + fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off()); + + if (m->sender || m->destination || m->path || m->interface || m->member) + fputs("\n", f); + + if (sd_bus_error_is_set(&m->error)) + fprintf(f, + " ErrorName=%s%s%s" + " ErrorMessage=%s\"%s\"%s\n", + ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(), + ansi_highlight_red(), strna(m->error.message), ansi_highlight_off()); + + if (m->monotonic != 0) + fprintf(f, " Monotonic=%llu", (unsigned long long) m->monotonic); + if (m->realtime != 0) + fprintf(f, " Realtime=%llu", (unsigned long long) m->realtime); + if (m->seqnum != 0) + fprintf(f, " SequenceNumber=%llu", (unsigned long long) m->seqnum); + + if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0) + fputs("\n", f); + + bus_creds_dump(&m->creds, f); + } + + r = sd_bus_message_rewind(m, true); + if (r < 0) { + log_error("Failed to rewind: %s", strerror(-r)); + return r; + } + + fprintf(f, " MESSAGE \"%s\" {\n", strempty(m->root_container.signature)); + + for (;;) { + _cleanup_free_ char *prefix = NULL; + const char *contents = NULL; + char type; + union { + uint8_t u8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + double d64; + const char *string; + int i; + } basic; + + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) { + log_error("Failed to peek type: %s", strerror(-r)); + return r; + } + + if (r == 0) { + if (level <= 1) + break; + + r = sd_bus_message_exit_container(m); + if (r < 0) { + log_error("Failed to exit container: %s", strerror(-r)); + return r; + } + + level--; + + prefix = indent(level); + if (!prefix) + return log_oom(); + + fprintf(f, "%s};\n", prefix); + continue; + } + + prefix = indent(level); + if (!prefix) + return log_oom(); + + if (bus_type_is_container(type) > 0) { + r = sd_bus_message_enter_container(m, type, contents); + if (r < 0) { + log_error("Failed to enter container: %s", strerror(-r)); + return r; + } + + if (type == SD_BUS_TYPE_ARRAY) + fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents); + else if (type == SD_BUS_TYPE_VARIANT) + fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents); + else if (type == SD_BUS_TYPE_STRUCT) + fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents); + else if (type == SD_BUS_TYPE_DICT_ENTRY) + fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents); + + level ++; + + continue; + } + + r = sd_bus_message_read_basic(m, type, &basic); + if (r < 0) { + log_error("Failed to get basic: %s", strerror(-r)); + return r; + } + + assert(r > 0); + + switch (type) { + + case SD_BUS_TYPE_BYTE: + fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_BOOLEAN: + fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off()); + break; + + case SD_BUS_TYPE_INT16: + fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_UINT16: + fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_INT32: + fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_UINT32: + fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_INT64: + fprintf(f, "%sINT64 %s%lli%s;\n", prefix, ansi_highlight(), (long long) basic.s64, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_UINT64: + fprintf(f, "%sUINT64 %s%llu%s;\n", prefix, ansi_highlight(), (unsigned long long) basic.u64, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_DOUBLE: + fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_STRING: + fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_OBJECT_PATH: + fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_SIGNATURE: + fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + break; + + case SD_BUS_TYPE_UNIX_FD: + fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off()); + break; + + default: + assert_not_reached("Unknown basic type."); + } + } + + fprintf(f, " };\n\n"); + return 0; +} + +static void dump_capabilities( + sd_bus_creds *c, + FILE *f, + const char *name, + int (*has)(sd_bus_creds *c, int capability)) { + + unsigned long i, last_cap; + unsigned n = 0; + int r; + + assert(c); + assert(f); + assert(name); + assert(has); + + i = 0; + r = has(c, i); + if (r < 0) + return; + + fprintf(f, " %s=", name); + last_cap = cap_last_cap(); + + for (;;) { + if (r > 0) { + _cleanup_cap_free_charp_ char *t; + + if (n > 0) + fputc(' ', f); + if (n % 4 == 3) + fputs("\n ", f); + + t = cap_to_name(i); + fprintf(f, "%s", t); + n++; + } + + i++; + + if (i > last_cap) + break; + + r = has(c, i); + } + + fputs("\n", f); +} + +int bus_creds_dump(sd_bus_creds *c, FILE *f) { + bool audit_sessionid_is_set = false, audit_loginuid_is_set = false; + const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL; + uid_t owner, audit_loginuid; + uint32_t audit_sessionid; + char **cmdline = NULL, **well_known = NULL; + int r; + + assert(c); + + if (!f) + f = stdout; + + if (c->mask & SD_BUS_CREDS_PID) + fprintf(f, " PID=%lu", (unsigned long) c->pid); + if (c->mask & SD_BUS_CREDS_PID_STARTTIME) + fprintf(f, " PIDStartTime=%llu", (unsigned long long) c->pid_starttime); + if (c->mask & SD_BUS_CREDS_TID) + fprintf(f, " TID=%lu", (unsigned long) c->tid); + if (c->mask & SD_BUS_CREDS_UID) + fprintf(f, " UID=%lu", (unsigned long) c->uid); + r = sd_bus_creds_get_owner_uid(c, &owner); + if (r >= 0) + fprintf(f, " OwnerUID=%lu", (unsigned long) owner); + if (c->mask & SD_BUS_CREDS_GID) + fprintf(f, " GID=%lu", (unsigned long) c->gid); + + if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0) + fputs("\n", f); + + if (c->mask & SD_BUS_CREDS_EXE) + fprintf(f, " Exe=%s", c->exe); + if (c->mask & SD_BUS_CREDS_COMM) + fprintf(f, " Comm=%s", c->comm); + if (c->mask & SD_BUS_CREDS_TID_COMM) + fprintf(f, " TIDComm=%s", c->tid_comm); + + if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)) + fputs("\n", f); + + if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT) + fprintf(f, " Label=%s", c->label); + if (c->mask & SD_BUS_CREDS_CONNECTION_NAME) + fprintf(f, " ConnectionName=%s", c->conn_name); + + if (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_CONNECTION_NAME)) + fputs("\n", f); + + if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) { + char **i; + + fputs(" CommandLine={", f); + STRV_FOREACH(i, cmdline) { + if (i != cmdline) + fputc(' ', f); + + fputs(*i, f); + } + + fputs("}\n", f); + } + + if (c->mask & SD_BUS_CREDS_CGROUP) + fprintf(f, " CGroup=%s", c->cgroup); + sd_bus_creds_get_unit(c, &u); + if (u) + fprintf(f, " Unit=%s", u); + sd_bus_creds_get_user_unit(c, &uu); + if (uu) + fprintf(f, " UserUnit=%s", uu); + sd_bus_creds_get_slice(c, &sl); + if (sl) + fprintf(f, " Slice=%s", sl); + sd_bus_creds_get_session(c, &s); + if (s) + fprintf(f, " Session=%s", s); + + if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s) + fputs("\n", f); + + if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) { + audit_loginuid_is_set = true; + fprintf(f, " AuditLoginUID=%lu", (unsigned long) audit_loginuid); + } + if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) { + audit_sessionid_is_set = true; + fprintf(f, " AuditSessionID=%lu", (unsigned long) audit_sessionid); + } + + if (audit_loginuid_is_set || audit_sessionid_is_set) + fputs("\n", f); + + if (c->mask & SD_BUS_CREDS_UNIQUE_NAME) + fprintf(f, " UniqueName=%s", c->unique_name); + + if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) { + char **i; + + fputs(" WellKnownNames={", f); + STRV_FOREACH(i, well_known) { + if (i != well_known) + fputc(' ', f); + + fputs(*i, f); + } + + fputc('}', f); + } + + if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known) + fputc('\n', f); + + dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap); + dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap); + dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap); + dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap); + + return 0; +} diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h new file mode 100644 index 0000000..bb1d25d --- /dev/null +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-bus.h" + +int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header); + +int bus_creds_dump(sd_bus_creds *c, FILE *f); diff --git a/src/libsystemd/sd-bus/bus-error-mapping.gperf b/src/libsystemd/sd-bus/bus-error-mapping.gperf new file mode 100644 index 0000000..df2c4d4 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-error-mapping.gperf @@ -0,0 +1,49 @@ +%{ +#include +#include "bus-error.h" +%} +name_error_mapping; +%null_strings +%language=ANSI-C +%define slot-name name +%define hash-function-name bus_error_mapping_hash +%define lookup-function-name bus_error_mapping_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +org.freedesktop.DBus.Error.Failed, EACCES +org.freedesktop.DBus.Error.NoMemory, ENOMEM +org.freedesktop.DBus.Error.ServiceUnknown, EHOSTUNREACH +org.freedesktop.DBus.Error.NameHasNoOwner, ENXIO +org.freedesktop.DBus.Error.NoReply, ETIMEDOUT +org.freedesktop.DBus.Error.IOError, EIO +org.freedesktop.DBus.Error.BadAddress, EADDRNOTAVAIL +org.freedesktop.DBus.Error.NotSupported, ENOTSUP +org.freedesktop.DBus.Error.LimitsExceeded, ENOBUFS +org.freedesktop.DBus.Error.AccessDenied, EACCES +org.freedesktop.DBus.Error.AuthFailed, EACCES +org.freedesktop.DBus.Error.NoServer, EHOSTDOWN +org.freedesktop.DBus.Error.Timeout, ETIMEDOUT +org.freedesktop.DBus.Error.NoNetwork, ENONET +org.freedesktop.DBus.Error.AddressInUse, EADDRINUSE +org.freedesktop.DBus.Error.Disconnected, ECONNRESET +org.freedesktop.DBus.Error.InvalidArgs, EINVAL +org.freedesktop.DBus.Error.FileNotFound, ENOENT +org.freedesktop.DBus.Error.FileExists, EEXIST +org.freedesktop.DBus.Error.UnknownMethod, EBADR +org.freedesktop.DBus.Error.UnknownObject, EBADR +org.freedesktop.DBus.Error.UnknownInterface, EBADR +org.freedesktop.DBus.Error.UnknownProperty, EBADR +org.freedesktop.DBus.Error.PropertyReadOnly, EROFS +org.freedesktop.DBus.Error.UnixProcessIdUnknown, ESRCH +org.freedesktop.DBus.Error.InvalidSignature, EINVAL +org.freedesktop.DBus.Error.InconsistentMessage, EBADMSG +# +org.freedesktop.DBus.Error.TimedOut, ETIMEDOUT +org.freedesktop.DBus.Error.MatchRuleInvalid, EINVAL +org.freedesktop.DBus.Error.InvalidFileContent, EINVAL +org.freedesktop.DBus.Error.MatchRuleNotFound, ENOENT +org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown, ESRCH +org.freedesktop.DBus.Error.ObjectPathInUse, EBUSY diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c new file mode 100644 index 0000000..c2e41fb --- /dev/null +++ b/src/libsystemd/sd-bus/bus-error.c @@ -0,0 +1,504 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "errno-list.h" + +#include "sd-bus.h" +#include "bus-error.h" + +#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory") +#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed") + +static int bus_error_name_to_errno(const char *name) { + const char *p; + int r; + const name_error_mapping *m; + + if (!name) + return EINVAL; + + p = startswith(name, "System.Error."); + if (p) { + r = errno_from_name(p); + if (r <= 0) + return EIO; + + return r; + } + + m = bus_error_mapping_lookup(name, strlen(name)); + if (m) + return m->code; + + return EIO; +} + +static sd_bus_error errno_to_bus_error_const(int error) { + + if (error < 0) + error = -error; + + switch (error) { + + case ENOMEM: + return BUS_ERROR_OOM; + + case EPERM: + case EACCES: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ACCESS_DENIED, "Access denied"); + + case EINVAL: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument"); + + case ESRCH: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process"); + + case ENOENT: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found"); + + case EEXIST: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "File exists"); + + case ETIMEDOUT: + case ETIME: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_TIMEOUT, "Timed out"); + + case EIO: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_IO_ERROR, "Input/output error"); + + case ENETRESET: + case ECONNABORTED: + case ECONNRESET: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected"); + + case ENOTSUP: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported"); + + case EADDRNOTAVAIL: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_BAD_ADDRESS, "Address not available"); + + case ENOBUFS: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded"); + + case EADDRINUSE: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use"); + + case EBADMSG: + return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message"); + } + + return SD_BUS_ERROR_NULL; +} + +static int errno_to_bus_error_name_new(int error, char **ret) { + const char *name; + char *n; + + if (error < 0) + error = -error; + + name = errno_to_name(error); + if (!name) + return 0; + + n = strappend("System.Error.", name); + if (!n) + return -ENOMEM; + + *ret = n; + return 1; +} + +bool bus_error_is_dirty(sd_bus_error *e) { + if (!e) + return false; + + return e->name || e->message || e->_need_free != 0; +} + +_public_ void sd_bus_error_free(sd_bus_error *e) { + if (!e) + return; + + if (e->_need_free > 0) { + free((void*) e->name); + free((void*) e->message); + } + + e->name = e->message = NULL; + e->_need_free = 0; +} + +_public_ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) { + + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (message) + e->message = strdup(message); + + e->_need_free = 1; + +finish: + return -bus_error_name_to_errno(name); +} + +int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) { + + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (format) + vasprintf((char**) &e->message, format, ap); + + e->_need_free = 1; + +finish: + return -bus_error_name_to_errno(name); +} + +_public_ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) { + + if (format) { + int r; + va_list ap; + + va_start(ap, format); + r = bus_error_setfv(e, name, format, ap); + va_end(ap); + + return r; + } + + return sd_bus_error_set(e, name, NULL); +} + +_public_ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) { + + if (!sd_bus_error_is_set(e)) + return 0; + if (!dest) + goto finish; + + assert_return(!bus_error_is_dirty(dest), -EINVAL); + + /* + * _need_free < 0 indicates that the error is temporarily const, needs deep copying + * _need_free == 0 indicates that the error is perpetually const, needs no deep copying + * _need_free > 0 indicates that the error is fully dynamic, needs deep copying + */ + + if (e->_need_free == 0) + *dest = *e; + else { + dest->name = strdup(e->name); + if (!dest->name) { + *dest = BUS_ERROR_OOM; + return -ENOMEM; + } + + if (e->message) + dest->message = strdup(e->message); + + dest->_need_free = 1; + } + +finish: + return -bus_error_name_to_errno(e->name); +} + +_public_ int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) { + if (!name) + return 0; + if (!e) + goto finish; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + *e = SD_BUS_ERROR_MAKE_CONST(name, message); + +finish: + return -bus_error_name_to_errno(name); +} + +_public_ int sd_bus_error_is_set(const sd_bus_error *e) { + if (!e) + return 0; + + return !!e->name; +} + +_public_ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) { + if (!e) + return 0; + + return streq_ptr(e->name, name); +} + +_public_ int sd_bus_error_get_errno(const sd_bus_error* e) { + if (!e) + return 0; + + if (!e->name) + return 0; + + return bus_error_name_to_errno(e->name); +} + +static void bus_error_strerror(sd_bus_error *e, int error) { + size_t k = 64; + char *m; + + assert(e); + + for (;;) { + char *x; + + m = new(char, k); + if (!m) + return; + + errno = 0; + x = strerror_r(error, m, k); + if (errno == ERANGE || strlen(x) >= k - 1) { + free(m); + k *= 2; + continue; + } + + if (!x || errno) { + free(m); + return; + } + + if (x == m) { + if (e->_need_free > 0) { + /* Error is already dynamic, let's just update the message */ + free((char*) e->message); + e->message = x; + + } else { + char *t; + /* Error was const so far, let's make it dynamic, if we can */ + + t = strdup(e->name); + if (!t) { + free(m); + return; + } + + e->_need_free = 1; + e->name = t; + e->message = x; + } + } else { + free(m); + + if (e->_need_free > 0) { + char *t; + + /* Error is dynamic, let's hence make the message also dynamic */ + t = strdup(x); + if (!t) + return; + + free((char*) e->message); + e->message = t; + } else { + /* Error is const, hence we can just override */ + e->message = x; + } + } + + return; + } +} + +_public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) { + + if (error < 0) + error = -error; + + if (!e) + return -error; + if (error == 0) + return -error; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + /* First, try a const translation */ + *e = errno_to_bus_error_const(error); + + if (!sd_bus_error_is_set(e)) { + int k; + + /* If that didn't work, try a dynamic one. */ + + k = errno_to_bus_error_name_new(error, (char**) &e->name); + if (k > 0) + e->_need_free = 1; + else if (k < 0) { + *e = BUS_ERROR_OOM; + return -error; + } else + *e = BUS_ERROR_FAILED; + } + + /* Now, fill in the message from strerror() if we can */ + bus_error_strerror(e, error); + return -error; +} + +int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) { + int r; + + if (error < 0) + error = -error; + + if (!e) + return -error; + if (error == 0) + return 0; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + /* First, try a const translation */ + *e = errno_to_bus_error_const(error); + + if (!sd_bus_error_is_set(e)) { + int k; + + /* If that didn't work, try a dynamic one */ + + k = errno_to_bus_error_name_new(error, (char**) &e->name); + if (k > 0) + e->_need_free = 1; + else if (k < 0) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } else + *e = BUS_ERROR_FAILED; + } + + if (format) { + char *m; + + /* First, let's try to fill in the supplied message */ + + r = vasprintf(&m, format, ap); + if (r >= 0) { + + if (e->_need_free <= 0) { + char *t; + + t = strdup(e->name); + if (t) { + e->_need_free = 1; + e->name = t; + e->message = m; + return -error; + } + + free(m); + } else { + free((char*) e->message); + e->message = m; + return -error; + } + } + } + + /* If that didn't work, use strerror() for the message */ + bus_error_strerror(e, error); + return -error; +} + +_public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) { + int r; + + if (error < 0) + error = -error; + + if (!e) + return -error; + if (error == 0) + return 0; + + assert_return(!bus_error_is_dirty(e), -EINVAL); + + if (format) { + va_list ap; + + va_start(ap, format); + r = bus_error_set_errnofv(e, error, format, ap); + va_end(ap); + + return r; + } + + return sd_bus_error_set_errno(e, error); +} + +const char *bus_error_message(const sd_bus_error *e, int error) { + + if (e) { + /* Sometimes the D-Bus server is a little bit too verbose with + * its error messages, so let's override them here */ + if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED)) + return "Access denied"; + + if (e->message) + return e->message; + } + + if (error < 0) + error = -error; + + return strerror(error); +} diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h new file mode 100644 index 0000000..cf0ad9d --- /dev/null +++ b/src/libsystemd/sd-bus/bus-error.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" +#include "macro.h" + +struct name_error_mapping { + const char* name; + int code; +}; +typedef struct name_error_mapping name_error_mapping; + +const name_error_mapping* bus_error_mapping_lookup(const char *str, unsigned int len); + +bool bus_error_is_dirty(sd_bus_error *e); + +const char *bus_error_message(const sd_bus_error *e, int error); + +int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) _printf_(3,0); +int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) _printf_(3,0); diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c new file mode 100644 index 0000000..dc40009 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-gvariant.c @@ -0,0 +1,249 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "bus-type.h" +#include "bus-gvariant.h" +#include "bus-signature.h" + +int bus_gvariant_get_size(const char *signature) { + const char *p; + int sum = 0, r; + + /* For fixed size structs. Fails for variable size structs. */ + + p = signature; + while (*p != 0) { + size_t n; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + else { + char t[n+1]; + + memcpy(t, p, n); + t[n] = 0; + + r = bus_gvariant_get_alignment(t); + if (r < 0) + return r; + + sum = ALIGN_TO(sum, r); + } + + switch (*p) { + + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_BYTE: + sum += 1; + break; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + sum += 2; + break; + + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_UNIX_FD: + sum += 4; + break; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + sum += 8; + break; + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + char t[n-1]; + + memcpy(t, p + 1, n - 2); + t[n - 2] = 0; + + r = bus_gvariant_get_size(t); + if (r < 0) + return r; + + sum += r; + break; + } + + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_ARRAY: + case SD_BUS_TYPE_VARIANT: + return -EINVAL; + + default: + assert_not_reached("Unknown signature type"); + } + + p += n; + } + + r = bus_gvariant_get_alignment(signature); + if (r < 0) + return r; + + return ALIGN_TO(sum, r); +} + +int bus_gvariant_get_alignment(const char *signature) { + size_t alignment = 1; + const char *p; + int r; + + p = signature; + while (*p != 0 && alignment < 8) { + size_t n; + int a; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + + switch (*p) { + + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + a = 1; + break; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + a = 2; + break; + + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_UNIX_FD: + a = 4; + break; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + case SD_BUS_TYPE_VARIANT: + a = 8; + break; + + case SD_BUS_TYPE_ARRAY: { + char t[n]; + + memcpy(t, p + 1, n - 1); + t[n - 1] = 0; + + a = bus_gvariant_get_alignment(t); + break; + } + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + char t[n-1]; + + memcpy(t, p + 1, n - 2); + t[n - 2] = 0; + + a = bus_gvariant_get_alignment(t); + break; + } + + default: + assert_not_reached("Unknown signature type"); + } + + if (a < 0) + return a; + + assert(a > 0 && a <= 8); + if ((size_t) a > alignment) + alignment = (size_t) a; + + p += n; + } + + return alignment; +} + +int bus_gvariant_is_fixed_size(const char *signature) { + const char *p; + int r; + + assert(signature); + + p = signature; + while (*p != 0) { + size_t n; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + + switch (*p) { + + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_ARRAY: + case SD_BUS_TYPE_VARIANT: + return 0; + + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_UNIX_FD: + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + break; + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + char t[n-1]; + + memcpy(t, p + 1, n - 2); + t[n - 2] = 0; + + r = bus_gvariant_is_fixed_size(t); + if (r <= 0) + return r; + break; + } + + default: + assert_not_reached("Unknown signature type"); + } + + p += n; + } + + return true; +} diff --git a/src/libsystemd/sd-bus/bus-gvariant.h b/src/libsystemd/sd-bus/bus-gvariant.h new file mode 100644 index 0000000..b4bd2a5 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-gvariant.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int bus_gvariant_get_size(const char *signature) _pure_; +int bus_gvariant_get_alignment(const char *signature) _pure_; +int bus_gvariant_is_fixed_size(const char *signature) _pure_; diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c new file mode 100644 index 0000000..0bea8ca --- /dev/null +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -0,0 +1,305 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-internal.h" + +bool object_path_is_valid(const char *p) { + const char *q; + bool slash; + + if (!p) + return false; + + if (p[0] != '/') + return false; + + if (p[1] == 0) + return true; + + for (slash = true, q = p+1; *q; q++) + if (*q == '/') { + if (slash) + return false; + + slash = true; + } else { + bool good; + + good = + (*q >= 'a' && *q <= 'z') || + (*q >= 'A' && *q <= 'Z') || + (*q >= '0' && *q <= '9') || + *q == '_'; + + if (!good) + return false; + + slash = false; + } + + if (slash) + return false; + + return true; +} + +char* object_path_startswith(const char *a, const char *b) { + const char *p; + + if (!object_path_is_valid(a) || + !object_path_is_valid(b)) + return NULL; + + if (streq(b, "/")) + return (char*) a + 1; + + p = startswith(a, b); + if (!p) + return NULL; + + if (*p == 0) + return (char*) p; + + if (*p == '/') + return (char*) p + 1; + + return NULL; +} + +bool interface_name_is_valid(const char *p) { + const char *q; + bool dot, found_dot = false; + + if (isempty(p)) + return false; + + for (dot = true, q = p; *q; q++) + if (*q == '.') { + if (dot) + return false; + + found_dot = dot = true; + } else { + bool good; + + good = + (*q >= 'a' && *q <= 'z') || + (*q >= 'A' && *q <= 'Z') || + (!dot && *q >= '0' && *q <= '9') || + *q == '_'; + + if (!good) + return false; + + dot = false; + } + + if (q - p > 255) + return false; + + if (dot) + return false; + + if (!found_dot) + return false; + + return true; +} + +bool service_name_is_valid(const char *p) { + const char *q; + bool dot, found_dot = false, unique; + + if (isempty(p)) + return false; + + unique = p[0] == ':'; + + for (dot = true, q = unique ? p+1 : p; *q; q++) + if (*q == '.') { + if (dot) + return false; + + found_dot = dot = true; + } else { + bool good; + + good = + (*q >= 'a' && *q <= 'z') || + (*q >= 'A' && *q <= 'Z') || + ((!dot || unique) && *q >= '0' && *q <= '9') || + *q == '_' || *q == '-'; + + if (!good) + return false; + + dot = false; + } + + if (q - p > 255) + return false; + + if (dot) + return false; + + if (!found_dot) + return false; + + return true; +} + +bool member_name_is_valid(const char *p) { + const char *q; + + if (isempty(p)) + return false; + + for (q = p; *q; q++) { + bool good; + + good = + (*q >= 'a' && *q <= 'z') || + (*q >= 'A' && *q <= 'Z') || + (*q >= '0' && *q <= '9') || + *q == '_'; + + if (!good) + return false; + } + + if (q - p > 255) + return false; + + return true; +} + +static bool complex_pattern_check(char c, const char *a, const char *b) { + bool separator = false; + + if (!a && !b) + return true; + + if (!a || !b) + return false; + + for (;;) { + if (*a != *b) + return (separator && (*a == 0 || *b == 0)) || + (*a == 0 && *b == c && b[1] == 0) || + (*b == 0 && *a == c && a[1] == 0); + + if (*a == 0) + return true; + + separator = *a == c; + + a++, b++; + } +} + +bool namespace_complex_pattern(const char *pattern, const char *value) { + return complex_pattern_check('.', pattern, value); +} + +bool path_complex_pattern(const char *pattern, const char *value) { + return complex_pattern_check('/', pattern, value); +} + +static bool simple_pattern_check(char c, const char *a, const char *b) { + + if (!a && !b) + return true; + + if (!a || !b) + return false; + + for (;;) { + if (*a != *b) + return *a == 0 && *b == c; + + if (*a == 0) + return true; + + a++, b++; + } +} + +bool namespace_simple_pattern(const char *pattern, const char *value) { + return simple_pattern_check('.', pattern, value); +} + +bool path_simple_pattern(const char *pattern, const char *value) { + return simple_pattern_check('/', pattern, value); +} + +int bus_message_type_from_string(const char *s, uint8_t *u) { + if (streq(s, "signal")) + *u = SD_BUS_MESSAGE_SIGNAL; + else if (streq(s, "method_call")) + *u = SD_BUS_MESSAGE_METHOD_CALL; + else if (streq(s, "error")) + *u = SD_BUS_MESSAGE_METHOD_ERROR; + else if (streq(s, "method_return")) + *u = SD_BUS_MESSAGE_METHOD_RETURN; + else + return -EINVAL; + + return 0; +} + +const char *bus_message_type_to_string(uint8_t u) { + if (u == SD_BUS_MESSAGE_SIGNAL) + return "signal"; + else if (u == SD_BUS_MESSAGE_METHOD_CALL) + return "method_call"; + else if (u == SD_BUS_MESSAGE_METHOD_ERROR) + return "error"; + else if (u == SD_BUS_MESSAGE_METHOD_RETURN) + return "method_return"; + else + return NULL; +} + +char *bus_address_escape(const char *v) { + const char *a; + char *r, *b; + + r = new(char, strlen(v)*3+1); + if (!r) + return NULL; + + for (a = v, b = r; *a; a++) { + + if ((*a >= '0' && *a <= '9') || + (*a >= 'a' && *a <= 'z') || + (*a >= 'A' && *a <= 'Z') || + strchr("_-/.", *a)) + *(b++) = *a; + else { + *(b++) = '%'; + *(b++) = hexchar(*a >> 4); + *(b++) = hexchar(*a & 0xF); + } + } + + *b = 0; + return r; +} diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h new file mode 100644 index 0000000..a4160ef --- /dev/null +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -0,0 +1,335 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "hashmap.h" +#include "prioq.h" +#include "list.h" +#include "util.h" +#include "refcnt.h" + +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-match.h" +#include "bus-kernel.h" +#include "kdbus.h" + +struct reply_callback { + sd_bus_message_handler_t callback; + void *userdata; + usec_t timeout; + uint64_t cookie; + unsigned prioq_idx; +}; + +struct filter_callback { + sd_bus_message_handler_t callback; + void *userdata; + + unsigned last_iteration; + + LIST_FIELDS(struct filter_callback, callbacks); +}; + +struct node { + char *path; + struct node *parent; + LIST_HEAD(struct node, child); + LIST_FIELDS(struct node, siblings); + + LIST_HEAD(struct node_callback, callbacks); + LIST_HEAD(struct node_vtable, vtables); + LIST_HEAD(struct node_enumerator, enumerators); + + bool object_manager; +}; + +struct node_callback { + struct node *node; + + bool is_fallback; + sd_bus_message_handler_t callback; + void *userdata; + + unsigned last_iteration; + + LIST_FIELDS(struct node_callback, callbacks); +}; + +struct node_enumerator { + struct node *node; + + sd_bus_node_enumerator_t callback; + void *userdata; + + unsigned last_iteration; + + LIST_FIELDS(struct node_enumerator, enumerators); +}; + +struct node_vtable { + struct node *node; + + char *interface; + bool is_fallback; + const sd_bus_vtable *vtable; + void *userdata; + sd_bus_object_find_t find; + + unsigned last_iteration; + + LIST_FIELDS(struct node_vtable, vtables); +}; + +struct vtable_member { + const char *path; + const char *interface; + const char *member; + struct node_vtable *parent; + unsigned last_iteration; + const sd_bus_vtable *vtable; +}; + +enum bus_state { + BUS_UNSET, + BUS_OPENING, + BUS_AUTHENTICATING, + BUS_HELLO, + BUS_RUNNING, + BUS_CLOSING, + BUS_CLOSED +}; + +static inline bool BUS_IS_OPEN(enum bus_state state) { + return state > BUS_UNSET && state < BUS_CLOSING; +} + +enum bus_auth { + _BUS_AUTH_INVALID, + BUS_AUTH_EXTERNAL, + BUS_AUTH_ANONYMOUS +}; + +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; + + enum bus_state state; + int input_fd, output_fd; + int message_version; + int message_endian; + + bool is_kernel:1; + bool can_fds:1; + bool bus_client:1; + bool ucred_valid:1; + bool is_server:1; + bool anonymous_auth:1; + bool prefer_readv:1; + bool prefer_writev:1; + bool match_callbacks_modified:1; + bool filter_callbacks_modified:1; + bool nodes_modified:1; + bool trusted:1; + bool fake_creds_valid:1; + bool manual_peer_interface:1; + bool is_system:1; + bool is_user:1; + + int use_memfd; + + void *rbuffer; + size_t rbuffer_size; + + sd_bus_message **rqueue; + unsigned rqueue_size; + size_t rqueue_allocated; + + sd_bus_message **wqueue; + unsigned wqueue_size; + size_t windex; + size_t wqueue_allocated; + + uint64_t cookie; + + char *unique_name; + uint64_t unique_id; + + struct bus_match_node match_callbacks; + Prioq *reply_callbacks_prioq; + Hashmap *reply_callbacks; + LIST_HEAD(struct filter_callback, filter_callbacks); + + Hashmap *nodes; + Hashmap *vtable_methods; + Hashmap *vtable_properties; + + union { + struct sockaddr sa; + struct sockaddr_un un; + struct sockaddr_in in; + struct sockaddr_in6 in6; + } sockaddr; + socklen_t sockaddr_size; + + char *kernel; + char *machine; + + sd_id128_t server_id; + + char *address; + unsigned address_index; + + int last_connect_error; + + enum bus_auth auth; + size_t auth_rbegin; + struct iovec auth_iovec[3]; + unsigned auth_index; + char *auth_buffer; + usec_t auth_timeout; + + struct ucred ucred; + char label[NAME_MAX]; + + uint64_t creds_mask; + + int *fds; + unsigned n_fds; + + char *exec_path; + char **exec_argv; + + uint64_t hello_cookie; + unsigned iteration_counter; + + void *kdbus_buffer; + + /* We do locking around the memfd cache, since we want to + * allow people to process a sd_bus_message in a different + * thread then it was generated on and free it there. Since + * adding something to the memfd cache might happen when a + * message is released, we hence need to protect this bit with + * a mutex. */ + pthread_mutex_t memfd_cache_mutex; + struct memfd_cache memfd_cache[MEMFD_CACHE_MAX]; + unsigned n_memfd_cache; + + pid_t original_pid; + + uint64_t hello_flags; + uint64_t attach_flags; + + uint64_t match_cookie; + + sd_event_source *input_io_event_source; + sd_event_source *output_io_event_source; + sd_event_source *time_event_source; + sd_event_source *quit_event_source; + sd_event *event; + int event_priority; + + sd_bus_message *current; + + sd_bus **default_bus_ptr; + pid_t tid; + + struct kdbus_creds fake_creds; + char *fake_label; + + char *cgroup_root; + + char *connection_name; + + size_t bloom_size; + unsigned bloom_n_hash; +}; + +#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) + +#define BUS_WQUEUE_MAX 1024 +#define BUS_RQUEUE_MAX 64*1024 + +#define BUS_MESSAGE_SIZE_MAX (64*1024*1024) +#define BUS_AUTH_SIZE_MAX (64*1024) + +#define BUS_CONTAINER_DEPTH 128 + +/* Defined by the specification as maximum size of an array in + * bytes */ +#define BUS_ARRAY_MAX_SIZE 67108864 + +#define BUS_FDS_MAX 1024 + +#define BUS_EXEC_ARGV_MAX 256 + +bool interface_name_is_valid(const char *p) _pure_; +bool service_name_is_valid(const char *p) _pure_; +bool member_name_is_valid(const char *p) _pure_; +bool object_path_is_valid(const char *p) _pure_; +char *object_path_startswith(const char *a, const char *b) _pure_; + +bool namespace_complex_pattern(const char *pattern, const char *value) _pure_; +bool path_complex_pattern(const char *pattern, const char *value) _pure_; + +bool namespace_simple_pattern(const char *pattern, const char *value) _pure_; +bool path_simple_pattern(const char *pattern, const char *value) _pure_; + +int bus_message_type_from_string(const char *s, uint8_t *u) _pure_; +const char *bus_message_type_to_string(uint8_t u) _pure_; + +#define error_name_is_valid interface_name_is_valid + +int bus_ensure_running(sd_bus *bus); +int bus_start_running(sd_bus *bus); +int bus_next_address(sd_bus *bus); + +int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m); + +int bus_rqueue_make_room(sd_bus *bus); + +bool bus_pid_changed(sd_bus *bus); + +char *bus_address_escape(const char *v); + +#define OBJECT_PATH_FOREACH_PREFIX(prefix, path) \ + for (char *_slash = ({ strcpy((prefix), (path)); streq((prefix), "/") ? NULL : strrchr((prefix), '/'); }) ; \ + _slash && !(_slash[(_slash) == (prefix)] = 0); \ + _slash = streq((prefix), "/") ? NULL : strrchr((prefix), '/')) + +/* If we are invoking callbacks of a bus object, ensure unreffing the + * bus from the callback doesn't destroy the object we are working + * on */ +#define BUS_DONT_DESTROY(bus) \ + _cleanup_bus_unref_ _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus) diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c new file mode 100644 index 0000000..d528ab2 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -0,0 +1,212 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "sd-bus-protocol.h" +#include "bus-introspect.h" +#include "bus-signature.h" +#include "bus-internal.h" +#include "bus-protocol.h" + +int introspect_begin(struct introspect *i, bool trusted) { + assert(i); + + zero(*i); + i->trusted = trusted; + + i->f = open_memstream(&i->introspection, &i->size); + if (!i->f) + return -ENOMEM; + + fputs(BUS_INTROSPECT_DOCTYPE + "\n", i->f); + + return 0; +} + +int introspect_write_default_interfaces(struct introspect *i, bool object_manager) { + assert(i); + + fputs(BUS_INTROSPECT_INTERFACE_PEER + BUS_INTROSPECT_INTERFACE_INTROSPECTABLE + BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f); + + if (object_manager) + fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f); + + return 0; +} + +int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) { + char *node; + + assert(i); + assert(prefix); + + while ((node = set_steal_first(s))) { + const char *e; + + e = object_path_startswith(node, prefix); + if (e && e[0]) + fprintf(i->f, " \n", e); + + free(node); + } + + return 0; +} + +static void introspect_write_flags(struct introspect *i, int type, int flags) { + if (flags & SD_BUS_VTABLE_DEPRECATED) + fputs(" \n", i->f); + + if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY)) + fputs(" \n", i->f); + + if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) { + if (flags & SD_BUS_VTABLE_PROPERTY_CONST) + fputs(" \n", i->f); + else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) + fputs(" \n", i->f); + else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) + fputs(" \n", i->f); + } + + if (!i->trusted && + (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) && + !(flags & SD_BUS_VTABLE_UNPRIVILEGED)) + fputs(" \n", i->f); +} + +static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) { + int r; + + for (;;) { + size_t l; + + if (!*signature) + return 0; + + r = signature_element_length(signature, &l); + if (r < 0) + return r; + + fprintf(i->f, " f, " direction=\"%s\"/>\n", direction); + else + fputs("/>\n", i->f); + + signature += l; + } +} + +int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) { + assert(i); + assert(v); + + for (; v->type != _SD_BUS_VTABLE_END; v++) { + + /* Ignore methods, signals and properties that are + * marked "hidden", but do show the interface + * itself */ + + if (v->type != _SD_BUS_VTABLE_START && (v->flags & SD_BUS_VTABLE_HIDDEN)) + continue; + + switch (v->type) { + + case _SD_BUS_VTABLE_START: + if (v->flags & SD_BUS_VTABLE_DEPRECATED) + fputs(" \n", i->f); + break; + + case _SD_BUS_VTABLE_METHOD: + fprintf(i->f, " \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"); + introspect_write_flags(i, v->type, v->flags); + fputs(" \n", i->f); + break; + + case _SD_BUS_VTABLE_PROPERTY: + case _SD_BUS_VTABLE_WRITABLE_PROPERTY: + fprintf(i->f, " \n", + v->x.property.member, + v->x.property.signature, + v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read"); + introspect_write_flags(i, v->type, v->flags); + fputs(" \n", i->f); + break; + + case _SD_BUS_VTABLE_SIGNAL: + fprintf(i->f, " \n", v->x.signal.member); + introspect_write_arguments(i, strempty(v->x.signal.signature), NULL); + introspect_write_flags(i, v->type, v->flags); + fputs(" \n", i->f); + break; + } + + } + + return 0; +} + +int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) { + sd_bus_message *q; + int r; + + assert(i); + assert(m); + assert(reply); + + fputs("\n", i->f); + fflush(i->f); + + if (ferror(i->f)) + return -ENOMEM; + + r = sd_bus_message_new_method_return(m, &q); + if (r < 0) + return r; + + r = sd_bus_message_append(q, "s", i->introspection); + if (r < 0) { + sd_bus_message_unref(q); + return r; + } + + *reply = q; + return 0; +} + +void introspect_free(struct introspect *i) { + assert(i); + + if (i->f) + fclose(i->f); + + if (i->introspection) + free(i->introspection); + + zero(*i); +} diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h new file mode 100644 index 0000000..98312d1 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-introspect.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-bus.h" +#include "set.h" + +struct introspect { + FILE *f; + char *introspection; + size_t size; + bool trusted; +}; + +int introspect_begin(struct introspect *i, bool trusted); +int introspect_write_default_interfaces(struct introspect *i, bool object_manager); +int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix); +int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v); +int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply); +void introspect_free(struct introspect *i); diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c new file mode 100644 index 0000000..eec62ac --- /dev/null +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -0,0 +1,1498 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include +#endif + +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" + +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-kernel.h" +#include "bus-bloom.h" +#include "bus-util.h" +#include "cgroup-util.h" + +#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) + +int bus_kernel_parse_unique_name(const char *s, uint64_t *id) { + int r; + + assert(s); + assert(id); + + if (!startswith(s, ":1.")) + return 0; + + r = safe_atou64(s + 3, id); + if (r < 0) + return r; + + return 1; +} + +static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) { + assert(d); + assert(sz > 0); + + *d = ALIGN8_PTR(*d); + + /* Note that p can be NULL, which encodes a region full of + * zeroes, which is useful to optimize certain padding + * conditions */ + + (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec); + (*d)->type = KDBUS_ITEM_PAYLOAD_VEC; + (*d)->vec.address = PTR_TO_UINT64(p); + (*d)->vec.size = sz; + + *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); +} + +static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) { + assert(d); + assert(memfd >= 0); + assert(sz > 0); + + *d = ALIGN8_PTR(*d); + (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd); + (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD; + (*d)->memfd.fd = memfd; + (*d)->memfd.size = sz; + + *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); +} + +static void append_destination(struct kdbus_item **d, const char *s, size_t length) { + assert(d); + assert(s); + + *d = ALIGN8_PTR(*d); + + (*d)->size = offsetof(struct kdbus_item, str) + length + 1; + (*d)->type = KDBUS_ITEM_DST_NAME; + memcpy((*d)->str, s, length + 1); + + *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); +} + +static struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) { + struct kdbus_item *i; + + assert(d); + + i = ALIGN8_PTR(*d); + + i->size = offsetof(struct kdbus_item, bloom_filter) + + offsetof(struct kdbus_bloom_filter, data) + + length; + i->type = KDBUS_ITEM_BLOOM_FILTER; + + *d = (struct kdbus_item *) ((uint8_t*) i + i->size); + + return &i->bloom_filter; +} + +static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) { + assert(d); + assert(fds); + assert(n_fds > 0); + + *d = ALIGN8_PTR(*d); + (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds; + (*d)->type = KDBUS_ITEM_FDS; + memcpy((*d)->fds, fds, sizeof(int) * n_fds); + + *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); +} + +static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) { + void *data; + unsigned i; + int r; + + assert(m); + assert(bloom); + + data = bloom->data; + memzero(data, m->bus->bloom_size); + bloom->generation = 0; + + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type)); + + if (m->interface) + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface); + if (m->member) + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member); + if (m->path) { + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path); + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/'); + } + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + for (i = 0; i < 64; i++) { + char type; + const char *t; + char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; + char *e; + + r = sd_bus_message_peek_type(m, &type, NULL); + if (r < 0) + return r; + + if (type != SD_BUS_TYPE_STRING && + type != SD_BUS_TYPE_OBJECT_PATH && + type != SD_BUS_TYPE_SIGNATURE) + break; + + r = sd_bus_message_read_basic(m, type, &t); + if (r < 0) + return r; + + e = stpcpy(buf, "arg"); + if (i < 10) + *(e++) = '0' + (char) i; + else { + *(e++) = '0' + (char) (i / 10); + *(e++) = '0' + (char) (i % 10); + } + + *e = 0; + bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t); + + strcpy(e, "-dot-prefix"); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.'); + strcpy(e, "-slash-prefix"); + bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/'); + } + + return 0; +} + +static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { + struct bus_body_part *part; + struct kdbus_item *d; + bool well_known; + uint64_t unique; + size_t sz, dl; + unsigned i; + int r; + + assert(b); + assert(m); + assert(m->sealed); + + /* We put this together only once, if this message is reused + * we reuse the earlier-built version */ + if (m->kdbus) + return 0; + + if (m->destination) { + r = bus_kernel_parse_unique_name(m->destination, &unique); + if (r < 0) + return r; + + well_known = r == 0; + } else + well_known = false; + + sz = offsetof(struct kdbus_msg, items); + + assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) == + ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd))); + + /* Add in fixed header, fields header and payload */ + sz += (1 + m->n_body_parts) * + ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)); + + /* Add space for bloom filter */ + sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) + + offsetof(struct kdbus_bloom_filter, data) + + m->bus->bloom_size); + + /* Add in well-known destination header */ + if (well_known) { + dl = strlen(m->destination); + sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1); + } + + /* Add space for unix fds */ + if (m->n_fds > 0) + sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds); + + m->kdbus = memalign(8, sz); + if (!m->kdbus) { + r = -ENOMEM; + goto fail; + } + + m->free_kdbus = true; + memzero(m->kdbus, sz); + + m->kdbus->flags = + ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) | + ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0); + m->kdbus->dst_id = + well_known ? 0 : + m->destination ? unique : KDBUS_DST_ID_BROADCAST; + m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS; + m->kdbus->cookie = m->header->serial; + m->kdbus->priority = m->priority; + + if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + m->kdbus->cookie_reply = m->reply_cookie; + else + m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC; + + d = m->kdbus->items; + + if (well_known) + append_destination(&d, m->destination, dl); + + append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m)); + + MESSAGE_FOREACH_PART(part, i, m) { + if (part->is_zero) { + /* If this is padding then simply send a + * vector with a NULL data pointer which the + * kernel will just pass through. This is the + * most efficient way to encode zeroes */ + + append_payload_vec(&d, NULL, part->size); + continue; + } + + if (part->memfd >= 0 && part->sealed && m->destination) { + /* Try to send a memfd, if the part is + * sealed and this is not a broadcast. Since we can only */ + + append_payload_memfd(&d, part->memfd, part->size); + continue; + } + + /* Otherwise, let's send a vector to the actual data. + * For that, we need to map it first. */ + r = bus_body_part_map(part); + if (r < 0) + goto fail; + + append_payload_vec(&d, part->data, part->size); + } + + if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) { + struct kdbus_bloom_filter *bloom; + + bloom = append_bloom(&d, m->bus->bloom_size); + r = bus_message_setup_bloom(m, bloom); + if (r < 0) + goto fail; + } + + if (m->n_fds > 0) + append_fds(&d, m->fds, m->n_fds); + + m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus; + assert(m->kdbus->size <= sz); + + return 0; + +fail: + m->poisoned = true; + return r; +} + +static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { + sd_bus_message *m = NULL; + struct kdbus_item *d; + unsigned n_fds = 0; + _cleanup_free_ int *fds = NULL; + struct bus_header *h = NULL; + size_t total, n_bytes = 0, idx = 0; + const char *destination = NULL, *seclabel = NULL; + int r; + + assert(bus); + assert(k); + assert(k->payload_type == KDBUS_PAYLOAD_DBUS); + + KDBUS_ITEM_FOREACH(d, k, items) { + size_t l; + + l = d->size - offsetof(struct kdbus_item, data); + + switch (d->type) { + + case KDBUS_ITEM_PAYLOAD_OFF: + if (!h) { + h = (struct bus_header *)((uint8_t *)k + d->vec.offset); + + if (!bus_header_is_complete(h, d->vec.size)) + return -EBADMSG; + } + + n_bytes += d->vec.size; + break; + + case KDBUS_ITEM_PAYLOAD_MEMFD: + if (!h) + return -EBADMSG; + + n_bytes += d->memfd.size; + break; + + case KDBUS_ITEM_FDS: { + int *f; + unsigned j; + + j = l / sizeof(int); + f = realloc(fds, sizeof(int) * (n_fds + j)); + if (!f) + return -ENOMEM; + + fds = f; + memcpy(fds + n_fds, d->fds, sizeof(int) * j); + n_fds += j; + break; + } + + case KDBUS_ITEM_SECLABEL: + seclabel = d->str; + break; + } + } + + if (!h) + return -EBADMSG; + + r = bus_header_message_size(h, &total); + if (r < 0) + return r; + + if (n_bytes != total) + return -EBADMSG; + + /* on kdbus we only speak native endian gvariant, never dbus1 + * marshalling or reverse endian */ + if (h->version != 2 || + h->endian != BUS_NATIVE_ENDIAN) + return -EPROTOTYPE; + + r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m); + if (r < 0) + return r; + + /* The well-known names list is different from the other + credentials. If we asked for it, but nothing is there, this + means that the list of well-known names is simply empty, not + that we lack any data */ + + m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask; + + KDBUS_ITEM_FOREACH(d, k, items) { + size_t l; + + l = d->size - offsetof(struct kdbus_item, data); + + switch (d->type) { + + case KDBUS_ITEM_PAYLOAD_OFF: { + size_t begin_body; + + begin_body = BUS_MESSAGE_BODY_BEGIN(m); + + if (idx + d->vec.size > begin_body) { + struct bus_body_part *part; + + /* Contains body material */ + + part = message_append_part(m); + if (!part) { + r = -ENOMEM; + goto fail; + } + + /* A -1 offset is NUL padding. */ + part->is_zero = d->vec.offset == ~0ULL; + + if (idx >= begin_body) { + if (!part->is_zero) + part->data = (uint8_t *)k + d->vec.offset; + part->size = d->vec.size; + } else { + if (!part->is_zero) + part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx); + part->size = d->vec.size - (begin_body - idx); + } + + part->sealed = true; + } + + idx += d->vec.size; + break; + } + + case KDBUS_ITEM_PAYLOAD_MEMFD: { + struct bus_body_part *part; + + if (idx < BUS_MESSAGE_BODY_BEGIN(m)) { + r = -EBADMSG; + goto fail; + } + + part = message_append_part(m); + if (!part) { + r = -ENOMEM; + goto fail; + } + + part->memfd = d->memfd.fd; + part->size = d->memfd.size; + part->sealed = true; + + idx += d->memfd.size; + break; + } + + case KDBUS_ITEM_CREDS: + /* UID/GID/PID are always valid */ + m->creds.uid = (uid_t) d->creds.uid; + m->creds.gid = (gid_t) d->creds.gid; + m->creds.pid = (pid_t) d->creds.pid; + m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask; + + /* The PID starttime/TID might be missing + * however, when the data is faked by some + * data bus proxy and it lacks that + * information about the real client since + * SO_PEERCRED is used for that */ + + if (d->creds.starttime > 0) { + m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC; + m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask; + } + + if (d->creds.tid > 0) { + m->creds.tid = (pid_t) d->creds.tid; + m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask; + } + break; + + case KDBUS_ITEM_TIMESTAMP: + + if (bus->attach_flags & KDBUS_ATTACH_TIMESTAMP) { + m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC; + m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC; + m->seqnum = d->timestamp.seqnum; + } + + break; + + case KDBUS_ITEM_PID_COMM: + m->creds.comm = d->str; + m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask; + break; + + case KDBUS_ITEM_TID_COMM: + m->creds.tid_comm = d->str; + m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask; + break; + + case KDBUS_ITEM_EXE: + m->creds.exe = d->str; + m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask; + break; + + case KDBUS_ITEM_CMDLINE: + m->creds.cmdline = d->str; + m->creds.cmdline_size = l; + m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask; + break; + + case KDBUS_ITEM_CGROUP: + m->creds.cgroup = d->str; + m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask; + + if (!bus->cgroup_root) { + r = cg_get_root_path(&bus->cgroup_root); + if (r < 0) + goto fail; + } + + m->creds.cgroup_root = bus->cgroup_root; + + break; + + case KDBUS_ITEM_AUDIT: + m->creds.audit_session_id = (uint32_t) d->audit.sessionid; + m->creds.audit_login_uid = (uid_t) d->audit.loginuid; + m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask; + break; + + case KDBUS_ITEM_CAPS: + m->creds.capability = d->data; + m->creds.capability_size = l; + m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask; + break; + + case KDBUS_ITEM_DST_NAME: + if (!service_name_is_valid(d->str)) + return -EBADMSG; + + destination = d->str; + break; + + case KDBUS_ITEM_NAME: + if (!service_name_is_valid(d->name.name)) + return -EBADMSG; + + r = strv_extend(&m->creds.well_known_names, d->name.name); + if (r < 0) + goto fail; + break; + + case KDBUS_ITEM_CONN_NAME: + m->creds.conn_name = d->str; + m->creds.mask |= SD_BUS_CREDS_CONNECTION_NAME & bus->creds_mask; + break; + + case KDBUS_ITEM_FDS: + case KDBUS_ITEM_SECLABEL: + break; + + default: + log_debug("Got unknown field from kernel %llu", d->type); + } + } + + r = bus_message_parse_fields(m); + if (r < 0) + goto fail; + + /* Override information from the user header with data from the kernel */ + if (k->src_id == KDBUS_SRC_ID_KERNEL) + m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus"; + else { + snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id); + m->sender = m->creds.unique_name = m->sender_buffer; + } + + if (destination) + m->destination = destination; + else if (k->dst_id == KDBUS_DST_ID_BROADCAST) + m->destination = NULL; + else if (k->dst_id == KDBUS_DST_ID_NAME) + m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */ + else { + snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id); + m->destination = m->destination_buffer; + } + + /* We take possession of the kmsg struct now */ + m->kdbus = k; + m->release_kdbus = true; + m->free_fds = true; + fds = NULL; + + bus->rqueue[bus->rqueue_size++] = m; + + return 1; + +fail: + if (m) { + struct bus_body_part *part; + unsigned i; + + /* Make sure the memfds are not freed twice */ + MESSAGE_FOREACH_PART(part, i, m) + if (part->memfd >= 0) + part->memfd = -1; + + sd_bus_message_unref(m); + } + + return r; +} + +int bus_kernel_take_fd(sd_bus *b) { + struct kdbus_cmd_hello *hello; + struct kdbus_item *item; + _cleanup_free_ char *g = NULL; + const char *name; + size_t l = 0, m = 0, sz; + int r; + + assert(b); + + if (b->is_server) + return -EINVAL; + + b->use_memfd = 1; + + if (b->connection_name) { + g = sd_bus_label_escape(b->connection_name); + if (!g) + return -ENOMEM; + + name = g; + } else { + char pr[17] = {}; + + /* If no name is explicitly set, we'll include a hint + * indicating the library implementation, a hint which + * kind of bus this is and the thread name */ + + assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0); + + if (isempty(pr)) { + name = b->is_system ? "sd-system" : + b->is_user ? "sd-user" : "sd"; + } else { + _cleanup_free_ char *e = NULL; + + e = sd_bus_label_escape(pr); + if (!e) + return -ENOMEM; + + g = strappend(b->is_system ? "sd-system-" : + b->is_user ? "sd-user-" : "sd-", + e); + if (!g) + return -ENOMEM; + + name = g; + } + + b->connection_name = sd_bus_label_unescape(name); + if (!b->connection_name) + return -ENOMEM; + } + + m = strlen(name); + + sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) + + ALIGN8(offsetof(struct kdbus_item, str) + m + 1); + + if (b->fake_creds_valid) + sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds)); + + if (b->fake_label) { + l = strlen(b->fake_label); + sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1); + } + + hello = alloca0(sz); + hello->size = sz; + hello->conn_flags = b->hello_flags; + hello->attach_flags = b->attach_flags; + hello->pool_size = KDBUS_POOL_SIZE; + + item = hello->items; + + item->size = offsetof(struct kdbus_item, str) + m + 1; + item->type = KDBUS_ITEM_CONN_NAME; + memcpy(item->str, name, m + 1); + item = KDBUS_ITEM_NEXT(item); + + if (b->fake_creds_valid) { + item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds); + item->type = KDBUS_ITEM_CREDS; + item->creds = b->fake_creds; + + item = KDBUS_ITEM_NEXT(item); + } + + if (b->fake_label) { + item->size = offsetof(struct kdbus_item, str) + l + 1; + item->type = KDBUS_ITEM_SECLABEL; + memcpy(item->str, b->fake_label, l+1); + } + + r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello); + if (r < 0) + return -errno; + + if (!b->kdbus_buffer) { + b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0); + if (b->kdbus_buffer == MAP_FAILED) { + b->kdbus_buffer = NULL; + return -errno; + } + } + + /* The higher 32bit of both flags fields are considered + * 'incompatible flags'. Refuse them all for now. */ + if (hello->bus_flags > 0xFFFFFFFFULL || + hello->conn_flags > 0xFFFFFFFFULL) + return -ENOTSUP; + + if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash)) + return -ENOTSUP; + + b->bloom_size = (size_t) hello->bloom.size; + b->bloom_n_hash = (unsigned) hello->bloom.n_hash; + + if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0) + return -ENOMEM; + + b->unique_id = hello->id; + + b->is_kernel = true; + b->bus_client = true; + b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD); + b->message_version = 2; + b->message_endian = BUS_NATIVE_ENDIAN; + + /* the kernel told us the UUID of the underlying bus */ + memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes)); + + return bus_start_running(b); +} + +int bus_kernel_connect(sd_bus *b) { + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + assert(b->kernel); + + if (b->is_server) + return -EINVAL; + + b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (b->input_fd < 0) + return -errno; + + b->output_fd = b->input_fd; + + return bus_kernel_take_fd(b); +} + +static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { + uint64_t off; + struct kdbus_item *d; + + assert(bus); + assert(k); + + off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer; + ioctl(bus->input_fd, KDBUS_CMD_FREE, &off); + + KDBUS_ITEM_FOREACH(d, k, items) { + + if (d->type == KDBUS_ITEM_FDS) + close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int)); + else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD) + close_nointr_nofail(d->memfd.fd); + } +} + +int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) { + int r; + + assert(bus); + assert(m); + assert(bus->state == BUS_RUNNING); + + /* If we can't deliver, we want room for the error message */ + r = bus_rqueue_make_room(bus); + if (r < 0) + return r; + + r = bus_message_setup_kmsg(bus, m); + if (r < 0) + return r; + + /* If this is a synchronous method call, then let's tell the + * kernel, so that it can pass CPU time/scheduling to the + * destination for the time, if it wants to. If we + * synchronously wait for the result anyway, we won't need CPU + * anyway. */ + if (hint_sync_call) + m->kdbus->flags |= KDBUS_MSG_FLAGS_EXPECT_REPLY|KDBUS_MSG_FLAGS_SYNC_REPLY; + + r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus); + if (r < 0) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message *reply; + + if (errno == EAGAIN || errno == EINTR) + return 0; + else if (errno == ENXIO || errno == ESRCH) { + + /* ENXIO: unique name not known + * ESRCH: well-known name not known */ + + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) + sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination); + else { + log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination); + return 0; + } + + } else if (errno == EADDRNOTAVAIL) { + + /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */ + + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) + sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination); + else { + log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination); + return 0; + } + } else + return -errno; + + r = bus_message_new_synthetic_error( + bus, + BUS_MESSAGE_COOKIE(m), + &error, + &reply); + + if (r < 0) + return r; + + r = bus_seal_synthetic_message(bus, reply); + if (r < 0) + return r; + + bus->rqueue[bus->rqueue_size++] = reply; + + } else if (hint_sync_call) { + struct kdbus_msg *k; + + k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + m->kdbus->offset_reply); + assert(k); + + if (k->payload_type == KDBUS_PAYLOAD_DBUS) { + + r = bus_kernel_make_message(bus, k); + if (r < 0) { + close_kdbus_msg(bus, k); + + /* Anybody can send us invalid messages, let's just drop them. */ + if (r == -EBADMSG || r == -EPROTOTYPE) + log_debug("Ignoring invalid message: %s", strerror(-r)); + else + return r; + } + } else { + log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type); + close_kdbus_msg(bus, k); + } + } + + return 1; +} + +static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "NameOwnerChanged"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "sss", name, old_owner, new_owner); + if (r < 0) + return r; + + m->sender = "org.freedesktop.DBus"; + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + bus->rqueue[bus->rqueue_size++] = m; + m = NULL; + + return 1; +} + +static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) { + char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX]; + + assert(bus); + assert(k); + assert(d); + + if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) + old_owner[0] = 0; + else + sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id); + + if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) { + + if (isempty(old_owner)) + return 0; + + new_owner[0] = 0; + } else + sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id); + + return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner); +} + +static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) { + char owner[UNIQUE_NAME_MAX]; + + assert(bus); + assert(k); + assert(d); + + sprintf(owner, ":1.%llu", d->id_change.id); + + return push_name_owner_changed( + bus, owner, + d->type == KDBUS_ITEM_ID_ADD ? NULL : owner, + d->type == KDBUS_ITEM_ID_ADD ? owner : NULL); +} + +static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + assert(k); + assert(d); + + r = bus_message_new_synthetic_error( + bus, + k->cookie_reply, + d->type == KDBUS_ITEM_REPLY_TIMEOUT ? + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") : + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"), + &m); + if (r < 0) + return r; + + m->sender = "org.freedesktop.DBus"; + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + bus->rqueue[bus->rqueue_size++] = m; + m = NULL; + + return 1; +} + +static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { + struct kdbus_item *d, *found = NULL; + + static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = { + [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, + [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, + [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change, + + [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change, + [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change, + + [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply, + [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply, + }; + + assert(bus); + assert(k); + assert(k->payload_type == KDBUS_PAYLOAD_KERNEL); + + KDBUS_ITEM_FOREACH(d, k, items) { + if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { + if (found) + return -EBADMSG; + found = d; + } else + log_debug("Got unknown field from kernel %llu", d->type); + } + + if (!found) { + log_debug("Didn't find a kernel message to translate."); + return 0; + } + + return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found); +} + +int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { + struct kdbus_cmd_recv recv = {}; + struct kdbus_msg *k; + int r; + + assert(bus); + + r = bus_rqueue_make_room(bus); + if (r < 0) + return r; + + if (hint_priority) { + recv.flags |= KDBUS_RECV_USE_PRIORITY; + recv.priority = priority; + } + + r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &recv); + if (r < 0) { + if (errno == EAGAIN) + return 0; + + return -errno; + } + + k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset); + if (k->payload_type == KDBUS_PAYLOAD_DBUS) { + r = bus_kernel_make_message(bus, k); + + /* Anybody can send us invalid messages, let's just drop them. */ + if (r == -EBADMSG || r == -EPROTOTYPE) { + log_debug("Ignoring invalid message: %s", strerror(-r)); + r = 0; + } + + } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL) + r = bus_kernel_translate_message(bus, k); + else { + log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type); + r = 0; + } + + if (r <= 0) + close_kdbus_msg(bus, k); + + return r < 0 ? r : 1; +} + +int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) { + struct memfd_cache *c; + int fd; + + assert(address); + assert(mapped); + assert(allocated); + + if (!bus || !bus->is_kernel) + return -ENOTSUP; + + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + + if (bus->n_memfd_cache <= 0) { + _cleanup_free_ char *g = NULL; + struct kdbus_cmd_memfd_make *cmd; + struct kdbus_item *item; + size_t l, sz; + int r; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + + assert(bus->connection_name); + + g = sd_bus_label_escape(bus->connection_name); + if (!g) + return -ENOMEM; + + l = strlen(g); + sz = ALIGN8(offsetof(struct kdbus_cmd_memfd_make, items)) + + ALIGN8(offsetof(struct kdbus_item, str)) + + l + 1; + cmd = alloca0(sz); + cmd->size = sz; + + item = cmd->items; + item->size = ALIGN8(offsetof(struct kdbus_item, str)) + l + 1; + item->type = KDBUS_ITEM_MEMFD_NAME; + memcpy(item->str, g, l + 1); + + r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, cmd); + if (r < 0) + return -errno; + + *address = NULL; + *mapped = 0; + *allocated = 0; + return cmd->fd; + } + + c = &bus->memfd_cache[--bus->n_memfd_cache]; + + assert(c->fd >= 0); + assert(c->mapped == 0 || c->address); + + *address = c->address; + *mapped = c->mapped; + *allocated = c->allocated; + fd = c->fd; + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + + return fd; +} + +static void close_and_munmap(int fd, void *address, size_t size) { + if (size > 0) + assert_se(munmap(address, PAGE_ALIGN(size)) >= 0); + + close_nointr_nofail(fd); +} + +void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) { + struct memfd_cache *c; + uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX); + + assert(fd >= 0); + assert(mapped == 0 || address); + + if (!bus || !bus->is_kernel) { + close_and_munmap(fd, address, mapped); + return; + } + + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + + if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + + close_and_munmap(fd, address, mapped); + return; + } + + c = &bus->memfd_cache[bus->n_memfd_cache++]; + c->fd = fd; + c->address = address; + + /* If overly long, let's return a bit to the OS */ + if (mapped > max_mapped) { + assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_mapped) >= 0); + assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0); + c->mapped = c->allocated = max_mapped; + } else { + c->mapped = mapped; + c->allocated = allocated; + } + + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); +} + +void bus_kernel_flush_memfd(sd_bus *b) { + unsigned i; + + assert(b); + + for (i = 0; i < b->n_memfd_cache; i++) + close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped); +} + +int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) { + uint64_t f = 0; + + assert(kdbus_flags); + + if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT) + f |= KDBUS_NAME_ALLOW_REPLACEMENT; + + if (flags & SD_BUS_NAME_REPLACE_EXISTING) + f |= KDBUS_NAME_REPLACE_EXISTING; + + if (flags & SD_BUS_NAME_QUEUE) + f |= KDBUS_NAME_QUEUE; + + *kdbus_flags = f; + return 0; +} + +int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) { + uint64_t m = 0; + + assert(kdbus_mask); + + if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID)) + m |= KDBUS_ATTACH_CREDS; + + if (mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)) + m |= KDBUS_ATTACH_COMM; + + if (mask & SD_BUS_CREDS_EXE) + m |= KDBUS_ATTACH_EXE; + + if (mask & SD_BUS_CREDS_CMDLINE) + m |= KDBUS_ATTACH_CMDLINE; + + if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) + m |= KDBUS_ATTACH_CGROUP; + + if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) + m |= KDBUS_ATTACH_CAPS; + + if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) + m |= KDBUS_ATTACH_SECLABEL; + + if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) + m |= KDBUS_ATTACH_AUDIT; + + if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) + m |= KDBUS_ATTACH_NAMES; + + if (mask & SD_BUS_CREDS_CONNECTION_NAME) + m |= KDBUS_ATTACH_CONN_NAME; + + *kdbus_mask = m; + return 0; +} + +int bus_kernel_create_bus(const char *name, bool world, char **s) { + struct kdbus_cmd_make *make; + struct kdbus_item *n; + int fd; + + assert(name); + assert(s); + + fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) + + offsetof(struct kdbus_item, data64) + sizeof(uint64_t) + + offsetof(struct kdbus_item, str) + + DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1)); + + make->size = offsetof(struct kdbus_cmd_make, items); + + n = make->items; + n->size = offsetof(struct kdbus_item, bloom_parameter) + + sizeof(struct kdbus_bloom_parameter); + n->type = KDBUS_ITEM_BLOOM_PARAMETER; + + n->bloom_parameter.size = DEFAULT_BLOOM_SIZE; + n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH; + + assert_cc(DEFAULT_BLOOM_SIZE > 0); + assert_cc(DEFAULT_BLOOM_N_HASH > 0); + + make->size += ALIGN8(n->size); + + n = KDBUS_ITEM_NEXT(n); + sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name); + n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; + n->type = KDBUS_ITEM_MAKE_NAME; + make->size += ALIGN8(n->size); + + make->flags = KDBUS_MAKE_POLICY_OPEN | (world ? KDBUS_MAKE_ACCESS_WORLD : 0); + + if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* The higher 32bit of the flags field are considered + * 'incompatible flags'. Refuse them all for now. */ + if (make->flags > 0xFFFFFFFFULL) { + close_nointr_nofail(fd); + return -ENOTSUP; + } + + if (s) { + char *p; + + p = strjoin("/dev/kdbus/", n->str, "/bus", NULL); + if (!p) { + close_nointr_nofail(fd); + return -ENOMEM; + } + + *s = p; + } + + return fd; +} + +int bus_kernel_create_starter(const char *bus, const char *name) { + struct kdbus_cmd_hello *hello; + struct kdbus_item *n; + char *p; + int fd; + + assert(bus); + assert(name); + + p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus")); + sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus); + + fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + hello = alloca0(ALIGN8(offsetof(struct kdbus_cmd_hello, items) + + offsetof(struct kdbus_item, str) + + strlen(name) + 1)); + + n = hello->items; + strcpy(n->str, name); + n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; + n->type = KDBUS_ITEM_NAME; + + hello->size = ALIGN8(offsetof(struct kdbus_cmd_hello, items) + n->size); + hello->conn_flags = KDBUS_HELLO_ACTIVATOR; + hello->pool_size = KDBUS_POOL_SIZE; + + if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* The higher 32bit of both flags fields are considered + * 'incompatible flags'. Refuse them all for now. */ + if (hello->bus_flags > 0xFFFFFFFFULL || + hello->conn_flags > 0xFFFFFFFFULL) { + close_nointr_nofail(fd); + return -ENOTSUP; + } + + if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash)) { + close_nointr_nofail(fd); + return -ENOTSUP; + } + + return fd; +} + +int bus_kernel_create_domain(const char *name, char **s) { + struct kdbus_cmd_make *make; + struct kdbus_item *n; + int fd; + + assert(name); + assert(s); + + fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) + + offsetof(struct kdbus_item, str) + + strlen(name) + 1)); + + n = make->items; + strcpy(n->str, name); + n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; + n->type = KDBUS_ITEM_MAKE_NAME; + + make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size); + make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD; + + if (ioctl(fd, KDBUS_CMD_DOMAIN_MAKE, make) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* The higher 32bit of the flags field are considered + * 'incompatible flags'. Refuse them all for now. */ + if (make->flags > 0xFFFFFFFFULL) { + close_nointr_nofail(fd); + return -ENOTSUP; + } + + if (s) { + char *p; + + p = strappend("/dev/kdbus/domain/", name); + if (!p) { + close_nointr_nofail(fd); + return -ENOMEM; + } + + *s = p; + } + + return fd; +} + +int bus_kernel_create_monitor(const char *bus) { + struct kdbus_cmd_hello *hello; + char *p; + int fd; + + assert(bus); + + p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus")); + sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus); + + fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + hello = alloca0(sizeof(struct kdbus_cmd_hello)); + hello->size = sizeof(struct kdbus_cmd_hello); + hello->conn_flags = KDBUS_HELLO_ACTIVATOR; + hello->pool_size = KDBUS_POOL_SIZE; + + if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* The higher 32bit of both flags fields are considered + * 'incompatible flags'. Refuse them all for now. */ + if (hello->bus_flags > 0xFFFFFFFFULL || + hello->conn_flags > 0xFFFFFFFFULL) { + close_nointr_nofail(fd); + return -ENOTSUP; + } + + return fd; +} + +int bus_kernel_try_close(sd_bus *bus) { + assert(bus); + assert(bus->is_kernel); + + if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0) + return -errno; + + return 0; +} + +int bus_kernel_drop_one(int fd) { + struct kdbus_cmd_recv recv = { + .flags = KDBUS_RECV_DROP + }; + + assert(fd >= 0); + + if (ioctl(fd, KDBUS_CMD_MSG_RECV, &recv) < 0) + return -errno; + + return 0; +} diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h new file mode 100644 index 0000000..8db418a --- /dev/null +++ b/src/libsystemd/sd-bus/bus-kernel.h @@ -0,0 +1,83 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" + +#define KDBUS_ITEM_NEXT(item) \ + (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size)) + +#define KDBUS_ITEM_FOREACH(part, head, first) \ + for (part = (head)->first; \ + (uint8_t *)(part) < (uint8_t *)(head) + (head)->size; \ + part = KDBUS_ITEM_NEXT(part)) + +#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) +#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) + +#define MEMFD_CACHE_MAX 32 + +/* When we cache a memfd block for reuse, we will truncate blocks + * longer than this in order not to keep too much data around. */ +#define MEMFD_CACHE_ITEM_SIZE_MAX (128*1024) + +/* This determines at which minimum size we prefer sending memfds over + * sending vectors */ +#define MEMFD_MIN_SIZE (512*1024) + +/* The size of the per-connection memory pool that we set up and where + * the kernel places our incoming messages */ +#define KDBUS_POOL_SIZE (16*1024*1024) + +struct memfd_cache { + int fd; + void *address; + size_t mapped; + size_t allocated; +}; + +int bus_kernel_connect(sd_bus *b); +int bus_kernel_take_fd(sd_bus *b); + +int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call); +int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority); + +int bus_kernel_create_bus(const char *name, bool world, char **s); +int bus_kernel_create_domain(const char *name, char **s); +int bus_kernel_create_starter(const char *bus, const char *name); +int bus_kernel_create_monitor(const char *bus); + +int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated); +void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated); + +void bus_kernel_flush_memfd(sd_bus *bus); + +int bus_kernel_parse_unique_name(const char *s, uint64_t *id); + +int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags); +int kdbus_translate_attach_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags); + +int bus_kernel_try_close(sd_bus *bus); + +int bus_kernel_drop_one(int fd); diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c new file mode 100644 index 0000000..8280488 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-match.c @@ -0,0 +1,1078 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-match.h" +#include "bus-error.h" +#include "bus-util.h" +#include "strv.h" + +/* Example: + * + * A: type=signal,sender=foo,interface=bar + * B: type=signal,sender=quux,interface=fips + * C: type=signal,sender=quux,interface=waldo + * D: type=signal,member=test + * E: sender=miau + * F: type=signal + * G: type=signal + * + * results in this tree: + * + * BUS_MATCH_ROOT + * + BUS_MATCH_MESSAGE_TYPE + * | ` BUS_MATCH_VALUE: value == signal + * | + DBUS_MATCH_SENDER + * | | + BUS_MATCH_VALUE: value == foo + * | | | ` DBUS_MATCH_INTERFACE + * | | | ` BUS_MATCH_VALUE: value == bar + * | | | ` BUS_MATCH_LEAF: A + * | | ` BUS_MATCH_VALUE: value == quux + * | | ` DBUS_MATCH_INTERFACE + * | | | BUS_MATCH_VALUE: value == fips + * | | | ` BUS_MATCH_LEAF: B + * | | ` BUS_MATCH_VALUE: value == waldo + * | | ` BUS_MATCH_LEAF: C + * | + DBUS_MATCH_MEMBER + * | | ` BUS_MATCH_VALUE: value == test + * | | ` BUS_MATCH_LEAF: D + * | + BUS_MATCH_LEAF: F + * | ` BUS_MATCH_LEAF: G + * ` BUS_MATCH_SENDER + * ` BUS_MATCH_VALUE: value == miau + * ` BUS_MATCH_LEAF: E + */ + +static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { + return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST; +} + +static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { + return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) || + (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST); +} + +static void bus_match_node_free(struct bus_match_node *node) { + assert(node); + assert(node->parent); + assert(!node->child); + assert(node->type != BUS_MATCH_ROOT); + assert(node->type < _BUS_MATCH_NODE_TYPE_MAX); + + if (node->parent->child) { + /* We are apparently linked into the parent's child + * list. Let's remove us from there. */ + if (node->prev) { + assert(node->prev->next == node); + node->prev->next = node->next; + } else { + assert(node->parent->child == node); + node->parent->child = node->next; + } + + if (node->next) + node->next->prev = node->prev; + } + + if (node->type == BUS_MATCH_VALUE) { + /* We might be in the parent's hash table, so clean + * this up */ + + if (node->parent->type == BUS_MATCH_MESSAGE_TYPE) + hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8)); + else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str) + hashmap_remove(node->parent->compare.children, node->value.str); + + free(node->value.str); + } + + if (BUS_MATCH_IS_COMPARE(node->type)) { + assert(hashmap_isempty(node->compare.children)); + hashmap_free(node->compare.children); + } + + free(node); +} + +static bool bus_match_node_maybe_free(struct bus_match_node *node) { + assert(node); + + if (node->child) + return false; + + if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children)) + return true; + + bus_match_node_free(node); + return true; +} + +static bool value_node_test( + struct bus_match_node *node, + enum bus_match_node_type parent_type, + uint8_t value_u8, + const char *value_str, + sd_bus_message *m) { + + assert(node); + assert(node->type == BUS_MATCH_VALUE); + + /* Tests parameters against this value node, doing prefix + * magic and stuff. */ + + switch (parent_type) { + + case BUS_MATCH_MESSAGE_TYPE: + return node->value.u8 == value_u8; + + case BUS_MATCH_SENDER: + if (streq_ptr(node->value.str, value_str)) + return true; + + if (m->creds.mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) { + char **i; + + /* on kdbus we have the well known names list + * in the credentials, let's make use of that + * for an accurate match */ + + STRV_FOREACH(i, m->creds.well_known_names) + if (streq_ptr(node->value.str, *i)) + return true; + + } else { + + /* If we don't have kdbus, we don't know the + * well-known names of the senders. In that, + * let's just hope that dbus-daemon doesn't + * send us stuff we didn't want. */ + + if (node->value.str[0] != ':' && value_str && value_str[0] == ':') + return true; + } + + return false; + + case BUS_MATCH_DESTINATION: + case BUS_MATCH_INTERFACE: + case BUS_MATCH_MEMBER: + case BUS_MATCH_PATH: + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + return streq_ptr(node->value.str, value_str); + + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: + return namespace_simple_pattern(node->value.str, value_str); + + case BUS_MATCH_PATH_NAMESPACE: + return path_simple_pattern(node->value.str, value_str); + + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: + return path_complex_pattern(node->value.str, value_str); + + default: + assert_not_reached("Invalid node type"); + } +} + +static bool value_node_same( + struct bus_match_node *node, + enum bus_match_node_type parent_type, + uint8_t value_u8, + const char *value_str) { + + /* Tests parameters against this value node, not doing prefix + * magic and stuff, i.e. this one actually compares the match + * itself.*/ + + assert(node); + assert(node->type == BUS_MATCH_VALUE); + + switch (parent_type) { + + case BUS_MATCH_MESSAGE_TYPE: + return node->value.u8 == value_u8; + + case BUS_MATCH_SENDER: + case BUS_MATCH_DESTINATION: + case BUS_MATCH_INTERFACE: + case BUS_MATCH_MEMBER: + case BUS_MATCH_PATH: + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: + case BUS_MATCH_PATH_NAMESPACE: + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: + return streq(node->value.str, value_str); + + default: + assert_not_reached("Invalid node type"); + } +} + +int bus_match_run( + sd_bus *bus, + struct bus_match_node *node, + sd_bus_message *m) { + + + const char *test_str = NULL; + uint8_t test_u8 = 0; + int r; + + assert(m); + + if (!node) + return 0; + + if (bus && bus->match_callbacks_modified) + return 0; + + /* Not these special semantics: when traversing the tree we + * usually let bus_match_run() when called for a node + * recursively invoke bus_match_run(). There's are two + * exceptions here though, which are BUS_NODE_ROOT (which + * cannot have a sibling), and BUS_NODE_VALUE (whose siblings + * are invoked anyway by its parent. */ + + switch (node->type) { + + case BUS_MATCH_ROOT: + + /* Run all children. Since we cannot have any siblings + * we won't call any. The children of the root node + * are compares or leaves, they will automatically + * call their siblings. */ + return bus_match_run(bus, node->child, m); + + case BUS_MATCH_VALUE: + + /* Run all children. We don't execute any siblings, we + * assume our caller does that. The children of value + * nodes are compares or leaves, they will + * automatically call their siblings */ + + assert(node->child); + return bus_match_run(bus, node->child, m); + + case BUS_MATCH_LEAF: + + if (bus) { + if (node->leaf.last_iteration == bus->iteration_counter) + return 0; + + node->leaf.last_iteration = bus->iteration_counter; + } + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + /* Run the callback. And then invoke siblings. */ + if (node->leaf.callback) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + + r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + if (r != 0) + return r; + } + + return bus_match_run(bus, node->next, m); + + case BUS_MATCH_MESSAGE_TYPE: + test_u8 = m->header->type; + break; + + case BUS_MATCH_SENDER: + test_str = m->sender; + /* FIXME: resolve test_str from a well-known to a unique name first */ + break; + + case BUS_MATCH_DESTINATION: + test_str = m->destination; + break; + + case BUS_MATCH_INTERFACE: + test_str = m->interface; + break; + + case BUS_MATCH_MEMBER: + test_str = m->member; + break; + + case BUS_MATCH_PATH: + case BUS_MATCH_PATH_NAMESPACE: + test_str = m->path; + break; + + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG); + break; + + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: + test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH); + break; + + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: + test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE); + break; + + default: + assert_not_reached("Unknown match type."); + } + + if (BUS_MATCH_CAN_HASH(node->type)) { + struct bus_match_node *found; + + /* Lookup via hash table, nice! So let's jump directly. */ + + if (test_str) + found = hashmap_get(node->compare.children, test_str); + else if (node->type == BUS_MATCH_MESSAGE_TYPE) + found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8)); + else + found = NULL; + + if (found) { + r = bus_match_run(bus, found, m); + if (r != 0) + return r; + } + } else { + struct bus_match_node *c; + + /* No hash table, so let's iterate manually... */ + + for (c = node->child; c; c = c->next) { + if (!value_node_test(c, node->type, test_u8, test_str, m)) + continue; + + r = bus_match_run(bus, c, m); + if (r != 0) + return r; + } + } + + if (bus && bus->match_callbacks_modified) + return 0; + + /* And now, let's invoke our siblings */ + return bus_match_run(bus, node->next, m); +} + +static int bus_match_add_compare_value( + struct bus_match_node *where, + enum bus_match_node_type t, + uint8_t value_u8, + const char *value_str, + struct bus_match_node **ret) { + + struct bus_match_node *c = NULL, *n = NULL; + int r; + + assert(where); + assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(BUS_MATCH_IS_COMPARE(t)); + assert(ret); + + for (c = where->child; c && c->type != t; c = c->next) + ; + + if (c) { + /* Comparison node already exists? Then let's see if + * the value node exists too. */ + + if (t == BUS_MATCH_MESSAGE_TYPE) + n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); + else if (BUS_MATCH_CAN_HASH(t)) + n = hashmap_get(c->compare.children, value_str); + else { + for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) + ; + } + + if (n) { + *ret = n; + return 0; + } + } else { + /* Comparison node, doesn't exist yet? Then let's + * create it. */ + + c = new0(struct bus_match_node, 1); + if (!c) { + r = -ENOMEM; + goto fail; + } + + c->type = t; + c->parent = where; + c->next = where->child; + if (c->next) + c->next->prev = c; + where->child = c; + + if (t == BUS_MATCH_MESSAGE_TYPE) { + c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func); + if (!c->compare.children) { + r = -ENOMEM; + goto fail; + } + } else if (BUS_MATCH_CAN_HASH(t)) { + c->compare.children = hashmap_new(string_hash_func, string_compare_func); + if (!c->compare.children) { + r = -ENOMEM; + goto fail; + } + } + } + + n = new0(struct bus_match_node, 1); + if (!n) { + r = -ENOMEM; + goto fail; + } + + n->type = BUS_MATCH_VALUE; + n->value.u8 = value_u8; + if (value_str) { + n->value.str = strdup(value_str); + if (!n->value.str) { + r = -ENOMEM; + goto fail; + } + } + + n->parent = c; + if (c->compare.children) { + + if (t == BUS_MATCH_MESSAGE_TYPE) + r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n); + else + r = hashmap_put(c->compare.children, n->value.str, n); + + if (r < 0) + goto fail; + } else { + n->next = c->child; + if (n->next) + n->next->prev = n; + c->child = n; + } + + *ret = n; + return 1; + +fail: + if (c) + bus_match_node_maybe_free(c); + + if (n) { + free(n->value.str); + free(n); + } + + return r; +} + +static int bus_match_find_compare_value( + struct bus_match_node *where, + enum bus_match_node_type t, + uint8_t value_u8, + const char *value_str, + struct bus_match_node **ret) { + + struct bus_match_node *c, *n; + + assert(where); + assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(BUS_MATCH_IS_COMPARE(t)); + assert(ret); + + for (c = where->child; c && c->type != t; c = c->next) + ; + + if (!c) + return 0; + + if (t == BUS_MATCH_MESSAGE_TYPE) + n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); + else if (BUS_MATCH_CAN_HASH(t)) + n = hashmap_get(c->compare.children, value_str); + else { + for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next) + ; + } + + if (n) { + *ret = n; + return 1; + } + + return 0; +} + +static int bus_match_add_leaf( + struct bus_match_node *where, + sd_bus_message_handler_t callback, + void *userdata, + uint64_t cookie, + struct bus_match_node **ret) { + + struct bus_match_node *n; + + assert(where); + assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(ret); + + n = new0(struct bus_match_node, 1); + if (!n) + return -ENOMEM; + + n->type = BUS_MATCH_LEAF; + n->parent = where; + n->next = where->child; + if (n->next) + n->next->prev = n; + n->leaf.callback = callback; + n->leaf.userdata = userdata; + n->leaf.cookie = cookie; + + where->child = n; + + *ret = n; + return 1; +} + +static int bus_match_find_leaf( + struct bus_match_node *where, + sd_bus_message_handler_t callback, + void *userdata, + struct bus_match_node **ret) { + + struct bus_match_node *c; + + assert(where); + assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); + assert(ret); + + for (c = where->child; c; c = c->next) { + if (c->type == BUS_MATCH_LEAF && + c->leaf.callback == callback && + c->leaf.userdata == userdata) { + *ret = c; + return 1; + } + } + + return 0; +} + +enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n) { + assert(k); + + if (n == 4 && startswith(k, "type")) + return BUS_MATCH_MESSAGE_TYPE; + if (n == 6 && startswith(k, "sender")) + return BUS_MATCH_SENDER; + if (n == 11 && startswith(k, "destination")) + return BUS_MATCH_DESTINATION; + if (n == 9 && startswith(k, "interface")) + return BUS_MATCH_INTERFACE; + if (n == 6 && startswith(k, "member")) + return BUS_MATCH_MEMBER; + if (n == 4 && startswith(k, "path")) + return BUS_MATCH_PATH; + if (n == 14 && startswith(k, "path_namespace")) + return BUS_MATCH_PATH_NAMESPACE; + + if (n == 4 && startswith(k, "arg")) { + int j; + + j = undecchar(k[3]); + if (j < 0) + return -EINVAL; + + return BUS_MATCH_ARG + j; + } + + if (n == 5 && startswith(k, "arg")) { + int a, b; + enum bus_match_node_type t; + + a = undecchar(k[3]); + b = undecchar(k[4]); + if (a <= 0 || b < 0) + return -EINVAL; + + t = BUS_MATCH_ARG + a * 10 + b; + if (t > BUS_MATCH_ARG_LAST) + return -EINVAL; + + return t; + } + + if (n == 8 && startswith(k, "arg") && startswith(k + 4, "path")) { + int j; + + j = undecchar(k[3]); + if (j < 0) + return -EINVAL; + + return BUS_MATCH_ARG_PATH + j; + } + + if (n == 9 && startswith(k, "arg") && startswith(k + 5, "path")) { + enum bus_match_node_type t; + int a, b; + + a = undecchar(k[3]); + b = undecchar(k[4]); + if (a <= 0 || b < 0) + return -EINVAL; + + t = BUS_MATCH_ARG_PATH + a * 10 + b; + if (t > BUS_MATCH_ARG_PATH_LAST) + return -EINVAL; + + return t; + } + + if (n == 13 && startswith(k, "arg") && startswith(k + 4, "namespace")) { + int j; + + j = undecchar(k[3]); + if (j < 0) + return -EINVAL; + + return BUS_MATCH_ARG_NAMESPACE + j; + } + + if (n == 14 && startswith(k, "arg") && startswith(k + 5, "namespace")) { + enum bus_match_node_type t; + int a, b; + + a = undecchar(k[3]); + b = undecchar(k[4]); + if (a <= 0 || b < 0) + return -EINVAL; + + t = BUS_MATCH_ARG_NAMESPACE + a * 10 + b; + if (t > BUS_MATCH_ARG_NAMESPACE_LAST) + return -EINVAL; + + return t; + } + + return -EINVAL; +} + +static int match_component_compare(const void *a, const void *b) { + const struct bus_match_component *x = a, *y = b; + + if (x->type < y->type) + return -1; + if (x->type > y->type) + return 1; + + return 0; +} + +void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) { + unsigned i; + + for (i = 0; i < n_components; i++) + free(components[i].value_str); + + free(components); +} + +int bus_match_parse( + const char *match, + struct bus_match_component **_components, + unsigned *_n_components) { + + const char *p = match; + struct bus_match_component *components = NULL; + size_t components_allocated = 0; + unsigned n_components = 0, i; + _cleanup_free_ char *value = NULL; + int r; + + assert(match); + assert(_components); + assert(_n_components); + + while (*p != 0) { + const char *eq, *q; + enum bus_match_node_type t; + unsigned j = 0; + size_t value_allocated = 0; + bool escaped = false, quoted; + uint8_t u; + + eq = strchr(p, '='); + if (!eq) + return -EINVAL; + + t = bus_match_node_type_from_string(p, eq - p); + if (t < 0) + return -EINVAL; + + quoted = eq[1] == '\''; + + for (q = eq + 1 + quoted;; q++) { + + if (*q == 0) { + + if (quoted) { + r = -EINVAL; + goto fail; + } else { + if (value) + value[j] = 0; + break; + } + } + + if (!escaped) { + if (*q == '\\') { + escaped = true; + continue; + } + + if (quoted) { + if (*q == '\'') { + if (value) + value[j] = 0; + break; + } + } else { + if (*q == ',') { + if (value) + value[j] = 0; + + break; + } + } + } + + if (!GREEDY_REALLOC(value, value_allocated, j + 2)) { + r = -ENOMEM; + goto fail; + } + + value[j++] = *q; + escaped = false; + } + + if (!value) { + value = strdup(""); + if (!value) { + r = -ENOMEM; + goto fail; + } + } + + if (t == BUS_MATCH_MESSAGE_TYPE) { + r = bus_message_type_from_string(value, &u); + if (r < 0) + goto fail; + + free(value); + value = NULL; + } else + u = 0; + + if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) { + r = -ENOMEM; + goto fail; + } + + components[n_components].type = t; + components[n_components].value_str = value; + components[n_components].value_u8 = u; + n_components++; + + value = NULL; + + if (q[quoted] == 0) + break; + + if (q[quoted] != ',') { + r = -EINVAL; + goto fail; + } + + p = q + 1 + quoted; + } + + /* Order the whole thing, so that we always generate the same tree */ + qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare); + + /* Check for duplicates */ + for (i = 0; i+1 < n_components; i++) + if (components[i].type == components[i+1].type) { + r = -EINVAL; + goto fail; + } + + *_components = components; + *_n_components = n_components; + + return 0; + +fail: + bus_match_parse_free(components, n_components); + return r; +} + +char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { + _cleanup_free_ FILE *f = NULL; + char *buffer = NULL; + size_t size = 0; + unsigned i; + + if (n_components <= 0) + return strdup(""); + + assert(components); + + f = open_memstream(&buffer, &size); + if (!f) + return NULL; + + for (i = 0; i < n_components; i++) { + char buf[32]; + + if (i != 0) + fputc(',', f); + + fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f); + fputc('=', f); + fputc('\'', f); + + if (components[i].type == BUS_MATCH_MESSAGE_TYPE) + fputs(bus_message_type_to_string(components[i].value_u8), f); + else + fputs(components[i].value_str, f); + + fputc('\'', f); + } + + fflush(f); + if (ferror(f)) + return NULL; + + return buffer; +} + +int bus_match_add( + struct bus_match_node *root, + struct bus_match_component *components, + unsigned n_components, + sd_bus_message_handler_t callback, + void *userdata, + uint64_t cookie, + struct bus_match_node **ret) { + + unsigned i; + struct bus_match_node *n; + int r; + + assert(root); + + n = root; + for (i = 0; i < n_components; i++) { + r = bus_match_add_compare_value( + n, components[i].type, + components[i].value_u8, components[i].value_str, &n); + if (r < 0) + return r; + } + + r = bus_match_add_leaf(n, callback, userdata, cookie, &n); + if (r < 0) + return r; + + if (ret) + *ret = n; + + return 0; +} + +int bus_match_remove( + struct bus_match_node *root, + struct bus_match_component *components, + unsigned n_components, + sd_bus_message_handler_t callback, + void *userdata, + uint64_t *cookie) { + + unsigned i; + struct bus_match_node *n, **gc; + int r; + + assert(root); + + gc = newa(struct bus_match_node*, n_components); + + n = root; + for (i = 0; i < n_components; i++) { + r = bus_match_find_compare_value( + n, components[i].type, + components[i].value_u8, components[i].value_str, + &n); + if (r <= 0) + return r; + + gc[i] = n; + } + + r = bus_match_find_leaf(n, callback, userdata, &n); + if (r <= 0) + return r; + + if (cookie) + *cookie = n->leaf.cookie; + + /* Free the leaf */ + bus_match_node_free(n); + + /* Prune the tree above */ + for (i = n_components; i > 0; i --) { + struct bus_match_node *p = gc[i-1]->parent; + + if (!bus_match_node_maybe_free(gc[i-1])) + break; + + if (!bus_match_node_maybe_free(p)) + break; + } + + return r; +} + +void bus_match_free(struct bus_match_node *node) { + struct bus_match_node *c; + + if (!node) + return; + + if (BUS_MATCH_CAN_HASH(node->type)) { + Iterator i; + + HASHMAP_FOREACH(c, node->compare.children, i) + bus_match_free(c); + + assert(hashmap_isempty(node->compare.children)); + } + + while ((c = node->child)) + bus_match_free(c); + + if (node->type != BUS_MATCH_ROOT) + bus_match_node_free(node); +} + +const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l) { + switch (t) { + + case BUS_MATCH_ROOT: + return "root"; + + case BUS_MATCH_VALUE: + return "value"; + + case BUS_MATCH_LEAF: + return "leaf"; + + case BUS_MATCH_MESSAGE_TYPE: + return "type"; + + case BUS_MATCH_SENDER: + return "sender"; + + case BUS_MATCH_DESTINATION: + return "destination"; + + case BUS_MATCH_INTERFACE: + return "interface"; + + case BUS_MATCH_MEMBER: + return "member"; + + case BUS_MATCH_PATH: + return "path"; + + case BUS_MATCH_PATH_NAMESPACE: + return "path_namespace"; + + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + snprintf(buf, l, "arg%i", t - BUS_MATCH_ARG); + return buf; + + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: + snprintf(buf, l, "arg%ipath", t - BUS_MATCH_ARG_PATH); + return buf; + + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: + snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE); + return buf; + + default: + return NULL; + } +} + +void bus_match_dump(struct bus_match_node *node, unsigned level) { + struct bus_match_node *c; + _cleanup_free_ char *pfx = NULL; + char buf[32]; + + if (!node) + return; + + pfx = strrep(" ", level); + printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf))); + + if (node->type == BUS_MATCH_VALUE) { + if (node->parent->type == BUS_MATCH_MESSAGE_TYPE) + printf(" <%u>\n", node->value.u8); + else + printf(" <%s>\n", node->value.str); + } else if (node->type == BUS_MATCH_ROOT) + puts(" root"); + else if (node->type == BUS_MATCH_LEAF) + printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata); + else + putchar('\n'); + + if (BUS_MATCH_CAN_HASH(node->type)) { + Iterator i; + + HASHMAP_FOREACH(c, node->compare.children, i) + bus_match_dump(c, level + 1); + } + + for (c = node->child; c; c = c->next) + bus_match_dump(c, level + 1); +} diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h new file mode 100644 index 0000000..056082b --- /dev/null +++ b/src/libsystemd/sd-bus/bus-match.h @@ -0,0 +1,93 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "hashmap.h" + +#include "sd-bus.h" + +enum bus_match_node_type { + BUS_MATCH_ROOT, + BUS_MATCH_VALUE, + BUS_MATCH_LEAF, + + /* The following are all different kinds of compare nodes */ + BUS_MATCH_SENDER, + BUS_MATCH_MESSAGE_TYPE, + BUS_MATCH_DESTINATION, + BUS_MATCH_INTERFACE, + BUS_MATCH_MEMBER, + BUS_MATCH_PATH, + BUS_MATCH_PATH_NAMESPACE, + BUS_MATCH_ARG, + BUS_MATCH_ARG_LAST = BUS_MATCH_ARG + 63, + BUS_MATCH_ARG_PATH, + BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63, + BUS_MATCH_ARG_NAMESPACE, + BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63, + _BUS_MATCH_NODE_TYPE_MAX, + _BUS_MATCH_NODE_TYPE_INVALID = -1 +}; + +struct bus_match_node { + enum bus_match_node_type type; + struct bus_match_node *parent, *next, *prev, *child; + + union { + struct { + char *str; + uint8_t u8; + } value; + struct { + sd_bus_message_handler_t callback; + void *userdata; + unsigned last_iteration; + uint64_t cookie; + } leaf; + struct { + /* If this is set, then the child is NULL */ + Hashmap *children; + } compare; + }; +}; + +struct bus_match_component { + enum bus_match_node_type type; + uint8_t value_u8; + char *value_str; +}; + +int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m); + +int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t cookie, struct bus_match_node **ret); +int bus_match_remove(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t *cookie); + +void bus_match_free(struct bus_match_node *node); + +void bus_match_dump(struct bus_match_node *node, unsigned level); + +const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l); +enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n); + +int bus_match_parse(const char *match, struct bus_match_component **_components, unsigned *_n_components); +void bus_match_parse_free(struct bus_match_component *components, unsigned n_components); +char *bus_match_to_string(struct bus_match_component *components, unsigned n_components); diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c new file mode 100644 index 0000000..fb894ef --- /dev/null +++ b/src/libsystemd/sd-bus/bus-message.c @@ -0,0 +1,5567 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "utf8.h" +#include "strv.h" +#include "time-util.h" +#include "cgroup-util.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-internal.h" +#include "bus-type.h" +#include "bus-signature.h" +#include "bus-gvariant.h" +#include "bus-util.h" + +static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); + +static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) { + + if (p == NULL) + return NULL; + + if (old_base == new_base) + return (void*) p; + + if ((uint8_t*) p < (uint8_t*) old_base) + return (void*) p; + + if ((uint8_t*) p >= (uint8_t*) old_base + sz) + return (void*) p; + + return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base); +} + +static void message_free_part(sd_bus_message *m, struct bus_body_part *part) { + assert(m); + assert(part); + + if (part->memfd >= 0) { + /* If we can reuse the memfd, try that. For that it + * can't be sealed yet. */ + + if (!part->sealed) + bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated); + else { + if (part->mapped > 0) + assert_se(munmap(part->data, part->mapped) == 0); + + close_nointr_nofail(part->memfd); + } + + } else if (part->munmap_this) + munmap(part->data, part->mapped); + else if (part->free_this) + free(part->data); + + if (part != &m->body) + free(part); +} + +static void message_reset_parts(sd_bus_message *m) { + struct bus_body_part *part; + + assert(m); + + part = &m->body; + while (m->n_body_parts > 0) { + struct bus_body_part *next = part->next; + message_free_part(m, part); + part = next; + m->n_body_parts--; + } + + m->body_end = NULL; + + m->cached_rindex_part = NULL; + m->cached_rindex_part_begin = 0; +} + +static void message_reset_containers(sd_bus_message *m) { + unsigned i; + + assert(m); + + for (i = 0; i < m->n_containers; i++) { + free(m->containers[i].signature); + free(m->containers[i].offsets); + } + + free(m->containers); + m->containers = NULL; + + m->n_containers = m->containers_allocated = 0; + m->root_container.index = 0; +} + +static void message_free(sd_bus_message *m) { + assert(m); + + if (m->free_header) + free(m->header); + + message_reset_parts(m); + + if (m->free_kdbus) + free(m->kdbus); + + if (m->release_kdbus) { + uint64_t off; + + off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer; + ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off); + } + + if (m->bus) + sd_bus_unref(m->bus); + + if (m->free_fds) { + close_many(m->fds, m->n_fds); + free(m->fds); + } + + if (m->iovec != m->iovec_fixed) + free(m->iovec); + + message_reset_containers(m); + free(m->root_container.signature); + free(m->root_container.offsets); + + free(m->root_container.peeked_signature); + + bus_creds_done(&m->creds); + free(m); +} + +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; + + assert(m); + + if (m->poisoned) + return NULL; + + old_size = sizeof(struct bus_header) + m->header->fields_size; + start = ALIGN_TO(old_size, align); + new_size = start + sz; + + if (old_size == new_size) + return (uint8_t*) m->header + old_size; + + if (new_size > (size_t) ((uint32_t) -1)) + goto poison; + + if (m->free_header) { + np = realloc(m->header, ALIGN8(new_size)); + if (!np) + goto poison; + } else { + /* Initially, the header is allocated as part of of + * the sd_bus_message itself, let's replace it by + * dynamic data */ + + np = malloc(ALIGN8(new_size)); + if (!np) + goto poison; + + memcpy(np, m->header, sizeof(struct bus_header)); + } + + /* Zero out padding */ + if (start > old_size) + memzero((uint8_t*) np + old_size, start - old_size); + + op = m->header; + m->header = np; + m->header->fields_size = new_size - sizeof(struct bus_header); + + /* Adjust quick access pointers */ + m->path = adjust_pointer(m->path, op, old_size, m->header); + m->interface = adjust_pointer(m->interface, op, old_size, m->header); + m->member = adjust_pointer(m->member, op, old_size, m->header); + m->destination = adjust_pointer(m->destination, op, old_size, m->header); + m->sender = adjust_pointer(m->sender, op, old_size, m->header); + m->error.name = adjust_pointer(m->error.name, op, old_size, m->header); + + m->free_header = true; + + if (add_offset) { + if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets)) + goto poison; + + m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header); + } + + return (uint8_t*) np + start; + +poison: + m->poisoned = true; + return NULL; +} + +static int message_append_field_string( + sd_bus_message *m, + uint8_t h, + char type, + const char *s, + const char **ret) { + + size_t l; + uint8_t *p; + + assert(m); + + /* dbus1 doesn't allow strings over 32bit, let's enforce this + * globally, to not risk convertability */ + l = strlen(s); + if (l > (size_t) (uint32_t) -1) + return -EINVAL; + + /* Signature "(yv)" where the variant contains "s" */ + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + + /* (field id byte + 7x padding, ((string + NUL) + NUL + signature string 's') */ + p = message_extend_fields(m, 8, 1 + 7 + l + 1 + 1 + 1, true); + if (!p) + return -ENOMEM; + + p[0] = h; + memzero(p+1, 7); + memcpy(p+8, s, l); + p[8+l] = 0; + p[8+l+1] = 0; + p[8+l+2] = type; + + if (ret) + *ret = (char*) p + 8; + + } else { + /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */ + p = message_extend_fields(m, 8, 4 + 4 + l + 1, false); + if (!p) + return -ENOMEM; + + p[0] = h; + p[1] = 1; + p[2] = type; + p[3] = 0; + + ((uint32_t*) p)[1] = l; + memcpy(p + 8, s, l + 1); + + if (ret) + *ret = (char*) p + 8; + } + + return 0; +} + +static int message_append_field_signature( + sd_bus_message *m, + uint8_t h, + const char *s, + const char **ret) { + + size_t l; + uint8_t *p; + + assert(m); + + /* dbus1 doesn't allow signatures over 32bit, let's enforce + * this globally, to not risk convertability */ + l = strlen(s); + if (l > 255) + return -EINVAL; + + /* Signature "(yv)" where the variant contains "g" */ + + if (BUS_MESSAGE_IS_GVARIANT(m)) + /* For gvariant the serialization is the same as for normal strings */ + return message_append_field_string(m, h, 'g', s, ret); + else { + /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */ + p = message_extend_fields(m, 8, 4 + 1 + l + 1, false); + if (!p) + return -ENOMEM; + + p[0] = h; + p[1] = 1; + p[2] = SD_BUS_TYPE_SIGNATURE; + p[3] = 0; + p[4] = l; + memcpy(p + 5, s, l + 1); + + if (ret) + *ret = (const char*) p + 5; + } + + return 0; +} + +static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) { + uint8_t *p; + + assert(m); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + /* (field id byte + 7x padding + ((value + NUL + signature string 'u') */ + + p = message_extend_fields(m, 8, 1 + 7 + 4 + 1 + 1, true); + if (!p) + return -ENOMEM; + + p[0] = h; + memzero(p+1, 7); + *((uint32_t*) (p + 8)) = x; + p[12] = 0; + p[13] = 'u'; + } else { + /* (field id byte + (signature length + signature 'u' + NUL) + value) */ + p = message_extend_fields(m, 8, 4 + 4, false); + if (!p) + return -ENOMEM; + + p[0] = h; + p[1] = 1; + p[2] = SD_BUS_TYPE_UINT32; + p[3] = 0; + + ((uint32_t*) p)[1] = x; + } + + return 0; +} + +int bus_message_from_header( + sd_bus *bus, + void *buffer, + size_t length, + int *fds, + unsigned n_fds, + const struct ucred *ucred, + const char *label, + size_t extra, + sd_bus_message **ret) { + + sd_bus_message *m; + struct bus_header *h; + size_t a, label_sz; + + assert(buffer || length <= 0); + assert(fds || n_fds <= 0); + assert(ret); + + if (length < sizeof(struct bus_header)) + return -EBADMSG; + + h = buffer; + if (h->version != 1 && + h->version != 2) + return -EBADMSG; + + if (h->serial == 0) + return -EBADMSG; + + if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID) + return -EBADMSG; + + if (h->endian != BUS_LITTLE_ENDIAN && + h->endian != BUS_BIG_ENDIAN) + return -EBADMSG; + + a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra); + + if (label) { + label_sz = strlen(label); + a += label_sz + 1; + } + + m = malloc0(a); + if (!m) + return -ENOMEM; + + m->n_ref = 1; + m->sealed = true; + m->header = h; + m->fds = fds; + m->n_fds = n_fds; + + if (ucred) { + m->creds.uid = ucred->uid; + m->creds.pid = ucred->pid; + m->creds.gid = ucred->gid; + m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID; + } + + if (label) { + m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra); + memcpy(m->creds.label, label, label_sz + 1); + + m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + + if (bus) + m->bus = sd_bus_ref(bus); + + *ret = m; + return 0; +} + +int bus_message_from_malloc( + sd_bus *bus, + void *buffer, + size_t length, + int *fds, + unsigned n_fds, + const struct ucred *ucred, + const char *label, + sd_bus_message **ret) { + + sd_bus_message *m; + size_t sz; + int r; + + r = bus_message_from_header(bus, buffer, length, fds, n_fds, ucred, label, 0, &m); + if (r < 0) + return r; + + if (length != BUS_MESSAGE_SIZE(m)) { + r = -EBADMSG; + goto fail; + } + + sz = length - sizeof(struct bus_header) - ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)); + if (sz > 0) { + m->n_body_parts = 1; + m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)); + m->body.size = sz; + m->body.sealed = true; + m->body.memfd = -1; + } + + m->n_iovec = 1; + m->iovec = m->iovec_fixed; + m->iovec[0].iov_base = buffer; + m->iovec[0].iov_len = length; + + r = bus_message_parse_fields(m); + if (r < 0) + goto fail; + + /* We take possession of the memory and fds now */ + m->free_header = true; + m->free_fds = true; + + *ret = m; + return 0; + +fail: + message_free(m); + return r; +} + +static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { + sd_bus_message *m; + + m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header)); + if (!m) + return NULL; + + m->n_ref = 1; + m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message))); + m->header->endian = BUS_NATIVE_ENDIAN; + m->header->type = type; + m->header->version = bus ? bus->message_version : 1; + m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); + m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m); + + if (bus) + m->bus = sd_bus_ref(bus); + + return m; +} + +_public_ int sd_bus_message_new_signal( + sd_bus *bus, + sd_bus_message **m, + const char *path, + const char *interface, + const char *member) { + + sd_bus_message *t; + int r; + + assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(m, -EINVAL); + + t = message_new(bus, SD_BUS_MESSAGE_SIGNAL); + if (!t) + return -ENOMEM; + + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + + r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path); + if (r < 0) + goto fail; + r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface); + if (r < 0) + goto fail; + r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member); + if (r < 0) + goto fail; + + *m = t; + return 0; + +fail: + sd_bus_message_unref(t); + return r; +} + +_public_ int sd_bus_message_new_method_call( + sd_bus *bus, + sd_bus_message **m, + const char *destination, + const char *path, + const char *interface, + const char *member) { + + sd_bus_message *t; + int r; + + assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN); + assert_return(!destination || service_name_is_valid(destination), -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(!interface || interface_name_is_valid(interface), -EINVAL); + assert_return(member_name_is_valid(member), -EINVAL); + assert_return(m, -EINVAL); + + t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL); + if (!t) + return -ENOMEM; + + r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path); + if (r < 0) + goto fail; + r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member); + if (r < 0) + goto fail; + + if (interface) { + r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface); + if (r < 0) + goto fail; + } + + if (destination) { + r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination); + if (r < 0) + goto fail; + } + + *m = t; + return 0; + +fail: + message_free(t); + return r; +} + +static int message_new_reply( + sd_bus_message *call, + uint8_t type, + sd_bus_message **m) { + + sd_bus_message *t; + int r; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN); + assert_return(m, -EINVAL); + + t = message_new(call->bus, type); + if (!t) + return -ENOMEM; + + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + t->reply_cookie = BUS_MESSAGE_COOKIE(call); + + r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie); + if (r < 0) + goto fail; + + if (call->sender) { + r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination); + if (r < 0) + goto fail; + } + + t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED); + t->enforced_reply_signature = call->enforced_reply_signature; + + *m = t; + return 0; + +fail: + message_free(t); + return r; +} + +_public_ int sd_bus_message_new_method_return( + sd_bus_message *call, + sd_bus_message **m) { + + return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m); +} + +_public_ int sd_bus_message_new_method_error( + sd_bus_message *call, + sd_bus_message **m, + const sd_bus_error *e) { + + sd_bus_message *t; + int r; + + assert_return(sd_bus_error_is_set(e), -EINVAL); + assert_return(m, -EINVAL); + + r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t); + if (r < 0) + return r; + + r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name); + if (r < 0) + goto fail; + + if (e->message) { + r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message); + if (r < 0) + goto fail; + } + + t->error._need_free = -1; + + *m = t; + return 0; + +fail: + message_free(t); + return r; +} + +_public_ int sd_bus_message_new_method_errorf( + sd_bus_message *call, + sd_bus_message **m, + const char *name, + const char *format, + ...) { + + _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + va_list ap; + + assert_return(name, -EINVAL); + assert_return(m, -EINVAL); + + va_start(ap, format); + bus_error_setfv(&error, name, format, ap); + va_end(ap); + + return sd_bus_message_new_method_error(call, m, &error); +} + +_public_ int sd_bus_message_new_method_errno( + sd_bus_message *call, + sd_bus_message **m, + int error, + const sd_bus_error *p) { + + _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + + if (sd_bus_error_is_set(p)) + return sd_bus_message_new_method_error(call, m, p); + + sd_bus_error_set_errno(&berror, error); + + return sd_bus_message_new_method_error(call, m, &berror); +} + +_public_ int sd_bus_message_new_method_errnof( + sd_bus_message *call, + sd_bus_message **m, + int error, + const char *format, + ...) { + + _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + va_list ap; + + va_start(ap, format); + bus_error_set_errnofv(&berror, error, format, ap); + va_end(ap); + + return sd_bus_message_new_method_error(call, m, &berror); +} + +int bus_message_new_synthetic_error( + sd_bus *bus, + uint64_t cookie, + const sd_bus_error *e, + sd_bus_message **m) { + + sd_bus_message *t; + int r; + + assert(sd_bus_error_is_set(e)); + assert(m); + + t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR); + if (!t) + return -ENOMEM; + + t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + t->reply_cookie = cookie; + + r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie); + if (r < 0) + goto fail; + + if (bus && bus->unique_name) { + r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination); + if (r < 0) + goto fail; + } + + r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name); + if (r < 0) + goto fail; + + if (e->message) { + r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message); + if (r < 0) + goto fail; + } + + t->error._need_free = -1; + + *m = t; + return 0; + +fail: + message_free(t); + return r; +} + +_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { + assert_return(m, NULL); + + assert(m->n_ref > 0); + m->n_ref++; + + return m; +} + +_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { + + if (!m) + return NULL; + + assert(m->n_ref > 0); + m->n_ref--; + + if (m->n_ref <= 0) + message_free(m); + + return NULL; +} + +_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) { + assert_return(m, -EINVAL); + assert_return(type, -EINVAL); + + *type = m->header->type; + return 0; +} + +_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) { + assert_return(m, -EINVAL); + assert_return(cookie, -EINVAL); + assert_return(m->header->serial != 0, -ENODATA); + + *cookie = BUS_MESSAGE_COOKIE(m); + return 0; +} + +_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) { + assert_return(m, -EINVAL); + assert_return(cookie, -EINVAL); + assert_return(m->reply_cookie != 0, -ENODATA); + + *cookie = m->reply_cookie; + return 0; +} + +_public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) { + assert_return(m, -EINVAL); + + return m->header->type == SD_BUS_MESSAGE_METHOD_CALL && + !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED); +} + +_public_ int sd_bus_message_get_auto_start(sd_bus_message *m) { + assert_return(m, -EINVAL); + + return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START); +} + +_public_ const char *sd_bus_message_get_path(sd_bus_message *m) { + assert_return(m, NULL); + + return m->path; +} + +_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) { + assert_return(m, NULL); + + return m->interface; +} + +_public_ const char *sd_bus_message_get_member(sd_bus_message *m) { + assert_return(m, NULL); + + return m->member; +} + +_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) { + assert_return(m, NULL); + + return m->destination; +} + +_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) { + assert_return(m, NULL); + + return m->sender; +} + +_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { + assert_return(m, NULL); + assert_return(sd_bus_error_is_set(&m->error), NULL); + + return &m->error; +} + +_public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) { + assert_return(m, -EINVAL); + assert_return(usec, -EINVAL); + + if (m->monotonic <= 0) + return -ENODATA; + + *usec = m->monotonic; + return 0; +} + +_public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) { + assert_return(m, -EINVAL); + assert_return(usec, -EINVAL); + + if (m->realtime <= 0) + return -ENODATA; + + *usec = m->realtime; + return 0; +} + +_public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) { + assert_return(m, -EINVAL); + assert_return(seqnum, -EINVAL); + + if (m->seqnum <= 0) + return -ENODATA; + + *seqnum = m->seqnum; + return 0; +} + +_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) { + assert_return(m, NULL); + + if (m->creds.mask == 0) + return NULL; + + return &m->creds; +} + +_public_ int sd_bus_message_is_signal(sd_bus_message *m, + const char *interface, + const char *member) { + assert_return(m, -EINVAL); + + if (m->header->type != SD_BUS_MESSAGE_SIGNAL) + return 0; + + if (interface && (!m->interface || !streq(m->interface, interface))) + return 0; + + if (member && (!m->member || !streq(m->member, member))) + return 0; + + return 1; +} + +_public_ int sd_bus_message_is_method_call(sd_bus_message *m, + const char *interface, + const char *member) { + assert_return(m, -EINVAL); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) + return 0; + + if (interface && (!m->interface || !streq(m->interface, interface))) + return 0; + + if (member && (!m->member || !streq(m->member, member))) + return 0; + + return 1; +} + +_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) { + assert_return(m, -EINVAL); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + return 0; + + if (name && (!m->error.name || !streq(m->error.name, name))) + return 0; + + return 1; +} + +_public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); + + if (b) + m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED; + else + m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + + return 0; +} + +_public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + if (b) + m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START; + else + m->header->flags |= BUS_MESSAGE_NO_AUTO_START; + + return 0; +} + +static struct bus_container *message_get_container(sd_bus_message *m) { + assert(m); + + if (m->n_containers == 0) + return &m->root_container; + + assert(m->containers); + return m->containers + m->n_containers - 1; +} + +struct bus_body_part *message_append_part(sd_bus_message *m) { + struct bus_body_part *part; + + assert(m); + + if (m->poisoned) + return NULL; + + if (m->n_body_parts <= 0) { + part = &m->body; + zero(*part); + } else { + assert(m->body_end); + + part = new0(struct bus_body_part, 1); + if (!part) { + m->poisoned = true; + return NULL; + } + + m->body_end->next = part; + } + + part->memfd = -1; + m->body_end = part; + m->n_body_parts ++; + + return part; +} + +static void part_zero(struct bus_body_part *part, size_t sz) { + assert(part); + assert(sz > 0); + assert(sz < 8); + + /* All other fields can be left in their defaults */ + assert(!part->data); + assert(part->memfd < 0); + + part->size = sz; + part->is_zero = true; + part->sealed = true; +} + +static int part_make_space( + struct sd_bus_message *m, + struct bus_body_part *part, + size_t sz, + void **q) { + + void *n; + int r; + + assert(m); + assert(part); + assert(!part->sealed); + + if (m->poisoned) + return -ENOMEM; + + if (!part->data && part->memfd < 0) + part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated); + + if (part->memfd >= 0) { + + if (part->allocated == 0 || sz > part->allocated) { + uint64_t new_allocated; + + new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1); + r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated); + if (r < 0) { + m->poisoned = true; + return -errno; + } + + part->allocated = new_allocated; + } + + if (!part->data || sz > part->mapped) { + size_t psz; + + psz = PAGE_ALIGN(sz > 0 ? sz : 1); + if (part->mapped <= 0) + n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0); + else + n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE); + + if (n == MAP_FAILED) { + m->poisoned = true; + return -errno; + } + + part->mapped = psz; + part->data = n; + } + + part->munmap_this = true; + } else { + if (part->allocated == 0 || sz > part->allocated) { + size_t new_allocated; + + new_allocated = sz > 0 ? 2 * sz : 64; + n = realloc(part->data, new_allocated); + if (!n) { + m->poisoned = true; + return -ENOMEM; + } + + part->data = n; + part->allocated = new_allocated; + part->free_this = true; + } + } + + if (q) + *q = part->data ? (uint8_t*) part->data + part->size : NULL; + + part->size = sz; + return 0; +} + +static int message_add_offset(sd_bus_message *m, size_t offset) { + struct bus_container *c; + + assert(m); + assert(BUS_MESSAGE_IS_GVARIANT(m)); + + /* Add offset to current container, unless this is the first + * item in it, which will have the 0 offset, which we can + * ignore. */ + c = message_get_container(m); + + if (!c->need_offsets) + return 0; + + if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1)) + return -ENOMEM; + + c->offsets[c->n_offsets++] = offset; + return 0; +} + +static void message_extend_containers(sd_bus_message *m, size_t expand) { + struct bus_container *c; + + assert(m); + + if (expand <= 0) + return; + + /* Update counters */ + for (c = m->containers; c < m->containers + m->n_containers; c++) { + + if (c->array_size) + *c->array_size += expand; + } +} + +static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) { + size_t start_body, end_body, padding, added; + void *p; + int r; + + assert(m); + assert(align > 0); + assert(!m->sealed); + + if (m->poisoned) + return NULL; + + start_body = ALIGN_TO((size_t) m->header->body_size, align); + end_body = start_body + sz; + + padding = start_body - m->header->body_size; + added = padding + sz; + + /* Check for 32bit overflows */ + if (end_body > (size_t) ((uint32_t) -1)) { + m->poisoned = true; + return NULL; + } + + if (added > 0) { + struct bus_body_part *part = NULL; + bool add_new_part; + + add_new_part = + m->n_body_parts <= 0 || + m->body_end->sealed || + padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size; + + if (add_new_part) { + if (padding > 0) { + part = message_append_part(m); + if (!part) + return NULL; + + part_zero(part, padding); + } + + part = message_append_part(m); + if (!part) + return NULL; + + r = part_make_space(m, part, sz, &p); + if (r < 0) + return NULL; + } else { + struct bus_container *c; + void *op; + size_t os, start_part, end_part; + + part = m->body_end; + op = part->data; + os = part->size; + + start_part = ALIGN_TO(part->size, align); + end_part = start_part + sz; + + r = part_make_space(m, part, end_part, &p); + if (r < 0) + return NULL; + + if (padding > 0) { + memzero(p, padding); + p = (uint8_t*) p + padding; + } + + /* Readjust pointers */ + for (c = m->containers; c < m->containers + m->n_containers; c++) + c->array_size = adjust_pointer(c->array_size, op, os, part->data); + + m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data); + } + } else + /* Return something that is not NULL and is aligned */ + p = (uint8_t *) NULL + align; + + m->header->body_size = end_body; + message_extend_containers(m, added); + + if (add_offset) { + r = message_add_offset(m, end_body); + if (r < 0) { + m->poisoned = true; + return NULL; + } + } + + return p; +} + +static int message_push_fd(sd_bus_message *m, int fd) { + int *f, copy; + + assert(m); + + if (fd < 0) + return -EINVAL; + + if (!m->allow_fds) + return -ENOTSUP; + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + f = realloc(m->fds, sizeof(int) * (m->n_fds + 1)); + if (!f) { + m->poisoned = true; + close_nointr_nofail(copy); + return -ENOMEM; + } + + m->fds = f; + m->fds[m->n_fds] = copy; + m->free_fds = true; + + return copy; +} + +int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) { + _cleanup_close_ int fd = -1; + struct bus_container *c; + ssize_t align, sz; + void *a; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_basic(type), -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + c = message_get_container(m); + + if (c->signature && c->signature[c->index]) { + /* Container signature is already set */ + + if (c->signature[c->index] != type) + return -ENXIO; + } else { + char *e; + + /* Maybe we can append to the signature? But only if this is the top-level container*/ + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(type), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + uint8_t u8; + uint32_t u32; + + switch (type) { + + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_STRING: + p = strempty(p); + + /* Fall through... */ + case SD_BUS_TYPE_OBJECT_PATH: + if (!p) + return -EINVAL; + + align = 1; + sz = strlen(p) + 1; + break; + + case SD_BUS_TYPE_BOOLEAN: + + u8 = p && *(int*) p; + p = &u8; + + align = sz = 1; + break; + + case SD_BUS_TYPE_UNIX_FD: + + if (!p) + return -EINVAL; + + fd = message_push_fd(m, *(int*) p); + if (fd < 0) + return fd; + + u32 = m->n_fds; + p = &u32; + + align = sz = 4; + break; + + default: + align = bus_gvariant_get_alignment(CHAR_TO_STR(type)); + sz = bus_gvariant_get_size(CHAR_TO_STR(type)); + break; + } + + assert(align > 0); + assert(sz > 0); + + a = message_extend_body(m, align, sz, true); + if (!a) + return -ENOMEM; + + memcpy(a, p, sz); + + if (stored) + *stored = (const uint8_t*) a; + + } else { + uint32_t u32; + + switch (type) { + + case SD_BUS_TYPE_STRING: + /* To make things easy we'll serialize a NULL string + * into the empty string */ + p = strempty(p); + + /* Fall through... */ + case SD_BUS_TYPE_OBJECT_PATH: + + if (!p) + return -EINVAL; + + align = 4; + sz = 4 + strlen(p) + 1; + break; + + case SD_BUS_TYPE_SIGNATURE: + + p = strempty(p); + + align = 1; + sz = 1 + strlen(p) + 1; + break; + + case SD_BUS_TYPE_BOOLEAN: + + u32 = p && *(int*) p; + p = &u32; + + align = sz = 4; + break; + + case SD_BUS_TYPE_UNIX_FD: + + if (!p) + return -EINVAL; + + fd = message_push_fd(m, *(int*) p); + if (fd < 0) + return fd; + + u32 = m->n_fds; + p = &u32; + + align = sz = 4; + break; + + default: + align = bus_type_get_alignment(type); + sz = bus_type_get_size(type); + break; + } + + assert(align > 0); + assert(sz > 0); + + a = message_extend_body(m, align, sz, false); + if (!a) + return -ENOMEM; + + if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) { + *(uint32_t*) a = sz - 5; + memcpy((uint8_t*) a + 4, p, sz - 4); + + if (stored) + *stored = (const uint8_t*) a + 4; + + } else if (type == SD_BUS_TYPE_SIGNATURE) { + *(uint8_t*) a = sz - 2; + memcpy((uint8_t*) a + 1, p, sz - 1); + + if (stored) + *stored = (const uint8_t*) a + 1; + } else { + memcpy(a, p, sz); + + if (stored) + *stored = a; + } + } + + if (type == SD_BUS_TYPE_UNIX_FD) + m->n_fds ++; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + fd = -1; + return 0; +} + +_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) { + return message_append_basic(m, type, p, NULL); +} + +_public_ int sd_bus_message_append_string_space( + sd_bus_message *m, + size_t size, + char **s) { + + struct bus_container *c; + void *a; + + assert_return(m, -EINVAL); + assert_return(s, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); + + c = message_get_container(m); + + if (c->signature && c->signature[c->index]) { + /* Container signature is already set */ + + if (c->signature[c->index] != SD_BUS_TYPE_STRING) + return -ENXIO; + } else { + char *e; + + /* Maybe we can append to the signature? But only if this is the top-level container*/ + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + a = message_extend_body(m, 1, size + 1, true); + if (!a) + return -ENOMEM; + + *s = a; + } else { + a = message_extend_body(m, 4, 4 + size + 1, false); + if (!a) + return -ENOMEM; + + *(uint32_t*) a = size; + *s = (char*) a + 4; + } + + (*s)[size] = 0; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 0; +} + +_public_ int sd_bus_message_append_string_iovec( + sd_bus_message *m, + const struct iovec *iov, + unsigned n) { + + size_t size; + unsigned i; + char *p; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(iov || n == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + size = IOVEC_TOTAL_SIZE(iov, n); + + r = sd_bus_message_append_string_space(m, size, &p); + if (r < 0) + return r; + + for (i = 0; i < n; i++) { + + if (iov[i].iov_base) + memcpy(p, iov[i].iov_base, iov[i].iov_len); + else + memset(p, ' ', iov[i].iov_len); + + p += iov[i].iov_len; + } + + return 0; +} + +static int bus_message_open_array( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + uint32_t **array_size, + size_t *begin, + bool *need_offsets) { + + unsigned nindex; + int alignment, r; + + assert(m); + assert(c); + assert(contents); + assert(array_size); + assert(begin); + assert(need_offsets); + + if (!signature_is_single(contents, true)) + return -EINVAL; + + if (c->signature && c->signature[c->index]) { + + /* Verify the existing signature */ + + if (c->signature[c->index] != SD_BUS_TYPE_ARRAY) + return -ENXIO; + + if (!startswith(c->signature + c->index + 1, contents)) + return -ENXIO; + + nindex = c->index + 1 + strlen(contents); + } else { + char *e; + + if (c->enclosing != 0) + return -ENXIO; + + /* Extend the existing signature */ + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + + nindex = e - c->signature; + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + alignment = bus_gvariant_get_alignment(contents); + if (alignment < 0) + return alignment; + + /* Add alignment padding and add to offset list */ + if (!message_extend_body(m, alignment, 0, false)) + return -ENOMEM; + + r = bus_gvariant_is_fixed_size(contents); + if (r < 0) + return r; + + *begin = m->header->body_size; + *need_offsets = r == 0; + } else { + void *a, *op; + size_t os; + struct bus_body_part *o; + + alignment = bus_type_get_alignment(contents[0]); + if (alignment < 0) + return alignment; + + a = message_extend_body(m, 4, 4, false); + if (!a) + return -ENOMEM; + + o = m->body_end; + op = m->body_end->data; + os = m->body_end->size; + + /* Add alignment between size and first element */ + if (!message_extend_body(m, alignment, 0, false)) + return -ENOMEM; + + /* location of array size might have changed so let's readjust a */ + if (o == m->body_end) + a = adjust_pointer(a, op, os, m->body_end->data); + + *(uint32_t*) a = 0; + *array_size = a; + } + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index = nindex; + + return 0; +} + +static int bus_message_open_variant( + sd_bus_message *m, + struct bus_container *c, + const char *contents) { + + assert(m); + assert(c); + assert(contents); + + if (!signature_is_single(contents, false)) + return -EINVAL; + + if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN) + return -EINVAL; + + if (c->signature && c->signature[c->index]) { + + if (c->signature[c->index] != SD_BUS_TYPE_VARIANT) + return -ENXIO; + + } else { + char *e; + + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + /* Variants are always aligned to 8 */ + + if (!message_extend_body(m, 8, 0, false)) + return -ENOMEM; + + } else { + size_t l; + void *a; + + l = strlen(contents); + a = message_extend_body(m, 1, 1 + l + 1, false); + if (!a) + return -ENOMEM; + + *(uint8_t*) a = l; + memcpy((uint8_t*) a + 1, contents, l + 1); + } + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 0; +} + +static int bus_message_open_struct( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *begin, + bool *need_offsets) { + + size_t nindex; + int r; + + assert(m); + assert(c); + assert(contents); + assert(begin); + assert(need_offsets); + + if (!signature_is_valid(contents, false)) + return -EINVAL; + + if (c->signature && c->signature[c->index]) { + size_t l; + + l = strlen(contents); + + if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN || + !startswith(c->signature + c->index + 1, contents) || + c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END) + return -ENXIO; + + nindex = c->index + 1 + l + 1; + } else { + char *e; + + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + + nindex = e - c->signature; + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + int alignment; + + alignment = bus_gvariant_get_alignment(contents); + if (alignment < 0) + return alignment; + + if (!message_extend_body(m, alignment, 0, false)) + return -ENOMEM; + + r = bus_gvariant_is_fixed_size(contents); + if (r < 0) + return r; + + *begin = m->header->body_size; + *need_offsets = r == 0; + } else { + /* Align contents to 8 byte boundary */ + if (!message_extend_body(m, 8, 0, false)) + return -ENOMEM; + } + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index = nindex; + + return 0; +} + +static int bus_message_open_dict_entry( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *begin, + bool *need_offsets) { + + int r; + + assert(m); + assert(c); + assert(contents); + assert(begin); + assert(need_offsets); + + if (!signature_is_pair(contents)) + return -EINVAL; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + return -ENXIO; + + if (c->signature && c->signature[c->index]) { + size_t l; + + l = strlen(contents); + + if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN || + !startswith(c->signature + c->index + 1, contents) || + c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END) + return -ENXIO; + } else + return -ENXIO; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + int alignment; + + alignment = bus_gvariant_get_alignment(contents); + if (alignment < 0) + return alignment; + + if (!message_extend_body(m, alignment, 0, false)) + return -ENOMEM; + + r = bus_gvariant_is_fixed_size(contents); + if (r < 0) + return r; + + *begin = m->header->body_size; + *need_offsets = r == 0; + } else { + /* Align contents to 8 byte boundary */ + if (!message_extend_body(m, 8, 0, false)) + return -ENOMEM; + } + + return 0; +} + +_public_ int sd_bus_message_open_container( + sd_bus_message *m, + char type, + const char *contents) { + + struct bus_container *c, *w; + uint32_t *array_size = NULL; + char *signature; + size_t before, begin = 0; + bool need_offsets = false; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(contents, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + /* Make sure we have space for one more container */ + if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) { + m->poisoned = true; + return -ENOMEM; + } + + c = message_get_container(m); + + signature = strdup(contents); + if (!signature) { + m->poisoned = true; + return -ENOMEM; + } + + /* Save old index in the parent container, in case we have to + * abort this container */ + c->saved_index = c->index; + before = m->header->body_size; + + if (type == SD_BUS_TYPE_ARRAY) + r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets); + else if (type == SD_BUS_TYPE_VARIANT) + r = bus_message_open_variant(m, c, contents); + else if (type == SD_BUS_TYPE_STRUCT) + r = bus_message_open_struct(m, c, contents, &begin, &need_offsets); + else if (type == SD_BUS_TYPE_DICT_ENTRY) + r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets); + else + r = -EINVAL; + + if (r < 0) { + free(signature); + return r; + } + + /* OK, let's fill it in */ + w = m->containers + m->n_containers++; + w->enclosing = type; + w->signature = signature; + w->index = 0; + w->array_size = array_size; + w->before = before; + w->begin = begin; + w->n_offsets = w->offsets_allocated = 0; + w->offsets = NULL; + w->need_offsets = need_offsets; + + return 0; +} + +static size_t determine_word_size(size_t sz, size_t extra) { + if (sz + extra <= 0xFF) + return 1; + else if (sz + extra*2 <= 0xFFFF) + return 2; + else if (sz + extra*4 <= 0xFFFFFFFF) + return 4; + else + return 8; +} + +static size_t read_word_le(void *p, size_t sz) { + union { + uint16_t u16; + uint32_t u32; + uint64_t u64; + } x; + + assert(p); + + if (sz == 1) + return *(uint8_t*) p; + + memcpy(&x, p, sz); + + if (sz == 2) + return le16toh(x.u16); + else if (sz == 4) + return le32toh(x.u32); + else if (sz == 8) + return le64toh(x.u64); + + assert_not_reached("unknown word width"); +} + +static void write_word_le(void *p, size_t sz, size_t value) { + union { + uint16_t u16; + uint32_t u32; + uint64_t u64; + } x; + + assert(p); + assert(sz == 8 || (value < (1ULL << (sz*8)))); + + if (sz == 1) { + *(uint8_t*) p = value; + return; + } else if (sz == 2) + x.u16 = htole16((uint16_t) value); + else if (sz == 4) + x.u32 = htole32((uint32_t) value); + else if (sz == 8) + x.u64 = htole64((uint64_t) value); + else + assert_not_reached("unknown word width"); + + memcpy(p, &x, sz); +} + +static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) { + + assert(m); + assert(c); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + if (c->need_offsets) { + size_t payload, sz, i; + uint8_t *a; + + /* Variable-width arrays */ + + payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0; + sz = determine_word_size(payload, c->n_offsets); + + a = message_extend_body(m, 1, sz * c->n_offsets, true); + if (!a) + return -ENOMEM; + + for (i = 0; i < c->n_offsets; i++) + write_word_le(a + sz*i, sz, c->offsets[i] - c->begin); + } else { + void *a; + + /* Fixed-width or empty arrays */ + + a = message_extend_body(m, 1, 0, true); /* let's add offset to parent */ + if (!a) + return -ENOMEM; + } + + return 0; +} + +static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) { + uint8_t *a; + size_t l; + + assert(m); + assert(c); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + l = strlen(c->signature); + + a = message_extend_body(m, 1, 1 + l, true); + if (!a) + return -ENOMEM; + + a[0] = 0; + memcpy(a+1, c->signature, l); + + return 0; +} + +static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) { + size_t n_variable = 0; + unsigned i = 0; + const char *p; + uint8_t *a; + int r; + + assert(m); + assert(c); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + p = strempty(c->signature); + while (*p != 0) { + size_t n; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + else { + char t[n+1]; + + memcpy(t, p, n); + t[n] = 0; + + r = bus_gvariant_is_fixed_size(t); + if (r < 0) + return r; + } + + assert(!c->need_offsets || i <= c->n_offsets); + + /* We need to add an offset for each item that has a + * variable size and that is not the last one in the + * list */ + if (r == 0 && p[n] != 0) + n_variable++; + + i++; + p += n; + } + + assert(!c->need_offsets || i == c->n_offsets); + assert(c->need_offsets || n_variable == 0); + + if (n_variable <= 0) { + a = message_extend_body(m, 1, 0, add_offset); + if (!a) + return -ENOMEM; + } else { + size_t sz; + unsigned j; + + assert(c->offsets[c->n_offsets-1] == m->header->body_size); + + sz = determine_word_size(m->header->body_size - c->begin, n_variable); + + a = message_extend_body(m, 1, sz * n_variable, add_offset); + if (!a) + return -ENOMEM; + + p = strempty(c->signature); + for (i = 0, j = 0; i < c->n_offsets; i++) { + unsigned k; + size_t n; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + else { + char t[n+1]; + + memcpy(t, p, n); + t[n] = 0; + + p += n; + + r = bus_gvariant_is_fixed_size(t); + if (r < 0) + return r; + if (r > 0 || p[0] == 0) + continue; + } + + k = n_variable - 1 - j; + + write_word_le(a + k * sz, sz, c->offsets[i] - c->begin); + + j++; + } + } + + return 0; +} + +_public_ int sd_bus_message_close_container(sd_bus_message *m) { + struct bus_container *c; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(m->n_containers > 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + c = message_get_container(m); + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + if (c->signature && c->signature[c->index] != 0) + return -EINVAL; + + m->n_containers--; + + if (c->enclosing == SD_BUS_TYPE_ARRAY) + r = bus_message_close_array(m, c); + else if (c->enclosing == SD_BUS_TYPE_VARIANT) + r = bus_message_close_variant(m, c); + else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY) + r = bus_message_close_struct(m, c, true); + else + assert_not_reached("Unknown container type"); + + free(c->signature); + free(c->offsets); + + return r; +} + +typedef struct { + const char *types; + unsigned n_struct; + unsigned n_array; +} TypeStack; + +static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) { + assert(stack); + assert(max > 0); + + if (*i >= max) + return -EINVAL; + + stack[*i].types = types; + stack[*i].n_struct = n_struct; + stack[*i].n_array = n_array; + (*i)++; + + return 0; +} + +static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) { + assert(stack); + assert(max > 0); + assert(types); + assert(n_struct); + assert(n_array); + + if (*i <= 0) + return 0; + + (*i)--; + *types = stack[*i].types; + *n_struct = stack[*i].n_struct; + *n_array = stack[*i].n_array; + + return 1; +} + +int bus_message_append_ap( + sd_bus_message *m, + const char *types, + va_list ap) { + + unsigned n_array, n_struct; + TypeStack stack[BUS_CONTAINER_DEPTH]; + unsigned stack_ptr = 0; + int r; + + assert(m); + + if (!types) + return 0; + + n_array = (unsigned) -1; + n_struct = strlen(types); + + for (;;) { + const char *t; + + if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + continue; + } + + t = types; + if (n_array != (unsigned) -1) + n_array --; + else { + types ++; + n_struct--; + } + + switch (*t) { + + case SD_BUS_TYPE_BYTE: { + uint8_t x; + + x = (uint8_t) va_arg(ap, int); + r = sd_bus_message_append_basic(m, *t, &x); + break; + } + + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_UNIX_FD: { + uint32_t x; + + /* We assume a boolean is the same as int32_t */ + assert_cc(sizeof(int32_t) == sizeof(int)); + + x = va_arg(ap, uint32_t); + r = sd_bus_message_append_basic(m, *t, &x); + break; + } + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: { + uint16_t x; + + x = (uint16_t) va_arg(ap, int); + r = sd_bus_message_append_basic(m, *t, &x); + break; + } + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: { + uint64_t x; + + x = va_arg(ap, uint64_t); + r = sd_bus_message_append_basic(m, *t, &x); + break; + } + + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: { + const char *x; + + x = va_arg(ap, const char*); + r = sd_bus_message_append_basic(m, *t, x); + break; + } + + case SD_BUS_TYPE_ARRAY: { + size_t k; + + r = signature_element_length(t + 1, &k); + if (r < 0) + return r; + + { + char s[k + 1]; + memcpy(s, t + 1, k); + s[k] = 0; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s); + if (r < 0) + return r; + } + + if (n_array == (unsigned) -1) { + types += k; + n_struct -= k; + } + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k; + n_array = va_arg(ap, unsigned); + + break; + } + + case SD_BUS_TYPE_VARIANT: { + const char *s; + + s = va_arg(ap, const char*); + if (!s) + return -EINVAL; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s); + if (r < 0) + return r; + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = s; + n_struct = strlen(s); + n_array = (unsigned) -1; + + break; + } + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + size_t k; + + r = signature_element_length(t, &k); + if (r < 0) + return r; + + { + char s[k - 1]; + + memcpy(s, t + 1, k - 2); + s[k - 2] = 0; + + r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); + if (r < 0) + return r; + } + + if (n_array == (unsigned) -1) { + types += k - 1; + n_struct -= k - 1; + } + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k - 2; + n_array = (unsigned) -1; + + break; + } + + default: + r = -EINVAL; + } + + if (r < 0) + return r; + } + + return 1; +} + +_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { + va_list ap; + int r; + + assert_return(m, -EINVAL); + assert_return(types, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); + + va_start(ap, types); + r = bus_message_append_ap(m, types, ap); + va_end(ap); + + return r; +} + +_public_ int sd_bus_message_append_array_space( + sd_bus_message *m, + char type, + size_t size, + void **ptr) { + + ssize_t align, sz; + void *a; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL); + assert_return(ptr || size == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + /* alignment and size of the trivial types (except bool) is + * identical for gvariant and dbus1 marshalling */ + align = bus_type_get_alignment(type); + sz = bus_type_get_size(type); + + assert_se(align > 0); + assert_se(sz > 0); + + if (size % sz != 0) + return -EINVAL; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); + if (r < 0) + return r; + + a = message_extend_body(m, align, size, false); + if (!a) + return -ENOMEM; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + *ptr = a; + return 0; +} + +_public_ int sd_bus_message_append_array(sd_bus_message *m, + char type, + const void *ptr, + size_t size) { + int r; + void *p; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr || size == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + r = sd_bus_message_append_array_space(m, type, size, &p); + if (r < 0) + return r; + + if (size > 0) + memcpy(p, ptr, size); + + return 0; +} + +_public_ int sd_bus_message_append_array_iovec( + sd_bus_message *m, + char type, + const struct iovec *iov, + unsigned n) { + + size_t size; + unsigned i; + void *p; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(iov || n == 0, -EINVAL); + assert_return(!m->poisoned, -ESTALE); + + size = IOVEC_TOTAL_SIZE(iov, n); + + r = sd_bus_message_append_array_space(m, type, size, &p); + if (r < 0) + return r; + + for (i = 0; i < n; i++) { + + if (iov[i].iov_base) + memcpy(p, iov[i].iov_base, iov[i].iov_len); + else + memzero(p, iov[i].iov_len); + + p = (uint8_t*) p + iov[i].iov_len; + } + + return 0; +} + +_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m, + char type, + sd_memfd *memfd) { + _cleanup_close_ int copy_fd = -1; + struct bus_body_part *part; + ssize_t align, sz; + uint64_t size; + void *a; + int r; + + if (!m) + return -EINVAL; + if (!memfd) + return -EINVAL; + if (m->sealed) + return -EPERM; + if (!bus_type_is_trivial(type)) + return -EINVAL; + if (m->poisoned) + return -ESTALE; + + r = sd_memfd_set_sealed(memfd, true); + if (r < 0) + return r; + + copy_fd = sd_memfd_dup_fd(memfd); + if (copy_fd < 0) + return copy_fd; + + r = sd_memfd_get_size(memfd, &size); + if (r < 0) + return r; + + align = bus_type_get_alignment(type); + sz = bus_type_get_size(type); + + assert_se(align > 0); + assert_se(sz > 0); + + if (size % sz != 0) + return -EINVAL; + + if (size > (uint64_t) (uint32_t) -1) + return -EINVAL; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); + if (r < 0) + return r; + + a = message_extend_body(m, align, 0, false); + if (!a) + return -ENOMEM; + + part = message_append_part(m); + if (!part) + return -ENOMEM; + + part->memfd = copy_fd; + part->sealed = true; + part->size = size; + copy_fd = -1; + + m->header->body_size += size; + message_extend_containers(m, size); + + return sd_bus_message_close_container(m); +} + +_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) { + _cleanup_close_ int copy_fd = -1; + struct bus_body_part *part; + struct bus_container *c; + uint64_t size; + void *a; + int r; + + assert_return(m, -EINVAL); + assert_return(memfd, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); + + r = sd_memfd_set_sealed(memfd, true); + if (r < 0) + return r; + + copy_fd = sd_memfd_dup_fd(memfd); + if (copy_fd < 0) + return copy_fd; + + r = sd_memfd_get_size(memfd, &size); + if (r < 0) + return r; + + /* We require this to be NUL terminated */ + if (size == 0) + return -EINVAL; + + if (size > (uint64_t) (uint32_t) -1) + return -EINVAL; + + c = message_get_container(m); + if (c->signature && c->signature[c->index]) { + /* Container signature is already set */ + + if (c->signature[c->index] != SD_BUS_TYPE_STRING) + return -ENXIO; + } else { + char *e; + + /* Maybe we can append to the signature? But only if this is the top-level container*/ + if (c->enclosing != 0) + return -ENXIO; + + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL); + if (!e) { + m->poisoned = true; + return -ENOMEM; + } + } + + if (!BUS_MESSAGE_IS_GVARIANT(m)) { + a = message_extend_body(m, 4, 4, false); + if (!a) + return -ENOMEM; + + *(uint32_t*) a = size - 1; + } + + part = message_append_part(m); + if (!part) + return -ENOMEM; + + part->memfd = copy_fd; + part->sealed = true; + part->size = size; + copy_fd = -1; + + m->header->body_size += size; + message_extend_containers(m, size); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + r = message_add_offset(m, m->header->body_size); + if (r < 0) { + m->poisoned = true; + return -ENOMEM; + } + } + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 0; +} + +_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) { + char **i; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return r; + + STRV_FOREACH(i, l) { + r = sd_bus_message_append_basic(m, 's', *i); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(m); +} + +static int bus_message_close_header(sd_bus_message *m) { + uint8_t *a; + size_t sz, i; + + assert(m); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + if (m->n_header_offsets < 1) + return 0; + + assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]); + + sz = determine_word_size(m->header->fields_size, m->n_header_offsets); + + a = message_extend_fields(m, 1, sz * m->n_header_offsets, false); + if (!a) + return -ENOMEM; + + for (i = 0; i < m->n_header_offsets; i++) + write_word_le(a + sz*i, sz, m->header_offsets[i]); + + return 0; +} + +int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) { + struct bus_body_part *part; + size_t l, a; + unsigned i; + int r; + + assert(m); + + if (m->sealed) + return -EPERM; + + if (m->n_containers > 0) + return -EBADMSG; + + if (m->poisoned) + return -ESTALE; + + /* In vtables the return signature of method calls is listed, + * let's check if they match if this is a response */ + if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN && + m->enforced_reply_signature && + !streq(strempty(m->root_container.signature), m->enforced_reply_signature)) + return -ENOMSG; + + /* If gvariant marshalling is used we need to close the body structure */ + r = bus_message_close_struct(m, &m->root_container, false); + if (r < 0) + return r; + + /* If there's a non-trivial signature set, then add it in here */ + if (!isempty(m->root_container.signature)) { + r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL); + if (r < 0) + return r; + } + + if (m->n_fds > 0) { + r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds); + if (r < 0) + return r; + } + + r = bus_message_close_header(m); + if (r < 0) + return r; + + m->header->serial = (uint32_t) cookie; + m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout; + + /* Add padding at the end of the fields part, since we know + * the body needs to start at an 8 byte alignment. We made + * sure we allocated enough space for this, so all we need to + * do here is to zero it out. */ + l = BUS_MESSAGE_FIELDS_SIZE(m); + a = ALIGN8(l) - l; + if (a > 0) + memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, a); + + /* If this is something we can send as memfd, then let's seal + the memfd now. Note that we can send memfds as payload only + for directed messages, and not for broadcasts. */ + if (m->destination && m->bus && m->bus->use_memfd) { + MESSAGE_FOREACH_PART(part, i, m) + if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) { + uint64_t sz; + + /* Try to seal it if that makes + * sense. First, unmap our own map to + * make sure we don't keep it busy. */ + bus_body_part_unmap(part); + + /* Then, sync up real memfd size */ + sz = part->size; + if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0) + return -errno; + + /* Finally, try to seal */ + if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0) + part->sealed = true; + } + } + + m->root_container.end = BUS_MESSAGE_BODY_SIZE(m); + m->root_container.index = 0; + m->root_container.offset_index = 0; + m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0; + + m->sealed = true; + + return 0; +} + +int bus_body_part_map(struct bus_body_part *part) { + void *p; + size_t psz; + + assert_se(part); + + if (part->data) + return 0; + + if (part->size <= 0) + return 0; + + /* For smaller zero parts (as used for padding) we don't need to map anything... */ + if (part->memfd < 0 && part->is_zero && part->size < 8) { + static const uint8_t zeroes[7] = { }; + part->data = (void*) zeroes; + return 0; + } + + psz = PAGE_ALIGN(part->size); + + if (part->memfd >= 0) + p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0); + else if (part->is_zero) + p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + else + return -EINVAL; + + if (p == MAP_FAILED) + return -errno; + + part->mapped = psz; + part->data = p; + part->munmap_this = true; + + return 0; +} + +void bus_body_part_unmap(struct bus_body_part *part) { + + assert_se(part); + + if (part->memfd < 0) + return; + + if (!part->data) + return; + + if (!part->munmap_this) + return; + + assert_se(munmap(part->data, part->mapped) == 0); + + part->data = NULL; + part->mapped = 0; + part->munmap_this = false; + + return; +} + +static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) { + size_t k, start, end; + + assert(rindex); + assert(align > 0); + + start = ALIGN_TO((size_t) *rindex, align); + end = start + nbytes; + + if (end > sz) + return -EBADMSG; + + /* Verify that padding is 0 */ + for (k = *rindex; k < start; k++) + if (((const uint8_t*) p)[k] != 0) + return -EBADMSG; + + if (r) + *r = (uint8_t*) p + start; + + *rindex = end; + + return 1; +} + +static bool message_end_of_signature(sd_bus_message *m) { + struct bus_container *c; + + assert(m); + + c = message_get_container(m); + return !c->signature || c->signature[c->index] == 0; +} + +static bool message_end_of_array(sd_bus_message *m, size_t index) { + struct bus_container *c; + + assert(m); + + c = message_get_container(m); + if (c->enclosing != SD_BUS_TYPE_ARRAY) + return false; + + if (BUS_MESSAGE_IS_GVARIANT(m)) + return index >= c->end; + else { + assert(c->array_size); + return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size); + } +} + +_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) { + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + + if (complete && m->n_containers > 0) + return false; + + if (message_end_of_signature(m)) + return true; + + if (message_end_of_array(m, m->rindex)) + return true; + + return false; +} + +static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) { + struct bus_body_part *part; + size_t begin; + int r; + + assert(m); + + if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) { + part = m->cached_rindex_part; + begin = m->cached_rindex_part_begin; + } else { + part = &m->body; + begin = 0; + } + + while (part) { + if (index < begin) + return NULL; + + if (index + sz <= begin + part->size) { + + r = bus_body_part_map(part); + if (r < 0) + return NULL; + + if (p) + *p = (uint8_t*) part->data + index - begin; + + m->cached_rindex_part = part; + m->cached_rindex_part_begin = begin; + + return part; + } + + begin += part->size; + part = part->next; + } + + return NULL; +} + +static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) { + int r; + + assert(m); + assert(c); + assert(rindex); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + if (c->enclosing == SD_BUS_TYPE_ARRAY) { + int sz; + + sz = bus_gvariant_get_size(c->signature); + if (sz < 0) { + int alignment; + + if (c->offset_index+1 >= c->n_offsets) + goto end; + + /* Variable-size array */ + + alignment = bus_gvariant_get_alignment(c->signature); + assert(alignment > 0); + + *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment); + c->item_size = c->offsets[c->offset_index+1] - *rindex; + } else { + + if (c->offset_index+1 >= (c->end-c->begin)/sz) + goto end; + + /* Fixed-size array */ + *rindex = c->begin + (c->offset_index+1) * sz; + c->item_size = sz; + } + + c->offset_index++; + + } else if (c->enclosing == 0 || + c->enclosing == SD_BUS_TYPE_STRUCT || + c->enclosing == SD_BUS_TYPE_DICT_ENTRY) { + + int alignment; + size_t n, j; + + if (c->offset_index+1 >= c->n_offsets) + goto end; + + r = signature_element_length(c->signature + c->index, &n); + if (r < 0) + return r; + + r = signature_element_length(c->signature + c->index + n, &j); + if (r < 0) + return r; + else { + char t[j+1]; + memcpy(t, c->signature + c->index + n, j); + t[j] = 0; + + alignment = bus_gvariant_get_alignment(t); + } + + assert(alignment > 0); + + *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment); + c->item_size = c->offsets[c->offset_index+1] - *rindex; + + c->offset_index++; + + } else if (c->enclosing == SD_BUS_TYPE_VARIANT) + goto end; + else + assert_not_reached("Unknown container type"); + + return 0; + +end: + /* Reached the end */ + *rindex = c->end; + c->item_size = 0; + return 0; +} + + +static int message_peek_body( + sd_bus_message *m, + size_t *rindex, + size_t align, + size_t nbytes, + void **ret) { + + size_t k, start, end, padding; + struct bus_body_part *part; + uint8_t *q; + + assert(m); + assert(rindex); + assert(align > 0); + + start = ALIGN_TO((size_t) *rindex, align); + padding = start - *rindex; + end = start + nbytes; + + if (end > BUS_MESSAGE_BODY_SIZE(m)) + return -EBADMSG; + + part = find_part(m, *rindex, padding, (void**) &q); + if (!part) + return -EBADMSG; + + if (q) { + /* Verify padding */ + for (k = 0; k < padding; k++) + if (q[k] != 0) + return -EBADMSG; + } + + part = find_part(m, start, nbytes, (void**) &q); + if (!part || (nbytes > 0 && !q)) + return -EBADMSG; + + *rindex = end; + + if (ret) + *ret = q; + + return 0; +} + +static bool validate_nul(const char *s, size_t l) { + + /* Check for NUL chars in the string */ + if (memchr(s, 0, l)) + return false; + + /* Check for NUL termination */ + if (s[l] != 0) + return false; + + return true; +} + +static bool validate_string(const char *s, size_t l) { + + if (!validate_nul(s, l)) + return false; + + /* Check if valid UTF8 */ + if (!utf8_is_valid(s)) + return false; + + return true; +} + +static bool validate_signature(const char *s, size_t l) { + + if (!validate_nul(s, l)) + return false; + + /* Check if valid signature */ + if (!signature_is_valid(s, true)) + return false; + + return true; +} + +static bool validate_object_path(const char *s, size_t l) { + + if (!validate_nul(s, l)) + return false; + + if (!object_path_is_valid(s)) + return false; + + return true; +} + +_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { + struct bus_container *c; + size_t rindex; + void *q; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(bus_type_is_basic(type), -EINVAL); + + if (message_end_of_signature(m)) + return -ENXIO; + + if (message_end_of_array(m, m->rindex)) + return 0; + + c = message_get_container(m); + if (c->signature[c->index] != type) + return -ENXIO; + + rindex = m->rindex; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + + if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) { + bool ok; + + r = message_peek_body(m, &rindex, 1, c->item_size, &q); + if (r < 0) + return r; + + if (type == SD_BUS_TYPE_STRING) + ok = validate_string(q, c->item_size-1); + else if (type == SD_BUS_TYPE_OBJECT_PATH) + ok = validate_object_path(q, c->item_size-1); + else + ok = validate_signature(q, c->item_size-1); + + if (!ok) + return -EBADMSG; + + if (p) + *(const char**) p = q; + } else { + int sz, align; + + sz = bus_gvariant_get_size(CHAR_TO_STR(type)); + assert(sz > 0); + if ((size_t) sz != c->item_size) + return -EBADMSG; + + align = bus_gvariant_get_alignment(CHAR_TO_STR(type)); + assert(align > 0); + + r = message_peek_body(m, &rindex, align, c->item_size, &q); + if (r < 0) + return r; + + switch (type) { + + case SD_BUS_TYPE_BYTE: + if (p) + *(uint8_t*) p = *(uint8_t*) q; + break; + + case SD_BUS_TYPE_BOOLEAN: + if (p) + *(int*) p = !!*(uint8_t*) q; + break; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + if (p) + *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q); + break; + + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + if (p) + *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + break; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + if (p) + *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q); + break; + + case SD_BUS_TYPE_UNIX_FD: { + uint32_t j; + + j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + if (j >= m->n_fds) + return -EBADMSG; + + if (p) + *(int*) p = m->fds[j]; + + break; + } + + default: + assert_not_reached("unexpected type"); + } + } + + r = container_next_item(m, c, &rindex); + if (r < 0) + return r; + } else { + + rindex = m->rindex; + + if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) { + uint32_t l; + bool ok; + + r = message_peek_body(m, &rindex, 4, 4, &q); + if (r < 0) + return r; + + l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + r = message_peek_body(m, &rindex, 1, l+1, &q); + if (r < 0) + return r; + + if (type == SD_BUS_TYPE_OBJECT_PATH) + ok = validate_object_path(q, l); + else + ok = validate_string(q, l); + if (!ok) + return -EBADMSG; + + if (p) + *(const char**) p = q; + + } else if (type == SD_BUS_TYPE_SIGNATURE) { + uint8_t l; + + r = message_peek_body(m, &rindex, 1, 1, &q); + if (r < 0) + return r; + + l = *(uint8_t*) q; + r = message_peek_body(m, &rindex, 1, l+1, &q); + if (r < 0) + return r; + + if (!validate_signature(q, l)) + return -EBADMSG; + + if (p) + *(const char**) p = q; + + } else { + ssize_t sz, align; + + align = bus_type_get_alignment(type); + assert(align > 0); + + sz = bus_type_get_size(type); + assert(sz > 0); + + r = message_peek_body(m, &rindex, align, sz, &q); + if (r < 0) + return r; + + switch (type) { + + case SD_BUS_TYPE_BYTE: + if (p) + *(uint8_t*) p = *(uint8_t*) q; + break; + + case SD_BUS_TYPE_BOOLEAN: + if (p) + *(int*) p = !!*(uint32_t*) q; + break; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + if (p) + *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q); + break; + + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + if (p) + *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + break; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + if (p) + *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q); + break; + + case SD_BUS_TYPE_UNIX_FD: { + uint32_t j; + + j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + if (j >= m->n_fds) + return -EBADMSG; + + if (p) + *(int*) p = m->fds[j]; + break; + } + + default: + assert_not_reached("Unknown basic type..."); + } + } + } + + m->rindex = rindex; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 1; +} + +static int bus_message_enter_array( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + uint32_t **array_size, + size_t *item_size, + size_t **offsets, + size_t *n_offsets) { + + size_t rindex; + void *q; + int r, alignment; + + assert(m); + assert(c); + assert(contents); + assert(array_size); + assert(item_size); + assert(offsets); + assert(n_offsets); + + if (!signature_is_single(contents, true)) + return -EINVAL; + + if (!c->signature || c->signature[c->index] == 0) + return -ENXIO; + + if (c->signature[c->index] != SD_BUS_TYPE_ARRAY) + return -ENXIO; + + if (!startswith(c->signature + c->index + 1, contents)) + return -ENXIO; + + rindex = m->rindex; + + if (!BUS_MESSAGE_IS_GVARIANT(m)) { + /* dbus1 */ + + r = message_peek_body(m, &rindex, 4, 4, &q); + if (r < 0) + return r; + + if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE) + return -EBADMSG; + + alignment = bus_type_get_alignment(contents[0]); + if (alignment < 0) + return alignment; + + r = message_peek_body(m, &rindex, alignment, 0, NULL); + if (r < 0) + return r; + + *array_size = (uint32_t*) q; + + } else if (c->item_size <= 0) { + + /* gvariant: empty array */ + *item_size = 0; + *offsets = NULL; + *n_offsets = 0; + + } else if (bus_gvariant_is_fixed_size(contents)) { + + /* gvariant: fixed length array */ + *item_size = bus_gvariant_get_size(contents); + *offsets = NULL; + *n_offsets = 0; + + } else { + size_t where, p = 0, framing, sz; + unsigned i; + + /* gvariant: variable length array */ + sz = determine_word_size(c->item_size, 0); + + where = rindex + c->item_size - sz; + r = message_peek_body(m, &where, 1, sz, &q); + if (r < 0) + return r; + + framing = read_word_le(q, sz); + if (framing > c->item_size - sz) + return -EBADMSG; + if ((c->item_size - framing) % sz != 0) + return -EBADMSG; + + *n_offsets = (c->item_size - framing) / sz; + + where = rindex + framing; + r = message_peek_body(m, &where, 1, *n_offsets * sz, &q); + if (r < 0) + return r; + + *offsets = new(size_t, *n_offsets); + if (!*offsets) + return -ENOMEM; + + for (i = 0; i < *n_offsets; i++) { + size_t x; + + x = read_word_le((uint8_t*) q + i * sz, sz); + if (x > c->item_size - sz) + return -EBADMSG; + if (x < p) + return -EBADMSG; + + (*offsets)[i] = rindex + x; + p = x; + } + + *item_size = (*offsets)[0] - rindex; + } + + m->rindex = rindex; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index += 1 + strlen(contents); + + return 1; +} + +static int bus_message_enter_variant( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *item_size) { + + size_t rindex; + uint8_t l; + void *q; + int r; + + assert(m); + assert(c); + assert(contents); + assert(item_size); + + if (!signature_is_single(contents, false)) + return -EINVAL; + + if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN) + return -EINVAL; + + if (!c->signature || c->signature[c->index] == 0) + return -ENXIO; + + if (c->signature[c->index] != SD_BUS_TYPE_VARIANT) + return -ENXIO; + + rindex = m->rindex; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + size_t k, where; + + k = strlen(contents); + if (1+k > c->item_size) + return -EBADMSG; + + where = rindex + c->item_size - (1+k); + r = message_peek_body(m, &where, 1, 1+k, &q); + if (r < 0) + return r; + + if (*(char*) q != 0) + return -EBADMSG; + + if (memcmp((uint8_t*) q+1, contents, k)) + return -ENXIO; + + *item_size = c->item_size - (1+k); + + } else { + r = message_peek_body(m, &rindex, 1, 1, &q); + if (r < 0) + return r; + + l = *(uint8_t*) q; + r = message_peek_body(m, &rindex, 1, l+1, &q); + if (r < 0) + return r; + + if (!validate_signature(q, l)) + return -EBADMSG; + + if (!streq(q, contents)) + return -ENXIO; + } + + m->rindex = rindex; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index++; + + return 1; +} + +static int build_struct_offsets( + sd_bus_message *m, + const char *signature, + size_t size, + size_t *item_size, + size_t **offsets, + size_t *n_offsets) { + + unsigned n_variable = 0, n_total = 0, v; + size_t previous = 0, where; + const char *p; + size_t sz; + void *q; + int r; + + assert(m); + assert(item_size); + assert(offsets); + assert(n_offsets); + + if (isempty(signature)) { + *item_size = 0; + *offsets = NULL; + *n_offsets = 0; + return 0; + } + + sz = determine_word_size(size, 0); + if (sz <= 0) + return -EBADMSG; + + /* First, loop over signature and count variable elements and + * elements in general. We use this to know how large the + * offset array is at the end of the structure. Note that + * GVariant only stores offsets for all variable size elements + * that are not the last item. */ + + p = signature; + while (*p != 0) { + size_t n; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + else { + char t[n+1]; + + memcpy(t, p, n); + t[n] = 0; + + r = bus_gvariant_is_fixed_size(t); + } + + if (r < 0) + return r; + if (r == 0 && p[n] != 0) /* except the last item */ + n_variable ++; + n_total++; + + p += n; + } + + if (size < n_variable * sz) + return -EBADMSG; + + where = m->rindex + size - (n_variable * sz); + r = message_peek_body(m, &where, 1, n_variable * sz, &q); + if (r < 0) + return r; + + v = n_variable; + + *offsets = new(size_t, n_total); + if (!*offsets) + return -ENOMEM; + + *n_offsets = 0; + + /* Second, loop again and build an offset table */ + p = signature; + while (*p != 0) { + size_t n, offset; + int k; + + r = signature_element_length(p, &n); + if (r < 0) + return r; + else { + char t[n+1]; + + memcpy(t, p, n); + t[n] = 0; + + k = bus_gvariant_get_size(t); + if (k < 0) { + size_t x; + + /* variable size */ + if (v > 0) { + v--; + + x = read_word_le((uint8_t*) q + v*sz, sz); + if (x >= size) + return -EBADMSG; + if (m->rindex + x < previous) + return -EBADMSG; + } else + /* The last item's end + * is determined from + * the start of the + * offset array */ + x = size - (n_variable * sz); + + offset = m->rindex + x; + + } else { + size_t align; + + /* fixed size */ + align = bus_gvariant_get_alignment(t); + assert(align > 0); + + offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k; + } + } + + previous = (*offsets)[(*n_offsets)++] = offset; + p += n; + } + + assert(v == 0); + assert(*n_offsets == n_total); + + *item_size = (*offsets)[0] - m->rindex; + return 0; +} + +static int enter_struct_or_dict_entry( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *item_size, + size_t **offsets, + size_t *n_offsets) { + + int r; + + assert(m); + assert(c); + assert(contents); + assert(item_size); + assert(offsets); + assert(n_offsets); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) { + + /* dbus1 */ + r = message_peek_body(m, &m->rindex, 8, 0, NULL); + if (r < 0) + return r; + + } else if (c->item_size <= 0) { + + /* gvariant empty struct */ + *item_size = 0; + *offsets = NULL; + *n_offsets = 0; + } else + /* gvariant with contents */ + return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets); + + return 0; +} + +static int bus_message_enter_struct( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *item_size, + size_t **offsets, + size_t *n_offsets) { + + size_t l; + int r; + + assert(m); + assert(c); + assert(contents); + assert(item_size); + assert(offsets); + assert(n_offsets); + + if (!signature_is_valid(contents, false)) + return -EINVAL; + + if (!c->signature || c->signature[c->index] == 0) + return -ENXIO; + + l = strlen(contents); + + if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN || + !startswith(c->signature + c->index + 1, contents) || + c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END) + return -ENXIO; + + r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets); + if (r < 0) + return r; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index += 1 + l + 1; + + return 1; +} + +static int bus_message_enter_dict_entry( + sd_bus_message *m, + struct bus_container *c, + const char *contents, + size_t *item_size, + size_t **offsets, + size_t *n_offsets) { + + size_t l; + int r; + + assert(m); + assert(c); + assert(contents); + + if (!signature_is_pair(contents)) + return -EINVAL; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + return -ENXIO; + + if (!c->signature || c->signature[c->index] == 0) + return 0; + + l = strlen(contents); + + if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN || + !startswith(c->signature + c->index + 1, contents) || + c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END) + return -ENXIO; + + r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets); + if (r < 0) + return r; + + if (c->enclosing != SD_BUS_TYPE_ARRAY) + c->index += 1 + l + 1; + + return 1; +} + +_public_ int sd_bus_message_enter_container(sd_bus_message *m, + char type, + const char *contents) { + struct bus_container *c, *w; + uint32_t *array_size = NULL; + char *signature; + size_t before; + size_t *offsets = NULL; + size_t n_offsets = 0, item_size = 0; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(type != 0 || !contents, -EINVAL); + + if (type == 0 || !contents) { + const char *cc; + char tt; + + /* Allow entering into anonymous containers */ + r = sd_bus_message_peek_type(m, &tt, &cc); + if (r < 0) + return r; + + if (type != 0 && type != tt) + return -ENXIO; + + if (contents && !streq(contents, cc)) + return -ENXIO; + + type = tt; + contents = cc; + } + + /* + * We enforce a global limit on container depth, that is much + * higher than the 32 structs and 32 arrays the specification + * mandates. This is simpler to implement for us, and we need + * this only to ensure our container array doesn't grow + * without bounds. We are happy to return any data from a + * message as long as the data itself is valid, even if the + * overall message might be not. + * + * Note that the message signature is validated when + * parsing the headers, and that validation does check the + * 32/32 limit. + * + * Note that the specification defines no limits on the depth + * of stacked variants, but we do. + */ + if (m->n_containers >= BUS_CONTAINER_DEPTH) + return -EBADMSG; + + if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) + return -ENOMEM; + + if (message_end_of_signature(m)) + return -ENXIO; + + if (message_end_of_array(m, m->rindex)) + return 0; + + c = message_get_container(m); + + signature = strdup(contents); + if (!signature) + return -ENOMEM; + + c->saved_index = c->index; + before = m->rindex; + + if (type == SD_BUS_TYPE_ARRAY) + r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets); + else if (type == SD_BUS_TYPE_VARIANT) + r = bus_message_enter_variant(m, c, contents, &item_size); + else if (type == SD_BUS_TYPE_STRUCT) + r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets); + else if (type == SD_BUS_TYPE_DICT_ENTRY) + r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets); + else + r = -EINVAL; + + if (r <= 0) { + free(signature); + free(offsets); + return r; + } + + /* OK, let's fill it in */ + w = m->containers + m->n_containers++; + w->enclosing = type; + w->signature = signature; + w->peeked_signature = NULL; + w->index = 0; + + w->before = before; + w->begin = m->rindex; + w->end = m->rindex + c->item_size; + + w->array_size = array_size; + w->item_size = item_size; + w->offsets = offsets; + w->n_offsets = n_offsets; + w->offset_index = 0; + + return 1; +} + +_public_ int sd_bus_message_exit_container(sd_bus_message *m) { + struct bus_container *c; + unsigned saved; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(m->n_containers > 0, -ENXIO); + + c = message_get_container(m); + + if (c->enclosing != SD_BUS_TYPE_ARRAY) { + if (c->signature && c->signature[c->index] != 0) + return -EBUSY; + } + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + if (m->rindex < c->end) + return -EBUSY; + + } else if (c->enclosing == SD_BUS_TYPE_ARRAY) { + uint32_t l; + + l = BUS_MESSAGE_BSWAP32(m, *c->array_size); + if (c->begin + l != m->rindex) + return -EBUSY; + } + + free(c->signature); + free(c->peeked_signature); + free(c->offsets); + m->n_containers--; + + c = message_get_container(m); + + saved = c->index; + c->index = c->saved_index; + r = container_next_item(m, c, &m->rindex); + c->index = saved; + if (r < 0) + return r; + + return 1; +} + +static void message_quit_container(sd_bus_message *m) { + struct bus_container *c; + + assert(m); + assert(m->sealed); + assert(m->n_containers > 0); + + c = message_get_container(m); + + /* Undo seeks */ + assert(m->rindex >= c->before); + m->rindex = c->before; + + /* Free container */ + free(c->signature); + free(c->offsets); + m->n_containers--; + + /* Correct index of new top-level container */ + c = message_get_container(m); + c->index = c->saved_index; +} + +_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) { + struct bus_container *c; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + + if (message_end_of_signature(m)) + goto eof; + + if (message_end_of_array(m, m->rindex)) + goto eof; + + c = message_get_container(m); + + if (bus_type_is_basic(c->signature[c->index])) { + if (contents) + *contents = NULL; + if (type) + *type = c->signature[c->index]; + return 1; + } + + if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) { + + if (contents) { + size_t l; + char *sig; + + r = signature_element_length(c->signature+c->index+1, &l); + if (r < 0) + return r; + + assert(l >= 1); + + sig = strndup(c->signature + c->index + 1, l); + if (!sig) + return -ENOMEM; + + free(c->peeked_signature); + *contents = c->peeked_signature = sig; + } + + if (type) + *type = SD_BUS_TYPE_ARRAY; + + return 1; + } + + if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN || + c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) { + + if (contents) { + size_t l; + char *sig; + + r = signature_element_length(c->signature+c->index, &l); + if (r < 0) + return r; + + assert(l >= 2); + sig = strndup(c->signature + c->index + 1, l - 2); + if (!sig) + return -ENOMEM; + + free(c->peeked_signature); + *contents = c->peeked_signature = sig; + } + + if (type) + *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY; + + return 1; + } + + if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) { + if (contents) { + void *q; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + size_t k; + + if (c->item_size < 2) + return -EBADMSG; + + /* Look for the NUL delimiter that + separates the payload from the + signature. Since the body might be + in a different part that then the + signature we map byte by byte. */ + + for (k = 2; k <= c->item_size; k++) { + size_t where; + + where = m->rindex + c->item_size - k; + r = message_peek_body(m, &where, 1, k, &q); + if (r < 0) + return r; + + if (*(char*) q == 0) + break; + } + + if (k > c->item_size) + return -EBADMSG; + + free(c->peeked_signature); + c->peeked_signature = strndup((char*) q + 1, k - 1); + if (!c->peeked_signature) + return -ENOMEM; + + if (!signature_is_valid(c->peeked_signature, true)) + return -EBADMSG; + + *contents = c->peeked_signature; + } else { + size_t rindex, l; + + rindex = m->rindex; + r = message_peek_body(m, &rindex, 1, 1, &q); + if (r < 0) + return r; + + l = *(uint8_t*) q; + r = message_peek_body(m, &rindex, 1, l+1, &q); + if (r < 0) + return r; + + if (!validate_signature(q, l)) + return -EBADMSG; + + *contents = q; + } + } + + if (type) + *type = SD_BUS_TYPE_VARIANT; + + return 1; + } + + return -EINVAL; + +eof: + if (type) + *type = 0; + if (contents) + *contents = NULL; + return 0; +} + +_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) { + struct bus_container *c; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + + if (complete) { + message_reset_containers(m); + m->rindex = 0; + + c = message_get_container(m); + } else { + c = message_get_container(m); + + c->offset_index = 0; + c->index = 0; + m->rindex = c->begin; + } + + c->offset_index = 0; + c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin; + + return !isempty(c->signature); +} + +static int message_read_ap( + sd_bus_message *m, + const char *types, + va_list ap) { + + unsigned n_array, n_struct; + TypeStack stack[BUS_CONTAINER_DEPTH]; + unsigned stack_ptr = 0; + unsigned n_loop = 0; + int r; + + assert(m); + + if (isempty(types)) + return 0; + + /* Ideally, we'd just call ourselves recursively on every + * complex type. However, the state of a va_list that is + * passed to a function is undefined after that function + * returns. This means we need to docode the va_list linearly + * in a single stackframe. We hence implement our own + * home-grown stack in an array. */ + + n_array = (unsigned) -1; /* lenght of current array entries */ + n_struct = strlen(types); /* length of current struct contents signature */ + + for (;;) { + const char *t; + + n_loop++; + + if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + continue; + } + + t = types; + if (n_array != (unsigned) -1) + n_array --; + else { + types ++; + n_struct--; + } + + switch (*t) { + + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_UNIX_FD: { + void *p; + + p = va_arg(ap, void*); + r = sd_bus_message_read_basic(m, *t, p); + if (r < 0) + return r; + if (r == 0) { + if (n_loop <= 1) + return 0; + + return -ENXIO; + } + + break; + } + + case SD_BUS_TYPE_ARRAY: { + size_t k; + + r = signature_element_length(t + 1, &k); + if (r < 0) + return r; + + { + char s[k + 1]; + memcpy(s, t + 1, k); + s[k] = 0; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s); + if (r < 0) + return r; + if (r == 0) { + if (n_loop <= 1) + return 0; + + return -ENXIO; + } + } + + if (n_array == (unsigned) -1) { + types += k; + n_struct -= k; + } + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k; + n_array = va_arg(ap, unsigned); + + break; + } + + case SD_BUS_TYPE_VARIANT: { + const char *s; + + s = va_arg(ap, const char *); + if (!s) + return -EINVAL; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s); + if (r < 0) + return r; + if (r == 0) { + if (n_loop <= 1) + return 0; + + return -ENXIO; + } + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = s; + n_struct = strlen(s); + n_array = (unsigned) -1; + + break; + } + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + size_t k; + + r = signature_element_length(t, &k); + if (r < 0) + return r; + + { + char s[k - 1]; + memcpy(s, t + 1, k - 2); + s[k - 2] = 0; + + r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); + if (r < 0) + return r; + if (r == 0) { + if (n_loop <= 1) + return 0; + return -ENXIO; + } + } + + if (n_array == (unsigned) -1) { + types += k - 1; + n_struct -= k - 1; + } + + r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array); + if (r < 0) + return r; + + types = t + 1; + n_struct = k - 2; + n_array = (unsigned) -1; + + break; + } + + default: + return -EINVAL; + } + } + + return 1; +} + +_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) { + va_list ap; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(types, -EINVAL); + + va_start(ap, types); + r = message_read_ap(m, types, ap); + va_end(ap); + + return r; +} + +_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) { + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(types, -EINVAL); + + if (isempty(types)) + return 0; + + switch (*types) { + + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_UNIX_FD: + + r = sd_bus_message_read_basic(m, *types, NULL); + if (r <= 0) + return r; + + r = sd_bus_message_skip(m, types + 1); + if (r < 0) + return r; + + return 1; + + case SD_BUS_TYPE_ARRAY: { + size_t k; + + r = signature_element_length(types + 1, &k); + if (r < 0) + return r; + + { + char s[k+1]; + memcpy(s, types+1, k); + s[k] = 0; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s); + if (r <= 0) + return r; + + for (;;) { + r = sd_bus_message_skip(m, s); + if (r < 0) + return r; + if (r == 0) + break; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + r = sd_bus_message_skip(m, types + 1 + k); + if (r < 0) + return r; + + return 1; + } + + case SD_BUS_TYPE_VARIANT: { + const char *contents; + char x; + + r = sd_bus_message_peek_type(m, &x, &contents); + if (r <= 0) + return r; + + if (x != SD_BUS_TYPE_VARIANT) + return -ENXIO; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r <= 0) + return r; + + r = sd_bus_message_skip(m, contents); + if (r < 0) + return r; + assert(r != 0); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + r = sd_bus_message_skip(m, types + 1); + if (r < 0) + return r; + + return 1; + } + + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { + size_t k; + + r = signature_element_length(types, &k); + if (r < 0) + return r; + + { + char s[k-1]; + memcpy(s, types+1, k-2); + s[k-2] = 0; + + r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s); + if (r <= 0) + return r; + + r = sd_bus_message_skip(m, s); + if (r < 0) + return r; + assert(r != 0); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + r = sd_bus_message_skip(m, types + k); + if (r < 0) + return r; + + return 1; + } + + default: + return -EINVAL; + } +} + +_public_ int sd_bus_message_read_array(sd_bus_message *m, + char type, + const void **ptr, + size_t *size) { + struct bus_container *c; + void *p; + size_t sz; + ssize_t align; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(bus_type_is_trivial(type), -EINVAL); + assert_return(ptr, -EINVAL); + assert_return(size, -EINVAL); + assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP); + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); + if (r <= 0) + return r; + + c = message_get_container(m); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + align = bus_gvariant_get_alignment(CHAR_TO_STR(type)); + if (align < 0) + return align; + + sz = c->end - c->begin; + } else { + align = bus_type_get_alignment(type); + if (align < 0) + return align; + + sz = BUS_MESSAGE_BSWAP32(m, *c->array_size); + } + + if (sz == 0) + /* Zero length array, let's return some aligned + * pointer that is not NULL */ + p = (uint8_t*) NULL + align; + else { + r = message_peek_body(m, &m->rindex, align, sz, &p); + if (r < 0) + goto fail; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto fail; + + *ptr = (const void*) p; + *size = sz; + + return 1; + +fail: + message_quit_container(m); + return r; +} + +static int message_peek_fields( + sd_bus_message *m, + size_t *rindex, + size_t align, + size_t nbytes, + void **ret) { + + assert(m); + assert(rindex); + assert(align > 0); + + return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret); +} + +static int message_peek_field_uint32( + sd_bus_message *m, + size_t *ri, + size_t item_size, + uint32_t *ret) { + + int r; + void *q; + + assert(m); + assert(ri); + + if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4) + return -EBADMSG; + + /* identical for gvariant and dbus1 */ + + r = message_peek_fields(m, ri, 4, 4, &q); + if (r < 0) + return r; + + if (ret) + *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + + return 0; +} + +static int message_peek_field_string( + sd_bus_message *m, + bool (*validate)(const char *p), + size_t *ri, + size_t item_size, + const char **ret) { + + uint32_t l; + int r; + void *q; + + assert(m); + assert(ri); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + + if (item_size <= 0) + return -EBADMSG; + + r = message_peek_fields(m, ri, 1, item_size, &q); + if (r < 0) + return r; + + l = item_size - 1; + } else { + r = message_peek_field_uint32(m, ri, 4, &l); + if (r < 0) + return r; + + r = message_peek_fields(m, ri, 1, l+1, &q); + if (r < 0) + return r; + } + + if (validate) { + if (!validate_nul(q, l)) + return -EBADMSG; + + if (!validate(q)) + return -EBADMSG; + } else { + if (!validate_string(q, l)) + return -EBADMSG; + } + + if (ret) + *ret = q; + + return 0; +} + +static int message_peek_field_signature( + sd_bus_message *m, + size_t *ri, + size_t item_size, + const char **ret) { + + size_t l; + int r; + void *q; + + assert(m); + assert(ri); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + + if (item_size <= 0) + return -EBADMSG; + + r = message_peek_fields(m, ri, 1, item_size, &q); + if (r < 0) + return r; + + l = item_size - 1; + } else { + r = message_peek_fields(m, ri, 1, 1, &q); + if (r < 0) + return r; + + l = *(uint8_t*) q; + r = message_peek_fields(m, ri, 1, l+1, &q); + if (r < 0) + return r; + } + + if (!validate_signature(q, l)) + return -EBADMSG; + + if (ret) + *ret = q; + + return 0; +} + +static int message_skip_fields( + sd_bus_message *m, + size_t *ri, + uint32_t array_size, + const char **signature) { + + size_t original_index; + int r; + + assert(m); + assert(ri); + assert(signature); + assert(!BUS_MESSAGE_IS_GVARIANT(m)); + + original_index = *ri; + + for (;;) { + char t; + size_t l; + + if (array_size != (uint32_t) -1 && + array_size <= *ri - original_index) + return 0; + + t = **signature; + if (!t) + return 0; + + if (t == SD_BUS_TYPE_STRING) { + + r = message_peek_field_string(m, NULL, ri, 0, NULL); + if (r < 0) + return r; + + (*signature)++; + + } else if (t == SD_BUS_TYPE_OBJECT_PATH) { + + r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL); + if (r < 0) + return r; + + (*signature)++; + + } else if (t == SD_BUS_TYPE_SIGNATURE) { + + r = message_peek_field_signature(m, ri, 0, NULL); + if (r < 0) + return r; + + (*signature)++; + + } else if (bus_type_is_basic(t)) { + ssize_t align, k; + + align = bus_type_get_alignment(t); + k = bus_type_get_size(t); + assert(align > 0 && k > 0); + + r = message_peek_fields(m, ri, align, k, NULL); + if (r < 0) + return r; + + (*signature)++; + + } else if (t == SD_BUS_TYPE_ARRAY) { + + r = signature_element_length(*signature+1, &l); + if (r < 0) + return r; + + assert(l >= 1); + { + char sig[l-1], *s; + uint32_t nas; + int alignment; + + strncpy(sig, *signature + 1, l-1); + s = sig; + + alignment = bus_type_get_alignment(sig[0]); + if (alignment < 0) + return alignment; + + r = message_peek_field_uint32(m, ri, 0, &nas); + if (r < 0) + return r; + if (nas > BUS_ARRAY_MAX_SIZE) + return -EBADMSG; + + r = message_peek_fields(m, ri, alignment, 0, NULL); + if (r < 0) + return r; + + r = message_skip_fields(m, ri, nas, (const char**) &s); + if (r < 0) + return r; + } + + (*signature) += 1 + l; + + } else if (t == SD_BUS_TYPE_VARIANT) { + const char *s; + + r = message_peek_field_signature(m, ri, 0, &s); + if (r < 0) + return r; + + r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s); + if (r < 0) + return r; + + (*signature)++; + + } else if (t == SD_BUS_TYPE_STRUCT || + t == SD_BUS_TYPE_DICT_ENTRY) { + + r = signature_element_length(*signature, &l); + if (r < 0) + return r; + + assert(l >= 2); + { + char sig[l-1], *s; + strncpy(sig, *signature + 1, l-1); + s = sig; + + r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s); + if (r < 0) + return r; + } + + *signature += l; + } else + return -EINVAL; + } +} + +int bus_message_parse_fields(sd_bus_message *m) { + size_t ri; + int r; + uint32_t unix_fds = 0; + void *offsets = NULL; + unsigned n_offsets = 0; + size_t sz = 0; + unsigned i = 0; + + assert(m); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + void *q; + + sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0); + if (sz > 0) { + size_t framing; + + ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz; + r = message_peek_fields(m, &ri, 1, sz, &q); + if (r < 0) + return r; + + framing = read_word_le(q, sz); + if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz) + return -EBADMSG; + if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0) + return -EBADMSG; + + ri = framing; + r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets); + if (r < 0) + return r; + + n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz; + } + } + + ri = 0; + while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) { + _cleanup_free_ char *sig = NULL; + const char *signature; + uint8_t *header; + size_t item_size = (size_t) -1; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + if (i >= n_offsets) + break; + + if (i == 0) + ri = 0; + else + ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8); + } + + r = message_peek_fields(m, &ri, 8, 1, (void**) &header); + if (r < 0) + return r; + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + size_t where, end; + char *b; + void *q; + + end = read_word_le((uint8_t*) offsets + i*sz, sz); + + if (end < ri) + return -EBADMSG; + + where = ri = ALIGN_TO(ri, 8); + item_size = end - ri; + r = message_peek_fields(m, &where, 1, item_size, &q); + if (r < 0) + return r; + + b = memrchr(q, 0, item_size); + if (!b) + return -EBADMSG; + + sig = strndup(b+1, item_size - (b+1-(char*) q)); + if (!sig) + return -ENOMEM; + + signature = sig; + item_size = b - (char*) q; + } else { + r = message_peek_field_signature(m, &ri, 0, &signature); + if (r < 0) + return r; + } + + switch (*header) { + case _BUS_MESSAGE_HEADER_INVALID: + return -EBADMSG; + + case BUS_MESSAGE_HEADER_PATH: + + if (m->path) + return -EBADMSG; + + if (!streq(signature, "o")) + return -EBADMSG; + + r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path); + break; + + case BUS_MESSAGE_HEADER_INTERFACE: + + if (m->interface) + return -EBADMSG; + + if (!streq(signature, "s")) + return -EBADMSG; + + r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface); + break; + + case BUS_MESSAGE_HEADER_MEMBER: + + if (m->member) + return -EBADMSG; + + if (!streq(signature, "s")) + return -EBADMSG; + + r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member); + break; + + case BUS_MESSAGE_HEADER_ERROR_NAME: + + if (m->error.name) + return -EBADMSG; + + if (!streq(signature, "s")) + return -EBADMSG; + + r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name); + if (r >= 0) + m->error._need_free = -1; + + break; + + case BUS_MESSAGE_HEADER_DESTINATION: + + if (m->destination) + return -EBADMSG; + + if (!streq(signature, "s")) + return -EBADMSG; + + r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination); + break; + + case BUS_MESSAGE_HEADER_SENDER: + + if (m->sender) + return -EBADMSG; + + if (!streq(signature, "s")) + return -EBADMSG; + + r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender); + + if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) { + m->creds.unique_name = (char*) m->sender; + m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask; + } + + break; + + + case BUS_MESSAGE_HEADER_SIGNATURE: { + const char *s; + char *c; + + if (m->root_container.signature) + return -EBADMSG; + + if (!streq(signature, "g")) + return -EBADMSG; + + r = message_peek_field_signature(m, &ri, item_size, &s); + if (r < 0) + return r; + + c = strdup(s); + if (!c) + return -ENOMEM; + + free(m->root_container.signature); + m->root_container.signature = c; + break; + } + + case BUS_MESSAGE_HEADER_REPLY_SERIAL: + if (m->reply_cookie != 0) + return -EBADMSG; + + if (!streq(signature, "u")) + return -EBADMSG; + + r = message_peek_field_uint32(m, &ri, item_size, &m->reply_cookie); + if (r < 0) + return r; + + if (m->reply_cookie == 0) + return -EBADMSG; + + break; + + case BUS_MESSAGE_HEADER_UNIX_FDS: + if (unix_fds != 0) + return -EBADMSG; + + if (!streq(signature, "u")) + return -EBADMSG; + + r = message_peek_field_uint32(m, &ri, item_size, &unix_fds); + if (r < 0) + return -EBADMSG; + + if (unix_fds == 0) + return -EBADMSG; + + break; + + default: + if (!BUS_MESSAGE_IS_GVARIANT(m)) + r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature); + } + + if (r < 0) + return r; + + i++; + } + + if (m->n_fds != unix_fds) + return -EBADMSG; + + switch (m->header->type) { + + case SD_BUS_MESSAGE_SIGNAL: + if (!m->path || !m->interface || !m->member) + return -EBADMSG; + break; + + case SD_BUS_MESSAGE_METHOD_CALL: + + if (!m->path || !m->member) + return -EBADMSG; + + break; + + case SD_BUS_MESSAGE_METHOD_RETURN: + + if (m->reply_cookie == 0) + return -EBADMSG; + break; + + case SD_BUS_MESSAGE_METHOD_ERROR: + + if (m->reply_cookie == 0 || !m->error.name) + return -EBADMSG; + break; + } + + /* Refuse non-local messages that claim they are local */ + if (streq_ptr(m->path, "/org/freedesktop/DBus/Local")) + return -EBADMSG; + if (streq_ptr(m->interface, "org.freedesktop.DBus.Local")) + return -EBADMSG; + if (streq_ptr(m->sender, "org.freedesktop.DBus.Local")) + return -EBADMSG; + + m->root_container.end = BUS_MESSAGE_BODY_SIZE(m); + + if (BUS_MESSAGE_IS_GVARIANT(m)) { + r = build_struct_offsets( + m, + m->root_container.signature, + BUS_MESSAGE_BODY_SIZE(m), + &m->root_container.item_size, + &m->root_container.offsets, + &m->root_container.n_offsets); + if (r < 0) + return r; + } + + /* Try to read the error message, but if we can't it's a non-issue */ + if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR) + sd_bus_message_read(m, "s", &m->error.message); + + return 0; +} + +_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) { + assert_return(m, -EINVAL); + assert_return(destination, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->destination, -EEXIST); + + return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination); +} + +int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) { + size_t total; + void *p, *e; + unsigned i; + struct bus_body_part *part; + + assert(m); + assert(buffer); + assert(sz); + + total = BUS_MESSAGE_SIZE(m); + + p = malloc(total); + if (!p) + return -ENOMEM; + + e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m)); + MESSAGE_FOREACH_PART(part, i, m) + e = mempcpy(e, part->data, part->size); + + assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p)); + + *buffer = p; + *sz = total; + + return 0; +} + +int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { + int r; + + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "s"); + if (r <= 0) + return r; + + for (;;) { + const char *s; + + r = sd_bus_message_read_basic(m, 's', &s); + if (r < 0) + return r; + if (r == 0) + break; + + r = strv_extend(l, s); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 1; +} + +_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { + char **strv = NULL; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(l, -EINVAL); + + r = bus_message_read_strv_extend(m, &strv); + if (r <= 0) { + strv_free(strv); + return r; + } + + *l = strv; + return 1; +} + +const char* bus_message_get_arg(sd_bus_message *m, unsigned i) { + int r; + const char *t = NULL; + unsigned j; + + assert(m); + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return NULL; + + for (j = 0; j <= i; j++) { + char type; + + r = sd_bus_message_peek_type(m, &type, NULL); + if (r < 0) + return NULL; + + if (type != SD_BUS_TYPE_STRING && + type != SD_BUS_TYPE_OBJECT_PATH && + type != SD_BUS_TYPE_SIGNATURE) + return NULL; + + r = sd_bus_message_read_basic(m, type, &t); + if (r < 0) + return NULL; + } + + return t; +} + +bool bus_header_is_complete(struct bus_header *h, size_t size) { + size_t full; + + assert(h); + assert(size); + + if (size < sizeof(struct bus_header)) + return false; + + full = sizeof(struct bus_header) + + (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size)); + + return size >= full; +} + +int bus_header_message_size(struct bus_header *h, size_t *sum) { + size_t fs, bs; + + assert(h); + assert(sum); + + if (h->endian == BUS_NATIVE_ENDIAN) { + fs = h->fields_size; + bs = h->body_size; + } else if (h->endian == BUS_REVERSE_ENDIAN) { + fs = bswap_32(h->fields_size); + bs = bswap_32(h->body_size); + } else + return -EBADMSG; + + *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs; + return 0; +} + +_public_ int sd_bus_message_get_errno(sd_bus_message *m) { + assert_return(m, -EINVAL); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + return 0; + + return sd_bus_error_get_errno(&m->error); +} + +_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) { + struct bus_container *c; + + assert_return(m, NULL); + + c = complete ? &m->root_container : message_get_container(m); + return strempty(c->signature); +} + +_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) { + bool done_something = false; + int r; + + assert_return(m, -EINVAL); + assert_return(source, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(source->sealed, -EPERM); + + do { + const char *contents; + char type; + union { + uint8_t u8; + uint16_t u16; + int16_t s16; + uint32_t u32; + int32_t s32; + uint64_t u64; + int64_t s64; + double d64; + const char *string; + int i; + } basic; + + r = sd_bus_message_peek_type(source, &type, &contents); + if (r < 0) + return r; + if (r == 0) + break; + + done_something = true; + + if (bus_type_is_container(type) > 0) { + + r = sd_bus_message_enter_container(source, type, contents); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, type, contents); + if (r < 0) + return r; + + r = sd_bus_message_copy(m, source, true); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(source); + if (r < 0) + return r; + + continue; + } + + r = sd_bus_message_read_basic(source, type, &basic); + if (r < 0) + return r; + + assert(r > 0); + + if (type == SD_BUS_TYPE_OBJECT_PATH || + type == SD_BUS_TYPE_SIGNATURE || + type == SD_BUS_TYPE_STRING) + r = sd_bus_message_append_basic(m, type, basic.string); + else + r = sd_bus_message_append_basic(m, type, &basic); + + if (r < 0) + return r; + + } while (all); + + return done_something; +} + +_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) { + const char *c; + char t; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(!type || bus_type_is_valid(type), -EINVAL); + assert_return(!contents || signature_is_valid(contents, true), -EINVAL); + assert_return(type || contents, -EINVAL); + assert_return(!contents || !type || bus_type_is_container(type), -EINVAL); + + r = sd_bus_message_peek_type(m, &t, &c); + if (r <= 0) + return r; + + if (type != 0 && type != t) + return 0; + + if (contents && !streq_ptr(contents, c)) + return 0; + + return 1; +} + +_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) { + assert_return(m, NULL); + + return m->bus; +} + +int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { + _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + usec_t timeout; + int r; + + assert(bus); + assert(m); + assert(*m); + + switch ((*m)->header->type) { + + case SD_BUS_MESSAGE_SIGNAL: + r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member); + if (r < 0) + return r; + + break; + + case SD_BUS_MESSAGE_METHOD_CALL: + r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member); + if (r < 0) + return r; + + break; + + case SD_BUS_MESSAGE_METHOD_RETURN: + case SD_BUS_MESSAGE_METHOD_ERROR: + + n = message_new(bus, (*m)->header->type); + if (!n) + return -ENOMEM; + + n->reply_cookie = (*m)->reply_cookie; + r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_cookie); + if (r < 0) + return r; + + if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message); + if (r < 0) + return r; + + n->error._need_free = -1; + } + + break; + + default: + return -EINVAL; + } + + if ((*m)->destination && !n->destination) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination); + if (r < 0) + return r; + } + + if ((*m)->sender && !n->sender) { + r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender); + if (r < 0) + return r; + } + + n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START); + + r = sd_bus_message_copy(n, *m, true); + if (r < 0) + return r; + + timeout = (*m)->timeout; + if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) + timeout = BUS_DEFAULT_TIMEOUT; + + r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout); + if (r < 0) + return r; + + sd_bus_message_unref(*m); + *m = n; + n = NULL; + + return 0; +} + +int bus_message_append_sender(sd_bus_message *m, const char *sender) { + assert(m); + assert(sender); + + assert_return(!m->sealed, -EPERM); + assert_return(!m->sender, -EPERM); + + return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender); +} + +_public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) { + assert_return(m, -EINVAL); + assert_return(priority, -EINVAL); + + *priority = m->priority; + return 0; +} + +_public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + m->priority = priority; + return 0; +} diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h new file mode 100644 index 0000000..5fbe3e6 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-message.h @@ -0,0 +1,246 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "macro.h" +#include "sd-bus.h" +#include "kdbus.h" +#include "time-util.h" +#include "bus-creds.h" +#include "bus-protocol.h" + +struct bus_container { + char enclosing; + bool need_offsets:1; + + /* Indexes into the signature string */ + unsigned index, saved_index; + char *signature; + + size_t before, begin, end; + + /* dbus1: pointer to the array size value, if this is a value */ + uint32_t *array_size; + + /* gvariant: list of offsets to end of children if this is struct/dict entry/array */ + size_t *offsets, n_offsets, offsets_allocated, offset_index; + size_t item_size; + + char *peeked_signature; +}; + +struct bus_header { + uint8_t endian; + uint8_t type; + uint8_t flags; + uint8_t version; + uint32_t body_size; + + /* Note that what the bus spec calls "serial" we'll call + "cookie" instead, because we don't want to imply that the + cookie was in any way monotonically increasing. */ + uint32_t serial; + uint32_t fields_size; +} _packed_; + +struct bus_body_part { + struct bus_body_part *next; + void *data; + size_t size; + size_t mapped; + size_t allocated; + int memfd; + bool free_this:1; + bool munmap_this:1; + bool sealed:1; + bool is_zero:1; +}; + +struct sd_bus_message { + unsigned n_ref; + + sd_bus *bus; + + uint32_t reply_cookie; + + const char *path; + const char *interface; + const char *member; + const char *destination; + const char *sender; + + sd_bus_error error; + + sd_bus_creds creds; + + usec_t monotonic; + usec_t realtime; + uint64_t seqnum; + int64_t priority; + + bool sealed:1; + bool dont_send:1; + bool allow_fds:1; + bool free_header:1; + bool free_kdbus:1; + bool free_fds:1; + bool release_kdbus:1; + bool poisoned:1; + + struct bus_header *header; + struct bus_body_part body; + struct bus_body_part *body_end; + unsigned n_body_parts; + + size_t rindex; + struct bus_body_part *cached_rindex_part; + size_t cached_rindex_part_begin; + + uint32_t n_fds; + int *fds; + + struct bus_container root_container, *containers; + unsigned n_containers; + size_t containers_allocated; + + struct iovec *iovec; + struct iovec iovec_fixed[2]; + unsigned n_iovec; + + struct kdbus_msg *kdbus; + + char *peeked_signature; + + /* If set replies to this message must carry the signature + * specified here to successfully seal. This is initialized + * from the vtable data */ + const char *enforced_reply_signature; + + usec_t timeout; + + char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; + char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; + + size_t header_offsets[_BUS_MESSAGE_HEADER_MAX]; + unsigned n_header_offsets; +}; + +#define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != BUS_NATIVE_ENDIAN) + +static inline uint16_t BUS_MESSAGE_BSWAP16(sd_bus_message *m, uint16_t u) { + return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_16(u) : u; +} + +static inline uint32_t BUS_MESSAGE_BSWAP32(sd_bus_message *m, uint32_t u) { + return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_32(u) : u; +} + +static inline uint64_t BUS_MESSAGE_BSWAP64(sd_bus_message *m, uint64_t u) { + return BUS_MESSAGE_NEED_BSWAP(m) ? bswap_64(u) : u; +} + +static inline uint32_t BUS_MESSAGE_COOKIE(sd_bus_message *m) { + return BUS_MESSAGE_BSWAP32(m, m->header->serial); +} + +static inline uint32_t BUS_MESSAGE_BODY_SIZE(sd_bus_message *m) { + return BUS_MESSAGE_BSWAP32(m, m->header->body_size); +} + +static inline uint32_t BUS_MESSAGE_FIELDS_SIZE(sd_bus_message *m) { + return BUS_MESSAGE_BSWAP32(m, m->header->fields_size); +} + +static inline uint32_t BUS_MESSAGE_SIZE(sd_bus_message *m) { + return + sizeof(struct bus_header) + + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) + + BUS_MESSAGE_BODY_SIZE(m); +} + +static inline uint32_t BUS_MESSAGE_BODY_BEGIN(sd_bus_message *m) { + return + sizeof(struct bus_header) + + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)); +} + +static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) { + return (uint8_t*) m->header + sizeof(struct bus_header); +} + +static inline bool BUS_MESSAGE_IS_GVARIANT(sd_bus_message *m) { + return m->header->version == 2; +} + +int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout); +int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz); +int bus_message_read_strv_extend(sd_bus_message *m, char ***l); + +int bus_message_from_header( + sd_bus *bus, + void *header, + size_t length, + int *fds, + unsigned n_fds, + const struct ucred *ucred, + const char *label, + size_t extra, + sd_bus_message **ret); + +int bus_message_from_malloc( + sd_bus *bus, + void *buffer, + size_t length, + int *fds, + unsigned n_fds, + const struct ucred *ucred, + const char *label, + sd_bus_message **ret); + +const char* bus_message_get_arg(sd_bus_message *m, unsigned i); + +int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap); + +int bus_message_parse_fields(sd_bus_message *m); + +bool bus_header_is_complete(struct bus_header *h, size_t size); +int bus_header_message_size(struct bus_header *h, size_t *sum); + +struct bus_body_part *message_append_part(sd_bus_message *m); + +#define MESSAGE_FOREACH_PART(part, i, m) \ + for ((i) = 0, (part) = &(m)->body; (i) < (m)->n_body_parts; (i)++, (part) = (part)->next) + +int bus_body_part_map(struct bus_body_part *part); +void bus_body_part_unmap(struct bus_body_part *part); + +int bus_message_to_errno(sd_bus_message *m); + +int bus_message_new_synthetic_error(sd_bus *bus, uint64_t serial, const sd_bus_error *e, sd_bus_message **m); + +int bus_message_remarshal(sd_bus *bus, sd_bus_message **m); + +int bus_message_append_sender(sd_bus_message *m, const char *sender); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c new file mode 100644 index 0000000..7d325fa --- /dev/null +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -0,0 +1,2507 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "strv.h" +#include "set.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-type.h" +#include "bus-signature.h" +#include "bus-introspect.h" +#include "bus-objects.h" +#include "bus-util.h" + +static int node_vtable_get_userdata( + sd_bus *bus, + const char *path, + struct node_vtable *c, + void **userdata, + sd_bus_error *error) { + + void *u; + int r; + + assert(bus); + assert(path); + assert(c); + + u = c->userdata; + if (c->find) { + r = c->find(bus, path, c->interface, u, &u, error); + if (r < 0) + return r; + if (sd_bus_error_is_set(error)) + return -sd_bus_error_get_errno(error); + if (r == 0) + return r; + } + + if (userdata) + *userdata = u; + + return 1; +} + +static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) { + assert(p); + + return (uint8_t*) u + p->x.property.offset; +} + +static int vtable_property_get_userdata( + sd_bus *bus, + const char *path, + struct vtable_member *p, + void **userdata, + sd_bus_error *error) { + + void *u; + int r; + + assert(bus); + assert(path); + assert(p); + assert(userdata); + + r = node_vtable_get_userdata(bus, path, p->parent, &u, error); + if (r <= 0) + return r; + if (bus->nodes_modified) + return 0; + + *userdata = vtable_property_convert_userdata(p->vtable, u); + return 1; +} + +static int add_enumerated_to_set( + sd_bus *bus, + const char *prefix, + struct node_enumerator *first, + Set *s, + sd_bus_error *error) { + + struct node_enumerator *c; + int r; + + assert(bus); + assert(prefix); + assert(s); + + LIST_FOREACH(enumerators, c, first) { + char **children = NULL, **k; + + if (bus->nodes_modified) + return 0; + + r = c->callback(bus, prefix, c->userdata, &children, error); + if (r < 0) + return r; + if (sd_bus_error_is_set(error)) + return -sd_bus_error_get_errno(error); + + STRV_FOREACH(k, children) { + if (r < 0) { + free(*k); + continue; + } + + if (!object_path_is_valid(*k)){ + free(*k); + r = -EINVAL; + continue; + } + + if (!object_path_startswith(*k, prefix)) { + free(*k); + continue; + } + + r = set_consume(s, *k); + if (r == -EEXIST) + r = 0; + } + + free(children); + if (r < 0) + return r; + } + + return 0; +} + +static int add_subtree_to_set( + sd_bus *bus, + const char *prefix, + struct node *n, + Set *s, + sd_bus_error *error) { + + struct node *i; + int r; + + assert(bus); + assert(prefix); + assert(n); + assert(s); + + r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + LIST_FOREACH(siblings, i, n->child) { + char *t; + + if (!object_path_startswith(i->path, prefix)) + continue; + + t = strdup(i->path); + if (!t) + return -ENOMEM; + + r = set_consume(s, t); + if (r < 0 && r != -EEXIST) + return r; + + r = add_subtree_to_set(bus, prefix, i, s, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + + return 0; +} + +static int get_child_nodes( + sd_bus *bus, + const char *prefix, + struct node *n, + Set **_s, + sd_bus_error *error) { + + Set *s = NULL; + int r; + + assert(bus); + assert(prefix); + assert(n); + assert(_s); + + s = set_new(string_hash_func, string_compare_func); + if (!s) + return -ENOMEM; + + r = add_subtree_to_set(bus, prefix, n, s, error); + if (r < 0) { + set_free_free(s); + return r; + } + + *_s = s; + return 0; +} + +static int node_callbacks_run( + sd_bus *bus, + sd_bus_message *m, + struct node_callback *first, + bool require_fallback, + bool *found_object) { + + struct node_callback *c; + int r; + + assert(bus); + assert(m); + assert(found_object); + + LIST_FOREACH(callbacks, c, first) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + + if (bus->nodes_modified) + return 0; + + if (require_fallback && !c->is_fallback) + continue; + + *found_object = true; + + if (c->last_iteration == bus->iteration_counter) + continue; + + c->last_iteration = bus->iteration_counter; + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + r = c->callback(bus, m, c->userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + if (r != 0) + return r; + } + + return 0; +} + +#define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF) + +static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + uint64_t cap; + uid_t uid; + int r; + + assert(bus); + assert(m); + assert(c); + + /* If the entire bus is trusted let's grant access */ + if (bus->trusted) + return 0; + + /* If the member is marked UNPRIVILEGED let's grant access */ + if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED) + return 0; + + /* If we are not connected to kdbus we cannot retrieve the + * effective capability set without race. Since we need this + * for a security decision we cannot use racy data, hence + * don't request it. */ + if (bus->is_kernel) + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds); + else + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + /* Check have the caller has the requested capability + * set. Note that the flags value contains the capability + * number plus one, which we need to subtract here. We do this + * so that we have 0 as special value for "default + * capability". */ + cap = CAPABILITY_SHIFT(c->vtable->flags); + if (cap == 0) + cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags); + if (cap == 0) + cap = CAP_SYS_ADMIN; + else + cap --; + + r = sd_bus_creds_has_effective_cap(creds, cap); + if (r > 0) + return 1; + + /* Caller has same UID as us, then let's grant access */ + r = sd_bus_creds_get_uid(creds, &uid); + if (r >= 0) { + if (uid == getuid()) + return 1; + } + + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member); +} + +static int method_callbacks_run( + sd_bus *bus, + sd_bus_message *m, + struct vtable_member *c, + bool require_fallback, + bool *found_object) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *signature; + void *u; + int r; + + assert(bus); + assert(m); + assert(c); + assert(found_object); + + if (require_fallback && !c->parent->is_fallback) + return 0; + + r = check_access(bus, m, c, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + + r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error); + if (r <= 0) + return bus_maybe_reply_error(m, r, &error); + if (bus->nodes_modified) + return 0; + + *found_object = true; + + if (c->last_iteration == bus->iteration_counter) + return 0; + + c->last_iteration = bus->iteration_counter; + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + signature = sd_bus_message_get_signature(m, true); + if (!signature) + return -EINVAL; + + if (!streq(strempty(c->vtable->x.method.signature), signature)) + return sd_bus_reply_method_errorf( + m, + SD_BUS_ERROR_INVALID_ARGS, + "Invalid arguments '%s' to call %s.%s(), expecting '%s'.", + signature, c->interface, c->member, strempty(c->vtable->x.method.signature)); + + /* Keep track what the signature of the reply to this message + * should be, so that this can be enforced when sealing the + * reply. */ + m->enforced_reply_signature = strempty(c->vtable->x.method.result); + + if (c->vtable->x.method.handler) { + r = c->vtable->x.method.handler(bus, m, u, &error); + return bus_maybe_reply_error(m, r, &error); + } + + /* If the method callback is NULL, make this a successful NOP */ + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) + return r; + + return 1; +} + +static int invoke_property_get( + sd_bus *bus, + const sd_bus_vtable *v, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + const void *p; + int r; + + assert(bus); + assert(v); + assert(path); + assert(interface); + assert(property); + assert(reply); + + if (v->x.property.get) { + r = v->x.property.get(bus, path, interface, property, reply, userdata, error); + if (r < 0) + return r; + if (sd_bus_error_is_set(error)) + return -sd_bus_error_get_errno(error); + return r; + } + + /* Automatic handling if no callback is defined. */ + + if (streq(v->x.property.signature, "as")) + return sd_bus_message_append_strv(reply, *(char***) userdata); + + assert(signature_is_single(v->x.property.signature, false)); + assert(bus_type_is_basic(v->x.property.signature[0])); + + switch (v->x.property.signature[0]) { + + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_SIGNATURE: + p = strempty(*(char**) userdata); + break; + + case SD_BUS_TYPE_OBJECT_PATH: + p = *(char**) userdata; + assert(p); + break; + + default: + p = userdata; + break; + } + + return sd_bus_message_append_basic(reply, v->x.property.signature[0], p); +} + +static int invoke_property_set( + sd_bus *bus, + const sd_bus_vtable *v, + const char *path, + const char *interface, + const char *property, + sd_bus_message *value, + void *userdata, + sd_bus_error *error) { + + int r; + + assert(bus); + assert(v); + assert(path); + assert(interface); + assert(property); + assert(value); + + if (v->x.property.set) { + r = v->x.property.set(bus, path, interface, property, value, userdata, error); + if (r < 0) + return r; + if (sd_bus_error_is_set(error)) + return -sd_bus_error_get_errno(error); + return r; + } + + /* Automatic handling if no callback is defined. */ + + assert(signature_is_single(v->x.property.signature, false)); + assert(bus_type_is_basic(v->x.property.signature[0])); + + switch (v->x.property.signature[0]) { + + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_SIGNATURE: { + const char *p; + char *n; + + r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p); + if (r < 0) + return r; + + n = strdup(p); + if (!n) + return -ENOMEM; + + free(*(char**) userdata); + *(char**) userdata = n; + + break; + } + + default: + r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata); + if (r < 0) + return r; + + break; + } + + return 1; +} + +static int property_get_set_callbacks_run( + sd_bus *bus, + sd_bus_message *m, + struct vtable_member *c, + bool require_fallback, + bool is_get, + bool *found_object) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + void *u = NULL; + int r; + + assert(bus); + assert(m); + assert(c); + assert(found_object); + + if (require_fallback && !c->parent->is_fallback) + return 0; + + r = vtable_property_get_userdata(bus, m->path, c, &u, &error); + if (r <= 0) + return bus_maybe_reply_error(m, r, &error); + if (bus->nodes_modified) + return 0; + + *found_object = true; + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + if (is_get) { + /* Note that we do not protect against reexecution + * here (using the last_iteration check, see below), + * should the node tree have changed and we got called + * again. We assume that property Get() calls are + * ultimately without side-effects or if they aren't + * then at least idempotent. */ + + r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature); + if (r < 0) + return r; + + /* Note that we do not do an access check here. Read + * access to properties is always unrestricted, since + * PropertiesChanged signals broadcast contents + * anyway. */ + + r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, u, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + } else { + if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member); + + /* Avoid that we call the set routine more than once + * if the processing of this message got restarted + * because the node tree changed. */ + if (c->last_iteration == bus->iteration_counter) + return 0; + + c->last_iteration = bus->iteration_counter; + + r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature); + if (r < 0) + return r; + + r = check_access(bus, m, c, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + + r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, u, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + r = sd_bus_send(bus, reply, NULL); + if (r < 0) + return r; + + return 1; +} + +static int vtable_append_one_property( + sd_bus *bus, + sd_bus_message *reply, + const char *path, + struct node_vtable *c, + const sd_bus_vtable *v, + void *userdata, + sd_bus_error *error) { + + int r; + + assert(bus); + assert(reply); + assert(path); + assert(c); + assert(v); + + r = sd_bus_message_open_container(reply, 'e', "sv"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", v->x.property.member); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'v', v->x.property.signature); + if (r < 0) + return r; + + r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return 0; +} + +static int vtable_append_all_properties( + sd_bus *bus, + sd_bus_message *reply, + const char *path, + struct node_vtable *c, + void *userdata, + sd_bus_error *error) { + + const sd_bus_vtable *v; + int r; + + assert(bus); + assert(reply); + assert(path); + assert(c); + + if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN) + return 1; + + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + continue; + + if (v->flags & SD_BUS_VTABLE_HIDDEN) + continue; + + r = vtable_append_one_property(bus, reply, path, c, v, userdata, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + + return 1; +} + +static int property_get_all_callbacks_run( + sd_bus *bus, + sd_bus_message *m, + struct node_vtable *first, + bool require_fallback, + const char *iface, + bool *found_object) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + struct node_vtable *c; + bool found_interface; + int r; + + assert(bus); + assert(m); + assert(found_object); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "{sv}"); + if (r < 0) + return r; + + found_interface = !iface || + streq(iface, "org.freedesktop.DBus.Properties") || + streq(iface, "org.freedesktop.DBus.Peer") || + streq(iface, "org.freedesktop.DBus.Introspectable"); + + LIST_FOREACH(vtables, c, first) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + void *u; + + if (require_fallback && !c->is_fallback) + continue; + + r = node_vtable_get_userdata(bus, m->path, c, &u, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + *found_object = true; + + if (iface && !streq(c->interface, iface)) + continue; + found_interface = true; + + r = vtable_append_all_properties(bus, reply, m->path, c, u, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + if (bus->nodes_modified) + return 0; + } + + if (!found_interface) { + r = sd_bus_reply_method_errorf( + m, + SD_BUS_ERROR_UNKNOWN_INTERFACE, + "Unknown interface '%s'.", iface); + if (r < 0) + return r; + + return 1; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_send(bus, reply, NULL); + if (r < 0) + return r; + + return 1; +} + +static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) { + assert(bus); + assert(n); + + if (n->object_manager) + return true; + + if (n->parent) + return bus_node_with_object_manager(bus, n->parent); + + return false; +} + +static bool bus_node_exists( + sd_bus *bus, + struct node *n, + const char *path, + bool require_fallback) { + + struct node_vtable *c; + struct node_callback *k; + + assert(bus); + assert(n); + assert(path); + + /* Tests if there's anything attached directly to this node + * for the specified path */ + + LIST_FOREACH(callbacks, k, n->callbacks) { + if (require_fallback && !k->is_fallback) + continue; + + return true; + } + + LIST_FOREACH(vtables, c, n->vtables) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + if (require_fallback && !c->is_fallback) + continue; + + if (node_vtable_get_userdata(bus, path, c, NULL, &error) > 0) + return true; + if (bus->nodes_modified) + return false; + } + + return !require_fallback && (n->enumerators || n->object_manager); +} + +static int process_introspect( + sd_bus *bus, + sd_bus_message *m, + struct node *n, + bool require_fallback, + bool *found_object) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_set_free_free_ Set *s = NULL; + const char *previous_interface = NULL; + struct introspect intro; + struct node_vtable *c; + bool empty; + int r; + + assert(bus); + assert(m); + assert(n); + assert(found_object); + + r = get_child_nodes(bus, m->path, n, &s, &error); + if (r < 0) + return bus_maybe_reply_error(m, r, &error); + if (bus->nodes_modified) + return 0; + + r = introspect_begin(&intro, bus->trusted); + if (r < 0) + return r; + + r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n)); + if (r < 0) + return r; + + empty = set_isempty(s); + + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; + + r = node_vtable_get_userdata(bus, m->path, c, NULL, &error); + if (r < 0) { + r = bus_maybe_reply_error(m, r, &error); + goto finish; + } + if (bus->nodes_modified) { + r = 0; + goto finish; + } + if (r == 0) + continue; + + empty = false; + + if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN) + continue; + + if (!streq_ptr(previous_interface, c->interface)) { + + if (previous_interface) + fputs(" \n", intro.f); + + fprintf(intro.f, " \n", c->interface); + } + + r = introspect_write_interface(&intro, c->vtable); + if (r < 0) + goto finish; + + previous_interface = c->interface; + } + + if (previous_interface) + fputs(" \n", intro.f); + + if (empty) { + /* Nothing?, let's see if we exist at all, and if not + * refuse to do anything */ + r = bus_node_exists(bus, n, m->path, require_fallback); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + goto finish; + } + + *found_object = true; + + r = introspect_write_child_nodes(&intro, s, m->path); + if (r < 0) + goto finish; + + r = introspect_finish(&intro, bus, m, &reply); + if (r < 0) + goto finish; + + r = sd_bus_send(bus, reply, NULL); + if (r < 0) + goto finish; + + r = 1; + +finish: + introspect_free(&intro); + return r; +} + +static int object_manager_serialize_path( + sd_bus *bus, + sd_bus_message *reply, + const char *prefix, + const char *path, + bool require_fallback, + sd_bus_error *error) { + + const char *previous_interface = NULL; + bool found_something = false; + struct node_vtable *i; + struct node *n; + int r; + + assert(bus); + assert(reply); + assert(prefix); + assert(path); + assert(error); + + n = hashmap_get(bus->nodes, prefix); + if (!n) + return 0; + + LIST_FOREACH(vtables, i, n->vtables) { + void *u; + + if (require_fallback && !i->is_fallback) + continue; + + r = node_vtable_get_userdata(bus, path, i, &u, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + if (!found_something) { + + /* Open the object part */ + + r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "o", path); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}"); + if (r < 0) + return r; + + found_something = true; + } + + if (!streq_ptr(previous_interface, i->interface)) { + + /* Maybe close the previous interface part */ + + if (previous_interface) { + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + /* Open the new interface part */ + + r = sd_bus_message_open_container(reply, 'e', "sa{sv}"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", i->interface); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "{sv}"); + if (r < 0) + return r; + } + + r = vtable_append_all_properties(bus, reply, path, i, u, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + previous_interface = i->interface; + } + + if (previous_interface) { + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + if (found_something) { + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + return 1; +} + +static int object_manager_serialize_path_and_fallbacks( + sd_bus *bus, + sd_bus_message *reply, + const char *path, + sd_bus_error *error) { + + char *prefix; + int r; + + assert(bus); + assert(reply); + assert(path); + assert(error); + + /* First, add all vtables registered for this path */ + r = object_manager_serialize_path(bus, reply, path, path, false, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + /* Second, add fallback vtables registered for any of the prefixes */ + prefix = alloca(strlen(path) + 1); + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = object_manager_serialize_path(bus, reply, prefix, path, true, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + + return 0; +} + +static int process_get_managed_objects( + sd_bus *bus, + sd_bus_message *m, + struct node *n, + bool require_fallback, + bool *found_object) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_set_free_free_ Set *s = NULL; + bool empty; + int r; + + assert(bus); + assert(m); + assert(n); + assert(found_object); + + if (!bus_node_with_object_manager(bus, n)) + return 0; + + r = get_child_nodes(bus, m->path, n, &s, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}"); + if (r < 0) + return r; + + empty = set_isempty(s); + if (empty) { + struct node_vtable *c; + + /* Hmm, so we have no children? Then let's check + * whether we exist at all, i.e. whether at least one + * vtable exists. */ + + LIST_FOREACH(vtables, c, n->vtables) { + + if (require_fallback && !c->is_fallback) + continue; + + if (r < 0) + return r; + if (r == 0) + continue; + + empty = false; + break; + } + + if (empty) + return 0; + } else { + Iterator i; + char *path; + + SET_FOREACH(path, s, i) { + r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error); + if (r < 0) + return r; + + if (bus->nodes_modified) + return 0; + } + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_send(bus, reply, NULL); + if (r < 0) + return r; + + return 1; +} + +static int object_find_and_run( + sd_bus *bus, + sd_bus_message *m, + const char *p, + bool require_fallback, + bool *found_object) { + + struct node *n; + struct vtable_member vtable_key, *v; + int r; + + assert(bus); + assert(m); + assert(p); + assert(found_object); + + n = hashmap_get(bus->nodes, p); + if (!n) + return 0; + + /* First, try object callbacks */ + r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object); + if (r != 0) + return r; + if (bus->nodes_modified) + return 0; + + if (!m->interface || !m->member) + return 0; + + /* Then, look for a known method */ + vtable_key.path = (char*) p; + vtable_key.interface = m->interface; + vtable_key.member = m->member; + + v = hashmap_get(bus->vtable_methods, &vtable_key); + if (v) { + r = method_callbacks_run(bus, m, v, require_fallback, found_object); + if (r != 0) + return r; + if (bus->nodes_modified) + return 0; + } + + /* Then, look for a known property */ + if (streq(m->interface, "org.freedesktop.DBus.Properties")) { + bool get = false; + + get = streq(m->member, "Get"); + + if (get || streq(m->member, "Set")) { + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + vtable_key.path = (char*) p; + + r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member); + if (r < 0) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters"); + + v = hashmap_get(bus->vtable_properties, &vtable_key); + if (v) { + r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object); + if (r != 0) + return r; + } + + } else if (streq(m->member, "GetAll")) { + const char *iface; + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + r = sd_bus_message_read(m, "s", &iface); + if (r < 0) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter"); + + if (iface[0] == 0) + iface = NULL; + + r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object); + if (r != 0) + return r; + } + + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { + + if (!isempty(sd_bus_message_get_signature(m, true))) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters"); + + r = process_introspect(bus, m, n, require_fallback, found_object); + if (r != 0) + return r; + + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) { + + if (!isempty(sd_bus_message_get_signature(m, true))) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters"); + + r = process_get_managed_objects(bus, m, n, require_fallback, found_object); + if (r != 0) + return r; + } + + if (bus->nodes_modified) + return 0; + + if (!*found_object) { + r = bus_node_exists(bus, n, m->path, require_fallback); + if (r < 0) + return r; + if (r > 0) + *found_object = true; + } + + return 0; +} + +int bus_process_object(sd_bus *bus, sd_bus_message *m) { + int r; + size_t pl; + bool found_object = false; + + assert(bus); + assert(m); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) + return 0; + + if (hashmap_isempty(bus->nodes)) + return 0; + + /* Never respond to broadcast messages */ + if (bus->bus_client && !m->destination) + return 0; + + assert(m->path); + assert(m->member); + + pl = strlen(m->path); + do { + char prefix[pl+1]; + + bus->nodes_modified = false; + + r = object_find_and_run(bus, m, m->path, false, &found_object); + if (r != 0) + return r; + + /* Look for fallback prefixes */ + OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) { + + if (bus->nodes_modified) + break; + + r = object_find_and_run(bus, m, prefix, true, &found_object); + if (r != 0) + return r; + } + + } while (bus->nodes_modified); + + if (!found_object) + return 0; + + if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") || + sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set")) + r = sd_bus_reply_method_errorf( + m, + SD_BUS_ERROR_UNKNOWN_PROPERTY, + "Unknown property or interface."); + else + r = sd_bus_reply_method_errorf( + m, + SD_BUS_ERROR_UNKNOWN_METHOD, + "Unknown method '%s' or interface '%s'.", m->member, m->interface); + + if (r < 0) + return r; + + return 1; +} + +static struct node *bus_node_allocate(sd_bus *bus, const char *path) { + struct node *n, *parent; + const char *e; + _cleanup_free_ char *s = NULL; + char *p; + int r; + + assert(bus); + assert(path); + assert(path[0] == '/'); + + n = hashmap_get(bus->nodes, path); + if (n) + return n; + + r = hashmap_ensure_allocated(&bus->nodes, string_hash_func, string_compare_func); + if (r < 0) + return NULL; + + s = strdup(path); + if (!s) + return NULL; + + if (streq(path, "/")) + parent = NULL; + else { + e = strrchr(path, '/'); + assert(e); + + p = strndupa(path, MAX(1, path - e)); + + parent = bus_node_allocate(bus, p); + if (!parent) + return NULL; + } + + n = new0(struct node, 1); + if (!n) + return NULL; + + n->parent = parent; + n->path = s; + s = NULL; /* do not free */ + + r = hashmap_put(bus->nodes, n->path, n); + if (r < 0) { + free(n->path); + free(n); + return NULL; + } + + if (parent) + LIST_PREPEND(siblings, parent->child, n); + + return n; +} + +static void bus_node_gc(sd_bus *b, struct node *n) { + assert(b); + + if (!n) + return; + + if (n->child || + n->callbacks || + n->vtables || + n->enumerators || + n->object_manager) + return; + + assert(hashmap_remove(b->nodes, n->path) == n); + + if (n->parent) + LIST_REMOVE(siblings, n->parent->child, n); + + free(n->path); + bus_node_gc(b, n->parent); + free(n); +} + +static int bus_add_object( + sd_bus *bus, + bool fallback, + const char *path, + sd_bus_message_handler_t callback, + void *userdata) { + + struct node_callback *c; + struct node *n; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = bus_node_allocate(bus, path); + if (!n) + return -ENOMEM; + + c = new0(struct node_callback, 1); + if (!c) { + r = -ENOMEM; + goto fail; + } + + c->node = n; + c->callback = callback; + c->userdata = userdata; + c->is_fallback = fallback; + + LIST_PREPEND(callbacks, n->callbacks, c); + bus->nodes_modified = true; + + return 0; + +fail: + free(c); + bus_node_gc(bus, n); + return r; +} + +static int bus_remove_object( + sd_bus *bus, + bool fallback, + const char *path, + sd_bus_message_handler_t callback, + void *userdata) { + + struct node_callback *c; + struct node *n; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = hashmap_get(bus->nodes, path); + if (!n) + return 0; + + LIST_FOREACH(callbacks, c, n->callbacks) + if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback) + break; + if (!c) + return 0; + + LIST_REMOVE(callbacks, n->callbacks, c); + free(c); + + bus_node_gc(bus, n); + bus->nodes_modified = true; + + return 1; +} + +_public_ int sd_bus_add_object(sd_bus *bus, + const char *path, + sd_bus_message_handler_t callback, + void *userdata) { + + return bus_add_object(bus, false, path, callback, userdata); +} + +_public_ int sd_bus_remove_object(sd_bus *bus, + const char *path, + sd_bus_message_handler_t callback, + void *userdata) { + + return bus_remove_object(bus, false, path, callback, userdata); +} + +_public_ int sd_bus_add_fallback(sd_bus *bus, + const char *prefix, + sd_bus_message_handler_t callback, + void *userdata) { + + return bus_add_object(bus, true, prefix, callback, userdata); +} + +_public_ int sd_bus_remove_fallback(sd_bus *bus, + const char *prefix, + sd_bus_message_handler_t callback, + void *userdata) { + + return bus_remove_object(bus, true, prefix, callback, userdata); +} + +static void free_node_vtable(sd_bus *bus, struct node_vtable *w) { + assert(bus); + + if (!w) + return; + + if (w->interface && w->node && w->vtable) { + const sd_bus_vtable *v; + + for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) { + struct vtable_member *x = NULL; + + switch (v->type) { + + case _SD_BUS_VTABLE_METHOD: { + struct vtable_member key; + + key.path = w->node->path; + key.interface = w->interface; + key.member = v->x.method.member; + + x = hashmap_remove(bus->vtable_methods, &key); + break; + } + + case _SD_BUS_VTABLE_PROPERTY: + case _SD_BUS_VTABLE_WRITABLE_PROPERTY: { + struct vtable_member key; + + key.path = w->node->path; + key.interface = w->interface; + key.member = v->x.property.member; + x = hashmap_remove(bus->vtable_properties, &key); + break; + }} + + free(x); + } + } + + free(w->interface); + free(w); +} + +static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { + const struct vtable_member *m = a; + uint8_t hash_key2[HASH_KEY_SIZE]; + unsigned long ret; + + assert(m); + + ret = string_hash_func(m->path, hash_key); + + /* Use a slightly different hash key for the interface */ + memcpy(hash_key2, hash_key, HASH_KEY_SIZE); + hash_key2[0]++; + ret ^= string_hash_func(m->interface, hash_key2); + + /* And an even different one for the member */ + hash_key2[0]++; + ret ^= string_hash_func(m->member, hash_key2); + + return ret; +} + +static int vtable_member_compare_func(const void *a, const void *b) { + const struct vtable_member *x = a, *y = b; + int r; + + assert(x); + assert(y); + + r = strcmp(x->path, y->path); + if (r != 0) + return r; + + r = strcmp(x->interface, y->interface); + if (r != 0) + return r; + + return strcmp(x->member, y->member); +} + +static int add_object_vtable_internal( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + bool fallback, + sd_bus_object_find_t find, + void *userdata) { + + struct node_vtable *c = NULL, *i, *existing = NULL; + const sd_bus_vtable *v; + struct node *n; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + 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(!bus_pid_changed(bus), -ECHILD); + assert_return(!streq(interface, "org.freedesktop.DBus.Properties") && + !streq(interface, "org.freedesktop.DBus.Introspectable") && + !streq(interface, "org.freedesktop.DBus.Peer") && + !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL); + + r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&bus->vtable_properties, vtable_member_hash_func, vtable_member_compare_func); + if (r < 0) + return r; + + n = bus_node_allocate(bus, path); + if (!n) + return -ENOMEM; + + LIST_FOREACH(vtables, i, n->vtables) { + if (i->is_fallback != fallback) { + r = -EPROTOTYPE; + goto fail; + } + + if (streq(i->interface, interface)) { + + if (i->vtable == vtable) { + r = -EEXIST; + goto fail; + } + + existing = i; + } + } + + c = new0(struct node_vtable, 1); + if (!c) { + r = -ENOMEM; + goto fail; + } + + c->node = n; + c->is_fallback = fallback; + c->vtable = vtable; + c->userdata = userdata; + c->find = find; + + c->interface = strdup(interface); + if (!c->interface) { + r = -ENOMEM; + goto fail; + } + + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + + switch (v->type) { + + case _SD_BUS_VTABLE_METHOD: { + struct vtable_member *m; + + 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) || + !(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; + goto fail; + } + + m = new0(struct vtable_member, 1); + if (!m) { + r = -ENOMEM; + goto fail; + } + + m->parent = c; + m->path = n->path; + m->interface = c->interface; + m->member = v->x.method.member; + m->vtable = v; + + r = hashmap_put(bus->vtable_methods, m, m); + if (r < 0) { + free(m); + goto fail; + } + + break; + } + + case _SD_BUS_VTABLE_WRITABLE_PROPERTY: + + if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) { + r = -EINVAL; + goto fail; + } + + /* Fall through */ + + case _SD_BUS_VTABLE_PROPERTY: { + struct vtable_member *m; + + if (!member_name_is_valid(v->x.property.member) || + !signature_is_single(v->x.property.signature, false) || + !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) || + v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY || + (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 || + (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) { + r = -EINVAL; + goto fail; + } + + m = new0(struct vtable_member, 1); + if (!m) { + r = -ENOMEM; + goto fail; + } + + m->parent = c; + m->path = n->path; + m->interface = c->interface; + m->member = v->x.property.member; + m->vtable = v; + + r = hashmap_put(bus->vtable_properties, m, m); + if (r < 0) { + free(m); + goto fail; + } + + break; + } + + case _SD_BUS_VTABLE_SIGNAL: + + if (!member_name_is_valid(v->x.signal.member) || + !signature_is_valid(strempty(v->x.signal.signature), false) || + v->flags & SD_BUS_VTABLE_UNPRIVILEGED) { + r = -EINVAL; + goto fail; + } + + break; + + default: + r = -EINVAL; + goto fail; + } + } + + LIST_INSERT_AFTER(vtables, n->vtables, existing, c); + bus->nodes_modified = true; + + return 0; + +fail: + if (c) + free_node_vtable(bus, c); + + bus_node_gc(bus, n); + return r; +} + +static int remove_object_vtable_internal( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + bool fallback, + sd_bus_object_find_t find, + void *userdata) { + + struct node_vtable *c; + struct node *n; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(interface_name_is_valid(interface), -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = hashmap_get(bus->nodes, path); + if (!n) + return 0; + + LIST_FOREACH(vtables, c, n->vtables) + if (streq(c->interface, interface) && + c->is_fallback == fallback && + c->vtable == vtable && + c->find == find && + c->userdata == userdata) + break; + + if (!c) + return 0; + + LIST_REMOVE(vtables, n->vtables, c); + + free_node_vtable(bus, c); + bus_node_gc(bus, n); + + bus->nodes_modified = true; + + return 1; +} + +_public_ int sd_bus_add_object_vtable( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + void *userdata) { + + return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata); +} + +_public_ int sd_bus_remove_object_vtable( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + void *userdata) { + + return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata); +} + +_public_ int sd_bus_add_fallback_vtable( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + sd_bus_object_find_t find, + void *userdata) { + + return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata); +} + +_public_ int sd_bus_remove_fallback_vtable( + sd_bus *bus, + const char *path, + const char *interface, + const sd_bus_vtable *vtable, + sd_bus_object_find_t find, + void *userdata) { + + return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata); +} + +_public_ int sd_bus_add_node_enumerator( + sd_bus *bus, + const char *path, + sd_bus_node_enumerator_t callback, + void *userdata) { + + struct node_enumerator *c; + struct node *n; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = bus_node_allocate(bus, path); + if (!n) + return -ENOMEM; + + c = new0(struct node_enumerator, 1); + if (!c) { + r = -ENOMEM; + goto fail; + } + + c->node = n; + c->callback = callback; + c->userdata = userdata; + + LIST_PREPEND(enumerators, n->enumerators, c); + + bus->nodes_modified = true; + + return 0; + +fail: + free(c); + bus_node_gc(bus, n); + return r; +} + +_public_ int sd_bus_remove_node_enumerator( + sd_bus *bus, + const char *path, + sd_bus_node_enumerator_t callback, + void *userdata) { + + struct node_enumerator *c; + struct node *n; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = hashmap_get(bus->nodes, path); + if (!n) + return 0; + + LIST_FOREACH(enumerators, c, n->enumerators) + if (c->callback == callback && c->userdata == userdata) + break; + + if (!c) + return 0; + + LIST_REMOVE(enumerators, n->enumerators, c); + free(c); + + bus_node_gc(bus, n); + + bus->nodes_modified = true; + + return 1; +} + +static int emit_properties_changed_on_interface( + sd_bus *bus, + const char *prefix, + const char *path, + const char *interface, + bool require_fallback, + bool *found_interface, + char **names) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + bool has_invalidating = false, has_changing = false; + struct vtable_member key = {}; + struct node_vtable *c; + struct node *n; + char **property; + void *u = NULL; + int r; + + assert(bus); + assert(prefix); + assert(path); + assert(interface); + assert(found_interface); + + n = hashmap_get(bus->nodes, prefix); + if (!n) + return 0; + + r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "s", interface); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "{sv}"); + if (r < 0) + return r; + + key.path = prefix; + key.interface = interface; + + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; + + if (!streq(c->interface, interface)) + continue; + + r = node_vtable_get_userdata(bus, path, c, &u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + *found_interface = true; + + if (names) { + /* If the caller specified a list of + * properties we include exactly those in the + * PropertiesChanged message */ + + STRV_FOREACH(property, names) { + struct vtable_member *v; + + assert_return(member_name_is_valid(*property), -EINVAL); + + key.member = *property; + v = hashmap_get(bus->vtable_properties, &key); + if (!v) + return -ENOENT; + + /* If there are two vtables for the same + * interface, let's handle this property when + * we come to that vtable. */ + if (c != v->parent) + continue; + + assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE || + v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM); + + assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM); + + if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) { + has_invalidating = true; + continue; + } + + has_changing = true; + + r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + } else { + const sd_bus_vtable *v; + + /* If the caller specified no properties list + * we include all properties that are marked + * as changing in the message. */ + + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + continue; + + if (v->flags & SD_BUS_VTABLE_HIDDEN) + continue; + + if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) { + has_invalidating = true; + continue; + } + + if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) + continue; + + has_changing = true; + + r = vtable_append_one_property(bus, m, m->path, c, v, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + } + } + + if (!has_invalidating && !has_changing) + return 0; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return r; + + if (has_invalidating) { + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; + + if (!streq(c->interface, interface)) + continue; + + r = node_vtable_get_userdata(bus, path, c, &u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + if (names) { + STRV_FOREACH(property, names) { + struct vtable_member *v; + + key.member = *property; + assert_se(v = hashmap_get(bus->vtable_properties, &key)); + assert(c == v->parent); + + if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) + continue; + + r = sd_bus_message_append(m, "s", *property); + if (r < 0) + return r; + } + } else { + const sd_bus_vtable *v; + + for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) { + if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) + continue; + + if (v->flags & SD_BUS_VTABLE_HIDDEN) + continue; + + if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) + continue; + + r = sd_bus_message_append(m, "s", v->x.property.member); + if (r < 0) + return r; + } + } + } + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_send(bus, m, NULL); + if (r < 0) + return r; + + return 1; +} + +_public_ int sd_bus_emit_properties_changed_strv( + sd_bus *bus, + const char *path, + const char *interface, + char **names) { + + BUS_DONT_DESTROY(bus); + bool found_interface = false; + char *prefix; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(interface_name_is_valid(interface), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + + /* A non-NULL but empty names list means nothing needs to be + generated. A NULL list OTOH indicates that all properties + that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be + included in the PropertiesChanged message. */ + if (names && names[0] == NULL) + return 0; + + do { + bus->nodes_modified = false; + + r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names); + if (r != 0) + return r; + if (bus->nodes_modified) + continue; + + prefix = alloca(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) + return r; + if (bus->nodes_modified) + break; + } + + } while (bus->nodes_modified); + + return found_interface ? 0 : -ENOENT; +} + +_public_ int sd_bus_emit_properties_changed( + sd_bus *bus, + const char *path, + const char *interface, + const char *name, ...) { + + char **names; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(interface_name_is_valid(interface), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (!name) + return 0; + + names = strv_from_stdarg_alloca(name); + + return sd_bus_emit_properties_changed_strv(bus, path, interface, names); +} + +static int interfaces_added_append_one_prefix( + sd_bus *bus, + sd_bus_message *m, + const char *prefix, + const char *path, + const char *interface, + bool require_fallback) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + bool found_interface = false; + struct node_vtable *c; + struct node *n; + void *u = NULL; + int r; + + assert(bus); + assert(m); + assert(prefix); + assert(path); + assert(interface); + + n = hashmap_get(bus->nodes, prefix); + if (!n) + return 0; + + LIST_FOREACH(vtables, c, n->vtables) { + if (require_fallback && !c->is_fallback) + continue; + + if (!streq(c->interface, interface)) + continue; + + r = node_vtable_get_userdata(bus, path, c, &u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + if (r == 0) + continue; + + if (!found_interface) { + r = sd_bus_message_append_basic(m, 's', interface); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "{sv}"); + if (r < 0) + return r; + + found_interface = true; + } + + r = vtable_append_all_properties(bus, m, path, c, u, &error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } + + if (found_interface) { + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + } + + return found_interface; +} + +static int interfaces_added_append_one( + sd_bus *bus, + sd_bus_message *m, + const char *path, + const char *interface) { + + char *prefix; + int r; + + assert(bus); + assert(m); + assert(path); + assert(interface); + + r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false); + if (r != 0) + return r; + if (bus->nodes_modified) + return 0; + + prefix = alloca(strlen(path) + 1); + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true); + if (r != 0) + return r; + if (bus->nodes_modified) + return 0; + } + + return -ENOENT; +} + +_public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) { + BUS_DONT_DESTROY(bus); + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + char **i; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (strv_isempty(interfaces)) + return 0; + + do { + bus->nodes_modified = false; + + if (m) + m = sd_bus_message_unref(m); + + r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); + if (r < 0) + return r; + + r = sd_bus_message_append_basic(m, 'o', path); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "{sa{sv}}"); + if (r < 0) + return r; + + STRV_FOREACH(i, interfaces) { + assert_return(interface_name_is_valid(*i), -EINVAL); + + r = sd_bus_message_open_container(m, 'e', "sa{sv}"); + if (r < 0) + return r; + + r = interfaces_added_append_one(bus, m, path, *i); + if (r < 0) + return r; + + if (bus->nodes_modified) + break; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + } + + if (bus->nodes_modified) + continue; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + } while (bus->nodes_modified); + + return sd_bus_send(bus, m, NULL); +} + +_public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) { + char **interfaces; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + interfaces = strv_from_stdarg_alloca(interface); + + return sd_bus_emit_interfaces_added_strv(bus, path, interfaces); +} + +_public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (strv_isempty(interfaces)) + return 0; + + r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); + if (r < 0) + return r; + + r = sd_bus_message_append_basic(m, 'o', path); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(m, interfaces); + if (r < 0) + return r; + + return sd_bus_send(bus, m, NULL); +} + +_public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) { + char **interfaces; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + interfaces = strv_from_stdarg_alloca(interface); + + return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces); +} + +_public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) { + struct node *n; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = bus_node_allocate(bus, path); + if (!n) + return -ENOMEM; + + n->object_manager = true; + bus->nodes_modified = true; + return 0; +} + +_public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) { + struct node *n; + + assert_return(bus, -EINVAL); + assert_return(object_path_is_valid(path), -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = hashmap_get(bus->nodes, path); + if (!n) + return 0; + + if (!n->object_manager) + return 0; + + n->object_manager = false; + bus->nodes_modified = true; + bus_node_gc(bus, n); + + return 1; +} diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h new file mode 100644 index 0000000..420edd9 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-objects.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "bus-internal.h" + +int bus_process_object(sd_bus *bus, sd_bus_message *m); diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h new file mode 100644 index 0000000..5046d17 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-protocol.h @@ -0,0 +1,147 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + + +/* Endianness */ + +enum { + _BUS_INVALID_ENDIAN = 0, + BUS_LITTLE_ENDIAN = 'l', + BUS_BIG_ENDIAN = 'B', +#if __BYTE_ORDER == __BIG_ENDIAN + BUS_NATIVE_ENDIAN = BUS_BIG_ENDIAN, + BUS_REVERSE_ENDIAN = BUS_LITTLE_ENDIAN +#else + BUS_NATIVE_ENDIAN = BUS_LITTLE_ENDIAN, + BUS_REVERSE_ENDIAN = BUS_BIG_ENDIAN +#endif +}; + +/* Flags */ + +enum { + BUS_MESSAGE_NO_REPLY_EXPECTED = 1, + BUS_MESSAGE_NO_AUTO_START = 2 +}; + +/* Header fields */ + +enum { + _BUS_MESSAGE_HEADER_INVALID = 0, + BUS_MESSAGE_HEADER_PATH, + BUS_MESSAGE_HEADER_INTERFACE, + BUS_MESSAGE_HEADER_MEMBER, + BUS_MESSAGE_HEADER_ERROR_NAME, + BUS_MESSAGE_HEADER_REPLY_SERIAL, + BUS_MESSAGE_HEADER_DESTINATION, + BUS_MESSAGE_HEADER_SENDER, + BUS_MESSAGE_HEADER_SIGNATURE, + BUS_MESSAGE_HEADER_UNIX_FDS, + _BUS_MESSAGE_HEADER_MAX +}; + +/* RequestName parameters */ + +enum { + BUS_NAME_ALLOW_REPLACEMENT = 1, + BUS_NAME_REPLACE_EXISTING = 2, + BUS_NAME_DO_NOT_QUEUE = 4 +}; + +/* RequestName returns */ +enum { + BUS_NAME_PRIMARY_OWNER = 1, + BUS_NAME_IN_QUEUE = 2, + BUS_NAME_EXISTS = 3, + BUS_NAME_ALREADY_OWNER = 4 +}; + +/* ReleaseName returns */ +enum { + BUS_NAME_RELEASED = 1, + BUS_NAME_NON_EXISTENT = 2, + BUS_NAME_NOT_OWNER = 3, +}; + +/* StartServiceByName returns */ +enum { + BUS_START_REPLY_SUCCESS = 1, + BUS_START_REPLY_ALREADY_RUNNING = 2, +}; + +#define BUS_INTROSPECT_DOCTYPE \ + "\n" + +#define BUS_INTROSPECT_INTERFACE_PEER \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" + +#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" + +#define BUS_INTROSPECT_INTERFACE_PROPERTIES \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" + +#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" diff --git a/src/libsystemd/sd-bus/bus-signature.c b/src/libsystemd/sd-bus/bus-signature.c new file mode 100644 index 0000000..1e5bf48 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-signature.c @@ -0,0 +1,160 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "bus-signature.h" +#include "bus-type.h" + +static int signature_element_length_internal( + const char *s, + bool allow_dict_entry, + unsigned array_depth, + unsigned struct_depth, + size_t *l) { + + int r; + + if (!s) + return -EINVAL; + + assert(l); + + if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) { + *l = 1; + return 0; + } + + if (*s == SD_BUS_TYPE_ARRAY) { + size_t t; + + if (array_depth >= 32) + return -EINVAL; + + r = signature_element_length_internal(s + 1, true, array_depth+1, struct_depth, &t); + if (r < 0) + return r; + + *l = t + 1; + return 0; + } + + if (*s == SD_BUS_TYPE_STRUCT_BEGIN) { + const char *p = s + 1; + + if (struct_depth >= 32) + return -EINVAL; + + while (*p != SD_BUS_TYPE_STRUCT_END) { + size_t t; + + r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t); + if (r < 0) + return r; + + p += t; + } + + *l = p - s + 1; + return 0; + } + + if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) { + const char *p = s + 1; + unsigned n = 0; + + if (struct_depth >= 32) + return -EINVAL; + + while (*p != SD_BUS_TYPE_DICT_ENTRY_END) { + size_t t; + + if (n == 0 && !bus_type_is_basic(*p)) + return -EINVAL; + + r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t); + if (r < 0) + return r; + + p += t; + n++; + } + + if (n != 2) + return -EINVAL; + + *l = p - s + 1; + return 0; + } + + return -EINVAL; +} + + +int signature_element_length(const char *s, size_t *l) { + return signature_element_length_internal(s, true, 0, 0, l); +} + +bool signature_is_single(const char *s, bool allow_dict_entry) { + int r; + size_t t; + + if (!s) + return false; + + r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t); + if (r < 0) + return false; + + return s[t] == 0; +} + +bool signature_is_pair(const char *s) { + + if (!s) + return false; + + if (!bus_type_is_basic(*s)) + return false; + + return signature_is_single(s + 1, false); +} + +bool signature_is_valid(const char *s, bool allow_dict_entry) { + const char *p; + int r; + + if (!s) + return false; + + p = s; + while (*p) { + size_t t; + + r = signature_element_length_internal(p, allow_dict_entry, 0, 0, &t); + if (r < 0) + return false; + + p += t; + } + + return p - s <= 255; +} diff --git a/src/libsystemd/sd-bus/bus-signature.h b/src/libsystemd/sd-bus/bus-signature.h new file mode 100644 index 0000000..2e06e30 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-signature.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +bool signature_is_single(const char *s, bool allow_dict_entry); +bool signature_is_pair(const char *s); +bool signature_is_valid(const char *s, bool allow_dict_entry); + +int signature_element_length(const char *s, size_t *l); diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c new file mode 100644 index 0000000..0c4b6af --- /dev/null +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -0,0 +1,1105 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "missing.h" +#include "strv.h" +#include "utf8.h" +#include "sd-daemon.h" + +#include "sd-bus.h" +#include "bus-socket.h" +#include "bus-internal.h" +#include "bus-message.h" + +#define SNDBUF_SIZE (8*1024*1024) + +static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) { + + while (size > 0) { + struct iovec *i = iov + *idx; + + if (i->iov_len > size) { + i->iov_base = (uint8_t*) i->iov_base + size; + i->iov_len -= size; + return; + } + + size -= i->iov_len; + + i->iov_base = NULL; + i->iov_len = 0; + + (*idx) ++; + } +} + +static int append_iovec(sd_bus_message *m, const void *p, size_t sz) { + assert(m); + assert(p); + assert(sz > 0); + + m->iovec[m->n_iovec].iov_base = (void*) p; + m->iovec[m->n_iovec].iov_len = sz; + m->n_iovec++; + + return 0; +} + +static int bus_message_setup_iovec(sd_bus_message *m) { + struct bus_body_part *part; + unsigned n, i; + int r; + + assert(m); + assert(m->sealed); + + if (m->n_iovec > 0) + return 0; + + assert(!m->iovec); + + n = 1 + m->n_body_parts; + if (n < ELEMENTSOF(m->iovec_fixed)) + m->iovec = m->iovec_fixed; + else { + m->iovec = new(struct iovec, n); + if (!m->iovec) { + r = -ENOMEM; + goto fail; + } + } + + r = append_iovec(m, m->header, BUS_MESSAGE_BODY_BEGIN(m)); + if (r < 0) + goto fail; + + MESSAGE_FOREACH_PART(part, i, m) { + r = bus_body_part_map(part); + if (r < 0) + goto fail; + + r = append_iovec(m, part->data, part->size); + if (r < 0) + goto fail; + } + + assert(n == m->n_iovec); + + return 0; + +fail: + m->poisoned = true; + return r; +} + +bool bus_socket_auth_needs_write(sd_bus *b) { + + unsigned i; + + if (b->auth_index >= ELEMENTSOF(b->auth_iovec)) + return false; + + for (i = b->auth_index; i < ELEMENTSOF(b->auth_iovec); i++) { + struct iovec *j = b->auth_iovec + i; + + if (j->iov_len > 0) + return true; + } + + return false; +} + +static int bus_socket_write_auth(sd_bus *b) { + ssize_t k; + + assert(b); + assert(b->state == BUS_AUTHENTICATING); + + if (!bus_socket_auth_needs_write(b)) + return 0; + + if (b->prefer_writev) + k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index); + else { + struct msghdr mh; + zero(mh); + + mh.msg_iov = b->auth_iovec + b->auth_index; + mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index; + + k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + if (k < 0 && errno == ENOTSOCK) { + b->prefer_writev = true; + k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index); + } + } + + if (k < 0) + return errno == EAGAIN ? 0 : -errno; + + iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k); + return 1; +} + +static int bus_socket_auth_verify_client(sd_bus *b) { + char *e, *f, *start; + sd_id128_t peer; + unsigned i; + int r; + + assert(b); + + /* We expect two response lines: "OK" and possibly + * "AGREE_UNIX_FD" */ + + e = memmem(b->rbuffer, b->rbuffer_size, "\r\n", 2); + if (!e) + return 0; + + if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) { + f = memmem(e + 2, b->rbuffer_size - (e - (char*) b->rbuffer) - 2, "\r\n", 2); + if (!f) + return 0; + + start = f + 2; + } else { + f = NULL; + start = e + 2; + } + + /* Nice! We got all the lines we need. First check the OK + * line */ + + if (e - (char*) b->rbuffer != 3 + 32) + return -EPERM; + + if (memcmp(b->rbuffer, "OK ", 3)) + return -EPERM; + + b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL; + + for (i = 0; i < 32; i += 2) { + int x, y; + + x = unhexchar(((char*) b->rbuffer)[3 + i]); + y = unhexchar(((char*) b->rbuffer)[3 + i + 1]); + + if (x < 0 || y < 0) + return -EINVAL; + + peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y); + } + + if (!sd_id128_equal(b->server_id, SD_ID128_NULL) && + !sd_id128_equal(b->server_id, peer)) + return -EPERM; + + b->server_id = peer; + + /* And possibly check the second line, too */ + + if (f) + b->can_fds = + (f - e == sizeof("\r\nAGREE_UNIX_FD") - 1) && + memcmp(e + 2, "AGREE_UNIX_FD", sizeof("AGREE_UNIX_FD") - 1) == 0; + + b->rbuffer_size -= (start - (char*) b->rbuffer); + memmove(b->rbuffer, start, b->rbuffer_size); + + r = bus_start_running(b); + if (r < 0) + return r; + + return 1; +} + +static bool line_equals(const char *s, size_t m, const char *line) { + size_t l; + + l = strlen(line); + if (l != m) + return false; + + return memcmp(s, line, l) == 0; +} + +static bool line_begins(const char *s, size_t m, const char *word) { + size_t l; + + l = strlen(word); + if (m < l) + return false; + + if (memcmp(s, word, l) != 0) + return false; + + return m == l || (m > l && s[l] == ' '); +} + +static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { + _cleanup_free_ char *token = NULL; + + if (!b->anonymous_auth) + return 0; + + if (l <= 0) + return 1; + + assert(p[0] == ' '); + p++; l--; + + if (l % 2 != 0) + return 0; + token = unhexmem(p, l); + if (!token) + return -ENOMEM; + + if (memchr(token, 0, l/2)) + return 0; + + return !!utf8_is_valid(token); +} + +static int verify_external_token(sd_bus *b, const char *p, size_t l) { + _cleanup_free_ char *token = NULL; + uid_t u; + int r; + + /* We don't do any real authentication here. Instead, we if + * the owner of this bus wanted authentication he should have + * checked SO_PEERCRED before even creating the bus object. */ + + if (!b->anonymous_auth && !b->ucred_valid) + return 0; + + if (l <= 0) + return 1; + + assert(p[0] == ' '); + p++; l--; + + if (l % 2 != 0) + return 0; + + token = unhexmem(p, l); + if (!token) + return -ENOMEM; + + if (memchr(token, 0, l/2)) + return 0; + + r = parse_uid(token, &u); + if (r < 0) + return 0; + + /* We ignore the passed value if anonymous authentication is + * on anyway. */ + if (!b->anonymous_auth && u != b->ucred.uid) + return 0; + + return 1; +} + +static int bus_socket_auth_write(sd_bus *b, const char *t) { + char *p; + size_t l; + + assert(b); + assert(t); + + /* We only make use of the first iovec */ + assert(b->auth_index == 0 || b->auth_index == 1); + + l = strlen(t); + p = malloc(b->auth_iovec[0].iov_len + l); + if (!p) + return -ENOMEM; + + memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); + memcpy(p + b->auth_iovec[0].iov_len, t, l); + + b->auth_iovec[0].iov_base = p; + b->auth_iovec[0].iov_len += l; + + free(b->auth_buffer); + b->auth_buffer = p; + b->auth_index = 0; + return 0; +} + +static int bus_socket_auth_write_ok(sd_bus *b) { + char t[3 + 32 + 2 + 1]; + + assert(b); + + snprintf(t, sizeof(t), "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->server_id)); + char_array_0(t); + + return bus_socket_auth_write(b, t); +} + +static int bus_socket_auth_verify_server(sd_bus *b) { + char *e; + const char *line; + size_t l; + bool processed = false; + int r; + + assert(b); + + if (b->rbuffer_size < 1) + return 0; + + /* First char must be a NUL byte */ + if (*(char*) b->rbuffer != 0) + return -EIO; + + if (b->rbuffer_size < 3) + return 0; + + /* Begin with the first line */ + if (b->auth_rbegin <= 0) + b->auth_rbegin = 1; + + for (;;) { + /* Check if line is complete */ + line = (char*) b->rbuffer + b->auth_rbegin; + e = memmem(line, b->rbuffer_size - b->auth_rbegin, "\r\n", 2); + if (!e) + return processed; + + l = e - line; + + if (line_begins(line, l, "AUTH ANONYMOUS")) { + + r = verify_anonymous_token(b, line + 14, l - 14); + 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); + } + + } else if (line_begins(line, l, "AUTH EXTERNAL")) { + + r = verify_external_token(b, line + 13, l - 13); + 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); + } + + } else if (line_begins(line, l, "AUTH")) + r = bus_socket_auth_write(b, "REJECTED EXTERNAL ANONYMOUS\r\n"); + else if (line_equals(line, l, "CANCEL") || + line_begins(line, l, "ERROR")) { + + b->auth = _BUS_AUTH_INVALID; + r = bus_socket_auth_write(b, "REJECTED\r\n"); + + } else if (line_equals(line, l, "BEGIN")) { + + if (b->auth == _BUS_AUTH_INVALID) + r = bus_socket_auth_write(b, "ERROR\r\n"); + else { + /* We can't leave from the auth phase + * before we haven't written + * everything queued, so let's check + * that */ + + if (bus_socket_auth_needs_write(b)) + return 1; + + b->rbuffer_size -= (e + 2 - (char*) b->rbuffer); + memmove(b->rbuffer, e + 2, b->rbuffer_size); + return bus_start_running(b); + } + + } else if (line_begins(line, l, "DATA")) { + + if (b->auth == _BUS_AUTH_INVALID) + r = bus_socket_auth_write(b, "ERROR\r\n"); + else { + if (b->auth == BUS_AUTH_ANONYMOUS) + r = verify_anonymous_token(b, line + 4, l - 4); + else + r = verify_external_token(b, line + 4, l - 4); + + if (r < 0) + return r; + if (r == 0) { + b->auth = _BUS_AUTH_INVALID; + r = bus_socket_auth_write(b, "REJECTED\r\n"); + } else + r = bus_socket_auth_write_ok(b); + } + } else if (line_equals(line, l, "NEGOTIATE_UNIX_FD")) { + if (b->auth == _BUS_AUTH_INVALID || !(b->hello_flags & KDBUS_HELLO_ACCEPT_FD)) + r = bus_socket_auth_write(b, "ERROR\r\n"); + else { + b->can_fds = true; + r = bus_socket_auth_write(b, "AGREE_UNIX_FD\r\n"); + } + } else + r = bus_socket_auth_write(b, "ERROR\r\n"); + + if (r < 0) + return r; + + b->auth_rbegin = e + 2 - (char*) b->rbuffer; + + processed = true; + } +} + +static int bus_socket_auth_verify(sd_bus *b) { + assert(b); + + if (b->is_server) + return bus_socket_auth_verify_server(b); + else + return bus_socket_auth_verify_client(b); +} + +static int bus_socket_read_auth(sd_bus *b) { + struct msghdr mh; + struct iovec iov; + size_t n; + ssize_t k; + int r; + void *p; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) + + CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(NAME_MAX)]; /*selinux label */ + } control; + struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(b); + assert(b->state == BUS_AUTHENTICATING); + + r = bus_socket_auth_verify(b); + if (r != 0) + return r; + + n = MAX(256u, b->rbuffer_size * 2); + + if (n > BUS_AUTH_SIZE_MAX) + n = BUS_AUTH_SIZE_MAX; + + if (b->rbuffer_size >= n) + return -ENOBUFS; + + p = realloc(b->rbuffer, n); + if (!p) + return -ENOMEM; + + b->rbuffer = p; + + zero(iov); + iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size; + iov.iov_len = n - b->rbuffer_size; + + if (b->prefer_readv) + k = readv(b->input_fd, &iov, 1); + else { + zero(mh); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (k < 0 && errno == ENOTSOCK) { + b->prefer_readv = true; + k = readv(b->input_fd, &iov, 1); + } else + handle_cmsg = true; + } + if (k < 0) + return errno == EAGAIN ? 0 : -errno; + if (k == 0) + return -ECONNRESET; + + b->rbuffer_size += k; + + if (handle_cmsg) { + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int j; + + /* Whut? We received fds during the auth + * protocol? Somebody is playing games with + * us. Close them all, and fail */ + j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + close_many((int*) CMSG_DATA(cmsg), j); + return -EIO; + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + /* Ignore bogus data, which we might + * get on socketpair() sockets */ + if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) { + memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + b->ucred_valid = true; + } + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_SECURITY) { + + size_t l; + + l = cmsg->cmsg_len - CMSG_LEN(0); + if (l > 0) { + memcpy(&b->label, CMSG_DATA(cmsg), l); + b->label[l] = 0; + } + } + } + } + + r = bus_socket_auth_verify(b); + if (r != 0) + return r; + + return 1; +} + +void bus_socket_setup(sd_bus *b) { + int enable; + + assert(b); + + /* Enable SO_PASSCRED + SO_PASSEC. We try this on any + * socket, just in case. */ + enable = !b->bus_client; + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); + + enable = !b->bus_client && (b->attach_flags & KDBUS_ATTACH_SECLABEL); + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); + + /* Increase the buffers to 8 MB */ + fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE); + fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE); + + b->is_kernel = false; + b->message_version = 1; + b->message_endian = 0; +} + +static void bus_get_peercred(sd_bus *b) { + assert(b); + + /* Get the peer for socketpair() sockets */ + b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; +} + +static int bus_socket_start_auth_client(sd_bus *b) { + size_t l; + const char *auth_suffix, *auth_prefix; + + 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[20 + 1]; /* enough space for a 64bit integer plus NUL */ + + auth_prefix = "\0AUTH EXTERNAL "; + + snprintf(text, sizeof(text), "%lu", (unsigned long) geteuid()); + char_array_0(text); + + l = strlen(text); + b->auth_buffer = hexmem(text, l); + } + + if (!b->auth_buffer) + return -ENOMEM; + + if (b->hello_flags & KDBUS_HELLO_ACCEPT_FD) + auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n"; + else + auth_suffix = "\r\nBEGIN\r\n"; + + b->auth_iovec[0].iov_base = (void*) auth_prefix; + b->auth_iovec[0].iov_len = 1 + strlen(auth_prefix + 1); + b->auth_iovec[1].iov_base = (void*) b->auth_buffer; + b->auth_iovec[1].iov_len = l * 2; + b->auth_iovec[2].iov_base = (void*) auth_suffix; + b->auth_iovec[2].iov_len = strlen(auth_suffix); + + return bus_socket_write_auth(b); +} + +int bus_socket_start_auth(sd_bus *b) { + assert(b); + + bus_get_peercred(b); + + b->state = BUS_AUTHENTICATING; + b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT; + + if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0) + b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; + + if (b->output_fd != b->input_fd) + if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0) + b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD; + + if (b->is_server) + return bus_socket_read_auth(b); + else + return bus_socket_start_auth_client(b); +} + +int bus_socket_connect(sd_bus *b) { + int r; + + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + assert(b->sockaddr.sa.sa_family != AF_UNSPEC); + + b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (b->input_fd < 0) + return -errno; + + b->output_fd = b->input_fd; + + bus_socket_setup(b); + + r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); + if (r < 0) { + if (errno == EINPROGRESS) + return 1; + + return -errno; + } + + return bus_socket_start_auth(b); +} + +int bus_socket_exec(sd_bus *b) { + int s[2], r; + pid_t pid; + + assert(b); + assert(b->input_fd < 0); + assert(b->output_fd < 0); + assert(b->exec_path); + + r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); + if (r < 0) + return -errno; + + pid = fork(); + if (pid < 0) { + close_pipe(s); + return -errno; + } + if (pid == 0) { + /* Child */ + + reset_all_signal_handlers(); + + close_all_fds(s+1, 1); + + assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO); + assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO); + + if (s[1] != STDIN_FILENO && s[1] != STDOUT_FILENO) + close_nointr_nofail(s[1]); + + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_nonblock(STDIN_FILENO, false); + fd_nonblock(STDOUT_FILENO, false); + + if (b->exec_argv) + execvp(b->exec_path, b->exec_argv); + else { + const char *argv[] = { b->exec_path, NULL }; + execvp(b->exec_path, (char**) argv); + } + + _exit(EXIT_FAILURE); + } + + close_nointr_nofail(s[1]); + b->output_fd = b->input_fd = s[0]; + + bus_socket_setup(b); + + return bus_socket_start_auth(b); +} + +int bus_socket_take_fd(sd_bus *b) { + assert(b); + + bus_socket_setup(b); + + return bus_socket_start_auth(b); +} + +int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { + struct iovec *iov; + ssize_t k; + size_t n; + unsigned j; + int r; + + assert(bus); + assert(m); + assert(idx); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + if (*idx >= BUS_MESSAGE_SIZE(m)) + return 0; + + r = bus_message_setup_iovec(m); + if (r < 0) + return r; + + n = m->n_iovec * sizeof(struct iovec); + iov = alloca(n); + memcpy(iov, m->iovec, n); + + j = 0; + iovec_advance(iov, &j, *idx); + + if (bus->prefer_writev) + k = writev(bus->output_fd, iov, m->n_iovec); + else { + struct msghdr mh; + zero(mh); + + if (m->n_fds > 0) { + struct cmsghdr *control; + control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds)); + + mh.msg_control = control; + control->cmsg_level = SOL_SOCKET; + control->cmsg_type = SCM_RIGHTS; + mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds); + memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds); + } + + mh.msg_iov = iov; + mh.msg_iovlen = m->n_iovec; + + k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + if (k < 0 && errno == ENOTSOCK) { + bus->prefer_writev = true; + k = writev(bus->output_fd, iov, m->n_iovec); + } + } + + if (k < 0) + return errno == EAGAIN ? 0 : -errno; + + *idx += (size_t) k; + return 1; +} + +static int bus_socket_read_message_need(sd_bus *bus, size_t *need) { + uint32_t a, b; + uint8_t e; + uint64_t sum; + + assert(bus); + assert(need); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + if (bus->rbuffer_size < sizeof(struct bus_header)) { + *need = sizeof(struct bus_header) + 8; + + /* Minimum message size: + * + * Header + + * + * Method Call: +2 string headers + * Signal: +3 string headers + * Method Error: +1 string headers + * +1 uint32 headers + * Method Reply: +1 uint32 headers + * + * A string header is at least 9 bytes + * A uint32 header is at least 8 bytes + * + * Hence the minimum message size of a valid message + * is header + 8 bytes */ + + return 0; + } + + a = ((const uint32_t*) bus->rbuffer)[1]; + b = ((const uint32_t*) bus->rbuffer)[3]; + + e = ((const uint8_t*) bus->rbuffer)[0]; + if (e == BUS_LITTLE_ENDIAN) { + a = le32toh(a); + b = le32toh(b); + } else if (e == BUS_BIG_ENDIAN) { + a = be32toh(a); + b = be32toh(b); + } else + return -EBADMSG; + + sum = (uint64_t) sizeof(struct bus_header) + (uint64_t) ALIGN_TO(b, 8) + (uint64_t) a; + if (sum >= BUS_MESSAGE_SIZE_MAX) + return -ENOBUFS; + + *need = (size_t) sum; + return 0; +} + +static int bus_socket_make_message(sd_bus *bus, size_t size) { + sd_bus_message *t; + void *b; + int r; + + assert(bus); + assert(bus->rbuffer_size >= size); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + r = bus_rqueue_make_room(bus); + if (r < 0) + return r; + + if (bus->rbuffer_size > size) { + b = memdup((const uint8_t*) bus->rbuffer + size, + bus->rbuffer_size - size); + if (!b) + return -ENOMEM; + } else + b = NULL; + + r = bus_message_from_malloc(bus, + bus->rbuffer, size, + bus->fds, bus->n_fds, + !bus->bus_client && bus->ucred_valid ? &bus->ucred : NULL, + !bus->bus_client && bus->label[0] ? bus->label : NULL, + &t); + if (r < 0) { + free(b); + return r; + } + + bus->rbuffer = b; + bus->rbuffer_size -= size; + + bus->fds = NULL; + bus->n_fds = 0; + + bus->rqueue[bus->rqueue_size++] = t; + + return 1; +} + +int bus_socket_read_message(sd_bus *bus) { + struct msghdr mh; + struct iovec iov; + ssize_t k; + size_t need; + int r; + void *b; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX) + + CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(NAME_MAX)]; /*selinux label */ + } control; + struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(bus); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + r = bus_socket_read_message_need(bus, &need); + if (r < 0) + return r; + + if (bus->rbuffer_size >= need) + return bus_socket_make_message(bus, need); + + b = realloc(bus->rbuffer, need); + if (!b) + return -ENOMEM; + + bus->rbuffer = b; + + zero(iov); + iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size; + iov.iov_len = need - bus->rbuffer_size; + + if (bus->prefer_readv) + k = readv(bus->input_fd, &iov, 1); + else { + zero(mh); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (k < 0 && errno == ENOTSOCK) { + bus->prefer_readv = true; + k = readv(bus->input_fd, &iov, 1); + } else + handle_cmsg = true; + } + if (k < 0) + return errno == EAGAIN ? 0 : -errno; + if (k == 0) + return -ECONNRESET; + + bus->rbuffer_size += k; + + if (handle_cmsg) { + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int n, *f; + + n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (!bus->can_fds) { + /* Whut? We received fds but this + * isn't actually enabled? Close them, + * and fail */ + + close_many((int*) CMSG_DATA(cmsg), n); + return -EIO; + } + + f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n)); + if (!f) { + close_many((int*) CMSG_DATA(cmsg), n); + return -ENOMEM; + } + + memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + bus->fds = f; + bus->n_fds += n; + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + /* Ignore bogus data, which we might + * get on socketpair() sockets */ + if (((struct ucred*) CMSG_DATA(cmsg))->pid != 0) { + memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + bus->ucred_valid = true; + } + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_SECURITY) { + + size_t l; + l = cmsg->cmsg_len - CMSG_LEN(0); + if (l > 0) { + memcpy(&bus->label, CMSG_DATA(cmsg), l); + bus->label[l] = 0; + } + } + } + } + + r = bus_socket_read_message_need(bus, &need); + if (r < 0) + return r; + + if (bus->rbuffer_size >= need) + return bus_socket_make_message(bus, need); + + return 1; +} + +int bus_socket_process_opening(sd_bus *b) { + int error = 0; + socklen_t slen = sizeof(error); + struct pollfd p = { + .fd = b->output_fd, + .events = POLLOUT, + }; + int r; + + assert(b->state == BUS_OPENING); + + r = poll(&p, 1, 0); + if (r < 0) + return -errno; + + if (!(p.revents & (POLLOUT|POLLERR|POLLHUP))) + return 0; + + r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen); + if (r < 0) + b->last_connect_error = errno; + else if (error != 0) + b->last_connect_error = error; + else if (p.revents & (POLLERR|POLLHUP)) + b->last_connect_error = ECONNREFUSED; + else + return bus_socket_start_auth(b); + + return bus_next_address(b); +} + +int bus_socket_process_authenticating(sd_bus *b) { + int r; + + assert(b); + assert(b->state == BUS_AUTHENTICATING); + + if (now(CLOCK_MONOTONIC) >= b->auth_timeout) + return -ETIMEDOUT; + + r = bus_socket_write_auth(b); + if (r != 0) + return r; + + return bus_socket_read_auth(b); +} diff --git a/src/libsystemd/sd-bus/bus-socket.h b/src/libsystemd/sd-bus/bus-socket.h new file mode 100644 index 0000000..5a1c7d4 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-socket.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" + +void bus_socket_setup(sd_bus *b); + +int bus_socket_connect(sd_bus *b); +int bus_socket_exec(sd_bus *b); +int bus_socket_take_fd(sd_bus *b); +int bus_socket_start_auth(sd_bus *b); + +int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx); +int bus_socket_read_message(sd_bus *bus); + +int bus_socket_process_opening(sd_bus *b); +int bus_socket_process_authenticating(sd_bus *b); + +bool bus_socket_auth_needs_write(sd_bus *b); diff --git a/src/libsystemd/sd-bus/bus-type.c b/src/libsystemd/sd-bus/bus-type.c new file mode 100644 index 0000000..b7914d1 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-type.c @@ -0,0 +1,179 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "bus-type.h" + +bool bus_type_is_valid(char c) { + static const char valid[] = { + SD_BUS_TYPE_BYTE, + SD_BUS_TYPE_BOOLEAN, + SD_BUS_TYPE_INT16, + SD_BUS_TYPE_UINT16, + SD_BUS_TYPE_INT32, + SD_BUS_TYPE_UINT32, + SD_BUS_TYPE_INT64, + SD_BUS_TYPE_UINT64, + SD_BUS_TYPE_DOUBLE, + SD_BUS_TYPE_STRING, + SD_BUS_TYPE_OBJECT_PATH, + SD_BUS_TYPE_SIGNATURE, + SD_BUS_TYPE_ARRAY, + SD_BUS_TYPE_VARIANT, + SD_BUS_TYPE_STRUCT, + SD_BUS_TYPE_DICT_ENTRY, + SD_BUS_TYPE_UNIX_FD + }; + + return !!memchr(valid, c, sizeof(valid)); +} + +bool bus_type_is_valid_in_signature(char c) { + static const char valid[] = { + SD_BUS_TYPE_BYTE, + SD_BUS_TYPE_BOOLEAN, + SD_BUS_TYPE_INT16, + SD_BUS_TYPE_UINT16, + SD_BUS_TYPE_INT32, + SD_BUS_TYPE_UINT32, + SD_BUS_TYPE_INT64, + SD_BUS_TYPE_UINT64, + SD_BUS_TYPE_DOUBLE, + SD_BUS_TYPE_STRING, + SD_BUS_TYPE_OBJECT_PATH, + SD_BUS_TYPE_SIGNATURE, + SD_BUS_TYPE_ARRAY, + SD_BUS_TYPE_VARIANT, + SD_BUS_TYPE_STRUCT_BEGIN, + SD_BUS_TYPE_STRUCT_END, + SD_BUS_TYPE_DICT_ENTRY_BEGIN, + SD_BUS_TYPE_DICT_ENTRY_END, + SD_BUS_TYPE_UNIX_FD + }; + + return !!memchr(valid, c, sizeof(valid)); +} + +bool bus_type_is_basic(char c) { + static const char valid[] = { + SD_BUS_TYPE_BYTE, + SD_BUS_TYPE_BOOLEAN, + SD_BUS_TYPE_INT16, + SD_BUS_TYPE_UINT16, + SD_BUS_TYPE_INT32, + SD_BUS_TYPE_UINT32, + SD_BUS_TYPE_INT64, + SD_BUS_TYPE_UINT64, + SD_BUS_TYPE_DOUBLE, + SD_BUS_TYPE_STRING, + SD_BUS_TYPE_OBJECT_PATH, + SD_BUS_TYPE_SIGNATURE, + SD_BUS_TYPE_UNIX_FD + }; + + return !!memchr(valid, c, sizeof(valid)); +} + +bool bus_type_is_trivial(char c) { + static const char valid[] = { + SD_BUS_TYPE_BYTE, + SD_BUS_TYPE_BOOLEAN, + SD_BUS_TYPE_INT16, + SD_BUS_TYPE_UINT16, + SD_BUS_TYPE_INT32, + SD_BUS_TYPE_UINT32, + SD_BUS_TYPE_INT64, + SD_BUS_TYPE_UINT64, + SD_BUS_TYPE_DOUBLE + }; + + return !!memchr(valid, c, sizeof(valid)); +} + +bool bus_type_is_container(char c) { + static const char valid[] = { + SD_BUS_TYPE_ARRAY, + SD_BUS_TYPE_VARIANT, + SD_BUS_TYPE_STRUCT, + SD_BUS_TYPE_DICT_ENTRY + }; + + return !!memchr(valid, c, sizeof(valid)); +} + +int bus_type_get_alignment(char c) { + + switch (c) { + case SD_BUS_TYPE_BYTE: + case SD_BUS_TYPE_SIGNATURE: + case SD_BUS_TYPE_VARIANT: + return 1; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + return 2; + + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: + case SD_BUS_TYPE_ARRAY: + case SD_BUS_TYPE_UNIX_FD: + return 4; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + case SD_BUS_TYPE_STRUCT: + case SD_BUS_TYPE_STRUCT_BEGIN: + case SD_BUS_TYPE_DICT_ENTRY: + case SD_BUS_TYPE_DICT_ENTRY_BEGIN: + return 8; + } + + return -EINVAL; +} + +int bus_type_get_size(char c) { + + switch (c) { + case SD_BUS_TYPE_BYTE: + return 1; + + case SD_BUS_TYPE_INT16: + case SD_BUS_TYPE_UINT16: + return 2; + + case SD_BUS_TYPE_BOOLEAN: + case SD_BUS_TYPE_INT32: + case SD_BUS_TYPE_UINT32: + case SD_BUS_TYPE_UNIX_FD: + return 4; + + case SD_BUS_TYPE_INT64: + case SD_BUS_TYPE_UINT64: + case SD_BUS_TYPE_DOUBLE: + return 8; + } + + return -EINVAL; +} diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h new file mode 100644 index 0000000..2e423bb --- /dev/null +++ b/src/libsystemd/sd-bus/bus-type.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" +#include "sd-bus-protocol.h" + +bool bus_type_is_valid(char c) _const_; +bool bus_type_is_valid_in_signature(char c) _const_; +bool bus_type_is_basic(char c) _const_; +bool bus_type_is_trivial(char c) _const_; +bool bus_type_is_container(char c) _const_; + +int bus_type_get_alignment(char c) _const_; +int bus_type_get_size(char c) _const_; diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c new file mode 100644 index 0000000..2935f69 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-util.c @@ -0,0 +1,1232 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "strv.h" +#include "macro.h" +#include "def.h" +#include "missing.h" + +#include "sd-event.h" +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-message.h" +#include "bus-util.h" +#include "bus-internal.h" + +static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + sd_event *e = userdata; + + assert(bus); + assert(m); + assert(e); + + sd_event_exit(e, 0); + return 1; +} + +int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) { + _cleanup_free_ char *match = NULL; + const char *unique; + int r; + + assert(e); + assert(bus); + assert(name); + + /* We unregister the name here and then wait for the + * NameOwnerChanged signal for this event to arrive before we + * quit. We do this in order to make sure that any queued + * requests are still processed before we really exit. */ + + r = sd_bus_get_unique_name(bus, &unique); + if (r < 0) + return r; + + r = asprintf(&match, + "sender='org.freedesktop.DBus'," + "type='signal'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "path='/org/freedesktop/DBus'," + "arg0='%s'," + "arg1='%s'," + "arg2=''", name, unique); + if (r < 0) + return -ENOMEM; + + r = sd_bus_add_match(bus, match, name_owner_change_callback, e); + if (r < 0) + return r; + + r = sd_bus_release_name(bus, name); + if (r < 0) + return r; + + return 0; +} + +int bus_event_loop_with_idle( + sd_event *e, + sd_bus *bus, + const char *name, + usec_t timeout, + check_idle_t check_idle, + void *userdata) { + bool exiting = false; + int r, code; + + assert(e); + assert(bus); + assert(name); + + for (;;) { + bool idle; + + r = sd_event_get_state(e); + if (r < 0) + return r; + if (r == SD_EVENT_FINISHED) + break; + + if (check_idle) + idle = check_idle(userdata); + else + idle = true; + + r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout); + if (r < 0) + return r; + + if (r == 0 && !exiting) { + r = bus_async_unregister_and_exit(e, bus, name); + if (r < 0) + return r; + + exiting = true; + } + } + + r = sd_event_get_exit_code(e, &code); + if (r < 0) + return r; + + return code; +} + +int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *rep = NULL; + int r, has_owner = 0; + + assert(c); + assert(name); + + r = sd_bus_call_method(c, + "org.freedesktop.DBus", + "/org/freedesktop/dbus", + "org.freedesktop.DBus", + "NameHasOwner", + error, + &rep, + "s", + name); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(rep, 'b', &has_owner); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + return has_owner; +} + +int bus_verify_polkit( + sd_bus *bus, + sd_bus_message *m, + const char *action, + bool interactive, + bool *_challenge, + sd_bus_error *e) { + + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + uid_t uid; + int r; + + assert(bus); + assert(m); + assert(action); + + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + if (uid == 0) + return 1; + +#ifdef ENABLE_POLKIT + else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int authorized = false, challenge = false; + const char *sender; + + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; + + r = sd_bus_call_method( + bus, + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + "CheckAuthorization", + e, + &reply, + "(sa{sv})sa{ss}us", + "system-bus-name", 1, "name", "s", sender, + action, + 0, + interactive ? 1 : 0, + ""); + + if (r < 0) { + /* Treat no PK available as access denied */ + if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { + sd_bus_error_free(e); + return -EACCES; + } + + return r; + } + + r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "bb", &authorized, &challenge); + if (r < 0) + return r; + + if (authorized) + return 1; + + if (_challenge) { + *_challenge = challenge; + return 0; + } + } +#endif + + return -EACCES; +} + +#ifdef ENABLE_POLKIT + +typedef struct AsyncPolkitQuery { + sd_bus_message *request, *reply; + sd_bus_message_handler_t callback; + void *userdata; + uint64_t serial; + Hashmap *registry; +} AsyncPolkitQuery; + +static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) { + + if (!q) + return; + + if (q->serial > 0 && b) + sd_bus_call_async_cancel(b, q->serial); + + if (q->registry && q->request) + hashmap_remove(q->registry, q->request); + + sd_bus_message_unref(q->request); + sd_bus_message_unref(q->reply); + + free(q); +} + +static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + AsyncPolkitQuery *q = userdata; + int r; + + assert(bus); + assert(reply); + assert(q); + + q->reply = sd_bus_message_ref(reply); + q->serial = 0; + + r = sd_bus_message_rewind(q->request, true); + if (r < 0) { + r = sd_bus_reply_method_errno(q->request, r, NULL); + goto finish; + } + + r = q->callback(bus, q->request, q->userdata, &error_buffer); + r = bus_maybe_reply_error(q->request, r, &error_buffer); + +finish: + async_polkit_query_free(bus, q); + return r; +} + +#endif + +int bus_verify_polkit_async( + sd_bus *bus, + Hashmap **registry, + sd_bus_message *m, + const char *action, + bool interactive, + sd_bus_error *error, + sd_bus_message_handler_t callback, + void *userdata) { + +#ifdef ENABLE_POLKIT + _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; + AsyncPolkitQuery *q; + const char *sender; +#endif + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + uid_t uid; + int r; + + assert(bus); + assert(registry); + assert(m); + assert(action); + +#ifdef ENABLE_POLKIT + q = hashmap_get(*registry, m); + if (q) { + int authorized, challenge; + + /* This is the second invocation of this function, and + * there's already a response from polkit, let's + * process it */ + assert(q->reply); + + 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; + + return -sd_bus_error_get_errno(e); + } + + r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); + if (r >= 0) + r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); + + if (r < 0) + return r; + + if (authorized) + return 1; + + return -EACCES; + } +#endif + + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + if (uid == 0) + return 1; + +#ifdef ENABLE_POLKIT + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; + + r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + r = sd_bus_message_new_method_call( + bus, + &pk, + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + "CheckAuthorization"); + if (r < 0) + return r; + + r = sd_bus_message_append( + pk, + "(sa{sv})sa{ss}us", + "system-bus-name", 1, "name", "s", sender, + action, + 0, + interactive ? 1 : 0, + NULL); + if (r < 0) + return r; + + q = new0(AsyncPolkitQuery, 1); + if (!q) + return -ENOMEM; + + q->request = sd_bus_message_ref(m); + q->callback = callback; + q->userdata = userdata; + + r = hashmap_put(*registry, m, q); + if (r < 0) { + async_polkit_query_free(bus, q); + return r; + } + + q->registry = *registry; + + r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial); + if (r < 0) { + async_polkit_query_free(bus, q); + return r; + } + + return 0; +#endif + + return -EACCES; +} + +void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) { +#ifdef ENABLE_POLKIT + AsyncPolkitQuery *q; + + while ((q = hashmap_steal_first(registry))) + async_polkit_query_free(bus, q); + + hashmap_free(registry); +#endif +} + +int bus_check_peercred(sd_bus *c) { + struct ucred ucred; + socklen_t l; + int fd; + + assert(c); + + fd = sd_bus_get_fd(c); + if (fd < 0) + return fd; + + l = sizeof(struct ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) + return -errno; + + if (l != sizeof(struct ucred)) + return -E2BIG; + + if (ucred.uid != 0 && ucred.uid != geteuid()) + return -EPERM; + + return 1; +} + +int bus_open_system_systemd(sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + assert(_bus); + + if (geteuid() != 0) + return sd_bus_open_system(_bus); + + /* If we are root and kdbus is not available, then let's talk + * directly to the system instance, instead of going via the + * bus */ + +#ifdef ENABLE_KDBUS + r = sd_bus_new(&bus); + if (r < 0) + return r; + + r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH); + if (r < 0) + return r; + + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + + r = sd_bus_new(&bus); + if (r < 0) + return r; + + r = sd_bus_set_address(bus, "unix:path=/run/systemd/private"); + if (r < 0) + return r; + + r = sd_bus_start(bus); + if (r < 0) + return sd_bus_open_system(_bus); + + r = bus_check_peercred(bus); + if (r < 0) + return r; + + *_bus = bus; + bus = NULL; + + return 0; +} + +int bus_open_user_systemd(sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_free_ char *ee = NULL; + const char *e; + int r; + + /* Try via kdbus first, and then directly */ + + assert(_bus); + +#ifdef ENABLE_KDBUS + r = sd_bus_new(&bus); + if (r < 0) + return r; + + if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()) < 0) + return -ENOMEM; + + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r >= 0) { + *_bus = bus; + bus = NULL; + return 0; + } + + bus = sd_bus_unref(bus); +#endif + + e = secure_getenv("XDG_RUNTIME_DIR"); + if (!e) + return sd_bus_open_user(_bus); + + ee = bus_address_escape(e); + if (!ee) + return -ENOMEM; + + r = sd_bus_new(&bus); + if (r < 0) + return r; + + bus->address = strjoin("unix:path=", ee, "/systemd/private", NULL); + if (!bus->address) + return -ENOMEM; + + r = sd_bus_start(bus); + if (r < 0) + return sd_bus_open_user(_bus); + + r = bus_check_peercred(bus); + if (r < 0) + return r; + + *_bus = bus; + bus = NULL; + + return 0; +} + +int bus_print_property(const char *name, sd_bus_message *property, bool all) { + char type; + const char *contents; + int r; + + assert(name); + assert(property); + + r = sd_bus_message_peek_type(property, &type, &contents); + if (r < 0) + return r; + + switch (type) { + + case SD_BUS_TYPE_STRING: { + const char *s; + + r = sd_bus_message_read_basic(property, type, &s); + if (r < 0) + return r; + + if (all || !isempty(s)) + printf("%s=%s\n", name, s); + + return 1; + } + + case SD_BUS_TYPE_BOOLEAN: { + bool b; + + r = sd_bus_message_read_basic(property, type, &b); + if (r < 0) + return r; + + printf("%s=%s\n", name, yes_no(b)); + + return 1; + } + + case SD_BUS_TYPE_UINT64: { + uint64_t u; + + r = sd_bus_message_read_basic(property, type, &u); + if (r < 0) + return r; + + /* Yes, heuristics! But we can change this check + * should it turn out to not be sufficient */ + + if (endswith(name, "Timestamp")) { + char timestamp[FORMAT_TIMESTAMP_MAX], *t; + + t = format_timestamp(timestamp, sizeof(timestamp), u); + if (t || all) + printf("%s=%s\n", name, strempty(t)); + + } else if (strstr(name, "USec")) { + char timespan[FORMAT_TIMESPAN_MAX]; + + printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0)); + } else + printf("%s=%llu\n", name, (unsigned long long) u); + + return 1; + } + + case SD_BUS_TYPE_UINT32: { + uint32_t u; + + r = sd_bus_message_read_basic(property, type, &u); + if (r < 0) + return r; + + if (strstr(name, "UMask") || strstr(name, "Mode")) + printf("%s=%04o\n", name, u); + else + printf("%s=%u\n", name, (unsigned) u); + + return 1; + } + + case SD_BUS_TYPE_INT32: { + int32_t i; + + r = sd_bus_message_read_basic(property, type, &i); + if (r < 0) + return r; + + printf("%s=%i\n", name, (int) i); + return 1; + } + + case SD_BUS_TYPE_DOUBLE: { + double d; + + r = sd_bus_message_read_basic(property, type, &d); + if (r < 0) + return r; + + printf("%s=%g\n", name, d); + return 1; + } + + case SD_BUS_TYPE_ARRAY: + if (streq(contents, "s")) { + bool first = true; + const char *str; + + r = sd_bus_message_enter_container(property, SD_BUS_TYPE_ARRAY, contents); + if (r < 0) + return r; + + while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { + if (first) + printf("%s=", name); + + printf("%s%s", first ? "" : " ", str); + + first = false; + } + if (r < 0) + return r; + + if (first && all) + printf("%s=", name); + if (!first || all) + puts(""); + + r = sd_bus_message_exit_container(property); + if (r < 0) + return r; + + return 1; + + } else if (streq(contents, "y")) { + const uint8_t *u; + size_t n; + + r = sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, (const void**) &u, &n); + if (r < 0) + return r; + + if (all || n > 0) { + unsigned int i; + + printf("%s=", name); + + for (i = 0; i < n; i++) + printf("%02x", u[i]); + + puts(""); + } + + return 1; + + } else if (streq(contents, "u")) { + uint32_t *u; + size_t n; + + r = sd_bus_message_read_array(property, SD_BUS_TYPE_UINT32, (const void**) &u, &n); + if (r < 0) + return r; + + if (all || n > 0) { + unsigned int i; + + printf("%s=", name); + + for (i = 0; i < n; i++) + printf("%08x", u[i]); + + puts(""); + } + + return 1; + } + + break; + } + + return 0; +} + +int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(path); + + r = sd_bus_call_method(bus, + dest, + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", ""); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *name; + const char *contents; + + r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name); + if (r < 0) + return r; + + if (!filter || strv_find(filter, name)) { + r = sd_bus_message_peek_type(reply, NULL, &contents); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + return r; + + r = bus_print_property(name, reply, all); + if (r < 0) + return r; + if (r == 0) { + if (all) + printf("%s=[unprintable]\n", name); + /* skip what we didn't read */ + r = sd_bus_message_skip(reply, contents); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + } else { + r = sd_bus_message_skip(reply, "v"); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + return 0; +} + +int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + sd_id128_t *p = userdata; + const void *v; + size_t n; + int r; + + r = sd_bus_message_read_array(m, SD_BUS_TYPE_BYTE, &v, &n); + if (r < 0) + return r; + + if (n == 0) + *p = SD_ID128_NULL; + else if (n == 16) + memcpy((*p).bytes, v, n); + else + return -EINVAL; + + return 0; +} + +static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char type; + int r; + + r = sd_bus_message_peek_type(m, &type, NULL); + if (r < 0) + return r; + + switch (type) { + case SD_BUS_TYPE_STRING: { + const char *s; + char *str; + char **p = userdata; + + r = sd_bus_message_read_basic(m, type, &s); + if (r < 0) + break; + + if (isempty(s)) + break; + + str = strdup(s); + if (!str) { + r = -ENOMEM; + break; + } + free(*p); + *p = str; + + break; + } + + case SD_BUS_TYPE_ARRAY: { + _cleanup_strv_free_ char **l = NULL; + char ***p = userdata; + + r = bus_message_read_strv_extend(m, &l); + if (r < 0) + break; + + strv_free(*p); + *p = l; + l = NULL; + + break; + } + + case SD_BUS_TYPE_BOOLEAN: { + unsigned b; + bool *p = userdata; + + r = sd_bus_message_read_basic(m, type, &b); + if (r < 0) + break; + + *p = b; + + break; + } + + case SD_BUS_TYPE_UINT32: { + uint64_t u; + uint32_t *p = userdata; + + r = sd_bus_message_read_basic(m, type, &u); + if (r < 0) + break; + + *p = u; + + break; + } + + case SD_BUS_TYPE_UINT64: { + uint64_t t; + uint64_t *p = userdata; + + r = sd_bus_message_read_basic(m, type, &t); + if (r < 0) + break; + + *p = t; + + break; + } + + default: + break; + } + + return r; +} + +int bus_map_all_properties(sd_bus *bus, + const char *destination, + const char *path, + const struct bus_properties_map *map, + void *userdata) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(destination); + assert(path); + assert(map); + + r = sd_bus_call_method( + bus, + destination, + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &m, + "s", ""); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const struct bus_properties_map *prop; + const char *member; + const char *contents; + void *v; + unsigned i; + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member); + if (r < 0) + return r; + + for (i = 0, prop = NULL; map[i].member; i++) + if (streq(map[i].member, member)) { + prop = &map[i]; + break; + } + + if (prop) { + r = sd_bus_message_peek_type(m, NULL, &contents); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + return r; + + v = (uint8_t *)userdata + prop->offset; + if (map[i].set) + r = prop->set(bus, member, m, &error, v); + else + r = map_basic(bus, member, m, &error, v); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } else { + r = sd_bus_message_skip(m, "v"); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + } + + return r; +} + +int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) { + int r; + + assert(transport >= 0); + assert(transport < _BUS_TRANSPORT_MAX); + assert(bus); + + assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL); + assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP); + + switch (transport) { + + case BUS_TRANSPORT_LOCAL: + if (user) + r = sd_bus_default_user(bus); + else + r = sd_bus_default_system(bus); + + break; + + case BUS_TRANSPORT_REMOTE: + r = sd_bus_open_system_remote(bus, host); + break; + + case BUS_TRANSPORT_CONTAINER: + r = sd_bus_open_system_container(bus, host); + break; + + default: + assert_not_reached("Hmm, unknown transport type."); + } + + return r; +} + +int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) { + int r; + + assert(transport >= 0); + assert(transport < _BUS_TRANSPORT_MAX); + assert(bus); + + assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL); + assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP); + + switch (transport) { + + case BUS_TRANSPORT_LOCAL: + if (user) + r = bus_open_user_systemd(bus); + else + r = bus_open_system_systemd(bus); + + break; + + case BUS_TRANSPORT_REMOTE: + r = sd_bus_open_system_remote(bus, host); + break; + + case BUS_TRANSPORT_CONTAINER: + r = sd_bus_open_system_container(bus, host); + break; + + default: + assert_not_reached("Hmm, unknown transport type."); + } + + return r; +} + +int bus_property_get_tristate( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + int *tristate = userdata; + + return sd_bus_message_append(reply, "b", *tristate > 0); +} + +int bus_property_get_bool( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + int b = *(bool*) userdata; + + return sd_bus_message_append_basic(reply, 'b', &b); +} + +#if __SIZEOF_SIZE_T__ != 8 +int bus_property_get_size( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + uint64_t sz = *(size_t*) userdata; + + return sd_bus_message_append_basic(reply, 't', &sz); +} +#endif + +#if __SIZEOF_LONG__ != 8 +int bus_property_get_long( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + int64_t l = *(long*) userdata; + + return sd_bus_message_append_basic(reply, 'x', &l); +} + +int bus_property_get_ulong( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + uint64_t ul = *(unsigned long*) userdata; + + return sd_bus_message_append_basic(reply, 't', &ul); +} +#endif + +int bus_log_parse_error(int r) { + log_error("Failed to parse message: %s", strerror(-r)); + return r; +} + +int bus_log_create_error(int r) { + log_error("Failed to create message: %s", strerror(-r)); + return r; +} + +int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { + assert(message); + assert(u); + + return sd_bus_message_read( + message, + "(ssssssouso)", + &u->id, + &u->description, + &u->load_state, + &u->active_state, + &u->sub_state, + &u->following, + &u->unit_path, + &u->job_id, + &u->job_type, + &u->job_path); +} + +int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) { + assert(m); + + if (r < 0) { + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) + sd_bus_reply_method_errno(m, r, error); + + } else if (sd_bus_error_is_set(error)) { + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) + sd_bus_reply_method_error(m, error); + } else + return r; + + log_debug("Failed to process message [type=%s sender=%s path=%s interface=%s member=%s signature=%s]: %s", + bus_message_type_to_string(m->header->type), + strna(m->sender), + strna(m->path), + strna(m->interface), + strna(m->member), + strna(m->root_container.signature), + bus_error_message(error, r)); + + return 1; +} diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h new file mode 100644 index 0000000..51e1613 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-util.h @@ -0,0 +1,180 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-event.h" +#include "sd-bus.h" +#include "hashmap.h" +#include "time-util.h" +#include "util.h" + +typedef enum BusTransport { + BUS_TRANSPORT_LOCAL, + BUS_TRANSPORT_REMOTE, + BUS_TRANSPORT_CONTAINER, + _BUS_TRANSPORT_MAX, + _BUS_TRANSPORT_INVALID = -1 +} BusTransport; + +typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata); + +struct bus_properties_map { + const char *member; + const char *signature; + bus_property_set_t set; + size_t offset; +}; + +int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata); + +int bus_map_all_properties(sd_bus *bus, + const char *destination, + const char *path, + const struct bus_properties_map *map, + void *userdata); + +int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name); + +typedef bool (*check_idle_t)(void *userdata); + +int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout, check_idle_t check_idle, void *userdata); + +int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error); + +int bus_check_peercred(sd_bus *c); + +int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e); + +int bus_verify_polkit_async(sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata); +void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry); + +int bus_open_system_systemd(sd_bus **_bus); +int bus_open_user_systemd(sd_bus **_bus); + +int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus); +int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus); + +int bus_print_property(const char *name, sd_bus_message *property, bool all); +int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all); + +int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); + +#define bus_property_get_usec ((sd_bus_property_get_t) NULL) +#define bus_property_set_usec ((sd_bus_property_set_t) NULL) + +assert_cc(sizeof(int) == sizeof(int32_t)); +#define bus_property_get_int ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(unsigned) == sizeof(unsigned)); +#define bus_property_get_unsigned ((sd_bus_property_get_t) NULL) + +/* On 64bit machines we can use the default serializer for size_t and + * friends, otherwise we need to cast this manually */ +#if __SIZEOF_SIZE_T__ == 8 +#define bus_property_get_size ((sd_bus_property_get_t) NULL) +#else +int bus_property_get_size(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +#endif + +#if __SIZEOF_LONG__ == 8 +#define bus_property_get_long ((sd_bus_property_get_t) NULL) +#define bus_property_get_ulong ((sd_bus_property_get_t) NULL) +#else +int bus_property_get_long(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +int bus_property_get_ulong(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); +#endif + +/* uid_t and friends on Linux 32 bit. This means we can just use the + * default serializer for 32bit unsigned, for serializing it, and map + * it to NULL here */ +assert_cc(sizeof(uid_t) == sizeof(uint32_t)); +#define bus_property_get_uid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(gid_t) == sizeof(uint32_t)); +#define bus_property_get_gid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(pid_t) == sizeof(uint32_t)); +#define bus_property_get_pid ((sd_bus_property_get_t) NULL) + +assert_cc(sizeof(mode_t) == sizeof(uint32_t)); +#define bus_property_get_mode ((sd_bus_property_get_t) NULL) + +int bus_log_parse_error(int r); +int bus_log_create_error(int r); + +typedef struct UnitInfo { + const char *id; + const char *description; + const char *load_state; + const char *active_state; + const char *sub_state; + const char *following; + const char *unit_path; + uint32_t job_id; + const char *job_type; + const char *job_path; +} UnitInfo; + +int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); + +#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) +#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) +#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) +#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free) + +#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \ + int function(sd_bus *bus, \ + const char *path, \ + const char *interface, \ + const char *property, \ + sd_bus_message *reply, \ + void *userdata, \ + sd_bus_error *error) { \ + \ + const char *value; \ + type *field = userdata; \ + int r; \ + \ + assert(bus); \ + assert(reply); \ + assert(field); \ + \ + value = strempty(name##_to_string(*field)); \ + \ + r = sd_bus_message_append_basic(reply, 's', value); \ + if (r < 0) \ + return r; \ + \ + return 1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \ + SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \ + SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags)) + +int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c new file mode 100644 index 0000000..e326cc0 --- /dev/null +++ b/src/libsystemd/sd-bus/busctl.c @@ -0,0 +1,533 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "strv.h" +#include "util.h" +#include "log.h" +#include "build.h" +#include "pager.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "bus-dump.h" + +static bool arg_no_pager = false; +static bool arg_legend = true; +static char *arg_address = NULL; +static bool arg_unique = false; +static bool arg_acquired = false; +static bool arg_activatable = false; +static bool arg_show_machine = false; +static char **arg_matches = NULL; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_user = false; + +static void pager_open_if_enabled(void) { + + /* Cache result before we open the pager */ + if (arg_no_pager) + return; + + pager_open(false); +} + +static int list_bus_names(sd_bus *bus, char **argv) { + _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL; + _cleanup_free_ char **merged = NULL; + _cleanup_hashmap_free_ Hashmap *names = NULL; + char **i; + int r; + size_t max_i = 0; + unsigned n = 0; + void *v; + char *k; + Iterator iterator; + + assert(bus); + + r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL); + if (r < 0) { + log_error("Failed to list names: %s", strerror(-r)); + return r; + } + + pager_open_if_enabled(); + + names = hashmap_new(string_hash_func, string_compare_func); + if (!names) + return log_oom(); + + STRV_FOREACH(i, acquired) { + max_i = MAX(max_i, strlen(*i)); + + r = hashmap_put(names, *i, INT_TO_PTR(1)); + if (r < 0) { + log_error("Failed to add to hashmap: %s", strerror(-r)); + return r; + } + } + + STRV_FOREACH(i, activatable) { + max_i = MAX(max_i, strlen(*i)); + + r = hashmap_put(names, *i, INT_TO_PTR(2)); + if (r < 0 && r != -EEXIST) { + log_error("Failed to add to hashmap: %s", strerror(-r)); + return r; + } + } + + merged = new(char*, hashmap_size(names) + 1); + HASHMAP_FOREACH_KEY(v, k, names, iterator) + merged[n++] = k; + + merged[n] = NULL; + strv_sort(merged); + + if (arg_legend) { + printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s", + (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "CONNECTION-NAME"); + + if (arg_show_machine) + puts(" MACHINE"); + else + putchar('\n'); + } + + STRV_FOREACH(i, merged) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_id128_t mid; + + if (hashmap_get(names, *i) == INT_TO_PTR(2)) { + /* Activatable */ + + printf("%-*s", (int) max_i, *i); + printf(" - - - (activatable) - - "); + if (arg_show_machine) + puts(" -"); + else + putchar('\n'); + continue; + + } + + if (!arg_unique && (*i)[0] == ':') + continue; + + if (!arg_acquired && (*i)[0] != ':') + continue; + + printf("%-*s", (int) max_i, *i); + + r = sd_bus_get_owner(bus, *i, + SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM| + SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION| + SD_BUS_CREDS_CONNECTION_NAME, &creds); + if (r >= 0) { + const char *unique, *session, *unit, *cn; + pid_t pid; + uid_t uid; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r >= 0) { + const char *comm = NULL; + + sd_bus_creds_get_comm(creds, &comm); + + printf(" %10lu %-15s", (unsigned long) pid, strna(comm)); + } else + fputs(" - - ", stdout); + + r = sd_bus_creds_get_uid(creds, &uid); + if (r >= 0) { + _cleanup_free_ char *u = NULL; + + u = uid_to_name(uid); + if (!u) + return log_oom(); + + if (strlen(u) > 16) + u[16] = 0; + + printf(" %-16s", u); + } else + fputs(" - ", stdout); + + r = sd_bus_creds_get_unique_name(creds, &unique); + if (r >= 0) + printf(" %-13s", unique); + else + fputs(" - ", stdout); + + r = sd_bus_creds_get_unit(creds, &unit); + if (r >= 0) { + _cleanup_free_ char *e; + + e = ellipsize(unit, 25, 100); + if (!e) + return log_oom(); + + printf(" %-25s", e); + } else + fputs(" - ", stdout); + + r = sd_bus_creds_get_session(creds, &session); + if (r >= 0) + printf(" %-10s", session); + else + fputs(" - ", stdout); + + r = sd_bus_creds_get_connection_name(creds, &cn); + if (r >= 0) + printf(" %-19s", cn); + else + fputs(" - ", stdout); + + } else + printf(" - - - - - - - "); + + if (arg_show_machine) { + r = sd_bus_get_owner_machine_id(bus, *i, &mid); + if (r >= 0) { + char m[SD_ID128_STRING_MAX]; + printf(" %s\n", sd_id128_to_string(mid, m)); + } else + puts(" -"); + } else + putchar('\n'); + } + + return 0; +} + +static int monitor(sd_bus *bus, char *argv[]) { + bool added_something = false; + char **i; + int r; + + 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; + } + + m = strjoin("sender='", *i, "'", NULL); + if (!m) + return log_oom(); + + r = sd_bus_add_match(bus, m, NULL, NULL); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + + added_something = true; + } + + STRV_FOREACH(i, arg_matches) { + r = sd_bus_add_match(bus, *i, NULL, NULL); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + + added_something = true; + } + + if (!added_something) { + r = sd_bus_add_match(bus, "", NULL, NULL); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + } + + for (;;) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + r = sd_bus_process(bus, &m); + if (r < 0) { + log_error("Failed to process bus: %s", strerror(-r)); + return r; + } + + if (m) { + bus_message_dump(m, stdout, true); + continue; + } + + if (r > 0) + continue; + + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) { + log_error("Failed to wait for bus: %s", strerror(-r)); + return r; + } + } +} + +static int status(sd_bus *bus, char *argv[]) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + pid_t pid; + int r; + + assert(bus); + + if (strv_length(argv) != 2) { + log_error("Expects one argument."); + return -EINVAL; + } + + r = parse_pid(argv[1], &pid); + if (r < 0) + r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds); + else + r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL); + + if (r < 0) { + log_error("Failed to get credentials: %s", strerror(-r)); + return r; + } + + bus_creds_dump(creds, NULL); + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Introspect the bus.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" + " --system Connect to system bus\n" + " --user Connect to user bus\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --address=ADDRESS Connect to bus specified by address\n" + " --show-machine Show machine ID column in list\n" + " --unique Only show unique names\n" + " --acquired Only show acquired names\n" + " --activatable Only show activatable names\n" + " --match=MATCH Only show matching messages\n\n" + "Commands:\n" + " list List bus names\n" + " monitor [SERVICE...] Show bus traffic\n" + " status NAME Show name status\n" + " help Show this help\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, + ARG_SYSTEM, + ARG_USER, + ARG_ADDRESS, + ARG_MATCH, + ARG_SHOW_MACHINE, + ARG_UNIQUE, + ARG_ACQUIRED, + ARG_ACTIVATABLE + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "user", no_argument, NULL, ARG_USER }, + { "address", required_argument, NULL, ARG_ADDRESS }, + { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE }, + { "unique", no_argument, NULL, ARG_UNIQUE }, + { "acquired", no_argument, NULL, ARG_ACQUIRED }, + { "activatable", no_argument, NULL, ARG_ACTIVATABLE }, + { "match", required_argument, NULL, ARG_MATCH }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + {}, + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + + case ARG_USER: + arg_user = true; + break; + + case ARG_SYSTEM: + arg_user = false; + break; + + case ARG_ADDRESS: + arg_address = optarg; + break; + + case ARG_SHOW_MACHINE: + arg_show_machine = true; + break; + + case ARG_UNIQUE: + arg_unique = true; + break; + + case ARG_ACQUIRED: + arg_acquired = true; + break; + + case ARG_ACTIVATABLE: + arg_activatable = true; + break; + + case ARG_MATCH: + if (strv_extend(&arg_matches, optarg) < 0) + return log_oom(); + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (!arg_unique && !arg_acquired && !arg_activatable) + arg_unique = arg_acquired = arg_activatable = true; + + return 1; +} + +static int busctl_main(sd_bus *bus, int argc, char *argv[]) { + assert(bus); + + if (optind >= argc || + streq(argv[optind], "list")) + return list_bus_names(bus, argv + optind); + + if (streq(argv[optind], "monitor")) + return monitor(bus, argv + optind); + + if (streq(argv[optind], "status")) + return status(bus, argv + optind); + + if (streq(argv[optind], "help")) + return help(); + + log_error("Unknown command '%s'", argv[optind]); + return -EINVAL; +} + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + if (arg_address) { + r = sd_bus_new(&bus); + if (r < 0) { + log_error("Failed to allocate bus: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_address(bus, arg_address); + if (r < 0) { + log_error("Failed to set address: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_set_bus_client(bus, true); + if (r < 0) { + log_error("Failed to set bus client: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_start(bus); + } else + r = bus_open_transport(arg_transport, arg_host, arg_user, &bus); + + if (r < 0) { + log_error("Failed to connect to bus: %s", strerror(-r)); + goto finish; + } + + r = busctl_main(bus, argc, argv); + +finish: + pager_close(); + + strv_free(arg_matches); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h new file mode 100644 index 0000000..c9a8940 --- /dev/null +++ b/src/libsystemd/sd-bus/kdbus.h @@ -0,0 +1,961 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * Copyright (C) 2013 Lennart Poettering + * Copyright (C) 2013 Daniel Mack + * + * kdbus 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. + * + * "Everything should be made as simple as possible, but not simpler." + * -- Albert Einstein + */ + +#ifndef _KDBUS_H_ +#define _KDBUS_H_ + +#ifndef __KERNEL__ +#include +#include +#include +#endif + +#define KDBUS_IOC_MAGIC 0x95 +#define KDBUS_SRC_ID_KERNEL (0) +#define KDBUS_DST_ID_NAME (0) +#define KDBUS_MATCH_ID_ANY (~0ULL) +#define KDBUS_DST_ID_BROADCAST (~0ULL) + +/** + * struct kdbus_notify_id_change - name registry change message + * @id: New or former owner of the name + * @flags: flags field from KDBUS_HELLO_* + * + * Sent from kernel to userspace when the owner or activator of + * a well-known name changes. + * + * Attached to: + * KDBUS_ITEM_ID_ADD + * KDBUS_ITEM_ID_REMOVE + */ +struct kdbus_notify_id_change { + __u64 id; + __u64 flags; +}; + +/** + * struct kdbus_notify_name_change - name registry change message + * @old: ID and flags of former owner of a name + * @new: ID and flags of new owner of a name + * @name: Well-known name + * + * Sent from kernel to userspace when the owner or activator of + * a well-known name changes. + * + * Attached to: + * KDBUS_ITEM_NAME_ADD + * KDBUS_ITEM_NAME_REMOVE + * KDBUS_ITEM_NAME_CHANGE + */ +struct kdbus_notify_name_change { + struct kdbus_notify_id_change old; + struct kdbus_notify_id_change new; + char name[0]; +}; + +/** + * struct kdbus_creds - process credentials + * @uid: User ID + * @gid: Group ID + * @pid: Process ID + * @tid: Thread ID + * @starttime: Starttime of the process + * + * The starttime of the process PID. This is useful to detect PID overruns + * from the client side. i.e. if you use the PID to look something up in + * /proc/$PID/ you can afterwards check the starttime field of it, to ensure + * you didn't run into a PID overrun. + * + * Attached to: + * KDBUS_ITEM_CREDS + */ +struct kdbus_creds { + __u64 uid; + __u64 gid; + __u64 pid; + __u64 tid; + __u64 starttime; +}; + +/** + * struct kdbus_audit - audit information + * @sessionid: The audit session ID + * @loginuid: The audit login uid + * + * Attached to: + * KDBUS_ITEM_AUDIT + */ +struct kdbus_audit { + __u64 sessionid; + __u64 loginuid; +}; + +/** + * struct kdbus_timestamp + * @seqnum: Global per-domain message sequence number + * @monotonic_ns: Monotonic timestamp, in nanoseconds + * @realtime_ns: Realtime timestamp, in nanoseconds + * + * Attached to: + * KDBUS_ITEM_TIMESTAMP + */ +struct kdbus_timestamp { + __u64 seqnum; + __u64 monotonic_ns; + __u64 realtime_ns; +}; + +/** + * struct kdbus_vec - I/O vector for kdbus payload items + * @size: The size of the vector + * @address: Memory address for memory addresses + * @offset: Offset in the in-message payload memory, + * relative to the message head + * + * Attached to: + * KDBUS_ITEM_PAYLOAD_VEC + */ +struct kdbus_vec { + __u64 size; + union { + __u64 address; + __u64 offset; + }; +}; + +/** + * struct kdbus_bloom_parameter - bus-wide bloom parameters + * @size: Size of the bit field in bytes (m / 8) + * @n_hash: Number of hash functions used (k) + */ +struct kdbus_bloom_parameter { + __u64 size; + __u64 n_hash; +}; + +/** + * struct kdbus_bloom_filter - bloom filter containing n elements + * @generation: Generation of the element set in the filter + * @data: Bit field, multiple of 8 bytes + */ +struct kdbus_bloom_filter { + __u64 generation; + __u64 data[0]; +}; + +/** + * struct kdbus_memfd - a kdbus memfd + * @size: The memfd's size + * @fd: The file descriptor number + * @__pad: Padding to ensure proper alignement and size + * + * Attached to: + * KDBUS_ITEM_PAYLOAD_MEMFD + */ +struct kdbus_memfd { + __u64 size; + int fd; + __u32 __pad; +}; + +/** + * struct kdbus_name - a registered well-known name with its flags + * @flags: flags from KDBUS_NAME_* + * @name: well-known name + * + * Attached to: + * KDBUS_ITEM_NAME + */ +struct kdbus_name { + __u64 flags; + char name[0]; +}; + +/** + * struct kdbus_policy_access - policy access item + * @type: One of KDBUS_POLICY_ACCESS_* types + * @bits: Access to grant. One of KDBUS_POLICY_* + * @id: For KDBUS_POLICY_ACCESS_USER, the uid + * For KDBUS_POLICY_ACCESS_GROUP, the gid + * + * Embedded in: + * struct kdbus_policy + */ +struct kdbus_policy_access { + __u64 type; /* USER, GROUP, WORLD */ + __u64 bits; /* RECV, SEND, OWN */ + __u64 id; /* uid, gid, 0 */ +}; + +/** + * struct kdbus_policy - a policy item + * @access: Policy access details + * @name: Well-known name to grant access to + * + * Attached to: + * KDBUS_POLICY_ACCESS + * KDBUS_ITEM_POLICY_NAME + */ +struct kdbus_policy { + union { + struct kdbus_policy_access access; + char name[0]; + }; +}; + +/** + * enum kdbus_item_type - item types to chain data in a list + * @_KDBUS_ITEM_NULL: Uninitialized/invalid + * @_KDBUS_ITEM_USER_BASE: Start of user items + * @KDBUS_ITEM_PAYLOAD_VEC: Vector to data + * @KDBUS_ITEM_PAYLOAD_OFF: Data at returned offset to message head + * @KDBUS_ITEM_PAYLOAD_MEMFD: Data as sealed memfd + * @KDBUS_ITEM_FDS: Attached file descriptors + * @KDBUS_ITEM_BLOOM_PARAMETER: Bus-wide bloom parameters, used with + * KDBUS_CMD_BUS_MAKE, carries a + * struct kdbus_bloom_parameter + * @KDBUS_ITEM_BLOOM_FILTER: Bloom filter carried with a message, used to + * match against a bloom mask of a connection, + * carries a struct kdbus_bloom_filter + * @KDBUS_ITEM_BLOOM_MASK: Bloom mask used to match against a message's + * bloom filter + * @KDBUS_ITEM_DST_NAME: Destination's well-known name + * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint + * @KDBUS_ITEM_MEMFD_NAME: The human readable name of a memfd (debugging) + * @KDBUS_ITEM_ATTACH_FLAGS: Attach-flags, used for updating which metadata + * a connection subscribes to + * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items + * @KDBUS_ITEM_NAME: Well-know name with flags + * @KDBUS_ITEM_ID: Connection ID + * @KDBUS_ITEM_TIMESTAMP: Timestamp + * @KDBUS_ITEM_CREDS: Process credential + * @KDBUS_ITEM_PID_COMM: Process ID "comm" identifier + * @KDBUS_ITEM_TID_COMM: Thread ID "comm" identifier + * @KDBUS_ITEM_EXE: The path of the executable + * @KDBUS_ITEM_CMDLINE: The process command line + * @KDBUS_ITEM_CGROUP: The croup membership + * @KDBUS_ITEM_CAPS: The process capabilities + * @KDBUS_ITEM_SECLABEL: The security label + * @KDBUS_ITEM_AUDIT: The audit IDs + * @KDBUS_ITEM_CONN_NAME: The connection's human-readable name (debugging) + * @_KDBUS_ITEM_POLICY_BASE: Start of policy items + * @KDBUS_ITEM_POLICY_NAME: Policy in struct kdbus_policy + * @KDBUS_ITEM_POLICY_ACCESS: Policy in struct kdbus_policy + * @_KDBUS_ITEM_KERNEL_BASE: Start of kernel-generated message items + * @KDBUS_ITEM_NAME_ADD: Notify in struct kdbus_notify_name_change + * @KDBUS_ITEM_NAME_REMOVE: Notify in struct kdbus_notify_name_change + * @KDBUS_ITEM_NAME_CHANGE: Notify in struct kdbus_notify_name_change + * @KDBUS_ITEM_ID_ADD: Notify in struct kdbus_notify_id_change + * @KDBUS_ITEM_ID_REMOVE: Notify in struct kdbus_notify_id_change + * @KDBUS_ITEM_REPLY_TIMEOUT: Timeout has been reached + * @KDBUS_ITEM_REPLY_DEAD: Destination died + */ +enum kdbus_item_type { + _KDBUS_ITEM_NULL, + _KDBUS_ITEM_USER_BASE, + KDBUS_ITEM_PAYLOAD_VEC = _KDBUS_ITEM_USER_BASE, + KDBUS_ITEM_PAYLOAD_OFF, + KDBUS_ITEM_PAYLOAD_MEMFD, + KDBUS_ITEM_FDS, + KDBUS_ITEM_BLOOM_PARAMETER, + KDBUS_ITEM_BLOOM_FILTER, + KDBUS_ITEM_BLOOM_MASK, + KDBUS_ITEM_DST_NAME, + KDBUS_ITEM_MAKE_NAME, + KDBUS_ITEM_MEMFD_NAME, + KDBUS_ITEM_ATTACH_FLAGS, + + _KDBUS_ITEM_ATTACH_BASE = 0x1000, + KDBUS_ITEM_NAME = _KDBUS_ITEM_ATTACH_BASE, + KDBUS_ITEM_ID, + KDBUS_ITEM_TIMESTAMP, + KDBUS_ITEM_CREDS, + KDBUS_ITEM_PID_COMM, + KDBUS_ITEM_TID_COMM, + KDBUS_ITEM_EXE, + KDBUS_ITEM_CMDLINE, + KDBUS_ITEM_CGROUP, + KDBUS_ITEM_CAPS, + KDBUS_ITEM_SECLABEL, + KDBUS_ITEM_AUDIT, + KDBUS_ITEM_CONN_NAME, + + _KDBUS_ITEM_POLICY_BASE = 0x2000, + KDBUS_ITEM_POLICY_NAME = _KDBUS_ITEM_POLICY_BASE, + KDBUS_ITEM_POLICY_ACCESS, + + _KDBUS_ITEM_KERNEL_BASE = 0x8000, + KDBUS_ITEM_NAME_ADD = _KDBUS_ITEM_KERNEL_BASE, + KDBUS_ITEM_NAME_REMOVE, + KDBUS_ITEM_NAME_CHANGE, + KDBUS_ITEM_ID_ADD, + KDBUS_ITEM_ID_REMOVE, + KDBUS_ITEM_REPLY_TIMEOUT, + KDBUS_ITEM_REPLY_DEAD, +}; + +/** + * struct kdbus_item - chain of data blocks + * @size: Overall data record size + * @type: Kdbus_item type of data + * @data: Generic bytes + * @data32: Generic 32 bit array + * @data64: Generic 64 bit array + * @str: Generic string + * @id: Connection ID + * @vec: KDBUS_ITEM_PAYLOAD_VEC + * @creds: KDBUS_ITEM_CREDS + * @audit: KDBUS_ITEM_AUDIT + * @timestamp: KDBUS_ITEM_TIMESTAMP + * @name: KDBUS_ITEM_NAME + * @bloom_parameter: KDBUS_ITEM_BLOOM_PARAMETER + * @bloom_filter: KDBUS_ITEM_BLOOM_FILTER + * @memfd: KDBUS_ITEM_PAYLOAD_MEMFD + * @name_change: KDBUS_ITEM_NAME_ADD + * KDBUS_ITEM_NAME_REMOVE + * KDBUS_ITEM_NAME_CHANGE + * @id_change: KDBUS_ITEM_ID_ADD + * KDBUS_ITEM_ID_REMOVE + * @policy: KDBUS_ITEM_POLICY_NAME + * KDBUS_ITEM_POLICY_ACCESS + */ +struct kdbus_item { + __u64 size; + __u64 type; + union { + __u8 data[0]; + __u32 data32[0]; + __u64 data64[0]; + char str[0]; + + __u64 id; + struct kdbus_vec vec; + struct kdbus_creds creds; + struct kdbus_audit audit; + struct kdbus_timestamp timestamp; + struct kdbus_name name; + struct kdbus_bloom_parameter bloom_parameter; + struct kdbus_bloom_filter bloom_filter; + struct kdbus_memfd memfd; + int fds[0]; + struct kdbus_notify_name_change name_change; + struct kdbus_notify_id_change id_change; + struct kdbus_policy policy; + }; +}; + +/** + * enum kdbus_msg_flags - type of message + * @KDBUS_MSG_FLAGS_EXPECT_REPLY: Expect a reply message, used for + * method calls. The userspace-supplied + * cookie identifies the message and the + * respective reply carries the cookie + * in cookie_reply + * @KDBUS_MSG_FLAGS_SYNC_REPLY: Wait for destination connection to + * reply to this message. The + * KDBUS_CMD_MSG_SEND ioctl() will block + * until the reply is received, and + * offset_reply in struct kdbus_msg will + * yield the offset in the sender's pool + * where the reply can be found. + * This flag is only valid if + * @KDBUS_MSG_FLAGS_EXPECT_REPLY is set as + * well. + * @KDBUS_MSG_FLAGS_NO_AUTO_START: Do not start a service, if the addressed + * name is not currently active + */ +enum kdbus_msg_flags { + KDBUS_MSG_FLAGS_EXPECT_REPLY = 1 << 0, + KDBUS_MSG_FLAGS_SYNC_REPLY = 1 << 1, + KDBUS_MSG_FLAGS_NO_AUTO_START = 1 << 2, +}; + +/** + * enum kdbus_payload_type - type of payload carried by message + * @KDBUS_PAYLOAD_KERNEL: Kernel-generated simple message + * @KDBUS_PAYLOAD_DBUS: D-Bus marshalling "DBusDBus" + */ +enum kdbus_payload_type { + KDBUS_PAYLOAD_KERNEL, + KDBUS_PAYLOAD_DBUS = 0x4442757344427573ULL, +}; + +/** + * struct kdbus_msg - the representation of a kdbus message + * @size: Total size of the message + * @flags: Message flags (KDBUS_MSG_FLAGS_*) + * @priority: Message queue priority value + * @dst_id: 64-bit ID of the destination connection + * @src_id: 64-bit ID of the source connection + * @payload_type: Payload type (KDBUS_PAYLOAD_*) + * @cookie: Userspace-supplied cookie, for the connection + * to identify its messages + * @timeout_ns: The time to wait for a message reply from the peer. + * If there is no reply, a kernel-generated message + * with an attached KDBUS_ITEM_REPLY_TIMEOUT item + * is sent to @src_id. + * @cookie_reply: A reply to the requesting message with the same + * cookie. The requesting connection can match its + * request and the reply with this value + * @offset_reply: If KDBUS_MSG_FLAGS_WAIT_FOR_REPLY, this field will + * contain the offset in the sender's pool where the + * reply is stored. + * @items: A list of kdbus_items containing the message payload + */ +struct kdbus_msg { + __u64 size; + __u64 flags; + __s64 priority; + __u64 dst_id; + __u64 src_id; + __u64 payload_type; + __u64 cookie; + union { + __u64 timeout_ns; + __u64 cookie_reply; + __u64 offset_reply; + }; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/** + * enum kdbus_recv_flags - flags for de-queuing messages + * @KDBUS_RECV_PEEK: Return the next queued message without + * actually de-queuing it, and without installing + * any file descriptors or other resources. It is + * usually used to determine the activating + * connection of a bus name. + * @KDBUS_RECV_DROP: Drop and free the next queued message and all + * its resources without actually receiving it. + * @KDBUS_RECV_USE_PRIORITY: Only de-queue messages with the specified or + * higher priority (lowest values); if not set, + * the priority value is ignored. + */ +enum kdbus_recv_flags { + KDBUS_RECV_PEEK = 1 << 0, + KDBUS_RECV_DROP = 1 << 1, + KDBUS_RECV_USE_PRIORITY = 1 << 2, +}; + +/** + * struct kdbus_cmd_recv - struct to de-queue a buffered message + * @flags: KDBUS_RECV_* flags + * @priority: Minimum priority of the messages to de-queue. Lowest + * values have the highest priority. + * @offset: Returned offset in the pool where the message is + * stored. The user must use KDBUS_CMD_FREE to free + * the allocated memory. + * + * This struct is used with the KDBUS_CMD_MSG_RECV ioctl. + */ +struct kdbus_cmd_recv { + __u64 flags; + __s64 priority; + __u64 offset; +} __attribute__((aligned(8))); + +/** + * enum kdbus_policy_access_type - permissions of a policy record + * @_KDBUS_POLICY_ACCESS_NULL: Uninitialized/invalid + * @KDBUS_POLICY_ACCESS_USER: Grant access to a uid + * @KDBUS_POLICY_ACCESS_GROUP: Grant access to gid + * @KDBUS_POLICY_ACCESS_WORLD: World-accessible + */ +enum kdbus_policy_access_type { + _KDBUS_POLICY_ACCESS_NULL, + KDBUS_POLICY_ACCESS_USER, + KDBUS_POLICY_ACCESS_GROUP, + KDBUS_POLICY_ACCESS_WORLD, +}; + +/** + * enum kdbus_policy_access_flags - mode flags + * @KDBUS_POLICY_RECV: Allow receive + * @KDBUS_POLICY_SEND: Allow send + * @KDBUS_POLICY_OWN: Allow to own a well-known name + */ +enum kdbus_policy_type { + KDBUS_POLICY_RECV = 1 << 2, + KDBUS_POLICY_SEND = 1 << 1, + KDBUS_POLICY_OWN = 1 << 0, +}; + +/** + * struct kdbus_cmd_policy - a series of policies to upload + * @size: The total size of the structure + * @policies: The policies to upload + * + * A KDBUS_POLICY_NAME must always preceeds a KDBUS_POLICY_ACCESS entry. + * A new KDBUS_POLICY_NAME can be added after KDBUS_POLICY_ACCESS for + * chaining multiple policies together. + */ +struct kdbus_cmd_policy { + __u64 size; + struct kdbus_item policies[0]; +} __attribute__((aligned(8))); + +/** + * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello + * @KDBUS_HELLO_ACCEPT_FD: The connection allows the receiving of + * any passed file descriptors + * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers + * a well-know name for a process to be started + * when traffic arrives + * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor + * bus traffic + */ +enum kdbus_hello_flags { + KDBUS_HELLO_ACCEPT_FD = 1 << 0, + KDBUS_HELLO_ACTIVATOR = 1 << 1, + KDBUS_HELLO_MONITOR = 1 << 2, +}; + +/** + * enum kdbus_attach_flags - flags for metadata attachments + * @KDBUS_ATTACH_TIMESTAMP: Timestamp + * @KDBUS_ATTACH_CREDS: Credentials + * @KDBUS_ATTACH_NAMES: Well-known names + * @KDBUS_ATTACH_COMM: The "comm" process identifier + * @KDBUS_ATTACH_EXE: The path of the executable + * @KDBUS_ATTACH_CMDLINE: The process command line + * @KDBUS_ATTACH_CGROUP: The croup membership + * @KDBUS_ATTACH_CAPS: The process capabilities + * @KDBUS_ATTACH_SECLABEL: The security label + * @KDBUS_ATTACH_AUDIT: The audit IDs + * @KDBUS_ATTACH_CONN_NAME: The human-readable connection name + */ +enum kdbus_attach_flags { + KDBUS_ATTACH_TIMESTAMP = 1 << 0, + KDBUS_ATTACH_CREDS = 1 << 1, + KDBUS_ATTACH_NAMES = 1 << 2, + KDBUS_ATTACH_COMM = 1 << 3, + KDBUS_ATTACH_EXE = 1 << 4, + KDBUS_ATTACH_CMDLINE = 1 << 5, + KDBUS_ATTACH_CGROUP = 1 << 6, + KDBUS_ATTACH_CAPS = 1 << 7, + KDBUS_ATTACH_SECLABEL = 1 << 8, + KDBUS_ATTACH_AUDIT = 1 << 9, + KDBUS_ATTACH_CONN_NAME = 1 << 10, +}; + +/** + * struct kdbus_cmd_hello - struct to say hello to kdbus + * @size: The total size of the structure + * @conn_flags: Connection flags (KDBUS_HELLO_*). The kernel will + * return its capabilities in that field. + * @attach_flags: Mask of metadata to attach to each message sent + * (KDBUS_ATTACH_*) + * @bus_flags: The flags field copied verbatim from the original + * KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful + * to do negotiation of features of the payload that is + * transferred (kernel → userspace) + * @id: The ID of this connection (kernel → userspace) + * @pool_size: Size of the connection's buffer where the received + * messages are placed + * @bloom: The bloom properties of the bus, specified + * by the bus creator (kernel → userspace) + * @id128: Unique 128-bit ID of the bus (kernel → userspace) + * @items: A list of items + * + * This struct is used with the KDBUS_CMD_HELLO ioctl. + */ +struct kdbus_cmd_hello { + __u64 size; + __u64 conn_flags; + __u64 attach_flags; + __u64 bus_flags; + __u64 id; + __u64 pool_size; + struct kdbus_bloom_parameter bloom; + __u8 id128[16]; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/* Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE */ +enum kdbus_make_flags { + KDBUS_MAKE_ACCESS_GROUP = 1 << 0, + KDBUS_MAKE_ACCESS_WORLD = 1 << 1, + KDBUS_MAKE_POLICY_OPEN = 1 << 2, +}; + +/** + * struct kdbus_cmd_make - struct to make a bus, an endpoint or a domain + * @size: The total size of the struct + * @flags: Properties for the bus/ep/domain to create + * @items: Items describing details + * + * This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_EP_MAKE and + * KDBUS_CMD_DOMAIN_MAKE ioctls. + */ +struct kdbus_cmd_make { + __u64 size; + __u64 flags; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/** + * enum kdbus_name_flags - properties of a well-known name + * @KDBUS_NAME_REPLACE_EXISTING: Try to replace name of other connections + * @KDBUS_NAME_ALLOW_REPLACEMENT: Allow the replacement of the name + * @KDBUS_NAME_QUEUE: Name should be queued if busy + * @KDBUS_NAME_IN_QUEUE: Name is queued + * @KDBUS_NAME_ACTIVATOR: Name is owned by a activator connection + */ +enum kdbus_name_flags { + KDBUS_NAME_REPLACE_EXISTING = 1 << 0, + KDBUS_NAME_ALLOW_REPLACEMENT = 1 << 1, + KDBUS_NAME_QUEUE = 1 << 2, + KDBUS_NAME_IN_QUEUE = 1 << 3, + KDBUS_NAME_ACTIVATOR = 1 << 4, +}; + +/** + * struct kdbus_cmd_name - struct to describe a well-known name + * @size: The total size of the struct + * @flags: Flags for a name entry (KDBUS_NAME_*) + * @owner_id: The current owner of the name. For requests, + * privileged users may set this field to + * (de)register names on behalf of other connections. + * @conn_flags: The flags of the owning connection (KDBUS_HELLO_*) + * @name: The well-known name + * + * This structure is used with the KDBUS_CMD_NAME_ACQUIRE ioctl. + */ +struct kdbus_cmd_name { + __u64 size; + __u64 flags; + __u64 owner_id; + __u64 conn_flags; + char name[0]; +} __attribute__((aligned(8))); + +/** + * enum kdbus_name_list_flags - what to include into the returned list + * @KDBUS_NAME_LIST_UNIQUE: All active connections + * @KDBUS_NAME_LIST_NAMES: All known well-known names + * @KDBUS_NAME_LIST_ACTIVATORS: All activator connections + * @KDBUS_NAME_LIST_QUEUED: All queued-up names + */ +enum kdbus_name_list_flags { + KDBUS_NAME_LIST_UNIQUE = 1 << 0, + KDBUS_NAME_LIST_NAMES = 1 << 1, + KDBUS_NAME_LIST_ACTIVATORS = 1 << 2, + KDBUS_NAME_LIST_QUEUED = 1 << 3, +}; + +/** + * struct kdbus_cmd_name_list - request a list of name entries + * @flags: Flags for the query (KDBUS_NAME_LIST_*) + * @offset: The returned offset in the caller's pool buffer. + * The user must use KDBUS_CMD_FREE to free the + * allocated memory. + * + * This structure is used with the KDBUS_CMD_NAME_LIST ioctl. + */ +struct kdbus_cmd_name_list { + __u64 flags; + __u64 offset; +} __attribute__((aligned(8))); + +/** + * struct kdbus_name_list - information returned by KDBUS_CMD_NAME_LIST + * @size: The total size of the structure + * @names: A list of names + * + * Note that the user is responsible for freeing the allocated memory with + * the KDBUS_CMD_FREE ioctl. + */ +struct kdbus_name_list { + __u64 size; + struct kdbus_cmd_name names[0]; +}; + +/** + * struct kdbus_cmd_conn_info - struct used for KDBUS_CMD_CONN_INFO ioctl + * @size: The total size of the struct + * @flags: KDBUS_ATTACH_* flags + * @id: The 64-bit ID of the connection. If set to zero, passing + * @name is required. kdbus will look up the name to + * determine the ID in this case. + * @offset: Returned offset in the caller's pool buffer where the + * kdbus_conn_info struct result is stored. The user must + * use KDBUS_CMD_FREE to free the allocated memory. + * @name: The optional well-known name to look up. Only needed in + * case @id is zero. + * + * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will + * tell the user the offset in the connection pool buffer at which to find the + * result in a struct kdbus_conn_info. + */ +struct kdbus_cmd_conn_info { + __u64 size; + __u64 flags; + __u64 id; + __u64 offset; + char name[0]; +} __attribute__((aligned(8))); + +/** + * struct kdbus_conn_info - information returned by KDBUS_CMD_CONN_INFO + * @size: The total size of the struct + * @id: The connection's 64-bit ID + * @flags: The connection's flags + * @items: A list of struct kdbus_item + * + * Note that the user is responsible for freeing the allocated memory with + * the KDBUS_CMD_FREE ioctl. + */ +struct kdbus_conn_info { + __u64 size; + __u64 id; + __u64 flags; + struct kdbus_item items[0]; +}; + +/** + * struct kdbus_cmd_conn_update - update flags of a connection + * @size: The total size of the struct + * @items: A list of struct kdbus_item + * + * This struct is used with the KDBUS_CMD_CONN_UPDATE ioctl. + */ +struct kdbus_cmd_conn_update { + __u64 size; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/** + * struct kdbus_cmd_match - struct to add or remove matches + * @size: The total size of the struct + * @owner_id: Privileged users may (de)register matches on behalf + * of other peers + * @cookie: Userspace supplied cookie. When removing, the cookie + * identifies the match to remove + * @items: A list of items for additional information + * + * This structure is used with the KDBUS_CMD_ADD_MATCH and + * KDBUS_CMD_REMOVE_MATCH ioctl. + */ +struct kdbus_cmd_match { + __u64 size; + __u64 owner_id; + __u64 cookie; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/** + * struct kdbus_cmd_memfd_make - create a kdbus memfd + * @size: The total size of the struct + * @file_size: The initial file size + * @fd: The returned file descriptor number + * @__pad: Padding to ensure proper alignement + * @items: A list of items for additional information + * + * This structure is used with the KDBUS_CMD_MEMFD_NEW ioctl. + */ +struct kdbus_cmd_memfd_make { + __u64 size; + __u64 file_size; + int fd; + __u32 __pad; + struct kdbus_item items[0]; +} __attribute__((aligned(8))); + +/** + * enum kdbus_ioctl_type - Ioctl API + * @KDBUS_CMD_BUS_MAKE: After opening the "control" device node, this + * command creates a new bus with the specified + * name. The bus is immediately shut down and + * cleaned up when the opened "control" device node + * is closed. + * @KDBUS_CMD_DOMAIN_MAKE: Similar to KDBUS_CMD_BUS_MAKE, but it creates a + * new kdbus domain. + * @KDBUS_CMD_EP_MAKE: Creates a new named special endpoint to talk to + * the bus. Such endpoints usually carry a more + * restrictive policy and grant restricted access + * to specific applications. + * @KDBUS_CMD_HELLO: By opening the bus device node a connection is + * created. After a HELLO the opened connection + * becomes an active peer on the bus. + * @KDBUS_CMD_BYEBYE: Disconnect a connection. If the connection's + * message list is empty, the calls succeeds, and + * the handle is rendered unusable. Otherwise, + * -EAGAIN is returned without any further side- + * effects. + * @KDBUS_CMD_MSG_SEND: Send a message and pass data from userspace to + * the kernel. + * @KDBUS_CMD_MSG_RECV: Receive a message from the kernel which is + * placed in the receiver's pool. + * @KDBUS_CMD_MSG_CANCEL: Cancel a pending request of a message that + * blocks while waiting for a reply. The parameter + * denotes the cookie of the message in flight. + * @KDBUS_CMD_FREE: Release the allocated memory in the receiver's + * pool. + * @KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with + * the connection. Well-known names are used to + * address a peer on the bus. + * @KDBUS_CMD_NAME_RELEASE: Release a well-known name the connection + * currently owns. + * @KDBUS_CMD_NAME_LIST: Retrieve the list of all currently registered + * well-known and unique names. + * @KDBUS_CMD_CONN_INFO: Retrieve credentials and properties of the + * initial creator of the connection. The data was + * stored at registration time and does not + * necessarily represent the connected process or + * the actual state of the process. + * @KDBUS_CMD_CONN_UPDATE: Update the properties of a connection. Used to + * update the metadata subscription. + * @KDBUS_CMD_MATCH_ADD: Install a match which broadcast messages should + * be delivered to the connection. + * @KDBUS_CMD_MATCH_REMOVE: Remove a current match for broadcast messages. + * @KDBUS_CMD_EP_POLICY_SET: Set the policy of an endpoint. It is used to + * restrict the access for endpoints created with + * KDBUS_CMD_EP_MAKE. + * @KDBUS_CMD_MEMFD_NEW: Return a new file descriptor which provides an + * anonymous shared memory file and which can be + * used to pass around larger chunks of data. + * Kdbus memfd files can be sealed, which allows + * the receiver to trust the data it has received. + * Kdbus memfd files expose only very limited + * operations, they can be mmap()ed, seek()ed, + * (p)read(v)() and (p)write(v)(); most other + * common file operations are not implemented. + * Special caution needs to be taken with + * read(v)()/write(v)() on a shared file; the + * underlying file position is always shared + * between all users of the file and race against + * each other, pread(v)()/pwrite(v)() avoid these + * issues. + * @KDBUS_CMD_MEMFD_SIZE_GET: Return the size of the underlying file, which + * changes with write(). + * @KDBUS_CMD_MEMFD_SIZE_SET: Truncate the underlying file to the specified + * size. + * @KDBUS_CMD_MEMFD_SEAL_GET: Return the state of the file sealing. + * @KDBUS_CMD_MEMFD_SEAL_SET: Seal or break a seal of the file. Only files + * which are not shared with other processes and + * which are currently not mapped can be sealed. + * The current process needs to be the one and + * single owner of the file, the sealing cannot + * be changed as long as the file is shared. + */ +enum kdbus_ioctl_type { + KDBUS_CMD_BUS_MAKE = _IOW (KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_make), + KDBUS_CMD_DOMAIN_MAKE = _IOW (KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_make), + KDBUS_CMD_EP_MAKE = _IOW (KDBUS_IOC_MAGIC, 0x20, struct kdbus_cmd_make), + + KDBUS_CMD_HELLO = _IOWR(KDBUS_IOC_MAGIC, 0x30, struct kdbus_cmd_hello), + KDBUS_CMD_BYEBYE = _IO (KDBUS_IOC_MAGIC, 0x31), + + KDBUS_CMD_MSG_SEND = _IOWR(KDBUS_IOC_MAGIC, 0x40, struct kdbus_msg), + KDBUS_CMD_MSG_RECV = _IOWR(KDBUS_IOC_MAGIC, 0x41, struct kdbus_cmd_recv), + KDBUS_CMD_MSG_CANCEL = _IOW (KDBUS_IOC_MAGIC, 0x42, __u64 *), + KDBUS_CMD_FREE = _IOW (KDBUS_IOC_MAGIC, 0x43, __u64 *), + + KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOC_MAGIC, 0x50, struct kdbus_cmd_name), + KDBUS_CMD_NAME_RELEASE = _IOW (KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name), + KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOC_MAGIC, 0x52, struct kdbus_cmd_name_list), + + KDBUS_CMD_CONN_INFO = _IOWR(KDBUS_IOC_MAGIC, 0x60, struct kdbus_cmd_conn_info), + KDBUS_CMD_CONN_UPDATE = _IOW (KDBUS_IOC_MAGIC, 0x61, struct kdbus_cmd_conn_update), + + KDBUS_CMD_MATCH_ADD = _IOW (KDBUS_IOC_MAGIC, 0x70, struct kdbus_cmd_match), + KDBUS_CMD_MATCH_REMOVE = _IOW (KDBUS_IOC_MAGIC, 0x71, struct kdbus_cmd_match), + + KDBUS_CMD_EP_POLICY_SET = _IOW (KDBUS_IOC_MAGIC, 0x80, struct kdbus_cmd_policy), + + KDBUS_CMD_MEMFD_NEW = _IOWR(KDBUS_IOC_MAGIC, 0xc0, struct kdbus_cmd_memfd_make), + KDBUS_CMD_MEMFD_SIZE_GET = _IOR (KDBUS_IOC_MAGIC, 0xc1, __u64 *), + KDBUS_CMD_MEMFD_SIZE_SET = _IOW (KDBUS_IOC_MAGIC, 0xc2, __u64 *), + KDBUS_CMD_MEMFD_SEAL_GET = _IOR (KDBUS_IOC_MAGIC, 0xc3, int *), + KDBUS_CMD_MEMFD_SEAL_SET = _IO (KDBUS_IOC_MAGIC, 0xc4), +}; + +/* + * errno - api error codes + * @E2BIG: A message contains too many records or items. + * @EADDRINUSE: A well-known bus name is already taken by another + * connection. + * @EADDRNOTAVAIL: A message flagged not to activate a service, addressed + * a service which is not currently running. + * @EAGAIN: No messages are queued at the moment. + * @EBADF: File descriptors passed with the message are not valid. + * @EBADFD: A bus connection is in a corrupted state. + * @EBADMSG: Passed data contains a combination of conflicting or + * inconsistent types. + * @EBUSY: The user tried to say BYEBYE to a connection, but the + * connection had a non-empty message list. + * @ECANCELED: A synchronous message sending was cancelled. + * @ECONNRESET: A connection is shut down, no further operations are + * possible. + * @ECOMM: A peer does not accept the file descriptors addressed + * to it. + * @EDESTADDRREQ: The well-known bus name is required but missing. + * @EDOM: The size of data does not match the expectations. Used + * for bloom bit field sizes. + * @EEXIST: A requested domain, bus or endpoint with the same + * name already exists. A specific data type, which is + * only expected once, is provided multiple times. + * @EFAULT: The supplied memory could not be accessed, or the data + * is not properly aligned. + * @EINVAL: The provided data does not match its type or other + * expectations, like a string which is not NUL terminated, + * or a string length that points behind the first + * \0-byte in the string. + * @EMEDIUMTYPE: A file descriptor which is not a kdbus memfd was + * refused to send as KDBUS_MSG_PAYLOAD_MEMFD. + * @EMFILE: Too many file descriptors have been supplied with a + * message. + * Too many connections or buses are created for a given + * user. + * @EMLINK: Too many requests from this connection to other peers + * are queued and waiting for a reply + * @EMSGSIZE: The supplied data is larger than the allowed maximum + * size. + * @ENAMETOOLONG: The requested name is larger than the allowed maximum + * size. + * @ENOBUFS: There is no space left for the submitted data to fit + * into the receiver's pool. + * @ENOENT: The name to query information about is currently not on + * the bus. + * @ENOMEM: Out of memory. + * @ENOMSG: The queue is not empty, but no message with a matching + * priority is currently queued. + * @ENOSYS: The requested functionality is not available. + * @ENOTSUPP: The feature negotiation failed, a not supported feature + * was requested, or an unknown item type was received. + * @ENOTTY: An unknown ioctl command was received. + * @ENOTUNIQ: A specific data type was addressed to a broadcast + * address, but only direct addresses support this kind of + * data. + * @ENXIO: A unique address does not exist, or an offset in the + * receiver's pool does not represent a queued message. + * @EPERM: The policy prevented an operation. The requested + * resource is owned by another entity. + * @EPIPE: When sending a message, a synchronous reply from the + * receiving connection was expected but the connection + * died before answering. + * @ESHUTDOWN: A domain or endpoint is currently shutting down; + * no further operations will be possible. + * @ESRCH: A requested well-known bus name is not found. + * @ETIMEDOUT: A synchronous wait for a message reply did not arrive + * within the specified time frame. + * @ETXTBSY: A kdbus memfd file cannot be sealed or the seal removed, + * because it is shared with other processes or still + * mmap()ed. + * @EXFULL: The size limits in the pool are reached, no data of + * the size tried to submit can be queued. + */ +#endif diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c new file mode 100644 index 0000000..20f540d --- /dev/null +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -0,0 +1,3126 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "strv.h" +#include "set.h" +#include "missing.h" +#include "def.h" +#include "cgroup-util.h" +#include "bus-label.h" + +#include "sd-bus.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-type.h" +#include "bus-socket.h" +#include "bus-kernel.h" +#include "bus-control.h" +#include "bus-introspect.h" +#include "bus-signature.h" +#include "bus-objects.h" +#include "bus-util.h" +#include "bus-container.h" +#include "bus-protocol.h" + +static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); +static int attach_io_events(sd_bus *b); +static void detach_io_events(sd_bus *b); + +static void bus_close_fds(sd_bus *b) { + assert(b); + + detach_io_events(b); + + if (b->input_fd >= 0) + close_nointr_nofail(b->input_fd); + + if (b->output_fd >= 0 && b->output_fd != b->input_fd) + close_nointr_nofail(b->output_fd); + + b->input_fd = b->output_fd = -1; +} + +static void bus_node_destroy(sd_bus *b, struct node *n) { + struct node_callback *c; + struct node_vtable *v; + struct node_enumerator *e; + + assert(b); + + if (!n) + return; + + while (n->child) + bus_node_destroy(b, n->child); + + while ((c = n->callbacks)) { + LIST_REMOVE(callbacks, n->callbacks, c); + free(c); + } + + while ((v = n->vtables)) { + LIST_REMOVE(vtables, n->vtables, v); + free(v->interface); + free(v); + } + + while ((e = n->enumerators)) { + LIST_REMOVE(enumerators, n->enumerators, e); + free(e); + } + + if (n->parent) + LIST_REMOVE(siblings, n->parent->child, n); + + assert_se(hashmap_remove(b->nodes, n->path) == n); + free(n->path); + free(n); +} + +static void bus_reset_queues(sd_bus *b) { + assert(b); + + while (b->rqueue_size > 0) + sd_bus_message_unref(b->rqueue[--b->rqueue_size]); + + free(b->rqueue); + b->rqueue = NULL; + b->rqueue_allocated = 0; + + while (b->wqueue_size > 0) + sd_bus_message_unref(b->wqueue[--b->wqueue_size]); + + free(b->wqueue); + b->wqueue = NULL; + b->wqueue_allocated = 0; +} + +static void bus_free(sd_bus *b) { + struct filter_callback *f; + struct node *n; + + assert(b); + + sd_bus_detach_event(b); + + if (b->default_bus_ptr) + *b->default_bus_ptr = NULL; + + bus_close_fds(b); + + if (b->kdbus_buffer) + munmap(b->kdbus_buffer, KDBUS_POOL_SIZE); + + free(b->rbuffer); + free(b->unique_name); + free(b->auth_buffer); + free(b->address); + free(b->kernel); + free(b->machine); + free(b->fake_label); + free(b->cgroup_root); + free(b->connection_name); + + free(b->exec_path); + strv_free(b->exec_argv); + + close_many(b->fds, b->n_fds); + free(b->fds); + + bus_reset_queues(b); + + hashmap_free_free(b->reply_callbacks); + prioq_free(b->reply_callbacks_prioq); + + while ((f = b->filter_callbacks)) { + LIST_REMOVE(callbacks, b->filter_callbacks, f); + free(f); + } + + bus_match_free(&b->match_callbacks); + + hashmap_free_free(b->vtable_methods); + hashmap_free_free(b->vtable_properties); + + while ((n = hashmap_first(b->nodes))) + bus_node_destroy(b, n); + + hashmap_free(b->nodes); + + bus_kernel_flush_memfd(b); + + assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0); + + free(b); +} + +_public_ int sd_bus_new(sd_bus **ret) { + sd_bus *r; + + assert_return(ret, -EINVAL); + + r = new0(sd_bus, 1); + if (!r) + return -ENOMEM; + + r->n_ref = REFCNT_INIT; + r->input_fd = r->output_fd = -1; + r->message_version = 1; + r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; + r->hello_flags |= KDBUS_HELLO_ACCEPT_FD; + r->attach_flags |= KDBUS_ATTACH_NAMES; + r->original_pid = getpid(); + + assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0); + + /* We guarantee that wqueue always has space for at least one + * entry */ + if (!GREEDY_REALLOC(r->wqueue, r->wqueue_allocated, 1)) { + free(r); + return -ENOMEM; + } + + *ret = r; + return 0; +} + +_public_ int sd_bus_set_address(sd_bus *bus, const char *address) { + char *a; + + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(address, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + a = strdup(address); + if (!a) + return -ENOMEM; + + free(bus->address); + bus->address = a; + + return 0; +} + +_public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(input_fd >= 0, -EINVAL); + assert_return(output_fd >= 0, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->input_fd = input_fd; + bus->output_fd = output_fd; + return 0; +} + +_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) { + char *p, **a; + + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(path, -EINVAL); + assert_return(!strv_isempty(argv), -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + p = strdup(path); + if (!p) + return -ENOMEM; + + a = strv_copy(argv); + if (!a) { + free(p); + return -ENOMEM; + } + + free(bus->exec_path); + strv_free(bus->exec_argv); + + bus->exec_path = p; + bus->exec_argv = a; + + return 0; +} + +_public_ int sd_bus_set_bus_client(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->bus_client = !!b; + return 0; +} + +_public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ACCEPT_FD, b); + return 0; +} + +_public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + SET_FLAG(bus->attach_flags, KDBUS_ATTACH_TIMESTAMP, b); + return 0; +} + +_public_ int sd_bus_negotiate_creds(sd_bus *bus, uint64_t mask) { + assert_return(bus, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + /* The well knowns we need unconditionally, so that matches can work */ + bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; + + return kdbus_translate_attach_flags(bus->creds_mask, &bus->creds_mask); +} + +_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { + assert_return(bus, -EINVAL); + assert_return(b || sd_id128_equal(server_id, SD_ID128_NULL), -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->is_server = !!b; + bus->server_id = server_id; + return 0; +} + +_public_ int sd_bus_set_anonymous(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->anonymous_auth = !!b; + return 0; +} + +_public_ int sd_bus_set_trusted(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->trusted = !!b; + return 0; +} + +_public_ int sd_bus_set_name(sd_bus *bus, const char *name) { + char *n; + + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + n = strdup(name); + if (!n) + return -ENOMEM; + + free(bus->connection_name); + bus->connection_name = n; + + return 0; +} + +static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) { + const char *s; + int r; + + assert(bus); + assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING); + assert(reply); + + r = sd_bus_message_get_errno(reply); + if (r < 0) + return r; + if (r > 0) + return -r; + + r = sd_bus_message_read(reply, "s", &s); + if (r < 0) + return r; + + if (!service_name_is_valid(s) || s[0] != ':') + return -EBADMSG; + + bus->unique_name = strdup(s); + if (!bus->unique_name) + return -ENOMEM; + + if (bus->state == BUS_HELLO) + bus->state = BUS_RUNNING; + + return 1; +} + +static int bus_send_hello(sd_bus *bus) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + + if (!bus->bus_client || bus->is_kernel) + return 0; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "Hello"); + if (r < 0) + return r; + + return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie); +} + +int bus_start_running(sd_bus *bus) { + assert(bus); + + if (bus->bus_client && !bus->is_kernel) { + bus->state = BUS_HELLO; + return 1; + } + + bus->state = BUS_RUNNING; + return 1; +} + +static int parse_address_key(const char **p, const char *key, char **value) { + size_t l, n = 0, allocated = 0; + const char *a; + char *r = NULL; + + assert(p); + assert(*p); + assert(value); + + if (key) { + l = strlen(key); + if (strncmp(*p, key, l) != 0) + return 0; + + if ((*p)[l] != '=') + return 0; + + if (*value) + return -EINVAL; + + a = *p + l + 1; + } else + a = *p; + + while (*a != ';' && *a != ',' && *a != 0) { + char c; + + if (*a == '%') { + int x, y; + + x = unhexchar(a[1]); + if (x < 0) { + free(r); + return x; + } + + y = unhexchar(a[2]); + if (y < 0) { + free(r); + return y; + } + + c = (char) ((x << 4) | y); + a += 3; + } else { + c = *a; + a++; + } + + if (!GREEDY_REALLOC(r, allocated, n + 2)) + return -ENOMEM; + + r[n++] = c; + } + + if (!r) { + r = strdup(""); + if (!r) + return -ENOMEM; + } else + r[n] = 0; + + if (*a == ',') + a++; + + *p = a; + + free(*value); + *value = r; + + return 1; +} + +static void skip_address_key(const char **p) { + assert(p); + assert(*p); + + *p += strcspn(*p, ","); + + if (**p == ',') + (*p) ++; +} + +static int parse_unix_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *path = NULL, *abstract = NULL; + size_t l; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "path", &path); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "abstract", &abstract); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!path && !abstract) + return -EINVAL; + + if (path && abstract) + return -EINVAL; + + if (path) { + l = strlen(path); + if (l > sizeof(b->sockaddr.un.sun_path)) + return -E2BIG; + + b->sockaddr.un.sun_family = AF_UNIX; + strncpy(b->sockaddr.un.sun_path, path, sizeof(b->sockaddr.un.sun_path)); + b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l; + } else if (abstract) { + l = strlen(abstract); + if (l > sizeof(b->sockaddr.un.sun_path) - 1) + return -E2BIG; + + b->sockaddr.un.sun_family = AF_UNIX; + b->sockaddr.un.sun_path[0] = 0; + strncpy(b->sockaddr.un.sun_path+1, abstract, sizeof(b->sockaddr.un.sun_path)-1); + b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l; + } + + return 0; +} + +static int parse_tcp_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *host = NULL, *port = NULL, *family = NULL; + int r; + struct addrinfo *result, hints = { + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_ADDRCONFIG, + }; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "host", &host); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "port", &port); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "family", &family); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!host || !port) + return -EINVAL; + + if (family) { + if (streq(family, "ipv4")) + hints.ai_family = AF_INET; + else if (streq(family, "ipv6")) + hints.ai_family = AF_INET6; + else + return -EINVAL; + } + + r = getaddrinfo(host, port, &hints, &result); + if (r == EAI_SYSTEM) + return -errno; + else if (r != 0) + return -EADDRNOTAVAIL; + + memcpy(&b->sockaddr, result->ai_addr, result->ai_addrlen); + b->sockaddr_size = result->ai_addrlen; + + freeaddrinfo(result); + + return 0; +} + +static int parse_exec_address(sd_bus *b, const char **p, char **guid) { + char *path = NULL; + unsigned n_argv = 0, j; + char **argv = NULL; + size_t allocated = 0; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + goto fail; + else if (r > 0) + continue; + + r = parse_address_key(p, "path", &path); + if (r < 0) + goto fail; + else if (r > 0) + continue; + + if (startswith(*p, "argv")) { + unsigned ul; + + errno = 0; + ul = strtoul(*p + 4, (char**) p, 10); + if (errno > 0 || **p != '=' || ul > 256) { + r = -EINVAL; + goto fail; + } + + (*p) ++; + + if (ul >= n_argv) { + if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) { + r = -ENOMEM; + goto fail; + } + + n_argv = ul + 1; + } + + r = parse_address_key(p, NULL, argv + ul); + if (r < 0) + goto fail; + + continue; + } + + skip_address_key(p); + } + + if (!path) { + r = -EINVAL; + goto fail; + } + + /* Make sure there are no holes in the array, with the + * exception of argv[0] */ + for (j = 1; j < n_argv; j++) + if (!argv[j]) { + r = -EINVAL; + goto fail; + } + + if (argv && argv[0] == NULL) { + argv[0] = strdup(path); + if (!argv[0]) { + r = -ENOMEM; + goto fail; + } + } + + b->exec_path = path; + b->exec_argv = argv; + return 0; + +fail: + for (j = 0; j < n_argv; j++) + free(argv[j]); + + free(argv); + free(path); + return r; +} + +static int parse_kernel_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *path = NULL; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "path", &path); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!path) + return -EINVAL; + + free(b->kernel); + b->kernel = path; + path = NULL; + + return 0; +} + +static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *machine = NULL; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "machine", &machine); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!machine) + return -EINVAL; + + if (!filename_is_safe(machine)) + return -EINVAL; + + free(b->machine); + b->machine = machine; + machine = NULL; + + b->sockaddr.un.sun_family = AF_UNIX; + strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path)); + b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/var/run/dbus/system_bus_socket") - 1; + + return 0; +} + +static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) { + _cleanup_free_ char *machine = NULL; + int r; + + assert(b); + assert(p); + assert(*p); + assert(guid); + + while (**p != 0 && **p != ';') { + r = parse_address_key(p, "guid", guid); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_address_key(p, "machine", &machine); + if (r < 0) + return r; + else if (r > 0) + continue; + + skip_address_key(p); + } + + if (!machine) + return -EINVAL; + + if (!filename_is_safe(machine)) + return -EINVAL; + + free(b->machine); + b->machine = machine; + machine = NULL; + + free(b->kernel); + b->kernel = strdup("/dev/kdbus/0-system/bus"); + if (!b->kernel) + return -ENOMEM; + + return 0; +} + +static void bus_reset_parsed_address(sd_bus *b) { + assert(b); + + zero(b->sockaddr); + b->sockaddr_size = 0; + strv_free(b->exec_argv); + free(b->exec_path); + b->exec_path = NULL; + b->exec_argv = NULL; + b->server_id = SD_ID128_NULL; + free(b->kernel); + b->kernel = NULL; + free(b->machine); + b->machine = NULL; +} + +static int bus_parse_next_address(sd_bus *b) { + _cleanup_free_ char *guid = NULL; + const char *a; + int r; + + assert(b); + + if (!b->address) + return 0; + if (b->address[b->address_index] == 0) + return 0; + + bus_reset_parsed_address(b); + + a = b->address + b->address_index; + + while (*a != 0) { + + if (*a == ';') { + a++; + continue; + } + + if (startswith(a, "unix:")) { + a += 5; + + r = parse_unix_address(b, &a, &guid); + if (r < 0) + return r; + break; + + } else if (startswith(a, "tcp:")) { + + a += 4; + r = parse_tcp_address(b, &a, &guid); + if (r < 0) + return r; + + break; + + } else if (startswith(a, "unixexec:")) { + + a += 9; + r = parse_exec_address(b, &a, &guid); + if (r < 0) + return r; + + break; + + } else if (startswith(a, "kernel:")) { + + a += 7; + r = parse_kernel_address(b, &a, &guid); + if (r < 0) + return r; + + break; + } else if (startswith(a, "x-container-unix:")) { + + a += 17; + r = parse_container_unix_address(b, &a, &guid); + if (r < 0) + return r; + + break; + } else if (startswith(a, "x-container-kernel:")) { + + a += 19; + r = parse_container_kernel_address(b, &a, &guid); + if (r < 0) + return r; + + break; + } + + a = strchr(a, ';'); + if (!a) + return 0; + } + + if (guid) { + r = sd_id128_from_string(guid, &b->server_id); + if (r < 0) + return r; + } + + b->address_index = a - b->address; + return 1; +} + +static int bus_start_address(sd_bus *b) { + int r; + + assert(b); + + for (;;) { + bool skipped = false; + + bus_close_fds(b); + + if (b->exec_path) + r = bus_socket_exec(b); + else if (b->machine && b->kernel) + r = bus_container_connect_kernel(b); + else if (b->machine && b->sockaddr.sa.sa_family != AF_UNSPEC) + r = bus_container_connect_socket(b); + else if (b->kernel) + r = bus_kernel_connect(b); + else if (b->sockaddr.sa.sa_family != AF_UNSPEC) + r = bus_socket_connect(b); + else + skipped = true; + + if (!skipped) { + if (r >= 0) { + r = attach_io_events(b); + if (r >= 0) + return r; + } + + b->last_connect_error = -r; + } + + r = bus_parse_next_address(b); + if (r < 0) + return r; + if (r == 0) + return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED; + } +} + +int bus_next_address(sd_bus *b) { + assert(b); + + bus_reset_parsed_address(b); + return bus_start_address(b); +} + +static int bus_start_fd(sd_bus *b) { + struct stat st; + int r; + + assert(b); + assert(b->input_fd >= 0); + assert(b->output_fd >= 0); + + r = fd_nonblock(b->input_fd, true); + if (r < 0) + return r; + + r = fd_cloexec(b->input_fd, true); + if (r < 0) + return r; + + if (b->input_fd != b->output_fd) { + r = fd_nonblock(b->output_fd, true); + if (r < 0) + return r; + + r = fd_cloexec(b->output_fd, true); + if (r < 0) + return r; + } + + if (fstat(b->input_fd, &st) < 0) + return -errno; + + if (S_ISCHR(b->input_fd)) + return bus_kernel_take_fd(b); + else + return bus_socket_take_fd(b); +} + +_public_ int sd_bus_start(sd_bus *bus) { + int r; + + assert_return(bus, -EINVAL); + assert_return(bus->state == BUS_UNSET, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + bus->state = BUS_OPENING; + + if (bus->is_server && bus->bus_client) + return -EINVAL; + + if (bus->input_fd >= 0) + r = bus_start_fd(bus); + else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine) + r = bus_start_address(bus); + else + return -EINVAL; + + if (r < 0) + return r; + + return bus_send_hello(bus); +} + +_public_ int sd_bus_open(sd_bus **ret) { + const char *e; + sd_bus *b; + int r; + + assert_return(ret, -EINVAL); + + /* Let's connect to the starter bus if it is set, and + * otherwise to the bus that is appropropriate for the scope + * we are running in */ + + e = secure_getenv("DBUS_STARTER_BUS_TYPE"); + if (e) { + if (streq(e, "system")) + return sd_bus_open_system(ret); + else if (streq(e, "session") || streq(e, "user")) + return sd_bus_open_user(ret); + } + + e = secure_getenv("DBUS_STARTER_ADDRESS"); + if (!e) { + if (cg_pid_get_owner_uid(0, NULL) >= 0) + return sd_bus_open_user(ret); + else + return sd_bus_open_system(ret); + } + + r = sd_bus_new(&b); + if (r < 0) + return r; + + r = sd_bus_set_address(b, e); + if (r < 0) + goto fail; + + b->bus_client = true; + + /* We don't know whether the bus is trusted or not, so better + * be safe, and authenticate everything */ + b->trusted = false; + b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; + + r = sd_bus_start(b); + if (r < 0) + goto fail; + + *ret = b; + return 0; + +fail: + bus_free(b); + return r; +} + +_public_ int sd_bus_open_system(sd_bus **ret) { + const char *e; + sd_bus *b; + int r; + + assert_return(ret, -EINVAL); + + r = sd_bus_new(&b); + if (r < 0) + return r; + + e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS"); + if (e) + r = sd_bus_set_address(b, e); + else + r = sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_PATH); + if (r < 0) + goto fail; + + b->bus_client = true; + b->is_system = true; + + /* Let's do per-method access control on the system bus. We + * need the caller's UID and capability set for that. */ + b->trusted = false; + b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS; + + r = sd_bus_start(b); + if (r < 0) + goto fail; + + *ret = b; + return 0; + +fail: + bus_free(b); + return r; +} + +_public_ int sd_bus_open_user(sd_bus **ret) { + const char *e; + sd_bus *b; + int r; + + assert_return(ret, -EINVAL); + + r = sd_bus_new(&b); + if (r < 0) + return r; + + e = secure_getenv("DBUS_SESSION_BUS_ADDRESS"); + if (e) { + r = sd_bus_set_address(b, e); + if (r < 0) + goto fail; + } else { + e = secure_getenv("XDG_RUNTIME_DIR"); + if (e) { + _cleanup_free_ char *ee = NULL; + + ee = bus_address_escape(e); + if (!ee) { + r = -ENOMEM; + goto fail; + } + +#ifdef ENABLE_KDBUS + asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, (unsigned long) getuid(), ee); +#else + asprintf(&b->address, UNIX_USER_BUS_FMT, ee); +#endif + } else { +#ifdef ENABLE_KDBUS + asprintf(&b->address, KERNEL_USER_BUS_FMT, (unsigned long) getuid()); +#else + return -ECONNREFUSED; +#endif + } + + if (!b->address) { + r = -ENOMEM; + goto fail; + } + } + + b->bus_client = true; + b->is_user = true; + + /* We don't do any per-method access control on the user + * bus. */ + b->trusted = true; + + r = sd_bus_start(b); + if (r < 0) + goto fail; + + *ret = b; + return 0; + +fail: + bus_free(b); + return r; +} + +_public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) { + _cleanup_free_ char *e = NULL; + char *p = NULL; + sd_bus *bus; + int r; + + assert_return(host, -EINVAL); + assert_return(ret, -EINVAL); + + e = bus_address_escape(host); + if (!e) + return -ENOMEM; + + p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL); + if (!p) + return -ENOMEM; + + r = sd_bus_new(&bus); + if (r < 0) { + free(p); + return r; + } + + bus->address = p; + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r < 0) { + bus_free(bus); + return r; + } + + *ret = bus; + return 0; +} + +_public_ int sd_bus_open_system_container(sd_bus **ret, const char *machine) { + _cleanup_free_ char *e = NULL; + sd_bus *bus; + char *p; + int r; + + assert_return(machine, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(filename_is_safe(machine), -EINVAL); + + e = bus_address_escape(machine); + if (!e) + return -ENOMEM; + +#ifdef ENABLE_KDBUS + p = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL); +#else + p = strjoin("x-container-unix:machine=", e, NULL); +#endif + if (!p) + return -ENOMEM; + + r = sd_bus_new(&bus); + if (r < 0) { + free(p); + return r; + } + + bus->address = p; + bus->bus_client = true; + + r = sd_bus_start(bus); + if (r < 0) { + bus_free(bus); + return r; + } + + *ret = bus; + return 0; +} + +_public_ void sd_bus_close(sd_bus *bus) { + + if (!bus) + return; + if (bus->state == BUS_CLOSED) + return; + if (bus_pid_changed(bus)) + return; + + bus->state = BUS_CLOSED; + + sd_bus_detach_event(bus); + + /* Drop all queued messages so that they drop references to + * the bus object and the bus may be freed */ + bus_reset_queues(bus); + + if (!bus->is_kernel) + bus_close_fds(bus); + + /* We'll leave the fd open in case this is a kernel bus, since + * there might still be memblocks around that reference this + * bus, and they might need to invoke the KDBUS_CMD_FREE + * ioctl on the fd when they are freed. */ +} + +static void bus_enter_closing(sd_bus *bus) { + assert(bus); + + if (bus->state != BUS_OPENING && + bus->state != BUS_AUTHENTICATING && + bus->state != BUS_HELLO && + bus->state != BUS_RUNNING) + return; + + bus->state = BUS_CLOSING; +} + +_public_ sd_bus *sd_bus_ref(sd_bus *bus) { + assert_return(bus, NULL); + + assert_se(REFCNT_INC(bus->n_ref) >= 2); + + return bus; +} + +_public_ sd_bus *sd_bus_unref(sd_bus *bus) { + unsigned i; + + if (!bus) + return NULL; + + if (REFCNT_GET(bus->n_ref) == bus->rqueue_size + bus->wqueue_size + 1) { + bool q = true; + + for (i = 0; i < bus->rqueue_size; i++) + if (bus->rqueue[i]->n_ref > 1) { + q = false; + break; + } + + if (q) { + for (i = 0; i < bus->wqueue_size; i++) + if (bus->wqueue[i]->n_ref > 1) { + q = false; + break; + } + } + + /* We are the only holders on the messages, and the + * messages are the only holders on us, so let's drop + * the messages and thus implicitly also kill our own + * last references */ + + if (q) + bus_reset_queues(bus); + } + + i = REFCNT_DEC(bus->n_ref); + if (i > 0) + return NULL; + + bus_free(bus); + return NULL; +} + +_public_ int sd_bus_is_open(sd_bus *bus) { + + assert_return(bus, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + return BUS_IS_OPEN(bus->state); +} + +_public_ int sd_bus_can_send(sd_bus *bus, char type) { + int r; + + assert_return(bus, -EINVAL); + assert_return(bus->state != BUS_UNSET, -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (type == SD_BUS_TYPE_UNIX_FD) { + if (!(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) + return 0; + + r = bus_ensure_running(bus); + if (r < 0) + return r; + + return bus->can_fds; + } + + return bus_type_is_valid(type); +} + +_public_ int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) { + int r; + + assert_return(bus, -EINVAL); + assert_return(server_id, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = bus_ensure_running(bus); + if (r < 0) + return r; + + *server_id = bus->server_id; + return 0; +} + +static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) { + assert(b); + assert(m); + + if (m->sealed) { + /* If we copy the same message to multiple + * destinations, avoid using the same cookie + * numbers. */ + b->cookie = MAX(b->cookie, BUS_MESSAGE_COOKIE(m)); + return 0; + } + + if (timeout == 0) + timeout = BUS_DEFAULT_TIMEOUT; + + return bus_message_seal(m, ++b->cookie, timeout); +} + +static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) { + assert(b); + + /* Do packet version and endianess already match? */ + if ((b->message_version == 0 || b->message_version == (*m)->header->version) && + (b->message_endian == 0 || b->message_endian == (*m)->header->endian)) + return 0; + + /* No? Then remarshal! */ + return bus_message_remarshal(b, m); +} + +int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) { + assert(b); + assert(m); + + /* The bus specification says the serial number cannot be 0, + * hence let's fill something in for synthetic messages. Since + * synthetic messages might have a fake sender and we don't + * want to interfere with the real sender's serial numbers we + * pick a fixed, artifical one. We use (uint32_t) -1 rather + * than (uint64_t) -1 since dbus1 only had 32bit identifiers, + * even though kdbus can do 64bit. */ + + return bus_message_seal(m, 0xFFFFFFFFULL, 0); +} + +static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call, size_t *idx) { + int r; + + assert(bus); + assert(m); + + if (bus->is_kernel) + r = bus_kernel_write_message(bus, m, hint_sync_call); + else + r = bus_socket_write_message(bus, m, idx); + + if (r <= 0) + return r; + + if (bus->is_kernel || *idx >= BUS_MESSAGE_SIZE(m)) + log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s", + bus_message_type_to_string(m->header->type), + strna(sd_bus_message_get_sender(m)), + strna(sd_bus_message_get_destination(m)), + strna(sd_bus_message_get_path(m)), + strna(sd_bus_message_get_interface(m)), + strna(sd_bus_message_get_member(m)), + (unsigned long) BUS_MESSAGE_COOKIE(m), + (unsigned long) m->reply_cookie, + strna(m->error.message)); + + return r; +} + +static int dispatch_wqueue(sd_bus *bus) { + int r, ret = 0; + + assert(bus); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + while (bus->wqueue_size > 0) { + + r = bus_write_message(bus, bus->wqueue[0], false, &bus->windex); + if (r < 0) + return r; + else if (r == 0) + /* Didn't do anything this time */ + return ret; + else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) { + /* Fully written. Let's drop the entry from + * the queue. + * + * This isn't particularly optimized, but + * well, this is supposed to be our worst-case + * buffer only, and the socket buffer is + * supposed to be our primary buffer, and if + * it got full, then all bets are off + * anyway. */ + + bus->wqueue_size --; + sd_bus_message_unref(bus->wqueue[0]); + memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size); + bus->windex = 0; + + ret = 1; + } + } + + return ret; +} + +static int bus_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { + assert(bus); + + if (bus->is_kernel) + return bus_kernel_read_message(bus, hint_priority, priority); + else + return bus_socket_read_message(bus); +} + +int bus_rqueue_make_room(sd_bus *bus) { + assert(bus); + + if (bus->rqueue_size >= BUS_RQUEUE_MAX) + return -ENOBUFS; + + if (!GREEDY_REALLOC(bus->rqueue, bus->rqueue_allocated, bus->rqueue_size + 1)) + return -ENOMEM; + + return 0; +} + +static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **m) { + int r, ret = 0; + + assert(bus); + assert(m); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + /* Note that the priority logic is only available on kdbus, + * where the rqueue is unused. We check the rqueue here + * anyway, because it's simple... */ + + 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); + return 1; + } + + /* Try to read a new message */ + r = bus_read_message(bus, hint_priority, priority); + if (r < 0) + return r; + if (r == 0) + return ret; + + ret = 1; + } +} + +static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) { + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(m, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (m->n_fds > 0) { + r = sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD); + if (r < 0) + return r; + if (r == 0) + return -ENOTSUP; + } + + /* If the cookie number isn't kept, then we know that no reply + * is expected */ + if (!cookie && !m->sealed) + m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + + r = bus_seal_message(bus, m, 0); + if (r < 0) + return r; + + /* Remarshall if we have to. This will possibly unref the + * message and place a replacement in m */ + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + + /* If this is a reply and no reply was requested, then let's + * suppress this, if we can */ + if (m->dont_send && !cookie) + return 1; + + if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) { + size_t idx = 0; + + r = bus_write_message(bus, m, hint_sync_call, &idx); + if (r < 0) { + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + return -ECONNRESET; + } + + return r; + } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) { + /* Wasn't fully written. So let's remember how + * much was written. Note that the first entry + * 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_size = 1; + bus->windex = idx; + } + } else { + /* Just append it to the queue. */ + + if (bus->wqueue_size >= BUS_WQUEUE_MAX) + return -ENOBUFS; + + if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1)) + return -ENOMEM; + + bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m); + } + + if (cookie) + *cookie = BUS_MESSAGE_COOKIE(m); + + return 1; +} + +_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) { + return bus_send_internal(bus, m, cookie, false); +} + +_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) { + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(m, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (!streq_ptr(m->destination, destination)) { + + if (!destination) + return -EEXIST; + + r = sd_bus_message_set_destination(m, destination); + if (r < 0) + return r; + } + + return sd_bus_send(bus, m, cookie); +} + +static usec_t calc_elapse(uint64_t usec) { + if (usec == (uint64_t) -1) + return 0; + + return now(CLOCK_MONOTONIC) + usec; +} + +static int timeout_compare(const void *a, const void *b) { + const struct reply_callback *x = a, *y = b; + + if (x->timeout != 0 && y->timeout == 0) + return -1; + + if (x->timeout == 0 && y->timeout != 0) + return 1; + + if (x->timeout < y->timeout) + return -1; + + if (x->timeout > y->timeout) + return 1; + + return 0; +} + +_public_ int sd_bus_call_async( + sd_bus *bus, + sd_bus_message *_m, + sd_bus_message_handler_t callback, + void *userdata, + uint64_t usec, + uint64_t *cookie) { + + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + struct reply_callback *c; + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(m, -EINVAL); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = hashmap_ensure_allocated(&bus->reply_callbacks, uint64_hash_func, uint64_compare_func); + if (r < 0) + return r; + + r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare); + if (r < 0) + return r; + + r = bus_seal_message(bus, m, usec); + if (r < 0) + return r; + + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + + c = new0(struct reply_callback, 1); + if (!c) + return -ENOMEM; + + c->callback = callback; + c->userdata = userdata; + c->cookie = BUS_MESSAGE_COOKIE(m); + c->timeout = calc_elapse(m->timeout); + + r = hashmap_put(bus->reply_callbacks, &c->cookie, c); + if (r < 0) { + free(c); + return r; + } + + if (c->timeout != 0) { + r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx); + if (r < 0) { + c->timeout = 0; + sd_bus_call_async_cancel(bus, c->cookie); + return r; + } + } + + r = sd_bus_send(bus, m, cookie); + if (r < 0) { + sd_bus_call_async_cancel(bus, c->cookie); + return r; + } + + return r; +} + +_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) { + struct reply_callback *c; + + assert_return(bus, -EINVAL); + assert_return(cookie != 0, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + c = hashmap_remove(bus->reply_callbacks, &cookie); + if (!c) + return 0; + + if (c->timeout != 0) + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + + free(c); + return 1; +} + +int bus_ensure_running(sd_bus *bus) { + int r; + + assert(bus); + + if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING) + return -ENOTCONN; + if (bus->state == BUS_RUNNING) + return 1; + + for (;;) { + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + if (bus->state == BUS_RUNNING) + return 1; + if (r > 0) + continue; + + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) + return r; + } +} + +_public_ int sd_bus_call( + sd_bus *bus, + sd_bus_message *_m, + uint64_t usec, + sd_bus_error *error, + sd_bus_message **reply) { + + _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + usec_t timeout; + uint64_t cookie; + unsigned i; + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(m, -EINVAL); + assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); + assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); + assert_return(!bus_error_is_dirty(error), -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = bus_ensure_running(bus); + if (r < 0) + return r; + + i = bus->rqueue_size; + + r = bus_seal_message(bus, m, usec); + if (r < 0) + return r; + + r = bus_remarshal_message(bus, &m); + if (r < 0) + return r; + + r = bus_send_internal(bus, m, &cookie, true); + if (r < 0) + return r; + + timeout = calc_elapse(m->timeout); + + for (;;) { + usec_t left; + + while (i < bus->rqueue_size) { + sd_bus_message *incoming = NULL; + + incoming = 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--; + + if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) { + + if (reply) + *reply = incoming; + else + sd_bus_message_unref(incoming); + + return 1; + } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) + r = sd_bus_error_copy(error, &incoming->error); + else + r = -EIO; + + sd_bus_message_unref(incoming); + return r; + + } else if (BUS_MESSAGE_COOKIE(incoming) == cookie && + bus->unique_name && + 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--; + + /* 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); + return -ELOOP; + } + + /* Try to read more, right-away */ + i++; + } + + r = bus_read_message(bus, false, 0); + if (r < 0) { + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + return -ECONNRESET; + } + + return r; + } + if (r > 0) + continue; + + if (timeout > 0) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + if (n >= timeout) + return -ETIMEDOUT; + + left = timeout - n; + } else + left = (uint64_t) -1; + + r = bus_poll(bus, true, left); + if (r < 0) + return r; + if (r == 0) + return -ETIMEDOUT; + + r = dispatch_wqueue(bus); + if (r < 0) { + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + return -ECONNRESET; + } + + return r; + } + } +} + +_public_ int sd_bus_get_fd(sd_bus *bus) { + + assert_return(bus, -EINVAL); + assert_return(bus->input_fd == bus->output_fd, -EPERM); + assert_return(!bus_pid_changed(bus), -ECHILD); + + return bus->input_fd; +} + +_public_ int sd_bus_get_events(sd_bus *bus) { + int flags = 0; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (bus->state == BUS_OPENING) + flags |= POLLOUT; + else if (bus->state == BUS_AUTHENTICATING) { + + if (bus_socket_auth_needs_write(bus)) + flags |= POLLOUT; + + flags |= POLLIN; + + } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) { + if (bus->rqueue_size <= 0) + flags |= POLLIN; + if (bus->wqueue_size > 0) + flags |= POLLOUT; + } + + return flags; +} + +_public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { + struct reply_callback *c; + + assert_return(bus, -EINVAL); + assert_return(timeout_usec, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (bus->state == BUS_CLOSING) { + *timeout_usec = 0; + return 1; + } + + if (bus->state == BUS_AUTHENTICATING) { + *timeout_usec = bus->auth_timeout; + return 1; + } + + if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + if (bus->rqueue_size > 0) { + *timeout_usec = 0; + return 1; + } + + c = prioq_peek(bus->reply_callbacks_prioq); + if (!c) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + *timeout_usec = c->timeout; + return 1; +} + +static int process_timeout(sd_bus *bus) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message* m = NULL; + struct reply_callback *c; + usec_t n; + int r; + + assert(bus); + + c = prioq_peek(bus->reply_callbacks_prioq); + if (!c) + return 0; + + n = now(CLOCK_MONOTONIC); + if (c->timeout > n) + return 0; + + r = bus_message_new_synthetic_error( + bus, + c->cookie, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out"), + &m); + if (r < 0) + return r; + + m->sender = "org.freedesktop.DBus"; + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + assert_se(prioq_pop(bus->reply_callbacks_prioq) == c); + hashmap_remove(bus->reply_callbacks, &c->cookie); + + bus->current = m; + bus->iteration_counter ++; + + r = c->callback(bus, m, c->userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + free(c); + + bus->current = NULL; + + return r; +} + +static int process_hello(sd_bus *bus, sd_bus_message *m) { + assert(bus); + assert(m); + + if (bus->state != BUS_HELLO) + return 0; + + /* Let's make sure the first message on the bus is the HELLO + * reply. But note that we don't actually parse the message + * here (we leave that to the usual handling), we just verify + * we don't let any earlier msg through. */ + + if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + return -EIO; + + if (m->reply_cookie != bus->hello_cookie) + return -EIO; + + return 0; +} + +static int process_reply(sd_bus *bus, sd_bus_message *m) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + struct reply_callback *c; + int r; + + assert(bus); + assert(m); + + if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_METHOD_ERROR) + return 0; + + c = hashmap_remove(bus->reply_callbacks, &m->reply_cookie); + if (!c) + return 0; + + if (c->timeout != 0) + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + r = c->callback(bus, m, c->userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + free(c); + + return r; +} + +static int process_filter(sd_bus *bus, sd_bus_message *m) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + struct filter_callback *l; + int r; + + assert(bus); + assert(m); + + do { + bus->filter_callbacks_modified = false; + + LIST_FOREACH(callbacks, l, bus->filter_callbacks) { + + if (bus->filter_callbacks_modified) + break; + + /* Don't run this more than once per iteration */ + if (l->last_iteration == bus->iteration_counter) + continue; + + l->last_iteration = bus->iteration_counter; + + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + r = l->callback(bus, m, l->userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + if (r != 0) + return r; + + } + + } while (bus->filter_callbacks_modified); + + return 0; +} + +static int process_match(sd_bus *bus, sd_bus_message *m) { + int r; + + assert(bus); + assert(m); + + do { + bus->match_callbacks_modified = false; + + r = bus_match_run(bus, &bus->match_callbacks, m); + if (r != 0) + return r; + + } while (bus->match_callbacks_modified); + + return 0; +} + +static int process_builtin(sd_bus *bus, sd_bus_message *m) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(bus); + assert(m); + + if (bus->manual_peer_interface) + return 0; + + if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL) + return 0; + + if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer")) + return 0; + + if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) + return 1; + + if (streq_ptr(m->member, "Ping")) + r = sd_bus_message_new_method_return(m, &reply); + else if (streq_ptr(m->member, "GetMachineId")) { + sd_id128_t id; + char sid[33]; + + r = sd_id128_get_machine(&id); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid)); + } else { + r = sd_bus_message_new_method_errorf( + m, &reply, + SD_BUS_ERROR_UNKNOWN_METHOD, + "Unknown method '%s' on interface '%s'.", m->member, m->interface); + } + + if (r < 0) + return r; + + r = sd_bus_send(bus, reply, NULL); + if (r < 0) + return r; + + return 1; +} + +static int process_message(sd_bus *bus, sd_bus_message *m) { + int r; + + assert(bus); + assert(m); + + bus->current = m; + bus->iteration_counter++; + + log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s", + bus_message_type_to_string(m->header->type), + strna(sd_bus_message_get_sender(m)), + strna(sd_bus_message_get_destination(m)), + strna(sd_bus_message_get_path(m)), + strna(sd_bus_message_get_interface(m)), + strna(sd_bus_message_get_member(m)), + (unsigned long) BUS_MESSAGE_COOKIE(m), + (unsigned long) m->reply_cookie, + strna(m->error.message)); + + r = process_hello(bus, m); + if (r != 0) + goto finish; + + r = process_reply(bus, m); + if (r != 0) + goto finish; + + r = process_filter(bus, m); + if (r != 0) + goto finish; + + r = process_match(bus, m); + if (r != 0) + goto finish; + + r = process_builtin(bus, m); + if (r != 0) + goto finish; + + r = bus_process_object(bus, m); + +finish: + bus->current = NULL; + return r; +} + +static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); + + r = process_timeout(bus); + if (r != 0) + goto null_message; + + r = dispatch_wqueue(bus); + if (r != 0) + goto null_message; + + r = dispatch_rqueue(bus, hint_priority, priority, &m); + if (r < 0) + return r; + if (!m) + goto null_message; + + r = process_message(bus, m); + if (r != 0) + goto null_message; + + if (ret) { + r = sd_bus_message_rewind(m, true); + if (r < 0) + return r; + + *ret = m; + m = NULL; + return 1; + } + + if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) { + + log_debug("Unprocessed message call sender=%s object=%s interface=%s member=%s", + strna(sd_bus_message_get_sender(m)), + strna(sd_bus_message_get_path(m)), + strna(sd_bus_message_get_interface(m)), + strna(sd_bus_message_get_member(m))); + + r = sd_bus_reply_method_errorf( + m, + SD_BUS_ERROR_UNKNOWN_OBJECT, + "Unknown object '%s'.", m->path); + if (r < 0) + return r; + } + + return 1; + +null_message: + if (r >= 0 && ret) + *ret = NULL; + + return r; +} + +static int process_closing(sd_bus *bus, sd_bus_message **ret) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + struct reply_callback *c; + int r; + + assert(bus); + assert(bus->state == BUS_CLOSING); + + c = hashmap_first(bus->reply_callbacks); + if (c) { + _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + + /* First, fail all outstanding method calls */ + r = bus_message_new_synthetic_error( + bus, + c->cookie, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), + &m); + if (r < 0) + return r; + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + if (c->timeout != 0) + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + + hashmap_remove(bus->reply_callbacks, &c->cookie); + + bus->current = m; + bus->iteration_counter++; + + r = c->callback(bus, m, c->userdata, &error_buffer); + r = bus_maybe_reply_error(m, r, &error_buffer); + free(c); + + goto finish; + } + + /* Then, synthesize a Disconnected message */ + r = sd_bus_message_new_signal( + bus, + &m, + "/org/freedesktop/DBus/Local", + "org.freedesktop.DBus.Local", + "Disconnected"); + if (r < 0) + return r; + + m->sender = "org.freedesktop.DBus.Local"; + + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; + + sd_bus_close(bus); + + bus->current = m; + bus->iteration_counter++; + + r = process_filter(bus, m); + if (r != 0) + goto finish; + + r = process_match(bus, m); + if (r != 0) + goto finish; + + if (ret) { + *ret = m; + m = NULL; + } + + r = 1; + +finish: + bus->current = NULL; + return r; +} + +static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) { + BUS_DONT_DESTROY(bus); + int r; + + /* Returns 0 when we didn't do anything. This should cause the + * caller to invoke sd_bus_wait() before returning the next + * time. Returns > 0 when we did something, which possibly + * means *ret is filled in with an unprocessed message. */ + + assert_return(bus, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + /* We don't allow recursively invoking sd_bus_process(). */ + assert_return(!bus->current, -EBUSY); + + switch (bus->state) { + + case BUS_UNSET: + return -ENOTCONN; + + case BUS_CLOSED: + return -ECONNRESET; + + case BUS_OPENING: + r = bus_socket_process_opening(bus); + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + r = 1; + } else if (r < 0) + return r; + if (ret) + *ret = NULL; + return r; + + case BUS_AUTHENTICATING: + r = bus_socket_process_authenticating(bus); + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + r = 1; + } else if (r < 0) + return r; + + if (ret) + *ret = NULL; + + return r; + + case BUS_RUNNING: + case BUS_HELLO: + r = process_running(bus, hint_priority, priority, ret); + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + r = 1; + + if (ret) + *ret = NULL; + } + + return r; + + case BUS_CLOSING: + return process_closing(bus, ret); + } + + assert_not_reached("Unknown state"); +} + +_public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { + return bus_process_internal(bus, false, 0, ret); +} + +_public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_message **ret) { + return bus_process_internal(bus, true, priority, ret); +} + +static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { + struct pollfd p[2] = {}; + int r, e, n; + struct timespec ts; + usec_t m = (usec_t) -1; + + assert(bus); + + if (bus->state == BUS_CLOSING) + return 1; + + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + + e = sd_bus_get_events(bus); + if (e < 0) + return e; + + if (need_more) + /* The caller really needs some more data, he doesn't + * care about what's already read, or any timeouts + * except its own.*/ + e |= POLLIN; + else { + usec_t until; + /* The caller wants to process if there's something to + * process, but doesn't care otherwise */ + + r = sd_bus_get_timeout(bus, &until); + if (r < 0) + return r; + if (r > 0) { + usec_t nw; + nw = now(CLOCK_MONOTONIC); + m = until > nw ? until - nw : 0; + } + } + + if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) + m = timeout_usec; + + p[0].fd = bus->input_fd; + if (bus->output_fd == bus->input_fd) { + p[0].events = e; + n = 1; + } else { + p[0].events = e & POLLIN; + p[1].fd = bus->output_fd; + p[1].events = e & POLLOUT; + n = 2; + } + + r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); + if (r < 0) + return -errno; + + return r > 0 ? 1 : 0; +} + +_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { + + assert_return(bus, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (bus->state == BUS_CLOSING) + return 0; + + assert_return(BUS_IS_OPEN(bus->state) , -ENOTCONN); + + if (bus->rqueue_size > 0) + return 0; + + return bus_poll(bus, false, timeout_usec); +} + +_public_ int sd_bus_flush(sd_bus *bus) { + int r; + + assert_return(bus, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + if (bus->state == BUS_CLOSING) + return 0; + + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + + r = bus_ensure_running(bus); + if (r < 0) + return r; + + if (bus->wqueue_size <= 0) + return 0; + + for (;;) { + r = dispatch_wqueue(bus); + if (r < 0) { + if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + bus_enter_closing(bus); + return -ECONNRESET; + } + + return r; + } + + if (bus->wqueue_size <= 0) + return 0; + + r = bus_poll(bus, false, (uint64_t) -1); + if (r < 0) + return r; + } +} + +_public_ int sd_bus_add_filter(sd_bus *bus, + sd_bus_message_handler_t callback, + void *userdata) { + + struct filter_callback *f; + + assert_return(bus, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + f = new0(struct filter_callback, 1); + if (!f) + return -ENOMEM; + f->callback = callback; + f->userdata = userdata; + + bus->filter_callbacks_modified = true; + LIST_PREPEND(callbacks, bus->filter_callbacks, f); + return 0; +} + +_public_ int sd_bus_remove_filter(sd_bus *bus, + sd_bus_message_handler_t callback, + void *userdata) { + + struct filter_callback *f; + + assert_return(bus, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + LIST_FOREACH(callbacks, f, bus->filter_callbacks) { + if (f->callback == callback && f->userdata == userdata) { + bus->filter_callbacks_modified = true; + LIST_REMOVE(callbacks, bus->filter_callbacks, f); + free(f); + return 1; + } + } + + return 0; +} + +_public_ int sd_bus_add_match(sd_bus *bus, + const char *match, + sd_bus_message_handler_t callback, + void *userdata) { + + struct bus_match_component *components = NULL; + unsigned n_components = 0; + uint64_t cookie = 0; + int r = 0; + + assert_return(bus, -EINVAL); + assert_return(match, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = bus_match_parse(match, &components, &n_components); + if (r < 0) + goto finish; + + if (bus->bus_client) { + cookie = ++bus->match_cookie; + + r = bus_add_match_internal(bus, match, components, n_components, cookie); + if (r < 0) + goto finish; + } + + bus->match_callbacks_modified = true; + r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL); + if (r < 0) { + if (bus->bus_client) + bus_remove_match_internal(bus, match, cookie); + } + +finish: + bus_match_parse_free(components, n_components); + return r; +} + +_public_ int sd_bus_remove_match(sd_bus *bus, + const char *match, + sd_bus_message_handler_t callback, + void *userdata) { + + struct bus_match_component *components = NULL; + unsigned n_components = 0; + int r = 0, q = 0; + uint64_t cookie = 0; + + assert_return(bus, -EINVAL); + assert_return(match, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + r = bus_match_parse(match, &components, &n_components); + if (r < 0) + return r; + + bus->match_callbacks_modified = true; + r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie); + + if (bus->bus_client) + q = bus_remove_match_internal(bus, match, cookie); + + bus_match_parse_free(components, n_components); + + return r < 0 ? r : q; +} + +bool bus_pid_changed(sd_bus *bus) { + assert(bus); + + /* We don't support people creating a bus connection and + * keeping it around over a fork(). Let's complain. */ + + return bus->original_pid != getpid(); +} + +static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + sd_bus *bus = userdata; + int r; + + assert(bus); + + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + + return 1; +} + +static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { + sd_bus *bus = userdata; + int r; + + assert(bus); + + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + + return 1; +} + +static int prepare_callback(sd_event_source *s, void *userdata) { + sd_bus *bus = userdata; + int r, e; + usec_t until; + + assert(s); + assert(bus); + + e = sd_bus_get_events(bus); + if (e < 0) + return e; + + if (bus->output_fd != bus->input_fd) { + + r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN); + if (r < 0) + return r; + + r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT); + if (r < 0) + return r; + } else { + r = sd_event_source_set_io_events(bus->input_io_event_source, e); + if (r < 0) + return r; + } + + r = sd_bus_get_timeout(bus, &until); + if (r < 0) + return r; + if (r > 0) { + int j; + + j = sd_event_source_set_time(bus->time_event_source, until); + if (j < 0) + return j; + } + + r = sd_event_source_set_enabled(bus->time_event_source, r > 0); + if (r < 0) + return r; + + return 1; +} + +static int quit_callback(sd_event_source *event, void *userdata) { + sd_bus *bus = userdata; + + assert(event); + + sd_bus_flush(bus); + + return 1; +} + +static int attach_io_events(sd_bus *bus) { + int r; + + assert(bus); + + if (bus->input_fd < 0) + return 0; + + if (!bus->event) + return 0; + + if (!bus->input_io_event_source) { + r = sd_event_add_io(bus->event, &bus->input_io_event_source, bus->input_fd, 0, io_callback, bus); + if (r < 0) + return r; + + r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback); + if (r < 0) + return r; + + r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority); + } else + r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd); + + if (r < 0) + return r; + + if (bus->output_fd != bus->input_fd) { + assert(bus->output_fd >= 0); + + if (!bus->output_io_event_source) { + r = sd_event_add_io(bus->event, &bus->output_io_event_source, bus->output_fd, 0, io_callback, bus); + if (r < 0) + return r; + + r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority); + } else + r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd); + + if (r < 0) + return r; + } + + return 0; +} + +static void detach_io_events(sd_bus *bus) { + assert(bus); + + if (bus->input_io_event_source) { + sd_event_source_set_enabled(bus->input_io_event_source, SD_EVENT_OFF); + bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source); + } + + if (bus->output_io_event_source) { + sd_event_source_set_enabled(bus->output_io_event_source, SD_EVENT_OFF); + bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source); + } +} + +_public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) { + int r; + + assert_return(bus, -EINVAL); + assert_return(!bus->event, -EBUSY); + + assert(!bus->input_io_event_source); + assert(!bus->output_io_event_source); + assert(!bus->time_event_source); + + if (event) + bus->event = sd_event_ref(event); + else { + r = sd_event_default(&bus->event); + if (r < 0) + return r; + } + + bus->event_priority = priority; + + r = sd_event_add_monotonic(bus->event, &bus->time_event_source, 0, 0, time_callback, bus); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(bus->time_event_source, priority); + if (r < 0) + goto fail; + + r = sd_event_add_exit(bus->event, &bus->quit_event_source, quit_callback, bus); + if (r < 0) + goto fail; + + r = attach_io_events(bus); + if (r < 0) + goto fail; + + return 0; + +fail: + sd_bus_detach_event(bus); + return r; +} + +_public_ int sd_bus_detach_event(sd_bus *bus) { + assert_return(bus, -EINVAL); + + if (!bus->event) + return 0; + + detach_io_events(bus); + + if (bus->time_event_source) { + sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF); + bus->time_event_source = sd_event_source_unref(bus->time_event_source); + } + + if (bus->quit_event_source) { + sd_event_source_set_enabled(bus->quit_event_source, SD_EVENT_OFF); + bus->quit_event_source = sd_event_source_unref(bus->quit_event_source); + } + + if (bus->event) + bus->event = sd_event_unref(bus->event); + + return 1; +} + +_public_ sd_event* sd_bus_get_event(sd_bus *bus) { + assert_return(bus, NULL); + + return bus->event; +} + +_public_ sd_bus_message* sd_bus_get_current(sd_bus *bus) { + assert_return(bus, NULL); + + return bus->current; +} + +static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) { + sd_bus *b = NULL; + int r; + + assert(bus_open); + assert(default_bus); + + if (!ret) + return !!*default_bus; + + if (*default_bus) { + *ret = sd_bus_ref(*default_bus); + return 0; + } + + r = bus_open(&b); + if (r < 0) + return r; + + b->default_bus_ptr = default_bus; + b->tid = gettid(); + *default_bus = b; + + *ret = b; + return 1; +} + +_public_ int sd_bus_default_system(sd_bus **ret) { + static thread_local sd_bus *default_system_bus = NULL; + + return bus_default(sd_bus_open_system, &default_system_bus, ret); +} + +_public_ int sd_bus_default_user(sd_bus **ret) { + static thread_local sd_bus *default_user_bus = NULL; + + return bus_default(sd_bus_open_user, &default_user_bus, ret); +} + +_public_ int sd_bus_default(sd_bus **ret) { + + const char *e; + + /* Let's try our best to reuse another cached connection. If + * the starter bus type is set, connect via our normal + * connection logic, ignoring $DBUS_STARTER_ADDRESS, so that + * we can share the connection with the user/system default + * bus. */ + + e = secure_getenv("DBUS_STARTER_BUS_TYPE"); + if (e) { + if (streq(e, "system")) + return sd_bus_default_system(ret); + else if (streq(e, "user") || streq(e, "session")) + return sd_bus_default_user(ret); + } + + /* No type is specified, so we have not other option than to + * use the starter address if it is set. */ + + e = secure_getenv("DBUS_STARTER_ADDRESS"); + if (e) { + static thread_local sd_bus *default_starter_bus = NULL; + + return bus_default(sd_bus_open, &default_starter_bus, ret); + } + + /* Finally, if nothing is set use the cached connection for + * the right scope */ + + if (cg_pid_get_owner_uid(0, NULL) >= 0) + return sd_bus_default_user(ret); + else + return sd_bus_default_system(ret); +} + +_public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) { + assert_return(b, -EINVAL); + assert_return(tid, -EINVAL); + assert_return(!bus_pid_changed(b), -ECHILD); + + if (b->tid != 0) { + *tid = b->tid; + return 0; + } + + if (b->event) + return sd_event_get_tid(b->event, tid); + + return -ENXIO; +} + +_public_ char *sd_bus_label_escape(const char *s) { + return bus_label_escape(s); +} + +_public_ char *sd_bus_label_unescape(const char *f) { + return bus_label_unescape(f); +} + +_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { + sd_bus_creds *c; + pid_t pid = 0; + int r; + + assert_return(bus, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP); + assert_return(ret, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus->is_kernel, -ENOTSUP); + + if (!bus->ucred_valid && !isempty(bus->label)) + return -ENODATA; + + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + if (bus->ucred_valid) { + pid = c->pid = bus->ucred.pid; + c->uid = bus->ucred.uid; + c->gid = bus->ucred.gid; + + c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask; + } + + if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) { + c->label = strdup(bus->label); + if (!c->label) { + sd_bus_creds_unref(c); + return -ENOMEM; + } + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + + r = bus_creds_add_more(c, mask, pid, 0); + if (r < 0) + return r; + + *ret = c; + return 0; +} + +_public_ int sd_bus_try_close(sd_bus *bus) { + int r; + + assert_return(bus, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(bus->is_kernel, -ENOTSUP); + + if (bus->rqueue_size > 0) + return -EBUSY; + + if (bus->wqueue_size > 0) + return -EBUSY; + + r = bus_kernel_try_close(bus); + if (r < 0) + return r; + + sd_bus_close(bus); + return 0; +} + +_public_ int sd_bus_get_name(sd_bus *bus, const char **name) { + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(!bus_pid_changed(bus), -ECHILD); + + *name = bus->connection_name; + return 0; +} diff --git a/src/libsystemd/sd-bus/sd-memfd.c b/src/libsystemd/sd-bus/sd-memfd.c new file mode 100644 index 0000000..7c71476 --- /dev/null +++ b/src/libsystemd/sd-bus/sd-memfd.c @@ -0,0 +1,321 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "kdbus.h" + +#include "sd-memfd.h" +#include "sd-bus.h" + +struct sd_memfd { + int fd; + FILE *f; +}; + +_public_ int sd_memfd_new(sd_memfd **m, const char *name) { + + struct kdbus_cmd_memfd_make *cmd; + struct kdbus_item *item; + _cleanup_close_ int kdbus = -1; + _cleanup_free_ char *g = NULL; + size_t sz, l; + sd_memfd *n; + + assert_return(m, -EINVAL); + + kdbus = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (kdbus < 0) + return -errno; + + if (name) { + /* The kernel side is pretty picky about the character + * set here, let's do the usual bus escaping to deal + * with that. */ + + g = sd_bus_label_escape(name); + if (!g) + return -ENOMEM; + + name = g; + + } else { + char pr[17] = {}; + + /* If no name is specified we generate one. We include + * a hint indicating our library implementation, and + * add the thread name to it */ + + assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0); + + if (isempty(pr)) + name = "sd"; + else { + _cleanup_free_ char *e = NULL; + + e = sd_bus_label_escape(pr); + if (!e) + return -ENOMEM; + + g = strappend("sd-", e); + if (!g) + return -ENOMEM; + + name = g; + } + } + + l = strlen(name); + sz = ALIGN8(offsetof(struct kdbus_cmd_memfd_make, items)) + + ALIGN8(offsetof(struct kdbus_item, str)) + + l + 1; + + cmd = alloca0(sz); + cmd->size = sz; + + item = cmd->items; + item->size = ALIGN8(offsetof(struct kdbus_item, str)) + l + 1; + item->type = KDBUS_ITEM_MEMFD_NAME; + memcpy(item->str, name, l + 1); + + if (ioctl(kdbus, KDBUS_CMD_MEMFD_NEW, cmd) < 0) + return -errno; + + n = new0(struct sd_memfd, 1); + if (!n) { + close_nointr_nofail(cmd->fd); + return -ENOMEM; + } + + n->fd = cmd->fd; + *m = n; + return 0; +} + +_public_ int sd_memfd_new_from_fd(sd_memfd **m, int fd) { + sd_memfd *n; + uint64_t sz; + + assert_return(m, -EINVAL); + assert_return(fd >= 0, -EINVAL); + + /* Check if this is a valid memfd */ + if (ioctl(fd, KDBUS_CMD_MEMFD_SIZE_GET, &sz) < 0) + return -ENOTTY; + + n = new0(struct sd_memfd, 1); + if (!n) + return -ENOMEM; + + n->fd = fd; + *m = n; + + return 0; +} + +_public_ void sd_memfd_free(sd_memfd *m) { + if (!m) + return; + + if (m->f) + fclose(m->f); + else + close_nointr_nofail(m->fd); + + free(m); +} + +_public_ int sd_memfd_get_fd(sd_memfd *m) { + assert_return(m, -EINVAL); + + return m->fd; +} + +_public_ int sd_memfd_get_file(sd_memfd *m, FILE **f) { + assert_return(m, -EINVAL); + assert_return(f, -EINVAL); + + if (!m->f) { + m->f = fdopen(m->fd, "r+"); + if (!m->f) + return -errno; + } + + *f = m->f; + return 0; +} + +_public_ int sd_memfd_dup_fd(sd_memfd *m) { + int fd; + + assert_return(m, -EINVAL); + + fd = fcntl(m->fd, F_DUPFD_CLOEXEC, 3); + if (fd < 0) + return -errno; + + return fd; +} + +_public_ int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p) { + void *q; + int sealed; + + assert_return(m, -EINVAL); + assert_return(size > 0, -EINVAL); + assert_return(p, -EINVAL); + + sealed = sd_memfd_get_sealed(m); + if (sealed < 0) + return sealed; + + q = mmap(NULL, size, sealed ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, offset); + if (q == MAP_FAILED) + return -errno; + + *p = q; + return 0; +} + +_public_ int sd_memfd_set_sealed(sd_memfd *m, int b) { + int r; + + assert_return(m, -EINVAL); + + r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_SET, b); + if (r < 0) + return -errno; + + return 0; +} + +_public_ int sd_memfd_get_sealed(sd_memfd *m) { + int r, b; + + assert_return(m, -EINVAL); + + r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_GET, &b); + if (r < 0) + return -errno; + + return !!b; +} + +_public_ int sd_memfd_get_size(sd_memfd *m, uint64_t *sz) { + int r; + + assert_return(m, -EINVAL); + assert_return(sz, -EINVAL); + + r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_GET, sz); + if (r < 0) + return -errno; + + return r; +} + +_public_ int sd_memfd_set_size(sd_memfd *m, uint64_t sz) { + int r; + + assert_return(m, -EINVAL); + + r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz); + if (r < 0) + return -errno; + + return r; +} + +_public_ int sd_memfd_new_and_map(sd_memfd **m, const char *name, size_t sz, void **p) { + sd_memfd *n; + int r; + + r = sd_memfd_new(&n, name); + if (r < 0) + return r; + + r = sd_memfd_set_size(n, sz); + if (r < 0) { + sd_memfd_free(n); + return r; + } + + r = sd_memfd_map(n, 0, sz, p); + if (r < 0) { + sd_memfd_free(n); + return r; + } + + *m = n; + return 0; +} + +_public_ int sd_memfd_get_name(sd_memfd *m, char **name) { + char path[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)], buf[FILENAME_MAX+1], *e; + const char *delim, *end; + _cleanup_free_ char *n = NULL; + ssize_t k; + + assert_return(m, -EINVAL); + assert_return(name, -EINVAL); + + sprintf(path, "/proc/self/fd/%i", m->fd); + + k = readlink(path, buf, sizeof(buf)); + if (k < 0) + return -errno; + + if ((size_t) k >= sizeof(buf)) + return -E2BIG; + + buf[k] = 0; + + delim = strstr(buf, ":["); + if (!delim) + return -EIO; + + delim = strchr(delim + 2, ':'); + if (!delim) + return -EIO; + + delim++; + + end = strchr(delim, ']'); + if (!end) + return -EIO; + + n = strndup(delim, end - delim); + if (!n) + return -ENOMEM; + + e = sd_bus_label_unescape(n); + if (!e) + return -ENOMEM; + + *name = e; + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c new file mode 100644 index 0000000..113d15b --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -0,0 +1,581 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "macro.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-match.h" +#include "bus-internal.h" +#include "bus-util.h" + +static int match_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m))); + return 0; +} + +static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + int r; + + assert(bus); + + if (sd_bus_message_is_method_error(m, NULL)) + return 0; + + if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) { + log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m)); + + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + return r; + } + + return 1; + } + + return 0; +} + +static int server_init(sd_bus **_bus) { + sd_bus *bus = NULL; + sd_id128_t id; + int r; + const char *unique; + + assert(_bus); + + r = sd_bus_open_user(&bus); + if (r < 0) { + log_error("Failed to connect to user bus: %s", strerror(-r)); + goto fail; + } + + r = sd_bus_get_server_id(bus, &id); + if (r < 0) { + log_error("Failed to get server ID: %s", strerror(-r)); + goto fail; + } + + r = sd_bus_get_unique_name(bus, &unique); + if (r < 0) { + log_error("Failed to get unique name: %s", strerror(-r)); + goto fail; + } + + log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id)); + log_info("Unique ID: %s", unique); + log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h')); + + r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0); + if (r < 0) { + log_error("Failed to acquire name: %s", strerror(-r)); + goto fail; + } + + r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL); + if (r < 0) { + log_error("Failed to add object: %s", strerror(-r)); + goto fail; + } + + r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + goto fail; + } + + r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + goto fail; + } + + bus_match_dump(&bus->match_callbacks, 0); + + *_bus = bus; + return 0; + +fail: + if (bus) + sd_bus_unref(bus); + + return r; +} + +static int server(sd_bus *bus) { + int r; + bool client1_gone = false, client2_gone = false; + + while (!client1_gone || !client2_gone) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + pid_t pid = 0; + const char *label = NULL; + + r = sd_bus_process(bus, &m); + if (r < 0) { + log_error("Failed to process requests: %s", strerror(-r)); + goto fail; + } + + if (r == 0) { + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) { + log_error("Failed to wait: %s", strerror(-r)); + goto fail; + } + + continue; + } + + if (!m) + continue; + + sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid); + sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label); + log_info("Got message! member=%s pid=%lu label=%s", + strna(sd_bus_message_get_member(m)), + (unsigned long) pid, + strna(label)); + /* bus_message_dump(m); */ + /* sd_bus_message_rewind(m, true); */ + + if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) { + const char *hello; + _cleanup_free_ char *lowercase = NULL; + + r = sd_bus_message_read(m, "s", &hello); + if (r < 0) { + log_error("Failed to get parameter: %s", strerror(-r)); + goto fail; + } + + lowercase = strdup(hello); + if (!lowercase) { + r = log_oom(); + goto fail; + } + + ascii_strlower(lowercase); + + r = sd_bus_reply_method_return(m, "s", lowercase); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) { + + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + + client1_gone = true; + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) { + + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + + client2_gone = true; + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) { + + sleep(1); + + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + + } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) { + int fd; + static const char x = 'X'; + + r = sd_bus_message_read(m, "h", &fd); + if (r < 0) { + log_error("Failed to get parameter: %s", strerror(-r)); + goto fail; + } + + log_info("Received fd=%d", fd); + + if (write(fd, &x, 1) < 0) { + log_error("Failed to write to fd: %m"); + close_nointr_nofail(fd); + goto fail; + } + + r = sd_bus_reply_method_return(m, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + + } else if (sd_bus_message_is_method_call(m, NULL, NULL)) { + + r = sd_bus_reply_method_error( + m, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method.")); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + } + } + + r = 0; + +fail: + if (bus) { + sd_bus_flush(bus); + sd_bus_unref(bus); + } + + return r; +} + +static void* client1(void*p) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + const char *hello; + int r; + int pp[2] = { -1, -1 }; + char x; + + r = sd_bus_open_user(&bus); + if (r < 0) { + log_error("Failed to connect to user bus: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "LowerCase", + &error, + &reply, + "s", + "HELLO"); + if (r < 0) { + log_error("Failed to issue method call: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_message_read(reply, "s", &hello); + if (r < 0) { + log_error("Failed to get string: %s", strerror(-r)); + goto finish; + } + + assert(streq(hello, "hello")); + + if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) { + log_error("Failed to allocate pipe: %m"); + r = -errno; + goto finish; + } + + log_info("Sending fd=%d", pp[1]); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "FileDescriptor", + &error, + NULL, + "h", + pp[1]); + if (r < 0) { + log_error("Failed to issue method call: %s", strerror(-r)); + goto finish; + } + + errno = 0; + if (read(pp[0], &x, 1) <= 0) { + log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read"); + goto finish; + } + + r = 0; + +finish: + if (bus) { + _cleanup_bus_message_unref_ sd_bus_message *q; + + r = sd_bus_message_new_method_call( + bus, + &q, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "ExitClient1"); + if (r < 0) + log_error("Failed to allocate method call: %s", strerror(-r)); + else + sd_bus_send(bus, q, NULL); + + sd_bus_flush(bus); + sd_bus_unref(bus); + } + + sd_bus_error_free(&error); + + close_pipe(pp); + + return INT_TO_PTR(r); +} + +static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + bool *x = userdata; + + log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m))); + + *x = 1; + return 1; +} + +static void* client2(void*p) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + bool quit = false; + const char *mid; + int r; + + r = sd_bus_open_user(&bus); + if (r < 0) { + log_error("Failed to connect to user bus: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd.test", + "/foo/bar/waldo/piep", + "org.object.test", + "Foobar"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_send(bus, m, NULL); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + goto finish; + } + + sd_bus_message_unref(m); + m = NULL; + + r = sd_bus_message_new_signal( + bus, + &m, + "/foobar", + "foo.bar", + "Notify"); + if (r < 0) { + log_error("Failed to allocate signal: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_send(bus, m, NULL); + if (r < 0) { + log_error("Failed to issue signal: %s", bus_error_message(&error, -r)); + goto finish; + } + + sd_bus_message_unref(m); + m = NULL; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.DBus.Peer", + "GetMachineId"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + goto finish; + } + + r = sd_bus_message_read(reply, "s", &mid); + if (r < 0) { + log_error("Failed to parse machine ID: %s", strerror(-r)); + goto finish; + } + + log_info("Machine ID is %s.", mid); + + sd_bus_message_unref(m); + m = NULL; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "Slow"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + goto finish; + } + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply); + if (r < 0) + log_info("Failed to issue method call: %s", bus_error_message(&error, -r)); + else + log_info("Slow call succeed."); + + sd_bus_message_unref(m); + m = NULL; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "Slow"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + goto finish; + } + + r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL); + if (r < 0) { + log_info("Failed to issue method call: %s", bus_error_message(&error, -r)); + goto finish; + } + + while (!quit) { + r = sd_bus_process(bus, NULL); + if (r < 0) { + log_error("Failed to process requests: %s", strerror(-r)); + goto finish; + } + if (r == 0) { + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) { + log_error("Failed to wait: %s", strerror(-r)); + goto finish; + } + } + } + + r = 0; + +finish: + if (bus) { + _cleanup_bus_message_unref_ sd_bus_message *q; + + r = sd_bus_message_new_method_call( + bus, + &q, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "ExitClient2"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + goto finish; + } + + sd_bus_send(bus, q, NULL); + sd_bus_flush(bus); + sd_bus_unref(bus); + } + + sd_bus_error_free(&error); + return INT_TO_PTR(r); +} + +int main(int argc, char *argv[]) { + pthread_t c1, c2; + sd_bus *bus; + void *p; + int q, r; + + r = server_init(&bus); + if (r < 0) { + log_info("Failed to connect to bus, skipping tests."); + return EXIT_TEST_SKIP; + } + + log_info("Initialized..."); + + r = pthread_create(&c1, NULL, client1, bus); + if (r != 0) + return EXIT_FAILURE; + + r = pthread_create(&c2, NULL, client2, bus); + if (r != 0) + return EXIT_FAILURE; + + r = server(bus); + + q = pthread_join(c1, &p); + if (q != 0) + return EXIT_FAILURE; + if (PTR_TO_INT(p) < 0) + return EXIT_FAILURE; + + q = pthread_join(c2, &p); + if (q != 0) + return EXIT_FAILURE; + if (PTR_TO_INT(p) < 0) + return EXIT_FAILURE; + + if (r < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c new file mode 100644 index 0000000..e36a69f --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -0,0 +1,80 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "refcnt.h" + +static void test_bus_new(void) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + + assert_se(sd_bus_new(&bus) == 0); + printf("after new: refcount %u\n", REFCNT_GET(bus->n_ref)); +} + +static void test_bus_open(void) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + + assert_se(sd_bus_open_system(&bus) >= 0); + printf("after open: refcount %u\n", REFCNT_GET(bus->n_ref)); +} + +static void test_bus_new_method_call(void) { + sd_bus *bus = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + assert_se(sd_bus_open_system(&bus) >= 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)); + + sd_bus_unref(bus); + printf("after bus_unref: refcount %u\n", m->n_ref); +} + +static void test_bus_new_signal(void) { + sd_bus *bus = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + assert_se(sd_bus_open_system(&bus) >= 0); + + 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)); + + sd_bus_unref(bus); + printf("after bus_unref: refcount %u\n", m->n_ref); +} + +int main(int argc, char **argv) { + log_parse_environment(); + log_open(); + + test_bus_new(); + test_bus_open(); + test_bus_new_method_call(); + test_bus_new_signal(); +} diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c new file mode 100644 index 0000000..c4894e8 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "bus-dump.h" +#include "bus-util.h" +#include "util.h" + +int main(int argc, char *argv[]) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + int r; + + r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL); + assert_se(r >= 0); + + bus_creds_dump(creds, NULL); + + creds = sd_bus_creds_unref(creds); + + r = sd_bus_creds_new_from_pid(&creds, 1, _SD_BUS_CREDS_ALL); + if (r != -EACCES) { + assert_se(r >= 0); + putchar('\n'); + bus_creds_dump(creds, NULL); + } + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c new file mode 100644 index 0000000..b78be54 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-bus.h" +#include "bus-error.h" +#include "bus-util.h" + +int main(int argc, char *argv[]) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; + const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error"); + const sd_bus_error temporarily_const_error = { + .name = SD_BUS_ERROR_ACCESS_DENIED, + .message = "oh! no", + ._need_free = -1 + }; + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -ENOTSUP); + assert_se(streq(error.name, SD_BUS_ERROR_NOT_SUPPORTED)); + assert_se(streq(error.message, "xxx")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_NOT_SUPPORTED)); + assert_se(sd_bus_error_get_errno(&error) == ENOTSUP); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT); + assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(streq(error.message, "yyy -1")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_get_errno(&error) == ENOENT); + assert_se(sd_bus_error_is_set(&error)); + + assert_se(!sd_bus_error_is_set(&second)); + assert_se(second._need_free == 0); + assert_se(error._need_free > 0); + assert_se(sd_bus_error_copy(&second, &error) == -ENOENT); + assert_se(second._need_free > 0); + assert_se(streq(error.name, second.name)); + assert_se(streq(error.message, second.message)); + assert_se(sd_bus_error_get_errno(&second) == ENOENT); + assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_is_set(&second)); + + sd_bus_error_free(&error); + sd_bus_error_free(&second); + + assert_se(!sd_bus_error_is_set(&second)); + assert_se(const_error._need_free == 0); + assert_se(sd_bus_error_copy(&second, &const_error) == -EEXIST); + assert_se(second._need_free == 0); + assert_se(streq(const_error.name, second.name)); + assert_se(streq(const_error.message, second.message)); + assert_se(sd_bus_error_get_errno(&second) == EEXIST); + assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_FILE_EXISTS)); + assert_se(sd_bus_error_is_set(&second)); + sd_bus_error_free(&second); + + assert_se(!sd_bus_error_is_set(&second)); + assert_se(temporarily_const_error._need_free < 0); + assert_se(sd_bus_error_copy(&second, &temporarily_const_error) == -EACCES); + assert_se(second._need_free > 0); + assert_se(streq(temporarily_const_error.name, second.name)); + assert_se(streq(temporarily_const_error.message, second.message)); + assert_se(sd_bus_error_get_errno(&second) == EACCES); + assert_se(sd_bus_error_has_name(&second, SD_BUS_ERROR_ACCESS_DENIED)); + assert_se(sd_bus_error_is_set(&second)); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_const(&error, "System.Error.EUCLEAN", "Hallo") == -EUCLEAN); + assert_se(streq(error.name, "System.Error.EUCLEAN")); + assert_se(streq(error.message, "Hallo")); + assert_se(sd_bus_error_has_name(&error, "System.Error.EUCLEAN")); + assert_se(sd_bus_error_get_errno(&error) == EUCLEAN); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errno(&error, EBUSY) == -EBUSY); + assert_se(streq(error.name, "System.Error.EBUSY")); + assert_se(streq(error.message, strerror(EBUSY))); + assert_se(sd_bus_error_has_name(&error, "System.Error.EBUSY")); + assert_se(sd_bus_error_get_errno(&error) == EBUSY); + assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errnof(&error, EIO, "Waldi %c", 'X') == -EIO); + assert_se(streq(error.name, SD_BUS_ERROR_IO_ERROR)); + assert_se(streq(error.message, "Waldi X")); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); + assert_se(sd_bus_error_get_errno(&error) == EIO); + assert_se(sd_bus_error_is_set(&error)); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c new file mode 100644 index 0000000..f2c1fc1 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -0,0 +1,201 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifdef HAVE_GLIB +#include +#endif + +#include "util.h" +#include "sd-bus.h" +#include "bus-gvariant.h" +#include "bus-util.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-dump.h" + +static void test_bus_gvariant_is_fixed_size(void) { + assert(bus_gvariant_is_fixed_size("") > 0); + assert(bus_gvariant_is_fixed_size("()") > 0); + assert(bus_gvariant_is_fixed_size("y") > 0); + assert(bus_gvariant_is_fixed_size("u") > 0); + assert(bus_gvariant_is_fixed_size("b") > 0); + assert(bus_gvariant_is_fixed_size("n") > 0); + assert(bus_gvariant_is_fixed_size("q") > 0); + assert(bus_gvariant_is_fixed_size("i") > 0); + assert(bus_gvariant_is_fixed_size("t") > 0); + assert(bus_gvariant_is_fixed_size("d") > 0); + assert(bus_gvariant_is_fixed_size("s") == 0); + assert(bus_gvariant_is_fixed_size("o") == 0); + assert(bus_gvariant_is_fixed_size("g") == 0); + assert(bus_gvariant_is_fixed_size("h") > 0); + assert(bus_gvariant_is_fixed_size("ay") == 0); + assert(bus_gvariant_is_fixed_size("v") == 0); + assert(bus_gvariant_is_fixed_size("(u)") > 0); + assert(bus_gvariant_is_fixed_size("(uuuuy)") > 0); + assert(bus_gvariant_is_fixed_size("(uusuuy)") == 0); + assert(bus_gvariant_is_fixed_size("a{ss}") == 0); + assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiii)))") > 0); + assert(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0); +} + +static void test_bus_gvariant_get_size(void) { + assert(bus_gvariant_get_size("") == 0); + assert(bus_gvariant_get_size("()") == 0); + assert(bus_gvariant_get_size("y") == 1); + assert(bus_gvariant_get_size("u") == 4); + assert(bus_gvariant_get_size("b") == 1); + assert(bus_gvariant_get_size("n") == 2); + assert(bus_gvariant_get_size("q") == 2); + assert(bus_gvariant_get_size("i") == 4); + assert(bus_gvariant_get_size("t") == 8); + assert(bus_gvariant_get_size("d") == 8); + assert(bus_gvariant_get_size("s") < 0); + assert(bus_gvariant_get_size("o") < 0); + assert(bus_gvariant_get_size("g") < 0); + assert(bus_gvariant_get_size("h") == 4); + assert(bus_gvariant_get_size("ay") < 0); + assert(bus_gvariant_get_size("v") < 0); + assert(bus_gvariant_get_size("(u)") == 4); + assert(bus_gvariant_get_size("(uuuuy)") == 20); + assert(bus_gvariant_get_size("(uusuuy)") < 0); + assert(bus_gvariant_get_size("a{ss}") < 0); + assert(bus_gvariant_get_size("((u)yyy(b(iiii)))") == 28); + assert(bus_gvariant_get_size("((u)yyy(b(iiivi)))") < 0); + assert(bus_gvariant_get_size("((b)(t))") == 16); + assert(bus_gvariant_get_size("((b)(b)(t))") == 16); + assert(bus_gvariant_get_size("(bt)") == 16); + assert(bus_gvariant_get_size("((t)(b))") == 16); + assert(bus_gvariant_get_size("(tb)") == 16); + assert(bus_gvariant_get_size("((b)(b))") == 2); + assert(bus_gvariant_get_size("((t)(t))") == 16); +} + +static void test_bus_gvariant_get_alignment(void) { + assert(bus_gvariant_get_alignment("") == 1); + assert(bus_gvariant_get_alignment("()") == 1); + assert(bus_gvariant_get_alignment("y") == 1); + assert(bus_gvariant_get_alignment("b") == 1); + assert(bus_gvariant_get_alignment("u") == 4); + assert(bus_gvariant_get_alignment("s") == 1); + assert(bus_gvariant_get_alignment("o") == 1); + assert(bus_gvariant_get_alignment("g") == 1); + assert(bus_gvariant_get_alignment("v") == 8); + assert(bus_gvariant_get_alignment("h") == 4); + assert(bus_gvariant_get_alignment("i") == 4); + assert(bus_gvariant_get_alignment("t") == 8); + assert(bus_gvariant_get_alignment("x") == 8); + assert(bus_gvariant_get_alignment("q") == 2); + assert(bus_gvariant_get_alignment("n") == 2); + assert(bus_gvariant_get_alignment("d") == 8); + assert(bus_gvariant_get_alignment("ay") == 1); + assert(bus_gvariant_get_alignment("as") == 1); + assert(bus_gvariant_get_alignment("au") == 4); + assert(bus_gvariant_get_alignment("an") == 2); + assert(bus_gvariant_get_alignment("ans") == 2); + assert(bus_gvariant_get_alignment("ant") == 8); + assert(bus_gvariant_get_alignment("(ss)") == 1); + assert(bus_gvariant_get_alignment("(ssu)") == 4); + assert(bus_gvariant_get_alignment("a(ssu)") == 4); + assert(bus_gvariant_get_alignment("(u)") == 4); + assert(bus_gvariant_get_alignment("(uuuuy)") == 4); + assert(bus_gvariant_get_alignment("(uusuuy)") == 4); + assert(bus_gvariant_get_alignment("a{ss}") == 1); + assert(bus_gvariant_get_alignment("((u)yyy(b(iiii)))") == 4); + assert(bus_gvariant_get_alignment("((u)yyy(b(iiivi)))") == 8); + assert(bus_gvariant_get_alignment("((b)(t))") == 8); + assert(bus_gvariant_get_alignment("((b)(b)(t))") == 8); + assert(bus_gvariant_get_alignment("(bt)") == 8); + assert(bus_gvariant_get_alignment("((t)(b))") == 8); + assert(bus_gvariant_get_alignment("(tb)") == 8); + assert(bus_gvariant_get_alignment("((b)(b))") == 1); + assert(bus_gvariant_get_alignment("((t)(t))") == 8); +} + +static void test_marshal(void) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_free_ void *blob; + size_t sz; + + assert_se(sd_bus_open_system(&bus) >= 0); + bus->message_version = 2; /* dirty hack to enable gvariant*/ + + assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName") >= 0); + + assert_se(sd_bus_message_append(m, + "a(usv)", 3, + 4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111, + 4712, "second-string-parameter", "(a(si))", 2, "Y", 5, "Z", 6, + 4713, "third-string-parameter", "(uu)", 1, 2) >= 0); + + assert_se(bus_message_seal(m, 4711, 0) >= 0); + +#ifdef HAVE_GLIB + { + GVariant *v; + char *t; + +#if !defined(GLIB_VERSION_2_36) + g_type_init(); +#endif + + v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuuua(yv))"), m->header, sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m), false, NULL, NULL); + t = g_variant_print(v, TRUE); + printf("%s\n", t); + g_free(t); + g_variant_unref(v); + + v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, BUS_MESSAGE_BODY_SIZE(m), false, NULL, NULL); + t = g_variant_print(v, TRUE); + printf("%s\n", t); + g_free(t); + g_variant_unref(v); + } +#endif + + assert_se(bus_message_dump(m, NULL, true) >= 0); + + assert_se(bus_message_get_blob(m, &blob, &sz) >= 0); + + assert_se(bus_message_from_malloc(NULL, blob, sz, NULL, 0, NULL, NULL, &n) >= 0); + blob = NULL; + + assert_se(bus_message_dump(n, NULL, true) >= 0); + + m = sd_bus_message_unref(m); + + assert_se(sd_bus_message_new_method_call(bus, &m, "a.x", "/a/x", "a.x", "Ax") >= 0); + + assert_se(sd_bus_message_append(m, "as", 0) >= 0); + + assert_se(bus_message_seal(m, 4712, 0) >= 0); + assert_se(bus_message_dump(m, NULL, true) >= 0); +} + +int main(int argc, char *argv[]) { + + test_bus_gvariant_is_fixed_size(); + test_bus_gvariant_get_size(); + test_bus_gvariant_get_alignment(); + test_marshal(); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c new file mode 100644 index 0000000..67b6461 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -0,0 +1,66 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "log.h" +#include "bus-introspect.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; +} + +static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { + return -EINVAL; +} + +static const sd_bus_vtable vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0), + SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED), + SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY), + SD_BUS_SIGNAL("Wowza", "sss", 0), + SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED), + SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0), + SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED), + SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; + +int main(int argc, char *argv[]) { + struct introspect intro; + + log_set_max_level(LOG_DEBUG); + + assert_se(introspect_begin(&intro, false) >= 0); + + fprintf(intro.f, " \n"); + assert_se(introspect_write_interface(&intro, vtable) >= 0); + fputs(" \n", intro.f); + + fflush(intro.f); + fputs(intro.introspection, stdout); + + introspect_free(&intro); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c new file mode 100644 index 0000000..bfeee59 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c @@ -0,0 +1,303 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "log.h" +#include "time-util.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-internal.h" +#include "bus-util.h" + +#define MAX_SIZE (4*1024*1024) + +static usec_t arg_loop_usec = 100 * USEC_PER_MSEC; + +static void server(sd_bus *b, size_t *result) { + int r; + + for (;;) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + r = sd_bus_process(b, &m); + assert_se(r >= 0); + + if (r == 0) + assert_se(sd_bus_wait(b, (usec_t) -1) >= 0); + if (!m) + continue; + + if (sd_bus_message_is_method_call(m, "benchmark.server", "Ping")) + assert_se(sd_bus_reply_method_return(m, NULL) >= 0); + else if (sd_bus_message_is_method_call(m, "benchmark.server", "Work")) { + const void *p; + size_t sz; + + /* Make sure the mmap is mapped */ + assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0); + + assert_se(sd_bus_reply_method_return(m, NULL) >= 0); + } else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) { + uint64_t res; + assert_se(sd_bus_message_read(m, "t", &res) > 0); + + *result = res; + return; + + } else + assert_not_reached("Unknown method"); + } +} + +static void transaction(sd_bus *b, size_t sz) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + uint8_t *p; + + assert_se(sd_bus_message_new_method_call(b, &m, ":1.1", "/", "benchmark.server", "Work") >= 0); + assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0); + + memset(p, 0x80, sz); + + assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0); +} + +static void client_bisect(const char *address) { + _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + size_t lsize, rsize, csize; + sd_bus *b; + int r; + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0); + + lsize = 1; + rsize = MAX_SIZE; + + printf("SIZE\tCOPY\tMEMFD\n"); + + for (;;) { + usec_t t; + unsigned n_copying, n_memfd; + + csize = (lsize + rsize) / 2; + + if (csize <= lsize) + break; + + if (csize <= 0) + break; + + printf("%zu\t", csize); + + b->use_memfd = 0; + + t = now(CLOCK_MONOTONIC); + for (n_copying = 0;; n_copying++) { + transaction(b, csize); + if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec) + break; + } + printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec)); + + b->use_memfd = -1; + + t = now(CLOCK_MONOTONIC); + for (n_memfd = 0;; n_memfd++) { + transaction(b, csize); + if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec) + break; + } + printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec)); + + if (n_copying == n_memfd) + break; + + if (n_copying > n_memfd) + lsize = csize; + else + rsize = csize; + } + + b->use_memfd = 1; + assert_se(sd_bus_message_new_method_call(b, &x, ":1.1", "/", "benchmark.server", "Exit") >= 0); + assert_se(sd_bus_message_append(x, "t", csize) >= 0); + assert_se(sd_bus_send(b, x, NULL) >= 0); + + sd_bus_unref(b); +} + +static void client_chart(const char *address) { + _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + size_t csize; + sd_bus *b; + int r; + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0); + + printf("SIZE\tCOPY\tMEMFD\n"); + + for (csize = 1; csize <= MAX_SIZE; csize *= 2) { + usec_t t; + unsigned n_copying, n_memfd; + + printf("%zu\t", csize); + + b->use_memfd = 0; + + t = now(CLOCK_MONOTONIC); + for (n_copying = 0;; n_copying++) { + transaction(b, csize); + if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec) + break; + } + + printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec)); + + b->use_memfd = -1; + + t = now(CLOCK_MONOTONIC); + for (n_memfd = 0;; n_memfd++) { + transaction(b, csize); + if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec) + break; + } + + printf("%u\n", (unsigned) ((n_memfd * USEC_PER_SEC) / arg_loop_usec)); + } + + b->use_memfd = 1; + assert_se(sd_bus_message_new_method_call(b, &x, ":1.1", "/", "benchmark.server", "Exit") >= 0); + assert_se(sd_bus_message_append(x, "t", csize) >= 0); + assert_se(sd_bus_send(b, x, NULL) >= 0); + + sd_bus_unref(b); +} + +int main(int argc, char *argv[]) { + enum { + MODE_BISECT, + MODE_CHART, + } mode = MODE_BISECT; + int i; + _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; + _cleanup_close_ int bus_ref = -1; + cpu_set_t cpuset; + size_t result; + sd_bus *b; + pid_t pid; + int r; + + for (i = 1; i < argc; i++) { + if (streq(argv[i], "chart")) { + mode = MODE_CHART; + continue; + } + + assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0); + } + + assert_se(arg_loop_usec > 0); + + assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0); + + bus_ref = bus_kernel_create_bus(name, false, &bus_name); + if (bus_ref == -ENOENT) + exit(EXIT_TEST_SKIP); + + assert_se(bus_ref >= 0); + + address = strappend("kernel:path=", bus_name); + assert_se(address); + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + sync(); + setpriority(PRIO_PROCESS, 0, -19); + + pid = fork(); + assert_se(pid >= 0); + + if (pid == 0) { + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + + close_nointr_nofail(bus_ref); + sd_bus_unref(b); + + switch (mode) { + case MODE_BISECT: + client_bisect(address); + break; + + case MODE_CHART: + client_chart(address); + break; + } + + _exit(0); + } + + CPU_ZERO(&cpuset); + CPU_SET(1, &cpuset); + pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + + server(b, &result); + + if (mode == MODE_BISECT) + printf("Copying/memfd are equally fast at %zu bytes\n", result); + + assert_se(waitpid(pid, NULL, 0) == pid); + + sd_bus_unref(b); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c new file mode 100644 index 0000000..0ecad18 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "log.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-util.h" + +static void test_one( + const char *path, + const char *interface, + const char *member, + const char *arg0, + const char *match, + bool good) { + + _cleanup_close_ int bus_ref = -1; + _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + sd_bus *a, *b; + int r; + + assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0); + + bus_ref = bus_kernel_create_bus(name, false, &bus_name); + if (bus_ref == -ENOENT) + exit(EXIT_TEST_SKIP); + + assert_se(bus_ref >= 0); + + address = strappend("kernel:path=", bus_name); + assert_se(address); + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(a, address); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + log_debug("match"); + r = sd_bus_add_match(b, match, NULL, NULL); + assert_se(r >= 0); + + log_debug("signal"); + r = sd_bus_emit_signal(a, path, interface, member, "s", arg0); + assert_se(r >= 0); + + r = sd_bus_process(b, &m); + assert_se(r >= 0 && (good == !!m)); + + sd_bus_unref(a); + sd_bus_unref(b); +} + +int main(int argc, char *argv[]) { + log_set_max_level(LOG_DEBUG); + + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/tuut'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "interface='waldo.com'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Piep'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Pi_ep'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foo_bar'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false); + + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/quux'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar/waldo'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/quux'", false); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c new file mode 100644 index 0000000..2f0f5aa --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -0,0 +1,188 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "log.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-util.h" +#include "bus-dump.h" + +int main(int argc, char *argv[]) { + _cleanup_close_ int bus_ref = -1; + _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *ua = NULL, *ub = NULL, *the_string = NULL; + sd_bus *a, *b; + int r, pipe_fds[2]; + const char *nn; + + log_set_max_level(LOG_DEBUG); + + assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0); + + bus_ref = bus_kernel_create_bus(name, false, &bus_name); + if (bus_ref == -ENOENT) + return EXIT_TEST_SKIP; + + assert_se(bus_ref >= 0); + + address = strappend("kernel:path=", bus_name); + assert_se(address); + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_name(a, "a"); + assert_se(r >= 0); + + r = sd_bus_set_address(a, address); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + assert_se(sd_bus_negotiate_timestamp(a, 1) >= 0); + assert_se(sd_bus_negotiate_creds(a, _SD_BUS_CREDS_ALL) >= 0); + + assert_se(sd_bus_negotiate_timestamp(b, 1) >= 0); + assert_se(sd_bus_negotiate_creds(b, _SD_BUS_CREDS_ALL) >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &ua); + assert_se(r >= 0); + printf("unique a: %s\n", ua); + + r = sd_bus_get_name(a, &nn); + assert_se(r >= 0); + printf("name of a: %s\n", nn); + + r = sd_bus_get_unique_name(b, &ub); + assert_se(r >= 0); + printf("unique b: %s\n", ub); + + r = sd_bus_get_name(b, &nn); + assert_se(r >= 0); + printf("name of b: %s\n", nn); + + r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay"); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN)); + assert_se(r == -EHOSTUNREACH); + + r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL); + assert_se(r >= 0); + + r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name"); + assert_se(r >= 0); + + r = sd_bus_try_close(b); + assert_se(r == -EBUSY); + + r = sd_bus_process_priority(b, -10, &m); + assert_se(r == -ENOMSG); + + r = sd_bus_process(b, &m); + assert_se(r > 0); + assert_se(m); + + bus_message_dump(m, stdout, true); + assert_se(sd_bus_message_rewind(m, true) >= 0); + + r = sd_bus_message_read(m, "s", &the_string); + assert_se(r >= 0); + assert_se(streq(the_string, "I am a string")); + + sd_bus_message_unref(m); + m = NULL; + + r = sd_bus_request_name(a, "net.x0pointer.foobar", 0); + assert_se(r >= 0); + + r = sd_bus_message_new_method_call(b, &m, "net.x0pointer.foobar", "/a/path", "an.inter.face", "AMethod"); + assert_se(r >= 0); + + assert_se(pipe2(pipe_fds, O_CLOEXEC) >= 0); + + assert_se(write(pipe_fds[1], "x", 1) == 1); + + close_nointr_nofail(pipe_fds[1]); + pipe_fds[1] = -1; + + r = sd_bus_message_append(m, "h", pipe_fds[0]); + assert_se(r >= 0); + + close_nointr_nofail(pipe_fds[0]); + pipe_fds[0] = -1; + + r = sd_bus_send(b, m, NULL); + assert_se(r >= 0); + + for (;;) { + sd_bus_message_unref(m); + m = NULL; + r = sd_bus_process(a, &m); + assert_se(r > 0); + assert_se(m); + + bus_message_dump(m, stdout, true); + assert_se(sd_bus_message_rewind(m, true) >= 0); + + if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) { + int fd; + char x; + + r = sd_bus_message_read(m, "h", &fd); + assert_se(r >= 0); + + assert_se(read(fd, &x, 1) == 1); + assert_se(x == 'x'); + break; + } + } + + r = sd_bus_release_name(a, "net.x0pointer.foobar"); + assert_se(r >= 0); + + r = sd_bus_release_name(a, "net.x0pointer.foobar"); + assert_se(r == -ESRCH); + + r = sd_bus_try_close(a); + assert_se(r >= 0); + + sd_bus_unref(a); + sd_bus_unref(b); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c new file mode 100644 index 0000000..85aaf95 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -0,0 +1,324 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#ifdef HAVE_GLIB +#include +#endif + +#ifdef HAVE_DBUS +#include +#endif + +#include "log.h" +#include "util.h" + +#include "sd-bus.h" +#include "bus-message.h" +#include "bus-util.h" +#include "bus-dump.h" + +static void test_bus_label_escape_one(const char *a, const char *b) { + _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL; + + assert_se(t = sd_bus_label_escape(a)); + assert_se(streq(t, b)); + + assert_se(x = sd_bus_label_unescape(t)); + assert_se(streq(a, x)); + + assert_se(y = sd_bus_label_unescape(b)); + assert_se(streq(a, y)); +} + +static void test_bus_label_escape(void) { + test_bus_label_escape_one("foo123bar", "foo123bar"); + test_bus_label_escape_one("foo.bar", "foo_2ebar"); + test_bus_label_escape_one("foo_2ebar", "foo_5f2ebar"); + test_bus_label_escape_one("", "_"); + test_bus_label_escape_one("_", "_5f"); + test_bus_label_escape_one("1", "_31"); + test_bus_label_escape_one(":1", "_3a1"); +} + +int main(int argc, char *argv[]) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL; + int r, boolean; + const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature; + uint8_t u, v; + void *buffer = NULL; + size_t sz; + char *h; + const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array; + char *s; + _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL; + _cleanup_fclose_ FILE *ms = NULL; + size_t first_size = 0, second_size = 0, third_size = 0; + + r = sd_bus_message_new_method_call(NULL, &m, "foobar.waldo", "/", "foobar.waldo", "Piep"); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "s", "a string"); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "s", NULL); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "asg", 2, "string #1", "string #2", "sba(tt)ss"); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after"); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo"); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3"); + assert_se(r >= 0); + + r = sd_bus_message_open_container(m, 'a', "s"); + assert_se(r >= 0); + + r = sd_bus_message_append_basic(m, 's', "foobar"); + assert_se(r >= 0); + + r = sd_bus_message_append_basic(m, 's', "waldo"); + assert_se(r >= 0); + + r = sd_bus_message_close_container(m); + assert_se(r >= 0); + + r = sd_bus_message_append_string_space(m, 5, &s); + assert_se(r >= 0); + strcpy(s, "hallo"); + + r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array)); + assert_se(r >= 0); + + r = sd_bus_message_append_array(m, 'u', NULL, 0); + assert_se(r >= 0); + + r = bus_message_seal(m, 4711, 0); + assert_se(r >= 0); + + bus_message_dump(m, stdout, true); + + ms = open_memstream(&first, &first_size); + bus_message_dump(m, ms, false); + fflush(ms); + assert_se(!ferror(ms)); + + r = bus_message_get_blob(m, &buffer, &sz); + assert_se(r >= 0); + + h = hexmem(buffer, sz); + assert_se(h); + + log_info("message size = %lu, contents =\n%s", (unsigned long) sz, h); + free(h); + +#ifdef HAVE_GLIB + { + GDBusMessage *g; + char *p; + +#if !defined(GLIB_VERSION_2_36) + g_type_init(); +#endif + + g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL); + p = g_dbus_message_print(g, 0); + log_info("%s", p); + g_free(p); + g_object_unref(g); + } +#endif + +#ifdef HAVE_DBUS + { + DBusMessage *w; + DBusError error; + + dbus_error_init(&error); + + w = dbus_message_demarshal(buffer, sz, &error); + if (!w) + log_error("%s", error.message); + else + dbus_message_unref(w); + } +#endif + + m = sd_bus_message_unref(m); + + r = bus_message_from_malloc(NULL, buffer, sz, NULL, 0, NULL, NULL, &m); + assert_se(r >= 0); + + bus_message_dump(m, stdout, true); + + fclose(ms); + ms = open_memstream(&second, &second_size); + bus_message_dump(m, ms, false); + fflush(ms); + assert_se(!ferror(ms)); + assert_se(first_size == second_size); + assert_se(memcmp(first, second, first_size) == 0); + + assert_se(sd_bus_message_rewind(m, true) >= 0); + + r = sd_bus_message_read(m, "ssasg", &x, &x2, 2, &y, &z, &a_signature); + assert_se(r > 0); + assert_se(streq(x, "a string")); + assert_se(streq(x2, "")); + assert_se(streq(y, "string #1")); + assert_se(streq(z, "string #2")); + assert_se(streq(a_signature, "sba(tt)ss")); + + r = sd_bus_message_read(m, "sass", &x, 5, &y, &z, &a, &b, &c, &d); + assert_se(r > 0); + assert_se(streq(x, "foobar")); + assert_se(streq(y, "foo")); + assert_se(streq(z, "bar")); + assert_se(streq(a, "waldo")); + assert_se(streq(b, "piep")); + assert_se(streq(c, "pap")); + assert_se(streq(d, "after")); + + r = sd_bus_message_read(m, "a{yv}", 2, &u, "s", &x, &v, "s", &y); + assert_se(r > 0); + assert_se(u == 3); + assert_se(streq(x, "foo")); + assert_se(v == 5); + assert_se(streq(y, "waldo")); + + r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d); + assert_se(r > 0); + assert_se(boolean); + assert_se(streq(x, "aaa")); + assert_se(streq(y, "1")); + assert_se(streq(a, "bbb")); + assert_se(streq(b, "2")); + assert_se(streq(c, "ccc")); + assert_se(streq(d, "3")); + + assert_se(sd_bus_message_verify_type(m, 'a', "s") > 0); + + r = sd_bus_message_read(m, "as", 2, &x, &y); + assert_se(r > 0); + assert_se(streq(x, "foobar")); + assert_se(streq(y, "waldo")); + + r = sd_bus_message_read_basic(m, 's', &s); + assert_se(r > 0); + assert_se(streq(s, "hallo")); + + r = sd_bus_message_read_array(m, 'i', (const void**) &return_array, &sz); + assert_se(r > 0); + assert_se(sz == sizeof(integer_array)); + assert_se(memcmp(integer_array, return_array, sz) == 0); + + r = sd_bus_message_read_array(m, 'u', (const void**) &return_array, &sz); + assert_se(r > 0); + assert_se(sz == 0); + + r = sd_bus_message_peek_type(m, NULL, NULL); + assert_se(r == 0); + + r = sd_bus_message_new_method_call(NULL, ©, "foobar.waldo", "/", "foobar.waldo", "Piep"); + assert_se(r >= 0); + + r = sd_bus_message_rewind(m, true); + assert_se(r >= 0); + + r = sd_bus_message_copy(copy, m, true); + assert_se(r >= 0); + + r = bus_message_seal(copy, 4712, 0); + assert_se(r >= 0); + + fclose(ms); + ms = open_memstream(&third, &third_size); + bus_message_dump(copy, ms, false); + fflush(ms); + assert_se(!ferror(ms)); + + printf("<%.*s>\n", (int) first_size, first); + printf("<%.*s>\n", (int) third_size, third); + + assert_se(first_size == third_size); + assert_se(memcmp(first, third, third_size) == 0); + + r = sd_bus_message_rewind(m, true); + assert_se(r >= 0); + + assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0); + + r = sd_bus_message_skip(m, "ssasg"); + assert_se(r > 0); + + assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0); + + r = sd_bus_message_skip(m, "sass"); + assert_se(r >= 0); + + assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0); + + r = sd_bus_message_skip(m, "a{yv}"); + assert_se(r >= 0); + + assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0); + + r = sd_bus_message_read(m, "b", &boolean); + assert_se(r > 0); + assert_se(boolean); + + r = sd_bus_message_enter_container(m, 0, NULL); + assert_se(r > 0); + + r = sd_bus_message_read(m, "(ss)", &x, &y); + assert_se(r > 0); + + r = sd_bus_message_read(m, "(ss)", &a, &b); + assert_se(r > 0); + + r = sd_bus_message_read(m, "(ss)", &c, &d); + assert_se(r > 0); + + r = sd_bus_message_read(m, "(ss)", &x, &y); + assert_se(r == 0); + + r = sd_bus_message_exit_container(m); + assert_se(r >= 0); + + assert_se(streq(x, "aaa")); + assert_se(streq(y, "1")); + assert_se(streq(a, "bbb")); + assert_se(streq(b, "2")); + assert_se(streq(c, "ccc")); + assert_se(streq(d, "3")); + + test_bus_label_escape(); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c new file mode 100644 index 0000000..c561be2 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -0,0 +1,145 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "log.h" +#include "util.h" +#include "macro.h" + +#include "bus-match.h" +#include "bus-message.h" +#include "bus-util.h" + +static bool mask[32]; + +static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + log_info("Ran %i", PTR_TO_INT(userdata)); + mask[PTR_TO_INT(userdata)] = true; + return 0; +} + +static bool mask_contains(unsigned a[], unsigned n) { + unsigned i, j; + + for (i = 0; i < ELEMENTSOF(mask); i++) { + bool found = false; + + for (j = 0; j < n; j++) + if (a[j] == i) { + found = true; + break; + } + + if (found != mask[i]) + return false; + } + + return true; +} + +static int match_add(struct bus_match_node *root, const char *match, int value) { + struct bus_match_component *components = NULL; + unsigned n_components = 0; + int r; + + r = bus_match_parse(match, &components, &n_components); + if (r < 0) + return r; + + r = bus_match_add(root, components, n_components, filter, INT_TO_PTR(value), 0, NULL); + bus_match_parse_free(components, n_components); + + return r; +} + +static int match_remove(struct bus_match_node *root, const char *match, int value) { + struct bus_match_component *components = NULL; + unsigned n_components = 0; + int r; + + r = bus_match_parse(match, &components, &n_components); + if (r < 0) + return r; + + r = bus_match_remove(root, components, n_components, filter, INT_TO_PTR(value), 0); + bus_match_parse_free(components, n_components); + + return r; +} + +int main(int argc, char *argv[]) { + struct bus_match_node root; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + enum bus_match_node_type i; + + zero(root); + root.type = BUS_MATCH_ROOT; + + assert_se(match_add(&root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0); + assert_se(match_add(&root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0); + assert_se(match_add(&root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0); + assert_se(match_add(&root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0); + assert_se(match_add(&root, "", 5) >= 0); + assert_se(match_add(&root, "interface='quux.x'", 6) >= 0); + assert_se(match_add(&root, "interface='bar.x'", 7) >= 0); + assert_se(match_add(&root, "member='waldo',path='/foo/bar'", 8) >= 0); + assert_se(match_add(&root, "path='/foo/bar'", 9) >= 0); + assert_se(match_add(&root, "path_namespace='/foo'", 10) >= 0); + assert_se(match_add(&root, "path_namespace='/foo/quux'", 11) >= 0); + assert_se(match_add(&root, "arg1='two'", 12) >= 0); + assert_se(match_add(&root, "member='waldo',arg2path='/prefix/'", 13) >= 0); + assert_se(match_add(&root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0); + + bus_match_dump(&root, 0); + + assert_se(sd_bus_message_new_signal(NULL, &m, "/foo/bar", "bar.x", "waldo") >= 0); + assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0); + assert_se(bus_message_seal(m, 1, 0) >= 0); + + zero(mask); + assert_se(bus_match_run(NULL, &root, m) == 0); + assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8)); + + assert_se(match_remove(&root, "member='waldo',path='/foo/bar'", 8) > 0); + assert_se(match_remove(&root, "arg2path='/prefix/',member='waldo'", 13) > 0); + assert_se(match_remove(&root, "interface='bar.xx'", 7) == 0); + + bus_match_dump(&root, 0); + + zero(mask); + assert_se(bus_match_run(NULL, &root, m) == 0); + assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6)); + + for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) { + char buf[32]; + const char *x; + + assert_se(x = bus_match_node_type_to_string(i, buf, sizeof(buf))); + + if (i >= BUS_MATCH_MESSAGE_TYPE) + assert_se(bus_match_node_type_from_string(x, strlen(x)) == i); + } + + bus_match_free(&root); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-memfd.c b/src/libsystemd/sd-bus/test-bus-memfd.c new file mode 100644 index 0000000..3462732 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-memfd.c @@ -0,0 +1,180 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" + +#include "sd-memfd.h" + +int main(int argc, char *argv[]) { + sd_memfd *m; + char *s, *name; + uint64_t sz; + int r, fd; + FILE *f = NULL; + char buf[3] = {}; + struct iovec iov[3] = {}; + char bufv[3][3] = {}; + + log_set_max_level(LOG_DEBUG); + + r = sd_memfd_new(&m, NULL); + if (r == -ENOENT) + return EXIT_TEST_SKIP; + + assert_se(r >= 0); + + assert_se(sd_memfd_get_name(m, &name) >= 0); + log_info("name: %s", name); + free(name); + + r = sd_memfd_map(m, 0, 12, (void**) &s); + assert_se(r >= 0); + + strcpy(s, "----- world"); + + r = sd_memfd_set_sealed(m, 1); + assert_se(r == -ETXTBSY); + + assert_se(write(sd_memfd_get_fd(m), "he", 2) == 2); + assert_se(write(sd_memfd_get_fd(m), "XXX", 3) == 3); + assert_se(streq(s, "heXXX world")); + + /* fix "hello" */ + assert_se(lseek(sd_memfd_get_fd(m), 2, SEEK_SET) == 2); + assert_se(write(sd_memfd_get_fd(m), "ll", 2) == 2); + + assert_se(sd_memfd_get_file(m, &f) >= 0); + fputc('o', f); + fflush(f); + + /* check content */ + assert_se(streq(s, "hello world")); + + assert_se(munmap(s, 12) == 0); + + r = sd_memfd_get_sealed(m); + assert_se(r == 0); + + r = sd_memfd_get_size(m, &sz); + assert_se(r >= 0); + assert_se(sz = page_size()); + + /* truncate it */ + r = sd_memfd_set_size(m, 6); + assert_se(r >= 0); + + /* get back new value */ + r = sd_memfd_get_size(m, &sz); + assert_se(r >= 0); + assert_se(sz == 6); + + r = sd_memfd_set_sealed(m, 1); + assert_se(r >= 0); + + r = sd_memfd_get_sealed(m); + assert_se(r == 1); + + fd = sd_memfd_dup_fd(m); + assert_se(fd >= 0); + + sd_memfd_free(m); + + /* new sd_memfd, same underlying memfd */ + r = sd_memfd_new_from_fd(&m, fd); + assert_se(r >= 0); + + /* we did truncate it to 6 */ + r = sd_memfd_get_size(m, &sz); + assert_se(r >= 0 && sz == 6); + + /* map it, check content */ + r = sd_memfd_map(m, 0, 12, (void **)&s); + assert_se(r >= 0); + + /* we only see the truncated size */ + assert_se(streq(s, "hello ")); + + /* it was already sealed */ + r = sd_memfd_set_sealed(m, 1); + assert_se(r == -EALREADY); + + /* we cannot break the seal, it is mapped */ + r = sd_memfd_set_sealed(m, 0); + assert_se(r == -ETXTBSY); + + /* unmap it; become the single owner */ + assert_se(munmap(s, 12) == 0); + + /* now we can do flip the sealing */ + r = sd_memfd_set_sealed(m, 0); + assert_se(r == 0); + r = sd_memfd_get_sealed(m); + assert_se(r == 0); + + r = sd_memfd_set_sealed(m, 1); + assert_se(r == 0); + r = sd_memfd_get_sealed(m); + assert_se(r == 1); + + r = sd_memfd_set_sealed(m, 0); + assert_se(r == 0); + r = sd_memfd_get_sealed(m); + assert_se(r == 0); + + /* seek at 2, read() 2 bytes */ + assert_se(lseek(fd, 2, SEEK_SET) == 2); + assert_se(read(fd, buf, 2) == 2); + + /* check content */ + assert_se(memcmp(buf, "ll", 2) == 0); + + /* writev it out*/ + iov[0].iov_base = (char *)"ABC"; + iov[0].iov_len = 3; + iov[1].iov_base = (char *)"DEF"; + iov[1].iov_len = 3; + iov[2].iov_base = (char *)"GHI"; + iov[2].iov_len = 3; + assert_se(pwritev(fd, iov, 3, 0) == 9); + + /* readv it back */ + iov[0].iov_base = bufv[0]; + iov[0].iov_len = 3; + iov[1].iov_base = bufv[1]; + iov[1].iov_len = 3; + iov[2].iov_base = bufv[2]; + iov[2].iov_len = 3; + assert_se(preadv(fd, iov, 3, 0) == 9); + + /* check content */ + assert_se(memcmp(bufv[0], "ABC", 3) == 0); + assert_se(memcmp(bufv[1], "DEF", 3) == 0); + assert_se(memcmp(bufv[2], "GHI", 3) == 0); + + sd_memfd_free(m); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c new file mode 100644 index 0000000..e2423c7 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -0,0 +1,500 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "macro.h" +#include "strv.h" + +#include "sd-bus.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-util.h" +#include "bus-dump.h" + +struct context { + int fds[2]; + bool quit; + char *something; + char *automatic_string_property; + uint32_t automatic_integer_property; +}; + +static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + struct context *c = userdata; + const char *s; + char *n = NULL; + int r; + + r = sd_bus_message_read(m, "s", &s); + assert_se(r > 0); + + n = strjoin("<<<", s, ">>>", NULL); + assert_se(n); + + free(c->something); + c->something = n; + + log_info("AlterSomething() called, got %s, returning %s", s, n); + + /* This should fail, since the return type doesn't match */ + assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG); + + r = sd_bus_reply_method_return(m, "s", n); + assert_se(r >= 0); + + return 1; +} + +static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + struct context *c = userdata; + int r; + + c->quit = true; + + log_info("Exit called"); + + r = sd_bus_reply_method_return(m, ""); + assert_se(r >= 0); + + return 1; +} + +static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { + struct context *c = userdata; + int r; + + log_info("property get for %s called, returning \"%s\".", property, c->something); + + r = sd_bus_message_append(reply, "s", c->something); + assert_se(r >= 0); + + return 1; +} + +static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) { + struct context *c = userdata; + const char *s; + char *n; + int r; + + log_info("property set for %s called", property); + + r = sd_bus_message_read(value, "s", &s); + assert_se(r >= 0); + + n = strdup(s); + assert_se(n); + + free(c->something); + c->something = n; + + return 1; +} + +static int value_handler(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 *s = NULL; + const char *x; + int r; + + assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0); + r = sd_bus_message_append(reply, "s", s); + assert_se(r >= 0); + + assert_se(x = startswith(path, "/value/")); + + assert_se(PTR_TO_UINT(userdata) == 30); + + return 1; +} + +static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int r; + + assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0); + + r = sd_bus_reply_method_return(m, NULL); + assert_se(r >= 0); + + return 1; +} + +static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int r; + + assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0); + + r = sd_bus_reply_method_return(m, NULL); + assert_se(r >= 0); + + return 1; +} + +static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int r; + + assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0); + + r = sd_bus_reply_method_return(m, NULL); + assert_se(r >= 0); + + return 1; +} + +static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int r; + + assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0); + + r = sd_bus_reply_method_return(m, NULL); + assert_se(r >= 0); + + return 1; +} + +static const sd_bus_vtable vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0), + SD_BUS_METHOD("Exit", "", "", exit_handler, 0), + SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0), + SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0), + SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0), + SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0), + SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0), + SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0), + SD_BUS_VTABLE_END +}; + +static const sd_bus_vtable vtable2[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0), + SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 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_PROPERTY("Value4", "s", value_handler, 10, 0), + SD_BUS_VTABLE_END +}; + +static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + + if (object_path_startswith("/value", path)) + assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL)); + + return 1; +} + +static void *server(void *p) { + struct context *c = p; + sd_bus *bus = NULL; + sd_id128_t id; + int r; + + c->quit = false; + + assert_se(sd_id128_randomize(&id) >= 0); + + assert_se(sd_bus_new(&bus) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); + assert_se(sd_bus_set_server(bus, 1, id) >= 0); + + assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0); + assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0); + assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0); + assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0); + assert_se(sd_bus_add_object_manager(bus, "/value") >= 0); + + assert_se(sd_bus_start(bus) >= 0); + + log_error("Entering event loop on server"); + + while (!c->quit) { + log_error("Loop!"); + + r = sd_bus_process(bus, NULL); + if (r < 0) { + log_error("Failed to process requests: %s", strerror(-r)); + goto fail; + } + + if (r == 0) { + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) { + log_error("Failed to wait: %s", strerror(-r)); + goto fail; + } + + continue; + } + } + + r = 0; + +fail: + if (bus) { + sd_bus_flush(bus); + sd_bus_unref(bus); + } + + return INT_TO_PTR(r); +} + +static int client(struct context *c) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *s; + int r; + + assert_se(sd_bus_new(&bus) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); + assert_se(sd_bus_start(bus) >= 0); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL); + assert_se(r >= 0); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo"); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + assert_se(streq(s, "<<>>")); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, ""); + assert_se(r < 0); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)); + + sd_bus_error_free(&error); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo"); + assert_se(r < 0); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)); + + sd_bus_error_free(&error); + + r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s"); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + assert_se(streq(s, "<<>>")); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test"); + assert_se(r >= 0); + + r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s"); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + assert_se(streq(s, "test")); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815); + assert_se(r >= 0); + + assert_se(c->automatic_integer_property == 815); + + r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!"); + assert_se(r >= 0); + + assert_se(streq(c->automatic_string_property, "Du Dödel, Du!")); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + fputs(s, stdout); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s"); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + log_info("read %s", s); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + fputs(s, stdout); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + fputs(s, stdout); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + fputs(s, stdout); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", ""); + assert_se(r >= 0); + + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2"); + assert_se(r < 0); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE)); + sd_bus_error_free(&error); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, ""); + assert_se(r < 0); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)); + sd_bus_error_free(&error); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, ""); + assert_se(r >= 0); + + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, ""); + assert_se(r >= 0); + + r = sd_bus_process(bus, &reply); + assert_se(r > 0); + + assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, ""); + assert_se(r >= 0); + + r = sd_bus_process(bus, &reply); + assert_se(r > 0); + + assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, ""); + assert_se(r >= 0); + + r = sd_bus_process(bus, &reply); + assert_se(r > 0); + + assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")); + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, ""); + assert_se(r >= 0); + + r = sd_bus_process(bus, &reply); + assert_se(r > 0); + + assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")); + bus_message_dump(reply, stdout, true); + + sd_bus_message_unref(reply); + reply = NULL; + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, ""); + assert_se(r >= 0); + + sd_bus_flush(bus); + + return 0; +} + +int main(int argc, char *argv[]) { + struct context c = {}; + pthread_t s; + void *p; + int r, q; + + zero(c); + + c.automatic_integer_property = 4711; + assert_se(c.automatic_string_property = strdup("dudeldu")); + + assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0); + + r = pthread_create(&s, NULL, server, &c); + if (r != 0) + return -r; + + r = client(&c); + + q = pthread_join(s, &p); + if (q != 0) + return -q; + + if (r < 0) + return r; + + if (PTR_TO_INT(p) < 0) + return PTR_TO_INT(p); + + free(c.something); + free(c.automatic_string_property); + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c new file mode 100644 index 0000000..96d6298 --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -0,0 +1,224 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "macro.h" + +#include "sd-bus.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-util.h" + +struct context { + int fds[2]; + + bool client_negotiate_unix_fds; + bool server_negotiate_unix_fds; + + bool client_anonymous_auth; + bool server_anonymous_auth; +}; + +static void *server(void *p) { + struct context *c = p; + sd_bus *bus = NULL; + sd_id128_t id; + bool quit = false; + int r; + + assert_se(sd_id128_randomize(&id) >= 0); + + assert_se(sd_bus_new(&bus) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0); + assert_se(sd_bus_set_server(bus, 1, id) >= 0); + assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0); + assert_se(sd_bus_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0); + assert_se(sd_bus_start(bus) >= 0); + + while (!quit) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + + r = sd_bus_process(bus, &m); + if (r < 0) { + log_error("Failed to process requests: %s", strerror(-r)); + goto fail; + } + + if (r == 0) { + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) { + log_error("Failed to wait: %s", strerror(-r)); + goto fail; + } + + continue; + } + + if (!m) + continue; + + log_info("Got message! member=%s", strna(sd_bus_message_get_member(m))); + + if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) { + + assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds)); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) { + log_error("Failed to allocate return: %s", strerror(-r)); + goto fail; + } + + quit = true; + + } else if (sd_bus_message_is_method_call(m, NULL, NULL)) { + r = sd_bus_message_new_method_error( + m, + &reply, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method.")); + if (r < 0) { + log_error("Failed to allocate return: %s", strerror(-r)); + goto fail; + } + } + + if (reply) { + r = sd_bus_send(bus, reply, NULL); + if (r < 0) { + log_error("Failed to send reply: %s", strerror(-r)); + goto fail; + } + } + } + + r = 0; + +fail: + if (bus) { + sd_bus_flush(bus); + sd_bus_unref(bus); + } + + return INT_TO_PTR(r); +} + +static int client(struct context *c) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert_se(sd_bus_new(&bus) >= 0); + assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0); + assert_se(sd_bus_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0); + assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0); + assert_se(sd_bus_start(bus) >= 0); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd.test", + "/", + "org.freedesktop.systemd.test", + "Exit"); + if (r < 0) { + log_error("Failed to allocate method call: %s", strerror(-r)); + return r; + } + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + return r; + } + + return 0; +} + +static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds, + bool client_anonymous_auth, bool server_anonymous_auth) { + + struct context c; + pthread_t s; + void *p; + int r, q; + + zero(c); + + assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0); + + c.client_negotiate_unix_fds = client_negotiate_unix_fds; + c.server_negotiate_unix_fds = server_negotiate_unix_fds; + c.client_anonymous_auth = client_anonymous_auth; + c.server_anonymous_auth = server_anonymous_auth; + + r = pthread_create(&s, NULL, server, &c); + if (r != 0) + return -r; + + r = client(&c); + + q = pthread_join(s, &p); + if (q != 0) + return -q; + + if (r < 0) + return r; + + if (PTR_TO_INT(p) < 0) + return PTR_TO_INT(p); + + return 0; +} + +int main(int argc, char *argv[]) { + int r; + + r = test_one(true, true, false, false); + assert_se(r >= 0); + + r = test_one(true, false, false, false); + assert_se(r >= 0); + + r = test_one(false, true, false, false); + assert_se(r >= 0); + + r = test_one(false, false, false, false); + assert_se(r >= 0); + + r = test_one(true, true, true, true); + assert_se(r >= 0); + + r = test_one(true, true, false, true); + assert_se(r >= 0); + + r = test_one(true, true, true, false); + assert_se(r == -EPERM); + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c new file mode 100644 index 0000000..3fc565c --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -0,0 +1,163 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "log.h" +#include "bus-signature.h" +#include "bus-internal.h" + +int main(int argc, char *argv[]) { + char prefix[256]; + int r; + + assert_se(signature_is_single("y", false)); + assert_se(signature_is_single("u", false)); + assert_se(signature_is_single("v", false)); + assert_se(signature_is_single("as", false)); + assert_se(signature_is_single("(ss)", false)); + assert_se(signature_is_single("()", false)); + assert_se(signature_is_single("(()()()()())", false)); + assert_se(signature_is_single("(((())))", false)); + assert_se(signature_is_single("((((s))))", false)); + assert_se(signature_is_single("{ss}", true)); + assert_se(signature_is_single("a{ss}", false)); + assert_se(!signature_is_single("uu", false)); + assert_se(!signature_is_single("", false)); + assert_se(!signature_is_single("(", false)); + assert_se(!signature_is_single(")", false)); + assert_se(!signature_is_single("())", false)); + assert_se(!signature_is_single("((())", false)); + assert_se(!signature_is_single("{)", false)); + assert_se(!signature_is_single("{}", true)); + assert_se(!signature_is_single("{sss}", true)); + assert_se(!signature_is_single("{s}", true)); + assert_se(!signature_is_single("{ss}", false)); + assert_se(!signature_is_single("{ass}", true)); + assert_se(!signature_is_single("a}", true)); + + assert_se(signature_is_pair("yy")); + assert_se(signature_is_pair("ss")); + assert_se(signature_is_pair("sas")); + assert_se(signature_is_pair("sv")); + assert_se(signature_is_pair("sa(vs)")); + assert_se(!signature_is_pair("")); + assert_se(!signature_is_pair("va")); + assert_se(!signature_is_pair("sss")); + assert_se(!signature_is_pair("{s}ss")); + + assert_se(signature_is_valid("ssa{ss}sssub", true)); + assert_se(signature_is_valid("ssa{ss}sssub", false)); + assert_se(signature_is_valid("{ss}", true)); + assert_se(!signature_is_valid("{ss}", false)); + assert_se(signature_is_valid("", true)); + assert_se(signature_is_valid("", false)); + + assert_se(signature_is_valid("sssusa(uuubbba(uu)uuuu)a{u(uuuvas)}", false)); + + assert_se(!signature_is_valid("a", false)); + assert_se(signature_is_valid("as", false)); + assert_se(signature_is_valid("aas", false)); + assert_se(signature_is_valid("aaas", false)); + assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad", false)); + assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false)); + assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false)); + + assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false)); + assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false)); + + assert_se(namespace_complex_pattern("", "")); + assert_se(namespace_complex_pattern("foobar", "foobar")); + assert_se(namespace_complex_pattern("foobar.waldo", "foobar.waldo")); + assert_se(namespace_complex_pattern("foobar.", "foobar.waldo")); + assert_se(namespace_complex_pattern("foobar.waldo", "foobar.")); + assert_se(!namespace_complex_pattern("foobar.waldo", "foobar")); + assert_se(!namespace_complex_pattern("foobar", "foobar.waldo")); + assert_se(!namespace_complex_pattern("", "foo")); + assert_se(!namespace_complex_pattern("foo", "")); + assert_se(!namespace_complex_pattern("foo.", "")); + + assert_se(path_complex_pattern("", "")); + assert_se(path_complex_pattern("", "/")); + assert_se(path_complex_pattern("/", "")); + assert_se(path_complex_pattern("/", "/")); + assert_se(path_complex_pattern("/foobar/", "/")); + assert_se(path_complex_pattern("/foobar/", "/foobar")); + assert_se(path_complex_pattern("/foobar", "/foobar")); + assert_se(path_complex_pattern("/foobar", "/foobar/")); + assert_se(!path_complex_pattern("/foobar", "/foobar/waldo")); + assert_se(path_complex_pattern("/foobar/", "/foobar/waldo")); + + assert_se(namespace_simple_pattern("", "")); + assert_se(namespace_simple_pattern("foobar", "foobar")); + assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo")); + assert_se(namespace_simple_pattern("foobar", "foobar.waldo")); + assert_se(!namespace_simple_pattern("foobar.waldo", "foobar")); + assert_se(!namespace_simple_pattern("", "foo")); + assert_se(!namespace_simple_pattern("foo", "")); + + assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar")); + assert_se(streq(object_path_startswith("/foo", "/foo"), "")); + assert_se(streq(object_path_startswith("/foo", "/"), "foo")); + assert_se(streq(object_path_startswith("/", "/"), "")); + assert_se(!object_path_startswith("/foo", "/bar")); + assert_se(!object_path_startswith("/", "/bar")); + assert_se(!object_path_startswith("/foo", "")); + + assert_se(object_path_is_valid("/foo/bar")); + assert_se(object_path_is_valid("/foo")); + assert_se(object_path_is_valid("/")); + assert_se(object_path_is_valid("/foo5")); + assert_se(object_path_is_valid("/foo_5")); + assert_se(!object_path_is_valid("")); + assert_se(!object_path_is_valid("/foo/")); + assert_se(!object_path_is_valid("//")); + assert_se(!object_path_is_valid("//foo")); + assert_se(!object_path_is_valid("/foo//bar")); + assert_se(!object_path_is_valid("/foo/aaaäöä")); + + OBJECT_PATH_FOREACH_PREFIX(prefix, "/") { + log_info("<%s>", prefix); + assert_not_reached("???"); + } + + r = 0; + OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx") { + log_info("<%s>", prefix); + assert_se(streq(prefix, "/")); + assert_se(r == 0); + r++; + } + assert_se(r == 1); + + r = 0; + OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx/yyy/zzz") { + log_info("<%s>", prefix); + assert_se(r != 0 || streq(prefix, "/xxx/yyy")); + assert_se(r != 1 || streq(prefix, "/xxx")); + assert_se(r != 2 || streq(prefix, "/")); + r++; + } + assert_se(r == 3); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c new file mode 100644 index 0000000..29e40aa --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -0,0 +1,197 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "log.h" + +#include "sd-bus.h" +#include "sd-memfd.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-dump.h" + +#define FIRST_ARRAY 17 +#define SECOND_ARRAY 33 + +#define STRING_SIZE 123 + +int main(int argc, char *argv[]) { + _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; + uint8_t *p; + sd_bus *a, *b; + int r, bus_ref; + sd_bus_message *m; + sd_memfd *f; + uint64_t sz; + uint32_t u32; + size_t i, l; + char *s; + + log_set_max_level(LOG_DEBUG); + + assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0); + + bus_ref = bus_kernel_create_bus(name, false, &bus_name); + if (bus_ref == -ENOENT) + return EXIT_TEST_SKIP; + + assert_se(bus_ref >= 0); + + address = strappend("kernel:path=", bus_name); + assert_se(address); + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(a, address); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + r = sd_bus_message_new_method_call(b, &m, ":1.1", "/a/path", "an.inter.face", "AMethod"); + assert_se(r >= 0); + + r = sd_bus_message_open_container(m, 'r', "aysay"); + assert_se(r >= 0); + + r = sd_bus_message_append_array_space(m, 'y', FIRST_ARRAY, (void**) &p); + assert_se(r >= 0); + + p[0] = '<'; + memset(p+1, 'L', FIRST_ARRAY-2); + p[FIRST_ARRAY-1] = '>'; + + r = sd_memfd_new_and_map(&f, NULL, STRING_SIZE, (void**) &s); + assert_se(r >= 0); + + s[0] = '<'; + for (i = 1; i < STRING_SIZE-2; i++) + s[i] = '0' + (i % 10); + s[STRING_SIZE-2] = '>'; + s[STRING_SIZE-1] = 0; + munmap(s, STRING_SIZE); + + r = sd_memfd_get_size(f, &sz); + assert_se(r >= 0); + assert_se(sz == STRING_SIZE); + + r = sd_bus_message_append_string_memfd(m, f); + assert_se(r >= 0); + + sd_memfd_free(f); + + r = sd_memfd_new_and_map(&f, NULL, SECOND_ARRAY, (void**) &p); + assert_se(r >= 0); + + p[0] = '<'; + memset(p+1, 'P', SECOND_ARRAY-2); + p[SECOND_ARRAY-1] = '>'; + munmap(p, SECOND_ARRAY); + + r = sd_memfd_get_size(f, &sz); + assert_se(r >= 0); + assert_se(sz == SECOND_ARRAY); + + r = sd_bus_message_append_array_memfd(m, 'y', f); + assert_se(r >= 0); + + sd_memfd_free(f); + + r = sd_bus_message_close_container(m); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "u", 4711); + assert_se(r >= 0); + + r = bus_message_seal(m, 55, 99*USEC_PER_SEC); + assert_se(r >= 0); + + bus_message_dump(m, stdout, true); + + r = sd_bus_send(b, m, NULL); + assert_se(r >= 0); + + sd_bus_message_unref(m); + + r = sd_bus_process(a, &m); + assert_se(r > 0); + + bus_message_dump(m, stdout, true); + sd_bus_message_rewind(m, true); + + r = sd_bus_message_enter_container(m, 'r', "aysay"); + assert_se(r > 0); + + r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l); + assert_se(r > 0); + assert_se(l == FIRST_ARRAY); + + assert_se(p[0] == '<'); + for (i = 1; i < l-1; i++) + assert_se(p[i] == 'L'); + assert_se(p[l-1] == '>'); + + r = sd_bus_message_read(m, "s", &s); + assert_se(r > 0); + + assert_se(s[0] == '<'); + for (i = 1; i < STRING_SIZE-2; i++) + assert_se(s[i] == (char) ('0' + (i % 10))); + assert_se(s[STRING_SIZE-2] == '>'); + assert_se(s[STRING_SIZE-1] == 0); + + r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l); + assert_se(r > 0); + assert_se(l == SECOND_ARRAY); + + assert_se(p[0] == '<'); + for (i = 1; i < l-1; i++) + assert_se(p[i] == 'P'); + assert_se(p[l-1] == '>'); + + r = sd_bus_message_exit_container(m); + assert_se(r > 0); + + r = sd_bus_message_read(m, "u", &u32); + assert_se(r > 0); + assert_se(u32 == 4711); + + sd_bus_message_unref(m); + + sd_bus_unref(a); + sd_bus_unref(b); + + return 0; +} diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c new file mode 100644 index 0000000..21fb346 --- /dev/null +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -0,0 +1,537 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "sd-daemon.h" + +_public_ int sd_listen_fds(int unset_environment) { + int r, fd; + const char *e; + char *p = NULL; + unsigned long l; + + e = getenv("LISTEN_PID"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno > 0) { + r = -errno; + goto finish; + } + + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + e = getenv("LISTEN_FDS"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno > 0) { + r = -errno; + goto finish; + } + + if (!p || p == e || *p) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags < 0) { + r = -errno; + goto finish; + } + + if (flags & FD_CLOEXEC) + continue; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + r = -errno; + goto finish; + } + } + + r = (int) l; + +finish: + if (unset_environment) { + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDS"); + } + + return r; +} + +_public_ int sd_is_fifo(int fd, const char *path) { + struct stat st_fd; + + if (fd < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISFIFO(st_fd.st_mode)) + return 0; + + if (path) { + struct stat st_path; + + if (stat(path, &st_path) < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + return -errno; + } + + return + st_path.st_dev == st_fd.st_dev && + st_path.st_ino == st_fd.st_ino; + } + + return 1; +} + +_public_ int sd_is_special(int fd, const char *path) { + struct stat st_fd; + + if (fd < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) + return 0; + + if (path) { + struct stat st_path; + + if (stat(path, &st_path) < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + return -errno; + } + + if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) + return + st_path.st_dev == st_fd.st_dev && + st_path.st_ino == st_fd.st_ino; + else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) + return st_path.st_rdev == st_fd.st_rdev; + else + return 0; + } + + return 1; +} + +static int sd_is_socket_internal(int fd, int type, int listening) { + struct stat st_fd; + + if (fd < 0 || type < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISSOCK(st_fd.st_mode)) + return 0; + + if (type != 0) { + int other_type = 0; + socklen_t l = sizeof(other_type); + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) + return -errno; + + if (l != sizeof(other_type)) + return -EINVAL; + + if (other_type != type) + return 0; + } + + if (listening >= 0) { + int accepting = 0; + socklen_t l = sizeof(accepting); + + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) + return -errno; + + if (l != sizeof(accepting)) + return -EINVAL; + + if (!accepting != !listening) + return 0; + } + + return 1; +} + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_storage storage; +}; + +_public_ int sd_is_socket(int fd, int family, int type, int listening) { + int r; + + if (family < 0) + return -EINVAL; + + r = sd_is_socket_internal(fd, type, listening); + if (r <= 0) + return r; + + if (family > 0) { + union sockaddr_union sockaddr = {}; + socklen_t l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + return sockaddr.sa.sa_family == family; + } + + return 1; +} + +_public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { + union sockaddr_union sockaddr = {}; + socklen_t l = sizeof(sockaddr); + int r; + + if (family != 0 && family != AF_INET && family != AF_INET6) + return -EINVAL; + + r = sd_is_socket_internal(fd, type, listening); + if (r <= 0) + return r; + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_INET && + sockaddr.sa.sa_family != AF_INET6) + return 0; + + if (family > 0) + if (sockaddr.sa.sa_family != family) + return 0; + + if (port > 0) { + if (sockaddr.sa.sa_family == AF_INET) { + if (l < sizeof(struct sockaddr_in)) + return -EINVAL; + + return htons(port) == sockaddr.in4.sin_port; + } else { + if (l < sizeof(struct sockaddr_in6)) + return -EINVAL; + + return htons(port) == sockaddr.in6.sin6_port; + } + } + + return 1; +} + +_public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { + union sockaddr_union sockaddr = {}; + socklen_t l = sizeof(sockaddr); + int r; + + r = sd_is_socket_internal(fd, type, listening); + if (r <= 0) + return r; + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_UNIX) + return 0; + + if (path) { + if (length == 0) + length = strlen(path); + + if (length == 0) + /* Unnamed socket */ + return l == offsetof(struct sockaddr_un, sun_path); + + if (path[0]) + /* Normal path socket */ + return + (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && + memcmp(path, sockaddr.un.sun_path, length+1) == 0; + else + /* Abstract namespace socket */ + return + (l == offsetof(struct sockaddr_un, sun_path) + length) && + memcmp(path, sockaddr.un.sun_path, length) == 0; + } + + return 1; +} + +_public_ int sd_is_mq(int fd, const char *path) { + struct mq_attr attr; + + if (fd < 0) + return -EINVAL; + + if (mq_getattr(fd, &attr) < 0) + return -errno; + + if (path) { + char fpath[PATH_MAX]; + struct stat a, b; + + if (path[0] != '/') + return -EINVAL; + + if (fstat(fd, &a) < 0) + return -errno; + + strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); + fpath[sizeof(fpath)-1] = 0; + + if (stat(fpath, &b) < 0) + return -errno; + + if (a.st_dev != b.st_dev || + a.st_ino != b.st_ino) + return 0; + } + + return 1; +} + +_public_ int sd_notify(int unset_environment, const char *state) { + int fd = -1, r; + struct msghdr msghdr; + struct iovec iovec; + union sockaddr_union sockaddr; + const char *e; + + if (!state) { + r = -EINVAL; + goto finish; + } + + e = getenv("NOTIFY_SOCKET"); + if (!e) + return 0; + + /* Must be an abstract socket, or an absolute path */ + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + r = -EINVAL; + goto finish; + } + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (fd < 0) { + r = -errno; + goto finish; + } + + memzero(&sockaddr, sizeof(sockaddr)); + sockaddr.sa.sa_family = AF_UNIX; + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); + + if (sockaddr.un.sun_path[0] == '@') + sockaddr.un.sun_path[0] = 0; + + memzero(&iovec, sizeof(iovec)); + iovec.iov_base = (char*) state; + iovec.iov_len = strlen(state); + + memzero(&msghdr, sizeof(msghdr)); + msghdr.msg_name = &sockaddr; + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); + + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) + msghdr.msg_namelen = sizeof(struct sockaddr_un); + + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { + r = -errno; + goto finish; + } + + r = 1; + +finish: + if (unset_environment) + unsetenv("NOTIFY_SOCKET"); + + if (fd >= 0) + close(fd); + + return r; +} + +_public_ int sd_notifyf(int unset_environment, const char *format, ...) { + va_list ap; + char *p = NULL; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0 || !p) + return -ENOMEM; + + r = sd_notify(unset_environment, p); + free(p); + + return r; +} + +_public_ int sd_booted(void) { + struct stat st; + + /* We test whether the runtime unit file directory has been + * created. This takes place in mount-setup.c, so is + * guaranteed to happen very early during boot. */ + + if (lstat("/run/systemd/system/", &st) < 0) + return 0; + + return !!S_ISDIR(st.st_mode); +} + +_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { + unsigned long long ll; + unsigned long l; + const char *e; + char *p = NULL; + int r; + + e = getenv("WATCHDOG_PID"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + if (errno > 0) { + r = -errno; + goto finish; + } + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + e = getenv("WATCHDOG_USEC"); + if (!e) { + r = -EINVAL; + goto finish; + } + + errno = 0; + ll = strtoull(e, &p, 10); + if (errno > 0) { + r = -errno; + goto finish; + } + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + if (usec) + *usec = ll; + + r = 1; + +finish: + if (unset_environment) { + unsetenv("WATCHDOG_PID"); + unsetenv("WATCHDOG_USEC"); + } + + return r; +} diff --git a/src/libsystemd/sd-event/Makefile b/src/libsystemd/sd-event/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-event/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h new file mode 100644 index 0000000..e58020d --- /dev/null +++ b/src/libsystemd/sd-event/event-util.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref); + +#define _cleanup_event_unref_ _cleanup_(sd_event_unrefp) +#define _cleanup_event_source_unref_ _cleanup_(sd_event_source_unrefp) diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c new file mode 100644 index 0000000..253923d --- /dev/null +++ b/src/libsystemd/sd-event/sd-event.c @@ -0,0 +1,2296 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-daemon.h" +#include "macro.h" +#include "prioq.h" +#include "hashmap.h" +#include "util.h" +#include "time-util.h" +#include "missing.h" +#include "set.h" + +#include "sd-event.h" + +#define EPOLL_QUEUE_MAX 512U +#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) + +typedef enum EventSourceType { + SOURCE_IO, + SOURCE_MONOTONIC, + SOURCE_REALTIME, + SOURCE_SIGNAL, + SOURCE_CHILD, + SOURCE_DEFER, + SOURCE_POST, + SOURCE_EXIT, + SOURCE_WATCHDOG +} EventSourceType; + +struct sd_event_source { + unsigned n_ref; + + sd_event *event; + void *userdata; + sd_event_handler_t prepare; + + EventSourceType type:4; + int enabled:3; + bool pending:1; + bool dispatching:1; + + int64_t priority; + unsigned pending_index; + unsigned prepare_index; + unsigned pending_iteration; + unsigned prepare_iteration; + + union { + struct { + sd_event_io_handler_t callback; + int fd; + uint32_t events; + uint32_t revents; + bool registered:1; + } io; + struct { + sd_event_time_handler_t callback; + usec_t next, accuracy; + unsigned earliest_index; + unsigned latest_index; + } time; + struct { + sd_event_signal_handler_t callback; + struct signalfd_siginfo siginfo; + int sig; + } signal; + struct { + sd_event_child_handler_t callback; + siginfo_t siginfo; + pid_t pid; + int options; + } child; + struct { + sd_event_handler_t callback; + } defer; + struct { + sd_event_handler_t callback; + } post; + struct { + sd_event_handler_t callback; + unsigned prioq_index; + } exit; + }; +}; + +struct sd_event { + unsigned n_ref; + + int epoll_fd; + int signal_fd; + int realtime_fd; + int monotonic_fd; + int watchdog_fd; + + Prioq *pending; + Prioq *prepare; + + /* For both clocks we maintain two priority queues each, one + * ordered for the earliest times the events may be + * dispatched, and one ordered by the latest times they must + * have been dispatched. The range between the top entries in + * the two prioqs is the time window we can freely schedule + * wakeups in */ + Prioq *monotonic_earliest; + Prioq *monotonic_latest; + Prioq *realtime_earliest; + Prioq *realtime_latest; + + usec_t realtime_next, monotonic_next; + usec_t perturb; + + sigset_t sigset; + sd_event_source **signal_sources; + + Hashmap *child_sources; + unsigned n_enabled_child_sources; + + Set *post_sources; + + Prioq *exit; + + pid_t original_pid; + + unsigned iteration; + dual_timestamp timestamp; + int state; + + bool exit_requested:1; + bool need_process_child:1; + bool watchdog:1; + + int exit_code; + + pid_t tid; + sd_event **default_event_ptr; + + usec_t watchdog_last, watchdog_period; + + unsigned n_sources; +}; + +static int pending_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert(x->pending); + assert(y->pending); + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Lower priority values first */ + if (x->priority < y->priority) + return -1; + if (x->priority > y->priority) + return 1; + + /* Older entries first */ + if (x->pending_iteration < y->pending_iteration) + return -1; + if (x->pending_iteration > y->pending_iteration) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + +static int prepare_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert(x->prepare); + assert(y->prepare); + + /* Move most recently prepared ones last, so that we can stop + * preparing as soon as we hit one that has already been + * prepared in the current iteration */ + if (x->prepare_iteration < y->prepare_iteration) + return -1; + if (x->prepare_iteration > y->prepare_iteration) + return 1; + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Lower priority values first */ + if (x->priority < y->priority) + return -1; + if (x->priority > y->priority) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + +static int earliest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert(x->type == SOURCE_MONOTONIC || x->type == SOURCE_REALTIME); + assert(y->type == SOURCE_MONOTONIC || y->type == SOURCE_REALTIME); + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Move the pending ones to the end */ + if (!x->pending && y->pending) + return -1; + if (x->pending && !y->pending) + return 1; + + /* Order by time */ + if (x->time.next < y->time.next) + return -1; + if (x->time.next > y->time.next) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + +static int latest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert((x->type == SOURCE_MONOTONIC && y->type == SOURCE_MONOTONIC) || + (x->type == SOURCE_REALTIME && y->type == SOURCE_REALTIME)); + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Move the pending ones to the end */ + if (!x->pending && y->pending) + return -1; + if (x->pending && !y->pending) + return 1; + + /* Order by time */ + if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy) + return -1; + if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + +static int exit_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + + assert(x->type == SOURCE_EXIT); + assert(y->type == SOURCE_EXIT); + + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + + /* Lower priority values first */ + if (x->priority < y->priority) + return -1; + if (x->priority > y->priority) + return 1; + + /* Stability for the rest */ + if (x < y) + return -1; + if (x > y) + return 1; + + return 0; +} + +static void event_free(sd_event *e) { + assert(e); + assert(e->n_sources == 0); + + if (e->default_event_ptr) + *(e->default_event_ptr) = NULL; + + if (e->epoll_fd >= 0) + close_nointr_nofail(e->epoll_fd); + + if (e->signal_fd >= 0) + close_nointr_nofail(e->signal_fd); + + if (e->realtime_fd >= 0) + close_nointr_nofail(e->realtime_fd); + + if (e->monotonic_fd >= 0) + close_nointr_nofail(e->monotonic_fd); + + if (e->watchdog_fd >= 0) + close_nointr_nofail(e->watchdog_fd); + + prioq_free(e->pending); + prioq_free(e->prepare); + prioq_free(e->monotonic_earliest); + prioq_free(e->monotonic_latest); + prioq_free(e->realtime_earliest); + prioq_free(e->realtime_latest); + prioq_free(e->exit); + + free(e->signal_sources); + + hashmap_free(e->child_sources); + set_free(e->post_sources); + free(e); +} + +_public_ int sd_event_new(sd_event** ret) { + sd_event *e; + int r; + + assert_return(ret, -EINVAL); + + e = new0(sd_event, 1); + if (!e) + return -ENOMEM; + + e->n_ref = 1; + e->signal_fd = e->realtime_fd = e->monotonic_fd = e->watchdog_fd = e->epoll_fd = -1; + e->realtime_next = e->monotonic_next = (usec_t) -1; + e->original_pid = getpid(); + + assert_se(sigemptyset(&e->sigset) == 0); + + e->pending = prioq_new(pending_prioq_compare); + if (!e->pending) { + r = -ENOMEM; + goto fail; + } + + e->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (e->epoll_fd < 0) { + r = -errno; + goto fail; + } + + *ret = e; + return 0; + +fail: + event_free(e); + return r; +} + +_public_ sd_event* sd_event_ref(sd_event *e) { + assert_return(e, NULL); + + assert(e->n_ref >= 1); + e->n_ref++; + + return e; +} + +_public_ sd_event* sd_event_unref(sd_event *e) { + + if (!e) + return NULL; + + assert(e->n_ref >= 1); + e->n_ref--; + + if (e->n_ref <= 0) + event_free(e); + + return NULL; +} + +static bool event_pid_changed(sd_event *e) { + assert(e); + + /* We don't support people creating am event loop and keeping + * it around over a fork(). Let's complain. */ + + return e->original_pid != getpid(); +} + +static int source_io_unregister(sd_event_source *s) { + int r; + + assert(s); + assert(s->type == SOURCE_IO); + + if (!s->io.registered) + return 0; + + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); + if (r < 0) + return -errno; + + s->io.registered = false; + return 0; +} + +static int source_io_register( + sd_event_source *s, + int enabled, + uint32_t events) { + + struct epoll_event ev = {}; + int r; + + assert(s); + assert(s->type == SOURCE_IO); + assert(enabled != SD_EVENT_OFF); + + ev.events = events; + ev.data.ptr = s; + + if (enabled == SD_EVENT_ONESHOT) + ev.events |= EPOLLONESHOT; + + if (s->io.registered) + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev); + else + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev); + + if (r < 0) + return -errno; + + s->io.registered = true; + + return 0; +} + +static void source_free(sd_event_source *s) { + assert(s); + + if (s->event) { + assert(s->event->n_sources > 0); + + switch (s->type) { + + case SOURCE_IO: + if (s->io.fd >= 0) + source_io_unregister(s); + + break; + + case SOURCE_MONOTONIC: + prioq_remove(s->event->monotonic_earliest, s, &s->time.earliest_index); + prioq_remove(s->event->monotonic_latest, s, &s->time.latest_index); + break; + + case SOURCE_REALTIME: + prioq_remove(s->event->realtime_earliest, s, &s->time.earliest_index); + prioq_remove(s->event->realtime_latest, s, &s->time.latest_index); + break; + + case SOURCE_SIGNAL: + if (s->signal.sig > 0) { + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) + assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); + + if (s->event->signal_sources) + s->event->signal_sources[s->signal.sig] = NULL; + } + + break; + + case SOURCE_CHILD: + if (s->child.pid > 0) { + if (s->enabled != SD_EVENT_OFF) { + assert(s->event->n_enabled_child_sources > 0); + s->event->n_enabled_child_sources--; + } + + if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) + assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); + + hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + } + + break; + + case SOURCE_DEFER: + /* nothing */ + break; + + case SOURCE_POST: + set_remove(s->event->post_sources, s); + break; + + case SOURCE_EXIT: + prioq_remove(s->event->exit, s, &s->exit.prioq_index); + break; + + case SOURCE_WATCHDOG: + assert_not_reached("Wut? I shouldn't exist."); + } + + if (s->pending) + prioq_remove(s->event->pending, s, &s->pending_index); + + if (s->prepare) + prioq_remove(s->event->prepare, s, &s->prepare_index); + + s->event->n_sources--; + sd_event_unref(s->event); + } + + free(s); +} + +static int source_set_pending(sd_event_source *s, bool b) { + int r; + + assert(s); + assert(s->type != SOURCE_EXIT); + + if (s->pending == b) + return 0; + + s->pending = b; + + if (b) { + s->pending_iteration = s->event->iteration; + + r = prioq_put(s->event->pending, s, &s->pending_index); + if (r < 0) { + s->pending = false; + return r; + } + } else + assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); + + if (s->type == SOURCE_REALTIME) { + prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + } else if (s->type == SOURCE_MONOTONIC) { + prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + } + + return 0; +} + +static sd_event_source *source_new(sd_event *e, EventSourceType type) { + sd_event_source *s; + + assert(e); + + s = new0(sd_event_source, 1); + if (!s) + return NULL; + + s->n_ref = 1; + s->event = sd_event_ref(e); + s->type = type; + s->pending_index = s->prepare_index = PRIOQ_IDX_NULL; + + e->n_sources ++; + + return s; +} + +_public_ int sd_event_add_io( + sd_event *e, + sd_event_source **ret, + int fd, + uint32_t events, + sd_event_io_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(fd >= 0, -EINVAL); + assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + s = source_new(e, SOURCE_IO); + if (!s) + return -ENOMEM; + + s->io.fd = fd; + s->io.events = events; + s->io.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ON; + + r = source_io_register(s, s->enabled, events); + if (r < 0) { + source_free(s); + return -errno; + } + + *ret = s; + return 0; +} + +static int event_setup_timer_fd( + sd_event *e, + EventSourceType type, + int *timer_fd, + clockid_t id) { + + sd_id128_t bootid = {}; + struct epoll_event ev = {}; + int r, fd; + + assert(e); + assert(timer_fd); + + if (_likely_(*timer_fd >= 0)) + return 0; + + fd = timerfd_create(id, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + return -errno; + + ev.events = EPOLLIN; + ev.data.ptr = INT_TO_PTR(type); + + r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); + if (r < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* When we sleep for longer, we try to realign the wakeup to + the same time wihtin each minute/second/250ms, so that + events all across the system can be coalesced into a single + CPU wakeup. However, let's take some system-specific + randomness for this value, so that in a network of systems + with synced clocks timer events are distributed a + bit. Here, we calculate a perturbation usec offset from the + boot ID. */ + + if (sd_id128_get_boot(&bootid) >= 0) + e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE; + + *timer_fd = fd; + return 0; +} + +static int event_add_time_internal( + sd_event *e, + sd_event_source **ret, + EventSourceType type, + int *timer_fd, + clockid_t id, + Prioq **earliest, + Prioq **latest, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(accuracy != (uint64_t) -1, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + assert(timer_fd); + assert(earliest); + assert(latest); + + if (!*earliest) { + *earliest = prioq_new(earliest_time_prioq_compare); + if (!*earliest) + return -ENOMEM; + } + + if (!*latest) { + *latest = prioq_new(latest_time_prioq_compare); + if (!*latest) + return -ENOMEM; + } + + if (*timer_fd < 0) { + r = event_setup_timer_fd(e, type, timer_fd, id); + if (r < 0) + return r; + } + + s = source_new(e, type); + if (!s) + return -ENOMEM; + + s->time.next = usec; + s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; + s->time.callback = callback; + s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + + r = prioq_put(*earliest, s, &s->time.earliest_index); + if (r < 0) + goto fail; + + r = prioq_put(*latest, s, &s->time.latest_index); + if (r < 0) + goto fail; + + *ret = s; + return 0; + +fail: + source_free(s); + return r; +} + +_public_ int sd_event_add_monotonic(sd_event *e, + sd_event_source **ret, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata) { + + return event_add_time_internal(e, ret, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata); +} + +_public_ int sd_event_add_realtime(sd_event *e, + sd_event_source **ret, + uint64_t usec, + uint64_t accuracy, + sd_event_time_handler_t callback, + void *userdata) { + + return event_add_time_internal(e, ret, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->realtime_latest, usec, accuracy, callback, userdata); +} + +static int event_update_signal_fd(sd_event *e) { + struct epoll_event ev = {}; + bool add_to_epoll; + int r; + + assert(e); + + add_to_epoll = e->signal_fd < 0; + + r = signalfd(e->signal_fd, &e->sigset, SFD_NONBLOCK|SFD_CLOEXEC); + if (r < 0) + return -errno; + + e->signal_fd = r; + + if (!add_to_epoll) + return 0; + + ev.events = EPOLLIN; + ev.data.ptr = INT_TO_PTR(SOURCE_SIGNAL); + + r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev); + if (r < 0) { + close_nointr_nofail(e->signal_fd); + e->signal_fd = -1; + + return -errno; + } + + return 0; +} + +_public_ int sd_event_add_signal( + sd_event *e, + sd_event_source **ret, + int sig, + sd_event_signal_handler_t callback, + void *userdata) { + + sd_event_source *s; + sigset_t ss; + int r; + + assert_return(e, -EINVAL); + assert_return(sig > 0, -EINVAL); + assert_return(sig < _NSIG, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + r = pthread_sigmask(SIG_SETMASK, NULL, &ss); + if (r < 0) + return -errno; + + if (!sigismember(&ss, sig)) + return -EBUSY; + + if (!e->signal_sources) { + e->signal_sources = new0(sd_event_source*, _NSIG); + if (!e->signal_sources) + return -ENOMEM; + } else if (e->signal_sources[sig]) + return -EBUSY; + + s = source_new(e, SOURCE_SIGNAL); + if (!s) + return -ENOMEM; + + s->signal.sig = sig; + s->signal.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ON; + + e->signal_sources[sig] = s; + assert_se(sigaddset(&e->sigset, sig) == 0); + + if (sig != SIGCHLD || e->n_enabled_child_sources == 0) { + r = event_update_signal_fd(e); + if (r < 0) { + source_free(s); + return r; + } + } + + *ret = s; + return 0; +} + +_public_ int sd_event_add_child( + sd_event *e, + sd_event_source **ret, + pid_t pid, + int options, + sd_event_child_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(pid > 1, -EINVAL); + assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); + assert_return(options != 0, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + r = hashmap_ensure_allocated(&e->child_sources, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + if (hashmap_contains(e->child_sources, INT_TO_PTR(pid))) + return -EBUSY; + + s = source_new(e, SOURCE_CHILD); + if (!s) + return -ENOMEM; + + s->child.pid = pid; + s->child.options = options; + s->child.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + + r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s); + if (r < 0) { + source_free(s); + return r; + } + + e->n_enabled_child_sources ++; + + assert_se(sigaddset(&e->sigset, SIGCHLD) == 0); + + if (!e->signal_sources || !e->signal_sources[SIGCHLD]) { + r = event_update_signal_fd(e); + if (r < 0) { + source_free(s); + return -errno; + } + } + + e->need_process_child = true; + + *ret = s; + return 0; +} + +_public_ int sd_event_add_defer( + sd_event *e, + sd_event_source **ret, + sd_event_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + s = source_new(e, SOURCE_DEFER); + if (!s) + return -ENOMEM; + + s->defer.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + + r = source_set_pending(s, true); + if (r < 0) { + source_free(s); + return r; + } + + *ret = s; + return 0; +} + +_public_ int sd_event_add_post( + sd_event *e, + sd_event_source **ret, + sd_event_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + r = set_ensure_allocated(&e->post_sources, trivial_hash_func, trivial_compare_func); + if (r < 0) + return r; + + s = source_new(e, SOURCE_POST); + if (!s) + return -ENOMEM; + + s->post.callback = callback; + s->userdata = userdata; + s->enabled = SD_EVENT_ON; + + r = set_put(e->post_sources, s); + if (r < 0) { + source_free(s); + return r; + } + + *ret = s; + return 0; +} + +_public_ int sd_event_add_exit( + sd_event *e, + sd_event_source **ret, + sd_event_handler_t callback, + void *userdata) { + + sd_event_source *s; + int r; + + assert_return(e, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + if (!e->exit) { + e->exit = prioq_new(exit_prioq_compare); + if (!e->exit) + return -ENOMEM; + } + + s = source_new(e, SOURCE_EXIT); + if (!s) + return -ENOMEM; + + s->exit.callback = callback; + s->userdata = userdata; + s->exit.prioq_index = PRIOQ_IDX_NULL; + s->enabled = SD_EVENT_ONESHOT; + + r = prioq_put(s->event->exit, s, &s->exit.prioq_index); + if (r < 0) { + source_free(s); + return r; + } + + *ret = s; + return 0; +} + +_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) { + assert_return(s, NULL); + + assert(s->n_ref >= 1); + s->n_ref++; + + return s; +} + +_public_ sd_event_source* sd_event_source_unref(sd_event_source *s) { + + if (!s) + return NULL; + + assert(s->n_ref >= 1); + s->n_ref--; + + if (s->n_ref <= 0) { + /* Here's a special hack: when we are called from a + * dispatch handler we won't free the event source + * immediately, but we will detach the fd from the + * epoll. This way it is safe for the caller to unref + * the event source and immediately close the fd, but + * we still retain a valid event source object after + * the callback. */ + + if (s->dispatching) { + if (s->type == SOURCE_IO) + source_io_unregister(s); + } else + source_free(s); + } + + return NULL; +} + +_public_ sd_event *sd_event_source_get_event(sd_event_source *s) { + assert_return(s, NULL); + + return s->event; +} + +_public_ int sd_event_source_get_pending(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type != SOURCE_EXIT, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + return s->pending; +} + +_public_ int sd_event_source_get_io_fd(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + return s->io.fd; +} + +_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { + int r; + + assert_return(s, -EINVAL); + assert_return(fd >= 0, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->io.fd == fd) + return 0; + + if (s->enabled == SD_EVENT_OFF) { + s->io.fd = fd; + s->io.registered = false; + } else { + int saved_fd; + + saved_fd = s->io.fd; + assert(s->io.registered); + + s->io.fd = fd; + s->io.registered = false; + + r = source_io_register(s, s->enabled, s->io.events); + if (r < 0) { + s->io.fd = saved_fd; + s->io.registered = true; + return r; + } + + epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); + } + + return 0; +} + +_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { + assert_return(s, -EINVAL); + assert_return(events, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *events = s->io.events; + return 0; +} + +_public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) { + int r; + + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->io.events == events) + return 0; + + if (s->enabled != SD_EVENT_OFF) { + r = source_io_register(s, s->enabled, events); + if (r < 0) + return r; + } + + s->io.events = events; + source_set_pending(s, false); + + return 0; +} + +_public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) { + assert_return(s, -EINVAL); + assert_return(revents, -EINVAL); + assert_return(s->type == SOURCE_IO, -EDOM); + assert_return(s->pending, -ENODATA); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *revents = s->io.revents; + return 0; +} + +_public_ int sd_event_source_get_signal(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_SIGNAL, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + return s->signal.sig; +} + +_public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) { + assert_return(s, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); + + return s->priority; +} + +_public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) { + assert_return(s, -EINVAL); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->priority == priority) + return 0; + + s->priority = priority; + + if (s->pending) + prioq_reshuffle(s->event->pending, s, &s->pending_index); + + if (s->prepare) + prioq_reshuffle(s->event->prepare, s, &s->prepare_index); + + if (s->type == SOURCE_EXIT) + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + + return 0; +} + +_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { + assert_return(s, -EINVAL); + assert_return(m, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *m = s->enabled; + return 0; +} + +_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + int r; + + assert_return(s, -EINVAL); + assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->enabled == m) + return 0; + + if (m == SD_EVENT_OFF) { + + switch (s->type) { + + case SOURCE_IO: + r = source_io_unregister(s); + if (r < 0) + return r; + + s->enabled = m; + break; + + case SOURCE_MONOTONIC: + s->enabled = m; + prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + break; + + case SOURCE_REALTIME: + s->enabled = m; + prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + break; + + case SOURCE_SIGNAL: + s->enabled = m; + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) { + assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0); + event_update_signal_fd(s->event); + } + + break; + + case SOURCE_CHILD: + s->enabled = m; + + assert(s->event->n_enabled_child_sources > 0); + s->event->n_enabled_child_sources--; + + if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) { + assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0); + event_update_signal_fd(s->event); + } + + break; + + case SOURCE_EXIT: + s->enabled = m; + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + break; + + case SOURCE_DEFER: + case SOURCE_POST: + s->enabled = m; + break; + + case SOURCE_WATCHDOG: + assert_not_reached("Wut? I shouldn't exist."); + } + + } else { + switch (s->type) { + + case SOURCE_IO: + r = source_io_register(s, m, s->io.events); + if (r < 0) + return r; + + s->enabled = m; + break; + + case SOURCE_MONOTONIC: + s->enabled = m; + prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + break; + + case SOURCE_REALTIME: + s->enabled = m; + prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + break; + + case SOURCE_SIGNAL: + s->enabled = m; + + if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0) { + assert_se(sigaddset(&s->event->sigset, s->signal.sig) == 0); + event_update_signal_fd(s->event); + } + break; + + case SOURCE_CHILD: + if (s->enabled == SD_EVENT_OFF) { + s->event->n_enabled_child_sources++; + + if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD]) { + assert_se(sigaddset(&s->event->sigset, SIGCHLD) == 0); + event_update_signal_fd(s->event); + } + } + + s->enabled = m; + break; + + case SOURCE_EXIT: + s->enabled = m; + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + break; + + case SOURCE_DEFER: + case SOURCE_POST: + s->enabled = m; + break; + + case SOURCE_WATCHDOG: + assert_not_reached("Wut? I shouldn't exist."); + } + } + + if (s->pending) + prioq_reshuffle(s->event->pending, s, &s->pending_index); + + if (s->prepare) + prioq_reshuffle(s->event->prepare, s, &s->prepare_index); + + return 0; +} + +_public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { + assert_return(s, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *usec = s->time.next; + return 0; +} + +_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { + assert_return(s, -EINVAL); + assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + s->time.next = usec; + + source_set_pending(s, false); + + if (s->type == SOURCE_REALTIME) { + prioq_reshuffle(s->event->realtime_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + } else { + prioq_reshuffle(s->event->monotonic_earliest, s, &s->time.earliest_index); + prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + } + + return 0; +} + +_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { + assert_return(s, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *usec = s->time.accuracy; + return 0; +} + +_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { + assert_return(s, -EINVAL); + assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(s->type == SOURCE_REALTIME || s->type == SOURCE_MONOTONIC, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (usec == 0) + usec = DEFAULT_ACCURACY_USEC; + + s->time.accuracy = usec; + + source_set_pending(s, false); + + if (s->type == SOURCE_REALTIME) + prioq_reshuffle(s->event->realtime_latest, s, &s->time.latest_index); + else + prioq_reshuffle(s->event->monotonic_latest, s, &s->time.latest_index); + + return 0; +} + +_public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { + assert_return(s, -EINVAL); + assert_return(pid, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + *pid = s->child.pid; + return 0; +} + +_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) { + int r; + + assert_return(s, -EINVAL); + assert_return(s->type != SOURCE_EXIT, -EDOM); + assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->prepare == callback) + return 0; + + if (callback && s->prepare) { + s->prepare = callback; + return 0; + } + + r = prioq_ensure_allocated(&s->event->prepare, prepare_prioq_compare); + if (r < 0) + return r; + + s->prepare = callback; + + if (callback) { + r = prioq_put(s->event->prepare, s, &s->prepare_index); + if (r < 0) + return r; + } else + prioq_remove(s->event->prepare, s, &s->prepare_index); + + return 0; +} + +_public_ void* sd_event_source_get_userdata(sd_event_source *s) { + assert_return(s, NULL); + + return s->userdata; +} + +_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) { + void *ret; + + assert_return(s, NULL); + + ret = s->userdata; + s->userdata = userdata; + + return ret; +} + +static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { + usec_t c; + assert(e); + assert(a <= b); + + if (a <= 0) + return 0; + + if (b <= a + 1) + return a; + + /* + Find a good time to wake up again between times a and b. We + have two goals here: + + a) We want to wake up as seldom as possible, hence prefer + later times over earlier times. + + b) But if we have to wake up, then let's make sure to + dispatch as much as possible on the entire system. + + We implement this by waking up everywhere at the same time + within any given minute if we can, synchronised via the + perturbation value determined from the boot ID. If we can't, + then we try to find the same spot in every 10s, then 1s and + then 250ms step. Otherwise, we pick the last possible time + to wake up. + */ + + c = (b / USEC_PER_MINUTE) * USEC_PER_MINUTE + e->perturb; + if (c >= b) { + if (_unlikely_(c < USEC_PER_MINUTE)) + return b; + + c -= USEC_PER_MINUTE; + } + + if (c >= a) + return c; + + c = (b / (USEC_PER_SEC*10)) * (USEC_PER_SEC*10) + (e->perturb % (USEC_PER_SEC*10)); + if (c >= b) { + if (_unlikely_(c < USEC_PER_SEC*10)) + return b; + + c -= USEC_PER_SEC*10; + } + + if (c >= a) + return c; + + c = (b / USEC_PER_SEC) * USEC_PER_SEC + (e->perturb % USEC_PER_SEC); + if (c >= b) { + if (_unlikely_(c < USEC_PER_SEC)) + return b; + + c -= USEC_PER_SEC; + } + + if (c >= a) + return c; + + c = (b / (USEC_PER_MSEC*250)) * (USEC_PER_MSEC*250) + (e->perturb % (USEC_PER_MSEC*250)); + if (c >= b) { + if (_unlikely_(c < USEC_PER_MSEC*250)) + return b; + + c -= USEC_PER_MSEC*250; + } + + if (c >= a) + return c; + + return b; +} + +static int event_arm_timer( + sd_event *e, + int timer_fd, + Prioq *earliest, + Prioq *latest, + usec_t *next) { + + struct itimerspec its = {}; + sd_event_source *a, *b; + usec_t t; + int r; + + assert(e); + assert(next); + + a = prioq_peek(earliest); + if (!a || a->enabled == SD_EVENT_OFF) { + + if (timer_fd < 0) + return 0; + + if (*next == (usec_t) -1) + return 0; + + /* disarm */ + r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + if (r < 0) + return r; + + *next = (usec_t) -1; + + return 0; + } + + b = prioq_peek(latest); + assert_se(b && b->enabled != SD_EVENT_OFF); + + t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy); + if (*next == t) + return 0; + + assert_se(timer_fd >= 0); + + if (t == 0) { + /* We don' want to disarm here, just mean some time looooong ago. */ + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 1; + } else + timespec_store(&its.it_value, t); + + r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL); + if (r < 0) + return -errno; + + *next = t; + return 0; +} + +static int process_io(sd_event *e, sd_event_source *s, uint32_t revents) { + assert(e); + assert(s); + assert(s->type == SOURCE_IO); + + /* If the event source was already pending, we just OR in the + * new revents, otherwise we reset the value. The ORing is + * necessary to handle EPOLLONESHOT events properly where + * readability might happen independently of writability, and + * we need to keep track of both */ + + if (s->pending) + s->io.revents |= revents; + else + s->io.revents = revents; + + return source_set_pending(s, true); +} + +static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) { + uint64_t x; + ssize_t ss; + + assert(e); + assert(fd >= 0); + + assert_return(events == EPOLLIN, -EIO); + + ss = read(fd, &x, sizeof(x)); + if (ss < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return -errno; + } + + if (_unlikely_(ss != sizeof(x))) + return -EIO; + + if (next) + *next = (usec_t) -1; + + return 0; +} + +static int process_timer( + sd_event *e, + usec_t n, + Prioq *earliest, + Prioq *latest) { + + sd_event_source *s; + int r; + + assert(e); + + for (;;) { + s = prioq_peek(earliest); + if (!s || + s->time.next > n || + s->enabled == SD_EVENT_OFF || + s->pending) + break; + + r = source_set_pending(s, true); + if (r < 0) + return r; + + prioq_reshuffle(earliest, s, &s->time.earliest_index); + prioq_reshuffle(latest, s, &s->time.latest_index); + } + + return 0; +} + +static int process_child(sd_event *e) { + sd_event_source *s; + Iterator i; + int r; + + assert(e); + + e->need_process_child = false; + + /* + So, this is ugly. We iteratively invoke waitid() with P_PID + + WNOHANG for each PID we wait for, instead of using + P_ALL. This is because we only want to get child + information of very specific child processes, and not all + of them. We might not have processed the SIGCHLD even of a + previous invocation and we don't want to maintain a + unbounded *per-child* event queue, hence we really don't + want anything flushed out of the kernel's queue that we + don't care about. Since this is O(n) this means that if you + have a lot of processes you probably want to handle SIGCHLD + yourself. + + We do not reap the children here (by using WNOWAIT), this + is only done after the event source is dispatched so that + the callback still sees the process as a zombie. + */ + + HASHMAP_FOREACH(s, e->child_sources, i) { + assert(s->type == SOURCE_CHILD); + + if (s->pending) + continue; + + if (s->enabled == SD_EVENT_OFF) + continue; + + zero(s->child.siginfo); + r = waitid(P_PID, s->child.pid, &s->child.siginfo, + WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options); + if (r < 0) + return -errno; + + if (s->child.siginfo.si_pid != 0) { + bool zombie = + s->child.siginfo.si_code == CLD_EXITED || + s->child.siginfo.si_code == CLD_KILLED || + s->child.siginfo.si_code == CLD_DUMPED; + + if (!zombie && (s->child.options & WEXITED)) { + /* If the child isn't dead then let's + * immediately remove the state change + * from the queue, since there's no + * benefit in leaving it queued */ + + assert(s->child.options & (WSTOPPED|WCONTINUED)); + waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); + } + + r = source_set_pending(s, true); + if (r < 0) + return r; + } + } + + return 0; +} + +static int process_signal(sd_event *e, uint32_t events) { + bool read_one = false; + int r; + + assert(e); + assert(e->signal_sources); + + assert_return(events == EPOLLIN, -EIO); + + for (;;) { + struct signalfd_siginfo si; + ssize_t ss; + sd_event_source *s; + + ss = read(e->signal_fd, &si, sizeof(si)); + if (ss < 0) { + if (errno == EAGAIN || errno == EINTR) + return read_one; + + return -errno; + } + + if (_unlikely_(ss != sizeof(si))) + return -EIO; + + read_one = true; + + s = e->signal_sources[si.ssi_signo]; + if (si.ssi_signo == SIGCHLD) { + r = process_child(e); + if (r < 0) + return r; + if (r > 0 || !s) + continue; + } else + if (!s) + return -EIO; + + s->signal.siginfo = si; + r = source_set_pending(s, true); + if (r < 0) + return r; + } + + return 0; +} + +static int source_dispatch(sd_event_source *s) { + int r = 0; + + assert(s); + assert(s->pending || s->type == SOURCE_EXIT); + + if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + + if (s->type != SOURCE_POST) { + sd_event_source *z; + Iterator i; + + /* If we execute a non-post source, let's mark all + * post sources as pending */ + + SET_FOREACH(z, s->event->post_sources, i) { + if (z->enabled == SD_EVENT_OFF) + continue; + + r = source_set_pending(z, true); + if (r < 0) + return r; + } + } + + if (s->enabled == SD_EVENT_ONESHOT) { + r = sd_event_source_set_enabled(s, SD_EVENT_OFF); + if (r < 0) + return r; + } + + s->dispatching = true; + + switch (s->type) { + + case SOURCE_IO: + r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata); + break; + + case SOURCE_MONOTONIC: + r = s->time.callback(s, s->time.next, s->userdata); + break; + + case SOURCE_REALTIME: + r = s->time.callback(s, s->time.next, s->userdata); + break; + + case SOURCE_SIGNAL: + r = s->signal.callback(s, &s->signal.siginfo, s->userdata); + break; + + case SOURCE_CHILD: { + bool zombie; + + zombie = s->child.siginfo.si_code == CLD_EXITED || + s->child.siginfo.si_code == CLD_KILLED || + s->child.siginfo.si_code == CLD_DUMPED; + + r = s->child.callback(s, &s->child.siginfo, s->userdata); + + /* Now, reap the PID for good. */ + if (zombie) + waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + + break; + } + + case SOURCE_DEFER: + r = s->defer.callback(s, s->userdata); + break; + + case SOURCE_POST: + r = s->post.callback(s, s->userdata); + break; + + case SOURCE_EXIT: + r = s->exit.callback(s, s->userdata); + break; + + case SOURCE_WATCHDOG: + assert_not_reached("Wut? I shouldn't exist."); + } + + s->dispatching = false; + + if (r < 0) + log_debug("Event source %p returned error, disabling: %s", s, strerror(-r)); + + if (s->n_ref == 0) + source_free(s); + else if (r < 0) + sd_event_source_set_enabled(s, SD_EVENT_OFF); + + return 1; +} + +static int event_prepare(sd_event *e) { + int r; + + assert(e); + + for (;;) { + sd_event_source *s; + + s = prioq_peek(e->prepare); + if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) + break; + + s->prepare_iteration = e->iteration; + r = prioq_reshuffle(e->prepare, s, &s->prepare_index); + if (r < 0) + return r; + + assert(s->prepare); + + s->dispatching = true; + r = s->prepare(s, s->userdata); + s->dispatching = false; + + if (r < 0) + log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r)); + + if (s->n_ref == 0) + source_free(s); + else if (r < 0) + sd_event_source_set_enabled(s, SD_EVENT_OFF); + } + + return 0; +} + +static int dispatch_exit(sd_event *e) { + sd_event_source *p; + int r; + + assert(e); + + p = prioq_peek(e->exit); + if (!p || p->enabled == SD_EVENT_OFF) { + e->state = SD_EVENT_FINISHED; + return 0; + } + + sd_event_ref(e); + e->iteration++; + e->state = SD_EVENT_EXITING; + + r = source_dispatch(p); + + e->state = SD_EVENT_PASSIVE; + sd_event_unref(e); + + return r; +} + +static sd_event_source* event_next_pending(sd_event *e) { + sd_event_source *p; + + assert(e); + + p = prioq_peek(e->pending); + if (!p) + return NULL; + + if (p->enabled == SD_EVENT_OFF) + return NULL; + + return p; +} + +static int arm_watchdog(sd_event *e) { + struct itimerspec its = {}; + usec_t t; + int r; + + assert(e); + assert(e->watchdog_fd >= 0); + + t = sleep_between(e, + e->watchdog_last + (e->watchdog_period / 2), + e->watchdog_last + (e->watchdog_period * 3 / 4)); + + timespec_store(&its.it_value, t); + + r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL); + if (r < 0) + return -errno; + + return 0; +} + +static int process_watchdog(sd_event *e) { + assert(e); + + if (!e->watchdog) + return 0; + + /* Don't notify watchdog too often */ + if (e->watchdog_last + e->watchdog_period / 4 > e->timestamp.monotonic) + return 0; + + sd_notify(false, "WATCHDOG=1"); + e->watchdog_last = e->timestamp.monotonic; + + return arm_watchdog(e); +} + +_public_ int sd_event_run(sd_event *e, uint64_t timeout) { + struct epoll_event *ev_queue; + unsigned ev_queue_max; + sd_event_source *p; + int r, i, m; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); + + if (e->exit_requested) + return dispatch_exit(e); + + sd_event_ref(e); + e->iteration++; + e->state = SD_EVENT_RUNNING; + + r = event_prepare(e); + if (r < 0) + goto finish; + + r = event_arm_timer(e, e->monotonic_fd, e->monotonic_earliest, e->monotonic_latest, &e->monotonic_next); + if (r < 0) + goto finish; + + r = event_arm_timer(e, e->realtime_fd, e->realtime_earliest, e->realtime_latest, &e->realtime_next); + if (r < 0) + goto finish; + + if (event_next_pending(e) || e->need_process_child) + timeout = 0; + ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX); + ev_queue = newa(struct epoll_event, ev_queue_max); + + 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)); + if (m < 0) { + r = errno == EAGAIN || errno == EINTR ? 1 : -errno; + goto finish; + } + + dual_timestamp_get(&e->timestamp); + + for (i = 0; i < m; i++) { + + if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_MONOTONIC)) + r = flush_timer(e, e->monotonic_fd, ev_queue[i].events, &e->monotonic_next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_REALTIME)) + r = flush_timer(e, e->realtime_fd, ev_queue[i].events, &e->realtime_next); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL)) + r = process_signal(e, ev_queue[i].events); + else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) + r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL); + else + r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + + if (r < 0) + goto finish; + } + + r = process_watchdog(e); + if (r < 0) + goto finish; + + r = process_timer(e, e->timestamp.monotonic, e->monotonic_earliest, e->monotonic_latest); + if (r < 0) + goto finish; + + r = process_timer(e, e->timestamp.realtime, e->realtime_earliest, e->realtime_latest); + if (r < 0) + goto finish; + + if (e->need_process_child) { + r = process_child(e); + if (r < 0) + goto finish; + } + + p = event_next_pending(e); + if (!p) { + r = 1; + goto finish; + } + + r = source_dispatch(p); + +finish: + e->state = SD_EVENT_PASSIVE; + sd_event_unref(e); + + return r; +} + +_public_ int sd_event_loop(sd_event *e) { + int r; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY); + + sd_event_ref(e); + + while (e->state != SD_EVENT_FINISHED) { + r = sd_event_run(e, (uint64_t) -1); + if (r < 0) + goto finish; + } + + r = e->exit_code; + +finish: + sd_event_unref(e); + return r; +} + +_public_ int sd_event_get_state(sd_event *e) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + return e->state; +} + +_public_ int sd_event_get_exit_code(sd_event *e, int *code) { + assert_return(e, -EINVAL); + assert_return(code, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + if (!e->exit_requested) + return -ENODATA; + + *code = e->exit_code; + return 0; +} + +_public_ int sd_event_exit(sd_event *e, int code) { + assert_return(e, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + e->exit_requested = true; + e->exit_code = code; + + return 0; +} + +_public_ int sd_event_get_now_realtime(sd_event *e, uint64_t *usec) { + assert_return(e, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA); + assert_return(!event_pid_changed(e), -ECHILD); + + *usec = e->timestamp.realtime; + return 0; +} + +_public_ int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec) { + assert_return(e, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(dual_timestamp_is_set(&e->timestamp), -ENODATA); + assert_return(!event_pid_changed(e), -ECHILD); + + *usec = e->timestamp.monotonic; + return 0; +} + +_public_ int sd_event_default(sd_event **ret) { + + static thread_local sd_event *default_event = NULL; + sd_event *e = NULL; + int r; + + if (!ret) + return !!default_event; + + if (default_event) { + *ret = sd_event_ref(default_event); + return 0; + } + + r = sd_event_new(&e); + if (r < 0) + return r; + + e->default_event_ptr = &default_event; + e->tid = gettid(); + default_event = e; + + *ret = e; + return 1; +} + +_public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { + assert_return(e, -EINVAL); + assert_return(tid, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + if (e->tid != 0) { + *tid = e->tid; + return 0; + } + + return -ENXIO; +} + +_public_ int sd_event_set_watchdog(sd_event *e, int b) { + int r; + + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + if (e->watchdog == !!b) + return e->watchdog; + + if (b) { + struct epoll_event ev = {}; + + r = sd_watchdog_enabled(false, &e->watchdog_period); + if (r <= 0) + return r; + + /* Issue first ping immediately */ + sd_notify(false, "WATCHDOG=1"); + e->watchdog_last = now(CLOCK_MONOTONIC); + + e->watchdog_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); + if (e->watchdog_fd < 0) + return -errno; + + r = arm_watchdog(e); + if (r < 0) + goto fail; + + ev.events = EPOLLIN; + ev.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG); + + r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev); + if (r < 0) { + r = -errno; + goto fail; + } + + } else { + if (e->watchdog_fd >= 0) { + epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); + close_nointr_nofail(e->watchdog_fd); + e->watchdog_fd = -1; + } + } + + e->watchdog = !!b; + return e->watchdog; + +fail: + close_nointr_nofail(e->watchdog_fd); + e->watchdog_fd = -1; + return r; +} + +_public_ int sd_event_get_watchdog(sd_event *e) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + return e->watchdog; +} diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c new file mode 100644 index 0000000..0b7e2e4 --- /dev/null +++ b/src/libsystemd/sd-event/test-event.c @@ -0,0 +1,248 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-event.h" +#include "log.h" +#include "util.h" + +static int prepare_handler(sd_event_source *s, void *userdata) { + log_info("preparing %c", PTR_TO_INT(userdata)); + return 1; +} + +static bool got_a, got_b, got_c, got_unref; +static unsigned got_d; + +static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + sd_event_source_unref(s); + got_unref = true; + return 0; +} + +static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + + log_info("got IO on %c", PTR_TO_INT(userdata)); + + if (userdata == INT_TO_PTR('a')) { + assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0); + assert_se(!got_a); + got_a = true; + } else if (userdata == INT_TO_PTR('b')) { + assert_se(!got_b); + got_b = true; + } else if (userdata == INT_TO_PTR('d')) { + got_d++; + if (got_d < 2) + assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0); + else + assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0); + } else + assert_not_reached("Yuck!"); + + return 1; +} + +static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) { + + assert(s); + assert(si); + + log_info("got child on %c", PTR_TO_INT(userdata)); + + assert(userdata == INT_TO_PTR('f')); + + assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0); + sd_event_source_unref(s); + + return 1; +} + +static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + sd_event_source *p = NULL; + sigset_t ss; + pid_t pid; + + assert(s); + assert(si); + + log_info("got signal on %c", PTR_TO_INT(userdata)); + + assert(userdata == INT_TO_PTR('e')); + + assert_se(sigemptyset(&ss) >= 0); + assert_se(sigaddset(&ss, SIGCHLD) >= 0); + assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0); + + pid = fork(); + assert_se(pid >= 0); + + if (pid == 0) + _exit(0); + + assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0); + assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); + + sd_event_source_unref(s); + + return 1; +} + +static int defer_handler(sd_event_source *s, void *userdata) { + sd_event_source *p = NULL; + sigset_t ss; + + assert(s); + + log_info("got defer on %c", PTR_TO_INT(userdata)); + + assert(userdata == INT_TO_PTR('d')); + + assert_se(sigemptyset(&ss) >= 0); + assert_se(sigaddset(&ss, SIGUSR1) >= 0); + assert_se(sigprocmask(SIG_BLOCK, &ss, NULL) >= 0); + assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0); + assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); + raise(SIGUSR1); + + sd_event_source_unref(s); + + return 1; +} + +static bool do_quit = false; + +static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) { + log_info("got timer on %c", PTR_TO_INT(userdata)); + + if (userdata == INT_TO_PTR('c')) { + + if (do_quit) { + sd_event_source *p; + + assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0); + assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0); + } else { + assert(!got_c); + got_c = true; + } + } else + assert_not_reached("Huh?"); + + return 2; +} + +static bool got_exit = false; + +static int exit_handler(sd_event_source *s, void *userdata) { + log_info("got quit handler on %c", PTR_TO_INT(userdata)); + + got_exit = true; + + return 3; +} + +int main(int argc, char *argv[]) { + sd_event *e = NULL; + sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL; + static const char ch = 'x'; + int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 }; + + assert_se(pipe(a) >= 0); + assert_se(pipe(b) >= 0); + assert_se(pipe(d) >= 0); + assert_se(pipe(k) >= 0); + + assert_se(sd_event_default(&e) >= 0); + + assert_se(sd_event_set_watchdog(e, true) >= 0); + + /* Test whether we cleanly can destroy an io event source from its own handler */ + got_unref = false; + assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0); + assert_se(write(k[1], &ch, 1) == 1); + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(got_unref); + + got_a = false, got_b = false, got_c = false, got_d = 0; + + /* Add a oneshot handler, trigger it, re-enable it, and trigger + * it again. */ + assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0); + assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0); + assert_se(write(d[1], &ch, 1) >= 0); + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(got_d == 1); + assert_se(write(d[1], &ch, 1) >= 0); + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(got_d == 2); + + assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0); + assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0); + assert_se(sd_event_add_monotonic(e, &z, 0, 0, time_handler, INT_TO_PTR('c')) >= 0); + assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0); + + assert_se(sd_event_source_set_priority(x, 99) >= 0); + assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0); + assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0); + assert_se(sd_event_source_set_priority(z, 50) >= 0); + assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); + assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0); + + assert_se(write(a[1], &ch, 1) >= 0); + assert_se(write(b[1], &ch, 1) >= 0); + + assert_se(!got_a && !got_b && !got_c); + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + + assert_se(!got_a && got_b && !got_c); + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + + assert_se(!got_a && got_b && got_c); + + assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + + assert_se(got_a && got_b && got_c); + + sd_event_source_unref(x); + sd_event_source_unref(y); + + do_quit = true; + assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0); + assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); + + assert_se(sd_event_loop(e) >= 0); + + sd_event_source_unref(z); + sd_event_source_unref(q); + + sd_event_source_unref(w); + + sd_event_unref(e); + + close_pipe(a); + close_pipe(b); + close_pipe(d); + close_pipe(k); + + return 0; +} diff --git a/src/libsystemd/sd-id128/Makefile b/src/libsystemd/sd-id128/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-id128/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-id128/libsystemd-id128.pc.in b/src/libsystemd/sd-id128/libsystemd-id128.pc.in new file mode 100644 index 0000000..bb65ffd --- /dev/null +++ b/src/libsystemd/sd-id128/libsystemd-id128.pc.in @@ -0,0 +1,18 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd 128 Bit ID Utility Library +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd-id128 +Cflags: -I${includedir} diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c new file mode 100644 index 0000000..a1e44e6 --- /dev/null +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -0,0 +1,226 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "sd-id128.h" + +_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) { + unsigned n; + + assert_return(s, NULL); + + for (n = 0; n < 16; n++) { + s[n*2] = hexchar(id.bytes[n] >> 4); + s[n*2+1] = hexchar(id.bytes[n] & 0xF); + } + + s[32] = 0; + + return s; +} + +_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { + unsigned n, i; + sd_id128_t t; + bool is_guid = false; + + assert_return(s, -EINVAL); + assert_return(ret, -EINVAL); + + for (n = 0, i = 0; n < 16;) { + int a, b; + + if (s[i] == '-') { + /* Is this a GUID? Then be nice, and skip over + * the dashes */ + + if (i == 8) + is_guid = true; + else if (i == 13 || i == 18 || i == 23) { + if (!is_guid) + return -EINVAL; + } else + return -EINVAL; + + i++; + continue; + } + + a = unhexchar(s[i++]); + if (a < 0) + return -EINVAL; + + b = unhexchar(s[i++]); + if (b < 0) + return -EINVAL; + + t.bytes[n++] = (a << 4) | b; + } + + if (i != (is_guid ? 36 : 32)) + return -EINVAL; + + if (s[i] != 0) + return -EINVAL; + + *ret = t; + return 0; +} + +static sd_id128_t make_v4_uuid(sd_id128_t id) { + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ + + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; + + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; + + return id; +} + +_public_ int sd_id128_get_machine(sd_id128_t *ret) { + static thread_local sd_id128_t saved_machine_id; + static thread_local bool saved_machine_id_valid = false; + _cleanup_close_ int fd = -1; + char buf[33]; + ssize_t k; + unsigned j; + sd_id128_t t; + + assert_return(ret, -EINVAL); + + if (saved_machine_id_valid) { + *ret = saved_machine_id; + return 0; + } + + fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + k = loop_read(fd, buf, 33, false); + if (k < 0) + return (int) k; + + if (k != 33) + return -EIO; + + if (buf[32] !='\n') + return -EIO; + + for (j = 0; j < 16; j++) { + int a, b; + + a = unhexchar(buf[j*2]); + b = unhexchar(buf[j*2+1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + } + + saved_machine_id = t; + saved_machine_id_valid = true; + + *ret = t; + return 0; +} + +_public_ int sd_id128_get_boot(sd_id128_t *ret) { + static thread_local sd_id128_t saved_boot_id; + static thread_local bool saved_boot_id_valid = false; + _cleanup_close_ int fd = -1; + char buf[36]; + ssize_t k; + unsigned j; + sd_id128_t t; + char *p; + + assert_return(ret, -EINVAL); + + if (saved_boot_id_valid) { + *ret = saved_boot_id; + return 0; + } + + fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + k = loop_read(fd, buf, 36, false); + if (k < 0) + return (int) k; + + if (k != 36) + return -EIO; + + for (j = 0, p = buf; j < 16; j++) { + int a, b; + + if (p >= buf + k) + return -EIO; + + if (*p == '-') + p++; + + a = unhexchar(p[0]); + b = unhexchar(p[1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + + p += 2; + } + + saved_boot_id = t; + saved_boot_id_valid = true; + + *ret = t; + return 0; +} + +_public_ int sd_id128_randomize(sd_id128_t *ret) { + sd_id128_t t; + int r; + + assert_return(ret, -EINVAL); + + r = dev_urandom(&t, sizeof(t)); + if (r < 0) + return r; + + /* Turn this into a valid v4 UUID, to be nice. Note that we + * only guarantee this for newly generated UUIDs, not for + * pre-existing ones.*/ + + *ret = make_v4_uuid(t); + return 0; +} diff --git a/src/libsystemd/sd-resolve/Makefile b/src/libsystemd/sd-resolve/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-resolve/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-resolve/resolve-util.h b/src/libsystemd/sd-resolve/resolve-util.h new file mode 100644 index 0000000..7da1d7b --- /dev/null +++ b/src/libsystemd/sd-resolve/resolve-util.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Daniel Buch + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo*, sd_resolve_freeaddrinfo); +#define _cleanup_resolve_unref_ _cleanup_(sd_resolve_unrefp) +#define _cleanup_resolve_addrinfo_free_ _cleanup_(sd_resolve_freeaddrinfop) diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c new file mode 100644 index 0000000..f05fe10 --- /dev/null +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -0,0 +1,1261 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2005-2008 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "list.h" +#include "socket-util.h" +#include "sd-resolve.h" + +#define WORKERS_MIN 1 +#define WORKERS_MAX 16 +#define QUERIES_MAX 256 +#define BUFSIZE 10240 + +typedef enum { + REQUEST_ADDRINFO, + RESPONSE_ADDRINFO, + REQUEST_NAMEINFO, + RESPONSE_NAMEINFO, + REQUEST_RES_QUERY, + REQUEST_RES_SEARCH, + RESPONSE_RES, + REQUEST_TERMINATE, + RESPONSE_DIED +} QueryType; + +enum { + REQUEST_RECV_FD, + REQUEST_SEND_FD, + RESPONSE_RECV_FD, + RESPONSE_SEND_FD, + _FD_MAX +}; + +struct sd_resolve { + bool dead:1; + pid_t original_pid; + + int fds[_FD_MAX]; + + pthread_t workers[WORKERS_MAX]; + unsigned n_valid_workers; + + unsigned current_id, current_index; + sd_resolve_query* queries[QUERIES_MAX]; + unsigned n_queries; + + LIST_HEAD(sd_resolve_query, done); + sd_resolve_query *done_tail; + unsigned n_done; +}; + +struct sd_resolve_query { + sd_resolve *resolve; + bool done:1; + unsigned id; + QueryType type; + + int ret; + int _errno; + int _h_errno; + struct addrinfo *addrinfo; + char *serv, *host; + + void *userdata; + + LIST_FIELDS(sd_resolve_query, done); +}; + +typedef struct RHeader { + QueryType type; + unsigned id; + size_t length; +} RHeader; + +typedef struct AddrInfoRequest { + struct RHeader header; + bool hints_valid; + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t node_len, service_len; +} AddrInfoRequest; + +typedef struct AddrInfoResponse { + struct RHeader header; + int ret; + int _errno; + int _h_errno; + /* followed by addrinfo_serialization[] */ +} AddrInfoResponse; + +typedef struct AddrInfoSerialization { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + size_t canonname_len; + /* Followed by ai_addr amd ai_canonname with variable lengths */ +} AddrInfoSerialization; + +typedef struct NameInfoRequest { + struct RHeader header; + int flags; + socklen_t sockaddr_len; + bool gethost:1, getserv:1; +} NameInfoRequest; + +typedef struct NameInfoResponse { + struct RHeader header; + size_t hostlen, servlen; + int ret; + int _errno; + int _h_errno; +} NameInfoResponse; + +typedef struct ResRequest { + struct RHeader header; + int class; + int type; + size_t dname_len; +} ResRequest; + +typedef struct ResResponse { + struct RHeader header; + int ret; + int _errno; + int _h_errno; +} ResResponse; + +typedef union Packet { + RHeader rheader; + AddrInfoRequest addrinfo_request; + AddrInfoResponse addrinfo_response; + NameInfoRequest nameinfo_request; + NameInfoResponse nameinfo_response; + ResRequest res_request; + ResResponse res_response; +} Packet; + +static int send_died(int out_fd) { + RHeader rh = {}; + + assert(out_fd >= 0); + + rh.type = RESPONSE_DIED; + rh.length = sizeof(rh); + + if (send(out_fd, &rh, rh.length, MSG_NOSIGNAL) < 0) + return -errno; + + return 0; +} + +static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) { + AddrInfoSerialization s; + size_t cnl, l; + + assert(p); + assert(ai); + assert(length); + assert(*length <= maxlength); + + cnl = ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0; + l = sizeof(AddrInfoSerialization) + ai->ai_addrlen + cnl; + + if (*length + l > maxlength) + return NULL; + + s.ai_flags = ai->ai_flags; + s.ai_family = ai->ai_family; + s.ai_socktype = ai->ai_socktype; + s.ai_protocol = ai->ai_protocol; + s.ai_addrlen = ai->ai_addrlen; + s.canonname_len = cnl; + + memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization)); + memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen); + + if (ai->ai_canonname) + memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl); + + *length += l; + return (uint8_t*) p + l; +} + +static int send_addrinfo_reply( + int out_fd, + unsigned id, + int ret, + struct addrinfo *ai, + int _errno, + int _h_errno) { + + AddrInfoResponse resp = {}; + struct msghdr mh = {}; + struct iovec iov[2]; + union { + AddrInfoSerialization ais; + uint8_t space[BUFSIZE]; + } buffer; + + assert(out_fd >= 0); + + resp.header.type = RESPONSE_ADDRINFO; + resp.header.id = id; + resp.header.length = sizeof(AddrInfoResponse); + resp.ret = ret; + resp._errno = _errno; + resp._h_errno = _h_errno; + + if (ret == 0 && ai) { + void *p = &buffer; + struct addrinfo *k; + + for (k = ai; k; k = k->ai_next) { + p = serialize_addrinfo(p, k, &resp.header.length, (uint8_t*) &buffer + BUFSIZE - (uint8_t*) p); + if (!p) { + freeaddrinfo(ai); + return -ENOBUFS; + } + } + } + + if (ai) + freeaddrinfo(ai); + + iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(AddrInfoResponse) }; + iov[1] = (struct iovec) { .iov_base = &buffer, .iov_len = resp.header.length - sizeof(AddrInfoResponse) }; + + mh.msg_iov = iov; + mh.msg_iovlen = ELEMENTSOF(iov); + + if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0) + return -errno; + + return 0; +} + +static int send_nameinfo_reply( + int out_fd, + unsigned id, + int ret, + const char *host, + const char *serv, + int _errno, + int _h_errno) { + + NameInfoResponse resp = {}; + struct msghdr mh = {}; + struct iovec iov[3]; + size_t hl, sl; + + assert(out_fd >= 0); + + sl = serv ? strlen(serv)+1 : 0; + hl = host ? strlen(host)+1 : 0; + + resp.header.type = RESPONSE_NAMEINFO; + resp.header.id = id; + resp.header.length = sizeof(NameInfoResponse) + hl + sl; + resp.ret = ret; + resp._errno = _errno; + resp._h_errno = _h_errno; + resp.hostlen = hl; + resp.servlen = sl; + + iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(NameInfoResponse) }; + iov[1] = (struct iovec) { .iov_base = (void*) host, .iov_len = hl }; + iov[2] = (struct iovec) { .iov_base = (void*) serv, .iov_len = sl }; + + mh.msg_iov = iov; + mh.msg_iovlen = ELEMENTSOF(iov); + + if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0) + return -errno; + + return 0; +} + +static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { + struct msghdr mh = {}; + struct iovec iov[2]; + ResResponse resp = {}; + size_t l; + + assert(out_fd >= 0); + + l = ret > 0 ? (size_t) ret : 0; + + resp.header.type = RESPONSE_RES; + resp.header.id = id; + resp.header.length = sizeof(ResResponse) + l; + resp.ret = ret; + resp._errno = _errno; + resp._h_errno = _h_errno; + + iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) }; + iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l }; + + mh.msg_iov = iov; + mh.msg_iovlen = ELEMENTSOF(iov); + + if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0) + return -errno; + + return 0; +} + +static int handle_request(int out_fd, const Packet *packet, size_t length) { + const RHeader *req; + + assert(out_fd >= 0); + assert(packet); + + req = &packet->rheader; + + assert(length >= sizeof(RHeader)); + assert(length == req->length); + + switch (req->type) { + + case REQUEST_ADDRINFO: { + const AddrInfoRequest *ai_req = &packet->addrinfo_request; + struct addrinfo hints = {}, *result = NULL; + const char *node, *service; + int ret; + + assert(length >= sizeof(AddrInfoRequest)); + assert(length == sizeof(AddrInfoRequest) + ai_req->node_len + ai_req->service_len); + + hints.ai_flags = ai_req->ai_flags; + hints.ai_family = ai_req->ai_family; + hints.ai_socktype = ai_req->ai_socktype; + hints.ai_protocol = ai_req->ai_protocol; + + node = ai_req->node_len ? (const char*) ai_req + sizeof(AddrInfoRequest) : NULL; + service = ai_req->service_len ? (const char*) ai_req + sizeof(AddrInfoRequest) + ai_req->node_len : NULL; + + ret = getaddrinfo( + node, service, + ai_req->hints_valid ? &hints : NULL, + &result); + + /* send_addrinfo_reply() frees result */ + return send_addrinfo_reply(out_fd, req->id, ret, result, errno, h_errno); + } + + case REQUEST_NAMEINFO: { + const NameInfoRequest *ni_req = &packet->nameinfo_request; + char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; + union sockaddr_union sa; + int ret; + + assert(length >= sizeof(NameInfoRequest)); + assert(length == sizeof(NameInfoRequest) + ni_req->sockaddr_len); + assert(sizeof(sa) >= ni_req->sockaddr_len); + + memcpy(&sa, (const uint8_t *) ni_req + sizeof(NameInfoRequest), ni_req->sockaddr_len); + + ret = getnameinfo(&sa.sa, ni_req->sockaddr_len, + ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0, + ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0, + ni_req->flags); + + return send_nameinfo_reply(out_fd, req->id, ret, + ret == 0 && ni_req->gethost ? hostbuf : NULL, + ret == 0 && ni_req->getserv ? servbuf : NULL, + errno, h_errno); + } + + case REQUEST_RES_QUERY: + case REQUEST_RES_SEARCH: { + const ResRequest *res_req = &packet->res_request; + union { + HEADER header; + uint8_t space[BUFSIZE]; + } answer; + const char *dname; + int ret; + + assert(length >= sizeof(ResRequest)); + assert(length == sizeof(ResRequest) + res_req->dname_len); + + dname = (const char *) req + sizeof(ResRequest); + + if (req->type == REQUEST_RES_QUERY) + ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); + else + ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); + + return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno); + } + + case REQUEST_TERMINATE: + /* Quit */ + return -ECONNRESET; + + default: + assert_not_reached("Unknown request"); + } + + return 0; +} + +static void* thread_worker(void *p) { + sd_resolve *resolve = p; + sigset_t fullset; + + /* No signals in this thread please */ + assert_se(sigfillset(&fullset) == 0); + assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0); + + /* Assign a pretty name to this thread */ + prctl(PR_SET_NAME, (unsigned long) "sd-resolve"); + + while (!resolve->dead) { + union { + Packet packet; + uint8_t space[BUFSIZE]; + } buf; + ssize_t length; + + length = recv(resolve->fds[REQUEST_RECV_FD], &buf, sizeof(buf), 0); + if (length < 0) { + if (errno == EINTR) + continue; + + break; + } + if (length == 0) + break; + + if (resolve->dead) + break; + + if (handle_request(resolve->fds[RESPONSE_SEND_FD], &buf.packet, (size_t) length) < 0) + break; + } + + send_died(resolve->fds[RESPONSE_SEND_FD]); + + return NULL; +} + +static int start_threads(sd_resolve *resolve, unsigned extra) { + unsigned n; + int r; + + n = resolve->n_queries - resolve->n_done + extra; + + if (n < WORKERS_MIN) + n = WORKERS_MIN; + if (n > WORKERS_MAX) + n = WORKERS_MAX; + + while (resolve->n_valid_workers < n) { + + r = pthread_create(&resolve->workers[resolve->n_valid_workers], NULL, thread_worker, resolve); + if (r != 0) + return -r; + + resolve->n_valid_workers ++; + } + + return 0; +} + +static bool resolve_pid_changed(sd_resolve *r) { + assert(r); + + /* We don't support people creating a resolver and keeping it + * around after fork(). Let's complain. */ + + return r->original_pid != getpid(); +} + +_public_ int sd_resolve_new(sd_resolve **ret) { + sd_resolve *resolve = NULL; + int i, r; + + assert_return(ret, -EINVAL); + + resolve = new0(sd_resolve, 1); + if (!resolve) + return -ENOMEM; + + for (i = 0; i < _FD_MAX; i++) + resolve->fds[i] = -1; + + resolve->original_pid = getpid(); + + r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + REQUEST_RECV_FD); + if (r < 0) { + r = -errno; + goto fail; + } + + r = socketpair(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, resolve->fds + RESPONSE_RECV_FD); + if (r < 0) { + r = -errno; + goto fail; + } + + fd_inc_sndbuf(resolve->fds[REQUEST_SEND_FD], QUERIES_MAX * BUFSIZE); + fd_inc_rcvbuf(resolve->fds[REQUEST_RECV_FD], QUERIES_MAX * BUFSIZE); + fd_inc_sndbuf(resolve->fds[RESPONSE_SEND_FD], QUERIES_MAX * BUFSIZE); + fd_inc_rcvbuf(resolve->fds[RESPONSE_RECV_FD], QUERIES_MAX * BUFSIZE); + + fd_nonblock(resolve->fds[RESPONSE_RECV_FD], true); + + *ret = resolve; + return 0; + +fail: + if (resolve) + sd_resolve_unref(resolve); + + return r; +} + +_public_ sd_resolve* sd_resolve_unref(sd_resolve *resolve) { + PROTECT_ERRNO; + + unsigned i; + + assert_return(resolve, NULL); + assert_return(!resolve_pid_changed(resolve), NULL); + + resolve->dead = true; + + if (resolve->fds[REQUEST_SEND_FD] >= 0) { + + RHeader req = { + .type = REQUEST_TERMINATE, + .length = sizeof(req) + }; + + /* Send one termination packet for each worker */ + for (i = 0; i < resolve->n_valid_workers; i++) + send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL); + } + + /* Now terminate them and wait until they are gone. */ + for (i = 0; i < resolve->n_valid_workers; i++) { + for (;;) { + if (pthread_join(resolve->workers[i], NULL) != EINTR) + break; + } + } + + /* Close all communication channels */ + for (i = 0; i < _FD_MAX; i++) + if (resolve->fds[i] >= 0) + close_nointr_nofail(resolve->fds[i]); + + for (i = 0; i < QUERIES_MAX && resolve->n_queries > 0; i++) + if (resolve->queries[i]) + sd_resolve_cancel(resolve->queries[i]); + + free(resolve); + return NULL; +} + +_public_ int sd_resolve_get_fd(sd_resolve *resolve) { + assert_return(resolve, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + return resolve->fds[RESPONSE_RECV_FD]; +} + +_public_ int sd_resolve_get_events(sd_resolve *resolve) { + assert_return(resolve, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + return resolve->n_queries > resolve->n_done ? POLLIN : 0; +} + +_public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) { + assert_return(resolve, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + *usec = (uint64_t) -1; + return 0; +} + +static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) { + sd_resolve_query *q; + + assert(resolve); + + q = resolve->queries[id % QUERIES_MAX]; + if (q) + if (q->id == id) + return q; + + return NULL; +} + +static void complete_query(sd_resolve_query *q) { + assert(q); + assert(!q->done); + + q->done = true; + LIST_PREPEND(done, q->resolve->done, q); + q->resolve->n_done ++; +} + +static int unserialize_addrinfo(const void **p, size_t *length, struct addrinfo **ret_ai) { + AddrInfoSerialization s; + size_t l; + struct addrinfo *ai; + + assert(p); + assert(*p); + assert(ret_ai); + assert(length); + + if (*length < sizeof(AddrInfoSerialization)) + return -EBADMSG; + + memcpy(&s, *p, sizeof(s)); + + l = sizeof(AddrInfoSerialization) + s.ai_addrlen + s.canonname_len; + if (*length < l) + return -EBADMSG; + + ai = new0(struct addrinfo, 1); + if (!ai) + return -ENOMEM; + + ai->ai_flags = s.ai_flags; + ai->ai_family = s.ai_family; + ai->ai_socktype = s.ai_socktype; + ai->ai_protocol = s.ai_protocol; + ai->ai_addrlen = s.ai_addrlen; + + if (s.ai_addrlen > 0) { + ai->ai_addr = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization), s.ai_addrlen); + if (!ai->ai_addr) { + free(ai); + return -ENOMEM; + } + } + + if (s.canonname_len > 0) { + ai->ai_canonname = memdup((const uint8_t*) *p + sizeof(AddrInfoSerialization) + s.ai_addrlen, s.canonname_len); + if (!ai->ai_canonname) { + free(ai->ai_addr); + free(ai); + return -ENOMEM; + } + } + + *length -= l; + *ret_ai = ai; + *p = ((const uint8_t*) *p) + l; + + return 0; +} + +static int handle_response(sd_resolve *resolve, const Packet *packet, size_t length) { + const RHeader *resp; + sd_resolve_query *q; + int r; + + assert(resolve); + + resp = &packet->rheader; + assert(resp); + assert(length >= sizeof(RHeader)); + assert(length == resp->length); + + if (resp->type == RESPONSE_DIED) { + resolve->dead = true; + return 0; + } + + q = lookup_query(resolve, resp->id); + if (!q) + return 0; + + switch (resp->type) { + + case RESPONSE_ADDRINFO: { + const AddrInfoResponse *ai_resp = &packet->addrinfo_response; + const void *p; + size_t l; + struct addrinfo *prev = NULL; + + assert(length >= sizeof(AddrInfoResponse)); + assert(q->type == REQUEST_ADDRINFO); + + q->ret = ai_resp->ret; + q->_errno = ai_resp->_errno; + q->_h_errno = ai_resp->_h_errno; + + l = length - sizeof(AddrInfoResponse); + p = (const uint8_t*) resp + sizeof(AddrInfoResponse); + + while (l > 0 && p) { + struct addrinfo *ai = NULL; + + r = unserialize_addrinfo(&p, &l, &ai); + if (r < 0) { + q->ret = EAI_SYSTEM; + q->_errno = -r; + q->_h_errno = 0; + freeaddrinfo(q->addrinfo); + q->addrinfo = NULL; + break; + } + + if (prev) + prev->ai_next = ai; + else + q->addrinfo = ai; + + prev = ai; + } + + complete_query(q); + break; + } + + case RESPONSE_NAMEINFO: { + const NameInfoResponse *ni_resp = &packet->nameinfo_response; + + assert(length >= sizeof(NameInfoResponse)); + assert(q->type == REQUEST_NAMEINFO); + + q->ret = ni_resp->ret; + q->_errno = ni_resp->_errno; + q->_h_errno = ni_resp->_h_errno; + + if (ni_resp->hostlen > 0) { + q->host = strndup((const char*) ni_resp + sizeof(NameInfoResponse), ni_resp->hostlen-1); + if (!q->host) { + q->ret = EAI_MEMORY; + q->_errno = ENOMEM; + q->_h_errno = 0; + } + } + + if (ni_resp->servlen > 0) { + q->serv = strndup((const char*) ni_resp + sizeof(NameInfoResponse) + ni_resp->hostlen, ni_resp->servlen-1); + if (!q->serv) { + q->ret = EAI_MEMORY; + q->_errno = ENOMEM; + q->_h_errno = 0; + } + } + + complete_query(q); + break; + } + + case RESPONSE_RES: { + const ResResponse *res_resp = &packet->res_response; + + assert(length >= sizeof(ResResponse)); + assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); + + q->ret = res_resp->ret; + q->_errno = res_resp->_errno; + q->_h_errno = res_resp->_h_errno; + + if (res_resp->ret >= 0) { + q->serv = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret); + if (!q->serv) { + q->ret = -1; + q->_errno = ENOMEM; + q->_h_errno = 0; + } + } + + complete_query(q); + break; + } + + default: + ; + } + + return 0; +} + +_public_ int sd_resolve_process(sd_resolve *resolve) { + int n_processed = 0, r; + + assert_return(resolve, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + for (;;) { + ssize_t l; + union { + Packet packet; + uint8_t space[BUFSIZE]; + } buf; + + l = recv(resolve->fds[RESPONSE_RECV_FD], &buf, sizeof(buf), 0); + if (l < 0) { + if (errno == EAGAIN) + return n_processed; + + return -errno; + } + if (l == 0) + return -ECONNREFUSED; + + r = handle_response(resolve, &buf.packet, (size_t) l); + if (r < 0) + return r; + + n_processed++; + } +} + +_public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) { + int r; + + assert_return(resolve, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + if (resolve->n_queries <= 0) + return 0; + + do { + r = fd_wait_for_event(resolve->fds[RESPONSE_RECV_FD], POLLIN, timeout_usec); + } while (r == -EINTR); + + if (r < 0) + return r; + + return sd_resolve_process(resolve); +} + +static int alloc_query(sd_resolve *resolve, sd_resolve_query **_q) { + sd_resolve_query *q; + int r; + + assert(resolve); + assert(_q); + + if (resolve->n_queries >= QUERIES_MAX) + return -ENOBUFS; + + r = start_threads(resolve, 1); + if (r < 0) + return r; + + while (resolve->queries[resolve->current_index]) { + resolve->current_index++; + resolve->current_id++; + + resolve->current_index %= QUERIES_MAX; + } + + q = resolve->queries[resolve->current_index] = new0(sd_resolve_query, 1); + if (!q) + return -ENOMEM; + + resolve->n_queries++; + + q->resolve = resolve; + q->id = resolve->current_id; + + *_q = q; + return 0; +} + +_public_ int sd_resolve_getaddrinfo( + sd_resolve *resolve, + sd_resolve_query **_q, + const char *node, + const char *service, + const struct addrinfo *hints) { + + AddrInfoRequest req = {}; + struct msghdr mh = {}; + struct iovec iov[3]; + sd_resolve_query *q; + int r; + + assert_return(resolve, -EINVAL); + assert_return(node || service, -EINVAL); + assert_return(_q, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + r = alloc_query(resolve, &q); + if (r < 0) + return r; + + req.node_len = node ? strlen(node)+1 : 0; + req.service_len = service ? strlen(service)+1 : 0; + + req.header.id = q->id; + req.header.type = q->type = REQUEST_ADDRINFO; + req.header.length = sizeof(AddrInfoRequest) + req.node_len + req.service_len; + + if (hints) { + req.hints_valid = true; + req.ai_flags = hints->ai_flags; + req.ai_family = hints->ai_family; + req.ai_socktype = hints->ai_socktype; + req.ai_protocol = hints->ai_protocol; + } + + iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(AddrInfoRequest) }; + + if (node) + iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) node, .iov_len = req.node_len }; + + if (service) + iov[mh.msg_iovlen++] = (struct iovec) { .iov_base = (void*) service, .iov_len = req.service_len }; + + mh.msg_iov = iov; + + if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) { + sd_resolve_cancel(q); + return -errno; + } + + *_q = q; + return 0; +} + +_public_ int sd_resolve_getaddrinfo_done(sd_resolve_query* q, struct addrinfo **ret_res) { + int ret; + + if (!q) { + errno = EINVAL; + return EAI_SYSTEM; + } + + if (q->type != REQUEST_ADDRINFO) { + errno = ENOTTY; + return EAI_SYSTEM; + } + + if (resolve_pid_changed(q->resolve)) { + errno = ECHILD; + return EAI_SYSTEM; + } + if (!q->done) + return EAI_AGAIN; + + if (ret_res) { + *ret_res = q->addrinfo; + q->addrinfo = NULL; + } + + ret = q->ret; + + if (ret != 0) { + errno = q->_errno; + h_errno = q->_h_errno; + } + + sd_resolve_cancel(q); + + return ret; +} + +_public_ int sd_resolve_getnameinfo( + sd_resolve *resolve, + sd_resolve_query**_q, + const struct sockaddr *sa, socklen_t salen, + int flags, + int gethost, int getserv) { + + NameInfoRequest req = {}; + struct msghdr mh = {}; + struct iovec iov[2]; + sd_resolve_query *q; + int r; + + assert_return(resolve, -EINVAL); + assert_return(sa, -EINVAL); + assert_return(salen >= sizeof(struct sockaddr), -EINVAL); + assert_return(salen <= sizeof(union sockaddr_union), -EINVAL); + assert_return(_q, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + r = alloc_query(resolve, &q); + if (r < 0) + return r; + + req.header.id = q->id; + req.header.type = q->type = REQUEST_NAMEINFO; + req.header.length = sizeof(NameInfoRequest) + salen; + + req.flags = flags; + req.sockaddr_len = salen; + req.gethost = !!gethost; + req.getserv = !!getserv; + + iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(NameInfoRequest) }; + iov[1] = (struct iovec) { .iov_base = (void*) sa, .iov_len = salen }; + + mh.msg_iov = iov; + mh.msg_iovlen = 2; + + if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) { + sd_resolve_cancel(q); + return -errno; + } + + *_q = q; + return 0; +} + +_public_ int sd_resolve_getnameinfo_done(sd_resolve_query* q, char **ret_host, char **ret_serv) { + int ret; + + if (!q) { + errno = EINVAL; + return EAI_SYSTEM; + } + + if (q->type != REQUEST_NAMEINFO) { + errno = ENOTTY; + return EAI_SYSTEM; + } + + if (resolve_pid_changed(q->resolve)) { + errno = ECHILD; + return EAI_SYSTEM; + } + + if (!q->done) + return EAI_AGAIN; + + if (ret_host) { + *ret_host = q->host; + q->host = NULL; + } + + if (ret_serv) { + *ret_serv = q->serv; + q->serv = NULL; + } + + ret = q->ret; + + if (ret != 0) { + errno = q->_errno; + h_errno = q->_h_errno; + } + + sd_resolve_cancel(q); + + return ret; +} + +static int resolve_res( + sd_resolve *resolve, + sd_resolve_query **_q, + QueryType qtype, + const char *dname, + int class, int type) { + + struct msghdr mh = {}; + struct iovec iov[2]; + ResRequest req = {}; + sd_resolve_query *q; + int r; + + assert_return(resolve, -EINVAL); + assert_return(dname, -EINVAL); + assert_return(_q, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + r = alloc_query(resolve, &q); + if (r < 0) + return r; + + req.dname_len = strlen(dname) + 1; + req.class = class; + req.type = type; + + req.header.id = q->id; + req.header.type = q->type = qtype; + req.header.length = sizeof(ResRequest) + req.dname_len; + + iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) }; + iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len }; + + mh.msg_iov = iov; + mh.msg_iovlen = 2; + + if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) { + sd_resolve_cancel(q); + return -errno; + } + + *_q = q; + return 0; +} + +_public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type) { + return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type); +} + +_public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type) { + return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type); +} + +_public_ int sd_resolve_res_done(sd_resolve_query* q, unsigned char **answer) { + int ret; + + assert_return(q, -EINVAL); + assert_return(answer, -EINVAL); + assert_return(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH, -ENOTTY); + assert_return(!resolve_pid_changed(q->resolve), -ECHILD); + + if (!q->done) + return -EAGAIN; + + *answer = (unsigned char *) q->serv; + q->serv = NULL; + + ret = q->ret; + + if (ret != 0) { + errno = q->_errno; + h_errno = q->_h_errno; + } + + sd_resolve_cancel(q); + + return ret < 0 ? -errno : ret; +} + +_public_ int sd_resolve_get_next(sd_resolve *resolve, sd_resolve_query **q) { + assert_return(resolve, -EINVAL); + assert_return(q, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + *q = resolve->done; + return !!resolve->done; +} + +_public_ int sd_resolve_get_n_queries(sd_resolve *resolve) { + assert_return(resolve, -EINVAL); + assert_return(!resolve_pid_changed(resolve), -ECHILD); + + return resolve->n_queries; +} + +_public_ int sd_resolve_cancel(sd_resolve_query* q) { + PROTECT_ERRNO; + int i; + + if (!q) + return 0; + + assert_return(!resolve_pid_changed(q->resolve), -ECHILD); + + assert(q->resolve); + assert(q->resolve->n_queries > 0); + + if (q->done) { + LIST_REMOVE(done, q->resolve->done, q); + q->resolve->n_done--; + } + + i = q->id % QUERIES_MAX; + assert(q->resolve->queries[i] == q); + q->resolve->queries[i] = NULL; + q->resolve->n_queries--; + + sd_resolve_freeaddrinfo(q->addrinfo); + free(q->host); + free(q->serv); + free(q); + + return 0; +} + +_public_ void sd_resolve_freeaddrinfo(struct addrinfo *ai) { + + while (ai) { + struct addrinfo *next = ai->ai_next; + + free(ai->ai_addr); + free(ai->ai_canonname); + free(ai); + + ai = next; + } +} + +_public_ int sd_resolve_is_done(sd_resolve_query *q) { + assert_return(q, -EINVAL); + assert_return(!resolve_pid_changed(q->resolve), -ECHILD); + + return q->done; +} + +_public_ void* sd_resolve_set_userdata(sd_resolve_query *q, void *userdata) { + void *ret; + + assert_return(q, NULL); + assert_return(!resolve_pid_changed(q->resolve), NULL); + + ret = q->userdata; + q->userdata = userdata; + + return ret; +} + +_public_ void* sd_resolve_get_userdata(sd_resolve_query *q) { + assert_return(q, NULL); + assert_return(!resolve_pid_changed(q->resolve), NULL); + + return q->userdata; +} diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c new file mode 100644 index 0000000..d3b2d55 --- /dev/null +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -0,0 +1,163 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2005-2008 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-resolve.h" +#include "resolve-util.h" +#include "macro.h" + +int main(int argc, char *argv[]) { + int r = 1; + _cleanup_resolve_unref_ sd_resolve *resolve = NULL; + _cleanup_resolve_addrinfo_free_ struct addrinfo *ai = NULL; + _cleanup_free_ unsigned char *srv = NULL; + sd_resolve_query *q1 = NULL, *q2 = NULL, *q3 = NULL; + struct addrinfo hints = {}; + struct sockaddr_in sa = {}; + _cleanup_free_ char *host = NULL, *serv = NULL; + + assert_se(sd_resolve_new(&resolve) >= 0); + + /* Make a name -> address query */ + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + + r = sd_resolve_getaddrinfo(resolve, &q1, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints); + if (r < 0) + log_error("sd_resolve_getaddrinfo(): %s\n", strerror(-r)); + + /* Make an address -> name query */ + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71"); + sa.sin_port = htons(80); + + r = sd_resolve_getnameinfo(resolve, &q2, (struct sockaddr*) &sa, sizeof(sa), 0, true, true); + if (r < 0) + log_error("sd_resolve_getnameinfo(): %s\n", strerror(-r)); + + /* Make a res_query() call */ + r = sd_resolve_res_query(resolve, &q3, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV); + if (r < 0) + log_error("sd_resolve_res_query(): %s\n", strerror(-r)); + + /* Wait until the three queries are completed */ + while (sd_resolve_is_done(q1) == 0 || + sd_resolve_is_done(q2) == 0 || + sd_resolve_is_done(q3) == 0) { + + r = sd_resolve_wait(resolve, (uint64_t) -1); + if (r < 0) { + log_error("sd_resolve_wait(): %s\n", strerror(-r)); + assert_not_reached("sd_resolve_wait() failed"); + } + } + + /* Interpret the result of the name -> addr query */ + r = sd_resolve_getaddrinfo_done(q1, &ai); + if (r != 0) + log_error("error: %s %i\n", gai_strerror(r), r); + else { + struct addrinfo *i; + + for (i = ai; i; i = i->ai_next) { + char t[256]; + const char *p = NULL; + + if (i->ai_family == PF_INET) + p = inet_ntop(AF_INET, &((struct sockaddr_in*) i->ai_addr)->sin_addr, t, sizeof(t)); + else if (i->ai_family == PF_INET6) + p = inet_ntop(AF_INET6, &((struct sockaddr_in6*) i->ai_addr)->sin6_addr, t, sizeof(t)); + + printf("%s\n", p); + } + + printf("canonical name: %s\n", strna(ai->ai_canonname)); + } + + /* Interpret the result of the addr -> name query */ + r = sd_resolve_getnameinfo_done(q2, &host, &serv); + if (r) + log_error("error: %s %i\n", gai_strerror(r), r); + else + printf("%s -- %s\n", host, serv); + + /* Interpret the result of the SRV lookup */ + r = sd_resolve_res_done(q3, &srv); + if (r < 0) + log_error("error: %s %i\n", strerror(-r), r); + else if (r == 0) + log_error("No reply for SRV lookup\n"); + else { + int qdcount; + int ancount; + int len; + const unsigned char *pos = srv + sizeof(HEADER); + unsigned char *end = srv + r; + HEADER *head = (HEADER *)srv; + char name[256]; + + qdcount = ntohs(head->qdcount); + ancount = ntohs(head->ancount); + + printf("%d answers for srv lookup:\n", ancount); + + /* Ignore the questions */ + while (qdcount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { + assert(len >= 0); + pos += len + QFIXEDSZ; + } + + /* Parse the answers */ + while (ancount-- > 0 && (len = dn_expand(srv, end, pos, name, 255)) >= 0) { + /* Ignore the initial string */ + uint16_t pref, weight, port; + assert(len >= 0); + pos += len; + /* Ignore type, ttl, class and dlen */ + pos += 10; + + GETSHORT(pref, pos); + GETSHORT(weight, pos); + GETSHORT(port, pos); + len = dn_expand(srv, end, pos, name, 255); + printf("\tpreference: %2d weight: %2d port: %d host: %s\n", + pref, weight, port, name); + + pos += len; + } + } + + r = 0; + + return r; +} diff --git a/src/libsystemd/sd-rtnl/Makefile b/src/libsystemd/sd-rtnl/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-rtnl/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h new file mode 100644 index 0000000..0667be5 --- /dev/null +++ b/src/libsystemd/sd-rtnl/rtnl-internal.h @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "refcnt.h" +#include "prioq.h" +#include "list.h" + +#include "sd-rtnl.h" + +#define RTNL_DEFAULT_TIMEOUT ((usec_t) (10 * USEC_PER_SEC)) + +#define RTNL_WQUEUE_MAX 1024 +#define RTNL_RQUEUE_MAX 64*1024 + +#define RTNL_CONTAINER_DEPTH 32 + +struct reply_callback { + sd_rtnl_message_handler_t callback; + void *userdata; + usec_t timeout; + uint64_t serial; + unsigned prioq_idx; +}; + +struct match_callback { + sd_rtnl_message_handler_t callback; + uint16_t type; + void *userdata; + + LIST_FIELDS(struct match_callback, match_callbacks); +}; + +struct sd_rtnl { + RefCount n_ref; + + int fd; + + union { + struct sockaddr sa; + struct sockaddr_nl nl; + } sockaddr; + + sd_rtnl_message **rqueue; + unsigned rqueue_size; + + sd_rtnl_message **wqueue; + unsigned wqueue_size; + + bool processing:1; + + uint32_t serial; + + struct Prioq *reply_callbacks_prioq; + Hashmap *reply_callbacks; + + LIST_HEAD(struct match_callback, match_callbacks); + + pid_t original_pid; + + sd_event_source *io_event_source; + sd_event_source *time_event_source; + sd_event_source *exit_event_source; + sd_event *event; +}; + +struct sd_rtnl_message { + RefCount n_ref; + + sd_rtnl *rtnl; + + struct nlmsghdr *hdr; + size_t container_offsets[RTNL_CONTAINER_DEPTH]; /* offset from hdr to each container's start */ + unsigned n_containers; /* number of containers */ + size_t next_rta_offset; /* offset from hdr to next rta */ + + bool sealed:1; +}; + +int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size); + +int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m); +int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret); + +/* Make sure callbacks don't destroy the rtnl connection */ +#define RTNL_DONT_DESTROY(rtnl) \ + _cleanup_rtnl_unref_ _unused_ sd_rtnl *_dont_destroy_##rtnl = sd_rtnl_ref(rtnl) diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c new file mode 100644 index 0000000..8c20b8e --- /dev/null +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -0,0 +1,1032 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "refcnt.h" +#include "missing.h" + +#include "sd-rtnl.h" +#include "rtnl-util.h" +#include "rtnl-internal.h" + +#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL) +#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset)) +#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr; +#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; + +int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) { + sd_rtnl_message *m; + + assert_return(ret, -EINVAL); + assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL); + + m = new0(sd_rtnl_message, 1); + if (!m) + return -ENOMEM; + + m->hdr = malloc0(initial_size); + if (!m->hdr) { + free(m); + return -ENOMEM; + } + + m->n_ref = REFCNT_INIT; + + m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + m->sealed = false; + + if (rtnl) + m->rtnl = sd_rtnl_ref(rtnl); + + *ret = m; + + return 0; +} + +int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + if ((rtm->rtm_family == AF_INET && prefixlen > 32) || + (rtm->rtm_family == AF_INET6 && prefixlen > 128)) + return -ERANGE; + + rtm->rtm_dst_len = prefixlen; + + return 0; +} + +int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, unsigned char rtm_family) { + struct rtmsg *rtm; + int r; + + assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL); + assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL); + assert_return(ret, -EINVAL); + + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct rtmsg))); + if (r < 0) + return r; + + (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + (*ret)->hdr->nlmsg_type = nlmsg_type; + if (nlmsg_type == RTM_NEWROUTE) + (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + + rtm = NLMSG_DATA((*ret)->hdr); + + UPDATE_RTA(*ret, RTM_RTA(rtm)); + + rtm->rtm_family = rtm_family; + rtm->rtm_scope = RT_SCOPE_UNIVERSE; + rtm->rtm_type = RTN_UNICAST; + rtm->rtm_table = RT_TABLE_MAIN; + rtm->rtm_protocol = RTPROT_BOOT; + + return 0; +} + +int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) { + struct ifinfomsg *ifi; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); + assert_return(change, -EINVAL); + + ifi = NLMSG_DATA(m->hdr); + + ifi->ifi_flags = flags; + ifi->ifi_change = change; + + return 0; +} + +int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) { + struct ifinfomsg *ifi; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); + + ifi = NLMSG_DATA(m->hdr); + + ifi->ifi_type = type; + + return 0; +} + +int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, int index) { + struct ifinfomsg *ifi; + int r; + + assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); + assert_return(nlmsg_type == RTM_NEWLINK || + nlmsg_type == RTM_SETLINK || index > 0, -EINVAL); + assert_return(ret, -EINVAL); + + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifinfomsg))); + if (r < 0) + return r; + + (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + (*ret)->hdr->nlmsg_type = nlmsg_type; + if (nlmsg_type == RTM_NEWLINK) + (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE; + + ifi = NLMSG_DATA((*ret)->hdr); + + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = index; + + UPDATE_RTA(*ret, IFLA_RTA(ifi)); + + return 0; +} + +int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) { + struct ifaddrmsg *ifa; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL); + + ifa = NLMSG_DATA(m->hdr); + + if ((ifa->ifa_family == AF_INET && prefixlen > 32) || + (ifa->ifa_family == AF_INET6 && prefixlen > 128)) + return -ERANGE; + + ifa->ifa_prefixlen = prefixlen; + + return 0; +} + +int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) { + struct ifaddrmsg *ifa; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL); + + ifa = NLMSG_DATA(m->hdr); + + ifa->ifa_flags = flags; + + return 0; +} + +int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) { + struct ifaddrmsg *ifa; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL); + + ifa = NLMSG_DATA(m->hdr); + + ifa->ifa_scope = scope; + + return 0; +} + +int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, + uint16_t nlmsg_type, int index, + unsigned char family) { + struct ifaddrmsg *ifa; + int r; + + assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL); + assert_return(index > 0, -EINVAL); + assert_return(family == AF_INET || family == AF_INET6, -EINVAL); + assert_return(ret, -EINVAL); + + r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifaddrmsg))); + if (r < 0) + return r; + + (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + (*ret)->hdr->nlmsg_type = nlmsg_type; + if (nlmsg_type == RTM_GETADDR && family == AF_INET) + (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP; + + ifa = NLMSG_DATA((*ret)->hdr); + + ifa->ifa_index = index; + ifa->ifa_family = family; + if (family == AF_INET) + ifa->ifa_prefixlen = 32; + else if (family == AF_INET6) + ifa->ifa_prefixlen = 128; + + UPDATE_RTA(*ret, IFA_RTA(ifa)); + + return 0; +} + +sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) { + if (m) + assert_se(REFCNT_INC(m->n_ref) >= 2); + + return m; +} + +sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { + if (m && REFCNT_DEC(m->n_ref) <= 0) { + sd_rtnl_unref(m->rtnl); + free(m->hdr); + free(m); + } + + return NULL; +} + +int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) { + assert_return(m, -EINVAL); + assert_return(type, -EINVAL); + + *type = m->hdr->nlmsg_type; + + return 0; +} + +int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) { + struct ifinfomsg *ifi; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); + assert_return(ifindex, -EINVAL); + + ifi = NLMSG_DATA(m->hdr); + + *ifindex = ifi->ifi_index; + + return 0; +} + +int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) { + struct ifinfomsg *ifi; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); + assert_return(flags, -EINVAL); + + ifi = NLMSG_DATA(m->hdr); + + *flags = ifi->ifi_flags; + + return 0; +} + +/* If successful the updated message will be correctly aligned, if + unsuccessful the old message is untouched. */ +static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) { + uint32_t rta_length, message_length; + struct nlmsghdr *new_hdr; + struct rtattr *rta; + char *padding; + unsigned i; + + assert(m); + assert(m->hdr); + assert(!m->sealed); + assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len); + assert(!data || data_length > 0); + assert(data || m->n_containers < RTNL_CONTAINER_DEPTH); + + /* get the size of the new rta attribute (with padding at the end) */ + rta_length = RTA_LENGTH(data_length); + + /* get the new message size (with padding at the end) */ + message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length); + + /* realloc to fit the new attribute */ + new_hdr = realloc(m->hdr, message_length); + if (!new_hdr) + return -ENOMEM; + m->hdr = new_hdr; + + /* get pointer to the attribute we are about to add */ + rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len); + + /* if we are inside containers, extend them */ + for (i = 0; i < m->n_containers; i++) + GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len; + + /* fill in the attribute */ + rta->rta_type = type; + rta->rta_len = rta_length; + if (!data) { + /* this is the start of a new container */ + m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len; + } else { + /* we don't deal with the case where the user lies about the type + * and gives us too little data (so don't do that) + */ + padding = mempcpy(RTA_DATA(rta), data, data_length); + /* make sure also the padding at the end of the message is initialized */ + memzero(padding, + (uint8_t *) m->hdr + message_length - (uint8_t *) padding); + } + + /* update message size */ + m->hdr->nlmsg_len = message_length; + + return 0; +} + +int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) { + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + /* check that the type is correct */ + switch (rtm_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + if (m->n_containers == 1) { + if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO || + type != IFLA_INFO_KIND) + return -ENOTSUP; + } else { + switch (type) { + case IFLA_IFNAME: + case IFLA_IFALIAS: + case IFLA_QDISC: + break; + default: + return -ENOTSUP; + } + } + break; + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + if (type != IFA_LABEL) + return -ENOTSUP; + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, data, strlen(data) + 1); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) { + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + switch (rtm_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + switch (type) { + case IFLA_CARRIER: + case IFLA_OPERSTATE: + case IFLA_LINKMODE: + break; + default: + return -ENOTSUP; + } + + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, &data, sizeof(uint8_t)); + if (r < 0) + return r; + + return 0; +} + + +int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) { + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + /* check that the type is correct */ + switch (rtm_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + if (m->n_containers == 2 && + GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO && + GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA && + type == IFLA_VLAN_ID) + break; + else + return -ENOTSUP; + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, &data, sizeof(uint16_t)); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) { + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + /* check that the type is correct */ + switch (rtm_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + switch (type) { + case IFLA_MASTER: + case IFLA_MTU: + case IFLA_LINK: + case IFLA_GROUP: + case IFLA_TXQLEN: + case IFLA_WEIGHT: + case IFLA_NET_NS_FD: + case IFLA_NET_NS_PID: + case IFLA_PROMISCUITY: + case IFLA_NUM_TX_QUEUES: + case IFLA_NUM_RX_QUEUES: + break; + default: + return -ENOTSUP; + } + break; + case RTM_NEWROUTE: + case RTM_GETROUTE: + case RTM_DELROUTE: + switch (type) { + case RTA_TABLE: + case RTA_PRIORITY: + case RTA_IIF: + case RTA_OIF: + case RTA_MARK: + break; + default: + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, &data, sizeof(uint32_t)); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) { + struct ifaddrmsg *ifa; + struct rtmsg *rtm; + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + /* check that the type is correct */ + switch (rtm_type) { + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + switch (type) { + case IFA_ADDRESS: + case IFA_LOCAL: + case IFA_BROADCAST: + case IFA_ANYCAST: + ifa = NLMSG_DATA(m->hdr); + + if (ifa->ifa_family != AF_INET) + return -EINVAL; + + break; + default: + return -ENOTSUP; + } + break; + case RTM_NEWROUTE: + case RTM_GETROUTE: + case RTM_DELROUTE: + switch (type) { + case RTA_DST: + case RTA_SRC: + case RTA_GATEWAY: + rtm = NLMSG_DATA(m->hdr); + + if (rtm->rtm_family != AF_INET) + return -EINVAL; + + break; + default: + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, data, sizeof(struct in_addr)); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) { + struct ifaddrmsg *ifa; + struct rtmsg *rtm; + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + /* check that the type is correct */ + switch (rtm_type) { + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + switch (type) { + case IFA_ADDRESS: + case IFA_LOCAL: + case IFA_BROADCAST: + case IFA_ANYCAST: + ifa = NLMSG_DATA(m->hdr); + + if (ifa->ifa_family != AF_INET6) + return -EINVAL; + + break; + default: + return -ENOTSUP; + } + break; + case RTM_NEWROUTE: + case RTM_GETROUTE: + case RTM_DELROUTE: + switch (type) { + case RTA_DST: + case RTA_SRC: + case RTA_GATEWAY: + rtm = NLMSG_DATA(m->hdr); + + if (rtm->rtm_family != AF_INET6) + return -EINVAL; + + break; + default: + return -ENOTSUP; + } + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, data, sizeof(struct in6_addr)); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) { + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + + sd_rtnl_message_get_type(m, &rtm_type); + + switch (rtm_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_DELLINK: + case RTM_GETLINK: + switch (type) { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + break; + default: + return -ENOTSUP; + } + break; + default: + return -ENOTSUP; + } + + r = add_rtattr(m, type, data, ETH_ALEN); + if (r < 0) + return r; + + return 0; +} + +int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) { + uint16_t rtm_type; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + sd_rtnl_message_get_type(m, &rtm_type); + + if (rtnl_message_type_is_link(rtm_type)) { + + if ((type == IFLA_LINKINFO && m->n_containers == 0) || + (type == IFLA_INFO_DATA && m->n_containers == 1 && + GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO)) + return add_rtattr(m, type, NULL, 0); + else if (type == VETH_INFO_PEER && m->n_containers == 2 && + GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA && + GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO) + return add_rtattr(m, type, NULL, sizeof(struct ifinfomsg)); + } + + return -ENOTSUP; +} + +int sd_rtnl_message_close_container(sd_rtnl_message *m) { + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(m->n_containers > 0, -EINVAL); + + m->n_containers --; + + return 0; +} + +int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) { + size_t remaining_size; + uint16_t rtm_type; + int r; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(m->next_rta_offset, -EINVAL); + assert_return(type, -EINVAL); + assert_return(data, -EINVAL); + + /* only read until the end of the current container */ + if (m->n_containers) + remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len - + (m->next_rta_offset - + m->container_offsets[m->n_containers - 1]); + else + remaining_size = m->hdr->nlmsg_len - m->next_rta_offset; + + if (!RTA_OK(NEXT_RTA(m), remaining_size)) + return 0; + + /* if we read a container, enter it and return its type */ + r = sd_rtnl_message_get_type(m, &rtm_type); + if (r < 0) + return r; + + *type = NEXT_RTA(m)->rta_type; + + if (rtnl_message_type_is_link(rtm_type) && + ((m->n_containers == 0 && + NEXT_RTA(m)->rta_type == IFLA_LINKINFO) || + (m->n_containers == 1 && + GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO && + NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) { + *data = NULL; + PUSH_CONTAINER(m, NEXT_RTA(m)); + UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m))); + } else { + *data = RTA_DATA(NEXT_RTA(m)); + UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size)); + } + + return 1; +} + +int sd_rtnl_message_exit_container(sd_rtnl_message *m) { + assert_return(m, -EINVAL); + assert_return(m->sealed, -EINVAL); + assert_return(m->n_containers > 0, -EINVAL); + + m->n_containers --; + + return 0; +} + +uint32_t rtnl_message_get_serial(sd_rtnl_message *m) { + assert(m); + assert(m->hdr); + + return m->hdr->nlmsg_seq; +} + +int sd_rtnl_message_get_errno(sd_rtnl_message *m) { + struct nlmsgerr *err; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + + if (m->hdr->nlmsg_type != NLMSG_ERROR) + return 0; + + err = NLMSG_DATA(m->hdr); + + return err->error; +} + +int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) { + int r; + + assert(m); + assert(m->hdr); + + if (m->sealed) + return -EPERM; + + if (nl) + m->hdr->nlmsg_seq = nl->serial++; + + m->sealed = true; + + r = sd_rtnl_message_rewind(m); + if (r < 0) + return r; + + return 0; +} + +static int message_receive_need(sd_rtnl *rtnl, size_t *need) { + assert(rtnl); + assert(need); + + /* ioctl(rtnl->fd, FIONREAD, &need) + Does not appear to work on netlink sockets. libnl uses + MSG_PEEK instead. I don't know if that is worth the + extra roundtrip. + + For now we simply use the maximum message size the kernel + may use (NLMSG_GOODSIZE), and then realloc to the actual + size after reading the message (hence avoiding huge memory + usage in case many small messages are kept around) */ + *need = page_size(); + if (*need > 8192UL) + *need = 8192UL; + + return 0; +} + +/* returns the number of bytes sent, or a negative error code */ +int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { + union { + struct sockaddr sa; + struct sockaddr_nl nl; + } addr = { + .nl.nl_family = AF_NETLINK, + }; + ssize_t k; + + assert(nl); + assert(m); + assert(m->hdr); + + k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len, + 0, &addr.sa, sizeof(addr)); + if (k < 0) + return (errno == EAGAIN) ? 0 : -errno; + + return k; +} + +/* On success, the number of bytes received is returned and *ret points to the received message + * which has a valid header and the correct size. + * If nothing useful was received 0 is returned. + * On failure, a negative error code is returned. + */ +int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) { + sd_rtnl_message *m; + union { + struct sockaddr sa; + struct sockaddr_nl nl; + } addr; + socklen_t addr_len; + int r; + ssize_t k; + size_t need; + + assert(nl); + assert(ret); + + r = message_receive_need(nl, &need); + if (r < 0) + return r; + + r = message_new(nl, &m, need); + if (r < 0) + return r; + + /* don't allow sealing/appending to received messages */ + m->sealed = true; + + addr_len = sizeof(addr); + + k = recvfrom(nl->fd, m->hdr, need, + 0, &addr.sa, &addr_len); + if (k < 0) + k = (errno == EAGAIN) ? 0 : -errno; /* no data */ + else if (k == 0) + k = -ECONNRESET; /* connection was closed by the kernel */ + else if (addr_len != sizeof(addr.nl) || + addr.nl.nl_family != AF_NETLINK) + k = -EIO; /* not a netlink message */ + else if (addr.nl.nl_pid != 0) + k = 0; /* not from the kernel */ + else if ((size_t) k < sizeof(struct nlmsghdr) || + (size_t) k < m->hdr->nlmsg_len) + k = -EIO; /* too small (we do accept too big though) */ + else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid) + k = 0; /* not broadcast and not for us */ + + if (k > 0) + switch (m->hdr->nlmsg_type) { + struct ifinfomsg *ifi; + struct ifaddrmsg *ifa; + struct rtmsg *rtm; + + /* check that the size matches the message type */ + case NLMSG_ERROR: + if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) + k = -EIO; + break; + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_DELLINK: + case RTM_GETLINK: + if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) + k = -EIO; + else { + ifi = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, IFLA_RTA(ifi)); + } + break; + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_GETADDR: + if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg))) + k = -EIO; + else { + ifa = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, IFA_RTA(ifa)); + } + break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + case RTM_GETROUTE: + if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg))) + k = -EIO; + else { + rtm = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, RTM_RTA(rtm)); + } + break; + case NLMSG_NOOP: + k = 0; + break; + default: + k = 0; /* ignoring message of unknown type */ + } + + if (k <= 0) + sd_rtnl_message_unref(m); + else { + /* we probably allocated way too much memory, give it back */ + m->hdr = realloc(m->hdr, m->hdr->nlmsg_len); + *ret = m; + } + + return k; +} + +int sd_rtnl_message_rewind(sd_rtnl_message *m) { + struct ifinfomsg *ifi; + struct ifaddrmsg *ifa; + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->sealed, -EPERM); + assert_return(m->hdr, -EINVAL); + + switch(m->hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + ifi = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, IFLA_RTA(ifi)); + + break; + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + ifa = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, IFA_RTA(ifa)); + + break; + case RTM_NEWROUTE: + case RTM_GETROUTE: + case RTM_DELROUTE: + rtm = NLMSG_DATA(m->hdr); + UPDATE_RTA(m, RTM_RTA(rtm)); + + break; + default: + return -ENOTSUP; + } + + m->n_containers = 0; + + return 0; +} diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c new file mode 100644 index 0000000..fc834e9 --- /dev/null +++ b/src/libsystemd/sd-rtnl/rtnl-util.c @@ -0,0 +1,171 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-rtnl.h" + +#include "rtnl-util.h" +#include "rtnl-internal.h" + +int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL; + int r; + + assert(rtnl); + assert(ifindex > 0); + assert(name); + + r = sd_rtnl_message_new_link(rtnl, &message, RTM_SETLINK, ifindex); + if (r < 0) + return r; + + r = sd_rtnl_message_append_string(message, IFLA_IFNAME, name); + if (r < 0) + return r; + + r = sd_rtnl_call(rtnl, message, 0, NULL); + if (r < 0) + return r; + + return 0; +} + +int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, + const struct ether_addr *mac, unsigned mtu) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL; + bool need_update = false; + int r; + + assert(rtnl); + assert(ifindex > 0); + + if (!alias && !mac && mtu == 0) + return 0; + + r = sd_rtnl_message_new_link(rtnl, &message, RTM_SETLINK, ifindex); + if (r < 0) + return r; + + if (alias) { + r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias); + if (r < 0) + return r; + + need_update = true; + + } + + if (mac) { + r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac); + if (r < 0) + return r; + + need_update = true; + } + + if (mtu > 0) { + r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu); + if (r < 0) + return r; + + need_update = true; + } + + if (need_update) { + r = sd_rtnl_call(rtnl, message, 0, NULL); + if (r < 0) + return r; + } + + return 0; +} + +int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) { + struct nlmsgerr *err; + int r; + + assert(error <= 0); + + r = message_new(NULL, ret, NLMSG_SPACE(sizeof(struct nlmsgerr))); + if (r < 0) + return r; + + (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + (*ret)->hdr->nlmsg_type = NLMSG_ERROR; + (*ret)->hdr->nlmsg_seq = serial; + + err = NLMSG_DATA((*ret)->hdr); + + err->error = error; + + return 0; +} + +bool rtnl_message_type_is_route(uint16_t type) { + switch (type) { + case RTM_NEWROUTE: + case RTM_GETROUTE: + case RTM_DELROUTE: + return true; + default: + return false; + } +} + +bool rtnl_message_type_is_link(uint16_t type) { + switch (type) { + case RTM_NEWLINK: + case RTM_SETLINK: + case RTM_GETLINK: + case RTM_DELLINK: + return true; + default: + return false; + } +} + +bool rtnl_message_type_is_addr(uint16_t type) { + switch (type) { + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + return true; + default: + return false; + } +} + +int rtnl_message_link_get_ifname(sd_rtnl_message *message, const char **ret) { + unsigned short type; + void *name; + + assert(rtnl_message_type_is_link(message->hdr->nlmsg_type)); + + while (sd_rtnl_message_read(message, &type, &name)) { + if (type == IFLA_IFNAME) { + *ret = name; + return 0; + } + } + + return -ENOENT; +} diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h new file mode 100644 index 0000000..33746af --- /dev/null +++ b/src/libsystemd/sd-rtnl/rtnl-util.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "sd-rtnl.h" + +int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret); +uint32_t rtnl_message_get_serial(sd_rtnl_message *m); +int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m); + +bool rtnl_message_type_is_link(uint16_t type); +bool rtnl_message_type_is_addr(uint16_t type); +bool rtnl_message_type_is_route(uint16_t type); + +int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name); +int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu); + +int rtnl_message_link_get_ifname(sd_rtnl_message *m, const char **ret); + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl*, sd_rtnl_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl_message*, sd_rtnl_message_unref); + +#define _cleanup_rtnl_unref_ _cleanup_(sd_rtnl_unrefp) +#define _cleanup_rtnl_message_unref_ _cleanup_(sd_rtnl_message_unrefp) diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c new file mode 100644 index 0000000..1b9f583 --- /dev/null +++ b/src/libsystemd/sd-rtnl/sd-rtnl.c @@ -0,0 +1,872 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "macro.h" +#include "util.h" +#include "hashmap.h" + +#include "sd-rtnl.h" +#include "rtnl-internal.h" +#include "rtnl-util.h" + +static int sd_rtnl_new(sd_rtnl **ret) { + sd_rtnl *rtnl; + + assert_return(ret, -EINVAL); + + rtnl = new0(sd_rtnl, 1); + if (!rtnl) + return -ENOMEM; + + rtnl->n_ref = REFCNT_INIT; + + rtnl->fd = -1; + + rtnl->sockaddr.nl.nl_family = AF_NETLINK; + + rtnl->original_pid = getpid(); + + LIST_HEAD_INIT(rtnl->match_callbacks); + + /* We guarantee that wqueue always has space for at least + * one entry */ + rtnl->wqueue = new(sd_rtnl_message*, 1); + if (!rtnl->wqueue) { + free(rtnl); + return -ENOMEM; + } + + *ret = rtnl; + return 0; +} + +static bool rtnl_pid_changed(sd_rtnl *rtnl) { + assert(rtnl); + + /* We don't support people creating an rtnl connection and + * keeping it around over a fork(). Let's complain. */ + + return rtnl->original_pid != getpid(); +} + +int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + socklen_t addrlen; + int r; + + assert_return(ret, -EINVAL); + + r = sd_rtnl_new(&rtnl); + if (r < 0) + return r; + + rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE); + if (rtnl->fd < 0) + return -errno; + + rtnl->sockaddr.nl.nl_groups = groups; + + addrlen = sizeof(rtnl->sockaddr); + + r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen); + if (r < 0) + return -errno; + + r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen); + if (r < 0) + return r; + + *ret = rtnl; + rtnl = NULL; + + return 0; +} + +sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) { + if (rtnl) + assert_se(REFCNT_INC(rtnl->n_ref) >= 2); + + return rtnl; +} + +sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) { + + if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) { + struct match_callback *f; + unsigned i; + + for (i = 0; i < rtnl->rqueue_size; i++) + sd_rtnl_message_unref(rtnl->rqueue[i]); + free(rtnl->rqueue); + + for (i = 0; i < rtnl->wqueue_size; i++) + sd_rtnl_message_unref(rtnl->wqueue[i]); + free(rtnl->wqueue); + + hashmap_free_free(rtnl->reply_callbacks); + prioq_free(rtnl->reply_callbacks_prioq); + + while ((f = rtnl->match_callbacks)) { + LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); + free(f); + } + + if (rtnl->fd >= 0) + close_nointr_nofail(rtnl->fd); + + free(rtnl); + } + + return NULL; +} + +int sd_rtnl_send(sd_rtnl *nl, + sd_rtnl_message *message, + uint32_t *serial) { + int r; + + assert_return(nl, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(message, -EINVAL); + + r = rtnl_message_seal(nl, message); + if (r < 0) + return r; + + if (nl->wqueue_size <= 0) { + /* send directly */ + r = socket_write_message(nl, message); + if (r < 0) + return r; + else if (r == 0) { + /* nothing was sent, so let's put it on + * the queue */ + nl->wqueue[0] = sd_rtnl_message_ref(message); + nl->wqueue_size = 1; + } + } else { + sd_rtnl_message **q; + + /* append to queue */ + if (nl->wqueue_size >= RTNL_WQUEUE_MAX) + return -ENOBUFS; + + q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1)); + if (!q) + return -ENOMEM; + + nl->wqueue = q; + q[nl->wqueue_size ++] = sd_rtnl_message_ref(message); + } + + if (serial) + *serial = rtnl_message_get_serial(message); + + return 1; +} + +static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) { + sd_rtnl_message *z = NULL; + int r; + + assert(rtnl); + assert(message); + + if (rtnl->rqueue_size > 0) { + /* Dispatch a queued message */ + + *message = rtnl->rqueue[0]; + rtnl->rqueue_size --; + memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size); + + return 1; + } + + /* Try to read a new message */ + r = socket_read_message(rtnl, &z); + if (r < 0) + return r; + if (r == 0) + return 0; + + *message = z; + + return 1; +} + +static int dispatch_wqueue(sd_rtnl *rtnl) { + int r, ret = 0; + + assert(rtnl); + + while (rtnl->wqueue_size > 0) { + r = socket_write_message(rtnl, rtnl->wqueue[0]); + if (r < 0) + return r; + else if (r == 0) + /* Didn't do anything this time */ + return ret; + else { + /* see equivalent in sd-bus.c */ + sd_rtnl_message_unref(rtnl->wqueue[0]); + rtnl->wqueue_size --; + memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size); + + ret = 1; + } + } + + return ret; +} + +static int process_timeout(sd_rtnl *rtnl) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + struct reply_callback *c; + usec_t n; + int r; + + assert(rtnl); + + c = prioq_peek(rtnl->reply_callbacks_prioq); + if (!c) + return 0; + + n = now(CLOCK_MONOTONIC); + if (c->timeout > n) + return 0; + + r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m); + if (r < 0) + return r; + + assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c); + hashmap_remove(rtnl->reply_callbacks, &c->serial); + + r = c->callback(rtnl, m, c->userdata); + free(c); + + return r < 0 ? r : 1; +} + +static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) { + struct reply_callback *c; + uint64_t serial; + int r; + + assert(rtnl); + assert(m); + + serial = rtnl_message_get_serial(m); + c = hashmap_remove(rtnl->reply_callbacks, &serial); + if (!c) + return 0; + + if (c->timeout != 0) + prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx); + + r = c->callback(rtnl, m, c->userdata); + free(c); + + return r; +} + +static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) { + struct match_callback *c; + uint16_t type; + int r; + + assert(rtnl); + assert(m); + + r = sd_rtnl_message_get_type(m, &type); + if (r < 0) + return r; + + LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) { + if (type == c->type) { + r = c->callback(rtnl, m, c->userdata); + if (r != 0) + return r; + } + } + + return 0; +} + +static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + int r; + + assert(rtnl); + + r = process_timeout(rtnl); + if (r != 0) + goto null_message; + + r = dispatch_wqueue(rtnl); + if (r != 0) + goto null_message; + + r = dispatch_rqueue(rtnl, &m); + if (r < 0) + return r; + if (!m) + goto null_message; + + r = process_reply(rtnl, m); + if (r != 0) + goto null_message; + + r = process_match(rtnl, m); + if (r != 0) + goto null_message; + + if (ret) { + *ret = m; + m = NULL; + + return 1; + } + + return 1; + +null_message: + if (r >= 0 && ret) + *ret = NULL; + + return r; +} + +int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) { + RTNL_DONT_DESTROY(rtnl); + int r; + + assert_return(rtnl, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(!rtnl->processing, -EBUSY); + + rtnl->processing = true; + r = process_running(rtnl, ret); + rtnl->processing = false; + + return r; +} + +static usec_t calc_elapse(uint64_t usec) { + if (usec == (uint64_t) -1) + return 0; + + if (usec == 0) + usec = RTNL_DEFAULT_TIMEOUT; + + return now(CLOCK_MONOTONIC) + usec; +} + +static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) { + struct pollfd p[1] = {}; + struct timespec ts; + usec_t m = (usec_t) -1; + int r, e; + + assert(rtnl); + + e = sd_rtnl_get_events(rtnl); + if (e < 0) + return e; + + if (need_more) + /* Caller wants more data, and doesn't care about + * what's been read or any other timeouts. */ + return e |= POLLIN; + else { + usec_t until; + /* Caller wants to process if there is something to + * process, but doesn't care otherwise */ + + r = sd_rtnl_get_timeout(rtnl, &until); + if (r < 0) + return r; + if (r > 0) { + usec_t nw; + nw = now(CLOCK_MONOTONIC); + m = until > nw ? until - nw : 0; + } + } + + if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) + m = timeout_usec; + + p[0].fd = rtnl->fd; + p[0].events = e; + + r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); + if (r < 0) + return -errno; + + return r > 0 ? 1 : 0; +} + +int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) { + assert_return(nl, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + + if (nl->rqueue_size > 0) + return 0; + + return rtnl_poll(nl, false, timeout_usec); +} + +static int timeout_compare(const void *a, const void *b) { + const struct reply_callback *x = a, *y = b; + + if (x->timeout != 0 && y->timeout == 0) + return -1; + + if (x->timeout == 0 && y->timeout != 0) + return 1; + + if (x->timeout < y->timeout) + return -1; + + if (x->timeout > y->timeout) + return 1; + + return 0; +} + +int sd_rtnl_call_async(sd_rtnl *nl, + sd_rtnl_message *m, + sd_rtnl_message_handler_t callback, + void *userdata, + uint64_t usec, + uint32_t *serial) { + struct reply_callback *c; + uint32_t s; + int r, k; + + assert_return(nl, -EINVAL); + assert_return(m, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + + r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func); + if (r < 0) + return r; + + if (usec != (uint64_t) -1) { + r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare); + if (r < 0) + return r; + } + + c = new0(struct reply_callback, 1); + if (!c) + return -ENOMEM; + + c->callback = callback; + c->userdata = userdata; + c->timeout = calc_elapse(usec); + + k = sd_rtnl_send(nl, m, &s); + if (k < 0) { + free(c); + return k; + } + + c->serial = s; + + r = hashmap_put(nl->reply_callbacks, &c->serial, c); + if (r < 0) { + free(c); + return r; + } + + if (c->timeout != 0) { + r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx); + if (r > 0) { + c->timeout = 0; + sd_rtnl_call_async_cancel(nl, c->serial); + return r; + } + } + + if (serial) + *serial = s; + + return k; +} + +int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) { + struct reply_callback *c; + uint64_t s = serial; + + assert_return(nl, -EINVAL); + assert_return(serial != 0, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + + c = hashmap_remove(nl->reply_callbacks, &s); + if (!c) + return 0; + + if (c->timeout != 0) + prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx); + + free(c); + return 1; +} + +int sd_rtnl_call(sd_rtnl *nl, + sd_rtnl_message *message, + uint64_t usec, + sd_rtnl_message **ret) { + usec_t timeout; + uint32_t serial; + bool room = false; + int r; + + assert_return(nl, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(message, -EINVAL); + + r = sd_rtnl_send(nl, message, &serial); + if (r < 0) + return r; + + timeout = calc_elapse(usec); + + for (;;) { + usec_t left; + _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL; + + if (!room) { + sd_rtnl_message **q; + + if (nl->rqueue_size >= RTNL_RQUEUE_MAX) + return -ENOBUFS; + + /* Make sure there's room for queueing this + * locally, before we read the message */ + + q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*)); + if (!q) + return -ENOMEM; + + nl->rqueue = q; + room = true; + } + + r = socket_read_message(nl, &incoming); + if (r < 0) + return r; + if (incoming) { + uint32_t received_serial = rtnl_message_get_serial(incoming); + + if (received_serial == serial) { + r = sd_rtnl_message_get_errno(incoming); + if (r < 0) + return r; + + if (ret) { + *ret = incoming; + incoming = NULL; + } + + return 1; + } + + /* Room was allocated on the queue above */ + nl->rqueue[nl->rqueue_size ++] = incoming; + incoming = NULL; + room = false; + + /* Try to read more, right away */ + continue; + } + if (r != 0) + continue; + + if (timeout > 0) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + if (n >= timeout) + return -ETIMEDOUT; + + left = timeout - n; + } else + left = (uint64_t) -1; + + r = rtnl_poll(nl, true, left); + if (r < 0) + return r; + + r = dispatch_wqueue(nl); + if (r < 0) + return r; + } +} + +int sd_rtnl_flush(sd_rtnl *rtnl) { + int r; + + assert_return(rtnl, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + + if (rtnl->wqueue_size <= 0) + return 0; + + for (;;) { + r = dispatch_wqueue(rtnl); + if (r < 0) + return r; + + if (rtnl->wqueue_size <= 0) + return 0; + + r = rtnl_poll(rtnl, false, (uint64_t) -1); + if (r < 0) + return r; + } +} + +int sd_rtnl_get_events(sd_rtnl *rtnl) { + int flags = 0; + + assert_return(rtnl, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + + if (rtnl->rqueue_size <= 0) + flags |= POLLIN; + if (rtnl->wqueue_size > 0) + flags |= POLLOUT; + + return flags; +} + +int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) { + struct reply_callback *c; + + assert_return(rtnl, -EINVAL); + assert_return(timeout_usec, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + + if (rtnl->rqueue_size > 0) { + *timeout_usec = 0; + return 1; + } + + c = prioq_peek(rtnl->reply_callbacks_prioq); + if (!c) { + *timeout_usec = (uint64_t) -1; + return 0; + } + + *timeout_usec = c->timeout; + + return 1; +} + +static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + sd_rtnl *rtnl = userdata; + int r; + + assert(rtnl); + + r = sd_rtnl_process(rtnl, NULL); + if (r < 0) + return r; + + return 1; +} + +static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { + sd_rtnl *rtnl = userdata; + int r; + + assert(rtnl); + + r = sd_rtnl_process(rtnl, NULL); + if (r < 0) + return r; + + return 1; +} + +static int prepare_callback(sd_event_source *s, void *userdata) { + sd_rtnl *rtnl = userdata; + int r, e; + usec_t until; + + assert(s); + assert(rtnl); + + e = sd_rtnl_get_events(rtnl); + if (e < 0) + return e; + + r = sd_event_source_set_io_events(rtnl->io_event_source, e); + if (r < 0) + return r; + + r = sd_rtnl_get_timeout(rtnl, &until); + if (r < 0) + return r; + if (r > 0) { + int j; + + j = sd_event_source_set_time(rtnl->time_event_source, until); + if (j < 0) + return j; + } + + r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0); + if (r < 0) + return r; + + return 1; +} + +static int exit_callback(sd_event_source *event, void *userdata) { + sd_rtnl *rtnl = userdata; + + assert(event); + + sd_rtnl_flush(rtnl); + + return 1; +} + +int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) { + int r; + + assert_return(rtnl, -EINVAL); + assert_return(!rtnl->event, -EBUSY); + + assert(!rtnl->io_event_source); + assert(!rtnl->time_event_source); + + if (event) + rtnl->event = sd_event_ref(event); + else { + r = sd_event_default(&rtnl->event); + if (r < 0) + return r; + } + + r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(rtnl->io_event_source, priority); + if (r < 0) + goto fail; + + r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback); + if (r < 0) + goto fail; + + r = sd_event_add_monotonic(rtnl->event, &rtnl->time_event_source, 0, 0, time_callback, rtnl); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(rtnl->time_event_source, priority); + if (r < 0) + goto fail; + + r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl); + if (r < 0) + goto fail; + + return 0; + +fail: + sd_rtnl_detach_event(rtnl); + return r; +} + +int sd_rtnl_detach_event(sd_rtnl *rtnl) { + assert_return(rtnl, -EINVAL); + assert_return(rtnl->event, -ENXIO); + + if (rtnl->io_event_source) + rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source); + + if (rtnl->time_event_source) + rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source); + + if (rtnl->exit_event_source) + rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source); + + if (rtnl->event) + rtnl->event = sd_event_unref(rtnl->event); + + return 0; +} + +int sd_rtnl_add_match(sd_rtnl *rtnl, + uint16_t type, + sd_rtnl_message_handler_t callback, + void *userdata) { + struct match_callback *c; + + assert_return(rtnl, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(rtnl_message_type_is_link(type) || + rtnl_message_type_is_addr(type) || + rtnl_message_type_is_route(type), -ENOTSUP); + + c = new0(struct match_callback, 1); + if (!c) + return -ENOMEM; + + c->callback = callback; + c->type = type; + c->userdata = userdata; + + LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c); + + return 0; +} + +int sd_rtnl_remove_match(sd_rtnl *rtnl, + uint16_t type, + sd_rtnl_message_handler_t callback, + void *userdata) { + struct match_callback *c; + + assert_return(rtnl, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + + LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) + if (c->callback == callback && c->type == type && c->userdata == userdata) { + LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c); + free(c); + + return 1; + } + + return 0; +} diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c new file mode 100644 index 0000000..dd74e76 --- /dev/null +++ b/src/libsystemd/sd-rtnl/test-rtnl.c @@ -0,0 +1,394 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "macro.h" +#include "sd-rtnl.h" +#include "socket-util.h" +#include "rtnl-util.h" +#include "event-util.h" +#include "missing.h" + +static void test_link_configure(sd_rtnl *rtnl, int ifindex) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *message; + uint16_t type; + const char *mac = "98:fe:94:3f:c6:18", *name = "test"; + unsigned int mtu = 1450; + void *data; + + /* we'd really like to test NEWLINK, but let's not mess with the running kernel */ + assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0); + assert_se(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0); + assert_se(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0); + assert_se(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0); + + assert_se(sd_rtnl_call(rtnl, message, 0, NULL) == 1); + + assert_se(sd_rtnl_message_read(message, &type, &data) > 0); + assert_se(type == IFLA_IFNAME); + assert_se(streq(name, (char *) data)); + + assert_se(sd_rtnl_message_read(message, &type, &data) > 0); + assert_se(type == IFLA_ADDRESS); + assert_se(streq(mac, ether_ntoa(data))); + + assert_se(sd_rtnl_message_read(message, &type, &data) > 0); + assert_se(type == IFLA_MTU); + assert_se(mtu == *(unsigned int *) data); +} + +static void test_link_get(sd_rtnl *rtnl, int ifindex) { + sd_rtnl_message *m; + sd_rtnl_message *r; + unsigned int mtu = 1500; + unsigned int *mtu_reply; + void *data; + uint16_t type; + + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); + assert_se(m); + + /* u8 test cases */ + assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0); + assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0); + assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0); + + /* u32 test cases */ + assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0); + assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0); + assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0); + assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0); + assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0); + + assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1); + + /* u8 read back */ + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_CARRIER); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_OPERSTATE); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_LINKMODE); + + /* u32 read back */ + assert_se(sd_rtnl_message_read(m, &type, (void **) &mtu_reply) == 1); + assert_se(type == IFLA_MTU); + assert_se(*mtu_reply == mtu); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_GROUP); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_TXQLEN); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_NUM_TX_QUEUES); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 1); + assert_se(type == IFLA_NUM_RX_QUEUES); + + while (sd_rtnl_message_read(r, &type, &data) > 0) { + switch (type) { +// case IFLA_MTU: +// assert_se(*(unsigned int *) data == 65536); +// break; +// case IFLA_QDISC: +// assert_se(streq((char *) data, "noqueue")); +// break; + case IFLA_IFNAME: + assert_se(streq((char *) data, "lo")); + break; + } + } + + assert_se(sd_rtnl_flush(rtnl) >= 0); + assert_se((m = sd_rtnl_message_unref(m)) == NULL); + +} + +static void test_route(void) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req; + struct in_addr addr; + uint32_t index = 2; + uint16_t type; + void *data; + int r; + + r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET); + if (r < 0) { + log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r)); + return; + } + + addr.s_addr = htonl(INADDR_LOOPBACK); + + r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr); + if (r < 0) { + log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r)); + return; + } + + r = sd_rtnl_message_append_u32(req, RTA_OIF, index); + if (r < 0) { + log_error("Could not append RTA_OIF attribute: %s", strerror(-r)); + return; + } + + assert_se(rtnl_message_seal(NULL, req) >= 0); + + assert_se(sd_rtnl_message_read(req, &type, &data) > 0); + assert_se(type == RTA_GATEWAY); + assert_se(((struct in_addr *)data)->s_addr == addr.s_addr); + + assert_se(sd_rtnl_message_read(req, &type, &data) > 0); + assert_se(type == RTA_OIF); + assert_se(*(uint32_t *) data == index); +} + +static void test_multiple(void) { + sd_rtnl *rtnl1, *rtnl2; + + assert_se(sd_rtnl_open(&rtnl1, 0) >= 0); + assert_se(sd_rtnl_open(&rtnl2, 0) >= 0); + + rtnl1 = sd_rtnl_unref(rtnl1); + rtnl2 = sd_rtnl_unref(rtnl2); +} + +static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + void *data; + uint16_t type; + char *ifname = userdata; + + assert_se(rtnl); + assert_se(m); + + log_info("got link info about %s", ifname); + free(ifname); + + while (sd_rtnl_message_read(m, &type, &data) > 0) { + switch (type) { +// case IFLA_MTU: +// assert_se(*(unsigned int *) data == 65536); +// break; +// case IFLA_QDISC: +// assert_se(streq((char *) data, "noqueue")); +// break; + case IFLA_IFNAME: + assert_se(streq((char *) data, "lo")); + break; + } + } + + return 1; +} + +static void test_event_loop(int ifindex) { + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + char *ifname; + + ifname = strdup("lo2"); + assert_se(ifname); + + assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); + + assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0); + + assert_se(sd_event_default(&event) >= 0); + + assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0); + + assert_se(sd_event_run(event, 0) >= 0); + + assert_se(sd_rtnl_detach_event(rtnl) >= 0); +} + +static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + int *counter = userdata; + + (*counter) --; + + log_info("got reply, %d left in pipe", *counter); + + return sd_rtnl_message_get_errno(m); +} + +static void test_async(int ifindex) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL; + uint32_t serial; + char *ifname; + + ifname = strdup("lo"); + assert_se(ifname); + + assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); + + assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0); + + assert_se(sd_rtnl_wait(rtnl, 0) >= 0); + assert_se(sd_rtnl_process(rtnl, &r) >= 0); +} + +static void test_pipe(int ifindex) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL; + int counter = 0; + + assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + + assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); + assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); + + counter ++; + assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0); + + counter ++; + assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0); + + while (counter > 0) { + assert_se(sd_rtnl_wait(rtnl, 0) >= 0); + assert_se(sd_rtnl_process(rtnl, NULL) >= 0); + } +} + +static void test_container(void) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + uint16_t type; + void *data; + + assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0); + + assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0); + assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) == -ENOTSUP); + assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0); + assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) >= 0); + assert_se(sd_rtnl_message_open_container(m, IFLA_INFO_DATA) == -ENOTSUP); + assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0); + assert_se(sd_rtnl_message_close_container(m) >= 0); + assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "kind") >= 0); + assert_se(sd_rtnl_message_close_container(m) >= 0); + assert_se(sd_rtnl_message_close_container(m) == -EINVAL); + + assert_se(rtnl_message_seal(NULL, m) >= 0); + + assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); + assert_se(type == IFLA_LINKINFO); + assert_se(data == NULL); + assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); + assert_se(type == IFLA_INFO_KIND); + assert_se(streq("kind", (char *)data)); + assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); + assert_se(type == IFLA_INFO_DATA); + assert_se(data == NULL); + assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); + assert_se(type == IFLA_VLAN_ID); + assert_se(*(uint16_t *)data == 100); + assert_se(sd_rtnl_message_read(m, &type, &data) == 0); + assert_se(sd_rtnl_message_exit_container(m) >= 0); + assert_se(sd_rtnl_message_read(m, &type, &data) >= 0); + assert_se(type == IFLA_INFO_KIND); + assert_se(streq("kind", (char *)data)); + assert_se(sd_rtnl_message_read(m, &type, &data) == 0); + assert_se(sd_rtnl_message_exit_container(m) >= 0); + assert_se(sd_rtnl_message_exit_container(m) == -EINVAL); +} + +static void test_match(void) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + + assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + + assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); + assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); + + assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1); + assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1); + assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0); +} + +int main(void) { + sd_rtnl *rtnl; + sd_rtnl_message *m; + sd_rtnl_message *r; + void *data; + int if_loopback; + uint16_t type; + + test_match(); + + test_multiple(); + + test_route(); + + test_container(); + + assert_se(sd_rtnl_open(&rtnl, 0) >= 0); + assert_se(rtnl); + + if_loopback = (int) if_nametoindex("lo"); + assert_se(if_loopback > 0); + + test_async(if_loopback); + + test_pipe(if_loopback); + + test_event_loop(if_loopback); + + test_link_configure(rtnl, if_loopback); + + assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0); + assert_se(m); + + assert_se(sd_rtnl_message_get_type(m, &type) >= 0); + assert_se(type == RTM_GETLINK); + + assert_se(sd_rtnl_message_read(m, &type, &data) == -EPERM); + + assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1); + assert_se(sd_rtnl_message_get_type(r, &type) >= 0); + assert_se(type == RTM_NEWLINK); + + assert_se(sd_rtnl_message_read(m, &type, &data) == 0); + assert_se((r = sd_rtnl_message_unref(r)) == NULL); + + assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM); + assert_se((m = sd_rtnl_message_unref(m)) == NULL); + assert_se((r = sd_rtnl_message_unref(r)) == NULL); + + test_link_get(rtnl, if_loopback); + + assert_se(sd_rtnl_flush(rtnl) >= 0); + assert_se((m = sd_rtnl_message_unref(m)) == NULL); + assert_se((r = sd_rtnl_message_unref(r)) == NULL); + assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL); + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-utf8/Makefile b/src/libsystemd/sd-utf8/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/libsystemd/sd-utf8/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c new file mode 100644 index 0000000..6f2aa60 --- /dev/null +++ b/src/libsystemd/sd-utf8/sd-utf8.c @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "utf8.h" +#include "sd-utf8.h" + +_public_ const char *sd_utf8_is_valid(const char *s) { + assert_return(s, NULL); + + return utf8_is_valid(s); +} + +_public_ const char *sd_ascii_is_valid(const char *s) { + assert_return(s, NULL); + + return ascii_is_valid(s); +} diff --git a/src/libudev/.gitignore b/src/libudev/.gitignore new file mode 100644 index 0000000..0c8a5d5 --- /dev/null +++ b/src/libudev/.gitignore @@ -0,0 +1 @@ +/libudev.pc diff --git a/src/libudev/Makefile b/src/libudev/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/libudev/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c new file mode 100644 index 0000000..cb4947f --- /dev/null +++ b/src/libudev/libudev-device-private.c @@ -0,0 +1,191 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static void udev_device_tag(struct udev_device *dev, const char *tag, bool add) +{ + const char *id; + char filename[UTIL_PATH_SIZE]; + + id = udev_device_get_id_filename(dev); + if (id == NULL) + return; + strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, NULL); + + if (add) { + int fd; + + mkdir_parents(filename, 0755); + fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); + if (fd >= 0) + close(fd); + } else { + unlink(filename); + } +} + +int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add) +{ + struct udev_list_entry *list_entry; + bool found; + + if (add && dev_old != NULL) { + /* delete possible left-over tags */ + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) { + const char *tag_old = udev_list_entry_get_name(list_entry); + struct udev_list_entry *list_entry_current; + + found = false; + udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) { + const char *tag = udev_list_entry_get_name(list_entry_current); + + if (streq(tag, tag_old)) { + found = true; + break; + } + } + if (!found) + udev_device_tag(dev_old, tag_old, false); + } + } + + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev)) + udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); + + return 0; +} + +static bool device_has_info(struct udev_device *udev_device) +{ + struct udev_list_entry *list_entry; + + if (udev_device_get_devlinks_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_devlink_priority(udev_device) != 0) + return true; + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) + if (udev_list_entry_get_num(list_entry)) + return true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_watch_handle(udev_device) >= 0) + return true; + return false; +} + +int udev_device_update_db(struct udev_device *udev_device) +{ + struct udev *udev = udev_device_get_udev(udev_device); + bool has_info; + const char *id; + char filename[UTIL_PATH_SIZE]; + char filename_tmp[UTIL_PATH_SIZE]; + FILE *f; + int r; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + + has_info = device_has_info(udev_device); + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + + /* do not store anything for otherwise empty devices */ + if (!has_info && + major(udev_device_get_devnum(udev_device)) == 0 && + udev_device_get_ifindex(udev_device) == 0) { + unlink(filename); + return 0; + } + + /* write a database file */ + strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); + mkdir_parents(filename_tmp, 0755); + f = fopen(filename_tmp, "we"); + if (f == NULL) { + udev_err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp); + return -1; + } + + /* + * set 'sticky' bit to indicate that we should not clean the + * database when we transition from initramfs to the real root + */ + if (udev_device_get_db_persist(udev_device)) + fchmod(fileno(f), 01644); + + if (has_info) { + struct udev_list_entry *list_entry; + + if (major(udev_device_get_devnum(udev_device)) > 0) { + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) + fprintf(f, "S:%s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/")); + if (udev_device_get_devlink_priority(udev_device) != 0) + fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device)); + if (udev_device_get_watch_handle(udev_device) >= 0) + fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device)); + } + + if (udev_device_get_usec_initialized(udev_device) > 0) + fprintf(f, "I:%llu\n", (unsigned long long)udev_device_get_usec_initialized(udev_device)); + + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { + if (!udev_list_entry_get_num(list_entry)) + continue; + fprintf(f, "E:%s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } + + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) + fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); + } + + fclose(f); + r = rename(filename_tmp, filename); + if (r < 0) + return -1; + udev_dbg(udev, "created %s file '%s' for '%s'\n", has_info ? "db" : "empty", + filename, udev_device_get_devpath(udev_device)); + return 0; +} + +int udev_device_delete_db(struct udev_device *udev_device) +{ + const char *id; + char filename[UTIL_PATH_SIZE]; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + unlink(filename); + return 0; +} diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c new file mode 100644 index 0000000..9f80f56 --- /dev/null +++ b/src/libudev/libudev-device.c @@ -0,0 +1,1873 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode); + +/** + * SECTION:libudev-device + * @short_description: kernel sys devices + * + * Representation of kernel sys devices. Devices are uniquely identified + * by their syspath, every device has exactly one path in the kernel sys + * filesystem. Devices usually belong to a kernel subsystem, and have + * a unique name inside that subsystem. + */ + +/** + * udev_device: + * + * Opaque object representing one kernel sys device. + */ +struct udev_device { + struct udev *udev; + struct udev_device *parent_device; + char *syspath; + const char *devpath; + char *sysname; + const char *sysnum; + char *devnode; + mode_t devnode_mode; + uid_t devnode_uid; + gid_t devnode_gid; + char *subsystem; + char *devtype; + char *driver; + char *action; + char *devpath_old; + char *id_filename; + char **envp; + char *monitor_buf; + size_t monitor_buf_len; + struct udev_list devlinks_list; + struct udev_list properties_list; + struct udev_list sysattr_value_list; + struct udev_list sysattr_list; + struct udev_list tags_list; + unsigned long long int seqnum; + usec_t usec_initialized; + int devlink_priority; + int refcount; + dev_t devnum; + int ifindex; + int watch_handle; + int maj, min; + bool parent_set; + bool subsystem_set; + bool devtype_set; + bool devlinks_uptodate; + bool envp_uptodate; + bool tags_uptodate; + bool driver_set; + bool info_loaded; + bool db_loaded; + bool uevent_loaded; + bool is_initialized; + bool sysattr_list_read; + bool db_persist; +}; + +/** + * udev_device_get_seqnum: + * @udev_device: udev device + * + * This is only valid if the device was received through a monitor. Devices read from + * sys do not have a sequence number. + * + * 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) +{ + if (udev_device == NULL) + return 0; + return udev_device->seqnum; +} + +static int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum) +{ + char num[32]; + + udev_device->seqnum = seqnum; + snprintf(num, sizeof(num), "%llu", seqnum); + udev_device_add_property(udev_device, "SEQNUM", num); + return 0; +} + +int udev_device_get_ifindex(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->ifindex; +} + +static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) +{ + char num[32]; + + udev_device->ifindex = ifindex; + snprintf(num, sizeof(num), "%u", ifindex); + udev_device_add_property(udev_device, "IFINDEX", num); + return 0; +} + +/** + * udev_device_get_devnum: + * @udev_device: udev device + * + * Get the device major/minor number. + * + * Returns: the dev_t number. + **/ +_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return makedev(0, 0); + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnum; +} + +static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) +{ + char num[32]; + + udev_device->devnum = devnum; + + snprintf(num, sizeof(num), "%u", major(devnum)); + udev_device_add_property(udev_device, "MAJOR", num); + snprintf(num, sizeof(num), "%u", minor(devnum)); + udev_device_add_property(udev_device, "MINOR", num); + return 0; +} + +const char *udev_device_get_devpath_old(struct udev_device *udev_device) +{ + return udev_device->devpath_old; +} + +static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old) +{ + const char *pos; + + free(udev_device->devpath_old); + udev_device->devpath_old = strdup(devpath_old); + if (udev_device->devpath_old == NULL) + return -ENOMEM; + udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old); + + pos = strrchr(udev_device->devpath_old, '/'); + if (pos == NULL) + return -EINVAL; + return 0; +} + +/** + * udev_device_get_driver: + * @udev_device: udev device + * + * Get the kernel driver name. + * + * Returns: the driver name string, or #NULL if there is no driver attached. + **/ +_public_ const char *udev_device_get_driver(struct udev_device *udev_device) +{ + char driver[UTIL_NAME_SIZE]; + + if (udev_device == NULL) + return NULL; + if (!udev_device->driver_set) { + udev_device->driver_set = true; + if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0) + udev_device->driver = strdup(driver); + } + return udev_device->driver; +} + +static int udev_device_set_driver(struct udev_device *udev_device, const char *driver) +{ + free(udev_device->driver); + udev_device->driver = strdup(driver); + if (udev_device->driver == NULL) + return -ENOMEM; + udev_device->driver_set = true; + udev_device_add_property(udev_device, "DRIVER", udev_device->driver); + return 0; +} + +/** + * udev_device_get_devtype: + * @udev_device: udev device + * + * Retrieve the devtype string of the udev device. + * + * Returns: the devtype name of the udev device, or #NULL if it can not be determined + **/ +_public_ const char *udev_device_get_devtype(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->devtype_set) { + udev_device->devtype_set = true; + udev_device_read_uevent_file(udev_device); + } + return udev_device->devtype; +} + +static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype) +{ + free(udev_device->devtype); + udev_device->devtype = strdup(devtype); + if (udev_device->devtype == NULL) + return -ENOMEM; + udev_device->devtype_set = true; + udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype); + return 0; +} + +int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) +{ + free(udev_device->subsystem); + udev_device->subsystem = strdup(subsystem); + if (udev_device->subsystem == NULL) + return -ENOMEM; + udev_device->subsystem_set = true; + udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem); + return 0; +} + +/** + * udev_device_get_subsystem: + * @udev_device: udev device + * + * Retrieve the subsystem string of the udev device. The string does not + * contain any "/". + * + * Returns: the subsystem name of the udev device, or #NULL if it can not be determined + **/ +_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) +{ + char subsystem[UTIL_NAME_SIZE]; + + if (udev_device == NULL) + return NULL; + if (!udev_device->subsystem_set) { + udev_device->subsystem_set = true; + /* read "subsystem" link */ + if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) { + udev_device_set_subsystem(udev_device, subsystem); + return udev_device->subsystem; + } + /* implicit names */ + if (startswith(udev_device->devpath, "/module/")) { + udev_device_set_subsystem(udev_device, "module"); + return udev_device->subsystem; + } + if (strstr(udev_device->devpath, "/drivers/") != NULL) { + udev_device_set_subsystem(udev_device, "drivers"); + return udev_device->subsystem; + } + if (startswith(udev_device->devpath, "/subsystem/") || + startswith(udev_device->devpath, "/class/") || + startswith(udev_device->devpath, "/bus/")) { + udev_device_set_subsystem(udev_device, "subsystem"); + return udev_device->subsystem; + } + } + return udev_device->subsystem; +} + +mode_t udev_device_get_devnode_mode(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_mode; +} + +static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode) +{ + char num[32]; + + udev_device->devnode_mode = mode; + snprintf(num, sizeof(num), "%#o", mode); + udev_device_add_property(udev_device, "DEVMODE", num); + return 0; +} + +uid_t udev_device_get_devnode_uid(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_uid; +} + +static int udev_device_set_devnode_uid(struct udev_device *udev_device, uid_t uid) +{ + char num[32]; + + udev_device->devnode_uid = uid; + snprintf(num, sizeof(num), "%u", uid); + udev_device_add_property(udev_device, "DEVUID", num); + return 0; +} + +gid_t udev_device_get_devnode_gid(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_gid; +} + +static int udev_device_set_devnode_gid(struct udev_device *udev_device, gid_t gid) +{ + char num[32]; + + udev_device->devnode_gid = gid; + snprintf(num, sizeof(num), "%u", gid); + udev_device_add_property(udev_device, "DEVGID", num); + return 0; +} + +struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) +{ + udev_device->envp_uptodate = false; + if (value == NULL) { + struct udev_list_entry *list_entry; + + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + if (list_entry != NULL) + udev_list_entry_delete(list_entry); + return NULL; + } + return udev_list_entry_add(&udev_device->properties_list, key, value); +} + +static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) +{ + char name[UTIL_LINE_SIZE]; + char *val; + + strscpy(name, sizeof(name), property); + val = strchr(name, '='); + if (val == NULL) + return NULL; + val[0] = '\0'; + val = &val[1]; + if (val[0] == '\0') + val = NULL; + return udev_device_add_property(udev_device, name, val); +} + +/* + * parse property string, and if needed, update internal values accordingly + * + * udev_device_add_property_from_string_parse_finish() needs to be + * called after adding properties, and its return value checked + * + * udev_device_set_info_loaded() needs to be set, to avoid trying + * to use a device without a DEVPATH set + */ +void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) +{ + if (startswith(property, "DEVPATH=")) { + char path[UTIL_PATH_SIZE]; + + strscpyl(path, sizeof(path), "/sys", &property[8], NULL); + udev_device_set_syspath(udev_device, path); + } else if (startswith(property, "SUBSYSTEM=")) { + udev_device_set_subsystem(udev_device, &property[10]); + } else if (startswith(property, "DEVTYPE=")) { + udev_device_set_devtype(udev_device, &property[8]); + } else if (startswith(property, "DEVNAME=")) { + udev_device_set_devnode(udev_device, &property[8]); + } else if (startswith(property, "DEVLINKS=")) { + char devlinks[UTIL_PATH_SIZE]; + char *slink; + char *next; + + strscpy(devlinks, sizeof(devlinks), &property[9]); + slink = devlinks; + next = strchr(slink, ' '); + while (next != NULL) { + next[0] = '\0'; + udev_device_add_devlink(udev_device, slink); + slink = &next[1]; + next = strchr(slink, ' '); + } + if (slink[0] != '\0') + udev_device_add_devlink(udev_device, slink); + } else if (startswith(property, "TAGS=")) { + char tags[UTIL_PATH_SIZE]; + char *next; + + strscpy(tags, sizeof(tags), &property[5]); + next = strchr(tags, ':'); + if (next != NULL) { + next++; + while (next[0] != '\0') { + char *tag; + + tag = next; + next = strchr(tag, ':'); + if (next == NULL) + break; + next[0] = '\0'; + next++; + udev_device_add_tag(udev_device, tag); + } + } + } else if (startswith(property, "USEC_INITIALIZED=")) { + udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10)); + } else if (startswith(property, "DRIVER=")) { + udev_device_set_driver(udev_device, &property[7]); + } else if (startswith(property, "ACTION=")) { + udev_device_set_action(udev_device, &property[7]); + } else if (startswith(property, "MAJOR=")) { + udev_device->maj = strtoull(&property[6], NULL, 10); + } else if (startswith(property, "MINOR=")) { + udev_device->min = strtoull(&property[6], NULL, 10); + } else if (startswith(property, "DEVPATH_OLD=")) { + udev_device_set_devpath_old(udev_device, &property[12]); + } else if (startswith(property, "SEQNUM=")) { + udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); + } else if (startswith(property, "IFINDEX=")) { + udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); + } else if (startswith(property, "DEVMODE=")) { + udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8)); + } else if (startswith(property, "DEVUID=")) { + udev_device_set_devnode_uid(udev_device, strtoul(&property[7], NULL, 10)); + } else if (startswith(property, "DEVGID=")) { + udev_device_set_devnode_gid(udev_device, strtoul(&property[7], NULL, 10)); + } else { + udev_device_add_property_from_string(udev_device, property); + } +} + +int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device) +{ + if (udev_device->maj > 0) + udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min)); + udev_device->maj = 0; + udev_device->min = 0; + + if (udev_device->devpath == NULL || udev_device->subsystem == NULL) + return -EINVAL; + return 0; +} + +/** + * udev_device_get_property_value: + * @udev_device: udev device + * @key: property name + * + * Get the value of a given property. + * + * Returns: the property string, or #NULL if there is no such property. + **/ +_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +{ + struct udev_list_entry *list_entry; + + if (udev_device == NULL) + return NULL; + if (key == NULL) + return NULL; + + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + return udev_list_entry_get_value(list_entry); +} + +int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) +{ + char filename[UTIL_PATH_SIZE]; + char line[UTIL_LINE_SIZE]; + FILE *f; + + /* providing a database file will always force-load it */ + if (dbfile == NULL) { + const char *id; + + if (udev_device->db_loaded) + return 0; + udev_device->db_loaded = true; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + dbfile = filename; + } + + f = fopen(dbfile, "re"); + if (f == NULL) { + udev_dbg(udev_device->udev, "no db file to read %s: %m\n", dbfile); + return -errno; + } + + /* devices with a database entry are initialized */ + udev_device->is_initialized = true; + + while (fgets(line, sizeof(line), f)) { + ssize_t len; + const char *val; + struct udev_list_entry *entry; + + len = strlen(line); + if (len < 4) + break; + line[len-1] = '\0'; + val = &line[2]; + switch(line[0]) { + case 'S': + strscpyl(filename, sizeof(filename), "/dev/", val, NULL); + udev_device_add_devlink(udev_device, filename); + break; + case 'L': + udev_device_set_devlink_priority(udev_device, atoi(val)); + break; + case 'E': + entry = udev_device_add_property_from_string(udev_device, val); + udev_list_entry_set_num(entry, true); + break; + case 'G': + udev_device_add_tag(udev_device, val); + break; + case 'W': + udev_device_set_watch_handle(udev_device, atoi(val)); + break; + case 'I': + udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10)); + break; + } + } + fclose(f); + + udev_dbg(udev_device->udev, "device %p filled with db file data\n", udev_device); + return 0; +} + +int udev_device_read_uevent_file(struct udev_device *udev_device) +{ + char filename[UTIL_PATH_SIZE]; + FILE *f; + char line[UTIL_LINE_SIZE]; + int maj = 0; + int min = 0; + + if (udev_device->uevent_loaded) + return 0; + + strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL); + f = fopen(filename, "re"); + if (f == NULL) + return -errno; + udev_device->uevent_loaded = true; + + while (fgets(line, sizeof(line), f)) { + char *pos; + + pos = strchr(line, '\n'); + if (pos == NULL) + continue; + pos[0] = '\0'; + + if (startswith(line, "DEVTYPE=")) { + udev_device_set_devtype(udev_device, &line[8]); + continue; + } + if (startswith(line, "IFINDEX=")) { + udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); + continue; + } + if (startswith(line, "DEVNAME=")) { + udev_device_set_devnode(udev_device, &line[8]); + continue; + } + + if (startswith(line, "MAJOR=")) + maj = strtoull(&line[6], NULL, 10); + else if (startswith(line, "MINOR=")) + min = strtoull(&line[6], NULL, 10); + else if (startswith(line, "DEVMODE=")) + udev_device->devnode_mode = strtoul(&line[8], NULL, 8); + + udev_device_add_property_from_string(udev_device, line); + } + + udev_device->devnum = makedev(maj, min); + fclose(f); + return 0; +} + +void udev_device_set_info_loaded(struct udev_device *device) +{ + device->info_loaded = true; +} + +struct udev_device *udev_device_new(struct udev *udev) +{ + struct udev_device *udev_device; + struct udev_list_entry *list_entry; + + if (udev == NULL) + return NULL; + + udev_device = new0(struct udev_device, 1); + if (udev_device == NULL) + return NULL; + udev_device->refcount = 1; + udev_device->udev = udev; + udev_list_init(udev, &udev_device->devlinks_list, true); + udev_list_init(udev, &udev_device->properties_list, true); + udev_list_init(udev, &udev_device->sysattr_value_list, true); + udev_list_init(udev, &udev_device->sysattr_list, false); + udev_list_init(udev, &udev_device->tags_list, true); + udev_device->watch_handle = -1; + /* copy global properties */ + udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev)) + udev_device_add_property(udev_device, + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + return udev_device; +} + +/** + * udev_device_new_from_syspath: + * @udev: udev library context + * @syspath: sys device path including sys directory + * + * Create new udev device, and fill in information from the sys + * device and the udev database entry. The syspath is the absolute + * path to the device, including the sys mount point. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) +{ + const char *subdir; + char path[UTIL_PATH_SIZE]; + char *pos; + struct stat statbuf; + struct udev_device *udev_device; + + if (udev == NULL) + return NULL; + if (syspath == NULL) + return NULL; + + /* path starts in sys */ + if (!startswith(syspath, "/sys")) { + udev_dbg(udev, "not in sys :%s\n", syspath); + return NULL; + } + + /* path is not a root directory */ + subdir = syspath + strlen("/sys"); + pos = strrchr(subdir, '/'); + if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) + return NULL; + + /* resolve possible symlink to real path */ + strscpy(path, sizeof(path), syspath); + util_resolve_sys_link(udev, path, sizeof(path)); + + if (startswith(path + strlen("/sys"), "/devices/")) { + char file[UTIL_PATH_SIZE]; + + /* all "devices" require a "uevent" file */ + strscpyl(file, sizeof(file), path, "/uevent", NULL); + if (stat(file, &statbuf) != 0) + return NULL; + } else { + /* everything else just needs to be a directory */ + if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) + return NULL; + } + + udev_device = udev_device_new(udev); + if (udev_device == NULL) + return NULL; + + udev_device_set_syspath(udev_device, path); + udev_dbg(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); + + return udev_device; +} + +/** + * udev_device_new_from_devnum: + * @udev: udev library context + * @type: char or block device + * @devnum: device major/minor number + * + * Create new udev device, and fill in information from the sys + * device and the udev database entry. The device is looked-up + * by its major/minor number and type. Character and block device + * numbers are not unique across the two types. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) +{ + char path[UTIL_PATH_SIZE]; + const char *type_str; + + if (type == 'b') + type_str = "block"; + else if (type == 'c') + type_str = "char"; + else + return NULL; + + /* use /sys/dev/{block,char}/: link */ + snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u", + type_str, major(devnum), minor(devnum)); + return udev_device_new_from_syspath(udev, path); +} + +/** + * udev_device_new_from_device_id: + * @udev: udev library context + * @id: text string identifying a kernel device + * + * Create new udev device, and fill in information from the sys + * device and the udev database entry. The device is looked-up + * by a special string: + * b8:2 - block device major:minor + * c128:1 - char device major:minor + * n3 - network device ifindex + * +sound:card29 - kernel driver core subsystem:device name + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) +{ + char type; + int maj, min; + char subsys[UTIL_PATH_SIZE]; + char *sysname; + + switch(id[0]) { + case 'b': + case 'c': + if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) + return NULL; + return udev_device_new_from_devnum(udev, type, makedev(maj, min)); + case 'n': { + int sk; + struct ifreq ifr; + struct udev_device *dev; + int ifindex; + + ifindex = strtoul(&id[1], NULL, 10); + if (ifindex <= 0) + return NULL; + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return NULL; + memzero(&ifr, sizeof(struct ifreq)); + ifr.ifr_ifindex = ifindex; + if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { + close(sk); + return NULL; + } + close(sk); + + dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name); + if (dev == NULL) + return NULL; + if (udev_device_get_ifindex(dev) == ifindex) + return dev; + udev_device_unref(dev); + return NULL; + } + case '+': + strscpy(subsys, sizeof(subsys), &id[1]); + sysname = strchr(subsys, ':'); + if (sysname == NULL) + return NULL; + sysname[0] = '\0'; + sysname = &sysname[1]; + return udev_device_new_from_subsystem_sysname(udev, subsys, sysname); + default: + return NULL; + } +} + +/** + * udev_device_new_from_subsystem_sysname: + * @udev: udev library context + * @subsystem: the subsystem of the device + * @sysname: the name of the device + * + * Create new udev device, and fill in information from the sys device + * and the udev database entry. The device is looked up by the subsystem + * and name string of the device, like "mem" / "zero", or "block" / "sda". + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) +{ + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + + if (streq(subsystem, "subsystem")) { + strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq(subsystem, "module")) { + strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq(subsystem, "drivers")) { + char subsys[UTIL_NAME_SIZE]; + char *driver; + + strscpy(subsys, sizeof(subsys), sysname); + driver = strchr(subsys, ':'); + if (driver != NULL) { + driver[0] = '\0'; + driver = &driver[1]; + + strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, "/drivers/", driver, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", subsys, "/drivers/", driver, NULL); + if (stat(path, &statbuf) == 0) + goto found; + } + goto out; + } + + strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; +out: + return NULL; +found: + return udev_device_new_from_syspath(udev, path); +} + +/** + * udev_device_new_from_environment + * @udev: udev library context + * + * Create new udev device, and fill in information from the + * current process environment. This only works reliable if + * the process is called from a udev rule. It is usually used + * for tools executed from IMPORT= rules. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) +{ + int i; + struct udev_device *udev_device; + + udev_device = udev_device_new(udev); + if (udev_device == NULL) + return NULL; + udev_device_set_info_loaded(udev_device); + + for (i = 0; environ[i] != NULL; i++) + udev_device_add_property_from_string_parse(udev_device, environ[i]); + + if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { + udev_dbg(udev, "missing values, invalid device\n"); + udev_device_unref(udev_device); + udev_device = NULL; + } + + return udev_device; +} + +static struct udev_device *device_new_from_parent(struct udev_device *udev_device) +{ + struct udev_device *udev_device_parent = NULL; + char path[UTIL_PATH_SIZE]; + const char *subdir; + + strscpy(path, sizeof(path), udev_device->syspath); + subdir = path + strlen("/sys/"); + for (;;) { + char *pos; + + pos = strrchr(subdir, '/'); + if (pos == NULL || pos < &subdir[2]) + break; + pos[0] = '\0'; + udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path); + if (udev_device_parent != NULL) + return udev_device_parent; + } + return NULL; +} + +/** + * udev_device_get_parent: + * @udev_device: the device to start searching from + * + * Find the next parent device, and fill in information from the sys + * device and the udev database entry. + * + * Returned device is not referenced. It is attached to the child + * device, and will be cleaned up when the child device is cleaned up. + * + * It is not necessarily just the upper level directory, empty or not + * recognized sys directories are ignored. + * + * It can be called as many times as needed, without caring about + * references. + * + * Returns: a new udev device, or #NULL, if it no parent exist. + **/ +_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->parent_set) { + udev_device->parent_set = true; + udev_device->parent_device = device_new_from_parent(udev_device); + } + return udev_device->parent_device; +} + +/** + * udev_device_get_parent_with_subsystem_devtype: + * @udev_device: udev device to start searching from + * @subsystem: the subsystem of the device + * @devtype: the type (DEVTYPE) of the device + * + * Find the next parent device, with a matching subsystem and devtype + * value, and fill in information from the sys device and the udev + * database entry. + * + * If devtype is #NULL, only subsystem is checked, and any devtype will + * match. + * + * Returned device is not referenced. It is attached to the child + * device, and will be cleaned up when the child device is cleaned up. + * + * It can be called as many times as needed, without caring about + * references. + * + * Returns: a new udev device, or #NULL if no matching parent exists. + **/ +_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) +{ + struct udev_device *parent; + + if (subsystem == NULL) + return NULL; + + parent = udev_device_get_parent(udev_device); + while (parent != NULL) { + const char *parent_subsystem; + const char *parent_devtype; + + parent_subsystem = udev_device_get_subsystem(parent); + if (parent_subsystem != NULL && streq(parent_subsystem, subsystem)) { + if (devtype == NULL) + break; + parent_devtype = udev_device_get_devtype(parent); + if (parent_devtype != NULL && streq(parent_devtype, devtype)) + break; + } + parent = udev_device_get_parent(parent); + } + return parent; +} + +/** + * udev_device_get_udev: + * @udev_device: udev device + * + * Retrieve the udev library context the device was created with. + * + * Returns: the udev library context + **/ +_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->udev; +} + +/** + * udev_device_ref: + * @udev_device: udev device + * + * Take a reference of a udev device. + * + * Returns: the passed udev device + **/ +_public_ struct udev_device *udev_device_ref(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + udev_device->refcount++; + return udev_device; +} + +/** + * udev_device_unref: + * @udev_device: udev device + * + * Drop a reference of a udev device. If the refcount reaches zero, + * the resources of the device will be released. + * + * Returns: #NULL + **/ +_public_ struct udev_device *udev_device_unref(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + udev_device->refcount--; + if (udev_device->refcount > 0) + return NULL; + if (udev_device->parent_device != NULL) + udev_device_unref(udev_device->parent_device); + free(udev_device->syspath); + free(udev_device->sysname); + free(udev_device->devnode); + free(udev_device->subsystem); + free(udev_device->devtype); + udev_list_cleanup(&udev_device->devlinks_list); + udev_list_cleanup(&udev_device->properties_list); + udev_list_cleanup(&udev_device->sysattr_value_list); + udev_list_cleanup(&udev_device->sysattr_list); + udev_list_cleanup(&udev_device->tags_list); + free(udev_device->action); + free(udev_device->driver); + free(udev_device->devpath_old); + free(udev_device->id_filename); + free(udev_device->envp); + free(udev_device->monitor_buf); + free(udev_device); + return NULL; +} + +/** + * udev_device_get_devpath: + * @udev_device: udev device + * + * Retrieve the kernel devpath value of the udev device. The path + * does not contain the sys mount point, and starts with a '/'. + * + * Returns: the devpath of the udev device + **/ +_public_ const char *udev_device_get_devpath(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->devpath; +} + +/** + * udev_device_get_syspath: + * @udev_device: udev device + * + * Retrieve the sys path of the udev device. The path is an + * absolute path and starts with the sys mount point. + * + * Returns: the sys path of the udev device + **/ +_public_ const char *udev_device_get_syspath(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->syspath; +} + +/** + * udev_device_get_sysname: + * @udev_device: udev device + * + * Get the kernel device name in /sys. + * + * Returns: the name string of the device device + **/ +_public_ const char *udev_device_get_sysname(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->sysname; +} + +/** + * udev_device_get_sysnum: + * @udev_device: udev device + * + * Get the instance number of the device. + * + * Returns: the trailing number string of the device name + **/ +_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_device->sysnum; +} + +/** + * udev_device_get_devnode: + * @udev_device: udev device + * + * Retrieve the device node file name belonging to the udev device. + * The path is an absolute path, and starts with the device directory. + * + * Returns: the device node file name of the udev device, or #NULL if no device node exists + **/ +_public_ const char *udev_device_get_devnode(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (udev_device->devnode != NULL) + return udev_device->devnode; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode; +} + +/** + * udev_device_get_devlinks_list_entry: + * @udev_device: udev device + * + * Retrieve the list of device links pointing to the device file of + * the udev device. The next list entry can be retrieved with + * udev_list_entry_get_next(), which returns #NULL if no more entries exist. + * The devlink path can be retrieved from the list entry by + * udev_list_entry_get_name(). The path is an absolute path, and starts with + * the device directory. + * + * Returns: the first entry of the device node link list + **/ +_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + return udev_list_get_entry(&udev_device->devlinks_list); +} + +void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) +{ + udev_device->devlinks_uptodate = false; + udev_list_cleanup(&udev_device->devlinks_list); +} + +/** + * udev_device_get_properties_list_entry: + * @udev_device: udev device + * + * Retrieve the list of key/value device properties of the udev + * device. The next list entry can be retrieved with udev_list_entry_get_next(), + * which returns #NULL if no more entries exist. The property name + * can be retrieved from the list entry by udev_list_entry_get_name(), + * the property value by udev_list_entry_get_value(). + * + * Returns: the first entry of the property list + **/ +_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) { + udev_device_read_uevent_file(udev_device); + udev_device_read_db(udev_device, NULL); + } + if (!udev_device->devlinks_uptodate) { + char symlinks[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + + udev_device->devlinks_uptodate = true; + list_entry = udev_device_get_devlinks_list_entry(udev_device); + if (list_entry != NULL) { + char *s; + size_t l; + + s = symlinks; + l = strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL); + udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) + l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL); + udev_device_add_property(udev_device, "DEVLINKS", symlinks); + } + } + if (!udev_device->tags_uptodate) { + udev_device->tags_uptodate = true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) { + char tags[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + char *s; + size_t l; + + s = tags; + l = strpcpyl(&s, sizeof(tags), ":", NULL); + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) + l = strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL); + udev_device_add_property(udev_device, "TAGS", tags); + } + } + return udev_list_get_entry(&udev_device->properties_list); +} + +/** + * udev_device_get_action: + * @udev_device: udev device + * + * This is only valid if the device was received through a monitor. Devices read from + * sys do not have an action string. Usual actions are: add, remove, change, online, + * offline. + * + * 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) +{ + if (udev_device == NULL) + return NULL; + return udev_device->action; +} + +/** + * udev_device_get_usec_since_initialized: + * @udev_device: udev device + * + * Return the number of microseconds passed since udev set up the + * device for the first time. + * + * This is only implemented for devices with need to store properties + * in the udev database. All other devices return 0 here. + * + * Returns: the number of microseconds since the device was first seen. + **/ +_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) +{ + usec_t now_ts; + + if (udev_device == NULL) + return 0; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + if (udev_device->usec_initialized == 0) + return 0; + now_ts = now(CLOCK_MONOTONIC); + if (now_ts == 0) + return 0; + return now_ts - udev_device->usec_initialized; +} + +usec_t udev_device_get_usec_initialized(struct udev_device *udev_device) +{ + return udev_device->usec_initialized; +} + +void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized) +{ + char num[32]; + + udev_device->usec_initialized = usec_initialized; + snprintf(num, sizeof(num), "%llu", (unsigned long long)usec_initialized); + udev_device_add_property(udev_device, "USEC_INITIALIZED", num); +} + +/** + * udev_device_get_sysattr_value: + * @udev_device: udev device + * @sysattr: attribute name + * + * The retrieved value is cached in the device. Repeated calls will return the same + * value and not open the attribute again. + * + * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. + **/ +_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) +{ + struct udev_list_entry *list_entry; + char path[UTIL_PATH_SIZE]; + char value[4096]; + struct stat statbuf; + int fd; + ssize_t size; + const char *val = NULL; + + if (udev_device == NULL) + return NULL; + if (sysattr == NULL) + return NULL; + + /* look for possibly already cached result */ + list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); + list_entry = udev_list_entry_get_by_name(list_entry, sysattr); + if (list_entry != NULL) + return udev_list_entry_get_value(list_entry); + + strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL); + if (lstat(path, &statbuf) != 0) { + udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL); + goto out; + } + + if (S_ISLNK(statbuf.st_mode)) { + /* + * Some core links return only the last element of the target path, + * these are just values, the paths should not be exposed. + */ + if (streq(sysattr, "driver") || + streq(sysattr, "subsystem") || + streq(sysattr, "module")) { + if (util_get_sys_core_link_value(udev_device->udev, sysattr, + udev_device->syspath, value, sizeof(value)) < 0) + return NULL; + list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); + val = udev_list_entry_get_value(list_entry); + goto out; + } + + goto out; + } + + /* skip directories */ + if (S_ISDIR(statbuf.st_mode)) + goto out; + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) + goto out; + + /* read attribute value */ + fd = open(path, O_RDONLY|O_CLOEXEC); + if (fd < 0) + goto out; + size = read(fd, value, sizeof(value)); + close(fd); + if (size < 0) + goto out; + if (size == sizeof(value)) + goto out; + + /* got a valid value, store it in cache and return it */ + value[size] = '\0'; + util_remove_trailing_chars(value, '\n'); + list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); + val = udev_list_entry_get_value(list_entry); +out: + return val; +} + +/** + * udev_device_set_sysattr_value: + * @udev_device: udev device + * @sysattr: attribute name + * @value: new value to be set + * + * Update the contents of the sys attribute and the cached value of the device. + * + * Returns: Negative error code on failure or 0 on success. + **/ +_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value) +{ + struct udev_device *dev; + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + int fd; + ssize_t size, value_len; + int ret = 0; + + if (udev_device == NULL) + return -EINVAL; + dev = udev_device; + if (sysattr == NULL) + return -EINVAL; + if (value == NULL) + value_len = 0; + else + value_len = strlen(value); + + strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, NULL); + if (lstat(path, &statbuf) != 0) { + udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL); + ret = -ENXIO; + goto out; + } + + if (S_ISLNK(statbuf.st_mode)) { + ret = -EINVAL; + goto out; + } + + /* skip directories */ + if (S_ISDIR(statbuf.st_mode)) { + ret = -EISDIR; + goto out; + } + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) { + ret = -EACCES; + goto out; + } + + /* Value is limited to 4k */ + if (value_len > 4096) { + ret = -EINVAL; + goto out; + } + util_remove_trailing_chars(value, '\n'); + + /* write attribute value */ + fd = open(path, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + ret = -errno; + goto out; + } + size = write(fd, value, value_len); + close(fd); + if (size < 0) { + ret = -errno; + goto out; + } + if (size < value_len) { + ret = -EIO; + goto out; + } + + /* wrote a valid value, store it in cache and return it */ + udev_list_entry_add(&dev->sysattr_value_list, sysattr, value); +out: + if (dev != udev_device) + udev_device_unref(dev); + return ret; +} + +static int udev_device_sysattr_list_read(struct udev_device *udev_device) +{ + struct dirent *dent; + DIR *dir; + int num = 0; + + if (udev_device == NULL) + return -EINVAL; + if (udev_device->sysattr_list_read) + return 0; + + dir = opendir(udev_device_get_syspath(udev_device)); + if (!dir) + return -errno; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + + /* only handle symlinks and regular files */ + if (dent->d_type != DT_LNK && dent->d_type != DT_REG) + continue; + + strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL); + if (lstat(path, &statbuf) != 0) + continue; + if ((statbuf.st_mode & S_IRUSR) == 0) + continue; + + udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL); + num++; + } + + closedir(dir); + udev_device->sysattr_list_read = true; + + return num; +} + +/** + * udev_device_get_sysattr_list_entry: + * @udev_device: udev device + * + * Retrieve the list of available sysattrs, with value being empty; + * This just return all available sysfs attributes for a particular + * device without reading their values. + * + * Returns: the first entry of the property list + **/ +_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) +{ + if (!udev_device->sysattr_list_read) { + int ret; + ret = udev_device_sysattr_list_read(udev_device); + if (0 > ret) + return NULL; + } + + return udev_list_get_entry(&udev_device->sysattr_list); +} + +int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath) +{ + const char *pos; + size_t len; + + free(udev_device->syspath); + udev_device->syspath = strdup(syspath); + if (udev_device->syspath == NULL) + return -ENOMEM; + udev_device->devpath = udev_device->syspath + strlen("/sys"); + udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath); + + pos = strrchr(udev_device->syspath, '/'); + if (pos == NULL) + return -EINVAL; + udev_device->sysname = strdup(&pos[1]); + if (udev_device->sysname == NULL) + return -ENOMEM; + + /* some devices have '!' in their name, change that to '/' */ + len = 0; + while (udev_device->sysname[len] != '\0') { + if (udev_device->sysname[len] == '!') + udev_device->sysname[len] = '/'; + len++; + } + + /* trailing number */ + while (len > 0 && isdigit(udev_device->sysname[--len])) + udev_device->sysnum = &udev_device->sysname[len]; + + /* sysname is completely numeric */ + if (len == 0) + udev_device->sysnum = NULL; + + return 0; +} + +static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode) +{ + free(udev_device->devnode); + if (devnode[0] != '/') { + if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0) + udev_device->devnode = NULL; + } else { + udev_device->devnode = strdup(devnode); + } + if (udev_device->devnode == NULL) + return -ENOMEM; + udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode); + return 0; +} + +int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink) +{ + struct udev_list_entry *list_entry; + + udev_device->devlinks_uptodate = false; + list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); + if (list_entry == NULL) + return -ENOMEM; + return 0; +} + +const char *udev_device_get_id_filename(struct udev_device *udev_device) +{ + if (udev_device->id_filename == NULL) { + if (udev_device_get_subsystem(udev_device) == NULL) + return NULL; + + if (major(udev_device_get_devnum(udev_device)) > 0) { + /* use dev_t -- b259:131072, c254:0 */ + if (asprintf(&udev_device->id_filename, "%c%u:%u", + streq(udev_device_get_subsystem(udev_device), "block") ? 'b' : 'c', + major(udev_device_get_devnum(udev_device)), + minor(udev_device_get_devnum(udev_device))) < 0) + udev_device->id_filename = NULL; + } else if (udev_device_get_ifindex(udev_device) > 0) { + /* use netdev ifindex -- n3 */ + if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0) + udev_device->id_filename = NULL; + } else { + /* + * use $subsys:$syname -- pci:0000:00:1f.2 + * sysname() has '!' translated, get it from devpath + */ + const char *sysname; + sysname = strrchr(udev_device->devpath, '/'); + if (sysname == NULL) + return NULL; + sysname = &sysname[1]; + if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0) + udev_device->id_filename = NULL; + } + } + return udev_device->id_filename; +} + +/** + * udev_device_get_is_initialized: + * @udev_device: udev device + * + * Check if udev has already handled the device and has set up + * device node permissions and context, or has renamed a network + * device. + * + * This is only implemented for devices with a device node + * or network interfaces. All other devices return 1 here. + * + * Returns: 1 if the device is set up. 0 otherwise. + **/ +_public_ int udev_device_get_is_initialized(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + return udev_device->is_initialized; +} + +void udev_device_set_is_initialized(struct udev_device *udev_device) +{ + udev_device->is_initialized = true; +} + +int udev_device_add_tag(struct udev_device *udev_device, const char *tag) +{ + if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) + return -EINVAL; + udev_device->tags_uptodate = false; + if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) + return 0; + return -ENOMEM; +} + +void udev_device_cleanup_tags_list(struct udev_device *udev_device) +{ + udev_device->tags_uptodate = false; + udev_list_cleanup(&udev_device->tags_list); +} + +/** + * udev_device_get_tags_list_entry: + * @udev_device: udev device + * + * Retrieve the list of tags attached to the udev device. The next + * list entry can be retrieved with udev_list_entry_get_next(), + * which returns #NULL if no more entries exist. The tag string + * can be retrieved from the list entry by udev_list_entry_get_name(). + * + * Returns: the first entry of the tag list + **/ +_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + return udev_list_get_entry(&udev_device->tags_list); +} + +/** + * udev_device_has_tag: + * @udev_device: udev device + * @tag: tag name + * + * Check if a given device has a certain tag associated. + * + * Returns: 1 if the tag is found. 0 otherwise. + **/ +_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) +{ + struct udev_list_entry *list_entry; + + if (udev_device == NULL) + return false; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + list_entry = udev_device_get_tags_list_entry(udev_device); + if (udev_list_entry_get_by_name(list_entry, tag) != NULL) + return true; + return false; +} + +#define ENVP_SIZE 128 +#define MONITOR_BUF_SIZE 4096 +static int update_envp_monitor_buf(struct udev_device *udev_device) +{ + struct udev_list_entry *list_entry; + char *s; + size_t l; + unsigned int i; + + /* monitor buffer of property strings */ + free(udev_device->monitor_buf); + udev_device->monitor_buf_len = 0; + udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); + if (udev_device->monitor_buf == NULL) + return -ENOMEM; + + /* envp array, strings will point into monitor buffer */ + if (udev_device->envp == NULL) + udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); + if (udev_device->envp == NULL) + return -ENOMEM; + + i = 0; + s = udev_device->monitor_buf; + l = MONITOR_BUF_SIZE; + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { + const char *key; + + key = udev_list_entry_get_name(list_entry); + /* skip private variables */ + if (key[0] == '.') + continue; + + /* add string to envp array */ + udev_device->envp[i++] = s; + if (i+1 >= ENVP_SIZE) + return -EINVAL; + + /* add property string to monitor buffer */ + l = strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL); + if (l == 0) + return -EINVAL; + /* advance past the trailing '\0' that strpcpyl() guarantees */ + s++; + l--; + } + udev_device->envp[i] = NULL; + udev_device->monitor_buf_len = s - udev_device->monitor_buf; + udev_device->envp_uptodate = true; + return 0; +} + +char **udev_device_get_properties_envp(struct udev_device *udev_device) +{ + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf(udev_device) != 0) + return NULL; + return udev_device->envp; +} + +ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf) +{ + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf(udev_device) != 0) + return -EINVAL; + *buf = udev_device->monitor_buf; + return udev_device->monitor_buf_len; +} + +int udev_device_set_action(struct udev_device *udev_device, const char *action) +{ + free(udev_device->action); + udev_device->action = strdup(action); + if (udev_device->action == NULL) + return -ENOMEM; + udev_device_add_property(udev_device, "ACTION", udev_device->action); + return 0; +} + +int udev_device_get_devlink_priority(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + return udev_device->devlink_priority; +} + +int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) +{ + udev_device->devlink_priority = prio; + return 0; +} + +int udev_device_get_watch_handle(struct udev_device *udev_device) +{ + if (!udev_device->info_loaded) + udev_device_read_db(udev_device, NULL); + return udev_device->watch_handle; +} + +int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) +{ + udev_device->watch_handle = handle; + return 0; +} + +bool udev_device_get_db_persist(struct udev_device *udev_device) +{ + return udev_device->db_persist; +} + +void udev_device_set_db_persist(struct udev_device *udev_device) +{ + udev_device->db_persist = true; +} diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c new file mode 100644 index 0000000..1a880c2 --- /dev/null +++ b/src/libudev/libudev-enumerate.c @@ -0,0 +1,970 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +/** + * SECTION:libudev-enumerate + * @short_description: lookup and sort sys devices + * + * Lookup devices in the sys filesystem, filter devices by properties, + * and return a sorted list of devices. + */ + +struct syspath { + char *syspath; + size_t len; +}; + +/** + * udev_enumerate: + * + * Opaque object representing one device lookup/sort context. + */ +struct udev_enumerate { + struct udev *udev; + int refcount; + struct udev_list sysattr_match_list; + struct udev_list sysattr_nomatch_list; + struct udev_list subsystem_match_list; + struct udev_list subsystem_nomatch_list; + struct udev_list sysname_match_list; + struct udev_list properties_match_list; + struct udev_list tags_match_list; + struct udev_device *parent_match; + struct udev_list devices_list; + struct syspath *devices; + unsigned int devices_cur; + unsigned int devices_max; + bool devices_uptodate:1; + bool match_is_initialized; +}; + +/** + * udev_enumerate_new: + * @udev: udev library context + * + * Create an enumeration context to scan /sys. + * + * Returns: an enumeration context. + **/ +_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) +{ + struct udev_enumerate *udev_enumerate; + + if (udev == NULL) + return NULL; + udev_enumerate = new0(struct udev_enumerate, 1); + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount = 1; + udev_enumerate->udev = udev; + udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); + udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); + udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); + udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); + udev_list_init(udev, &udev_enumerate->sysname_match_list, true); + udev_list_init(udev, &udev_enumerate->properties_match_list, false); + udev_list_init(udev, &udev_enumerate->tags_match_list, true); + udev_list_init(udev, &udev_enumerate->devices_list, false); + return udev_enumerate; +} + +/** + * udev_enumerate_ref: + * @udev_enumerate: context + * + * Take a reference of a enumeration context. + * + * Returns: the passed enumeration context + **/ +_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount++; + return udev_enumerate; +} + +/** + * udev_enumerate_unref: + * @udev_enumerate: context + * + * Drop a reference of an enumeration context. If the refcount reaches zero, + * all resources of the enumeration context will be released. + * + * Returns: #NULL + **/ +_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) +{ + unsigned int i; + + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount--; + if (udev_enumerate->refcount > 0) + return NULL; + udev_list_cleanup(&udev_enumerate->sysattr_match_list); + udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); + udev_list_cleanup(&udev_enumerate->subsystem_match_list); + udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); + udev_list_cleanup(&udev_enumerate->sysname_match_list); + udev_list_cleanup(&udev_enumerate->properties_match_list); + udev_list_cleanup(&udev_enumerate->tags_match_list); + udev_device_unref(udev_enumerate->parent_match); + udev_list_cleanup(&udev_enumerate->devices_list); + for (i = 0; i < udev_enumerate->devices_cur; i++) + free(udev_enumerate->devices[i].syspath); + free(udev_enumerate->devices); + free(udev_enumerate); + return NULL; +} + +/** + * udev_enumerate_get_udev: + * @udev_enumerate: context + * + * Get the udev library context. + * + * Returns: a pointer to the context. + */ +_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return NULL; + return udev_enumerate->udev; +} + +static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath) +{ + char *path; + struct syspath *entry; + + /* double array size if needed */ + if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { + struct syspath *buf; + unsigned int add; + + add = udev_enumerate->devices_max; + if (add < 1024) + add = 1024; + buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath)); + if (buf == NULL) + return -ENOMEM; + udev_enumerate->devices = buf; + udev_enumerate->devices_max += add; + } + + path = strdup(syspath); + if (path == NULL) + return -ENOMEM; + entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; + entry->syspath = path; + entry->len = strlen(path); + udev_enumerate->devices_cur++; + udev_enumerate->devices_uptodate = false; + return 0; +} + +static int syspath_cmp(const void *p1, const void *p2) +{ + const struct syspath *path1 = p1; + const struct syspath *path2 = p2; + size_t len; + int ret; + + len = MIN(path1->len, path2->len); + ret = memcmp(path1->syspath, path2->syspath, len); + if (ret == 0) { + if (path1->len < path2->len) + ret = -1; + else if (path1->len > path2->len) + ret = 1; + } + return ret; +} + +/* For devices that should be moved to the absolute end of the list */ +static bool devices_delay_end(struct udev *udev, const char *syspath) +{ + static const char *delay_device_list[] = { + "/block/md", + "/block/dm-", + NULL + }; + int i; + + for (i = 0; delay_device_list[i] != NULL; i++) { + if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL) + return true; + } + return false; +} + +/* For devices that should just be moved a little bit later, just + * before the point where some common path prefix changes. Returns the + * number of characters that make up that common prefix */ +static size_t devices_delay_later(struct udev *udev, const char *syspath) +{ + const char *c; + + /* For sound cards the control device must be enumerated last + * to make sure it's the final device node that gets ACLs + * applied. Applications rely on this fact and use ACL changes + * on the control node as an indicator that the ACL change of + * the entire sound card completed. The kernel makes this + * guarantee when creating those devices, and hence we should + * too when enumerating them. */ + + if ((c = strstr(syspath, "/sound/card"))) { + c += 11; + c += strcspn(c, "/"); + + if (startswith(c, "/controlC")) + return c - syspath + 1; + } + + return 0; +} + +/** + * udev_enumerate_get_list_entry: + * @udev_enumerate: context + * + * Get the first entry of the sorted list of device paths. + * + * Returns: a udev_list_entry. + */ +_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return NULL; + if (!udev_enumerate->devices_uptodate) { + unsigned int i; + int move_later = -1; + unsigned int max; + struct syspath *prev = NULL; + size_t move_later_prefix = 0; + + udev_list_cleanup(&udev_enumerate->devices_list); + qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp); + + max = udev_enumerate->devices_cur; + for (i = 0; i < max; i++) { + struct syspath *entry = &udev_enumerate->devices[i]; + + /* skip duplicated entries */ + if (prev != NULL && + entry->len == prev->len && + memcmp(entry->syspath, prev->syspath, entry->len) == 0) + continue; + prev = entry; + + /* skip to be delayed devices, and add them to the end of the list */ + if (devices_delay_end(udev_enumerate->udev, entry->syspath)) { + syspath_add(udev_enumerate, entry->syspath); + /* need to update prev here for the case realloc() gives a different address */ + prev = &udev_enumerate->devices[i]; + continue; + } + + /* skip to be delayed devices, and move the to + * the point where the prefix changes. We can + * only move one item at a time. */ + if (move_later == -1) { + move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath); + + if (move_later_prefix > 0) { + move_later = i; + continue; + } + } + + if ((move_later >= 0) && + !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) { + + udev_list_entry_add(&udev_enumerate->devices_list, + udev_enumerate->devices[move_later].syspath, NULL); + move_later = -1; + } + + udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); + } + + if (move_later >= 0) + udev_list_entry_add(&udev_enumerate->devices_list, + udev_enumerate->devices[move_later].syspath, NULL); + + /* add and cleanup delayed devices from end of list */ + for (i = max; i < udev_enumerate->devices_cur; i++) { + struct syspath *entry = &udev_enumerate->devices[i]; + + udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); + free(entry->syspath); + } + udev_enumerate->devices_cur = max; + + udev_enumerate->devices_uptodate = true; + } + return udev_list_get_entry(&udev_enumerate->devices_list); +} + +/** + * udev_enumerate_add_match_subsystem: + * @udev_enumerate: context + * @subsystem: filter for a subsystem of the device to include in the list + * + * Match only devices belonging to a certain kernel subsystem. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_enumerate_add_nomatch_subsystem: + * @udev_enumerate: context + * @subsystem: filter for a subsystem of the device to exclude from the list + * + * Match only devices not belonging to a certain kernel subsystem. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_enumerate_add_match_sysattr: + * @udev_enumerate: context + * @sysattr: filter for a sys attribute at the device to include in the list + * @value: optional value of the sys attribute + * + * Match only devices with a certain /sys device attribute. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_enumerate_add_nomatch_sysattr: + * @udev_enumerate: context + * @sysattr: filter for a sys attribute at the device to exclude from the list + * @value: optional value of the sys attribute + * + * Match only devices not having a certain /sys device attribute. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; +} + +static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val) +{ + const char *val = NULL; + bool match = false; + + val = udev_device_get_sysattr_value(dev, sysattr); + if (val == NULL) + goto exit; + if (match_val == NULL) { + match = true; + goto exit; + } + if (fnmatch(match_val, val, 0) == 0) { + match = true; + goto exit; + } +exit: + return match; +} + +/** + * udev_enumerate_add_match_property: + * @udev_enumerate: context + * @property: filter for a property of the device to include in the list + * @value: value of the property + * + * Match only devices with a certain property. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (property == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_enumerate_add_match_tag: + * @udev_enumerate: context + * @tag: filter for a tag of the device to include in the list + * + * Match only devices with a certain tag. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (tag == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_enumerate_add_match_parent: + * @udev_enumerate: context + * @parent: parent device where to start searching + * + * 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) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (parent == NULL) + return 0; + if (udev_enumerate->parent_match != NULL) + udev_device_unref(udev_enumerate->parent_match); + udev_enumerate->parent_match = udev_device_ref(parent); + return 0; +} + +/** + * udev_enumerate_add_match_is_initialized: + * @udev_enumerate: context + * + * Match only devices which udev has set up already. This makes + * sure, that the device node permissions and context are properly set + * and that network devices are fully renamed. + * + * Usually, devices which are found in the kernel but not already + * handled by udev, have still pending events. Services should subscribe + * to monitor events and wait for these devices to become ready, instead + * of using uninitialized devices. + * + * For now, this will not affect devices which do not have a device node + * and are not network interfaces. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return -EINVAL; + udev_enumerate->match_is_initialized = true; + return 0; +} + +/** + * udev_enumerate_add_match_sysname: + * @udev_enumerate: context + * @sysname: filter for the name of the device to include in the list + * + * Match only devices with a given /sys device name. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +{ + if (udev_enumerate == NULL) + return -EINVAL; + if (sysname == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) + return -ENOMEM; + return 0; +} + +static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +{ + struct udev_list_entry *list_entry; + + /* skip list */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) { + if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry))) + return false; + } + /* include list */ + if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) { + /* anything that does not match, will make it FALSE */ + if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry))) + return false; + } + return true; + } + return true; +} + +static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +{ + struct udev_list_entry *list_entry; + bool match = false; + + /* no match always matches */ + if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) + return true; + + /* loop over matches */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) { + const char *match_key = udev_list_entry_get_name(list_entry); + const char *match_value = udev_list_entry_get_value(list_entry); + struct udev_list_entry *property_entry; + + /* loop over device properties */ + udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) { + const char *dev_key = udev_list_entry_get_name(property_entry); + const char *dev_value = udev_list_entry_get_value(property_entry); + + if (fnmatch(match_key, dev_key, 0) != 0) + continue; + if (match_value == NULL && dev_value == NULL) { + match = true; + goto out; + } + if (match_value == NULL || dev_value == NULL) + continue; + if (fnmatch(match_value, dev_value, 0) == 0) { + match = true; + goto out; + } + } + } +out: + return match; +} + +static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +{ + struct udev_list_entry *list_entry; + + /* no match always matches */ + if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) + return true; + + /* loop over matches */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) + if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) + return false; + + return true; +} + +static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +{ + if (udev_enumerate->parent_match == NULL) + return true; + + return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match)); +} + +static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +{ + struct udev_list_entry *list_entry; + + if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) + return true; + + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) { + if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0) + continue; + return true; + } + return false; +} + +static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, + const char *basedir, const char *subdir1, const char *subdir2) +{ + char path[UTIL_PATH_SIZE]; + size_t l; + char *s; + DIR *dir; + struct dirent *dent; + + s = path; + l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL); + if (subdir1 != NULL) + l = strpcpyl(&s, l, "/", subdir1, NULL); + if (subdir2 != NULL) + strpcpyl(&s, l, "/", subdir2, NULL); + dir = opendir(path); + if (dir == NULL) + return -ENOENT; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char syspath[UTIL_PATH_SIZE]; + struct udev_device *dev; + + if (dent->d_name[0] == '.') + continue; + + if (!match_sysname(udev_enumerate, dent->d_name)) + continue; + + strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL); + dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath); + if (dev == NULL) + continue; + + if (udev_enumerate->match_is_initialized) { + /* + * All devices with a device node or network interfaces + * possibly need udev to adjust the device node permission + * or context, or rename the interface before it can be + * reliably used from other processes. + * + * For now, we can only check these types of devices, we + * might not store a database, and have no way to find out + * for all other types of devices. + */ + if (!udev_device_get_is_initialized(dev) && + (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0)) + goto nomatch; + } + if (!match_parent(udev_enumerate, dev)) + goto nomatch; + if (!match_tag(udev_enumerate, dev)) + goto nomatch; + if (!match_property(udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr(udev_enumerate, dev)) + goto nomatch; + + syspath_add(udev_enumerate, udev_device_get_syspath(dev)); +nomatch: + udev_device_unref(dev); + } + closedir(dir); + return 0; +} + +static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + struct udev_list_entry *list_entry; + + if (!subsystem) + return false; + + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) { + if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) + return false; + } + + if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) { + if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) + return true; + } + return false; + } + + return true; +} + +static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem) +{ + char path[UTIL_PATH_SIZE]; + DIR *dir; + struct dirent *dent; + + strscpyl(path, sizeof(path), "/sys/", basedir, NULL); + dir = opendir(path); + if (dir == NULL) + return -1; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + if (dent->d_name[0] == '.') + continue; + if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name)) + continue; + scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir); + } + closedir(dir); + return 0; +} + +/** + * udev_enumerate_add_syspath: + * @udev_enumerate: context + * @syspath: path of a device + * + * Add a device to the list of devices, to retrieve it back sorted in dependency order. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) +{ + struct udev_device *udev_device; + + if (udev_enumerate == NULL) + return -EINVAL; + if (syspath == NULL) + return 0; + /* resolve to real syspath */ + udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath); + if (udev_device == NULL) + return -EINVAL; + syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); + udev_device_unref(udev_device); + return 0; +} + +static int scan_devices_tags(struct udev_enumerate *udev_enumerate) +{ + struct udev_list_entry *list_entry; + + /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) { + DIR *dir; + struct dirent *dent; + char path[UTIL_PATH_SIZE]; + + strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL); + dir = opendir(path); + if (dir == NULL) + continue; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct udev_device *dev; + + if (dent->d_name[0] == '.') + continue; + + dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name); + if (dev == NULL) + continue; + + if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev))) + goto nomatch; + if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev))) + goto nomatch; + if (!match_parent(udev_enumerate, dev)) + goto nomatch; + if (!match_property(udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr(udev_enumerate, dev)) + goto nomatch; + + syspath_add(udev_enumerate, udev_device_get_syspath(dev)); +nomatch: + udev_device_unref(dev); + } + closedir(dir); + } + return 0; +} + +static int parent_add_child(struct udev_enumerate *enumerate, const char *path) +{ + struct udev_device *dev; + int r = 0; + + dev = udev_device_new_from_syspath(enumerate->udev, path); + if (dev == NULL) + return -ENODEV; + + if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) + goto nomatch; + if (!match_sysname(enumerate, udev_device_get_sysname(dev))) + goto nomatch; + if (!match_property(enumerate, dev)) + goto nomatch; + if (!match_sysattr(enumerate, dev)) + goto nomatch; + + syspath_add(enumerate, udev_device_get_syspath(dev)); + r = 1; + +nomatch: + udev_device_unref(dev); + return r; +} + +static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth) +{ + DIR *d; + struct dirent *dent; + + d = opendir(path); + if (d == NULL) + return -errno; + + for (dent = readdir(d); dent != NULL; dent = readdir(d)) { + char *child; + + if (dent->d_name[0] == '.') + continue; + if (dent->d_type != DT_DIR) + continue; + if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) + continue; + parent_add_child(enumerate, child); + if (maxdepth > 0) + parent_crawl_children(enumerate, child, maxdepth-1); + free(child); + } + + closedir(d); + return 0; +} + +static int scan_devices_children(struct udev_enumerate *enumerate) +{ + const char *path; + + path = udev_device_get_syspath(enumerate->parent_match); + parent_add_child(enumerate, path); + return parent_crawl_children(enumerate, path, 256); +} + +static int scan_devices_all(struct udev_enumerate *udev_enumerate) +{ + struct stat statbuf; + + if (stat("/sys/subsystem", &statbuf) == 0) { + /* we have /subsystem/, forget all the old stuff */ + scan_dir(udev_enumerate, "subsystem", "devices", NULL); + } else { + scan_dir(udev_enumerate, "bus", "devices", NULL); + scan_dir(udev_enumerate, "class", NULL, NULL); + } + return 0; +} + +/** + * udev_enumerate_scan_devices: + * @udev_enumerate: udev enumeration context + * + * Scan /sys for all devices which match the given filters. No matches + * will return all currently available devices. + * + * Returns: 0 on success, otherwise a negative error value. + **/ +_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return -EINVAL; + + /* efficiently lookup tags only, we maintain a reverse-index */ + if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) + return scan_devices_tags(udev_enumerate); + + /* walk the subtree of one parent device only */ + if (udev_enumerate->parent_match != NULL) + return scan_devices_children(udev_enumerate); + + /* scan devices of all subsystems */ + return scan_devices_all(udev_enumerate); +} + +/** + * udev_enumerate_scan_subsystems: + * @udev_enumerate: udev enumeration context + * + * Scan /sys for all kernel subsystems, including buses, classes, drivers. + * + * Returns: 0 on success, otherwise a negative error value. + **/ +_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) +{ + struct stat statbuf; + const char *subsysdir; + + if (udev_enumerate == NULL) + return -EINVAL; + + /* all kernel modules */ + if (match_subsystem(udev_enumerate, "module")) + scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); + + if (stat("/sys/subsystem", &statbuf) == 0) + subsysdir = "subsystem"; + else + subsysdir = "bus"; + + /* all subsystems (only buses support coldplug) */ + if (match_subsystem(udev_enumerate, "subsystem")) + scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); + + /* all subsystem drivers */ + if (match_subsystem(udev_enumerate, "drivers")) + scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); + return 0; +} diff --git a/src/libudev/libudev-hwdb-def.h b/src/libudev/libudev-hwdb-def.h new file mode 100644 index 0000000..b76a13f --- /dev/null +++ b/src/libudev/libudev-hwdb-def.h @@ -0,0 +1,74 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifndef _LIBUDEV_HWDB_DEF_H_ +#define _LIBUDEV_HWDB_DEF_H_ + +#include "sparse-endian.h" + +#define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' } + +/* on-disk trie objects */ +struct trie_header_f { + uint8_t signature[8]; + + /* version of tool which created the file */ + le64_t tool_version; + le64_t file_size; + + /* size of structures to allow them to grow */ + le64_t header_size; + le64_t node_size; + le64_t child_entry_size; + le64_t value_entry_size; + + /* offset of the root trie node */ + le64_t nodes_root_off; + + /* size of the nodes and string section */ + le64_t nodes_len; + le64_t strings_len; +} _packed_; + +struct trie_node_f { + /* prefix of lookup string, shared by all children */ + le64_t prefix_off; + /* size of children entry array appended to the node */ + uint8_t children_count; + uint8_t padding[7]; + /* size of value entry array appended to the node */ + le64_t values_count; +} _packed_; + +/* array of child entries, follows directly the node record */ +struct trie_child_entry_f { + /* index of the child node */ + uint8_t c; + uint8_t padding[7]; + /* offset of the child node */ + le64_t child_off; +} _packed_; + +/* array of value entries, follows directly the node record/child array */ +struct trie_value_entry_f { + le64_t key_off; + le64_t value_off; +} _packed_; + +#endif diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c new file mode 100644 index 0000000..ff34e5a --- /dev/null +++ b/src/libudev/libudev-hwdb.c @@ -0,0 +1,396 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + Copyright 2008 Alan Jenkins + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev-private.h" +#include "libudev-hwdb-def.h" + +/** + * SECTION:libudev-hwdb + * @short_description: retrieve properties from the hardware database + * + * Libudev hardware database interface. + */ + +/** + * udev_hwdb: + * + * Opaque object representing the hardware database. + */ +struct udev_hwdb { + struct udev *udev; + int refcount; + + FILE *f; + struct stat st; + union { + struct trie_header_f *head; + const char *map; + }; + + struct udev_list properties_list; +}; + +struct linebuf { + char bytes[LINE_MAX]; + size_t size; + size_t len; +}; + +static void linebuf_init(struct linebuf *buf) { + buf->size = 0; + buf->len = 0; +} + +static const char *linebuf_get(struct linebuf *buf) { + if (buf->len + 1 >= sizeof(buf->bytes)) + return NULL; + buf->bytes[buf->len] = '\0'; + return buf->bytes; +} + +static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) { + if (buf->len + len >= sizeof(buf->bytes)) + return false; + memcpy(buf->bytes + buf->len, s, len); + buf->len += len; + return true; +} + +static bool linebuf_add_char(struct linebuf *buf, char c) +{ + if (buf->len + 1 >= sizeof(buf->bytes)) + return false; + buf->bytes[buf->len++] = c; + return true; +} + +static void linebuf_rem(struct linebuf *buf, size_t count) { + assert(buf->len >= count); + buf->len -= count; +} + +static void linebuf_rem_char(struct linebuf *buf) { + linebuf_rem(buf, 1); +} + +static const struct trie_child_entry_f *trie_node_children(struct udev_hwdb *hwdb, const struct trie_node_f *node) { + return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size)); +} + +static const struct trie_value_entry_f *trie_node_values(struct udev_hwdb *hwdb, const struct trie_node_f *node) { + const char *base = (const char *)node; + + base += le64toh(hwdb->head->node_size); + base += node->children_count * le64toh(hwdb->head->child_entry_size); + return (const struct trie_value_entry_f *)base; +} + +static const struct trie_node_f *trie_node_from_off(struct udev_hwdb *hwdb, le64_t off) { + return (const struct trie_node_f *)(hwdb->map + le64toh(off)); +} + +static const char *trie_string(struct udev_hwdb *hwdb, le64_t off) { + return hwdb->map + le64toh(off); +} + +static int trie_children_cmp_f(const void *v1, const void *v2) { + const struct trie_child_entry_f *n1 = v1; + const struct trie_child_entry_f *n2 = v2; + + return n1->c - n2->c; +} + +static const struct trie_node_f *node_lookup_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) { + struct trie_child_entry_f *child; + struct trie_child_entry_f search; + + search.c = c; + child = bsearch(&search, trie_node_children(hwdb, node), node->children_count, + le64toh(hwdb->head->child_entry_size), trie_children_cmp_f); + if (child) + return trie_node_from_off(hwdb, child->child_off); + return NULL; +} + +static int hwdb_add_property(struct udev_hwdb *hwdb, const char *key, const char *value) { + /* + * Silently ignore all properties which do not start with a + * space; future extensions might use additional prefixes. + */ + if (key[0] != ' ') + return 0; + + if (udev_list_entry_add(&hwdb->properties_list, key+1, value) == NULL) + return -ENOMEM; + return 0; +} + +static int trie_fnmatch_f(struct udev_hwdb *hwdb, const struct trie_node_f *node, size_t p, + struct linebuf *buf, const char *search) { + size_t len; + size_t i; + const char *prefix; + int err; + + prefix = trie_string(hwdb, node->prefix_off); + len = strlen(prefix + p); + linebuf_add(buf, prefix + p, len); + + for (i = 0; i < node->children_count; i++) { + const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i]; + + linebuf_add_char(buf, child->c); + err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search); + if (err < 0) + return err; + linebuf_rem_char(buf); + } + + if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0) + for (i = 0; i < le64toh(node->values_count); i++) { + err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off), + trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off)); + if (err < 0) + return err; + } + + linebuf_rem(buf, len); + return 0; +} + +static int trie_search_f(struct udev_hwdb *hwdb, const char *search) { + struct linebuf buf; + const struct trie_node_f *node; + size_t i = 0; + int err; + + linebuf_init(&buf); + + node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off); + while (node) { + const struct trie_node_f *child; + size_t p = 0; + + if (node->prefix_off) { + uint8_t c; + + for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) { + if (c == '*' || c == '?' || c == '[') + return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p); + if (c != search[i + p]) + return 0; + } + i += p; + } + + child = node_lookup_f(hwdb, node, '*'); + if (child) { + linebuf_add_char(&buf, '*'); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + child = node_lookup_f(hwdb, node, '?'); + if (child) { + linebuf_add_char(&buf, '?'); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + child = node_lookup_f(hwdb, node, '['); + if (child) { + linebuf_add_char(&buf, '['); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + if (search[i] == '\0') { + size_t n; + + for (n = 0; n < le64toh(node->values_count); n++) { + err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off), + trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off)); + if (err < 0) + return err; + } + return 0; + } + + child = node_lookup_f(hwdb, node, search[i]); + node = child; + i++; + } + return 0; +} + +/** + * udev_hwdb_new: + * @udev: udev library context + * + * Create a hardware database context to query properties for devices. + * + * Returns: a hwdb context. + **/ +_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) { + struct udev_hwdb *hwdb; + const char sig[] = HWDB_SIG; + + hwdb = new0(struct udev_hwdb, 1); + if (!hwdb) + return NULL; + + hwdb->refcount = 1; + udev_list_init(udev, &hwdb->properties_list, true); + + hwdb->f = fopen("/etc/udev/hwdb.bin", "re"); + if (!hwdb->f) { + udev_dbg(udev, "error reading /etc/udev/hwdb.bin: %m"); + udev_hwdb_unref(hwdb); + return NULL; + } + + if (fstat(fileno(hwdb->f), &hwdb->st) < 0 || + (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8) { + udev_dbg(udev, "error reading /etc/udev/hwdb.bin: %m"); + udev_hwdb_unref(hwdb); + return NULL; + } + + hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0); + if (hwdb->map == MAP_FAILED) { + udev_dbg(udev, "error mapping /etc/udev/hwdb.bin: %m"); + udev_hwdb_unref(hwdb); + return NULL; + } + + if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 || + (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) { + udev_dbg(udev, "error recognizing the format of /etc/udev/hwdb.bin"); + udev_hwdb_unref(hwdb); + return NULL; + } + + udev_dbg(udev, "=== trie on-disk ===\n"); + udev_dbg(udev, "tool version: %"PRIu64, le64toh(hwdb->head->tool_version)); + udev_dbg(udev, "file size: %8llu bytes\n", (unsigned long long) hwdb->st.st_size); + udev_dbg(udev, "header size %8"PRIu64" bytes\n", le64toh(hwdb->head->header_size)); + udev_dbg(udev, "strings %8"PRIu64" bytes\n", le64toh(hwdb->head->strings_len)); + udev_dbg(udev, "nodes %8"PRIu64" bytes\n", le64toh(hwdb->head->nodes_len)); + return hwdb; +} + +/** + * udev_hwdb_ref: + * @hwdb: context + * + * Take a reference of a hwdb context. + * + * Returns: the passed enumeration context + **/ +_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) { + if (!hwdb) + return NULL; + hwdb->refcount++; + return hwdb; +} + +/** + * udev_hwdb_unref: + * @hwdb: context + * + * Drop a reference of a hwdb context. If the refcount reaches zero, + * all resources of the hwdb context will be released. + * + * Returns: #NULL + **/ +_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) { + if (!hwdb) + return NULL; + hwdb->refcount--; + if (hwdb->refcount > 0) + return NULL; + if (hwdb->map) + munmap((void *)hwdb->map, hwdb->st.st_size); + if (hwdb->f) + fclose(hwdb->f); + udev_list_cleanup(&hwdb->properties_list); + free(hwdb); + return NULL; +} + +bool udev_hwdb_validate(struct udev_hwdb *hwdb) { + struct stat st; + + if (!hwdb) + return false; + if (!hwdb->f) + return false; + if (stat("/etc/udev/hwdb.bin", &st) < 0) + return true; + if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim)) + return true; + return false; +} + +/** + * udev_hwdb_get_properties_list_entry: + * @hwdb: context + * @modalias: modalias string + * @flags: (unused) + * + * Lookup a matching device in the hardware database. The lookup key is a + * modalias string, whose formats are defined for the Linux kernel modules. + * Examples are: pci:v00008086d00001C2D*, usb:v04F2pB221*. The first entry + * of a list of retrieved properties is returned. + * + * Returns: a udev_list_entry. + */ +_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) { + int err; + + if (!hwdb || !hwdb->f) { + errno = EINVAL; + return NULL; + } + + udev_list_cleanup(&hwdb->properties_list); + err = trie_search_f(hwdb, modalias); + if (err < 0) { + errno = -err; + return NULL; + } + return udev_list_get_entry(&hwdb->properties_list); +} diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c new file mode 100644 index 0000000..42fcb85 --- /dev/null +++ b/src/libudev/libudev-list.c @@ -0,0 +1,355 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +/** + * SECTION:libudev-list + * @short_description: list operation + * + * Libudev list operations. + */ + +/** + * udev_list_entry: + * + * Opaque object representing one entry in a list. An entry contains + * contains a name, and optionally a value. + */ +struct udev_list_entry { + struct udev_list_node node; + struct udev_list *list; + char *name; + char *value; + int num; +}; + +/* the list's head points to itself if empty */ +void udev_list_node_init(struct udev_list_node *list) +{ + list->next = list; + list->prev = list; +} + +int udev_list_node_is_empty(struct udev_list_node *list) +{ + return list->next == list; +} + +static void udev_list_node_insert_between(struct udev_list_node *new, + struct udev_list_node *prev, + struct udev_list_node *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) +{ + udev_list_node_insert_between(new, list->prev, list); +} + +void udev_list_node_remove(struct udev_list_node *entry) +{ + struct udev_list_node *prev = entry->prev; + struct udev_list_node *next = entry->next; + + next->prev = prev; + prev->next = next; + + entry->prev = NULL; + entry->next = NULL; +} + +/* return list entry which embeds this node */ +static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) +{ + return container_of(node, struct udev_list_entry, node); +} + +void udev_list_init(struct udev *udev, struct udev_list *list, bool unique) +{ + memzero(list, sizeof(struct udev_list)); + list->udev = udev; + list->unique = unique; + udev_list_node_init(&list->node); +} + +/* insert entry into a list as the last element */ +static void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list) +{ + /* inserting before the list head make the node the last node in the list */ + udev_list_node_insert_between(&new->node, list->node.prev, &list->node); + new->list = list; +} + +/* insert entry into a list, before a given existing entry */ +static void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) +{ + udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); + new->list = entry->list; +} + +/* binary search in sorted array */ +static int list_search(struct udev_list *list, const char *name) +{ + unsigned int first, last; + + first = 0; + last = list->entries_cur; + while (first < last) { + unsigned int i; + int cmp; + + i = (first + last)/2; + cmp = strcmp(name, list->entries[i]->name); + if (cmp < 0) + last = i; + else if (cmp > 0) + first = i+1; + else + return i; + } + + /* not found, return negative insertion-index+1 */ + return -(first+1); +} + +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value) +{ + struct udev_list_entry *entry; + int i = 0; + + if (list->unique) { + /* lookup existing name or insertion-index */ + i = list_search(list, name); + if (i >= 0) { + entry = list->entries[i]; + + free(entry->value); + if (value == NULL) { + entry->value = NULL; + return entry; + } + entry->value = strdup(value); + if (entry->value == NULL) + return NULL; + return entry; + } + } + + /* add new name */ + entry = new0(struct udev_list_entry, 1); + if (entry == NULL) + return NULL; + entry->name = strdup(name); + if (entry->name == NULL) { + free(entry); + return NULL; + } + if (value != NULL) { + entry->value = strdup(value); + if (entry->value == NULL) { + free(entry->name); + free(entry); + return NULL; + } + } + + if (list->unique) { + /* allocate or enlarge sorted array if needed */ + if (list->entries_cur >= list->entries_max) { + struct udev_list_entry **entries; + unsigned int add; + + add = list->entries_max; + if (add < 1) + add = 64; + entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *)); + if (entries == NULL) { + free(entry->name); + free(entry->value); + free(entry); + return NULL; + } + list->entries = entries; + list->entries_max += add; + } + + /* the negative i returned the insertion index */ + i = (-i)-1; + + /* insert into sorted list */ + if ((unsigned int)i < list->entries_cur) + udev_list_entry_insert_before(entry, list->entries[i]); + else + udev_list_entry_append(entry, list); + + /* insert into sorted array */ + memmove(&list->entries[i+1], &list->entries[i], + (list->entries_cur - i) * sizeof(struct udev_list_entry *)); + list->entries[i] = entry; + list->entries_cur++; + } else { + udev_list_entry_append(entry, list); + } + + return entry; +} + +void udev_list_entry_delete(struct udev_list_entry *entry) +{ + if (entry->list->entries != NULL) { + int i; + struct udev_list *list = entry->list; + + /* remove entry from sorted array */ + i = list_search(list, entry->name); + if (i >= 0) { + memmove(&list->entries[i], &list->entries[i+1], + ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *)); + list->entries_cur--; + } + } + + udev_list_node_remove(&entry->node); + free(entry->name); + free(entry->value); + free(entry); +} + +void udev_list_cleanup(struct udev_list *list) +{ + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_tmp; + + free(list->entries); + list->entries = NULL; + list->entries_cur = 0; + list->entries_max = 0; + udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) + udev_list_entry_delete(entry_loop); +} + +struct udev_list_entry *udev_list_get_entry(struct udev_list *list) +{ + if (udev_list_node_is_empty(&list->node)) + return NULL; + return list_node_to_entry(list->node.next); +} + +/** + * udev_list_entry_get_next: + * @list_entry: current entry + * + * Get the next entry from the list. + * + * Returns: udev_list_entry, #NULL if no more entries are available. + */ +_public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) +{ + struct udev_list_node *next; + + if (list_entry == NULL) + return NULL; + next = list_entry->node.next; + /* empty list or no more entries */ + if (next == &list_entry->list->node) + return NULL; + return list_node_to_entry(next); +} + +/** + * udev_list_entry_get_by_name: + * @list_entry: current entry + * @name: name string to match + * + * Lookup an entry in the list with a certain name. + * + * Returns: udev_list_entry, #NULL if no matching entry is found. + */ +_public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) +{ + int i; + + if (list_entry == NULL) + return NULL; + + if (!list_entry->list->unique) + return NULL; + + i = list_search(list_entry->list, name); + if (i < 0) + return NULL; + return list_entry->list->entries[i]; +} + +/** + * udev_list_entry_get_name: + * @list_entry: current entry + * + * Get the name of a list entry. + * + * Returns: the name string of this entry. + */ +_public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) +{ + if (list_entry == NULL) + return NULL; + return list_entry->name; +} + +/** + * udev_list_entry_get_value: + * @list_entry: current entry + * + * Get the value of list entry. + * + * Returns: the value string of this entry. + */ +_public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) +{ + if (list_entry == NULL) + return NULL; + return list_entry->value; +} + +int udev_list_entry_get_num(struct udev_list_entry *list_entry) +{ + if (list_entry == NULL) + return -EINVAL; + return list_entry->num; +} + +void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num) +{ + if (list_entry == NULL) + return; + list_entry->num = num; +} diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c new file mode 100644 index 0000000..ba1b04d --- /dev/null +++ b/src/libudev/libudev-monitor.c @@ -0,0 +1,854 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "socket-util.h" +#include "missing.h" + +/** + * SECTION:libudev-monitor + * @short_description: device event source + * + * Connects to a device event source. + */ + +/** + * udev_monitor: + * + * Opaque object handling an event source. + */ +struct udev_monitor { + struct udev *udev; + int refcount; + int sock; + union sockaddr_union snl; + union sockaddr_union snl_trusted_sender; + union sockaddr_union snl_destination; + socklen_t addrlen; + struct udev_list filter_subsystem_list; + struct udev_list filter_tag_list; + bool bound; +}; + +enum udev_monitor_netlink_group { + UDEV_MONITOR_NONE, + UDEV_MONITOR_KERNEL, + UDEV_MONITOR_UDEV, +}; + +#define UDEV_MONITOR_MAGIC 0xfeedcafe +struct udev_monitor_netlink_header { + /* "libudev" prefix to distinguish libudev and kernel messages */ + char prefix[8]; + /* + * magic to protect against daemon <-> library message format mismatch + * used in the kernel from socket filter rules; needs to be stored in network order + */ + unsigned int magic; + /* total length of header structure known to the sender */ + unsigned int header_size; + /* properties string buffer */ + unsigned int properties_off; + unsigned int properties_len; + /* + * hashes of primary device properties strings, to let libudev subscribers + * use in-kernel socket filters; values need to be stored in network order + */ + unsigned int filter_subsystem_hash; + unsigned int filter_devtype_hash; + unsigned int filter_tag_bloom_hi; + unsigned int filter_tag_bloom_lo; +}; + +static struct udev_monitor *udev_monitor_new(struct udev *udev) +{ + struct udev_monitor *udev_monitor; + + udev_monitor = new0(struct udev_monitor, 1); + if (udev_monitor == NULL) + return NULL; + udev_monitor->refcount = 1; + udev_monitor->udev = udev; + udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); + udev_list_init(udev, &udev_monitor->filter_tag_list, true); + return udev_monitor; +} + +/* we consider udev running when /dev is on devtmpfs */ +static bool udev_has_devtmpfs(struct udev *udev) { + struct file_handle *h; + int mount_id; + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX], *e; + int r; + + h = alloca(MAX_HANDLE_SZ); + h->handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(AT_FDCWD, "/dev", h, &mount_id, 0); + if (r < 0) + return false; + + + f = fopen("/proc/self/mountinfo", "re"); + if (!f) + return false; + + FOREACH_LINE(line, f, return false) { + int mid; + + if (sscanf(line, "%i", &mid) != 1) + continue; + + if (mid != mount_id) + continue; + + e = strstr(line, " - "); + if (!e) + continue; + + /* accept any name that starts with the currently expected type */ + if (startswith(e + 3, "devtmpfs")) + return true; + } + + return false; +} + +/* we consider udev running when we have running udev service */ +static bool udev_has_service(struct udev *udev) { + struct udev_queue *queue; + bool active; + + queue = udev_queue_new(udev); + if (!queue) + return false; + + active = udev_queue_get_udev_is_active(queue); + udev_queue_unref(queue); + + return active; +} + +struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) +{ + struct udev_monitor *udev_monitor; + unsigned int group; + + if (udev == NULL) + return NULL; + + if (name == NULL) + group = UDEV_MONITOR_NONE; + else if (streq(name, "udev")) { + /* + * We do not support subscribing to uevents if no instance of + * udev is running. Uevents would otherwise broadcast the + * processing data of the host into containers, which is not + * desired. + * + * Containers will currently not get any udev uevents, until + * a supporting infrastructure is available. + * + * We do not set a netlink multicast group here, so the socket + * will not receive any messages. + */ + if (!udev_has_service(udev) && !udev_has_devtmpfs(udev)) { + udev_dbg(udev, "the udev service seems not to be active, disable the monitor\n"); + group = UDEV_MONITOR_NONE; + } else + group = UDEV_MONITOR_UDEV; + } else if (streq(name, "kernel")) + group = UDEV_MONITOR_KERNEL; + else + return NULL; + + udev_monitor = udev_monitor_new(udev); + if (udev_monitor == NULL) + return NULL; + + if (fd < 0) { + udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); + if (udev_monitor->sock == -1) { + udev_err(udev, "error getting socket: %m\n"); + free(udev_monitor); + return NULL; + } + } else { + udev_monitor->bound = true; + udev_monitor->sock = fd; + } + + udev_monitor->snl.nl.nl_family = AF_NETLINK; + udev_monitor->snl.nl.nl_groups = group; + + /* default destination for sending */ + udev_monitor->snl_destination.nl.nl_family = AF_NETLINK; + udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; + + return udev_monitor; +} + +/** + * udev_monitor_new_from_netlink: + * @udev: udev library context + * @name: name of event source + * + * Create new udev monitor and connect to a specified event + * source. Valid sources identifiers are "udev" and "kernel". + * + * Applications should usually not connect directly to the + * "kernel" events, because the devices might not be useable + * at that time, before udev has configured them, and created + * device nodes. Accessing devices at the same time as udev, + * might result in unpredictable behavior. The "udev" events + * are sent out after udev has finished its event processing, + * all rules have been processed, and needed device nodes are + * created. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev monitor. + * + * Returns: a new udev monitor, or #NULL, in case of an error + **/ +_public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +{ + return udev_monitor_new_from_netlink_fd(udev, name, -1); +} + +static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data) +{ + struct sock_filter *ins = &inss[*i]; + + ins->code = code; + ins->k = data; + (*i)++; +} + +static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data, + unsigned short jt, unsigned short jf) +{ + struct sock_filter *ins = &inss[*i]; + + ins->code = code; + ins->jt = jt; + ins->jf = jf; + ins->k = data; + (*i)++; +} + +/** + * udev_monitor_filter_update: + * @udev_monitor: monitor + * + * Update the installed socket filter. This is only needed, + * if the filter was removed or changed. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) +{ + struct sock_filter ins[512]; + struct sock_fprog filter; + unsigned int i; + struct udev_list_entry *list_entry; + int err; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL && + udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) + return 0; + + memzero(ins, sizeof(ins)); + i = 0; + + /* load magic in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic)); + /* jump if magic matches */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0); + /* wrong magic, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) { + int tag_matches; + + /* count tag matches, to calculate end of tag match block */ + tag_matches = 0; + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) + tag_matches++; + + /* add all tags matches */ + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { + uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry)); + uint32_t tag_bloom_hi = tag_bloom_bits >> 32; + uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi); + /* jump to next tag if it does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3); + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo); + /* jump behind end of tag match block if tag matches */ + tag_matches--; + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0); + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + } + + /* add all subsystem matches */ + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) { + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { + unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry)); + + /* load device subsystem value in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash)); + if (udev_list_entry_get_value(list_entry) == NULL) { + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); + } else { + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3); + + /* load device devtype value in A */ + bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash)); + /* jump if value does not match */ + hash = util_string_hash32(udev_list_entry_get_value(list_entry)); + bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + if (i+1 >= ELEMENTSOF(ins)) + return -E2BIG; + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); + + /* install filter */ + memzero(&filter, sizeof(filter)); + filter.len = i; + filter.filter = ins; + err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); + return err < 0 ? -errno : 0; +} + +int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) +{ + udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; + return 0; +} +/** + * udev_monitor_enable_receiving: + * @udev_monitor: the monitor which should receive events + * + * Binds the @udev_monitor socket to the event source. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +{ + int err = 0; + const int on = 1; + + udev_monitor_filter_update(udev_monitor); + + if (!udev_monitor->bound) { + err = bind(udev_monitor->sock, + &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)); + if (err == 0) + udev_monitor->bound = true; + } + + if (err >= 0) { + union sockaddr_union snl; + socklen_t addrlen; + + /* + * get the address the kernel has assigned us + * it is usually, but not necessarily the pid + */ + addrlen = sizeof(struct sockaddr_nl); + err = getsockname(udev_monitor->sock, &snl.sa, &addrlen); + if (err == 0) + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; + } else { + udev_err(udev_monitor->udev, "bind failed: %m\n"); + return -errno; + } + + /* enable receiving of sender credentials */ + setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + return 0; +} + +/** + * udev_monitor_set_receive_buffer_size: + * @udev_monitor: the monitor which should receive events + * @size: the size in bytes + * + * Set the size of the kernel socket buffer. This call needs the + * appropriate privileges to succeed. + * + * Returns: 0 on success, otherwise -1 on error. + */ +_public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) +{ + if (udev_monitor == NULL) + return -EINVAL; + return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)); +} + +int udev_monitor_disconnect(struct udev_monitor *udev_monitor) +{ + int err; + + err = close(udev_monitor->sock); + udev_monitor->sock = -1; + return err < 0 ? -errno : 0; +} + +/** + * udev_monitor_ref: + * @udev_monitor: udev monitor + * + * Take a reference of a udev monitor. + * + * Returns: the passed udev monitor + **/ +_public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) +{ + if (udev_monitor == NULL) + return NULL; + udev_monitor->refcount++; + return udev_monitor; +} + +/** + * udev_monitor_unref: + * @udev_monitor: udev monitor + * + * Drop a reference of a udev monitor. If the refcount reaches zero, + * the bound socket will be closed, and the resources of the monitor + * will be released. + * + * Returns: #NULL + **/ +_public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) +{ + if (udev_monitor == NULL) + return NULL; + udev_monitor->refcount--; + if (udev_monitor->refcount > 0) + return NULL; + if (udev_monitor->sock >= 0) + close(udev_monitor->sock); + udev_list_cleanup(&udev_monitor->filter_subsystem_list); + udev_list_cleanup(&udev_monitor->filter_tag_list); + free(udev_monitor); + return NULL; +} + +/** + * udev_monitor_get_udev: + * @udev_monitor: udev monitor + * + * Retrieve the udev library context the monitor was created with. + * + * Returns: the udev library context + **/ +_public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) +{ + if (udev_monitor == NULL) + return NULL; + return udev_monitor->udev; +} + +/** + * udev_monitor_get_fd: + * @udev_monitor: udev monitor + * + * Retrieve the socket file descriptor associated with the monitor. + * + * Returns: the socket file descriptor + **/ +_public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) +{ + if (udev_monitor == NULL) + return -EINVAL; + return udev_monitor->sock; +} + +static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) +{ + struct udev_list_entry *list_entry; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) + goto tag; + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { + const char *subsys = udev_list_entry_get_name(list_entry); + const char *dsubsys = udev_device_get_subsystem(udev_device); + const char *devtype; + const char *ddevtype; + + if (!streq(dsubsys, subsys)) + continue; + + devtype = udev_list_entry_get_value(list_entry); + if (devtype == NULL) + goto tag; + ddevtype = udev_device_get_devtype(udev_device); + if (ddevtype == NULL) + continue; + if (streq(ddevtype, devtype)) + goto tag; + } + return 0; + +tag: + if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) + return 1; + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { + const char *tag = udev_list_entry_get_name(list_entry); + + if (udev_device_has_tag(udev_device, tag)) + return 1; + } + return 0; +} + +/** + * udev_monitor_receive_device: + * @udev_monitor: udev monitor + * + * Receive data from the udev monitor socket, allocate a new udev + * device, fill in the received data, and return the device. + * + * Only socket connections with uid=0 are accepted. + * + * The monitor socket is by default set to NONBLOCK. A variant of poll() on + * the file descriptor returned by udev_monitor_get_fd() should to be used to + * wake up when new devices arrive, or alternatively the file descriptor + * switched into blocking mode. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, in case of an error + **/ +_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) +{ + struct udev_device *udev_device; + struct msghdr smsg; + struct iovec iov; + char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *cmsg; + union sockaddr_union snl; + struct ucred *cred; + char buf[8192]; + ssize_t buflen; + ssize_t bufpos; + +retry: + if (udev_monitor == NULL) + return NULL; + iov.iov_base = &buf; + iov.iov_len = sizeof(buf); + memzero(&smsg, sizeof(struct msghdr)); + smsg.msg_iov = &iov; + smsg.msg_iovlen = 1; + smsg.msg_control = cred_msg; + smsg.msg_controllen = sizeof(cred_msg); + smsg.msg_name = &snl; + smsg.msg_namelen = sizeof(snl); + + buflen = recvmsg(udev_monitor->sock, &smsg, 0); + if (buflen < 0) { + if (errno != EINTR) + udev_dbg(udev_monitor->udev, "unable to receive message\n"); + return NULL; + } + + if (buflen < 32 || (size_t)buflen >= sizeof(buf)) { + udev_dbg(udev_monitor->udev, "invalid message length\n"); + return NULL; + } + + if (snl.nl.nl_groups == 0) { + /* unicast message, check if we trust the sender */ + if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || + snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) { + udev_dbg(udev_monitor->udev, "unicast netlink message ignored\n"); + return NULL; + } + } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { + if (snl.nl.nl_pid > 0) { + udev_dbg(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n", + snl.nl.nl_pid); + return NULL; + } + } + + cmsg = CMSG_FIRSTHDR(&smsg); + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { + udev_dbg(udev_monitor->udev, "no sender credentials received, message ignored\n"); + return NULL; + } + + cred = (struct ucred *)CMSG_DATA(cmsg); + if (cred->uid != 0) { + udev_dbg(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid); + return NULL; + } + + udev_device = udev_device_new(udev_monitor->udev); + if (udev_device == NULL) + return NULL; + + if (memcmp(buf, "libudev", 8) == 0) { + struct udev_monitor_netlink_header *nlh; + + /* udev message needs proper version magic */ + nlh = (struct udev_monitor_netlink_header *) buf; + if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) { + udev_err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n", + nlh->magic, htonl(UDEV_MONITOR_MAGIC)); + udev_device_unref(udev_device); + return NULL; + } + if (nlh->properties_off+32 > (size_t)buflen) { + udev_device_unref(udev_device); + return NULL; + } + + bufpos = nlh->properties_off; + + /* devices received from udev are always initialized */ + udev_device_set_is_initialized(udev_device); + } else { + /* kernel message with header */ + bufpos = strlen(buf) + 1; + if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) { + udev_dbg(udev_monitor->udev, "invalid message length\n"); + udev_device_unref(udev_device); + return NULL; + } + + /* check message header */ + if (strstr(buf, "@/") == NULL) { + udev_dbg(udev_monitor->udev, "unrecognized message header\n"); + udev_device_unref(udev_device); + return NULL; + } + } + + udev_device_set_info_loaded(udev_device); + + while (bufpos < buflen) { + char *key; + size_t keylen; + + key = &buf[bufpos]; + keylen = strlen(key); + if (keylen == 0) + break; + bufpos += keylen + 1; + udev_device_add_property_from_string_parse(udev_device, key); + } + + if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { + udev_dbg(udev_monitor->udev, "missing values, invalid device\n"); + udev_device_unref(udev_device); + return NULL; + } + + /* skip device, if it does not pass the current filter */ + if (!passes_filter(udev_monitor, udev_device)) { + struct pollfd pfd[1]; + int rc; + + udev_device_unref(udev_device); + + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + rc = poll(pfd, 1, 0); + if (rc > 0) + goto retry; + return NULL; + } + + return udev_device; +} + +int udev_monitor_send_device(struct udev_monitor *udev_monitor, + struct udev_monitor *destination, struct udev_device *udev_device) +{ + const char *buf; + ssize_t blen; + ssize_t count; + struct msghdr smsg; + struct iovec iov[2]; + const char *val; + struct udev_monitor_netlink_header nlh; + struct udev_list_entry *list_entry; + uint64_t tag_bloom_bits; + + blen = udev_device_get_properties_monitor_buf(udev_device, &buf); + if (blen < 32) + return -EINVAL; + + /* add versioned header */ + memzero(&nlh, sizeof(struct udev_monitor_netlink_header)); + memcpy(nlh.prefix, "libudev", 8); + nlh.magic = htonl(UDEV_MONITOR_MAGIC); + nlh.header_size = sizeof(struct udev_monitor_netlink_header); + val = udev_device_get_subsystem(udev_device); + nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); + val = udev_device_get_devtype(udev_device); + if (val != NULL) + nlh.filter_devtype_hash = htonl(util_string_hash32(val)); + iov[0].iov_base = &nlh; + iov[0].iov_len = sizeof(struct udev_monitor_netlink_header); + + /* add tag bloom filter */ + tag_bloom_bits = 0; + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) + tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); + if (tag_bloom_bits > 0) { + nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); + } + + /* add properties list */ + nlh.properties_off = iov[0].iov_len; + nlh.properties_len = blen; + iov[1].iov_base = (char *)buf; + iov[1].iov_len = blen; + + memzero(&smsg, sizeof(struct msghdr)); + smsg.msg_iov = iov; + smsg.msg_iovlen = 2; + /* + * Use custom address for target, or the default one. + * + * If we send to a multicast group, we will get + * ECONNREFUSED, which is expected. + */ + if (destination != NULL) + smsg.msg_name = &destination->snl; + else + smsg.msg_name = &udev_monitor->snl_destination; + smsg.msg_namelen = sizeof(struct sockaddr_nl); + count = sendmsg(udev_monitor->sock, &smsg, 0); + udev_dbg(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor); + return count; +} + +/** + * udev_monitor_filter_add_match_subsystem_devtype: + * @udev_monitor: the monitor + * @subsystem: the subsystem value to match the incoming devices against + * @devtype: the devtype value to match the incoming devices against + * + * This filter is efficiently executed inside the kernel, and libudev subscribers + * will usually not be woken up for devices which do not match. + * + * The filter must be installed before the monitor is switched to listening mode. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +{ + if (udev_monitor == NULL) + return -EINVAL; + if (subsystem == NULL) + return -EINVAL; + if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_monitor_filter_add_match_tag: + * @udev_monitor: the monitor + * @tag: the name of a tag + * + * This filter is efficiently executed inside the kernel, and libudev subscribers + * will usually not be woken up for devices which do not match. + * + * The filter must be installed before the monitor is switched to listening mode. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) +{ + if (udev_monitor == NULL) + return -EINVAL; + if (tag == NULL) + return -EINVAL; + if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL) + return -ENOMEM; + return 0; +} + +/** + * udev_monitor_filter_remove: + * @udev_monitor: monitor + * + * Remove all filters from monitor. + * + * Returns: 0 on success, otherwise a negative error value. + */ +_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) +{ + static struct sock_fprog filter = { 0, NULL }; + + udev_list_cleanup(&udev_monitor->filter_subsystem_list); + return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); +} diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h new file mode 100644 index 0000000..af0f125 --- /dev/null +++ b/src/libudev/libudev-private.h @@ -0,0 +1,176 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifndef _LIBUDEV_PRIVATE_H_ +#define _LIBUDEV_PRIVATE_H_ + +#include +#include +#include +#include + +#include "libudev.h" +#include "macro.h" +#include "util.h" +#include "mkdir.h" +#include "strxcpyx.h" + +#define READ_END 0 +#define WRITE_END 1 + +/* avoid (sometimes expensive) calculations of parameters for debug output */ +#define udev_log_cond(udev, prio, arg...) \ + do { \ + if (udev_get_log_priority(udev) >= prio) \ + udev_log(udev, prio, __FILE__, __LINE__, __FUNCTION__, ## arg); \ + } while (0) + +#define udev_dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg) +#define udev_info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg) +#define udev_err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg) + +/* libudev.c */ +void udev_log(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, ...) _printf_(6, 7); +int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]); +struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value); +struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev); + +/* libudev-device.c */ +struct udev_device *udev_device_new(struct udev *udev); +mode_t udev_device_get_devnode_mode(struct udev_device *udev_device); +uid_t udev_device_get_devnode_uid(struct udev_device *udev_device); +gid_t udev_device_get_devnode_gid(struct udev_device *udev_device); +int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem); +int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath); +int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink); +void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); +struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); +void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property); +int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device); +char **udev_device_get_properties_envp(struct udev_device *udev_device); +ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf); +int udev_device_read_db(struct udev_device *udev_device, const char *dbfile); +int udev_device_read_uevent_file(struct udev_device *udev_device); +int udev_device_set_action(struct udev_device *udev_device, const char *action); +const char *udev_device_get_devpath_old(struct udev_device *udev_device); +const char *udev_device_get_id_filename(struct udev_device *udev_device); +void udev_device_set_is_initialized(struct udev_device *udev_device); +int udev_device_add_tag(struct udev_device *udev_device, const char *tag); +void udev_device_cleanup_tags_list(struct udev_device *udev_device); +usec_t udev_device_get_usec_initialized(struct udev_device *udev_device); +void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized); +int udev_device_get_devlink_priority(struct udev_device *udev_device); +int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio); +int udev_device_get_watch_handle(struct udev_device *udev_device); +int udev_device_set_watch_handle(struct udev_device *udev_device, int handle); +int udev_device_get_ifindex(struct udev_device *udev_device); +void udev_device_set_info_loaded(struct udev_device *device); +bool udev_device_get_db_persist(struct udev_device *udev_device); +void udev_device_set_db_persist(struct udev_device *udev_device); + +/* libudev-device-private.c */ +int udev_device_update_db(struct udev_device *udev_device); +int udev_device_delete_db(struct udev_device *udev_device); +int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add); + +/* libudev-monitor.c - netlink/unix socket communication */ +int udev_monitor_disconnect(struct udev_monitor *udev_monitor); +int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender); +int udev_monitor_send_device(struct udev_monitor *udev_monitor, + struct udev_monitor *destination, struct udev_device *udev_device); +struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); + +/* libudev-list.c */ +struct udev_list_node { + struct udev_list_node *next, *prev; +}; +struct udev_list { + struct udev *udev; + struct udev_list_node node; + struct udev_list_entry **entries; + unsigned int entries_cur; + unsigned int entries_max; + bool unique; +}; +#define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } +void udev_list_node_init(struct udev_list_node *list); +int udev_list_node_is_empty(struct udev_list_node *list); +void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list); +void udev_list_node_remove(struct udev_list_node *entry); +#define udev_list_node_foreach(node, list) \ + for (node = (list)->next; \ + node != list; \ + node = (node)->next) +#define udev_list_node_foreach_safe(node, tmp, list) \ + for (node = (list)->next, tmp = (node)->next; \ + node != list; \ + node = tmp, tmp = (tmp)->next) +void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); +void udev_list_cleanup(struct udev_list *list); +struct udev_list_entry *udev_list_get_entry(struct udev_list *list); +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value); +void udev_list_entry_delete(struct udev_list_entry *entry); +int udev_list_entry_get_num(struct udev_list_entry *list_entry); +void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); +#define udev_list_entry_foreach_safe(entry, tmp, first) \ + for (entry = first, tmp = udev_list_entry_get_next(entry); \ + entry != NULL; \ + entry = tmp, tmp = udev_list_entry_get_next(tmp)) + +/* libudev-queue.c */ +unsigned long long int udev_get_kernel_seqnum(struct udev *udev); +int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum); +ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size); +ssize_t udev_queue_skip_devpath(FILE *queue_file); + +/* libudev-queue-private.c */ +struct udev_queue_export *udev_queue_export_new(struct udev *udev); +struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export); +void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export); +int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); +int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); + +/* libudev-hwdb.c */ +bool udev_hwdb_validate(struct udev_hwdb *hwdb); + +/* libudev-util.c */ +#define UTIL_PATH_SIZE 1024 +#define UTIL_NAME_SIZE 512 +#define UTIL_LINE_SIZE 16384 +#define UDEV_ALLOWED_CHARS_INPUT "/ $%?," +ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); +int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); +int util_log_priority(const char *priority); +size_t util_path_encode(const char *src, char *dest, size_t size); +void util_remove_trailing_chars(char *path, char c); +int util_replace_whitespace(const char *str, char *to, size_t len); +int util_replace_chars(char *str, const char *white); +unsigned int util_string_hash32(const char *key); +uint64_t util_string_bloom64(const char *str); + +/* libudev-util-private.c */ +int util_delete_path(struct udev *udev, const char *path); +uid_t util_lookup_user(struct udev *udev, const char *user); +gid_t util_lookup_group(struct udev *udev, const char *group); +int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); +ssize_t print_kmsg(const char *fmt, ...) _printf_(1, 2); + +#endif diff --git a/src/libudev/libudev-queue-private.c b/src/libudev/libudev-queue-private.c new file mode 100644 index 0000000..d5a2b50 --- /dev/null +++ b/src/libudev/libudev-queue-private.c @@ -0,0 +1,406 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + Copyright 2009 Alan Jenkins + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* + * DISCLAIMER - The file format mentioned here is private to udev/libudev, + * and may be changed without notice. + * + * The udev event queue is exported as a binary log file. + * Each log record consists of a sequence number followed by the device path. + * + * When a new event is queued, its details are appended to the log. + * When the event finishes, a second record is appended to the log + * with the same sequence number but a devpath len of 0. + * + * Example: + * { 0x0000000000000001 } + * { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" }, + * { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" }, + * { 0x0000000000000001, 0x0000 }, + * { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" }, + * + * Events 2 and 3 are still queued, but event 1 has finished. + * + * The queue does not grow indefinitely. It is periodically re-created + * to remove finished events. Atomic rename() makes this transparent to readers. + * + * The queue file starts with a single sequence number which specifies the + * minimum sequence number in the log that follows. Any events prior to this + * sequence number have already finished. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static int rebuild_queue_file(struct udev_queue_export *udev_queue_export); + +struct udev_queue_export { + struct udev *udev; + int queued_count; /* number of unfinished events exported in queue file */ + FILE *queue_file; + unsigned long long int seqnum_max; /* earliest sequence number in queue file */ + unsigned long long int seqnum_min; /* latest sequence number in queue file */ + int waste_bytes; /* queue file bytes wasted on finished events */ +}; + +struct udev_queue_export *udev_queue_export_new(struct udev *udev) +{ + struct udev_queue_export *udev_queue_export; + unsigned long long int initial_seqnum; + + if (udev == NULL) + return NULL; + + udev_queue_export = new0(struct udev_queue_export, 1); + if (udev_queue_export == NULL) + return NULL; + udev_queue_export->udev = udev; + + initial_seqnum = udev_get_kernel_seqnum(udev); + udev_queue_export->seqnum_min = initial_seqnum; + udev_queue_export->seqnum_max = initial_seqnum; + + udev_queue_export_cleanup(udev_queue_export); + if (rebuild_queue_file(udev_queue_export) != 0) { + free(udev_queue_export); + return NULL; + } + + return udev_queue_export; +} + +struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export) +{ + if (udev_queue_export == NULL) + return NULL; + if (udev_queue_export->queue_file != NULL) + fclose(udev_queue_export->queue_file); + free(udev_queue_export); + return NULL; +} + +void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export) +{ + if (udev_queue_export == NULL) + return; + unlink("/run/udev/queue.tmp"); + unlink("/run/udev/queue.bin"); +} + +static int skip_to(FILE *file, long offset) +{ + long old_offset; + + /* fseek may drop buffered data, avoid it for small seeks */ + old_offset = ftell(file); + if (offset > old_offset && offset - old_offset <= BUFSIZ) { + size_t skip_bytes = offset - old_offset; + char *buf = alloca(skip_bytes); + + if (fread(buf, skip_bytes, 1, file) != skip_bytes) + return -1; + } + + return fseek(file, offset, SEEK_SET); +} + +struct queue_devpaths { + unsigned int devpaths_first; /* index of first queued event */ + unsigned int devpaths_size; + long devpaths[]; /* seqnum -> offset of devpath in queue file (or 0) */ +}; + +/* + * Returns a table mapping seqnum to devpath file offset for currently queued events. + * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min. + */ +static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export) +{ + struct queue_devpaths *devpaths; + unsigned long long int range; + long devpath_offset; + ssize_t devpath_len; + unsigned long long int seqnum; + unsigned long long int n; + unsigned int i; + + /* seek to the first event in the file */ + rewind(udev_queue_export->queue_file); + udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum); + + /* allocate the table */ + range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max; + if (range - 1 > INT_MAX) { + udev_err(udev_queue_export->udev, "queue file overflow\n"); + return NULL; + } + devpaths = malloc0(sizeof(struct queue_devpaths) + (range + 1) * sizeof(long)); + if (devpaths == NULL) + return NULL; + devpaths->devpaths_size = range + 1; + + /* read all records and populate the table */ + for (;;) { + if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0) + break; + n = seqnum - udev_queue_export->seqnum_max; + if (n >= devpaths->devpaths_size) + goto read_error; + + devpath_offset = ftell(udev_queue_export->queue_file); + devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file); + if (devpath_len < 0) + goto read_error; + + if (devpath_len > 0) + devpaths->devpaths[n] = devpath_offset; + else + devpaths->devpaths[n] = 0; + } + + /* find first queued event */ + for (i = 0; i < devpaths->devpaths_size; i++) { + if (devpaths->devpaths[i] != 0) + break; + } + devpaths->devpaths_first = i; + + return devpaths; + +read_error: + udev_err(udev_queue_export->udev, "queue file corrupted\n"); + free(devpaths); + return NULL; +} + +static int rebuild_queue_file(struct udev_queue_export *udev_queue_export) +{ + unsigned long long int seqnum; + struct queue_devpaths *devpaths = NULL; + FILE *new_queue_file = NULL; + unsigned int i; + + /* read old queue file */ + if (udev_queue_export->queue_file != NULL) { + devpaths = build_index(udev_queue_export); + if (devpaths != NULL) + udev_queue_export->seqnum_max += devpaths->devpaths_first; + } + if (devpaths == NULL) { + udev_queue_export->queued_count = 0; + udev_queue_export->seqnum_max = udev_queue_export->seqnum_min; + } + + /* create new queue file */ + new_queue_file = fopen("/run/udev/queue.tmp", "w+e"); + if (new_queue_file == NULL) + goto error; + seqnum = udev_queue_export->seqnum_max; + fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file); + + /* copy unfinished events only to the new file */ + if (devpaths != NULL) { + for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) { + char devpath[UTIL_PATH_SIZE]; + int err; + unsigned short devpath_len; + + if (devpaths->devpaths[i] != 0) + { + skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]); + err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath)); + devpath_len = err; + + fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file); + fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file); + fwrite(devpath, 1, devpath_len, new_queue_file); + } + seqnum++; + } + free(devpaths); + devpaths = NULL; + } + fflush(new_queue_file); + if (ferror(new_queue_file)) + goto error; + + /* rename the new file on top of the old one */ + if (rename("/run/udev/queue.tmp", "/run/udev/queue.bin") != 0) + goto error; + + if (udev_queue_export->queue_file != NULL) + fclose(udev_queue_export->queue_file); + udev_queue_export->queue_file = new_queue_file; + udev_queue_export->waste_bytes = 0; + + return 0; + +error: + udev_err(udev_queue_export->udev, "failed to create queue file: %m\n"); + udev_queue_export_cleanup(udev_queue_export); + + if (udev_queue_export->queue_file != NULL) { + fclose(udev_queue_export->queue_file); + udev_queue_export->queue_file = NULL; + } + if (new_queue_file != NULL) + fclose(new_queue_file); + + if (devpaths != NULL) + free(devpaths); + udev_queue_export->queued_count = 0; + udev_queue_export->waste_bytes = 0; + udev_queue_export->seqnum_max = udev_queue_export->seqnum_min; + + return -1; +} + +static int write_queue_record(struct udev_queue_export *udev_queue_export, + unsigned long long int seqnum, const char *devpath, size_t devpath_len) +{ + unsigned short len; + + if (udev_queue_export->queue_file == NULL) + return -1; + + if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1) + goto write_error; + + len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX; + if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1) + goto write_error; + if (len > 0) { + if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len) + goto write_error; + } + + /* *must* flush output; caller may fork */ + if (fflush(udev_queue_export->queue_file) != 0) + goto write_error; + + return 0; + +write_error: + /* if we failed half way through writing a record to a file, + we should not try to write any further records to it. */ + udev_err(udev_queue_export->udev, "error writing to queue file: %m\n"); + fclose(udev_queue_export->queue_file); + udev_queue_export->queue_file = NULL; + + return -1; +} + +enum device_state { + DEVICE_QUEUED, + DEVICE_FINISHED, +}; + +static inline size_t queue_record_size(size_t devpath_len) +{ + return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len; +} + +static int update_queue(struct udev_queue_export *udev_queue_export, + struct udev_device *udev_device, enum device_state state) +{ + unsigned long long int seqnum = udev_device_get_seqnum(udev_device); + const char *devpath = NULL; + size_t devpath_len = 0; + int bytes; + int err; + + /* FINISHED records have a zero length devpath */ + if (state == DEVICE_QUEUED) { + devpath = udev_device_get_devpath(udev_device); + devpath_len = strlen(devpath); + } + + /* recover from an earlier failed rebuild */ + if (udev_queue_export->queue_file == NULL) { + if (rebuild_queue_file(udev_queue_export) != 0) + return -1; + } + + /* if we're removing the last event from the queue, that's the best time to rebuild it */ + if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) { + /* we don't need to read the old queue file */ + fclose(udev_queue_export->queue_file); + udev_queue_export->queue_file = NULL; + rebuild_queue_file(udev_queue_export); + return 0; + } + + /* try to rebuild the queue files before they grow larger than one page. */ + bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len); + if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096) + rebuild_queue_file(udev_queue_export); + + /* don't record a finished event, if we already dropped the event in a failed rebuild */ + if (seqnum < udev_queue_export->seqnum_max) + return 0; + + /* now write to the queue */ + if (state == DEVICE_QUEUED) { + udev_queue_export->queued_count++; + udev_queue_export->seqnum_min = seqnum; + } else { + udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0); + udev_queue_export->queued_count--; + } + err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len); + + /* try to handle ENOSPC */ + if (err != 0 && udev_queue_export->queued_count == 0) { + udev_queue_export_cleanup(udev_queue_export); + err = rebuild_queue_file(udev_queue_export); + } + + return err; +} + +static int update(struct udev_queue_export *udev_queue_export, + struct udev_device *udev_device, enum device_state state) +{ + if (update_queue(udev_queue_export, udev_device, state) != 0) + return -1; + + return 0; +} + +int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device) +{ + return update(udev_queue_export, udev_device, DEVICE_QUEUED); +} + +int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device) +{ + return update(udev_queue_export, udev_device, DEVICE_FINISHED); +} diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c new file mode 100644 index 0000000..2cb4d67 --- /dev/null +++ b/src/libudev/libudev-queue.c @@ -0,0 +1,480 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + Copyright 2009 Alan Jenkins + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +/** + * SECTION:libudev-queue + * @short_description: access to currently active events + * + * The udev daemon processes events asynchronously. All events which do not have + * interdependencies run in parallel. This exports the current state of the + * event processing queue, and the current event sequence numbers from the kernel + * and the udev daemon. + */ + +/** + * udev_queue: + * + * Opaque object representing the current event queue in the udev daemon. + */ +struct udev_queue { + struct udev *udev; + int refcount; + struct udev_list queue_list; +}; + +/** + * udev_queue_new: + * @udev: udev library context + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev queue context. + * + * Returns: the udev queue context, or #NULL on error. + **/ +_public_ struct udev_queue *udev_queue_new(struct udev *udev) +{ + struct udev_queue *udev_queue; + + if (udev == NULL) + return NULL; + + udev_queue = new0(struct udev_queue, 1); + if (udev_queue == NULL) + return NULL; + udev_queue->refcount = 1; + udev_queue->udev = udev; + udev_list_init(udev, &udev_queue->queue_list, false); + return udev_queue; +} + +/** + * udev_queue_ref: + * @udev_queue: udev queue context + * + * Take a reference of a udev queue context. + * + * Returns: the same udev queue context. + **/ +_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) +{ + if (udev_queue == NULL) + return NULL; + udev_queue->refcount++; + return udev_queue; +} + +/** + * udev_queue_unref: + * @udev_queue: udev queue context + * + * Drop a reference of a udev queue context. If the refcount reaches zero, + * the resources of the queue context will be released. + * + * Returns: #NULL + **/ +_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) +{ + if (udev_queue == NULL) + return NULL; + udev_queue->refcount--; + if (udev_queue->refcount > 0) + return NULL; + udev_list_cleanup(&udev_queue->queue_list); + free(udev_queue); + return NULL; +} + +/** + * udev_queue_get_udev: + * @udev_queue: udev queue context + * + * Retrieve the udev library context the queue context was created with. + * + * Returns: the udev library context. + **/ +_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) +{ + if (udev_queue == NULL) + return NULL; + return udev_queue->udev; +} + +unsigned long long int udev_get_kernel_seqnum(struct udev *udev) +{ + unsigned long long int seqnum; + int fd; + char buf[32]; + ssize_t len; + + fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC); + if (fd < 0) + return 0; + len = read(fd, buf, sizeof(buf)); + close(fd); + if (len <= 2) + return 0; + buf[len-1] = '\0'; + seqnum = strtoull(buf, NULL, 10); + return seqnum; +} + +/** + * udev_queue_get_kernel_seqnum: + * @udev_queue: udev queue context + * + * Get the current kernel event sequence number. + * + * Returns: the sequence number. + **/ +_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) +{ + unsigned long long int seqnum; + + if (udev_queue == NULL) + return -EINVAL; + + seqnum = udev_get_kernel_seqnum(udev_queue->udev); + return seqnum; +} + +int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum) +{ + if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1) + return -1; + + return 0; +} + +ssize_t udev_queue_skip_devpath(FILE *queue_file) +{ + unsigned short int len; + + if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) { + char *devpath = alloca(len); + + /* use fread to skip, fseek might drop buffered data */ + if (fread(devpath, 1, len, queue_file) == len) + return len; + } + + return -1; +} + +ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size) +{ + unsigned short int read_bytes = 0; + unsigned short int len; + + if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1) + return -1; + + read_bytes = (len < size - 1) ? len : size - 1; + if (fread(devpath, 1, read_bytes, queue_file) != read_bytes) + return -1; + devpath[read_bytes] = '\0'; + + /* if devpath was too long, skip unread characters */ + if (read_bytes != len) { + unsigned short int skip_bytes = len - read_bytes; + char *buf = alloca(skip_bytes); + + if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes) + return -1; + } + + return read_bytes; +} + +static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start) +{ + FILE *queue_file; + + queue_file = fopen("/run/udev/queue.bin", "re"); + if (queue_file == NULL) + return NULL; + + if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) { + udev_err(udev_queue->udev, "corrupt queue file\n"); + fclose(queue_file); + return NULL; + } + + return queue_file; +} + +/** + * udev_queue_get_udev_seqnum: + * @udev_queue: udev queue context + * + * Get the last known udev event sequence number. + * + * Returns: the sequence number. + **/ +_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) +{ + unsigned long long int seqnum_udev; + FILE *queue_file; + + queue_file = open_queue_file(udev_queue, &seqnum_udev); + if (queue_file == NULL) + return 0; + + for (;;) { + unsigned long long int seqnum; + ssize_t devpath_len; + + if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) + break; + devpath_len = udev_queue_skip_devpath(queue_file); + if (devpath_len < 0) + break; + if (devpath_len > 0) + seqnum_udev = seqnum; + } + + fclose(queue_file); + return seqnum_udev; +} + +/** + * udev_queue_get_udev_is_active: + * @udev_queue: udev queue context + * + * Check if udev is active on the system. + * + * Returns: a flag indicating if udev is active. + **/ +_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) +{ + unsigned long long int seqnum_start; + FILE *queue_file; + + queue_file = open_queue_file(udev_queue, &seqnum_start); + if (queue_file == NULL) + return 0; + + fclose(queue_file); + return 1; +} + +/** + * udev_queue_get_queue_is_empty: + * @udev_queue: udev queue context + * + * Check if udev is currently processing any events. + * + * Returns: a flag indicating if udev is currently handling events. + **/ +_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) +{ + unsigned long long int seqnum_kernel; + unsigned long long int seqnum_udev = 0; + int queued = 0; + int is_empty = 0; + FILE *queue_file; + + if (udev_queue == NULL) + return -EINVAL; + queue_file = open_queue_file(udev_queue, &seqnum_udev); + if (queue_file == NULL) + return 1; + + for (;;) { + unsigned long long int seqnum; + ssize_t devpath_len; + + if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) + break; + devpath_len = udev_queue_skip_devpath(queue_file); + if (devpath_len < 0) + break; + + if (devpath_len > 0) { + queued++; + seqnum_udev = seqnum; + } else { + queued--; + } + } + + if (queued > 0) + goto out; + + seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue); + if (seqnum_udev < seqnum_kernel) + goto out; + + is_empty = 1; + +out: + fclose(queue_file); + return is_empty; +} + +/** + * udev_queue_get_seqnum_sequence_is_finished: + * @udev_queue: udev queue context + * @start: first event sequence number + * @end: last event sequence number + * + * Check if udev is currently processing any events in a given sequence number range. + * + * Returns: a flag indicating if any of the sequence numbers in the given range is currently active. + **/ +_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, + unsigned long long int start, unsigned long long int end) +{ + unsigned long long int seqnum; + ssize_t devpath_len; + int unfinished; + FILE *queue_file; + + if (udev_queue == NULL) + return -EINVAL; + queue_file = open_queue_file(udev_queue, &seqnum); + if (queue_file == NULL) + return 1; + if (start < seqnum) + start = seqnum; + if (start > end) { + fclose(queue_file); + return 1; + } + if (end - start > INT_MAX - 1) { + fclose(queue_file); + return -EOVERFLOW; + } + + /* + * we might start with 0, and handle the initial seqnum + * only when we find an entry in the queue file + **/ + unfinished = end - start; + + do { + if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) + break; + devpath_len = udev_queue_skip_devpath(queue_file); + if (devpath_len < 0) + break; + + /* + * we might start with an empty or re-build queue file, where + * the initial seqnum is not recorded as finished + */ + if (start == seqnum && devpath_len > 0) + unfinished++; + + if (devpath_len == 0) { + if (seqnum >= start && seqnum <= end) + unfinished--; + } + } while (unfinished > 0); + + fclose(queue_file); + + return (unfinished == 0); +} + +/** + * udev_queue_get_seqnum_is_finished: + * @udev_queue: udev queue context + * @seqnum: sequence number + * + * Check if udev is currently processing a given sequence number. + * + * Returns: a flag indicating if the given sequence number is currently active. + **/ +_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) +{ + if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum)) + return 0; + + return 1; +} + +/** + * udev_queue_get_queued_list_entry: + * @udev_queue: udev queue context + * + * Get the first entry of the list of queued events. + * + * Returns: a udev_list_entry. + **/ +_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) +{ + unsigned long long int seqnum; + FILE *queue_file; + + if (udev_queue == NULL) + return NULL; + udev_list_cleanup(&udev_queue->queue_list); + + queue_file = open_queue_file(udev_queue, &seqnum); + if (queue_file == NULL) + return NULL; + + for (;;) { + char syspath[UTIL_PATH_SIZE]; + char *s; + size_t l; + ssize_t len; + char seqnum_str[32]; + struct udev_list_entry *list_entry; + + if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) + break; + snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum); + + s = syspath; + l = strpcpy(&s, sizeof(syspath), "/sys"); + len = udev_queue_read_devpath(queue_file, s, l); + if (len < 0) + break; + + if (len > 0) { + udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str); + } else { + udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) { + if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) { + udev_list_entry_delete(list_entry); + break; + } + } + } + } + fclose(queue_file); + + return udev_list_get_entry(&udev_queue->queue_list); +} diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c new file mode 100644 index 0000000..d9cdde1 --- /dev/null +++ b/src/libudev/libudev-util.c @@ -0,0 +1,442 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device-nodes.h" +#include "libudev.h" +#include "libudev-private.h" +#include "utf8.h" +#include "MurmurHash2.h" + +/** + * SECTION:libudev-util + * @short_description: utils + * + * Utilities useful when dealing with devices and device node names. + */ + +int util_delete_path(struct udev *udev, const char *path) +{ + char p[UTIL_PATH_SIZE]; + char *pos; + int err = 0; + + if (path[0] == '/') + while(path[1] == '/') + path++; + strscpy(p, sizeof(p), path); + pos = strrchr(p, '/'); + if (pos == p || pos == NULL) + return 0; + + for (;;) { + *pos = '\0'; + pos = strrchr(p, '/'); + + /* don't remove the last one */ + if ((pos == p) || (pos == NULL)) + break; + + err = rmdir(p); + if (err < 0) { + if (errno == ENOENT) + err = 0; + break; + } + } + return err; +} + +uid_t util_lookup_user(struct udev *udev, const char *user) +{ + char *endptr; + struct passwd pwbuf; + struct passwd *pw; + uid_t uid; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *buf = alloca(buflen); + + if (streq(user, "root")) + return 0; + uid = strtoul(user, &endptr, 10); + if (endptr[0] == '\0') + return uid; + + errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw); + if (pw != NULL) + return pw->pw_uid; + if (errno == 0 || errno == ENOENT || errno == ESRCH) + udev_err(udev, "specified user '%s' unknown\n", user); + else + udev_err(udev, "error resolving user '%s': %m\n", user); + return 0; +} + +gid_t util_lookup_group(struct udev *udev, const char *group) +{ + char *endptr; + struct group grbuf; + struct group *gr; + gid_t gid = 0; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *buf = NULL; + + if (streq(group, "root")) + return 0; + gid = strtoul(group, &endptr, 10); + if (endptr[0] == '\0') + return gid; + gid = 0; + for (;;) { + char *newbuf; + + newbuf = realloc(buf, buflen); + if (!newbuf) + break; + buf = newbuf; + errno = getgrnam_r(group, &grbuf, buf, buflen, &gr); + if (gr != NULL) { + gid = gr->gr_gid; + } else if (errno == ERANGE) { + buflen *= 2; + continue; + } else if (errno == 0 || errno == ENOENT || errno == ESRCH) { + udev_err(udev, "specified group '%s' unknown\n", group); + } else { + udev_err(udev, "error resolving group '%s': %m\n", group); + } + break; + } + free(buf); + return gid; +} + +/* handle "[/]" format */ +int util_resolve_subsys_kernel(struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value) +{ + char temp[UTIL_PATH_SIZE]; + char *subsys; + char *sysname; + struct udev_device *dev; + char *attr; + + if (string[0] != '[') + return -1; + + strscpy(temp, sizeof(temp), string); + + subsys = &temp[1]; + + sysname = strchr(subsys, '/'); + if (sysname == NULL) + return -1; + sysname[0] = '\0'; + sysname = &sysname[1]; + + attr = strchr(sysname, ']'); + if (attr == NULL) + return -1; + attr[0] = '\0'; + attr = &attr[1]; + if (attr[0] == '/') + attr = &attr[1]; + if (attr[0] == '\0') + attr = NULL; + + if (read_value && attr == NULL) + return -1; + + dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); + if (dev == NULL) + return -1; + + if (read_value) { + const char *val; + + val = udev_device_get_sysattr_value(dev, attr); + if (val != NULL) + strscpy(result, maxsize, val); + else + result[0] = '\0'; + udev_dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); + } else { + size_t l; + char *s; + + s = result; + l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); + if (attr != NULL) + strpcpyl(&s, l, "/", attr, NULL); + udev_dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); + } + udev_device_unref(dev); + return 0; +} + +ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size) +{ + char path[UTIL_PATH_SIZE]; + char target[UTIL_PATH_SIZE]; + ssize_t len; + const char *pos; + + strscpyl(path, sizeof(path), syspath, "/", slink, NULL); + len = readlink(path, target, sizeof(target)); + if (len <= 0 || len == (ssize_t)sizeof(target)) + return -1; + target[len] = '\0'; + pos = strrchr(target, '/'); + if (pos == NULL) + return -1; + pos = &pos[1]; + return strscpy(value, size, pos); +} + +int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) +{ + char link_target[UTIL_PATH_SIZE]; + + ssize_t len; + int i; + int back; + char *base = NULL; + + len = readlink(syspath, link_target, sizeof(link_target)); + if (len <= 0 || len == (ssize_t)sizeof(link_target)) + return -1; + link_target[len] = '\0'; + + for (back = 0; startswith(&link_target[back * 3], "../"); back++) + ; + for (i = 0; i <= back; i++) { + base = strrchr(syspath, '/'); + if (base == NULL) + return -EINVAL; + base[0] = '\0'; + } + + strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL); + return 0; +} + +int util_log_priority(const char *priority) +{ + char *endptr; + int prio; + + prio = strtol(priority, &endptr, 10); + if (endptr[0] == '\0' || isspace(endptr[0])) + return prio; + if (startswith(priority, "err")) + return LOG_ERR; + if (startswith(priority, "info")) + return LOG_INFO; + if (startswith(priority, "debug")) + return LOG_DEBUG; + return 0; +} + +size_t util_path_encode(const char *src, char *dest, size_t size) +{ + size_t i, j; + + for (i = 0, j = 0; src[i] != '\0'; i++) { + if (src[i] == '/') { + if (j+4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x2f", 4); + j += 4; + } else if (src[i] == '\\') { + if (j+4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x5c", 4); + j += 4; + } else { + if (j+1 >= size) { + j = 0; + break; + } + dest[j] = src[i]; + j++; + } + } + dest[j] = '\0'; + return j; +} + +void util_remove_trailing_chars(char *path, char c) +{ + size_t len; + + if (path == NULL) + return; + len = strlen(path); + while (len > 0 && path[len-1] == c) + path[--len] = '\0'; +} + +int util_replace_whitespace(const char *str, char *to, size_t len) +{ + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen(str, len); + while (len && isspace(str[len-1])) + len--; + + /* strip leading whitespace */ + i = 0; + while (isspace(str[i]) && (i < len)) + i++; + + j = 0; + while (i < len) { + /* substitute multiple whitespace with a single '_' */ + if (isspace(str[i])) { + while (isspace(str[i])) + i++; + to[j++] = '_'; + } + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; +} + +/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ +int util_replace_chars(char *str, const char *white) +{ + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') { + int len; + + if (whitelisted_char_for_devnode(str[i], white)) { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i+1] == 'x') { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = utf8_encoded_valid_unichar(&str[i]); + if (len > 1) { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { + str[i] = ' '; + i++; + replaced++; + continue; + } + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; +} + +/** + * udev_util_encode_string: + * @str: input string to be encoded + * @str_enc: output string to store the encoded input string + * @len: maximum size of the output string, which may be + * four times as long as the input string + * + * Encode all potentially unsafe characters of a string to the + * corresponding 2 char hex value prefixed by '\x'. + * + * Returns: 0 if the entire string was copied, non-zero otherwise. + **/ +_public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len) +{ + return encode_devnode_name(str, str_enc, len); +} + +unsigned int util_string_hash32(const char *str) +{ + return MurmurHash2(str, strlen(str), 0); +} + +/* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ +uint64_t util_string_bloom64(const char *str) +{ + uint64_t bits = 0; + unsigned int hash = util_string_hash32(str); + + bits |= 1LLU << (hash & 63); + bits |= 1LLU << ((hash >> 6) & 63); + bits |= 1LLU << ((hash >> 12) & 63); + bits |= 1LLU << ((hash >> 18) & 63); + return bits; +} + +ssize_t print_kmsg(const char *fmt, ...) +{ + _cleanup_close_ int fd = -1; + va_list ap; + char text[1024]; + ssize_t len; + ssize_t ret; + + fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + len = snprintf(text, sizeof(text), "<30>systemd-udevd[%u]: ", getpid()); + + va_start(ap, fmt); + len += vsnprintf(text + len, sizeof(text) - len, fmt, ap); + va_end(ap); + + ret = write(fd, text, len); + if (ret < 0) + return -errno; + + return ret; +} diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c new file mode 100644 index 0000000..e2ab960 --- /dev/null +++ b/src/libudev/libudev.c @@ -0,0 +1,315 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "missing.h" + +/** + * SECTION:libudev + * @short_description: libudev context + * + * The context contains the default values read from the udev config file, + * and is passed to all library operations. + */ + +/** + * udev: + * + * Opaque object representing the library context. + */ +struct udev { + int refcount; + void (*log_fn)(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, va_list args); + void *userdata; + struct udev_list properties_list; + int log_priority; +}; + +void udev_log(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + udev->log_fn(udev, priority, file, line, fn, format, args); + va_end(args); +} + +_printf_(6,0) +static void log_stderr(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, va_list args) +{ + fprintf(stderr, "libudev: %s: ", fn); + vfprintf(stderr, format, args); +} + +/** + * udev_get_userdata: + * @udev: udev library context + * + * Retrieve stored data pointer from library context. This might be useful + * to access from callbacks like a custom logging function. + * + * Returns: stored userdata + **/ +_public_ void *udev_get_userdata(struct udev *udev) +{ + if (udev == NULL) + return NULL; + return udev->userdata; +} + +/** + * udev_set_userdata: + * @udev: udev library context + * @userdata: data pointer + * + * Store custom @userdata in the library context. + **/ +_public_ void udev_set_userdata(struct udev *udev, void *userdata) +{ + if (udev == NULL) + return; + udev->userdata = userdata; +} + +/** + * udev_new: + * + * Create udev library context. This reads the udev configuration + * file, and fills in the default values. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev library context. + * + * Returns: a new udev library context + **/ +_public_ struct udev *udev_new(void) +{ + struct udev *udev; + const char *env; + FILE *f; + + udev = new0(struct udev, 1); + if (udev == NULL) + return NULL; + udev->refcount = 1; + udev->log_fn = log_stderr; + udev->log_priority = LOG_INFO; + udev_list_init(udev, &udev->properties_list, true); + + f = fopen("/etc/udev/udev.conf", "re"); + if (f != NULL) { + char line[UTIL_LINE_SIZE]; + int line_nr = 0; + + while (fgets(line, sizeof(line), f)) { + size_t len; + char *key; + char *val; + + line_nr++; + + /* find key */ + key = line; + while (isspace(key[0])) + key++; + + /* comment or empty line */ + if (key[0] == '#' || key[0] == '\0') + continue; + + /* split key/value */ + val = strchr(key, '='); + if (val == NULL) { + udev_err(udev, "missing = in /etc/udev/udev.conf[%i]; skip line\n", line_nr); + continue; + } + val[0] = '\0'; + val++; + + /* find value */ + while (isspace(val[0])) + val++; + + /* terminate key */ + len = strlen(key); + if (len == 0) + continue; + while (isspace(key[len-1])) + len--; + key[len] = '\0'; + + /* terminate value */ + len = strlen(val); + if (len == 0) + continue; + while (isspace(val[len-1])) + len--; + val[len] = '\0'; + + if (len == 0) + continue; + + /* unquote */ + if (val[0] == '"' || val[0] == '\'') { + if (val[len-1] != val[0]) { + udev_err(udev, "inconsistent quoting in /etc/udev/udev.conf[%i]; skip line\n", line_nr); + continue; + } + val[len-1] = '\0'; + val++; + } + + if (streq(key, "udev_log")) { + udev_set_log_priority(udev, util_log_priority(val)); + continue; + } + } + fclose(f); + } + + /* environment overrides config */ + env = secure_getenv("UDEV_LOG"); + if (env != NULL) + udev_set_log_priority(udev, util_log_priority(env)); + + return udev; +} + +/** + * udev_ref: + * @udev: udev library context + * + * Take a reference of the udev library context. + * + * Returns: the passed udev library context + **/ +_public_ struct udev *udev_ref(struct udev *udev) +{ + if (udev == NULL) + return NULL; + udev->refcount++; + return udev; +} + +/** + * udev_unref: + * @udev: udev library context + * + * Drop a reference of the udev library context. If the refcount + * reaches zero, the resources of the context will be released. + * + * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise. + **/ +_public_ struct udev *udev_unref(struct udev *udev) +{ + if (udev == NULL) + return NULL; + udev->refcount--; + if (udev->refcount > 0) + return udev; + udev_list_cleanup(&udev->properties_list); + free(udev); + return NULL; +} + +/** + * udev_set_log_fn: + * @udev: udev library context + * @log_fn: function to be called for logging messages + * + * The built-in logging writes to stderr. It can be + * overridden by a custom function, to plug log messages + * into the users' logging functionality. + * + **/ +_public_ void udev_set_log_fn(struct udev *udev, + void (*log_fn)(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, va_list args)) +{ + udev->log_fn = log_fn; + udev_dbg(udev, "custom logging function %p registered\n", log_fn); +} + +/** + * udev_get_log_priority: + * @udev: udev library context + * + * The initial logging priority is read from the udev config file + * at startup. + * + * Returns: the current logging priority + **/ +_public_ int udev_get_log_priority(struct udev *udev) +{ + return udev->log_priority; +} + +/** + * udev_set_log_priority: + * @udev: udev library context + * @priority: the new logging priority + * + * Set the current logging priority. The value controls which messages + * are logged. + **/ +_public_ void udev_set_log_priority(struct udev *udev, int priority) +{ + char num[32]; + + udev->log_priority = priority; + snprintf(num, sizeof(num), "%u", udev->log_priority); + udev_add_property(udev, "UDEV_LOG", num); +} + +struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value) +{ + if (value == NULL) { + struct udev_list_entry *list_entry; + + list_entry = udev_get_properties_list_entry(udev); + list_entry = udev_list_entry_get_by_name(list_entry, key); + if (list_entry != NULL) + udev_list_entry_delete(list_entry); + return NULL; + } + return udev_list_entry_add(&udev->properties_list, key, value); +} + +struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) +{ + return udev_list_get_entry(&udev->properties_list); +} diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h new file mode 100644 index 0000000..b9b8f13 --- /dev/null +++ b/src/libudev/libudev.h @@ -0,0 +1,205 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifndef _LIBUDEV_H_ +#define _LIBUDEV_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * udev - library context + * + * reads the udev config and system environment + * allows custom logging + */ +struct udev; +struct udev *udev_ref(struct udev *udev); +struct udev *udev_unref(struct udev *udev); +struct udev *udev_new(void); +void udev_set_log_fn(struct udev *udev, + void (*log_fn)(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, va_list args)); +int udev_get_log_priority(struct udev *udev); +void udev_set_log_priority(struct udev *udev, int priority); +void *udev_get_userdata(struct udev *udev); +void udev_set_userdata(struct udev *udev, void *userdata); + +/* + * udev_list + * + * access to libudev generated lists + */ +struct udev_list_entry; +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); +struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name); +const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); +const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); +/** + * udev_list_entry_foreach: + * @list_entry: entry to store the current position + * @first_entry: first entry to start with + * + * Helper to iterate over all entries of a list. + */ +#define udev_list_entry_foreach(list_entry, first_entry) \ + for (list_entry = first_entry; \ + list_entry != NULL; \ + list_entry = udev_list_entry_get_next(list_entry)) + +/* + * udev_device + * + * access to sysfs/kernel devices + */ +struct udev_device; +struct udev_device *udev_device_ref(struct udev_device *udev_device); +struct udev_device *udev_device_unref(struct udev_device *udev_device); +struct udev *udev_device_get_udev(struct udev_device *udev_device); +struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); +struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); +struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); +struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id); +struct udev_device *udev_device_new_from_environment(struct udev *udev); +/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ +struct udev_device *udev_device_get_parent(struct udev_device *udev_device); +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, + const char *subsystem, const char *devtype); +/* retrieve device properties */ +const char *udev_device_get_devpath(struct udev_device *udev_device); +const char *udev_device_get_subsystem(struct udev_device *udev_device); +const char *udev_device_get_devtype(struct udev_device *udev_device); +const char *udev_device_get_syspath(struct udev_device *udev_device); +const char *udev_device_get_sysname(struct udev_device *udev_device); +const char *udev_device_get_sysnum(struct udev_device *udev_device); +const char *udev_device_get_devnode(struct udev_device *udev_device); +int udev_device_get_is_initialized(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); +const char *udev_device_get_driver(struct udev_device *udev_device); +dev_t udev_device_get_devnum(struct udev_device *udev_device); +const char *udev_device_get_action(struct udev_device *udev_device); +unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device); +unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device); +const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); +int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value); +int udev_device_has_tag(struct udev_device *udev_device, const char *tag); + +/* + * udev_monitor + * + * access to kernel uevents and udev events + */ +struct udev_monitor; +struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); +struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor); +struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); +/* kernel and udev generated events over netlink */ +struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); +/* bind socket */ +int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); +int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size); +int udev_monitor_get_fd(struct udev_monitor *udev_monitor); +struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); +/* in-kernel socket filters to select messages that get delivered to a listener */ +int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, + const char *subsystem, const char *devtype); +int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag); +int udev_monitor_filter_update(struct udev_monitor *udev_monitor); +int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); + +/* + * udev_enumerate + * + * search sysfs for specific devices and provide a sorted list + */ +struct udev_enumerate; +struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); +struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate); +struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); +struct udev_enumerate *udev_enumerate_new(struct udev *udev); +/* device properties filter */ +int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); +int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); +int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); +int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); +int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); +int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); +int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag); +int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent); +int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate); +int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath); +/* run enumeration with active filters */ +int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); +int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); +/* return device list */ +struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); + +/* + * udev_queue + * + * access to the currently running udev events + */ +struct udev_queue; +struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); +struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue); +struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); +struct udev_queue *udev_queue_new(struct udev *udev); +unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue); +unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue); +int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); +int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); +int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum); +int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, + unsigned long long int start, unsigned long long int end); +struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue); + +/* + * udev_hwdb + * + * access to the static hardware properties database + */ +struct udev_hwdb; +struct udev_hwdb *udev_hwdb_new(struct udev *udev); +struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb); +struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb); +struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags); + +/* + * udev_util + * + * udev specific utilities + */ +int udev_util_encode_string(const char *str, char *str_enc, size_t len); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/libudev/libudev.pc.in b/src/libudev/libudev.pc.in new file mode 100644 index 0000000..a0f3f52 --- /dev/null +++ b/src/libudev/libudev.pc.in @@ -0,0 +1,17 @@ +# 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libudev +Description: Library to access udev device information +Version: @VERSION@ +Libs: -L${libdir} -ludev +Cflags: -I${includedir} diff --git a/src/libudev/libudev.sym b/src/libudev/libudev.sym new file mode 100644 index 0000000..1e6f885 --- /dev/null +++ b/src/libudev/libudev.sym @@ -0,0 +1,114 @@ +/*** + 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. +***/ + +LIBUDEV_183 { +global: + udev_device_get_action; + udev_device_get_devlinks_list_entry; + udev_device_get_devnode; + udev_device_get_devnum; + udev_device_get_devpath; + udev_device_get_devtype; + udev_device_get_driver; + udev_device_get_is_initialized; + udev_device_get_parent; + udev_device_get_parent_with_subsystem_devtype; + udev_device_get_properties_list_entry; + udev_device_get_property_value; + udev_device_get_seqnum; + udev_device_get_subsystem; + udev_device_get_sysattr_list_entry; + udev_device_get_sysattr_value; + udev_device_get_sysname; + udev_device_get_sysnum; + udev_device_get_syspath; + udev_device_get_tags_list_entry; + udev_device_get_udev; + udev_device_get_usec_since_initialized; + udev_device_has_tag; + udev_device_new_from_devnum; + udev_device_new_from_environment; + udev_device_new_from_subsystem_sysname; + udev_device_new_from_syspath; + udev_device_ref; + udev_device_unref; + udev_enumerate_add_match_is_initialized; + udev_enumerate_add_match_parent; + udev_enumerate_add_match_property; + udev_enumerate_add_match_subsystem; + udev_enumerate_add_match_sysattr; + udev_enumerate_add_match_sysname; + udev_enumerate_add_match_tag; + udev_enumerate_add_nomatch_subsystem; + udev_enumerate_add_nomatch_sysattr; + udev_enumerate_add_syspath; + udev_enumerate_get_list_entry; + udev_enumerate_get_udev; + udev_enumerate_new; + udev_enumerate_ref; + udev_enumerate_scan_devices; + udev_enumerate_scan_subsystems; + udev_enumerate_unref; + udev_get_log_priority; + udev_get_userdata; + udev_list_entry_get_by_name; + udev_list_entry_get_name; + udev_list_entry_get_next; + udev_list_entry_get_value; + udev_monitor_enable_receiving; + udev_monitor_filter_add_match_subsystem_devtype; + udev_monitor_filter_add_match_tag; + udev_monitor_filter_remove; + udev_monitor_filter_update; + udev_monitor_get_fd; + udev_monitor_get_udev; + udev_monitor_new_from_netlink; + udev_monitor_receive_device; + udev_monitor_ref; + udev_monitor_set_receive_buffer_size; + udev_monitor_unref; + udev_new; + udev_queue_get_kernel_seqnum; + udev_queue_get_queue_is_empty; + udev_queue_get_queued_list_entry; + udev_queue_get_seqnum_is_finished; + udev_queue_get_seqnum_sequence_is_finished; + udev_queue_get_udev; + udev_queue_get_udev_is_active; + udev_queue_get_udev_seqnum; + udev_queue_new; + udev_queue_ref; + udev_queue_unref; + udev_ref; + udev_set_log_fn; + udev_set_log_priority; + udev_set_userdata; + udev_unref; + udev_util_encode_string; +local: + *; +}; + +LIBUDEV_189 { +global: + udev_device_new_from_device_id; +} LIBUDEV_183; + +LIBUDEV_196 { +global: + udev_hwdb_new; + udev_hwdb_ref; + udev_hwdb_unref; + udev_hwdb_get_properties_list_entry; +} LIBUDEV_189; + +LIBUDEV_199 { +global: + udev_device_set_sysattr_value; +} LIBUDEV_196; diff --git a/src/linux/auto_dev-ioctl.h b/src/linux/auto_dev-ioctl.h deleted file mode 100644 index 850f39b..0000000 --- a/src/linux/auto_dev-ioctl.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2008 Red Hat, Inc. All rights reserved. - * Copyright 2008 Ian Kent - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - */ - -#ifndef _LINUX_AUTO_DEV_IOCTL_H -#define _LINUX_AUTO_DEV_IOCTL_H - -#include - -#ifdef __KERNEL__ -#include -#else -#include -#endif /* __KERNEL__ */ - -#define AUTOFS_DEVICE_NAME "autofs" - -#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1 -#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0 - -#define AUTOFS_DEVID_LEN 16 - -#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) - -/* - * An ioctl interface for autofs mount point control. - */ - -struct args_protover { - __u32 version; -}; - -struct args_protosubver { - __u32 sub_version; -}; - -struct args_openmount { - __u32 devid; -}; - -struct args_ready { - __u32 token; -}; - -struct args_fail { - __u32 token; - __s32 status; -}; - -struct args_setpipefd { - __s32 pipefd; -}; - -struct args_timeout { - __u64 timeout; -}; - -struct args_requester { - __u32 uid; - __u32 gid; -}; - -struct args_expire { - __u32 how; -}; - -struct args_askumount { - __u32 may_umount; -}; - -struct args_ismountpoint { - union { - struct args_in { - __u32 type; - } in; - struct args_out { - __u32 devid; - __u32 magic; - } out; - }; -}; - -/* - * All the ioctls use this structure. - * When sending a path size must account for the total length - * of the chunk of memory otherwise is is the size of the - * structure. - */ - -struct autofs_dev_ioctl { - __u32 ver_major; - __u32 ver_minor; - __u32 size; /* total size of data passed in - * including this struct */ - __s32 ioctlfd; /* automount command fd */ - - /* Command parameters */ - - union { - struct args_protover protover; - struct args_protosubver protosubver; - struct args_openmount openmount; - struct args_ready ready; - struct args_fail fail; - struct args_setpipefd setpipefd; - struct args_timeout timeout; - struct args_requester requester; - struct args_expire expire; - struct args_askumount askumount; - struct args_ismountpoint ismountpoint; - }; - - char path[0]; -}; - -static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in) -{ - memset(in, 0, sizeof(struct autofs_dev_ioctl)); - in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; - in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; - in->size = sizeof(struct autofs_dev_ioctl); - in->ioctlfd = -1; - return; -} - -/* - * If you change this make sure you make the corresponding change - * to autofs-dev-ioctl.c:lookup_ioctl() - */ -enum { - /* Get various version info */ - AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71, - AUTOFS_DEV_IOCTL_PROTOVER_CMD, - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, - - /* Open mount ioctl fd */ - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, - - /* Close mount ioctl fd */ - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, - - /* Mount/expire status returns */ - AUTOFS_DEV_IOCTL_READY_CMD, - AUTOFS_DEV_IOCTL_FAIL_CMD, - - /* Activate/deactivate autofs mount */ - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, - AUTOFS_DEV_IOCTL_CATATONIC_CMD, - - /* Expiry timeout */ - AUTOFS_DEV_IOCTL_TIMEOUT_CMD, - - /* Get mount last requesting uid and gid */ - AUTOFS_DEV_IOCTL_REQUESTER_CMD, - - /* Check for eligible expire candidates */ - AUTOFS_DEV_IOCTL_EXPIRE_CMD, - - /* Request busy status */ - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, - - /* Check if path is a mountpoint */ - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, -}; - -#define AUTOFS_IOCTL 0x93 - -#define AUTOFS_DEV_IOCTL_VERSION \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_PROTOVER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_PROTOSUBVER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_OPENMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_READY \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_FAIL \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_SETPIPEFD \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_CATATONIC \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_TIMEOUT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_REQUESTER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_EXPIRE \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_ASKUMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl) - -#endif /* _LINUX_AUTO_DEV_IOCTL_H */ diff --git a/src/list.h b/src/list.h deleted file mode 100644 index 2bec8c9..0000000 --- a/src/list.h +++ /dev/null @@ -1,128 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foolisthfoo -#define foolisthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -/* The head of the linked list. Use this in the structure that shall - * contain the head of the linked list */ -#define LIST_HEAD(t,name) \ - t *name - -/* The pointers in the linked list's items. Use this in the item structure */ -#define LIST_FIELDS(t,name) \ - t *name##_next, *name##_prev - -/* Initialize the list's head */ -#define LIST_HEAD_INIT(t,head) \ - do { \ - (head) = NULL; } \ - while(false) - -/* Initialize a list item */ -#define LIST_INIT(t,name,item) \ - do { \ - t *_item = (item); \ - assert(_item); \ - _item->name##_prev = _item->name##_next = NULL; \ - } while(false) - -/* Prepend an item to the list */ -#define LIST_PREPEND(t,name,head,item) \ - do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->name##_next = *_head)) \ - _item->name##_next->name##_prev = _item; \ - _item->name##_prev = NULL; \ - *_head = _item; \ - } while(false) - -/* Remove an item from the list */ -#define LIST_REMOVE(t,name,head,item) \ - do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->name##_next) \ - _item->name##_next->name##_prev = _item->name##_prev; \ - if (_item->name##_prev) \ - _item->name##_prev->name##_next = _item->name##_next; \ - else { \ - assert(*_head == _item); \ - *_head = _item->name##_next; \ - } \ - _item->name##_next = _item->name##_prev = NULL; \ - } while(false) - -/* Find the head of the list */ -#define LIST_FIND_HEAD(t,name,item,head) \ - do { \ - t *_item = (item); \ - assert(_item); \ - while (_item->name##_prev) \ - _item = _item->name##_prev; \ - (head) = _item; \ - } while (false) - -/* Find the head of the list */ -#define LIST_FIND_TAIL(t,name,item,tail) \ - do { \ - t *_item = (item); \ - assert(_item); \ - while (_item->name##_next) \ - _item = _item->name##_next; \ - (tail) = _item; \ - } while (false) - -/* Insert an item after another one (a = where, b = what) */ -#define LIST_INSERT_AFTER(t,name,head,a,b) \ - do { \ - t **_head = &(head), *_a = (a), *_b = (b); \ - assert(_b); \ - if (!_a) { \ - if ((_b->name##_next = *_head)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = NULL; \ - *_head = _b; \ - } else { \ - if ((_b->name##_next = _a->name##_next)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = _a; \ - _a->name##_next = _b; \ - } \ - } while(false) - -#define LIST_JUST_US(name,item) \ - (!(item)->name##_prev && !(item)->name##_next) \ - -#define LIST_FOREACH(name,i,head) \ - for ((i) = (head); (i); (i) = (i)->name##_next) - -#define LIST_FOREACH_SAFE(name,i,n,head) \ - for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) - -#define LIST_FOREACH_BEFORE(name,i,p) \ - for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) - -#define LIST_FOREACH_AFTER(name,i,p) \ - for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) - -#endif diff --git a/src/load-dropin.c b/src/load-dropin.c deleted file mode 100644 index d114faa..0000000 --- a/src/load-dropin.c +++ /dev/null @@ -1,150 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "unit.h" -#include "load-dropin.h" -#include "log.h" -#include "strv.h" -#include "unit-name.h" - -static int iterate_dir(Unit *u, const char *path, UnitDependency dependency) { - DIR *d; - struct dirent *de; - int r; - - assert(u); - assert(path); - - d = opendir(path); - if (!d) { - - if (errno == ENOENT) - return 0; - - return -errno; - } - - while ((de = readdir(d))) { - char *f; - - if (ignore_file(de->d_name)) - continue; - - f = join(path, "/", de->d_name, NULL); - if (!f) { - r = -ENOMEM; - goto finish; - } - - r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true); - free(f); - - if (r < 0) - log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->meta.id, strerror(-r)); - } - - r = 0; - -finish: - closedir(d); - return r; -} - -static int process_dir(Unit *u, const char *unit_path, const char *name, const char *suffix, UnitDependency dependency) { - int r; - char *path; - - assert(u); - assert(unit_path); - assert(name); - assert(suffix); - - path = join(unit_path, "/", name, suffix, NULL); - if (!path) - return -ENOMEM; - - if (u->meta.manager->unit_path_cache && - !set_get(u->meta.manager->unit_path_cache, path)) - r = 0; - else - r = iterate_dir(u, path, dependency); - free(path); - - if (r < 0) - return r; - - if (u->meta.instance) { - char *template; - /* Also try the template dir */ - - template = unit_name_template(name); - if (!template) - return -ENOMEM; - - path = join(unit_path, "/", template, suffix, NULL); - free(template); - - if (!path) - return -ENOMEM; - - if (u->meta.manager->unit_path_cache && - !set_get(u->meta.manager->unit_path_cache, path)) - r = 0; - else - r = iterate_dir(u, path, dependency); - free(path); - - if (r < 0) - return r; - } - - return 0; -} - -int unit_load_dropin(Unit *u) { - Iterator i; - char *t; - - assert(u); - - /* Load dependencies from supplementary drop-in directories */ - - SET_FOREACH(t, u->meta.names, i) { - char **p; - - STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) { - int r; - - r = process_dir(u, *p, t, ".wants", UNIT_WANTS); - if (r < 0) - return r; - - r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES); - if (r < 0) - return r; - } - } - - return 0; -} diff --git a/src/load-dropin.h b/src/load-dropin.h deleted file mode 100644 index cf3a799..0000000 --- a/src/load-dropin.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooloaddropinhfoo -#define fooloaddropinhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "unit.h" - -/* Read service data supplementary drop-in directories */ - -int unit_load_dropin(Unit *u); - -#endif diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4 deleted file mode 100644 index 41797d2..0000000 --- a/src/load-fragment-gperf.gperf.m4 +++ /dev/null @@ -1,219 +0,0 @@ -%{ -#include -#include "conf-parser.h" -#include "load-fragment.h" -#include "missing.h" -%} -struct ConfigPerfItem; -%null_strings -%language=ANSI-C -%define slot-name section_and_lvalue -%define hash-function-name load_fragment_gperf_hash -%define lookup-function-name load_fragment_gperf_lookup -%readonly-tables -%omit-struct-type -%struct-type -%includes -%% -m4_dnl Define the context options only once -m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', -`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) -$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) -$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) -$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) -$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups) -$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context) -$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context) -$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context) -$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context) -$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context) -$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context) -$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork) -$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context) -$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) -$1.Environment, config_parse_unit_strv_printf, 0, offsetof($1, exec_context.environment) -$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) -$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) -$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) -$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) -$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path) -$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset) -$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup) -$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate) -$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier) -$1.SyslogFacility, config_parse_facility, 0, offsetof($1, exec_context.syslog_priority) -$1.SyslogLevel, config_parse_level, 0, offsetof($1, exec_context.syslog_priority) -$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) -$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) -$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) -$1.CapabilityBoundingSet, config_parse_exec_bounding_set, 0, offsetof($1, exec_context) -$1.TimerSlackNSec, config_parse_exec_timer_slack_nsec, 0, offsetof($1, exec_context) -$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) -$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) -$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) -$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) -$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) -$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) -$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) -$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) -$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) -$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) -$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) -$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) -$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) -$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) -$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) -$1.ControlGroup, config_parse_unit_cgroup, 0, 0 -$1.ControlGroupAttribute, config_parse_unit_cgroup_attr, 0, 0 -$1.CPUShares, config_parse_unit_cpu_shares, 0, 0 -$1.MemoryLimit, config_parse_unit_memory_limit, 0, 0 -$1.MemorySoftLimit, config_parse_unit_memory_limit, 0, 0 -$1.DeviceAllow, config_parse_unit_device_allow, 0, 0 -$1.DeviceDeny, config_parse_unit_device_allow, 0, 0 -$1.BlockIOWeight, config_parse_unit_blkio_weight, 0, 0 -$1.BlockIOReadBandwidth, config_parse_unit_blkio_bandwidth, 0, 0 -$1.BlockIOWriteBandwidth, config_parse_unit_blkio_bandwidth, 0, 0 -$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs) -$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs) -$1.InaccessibleDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) -$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) -$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) -$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) -$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name) -$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name) -$1.KillMode, config_parse_kill_mode, 0, offsetof($1, exec_context.kill_mode) -$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, exec_context.kill_signal) -$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, exec_context.send_sigkill) -$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) -$1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify)' -)m4_dnl -Unit.Names, config_parse_unit_names, 0, 0 -Unit.Description, config_parse_unit_string_printf, 0, offsetof(Meta, description) -Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 -Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 -Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 -Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 -Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 -Unit.BindTo, config_parse_unit_deps, UNIT_BIND_TO, 0 -Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0 -Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0 -Unit.After, config_parse_unit_deps, UNIT_AFTER, 0 -Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 -Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Meta, stop_when_unneeded) -Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Meta, refuse_manual_start) -Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Meta, refuse_manual_stop) -Unit.AllowIsolate, config_parse_bool, 0, offsetof(Meta, allow_isolate) -Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Meta, default_dependencies) -Unit.OnFailureIsolate, config_parse_bool, 0, offsetof(Meta, on_failure_isolate) -Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Meta, ignore_on_isolate) -Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Meta, ignore_on_snapshot) -Unit.JobTimeoutSec, config_parse_usec, 0, offsetof(Meta, job_timeout) -Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 -Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 -Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 -Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0 -Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0 -Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 -Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 -Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 -Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 -Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 -Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 -Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 -m4_dnl -Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) -Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) -Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command) -Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command) -Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command) -Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) -Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) -Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec) -Service.TimeoutSec, config_parse_usec, 0, offsetof(Service, timeout_usec) -Service.Type, config_parse_service_type, 0, offsetof(Service, type) -Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) -Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) -Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only) -Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit) -Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid) -m4_ifdef(`HAVE_SYSV_COMPAT', -`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)', -`Service.SysVStartPriority, config_parse_warn_compat, 0, 0') -Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking) -Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name) -Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) -Service.Sockets, config_parse_service_sockets, 0, 0 -Service.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Service, fsck_passno) -EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl -m4_dnl -Socket.ListenStream, config_parse_socket_listen, 0, 0 -Socket.ListenDatagram, config_parse_socket_listen, 0, 0 -Socket.ListenSequentialPacket, config_parse_socket_listen, 0, 0 -Socket.ListenFIFO, config_parse_socket_listen, 0, 0 -Socket.ListenNetlink, config_parse_socket_listen, 0, 0 -Socket.ListenSpecial, config_parse_socket_listen, 0, 0 -Socket.ListenMessageQueue, config_parse_socket_listen, 0, 0 -Socket.BindIPv6Only, config_parse_socket_bind, 0, 0, -Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog) -Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0 -Socket.ExecStartPre, config_parse_exec, SOCKET_EXEC_START_PRE, offsetof(Socket, exec_command) -Socket.ExecStartPost, config_parse_exec, SOCKET_EXEC_START_POST, offsetof(Socket, exec_command) -Socket.ExecStopPre, config_parse_exec, SOCKET_EXEC_STOP_PRE, offsetof(Socket, exec_command) -Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC_STOP_POST, offsetof(Socket, exec_command) -Socket.TimeoutSec, config_parse_usec, 0, offsetof(Socket, timeout_usec) -Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) -Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) -Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) -Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) -Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) -Socket.Priority, config_parse_int, 0, offsetof(Socket, priority) -Socket.ReceiveBuffer, config_parse_size, 0, offsetof(Socket, receive_buffer) -Socket.SendBuffer, config_parse_size, 0, offsetof(Socket, send_buffer) -Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos) -Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl) -Socket.Mark, config_parse_int, 0, offsetof(Socket, mark) -Socket.PipeSize, config_parse_size, 0, offsetof(Socket, pipe_size) -Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind) -Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) -Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) -Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) -Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) -Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) -Socket.Service, config_parse_socket_service, 0, 0 -EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl -m4_dnl -Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) -Mount.Where, config_parse_path, 0, offsetof(Mount, where) -Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) -Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) -Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) -Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) -EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl -m4_dnl -Automount.Where, config_parse_path, 0, offsetof(Automount, where) -Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) -m4_dnl -Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) -Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) -Swap.TimeoutSec, config_parse_usec, 0, offsetof(Swap, timeout_usec) -EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl -m4_dnl -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.Unit, config_parse_timer_unit, 0, 0 -m4_dnl -Path.PathExists, config_parse_path_spec, 0, 0 -Path.PathExistsGlob, config_parse_path_spec, 0, 0 -Path.PathChanged, config_parse_path_spec, 0, 0 -Path.DirectoryNotEmpty, config_parse_path_spec, 0, 0 -Path.Unit, config_parse_path_unit, 0, 0 -Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory) -Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode) -m4_dnl The [Install] section is ignored here. -Install.Alias, NULL, 0, 0 -Install.WantedBy, NULL, 0, 0 -Install.Also, NULL, 0, 0 diff --git a/src/load-fragment.c b/src/load-fragment.c deleted file mode 100644 index 12079c6..0000000 --- a/src/load-fragment.c +++ /dev/null @@ -1,2424 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "unit.h" -#include "strv.h" -#include "conf-parser.h" -#include "load-fragment.h" -#include "log.h" -#include "ioprio.h" -#include "securebits.h" -#include "missing.h" -#include "unit-name.h" -#include "bus-errors.h" - -#ifndef HAVE_SYSV_COMPAT -int config_parse_warn_compat( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue); - return 0; -} -#endif - -int config_parse_unit_deps( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - UnitDependency d = ltype; - Unit *u = userdata; - char *w; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t, *k; - int r; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - k = unit_name_printf(u, t); - free(t); - - if (!k) - return -ENOMEM; - - r = unit_add_dependency_by_name(u, d, k, NULL, true); - - if (r < 0) { - log_error("Failed to add dependency on %s, ignoring: %s", k, strerror(-r)); - free(k); - return 0; - } - - free(k); - } - - return 0; -} - -int config_parse_unit_names( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char *w; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t, *k; - int r; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - k = unit_name_printf(u, t); - free(t); - - if (!k) - return -ENOMEM; - - r = unit_merge_by_name(u, k); - - if (r < 0) { - log_error("Failed to add name %s, ignoring: %s", k, strerror(-r)); - free(k); - return 0; - } - - free(k); - } - - return 0; -} - -int config_parse_unit_string_printf( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char **s = data; - char *k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(s); - assert(u); - - if (!(k = unit_full_printf(u, rvalue))) - return -ENOMEM; - - free(*s); - if (*k) - *s = k; - else { - free(k); - *s = NULL; - } - - return 0; -} - -int config_parse_unit_strv_printf( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char *k; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(u); - - k = unit_full_printf(u, rvalue); - if (!k) - return -ENOMEM; - - r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata); - free(k); - - return r; -} - -int config_parse_unit_path_printf( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char **s = data; - char *k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(s); - assert(u); - - if (!(k = unit_full_printf(u, rvalue))) - return -ENOMEM; - - if (!path_is_absolute(k)) { - log_error("[%s:%u] Not an absolute path: %s", filename, line, k); - free(k); - return -EINVAL; - } - - path_kill_slashes(k); - - free(*s); - *s = k; - - return 0; -} - -int config_parse_socket_listen( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - SocketPort *p, *tail; - Socket *s; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - s = (Socket*) data; - - if (!(p = new0(SocketPort, 1))) - return -ENOMEM; - - if (streq(lvalue, "ListenFIFO")) { - p->type = SOCKET_FIFO; - - if (!(p->path = unit_full_printf(UNIT(s), rvalue))) { - free(p); - return -ENOMEM; - } - - path_kill_slashes(p->path); - - } else if (streq(lvalue, "ListenSpecial")) { - p->type = SOCKET_SPECIAL; - - if (!(p->path = unit_full_printf(UNIT(s), rvalue))) { - free(p); - return -ENOMEM; - } - - path_kill_slashes(p->path); - - } else if (streq(lvalue, "ListenMessageQueue")) { - - p->type = SOCKET_MQUEUE; - - if (!(p->path = unit_full_printf(UNIT(s), rvalue))) { - free(p); - return -ENOMEM; - } - - path_kill_slashes(p->path); - - } else if (streq(lvalue, "ListenNetlink")) { - char *k; - int r; - - p->type = SOCKET_SOCKET; - k = unit_full_printf(UNIT(s), rvalue); - r = socket_address_parse_netlink(&p->address, k); - free(k); - - if (r < 0) { - log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue); - free(p); - return 0; - } - - } else { - char *k; - int r; - - p->type = SOCKET_SOCKET; - k = unit_full_printf(UNIT(s), rvalue); - r = socket_address_parse(&p->address, k); - free(k); - - if (r < 0) { - log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue); - free(p); - return 0; - } - - if (streq(lvalue, "ListenStream")) - p->address.type = SOCK_STREAM; - else if (streq(lvalue, "ListenDatagram")) - p->address.type = SOCK_DGRAM; - else { - assert(streq(lvalue, "ListenSequentialPacket")); - p->address.type = SOCK_SEQPACKET; - } - - if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) { - log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue); - free(p); - return 0; - } - } - - p->fd = -1; - - if (s->ports) { - LIST_FIND_TAIL(SocketPort, port, s->ports, tail); - LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p); - } else - LIST_PREPEND(SocketPort, port, s->ports, p); - - return 0; -} - -int config_parse_socket_bind( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Socket *s; - SocketAddressBindIPv6Only b; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - s = (Socket*) data; - - if ((b = socket_address_bind_ipv6_only_from_string(rvalue)) < 0) { - int r; - - if ((r = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue); - return 0; - } - - s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH; - } else - s->bind_ipv6_only = b; - - return 0; -} - -int config_parse_exec_nice( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - int priority; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atoi(rvalue, &priority) < 0) { - log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue); - return 0; - } - - if (priority < PRIO_MIN || priority >= PRIO_MAX) { - log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->nice = priority; - c->nice_set = true; - - return 0; -} - -int config_parse_exec_oom_score_adjust( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - int oa; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atoi(rvalue, &oa) < 0) { - log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) { - log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->oom_score_adjust = oa; - c->oom_score_adjust_set = true; - - return 0; -} - -int config_parse_exec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecCommand **e = data, *nce; - char *path, **n; - unsigned k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(e); - - /* We accept an absolute path as first argument, or - * alternatively an absolute prefixed with @ to allow - * overriding of argv[0]. */ - - e += ltype; - - for (;;) { - char *w; - size_t l; - char *state; - bool honour_argv0 = false, ignore = false; - - path = NULL; - nce = NULL; - n = NULL; - - rvalue += strspn(rvalue, WHITESPACE); - - if (rvalue[0] == 0) - break; - - if (rvalue[0] == '-') { - ignore = true; - rvalue ++; - } - - if (rvalue[0] == '@') { - honour_argv0 = true; - rvalue ++; - } - - if (*rvalue != '/') { - log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue); - return 0; - } - - k = 0; - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (strncmp(w, ";", MAX(l, 1U)) == 0) - break; - - k++; - } - - if (!(n = new(char*, k + !honour_argv0))) - return -ENOMEM; - - k = 0; - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (strncmp(w, ";", MAX(l, 1U)) == 0) - break; - - if (honour_argv0 && w == rvalue) { - assert(!path); - if (!(path = cunescape_length(w, l))) - goto fail; - } else { - if (!(n[k++] = cunescape_length(w, l))) - goto fail; - } - } - - n[k] = NULL; - - if (!n[0]) { - log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue); - strv_free(n); - free(path); - return 0; - } - - if (!path) - if (!(path = strdup(n[0]))) - goto fail; - - assert(path_is_absolute(path)); - - if (!(nce = new0(ExecCommand, 1))) - goto fail; - - nce->argv = n; - nce->path = path; - nce->ignore = ignore; - - path_kill_slashes(nce->path); - - exec_command_append_list(e, nce); - - rvalue = state; - } - - return 0; - -fail: - n[k] = NULL; - strv_free(n); - free(path); - free(nce); - - return -ENOMEM; -} - -DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); -DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); - -int config_parse_socket_bindtodevice( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Socket *s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (rvalue[0] && !streq(rvalue, "*")) { - if (!(n = strdup(rvalue))) - return -ENOMEM; - } else - n = NULL; - - free(s->bind_to_device); - s->bind_to_device = n; - - return 0; -} - -DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier"); -DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier"); - -int config_parse_facility( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - - int *o = data, x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((x = log_facility_unshifted_from_string(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue); - return 0; - } - - *o = (x << 3) | LOG_PRI(*o); - - return 0; -} - -int config_parse_level( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - - int *o = data, x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((x = log_level_from_string(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue); - return 0; - } - - *o = (*o & LOG_FACMASK) | x; - return 0; -} - -int config_parse_exec_io_class( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - int x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((x = ioprio_class_from_string(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio)); - c->ioprio_set = true; - - return 0; -} - -int config_parse_exec_io_priority( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - int i; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) { - log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i); - c->ioprio_set = true; - - return 0; -} - -int config_parse_exec_cpu_sched_policy( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - - ExecContext *c = data; - int x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((x = sched_policy_from_string(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->cpu_sched_policy = x; - c->cpu_sched_set = true; - - return 0; -} - -int config_parse_exec_cpu_sched_prio( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - int i; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - /* On Linux RR/FIFO have the same range */ - if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) { - log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->cpu_sched_priority = i; - c->cpu_sched_set = true; - - return 0; -} - -int config_parse_exec_cpu_affinity( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - char *w; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t; - int r; - unsigned cpu; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - r = safe_atou(t, &cpu); - free(t); - - if (!(c->cpuset)) - if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus))) - return -ENOMEM; - - if (r < 0 || cpu >= c->cpuset_ncpus) { - log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue); - return 0; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset); - } - - return 0; -} - -int config_parse_exec_capabilities( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - cap_t cap; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (!(cap = cap_from_text(rvalue))) { - if (errno == ENOMEM) - return -ENOMEM; - - log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (c->capabilities) - cap_free(c->capabilities); - c->capabilities = cap; - - return 0; -} - -int config_parse_exec_secure_bits( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - char *w; - size_t l; - char *state; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (first_word(w, "keep-caps")) - c->secure_bits |= SECURE_KEEP_CAPS; - else if (first_word(w, "keep-caps-locked")) - c->secure_bits |= SECURE_KEEP_CAPS_LOCKED; - else if (first_word(w, "no-setuid-fixup")) - c->secure_bits |= SECURE_NO_SETUID_FIXUP; - else if (first_word(w, "no-setuid-fixup-locked")) - c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED; - else if (first_word(w, "noroot")) - c->secure_bits |= SECURE_NOROOT; - else if (first_word(w, "noroot-locked")) - c->secure_bits |= SECURE_NOROOT_LOCKED; - else { - log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue); - return 0; - } - } - - return 0; -} - -int config_parse_exec_bounding_set( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - char *w; - size_t l; - char *state; - bool invert = false; - uint64_t sum = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (rvalue[0] == '~') { - invert = true; - rvalue++; - } - - /* Note that we store this inverted internally, since the - * kernel wants it like this. But we actually expose it - * non-inverted everywhere to have a fully normalized - * interface. */ - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t; - int r; - cap_value_t cap; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - r = cap_from_name(t, &cap); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue); - return 0; - } - - sum |= ((uint64_t) 1ULL) << (uint64_t) cap; - } - - if (invert) - c->capability_bounding_set_drop |= sum; - else - c->capability_bounding_set_drop |= ~sum; - - return 0; -} - -int config_parse_exec_timer_slack_nsec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - unsigned long u; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atolu(rvalue, &u) < 0) { - log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue); - return 0; - } - - c->timer_slack_nsec = u; - - return 0; -} - -int config_parse_limit( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - struct rlimit **rl = data; - unsigned long long u; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - rl += ltype; - - if (streq(rvalue, "infinity")) - u = (unsigned long long) RLIM_INFINITY; - else if (safe_atollu(rvalue, &u) < 0) { - log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (!*rl) - if (!(*rl = new(struct rlimit, 1))) - return -ENOMEM; - - (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u; - return 0; -} - -int config_parse_unit_cgroup( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = userdata; - char *w; - size_t l; - char *state; - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t, *k; - int r; - - t = strndup(w, l); - if (!t) - return -ENOMEM; - - k = unit_full_printf(u, t); - free(t); - - if (!k) - return -ENOMEM; - - t = cunescape(k); - free(k); - - if (!t) - return -ENOMEM; - - r = unit_add_cgroup_from_text(u, t); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue); - return 0; - } - } - - return 0; -} - -#ifdef HAVE_SYSV_COMPAT -int config_parse_sysv_priority( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *priority = data; - int i; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atoi(rvalue, &i) < 0 || i < 0) { - log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue); - return 0; - } - - *priority = (int) i; - return 0; -} -#endif - -int config_parse_fsck_passno( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *passno = data; - int i; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atoi(rvalue, &i) || i < 0) { - log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue); - return 0; - } - - *passno = (int) i; - return 0; -} - -DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode"); - -int config_parse_kill_signal( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *sig = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(sig); - - if ((r = signal_from_string_try_harder(rvalue)) <= 0) { - log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue); - return 0; - } - - *sig = r; - return 0; -} - -int config_parse_exec_mount_flags( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ExecContext *c = data; - char *w; - size_t l; - char *state; - unsigned long flags = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - if (strncmp(w, "shared", MAX(l, 6U)) == 0) - flags |= MS_SHARED; - else if (strncmp(w, "slave", MAX(l, 5U)) == 0) - flags |= MS_SLAVE; - else if (strncmp(w, "private", MAX(l, 7U)) == 0) - flags |= MS_PRIVATE; - else { - log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue); - return 0; - } - } - - c->mount_flags = flags; - return 0; -} - -int config_parse_timer( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Timer *t = data; - usec_t u; - TimerValue *v; - TimerBase b; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((b = timer_base_from_string(lvalue)) < 0) { - log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue); - return 0; - } - - if (parse_usec(rvalue, &u) < 0) { - log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (!(v = new0(TimerValue, 1))) - return -ENOMEM; - - v->base = b; - v->value = u; - - LIST_PREPEND(TimerValue, value, t->values, v); - - return 0; -} - -int config_parse_timer_unit( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Timer *t = data; - int r; - DBusError error; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - dbus_error_init(&error); - - if (endswith(rvalue, ".timer")) { - log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue); - return 0; - } - - if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &t->unit)) < 0) { - log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); - dbus_error_free(&error); - return 0; - } - - return 0; -} - -int config_parse_path_spec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Path *p = data; - PathSpec *s; - PathType b; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((b = path_type_from_string(lvalue)) < 0) { - log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue); - return 0; - } - - if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (!(s = new0(PathSpec, 1))) - return -ENOMEM; - - if (!(s->path = strdup(rvalue))) { - free(s); - return -ENOMEM; - } - - path_kill_slashes(s->path); - - s->type = b; - s->inotify_fd = -1; - - LIST_PREPEND(PathSpec, spec, p->specs, s); - - return 0; -} - -int config_parse_path_unit( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Path *t = data; - int r; - DBusError error; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - dbus_error_init(&error); - - if (endswith(rvalue, ".path")) { - log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue); - return 0; - } - - if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &t->unit)) < 0) { - log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); - dbus_error_free(&error); - return 0; - } - - return 0; -} - -int config_parse_socket_service( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Socket *s = data; - int r; - DBusError error; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - dbus_error_init(&error); - - if (!endswith(rvalue, ".service")) { - log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue); - return 0; - } - - if ((r = manager_load_unit(s->meta.manager, rvalue, NULL, &error, (Unit**) &s->service)) < 0) { - log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); - dbus_error_free(&error); - return 0; - } - - return 0; -} - -int config_parse_service_sockets( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Service *s = data; - int r; - DBusError error; - char *state, *w; - size_t l; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - dbus_error_init(&error); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t; - Unit *sock; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - if (!endswith(t, ".socket")) { - log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue); - free(t); - continue; - } - - r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); - dbus_error_free(&error); - continue; - } - - if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0) - return r; - - if ((r = set_put(s->configured_sockets, sock)) < 0) - return r; - } - - return 0; -} - -int config_parse_unit_env_file( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char ***env = data, **k; - Unit *u = userdata; - char *s; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - s = unit_full_printf(u, rvalue); - if (!s) - return -ENOMEM; - - if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) { - log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s); - free(s); - return 0; - } - - k = strv_append(*env, s); - free(s); - if (!k) - return -ENOMEM; - - strv_free(*env); - *env = k; - - return 0; -} - -int config_parse_ip_tos( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *ip_tos = data, x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((x = ip_tos_from_string(rvalue)) < 0) - if (safe_atoi(rvalue, &x) < 0) { - log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *ip_tos = x; - return 0; -} - -int config_parse_unit_condition_path( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ConditionType cond = ltype; - Unit *u = data; - bool trigger, negate; - Condition *c; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - trigger = rvalue[0] == '|'; - if (trigger) - rvalue++; - - negate = rvalue[0] == '!'; - if (negate) - rvalue++; - - if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, rvalue); - return 0; - } - - c = condition_new(cond, rvalue, trigger, negate); - if (!c) - return -ENOMEM; - - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); - return 0; -} - -int config_parse_unit_condition_string( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ConditionType cond = ltype; - Unit *u = data; - bool trigger, negate; - Condition *c; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((trigger = rvalue[0] == '|')) - rvalue++; - - if ((negate = rvalue[0] == '!')) - rvalue++; - - if (!(c = condition_new(cond, rvalue, trigger, negate))) - return -ENOMEM; - - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); - return 0; -} - -int config_parse_unit_condition_null( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = data; - Condition *c; - bool trigger, negate; - int b; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((trigger = rvalue[0] == '|')) - rvalue++; - - if ((negate = rvalue[0] == '!')) - rvalue++; - - if ((b = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (!b) - negate = !negate; - - if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate))) - return -ENOMEM; - - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); - return 0; -} - -DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); - -int config_parse_unit_cgroup_attr( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Unit *u = data; - char **l; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - l = strv_split_quoted(rvalue); - if (!l) - return -ENOMEM; - - if (strv_length(l) != 2) { - log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL); - strv_free(l); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { - Unit *u = data; - int r; - unsigned long ul; - char *t; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (safe_atolu(rvalue, &ul) < 0 || ul < 1) { - log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (asprintf(&t, "%lu", ul) < 0) - return -ENOMEM; - - r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { - Unit *u = data; - int r; - off_t sz; - char *t; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) { - log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (asprintf(&t, "%llu", (unsigned long long) sz) < 0) - return -ENOMEM; - - r = unit_add_cgroup_attribute(u, - "memory", - streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes", - t, NULL); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -static int device_map(const char *controller, const char *name, const char *value, char **ret) { - char **l; - - assert(controller); - assert(name); - assert(value); - assert(ret); - - l = strv_split_quoted(value); - if (!l) - return -ENOMEM; - - assert(strv_length(l) >= 1); - - if (streq(l[0], "*")) { - - if (asprintf(ret, "a *:*%s%s", - isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) { - strv_free(l); - return -ENOMEM; - } - - } else { - struct stat st; - - if (stat(l[0], &st) < 0) { - log_warning("Couldn't stat device %s", l[0]); - strv_free(l); - return -errno; - } - - if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { - log_warning("%s is not a device.", l[0]); - strv_free(l); - return -ENODEV; - } - - if (asprintf(ret, "%c %u:%u%s%s", - S_ISCHR(st.st_mode) ? 'c' : 'b', - major(st.st_rdev), minor(st.st_rdev), - isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) { - - strv_free(l); - return -ENOMEM; - } - } - - strv_free(l); - return 0; -} - -int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { - Unit *u = data; - char **l; - int r; - unsigned k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - l = strv_split_quoted(rvalue); - if (!l) - return -ENOMEM; - - k = strv_length(l); - if (k < 1 || k > 2) { - log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) { - log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (!isempty(l[1]) && !in_charset(l[1], "rwm")) { - log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - strv_free(l); - - r = unit_add_cgroup_attribute(u, "devices", - streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny", - rvalue, device_map); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -static int blkio_map(const char *controller, const char *name, const char *value, char **ret) { - struct stat st; - char **l; - dev_t d; - - assert(controller); - assert(name); - assert(value); - assert(ret); - - l = strv_split_quoted(value); - if (!l) - return -ENOMEM; - - assert(strv_length(l) == 2); - - if (stat(l[0], &st) < 0) { - log_warning("Couldn't stat device %s", l[0]); - strv_free(l); - return -errno; - } - - if (S_ISBLK(st.st_mode)) - d = st.st_rdev; - else if (major(st.st_dev) != 0) { - /* If this is not a device node then find the block - * device this file is stored on */ - d = st.st_dev; - - /* If this is a partition, try to get the originating - * block device */ - block_get_whole_disk(d, &d); - } else { - log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]); - strv_free(l); - return -ENODEV; - } - - if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) { - strv_free(l); - return -ENOMEM; - } - - strv_free(l); - return 0; -} - -int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { - Unit *u = data; - int r; - unsigned long ul; - const char *device = NULL, *weight; - unsigned k; - char *t, **l; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - l = strv_split_quoted(rvalue); - if (!l) - return -ENOMEM; - - k = strv_length(l); - if (k < 1 || k > 2) { - log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (k == 1) - weight = l[0]; - else { - device = l[0]; - weight = l[1]; - } - - if (device && !path_is_absolute(device)) { - log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) { - log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (device) - r = asprintf(&t, "%s %lu", device, ul); - else - r = asprintf(&t, "%lu", ul); - strv_free(l); - - if (r < 0) - return -ENOMEM; - - if (device) - r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map); - else - r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { - Unit *u = data; - int r; - off_t bytes; - unsigned k; - char *t, **l; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - l = strv_split_quoted(rvalue); - if (!l) - return -ENOMEM; - - k = strv_length(l); - if (k != 2) { - log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (!path_is_absolute(l[0])) { - log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) { - log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue); - strv_free(l); - return 0; - } - - r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes); - strv_free(l); - - if (r < 0) - return -ENOMEM; - - r = unit_add_cgroup_attribute(u, "blkio", - streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device", - t, blkio_map); - free(t); - - if (r < 0) { - log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - - -#define FOLLOW_MAX 8 - -static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { - unsigned c = 0; - int fd, r; - FILE *f; - char *id = NULL; - - assert(filename); - assert(*filename); - assert(_f); - assert(names); - - /* This will update the filename pointer if the loaded file is - * reached by a symlink. The old string will be freed. */ - - for (;;) { - char *target, *name; - - if (c++ >= FOLLOW_MAX) - return -ELOOP; - - path_kill_slashes(*filename); - - /* Add the file name we are currently looking at to - * the names of this unit, but only if it is a valid - * unit name. */ - name = file_name_from_path(*filename); - - if (unit_name_is_valid(name, true)) { - - id = set_get(names, name); - if (!id) { - id = strdup(name); - if (!id) - return -ENOMEM; - - r = set_put(names, id); - if (r < 0) { - free(id); - return r; - } - } - } - - /* Try to open the file name, but don't if its a symlink */ - if ((fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0) - break; - - if (errno != ELOOP) - return -errno; - - /* Hmm, so this is a symlink. Let's read the name, and follow it manually */ - if ((r = readlink_and_make_absolute(*filename, &target)) < 0) - return r; - - free(*filename); - *filename = target; - } - - if (!(f = fdopen(fd, "re"))) { - r = -errno; - close_nointr_nofail(fd); - return r; - } - - *_f = f; - *_final = id; - return 0; -} - -static int merge_by_names(Unit **u, Set *names, const char *id) { - char *k; - int r; - - assert(u); - assert(*u); - assert(names); - - /* Let's try to add in all symlink names we found */ - while ((k = set_steal_first(names))) { - - /* First try to merge in the other name into our - * unit */ - if ((r = unit_merge_by_name(*u, k)) < 0) { - Unit *other; - - /* Hmm, we couldn't merge the other unit into - * ours? Then let's try it the other way - * round */ - - other = manager_get_unit((*u)->meta.manager, k); - free(k); - - if (other) - if ((r = unit_merge(other, *u)) >= 0) { - *u = other; - return merge_by_names(u, names, NULL); - } - - return r; - } - - if (id == k) - unit_choose_id(*u, id); - - free(k); - } - - return 0; -} - -static int load_from_path(Unit *u, const char *path) { - int r; - Set *symlink_names; - FILE *f = NULL; - char *filename = NULL, *id = NULL; - Unit *merged; - struct stat st; - - assert(u); - assert(path); - - symlink_names = set_new(string_hash_func, string_compare_func); - if (!symlink_names) - return -ENOMEM; - - if (path_is_absolute(path)) { - - if (!(filename = strdup(path))) { - r = -ENOMEM; - goto finish; - } - - if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) { - free(filename); - filename = NULL; - - if (r != -ENOENT) - goto finish; - } - - } else { - char **p; - - STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) { - - /* Instead of opening the path right away, we manually - * follow all symlinks and add their name to our unit - * name set while doing so */ - if (!(filename = path_make_absolute(path, *p))) { - r = -ENOMEM; - goto finish; - } - - if (u->meta.manager->unit_path_cache && - !set_get(u->meta.manager->unit_path_cache, filename)) - r = -ENOENT; - else - r = open_follow(&filename, &f, symlink_names, &id); - - if (r < 0) { - char *sn; - - free(filename); - filename = NULL; - - if (r != -ENOENT) - goto finish; - - /* Empty the symlink names for the next run */ - while ((sn = set_steal_first(symlink_names))) - free(sn); - - continue; - } - - break; - } - } - - if (!filename) { - /* Hmm, no suitable file found? */ - r = 0; - goto finish; - } - - merged = u; - if ((r = merge_by_names(&merged, symlink_names, id)) < 0) - goto finish; - - if (merged != u) { - u->meta.load_state = UNIT_MERGED; - r = 0; - goto finish; - } - - zero(st); - if (fstat(fileno(f), &st) < 0) { - r = -errno; - goto finish; - } - - if (null_or_empty(&st)) - u->meta.load_state = UNIT_MASKED; - else { - /* Now, parse the file contents */ - r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u); - if (r < 0) - goto finish; - - u->meta.load_state = UNIT_LOADED; - } - - free(u->meta.fragment_path); - u->meta.fragment_path = filename; - filename = NULL; - - u->meta.fragment_mtime = timespec_load(&st.st_mtim); - - r = 0; - -finish: - set_free_free(symlink_names); - free(filename); - - if (f) - fclose(f); - - return r; -} - -int unit_load_fragment(Unit *u) { - int r; - Iterator i; - const char *t; - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - assert(u->meta.id); - - /* First, try to find the unit under its id. We always look - * for unit files in the default directories, to make it easy - * to override things by placing things in /etc/systemd/system */ - if ((r = load_from_path(u, u->meta.id)) < 0) - return r; - - /* Try to find an alias we can load this with */ - if (u->meta.load_state == UNIT_STUB) - SET_FOREACH(t, u->meta.names, i) { - - if (t == u->meta.id) - continue; - - if ((r = load_from_path(u, t)) < 0) - return r; - - if (u->meta.load_state != UNIT_STUB) - break; - } - - /* And now, try looking for it under the suggested (originally linked) path */ - if (u->meta.load_state == UNIT_STUB && u->meta.fragment_path) { - - if ((r = load_from_path(u, u->meta.fragment_path)) < 0) - return r; - - if (u->meta.load_state == UNIT_STUB) { - /* Hmm, this didn't work? Then let's get rid - * of the fragment path stored for us, so that - * we don't point to an invalid location. */ - free(u->meta.fragment_path); - u->meta.fragment_path = NULL; - } - } - - /* Look for a template */ - if (u->meta.load_state == UNIT_STUB && u->meta.instance) { - char *k; - - if (!(k = unit_name_template(u->meta.id))) - return -ENOMEM; - - r = load_from_path(u, k); - free(k); - - if (r < 0) - return r; - - if (u->meta.load_state == UNIT_STUB) - SET_FOREACH(t, u->meta.names, i) { - - if (t == u->meta.id) - continue; - - if (!(k = unit_name_template(t))) - return -ENOMEM; - - r = load_from_path(u, k); - free(k); - - if (r < 0) - return r; - - if (u->meta.load_state != UNIT_STUB) - break; - } - } - - return 0; -} - -void unit_dump_config_items(FILE *f) { - static const struct { - const ConfigParserCallback callback; - const char *rvalue; - } table[] = { - { config_parse_int, "INTEGER" }, - { config_parse_unsigned, "UNSIGNED" }, - { config_parse_size, "SIZE" }, - { config_parse_bool, "BOOLEAN" }, - { config_parse_string, "STRING" }, - { config_parse_path, "PATH" }, - { config_parse_unit_path_printf, "PATH" }, - { config_parse_strv, "STRING [...]" }, - { config_parse_exec_nice, "NICE" }, - { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" }, - { config_parse_exec_io_class, "IOCLASS" }, - { config_parse_exec_io_priority, "IOPRIORITY" }, - { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" }, - { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" }, - { config_parse_exec_cpu_affinity, "CPUAFFINITY" }, - { config_parse_mode, "MODE" }, - { config_parse_unit_env_file, "FILE" }, - { config_parse_output, "OUTPUT" }, - { config_parse_input, "INPUT" }, - { config_parse_facility, "FACILITY" }, - { config_parse_level, "LEVEL" }, - { config_parse_exec_capabilities, "CAPABILITIES" }, - { config_parse_exec_secure_bits, "SECUREBITS" }, - { config_parse_exec_bounding_set, "BOUNDINGSET" }, - { config_parse_exec_timer_slack_nsec, "TIMERSLACK" }, - { config_parse_limit, "LIMIT" }, - { config_parse_unit_cgroup, "CGROUP [...]" }, - { config_parse_unit_deps, "UNIT [...]" }, - { config_parse_unit_names, "UNIT [...]" }, - { config_parse_exec, "PATH [ARGUMENT [...]]" }, - { config_parse_service_type, "SERVICETYPE" }, - { config_parse_service_restart, "SERVICERESTART" }, -#ifdef HAVE_SYSV_COMPAT - { config_parse_sysv_priority, "SYSVPRIORITY" }, -#else - { config_parse_warn_compat, "NOTSUPPORTED" }, -#endif - { config_parse_kill_mode, "KILLMODE" }, - { config_parse_kill_signal, "SIGNAL" }, - { config_parse_socket_listen, "SOCKET [...]" }, - { config_parse_socket_bind, "SOCKETBIND" }, - { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, - { config_parse_usec, "SECONDS" }, - { config_parse_path_strv, "PATH [...]" }, - { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, - { config_parse_unit_string_printf, "STRING" }, - { config_parse_timer, "TIMER" }, - { config_parse_timer_unit, "NAME" }, - { config_parse_path_spec, "PATH" }, - { config_parse_path_unit, "UNIT" }, - { config_parse_notify_access, "ACCESS" }, - { config_parse_ip_tos, "TOS" }, - { config_parse_unit_condition_path, "CONDITION" }, - { config_parse_unit_condition_string, "CONDITION" }, - { config_parse_unit_condition_null, "CONDITION" }, - }; - - const char *prev = NULL; - const char *i; - - assert(f); - - NULSTR_FOREACH(i, load_fragment_gperf_nulstr) { - const char *rvalue = "OTHER", *lvalue; - unsigned j; - size_t prefix_len; - const char *dot; - const ConfigPerfItem *p; - - assert_se(p = load_fragment_gperf_lookup(i, strlen(i))); - - dot = strchr(i, '.'); - lvalue = dot ? dot + 1 : i; - prefix_len = dot-i; - - if (dot) - if (!prev || strncmp(prev, i, prefix_len+1) != 0) { - if (prev) - fputc('\n', f); - - fprintf(f, "[%.*s]\n", (int) prefix_len, i); - } - - for (j = 0; j < ELEMENTSOF(table); j++) - if (p->parse == table[j].callback) { - rvalue = table[j].rvalue; - break; - } - - fprintf(f, "%s=%s\n", lvalue, rvalue); - prev = i; - } -} diff --git a/src/load-fragment.h b/src/load-fragment.h deleted file mode 100644 index fbb31f9..0000000 --- a/src/load-fragment.h +++ /dev/null @@ -1,90 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooloadfragmenthfoo -#define fooloadfragmenthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "unit.h" - -/* Read service data from .desktop file style configuration fragments */ - -int unit_load_fragment(Unit *u); - -void unit_dump_config_items(FILE *f); - -int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_names(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_output(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_input(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_io_class(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_io_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_cpu_sched_policy(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_fsck_passno(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_kill_signal(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_exec_mount_flags(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_timer(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_timer_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path_spec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* gperf prototypes */ -const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); -extern const char load_fragment_gperf_nulstr[]; - -#endif diff --git a/src/locale-setup.c b/src/locale-setup.c deleted file mode 100644 index 87ee022..0000000 --- a/src/locale-setup.c +++ /dev/null @@ -1,251 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "locale-setup.h" -#include "util.h" -#include "macro.h" -#include "virt.h" - -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - - VARIABLE_LANG, - VARIABLE_LANGUAGE, - VARIABLE_LC_CTYPE, - VARIABLE_LC_NUMERIC, - VARIABLE_LC_TIME, - VARIABLE_LC_COLLATE, - VARIABLE_LC_MONETARY, - VARIABLE_LC_MESSAGES, - VARIABLE_LC_PAPER, - VARIABLE_LC_NAME, - VARIABLE_LC_ADDRESS, - VARIABLE_LC_TELEPHONE, - VARIABLE_LC_MEASUREMENT, - VARIABLE_LC_IDENTIFICATION, - _VARIABLE_MAX -}; - -static const char * const variable_names[_VARIABLE_MAX] = { - [VARIABLE_LANG] = "LANG", - [VARIABLE_LANGUAGE] = "LANGUAGE", - [VARIABLE_LC_CTYPE] = "LC_CTYPE", - [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", - [VARIABLE_LC_TIME] = "LC_TIME", - [VARIABLE_LC_COLLATE] = "LC_COLLATE", - [VARIABLE_LC_MONETARY] = "LC_MONETARY", - [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", - [VARIABLE_LC_PAPER] = "LC_PAPER", - [VARIABLE_LC_NAME] = "LC_NAME", - [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", - [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", - [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", - [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; - -int locale_setup(void) { - char *variables[_VARIABLE_MAX]; - int r = 0, i; - - zero(variables); - - if (detect_container(NULL) <= 0) - if ((r = parse_env_file("/proc/cmdline", WHITESPACE, -#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO) - "LANG", &variables[VARIABLE_LANG], -#endif - "locale.LANG", &variables[VARIABLE_LANG], - "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE], - "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "locale.LC_TIME", &variables[VARIABLE_LC_TIME], - "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER], - "locale.LC_NAME", &variables[VARIABLE_LC_NAME], - "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); - } - - /* Hmm, nothing set on the kernel cmd line? Then let's - * try /etc/locale.conf */ - if (r <= 0 && - (r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LANGUAGE", &variables[VARIABLE_LANGUAGE], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/locale.conf: %s", strerror(-r)); - } - -#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MEEGO) - if (r <= 0 && - (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - -#elif defined(TARGET_SUSE) - if (r <= 0 && - (r = parse_env_file("/etc/sysconfig/language", NEWLINE, - "RC_LANG", &variables[VARIABLE_LANG], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r)); - } - -#elif defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) || defined(TARGET_SLP) - if (r <= 0 && - (r = parse_env_file("/etc/default/locale", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/default/locale: %s", strerror(-r)); - } - -#elif defined(TARGET_ARCH) - if (r <= 0 && - (r = parse_env_file("/etc/rc.conf", NEWLINE, - "LOCALE", &variables[VARIABLE_LANG], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/rc.conf: %s", strerror(-r)); - } - -#elif defined(TARGET_GENTOO) - /* Gentoo's openrc expects locale variables in /etc/env.d/ - * These files are later compiled by env-update into shell - * export commands at /etc/profile.env, with variables being - * exported by openrc's runscript (so /etc/init.d/) - */ - if (r <= 0 && - (r = parse_env_file("/etc/profile.env", NEWLINE, - "export LANG", &variables[VARIABLE_LANG], - "export LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "export LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "export LC_TIME", &variables[VARIABLE_LC_TIME], - "export LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "export LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "export LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "export LC_PAPER", &variables[VARIABLE_LC_PAPER], - "export LC_NAME", &variables[VARIABLE_LC_NAME], - "export LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "export LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "export LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/profile.env: %s", strerror(-r)); - } -#elif defined(TARGET_MANDRIVA) - if (r <= 0 && - (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "LANG", &variables[VARIABLE_LANG], - "LC_CTYPE", &variables[VARIABLE_LC_CTYPE], - "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC], - "LC_TIME", &variables[VARIABLE_LC_TIME], - "LC_COLLATE", &variables[VARIABLE_LC_COLLATE], - "LC_MONETARY", &variables[VARIABLE_LC_MONETARY], - "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES], - "LC_PAPER", &variables[VARIABLE_LC_PAPER], - "LC_NAME", &variables[VARIABLE_LC_NAME], - "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS], - "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE], - "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT], - "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION], - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - -#endif - - if (!variables[VARIABLE_LANG]) { - if (!(variables[VARIABLE_LANG] = strdup("C"))) { - r = -ENOMEM; - goto finish; - } - } - - for (i = 0; i < _VARIABLE_MAX; i++) { - - if (variables[i]) { - if (setenv(variable_names[i], variables[i], 1) < 0) { - r = -errno; - goto finish; - } - } else - unsetenv(variable_names[i]); - } - - r = 0; - -finish: - for (i = 0; i < _VARIABLE_MAX; i++) - free(variables[i]); - - return r; -} diff --git a/src/locale-setup.h b/src/locale-setup.h deleted file mode 100644 index 09a6bc6..0000000 --- a/src/locale-setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foolocalesetuphfoo -#define foolocalesetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int locale_setup(void); - -#endif diff --git a/src/locale/.gitignore b/src/locale/.gitignore new file mode 100644 index 0000000..b1e0ba7 --- /dev/null +++ b/src/locale/.gitignore @@ -0,0 +1 @@ +org.freedesktop.locale1.policy diff --git a/src/locale/Makefile b/src/locale/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/locale/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/locale/generate-kbd-model-map b/src/locale/generate-kbd-model-map new file mode 100755 index 0000000..b8ffa0f --- /dev/null +++ b/src/locale/generate-kbd-model-map @@ -0,0 +1,31 @@ +import sys +import system_config_keyboard.keyboard_models + +def strdash(s): + return s.strip() or '-' + +def tab_extend(s, n=1): + s = strdash(s) + k = len(s) // 8 + + if k >= n: + f = 1 + else: + f = n - k + + return s + '\t'*f + + +models = system_config_keyboard.keyboard_models.KeyboardModels().get_models() + +print "# Generated from system-config-keyboard's model list" +print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions" + +for key, value in reversed(models.items()): + options = "terminate:ctrl_alt_bksp" + if value[4]: + options += ',' + value[4] + + print ''.join((tab_extend(key, 3), tab_extend(value[1]), + tab_extend(value[2], 2), tab_extend(value[3], 2), + options)) diff --git a/src/locale/kbd-model-map b/src/locale/kbd-model-map new file mode 100644 index 0000000..322c0a9 --- /dev/null +++ b/src/locale/kbd-model-map @@ -0,0 +1,65 @@ +# Generated from system-config-keyboard's model list +# consolelayout xlayout xmodel xvariant xoptions +sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp +nl nl pc105 - terminate:ctrl_alt_bksp +mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +trq tr pc105 - terminate:ctrl_alt_bksp +uk gb pc105 - terminate:ctrl_alt_bksp +is-latin1 is pc105 - terminate:ctrl_alt_bksp +de de pc105 - terminate:ctrl_alt_bksp +la-latin1 latam pc105 - terminate:ctrl_alt_bksp +us us pc105+inet - terminate:ctrl_alt_bksp +ko kr pc105 - terminate:ctrl_alt_bksp +ro-std ro pc105 std terminate:ctrl_alt_bksp +de-latin1 de pc105 - terminate:ctrl_alt_bksp +slovene si pc105 - terminate:ctrl_alt_bksp +hu101 hu pc105 qwerty terminate:ctrl_alt_bksp +jp106 jp jp106 - terminate:ctrl_alt_bksp +croat hr pc105 - terminate:ctrl_alt_bksp +fi-latin1 fi pc105 - terminate:ctrl_alt_bksp +it2 it pc105 - terminate:ctrl_alt_bksp +hu hu pc105 - terminate:ctrl_alt_bksp +sr-latin rs pc105 latin terminate:ctrl_alt_bksp +fi fi pc105 - terminate:ctrl_alt_bksp +fr_CH ch pc105 fr terminate:ctrl_alt_bksp +dk-latin1 dk pc105 - terminate:ctrl_alt_bksp +fr fr pc105 - terminate:ctrl_alt_bksp +it it pc105 - terminate:ctrl_alt_bksp +ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +fr-latin1 fr pc105 - terminate:ctrl_alt_bksp +sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp +be-latin1 be pc105 - terminate:ctrl_alt_bksp +dk dk pc105 - terminate:ctrl_alt_bksp +fr-pc fr pc105 - terminate:ctrl_alt_bksp +bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +it-ibm it pc105 - terminate:ctrl_alt_bksp +cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +br-abnt2 br abnt2 - terminate:ctrl_alt_bksp +ro ro pc105 - terminate:ctrl_alt_bksp +us-acentos us pc105 intl terminate:ctrl_alt_bksp +pt-latin1 pt pc105 - terminate:ctrl_alt_bksp +ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp +tj_alt-UTF8 tj pc105 - terminate:ctrl_alt_bksp +de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp +no no pc105 - terminate:ctrl_alt_bksp +bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +dvorak us pc105 dvorak terminate:ctrl_alt_bksp +dvorak us pc105 dvorak-alt-intl terminate:ctrl_alt_bksp +ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp +pl2 pl pc105 - terminate:ctrl_alt_bksp +es es pc105 - terminate:ctrl_alt_bksp +ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp +ie ie pc105 - terminate:ctrl_alt_bksp +et ee pc105 - terminate:ctrl_alt_bksp +sk-qwerty sk pc105 - terminate:ctrl_alt_bksp,qwerty +fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp +fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp +cf ca pc105 - terminate:ctrl_alt_bksp +sv-latin1 se pc105 - terminate:ctrl_alt_bksp +sr-cy rs pc105 - terminate:ctrl_alt_bksp +gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +by by,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +il il pc105 - terminate:ctrl_alt_bksp +kazakh kz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll +lt lt pc105 - terminate:ctrl_alt_bksp diff --git a/src/locale/localectl.c b/src/locale/localectl.c new file mode 100644 index 0000000..2632305 --- /dev/null +++ b/src/locale/localectl.c @@ -0,0 +1,822 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-message.h" +#include "util.h" +#include "spawn-polkit-agent.h" +#include "build.h" +#include "strv.h" +#include "pager.h" +#include "set.h" +#include "path-util.h" +#include "utf8.h" +#include "def.h" + +static bool arg_no_pager = false; +static bool arg_ask_password = true; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_convert = true; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static void polkit_agent_open_if_enabled(void) { + + /* Open the polkit agent as a child process if necessary */ + if (!arg_ask_password) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + polkit_agent_open(); +} + +typedef struct StatusInfo { + char **locale; + const char *vconsole_keymap; + const char *vconsole_keymap_toggle; + const char *x11_layout; + const char *x11_model; + const char *x11_variant; + const char *x11_options; +} StatusInfo; + +static void print_status_info(StatusInfo *i) { + assert(i); + + if (strv_isempty(i->locale)) + puts(" System Locale: n/a\n"); + else { + char **j; + + printf(" System Locale: %s\n", i->locale[0]); + STRV_FOREACH(j, i->locale + 1) + printf(" %s\n", *j); + } + + printf(" VC Keymap: %s\n", strna(i->vconsole_keymap)); + if (!isempty(i->vconsole_keymap_toggle)) + printf("VC Toggle Keymap: %s\n", i->vconsole_keymap_toggle); + + printf(" X11 Layout: %s\n", strna(i->x11_layout)); + if (!isempty(i->x11_model)) + printf(" X11 Model: %s\n", i->x11_model); + if (!isempty(i->x11_variant)) + printf(" X11 Variant: %s\n", i->x11_variant); + if (!isempty(i->x11_options)) + printf(" X11 Options: %s\n", i->x11_options); +} + +static int show_status(sd_bus *bus, char **args, unsigned n) { + StatusInfo info = {}; + static const struct bus_properties_map map[] = { + { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) }, + { "VConsoleKeymap", "s", NULL, offsetof(StatusInfo, vconsole_keymap) }, + { "VConsoleKeymapToggle", "s", NULL, offsetof(StatusInfo, vconsole_keymap_toggle) }, + { "X11Layout", "s", NULL, offsetof(StatusInfo, x11_layout) }, + { "X11Model", "s", NULL, offsetof(StatusInfo, x11_model) }, + { "X11Variant", "s", NULL, offsetof(StatusInfo, x11_variant) }, + { "X11Options", "s", NULL, offsetof(StatusInfo, x11_options) }, + { "Locale", "as", NULL, offsetof(StatusInfo, locale) }, + {} + }; + int r; + + assert(bus); + + r = bus_map_all_properties(bus, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + map, + &info); + if (r < 0) { + log_error("Could not get properties: %s", strerror(-r)); + goto fail; + } + + print_status_info(&info); + +fail: + strv_free(info.locale); + return r; +} + +static int set_locale(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(args); + + polkit_agent_open_if_enabled(); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "SetLocale"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, args + 1); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "b", arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + return r; + } + + return 0; +} + +static int add_locales_from_archive(Set *locales) { + /* Stolen from glibc... */ + + struct locarhead { + uint32_t magic; + /* Serial number. */ + uint32_t serial; + /* Name hash table. */ + uint32_t namehash_offset; + uint32_t namehash_used; + uint32_t namehash_size; + /* String table. */ + uint32_t string_offset; + uint32_t string_used; + uint32_t string_size; + /* Table with locale records. */ + uint32_t locrectab_offset; + uint32_t locrectab_used; + uint32_t locrectab_size; + /* MD5 sum hash table. */ + uint32_t sumhash_offset; + uint32_t sumhash_used; + uint32_t sumhash_size; + }; + + struct namehashent { + /* Hash value of the name. */ + uint32_t hashval; + /* Offset of the name in the string table. */ + uint32_t name_offset; + /* Offset of the locale record. */ + uint32_t locrec_offset; + }; + + const struct locarhead *h; + const struct namehashent *e; + const void *p = MAP_FAILED; + _cleanup_close_ int fd = -1; + size_t sz = 0; + struct stat st; + unsigned i; + int r; + + fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) { + if (errno != ENOENT) + log_error("Failed to open locale archive: %m"); + r = -errno; + goto finish; + } + + if (fstat(fd, &st) < 0) { + log_error("fstat() failed: %m"); + r = -errno; + goto finish; + } + + if (!S_ISREG(st.st_mode)) { + log_error("Archive file is not regular"); + r = -EBADMSG; + goto finish; + } + + if (st.st_size < (off_t) sizeof(struct locarhead)) { + log_error("Archive has invalid size"); + r = -EBADMSG; + goto finish; + } + + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) { + log_error("Failed to map archive: %m"); + r = -errno; + goto finish; + } + + h = (const struct locarhead *) p; + if (h->magic != 0xde020109 || + h->namehash_offset + h->namehash_size > st.st_size || + h->string_offset + h->string_size > st.st_size || + h->locrectab_offset + h->locrectab_size > st.st_size || + h->sumhash_offset + h->sumhash_size > st.st_size) { + log_error("Invalid archive file."); + r = -EBADMSG; + goto finish; + } + + e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset); + for (i = 0; i < h->namehash_size; i++) { + char *z; + + if (e[i].locrec_offset == 0) + continue; + + if (!utf8_is_valid((char*) p + e[i].name_offset)) + continue; + + z = strdup((char*) p + e[i].name_offset); + if (!z) { + r = log_oom(); + goto finish; + } + + r = set_consume(locales, z); + if (r < 0) { + log_error("Failed to add locale: %s", strerror(-r)); + goto finish; + } + } + + r = 0; + + finish: + if (p != MAP_FAILED) + munmap((void*) p, sz); + + return r; +} + +static int add_locales_from_libdir (Set *locales) { + _cleanup_closedir_ DIR *dir; + struct dirent *entry; + int r; + + dir = opendir("/usr/lib/locale"); + if (!dir) { + log_error("Failed to open locale directory: %m"); + return -errno; + } + + errno = 0; + while ((entry = readdir(dir))) { + char *z; + + if (entry->d_type != DT_DIR) + continue; + + if (ignore_file(entry->d_name)) + continue; + + z = strdup(entry->d_name); + if (!z) + return log_oom(); + + r = set_consume(locales, z); + if (r < 0 && r != -EEXIST) { + log_error("Failed to add locale: %s", strerror(-r)); + return r; + } + + errno = 0; + } + + if (errno > 0) { + log_error("Failed to read locale directory: %m"); + return -errno; + } + + return 0; +} + +static int list_locales(sd_bus *bus, char **args, unsigned n) { + _cleanup_set_free_ Set *locales; + _cleanup_strv_free_ char **l = NULL; + int r; + + locales = set_new(string_hash_func, string_compare_func); + if (!locales) + return log_oom(); + + r = add_locales_from_archive(locales); + if (r < 0 && r != -ENOENT) + return r; + + r = add_locales_from_libdir(locales); + if (r < 0) + return r; + + l = set_get_strv(locales); + if (!l) + return log_oom(); + + strv_sort(l); + + pager_open_if_enabled(); + + strv_print(l); + + return 0; +} + +static int set_vconsole_keymap(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *map, *toggle_map; + int r; + + assert(bus); + assert(args); + + if (n > 3) { + log_error("Too many arguments."); + return -EINVAL; + } + + polkit_agent_open_if_enabled(); + + map = args[1]; + toggle_map = n > 2 ? args[2] : ""; + + r = sd_bus_call_method( + bus, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "SetVConsoleKeyboard", + &error, + NULL, + "ssbb", map, toggle_map, arg_convert, arg_ask_password); + if (r < 0) + log_error("Failed to set keymap: %s", bus_error_message(&error, -r)); + + return r; +} + +static 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 log_oom(); + + 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) { + log_error("Can't add keymap: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { + _cleanup_strv_free_ char **l = NULL; + const char *dir; + + keymaps = set_new(string_hash_func, string_compare_func); + if (!keymaps) + return log_oom(); + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) + nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS); + + l = set_get_strv(keymaps); + if (!l) { + set_free_free(keymaps); + return log_oom(); + } + + set_free(keymaps); + + if (strv_isempty(l)) { + log_error("Couldn't find any console keymaps."); + return -ENOENT; + } + + strv_sort(l); + + pager_open_if_enabled(); + + strv_print(l); + + return 0; +} + +static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *layout, *model, *variant, *options; + int r; + + assert(bus); + assert(args); + + if (n > 5) { + log_error("Too many arguments."); + return -EINVAL; + } + + polkit_agent_open_if_enabled(); + + layout = args[1]; + model = n > 2 ? args[2] : ""; + variant = n > 3 ? args[3] : ""; + options = n > 4 ? args[4] : ""; + + r = sd_bus_call_method( + bus, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "SetX11Keyboard", + &error, + NULL, + "ssssbb", layout, model, variant, options, + arg_convert, arg_ask_password); + if (r < 0) + log_error("Failed to set keymap: %s", bus_error_message(&error, -r)); + + return r; +} + +static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **list = NULL; + char line[LINE_MAX]; + enum { + NONE, + MODELS, + LAYOUTS, + VARIANTS, + OPTIONS + } state = NONE, look_for; + int r; + + if (n > 2) { + log_error("Too many arguments."); + return -EINVAL; + } + + f = fopen("/usr/share/X11/xkb/rules/base.lst", "re"); + if (!f) { + log_error("Failed to open keyboard mapping list. %m"); + return -errno; + } + + if (streq(args[0], "list-x11-keymap-models")) + look_for = MODELS; + else if (streq(args[0], "list-x11-keymap-layouts")) + look_for = LAYOUTS; + else if (streq(args[0], "list-x11-keymap-variants")) + look_for = VARIANTS; + else if (streq(args[0], "list-x11-keymap-options")) + look_for = OPTIONS; + else + assert_not_reached("Wrong parameter"); + + FOREACH_LINE(line, f, break) { + char *l, *w; + + l = strstrip(line); + + if (isempty(l)) + continue; + + if (l[0] == '!') { + if (startswith(l, "! model")) + state = MODELS; + else if (startswith(l, "! layout")) + state = LAYOUTS; + else if (startswith(l, "! variant")) + state = VARIANTS; + else if (startswith(l, "! option")) + state = OPTIONS; + else + state = NONE; + + continue; + } + + if (state != look_for) + continue; + + w = l + strcspn(l, WHITESPACE); + + if (n > 1) { + char *e; + + if (*w == 0) + continue; + + *w = 0; + w++; + w += strspn(w, WHITESPACE); + + e = strchr(w, ':'); + if (!e) + continue; + + *e = 0; + + if (!streq(w, args[1])) + continue; + } else + *w = 0; + + r = strv_extend(&list, l); + if (r < 0) + return log_oom(); + } + + if (strv_isempty(list)) { + log_error("Couldn't find any entries."); + return -ENOENT; + } + + strv_sort(list); + strv_uniq(list); + + pager_open_if_enabled(); + + strv_print(list); + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] COMMAND ...\n\n" + "Query or change system locale and keyboard settings.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-ask-password Do not prompt for password\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --no-convert Don't convert keyboard mappings\n\n" + "Commands:\n" + " status Show current locale settings\n" + " set-locale LOCALE... Set system locale\n" + " list-locales Show known locales\n" + " set-keymap MAP [MAP] Set virtual console keyboard mapping\n" + " list-keymaps Show known virtual console keyboard mappings\n" + " set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS]\n" + " Set X11 keyboard mapping\n" + " list-x11-keymap-models Show known X11 keyboard mapping models\n" + " list-x11-keymap-layouts Show known X11 keyboard mapping layouts\n" + " list-x11-keymap-variants [LAYOUT]\n" + " Show known X11 keyboard mapping variants\n" + " list-x11-keymap-options Show known X11 keyboard mapping options\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_CONVERT, + ARG_NO_ASK_PASSWORD + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "no-convert", no_argument, NULL, ARG_NO_CONVERT }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_NO_CONVERT: + arg_convert = false; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int localectl_main(sd_bus *bus, int argc, char *argv[]) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args, unsigned n); + } verbs[] = { + { "status", LESS, 1, show_status }, + { "set-locale", MORE, 2, set_locale }, + { "list-locales", EQUAL, 1, list_locales }, + { "set-keymap", MORE, 2, set_vconsole_keymap }, + { "list-keymaps", EQUAL, 1, list_vconsole_keymaps }, + { "set-x11-keymap", MORE, 2, set_x11_keymap }, + { "list-x11-keymap-models", EQUAL, 1, list_x11_keymaps }, + { "list-x11-keymap-layouts", EQUAL, 1, list_x11_keymaps }, + { "list-x11-keymap-variants", LESS, 2, list_x11_keymaps }, + { "list-x11-keymap-options", EQUAL, 1, list_x11_keymaps }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "status" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(bus, argv + optind, left); +} + +int main(int argc, char*argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, false, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + r = localectl_main(bus, argc, argv); + +finish: + pager_close(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/locale/localed.c b/src/locale/localed.c new file mode 100644 index 0000000..de6e3b2 --- /dev/null +++ b/src/locale/localed.c @@ -0,0 +1,1162 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-bus.h" + +#include "util.h" +#include "mkdir.h" +#include "strv.h" +#include "def.h" +#include "env-util.h" +#include "fileio.h" +#include "fileio-label.h" +#include "label.h" +#include "bus-util.h" +#include "bus-error.h" +#include "bus-message.h" +#include "event-util.h" + +enum { + /* We don't list LC_ALL here on purpose. People should be + * using LANG instead. */ + LOCALE_LANG, + LOCALE_LANGUAGE, + LOCALE_LC_CTYPE, + LOCALE_LC_NUMERIC, + LOCALE_LC_TIME, + LOCALE_LC_COLLATE, + LOCALE_LC_MONETARY, + LOCALE_LC_MESSAGES, + LOCALE_LC_PAPER, + LOCALE_LC_NAME, + LOCALE_LC_ADDRESS, + LOCALE_LC_TELEPHONE, + LOCALE_LC_MEASUREMENT, + LOCALE_LC_IDENTIFICATION, + _LOCALE_MAX +}; + +static const char * const names[_LOCALE_MAX] = { + [LOCALE_LANG] = "LANG", + [LOCALE_LANGUAGE] = "LANGUAGE", + [LOCALE_LC_CTYPE] = "LC_CTYPE", + [LOCALE_LC_NUMERIC] = "LC_NUMERIC", + [LOCALE_LC_TIME] = "LC_TIME", + [LOCALE_LC_COLLATE] = "LC_COLLATE", + [LOCALE_LC_MONETARY] = "LC_MONETARY", + [LOCALE_LC_MESSAGES] = "LC_MESSAGES", + [LOCALE_LC_PAPER] = "LC_PAPER", + [LOCALE_LC_NAME] = "LC_NAME", + [LOCALE_LC_ADDRESS] = "LC_ADDRESS", + [LOCALE_LC_TELEPHONE] = "LC_TELEPHONE", + [LOCALE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [LOCALE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +}; + +typedef struct Context { + char *locale[_LOCALE_MAX]; + + char *x11_layout; + char *x11_model; + char *x11_variant; + char *x11_options; + + char *vc_keymap; + char *vc_keymap_toggle; + + Hashmap *polkit_registry; +} Context; + +static int free_and_copy(char **s, const char *v) { + int r; + char *t; + + assert(s); + + r = strdup_or_null(isempty(v) ? NULL : v, &t); + if (r < 0) + return r; + + free(*s); + *s = t; + + return 0; +} + +static void free_and_replace(char **s, char *v) { + free(*s); + *s = v; +} + +static void context_free_x11(Context *c) { + free_and_replace(&c->x11_layout, NULL); + free_and_replace(&c->x11_model, NULL); + free_and_replace(&c->x11_variant, NULL); + free_and_replace(&c->x11_options, NULL); +} + +static void context_free_vconsole(Context *c) { + free_and_replace(&c->vc_keymap, NULL); + free_and_replace(&c->vc_keymap_toggle, NULL); +} + +static void context_free_locale(Context *c) { + int p; + + for (p = 0; p < _LOCALE_MAX; p++) + free_and_replace(&c->locale[p], NULL); +} + +static void context_free(Context *c, sd_bus *bus) { + context_free_locale(c); + context_free_x11(c); + context_free_vconsole(c); + + bus_verify_polkit_async_registry_free(bus, c->polkit_registry); +}; + +static void locale_simplify(Context *c) { + int p; + + for (p = LOCALE_LANG+1; p < _LOCALE_MAX; p++) + if (isempty(c->locale[p]) || streq_ptr(c->locale[LOCALE_LANG], c->locale[p])) { + free(c->locale[p]); + c->locale[p] = NULL; + } +} + +static int locale_read_data(Context *c) { + int r; + + context_free_locale(c); + + r = parse_env_file("/etc/locale.conf", NEWLINE, + "LANG", &c->locale[LOCALE_LANG], + "LANGUAGE", &c->locale[LOCALE_LANGUAGE], + "LC_CTYPE", &c->locale[LOCALE_LC_CTYPE], + "LC_NUMERIC", &c->locale[LOCALE_LC_NUMERIC], + "LC_TIME", &c->locale[LOCALE_LC_TIME], + "LC_COLLATE", &c->locale[LOCALE_LC_COLLATE], + "LC_MONETARY", &c->locale[LOCALE_LC_MONETARY], + "LC_MESSAGES", &c->locale[LOCALE_LC_MESSAGES], + "LC_PAPER", &c->locale[LOCALE_LC_PAPER], + "LC_NAME", &c->locale[LOCALE_LC_NAME], + "LC_ADDRESS", &c->locale[LOCALE_LC_ADDRESS], + "LC_TELEPHONE", &c->locale[LOCALE_LC_TELEPHONE], + "LC_MEASUREMENT", &c->locale[LOCALE_LC_MEASUREMENT], + "LC_IDENTIFICATION", &c->locale[LOCALE_LC_IDENTIFICATION], + NULL); + + if (r == -ENOENT) { + int p; + + /* Fill in what we got passed from systemd. */ + for (p = 0; p < _LOCALE_MAX; p++) { + assert(names[p]); + + r = free_and_copy(&c->locale[p], getenv(names[p])); + if (r < 0) + return r; + } + + r = 0; + } + + locale_simplify(c); + return r; +} + +static int vconsole_read_data(Context *c) { + int r; + + context_free_vconsole(c); + + r = parse_env_file("/etc/vconsole.conf", NEWLINE, + "KEYMAP", &c->vc_keymap, + "KEYMAP_TOGGLE", &c->vc_keymap_toggle, + NULL); + + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static int x11_read_data(Context *c) { + FILE *f; + char line[LINE_MAX]; + bool in_section = false; + + context_free_x11(c); + + f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); + if (!f) + return errno == ENOENT ? 0 : -errno; + + while (fgets(line, sizeof(line), f)) { + char *l; + + char_array_0(line); + l = strstrip(line); + + if (l[0] == 0 || l[0] == '#') + continue; + + if (in_section && first_word(l, "Option")) { + char **a; + + a = strv_split_quoted(l); + if (!a) { + fclose(f); + return -ENOMEM; + } + + if (strv_length(a) == 3) { + if (streq(a[1], "XkbLayout")) { + free_and_replace(&c->x11_layout, a[2]); + a[2] = NULL; + } else if (streq(a[1], "XkbModel")) { + free_and_replace(&c->x11_model, a[2]); + a[2] = NULL; + } else if (streq(a[1], "XkbVariant")) { + free_and_replace(&c->x11_variant, a[2]); + a[2] = NULL; + } else if (streq(a[1], "XkbOptions")) { + free_and_replace(&c->x11_options, a[2]); + a[2] = NULL; + } + } + + strv_free(a); + + } else if (!in_section && first_word(l, "Section")) { + char **a; + + a = strv_split_quoted(l); + if (!a) { + fclose(f); + return -ENOMEM; + } + + if (strv_length(a) == 2 && streq(a[1], "InputClass")) + in_section = true; + + strv_free(a); + } else if (in_section && first_word(l, "EndSection")) + in_section = false; + } + + fclose(f); + + return 0; +} + +static int context_read_data(Context *c) { + int r, q, p; + + r = locale_read_data(c); + q = vconsole_read_data(c); + p = x11_read_data(c); + + return r < 0 ? r : q < 0 ? q : p; +} + +static int locale_write_data(Context *c) { + int r, p; + char **l = NULL; + + r = load_env_file("/etc/locale.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 0; p < _LOCALE_MAX; p++) { + char *t, **u; + + assert(names[p]); + + if (isempty(c->locale[p])) { + l = strv_env_unset(l, names[p]); + continue; + } + + if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) { + strv_free(l); + return -ENOMEM; + } + + u = strv_env_set(l, t); + free(t); + strv_free(l); + + if (!u) + return -ENOMEM; + + l = u; + } + + if (strv_isempty(l)) { + strv_free(l); + + if (unlink("/etc/locale.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file_label("/etc/locale.conf", l); + strv_free(l); + + return r; +} + +static int locale_update_system_manager(Context *c, sd_bus *bus) { + _cleanup_free_ char **l_unset = NULL; + _cleanup_strv_free_ char **l_set = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned c_set, c_unset, p; + int r; + + assert(bus); + + l_unset = new0(char*, _LOCALE_MAX); + if (!l_unset) + return -ENOMEM; + + l_set = new0(char*, _LOCALE_MAX); + if (!l_set) + return -ENOMEM; + + for (p = 0, c_set = 0, c_unset = 0; p < _LOCALE_MAX; p++) { + assert(names[p]); + + if (isempty(c->locale[p])) + l_unset[c_set++] = (char*) names[p]; + else { + char *s; + + if (asprintf(&s, "%s=%s", names[p], c->locale[p]) < 0) + return -ENOMEM; + + l_set[c_unset++] = s; + } + } + + assert(c_set + c_unset == _LOCALE_MAX); + r = sd_bus_message_new_method_call(bus, &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnsetAndSetEnvironment"); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(m, l_unset); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(m, l_set); + if (r < 0) + return r; + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) + log_error("Failed to update the manager environment: %s", strerror(-r)); + + return 0; +} + +static int vconsole_write_data(Context *c) { + int r; + _cleanup_strv_free_ char **l = NULL; + + r = load_env_file("/etc/vconsole.conf", NULL, &l); + if (r < 0 && r != -ENOENT) + return r; + + if (isempty(c->vc_keymap)) + l = strv_env_unset(l, "KEYMAP"); + else { + char *s, **u; + + s = strappend("KEYMAP=", c->vc_keymap); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + free(s); + strv_free(l); + + if (!u) + return -ENOMEM; + + l = u; + } + + if (isempty(c->vc_keymap_toggle)) + l = strv_env_unset(l, "KEYMAP_TOGGLE"); + else { + char *s, **u; + + s = strappend("KEYMAP_TOGGLE=", c->vc_keymap_toggle); + if (!s) + return -ENOMEM; + + u = strv_env_set(l, s); + free(s); + strv_free(l); + + if (!u) + return -ENOMEM; + + l = u; + } + + if (strv_isempty(l)) { + if (unlink("/etc/vconsole.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file_label("/etc/vconsole.conf", l); + return r; +} + +static int write_data_x11(Context *c) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *temp_path = NULL; + int r; + + if (isempty(c->x11_layout) && + isempty(c->x11_model) && + isempty(c->x11_variant) && + isempty(c->x11_options)) { + + if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + 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; + + fchmod(fileno(f), 0644); + + fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" + "# manually too freely.\n" + "Section \"InputClass\"\n" + " Identifier \"system-keyboard\"\n" + " MatchIsKeyboard \"on\"\n", f); + + if (!isempty(c->x11_layout)) + fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout); + + if (!isempty(c->x11_model)) + fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model); + + if (!isempty(c->x11_variant)) + fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant); + + if (!isempty(c->x11_options)) + fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options); + + fputs("EndSection\n", f); + fflush(f); + + if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { + r = -errno; + unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); + unlink(temp_path); + return r; + } else + return 0; +} + +static int vconsole_reload(sd_bus *bus) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + + r = sd_bus_call_method(bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "RestartUnit", + &error, + NULL, + "ss", "systemd-vconsole-setup.service", "replace"); + + if (r < 0) + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + return r; +} + +static char *strnulldash(const char *s) { + return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s; +} + +static int read_next_mapping(FILE *f, unsigned *n, char ***a) { + assert(f); + assert(n); + assert(a); + + for (;;) { + char line[LINE_MAX]; + char *l, **b; + + errno = 0; + if (!fgets(line, sizeof(line), f)) { + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; + } + + (*n) ++; + + l = strstrip(line); + if (l[0] == 0 || l[0] == '#') + continue; + + b = strv_split_quoted(l); + if (!b) + return -ENOMEM; + + if (strv_length(b) < 5) { + log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n); + strv_free(b); + continue; + + } + + *a = b; + return 1; + } +} + +static int vconsole_convert_to_x11(Context *c, sd_bus *bus) { + bool modified = false; + + assert(bus); + + if (isempty(c->vc_keymap)) { + + modified = + !isempty(c->x11_layout) || + !isempty(c->x11_model) || + !isempty(c->x11_variant) || + !isempty(c->x11_options); + + context_free_x11(c); + } else { + _cleanup_fclose_ FILE *f = NULL; + unsigned n = 0; + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + int r; + + r = read_next_mapping(f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + 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 (free_and_copy(&c->x11_layout, strnulldash(a[1])) < 0 || + free_and_copy(&c->x11_model, strnulldash(a[2])) < 0 || + free_and_copy(&c->x11_variant, strnulldash(a[3])) < 0 || + free_and_copy(&c->x11_options, strnulldash(a[4])) < 0) + return -ENOMEM; + + modified = true; + } + + break; + } + } + + if (modified) { + int r; + + r = write_data_x11(c); + if (r < 0) + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "X11Layout", "X11Model", "X11Variant", "X11Options", NULL); + } + + return 0; +} + +static int find_converted_keymap(Context *c, char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + + if (c->x11_variant) + n = strjoin(c->x11_layout, "-", c->x11_variant, NULL); + else + n = strdup(c->x11_layout); + if (!n) + return -ENOMEM; + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; + + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; + + if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) { + *new_keymap = n; + n = NULL; + return 1; + } + } + + return 0; +} + +static int find_legacy_keymap(Context *c, char **new_keymap) { + _cleanup_fclose_ FILE *f; + unsigned n = 0; + unsigned best_matching = 0; + + + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; + + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; + int r; + + r = read_next_mapping(f, &n, &a); + if (r < 0) + return r; + if (r == 0) + break; + + /* Determine how well matching this entry is */ + if (streq_ptr(c->x11_layout, a[1])) + /* If we got an exact match, this is best */ + matching = 10; + else { + size_t x; + + x = strcspn(c->x11_layout, ","); + + /* We have multiple X layouts, look for an + * entry that matches our key with everything + * but the first layout stripped off. */ + if (x > 0 && + strlen(a[1]) == x && + strneq(c->x11_layout, a[1], x)) + matching = 5; + else { + size_t w; + + /* If that didn't work, strip off the + * other layouts from the entry, too */ + w = strcspn(a[1], ","); + + if (x > 0 && x == w && + memcmp(c->x11_layout, a[1], x) == 0) + matching = 1; + } + } + + if (matching > 0 && + streq_ptr(c->x11_model, a[2])) { + matching++; + + if (streq_ptr(c->x11_variant, a[3])) { + matching++; + + if (streq_ptr(c->x11_options, a[4])) + matching++; + } + } + + /* The best matching entry so far, then let's save that */ + if (matching > best_matching) { + best_matching = matching; + + free(*new_keymap); + *new_keymap = strdup(a[0]); + if (!*new_keymap) + return -ENOMEM; + } + } + + return 0; +} + +static int x11_convert_to_vconsole(Context *c, sd_bus *bus) { + bool modified = false; + int r; + + assert(bus); + + if (isempty(c->x11_layout)) { + + modified = + !isempty(c->vc_keymap) || + !isempty(c->vc_keymap_toggle); + + context_free_x11(c); + } else { + char *new_keymap = NULL; + + r = find_converted_keymap(c, &new_keymap); + if (r < 0) + return r; + else if (r == 0) { + r = find_legacy_keymap(c, &new_keymap); + if (r < 0) + return r; + } + + if (!streq_ptr(c->vc_keymap, new_keymap)) { + free_and_replace(&c->vc_keymap, new_keymap); + free_and_replace(&c->vc_keymap_toggle, NULL); + modified = true; + } else + free(new_keymap); + } + + if (modified) { + r = vconsole_write_data(c); + if (r < 0) + log_error("Failed to set virtual console keymap: %s", strerror(-r)); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "VConsoleKeymap", "VConsoleKeymapToggle", NULL); + + return vconsole_reload(bus); + } + + return 0; +} + +static int property_get_locale( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Context *c = userdata; + _cleanup_strv_free_ char **l = NULL; + int p, q; + + l = new0(char*, _LOCALE_MAX+1); + if (!l) + return -ENOMEM; + + for (p = 0, q = 0; p < _LOCALE_MAX; p++) { + char *t; + + if (isempty(c->locale[p])) + continue; + + if (asprintf(&t, "%s=%s", names[p], c->locale[p]) < 0) + return -ENOMEM; + + l[q++] = t; + } + + return sd_bus_message_append_strv(reply, l); +} + +static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + _cleanup_strv_free_ char **l = NULL; + char **i; + int interactive; + bool modified = false; + bool passed[_LOCALE_MAX] = {}; + int p; + int r; + + r = bus_message_read_strv_extend(m, &l); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(m, 'b', &interactive); + if (r < 0) + return r; + + /* Check whether a variable changed and if so valid */ + STRV_FOREACH(i, l) { + bool valid = false; + + for (p = 0; p < _LOCALE_MAX; p++) { + size_t k; + + k = strlen(names[p]); + if (startswith(*i, names[p]) && + (*i)[k] == '=' && + string_is_safe((*i) + k + 1)) { + valid = true; + passed[p] = true; + + if (!streq_ptr(*i + k + 1, c->locale[p])) + modified = true; + + break; + } + } + + if (!valid) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data."); + } + + /* Check whether a variable is unset */ + if (!modified) { + for (p = 0; p < _LOCALE_MAX; p++) + if (!isempty(c->locale[p]) && !passed[p]) { + modified = true; + break; + } + } + + if (modified) { + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, + "org.freedesktop.locale1.set-locale", interactive, + error, method_set_locale, c); + 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 */ + + STRV_FOREACH(i, l) { + for (p = 0; p < _LOCALE_MAX; p++) { + size_t k; + + k = strlen(names[p]); + if (startswith(*i, names[p]) && (*i)[k] == '=') { + char *t; + + t = strdup(*i + k + 1); + if (!t) + return -ENOMEM; + + free(c->locale[p]); + c->locale[p] = t; + break; + } + } + } + + for (p = 0; p < _LOCALE_MAX; p++) { + if (passed[p]) + continue; + + free_and_replace(&c->locale[p], NULL); + } + + locale_simplify(c); + + r = locale_write_data(c); + if (r < 0) { + log_error("Failed to set locale: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r)); + } + + locale_update_system_manager(c, bus); + + log_info("Changed locale information."); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "Locale", NULL); + } + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + const char *keymap, *keymap_toggle; + int convert, interactive; + int r; + + r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive); + if (r < 0) + return r; + + if (isempty(keymap)) + keymap = NULL; + + if (isempty(keymap_toggle)) + keymap_toggle = NULL; + + if (!streq_ptr(keymap, c->vc_keymap) || + !streq_ptr(keymap_toggle, c->vc_keymap_toggle)) { + + if ((keymap && (!filename_is_safe(keymap) || !string_is_safe(keymap))) || + (keymap_toggle && (!filename_is_safe(keymap_toggle) || !string_is_safe(keymap_toggle)))) + return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data"); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, + "org.freedesktop.locale1.set-keyboard", + interactive, error, method_set_vc_keyboard, c); + 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 (free_and_copy(&c->vc_keymap, keymap) < 0 || + free_and_copy(&c->vc_keymap_toggle, keymap_toggle) < 0) + return -ENOMEM; + + r = vconsole_write_data(c); + if (r < 0) { + log_error("Failed to set virtual console keymap: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r)); + } + + log_info("Changed virtual console keymap to '%s'", strempty(c->vc_keymap)); + + r = vconsole_reload(bus); + if (r < 0) + log_error("Failed to request keymap reload: %s", strerror(-r)); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "VConsoleKeymap", "VConsoleKeymapToggle", NULL); + + if (convert) { + r = vconsole_convert_to_x11(c, bus); + if (r < 0) + log_error("Failed to convert keymap data: %s", strerror(-r)); + } + } + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + const char *layout, *model, *variant, *options; + int convert, interactive; + int r; + + r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive); + if (r < 0) + return r; + + if (isempty(layout)) + layout = NULL; + + if (isempty(model)) + model = NULL; + + if (isempty(variant)) + variant = NULL; + + if (isempty(options)) + options = NULL; + + if (!streq_ptr(layout, c->x11_layout) || + !streq_ptr(model, c->x11_model) || + !streq_ptr(variant, c->x11_variant) || + !streq_ptr(options, c->x11_options)) { + + if ((layout && !string_is_safe(layout)) || + (model && !string_is_safe(model)) || + (variant && !string_is_safe(variant)) || + (options && !string_is_safe(options))) + return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data"); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, + "org.freedesktop.locale1.set-keyboard", + interactive, error, method_set_x11_keyboard, c); + 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 (free_and_copy(&c->x11_layout, layout) < 0 || + free_and_copy(&c->x11_model, model) < 0 || + free_and_copy(&c->x11_variant, variant) < 0 || + free_and_copy(&c->x11_options, options) < 0) + return -ENOMEM; + + r = write_data_x11(c); + if (r < 0) { + log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r)); + } + + log_info("Changed X11 keyboard layout to '%s'", strempty(c->x11_layout)); + + sd_bus_emit_properties_changed(bus, + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + "X11Layout" "X11Model" "X11Variant" "X11Options", NULL); + + if (convert) { + r = x11_convert_to_vconsole(c, bus); + if (r < 0) + log_error("Failed to convert keymap data: %s", strerror(-r)); + } + } + + return sd_bus_reply_method_return(m, NULL); +} + +static const sd_bus_vtable locale_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Locale", "as", property_get_locale, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("X11Layout", "s", NULL, offsetof(Context, x11_layout), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("X11Model", "s", NULL, offsetof(Context, x11_model), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("X11Variant", "s", NULL, offsetof(Context, x11_variant), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("X11Options", "s", NULL, offsetof(Context, x11_options), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("VConsoleKeymap", "s", NULL, offsetof(Context, vc_keymap), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("VConsoleKeymapToggle", "s", NULL, offsetof(Context, vc_keymap_toggle), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_METHOD("SetLocale", "asb", NULL, method_set_locale, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetVConsoleKeyboard", "ssbb", NULL, method_set_vc_keyboard, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetX11Keyboard", "ssssbb", NULL, method_set_x11_keyboard, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END +}; + +static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + assert(c); + assert(event); + assert(_bus); + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to get system bus connection: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_object_vtable(bus, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c); + if (r < 0) { + log_error("Failed to register object: %s", strerror(-r)); + return r; + } + + r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(bus, event, 0); + if (r < 0) { + log_error("Failed to attach bus to event loop: %s", strerror(-r)); + return r; + } + + *_bus = bus; + bus = NULL; + + return 0; +} + +int main(int argc, char *argv[]) { + Context context = {}; + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + label_init("/etc"); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + r = sd_event_default(&event); + if (r < 0) { + log_error("Failed to allocate event loop: %s", strerror(-r)); + goto finish; + } + + sd_event_set_watchdog(event, true); + + r = connect_bus(&context, event, &bus); + if (r < 0) + goto finish; + + r = context_read_data(&context); + if (r < 0) { + log_error("Failed to read locale data: %s", strerror(-r)); + goto finish; + } + + r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + goto finish; + } + +finish: + context_free(&context, bus); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/locale/org.freedesktop.locale1.conf b/src/locale/org.freedesktop.locale1.conf new file mode 100644 index 0000000..79d0ecd --- /dev/null +++ b/src/locale/org.freedesktop.locale1.conf @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/locale/org.freedesktop.locale1.policy.in b/src/locale/org.freedesktop.locale1.policy.in new file mode 100644 index 0000000..df63845 --- /dev/null +++ b/src/locale/org.freedesktop.locale1.policy.in @@ -0,0 +1,40 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Set system locale + <_message>Authentication is required to set the system locale. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.locale1.set-keyboard + + + + <_description>Set system keyboard settings + <_message>Authentication is required to set the system keyboard settings. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + diff --git a/src/locale/org.freedesktop.locale1.service b/src/locale/org.freedesktop.locale1.service new file mode 100644 index 0000000..025f9a0 --- /dev/null +++ b/src/locale/org.freedesktop.locale1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.locale1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.locale1.service diff --git a/src/localed.c b/src/localed.c deleted file mode 100644 index c6b48de..0000000 --- a/src/localed.c +++ /dev/null @@ -1,1429 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include -#include -#include - -#include "util.h" -#include "strv.h" -#include "dbus-common.h" -#include "polkit.h" -#include "def.h" - -#define INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - BUS_PEER_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.locale1\0" - -const char locale_interface[] _introspect_("locale1") = INTERFACE; - -enum { - /* We don't list LC_ALL here on purpose. People should be - * using LANG instead. */ - - PROP_LANG, - PROP_LANGUAGE, - PROP_LC_CTYPE, - PROP_LC_NUMERIC, - PROP_LC_TIME, - PROP_LC_COLLATE, - PROP_LC_MONETARY, - PROP_LC_MESSAGES, - PROP_LC_PAPER, - PROP_LC_NAME, - PROP_LC_ADDRESS, - PROP_LC_TELEPHONE, - PROP_LC_MEASUREMENT, - PROP_LC_IDENTIFICATION, - _PROP_MAX -}; - -static const char * const names[_PROP_MAX] = { - [PROP_LANG] = "LANG", - [PROP_LANGUAGE] = "LANGUAGE", - [PROP_LC_CTYPE] = "LC_CTYPE", - [PROP_LC_NUMERIC] = "LC_NUMERIC", - [PROP_LC_TIME] = "LC_TIME", - [PROP_LC_COLLATE] = "LC_COLLATE", - [PROP_LC_MONETARY] = "LC_MONETARY", - [PROP_LC_MESSAGES] = "LC_MESSAGES", - [PROP_LC_PAPER] = "LC_PAPER", - [PROP_LC_NAME] = "LC_NAME", - [PROP_LC_ADDRESS] = "LC_ADDRESS", - [PROP_LC_TELEPHONE] = "LC_TELEPHONE", - [PROP_LC_MEASUREMENT] = "LC_MEASUREMENT", - [PROP_LC_IDENTIFICATION] = "LC_IDENTIFICATION" -}; - -static char *data[_PROP_MAX] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -static char *x11_layout = NULL, *x11_model = NULL, *x11_variant = NULL, *x11_options = NULL; -static char *vc_keymap = NULL, *vc_keymap_toggle = NULL; - -static usec_t remain_until = 0; - -static int free_and_set(char **s, const char *v) { - int r; - char *t; - - assert(s); - - r = strdup_or_null(isempty(v) ? NULL : v, &t); - if (r < 0) - return r; - - free(*s); - *s = t; - - return 0; -} - -static void free_data_locale(void) { - int p; - - for (p = 0; p < _PROP_MAX; p++) { - free(data[p]); - data[p] = NULL; - } -} - -static void free_data_x11(void) { - free(x11_layout); - free(x11_model); - free(x11_variant); - free(x11_options); - - x11_layout = x11_model = x11_variant = x11_options = NULL; -} - -static void free_data_vconsole(void) { - free(vc_keymap); - free(vc_keymap_toggle); - - vc_keymap = vc_keymap_toggle = NULL; -} - -static void simplify(void) { - int p; - - for (p = 1; p < _PROP_MAX; p++) - if (isempty(data[p]) || streq_ptr(data[PROP_LANG], data[p])) { - free(data[p]); - data[p] = NULL; - } -} - -static int read_data_locale(void) { - int r; - - free_data_locale(); - - r = parse_env_file("/etc/locale.conf", NEWLINE, - "LANG", &data[PROP_LANG], - "LANGUAGE", &data[PROP_LANGUAGE], - "LC_CTYPE", &data[PROP_LC_CTYPE], - "LC_NUMERIC", &data[PROP_LC_NUMERIC], - "LC_TIME", &data[PROP_LC_TIME], - "LC_COLLATE", &data[PROP_LC_COLLATE], - "LC_MONETARY", &data[PROP_LC_MONETARY], - "LC_MESSAGES", &data[PROP_LC_MESSAGES], - "LC_PAPER", &data[PROP_LC_PAPER], - "LC_NAME", &data[PROP_LC_NAME], - "LC_ADDRESS", &data[PROP_LC_ADDRESS], - "LC_TELEPHONE", &data[PROP_LC_TELEPHONE], - "LC_MEASUREMENT", &data[PROP_LC_MEASUREMENT], - "LC_IDENTIFICATION", &data[PROP_LC_IDENTIFICATION], - NULL); - - if (r == -ENOENT) { - int p; - - /* Fill in what we got passed from systemd. */ - - for (p = 0; p < _PROP_MAX; p++) { - char *e, *d; - - assert(names[p]); - - e = getenv(names[p]); - if (e) { - d = strdup(e); - if (!d) - return -ENOMEM; - } else - d = NULL; - - free(data[p]); - data[p] = d; - } - - r = 0; - } - - simplify(); - return r; -} - -static void free_data(void) { - free_data_locale(); - free_data_vconsole(); - free_data_x11(); -} - -static int read_data_vconsole(void) { - int r; - - free_data_vconsole(); - - r = parse_env_file("/etc/vconsole.conf", NEWLINE, - "KEYMAP", &vc_keymap, - "KEYMAP_TOGGLE", &vc_keymap_toggle, - NULL); - - if (r < 0 && r != -ENOENT) - return r; - - return 0; -} - -static int read_data_x11(void) { - FILE *f; - char line[LINE_MAX]; - bool in_section = false; - - free_data_x11(); - - f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re"); - if (!f) { - if (errno == ENOENT) { - -#ifdef TARGET_FEDORA - f = fopen("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf", "re"); - if (!f) { - if (errno == ENOENT) - return 0; - else - return -errno; - } -#else - return 0; -#endif - - } else - return -errno; - } - - while (fgets(line, sizeof(line), f)) { - char *l; - - char_array_0(line); - l = strstrip(line); - - if (l[0] == 0 || l[0] == '#') - continue; - - if (in_section && first_word(l, "Option")) { - char **a; - - a = strv_split_quoted(l); - if (!a) { - fclose(f); - return -ENOMEM; - } - - if (strv_length(a) == 3) { - - if (streq(a[1], "XkbLayout")) { - free(x11_layout); - x11_layout = a[2]; - a[2] = NULL; - } else if (streq(a[1], "XkbModel")) { - free(x11_model); - x11_model = a[2]; - a[2] = NULL; - } else if (streq(a[1], "XkbVariant")) { - free(x11_variant); - x11_variant = a[2]; - a[2] = NULL; - } else if (streq(a[1], "XkbOptions")) { - free(x11_options); - x11_options = a[2]; - a[2] = NULL; - } - } - - strv_free(a); - - } else if (!in_section && first_word(l, "Section")) { - char **a; - - a = strv_split_quoted(l); - if (!a) { - fclose(f); - return -ENOMEM; - } - - if (strv_length(a) == 2 && streq(a[1], "InputClass")) - in_section = true; - - strv_free(a); - } else if (in_section && first_word(l, "EndSection")) - in_section = false; - } - - fclose(f); - - return 0; -} - -static int read_data(void) { - int r, q, p; - - r = read_data_locale(); - q = read_data_vconsole(); - p = read_data_x11(); - - return r < 0 ? r : q < 0 ? q : p; -} - -static int write_data_locale(void) { - int r, p; - char **l = NULL; - - r = load_env_file("/etc/locale.conf", &l); - if (r < 0 && r != -ENOENT) - return r; - - for (p = 0; p < _PROP_MAX; p++) { - char *t, **u; - - assert(names[p]); - - if (isempty(data[p])) { - l = strv_env_unset(l, names[p]); - continue; - } - - if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) { - strv_free(l); - return -ENOMEM; - } - - u = strv_env_set(l, t); - free(t); - strv_free(l); - - if (!u) - return -ENOMEM; - - l = u; - } - - if (strv_isempty(l)) { - strv_free(l); - - if (unlink("/etc/locale.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file("/etc/locale.conf", l); - strv_free(l); - - return r; -} - -static void push_data(DBusConnection *bus) { - char **l_set = NULL, **l_unset = NULL, **t; - int c_set = 0, c_unset = 0, p; - DBusError error; - DBusMessage *m = NULL, *reply = NULL; - DBusMessageIter iter, sub; - - dbus_error_init(&error); - - assert(bus); - - l_set = new0(char*, _PROP_MAX); - l_unset = new0(char*, _PROP_MAX); - if (!l_set || !l_unset) { - log_error("Out of memory"); - goto finish; - } - - for (p = 0; p < _PROP_MAX; p++) { - assert(names[p]); - - if (isempty(data[p])) - l_unset[c_set++] = (char*) names[p]; - else { - char *s; - - if (asprintf(&s, "%s=%s", names[p], data[p]) < 0) { - log_error("Out of memory"); - goto finish; - } - - l_set[c_unset++] = s; - } - } - - assert(c_set + c_unset == _PROP_MAX); - m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment"); - if (!m) { - log_error("Could not allocate message."); - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) { - log_error("Out of memory."); - goto finish; - } - - STRV_FOREACH(t, l_unset) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) { - log_error("Out of memory."); - goto finish; - } - - if (!dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) { - log_error("Out of memory."); - goto finish; - } - - STRV_FOREACH(t, l_set) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) { - log_error("Out of memory."); - goto finish; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) { - log_error("Out of memory."); - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to set locale information: %s", bus_error_message(&error)); - goto finish; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - strv_free(l_set); - free(l_unset); -} - -static int write_data_vconsole(void) { - int r; - char **l = NULL; - - r = load_env_file("/etc/vconsole.conf", &l); - if (r < 0 && r != -ENOENT) - return r; - - if (isempty(vc_keymap)) - l = strv_env_unset(l, "KEYMAP"); - else { - char *s, **u; - - s = strappend("KEYMAP=", vc_keymap); - if (!s) { - strv_free(l); - return -ENOMEM; - } - - u = strv_env_set(l, s); - free(s); - strv_free(l); - - if (!u) - return -ENOMEM; - - l = u; - } - - if (isempty(vc_keymap_toggle)) - l = strv_env_unset(l, "KEYMAP_TOGGLE"); - else { - char *s, **u; - - s = strappend("KEYMAP_TOGGLE=", vc_keymap_toggle); - if (!s) { - strv_free(l); - return -ENOMEM; - } - - u = strv_env_set(l, s); - free(s); - strv_free(l); - - if (!u) - return -ENOMEM; - - l = u; - } - - if (strv_isempty(l)) { - strv_free(l); - - if (unlink("/etc/vconsole.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - r = write_env_file("/etc/vconsole.conf", l); - strv_free(l); - - return r; -} - -static int write_data_x11(void) { - FILE *f; - char *temp_path; - int r; - - if (isempty(x11_layout) && - isempty(x11_model) && - isempty(x11_variant) && - isempty(x11_options)) { - -#ifdef TARGET_FEDORA - unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf"); - - /* Symlink this to /dev/null, so that s-s-k (if it is - * still running) doesn't recreate this. */ - symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf"); -#endif - - if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) - return errno == ENOENT ? 0 : -errno; - - return 0; - } - - mkdir_parents("/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; - - fchmod(fileno(f), 0644); - - fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n" - "# manually too freely.\n" - "Section \"InputClass\"\n" - " Identifier \"system-keyboard\"\n" - " MatchIsKeyboard \"on\"\n", f); - - if (!isempty(x11_layout)) - fprintf(f, " Option \"XkbLayout\" \"%s\"\n", x11_layout); - - if (!isempty(x11_model)) - fprintf(f, " Option \"XkbModel\" \"%s\"\n", x11_model); - - if (!isempty(x11_variant)) - fprintf(f, " Option \"XkbVariant\" \"%s\"\n", x11_variant); - - if (!isempty(x11_options)) - fprintf(f, " Option \"XkbOptions\" \"%s\"\n", x11_options); - - fputs("EndSection\n", f); - fflush(f); - - if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) { - r = -errno; - unlink("/etc/X11/xorg.conf.d/00-keyboard.conf"); - unlink(temp_path); - } else { - -#ifdef TARGET_FEDORA - unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf"); - - /* Symlink this to /dev/null, so that s-s-k (if it is - * still running) doesn't recreate this. */ - symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf"); -#endif - - r = 0; - } - - fclose(f); - free(temp_path); - - return r; -} - -static int load_vconsole_keymap(DBusConnection *bus, DBusError *error) { - DBusMessage *m = NULL, *reply = NULL; - const char *name = "systemd-vconsole-setup.service", *mode = "replace"; - int r; - DBusError _error; - - assert(bus); - - if (!error) { - dbus_error_init(&_error); - error = &_error; - } - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "RestartUnit"); - if (!m) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - if (error == &_error) - dbus_error_free(error); - - return r; -} - -static char *strnulldash(const char *s) { - return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s; -} - -static int read_next_mapping(FILE *f, unsigned *n, char ***a) { - assert(f); - assert(n); - assert(a); - - for (;;) { - char line[LINE_MAX]; - char *l, **b; - - errno = 0; - if (!fgets(line, sizeof(line), f)) { - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; - } - - (*n) ++; - - l = strstrip(line); - if (l[0] == 0 || l[0] == '#') - continue; - - b = strv_split_quoted(l); - if (!b) - return -ENOMEM; - - if (strv_length(b) < 5) { - log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n); - strv_free(b); - continue; - - } - - *a = b; - return 1; - } -} - -static int convert_vconsole_to_x11(DBusConnection *connection) { - bool modified = false; - - assert(connection); - - if (isempty(vc_keymap)) { - - modified = - !isempty(x11_layout) || - !isempty(x11_model) || - !isempty(x11_variant) || - !isempty(x11_options); - - free_data_x11(); - } else { - FILE *f; - unsigned n = 0; - - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - char **a; - int r; - - r = read_next_mapping(f, &n, &a); - if (r < 0) { - fclose(f); - return r; - } - - if (r == 0) - break; - - if (!streq(vc_keymap, a[0])) { - strv_free(a); - continue; - } - - if (!streq_ptr(x11_layout, strnulldash(a[1])) || - !streq_ptr(x11_model, strnulldash(a[2])) || - !streq_ptr(x11_variant, strnulldash(a[3])) || - !streq_ptr(x11_options, strnulldash(a[4]))) { - - if (free_and_set(&x11_layout, strnulldash(a[1])) < 0 || - free_and_set(&x11_model, strnulldash(a[2])) < 0 || - free_and_set(&x11_variant, strnulldash(a[3])) < 0 || - free_and_set(&x11_options, strnulldash(a[4])) < 0) { - strv_free(a); - fclose(f); - return -ENOMEM; - } - - modified = true; - } - - strv_free(a); - break; - } - - fclose(f); - } - - if (modified) { - dbus_bool_t b; - DBusMessage *changed; - int r; - - r = write_data_x11(); - if (r < 0) - log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); - - changed = bus_properties_changed_new( - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "X11Layout\0" - "X11Model\0" - "X11Variant\0" - "X11Options\0"); - - if (!changed) - return -ENOMEM; - - b = dbus_connection_send(connection, changed, NULL); - dbus_message_unref(changed); - - if (!b) - return -ENOMEM; - } - - return 0; -} - -static int convert_x11_to_vconsole(DBusConnection *connection) { - bool modified = false; - - assert(connection); - - if (isempty(x11_layout)) { - - modified = - !isempty(vc_keymap) || - !isempty(vc_keymap_toggle); - - free_data_x11(); - } else { - FILE *f; - unsigned n = 0; - unsigned best_matching = 0; - char *new_keymap = NULL; - - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; - - for (;;) { - char **a; - unsigned matching = 0; - int r; - - r = read_next_mapping(f, &n, &a); - if (r < 0) { - fclose(f); - return r; - } - - if (r == 0) - break; - - /* Determine how well matching this entry is */ - if (streq_ptr(x11_layout, a[1])) - /* If we got an exact match, this is best */ - matching = 10; - else { - size_t x; - - x = strcspn(x11_layout, ","); - - /* We have multiple X layouts, look - * for an entry that matches our key - * with the everything but the first - * layout stripped off. */ - if (x > 0 && - strlen(a[1]) == x && - strncmp(x11_layout, a[1], x) == 0) - matching = 5; - else { - size_t w; - - /* If that didn't work, strip - * off the other layouts from - * the entry, too */ - - w = strcspn(a[1], ","); - - if (x > 0 && x == w && - memcmp(x11_layout, a[1], x) == 0) - matching = 1; - } - } - - if (matching > 0 && - streq_ptr(x11_model, a[2])) { - matching++; - - if (streq_ptr(x11_variant, a[3])) { - matching++; - - if (streq_ptr(x11_options, a[4])) - matching++; - } - } - - /* The best matching entry so far, then let's - * save that */ - if (matching > best_matching) { - best_matching = matching; - - free(new_keymap); - new_keymap = strdup(a[0]); - - if (!new_keymap) { - strv_free(a); - fclose(f); - return -ENOMEM; - } - } - - strv_free(a); - } - - fclose(f); - - if (!streq_ptr(vc_keymap, new_keymap)) { - free(vc_keymap); - vc_keymap = new_keymap; - - free(vc_keymap_toggle); - vc_keymap_toggle = NULL; - - modified = true; - } else - free(new_keymap); - } - - if (modified) { - dbus_bool_t b; - DBusMessage *changed; - int r; - - r = write_data_vconsole(); - if (r < 0) - log_error("Failed to set virtual console keymap: %s", strerror(-r)); - - changed = bus_properties_changed_new( - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "VConsoleKeymap\0" - "VConsoleKeymapToggle\0"); - - if (!changed) - return -ENOMEM; - - b = dbus_connection_send(connection, changed, NULL); - dbus_message_unref(changed); - - if (!b) - return -ENOMEM; - - return load_vconsole_keymap(connection, NULL); - } - - return 0; -} - -static int append_locale(DBusMessageIter *i, const char *property, void *userdata) { - int r, c = 0, p; - char **l; - - l = new0(char*, _PROP_MAX+1); - if (!l) - return -ENOMEM; - - for (p = 0; p < _PROP_MAX; p++) { - char *t; - - if (isempty(data[p])) - continue; - - if (asprintf(&t, "%s=%s", names[p], data[p]) < 0) { - strv_free(l); - return -ENOMEM; - } - - l[c++] = t; - } - - r = bus_property_append_strv(i, property, (void*) l); - strv_free(l); - - return r; -} - -static DBusHandlerResult locale_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - const BusProperty properties[] = { - { "org.freedesktop.locale1", "Locale", append_locale, "as", NULL }, - { "org.freedesktop.locale1", "X11Layout", bus_property_append_string, "s", x11_layout }, - { "org.freedesktop.locale1", "X11Model", bus_property_append_string, "s", x11_model }, - { "org.freedesktop.locale1", "X11Variant", bus_property_append_string, "s", x11_variant }, - { "org.freedesktop.locale1", "X11Options", bus_property_append_string, "s", x11_options }, - { "org.freedesktop.locale1", "VConsoleKeymap", bus_property_append_string, "s", vc_keymap }, - { "org.freedesktop.locale1", "VConsoleKeymapToggle", bus_property_append_string, "s", vc_keymap_toggle }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL, *changed = NULL; - DBusError error; - int r; - - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetLocale")) { - char **l = NULL, **i; - dbus_bool_t interactive; - DBusMessageIter iter; - bool modified = false; - bool passed[_PROP_MAX]; - int p; - - if (!dbus_message_iter_init(message, &iter)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - r = bus_parse_strv_iter(&iter, &l); - if (r < 0) { - if (r == -ENOMEM) - goto oom; - - return bus_send_error_reply(connection, message, NULL, r); - } - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EINVAL); - } - - dbus_message_iter_get_basic(&iter, &interactive); - - zero(passed); - - /* Check whether a variable changed and if so valid */ - STRV_FOREACH(i, l) { - bool valid = false; - - for (p = 0; p < _PROP_MAX; p++) { - size_t k; - - k = strlen(names[p]); - if (startswith(*i, names[p]) && (*i)[k] == '=') { - valid = true; - passed[p] = true; - - if (!streq_ptr(*i + k + 1, data[p])) - modified = true; - - break; - } - } - - if (!valid) { - strv_free(l); - return bus_send_error_reply(connection, message, NULL, -EINVAL); - } - } - - /* Check whether a variable is unset */ - if (!modified) { - for (p = 0; p < _PROP_MAX; p++) - if (!isempty(data[p]) && !passed[p]) { - modified = true; - break; - } - } - - if (modified) { - - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-locale", interactive, &error); - if (r < 0) { - strv_free(l); - return bus_send_error_reply(connection, message, &error, r); - } - - STRV_FOREACH(i, l) { - for (p = 0; p < _PROP_MAX; p++) { - size_t k; - - k = strlen(names[p]); - if (startswith(*i, names[p]) && (*i)[k] == '=') { - char *t; - - t = strdup(*i + k + 1); - if (!t) { - strv_free(l); - goto oom; - } - - free(data[p]); - data[p] = t; - - break; - } - } - } - - strv_free(l); - - for (p = 0; p < _PROP_MAX; p++) { - if (passed[p]) - continue; - - free(data[p]); - data[p] = NULL; - } - - simplify(); - - r = write_data_locale(); - if (r < 0) { - log_error("Failed to set locale: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - push_data(connection); - - log_info("Changed locale information."); - - changed = bus_properties_changed_new( - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "Locale\0"); - if (!changed) - goto oom; - } - } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetVConsoleKeyboard")) { - - const char *keymap, *keymap_toggle; - dbus_bool_t convert, interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &keymap, - DBUS_TYPE_STRING, &keymap_toggle, - DBUS_TYPE_BOOLEAN, &convert, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(keymap)) - keymap = NULL; - - if (isempty(keymap_toggle)) - keymap_toggle = NULL; - - if (!streq_ptr(keymap, vc_keymap) || - !streq_ptr(keymap_toggle, vc_keymap_toggle)) { - - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (free_and_set(&vc_keymap, keymap) < 0 || - free_and_set(&vc_keymap_toggle, keymap_toggle) < 0) - goto oom; - - r = write_data_vconsole(); - if (r < 0) { - log_error("Failed to set virtual console keymap: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed virtual console keymap to '%s'", strempty(vc_keymap)); - - r = load_vconsole_keymap(connection, NULL); - if (r < 0) - log_error("Failed to request keymap reload: %s", strerror(-r)); - - changed = bus_properties_changed_new( - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "VConsoleKeymap\0" - "VConsoleKeymapToggle\0"); - if (!changed) - goto oom; - - if (convert) { - r = convert_vconsole_to_x11(connection); - - if (r < 0) - log_error("Failed to convert keymap data: %s", strerror(-r)); - } - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetX11Keyboard")) { - - const char *layout, *model, *variant, *options; - dbus_bool_t convert, interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &layout, - DBUS_TYPE_STRING, &model, - DBUS_TYPE_STRING, &variant, - DBUS_TYPE_STRING, &options, - DBUS_TYPE_BOOLEAN, &convert, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(layout)) - layout = NULL; - - if (isempty(model)) - model = NULL; - - if (isempty(variant)) - variant = NULL; - - if (isempty(options)) - options = NULL; - - if (!streq_ptr(layout, x11_layout) || - !streq_ptr(model, x11_model) || - !streq_ptr(variant, x11_variant) || - !streq_ptr(options, x11_options)) { - - r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (free_and_set(&x11_layout, layout) < 0 || - free_and_set(&x11_model, model) < 0 || - free_and_set(&x11_variant, variant) < 0 || - free_and_set(&x11_options, options) < 0) - goto oom; - - r = write_data_x11(); - if (r < 0) { - log_error("Failed to set X11 keyboard layout: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - log_info("Changed X11 keyboard layout to '%s'", strempty(x11_layout)); - - changed = bus_properties_changed_new( - "/org/freedesktop/locale1", - "org.freedesktop.locale1", - "X11Layout\0" - "X11Model\0" - "X11Variant\0" - "X11Options\0"); - if (!changed) - goto oom; - - if (convert) { - r = convert_x11_to_vconsole(connection); - - if (r < 0) - log_error("Failed to convert keymap data: %s", strerror(-r)); - } - } - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - reply = NULL; - - if (changed) { - - if (!dbus_connection_send(connection, changed, NULL)) - goto oom; - - dbus_message_unref(changed); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (changed) - dbus_message_unref(changed); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static int connect_bus(DBusConnection **_bus) { - static const DBusObjectPathVTable locale_vtable = { - .message_function = locale_message_handler - }; - DBusError error; - DBusConnection *bus = NULL; - int r; - - assert(_bus); - - dbus_error_init(&error); - - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!bus) { - log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); - r = -ECONNREFUSED; - goto fail; - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL) || - !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - r = dbus_bus_request_name(bus, "org.freedesktop.locale1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); - if (dbus_error_is_set(&error)) { - log_error("Failed to register name on bus: %s", bus_error_message(&error)); - r = -EEXIST; - goto fail; - } - - if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - log_error("Failed to acquire name."); - r = -EEXIST; - goto fail; - } - - if (_bus) - *_bus = bus; - - return 0; - -fail: - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_error_free(&error); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - DBusConnection *bus = NULL; - bool exiting = false; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc == 2 && streq(argv[1], "--introspect")) { - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", stdout); - fputs(locale_interface, stdout); - fputs("\n", stdout); - return 0; - } - - if (argc != 1) { - log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; - } - - r = read_data(); - if (r < 0) { - log_error("Failed to read locale data: %s", strerror(-r)); - goto finish; - } - - r = connect_bus(&bus); - if (r < 0) - goto finish; - - remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - for (;;) { - - if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) - break; - - if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { - exiting = true; - bus_async_unregister_and_exit(bus, "org.freedesktop.locale1"); - } - } - - r = 0; - -finish: - free_data(); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/log.c b/src/log.c deleted file mode 100644 index b8ce122..0000000 --- a/src/log.c +++ /dev/null @@ -1,593 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "macro.h" - -#define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC) - -static LogTarget log_target = LOG_TARGET_CONSOLE; -static int log_max_level = LOG_INFO; - -static int console_fd = STDERR_FILENO; -static int syslog_fd = -1; -static int kmsg_fd = -1; - -static bool syslog_is_stream = false; - -static bool show_color = false; -static bool show_location = false; - -/* Akin to glibc's __abort_msg; which is private and we hence cannot - * use here. */ -static char *log_abort_msg = NULL; - -void log_close_console(void) { - - if (console_fd < 0) - return; - - if (getpid() == 1) { - if (console_fd >= 3) - close_nointr_nofail(console_fd); - - console_fd = -1; - } -} - -static int log_open_console(void) { - - if (console_fd >= 0) - return 0; - - if (getpid() == 1) { - - if ((console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) { - log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd)); - return console_fd; - } - - log_debug("Successfully opened /dev/console for logging."); - } else - console_fd = STDERR_FILENO; - - return 0; -} - -void log_close_kmsg(void) { - - if (kmsg_fd < 0) - return; - - close_nointr_nofail(kmsg_fd); - kmsg_fd = -1; -} - -static int log_open_kmsg(void) { - - if (kmsg_fd >= 0) - return 0; - - if ((kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) { - log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno)); - return -errno; - } - - log_debug("Successfully opened /dev/kmsg for logging."); - - return 0; -} - -void log_close_syslog(void) { - - if (syslog_fd < 0) - return; - - close_nointr_nofail(syslog_fd); - syslog_fd = -1; -} - -static int create_log_socket(int type) { - struct timeval tv; - int fd; - - if ((fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0)) < 0) - return -errno; - - /* Make sure we don't block for more than 5s when talking to - * syslog */ - timeval_store(&tv, SYSLOG_TIMEOUT_USEC); - if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - return fd; -} - -static int log_open_syslog(void) { - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - int r; - - if (syslog_fd >= 0) - return 0; - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); - - if ((syslog_fd = create_log_socket(SOCK_DGRAM)) < 0) { - r = -errno; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) { - close_nointr_nofail(syslog_fd); - - /* Some legacy syslog systems still use stream - * sockets. They really shouldn't. But what can we - * do... */ - if ((syslog_fd = create_log_socket(SOCK_STREAM)) < 0) { - r = -errno; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, sizeof(sa)) < 0) { - r = -errno; - goto fail; - } - - syslog_is_stream = true; - } else - syslog_is_stream = false; - - log_debug("Successfully opened syslog for logging."); - - return 0; - -fail: - log_close_syslog(); - log_debug("Failed to open syslog for logging: %s", strerror(-r)); - return r; -} - -int log_open(void) { - int r; - - /* If we don't use the console we close it here, to not get - * killed by SAK. If we don't use syslog we close it here so - * that we are not confused by somebody deleting the socket in - * the fs. If we don't use /dev/kmsg we still keep it open, - * because there is no reason to close it. */ - - if (log_target == LOG_TARGET_NULL) { - log_close_syslog(); - log_close_console(); - return 0; - } - - if (log_target != LOG_TARGET_AUTO || - getpid() == 1 || - isatty(STDERR_FILENO) <= 0) { - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) - if ((r = log_open_syslog()) >= 0) { - log_close_console(); - return r; - } - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG) - if ((r = log_open_kmsg()) >= 0) { - log_close_syslog(); - log_close_console(); - return r; - } - } - - log_close_syslog(); - - /* Get the real /dev/console if we are PID=1, hence reopen */ - log_close_console(); - return log_open_console(); -} - -void log_set_target(LogTarget target) { - assert(target >= 0); - assert(target < _LOG_TARGET_MAX); - - log_target = target; -} - -void log_close(void) { - log_close_console(); - log_close_kmsg(); - log_close_syslog(); -} - -void log_set_max_level(int level) { - assert((level & LOG_PRIMASK) == level); - - log_max_level = level; -} - -static int write_to_console( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char location[64]; - struct iovec iovec[5]; - unsigned n = 0; - bool highlight; - - if (console_fd < 0) - return 0; - - snprintf(location, sizeof(location), "(%s:%u) ", file, line); - char_array_0(location); - - highlight = LOG_PRI(level) <= LOG_ERR && show_color; - - zero(iovec); - if (show_location) - IOVEC_SET_STRING(iovec[n++], location); - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_ON); - IOVEC_SET_STRING(iovec[n++], buffer); - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(console_fd, iovec, n) < 0) - return -errno; - - return 1; -} - -static int write_to_syslog( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header_priority[16], header_time[64], header_pid[16]; - struct iovec iovec[5]; - struct msghdr msghdr; - time_t t; - struct tm *tm; - - if (syslog_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); - if (!(tm = localtime(&t))) - return -EINVAL; - - if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) - return -EINVAL; - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); - char_array_0(header_pid); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], header_time); - IOVEC_SET_STRING(iovec[2], program_invocation_short_name); - IOVEC_SET_STRING(iovec[3], header_pid); - IOVEC_SET_STRING(iovec[4], buffer); - - /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ - if (syslog_is_stream) - iovec[4].iov_len++; - - zero(msghdr); - msghdr.msg_iov = iovec; - msghdr.msg_iovlen = ELEMENTSOF(iovec); - - for (;;) { - ssize_t n; - - if ((n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL)) < 0) - return -errno; - - if (!syslog_is_stream || - (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) - break; - - IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); - } - - return 1; -} - -static int write_to_kmsg( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header_priority[16], header_pid[16]; - struct iovec iovec[5]; - - if (kmsg_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); - char_array_0(header_pid); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], program_invocation_short_name); - IOVEC_SET_STRING(iovec[2], header_pid); - IOVEC_SET_STRING(iovec[3], buffer); - IOVEC_SET_STRING(iovec[4], "\n"); - - if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) - return -errno; - - return 1; -} - -static int log_dispatch( - int level, - const char*file, - int line, - const char *func, - char *buffer) { - - int r = 0; - - if (log_target == LOG_TARGET_NULL) - return 0; - - /* Patch in LOG_DAEMON facility if necessary */ - if ((level & LOG_FACMASK) == 0) - level = LOG_DAEMON | LOG_PRI(level); - - do { - char *e; - int k = 0; - - buffer += strspn(buffer, NEWLINE); - - if (buffer[0] == 0) - break; - - if ((e = strpbrk(buffer, NEWLINE))) - *(e++) = 0; - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { - - if ((k = write_to_syslog(level, file, line, func, buffer)) < 0) { - log_close_syslog(); - log_open_kmsg(); - } else if (k > 0) - r++; - } - - if (k <= 0 && - (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG)) { - - if ((k = write_to_kmsg(level, file, line, func, buffer)) < 0) { - log_close_kmsg(); - log_open_console(); - } else if (k > 0) - r++; - } - - if (k <= 0 && - (k = write_to_console(level, file, line, func, buffer)) < 0) - return k; - - buffer = e; - } while (buffer); - - return r; -} - -int log_dump_internal( - int level, - const char*file, - int line, - const char *func, - char *buffer) { - - int saved_errno, r; - - /* This modifies the buffer... */ - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - saved_errno = errno; - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; - - return r; -} - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) { - - char buffer[LINE_MAX]; - int saved_errno, r; - va_list ap; - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - saved_errno = errno; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - char_array_0(buffer); - - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; - - return r; -} - -void log_assert( - const char*file, - int line, - const char *func, - const char *format, ...) { - - static char buffer[LINE_MAX]; - int saved_errno = errno; - va_list ap; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - char_array_0(buffer); - log_abort_msg = buffer; - - log_dispatch(LOG_CRIT, file, line, func, buffer); - abort(); - - /* If the user chose to ignore this SIGABRT, we are happy to go on, as if nothing happened. */ - errno = saved_errno; -} - -int log_set_target_from_string(const char *e) { - LogTarget t; - - if ((t = log_target_from_string(e)) < 0) - return -EINVAL; - - log_set_target(t); - return 0; -} - -int log_set_max_level_from_string(const char *e) { - int t; - - if ((t = log_level_from_string(e)) < 0) - return -EINVAL; - - log_set_max_level(t); - return 0; -} - -void log_parse_environment(void) { - const char *e; - - if ((e = getenv("SYSTEMD_LOG_TARGET"))) - if (log_set_target_from_string(e) < 0) - log_warning("Failed to parse log target %s. Ignoring.", e); - - if ((e = getenv("SYSTEMD_LOG_LEVEL"))) - if (log_set_max_level_from_string(e) < 0) - log_warning("Failed to parse log level %s. Ignoring.", e); - - if ((e = getenv("SYSTEMD_LOG_COLOR"))) - if (log_show_color_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); - - if ((e = getenv("SYSTEMD_LOG_LOCATION"))) - if (log_show_location_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); -} - -LogTarget log_get_target(void) { - return log_target; -} - -int log_get_max_level(void) { - return log_max_level; -} - -void log_show_color(bool b) { - show_color = b; -} - -void log_show_location(bool b) { - show_location = b; -} - -int log_show_color_from_string(const char *e) { - int t; - - if ((t = parse_boolean(e)) < 0) - return -EINVAL; - - log_show_color(t); - return 0; -} - -int log_show_location_from_string(const char *e) { - int t; - - if ((t = parse_boolean(e)) < 0) - return -EINVAL; - - log_show_location(t); - return 0; -} - -static const char *const log_target_table[] = { - [LOG_TARGET_CONSOLE] = "console", - [LOG_TARGET_SYSLOG] = "syslog", - [LOG_TARGET_KMSG] = "kmsg", - [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", - [LOG_TARGET_NULL] = "null", - [LOG_TARGET_AUTO] = "auto" -}; - -DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); diff --git a/src/log.h b/src/log.h deleted file mode 100644 index c402afb..0000000 --- a/src/log.h +++ /dev/null @@ -1,102 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologhfoo -#define foologhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "macro.h" - -/* If set to SYSLOG and /dev/log can not be opened we fall back to - * KSMG. If KMSG fails, we fall back to CONSOLE */ -typedef enum LogTarget{ - LOG_TARGET_CONSOLE, - LOG_TARGET_KMSG, - LOG_TARGET_SYSLOG, - LOG_TARGET_SYSLOG_OR_KMSG, - LOG_TARGET_AUTO, /* console if stderr is tty, SYSLOG_OR_KMSG otherwise */ - LOG_TARGET_NULL, - _LOG_TARGET_MAX, - _LOG_TARGET_INVALID = -1 -} LogTarget; - -void log_set_target(LogTarget target); -void log_set_max_level(int level); - -int log_set_target_from_string(const char *e); -int log_set_max_level_from_string(const char *e); - -void log_show_color(bool b); -void log_show_location(bool b); - -int log_show_color_from_string(const char *e); -int log_show_location_from_string(const char *e); - -LogTarget log_get_target(void); -int log_get_max_level(void); - -int log_open(void); -void log_close(void); - -void log_close_syslog(void); -void log_close_kmsg(void); -void log_close_console(void); - -void log_parse_environment(void); - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) _printf_attr_(5,6); - -_noreturn_ void log_assert( - const char*file, - int line, - const char *func, - const char *format, ...) _printf_attr_(4,5); - -/* This modifies the buffer passed! */ -int log_dump_internal( - int level, - const char*file, - int line, - const char *func, - char *buffer); - -#define log_full(level, ...) log_meta(level, __FILE__, __LINE__, __func__, __VA_ARGS__) - -#define log_debug(...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_info(...) log_meta(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_notice(...) log_meta(LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_error(...) log_meta(LOG_ERR, __FILE__, __LINE__, __func__, __VA_ARGS__) - -/* This modifies the buffer passed! */ -#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer) - -const char *log_target_to_string(LogTarget target); -LogTarget log_target_from_string(const char *s); - -#endif diff --git a/src/login/.gitignore b/src/login/.gitignore new file mode 100644 index 0000000..5c0b2ac --- /dev/null +++ b/src/login/.gitignore @@ -0,0 +1,4 @@ +/logind-gperf.c +/org.freedesktop.login1.policy +/71-seat.rules +/73-seat-late.rules diff --git a/src/login/70-power-switch.rules b/src/login/70-power-switch.rules new file mode 100644 index 0000000..36fb827 --- /dev/null +++ b/src/login/70-power-switch.rules @@ -0,0 +1,13 @@ +# 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. + +ACTION=="remove", GOTO="power_switch_end" + +SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="acpi", TAG+="power-switch" +SUBSYSTEM=="input", KERNEL=="event*", KERNELS=="thinkpad_acpi", TAG+="power-switch" + +LABEL="power_switch_end" diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules new file mode 100644 index 0000000..e1cf897 --- /dev/null +++ b/src/login/70-uaccess.rules @@ -0,0 +1,75 @@ +# 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. + +ACTION=="remove", GOTO="uaccess_end" +ENV{MAJOR}=="", GOTO="uaccess_end" + +# PTP/MTP protocol devices, cameras, portable media players +SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess" + +# Digicams with proprietary protocol +ENV{ID_GPHOTO2}=="*?", TAG+="uaccess" + +# SCSI and USB scanners +ENV{libsane_matched}=="yes", TAG+="uaccess" + +# HPLIP devices (necessary for ink level check and HP tool maintenance) +ENV{ID_HPLIP}=="1", TAG+="uaccess" + +# optical drives +SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess" + +# Sound devices +SUBSYSTEM=="sound", TAG+="uaccess" \ + OPTIONS+="static_node=snd/timer", OPTIONS+="static_node=snd/seq" + +# ffado is an userspace driver for firewire sound cards +SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess" + +# Webcams, frame grabber, TV cards +SUBSYSTEM=="video4linux", TAG+="uaccess" +SUBSYSTEM=="dvb", TAG+="uaccess" + +# IIDC devices: industrial cameras and some webcams +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" +# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" + +# DRI video devices +SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" + +# KVM +SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" + +# smart-card readers +ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess" + +# (USB) authentication devices +ENV{ID_SECURITY_TOKEN}=="*?", TAG+="uaccess" + +# PDA devices +ENV{ID_PDA}=="*?", TAG+="uaccess" + +# Programmable remote control +ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess" + +# joysticks +SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess" + +# color measurement devices +ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess" + +# DDC/CI device, usually high-end monitors such as the DreamColor +ENV{DDC_DEVICE}=="*?", TAG+="uaccess" + +# media player raw devices (for user-mode drivers, Android SDK, etc.) +SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" + +LABEL="uaccess_end" diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in new file mode 100644 index 0000000..ad26acb --- /dev/null +++ b/src/login/71-seat.rules.in @@ -0,0 +1,48 @@ +# 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. + +ACTION=="remove", GOTO="seat_end" + +TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" +SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" +SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" +SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat", TAG+="master-of-seat" +SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" + +# 'Plugable' USB hub, sound, network, graphics adapter +SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" + +# 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 +# check it from the parent. There's a bit of a race here however, +# given that the child devices might not exist yet at the time this +# rule is executed. To work around this we'll trigger the parent from +# the child if we notice that the parent wasn't recognized yet. + +# Match parent +SUBSYSTEM=="usb", ATTR{idVendor}=="058f", ATTR{idProduct}=="6254", \ + ATTR{%k.2/idVendor}=="17e9", ATTR{%k.2/idProduct}=="401a", ATTR{%k.2/product}=="mimo inc", \ + ENV{ID_AUTOSEAT}="1", ENV{ID_AVOID_LOOP}="1" + +# Match child, look for parent's ID_AVOID_LOOP +SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", ATTR{idProduct}=="401a", ATTR{product}=="mimo inc", \ + ATTR{../idVendor}=="058f", ATTR{../idProduct}=="6254", \ + IMPORT{parent}="ID_AVOID_LOOP" + +# Match child, retrigger parent +SUBSYSTEM=="usb", ATTR{idVendor}=="17e9", ATTR{idProduct}=="401a", ATTR{product}=="mimo inc", \ + ATTR{../idVendor}=="058f", ATTR{../idProduct}=="6254", \ + ENV{ID_AVOID_LOOP}=="", \ + RUN+="@rootbindir@/udevadm trigger --parent-match=%p/.." + +TAG=="seat", ENV{ID_PATH}=="", IMPORT{builtin}="path_id" +TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}" + +SUBSYSTEM=="input", ATTR{name}=="Wiebetech LLC Wiebetech", RUN+="@rootbindir@/loginctl lock-sessions" + +LABEL="seat_end" diff --git a/src/login/73-seat-late.rules.in b/src/login/73-seat-late.rules.in new file mode 100644 index 0000000..901df75 --- /dev/null +++ b/src/login/73-seat-late.rules.in @@ -0,0 +1,17 @@ +# 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. + +ACTION=="remove", GOTO="seat_late_end" + +ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" +ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" + +ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" + +TAG=="uaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess" + +LABEL="seat_late_end" diff --git a/src/login/Makefile b/src/login/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/login/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/login/inhibit.c b/src/login/inhibit.c new file mode 100644 index 0000000..48c2ec4 --- /dev/null +++ b/src/login/inhibit.c @@ -0,0 +1,285 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "util.h" +#include "build.h" +#include "strv.h" + +static const char* arg_what = "idle:sleep:shutdown"; +static const char* arg_who = NULL; +static const char* arg_why = "Unknown reason"; +static const char* arg_mode = "block"; + +static enum { + ACTION_INHIBIT, + ACTION_LIST +} arg_action = ACTION_INHIBIT; + +static int inhibit(sd_bus *bus, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + int fd; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit", + error, + &reply, + "ssss", arg_what, arg_who, arg_why, arg_mode); + if (r < 0) + return r; + + r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd); + if (r < 0) + return r; + + r = dup(fd); + if (r < 0) + return -errno; + + return r; +} + +static int print_inhibitors(sd_bus *bus, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *what, *who, *why, *mode; + unsigned int uid, pid; + unsigned n = 0; + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListInhibitors", + error, + &reply, + ""); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) { + _cleanup_free_ char *comm = NULL, *u = NULL; + + get_process_comm(pid, &comm); + u = uid_to_name(uid); + + printf(" Who: %s (UID %lu/%s, PID %lu/%s)\n" + " What: %s\n" + " Why: %s\n" + " Mode: %s\n\n", + who, (unsigned long) uid, strna(u), (unsigned long) pid, strna(comm), + what, + why, + mode); + + n++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + printf("%u inhibitors listed.\n", n); + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Execute a process while inhibiting shutdown/sleep/idle.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --what=WHAT Operations to inhibit, colon separated list of:\n" + " shutdown, sleep, idle, handle-power-key,\n" + " handle-suspend-key, handle-hibernate-key,\n" + " handle-lid-switch\n" + " --who=STRING A descriptive string who is inhibiting\n" + " --why=STRING A descriptive string why is being inhibited\n" + " --mode=MODE One of block or delay\n" + " --list List active inhibitors\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_WHAT, + ARG_WHO, + ARG_WHY, + ARG_MODE, + ARG_LIST, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "what", required_argument, NULL, ARG_WHAT }, + { "who", required_argument, NULL, ARG_WHO }, + { "why", required_argument, NULL, ARG_WHY }, + { "mode", required_argument, NULL, ARG_MODE }, + { "list", no_argument, NULL, ARG_LIST }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_WHAT: + arg_what = optarg; + break; + + case ARG_WHO: + arg_who = optarg; + break; + + case ARG_WHY: + arg_why = optarg; + break; + + case ARG_MODE: + arg_mode = optarg; + break; + + case ARG_LIST: + arg_action = ACTION_LIST; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (arg_action == ACTION_INHIBIT && argc == 1) + arg_action = ACTION_LIST; + + else if (arg_action == ACTION_INHIBIT && optind >= argc) { + log_error("Missing command line to execute."); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r < 0) + return EXIT_FAILURE; + if (r == 0) + return EXIT_SUCCESS; + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to connect to bus: %s", strerror(-r)); + return EXIT_FAILURE; + } + + if (arg_action == ACTION_LIST) { + + r = print_inhibitors(bus, &error); + if (r < 0) { + log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r)); + return EXIT_FAILURE; + } + + } else { + _cleanup_close_ int fd = -1; + _cleanup_free_ char *w = NULL; + pid_t pid; + + if (!arg_who) + arg_who = w = strv_join(argv + optind, " "); + + fd = inhibit(bus, &error); + if (fd < 0) { + log_error("Failed to inhibit: %s", bus_error_message(&error, -r)); + return EXIT_FAILURE; + } + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + return EXIT_FAILURE; + } + + if (pid == 0) { + /* Child */ + + close_all_fds(NULL, 0); + + execvp(argv[optind], argv + optind); + log_error("Failed to execute %s: %m", argv[optind]); + _exit(EXIT_FAILURE); + } + + r = wait_for_terminate_and_warn(argv[optind], pid); + return r < 0 ? EXIT_FAILURE : r; + } + + return 0; +} diff --git a/src/login/login-shared.c b/src/login/login-shared.c new file mode 100644 index 0000000..054c775 --- /dev/null +++ b/src/login/login-shared.c @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "login-shared.h" +#include "def.h" + +bool session_id_valid(const char *id) { + assert(id); + + return id[0] && id[strspn(id, LETTERS DIGITS)] == '\0'; +} diff --git a/src/login/login-shared.h b/src/login/login-shared.h new file mode 100644 index 0000000..b2787c9 --- /dev/null +++ b/src/login/login-shared.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +bool session_id_valid(const char *id); diff --git a/src/login/loginctl.c b/src/login/loginctl.c new file mode 100644 index 0000000..ebe9c1f --- /dev/null +++ b/src/login/loginctl.c @@ -0,0 +1,1326 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "log.h" +#include "util.h" +#include "macro.h" +#include "pager.h" +#include "build.h" +#include "strv.h" +#include "unit-name.h" +#include "sysfs-show.h" +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "spawn-polkit-agent.h" + +static char **arg_property = NULL; +static bool arg_all = false; +static bool arg_full = false; +static bool arg_no_pager = false; +static bool arg_legend = true; +static const char *arg_kill_who = NULL; +static int arg_signal = SIGTERM; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static bool arg_ask_password = true; +static char *arg_host = NULL; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static void polkit_agent_open_if_enabled(void) { + + /* Open the polkit agent as a child process if necessary */ + + if (!arg_ask_password) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + polkit_agent_open(); +} + +static int list_sessions(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *id, *user, *seat, *object; + unsigned k = 0; + uint32_t uid; + int r; + + pager_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListSessions", + &error, &reply, + ""); + if (r < 0) { + log_error("Failed to list sessions: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'a', "(susso)"); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT"); + + while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) { + printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat); + k++; + } + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("\n%u sessions listed.\n", k); + + return 0; +} + +static int list_users(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *user, *object; + unsigned k = 0; + uint32_t uid; + int r; + + pager_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListUsers", + &error, &reply, + ""); + if (r < 0) { + log_error("Failed to list users: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'a', "(uso)"); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("%10s %-16s\n", "UID", "USER"); + + while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) { + printf("%10u %-16s\n", (unsigned) uid, user); + k++; + } + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("\n%u users listed.\n", k); + + return 0; +} + +static int list_seats(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *seat, *object; + unsigned k = 0; + int r; + + pager_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListSeats", + &error, &reply, + ""); + if (r < 0) { + log_error("Failed to list seats: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'a', "(so)"); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("%-16s\n", "SEAT"); + + while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) { + printf("%-16s\n", seat); + k++; + } + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("\n%u seats listed.\n", k); + + return 0; +} + +static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ char *path = NULL; + const char *cgroup; + int r, output_flags; + unsigned c; + + assert(bus); + assert(unit); + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return 0; + + path = unit_dbus_path_from_name(unit); + if (!path) + return -ENOMEM; + + r = sd_bus_get_property( + bus, + "org.freedesktop.systemd1", + path, + interface, + "ControlGroup", + &error, &reply, "s"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "s", &cgroup); + if (r < 0) + return r; + + if (isempty(cgroup)) + return 0; + + if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0) + return 0; + + output_flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH; + + c = columns(); + if (c > 18) + c -= 18; + else + c = 0; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags); + return 0; +} + +typedef struct SessionStatusInfo { + const char *id; + uid_t uid; + const char *name; + usec_t timestamp; + unsigned int vtnr; + const char *seat; + const char *tty; + const char *display; + bool remote; + const char *remote_host; + const char *remote_user; + const char *service; + pid_t leader; + const char *type; + const char *class; + const char *state; + const char *scope; + const char *desktop; +} SessionStatusInfo; + +typedef struct UserStatusInfo { + uid_t uid; + const char *name; + usec_t timestamp; + const char *state; + char **sessions; + const char *display; + const char *slice; +} UserStatusInfo; + +typedef struct SeatStatusInfo { + const char *id; + const char *active_session; + char **sessions; +} SeatStatusInfo; + +static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + const char *contents; + int r; + + r = sd_bus_message_peek_type(m, NULL, &contents); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents); + if (r < 0) + return r; + + if (contents[0] == 's' || contents[0] == 'o') { + const char *s; + char **p = (char **) userdata; + + r = sd_bus_message_read_basic(m, contents[0], &s); + if (r < 0) + return r; + + free(*p); + *p = strdup(s); + + if (!*p) + return -ENOMEM; + } else { + r = sd_bus_message_read_basic(m, contents[0], userdata); + if (r < 0) + return r; + } + + r = sd_bus_message_skip(m, contents+1); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + const char *name; + int r; + + assert(bus); + assert(m); + + r = sd_bus_message_enter_container(m, 'a', "(so)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) { + r = strv_extend(userdata, name); + if (r < 0) + return r; + } + if (r < 0) + return r; + + return sd_bus_message_exit_container(m); +} + +static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) { + + static const struct bus_properties_map map[] = { + { "Id", "s", NULL, offsetof(SessionStatusInfo, id) }, + { "Name", "s", NULL, offsetof(SessionStatusInfo, name) }, + { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) }, + { "Display", "s", NULL, offsetof(SessionStatusInfo, display) }, + { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) }, + { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) }, + { "Service", "s", NULL, offsetof(SessionStatusInfo, service) }, + { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) }, + { "Type", "s", NULL, offsetof(SessionStatusInfo, type) }, + { "Class", "s", NULL, offsetof(SessionStatusInfo, class) }, + { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) }, + { "State", "s", NULL, offsetof(SessionStatusInfo, state) }, + { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) }, + { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) }, + { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) }, + { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) }, + { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) }, + { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) }, + {} + }; + + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; + char since2[FORMAT_TIMESTAMP_MAX], *s2; + SessionStatusInfo i = {}; + int r; + + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + if (r < 0) { + log_error("Could not get properties: %s", strerror(-r)); + return r; + } + + if (*new_line) + printf("\n"); + + *new_line = true; + + printf("%s - ", strna(i.id)); + + if (i.name) + printf("%s (%u)\n", i.name, (unsigned) i.uid); + else + printf("%u\n", (unsigned) i.uid); + + s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp); + s2 = format_timestamp(since2, sizeof(since2), i.timestamp); + + if (s1) + printf("\t Since: %s; %s\n", s2, s1); + else if (s2) + printf("\t Since: %s\n", s2); + + if (i.leader > 0) { + _cleanup_free_ char *t = NULL; + + printf("\t Leader: %u", (unsigned) i.leader); + + get_process_comm(i.leader, &t); + if (t) + printf(" (%s)", t); + + printf("\n"); + } + + if (!isempty(i.seat)) { + printf("\t Seat: %s", i.seat); + + if (i.vtnr > 0) + printf("; vc%i", i.vtnr); + + printf("\n"); + } + + if (i.tty) + printf("\t TTY: %s\n", i.tty); + else if (i.display) + printf("\t Display: %s\n", i.display); + + if (i.remote_host && i.remote_user) + printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host); + else if (i.remote_host) + printf("\t Remote: %s\n", i.remote_host); + else if (i.remote_user) + printf("\t Remote: user %s\n", i.remote_user); + else if (i.remote) + printf("\t Remote: Yes\n"); + + if (i.service) { + printf("\t Service: %s", i.service); + + if (i.type) + printf("; type %s", i.type); + + if (i.class) + printf("; class %s", i.class); + + printf("\n"); + } else if (i.type) { + printf("\t Type: %s", i.type); + + if (i.class) + printf("; class %s", i.class); + + printf("\n"); + } else if (i.class) + printf("\t Class: %s\n", i.class); + + if (!isempty(i.desktop)) + printf("\t Desktop: %s\n", i.desktop); + + if (i.state) + printf("\t State: %s\n", i.state); + + if (i.scope) { + printf("\t Unit: %s\n", i.scope); + show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader); + } + + return 0; +} + +static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) { + + static const struct bus_properties_map map[] = { + { "Name", "s", NULL, offsetof(UserStatusInfo, name) }, + { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) }, + { "State", "s", NULL, offsetof(UserStatusInfo, state) }, + { "UID", "u", NULL, offsetof(UserStatusInfo, uid) }, + { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) }, + { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) }, + { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) }, + {} + }; + + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; + char since2[FORMAT_TIMESTAMP_MAX], *s2; + UserStatusInfo i = {}; + int r; + + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + if (r < 0) { + log_error("Could not get properties: %s", strerror(-r)); + goto finish; + } + + if (*new_line) + printf("\n"); + + *new_line = true; + + if (i.name) + printf("%s (%u)\n", i.name, (unsigned) i.uid); + else + printf("%u\n", (unsigned) i.uid); + + s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp); + s2 = format_timestamp(since2, sizeof(since2), i.timestamp); + + if (s1) + printf("\t Since: %s; %s\n", s2, s1); + else if (s2) + printf("\t Since: %s\n", s2); + + if (!isempty(i.state)) + printf("\t State: %s\n", i.state); + + if (!strv_isempty(i.sessions)) { + char **l; + printf("\tSessions:"); + + STRV_FOREACH(l, i.sessions) { + if (streq_ptr(*l, i.display)) + printf(" *%s", *l); + else + printf(" %s", *l); + } + + printf("\n"); + } + + if (i.slice) { + printf("\t Unit: %s\n", i.slice); + show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0); + } + +finish: + strv_free(i.sessions); + + return r; +} + +static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) { + + static const struct bus_properties_map map[] = { + { "Id", "s", NULL, offsetof(SeatStatusInfo, id) }, + { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) }, + { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) }, + {} + }; + + SeatStatusInfo i = {}; + int r; + + r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i); + if (r < 0) { + log_error("Could not get properties: %s", strerror(-r)); + goto finish; + } + + if (*new_line) + printf("\n"); + + *new_line = true; + + printf("%s\n", strna(i.id)); + + if (!strv_isempty(i.sessions)) { + char **l; + printf("\tSessions:"); + + STRV_FOREACH(l, i.sessions) { + if (streq_ptr(*l, i.active_session)) + printf(" *%s", *l); + else + printf(" %s", *l); + } + + printf("\n"); + } + + if (arg_transport == BUS_TRANSPORT_LOCAL) { + unsigned c; + + c = columns(); + if (c > 21) + c -= 21; + else + c = 0; + + printf("\t Devices:\n"); + + show_sysfs(i.id, "\t\t ", c); + } + +finish: + strv_free(i.sessions); + + return r; +} + +static int show_properties(sd_bus *bus, const char *path, bool *new_line) { + int r; + + if (*new_line) + printf("\n"); + + *new_line = true; + + r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all); + if (r < 0) + log_error("Could not get properties: %s", strerror(-r)); + + return r; +} + +static int show_session(sd_bus *bus, char **args, unsigned n) { + bool properties, new_line = false; + unsigned i; + int r; + + assert(bus); + assert(args); + + properties = !strstr(args[0], "status"); + + pager_open_if_enabled(); + + if (properties && n <= 1) { + /* If not argument is specified inspect the manager + * itself */ + return show_properties(bus, "/org/freedesktop/login1", &new_line); + } + + for (i = 1; i < n; i++) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + const char *path = NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "GetSession", + &error, &reply, + "s", args[i]); + if (r < 0) { + log_error("Failed to get session: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + if (properties) + r = show_properties(bus, path, &new_line); + else + r = print_session_status_info(bus, path, &new_line); + + if (r < 0) + return r; + } + + return 0; +} + +static int show_user(sd_bus *bus, char **args, unsigned n) { + bool properties, new_line = false; + unsigned i; + int r; + + assert(bus); + assert(args); + + properties = !strstr(args[0], "status"); + + pager_open_if_enabled(); + + if (properties && n <= 1) { + /* If not argument is specified inspect the manager + * itself */ + return show_properties(bus, "/org/freedesktop/login1", &new_line); + } + + for (i = 1; i < n; i++) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + const char *path = NULL; + uid_t uid; + + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "GetUser", + &error, &reply, + "u", (uint32_t) uid); + if (r < 0) { + log_error("Failed to get user: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + if (properties) + r = show_properties(bus, path, &new_line); + else + r = print_user_status_info(bus, path, &new_line); + + if (r < 0) + return r; + } + + return 0; +} + +static int show_seat(sd_bus *bus, char **args, unsigned n) { + bool properties, new_line = false; + unsigned i; + int r; + + assert(bus); + assert(args); + + properties = !strstr(args[0], "status"); + + pager_open_if_enabled(); + + if (properties && n <= 1) { + /* If not argument is specified inspect the manager + * itself */ + return show_properties(bus, "/org/freedesktop/login1", &new_line); + } + + for (i = 1; i < n; i++) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + const char *path = NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "GetSeat", + &error, &reply, + "s", args[i]); + if (r < 0) { + log_error("Failed to get seat: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + if (properties) + r = show_properties(bus, path, &new_line); + else + r = print_seat_status_info(bus, path, &new_line); + + if (r < 0) + return r; + } + + return 0; +} + +static int activate(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + for (i = 1; i < n; i++) { + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + streq(args[0], "lock-session") ? "LockSession" : + streq(args[0], "unlock-session") ? "UnlockSession" : + streq(args[0], "terminate-session") ? "TerminateSession" : + "ActivateSession", + &error, NULL, + "s", args[i]); + if (r < 0) { + log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int kill_session(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + if (!arg_kill_who) + arg_kill_who = "all"; + + for (i = 1; i < n; i++) { + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "KillSession", + &error, NULL, + "ssi", args[i], arg_kill_who, arg_signal); + if (r < 0) { + log_error("Could not kill session: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int enable_linger(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + bool b; + int r; + + assert(args); + + polkit_agent_open_if_enabled(); + + b = streq(args[0], "enable-linger"); + + for (i = 1; i < n; i++) { + uid_t uid; + + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; + } + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "SetUserLinger", + &error, NULL, + "ubb", (uint32_t) uid, b, true); + if (r < 0) { + log_error("Could not enable linger: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int terminate_user(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + for (i = 1; i < n; i++) { + uid_t uid; + + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; + } + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "TerminateUser", + &error, NULL, + "u", (uint32_t) uid); + if (r < 0) { + log_error("Could not terminate user: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int kill_user(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + if (!arg_kill_who) + arg_kill_who = "all"; + + for (i = 1; i < n; i++) { + uid_t uid; + + r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to look up user %s: %s", args[i], strerror(-r)); + return r; + } + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "KillUser", + &error, NULL, + "ui", (uint32_t) uid, arg_signal); + if (r < 0) { + log_error("Could not kill user: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int attach(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + polkit_agent_open_if_enabled(); + + for (i = 2; i < n; i++) { + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "AttachDevice", + &error, NULL, + "ssb", args[1], args[i], true); + + if (r < 0) { + log_error("Could not attach device: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int flush_devices(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(args); + + polkit_agent_open_if_enabled(); + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "FlushDevices", + &error, NULL, + "b", true); + if (r < 0) + log_error("Could not flush devices: %s", bus_error_message(&error, -r)); + + return r; +} + +static int lock_sessions(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(args); + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions", + &error, NULL, + NULL); + if (r < 0) + log_error("Could not lock sessions: %s", bus_error_message(&error, -r)); + + return r; +} + +static int terminate_seat(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + for (i = 1; i < n; i++) { + + r = sd_bus_call_method ( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "TerminateSeat", + &error, NULL, + "s", args[i]); + if (r < 0) { + log_error("Could not terminate seat: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Send control commands to or query the login manager.\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" + " --no-ask-password Don't prompt for password\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " -p --property=NAME Show only properties by this name\n" + " -a --all Show all properties, including empty ones\n" + " -l --full Do not ellipsize output\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n\n" + "Commands:\n" + " list-sessions List sessions\n" + " session-status ID... Show session status\n" + " show-session [ID...] Show properties of sessions or the manager\n" + " activate ID Activate a session\n" + " lock-session ID... Screen lock one or more sessions\n" + " unlock-session ID... Screen unlock one or more sessions\n" + " lock-sessions Screen lock all current sessions\n" + " unlock-sessions Screen unlock all current sessions\n" + " terminate-session ID... Terminate one or more sessions\n" + " kill-session ID... Send signal to processes of a session\n" + " list-users List users\n" + " user-status USER... Show user status\n" + " show-user [USER...] Show properties of users or the manager\n" + " enable-linger USER... Enable linger state of one or more users\n" + " disable-linger USER... Disable linger state of one or more users\n" + " terminate-user USER... Terminate all sessions of one or more users\n" + " kill-user USER... Send signal to processes of a user\n" + " list-seats List seats\n" + " seat-status NAME... Show seat status\n" + " show-seat NAME... Show properties of one or more seats\n" + " attach NAME DEVICE... Attach one or more devices to a seat\n" + " flush-devices Flush all device associations\n" + " terminate-seat NAME... Terminate all sessions on one or more seats\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, + ARG_KILL_WHO, + ARG_NO_ASK_PASSWORD, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "property", required_argument, NULL, 'p' }, + { "all", no_argument, NULL, 'a' }, + { "full", no_argument, NULL, 'l' }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "kill-who", required_argument, NULL, ARG_KILL_WHO }, + { "signal", required_argument, NULL, 's' }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'p': { + r = strv_extend(&arg_property, optarg); + if (r < 0) + return log_oom(); + + /* If the user asked for a particular + * property, show it to him, even if it is + * empty. */ + arg_all = true; + break; + } + + case 'a': + arg_all = true; + break; + + case 'l': + arg_full = true; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + case ARG_KILL_WHO: + arg_kill_who = optarg; + break; + + case 's': + arg_signal = signal_from_string_try_harder(optarg); + if (arg_signal < 0) { + log_error("Failed to parse signal string %s.", optarg); + return -EINVAL; + } + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int loginctl_main(sd_bus *bus, int argc, char *argv[]) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args, unsigned n); + } verbs[] = { + { "list-sessions", LESS, 1, list_sessions }, + { "session-status", MORE, 2, show_session }, + { "show-session", MORE, 1, show_session }, + { "activate", EQUAL, 2, activate }, + { "lock-session", MORE, 2, activate }, + { "unlock-session", MORE, 2, activate }, + { "lock-sessions", EQUAL, 1, lock_sessions }, + { "unlock-sessions", EQUAL, 1, lock_sessions }, + { "terminate-session", MORE, 2, activate }, + { "kill-session", MORE, 2, kill_session }, + { "list-users", EQUAL, 1, list_users }, + { "user-status", MORE, 2, show_user }, + { "show-user", MORE, 1, show_user }, + { "enable-linger", MORE, 2, enable_linger }, + { "disable-linger", MORE, 2, enable_linger }, + { "terminate-user", MORE, 2, terminate_user }, + { "kill-user", MORE, 2, kill_user }, + { "list-seats", EQUAL, 1, list_seats }, + { "seat-status", MORE, 2, show_seat }, + { "show-seat", MORE, 1, show_seat }, + { "attach", MORE, 3, attach }, + { "flush-devices", EQUAL, 1, flush_devices }, + { "terminate-seat", MORE, 2, terminate_seat }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "list-sessions" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(bus, argv + optind, left); +} + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, false, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + r = loginctl_main(bus, argc, argv); + +finish: + pager_close(); + + strv_free(arg_property); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c new file mode 100644 index 0000000..dc86f0f --- /dev/null +++ b/src/login/logind-acl.c @@ -0,0 +1,287 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "acl-util.h" +#include "set.h" +#include "logind-acl.h" +#include "udev-util.h" + +static int flush_acl(acl_t acl) { + acl_entry_t i; + int found; + bool changed = false; + + assert(acl); + + for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + found > 0; + found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + + acl_tag_t tag; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (tag != ACL_USER) + continue; + + if (acl_delete_entry(acl, i) < 0) + return -errno; + + changed = true; + } + + if (found < 0) + return -errno; + + return changed; +} + +int devnode_acl(const char *path, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid) { + + acl_t acl; + int r = 0; + bool changed = false; + + assert(path); + + acl = acl_get_file(path, ACL_TYPE_ACCESS); + if (!acl) + return -errno; + + if (flush) { + + r = flush_acl(acl); + if (r < 0) + goto finish; + if (r > 0) + changed = true; + + } else if (del && old_uid > 0) { + acl_entry_t entry; + + r = acl_find_uid(acl, old_uid, &entry); + if (r < 0) + goto finish; + + if (r > 0) { + if (acl_delete_entry(acl, entry) < 0) { + r = -errno; + goto finish; + } + + changed = true; + } + } + + if (add && new_uid > 0) { + acl_entry_t entry; + acl_permset_t permset; + int rd, wt; + + r = acl_find_uid(acl, new_uid, &entry); + if (r < 0) + goto finish; + + if (r == 0) { + if (acl_create_entry(&acl, &entry) < 0) { + r = -errno; + goto finish; + } + + if (acl_set_tag_type(entry, ACL_USER) < 0 || + acl_set_qualifier(entry, &new_uid) < 0) { + r = -errno; + goto finish; + } + } + + if (acl_get_permset(entry, &permset) < 0) { + r = -errno; + goto finish; + } + + rd = acl_get_perm(permset, ACL_READ); + if (rd < 0) { + r = -errno; + goto finish; + } + + wt = acl_get_perm(permset, ACL_WRITE); + if (wt < 0) { + r = -errno; + goto finish; + } + + if (!rd || !wt) { + + if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) { + r = -errno; + goto finish; + } + + changed = true; + } + } + + if (!changed) + goto finish; + + if (acl_calc_mask(&acl) < 0) { + r = -errno; + goto finish; + } + + if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) { + r = -errno; + goto finish; + } + + r = 0; + +finish: + acl_free(acl); + + return r; +} + +int devnode_acl_all(struct udev *udev, + const char *seat, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid) { + + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_set_free_free_ Set *nodes = NULL; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *dent; + Iterator i; + char *n; + int r; + + assert(udev); + + nodes = set_new(string_hash_func, string_compare_func); + if (!nodes) + return -ENOMEM; + + e = udev_enumerate_new(udev); + if (!e) + return -ENOMEM; + + if (isempty(seat)) + seat = "seat0"; + + /* We can only match by one tag in libudev. We choose + * "uaccess" for that. If we could match for two tags here we + * could add the seat name as second match tag, but this would + * be hardly optimizable in libudev, and hence checking the + * second tag manually in our loop is a good solution. */ + r = udev_enumerate_add_match_tag(e, "uaccess"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + const char *node, *sn; + + d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(sn)) + sn = "seat0"; + + if (!streq(seat, sn)) + continue; + + node = udev_device_get_devnode(d); + /* In case people mistag devices with nodes, we need to ignore this */ + if (!node) + continue; + + n = strdup(node); + if (!n) + return -ENOMEM; + + log_debug("Found udev node %s for seat %s", n, seat); + r = set_consume(nodes, n); + if (r < 0) + return r; + } + + /* udev exports "dead" device nodes to allow module on-demand loading, + * these devices are not known to the kernel at this moment */ + dir = opendir("/run/udev/static_node-tags/uaccess"); + if (dir) { + FOREACH_DIRENT(dent, dir, return -errno) { + _cleanup_free_ char *unescaped_devname = NULL; + + unescaped_devname = cunescape(dent->d_name); + if (!unescaped_devname) + return -ENOMEM; + + n = strappend("/dev/", unescaped_devname); + if (!n) + return -ENOMEM; + + log_debug("Found static node %s for seat %s", n, seat); + r = set_consume(nodes, n); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + } + + r = 0; + SET_FOREACH(n, nodes, i) { + int k; + + log_debug("Fixing up ACLs at %s for seat %s", n, seat); + k = devnode_acl(n, flush, del, old_uid, add, new_uid); + if (k < 0) + r = k; + } + + return r; +} diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h new file mode 100644 index 0000000..ec09843 --- /dev/null +++ b/src/login/logind-acl.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#ifdef HAVE_ACL + +int devnode_acl(const char *path, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid); + +int devnode_acl_all(struct udev *udev, + const char *seat, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid); +#else + +static inline int devnode_acl(const char *path, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid) { + return 0; +} + +static inline int devnode_acl_all(struct udev *udev, + const char *seat, + bool flush, + bool del, uid_t old_uid, + bool add, uid_t new_uid) { + return 0; +} + +#endif diff --git a/src/login/logind-action.c b/src/login/logind-action.c new file mode 100644 index 0000000..c04f210 --- /dev/null +++ b/src/login/logind-action.c @@ -0,0 +1,173 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "sd-messages.h" +#include "conf-parser.h" +#include "special.h" +#include "sleep-config.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind-action.h" + +int manager_handle_action( + Manager *m, + InhibitWhat inhibit_key, + HandleAction handle, + bool ignore_inhibited, + bool is_edge) { + + static const char * const message_table[_HANDLE_ACTION_MAX] = { + [HANDLE_POWEROFF] = "Powering Off...", + [HANDLE_REBOOT] = "Rebooting...", + [HANDLE_HALT] = "Halting...", + [HANDLE_KEXEC] = "Rebooting via kexec...", + [HANDLE_SUSPEND] = "Suspending...", + [HANDLE_HIBERNATE] = "Hibernating...", + [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending..." + }; + + static const char * const target_table[_HANDLE_ACTION_MAX] = { + [HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET, + [HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET, + [HANDLE_HALT] = SPECIAL_HALT_TARGET, + [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET, + [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET, + [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, + [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET + }; + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + InhibitWhat inhibit_operation; + Inhibitor *offending = NULL; + bool supported; + int r; + + assert(m); + + /* If the key handling is turned off, don't do anything */ + if (handle == HANDLE_IGNORE) { + log_debug("Refusing operation, as it is turned off."); + return 0; + } + + /* If we are docked don't react to lid closing */ + if (inhibit_key == INHIBIT_HANDLE_LID_SWITCH) { + if (manager_is_docked(m)) { + log_debug("Ignoring lid switch request, system is docked."); + return 0; + } + } + + /* If the key handling is inhibited, don't do anything */ + if (inhibit_key > 0) { + if (manager_is_inhibited(m, inhibit_key, INHIBIT_BLOCK, NULL, true, false, 0, NULL)) { + log_debug("Refusing operation, %s is inhibited.", inhibit_what_to_string(inhibit_key)); + return 0; + } + } + + /* Locking is handled differently from the rest. */ + if (handle == HANDLE_LOCK) { + + if (!is_edge) + return 0; + + log_info("Locking sessions..."); + session_send_lock_all(m, true); + return 1; + } + + if (handle == HANDLE_SUSPEND) + supported = can_sleep("suspend") > 0; + else if (handle == HANDLE_HIBERNATE) + supported = can_sleep("hibernate") > 0; + else if (handle == HANDLE_HYBRID_SLEEP) + supported = can_sleep("hybrid-sleep") > 0; + else if (handle == HANDLE_KEXEC) + supported = access(KEXEC, X_OK) >= 0; + else + supported = true; + + if (!supported) { + log_warning("Requested operation not supported, ignoring."); + return -ENOTSUP; + } + + if (m->action_what) { + log_debug("Action already in progress, ignoring."); + return -EALREADY; + } + + inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE || handle == HANDLE_HYBRID_SLEEP ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; + + /* If the actual operation is inhibited, warn and fail */ + if (!ignore_inhibited && + manager_is_inhibited(m, inhibit_operation, INHIBIT_BLOCK, NULL, false, false, 0, &offending)) { + _cleanup_free_ char *comm = NULL, *u = NULL; + + get_process_comm(offending->pid, &comm); + u = uid_to_name(offending->uid); + + /* If this is just a recheck of the lid switch then don't warn about anything */ + if (!is_edge) { + log_debug("Refusing operation, %s is inhibited by UID %lu/%s, PID %lu/%s.", + inhibit_what_to_string(inhibit_operation), + (unsigned long) offending->uid, strna(u), + (unsigned long) offending->pid, strna(comm)); + return 0; + } + + log_error("Refusing operation, %s is inhibited by UID %lu/%s, PID %lu/%s.", + inhibit_what_to_string(inhibit_operation), + (unsigned long) offending->uid, strna(u), + (unsigned long) offending->pid, strna(comm)); + + warn_melody(); + return -EPERM; + } + + log_info("%s", message_table[handle]); + + r = bus_manager_shutdown_or_sleep_now_or_later(m, target_table[handle], inhibit_operation, &error); + if (r < 0) { + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + return r; + } + + return 1; +} + +static const char* const handle_action_table[_HANDLE_ACTION_MAX] = { + [HANDLE_IGNORE] = "ignore", + [HANDLE_POWEROFF] = "poweroff", + [HANDLE_REBOOT] = "reboot", + [HANDLE_HALT] = "halt", + [HANDLE_KEXEC] = "kexec", + [HANDLE_SUSPEND] = "suspend", + [HANDLE_HIBERNATE] = "hibernate", + [HANDLE_HYBRID_SLEEP] = "hybrid-sleep", + [HANDLE_LOCK] = "lock" +}; + +DEFINE_STRING_TABLE_LOOKUP(handle_action, HandleAction); +DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_action, handle_action, HandleAction, "Failed to parse handle action setting"); diff --git a/src/login/logind-action.h b/src/login/logind-action.h new file mode 100644 index 0000000..e9b424b --- /dev/null +++ b/src/login/logind-action.h @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef enum HandleAction { + HANDLE_IGNORE, + HANDLE_POWEROFF, + HANDLE_REBOOT, + HANDLE_HALT, + HANDLE_KEXEC, + HANDLE_SUSPEND, + HANDLE_HIBERNATE, + HANDLE_HYBRID_SLEEP, + HANDLE_LOCK, + _HANDLE_ACTION_MAX, + _HANDLE_ACTION_INVALID = -1 +} HandleAction; + +#include "logind.h" +#include "logind-inhibit.h" + +int manager_handle_action( + Manager *m, + InhibitWhat inhibit_key, + HandleAction handle, + bool ignore_inhibited, + bool is_edge); + +const char* handle_action_to_string(HandleAction h) _const_; +HandleAction handle_action_from_string(const char *s) _pure_; + +int config_parse_handle_action(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/login/logind-button.c b/src/login/logind-button.c new file mode 100644 index 0000000..060978d --- /dev/null +++ b/src/login/logind-button.c @@ -0,0 +1,283 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-messages.h" +#include "conf-parser.h" +#include "util.h" +#include "special.h" +#include "logind-button.h" + +Button* button_new(Manager *m, const char *name) { + Button *b; + + assert(m); + assert(name); + + b = new0(Button, 1); + if (!b) + return NULL; + + b->name = strdup(name); + if (!b->name) { + free(b); + return NULL; + } + + if (hashmap_put(m->buttons, b->name, b) < 0) { + free(b->name); + free(b); + return NULL; + } + + b->manager = m; + b->fd = -1; + + return b; +} + +void button_free(Button *b) { + assert(b); + + hashmap_remove(b->manager->buttons, b->name); + + sd_event_source_unref(b->io_event_source); + sd_event_source_unref(b->check_event_source); + + if (b->fd >= 0) { + /* If the device has been unplugged close() returns + * ENODEV, let's ignore this, hence we don't use + * close_nointr_nofail() */ + close(b->fd); + } + + free(b->name); + free(b->seat); + free(b); +} + +int button_set_seat(Button *b, const char *sn) { + char *s; + + assert(b); + assert(sn); + + s = strdup(sn); + if (!s) + return -ENOMEM; + + free(b->seat); + b->seat = s; + + return 0; +} + +static int button_recheck(sd_event_source *e, void *userdata) { + Button *b = userdata; + + assert(b); + assert(b->lid_closed); + + manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, false); + return 1; +} + +static int button_install_check_event_source(Button *b) { + int r; + assert(b); + + /* Install a post handler, so that we keep rechecking as long as the lid is closed. */ + + if (b->check_event_source) + return 0; + + r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b); + if (r < 0) + return r; + + return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1); +} + +static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Button *b = userdata; + struct input_event ev; + ssize_t l; + + assert(s); + assert(fd == b->fd); + assert(b); + + l = read(b->fd, &ev, sizeof(ev)); + if (l < 0) + return errno != EAGAIN ? -errno : 0; + if ((size_t) l < sizeof(ev)) + return -EIO; + + if (ev.type == EV_KEY && ev.value > 0) { + + switch (ev.code) { + + case KEY_POWER: + case KEY_POWER2: + log_struct(LOG_INFO, + "MESSAGE=Power key pressed.", + MESSAGE_ID(SD_MESSAGE_POWER_KEY), + NULL); + + manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true); + break; + + /* The kernel is a bit confused here: + + KEY_SLEEP = suspend-to-ram, which everybody else calls "suspend" + KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate" + */ + + case KEY_SLEEP: + log_struct(LOG_INFO, + "MESSAGE=Suspend key pressed.", + MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY), + NULL); + + manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true); + break; + + case KEY_SUSPEND: + log_struct(LOG_INFO, + "MESSAGE=Hibernate key pressed.", + MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY), + NULL); + + manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true); + break; + } + + } else if (ev.type == EV_SW && ev.value > 0) { + + if (ev.code == SW_LID) { + log_struct(LOG_INFO, + "MESSAGE=Lid closed.", + MESSAGE_ID(SD_MESSAGE_LID_CLOSED), + NULL); + + b->lid_closed = true; + manager_handle_action(b->manager, INHIBIT_HANDLE_LID_SWITCH, b->manager->handle_lid_switch, b->manager->lid_switch_ignore_inhibited, true); + button_install_check_event_source(b); + + } else if (ev.code == SW_DOCK) { + log_struct(LOG_INFO, + "MESSAGE=System docked.", + MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED), + NULL); + + b->docked = true; + } + + } else if (ev.type == EV_SW && ev.value == 0) { + + if (ev.code == SW_LID) { + log_struct(LOG_INFO, + "MESSAGE=Lid opened.", + MESSAGE_ID(SD_MESSAGE_LID_OPENED), + NULL); + + b->lid_closed = false; + b->check_event_source = sd_event_source_unref(b->check_event_source); + + } else if (ev.code == SW_DOCK) { + log_struct(LOG_INFO, + "MESSAGE=System undocked.", + MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED), + NULL); + + b->docked = false; + } + } + + return 0; +} + +int button_open(Button *b) { + char *p, name[256]; + int r; + + assert(b); + + if (b->fd >= 0) { + close(b->fd); + b->fd = -1; + } + + p = strappenda("/dev/input/", b->name); + + b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (b->fd < 0) { + log_warning("Failed to open %s: %m", b->name); + return -errno; + } + + if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) { + log_error("Failed to get input name: %m"); + r = -errno; + goto fail; + } + + r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b); + if (r < 0) { + log_error("Failed to add button event: %s", strerror(-r)); + goto fail; + } + + log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name); + + return 0; + +fail: + close(b->fd); + b->fd = -1; + return r; +} + +int button_check_switches(Button *b) { + uint8_t switches[SW_MAX/8+1] = {}; + assert(b); + + if (b->fd < 0) + return -EINVAL; + + if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0) + return -errno; + + b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1; + b->docked = (switches[SW_DOCK/8] >> (SW_DOCK % 8)) & 1; + + if (b->lid_closed) + button_install_check_event_source(b); + + return 0; +} diff --git a/src/login/logind-button.h b/src/login/logind-button.h new file mode 100644 index 0000000..72a612e --- /dev/null +++ b/src/login/logind-button.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Button Button; + +#include "list.h" +#include "util.h" +#include "logind.h" + +struct Button { + Manager *manager; + + sd_event_source *io_event_source; + sd_event_source *check_event_source; + + char *name; + char *seat; + int fd; + + bool lid_closed; + bool docked; +}; + +Button* button_new(Manager *m, const char *name); +void button_free(Button*b); +int button_open(Button *b); +int button_set_seat(Button *b, const char *sn); +int button_check_switches(Button *b); diff --git a/src/login/logind-core.c b/src/login/logind-core.c new file mode 100644 index 0000000..e4e593f --- /dev/null +++ b/src/login/logind-core.c @@ -0,0 +1,516 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "strv.h" +#include "cgroup-util.h" +#include "audit.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind.h" + +int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) { + Device *d; + + assert(m); + assert(sysfs); + + d = hashmap_get(m->devices, sysfs); + if (d) { + if (_device) + *_device = d; + + /* we support adding master-flags, but not removing them */ + d->master = d->master || master; + + return 0; + } + + d = device_new(m, sysfs, master); + if (!d) + return -ENOMEM; + + if (_device) + *_device = d; + + return 0; +} + +int manager_add_seat(Manager *m, const char *id, Seat **_seat) { + Seat *s; + + assert(m); + assert(id); + + s = hashmap_get(m->seats, id); + if (s) { + if (_seat) + *_seat = s; + + return 0; + } + + s = seat_new(m, id); + if (!s) + return -ENOMEM; + + if (_seat) + *_seat = s; + + return 0; +} + +int manager_add_session(Manager *m, const char *id, Session **_session) { + Session *s; + + assert(m); + assert(id); + + s = hashmap_get(m->sessions, id); + if (s) { + if (_session) + *_session = s; + + return 0; + } + + s = session_new(m, id); + if (!s) + return -ENOMEM; + + if (_session) + *_session = s; + + return 0; +} + +int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) { + User *u; + + assert(m); + assert(name); + + u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (u) { + if (_user) + *_user = u; + + return 0; + } + + u = user_new(m, uid, gid, name); + if (!u) + return -ENOMEM; + + if (_user) + *_user = u; + + return 0; +} + +int manager_add_user_by_name(Manager *m, const char *name, User **_user) { + uid_t uid; + gid_t gid; + int r; + + assert(m); + assert(name); + + r = get_user_creds(&name, &uid, &gid, NULL, NULL); + if (r < 0) + return r; + + return manager_add_user(m, uid, gid, name, _user); +} + +int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { + struct passwd *p; + + assert(m); + + errno = 0; + p = getpwuid(uid); + if (!p) + return errno ? -errno : -ENOENT; + + return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user); +} + +int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) { + Inhibitor *i; + + assert(m); + assert(id); + + i = hashmap_get(m->inhibitors, id); + if (i) { + if (_inhibitor) + *_inhibitor = i; + + return 0; + } + + i = inhibitor_new(m, id); + if (!i) + return -ENOMEM; + + if (_inhibitor) + *_inhibitor = i; + + return 0; +} + +int manager_add_button(Manager *m, const char *name, Button **_button) { + Button *b; + + assert(m); + assert(name); + + b = hashmap_get(m->buttons, name); + if (b) { + if (_button) + *_button = b; + + return 0; + } + + b = button_new(m, name); + if (!b) + return -ENOMEM; + + if (_button) + *_button = b; + + return 0; +} + +int manager_watch_busname(Manager *m, const char *name) { + char *n; + int r; + + assert(m); + assert(name); + + if (set_get(m->busnames, (char*) name)) + return 0; + + n = strdup(name); + if (!n) + return -ENOMEM; + + r = set_put(m->busnames, n); + if (r < 0) { + free(n); + return r; + } + + return 0; +} + +void manager_drop_busname(Manager *m, const char *name) { + Session *session; + Iterator i; + + assert(m); + assert(name); + + /* keep it if the name still owns a controller */ + HASHMAP_FOREACH(session, m->sessions, i) + if (session_is_controller(session, name)) + return; + + free(set_remove(m->busnames, (char*) name)); +} + +int manager_process_seat_device(Manager *m, struct udev_device *d) { + Device *device; + int r; + + assert(m); + + if (streq_ptr(udev_device_get_action(d), "remove")) { + + device = hashmap_get(m->devices, udev_device_get_syspath(d)); + if (!device) + return 0; + + seat_add_to_gc_queue(device->seat); + device_free(device); + + } else { + const char *sn; + Seat *seat = NULL; + bool master; + + sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(sn)) + sn = "seat0"; + + if (!seat_name_is_valid(sn)) { + log_warning("Device with invalid seat name %s found, ignoring.", sn); + return 0; + } + + /* ignore non-master devices for unknown seats */ + master = udev_device_has_tag(d, "master-of-seat"); + if (!master && !(seat = hashmap_get(m->seats, sn))) + return 0; + + r = manager_add_device(m, udev_device_get_syspath(d), master, &device); + if (r < 0) + return r; + + if (!seat) { + r = manager_add_seat(m, sn, &seat); + if (r < 0) { + if (!device->seat) + device_free(device); + + return r; + } + } + + device_attach(device, seat); + seat_start(seat); + } + + return 0; +} + +int manager_process_button_device(Manager *m, struct udev_device *d) { + Button *b; + + int r; + + assert(m); + + if (streq_ptr(udev_device_get_action(d), "remove")) { + + b = hashmap_get(m->buttons, udev_device_get_sysname(d)); + if (!b) + return 0; + + button_free(b); + + } else { + const char *sn; + + r = manager_add_button(m, udev_device_get_sysname(d), &b); + if (r < 0) + return r; + + sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(sn)) + sn = "seat0"; + + button_set_seat(b, sn); + button_open(b); + } + + return 0; +} + +int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { + _cleanup_free_ char *unit = NULL; + Session *s; + int r; + + assert(m); + assert(session); + + if (pid < 1) + return -EINVAL; + + r = cg_pid_get_unit(pid, &unit); + if (r < 0) + return 0; + + s = hashmap_get(m->session_units, unit); + if (!s) + return 0; + + *session = s; + return 1; +} + +int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) { + _cleanup_free_ char *unit = NULL; + User *u; + int r; + + assert(m); + assert(user); + + if (pid < 1) + return -EINVAL; + + r = cg_pid_get_slice(pid, &unit); + if (r < 0) + return 0; + + u = hashmap_get(m->user_units, unit); + if (!u) + return 0; + + *user = u; + return 1; +} + +int manager_get_idle_hint(Manager *m, dual_timestamp *t) { + Session *s; + bool idle_hint; + dual_timestamp ts = { 0, 0 }; + Iterator i; + + assert(m); + + idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL); + + HASHMAP_FOREACH(s, m->sessions, i) { + dual_timestamp k; + int ih; + + ih = session_get_idle_hint(s, &k); + if (ih < 0) + return ih; + + if (!ih) { + if (!idle_hint) { + if (k.monotonic < ts.monotonic) + ts = k; + } else { + idle_hint = false; + ts = k; + } + } else if (idle_hint) { + + if (k.monotonic > ts.monotonic) + ts = k; + } + } + + if (t) + *t = ts; + + return idle_hint; +} + +bool manager_shall_kill(Manager *m, const char *user) { + assert(m); + assert(user); + + if (!m->kill_user_processes) + return false; + + if (strv_contains(m->kill_exclude_users, user)) + return false; + + if (strv_isempty(m->kill_only_users)) + return true; + + return strv_contains(m->kill_only_users, user); +} + +static int vt_is_busy(unsigned int vtnr) { + struct vt_stat vt_stat; + int r = 0, fd; + + assert(vtnr >= 1); + + /* We explicitly open /dev/tty1 here instead of /dev/tty0. If + * we'd open the latter we'd open the foreground tty which + * hence would be unconditionally busy. By opening /dev/tty1 + * we avoid this. Since tty1 is special and needs to be an + * explicitly loaded getty or DM this is safe. */ + + fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0) + r = -errno; + else + r = !!(vt_stat.v_state & (1 << vtnr)); + + close_nointr_nofail(fd); + + return r; +} + +int manager_spawn_autovt(Manager *m, unsigned int vtnr) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *name = NULL; + int r; + + assert(m); + assert(vtnr >= 1); + + if (vtnr > m->n_autovts && + vtnr != m->reserve_vt) + return 0; + + if (vtnr != m->reserve_vt) { + /* If this is the reserved TTY, we'll start the getty + * on it in any case, but otherwise only if it is not + * busy. */ + + r = vt_is_busy(vtnr); + if (r < 0) + return r; + else if (r > 0) + return -EBUSY; + } + + if (asprintf(&name, "autovt@tty%u.service", vtnr) < 0) + return log_oom(); + + r = sd_bus_call_method( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + &error, + NULL, + "ss", name, "fail"); + if (r < 0) + log_error("Failed to start %s: %s", name, bus_error_message(&error, r)); + + return r; +} + +bool manager_is_docked(Manager *m) { + Iterator i; + Button *b; + + HASHMAP_FOREACH(b, m->buttons, i) + if (b->docked) + return true; + + return false; +} diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c new file mode 100644 index 0000000..fc89531 --- /dev/null +++ b/src/login/logind-dbus.c @@ -0,0 +1,2492 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "strv.h" +#include "mkdir.h" +#include "path-util.h" +#include "special.h" +#include "sleep-config.h" +#include "fileio-label.h" +#include "label.h" +#include "utf8.h" +#include "unit-name.h" +#include "virt.h" +#include "audit.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind.h" +#include "bus-errors.h" +#include "udev-util.h" + +static int property_get_idle_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0); +} + +static int property_get_idle_since_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + dual_timestamp t; + + assert(bus); + assert(reply); + assert(m); + + manager_get_idle_hint(m, &t); + + return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic); +} + +static int property_get_inhibited( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + InhibitWhat w; + + assert(bus); + assert(reply); + assert(m); + + w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY); + + return sd_bus_message_append(reply, "s", inhibit_what_to_string(w)); +} + +static int property_get_preparing( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + bool b; + + assert(bus); + assert(reply); + assert(m); + + if (streq(property, "PreparingForShutdown")) + b = !!(m->action_what & INHIBIT_SHUTDOWN); + else + b = !!(m->action_what & INHIBIT_SLEEP); + + return sd_bus_message_append(reply, "b", b); +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction); + +static int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + const char *name; + Session *session; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Session *session = NULL; + Manager *m = userdata; + pid_t pid; + int r; + + assert(bus); + assert(message); + assert(m); + + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + + r = sd_bus_message_read(message, "u", &pid); + if (r < 0) + return r; + + if (pid == 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + } + + r = manager_get_session_by_pid(m, pid, &session); + if (r < 0) + return r; + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID %lu does not belong to any known session", (unsigned long) pid); + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + uint32_t uid; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "u", &uid); + if (r < 0) + return r; + + user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (!user) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid); + + p = user_bus_path(user); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + User *user = NULL; + pid_t pid; + int r; + + assert(bus); + assert(message); + assert(m); + + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + + r = sd_bus_message_read(message, "u", &pid); + if (r < 0) + return r; + + if (pid == 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + } + + r = manager_get_user_by_pid(m, pid, &user); + if (r < 0) + return r; + if (!user) + return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "PID %lu does not belong to any known or logged in user", (unsigned long) pid); + + p = user_bus_path(user); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + const char *name; + Seat *seat; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + seat = hashmap_get(m->seats, name); + if (!seat) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name); + + p = seat_bus_path(seat); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Session *session; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(susso)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(session, m->sessions, i) { + _cleanup_free_ char *p = NULL; + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(susso)", + session->id, + (uint32_t) session->user->uid, + session->user->name, + session->seat ? session->seat->id : "", + p); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + User *user; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(uso)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(user, m->users, i) { + _cleanup_free_ char *p = NULL; + + p = user_bus_path(user); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(uso)", + (uint32_t) user->uid, + user->name, + p); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Seat *seat; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(so)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(seat, m->seats, i) { + _cleanup_free_ char *p = NULL; + + p = seat_bus_path(seat); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(so)", seat->id, p); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Inhibitor *inhibitor; + Iterator i; + int r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(ssssuu)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(inhibitor, m->inhibitors, i) { + + r = sd_bus_message_append(reply, "(ssssuu)", + strempty(inhibit_what_to_string(inhibitor->what)), + strempty(inhibitor->who), + strempty(inhibitor->why), + strempty(inhibit_mode_to_string(inhibitor->mode)), + (uint32_t) inhibitor->uid, + (uint32_t) inhibitor->pid); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(bus, reply, NULL); +} + +static int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop; + uint32_t uid, leader, audit_id = 0; + _cleanup_free_ char *id = NULL; + Session *session = NULL; + Manager *m = userdata; + User *user = NULL; + Seat *seat = NULL; + int remote; + uint32_t vtnr = 0; + SessionType t; + SessionClass c; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host); + if (r < 0) + return r; + + if (leader == 1) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); + + if (isempty(type)) + t = _SESSION_TYPE_INVALID; + 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); + } + + if (isempty(class)) + c = _SESSION_CLASS_INVALID; + 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); + } + + 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); + } + + if (isempty(cseat)) + seat = NULL; + 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); + } + + if (tty_is_vc(tty)) { + int v; + + 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); + + 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); + + if (!vtnr) + 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"); + + } 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"); + + if (vtnr != 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 || vtnr > 63) + 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"); + } + } + + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) + return r; + + if (t == _SESSION_TYPE_INVALID) { + if (!isempty(display)) + t = SESSION_X11; + else if (!isempty(tty)) + t = SESSION_TTY; + else + t = SESSION_UNSPECIFIED; + } + + if (c == _SESSION_CLASS_INVALID) { + if (t == SESSION_UNSPECIFIED) + c = SESSION_BACKGROUND; + else + c = SESSION_USER; + } + + if (leader <= 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + assert_cc(sizeof(uint32_t) == sizeof(pid_t)); + + r = sd_bus_creds_get_pid(creds, (pid_t*) &leader); + if (r < 0) + return r; + } + + manager_get_session_by_pid(m, leader, &session); + if (session) { + _cleanup_free_ char *path = NULL; + _cleanup_close_ int fifo_fd = -1; + + /* Session already exists, client is probably + * something like "su" which changes uid but is still + * the same session */ + + fifo_fd = session_create_fifo(session); + if (fifo_fd < 0) + return fifo_fd; + + path = session_bus_path(session); + if (!path) + return -ENOMEM; + + return sd_bus_reply_method_return( + message, "soshusub", + session->id, + path, + session->user->runtime_path, + fifo_fd, + (uint32_t) session->user->uid, + session->seat ? session->seat->id : "", + (uint32_t) session->vtnr, + true); + } + + audit_session_from_pid(leader, &audit_id); + if (audit_id > 0) { + /* Keep our session IDs and the audit session IDs in sync */ + + if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) + return -ENOMEM; + + /* Wut? There's already a session by this name and we + * didn't find it above? Weird, then let's not trust + * the audit data and let's better register a new + * ID */ + if (hashmap_get(m->sessions, id)) { + log_warning("Existing logind session ID %s used by new audit session, ignoring", id); + audit_id = 0; + + free(id); + id = NULL; + } + } + + if (!id) { + do { + free(id); + id = NULL; + + if (asprintf(&id, "c%lu", ++m->session_counter) < 0) + return -ENOMEM; + + } while (hashmap_get(m->sessions, id)); + } + + r = manager_add_user_by_uid(m, uid, &user); + if (r < 0) + goto fail; + + r = manager_add_session(m, id, &session); + if (r < 0) + goto fail; + + session_set_user(session, user); + + session->leader = leader; + session->audit_id = audit_id; + session->type = t; + session->class = c; + session->remote = remote; + session->vtnr = vtnr; + + if (!isempty(tty)) { + session->tty = strdup(tty); + if (!session->tty) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(display)) { + session->display = strdup(display); + if (!session->display) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(remote_user)) { + session->remote_user = strdup(remote_user); + if (!session->remote_user) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(remote_host)) { + session->remote_host = strdup(remote_host); + if (!session->remote_host) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(service)) { + session->service = strdup(service); + if (!session->service) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(desktop)) { + session->desktop = strdup(desktop); + if (!session->desktop) { + r = -ENOMEM; + goto fail; + } + } + + if (seat) { + r = seat_attach_session(seat, session); + if (r < 0) + goto fail; + } + + r = session_start(session); + if (r < 0) + goto fail; + + session->create_message = sd_bus_message_ref(message); + + /* Now, let's wait until the slice unit and stuff got + * created. We send the reply back from + * session_send_create_reply().*/ + + return 1; + +fail: + if (session) + session_add_to_gc_queue(session); + + if (user) + user_add_to_gc_queue(user); + + return r; +} + +static int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Session *session; + const char *name; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + session_release(session); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Session *session; + const char *name; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + r = session_activate(session); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *session_name, *seat_name; + Manager *m = userdata; + Session *session; + Seat *seat; + int r; + + assert(bus); + assert(message); + assert(m); + + /* Same as ActivateSession() but refuses to work if + * the seat doesn't match */ + + r = sd_bus_message_read(message, "ss", &session_name, &seat_name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, session_name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", session_name); + + seat = hashmap_get(m->seats, seat_name); + if (!seat) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", seat_name); + + 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); + + r = session_activate(session); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Session *session; + const char *name; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + r = session_send_lock(session, streq(sd_bus_message_get_member(message), "LockSession")); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions")); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *name, *swho; + Manager *m = userdata; + Session *session; + int32_t signo; + KillWho who; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ssi", &name, &swho, &signo); + if (r < 0) + return r; + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); + } + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + r = session_kill(session, who, signo); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + uint32_t uid; + int32_t signo; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ui", &uid, &signo); + if (r < 0) + return r; + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (!user) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid); + + r = user_kill(user, signo); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Session *session; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(m->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + r = session_stop(session, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + uint32_t uid; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "u", &uid); + if (r < 0) + return r; + + user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (!user) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user '%lu' known or logged in", (unsigned long) uid); + + r = user_stop(user, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Seat *seat; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + seat = hashmap_get(m->seats, name); + if (!seat) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name); + + r = seat_stop_sessions(seat, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *cc = NULL; + Manager *m = userdata; + int b, r; + struct passwd *pw; + const char *path; + uint32_t uid; + int interactive; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive); + if (r < 0) + return r; + + errno = 0; + pw = getpwuid(uid); + if (!pw) + return errno ? -errno : -ENOENT; + + r = bus_verify_polkit_async(bus, + &m->polkit_registry, + message, + "org.freedesktop.login1.set-user-linger", + interactive, + error, + method_set_user_linger, m); + 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 */ + + mkdir_p_label("/var/lib/systemd", 0755); + + r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0); + if (r < 0) + return r; + + cc = cescape(pw->pw_name); + if (!cc) + return -ENOMEM; + + path = strappenda("/var/lib/systemd/linger/", cc); + if (b) { + User *u; + + r = touch(path); + if (r < 0) + return r; + + if (manager_add_user_by_uid(m, uid, &u) >= 0) + user_start(u); + + } else { + User *u; + + r = unlink(path); + if (r < 0 && errno != ENOENT) + return -errno; + + u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); + if (u) + user_add_to_gc_queue(u); + } + + return sd_bus_reply_method_return(message, NULL); +} + +static int trigger_device(Manager *m, struct udev_device *d) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *first, *item; + int r; + + assert(m); + + e = udev_enumerate_new(m->udev); + if (!e) + return -ENOMEM; + + if (d) { + r = udev_enumerate_add_match_parent(e, d); + if (r < 0) + return r; + } + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_free_ char *t = NULL; + const char *p; + + p = udev_list_entry_get_name(item); + + t = strappend(p, "/uevent"); + if (!t) + return -ENOMEM; + + write_string_file(t, "change"); + } + + return 0; +} + +static int attach_device(Manager *m, const char *seat, const char *sysfs) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + _cleanup_free_ char *rule = NULL, *file = NULL; + const char *id_for_seat; + int r; + + assert(m); + assert(seat); + assert(sysfs); + + d = udev_device_new_from_syspath(m->udev, sysfs); + if (!d) + return -ENODEV; + + if (!udev_device_has_tag(d, "seat")) + return -ENODEV; + + id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT"); + if (!id_for_seat) + return -ENODEV; + + if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) + return -ENOMEM; + + if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) + return -ENOMEM; + + mkdir_p_label("/etc/udev/rules.d", 0755); + label_init("/etc"); + r = write_string_file_atomic_label(file, rule); + if (r < 0) + return r; + + return trigger_device(m, d); +} + +static int flush_devices(Manager *m) { + _cleanup_closedir_ DIR *d; + + assert(m); + + d = opendir("/etc/udev/rules.d"); + if (!d) { + if (errno != ENOENT) + log_warning("Failed to open /etc/udev/rules.d: %m"); + } else { + struct dirent *de; + + while ((de = readdir(d))) { + + if (!dirent_is_file(de)) + continue; + + if (!startswith(de->d_name, "72-seat-")) + continue; + + if (!endswith(de->d_name, ".rules")) + continue; + + if (unlinkat(dirfd(d), de->d_name, 0) < 0) + log_warning("Failed to unlink %s: %m", de->d_name); + } + } + + return trigger_device(m, NULL); +} + +static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *sysfs, *seat; + Manager *m = userdata; + int interactive, r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ssb", &seat, &sysfs, &interactive); + if (r < 0) + return r; + + if (!path_startswith(sysfs, "/sys")) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs); + + if (!seat_name_is_valid(seat)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat); + + r = bus_verify_polkit_async(bus, + &m->polkit_registry, + message, + "org.freedesktop.login1.attach-device", + interactive, + error, + method_attach_device, m); + 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 = attach_device(m, seat, sysfs); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int interactive, r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "b", &interactive); + if (r < 0) + return r; + + r = bus_verify_polkit_async(bus, + &m->polkit_registry, + message, + "org.freedesktop.login1.flush-devices", + interactive, + error, + method_flush_devices, m); + 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 = flush_devices(m); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int have_multiple_sessions( + Manager *m, + uid_t uid) { + + Session *session; + Iterator i; + + assert(m); + + /* Check for other users' sessions. Greeter sessions do not + * count, and non-login sessions do not count either. */ + HASHMAP_FOREACH(session, m->sessions, i) + if (session->class == SESSION_USER && + session->user->uid != uid) + return true; + + return false; +} + +static int bus_manager_log_shutdown( + Manager *m, + InhibitWhat w, + const char *unit_name) { + + const char *p, *q; + + assert(m); + assert(unit_name); + + if (w != INHIBIT_SHUTDOWN) + return 0; + + if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) { + p = "MESSAGE=System is powering down."; + q = "SHUTDOWN=power-off"; + } else if (streq(unit_name, SPECIAL_HALT_TARGET)) { + p = "MESSAGE=System is halting."; + q = "SHUTDOWN=halt"; + } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) { + p = "MESSAGE=System is rebooting."; + q = "SHUTDOWN=reboot"; + } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) { + p = "MESSAGE=System is rebooting with kexec."; + q = "SHUTDOWN=kexec"; + } else { + p = "MESSAGE=System is shutting down."; + q = NULL; + } + + return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN), + p, + q, NULL); +} + +static int execute_shutdown_or_sleep( + Manager *m, + InhibitWhat w, + const char *unit_name, + sd_bus_error *error) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *p; + char *c; + int r; + + assert(m); + assert(w >= 0); + assert(w < _INHIBIT_WHAT_MAX); + assert(unit_name); + + bus_manager_log_shutdown(m, w, unit_name); + + r = sd_bus_call_method( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + error, + &reply, + "ss", unit_name, "replace-irreversibly"); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "o", &p); + if (r < 0) + return r; + + c = strdup(p); + if (!c) + return -ENOMEM; + + m->action_unit = unit_name; + free(m->action_job); + m->action_job = c; + m->action_what = w; + + return 0; +} + +static int delay_shutdown_or_sleep( + Manager *m, + InhibitWhat w, + const char *unit_name) { + + assert(m); + assert(w >= 0); + assert(w < _INHIBIT_WHAT_MAX); + assert(unit_name); + + m->action_timestamp = now(CLOCK_MONOTONIC); + m->action_unit = unit_name; + m->action_what = w; + + return 0; +} + +static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { + + static const char * const signal_name[_INHIBIT_WHAT_MAX] = { + [INHIBIT_SHUTDOWN] = "PrepareForShutdown", + [INHIBIT_SLEEP] = "PrepareForSleep" + }; + + int active = _active; + + assert(m); + assert(w >= 0); + assert(w < _INHIBIT_WHAT_MAX); + assert(signal_name[w]); + + return sd_bus_emit_signal(m->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + signal_name[w], + "b", + active); +} + +int bus_manager_shutdown_or_sleep_now_or_later( + Manager *m, + const char *unit_name, + InhibitWhat w, + sd_bus_error *error) { + + bool delayed; + int r; + + assert(m); + assert(unit_name); + assert(w >= 0); + assert(w <= _INHIBIT_WHAT_MAX); + assert(!m->action_job); + + /* Tell everybody to prepare for shutdown/sleep */ + send_prepare_for(m, w, true); + + delayed = + m->inhibit_delay_max > 0 && + manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL); + + if (delayed) + /* Shutdown is delayed, keep in mind what we + * want to do, and start a timeout */ + r = delay_shutdown_or_sleep(m, w, unit_name); + else + /* Shutdown is not delayed, execute it + * immediately */ + r = execute_shutdown_or_sleep(m, w, unit_name, error); + + return r; +} + +static int method_do_shutdown_or_sleep( + Manager *m, + sd_bus_message *message, + const char *unit_name, + InhibitWhat w, + const char *action, + const char *action_multiple_sessions, + const char *action_ignore_inhibit, + const char *sleep_verb, + sd_bus_message_handler_t method, + sd_bus_error *error) { + + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + bool multiple_sessions, blocked; + int interactive, r; + uid_t uid; + + assert(m); + assert(message); + assert(unit_name); + assert(w >= 0); + assert(w <= _INHIBIT_WHAT_MAX); + assert(action); + assert(action_multiple_sessions); + assert(action_ignore_inhibit); + assert(method); + + r = sd_bus_message_read(message, "b", &interactive); + if (r < 0) + return r; + + /* Don't allow multiple jobs being executed at the same time */ + if (m->action_what) + 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); + if (r < 0) + return r; + + if (r == 0) + return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported"); + } + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + r = have_multiple_sessions(m, uid); + if (r < 0) + return r; + + multiple_sessions = r > 0; + blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + + if (multiple_sessions) { + r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, + action_multiple_sessions, interactive, error, method, m); + if (r < 0) + return r; + } + + if (blocked) { + r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, + action_ignore_inhibit, interactive, error, method, m); + if (r < 0) + return r; + } + + if (!multiple_sessions && !blocked) { + r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, + action, interactive, error, method, m); + if (r < 0) + return r; + } + + r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_POWEROFF_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.power-off", + "org.freedesktop.login1.power-off-multiple-sessions", + "org.freedesktop.login1.power-off-ignore-inhibit", + NULL, + method_poweroff, + error); +} + +static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_REBOOT_TARGET, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.reboot", + "org.freedesktop.login1.reboot-multiple-sessions", + "org.freedesktop.login1.reboot-ignore-inhibit", + NULL, + method_reboot, + error); +} + +static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_SUSPEND_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.suspend", + "org.freedesktop.login1.suspend-multiple-sessions", + "org.freedesktop.login1.suspend-ignore-inhibit", + "suspend", + method_suspend, + error); +} + +static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_HIBERNATE_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hibernate", + method_hibernate, + error); +} + +static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_HYBRID_SLEEP_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", + method_hybrid_sleep, + error); +} + +static int method_can_shutdown_or_sleep( + Manager *m, + sd_bus_message *message, + InhibitWhat w, + const char *action, + const char *action_multiple_sessions, + const char *action_ignore_inhibit, + const char *sleep_verb, + sd_bus_error *error) { + + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + bool multiple_sessions, challenge, blocked; + const char *result = NULL; + uid_t uid; + int r; + + assert(m); + assert(message); + assert(w >= 0); + assert(w <= _INHIBIT_WHAT_MAX); + assert(action); + assert(action_multiple_sessions); + assert(action_ignore_inhibit); + + if (sleep_verb) { + r = can_sleep(sleep_verb); + if (r < 0) + return r; + if (r == 0) + return sd_bus_reply_method_return(message, "s", "na"); + } + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + r = have_multiple_sessions(m, uid); + if (r < 0) + return r; + + multiple_sessions = r > 0; + blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + + if (multiple_sessions) { + r = bus_verify_polkit(m->bus, message, action_multiple_sessions, false, &challenge, error); + if (r < 0) + return r; + + if (r > 0) + result = "yes"; + else if (challenge) + result = "challenge"; + else + result = "no"; + } + + if (blocked) { + r = bus_verify_polkit(m->bus, message, action_ignore_inhibit, false, &challenge, error); + if (r < 0) + return r; + + if (r > 0 && !result) + result = "yes"; + else if (challenge && (!result || streq(result, "yes"))) + result = "challenge"; + else + result = "no"; + } + + if (!multiple_sessions && !blocked) { + /* If neither inhibit nor multiple sessions + * apply then just check the normal policy */ + + r = bus_verify_polkit(m->bus, message, action, false, &challenge, error); + 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 method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.power-off", + "org.freedesktop.login1.power-off-multiple-sessions", + "org.freedesktop.login1.power-off-ignore-inhibit", + NULL, + error); +} + +static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SHUTDOWN, + "org.freedesktop.login1.reboot", + "org.freedesktop.login1.reboot-multiple-sessions", + "org.freedesktop.login1.reboot-ignore-inhibit", + NULL, + error); +} + +static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SLEEP, + "org.freedesktop.login1.suspend", + "org.freedesktop.login1.suspend-multiple-sessions", + "org.freedesktop.login1.suspend-ignore-inhibit", + "suspend", + error); +} + +static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hibernate", + error); +} + +static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", + error); +} + +static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + const char *who, *why, *what, *mode; + _cleanup_free_ char *id = NULL; + _cleanup_close_ int fifo_fd = -1; + Manager *m = userdata; + Inhibitor *i = NULL; + InhibitMode mm; + InhibitWhat w; + pid_t pid; + uid_t uid; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ssss", &what, &who, &why, &mode); + if (r < 0) + return r; + + 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); + + 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); + + /* 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"); + + /* 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"); + + r = bus_verify_polkit_async(bus, &m->polkit_registry, message, + w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") : + w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") : + w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" : + w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" : + w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" : + w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" : + "org.freedesktop.login1.inhibit-handle-lid-switch", + false, error, method_inhibit, m); + 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 = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + do { + free(id); + id = NULL; + + if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) + return -ENOMEM; + + } while (hashmap_get(m->inhibitors, id)); + + r = manager_add_inhibitor(m, id, &i); + if (r < 0) + return r; + + i->what = w; + i->mode = mm; + i->pid = pid; + i->uid = uid; + i->why = strdup(why); + i->who = strdup(who); + + if (!i->why || !i->who) { + r = -ENOMEM; + goto fail; + } + + fifo_fd = inhibitor_create_fifo(i); + if (fifo_fd < 0) { + r = fifo_fd; + goto fail; + } + + inhibitor_start(i); + + return sd_bus_reply_method_return(message, "h", fifo_fd); + +fail: + if (i) + inhibitor_free(i); + + return r; +} + +const sd_bus_vtable manager_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST), + 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("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_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0), + SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0), + + SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUser", "u", "o", method_get_user, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CreateSession", "uusssssussbssa(sv)", "soshusub", method_create_session, 0), + SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0), + SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, 0), + SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, 0), + SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, 0), + SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, 0), + SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_SIGNAL("SessionNew", "so", 0), + SD_BUS_SIGNAL("SessionRemoved", "so", 0), + SD_BUS_SIGNAL("UserNew", "uo", 0), + SD_BUS_SIGNAL("UserRemoved", "uo", 0), + SD_BUS_SIGNAL("SeatNew", "so", 0), + SD_BUS_SIGNAL("SeatRemoved", "so", 0), + SD_BUS_SIGNAL("PrepareForShutdown", "b", 0), + SD_BUS_SIGNAL("PrepareForSleep", "b", 0), + + SD_BUS_VTABLE_END +}; + +static int session_jobs_reply(Session *s, const char *unit, const char *result) { + int r = 0; + + assert(s); + assert(unit); + + if (!s->started) + return r; + + if (streq(result, "done")) + r = session_send_create_reply(s, NULL); + else { + _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + + sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result); + r = session_send_create_reply(s, &e); + } + + return r; +} + +int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *path, *result, *unit; + Manager *m = userdata; + Session *session; + uint32_t id; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + if (m->action_job && streq(m->action_job, path)) { + log_info("Operation finished."); + + /* Tell people that they now may take a lock again */ + send_prepare_for(m, m->action_what, false); + + free(m->action_job); + m->action_job = NULL; + m->action_unit = NULL; + m->action_what = 0; + return 0; + } + + session = hashmap_get(m->session_units, unit); + if (session) { + + if (streq_ptr(path, session->scope_job)) { + free(session->scope_job); + session->scope_job = NULL; + } + + session_jobs_reply(session, unit, result); + + session_save(session); + session_add_to_gc_queue(session); + } + + user = hashmap_get(m->user_units, unit); + if (user) { + + if (streq_ptr(path, user->service_job)) { + free(user->service_job); + user->service_job = NULL; + } + + if (streq_ptr(path, user->slice_job)) { + free(user->slice_job); + user->slice_job = NULL; + } + + LIST_FOREACH(sessions_by_user, session, user->sessions) { + session_jobs_reply(session, unit, result); + } + + user_save(user); + user_add_to_gc_queue(user); + } + + return 0; +} + +int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *path, *unit; + Manager *m = userdata; + Session *session; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "so", &unit, &path); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + session = hashmap_get(m->session_units, unit); + if (session) + session_add_to_gc_queue(session); + + user = hashmap_get(m->user_units, unit); + if (user) + user_add_to_gc_queue(user); + + return 0; +} + +int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *unit = NULL; + Manager *m = userdata; + const char *path; + Session *session; + User *user; + int r; + + assert(bus); + assert(message); + assert(m); + + path = sd_bus_message_get_path(message); + if (!path) + return 0; + + r = unit_name_from_dbus_path(path, &unit); + if (r < 0) + /* quietly ignore non-units paths */ + return r == -EINVAL ? 0 : r; + + session = hashmap_get(m->session_units, unit); + if (session) + session_add_to_gc_queue(session); + + user = hashmap_get(m->user_units, unit); + if (user) + user_add_to_gc_queue(user); + + return 0; +} + +int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Session *session; + Iterator i; + int b, r; + + assert(bus); + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + if (b) + return 0; + + /* systemd finished reloading, let's recheck all our sessions */ + log_debug("System manager has been reloaded, rechecking sessions..."); + + HASHMAP_FOREACH(session, m->sessions, i) + session_add_to_gc_queue(session); + + return 0; +} + +int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *name, *old, *new; + Manager *m = userdata; + Session *session; + Iterator i; + int r; + + + char *key; + + r = sd_bus_message_read(message, "sss", &name, &old, &new); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + if (isempty(old) || !isempty(new)) + return 0; + + key = set_remove(m->busnames, (char*) old); + if (!key) + return 0; + + /* Drop all controllers owned by this name */ + + free(key); + + HASHMAP_FOREACH(session, m->sessions, i) + if (session_is_controller(session, old)) + session_drop_controller(session); + + return 0; +} + +int manager_send_changed(Manager *manager, const char *property, ...) { + char **l; + + assert(manager); + + l = strv_from_stdarg_alloca(property); + + return sd_bus_emit_properties_changed_strv( + manager->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + l); +} + +int manager_dispatch_delayed(Manager *manager) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + Inhibitor *offending = NULL; + int r; + + assert(manager); + + if (manager->action_what == 0 || manager->action_job) + return 0; + + /* Continue delay? */ + if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) { + _cleanup_free_ char *comm = NULL, *u = NULL; + + get_process_comm(offending->pid, &comm); + u = uid_to_name(offending->uid); + + if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC)) + return 0; + + log_info("Delay lock is active (UID %lu/%s, PID %lu/%s) but inhibitor timeout is reached.", + (unsigned long) offending->uid, strna(u), + (unsigned long) offending->pid, strna(comm)); + } + + /* Actually do the operation */ + r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error); + if (r < 0) { + log_warning("Failed to send delayed message: %s", bus_error_message(&error, r)); + + manager->action_unit = NULL; + manager->action_what = 0; + return r; + } + + return 1; +} + +int manager_start_scope( + Manager *manager, + const char *scope, + pid_t pid, + const char *slice, + const char *description, + const char *after, const char *after2, + sd_bus_error *error, + char **job) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + int r; + + assert(manager); + assert(scope); + assert(pid > 1); + + r = sd_bus_message_new_method_call( + manager->bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "ss", strempty(scope), "fail"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) + return r; + + if (!isempty(slice)) { + r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); + if (r < 0) + return r; + } + + if (!isempty(description)) { + r = sd_bus_message_append(m, "(sv)", "Description", "s", description); + if (r < 0) + return r; + } + + if (!isempty(after)) { + r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after); + if (r < 0) + return r; + } + + if (!isempty(after2)) { + r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2); + if (r < 0) + return r; + } + + /* cgroup empty notification is not available in containers + * currently. To make this less problematic, let's shorten the + * stop timeout for sessions, so that we don't wait + * forever. */ + + /* Make sure that the session shells are terminated with + * SIGHUP since bash and friends tend to ignore SIGTERM */ + r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "a(sa(sv))", 0); + if (r < 0) + return r; + + r = sd_bus_call(manager->bus, m, 0, error, &reply); + if (r < 0) + return r; + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + +int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(manager); + assert(unit); + + r = sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + error, + &reply, + "ss", unit, "fail"); + if (r < 0) + return r; + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + +int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(manager); + assert(unit); + + r = sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StopUnit", + error, + &reply, + "ss", unit, "fail"); + if (r < 0) { + if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) || + sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) { + + if (job) + *job = NULL; + + sd_bus_error_free(error); + return 0; + } + + return r; + } + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + +int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) { + _cleanup_free_ char *path = NULL; + int r; + + assert(manager); + assert(scope); + + path = unit_dbus_path_from_name(scope); + if (!path) + return -ENOMEM; + + r = sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Scope", + "Abandon", + error, + NULL, + NULL); + if (r < 0) { + if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) || + sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED) || + sd_bus_error_has_name(error, BUS_ERROR_SCOPE_NOT_RUNNING)) { + sd_bus_error_free(error); + return 0; + } + + return r; + } + + return 1; +} + +int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) { + assert(manager); + assert(unit); + + return sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + error, + NULL, + "ssi", unit, who == KILL_LEADER ? "main" : "all", signo); +} + +int manager_unit_is_active(Manager *manager, const char *unit) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ char *path = NULL; + const char *state; + int r; + + assert(manager); + assert(unit); + + path = unit_dbus_path_from_name(unit); + if (!path) + return -ENOMEM; + + r = sd_bus_get_property( + manager->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &reply, + "s"); + if (r < 0) { + /* systemd might have droppped 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)) + return true; + + /* If the unit is already unloaded then it's not + * active */ + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) || + sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) + return false; + + return r; + } + + r = sd_bus_message_read(reply, "s", &state); + if (r < 0) + return -EINVAL; + + return !streq(state, "inactive") && !streq(state, "failed"); +} + +int manager_job_is_active(Manager *manager, const char *path) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(manager); + assert(path); + + r = sd_bus_get_property( + manager->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Job", + "State", + &error, + &reply, + "s"); + if (r < 0) { + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) || + sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED)) + return true; + + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT)) + return false; + + return r; + } + + /* We don't actually care about the state really. The fact + * that we could read the job state is enough for us */ + + return true; +} diff --git a/src/login/logind-device.c b/src/login/logind-device.c new file mode 100644 index 0000000..76c5a5c --- /dev/null +++ b/src/login/logind-device.c @@ -0,0 +1,126 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "logind-device.h" + +Device* device_new(Manager *m, const char *sysfs, bool master) { + Device *d; + + assert(m); + assert(sysfs); + + d = new0(Device, 1); + if (!d) + return NULL; + + d->sysfs = strdup(sysfs); + if (!d->sysfs) { + free(d); + return NULL; + } + + if (hashmap_put(m->devices, d->sysfs, d) < 0) { + free(d->sysfs); + free(d); + return NULL; + } + + d->manager = m; + d->master = master; + dual_timestamp_get(&d->timestamp); + + return d; +} + +static void device_detach(Device *d) { + Seat *s; + SessionDevice *sd; + + assert(d); + + if (!d->seat) + return; + + while ((sd = d->session_devices)) + session_device_free(sd); + + s = d->seat; + LIST_REMOVE(devices, d->seat->devices, d); + d->seat = NULL; + + if (!seat_has_master_device(s)) { + seat_add_to_gc_queue(s); + seat_send_changed(s, "CanGraphical", NULL); + } +} + +void device_free(Device *d) { + assert(d); + + device_detach(d); + + hashmap_remove(d->manager->devices, d->sysfs); + + free(d->sysfs); + free(d); +} + +void device_attach(Device *d, Seat *s) { + Device *i; + bool had_master; + + assert(d); + assert(s); + + if (d->seat == s) + return; + + if (d->seat) + device_detach(d); + + d->seat = s; + had_master = seat_has_master_device(s); + + /* We keep the device list sorted by the "master" flag. That is, master + * devices are at the front, other devices at the tail. As there is no + * way to easily add devices at the list-tail, we need to iterate the + * list to find the first non-master device when adding non-master + * devices. We assume there is only a few (normally 1) master devices + * per seat, so we iterate only a few times. */ + + if (d->master || !s->devices) + LIST_PREPEND(devices, s->devices, d); + else { + LIST_FOREACH(devices, i, s->devices) { + if (!i->devices_next || !i->master) { + LIST_INSERT_AFTER(devices, s->devices, i, d); + break; + } + } + } + + if (!had_master && d->master) + seat_send_changed(s, "CanGraphical", NULL); +} diff --git a/src/login/logind-device.h b/src/login/logind-device.h new file mode 100644 index 0000000..c273d2b --- /dev/null +++ b/src/login/logind-device.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Device Device; + +#include "list.h" +#include "util.h" +#include "logind.h" +#include "logind-seat.h" +#include "logind-session-device.h" + +struct Device { + Manager *manager; + + char *sysfs; + Seat *seat; + bool master; + + dual_timestamp timestamp; + + LIST_FIELDS(struct Device, devices); + LIST_HEAD(SessionDevice, session_devices); +}; + +Device* device_new(Manager *m, const char *sysfs, bool master); +void device_free(Device *d); +void device_attach(Device *d, Seat *s); diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf new file mode 100644 index 0000000..845302a --- /dev/null +++ b/src/login/logind-gperf.gperf @@ -0,0 +1,32 @@ +%{ +#include +#include "conf-parser.h" +#include "logind.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name logind_gperf_hash +%define lookup-function-name logind_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Login.NAutoVTs, config_parse_unsigned, 0, offsetof(Manager, n_autovts) +Login.ReserveVT, config_parse_unsigned, 0, offsetof(Manager, reserve_vt) +Login.KillUserProcesses, config_parse_bool, 0, offsetof(Manager, kill_user_processes) +Login.KillOnlyUsers, config_parse_strv, 0, offsetof(Manager, kill_only_users) +Login.KillExcludeUsers, config_parse_strv, 0, offsetof(Manager, kill_exclude_users) +Login.InhibitDelayMaxSec, config_parse_sec, 0, offsetof(Manager, inhibit_delay_max) +Login.HandlePowerKey, config_parse_handle_action, 0, offsetof(Manager, handle_power_key) +Login.HandleSuspendKey, config_parse_handle_action, 0, offsetof(Manager, handle_suspend_key) +Login.HandleHibernateKey, config_parse_handle_action, 0, offsetof(Manager, handle_hibernate_key) +Login.HandleLidSwitch, config_parse_handle_action, 0, offsetof(Manager, handle_lid_switch) +Login.PowerKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, power_key_ignore_inhibited) +Login.SuspendKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, suspend_key_ignore_inhibited) +Login.HibernateKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, hibernate_key_ignore_inhibited) +Login.LidSwitchIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, lid_switch_ignore_inhibited) +Login.IdleAction, config_parse_handle_action, 0, offsetof(Manager, idle_action) +Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c new file mode 100644 index 0000000..d19d648 --- /dev/null +++ b/src/login/logind-inhibit.c @@ -0,0 +1,478 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "path-util.h" +#include "logind-inhibit.h" +#include "fileio.h" + +Inhibitor* inhibitor_new(Manager *m, const char* id) { + Inhibitor *i; + + assert(m); + + i = new0(Inhibitor, 1); + if (!i) + return NULL; + + i->state_file = strappend("/run/systemd/inhibit/", id); + if (!i->state_file) { + free(i); + return NULL; + } + + i->id = basename(i->state_file); + + if (hashmap_put(m->inhibitors, i->id, i) < 0) { + free(i->state_file); + free(i); + return NULL; + } + + i->manager = m; + i->fifo_fd = -1; + + return i; +} + +void inhibitor_free(Inhibitor *i) { + assert(i); + + hashmap_remove(i->manager->inhibitors, i->id); + + inhibitor_remove_fifo(i); + + free(i->who); + free(i->why); + + if (i->state_file) { + unlink(i->state_file); + free(i->state_file); + } + + free(i); +} + +int inhibitor_save(Inhibitor *i) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(i); + + r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0); + if (r < 0) + goto finish; + + r = fopen_temporary(i->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "WHAT=%s\n" + "MODE=%s\n" + "UID="UID_FMT"\n" + "PID="PID_FMT"\n", + inhibit_what_to_string(i->what), + inhibit_mode_to_string(i->mode), + i->uid, + i->pid); + + if (i->who) { + _cleanup_free_ char *cc = NULL; + + cc = cescape(i->who); + if (!cc) + r = -ENOMEM; + else + fprintf(f, "WHO=%s\n", cc); + } + + if (i->why) { + _cleanup_free_ char *cc = NULL; + + cc = cescape(i->why); + if (!cc) + r = -ENOMEM; + else + fprintf(f, "WHY=%s\n", cc); + } + + if (i->fifo_path) + fprintf(f, "FIFO=%s\n", i->fifo_path); + + fflush(f); + + if (ferror(f) || rename(temp_path, i->state_file) < 0) { + r = -errno; + unlink(i->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save inhibit data %s: %s", i->state_file, strerror(-r)); + + return r; +} + +int inhibitor_start(Inhibitor *i) { + assert(i); + + if (i->started) + return 0; + + dual_timestamp_get(&i->since); + + log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.", + strna(i->who), strna(i->why), + (unsigned long) i->pid, (unsigned long) i->uid, + inhibit_mode_to_string(i->mode)); + + inhibitor_save(i); + + i->started = true; + + manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL); + + return 0; +} + +int inhibitor_stop(Inhibitor *i) { + assert(i); + + if (i->started) + log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.", + strna(i->who), strna(i->why), + (unsigned long) i->pid, (unsigned long) i->uid, + inhibit_mode_to_string(i->mode)); + + if (i->state_file) + unlink(i->state_file); + + i->started = false; + + manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL); + + return 0; +} + +int inhibitor_load(Inhibitor *i) { + + _cleanup_free_ char + *what = NULL, + *uid = NULL, + *pid = NULL, + *who = NULL, + *why = NULL, + *mode = NULL; + + InhibitWhat w; + InhibitMode mm; + char *cc; + int r; + + r = parse_env_file(i->state_file, NEWLINE, + "WHAT", &what, + "UID", &uid, + "PID", &pid, + "WHO", &who, + "WHY", &why, + "MODE", &mode, + "FIFO", &i->fifo_path, + NULL); + if (r < 0) + return r; + + w = what ? inhibit_what_from_string(what) : 0; + if (w >= 0) + i->what = w; + + mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK; + if (mm >= 0) + i->mode = mm; + + if (uid) { + r = parse_uid(uid, &i->uid); + if (r < 0) + return r; + } + + if (pid) { + r = parse_pid(pid, &i->pid); + if (r < 0) + return r; + } + + if (who) { + cc = cunescape(who); + if (!cc) + return -ENOMEM; + + free(i->who); + i->who = cc; + } + + if (why) { + cc = cunescape(why); + if (!cc) + return -ENOMEM; + + free(i->why); + i->why = cc; + } + + if (i->fifo_path) { + int fd; + + fd = inhibitor_create_fifo(i); + if (fd >= 0) + close_nointr_nofail(fd); + } + + return 0; +} + +static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Inhibitor *i = userdata; + + assert(s); + assert(fd == i->fifo_fd); + assert(i); + + inhibitor_stop(i); + inhibitor_free(i); + + return 0; +} + +int inhibitor_create_fifo(Inhibitor *i) { + int r; + + assert(i); + + /* Create FIFO */ + if (!i->fifo_path) { + r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0); + if (r < 0) + return r; + + i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL); + if (!i->fifo_path) + return -ENOMEM; + + if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST) + return -errno; + } + + /* Open reading side */ + if (i->fifo_fd < 0) { + i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY); + if (i->fifo_fd < 0) + return -errno; + } + + if (!i->event_source) { + r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i); + if (r < 0) + return r; + + r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + return r; + } + + /* Open writing side */ + r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY); + if (r < 0) + return -errno; + + return r; +} + +void inhibitor_remove_fifo(Inhibitor *i) { + assert(i); + + if (i->event_source) + i->event_source = sd_event_source_unref(i->event_source); + + if (i->fifo_fd >= 0) { + close_nointr_nofail(i->fifo_fd); + i->fifo_fd = -1; + } + + if (i->fifo_path) { + unlink(i->fifo_path); + free(i->fifo_path); + i->fifo_path = NULL; + } +} + +InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) { + Inhibitor *i; + Iterator j; + InhibitWhat what = 0; + + assert(m); + + HASHMAP_FOREACH(i, m->inhibitors, j) + if (i->mode == mm) + what |= i->what; + + return what; +} + +static int pid_is_active(Manager *m, pid_t pid) { + Session *s; + int r; + + r = manager_get_session_by_pid(m, pid, &s); + if (r < 0) + return r; + + /* If there's no session assigned to it, then it's globally + * active on all ttys */ + if (r == 0) + return 1; + + return session_is_active(s); +} + +bool manager_is_inhibited( + Manager *m, + InhibitWhat w, + InhibitMode mm, + dual_timestamp *since, + bool ignore_inactive, + bool ignore_uid, + uid_t uid, + Inhibitor **offending) { + + Inhibitor *i; + Iterator j; + struct dual_timestamp ts = { 0, 0 }; + bool inhibited = false; + + assert(m); + assert(w > 0 && w < _INHIBIT_WHAT_MAX); + + HASHMAP_FOREACH(i, m->inhibitors, j) { + if (!(i->what & w)) + continue; + + if (i->mode != mm) + continue; + + if (ignore_inactive && pid_is_active(m, i->pid) <= 0) + continue; + + if (ignore_uid && i->uid == uid) + continue; + + if (!inhibited || + i->since.monotonic < ts.monotonic) + ts = i->since; + + inhibited = true; + + if (offending) + *offending = i; + } + + if (since) + *since = ts; + + return inhibited; +} + +const char *inhibit_what_to_string(InhibitWhat w) { + static thread_local char buffer[97]; + char *p; + + if (w < 0 || w >= _INHIBIT_WHAT_MAX) + return NULL; + + p = buffer; + if (w & INHIBIT_SHUTDOWN) + p = stpcpy(p, "shutdown:"); + if (w & INHIBIT_SLEEP) + p = stpcpy(p, "sleep:"); + if (w & INHIBIT_IDLE) + p = stpcpy(p, "idle:"); + if (w & INHIBIT_HANDLE_POWER_KEY) + p = stpcpy(p, "handle-power-key:"); + if (w & INHIBIT_HANDLE_SUSPEND_KEY) + p = stpcpy(p, "handle-suspend-key:"); + if (w & INHIBIT_HANDLE_HIBERNATE_KEY) + p = stpcpy(p, "handle-hibernate-key:"); + if (w & INHIBIT_HANDLE_LID_SWITCH) + p = stpcpy(p, "handle-lid-switch:"); + + if (p > buffer) + *(p-1) = 0; + else + *p = 0; + + return buffer; +} + +InhibitWhat inhibit_what_from_string(const char *s) { + InhibitWhat what = 0; + char *w, *state; + size_t l; + + FOREACH_WORD_SEPARATOR(w, l, s, ":", state) { + if (l == 8 && strneq(w, "shutdown", l)) + what |= INHIBIT_SHUTDOWN; + else if (l == 5 && strneq(w, "sleep", l)) + what |= INHIBIT_SLEEP; + else if (l == 4 && strneq(w, "idle", l)) + what |= INHIBIT_IDLE; + else if (l == 16 && strneq(w, "handle-power-key", l)) + what |= INHIBIT_HANDLE_POWER_KEY; + else if (l == 18 && strneq(w, "handle-suspend-key", l)) + what |= INHIBIT_HANDLE_SUSPEND_KEY; + else if (l == 20 && strneq(w, "handle-hibernate-key", l)) + what |= INHIBIT_HANDLE_HIBERNATE_KEY; + else if (l == 17 && strneq(w, "handle-lid-switch", l)) + what |= INHIBIT_HANDLE_LID_SWITCH; + else + return _INHIBIT_WHAT_INVALID; + } + + return what; +} + +static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = { + [INHIBIT_BLOCK] = "block", + [INHIBIT_DELAY] = "delay" +}; + +DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode); diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h new file mode 100644 index 0000000..f767876 --- /dev/null +++ b/src/login/logind-inhibit.h @@ -0,0 +1,94 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Inhibitor Inhibitor; + +#include "list.h" +#include "util.h" + +typedef enum InhibitWhat { + INHIBIT_SHUTDOWN = 1, + INHIBIT_SLEEP = 2, + INHIBIT_IDLE = 4, + INHIBIT_HANDLE_POWER_KEY = 8, + INHIBIT_HANDLE_SUSPEND_KEY = 16, + INHIBIT_HANDLE_HIBERNATE_KEY = 32, + INHIBIT_HANDLE_LID_SWITCH = 64, + _INHIBIT_WHAT_MAX = 128, + _INHIBIT_WHAT_INVALID = -1 +} InhibitWhat; + +typedef enum InhibitMode { + INHIBIT_BLOCK, + INHIBIT_DELAY, + _INHIBIT_MODE_MAX, + _INHIBIT_MODE_INVALID = -1 +} InhibitMode; + +#include "logind.h" +#include "logind-seat.h" + +struct Inhibitor { + Manager *manager; + + sd_event_source *event_source; + + char *id; + char *state_file; + + bool started; + + InhibitWhat what; + char *who; + char *why; + InhibitMode mode; + + pid_t pid; + uid_t uid; + + dual_timestamp since; + + char *fifo_path; + int fifo_fd; +}; + +Inhibitor* inhibitor_new(Manager *m, const char *id); +void inhibitor_free(Inhibitor *i); + +int inhibitor_save(Inhibitor *i); +int inhibitor_load(Inhibitor *i); + +int inhibitor_start(Inhibitor *i); +int inhibitor_stop(Inhibitor *i); + +int inhibitor_create_fifo(Inhibitor *i); +void inhibitor_remove_fifo(Inhibitor *i); + +InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm); +bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since, bool ignore_inactive, bool ignore_uid, uid_t uid, Inhibitor **offending); + +const char *inhibit_what_to_string(InhibitWhat k); +InhibitWhat inhibit_what_from_string(const char *s); + +const char *inhibit_mode_to_string(InhibitMode k); +InhibitMode inhibit_mode_from_string(const char *s); diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c new file mode 100644 index 0000000..26cddfe --- /dev/null +++ b/src/login/logind-seat-dbus.c @@ -0,0 +1,448 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "bus-util.h" +#include "strv.h" +#include "bus-errors.h" +#include "logind.h" +#include "logind-seat.h" + +static int property_get_active_session( + 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 *p = NULL; + Seat *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + p = s->active ? session_bus_path(s->active) : strdup("/"); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p); +} + +static int property_get_can_multi_session( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", seat_can_multi_session(s)); +} + +static int property_get_can_tty( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", seat_can_tty(s)); +} + +static int property_get_can_graphical( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", seat_can_graphical(s)); +} + +static int property_get_sessions( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + Session *session; + int r; + + assert(bus); + assert(reply); + assert(s); + + r = sd_bus_message_open_container(reply, 'a', "(so)"); + if (r < 0) + return r; + + LIST_FOREACH(sessions_by_seat, session, s->sessions) { + _cleanup_free_ char *p = NULL; + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(so)", session->id, p); + if (r < 0) + return r; + + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return 1; +} + +static int property_get_idle_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0); +} + +static int property_get_idle_since_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Seat *s = userdata; + dual_timestamp t; + uint64_t u; + int r; + + assert(bus); + assert(reply); + assert(s); + + r = seat_get_idle_hint(s, &t); + if (r < 0) + return r; + + u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; + + return sd_bus_message_append(reply, "t", u); +} + +static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = seat_stop_sessions(s, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + const char *name; + Session *session; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + session = hashmap_get(s->manager->sessions, name); + if (!session) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); + + if (session->seat != s) + return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id); + + r = session_activate(session); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + unsigned int to; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "u", &to); + if (r < 0) + return r; + + if (to <= 0) + return -EINVAL; + + r = seat_switch_to(s, to); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = seat_switch_to_next(s); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Seat *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = seat_switch_to_previous(s); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable seat_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + 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("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_VTABLE_END +}; + +int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Seat *seat; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + if (streq(path, "/org/freedesktop/login1/seat/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_bus_message *message; + Session *session; + pid_t pid; + + message = sd_bus_get_current(bus); + if (!message) + return 0; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + r = manager_get_session_by_pid(m, pid, &session); + if (r <= 0) + return 0; + + if (!session->seat) + return 0; + + seat = session->seat; + } else { + _cleanup_free_ char *e = NULL; + const char *p; + + p = startswith(path, "/org/freedesktop/login1/seat/"); + if (!p) + return 0; + + e = sd_bus_label_unescape(p); + if (!e) + return -ENOMEM; + + seat = hashmap_get(m->seats, e); + if (!seat) + return 0; + } + + *found = seat; + return 1; +} + +char *seat_bus_path(Seat *s) { + _cleanup_free_ char *t = NULL; + + assert(s); + + t = sd_bus_label_escape(s->id); + if (!t) + return NULL; + + return strappend("/org/freedesktop/login1/seat/", t); +} + +int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + Manager *m = userdata; + Seat *seat; + Iterator i; + int r; + + assert(bus); + assert(path); + assert(nodes); + + HASHMAP_FOREACH(seat, m->seats, i) { + char *p; + + p = seat_bus_path(seat); + if (!p) + return -ENOMEM; + + r = strv_push(&l, p); + if (r < 0) { + free(p); + return r; + } + } + + *nodes = l; + l = NULL; + + return 1; +} + +int seat_send_signal(Seat *s, bool new_seat) { + _cleanup_free_ char *p = NULL; + + assert(s); + + p = seat_bus_path(s); + if (!p) + return -ENOMEM; + + return sd_bus_emit_signal( + s->manager->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + new_seat ? "SeatNew" : "SeatRemoved", + "so", s->id, p); +} + +int seat_send_changed(Seat *s, const char *properties, ...) { + _cleanup_free_ char *p = NULL; + char **l; + + assert(s); + + if (!s->started) + return 0; + + p = seat_bus_path(s); + if (!p) + return -ENOMEM; + + l = strv_from_stdarg_alloca(properties); + + return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l); +} diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c new file mode 100644 index 0000000..631be5f --- /dev/null +++ b/src/login/logind-seat.c @@ -0,0 +1,661 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "logind-seat.h" +#include "logind-acl.h" +#include "util.h" +#include "mkdir.h" +#include "path-util.h" + +Seat *seat_new(Manager *m, const char *id) { + Seat *s; + + assert(m); + assert(id); + + s = new0(Seat, 1); + if (!s) + return NULL; + + s->state_file = strappend("/run/systemd/seats/", id); + if (!s->state_file) { + free(s); + return NULL; + } + + s->id = basename(s->state_file); + s->manager = m; + + if (hashmap_put(m->seats, s->id, s) < 0) { + free(s->state_file); + free(s); + return NULL; + } + + return s; +} + +void seat_free(Seat *s) { + assert(s); + + if (s->in_gc_queue) + LIST_REMOVE(gc_queue, s->manager->seat_gc_queue, s); + + while (s->sessions) + session_free(s->sessions); + + assert(!s->active); + + while (s->devices) + device_free(s->devices); + + hashmap_remove(s->manager->seats, s->id); + + free(s->positions); + free(s->state_file); + free(s); +} + +int seat_save(Seat *s) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(s); + + if (!s->started) + return 0; + + r = mkdir_safe_label("/run/systemd/seats", 0755, 0, 0); + if (r < 0) + goto finish; + + r = fopen_temporary(s->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "IS_SEAT0=%i\n" + "CAN_MULTI_SESSION=%i\n" + "CAN_TTY=%i\n" + "CAN_GRAPHICAL=%i\n", + seat_is_seat0(s), + seat_can_multi_session(s), + seat_can_tty(s), + seat_can_graphical(s)); + + if (s->active) { + assert(s->active->user); + + fprintf(f, + "ACTIVE=%s\n" + "ACTIVE_UID=%lu\n", + s->active->id, + (unsigned long) s->active->user->uid); + } + + if (s->sessions) { + Session *i; + + fputs("SESSIONS=", f); + LIST_FOREACH(sessions_by_seat, i, s->sessions) { + fprintf(f, + "%s%c", + i->id, + i->sessions_by_seat_next ? ' ' : '\n'); + } + + fputs("UIDS=", f); + LIST_FOREACH(sessions_by_seat, i, s->sessions) + fprintf(f, + UID_FMT"%c", + i->user->uid, + i->sessions_by_seat_next ? ' ' : '\n'); + } + + fflush(f); + + if (ferror(f) || rename(temp_path, s->state_file) < 0) { + r = -errno; + unlink(s->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save seat data %s: %s", s->state_file, strerror(-r)); + + return r; +} + +int seat_load(Seat *s) { + assert(s); + + /* There isn't actually anything to read here ... */ + + return 0; +} + +static int vt_allocate(unsigned int vtnr) { + _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; + + assert(vtnr >= 1); + + if (asprintf(&p, "/dev/tty%u", vtnr) < 0) + return -ENOMEM; + + fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + return 0; +} + +int seat_preallocate_vts(Seat *s) { + int r = 0; + unsigned i; + + assert(s); + assert(s->manager); + + log_debug("Preallocating VTs..."); + + if (s->manager->n_autovts <= 0) + return 0; + + if (!seat_has_vts(s)) + return 0; + + for (i = 1; i <= s->manager->n_autovts; i++) { + int q; + + q = vt_allocate(i); + if (q < 0) { + log_error("Failed to preallocate VT %i: %s", i, strerror(-q)); + r = q; + } + } + + return r; +} + +int seat_apply_acls(Seat *s, Session *old_active) { + int r; + + assert(s); + + r = devnode_acl_all(s->manager->udev, + s->id, + false, + !!old_active, old_active ? old_active->user->uid : 0, + !!s->active, s->active ? s->active->user->uid : 0); + + if (r < 0) + log_error("Failed to apply ACLs: %s", strerror(-r)); + + return r; +} + +int seat_set_active(Seat *s, Session *session) { + Session *old_active; + + assert(s); + assert(!session || session->seat == s); + + if (session == s->active) + return 0; + + old_active = s->active; + s->active = session; + + if (old_active) { + session_device_pause_all(old_active); + session_send_changed(old_active, "Active", NULL); + } + + seat_apply_acls(s, old_active); + + if (session && session->started) { + session_send_changed(session, "Active", NULL); + session_device_resume_all(session); + } + + if (!session || session->started) + seat_send_changed(s, "ActiveSession", NULL); + + seat_save(s); + + if (session) { + session_save(session); + user_save(session->user); + } + + if (old_active) { + session_save(old_active); + if (!session || session->user != old_active->user) + user_save(old_active->user); + } + + return 0; +} + +int seat_switch_to(Seat *s, unsigned int num) { + /* Public session positions skip 0 (there is only F1-F12). Maybe it + * will get reassigned in the future, so return error for now. */ + if (!num) + return -EINVAL; + + if (num >= s->position_count || !s->positions[num]) + return -EINVAL; + + return session_activate(s->positions[num]); +} + +int seat_switch_to_next(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start + 1; i < s->position_count; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = 1; i < start; ++i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + +int seat_switch_to_previous(Seat *s) { + unsigned int start, i; + + if (!s->position_count) + return -EINVAL; + + start = 1; + if (s->active && s->active->pos > 0) + start = s->active->pos; + + for (i = start - 1; i > 0; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + for (i = s->position_count - 1; i > start; --i) + if (s->positions[i]) + return session_activate(s->positions[i]); + + return -EINVAL; +} + +int seat_active_vt_changed(Seat *s, unsigned int vtnr) { + Session *i, *new_active = NULL; + int r; + + assert(s); + assert(vtnr >= 1); + + if (!seat_has_vts(s)) + return -EINVAL; + + log_debug("VT changed to %u", vtnr); + + LIST_FOREACH(sessions_by_seat, i, s->sessions) + if (i->vtnr == vtnr) { + new_active = i; + break; + } + + r = seat_set_active(s, new_active); + manager_spawn_autovt(s->manager, vtnr); + + return r; +} + +int seat_read_active_vt(Seat *s) { + char t[64]; + ssize_t k; + unsigned int vtnr; + int r; + + assert(s); + + if (!seat_has_vts(s)) + return 0; + + lseek(s->manager->console_active_fd, SEEK_SET, 0); + + k = read(s->manager->console_active_fd, t, sizeof(t)-1); + if (k <= 0) { + log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF"); + return k < 0 ? -errno : -EIO; + } + + t[k] = 0; + truncate_nl(t); + + if (!startswith(t, "tty")) { + log_error("Hm, /sys/class/tty/tty0/active is badly formatted."); + return -EIO; + } + + r = safe_atou(t+3, &vtnr); + if (r < 0) { + log_error("Failed to parse VT number %s", t+3); + return r; + } + + if (!vtnr) { + log_error("VT number invalid: %s", t+3); + return -EIO; + } + + return seat_active_vt_changed(s, vtnr); +} + +int seat_start(Seat *s) { + assert(s); + + if (s->started) + return 0; + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SEAT_START), + "SEAT_ID=%s", s->id, + "MESSAGE=New seat %s.", s->id, + NULL); + + /* Initialize VT magic stuff */ + seat_preallocate_vts(s); + + /* Read current VT */ + seat_read_active_vt(s); + + s->started = true; + + /* Save seat data */ + seat_save(s); + + seat_send_signal(s, true); + + return 0; +} + +int seat_stop(Seat *s, bool force) { + int r = 0; + + assert(s); + + if (s->started) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SEAT_STOP), + "SEAT_ID=%s", s->id, + "MESSAGE=Removed seat %s.", s->id, + NULL); + + seat_stop_sessions(s, force); + + unlink(s->state_file); + seat_add_to_gc_queue(s); + + if (s->started) + seat_send_signal(s, false); + + s->started = false; + + return r; +} + +int seat_stop_sessions(Seat *s, bool force) { + Session *session; + int r = 0, k; + + assert(s); + + LIST_FOREACH(sessions_by_seat, session, s->sessions) { + k = session_stop(session, force); + if (k < 0) + r = k; + } + + return r; +} + +void seat_evict_position(Seat *s, Session *session) { + unsigned int pos = session->pos; + + session->pos = 0; + + if (!pos) + return; + + if (pos < s->position_count && s->positions[pos] == session) + s->positions[pos] = NULL; +} + +void seat_claim_position(Seat *s, Session *session, unsigned int pos) { + /* with VTs, the position is always the same as the VTnr */ + if (seat_has_vts(s)) + pos = session->vtnr; + + if (!GREEDY_REALLOC0(s->positions, s->position_count, pos + 1)) + return; + + seat_evict_position(s, session); + + session->pos = pos; + if (pos > 0 && !s->positions[pos]) + s->positions[pos] = session; +} + +static void seat_assign_position(Seat *s, Session *session) { + unsigned int pos; + + if (session->pos > 0) + return; + + for (pos = 1; pos < s->position_count; ++pos) + if (!s->positions[pos]) + break; + + seat_claim_position(s, session, pos); +} + +int seat_attach_session(Seat *s, Session *session) { + assert(s); + assert(session); + assert(!session->seat); + + if (!seat_has_vts(s) != !session->vtnr) + return -EINVAL; + + session->seat = s; + LIST_PREPEND(sessions_by_seat, s->sessions, session); + seat_assign_position(s, session); + + seat_send_changed(s, "Sessions", NULL); + + /* On seats with VTs, the VT logic defines which session is active. On + * seats without VTs, we automatically activate new sessions. */ + if (!seat_has_vts(s)) + seat_set_active(s, session); + + return 0; +} + +void seat_complete_switch(Seat *s) { + Session *session; + + assert(s); + + /* if no session-switch is pending or if it got canceled, do nothing */ + if (!s->pending_switch) + return; + + session = s->pending_switch; + s->pending_switch = NULL; + + seat_set_active(s, session); +} + +bool seat_has_vts(Seat *s) { + assert(s); + + return seat_is_seat0(s) && s->manager->console_active_fd >= 0; +} + +bool seat_is_seat0(Seat *s) { + assert(s); + + return s->manager->seat0 == s; +} + +bool seat_can_multi_session(Seat *s) { + assert(s); + + return seat_has_vts(s); +} + +bool seat_can_tty(Seat *s) { + assert(s); + + return seat_has_vts(s); +} + +bool seat_has_master_device(Seat *s) { + assert(s); + + /* device list is ordered by "master" flag */ + return !!s->devices && s->devices->master; +} + +bool seat_can_graphical(Seat *s) { + assert(s); + + return seat_has_master_device(s); +} + +int seat_get_idle_hint(Seat *s, dual_timestamp *t) { + Session *session; + bool idle_hint = true; + dual_timestamp ts = { 0, 0 }; + + assert(s); + + LIST_FOREACH(sessions_by_seat, session, s->sessions) { + dual_timestamp k; + int ih; + + ih = session_get_idle_hint(session, &k); + if (ih < 0) + return ih; + + if (!ih) { + if (!idle_hint) { + if (k.monotonic > ts.monotonic) + ts = k; + } else { + idle_hint = false; + ts = k; + } + } else if (idle_hint) { + + if (k.monotonic > ts.monotonic) + ts = k; + } + } + + if (t) + *t = ts; + + return idle_hint; +} + +bool seat_check_gc(Seat *s, bool drop_not_started) { + assert(s); + + if (drop_not_started && !s->started) + return false; + + if (seat_is_seat0(s)) + return true; + + return seat_has_master_device(s); +} + +void seat_add_to_gc_queue(Seat *s) { + assert(s); + + if (s->in_gc_queue) + return; + + LIST_PREPEND(gc_queue, s->manager->seat_gc_queue, s); + s->in_gc_queue = true; +} + +static bool seat_name_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_'; +} + +bool seat_name_is_valid(const char *name) { + const char *p; + + assert(name); + + if (!startswith(name, "seat")) + return false; + + if (!name[4]) + return false; + + for (p = name; *p; p++) + if (!seat_name_valid_char(*p)) + return false; + + if (strlen(name) > 255) + return false; + + return true; +} diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h new file mode 100644 index 0000000..9e469d4 --- /dev/null +++ b/src/login/logind-seat.h @@ -0,0 +1,98 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Seat Seat; + +#include "list.h" +#include "util.h" +#include "logind.h" +#include "logind-device.h" +#include "logind-session.h" + +struct Seat { + Manager *manager; + char *id; + + char *state_file; + + LIST_HEAD(Device, devices); + + Session *active; + Session *pending_switch; + LIST_HEAD(Session, sessions); + + Session **positions; + size_t position_count; + + bool in_gc_queue:1; + bool started:1; + + LIST_FIELDS(Seat, gc_queue); +}; + +Seat *seat_new(Manager *m, const char *id); +void seat_free(Seat *s); + +int seat_save(Seat *s); +int seat_load(Seat *s); + +int seat_apply_acls(Seat *s, Session *old_active); +int seat_set_active(Seat *s, Session *session); +int seat_switch_to(Seat *s, unsigned int num); +int seat_switch_to_next(Seat *s); +int seat_switch_to_previous(Seat *s); +int seat_active_vt_changed(Seat *s, unsigned int vtnr); +int seat_read_active_vt(Seat *s); +int seat_preallocate_vts(Seat *s); + +int seat_attach_session(Seat *s, Session *session); +void seat_complete_switch(Seat *s); +void seat_evict_position(Seat *s, Session *session); +void seat_claim_position(Seat *s, Session *session, unsigned int pos); + +bool seat_has_vts(Seat *s); +bool seat_is_seat0(Seat *s); +bool seat_can_multi_session(Seat *s); +bool seat_can_tty(Seat *s); +bool seat_has_master_device(Seat *s); +bool seat_can_graphical(Seat *s); + +int seat_get_idle_hint(Seat *s, dual_timestamp *t); + +int seat_start(Seat *s); +int seat_stop(Seat *s, bool force); +int seat_stop_sessions(Seat *s, bool force); + +bool seat_check_gc(Seat *s, bool drop_not_started); +void seat_add_to_gc_queue(Seat *s); + +bool seat_name_is_valid(const char *name); + +extern const sd_bus_vtable seat_vtable[]; + +int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *seat_bus_path(Seat *s); + +int seat_send_signal(Seat *s, bool new_seat); +int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c new file mode 100644 index 0000000..f9305dd --- /dev/null +++ b/src/login/logind-session-dbus.c @@ -0,0 +1,698 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "strv.h" +#include "bus-util.h" +#include "bus-errors.h" + +#include "logind.h" +#include "logind-session.h" +#include "logind-session-device.h" + +static int property_get_user( + 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 *p = NULL; + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + p = user_bus_path(s->user); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(uo)", (uint32_t) s->user->uid, p); +} + +static int property_get_name( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "s", s->user->name); +} + +static int property_get_seat( + 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 *p = NULL; + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + p = s->seat ? seat_bus_path(s->seat) : strdup("/"); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(so)", s->seat ? s->seat->id : "", p); +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, session_type, SessionType); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, session_class, SessionClass); + +static int property_get_active( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", session_is_active(s)); +} + +static int property_get_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "s", session_state_to_string(session_get_state(s))); +} + +static int property_get_idle_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", session_get_idle_hint(s, NULL) > 0); +} + +static int property_get_idle_since_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + dual_timestamp t; + uint64_t u; + int r; + + assert(bus); + assert(reply); + assert(s); + + r = session_get_idle_hint(s, &t); + if (r < 0) + return r; + + u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; + + return sd_bus_message_append(reply, "t", u); +} + +static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = session_stop(s, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = session_activate(s); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + int r; + + assert(bus); + assert(message); + assert(s); + + r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock")); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + Session *s = userdata; + uid_t uid; + int r, b; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + if (uid != 0 && uid != s->user->uid) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session my set idle hint"); + + session_set_idle_hint(s, b); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + const char *swho; + int32_t signo; + KillWho who; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "si", &swho, &signo); + if (r < 0) + return r; + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); + } + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + r = session_kill(s, who, signo); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + Session *s = userdata; + int r, force; + uid_t uid; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "b", &force); + if (r < 0) + return r; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_uid(creds, &uid); + if (r < 0) + return r; + + if (uid != 0 && (force || uid != s->user->uid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may take control"); + + r = session_set_controller(s, sd_bus_message_get_sender(message), force); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + + assert(bus); + assert(message); + assert(s); + + if (!session_is_controller(s, sd_bus_message_get_sender(message))) + return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session"); + + session_drop_controller(s); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + uint32_t major, minor; + SessionDevice *sd; + dev_t dev; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "uu", &major, &minor); + if (r < 0) + return r; + + if (!session_is_controller(s, sd_bus_message_get_sender(message))) + return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session"); + + dev = makedev(major, minor); + sd = hashmap_get(s->devices, &dev); + if (sd) + /* We don't allow retrieving a device multiple times. + * The related ReleaseDevice call is not ref-counted. + * The caller should use dup() if it requires more + * than one fd (it would be functionally + * equivalent). */ + return sd_bus_error_setf(error, BUS_ERROR_DEVICE_IS_TAKEN, "Device already taken"); + + r = session_device_new(s, dev, &sd); + if (r < 0) + return r; + + r = sd_bus_reply_method_return(message, "hb", sd->fd, !sd->active); + if (r < 0) + session_device_free(sd); + + return r; +} + +static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + uint32_t major, minor; + SessionDevice *sd; + dev_t dev; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "uu", &major, &minor); + if (r < 0) + return r; + + if (!session_is_controller(s, sd_bus_message_get_sender(message))) + return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session"); + + dev = makedev(major, minor); + sd = hashmap_get(s->devices, &dev); + if (!sd) + return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken"); + + session_device_free(sd); + return sd_bus_reply_method_return(message, NULL); +} + +static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + uint32_t major, minor; + SessionDevice *sd; + dev_t dev; + int r; + + assert(bus); + assert(message); + assert(s); + + r = sd_bus_message_read(message, "uu", &major, &minor); + if (r < 0) + return r; + + if (!session_is_controller(s, sd_bus_message_get_sender(message))) + return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You are not in control of this session"); + + dev = makedev(major, minor); + sd = hashmap_get(s->devices, &dev); + if (!sd) + return sd_bus_error_setf(error, BUS_ERROR_DEVICE_NOT_TAKEN, "Device not taken"); + + session_device_complete_pause(sd); + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable session_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), + 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("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0), + SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0), + SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_SIGNAL("PauseDevice", "uus", 0), + SD_BUS_SIGNAL("ResumeDevice", "uuh", 0), + SD_BUS_SIGNAL("Lock", NULL, 0), + SD_BUS_SIGNAL("Unlock", NULL, 0), + + SD_BUS_VTABLE_END +}; + +int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Session *session; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + if (streq(path, "/org/freedesktop/login1/session/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_bus_message *message; + pid_t pid; + + message = sd_bus_get_current(bus); + if (!message) + return 0; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + r = manager_get_session_by_pid(m, pid, &session); + if (r <= 0) + return 0; + } else { + _cleanup_free_ char *e = NULL; + const char *p; + + p = startswith(path, "/org/freedesktop/login1/session/"); + if (!p) + return 0; + + e = sd_bus_label_unescape(p); + if (!e) + return -ENOMEM; + + session = hashmap_get(m->sessions, e); + if (!session) + return 0; + } + + *found = session; + return 1; +} + +char *session_bus_path(Session *s) { + _cleanup_free_ char *t = NULL; + + assert(s); + + t = sd_bus_label_escape(s->id); + if (!t) + return NULL; + + return strappend("/org/freedesktop/login1/session/", t); +} + +int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + Manager *m = userdata; + Session *session; + Iterator i; + int r; + + assert(bus); + assert(path); + assert(nodes); + + HASHMAP_FOREACH(session, m->sessions, i) { + char *p; + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + r = strv_push(&l, p); + if (r < 0) { + free(p); + return r; + } + } + + *nodes = l; + l = NULL; + + return 1; +} + +int session_send_signal(Session *s, bool new_session) { + _cleanup_free_ char *p = NULL; + + assert(s); + + p = session_bus_path(s); + if (!p) + return -ENOMEM; + + return sd_bus_emit_signal( + s->manager->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + new_session ? "SessionNew" : "SessionRemoved", + "so", s->id, p); +} + +int session_send_changed(Session *s, const char *properties, ...) { + _cleanup_free_ char *p = NULL; + char **l; + + assert(s); + + if (!s->started) + return 0; + + p = session_bus_path(s); + if (!p) + return -ENOMEM; + + l = strv_from_stdarg_alloca(properties); + + return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Session", l); +} + +int session_send_lock(Session *s, bool lock) { + _cleanup_free_ char *p = NULL; + + assert(s); + + p = session_bus_path(s); + if (!p) + return -ENOMEM; + + return sd_bus_emit_signal( + s->manager->bus, + p, + "org.freedesktop.login1.Session", + lock ? "Lock" : "Unlock", + NULL); +} + +int session_send_lock_all(Manager *m, bool lock) { + Session *session; + Iterator i; + int r = 0; + + assert(m); + + HASHMAP_FOREACH(session, m->sessions, i) { + int k; + + k = session_send_lock(session, lock); + if (k < 0) + r = k; + } + + return r; +} + +int session_send_create_reply(Session *s, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *c = NULL; + _cleanup_close_ int fifo_fd = -1; + _cleanup_free_ char *p = NULL; + + assert(s); + + /* This is called after the session scope and the user service + * were successfully created, and finishes where + * bus_manager_create_session() left off. */ + + if (!s->create_message) + return 0; + + if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job)) + return 0; + + c = s->create_message; + s->create_message = NULL; + + if (error) + return sd_bus_reply_method_error(c, error); + + fifo_fd = session_create_fifo(s); + if (fifo_fd < 0) + return fifo_fd; + + /* Update the session state file before we notify the client + * about the result. */ + session_save(s); + + p = session_bus_path(s); + if (!p) + return -ENOMEM; + + log_debug("Sending reply about created session: " + "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u", + s->id, + p, + s->user->runtime_path, + fifo_fd, + s->seat ? s->seat->id : "", + (uint32_t) s->vtnr); + + return sd_bus_reply_method_return( + c, "soshusub", + s->id, + p, + s->user->runtime_path, + fifo_fd, + (uint32_t) s->user->uid, + s->seat ? s->seat->id : "", + (uint32_t) s->vtnr, + false); +} diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c new file mode 100644 index 0000000..932abb8 --- /dev/null +++ b/src/login/logind-session-device.c @@ -0,0 +1,483 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 David Herrmann + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "missing.h" +#include "bus-util.h" +#include "logind-session-device.h" + +enum SessionDeviceNotifications { + SESSION_DEVICE_RESUME, + SESSION_DEVICE_TRY_PAUSE, + SESSION_DEVICE_PAUSE, + SESSION_DEVICE_RELEASE, +}; + +static int session_device_notify(SessionDevice *sd, enum SessionDeviceNotifications type) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *path = NULL; + const char *t = NULL; + uint32_t major, minor; + int r; + + assert(sd); + + major = major(sd->dev); + minor = minor(sd->dev); + + if (!sd->session->controller) + return 0; + + path = session_bus_path(sd->session); + if (!path) + return -ENOMEM; + + r = sd_bus_message_new_signal( + sd->session->manager->bus, + &m, path, + "org.freedesktop.login1.Session", + (type == SESSION_DEVICE_RESUME) ? "ResumeDevice" : "PauseDevice"); + if (!m) + return r; + + r = sd_bus_message_set_destination(m, sd->session->controller); + if (r < 0) + return r; + + switch (type) { + case SESSION_DEVICE_RESUME: + r = sd_bus_message_append(m, "uuh", major, minor, sd->fd); + if (r < 0) + return r; + break; + case SESSION_DEVICE_TRY_PAUSE: + t = "pause"; + break; + case SESSION_DEVICE_PAUSE: + t = "force"; + break; + case SESSION_DEVICE_RELEASE: + t = "gone"; + break; + default: + return -EINVAL; + } + + if (t) { + r = sd_bus_message_append(m, "uus", major, minor, t); + if (r < 0) + return r; + } + + return sd_bus_send(sd->session->manager->bus, m, NULL); +} + +static int sd_eviocrevoke(int fd) { + static bool warned; + int r; + + assert(fd >= 0); + + r = ioctl(fd, EVIOCREVOKE, 1); + if (r < 0) { + r = -errno; + if (r == -EINVAL && !warned) { + warned = true; + log_warning("kernel does not support evdev-revocation"); + } + } + + return 0; +} + +static int sd_drmsetmaster(int fd) { + int r; + + assert(fd >= 0); + + r = ioctl(fd, DRM_IOCTL_SET_MASTER, 0); + if (r < 0) + return -errno; + + return 0; +} + +static int sd_drmdropmaster(int fd) { + int r; + + assert(fd >= 0); + + r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); + if (r < 0) + return -errno; + + return 0; +} + +static int session_device_open(SessionDevice *sd, bool active) { + int fd, r; + + assert(sd->type != DEVICE_TYPE_UNKNOWN); + + /* open device and try to get an udev_device from it */ + fd = open(sd->node, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (fd < 0) + return -errno; + + switch (sd->type) { + case DEVICE_TYPE_DRM: + if (active) { + /* Weird legacy DRM semantics might return an error + * even though we're master. No way to detect that so + * fail at all times and let caller retry in inactive + * state. */ + r = sd_drmsetmaster(fd); + if (r < 0) { + close_nointr(fd); + return r; + } + } else { + /* DRM-Master is granted to the first user who opens a + * device automatically (ughh, racy!). Hence, we just + * drop DRM-Master in case we were the first. */ + sd_drmdropmaster(fd); + } + break; + case DEVICE_TYPE_EVDEV: + if (!active) + sd_eviocrevoke(fd); + break; + case DEVICE_TYPE_UNKNOWN: + default: + /* fallback for devices wihout synchronizations */ + break; + } + + return fd; +} + +static int session_device_start(SessionDevice *sd) { + int r; + + assert(sd); + assert(session_is_active(sd->session)); + + if (sd->active) + return 0; + + switch (sd->type) { + case DEVICE_TYPE_DRM: + /* Device is kept open. Simply call drmSetMaster() and hope + * there is no-one else. In case it fails, we keep the device + * paused. Maybe at some point we have a drmStealMaster(). */ + r = sd_drmsetmaster(sd->fd); + if (r < 0) + return r; + break; + case DEVICE_TYPE_EVDEV: + /* Evdev devices are revoked while inactive. Reopen it and we + * are fine. */ + r = session_device_open(sd, true); + if (r < 0) + return r; + close_nointr(sd->fd); + sd->fd = r; + break; + case DEVICE_TYPE_UNKNOWN: + default: + /* fallback for devices wihout synchronizations */ + break; + } + + sd->active = true; + return 0; +} + +static void session_device_stop(SessionDevice *sd) { + assert(sd); + + if (!sd->active) + return; + + switch (sd->type) { + case DEVICE_TYPE_DRM: + /* On DRM devices we simply drop DRM-Master but keep it open. + * This allows the user to keep resources allocated. The + * CAP_SYS_ADMIN restriction to DRM-Master prevents users from + * circumventing this. */ + sd_drmdropmaster(sd->fd); + break; + case DEVICE_TYPE_EVDEV: + /* Revoke access on evdev file-descriptors during deactivation. + * This will basically prevent any operations on the fd and + * cannot be undone. Good side is: it needs no CAP_SYS_ADMIN + * protection this way. */ + sd_eviocrevoke(sd->fd); + break; + case DEVICE_TYPE_UNKNOWN: + default: + /* fallback for devices without synchronization */ + break; + } + + sd->active = false; +} + +static DeviceType detect_device_type(struct udev_device *dev) { + const char *sysname, *subsystem; + DeviceType type; + + sysname = udev_device_get_sysname(dev); + subsystem = udev_device_get_subsystem(dev); + type = DEVICE_TYPE_UNKNOWN; + + if (streq_ptr(subsystem, "drm")) { + if (startswith(sysname, "card")) + type = DEVICE_TYPE_DRM; + } else if (streq_ptr(subsystem, "input")) { + if (startswith(sysname, "event")) + type = DEVICE_TYPE_EVDEV; + } + + return type; +} + +static int session_device_verify(SessionDevice *sd) { + struct udev_device *dev, *p = NULL; + const char *sp, *node; + int r; + + dev = udev_device_new_from_devnum(sd->session->manager->udev, 'c', sd->dev); + if (!dev) + return -ENODEV; + + sp = udev_device_get_syspath(dev); + node = udev_device_get_devnode(dev); + if (!node) { + r = -EINVAL; + goto err_dev; + } + + /* detect device type so we can find the correct sysfs parent */ + sd->type = detect_device_type(dev); + if (sd->type == DEVICE_TYPE_UNKNOWN) { + r = -ENODEV; + goto err_dev; + } else if (sd->type == DEVICE_TYPE_EVDEV) { + /* for evdev devices we need the parent node as device */ + p = dev; + dev = udev_device_get_parent_with_subsystem_devtype(p, "input", NULL); + if (!dev) { + r = -ENODEV; + goto err_dev; + } + sp = udev_device_get_syspath(dev); + } else if (sd->type != DEVICE_TYPE_DRM) { + /* Prevent opening unsupported devices. Especially devices of + * subsystem "input" must be opened via the evdev node as + * we require EVIOCREVOKE. */ + r = -ENODEV; + goto err_dev; + } + + /* search for an existing seat device and return it if available */ + sd->device = hashmap_get(sd->session->manager->devices, sp); + if (!sd->device) { + /* The caller might have gotten the udev event before we were + * able to process it. Hence, fake the "add" event and let the + * logind-manager handle the new device. */ + r = manager_process_seat_device(sd->session->manager, dev); + if (r < 0) + goto err_dev; + + /* if it's still not available, then the device is invalid */ + sd->device = hashmap_get(sd->session->manager->devices, sp); + if (!sd->device) { + r = -ENODEV; + goto err_dev; + } + } + + if (sd->device->seat != sd->session->seat) { + r = -EPERM; + goto err_dev; + } + + sd->node = strdup(node); + if (!sd->node) { + r = -ENOMEM; + goto err_dev; + } + + r = 0; +err_dev: + udev_device_unref(p ? : dev); + return r; +} + +int session_device_new(Session *s, dev_t dev, SessionDevice **out) { + SessionDevice *sd; + int r; + + assert(s); + assert(out); + + if (!s->seat) + return -EPERM; + + sd = new0(SessionDevice, 1); + if (!sd) + return -ENOMEM; + + sd->session = s; + sd->dev = dev; + sd->fd = -1; + sd->type = DEVICE_TYPE_UNKNOWN; + + r = session_device_verify(sd); + if (r < 0) + goto error; + + r = hashmap_put(s->devices, &sd->dev, sd); + if (r < 0) { + r = -ENOMEM; + goto error; + } + + /* Open the device for the first time. We need a valid fd to pass back + * to the caller. If the session is not active, this _might_ immediately + * revoke access and thus invalidate the fd. But this is still needed + * to pass a valid fd back. */ + sd->active = session_is_active(s); + r = session_device_open(sd, sd->active); + if (r < 0) { + /* EINVAL _may_ mean a master is active; retry inactive */ + if (sd->active && r == -EINVAL) { + sd->active = false; + r = session_device_open(sd, false); + } + if (r < 0) + goto error; + } + sd->fd = r; + + LIST_PREPEND(sd_by_device, sd->device->session_devices, sd); + + *out = sd; + return 0; + +error: + hashmap_remove(s->devices, &sd->dev); + free(sd->node); + free(sd); + return r; +} + +void session_device_free(SessionDevice *sd) { + assert(sd); + + session_device_stop(sd); + session_device_notify(sd, SESSION_DEVICE_RELEASE); + close_nointr(sd->fd); + + LIST_REMOVE(sd_by_device, sd->device->session_devices, sd); + + hashmap_remove(sd->session->devices, &sd->dev); + + free(sd->node); + free(sd); +} + +void session_device_complete_pause(SessionDevice *sd) { + SessionDevice *iter; + Iterator i; + + if (!sd->active) + return; + + session_device_stop(sd); + + /* if not all devices are paused, wait for further completion events */ + HASHMAP_FOREACH(iter, sd->session->devices, i) + if (iter->active) + return; + + /* complete any pending session switch */ + seat_complete_switch(sd->session->seat); +} + +void session_device_resume_all(Session *s) { + SessionDevice *sd; + Iterator i; + int r; + + assert(s); + + HASHMAP_FOREACH(sd, s->devices, i) { + if (!sd->active) { + r = session_device_start(sd); + if (!r) + session_device_notify(sd, SESSION_DEVICE_RESUME); + } + } +} + +void session_device_pause_all(Session *s) { + SessionDevice *sd; + Iterator i; + + assert(s); + + HASHMAP_FOREACH(sd, s->devices, i) { + if (sd->active) { + session_device_stop(sd); + session_device_notify(sd, SESSION_DEVICE_PAUSE); + } + } +} + +unsigned int session_device_try_pause_all(Session *s) { + SessionDevice *sd; + Iterator i; + unsigned int num_pending = 0; + + assert(s); + + HASHMAP_FOREACH(sd, s->devices, i) { + if (sd->active) { + session_device_notify(sd, SESSION_DEVICE_TRY_PAUSE); + ++num_pending; + } + } + + return num_pending; +} diff --git a/src/login/logind-session-device.h b/src/login/logind-session-device.h new file mode 100644 index 0000000..61a843d --- /dev/null +++ b/src/login/logind-session-device.h @@ -0,0 +1,59 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 David Herrmann + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef enum DeviceType DeviceType; +typedef struct SessionDevice SessionDevice; + +#include "list.h" +#include "util.h" +#include "logind.h" +#include "logind-device.h" +#include "logind-seat.h" +#include "logind-session.h" + +enum DeviceType { + DEVICE_TYPE_UNKNOWN, + DEVICE_TYPE_DRM, + DEVICE_TYPE_EVDEV, +}; + +struct SessionDevice { + Session *session; + Device *device; + + dev_t dev; + char *node; + int fd; + bool active; + DeviceType type; + + LIST_FIELDS(struct SessionDevice, sd_by_device); +}; + +int session_device_new(Session *s, dev_t dev, SessionDevice **out); +void session_device_free(SessionDevice *sd); +void session_device_complete_pause(SessionDevice *sd); + +void session_device_resume_all(Session *s); +void session_device_pause_all(Session *s); +unsigned int session_device_try_pause_all(Session *s); diff --git a/src/login/logind-session.c b/src/login/logind-session.c new file mode 100644 index 0000000..548f049 --- /dev/null +++ b/src/login/logind-session.c @@ -0,0 +1,1140 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "strv.h" +#include "util.h" +#include "mkdir.h" +#include "path-util.h" +#include "fileio.h" +#include "audit.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind-session.h" + +#define RELEASE_USEC (20*USEC_PER_SEC) + +static void session_remove_fifo(Session *s); + +static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u = *(const dev_t*)p; + + return uint64_hash_func(&u, hash_key); +} + +static int devt_compare_func(const void *_a, const void *_b) { + dev_t a, b; + + a = *(const dev_t*) _a; + b = *(const dev_t*) _b; + + return a < b ? -1 : (a > b ? 1 : 0); +} + +Session* session_new(Manager *m, const char *id) { + Session *s; + + assert(m); + assert(id); + assert(session_id_valid(id)); + + s = new0(Session, 1); + if (!s) + return NULL; + + s->state_file = strappend("/run/systemd/sessions/", id); + if (!s->state_file) { + free(s); + return NULL; + } + + s->devices = hashmap_new(devt_hash_func, devt_compare_func); + if (!s->devices) { + free(s->state_file); + free(s); + return NULL; + } + + s->id = basename(s->state_file); + + if (hashmap_put(m->sessions, s->id, s) < 0) { + hashmap_free(s->devices); + free(s->state_file); + free(s); + return NULL; + } + + s->manager = m; + s->fifo_fd = -1; + s->vtfd = -1; + + return s; +} + +void session_free(Session *s) { + SessionDevice *sd; + + assert(s); + + if (s->in_gc_queue) + LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + session_remove_fifo(s); + + session_drop_controller(s); + + while ((sd = hashmap_first(s->devices))) + session_device_free(sd); + + hashmap_free(s->devices); + + if (s->user) { + LIST_REMOVE(sessions_by_user, s->user->sessions, s); + + if (s->user->display == s) + s->user->display = NULL; + } + + if (s->seat) { + if (s->seat->active == s) + s->seat->active = NULL; + if (s->seat->pending_switch == s) + s->seat->pending_switch = NULL; + + seat_evict_position(s->seat, s); + LIST_REMOVE(sessions_by_seat, s->seat->sessions, s); + } + + if (s->scope) { + hashmap_remove(s->manager->session_units, s->scope); + free(s->scope); + } + + free(s->scope_job); + + sd_bus_message_unref(s->create_message); + + free(s->tty); + free(s->display); + free(s->remote_host); + free(s->remote_user); + free(s->service); + free(s->desktop); + + hashmap_remove(s->manager->sessions, s->id); + + s->vt_source = sd_event_source_unref(s->vt_source); + + free(s->state_file); + free(s); +} + +void session_set_user(Session *s, User *u) { + assert(s); + assert(!s->user); + + s->user = u; + LIST_PREPEND(sessions_by_user, u->sessions, s); +} + +int session_save(Session *s) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r = 0; + + assert(s); + + if (!s->user) + return -ESTALE; + + if (!s->started) + return 0; + + r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0); + if (r < 0) + goto finish; + + r = fopen_temporary(s->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + assert(s->user); + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "UID="UID_FMT"\n" + "USER=%s\n" + "ACTIVE=%i\n" + "STATE=%s\n" + "REMOTE=%i\n", + s->user->uid, + s->user->name, + session_is_active(s), + session_state_to_string(session_get_state(s)), + s->remote); + + if (s->type >= 0) + fprintf(f, "TYPE=%s\n", session_type_to_string(s->type)); + + if (s->class >= 0) + fprintf(f, "CLASS=%s\n", session_class_to_string(s->class)); + + if (s->scope) + fprintf(f, "SCOPE=%s\n", s->scope); + + if (s->scope_job) + fprintf(f, "SCOPE_JOB=%s\n", s->scope_job); + + if (s->fifo_path) + fprintf(f, "FIFO=%s\n", s->fifo_path); + + if (s->seat) + fprintf(f, "SEAT=%s\n", s->seat->id); + + if (s->tty) + fprintf(f, "TTY=%s\n", s->tty); + + if (s->display) + fprintf(f, "DISPLAY=%s\n", s->display); + + if (s->remote_host) + fprintf(f, "REMOTE_HOST=%s\n", s->remote_host); + + if (s->remote_user) + fprintf(f, "REMOTE_USER=%s\n", s->remote_user); + + if (s->service) + fprintf(f, "SERVICE=%s\n", s->service); + + if (s->desktop) + fprintf(f, "DESKTOP=%s\n", s->desktop); + + if (s->seat && seat_has_vts(s->seat)) + fprintf(f, "VTNR=%u\n", s->vtnr); + + if (!s->vtnr) + fprintf(f, "POS=%u\n", s->pos); + + if (s->leader > 0) + fprintf(f, "LEADER="PID_FMT"\n", s->leader); + + if (s->audit_id > 0) + fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id); + + if (dual_timestamp_is_set(&s->timestamp)) + fprintf(f, + "REALTIME="USEC_FMT"\n" + "MONOTONIC="USEC_FMT"\n", + s->timestamp.realtime, + s->timestamp.monotonic); + + if (s->controller) + fprintf(f, "CONTROLLER=%s\n", s->controller); + + fflush(f); + + if (ferror(f) || rename(temp_path, s->state_file) < 0) { + r = -errno; + unlink(s->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save session data %s: %s", s->state_file, strerror(-r)); + + return r; +} + +int session_load(Session *s) { + _cleanup_free_ char *remote = NULL, + *seat = NULL, + *vtnr = NULL, + *pos = NULL, + *leader = NULL, + *type = NULL, + *class = NULL, + *uid = NULL, + *realtime = NULL, + *monotonic = NULL, + *controller = NULL; + + int k, r; + + assert(s); + + r = parse_env_file(s->state_file, NEWLINE, + "REMOTE", &remote, + "SCOPE", &s->scope, + "SCOPE_JOB", &s->scope_job, + "FIFO", &s->fifo_path, + "SEAT", &seat, + "TTY", &s->tty, + "DISPLAY", &s->display, + "REMOTE_HOST", &s->remote_host, + "REMOTE_USER", &s->remote_user, + "SERVICE", &s->service, + "DESKTOP", &s->desktop, + "VTNR", &vtnr, + "POS", &pos, + "LEADER", &leader, + "TYPE", &type, + "CLASS", &class, + "UID", &uid, + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + "CONTROLLER", &controller, + NULL); + + if (r < 0) { + log_error("Failed to read %s: %s", s->state_file, strerror(-r)); + return r; + } + + if (!s->user) { + uid_t u; + User *user; + + if (!uid) { + log_error("UID not specified for session %s", s->id); + return -ENOENT; + } + + r = parse_uid(uid, &u); + if (r < 0) { + log_error("Failed to parse UID value %s for session %s.", uid, s->id); + return r; + } + + user = hashmap_get(s->manager->users, ULONG_TO_PTR((unsigned long) u)); + if (!user) { + log_error("User of session %s not known.", s->id); + return -ENOENT; + } + + session_set_user(s, user); + } + + if (remote) { + k = parse_boolean(remote); + if (k >= 0) + s->remote = k; + } + + if (vtnr) + safe_atou(vtnr, &s->vtnr); + + if (seat && !s->seat) { + Seat *o; + + o = hashmap_get(s->manager->seats, seat); + if (o) + r = seat_attach_session(o, s); + if (!o || r < 0) + log_error("Cannot attach session %s to seat %s", s->id, seat); + } + + if (!s->seat || !seat_has_vts(s->seat)) + s->vtnr = 0; + + if (pos && s->seat) { + unsigned int npos; + + safe_atou(pos, &npos); + seat_claim_position(s->seat, s, npos); + } + + if (leader) { + k = parse_pid(leader, &s->leader); + if (k >= 0) + audit_session_from_pid(s->leader, &s->audit_id); + } + + if (type) { + SessionType t; + + t = session_type_from_string(type); + if (t >= 0) + s->type = t; + } + + if (class) { + SessionClass c; + + c = session_class_from_string(class); + if (c >= 0) + s->class = c; + } + + if (s->fifo_path) { + int fd; + + /* If we open an unopened pipe for reading we will not + get an EOF. to trigger an EOF we hence open it for + reading, but close it right-away which then will + trigger the EOF. */ + + fd = session_create_fifo(s); + if (fd >= 0) + close_nointr_nofail(fd); + } + + if (realtime) { + unsigned long long l; + if (sscanf(realtime, "%llu", &l) > 0) + s->timestamp.realtime = l; + } + + if (monotonic) { + unsigned long long l; + if (sscanf(monotonic, "%llu", &l) > 0) + s->timestamp.monotonic = l; + } + + if (controller) { + if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) + session_set_controller(s, controller, false); + else + session_restore_vt(s); + } + + return r; +} + +int session_activate(Session *s) { + unsigned int num_pending; + + assert(s); + assert(s->user); + + if (!s->seat) + return -ENOTSUP; + + if (s->seat->active == s) + return 0; + + /* on seats with VTs, we let VTs manage session-switching */ + if (seat_has_vts(s->seat)) { + if (!s->vtnr) + return -ENOTSUP; + + return chvt(s->vtnr); + } + + /* On seats without VTs, we implement session-switching in logind. We + * try to pause all session-devices and wait until the session + * controller acknowledged them. Once all devices are asleep, we simply + * switch the active session and be done. + * We save the session we want to switch to in seat->pending_switch and + * seat_complete_switch() will perform the final switch. */ + + s->seat->pending_switch = s; + + /* if no devices are running, immediately perform the session switch */ + num_pending = session_device_try_pause_all(s); + if (!num_pending) + seat_complete_switch(s->seat); + + return 0; +} + +static int session_start_scope(Session *s) { + int r; + + assert(s); + assert(s->user); + assert(s->user->slice); + + if (!s->scope) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *description = NULL; + char *scope, *job = NULL; + + description = strjoin("Session ", s->id, " of user ", s->user->name, NULL); + if (!description) + return log_oom(); + + scope = strjoin("session-", s->id, ".scope", NULL); + if (!scope) + return log_oom(); + + r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-session.service", &error, &job); + if (r < 0) { + log_error("Failed to start session scope %s: %s %s", + scope, bus_error_message(&error, r), error.name); + free(scope); + return r; + } else { + s->scope = scope; + + free(s->scope_job); + s->scope_job = job; + } + } + + if (s->scope) + hashmap_put(s->manager->session_units, s->scope, s); + + return 0; +} + +int session_start(Session *s) { + int r; + + assert(s); + + if (!s->user) + return -ESTALE; + + if (s->started) + return 0; + + r = user_start(s->user); + if (r < 0) + return r; + + /* Create cgroup */ + r = session_start_scope(s); + if (r < 0) + return r; + + log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SESSION_START), + "SESSION_ID=%s", s->id, + "USER_ID=%s", s->user->name, + "LEADER=%lu", (unsigned long) s->leader, + "MESSAGE=New session %s of user %s.", s->id, s->user->name, + NULL); + + if (!dual_timestamp_is_set(&s->timestamp)) + dual_timestamp_get(&s->timestamp); + + if (s->seat) + seat_read_active_vt(s->seat); + + s->started = true; + + /* Save data */ + session_save(s); + user_save(s->user); + if (s->seat) + seat_save(s->seat); + + /* Send signals */ + session_send_signal(s, true); + user_send_changed(s->user, "Sessions", NULL); + if (s->seat) { + if (s->seat->active == s) + seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL); + else + seat_send_changed(s->seat, "Sessions", NULL); + } + + return 0; +} + +static int session_stop_scope(Session *s, bool force) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char *job = NULL; + int r; + + assert(s); + + if (!s->scope) + return 0; + + if (force || manager_shall_kill(s->manager, s->user->name)) { + r = manager_stop_unit(s->manager, s->scope, &error, &job); + if (r < 0) { + log_error("Failed to stop session scope: %s", bus_error_message(&error, r)); + return r; + } + + free(s->scope_job); + s->scope_job = job; + } else { + r = manager_abandon_scope(s->manager, s->scope, &error); + if (r < 0) { + log_error("Failed to abandon session scope: %s", bus_error_message(&error, r)); + return r; + } + } + + return 0; +} + +int session_stop(Session *s, bool force) { + int r; + + assert(s); + + if (!s->user) + return -ESTALE; + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + /* We are going down, don't care about FIFOs anymore */ + session_remove_fifo(s); + + /* Kill cgroup */ + r = session_stop_scope(s, force); + + s->stopping = true; + + session_save(s); + user_save(s->user); + + return r; +} + +int session_finalize(Session *s) { + int r = 0; + SessionDevice *sd; + + assert(s); + + if (!s->user) + return -ESTALE; + + if (s->started) + log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SESSION_STOP), + "SESSION_ID=%s", s->id, + "USER_ID=%s", s->user->name, + "LEADER=%lu", (unsigned long) s->leader, + "MESSAGE=Removed session %s.", s->id, + NULL); + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + + /* Kill session devices */ + while ((sd = hashmap_first(s->devices))) + session_device_free(sd); + + unlink(s->state_file); + session_add_to_gc_queue(s); + user_add_to_gc_queue(s->user); + + if (s->started) { + session_send_signal(s, false); + s->started = false; + } + + if (s->seat) { + if (s->seat->active == s) + seat_set_active(s->seat, NULL); + + seat_save(s->seat); + seat_send_changed(s->seat, "Sessions", NULL); + } + + user_save(s->user); + user_send_changed(s->user, "Sessions", NULL); + + return r; +} + +static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) { + Session *s = userdata; + + assert(es); + assert(s); + + session_stop(s, false); + return 0; +} + +void session_release(Session *s) { + assert(s); + + if (!s->started || s->stopping) + return; + + if (!s->timer_event_source) + sd_event_add_monotonic(s->manager->event, &s->timer_event_source, now(CLOCK_MONOTONIC) + RELEASE_USEC, 0, release_timeout_callback, s); +} + +bool session_is_active(Session *s) { + assert(s); + + if (!s->seat) + return true; + + return s->seat->active == s; +} + +static int get_tty_atime(const char *tty, usec_t *atime) { + _cleanup_free_ char *p = NULL; + struct stat st; + + assert(tty); + assert(atime); + + if (!path_is_absolute(tty)) { + p = strappend("/dev/", tty); + if (!p) + return -ENOMEM; + + tty = p; + } else if (!path_startswith(tty, "/dev/")) + return -ENOENT; + + if (lstat(tty, &st) < 0) + return -errno; + + *atime = timespec_load(&st.st_atim); + return 0; +} + +static int get_process_ctty_atime(pid_t pid, usec_t *atime) { + _cleanup_free_ char *p = NULL; + int r; + + assert(pid > 0); + assert(atime); + + r = get_ctty(pid, NULL, &p); + if (r < 0) + return r; + + return get_tty_atime(p, atime); +} + +int session_get_idle_hint(Session *s, dual_timestamp *t) { + usec_t atime = 0, n; + int r; + + assert(s); + + /* Explicit idle hint is set */ + if (s->idle_hint) { + if (t) + *t = s->idle_hint_timestamp; + + return s->idle_hint; + } + + /* Graphical sessions should really implement a real + * idle hint logic */ + if (s->display) + goto dont_know; + + /* For sessions with an explicitly configured tty, let's check + * its atime */ + if (s->tty) { + r = get_tty_atime(s->tty, &atime); + if (r >= 0) + goto found_atime; + } + + /* For sessions with a leader but no explicitly configured + * tty, let's check the controlling tty of the leader */ + if (s->leader > 0) { + r = get_process_ctty_atime(s->leader, &atime); + if (r >= 0) + goto found_atime; + } + +dont_know: + if (t) + *t = s->idle_hint_timestamp; + + return 0; + +found_atime: + if (t) + dual_timestamp_from_realtime(t, atime); + + n = now(CLOCK_REALTIME); + + if (s->manager->idle_action_usec <= 0) + return 0; + + return atime + s->manager->idle_action_usec <= n; +} + +void session_set_idle_hint(Session *s, bool b) { + assert(s); + + if (s->idle_hint == b) + return; + + s->idle_hint = b; + dual_timestamp_get(&s->idle_hint_timestamp); + + session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); + + if (s->seat) + seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); + + user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); + manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); +} + +static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Session *s = userdata; + + assert(s); + assert(s->fifo_fd == fd); + + /* EOF on the FIFO means the session died abnormally. */ + + session_remove_fifo(s); + session_stop(s, false); + + return 1; +} + +int session_create_fifo(Session *s) { + int r; + + assert(s); + + /* Create FIFO */ + if (!s->fifo_path) { + r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0); + if (r < 0) + return r; + + if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0) + return -ENOMEM; + + if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST) + return -errno; + } + + /* Open reading side */ + if (s->fifo_fd < 0) { + s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY); + if (s->fifo_fd < 0) + return -errno; + + } + + if (!s->fifo_event_source) { + r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + return r; + } + + /* Open writing side */ + r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY); + if (r < 0) + return -errno; + + return r; +} + +static void session_remove_fifo(Session *s) { + assert(s); + + if (s->fifo_event_source) + s->fifo_event_source = sd_event_source_unref(s->fifo_event_source); + + if (s->fifo_fd >= 0) { + close_nointr_nofail(s->fifo_fd); + s->fifo_fd = -1; + } + + if (s->fifo_path) { + unlink(s->fifo_path); + free(s->fifo_path); + s->fifo_path = NULL; + } +} + +bool session_check_gc(Session *s, bool drop_not_started) { + assert(s); + + if (drop_not_started && !s->started) + return false; + + if (!s->user) + return false; + + if (s->fifo_fd >= 0) { + if (pipe_eof(s->fifo_fd) <= 0) + return true; + } + + if (s->scope_job && manager_job_is_active(s->manager, s->scope_job)) + return true; + + if (s->scope && manager_unit_is_active(s->manager, s->scope)) + return true; + + return false; +} + +void session_add_to_gc_queue(Session *s) { + assert(s); + + if (s->in_gc_queue) + return; + + LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s); + s->in_gc_queue = true; +} + +SessionState session_get_state(Session *s) { + assert(s); + + /* always check closing first */ + if (s->stopping || s->timer_event_source) + return SESSION_CLOSING; + + if (s->scope_job || s->fifo_fd < 0) + return SESSION_OPENING; + + if (session_is_active(s)) + return SESSION_ACTIVE; + + return SESSION_ONLINE; +} + +int session_kill(Session *s, KillWho who, int signo) { + assert(s); + + if (!s->scope) + return -ESRCH; + + return manager_kill_unit(s->manager, s->scope, who, signo, NULL); +} + +static int session_open_vt(Session *s) { + char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)]; + + if (!s->vtnr) + return -1; + + if (s->vtfd >= 0) + return s->vtfd; + + sprintf(path, "/dev/tty%u", s->vtnr); + s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); + if (s->vtfd < 0) { + log_error("cannot open VT %s of session %s: %m", path, s->id); + return -1; + } + + return s->vtfd; +} + +static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) { + Session *s = data; + + if (s->vtfd >= 0) + ioctl(s->vtfd, VT_RELDISP, 1); + + return 0; +} + +void session_mute_vt(Session *s) { + int vt, r; + struct vt_mode mode = { 0 }; + sigset_t mask; + + vt = session_open_vt(s); + if (vt < 0) + return; + + r = ioctl(vt, KDSKBMODE, K_OFF); + if (r < 0) + goto error; + + r = ioctl(vt, KDSETMODE, KD_GRAPHICS); + if (r < 0) + goto error; + + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, NULL); + + r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s); + if (r < 0) + goto error; + + /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS. + * So we need a dummy handler here which just acknowledges *all* VT + * switch requests. */ + mode.mode = VT_PROCESS; + mode.relsig = SIGUSR1; + mode.acqsig = SIGUSR1; + r = ioctl(vt, VT_SETMODE, &mode); + if (r < 0) + goto error; + + return; + +error: + log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno); + session_restore_vt(s); +} + +void session_restore_vt(Session *s) { + _cleanup_free_ char *utf8 = NULL; + int vt, kb = K_XLATE; + struct vt_mode mode = { 0 }; + + vt = session_open_vt(s); + if (vt < 0) + return; + + s->vt_source = sd_event_source_unref(s->vt_source); + + ioctl(vt, KDSETMODE, KD_TEXT); + + if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1') + kb = K_UNICODE; + ioctl(vt, KDSKBMODE, kb); + + mode.mode = VT_AUTO; + ioctl(vt, VT_SETMODE, &mode); + + close_nointr_nofail(vt); + s->vtfd = -1; +} + +bool session_is_controller(Session *s, const char *sender) { + assert(s); + + return streq_ptr(s->controller, sender); +} + +static void session_swap_controller(Session *s, char *name) { + SessionDevice *sd; + + if (s->controller) { + manager_drop_busname(s->manager, s->controller); + free(s->controller); + s->controller = NULL; + + /* Drop all devices as they're now unused. Do that after the + * controller is released to avoid sending out useles + * dbus signals. */ + while ((sd = hashmap_first(s->devices))) + session_device_free(sd); + + if (!name) + session_restore_vt(s); + } + + s->controller = name; + session_save(s); +} + +int session_set_controller(Session *s, const char *sender, bool force) { + char *t; + int r; + + assert(s); + assert(sender); + + if (session_is_controller(s, sender)) + return 0; + if (s->controller && !force) + return -EBUSY; + + t = strdup(sender); + if (!t) + return -ENOMEM; + + r = manager_watch_busname(s->manager, sender); + if (r) { + free(t); + return r; + } + + session_swap_controller(s, t); + + /* When setting a session controller, we forcibly mute the VT and set + * it into graphics-mode. Applications can override that by changing + * VT state after calling TakeControl(). However, this serves as a good + * default and well-behaving controllers can now ignore VTs entirely. + * Note that we reset the VT on ReleaseControl() and if the controller + * exits. + * If logind crashes/restarts, we restore the controller during restart + * or reset the VT in case it crashed/exited, too. */ + session_mute_vt(s); + + return 0; +} + +void session_drop_controller(Session *s) { + assert(s); + + if (!s->controller) + return; + + session_swap_controller(s, NULL); +} + +static const char* const session_state_table[_SESSION_STATE_MAX] = { + [SESSION_OPENING] = "opening", + [SESSION_ONLINE] = "online", + [SESSION_ACTIVE] = "active", + [SESSION_CLOSING] = "closing" +}; + +DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState); + +static const char* const session_type_table[_SESSION_TYPE_MAX] = { + [SESSION_TTY] = "tty", + [SESSION_X11] = "x11", + [SESSION_WAYLAND] = "wayland", + [SESSION_UNSPECIFIED] = "unspecified", +}; + +DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType); + +static const char* const session_class_table[_SESSION_CLASS_MAX] = { + [SESSION_USER] = "user", + [SESSION_GREETER] = "greeter", + [SESSION_LOCK_SCREEN] = "lock-screen", + [SESSION_BACKGROUND] = "background" +}; + +DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass); + +static const char* const kill_who_table[_KILL_WHO_MAX] = { + [KILL_LEADER] = "leader", + [KILL_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/login/logind-session.h b/src/login/logind-session.h new file mode 100644 index 0000000..c9af5eb --- /dev/null +++ b/src/login/logind-session.h @@ -0,0 +1,177 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Session Session; +typedef enum KillWho KillWho; + +#include "list.h" +#include "util.h" +#include "logind.h" +#include "logind-seat.h" +#include "logind-session-device.h" +#include "logind-user.h" +#include "login-shared.h" + +typedef enum SessionState { + SESSION_OPENING, /* Session scope is being created */ + SESSION_ONLINE, /* Logged in */ + SESSION_ACTIVE, /* Logged in and in the fg */ + SESSION_CLOSING, /* Logged out, but scope is still there */ + _SESSION_STATE_MAX, + _SESSION_STATE_INVALID = -1 +} SessionState; + +typedef enum SessionClass { + SESSION_USER, + SESSION_GREETER, + SESSION_LOCK_SCREEN, + SESSION_BACKGROUND, + _SESSION_CLASS_MAX, + _SESSION_CLASS_INVALID = -1 +} SessionClass; + +typedef enum SessionType { + SESSION_UNSPECIFIED, + SESSION_TTY, + SESSION_X11, + SESSION_WAYLAND, + _SESSION_TYPE_MAX, + _SESSION_TYPE_INVALID = -1 +} SessionType; + +enum KillWho { + KILL_LEADER, + KILL_ALL, + _KILL_WHO_MAX, + _KILL_WHO_INVALID = -1 +}; + +struct Session { + Manager *manager; + + char *id; + unsigned int pos; + SessionType type; + SessionClass class; + + char *state_file; + + User *user; + + dual_timestamp timestamp; + + char *tty; + char *display; + + bool remote; + char *remote_user; + char *remote_host; + char *service; + char *desktop; + + char *scope; + char *scope_job; + + Seat *seat; + unsigned int vtnr; + int vtfd; + sd_event_source *vt_source; + + pid_t leader; + uint32_t audit_id; + + int fifo_fd; + char *fifo_path; + + sd_event_source *fifo_event_source; + + bool idle_hint; + dual_timestamp idle_hint_timestamp; + + bool in_gc_queue:1; + bool started:1; + bool stopping:1; + + sd_bus_message *create_message; + + sd_event_source *timer_event_source; + + char *controller; + Hashmap *devices; + + LIST_FIELDS(Session, sessions_by_user); + LIST_FIELDS(Session, sessions_by_seat); + + LIST_FIELDS(Session, gc_queue); +}; + +Session *session_new(Manager *m, const char *id); +void session_free(Session *s); +void session_set_user(Session *s, User *u); +bool session_check_gc(Session *s, bool drop_not_started); +void session_add_to_gc_queue(Session *s); +int session_activate(Session *s); +bool session_is_active(Session *s); +int session_get_idle_hint(Session *s, dual_timestamp *t); +void session_set_idle_hint(Session *s, bool b); +int session_create_fifo(Session *s); +int session_start(Session *s); +int session_stop(Session *s, bool force); +int session_finalize(Session *s); +void session_release(Session *s); +int session_save(Session *s); +int session_load(Session *s); +int session_kill(Session *s, KillWho who, int signo); + +SessionState session_get_state(Session *u); + +extern const sd_bus_vtable session_vtable[]; +int session_node_enumerator(sd_bus *bus, const char *path,void *userdata, char ***nodes, sd_bus_error *error); +int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *session_bus_path(Session *s); + +int session_send_signal(Session *s, bool new_session); +int session_send_changed(Session *s, const char *properties, ...) _sentinel_; +int session_send_lock(Session *s, bool lock); +int session_send_lock_all(Manager *m, bool lock); + +int session_send_create_reply(Session *s, sd_bus_error *error); + +const char* session_state_to_string(SessionState t) _const_; +SessionState session_state_from_string(const char *s) _pure_; + +const char* session_type_to_string(SessionType t) _const_; +SessionType session_type_from_string(const char *s) _pure_; + +const char* session_class_to_string(SessionClass t) _const_; +SessionClass session_class_from_string(const char *s) _pure_; + +const char *kill_who_to_string(KillWho k) _const_; +KillWho kill_who_from_string(const char *s) _pure_; + +void session_mute_vt(Session *s); +void session_restore_vt(Session *s); + +bool session_is_controller(Session *s, const char *sender); +int session_set_controller(Session *s, const char *sender, bool force); +void session_drop_controller(Session *s); diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c new file mode 100644 index 0000000..18eea89 --- /dev/null +++ b/src/login/logind-user-dbus.c @@ -0,0 +1,364 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "strv.h" +#include "bus-util.h" +#include "logind.h" +#include "logind-user.h" + +static int property_get_display( + 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 *p = NULL; + User *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + p = u->display ? session_bus_path(u->display) : strdup("/"); + if (!p) + return -ENOMEM; + + return sd_bus_message_append(reply, "(so)", u->display ? u->display->id : "", p); +} + +static int property_get_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + User *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "s", user_state_to_string(user_get_state(u))); +} + +static int property_get_sessions( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + User *u = userdata; + Session *session; + int r; + + assert(bus); + assert(reply); + assert(u); + + r = sd_bus_message_open_container(reply, 'a', "(so)"); + if (r < 0) + return r; + + LIST_FOREACH(sessions_by_user, session, u->sessions) { + _cleanup_free_ char *p = NULL; + + p = session_bus_path(session); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(so)", session->id, p); + if (r < 0) + return r; + + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return 1; +} + +static int property_get_idle_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + User *u = userdata; + + assert(bus); + assert(reply); + assert(u); + + return sd_bus_message_append(reply, "b", user_get_idle_hint(u, NULL) > 0); +} + +static int property_get_idle_since_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + User *u = userdata; + dual_timestamp t; + uint64_t k; + + assert(bus); + assert(reply); + assert(u); + + user_get_idle_hint(u, &t); + k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; + + return sd_bus_message_append(reply, "t", k); +} + +static int property_get_linger( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + User *u = userdata; + int r; + + assert(bus); + assert(reply); + assert(u); + + r = user_check_linger_file(u); + + return sd_bus_message_append(reply, "b", r > 0); +} + +static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + User *u = userdata; + int r; + + assert(bus); + assert(message); + assert(u); + + r = user_stop(u, true); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + User *u = userdata; + int32_t signo; + int r; + + assert(bus); + assert(message); + assert(u); + + r = sd_bus_message_read(message, "i", &signo); + if (r < 0) + return r; + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + r = user_kill(u, signo); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable user_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(User, uid), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(User, gid), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Name", "s", NULL, offsetof(User, name), SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + 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_PROPERTY("Linger", "b", property_get_linger, 0, 0), + + SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("Kill", "i", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + + SD_BUS_VTABLE_END +}; + +int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + User *user; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + if (streq(path, "/org/freedesktop/login1/user/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_bus_message *message; + pid_t pid; + + message = sd_bus_get_current(bus); + if (!message) + return 0; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + r = manager_get_user_by_pid(m, pid, &user); + if (r <= 0) + return 0; + } else { + unsigned long lu; + const char *p; + + p = startswith(path, "/org/freedesktop/login1/user/_"); + if (!p) + return 0; + + r = safe_atolu(p, &lu); + if (r < 0) + return 0; + + user = hashmap_get(m->users, ULONG_TO_PTR(lu)); + if (!user) + return 0; + } + + *found = user; + return 1; +} + +char *user_bus_path(User *u) { + char *s; + + assert(u); + + if (asprintf(&s, "/org/freedesktop/login1/user/_%llu", (unsigned long long) u->uid) < 0) + return NULL; + + return s; +} + +int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + Manager *m = userdata; + User *user; + Iterator i; + int r; + + assert(bus); + assert(path); + assert(nodes); + + HASHMAP_FOREACH(user, m->users, i) { + char *p; + + p = user_bus_path(user); + if (!p) + return -ENOMEM; + + r = strv_push(&l, p); + if (r < 0) { + free(p); + return r; + } + } + + *nodes = l; + l = NULL; + + return 1; +} + +int user_send_signal(User *u, bool new_user) { + _cleanup_free_ char *p = NULL; + + assert(u); + + p = user_bus_path(u); + if (!p) + return -ENOMEM; + + return sd_bus_emit_signal( + u->manager->bus, + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + new_user ? "UserNew" : "UserRemoved", + "uo", (uint32_t) u->uid, p); +} + +int user_send_changed(User *u, const char *properties, ...) { + _cleanup_free_ char *p = NULL; + char **l; + + assert(u); + + if (!u->started) + return 0; + + p = user_bus_path(u); + if (!p) + return -ENOMEM; + + l = strv_from_stdarg_alloca(properties); + + return sd_bus_emit_properties_changed_strv(u->manager->bus, p, "org.freedesktop.login1.User", l); +} diff --git a/src/login/logind-user.c b/src/login/logind-user.c new file mode 100644 index 0000000..4af0e90 --- /dev/null +++ b/src/login/logind-user.c @@ -0,0 +1,693 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "hashmap.h" +#include "strv.h" +#include "fileio.h" +#include "special.h" +#include "unit-name.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind-user.h" + +User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { + User *u; + + assert(m); + assert(name); + + u = new0(User, 1); + if (!u) + return NULL; + + u->name = strdup(name); + if (!u->name) + goto fail; + + if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) + goto fail; + + if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) + goto fail; + + u->manager = m; + u->uid = uid; + u->gid = gid; + + return u; + +fail: + free(u->state_file); + free(u->name); + free(u); + + return NULL; +} + +void user_free(User *u) { + assert(u); + + if (u->in_gc_queue) + LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u); + + while (u->sessions) + session_free(u->sessions); + + if (u->slice) { + hashmap_remove(u->manager->user_units, u->slice); + free(u->slice); + } + + if (u->service) { + hashmap_remove(u->manager->user_units, u->service); + free(u->service); + } + + free(u->slice_job); + free(u->service_job); + + free(u->runtime_path); + + hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid)); + + free(u->name); + free(u->state_file); + free(u); +} + +int user_save(User *u) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(u); + assert(u->state_file); + + if (!u->started) + return 0; + + r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0); + if (r < 0) + goto finish; + + r = fopen_temporary(u->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "NAME=%s\n" + "STATE=%s\n", + u->name, + user_state_to_string(user_get_state(u))); + + if (u->runtime_path) + fprintf(f, "RUNTIME=%s\n", u->runtime_path); + + if (u->service) + fprintf(f, "SERVICE=%s\n", u->service); + if (u->service_job) + fprintf(f, "SERVICE_JOB=%s\n", u->service_job); + + if (u->slice) + fprintf(f, "SLICE=%s\n", u->slice); + if (u->slice_job) + fprintf(f, "SLICE_JOB=%s\n", u->slice_job); + + if (u->display) + fprintf(f, "DISPLAY=%s\n", u->display->id); + + if (dual_timestamp_is_set(&u->timestamp)) + fprintf(f, + "REALTIME="USEC_FMT"\n" + "MONOTONIC="USEC_FMT"\n", + u->timestamp.realtime, + u->timestamp.monotonic); + + if (u->sessions) { + Session *i; + bool first; + + fputs("SESSIONS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->id, f); + } + + fputs("\nSEATS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (!i->seat) + continue; + + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->seat->id, f); + } + + fputs("\nACTIVE_SESSIONS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (!session_is_active(i)) + continue; + + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->id, f); + } + + fputs("\nONLINE_SESSIONS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (session_get_state(i) == SESSION_CLOSING) + continue; + + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->id, f); + } + + fputs("\nACTIVE_SEATS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (!session_is_active(i) || !i->seat) + continue; + + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->seat->id, f); + } + + fputs("\nONLINE_SEATS=", f); + first = true; + LIST_FOREACH(sessions_by_user, i, u->sessions) { + if (session_get_state(i) == SESSION_CLOSING || !i->seat) + continue; + + if (first) + first = false; + else + fputc(' ', f); + + fputs(i->seat->id, f); + } + fputc('\n', f); + } + + fflush(f); + + if (ferror(f) || rename(temp_path, u->state_file) < 0) { + r = -errno; + unlink(u->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save user data %s: %s", u->state_file, strerror(-r)); + + return r; +} + +int user_load(User *u) { + _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL; + Session *s = NULL; + int r; + + assert(u); + + r = parse_env_file(u->state_file, NEWLINE, + "RUNTIME", &u->runtime_path, + "SERVICE", &u->service, + "SERVICE_JOB", &u->service_job, + "SLICE", &u->slice, + "SLICE_JOB", &u->slice_job, + "DISPLAY", &display, + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + NULL); + if (r < 0) { + if (r == -ENOENT) + return 0; + + log_error("Failed to read %s: %s", u->state_file, strerror(-r)); + return r; + } + + if (display) + s = hashmap_get(u->manager->sessions, display); + + if (s && s->display && display_is_local(s->display)) + u->display = s; + + if (realtime) { + unsigned long long l; + if (sscanf(realtime, "%llu", &l) > 0) + u->timestamp.realtime = l; + } + + if (monotonic) { + unsigned long long l; + if (sscanf(monotonic, "%llu", &l) > 0) + u->timestamp.monotonic = l; + } + + return r; +} + +static int user_mkdir_runtime_path(User *u) { + char *p; + int r; + + assert(u); + + r = mkdir_safe_label("/run/user", 0755, 0, 0); + if (r < 0) { + log_error("Failed to create /run/user: %s", strerror(-r)); + return r; + } + + if (!u->runtime_path) { + if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0) + return log_oom(); + } else + p = u->runtime_path; + + r = mkdir_safe_label(p, 0700, u->uid, u->gid); + if (r < 0) { + log_error("Failed to create runtime directory %s: %s", p, strerror(-r)); + free(p); + u->runtime_path = NULL; + return r; + } + + u->runtime_path = p; + return 0; +} + +static int user_start_slice(User *u) { + char *job; + int r; + + assert(u); + + if (!u->slice) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice; + sprintf(lu, "%lu", (unsigned long) u->uid); + + r = build_subslice(SPECIAL_USER_SLICE, lu, &slice); + if (r < 0) + return r; + + r = manager_start_unit(u->manager, slice, &error, &job); + if (r < 0) { + log_error("Failed to start user slice: %s", bus_error_message(&error, r)); + free(slice); + } else { + u->slice = slice; + + free(u->slice_job); + u->slice_job = job; + } + } + + if (u->slice) + hashmap_put(u->manager->user_units, u->slice, u); + + return 0; +} + +static int user_start_service(User *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char *job; + int r; + + assert(u); + + if (!u->service) { + char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service; + sprintf(lu, "%lu", (unsigned long) u->uid); + + service = unit_name_build("user", lu, ".service"); + if (!service) + return log_oom(); + + r = manager_start_unit(u->manager, service, &error, &job); + if (r < 0) { + log_error("Failed to start user service: %s", bus_error_message(&error, r)); + free(service); + } else { + u->service = service; + + free(u->service_job); + u->service_job = job; + } + } + + if (u->service) + hashmap_put(u->manager->user_units, u->service, u); + + return 0; +} + +int user_start(User *u) { + int r; + + assert(u); + + if (u->started) + return 0; + + log_debug("New user %s logged in.", u->name); + + /* Make XDG_RUNTIME_DIR */ + r = user_mkdir_runtime_path(u); + if (r < 0) + return r; + + /* Create cgroup */ + r = user_start_slice(u); + if (r < 0) + return r; + + /* Spawn user systemd */ + r = user_start_service(u); + if (r < 0) + return r; + + if (!dual_timestamp_is_set(&u->timestamp)) + dual_timestamp_get(&u->timestamp); + + u->started = true; + + /* Save new user data */ + user_save(u); + + user_send_signal(u, true); + + return 0; +} + +static int user_stop_slice(User *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char *job; + int r; + + assert(u); + + if (!u->slice) + return 0; + + r = manager_stop_unit(u->manager, u->slice, &error, &job); + if (r < 0) { + log_error("Failed to stop user slice: %s", bus_error_message(&error, r)); + return r; + } + + free(u->slice_job); + u->slice_job = job; + + return r; +} + +static int user_stop_service(User *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char *job; + int r; + + assert(u); + + if (!u->service) + return 0; + + r = manager_stop_unit(u->manager, u->service, &error, &job); + if (r < 0) { + log_error("Failed to stop user service: %s", bus_error_message(&error, r)); + return r; + } + + free(u->service_job); + u->service_job = job; + + return r; +} + +static int user_remove_runtime_path(User *u) { + int r; + + assert(u); + + if (!u->runtime_path) + return 0; + + r = rm_rf(u->runtime_path, false, true, false); + if (r < 0) + log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r)); + + free(u->runtime_path); + u->runtime_path = NULL; + + return r; +} + +int user_stop(User *u, bool force) { + Session *s; + int r = 0, k; + assert(u); + + /* Stop jobs have already been queued */ + if (u->stopping) { + user_save(u); + return r; + } + + LIST_FOREACH(sessions_by_user, s, u->sessions) { + k = session_stop(s, force); + if (k < 0) + r = k; + } + + /* Kill systemd */ + k = user_stop_service(u); + if (k < 0) + r = k; + + /* Kill cgroup */ + k = user_stop_slice(u); + if (k < 0) + r = k; + + u->stopping = true; + + user_save(u); + + return r; +} + +int user_finalize(User *u) { + Session *s; + int r = 0, k; + + assert(u); + + if (u->started) + log_debug("User %s logged out.", u->name); + + LIST_FOREACH(sessions_by_user, s, u->sessions) { + k = session_finalize(s); + if (k < 0) + r = k; + } + + /* Kill XDG_RUNTIME_DIR */ + k = user_remove_runtime_path(u); + if (k < 0) + r = k; + + unlink(u->state_file); + user_add_to_gc_queue(u); + + if (u->started) { + user_send_signal(u, false); + u->started = false; + } + + return r; +} + +int user_get_idle_hint(User *u, dual_timestamp *t) { + Session *s; + bool idle_hint = true; + dual_timestamp ts = { 0, 0 }; + + assert(u); + + LIST_FOREACH(sessions_by_user, s, u->sessions) { + dual_timestamp k; + int ih; + + ih = session_get_idle_hint(s, &k); + if (ih < 0) + return ih; + + if (!ih) { + if (!idle_hint) { + if (k.monotonic < ts.monotonic) + ts = k; + } else { + idle_hint = false; + ts = k; + } + } else if (idle_hint) { + + if (k.monotonic > ts.monotonic) + ts = k; + } + } + + if (t) + *t = ts; + + return idle_hint; +} + +int user_check_linger_file(User *u) { + _cleanup_free_ char *cc = NULL; + char *p = NULL; + + cc = cescape(u->name); + if (!cc) + return -ENOMEM; + + p = strappenda("/var/lib/systemd/linger/", cc); + + return access(p, F_OK) >= 0; +} + +bool user_check_gc(User *u, bool drop_not_started) { + assert(u); + + if (drop_not_started && !u->started) + return false; + + if (u->sessions) + return true; + + if (user_check_linger_file(u) > 0) + return true; + + if (u->slice_job && manager_job_is_active(u->manager, u->slice_job)) + return true; + + if (u->service_job && manager_job_is_active(u->manager, u->service_job)) + return true; + + return false; +} + +void user_add_to_gc_queue(User *u) { + assert(u); + + if (u->in_gc_queue) + return; + + LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u); + u->in_gc_queue = true; +} + +UserState user_get_state(User *u) { + Session *i; + + assert(u); + + if (u->stopping) + return USER_CLOSING; + + if (u->slice_job || u->service_job) + return USER_OPENING; + + if (u->sessions) { + bool all_closing = true; + + LIST_FOREACH(sessions_by_user, i, u->sessions) { + SessionState state; + + state = session_get_state(i); + if (state == SESSION_ACTIVE) + return USER_ACTIVE; + if (state != SESSION_CLOSING) + all_closing = false; + } + + return all_closing ? USER_CLOSING : USER_ONLINE; + } + + if (user_check_linger_file(u) > 0) + return USER_LINGERING; + + return USER_CLOSING; +} + +int user_kill(User *u, int signo) { + assert(u); + + if (!u->slice) + return -ESRCH; + + return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL); +} + +static const char* const user_state_table[_USER_STATE_MAX] = { + [USER_OFFLINE] = "offline", + [USER_OPENING] = "opening", + [USER_LINGERING] = "lingering", + [USER_ONLINE] = "online", + [USER_ACTIVE] = "active", + [USER_CLOSING] = "closing" +}; + +DEFINE_STRING_TABLE_LOOKUP(user_state, UserState); diff --git a/src/login/logind-user.h b/src/login/logind-user.h new file mode 100644 index 0000000..f237d2a --- /dev/null +++ b/src/login/logind-user.h @@ -0,0 +1,93 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct User User; + +#include "list.h" +#include "util.h" +#include "logind.h" +#include "logind-session.h" + +typedef enum UserState { + USER_OFFLINE, /* Not logged in at all */ + USER_OPENING, /* Is logging in */ + USER_LINGERING, /* Lingering has been enabled by the admin for this user */ + USER_ONLINE, /* User logged in */ + USER_ACTIVE, /* User logged in and has a session in the fg */ + USER_CLOSING, /* User logged out, but processes still remain and lingering is not enabled */ + _USER_STATE_MAX, + _USER_STATE_INVALID = -1 +} UserState; + +struct User { + Manager *manager; + + uid_t uid; + gid_t gid; + char *name; + + char *state_file; + char *runtime_path; + + char *service; + char *slice; + + char *service_job; + char *slice_job; + + Session *display; + + dual_timestamp timestamp; + + bool in_gc_queue:1; + bool started:1; + bool stopping:1; + + LIST_HEAD(Session, sessions); + LIST_FIELDS(User, gc_queue); +}; + +User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name); +void user_free(User *u); +bool user_check_gc(User *u, bool drop_not_started); +void user_add_to_gc_queue(User *u); +int user_start(User *u); +int user_stop(User *u, bool force); +int user_finalize(User *u); +UserState user_get_state(User *u); +int user_get_idle_hint(User *u, dual_timestamp *t); +int user_save(User *u); +int user_load(User *u); +int user_kill(User *u, int signo); +int user_check_linger_file(User *u); + +extern const sd_bus_vtable user_vtable[]; +int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *user_bus_path(User *s); + +int user_send_signal(User *u, bool new_user); +int user_send_changed(User *u, const char *properties, ...) _sentinel_; + +const char* user_state_to_string(UserState s) _const_; +UserState user_state_from_string(const char *s) _pure_; diff --git a/src/login/logind.c b/src/login/logind.c new file mode 100644 index 0000000..3a514bb --- /dev/null +++ b/src/login/logind.c @@ -0,0 +1,1167 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" +#include "strv.h" +#include "conf-parser.h" +#include "mkdir.h" +#include "bus-util.h" +#include "bus-error.h" +#include "logind.h" +#include "udev-util.h" + +Manager *manager_new(void) { + Manager *m; + int r; + + m = new0(Manager, 1); + if (!m) + return NULL; + + m->console_active_fd = -1; + m->reserve_vt_fd = -1; + + m->n_autovts = 6; + m->reserve_vt = 6; + m->inhibit_delay_max = 5 * USEC_PER_SEC; + m->handle_power_key = HANDLE_POWEROFF; + m->handle_suspend_key = HANDLE_SUSPEND; + m->handle_hibernate_key = HANDLE_HIBERNATE; + m->handle_lid_switch = HANDLE_SUSPEND; + m->lid_switch_ignore_inhibited = true; + + m->idle_action_usec = 30 * USEC_PER_MINUTE; + m->idle_action = HANDLE_IGNORE; + m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); + + m->devices = hashmap_new(string_hash_func, string_compare_func); + m->seats = hashmap_new(string_hash_func, string_compare_func); + m->sessions = hashmap_new(string_hash_func, string_compare_func); + m->users = hashmap_new(trivial_hash_func, trivial_compare_func); + m->inhibitors = hashmap_new(string_hash_func, string_compare_func); + m->buttons = hashmap_new(string_hash_func, string_compare_func); + + m->user_units = hashmap_new(string_hash_func, string_compare_func); + m->session_units = hashmap_new(string_hash_func, string_compare_func); + + m->busnames = set_new(string_hash_func, string_compare_func); + + if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames || + !m->user_units || !m->session_units) + goto fail; + + m->kill_exclude_users = strv_new("root", NULL); + if (!m->kill_exclude_users) + goto fail; + + m->udev = udev_new(); + if (!m->udev) + goto fail; + + r = sd_event_default(&m->event); + if (r < 0) + goto fail; + + sd_event_set_watchdog(m->event, true); + + return m; + +fail: + manager_free(m); + return NULL; +} + +void manager_free(Manager *m) { + Session *session; + User *u; + Device *d; + Seat *s; + Inhibitor *i; + Button *b; + + assert(m); + + while ((session = hashmap_first(m->sessions))) + session_free(session); + + while ((u = hashmap_first(m->users))) + user_free(u); + + while ((d = hashmap_first(m->devices))) + device_free(d); + + while ((s = hashmap_first(m->seats))) + seat_free(s); + + while ((i = hashmap_first(m->inhibitors))) + inhibitor_free(i); + + while ((b = hashmap_first(m->buttons))) + button_free(b); + + hashmap_free(m->devices); + hashmap_free(m->seats); + hashmap_free(m->sessions); + hashmap_free(m->users); + hashmap_free(m->inhibitors); + hashmap_free(m->buttons); + + hashmap_free(m->user_units); + hashmap_free(m->session_units); + + set_free_free(m->busnames); + + sd_event_source_unref(m->idle_action_event_source); + + sd_event_source_unref(m->console_active_event_source); + sd_event_source_unref(m->udev_seat_event_source); + sd_event_source_unref(m->udev_device_event_source); + sd_event_source_unref(m->udev_vcsa_event_source); + sd_event_source_unref(m->udev_button_event_source); + + if (m->console_active_fd >= 0) + close_nointr_nofail(m->console_active_fd); + + if (m->udev_seat_monitor) + udev_monitor_unref(m->udev_seat_monitor); + if (m->udev_device_monitor) + udev_monitor_unref(m->udev_device_monitor); + if (m->udev_vcsa_monitor) + udev_monitor_unref(m->udev_vcsa_monitor); + if (m->udev_button_monitor) + udev_monitor_unref(m->udev_button_monitor); + + if (m->udev) + udev_unref(m->udev); + + bus_verify_polkit_async_registry_free(m->bus, m->polkit_registry); + + sd_bus_unref(m->bus); + sd_event_unref(m->event); + + if (m->reserve_vt_fd >= 0) + close_nointr_nofail(m->reserve_vt_fd); + + strv_free(m->kill_only_users); + strv_free(m->kill_exclude_users); + + free(m->action_job); + free(m); +} + +static int manager_enumerate_devices(Manager *m) { + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + int r; + + assert(m); + + /* Loads devices from udev and creates seats for them as + * necessary */ + + e = udev_enumerate_new(m->udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_tag(e, "master-of-seat"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + int k; + + d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + k = manager_process_seat_device(m, d); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_enumerate_buttons(Manager *m) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + int r; + + assert(m); + + /* Loads buttons from udev */ + + if (m->handle_power_key == HANDLE_IGNORE && + m->handle_suspend_key == HANDLE_IGNORE && + m->handle_hibernate_key == HANDLE_IGNORE && + m->handle_lid_switch == HANDLE_IGNORE) + return 0; + + e = udev_enumerate_new(m->udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_subsystem(e, "input"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_tag(e, "power-switch"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + int k; + + d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + k = manager_process_button_device(m, d); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_enumerate_seats(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(m); + + /* This loads data about seats stored on disk, but does not + * actually create any seats. Removes data of seats that no + * longer exist. */ + + d = opendir("/run/systemd/seats"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /run/systemd/seats: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + Seat *s; + int k; + + if (!dirent_is_file(de)) + continue; + + s = hashmap_get(m->seats, de->d_name); + if (!s) { + unlinkat(dirfd(d), de->d_name, 0); + continue; + } + + k = seat_load(s); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_enumerate_linger_users(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(m); + + d = opendir("/var/lib/systemd/linger"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /var/lib/systemd/linger/: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + int k; + + if (!dirent_is_file(de)) + continue; + + k = manager_add_user_by_name(m, de->d_name, NULL); + if (k < 0) { + log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k)); + r = k; + } + } + + return r; +} + +static int manager_enumerate_users(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r, k; + + assert(m); + + /* Add lingering users */ + r = manager_enumerate_linger_users(m); + + /* Read in user data stored on disk */ + d = opendir("/run/systemd/users"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /run/systemd/users: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + User *u; + + if (!dirent_is_file(de)) + continue; + + k = manager_add_user_by_name(m, de->d_name, &u); + if (k < 0) { + log_error("Failed to add user by file name %s: %s", de->d_name, strerror(-k)); + + r = k; + continue; + } + + user_add_to_gc_queue(u); + + k = user_load(u); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_enumerate_sessions(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(m); + + /* Read in session data stored on disk */ + d = opendir("/run/systemd/sessions"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /run/systemd/sessions: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + struct Session *s; + int k; + + if (!dirent_is_file(de)) + continue; + + if (!session_id_valid(de->d_name)) { + log_warning("Invalid session file name '%s', ignoring.", de->d_name); + r = -EINVAL; + continue; + } + + k = manager_add_session(m, de->d_name, &s); + if (k < 0) { + log_error("Failed to add session by file name %s: %s", de->d_name, strerror(-k)); + + r = k; + continue; + } + + session_add_to_gc_queue(s); + + k = session_load(s); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_enumerate_inhibitors(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(m); + + d = opendir("/run/systemd/inhibit"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /run/systemd/inhibit: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + int k; + Inhibitor *i; + + if (!dirent_is_file(de)) + continue; + + k = manager_add_inhibitor(m, de->d_name, &i); + if (k < 0) { + log_notice("Couldn't add inhibitor %s: %s", de->d_name, strerror(-k)); + r = k; + continue; + } + + k = inhibitor_load(i); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_dispatch_seat_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + Manager *m = userdata; + + assert(m); + + d = udev_monitor_receive_device(m->udev_seat_monitor); + if (!d) + return -ENOMEM; + + manager_process_seat_device(m, d); + return 0; +} + +static int manager_dispatch_device_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + Manager *m = userdata; + + assert(m); + + d = udev_monitor_receive_device(m->udev_device_monitor); + if (!d) + return -ENOMEM; + + manager_process_seat_device(m, d); + return 0; +} + +static int manager_dispatch_vcsa_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + Manager *m = userdata; + const char *name; + + assert(m); + + d = udev_monitor_receive_device(m->udev_vcsa_monitor); + if (!d) + return -ENOMEM; + + name = udev_device_get_sysname(d); + + /* Whenever a VCSA device is removed try to reallocate our + * VTs, to make sure our auto VTs never go away. */ + + if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove")) + seat_preallocate_vts(m->seat0); + + return 0; +} + +static int manager_dispatch_button_udev(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + Manager *m = userdata; + + assert(m); + + d = udev_monitor_receive_device(m->udev_button_monitor); + if (!d) + return -ENOMEM; + + manager_process_button_device(m, d); + return 0; +} + +static int manager_dispatch_console(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + + assert(m); + assert(m->seat0); + assert(m->console_active_fd == fd); + + seat_read_active_vt(m->seat0); + return 0; +} + +static int manager_reserve_vt(Manager *m) { + _cleanup_free_ char *p = NULL; + + assert(m); + + if (m->reserve_vt <= 0) + return 0; + + if (asprintf(&p, "/dev/tty%u", m->reserve_vt) < 0) + return log_oom(); + + m->reserve_vt_fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (m->reserve_vt_fd < 0) { + + /* Don't complain on VT-less systems */ + if (errno != ENOENT) + log_warning("Failed to pin reserved VT: %m"); + return -errno; + } + + return 0; +} + +static int manager_connect_bus(Manager *m) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(m); + assert(!m->bus); + + r = sd_bus_default_system(&m->bus); + if (r < 0) { + log_error("Failed to connect to system bus: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m); + if (r < 0) { + log_error("Failed to add manager object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m); + if (r < 0) { + log_error("Failed to add seat object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/seat", seat_node_enumerator, m); + if (r < 0) { + log_error("Failed to add seat enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m); + if (r < 0) { + log_error("Failed to add session object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/session", session_node_enumerator, m); + if (r < 0) { + log_error("Failed to add session enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m); + if (r < 0) { + log_error("Failed to add user object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/user", user_node_enumerator, m); + if (r < 0) { + log_error("Failed to add user enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "path='/org/freedesktop/DBus'", + match_name_owner_changed, m); + if (r < 0) { + log_error("Failed to add match for NameOwnerChanged: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + match_job_removed, m); + if (r < 0) { + log_error("Failed to add match for JobRemoved: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='UnitRemoved'," + "path='/org/freedesktop/systemd1'", + match_unit_removed, m); + if (r < 0) { + log_error("Failed to add match for UnitRemoved: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.DBus.Properties'," + "member='PropertiesChanged'", + match_properties_changed, m); + if (r < 0) { + log_error("Failed to add match for PropertiesChanged: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='Reloading'," + "path='/org/freedesktop/systemd1'", + match_reloading, m); + if (r < 0) { + log_error("Failed to add match for Reloading: %s", strerror(-r)); + return r; + } + + r = sd_bus_call_method( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Subscribe", + &error, + NULL, NULL); + if (r < 0) { + log_error("Failed to enable subscription: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(m->bus, m->event, 0); + if (r < 0) { + log_error("Failed to attach bus to event loop: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int manager_connect_console(Manager *m) { + int r; + + assert(m); + assert(m->console_active_fd < 0); + + /* On certain architectures (S390 and Xen, and containers), + /dev/tty0 does not exist, so don't fail if we can't open + it. */ + if (access("/dev/tty0", F_OK) < 0) + return 0; + + m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (m->console_active_fd < 0) { + + /* On some systems the device node /dev/tty0 may exist + * even though /sys/class/tty/tty0 does not. */ + if (errno == ENOENT) + return 0; + + log_error("Failed to open /sys/class/tty/tty0/active: %m"); + return -errno; + } + + r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m); + if (r < 0) { + log_error("Failed to watch foreground console"); + return r; + } + + return 0; +} + +static int manager_connect_udev(Manager *m) { + int r; + + assert(m); + assert(!m->udev_seat_monitor); + assert(!m->udev_device_monitor); + assert(!m->udev_vcsa_monitor); + assert(!m->udev_button_monitor); + + m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_seat_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "master-of-seat"); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_seat_monitor); + if (r < 0) + return r; + + r = sd_event_add_io(m->event, &m->udev_seat_event_source, udev_monitor_get_fd(m->udev_seat_monitor), EPOLLIN, manager_dispatch_seat_udev, m); + if (r < 0) + return r; + + m->udev_device_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_device_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "input", NULL); + if (r < 0) + return r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "graphics", NULL); + if (r < 0) + return r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_device_monitor, "drm", NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_device_monitor); + if (r < 0) + return r; + + r = sd_event_add_io(m->event, &m->udev_device_event_source, udev_monitor_get_fd(m->udev_device_monitor), EPOLLIN, manager_dispatch_device_udev, m); + if (r < 0) + return r; + + /* Don't watch keys if nobody cares */ + if (m->handle_power_key != HANDLE_IGNORE || + m->handle_suspend_key != HANDLE_IGNORE || + m->handle_hibernate_key != HANDLE_IGNORE || + m->handle_lid_switch != HANDLE_IGNORE) { + + m->udev_button_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_button_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_tag(m->udev_button_monitor, "power-switch"); + if (r < 0) + return r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_button_monitor, "input", NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_button_monitor); + if (r < 0) + return r; + + r = sd_event_add_io(m->event, &m->udev_button_event_source, udev_monitor_get_fd(m->udev_button_monitor), EPOLLIN, manager_dispatch_button_udev, m); + if (r < 0) + return r; + } + + /* Don't bother watching VCSA devices, if nobody cares */ + if (m->n_autovts > 0 && m->console_active_fd >= 0) { + + m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_vcsa_monitor) + return -ENOMEM; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); + if (r < 0) + return r; + + r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); + if (r < 0) + return r; + + r = sd_event_add_io(m->event, &m->udev_vcsa_event_source, udev_monitor_get_fd(m->udev_vcsa_monitor), EPOLLIN, manager_dispatch_vcsa_udev, m); + if (r < 0) + return r; + } + + return 0; +} + +void manager_gc(Manager *m, bool drop_not_started) { + Seat *seat; + Session *session; + User *user; + + assert(m); + + while ((seat = m->seat_gc_queue)) { + LIST_REMOVE(gc_queue, m->seat_gc_queue, seat); + seat->in_gc_queue = false; + + if (!seat_check_gc(seat, drop_not_started)) { + seat_stop(seat, false); + seat_free(seat); + } + } + + while ((session = m->session_gc_queue)) { + LIST_REMOVE(gc_queue, m->session_gc_queue, session); + session->in_gc_queue = false; + + /* First, if we are not closing yet, initiate stopping */ + if (!session_check_gc(session, drop_not_started) && + session_get_state(session) != SESSION_CLOSING) + session_stop(session, false); + + /* Normally, this should make the session busy again, + * if it doesn't then let's get rid of it + * immediately */ + if (!session_check_gc(session, drop_not_started)) { + session_finalize(session); + session_free(session); + } + } + + while ((user = m->user_gc_queue)) { + LIST_REMOVE(gc_queue, m->user_gc_queue, user); + user->in_gc_queue = false; + + /* First step: queue stop jobs */ + if (!user_check_gc(user, drop_not_started)) + user_stop(user, false); + + /* Second step: finalize user */ + if (!user_check_gc(user, drop_not_started)) { + user_finalize(user); + user_free(user); + } + } +} + +static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *userdata) { + Manager *m = userdata; + struct dual_timestamp since; + usec_t n, elapse; + int r; + + assert(m); + + if (m->idle_action == HANDLE_IGNORE || + m->idle_action_usec <= 0) + return 0; + + n = now(CLOCK_MONOTONIC); + + r = manager_get_idle_hint(m, &since); + if (r <= 0) + /* Not idle. Let's check if after a timeout it might be idle then. */ + elapse = n + m->idle_action_usec; + else { + /* Idle! Let's see if it's time to do something, or if + * we shall sleep for longer. */ + + if (n >= since.monotonic + m->idle_action_usec && + (m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) { + log_info("System idle. Taking action."); + + manager_handle_action(m, 0, m->idle_action, false, false); + m->idle_action_not_before_usec = n; + } + + elapse = MAX(since.monotonic, m->idle_action_not_before_usec) + m->idle_action_usec; + } + + if (!m->idle_action_event_source) { + + r = sd_event_add_monotonic(m->event, &m->idle_action_event_source, elapse, USEC_PER_SEC*30, manager_dispatch_idle_action, m); + if (r < 0) { + log_error("Failed to add idle event source: %s", strerror(-r)); + return r; + } + + r = sd_event_source_set_priority(m->idle_action_event_source, SD_EVENT_PRIORITY_IDLE+10); + if (r < 0) { + log_error("Failed to set idle event source priority: %s", strerror(-r)); + return r; + } + } else { + r = sd_event_source_set_time(m->idle_action_event_source, elapse); + if (r < 0) { + log_error("Failed to set idle event timer: %s", strerror(-r)); + return r; + } + + r = sd_event_source_set_enabled(m->idle_action_event_source, SD_EVENT_ONESHOT); + if (r < 0) { + log_error("Failed to enable idle event timer: %s", strerror(-r)); + return r; + } + } + + return 0; +} + +int manager_startup(Manager *m) { + int r; + Seat *seat; + Session *session; + User *user; + Button *button; + Inhibitor *inhibitor; + Iterator i; + + assert(m); + + /* Connect to console */ + r = manager_connect_console(m); + if (r < 0) + return r; + + /* Connect to udev */ + r = manager_connect_udev(m); + if (r < 0) { + log_error("Failed to create udev watchers: %s", strerror(-r)); + return r; + } + + /* Connect to the bus */ + r = manager_connect_bus(m); + if (r < 0) + return r; + + /* Instantiate magic seat 0 */ + r = manager_add_seat(m, "seat0", &m->seat0); + if (r < 0) { + log_error("Failed to add seat0: %s", strerror(-r)); + return r; + } + + /* Deserialize state */ + r = manager_enumerate_devices(m); + if (r < 0) + log_warning("Device enumeration failed: %s", strerror(-r)); + + r = manager_enumerate_seats(m); + if (r < 0) + log_warning("Seat enumeration failed: %s", strerror(-r)); + + r = manager_enumerate_users(m); + if (r < 0) + log_warning("User enumeration failed: %s", strerror(-r)); + + r = manager_enumerate_sessions(m); + if (r < 0) + log_warning("Session enumeration failed: %s", strerror(-r)); + + r = manager_enumerate_inhibitors(m); + if (r < 0) + log_warning("Inhibitor enumeration failed: %s", strerror(-r)); + + r = manager_enumerate_buttons(m); + if (r < 0) + log_warning("Button enumeration failed: %s", strerror(-r)); + + /* Remove stale objects before we start them */ + manager_gc(m, false); + + /* Reserve the special reserved VT */ + manager_reserve_vt(m); + + /* And start everything */ + HASHMAP_FOREACH(seat, m->seats, i) + seat_start(seat); + + HASHMAP_FOREACH(user, m->users, i) + user_start(user); + + HASHMAP_FOREACH(session, m->sessions, i) + session_start(session); + + HASHMAP_FOREACH(inhibitor, m->inhibitors, i) + inhibitor_start(inhibitor); + + HASHMAP_FOREACH(button, m->buttons, i) + button_check_switches(button); + + manager_dispatch_idle_action(NULL, 0, m); + + return 0; +} + +int manager_run(Manager *m) { + int r; + + assert(m); + + for (;;) { + usec_t us = (uint64_t) -1; + + r = sd_event_get_state(m->event); + if (r < 0) + return r; + if (r == SD_EVENT_FINISHED) + return 0; + + manager_gc(m, true); + + if (manager_dispatch_delayed(m) > 0) + continue; + + if (m->action_what != 0 && !m->action_job) { + usec_t x, y; + + x = now(CLOCK_MONOTONIC); + y = m->action_timestamp + m->inhibit_delay_max; + + us = x >= y ? 0 : y - x; + } + + r = sd_event_run(m->event, us); + if (r < 0) + return r; + } + + return 0; +} + +static int manager_parse_config_file(Manager *m) { + static const char fn[] = "/etc/systemd/logind.conf"; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(m); + + f = fopen(fn, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_warning("Failed to open configuration file %s: %m", fn); + return -errno; + } + + r = config_parse(NULL, fn, f, "Login\0", config_item_perf_lookup, + (void*) logind_gperf_lookup, false, false, m); + if (r < 0) + log_warning("Failed to parse configuration file: %s", strerror(-r)); + + return r; +} + +int main(int argc, char *argv[]) { + Manager *m = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_set_facility(LOG_AUTH); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + /* Always create the directories people can create inotify + * watches in. Note that some applications might check for the + * existence of /run/systemd/seats/ to determine whether + * logind is available, so please always make sure this check + * stays in. */ + mkdir_label("/run/systemd/seats", 0755); + mkdir_label("/run/systemd/users", 0755); + mkdir_label("/run/systemd/sessions", 0755); + + m = manager_new(); + if (!m) { + r = log_oom(); + goto finish; + } + + manager_parse_config_file(m); + + r = manager_startup(m); + if (r < 0) { + log_error("Failed to fully start up daemon: %s", strerror(-r)); + goto finish; + } + + log_debug("systemd-logind running as pid %lu", (unsigned long) getpid()); + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + r = manager_run(m); + + log_debug("systemd-logind stopped as pid %lu", (unsigned long) getpid()); + +finish: + sd_notify(false, + "STATUS=Shutting down..."); + + if (m) + manager_free(m); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/login/logind.conf b/src/login/logind.conf new file mode 100644 index 0000000..c0abf01 --- /dev/null +++ b/src/login/logind.conf @@ -0,0 +1,26 @@ +# 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. +# +# See logind.conf(5) for details + +[Login] +#NAutoVTs=6 +#ReserveVT=6 +#KillUserProcesses=no +#KillOnlyUsers= +#KillExcludeUsers=root +#InhibitDelayMaxSec=5 +#HandlePowerKey=poweroff +#HandleSuspendKey=suspend +#HandleHibernateKey=hibernate +#HandleLidSwitch=suspend +#PowerKeyIgnoreInhibited=no +#SuspendKeyIgnoreInhibited=no +#HibernateKeyIgnoreInhibited=no +#LidSwitchIgnoreInhibited=yes +#IdleAction=ignore +#IdleActionSec=30min diff --git a/src/login/logind.h b/src/login/logind.h new file mode 100644 index 0000000..0344acc --- /dev/null +++ b/src/login/logind.h @@ -0,0 +1,179 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-event.h" +#include "sd-bus.h" +#include "util.h" +#include "list.h" +#include "hashmap.h" +#include "set.h" + +typedef struct Manager Manager; + +#include "logind-device.h" +#include "logind-seat.h" +#include "logind-session.h" +#include "logind-user.h" +#include "logind-inhibit.h" +#include "logind-button.h" +#include "logind-action.h" + +struct Manager { + sd_event *event; + sd_bus *bus; + + Hashmap *devices; + Hashmap *seats; + Hashmap *sessions; + Hashmap *users; + Hashmap *inhibitors; + Hashmap *buttons; + + Set *busnames; + + LIST_HEAD(Seat, seat_gc_queue); + LIST_HEAD(Session, session_gc_queue); + LIST_HEAD(User, user_gc_queue); + + struct udev *udev; + struct udev_monitor *udev_seat_monitor, *udev_device_monitor, *udev_vcsa_monitor, *udev_button_monitor; + + sd_event_source *console_active_event_source; + sd_event_source *udev_seat_event_source; + sd_event_source *udev_device_event_source; + sd_event_source *udev_vcsa_event_source; + sd_event_source *udev_button_event_source; + + int console_active_fd; + + unsigned n_autovts; + + unsigned reserve_vt; + int reserve_vt_fd; + + Seat *seat0; + + char **kill_only_users, **kill_exclude_users; + bool kill_user_processes; + + unsigned long session_counter; + unsigned long inhibit_counter; + + Hashmap *session_units; + Hashmap *user_units; + + usec_t inhibit_delay_max; + + /* If an action is currently being executed or is delayed, + * this is != 0 and encodes what is being done */ + InhibitWhat action_what; + + /* If a shutdown/suspend was delayed due to a inhibitor this + contains the unit name we are supposed to start after the + delay is over */ + const char *action_unit; + + /* If a shutdown/suspend is currently executed, then this is + * the job of it */ + char *action_job; + usec_t action_timestamp; + + sd_event_source *idle_action_event_source; + usec_t idle_action_usec; + usec_t idle_action_not_before_usec; + HandleAction idle_action; + + HandleAction handle_power_key; + HandleAction handle_suspend_key; + HandleAction handle_hibernate_key; + HandleAction handle_lid_switch; + + bool power_key_ignore_inhibited; + bool suspend_key_ignore_inhibited; + bool hibernate_key_ignore_inhibited; + bool lid_switch_ignore_inhibited; + + Hashmap *polkit_registry; +}; + +Manager *manager_new(void); +void manager_free(Manager *m); + +int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); +int manager_add_button(Manager *m, const char *name, Button **_button); +int manager_add_seat(Manager *m, const char *id, Seat **_seat); +int manager_add_session(Manager *m, const char *id, Session **_session); +int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user); +int manager_add_user_by_name(Manager *m, const char *name, User **_user); +int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user); +int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor); + +int manager_process_seat_device(Manager *m, struct udev_device *d); +int manager_process_button_device(Manager *m, struct udev_device *d); + +int manager_startup(Manager *m); +int manager_run(Manager *m); +int manager_spawn_autovt(Manager *m, unsigned int vtnr); + +void manager_gc(Manager *m, bool drop_not_started); + +bool manager_shall_kill(Manager *m, const char *user); + +int manager_get_idle_hint(Manager *m, dual_timestamp *t); + +int manager_get_user_by_pid(Manager *m, pid_t pid, User **user); +int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session); + +bool manager_is_docked(Manager *m); + +extern const sd_bus_vtable manager_vtable[]; + +int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); + +int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error); + +int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; + +int manager_dispatch_delayed(Manager *manager); + +int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job); +int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); +int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); +int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); +int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error); +int manager_unit_is_active(Manager *manager, const char *unit); +int manager_job_is_active(Manager *manager, const char *path); + +/* gperf lookup function */ +const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length); + +int manager_watch_busname(Manager *manager, const char *name); +void manager_drop_busname(Manager *manager, const char *name); diff --git a/src/login/multi-seat-x.c b/src/login/multi-seat-x.c new file mode 100644 index 0000000..83760d4 --- /dev/null +++ b/src/login/multi-seat-x.c @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "mkdir.h" + +int main(int argc, char *argv[]) { + + int i; + const char *seat = NULL; + char **new_argv; + _cleanup_free_ char *path = NULL; + int r; + _cleanup_fclose_ FILE *f = NULL; + + /* This binary will go away as soon as X natively takes the + * arguments in question as command line parameters, instead + * of requiring them in the configuration file. */ + + /* If this file is removed, don't forget to remove the code + * that invokes this in gdm and other display managers. */ + + for (i = 1; i < argc; i++) + if (streq(argv[i], "-seat")) + seat = argv[i+1]; + + if (isempty(seat) || streq(seat, "seat0")) { + argv[0] = (char*) X_SERVER; + execv(X_SERVER, argv); + log_error("Failed to execute real X server: %m"); + goto fail; + } + + r = mkdir_safe_label("/run/systemd/multi-session-x", 0755, 0, 0); + if (r < 0) { + log_error("Failed to create directory: %s", strerror(-r)); + goto fail; + } + + path = strappend("/run/systemd/multi-session-x/", seat); + if (!path) { + log_oom(); + goto fail; + } + + f = fopen(path, "we"); + if (!f) { + log_error("Failed to write configuration file: %m"); + goto fail; + } + + fprintf(f, + "Section \"ServerFlags\"\n" + " Option \"AutoAddDevices\" \"True\"\n" + " Option \"AllowEmptyInput\" \"True\"\n" + " Option \"DontVTSwitch\" \"True\"\n" + "EndSection\n" + "Section \"InputClass\"\n" + " Identifier \"Force Input Devices to Seat\"\n" + " Option \"GrabDevice\" \"True\"\n" + "EndSection\n"); + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write configuration file: %m"); + goto fail; + } + + fclose(f); + f = NULL; + + new_argv = newa(char*, argc + 3 + 1); + memcpy(new_argv, argv, sizeof(char*) * (argc + 2 + 1)); + + new_argv[0] = (char*) X_SERVER; + new_argv[argc+0] = (char*) "-config"; + new_argv[argc+1] = path; + new_argv[argc+2] = (char*) "-sharevts"; + new_argv[argc+3] = NULL; + + execv(X_SERVER, new_argv); + log_error("Failed to execute real X server: %m"); + +fail: + return EXIT_FAILURE; +} diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf new file mode 100644 index 0000000..d677f61 --- /dev/null +++ b/src/login/org.freedesktop.login1.conf @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in new file mode 100644 index 0000000..b96d32d --- /dev/null +++ b/src/login/org.freedesktop.login1.policy.in @@ -0,0 +1,273 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Allow applications to inhibit system shutdown + <_message>Authentication is required to allow an application to inhibit system shutdown. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-shutdown org.freedesktop.login1.inhibit-block-sleep org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + <_description>Allow applications to delay system shutdown + <_message>Authentication is required to allow an application to delay system shutdown. + + yes + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep + + + + <_description>Allow applications to inhibit system sleep + <_message>Authentication is required to allow an application to inhibit system sleep. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + <_description>Allow applications to delay system sleep + <_message>Authentication is required to allow an application to delay system sleep. + + yes + yes + yes + + + + + <_description>Allow applications to inhibit automatic system suspend + <_message>Authentication is required to allow an application to inhibit automatic system suspend. + + yes + yes + yes + + + + + <_description>Allow applications to inhibit system handling of the power key + <_message>Authentication is required to allow an application to inhibit system handling of the power key. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-suspend-key org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + <_description>Allow applications to inhibit system handling of the suspend key + <_message>Authentication is required to allow an application to inhibit system handling of the suspend key. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + <_description>Allow applications to inhibit system handling of the hibernate key + <_message>Authentication is required to allow an application to inhibit system handling of the hibernate key. + + no + yes + yes + + + + + <_description>Allow applications to inhibit system handling of the lid switch + <_message>Authentication is required to allow an application to inhibit system handling of the lid switch. + + no + yes + yes + + + + + <_description>Allow non-logged-in users to run programs + <_message>Authentication is required to allow a non-logged-in user to run programs. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Allow attaching devices to seats + <_message>Authentication is required for attaching a device to a seat. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.flush-devices + + + + <_description>Flush device to seat attachments + <_message>Authentication is required for resetting how devices are attached to seats. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Power off the system + <_message>Authentication is required for powering off the system. + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Power off the system while other users are logged in + <_message>Authentication is required for powering off the system while other users are logged in. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.power-off + + + + <_description>Power off the system while an application asked to inhibit it + <_message>Authentication is required for powering off the system while an application asked to inhibit it. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.power-off + + + + <_description>Reboot the system + <_message>Authentication is required for rebooting the system. + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Reboot the system while other users are logged in + <_message>Authentication is required for rebooting the system while other users are logged in. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.reboot + + + + <_description>Reboot the system while an application asked to inhibit it + <_message>Authentication is required for rebooting the system while an application asked to inhibit it. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.reboot + + + + <_description>Suspend the system + <_message>Authentication is required for suspending the system. + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Suspend the system while other users are logged in + <_message>Authentication is required for suspending the system while other users are logged in. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.suspend + + + + <_description>Suspend the system while an application asked to inhibit it + <_message>Authentication is required for suspending the system while an application asked to inhibit it. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.suspend + + + + <_description>Hibernate the system + <_message>Authentication is required for hibernating the system. + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Hibernate the system while other users are logged in + <_message>Authentication is required for hibernating the system while other users are logged in. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.hibernate + + + + <_description>Hibernate the system while an application asked to inhibit it + <_message>Authentication is required for hibernating the system while an application asked to inhibit it. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.hibernate + + + diff --git a/src/login/org.freedesktop.login1.service b/src/login/org.freedesktop.login1.service new file mode 100644 index 0000000..762dae2 --- /dev/null +++ b/src/login/org.freedesktop.login1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.login1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.login1.service diff --git a/src/login/pam-module.c b/src/login/pam-module.c new file mode 100644 index 0000000..195d4d5 --- /dev/null +++ b/src/login/pam-module.c @@ -0,0 +1,548 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "util.h" +#include "audit.h" +#include "macro.h" +#include "strv.h" +#include "bus-util.h" +#include "def.h" +#include "socket-util.h" +#include "fileio.h" +#include "bus-error.h" + +static int parse_argv( + pam_handle_t *handle, + int argc, const char **argv, + const char **class, + const char **type, + bool *debug) { + + unsigned i; + + assert(argc >= 0); + assert(argc == 0 || argv); + + for (i = 0; i < (unsigned) argc; i++) { + if (startswith(argv[i], "class=")) { + if (class) + *class = argv[i] + 6; + + } else if (startswith(argv[i], "type=")) { + if (type) + *type = argv[i] + 5; + + } else if (streq(argv[i], "debug")) { + if (debug) + *debug = true; + + } else if (startswith(argv[i], "debug=")) { + int k; + + k = parse_boolean(argv[i] + 6); + if (k < 0) + pam_syslog(handle, LOG_WARNING, "Failed to parse debug= argument, ignoring."); + else if (debug) + *debug = k; + + } else + pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring", argv[i]); + } + + return 0; +} + +static int get_user_data( + pam_handle_t *handle, + const char **ret_username, + struct passwd **ret_pw) { + + const char *username = NULL; + struct passwd *pw = NULL; + int r; + + assert(handle); + assert(ret_username); + assert(ret_pw); + + r = pam_get_user(handle, &username, NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to get user name."); + return r; + } + + if (isempty(username)) { + pam_syslog(handle, LOG_ERR, "User name not valid."); + return PAM_AUTH_ERR; + } + + pw = pam_modutil_getpwnam(handle, username); + if (!pw) { + pam_syslog(handle, LOG_ERR, "Failed to get user data."); + return PAM_USER_UNKNOWN; + } + + *ret_pw = pw; + *ret_username = username ? username : pw->pw_name; + + return PAM_SUCCESS; +} + +static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + _cleanup_free_ char *p = NULL, *tty = NULL; + _cleanup_close_ int fd = -1; + struct ucred ucred; + int v, r; + + assert(display); + assert(vtnr); + + /* We deduce the X11 socket from the display name, then use + * SO_PEERCRED to determine the X11 server process, ask for + * the controlling tty of that and if it's a VC then we know + * the seat and the virtual terminal. Sounds ugly, is only + * semi-ugly. */ + + r = socket_from_display(display, &p); + if (r < 0) + return r; + strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1); + + fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) + return -errno; + + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + r = get_ctty(ucred.pid, NULL, &tty); + if (r < 0) + return r; + + v = vtnr_from_tty(tty); + if (v < 0) + return v; + else if (v == 0) + return -ENOENT; + + if (seat) + *seat = "seat0"; + *vtnr = (uint32_t) v; + + return 0; +} + +static int export_legacy_dbus_address( + pam_handle_t *handle, + uid_t uid, + const char *runtime) { + +#ifdef ENABLE_KDBUS + _cleanup_free_ char *s = NULL; + int r; + + /* skip export if kdbus is not active */ + if (access("/dev/kdbus", F_OK) < 0) + return PAM_SUCCESS; + + if (asprintf(&s, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, + (unsigned long) uid, runtime) < 0) { + pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); + return PAM_BUF_ERR; + } + + r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); + return r; + } +#endif + return PAM_SUCCESS; +} + +_public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, + int argc, const char **argv) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char + *username, *id, *object_path, *runtime_path, + *service = NULL, + *tty = NULL, *display = NULL, + *remote_user = NULL, *remote_host = NULL, + *seat = NULL, + *type = NULL, *class = NULL, + *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int session_fd = -1, existing, r; + bool debug = false, remote; + struct passwd *pw; + uint32_t vtnr = 0; + uid_t original_uid; + + assert(handle); + + /* Make this a NOP on non-logind systems */ + if (!logind_running()) + return PAM_SUCCESS; + + if (parse_argv(handle, + argc, argv, + &class_pam, + &type_pam, + &debug) < 0) + return PAM_SESSION_ERR; + + if (debug) + pam_syslog(handle, LOG_DEBUG, "pam-systemd initializing"); + + r = get_user_data(handle, &username, &pw); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to get user data."); + return r; + } + + /* Make sure we don't enter a loop by talking to + * systemd-logind when it is actually waiting for the + * background to finish start-up. If the service is + * "systemd-user" we simply set XDG_RUNTIME_DIR and + * leave. */ + + pam_get_item(handle, PAM_SERVICE, (const void**) &service); + if (streq_ptr(service, "systemd-user")) { + _cleanup_free_ char *p = NULL, *rt = NULL; + + if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) pw->pw_uid) < 0) + return PAM_BUF_ERR; + + r = parse_env_file(p, NEWLINE, + "RUNTIME", &rt, + NULL); + if (r < 0 && r != -ENOENT) + return PAM_SESSION_ERR; + + if (rt) { + r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); + return r; + } + + r = export_legacy_dbus_address(handle, pw->pw_uid, rt); + if (r != PAM_SUCCESS) + return r; + } + + return PAM_SUCCESS; + } + + /* Otherwise, we ask logind to create a session for us */ + + pam_get_item(handle, PAM_XDISPLAY, (const void**) &display); + pam_get_item(handle, PAM_TTY, (const void**) &tty); + pam_get_item(handle, PAM_RUSER, (const void**) &remote_user); + pam_get_item(handle, PAM_RHOST, (const void**) &remote_host); + + seat = pam_getenv(handle, "XDG_SEAT"); + if (isempty(seat)) + seat = getenv("XDG_SEAT"); + + cvtnr = pam_getenv(handle, "XDG_VTNR"); + if (isempty(cvtnr)) + cvtnr = getenv("XDG_VTNR"); + + type = pam_getenv(handle, "XDG_SESSION_TYPE"); + if (isempty(type)) + type = getenv("XDG_SESSION_TYPE"); + if (isempty(type)) + type = type_pam; + + class = pam_getenv(handle, "XDG_SESSION_CLASS"); + if (isempty(class)) + class = getenv("XDG_SESSION_CLASS"); + if (isempty(class)) + class = class_pam; + + desktop = pam_getenv(handle, "XDG_SESSION_DESKTOP"); + if (isempty(desktop)) + desktop = getenv("XDG_SESSION_DESKTOP"); + + tty = strempty(tty); + + if (strchr(tty, ':')) { + /* A tty with a colon is usually an X11 display, + * placed there to show up in utmp. We rearrange + * things and don't pretend that an X display was a + * tty. */ + + if (isempty(display)) + display = tty; + tty = NULL; + } else if (streq(tty, "cron")) { + /* cron has been setting PAM_TTY to "cron" for a very + * long time and it probably shouldn't stop doing that + * for compatibility reasons. */ + type = "unspecified"; + class = "background"; + tty = NULL; + } else if (streq(tty, "ssh")) { + /* ssh has been setting PAM_TTY to "ssh" for a very + * long time and probably shouldn't stop doing that + * for compatibility reasons. */ + type ="tty"; + class = "user"; + tty = NULL; + } + + /* If this fails vtnr will be 0, that's intended */ + if (!isempty(cvtnr)) + safe_atou32(cvtnr, &vtnr); + + if (!isempty(display) && !vtnr) { + if (isempty(seat)) + get_seat_from_display(display, &seat, &vtnr); + else if (streq(seat, "seat0")) + get_seat_from_display(display, NULL, &vtnr); + } + + if (seat && !streq(seat, "seat0") && vtnr != 0) { + pam_syslog(handle, LOG_DEBUG, "Ignoring vtnr %d for %s which is not seat0", vtnr, seat); + vtnr = 0; + } + + if (isempty(type)) + type = !isempty(display) ? "x11" : + !isempty(tty) ? "tty" : "unspecified"; + + if (isempty(class)) + class = streq(type, "unspecified") ? "background" : "user"; + + remote = !isempty(remote_host) && + !streq_ptr(remote_host, "localhost") && + !streq_ptr(remote_host, "localhost.localdomain"); + + /* Talk to logind over the message bus */ + + r = sd_bus_open_system(&bus); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + if (debug) + pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: " + "uid=%u pid=%u service=%s type=%s class=%s desktop=%s seat=%s vtnr=%u tty=%s display=%s remote=%s remote_user=%s remote_host=%s", + pw->pw_uid, getpid(), + strempty(service), + type, class, strempty(desktop), + strempty(seat), vtnr, strempty(tty), strempty(display), + yes_no(remote), strempty(remote_user), strempty(remote_host)); + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "CreateSession", + &error, + &reply, + "uusssssussbssa(sv)", + (uint32_t) pw->pw_uid, + (uint32_t) getpid(), + service, + type, + class, + desktop, + seat, + vtnr, + tty, + display, + remote, + remote_user, + remote_host, + 0); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); + return PAM_SYSTEM_ERR; + } + + r = sd_bus_message_read(reply, + "soshusub", + &id, + &object_path, + &runtime_path, + &session_fd, + &original_uid, + &seat, + &vtnr, + &existing); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + if (debug) + pam_syslog(handle, LOG_DEBUG, "Reply from logind: " + "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u", + id, object_path, runtime_path, session_fd, seat, vtnr, original_uid); + + r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set session id."); + return r; + } + + if (original_uid == pw->pw_uid) { + /* Don't set $XDG_RUNTIME_DIR if the user we now + * authenticated for does not match the original user + * of the session. We do this in order not to result + * in privileged apps clobbering the runtime directory + * unnecessarily. */ + + r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); + return r; + } + + r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path); + if (r != PAM_SUCCESS) + return r; + } + + if (!isempty(seat)) { + r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set seat."); + return r; + } + } + + if (vtnr > 0) { + char buf[DECIMAL_STR_MAX(vtnr)]; + sprintf(buf, "%u", vtnr); + + r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number."); + return r; + } + } + + r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to install existing flag."); + return r; + } + + if (session_fd >= 0) { + session_fd = dup(session_fd); + if (session_fd < 0) { + pam_syslog(handle, LOG_ERR, "Failed to dup session fd: %m"); + return PAM_SESSION_ERR; + } + + r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to install session fd."); + close_nointr_nofail(session_fd); + return r; + } + } + + return PAM_SUCCESS; +} + +_public_ PAM_EXTERN int pam_sm_close_session( + pam_handle_t *handle, + int flags, + int argc, const char **argv) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + const void *existing = NULL; + const char *id; + int r; + + assert(handle); + + /* Only release session if it wasn't pre-existing when we + * tried to create it */ + pam_get_data(handle, "systemd.existing", &existing); + + id = pam_getenv(handle, "XDG_SESSION_ID"); + if (id && !existing) { + + /* Before we go and close the FIFO we need to tell + * logind that this is a clean session shutdown, so + * that it doesn't just go and slaughter us + * immediately after closing the fd */ + + r = sd_bus_open_system(&bus); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", strerror(-r)); + return PAM_SESSION_ERR; + } + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ReleaseSession", + &error, + NULL, + "s", + id); + if (r < 0) { + pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error, r)); + return PAM_SESSION_ERR; + } + } + + /* Note that we are knowingly leaking the FIFO fd here. This + * way, logind can watch us die. If we closed it here it would + * not have any clue when that is completed. Given that one + * cannot really have multiple PAM sessions open from the same + * process this means we will leak one FD at max. */ + + return PAM_SUCCESS; +} diff --git a/src/login/sd-login.c b/src/login/sd-login.c new file mode 100644 index 0000000..ef67040 --- /dev/null +++ b/src/login/sd-login.c @@ -0,0 +1,774 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "cgroup-util.h" +#include "macro.h" +#include "strv.h" +#include "fileio.h" +#include "login-shared.h" +#include "sd-login.h" + +_public_ int sd_pid_get_session(pid_t pid, char **session) { + + assert_return(pid >= 0, -EINVAL); + assert_return(session, -EINVAL); + + return cg_pid_get_session(pid, session); +} + +_public_ int sd_pid_get_unit(pid_t pid, char **unit) { + + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); + + return cg_pid_get_unit(pid, unit); +} + +_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) { + + assert_return(pid >= 0, -EINVAL); + assert_return(unit, -EINVAL); + + return cg_pid_get_user_unit(pid, unit); +} + +_public_ int sd_pid_get_machine_name(pid_t pid, char **name) { + + assert_return(pid >= 0, -EINVAL); + assert_return(name, -EINVAL); + + return cg_pid_get_machine_name(pid, name); +} + +_public_ int sd_pid_get_slice(pid_t pid, char **slice) { + + assert_return(pid >= 0, -EINVAL); + assert_return(slice, -EINVAL); + + return cg_pid_get_slice(pid, slice); +} + +_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { + + assert_return(pid >= 0, -EINVAL); + assert_return(uid, -EINVAL); + + return cg_pid_get_owner_uid(pid, uid); +} + +_public_ int sd_uid_get_state(uid_t uid, char**state) { + char *p, *s = NULL; + int r; + + assert_return(state, -EINVAL); + + if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); + free(p); + + if (r == -ENOENT) { + free(s); + s = strdup("offline"); + if (!s) + return -ENOMEM; + + *state = s; + return 0; + } else if (r < 0) { + free(s); + return r; + } else if (!s) + return -EIO; + + *state = s; + return 0; +} + +_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { + char *w, *state; + _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL; + size_t l; + int r; + const char *variable; + + assert_return(seat, -EINVAL); + + variable = require_active ? "ACTIVE_UID" : "UIDS"; + + p = strappend("/run/systemd/seats/", seat); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, variable, &s, NULL); + + if (r < 0) + return r; + + if (!s) + return -EIO; + + if (asprintf(&t, "%lu", (unsigned long) uid) < 0) + return -ENOMEM; + + FOREACH_WORD(w, l, s, state) { + if (strneq(t, w, l)) + return 1; + } + + return 0; +} + +static int uid_get_array(uid_t uid, const char *variable, char ***array) { + _cleanup_free_ char *p = NULL, *s = NULL; + char **a; + int r; + + if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, + variable, &s, + NULL); + if (r < 0) { + if (r == -ENOENT) { + if (array) + *array = NULL; + return 0; + } + + return r; + } + + if (!s) { + if (array) + *array = NULL; + return 0; + } + + a = strv_split(s, " "); + + if (!a) + return -ENOMEM; + + strv_uniq(a); + r = strv_length(a); + + if (array) + *array = a; + else + strv_free(a); + + return r; +} + +_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) { + return uid_get_array( + uid, + require_active == 0 ? "ONLINE_SESSIONS" : + require_active > 0 ? "ACTIVE_SESSIONS" : + "SESSIONS", + sessions); +} + +_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) { + return uid_get_array( + uid, + require_active == 0 ? "ONLINE_SEATS" : + require_active > 0 ? "ACTIVE_SEATS" : + "SEATS", + seats); +} + +static int file_of_session(const char *session, char **_p) { + char *p; + int r; + + assert(_p); + + if (session) { + if (!session_id_valid(session)) + return -EINVAL; + + p = strappend("/run/systemd/sessions/", session); + } else { + _cleanup_free_ char *buf = NULL; + + r = sd_pid_get_session(0, &buf); + if (r < 0) + return r; + + p = strappend("/run/systemd/sessions/", buf); + } + + if (!p) + return -ENOMEM; + + *_p = p; + return 0; +} + +_public_ int sd_session_is_active(const char *session) { + int r; + _cleanup_free_ char *p = NULL, *s = NULL; + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); + if (r < 0) + return r; + + if (!s) + return -EIO; + + r = parse_boolean(s); + + return r; +} + +_public_ int sd_session_is_remote(const char *session) { + int r; + _cleanup_free_ char *p = NULL, *s = NULL; + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL); + if (r < 0) + return r; + + if (!s) + return -EIO; + + r = parse_boolean(s); + + return r; +} + +_public_ int sd_session_get_state(const char *session, char **state) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; + + assert_return(state, -EINVAL); + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); + + if (r < 0) + return r; + else if (!s) + return -EIO; + + *state = s; + s = NULL; + + return 0; +} + +_public_ int sd_session_get_uid(const char *session, uid_t *uid) { + int r; + _cleanup_free_ char *p = NULL, *s = NULL; + + assert_return(uid, -EINVAL); + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, "UID", &s, NULL); + + if (r < 0) + return r; + + if (!s) + return -EIO; + + r = parse_uid(s, uid); + + return r; +} + +static int session_get_string(const char *session, const char *field, char **value) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; + + assert_return(value, -EINVAL); + + r = file_of_session(session, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, field, &s, NULL); + + if (r < 0) + return r; + + if (isempty(s)) + return -ENOENT; + + *value = s; + s = NULL; + return 0; +} + +_public_ int sd_session_get_seat(const char *session, char **seat) { + return session_get_string(session, "SEAT", seat); +} + +_public_ int sd_session_get_tty(const char *session, char **tty) { + return session_get_string(session, "TTY", tty); +} + +_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) { + _cleanup_free_ char *vtnr_string = NULL; + unsigned u; + int r; + + r = session_get_string(session, "VTNR", &vtnr_string); + if (r < 0) + return r; + + r = safe_atou(vtnr_string, &u); + if (r < 0) + return r; + + *vtnr = u; + return 0; +} + +_public_ int sd_session_get_service(const char *session, char **service) { + return session_get_string(session, "SERVICE", service); +} + +_public_ int sd_session_get_type(const char *session, char **type) { + return session_get_string(session, "TYPE", type); +} + +_public_ int sd_session_get_class(const char *session, char **class) { + return session_get_string(session, "CLASS", class); +} + +_public_ int sd_session_get_display(const char *session, char **display) { + return session_get_string(session, "DISPLAY", display); +} + +_public_ int sd_session_get_remote_user(const char *session, char **remote_user) { + return session_get_string(session, "REMOTE_USER", remote_user); +} + +_public_ int sd_session_get_remote_host(const char *session, char **remote_host) { + return session_get_string(session, "REMOTE_HOST", remote_host); +} + +static int file_of_seat(const char *seat, char **_p) { + char *p; + int r; + + assert(_p); + + if (seat) + p = strappend("/run/systemd/seats/", seat); + else { + _cleanup_free_ char *buf = NULL; + + r = sd_session_get_seat(NULL, &buf); + if (r < 0) + return r; + + p = strappend("/run/systemd/seats/", buf); + } + + if (!p) + return -ENOMEM; + + *_p = p; + p = NULL; + return 0; +} + +_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { + _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; + int r; + + assert_return(session || uid, -EINVAL); + + r = file_of_seat(seat, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, + "ACTIVE", &s, + "ACTIVE_UID", &t, + NULL); + if (r < 0) + return r; + + if (session && !s) + return -ENOENT; + + if (uid && !t) + return -ENOENT; + + if (uid && t) { + r = parse_uid(t, uid); + if (r < 0) + return r; + } + + if (session && s) { + *session = s; + s = NULL; + } + + return 0; +} + +_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) { + _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; + _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ uid_t *b = NULL; + unsigned n = 0; + int r; + + r = file_of_seat(seat, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, + "SESSIONS", &s, + "ACTIVE_SESSIONS", &t, + NULL); + + if (r < 0) + return r; + + if (s) { + a = strv_split(s, " "); + if (!a) + return -ENOMEM; + } + + if (uids && t) { + char *w, *state; + size_t l; + + FOREACH_WORD(w, l, t, state) + n++; + + if (n > 0) { + unsigned i = 0; + + b = new(uid_t, n); + if (!b) + return -ENOMEM; + + FOREACH_WORD(w, l, t, state) { + _cleanup_free_ char *k = NULL; + + k = strndup(w, l); + if (!k) + return -ENOMEM; + + r = parse_uid(k, b + i); + + if (r < 0) + continue; + + i++; + } + } + } + + r = strv_length(a); + + if (sessions) { + *sessions = a; + a = NULL; + } + + if (uids) { + *uids = b; + b = NULL; + } + + if (n_uids) + *n_uids = n; + + return r; +} + +static int seat_get_can(const char *seat, const char *variable) { + _cleanup_free_ char *p = NULL, *s = NULL; + int r; + + r = file_of_seat(seat, &p); + if (r < 0) + return r; + + r = parse_env_file(p, NEWLINE, + variable, &s, + NULL); + if (r < 0) + return r; + + if (s) + r = parse_boolean(s); + else + r = 0; + + return r; +} + +_public_ int sd_seat_can_multi_session(const char *seat) { + return seat_get_can(seat, "CAN_MULTI_SESSION"); +} + +_public_ int sd_seat_can_tty(const char *seat) { + return seat_get_can(seat, "CAN_TTY"); +} + +_public_ int sd_seat_can_graphical(const char *seat) { + return seat_get_can(seat, "CAN_GRAPHICAL"); +} + +_public_ int sd_get_seats(char ***seats) { + return get_files_in_directory("/run/systemd/seats/", seats); +} + +_public_ int sd_get_sessions(char ***sessions) { + return get_files_in_directory("/run/systemd/sessions/", sessions); +} + +_public_ int sd_get_uids(uid_t **users) { + _cleanup_closedir_ DIR *d; + int r = 0; + unsigned n = 0; + _cleanup_free_ uid_t *l = NULL; + + d = opendir("/run/systemd/users/"); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + int k; + uid_t uid; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + k = parse_uid(de->d_name, &uid); + if (k < 0) + continue; + + if (users) { + if ((unsigned) r >= n) { + uid_t *t; + + n = MAX(16, 2*r); + t = realloc(l, sizeof(uid_t) * n); + if (!t) + return -ENOMEM; + + l = t; + } + + assert((unsigned) r < n); + l[r++] = uid; + } else + r++; + } + + if (users) { + *users = l; + l = NULL; + } + + return r; +} + +_public_ int sd_get_machine_names(char ***machines) { + char **l = NULL, **a, **b; + int r; + + r = get_files_in_directory("/run/systemd/machines/", &l); + if (r < 0) + return r; + + if (l) { + r = 0; + + /* Filter out the unit: symlinks */ + for (a = l, b = l; *a; a++) { + if (startswith(*a, "unit:")) + free(*a); + else { + *b = *a; + b++; + r++; + } + } + + *b = NULL; + } + + *machines = l; + return r; +} + +static inline int MONITOR_TO_FD(sd_login_monitor *m) { + return (int) (unsigned long) m - 1; +} + +static inline sd_login_monitor* FD_TO_MONITOR(int fd) { + return (sd_login_monitor*) (unsigned long) (fd + 1); +} + +_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { + int fd, k; + bool good = false; + + assert_return(m, -EINVAL); + + fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (fd < 0) + return -errno; + + if (!category || streq(category, "seat")) { + k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!category || streq(category, "session")) { + k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!category || streq(category, "uid")) { + k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!category || streq(category, "machine")) { + k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE); + if (k < 0) { + close_nointr_nofail(fd); + return -errno; + } + + good = true; + } + + if (!good) { + close_nointr(fd); + return -EINVAL; + } + + *m = FD_TO_MONITOR(fd); + return 0; +} + +_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { + int fd; + + assert_return(m, NULL); + + fd = MONITOR_TO_FD(m); + close_nointr(fd); + + return NULL; +} + +_public_ int sd_login_monitor_flush(sd_login_monitor *m) { + + assert_return(m, -EINVAL); + + return flush_fd(MONITOR_TO_FD(m)); +} + +_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { + + assert_return(m, -EINVAL); + + return MONITOR_TO_FD(m); +} + +_public_ int sd_login_monitor_get_events(sd_login_monitor *m) { + + assert_return(m, -EINVAL); + + /* For now we will only return POLLIN here, since we don't + * need anything else ever for inotify. However, let's have + * this API to keep our options open should we later on need + * it. */ + return POLLIN; +} + +_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) { + + assert_return(m, -EINVAL); + assert_return(timeout_usec, -EINVAL); + + /* For now we will only return (uint64_t) -1, since we don't + * need any timeout. However, let's have this API to keep our + * options open should we later on need it. */ + *timeout_usec = (uint64_t) -1; + return 0; +} diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c new file mode 100644 index 0000000..939bd61 --- /dev/null +++ b/src/login/sysfs-show.c @@ -0,0 +1,186 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "sysfs-show.h" +#include "path-util.h" +#include "udev-util.h" + +static int show_sysfs_one( + struct udev *udev, + const char *seat, + struct udev_list_entry **item, + const char *sub, + const char *prefix, + unsigned n_columns) { + + assert(udev); + assert(seat); + assert(item); + assert(prefix); + + while (*item) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct udev_list_entry *next, *lookahead; + const char *sn, *name, *sysfs, *subsystem, *sysname; + _cleanup_free_ char *k = NULL, *l = NULL; + bool is_master; + + sysfs = udev_list_entry_get_name(*item); + if (!path_startswith(sysfs, sub)) + return 0; + + d = udev_device_new_from_syspath(udev, sysfs); + if (!d) { + *item = udev_list_entry_get_next(*item); + continue; + } + + sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(sn)) + sn = "seat0"; + + /* Explicitly also check for tag 'seat' here */ + if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) { + *item = udev_list_entry_get_next(*item); + continue; + } + + is_master = udev_device_has_tag(d, "master-of-seat"); + + name = udev_device_get_sysattr_value(d, "name"); + if (!name) + name = udev_device_get_sysattr_value(d, "id"); + subsystem = udev_device_get_subsystem(d); + sysname = udev_device_get_sysname(d); + + /* Look if there's more coming after this */ + lookahead = next = udev_list_entry_get_next(*item); + while (lookahead) { + const char *lookahead_sysfs; + + lookahead_sysfs = udev_list_entry_get_name(lookahead); + + if (path_startswith(lookahead_sysfs, sub) && + !path_startswith(lookahead_sysfs, sysfs)) { + _cleanup_udev_device_unref_ struct udev_device *lookahead_d = NULL; + + lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs); + if (lookahead_d) { + const char *lookahead_sn; + + lookahead_sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(lookahead_sn)) + lookahead_sn = "seat0"; + + if (streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat")) + break; + } + } + + lookahead = udev_list_entry_get_next(lookahead); + } + + k = ellipsize(sysfs, n_columns, 20); + if (!k) + return -ENOMEM; + + printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), k); + + if (asprintf(&l, + "%s%s:%s%s%s%s", + is_master ? "[MASTER] " : "", + subsystem, sysname, + name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) + return -ENOMEM; + + free(k); + k = ellipsize(l, n_columns, 70); + if (!k) + return -ENOMEM; + + printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : " ", k); + + *item = next; + if (*item) { + _cleanup_free_ char *p = NULL; + + p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : " "); + if (!p) + return -ENOMEM; + + show_sysfs_one(udev, seat, item, sysfs, p, n_columns - 2); + } + } + + return 0; +} + +int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + struct udev_list_entry *first = NULL; + int r; + + if (n_columns <= 0) + n_columns = columns(); + + if (!prefix) + prefix = ""; + + if (isempty(seat)) + seat = "seat0"; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + e = udev_enumerate_new(udev); + if (!e) + return -ENOMEM; + + if (!streq(seat, "seat0")) + r = udev_enumerate_add_match_tag(e, seat); + else + r = udev_enumerate_add_match_tag(e, "seat"); + if (r < 0) + return r; + + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + return r; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + if (first) + show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); + else + printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), "(none)"); + + return r; +} diff --git a/src/login/systemd-user b/src/login/systemd-user new file mode 100644 index 0000000..7b57dbf --- /dev/null +++ b/src/login/systemd-user @@ -0,0 +1,8 @@ +#%PAM-1.0 + +# Used by systemd when launching systemd user instances. + +account include system-auth +session include system-auth +auth required pam_deny.so +password required pam_deny.so diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c new file mode 100644 index 0000000..70b8314 --- /dev/null +++ b/src/login/test-inhibit.c @@ -0,0 +1,113 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" +#include "util.h" +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" + +static int inhibit(sd_bus *bus, const char *what) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *who = "Test Tool", *reason = "Just because!", *mode = "block"; + int fd; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "Inhibit", + &error, + &reply, + "ssss", what, who, reason, mode); + assert(r >= 0); + + r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd); + assert(r >= 0); + assert(fd >= 0); + + return dup(fd); +} + +static void print_inhibitors(sd_bus *bus) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *what, *who, *why, *mode; + uint32_t uid, pid; + unsigned n = 0; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListInhibitors", + &error, + &reply, + ""); + assert(r >= 0); + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)"); + assert(r >= 0); + + while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) { + printf("what=<%s> who=<%s> why=<%s> mode=<%s> uid=<%lu> pid=<%lu>\n", + what, who, why, mode, (unsigned long) uid, (unsigned long) pid); + + n++; + } + assert(r >= 0); + + printf("%u inhibitors\n", n); +} + +int main(int argc, char*argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int fd1, fd2; + int r; + + r = sd_bus_open_system(&bus); + assert(r >= 0); + + print_inhibitors(bus); + + fd1 = inhibit(bus, "sleep"); + assert(fd1 >= 0); + print_inhibitors(bus); + + fd2 = inhibit(bus, "idle:shutdown"); + assert(fd2 >= 0); + print_inhibitors(bus); + + close_nointr_nofail(fd1); + sleep(1); + print_inhibitors(bus); + + close_nointr_nofail(fd2); + sleep(1); + print_inhibitors(bus); + + return 0; +} diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c new file mode 100644 index 0000000..d29d7e7 --- /dev/null +++ b/src/login/test-login-shared.c @@ -0,0 +1,41 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "macro.h" +#include "login-shared.h" + +static void test_session_id_valid(void) { + assert_se(session_id_valid("c1")); + assert_se(session_id_valid("1234")); + + assert_se(!session_id_valid("1-2")); + assert_se(!session_id_valid("")); + assert_se(!session_id_valid("\tid")); +} + +int main(int argc, char* argv[]) { + log_parse_environment(); + log_open(); + + test_session_id_valid(); + + return 0; +} diff --git a/src/login/test-login-tables.c b/src/login/test-login-tables.c new file mode 100644 index 0000000..a4196bf --- /dev/null +++ b/src/login/test-login-tables.c @@ -0,0 +1,35 @@ +/*** + This file is part of systemd + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "logind-action.h" +#include "logind-session.h" + +#include "test-tables.h" + +int main(int argc, char **argv) { + test_table(handle_action, HANDLE_ACTION); + test_table(inhibit_mode, INHIBIT_MODE); + test_table(kill_who, KILL_WHO); + test_table(session_class, SESSION_CLASS); + test_table(session_state, SESSION_STATE); + test_table(session_type, SESSION_TYPE); + test_table(user_state, USER_STATE); + + return EXIT_SUCCESS; +} diff --git a/src/login/test-login.c b/src/login/test-login.c new file mode 100644 index 0000000..d78cea4 --- /dev/null +++ b/src/login/test-login.c @@ -0,0 +1,239 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include + +#include "util.h" +#include "strv.h" + +static void test_login(void) { + int r, k; + uid_t u, u2; + char *seat, *type, *class, *display, *remote_user, *remote_host; + char *session; + char *state; + char *session2; + char *t; + char **seats, **sessions, **machines; + uid_t *uids; + unsigned n; + struct pollfd pollfd; + sd_login_monitor *m = NULL; + + assert_se(sd_pid_get_session(0, &session) == 0); + printf("session = %s\n", session); + + assert_se(sd_pid_get_owner_uid(0, &u2) == 0); + printf("user = %lu\n", (unsigned long) u2); + + r = sd_uid_get_sessions(u2, false, &sessions); + assert_se(r >= 0); + assert_se(r == (int) strv_length(sessions)); + assert_se(t = strv_join(sessions, ", ")); + strv_free(sessions); + printf("sessions = %s\n", t); + free(t); + + assert_se(r == sd_uid_get_sessions(u2, false, NULL)); + + r = sd_uid_get_seats(u2, false, &seats); + assert_se(r >= 0); + assert_se(r == (int) strv_length(seats)); + assert_se(t = strv_join(seats, ", ")); + strv_free(seats); + printf("seats = %s\n", t); + free(t); + + assert_se(r == sd_uid_get_seats(u2, false, NULL)); + + r = sd_session_is_active(session); + assert_se(r >= 0); + printf("active = %s\n", yes_no(r)); + + r = sd_session_is_remote(session); + assert_se(r >= 0); + printf("remote = %s\n", yes_no(r)); + + r = sd_session_get_state(session, &state); + assert_se(r >= 0); + printf("state = %s\n", state); + free(state); + + assert_se(sd_session_get_uid(session, &u) >= 0); + printf("uid = %lu\n", (unsigned long) u); + assert_se(u == u2); + + assert_se(sd_session_get_type(session, &type) >= 0); + printf("type = %s\n", type); + free(type); + + assert_se(sd_session_get_class(session, &class) >= 0); + printf("class = %s\n", class); + free(class); + + assert_se(sd_session_get_display(session, &display) >= 0); + printf("display = %s\n", display); + free(display); + + assert_se(sd_session_get_remote_user(session, &remote_user) >= 0); + printf("remote_user = %s\n", remote_user); + free(remote_user); + + assert_se(sd_session_get_remote_host(session, &remote_host) >= 0); + printf("remote_host = %s\n", remote_host); + free(remote_host); + + assert_se(sd_session_get_seat(session, &seat) >= 0); + printf("seat = %s\n", seat); + + r = sd_seat_can_multi_session(seat); + assert_se(r >= 0); + printf("can do multi session = %s\n", yes_no(r)); + + r = sd_seat_can_tty(seat); + assert_se(r >= 0); + printf("can do tty = %s\n", yes_no(r)); + + r = sd_seat_can_graphical(seat); + assert_se(r >= 0); + printf("can do graphical = %s\n", yes_no(r)); + + assert_se(sd_uid_get_state(u, &state) >= 0); + printf("state = %s\n", state); + + assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); + + k = sd_uid_is_on_seat(u, 1, seat); + assert_se(k >= 0); + assert_se(!!r == !!r); + + assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); + printf("session2 = %s\n", session2); + printf("uid2 = %lu\n", (unsigned long) u2); + + r = sd_seat_get_sessions(seat, &sessions, &uids, &n); + assert_se(r >= 0); + printf("n_sessions = %i\n", r); + assert_se(r == (int) strv_length(sessions)); + assert_se(t = strv_join(sessions, ", ")); + strv_free(sessions); + printf("sessions = %s\n", t); + free(t); + printf("uids ="); + for (k = 0; k < (int) n; k++) + printf(" %lu", (unsigned long) uids[k]); + printf("\n"); + free(uids); + + assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); + + free(session); + free(state); + free(session2); + free(seat); + + r = sd_get_seats(&seats); + assert_se(r >= 0); + assert_se(r == (int) strv_length(seats)); + assert_se(t = strv_join(seats, ", ")); + strv_free(seats); + printf("n_seats = %i\n", r); + printf("seats = %s\n", t); + free(t); + + assert_se(sd_get_seats(NULL) == r); + + r = sd_seat_get_active(NULL, &t, NULL); + assert_se(r >= 0); + printf("active session on current seat = %s\n", t); + free(t); + + r = sd_get_sessions(&sessions); + assert_se(r >= 0); + assert_se(r == (int) strv_length(sessions)); + assert_se(t = strv_join(sessions, ", ")); + strv_free(sessions); + printf("n_sessions = %i\n", r); + printf("sessions = %s\n", t); + free(t); + + assert_se(sd_get_sessions(NULL) == r); + + r = sd_get_uids(&uids); + assert_se(r >= 0); + + printf("uids ="); + for (k = 0; k < r; k++) + printf(" %lu", (unsigned long) uids[k]); + printf("\n"); + free(uids); + + printf("n_uids = %i\n", r); + assert_se(sd_get_uids(NULL) == r); + + r = sd_get_machine_names(&machines); + assert_se(r >= 0); + assert_se(r == (int) strv_length(machines)); + assert_se(t = strv_join(machines, ", ")); + strv_free(machines); + printf("n_machines = %i\n", r); + printf("machines = %s\n", t); + free(t); + + r = sd_login_monitor_new("session", &m); + assert_se(r >= 0); + + for (n = 0; n < 5; n++) { + usec_t timeout, nw; + + zero(pollfd); + assert_se((pollfd.fd = sd_login_monitor_get_fd(m)) >= 0); + assert_se((pollfd.events = sd_login_monitor_get_events(m)) >= 0); + + assert_se(sd_login_monitor_get_timeout(m, &timeout) >= 0); + + nw = now(CLOCK_MONOTONIC); + + r = poll(&pollfd, 1, + timeout == (uint64_t) -1 ? -1 : + timeout > nw ? (int) ((timeout - nw) / 1000) : + 0); + + assert_se(r >= 0); + + sd_login_monitor_flush(m); + printf("Wake!\n"); + } + + sd_login_monitor_unref(m); +} + +int main(int argc, char* argv[]) { + log_parse_environment(); + log_open(); + + test_login(); + + return 0; +} diff --git a/src/login/user-sessions.c b/src/login/user-sessions.c new file mode 100644 index 0000000..ca5de41 --- /dev/null +++ b/src/login/user-sessions.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "fileio.h" + +int main(int argc, char*argv[]) { + + if (argc != 2) { + log_error("This program requires one argument."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (streq(argv[1], "start")) { + int r = 0; + + if (unlink("/run/nologin") < 0 && errno != ENOENT) { + log_error("Failed to remove /run/nologin file: %m"); + r = -errno; + } + + if (unlink("/etc/nologin") < 0 && errno != ENOENT) { + /* If the file doesn't exist and /etc simply + * was read-only (in which case unlink() + * returns EROFS even if the file doesn't + * exist), don't complain */ + + if (errno != EROFS || access("/etc/nologin", F_OK) >= 0) { + log_error("Failed to remove /etc/nologin file: %m"); + return EXIT_FAILURE; + } + } + + if (r < 0) + return EXIT_FAILURE; + + } else if (streq(argv[1], "stop")) { + int r; + + r = write_string_file_atomic("/run/nologin", "System is going down."); + if (r < 0) { + log_error("Failed to create /run/nologin: %s", strerror(-r)); + return EXIT_FAILURE; + } + + } else { + log_error("Unknown verb %s.", argv[1]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/loginctl.c b/src/loginctl.c deleted file mode 100644 index 89762b6..0000000 --- a/src/loginctl.c +++ /dev/null @@ -1,1914 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "macro.h" -#include "pager.h" -#include "dbus-common.h" -#include "build.h" -#include "strv.h" -#include "cgroup-show.h" -#include "sysfs-show.h" - -static char **arg_property = NULL; -static bool arg_all = false; -static bool arg_no_pager = false; -static const char *arg_kill_who = NULL; -static int arg_signal = SIGTERM; -static enum transport { - TRANSPORT_NORMAL, - TRANSPORT_SSH, - TRANSPORT_POLKIT -} arg_transport = TRANSPORT_NORMAL; -static const char *arg_host = NULL; - -static bool on_tty(void) { - static int t = -1; - - /* Note that this is invoked relatively early, before we start - * the pager. That means the value we return reflects whether - * we originally were started on a tty, not if we currently - * are. But this is intended, since we want colour and so on - * when run in our own pager. */ - - if (_unlikely_(t < 0)) - t = isatty(STDOUT_FILENO) > 0; - - return t; -} - -static void pager_open_if_enabled(void) { - - /* Cache result before we open the pager */ - on_tty(); - - if (!arg_no_pager) - pager_open(); -} - -static int list_sessions(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned k = 0; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "ListSessions"); - if (!m) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (on_tty()) - printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT"); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *id, *user, *seat, *object; - uint32_t uid; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat); - - k++; - - dbus_message_iter_next(&sub); - } - - if (on_tty()) - printf("\n%u sessions listed.\n", k); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int list_users(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned k = 0; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "ListUsers"); - if (!m) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (on_tty()) - printf("%10s %-16s\n", "UID", "USER"); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *user, *object; - uint32_t uid; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - printf("%10u %-16s\n", (unsigned) uid, user); - - k++; - - dbus_message_iter_next(&sub); - } - - if (on_tty()) - printf("\n%u users listed.\n", k); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int list_seats(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned k = 0; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "ListSeats"); - if (!m) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (on_tty()) - printf("%-16s\n", "SEAT"); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *seat, *object; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - printf("%-16s\n", seat); - - k++; - - dbus_message_iter_next(&sub); - } - - if (on_tty()) - printf("\n%u seats listed.\n", k); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -typedef struct SessionStatusInfo { - const char *id; - uid_t uid; - const char *name; - usec_t timestamp; - const char *control_group; - int vtnr; - const char *seat; - const char *tty; - const char *display; - bool remote; - const char *remote_host; - const char *remote_user; - const char *service; - pid_t leader; - const char *type; - bool active; -} SessionStatusInfo; - -typedef struct UserStatusInfo { - uid_t uid; - const char *name; - usec_t timestamp; - const char *control_group; - const char *state; - char **sessions; - const char *display; -} UserStatusInfo; - -typedef struct SeatStatusInfo { - const char *id; - const char *active_session; - char **sessions; -} SeatStatusInfo; - -static void print_session_status_info(SessionStatusInfo *i) { - char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1; - char since2[FORMAT_TIMESTAMP_MAX], *s2; - assert(i); - - printf("%s - ", strna(i->id)); - - if (i->name) - printf("%s (%u)\n", i->name, (unsigned) i->uid); - else - printf("%u\n", (unsigned) i->uid); - - s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp); - s2 = format_timestamp(since2, sizeof(since2), i->timestamp); - - if (s1) - printf("\t Since: %s; %s\n", s2, s1); - else if (s2) - printf("\t Since: %s\n", s2); - - if (i->leader > 0) { - char *t = NULL; - - printf("\t Leader: %u", (unsigned) i->leader); - - get_process_name(i->leader, &t); - if (t) { - printf(" (%s)", t); - free(t); - } - - printf("\n"); - } - - if (i->seat) { - printf("\t Seat: %s", i->seat); - - if (i->vtnr > 0) - printf("; vc%i", i->vtnr); - - printf("\n"); - } - - if (i->tty) - printf("\t TTY: %s\n", i->tty); - else if (i->display) - printf("\t Display: %s\n", i->display); - - if (i->remote_host && i->remote_user) - printf("\t Remote: %s@%s\n", i->remote_user, i->remote_host); - else if (i->remote_host) - printf("\t Remote: %s\n", i->remote_host); - else if (i->remote_user) - printf("\t Remote: user %s\n", i->remote_user); - else if (i->remote) - printf("\t Remote: Yes\n"); - - if (i->service) { - printf("\t Service: %s", i->service); - - if (i->type) - printf("; type %s", i->type); - - printf("\n"); - } else if (i->type) - printf("\t Type: %s\n", i->type); - - printf("\t Active: %s\n", yes_no(i->active)); - - if (i->control_group) { - unsigned c; - - printf("\t CGroup: %s\n", i->control_group); - - if (arg_transport != TRANSPORT_SSH) { - c = columns(); - if (c > 18) - c -= 18; - else - c = 0; - - show_cgroup_by_path(i->control_group, "\t\t ", c); - } - } -} - -static void print_user_status_info(UserStatusInfo *i) { - char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1; - char since2[FORMAT_TIMESTAMP_MAX], *s2; - assert(i); - - if (i->name) - printf("%s (%u)\n", i->name, (unsigned) i->uid); - else - printf("%u\n", (unsigned) i->uid); - - s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp); - s2 = format_timestamp(since2, sizeof(since2), i->timestamp); - - if (s1) - printf("\t Since: %s; %s\n", s2, s1); - else if (s2) - printf("\t Since: %s\n", s2); - - if (!isempty(i->state)) - printf("\t State: %s\n", i->state); - - if (!strv_isempty(i->sessions)) { - char **l; - printf("\tSessions:"); - - STRV_FOREACH(l, i->sessions) { - if (streq_ptr(*l, i->display)) - printf(" *%s", *l); - else - printf(" %s", *l); - } - - printf("\n"); - } - - if (i->control_group) { - unsigned c; - - printf("\t CGroup: %s\n", i->control_group); - - if (arg_transport != TRANSPORT_SSH) { - c = columns(); - if (c > 18) - c -= 18; - else - c = 0; - - show_cgroup_by_path(i->control_group, "\t\t ", c); - } - } -} - -static void print_seat_status_info(SeatStatusInfo *i) { - assert(i); - - printf("%s\n", strna(i->id)); - - if (!strv_isempty(i->sessions)) { - char **l; - printf("\tSessions:"); - - STRV_FOREACH(l, i->sessions) { - if (streq_ptr(*l, i->active_session)) - printf(" *%s", *l); - else - printf(" %s", *l); - } - - printf("\n"); - } - - if (arg_transport != TRANSPORT_SSH) { - unsigned c; - - c = columns(); - if (c > 21) - c -= 21; - else - c = 0; - - printf("\t Devices:\n"); - - show_sysfs(i->id, "\t\t ", c); - } -} - -static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) { - assert(name); - assert(iter); - assert(i); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - - dbus_message_iter_get_basic(iter, &s); - - if (!isempty(s)) { - if (streq(name, "Id")) - i->id = s; - else if (streq(name, "Name")) - i->name = s; - else if (streq(name, "ControlGroupPath")) - i->control_group = s; - else if (streq(name, "TTY")) - i->tty = s; - else if (streq(name, "Display")) - i->display = s; - else if (streq(name, "RemoteHost")) - i->remote_host = s; - else if (streq(name, "RemoteUser")) - i->remote_user = s; - else if (streq(name, "Service")) - i->service = s; - else if (streq(name, "Type")) - i->type = s; - } - break; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "VTNr")) - i->vtnr = (int) u; - else if (streq(name, "Leader")) - i->leader = (pid_t) u; - - break; - } - - case DBUS_TYPE_BOOLEAN: { - dbus_bool_t b; - - dbus_message_iter_get_basic(iter, &b); - - if (streq(name, "Remote")) - i->remote = b; - else if (streq(name, "Active")) - i->active = b; - - break; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "Timestamp")) - i->timestamp = (usec_t) u; - - break; - } - - case DBUS_TYPE_STRUCT: { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) { - uint32_t u; - - dbus_message_iter_get_basic(&sub, &u); - i->uid = (uid_t) u; - - } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) { - const char *s; - - dbus_message_iter_get_basic(&sub, &s); - - if (!isempty(s)) - i->seat = s; - } - - break; - } - } - - return 0; -} - -static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) { - assert(name); - assert(iter); - assert(i); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - - dbus_message_iter_get_basic(iter, &s); - - if (!isempty(s)) { - if (streq(name, "Name")) - i->name = s; - else if (streq(name, "ControlGroupPath")) - i->control_group = s; - else if (streq(name, "State")) - i->state = s; - } - break; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "UID")) - i->uid = (uid_t) u; - - break; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "Timestamp")) - i->timestamp = (usec_t) u; - - break; - } - - case DBUS_TYPE_STRUCT: { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) { - const char *s; - - dbus_message_iter_get_basic(&sub, &s); - - if (!isempty(s)) - i->display = s; - } - - break; - } - - case DBUS_TYPE_ARRAY: { - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *id; - const char *path; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) { - char **l; - - l = strv_append(i->sessions, id); - if (!l) - return -ENOMEM; - - strv_free(i->sessions); - i->sessions = l; - } - - dbus_message_iter_next(&sub); - } - - return 0; - } - } - } - - return 0; -} - -static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) { - assert(name); - assert(iter); - assert(i); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - - dbus_message_iter_get_basic(iter, &s); - - if (!isempty(s)) { - if (streq(name, "Id")) - i->id = s; - } - break; - } - - case DBUS_TYPE_STRUCT: { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) { - const char *s; - - dbus_message_iter_get_basic(&sub, &s); - - if (!isempty(s)) - i->active_session = s; - } - - break; - } - - case DBUS_TYPE_ARRAY: { - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *id; - const char *path; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) { - char **l; - - l = strv_append(i->sessions, id); - if (!l) - return -ENOMEM; - - strv_free(i->sessions); - i->sessions = l; - } - - dbus_message_iter_next(&sub); - } - - return 0; - } - } - } - - return 0; -} - -static int print_property(const char *name, DBusMessageIter *iter) { - assert(name); - assert(iter); - - if (arg_property && !strv_find(arg_property, name)) - return 0; - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRUCT: { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && - (streq(name, "Display") || streq(name, "ActiveSession"))) { - const char *s; - - dbus_message_iter_get_basic(&sub, &s); - - if (arg_all || !isempty(s)) - printf("%s=%s\n", name, s); - return 0; - } - break; - } - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) { - DBusMessageIter sub, sub2; - bool found = false; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *id; - const char *path; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) { - if (found) - printf(" %s", id); - else { - printf("%s=%s", name, id); - found = true; - } - } - - dbus_message_iter_next(&sub); - } - - if (!found && arg_all) - printf("%s=\n", name); - else if (found) - printf("\n"); - - return 0; - } - - break; - } - - if (generic_print_property(name, iter, arg_all) > 0) - return 0; - - if (arg_all) - printf("%s=[unprintable]\n", name); - - return 0; -} - -static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { - DBusMessage *m = NULL, *reply = NULL; - const char *interface = ""; - int r; - DBusError error; - DBusMessageIter iter, sub, sub2, sub3; - SessionStatusInfo session_info; - UserStatusInfo user_info; - SeatStatusInfo seat_info; - - assert(bus); - assert(path); - assert(new_line); - - zero(session_info); - zero(user_info); - zero(seat_info); - - dbus_error_init(&error); - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - path, - "org.freedesktop.DBus.Properties", - "GetAll"); - if (!m) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (*new_line) - printf("\n"); - - *new_line = true; - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *name; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub2, &sub3); - - if (show_properties) - r = print_property(name, &sub3); - else if (strstr(verb, "session")) - r = status_property_session(name, &sub3, &session_info); - else if (strstr(verb, "user")) - r = status_property_user(name, &sub3, &user_info); - else - r = status_property_seat(name, &sub3, &seat_info); - - if (r < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_next(&sub); - } - - if (!show_properties) { - if (strstr(verb, "session")) - print_session_status_info(&session_info); - else if (strstr(verb, "user")) - print_user_status_info(&user_info); - else - print_seat_status_info(&seat_info); - } - - strv_free(seat_info.sessions); - strv_free(user_info.sessions); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int show(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; - int r, ret = 0; - DBusError error; - unsigned i; - bool show_properties, new_line = false; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - show_properties = !strstr(args[0], "status"); - - if (show_properties) - pager_open_if_enabled(); - - if (show_properties && n <= 1) { - /* If not argument is specified inspect the manager - * itself */ - - ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line); - goto finish; - } - - for (i = 1; i < n; i++) { - const char *path = NULL; - - if (strstr(args[0], "session")) { - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "GetSession"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - } else if (strstr(args[0], "user")) { - uid_t uid; - uint32_t u; - - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL); - if (ret < 0) { - log_error("User %s unknown.", args[i]); - goto finish; - } - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "GetUser"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - u = (uint32_t) uid; - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - } else { - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "GetSeat"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - r = show_one(args[0], bus, path, show_properties, &new_line); - if (r != 0) - ret = r; - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return ret; -} - -static int activate(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - for (i = 1; i < n; i++) { - DBusMessage *reply; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - streq(args[0], "lock-session") ? "LockSession" : - streq(args[0], "unlock-session") ? "UnlockSession" : - streq(args[0], "terminate-session") ? "TerminateSession" : - "ActivateSession"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int kill_session(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - if (!arg_kill_who) - arg_kill_who = "all"; - - for (i = 1; i < n; i++) { - DBusMessage *reply; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "KillSession"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_STRING, &arg_kill_who, - DBUS_TYPE_INT32, arg_signal, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int enable_linger(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - dbus_bool_t b, interactive = true; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - b = streq(args[0], "enable-linger"); - - for (i = 1; i < n; i++) { - DBusMessage *reply; - uint32_t u; - uid_t uid; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetUserLinger"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL); - if (ret < 0) { - log_error("Failed to resolve user %s: %s", args[i], strerror(-ret)); - goto finish; - } - - u = (uint32_t) uid; - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_BOOLEAN, &b, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - ret = 0; - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int terminate_user(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - for (i = 1; i < n; i++) { - uint32_t u; - uid_t uid; - DBusMessage *reply; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "TerminateUser"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL); - if (ret < 0) { - log_error("Failed to look up user %s: %s", args[i], strerror(-ret)); - goto finish; - } - - u = (uint32_t) uid; - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - ret = 0; - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int kill_user(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - if (!arg_kill_who) - arg_kill_who = "all"; - - for (i = 1; i < n; i++) { - DBusMessage *reply; - uid_t uid; - uint32_t u; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "KillUser"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL); - if (ret < 0) { - log_error("Failed to look up user %s: %s", args[i], strerror(-ret)); - goto finish; - } - - u = (uint32_t) uid; - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &u, - DBUS_TYPE_INT32, arg_signal, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - ret = 0; - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int attach(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - dbus_bool_t interactive = true; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - for (i = 2; i < n; i++) { - DBusMessage *reply; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "AttachDevice"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[1], - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int flush_devices(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; - int ret = 0; - DBusError error; - dbus_bool_t interactive = true; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "FlushDevices"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return ret; -} - -static int terminate_seat(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL; - int ret = 0; - DBusError error; - unsigned i; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - for (i = 1; i < n; i++) { - DBusMessage *reply; - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "TerminateSeat"); - if (!m) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &args[i], - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return ret; -} - -static int help(void) { - - printf("%s [OPTIONS...] {COMMAND} ...\n\n" - "Send control commands to or query the login manager.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " -p --property=NAME Show only properties by this name\n" - " -a --all Show all properties, including empty ones\n" - " --kill-who=WHO Who to send signal to\n" - " -s --signal=SIGNAL Which signal to send\n" - " -H --host=[USER@]HOST\n" - " Show information for remote host\n" - " -P --privileged Acquire privileges before execution\n" - " --no-pager Do not pipe output into a pager\n\n" - "Commands:\n" - " list-sessions List sessions\n" - " session-status [ID...] Show session status\n" - " show-session [ID...] Show properties of one or more sessions\n" - " activate [ID] Activate a session\n" - " lock-session [ID...] Screen lock one or more sessions\n" - " unlock-session [ID...] Screen unlock one or more sessions\n" - " terminate-session [ID...] Terminate one or more sessions\n" - " kill-session [ID...] Send signal to processes of a session\n" - " list-users List users\n" - " user-status [USER...] Show user status\n" - " show-user [USER...] Show properties of one or more users\n" - " enable-linger [USER...] Enable linger state of one or more users\n" - " disable-linger [USER...] Disable linger state of one or more users\n" - " terminate-user [USER...] Terminate all sessions of one or more users\n" - " kill-user [USER...] Send signal to processes of a user\n" - " list-seats List seats\n" - " seat-status [NAME...] Show seat status\n" - " show-seat [NAME...] Show properties of one or more seats\n" - " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n" - " flush-devices Flush all device associations\n" - " terminate-seat [NAME...] Terminate all sessions on one or more seats\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_NO_PAGER, - ARG_KILL_WHO - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "property", required_argument, NULL, 'p' }, - { "all", no_argument, NULL, 'a' }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "kill-who", required_argument, NULL, ARG_KILL_WHO }, - { "signal", required_argument, NULL, 's' }, - { "host", required_argument, NULL, 'H' }, - { "privileged",no_argument, NULL, 'P' }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(DISTRIBUTION); - puts(SYSTEMD_FEATURES); - return 0; - - case 'p': { - char **l; - - l = strv_append(arg_property, optarg); - if (!l) - return -ENOMEM; - - strv_free(arg_property); - arg_property = l; - - /* If the user asked for a particular - * property, show it to him, even if it is - * empty. */ - arg_all = true; - break; - } - - case 'a': - arg_all = true; - break; - - case ARG_NO_PAGER: - arg_no_pager = true; - break; - - case ARG_KILL_WHO: - arg_kill_who = optarg; - break; - - case 's': - arg_signal = signal_from_string_try_harder(optarg); - if (arg_signal < 0) { - log_error("Failed to parse signal string %s.", optarg); - return -EINVAL; - } - break; - - case 'P': - arg_transport = TRANSPORT_POLKIT; - break; - - case 'H': - arg_transport = TRANSPORT_SSH; - arg_host = optarg; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - return 1; -} - -static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) { - - static const struct { - const char* verb; - const enum { - MORE, - LESS, - EQUAL - } argc_cmp; - const int argc; - int (* const dispatch)(DBusConnection *bus, char **args, unsigned n); - } verbs[] = { - { "list-sessions", LESS, 1, list_sessions }, - { "session-status", MORE, 2, show }, - { "show-session", MORE, 1, show }, - { "activate", EQUAL, 2, activate }, - { "lock-session", MORE, 2, activate }, - { "unlock-session", MORE, 2, activate }, - { "terminate-session", MORE, 2, activate }, - { "kill-session", MORE, 2, kill_session }, - { "list-users", EQUAL, 1, list_users }, - { "user-status", MORE, 2, show }, - { "show-user", MORE, 1, show }, - { "enable-linger", MORE, 2, enable_linger }, - { "disable-linger", MORE, 2, enable_linger }, - { "terminate-user", MORE, 2, terminate_user }, - { "kill-user", MORE, 2, kill_user }, - { "list-seats", EQUAL, 1, list_seats }, - { "seat-status", MORE, 2, show }, - { "show-seat", MORE, 1, show }, - { "attach", MORE, 3, attach }, - { "flush-devices", EQUAL, 1, flush_devices }, - { "terminate-seat", MORE, 2, terminate_seat }, - }; - - int left; - unsigned i; - - assert(argc >= 0); - assert(argv); - assert(error); - - left = argc - optind; - - if (left <= 0) - /* Special rule: no arguments means "list-sessions" */ - i = 0; - else { - if (streq(argv[optind], "help")) { - help(); - return 0; - } - - for (i = 0; i < ELEMENTSOF(verbs); i++) - if (streq(argv[optind], verbs[i].verb)) - break; - - if (i >= ELEMENTSOF(verbs)) { - log_error("Unknown operation %s", argv[optind]); - return -EINVAL; - } - } - - switch (verbs[i].argc_cmp) { - - case EQUAL: - if (left != verbs[i].argc) { - log_error("Invalid number of arguments."); - return -EINVAL; - } - - break; - - case MORE: - if (left < verbs[i].argc) { - log_error("Too few arguments."); - return -EINVAL; - } - - break; - - case LESS: - if (left > verbs[i].argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - break; - - default: - assert_not_reached("Unknown comparison operator."); - } - - if (!bus) { - log_error("Failed to get D-Bus connection: %s", error->message); - return -EIO; - } - - return verbs[i].dispatch(bus, argv + optind, left); -} - -int main(int argc, char*argv[]) { - int r, retval = EXIT_FAILURE; - DBusConnection *bus = NULL; - DBusError error; - - dbus_error_init(&error); - - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r < 0) - goto finish; - else if (r == 0) { - retval = EXIT_SUCCESS; - goto finish; - } - - if (arg_transport == TRANSPORT_NORMAL) - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - else if (arg_transport == TRANSPORT_POLKIT) - bus_connect_system_polkit(&bus, &error); - else if (arg_transport == TRANSPORT_SSH) - bus_connect_system_ssh(NULL, arg_host, &bus, &error); - else - assert_not_reached("Uh, invalid transport..."); - - r = loginctl_main(bus, argc, argv, &error); - retval = r < 0 ? EXIT_FAILURE : r; - -finish: - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - dbus_error_free(&error); - dbus_shutdown(); - - strv_free(arg_property); - - pager_close(); - - return retval; -} diff --git a/src/logind-acl.c b/src/logind-acl.c deleted file mode 100644 index 7a06b50..0000000 --- a/src/logind-acl.c +++ /dev/null @@ -1,287 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "logind-acl.h" -#include "util.h" - -static int find_acl(acl_t acl, uid_t uid, acl_entry_t *entry) { - acl_entry_t i; - int found; - - assert(acl); - assert(entry); - - for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { - - acl_tag_t tag; - uid_t *u; - bool b; - - if (acl_get_tag_type(i, &tag) < 0) - return -errno; - - if (tag != ACL_USER) - continue; - - u = acl_get_qualifier(i); - if (!u) - return -errno; - - b = *u == uid; - acl_free(u); - - if (b) { - *entry = i; - return 1; - } - } - - if (found < 0) - return -errno; - - return 0; -} - -static int flush_acl(acl_t acl) { - acl_entry_t i; - int found; - bool changed = false; - - assert(acl); - - for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { - - acl_tag_t tag; - - if (acl_get_tag_type(i, &tag) < 0) - return -errno; - - if (tag != ACL_USER) - continue; - - if (acl_delete_entry(acl, i) < 0) - return -errno; - - changed = true; - } - - if (found < 0) - return -errno; - - return changed; -} - -int devnode_acl(const char *path, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid) { - - acl_t acl; - int r = 0; - bool changed = false; - - assert(path); - - acl = acl_get_file(path, ACL_TYPE_ACCESS); - if (!acl) - return -errno; - - if (flush) { - - r = flush_acl(acl); - if (r < 0) - goto finish; - if (r > 0) - changed = true; - - } else if (del && old_uid > 0) { - acl_entry_t entry; - - r = find_acl(acl, old_uid, &entry); - if (r < 0) - goto finish; - - if (r > 0) { - if (acl_delete_entry(acl, entry) < 0) { - r = -errno; - goto finish; - } - - changed = true; - } - } - - if (add && new_uid > 0) { - acl_entry_t entry; - acl_permset_t permset; - int rd, wt; - - r = find_acl(acl, new_uid, &entry); - if (r < 0) - goto finish; - - if (r == 0) { - if (acl_create_entry(&acl, &entry) < 0) { - r = -errno; - goto finish; - } - - if (acl_set_tag_type(entry, ACL_USER) < 0 || - acl_set_qualifier(entry, &new_uid) < 0) { - r = -errno; - goto finish; - } - } - - if (acl_get_permset(entry, &permset) < 0) { - r = -errno; - goto finish; - } - - rd = acl_get_perm(permset, ACL_READ); - if (rd < 0) { - r = -errno; - goto finish; - } - - wt = acl_get_perm(permset, ACL_WRITE); - if (wt < 0) { - r = -errno; - goto finish; - } - - if (!rd || !wt) { - - if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) { - r = -errno; - goto finish; - } - - changed = true; - } - } - - if (!changed) - goto finish; - - if (acl_calc_mask(&acl) < 0) { - r = -errno; - goto finish; - } - - if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) { - r = -errno; - goto finish; - } - - r = 0; - -finish: - acl_free(acl); - - return r; -} - -int devnode_acl_all(struct udev *udev, - const char *seat, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid) { - - struct udev_list_entry *item = NULL, *first = NULL; - struct udev_enumerate *e; - int r; - - assert(udev); - - if (isempty(seat)) - seat = "seat0"; - - e = udev_enumerate_new(udev); - if (!e) - return -ENOMEM; - - /* We can only match by one tag in libudev. We choose - * "uaccess" for that. If we could match for two tags here we - * could add the seat name as second match tag, but this would - * be hardly optimizable in libudev, and hence checking the - * second tag manually in our loop is a good solution. */ - - r = udev_enumerate_add_match_tag(e, "uaccess"); - if (r < 0) - goto finish; - - r = udev_enumerate_scan_devices(e); - if (r < 0) - goto finish; - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - struct udev_device *d; - const char *node, *sn; - - d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); - if (!d) { - r = -ENOMEM; - goto finish; - } - - sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(sn)) - sn = "seat0"; - - if (!streq(seat, sn)) { - udev_device_unref(d); - continue; - } - - node = udev_device_get_devnode(d); - if (!node) { - /* In case people mistag devices with nodes, we need to ignore this */ - udev_device_unref(d); - continue; - } - - log_debug("Fixing up %s for seat %s...", node, sn); - - r = devnode_acl(node, flush, del, old_uid, add, new_uid); - udev_device_unref(d); - - if (r < 0) - goto finish; - } - -finish: - if (e) - udev_enumerate_unref(e); - - return r; -} diff --git a/src/logind-acl.h b/src/logind-acl.h deleted file mode 100644 index 72740f5..0000000 --- a/src/logind-acl.h +++ /dev/null @@ -1,60 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologindaclhfoo -#define foologindaclhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#ifdef HAVE_ACL - -int devnode_acl(const char *path, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid); - -int devnode_acl_all(struct udev *udev, - const char *seat, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid); -#else - -static inline int devnode_acl(const char *path, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid) { - return 0; -} - -static inline int devnode_acl_all(struct udev *udev, - const char *seat, - bool flush, - bool del, uid_t old_uid, - bool add, uid_t new_uid) { - return 0; -} - -#endif - -#endif diff --git a/src/logind-dbus.c b/src/logind-dbus.c deleted file mode 100644 index 0550d1b..0000000 --- a/src/logind-dbus.c +++ /dev/null @@ -1,1504 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "logind.h" -#include "dbus-common.h" -#include "strv.h" -#include "polkit.h" -#include "special.h" - -#define BUS_MANAGER_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION_BEGIN \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_MANAGER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE - -#define INTROSPECTION_END \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.login1.Manager\0" - -static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(m); - - b = manager_get_idle_hint(m, NULL) > 0; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) { - Manager *m = data; - dual_timestamp t; - uint64_t u; - - assert(i); - assert(property); - assert(m); - - manager_get_idle_hint(m, &t); - u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) { - Session *session = NULL; - User *user = NULL; - const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service; - uint32_t uid, leader, audit_id = 0; - dbus_bool_t remote, kill_processes; - char **controllers = NULL, **reset_controllers = NULL; - SessionType t; - Seat *s; - DBusMessageIter iter; - int r; - char *id = NULL, *p; - uint32_t vtnr = 0; - int fifo_fd = -1; - DBusMessage *reply = NULL; - bool b; - - assert(m); - assert(message); - assert(_reply); - - if (!dbus_message_iter_init(message, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &uid); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &leader); - - if (leader <= 0 || - !dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &service); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &type); - t = session_type_from_string(type); - - if (t < 0 || - !dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &seat); - - if (isempty(seat)) - s = NULL; - else { - s = hashmap_get(m->seats, seat); - if (!s) - return -ENOENT; - } - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &vtnr); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &tty); - - if (tty_is_vc(tty)) { - int v; - - if (!s) - s = m->vtconsole; - else if (s != m->vtconsole) - return -EINVAL; - - v = vtnr_from_tty(tty); - - if (v <= 0) - return v < 0 ? v : -EINVAL; - - if (vtnr <= 0) - vtnr = (uint32_t) v; - else if (vtnr != (uint32_t) v) - return -EINVAL; - - } else if (!isempty(tty) && s && seat_is_vtconsole(s)) - return -EINVAL; - - if (s) { - if (seat_is_vtconsole(s)) { - if (vtnr <= 0 || vtnr > 63) - return -EINVAL; - } else { - if (vtnr > 0) - return -EINVAL; - } - } - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &display); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &remote); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &remote_user); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_get_basic(&iter, &remote_host); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) - return -EINVAL; - - r = bus_parse_strv_iter(&iter, &controllers); - if (r < 0) - return -EINVAL; - - if (strv_contains(controllers, "systemd") || - !dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) { - r = -EINVAL; - goto fail; - } - - r = bus_parse_strv_iter(&iter, &reset_controllers); - if (r < 0) - goto fail; - - if (strv_contains(reset_controllers, "systemd") || - !dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) { - r = -EINVAL; - goto fail; - } - - dbus_message_iter_get_basic(&iter, &kill_processes); - - r = manager_add_user_by_uid(m, uid, &user); - if (r < 0) - goto fail; - - audit_session_from_pid(leader, &audit_id); - - if (audit_id > 0) { - asprintf(&id, "%lu", (unsigned long) audit_id); - - if (!id) { - r = -ENOMEM; - goto fail; - } - - session = hashmap_get(m->sessions, id); - - if (session) { - free(id); - - fifo_fd = session_create_fifo(session); - if (fifo_fd < 0) { - r = fifo_fd; - goto fail; - } - - /* Session already exists, client is probably - * something like "su" which changes uid but - * is still the same audit session */ - - reply = dbus_message_new_method_return(message); - if (!reply) { - r = -ENOMEM; - goto fail; - } - - p = session_bus_path(session); - if (!p) { - r = -ENOMEM; - goto fail; - } - - seat = session->seat ? session->seat->id : ""; - vtnr = session->vtnr; - b = dbus_message_append_args( - reply, - DBUS_TYPE_STRING, &session->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &fifo_fd, - DBUS_TYPE_STRING, &seat, - DBUS_TYPE_UINT32, &vtnr, - DBUS_TYPE_INVALID); - free(p); - - if (!b) { - r = -ENOMEM; - goto fail; - } - - close_nointr_nofail(fifo_fd); - *_reply = reply; - - strv_free(controllers); - strv_free(reset_controllers); - - return 0; - } - - } else { - do { - free(id); - asprintf(&id, "c%lu", ++m->session_counter); - - if (!id) { - r = -ENOMEM; - goto fail; - } - - } while (hashmap_get(m->sessions, id)); - } - - r = manager_add_session(m, user, id, &session); - free(id); - if (r < 0) - goto fail; - - session->leader = leader; - session->audit_id = audit_id; - session->type = t; - session->remote = remote; - session->controllers = controllers; - session->reset_controllers = reset_controllers; - session->kill_processes = kill_processes; - session->vtnr = vtnr; - - controllers = reset_controllers = NULL; - - if (!isempty(tty)) { - session->tty = strdup(tty); - if (!session->tty) { - r = -ENOMEM; - goto fail; - } - } - - if (!isempty(display)) { - session->display = strdup(display); - if (!session->display) { - r = -ENOMEM; - goto fail; - } - } - - if (!isempty(remote_user)) { - session->remote_user = strdup(remote_user); - if (!session->remote_user) { - r = -ENOMEM; - goto fail; - } - } - - if (!isempty(remote_host)) { - session->remote_host = strdup(remote_host); - if (!session->remote_host) { - r = -ENOMEM; - goto fail; - } - } - - if (!isempty(service)) { - session->service = strdup(service); - if (!session->service) { - r = -ENOMEM; - goto fail; - } - } - - fifo_fd = session_create_fifo(session); - if (fifo_fd < 0) { - r = fifo_fd; - goto fail; - } - - if (s) { - r = seat_attach_session(s, session); - if (r < 0) - goto fail; - } - - r = session_start(session); - if (r < 0) - goto fail; - - reply = dbus_message_new_method_return(message); - if (!reply) { - r = -ENOMEM; - goto fail; - } - - p = session_bus_path(session); - if (!p) { - r = -ENOMEM; - goto fail; - } - - seat = s ? s->id : ""; - b = dbus_message_append_args( - reply, - DBUS_TYPE_STRING, &session->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_STRING, &session->user->runtime_path, - DBUS_TYPE_UNIX_FD, &fifo_fd, - DBUS_TYPE_STRING, &seat, - DBUS_TYPE_UINT32, &vtnr, - DBUS_TYPE_INVALID); - free(p); - - if (!b) { - r = -ENOMEM; - goto fail; - } - - close_nointr_nofail(fifo_fd); - *_reply = reply; - - return 0; - -fail: - strv_free(controllers); - strv_free(reset_controllers); - - if (session) - session_add_to_gc_queue(session); - - if (user) - user_add_to_gc_queue(user); - - if (fifo_fd >= 0) - close_nointr_nofail(fifo_fd); - - if (reply) - dbus_message_unref(reply); - - return r; -} - -static int trigger_device(Manager *m, struct udev_device *d) { - struct udev_enumerate *e; - struct udev_list_entry *first, *item; - int r; - - assert(m); - - e = udev_enumerate_new(m->udev); - if (!e) { - r = -ENOMEM; - goto finish; - } - - if (d) { - if (udev_enumerate_add_match_parent(e, d) < 0) { - r = -EIO; - goto finish; - } - } - - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; - goto finish; - } - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - char *t; - const char *p; - - p = udev_list_entry_get_name(item); - - t = strappend(p, "/uevent"); - if (!t) { - r = -ENOMEM; - goto finish; - } - - write_one_line_file(t, "change"); - free(t); - } - - r = 0; - -finish: - if (e) - udev_enumerate_unref(e); - - return r; -} - -static int attach_device(Manager *m, const char *seat, const char *sysfs) { - struct udev_device *d; - char *rule = NULL, *file = NULL; - const char *id_for_seat; - int r; - - assert(m); - assert(seat); - assert(sysfs); - - d = udev_device_new_from_syspath(m->udev, sysfs); - if (!d) - return -ENODEV; - - if (!udev_device_has_tag(d, "seat")) { - r = -ENODEV; - goto finish; - } - - id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT"); - if (!id_for_seat) { - r = -ENODEV; - goto finish; - } - - if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) { - r = -ENOMEM; - goto finish; - } - - if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) { - r = -ENOMEM; - goto finish; - } - - mkdir_p("/etc/udev/rules.d", 0755); - r = write_one_line_file_atomic(file, rule); - if (r < 0) - goto finish; - - r = trigger_device(m, d); - -finish: - free(rule); - free(file); - - if (d) - udev_device_unref(d); - - return r; -} - -static int flush_devices(Manager *m) { - DIR *d; - - assert(m); - - d = opendir("/etc/udev/rules.d"); - if (!d) { - if (errno != ENOENT) - log_warning("Failed to open /etc/udev/rules.d: %m"); - } else { - struct dirent *de; - - while ((de = readdir(d))) { - - if (!dirent_is_file(de)) - continue; - - if (!startswith(de->d_name, "72-seat-")) - continue; - - if (!endswith(de->d_name, ".rules")) - continue; - - if (unlinkat(dirfd(d), de->d_name, 0) < 0) - log_warning("Failed to unlink %s: %m", de->d_name); - } - - closedir(d); - } - - return trigger_device(m, NULL); -} - -static DBusHandlerResult manager_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - Manager *m = userdata; - - const BusProperty properties[] = { - { "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path }, - { "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers }, - { "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers }, - { "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts }, - { "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users }, - { "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users }, - { "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes }, - { "org.freedesktop.login1.Manager", "IdleHint", bus_manager_append_idle_hint, "b", m }, - { "org.freedesktop.login1.Manager", "IdleSinceHint", bus_manager_append_idle_hint_since, "t", m }, - { "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(connection); - assert(message); - assert(m); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) { - const char *name; - char *p; - Session *session; - bool b; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(m->sessions, name); - if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - p = session_bus_path(session); - if (!p) - goto oom; - - b = dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID); - free(p); - - if (!b) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) { - uint32_t uid; - char *p; - User *user; - bool b; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); - if (!user) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - p = user_bus_path(user); - if (!p) - goto oom; - - b = dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID); - free(p); - - if (!b) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) { - const char *name; - char *p; - Seat *seat; - bool b; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - seat = hashmap_get(m->seats, name); - if (!seat) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - p = seat_bus_path(seat); - if (!p) - goto oom; - - b = dbus_message_append_args( - reply, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID); - free(p); - - if (!b) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) { - char *p; - Session *session; - Iterator i; - DBusMessageIter iter, sub; - const char *empty = ""; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub)) - goto oom; - - HASHMAP_FOREACH(session, m->sessions, i) { - DBusMessageIter sub2; - uint32_t uid; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - uid = session->user->uid; - - p = session_bus_path(session); - if (!p) - goto oom; - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - goto oom; - } - - free(p); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) { - char *p; - User *user; - Iterator i; - DBusMessageIter iter, sub; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub)) - goto oom; - - HASHMAP_FOREACH(user, m->users, i) { - DBusMessageIter sub2; - uint32_t uid; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - uid = user->uid; - - p = user_bus_path(user); - if (!p) - goto oom; - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - goto oom; - } - - free(p); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) { - char *p; - Seat *seat; - Iterator i; - DBusMessageIter iter, sub; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub)) - goto oom; - - HASHMAP_FOREACH(seat, m->seats, i) { - DBusMessageIter sub2; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - goto oom; - - p = seat_bus_path(seat); - if (!p) - goto oom; - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - goto oom; - } - - free(p); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) { - - r = bus_manager_create_session(m, message, &reply); - - /* Don't delay the work on OOM here, since it might be - * triggered by a low RLIMIT_NOFILE here (since we - * send a dupped fd to the client), and we'd rather - * see this fail quickly then be retried later */ - - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) { - const char *name; - Session *session; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(m->sessions, name); - if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = session_activate(session); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") || - dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) { - const char *name; - Session *session; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(m->sessions, name); - if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0) - goto oom; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) { - const char *swho; - int32_t signo; - KillWho who; - const char *name; - Session *session; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(m->sessions, name); - if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = session_kill(session, who, signo); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) { - uint32_t uid; - User *user; - int32_t signo; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); - if (!user) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = user_kill(user, signo); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) { - const char *name; - Session *session; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(m->sessions, name); - if (!session) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = session_stop(session); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) { - uint32_t uid; - User *user; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); - if (!user) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = user_stop(user); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) { - const char *name; - Seat *seat; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - seat = hashmap_get(m->seats, name); - if (!seat) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = seat_stop_sessions(seat); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) { - uint32_t uid; - struct passwd *pw; - dbus_bool_t b, interactive; - char *path; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_BOOLEAN, &b, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - errno = 0; - pw = getpwuid(uid); - if (!pw) - return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL); - - r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - path = strappend("/var/lib/systemd/linger/", pw->pw_name); - if (!path) - goto oom; - - if (b) { - User *u; - - r = touch(path); - free(path); - - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (manager_add_user_by_uid(m, uid, &u) >= 0) - user_start(u); - - } else { - User *u; - - r = unlink(path); - free(path); - - if (r < 0 && errno != ENOENT) - return bus_send_error_reply(connection, message, &error, -errno); - - u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); - if (u) - user_add_to_gc_queue(u); - } - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) { - const char *sysfs, *seat; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &seat, - DBUS_TYPE_STRING, &sysfs, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - r = attach_device(m, seat, sysfs); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) { - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - r = flush_devices(m); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") || - dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) { - dbus_bool_t interactive; - bool multiple_sessions; - DBusMessage *forward, *freply; - const char *name; - const char *mode = "replace"; - const char *action; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - multiple_sessions = hashmap_size(m->sessions) > 1; - - if (!multiple_sessions) { - Session *s; - - /* Hmm, there's only one session, but let's - * make sure it actually belongs to the user - * who is asking. If not, better be safe than - * sorry. */ - - s = hashmap_first(m->sessions); - if (s) { - unsigned long ul; - - ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error); - if (ul == (unsigned long) -1) - return bus_send_error_reply(connection, message, &error, -EIO); - - multiple_sessions = s->user->uid != ul; - } - } - - if (streq(dbus_message_get_member(message), "PowerOff")) { - if (multiple_sessions) - action = "org.freedesktop.login1.power-off-multiple-sessions"; - else - action = "org.freedesktop.login1.power-off"; - - name = SPECIAL_POWEROFF_TARGET; - } else { - if (multiple_sessions) - action = "org.freedesktop.login1.reboot-multiple-sessions"; - else - action = "org.freedesktop.login1.reboot"; - - name = SPECIAL_REBOOT_TARGET; - } - - r = verify_polkit(connection, message, action, interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - forward = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "StartUnit"); - if (!forward) - return bus_send_error_reply(connection, message, NULL, -ENOMEM); - - if (!dbus_message_append_args(forward, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - dbus_message_unref(forward); - return bus_send_error_reply(connection, message, NULL, -ENOMEM); - } - - freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error); - dbus_message_unref(forward); - - if (!freply) - return bus_send_error_reply(connection, message, &error, -EIO); - - dbus_message_unref(freply); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; - FILE *f; - Iterator i; - Session *session; - Seat *seat; - User *user; - size_t size; - char *p; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - /* We roll our own introspection code here, instead of - * relying on bus_default_message_handler() because we - * need to generate our introspection string - * dynamically. */ - - if (!(f = open_memstream(&introspection, &size))) - goto oom; - - fputs(INTROSPECTION_BEGIN, f); - - HASHMAP_FOREACH(seat, m->seats, i) { - p = bus_path_escape(seat->id); - - if (p) { - fprintf(f, "", p); - free(p); - } - } - - HASHMAP_FOREACH(user, m->users, i) - fprintf(f, "", (unsigned long long) user->uid); - - HASHMAP_FOREACH(session, m->sessions, i) { - p = bus_path_escape(session->id); - - if (p) { - fprintf(f, "", p); - free(p); - } - } - - fputs(INTROSPECTION_END, f); - - if (ferror(f)) { - fclose(f); - free(introspection); - goto oom; - } - - fclose(f); - - if (!introspection) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); - goto oom; - } - - free(introspection); - } else - return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -const DBusObjectPathVTable bus_manager_vtable = { - .message_function = manager_message_handler -}; - -DBusHandlerResult bus_message_filter( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - Manager *m = userdata; - DBusError error; - - assert(m); - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) { - const char *cgroup; - - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &cgroup, - DBUS_TYPE_INVALID)) - log_error("Failed to parse Released message: %s", bus_error_message(&error)); - else - manager_cgroup_notify_empty(m, cgroup); - } - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -int manager_send_changed(Manager *manager, const char *properties) { - DBusMessage *m; - int r = -ENOMEM; - - assert(manager); - - m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties); - if (!m) - goto finish; - - if (!dbus_connection_send(manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - return r; -} diff --git a/src/logind-device.c b/src/logind-device.c deleted file mode 100644 index bbd370f..0000000 --- a/src/logind-device.c +++ /dev/null @@ -1,86 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "logind-device.h" -#include "util.h" - -Device* device_new(Manager *m, const char *sysfs) { - Device *d; - - assert(m); - assert(sysfs); - - d = new0(Device, 1); - if (!d) - return NULL; - - d->sysfs = strdup(sysfs); - if (!d->sysfs) { - free(d); - return NULL; - } - - if (hashmap_put(m->devices, d->sysfs, d) < 0) { - free(d->sysfs); - free(d); - return NULL; - } - - d->manager = m; - dual_timestamp_get(&d->timestamp); - - return d; -} - -void device_free(Device *d) { - assert(d); - - device_detach(d); - - hashmap_remove(d->manager->devices, d->sysfs); - - free(d->sysfs); - free(d); -} - -void device_detach(Device *d) { - assert(d); - - if (d->seat) - LIST_REMOVE(Device, devices, d->seat->devices, d); - - seat_add_to_gc_queue(d->seat); - d->seat = NULL; -} - -void device_attach(Device *d, Seat *s) { - assert(d); - assert(s); - - if (d->seat) - device_detach(d); - - d->seat = s; - LIST_PREPEND(Device, devices, s->devices, d); -} diff --git a/src/logind-device.h b/src/logind-device.h deleted file mode 100644 index e25a534..0000000 --- a/src/logind-device.h +++ /dev/null @@ -1,48 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologinddevicehfoo -#define foologinddevicehfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Device Device; - -#include "list.h" -#include "util.h" -#include "logind.h" -#include "logind-seat.h" - -struct Device { - Manager *manager; - - char *sysfs; - Seat *seat; - - dual_timestamp timestamp; - - LIST_FIELDS(struct Device, devices); -}; - -Device* device_new(Manager *m, const char *sysfs); -void device_free(Device *d); -void device_attach(Device *d, Seat *s); -void device_detach(Device *d); - -#endif diff --git a/src/logind-gperf.gperf b/src/logind-gperf.gperf deleted file mode 100644 index 940fe10..0000000 --- a/src/logind-gperf.gperf +++ /dev/null @@ -1,22 +0,0 @@ -%{ -#include -#include "conf-parser.h" -#include "logind.h" -%} -struct ConfigPerfItem; -%null_strings -%language=ANSI-C -%define slot-name section_and_lvalue -%define hash-function-name logind_gperf_hash -%define lookup-function-name logind_gperf_lookup -%readonly-tables -%omit-struct-type -%struct-type -%includes -%% -Login.NAutoVTs, config_parse_unsigned, 0, offsetof(Manager, n_autovts) -Login.KillUserProcesses, config_parse_bool, 0, offsetof(Manager, kill_user_processes) -Login.KillOnlyUsers, config_parse_strv, 0, offsetof(Manager, kill_only_users) -Login.KillExcludeUsers, config_parse_strv, 0, offsetof(Manager, kill_exclude_users) -Login.Controllers, config_parse_strv, 0, offsetof(Manager, controllers) -Login.ResetControllers, config_parse_strv, 0, offsetof(Manager, reset_controllers) diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c deleted file mode 100644 index 3a916ee..0000000 --- a/src/logind-seat-dbus.c +++ /dev/null @@ -1,403 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "logind.h" -#include "logind-seat.h" -#include "dbus-common.h" -#include "util.h" - -#define BUS_SEAT_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_SEAT_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.login1.Seat\0" - -static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; - Seat *s = data; - const char *id, *path; - char *p = NULL; - - assert(i); - assert(property); - assert(s); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (s->active) { - id = s->active->id; - path = p = session_bus_path(s->active); - - if (!p) - return -ENOMEM; - } else { - id = ""; - path = "/"; - } - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub, sub2; - Seat *s = data; - Session *session; - - assert(i); - assert(property); - assert(s); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub)) - return -ENOMEM; - - LIST_FOREACH(sessions_by_seat, session, s->sessions) { - char *p; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - return -ENOMEM; - - p = session_bus_path(session); - if (!p) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_seat_append_multi_session(DBusMessageIter *i, const char *property, void *data) { - Seat *s = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(s); - - b = seat_is_vtconsole(s); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) { - Seat *s = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(s); - - b = seat_get_idle_hint(s, NULL) > 0; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) { - Seat *s = data; - dual_timestamp t; - uint64_t k; - - assert(i); - assert(property); - assert(s); - - seat_get_idle_hint(s, &t); - k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k)) - return -ENOMEM; - - return 0; -} - -static int get_seat_for_path(Manager *m, const char *path, Seat **_s) { - Seat *s; - char *id; - - assert(m); - assert(path); - assert(_s); - - if (!startswith(path, "/org/freedesktop/login1/seat/")) - return -EINVAL; - - id = bus_path_unescape(path + 29); - if (!id) - return -ENOMEM; - - s = hashmap_get(m->seats, id); - free(id); - - if (!s) - return -ENOENT; - - *_s = s; - return 0; -} - -static DBusHandlerResult seat_message_dispatch( - Seat *s, - DBusConnection *connection, - DBusMessage *message) { - - const BusProperty properties[] = { - { "org.freedesktop.login1.Seat", "Id", bus_property_append_string, "s", s->id }, - { "org.freedesktop.login1.Seat", "ActiveSession", bus_seat_append_active, "(so)", s }, - { "org.freedesktop.login1.Seat", "CanMultiSession", bus_seat_append_multi_session, "b", s }, - { "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s }, - { "org.freedesktop.login1.Seat", "IdleHint", bus_seat_append_idle_hint, "b", s }, - { "org.freedesktop.login1.Seat", "IdleSinceHint", bus_seat_append_idle_hint_since, "t", s }, - { "org.freedesktop.login1.Seat", "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", s }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(s); - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) { - - r = seat_stop_sessions(s); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) { - const char *name; - Session *session; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - session = hashmap_get(s->manager->sessions, name); - if (!session || session->seat != s) - return bus_send_error_reply(connection, message, &error, -ENOENT); - - r = session_activate(session); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult seat_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - Manager *m = userdata; - Seat *s; - int r; - - r = get_seat_for_path(m, dbus_message_get_path(message), &s); - if (r < 0) { - - if (r == -ENOMEM) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat"); - return bus_send_error_reply(connection, message, &e, r); - } - - return bus_send_error_reply(connection, message, NULL, r); - } - - return seat_message_dispatch(s, connection, message); -} - -const DBusObjectPathVTable bus_seat_vtable = { - .message_function = seat_message_handler -}; - -char *seat_bus_path(Seat *s) { - char *t, *r; - - assert(s); - - t = bus_path_escape(s->id); - if (!t) - return NULL; - - r = strappend("/org/freedesktop/login1/seat/", t); - free(t); - - return r; -} - -int seat_send_signal(Seat *s, bool new_seat) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - - assert(s); - - m = dbus_message_new_signal("/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - new_seat ? "SeatNew" : "SeatRemoved"); - - if (!m) - return -ENOMEM; - - p = seat_bus_path(s); - if (!p) - goto finish; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &s->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto finish; - - if (!dbus_connection_send(s->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - dbus_message_unref(m); - free(p); - - return r; -} - -int seat_send_changed(Seat *s, const char *properties) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - - assert(s); - - if (!s->started) - return 0; - - p = seat_bus_path(s); - if (!p) - return -ENOMEM; - - m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties); - if (!m) - goto finish; - - if (!dbus_connection_send(s->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - free(p); - - return r; -} diff --git a/src/logind-seat.c b/src/logind-seat.c deleted file mode 100644 index 3cf3958..0000000 --- a/src/logind-seat.c +++ /dev/null @@ -1,499 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "logind-seat.h" -#include "logind-acl.h" -#include "util.h" - -Seat *seat_new(Manager *m, const char *id) { - Seat *s; - - assert(m); - assert(id); - - s = new0(Seat, 1); - if (!s) - return NULL; - - s->state_file = strappend("/run/systemd/seats/", id); - if (!s->state_file) { - free(s); - return NULL; - } - - s->id = file_name_from_path(s->state_file); - s->manager = m; - - if (hashmap_put(m->seats, s->id, s) < 0) { - free(s->state_file); - free(s); - return NULL; - } - - return s; -} - -void seat_free(Seat *s) { - assert(s); - - if (s->in_gc_queue) - LIST_REMOVE(Seat, gc_queue, s->manager->seat_gc_queue, s); - - while (s->sessions) - session_free(s->sessions); - - assert(!s->active); - - while (s->devices) - device_free(s->devices); - - hashmap_remove(s->manager->seats, s->id); - - free(s->state_file); - free(s); -} - -int seat_save(Seat *s) { - int r; - FILE *f; - char *temp_path; - - assert(s); - - if (!s->started) - return 0; - - r = safe_mkdir("/run/systemd/seats", 0755, 0, 0); - if (r < 0) - goto finish; - - r = fopen_temporary(s->state_file, &f, &temp_path); - if (r < 0) - goto finish; - - fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "IS_VTCONSOLE=%i\n", - seat_is_vtconsole(s)); - - if (s->active) { - assert(s->active->user); - - fprintf(f, - "ACTIVE=%s\n" - "ACTIVE_UID=%lu\n", - s->active->id, - (unsigned long) s->active->user->uid); - } - - if (s->sessions) { - Session *i; - - fputs("SESSIONS=", f); - LIST_FOREACH(sessions_by_seat, i, s->sessions) { - fprintf(f, - "%s%c", - i->id, - i->sessions_by_seat_next ? ' ' : '\n'); - } - - fputs("UIDS=", f); - LIST_FOREACH(sessions_by_seat, i, s->sessions) - fprintf(f, - "%lu%c", - (unsigned long) i->user->uid, - i->sessions_by_seat_next ? ' ' : '\n'); - } - - fflush(f); - - if (ferror(f) || rename(temp_path, s->state_file) < 0) { - r = -errno; - unlink(s->state_file); - unlink(temp_path); - } - - fclose(f); - free(temp_path); - -finish: - if (r < 0) - log_error("Failed to save seat data for %s: %s", s->id, strerror(-r)); - - return r; -} - -int seat_load(Seat *s) { - assert(s); - - /* There isn't actually anything to read here ... */ - - return 0; -} - -static int vt_allocate(int vtnr) { - int fd, r; - char *p; - - assert(vtnr >= 1); - - if (asprintf(&p, "/dev/tty%i", vtnr) < 0) - return -ENOMEM; - - fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC); - free(p); - - r = fd < 0 ? -errno : 0; - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -int seat_preallocate_vts(Seat *s) { - int r = 0; - unsigned i; - - assert(s); - assert(s->manager); - - log_debug("Preallocating VTs..."); - - if (s->manager->n_autovts <= 0) - return 0; - - if (!seat_is_vtconsole(s)) - return 0; - - for (i = 1; i <= s->manager->n_autovts; i++) { - int q; - - q = vt_allocate(i); - if (q < 0) { - log_error("Failed to preallocate VT %i: %s", i, strerror(-q)); - r = q; - } - } - - return r; -} - -int seat_apply_acls(Seat *s, Session *old_active) { - int r; - - assert(s); - - r = devnode_acl_all(s->manager->udev, - s->id, - false, - !!old_active, old_active ? old_active->user->uid : 0, - !!s->active, s->active ? s->active->user->uid : 0); - - if (r < 0) - log_error("Failed to apply ACLs: %s", strerror(-r)); - - return r; -} - -int seat_set_active(Seat *s, Session *session) { - Session *old_active; - - assert(s); - assert(!session || session->seat == s); - - if (session == s->active) - return 0; - - old_active = s->active; - s->active = session; - - seat_apply_acls(s, old_active); - - if (session && session->started) - session_send_changed(session, "Active\0"); - - if (!session || session->started) - seat_send_changed(s, "ActiveSession\0"); - - seat_save(s); - - if (session) { - session_save(session); - user_save(session->user); - } - - if (old_active) { - session_save(old_active); - user_save(old_active->user); - } - - return 0; -} - -int seat_active_vt_changed(Seat *s, int vtnr) { - Session *i, *new_active = NULL; - int r; - - assert(s); - assert(vtnr >= 1); - - if (!seat_is_vtconsole(s)) - return -EINVAL; - - log_debug("VT changed to %i", vtnr); - - LIST_FOREACH(sessions_by_seat, i, s->sessions) - if (i->vtnr == vtnr) { - new_active = i; - break; - } - - r = seat_set_active(s, new_active); - manager_spawn_autovt(s->manager, vtnr); - - return r; -} - -int seat_read_active_vt(Seat *s) { - char t[64]; - ssize_t k; - int r, vtnr; - - assert(s); - - if (!seat_is_vtconsole(s)) - return 0; - - lseek(s->manager->console_active_fd, SEEK_SET, 0); - - k = read(s->manager->console_active_fd, t, sizeof(t)-1); - if (k <= 0) { - log_error("Failed to read current console: %s", k < 0 ? strerror(-errno) : "EOF"); - return k < 0 ? -errno : -EIO; - } - - t[k] = 0; - truncate_nl(t); - - if (!startswith(t, "tty")) { - log_error("Hm, /sys/class/tty/tty0/active is badly formatted."); - return -EIO; - } - - r = safe_atoi(t+3, &vtnr); - if (r < 0) { - log_error("Failed to parse VT number %s", t+3); - return r; - } - - if (vtnr <= 0) { - log_error("VT number invalid: %s", t+3); - return -EIO; - } - - return seat_active_vt_changed(s, vtnr); -} - -int seat_start(Seat *s) { - assert(s); - - if (s->started) - return 0; - - log_info("New seat %s.", s->id); - - /* Initialize VT magic stuff */ - seat_preallocate_vts(s); - - /* Read current VT */ - seat_read_active_vt(s); - - s->started = true; - - /* Save seat data */ - seat_save(s); - - seat_send_signal(s, true); - - return 0; -} - -int seat_stop(Seat *s) { - int r = 0; - - assert(s); - - if (s->started) - log_info("Removed seat %s.", s->id); - - seat_stop_sessions(s); - - unlink(s->state_file); - seat_add_to_gc_queue(s); - - if (s->started) - seat_send_signal(s, false); - - s->started = false; - - return r; -} - -int seat_stop_sessions(Seat *s) { - Session *session; - int r = 0, k; - - assert(s); - - LIST_FOREACH(sessions_by_seat, session, s->sessions) { - k = session_stop(session); - if (k < 0) - r = k; - } - - return r; -} - -int seat_attach_session(Seat *s, Session *session) { - assert(s); - assert(session); - assert(!session->seat); - - if (!seat_is_vtconsole(s) && s->sessions) - return -EEXIST; - - session->seat = s; - LIST_PREPEND(Session, sessions_by_seat, s->sessions, session); - - seat_send_changed(s, "Sessions\0"); - - if (!seat_is_vtconsole(s)) { - assert(!s->active); - seat_set_active(s, session); - } - - return 0; -} - -bool seat_is_vtconsole(Seat *s) { - assert(s); - - return s->manager->vtconsole == s; -} - -int seat_get_idle_hint(Seat *s, dual_timestamp *t) { - Session *session; - bool idle_hint = true; - dual_timestamp ts = { 0, 0 }; - - assert(s); - - LIST_FOREACH(sessions_by_seat, session, s->sessions) { - dual_timestamp k; - int ih; - - ih = session_get_idle_hint(session, &k); - if (ih < 0) - return ih; - - if (!ih) { - if (!idle_hint) { - if (k.monotonic < ts.monotonic) - ts = k; - } else { - idle_hint = false; - ts = k; - } - } else if (idle_hint) { - - if (k.monotonic > ts.monotonic) - ts = k; - } - } - - if (t) - *t = ts; - - return idle_hint; -} - -int seat_check_gc(Seat *s, bool drop_not_started) { - assert(s); - - if (drop_not_started && !s->started) - return 0; - - if (seat_is_vtconsole(s)) - return 1; - - return !!s->devices; -} - -void seat_add_to_gc_queue(Seat *s) { - assert(s); - - if (s->in_gc_queue) - return; - - LIST_PREPEND(Seat, gc_queue, s->manager->seat_gc_queue, s); - s->in_gc_queue = true; -} - -static bool seat_name_valid_char(char c) { - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '-' || - c == '_'; -} - -bool seat_name_is_valid(const char *name) { - const char *p; - - assert(name); - - if (!startswith(name, "seat")) - return false; - - if (!name[4]) - return false; - - for (p = name; *p; p++) - if (!seat_name_valid_char(*p)) - return false; - - if (strlen(name) > 255) - return false; - - return true; -} diff --git a/src/logind-seat.h b/src/logind-seat.h deleted file mode 100644 index 5bce143..0000000 --- a/src/logind-seat.h +++ /dev/null @@ -1,82 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologindseathfoo -#define foologindseathfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Seat Seat; - -#include "list.h" -#include "util.h" -#include "logind.h" -#include "logind-device.h" -#include "logind-session.h" - -struct Seat { - Manager *manager; - char *id; - - char *state_file; - - LIST_HEAD(Device, devices); - - Session *active; - LIST_HEAD(Session, sessions); - - bool in_gc_queue:1; - bool started:1; - - LIST_FIELDS(Seat, gc_queue); -}; - -Seat *seat_new(Manager *m, const char *id); -void seat_free(Seat *s); - -int seat_save(Seat *s); -int seat_load(Seat *s); - -int seat_apply_acls(Seat *s, Session *old_active); -int seat_set_active(Seat *s, Session *session); -int seat_active_vt_changed(Seat *s, int vtnr); -int seat_read_active_vt(Seat *s); -int seat_preallocate_vts(Seat *s); - -int seat_attach_session(Seat *s, Session *session); - -bool seat_is_vtconsole(Seat *s); -int seat_get_idle_hint(Seat *s, dual_timestamp *t); - -int seat_start(Seat *s); -int seat_stop(Seat *s); -int seat_stop_sessions(Seat *s); - -int seat_check_gc(Seat *s, bool drop_not_started); -void seat_add_to_gc_queue(Seat *s); - -bool seat_name_is_valid(const char *name); -char *seat_bus_path(Seat *s); - -extern const DBusObjectPathVTable bus_seat_vtable; - -int seat_send_signal(Seat *s, bool new_seat); -int seat_send_changed(Seat *s, const char *properties); - -#endif diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c deleted file mode 100644 index dc0ef5b..0000000 --- a/src/logind-session-dbus.c +++ /dev/null @@ -1,515 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "logind.h" -#include "logind-session.h" -#include "dbus-common.h" -#include "util.h" - -#define BUS_SESSION_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_SESSION_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.login1.Session\0" - -static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; - Session *s = data; - const char *id, *path; - char *p = NULL; - - assert(i); - assert(property); - assert(s); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (s->seat) { - id = s->seat->id; - path = p = seat_bus_path(s->seat); - - if (!p) - return -ENOMEM; - } else { - id = ""; - path = "/"; - } - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; - Session *s = data; - char *p = NULL; - - assert(i); - assert(property); - assert(s); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - p = user_bus_path(s->user); - if (!p) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &s->user->uid) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) { - Session *s = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(s); - - b = session_is_active(s); - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) { - Session *s = data; - int b; - - assert(i); - assert(property); - assert(s); - - b = session_get_idle_hint(s, NULL) > 0; - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) { - Session *s = data; - dual_timestamp t; - uint64_t u; - - assert(i); - assert(property); - assert(s); - - session_get_idle_hint(s, &t); - u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType); - -static int get_session_for_path(Manager *m, const char *path, Session **_s) { - Session *s; - char *id; - - assert(m); - assert(path); - assert(_s); - - if (!startswith(path, "/org/freedesktop/login1/session/")) - return -EINVAL; - - id = bus_path_unescape(path + 32); - if (!id) - return -ENOMEM; - - s = hashmap_get(m->sessions, id); - free(id); - - if (!s) - return -ENOENT; - - *_s = s; - return 0; -} - -static DBusHandlerResult session_message_dispatch( - Session *s, - DBusConnection *connection, - DBusMessage *message) { - - const BusProperty properties[] = { - { "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id }, - { "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s }, - { "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name }, - { "org.freedesktop.login1.Session", "Timestamp", bus_property_append_usec, "t", &s->timestamp.realtime }, - { "org.freedesktop.login1.Session", "TimestampMonotonic", bus_property_append_usec, "t", &s->timestamp.monotonic }, - { "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path }, - { "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr }, - { "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s }, - { "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty }, - { "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display }, - { "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote }, - { "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user }, - { "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host }, - { "org.freedesktop.login1.Session", "Service", bus_property_append_string, "s", s->service }, - { "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader }, - { "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id }, - { "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type }, - { "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s }, - { "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers }, - { "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers }, - { "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes }, - { "org.freedesktop.login1.Session", "IdleHint", bus_session_append_idle_hint, "b", s }, - { "org.freedesktop.login1.Session", "IdleSinceHint", bus_session_append_idle_hint_since, "t", s }, - { "org.freedesktop.login1.Session", "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", s }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(s); - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) { - - r = session_stop(s); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) { - - r = session_activate(s); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") || - dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) { - - if (session_send_signal(s, streq(dbus_message_get_member(message), "Lock")) < 0) - goto oom; - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) { - dbus_bool_t b; - unsigned long ul; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_BOOLEAN, &b, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error); - if (ul == (unsigned long) -1) - return bus_send_error_reply(connection, message, &error, -EIO); - - if (ul != 0 && ul != s->user->uid) - return bus_send_error_reply(connection, message, NULL, -EPERM); - - session_set_idle_hint(s, b); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) { - const char *swho; - int32_t signo; - KillWho who; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &swho, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (isempty(swho)) - who = KILL_ALL; - else { - who = kill_who_from_string(swho); - if (who < 0) - return bus_send_error_reply(connection, message, &error, -EINVAL); - } - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - r = session_kill(s, who, signo); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult session_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - Manager *m = userdata; - Session *s; - int r; - - r = get_session_for_path(m, dbus_message_get_path(message), &s); - if (r < 0) { - - if (r == -ENOMEM) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session"); - return bus_send_error_reply(connection, message, &e, r); - } - - return bus_send_error_reply(connection, message, NULL, r); - } - - return session_message_dispatch(s, connection, message); -} - -const DBusObjectPathVTable bus_session_vtable = { - .message_function = session_message_handler -}; - -char *session_bus_path(Session *s) { - char *t, *r; - - assert(s); - - t = bus_path_escape(s->id); - if (!t) - return NULL; - - r = strappend("/org/freedesktop/login1/session/", t); - free(t); - - return r; -} - -int session_send_signal(Session *s, bool new_session) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - - assert(s); - - m = dbus_message_new_signal("/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - new_session ? "SessionNew" : "SessionRemoved"); - - if (!m) - return -ENOMEM; - - p = session_bus_path(s); - if (!p) - goto finish; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &s->id, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto finish; - - if (!dbus_connection_send(s->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - dbus_message_unref(m); - free(p); - - return r; -} - -int session_send_changed(Session *s, const char *properties) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - - assert(s); - - if (!s->started) - return 0; - - p = session_bus_path(s); - if (!p) - return -ENOMEM; - - m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties); - if (!m) - goto finish; - - if (!dbus_connection_send(s->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - free(p); - - return r; -} - -int session_send_lock(Session *s, bool lock) { - DBusMessage *m; - bool b; - char *p; - - assert(s); - - p = session_bus_path(s); - if (!p) - return -ENOMEM; - - m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock"); - free(p); - - if (!m) - return -ENOMEM; - - b = dbus_connection_send(s->manager->bus, m, NULL); - dbus_message_unref(m); - - if (!b) - return -ENOMEM; - - return 0; -} diff --git a/src/logind-session.c b/src/logind-session.c deleted file mode 100644 index b0a09e3..0000000 --- a/src/logind-session.c +++ /dev/null @@ -1,945 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "logind-session.h" -#include "strv.h" -#include "util.h" -#include "cgroup-util.h" - -#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE) - -Session* session_new(Manager *m, User *u, const char *id) { - Session *s; - - assert(m); - assert(id); - - s = new0(Session, 1); - if (!s) - return NULL; - - s->state_file = strappend("/run/systemd/sessions/", id); - if (!s->state_file) { - free(s); - return NULL; - } - - s->id = file_name_from_path(s->state_file); - - if (hashmap_put(m->sessions, s->id, s) < 0) { - free(s->id); - free(s); - return NULL; - } - - s->manager = m; - s->fifo_fd = -1; - s->user = u; - - LIST_PREPEND(Session, sessions_by_user, u->sessions, s); - - return s; -} - -void session_free(Session *s) { - assert(s); - - if (s->in_gc_queue) - LIST_REMOVE(Session, gc_queue, s->manager->session_gc_queue, s); - - if (s->user) { - LIST_REMOVE(Session, sessions_by_user, s->user->sessions, s); - - if (s->user->display == s) - s->user->display = NULL; - } - - if (s->seat) { - if (s->seat->active == s) - s->seat->active = NULL; - - LIST_REMOVE(Session, sessions_by_seat, s->seat->sessions, s); - } - - if (s->cgroup_path) - hashmap_remove(s->manager->cgroups, s->cgroup_path); - - free(s->cgroup_path); - strv_free(s->controllers); - - free(s->tty); - free(s->display); - free(s->remote_host); - free(s->remote_user); - free(s->service); - - hashmap_remove(s->manager->sessions, s->id); - - session_remove_fifo(s); - - free(s->state_file); - free(s); -} - -int session_save(Session *s) { - FILE *f; - int r = 0; - char *temp_path; - - assert(s); - - if (!s->started) - return 0; - - r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0); - if (r < 0) - goto finish; - - r = fopen_temporary(s->state_file, &f, &temp_path); - if (r < 0) - goto finish; - - assert(s->user); - - fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "UID=%lu\n" - "USER=%s\n" - "ACTIVE=%i\n" - "REMOTE=%i\n" - "KILL_PROCESSES=%i\n", - (unsigned long) s->user->uid, - s->user->name, - session_is_active(s), - s->remote, - s->kill_processes); - - if (s->type >= 0) - fprintf(f, - "TYPE=%s\n", - session_type_to_string(s->type)); - - if (s->cgroup_path) - fprintf(f, - "CGROUP=%s\n", - s->cgroup_path); - - if (s->fifo_path) - fprintf(f, - "FIFO=%s\n", - s->fifo_path); - - if (s->seat) - fprintf(f, - "SEAT=%s\n", - s->seat->id); - - if (s->tty) - fprintf(f, - "TTY=%s\n", - s->tty); - - if (s->display) - fprintf(f, - "DISPLAY=%s\n", - s->display); - - if (s->remote_host) - fprintf(f, - "REMOTE_HOST=%s\n", - s->remote_host); - - if (s->remote_user) - fprintf(f, - "REMOTE_USER=%s\n", - s->remote_user); - - if (s->service) - fprintf(f, - "SERVICE=%s\n", - s->service); - - if (s->seat && seat_is_vtconsole(s->seat)) - fprintf(f, - "VTNR=%i\n", - s->vtnr); - - if (s->leader > 0) - fprintf(f, - "LEADER=%lu\n", - (unsigned long) s->leader); - - if (s->audit_id > 0) - fprintf(f, - "AUDIT=%llu\n", - (unsigned long long) s->audit_id); - - fflush(f); - - if (ferror(f) || rename(temp_path, s->state_file) < 0) { - r = -errno; - unlink(s->state_file); - unlink(temp_path); - } - - fclose(f); - free(temp_path); - -finish: - if (r < 0) - log_error("Failed to save session data for %s: %s", s->id, strerror(-r)); - - return r; -} - -int session_load(Session *s) { - char *remote = NULL, - *kill_processes = NULL, - *seat = NULL, - *vtnr = NULL, - *leader = NULL, - *audit_id = NULL, - *type = NULL; - - int k, r; - - assert(s); - - r = parse_env_file(s->state_file, NEWLINE, - "REMOTE", &remote, - "KILL_PROCESSES", &kill_processes, - "CGROUP", &s->cgroup_path, - "FIFO", &s->fifo_path, - "SEAT", &seat, - "TTY", &s->tty, - "DISPLAY", &s->display, - "REMOTE_HOST", &s->remote_host, - "REMOTE_USER", &s->remote_user, - "SERVICE", &s->service, - "VTNR", &vtnr, - "LEADER", &leader, - "TYPE", &type, - NULL); - - if (r < 0) - goto finish; - - if (remote) { - k = parse_boolean(remote); - if (k >= 0) - s->remote = k; - } - - if (kill_processes) { - k = parse_boolean(kill_processes); - if (k >= 0) - s->kill_processes = k; - } - - if (seat && !s->seat) { - Seat *o; - - o = hashmap_get(s->manager->seats, seat); - if (o) - seat_attach_session(o, s); - } - - if (vtnr && s->seat && seat_is_vtconsole(s->seat)) { - int v; - - k = safe_atoi(vtnr, &v); - if (k >= 0 && v >= 1) - s->vtnr = v; - } - - if (leader) { - pid_t pid; - - k = parse_pid(leader, &pid); - if (k >= 0 && pid >= 1) { - s->leader = pid; - - audit_session_from_pid(pid, &s->audit_id); - } - } - - if (type) { - SessionType t; - - t = session_type_from_string(type); - if (t >= 0) - s->type = t; - } - - if (s->fifo_path) { - int fd; - - /* If we open an unopened pipe for reading we will not - get an EOF. to trigger an EOF we hence open it for - reading, but close it right-away which then will - trigger the EOF. */ - - fd = session_create_fifo(s); - if (fd >= 0) - close_nointr_nofail(fd); - } - - -finish: - free(remote); - free(kill_processes); - free(seat); - free(vtnr); - free(leader); - free(audit_id); - - return r; -} - -int session_activate(Session *s) { - int r; - Session *old_active; - - assert(s); - - if (s->vtnr < 0) - return -ENOTSUP; - - if (!s->seat) - return -ENOTSUP; - - if (s->seat->active == s) - return 0; - - assert(seat_is_vtconsole(s->seat)); - - r = chvt(s->vtnr); - if (r < 0) - return r; - - old_active = s->seat->active; - s->seat->active = s; - - return seat_apply_acls(s->seat, old_active); -} - -static int session_link_x11_socket(Session *s) { - char *t, *f, *c; - size_t k; - - assert(s); - assert(s->user); - assert(s->user->runtime_path); - - if (s->user->display) - return 0; - - if (!s->display || !display_is_local(s->display)) - return 0; - - k = strspn(s->display+1, "0123456789"); - f = new(char, sizeof("/tmp/.X11-unix/X") + k); - if (!f) { - log_error("Out of memory"); - return -ENOMEM; - } - - c = stpcpy(f, "/tmp/.X11-unix/X"); - memcpy(c, s->display+1, k); - c[k] = 0; - - if (access(f, F_OK) < 0) { - log_warning("Session %s has display %s with nonexisting socket %s.", s->id, s->display, f); - free(f); - return -ENOENT; - } - - t = strappend(s->user->runtime_path, "/X11/display"); - if (!t) { - log_error("Out of memory"); - free(f); - return -ENOMEM; - } - - mkdir_parents(t, 0755); - - if (link(f, t) < 0) { - if (errno == EEXIST) { - unlink(t); - - if (link(f, t) >= 0) - goto done; - } - - if (symlink(f, t) < 0) { - - if (errno == EEXIST) { - unlink(t); - - if (symlink(f, t) >= 0) - goto done; - } - - log_error("Failed to link %s to %s: %m", f, t); - free(f); - free(t); - return -errno; - } - } - -done: - log_info("Linked %s to %s.", f, t); - free(f); - free(t); - - s->user->display = s; - - return 0; -} - -static int session_create_one_group(Session *s, const char *controller, const char *path) { - int r; - - assert(s); - assert(controller); - assert(path); - - if (s->leader > 0) { - r = cg_create_and_attach(controller, path, s->leader); - if (r < 0) - r = cg_create(controller, path); - } else - r = cg_create(controller, path); - - if (r < 0) - return r; - - r = cg_set_task_access(controller, path, 0644, s->user->uid, s->user->gid); - if (r >= 0) - r = cg_set_group_access(controller, path, 0755, s->user->uid, s->user->gid); - - return r; -} - -static int session_create_cgroup(Session *s) { - char **k; - char *p; - int r; - - assert(s); - assert(s->user); - assert(s->user->cgroup_path); - - if (!s->cgroup_path) { - if (asprintf(&p, "%s/%s", s->user->cgroup_path, s->id) < 0) { - log_error("Out of memory"); - return -ENOMEM; - } - } else - p = s->cgroup_path; - - r = session_create_one_group(s, SYSTEMD_CGROUP_CONTROLLER, p); - if (r < 0) { - log_error("Failed to create "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r)); - free(p); - s->cgroup_path = NULL; - return r; - } - - s->cgroup_path = p; - - STRV_FOREACH(k, s->controllers) { - - if (strv_contains(s->reset_controllers, *k)) - continue; - - r = session_create_one_group(s, *k, p); - if (r < 0) - log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r)); - } - - STRV_FOREACH(k, s->manager->controllers) { - - if (strv_contains(s->reset_controllers, *k) || - strv_contains(s->manager->reset_controllers, *k) || - strv_contains(s->controllers, *k)) - continue; - - r = session_create_one_group(s, *k, p); - if (r < 0) - log_warning("Failed to create %s:%s: %s", *k, p, strerror(-r)); - } - - if (s->leader > 0) { - - STRV_FOREACH(k, s->reset_controllers) { - r = cg_attach(*k, "/", s->leader); - if (r < 0) - log_warning("Failed to reset controller %s: %s", *k, strerror(-r)); - - } - - STRV_FOREACH(k, s->manager->reset_controllers) { - - if (strv_contains(s->reset_controllers, *k) || - strv_contains(s->controllers, *k)) - continue; - - r = cg_attach(*k, "/", s->leader); - if (r < 0) - log_warning("Failed to reset controller %s: %s", *k, strerror(-r)); - - } - } - - hashmap_put(s->manager->cgroups, s->cgroup_path, s); - - return 0; -} - -int session_start(Session *s) { - int r; - - assert(s); - assert(s->user); - - if (s->started) - return 0; - - r = user_start(s->user); - if (r < 0) - return r; - - log_full(s->display || s->tty ? LOG_INFO : LOG_DEBUG, - "New session %s of user %s.", s->id, s->user->name); - - /* Create cgroup */ - r = session_create_cgroup(s); - if (r < 0) - return r; - - /* Create X11 symlink */ - session_link_x11_socket(s); - - dual_timestamp_get(&s->timestamp); - - if (s->seat) - seat_read_active_vt(s->seat); - - s->started = true; - - /* Save session data */ - session_save(s); - user_save(s->user); - - session_send_signal(s, true); - - if (s->seat) { - seat_save(s->seat); - - if (s->seat->active == s) - seat_send_changed(s->seat, "Sessions\0ActiveSession\0"); - else - seat_send_changed(s->seat, "Sessions\0"); - } - - user_send_changed(s->user, "Sessions\0"); - - return 0; -} - -static bool session_shall_kill(Session *s) { - assert(s); - - if (!s->kill_processes) - return false; - - if (strv_contains(s->manager->kill_exclude_users, s->user->name)) - return false; - - if (strv_isempty(s->manager->kill_only_users)) - return true; - - return strv_contains(s->manager->kill_only_users, s->user->name); -} - -static int session_terminate_cgroup(Session *s) { - int r; - char **k; - - assert(s); - - if (!s->cgroup_path) - return 0; - - cg_trim(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false); - - if (session_shall_kill(s)) { - - r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true); - if (r < 0) - log_error("Failed to kill session cgroup: %s", strerror(-r)); - - } else { - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, true); - if (r < 0) - log_error("Failed to check session cgroup: %s", strerror(-r)); - else if (r > 0) { - r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path); - if (r < 0) - log_error("Failed to delete session cgroup: %s", strerror(-r)); - } else - r = -EBUSY; - } - - STRV_FOREACH(k, s->user->manager->controllers) - cg_trim(*k, s->cgroup_path, true); - - hashmap_remove(s->manager->cgroups, s->cgroup_path); - - free(s->cgroup_path); - s->cgroup_path = NULL; - - return r; -} - -static int session_unlink_x11_socket(Session *s) { - char *t; - int r; - - assert(s); - assert(s->user); - - if (s->user->display != s) - return 0; - - s->user->display = NULL; - - t = strappend(s->user->runtime_path, "/X11/display"); - if (!t) { - log_error("Out of memory"); - return -ENOMEM; - } - - r = unlink(t); - free(t); - - return r < 0 ? -errno : 0; -} - -int session_stop(Session *s) { - int r = 0, k; - - assert(s); - - if (s->started) - log_full(s->display || s->tty ? LOG_INFO : LOG_DEBUG, - "Removed session %s.", s->id); - - /* Kill cgroup */ - k = session_terminate_cgroup(s); - if (k < 0) - r = k; - - /* Remove X11 symlink */ - session_unlink_x11_socket(s); - - unlink(s->state_file); - session_add_to_gc_queue(s); - user_add_to_gc_queue(s->user); - - if (s->started) - session_send_signal(s, false); - - if (s->seat) { - if (s->seat->active == s) - seat_set_active(s->seat, NULL); - - seat_send_changed(s->seat, "Sessions\0"); - } - - user_send_changed(s->user, "Sessions\0"); - - s->started = false; - - return r; -} - -bool session_is_active(Session *s) { - assert(s); - - if (!s->seat) - return true; - - return s->seat->active == s; -} - -int session_get_idle_hint(Session *s, dual_timestamp *t) { - char *p; - struct stat st; - usec_t u, n; - bool b; - int k; - - assert(s); - - if (s->idle_hint) { - if (t) - *t = s->idle_hint_timestamp; - - return s->idle_hint; - } - - if (isempty(s->tty)) - goto dont_know; - - if (s->tty[0] != '/') { - p = strappend("/dev/", s->tty); - if (!p) - return -ENOMEM; - } else - p = NULL; - - if (!startswith(p ? p : s->tty, "/dev/")) { - free(p); - goto dont_know; - } - - k = lstat(p ? p : s->tty, &st); - free(p); - - if (k < 0) - goto dont_know; - - u = timespec_load(&st.st_atim); - n = now(CLOCK_REALTIME); - b = u + IDLE_THRESHOLD_USEC < n; - - if (t) - dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0); - - return b; - -dont_know: - if (t) - *t = s->idle_hint_timestamp; - - return 0; -} - -void session_set_idle_hint(Session *s, bool b) { - assert(s); - - if (s->idle_hint == b) - return; - - s->idle_hint = b; - dual_timestamp_get(&s->idle_hint_timestamp); - - session_send_changed(s, - "IdleHint\0" - "IdleSinceHint\0" - "IdleSinceHintMonotonic\0"); - - if (s->seat) - seat_send_changed(s->seat, - "IdleHint\0" - "IdleSinceHint\0" - "IdleSinceHintMonotonic\0"); - - user_send_changed(s->user, - "IdleHint\0" - "IdleSinceHint\0" - "IdleSinceHintMonotonic\0"); - - manager_send_changed(s->manager, - "IdleHint\0" - "IdleSinceHint\0" - "IdleSinceHintMonotonic\0"); -} - -int session_create_fifo(Session *s) { - int r; - - assert(s); - - /* Create FIFO */ - if (!s->fifo_path) { - r = safe_mkdir("/run/systemd/sessions", 0755, 0, 0); - if (r < 0) - return r; - - if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0) - return -ENOMEM; - - if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST) - return -errno; - } - - /* Open reading side */ - if (s->fifo_fd < 0) { - struct epoll_event ev; - - s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY); - if (s->fifo_fd < 0) - return -errno; - - r = hashmap_put(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1), s); - if (r < 0) - return r; - - zero(ev); - ev.events = 0; - ev.data.u32 = FD_FIFO_BASE + s->fifo_fd; - - if (epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->fifo_fd, &ev) < 0) - return -errno; - } - - /* Open writing side */ - r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY); - if (r < 0) - return -errno; - - return r; -} - -void session_remove_fifo(Session *s) { - assert(s); - - if (s->fifo_fd >= 0) { - assert_se(hashmap_remove(s->manager->fifo_fds, INT_TO_PTR(s->fifo_fd + 1)) == s); - assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0); - close_nointr_nofail(s->fifo_fd); - s->fifo_fd = -1; - } - - if (s->fifo_path) { - unlink(s->fifo_path); - free(s->fifo_path); - s->fifo_path = NULL; - } -} - -int session_check_gc(Session *s, bool drop_not_started) { - int r; - - assert(s); - - if (drop_not_started && !s->started) - return 0; - - if (s->fifo_fd >= 0) { - - r = pipe_eof(s->fifo_fd); - if (r < 0) - return r; - - if (r == 0) - return 1; - } - - if (s->cgroup_path) { - - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, false); - if (r < 0) - return r; - - if (r <= 0) - return 1; - } - - return 0; -} - -void session_add_to_gc_queue(Session *s) { - assert(s); - - if (s->in_gc_queue) - return; - - LIST_PREPEND(Session, gc_queue, s->manager->session_gc_queue, s); - s->in_gc_queue = true; -} - -int session_kill(Session *s, KillWho who, int signo) { - int r = 0; - Set *pid_set = NULL; - - assert(s); - - if (!s->cgroup_path) - return -ESRCH; - - if (s->leader <= 0 && who == KILL_LEADER) - return -ESRCH; - - if (s->leader > 0) - if (kill(s->leader, signo) < 0) - r = -errno; - - if (who == KILL_ALL) { - int q; - - pid_set = set_new(trivial_hash_func, trivial_compare_func); - if (!pid_set) - return -ENOMEM; - - if (s->leader > 0) { - q = set_put(pid_set, LONG_TO_PTR(s->leader)); - if (q < 0) - r = q; - } - - q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set); - if (q < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - } - - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const session_type_table[_SESSION_TYPE_MAX] = { - [SESSION_TTY] = "tty", - [SESSION_X11] = "x11", - [SESSION_UNSPECIFIED] = "unspecified" -}; - -DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType); - -static const char* const kill_who_table[_KILL_WHO_MAX] = { - [KILL_LEADER] = "leader", - [KILL_ALL] = "all" -}; - -DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/logind-session.h b/src/logind-session.h deleted file mode 100644 index 8e394ac..0000000 --- a/src/logind-session.h +++ /dev/null @@ -1,124 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologindsessionhfoo -#define foologindsessionhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Session Session; - -#include "list.h" -#include "util.h" -#include "logind.h" -#include "logind-seat.h" -#include "logind-user.h" - -typedef enum SessionType { - SESSION_UNSPECIFIED, - SESSION_TTY, - SESSION_X11, - _SESSION_TYPE_MAX, - _SESSION_TYPE_INVALID = -1 -} SessionType; - -typedef enum KillWho { - KILL_LEADER, - KILL_ALL, - _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 -} KillWho; - -struct Session { - Manager *manager; - - char *id; - SessionType type; - - char *state_file; - - User *user; - - dual_timestamp timestamp; - - char *tty; - char *display; - - bool remote; - char *remote_user; - char *remote_host; - - char *service; - - int vtnr; - Seat *seat; - - pid_t leader; - uint32_t audit_id; - - int fifo_fd; - char *fifo_path; - - char *cgroup_path; - char **controllers, **reset_controllers; - - bool idle_hint; - dual_timestamp idle_hint_timestamp; - - bool kill_processes; - bool in_gc_queue:1; - bool started:1; - - LIST_FIELDS(Session, sessions_by_user); - LIST_FIELDS(Session, sessions_by_seat); - - LIST_FIELDS(Session, gc_queue); -}; - -Session *session_new(Manager *m, User *u, const char *id); -void session_free(Session *s); -int session_check_gc(Session *s, bool drop_not_started); -void session_add_to_gc_queue(Session *s); -int session_activate(Session *s); -bool session_is_active(Session *s); -int session_get_idle_hint(Session *s, dual_timestamp *t); -void session_set_idle_hint(Session *s, bool b); -int session_create_fifo(Session *s); -void session_remove_fifo(Session *s); -int session_start(Session *s); -int session_stop(Session *s); -int session_save(Session *s); -int session_load(Session *s); -int session_kill(Session *s, KillWho who, int signo); - -char *session_bus_path(Session *s); - -extern const DBusObjectPathVTable bus_session_vtable; - -int session_send_signal(Session *s, bool new_session); -int session_send_changed(Session *s, const char *properties); -int session_send_lock(Session *s, bool lock); - -const char* session_type_to_string(SessionType t); -SessionType session_type_from_string(const char *s); - -const char *kill_who_to_string(KillWho k); -KillWho kill_who_from_string(const char *s); - -#endif diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c deleted file mode 100644 index 3673a28..0000000 --- a/src/logind-user-dbus.c +++ /dev/null @@ -1,411 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "logind.h" -#include "logind-user.h" -#include "dbus-common.h" - -#define BUS_USER_INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - BUS_USER_INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_PEER_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.login1.User\0" - -static int bus_user_append_display(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; - User *u = data; - const char *id, *path; - char *p = NULL; - - assert(i); - assert(property); - assert(u); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub)) - return -ENOMEM; - - if (u->display) { - id = u->display->id; - path = p = session_bus_path(u->display); - - if (!p) - return -ENOMEM; - } else { - id = ""; - path = "/"; - } - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_user_append_state(DBusMessageIter *i, const char *property, void *data) { - User *u = data; - const char *state; - - assert(i); - assert(property); - assert(u); - - state = user_state_to_string(user_get_state(u)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state)) - return -ENOMEM; - - return 0; -} - -static int bus_user_append_sessions(DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub, sub2; - User *u = data; - Session *session; - - assert(i); - assert(property); - assert(u); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub)) - return -ENOMEM; - - LIST_FOREACH(sessions_by_user, session, u->sessions) { - char *p; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2)) - return -ENOMEM; - - p = session_bus_path(session); - if (!p) - return -ENOMEM; - - if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) { - free(p); - return -ENOMEM; - } - - free(p); - - if (!dbus_message_iter_close_container(&sub, &sub2)) - return -ENOMEM; - } - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -static int bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) { - User *u = data; - dbus_bool_t b; - - assert(i); - assert(property); - assert(u); - - b = user_get_idle_hint(u, NULL) > 0; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b)) - return -ENOMEM; - - return 0; -} - -static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) { - User *u = data; - dual_timestamp t; - uint64_t k; - - assert(i); - assert(property); - assert(u); - - user_get_idle_hint(u, &t); - k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k)) - return -ENOMEM; - - return 0; -} - -static int get_user_for_path(Manager *m, const char *path, User **_u) { - User *u; - unsigned long lu; - int r; - - assert(m); - assert(path); - assert(_u); - - if (!startswith(path, "/org/freedesktop/login1/user/")) - return -EINVAL; - - r = safe_atolu(path + 29, &lu); - if (r < 0) - return r; - - u = hashmap_get(m->users, ULONG_TO_PTR(lu)); - if (!u) - return -ENOENT; - - *_u = u; - return 0; -} - -static DBusHandlerResult user_message_dispatch( - User *u, - DBusConnection *connection, - DBusMessage *message) { - - const BusProperty properties[] = { - { "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid }, - { "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid }, - { "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name }, - { "org.freedesktop.login1.User", "Timestamp", bus_property_append_usec, "t", &u->timestamp.realtime }, - { "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec, "t", &u->timestamp.monotonic }, - { "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path }, - { "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path }, - { "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service }, - { "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u }, - { "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u }, - { "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u }, - { "org.freedesktop.login1.User", "IdleHint", bus_user_append_idle_hint, "b", u }, - { "org.freedesktop.login1.User", "IdleSinceHint", bus_user_append_idle_hint_since, "t", u }, - { "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(u); - assert(connection); - assert(message); - - if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) { - - r = user_stop(u); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Kill")) { - int32_t signo; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_INT32, &signo, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - r = user_kill(u, signo); - if (r < 0) - return bus_send_error_reply(connection, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (reply) { - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static DBusHandlerResult user_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - Manager *m = userdata; - User *u; - int r; - - r = get_user_for_path(m, dbus_message_get_path(message), &u); - if (r < 0) { - - if (r == -ENOMEM) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - if (r == -ENOENT) { - DBusError e; - - dbus_error_init(&e); - dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown user"); - return bus_send_error_reply(connection, message, &e, r); - } - - return bus_send_error_reply(connection, message, NULL, r); - } - - return user_message_dispatch(u, connection, message); -} - -const DBusObjectPathVTable bus_user_vtable = { - .message_function = user_message_handler -}; - -char *user_bus_path(User *u) { - char *s; - - assert(u); - - if (asprintf(&s, "/org/freedesktop/login1/user/%llu", (unsigned long long) u->uid) < 0) - return NULL; - - return s; -} - -int user_send_signal(User *u, bool new_user) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - uint32_t uid; - - assert(u); - - m = dbus_message_new_signal("/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - new_user ? "UserNew" : "UserRemoved"); - - if (!m) - return -ENOMEM; - - p = user_bus_path(u); - if (!p) - goto finish; - - uid = u->uid; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_OBJECT_PATH, &p, - DBUS_TYPE_INVALID)) - goto finish; - - if (!dbus_connection_send(u->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - dbus_message_unref(m); - free(p); - - return r; -} - -int user_send_changed(User *u, const char *properties) { - DBusMessage *m; - int r = -ENOMEM; - char *p = NULL; - - assert(u); - - if (!u->started) - return 0; - - p = user_bus_path(u); - if (!p) - return -ENOMEM; - - m = bus_properties_changed_new(p, "org.freedesktop.login1.User", properties); - if (!m) - goto finish; - - if (!dbus_connection_send(u->manager->bus, m, NULL)) - goto finish; - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - free(p); - - return r; -} diff --git a/src/logind-user.c b/src/logind-user.c deleted file mode 100644 index 56c7de4..0000000 --- a/src/logind-user.c +++ /dev/null @@ -1,587 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "logind-user.h" -#include "util.h" -#include "cgroup-util.h" -#include "hashmap.h" -#include "strv.h" - -User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { - User *u; - - assert(m); - assert(name); - - u = new0(User, 1); - if (!u) - return NULL; - - u->name = strdup(name); - if (!u->name) { - free(u); - return NULL; - } - - if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0) { - free(u->name); - free(u); - return NULL; - } - - if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0) { - free(u->state_file); - free(u->name); - free(u); - return NULL; - } - - u->manager = m; - u->uid = uid; - u->gid = gid; - - return u; -} - -void user_free(User *u) { - assert(u); - - if (u->in_gc_queue) - LIST_REMOVE(User, gc_queue, u->manager->user_gc_queue, u); - - while (u->sessions) - session_free(u->sessions); - - free(u->cgroup_path); - - free(u->service); - free(u->runtime_path); - - hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid)); - - free(u->name); - free(u->state_file); - free(u); -} - -int user_save(User *u) { - FILE *f; - int r; - char *temp_path; - - assert(u); - assert(u->state_file); - - if (!u->started) - return 0; - - r = safe_mkdir("/run/systemd/users", 0755, 0, 0); - if (r < 0) - goto finish; - - r = fopen_temporary(u->state_file, &f, &temp_path); - if (r < 0) - goto finish; - - fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "NAME=%s\n" - "STATE=%s\n", - u->name, - user_state_to_string(user_get_state(u))); - - if (u->cgroup_path) - fprintf(f, - "CGROUP=%s\n", - u->cgroup_path); - - if (u->runtime_path) - fprintf(f, - "RUNTIME=%s\n", - u->runtime_path); - - if (u->service) - fprintf(f, - "SERVICE=%s\n", - u->service); - - if (u->display) - fprintf(f, - "DISPLAY=%s\n", - u->display->id); - - if (u->sessions) { - Session *i; - - fputs("SESSIONS=", f); - LIST_FOREACH(sessions_by_user, i, u->sessions) { - fprintf(f, - "%s%c", - i->id, - i->sessions_by_user_next ? ' ' : '\n'); - } - - fputs("SEATS=", f); - LIST_FOREACH(sessions_by_user, i, u->sessions) { - if (i->seat) - fprintf(f, - "%s%c", - i->seat->id, - i->sessions_by_user_next ? ' ' : '\n'); - } - - fputs("ACTIVE_SESSIONS=", f); - LIST_FOREACH(sessions_by_user, i, u->sessions) - if (session_is_active(i)) - fprintf(f, - "%lu%c", - (unsigned long) i->user->uid, - i->sessions_by_user_next ? ' ' : '\n'); - - fputs("ACTIVE_SEATS=", f); - LIST_FOREACH(sessions_by_user, i, u->sessions) { - if (session_is_active(i) && i->seat) - fprintf(f, - "%s%c", - i->seat->id, - i->sessions_by_user_next ? ' ' : '\n'); - } - } - - fflush(f); - - if (ferror(f) || rename(temp_path, u->state_file) < 0) { - r = -errno; - unlink(u->state_file); - unlink(temp_path); - } - - fclose(f); - free(temp_path); - -finish: - if (r < 0) - log_error("Failed to save user data for %s: %s", u->name, strerror(-r)); - - return r; -} - -int user_load(User *u) { - int r; - char *display = NULL; - Session *s = NULL; - - assert(u); - - r = parse_env_file(u->state_file, NEWLINE, - "CGROUP", &u->cgroup_path, - "RUNTIME", &u->runtime_path, - "SERVICE", &u->service, - "DISPLAY", &display, - NULL); - if (r < 0) { - free(display); - - if (r == -ENOENT) - return 0; - - log_error("Failed to read %s: %s", u->state_file, strerror(-r)); - return r; - } - - if (display) { - s = hashmap_get(u->manager->sessions, display); - free(display); - } - - if (s && s->display && display_is_local(s->display)) - u->display = s; - - return r; -} - -static int user_mkdir_runtime_path(User *u) { - char *p; - int r; - - assert(u); - - r = safe_mkdir("/run/user", 0755, 0, 0); - if (r < 0) { - log_error("Failed to create /run/user: %s", strerror(-r)); - return r; - } - - if (!u->runtime_path) { - p = strappend("/run/user/", u->name); - - if (!p) { - log_error("Out of memory"); - return -ENOMEM; - } - } else - p = u->runtime_path; - - r = safe_mkdir(p, 0700, u->uid, u->gid); - if (r < 0) { - log_error("Failed to create runtime directory %s: %s", p, strerror(-r)); - free(p); - u->runtime_path = NULL; - return r; - } - - u->runtime_path = p; - return 0; -} - -static int user_create_cgroup(User *u) { - char **k; - char *p; - int r; - - assert(u); - - if (!u->cgroup_path) { - if (asprintf(&p, "%s/%s", u->manager->cgroup_path, u->name) < 0) { - log_error("Out of memory"); - return -ENOMEM; - } - } else - p = u->cgroup_path; - - r = cg_create(SYSTEMD_CGROUP_CONTROLLER, p); - if (r < 0) { - log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", p, strerror(-r)); - free(p); - u->cgroup_path = NULL; - return r; - } - - u->cgroup_path = p; - - STRV_FOREACH(k, u->manager->controllers) { - - if (strv_contains(u->manager->reset_controllers, *k)) - continue; - - r = cg_create(*k, p); - if (r < 0) - log_warning("Failed to create cgroup %s:%s: %s", *k, p, strerror(-r)); - } - - return 0; -} - -static int user_start_service(User *u) { - assert(u); - - return 0; -} - -int user_start(User *u) { - int r; - - assert(u); - - if (u->started) - return 0; - - log_info("New user %s logged in.", u->name); - - /* Make XDG_RUNTIME_DIR */ - r = user_mkdir_runtime_path(u); - if (r < 0) - return r; - - /* Create cgroup */ - r = user_create_cgroup(u); - if (r < 0) - return r; - - /* Spawn user systemd */ - r = user_start_service(u); - if (r < 0) - return r; - - dual_timestamp_get(&u->timestamp); - - u->started = true; - - /* Save new user data */ - user_save(u); - - user_send_signal(u, true); - - return 0; -} - -static int user_stop_service(User *u) { - assert(u); - - if (!u->service) - return 0; - - return 0; -} - -static int user_shall_kill(User *u) { - assert(u); - - if (!u->manager->kill_user_processes) - return false; - - if (strv_contains(u->manager->kill_exclude_users, u->name)) - return false; - - if (strv_isempty(u->manager->kill_only_users)) - return true; - - return strv_contains(u->manager->kill_only_users, u->name); -} - -static int user_terminate_cgroup(User *u) { - int r; - char **k; - - assert(u); - - if (!u->cgroup_path) - return 0; - - cg_trim(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false); - - if (user_shall_kill(u)) { - - r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); - if (r < 0) - log_error("Failed to kill user cgroup: %s", strerror(-r)); - } else { - - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); - if (r < 0) - log_error("Failed to check user cgroup: %s", strerror(-r)); - else if (r > 0) { - r = cg_delete(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path); - if (r < 0) - log_error("Failed to delete user cgroup: %s", strerror(-r)); - } else - r = -EBUSY; - } - - STRV_FOREACH(k, u->manager->controllers) - cg_trim(*k, u->cgroup_path, true); - - free(u->cgroup_path); - u->cgroup_path = NULL; - - return r; -} - -static int user_remove_runtime_path(User *u) { - int r; - - assert(u); - - if (!u->runtime_path) - return 0; - - r = rm_rf(u->runtime_path, false, true, false); - if (r < 0) - log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r)); - - free(u->runtime_path); - u->runtime_path = NULL; - - return r; -} - -int user_stop(User *u) { - Session *s; - int r = 0, k; - assert(u); - - if (u->started) - log_info("User %s logged out.", u->name); - - LIST_FOREACH(sessions_by_user, s, u->sessions) { - k = session_stop(s); - if (k < 0) - r = k; - } - - /* Kill systemd */ - k = user_stop_service(u); - if (k < 0) - r = k; - - /* Kill cgroup */ - k = user_terminate_cgroup(u); - if (k < 0) - r = k; - - /* Kill XDG_RUNTIME_DIR */ - k = user_remove_runtime_path(u); - if (k < 0) - r = k; - - unlink(u->state_file); - user_add_to_gc_queue(u); - - if (u->started) - user_send_signal(u, false); - - u->started = false; - - return r; -} - -int user_get_idle_hint(User *u, dual_timestamp *t) { - Session *s; - bool idle_hint = true; - dual_timestamp ts = { 0, 0 }; - - assert(u); - - LIST_FOREACH(sessions_by_user, s, u->sessions) { - dual_timestamp k; - int ih; - - ih = session_get_idle_hint(s, &k); - if (ih < 0) - return ih; - - if (!ih) { - if (!idle_hint) { - if (k.monotonic < ts.monotonic) - ts = k; - } else { - idle_hint = false; - ts = k; - } - } else if (idle_hint) { - - if (k.monotonic > ts.monotonic) - ts = k; - } - } - - if (t) - *t = ts; - - return idle_hint; -} - -int user_check_gc(User *u, bool drop_not_started) { - int r; - char *p; - - assert(u); - - if (drop_not_started && !u->started) - return 0; - - if (u->sessions) - return 1; - - if (asprintf(&p, "/var/lib/systemd/linger/%s", u->name) < 0) - return -ENOMEM; - - r = access(p, F_OK) >= 0; - free(p); - - if (r > 0) - return 1; - - if (u->cgroup_path) { - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, false); - if (r < 0) - return r; - - if (r <= 0) - return 1; - } - - return 0; -} - -void user_add_to_gc_queue(User *u) { - assert(u); - - if (u->in_gc_queue) - return; - - LIST_PREPEND(User, gc_queue, u->manager->user_gc_queue, u); - u->in_gc_queue = true; -} - -UserState user_get_state(User *u) { - Session *i; - - assert(u); - - if (!u->sessions) - return USER_LINGERING; - - LIST_FOREACH(sessions_by_user, i, u->sessions) - if (session_is_active(i)) - return USER_ACTIVE; - - return USER_ONLINE; -} - -int user_kill(User *u, int signo) { - int r = 0, q; - Set *pid_set = NULL; - - assert(u); - - if (!u->cgroup_path) - return -ESRCH; - - pid_set = set_new(trivial_hash_func, trivial_compare_func); - if (!pid_set) - return -ENOMEM; - - q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set); - if (q < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const user_state_table[_USER_STATE_MAX] = { - [USER_OFFLINE] = "offline", - [USER_LINGERING] = "lingering", - [USER_ONLINE] = "online", - [USER_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(user_state, UserState); diff --git a/src/logind-user.h b/src/logind-user.h deleted file mode 100644 index db9a5f6..0000000 --- a/src/logind-user.h +++ /dev/null @@ -1,86 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologinduserhfoo -#define foologinduserhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct User User; - -#include "list.h" -#include "util.h" -#include "logind.h" -#include "logind-session.h" - -typedef enum UserState { - USER_OFFLINE, - USER_LINGERING, - USER_ONLINE, - USER_ACTIVE, - _USER_STATE_MAX, - _USER_STATE_INVALID = -1 -} UserState; - -struct User { - Manager *manager; - - uid_t uid; - gid_t gid; - char *name; - - char *state_file; - char *runtime_path; - char *service; - char *cgroup_path; - - Session *display; - - dual_timestamp timestamp; - - bool in_gc_queue:1; - bool started:1; - - LIST_HEAD(Session, sessions); - LIST_FIELDS(User, gc_queue); -}; - -User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name); -void user_free(User *u); -int user_check_gc(User *u, bool drop_not_started); -void user_add_to_gc_queue(User *u); -int user_start(User *u); -int user_stop(User *u); -UserState user_get_state(User *u); -int user_get_idle_hint(User *u, dual_timestamp *t); -int user_save(User *u); -int user_load(User *u); -int user_kill(User *u, int signo); - -char *user_bus_path(User *s); - -extern const DBusObjectPathVTable bus_user_vtable; - -int user_send_signal(User *u, bool new_user); -int user_send_changed(User *u, const char *properties); - -const char* user_state_to_string(UserState s); -UserState user_state_from_string(const char *s); - -#endif diff --git a/src/logind.c b/src/logind.c deleted file mode 100644 index 4633a5e..0000000 --- a/src/logind.c +++ /dev/null @@ -1,1228 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "logind.h" -#include "dbus-common.h" -#include "dbus-loop.h" -#include "strv.h" -#include "conf-parser.h" - -Manager *manager_new(void) { - Manager *m; - - m = new0(Manager, 1); - if (!m) - return NULL; - - m->console_active_fd = -1; - m->bus_fd = -1; - m->udev_seat_fd = -1; - m->udev_vcsa_fd = -1; - m->epoll_fd = -1; - m->n_autovts = 6; - - m->devices = hashmap_new(string_hash_func, string_compare_func); - m->seats = hashmap_new(string_hash_func, string_compare_func); - m->sessions = hashmap_new(string_hash_func, string_compare_func); - m->users = hashmap_new(trivial_hash_func, trivial_compare_func); - m->cgroups = hashmap_new(string_hash_func, string_compare_func); - m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func); - - if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) { - manager_free(m); - return NULL; - } - - m->reset_controllers = strv_new("cpu", NULL); - m->kill_exclude_users = strv_new("root", NULL); - if (!m->reset_controllers || !m->kill_exclude_users) { - manager_free(m); - return NULL; - } - - m->udev = udev_new(); - if (!m->udev) { - manager_free(m); - return NULL; - } - - if (cg_get_user_path(&m->cgroup_path) < 0) { - manager_free(m); - return NULL; - } - - return m; -} - -void manager_free(Manager *m) { - Session *session; - User *u; - Device *d; - Seat *s; - - assert(m); - - while ((session = hashmap_first(m->sessions))) - session_free(session); - - while ((u = hashmap_first(m->users))) - user_free(u); - - while ((d = hashmap_first(m->devices))) - device_free(d); - - while ((s = hashmap_first(m->seats))) - seat_free(s); - - hashmap_free(m->sessions); - hashmap_free(m->users); - hashmap_free(m->devices); - hashmap_free(m->seats); - hashmap_free(m->cgroups); - hashmap_free(m->fifo_fds); - - if (m->console_active_fd >= 0) - close_nointr_nofail(m->console_active_fd); - - if (m->udev_seat_monitor) - udev_monitor_unref(m->udev_seat_monitor); - - if (m->udev_vcsa_monitor) - udev_monitor_unref(m->udev_vcsa_monitor); - - if (m->udev) - udev_unref(m->udev); - - if (m->bus) { - dbus_connection_flush(m->bus); - dbus_connection_close(m->bus); - dbus_connection_unref(m->bus); - } - - if (m->bus_fd >= 0) - close_nointr_nofail(m->bus_fd); - - if (m->epoll_fd >= 0) - close_nointr_nofail(m->epoll_fd); - - strv_free(m->controllers); - strv_free(m->reset_controllers); - strv_free(m->kill_only_users); - strv_free(m->kill_exclude_users); - - free(m->cgroup_path); - free(m); -} - -int manager_add_device(Manager *m, const char *sysfs, Device **_device) { - Device *d; - - assert(m); - assert(sysfs); - - d = hashmap_get(m->devices, sysfs); - if (d) { - if (_device) - *_device = d; - - return 0; - } - - d = device_new(m, sysfs); - if (!d) - return -ENOMEM; - - if (_device) - *_device = d; - - return 0; -} - -int manager_add_seat(Manager *m, const char *id, Seat **_seat) { - Seat *s; - - assert(m); - assert(id); - - s = hashmap_get(m->seats, id); - if (s) { - if (_seat) - *_seat = s; - - return 0; - } - - s = seat_new(m, id); - if (!s) - return -ENOMEM; - - if (_seat) - *_seat = s; - - return 0; -} - -int manager_add_session(Manager *m, User *u, const char *id, Session **_session) { - Session *s; - - assert(m); - assert(id); - - s = hashmap_get(m->sessions, id); - if (s) { - if (_session) - *_session = s; - - return 0; - } - - s = session_new(m, u, id); - if (!s) - return -ENOMEM; - - if (_session) - *_session = s; - - return 0; -} - -int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) { - User *u; - - assert(m); - assert(name); - - u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid)); - if (u) { - if (_user) - *_user = u; - - return 0; - } - - u = user_new(m, uid, gid, name); - if (!u) - return -ENOMEM; - - if (_user) - *_user = u; - - return 0; -} - -int manager_add_user_by_name(Manager *m, const char *name, User **_user) { - uid_t uid; - gid_t gid; - int r; - - assert(m); - assert(name); - - r = get_user_creds(&name, &uid, &gid, NULL); - if (r < 0) - return r; - - return manager_add_user(m, uid, gid, name, _user); -} - -int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { - struct passwd *p; - - assert(m); - - errno = 0; - p = getpwuid(uid); - if (!p) - return errno ? -errno : -ENOENT; - - return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user); -} - -int manager_process_seat_device(Manager *m, struct udev_device *d) { - Device *device; - int r; - - assert(m); - - if (streq_ptr(udev_device_get_action(d), "remove")) { - - device = hashmap_get(m->devices, udev_device_get_syspath(d)); - if (!device) - return 0; - - seat_add_to_gc_queue(device->seat); - device_free(device); - - } else { - const char *sn; - Seat *seat; - - sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(sn)) - sn = "seat0"; - - if (!seat_name_is_valid(sn)) { - log_warning("Device with invalid seat name %s found, ignoring.", sn); - return 0; - } - - r = manager_add_device(m, udev_device_get_syspath(d), &device); - if (r < 0) - return r; - - r = manager_add_seat(m, sn, &seat); - if (r < 0) { - if (!device->seat) - device_free(device); - - return r; - } - - device_attach(device, seat); - seat_start(seat); - } - - return 0; -} - -int manager_enumerate_devices(Manager *m) { - struct udev_list_entry *item = NULL, *first = NULL; - struct udev_enumerate *e; - int r; - - assert(m); - - /* Loads devices from udev and creates seats for them as - * necessary */ - - e = udev_enumerate_new(m->udev); - if (!e) { - r = -ENOMEM; - goto finish; - } - - r = udev_enumerate_add_match_subsystem(e, "graphics"); - if (r < 0) - goto finish; - - r = udev_enumerate_add_match_tag(e, "seat"); - if (r < 0) - goto finish; - - r = udev_enumerate_scan_devices(e); - if (r < 0) - goto finish; - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - struct udev_device *d; - int k; - - d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); - if (!d) { - r = -ENOMEM; - goto finish; - } - - k = manager_process_seat_device(m, d); - udev_device_unref(d); - - if (k < 0) - r = k; - } - -finish: - if (e) - udev_enumerate_unref(e); - - return r; -} - -int manager_enumerate_seats(Manager *m) { - DIR *d; - struct dirent *de; - int r = 0; - - assert(m); - - /* This loads data about seats stored on disk, but does not - * actually create any seats. Removes data of seats that no - * longer exist. */ - - d = opendir("/run/systemd/seats"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /run/systemd/seats: %m"); - return -errno; - } - - while ((de = readdir(d))) { - Seat *s; - int k; - - if (!dirent_is_file(de)) - continue; - - s = hashmap_get(m->seats, de->d_name); - if (!s) { - unlinkat(dirfd(d), de->d_name, 0); - continue; - } - - k = seat_load(s); - if (k < 0) - r = k; - } - - closedir(d); - - return r; -} - -static int manager_enumerate_users_from_cgroup(Manager *m) { - int r = 0; - char *name; - DIR *d; - int k; - - r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d); - if (r < 0) { - if (r == -ENOENT) - return 0; - - log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r)); - return r; - } - - while ((k = cg_read_subgroup(d, &name)) > 0) { - User *user; - - k = manager_add_user_by_name(m, name, &user); - if (k < 0) { - free(name); - r = k; - continue; - } - - user_add_to_gc_queue(user); - - if (!user->cgroup_path) - if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) { - r = -ENOMEM; - free(name); - break; - } - - free(name); - } - - if (r >= 0 && k < 0) - r = k; - - closedir(d); - - return r; -} - -static int manager_enumerate_linger_users(Manager *m) { - DIR *d; - struct dirent *de; - int r = 0; - - d = opendir("/var/lib/systemd/linger"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /var/lib/systemd/linger/: %m"); - return -errno; - } - - while ((de = readdir(d))) { - int k; - - if (!dirent_is_file(de)) - continue; - - k = manager_add_user_by_name(m, de->d_name, NULL); - if (k < 0) { - log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k)); - r = k; - } - } - - closedir(d); - - return r; -} - -int manager_enumerate_users(Manager *m) { - DIR *d; - struct dirent *de; - int r, k; - - assert(m); - - /* First, enumerate user cgroups */ - r = manager_enumerate_users_from_cgroup(m); - - /* Second, add lingering users on top */ - k = manager_enumerate_linger_users(m); - if (k < 0) - r = k; - - /* Third, read in user data stored on disk */ - d = opendir("/run/systemd/users"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /run/systemd/users: %m"); - return -errno; - } - - while ((de = readdir(d))) { - uid_t uid; - User *u; - - if (!dirent_is_file(de)) - continue; - - k = parse_uid(de->d_name, &uid); - if (k < 0) { - log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k)); - continue; - } - - u = hashmap_get(m->users, ULONG_TO_PTR(uid)); - if (!u) { - unlinkat(dirfd(d), de->d_name, 0); - continue; - } - - k = user_load(u); - if (k < 0) - r = k; - } - - closedir(d); - - return r; -} - -static int manager_enumerate_sessions_from_cgroup(Manager *m) { - User *u; - Iterator i; - int r = 0; - - HASHMAP_FOREACH(u, m->users, i) { - DIR *d; - char *name; - int k; - - if (!u->cgroup_path) - continue; - - k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d); - if (k < 0) { - if (k == -ENOENT) - continue; - - log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k)); - r = k; - continue; - } - - while ((k = cg_read_subgroup(d, &name)) > 0) { - Session *session; - - if (streq(name, "shared")) - continue; - - k = manager_add_session(m, u, name, &session); - if (k < 0) { - free(name); - break; - } - - session_add_to_gc_queue(session); - - if (!session->cgroup_path) - if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) { - k = -ENOMEM; - free(name); - break; - } - - free(name); - } - - closedir(d); - - if (k < 0) - r = k; - } - - return r; -} - -int manager_enumerate_sessions(Manager *m) { - DIR *d; - struct dirent *de; - int r = 0; - - assert(m); - - /* First enumerate session cgroups */ - r = manager_enumerate_sessions_from_cgroup(m); - - /* Second, read in session data stored on disk */ - d = opendir("/run/systemd/sessions"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /run/systemd/sessions: %m"); - return -errno; - } - - while ((de = readdir(d))) { - struct Session *s; - int k; - - if (!dirent_is_file(de)) - continue; - - s = hashmap_get(m->sessions, de->d_name); - if (!s) { - unlinkat(dirfd(d), de->d_name, 0); - continue; - } - - k = session_load(s); - if (k < 0) - r = k; - } - - closedir(d); - - return r; -} - -int manager_dispatch_seat_udev(Manager *m) { - struct udev_device *d; - int r; - - assert(m); - - d = udev_monitor_receive_device(m->udev_seat_monitor); - if (!d) - return -ENOMEM; - - r = manager_process_seat_device(m, d); - udev_device_unref(d); - - return r; -} - - -int manager_dispatch_vcsa_udev(Manager *m) { - struct udev_device *d; - int r = 0; - const char *name; - - assert(m); - - d = udev_monitor_receive_device(m->udev_vcsa_monitor); - if (!d) - return -ENOMEM; - - name = udev_device_get_sysname(d); - - /* Whenever a VCSA device is removed try to reallocate our - * VTs, to make sure our auto VTs never go away. */ - - if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove")) - r = seat_preallocate_vts(m->vtconsole); - - udev_device_unref(d); - - return r; -} - -int manager_dispatch_console(Manager *m) { - assert(m); - - if (m->vtconsole) - seat_read_active_vt(m->vtconsole); - - return 0; -} - -static int vt_is_busy(int vtnr) { - struct vt_stat vt_stat; - int r = 0, fd; - - assert(vtnr >= 1); - - /* We explicitly open /dev/tty1 here instead of /dev/tty0. If - * we'd open the latter we'd open the foreground tty which - * hence would be unconditionally busy. By opening /dev/tty1 - * we avoid this. Since tty1 is special and needs to be an - * explicitly loaded getty or DM this is safe. */ - - fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return -errno; - - if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0) - r = -errno; - else - r = !!(vt_stat.v_state & (1 << vtnr)); - - close_nointr_nofail(fd); - - return r; -} - -int manager_spawn_autovt(Manager *m, int vtnr) { - int r; - DBusMessage *message = NULL, *reply = NULL; - char *name = NULL; - const char *mode = "fail"; - DBusError error; - - assert(m); - assert(vtnr >= 1); - - dbus_error_init(&error); - - if ((unsigned) vtnr > m->n_autovts) - return 0; - - r = vt_is_busy(vtnr); - if (r < 0) - return r; - else if (r > 0) - return -EBUSY; - - message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"); - if (!message) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) { - log_error("Could not allocate service name."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(message, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not attach target and flag information to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error); - if (!reply) { - log_error("Failed to start unit: %s", bus_error_message(&error)); - goto finish; - } - - r = 0; - -finish: - free(name); - - if (message) - dbus_message_unref(message); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -void manager_cgroup_notify_empty(Manager *m, const char *cgroup) { - Session *s; - char *p; - - assert(m); - assert(cgroup); - - p = strdup(cgroup); - if (!p) { - log_error("Out of memory."); - return; - } - - for (;;) { - char *e; - - if (isempty(p) || streq(p, "/")) - break; - - s = hashmap_get(m->cgroups, p); - if (s) - session_add_to_gc_queue(s); - - assert_se(e = strrchr(p, '/')); - *e = 0; - } - - free(p); -} - -static void manager_pipe_notify_eof(Manager *m, int fd) { - Session *s; - - assert_se(m); - assert_se(fd >= 0); - - assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1))); - assert(s->fifo_fd == fd); - session_remove_fifo(s); - - session_stop(s); -} - -static int manager_connect_bus(Manager *m) { - DBusError error; - int r; - struct epoll_event ev; - - assert(m); - assert(!m->bus); - assert(m->bus_fd < 0); - - dbus_error_init(&error); - - m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!m->bus) { - log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); - r = -ECONNREFUSED; - goto fail; - } - - if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) || - !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) || - !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) || - !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) || - !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - dbus_bus_add_match(m->bus, - "type='signal'," - "interface='org.freedesktop.systemd1.Agent'," - "member='Released'," - "path='/org/freedesktop/systemd1/agent'", - &error); - - if (dbus_error_is_set(&error)) { - log_error("Failed to register match: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - - r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); - if (dbus_error_is_set(&error)) { - log_error("Failed to register name on bus: %s", bus_error_message(&error)); - r = -EIO; - goto fail; - } - - if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - log_error("Failed to acquire name."); - r = -EEXIST; - goto fail; - } - - m->bus_fd = bus_loop_open(m->bus); - if (m->bus_fd < 0) { - r = m->bus_fd; - goto fail; - } - - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_BUS; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0) - goto fail; - - return 0; - -fail: - dbus_error_free(&error); - - return r; -} - -static int manager_connect_console(Manager *m) { - struct epoll_event ev; - - assert(m); - assert(m->console_active_fd < 0); - - m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (m->console_active_fd < 0) { - log_error("Failed to open /sys/class/tty/tty0/active: %m"); - return -errno; - } - - zero(ev); - ev.events = 0; - ev.data.u32 = FD_CONSOLE; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0) - return -errno; - - return 0; -} - -static int manager_connect_udev(Manager *m) { - struct epoll_event ev; - int r; - - assert(m); - assert(!m->udev_seat_monitor); - assert(!m->udev_vcsa_monitor); - - m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_seat_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat"); - if (r < 0) - return r; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL); - if (r < 0) - return r; - - r = udev_monitor_enable_receiving(m->udev_seat_monitor); - if (r < 0) - return r; - - m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor); - - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_SEAT_UDEV; - - if (m->n_autovts <= 0) - return 0; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0) - return -errno; - - m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_vcsa_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL); - if (r < 0) - return r; - - r = udev_monitor_enable_receiving(m->udev_vcsa_monitor); - if (r < 0) - return r; - - m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor); - - zero(ev); - ev.events = EPOLLIN; - ev.data.u32 = FD_VCSA_UDEV; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0) - return -errno; - - return 0; -} - -void manager_gc(Manager *m, bool drop_not_started) { - Seat *seat; - Session *session; - User *user; - - assert(m); - - while ((seat = m->seat_gc_queue)) { - LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat); - seat->in_gc_queue = false; - - if (seat_check_gc(seat, drop_not_started) == 0) { - seat_stop(seat); - seat_free(seat); - } - } - - while ((session = m->session_gc_queue)) { - LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session); - session->in_gc_queue = false; - - if (session_check_gc(session, drop_not_started) == 0) { - session_stop(session); - session_free(session); - } - } - - while ((user = m->user_gc_queue)) { - LIST_REMOVE(User, gc_queue, m->user_gc_queue, user); - user->in_gc_queue = false; - - if (user_check_gc(user, drop_not_started) == 0) { - user_stop(user); - user_free(user); - } - } -} - -int manager_get_idle_hint(Manager *m, dual_timestamp *t) { - Session *s; - bool idle_hint = true; - dual_timestamp ts = { 0, 0 }; - Iterator i; - - assert(m); - - HASHMAP_FOREACH(s, m->sessions, i) { - dual_timestamp k; - int ih; - - ih = session_get_idle_hint(s, &k); - if (ih < 0) - return ih; - - if (!ih) { - if (!idle_hint) { - if (k.monotonic < ts.monotonic) - ts = k; - } else { - idle_hint = false; - ts = k; - } - } else if (idle_hint) { - - if (k.monotonic > ts.monotonic) - ts = k; - } - } - - if (t) - *t = ts; - - return idle_hint; -} - -int manager_startup(Manager *m) { - int r; - Seat *seat; - Session *session; - User *user; - Iterator i; - - assert(m); - assert(m->epoll_fd <= 0); - - m->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (m->epoll_fd < 0) - return -errno; - - /* Connect to udev */ - r = manager_connect_udev(m); - if (r < 0) - return r; - - /* Connect to console */ - r = manager_connect_console(m); - if (r < 0) - return r; - - /* Connect to the bus */ - r = manager_connect_bus(m); - if (r < 0) - return r; - - /* Instantiate magic seat 0 */ - r = manager_add_seat(m, "seat0", &m->vtconsole); - if (r < 0) - return r; - - /* Deserialize state */ - manager_enumerate_devices(m); - manager_enumerate_seats(m); - manager_enumerate_users(m); - manager_enumerate_sessions(m); - - /* Remove stale objects before we start them */ - manager_gc(m, false); - - /* And start everything */ - HASHMAP_FOREACH(seat, m->seats, i) - seat_start(seat); - - HASHMAP_FOREACH(user, m->users, i) - user_start(user); - - HASHMAP_FOREACH(session, m->sessions, i) - session_start(session); - - return 0; -} - -int manager_run(Manager *m) { - assert(m); - - for (;;) { - struct epoll_event event; - int n; - - manager_gc(m, true); - - if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE) - continue; - - manager_gc(m, true); - - n = epoll_wait(m->epoll_fd, &event, 1, -1); - if (n < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - - log_error("epoll() failed: %m"); - return -errno; - } - - switch (event.data.u32) { - - case FD_SEAT_UDEV: - manager_dispatch_seat_udev(m); - break; - - case FD_VCSA_UDEV: - manager_dispatch_vcsa_udev(m); - break; - - case FD_CONSOLE: - manager_dispatch_console(m); - break; - - case FD_BUS: - bus_loop_dispatch(m->bus_fd); - break; - - default: - if (event.data.u32 >= FD_FIFO_BASE) - manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE); - } - } - - return 0; -} - -static int manager_parse_config_file(Manager *m) { - FILE *f; - const char *fn; - int r; - - assert(m); - - fn = "/etc/systemd/systemd-logind.conf"; - f = fopen(fn, "re"); - if (!f) { - if (errno == ENOENT) - return 0; - - log_warning("Failed to open configuration file %s: %m", fn); - return -errno; - } - - r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m); - if (r < 0) - log_warning("Failed to parse configuration file: %s", strerror(-r)); - - fclose(f); - - return r; -} - -int main(int argc, char *argv[]) { - Manager *m = NULL; - int r; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc != 1) { - log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; - } - - m = manager_new(); - if (!m) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - manager_parse_config_file(m); - - r = manager_startup(m); - if (r < 0) { - log_error("Failed to fully start up daemon: %s", strerror(-r)); - goto finish; - } - - r = manager_run(m); - -finish: - if (m) - manager_free(m); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/logind.h b/src/logind.h deleted file mode 100644 index fd668a2..0000000 --- a/src/logind.h +++ /dev/null @@ -1,128 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foologindhfoo -#define foologindhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "list.h" -#include "hashmap.h" -#include "cgroup-util.h" - -typedef struct Manager Manager; - -#include "logind-device.h" -#include "logind-seat.h" -#include "logind-session.h" -#include "logind-user.h" - -struct Manager { - DBusConnection *bus; - - Hashmap *devices; - Hashmap *seats; - Hashmap *sessions; - Hashmap *users; - - LIST_HEAD(Seat, seat_gc_queue); - LIST_HEAD(Session, session_gc_queue); - LIST_HEAD(User, user_gc_queue); - - struct udev *udev; - struct udev_monitor *udev_seat_monitor, *udev_vcsa_monitor; - - int udev_seat_fd; - int udev_vcsa_fd; - - int console_active_fd; - int bus_fd; - int epoll_fd; - - unsigned n_autovts; - - Seat *vtconsole; - - char *cgroup_path; - char **controllers, **reset_controllers; - - char **kill_only_users, **kill_exclude_users; - - bool kill_user_processes; - - unsigned long session_counter; - - Hashmap *cgroups; - Hashmap *fifo_fds; -}; - -enum { - FD_SEAT_UDEV, - FD_VCSA_UDEV, - FD_CONSOLE, - FD_BUS, - FD_FIFO_BASE -}; - -Manager *manager_new(void); -void manager_free(Manager *m); - -int manager_add_device(Manager *m, const char *sysfs, Device **_device); -int manager_add_seat(Manager *m, const char *id, Seat **_seat); -int manager_add_session(Manager *m, User *u, const char *id, Session **_session); -int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user); -int manager_add_user_by_name(Manager *m, const char *name, User **_user); -int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user); - -int manager_process_seat_device(Manager *m, struct udev_device *d); -int manager_dispatch_seat_udev(Manager *m); -int manager_dispatch_vcsa_udev(Manager *m); -int manager_dispatch_console(Manager *m); - -int manager_enumerate_devices(Manager *m); -int manager_enumerate_seats(Manager *m); -int manager_enumerate_sessions(Manager *m); -int manager_enumerate_users(Manager *m); - -int manager_startup(Manager *m); -int manager_run(Manager *m); -int manager_spawn_autovt(Manager *m, int vtnr); - -void manager_cgroup_notify_empty(Manager *m, const char *cgroup); - -void manager_gc(Manager *m, bool drop_not_started); - -int manager_get_idle_hint(Manager *m, dual_timestamp *t); - -extern const DBusObjectPathVTable bus_manager_vtable; - -DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, void *userdata); - -int manager_send_changed(Manager *manager, const char *properties); - -/* gperf lookup function */ -const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length); - -#endif diff --git a/src/loopback-setup.c b/src/loopback-setup.c deleted file mode 100644 index b6359de..0000000 --- a/src/loopback-setup.c +++ /dev/null @@ -1,274 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "macro.h" -#include "loopback-setup.h" -#include "socket-util.h" - -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - -static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) { - size_t length; - struct rtattr *rta; - - length = RTA_LENGTH(data_length); - - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length) - return -E2BIG; - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = length; - memcpy(RTA_DATA(rta), data, data_length); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length); - - return 0; -} - -static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) { - - for (;;) { - ssize_t l; - - if ((l = sendto(fd, buf, buf_len, flags, sa, sa_len)) >= 0) - return l; - - if (errno != EINTR) - return -errno; - } -} - -static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) { - - for (;;) { - ssize_t l; - - if ((l = recvfrom(fd, buf, buf_len, flags, sa, sa_len)) >= 0) - return l; - - if (errno != EINTR) - return -errno; - } -} - -static int add_adresses(int fd, int if_loopback, unsigned *requests) { - union { - struct sockaddr sa; - struct sockaddr_nl nl; - } sa; - union { - struct nlmsghdr header; - uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + - NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + - RTA_LENGTH(sizeof(struct in6_addr))]; - } request; - - struct ifaddrmsg *ifaddrmsg; - uint32_t ipv4_address = htonl(INADDR_LOOPBACK); - int r; - - zero(request); - - request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - request.header.nlmsg_type = RTM_NEWADDR; - request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK; - request.header.nlmsg_seq = *requests + 1; - - ifaddrmsg = NLMSG_DATA(&request.header); - ifaddrmsg->ifa_family = AF_INET; - ifaddrmsg->ifa_prefixlen = 8; - ifaddrmsg->ifa_flags = IFA_F_PERMANENT; - ifaddrmsg->ifa_scope = RT_SCOPE_HOST; - ifaddrmsg->ifa_index = if_loopback; - - if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address))) < 0) - return r; - - zero(sa); - sa.nl.nl_family = AF_NETLINK; - - if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0) - return -errno; - (*requests)++; - - if (!socket_ipv6_is_supported()) - return 0; - - request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - request.header.nlmsg_seq = *requests + 1; - - ifaddrmsg->ifa_family = AF_INET6; - ifaddrmsg->ifa_prefixlen = 128; - - if ((r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback))) < 0) - return r; - - if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0) - return -errno; - (*requests)++; - - return 0; -} - -static int start_interface(int fd, int if_loopback, unsigned *requests) { - union { - struct sockaddr sa; - struct sockaddr_nl nl; - } sa; - union { - struct nlmsghdr header; - uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + - NLMSG_ALIGN(sizeof(struct ifinfomsg))]; - } request; - - struct ifinfomsg *ifinfomsg; - - zero(request); - - request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - request.header.nlmsg_type = RTM_NEWLINK; - request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - request.header.nlmsg_seq = *requests + 1; - - ifinfomsg = NLMSG_DATA(&request.header); - ifinfomsg->ifi_family = AF_UNSPEC; - ifinfomsg->ifi_index = if_loopback; - ifinfomsg->ifi_flags = IFF_UP; - ifinfomsg->ifi_change = IFF_UP; - - zero(sa); - sa.nl.nl_family = AF_NETLINK; - - if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0) - return -errno; - - (*requests)++; - - return 0; -} - -static int read_response(int fd, unsigned requests_max) { - union { - struct sockaddr sa; - struct sockaddr_nl nl; - } sa; - union { - struct nlmsghdr header; - uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + - NLMSG_ALIGN(sizeof(struct nlmsgerr))]; - } response; - - ssize_t l; - socklen_t sa_len = sizeof(sa); - struct nlmsgerr *nlmsgerr; - - if ((l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len)) < 0) - return -errno; - - if (sa_len != sizeof(sa.nl) || - sa.nl.nl_family != AF_NETLINK) - return -EIO; - - if (sa.nl.nl_pid != 0) - return 0; - - if ((size_t) l < sizeof(struct nlmsghdr)) - return -EIO; - - if (response.header.nlmsg_type != NLMSG_ERROR || - (pid_t) response.header.nlmsg_pid != getpid() || - response.header.nlmsg_seq >= requests_max) - return 0; - - if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) || - response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) - return -EIO; - - nlmsgerr = NLMSG_DATA(&response.header); - - if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST) { - log_warning("Netlink failure for request %i: %s", response.header.nlmsg_seq, strerror(-nlmsgerr->error)); - return nlmsgerr->error; - } - - return response.header.nlmsg_seq; -} - -int loopback_setup(void) { - int r, if_loopback; - union { - struct sockaddr sa; - struct sockaddr_nl nl; - struct sockaddr_storage storage; - } sa; - unsigned requests = 0, i; - int fd; - - errno = 0; - if ((if_loopback = (int) if_nametoindex("lo")) <= 0) - return errno ? -errno : -ENODEV; - - if ((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) - return -errno; - - zero(sa); - sa.nl.nl_family = AF_NETLINK; - - if (bind(fd, &sa.sa, sizeof(sa)) < 0) { - r = -errno; - goto finish; - } - - if ((r = add_adresses(fd, if_loopback, &requests)) < 0) - goto finish; - - if ((r = start_interface(fd, if_loopback, &requests)) < 0) - goto finish; - - for (i = 0; i < requests; i++) { - if ((r = read_response(fd, requests)) < 0) - goto finish; - } - - r = 0; - -finish: - if (r < 0) - log_warning("Failed to configure loopback device: %s", strerror(-r)); - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} diff --git a/src/loopback-setup.h b/src/loopback-setup.h deleted file mode 100644 index 81f4529..0000000 --- a/src/loopback-setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooloopbacksetuphfoo -#define fooloopbacksetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int loopback_setup(void); - -#endif diff --git a/src/machine-id-main.c b/src/machine-id-main.c deleted file mode 100644 index 03970a2..0000000 --- a/src/machine-id-main.c +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "machine-id-setup.h" -#include "log.h" - -int main(int argc, char *argv[]) { - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - return machine_id_setup() < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/machine-id-setup.c b/src/machine-id-setup.c deleted file mode 100644 index 519521f..0000000 --- a/src/machine-id-setup.c +++ /dev/null @@ -1,196 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "machine-id-setup.h" -#include "macro.h" -#include "util.h" -#include "log.h" - -static void make_v4_uuid(unsigned char *id) { - /* Stolen from generate_random_uuid() of drivers/char/random.c - * in the kernel sources */ - - /* Set UUID version to 4 --- truly random generation */ - id[6] = (id[6] & 0x0F) | 0x40; - - /* Set the UUID variant to DCE */ - id[8] = (id[8] & 0x3F) | 0x80; -} - -static int generate(char id[34]) { - int fd; - unsigned char buf[16], *p; - char *q; - ssize_t k; - - assert(id); - - /* First, try reading the D-Bus machine id, unless it is a symlink */ - fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd >= 0) { - - k = loop_read(fd, id, 33, false); - close_nointr_nofail(fd); - - if (k >= 32) { - id[32] = '\n'; - id[33] = 0; - - log_info("Initializing machine ID from D-Bus machine ID."); - return 0; - } - } - - /* If that didn't work, generate a random machine id */ - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - log_error("Failed to open /dev/urandom: %m"); - return -errno; - } - - k = loop_read(fd, buf, sizeof(buf), false); - close_nointr_nofail(fd); - - if (k != sizeof(buf)) { - log_error("Failed to read /dev/urandom: %s", strerror(k < 0 ? -k : EIO)); - return k < 0 ? (int) k : -EIO; - } - - /* Turn this into a valid v4 UUID, to be nice. Note that we - * only guarantee this for newly generated UUIDs, not for - * pre-existing ones.*/ - make_v4_uuid(buf); - - for (p = buf, q = id; p < buf + sizeof(buf); p++, q += 2) { - q[0] = hexchar(*p >> 4); - q[1] = hexchar(*p & 15); - } - - id[32] = '\n'; - id[33] = 0; - - log_info("Initializing machine ID from random generator."); - - return 0; -} - -int machine_id_setup(void) { - int fd, r; - bool writable; - struct stat st; - char id[34]; /* 32 + \n + \0 */ - mode_t m; - - m = umask(0000); - - /* We create this 0444, to indicate that this isn't really - * something you should ever modify. Of course, since the file - * will be owned by root it doesn't matter much, but maybe - * people look. */ - - fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); - if (fd >= 0) - writable = true; - else { - fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - umask(m); - log_error("Cannot open /etc/machine-id: %m"); - return -errno; - } - - writable = false; - } - - umask(m); - - if (fstat(fd, &st) < 0) { - log_error("fstat() failed: %m"); - r = -errno; - goto finish; - } - - if (S_ISREG(st.st_mode)) { - if (loop_read(fd, id, 32, false) >= 32) { - r = 0; - goto finish; - } - } - - /* Hmm, so, the id currently stored is not useful, then let's - * generate one */ - - r = generate(id); - if (r < 0) - goto finish; - - if (S_ISREG(st.st_mode) && writable) { - lseek(fd, 0, SEEK_SET); - - if (loop_write(fd, id, 33, false) == 33) { - r = 0; - goto finish; - } - } - - close_nointr_nofail(fd); - fd = -1; - - /* Hmm, we couldn't write it? So let's write it to - * /run/systemd/machine-id as a replacement */ - - mkdir_p("/run/systemd", 0755); - - m = umask(0022); - r = write_one_line_file("/run/systemd/machine-id", id); - umask(m); - - if (r < 0) { - log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r)); - - unlink("/run/systemd/machine-id"); - goto finish; - } - - /* And now, let's mount it over */ - r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0; - unlink("/run/systemd/machine-id"); - - if (r < 0) - log_error("Failed to mount /etc/machine-id: %s", strerror(-r)); - else - log_info("Installed transient /etc/machine-id file."); - -finish: - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} diff --git a/src/machine-id-setup.h b/src/machine-id-setup.h deleted file mode 100644 index 4d0a9cf..0000000 --- a/src/machine-id-setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomachineidsetuphfoo -#define foomachineidsetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int machine_id_setup(void); - -#endif diff --git a/src/machine-id-setup/Makefile b/src/machine-id-setup/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/machine-id-setup/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c new file mode 100644 index 0000000..84af925 --- /dev/null +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -0,0 +1,99 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "machine-id-setup.h" +#include "log.h" +#include "build.h" + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Initialize /etc/machine-id from a random source.\n\n" + " -h --help Show this help\n" + " --version Show package version\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100 + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind < argc) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + return machine_id_setup() < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/machine/Makefile b/src/machine/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/machine/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c new file mode 100644 index 0000000..df96ccf --- /dev/null +++ b/src/machine/machine-dbus.c @@ -0,0 +1,282 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "bus-util.h" +#include "strv.h" +#include "machine.h" + +static int property_get_id( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Machine *m = userdata; + int r; + + assert(bus); + assert(reply); + assert(m); + + r = sd_bus_message_append_array(reply, 'y', &m->id, 16); + if (r < 0) + return r; + + return 1; +} + +static int property_get_state( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Machine *m = userdata; + const char *state; + int r; + + assert(bus); + assert(reply); + assert(m); + + state = machine_state_to_string(machine_get_state(m)); + + r = sd_bus_message_append_basic(reply, 's', state); + if (r < 0) + return r; + + return 1; +} + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass); + +static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Machine *m = userdata; + int r; + + assert(bus); + assert(message); + assert(m); + + r = machine_stop(m); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Machine *m = userdata; + const char *swho; + int32_t signo; + KillWho who; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "si", &swho, &signo); + if (r < 0) + return r; + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); + } + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + r = machine_kill(m, who, signo); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable machine_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST), + BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), + SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_VTABLE_END +}; + +int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + if (streq(path, "/org/freedesktop/machine1/machine/self")) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + sd_bus_message *message; + pid_t pid; + + message = sd_bus_get_current(bus); + if (!message) + return 0; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + + r = manager_get_machine_by_pid(m, pid, &machine); + if (r <= 0) + return 0; + } else { + _cleanup_free_ char *e = NULL; + const char *p; + + p = startswith(path, "/org/freedesktop/machine1/machine/"); + if (!p) + return 0; + + e = sd_bus_label_unescape(p); + if (!e) + return -ENOMEM; + + machine = hashmap_get(m->machines, e); + if (!machine) + return 0; + } + + *found = machine; + return 1; +} + +char *machine_bus_path(Machine *m) { + _cleanup_free_ char *e = NULL; + + assert(m); + + e = sd_bus_label_escape(m->name); + if (!e) + return NULL; + + return strappend("/org/freedesktop/machine1/machine/", e); +} + +int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + Machine *machine = NULL; + Manager *m = userdata; + Iterator i; + int r; + + assert(bus); + assert(path); + assert(nodes); + + HASHMAP_FOREACH(machine, m->machines, i) { + char *p; + + p = machine_bus_path(machine); + if (!p) + return -ENOMEM; + + r = strv_push(&l, p); + if (r < 0) { + free(p); + return r; + } + } + + *nodes = l; + l = NULL; + + return 1; +} + +int machine_send_signal(Machine *m, bool new_machine) { + _cleanup_free_ char *p = NULL; + + assert(m); + + p = machine_bus_path(m); + if (!p) + return -ENOMEM; + + return sd_bus_emit_signal( + m->manager->bus, + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + new_machine ? "MachineNew" : "MachineRemoved", + "so", m->name, p); +} + +int machine_send_create_reply(Machine *m, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *c = NULL; + _cleanup_free_ char *p = NULL; + + assert(m); + + if (!m->create_message) + return 0; + + c = m->create_message; + m->create_message = NULL; + + if (error) + return sd_bus_reply_method_error(c, error); + + /* Update the machine state file before we notify the client + * about the result. */ + machine_save(m); + + p = machine_bus_path(m); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(c, "o", p); +} diff --git a/src/machine/machine.c b/src/machine/machine.c new file mode 100644 index 0000000..4596a80 --- /dev/null +++ b/src/machine/machine.c @@ -0,0 +1,436 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-messages.h" + +#include "util.h" +#include "mkdir.h" +#include "hashmap.h" +#include "strv.h" +#include "fileio.h" +#include "special.h" +#include "unit-name.h" +#include "machine.h" +#include "bus-util.h" +#include "bus-error.h" + +Machine* machine_new(Manager *manager, const char *name) { + Machine *m; + + assert(manager); + assert(name); + + m = new0(Machine, 1); + if (!m) + return NULL; + + m->name = strdup(name); + if (!m->name) + goto fail; + + m->state_file = strappend("/run/systemd/machines/", m->name); + if (!m->state_file) + goto fail; + + if (hashmap_put(manager->machines, m->name, m) < 0) + goto fail; + + m->class = _MACHINE_CLASS_INVALID; + m->manager = manager; + + return m; + +fail: + free(m->state_file); + free(m->name); + free(m); + + return NULL; +} + +void machine_free(Machine *m) { + assert(m); + + if (m->in_gc_queue) + LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m); + + if (m->unit) { + hashmap_remove(m->manager->machine_units, m->unit); + free(m->unit); + } + + free(m->scope_job); + + hashmap_remove(m->manager->machines, m->name); + + if (m->leader > 0) + hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); + + sd_bus_message_unref(m->create_message); + + free(m->name); + free(m->state_file); + free(m->service); + free(m->root_directory); + free(m); +} + +int machine_save(Machine *m) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(m); + assert(m->state_file); + + if (!m->started) + return 0; + + r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0); + if (r < 0) + goto finish; + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "NAME=%s\n", + m->name); + + if (m->unit) + fprintf(f, "SCOPE=%s\n", m->unit); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */ + + if (m->scope_job) + fprintf(f, "SCOPE_JOB=%s\n", m->scope_job); + + if (m->service) + fprintf(f, "SERVICE=%s\n", m->service); + + if (m->root_directory) + fprintf(f, "ROOT=%s\n", m->root_directory); + + if (!sd_id128_equal(m->id, SD_ID128_NULL)) + fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id)); + + if (m->leader != 0) + fprintf(f, "LEADER="PID_FMT"\n", m->leader); + + if (m->class != _MACHINE_CLASS_INVALID) + fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class)); + + if (dual_timestamp_is_set(&m->timestamp)) + fprintf(f, + "REALTIME="USEC_FMT"\n" + "MONOTONIC="USEC_FMT"\n", + m->timestamp.realtime, + m->timestamp.monotonic); + + fflush(f); + + if (ferror(f) || rename(temp_path, m->state_file) < 0) { + r = -errno; + unlink(m->state_file); + unlink(temp_path); + } + + if (m->unit) { + char *sl; + + /* Create a symlink from the unit name to the machine + * name, so that we can quickly find the machine for + * each given unit */ + sl = strappenda("/run/systemd/machines/unit:", m->unit); + symlink(m->name, sl); + } + +finish: + if (r < 0) + log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r)); + + return r; +} + +static void machine_unlink(Machine *m) { + assert(m); + + if (m->unit) { + + char *sl; + + sl = strappenda("/run/systemd/machines/unit:", m->unit); + unlink(sl); + } + + if (m->state_file) + unlink(m->state_file); +} + +int machine_load(Machine *m) { + _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL; + int r; + + assert(m); + + r = parse_env_file(m->state_file, NEWLINE, + "SCOPE", &m->unit, + "SCOPE_JOB", &m->scope_job, + "SERVICE", &m->service, + "ROOT", &m->root_directory, + "ID", &id, + "LEADER", &leader, + "CLASS", &class, + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + NULL); + if (r < 0) { + if (r == -ENOENT) + return 0; + + log_error("Failed to read %s: %s", m->state_file, strerror(-r)); + return r; + } + + if (id) + sd_id128_from_string(id, &m->id); + + if (leader) + parse_pid(leader, &m->leader); + + if (class) { + MachineClass c; + + c = machine_class_from_string(class); + if (c >= 0) + m->class = c; + } + + if (realtime) { + unsigned long long l; + if (sscanf(realtime, "%llu", &l) > 0) + m->timestamp.realtime = l; + } + + if (monotonic) { + unsigned long long l; + if (sscanf(monotonic, "%llu", &l) > 0) + m->timestamp.monotonic = l; + } + + return r; +} + +static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) { + int r = 0; + + assert(m); + + if (!m->unit) { + _cleanup_free_ char *escaped = NULL; + char *scope, *description, *job = NULL; + + escaped = unit_name_escape(m->name); + if (!escaped) + return log_oom(); + + scope = strjoin("machine-", escaped, ".scope", NULL); + if (!scope) + return log_oom(); + + description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name); + + r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job); + if (r < 0) { + log_error("Failed to start machine scope: %s", bus_error_message(error, r)); + free(scope); + return r; + } else { + m->unit = scope; + + free(m->scope_job); + m->scope_job = job; + } + } + + if (m->unit) + hashmap_put(m->manager->machine_units, m->unit, m); + + return r; +} + +int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) { + int r; + + assert(m); + + if (m->started) + return 0; + + r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); + if (r < 0) + return r; + + /* Create cgroup */ + r = machine_start_scope(m, properties, error); + if (r < 0) + return r; + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_MACHINE_START), + "NAME=%s", m->name, + "LEADER=%lu", (unsigned long) m->leader, + "MESSAGE=New machine %s.", m->name, + NULL); + + if (!dual_timestamp_is_set(&m->timestamp)) + dual_timestamp_get(&m->timestamp); + + m->started = true; + + /* Save new machine data */ + machine_save(m); + + machine_send_signal(m, true); + + return 0; +} + +static int machine_stop_scope(Machine *m) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char *job = NULL; + int r; + + assert(m); + + if (!m->unit) + return 0; + + r = manager_stop_unit(m->manager, m->unit, &error, &job); + if (r < 0) { + log_error("Failed to stop machine scope: %s", bus_error_message(&error, r)); + return r; + } + + free(m->scope_job); + m->scope_job = job; + + return r; +} + +int machine_stop(Machine *m) { + int r = 0, k; + assert(m); + + if (m->started) + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_MACHINE_STOP), + "NAME=%s", m->name, + "LEADER=%lu", (unsigned long) m->leader, + "MESSAGE=Machine %s terminated.", m->name, + NULL); + + /* Kill cgroup */ + k = machine_stop_scope(m); + if (k < 0) + r = k; + + machine_unlink(m); + machine_add_to_gc_queue(m); + + if (m->started) + machine_send_signal(m, false); + + m->started = false; + + return r; +} + +bool machine_check_gc(Machine *m, bool drop_not_started) { + assert(m); + + if (drop_not_started && !m->started) + return false; + + if (m->scope_job && manager_job_is_active(m->manager, m->scope_job)) + return true; + + if (m->unit && manager_unit_is_active(m->manager, m->unit)) + return true; + + return false; +} + +void machine_add_to_gc_queue(Machine *m) { + assert(m); + + if (m->in_gc_queue) + return; + + LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m); + m->in_gc_queue = true; +} + +MachineState machine_get_state(Machine *s) { + assert(s); + + if (s->scope_job) + return s->started ? MACHINE_OPENING : MACHINE_CLOSING; + + return MACHINE_RUNNING; +} + +int machine_kill(Machine *m, KillWho who, int signo) { + assert(m); + + if (!m->unit) + return -ESRCH; + + return manager_kill_unit(m->manager, m->unit, who, signo, NULL); +} + +static const char* const machine_class_table[_MACHINE_CLASS_MAX] = { + [MACHINE_CONTAINER] = "container", + [MACHINE_VM] = "vm" +}; + +DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass); + +static const char* const machine_state_table[_MACHINE_STATE_MAX] = { + [MACHINE_OPENING] = "opening", + [MACHINE_RUNNING] = "running", + [MACHINE_CLOSING] = "closing" +}; + +DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState); + +static const char* const kill_who_table[_KILL_WHO_MAX] = { + [KILL_LEADER] = "leader", + [KILL_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho); diff --git a/src/machine/machine.h b/src/machine/machine.h new file mode 100644 index 0000000..f4aefc5 --- /dev/null +++ b/src/machine/machine.h @@ -0,0 +1,109 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct Machine Machine; +typedef enum KillWho KillWho; + +#include "list.h" +#include "util.h" +#include "machined.h" + +typedef enum MachineState { + MACHINE_OPENING, /* Machine is being registered */ + MACHINE_RUNNING, /* Machine is running */ + MACHINE_CLOSING, /* Machine is terminating */ + _MACHINE_STATE_MAX, + _MACHINE_STATE_INVALID = -1 +} MachineState; + +typedef enum MachineClass { + MACHINE_CONTAINER, + MACHINE_VM, + _MACHINE_CLASS_MAX, + _MACHINE_CLASS_INVALID = -1 +} MachineClass; + +enum KillWho { + KILL_LEADER, + KILL_ALL, + _KILL_WHO_MAX, + _KILL_WHO_INVALID = -1 +}; + +struct Machine { + Manager *manager; + + char *name; + sd_id128_t id; + + MachineState state; + MachineClass class; + + char *state_file; + char *service; + char *root_directory; + + char *unit; + char *scope_job; + + pid_t leader; + + dual_timestamp timestamp; + + bool in_gc_queue:1; + bool started:1; + + sd_bus_message *create_message; + + LIST_FIELDS(Machine, gc_queue); +}; + +Machine* machine_new(Manager *manager, const char *name); +void machine_free(Machine *m); +bool machine_check_gc(Machine *m, bool drop_not_started); +void machine_add_to_gc_queue(Machine *m); +int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error); +int machine_stop(Machine *m); +int machine_save(Machine *m); +int machine_load(Machine *m); +int machine_kill(Machine *m, KillWho who, int signo); + +MachineState machine_get_state(Machine *u); + +extern const sd_bus_vtable machine_vtable[]; + +char *machine_bus_path(Machine *s); +int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); + +int machine_send_signal(Machine *m, bool new_machine); +int machine_send_create_reply(Machine *m, sd_bus_error *error); + +const char* machine_class_to_string(MachineClass t) _const_; +MachineClass machine_class_from_string(const char *s) _pure_; + +const char* machine_state_to_string(MachineState t) _const_; +MachineState machine_state_from_string(const char *s) _pure_; + +const char *kill_who_to_string(KillWho k) _const_; +KillWho kill_who_from_string(const char *s) _pure_; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c new file mode 100644 index 0000000..32f862d --- /dev/null +++ b/src/machine/machinectl.c @@ -0,0 +1,907 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "log.h" +#include "util.h" +#include "macro.h" +#include "pager.h" +#include "bus-util.h" +#include "bus-error.h" +#include "build.h" +#include "strv.h" +#include "unit-name.h" +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "ptyfwd.h" + +static char **arg_property = NULL; +static bool arg_all = false; +static bool arg_full = false; +static bool arg_no_pager = false; +static bool arg_legend = true; +static const char *arg_kill_who = NULL; +static int arg_signal = SIGTERM; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; + +static void pager_open_if_enabled(void) { + + /* Cache result before we open the pager */ + if (arg_no_pager) + return; + + pager_open(false); +} + +static int list_machines(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *name, *class, *service, *object; + unsigned k = 0; + int r; + + pager_open_if_enabled(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "ListMachines", + &error, + &reply, + ""); + if (r < 0) { + log_error("Could not get machines: %s", bus_error_message(&error, -r)); + return r; + } + + if (arg_legend) + printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE"); + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) { + printf("%-32s %-9s %-16s\n", name, class, service); + + k++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_legend) + printf("\n%u machines listed.\n", k); + + return 0; +} + +static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL; + const char *cgroup; + int r, output_flags; + unsigned c; + + assert(bus); + assert(unit); + + if (arg_transport == BUS_TRANSPORT_REMOTE) + return 0; + + path = unit_dbus_path_from_name(unit); + if (!path) + return log_oom(); + + r = sd_bus_get_property( + bus, + "org.freedesktop.systemd1", + path, + endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service", + "ControlGroup", + &error, + &reply, + "s"); + if (r < 0) { + log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &cgroup); + if (r < 0) + return bus_log_parse_error(r); + + if (isempty(cgroup)) + return 0; + + if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0) + return 0; + + output_flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH; + + c = columns(); + if (c > 18) + c -= 18; + else + c = 0; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags); + return 0; +} + +typedef struct MachineStatusInfo { + char *name; + sd_id128_t id; + char *class; + char *service; + char *unit; + char *root_directory; + pid_t leader; + usec_t timestamp; +} MachineStatusInfo; + +static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) { + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; + char since2[FORMAT_TIMESTAMP_MAX], *s2; + assert(i); + + fputs(strna(i->name), stdout); + + if (!sd_id128_equal(i->id, SD_ID128_NULL)) + printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id)); + else + putchar('\n'); + + s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp); + s2 = format_timestamp(since2, sizeof(since2), i->timestamp); + + if (s1) + printf("\t Since: %s; %s\n", s2, s1); + else if (s2) + printf("\t Since: %s\n", s2); + + if (i->leader > 0) { + _cleanup_free_ char *t = NULL; + + printf("\t Leader: %u", (unsigned) i->leader); + + get_process_comm(i->leader, &t); + if (t) + printf(" (%s)", t); + + putchar('\n'); + } + + if (i->service) { + printf("\t Service: %s", i->service); + + if (i->class) + printf("; class %s", i->class); + + putchar('\n'); + } else if (i->class) + printf("\t Class: %s\n", i->class); + + if (i->root_directory) + printf("\t Root: %s\n", i->root_directory); + + if (i->unit) { + printf("\t Unit: %s\n", i->unit); + show_unit_cgroup(bus, i->unit, i->leader); + } +} + +static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) { + + static const struct bus_properties_map map[] = { + { "Name", "s", NULL, offsetof(MachineStatusInfo, name) }, + { "Class", "s", NULL, offsetof(MachineStatusInfo, class) }, + { "Service", "s", NULL, offsetof(MachineStatusInfo, service) }, + { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) }, + { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) }, + { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) }, + { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp) }, + { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) }, + {} + }; + + MachineStatusInfo info = {}; + int r; + + assert(path); + assert(new_line); + + r = bus_map_all_properties(bus, + "org.freedesktop.machine1", + path, + map, + &info); + if (r < 0) { + log_error("Could not get properties: %s", strerror(-r)); + return r; + } + + if (*new_line) + printf("\n"); + *new_line = true; + + print_machine_status_info(bus, &info); + + free(info.name); + free(info.class); + free(info.service); + free(info.unit); + free(info.root_directory); + + return r; +} + +static int show_properties(sd_bus *bus, const char *path, bool *new_line) { + int r; + + if (*new_line) + printf("\n"); + + *new_line = true; + + r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all); + if (r < 0) + log_error("Could not get properties: %s", strerror(-r)); + + return r; +} + +static int show(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r = 0; + unsigned i; + bool properties, new_line = false; + + assert(bus); + assert(args); + + properties = !strstr(args[0], "status"); + + pager_open_if_enabled(); + + if (properties && n <= 1) { + + /* If no argument is specified, inspect the manager + * itself */ + r = show_properties(bus, "/org/freedesktop/machine1", &new_line); + if (r < 0) + return r; + } + + for (i = 1; i < n; i++) { + const char *path = NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachine", + &error, + &reply, + "s", args[i]); + if (r < 0) { + log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + if (properties) + r = show_properties(bus, path, &new_line); + else + r = show_info(args[0], bus, path, &new_line); + } + + return r; +} + +static int kill_machine(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + + assert(args); + + if (!arg_kill_who) + arg_kill_who = "all"; + + for (i = 1; i < n; i++) { + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "KillMachine", + &error, + NULL, + "ssi", args[i], arg_kill_who, arg_signal); + if (r < 0) { + log_error("Could not kill machine: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int terminate_machine(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + + assert(args); + + for (i = 1; i < n; i++) { + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "TerminateMachine", + &error, + NULL, + "s", args[i]); + if (r < 0) { + log_error("Could not terminate machine: %s", bus_error_message(&error, -r)); + return r; + } + } + + return 0; +} + +static int reboot_machine(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + unsigned i; + int r; + + assert(args); + + if (arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Reboot only supported on local machines."); + return -ENOTSUP; + } + + for (i = 1; i < n; i++) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL; + const char *path; + uint32_t leader; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachine", + &error, + &reply, + "s", args[i]); + + if (r < 0) { + log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_get_property( + bus, + "org.freedesktop.machine1", + path, + "org.freedesktop.machine1.Machine", + "Leader", + &error, + &reply2, + "u"); + if (r < 0) { + log_error("Failed to retrieve PID of leader: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_read(reply2, "u", &leader); + if (r < 0) + return bus_log_parse_error(r); + + if (kill(leader, SIGINT) < 0) { + log_error("Failed to kill init process " PID_FMT ": %m", (pid_t) leader); + return -errno; + } + } + + return 0; +} + +static int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_pipe_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + int master = -1, r; + pid_t child; + siginfo_t si; + + r = namespace_open(pid, &pidnsfd, &mntnsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + close_nointr_nofail(pair[0]); + pair[0] = -1; + + r = namespace_enter(pidnsfd, mntnsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags); + if (master < 0) + _exit(EXIT_FAILURE); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + close_nointr_nofail(pair[1]); + pair[1] = -1; + + r = wait_for_terminate(child, &si); + if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) { + + return r < 0 ? r : -EIO; + } + + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; + + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (n_fds != 1) { + close_many(fds, n_fds); + return -EIO; + } + + master = fds[0]; + } + + if (master < 0) + return -EIO; + + return master; +} + +static int login_machine(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL, *reply3 = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *container_bus = NULL; + _cleanup_close_ int master = -1; + _cleanup_free_ char *getty = NULL; + const char *path, *pty, *p; + uint32_t leader; + sigset_t mask; + int r; + + assert(bus); + assert(args); + + if (arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Login only supported on local machines."); + return -ENOTSUP; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachine", + &error, + &reply, + "s", args[1]); + if (r < 0) { + log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_get_property( + bus, + "org.freedesktop.machine1", + path, + "org.freedesktop.machine1.Machine", + "Leader", + &error, + &reply2, + "u"); + if (r < 0) { + log_error("Failed to retrieve PID of leader: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_read(reply2, "u", &leader); + if (r < 0) + return bus_log_parse_error(r); + + master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); + if (master < 0) { + log_error("Failed to acquire pseudo tty: %s", strerror(-master)); + return master; + } + + pty = ptsname(master); + if (!pty) { + log_error("Failed to get pty name: %m"); + return -errno; + } + + p = startswith(pty, "/dev/pts/"); + if (!p) { + log_error("Invalid pty name %s.", pty); + return -EIO; + } + + r = sd_bus_open_system_container(&container_bus, args[1]); + if (r < 0) { + log_error("Failed to get container bus: %s", strerror(-r)); + return r; + } + + getty = strjoin("container-getty@", p, ".service", NULL); + if (!getty) + return log_oom(); + + if (unlockpt(master) < 0) { + log_error("Failed to unlock tty: %m"); + return -errno; + } + + r = sd_bus_call_method(container_bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + &error, &reply3, + "ss", getty, "replace"); + if (r < 0) { + log_error("Failed to start getty service: %s", bus_error_message(&error, r)); + return r; + } + + container_bus = sd_bus_unref(container_bus); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1); + assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); + + log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]); + + r = process_pty(master, &mask, 0, 0); + if (r < 0) { + log_error("Failed to process pseudo tty: %s", strerror(-r)); + return r; + } + + fputc('\n', stdout); + + log_info("Connection to container %s terminated.", args[1]); + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Send control commands to or query the virtual machine and container registration manager.\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" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " -p --property=NAME Show only properties by this name\n" + " -a --all Show all properties, including empty ones\n" + " -l --full Do not ellipsize output\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n\n" + "Commands:\n" + " list List running VMs and containers\n" + " status NAME... Show VM/container status\n" + " show NAME... Show properties of one or more VMs/containers\n" + " terminate NAME... Terminate one or more VMs/containers\n" + " kill NAME... Send signal to processes of a VM/container\n" + " reboot NAME... Reboot one or more containers\n" + " login NAME Get a login prompt on a container\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, + ARG_KILL_WHO, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "property", required_argument, NULL, 'p' }, + { "all", no_argument, NULL, 'a' }, + { "full", no_argument, NULL, 'l' }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "kill-who", required_argument, NULL, ARG_KILL_WHO }, + { "signal", required_argument, NULL, 's' }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'p': + r = strv_extend(&arg_property, optarg); + if (r < 0) + return log_oom(); + + /* If the user asked for a particular + * property, show it to him, even if it is + * empty. */ + arg_all = true; + break; + + case 'a': + arg_all = true; + break; + + case 'l': + arg_full = true; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + + case ARG_KILL_WHO: + arg_kill_who = optarg; + break; + + case 's': + arg_signal = signal_from_string_try_harder(optarg); + if (arg_signal < 0) { + log_error("Failed to parse signal string %s.", optarg); + return -EINVAL; + } + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int machinectl_main(sd_bus *bus, int argc, char *argv[]) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args, unsigned n); + } verbs[] = { + { "list", LESS, 1, list_machines }, + { "status", MORE, 2, show }, + { "show", MORE, 1, show }, + { "terminate", MORE, 2, terminate_machine }, + { "reboot", MORE, 2, reboot_machine }, + { "kill", MORE, 2, kill_machine }, + { "login", MORE, 2, login_machine }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "list" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(bus, argv + optind, left); +} + +int main(int argc, char*argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, false, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + r = machinectl_main(bus, argc, argv); + +finish: + pager_close(); + + strv_free(arg_property); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c new file mode 100644 index 0000000..09d28bb --- /dev/null +++ b/src/machine/machined-dbus.c @@ -0,0 +1,788 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" + +#include "strv.h" +#include "mkdir.h" +#include "path-util.h" +#include "special.h" +#include "fileio-label.h" +#include "label.h" +#include "utf8.h" +#include "unit-name.h" +#include "bus-util.h" +#include "bus-errors.h" +#include "time-util.h" +#include "cgroup-util.h" +#include "machined.h" + +static bool valid_machine_name(const char *p) { + size_t l; + + if (!filename_is_safe(p)) + return false; + + if (!ascii_is_valid(p)) + return false; + + l = strlen(p); + + if (l < 1 || l> 64) + return false; + + return true; +} + +static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + Machine *machine; + const char *name; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + p = machine_bus_path(machine); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + Machine *machine = NULL; + pid_t pid; + int r; + + assert(bus); + assert(message); + assert(m); + + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + + r = sd_bus_message_read(message, "u", &pid); + if (r < 0) + return r; + + if (pid == 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_pid(creds, &pid); + if (r < 0) + return r; + } + + r = manager_get_machine_by_pid(m, pid, &machine); + if (r < 0) + return r; + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid); + + p = machine_bus_path(machine); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + +static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; + Machine *machine; + Iterator i; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + r = sd_bus_message_open_container(reply, 'a', "(ssso)"); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + HASHMAP_FOREACH(machine, m->machines, i) { + _cleanup_free_ char *p = NULL; + + p = machine_bus_path(machine); + if (!p) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(ssso)", + machine->name, + strempty(machine_class_to_string(machine->class)), + machine->service, + p); + if (r < 0) + return sd_bus_error_set_errno(error, r); + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + return sd_bus_send(bus, reply, NULL); +} + +static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) { + const char *name, *service, *class, *root_directory; + MachineClass c; + uint32_t leader; + sd_id128_t id; + const void *v; + Machine *m; + size_t n; + int r; + + assert(manager); + assert(message); + assert(_m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + if (!valid_machine_name(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name"); + + r = sd_bus_message_read_array(message, 'y', &v, &n); + if (r < 0) + return r; + if (n == 0) + id = SD_ID128_NULL; + else if (n == 16) + memcpy(&id, v, n); + else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter"); + + r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory); + if (r < 0) + return r; + + if (isempty(class)) + c = _MACHINE_CLASS_INVALID; + else { + c = machine_class_from_string(class); + if (c < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter"); + } + + if (leader == 1) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); + + if (!isempty(root_directory) && !path_is_absolute(root_directory)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path"); + + if (leader == 0) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); + if (r < 0) + return r; + + assert_cc(sizeof(uint32_t) == sizeof(pid_t)); + + r = sd_bus_creds_get_pid(creds, (pid_t*) &leader); + if (r < 0) + return r; + } + + if (hashmap_get(manager->machines, name)) + return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); + + r = manager_add_machine(manager, name, &m); + if (r < 0) + return r; + + m->leader = leader; + m->class = c; + m->id = id; + + if (!isempty(service)) { + m->service = strdup(service); + if (!m->service) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(root_directory)) { + m->root_directory = strdup(root_directory); + if (!m->root_directory) { + r = -ENOMEM; + goto fail; + } + } + + *_m = m; + + return 1; + +fail: + machine_add_to_gc_queue(m); + return r; +} + +static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *manager = userdata; + Machine *m = NULL; + int r; + + r = method_create_or_register_machine(manager, message, &m, error); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) + goto fail; + + r = machine_start(m, message, error); + if (r < 0) + goto fail; + + m->create_message = sd_bus_message_ref(message); + return 1; + +fail: + machine_add_to_gc_queue(m); + return r; +} + +static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *manager = userdata; + _cleanup_free_ char *p = NULL; + Machine *m = NULL; + int r; + + r = method_create_or_register_machine(manager, message, &m, error); + if (r < 0) + return r; + + r = cg_pid_get_unit(m->leader, &m->unit); + if (r < 0) { + r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r)); + goto fail; + } + + r = machine_start(m, NULL, error); + if (r < 0) + goto fail; + + p = machine_bus_path(m); + if (!p) { + r = -ENOMEM; + goto fail; + } + + return sd_bus_reply_method_return(message, "o", p); + +fail: + machine_add_to_gc_queue(m); + return r; +} + +static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + const char *name; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + r = machine_stop(machine); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + const char *name; + const char *swho; + int32_t signo; + KillWho who; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "ssi", &name, &swho, &signo); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + if (isempty(swho)) + who = KILL_ALL; + else { + who = kill_who_from_string(swho); + if (who < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); + } + + if (signo <= 0 || signo >= _NSIG) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + r = machine_kill(machine, who, signo); + if (r < 0) + return sd_bus_error_set_errno(error, r); + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable manager_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0), + SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0), + SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_SIGNAL("MachineNew", "so", 0), + SD_BUS_SIGNAL("MachineRemoved", "so", 0), + SD_BUS_VTABLE_END +}; + +int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *path, *result, *unit; + Manager *m = userdata; + Machine *machine; + uint32_t id; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + machine = hashmap_get(m->machine_units, unit); + if (!machine) + return 0; + + if (streq_ptr(path, machine->scope_job)) { + free(machine->scope_job); + machine->scope_job = NULL; + + if (machine->started) { + if (streq(result, "done")) + machine_send_create_reply(machine, NULL); + else { + _cleanup_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); + + machine_send_create_reply(machine, &e); + } + } else + machine_save(machine); + } + + machine_add_to_gc_queue(machine); + return 0; +} + +int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *unit = NULL; + Manager *m = userdata; + Machine *machine; + const char *path; + int r; + + assert(bus); + assert(message); + assert(m); + + path = sd_bus_message_get_path(message); + if (!path) + return 0; + + r = unit_name_from_dbus_path(path, &unit); + if (r < 0) + return r; + + machine = hashmap_get(m->machine_units, unit); + if (machine) + machine_add_to_gc_queue(machine); + + return 0; +} + +int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + const char *path, *unit; + Manager *m = userdata; + Machine *machine; + int r; + + assert(bus); + assert(message); + assert(m); + + r = sd_bus_message_read(message, "so", &unit, &path); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + + machine = hashmap_get(m->machine_units, unit); + if (machine) + machine_add_to_gc_queue(machine); + + return 0; +} + +int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + Iterator i; + int b, r; + + assert(bus); + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) { + bus_log_parse_error(r); + return r; + } + if (b) + return 0; + + /* systemd finished reloading, let's recheck all our machines */ + log_debug("System manager has been reloaded, rechecking machines..."); + + HASHMAP_FOREACH(machine, m->machines, i) + machine_add_to_gc_queue(machine); + + return 0; +} + +int manager_start_scope( + Manager *manager, + const char *scope, + pid_t pid, + const char *slice, + const char *description, + sd_bus_message *more_properties, + sd_bus_error *error, + char **job) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + int r; + + assert(manager); + assert(scope); + assert(pid > 1); + + r = sd_bus_message_new_method_call( + manager->bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "ss", strempty(scope), "fail"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) + return r; + + if (!isempty(slice)) { + r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); + if (r < 0) + return r; + } + + if (!isempty(description)) { + r = sd_bus_message_append(m, "(sv)", "Description", "s", description); + if (r < 0) + return r; + } + + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid); + if (r < 0) + return r; + + if (more_properties) { + r = sd_bus_message_copy(m, more_properties, true); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "a(sa(sv))", 0); + if (r < 0) + return r; + + r = sd_bus_call(manager->bus, m, 0, error, &reply); + if (r < 0) + return r; + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + +int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(manager); + assert(unit); + + r = sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StopUnit", + error, + &reply, + "ss", unit, "fail"); + if (r < 0) { + if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) || + sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) { + + if (job) + *job = NULL; + + sd_bus_error_free(error); + return 0; + } + + return r; + } + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + +int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) { + assert(manager); + assert(unit); + + return sd_bus_call_method( + manager->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + error, + NULL, + "ssi", unit, who == KILL_LEADER ? "main" : "all", signo); +} + +int manager_unit_is_active(Manager *manager, const char *unit) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ char *path = NULL; + const char *state; + int r; + + assert(manager); + assert(unit); + + path = unit_dbus_path_from_name(unit); + if (!path) + return -ENOMEM; + + r = sd_bus_get_property( + manager->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &reply, + "s"); + if (r < 0) { + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) || + sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED)) + return true; + + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) || + sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) + return false; + + return r; + } + + r = sd_bus_message_read(reply, "s", &state); + if (r < 0) + return -EINVAL; + + return !streq(state, "inactive") && !streq(state, "failed"); +} + +int manager_job_is_active(Manager *manager, const char *path) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + int r; + + assert(manager); + assert(path); + + r = sd_bus_get_property( + manager->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Job", + "State", + &error, + &reply, + "s"); + if (r < 0) { + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) || + sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED)) + return true; + + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT)) + return false; + + return r; + } + + /* We don't actually care about the state really. The fact + * that we could read the job state is enough for us */ + + return true; +} + +int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) { + _cleanup_free_ char *unit = NULL; + Machine *mm; + int r; + + assert(m); + assert(pid >= 1); + assert(machine); + + r = cg_pid_get_unit(pid, &unit); + if (r < 0) + mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid)); + else + mm = hashmap_get(m->machine_units, unit); + + if (!mm) + return 0; + + *machine = mm; + return 1; +} + +int manager_add_machine(Manager *m, const char *name, Machine **_machine) { + Machine *machine; + + assert(m); + assert(name); + + machine = hashmap_get(m->machines, name); + if (!machine) { + machine = machine_new(m, name); + if (!machine) + return -ENOMEM; + } + + if (_machine) + *_machine = machine; + + return 0; +} diff --git a/src/machine/machined.c b/src/machine/machined.c new file mode 100644 index 0000000..20e6f7c --- /dev/null +++ b/src/machine/machined.c @@ -0,0 +1,355 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" + +#include "strv.h" +#include "conf-parser.h" +#include "cgroup-util.h" +#include "mkdir.h" +#include "bus-util.h" +#include "bus-error.h" +#include "machined.h" + +Manager *manager_new(void) { + Manager *m; + int r; + + m = new0(Manager, 1); + if (!m) + return NULL; + + m->machines = hashmap_new(string_hash_func, string_compare_func); + m->machine_units = hashmap_new(string_hash_func, string_compare_func); + m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func); + + if (!m->machines || !m->machine_units || !m->machine_leaders) { + manager_free(m); + return NULL; + } + + r = sd_event_default(&m->event); + if (r < 0) { + manager_free(m); + return NULL; + } + + sd_event_set_watchdog(m->event, true); + + return m; +} + +void manager_free(Manager *m) { + Machine *machine; + + assert(m); + + while ((machine = hashmap_first(m->machines))) + machine_free(machine); + + hashmap_free(m->machines); + hashmap_free(m->machine_units); + hashmap_free(m->machine_leaders); + + sd_bus_unref(m->bus); + sd_event_unref(m->event); + + free(m); +} + +int manager_enumerate_machines(Manager *m) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(m); + + /* Read in machine data stored on disk */ + d = opendir("/run/systemd/machines"); + if (!d) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open /run/systemd/machines: %m"); + return -errno; + } + + FOREACH_DIRENT(de, d, return -errno) { + struct Machine *machine; + int k; + + if (!dirent_is_file(de)) + continue; + + /* Ignore symlinks that map the unit name to the machine */ + if (startswith(de->d_name, "unit:")) + continue; + + k = manager_add_machine(m, de->d_name, &machine); + if (k < 0) { + log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k)); + + r = k; + continue; + } + + machine_add_to_gc_queue(machine); + + k = machine_load(machine); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_connect_bus(Manager *m) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(m); + assert(!m->bus); + + r = sd_bus_default_system(&m->bus); + if (r < 0) { + log_error("Failed to connect to system bus: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m); + if (r < 0) { + log_error("Failed to add manager object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m); + if (r < 0) { + log_error("Failed to add machine object vtable: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m); + if (r < 0) { + log_error("Failed to add machine enumerator: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + match_job_removed, + m); + if (r < 0) { + log_error("Failed to add match for JobRemoved: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='UnitRemoved'," + "path='/org/freedesktop/systemd1'", + match_unit_removed, + m); + if (r < 0) { + log_error("Failed to add match for UnitRemoved: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.DBus.Properties'," + "member='PropertiesChanged'", + match_properties_changed, + m); + if (r < 0) { + log_error("Failed to add match for PropertiesChanged: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_match(m->bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='Reloading'," + "path='/org/freedesktop/systemd1'", + match_reloading, + m); + if (r < 0) { + log_error("Failed to add match for Reloading: %s", strerror(-r)); + return r; + } + + r = sd_bus_call_method( + m->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Subscribe", + &error, + NULL, NULL); + if (r < 0) { + log_error("Failed to enable subscription: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(m->bus, m->event, 0); + if (r < 0) { + log_error("Failed to attach bus to event loop: %s", strerror(-r)); + return r; + } + + return 0; +} + +void manager_gc(Manager *m, bool drop_not_started) { + Machine *machine; + + assert(m); + + while ((machine = m->machine_gc_queue)) { + LIST_REMOVE(gc_queue, m->machine_gc_queue, machine); + machine->in_gc_queue = false; + + if (!machine_check_gc(machine, drop_not_started)) { + machine_stop(machine); + machine_free(machine); + } + } +} + +int manager_startup(Manager *m) { + Machine *machine; + Iterator i; + int r; + + assert(m); + + /* Connect to the bus */ + r = manager_connect_bus(m); + if (r < 0) + return r; + + /* Deserialize state */ + manager_enumerate_machines(m); + + /* Remove stale objects before we start them */ + manager_gc(m, false); + + /* And start everything */ + HASHMAP_FOREACH(machine, m->machines, i) + machine_start(machine, NULL, NULL); + + return 0; +} + +static bool check_idle(void *userdata) { + Manager *m = userdata; + + manager_gc(m, true); + + return hashmap_isempty(m->machines); +} + +int manager_run(Manager *m) { + assert(m); + + return bus_event_loop_with_idle( + m->event, + m->bus, + "org.freedesktop.machine1", + DEFAULT_EXIT_USEC, + check_idle, m); +} + +int main(int argc, char *argv[]) { + Manager *m = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_set_facility(LOG_AUTH); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + /* Always create the directories people can create inotify + * watches in. Note that some applications might check for the + * existence of /run/systemd/machines/ to determine whether + * machined is available, so please always make sure this + * check stays in. */ + mkdir_label("/run/systemd/machines", 0755); + + m = manager_new(); + if (!m) { + r = log_oom(); + goto finish; + } + + r = manager_startup(m); + if (r < 0) { + log_error("Failed to fully start up daemon: %s", strerror(-r)); + goto finish; + } + + log_debug("systemd-machined running as pid %lu", (unsigned long) getpid()); + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + r = manager_run(m); + + log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid()); + +finish: + sd_notify(false, + "STATUS=Shutting down..."); + + if (m) + manager_free(m); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/machine/machined.h b/src/machine/machined.h new file mode 100644 index 0000000..d4b581b --- /dev/null +++ b/src/machine/machined.h @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "list.h" +#include "hashmap.h" +#include "sd-event.h" +#include "sd-bus.h" + +typedef struct Manager Manager; + +#include "machine.h" + +struct Manager { + sd_event *event; + sd_bus *bus; + + Hashmap *machines; + Hashmap *machine_units; + Hashmap *machine_leaders; + + LIST_HEAD(Machine, machine_gc_queue); +}; + +Manager *manager_new(void); +void manager_free(Manager *m); + +int manager_add_machine(Manager *m, const char *name, Machine **_machine); +int manager_enumerate_machines(Manager *m); + +int manager_startup(Manager *m); +int manager_run(Manager *m); + +void manager_gc(Manager *m, bool drop_not_started); + +int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine); + +extern const sd_bus_vtable manager_vtable[]; + +int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); + +int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job); +int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); +int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error); +int manager_unit_is_active(Manager *manager, const char *unit); +int manager_job_is_active(Manager *manager, const char *path); diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf new file mode 100644 index 0000000..970ccd8 --- /dev/null +++ b/src/machine/org.freedesktop.machine1.conf @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/machine/org.freedesktop.machine1.service b/src/machine/org.freedesktop.machine1.service new file mode 100644 index 0000000..d3dc998 --- /dev/null +++ b/src/machine/org.freedesktop.machine1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.machine1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.machine1.service diff --git a/src/machine/test-machine-tables.c b/src/machine/test-machine-tables.c new file mode 100644 index 0000000..4aae426 --- /dev/null +++ b/src/machine/test-machine-tables.c @@ -0,0 +1,30 @@ +/*** + This file is part of systemd + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "machine.h" + +#include "test-tables.h" + +int main(int argc, char **argv) { + test_table(machine_class, MACHINE_CLASS); + test_table(machine_state, MACHINE_STATE); + test_table(kill_who, KILL_WHO); + + return EXIT_SUCCESS; +} diff --git a/src/macro.h b/src/macro.h deleted file mode 100644 index e7a4d2c..0000000 --- a/src/macro.h +++ /dev/null @@ -1,184 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomacrohfoo -#define foomacrohfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b))) -#define _sentinel_ __attribute__ ((sentinel)) -#define _noreturn_ __attribute__((noreturn)) -#define _unused_ __attribute__ ((unused)) -#define _destructor_ __attribute__ ((destructor)) -#define _pure_ __attribute__ ((pure)) -#define _const_ __attribute__ ((const)) -#define _deprecated_ __attribute__ ((deprecated)) -#define _packed_ __attribute__ ((packed)) -#define _malloc_ __attribute__ ((malloc)) -#define _weak_ __attribute__ ((weak)) -#define _likely_(x) (__builtin_expect(!!(x),1)) -#define _unlikely_(x) (__builtin_expect(!!(x),0)) -#define _public_ __attribute__ ((visibility("default"))) -#define _hidden_ __attribute__ ((visibility("hidden"))) -#define _weakref_(x) __attribute__((weakref(#x))) -#define _introspect_(x) __attribute__((section("introspect." x))) - -#define XSTRINGIFY(x) #x -#define STRINGIFY(x) XSTRINGIFY(x) - -/* Rounds up */ -#define ALIGN(l) ALIGN_TO((l), sizeof(void*)) -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); -} - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -#ifndef MAX -#define MAX(a,b) \ - __extension__ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ - _a > _b ? _a : _b; \ - }) -#endif - -#define MAX3(a,b,c) \ - MAX(MAX(a,b),c) - -#ifndef MIN -#define MIN(a,b) \ - __extension__ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ - _a < _b ? _a : _b; \ - }) -#endif - -#define MIN3(a,b,c) \ - MIN(MIN(a,b),c) - -#define CLAMP(x, low, high) \ - __extension__ ({ \ - typeof(x) _x = (x); \ - typeof(low) _low = (low); \ - typeof(high) _high = (high); \ - ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ - }) - -#define assert_se(expr) \ - do { \ - if (_unlikely_(!(expr))) \ - log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ - "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \ - #expr , __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) \ - -/* We override the glibc assert() here. */ -#undef assert -#ifdef NDEBUG -#define assert(expr) do {} while(false) -#else -#define assert(expr) assert_se(expr) -#endif - -#define assert_not_reached(t) \ - do { \ - log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ - "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", \ - t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) - -#define assert_cc(expr) \ - do { \ - switch (0) { \ - case 0: \ - case !!(expr): \ - ; \ - } \ - } while (false) - -#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) -#define UINT_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) -#define UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) -#define ULONG_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) -#define INT_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define TO_INT32(p) ((int32_t) ((intptr_t) (p))) -#define INT32_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) -#define LONG_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define memzero(x,l) (memset((x), 0, (l))) -#define zero(x) (memzero(&(x), sizeof(x))) - -#define char_array_0(x) x[sizeof(x)-1] = 0; - -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false); - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - -#include "log.h" - -#endif diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 5c28a6c..0000000 --- a/src/main.c +++ /dev/null @@ -1,1597 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "manager.h" -#include "log.h" -#include "mount-setup.h" -#include "hostname-setup.h" -#include "loopback-setup.h" -#include "kmod-setup.h" -#include "locale-setup.h" -#include "selinux-setup.h" -#include "machine-id-setup.h" -#include "load-fragment.h" -#include "fdset.h" -#include "special.h" -#include "conf-parser.h" -#include "bus-errors.h" -#include "missing.h" -#include "label.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "virt.h" - -static enum { - ACTION_RUN, - ACTION_HELP, - ACTION_TEST, - ACTION_DUMP_CONFIGURATION_ITEMS, - ACTION_DONE -} arg_action = ACTION_RUN; - -static char *arg_default_unit = NULL; -static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; - -static bool arg_dump_core = true; -static bool arg_crash_shell = false; -static int arg_crash_chvt = -1; -static bool arg_confirm_spawn = false; -static bool arg_show_status = true; -#ifdef HAVE_SYSV_COMPAT -static bool arg_sysv_console = true; -#endif -static bool arg_mount_auto = true; -static bool arg_swap_auto = true; -static char **arg_default_controllers = NULL; -static char ***arg_join_controllers = NULL; -static ExecOutput arg_default_std_output = EXEC_OUTPUT_SYSLOG; -static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; - -static FILE* serialization = NULL; - -static void nop_handler(int sig) { -} - -_noreturn_ static void crash(int sig) { - - if (!arg_dump_core) - log_error("Caught <%s>, not dumping core.", signal_to_string(sig)); - else { - struct sigaction sa; - pid_t pid; - - /* We want to wait for the core process, hence let's enable SIGCHLD */ - zero(sa); - sa.sa_handler = nop_handler; - sa.sa_flags = SA_NOCLDSTOP|SA_RESTART; - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); - - if ((pid = fork()) < 0) - log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno)); - - else if (pid == 0) { - struct rlimit rl; - - /* Enable default signal handler for core dump */ - zero(sa); - sa.sa_handler = SIG_DFL; - assert_se(sigaction(sig, &sa, NULL) == 0); - - /* Don't limit the core dump size */ - zero(rl); - rl.rlim_cur = RLIM_INFINITY; - rl.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &rl); - - /* Just to be sure... */ - assert_se(chdir("/") == 0); - - /* Raise the signal again */ - raise(sig); - - assert_not_reached("We shouldn't be here..."); - _exit(1); - - } else { - siginfo_t status; - int r; - - /* Order things nicely. */ - if ((r = wait_for_terminate(pid, &status)) < 0) - log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r)); - else if (status.si_code != CLD_DUMPED) - log_error("Caught <%s>, core dump failed.", signal_to_string(sig)); - else - log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid); - } - } - - if (arg_crash_chvt) - chvt(arg_crash_chvt); - - if (arg_crash_shell) { - struct sigaction sa; - pid_t pid; - - log_info("Executing crash shell in 10s..."); - sleep(10); - - /* Let the kernel reap children for us */ - zero(sa); - sa.sa_handler = SIG_IGN; - sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART; - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); - - if ((pid = fork()) < 0) - log_error("Failed to fork off crash shell: %s", strerror(errno)); - else if (pid == 0) { - int fd, r; - - if ((fd = acquire_terminal("/dev/console", false, true, true)) < 0) - log_error("Failed to acquire terminal: %s", strerror(-fd)); - else if ((r = make_stdio(fd)) < 0) - log_error("Failed to duplicate terminal fd: %s", strerror(-r)); - - execl("/bin/sh", "/bin/sh", NULL); - - log_error("execl() failed: %s", strerror(errno)); - _exit(1); - } - - log_info("Successfully spawned crash shell as pid %lu.", (unsigned long) pid); - } - - log_info("Freezing execution."); - freeze(); -} - -static void install_crash_handler(void) { - struct sigaction sa; - - zero(sa); - - sa.sa_handler = crash; - sa.sa_flags = SA_NODEFER; - - sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1); -} - -static int console_setup(bool do_reset) { - int tty_fd, r; - - /* If we are init, we connect stdin/stdout/stderr to /dev/null - * and make sure we don't have a controlling tty. */ - - release_terminal(); - - if (!do_reset) - return 0; - - if ((tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) { - log_error("Failed to open /dev/console: %s", strerror(-tty_fd)); - return -tty_fd; - } - - if ((r = reset_terminal_fd(tty_fd)) < 0) - log_error("Failed to reset /dev/console: %s", strerror(-r)); - - close_nointr_nofail(tty_fd); - return r; -} - -static int set_default_unit(const char *u) { - char *c; - - assert(u); - - if (!(c = strdup(u))) - return -ENOMEM; - - free(arg_default_unit); - arg_default_unit = c; - return 0; -} - -static int parse_proc_cmdline_word(const char *word) { - - static const char * const rlmap[] = { - "emergency", SPECIAL_EMERGENCY_TARGET, - "-b", SPECIAL_EMERGENCY_TARGET, - "single", SPECIAL_RESCUE_TARGET, - "-s", SPECIAL_RESCUE_TARGET, - "s", SPECIAL_RESCUE_TARGET, - "S", SPECIAL_RESCUE_TARGET, - "1", SPECIAL_RESCUE_TARGET, - "2", SPECIAL_RUNLEVEL2_TARGET, - "3", SPECIAL_RUNLEVEL3_TARGET, - "4", SPECIAL_RUNLEVEL4_TARGET, - "5", SPECIAL_RUNLEVEL5_TARGET, - }; - - assert(word); - - if (startswith(word, "systemd.unit=")) - return set_default_unit(word + 13); - - else if (startswith(word, "systemd.log_target=")) { - - if (log_set_target_from_string(word + 19) < 0) - log_warning("Failed to parse log target %s. Ignoring.", word + 19); - - } else if (startswith(word, "systemd.log_level=")) { - - if (log_set_max_level_from_string(word + 18) < 0) - log_warning("Failed to parse log level %s. Ignoring.", word + 18); - - } else if (startswith(word, "systemd.log_color=")) { - - if (log_show_color_from_string(word + 18) < 0) - log_warning("Failed to parse log color setting %s. Ignoring.", word + 18); - - } else if (startswith(word, "systemd.log_location=")) { - - if (log_show_location_from_string(word + 21) < 0) - log_warning("Failed to parse log location setting %s. Ignoring.", word + 21); - - } else if (startswith(word, "systemd.dump_core=")) { - int r; - - if ((r = parse_boolean(word + 18)) < 0) - log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18); - else - arg_dump_core = r; - - } else if (startswith(word, "systemd.crash_shell=")) { - int r; - - if ((r = parse_boolean(word + 20)) < 0) - log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20); - else - arg_crash_shell = r; - - } else if (startswith(word, "systemd.confirm_spawn=")) { - int r; - - if ((r = parse_boolean(word + 22)) < 0) - log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22); - else - arg_confirm_spawn = r; - - } else if (startswith(word, "systemd.crash_chvt=")) { - int k; - - if (safe_atoi(word + 19, &k) < 0) - log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19); - else - arg_crash_chvt = k; - - } else if (startswith(word, "systemd.show_status=")) { - int r; - - if ((r = parse_boolean(word + 20)) < 0) - log_warning("Failed to parse show status switch %s, Ignoring.", word + 20); - else - arg_show_status = r; - } else if (startswith(word, "systemd.default_standard_output=")) { - int r; - - if ((r = exec_output_from_string(word + 32)) < 0) - log_warning("Failed to parse default standard output switch %s, Ignoring.", word + 32); - else - arg_default_std_output = r; - } else if (startswith(word, "systemd.default_standard_error=")) { - int r; - - if ((r = exec_output_from_string(word + 31)) < 0) - log_warning("Failed to parse default standard error switch %s, Ignoring.", word + 31); - else - arg_default_std_error = r; -#ifdef HAVE_SYSV_COMPAT - } else if (startswith(word, "systemd.sysv_console=")) { - int r; - - if ((r = parse_boolean(word + 21)) < 0) - log_warning("Failed to parse SysV console switch %s, Ignoring.", word + 20); - else - arg_sysv_console = r; -#endif - - } else if (startswith(word, "systemd.")) { - - log_warning("Unknown kernel switch %s. Ignoring.", word); - - log_info("Supported kernel switches:\n" - "systemd.unit=UNIT Default unit to start\n" - "systemd.dump_core=0|1 Dump core on crash\n" - "systemd.crash_shell=0|1 Run shell on crash\n" - "systemd.crash_chvt=N Change to VT #N on crash\n" - "systemd.confirm_spawn=0|1 Confirm every process spawn\n" - "systemd.show_status=0|1 Show status updates on the console during bootup\n" -#ifdef HAVE_SYSV_COMPAT - "systemd.sysv_console=0|1 Connect output of SysV scripts to console\n" -#endif - "systemd.log_target=console|kmsg|syslog|syslog-or-kmsg|null\n" - " Log target\n" - "systemd.log_level=LEVEL Log level\n" - "systemd.log_color=0|1 Highlight important log messages\n" - "systemd.log_location=0|1 Include code location in log messages\n" - "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console\n" - " Set default log output for services\n" - "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console\n" - " Set default log error output for services\n"); - - } else if (streq(word, "quiet")) { - arg_show_status = false; -#ifdef HAVE_SYSV_COMPAT - arg_sysv_console = false; -#endif - } else { - unsigned i; - - /* SysV compatibility */ - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) - return set_default_unit(rlmap[i+1]); - } - - return 0; -} - -static int config_parse_level2( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - assert(filename); - assert(lvalue); - assert(rvalue); - - log_set_max_level_from_string(rvalue); - return 0; -} - -static int config_parse_target( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - assert(filename); - assert(lvalue); - assert(rvalue); - - log_set_target_from_string(rvalue); - return 0; -} - -static int config_parse_color( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - assert(filename); - assert(lvalue); - assert(rvalue); - - log_show_color_from_string(rvalue); - return 0; -} - -static int config_parse_location( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - assert(filename); - assert(lvalue); - assert(rvalue); - - log_show_location_from_string(rvalue); - return 0; -} - -static int config_parse_cpu_affinity2( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char *w; - size_t l; - char *state; - cpu_set_t *c = NULL; - unsigned ncpus = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t; - int r; - unsigned cpu; - - if (!(t = strndup(w, l))) - return -ENOMEM; - - r = safe_atou(t, &cpu); - free(t); - - if (!c) - if (!(c = cpu_set_malloc(&ncpus))) - return -ENOMEM; - - if (r < 0 || cpu >= ncpus) { - log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue); - CPU_FREE(c); - return -EBADMSG; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - - if (c) { - if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) - log_warning("Failed to set CPU affinity: %m"); - - CPU_FREE(c); - } - - return 0; -} - -static void strv_free_free(char ***l) { - char ***i; - - if (!l) - return; - - for (i = l; *i; i++) - strv_free(*i); - - free(l); -} - -static void free_join_controllers(void) { - if (!arg_join_controllers) - return; - - strv_free_free(arg_join_controllers); - arg_join_controllers = NULL; -} - -static int config_parse_join_controllers( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - unsigned n = 0; - char *state, *w; - size_t length; - - assert(filename); - assert(lvalue); - assert(rvalue); - - free_join_controllers(); - - FOREACH_WORD_QUOTED(w, length, rvalue, state) { - char *s, **l; - - s = strndup(w, length); - if (!s) - return -ENOMEM; - - l = strv_split(s, ","); - free(s); - - strv_uniq(l); - - if (strv_length(l) <= 1) { - strv_free(l); - continue; - } - - if (!arg_join_controllers) { - arg_join_controllers = new(char**, 2); - if (!arg_join_controllers) { - strv_free(l); - return -ENOMEM; - } - - arg_join_controllers[0] = l; - arg_join_controllers[1] = NULL; - - n = 1; - } else { - char ***a; - char ***t; - - t = new0(char**, n+2); - if (!t) { - strv_free(l); - return -ENOMEM; - } - - n = 0; - - for (a = arg_join_controllers; *a; a++) { - - if (strv_overlap(*a, l)) { - char **c; - - c = strv_merge(*a, l); - if (!c) { - strv_free(l); - strv_free_free(t); - return -ENOMEM; - } - - strv_free(l); - l = c; - } else { - char **c; - - c = strv_copy(*a); - if (!c) { - strv_free(l); - strv_free_free(t); - return -ENOMEM; - } - - t[n++] = c; - } - } - - t[n++] = strv_uniq(l); - - strv_free_free(arg_join_controllers); - arg_join_controllers = t; - } - } - - return 0; -} - -static int parse_config_file(void) { - - const ConfigTableItem items[] = { - { "Manager", "LogLevel", config_parse_level2, 0, NULL }, - { "Manager", "LogTarget", config_parse_target, 0, NULL }, - { "Manager", "LogColor", config_parse_color, 0, NULL }, - { "Manager", "LogLocation", config_parse_location, 0, NULL }, - { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, - { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, - { "Manager", "ShowStatus", config_parse_bool, 0, &arg_show_status }, -#ifdef HAVE_SYSV_COMPAT - { "Manager", "SysVConsole", config_parse_bool, 0, &arg_sysv_console }, -#endif - { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, - { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, - { "Manager", "MountAuto", config_parse_bool, 0, &arg_mount_auto }, - { "Manager", "SwapAuto", config_parse_bool, 0, &arg_swap_auto }, - { "Manager", "DefaultControllers", config_parse_strv, 0, &arg_default_controllers }, - { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output }, - { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error }, - { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, - { NULL, NULL, NULL, 0, NULL } - }; - - FILE *f; - const char *fn; - int r; - - fn = arg_running_as == MANAGER_SYSTEM ? SYSTEM_CONFIG_FILE : USER_CONFIG_FILE; - f = fopen(fn, "re"); - if (!f) { - if (errno == ENOENT) - return 0; - - log_warning("Failed to open configuration file '%s': %m", fn); - return 0; - } - - r = config_parse(fn, f, "Manager\0", config_item_table_lookup, (void*) items, false, NULL); - if (r < 0) - log_warning("Failed to parse configuration file: %s", strerror(-r)); - - fclose(f); - - return 0; -} - -static int parse_proc_cmdline(void) { - char *line, *w, *state; - int r; - size_t l; - - /* Don't read /proc/cmdline if we are in a container, since - * that is only relevant for the host system */ - if (detect_container(NULL) > 0) - return 0; - - if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) { - log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); - return 0; - } - - FOREACH_WORD_QUOTED(w, l, line, state) { - char *word; - - if (!(word = strndup(w, l))) { - r = -ENOMEM; - goto finish; - } - - r = parse_proc_cmdline_word(word); - free(word); - - if (r < 0) - goto finish; - } - - r = 0; - -finish: - free(line); - return r; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_LOG_LEVEL = 0x100, - ARG_LOG_TARGET, - ARG_LOG_COLOR, - ARG_LOG_LOCATION, - ARG_UNIT, - ARG_SYSTEM, - ARG_USER, - ARG_TEST, - ARG_DUMP_CONFIGURATION_ITEMS, - ARG_DUMP_CORE, - ARG_CRASH_SHELL, - ARG_CONFIRM_SPAWN, - ARG_SHOW_STATUS, - ARG_SYSV_CONSOLE, - ARG_DESERIALIZE, - ARG_INTROSPECT, - ARG_DEFAULT_STD_OUTPUT, - ARG_DEFAULT_STD_ERROR - }; - - static const struct option options[] = { - { "log-level", required_argument, NULL, ARG_LOG_LEVEL }, - { "log-target", required_argument, NULL, ARG_LOG_TARGET }, - { "log-color", optional_argument, NULL, ARG_LOG_COLOR }, - { "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, - { "unit", required_argument, NULL, ARG_UNIT }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "user", no_argument, NULL, ARG_USER }, - { "test", no_argument, NULL, ARG_TEST }, - { "help", no_argument, NULL, 'h' }, - { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, - { "dump-core", no_argument, NULL, ARG_DUMP_CORE }, - { "crash-shell", no_argument, NULL, ARG_CRASH_SHELL }, - { "confirm-spawn", no_argument, NULL, ARG_CONFIRM_SPAWN }, - { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, -#ifdef HAVE_SYSV_COMPAT - { "sysv-console", optional_argument, NULL, ARG_SYSV_CONSOLE }, -#endif - { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, - { "introspect", optional_argument, NULL, ARG_INTROSPECT }, - { "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, }, - { "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, }, - { NULL, 0, NULL, 0 } - }; - - int c, r; - - assert(argc >= 1); - assert(argv); - - if (getpid() == 1) - opterr = 0; - - while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0) - - switch (c) { - - case ARG_LOG_LEVEL: - if ((r = log_set_max_level_from_string(optarg)) < 0) { - log_error("Failed to parse log level %s.", optarg); - return r; - } - - break; - - case ARG_LOG_TARGET: - - if ((r = log_set_target_from_string(optarg)) < 0) { - log_error("Failed to parse log target %s.", optarg); - return r; - } - - break; - - case ARG_LOG_COLOR: - - if (optarg) { - if ((r = log_show_color_from_string(optarg)) < 0) { - log_error("Failed to parse log color setting %s.", optarg); - return r; - } - } else - log_show_color(true); - - break; - - case ARG_LOG_LOCATION: - - if (optarg) { - if ((r = log_show_location_from_string(optarg)) < 0) { - log_error("Failed to parse log location setting %s.", optarg); - return r; - } - } else - log_show_location(true); - - break; - - case ARG_DEFAULT_STD_OUTPUT: - - if ((r = exec_output_from_string(optarg)) < 0) { - log_error("Failed to parse default standard output setting %s.", optarg); - return r; - } else - arg_default_std_output = r; - break; - - case ARG_DEFAULT_STD_ERROR: - - if ((r = exec_output_from_string(optarg)) < 0) { - log_error("Failed to parse default standard error output setting %s.", optarg); - return r; - } else - arg_default_std_error = r; - break; - - case ARG_UNIT: - - if ((r = set_default_unit(optarg)) < 0) { - log_error("Failed to set default unit %s: %s", optarg, strerror(-r)); - return r; - } - - break; - - case ARG_SYSTEM: - arg_running_as = MANAGER_SYSTEM; - break; - - case ARG_USER: - arg_running_as = MANAGER_USER; - break; - - case ARG_TEST: - arg_action = ACTION_TEST; - break; - - case ARG_DUMP_CONFIGURATION_ITEMS: - arg_action = ACTION_DUMP_CONFIGURATION_ITEMS; - break; - - case ARG_DUMP_CORE: - arg_dump_core = true; - break; - - case ARG_CRASH_SHELL: - arg_crash_shell = true; - break; - - case ARG_CONFIRM_SPAWN: - arg_confirm_spawn = true; - break; - - case ARG_SHOW_STATUS: - - if (optarg) { - if ((r = parse_boolean(optarg)) < 0) { - log_error("Failed to show status boolean %s.", optarg); - return r; - } - arg_show_status = r; - } else - arg_show_status = true; - break; -#ifdef HAVE_SYSV_COMPAT - case ARG_SYSV_CONSOLE: - - if (optarg) { - if ((r = parse_boolean(optarg)) < 0) { - log_error("Failed to SysV console boolean %s.", optarg); - return r; - } - arg_sysv_console = r; - } else - arg_sysv_console = true; - break; -#endif - - case ARG_DESERIALIZE: { - int fd; - FILE *f; - - if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) { - log_error("Failed to parse deserialize option %s.", optarg); - return r; - } - - if (!(f = fdopen(fd, "r"))) { - log_error("Failed to open serialization fd: %m"); - return r; - } - - if (serialization) - fclose(serialization); - - serialization = f; - - break; - } - - case ARG_INTROSPECT: { - const char * const * i = NULL; - - for (i = bus_interface_table; *i; i += 2) - if (!optarg || streq(i[0], optarg)) { - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", stdout); - fputs(i[1], stdout); - fputs("\n", stdout); - - if (optarg) - break; - } - - if (!i[0] && optarg) - log_error("Unknown interface %s.", optarg); - - arg_action = ACTION_DONE; - break; - } - - case 'h': - arg_action = ACTION_HELP; - break; - - case 'D': - log_set_max_level(LOG_DEBUG); - break; - - case 'b': - case 's': - case 'z': - /* Just to eat away the sysvinit kernel - * cmdline args without getopt() error - * messages that we'll parse in - * parse_proc_cmdline_word() or ignore. */ - - case '?': - default: - if (getpid() != 1) { - log_error("Unknown option code %c", c); - return -EINVAL; - } - - break; - } - - if (optind < argc && getpid() != 1) { - /* Hmm, when we aren't run as init system - * let's complain about excess arguments */ - - log_error("Excess arguments."); - return -EINVAL; - } - - if (detect_container(NULL) > 0) { - char **a; - - /* All /proc/cmdline arguments the kernel didn't - * understand it passed to us. We're not really - * interested in that usually since /proc/cmdline is - * more interesting and complete. With one exception: - * if we are run in a container /proc/cmdline is not - * relevant for the container, hence we rely on argv[] - * instead. */ - - for (a = argv; a < argv + argc; a++) - if ((r = parse_proc_cmdline_word(*a)) < 0) - return r; - } - - return 0; -} - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "Starts up and maintains the system or user services.\n\n" - " -h --help Show this help\n" - " --test Determine startup sequence, dump it and exit\n" - " --dump-configuration-items Dump understood unit configuration items\n" - " --introspect[=INTERFACE] Extract D-Bus interface data\n" - " --unit=UNIT Set default unit\n" - " --system Run a system instance, even if PID != 1\n" - " --user Run a user instance\n" - " --dump-core Dump core on crash\n" - " --crash-shell Run shell on crash\n" - " --confirm-spawn Ask for confirmation when spawning processes\n" - " --show-status[=0|1] Show status updates on the console during bootup\n" -#ifdef HAVE_SYSV_COMPAT - " --sysv-console[=0|1] Connect output of SysV scripts to console\n" -#endif - " --log-target=TARGET Set log target (console, syslog, kmsg, syslog-or-kmsg, null)\n" - " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" - " --log-color[=0|1] Highlight important log messages\n" - " --log-location[=0|1] Include code location in log messages\n" - " --default-standard-output= Set default standard output for services\n" - " --default-standard-error= Set default standard error output for services\n", - program_invocation_short_name); - - return 0; -} - -static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) { - FILE *f = NULL; - FDSet *fds = NULL; - int r; - - assert(m); - assert(_f); - assert(_fds); - - /* Make sure nothing is really destructed when we shut down */ - m->n_reloading ++; - - if ((r = manager_open_serialization(m, &f)) < 0) { - log_error("Failed to create serialization file: %s", strerror(-r)); - goto fail; - } - - if (!(fds = fdset_new())) { - r = -ENOMEM; - log_error("Failed to allocate fd set: %s", strerror(-r)); - goto fail; - } - - if ((r = manager_serialize(m, f, fds)) < 0) { - log_error("Failed to serialize state: %s", strerror(-r)); - goto fail; - } - - if (fseeko(f, 0, SEEK_SET) < 0) { - log_error("Failed to rewind serialization fd: %m"); - goto fail; - } - - if ((r = fd_cloexec(fileno(f), false)) < 0) { - log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r)); - goto fail; - } - - if ((r = fdset_cloexec(fds, false)) < 0) { - log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r)); - goto fail; - } - - *_f = f; - *_fds = fds; - - return 0; - -fail: - fdset_free(fds); - - if (f) - fclose(f); - - return r; -} - -static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) { - const char *e; - unsigned long long a, b; - - assert(t); - - if (!(e = getenv("RD_TIMESTAMP"))) - return NULL; - - if (sscanf(e, "%llu %llu", &a, &b) != 2) - return NULL; - - t->realtime = (usec_t) a; - t->monotonic = (usec_t) b; - - return t; -} - -static void test_mtab(void) { - char *p; - - /* Check that /etc/mtab is a symlink */ - - if (readlink_malloc("/etc/mtab", &p) >= 0) { - bool b; - - b = streq(p, "/proc/self/mounts") || streq(p, "/proc/mounts"); - free(p); - - if (b) - return; - } - - log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " - "This is not supported anymore. " - "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); -} - -static void test_usr(void) { - - /* Check that /usr is not a separate fs */ - - if (dir_is_empty("/usr") <= 0) - return; - - log_warning("/usr appears to be on its own filesytem and is not already mounted. This is not a supported setup. " - "Some things will probably break (sometimes even silently) in mysterious ways. " - "Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information."); -} - -static void test_cgroups(void) { - - if (access("/proc/cgroups", F_OK) >= 0) - return; - - log_warning("CONFIG_CGROUPS was not set when your kernel was compiled. " - "Systems without control groups are not supported. " - "We will now sleep for 10s, and then continue boot-up. " - "Expect breakage and please do not file bugs. " - "Instead fix your kernel and enable CONFIG_CGROUPS." ); - - sleep(10); -} - -int main(int argc, char *argv[]) { - Manager *m = NULL; - int r, retval = EXIT_FAILURE; - usec_t before_startup, after_startup; - char timespan[FORMAT_TIMESPAN_MAX]; - FDSet *fds = NULL; - bool reexecute = false; - const char *shutdown_verb = NULL; - dual_timestamp initrd_timestamp = { 0ULL, 0ULL }; - char systemd[] = "systemd"; - bool is_reexec = false; - int j; - bool loaded_policy = false; - -#ifdef HAVE_SYSV_COMPAT - if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { - /* This is compatibility support for SysV, where - * calling init as a user is identical to telinit. */ - - errno = -ENOENT; - execv(SYSTEMCTL_BINARY_PATH, argv); - log_error("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m"); - return 1; - } -#endif - - /* Determine if this is a reexecution or normal bootup. We do - * the full command line parsing much later, so let's just - * have a quick peek here. */ - - for (j = 1; j < argc; j++) - if (streq(argv[j], "--deserialize")) { - is_reexec = true; - break; - } - - /* If we get started via the /sbin/init symlink then we are - called 'init'. After a subsequent reexecution we are then - called 'systemd'. That is confusing, hence let's call us - systemd right-away. */ - - program_invocation_short_name = systemd; - prctl(PR_SET_NAME, systemd); - saved_argv = argv; - saved_argc = argc; - - log_show_color(isatty(STDERR_FILENO) > 0); - log_show_location(false); - log_set_max_level(LOG_INFO); - - if (getpid() == 1) { - arg_running_as = MANAGER_SYSTEM; - log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_SYSLOG_OR_KMSG); - - if (!is_reexec) - if (selinux_setup(&loaded_policy) < 0) - goto finish; - - log_open(); - - if (label_init() < 0) - goto finish; - - if (!is_reexec) - if (hwclock_is_localtime() > 0) { - int min; - - r = hwclock_apply_localtime_delta(&min); - if (r < 0) - log_error("Failed to apply local time delta, ignoring: %s", strerror(-r)); - else - log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); - } - - } else { - arg_running_as = MANAGER_USER; - log_set_target(LOG_TARGET_AUTO); - log_open(); - } - - /* Initialize default unit */ - if (set_default_unit(SPECIAL_DEFAULT_TARGET) < 0) - goto finish; - - /* By default, mount "cpu" and "cpuacct" together */ - arg_join_controllers = new(char**, 2); - if (!arg_join_controllers) - goto finish; - - arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL); - arg_join_controllers[1] = NULL; - - if (!arg_join_controllers[0]) - goto finish; - - /* Mount /proc, /sys and friends, so that /proc/cmdline and - * /proc/$PID/fd is available. */ - if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS")) { - r = mount_setup(loaded_policy); - if (r < 0) - goto finish; - } - - /* Reset all signal handlers. */ - assert_se(reset_all_signal_handlers() == 0); - - /* If we are init, we can block sigkill. Yay. */ - ignore_signals(SIGNALS_IGNORE, -1); - - if (parse_config_file() < 0) - goto finish; - - if (arg_running_as == MANAGER_SYSTEM) - if (parse_proc_cmdline() < 0) - goto finish; - - log_parse_environment(); - - if (parse_argv(argc, argv) < 0) - goto finish; - - if (arg_action == ACTION_TEST && geteuid() == 0) { - log_error("Don't run test mode as root."); - goto finish; - } - - if (arg_running_as == MANAGER_SYSTEM && - arg_action == ACTION_RUN && - running_in_chroot() > 0) { - log_error("Cannot be run in a chroot() environment."); - goto finish; - } - - if (arg_action == ACTION_HELP) { - retval = help(); - goto finish; - } else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) { - unit_dump_config_items(stdout); - retval = EXIT_SUCCESS; - goto finish; - } else if (arg_action == ACTION_DONE) { - retval = EXIT_SUCCESS; - goto finish; - } - - assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST); - - /* Close logging fds, in order not to confuse fdset below */ - log_close(); - - /* Remember open file descriptors for later deserialization */ - if (serialization) { - if ((r = fdset_new_fill(&fds)) < 0) { - log_error("Failed to allocate fd set: %s", strerror(-r)); - goto finish; - } - - assert_se(fdset_remove(fds, fileno(serialization)) >= 0); - } else - close_all_fds(NULL, 0); - - /* Set up PATH unless it is already set */ - setenv("PATH", - "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - arg_running_as == MANAGER_SYSTEM); - - if (arg_running_as == MANAGER_SYSTEM) { - /* Parse the data passed to us by the initrd and unset it */ - parse_initrd_timestamp(&initrd_timestamp); - filter_environ("RD_"); - - /* Unset some environment variables passed in from the - * kernel that don't really make sense for us. */ - unsetenv("HOME"); - unsetenv("TERM"); - - /* All other variables are left as is, so that clients - * can still read them via /proc/1/environ */ - } - - /* Move out of the way, so that we won't block unmounts */ - assert_se(chdir("/") == 0); - - if (arg_running_as == MANAGER_SYSTEM) { - /* Become a session leader if we aren't one yet. */ - setsid(); - - /* Disable the umask logic */ - umask(0); - } - - /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */ - dbus_connection_set_change_sigpipe(FALSE); - - /* Reset the console, but only if this is really init and we - * are freshly booted */ - if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) { - console_setup(getpid() == 1 && !is_reexec); - make_null_stdio(); - } - - /* Open the logging devices, if possible and necessary */ - log_open(); - - /* Make sure we leave a core dump without panicing the - * kernel. */ - if (getpid() == 1) - install_crash_handler(); - - if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS")) { - r = mount_cgroup_controllers(arg_join_controllers); - if (r < 0) - goto finish; - } - - log_full(arg_running_as == MANAGER_SYSTEM ? LOG_INFO : LOG_DEBUG, - PACKAGE_STRING " running in %s mode. (" SYSTEMD_FEATURES "; " DISTRIBUTION ")", manager_running_as_to_string(arg_running_as)); - - if (arg_running_as == MANAGER_SYSTEM && !is_reexec) { - locale_setup(); - - if (arg_show_status || plymouth_running()) - status_welcome(); - - kmod_setup(); - hostname_setup(); - machine_id_setup(); - loopback_setup(); - - test_mtab(); - test_usr(); - test_cgroups(); - } - - if ((r = manager_new(arg_running_as, &m)) < 0) { - log_error("Failed to allocate manager object: %s", strerror(-r)); - goto finish; - } - - m->confirm_spawn = arg_confirm_spawn; -#ifdef HAVE_SYSV_COMPAT - m->sysv_console = arg_sysv_console; -#endif - m->mount_auto = arg_mount_auto; - m->swap_auto = arg_swap_auto; - m->default_std_output = arg_default_std_output; - m->default_std_error = arg_default_std_error; - - if (dual_timestamp_is_set(&initrd_timestamp)) - m->initrd_timestamp = initrd_timestamp; - - if (arg_default_controllers) - manager_set_default_controllers(m, arg_default_controllers); - - manager_set_show_status(m, arg_show_status); - - before_startup = now(CLOCK_MONOTONIC); - - if ((r = manager_startup(m, serialization, fds)) < 0) - log_error("Failed to fully start up daemon: %s", strerror(-r)); - - if (fds) { - /* This will close all file descriptors that were opened, but - * not claimed by any unit. */ - - fdset_free(fds); - fds = NULL; - } - - if (serialization) { - fclose(serialization); - serialization = NULL; - } else { - DBusError error; - Unit *target = NULL; - - dbus_error_init(&error); - - log_debug("Activating default unit: %s", arg_default_unit); - - if ((r = manager_load_unit(m, arg_default_unit, NULL, &error, &target)) < 0) { - log_error("Failed to load default target: %s", bus_error(&error, r)); - dbus_error_free(&error); - } else if (target->meta.load_state == UNIT_ERROR) - log_error("Failed to load default target: %s", strerror(-target->meta.load_error)); - else if (target->meta.load_state == UNIT_MASKED) - log_error("Default target masked."); - - if (!target || target->meta.load_state != UNIT_LOADED) { - log_info("Trying to load rescue target..."); - - if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target)) < 0) { - log_error("Failed to load rescue target: %s", bus_error(&error, r)); - dbus_error_free(&error); - goto finish; - } else if (target->meta.load_state == UNIT_ERROR) { - log_error("Failed to load rescue target: %s", strerror(-target->meta.load_error)); - goto finish; - } else if (target->meta.load_state == UNIT_MASKED) { - log_error("Rescue target masked."); - goto finish; - } - } - - assert(target->meta.load_state == UNIT_LOADED); - - if (arg_action == ACTION_TEST) { - printf("-> By units:\n"); - manager_dump_units(m, stdout, "\t"); - } - - if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, NULL)) < 0) { - log_error("Failed to start default target: %s", bus_error(&error, r)); - dbus_error_free(&error); - goto finish; - } - - after_startup = now(CLOCK_MONOTONIC); - log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG, - "Loaded units and determined initial transaction in %s.", - format_timespan(timespan, sizeof(timespan), after_startup - before_startup)); - - if (arg_action == ACTION_TEST) { - printf("-> By jobs:\n"); - manager_dump_jobs(m, stdout, "\t"); - retval = EXIT_SUCCESS; - goto finish; - } - } - - for (;;) { - if ((r = manager_loop(m)) < 0) { - log_error("Failed to run mainloop: %s", strerror(-r)); - goto finish; - } - - switch (m->exit_code) { - - case MANAGER_EXIT: - retval = EXIT_SUCCESS; - log_debug("Exit."); - goto finish; - - case MANAGER_RELOAD: - log_info("Reloading."); - if ((r = manager_reload(m)) < 0) - log_error("Failed to reload: %s", strerror(-r)); - break; - - case MANAGER_REEXECUTE: - if (prepare_reexecute(m, &serialization, &fds) < 0) - goto finish; - - reexecute = true; - log_notice("Reexecuting."); - goto finish; - - case MANAGER_REBOOT: - case MANAGER_POWEROFF: - case MANAGER_HALT: - case MANAGER_KEXEC: { - static const char * const table[_MANAGER_EXIT_CODE_MAX] = { - [MANAGER_REBOOT] = "reboot", - [MANAGER_POWEROFF] = "poweroff", - [MANAGER_HALT] = "halt", - [MANAGER_KEXEC] = "kexec" - }; - - assert_se(shutdown_verb = table[m->exit_code]); - - log_notice("Shutting down."); - goto finish; - } - - default: - assert_not_reached("Unknown exit code."); - } - } - -finish: - if (m) - manager_free(m); - - free(arg_default_unit); - strv_free(arg_default_controllers); - free_join_controllers(); - - dbus_shutdown(); - - label_finish(); - - if (reexecute) { - const char *args[15]; - unsigned i = 0; - char sfd[16]; - - assert(serialization); - assert(fds); - - args[i++] = SYSTEMD_BINARY_PATH; - - args[i++] = "--log-level"; - args[i++] = log_level_to_string(log_get_max_level()); - - args[i++] = "--log-target"; - args[i++] = log_target_to_string(log_get_target()); - - if (arg_running_as == MANAGER_SYSTEM) - args[i++] = "--system"; - else - args[i++] = "--user"; - - if (arg_dump_core) - args[i++] = "--dump-core"; - - if (arg_crash_shell) - args[i++] = "--crash-shell"; - - if (arg_confirm_spawn) - args[i++] = "--confirm-spawn"; - - if (arg_show_status) - args[i++] = "--show-status=1"; - else - args[i++] = "--show-status=0"; - -#ifdef HAVE_SYSV_COMPAT - if (arg_sysv_console) - args[i++] = "--sysv-console=1"; - else - args[i++] = "--sysv-console=0"; -#endif - - snprintf(sfd, sizeof(sfd), "%i", fileno(serialization)); - char_array_0(sfd); - - args[i++] = "--deserialize"; - args[i++] = sfd; - - args[i++] = NULL; - - assert(i <= ELEMENTSOF(args)); - - execv(args[0], (char* const*) args); - - log_error("Failed to reexecute: %m"); - } - - if (serialization) - fclose(serialization); - - if (fds) - fdset_free(fds); - - if (shutdown_verb) { - const char * command_line[] = { - SYSTEMD_SHUTDOWN_BINARY_PATH, - shutdown_verb, - NULL - }; - - execv(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line); - log_error("Failed to execute shutdown binary, freezing: %m"); - } - - if (getpid() == 1) - freeze(); - - return retval; -} diff --git a/src/manager.c b/src/manager.c deleted file mode 100644 index e626347..0000000 --- a/src/manager.c +++ /dev/null @@ -1,3174 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_AUDIT -#include -#endif - -#include "manager.h" -#include "hashmap.h" -#include "macro.h" -#include "strv.h" -#include "log.h" -#include "util.h" -#include "ratelimit.h" -#include "cgroup.h" -#include "mount-setup.h" -#include "unit-name.h" -#include "dbus-unit.h" -#include "dbus-job.h" -#include "missing.h" -#include "path-lookup.h" -#include "special.h" -#include "bus-errors.h" -#include "exit-status.h" -#include "sd-daemon.h" -#include "virt.h" - -/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ -#define GC_QUEUE_ENTRIES_MAX 16 - -/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */ -#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC) - -/* Where clients shall send notification messages to */ -#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify" -#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify" - -static int manager_setup_notify(Manager *m) { - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - struct epoll_event ev; - int one = 1, r; - mode_t u; - - assert(m); - - m->notify_watch.type = WATCH_NOTIFY; - if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("Failed to allocate notification socket: %m"); - return -errno; - } - - zero(sa); - sa.sa.sa_family = AF_UNIX; - - if (getpid() != 1) - snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull()); - else { - unlink(NOTIFY_SOCKET_SYSTEM); - strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path)); - } - - if (sa.un.sun_path[0] == '@') - sa.un.sun_path[0] = 0; - - u = umask(0111); - r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); - umask(u); - - if (r < 0) { - log_error("bind() failed: %m"); - return -errno; - } - - if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - log_error("SO_PASSCRED failed: %m"); - return -errno; - } - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = &m->notify_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0) - return -errno; - - if (sa.un.sun_path[0] == 0) - sa.un.sun_path[0] = '@'; - - if (!(m->notify_socket = strdup(sa.un.sun_path))) - return -ENOMEM; - - log_debug("Using notification socket %s", m->notify_socket); - - return 0; -} - -static int enable_special_signals(Manager *m) { - int fd; - - assert(m); - - /* Enable that we get SIGINT on control-alt-del */ - if (reboot(RB_DISABLE_CAD) < 0) - log_warning("Failed to enable ctrl-alt-del handling: %m"); - - if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) - log_warning("Failed to open /dev/tty0: %m"); - else { - /* Enable that we get SIGWINCH on kbrequest */ - if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0) - log_warning("Failed to enable kbrequest handling: %s", strerror(errno)); - - close_nointr_nofail(fd); - } - - return 0; -} - -static int manager_setup_signals(Manager *m) { - sigset_t mask; - struct epoll_event ev; - struct sigaction sa; - - assert(m); - - /* We are not interested in SIGSTOP and friends. */ - zero(sa); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_NOCLDSTOP|SA_RESTART; - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); - - assert_se(sigemptyset(&mask) == 0); - - sigset_add_many(&mask, - SIGCHLD, /* Child died */ - SIGTERM, /* Reexecute daemon */ - SIGHUP, /* Reload configuration */ - SIGUSR1, /* systemd/upstart: reconnect to D-Bus */ - SIGUSR2, /* systemd: dump status */ - SIGINT, /* Kernel sends us this on control-alt-del */ - SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */ - SIGPWR, /* Some kernel drivers and upsd send us this on power failure */ - SIGRTMIN+0, /* systemd: start default.target */ - SIGRTMIN+1, /* systemd: isolate rescue.target */ - SIGRTMIN+2, /* systemd: isolate emergency.target */ - SIGRTMIN+3, /* systemd: start halt.target */ - SIGRTMIN+4, /* systemd: start poweroff.target */ - SIGRTMIN+5, /* systemd: start reboot.target */ - SIGRTMIN+6, /* systemd: start kexec.target */ - SIGRTMIN+13, /* systemd: Immediate halt */ - SIGRTMIN+14, /* systemd: Immediate poweroff */ - SIGRTMIN+15, /* systemd: Immediate reboot */ - SIGRTMIN+16, /* systemd: Immediate kexec */ - SIGRTMIN+20, /* systemd: enable status messages */ - SIGRTMIN+21, /* systemd: disable status messages */ - SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */ - SIGRTMIN+23, /* systemd: set log level to LOG_INFO */ - SIGRTMIN+27, /* systemd: set log target to console */ - SIGRTMIN+28, /* systemd: set log target to kmsg */ - SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */ - -1); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - m->signal_watch.type = WATCH_SIGNAL; - if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) - return -errno; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = &m->signal_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) - return -errno; - - if (m->running_as == MANAGER_SYSTEM) - return enable_special_signals(m); - - return 0; -} - -int manager_new(ManagerRunningAs running_as, Manager **_m) { - Manager *m; - int r = -ENOMEM; - - assert(_m); - assert(running_as >= 0); - assert(running_as < _MANAGER_RUNNING_AS_MAX); - - if (!(m = new0(Manager, 1))) - return -ENOMEM; - - dual_timestamp_get(&m->startup_timestamp); - - m->running_as = running_as; - m->name_data_slot = m->subscribed_data_slot = -1; - m->exit_code = _MANAGER_EXIT_CODE_INVALID; - m->pin_cgroupfs_fd = -1; - -#ifdef HAVE_AUDIT - m->audit_fd = -1; -#endif - - m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1; - m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ - - if (!(m->environment = strv_copy(environ))) - goto fail; - - if (!(m->default_controllers = strv_new("cpu", NULL))) - goto fail; - - if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) - goto fail; - - if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) - goto fail; - - if (!(m->transaction_jobs = hashmap_new(trivial_hash_func, trivial_compare_func))) - goto fail; - - if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func))) - goto fail; - - if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func))) - goto fail; - - if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func))) - goto fail; - - if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) - goto fail; - - if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) - goto fail; - - if ((r = manager_setup_signals(m)) < 0) - goto fail; - - if ((r = manager_setup_cgroup(m)) < 0) - goto fail; - - if ((r = manager_setup_notify(m)) < 0) - goto fail; - - /* Try to connect to the busses, if possible. */ - if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0) - goto fail; - -#ifdef HAVE_AUDIT - if ((m->audit_fd = audit_open()) < 0) - log_error("Failed to connect to audit log: %m"); -#endif - - m->taint_usr = dir_is_empty("/usr") > 0; - - *_m = m; - return 0; - -fail: - manager_free(m); - return r; -} - -static unsigned manager_dispatch_cleanup_queue(Manager *m) { - Meta *meta; - unsigned n = 0; - - assert(m); - - while ((meta = m->cleanup_queue)) { - assert(meta->in_cleanup_queue); - - unit_free((Unit*) meta); - n++; - } - - return n; -} - -enum { - GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */ - GC_OFFSET_UNSURE, /* No clue */ - GC_OFFSET_GOOD, /* We still need this unit */ - GC_OFFSET_BAD, /* We don't need this unit anymore */ - _GC_OFFSET_MAX -}; - -static void unit_gc_sweep(Unit *u, unsigned gc_marker) { - Iterator i; - Unit *other; - bool is_bad; - - assert(u); - - if (u->meta.gc_marker == gc_marker + GC_OFFSET_GOOD || - u->meta.gc_marker == gc_marker + GC_OFFSET_BAD || - u->meta.gc_marker == gc_marker + GC_OFFSET_IN_PATH) - return; - - if (u->meta.in_cleanup_queue) - goto bad; - - if (unit_check_gc(u)) - goto good; - - u->meta.gc_marker = gc_marker + GC_OFFSET_IN_PATH; - - is_bad = true; - - SET_FOREACH(other, u->meta.dependencies[UNIT_REFERENCED_BY], i) { - unit_gc_sweep(other, gc_marker); - - if (other->meta.gc_marker == gc_marker + GC_OFFSET_GOOD) - goto good; - - if (other->meta.gc_marker != gc_marker + GC_OFFSET_BAD) - is_bad = false; - } - - if (is_bad) - goto bad; - - /* We were unable to find anything out about this entry, so - * let's investigate it later */ - u->meta.gc_marker = gc_marker + GC_OFFSET_UNSURE; - unit_add_to_gc_queue(u); - return; - -bad: - /* We definitely know that this one is not useful anymore, so - * let's mark it for deletion */ - u->meta.gc_marker = gc_marker + GC_OFFSET_BAD; - unit_add_to_cleanup_queue(u); - return; - -good: - u->meta.gc_marker = gc_marker + GC_OFFSET_GOOD; -} - -static unsigned manager_dispatch_gc_queue(Manager *m) { - Meta *meta; - unsigned n = 0; - unsigned gc_marker; - - assert(m); - - if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) && - (m->gc_queue_timestamp <= 0 || - (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC))) - return 0; - - log_debug("Running GC..."); - - m->gc_marker += _GC_OFFSET_MAX; - if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX) - m->gc_marker = 1; - - gc_marker = m->gc_marker; - - while ((meta = m->gc_queue)) { - assert(meta->in_gc_queue); - - unit_gc_sweep((Unit*) meta, gc_marker); - - LIST_REMOVE(Meta, gc_queue, m->gc_queue, meta); - meta->in_gc_queue = false; - - n++; - - if (meta->gc_marker == gc_marker + GC_OFFSET_BAD || - meta->gc_marker == gc_marker + GC_OFFSET_UNSURE) { - log_debug("Collecting %s", meta->id); - meta->gc_marker = gc_marker + GC_OFFSET_BAD; - unit_add_to_cleanup_queue((Unit*) meta); - } - } - - m->n_in_gc_queue = 0; - m->gc_queue_timestamp = 0; - - return n; -} - -static void manager_clear_jobs_and_units(Manager *m) { - Job *j; - Unit *u; - - assert(m); - - while ((j = hashmap_first(m->transaction_jobs))) - job_free(j); - - while ((u = hashmap_first(m->units))) - unit_free(u); - - manager_dispatch_cleanup_queue(m); - - assert(!m->load_queue); - assert(!m->run_queue); - assert(!m->dbus_unit_queue); - assert(!m->dbus_job_queue); - assert(!m->cleanup_queue); - assert(!m->gc_queue); - - assert(hashmap_isempty(m->transaction_jobs)); - assert(hashmap_isempty(m->jobs)); - assert(hashmap_isempty(m->units)); -} - -void manager_free(Manager *m) { - UnitType c; - - assert(m); - - manager_clear_jobs_and_units(m); - - for (c = 0; c < _UNIT_TYPE_MAX; c++) - if (unit_vtable[c]->shutdown) - unit_vtable[c]->shutdown(m); - - /* If we reexecute ourselves, we keep the root cgroup - * around */ - manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE); - - manager_undo_generators(m); - - bus_done(m); - - hashmap_free(m->units); - hashmap_free(m->jobs); - hashmap_free(m->transaction_jobs); - hashmap_free(m->watch_pids); - hashmap_free(m->watch_bus); - - if (m->epoll_fd >= 0) - close_nointr_nofail(m->epoll_fd); - if (m->signal_watch.fd >= 0) - close_nointr_nofail(m->signal_watch.fd); - if (m->notify_watch.fd >= 0) - close_nointr_nofail(m->notify_watch.fd); - -#ifdef HAVE_AUDIT - if (m->audit_fd >= 0) - audit_close(m->audit_fd); -#endif - - free(m->notify_socket); - - lookup_paths_free(&m->lookup_paths); - strv_free(m->environment); - - strv_free(m->default_controllers); - - hashmap_free(m->cgroup_bondings); - set_free_free(m->unit_path_cache); - - free(m); -} - -int manager_enumerate(Manager *m) { - int r = 0, q; - UnitType c; - - assert(m); - - /* Let's ask every type to load all units from disk/kernel - * that it might know */ - for (c = 0; c < _UNIT_TYPE_MAX; c++) - if (unit_vtable[c]->enumerate) - if ((q = unit_vtable[c]->enumerate(m)) < 0) - r = q; - - manager_dispatch_load_queue(m); - return r; -} - -int manager_coldplug(Manager *m) { - int r = 0, q; - Iterator i; - Unit *u; - char *k; - - assert(m); - - /* Then, let's set up their initial state. */ - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - - /* ignore aliases */ - if (u->meta.id != k) - continue; - - if ((q = unit_coldplug(u)) < 0) - r = q; - } - - return r; -} - -static void manager_build_unit_path_cache(Manager *m) { - char **i; - DIR *d = NULL; - int r; - - assert(m); - - set_free_free(m->unit_path_cache); - - if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) { - log_error("Failed to allocate unit path cache."); - return; - } - - /* This simply builds a list of files we know exist, so that - * we don't always have to go to disk */ - - STRV_FOREACH(i, m->lookup_paths.unit_path) { - struct dirent *de; - - if (!(d = opendir(*i))) { - log_error("Failed to open directory: %m"); - continue; - } - - while ((de = readdir(d))) { - char *p; - - if (ignore_file(de->d_name)) - continue; - - p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); - if (!p) { - r = -ENOMEM; - goto fail; - } - - if ((r = set_put(m->unit_path_cache, p)) < 0) { - free(p); - goto fail; - } - } - - closedir(d); - d = NULL; - } - - return; - -fail: - log_error("Failed to build unit path cache: %s", strerror(-r)); - - set_free_free(m->unit_path_cache); - m->unit_path_cache = NULL; - - if (d) - closedir(d); -} - -int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - int r, q; - - assert(m); - - manager_run_generators(m); - - manager_build_unit_path_cache(m); - - /* If we will deserialize make sure that during enumeration - * this is already known, so we increase the counter here - * already */ - if (serialization) - m->n_reloading ++; - - /* First, enumerate what we can from all config files */ - r = manager_enumerate(m); - - /* Second, deserialize if there is something to deserialize */ - if (serialization) - if ((q = manager_deserialize(m, serialization, fds)) < 0) - r = q; - - /* Third, fire things up! */ - if ((q = manager_coldplug(m)) < 0) - r = q; - - if (serialization) { - assert(m->n_reloading > 0); - m->n_reloading --; - } - - return r; -} - -static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) { - assert(m); - assert(j); - - /* Deletes one job from the transaction */ - - manager_transaction_unlink_job(m, j, delete_dependencies); - - if (!j->installed) - job_free(j); -} - -static void transaction_delete_unit(Manager *m, Unit *u) { - Job *j; - - /* Deletes all jobs associated with a certain unit from the - * transaction */ - - while ((j = hashmap_get(m->transaction_jobs, u))) - transaction_delete_job(m, j, true); -} - -static void transaction_clean_dependencies(Manager *m) { - Iterator i; - Job *j; - - assert(m); - - /* Drops all dependencies of all installed jobs */ - - HASHMAP_FOREACH(j, m->jobs, i) { - while (j->subject_list) - job_dependency_free(j->subject_list); - while (j->object_list) - job_dependency_free(j->object_list); - } - - assert(!m->transaction_anchor); -} - -static void transaction_abort(Manager *m) { - Job *j; - - assert(m); - - while ((j = hashmap_first(m->transaction_jobs))) - if (j->installed) - transaction_delete_job(m, j, true); - else - job_free(j); - - assert(hashmap_isempty(m->transaction_jobs)); - - transaction_clean_dependencies(m); -} - -static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) { - JobDependency *l; - - assert(m); - - /* A recursive sweep through the graph that marks all units - * that matter to the anchor job, i.e. are directly or - * indirectly a dependency of the anchor job via paths that - * are fully marked as mattering. */ - - if (j) - l = j->subject_list; - else - l = m->transaction_anchor; - - LIST_FOREACH(subject, l, l) { - - /* This link does not matter */ - if (!l->matters) - continue; - - /* This unit has already been marked */ - if (l->object->generation == generation) - continue; - - l->object->matters_to_anchor = true; - l->object->generation = generation; - - transaction_find_jobs_that_matter_to_anchor(m, l->object, generation); - } -} - -static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, JobType t) { - JobDependency *l, *last; - - assert(j); - assert(other); - assert(j->unit == other->unit); - assert(!j->installed); - - /* Merges 'other' into 'j' and then deletes j. */ - - j->type = t; - j->state = JOB_WAITING; - j->override = j->override || other->override; - - j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor; - - /* Patch us in as new owner of the JobDependency objects */ - last = NULL; - LIST_FOREACH(subject, l, other->subject_list) { - assert(l->subject == other); - l->subject = j; - last = l; - } - - /* Merge both lists */ - if (last) { - last->subject_next = j->subject_list; - if (j->subject_list) - j->subject_list->subject_prev = last; - j->subject_list = other->subject_list; - } - - /* Patch us in as new owner of the JobDependency objects */ - last = NULL; - LIST_FOREACH(object, l, other->object_list) { - assert(l->object == other); - l->object = j; - last = l; - } - - /* Merge both lists */ - if (last) { - last->object_next = j->object_list; - if (j->object_list) - j->object_list->object_prev = last; - j->object_list = other->object_list; - } - - /* Kill the other job */ - other->subject_list = NULL; - other->object_list = NULL; - transaction_delete_job(m, other, true); -} -static bool job_is_conflicted_by(Job *j) { - JobDependency *l; - - assert(j); - - /* Returns true if this job is pulled in by a least one - * ConflictedBy dependency. */ - - LIST_FOREACH(object, l, j->object_list) - if (l->conflicts) - return true; - - return false; -} - -static int delete_one_unmergeable_job(Manager *m, Job *j) { - Job *k; - - assert(j); - - /* Tries to delete one item in the linked list - * j->transaction_next->transaction_next->... that conflicts - * with another one, in an attempt to make an inconsistent - * transaction work. */ - - /* We rely here on the fact that if a merged with b does not - * merge with c, either a or b merge with c neither */ - LIST_FOREACH(transaction, j, j) - LIST_FOREACH(transaction, k, j->transaction_next) { - Job *d; - - /* Is this one mergeable? Then skip it */ - if (job_type_is_mergeable(j->type, k->type)) - continue; - - /* Ok, we found two that conflict, let's see if we can - * drop one of them */ - if (!j->matters_to_anchor && !k->matters_to_anchor) { - - /* Both jobs don't matter, so let's - * find the one that is smarter to - * remove. Let's think positive and - * rather remove stops then starts -- - * except if something is being - * stopped because it is conflicted by - * another unit in which case we - * rather remove the start. */ - - log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j))); - log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->meta.id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k))); - - if (j->type == JOB_STOP) { - - if (job_is_conflicted_by(j)) - d = k; - else - d = j; - - } else if (k->type == JOB_STOP) { - - if (job_is_conflicted_by(k)) - d = j; - else - d = k; - } else - d = j; - - } else if (!j->matters_to_anchor) - d = j; - else if (!k->matters_to_anchor) - d = k; - else - return -ENOEXEC; - - /* Ok, we can drop one, so let's do so. */ - log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type)); - transaction_delete_job(m, d, true); - return 0; - } - - return -EINVAL; -} - -static int transaction_merge_jobs(Manager *m, DBusError *e) { - Job *j; - Iterator i; - int r; - - assert(m); - - /* First step, check whether any of the jobs for one specific - * task conflict. If so, try to drop one of them. */ - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - JobType t; - Job *k; - - t = j->type; - LIST_FOREACH(transaction, k, j->transaction_next) { - if (job_type_merge(&t, k->type) >= 0) - continue; - - /* OK, we could not merge all jobs for this - * action. Let's see if we can get rid of one - * of them */ - - if ((r = delete_one_unmergeable_job(m, j)) >= 0) - /* Ok, we managed to drop one, now - * let's ask our callers to call us - * again after garbage collecting */ - return -EAGAIN; - - /* We couldn't merge anything. Failure */ - dbus_set_error(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, "Transaction contains conflicting jobs '%s' and '%s' for %s. Probably contradicting requirement dependencies configured.", - job_type_to_string(t), job_type_to_string(k->type), k->unit->meta.id); - return r; - } - } - - /* Second step, merge the jobs. */ - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - JobType t = j->type; - Job *k; - - /* Merge all transactions */ - LIST_FOREACH(transaction, k, j->transaction_next) - assert_se(job_type_merge(&t, k->type) == 0); - - /* If an active job is mergeable, merge it too */ - if (j->unit->meta.job) - job_type_merge(&t, j->unit->meta.job->type); /* Might fail. Which is OK */ - - while ((k = j->transaction_next)) { - if (j->installed) { - transaction_merge_and_delete_job(m, k, j, t); - j = k; - } else - transaction_merge_and_delete_job(m, j, k, t); - } - - if (j->unit->meta.job && !j->installed) - transaction_merge_and_delete_job(m, j, j->unit->meta.job, t); - - assert(!j->transaction_next); - assert(!j->transaction_prev); - } - - return 0; -} - -static void transaction_drop_redundant(Manager *m) { - bool again; - - assert(m); - - /* Goes through the transaction and removes all jobs that are - * a noop */ - - do { - Job *j; - Iterator i; - - again = false; - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - bool changes_something = false; - Job *k; - - LIST_FOREACH(transaction, k, j) { - - if (!job_is_anchor(k) && - (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && - (!k->unit->meta.job || !job_type_is_conflicting(k->type, k->unit->meta.job->type))) - continue; - - changes_something = true; - break; - } - - if (changes_something) - continue; - - /* log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type)); */ - transaction_delete_job(m, j, false); - again = true; - break; - } - - } while (again); -} - -static bool unit_matters_to_anchor(Unit *u, Job *j) { - assert(u); - assert(!j->transaction_prev); - - /* Checks whether at least one of the jobs for this unit - * matters to the anchor. */ - - LIST_FOREACH(transaction, j, j) - if (j->matters_to_anchor) - return true; - - return false; -} - -static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned generation, DBusError *e) { - Iterator i; - Unit *u; - int r; - - assert(m); - assert(j); - assert(!j->transaction_prev); - - /* Does a recursive sweep through the ordering graph, looking - * for a cycle. If we find cycle we try to break it. */ - - /* Have we seen this before? */ - if (j->generation == generation) { - Job *k, *delete; - - /* If the marker is NULL we have been here already and - * decided the job was loop-free from here. Hence - * shortcut things and return right-away. */ - if (!j->marker) - return 0; - - /* So, the marker is not NULL and we already have been - * here. We have a cycle. Let's try to break it. We go - * backwards in our path and try to find a suitable - * job to remove. We use the marker to find our way - * back, since smart how we are we stored our way back - * in there. */ - log_warning("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type)); - - delete = NULL; - for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { - - log_info("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type)); - - if (!delete && - !k->installed && - !unit_matters_to_anchor(k->unit, k)) { - /* Ok, we can drop this one, so let's - * do so. */ - delete = k; - } - - /* Check if this in fact was the beginning of - * the cycle */ - if (k == j) - break; - } - - - if (delete) { - log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->meta.id, job_type_to_string(delete->type)); - transaction_delete_unit(m, delete->unit); - return -EAGAIN; - } - - log_error("Unable to break cycle"); - - dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details."); - return -ENOEXEC; - } - - /* Make the marker point to where we come from, so that we can - * find our way backwards if we want to break a cycle. We use - * a special marker for the beginning: we point to - * ourselves. */ - j->marker = from ? from : j; - j->generation = generation; - - /* We assume that the the dependencies are bidirectional, and - * hence can ignore UNIT_AFTER */ - SET_FOREACH(u, j->unit->meta.dependencies[UNIT_BEFORE], i) { - Job *o; - - /* Is there a job for this unit? */ - if (!(o = hashmap_get(m->transaction_jobs, u))) - - /* Ok, there is no job for this in the - * transaction, but maybe there is already one - * running? */ - if (!(o = u->meta.job)) - continue; - - if ((r = transaction_verify_order_one(m, o, j, generation, e)) < 0) - return r; - } - - /* Ok, let's backtrack, and remember that this entry is not on - * our path anymore. */ - j->marker = NULL; - - return 0; -} - -static int transaction_verify_order(Manager *m, unsigned *generation, DBusError *e) { - Job *j; - int r; - Iterator i; - unsigned g; - - assert(m); - assert(generation); - - /* Check if the ordering graph is cyclic. If it is, try to fix - * that up by dropping one of the jobs. */ - - g = (*generation)++; - - HASHMAP_FOREACH(j, m->transaction_jobs, i) - if ((r = transaction_verify_order_one(m, j, NULL, g, e)) < 0) - return r; - - return 0; -} - -static void transaction_collect_garbage(Manager *m) { - bool again; - - assert(m); - - /* Drop jobs that are not required by any other job */ - - do { - Iterator i; - Job *j; - - again = false; - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - if (j->object_list) { - /* log_debug("Keeping job %s/%s because of %s/%s", */ - /* j->unit->meta.id, job_type_to_string(j->type), */ - /* j->object_list->subject ? j->object_list->subject->unit->meta.id : "root", */ - /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */ - continue; - } - - /* log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type)); */ - transaction_delete_job(m, j, true); - again = true; - break; - } - - } while (again); -} - -static int transaction_is_destructive(Manager *m, DBusError *e) { - Iterator i; - Job *j; - - assert(m); - - /* Checks whether applying this transaction means that - * existing jobs would be replaced */ - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - - /* Assume merged */ - assert(!j->transaction_prev); - assert(!j->transaction_next); - - if (j->unit->meta.job && - j->unit->meta.job != j && - !job_type_is_superset(j->type, j->unit->meta.job->type)) { - - dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); - return -EEXIST; - } - } - - return 0; -} - -static void transaction_minimize_impact(Manager *m) { - bool again; - assert(m); - - /* Drops all unnecessary jobs that reverse already active jobs - * or that stop a running service. */ - - do { - Job *j; - Iterator i; - - again = false; - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - LIST_FOREACH(transaction, j, j) { - bool stops_running_service, changes_existing_job; - - /* If it matters, we shouldn't drop it */ - if (j->matters_to_anchor) - continue; - - /* Would this stop a running service? - * Would this change an existing job? - * If so, let's drop this entry */ - - stops_running_service = - j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); - - changes_existing_job = - j->unit->meta.job && - job_type_is_conflicting(j->type, j->unit->meta.job->type); - - if (!stops_running_service && !changes_existing_job) - continue; - - if (stops_running_service) - log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type)); - - if (changes_existing_job) - log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type)); - - /* Ok, let's get rid of this */ - log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type)); - - transaction_delete_job(m, j, true); - again = true; - break; - } - - if (again) - break; - } - - } while (again); -} - -static int transaction_apply(Manager *m, JobMode mode) { - Iterator i; - Job *j; - int r; - - /* Moves the transaction jobs to the set of active jobs */ - - if (mode == JOB_ISOLATE) { - - /* When isolating first kill all installed jobs which - * aren't part of the new transaction */ - HASHMAP_FOREACH(j, m->jobs, i) { - assert(j->installed); - - if (hashmap_get(m->transaction_jobs, j->unit)) - continue; - - job_finish_and_invalidate(j, JOB_CANCELED); - } - } - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - /* Assume merged */ - assert(!j->transaction_prev); - assert(!j->transaction_next); - - if (j->installed) - continue; - - if ((r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j)) < 0) - goto rollback; - } - - while ((j = hashmap_steal_first(m->transaction_jobs))) { - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->meta.id, job_type_to_string(j->type), (unsigned) j->id); */ - continue; - } - - if (j->unit->meta.job) - job_free(j->unit->meta.job); - - j->unit->meta.job = j; - j->installed = true; - m->n_installed_jobs ++; - - /* We're fully installed. Now let's free data we don't - * need anymore. */ - - assert(!j->transaction_next); - assert(!j->transaction_prev); - - job_add_to_run_queue(j); - job_add_to_dbus_queue(j); - job_start_timer(j); - - log_debug("Installed new job %s/%s as %u", j->unit->meta.id, job_type_to_string(j->type), (unsigned) j->id); - } - - /* As last step, kill all remaining job dependencies. */ - transaction_clean_dependencies(m); - - return 0; - -rollback: - - HASHMAP_FOREACH(j, m->transaction_jobs, i) { - if (j->installed) - continue; - - hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); - } - - return r; -} - -static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { - int r; - unsigned generation = 1; - - assert(m); - - /* This applies the changes recorded in transaction_jobs to - * the actual list of jobs, if possible. */ - - /* First step: figure out which jobs matter */ - transaction_find_jobs_that_matter_to_anchor(m, NULL, generation++); - - /* Second step: Try not to stop any running services if - * we don't have to. Don't try to reverse running - * jobs if we don't have to. */ - if (mode == JOB_FAIL) - transaction_minimize_impact(m); - - /* Third step: Drop redundant jobs */ - transaction_drop_redundant(m); - - for (;;) { - /* Fourth step: Let's remove unneeded jobs that might - * be lurking. */ - if (mode != JOB_ISOLATE) - transaction_collect_garbage(m); - - /* Fifth step: verify order makes sense and correct - * cycles if necessary and possible */ - if ((r = transaction_verify_order(m, &generation, e)) >= 0) - break; - - if (r != -EAGAIN) { - log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error(e, r)); - goto rollback; - } - - /* Let's see if the resulting transaction ordering - * graph is still cyclic... */ - } - - for (;;) { - /* Sixth step: let's drop unmergeable entries if - * necessary and possible, merge entries we can - * merge */ - if ((r = transaction_merge_jobs(m, e)) >= 0) - break; - - if (r != -EAGAIN) { - log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r)); - goto rollback; - } - - /* Seventh step: an entry got dropped, let's garbage - * collect its dependencies. */ - if (mode != JOB_ISOLATE) - transaction_collect_garbage(m); - - /* Let's see if the resulting transaction still has - * unmergeable entries ... */ - } - - /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */ - transaction_drop_redundant(m); - - /* Ninth step: check whether we can actually apply this */ - if (mode == JOB_FAIL) - if ((r = transaction_is_destructive(m, e)) < 0) { - log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r)); - goto rollback; - } - - /* Tenth step: apply changes */ - if ((r = transaction_apply(m, mode)) < 0) { - log_warning("Failed to apply transaction: %s", strerror(-r)); - goto rollback; - } - - assert(hashmap_isempty(m->transaction_jobs)); - assert(!m->transaction_anchor); - - return 0; - -rollback: - transaction_abort(m); - return r; -} - -static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) { - Job *j, *f; - - assert(m); - assert(unit); - - /* Looks for an existing prospective job and returns that. If - * it doesn't exist it is created and added to the prospective - * jobs list. */ - - f = hashmap_get(m->transaction_jobs, unit); - - LIST_FOREACH(transaction, j, f) { - assert(j->unit == unit); - - if (j->type == type) { - if (is_new) - *is_new = false; - return j; - } - } - - if (unit->meta.job && unit->meta.job->type == type) - j = unit->meta.job; - else if (!(j = job_new(m, type, unit))) - return NULL; - - j->generation = 0; - j->marker = NULL; - j->matters_to_anchor = false; - j->override = override; - - LIST_PREPEND(Job, transaction, f, j); - - if (hashmap_replace(m->transaction_jobs, unit, f) < 0) { - job_free(j); - return NULL; - } - - if (is_new) - *is_new = true; - - /* log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type)); */ - - return j; -} - -void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) { - assert(m); - assert(j); - - if (j->transaction_prev) - j->transaction_prev->transaction_next = j->transaction_next; - else if (j->transaction_next) - hashmap_replace(m->transaction_jobs, j->unit, j->transaction_next); - else - hashmap_remove_value(m->transaction_jobs, j->unit, j); - - if (j->transaction_next) - j->transaction_next->transaction_prev = j->transaction_prev; - - j->transaction_prev = j->transaction_next = NULL; - - while (j->subject_list) - job_dependency_free(j->subject_list); - - while (j->object_list) { - Job *other = j->object_list->matters ? j->object_list->subject : NULL; - - job_dependency_free(j->object_list); - - if (other && delete_dependencies) { - log_debug("Deleting job %s/%s as dependency of job %s/%s", - other->unit->meta.id, job_type_to_string(other->type), - j->unit->meta.id, job_type_to_string(j->type)); - transaction_delete_job(m, other, delete_dependencies); - } - } -} - -static int transaction_add_job_and_dependencies( - Manager *m, - JobType type, - Unit *unit, - Job *by, - bool matters, - bool override, - bool conflicts, - bool ignore_requirements, - bool ignore_order, - DBusError *e, - Job **_ret) { - Job *ret; - Iterator i; - Unit *dep; - int r; - bool is_new; - - assert(m); - assert(type < _JOB_TYPE_MAX); - assert(unit); - - /* log_debug("Pulling in %s/%s from %s/%s", */ - /* unit->meta.id, job_type_to_string(type), */ - /* by ? by->unit->meta.id : "NA", */ - /* by ? job_type_to_string(by->type) : "NA"); */ - - if (unit->meta.load_state != UNIT_LOADED && - unit->meta.load_state != UNIT_ERROR && - unit->meta.load_state != UNIT_MASKED) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->meta.id); - return -EINVAL; - } - - if (type != JOB_STOP && unit->meta.load_state == UNIT_ERROR) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, - "Unit %s failed to load: %s. " - "See system logs and 'systemctl status %s' for details.", - unit->meta.id, - strerror(-unit->meta.load_error), - unit->meta.id); - return -EINVAL; - } - - if (type != JOB_STOP && unit->meta.load_state == UNIT_MASKED) { - dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->meta.id); - return -EINVAL; - } - - if (!unit_job_is_applicable(unit, type)) { - dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->meta.id); - return -EBADR; - } - - /* First add the job. */ - if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new))) - return -ENOMEM; - - ret->ignore_order = ret->ignore_order || ignore_order; - - /* Then, add a link to the job. */ - if (!job_dependency_new(by, ret, matters, conflicts)) - return -ENOMEM; - - if (is_new && !ignore_requirements) { - Set *following; - - /* If we are following some other unit, make sure we - * add all dependencies of everybody following. */ - if (unit_following_set(ret->unit, &following) > 0) { - SET_FOREACH(dep, following, i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } - - set_free(following); - } - - /* Finally, recursively add in all dependencies. */ - if (type == JOB_START || type == JOB_RELOAD_OR_START) { - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BIND_TO], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { - - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { - - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) { - - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); - - if (e) - dbus_error_free(e); - } - - } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { - - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - - SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BOUND_BY], i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { - - if (r != -EBADR) - goto fail; - - if (e) - dbus_error_free(e); - } - } - - /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */ - } - - if (_ret) - *_ret = ret; - - return 0; - -fail: - return r; -} - -static int transaction_add_isolate_jobs(Manager *m) { - Iterator i; - Unit *u; - char *k; - int r; - - assert(m); - - HASHMAP_FOREACH_KEY(u, k, m->units, i) { - - /* ignore aliases */ - if (u->meta.id != k) - continue; - - if (u->meta.ignore_on_isolate) - continue; - - /* No need to stop inactive jobs */ - if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->meta.job) - continue; - - /* Is there already something listed for this? */ - if (hashmap_get(m->transaction_jobs, u)) - continue; - - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL)) < 0) - log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r)); - } - - return 0; -} - -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { - int r; - Job *ret; - - assert(m); - assert(type < _JOB_TYPE_MAX); - assert(unit); - assert(mode < _JOB_MODE_MAX); - - if (mode == JOB_ISOLATE && type != JOB_START) { - dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start."); - return -EINVAL; - } - - if (mode == JOB_ISOLATE && !unit->meta.allow_isolate) { - dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated."); - return -EPERM; - } - - log_debug("Trying to enqueue job %s/%s/%s", unit->meta.id, job_type_to_string(type), job_mode_to_string(mode)); - - if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, - mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, - mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) { - transaction_abort(m); - return r; - } - - if (mode == JOB_ISOLATE) - if ((r = transaction_add_isolate_jobs(m)) < 0) { - transaction_abort(m); - return r; - } - - if ((r = transaction_activate(m, mode, e)) < 0) - return r; - - log_debug("Enqueued job %s/%s as %u", unit->meta.id, job_type_to_string(type), (unsigned) ret->id); - - if (_ret) - *_ret = ret; - - return 0; -} - -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) { - Unit *unit; - int r; - - assert(m); - assert(type < _JOB_TYPE_MAX); - assert(name); - assert(mode < _JOB_MODE_MAX); - - if ((r = manager_load_unit(m, name, NULL, NULL, &unit)) < 0) - return r; - - return manager_add_job(m, type, unit, mode, override, e, _ret); -} - -Job *manager_get_job(Manager *m, uint32_t id) { - assert(m); - - return hashmap_get(m->jobs, UINT32_TO_PTR(id)); -} - -Unit *manager_get_unit(Manager *m, const char *name) { - assert(m); - assert(name); - - return hashmap_get(m->units, name); -} - -unsigned manager_dispatch_load_queue(Manager *m) { - Meta *meta; - unsigned n = 0; - - assert(m); - - /* Make sure we are not run recursively */ - if (m->dispatching_load_queue) - return 0; - - m->dispatching_load_queue = true; - - /* Dispatches the load queue. Takes a unit from the queue and - * tries to load its data until the queue is empty */ - - while ((meta = m->load_queue)) { - assert(meta->in_load_queue); - - unit_load((Unit*) meta); - n++; - } - - m->dispatching_load_queue = false; - return n; -} - -int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) { - Unit *ret; - int r; - - assert(m); - assert(name || path); - - /* This will prepare the unit for loading, but not actually - * load anything from disk. */ - - if (path && !is_path(path)) { - dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path); - return -EINVAL; - } - - if (!name) - name = file_name_from_path(path); - - if (!unit_name_is_valid(name, false)) { - dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name); - return -EINVAL; - } - - if ((ret = manager_get_unit(m, name))) { - *_ret = ret; - return 1; - } - - if (!(ret = unit_new(m))) - return -ENOMEM; - - if (path) - if (!(ret->meta.fragment_path = strdup(path))) { - unit_free(ret); - return -ENOMEM; - } - - if ((r = unit_add_name(ret, name)) < 0) { - unit_free(ret); - return r; - } - - unit_add_to_load_queue(ret); - unit_add_to_dbus_queue(ret); - unit_add_to_gc_queue(ret); - - if (_ret) - *_ret = ret; - - return 0; -} - -int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret) { - int r; - - assert(m); - - /* This will load the service information files, but not actually - * start any services or anything. */ - - if ((r = manager_load_unit_prepare(m, name, path, e, _ret)) != 0) - return r; - - manager_dispatch_load_queue(m); - - if (_ret) - *_ret = unit_follow_merge(*_ret); - - return 0; -} - -void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) { - Iterator i; - Job *j; - - assert(s); - assert(f); - - HASHMAP_FOREACH(j, s->jobs, i) - job_dump(j, f, prefix); -} - -void manager_dump_units(Manager *s, FILE *f, const char *prefix) { - Iterator i; - Unit *u; - const char *t; - - assert(s); - assert(f); - - HASHMAP_FOREACH_KEY(u, t, s->units, i) - if (u->meta.id == t) - unit_dump(u, f, prefix); -} - -void manager_clear_jobs(Manager *m) { - Job *j; - - assert(m); - - transaction_abort(m); - - while ((j = hashmap_first(m->jobs))) - job_finish_and_invalidate(j, JOB_CANCELED); -} - -unsigned manager_dispatch_run_queue(Manager *m) { - Job *j; - unsigned n = 0; - - if (m->dispatching_run_queue) - return 0; - - m->dispatching_run_queue = true; - - while ((j = m->run_queue)) { - assert(j->installed); - assert(j->in_run_queue); - - job_run_and_invalidate(j); - n++; - } - - m->dispatching_run_queue = false; - return n; -} - -unsigned manager_dispatch_dbus_queue(Manager *m) { - Job *j; - Meta *meta; - unsigned n = 0; - - assert(m); - - if (m->dispatching_dbus_queue) - return 0; - - m->dispatching_dbus_queue = true; - - while ((meta = m->dbus_unit_queue)) { - assert(meta->in_dbus_queue); - - bus_unit_send_change_signal((Unit*) meta); - n++; - } - - while ((j = m->dbus_job_queue)) { - assert(j->in_dbus_queue); - - bus_job_send_change_signal(j); - n++; - } - - m->dispatching_dbus_queue = false; - return n; -} - -static int manager_process_notify_fd(Manager *m) { - ssize_t n; - - assert(m); - - for (;;) { - char buf[4096]; - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - Unit *u; - char **tags; - - zero(iovec); - iovec.iov_base = buf; - iovec.iov_len = sizeof(buf)-1; - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) { - if (n >= 0) - return -EIO; - - if (errno == EAGAIN || errno == EINTR) - break; - - return -errno; - } - - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - control.cmsghdr.cmsg_level != SOL_SOCKET || - control.cmsghdr.cmsg_type != SCM_CREDENTIALS || - control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received notify message without credentials. Ignoring."); - continue; - } - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - - if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid)))) - if (!(u = cgroup_unit_by_pid(m, ucred->pid))) { - log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid); - continue; - } - - assert((size_t) n < sizeof(buf)); - buf[n] = 0; - if (!(tags = strv_split(buf, "\n\r"))) - return -ENOMEM; - - log_debug("Got notification message for unit %s", u->meta.id); - - if (UNIT_VTABLE(u)->notify_message) - UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags); - - strv_free(tags); - } - - return 0; -} - -static int manager_dispatch_sigchld(Manager *m) { - assert(m); - - for (;;) { - siginfo_t si; - Unit *u; - int r; - - zero(si); - - /* First we call waitd() for a PID and do not reap the - * zombie. That way we can still access /proc/$PID for - * it while it is a zombie. */ - if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) { - - if (errno == ECHILD) - break; - - if (errno == EINTR) - continue; - - return -errno; - } - - if (si.si_pid <= 0) - break; - - if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) { - char *name = NULL; - - get_process_name(si.si_pid, &name); - log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name)); - free(name); - } - - /* Let's flush any message the dying child might still - * have queued for us. This ensures that the process - * still exists in /proc so that we can figure out - * which cgroup and hence unit it belongs to. */ - if ((r = manager_process_notify_fd(m)) < 0) - return r; - - /* And now figure out the unit this belongs to */ - if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid)))) - u = cgroup_unit_by_pid(m, si.si_pid); - - /* And now, we actually reap the zombie. */ - if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) { - if (errno == EINTR) - continue; - - return -errno; - } - - if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED) - continue; - - log_debug("Child %lu died (code=%s, status=%i/%s)", - (long unsigned) si.si_pid, - sigchld_code_to_string(si.si_code), - si.si_status, - strna(si.si_code == CLD_EXITED - ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL) - : signal_to_string(si.si_status))); - - if (!u) - continue; - - log_debug("Child %lu belongs to %s", (long unsigned) si.si_pid, u->meta.id); - - hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid)); - UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status); - } - - return 0; -} - -static int manager_start_target(Manager *m, const char *name, JobMode mode) { - int r; - DBusError error; - - dbus_error_init(&error); - - log_debug("Activating special unit %s", name); - - if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0) - log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r)); - - dbus_error_free(&error); - - return r; -} - -static int manager_process_signal_fd(Manager *m) { - ssize_t n; - struct signalfd_siginfo sfsi; - bool sigchld = false; - - assert(m); - - for (;;) { - if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { - - if (n >= 0) - return -EIO; - - if (errno == EINTR || errno == EAGAIN) - break; - - return -errno; - } - - if (sfsi.ssi_pid > 0) { - char *p = NULL; - - get_process_name(sfsi.ssi_pid, &p); - - log_debug("Received SIG%s from PID %lu (%s).", - signal_to_string(sfsi.ssi_signo), - (unsigned long) sfsi.ssi_pid, strna(p)); - free(p); - } else - log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo)); - - switch (sfsi.ssi_signo) { - - case SIGCHLD: - sigchld = true; - break; - - case SIGTERM: - if (m->running_as == MANAGER_SYSTEM) { - /* This is for compatibility with the - * original sysvinit */ - m->exit_code = MANAGER_REEXECUTE; - break; - } - - /* Fall through */ - - case SIGINT: - if (m->running_as == MANAGER_SYSTEM) { - manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE); - break; - } - - /* Run the exit target if there is one, if not, just exit. */ - if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) { - m->exit_code = MANAGER_EXIT; - return 0; - } - - break; - - case SIGWINCH: - if (m->running_as == MANAGER_SYSTEM) - manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE); - - /* This is a nop on non-init */ - break; - - case SIGPWR: - if (m->running_as == MANAGER_SYSTEM) - manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE); - - /* This is a nop on non-init */ - break; - - case SIGUSR1: { - Unit *u; - - u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); - - if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) { - log_info("Trying to reconnect to bus..."); - bus_init(m, true); - } - - if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) { - log_info("Loading D-Bus service..."); - manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE); - } - - break; - } - - case SIGUSR2: { - FILE *f; - char *dump = NULL; - size_t size; - - if (!(f = open_memstream(&dump, &size))) { - log_warning("Failed to allocate memory stream."); - break; - } - - manager_dump_units(m, f, "\t"); - manager_dump_jobs(m, f, "\t"); - - if (ferror(f)) { - fclose(f); - free(dump); - log_warning("Failed to write status stream"); - break; - } - - fclose(f); - log_dump(LOG_INFO, dump); - free(dump); - - break; - } - - case SIGHUP: - m->exit_code = MANAGER_RELOAD; - break; - - default: { - - /* Starting SIGRTMIN+0 */ - static const char * const target_table[] = { - [0] = SPECIAL_DEFAULT_TARGET, - [1] = SPECIAL_RESCUE_TARGET, - [2] = SPECIAL_EMERGENCY_TARGET, - [3] = SPECIAL_HALT_TARGET, - [4] = SPECIAL_POWEROFF_TARGET, - [5] = SPECIAL_REBOOT_TARGET, - [6] = SPECIAL_KEXEC_TARGET - }; - - /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */ - static const ManagerExitCode code_table[] = { - [0] = MANAGER_HALT, - [1] = MANAGER_POWEROFF, - [2] = MANAGER_REBOOT, - [3] = MANAGER_KEXEC - }; - - if ((int) sfsi.ssi_signo >= SIGRTMIN+0 && - (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) { - int idx = (int) sfsi.ssi_signo - SIGRTMIN; - manager_start_target(m, target_table[idx], - (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE); - break; - } - - if ((int) sfsi.ssi_signo >= SIGRTMIN+13 && - (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) { - m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13]; - break; - } - - switch (sfsi.ssi_signo - SIGRTMIN) { - - case 20: - log_debug("Enabling showing of status."); - manager_set_show_status(m, true); - break; - - case 21: - log_debug("Disabling showing of status."); - manager_set_show_status(m, false); - break; - - case 22: - log_set_max_level(LOG_DEBUG); - log_notice("Setting log level to debug."); - break; - - case 23: - log_set_max_level(LOG_INFO); - log_notice("Setting log level to info."); - break; - - case 27: - log_set_target(LOG_TARGET_CONSOLE); - log_notice("Setting log target to console."); - break; - - case 28: - log_set_target(LOG_TARGET_KMSG); - log_notice("Setting log target to kmsg."); - break; - - case 29: - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_notice("Setting log target to syslog-or-kmsg."); - break; - - default: - log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo)); - } - } - } - } - - if (sigchld) - return manager_dispatch_sigchld(m); - - return 0; -} - -static int process_event(Manager *m, struct epoll_event *ev) { - int r; - Watch *w; - - assert(m); - assert(ev); - - assert_se(w = ev->data.ptr); - - if (w->type == WATCH_INVALID) - return 0; - - switch (w->type) { - - case WATCH_SIGNAL: - - /* An incoming signal? */ - if (ev->events != EPOLLIN) - return -EINVAL; - - if ((r = manager_process_signal_fd(m)) < 0) - return r; - - break; - - case WATCH_NOTIFY: - - /* An incoming daemon notification event? */ - if (ev->events != EPOLLIN) - return -EINVAL; - - if ((r = manager_process_notify_fd(m)) < 0) - return r; - - break; - - case WATCH_FD: - - /* Some fd event, to be dispatched to the units */ - UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w); - break; - - case WATCH_UNIT_TIMER: - case WATCH_JOB_TIMER: { - uint64_t v; - ssize_t k; - - /* Some timer event, to be dispatched to the units */ - if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) { - - if (k < 0 && (errno == EINTR || errno == EAGAIN)) - break; - - return k < 0 ? -errno : -EIO; - } - - if (w->type == WATCH_UNIT_TIMER) - UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w); - else - job_timer_event(w->data.job, v, w); - break; - } - - case WATCH_MOUNT: - /* Some mount table change, intended for the mount subsystem */ - mount_fd_event(m, ev->events); - break; - - case WATCH_SWAP: - /* Some swap table change, intended for the swap subsystem */ - swap_fd_event(m, ev->events); - break; - - case WATCH_UDEV: - /* Some notification from udev, intended for the device subsystem */ - device_fd_event(m, ev->events); - break; - - case WATCH_DBUS_WATCH: - bus_watch_event(m, w, ev->events); - break; - - case WATCH_DBUS_TIMEOUT: - bus_timeout_event(m, w, ev->events); - break; - - default: - log_error("event type=%i", w->type); - assert_not_reached("Unknown epoll event type."); - } - - return 0; -} - -int manager_loop(Manager *m) { - int r; - - RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000); - - assert(m); - m->exit_code = MANAGER_RUNNING; - - /* Release the path cache */ - set_free_free(m->unit_path_cache); - m->unit_path_cache = NULL; - - manager_check_finished(m); - - /* There might still be some zombies hanging around from - * before we were exec()'ed. Leat's reap them */ - if ((r = manager_dispatch_sigchld(m)) < 0) - return r; - - while (m->exit_code == MANAGER_RUNNING) { - struct epoll_event event; - int n; - - if (!ratelimit_test(&rl)) { - /* Yay, something is going seriously wrong, pause a little */ - log_warning("Looping too fast. Throttling execution a little."); - sleep(1); - } - - if (manager_dispatch_load_queue(m) > 0) - continue; - - if (manager_dispatch_run_queue(m) > 0) - continue; - - if (bus_dispatch(m) > 0) - continue; - - if (manager_dispatch_cleanup_queue(m) > 0) - continue; - - if (manager_dispatch_gc_queue(m) > 0) - continue; - - if (manager_dispatch_dbus_queue(m) > 0) - continue; - - if (swap_dispatch_reload(m) > 0) - continue; - - if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) { - - if (errno == EINTR) - continue; - - return -errno; - } - - assert(n == 1); - - if ((r = process_event(m, &event)) < 0) - return r; - } - - return m->exit_code; -} - -int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) { - char *n; - Unit *u; - - assert(m); - assert(s); - assert(_u); - - if (!startswith(s, "/org/freedesktop/systemd1/unit/")) - return -EINVAL; - - if (!(n = bus_path_unescape(s+31))) - return -ENOMEM; - - u = manager_get_unit(m, n); - free(n); - - if (!u) - return -ENOENT; - - *_u = u; - - return 0; -} - -int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) { - Job *j; - unsigned id; - int r; - - assert(m); - assert(s); - assert(_j); - - if (!startswith(s, "/org/freedesktop/systemd1/job/")) - return -EINVAL; - - if ((r = safe_atou(s + 30, &id)) < 0) - return r; - - if (!(j = manager_get_job(m, id))) - return -ENOENT; - - *_j = j; - - return 0; -} - -void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { - -#ifdef HAVE_AUDIT - char *p; - - if (m->audit_fd < 0) - return; - - /* Don't generate audit events if the service was already - * started and we're just deserializing */ - if (m->n_reloading > 0) - return; - - if (m->running_as != MANAGER_SYSTEM) - return; - - if (u->meta.type != UNIT_SERVICE) - return; - - if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) { - log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM)); - return; - } - - if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) { - log_warning("Failed to send audit message: %m"); - - if (errno == EPERM) { - /* We aren't allowed to send audit messages? - * Then let's not retry again, to avoid - * spamming the user with the same and same - * messages over and over. */ - - audit_close(m->audit_fd); - m->audit_fd = -1; - } - } - - free(p); -#endif - -} - -void manager_send_unit_plymouth(Manager *m, Unit *u) { - int fd = -1; - union sockaddr_union sa; - int n = 0; - char *message = NULL; - - /* Don't generate plymouth events if the service was already - * started and we're just deserializing */ - if (m->n_reloading > 0) - return; - - if (m->running_as != MANAGER_SYSTEM) - return; - - if (u->meta.type != UNIT_SERVICE && - u->meta.type != UNIT_MOUNT && - u->meta.type != UNIT_SWAP) - return; - - /* We set SOCK_NONBLOCK here so that we rather drop the - * message then wait for plymouth */ - if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("socket() failed: %m"); - return; - } - - zero(sa); - sa.sa.sa_family = AF_UNIX; - strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1); - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { - - if (errno != EPIPE && - errno != EAGAIN && - errno != ENOENT && - errno != ECONNREFUSED && - errno != ECONNRESET && - errno != ECONNABORTED) - log_error("connect() failed: %m"); - - goto finish; - } - - if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->meta.id) + 1), u->meta.id, &n) < 0) { - log_error("Out of memory"); - goto finish; - } - - errno = 0; - if (write(fd, message, n + 1) != n + 1) { - - if (errno != EPIPE && - errno != EAGAIN && - errno != ENOENT && - errno != ECONNREFUSED && - errno != ECONNRESET && - errno != ECONNABORTED) - log_error("Failed to write Plymouth message: %m"); - - goto finish; - } - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - free(message); -} - -void manager_dispatch_bus_name_owner_changed( - Manager *m, - const char *name, - const char* old_owner, - const char *new_owner) { - - Unit *u; - - assert(m); - assert(name); - - if (!(u = hashmap_get(m->watch_bus, name))) - return; - - UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner); -} - -void manager_dispatch_bus_query_pid_done( - Manager *m, - const char *name, - pid_t pid) { - - Unit *u; - - assert(m); - assert(name); - assert(pid >= 1); - - if (!(u = hashmap_get(m->watch_bus, name))) - return; - - UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid); -} - -int manager_open_serialization(Manager *m, FILE **_f) { - char *path = NULL; - mode_t saved_umask; - int fd; - FILE *f; - - assert(_f); - - if (m->running_as == MANAGER_SYSTEM) - asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid()); - else - asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid()); - - if (!path) - return -ENOMEM; - - saved_umask = umask(0077); - fd = mkostemp(path, O_RDWR|O_CLOEXEC); - umask(saved_umask); - - if (fd < 0) { - free(path); - return -errno; - } - - unlink(path); - - log_debug("Serializing state to %s", path); - free(path); - - if (!(f = fdopen(fd, "w+"))) - return -errno; - - *_f = f; - - return 0; -} - -int manager_serialize(Manager *m, FILE *f, FDSet *fds) { - Iterator i; - Unit *u; - const char *t; - int r; - - assert(m); - assert(f); - assert(fds); - - m->n_reloading ++; - - fprintf(f, "current-job-id=%i\n", m->current_job_id); - fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); - - dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp); - dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp); - dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); - - fputc('\n', f); - - HASHMAP_FOREACH_KEY(u, t, m->units, i) { - if (u->meta.id != t) - continue; - - if (!unit_can_serialize(u)) - continue; - - /* Start marker */ - fputs(u->meta.id, f); - fputc('\n', f); - - if ((r = unit_serialize(u, f, fds)) < 0) { - m->n_reloading --; - return r; - } - } - - assert(m->n_reloading > 0); - m->n_reloading --; - - if (ferror(f)) - return -EIO; - - r = bus_fdset_add_all(m, fds); - if (r < 0) - return r; - - return 0; -} - -int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { - int r = 0; - - assert(m); - assert(f); - - log_debug("Deserializing state..."); - - m->n_reloading ++; - - for (;;) { - char line[LINE_MAX], *l; - - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - r = 0; - else - r = -errno; - - goto finish; - } - - char_array_0(line); - l = strstrip(line); - - if (l[0] == 0) - break; - - if (startswith(l, "current-job-id=")) { - uint32_t id; - - if (safe_atou32(l+15, &id) < 0) - log_debug("Failed to parse current job id value %s", l+15); - else - m->current_job_id = MAX(m->current_job_id, id); - } else if (startswith(l, "taint-usr=")) { - int b; - - if ((b = parse_boolean(l+10)) < 0) - log_debug("Failed to parse taint /usr flag %s", l+10); - else - m->taint_usr = m->taint_usr || b; - } else if (startswith(l, "initrd-timestamp=")) - dual_timestamp_deserialize(l+17, &m->initrd_timestamp); - else if (startswith(l, "startup-timestamp=")) - dual_timestamp_deserialize(l+18, &m->startup_timestamp); - else if (startswith(l, "finish-timestamp=")) - dual_timestamp_deserialize(l+17, &m->finish_timestamp); - else - log_debug("Unknown serialization item '%s'", l); - } - - for (;;) { - Unit *u; - char name[UNIT_NAME_MAX+2]; - - /* Start marker */ - if (!fgets(name, sizeof(name), f)) { - if (feof(f)) - r = 0; - else - r = -errno; - - goto finish; - } - - char_array_0(name); - - if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0) - goto finish; - - if ((r = unit_deserialize(u, f, fds)) < 0) - goto finish; - } - -finish: - if (ferror(f)) { - r = -EIO; - goto finish; - } - - assert(m->n_reloading > 0); - m->n_reloading --; - - return r; -} - -int manager_reload(Manager *m) { - int r, q; - FILE *f; - FDSet *fds; - - assert(m); - - if ((r = manager_open_serialization(m, &f)) < 0) - return r; - - m->n_reloading ++; - - if (!(fds = fdset_new())) { - m->n_reloading --; - r = -ENOMEM; - goto finish; - } - - if ((r = manager_serialize(m, f, fds)) < 0) { - m->n_reloading --; - goto finish; - } - - if (fseeko(f, 0, SEEK_SET) < 0) { - m->n_reloading --; - r = -errno; - goto finish; - } - - /* From here on there is no way back. */ - manager_clear_jobs_and_units(m); - manager_undo_generators(m); - - /* Find new unit paths */ - lookup_paths_free(&m->lookup_paths); - if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) - r = q; - - manager_run_generators(m); - - manager_build_unit_path_cache(m); - - /* First, enumerate what we can from all config files */ - if ((q = manager_enumerate(m)) < 0) - r = q; - - /* Second, deserialize our stored data */ - if ((q = manager_deserialize(m, f, fds)) < 0) - r = q; - - fclose(f); - f = NULL; - - /* Third, fire things up! */ - if ((q = manager_coldplug(m)) < 0) - r = q; - - assert(m->n_reloading > 0); - m->n_reloading--; - -finish: - if (f) - fclose(f); - - if (fds) - fdset_free(fds); - - return r; -} - -bool manager_is_booting_or_shutting_down(Manager *m) { - Unit *u; - - assert(m); - - /* Is the initial job still around? */ - if (manager_get_job(m, 1)) - return true; - - /* Is there a job for the shutdown target? */ - u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); - if (u) - return !!u->meta.job; - - return false; -} - -void manager_reset_failed(Manager *m) { - Unit *u; - Iterator i; - - assert(m); - - HASHMAP_FOREACH(u, m->units, i) - unit_reset_failed(u); -} - -bool manager_unit_pending_inactive(Manager *m, const char *name) { - Unit *u; - - assert(m); - assert(name); - - /* Returns true if the unit is inactive or going down */ - if (!(u = manager_get_unit(m, name))) - return true; - - return unit_pending_inactive(u); -} - -void manager_check_finished(Manager *m) { - char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX]; - usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0; - - assert(m); - - if (dual_timestamp_is_set(&m->finish_timestamp)) - return; - - if (hashmap_size(m->jobs) > 0) - return; - - dual_timestamp_get(&m->finish_timestamp); - - if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) { - - userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic; - total_usec = m->finish_timestamp.monotonic; - - if (dual_timestamp_is_set(&m->initrd_timestamp)) { - - kernel_usec = m->initrd_timestamp.monotonic; - initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic; - - log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", - format_timespan(kernel, sizeof(kernel), kernel_usec), - format_timespan(initrd, sizeof(initrd), initrd_usec), - format_timespan(userspace, sizeof(userspace), userspace_usec), - format_timespan(sum, sizeof(sum), total_usec)); - } else { - kernel_usec = m->startup_timestamp.monotonic; - initrd_usec = 0; - - log_info("Startup finished in %s (kernel) + %s (userspace) = %s.", - format_timespan(kernel, sizeof(kernel), kernel_usec), - format_timespan(userspace, sizeof(userspace), userspace_usec), - format_timespan(sum, sizeof(sum), total_usec)); - } - } else { - userspace_usec = initrd_usec = kernel_usec = 0; - total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic; - - log_debug("Startup finished in %s.", - format_timespan(sum, sizeof(sum), total_usec)); - } - - bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec); - - sd_notifyf(false, - "READY=1\nSTATUS=Startup finished in %s.", - format_timespan(sum, sizeof(sum), total_usec)); -} - -void manager_run_generators(Manager *m) { - DIR *d = NULL; - const char *generator_path; - const char *argv[3]; - mode_t u; - - assert(m); - - generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH; - if (!(d = opendir(generator_path))) { - - if (errno == ENOENT) - return; - - log_error("Failed to enumerate generator directory: %m"); - return; - } - - if (!m->generator_unit_path) { - const char *p; - char user_path[] = "/tmp/systemd-generator-XXXXXX"; - - if (m->running_as == MANAGER_SYSTEM && getpid() == 1) { - p = "/run/systemd/generator"; - - if (mkdir_p(p, 0755) < 0) { - log_error("Failed to create generator directory: %m"); - goto finish; - } - - } else { - if (!(p = mkdtemp(user_path))) { - log_error("Failed to create generator directory: %m"); - goto finish; - } - } - - if (!(m->generator_unit_path = strdup(p))) { - log_error("Failed to allocate generator unit path."); - goto finish; - } - } - - argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */ - argv[1] = m->generator_unit_path; - argv[2] = NULL; - - u = umask(0022); - execute_directory(generator_path, d, (char**) argv); - umask(u); - - if (rmdir(m->generator_unit_path) >= 0) { - /* Uh? we were able to remove this dir? I guess that - * means the directory was empty, hence let's shortcut - * this */ - - free(m->generator_unit_path); - m->generator_unit_path = NULL; - goto finish; - } - - if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) { - char **l; - - if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) { - log_error("Failed to add generator directory to unit search path: %m"); - goto finish; - } - - strv_free(m->lookup_paths.unit_path); - m->lookup_paths.unit_path = l; - - log_debug("Added generator unit path %s to search path.", m->generator_unit_path); - } - -finish: - if (d) - closedir(d); -} - -void manager_undo_generators(Manager *m) { - assert(m); - - if (!m->generator_unit_path) - return; - - strv_remove(m->lookup_paths.unit_path, m->generator_unit_path); - rm_rf(m->generator_unit_path, false, true, false); - - free(m->generator_unit_path); - m->generator_unit_path = NULL; -} - -int manager_set_default_controllers(Manager *m, char **controllers) { - char **l; - - assert(m); - - if (!(l = strv_copy(controllers))) - return -ENOMEM; - - strv_free(m->default_controllers); - m->default_controllers = l; - - return 0; -} - -void manager_recheck_syslog(Manager *m) { - Unit *u; - - assert(m); - - if (m->running_as != MANAGER_SYSTEM) - return; - - if ((u = manager_get_unit(m, SPECIAL_SYSLOG_SOCKET))) { - SocketState state; - - state = SOCKET(u)->state; - - if (state != SOCKET_DEAD && - state != SOCKET_FAILED && - state != SOCKET_RUNNING) { - - /* Hmm, the socket is not set up, or is still - * listening, let's better not try to use - * it. Note that we have no problem if the - * socket is completely down, since there - * might be a foreign /dev/log socket around - * and we want to make use of that. - */ - - log_close_syslog(); - return; - } - } - - if ((u = manager_get_unit(m, SPECIAL_SYSLOG_TARGET))) - if (TARGET(u)->state != TARGET_ACTIVE) { - log_close_syslog(); - return; - } - - /* Hmm, OK, so the socket is either fully up, or fully down, - * and the target is up, then let's make use of the socket */ - log_open(); -} - -void manager_set_show_status(Manager *m, bool b) { - assert(m); - - if (m->running_as != MANAGER_SYSTEM) - return; - - m->show_status = b; - - if (b) - touch("/run/systemd/show-status"); - else - unlink("/run/systemd/show-status"); -} - -bool manager_get_show_status(Manager *m) { - assert(m); - - if (m->running_as != MANAGER_SYSTEM) - return false; - - if (m->show_status) - return true; - - /* If Plymouth is running make sure we show the status, so - * that there's something nice to see when people press Esc */ - - return plymouth_running(); -} - -static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = { - [MANAGER_SYSTEM] = "system", - [MANAGER_USER] = "user" -}; - -DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs); diff --git a/src/manager.h b/src/manager.h deleted file mode 100644 index 5deb569..0000000 --- a/src/manager.h +++ /dev/null @@ -1,299 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomanagerhfoo -#define foomanagerhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "fdset.h" - -/* Enforce upper limit how many names we allow */ -#define MANAGER_MAX_NAMES 131072 /* 128K */ - -typedef struct Manager Manager; -typedef enum WatchType WatchType; -typedef struct Watch Watch; - -typedef enum ManagerExitCode { - MANAGER_RUNNING, - MANAGER_EXIT, - MANAGER_RELOAD, - MANAGER_REEXECUTE, - MANAGER_REBOOT, - MANAGER_POWEROFF, - MANAGER_HALT, - MANAGER_KEXEC, - _MANAGER_EXIT_CODE_MAX, - _MANAGER_EXIT_CODE_INVALID = -1 -} ManagerExitCode; - -typedef enum ManagerRunningAs { - MANAGER_SYSTEM, - MANAGER_USER, - _MANAGER_RUNNING_AS_MAX, - _MANAGER_RUNNING_AS_INVALID = -1 -} ManagerRunningAs; - -enum WatchType { - WATCH_INVALID, - WATCH_SIGNAL, - WATCH_NOTIFY, - WATCH_FD, - WATCH_UNIT_TIMER, - WATCH_JOB_TIMER, - WATCH_MOUNT, - WATCH_SWAP, - WATCH_UDEV, - WATCH_DBUS_WATCH, - WATCH_DBUS_TIMEOUT -}; - -struct Watch { - int fd; - WatchType type; - union { - union Unit *unit; - struct Job *job; - DBusWatch *bus_watch; - DBusTimeout *bus_timeout; - } data; - bool fd_is_dupped:1; - bool socket_accept:1; -}; - -#include "unit.h" -#include "job.h" -#include "hashmap.h" -#include "list.h" -#include "set.h" -#include "dbus.h" -#include "path-lookup.h" - -struct Manager { - /* Note that the set of units we know of is allowed to be - * inconsistent. However the subset of it that is loaded may - * not, and the list of jobs may neither. */ - - /* Active jobs and units */ - Hashmap *units; /* name string => Unit object n:1 */ - Hashmap *jobs; /* job id => Job object 1:1 */ - - /* To make it easy to iterate through the units of a specific - * type we maintain a per type linked list */ - LIST_HEAD(Meta, units_by_type[_UNIT_TYPE_MAX]); - - /* Units that need to be loaded */ - LIST_HEAD(Meta, load_queue); /* this is actually more a stack than a queue, but uh. */ - - /* Jobs that need to be run */ - LIST_HEAD(Job, run_queue); /* more a stack than a queue, too */ - - /* Units and jobs that have not yet been announced via - * D-Bus. When something about a job changes it is added here - * if it is not in there yet. This allows easy coalescing of - * D-Bus change signals. */ - LIST_HEAD(Meta, dbus_unit_queue); - LIST_HEAD(Job, dbus_job_queue); - - /* Units to remove */ - LIST_HEAD(Meta, cleanup_queue); - - /* Units to check when doing GC */ - LIST_HEAD(Meta, gc_queue); - - /* Jobs to be added */ - Hashmap *transaction_jobs; /* Unit object => Job object list 1:1 */ - JobDependency *transaction_anchor; - - Hashmap *watch_pids; /* pid => Unit object n:1 */ - - char *notify_socket; - - Watch notify_watch; - Watch signal_watch; - - int epoll_fd; - - unsigned n_snapshots; - - LookupPaths lookup_paths; - Set *unit_path_cache; - - char **environment; - char **default_controllers; - - dual_timestamp initrd_timestamp; - dual_timestamp startup_timestamp; - dual_timestamp finish_timestamp; - - char *generator_unit_path; - - /* Data specific to the device subsystem */ - struct udev* udev; - struct udev_monitor* udev_monitor; - Watch udev_watch; - Hashmap *devices_by_sysfs; - - /* Data specific to the mount subsystem */ - FILE *proc_self_mountinfo; - Watch mount_watch; - - /* Data specific to the swap filesystem */ - FILE *proc_swaps; - Hashmap *swaps_by_proc_swaps; - bool request_reload; - Watch swap_watch; - - /* Data specific to the D-Bus subsystem */ - DBusConnection *api_bus, *system_bus; - DBusServer *private_bus; - Set *bus_connections, *bus_connections_for_dispatch; - - DBusMessage *queued_message; /* This is used during reloading: - * before the reload we queue the - * reply message here, and - * afterwards we send it */ - DBusConnection *queued_message_connection; /* The connection to send the queued message on */ - - Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */ - int32_t name_data_slot; - int32_t subscribed_data_slot; - - uint32_t current_job_id; - - /* Data specific to the Automount subsystem */ - int dev_autofs_fd; - - /* Data specific to the cgroup subsystem */ - Hashmap *cgroup_bondings; /* path string => CGroupBonding object 1:n */ - char *cgroup_hierarchy; - - usec_t gc_queue_timestamp; - int gc_marker; - unsigned n_in_gc_queue; - - /* Make sure the user cannot accidentally unmount our cgroup - * file system */ - int pin_cgroupfs_fd; - - /* Audit fd */ -#ifdef HAVE_AUDIT - int audit_fd; -#endif - - /* Flags */ - ManagerRunningAs running_as; - ManagerExitCode exit_code:5; - - bool dispatching_load_queue:1; - bool dispatching_run_queue:1; - bool dispatching_dbus_queue:1; - - bool taint_usr:1; - - bool show_status; - bool confirm_spawn; -#ifdef HAVE_SYSV_COMPAT - bool sysv_console; -#endif - bool mount_auto; - bool swap_auto; - - ExecOutput default_std_output, default_std_error; - - /* non-zero if we are reloading or reexecuting, */ - int n_reloading; - - unsigned n_installed_jobs; - unsigned n_failed_jobs; -}; - -int manager_new(ManagerRunningAs running_as, Manager **m); -void manager_free(Manager *m); - -int manager_enumerate(Manager *m); -int manager_coldplug(Manager *m); -int manager_startup(Manager *m, FILE *serialization, FDSet *fds); - -Job *manager_get_job(Manager *m, uint32_t id); -Unit *manager_get_unit(Manager *m, const char *name); - -int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u); -int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); - -int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret); -int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret); - -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, DBusError *e, Job **_ret); -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, DBusError *e, Job **_ret); - -void manager_dump_units(Manager *s, FILE *f, const char *prefix); -void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); - -void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies); - -void manager_clear_jobs(Manager *m); - -unsigned manager_dispatch_load_queue(Manager *m); -unsigned manager_dispatch_run_queue(Manager *m); -unsigned manager_dispatch_dbus_queue(Manager *m); - -int manager_set_default_controllers(Manager *m, char **controllers); - -int manager_loop(Manager *m); - -void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner); -void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid); - -int manager_open_serialization(Manager *m, FILE **_f); - -int manager_serialize(Manager *m, FILE *f, FDSet *fds); -int manager_deserialize(Manager *m, FILE *f, FDSet *fds); - -int manager_reload(Manager *m); - -bool manager_is_booting_or_shutting_down(Manager *m); - -void manager_reset_failed(Manager *m); - -void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success); -void manager_send_unit_plymouth(Manager *m, Unit *u); - -bool manager_unit_pending_inactive(Manager *m, const char *name); - -void manager_check_finished(Manager *m); - -void manager_run_generators(Manager *m); -void manager_undo_generators(Manager *m); - -void manager_recheck_syslog(Manager *m); - -void manager_set_show_status(Manager *m, bool b); -bool manager_get_show_status(Manager *m); - -const char *manager_running_as_to_string(ManagerRunningAs i); -ManagerRunningAs manager_running_as_from_string(const char *s); - -#endif diff --git a/src/missing.h b/src/missing.h deleted file mode 100644 index 213ef2f..0000000 --- a/src/missing.h +++ /dev/null @@ -1,183 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomissinghfoo -#define foomissinghfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -/* Missing glibc definitions to access certain kernel APIs */ - -#include -#include -#include -#include -#include - -#ifdef HAVE_AUDIT -#include -#endif - -#include "macro.h" - -#ifdef ARCH_MIPS -#include -#endif - -#ifndef RLIMIT_RTTIME -#define RLIMIT_RTTIME 15 -#endif - -#ifndef F_LINUX_SPECIFIC_BASE -#define F_LINUX_SPECIFIC_BASE 1024 -#endif - -#ifndef F_SETPIPE_SZ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#endif - -#ifndef F_GETPIPE_SZ -#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) -#endif - -#ifndef IP_FREEBIND -#define IP_FREEBIND 15 -#endif - -#ifndef OOM_SCORE_ADJ_MIN -#define OOM_SCORE_ADJ_MIN (-1000) -#endif - -#ifndef OOM_SCORE_ADJ_MAX -#define OOM_SCORE_ADJ_MAX 1000 -#endif - -#ifndef AUDIT_SERVICE_START -#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */ -#endif - -#ifndef AUDIT_SERVICE_STOP -#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ -#endif - -#ifndef TIOCVHANGUP -#define TIOCVHANGUP 0x5437 -#endif - -#ifndef IP_TRANSPARENT -#define IP_TRANSPARENT 19 -#endif - -static inline int pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); -} - -#ifdef __x86_64__ -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 300 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 301 -# endif -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 4336 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 4337 -# endif -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 6300 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 6301 -# endif -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 5295 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 5296 -# endif -# endif -#else -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 338 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 339 -# endif -#endif - -static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags) { - return syscall(__NR_fanotify_init, flags, event_f_flags); -} - -static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t mask, - int dfd, const char *pathname) { -#if defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI32 - union { - uint64_t _64; - uint32_t _32[2]; - } _mask; - _mask._64 = mask; - - return syscall(__NR_fanotify_mark, fanotify_fd, flags, - _mask._32[0], _mask._32[1], dfd, pathname); -#else - return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); -#endif -} - -#ifndef BTRFS_IOCTL_MAGIC -#define BTRFS_IOCTL_MAGIC 0x94 -#endif - -#ifndef BTRFS_PATH_NAME_MAX -#define BTRFS_PATH_NAME_MAX 4087 -#endif - -struct btrfs_ioctl_vol_args { - int64_t fd; - char name[BTRFS_PATH_NAME_MAX + 1]; -}; - -#ifndef BTRFS_IOC_DEFRAG -#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, struct btrfs_ioctl_vol_args) -#endif - -#ifndef BTRFS_SUPER_MAGIC -#define BTRFS_SUPER_MAGIC 0x9123683E -#endif - -#ifndef MS_MOVE -#define MS_MOVE 8192 -#endif - -#ifndef MS_PRIVATE -#define MS_PRIVATE (1 << 18) -#endif - -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} - -#endif diff --git a/src/modules-load.c b/src/modules-load.c deleted file mode 100644 index 8dd98f7..0000000 --- a/src/modules-load.c +++ /dev/null @@ -1,143 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "strv.h" - -int main(int argc, char *argv[]) { - int r = EXIT_FAILURE; - char **arguments = NULL; - unsigned n_arguments = 0, n_allocated = 0; - char **files, **fn; - - if (argc > 1) { - log_error("This program takes no argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if (!(arguments = strv_new("/sbin/modprobe", "-sab", "--", NULL))) { - log_error("Failed to allocate string array"); - goto finish; - } - - n_arguments = n_allocated = 3; - - if (conf_files_list(&files, ".conf", - "/run/modules-load.d", - "/etc/modules-load.d", - "/usr/local/lib/modules-load.d", - "/usr/lib/modules-load.d", - "/lib/modules-load.d", - NULL) < 0) { - log_error("Failed to enumerate modules-load.d files: %s", strerror(-r)); - goto finish; - } - - r = EXIT_SUCCESS; - - STRV_FOREACH(fn, files) { - FILE *f; - - f = fopen(*fn, "re"); - if (!f) { - if (errno == ENOENT) - continue; - - log_error("Failed to open %s: %m", *fn); - r = EXIT_FAILURE; - continue; - } - - log_debug("apply: %s\n", *fn); - for (;;) { - char line[LINE_MAX], *l, *t; - - if (!(fgets(line, sizeof(line), f))) - break; - - l = strstrip(line); - if (*l == '#' || *l == 0) - continue; - - if (!(t = strdup(l))) { - log_error("Failed to allocate module name."); - continue; - } - - if (n_arguments >= n_allocated) { - char **a; - unsigned m; - - m = MAX(16U, n_arguments*2); - - if (!(a = realloc(arguments, sizeof(char*) * (m+1)))) { - log_error("Failed to increase module array size."); - free(t); - r = EXIT_FAILURE; - continue; - } - - arguments = a; - n_allocated = m; - } - - arguments[n_arguments++] = t; - } - - if (ferror(f)) { - r = EXIT_FAILURE; - log_error("Failed to read from file: %m"); - } - - fclose(f); - } - - strv_free(files); -finish: - - if (n_arguments > 3) { - arguments[n_arguments] = NULL; - strv_uniq(arguments); - execv("/sbin/modprobe", arguments); - - log_error("Failed to execute /sbin/modprobe: %m"); - r = EXIT_FAILURE; - } - - strv_free(arguments); - - return r; -} diff --git a/src/modules-load/Makefile b/src/modules-load/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/modules-load/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c new file mode 100644 index 0000000..37d7a77 --- /dev/null +++ b/src/modules-load/modules-load.c @@ -0,0 +1,309 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "strv.h" +#include "conf-files.h" +#include "fileio.h" +#include "build.h" + +static char **arg_proc_cmdline_modules = NULL; + +static const char conf_file_dirs[] = + "/etc/modules-load.d\0" + "/run/modules-load.d\0" + "/usr/local/lib/modules-load.d\0" + "/usr/lib/modules-load.d\0" +#ifdef HAVE_SPLIT_USR + "/lib/modules-load.d\0" +#endif + ; + +static void systemd_kmod_log(void *data, int priority, const char *file, int line, + const char *fn, const char *format, va_list args) { + + DISABLE_WARNING_FORMAT_NONLITERAL; + log_metav(priority, file, line, fn, format, args); + REENABLE_WARNING; +} + +static int add_modules(const char *p) { + _cleanup_strv_free_ char **k = NULL; + + k = strv_split(p, ","); + if (!k) + return log_oom(); + + if (strv_extend_strv(&arg_proc_cmdline_modules, k) < 0) + return log_oom(); + + return 0; +} + +static int parse_proc_cmdline_word(const char *word) { + int r; + + if (startswith(word, "modules-load=")) { + r = add_modules(word + 13); + if (r < 0) + return r; + + } else if (startswith(word, "rd.modules-load=")) { + if (in_initrd()) { + r = add_modules(word + 16); + if (r < 0) + return r; + } + } + + return 0; +} + +static int load_module(struct kmod_ctx *ctx, const char *m) { + const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST; + struct kmod_list *itr, *modlist = NULL; + int r = 0; + + log_debug("load: %s", m); + + r = kmod_module_new_from_lookup(ctx, m, &modlist); + if (r < 0) { + log_error("Failed to lookup alias '%s': %s", m, strerror(-r)); + return r; + } + + if (!modlist) { + log_error("Failed to find module '%s'", m); + return -ENOENT; + } + + kmod_list_foreach(itr, modlist) { + struct kmod_module *mod; + int state, err; + + mod = kmod_module_get_module(itr); + state = kmod_module_get_initstate(mod); + + switch (state) { + case KMOD_MODULE_BUILTIN: + log_info("Module '%s' is builtin", kmod_module_get_name(mod)); + break; + + case KMOD_MODULE_LIVE: + log_debug("Module '%s' is already loaded", kmod_module_get_name(mod)); + break; + + default: + err = kmod_module_probe_insert_module(mod, probe_flags, + NULL, NULL, NULL, NULL); + + if (err == 0) + log_info("Inserted module '%s'", kmod_module_get_name(mod)); + else if (err == KMOD_PROBE_APPLY_BLACKLIST) + log_info("Module '%s' is blacklisted", kmod_module_get_name(mod)); + else { + log_error("Failed to insert '%s': %s", kmod_module_get_name(mod), + strerror(-err)); + r = err; + } + } + + kmod_module_unref(mod); + } + + kmod_module_unref_list(modlist); + + return r; +} + +static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) { + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(ctx); + assert(path); + + r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f); + if (r < 0) { + if (ignore_enoent && r == -ENOENT) + return 0; + + log_error("Failed to open %s, ignoring: %s", path, strerror(-r)); + return r; + } + + log_debug("apply: %s", path); + for (;;) { + char line[LINE_MAX], *l; + int k; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + break; + + log_error("Failed to read file '%s', ignoring: %m", path); + return -errno; + } + + l = strstrip(line); + if (!*l) + continue; + if (strchr(COMMENTS "\n", *l)) + continue; + + k = load_module(ctx, l); + if (k < 0 && r == 0) + r = k; + } + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" + "Loads statically configured kernel modules.\n\n" + " -h --help Show this help\n" + " --version Show package version\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r, k; + struct kmod_ctx *ctx; + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (parse_proc_cmdline(parse_proc_cmdline_word) < 0) + return EXIT_FAILURE; + + ctx = kmod_new(NULL, NULL); + if (!ctx) { + log_error("Failed to allocate memory for kmod."); + goto finish; + } + + kmod_load_resources(ctx); + kmod_set_log_fn(ctx, systemd_kmod_log, NULL); + + r = 0; + + if (argc > optind) { + int i; + + for (i = optind; i < argc; i++) { + k = apply_file(ctx, argv[i], false); + if (k < 0 && r == 0) + r = k; + } + + } else { + _cleanup_free_ char **files = NULL; + char **fn, **i; + + STRV_FOREACH(i, arg_proc_cmdline_modules) { + k = load_module(ctx, *i); + if (k < 0 && r == 0) + r = k; + } + + k = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); + if (k < 0) { + log_error("Failed to enumerate modules-load.d files: %s", strerror(-k)); + if (r == 0) + r = k; + goto finish; + } + + STRV_FOREACH(fn, files) { + k = apply_file(ctx, *fn, true); + if (k < 0 && r == 0) + r = k; + } + } + +finish: + kmod_unref(ctx); + strv_free(arg_proc_cmdline_modules); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/mount-setup.c b/src/mount-setup.c deleted file mode 100644 index 7c14ea8..0000000 --- a/src/mount-setup.c +++ /dev/null @@ -1,420 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mount-setup.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "label.h" -#include "set.h" -#include "strv.h" - -#ifndef TTY_GID -#define TTY_GID 5 -#endif - -typedef struct MountPoint { - const char *what; - const char *where; - const char *type; - const char *options; - unsigned long flags; - bool fatal; -} MountPoint; - -/* The first three entries we might need before SELinux is up. The - * other ones we can delay until SELinux is loaded. */ -#define N_EARLY_MOUNT 3 - -static const MountPoint mount_table[] = { - { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, - { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, - { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID, true }, - { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV, true }, - { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false }, - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV, true }, - { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, false }, - { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false }, -}; - -/* These are API file systems that might be mounted by other software, - * we just list them here so that we know that we should ignore them */ - -static const char * const ignore_paths[] = { - "/sys/fs/selinux", - "/selinux", - "/proc/bus/usb" -}; - -bool mount_point_is_api(const char *path) { - unsigned i; - - /* Checks if this mount point is considered "API", and hence - * should be ignored */ - - for (i = 0; i < ELEMENTSOF(mount_table); i ++) - if (path_equal(path, mount_table[i].where)) - return true; - - return path_startswith(path, "/sys/fs/cgroup/"); -} - -bool mount_point_ignore(const char *path) { - unsigned i; - - for (i = 0; i < ELEMENTSOF(ignore_paths); i++) - if (path_equal(path, ignore_paths[i])) - return true; - - return false; -} - -static int mount_one(const MountPoint *p, bool relabel) { - int r; - - assert(p); - - /* Relabel first, just in case */ - if (relabel) - label_fix(p->where, true); - - if ((r = path_is_mount_point(p->where, true)) < 0) - return r; - - if (r > 0) - return 0; - - /* The access mode here doesn't really matter too much, since - * the mounted file system will take precedence anyway. */ - mkdir_p(p->where, 0755); - - log_debug("Mounting %s to %s of type %s with options %s.", - p->what, - p->where, - p->type, - strna(p->options)); - - if (mount(p->what, - p->where, - p->type, - p->flags, - p->options) < 0) { - log_error("Failed to mount %s: %s", p->where, strerror(errno)); - return p->fatal ? -errno : 0; - } - - /* Relabel again, since we now mounted something fresh here */ - if (relabel) - label_fix(p->where, false); - - return 1; -} - -int mount_setup_early(void) { - unsigned i; - int r = 0; - - assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table)); - - /* Do a minimal mount of /proc and friends to enable the most - * basic stuff, such as SELinux */ - for (i = 0; i < N_EARLY_MOUNT; i ++) { - int j; - - j = mount_one(mount_table + i, false); - if (r == 0) - r = j; - } - - return r; -} - -int mount_cgroup_controllers(char ***join_controllers) { - int r; - FILE *f; - char buf[LINE_MAX]; - Set *controllers; - - /* Mount all available cgroup controllers that are built into the kernel. */ - - f = fopen("/proc/cgroups", "re"); - if (!f) { - log_error("Failed to enumerate cgroup controllers: %m"); - return 0; - } - - controllers = set_new(string_hash_func, string_compare_func); - if (!controllers) { - r = -ENOMEM; - log_error("Failed to allocate controller set."); - goto finish; - } - - /* Ignore the header line */ - (void) fgets(buf, sizeof(buf), f); - - for (;;) { - char *controller; - int enabled = 0; - - if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) { - - if (feof(f)) - break; - - log_error("Failed to parse /proc/cgroups."); - r = -EIO; - goto finish; - } - - if (!enabled) { - free(controller); - continue; - } - - r = set_put(controllers, controller); - if (r < 0) { - log_error("Failed to add controller to set."); - free(controller); - goto finish; - } - } - - for (;;) { - MountPoint p; - char *controller, *where, *options; - char ***k = NULL; - - controller = set_steal_first(controllers); - if (!controller) - break; - - if (join_controllers) - for (k = join_controllers; *k; k++) - if (strv_find(*k, controller)) - break; - - if (k && *k) { - char **i, **j; - - for (i = *k, j = *k; *i; i++) { - - if (!streq(*i, controller)) { - char *t; - - t = set_remove(controllers, *i); - if (!t) { - free(*i); - continue; - } - free(t); - } - - *(j++) = *i; - } - - *j = NULL; - - options = strv_join(*k, ","); - if (!options) { - log_error("Failed to join options"); - free(controller); - r = -ENOMEM; - goto finish; - } - - } else { - options = controller; - controller = NULL; - } - - where = strappend("/sys/fs/cgroup/", options); - if (!where) { - log_error("Failed to build path"); - free(options); - r = -ENOMEM; - goto finish; - } - - zero(p); - p.what = "cgroup"; - p.where = where; - p.type = "cgroup"; - p.options = options; - p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV; - p.fatal = false; - - r = mount_one(&p, true); - free(controller); - free(where); - - if (r < 0) { - free(options); - goto finish; - } - - if (r > 0 && k && *k) { - char **i; - - for (i = *k; *i; i++) { - char *t; - - t = strappend("/sys/fs/cgroup/", *i); - if (!t) { - log_error("Failed to build path"); - r = -ENOMEM; - free(options); - goto finish; - } - - r = symlink(options, t); - free(t); - - if (r < 0 && errno != EEXIST) { - log_error("Failed to create symlink: %m"); - r = -errno; - free(options); - goto finish; - } - } - } - - free(options); - } - - r = 0; - -finish: - set_free_free(controllers); - - fclose(f); - - return r; -} - -static int symlink_and_label(const char *old_path, const char *new_path) { - int r; - - assert(old_path); - assert(new_path); - - if ((r = label_symlinkfile_set(new_path)) < 0) - return r; - - if (symlink(old_path, new_path) < 0) - r = -errno; - - label_file_clear(); - - return r; -} - -static int nftw_cb( - const char *fpath, - const struct stat *sb, - int tflag, - struct FTW *ftwbuf) { - - /* No need to label /dev twice in a row... */ - if (_unlikely_(ftwbuf->level == 0)) - return FTW_CONTINUE; - - label_fix(fpath, true); - - /* /run/initramfs is static data and big, no need to - * dynamically relabel its contents at boot... */ - if (_unlikely_(ftwbuf->level == 1 && - tflag == FTW_D && - streq(fpath, "/run/initramfs"))) - return FTW_SKIP_SUBTREE; - - return FTW_CONTINUE; -}; - -int mount_setup(bool loaded_policy) { - - static const char symlinks[] = - "/proc/kcore\0" "/dev/core\0" - "/proc/self/fd\0" "/dev/fd\0" - "/proc/self/fd/0\0" "/dev/stdin\0" - "/proc/self/fd/1\0" "/dev/stdout\0" - "/proc/self/fd/2\0" "/dev/stderr\0"; - - static const char relabel[] = - "/run/initramfs/root-fsck\0" - "/run/initramfs/shutdown\0"; - - int r; - unsigned i; - const char *j, *k; - - for (i = 0; i < ELEMENTSOF(mount_table); i ++) { - r = mount_one(mount_table + i, true); - - if (r < 0) - return r; - } - - /* Nodes in devtmpfs and /run need to be manually updated for - * the appropriate labels, after mounting. The other virtual - * API file systems like /sys and /proc do not need that, they - * use the same label for all their files. */ - if (loaded_policy) { - usec_t before_relabel, after_relabel; - char timespan[FORMAT_TIMESPAN_MAX]; - - before_relabel = now(CLOCK_MONOTONIC); - - nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); - nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); - - /* Explicitly relabel these */ - NULSTR_FOREACH(j, relabel) - label_fix(j, true); - - after_relabel = now(CLOCK_MONOTONIC); - - log_info("Relabelled /dev and /run in %s.", - format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel)); - } - - /* Create a few default symlinks, which are normally created - * by udevd, but some scripts might need them before we start - * udevd. */ - NULSTR_FOREACH_PAIR(j, k, symlinks) - symlink_and_label(j, k); - - /* Create a few directories we always want around */ - label_mkdir("/run/systemd", 0755); - label_mkdir("/run/systemd/system", 0755); - - return 0; -} diff --git a/src/mount-setup.h b/src/mount-setup.h deleted file mode 100644 index c1a27ba..0000000 --- a/src/mount-setup.h +++ /dev/null @@ -1,36 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomountsetuphfoo -#define foomountsetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -int mount_setup_early(void); - -int mount_setup(bool loaded_policy); - -int mount_cgroup_controllers(char ***join_controllers); - -bool mount_point_is_api(const char *path); -bool mount_point_ignore(const char *path); - -#endif diff --git a/src/mount.c b/src/mount.c deleted file mode 100644 index ef953f0..0000000 --- a/src/mount.c +++ /dev/null @@ -1,1886 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "unit.h" -#include "mount.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "strv.h" -#include "mount-setup.h" -#include "unit-name.h" -#include "dbus-mount.h" -#include "special.h" -#include "bus-errors.h" -#include "exit-status.h" -#include "def.h" - -static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = UNIT_INACTIVE, - [MOUNT_MOUNTING] = UNIT_ACTIVATING, - [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE, - [MOUNT_MOUNTED] = UNIT_ACTIVE, - [MOUNT_REMOUNTING] = UNIT_RELOADING, - [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, - [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING, - [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING, - [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING, - [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING, - [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING, - [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING, - [MOUNT_FAILED] = UNIT_FAILED -}; - -static void mount_init(Unit *u) { - Mount *m = MOUNT(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - m->timeout_usec = DEFAULT_TIMEOUT_USEC; - m->directory_mode = 0755; - - exec_context_init(&m->exec_context); - - /* The stdio/kmsg bridge socket is on /, in order to avoid a - * dep loop, don't use kmsg logging for -.mount */ - if (!unit_has_name(u, "-.mount")) - m->exec_context.std_output = EXEC_OUTPUT_KMSG; - - /* We need to make sure that /bin/mount is always called in - * the same process group as us, so that the autofs kernel - * side doesn't send us another mount request while we are - * already trying to comply its last one. */ - m->exec_context.same_pgrp = true; - - m->timer_watch.type = WATCH_INVALID; - - m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; - - m->meta.ignore_on_isolate = true; -} - -static void mount_unwatch_control_pid(Mount *m) { - assert(m); - - if (m->control_pid <= 0) - return; - - unit_unwatch_pid(UNIT(m), m->control_pid); - m->control_pid = 0; -} - -static void mount_parameters_done(MountParameters *p) { - assert(p); - - free(p->what); - free(p->options); - free(p->fstype); - - p->what = p->options = p->fstype = NULL; -} - -static void mount_done(Unit *u) { - Mount *m = MOUNT(u); - Meta *other; - - assert(m); - - free(m->where); - m->where = NULL; - - /* Try to detach us from the automount unit if there is any */ - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_AUTOMOUNT]) { - Automount *a = (Automount*) other; - - if (a->mount == m) - a->mount = NULL; - } - - mount_parameters_done(&m->parameters_etc_fstab); - mount_parameters_done(&m->parameters_proc_self_mountinfo); - mount_parameters_done(&m->parameters_fragment); - - exec_context_done(&m->exec_context); - exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX); - m->control_command = NULL; - - mount_unwatch_control_pid(m); - - unit_unwatch_timer(u, &m->timer_watch); -} - -static MountParameters* get_mount_parameters_configured(Mount *m) { - assert(m); - - if (m->from_fragment) - return &m->parameters_fragment; - else if (m->from_etc_fstab) - return &m->parameters_etc_fstab; - - return NULL; -} - -static MountParameters* get_mount_parameters(Mount *m) { - assert(m); - - if (m->from_proc_self_mountinfo) - return &m->parameters_proc_self_mountinfo; - - return get_mount_parameters_configured(m); -} - -static int mount_add_mount_links(Mount *m) { - Meta *other; - int r; - MountParameters *pm; - - assert(m); - - pm = get_mount_parameters_configured(m); - - /* Adds in links to other mount points that might lie below or - * above us in the hierarchy */ - - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_MOUNT]) { - Mount *n = (Mount*) other; - MountParameters *pn; - - if (n == m) - continue; - - if (n->meta.load_state != UNIT_LOADED) - continue; - - pn = get_mount_parameters_configured(n); - - if (path_startswith(m->where, n->where)) { - - if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0) - return r; - - if (pn) - if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0) - return r; - - } else if (path_startswith(n->where, m->where)) { - - if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0) - return r; - - if (pm) - if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - - } else if (pm && path_startswith(pm->what, n->where)) { - - if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0) - return r; - - if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0) - return r; - - } else if (pn && path_startswith(pn->what, m->where)) { - - if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0) - return r; - - if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - } - } - - return 0; -} - -static int mount_add_swap_links(Mount *m) { - Meta *other; - int r; - - assert(m); - - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_SWAP]) - if ((r = swap_add_one_mount_link((Swap*) other, m)) < 0) - return r; - - return 0; -} - -static int mount_add_path_links(Mount *m) { - Meta *other; - int r; - - assert(m); - - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_PATH]) - if ((r = path_add_one_mount_link((Path*) other, m)) < 0) - return r; - - return 0; -} - -static int mount_add_automount_links(Mount *m) { - Meta *other; - int r; - - assert(m); - - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_AUTOMOUNT]) - if ((r = automount_add_one_mount_link((Automount*) other, m)) < 0) - return r; - - return 0; -} - -static int mount_add_socket_links(Mount *m) { - Meta *other; - int r; - - assert(m); - - LIST_FOREACH(units_by_type, other, m->meta.manager->units_by_type[UNIT_SOCKET]) - if ((r = socket_add_one_mount_link((Socket*) other, m)) < 0) - return r; - - return 0; -} - -static char* mount_test_option(const char *haystack, const char *needle) { - struct mntent me; - - assert(needle); - - /* Like glibc's hasmntopt(), but works on a string, not a - * struct mntent */ - - if (!haystack) - return false; - - zero(me); - me.mnt_opts = (char*) haystack; - - return hasmntopt(&me, needle); -} - -static bool mount_is_network(MountParameters *p) { - assert(p); - - if (mount_test_option(p->options, "_netdev")) - return true; - - if (p->fstype && fstype_is_network(p->fstype)) - return true; - - return false; -} - -static bool mount_is_bind(MountParameters *p) { - assert(p); - - if (mount_test_option(p->options, "bind")) - return true; - - if (p->fstype && streq(p->fstype, "bind")) - return true; - - return false; -} - -static bool needs_quota(MountParameters *p) { - assert(p); - - if (mount_is_network(p)) - return false; - - if (mount_is_bind(p)) - return false; - - return mount_test_option(p->options, "usrquota") || - mount_test_option(p->options, "grpquota") || - mount_test_option(p->options, "quota") || - mount_test_option(p->options, "usrjquota") || - mount_test_option(p->options, "grpjquota"); -} - -static int mount_add_fstab_links(Mount *m) { - const char *target, *after = NULL; - MountParameters *p; - Unit *tu; - int r; - bool noauto, nofail, handle, automount; - - assert(m); - - if (m->meta.manager->running_as != MANAGER_SYSTEM) - return 0; - - if (!(p = get_mount_parameters_configured(m))) - return 0; - - if (p != &m->parameters_etc_fstab) - return 0; - - noauto = !!mount_test_option(p->options, "noauto"); - nofail = !!mount_test_option(p->options, "nofail"); - automount = - mount_test_option(p->options, "comment=systemd.automount") || - mount_test_option(p->options, "x-systemd-automount"); - handle = - automount || - mount_test_option(p->options, "comment=systemd.mount") || - mount_test_option(p->options, "x-systemd-mount") || - m->meta.manager->mount_auto; - - if (mount_is_network(p)) { - target = SPECIAL_REMOTE_FS_TARGET; - after = SPECIAL_REMOTE_FS_PRE_TARGET; - } else { - target = SPECIAL_LOCAL_FS_TARGET; - after = SPECIAL_LOCAL_FS_PRE_TARGET; - } - - if (!path_equal(m->where, "/")) - if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0) - return r; - - if ((r = manager_load_unit(m->meta.manager, target, NULL, NULL, &tu)) < 0) - return r; - - if (after) - if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true)) < 0) - return r; - - if (automount) { - Unit *am; - - if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0) - return r; - - /* If auto is configured as well also pull in the - * mount right-away, but don't rely on it. */ - if (!noauto) /* automount + auto */ - if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0) - return r; - - /* Install automount unit */ - if (!nofail) /* automount + fail */ - return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(am), true); - else /* automount + nofail */ - return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_WANTS, UNIT(am), true); - - } else if (handle && !noauto) { - - /* Automatically add mount points that aren't natively - * configured to local-fs.target */ - - if (!nofail) /* auto + fail */ - return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true); - else /* auto + nofail */ - return unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true); - } - - return 0; -} - -static int mount_add_device_links(Mount *m) { - MountParameters *p; - int r; - - assert(m); - - if (!(p = get_mount_parameters_configured(m))) - return 0; - - if (!p->what) - return 0; - - if (!mount_is_bind(p) && - !path_equal(m->where, "/") && - p == &m->parameters_etc_fstab) { - bool nofail, noauto; - - noauto = !!mount_test_option(p->options, "noauto"); - nofail = !!mount_test_option(p->options, "nofail"); - - if ((r = unit_add_node_link(UNIT(m), p->what, - !noauto && nofail && - UNIT(m)->meta.manager->running_as == MANAGER_SYSTEM)) < 0) - return r; - } - - if (p->passno > 0 && - !mount_is_bind(p) && - UNIT(m)->meta.manager->running_as == MANAGER_SYSTEM && - !path_equal(m->where, "/")) { - char *name; - Unit *fsck; - /* Let's add in the fsck service */ - - /* aka SPECIAL_FSCK_SERVICE */ - if (!(name = unit_name_from_path_instance("fsck", p->what, ".service"))) - return -ENOMEM; - - if ((r = manager_load_unit_prepare(m->meta.manager, name, NULL, NULL, &fsck)) < 0) { - log_warning("Failed to prepare unit %s: %s", name, strerror(-r)); - free(name); - return r; - } - - free(name); - - SERVICE(fsck)->fsck_passno = p->passno; - - if ((r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true)) < 0) - return r; - } - - return 0; -} - -static int mount_add_default_dependencies(Mount *m) { - int r; - - assert(m); - - if (m->meta.manager->running_as == MANAGER_SYSTEM && - !path_equal(m->where, "/")) { - MountParameters *p; - - p = get_mount_parameters_configured(m); - - if (p && needs_quota(p)) { - if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true)) < 0 || - (r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true)) < 0) - return r; - } - - if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0) - return r; - } - - return 0; -} - -static int mount_fix_timeouts(Mount *m) { - MountParameters *p; - const char *timeout = NULL; - Unit *other; - Iterator i; - usec_t u; - char *t; - int r; - - assert(m); - - if (!(p = get_mount_parameters_configured(m))) - return 0; - - /* Allow configuration how long we wait for a device that - * backs a mount point to show up. This is useful to support - * endless device timeouts for devices that show up only after - * user input, like crypto devices. */ - - if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout"))) - timeout += 31; - else if ((timeout = mount_test_option(p->options, "x-systemd-device-timeout"))) - timeout += 25; - else - return 0; - - t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE)); - if (!t) - return -ENOMEM; - - r = parse_usec(t, &u); - free(t); - - if (r < 0) { - log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout); - return r; - } - - SET_FOREACH(other, m->meta.dependencies[UNIT_AFTER], i) { - if (other->meta.type != UNIT_DEVICE) - continue; - - other->meta.job_timeout = u; - } - - return 0; -} - -static int mount_verify(Mount *m) { - bool b; - char *e; - assert(m); - - if (m->meta.load_state != UNIT_LOADED) - return 0; - - if (!m->from_etc_fstab && !m->from_fragment && !m->from_proc_self_mountinfo) - return -ENOENT; - - if (!(e = unit_name_from_path(m->where, ".mount"))) - return -ENOMEM; - - b = unit_has_name(UNIT(m), e); - free(e); - - if (!b) { - log_error("%s's Where setting doesn't match unit name. Refusing.", m->meta.id); - return -EINVAL; - } - - if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) { - log_error("Cannot create mount unit for API file system %s. Refusing.", m->where); - return -EINVAL; - } - - if (m->meta.fragment_path && !m->parameters_fragment.what) { - log_error("%s's What setting is missing. Refusing.", m->meta.id); - return -EBADMSG; - } - - if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) { - log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", m->meta.id); - return -EINVAL; - } - - return 0; -} - -static int mount_load(Unit *u) { - Mount *m = MOUNT(u); - int r; - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - if ((r = unit_load_fragment_and_dropin_optional(u)) < 0) - return r; - - /* This is a new unit? Then let's add in some extras */ - if (u->meta.load_state == UNIT_LOADED) { - if ((r = unit_add_exec_dependencies(u, &m->exec_context)) < 0) - return r; - - if (m->meta.fragment_path) - m->from_fragment = true; - else if (m->from_etc_fstab) - m->meta.default_dependencies = false; - - if (!m->where) - if (!(m->where = unit_name_to_path(u->meta.id))) - return -ENOMEM; - - path_kill_slashes(m->where); - - if (!m->meta.description) - if ((r = unit_set_description(u, m->where)) < 0) - return r; - - if ((r = mount_add_device_links(m)) < 0) - return r; - - if ((r = mount_add_mount_links(m)) < 0) - return r; - - if ((r = mount_add_socket_links(m)) < 0) - return r; - - if ((r = mount_add_swap_links(m)) < 0) - return r; - - if ((r = mount_add_path_links(m)) < 0) - return r; - - if ((r = mount_add_automount_links(m)) < 0) - return r; - - if ((r = mount_add_fstab_links(m)) < 0) - return r; - - if (m->meta.default_dependencies) - if ((r = mount_add_default_dependencies(m)) < 0) - return r; - - if ((r = unit_add_default_cgroups(u)) < 0) - return r; - - mount_fix_timeouts(m); - } - - return mount_verify(m); -} - -static int mount_notify_automount(Mount *m, int status) { - Unit *p; - int r; - - assert(m); - - if ((r = unit_get_related_unit(UNIT(m), ".automount", &p)) < 0) - return r == -ENOENT ? 0 : r; - - return automount_send_ready(AUTOMOUNT(p), status); -} - -static void mount_set_state(Mount *m, MountState state) { - MountState old_state; - assert(m); - - old_state = m->state; - m->state = state; - - if (state != MOUNT_MOUNTING && - state != MOUNT_MOUNTING_DONE && - state != MOUNT_REMOUNTING && - state != MOUNT_UNMOUNTING && - state != MOUNT_MOUNTING_SIGTERM && - state != MOUNT_MOUNTING_SIGKILL && - state != MOUNT_UNMOUNTING_SIGTERM && - state != MOUNT_UNMOUNTING_SIGKILL && - state != MOUNT_REMOUNTING_SIGTERM && - state != MOUNT_REMOUNTING_SIGKILL) { - unit_unwatch_timer(UNIT(m), &m->timer_watch); - mount_unwatch_control_pid(m); - m->control_command = NULL; - m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; - } - - if (state == MOUNT_MOUNTED || - state == MOUNT_REMOUNTING) - mount_notify_automount(m, 0); - else if (state == MOUNT_DEAD || - state == MOUNT_UNMOUNTING || - state == MOUNT_MOUNTING_SIGTERM || - state == MOUNT_MOUNTING_SIGKILL || - state == MOUNT_REMOUNTING_SIGTERM || - state == MOUNT_REMOUNTING_SIGKILL || - state == MOUNT_UNMOUNTING_SIGTERM || - state == MOUNT_UNMOUNTING_SIGKILL || - state == MOUNT_FAILED) - mount_notify_automount(m, -ENODEV); - - if (state != old_state) - log_debug("%s changed %s -> %s", - m->meta.id, - mount_state_to_string(old_state), - mount_state_to_string(state)); - - unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], !m->reload_failure); - m->reload_failure = false; -} - -static int mount_coldplug(Unit *u) { - Mount *m = MOUNT(u); - MountState new_state = MOUNT_DEAD; - int r; - - assert(m); - assert(m->state == MOUNT_DEAD); - - if (m->deserialized_state != m->state) - new_state = m->deserialized_state; - else if (m->from_proc_self_mountinfo) - new_state = MOUNT_MOUNTED; - - if (new_state != m->state) { - - if (new_state == MOUNT_MOUNTING || - new_state == MOUNT_MOUNTING_DONE || - new_state == MOUNT_REMOUNTING || - new_state == MOUNT_UNMOUNTING || - new_state == MOUNT_MOUNTING_SIGTERM || - new_state == MOUNT_MOUNTING_SIGKILL || - new_state == MOUNT_UNMOUNTING_SIGTERM || - new_state == MOUNT_UNMOUNTING_SIGKILL || - new_state == MOUNT_REMOUNTING_SIGTERM || - new_state == MOUNT_REMOUNTING_SIGKILL) { - - if (m->control_pid <= 0) - return -EBADMSG; - - if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0) - return r; - - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) - return r; - } - - mount_set_state(m, new_state); - } - - return 0; -} - -static void mount_dump(Unit *u, FILE *f, const char *prefix) { - Mount *m = MOUNT(u); - MountParameters *p; - - assert(m); - assert(f); - - p = get_mount_parameters(m); - - fprintf(f, - "%sMount State: %s\n" - "%sWhere: %s\n" - "%sWhat: %s\n" - "%sFile System Type: %s\n" - "%sOptions: %s\n" - "%sFrom /etc/fstab: %s\n" - "%sFrom /proc/self/mountinfo: %s\n" - "%sFrom fragment: %s\n" - "%sDirectoryMode: %04o\n", - prefix, mount_state_to_string(m->state), - prefix, m->where, - prefix, strna(p->what), - prefix, strna(p->fstype), - prefix, strna(p->options), - prefix, yes_no(m->from_etc_fstab), - prefix, yes_no(m->from_proc_self_mountinfo), - prefix, yes_no(m->from_fragment), - prefix, m->directory_mode); - - if (m->control_pid > 0) - fprintf(f, - "%sControl PID: %lu\n", - prefix, (unsigned long) m->control_pid); - - exec_context_dump(&m->exec_context, f, prefix); -} - -static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { - pid_t pid; - int r; - - assert(m); - assert(c); - assert(_pid); - - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) - goto fail; - - if ((r = exec_spawn(c, - NULL, - &m->exec_context, - NULL, 0, - m->meta.manager->environment, - true, - true, - true, - m->meta.manager->confirm_spawn, - m->meta.cgroup_bondings, - m->meta.cgroup_attributes, - &pid)) < 0) - goto fail; - - if ((r = unit_watch_pid(UNIT(m), pid)) < 0) - /* FIXME: we need to do something here */ - goto fail; - - *_pid = pid; - - return 0; - -fail: - unit_unwatch_timer(UNIT(m), &m->timer_watch); - - return r; -} - -static void mount_enter_dead(Mount *m, bool success) { - assert(m); - - if (!success) - m->failure = true; - - mount_set_state(m, m->failure ? MOUNT_FAILED : MOUNT_DEAD); -} - -static void mount_enter_mounted(Mount *m, bool success) { - assert(m); - - if (!success) - m->failure = true; - - mount_set_state(m, MOUNT_MOUNTED); -} - -static void mount_enter_signal(Mount *m, MountState state, bool success) { - int r; - Set *pid_set = NULL; - bool wait_for_exit = false; - - assert(m); - - if (!success) - m->failure = true; - - if (m->exec_context.kill_mode != KILL_NONE) { - int sig = (state == MOUNT_MOUNTING_SIGTERM || - state == MOUNT_UNMOUNTING_SIGTERM || - state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL; - - if (m->control_pid > 0) { - if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH) - - log_warning("Failed to kill control process %li: %m", (long) m->control_pid); - else - wait_for_exit = true; - } - - if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) { - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { - r = -ENOMEM; - goto fail; - } - - /* Exclude the control pid from being killed via the cgroup */ - if (m->control_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) - goto fail; - - if ((r = cgroup_bonding_kill_list(m->meta.cgroup_bondings, sig, true, pid_set)) < 0) { - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) - log_warning("Failed to kill control group: %s", strerror(-r)); - } else if (r > 0) - wait_for_exit = true; - - set_free(pid_set); - pid_set = NULL; - } - } - - if (wait_for_exit) { - if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0) - goto fail; - - mount_set_state(m, state); - } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL) - mount_enter_mounted(m, true); - else - mount_enter_dead(m, true); - - return; - -fail: - log_warning("%s failed to kill processes: %s", m->meta.id, strerror(-r)); - - if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - - if (pid_set) - set_free(pid_set); -} - -static void mount_enter_unmounting(Mount *m, bool success) { - int r; - - assert(m); - - if (!success) - m->failure = true; - - m->control_command_id = MOUNT_EXEC_UNMOUNT; - m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; - - if ((r = exec_command_set( - m->control_command, - "/bin/umount", - m->where, - NULL)) < 0) - goto fail; - - mount_unwatch_control_pid(m); - - if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) - goto fail; - - mount_set_state(m, MOUNT_UNMOUNTING); - - return; - -fail: - log_warning("%s failed to run 'umount' task: %s", m->meta.id, strerror(-r)); - mount_enter_mounted(m, false); -} - -static void mount_enter_mounting(Mount *m) { - int r; - MountParameters *p; - - assert(m); - - m->control_command_id = MOUNT_EXEC_MOUNT; - m->control_command = m->exec_command + MOUNT_EXEC_MOUNT; - - mkdir_p(m->where, m->directory_mode); - - /* Create the source directory for bind-mounts if needed */ - p = get_mount_parameters_configured(m); - if (p && mount_is_bind(p)) - mkdir_p(p->what, m->directory_mode); - - if (m->from_fragment) - r = exec_command_set( - m->control_command, - "/bin/mount", - m->parameters_fragment.what, - m->where, - "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", - m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options, - NULL); - else if (m->from_etc_fstab) - r = exec_command_set( - m->control_command, - "/bin/mount", - m->where, - NULL); - else - r = -ENOENT; - - if (r < 0) - goto fail; - - mount_unwatch_control_pid(m); - - if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) - goto fail; - - mount_set_state(m, MOUNT_MOUNTING); - - return; - -fail: - log_warning("%s failed to run 'mount' task: %s", m->meta.id, strerror(-r)); - mount_enter_dead(m, false); -} - -static void mount_enter_mounting_done(Mount *m) { - assert(m); - - mount_set_state(m, MOUNT_MOUNTING_DONE); -} - -static void mount_enter_remounting(Mount *m, bool success) { - int r; - - assert(m); - - if (!success) - m->failure = true; - - m->control_command_id = MOUNT_EXEC_REMOUNT; - m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT; - - if (m->from_fragment) { - char *buf = NULL; - const char *o; - - if (m->parameters_fragment.options) { - if (!(buf = strappend("remount,", m->parameters_fragment.options))) { - r = -ENOMEM; - goto fail; - } - - o = buf; - } else - o = "remount"; - - r = exec_command_set( - m->control_command, - "/bin/mount", - m->parameters_fragment.what, - m->where, - "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto", - "-o", o, - NULL); - - free(buf); - } else if (m->from_etc_fstab) - r = exec_command_set( - m->control_command, - "/bin/mount", - m->where, - "-o", "remount", - NULL); - else - r = -ENOENT; - - if (r < 0) - goto fail; - - mount_unwatch_control_pid(m); - - if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0) - goto fail; - - mount_set_state(m, MOUNT_REMOUNTING); - - return; - -fail: - log_warning("%s failed to run 'remount' task: %s", m->meta.id, strerror(-r)); - m->reload_failure = true; - mount_enter_mounted(m, true); -} - -static int mount_start(Unit *u) { - Mount *m = MOUNT(u); - - assert(m); - - /* We cannot fulfill this request right now, try again later - * please! */ - if (m->state == MOUNT_UNMOUNTING || - m->state == MOUNT_UNMOUNTING_SIGTERM || - m->state == MOUNT_UNMOUNTING_SIGKILL || - m->state == MOUNT_MOUNTING_SIGTERM || - m->state == MOUNT_MOUNTING_SIGKILL) - return -EAGAIN; - - /* Already on it! */ - if (m->state == MOUNT_MOUNTING) - return 0; - - assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED); - - m->failure = false; - mount_enter_mounting(m); - return 0; -} - -static int mount_stop(Unit *u) { - Mount *m = MOUNT(u); - - assert(m); - - /* Already on it */ - if (m->state == MOUNT_UNMOUNTING || - m->state == MOUNT_UNMOUNTING_SIGKILL || - m->state == MOUNT_UNMOUNTING_SIGTERM || - m->state == MOUNT_MOUNTING_SIGTERM || - m->state == MOUNT_MOUNTING_SIGKILL) - return 0; - - assert(m->state == MOUNT_MOUNTING || - m->state == MOUNT_MOUNTING_DONE || - m->state == MOUNT_MOUNTED || - m->state == MOUNT_REMOUNTING || - m->state == MOUNT_REMOUNTING_SIGTERM || - m->state == MOUNT_REMOUNTING_SIGKILL); - - mount_enter_unmounting(m, true); - return 0; -} - -static int mount_reload(Unit *u) { - Mount *m = MOUNT(u); - - assert(m); - - if (m->state == MOUNT_MOUNTING_DONE) - return -EAGAIN; - - assert(m->state == MOUNT_MOUNTED); - - mount_enter_remounting(m, true); - return 0; -} - -static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { - Mount *m = MOUNT(u); - - assert(m); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", mount_state_to_string(m->state)); - unit_serialize_item(u, f, "failure", yes_no(m->failure)); - - if (m->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) m->control_pid); - - if (m->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id)); - - return 0; -} - -static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Mount *m = MOUNT(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - MountState state; - - if ((state = mount_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - m->deserialized_state = state; - } else if (streq(key, "failure")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse failure value %s", value); - else - m->failure = b || m->failure; - - } else if (streq(key, "control-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse control-pid value %s", value); - else - m->control_pid = pid; - } else if (streq(key, "control-command")) { - MountExecCommand id; - - if ((id = mount_exec_command_from_string(value)) < 0) - log_debug("Failed to parse exec-command value %s", value); - else { - m->control_command_id = id; - m->control_command = m->exec_command + id; - } - - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState mount_active_state(Unit *u) { - assert(u); - - return state_translation_table[MOUNT(u)->state]; -} - -static const char *mount_sub_state_to_string(Unit *u) { - assert(u); - - return mount_state_to_string(MOUNT(u)->state); -} - -static bool mount_check_gc(Unit *u) { - Mount *m = MOUNT(u); - - assert(m); - - return m->from_etc_fstab || m->from_proc_self_mountinfo; -} - -static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { - Mount *m = MOUNT(u); - bool success; - - assert(m); - assert(pid >= 0); - - if (pid != m->control_pid) - return; - - m->control_pid = 0; - - success = is_clean_exit(code, status); - m->failure = m->failure || !success; - - if (m->control_command) { - exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status); - m->control_command = NULL; - m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; - } - - log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s mount process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); - - /* Note that mount(8) returning and the kernel sending us a - * mount table change event might happen out-of-order. If an - * operation succeed we assume the kernel will follow soon too - * and already change into the resulting state. If it fails - * we check if the kernel still knows about the mount. and - * change state accordingly. */ - - switch (m->state) { - - case MOUNT_MOUNTING: - case MOUNT_MOUNTING_DONE: - case MOUNT_MOUNTING_SIGKILL: - case MOUNT_MOUNTING_SIGTERM: - - if (success) - mount_enter_mounted(m, true); - else if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - break; - - case MOUNT_REMOUNTING: - case MOUNT_REMOUNTING_SIGKILL: - case MOUNT_REMOUNTING_SIGTERM: - - m->reload_failure = !success; - if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, true); - else - mount_enter_dead(m, true); - - break; - - case MOUNT_UNMOUNTING: - case MOUNT_UNMOUNTING_SIGKILL: - case MOUNT_UNMOUNTING_SIGTERM: - - if (success) - mount_enter_dead(m, true); - else if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - break; - - default: - assert_not_reached("Uh, control process died at wrong time."); - } - - /* Notify clients about changed exit status */ - unit_add_to_dbus_queue(u); -} - -static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Mount *m = MOUNT(u); - - assert(m); - assert(elapsed == 1); - assert(w == &m->timer_watch); - - switch (m->state) { - - case MOUNT_MOUNTING: - case MOUNT_MOUNTING_DONE: - log_warning("%s mounting timed out. Stopping.", u->meta.id); - mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, false); - break; - - case MOUNT_REMOUNTING: - log_warning("%s remounting timed out. Stopping.", u->meta.id); - m->reload_failure = true; - mount_enter_mounted(m, true); - break; - - case MOUNT_UNMOUNTING: - log_warning("%s unmounting timed out. Stopping.", u->meta.id); - mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, false); - break; - - case MOUNT_MOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { - log_warning("%s mounting timed out. Killing.", u->meta.id); - mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, false); - } else { - log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - - if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - } - break; - - case MOUNT_REMOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { - log_warning("%s remounting timed out. Killing.", u->meta.id); - mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, false); - } else { - log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - - if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - } - break; - - case MOUNT_UNMOUNTING_SIGTERM: - if (m->exec_context.send_sigkill) { - log_warning("%s unmounting timed out. Killing.", u->meta.id); - mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, false); - } else { - log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - - if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - } - break; - - case MOUNT_MOUNTING_SIGKILL: - case MOUNT_REMOUNTING_SIGKILL: - case MOUNT_UNMOUNTING_SIGKILL: - log_warning("%s mount process still around after SIGKILL. Ignoring.", u->meta.id); - - if (m->from_proc_self_mountinfo) - mount_enter_mounted(m, false); - else - mount_enter_dead(m, false); - break; - - default: - assert_not_reached("Timeout at wrong time."); - } -} - -static int mount_add_one( - Manager *m, - const char *what, - const char *where, - const char *options, - const char *fstype, - int passno, - bool from_proc_self_mountinfo, - bool set_flags) { - int r; - Unit *u; - bool delete; - char *e, *w = NULL, *o = NULL, *f = NULL; - MountParameters *p; - - assert(m); - assert(what); - assert(where); - assert(options); - assert(fstype); - - assert(!set_flags || from_proc_self_mountinfo); - - /* Ignore API mount points. They should never be referenced in - * dependencies ever. */ - if (mount_point_is_api(where) || mount_point_ignore(where)) - return 0; - - if (streq(fstype, "autofs")) - return 0; - - /* probably some kind of swap, ignore */ - if (!is_path(where)) - return 0; - - if (!(e = unit_name_from_path(where, ".mount"))) - return -ENOMEM; - - if (!(u = manager_get_unit(m, e))) { - delete = true; - - if (!(u = unit_new(m))) { - free(e); - return -ENOMEM; - } - - r = unit_add_name(u, e); - free(e); - - if (r < 0) - goto fail; - - if (!(MOUNT(u)->where = strdup(where))) { - r = -ENOMEM; - goto fail; - } - - unit_add_to_load_queue(u); - } else { - delete = false; - free(e); - } - - if (!(w = strdup(what)) || - !(o = strdup(options)) || - !(f = strdup(fstype))) { - r = -ENOMEM; - goto fail; - } - - if (from_proc_self_mountinfo) { - p = &MOUNT(u)->parameters_proc_self_mountinfo; - - if (set_flags) { - MOUNT(u)->is_mounted = true; - MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo; - MOUNT(u)->just_changed = !streq_ptr(p->options, o); - } - - MOUNT(u)->from_proc_self_mountinfo = true; - } else { - p = &MOUNT(u)->parameters_etc_fstab; - MOUNT(u)->from_etc_fstab = true; - } - - free(p->what); - p->what = w; - - free(p->options); - p->options = o; - - free(p->fstype); - p->fstype = f; - - p->passno = passno; - - unit_add_to_dbus_queue(u); - - return 0; - -fail: - free(w); - free(o); - free(f); - - if (delete && u) - unit_free(u); - - return r; -} - -static int mount_find_pri(char *options) { - char *end, *pri; - unsigned long r; - - if (!(pri = mount_test_option(options, "pri"))) - return 0; - - pri += 4; - - errno = 0; - r = strtoul(pri, &end, 10); - - if (errno != 0) - return -errno; - - if (end == pri || (*end != ',' && *end != 0)) - return -EINVAL; - - return (int) r; -} - -static int mount_load_etc_fstab(Manager *m) { - FILE *f; - int r = 0; - struct mntent* me; - - assert(m); - - errno = 0; - if (!(f = setmntent("/etc/fstab", "r"))) - return -errno; - - while ((me = getmntent(f))) { - char *where, *what; - int k; - - if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) { - r = -ENOMEM; - goto finish; - } - - if (!(where = strdup(me->mnt_dir))) { - free(what); - r = -ENOMEM; - goto finish; - } - - if (what[0] == '/') - path_kill_slashes(what); - - if (where[0] == '/') - path_kill_slashes(where); - - if (streq(me->mnt_type, "swap")) { - int pri; - - if ((pri = mount_find_pri(me->mnt_opts)) < 0) - k = pri; - else - k = swap_add_one(m, - what, - NULL, - pri, - !!mount_test_option(me->mnt_opts, "noauto"), - !!mount_test_option(me->mnt_opts, "nofail"), - !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"), - false); - } else - k = mount_add_one(m, what, where, me->mnt_opts, me->mnt_type, me->mnt_passno, false, false); - - free(what); - free(where); - - if (r < 0) - r = k; - } - -finish: - - endmntent(f); - return r; -} - -static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { - int r = 0; - unsigned i; - char *device, *path, *options, *options2, *fstype, *d, *p, *o; - - assert(m); - - rewind(m->proc_self_mountinfo); - - for (i = 1;; i++) { - int k; - - device = path = options = options2 = fstype = d = p = o = NULL; - - if ((k = fscanf(m->proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%ms" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%ms " /* (9) file system type */ - "%ms" /* (10) mount source */ - "%ms" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &path, - &options, - &fstype, - &device, - &options2)) != 5) { - - if (k == EOF) - break; - - log_warning("Failed to parse /proc/self/mountinfo:%u.", i); - goto clean_up; - } - - if (asprintf(&o, "%s,%s", options, options2) < 0) { - r = -ENOMEM; - goto finish; - } - - if (!(d = cunescape(device)) || - !(p = cunescape(path))) { - r = -ENOMEM; - goto finish; - } - - if ((k = mount_add_one(m, d, p, o, fstype, 0, true, set_flags)) < 0) - r = k; - -clean_up: - free(device); - free(path); - free(options); - free(options2); - free(fstype); - free(d); - free(p); - free(o); - } - -finish: - free(device); - free(path); - free(options); - free(options2); - free(fstype); - free(d); - free(p); - free(o); - - return r; -} - -static void mount_shutdown(Manager *m) { - assert(m); - - if (m->proc_self_mountinfo) { - fclose(m->proc_self_mountinfo); - m->proc_self_mountinfo = NULL; - } -} - -static int mount_enumerate(Manager *m) { - int r; - struct epoll_event ev; - assert(m); - - if (!m->proc_self_mountinfo) { - if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"))) - return -errno; - - m->mount_watch.type = WATCH_MOUNT; - m->mount_watch.fd = fileno(m->proc_self_mountinfo); - - zero(ev); - ev.events = EPOLLPRI; - ev.data.ptr = &m->mount_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0) - return -errno; - } - - if ((r = mount_load_etc_fstab(m)) < 0) - goto fail; - - if ((r = mount_load_proc_self_mountinfo(m, false)) < 0) - goto fail; - - return 0; - -fail: - mount_shutdown(m); - return r; -} - -void mount_fd_event(Manager *m, int events) { - Meta *meta; - int r; - - assert(m); - assert(events & EPOLLPRI); - - /* The manager calls this for every fd event happening on the - * /proc/self/mountinfo file, which informs us about mounting - * table changes */ - - if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) { - log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r)); - - /* Reset flags, just in case, for later calls */ - LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_MOUNT]) { - Mount *mount = (Mount*) meta; - - mount->is_mounted = mount->just_mounted = mount->just_changed = false; - } - - return; - } - - manager_dispatch_load_queue(m); - - LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_MOUNT]) { - Mount *mount = (Mount*) meta; - - if (!mount->is_mounted) { - /* This has just been unmounted. */ - - mount->from_proc_self_mountinfo = false; - - switch (mount->state) { - - case MOUNT_MOUNTED: - mount_enter_dead(mount, true); - break; - - default: - mount_set_state(mount, mount->state); - break; - - } - - } else if (mount->just_mounted || mount->just_changed) { - - /* New or changed mount entry */ - - switch (mount->state) { - - case MOUNT_DEAD: - case MOUNT_FAILED: - mount_enter_mounted(mount, true); - break; - - case MOUNT_MOUNTING: - mount_enter_mounting_done(mount); - break; - - default: - /* Nothing really changed, but let's - * issue an notification call - * nonetheless, in case somebody is - * waiting for this. (e.g. file system - * ro/rw remounts.) */ - mount_set_state(mount, mount->state); - break; - } - } - - /* Reset the flags for later calls */ - mount->is_mounted = mount->just_mounted = mount->just_changed = false; - } -} - -static void mount_reset_failed(Unit *u) { - Mount *m = MOUNT(u); - - assert(m); - - if (m->state == MOUNT_FAILED) - mount_set_state(m, MOUNT_DEAD); - - m->failure = false; -} - -static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { - Mount *m = MOUNT(u); - int r = 0; - Set *pid_set = NULL; - - assert(m); - - if (who == KILL_MAIN) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes"); - return -ESRCH; - } - - if (m->control_pid <= 0 && who == KILL_CONTROL) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); - return -ESRCH; - } - - if (who == KILL_CONTROL || who == KILL_ALL) - if (m->control_pid > 0) - if (kill(m->control_pid, signo) < 0) - r = -errno; - - if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) { - int q; - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - /* Exclude the control pid from being killed via the cgroup */ - if (m->control_pid > 0) - if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) { - r = q; - goto finish; - } - - if ((q = cgroup_bonding_kill_list(m->meta.cgroup_bondings, signo, false, pid_set)) < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - } - -finish: - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const mount_state_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = "dead", - [MOUNT_MOUNTING] = "mounting", - [MOUNT_MOUNTING_DONE] = "mounting-done", - [MOUNT_MOUNTED] = "mounted", - [MOUNT_REMOUNTING] = "remounting", - [MOUNT_UNMOUNTING] = "unmounting", - [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", - [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", - [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", - [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", - [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", - [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", - [MOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); - -static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { - [MOUNT_EXEC_MOUNT] = "ExecMount", - [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", - [MOUNT_EXEC_REMOUNT] = "ExecRemount", -}; - -DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand); - -const UnitVTable mount_vtable = { - .suffix = ".mount", - .sections = - "Unit\0" - "Mount\0" - "Install\0", - - .no_alias = true, - .no_instances = true, - .show_status = true, - - .init = mount_init, - .load = mount_load, - .done = mount_done, - - .coldplug = mount_coldplug, - - .dump = mount_dump, - - .start = mount_start, - .stop = mount_stop, - .reload = mount_reload, - - .kill = mount_kill, - - .serialize = mount_serialize, - .deserialize_item = mount_deserialize_item, - - .active_state = mount_active_state, - .sub_state_to_string = mount_sub_state_to_string, - - .check_gc = mount_check_gc, - - .sigchld_event = mount_sigchld_event, - .timer_event = mount_timer_event, - - .reset_failed = mount_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Mount", - .bus_message_handler = bus_mount_message_handler, - .bus_invalidating_properties = bus_mount_invalidating_properties, - - .enumerate = mount_enumerate, - .shutdown = mount_shutdown -}; diff --git a/src/mount.h b/src/mount.h deleted file mode 100644 index 7c5d9d1..0000000 --- a/src/mount.h +++ /dev/null @@ -1,110 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomounthfoo -#define foomounthfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Mount Mount; - -#include "unit.h" - -typedef enum MountState { - MOUNT_DEAD, - MOUNT_MOUNTING, /* /bin/mount is running, but the mount is not done yet. */ - MOUNT_MOUNTING_DONE, /* /bin/mount is running, and the mount is done. */ - MOUNT_MOUNTED, - MOUNT_REMOUNTING, - MOUNT_UNMOUNTING, - MOUNT_MOUNTING_SIGTERM, - MOUNT_MOUNTING_SIGKILL, - MOUNT_REMOUNTING_SIGTERM, - MOUNT_REMOUNTING_SIGKILL, - MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL, - MOUNT_FAILED, - _MOUNT_STATE_MAX, - _MOUNT_STATE_INVALID = -1 -} MountState; - -typedef enum MountExecCommand { - MOUNT_EXEC_MOUNT, - MOUNT_EXEC_UNMOUNT, - MOUNT_EXEC_REMOUNT, - _MOUNT_EXEC_COMMAND_MAX, - _MOUNT_EXEC_COMMAND_INVALID = -1 -} MountExecCommand; - -typedef struct MountParameters { - char *what; - char *options; - char *fstype; - int passno; -} MountParameters; - -struct Mount { - Meta meta; - - char *where; - - MountParameters parameters_etc_fstab; - MountParameters parameters_proc_self_mountinfo; - MountParameters parameters_fragment; - - bool from_etc_fstab:1; - bool from_proc_self_mountinfo:1; - bool from_fragment:1; - - /* Used while looking for mount points that vanished or got - * added from/to /proc/self/mountinfo */ - bool is_mounted:1; - bool just_mounted:1; - bool just_changed:1; - - bool failure:1; - bool reload_failure:1; - - mode_t directory_mode; - - usec_t timeout_usec; - - ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX]; - ExecContext exec_context; - - MountState state, deserialized_state; - - ExecCommand* control_command; - MountExecCommand control_command_id; - pid_t control_pid; - - Watch timer_watch; -}; - -extern const UnitVTable mount_vtable; - -void mount_fd_event(Manager *m, int events); - -const char* mount_state_to_string(MountState i); -MountState mount_state_from_string(const char *s); - -const char* mount_exec_command_to_string(MountExecCommand i); -MountExecCommand mount_exec_command_from_string(const char *s); - -#endif diff --git a/src/namespace.c b/src/namespace.c deleted file mode 100644 index 54b22f4..0000000 --- a/src/namespace.c +++ /dev/null @@ -1,334 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "strv.h" -#include "util.h" -#include "namespace.h" -#include "missing.h" - -typedef enum PathMode { - /* This is ordered by priority! */ - INACCESSIBLE, - READONLY, - PRIVATE, - READWRITE -} PathMode; - -typedef struct Path { - const char *path; - PathMode mode; -} Path; - -static int append_paths(Path **p, char **strv, PathMode mode) { - char **i; - - STRV_FOREACH(i, strv) { - - if (!path_is_absolute(*i)) - return -EINVAL; - - (*p)->path = *i; - (*p)->mode = mode; - (*p)++; - } - - return 0; -} - -static int path_compare(const void *a, const void *b) { - const Path *p = a, *q = b; - - if (path_equal(p->path, q->path)) { - - /* If the paths are equal, check the mode */ - if (p->mode < q->mode) - return -1; - - if (p->mode > q->mode) - return 1; - - return 0; - } - - /* If the paths are not equal, then order prefixes first */ - if (path_startswith(p->path, q->path)) - return 1; - - if (path_startswith(q->path, p->path)) - return -1; - - return 0; -} - -static void drop_duplicates(Path *p, unsigned *n, bool *need_inaccessible, bool *need_private) { - Path *f, *t, *previous; - - assert(p); - assert(n); - assert(need_inaccessible); - assert(need_private); - - for (f = p, t = p, previous = NULL; f < p+*n; f++) { - - if (previous && path_equal(f->path, previous->path)) - continue; - - t->path = f->path; - t->mode = f->mode; - - if (t->mode == PRIVATE) - *need_private = true; - - if (t->mode == INACCESSIBLE) - *need_inaccessible = true; - - previous = t; - - t++; - } - - *n = t - p; -} - -static int apply_mount(Path *p, const char *root_dir, const char *inaccessible_dir, const char *private_dir, unsigned long flags) { - const char *what; - char *where; - int r; - - assert(p); - assert(root_dir); - assert(inaccessible_dir); - assert(private_dir); - - if (!(where = strappend(root_dir, p->path))) - return -ENOMEM; - - switch (p->mode) { - - case INACCESSIBLE: - what = inaccessible_dir; - flags |= MS_RDONLY; - break; - - case READONLY: - flags |= MS_RDONLY; - /* Fall through */ - - case READWRITE: - what = p->path; - break; - - case PRIVATE: - what = private_dir; - break; - - default: - assert_not_reached("Unknown mode"); - } - - if ((r = mount(what, where, NULL, MS_BIND|MS_REC, NULL)) >= 0) { - log_debug("Successfully mounted %s to %s", what, where); - - /* The bind mount will always inherit the original - * flags. If we want to set any flag we need - * to do so in a second independent step. */ - if (flags) - r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL); - - /* Avoid exponential growth of trees */ - if (r >= 0 && path_equal(p->path, "/")) - r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_UNBINDABLE|flags, NULL); - - if (r < 0) { - r = -errno; - umount2(where, MNT_DETACH); - } - } - - free(where); - return r; -} - -int setup_namespace( - char **writable, - char **readable, - char **inaccessible, - bool private_tmp, - unsigned long flags) { - - char - tmp_dir[] = "/tmp/systemd-namespace-XXXXXX", - root_dir[] = "/tmp/systemd-namespace-XXXXXX/root", - old_root_dir[] = "/tmp/systemd-namespace-XXXXXX/root/tmp/old-root-XXXXXX", - inaccessible_dir[] = "/tmp/systemd-namespace-XXXXXX/inaccessible", - private_dir[] = "/tmp/systemd-namespace-XXXXXX/private"; - - Path *paths, *p; - unsigned n; - bool need_private = false, need_inaccessible = false; - bool remove_tmp = false, remove_root = false, remove_old_root = false, remove_inaccessible = false, remove_private = false; - int r; - const char *t; - - n = - strv_length(writable) + - strv_length(readable) + - strv_length(inaccessible) + - (private_tmp ? 2 : 1); - - if (!(paths = new(Path, n))) - return -ENOMEM; - - p = paths; - if ((r = append_paths(&p, writable, READWRITE)) < 0 || - (r = append_paths(&p, readable, READONLY)) < 0 || - (r = append_paths(&p, inaccessible, INACCESSIBLE)) < 0) - goto fail; - - if (private_tmp) { - p->path = "/tmp"; - p->mode = PRIVATE; - p++; - } - - p->path = "/"; - p->mode = READWRITE; - p++; - - assert(paths + n == p); - - qsort(paths, n, sizeof(Path), path_compare); - drop_duplicates(paths, &n, &need_inaccessible, &need_private); - - if (!mkdtemp(tmp_dir)) { - r = -errno; - goto fail; - } - remove_tmp = true; - - memcpy(root_dir, tmp_dir, sizeof(tmp_dir)-1); - if (mkdir(root_dir, 0777) < 0) { - r = -errno; - goto fail; - } - remove_root = true; - - if (need_inaccessible) { - memcpy(inaccessible_dir, tmp_dir, sizeof(tmp_dir)-1); - if (mkdir(inaccessible_dir, 0) < 0) { - r = -errno; - goto fail; - } - remove_inaccessible = true; - } - - if (need_private) { - memcpy(private_dir, tmp_dir, sizeof(tmp_dir)-1); - if (mkdir(private_dir, 0777 + S_ISVTX) < 0) { - r = -errno; - goto fail; - } - remove_private = true; - } - - if (unshare(CLONE_NEWNS) < 0) { - r = -errno; - goto fail; - } - - /* We assume that by default mount events from us won't be - * propagated to the root namespace. */ - - for (p = paths; p < paths + n; p++) - if ((r = apply_mount(p, root_dir, inaccessible_dir, private_dir, flags)) < 0) - goto undo_mounts; - - memcpy(old_root_dir, tmp_dir, sizeof(tmp_dir)-1); - if (!mkdtemp(old_root_dir)) { - r = -errno; - goto undo_mounts; - } - remove_old_root = true; - - if (chdir(root_dir) < 0) { - r = -errno; - goto undo_mounts; - } - - if (pivot_root(root_dir, old_root_dir) < 0) { - r = -errno; - goto undo_mounts; - } - - t = old_root_dir + sizeof(root_dir) - 1; - if (umount2(t, MNT_DETACH) < 0) - /* At this point it's too late to turn anything back, - * since we are already in the new root. */ - return -errno; - - if (rmdir(t) < 0) - return -errno; - - return 0; - -undo_mounts: - - for (p--; p >= paths; p--) { - char full_path[PATH_MAX]; - - snprintf(full_path, sizeof(full_path), "%s%s", root_dir, p->path); - char_array_0(full_path); - - umount2(full_path, MNT_DETACH); - } - -fail: - if (remove_old_root) - rmdir(old_root_dir); - - if (remove_inaccessible) - rmdir(inaccessible_dir); - - if (remove_private) - rmdir(private_dir); - - if (remove_root) - rmdir(root_dir); - - if (remove_tmp) - rmdir(tmp_dir); - - free(paths); - - return r; -} diff --git a/src/namespace.h b/src/namespace.h deleted file mode 100644 index 7cf1ded..0000000 --- a/src/namespace.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foonamespacehfoo -#define foonamespacehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -int setup_namespace( - char **writable, - char **readable, - char **inaccessible, - bool private_tmp, - unsigned long flags); - -#endif diff --git a/src/network/.gitignore b/src/network/.gitignore new file mode 100644 index 0000000..8858596 --- /dev/null +++ b/src/network/.gitignore @@ -0,0 +1,2 @@ +/networkd-network-gperf.c +/networkd-netdev-gperf.c diff --git a/src/network/Makefile b/src/network/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/network/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c new file mode 100644 index 0000000..a637739 --- /dev/null +++ b/src/network/networkd-address.c @@ -0,0 +1,418 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "networkd.h" + +#include "utf8.h" +#include "util.h" +#include "conf-parser.h" +#include "net-util.h" + +int address_new_static(Network *network, unsigned section, Address **ret) { + _cleanup_address_free_ Address *address = NULL; + + if (section) { + uint64_t key = section; + address = hashmap_get(network->addresses_by_section, &key); + if (address) { + *ret = address; + address = NULL; + + return 0; + } + } + + address = new0(Address, 1); + if (!address) + return -ENOMEM; + + address->family = AF_UNSPEC; + + address->network = network; + + LIST_PREPEND(static_addresses, network->static_addresses, address); + + if (section) { + address->section = section; + hashmap_put(network->addresses_by_section, &address->section, address); + } + + *ret = address; + address = NULL; + + return 0; +} + +int address_new_dynamic(Address **ret) { + _cleanup_address_free_ Address *address = NULL; + + address = new0(Address, 1); + if (!address) + return -ENOMEM; + + address->family = AF_UNSPEC; + + *ret = address; + address = NULL; + + return 0; +} + +void address_free(Address *address) { + if (!address) + return; + + if (address->network) { + LIST_REMOVE(static_addresses, address->network->static_addresses, address); + + if (address->section) + hashmap_remove(address->network->addresses_by_section, + &address->section); + } + + free(address); +} + +int address_drop(Address *address, Link *link, + sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(address); + assert(address->family == AF_INET || address->family == AF_INET6); + assert(link); + assert(link->ifindex > 0); + assert(link->manager); + assert(link->manager->rtnl); + + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, + link->ifindex, address->family); + if (r < 0) { + log_error("Could not allocate RTM_DELADDR message: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + if (r < 0) { + log_error("Could not set prefixlen: %s", strerror(-r)); + return r; + } + + if (address->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); + else if (address->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); + if (r < 0) { + log_error("Could not append IFA_LOCAL attribute: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + log_error("Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +int address_configure(Address *address, Link *link, + sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(address); + assert(address->family == AF_INET || address->family == AF_INET6); + assert(link); + assert(link->ifindex > 0); + assert(link->manager); + assert(link->manager->rtnl); + + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, + link->ifindex, address->family); + if (r < 0) { + log_error("Could not allocate RTM_NEWADDR message: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + if (r < 0) { + log_error("Could not set prefixlen: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT); + if (r < 0) { + log_error("Could not set flags: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_UNIVERSE); + if (r < 0) { + log_error("Could not set scope: %s", strerror(-r)); + return r; + } + + if (address->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); + else if (address->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); + if (r < 0) { + log_error("Could not append IFA_LOCAL attribute: %s", + strerror(-r)); + return r; + } + + if (address->family == AF_INET) { + r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); + if (r < 0) { + log_error("Could not append IFA_BROADCAST attribute: %s", + strerror(-r)); + return r; + } + } + + if (address->label) { + r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label); + if (r < 0) { + log_error("Could not append IFA_LABEL attribute: %s", + strerror(-r)); + return r; + } + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + log_error("Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +int config_parse_dns(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Address **dns = data; + _cleanup_address_free_ Address *n = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_dynamic(&n); + if (r < 0) + return r; + + r = net_parse_inaddr(rvalue, &n->family, &n->in_addr); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "DNS address is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + *dns = n; + n = NULL; + + return 0; +} + +int config_parse_broadcast(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_address_free_ Address *n = NULL; + _cleanup_free_ char *address = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_static(network, section_line, &n); + if (r < 0) + return r; + + if (n->family == AF_INET6) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Broadcast is not valid for IPv6 addresses, " + "ignoring assignment: %s", address); + return 0; + } + + r = net_parse_inaddr(address, &n->family, &n->broadcast); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Broadcast is invalid, ignoring assignment: %s", address); + return 0; + } + + n = NULL; + + return 0; +} + +int config_parse_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) { + Network *network = userdata; + _cleanup_address_free_ Address *n = NULL; + _cleanup_free_ char *address = NULL; + const char *e; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + if (streq(section, "Network")) { + /* we are not in an Address section, so treat + * this as the special '0' section */ + section_line = 0; + } + + r = address_new_static(network, section_line, &n); + if (r < 0) + return r; + + /* Address=address/prefixlen */ + + /* prefixlen */ + e = strchr(rvalue, '/'); + if (e) { + unsigned i; + r = safe_atou(e + 1, &i); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Interface prefix length is invalid, " + "ignoring assignment: %s", e + 1); + return 0; + } + + n->prefixlen = (unsigned char) i; + + address = strndup(rvalue, e - rvalue); + if (!address) + return log_oom(); + } else { + address = strdup(rvalue); + if (!address) + return log_oom(); + } + + r = net_parse_inaddr(address, &n->family, &n->in_addr); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Address is invalid, ignoring assignment: %s", address); + return 0; + } + + if (n->family == AF_INET && !n->broadcast.s_addr) + n->broadcast.s_addr = n->in_addr.in.s_addr | + htonl(0xfffffffflu >> n->prefixlen); + + n = NULL; + + return 0; +} + +int config_parse_label(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_address_free_ Address *n = NULL; + char *label; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_static(network, section_line, &n); + if (r < 0) + return r; + + label = strdup(rvalue); + if (!label) + return log_oom(); + + if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Interface label is not ASCII clean or is too" + " long, ignoring assignment: %s", rvalue); + free(label); + return 0; + } + + free(n->label); + if (*label) + n->label = label; + else { + free(label); + n->label = NULL; + } + + n = NULL; + + return 0; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c new file mode 100644 index 0000000..1f495b3 --- /dev/null +++ b/src/network/networkd-link.c @@ -0,0 +1,1049 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "networkd.h" +#include "libudev-private.h" +#include "util.h" +#include "bus-util.h" +#include "net-util.h" + +int link_new(Manager *manager, struct udev_device *device, Link **ret) { + _cleanup_link_free_ Link *link = NULL; + const char *mac; + struct ether_addr *mac_addr; + const char *ifname; + int r; + + assert(manager); + assert(manager->links); + assert(device); + assert(ret); + + link = new0(Link, 1); + if (!link) + return -ENOMEM; + + link->manager = manager; + link->state = _LINK_STATE_INVALID; + + link->ifindex = udev_device_get_ifindex(device); + if (link->ifindex <= 0) + return -EINVAL; + + mac = udev_device_get_sysattr_value(device, "address"); + if (mac) { + mac_addr = ether_aton(mac); + if (mac_addr) + memcpy(&link->mac, mac_addr, sizeof(struct ether_addr)); + } + + ifname = udev_device_get_sysname(device); + link->ifname = strdup(ifname); + + r = hashmap_put(manager->links, &link->ifindex, link); + if (r < 0) + return r; + + *ret = link; + link = NULL; + + return 0; +} + +void link_free(Link *link) { + if (!link) + return; + + assert(link->manager); + + sd_dhcp_client_free(link->dhcp_client); + sd_dhcp_lease_unref(link->dhcp_lease); + + hashmap_remove(link->manager->links, &link->ifindex); + + free(link->ifname); + + free(link); +} + +int link_get(Manager *m, int ifindex, Link **ret) { + Link *link; + uint64_t ifindex_64; + + assert(m); + assert(m->links); + assert(ifindex); + assert(ret); + + ifindex_64 = ifindex; + link = hashmap_get(m->links, &ifindex_64); + if (!link) + return -ENODEV; + + *ret = link; + + return 0; +} + +int link_add(Manager *m, struct udev_device *device, Link **ret) { + Link *link = NULL; + Network *network; + int r; + + assert(m); + assert(device); + + r = link_new(m, device, &link); + if (r < 0) + return r; + + *ret = link; + + r = network_get(m, device, &network); + if (r < 0) + return r == -ENOENT ? 0 : r; + + r = network_apply(m, network, link); + if (r < 0) + return r; + + return 0; +} + +static int link_enter_configured(Link *link) { + assert(link); + assert(link->state == LINK_STATE_SETTING_ROUTES); + + log_info_link(link, "link configured"); + + link->state = LINK_STATE_CONFIGURED; + + return 0; +} + +static void link_enter_failed(Link *link) { + assert(link); + + log_warning_link(link, "failed"); + + link->state = LINK_STATE_FAILED; +} + +static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(link->route_messages > 0); + assert(link->state == LINK_STATE_SETTING_ADDRESSES || + link->state == LINK_STATE_SETTING_ROUTES || + link->state == LINK_STATE_FAILED); + + link->route_messages --; + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -EEXIST) + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not set route: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + + /* we might have received an old reply after moving back to SETTING_ADDRESSES, + * ignore it */ + if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) { + log_debug_link(link, "routes set"); + link_enter_configured(link); + } + + return 1; +} + +static int link_enter_set_routes(Link *link) { + Route *rt; + int r; + + assert(link); + assert(link->network); + assert(link->state == LINK_STATE_SETTING_ADDRESSES); + + link->state = LINK_STATE_SETTING_ROUTES; + + if (!link->network->static_routes && !link->dhcp_lease) + return link_enter_configured(link); + + log_debug_link(link, "setting routes"); + + LIST_FOREACH(static_routes, rt, link->network->static_routes) { + r = route_configure(rt, link, &route_handler); + if (r < 0) { + log_warning_link(link, + "could not set routes: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + + link->route_messages ++; + } + + if (link->dhcp_lease) { + _cleanup_route_free_ Route *route = NULL; + struct in_addr gateway; + + r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); + if (r < 0) { + log_warning_link(link, "DHCP error: no router: %s", + strerror(-r)); + return r; + } + + r = route_new_dynamic(&route); + if (r < 0) { + log_error_link(link, "Could not allocate route: %s", + strerror(-r)); + return r; + } + + route->family = AF_INET; + route->in_addr.in = gateway; + + r = route_configure(route, link, &route_handler); + if (r < 0) { + log_warning_link(link, + "could not set routes: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + + link->route_messages ++; + } + + return 0; +} + +static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(m); + assert(link); + assert(link->ifname); + assert(link->addr_messages > 0); + assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED); + + link->addr_messages --; + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -EEXIST) + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not set address: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + + if (link->addr_messages == 0) { + log_debug_link(link, "addresses set"); + link_enter_set_routes(link); + } + + return 1; +} + +static int link_enter_set_addresses(Link *link) { + Address *ad; + int r; + + assert(link); + assert(link->network); + assert(link->state != _LINK_STATE_INVALID); + + link->state = LINK_STATE_SETTING_ADDRESSES; + + if (!link->network->static_addresses && !link->dhcp_lease) + return link_enter_set_routes(link); + + log_debug_link(link, "setting addresses"); + + LIST_FOREACH(static_addresses, ad, link->network->static_addresses) { + r = address_configure(ad, link, &address_handler); + if (r < 0) { + log_warning_link(link, + "could not set addresses: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + + link->addr_messages ++; + } + + if (link->dhcp_lease) { + _cleanup_address_free_ Address *address = NULL; + struct in_addr addr; + struct in_addr netmask; + unsigned prefixlen; + + r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); + if (r < 0) { + log_warning_link(link, "DHCP error: no address: %s", + strerror(-r)); + return r; + } + + r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); + if (r < 0) { + log_warning_link(link, "DHCP error: no netmask: %s", + strerror(-r)); + return r; + } + + prefixlen = net_netmask_to_prefixlen(&netmask); + + r = address_new_dynamic(&address); + if (r < 0) { + log_error_link(link, "Could not allocate address: %s", + strerror(-r)); + return r; + } + + address->family = AF_INET; + address->in_addr.in = addr; + address->prefixlen = prefixlen; + address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr; + + r = address_configure(address, link, &address_handler); + if (r < 0) { + log_warning_link(link, + "could not set addresses: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + + link->addr_messages ++; + } + + return 0; +} + +static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(m); + assert(link); + assert(link->ifname); + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -ENOENT) + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not drop address: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + + return 1; +} + +static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + int r; + + r = sd_bus_message_get_errno(m); + if (r < 0) + log_warning("Could not set hostname: %s", strerror(-r)); + + return 1; +} + +static int set_hostname(sd_bus *bus, const char *hostname) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r = 0; + + assert(hostname); + + log_debug("Setting transient hostname: '%s'", hostname); + + if (!bus) { /* TODO: replace by assert when we can rely on kdbus */ + log_info("Not connected to system bus, ignoring transient hostname."); + return 0; + } + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "SetHostname"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "sb", hostname, false); + if (r < 0) + return r; + + r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL); + if (r < 0) + log_error("Could not set transient hostname: %s", strerror(-r)); + + return r; +} + +static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(m); + assert(link); + assert(link->ifname); + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0) + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not set MTU: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + + return 1; +} + +static int link_set_mtu(Link *link, uint32_t mtu) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + + log_debug_link(link, "setting MTU: %" PRIu32, mtu); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, + RTM_SETLINK, link->ifindex); + if (r < 0) { + log_error_link(link, "Could not allocate RTM_SETLINK message"); + return r; + } + + r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu); + if (r < 0) { + log_error_link(link, "Could not append MTU: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL); + if (r < 0) { + log_error_link(link, + "Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int dhcp_lease_lost(Link *link) { + _cleanup_address_free_ Address *address = NULL; + struct in_addr addr; + struct in_addr netmask; + unsigned prefixlen; + int r; + + assert(link); + assert(link->dhcp_lease); + + log_warning_link(link, "DHCP lease lost"); + + r = address_new_dynamic(&address); + if (r >= 0) { + sd_dhcp_lease_get_address(link->dhcp_lease, &addr); + sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); + prefixlen = net_netmask_to_prefixlen(&netmask); + + address->family = AF_INET; + address->in_addr.in = addr; + address->prefixlen = prefixlen; + + address_drop(address, link, address_drop_handler); + } + + if (link->network->dhcp_mtu) { + uint16_t mtu; + + 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); + if (r < 0) { + log_warning_link(link, "DHCP error: could not reset MTU"); + link_enter_failed(link); + return r; + } + } + } + + if (link->network->dhcp_hostname) { + const char *hostname = NULL; + + r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); + if (r >= 0 && hostname) { + r = set_hostname(link->manager->bus, ""); + if (r < 0) + log_error("Failed to reset transient hostname"); + } + } + + link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); + + return 0; +} + +static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { + sd_dhcp_lease *lease; + struct in_addr address; + struct in_addr netmask; + struct in_addr gateway; + unsigned prefixlen; + struct in_addr *nameservers; + size_t nameservers_size; + int r; + + assert(client); + assert(link); + + r = sd_dhcp_client_get_lease(client, &lease); + if (r < 0) { + log_warning_link(link, "DHCP error: no lease: %s", + strerror(-r)); + return r; + } + + r = sd_dhcp_lease_get_address(lease, &address); + if (r < 0) { + log_warning_link(link, "DHCP error: no address: %s", + strerror(-r)); + return r; + } + + r = sd_dhcp_lease_get_netmask(lease, &netmask); + if (r < 0) { + log_warning_link(link, "DHCP error: no netmask: %s", + strerror(-r)); + return r; + } + + prefixlen = net_netmask_to_prefixlen(&netmask); + + r = sd_dhcp_lease_get_router(lease, &gateway); + if (r < 0) { + log_warning_link(link, "DHCP error: no router: %s", + strerror(-r)); + return r; + } + + log_struct_link(LOG_INFO, link, + "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", + link->ifname, + ADDRESS_FMT_VAL(address), + prefixlen, + ADDRESS_FMT_VAL(gateway), + "ADDRESS=%u.%u.%u.%u", + ADDRESS_FMT_VAL(address), + "PREFIXLEN=%u", + prefixlen, + "GATEWAY=%u.%u.%u.%u", + ADDRESS_FMT_VAL(gateway), + NULL); + + link->dhcp_lease = lease; + + if (link->network->dhcp_dns) { + r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size); + if (r >= 0) { + r = manager_update_resolv_conf(link->manager); + if (r < 0) + log_error("Failed to update resolv.conf"); + } + } + + if (link->network->dhcp_mtu) { + uint16_t mtu; + + r = sd_dhcp_lease_get_mtu(lease, &mtu); + if (r >= 0) { + r = link_set_mtu(link, mtu); + if (r < 0) + log_error_link(link, "Failed to set MTU " + "to %" PRIu16, mtu); + } + } + + if (link->network->dhcp_hostname) { + const char *hostname; + + r = sd_dhcp_lease_get_hostname(lease, &hostname); + if (r >= 0) { + r = set_hostname(link->manager->bus, hostname); + if (r < 0) + log_error("Failed to set transient hostname " + "to '%s'", hostname); + } + } + + link_enter_set_addresses(link); + + return 0; +} + +static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + + if (link->state == LINK_STATE_FAILED) + return; + + switch (event) { + case DHCP_EVENT_NO_LEASE: + log_debug_link(link, "IP address in use."); + break; + case DHCP_EVENT_EXPIRED: + case DHCP_EVENT_STOP: + case DHCP_EVENT_IP_CHANGE: + if (link->network->dhcp_critical) { + log_error_link(link, "DHCPv4 connection considered system critical, " + "ignoring request to reconfigure it."); + return; + } + + if (link->dhcp_lease) { + r = dhcp_lease_lost(link); + if (r < 0) { + link_enter_failed(link); + return; + } + } + + if (event == DHCP_EVENT_IP_CHANGE) { + r = dhcp_lease_acquired(client, link); + if (r < 0) { + link_enter_failed(link); + return; + } + } + + break; + case DHCP_EVENT_IP_ACQUIRE: + r = dhcp_lease_acquired(client, link); + if (r < 0) { + link_enter_failed(link); + return; + } + break; + default: + if (event < 0) + log_warning_link(link, "DHCP error: %s", strerror(-event)); + else + log_warning_link(link, "DHCP unknown event: %d", event); + break; + } + + return; +} + +static int link_acquire_conf(Link *link) { + int r; + + assert(link); + assert(link->network); + assert(link->network->dhcp); + assert(link->manager); + assert(link->manager->event); + + if (!link->dhcp_client) { + r = sd_dhcp_client_new(&link->dhcp_client); + if (r < 0) + return r; + + r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0); + if (r < 0) + return r; + + r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex); + if (r < 0) + return r; + + r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac); + if (r < 0) + return r; + + r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link); + if (r < 0) + return r; + + if (link->network->dhcp_mtu) { + r = sd_dhcp_client_set_request_option(link->dhcp_client, 26); + if (r < 0) + return r; + } + } + + log_debug_link(link, "acquiring DHCPv4 lease"); + + r = sd_dhcp_client_start(link->dhcp_client); + if (r < 0) + return r; + + return 0; +} + +static int link_update_flags(Link *link, unsigned flags) { + int r; + + assert(link); + assert(link->network); + + if (link->state == LINK_STATE_FAILED) + return 0; + + if (link->flags == flags) { + log_debug_link(link, "link status unchanged: %#.8x", flags); + return 0; + } + + if ((link->flags & IFF_UP) != (flags & IFF_UP)) + log_info_link(link, + "link is %s", flags & IFF_UP ? "up": "down"); + + if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) { + if (flags & IFF_LOWER_UP) { + log_info_link(link, "carrier on"); + + if (link->network->dhcp) { + r = link_acquire_conf(link); + if (r < 0) { + log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + } + } else { + log_info_link(link, "carrier off"); + + if (link->network->dhcp) { + r = sd_dhcp_client_stop(link->dhcp_client); + if (r < 0) { + log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r)); + link_enter_failed(link); + return r; + } + } + } + } + + log_debug_link(link, + "link status updated: %#.8x -> %#.8x", link->flags, flags); + + link->flags = flags; + + return 0; +} + +static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0) { + log_struct_link(LOG_ERR, link, + "MESSAGE=%s: could not bring up interface: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + link_enter_failed(link); + return 1; + } + + link_update_flags(link, link->flags | IFF_UP); + + return 1; +} + +static int link_up(Link *link) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + + log_debug_link(link, "bringing link up"); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, + RTM_SETLINK, link->ifindex); + if (r < 0) { + log_error_link(link, "Could not allocate RTM_SETLINK message"); + return r; + } + + r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP); + if (r < 0) { + log_error_link(link, "Could not set link flags: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL); + if (r < 0) { + log_error_link(link, + "Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int link_enslaved(Link *link) { + int r; + + assert(link); + assert(link->state == LINK_STATE_ENSLAVING); + assert(link->network); + + r = link_up(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + + if (!link->network->dhcp) + return link_enter_set_addresses(link); + + return 0; +} + +static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED); + assert(link->network); + + link->enslaving --; + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0) { + log_struct_link(LOG_ERR, link, + "MESSAGE=%s: could not enslave: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + link_enter_failed(link); + return 1; + } + + log_debug_link(link, "enslaved"); + + if (link->enslaving == 0) + link_enslaved(link); + + return 1; +} + +static int link_enter_enslave(Link *link) { + NetDev *vlan; + Iterator i; + int r; + + assert(link); + assert(link->network); + assert(link->state == _LINK_STATE_INVALID); + + link->state = LINK_STATE_ENSLAVING; + + if (!link->network->bridge && !link->network->bond && + hashmap_isempty(link->network->vlans)) + return link_enslaved(link); + + if (link->network->bridge) { + log_struct_link(LOG_DEBUG, link, + "MESSAGE=%s: enslaving by '%s'", + link->ifname, link->network->bridge->name, + NETDEV(link->network->bridge), + NULL); + + r = netdev_enslave(link->network->bridge, link, &enslave_handler); + if (r < 0) { + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not enslave by '%s': %s", + link->ifname, link->network->bridge->name, strerror(-r), + NETDEV(link->network->bridge), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving ++; + } + + HASHMAP_FOREACH(vlan, link->network->vlans, i) { + log_struct_link(LOG_DEBUG, link, + "MESSAGE=%s: enslaving by '%s'", + link->ifname, vlan->name, NETDEV(vlan), NULL); + + r = netdev_enslave(vlan, link, &enslave_handler); + if (r < 0) { + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not enslave by '%s': %s", + link->ifname, vlan->name, strerror(-r), + NETDEV(vlan), NULL); + link_enter_failed(link); + return r; + } + + link->enslaving ++; + } + + return 0; +} + +static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m, + void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + if (link->state == LINK_STATE_FAILED) + return 1; + + r = sd_rtnl_message_get_errno(m); + if (r < 0) { + log_struct_link(LOG_ERR, link, + "MESSAGE=%s: could not get state: %s", + link->ifname, strerror(-r), + "ERRNO=%d", -r, + NULL); + link_enter_failed(link); + return 1; + } + + log_debug_link(link, "got link state"); + + link_update(link, m); + + return 1; +} + +static int link_getlink(Link *link) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + + log_debug_link(link, "requesting link status"); + + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, + RTM_GETLINK, link->ifindex); + if (r < 0) { + log_error_link(link, "Could not allocate RTM_GETLINK message"); + return r; + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler, + link, 0, NULL); + if (r < 0) { + log_error_link(link, + "Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +int link_configure(Link *link) { + int r; + + assert(link); + assert(link->network); + assert(link->state == _LINK_STATE_INVALID); + + r = link_getlink(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + + return link_enter_enslave(link); +} + +int link_update(Link *link, sd_rtnl_message *m) { + unsigned flags; + void *data; + uint16_t type; + int r; + + assert(link); + assert(m); + + if (link->state == LINK_STATE_FAILED) + return 0; + + r = sd_rtnl_message_link_get_flags(m, &flags); + if (r < 0) { + log_warning_link(link, "Could not get link flags"); + return r; + } + + while (sd_rtnl_message_read(m, &type, &data) > 0) { + if (type == IFLA_MTU && link->network->dhcp && + link->network->dhcp_mtu && !link->original_mtu) { + link->original_mtu = *(uint16_t *) data; + log_debug_link(link, "saved original MTU: %" PRIu16, + link->original_mtu); + } + } + + return link_update_flags(link, flags); +} diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c new file mode 100644 index 0000000..c89adfb --- /dev/null +++ b/src/network/networkd-manager.c @@ -0,0 +1,464 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include + +#include "path-util.h" +#include "networkd.h" +#include "libudev-private.h" +#include "udev-util.h" +#include "rtnl-util.h" +#include "mkdir.h" +#include "virt.h" + +const char* const network_dirs[] = { + "/etc/systemd/network", + "/run/systemd/network", + "/usr/lib/systemd/network", +#ifdef HAVE_SPLIT_USER + "/lib/systemd/network", +#endif + NULL}; + +static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Manager *m = userdata; + + assert(m); + + log_received_signal(LOG_INFO, si); + + sd_event_exit(m->event, 0); + return 0; +} + +static int setup_signals(Manager *m) { + sigset_t mask; + int r; + + assert(m); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m); + if (r < 0) + return r; + + r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m); + if (r < 0) + return r; + + return 0; +} + +int manager_new(Manager **ret) { + _cleanup_manager_free_ Manager *m = NULL; + int r; + + m = new0(Manager, 1); + if (!m) + return -ENOMEM; + + r = sd_event_default(&m->event); + if (r < 0) + return r; + + sd_event_set_watchdog(m->event, true); + + r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR); + if (r < 0) + return r; + + r = sd_bus_default_system(&m->bus); + if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */ + return r; + + r = setup_signals(m); + if (r < 0) + return r; + + m->udev = udev_new(); + if (!m->udev) + return -ENOMEM; + + /* udev does not initialize devices inside containers, + * so we rely on them being already initialized before + * entering the container */ + if (detect_container(NULL) > 0) { + m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel"); + if (!m->udev_monitor) + return -ENOMEM; + } else { + m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); + if (!m->udev_monitor) + return -ENOMEM; + } + + m->links = hashmap_new(uint64_hash_func, uint64_compare_func); + if (!m->links) + return -ENOMEM; + + m->netdevs = hashmap_new(string_hash_func, string_compare_func); + if (!m->netdevs) + return -ENOMEM; + + LIST_HEAD_INIT(m->networks); + + *ret = m; + m = NULL; + + return 0; +} + +void manager_free(Manager *m) { + Network *network; + NetDev *netdev; + Link *link; + + if (!m) + return; + + udev_monitor_unref(m->udev_monitor); + udev_unref(m->udev); + sd_bus_unref(m->bus); + sd_event_source_unref(m->udev_event_source); + sd_event_source_unref(m->sigterm_event_source); + sd_event_source_unref(m->sigint_event_source); + sd_event_unref(m->event); + + while ((network = m->networks)) + network_free(network); + + while ((link = hashmap_first(m->links))) + link_free(link); + hashmap_free(m->links); + + while ((netdev = hashmap_first(m->netdevs))) + netdev_free(netdev); + hashmap_free(m->netdevs); + + sd_rtnl_unref(m->rtnl); + + free(m); +} + +int manager_load_config(Manager *m) { + int r; + + /* update timestamp */ + paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true); + + r = netdev_load(m); + if (r < 0) + return r; + + r = network_load(m); + if (r < 0) + return r; + + return 0; +} + +bool manager_should_reload(Manager *m) { + return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false); +} + +static int manager_process_link(Manager *m, struct udev_device *device) { + Link *link = NULL; + int r; + + assert(m); + assert(device); + + link_get(m, udev_device_get_ifindex(device), &link); + + if (streq_ptr(udev_device_get_action(device), "remove")) { + log_debug("%s: link removed", udev_device_get_sysname(device)); + + if (link) + link_free(link); + } else { + if (link) { + log_debug("%s: link already exists, ignoring", + link->ifname); + return 0; + } + + r = link_add(m, device, &link); + if (r < 0) { + log_error("%s: could not handle link: %s", + udev_device_get_sysname(device), + strerror(-r)); + } else + log_debug("%s: link (with ifindex %" PRIu64") added", + link->ifname, link->ifindex); + } + + return 0; +} + +int manager_udev_enumerate_links(Manager *m) { + _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; + struct udev_list_entry *item = NULL, *first = NULL; + int r; + + assert(m); + + e = udev_enumerate_new(m->udev); + if (!e) + return -ENOMEM; + + r = udev_enumerate_add_match_subsystem(e, "net"); + if (r < 0) + return r; + + /* udev does not initialize devices inside containers, + * so we rely on them being already initialized before + * entering the container */ + if (detect_container(NULL) <= 0) { + r = udev_enumerate_add_match_is_initialized(e); + if (r < 0) + return r; + } + + r = udev_enumerate_scan_devices(e); + if (r < 0) + return r; + + first = udev_enumerate_get_list_entry(e); + udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + int k; + + d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item)); + if (!d) + return -ENOMEM; + + k = manager_process_link(m, d); + if (k < 0) + r = k; + } + + return r; +} + +static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + struct udev_monitor *monitor = m->udev_monitor; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + + device = udev_monitor_receive_device(monitor); + if (!device) + return -ENOMEM; + + manager_process_link(m, device); + return 0; +} + +int manager_udev_listen(Manager *m) { + int r; + + r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL); + if (r < 0) { + log_error("Could not add udev monitor filter: %s", strerror(-r)); + return r; + } + + r = udev_monitor_enable_receiving(m->udev_monitor); + if (r < 0) { + log_error("Could not enable udev monitor"); + return r; + } + + r = sd_event_add_io(m->event, + &m->udev_event_source, + udev_monitor_get_fd(m->udev_monitor), + EPOLLIN, manager_dispatch_link_udev, + m); + if (r < 0) + return r; + + return 0; +} + +static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) { + Manager *m = userdata; + Link *link; + const char *name; + int r, ifindex; + + assert(rtnl); + assert(message); + assert(m); + + r = sd_rtnl_message_link_get_ifindex(message, &ifindex); + if (r < 0 || ifindex <= 0) { + log_debug("received RTM_NEWLINK message without valid ifindex"); + return 0; + } + + r = rtnl_message_link_get_ifname(message, &name); + if (r < 0) + log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME"); + else { + NetDev *netdev; + + r = netdev_get(m, name, &netdev); + if (r >= 0) { + r = netdev_set_ifindex(netdev, ifindex); + if (r < 0) + log_debug("could not set ifindex of netdev '%s' to %d: %s", + name, ifindex, strerror(-r)); + } + } + + r = link_get(m, ifindex, &link); + if (r < 0) { + log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex); + return 0; + } + + /* only track the status of links we want to manage */ + if (link->network) { + r = link_update(link, message); + if (r < 0) + return 0; + } else + log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname); + + return 1; +} + +int manager_rtnl_listen(Manager *m) { + int r; + + r = sd_rtnl_attach_event(m->rtnl, m->event, 0); + if (r < 0) + return r; + + r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m); + if (r < 0) + return r; + + return 0; +} + +int manager_bus_listen(Manager *m) { + int r; + + assert(m->event); + + if (!m->bus) /* TODO: drop when we can rely on kdbus */ + return 0; + + r = sd_bus_attach_event(m->bus, m->event, 0); + if (r < 0) + return r; + + return 0; +} + +static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) { + char buf[INET6_ADDRSTRLEN]; + const char *address; + + address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN); + if (!address) { + log_warning("Invalid DNS address. Ignoring."); + return; + } + + if (*count == MAXNS) + fputs("# Too many DNS servers configured, the following entries " + "will be ignored\n", f); + + fprintf(f, "nameserver %s\n", address); + + (*count) ++; +} + +int manager_update_resolv_conf(Manager *m) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + Link *link; + Iterator i; + unsigned count = 0; + const char *domainname = NULL; + int r; + + assert(m); + + r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0); + if (r < 0) + return r; + + r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n" + "# Third party programs must not access this file directly, but\n" + "# only through the symlink at /etc/resolv.conf. To manage\n" + "# resolv.conf(5) in a different way, replace the symlink by a\n" + "# static file or a different symlink.\n\n", f); + + HASHMAP_FOREACH(link, m->links, i) { + if (link->dhcp_lease) { + struct in_addr *nameservers; + size_t nameservers_size; + + if (link->network->dhcp_dns) { + r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size); + if (r >= 0) { + unsigned j; + + for (j = 0; j < nameservers_size; j++) + append_dns(f, &nameservers[j], AF_INET, &count); + } + } + + if (link->network->dhcp_domainname && !domainname) { + r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); + if (r >= 0) + fprintf(f, "domain %s\n", domainname); + } + } + } + + HASHMAP_FOREACH(link, m->links, i) + if (link->network && link->network->dns) + append_dns(f, &link->network->dns->in_addr.in, + link->network->dns->family, &count); + + fflush(f); + + if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) { + r = -errno; + unlink("/run/systemd/network/resolv.conf"); + unlink(temp_path); + return r; + } + + return 0; +} diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf new file mode 100644 index 0000000..7dd47f9 --- /dev/null +++ b/src/network/networkd-netdev-gperf.gperf @@ -0,0 +1,25 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd.h" +#include "net-util.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name network_netdev_gperf_hash +%define lookup-function-name network_netdev_gperf_lookup +%readonly-tables +%omit-struct-type +%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) +Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch) +NetDev.Description, config_parse_string, 0, offsetof(NetDev, description) +NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, name) +NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind) +VLAN.Id, config_parse_uint64, 0, offsetof(NetDev, vlanid) diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c new file mode 100644 index 0000000..05f21fa --- /dev/null +++ b/src/network/networkd-netdev.c @@ -0,0 +1,414 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd.h" +#include "net-util.h" +#include "path-util.h" +#include "conf-files.h" +#include "conf-parser.h" +#include "list.h" + +#define VLANID_MAX 4094 + +static const char* const netdev_kind_table[] = { + [NETDEV_KIND_BRIDGE] = "bridge", + [NETDEV_KIND_BOND] = "bond", + [NETDEV_KIND_VLAN] = "vlan", +}; + +DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); +DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind"); + +void netdev_free(NetDev *netdev) { + netdev_enslave_callback *callback; + + if (!netdev) + return; + + while ((callback = netdev->callbacks)) { + LIST_REMOVE(callbacks, netdev->callbacks, callback); + free(callback); + } + + if (netdev->name) + hashmap_remove(netdev->manager->netdevs, netdev->name); + + free(netdev->filename); + + free(netdev->description); + free(netdev->name); + + free(netdev); +} + +int netdev_get(Manager *manager, const char *name, NetDev **ret) { + NetDev *netdev; + + assert(manager); + assert(name); + assert(ret); + + netdev = hashmap_get(manager->netdevs, name); + if (!netdev) { + *ret = NULL; + return -ENOENT; + } + + *ret = netdev; + + return 0; +} + +static int netdev_enter_failed(NetDev *netdev) { + netdev->state = NETDEV_STATE_FAILED; + + return 0; +} + +static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(netdev); + assert(netdev->state == NETDEV_STATE_READY); + assert(netdev->manager); + assert(netdev->manager->rtnl); + assert(link); + assert(callback); + + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, + RTM_SETLINK, link->ifindex); + if (r < 0) { + log_error_netdev(netdev, + "Could not allocate RTM_SETLINK message: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_MASTER attribute: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + log_error_netdev(netdev, + "Could not send rtnetlink message: %s", + strerror(-r)); + return r; + } + + log_debug_netdev(netdev, "enslaving link '%s'", link->ifname); + + return 0; +} + +static int netdev_enter_ready(NetDev *netdev) { + netdev_enslave_callback *callback; + + assert(netdev); + assert(netdev->name); + + netdev->state = NETDEV_STATE_READY; + + log_info_netdev(netdev, "netdev ready"); + + LIST_FOREACH(callbacks, callback, netdev->callbacks) { + /* enslave the links that were attempted to be enslaved befor the + * link was ready */ + netdev_enslave_ready(netdev, callback->link, callback->callback); + } + + return 0; +} + +static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + NetDev *netdev = userdata; + int r; + + assert(netdev->state != _NETDEV_STATE_INVALID); + + r = sd_rtnl_message_get_errno(m); + if (r < 0) { + log_warning_netdev(netdev, "netdev failed: %s", strerror(-r)); + netdev_enter_failed(netdev); + + return 1; + } + + return 1; +} + +static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + const char *kind; + int r; + + assert(netdev); + assert(!(netdev->kind == NETDEV_KIND_VLAN) || + (link && callback && netdev->vlanid <= VLANID_MAX)); + assert(netdev->name); + assert(netdev->manager); + assert(netdev->manager->rtnl); + + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0); + if (r < 0) { + log_error_netdev(netdev, + "Could not allocate RTM_NEWLINK message: %s", + strerror(-r)); + return r; + } + + if (link) { + r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_LINK attribute: %s", + strerror(-r)); + return r; + } + } + + r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_IFNAME attribute: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_open_container(req, IFLA_LINKINFO); + if (r < 0) { + log_error_netdev(netdev, + "Could not open IFLA_LINKINFO container: %s", + strerror(-r)); + return r; + } + + kind = netdev_kind_to_string(netdev->kind); + if (!kind) { + log_error_netdev(netdev, "Invalid kind"); + return -EINVAL; + } + + r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_INFO_KIND attribute: %s", + strerror(-r)); + return r; + } + + if (netdev->vlanid <= VLANID_MAX) { + r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA); + if (r < 0) { + log_error_netdev(netdev, + "Could not open IFLA_INFO_DATA container: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_VLAN_ID attribute: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(req); + if (r < 0) { + log_error_netdev(netdev, + "Could not close IFLA_INFO_DATA container %s", + strerror(-r)); + return r; + } + } + + r = sd_rtnl_message_close_container(req); + if (r < 0) { + log_error_netdev(netdev, + "Could not close IFLA_LINKINFO container %s", + strerror(-r)); + return r; + } + + if (link) + r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL); + else + r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL); + if (r < 0) { + log_error_netdev(netdev, + "Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + log_debug_netdev(netdev, "creating netdev"); + + netdev->state = NETDEV_STATE_CREATING; + + return 0; +} + +int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { + if (netdev->kind == NETDEV_KIND_VLAN) + return netdev_create(netdev, link, callback); + + if (netdev->state == NETDEV_STATE_READY) { + netdev_enslave_ready(netdev, link, callback); + } else { + /* the netdev is not yet read, save this request for when it is*/ + netdev_enslave_callback *cb; + + cb = new0(netdev_enslave_callback, 1); + if (!cb) + return log_oom(); + + cb->callback = callback; + cb->link = link; + + LIST_PREPEND(callbacks, netdev->callbacks, cb); + } + + return 0; +} + +int netdev_set_ifindex(NetDev *netdev, int ifindex) { + assert(netdev); + assert(ifindex > 0); + + if (netdev->ifindex > 0) { + if (netdev->ifindex == ifindex) + return 0; + else + return -EEXIST; + } + + netdev->ifindex = ifindex; + + netdev_enter_ready(netdev); + + return 0; +} + +static int netdev_load_one(Manager *manager, const char *filename) { + _cleanup_netdev_free_ NetDev *netdev = NULL; + _cleanup_fclose_ FILE *file = NULL; + int r; + + assert(manager); + assert(filename); + + file = fopen(filename, "re"); + if (!file) { + if (errno == ENOENT) + return 0; + else + return errno; + } + + netdev = new0(NetDev, 1); + if (!netdev) + return log_oom(); + + netdev->manager = manager; + netdev->state = _NETDEV_STATE_INVALID; + netdev->kind = _NETDEV_KIND_INVALID; + netdev->vlanid = VLANID_MAX + 1; + + r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0", config_item_perf_lookup, + (void*) network_netdev_gperf_lookup, false, false, netdev); + if (r < 0) { + log_warning("Could not parse config file %s: %s", filename, strerror(-r)); + return r; + } + + if (netdev->kind == _NETDEV_KIND_INVALID) { + log_warning("NetDev without Kind configured in %s. Ignoring", filename); + return 0; + } + + if (!netdev->name) { + log_warning("NetDev without Name configured in %s. Ignoring", filename); + return 0; + } + + if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) { + log_warning("VLAN without valid Id configured in %s. Ignoring", filename); + return 0; + } + + netdev->filename = strdup(filename); + if (!netdev->filename) + return log_oom(); + + if (net_match_config(NULL, NULL, NULL, NULL, NULL, + netdev->match_host, netdev->match_virt, + netdev->match_kernel, netdev->match_arch, + NULL, NULL, NULL, NULL, NULL, NULL) <= 0) + return 0; + + r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev); + if (r < 0) + return r; + + LIST_HEAD_INIT(netdev->callbacks); + + if (netdev->kind != NETDEV_KIND_VLAN) { + r = netdev_create(netdev, NULL, NULL); + if (r < 0) + return r; + } + + netdev = NULL; + + return 0; +} + +int netdev_load(Manager *manager) { + NetDev *netdev; + char **files, **f; + int r; + + assert(manager); + + while ((netdev = hashmap_first(manager->netdevs))) + netdev_free(netdev); + + r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs); + if (r < 0) { + log_error("Failed to enumerate netdev files: %s", strerror(-r)); + return r; + } + + STRV_FOREACH_BACKWARDS(f, files) { + r = netdev_load_one(manager, *f); + if (r < 0) + return r; + } + + strv_free(files); + + return 0; +} diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf new file mode 100644 index 0000000..44aeb9c --- /dev/null +++ b/src/network/networkd-network-gperf.gperf @@ -0,0 +1,44 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd.h" +#include "net-util.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name network_network_gperf_hash +%define lookup-function-name network_network_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) +Match.Path, config_parse_string, 0, offsetof(Network, match_path) +Match.Driver, config_parse_string, 0, offsetof(Network, match_driver) +Match.Type, config_parse_string, 0, offsetof(Network, match_type) +Match.Name, config_parse_ifname, 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) +Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) +Network.Description, config_parse_string, 0, offsetof(Network, description) +Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge) +Network.Bond, config_parse_bond, 0, offsetof(Network, bond) +Network.VLAN, config_parse_vlan, 0, offsetof(Network, vlans) +Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) +Network.Address, config_parse_address, 0, 0 +Network.Gateway, config_parse_gateway, 0, 0 +Network.DNS, config_parse_dns, 0, offsetof(Network, dns) +Address.Address, config_parse_address, 0, 0 +Address.Broadcast, config_parse_broadcast, 0, 0 +Address.Label, config_parse_label, 0, 0 +Route.Gateway, config_parse_gateway, 0, 0 +Route.Destination, config_parse_destination, 0, 0 +DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domainname) +DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c new file mode 100644 index 0000000..14fa92a --- /dev/null +++ b/src/network/networkd-network.c @@ -0,0 +1,332 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd.h" +#include "net-util.h" +#include "path-util.h" +#include "conf-files.h" +#include "conf-parser.h" +#include "util.h" + +static int network_load_one(Manager *manager, const char *filename) { + _cleanup_network_free_ Network *network = NULL; + _cleanup_fclose_ FILE *file = NULL; + Route *route; + Address *address; + int r; + + assert(manager); + assert(filename); + + file = fopen(filename, "re"); + if (!file) { + if (errno == ENOENT) + return 0; + else + return errno; + } + + network = new0(Network, 1); + if (!network) + return log_oom(); + + network->manager = manager; + + LIST_HEAD_INIT(network->static_addresses); + LIST_HEAD_INIT(network->static_routes); + + network->vlans = hashmap_new(uint64_hash_func, uint64_compare_func); + if (!network->vlans) + return log_oom(); + + network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func); + if (!network->addresses_by_section) + return log_oom(); + + network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func); + if (!network->routes_by_section) + return log_oom(); + + network->filename = strdup(filename); + if (!network->filename) + return log_oom(); + + network->dhcp_dns = true; + network->dhcp_hostname = true; + network->dhcp_domainname = true; + + r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup, + (void*) network_network_gperf_lookup, false, false, network); + if (r < 0) { + log_warning("Could not parse config file %s: %s", filename, strerror(-r)); + return r; + } + + LIST_PREPEND(networks, manager->networks, network); + + LIST_FOREACH(static_routes, route, network->static_routes) { + if (!route->family) { + log_warning("Route section without Gateway field configured in %s. " + "Ignoring", filename); + return 0; + } + } + + LIST_FOREACH(static_addresses, address, network->static_addresses) { + if (!address->family) { + log_warning("Address section without Address field configured in %s. " + "Ignoring", filename); + return 0; + } + } + + network = NULL; + + return 0; +} + +int network_load(Manager *manager) { + Network *network; + _cleanup_strv_free_ char **files = NULL; + char **f; + int r; + + assert(manager); + + while ((network = manager->networks)) + network_free(network); + + r = conf_files_list_strv(&files, ".network", NULL, network_dirs); + if (r < 0) { + log_error("Failed to enumerate network files: %s", strerror(-r)); + return r; + } + + STRV_FOREACH_BACKWARDS(f, files) { + r = network_load_one(manager, *f); + if (r < 0) + return r; + } + + return 0; +} + +void network_free(Network *network) { + Route *route; + Address *address; + + if (!network) + return; + + free(network->filename); + + free(network->match_mac); + free(network->match_path); + free(network->match_driver); + free(network->match_type); + free(network->match_name); + + free(network->description); + + address_free(network->dns); + + hashmap_free(network->vlans); + + while ((route = network->static_routes)) + route_free(route); + + while ((address = network->static_addresses)) + address_free(address); + + hashmap_free(network->addresses_by_section); + hashmap_free(network->routes_by_section); + + if (network->manager && network->manager->networks) + LIST_REMOVE(networks, network->manager->networks, network); + + free(network); +} + +int network_get(Manager *manager, struct udev_device *device, Network **ret) { + Network *network; + + assert(manager); + assert(device); + assert(ret); + + 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, + network->match_arch, + udev_device_get_sysattr_value(device, "address"), + udev_device_get_property_value(device, "ID_PATH"), + udev_device_get_driver(udev_device_get_parent(device)), + udev_device_get_property_value(device, "ID_NET_DRIVER"), + udev_device_get_devtype(device), + udev_device_get_sysname(device))) { + log_debug("%s: found matching network '%s'", + udev_device_get_sysname(device), + network->filename); + *ret = network; + return 0; + } + } + + *ret = NULL; + + return -ENOENT; +} + +int network_apply(Manager *manager, Network *network, Link *link) { + int r; + + link->network = network; + + r = link_configure(link); + if (r < 0) + return r; + + if (network->dns) { + r = manager_update_resolv_conf(manager); + if (r < 0) + return r; + } + + return 0; +} + +int config_parse_bridge(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, EINVAL, + "Bridge is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (netdev->kind != NETDEV_KIND_BRIDGE) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "NetDev is not a bridge, ignoring assignment: %s", rvalue); + return 0; + } + + network->bridge = netdev; + + return 0; +} + +int config_parse_bond(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, EINVAL, + "Bond is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (netdev->kind != NETDEV_KIND_BOND) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "NetDev is not a bond, ignoring assignment: %s", rvalue); + return 0; + } + + network->bond = netdev; + + return 0; +} + +int config_parse_vlan(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, EINVAL, + "VLAN is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (netdev->kind != NETDEV_KIND_VLAN) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "NetDev is not a VLAN, ignoring assignment: %s", rvalue); + return 0; + } + + r = hashmap_put(network->vlans, &netdev->vlanid, netdev); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Can not add VLAN to network: %s", rvalue); + return 0; + } + + return 0; +} diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c new file mode 100644 index 0000000..46a4537 --- /dev/null +++ b/src/network/networkd-route.c @@ -0,0 +1,273 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "networkd.h" + +#include "utf8.h" +#include "util.h" +#include "conf-parser.h" +#include "net-util.h" + +int route_new_static(Network *network, unsigned section, Route **ret) { + _cleanup_route_free_ Route *route = NULL; + + if (section) { + uint64_t key = section; + + route = hashmap_get(network->routes_by_section, &key); + if (route) { + *ret = route; + route = NULL; + + return 0; + } + } + + route = new0(Route, 1); + if (!route) + return -ENOMEM; + + route->family = AF_UNSPEC; + + route->network = network; + + LIST_PREPEND(static_routes, network->static_routes, route); + + if (section) { + route->section = section; + hashmap_put(network->routes_by_section, &route->section, route); + } + + *ret = route; + route = NULL; + + return 0; +} + +int route_new_dynamic(Route **ret) { + _cleanup_route_free_ Route *route = NULL; + + route = new0(Route, 1); + if (!route) + return -ENOMEM; + + route->family = AF_UNSPEC; + + *ret = route; + route = NULL; + + return 0; +} + +void route_free(Route *route) { + if (!route) + return; + + if (route->network) { + LIST_REMOVE(static_routes, route->network->static_routes, route); + + if (route->section) + hashmap_remove(route->network->routes_by_section, + &route->section); + } + + free(route); +} + +int route_configure(Route *route, Link *link, + sd_rtnl_message_handler_t callback) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->rtnl); + assert(link->ifindex > 0); + assert(route->family == AF_INET || route->family == AF_INET6); + + r = sd_rtnl_message_new_route(link->manager->rtnl, &req, + RTM_NEWROUTE, route->family); + if (r < 0) { + log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r)); + return r; + } + + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + if (r < 0) { + log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r)); + return r; + } + + if (route->dst_prefixlen) { + if (route->family == AF_INET) + r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + else if (route->family == AF_INET6) + r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + if (r < 0) { + log_error("Could not append RTA_DST attribute: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen); + if (r < 0) { + log_error("Could not set destination prefix length: %s", strerror(-r)); + return r; + } + } + + r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex); + if (r < 0) { + log_error("Could not append RTA_OIF attribute: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + log_error("Could not send rtnetlink message: %s", strerror(-r)); + return r; + } + + return 0; +} + +int config_parse_gateway(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_route_free_ Route *n = NULL; + _cleanup_free_ char *route = NULL; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + if (streq(section, "Network")) { + /* we are not in an Route section, so treat + * this as the special '0' section */ + section_line = 0; + } + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + r = net_parse_inaddr(rvalue, &n->family, &n->in_addr); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Route is invalid, ignoring assignment: %s", route); + return 0; + } + + n = NULL; + + return 0; +} + +int config_parse_destination(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + _cleanup_route_free_ Route *n = NULL; + _cleanup_free_ char *address = NULL; + const char *e; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + /* Destination=address/prefixlen */ + + /* address */ + e = strchr(rvalue, '/'); + if (e) { + address = strndup(rvalue, e - rvalue); + if (!address) + return log_oom(); + } else { + address = strdup(rvalue); + if (!address) + return log_oom(); + } + + r = net_parse_inaddr(address, &n->family, &n->dst_addr); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Destination is invalid, ignoring assignment: %s", address); + return 0; + } + + /* prefixlen */ + if (e) { + unsigned i; + + r = safe_atou(e + 1, &i); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Route destination prefix length is invalid, " + "ignoring assignment: %s", e + 1); + return 0; + } + + n->dst_prefixlen = (unsigned char) i; + } else { + switch (n->family) { + case AF_INET: + n->dst_prefixlen = 32; + break; + case AF_INET6: + n->dst_prefixlen = 128; + break; + } + } + + n = NULL; + + return 0; +} diff --git a/src/network/networkd.c b/src/network/networkd.c new file mode 100644 index 0000000..00e9a5f --- /dev/null +++ b/src/network/networkd.c @@ -0,0 +1,102 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-event.h" +#include "sd-daemon.h" + +#include "networkd.h" + +int main(int argc, char *argv[]) { + _cleanup_manager_free_ Manager *m = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto out; + } + + r = manager_new(&m); + if (r < 0) { + log_error("Could not create manager: %s", strerror(-r)); + goto out; + } + + r = manager_load_config(m); + if (r < 0) { + log_error("Could not load configuration files: %s", strerror(-r)); + goto out; + } + + r = manager_udev_listen(m); + if (r < 0) { + log_error("Could not connect to udev: %s", strerror(-r)); + goto out; + } + + r = manager_udev_enumerate_links(m); + if (r < 0) { + log_error("Could not enumerate links: %s", strerror(-r)); + goto out; + } + + r = manager_rtnl_listen(m); + if (r < 0) { + log_error("Could not connect to rtnl: %s", strerror(-r)); + goto out; + } + + r = manager_bus_listen(m); + if (r < 0) { + log_error("Could not connect to system bus: %s", strerror(-r)); + goto out; + } + + /* write out empty resolv.conf to avoid a + * dangling symlink */ + r = manager_update_resolv_conf(m); + if (r < 0) { + log_error("Could not create resolv.conf: %s", strerror(-r)); + goto out; + } + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + r = sd_event_loop(m->event); + if (r < 0) { + log_error("Event loop failed: %s", strerror(-r)); + goto out; + } + +out: + sd_notify(false, + "STATUS=Shutting down..."); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/network/networkd.h b/src/network/networkd.h new file mode 100644 index 0000000..8307bb5 --- /dev/null +++ b/src/network/networkd.h @@ -0,0 +1,366 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include + +#include "sd-event.h" +#include "sd-rtnl.h" +#include "sd-bus.h" +#include "sd-dhcp-client.h" +#include "udev.h" + +#include "rtnl-util.h" +#include "hashmap.h" +#include "list.h" +#include "condition-util.h" + +typedef struct NetDev NetDev; +typedef struct Network Network; +typedef struct Link Link; +typedef struct Address Address; +typedef struct Route Route; +typedef struct Manager Manager; + +typedef struct netdev_enslave_callback netdev_enslave_callback; + +struct netdev_enslave_callback { + sd_rtnl_message_handler_t callback; + Link *link; + + LIST_FIELDS(netdev_enslave_callback, callbacks); +}; + +typedef enum NetDevKind { + NETDEV_KIND_BRIDGE, + NETDEV_KIND_BOND, + NETDEV_KIND_VLAN, + _NETDEV_KIND_MAX, + _NETDEV_KIND_INVALID = -1 +} NetDevKind; + +typedef enum NetDevState { + NETDEV_STATE_FAILED, + NETDEV_STATE_CREATING, + NETDEV_STATE_READY, + _NETDEV_STATE_MAX, + _NETDEV_STATE_INVALID = -1, +} NetDevState; + +struct NetDev { + Manager *manager; + + char *filename; + + Condition *match_host; + Condition *match_virt; + Condition *match_kernel; + Condition *match_arch; + + char *description; + char *name; + NetDevKind kind; + + uint64_t vlanid; + + int ifindex; + NetDevState state; + + LIST_HEAD(netdev_enslave_callback, callbacks); +}; + +struct Network { + Manager *manager; + + char *filename; + + struct ether_addr *match_mac; + char *match_path; + char *match_driver; + char *match_type; + char *match_name; + Condition *match_host; + Condition *match_virt; + Condition *match_kernel; + Condition *match_arch; + + char *description; + NetDev *bridge; + NetDev *bond; + Hashmap *vlans; + bool dhcp; + bool dhcp_dns; + bool dhcp_mtu; + bool dhcp_hostname; + bool dhcp_domainname; + bool dhcp_critical; + + LIST_HEAD(Address, static_addresses); + LIST_HEAD(Route, static_routes); + Address *dns; + + Hashmap *addresses_by_section; + Hashmap *routes_by_section; + + LIST_FIELDS(Network, networks); +}; + +struct Address { + Network *network; + uint64_t section; + + unsigned char family; + unsigned char prefixlen; + char *label; + + struct in_addr broadcast; + + union { + struct in_addr in; + struct in6_addr in6; + } in_addr; + + LIST_FIELDS(Address, static_addresses); +}; + +struct Route { + Network *network; + uint64_t section; + + unsigned char family; + unsigned char dst_prefixlen; + + union { + struct in_addr in; + struct in6_addr in6; + } in_addr; + + union { + struct in_addr in; + struct in6_addr in6; + } dst_addr; + + LIST_FIELDS(Route, static_routes); +}; + +typedef enum LinkState { + LINK_STATE_ENSLAVING, + LINK_STATE_SETTING_ADDRESSES, + LINK_STATE_SETTING_ROUTES, + LINK_STATE_CONFIGURED, + LINK_STATE_FAILED, + _LINK_STATE_MAX, + _LINK_STATE_INVALID = -1 +} LinkState; + +struct Link { + Manager *manager; + + uint64_t ifindex; + char *ifname; + struct ether_addr mac; + + unsigned flags; + + Network *network; + + LinkState state; + + unsigned addr_messages; + unsigned route_messages; + unsigned enslaving; + + sd_dhcp_client *dhcp_client; + sd_dhcp_lease *dhcp_lease; + uint16_t original_mtu; +}; + +struct Manager { + sd_rtnl *rtnl; + sd_event *event; + sd_bus *bus; + struct udev *udev; + struct udev_monitor *udev_monitor; + sd_event_source *udev_event_source; + sd_event_source *sigterm_event_source; + sd_event_source *sigint_event_source; + + Hashmap *links; + Hashmap *netdevs; + LIST_HEAD(Network, networks); + + usec_t network_dirs_ts_usec; +}; + +extern const char* const network_dirs[]; + +/* Manager */ + +int manager_new(Manager **ret); +void manager_free(Manager *m); + +int manager_load_config(Manager *m); +bool manager_should_reload(Manager *m); + +int manager_udev_enumerate_links(Manager *m); +int manager_udev_listen(Manager *m); + +int manager_rtnl_listen(Manager *m); +int manager_bus_listen(Manager *m); + +int manager_update_resolv_conf(Manager *m); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); +#define _cleanup_manager_free_ _cleanup_(manager_freep) + +/* NetDev */ + +int netdev_load(Manager *manager); + +void netdev_free(NetDev *netdev); + +DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_free); +#define _cleanup_netdev_free_ _cleanup_(netdev_freep) + +int netdev_get(Manager *manager, const char *name, NetDev **ret); +int netdev_set_ifindex(NetDev *netdev, int ifindex); +int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t cb); + +const char *netdev_kind_to_string(NetDevKind d) _const_; +NetDevKind netdev_kind_from_string(const char *d) _pure_; + +int config_parse_netdev_kind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +/* gperf */ +const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsigned length); + +/* Network */ + +int network_load(Manager *manager); + +void network_free(Network *network); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); +#define _cleanup_network_free_ _cleanup_(network_freep) + +int network_get(Manager *manager, struct udev_device *device, Network **ret); +int network_apply(Manager *manager, Network *network, Link *link); + +int config_parse_bridge(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_bond(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_vlan(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +/* gperf */ +const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); + +/* Route */ +int route_new_static(Network *network, unsigned section, Route **ret); +int route_new_dynamic(Route **ret); +void route_free(Route *route); +int route_configure(Route *route, Link *link, sd_rtnl_message_handler_t callback); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); +#define _cleanup_route_free_ _cleanup_(route_freep) + +int config_parse_gateway(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_destination(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); + +/* Address */ +int address_new_static(Network *network, unsigned section, Address **ret); +int address_new_dynamic(Address **ret); +void address_free(Address *address); +int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback); +int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); +#define _cleanup_address_free_ _cleanup_(address_freep) + +int config_parse_dns(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_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); + +int config_parse_broadcast(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_label(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); + +/* Link */ + +int link_new(Manager *manager, struct udev_device *device, Link **ret); +void link_free(Link *link); +int link_get(Manager *m, int ifindex, Link **ret); +int link_add(Manager *manager, struct udev_device *device, Link **ret); +int link_configure(Link *link); + +int link_update(Link *link, sd_rtnl_message *message); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free); +#define _cleanup_link_free_ _cleanup_(link_freep) + +/* Macros which append INTERFACE= to the message */ + +#define log_full_link(level, link, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", link->ifname, "%s: " fmt, link->ifname, ##__VA_ARGS__) +#define log_debug_link(link, ...) log_full_link(LOG_DEBUG, link, ##__VA_ARGS__) +#define log_info_link(link, ...) log_full_link(LOG_INFO, link, ##__VA_ARGS__) +#define log_notice_link(link, ...) log_full_link(LOG_NOTICE, link, ##__VA_ARGS__) +#define log_warning_link(link, ...) log_full_link(LOG_WARNING, link, ##__VA_ARGS__) +#define log_error_link(link, ...) log_full_link(LOG_ERR, link, ##__VA_ARGS__) + +#define log_struct_link(level, link, ...) log_struct(level, "INTERFACE=%s", link->ifname, __VA_ARGS__) + +/* More macros which append INTERFACE= to the message */ + +#define log_full_netdev(level, netdev, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", netdev->name, "%s: " fmt, netdev->name, ##__VA_ARGS__) +#define log_debug_netdev(netdev, ...) log_full_netdev(LOG_DEBUG, netdev, ##__VA_ARGS__) +#define log_info_netdev(netdev, ...) log_full_netdev(LOG_INFO, netdev, ##__VA_ARGS__) +#define log_notice_netdev(netdev, ...) log_full_netdev(LOG_NOTICE, netdev, ##__VA_ARGS__) +#define log_warning_netdev(netdev, ...) log_full_netdev(LOG_WARNING, netdev,## __VA_ARGS__) +#define log_error_netdev(netdev, ...) log_full_netdev(LOG_ERR, netdev, ##__VA_ARGS__) + +#define log_struct_netdev(level, netdev, ...) log_struct(level, "INTERFACE=%s", netdev->name, __VA_ARGS__) + +#define NETDEV(netdev) "INTERFACE=%s", netdev->name +#define ADDRESS_FMT_VAL(address) \ + (address).s_addr & 0xFF, \ + ((address).s_addr >> 8) & 0xFF, \ + ((address).s_addr >> 16) & 0xFF, \ + (address).s_addr >> 24 diff --git a/src/network/test-network.c b/src/network/test-network.c new file mode 100644 index 0000000..9c372c7 --- /dev/null +++ b/src/network/test-network.c @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "networkd.h" + +static void test_link(Manager *manager, struct udev_device *loopback) { + Link *link = NULL; + + assert_se(link_new(manager, loopback, &link) >= 0); + assert_se(link); +} + +static void test_load_config(Manager *manager) { +/* TODO: should_reload, is false if the config dirs do not exist, so + * so we can't do this test here, move it to a test for paths_check_timestamps + * directly + * + * assert_se(network_should_reload(manager) == true); +*/ + assert_se(manager_load_config(manager) >= 0); + assert_se(manager_should_reload(manager) == false); +} + +static void test_network_get(Manager *manager, struct udev_device *loopback) { + Network *network; + + /* let's assume that the test machine does not have a .network file + that applies to the loopback device... */ + assert_se(network_get(manager, loopback, &network) == -ENOENT); + assert_se(!network); +} + +int main(void) { + _cleanup_manager_free_ Manager *manager = NULL; + struct udev *udev; + struct udev_device *loopback; + + assert_se(manager_new(&manager) >= 0); + + test_load_config(manager); + + udev = udev_new(); + assert_se(udev); + + loopback = udev_device_new_from_syspath(udev, "/sys/class/net/lo"); + assert_se(loopback); + assert_se(udev_device_get_ifindex(loopback) == 1); + + test_network_get(manager, loopback); + + test_link(manager, loopback); + + assert_se(manager_udev_listen(manager) >= 0); + assert_se(manager_udev_enumerate_links(manager) >= 0); + assert_se(manager_rtnl_listen(manager) >= 0); + + udev_device_unref(loopback); + udev_unref(udev); +} diff --git a/src/notify.c b/src/notify.c deleted file mode 100644 index a9bc51e..0000000 --- a/src/notify.c +++ /dev/null @@ -1,217 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "strv.h" -#include "util.h" -#include "log.h" -#include "sd-daemon.h" -#include "sd-readahead.h" - -static bool arg_ready = false; -static pid_t arg_pid = 0; -static const char *arg_status = NULL; -static bool arg_booted = false; -static const char *arg_readahead = NULL; - -static int help(void) { - - printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n" - "Notify the init system about service status updates.\n\n" - " -h --help Show this help\n" - " --ready Inform the init system about service start-up completion\n" - " --pid[=PID] Set main pid of daemon\n" - " --status=TEXT Set status text\n" - " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n" - " --readahead=ACTION Controls read-ahead operations\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_READY = 0x100, - ARG_PID, - ARG_STATUS, - ARG_BOOTED, - ARG_READAHEAD - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "ready", no_argument, NULL, ARG_READY }, - { "pid", optional_argument, NULL, ARG_PID }, - { "status", required_argument, NULL, ARG_STATUS }, - { "booted", no_argument, NULL, ARG_BOOTED }, - { "readahead", required_argument, NULL, ARG_READAHEAD }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_READY: - arg_ready = true; - break; - - case ARG_PID: - - if (optarg) { - if (parse_pid(optarg, &arg_pid) < 0) { - log_error("Failed to parse PID %s.", optarg); - return -EINVAL; - } - } else - arg_pid = getppid(); - - break; - - case ARG_STATUS: - arg_status = optarg; - break; - - case ARG_BOOTED: - arg_booted = true; - break; - - case ARG_READAHEAD: - arg_readahead = optarg; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind >= argc && - !arg_ready && - !arg_status && - !arg_pid && - !arg_booted && - !arg_readahead) { - help(); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char* argv[]) { - char* our_env[4], **final_env = NULL; - unsigned i = 0; - char *status = NULL, *cpid = NULL, *n = NULL; - int r, retval = EXIT_FAILURE; - - log_parse_environment(); - log_open(); - - if ((r = parse_argv(argc, argv)) <= 0) { - retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - goto finish; - } - - if (arg_booted) - return sd_booted() <= 0; - - if (arg_readahead) { - if ((r = sd_readahead(arg_readahead)) < 0) { - log_error("Failed to issue read-ahead control command: %s", strerror(-r)); - goto finish; - } - } - - if (arg_ready) - our_env[i++] = (char*) "READY=1"; - - if (arg_status) { - if (!(status = strappend("STATUS=", arg_status))) { - log_error("Failed to allocate STATUS string."); - goto finish; - } - - our_env[i++] = status; - } - - if (arg_pid > 0) { - if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) { - log_error("Failed to allocate MAINPID string."); - goto finish; - } - - our_env[i++] = cpid; - } - - our_env[i++] = NULL; - - if (!(final_env = strv_env_merge(2, our_env, argv + optind))) { - log_error("Failed to merge string sets."); - goto finish; - } - - if (strv_length(final_env) <= 0) { - retval = EXIT_SUCCESS; - goto finish; - } - - if (!(n = strv_join(final_env, "\n"))) { - log_error("Failed to concatenate strings."); - goto finish; - } - - if ((r = sd_notify(false, n)) < 0) { - log_error("Failed to notify init system: %s", strerror(-r)); - goto finish; - } - - retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS; - -finish: - free(status); - free(cpid); - free(n); - - strv_free(final_env); - - return retval; -} diff --git a/src/notify/Makefile b/src/notify/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/notify/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/notify/notify.c b/src/notify/notify.c new file mode 100644 index 0000000..a145b8f --- /dev/null +++ b/src/notify/notify.c @@ -0,0 +1,227 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "strv.h" +#include "util.h" +#include "log.h" +#include "sd-readahead.h" +#include "build.h" +#include "env-util.h" + +static bool arg_ready = false; +static pid_t arg_pid = 0; +static const char *arg_status = NULL; +static bool arg_booted = false; +static const char *arg_readahead = NULL; + +static int help(void) { + + printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n" + "Notify the init system about service status updates.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --ready Inform the init system about service start-up completion\n" + " --pid[=PID] Set main pid of daemon\n" + " --status=TEXT Set status text\n" + " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n" + " --readahead=ACTION Controls read-ahead operations\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_READY = 0x100, + ARG_VERSION, + ARG_PID, + ARG_STATUS, + ARG_BOOTED, + ARG_READAHEAD + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "ready", no_argument, NULL, ARG_READY }, + { "pid", optional_argument, NULL, ARG_PID }, + { "status", required_argument, NULL, ARG_STATUS }, + { "booted", no_argument, NULL, ARG_BOOTED }, + { "readahead", required_argument, NULL, ARG_READAHEAD }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_READY: + arg_ready = true; + break; + + case ARG_PID: + + if (optarg) { + if (parse_pid(optarg, &arg_pid) < 0) { + log_error("Failed to parse PID %s.", optarg); + return -EINVAL; + } + } else + arg_pid = getppid(); + + break; + + case ARG_STATUS: + arg_status = optarg; + break; + + case ARG_BOOTED: + arg_booted = true; + break; + + case ARG_READAHEAD: + arg_readahead = optarg; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind >= argc && + !arg_ready && + !arg_status && + !arg_pid && + !arg_booted && + !arg_readahead) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char* argv[]) { + char* our_env[4], **final_env = NULL; + unsigned i = 0; + char *status = NULL, *cpid = NULL, *n = NULL; + int r, retval = EXIT_FAILURE; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) { + retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + goto finish; + } + + if (arg_booted) + return sd_booted() <= 0; + + if (arg_readahead) { + if ((r = sd_readahead(arg_readahead)) < 0) { + log_error("Failed to issue read-ahead control command: %s", strerror(-r)); + goto finish; + } + } + + if (arg_ready) + our_env[i++] = (char*) "READY=1"; + + if (arg_status) { + if (!(status = strappend("STATUS=", arg_status))) { + log_error("Failed to allocate STATUS string."); + goto finish; + } + + our_env[i++] = status; + } + + if (arg_pid > 0) { + if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) { + log_error("Failed to allocate MAINPID string."); + goto finish; + } + + our_env[i++] = cpid; + } + + our_env[i++] = NULL; + + if (!(final_env = strv_env_merge(2, our_env, argv + optind))) { + log_error("Failed to merge string sets."); + goto finish; + } + + if (strv_length(final_env) <= 0) { + retval = EXIT_SUCCESS; + goto finish; + } + + if (!(n = strv_join(final_env, "\n"))) { + log_error("Failed to concatenate strings."); + goto finish; + } + + if ((r = sd_notify(false, n)) < 0) { + log_error("Failed to notify init system: %s", strerror(-r)); + goto finish; + } + + retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS; + +finish: + free(status); + free(cpid); + free(n); + + strv_free(final_env); + + return retval; +} diff --git a/src/nspawn.c b/src/nspawn.c deleted file mode 100644 index 8441c05..0000000 --- a/src/nspawn.c +++ /dev/null @@ -1,888 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "missing.h" -#include "cgroup-util.h" -#include "sd-daemon.h" -#include "strv.h" -#include "loopback-setup.h" - -static char *arg_directory = NULL; -static char *arg_user = NULL; -static bool arg_private_network = false; - -static int help(void) { - - printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" - "Spawn a minimal namespace container for debugging, testing and building.\n\n" - " -h --help Show this help\n" - " -D --directory=NAME Root directory for the container\n" - " -u --user=USER Run the command under specified user or uid\n" - " --private-network Disable network in container\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_PRIVATE_NETWORK = 0x100 - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "directory", required_argument, NULL, 'D' }, - { "user", required_argument, NULL, 'u' }, - { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "+hD:u:", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case 'D': - free(arg_directory); - if (!(arg_directory = strdup(optarg))) { - log_error("Failed to duplicate root directory."); - return -ENOMEM; - } - - break; - - case 'u': - free(arg_user); - if (!(arg_user = strdup(optarg))) { - log_error("Failed to duplicate user name."); - return -ENOMEM; - } - - break; - - case ARG_PRIVATE_NETWORK: - arg_private_network = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - return 1; -} - -static int mount_all(const char *dest) { - - typedef struct MountPoint { - const char *what; - const char *where; - const char *type; - const char *options; - unsigned long flags; - bool fatal; - } MountPoint; - - static const MountPoint mount_table[] = { - { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, - { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND, true }, /* Bind mount first */ - { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */ - { "/sys", "/sys", "bind", NULL, MS_BIND, true }, /* Bind mount first */ - { "/sys", "/sys", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */ - { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID, true }, - { "/dev/pts", "/dev/pts", "bind", NULL, MS_BIND, true }, - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV, true }, -#ifdef HAVE_SELINUX - { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL, MS_BIND, false }, /* Bind mount first */ - { "/sys/fs/selinux", "/sys/fs/selinux", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, false }, /* Then, make it r/o */ -#endif - }; - - unsigned k; - int r = 0; - char *where; - - for (k = 0; k < ELEMENTSOF(mount_table); k++) { - int t; - - if (asprintf(&where, "%s/%s", dest, mount_table[k].where) < 0) { - log_error("Out of memory"); - - if (r == 0) - r = -ENOMEM; - - break; - } - - if ((t = path_is_mount_point(where, false)) < 0) { - log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t)); - free(where); - - if (r == 0) - r = t; - - continue; - } - - mkdir_p(where, 0755); - - if (mount(mount_table[k].what, - where, - mount_table[k].type, - mount_table[k].flags, - mount_table[k].options) < 0 && - mount_table[k].fatal) { - - log_error("mount(%s) failed: %m", where); - - if (r == 0) - r = -errno; - } - - free(where); - } - - /* Fix the timezone, if possible */ - if (asprintf(&where, "%s/%s", dest, "/etc/localtime") >= 0) { - - if (mount("/etc/localtime", where, "bind", MS_BIND, NULL) >= 0) - mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL); - - free(where); - } - - return r; -} - -static int copy_devnodes(const char *dest, const char *console) { - - static const char devnodes[] = - "null\0" - "zero\0" - "full\0" - "random\0" - "urandom\0" - "tty\0" - "ptmx\0" - "kmsg\0" - "rtc0\0"; - - const char *d; - int r = 0, k; - mode_t u; - struct stat st; - char *from = NULL, *to = NULL; - - assert(dest); - assert(console); - - u = umask(0000); - - NULSTR_FOREACH(d, devnodes) { - from = to = NULL; - - asprintf(&from, "/dev/%s", d); - asprintf(&to, "%s/dev/%s", dest, d); - - if (!from || !to) { - log_error("Failed to allocate devnode path"); - - free(from); - free(to); - - from = to = NULL; - - if (r == 0) - r = -ENOMEM; - - break; - } - - if (stat(from, &st) < 0) { - - if (errno != ENOENT) { - log_error("Failed to stat %s: %m", from); - if (r == 0) - r = -errno; - } - - } else if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { - - log_error("%s is not a char or block device, cannot copy.", from); - if (r == 0) - r = -EIO; - - } else if (mknod(to, st.st_mode, st.st_rdev) < 0) { - - log_error("mknod(%s) failed: %m", dest); - if (r == 0) - r = -errno; - } - - free(from); - free(to); - } - - if (stat(console, &st) < 0) { - - log_error("Failed to stat %s: %m", console); - if (r == 0) - r = -errno; - - goto finish; - - } else if (!S_ISCHR(st.st_mode)) { - - log_error("/dev/console is not a char device."); - if (r == 0) - r = -EIO; - - goto finish; - } - - if (asprintf(&to, "%s/dev/console", dest) < 0) { - - log_error("Out of memory"); - if (r == 0) - r = -ENOMEM; - - goto finish; - } - - /* We need to bind mount the right tty to /dev/console since - * ptys can only exist on pts file systems. To have something - * to bind mount things on we create a device node first, that - * has the right major/minor (note that the major minor - * doesn't actually matter here, since we mount it over - * anyway). */ - - if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) - log_error("mknod for /dev/console failed: %m"); - - if (mount(console, to, "bind", MS_BIND, NULL) < 0) { - log_error("bind mount for /dev/console failed: %m"); - - if (r == 0) - r = -errno; - } - - free(to); - - if ((k = chmod_and_chown(console, 0600, 0, 0)) < 0) { - log_error("Failed to correct access mode for TTY: %s", strerror(-k)); - - if (r == 0) - r = k; - } - -finish: - umask(u); - - return r; -} - -static int drop_capabilities(void) { - static const unsigned long retain[] = { - CAP_CHOWN, - CAP_DAC_OVERRIDE, - CAP_DAC_READ_SEARCH, - CAP_FOWNER, - CAP_FSETID, - CAP_IPC_OWNER, - CAP_KILL, - CAP_LEASE, - CAP_LINUX_IMMUTABLE, - CAP_NET_BIND_SERVICE, - CAP_NET_BROADCAST, - CAP_NET_RAW, - CAP_SETGID, - CAP_SETFCAP, - CAP_SETPCAP, - CAP_SETUID, - CAP_SYS_ADMIN, - CAP_SYS_CHROOT, - CAP_SYS_NICE, - CAP_SYS_PTRACE, - CAP_SYS_TTY_CONFIG - }; - - unsigned long l; - - for (l = 0; l <= MAX(63LU, (unsigned long) CAP_LAST_CAP); l++) { - unsigned i; - - for (i = 0; i < ELEMENTSOF(retain); i++) - if (retain[i] == l) - break; - - if (i < ELEMENTSOF(retain)) - continue; - - if (prctl(PR_CAPBSET_DROP, l) < 0) { - - /* If this capability is not known, EINVAL - * will be returned, let's ignore this. */ - if (errno == EINVAL) - break; - - log_error("PR_CAPBSET_DROP failed: %m"); - return -errno; - } - } - - return 0; -} - -static int is_os_tree(const char *path) { - int r; - char *p; - /* We use /bin/sh as flag file if something is an OS */ - - if (asprintf(&p, "%s/bin/sh", path) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - return r < 0 ? 0 : 1; -} - -#define BUFFER_SIZE 1024 - -static int process_pty(int master, sigset_t *mask) { - - char in_buffer[BUFFER_SIZE], out_buffer[BUFFER_SIZE]; - size_t in_buffer_full = 0, out_buffer_full = 0; - struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev; - bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false; - int ep = -1, signal_fd = -1, r; - - fd_nonblock(STDIN_FILENO, 1); - fd_nonblock(STDOUT_FILENO, 1); - fd_nonblock(master, 1); - - if ((signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - if ((ep = epoll_create1(EPOLL_CLOEXEC)) < 0) { - log_error("Failed to create epoll: %m"); - r = -errno; - goto finish; - } - - zero(stdin_ev); - stdin_ev.events = EPOLLIN|EPOLLET; - stdin_ev.data.fd = STDIN_FILENO; - - zero(stdout_ev); - stdout_ev.events = EPOLLOUT|EPOLLET; - stdout_ev.data.fd = STDOUT_FILENO; - - zero(master_ev); - master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET; - master_ev.data.fd = master; - - zero(signal_ev); - signal_ev.events = EPOLLIN; - signal_ev.data.fd = signal_fd; - - if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 || - epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 || - epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 || - epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) { - log_error("Failed to regiser fds in epoll: %m"); - r = -errno; - goto finish; - } - - for (;;) { - struct epoll_event ev[16]; - ssize_t k; - int i, nfds; - - if ((nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1)) < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - log_error("epoll_wait(): %m"); - r = -errno; - goto finish; - } - - assert(nfds >= 1); - - for (i = 0; i < nfds; i++) { - if (ev[i].data.fd == STDIN_FILENO) { - - if (ev[i].events & (EPOLLIN|EPOLLHUP)) - stdin_readable = true; - - } else if (ev[i].data.fd == STDOUT_FILENO) { - - if (ev[i].events & (EPOLLOUT|EPOLLHUP)) - stdout_writable = true; - - } else if (ev[i].data.fd == master) { - - if (ev[i].events & (EPOLLIN|EPOLLHUP)) - master_readable = true; - - if (ev[i].events & (EPOLLOUT|EPOLLHUP)) - master_writable = true; - - } else if (ev[i].data.fd == signal_fd) { - struct signalfd_siginfo sfsi; - ssize_t n; - - if ((n = read(signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { - - if (n >= 0) { - log_error("Failed to read from signalfd: invalid block size"); - r = -EIO; - goto finish; - } - - if (errno != EINTR && errno != EAGAIN) { - log_error("Failed to read from signalfd: %m"); - r = -errno; - goto finish; - } - } else { - - if (sfsi.ssi_signo == SIGWINCH) { - struct winsize ws; - - /* The window size changed, let's forward that. */ - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) - ioctl(master, TIOCSWINSZ, &ws); - } else { - r = 0; - goto finish; - } - } - } - } - - while ((stdin_readable && in_buffer_full <= 0) || - (master_writable && in_buffer_full > 0) || - (master_readable && out_buffer_full <= 0) || - (stdout_writable && out_buffer_full > 0)) { - - if (stdin_readable && in_buffer_full < BUFFER_SIZE) { - - if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, BUFFER_SIZE - in_buffer_full)) < 0) { - - if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO) - stdin_readable = false; - else { - log_error("read(): %m"); - r = -errno; - goto finish; - } - } else - in_buffer_full += (size_t) k; - } - - if (master_writable && in_buffer_full > 0) { - - if ((k = write(master, in_buffer, in_buffer_full)) < 0) { - - if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO) - master_writable = false; - else { - log_error("write(): %m"); - r = -errno; - goto finish; - } - - } else { - assert(in_buffer_full >= (size_t) k); - memmove(in_buffer, in_buffer + k, in_buffer_full - k); - in_buffer_full -= k; - } - } - - if (master_readable && out_buffer_full < BUFFER_SIZE) { - - if ((k = read(master, out_buffer + out_buffer_full, BUFFER_SIZE - out_buffer_full)) < 0) { - - if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO) - master_readable = false; - else { - log_error("read(): %m"); - r = -errno; - goto finish; - } - } else - out_buffer_full += (size_t) k; - } - - if (stdout_writable && out_buffer_full > 0) { - - if ((k = write(STDOUT_FILENO, out_buffer, out_buffer_full)) < 0) { - - if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO) - stdout_writable = false; - else { - log_error("write(): %m"); - r = -errno; - goto finish; - } - - } else { - assert(out_buffer_full >= (size_t) k); - memmove(out_buffer, out_buffer + k, out_buffer_full - k); - out_buffer_full -= k; - } - } - } - } - -finish: - if (ep >= 0) - close_nointr_nofail(ep); - - if (signal_fd >= 0) - close_nointr_nofail(signal_fd); - - return r; -} - -int main(int argc, char *argv[]) { - pid_t pid = 0; - int r = EXIT_FAILURE, k; - char *oldcg = NULL, *newcg = NULL; - int master = -1; - const char *console = NULL; - struct termios saved_attr, raw_attr; - sigset_t mask; - bool saved_attr_valid = false; - struct winsize ws; - - log_parse_environment(); - log_open(); - - if ((r = parse_argv(argc, argv)) <= 0) - goto finish; - - if (arg_directory) { - char *p; - - p = path_make_absolute_cwd(arg_directory); - free(arg_directory); - arg_directory = p; - } else - arg_directory = get_current_dir_name(); - - if (!arg_directory) { - log_error("Failed to determine path"); - goto finish; - } - - path_kill_slashes(arg_directory); - - if (geteuid() != 0) { - log_error("Need to be root."); - goto finish; - } - - if (sd_booted() <= 0) { - log_error("Not running on a systemd system."); - goto finish; - } - - if (path_equal(arg_directory, "/")) { - log_error("Spawning container on root directory not supported."); - goto finish; - } - - if (is_os_tree(arg_directory) <= 0) { - log_error("Directory %s doesn't look like an OS root directory. Refusing.", arg_directory); - goto finish; - } - - if ((k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg)) < 0) { - log_error("Failed to determine current cgroup: %s", strerror(-k)); - goto finish; - } - - if (asprintf(&newcg, "%s/nspawn-%lu", oldcg, (unsigned long) getpid()) < 0) { - log_error("Failed to allocate cgroup path."); - goto finish; - } - - if ((k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0)) < 0) { - log_error("Failed to create cgroup: %s", strerror(-k)); - goto finish; - } - - if ((master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY)) < 0) { - log_error("Failed to acquire pseudo tty: %m"); - goto finish; - } - - if (!(console = ptsname(master))) { - log_error("Failed to determine tty name: %m"); - goto finish; - } - - log_info("Spawning namespace container on %s (console is %s).", arg_directory, console); - - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) - ioctl(master, TIOCSWINSZ, &ws); - - if (unlockpt(master) < 0) { - log_error("Failed to unlock tty: %m"); - goto finish; - } - - if (tcgetattr(STDIN_FILENO, &saved_attr) < 0) { - log_error("Failed to get terminal attributes: %m"); - goto finish; - } - - saved_attr_valid = true; - - raw_attr = saved_attr; - cfmakeraw(&raw_attr); - raw_attr.c_lflag &= ~ECHO; - - if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) { - log_error("Failed to set terminal attributes: %m"); - goto finish; - } - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1); - assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); - - if ((pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL)) < 0) { - log_error("clone() failed: %m"); - goto finish; - } - - if (pid == 0) { - /* child */ - - const char *hn; - const char *home = NULL; - uid_t uid = (uid_t) -1; - gid_t gid = (gid_t) -1; - const char *envp[] = { - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ - NULL, /* TERM */ - NULL, /* HOME */ - NULL, /* USER */ - NULL, /* LOGNAME */ - NULL - }; - - envp[2] = strv_find_prefix(environ, "TERM="); - - close_nointr_nofail(master); - - close_nointr(STDIN_FILENO); - close_nointr(STDOUT_FILENO); - close_nointr(STDERR_FILENO); - - close_all_fds(NULL, 0); - - reset_all_signal_handlers(); - - assert_se(sigemptyset(&mask) == 0); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if (setsid() < 0) - goto child_fail; - - if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) - goto child_fail; - - /* Mark / as private, in case somebody marked it shared */ - if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) - goto child_fail; - - if (mount_all(arg_directory) < 0) - goto child_fail; - - if (copy_devnodes(arg_directory, console) < 0) - goto child_fail; - - if (chdir(arg_directory) < 0) { - log_error("chdir(%s) failed: %m", arg_directory); - goto child_fail; - } - - if (open_terminal("dev/console", O_RDWR) != STDIN_FILENO || - dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || - dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) - goto child_fail; - - if (mount(arg_directory, "/", "bind", MS_BIND|MS_MOVE, NULL) < 0) { - log_error("mount(MS_MOVE) failed: %m"); - goto child_fail; - } - - if (chroot(".") < 0) { - log_error("chroot() failed: %m"); - goto child_fail; - } - - if (chdir("/") < 0) { - log_error("chdir() failed: %m"); - goto child_fail; - } - - umask(0022); - - loopback_setup(); - - if (drop_capabilities() < 0) - goto child_fail; - - if (arg_user) { - - if (get_user_creds((const char**)&arg_user, &uid, &gid, &home) < 0) { - log_error("get_user_creds() failed: %m"); - goto child_fail; - } - - if (mkdir_parents(home, 0775) < 0) { - log_error("mkdir_parents() failed: %m"); - goto child_fail; - } - - if (safe_mkdir(home, 0775, uid, gid) < 0) { - log_error("safe_mkdir() failed: %m"); - goto child_fail; - } - - if (initgroups((const char*)arg_user, gid) < 0) { - log_error("initgroups() failed: %m"); - goto child_fail; - } - - if (setresgid(gid, gid, gid) < 0) { - log_error("setregid() failed: %m"); - goto child_fail; - } - - if (setresuid(uid, uid, uid) < 0) { - log_error("setreuid() failed: %m"); - goto child_fail; - } - } - - if ((asprintf((char**)(envp + 3), "HOME=%s", home? home: "/root") < 0) || - (asprintf((char**)(envp + 4), "USER=%s", arg_user? arg_user : "root") < 0) || - (asprintf((char**)(envp + 5), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) { - log_error("Out of memory"); - goto child_fail; - } - - if ((hn = file_name_from_path(arg_directory))) - sethostname(hn, strlen(hn)); - - if (argc > optind) - execvpe(argv[optind], argv + optind, (char**) envp); - else { - chdir(home ? home : "/root"); - execle("/bin/bash", "-bash", NULL, (char**) envp); - } - - log_error("execv() failed: %m"); - - child_fail: - _exit(EXIT_FAILURE); - } - - if (process_pty(master, &mask) < 0) - goto finish; - - if (saved_attr_valid) { - tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr); - saved_attr_valid = false; - } - - r = wait_for_terminate_and_warn(argc > optind ? argv[optind] : "bash", pid); - - if (r < 0) - r = EXIT_FAILURE; - -finish: - if (saved_attr_valid) - tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr); - - if (master >= 0) - close_nointr_nofail(master); - - if (oldcg) - cg_attach(SYSTEMD_CGROUP_CONTROLLER, oldcg, 0); - - if (newcg) - cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, newcg, true); - - free(arg_directory); - free(oldcg); - free(newcg); - - return r; -} diff --git a/src/nspawn/Makefile b/src/nspawn/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/nspawn/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c new file mode 100644 index 0000000..de74a43 --- /dev/null +++ b/src/nspawn/nspawn.c @@ -0,0 +1,2224 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SELINUX +#include +#endif + +#ifdef HAVE_SECCOMP +#include +#endif + +#include "sd-daemon.h" +#include "sd-bus.h" +#include "sd-id128.h" +#include "sd-rtnl.h" +#include "log.h" +#include "util.h" +#include "mkdir.h" +#include "macro.h" +#include "audit.h" +#include "missing.h" +#include "cgroup-util.h" +#include "strv.h" +#include "path-util.h" +#include "loopback-setup.h" +#include "dev-setup.h" +#include "fdset.h" +#include "build.h" +#include "fileio.h" +#include "bus-util.h" +#include "bus-error.h" +#include "ptyfwd.h" +#include "bus-kernel.h" +#include "env-util.h" +#include "def.h" +#include "rtnl-util.h" +#include "udev-util.h" + +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif + +typedef enum LinkJournal { + LINK_NO, + LINK_AUTO, + LINK_HOST, + LINK_GUEST +} LinkJournal; + +static char *arg_directory = NULL; +static char *arg_user = NULL; +static sd_id128_t arg_uuid = {}; +static char *arg_machine = NULL; +static char *arg_selinux_context = NULL; +static char *arg_selinux_apifs_context = NULL; +static const char *arg_slice = NULL; +static bool arg_private_network = false; +static bool arg_read_only = false; +static bool arg_boot = false; +static LinkJournal arg_link_journal = LINK_AUTO; +static uint64_t arg_retain = + (1ULL << CAP_CHOWN) | + (1ULL << CAP_DAC_OVERRIDE) | + (1ULL << CAP_DAC_READ_SEARCH) | + (1ULL << CAP_FOWNER) | + (1ULL << CAP_FSETID) | + (1ULL << CAP_IPC_OWNER) | + (1ULL << CAP_KILL) | + (1ULL << CAP_LEASE) | + (1ULL << CAP_LINUX_IMMUTABLE) | + (1ULL << CAP_NET_BIND_SERVICE) | + (1ULL << CAP_NET_BROADCAST) | + (1ULL << CAP_NET_RAW) | + (1ULL << CAP_SETGID) | + (1ULL << CAP_SETFCAP) | + (1ULL << CAP_SETPCAP) | + (1ULL << CAP_SETUID) | + (1ULL << CAP_SYS_ADMIN) | + (1ULL << CAP_SYS_CHROOT) | + (1ULL << CAP_SYS_NICE) | + (1ULL << CAP_SYS_PTRACE) | + (1ULL << CAP_SYS_TTY_CONFIG) | + (1ULL << CAP_SYS_RESOURCE) | + (1ULL << CAP_SYS_BOOT) | + (1ULL << CAP_AUDIT_WRITE) | + (1ULL << CAP_AUDIT_CONTROL) | + (1ULL << CAP_MKNOD); +static char **arg_bind = NULL; +static char **arg_bind_ro = NULL; +static char **arg_setenv = NULL; +static bool arg_quiet = false; +static bool arg_share_system = false; +static bool arg_register = true; +static bool arg_keep_unit = false; +static char **arg_network_interfaces = NULL; +static bool arg_network_veth = false; +static char *arg_network_bridge = NULL; +static unsigned long arg_personality = 0xffffffffLU; + +static int help(void) { + + printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" + "Spawn a minimal namespace container for debugging, testing and building.\n\n" + " -h --help Show this help\n" + " --version Print version string\n" + " -q --quiet Do not show status information\n" + " -D --directory=NAME Root directory for the container\n" + " -b --boot Boot up full system (i.e. invoke init)\n" + " -u --user=USER Run the command under specified user or uid\n" + " -M --machine=NAME Set the machine name for the container\n" + " --uuid=UUID Set a specific machine UUID for the container\n" + " -S --slice=SLICE Place the container in the specified slice\n" + " --private-network Disable network in container\n" + " --network-interface=INTERFACE\n" + " Assign an existing network interface to the\n" + " container\n" + " --network-veth Add a virtual ethernet connection between host\n" + " and container\n" + " --network-bridge=INTERFACE\n" + " Add a virtual ethernet connection between host\n" + " and container and add it to an existing bridge on\n" + " 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" + " --capability=CAP In addition to the default, retain specified\n" + " capability\n" + " --drop-capability=CAP Drop the specified capability from the default set\n" + " --link-journal=MODE Link up guest journal, one of no, auto, guest, host\n" + " -j Equivalent to --link-journal=host\n" + " --read-only Mount the root directory read-only\n" + " --bind=PATH[:PATH] Bind mount a file or directory from the host into\n" + " the container\n" + " --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n" + " --setenv=NAME=VALUE Pass an environment variable to PID 1\n" + " --share-system Share system namespaces with host\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", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_PRIVATE_NETWORK, + ARG_UUID, + ARG_READ_ONLY, + ARG_CAPABILITY, + ARG_DROP_CAPABILITY, + ARG_LINK_JOURNAL, + ARG_BIND, + ARG_BIND_RO, + ARG_SETENV, + ARG_SHARE_SYSTEM, + ARG_REGISTER, + ARG_KEEP_UNIT, + ARG_NETWORK_INTERFACE, + ARG_NETWORK_VETH, + ARG_NETWORK_BRIDGE, + ARG_PERSONALITY, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "directory", required_argument, NULL, 'D' }, + { "user", required_argument, NULL, 'u' }, + { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, + { "boot", no_argument, NULL, 'b' }, + { "uuid", required_argument, NULL, ARG_UUID }, + { "read-only", no_argument, NULL, ARG_READ_ONLY }, + { "capability", required_argument, NULL, ARG_CAPABILITY }, + { "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY }, + { "link-journal", required_argument, NULL, ARG_LINK_JOURNAL }, + { "bind", required_argument, NULL, ARG_BIND }, + { "bind-ro", required_argument, NULL, ARG_BIND_RO }, + { "machine", required_argument, NULL, 'M' }, + { "slice", required_argument, NULL, 'S' }, + { "setenv", required_argument, NULL, ARG_SETENV }, + { "selinux-context", required_argument, NULL, 'Z' }, + { "selinux-apifs-context", required_argument, NULL, 'L' }, + { "quiet", no_argument, NULL, 'q' }, + { "share-system", no_argument, NULL, ARG_SHARE_SYSTEM }, + { "register", required_argument, NULL, ARG_REGISTER }, + { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, + { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, + { "network-veth", no_argument, NULL, ARG_NETWORK_VETH }, + { "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE }, + { "personality", required_argument, NULL, ARG_PERSONALITY }, + {} + }; + + int c, r; + uint64_t plus = 0, minus = 0; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:q", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'D': + free(arg_directory); + arg_directory = canonicalize_file_name(optarg); + if (!arg_directory) { + log_error("Invalid root directory: %m"); + return -ENOMEM; + } + + break; + + case 'u': + free(arg_user); + arg_user = strdup(optarg); + if (!arg_user) + return log_oom(); + + break; + + case ARG_NETWORK_BRIDGE: + arg_network_bridge = strdup(optarg); + if (!arg_network_bridge) + return log_oom(); + + /* fall through */ + + case ARG_NETWORK_VETH: + arg_network_veth = true; + arg_private_network = true; + break; + + case ARG_NETWORK_INTERFACE: + if (strv_push(&arg_network_interfaces, optarg) < 0) + return log_oom(); + + /* fall through */ + + case ARG_PRIVATE_NETWORK: + arg_private_network = true; + break; + + case 'b': + arg_boot = true; + break; + + case ARG_UUID: + r = sd_id128_from_string(optarg, &arg_uuid); + if (r < 0) { + log_error("Invalid UUID: %s", optarg); + return r; + } + break; + + case 'S': + arg_slice = strdup(optarg); + if (!arg_slice) + return log_oom(); + + break; + + case 'M': + if (isempty(optarg)) { + free(arg_machine); + arg_machine = NULL; + } else { + + if (!hostname_is_valid(optarg)) { + log_error("Invalid machine name: %s", optarg); + return -EINVAL; + } + + free(arg_machine); + arg_machine = strdup(optarg); + if (!arg_machine) + return log_oom(); + + break; + } + + case 'Z': + arg_selinux_context = optarg; + break; + + case 'L': + arg_selinux_apifs_context = optarg; + break; + + case ARG_READ_ONLY: + arg_read_only = true; + break; + + case ARG_CAPABILITY: + case ARG_DROP_CAPABILITY: { + char *state, *word; + size_t length; + + FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) { + _cleanup_free_ char *t; + cap_value_t cap; + + t = strndup(word, length); + if (!t) + return log_oom(); + + if (streq(t, "all")) { + if (c == ARG_CAPABILITY) + plus = (uint64_t) -1; + else + minus = (uint64_t) -1; + } else { + if (cap_from_name(t, &cap) < 0) { + log_error("Failed to parse capability %s.", t); + return -EINVAL; + } + + if (c == ARG_CAPABILITY) + plus |= 1ULL << (uint64_t) cap; + else + minus |= 1ULL << (uint64_t) cap; + } + } + + break; + } + + case 'j': + arg_link_journal = LINK_GUEST; + break; + + case ARG_LINK_JOURNAL: + if (streq(optarg, "auto")) + arg_link_journal = LINK_AUTO; + else if (streq(optarg, "no")) + arg_link_journal = LINK_NO; + else if (streq(optarg, "guest")) + arg_link_journal = LINK_GUEST; + else if (streq(optarg, "host")) + arg_link_journal = LINK_HOST; + else { + log_error("Failed to parse link journal mode %s", optarg); + return -EINVAL; + } + + break; + + case ARG_BIND: + case ARG_BIND_RO: { + _cleanup_free_ char *a = NULL, *b = NULL; + char *e; + char ***x; + + x = c == ARG_BIND ? &arg_bind : &arg_bind_ro; + + e = strchr(optarg, ':'); + if (e) { + a = strndup(optarg, e - optarg); + b = strdup(e + 1); + } else { + a = strdup(optarg); + b = strdup(optarg); + } + + if (!a || !b) + return log_oom(); + + if (!path_is_absolute(a) || !path_is_absolute(b)) { + log_error("Invalid bind mount specification: %s", optarg); + return -EINVAL; + } + + r = strv_extend(x, a); + if (r < 0) + return log_oom(); + + r = strv_extend(x, b); + if (r < 0) + return log_oom(); + + break; + } + + case ARG_SETENV: { + char **n; + + if (!env_assignment_is_valid(optarg)) { + log_error("Environment variable assignment '%s' is not valid.", optarg); + return -EINVAL; + } + + n = strv_env_set(arg_setenv, optarg); + if (!n) + return log_oom(); + + strv_free(arg_setenv); + arg_setenv = n; + break; + } + + case 'q': + arg_quiet = true; + break; + + case ARG_SHARE_SYSTEM: + arg_share_system = true; + break; + + case ARG_REGISTER: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --register= argument: %s", optarg); + return r; + } + + arg_register = r; + break; + + case ARG_KEEP_UNIT: + arg_keep_unit = true; + break; + + case ARG_PERSONALITY: + + arg_personality = personality_from_string(optarg); + if (arg_personality == 0xffffffffLU) { + log_error("Unknown or unsupported personality '%s'.", optarg); + return -EINVAL; + } + + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (arg_share_system) + arg_register = false; + + if (arg_boot && arg_share_system) { + log_error("--boot and --share-system may not be combined."); + return -EINVAL; + } + + if (arg_keep_unit && cg_pid_get_owner_uid(0, NULL) >= 0) { + log_error("--keep-unit may not be used when invoked from a user session."); + return -EINVAL; + } + + arg_retain = (arg_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus; + + return 1; +} + +static int mount_all(const char *dest) { + + typedef struct MountPoint { + const char *what; + const char *where; + const char *type; + const char *options; + unsigned long flags; + bool fatal; + } MountPoint; + + static const MountPoint mount_table[] = { + { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, + { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true }, /* Bind mount first */ + { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */ + { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, + { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true }, + { "devpts", "/dev/pts", "devpts","newinstance,ptmxmode=0666,mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, true }, + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true }, + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true }, +#ifdef HAVE_SELINUX + { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false }, /* Bind mount first */ + { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, false }, /* Then, make it r/o */ +#endif + }; + + unsigned k; + int r = 0; + + for (k = 0; k < ELEMENTSOF(mount_table); k++) { + _cleanup_free_ char *where = NULL; +#ifdef HAVE_SELINUX + _cleanup_free_ char *options = NULL; +#endif + const char *o; + int t; + + where = strjoin(dest, "/", mount_table[k].where, NULL); + if (!where) + return log_oom(); + + t = path_is_mount_point(where, true); + if (t < 0) { + log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t)); + + if (r == 0) + r = t; + + continue; + } + + /* Skip this entry if it is not a remount. */ + if (mount_table[k].what && t > 0) + continue; + + mkdir_p(where, 0755); + +#ifdef HAVE_SELINUX + if (arg_selinux_apifs_context && + (streq_ptr(mount_table[k].what, "tmpfs") || streq_ptr(mount_table[k].what, "devpts"))) { + options = strjoin(mount_table[k].options, ",context=\"", arg_selinux_apifs_context, "\"", NULL); + if (!options) + return log_oom(); + + o = options; + } else +#endif + o = mount_table[k].options; + + + if (mount(mount_table[k].what, + where, + mount_table[k].type, + mount_table[k].flags, + o) < 0 && + mount_table[k].fatal) { + + log_error("mount(%s) failed: %m", where); + + if (r == 0) + r = -errno; + } + } + + return r; +} + +static int mount_binds(const char *dest, char **l, unsigned long flags) { + char **x, **y; + + STRV_FOREACH_PAIR(x, y, l) { + char *where; + struct stat source_st, dest_st; + int r; + + if (stat(*x, &source_st) < 0) { + log_error("failed to stat %s: %m", *x); + return -errno; + } + + where = strappenda(dest, *y); + r = stat(where, &dest_st); + if (r == 0) { + if ((source_st.st_mode & S_IFMT) != (dest_st.st_mode & S_IFMT)) { + log_error("The file types of %s and %s do not match. Refusing bind mount", + *x, where); + return -EINVAL; + } + } else if (errno == ENOENT) { + r = mkdir_parents_label(where, 0755); + if (r < 0) { + log_error("Failed to bind mount %s: %s", *x, strerror(-r)); + return r; + } + } else { + log_error("Failed to bind mount %s: %s", *x, strerror(errno)); + return -errno; + } + /* Create the mount point, but be conservative -- refuse to create block + * and char devices. */ + if (S_ISDIR(source_st.st_mode)) + mkdir_label(where, 0755); + else if (S_ISFIFO(source_st.st_mode)) + mkfifo(where, 0644); + else if (S_ISSOCK(source_st.st_mode)) + mknod(where, 0644 | S_IFSOCK, 0); + else if (S_ISREG(source_st.st_mode)) + touch(where); + else { + log_error("Refusing to create mountpoint for file: %s", *x); + return -ENOTSUP; + } + + if (mount(*x, where, "bind", MS_BIND, NULL) < 0) { + log_error("mount(%s) failed: %m", where); + return -errno; + } + + if (flags && mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|flags, NULL) < 0) { + log_error("mount(%s) failed: %m", where); + return -errno; + } + } + + return 0; +} + +static int setup_timezone(const char *dest) { + _cleanup_free_ char *where = NULL, *p = NULL, *q = NULL, *check = NULL, *what = NULL; + char *z, *y; + int r; + + assert(dest); + + /* Fix the timezone, if possible */ + r = readlink_malloc("/etc/localtime", &p); + if (r < 0) { + log_warning("/etc/localtime is not a symlink, not updating container timezone."); + return 0; + } + + z = path_startswith(p, "../usr/share/zoneinfo/"); + if (!z) + z = path_startswith(p, "/usr/share/zoneinfo/"); + if (!z) { + log_warning("/etc/localtime does not point into /usr/share/zoneinfo/, not updating container timezone."); + return 0; + } + + where = strappend(dest, "/etc/localtime"); + if (!where) + return log_oom(); + + r = readlink_malloc(where, &q); + if (r >= 0) { + y = path_startswith(q, "../usr/share/zoneinfo/"); + if (!y) + y = path_startswith(q, "/usr/share/zoneinfo/"); + + + /* Already pointing to the right place? Then do nothing .. */ + if (y && streq(y, z)) + return 0; + } + + check = strjoin(dest, "/usr/share/zoneinfo/", z, NULL); + if (!check) + return log_oom(); + + if (access(check, F_OK) < 0) { + log_warning("Timezone %s does not exist in container, not updating container timezone.", z); + return 0; + } + + what = strappend("../usr/share/zoneinfo/", z); + if (!what) + return log_oom(); + + unlink(where); + if (symlink(what, where) < 0) { + log_error("Failed to correct timezone of container: %m"); + return 0; + } + + return 0; +} + +static int setup_resolv_conf(const char *dest) { + char _cleanup_free_ *where = NULL; + + assert(dest); + + if (arg_private_network) + return 0; + + /* Fix resolv.conf, if possible */ + where = strappend(dest, "/etc/resolv.conf"); + if (!where) + return log_oom(); + + /* We don't really care for the results of this really. If it + * fails, it fails, but meh... */ + copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW); + + return 0; +} + +static int setup_boot_id(const char *dest) { + _cleanup_free_ char *from = NULL, *to = NULL; + sd_id128_t rnd = {}; + char as_uuid[37]; + int r; + + assert(dest); + + if (arg_share_system) + return 0; + + /* Generate a new randomized boot ID, so that each boot-up of + * the container gets a new one */ + + from = strappend(dest, "/dev/proc-sys-kernel-random-boot-id"); + to = strappend(dest, "/proc/sys/kernel/random/boot_id"); + if (!from || !to) + return log_oom(); + + r = sd_id128_randomize(&rnd); + if (r < 0) { + log_error("Failed to generate random boot id: %s", strerror(-r)); + return r; + } + + snprintf(as_uuid, sizeof(as_uuid), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + SD_ID128_FORMAT_VAL(rnd)); + char_array_0(as_uuid); + + r = write_string_file(from, as_uuid); + if (r < 0) { + log_error("Failed to write boot id: %s", strerror(-r)); + return r; + } + + if (mount(from, to, "bind", MS_BIND, NULL) < 0) { + log_error("Failed to bind mount boot id: %m"); + r = -errno; + } else if (mount(from, to, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL)) + log_warning("Failed to make boot id read-only: %m"); + + unlink(from); + return r; +} + +static int copy_devnodes(const char *dest) { + + static const char devnodes[] = + "null\0" + "zero\0" + "full\0" + "random\0" + "urandom\0" + "tty\0"; + + const char *d; + int r = 0; + _cleanup_umask_ mode_t u; + + assert(dest); + + u = umask(0000); + + NULSTR_FOREACH(d, devnodes) { + _cleanup_free_ char *from = NULL, *to = NULL; + struct stat st; + + from = strappend("/dev/", d); + to = strjoin(dest, "/dev/", d, NULL); + if (!from || !to) + return log_oom(); + + if (stat(from, &st) < 0) { + + if (errno != ENOENT) { + log_error("Failed to stat %s: %m", from); + return -errno; + } + + } else if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { + + log_error("%s is not a char or block device, cannot copy", from); + return -EIO; + + } else if (mknod(to, st.st_mode, st.st_rdev) < 0) { + + log_error("mknod(%s) failed: %m", dest); + return -errno; + } + } + + return r; +} + +static int setup_ptmx(const char *dest) { + _cleanup_free_ char *p = NULL; + + p = strappend(dest, "/dev/ptmx"); + if (!p) + return log_oom(); + + if (symlink("pts/ptmx", p) < 0) { + log_error("Failed to create /dev/ptmx symlink: %m"); + return -errno; + } + + return 0; +} + +static int setup_dev_console(const char *dest, const char *console) { + struct stat st; + _cleanup_free_ char *to = NULL; + int r; + _cleanup_umask_ mode_t u; + + assert(dest); + assert(console); + + u = umask(0000); + + if (stat(console, &st) < 0) { + log_error("Failed to stat %s: %m", console); + return -errno; + + } else if (!S_ISCHR(st.st_mode)) { + log_error("/dev/console is not a char device"); + return -EIO; + } + + r = chmod_and_chown(console, 0600, 0, 0); + if (r < 0) { + log_error("Failed to correct access mode for TTY: %s", strerror(-r)); + return r; + } + + if (asprintf(&to, "%s/dev/console", dest) < 0) + return log_oom(); + + /* We need to bind mount the right tty to /dev/console since + * ptys can only exist on pts file systems. To have something + * to bind mount things on we create a device node first, that + * has the right major/minor (note that the major minor + * doesn't actually matter here, since we mount it over + * anyway). */ + + if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) { + log_error("mknod() for /dev/console failed: %m"); + return -errno; + } + + if (mount(console, to, "bind", MS_BIND, NULL) < 0) { + log_error("Bind mount for /dev/console failed: %m"); + return -errno; + } + + return 0; +} + +static int setup_kmsg(const char *dest, int kmsg_socket) { + _cleanup_free_ char *from = NULL, *to = NULL; + int r, fd, k; + _cleanup_umask_ mode_t u; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + + assert(dest); + assert(kmsg_socket >= 0); + + u = umask(0000); + + /* We create the kmsg FIFO as /dev/kmsg, 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. */ + if (asprintf(&from, "%s/dev/kmsg", dest) < 0 || + asprintf(&to, "%s/proc/kmsg", dest) < 0) + return log_oom(); + + if (mkfifo(from, 0600) < 0) { + log_error("mkfifo() for /dev/kmsg failed: %m"); + return -errno; + } + + r = chmod_and_chown(from, 0600, 0, 0); + if (r < 0) { + log_error("Failed to correct access mode for /dev/kmsg: %s", strerror(-r)); + return r; + } + + if (mount(from, to, "bind", MS_BIND, NULL) < 0) { + log_error("Bind mount for /proc/kmsg failed: %m"); + return -errno; + } + + fd = open(from, O_RDWR|O_NDELAY|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to open fifo: %m"); + return -errno; + } + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + /* Store away the fd in the socket, so that it stays open as + * long as we run the child */ + k = sendmsg(kmsg_socket, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + close_nointr_nofail(fd); + + if (k < 0) { + log_error("Failed to send FIFO fd: %m"); + return -errno; + } + + /* And now make the FIFO unavailable as /dev/kmsg... */ + unlink(from); + return 0; +} + +static int setup_hostname(void) { + + if (arg_share_system) + return 0; + + if (sethostname(arg_machine, strlen(arg_machine)) < 0) + return -errno; + + return 0; +} + +static int setup_journal(const char *directory) { + sd_id128_t machine_id, this_id; + _cleanup_free_ char *p = NULL, *b = NULL, *q = NULL, *d = NULL; + char *id; + int r; + + p = strappend(directory, "/etc/machine-id"); + if (!p) + return log_oom(); + + r = read_one_line_file(p, &b); + if (r == -ENOENT && arg_link_journal == LINK_AUTO) + return 0; + else if (r < 0) { + log_error("Failed to read machine ID from %s: %s", p, strerror(-r)); + return r; + } + + id = strstrip(b); + if (isempty(id) && arg_link_journal == LINK_AUTO) + return 0; + + /* Verify validity */ + r = sd_id128_from_string(id, &machine_id); + if (r < 0) { + log_error("Failed to parse machine ID from %s: %s", p, strerror(-r)); + return r; + } + + r = sd_id128_get_machine(&this_id); + if (r < 0) { + log_error("Failed to retrieve machine ID: %s", strerror(-r)); + return r; + } + + if (sd_id128_equal(machine_id, this_id)) { + log_full(arg_link_journal == LINK_AUTO ? LOG_WARNING : LOG_ERR, + "Host and machine ids are equal (%s): refusing to link journals", id); + if (arg_link_journal == LINK_AUTO) + return 0; + return + -EEXIST; + } + + if (arg_link_journal == LINK_NO) + return 0; + + free(p); + p = strappend("/var/log/journal/", id); + q = strjoin(directory, "/var/log/journal/", id, NULL); + if (!p || !q) + return log_oom(); + + if (path_is_mount_point(p, false) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", p); + return -EEXIST; + } + + return 0; + } + + if (path_is_mount_point(q, false) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", q); + return -EEXIST; + } + + return 0; + } + + r = readlink_and_make_absolute(p, &d); + if (r >= 0) { + if ((arg_link_journal == LINK_GUEST || + arg_link_journal == LINK_AUTO) && + path_equal(d, q)) { + + r = mkdir_p(q, 0755); + if (r < 0) + log_warning("failed to create directory %s: %m", q); + return 0; + } + + if (unlink(p) < 0) { + log_error("Failed to remove symlink %s: %m", p); + return -errno; + } + } else if (r == -EINVAL) { + + if (arg_link_journal == LINK_GUEST && + rmdir(p) < 0) { + + if (errno == ENOTDIR) { + log_error("%s already exists and is neither a symlink nor a directory", p); + return r; + } else { + log_error("Failed to remove %s: %m", p); + return -errno; + } + } + } else if (r != -ENOENT) { + log_error("readlink(%s) failed: %m", p); + return r; + } + + if (arg_link_journal == LINK_GUEST) { + + if (symlink(q, p) < 0) { + log_error("Failed to symlink %s to %s: %m", q, p); + return -errno; + } + + r = mkdir_p(q, 0755); + if (r < 0) + log_warning("failed to create directory %s: %m", q); + return 0; + } + + if (arg_link_journal == LINK_HOST) { + r = mkdir_p(p, 0755); + if (r < 0) { + log_error("Failed to create %s: %m", p); + return r; + } + + } else if (access(p, F_OK) < 0) + return 0; + + if (dir_is_empty(q) == 0) { + log_error("%s not empty.", q); + return -ENOTEMPTY; + } + + r = mkdir_p(q, 0755); + if (r < 0) { + log_error("Failed to create %s: %m", q); + return r; + } + + if (mount(p, q, "bind", MS_BIND, NULL) < 0) { + log_error("Failed to bind mount journal from host into guest: %m"); + return -errno; + } + + return 0; +} + +static int setup_kdbus(const char *dest, const char *path) { + const char *p; + + if (!path) + return 0; + + p = strappenda(dest, "/dev/kdbus"); + if (mkdir(p, 0755) < 0) { + log_error("Failed to create kdbus path: %m"); + return -errno; + } + + if (mount(path, p, "bind", MS_BIND, NULL) < 0) { + log_error("Failed to mount kdbus domain path: %m"); + return -errno; + } + + return 0; +} + +static int drop_capabilities(void) { + return capability_bounding_set_drop(~arg_retain, false); +} + +static int register_machine(pid_t pid) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + if (!arg_register) + return 0; + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to open system bus: %s", strerror(-r)); + return r; + } + + if (arg_keep_unit) { + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "RegisterMachine", + &error, + NULL, + "sayssus", + arg_machine, + SD_BUS_MESSAGE_APPEND_ID128(arg_uuid), + "nspawn", + "container", + (uint32_t) pid, + strempty(arg_directory)); + } else { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "CreateMachine"); + if (r < 0) { + log_error("Failed to create message: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_append( + m, + "sayssus", + arg_machine, + SD_BUS_MESSAGE_APPEND_ID128(arg_uuid), + "nspawn", + "container", + (uint32_t) pid, + strempty(arg_directory)); + if (r < 0) { + log_error("Failed to append message arguments: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) { + log_error("Failed to open container: %s", strerror(-r)); + return r; + } + + if (!isempty(arg_slice)) { + r = sd_bus_message_append(m, "(sv)", "Slice", "s", arg_slice); + if (r < 0) { + log_error("Failed to append slice: %s", strerror(-r)); + return r; + } + } + + r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict"); + if (r < 0) { + log_error("Failed to add device policy: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 8, + /* Allow the container to + * access and create the API + * device nodes, so that + * PrivateDevices= in the + * container can work + * fine */ + "/dev/null", "rwm", + "/dev/zero", "rwm", + "/dev/full", "rwm", + "/dev/random", "rwm", + "/dev/urandom", "rwm", + "/dev/tty", "rwm", + /* Allow the container + * access to ptys. However, + * do not permit the + * container to ever create + * these device nodes. */ + "/dev/pts/ptmx", "rw", + "char-pts", "rw"); + if (r < 0) { + log_error("Failed to add device whitelist: %s", strerror(-r)); + return r; + } + + r = sd_bus_message_close_container(m); + if (r < 0) { + log_error("Failed to close container: %s", strerror(-r)); + return r; + } + + r = sd_bus_call(bus, m, 0, &error, NULL); + } + + if (r < 0) { + log_error("Failed to register machine: %s", bus_error_message(&error, r)); + return r; + } + + return 0; +} + +static int terminate_machine(pid_t pid) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + const char *path; + int r; + + if (!arg_register) + return 0; + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to open system bus: %s", strerror(-r)); + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachineByPID", + &error, + &reply, + "u", + (uint32_t) pid); + if (r < 0) { + /* Note that the machine might already have been + * cleaned up automatically, hence don't consider it a + * failure if we cannot get the machine object. */ + log_debug("Failed to get machine: %s", bus_error_message(&error, r)); + return 0; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + path, + "org.freedesktop.machine1.Machine", + "Terminate", + &error, + NULL, + NULL); + if (r < 0) { + log_debug("Failed to terminate machine: %s", bus_error_message(&error, r)); + return 0; + } + + return 0; +} + +static int reset_audit_loginuid(void) { + _cleanup_free_ char *p = NULL; + int r; + + if (arg_share_system) + return 0; + + r = read_one_line_file("/proc/self/loginuid", &p); + if (r == -EEXIST) + return 0; + if (r < 0) { + log_error("Failed to read /proc/self/loginuid: %s", strerror(-r)); + return r; + } + + /* Already reset? */ + if (streq(p, "4294967295")) + return 0; + + r = write_string_file("/proc/self/loginuid", "4294967295"); + if (r < 0) { + log_error("Failed to reset audit login UID. This probably means that your kernel is too\n" + "old and you have audit enabled. Note that the auditing subsystem is known to\n" + "be incompatible with containers on old kernels. Please make sure to upgrade\n" + "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" + "using systemd-nspawn. Sleeping for 5s... (%s)\n", strerror(-r)); + + sleep(5); + } + + return 0; +} + +static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ]) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + int r; + + if (!arg_private_network) + return 0; + + if (!arg_network_veth) + return 0; + + /* Use two different interface name prefixes depending whether + * we are in bridge mode or not. */ + if (arg_network_bridge) + memcpy(iface_name, "vb-", 3); + else + memcpy(iface_name, "ve-", 3); + + strncpy(iface_name+3, arg_machine, IFNAMSIZ - 3); + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) { + log_error("Failed to connect to netlink: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0); + if (r < 0) { + log_error("Failed to allocate netlink message: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_string(m, IFLA_IFNAME, iface_name); + if (r < 0) { + log_error("Failed to add netlink interface name: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_open_container(m, IFLA_LINKINFO); + if (r < 0) { + log_error("Failed to open netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "veth"); + if (r < 0) { + log_error("Failed to append netlink kind: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_open_container(m, IFLA_INFO_DATA); + if (r < 0) { + log_error("Failed to open netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_open_container(m, VETH_INFO_PEER); + if (r < 0) { + log_error("Failed to open netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_string(m, IFLA_IFNAME, "host0"); + if (r < 0) { + log_error("Failed to add netlink interface name: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid); + if (r < 0) { + log_error("Failed to add netlink namespace field: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(m); + if (r < 0) { + log_error("Failed to close netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(m); + if (r < 0) { + log_error("Failed to close netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(m); + if (r < 0) { + log_error("Failed to close netlink container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call(rtnl, m, 0, NULL); + if (r < 0) { + log_error("Failed to add new veth interfaces: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int setup_bridge(const char veth_name[]) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + int r, bridge; + + if (!arg_private_network) + return 0; + + if (!arg_network_veth) + return 0; + + if (!arg_network_bridge) + return 0; + + bridge = (int) if_nametoindex(arg_network_bridge); + if (bridge <= 0) { + log_error("Failed to resolve interface %s: %m", arg_network_bridge); + return -errno; + } + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) { + log_error("Failed to connect to netlink: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0); + if (r < 0) { + log_error("Failed to allocate netlink message: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_string(m, IFLA_IFNAME, veth_name); + if (r < 0) { + log_error("Failed to add netlink interface name field: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u32(m, IFLA_MASTER, bridge); + if (r < 0) { + log_error("Failed to add netlink master field: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call(rtnl, m, 0, NULL); + if (r < 0) { + log_error("Failed to add veth interface to bridge: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int move_network_interfaces(pid_t pid) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + char **i; + int r; + + if (!arg_private_network) + return 0; + + if (strv_isempty(arg_network_interfaces)) + return 0; + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) { + log_error("Failed to connect to netlink: %s", strerror(-r)); + return r; + } + + udev = udev_new(); + if (!udev) { + log_error("Failed to connect to udev."); + return -ENOMEM; + } + + STRV_FOREACH(i, arg_network_interfaces) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + char ifi_str[2 + DECIMAL_STR_MAX(int)]; + int ifi; + + ifi = (int) if_nametoindex(*i); + if (ifi <= 0) { + log_error("Failed to resolve interface %s: %m", *i); + return -errno; + } + + sprintf(ifi_str, "n%i", ifi); + d = udev_device_new_from_device_id(udev, ifi_str); + if (!d) { + log_error("Failed to get udev device for interface %s: %m", *i); + return -errno; + } + + if (udev_device_get_is_initialized(d) <= 0) { + log_error("Network interface %s is not initialized yet.", *i); + return -EBUSY; + } + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, ifi); + if (r < 0) { + log_error("Failed to allocate netlink message: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid); + if (r < 0) { + log_error("Failed to append namespace PID to netlink message: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_call(rtnl, m, 0, NULL); + if (r < 0) { + log_error("Failed to move interface %s to namespace: %s", *i, strerror(-r)); + return r; + } + } + + return 0; +} + +static int audit_still_doesnt_work_in_containers(void) { + +#ifdef HAVE_SECCOMP + scmp_filter_ctx seccomp; + int r; + + /* + Audit is broken in containers, much of the userspace audit + hookup will fail if running inside a container. We don't + care and just turn off creation of audit sockets. + + This will make socket(AF_NETLINK, *, NETLINK_AUDIT) fail + with EAFNOSUPPORT which audit userspace uses as indication + that audit is disabled in the kernel. + */ + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return log_oom(); + + r = seccomp_add_secondary_archs(seccomp); + if (r < 0 && r != -EEXIST) { + log_error("Failed to add secondary archs to seccomp filter: %s", strerror(-r)); + goto finish; + } + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EAFNOSUPPORT), + SCMP_SYS(socket), + 2, + SCMP_A0(SCMP_CMP_EQ, AF_NETLINK), + SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT)); + if (r < 0) { + log_error("Failed to add audit seccomp rule: %s", strerror(-r)); + goto finish; + } + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) { + log_error("Failed to unset NO_NEW_PRIVS: %s", strerror(-r)); + goto finish; + } + + r = seccomp_load(seccomp); + if (r < 0) + log_error("Failed to install seccomp audit filter: %s", strerror(-r)); + +finish: + seccomp_release(seccomp); + return r; +#else + return 0; +#endif + +} + +int main(int argc, char *argv[]) { + + _cleanup_close_ int master = -1, kdbus_fd = -1, sync_fd = -1; + _cleanup_close_pipe_ int kmsg_socket_pair[2] = { -1, -1 }; + _cleanup_free_ char *kdbus_domain = NULL; + _cleanup_fdset_free_ FDSet *fds = NULL; + const char *console = NULL; + int r = EXIT_FAILURE, k; + int n_fd_passed; + pid_t pid = 0; + sigset_t mask; + char veth_name[IFNAMSIZ]; + + log_parse_environment(); + log_open(); + + k = parse_argv(argc, argv); + if (k < 0) + goto finish; + else if (k == 0) { + r = EXIT_SUCCESS; + goto finish; + } + + if (arg_directory) { + char *p; + + p = path_make_absolute_cwd(arg_directory); + free(arg_directory); + arg_directory = p; + } else + arg_directory = get_current_dir_name(); + + if (!arg_directory) { + log_error("Failed to determine path, please use -D."); + goto finish; + } + + path_kill_slashes(arg_directory); + + if (!arg_machine) { + arg_machine = strdup(basename(arg_directory)); + if (!arg_machine) { + log_oom(); + goto finish; + } + + hostname_cleanup(arg_machine, false); + if (isempty(arg_machine)) { + log_error("Failed to determine machine name automatically, please use -M."); + goto finish; + } + } + + if (geteuid() != 0) { + log_error("Need to be root."); + goto finish; + } + + if (sd_booted() <= 0) { + log_error("Not running on a systemd system."); + goto finish; + } + + if (path_equal(arg_directory, "/")) { + log_error("Spawning container on root directory not supported."); + goto finish; + } + + if (arg_boot) { + if (path_is_os_tree(arg_directory) <= 0) { + log_error("Directory %s doesn't look like an OS root directory (/etc/os-release is missing). Refusing.", arg_directory); + goto finish; + } + } else { + const char *p; + + p = strappenda(arg_directory, + argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/"); + if (access(p, F_OK) < 0) { + log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory); + goto finish; + + } + } + + log_close(); + n_fd_passed = sd_listen_fds(false); + if (n_fd_passed > 0) { + k = fdset_new_listen_fds(&fds, false); + if (k < 0) { + log_error("Failed to collect file descriptors: %s", strerror(-k)); + goto finish; + } + } + fdset_close_others(fds); + log_open(); + + master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); + if (master < 0) { + log_error("Failed to acquire pseudo tty: %m"); + goto finish; + } + + console = ptsname(master); + if (!console) { + log_error("Failed to determine tty name: %m"); + goto finish; + } + + if (!arg_quiet) + log_info("Spawning container %s on %s. Press ^] three times within 1s to abort execution.", arg_machine, arg_directory); + + if (unlockpt(master) < 0) { + log_error("Failed to unlock tty: %m"); + goto finish; + } + + if (access("/dev/kdbus/control", F_OK) >= 0) { + + if (arg_share_system) { + kdbus_domain = strdup("/dev/kdbus"); + if (!kdbus_domain) { + log_oom(); + goto finish; + } + } else { + const char *ns; + + ns = strappenda("machine-", arg_machine); + kdbus_fd = bus_kernel_create_domain(ns, &kdbus_domain); + if (r < 0) + log_debug("Failed to create kdbus domain: %s", strerror(-r)); + else + log_debug("Successfully created kdbus domain as %s", kdbus_domain); + } + } + + if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) { + log_error("Failed to create kmsg socket pair: %m"); + goto finish; + } + + sd_notify(0, "READY=1"); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1); + assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); + + for (;;) { + siginfo_t status; + + sync_fd = eventfd(0, EFD_CLOEXEC); + if (sync_fd < 0) { + log_error("Failed to create event fd: %m"); + goto finish; + } + + pid = syscall(__NR_clone, + SIGCHLD|CLONE_NEWNS| + (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS)| + (arg_private_network ? CLONE_NEWNET : 0), NULL); + if (pid < 0) { + if (errno == EINVAL) + log_error("clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m"); + else + log_error("clone() failed: %m"); + + goto finish; + } + + if (pid == 0) { + /* child */ + const char *home = NULL; + uid_t uid = (uid_t) -1; + gid_t gid = (gid_t) -1; + unsigned n_env = 2; + const char *envp[] = { + "PATH=" DEFAULT_PATH_SPLIT_USR, + "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ + NULL, /* TERM */ + NULL, /* HOME */ + NULL, /* USER */ + NULL, /* LOGNAME */ + NULL, /* container_uuid */ + NULL, /* LISTEN_FDS */ + NULL, /* LISTEN_PID */ + NULL + }; + char **env_use; + eventfd_t x; + + envp[n_env] = strv_find_prefix(environ, "TERM="); + if (envp[n_env]) + n_env ++; + + close_nointr_nofail(master); + master = -1; + + close_nointr(STDIN_FILENO); + close_nointr(STDOUT_FILENO); + close_nointr(STDERR_FILENO); + + close_nointr_nofail(kmsg_socket_pair[0]); + kmsg_socket_pair[0] = -1; + + reset_all_signal_handlers(); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + k = open_terminal(console, O_RDWR); + if (k != STDIN_FILENO) { + if (k >= 0) { + close_nointr_nofail(k); + k = -EINVAL; + } + + log_error("Failed to open console: %s", strerror(-k)); + goto child_fail; + } + + if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || + dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { + log_error("Failed to duplicate console: %m"); + goto child_fail; + } + + if (setsid() < 0) { + log_error("setsid() failed: %m"); + goto child_fail; + } + + if (reset_audit_loginuid() < 0) + goto child_fail; + + if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) { + log_error("PR_SET_PDEATHSIG failed: %m"); + goto child_fail; + } + + /* Mark everything as slave, so that we still + * receive mounts from the real root, but don't + * propagate mounts to the real root. */ + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) { + log_error("MS_SLAVE|MS_REC failed: %m"); + goto child_fail; + } + + /* Turn directory into bind mount */ + if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REC, NULL) < 0) { + log_error("Failed to make bind mount."); + goto child_fail; + } + + if (arg_read_only) + if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) { + log_error("Failed to make read-only."); + goto child_fail; + } + + if (mount_all(arg_directory) < 0) + goto child_fail; + + if (copy_devnodes(arg_directory) < 0) + goto child_fail; + + if (setup_ptmx(arg_directory) < 0) + goto child_fail; + + dev_setup(arg_directory); + + if (audit_still_doesnt_work_in_containers() < 0) + goto child_fail; + + if (setup_dev_console(arg_directory, console) < 0) + goto child_fail; + + if (setup_kmsg(arg_directory, kmsg_socket_pair[1]) < 0) + goto child_fail; + + close_nointr_nofail(kmsg_socket_pair[1]); + kmsg_socket_pair[1] = -1; + + if (setup_boot_id(arg_directory) < 0) + goto child_fail; + + if (setup_timezone(arg_directory) < 0) + goto child_fail; + + if (setup_resolv_conf(arg_directory) < 0) + goto child_fail; + + if (setup_journal(arg_directory) < 0) + goto child_fail; + + if (mount_binds(arg_directory, arg_bind, 0) < 0) + goto child_fail; + + if (mount_binds(arg_directory, arg_bind_ro, MS_RDONLY) < 0) + goto child_fail; + + if (setup_kdbus(arg_directory, kdbus_domain) < 0) + goto child_fail; + + if (chdir(arg_directory) < 0) { + log_error("chdir(%s) failed: %m", arg_directory); + goto child_fail; + } + + if (mount(arg_directory, "/", NULL, MS_MOVE, NULL) < 0) { + log_error("mount(MS_MOVE) failed: %m"); + goto child_fail; + } + + if (chroot(".") < 0) { + log_error("chroot() failed: %m"); + goto child_fail; + } + + if (chdir("/") < 0) { + log_error("chdir() failed: %m"); + goto child_fail; + } + + umask(0022); + + if (arg_private_network) + loopback_setup(); + + if (drop_capabilities() < 0) { + log_error("drop_capabilities() failed: %m"); + goto child_fail; + } + + if (arg_user) { + + /* Note that this resolves user names + * inside the container, and hence + * accesses the NSS modules from the + * container and not the host. This is + * a bit weird... */ + + if (get_user_creds((const char**)&arg_user, &uid, &gid, &home, NULL) < 0) { + log_error("get_user_creds() failed: %m"); + goto child_fail; + } + + if (mkdir_parents_label(home, 0775) < 0) { + log_error("mkdir_parents_label() failed: %m"); + goto child_fail; + } + + if (mkdir_safe_label(home, 0775, uid, gid) < 0) { + log_error("mkdir_safe_label() failed: %m"); + goto child_fail; + } + + if (initgroups((const char*)arg_user, gid) < 0) { + log_error("initgroups() failed: %m"); + goto child_fail; + } + + if (setresgid(gid, gid, gid) < 0) { + log_error("setregid() failed: %m"); + goto child_fail; + } + + if (setresuid(uid, uid, uid) < 0) { + log_error("setreuid() failed: %m"); + goto child_fail; + } + } else { + /* Reset everything fully to 0, just in case */ + + if (setgroups(0, NULL) < 0) { + log_error("setgroups() failed: %m"); + goto child_fail; + } + + if (setresgid(0, 0, 0) < 0) { + log_error("setregid() failed: %m"); + goto child_fail; + } + + if (setresuid(0, 0, 0) < 0) { + log_error("setreuid() failed: %m"); + goto child_fail; + } + } + + 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)) { + log_oom(); + goto child_fail; + } + + if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) { + if (asprintf((char**)(envp + n_env++), "container_uuid=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(arg_uuid)) < 0) { + log_oom(); + goto child_fail; + } + } + + if (fdset_size(fds) > 0) { + k = fdset_cloexec(fds, false); + if (k < 0) { + log_error("Failed to unset O_CLOEXEC for file descriptors."); + goto child_fail; + } + + if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) || + (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0)) { + log_oom(); + goto child_fail; + } + } + + setup_hostname(); + + if (arg_personality != 0xffffffffLU) { + if (personality(arg_personality) < 0) { + log_error("personality() failed: %m"); + goto child_fail; + } + } + + eventfd_read(sync_fd, &x); + close_nointr_nofail(sync_fd); + sync_fd = -1; + + if (!strv_isempty(arg_setenv)) { + char **n; + + n = strv_env_merge(2, envp, arg_setenv); + if (!n) { + log_oom(); + goto child_fail; + } + + env_use = n; + } else + env_use = (char**) envp; + +#ifdef HAVE_SELINUX + if (arg_selinux_context) + if (setexeccon(arg_selinux_context) < 0) + log_error("setexeccon(\"%s\") failed: %m", arg_selinux_context); +#endif + if (arg_boot) { + char **a; + size_t l; + + /* Automatically search for the init system */ + + l = 1 + argc - optind; + a = newa(char*, l + 1); + memcpy(a + 1, argv + optind, l * sizeof(char*)); + + a[0] = (char*) "/usr/lib/systemd/systemd"; + execve(a[0], a, env_use); + + a[0] = (char*) "/lib/systemd/systemd"; + execve(a[0], a, env_use); + + a[0] = (char*) "/sbin/init"; + execve(a[0], a, env_use); + } else if (argc > optind) + execvpe(argv[optind], argv + optind, env_use); + else { + chdir(home ? home : "/root"); + execle("/bin/bash", "-bash", NULL, env_use); + execle("/bin/sh", "-sh", NULL, env_use); + } + + log_error("execv() failed: %m"); + + child_fail: + _exit(EXIT_FAILURE); + } + + fdset_free(fds); + fds = NULL; + + r = register_machine(pid); + if (r < 0) + goto finish; + + r = move_network_interfaces(pid); + if (r < 0) + goto finish; + + r = setup_veth(pid, veth_name); + if (r < 0) + goto finish; + + r = setup_bridge(veth_name); + if (r < 0) + goto finish; + + eventfd_write(sync_fd, 1); + close_nointr_nofail(sync_fd); + sync_fd = -1; + + k = process_pty(master, &mask, arg_boot ? pid : 0, SIGRTMIN+3); + if (k < 0) { + r = EXIT_FAILURE; + break; + } + + if (!arg_quiet) + putc('\n', stdout); + + /* Kill if it is not dead yet anyway */ + terminate_machine(pid); + + /* Redundant, but better safe than sorry */ + kill(pid, SIGKILL); + + k = wait_for_terminate(pid, &status); + pid = 0; + + if (k < 0) { + r = EXIT_FAILURE; + break; + } + + if (status.si_code == CLD_EXITED) { + r = status.si_status; + if (status.si_status != 0) { + log_error("Container %s failed with error code %i.", arg_machine, status.si_status); + break; + } + + if (!arg_quiet) + log_debug("Container %s exited successfully.", arg_machine); + break; + } else if (status.si_code == CLD_KILLED && + status.si_status == SIGINT) { + + if (!arg_quiet) + log_info("Container %s has been shut down.", arg_machine); + r = 0; + break; + } else if (status.si_code == CLD_KILLED && + status.si_status == SIGHUP) { + + if (!arg_quiet) + log_info("Container %s is being rebooted.", arg_machine); + continue; + } else if (status.si_code == CLD_KILLED || + status.si_code == CLD_DUMPED) { + + log_error("Container %s terminated by signal %s.", arg_machine, signal_to_string(status.si_status)); + r = EXIT_FAILURE; + break; + } else { + log_error("Container %s failed due to unknown reason.", arg_machine); + r = EXIT_FAILURE; + break; + } + } + +finish: + if (pid > 0) + kill(pid, SIGKILL); + + free(arg_directory); + free(arg_machine); + free(arg_setenv); + free(arg_network_interfaces); + + return r; +} diff --git a/src/nss-myhostname/Makefile b/src/nss-myhostname/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/nss-myhostname/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/nss-myhostname/ifconf.h b/src/nss-myhostname/ifconf.h new file mode 100644 index 0000000..cd598d2 --- /dev/null +++ b/src/nss-myhostname/ifconf.h @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2008-2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +struct address { + unsigned char family; + uint8_t address[16]; + unsigned char scope; + int ifindex; +}; + +#define _public_ __attribute__ ((visibility("default"))) +#define _hidden_ __attribute__ ((visibility("hidden"))) + +int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) _hidden_; + +static inline size_t PROTO_ADDRESS_SIZE(int proto) { + assert(proto == AF_INET || proto == AF_INET6); + + return proto == AF_INET6 ? 16 : 4; +} + +static inline int address_compare(const void *_a, const void *_b) { + const struct address *a = _a, *b = _b; + + /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */ + + if (a->scope < b->scope) + return -1; + if (a->scope > b->scope) + return 1; + + if (a->family == AF_INET && b->family == AF_INET6) + return -1; + if (a->family == AF_INET6 && b->family == AF_INET) + return 1; + + if (a->ifindex < b->ifindex) + return -1; + if (a->ifindex > b->ifindex) + return 1; + + return 0; +} diff --git a/src/nss-myhostname/netlink.c b/src/nss-myhostname/netlink.c new file mode 100644 index 0000000..d61ecdf --- /dev/null +++ b/src/nss-myhostname/netlink.c @@ -0,0 +1,206 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2008-2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifconf.h" + +#define SEQ 4711 + +static int read_reply(int fd, struct address **list, unsigned *n_list) { + ssize_t bytes; + struct cmsghdr *cmsg; + struct ucred *ucred; + struct nlmsghdr *p; + uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))]; + struct { + struct nlmsghdr hdr; + struct ifaddrmsg ifaddrmsg; + uint8_t payload[16*1024]; + } resp; + struct iovec iov = { + .iov_base = &resp, + .iov_len = sizeof(resp), + }; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cred_buffer, + .msg_controllen = sizeof(cred_buffer), + .msg_flags = 0, + }; + + assert(fd >= 0); + assert(list); + + bytes = recvmsg(fd, &msg, 0); + if (bytes < 0) + return -errno; + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) + return -EIO; + + ucred = (struct ucred*) CMSG_DATA(cmsg); + if (ucred->uid != 0 || ucred->pid != 0) + return 0; + + for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) { + struct ifaddrmsg *ifaddrmsg; + struct rtattr *a; + size_t l; + void *local = NULL, *address = NULL; + + if (!NLMSG_OK(p, (size_t) bytes)) + return -EIO; + + if (p->nlmsg_seq != SEQ) + continue; + + if (p->nlmsg_type == NLMSG_DONE) + return 1; + + if (p->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *nlmsgerr; + + nlmsgerr = NLMSG_DATA(p); + return -nlmsgerr->error; + } + + if (p->nlmsg_type != RTM_NEWADDR) + continue; + + ifaddrmsg = NLMSG_DATA(p); + + if (ifaddrmsg->ifa_family != AF_INET && + ifaddrmsg->ifa_family != AF_INET6) + continue; + + if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST || + ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE) + continue; + + if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED) + continue; + + l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg)); + a = IFA_RTA(ifaddrmsg); + + while (RTA_OK(a, l)) { + + if (a->rta_type == IFA_ADDRESS) + address = RTA_DATA(a); + else if (a->rta_type == IFA_LOCAL) + local = RTA_DATA(a); + + a = RTA_NEXT(a, l); + } + + if (local) + address = local; + + if (!address) + continue; + + *list = realloc(*list, (*n_list+1) * sizeof(struct address)); + if (!*list) + return -ENOMEM; + + (*list)[*n_list].family = ifaddrmsg->ifa_family; + (*list)[*n_list].scope = ifaddrmsg->ifa_scope; + memcpy((*list)[*n_list].address, + address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16); + (*list)[*n_list].ifindex = ifaddrmsg->ifa_index; + + (*n_list)++; + } + + return 0; +} + + +int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) { + + struct { + struct nlmsghdr hdr; + struct rtgenmsg gen; + } req = { { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .nlmsg_type = RTM_GETADDR, + .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK, + .nlmsg_seq = SEQ, + .nlmsg_pid = 0, + }, { + .rtgen_family = AF_UNSPEC, + } + }; + int r, on = 1; + struct address *list = NULL; + unsigned n_list = 0; + int fd; + + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd < 0) + return -errno; + + if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { + r = -errno; + goto finish; + } + + if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) { + r = -errno; + goto finish; + } + + while((r = read_reply(fd, &list, &n_list)) == 0) + ; + +finish: + close(fd); + + if (r < 0) { + free(list); + return r; + } + + if (n_list) + qsort(list, n_list, sizeof(struct address), address_compare); + + *_list = list; + *_n_list = n_list; + + return 0; +} diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c new file mode 100644 index 0000000..60e256d --- /dev/null +++ b/src/nss-myhostname/nss-myhostname.c @@ -0,0 +1,533 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2008-2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifconf.h" +#include "macro.h" + +/* Ensure that glibc's assert is used. We cannot use assert from macro.h, as + * libnss_myhostname will be linked into arbitrary programs which will, in turn + * attempt to write to the journal via log_dispatch() */ +#include + +/* 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 + * IPv6 we use ::1 which unfortunately will not translate back to the + * hostname but instead something like "localhost6" or so. */ + +#define LOCALADDRESS_IPV4 (htonl(0x7F000002)) +#define LOCALADDRESS_IPV6 &in6addr_loopback +#define LOOPBACK_INTERFACE "lo" + +enum nss_status _nss_myhostname_gethostbyname4_r( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp) _public_; + +enum nss_status _nss_myhostname_gethostbyname3_r( + const char *name, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp) _public_; + +enum nss_status _nss_myhostname_gethostbyname2_r( + const char *name, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) _public_; + +enum nss_status _nss_myhostname_gethostbyname_r( + const char *name, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) _public_; + +enum nss_status _nss_myhostname_gethostbyaddr2_r( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp) _public_; + +enum nss_status _nss_myhostname_gethostbyaddr_r( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) _public_; + +enum nss_status _nss_myhostname_gethostbyname4_r( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp) { + + unsigned lo_ifi; + char hn[HOST_NAME_MAX+1] = {}; + const char *canonical = NULL; + size_t l, idx, ms; + char *r_name; + struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL; + struct address *addresses = NULL, *a; + unsigned n_addresses = 0, n; + uint32_t local_address_ipv4; + + if (strcasecmp(name, "localhost") == 0) { + /* We respond to 'localhost', so that /etc/hosts + * is optional */ + + canonical = "localhost"; + local_address_ipv4 = htonl(INADDR_LOOPBACK); + } else { + /* We respond to our local host name */ + + if (gethostname(hn, sizeof(hn)-1) < 0) { + *errnop = errno; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + if (strcasecmp(name, hn) != 0) { + *errnop = ENOENT; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + /* If this fails, n_addresses is 0. Which is fine */ + ifconf_acquire_addresses(&addresses, &n_addresses); + + canonical = hn; + local_address_ipv4 = LOCALADDRESS_IPV4; + } + + /* If this call fails we fill in 0 as scope. Which is fine */ + lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0; + + l = strlen(canonical); + ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*(n_addresses > 0 ? n_addresses : 2); + if (buflen < ms) { + *errnop = ENOMEM; + *h_errnop = NO_RECOVERY; + free(addresses); + return NSS_STATUS_TRYAGAIN; + } + + /* First, fill in hostname */ + r_name = buffer; + memcpy(r_name, canonical, l+1); + idx = ALIGN(l+1); + + if (n_addresses <= 0) { + /* Second, fill in IPv6 tuple */ + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = r_tuple_prev; + r_tuple->name = r_name; + r_tuple->family = AF_INET6; + memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16); + r_tuple->scopeid = (uint32_t) lo_ifi; + + idx += ALIGN(sizeof(struct gaih_addrtuple)); + r_tuple_prev = r_tuple; + + /* Third, fill in IPv4 tuple */ + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = r_tuple_prev; + r_tuple->name = r_name; + r_tuple->family = AF_INET; + *(uint32_t*) r_tuple->addr = local_address_ipv4; + r_tuple->scopeid = (uint32_t) lo_ifi; + + idx += ALIGN(sizeof(struct gaih_addrtuple)); + r_tuple_prev = r_tuple; + } + + /* Fourth, fill actual addresses in, but in backwards order */ + for (a = addresses + n_addresses - 1, n = 0; n < n_addresses; n++, a--) { + r_tuple = (struct gaih_addrtuple*) (buffer + idx); + r_tuple->next = r_tuple_prev; + r_tuple->name = r_name; + r_tuple->family = a->family; + r_tuple->scopeid = a->ifindex; + memcpy(r_tuple->addr, a->address, 16); + + idx += ALIGN(sizeof(struct gaih_addrtuple)); + r_tuple_prev = r_tuple; + } + + /* Verify the size matches */ + assert(idx == ms); + + /* Nscd expects us to store the first record in **pat. */ + if (*pat) + **pat = *r_tuple_prev; + else + *pat = r_tuple_prev; + + if (ttlp) + *ttlp = 0; + + free(addresses); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status fill_in_hostent( + const char *canonical, const char *additional, + int af, + struct address *addresses, unsigned n_addresses, + uint32_t local_address_ipv4, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp) { + + size_t l_canonical, l_additional, idx, ms; + char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list; + size_t alen; + struct address *a; + unsigned n, c; + + alen = PROTO_ADDRESS_SIZE(af); + + for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++) + if (af == a->family) + c++; + + l_canonical = strlen(canonical); + l_additional = additional ? strlen(additional) : 0; + ms = ALIGN(l_canonical+1)+ + (additional ? ALIGN(l_additional+1) : 0) + + sizeof(char*)+ + (additional ? sizeof(char*) : 0) + + (c > 0 ? c : 1)*ALIGN(alen)+ + (c > 0 ? c+1 : 2)*sizeof(char*); + + if (buflen < ms) { + *errnop = ENOMEM; + *h_errnop = NO_RECOVERY; + free(addresses); + return NSS_STATUS_TRYAGAIN; + } + + /* First, fill in hostnames */ + r_name = buffer; + memcpy(r_name, canonical, l_canonical+1); + idx = ALIGN(l_canonical+1); + + if (additional) { + r_alias = buffer + idx; + memcpy(r_alias, additional, l_additional+1); + idx += ALIGN(l_additional+1); + } + + /* Second, create aliases array */ + r_aliases = buffer + idx; + if (additional) { + ((char**) r_aliases)[0] = r_alias; + ((char**) r_aliases)[1] = NULL; + idx += 2*sizeof(char*); + } else { + ((char**) r_aliases)[0] = NULL; + idx += sizeof(char*); + } + + /* Third, add addresses */ + r_addr = buffer + idx; + if (c > 0) { + unsigned i = 0; + + for (a = addresses, n = 0; n < n_addresses; a++, n++) { + if (af != a->family) + continue; + + memcpy(r_addr + i*ALIGN(alen), a->address, alen); + i++; + } + + assert(i == c); + idx += c*ALIGN(alen); + } else { + if (af == AF_INET) + *(uint32_t*) r_addr = local_address_ipv4; + else + memcpy(r_addr, LOCALADDRESS_IPV6, 16); + + idx += ALIGN(alen); + } + + /* Fourth, add address pointer array */ + r_addr_list = buffer + idx; + if (c > 0) { + unsigned i = 0; + + for (a = addresses, n = 0; n < n_addresses; a++, n++) { + if (af != a->family) + continue; + + ((char**) r_addr_list)[i] = (r_addr + i*ALIGN(alen)); + i++; + } + + assert(i == c); + ((char**) r_addr_list)[c] = NULL; + idx += (c+1)*sizeof(char*); + + } else { + ((char**) r_addr_list)[0] = r_addr; + ((char**) r_addr_list)[1] = NULL; + idx += 2*sizeof(char*); + } + + /* Verify the size matches */ + assert(idx == ms); + + result->h_name = r_name; + result->h_aliases = (char**) r_aliases; + result->h_addrtype = af; + result->h_length = alen; + result->h_addr_list = (char**) r_addr_list; + + if (ttlp) + *ttlp = 0; + + if (canonp) + *canonp = r_name; + + free(addresses); + + return NSS_STATUS_SUCCESS; +} + +enum nss_status _nss_myhostname_gethostbyname3_r( + const char *name, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp) { + + char hn[HOST_NAME_MAX+1] = {}; + struct address *addresses = NULL; + unsigned n_addresses = 0; + const char *canonical, *additional = NULL; + uint32_t local_address_ipv4; + + if (af == AF_UNSPEC) + af = AF_INET; + + if (af != AF_INET && af != AF_INET6) { + *errnop = EAFNOSUPPORT; + *h_errnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + if (strcasecmp(name, "localhost") == 0) { + canonical = "localhost"; + local_address_ipv4 = htonl(INADDR_LOOPBACK); + } else { + if (gethostname(hn, sizeof(hn)-1) < 0) { + *errnop = errno; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + if (strcasecmp(name, hn) != 0) { + *errnop = ENOENT; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + + ifconf_acquire_addresses(&addresses, &n_addresses); + + canonical = hn; + additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL; + local_address_ipv4 = LOCALADDRESS_IPV4; + } + + return fill_in_hostent( + canonical, additional, + af, + addresses, n_addresses, + local_address_ipv4, + host, + buffer, buflen, + errnop, h_errnop, + ttlp, + canonp); +} + +enum nss_status _nss_myhostname_gethostbyname2_r( + const char *name, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) { + + return _nss_myhostname_gethostbyname3_r( + name, + af, + host, + buffer, buflen, + errnop, h_errnop, + NULL, + NULL); +} + +enum nss_status _nss_myhostname_gethostbyname_r( + const char *name, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) { + + return _nss_myhostname_gethostbyname3_r( + name, + AF_UNSPEC, + host, + buffer, buflen, + errnop, h_errnop, + NULL, + NULL); +} + +enum nss_status _nss_myhostname_gethostbyaddr2_r( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp) { + + char hn[HOST_NAME_MAX+1] = {}; + struct address *addresses = NULL; + struct address *a; + unsigned n_addresses = 0, n; + uint32_t local_address_ipv4 = LOCALADDRESS_IPV4; + const char *canonical = NULL, *additional = NULL; + + if (len != PROTO_ADDRESS_SIZE(af)) { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } + + if (af == AF_INET) { + + if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) + goto found; + + if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) { + canonical = "localhost"; + local_address_ipv4 = htonl(INADDR_LOOPBACK); + goto found; + } + + } else if (af == AF_INET6) { + + if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) { + additional = "localhost"; + goto found; + } + + } else { + *errnop = EAFNOSUPPORT; + *h_errnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } + + ifconf_acquire_addresses(&addresses, &n_addresses); + + for (a = addresses, n = 0; n < n_addresses; n++, a++) { + if (af != a->family) + continue; + + if (memcmp(addr, a->address, PROTO_ADDRESS_SIZE(af)) == 0) + goto found; + } + + *errnop = ENOENT; + *h_errnop = HOST_NOT_FOUND; + + free(addresses); + + return NSS_STATUS_NOTFOUND; + +found: + if (!canonical) { + if (gethostname(hn, sizeof(hn)-1) < 0) { + *errnop = errno; + *h_errnop = NO_RECOVERY; + + free(addresses); + + return NSS_STATUS_UNAVAIL; + } + + canonical = hn; + } + + return fill_in_hostent( + canonical, additional, + af, + addresses, n_addresses, + local_address_ipv4, + host, + buffer, buflen, + errnop, h_errnop, + ttlp, + NULL); + +} + +enum nss_status _nss_myhostname_gethostbyaddr_r( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop) { + + return _nss_myhostname_gethostbyaddr2_r( + addr, len, + af, + host, + buffer, buflen, + errnop, h_errnop, + NULL); +} diff --git a/src/org.freedesktop.hostname1.conf b/src/org.freedesktop.hostname1.conf deleted file mode 100644 index eb241c0..0000000 --- a/src/org.freedesktop.hostname1.conf +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.hostname1.policy.in b/src/org.freedesktop.hostname1.policy.in deleted file mode 100644 index 7d56b22..0000000 --- a/src/org.freedesktop.hostname1.policy.in +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Set host name - <_message>Authentication is required to set the local host name. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Set static host name - <_message>Authentication is required to set the statically configured local host name, as well as the pretty host name. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Set machine information - <_message>Authentication is required to set local machine information. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - diff --git a/src/org.freedesktop.hostname1.service b/src/org.freedesktop.hostname1.service deleted file mode 100644 index 42e4adb..0000000 --- a/src/org.freedesktop.hostname1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.hostname1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.hostname1.service diff --git a/src/org.freedesktop.locale1.conf b/src/org.freedesktop.locale1.conf deleted file mode 100644 index 6827331..0000000 --- a/src/org.freedesktop.locale1.conf +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.locale1.policy.in b/src/org.freedesktop.locale1.policy.in deleted file mode 100644 index 1ac50bf..0000000 --- a/src/org.freedesktop.locale1.policy.in +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Set system locale - <_message>Authentication is required to set the system locale. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Set system keyboard settings - <_message>Authentication is required to set the system keyboard settings. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - diff --git a/src/org.freedesktop.locale1.service b/src/org.freedesktop.locale1.service deleted file mode 100644 index 29bd582..0000000 --- a/src/org.freedesktop.locale1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.locale1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.locale1.service diff --git a/src/org.freedesktop.login1.conf b/src/org.freedesktop.login1.conf deleted file mode 100644 index c423ef5..0000000 --- a/src/org.freedesktop.login1.conf +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.login1.policy.in b/src/org.freedesktop.login1.policy.in deleted file mode 100644 index adc9048..0000000 --- a/src/org.freedesktop.login1.policy.in +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Allow non-logged-in users to run programs - <_message>Authentication is required to allow a non-logged-in user to run programs - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Allow attaching devices to seats - <_message>Authentication is required to allow attaching a device to a seat - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Flush device to seat attachments - <_message>Authentication is required to allow resetting how devices are attached to seats - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Power off the system - <_message>Authentication is required to allow powering off the system - - auth_admin_keep - auth_admin_keep - yes - - - - - <_description>Power off the system when other users are logged in - <_message>Authentication is required to allow powering off the system while other users are logged in - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Reboot the system - <_message>Authentication is required to allow rebooting the system - - auth_admin_keep - auth_admin_keep - yes - - - - - <_description>Reboot the system when other users are logged in - <_message>Authentication is required to allow rebooting the system while other users are logged in - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - diff --git a/src/org.freedesktop.login1.service b/src/org.freedesktop.login1.service deleted file mode 100644 index 4a64177..0000000 --- a/src/org.freedesktop.login1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.login1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.login1.service diff --git a/src/org.freedesktop.systemd1.conf b/src/org.freedesktop.systemd1.conf deleted file mode 100644 index 201afe6..0000000 --- a/src/org.freedesktop.systemd1.conf +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.systemd1.policy.in.in b/src/org.freedesktop.systemd1.policy.in.in deleted file mode 100644 index 1771314..0000000 --- a/src/org.freedesktop.systemd1.policy.in.in +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Send passphrase back to system - <_message>Authentication is required to send the entered passphrase back to the system. - - no - no - auth_admin_keep - - @rootlibexecdir@/systemd-reply-password - - - - <_description>Privileged system and service manager access - <_message>Authentication is required to access the system and service manager. - - no - no - auth_admin_keep - - @bindir@/systemd-stdio-bridge - - - diff --git a/src/org.freedesktop.systemd1.service b/src/org.freedesktop.systemd1.service deleted file mode 100644 index 7e1dfd4..0000000 --- a/src/org.freedesktop.systemd1.service +++ /dev/null @@ -1,11 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.systemd1 -Exec=/bin/false -User=root diff --git a/src/org.freedesktop.timedate1.conf b/src/org.freedesktop.timedate1.conf deleted file mode 100644 index c9c221b..0000000 --- a/src/org.freedesktop.timedate1.conf +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.timedate1.policy.in b/src/org.freedesktop.timedate1.policy.in deleted file mode 100644 index 3d9c208..0000000 --- a/src/org.freedesktop.timedate1.policy.in +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Set system time - <_message>Authentication is required to set the system time. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Set system timezone - <_message>Authentication is required to set the system timezone. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Set RTC to local timezone or UTC - <_message>Authentication is required to control whether - the RTC stores the local or UTC time. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Turn network time synchronization on or off - <_message>Authentication is required to control whether - network time synchronization shall be enabled. - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - diff --git a/src/org.freedesktop.timedate1.service b/src/org.freedesktop.timedate1.service deleted file mode 100644 index c3120b6..0000000 --- a/src/org.freedesktop.timedate1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.timedate1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.timedate1.service diff --git a/src/pager.c b/src/pager.c deleted file mode 100644 index 3fc8182..0000000 --- a/src/pager.c +++ /dev/null @@ -1,134 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "pager.h" -#include "util.h" -#include "macro.h" - -static pid_t pager_pid = 0; - -_noreturn_ static void pager_fallback(void) { - ssize_t n; - do { - n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0); - } while (n > 0); - if (n < 0) { - log_error("Internal pager failed: %m"); - _exit(EXIT_FAILURE); - } - _exit(EXIT_SUCCESS); -} - -void pager_open(void) { - int fd[2]; - const char *pager; - pid_t parent_pid; - - if (pager_pid > 0) - return; - - if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) - if (!*pager || streq(pager, "cat")) - return; - - if (isatty(STDOUT_FILENO) <= 0) - return; - - /* Determine and cache number of columns before we spawn the - * pager so that we get the value from the actual tty */ - columns(); - - if (pipe(fd) < 0) { - log_error("Failed to create pager pipe: %m"); - return; - } - - parent_pid = getpid(); - - pager_pid = fork(); - if (pager_pid < 0) { - log_error("Failed to fork pager: %m"); - close_pipe(fd); - return; - } - - /* In the child start the pager */ - if (pager_pid == 0) { - - dup2(fd[0], STDIN_FILENO); - close_pipe(fd); - - setenv("LESS", "FRSX", 0); - - /* Make sure the pager goes away when the parent dies */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - _exit(EXIT_FAILURE); - - /* Check whether our parent died before we were able - * to set the death signal */ - if (getppid() != parent_pid) - _exit(EXIT_SUCCESS); - - if (pager) { - execlp(pager, pager, NULL); - execl("/bin/sh", "sh", "-c", pager, NULL); - } - - /* Debian's alternatives command for pagers is - * called 'pager'. Note that we do not call - * sensible-pagers here, since that is just a - * shell script that implements a logic that - * is similar to this one anyway, but is - * Debian-specific. */ - execlp("pager", "pager", NULL); - - execlp("less", "less", NULL); - execlp("more", "more", NULL); - - pager_fallback(); - /* not reached */ - } - - /* Return in the parent */ - if (dup2(fd[1], STDOUT_FILENO) < 0) - log_error("Failed to duplicate pager pipe: %m"); - - close_pipe(fd); -} - -void pager_close(void) { - - if (pager_pid <= 0) - return; - - /* Inform pager that we are done */ - fclose(stdout); - kill(pager_pid, SIGCONT); - wait_for_terminate(pager_pid, NULL); - pager_pid = 0; -} diff --git a/src/pager.h b/src/pager.h deleted file mode 100644 index b5b4998..0000000 --- a/src/pager.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foopagerhfoo -#define foopagerhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -void pager_open(void); -void pager_close(void); - -#endif diff --git a/src/pam-module.c b/src/pam-module.c deleted file mode 100644 index dd05f93..0000000 --- a/src/pam-module.c +++ /dev/null @@ -1,622 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "util.h" -#include "macro.h" -#include "sd-daemon.h" -#include "strv.h" -#include "dbus-common.h" -#include "def.h" -#include "socket-util.h" - -static int parse_argv(pam_handle_t *handle, - int argc, const char **argv, - char ***controllers, - char ***reset_controllers, - bool *kill_processes, - char ***kill_only_users, - char ***kill_exclude_users, - bool *debug) { - - unsigned i; - - assert(argc >= 0); - assert(argc == 0 || argv); - - for (i = 0; i < (unsigned) argc; i++) { - int k; - - if (startswith(argv[i], "kill-session-processes=")) { - if ((k = parse_boolean(argv[i] + 23)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to parse kill-session-processes= argument."); - return k; - } - - if (kill_processes) - *kill_processes = k; - - } else if (startswith(argv[i], "kill-session=")) { - /* As compatibility for old versions */ - - if ((k = parse_boolean(argv[i] + 13)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to parse kill-session= argument."); - return k; - } - - if (kill_processes) - *kill_processes = k; - - } else if (startswith(argv[i], "controllers=")) { - - if (controllers) { - char **l; - - if (!(l = strv_split(argv[i] + 12, ","))) { - pam_syslog(handle, LOG_ERR, "Out of memory."); - return -ENOMEM; - } - - strv_free(*controllers); - *controllers = l; - } - - } else if (startswith(argv[i], "reset-controllers=")) { - - if (reset_controllers) { - char **l; - - if (!(l = strv_split(argv[i] + 18, ","))) { - pam_syslog(handle, LOG_ERR, "Out of memory."); - return -ENOMEM; - } - - strv_free(*reset_controllers); - *reset_controllers = l; - } - - } else if (startswith(argv[i], "kill-only-users=")) { - - if (kill_only_users) { - char **l; - - if (!(l = strv_split(argv[i] + 16, ","))) { - pam_syslog(handle, LOG_ERR, "Out of memory."); - return -ENOMEM; - } - - strv_free(*kill_only_users); - *kill_only_users = l; - } - - } else if (startswith(argv[i], "kill-exclude-users=")) { - - if (kill_exclude_users) { - char **l; - - if (!(l = strv_split(argv[i] + 19, ","))) { - pam_syslog(handle, LOG_ERR, "Out of memory."); - return -ENOMEM; - } - - strv_free(*kill_exclude_users); - *kill_exclude_users = l; - } - - } else if (startswith(argv[i], "debug=")) { - if ((k = parse_boolean(argv[i] + 6)) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to parse debug= argument."); - return k; - } - - if (debug) - *debug = k; - - } else if (startswith(argv[i], "create-session=") || - startswith(argv[i], "kill-user=")) { - - pam_syslog(handle, LOG_WARNING, "Option %s not supported anymore, ignoring.", argv[i]); - - } else { - pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]); - return -EINVAL; - } - } - - return 0; -} - -static int get_user_data( - pam_handle_t *handle, - const char **ret_username, - struct passwd **ret_pw) { - - const char *username = NULL; - struct passwd *pw = NULL; - int r; - bool have_loginuid = false; - char *s; - - assert(handle); - assert(ret_username); - assert(ret_pw); - - if (have_effective_cap(CAP_AUDIT_CONTROL) > 0) { - /* Only use audit login uid if we are executed with - * sufficient capabilities so that pam_loginuid could - * do its job. If we are lacking the CAP_AUDIT_CONTROL - * capabality we most likely are being run in a - * container and /proc/self/loginuid is useless since - * it probably contains a uid of the host system. */ - - if (read_one_line_file("/proc/self/loginuid", &s) >= 0) { - uid_t uid; - - r = parse_uid(s, &uid); - free(s); - - if (r >= 0 && uid != (uint32_t) -1) { - have_loginuid = true; - pw = pam_modutil_getpwuid(handle, uid); - } - } - } - - if (!have_loginuid) { - if ((r = pam_get_user(handle, &username, NULL)) != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to get user name."); - return r; - } - - if (!username || !*username) { - pam_syslog(handle, LOG_ERR, "User name not valid."); - return PAM_AUTH_ERR; - } - - pw = pam_modutil_getpwnam(handle, username); - } - - if (!pw) { - pam_syslog(handle, LOG_ERR, "Failed to get user data."); - return PAM_USER_UNKNOWN; - } - - *ret_pw = pw; - *ret_username = username ? username : pw->pw_name; - - return PAM_SUCCESS; -} - -static bool check_user_lists( - pam_handle_t *handle, - uid_t uid, - char **kill_only_users, - char **kill_exclude_users) { - - const char *name = NULL; - char **l; - - assert(handle); - - if (uid == 0) - name = "root"; /* Avoid obvious NSS requests, to suppress network traffic */ - else { - struct passwd *pw; - - pw = pam_modutil_getpwuid(handle, uid); - if (pw) - name = pw->pw_name; - } - - STRV_FOREACH(l, kill_exclude_users) { - uid_t u; - - if (parse_uid(*l, &u) >= 0) - if (u == uid) - return false; - - if (name && streq(name, *l)) - return false; - } - - if (strv_isempty(kill_only_users)) - return true; - - STRV_FOREACH(l, kill_only_users) { - uid_t u; - - if (parse_uid(*l, &u) >= 0) - if (u == uid) - return true; - - if (name && streq(name, *l)) - return true; - } - - return false; -} - -static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) { - char *p = NULL; - int r; - int fd; - union sockaddr_union sa; - struct ucred ucred; - socklen_t l; - char *tty; - int v; - - assert(display); - assert(seat); - assert(vtnr); - - /* We deduce the X11 socket from the display name, then use - * SO_PEERCRED to determine the X11 server process, ask for - * the controlling tty of that and if it's a VC then we know - * the seat and the virtual terminal. Sounds ugly, is only - * semi-ugly. */ - - r = socket_from_display(display, &p); - if (r < 0) - return r; - - fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (fd < 0) { - free(p); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, p, sizeof(sa.un.sun_path)-1); - free(p); - - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - l = sizeof(ucred); - r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l); - close_nointr_nofail(fd); - - if (r < 0) - return -errno; - - r = get_ctty(ucred.pid, NULL, &tty); - if (r < 0) - return r; - - v = vtnr_from_tty(tty); - free(tty); - - if (v < 0) - return v; - else if (v == 0) - return -ENOENT; - - *seat = "seat0"; - *vtnr = (uint32_t) v; - - return 0; -} - -_public_ PAM_EXTERN int pam_sm_open_session( - pam_handle_t *handle, - int flags, - int argc, const char **argv) { - - struct passwd *pw; - bool kill_processes = false, debug = false; - const char *username, *id, *object_path, *runtime_path, *service = NULL, *tty = NULL, *display = NULL, *remote_user = NULL, *remote_host = NULL, *seat = NULL, *type, *cvtnr = NULL; - char **controllers = NULL, **reset_controllers = NULL, **kill_only_users = NULL, **kill_exclude_users = NULL; - DBusError error; - uint32_t uid, pid; - DBusMessageIter iter; - dbus_bool_t kp; - int session_fd = -1; - DBusConnection *bus = NULL; - DBusMessage *m = NULL, *reply = NULL; - dbus_bool_t remote; - int r; - uint32_t vtnr = 0; - - assert(handle); - - dbus_error_init(&error); - - /* pam_syslog(handle, LOG_INFO, "pam-systemd initializing"); */ - - /* Make this a NOP on non-systemd systems */ - if (sd_booted() <= 0) - return PAM_SUCCESS; - - if (parse_argv(handle, - argc, argv, - &controllers, &reset_controllers, - &kill_processes, &kill_only_users, &kill_exclude_users, - &debug) < 0) { - r = PAM_SESSION_ERR; - goto finish; - } - - r = get_user_data(handle, &username, &pw); - if (r != PAM_SUCCESS) - goto finish; - - /* Make sure we don't enter a loop by talking to - * systemd-logind when it is actually waiting for the - * background to finish start-up. If the service is - * "systemd-shared" we simply set XDG_RUNTIME_DIR and - * leave. */ - - pam_get_item(handle, PAM_SERVICE, (const void**) &service); - if (streq_ptr(service, "systemd-shared")) { - char *p, *rt = NULL; - - if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) pw->pw_uid) < 0) { - r = PAM_BUF_ERR; - goto finish; - } - - r = parse_env_file(p, NEWLINE, - "RUNTIME", &rt, - NULL); - free(p); - - if (r < 0 && r != -ENOENT) { - r = PAM_SESSION_ERR; - free(rt); - goto finish; - } - - if (rt) { - r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); - free(rt); - - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); - goto finish; - } - } - - r = PAM_SUCCESS; - goto finish; - } - - if (kill_processes) - kill_processes = check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users); - - dbus_connection_set_change_sigpipe(FALSE); - - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!bus) { - pam_syslog(handle, LOG_ERR, "Failed to connect to system bus: %s", bus_error_message(&error)); - r = PAM_SESSION_ERR; - goto finish; - } - - m = dbus_message_new_method_call( - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "CreateSession"); - - if (!m) { - pam_syslog(handle, LOG_ERR, "Could not allocate create session message."); - r = PAM_BUF_ERR; - goto finish; - } - - uid = pw->pw_uid; - pid = getpid(); - - pam_get_item(handle, PAM_XDISPLAY, (const void**) &display); - pam_get_item(handle, PAM_TTY, (const void**) &tty); - pam_get_item(handle, PAM_RUSER, (const void**) &remote_user); - pam_get_item(handle, PAM_RHOST, (const void**) &remote_host); - seat = pam_getenv(handle, "XDG_SEAT"); - cvtnr = pam_getenv(handle, "XDG_VTNR"); - - service = strempty(service); - tty = strempty(tty); - display = strempty(display); - remote_user = strempty(remote_user); - remote_host = strempty(remote_host); - seat = strempty(seat); - - if (strchr(tty, ':')) { - /* A tty with a colon is usually an X11 display, place - * there to show up in utmp. We rearrange things and - * don't pretend that an X display was a tty */ - - if (isempty(display)) - display = tty; - tty = ""; - } - - if (!isempty(cvtnr)) - safe_atou32(cvtnr, &vtnr); - - if (!isempty(display) && isempty(seat) && vtnr <= 0) - get_seat_from_display(display, &seat, &vtnr); - - type = !isempty(display) ? "x11" : - !isempty(tty) ? "tty" : "other"; - - remote = !isempty(remote_host) && !streq(remote_host, "localhost") && !streq(remote_host, "localhost.localdomain"); - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &uid, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_STRING, &service, - DBUS_TYPE_STRING, &type, - DBUS_TYPE_STRING, &seat, - DBUS_TYPE_UINT32, &vtnr, - DBUS_TYPE_STRING, &tty, - DBUS_TYPE_STRING, &display, - DBUS_TYPE_BOOLEAN, &remote, - DBUS_TYPE_STRING, &remote_user, - DBUS_TYPE_STRING, &remote_host, - DBUS_TYPE_INVALID)) { - pam_syslog(handle, LOG_ERR, "Could not attach parameters to message."); - r = PAM_BUF_ERR; - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - r = bus_append_strv_iter(&iter, controllers); - if (r < 0) { - pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); - r = PAM_BUF_ERR; - goto finish; - } - - r = bus_append_strv_iter(&iter, reset_controllers); - if (r < 0) { - pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); - r = PAM_BUF_ERR; - goto finish; - } - - kp = kill_processes; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &kp)) { - pam_syslog(handle, LOG_ERR, "Could not attach parameter to message."); - r = PAM_BUF_ERR; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error)); - r = PAM_SESSION_ERR; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &id, - DBUS_TYPE_OBJECT_PATH, &object_path, - DBUS_TYPE_STRING, &runtime_path, - DBUS_TYPE_UNIX_FD, &session_fd, - DBUS_TYPE_STRING, &seat, - DBUS_TYPE_UINT32, &vtnr, - DBUS_TYPE_INVALID)) { - pam_syslog(handle, LOG_ERR, "Failed to parse message: %s", bus_error_message(&error)); - r = PAM_SESSION_ERR; - goto finish; - } - - r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set session id."); - goto finish; - } - - r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); - goto finish; - } - - if (!isempty(seat)) { - r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set seat."); - goto finish; - } - } - - if (vtnr > 0) { - char buf[11]; - snprintf(buf, sizeof(buf), "%u", vtnr); - char_array_0(buf); - - r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number."); - goto finish; - } - } - - if (session_fd >= 0) { - r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to install session fd."); - return r; - } - } - - session_fd = -1; - - r = PAM_SUCCESS; - -finish: - strv_free(controllers); - strv_free(reset_controllers); - strv_free(kill_only_users); - strv_free(kill_exclude_users); - - dbus_error_free(&error); - - if (bus) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - if (session_fd >= 0) - close_nointr_nofail(session_fd); - - return r; -} - -_public_ PAM_EXTERN int pam_sm_close_session( - pam_handle_t *handle, - int flags, - int argc, const char **argv) { - - const void *p = NULL; - - pam_get_data(handle, "systemd.session-fd", &p); - - if (p) - close_nointr(PTR_TO_INT(p) - 1); - - return PAM_SUCCESS; -} diff --git a/src/path-lookup.c b/src/path-lookup.c deleted file mode 100644 index 5f5ad8c..0000000 --- a/src/path-lookup.c +++ /dev/null @@ -1,345 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" - -#include "path-lookup.h" - -int user_config_home(char **config_home) { - const char *e; - - if ((e = getenv("XDG_CONFIG_HOME"))) { - if (asprintf(config_home, "%s/systemd/user", e) < 0) - return -ENOMEM; - - return 1; - } else { - const char *home; - - if ((home = getenv("HOME"))) { - if (asprintf(config_home, "%s/.config/systemd/user", home) < 0) - return -ENOMEM; - - return 1; - } - } - - return 0; -} - -static char** user_dirs(void) { - const char * const config_unit_paths[] = { - "/run/systemd/user", - USER_CONFIG_UNIT_PATH, - "/etc/systemd/user", - NULL - }; - - const char * const data_unit_paths[] = { - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", - USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", - NULL - }; - - const char *home, *e; - char *config_home = NULL, *data_home = NULL; - char **config_dirs = NULL, **data_dirs = NULL; - char **r = NULL, **t; - - /* Implement the mechanisms defined in - * - * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html - * - * We look in both the config and the data dirs because we - * want to encourage that distributors ship their unit files - * as data, and allow overriding as configuration. - */ - - if (user_config_home(&config_home) < 0) - goto fail; - - home = getenv("HOME"); - - if ((e = getenv("XDG_CONFIG_DIRS"))) - if (!(config_dirs = strv_split(e, ":"))) - goto fail; - - /* We don't treat /etc/xdg/systemd here as the spec - * suggests because we assume that that is a link to - * /etc/systemd/ anyway. */ - - if ((e = getenv("XDG_DATA_HOME"))) { - if (asprintf(&data_home, "%s/systemd/user", e) < 0) - goto fail; - - } else if (home) { - if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0) - goto fail; - - /* There is really no need for two unit dirs in $HOME, - * except to be fully compliant with the XDG spec. We - * now try to link the two dirs, so that we can - * minimize disk seeks a little. Further down we'll - * then filter out this link, if it is actually is - * one. */ - - mkdir_parents(data_home, 0777); - (void) symlink("../../../.config/systemd/user", data_home); - } - - if ((e = getenv("XDG_DATA_DIRS"))) - data_dirs = strv_split(e, ":"); - else - data_dirs = strv_new("/usr/local/share", - "/usr/share", - NULL); - - if (!data_dirs) - goto fail; - - /* Now merge everything we found. */ - if (config_home) { - if (!(t = strv_append(r, config_home))) - goto fail; - strv_free(r); - r = t; - } - - if (!strv_isempty(config_dirs)) { - if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user"))) - goto finish; - strv_free(r); - r = t; - } - - if (!(t = strv_merge(r, (char**) config_unit_paths))) - goto fail; - strv_free(r); - r = t; - - if (data_home) { - if (!(t = strv_append(r, data_home))) - goto fail; - strv_free(r); - r = t; - } - - if (!strv_isempty(data_dirs)) { - if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user"))) - goto fail; - strv_free(r); - r = t; - } - - if (!(t = strv_merge(r, (char**) data_unit_paths))) - goto fail; - strv_free(r); - r = t; - - if (!strv_path_make_absolute_cwd(r)) - goto fail; - -finish: - free(config_home); - strv_free(config_dirs); - free(data_home); - strv_free(data_dirs); - - return r; - -fail: - strv_free(r); - r = NULL; - goto finish; -} - -int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) { - const char *e; - char *t; - - assert(p); - - /* First priority is whatever has been passed to us via env - * vars */ - if ((e = getenv("SYSTEMD_UNIT_PATH"))) - if (!(p->unit_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(p->unit_path)) { - - /* Nothing is set, so let's figure something out. */ - strv_free(p->unit_path); - - if (running_as == MANAGER_USER) { - - if (personal) - p->unit_path = user_dirs(); - else - p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemduserunitpath= in systemd.pc.in, and - * the arrays in user_dirs() above! */ - "/run/systemd/user", - USER_CONFIG_UNIT_PATH, - "/etc/systemd/user", - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", - USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", - NULL); - - if (!p->unit_path) - return -ENOMEM; - - } else - if (!(p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemdsystemunitpath= in systemd.pc.in! */ - "/run/systemd/system", - SYSTEM_CONFIG_UNIT_PATH, - "/etc/systemd/system", - "/usr/local/lib/systemd/system", - "/usr/lib/systemd/system", - SYSTEM_DATA_UNIT_PATH, - "/lib/systemd/system", - NULL))) - return -ENOMEM; - } - - if (p->unit_path) - if (!strv_path_canonicalize(p->unit_path)) - return -ENOMEM; - - strv_uniq(p->unit_path); - strv_path_remove_empty(p->unit_path); - - if (!strv_isempty(p->unit_path)) { - - if (!(t = strv_join(p->unit_path, "\n\t"))) - return -ENOMEM; - log_debug("Looking for unit files in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring unit files."); - strv_free(p->unit_path); - p->unit_path = NULL; - } - - if (running_as == MANAGER_SYSTEM) { -#ifdef HAVE_SYSV_COMPAT - /* /etc/init.d/ compatibility does not matter to users */ - - if ((e = getenv("SYSTEMD_SYSVINIT_PATH"))) - if (!(p->sysvinit_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(p->sysvinit_path)) { - strv_free(p->sysvinit_path); - - if (!(p->sysvinit_path = strv_new( - SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ - NULL))) - return -ENOMEM; - } - - if ((e = getenv("SYSTEMD_SYSVRCND_PATH"))) - if (!(p->sysvrcnd_path = split_path_and_make_absolute(e))) - return -ENOMEM; - - if (strv_isempty(p->sysvrcnd_path)) { - strv_free(p->sysvrcnd_path); - - if (!(p->sysvrcnd_path = strv_new( - SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ - NULL))) - return -ENOMEM; - } - - if (p->sysvinit_path) - if (!strv_path_canonicalize(p->sysvinit_path)) - return -ENOMEM; - - if (p->sysvrcnd_path) - if (!strv_path_canonicalize(p->sysvrcnd_path)) - return -ENOMEM; - - strv_uniq(p->sysvinit_path); - strv_uniq(p->sysvrcnd_path); - - strv_path_remove_empty(p->sysvinit_path); - strv_path_remove_empty(p->sysvrcnd_path); - - if (!strv_isempty(p->sysvinit_path)) { - - if (!(t = strv_join(p->sysvinit_path, "\n\t"))) - return -ENOMEM; - - log_debug("Looking for SysV init scripts in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV init scripts."); - strv_free(p->sysvinit_path); - p->sysvinit_path = NULL; - } - - if (!strv_isempty(p->sysvrcnd_path)) { - - if (!(t = strv_join(p->sysvrcnd_path, "\n\t"))) - return -ENOMEM; - - log_debug("Looking for SysV rcN.d links in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV rcN.d links."); - strv_free(p->sysvrcnd_path); - p->sysvrcnd_path = NULL; - } -#else - log_debug("Disabled SysV init scripts and rcN.d links support"); -#endif - } - - return 0; -} - -void lookup_paths_free(LookupPaths *p) { - assert(p); - - strv_free(p->unit_path); - p->unit_path = NULL; - -#ifdef HAVE_SYSV_COMPAT - strv_free(p->sysvinit_path); - strv_free(p->sysvrcnd_path); - p->sysvinit_path = p->sysvrcnd_path = NULL; -#endif -} diff --git a/src/path-lookup.h b/src/path-lookup.h deleted file mode 100644 index fc2887d..0000000 --- a/src/path-lookup.h +++ /dev/null @@ -1,40 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foopathlookuphfoo -#define foopathlookuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct LookupPaths { - char **unit_path; -#ifdef HAVE_SYSV_COMPAT - char **sysvinit_path; - char **sysvrcnd_path; -#endif -} LookupPaths; - -#include "manager.h" - -int user_config_home(char **config_home); - -int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal); -void lookup_paths_free(LookupPaths *p); - -#endif diff --git a/src/path.c b/src/path.c deleted file mode 100644 index f15c921..0000000 --- a/src/path.c +++ /dev/null @@ -1,717 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "unit.h" -#include "unit-name.h" -#include "path.h" -#include "dbus-path.h" -#include "special.h" -#include "bus-errors.h" - -static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { - [PATH_DEAD] = UNIT_INACTIVE, - [PATH_WAITING] = UNIT_ACTIVE, - [PATH_RUNNING] = UNIT_ACTIVE, - [PATH_FAILED] = UNIT_FAILED -}; - -static void path_init(Unit *u) { - Path *p = PATH(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - p->directory_mode = 0755; -} - -static void path_unwatch_one(Path *p, PathSpec *s) { - - if (s->inotify_fd < 0) - return; - - unit_unwatch_fd(UNIT(p), &s->watch); - - close_nointr_nofail(s->inotify_fd); - s->inotify_fd = -1; -} - -static void path_done(Unit *u) { - Path *p = PATH(u); - PathSpec *s; - - assert(p); - - while ((s = p->specs)) { - path_unwatch_one(p, s); - LIST_REMOVE(PathSpec, spec, p->specs, s); - free(s->path); - free(s); - } -} - -int path_add_one_mount_link(Path *p, Mount *m) { - PathSpec *s; - int r; - - assert(p); - assert(m); - - if (p->meta.load_state != UNIT_LOADED || - m->meta.load_state != UNIT_LOADED) - return 0; - - LIST_FOREACH(spec, s, p->specs) { - - if (!path_startswith(s->path, m->where)) - continue; - - if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - } - - return 0; -} - -static int path_add_mount_links(Path *p) { - Meta *other; - int r; - - assert(p); - - LIST_FOREACH(units_by_type, other, p->meta.manager->units_by_type[UNIT_MOUNT]) - if ((r = path_add_one_mount_link(p, (Mount*) other)) < 0) - return r; - - return 0; -} - -static int path_verify(Path *p) { - assert(p); - - if (p->meta.load_state != UNIT_LOADED) - return 0; - - if (!p->specs) { - log_error("%s lacks path setting. Refusing.", p->meta.id); - return -EINVAL; - } - - return 0; -} - -static int path_add_default_dependencies(Path *p) { - int r; - - assert(p); - - if (p->meta.manager->running_as == MANAGER_SYSTEM) { - if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0) - return r; - - if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0) - return r; - } - - return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); -} - -static int path_load(Unit *u) { - Path *p = PATH(u); - int r; - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - if ((r = unit_load_fragment_and_dropin(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_LOADED) { - - if (!p->unit) - if ((r = unit_load_related_unit(u, ".service", &p->unit))) - return r; - - if ((r = unit_add_dependency(u, UNIT_BEFORE, p->unit, true)) < 0) - return r; - - if ((r = path_add_mount_links(p)) < 0) - return r; - - if (p->meta.default_dependencies) - if ((r = path_add_default_dependencies(p)) < 0) - return r; - } - - return path_verify(p); -} - -static void path_dump(Unit *u, FILE *f, const char *prefix) { - Path *p = PATH(u); - PathSpec *s; - - assert(p); - assert(f); - - fprintf(f, - "%sPath State: %s\n" - "%sUnit: %s\n" - "%sMakeDirectory: %s\n" - "%sDirectoryMode: %04o\n", - prefix, path_state_to_string(p->state), - prefix, p->unit->meta.id, - prefix, yes_no(p->make_directory), - prefix, p->directory_mode); - - LIST_FOREACH(spec, s, p->specs) - fprintf(f, - "%s%s: %s\n", - prefix, - path_type_to_string(s->type), - s->path); -} - -static int path_watch_one(Path *p, PathSpec *s) { - static const int flags_table[_PATH_TYPE_MAX] = { - [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB, - [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB, - [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO, - [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO - }; - - bool exists = false; - char *k, *slash; - int r; - - assert(p); - assert(s); - - path_unwatch_one(p, s); - - if (!(k = strdup(s->path))) - return -ENOMEM; - - if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) { - r = -errno; - goto fail; - } - - if (unit_watch_fd(UNIT(p), s->inotify_fd, EPOLLIN, &s->watch) < 0) { - r = -errno; - goto fail; - } - - if ((s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type])) >= 0) - exists = true; - - do { - int flags; - - /* This assumes the path was passed through path_kill_slashes()! */ - if (!(slash = strrchr(k, '/'))) - break; - - /* Trim the path at the last slash. Keep the slash if it's the root dir. */ - slash[slash == k] = 0; - - flags = IN_MOVE_SELF; - if (!exists) - flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO; - - if (inotify_add_watch(s->inotify_fd, k, flags) >= 0) - exists = true; - } while (slash != k); - - return 0; - -fail: - free(k); - - path_unwatch_one(p, s); - return r; -} - -static void path_unwatch(Path *p) { - PathSpec *s; - - assert(p); - - LIST_FOREACH(spec, s, p->specs) - path_unwatch_one(p, s); -} - -static int path_watch(Path *p) { - int r; - PathSpec *s; - - assert(p); - - LIST_FOREACH(spec, s, p->specs) - if ((r = path_watch_one(p, s)) < 0) - return r; - - return 0; -} - -static void path_set_state(Path *p, PathState state) { - PathState old_state; - assert(p); - - old_state = p->state; - p->state = state; - - if (state != PATH_WAITING && - (state != PATH_RUNNING || p->inotify_triggered)) - path_unwatch(p); - - if (state != old_state) - log_debug("%s changed %s -> %s", - p->meta.id, - path_state_to_string(old_state), - path_state_to_string(state)); - - unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true); -} - -static void path_enter_waiting(Path *p, bool initial, bool recheck); - -static int path_coldplug(Unit *u) { - Path *p = PATH(u); - - assert(p); - assert(p->state == PATH_DEAD); - - if (p->deserialized_state != p->state) { - - if (p->deserialized_state == PATH_WAITING || - p->deserialized_state == PATH_RUNNING) - path_enter_waiting(p, true, true); - else - path_set_state(p, p->deserialized_state); - } - - return 0; -} - -static void path_enter_dead(Path *p, bool success) { - assert(p); - - if (!success) - p->failure = true; - - path_set_state(p, p->failure ? PATH_FAILED : PATH_DEAD); -} - -static void path_enter_running(Path *p) { - int r; - DBusError error; - - assert(p); - dbus_error_init(&error); - - /* Don't start job if we are supposed to go down */ - if (p->meta.job && p->meta.job->type == JOB_STOP) - return; - - if ((r = manager_add_job(p->meta.manager, JOB_START, p->unit, JOB_REPLACE, true, &error, NULL)) < 0) - goto fail; - - p->inotify_triggered = false; - - if ((r = path_watch(p)) < 0) - goto fail; - - path_set_state(p, PATH_RUNNING); - return; - -fail: - log_warning("%s failed to queue unit startup job: %s", p->meta.id, bus_error(&error, r)); - path_enter_dead(p, false); - - dbus_error_free(&error); -} - -static bool path_check_good(Path *p, bool initial) { - PathSpec *s; - bool good = false; - - assert(p); - - LIST_FOREACH(spec, s, p->specs) { - - switch (s->type) { - - case PATH_EXISTS: - good = access(s->path, F_OK) >= 0; - break; - - case PATH_EXISTS_GLOB: - good = glob_exists(s->path) > 0; - break; - - case PATH_DIRECTORY_NOT_EMPTY: { - int k; - - k = dir_is_empty(s->path); - good = !(k == -ENOENT || k > 0); - break; - } - - case PATH_CHANGED: { - bool b; - - b = access(s->path, F_OK) >= 0; - good = !initial && b != s->previous_exists; - s->previous_exists = b; - break; - } - - default: - ; - } - - if (good) - break; - } - - return good; -} - -static void path_enter_waiting(Path *p, bool initial, bool recheck) { - int r; - - if (recheck) - if (path_check_good(p, initial)) { - log_debug("%s got triggered.", p->meta.id); - path_enter_running(p); - return; - } - - if ((r = path_watch(p)) < 0) - goto fail; - - /* Hmm, so now we have created inotify watches, but the file - * might have appeared/been removed by now, so we must - * recheck */ - - if (recheck) - if (path_check_good(p, false)) { - log_debug("%s got triggered.", p->meta.id); - path_enter_running(p); - return; - } - - path_set_state(p, PATH_WAITING); - return; - -fail: - log_warning("%s failed to enter waiting state: %s", p->meta.id, strerror(-r)); - path_enter_dead(p, false); -} - -static void path_mkdir(Path *p) { - PathSpec *s; - - assert(p); - - if (!p->make_directory) - return; - - LIST_FOREACH(spec, s, p->specs) { - int r; - - if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB) - continue; - - if ((r = mkdir_p(s->path, p->directory_mode)) < 0) - log_warning("mkdir(%s) failed: %s", s->path, strerror(-r)); - } -} - -static int path_start(Unit *u) { - Path *p = PATH(u); - - assert(p); - assert(p->state == PATH_DEAD || p->state == PATH_FAILED); - - if (p->unit->meta.load_state != UNIT_LOADED) - return -ENOENT; - - path_mkdir(p); - - p->failure = false; - path_enter_waiting(p, true, true); - - return 0; -} - -static int path_stop(Unit *u) { - Path *p = PATH(u); - - assert(p); - assert(p->state == PATH_WAITING || p->state == PATH_RUNNING); - - path_enter_dead(p, true); - return 0; -} - -static int path_serialize(Unit *u, FILE *f, FDSet *fds) { - Path *p = PATH(u); - - assert(u); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", path_state_to_string(p->state)); - - return 0; -} - -static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Path *p = PATH(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - PathState state; - - if ((state = path_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - p->deserialized_state = state; - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState path_active_state(Unit *u) { - assert(u); - - return state_translation_table[PATH(u)->state]; -} - -static const char *path_sub_state_to_string(Unit *u) { - assert(u); - - return path_state_to_string(PATH(u)->state); -} - -static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Path *p = PATH(u); - int l; - ssize_t k; - uint8_t *buf = NULL; - struct inotify_event *e; - PathSpec *s; - bool changed; - - assert(p); - assert(fd >= 0); - - if (p->state != PATH_WAITING && - p->state != PATH_RUNNING) - return; - - /* log_debug("inotify wakeup on %s.", u->meta.id); */ - - if (events != EPOLLIN) { - log_error("Got Invalid poll event on inotify."); - goto fail; - } - - LIST_FOREACH(spec, s, p->specs) - if (s->inotify_fd == fd) - break; - - if (!s) { - log_error("Got event on unknown fd."); - goto fail; - } - - if (ioctl(fd, FIONREAD, &l) < 0) { - log_error("FIONREAD failed: %s", strerror(errno)); - goto fail; - } - - assert(l > 0); - - if (!(buf = malloc(l))) { - log_error("Failed to allocate buffer: %s", strerror(ENOMEM)); - goto fail; - } - - if ((k = read(fd, buf, l)) < 0) { - log_error("Failed to read inotify event: %s", strerror(-errno)); - goto fail; - } - - /* If we are already running, then remember that one event was - * dispatched so that we restart the service only if something - * actually changed on disk */ - p->inotify_triggered = true; - - e = (struct inotify_event*) buf; - - changed = false; - while (k > 0) { - size_t step; - - if (s->type == PATH_CHANGED && s->primary_wd == e->wd) - changed = true; - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) k); - - e = (struct inotify_event*) ((uint8_t*) e + step); - k -= step; - } - - if (changed) - path_enter_running(p); - else - path_enter_waiting(p, false, true); - - free(buf); - - return; - -fail: - free(buf); - path_enter_dead(p, false); -} - -void path_unit_notify(Unit *u, UnitActiveState new_state) { - char *n; - int r; - Iterator i; - - if (u->meta.type == UNIT_PATH) - return; - - SET_FOREACH(n, u->meta.names, i) { - char *k; - Unit *t; - Path *p; - - if (!(k = unit_name_change_suffix(n, ".path"))) { - r = -ENOMEM; - goto fail; - } - - t = manager_get_unit(u->meta.manager, k); - free(k); - - if (!t) - continue; - - if (t->meta.load_state != UNIT_LOADED) - continue; - - p = PATH(t); - - if (p->unit != u) - continue; - - if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) { - log_debug("%s got notified about unit deactivation.", p->meta.id); - - /* Hmm, so inotify was triggered since the - * last activation, so I guess we need to - * recheck what is going on. */ - path_enter_waiting(p, false, p->inotify_triggered); - } - } - - return; - -fail: - log_error("Failed find path unit: %s", strerror(-r)); -} - -static void path_reset_failed(Unit *u) { - Path *p = PATH(u); - - assert(p); - - if (p->state == PATH_FAILED) - path_set_state(p, PATH_DEAD); - - p->failure = false; -} - -static const char* const path_state_table[_PATH_STATE_MAX] = { - [PATH_DEAD] = "dead", - [PATH_WAITING] = "waiting", - [PATH_RUNNING] = "running", - [PATH_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); - -static const char* const path_type_table[_PATH_TYPE_MAX] = { - [PATH_EXISTS] = "PathExists", - [PATH_EXISTS_GLOB] = "PathExistsGlob", - [PATH_CHANGED] = "PathChanged", - [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty" -}; - -DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); - -const UnitVTable path_vtable = { - .suffix = ".path", - .sections = - "Unit\0" - "Path\0" - "Install\0", - - .init = path_init, - .done = path_done, - .load = path_load, - - .coldplug = path_coldplug, - - .dump = path_dump, - - .start = path_start, - .stop = path_stop, - - .serialize = path_serialize, - .deserialize_item = path_deserialize_item, - - .active_state = path_active_state, - .sub_state_to_string = path_sub_state_to_string, - - .fd_event = path_fd_event, - - .reset_failed = path_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Path", - .bus_message_handler = bus_path_message_handler -}; diff --git a/src/path.h b/src/path.h deleted file mode 100644 index 116fc63..0000000 --- a/src/path.h +++ /dev/null @@ -1,93 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foopathhfoo -#define foopathhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Path Path; - -#include "unit.h" -#include "mount.h" - -typedef enum PathState { - PATH_DEAD, - PATH_WAITING, - PATH_RUNNING, - PATH_FAILED, - _PATH_STATE_MAX, - _PATH_STATE_INVALID = -1 -} PathState; - -typedef enum PathType { - PATH_EXISTS, - PATH_EXISTS_GLOB, - PATH_DIRECTORY_NOT_EMPTY, - PATH_CHANGED, - _PATH_TYPE_MAX, - _PATH_TYPE_INVALID = -1 -} PathType; - -typedef struct PathSpec { - char *path; - - Watch watch; - - LIST_FIELDS(struct PathSpec, spec); - - PathType type; - int inotify_fd; - int primary_wd; - - bool previous_exists; - -} PathSpec; - -struct Path { - Meta meta; - - LIST_HEAD(PathSpec, specs); - - Unit *unit; - - PathState state, deserialized_state; - - bool failure; - bool inotify_triggered; - - bool make_directory; - mode_t directory_mode; -}; - -void path_unit_notify(Unit *u, UnitActiveState new_state); - -/* Called from the mount code figure out if a mount is a dependency of - * any of the paths of this path object */ -int path_add_one_mount_link(Path *p, Mount *m); - -extern const UnitVTable path_vtable; - -const char* path_state_to_string(PathState i); -PathState path_state_from_string(const char *s); - -const char* path_type_to_string(PathType i); -PathType path_type_from_string(const char *s); - -#endif diff --git a/src/polkit.c b/src/polkit.c deleted file mode 100644 index 5b67480..0000000 --- a/src/polkit.c +++ /dev/null @@ -1,190 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include - -#include "util.h" -#include "dbus-common.h" -#include "polkit.h" - -/* This mimics dbus_bus_get_unix_user() */ -static pid_t get_unix_process_id( - DBusConnection *connection, - const char *name, - DBusError *error) { - - DBusMessage *m = NULL, *reply = NULL; - uint32_t pid = 0; - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID"); - if (!m) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - goto finish; - } - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); - if (!reply) - goto finish; - - if (dbus_set_error_from_message(error, reply)) - goto finish; - - if (!dbus_message_get_args( - reply, error, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_INVALID)) - goto finish; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return (pid_t) pid; -} - -int verify_polkit( - DBusConnection *c, - DBusMessage *request, - const char *action, - bool interactive, - DBusError *error) { - - DBusMessage *m = NULL, *reply = NULL; - const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = ""; - const char *sender; - uint32_t flags = interactive ? 1 : 0; - pid_t pid_raw; - uint32_t pid_u32; - unsigned long long starttime_raw; - uint64_t starttime_u64; - DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant; - int r; - dbus_bool_t authorized = FALSE; - - assert(c); - assert(request); - - sender = dbus_message_get_sender(request); - if (!sender) - return -EINVAL; - - pid_raw = get_unix_process_id(c, sender, error); - if (pid_raw == 0) - return -EINVAL; - - r = get_starttime_of_pid(pid_raw, &starttime_raw); - if (r < 0) - return r; - - m = dbus_message_new_method_call( - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - "org.freedesktop.PolicyKit1.Authority", - "CheckAuthorization"); - if (!m) - return -ENOMEM; - - dbus_message_iter_init_append(m, &iter_msg); - - pid_u32 = (uint32_t) pid_raw; - starttime_u64 = (uint64_t) starttime_raw; - - if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) || - !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) || - !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) || - !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || - !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) || - !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) || - !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) || - !dbus_message_iter_close_container(&iter_dict, &iter_variant) || - !dbus_message_iter_close_container(&iter_array, &iter_dict) || - !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || - !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) || - !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) || - !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) || - !dbus_message_iter_close_container(&iter_dict, &iter_variant) || - !dbus_message_iter_close_container(&iter_array, &iter_dict) || - !dbus_message_iter_close_container(&iter_struct, &iter_array) || - !dbus_message_iter_close_container(&iter_msg, &iter_struct) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) || - !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) || - !dbus_message_iter_close_container(&iter_msg, &iter_array) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) { - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(c, m, -1, error); - if (!reply) { - r = -EIO; - goto finish; - } - - if (dbus_set_error_from_message(error, reply)) { - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter_msg) || - dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) { - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter_msg, &iter_struct); - - if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) { - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&iter_struct, &authorized); - - r = authorized ? 0 : -EPERM; - -finish: - - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return r; -} diff --git a/src/polkit.h b/src/polkit.h deleted file mode 100644 index fc4e771..0000000 --- a/src/polkit.h +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foopolkithfoo -#define foopolkithfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -int verify_polkit( - DBusConnection *c, - DBusMessage *request, - const char *action, - bool interactive, - DBusError *error); - -#endif diff --git a/src/python-systemd/.gitignore b/src/python-systemd/.gitignore new file mode 100644 index 0000000..4124b7a --- /dev/null +++ b/src/python-systemd/.gitignore @@ -0,0 +1,2 @@ +/id128-constants.h +*.py[oc] diff --git a/src/python-systemd/Makefile b/src/python-systemd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/python-systemd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/python-systemd/__init__.py b/src/python-systemd/__init__.py new file mode 100644 index 0000000..0d56b99 --- /dev/null +++ b/src/python-systemd/__init__.py @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012 David Strauss +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . diff --git a/src/python-systemd/_daemon.c b/src/python-systemd/_daemon.c new file mode 100644 index 0000000..7756a78 --- /dev/null +++ b/src/python-systemd/_daemon.c @@ -0,0 +1,331 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define PY_SSIZE_T_CLEAN +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#include +#pragma GCC diagnostic pop + +#include +#include +#include + +#include +#include "pyutil.h" +#include "macro.h" + +PyDoc_STRVAR(module__doc__, + "Python interface to the libsystemd-daemon library.\n\n" + "Provides _listen_fds, notify, booted, and is_* functions\n" + "which wrap sd_listen_fds, sd_notify, sd_booted, sd_is_* and\n" + "useful for socket activation and checking if the system is\n" + "running under systemd." +); + +PyDoc_STRVAR(booted__doc__, + "booted() -> bool\n\n" + "Return True iff this system is running under systemd.\n" + "Wraps sd_daemon_booted(3)." +); + +static PyObject* booted(PyObject *self, PyObject *args) { + int r; + assert(args == NULL); + + r = sd_booted(); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + +PyDoc_STRVAR(notify__doc__, + "notify(status, unset_environment=False) -> bool\n\n" + "Send a message to the init system about a status change.\n" + "Wraps sd_notify(3)."); + +static PyObject* notify(PyObject *self, PyObject *args, PyObject *keywds) { + int r; + const char* msg; + int unset = false; + + static const char* const kwlist[] = { + "status", + "unset_environment", + NULL, + }; +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3 + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p:notify", + (char**) kwlist, &msg, &unset)) + return NULL; +#else + PyObject *obj = NULL; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|O:notify", + (char**) kwlist, &msg, &obj)) + return NULL; + if (obj != NULL) + unset = PyObject_IsTrue(obj); + if (unset < 0) + return NULL; +#endif + + r = sd_notify(unset, msg); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + +PyDoc_STRVAR(listen_fds__doc__, + "_listen_fds(unset_environment=True) -> int\n\n" + "Return the number of descriptors passed to this process by the init system\n" + "as part of the socket-based activation logic.\n" + "Wraps sd_listen_fds(3)." +); + +static PyObject* listen_fds(PyObject *self, PyObject *args, PyObject *keywds) { + int r; + int unset = true; + + static const char* const kwlist[] = {"unset_environment", NULL}; +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3 + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|p:_listen_fds", + (char**) kwlist, &unset)) + return NULL; +#else + PyObject *obj = NULL; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O:_listen_fds", + (char**) kwlist, &obj)) + return NULL; + if (obj != NULL) + unset = PyObject_IsTrue(obj); + if (unset < 0) + return NULL; +#endif + + r = sd_listen_fds(unset); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return long_FromLong(r); +} + +PyDoc_STRVAR(is_fifo__doc__, + "_is_fifo(fd, path) -> bool\n\n" + "Returns True iff the descriptor refers to a FIFO or a pipe.\n" + "Wraps sd_is_fifo(3)." +); + + +static PyObject* is_fifo(PyObject *self, PyObject *args) { + int r; + int fd; + const char *path = NULL; + +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + if (!PyArg_ParseTuple(args, "i|O&:_is_fifo", + &fd, Unicode_FSConverter, &path)) + return NULL; +#else + if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path)) + return NULL; +#endif + + r = sd_is_fifo(fd, path); + if (set_error(r, path, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + +PyDoc_STRVAR(is_mq__doc__, + "_is_mq(fd, path) -> bool\n\n" + "Returns True iff the descriptor refers to a POSIX message queue.\n" + "Wraps sd_is_mq(3)." +); + +static PyObject* is_mq(PyObject *self, PyObject *args) { + int r; + int fd; + const char *path = NULL; + +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + if (!PyArg_ParseTuple(args, "i|O&:_is_mq", + &fd, Unicode_FSConverter, &path)) + return NULL; +#else + if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path)) + return NULL; +#endif + + r = sd_is_mq(fd, path); + if (set_error(r, path, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + + +PyDoc_STRVAR(is_socket__doc__, + "_is_socket(fd, family=AF_UNSPEC, type=0, listening=-1) -> bool\n\n" + "Returns True iff the descriptor refers to a socket.\n" + "Wraps sd_is_socket(3).\n\n" + "Constants for `family` are defined in the socket module." +); + +static PyObject* is_socket(PyObject *self, PyObject *args) { + int r; + int fd, family = AF_UNSPEC, type = 0, listening = -1; + + if (!PyArg_ParseTuple(args, "i|iii:_is_socket", + &fd, &family, &type, &listening)) + return NULL; + + r = sd_is_socket(fd, family, type, listening); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + +PyDoc_STRVAR(is_socket_inet__doc__, + "_is_socket_inet(fd, family=AF_UNSPEC, type=0, listening=-1, port=0) -> bool\n\n" + "Wraps sd_is_socket_inet(3).\n\n" + "Constants for `family` are defined in the socket module." +); + +static PyObject* is_socket_inet(PyObject *self, PyObject *args) { + int r; + int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0; + + if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet", + &fd, &family, &type, &listening, &port)) + return NULL; + + if (port < 0 || port > INT16_MAX) { + set_error(-EINVAL, NULL, "port must fit into uint16_t"); + return NULL; + } + + r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + +PyDoc_STRVAR(is_socket_unix__doc__, + "_is_socket_unix(fd, type, listening, path) -> bool\n\n" + "Wraps sd_is_socket_unix(3)." +); + +static PyObject* is_socket_unix(PyObject *self, PyObject *args) { + int r; + int fd, type = 0, listening = -1; + char* path = NULL; + Py_ssize_t length = 0; + +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + _cleanup_Py_DECREF_ PyObject *_path = NULL; + if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix", + &fd, &type, &listening, Unicode_FSConverter, &_path)) + return NULL; + if (_path) { + assert(PyBytes_Check(_path)); + if (PyBytes_AsStringAndSize(_path, &path, &length)) + return NULL; + } +#else + if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix", + &fd, &type, &listening, &path, &length)) + return NULL; +#endif + + r = sd_is_socket_unix(fd, type, listening, path, length); + if (set_error(r, path, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + + +static PyMethodDef methods[] = { + { "booted", booted, METH_NOARGS, booted__doc__}, + { "notify", (PyCFunction) notify, METH_VARARGS | METH_KEYWORDS, notify__doc__}, + { "_listen_fds", (PyCFunction) listen_fds, METH_VARARGS | METH_KEYWORDS, listen_fds__doc__}, + { "_is_fifo", is_fifo, METH_VARARGS, is_fifo__doc__}, + { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__}, + { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__}, + { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__}, + { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__}, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +#if PY_MAJOR_VERSION < 3 + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC init_daemon(void) { + PyObject *m; + + m = Py_InitModule3("_daemon", methods, module__doc__); + if (m == NULL) + return; + + PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START); + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); +} +REENABLE_WARNING; + +#else + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "_daemon", /* name of module */ + module__doc__, /* module documentation, may be NULL */ + 0, /* size of per-interpreter state of the module */ + methods +}; + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC PyInit__daemon(void) { + PyObject *m; + + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) || + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { + Py_DECREF(m); + return NULL; + } + + return m; +} +REENABLE_WARNING; + +#endif diff --git a/src/python-systemd/_journal.c b/src/python-systemd/_journal.c new file mode 100644 index 0000000..cbc661d --- /dev/null +++ b/src/python-systemd/_journal.c @@ -0,0 +1,157 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 David Strauss + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include +#include "util.h" + +#define SD_JOURNAL_SUPPRESS_LOCATION +#include + +PyDoc_STRVAR(journal_sendv__doc__, + "sendv('FIELD=value', 'FIELD=value', ...) -> None\n\n" + "Send an entry to the journal." +); + +static PyObject *journal_sendv(PyObject *self, PyObject *args) { + struct iovec *iov = NULL; + int argc; + int i, r; + PyObject *ret = NULL; + PyObject **encoded; + + /* Allocate an array for the argument strings */ + argc = PyTuple_Size(args); + encoded = alloca0(argc * sizeof(PyObject*)); + + /* Allocate sufficient iovector space for the arguments. */ + iov = alloca(argc * sizeof(struct iovec)); + + /* Iterate through the Python arguments and fill the iovector. */ + for (i = 0; i < argc; ++i) { + PyObject *item = PyTuple_GetItem(args, i); + char *stritem; + Py_ssize_t length; + + if (PyUnicode_Check(item)) { + encoded[i] = PyUnicode_AsEncodedString(item, "utf-8", "strict"); + if (encoded[i] == NULL) + goto out; + item = encoded[i]; + } + if (PyBytes_AsStringAndSize(item, &stritem, &length)) + goto out; + + iov[i].iov_base = stritem; + iov[i].iov_len = length; + } + + /* Send the iovector to the journal. */ + r = sd_journal_sendv(iov, argc); + if (r < 0) { + errno = -r; + PyErr_SetFromErrno(PyExc_IOError); + goto out; + } + + /* End with success. */ + Py_INCREF(Py_None); + ret = Py_None; + +out: + for (i = 0; i < argc; ++i) + Py_XDECREF(encoded[i]); + + return ret; +} + +PyDoc_STRVAR(journal_stream_fd__doc__, + "stream_fd(identifier, priority, level_prefix) -> fd\n\n" + "Open a stream to journal by calling sd_journal_stream_fd(3)." +); + +static PyObject* journal_stream_fd(PyObject *self, PyObject *args) { + const char* identifier; + int priority, level_prefix; + int fd; + + if (!PyArg_ParseTuple(args, "sii:stream_fd", + &identifier, &priority, &level_prefix)) + return NULL; + + fd = sd_journal_stream_fd(identifier, priority, level_prefix); + if (fd < 0) { + errno = -fd; + return PyErr_SetFromErrno(PyExc_IOError); + } + + return PyLong_FromLong(fd); +} + +static PyMethodDef methods[] = { + { "sendv", journal_sendv, METH_VARARGS, journal_sendv__doc__ }, + { "stream_fd", journal_stream_fd, METH_VARARGS, journal_stream_fd__doc__ }, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +#if PY_MAJOR_VERSION < 3 + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC init_journal(void) { + PyObject *m; + + m = Py_InitModule("_journal", methods); + if (m == NULL) + return; + + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); +} +REENABLE_WARNING; + +#else + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "_journal", /* name of module */ + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module */ + methods +}; + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC PyInit__journal(void) { + PyObject *m; + + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { + Py_DECREF(m); + return NULL; + } + + return m; +} +REENABLE_WARNING; + +#endif diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c new file mode 100644 index 0000000..059b904 --- /dev/null +++ b/src/python-systemd/_reader.c @@ -0,0 +1,1107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Steven Hiscocks, Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include + +#include "pyutil.h" +#include "macro.h" +#include "util.h" +#include "strv.h" +#include "build.h" + +typedef struct { + PyObject_HEAD + sd_journal *j; +} Reader; +static PyTypeObject ReaderType; + +PyDoc_STRVAR(module__doc__, + "Class to reads the systemd journal similar to journalctl."); + + +#if PY_MAJOR_VERSION >= 3 +static PyTypeObject MonotonicType; + +PyDoc_STRVAR(MonotonicType__doc__, + "A tuple of (timestamp, bootid) for holding monotonic timestamps"); + +static PyStructSequence_Field MonotonicType_fields[] = { + {(char*) "timestamp", (char*) "Time"}, + {(char*) "bootid", (char*) "Unique identifier of the boot"}, + {} /* Sentinel */ +}; + +static PyStructSequence_Desc Monotonic_desc = { + (char*) "journal.Monotonic", + MonotonicType__doc__, + MonotonicType_fields, + 2, +}; +#endif + +/** + * Convert a Python sequence object into a strv (char**), and + * None into a NULL pointer. + */ +static int strv_converter(PyObject* obj, void *_result) { + char ***result = _result; + Py_ssize_t i, len; + + assert(result); + + if (!obj) + return 0; + + if (obj == Py_None) { + *result = NULL; + return 1; + } + + if (!PySequence_Check(obj)) + return 0; + + len = PySequence_Length(obj); + *result = new0(char*, len + 1); + if (!*result) { + set_error(-ENOMEM, NULL, NULL); + return 0; + } + + for (i = 0; i < len; i++) { + PyObject *item; +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + int r; + PyObject *bytes; +#endif + char *s, *s2; + + item = PySequence_ITEM(obj, i); +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 + r = PyUnicode_FSConverter(item, &bytes); + if (r == 0) + goto cleanup; + + s = PyBytes_AsString(bytes); +#else + s = PyString_AsString(item); +#endif + if (!s) + goto cleanup; + + s2 = strdup(s); + if (!s2) + log_oom(); + + (*result)[i] = s2; + } + + return 1; + +cleanup: + strv_free(*result); + *result = NULL; + + return 0; +} + +static void Reader_dealloc(Reader* self) { + sd_journal_close(self->j); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(Reader__doc__, + "_Reader([flags | path | files]) -> ...\n\n" + "_Reader allows filtering and retrieval of Journal entries.\n" + "Note: this is a low-level interface, and probably not what you\n" + "want, use systemd.journal.Reader instead.\n\n" + "Argument `flags` sets open flags of the journal, which can be one\n" + "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n" + "journal on local machine only; RUNTIME_ONLY opens only\n" + "volatile journal files; and SYSTEM opens journal files of\n" + "system services and the kernel, and CURRENT_USER opens files\n" + "of the current user.\n\n" + "Argument `path` is the directory of journal files.\n" + "Argument `files` is a list of files. Note that\n" + "`flags`, `path`, and `files` are exclusive.\n\n" + "_Reader implements the context manager protocol: the journal\n" + "will be closed when exiting the block."); +static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { + int flags = 0, r; + char *path = NULL; + char **files = NULL; + + static const char* const kwlist[] = {"flags", "path", "files", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&:__init__", (char**) kwlist, + &flags, &path, strv_converter, &files)) + return -1; + + if (!!flags + !!path + !!files > 1) { + PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files"); + return -1; + } + + if (!flags) + flags = SD_JOURNAL_LOCAL_ONLY; + + Py_BEGIN_ALLOW_THREADS + if (path) + r = sd_journal_open_directory(&self->j, path, 0); + else if (files) + r = sd_journal_open_files(&self->j, (const char**) files, 0); + else + r = sd_journal_open(&self->j, flags); + Py_END_ALLOW_THREADS + + return set_error(r, path, "Invalid flags or path"); +} + +PyDoc_STRVAR(Reader_fileno__doc__, + "fileno() -> int\n\n" + "Get a file descriptor to poll for changes in the journal.\n" + "This method invokes sd_journal_get_fd().\n" + "See man:sd_journal_get_fd(3)."); +static PyObject* Reader_fileno(Reader *self, PyObject *args) { + int fd; + + fd = sd_journal_get_fd(self->j); + set_error(fd, NULL, NULL); + if (fd < 0) + return NULL; + return long_FromLong(fd); +} + +PyDoc_STRVAR(Reader_reliable_fd__doc__, + "reliable_fd() -> bool\n\n" + "Returns True iff the journal can be polled reliably.\n" + "This method invokes sd_journal_reliable_fd().\n" + "See man:sd_journal_reliable_fd(3)."); +static PyObject* Reader_reliable_fd(Reader *self, PyObject *args) { + int r; + + r = sd_journal_reliable_fd(self->j); + if (set_error(r, NULL, NULL) < 0) + return NULL; + return PyBool_FromLong(r); +} + +PyDoc_STRVAR(Reader_get_events__doc__, + "get_events() -> int\n\n" + "Returns a mask of poll() events to wait for on the file\n" + "descriptor returned by .fileno().\n\n" + "See man:sd_journal_get_events(3) for further discussion."); +static PyObject* Reader_get_events(Reader *self, PyObject *args) { + int r; + + r = sd_journal_get_events(self->j); + if (set_error(r, NULL, NULL) < 0) + return NULL; + return long_FromLong(r); +} + +PyDoc_STRVAR(Reader_get_timeout__doc__, + "get_timeout() -> int or None\n\n" + "Returns a timeout value for usage in poll(), the time since the\n" + "epoch of clock_gettime(2) in microseconds, or None if no timeout\n" + "is necessary.\n\n" + "The return value must be converted to a relative timeout in\n" + "milliseconds if it is to be used as an argument for poll().\n" + "See man:sd_journal_get_timeout(3) for further discussion."); +static PyObject* Reader_get_timeout(Reader *self, PyObject *args) { + int r; + uint64_t t; + + r = sd_journal_get_timeout(self->j, &t); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + if (t == (uint64_t) -1) + Py_RETURN_NONE; + + assert_cc(sizeof(unsigned long long) == sizeof(t)); + return PyLong_FromUnsignedLongLong(t); +} + +PyDoc_STRVAR(Reader_get_timeout_ms__doc__, + "get_timeout_ms() -> int\n\n" + "Returns a timeout value suitable for usage in poll(), the value\n" + "returned by .get_timeout() converted to relative ms, or -1 if\n" + "no timeout is necessary."); +static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) { + int r; + uint64_t t; + + r = sd_journal_get_timeout(self->j, &t); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return absolute_timeout(t); +} + +PyDoc_STRVAR(Reader_close__doc__, + "close() -> None\n\n" + "Free resources allocated by this Reader object.\n" + "This method invokes sd_journal_close().\n" + "See man:sd_journal_close(3)."); +static PyObject* Reader_close(Reader *self, PyObject *args) { + assert(self); + assert(!args); + + sd_journal_close(self->j); + self->j = NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_get_usage__doc__, + "get_usage() -> int\n\n" + "Returns the total disk space currently used by journal\n" + "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n" + "passed when opening the journal this value will only reflect\n" + "the size of journal files of the local host, otherwise\n" + "of all hosts.\n\n" + "This method invokes sd_journal_get_usage().\n" + "See man:sd_journal_get_usage(3)."); +static PyObject* Reader_get_usage(Reader *self, PyObject *args) { + int r; + uint64_t bytes; + + r = sd_journal_get_usage(self->j, &bytes); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + assert_cc(sizeof(unsigned long long) == sizeof(bytes)); + return PyLong_FromUnsignedLongLong(bytes); +} + +PyDoc_STRVAR(Reader___enter____doc__, + "__enter__() -> self\n\n" + "Part of the context manager protocol.\n" + "Returns self.\n"); +static PyObject* Reader___enter__(PyObject *self, PyObject *args) { + assert(self); + assert(!args); + + Py_INCREF(self); + return self; +} + +PyDoc_STRVAR(Reader___exit____doc__, + "__exit__(type, value, traceback) -> None\n\n" + "Part of the context manager protocol.\n" + "Closes the journal.\n"); +static PyObject* Reader___exit__(Reader *self, PyObject *args) { + return Reader_close(self, args); +} + +PyDoc_STRVAR(Reader_next__doc__, + "next([skip]) -> bool\n\n" + "Go to the next log entry. Optional skip value means to go to\n" + "the `skip`\\-th log entry.\n" + "Returns False if at end of file, True otherwise."); +static PyObject* Reader_next(Reader *self, PyObject *args) { + int64_t skip = 1LL; + int r; + + if (!PyArg_ParseTuple(args, "|L:next", &skip)) + return NULL; + + if (skip == 0LL) { + PyErr_SetString(PyExc_ValueError, "skip must be nonzero"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + if (skip == 1LL) + r = sd_journal_next(self->j); + else if (skip == -1LL) + r = sd_journal_previous(self->j); + else if (skip > 1LL) + r = sd_journal_next_skip(self->j, skip); + else if (skip < -1LL) + r = sd_journal_previous_skip(self->j, -skip); + else + assert_not_reached("should not be here"); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + return PyBool_FromLong(r); +} + +PyDoc_STRVAR(Reader_previous__doc__, + "previous([skip]) -> bool\n\n" + "Go to the previous log entry. Optional skip value means to \n" + "go to the `skip`\\-th previous log entry.\n" + "Returns False if at start of file, True otherwise."); +static PyObject* Reader_previous(Reader *self, PyObject *args) { + int64_t skip = 1LL; + if (!PyArg_ParseTuple(args, "|L:previous", &skip)) + return NULL; + + return PyObject_CallMethod((PyObject *)self, (char*) "_next", + (char*) "L", -skip); +} + +static int extract(const char* msg, size_t msg_len, + PyObject **key, PyObject **value) { + PyObject *k = NULL, *v; + const char *delim_ptr; + + delim_ptr = memchr(msg, '=', msg_len); + if (!delim_ptr) { + PyErr_SetString(PyExc_OSError, + "journal gave us a field without '='"); + return -1; + } + + if (key) { + k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg); + if (!k) + return -1; + } + + if (value) { + v = PyBytes_FromStringAndSize(delim_ptr + 1, + (const char*) msg + msg_len - (delim_ptr + 1)); + if (!v) { + Py_XDECREF(k); + return -1; + } + + *value = v; + } + + if (key) + *key = k; + + return 0; +} + +PyDoc_STRVAR(Reader_get__doc__, + "get(str) -> str\n\n" + "Return data associated with this key in current log entry.\n" + "Throws KeyError is the data is not available."); +static PyObject* Reader_get(Reader *self, PyObject *args) { + const char* field; + const void* msg; + size_t msg_len; + PyObject *value; + int r; + + assert(self); + assert(args); + + if (!PyArg_ParseTuple(args, "s:get", &field)) + return NULL; + + r = sd_journal_get_data(self->j, field, &msg, &msg_len); + if (r == -ENOENT) { + PyErr_SetString(PyExc_KeyError, field); + return NULL; + } + if (set_error(r, NULL, "field name is not valid") < 0) + return NULL; + + r = extract(msg, msg_len, NULL, &value); + if (r < 0) + return NULL; + return value; +} + +PyDoc_STRVAR(Reader_get_all__doc__, + "_get_all() -> dict\n\n" + "Return dictionary of the current log entry."); +static PyObject* Reader_get_all(Reader *self, PyObject *args) { + PyObject *dict; + const void *msg; + size_t msg_len; + int r; + + dict = PyDict_New(); + if (!dict) + return NULL; + + SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) { + _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL; + + r = extract(msg, msg_len, &key, &value); + if (r < 0) + goto error; + + if (PyDict_Contains(dict, key)) { + PyObject *cur_value = PyDict_GetItem(dict, key); + + if (PyList_CheckExact(cur_value)) { + r = PyList_Append(cur_value, value); + if (r < 0) + goto error; + } else { + _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0); + if (!tmp_list) + goto error; + + r = PyList_Append(tmp_list, cur_value); + if (r < 0) + goto error; + + r = PyList_Append(tmp_list, value); + if (r < 0) + goto error; + + r = PyDict_SetItem(dict, key, tmp_list); + if (r < 0) + goto error; + } + } else { + r = PyDict_SetItem(dict, key, value); + if (r < 0) + goto error; + } + } + + return dict; + +error: + Py_DECREF(dict); + return NULL; +} + +PyDoc_STRVAR(Reader_get_realtime__doc__, + "get_realtime() -> int\n\n" + "Return the realtime timestamp for the current journal entry\n" + "in microseconds.\n\n" + "Wraps sd_journal_get_realtime_usec().\n" + "See man:sd_journal_get_realtime_usec(3)."); +static PyObject* Reader_get_realtime(Reader *self, PyObject *args) { + uint64_t timestamp; + int r; + + assert(self); + assert(!args); + + r = sd_journal_get_realtime_usec(self->j, ×tamp); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + assert_cc(sizeof(unsigned long long) == sizeof(timestamp)); + return PyLong_FromUnsignedLongLong(timestamp); +} + +PyDoc_STRVAR(Reader_get_monotonic__doc__, + "get_monotonic() -> (timestamp, bootid)\n\n" + "Return the monotonic timestamp for the current journal entry\n" + "as a tuple of time in microseconds and bootid.\n\n" + "Wraps sd_journal_get_monotonic_usec().\n" + "See man:sd_journal_get_monotonic_usec(3)."); +static PyObject* Reader_get_monotonic(Reader *self, PyObject *args) { + uint64_t timestamp; + sd_id128_t id; + PyObject *monotonic, *bootid, *tuple; + int r; + + assert(self); + assert(!args); + + r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + assert_cc(sizeof(unsigned long long) == sizeof(timestamp)); + monotonic = PyLong_FromUnsignedLongLong(timestamp); + bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes)); +#if PY_MAJOR_VERSION >= 3 + tuple = PyStructSequence_New(&MonotonicType); +#else + tuple = PyTuple_New(2); +#endif + if (!monotonic || !bootid || !tuple) { + Py_XDECREF(monotonic); + Py_XDECREF(bootid); + Py_XDECREF(tuple); + return NULL; + } + +#if PY_MAJOR_VERSION >= 3 + PyStructSequence_SET_ITEM(tuple, 0, monotonic); + PyStructSequence_SET_ITEM(tuple, 1, bootid); +#else + PyTuple_SET_ITEM(tuple, 0, monotonic); + PyTuple_SET_ITEM(tuple, 1, bootid); +#endif + + return tuple; +} + +PyDoc_STRVAR(Reader_add_match__doc__, + "add_match(match) -> None\n\n" + "Add a match to filter journal log entries. All matches of different\n" + "fields are combined with logical AND, and matches of the same field\n" + "are automatically combined with logical OR.\n" + "Match is a string of the form \"FIELD=value\"."); +static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) { + char *match; + int match_len, r; + if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len)) + return NULL; + + r = sd_journal_add_match(self->j, match, match_len); + if (set_error(r, NULL, "Invalid match") < 0) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_add_disjunction__doc__, + "add_disjunction() -> None\n\n" + "Inserts a logical OR between matches added since previous\n" + "add_disjunction() or add_conjunction() and the next\n" + "add_disjunction() or add_conjunction().\n\n" + "See man:sd_journal_add_disjunction(3) for explanation."); +static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) { + int r; + r = sd_journal_add_disjunction(self->j); + if (set_error(r, NULL, NULL) < 0) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_add_conjunction__doc__, + "add_conjunction() -> None\n\n" + "Inserts a logical AND between matches added since previous\n" + "add_disjunction() or add_conjunction() and the next\n" + "add_disjunction() or add_conjunction().\n\n" + "See man:sd_journal_add_disjunction(3) for explanation."); +static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) { + int r; + r = sd_journal_add_conjunction(self->j); + if (set_error(r, NULL, NULL) < 0) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_flush_matches__doc__, + "flush_matches() -> None\n\n" + "Clear all current match filters."); +static PyObject* Reader_flush_matches(Reader *self, PyObject *args) { + sd_journal_flush_matches(self->j); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_seek_head__doc__, + "seek_head() -> None\n\n" + "Jump to the beginning of the journal.\n" + "This method invokes sd_journal_seek_head().\n" + "See man:sd_journal_seek_head(3)."); +static PyObject* Reader_seek_head(Reader *self, PyObject *args) { + int r; + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_head(self->j); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_seek_tail__doc__, + "seek_tail() -> None\n\n" + "Jump to the end of the journal.\n" + "This method invokes sd_journal_seek_tail().\n" + "See man:sd_journal_seek_tail(3)."); +static PyObject* Reader_seek_tail(Reader *self, PyObject *args) { + int r; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_tail(self->j); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_seek_realtime__doc__, + "seek_realtime(realtime) -> None\n\n" + "Seek to nearest matching journal entry to `realtime`. Argument\n" + "`realtime` in specified in seconds."); +static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) { + uint64_t timestamp; + int r; + + if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_realtime_usec(self->j, timestamp); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_seek_monotonic__doc__, + "seek_monotonic(monotonic[, bootid]) -> None\n\n" + "Seek to nearest matching journal entry to `monotonic`. Argument\n" + "`monotonic` is an timestamp from boot in microseconds.\n" + "Argument `bootid` is a string representing which boot the\n" + "monotonic time is reference to. Defaults to current bootid."); +static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) { + char *bootid = NULL; + uint64_t timestamp; + sd_id128_t id; + int r; + + if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid)) + return NULL; + + if (bootid) { + r = sd_id128_from_string(bootid, &id); + if (set_error(r, NULL, "Invalid bootid") < 0) + return NULL; + } else { + Py_BEGIN_ALLOW_THREADS + r = sd_id128_get_boot(&id); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_monotonic_usec(self->j, id, timestamp); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + Py_RETURN_NONE; +} + + +PyDoc_STRVAR(Reader_process__doc__, + "process() -> state change (integer)\n\n" + "Process events and reset the readable state of the file\n" + "descriptor returned by .fileno().\n\n" + "Will return constants: NOP if no change; APPEND if new\n" + "entries have been added to the end of the journal; and\n" + "INVALIDATE if journal files have been added or removed.\n\n" + "See man:sd_journal_process(3) for further discussion."); +static PyObject* Reader_process(Reader *self, PyObject *args) { + int r; + + assert(!args); + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_process(self->j); + Py_END_ALLOW_THREADS + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return long_FromLong(r); +} + +PyDoc_STRVAR(Reader_wait__doc__, + "wait([timeout]) -> state change (integer)\n\n" + "Wait for a change in the journal. Argument `timeout` specifies\n" + "the maximum number of microseconds to wait before returning\n" + "regardless of wheter the journal has changed. If `timeout` is -1,\n" + "then block forever.\n\n" + "Will return constants: NOP if no change; APPEND if new\n" + "entries have been added to the end of the journal; and\n" + "INVALIDATE if journal files have been added or removed.\n\n" + "See man:sd_journal_wait(3) for further discussion."); +static PyObject* Reader_wait(Reader *self, PyObject *args) { + int r; + int64_t timeout; + + if (!PyArg_ParseTuple(args, "|L:wait", &timeout)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_wait(self->j, timeout); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return long_FromLong(r); +} + +PyDoc_STRVAR(Reader_seek_cursor__doc__, + "seek_cursor(cursor) -> None\n\n" + "Seek to journal entry by given unique reference `cursor`."); +static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) { + const char *cursor; + int r; + + if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_seek_cursor(self->j, cursor); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, "Invalid cursor") < 0) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Reader_get_cursor__doc__, + "get_cursor() -> str\n\n" + "Return a cursor string for the current journal entry.\n\n" + "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3)."); +static PyObject* Reader_get_cursor(Reader *self, PyObject *args) { + _cleanup_free_ char *cursor = NULL; + int r; + + assert(self); + assert(!args); + + r = sd_journal_get_cursor(self->j, &cursor); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return unicode_FromString(cursor); +} + +PyDoc_STRVAR(Reader_test_cursor__doc__, + "test_cursor(str) -> bool\n\n" + "Test whether the cursor string matches current journal entry.\n\n" + "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3)."); +static PyObject* Reader_test_cursor(Reader *self, PyObject *args) { + const char *cursor; + int r; + + assert(self); + assert(args); + + if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor)) + return NULL; + + r = sd_journal_test_cursor(self->j, cursor); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return PyBool_FromLong(r); +} + +PyDoc_STRVAR(Reader_query_unique__doc__, + "query_unique(field) -> a set of values\n\n" + "Return a set of unique values appearing in journal for the\n" + "given `field`. Note this does not respect any journal matches."); +static PyObject* Reader_query_unique(Reader *self, PyObject *args) { + char *query; + int r; + const void *uniq; + size_t uniq_len; + PyObject *value_set, *key, *value; + + if (!PyArg_ParseTuple(args, "s:query_unique", &query)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_query_unique(self->j, query); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, "Invalid field name") < 0) + return NULL; + + value_set = PySet_New(0); + key = unicode_FromString(query); + + SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) { + const char *delim_ptr; + + delim_ptr = memchr(uniq, '=', uniq_len); + value = PyBytes_FromStringAndSize( + delim_ptr + 1, + (const char*) uniq + uniq_len - (delim_ptr + 1)); + PySet_Add(value_set, value); + Py_DECREF(value); + } + + Py_DECREF(key); + return value_set; +} + +PyDoc_STRVAR(Reader_get_catalog__doc__, + "get_catalog() -> str\n\n" + "Retrieve a message catalog entry for the current journal entry.\n" + "Will throw IndexError if the entry has no MESSAGE_ID\n" + "and KeyError is the id is specified, but hasn't been found\n" + "in the catalog.\n\n" + "Wraps man:sd_journal_get_catalog(3)."); +static PyObject* Reader_get_catalog(Reader *self, PyObject *args) { + int r; + _cleanup_free_ char *msg = NULL; + + assert(self); + assert(!args); + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_get_catalog(self->j, &msg); + Py_END_ALLOW_THREADS + + if (r == -ENOENT) { + const void* mid; + size_t mid_len; + + r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len); + if (r == 0) { + const size_t l = sizeof("MESSAGE_ID"); + assert(mid_len > l); + PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l), + (const char*) mid + l); + } else if (r == -ENOENT) + PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field"); + else + set_error(r, NULL, NULL); + return NULL; + } + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return unicode_FromString(msg); +} + +PyDoc_STRVAR(get_catalog__doc__, + "get_catalog(id128) -> str\n\n" + "Retrieve a message catalog entry for the given id.\n" + "Wraps man:sd_journal_get_catalog_for_message_id(3)."); +static PyObject* get_catalog(PyObject *self, PyObject *args) { + int r; + char *id_ = NULL; + sd_id128_t id; + _cleanup_free_ char *msg = NULL; + + assert(!self); + assert(args); + + if (!PyArg_ParseTuple(args, "z:get_catalog", &id_)) + return NULL; + + r = sd_id128_from_string(id_, &id); + if (set_error(r, NULL, "Invalid id128") < 0) + return NULL; + + Py_BEGIN_ALLOW_THREADS + r = sd_journal_get_catalog_for_message_id(id, &msg); + Py_END_ALLOW_THREADS + + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return unicode_FromString(msg); +} + +PyDoc_STRVAR(data_threshold__doc__, + "Threshold for field size truncation in bytes.\n\n" + "Fields longer than this will be truncated to the threshold size.\n" + "Defaults to 64Kb."); + +static PyObject* Reader_get_data_threshold(Reader *self, void *closure) { + size_t cvalue; + int r; + + r = sd_journal_get_data_threshold(self->j, &cvalue); + if (set_error(r, NULL, NULL) < 0) + return NULL; + + return long_FromSize_t(cvalue); +} + +static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) { + int r; + + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold"); + return -1; + } + + if (!long_Check(value)){ + PyErr_SetString(PyExc_TypeError, "Data threshold must be an int"); + return -1; + } + + r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value)); + return set_error(r, NULL, NULL); +} + +PyDoc_STRVAR(closed__doc__, + "True iff journal is closed"); +static PyObject* Reader_get_closed(Reader *self, void *closure) { + return PyBool_FromLong(self->j == NULL); +} + +static PyGetSetDef Reader_getsetters[] = { + { (char*) "data_threshold", + (getter) Reader_get_data_threshold, + (setter) Reader_set_data_threshold, + (char*) data_threshold__doc__, + NULL }, + { (char*) "closed", + (getter) Reader_get_closed, + NULL, + (char*) closed__doc__, + NULL }, + {} /* Sentinel */ +}; + +static PyMethodDef Reader_methods[] = { + {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__}, + {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__}, + {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__}, + {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__}, + {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__}, + {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__}, + {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__}, + {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__}, + {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__}, + {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__}, + {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__}, + {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__}, + {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__}, + {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__}, + {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__}, + {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__}, + {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__}, + {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__}, + {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__}, + {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__}, + {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__}, + {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__}, + {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__}, + {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__}, + {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__}, + {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__}, + {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__}, + {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__}, + {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__}, + {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__}, + {} /* Sentinel */ +}; + +static PyTypeObject ReaderType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_reader._Reader", + .tp_basicsize = sizeof(Reader), + .tp_dealloc = (destructor) Reader_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_doc = Reader__doc__, + .tp_methods = Reader_methods, + .tp_getset = Reader_getsetters, + .tp_init = (initproc) Reader_init, + .tp_new = PyType_GenericNew, +}; + +static PyMethodDef methods[] = { + { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__}, + {} /* Sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 +static PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "_reader", + module__doc__, + -1, + methods, +}; +#endif + +#if PY_MAJOR_VERSION >= 3 +static bool initialized = false; +#endif + +DISABLE_WARNING_MISSING_PROTOTYPES; + +PyMODINIT_FUNC +#if PY_MAJOR_VERSION >= 3 +PyInit__reader(void) +#else +init_reader(void) +#endif +{ + PyObject* m; + + PyDateTime_IMPORT; + + if (PyType_Ready(&ReaderType) < 0) +#if PY_MAJOR_VERSION >= 3 + return NULL; +#else + return; +#endif + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + if (!initialized) { + PyStructSequence_InitType(&MonotonicType, &Monotonic_desc); + initialized = true; + } +#else + m = Py_InitModule3("_reader", methods, module__doc__); + if (m == NULL) + return; +#endif + + Py_INCREF(&ReaderType); +#if PY_MAJOR_VERSION >= 3 + Py_INCREF(&MonotonicType); +#endif + if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) || +#if PY_MAJOR_VERSION >= 3 + PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) || +#endif + PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) || + PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) || + PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) || + PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) || + PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) || + PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) || + PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) || + PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) || + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { +#if PY_MAJOR_VERSION >= 3 + Py_DECREF(m); + return NULL; +#endif + } + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} + +REENABLE_WARNING; diff --git a/src/python-systemd/daemon.py b/src/python-systemd/daemon.py new file mode 100644 index 0000000..1c386bb --- /dev/null +++ b/src/python-systemd/daemon.py @@ -0,0 +1,55 @@ +from ._daemon import (__version__, + booted, + notify, + _listen_fds, + _is_fifo, + _is_socket, + _is_socket_inet, + _is_socket_unix, + _is_mq, + LISTEN_FDS_START) +from socket import AF_UNSPEC as _AF_UNSPEC + +def _convert_fileobj(fileobj): + try: + return fileobj.fileno() + except AttributeError: + return fileobj + +def is_fifo(fileobj, path=None): + fd = _convert_fileobj(fileobj) + return _is_fifo(fd, path) + +def is_socket(fileobj, family=_AF_UNSPEC, type=0, listening=-1): + fd = _convert_fileobj(fileobj) + return _is_socket(fd, family, type, listening) + +def is_socket_inet(fileobj, family=_AF_UNSPEC, type=0, listening=-1, port=0): + fd = _convert_fileobj(fileobj) + return _is_socket_inet(fd, family, type, listening) + +def is_socket_unix(fileobj, type=0, listening=-1, path=None): + fd = _convert_fileobj(fileobj) + return _is_socket_unix(fd, type, listening, path) + +def is_mq(fileobj, path=None): + fd = _convert_fileobj(fileobj) + return _is_mq(fd, path) + +def listen_fds(unset_environment=True): + """Return a list of socket activated descriptors + + Example:: + + (in primary window) + $ systemd-activate -l 2000 python3 -c \\ + 'from systemd.daemon import listen_fds; print(listen_fds())' + (in another window) + $ telnet localhost 2000 + (in primary window) + ... + Execing python3 (...) + [3] + """ + num = _listen_fds(unset_environment) + return list(range(LISTEN_FDS_START, LISTEN_FDS_START + num)) diff --git a/src/python-systemd/docs/.gitignore b/src/python-systemd/docs/.gitignore new file mode 100644 index 0000000..b06a965 --- /dev/null +++ b/src/python-systemd/docs/.gitignore @@ -0,0 +1 @@ +!layout.html diff --git a/src/python-systemd/docs/conf.py b/src/python-systemd/docs/conf.py new file mode 100644 index 0000000..1919170 --- /dev/null +++ b/src/python-systemd/docs/conf.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +# +# python-systemd documentation build configuration file, created by +# sphinx-quickstart on Sat Feb 9 13:49:42 2013. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['.'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'python-systemd' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['.'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'python-systemddoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'python-systemd.tex', u'python-systemd Documentation', + None, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'python-systemd', u'python-systemd Documentation', + [], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'python-systemd', u'python-systemd Documentation', + u'David Strauss, Zbigniew Jędrzejewski-Szmek, Marti Raudsepp, Steven Hiscocks', 'python-systemd', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'python-systemd' +epub_author = u'David Strauss, Zbigniew Jędrzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' +epub_publisher = u'David Strauss, Zbigniew Jędrzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' +epub_copyright = u'2013, David Strauss, Zbigniew Jędrzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/src/python-systemd/docs/daemon.rst b/src/python-systemd/docs/daemon.rst new file mode 100644 index 0000000..0ad11ed --- /dev/null +++ b/src/python-systemd/docs/daemon.rst @@ -0,0 +1,18 @@ +`systemd.daemon` module +======================= + +.. automodule:: systemd.daemon + :members: + :undoc-members: + :inherited-members: + + .. autoattribute:: systemd.daemon.LISTEN_FDS_START + + .. autofunction:: _listen_fds + .. autofunction:: _is_fifo + .. autofunction:: _is_socket + .. autofunction:: _is_socket_unix + .. autofunction:: _is_socket_inet + .. autofunction:: _is_mq + .. autofunction:: notify + .. autofunction:: booted diff --git a/src/python-systemd/docs/default.css b/src/python-systemd/docs/default.css new file mode 100644 index 0000000..7c097d6 --- /dev/null +++ b/src/python-systemd/docs/default.css @@ -0,0 +1,196 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { + background-color: #dddddd; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; +} + +div.sphinxsidebar input { + border: 1px solid #000000; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning tt { + background: #efc2c2; +} + +.note tt { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} diff --git a/src/python-systemd/docs/id128.rst b/src/python-systemd/docs/id128.rst new file mode 100644 index 0000000..89c37f3 --- /dev/null +++ b/src/python-systemd/docs/id128.rst @@ -0,0 +1,40 @@ +`systemd.id128` module +====================== + +.. automodule:: systemd.id128 + :members: + :undoc-members: + :inherited-members: + + .. autoattribute:: systemd.id128.SD_MESSAGE_COREDUMP + .. autoattribute:: systemd.id128.SD_MESSAGE_FORWARD_SYSLOG_MISSED + .. autoattribute:: systemd.id128.SD_MESSAGE_HIBERNATE_KEY + .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_DROPPED + .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_MISSED + .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_START + .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_STOP + .. autoattribute:: systemd.id128.SD_MESSAGE_LID_CLOSED + .. autoattribute:: systemd.id128.SD_MESSAGE_LID_OPENED + .. autoattribute:: systemd.id128.SD_MESSAGE_OVERMOUNTING + .. autoattribute:: systemd.id128.SD_MESSAGE_POWER_KEY + .. autoattribute:: systemd.id128.SD_MESSAGE_SEAT_START + .. autoattribute:: systemd.id128.SD_MESSAGE_SEAT_STOP + .. autoattribute:: systemd.id128.SD_MESSAGE_SESSION_START + .. autoattribute:: systemd.id128.SD_MESSAGE_SESSION_STOP + .. autoattribute:: systemd.id128.SD_MESSAGE_SHUTDOWN + .. autoattribute:: systemd.id128.SD_MESSAGE_SLEEP_START + .. autoattribute:: systemd.id128.SD_MESSAGE_SLEEP_STOP + .. autoattribute:: systemd.id128.SD_MESSAGE_SPAWN_FAILED + .. autoattribute:: systemd.id128.SD_MESSAGE_STARTUP_FINISHED + .. autoattribute:: systemd.id128.SD_MESSAGE_SUSPEND_KEY + .. autoattribute:: systemd.id128.SD_MESSAGE_TIMEZONE_CHANGE + .. autoattribute:: systemd.id128.SD_MESSAGE_TIME_CHANGE + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_FAILED + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_RELOADED + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_RELOADING + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STARTED + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STARTING + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STOPPED + .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STOPPING + .. autoattribute:: systemd.id128.SD_MESSAGE_CONFIG_ERROR + .. autoattribute:: systemd.id128.SD_MESSAGE_BOOTCHART diff --git a/src/python-systemd/docs/index.rst b/src/python-systemd/docs/index.rst new file mode 100644 index 0000000..e78d966 --- /dev/null +++ b/src/python-systemd/docs/index.rst @@ -0,0 +1,24 @@ +.. python-systemd documentation master file, created by + sphinx-quickstart on Sat Feb 9 13:49:42 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to python-systemd's documentation! +========================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + journal + id128 + daemon + login + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/src/python-systemd/docs/journal.rst b/src/python-systemd/docs/journal.rst new file mode 100644 index 0000000..ea74cf8 --- /dev/null +++ b/src/python-systemd/docs/journal.rst @@ -0,0 +1,64 @@ +`systemd.journal` module +======================== + +.. automodule:: systemd.journal + :members: send, sendv, stream, stream_fd + :undoc-members: + +`JournalHandler` class +---------------------- + +.. autoclass:: JournalHandler + +Accessing the Journal +--------------------- + +.. autoclass:: _Reader + :undoc-members: + :inherited-members: + +.. autoclass:: Reader + :undoc-members: + :inherited-members: + + .. automethod:: __init__ + +.. autofunction:: _get_catalog +.. autofunction:: get_catalog + +.. autoclass:: Monotonic + +.. autoattribute:: systemd.journal.DEFAULT_CONVERTERS + +Example: polling for journal events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows that journal events can be waited for (using +e.g. `poll`). This makes it easy to integrate Reader in an external +event loop: + + >>> import select + >>> from systemd import journal + >>> j = journal.Reader() + >>> j.seek_tail() + >>> p = select.poll() + >>> p.register(j, j.get_events()) + >>> p.poll() + [(3, 1)] + >>> j.get_next() + + +Journal access types +~~~~~~~~~~~~~~~~~~~~ + +.. autoattribute:: systemd.journal.LOCAL_ONLY +.. autoattribute:: systemd.journal.RUNTIME_ONLY +.. autoattribute:: systemd.journal.SYSTEM +.. autoattribute:: systemd.journal.CURRENT_USER + +Journal event types +~~~~~~~~~~~~~~~~~~~ + +.. autoattribute:: systemd.journal.NOP +.. autoattribute:: systemd.journal.APPEND +.. autoattribute:: systemd.journal.INVALIDATE diff --git a/src/python-systemd/docs/layout.html b/src/python-systemd/docs/layout.html new file mode 100644 index 0000000..be5ff98 --- /dev/null +++ b/src/python-systemd/docs/layout.html @@ -0,0 +1,17 @@ +{% extends "!layout.html" %} + +{% block relbar1 %} + Index · + Directives · + Python · + libudev · + gudev + systemd {{release}} +
+{% endblock %} + +{# remove the lower relbar #} +{% block relbar2 %} {% endblock %} + +{# remove the footer #} +{% block footer %} {% endblock %} diff --git a/src/python-systemd/docs/login.rst b/src/python-systemd/docs/login.rst new file mode 100644 index 0000000..6b4de64 --- /dev/null +++ b/src/python-systemd/docs/login.rst @@ -0,0 +1,28 @@ +`systemd.login` module +======================= + +.. automodule:: systemd.login + :members: + +.. autoclass:: Monitor + :undoc-members: + :inherited-members: + +Example: polling for events +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows that session/uid/seat/machine events can be waited +for (using e.g. `poll`). This makes it easy to integrate Monitor in an +external event loop: + + >>> import select + >>> from systemd import login + >>> m = login.Monitor("machine") + >>> p = select.poll() + >>> p.register(m, m.get_events()) + >>> login.machine_names() + [] + >>> p.poll() + [(3, 1)] + >>> login.machine_names() + ['fedora-19.nspawn'] diff --git a/src/python-systemd/id128.c b/src/python-systemd/id128.c new file mode 100644 index 0000000..6dadf7b --- /dev/null +++ b/src/python-systemd/id128.c @@ -0,0 +1,163 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include + +#include "pyutil.h" +#include "log.h" +#include "util.h" +#include "macro.h" + +PyDoc_STRVAR(module__doc__, + "Python interface to the libsystemd-id128 library.\n\n" + "Provides SD_MESSAGE_* constants and functions to query and generate\n" + "128-bit unique identifiers." +); + +PyDoc_STRVAR(randomize__doc__, + "randomize() -> UUID\n\n" + "Return a new random 128-bit unique identifier.\n" + "Wraps sd_id128_randomize(3)." +); + +PyDoc_STRVAR(get_machine__doc__, + "get_machine() -> UUID\n\n" + "Return a 128-bit unique identifier for this machine.\n" + "Wraps sd_id128_get_machine(3)." +); + +PyDoc_STRVAR(get_boot__doc__, + "get_boot() -> UUID\n\n" + "Return a 128-bit unique identifier for this boot.\n" + "Wraps sd_id128_get_boot(3)." +); + +static PyObject* make_uuid(sd_id128_t id) { + _cleanup_Py_DECREF_ PyObject + *uuid = NULL, *UUID = NULL, *bytes = NULL, + *args = NULL, *kwargs = NULL; + + uuid = PyImport_ImportModule("uuid"); + if (!uuid) + return NULL; + + UUID = PyObject_GetAttrString(uuid, "UUID"); + bytes = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes)); + args = Py_BuildValue("()"); + kwargs = PyDict_New(); + if (!UUID || !bytes || !args || !kwargs) + return NULL; + + if (PyDict_SetItemString(kwargs, "bytes", bytes) < 0) + return NULL; + + return PyObject_Call(UUID, args, kwargs); +} + +#define helper(name) \ + static PyObject *name(PyObject *self, PyObject *args) { \ + sd_id128_t id; \ + int r; \ + \ + assert(args == NULL); \ + \ + r = sd_id128_##name(&id); \ + if (r < 0) { \ + errno = -r; \ + return PyErr_SetFromErrno(PyExc_IOError); \ + } \ + \ + return make_uuid(id); \ + } + +helper(randomize) +helper(get_machine) +helper(get_boot) + +static PyMethodDef methods[] = { + { "randomize", randomize, METH_NOARGS, randomize__doc__}, + { "get_machine", get_machine, METH_NOARGS, get_machine__doc__}, + { "get_boot", get_boot, METH_NOARGS, get_boot__doc__}, + { NULL, NULL, 0, NULL } /* Sentinel */ +}; + +static int add_id(PyObject *module, const char* name, sd_id128_t id) { + PyObject *obj; + + obj = make_uuid(id); + if (!obj) + return -1; + + return PyModule_AddObject(module, name, obj); +} + +#if PY_MAJOR_VERSION < 3 + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC initid128(void) { + PyObject *m; + + m = Py_InitModule3("id128", methods, module__doc__); + if (m == NULL) + return; + + /* a series of lines like 'add_id() ;' follow */ +#define JOINER ; +#include "id128-constants.h" +#undef JOINER + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); +} +REENABLE_WARNING; + +#else + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "id128", /* name of module */ + module__doc__, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module */ + methods +}; + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC PyInit_id128(void) { + PyObject *m; + + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + if ( /* a series of lines like 'add_id() ||' follow */ +#define JOINER || +#include "id128-constants.h" +#undef JOINER + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { + Py_DECREF(m); + return NULL; + } + + return m; +} +REENABLE_WARNING; + +#endif diff --git a/src/python-systemd/journal.py b/src/python-systemd/journal.py new file mode 100644 index 0000000..9c7e004 --- /dev/null +++ b/src/python-systemd/journal.py @@ -0,0 +1,548 @@ +# -*- Mode: python; coding:utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012 David Strauss +# Copyright 2012 Zbigniew Jędrzejewski-Szmek +# Copyright 2012 Marti Raudsepp +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +from __future__ import division + +import sys as _sys +import datetime as _datetime +import uuid as _uuid +import traceback as _traceback +import os as _os +import logging as _logging +if _sys.version_info >= (3,3): + from collections import ChainMap as _ChainMap +from syslog import (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, + LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG) +from ._journal import __version__, sendv, stream_fd +from ._reader import (_Reader, NOP, APPEND, INVALIDATE, + LOCAL_ONLY, RUNTIME_ONLY, + SYSTEM, SYSTEM_ONLY, CURRENT_USER, + _get_catalog) +from . import id128 as _id128 + +if _sys.version_info >= (3,): + from ._reader import Monotonic +else: + Monotonic = tuple + +def _convert_monotonic(m): + return Monotonic((_datetime.timedelta(microseconds=m[0]), + _uuid.UUID(bytes=m[1]))) + +def _convert_source_monotonic(s): + return _datetime.timedelta(microseconds=int(s)) + +def _convert_realtime(t): + return _datetime.datetime.fromtimestamp(t / 1000000) + +def _convert_timestamp(s): + return _datetime.datetime.fromtimestamp(int(s) / 1000000) + +def _convert_trivial(x): + return x + +if _sys.version_info >= (3,): + def _convert_uuid(s): + return _uuid.UUID(s.decode()) +else: + _convert_uuid = _uuid.UUID + +DEFAULT_CONVERTERS = { + 'MESSAGE_ID': _convert_uuid, + '_MACHINE_ID': _convert_uuid, + '_BOOT_ID': _convert_uuid, + 'PRIORITY': int, + 'LEADER': int, + 'SESSION_ID': int, + 'USERSPACE_USEC': int, + 'INITRD_USEC': int, + 'KERNEL_USEC': int, + '_UID': int, + '_GID': int, + '_PID': int, + 'SYSLOG_FACILITY': int, + 'SYSLOG_PID': int, + '_AUDIT_SESSION': int, + '_AUDIT_LOGINUID': int, + '_SYSTEMD_SESSION': int, + '_SYSTEMD_OWNER_UID': int, + 'CODE_LINE': int, + 'ERRNO': int, + 'EXIT_STATUS': int, + '_SOURCE_REALTIME_TIMESTAMP': _convert_timestamp, + '__REALTIME_TIMESTAMP': _convert_realtime, + '_SOURCE_MONOTONIC_TIMESTAMP': _convert_source_monotonic, + '__MONOTONIC_TIMESTAMP': _convert_monotonic, + '__CURSOR': _convert_trivial, + 'COREDUMP': bytes, + 'COREDUMP_PID': int, + 'COREDUMP_UID': int, + 'COREDUMP_GID': int, + 'COREDUMP_SESSION': int, + 'COREDUMP_SIGNAL': int, + 'COREDUMP_TIMESTAMP': _convert_timestamp, +} + +_IDENT_LETTER = set('ABCDEFGHIJKLMNOPQRTSUVWXYZ_') + +def _valid_field_name(s): + return not (set(s) - _IDENT_LETTER) + +class Reader(_Reader): + """Reader allows the access and filtering of systemd journal + entries. Note that in order to access the system journal, a + non-root user must be in the `systemd-journal` group. + + Example usage to print out all informational or higher level + messages for systemd-udevd for this boot: + + >>> j = journal.Reader() + >>> j.this_boot() + >>> j.log_level(journal.LOG_INFO) + >>> j.add_match(_SYSTEMD_UNIT="systemd-udevd.service") + >>> for entry in j: + ... print(entry['MESSAGE']) + + See systemd.journal-fields(7) for more info on typical fields + found in the journal. + """ + def __init__(self, flags=0, path=None, files=None, converters=None): + """Create an instance of Reader, which allows filtering and + return of journal entries. + + Argument `flags` sets open flags of the journal, which can be one + of, or ORed combination of constants: LOCAL_ONLY (default) opens + journal on local machine only; RUNTIME_ONLY opens only + volatile journal files; and SYSTEM_ONLY opens only + journal files of system services and the kernel. + + Argument `path` is the directory of journal files. Note that + `flags` and `path` are exclusive. + + Argument `converters` is a dictionary which updates the + DEFAULT_CONVERTERS to convert journal field values. Field + names are used as keys into this dictionary. The values must + be single argument functions, which take a `bytes` object and + return a converted value. When there's no entry for a field + name, then the default UTF-8 decoding will be attempted. If + the conversion fails with a ValueError, unconverted bytes + object will be returned. (Note that ValueEror is a superclass + of UnicodeDecodeError). + + Reader implements the context manager protocol: the journal + will be closed when exiting the block. + """ + super(Reader, self).__init__(flags, path, files) + if _sys.version_info >= (3,3): + self.converters = _ChainMap() + if converters is not None: + self.converters.maps.append(converters) + self.converters.maps.append(DEFAULT_CONVERTERS) + else: + self.converters = DEFAULT_CONVERTERS.copy() + if converters is not None: + self.converters.update(converters) + + def _convert_field(self, key, value): + """Convert value using self.converters[key] + + If `key` is not present in self.converters, a standard unicode + decoding will be attempted. If the conversion (either + key-specific or the default one) fails with a ValueError, the + original bytes object will be returned. + """ + convert = self.converters.get(key, bytes.decode) + try: + return convert(value) + except ValueError: + # Leave in default bytes + return value + + def _convert_entry(self, entry): + """Convert entire journal entry utilising _covert_field""" + result = {} + for key, value in entry.items(): + if isinstance(value, list): + result[key] = [self._convert_field(key, val) for val in value] + else: + result[key] = self._convert_field(key, value) + return result + + def __iter__(self): + """Part of iterator protocol. + Returns self. + """ + return self + + def __next__(self): + """Part of iterator protocol. + Returns self.get_next() or raises StopIteration. + """ + ans = self.get_next() + if ans: + return ans + else: + raise StopIteration() + + if _sys.version_info < (3,): + next = __next__ + + def add_match(self, *args, **kwargs): + """Add one or more matches to the filter journal log entries. + All matches of different field are combined in a logical AND, + and matches of the same field are automatically combined in a + logical OR. + Matches can be passed as strings of form "FIELD=value", or + keyword arguments FIELD="value". + """ + args = list(args) + args.extend(_make_line(key, val) for key, val in kwargs.items()) + for arg in args: + super(Reader, self).add_match(arg) + + def get_next(self, skip=1): + """Return the next log entry as a mapping type, currently + a standard dictionary of fields. + + Optional skip value will return the `skip`\-th log entry. + + Entries will be processed with converters specified during + Reader creation. + """ + if super(Reader, self)._next(skip): + entry = super(Reader, self)._get_all() + if entry: + entry['__REALTIME_TIMESTAMP'] = self._get_realtime() + entry['__MONOTONIC_TIMESTAMP'] = self._get_monotonic() + entry['__CURSOR'] = self._get_cursor() + return self._convert_entry(entry) + return dict() + + def get_previous(self, skip=1): + """Return the previous log entry as a mapping type, + currently a standard dictionary of fields. + + Optional skip value will return the -`skip`\-th log entry. + + Entries will be processed with converters specified during + Reader creation. + + Equivalent to get_next(-skip). + """ + return self.get_next(-skip) + + def query_unique(self, field): + """Return unique values appearing in the journal for given `field`. + + Note this does not respect any journal matches. + + Entries will be processed with converters specified during + Reader creation. + """ + return set(self._convert_field(field, value) + for value in super(Reader, self).query_unique(field)) + + def wait(self, timeout=None): + """Wait for a change in the journal. `timeout` is the maximum + time in seconds to wait, or None, to wait forever. + + Returns one of NOP (no change), APPEND (new entries have been + added to the end of the journal), or INVALIDATE (journal files + have been added or removed). + """ + us = -1 if timeout is None else int(timeout * 1000000) + return super(Reader, self).wait(us) + + def seek_realtime(self, realtime): + """Seek to a matching journal entry nearest to `realtime` time. + + Argument `realtime` must be either an integer unix timestamp + or datetime.datetime instance. + """ + if isinstance(realtime, _datetime.datetime): + realtime = float(realtime.strftime("%s.%f")) * 1000000 + return super(Reader, self).seek_realtime(int(realtime)) + + def seek_monotonic(self, monotonic, bootid=None): + """Seek to a matching journal entry nearest to `monotonic` time. + + Argument `monotonic` is a timestamp from boot in either + seconds or a datetime.timedelta instance. Argument `bootid` + is a string or UUID representing which boot the monotonic time + is reference to. Defaults to current bootid. + """ + if isinstance(monotonic, _datetime.timedelta): + monotonic = monotonic.totalseconds() + monotonic = int(monotonic * 1000000) + if isinstance(bootid, _uuid.UUID): + bootid = bootid.get_hex() + return super(Reader, self).seek_monotonic(monotonic, bootid) + + def log_level(self, level): + """Set maximum log `level` by setting matches for PRIORITY. + """ + if 0 <= level <= 7: + for i in range(level+1): + self.add_match(PRIORITY="%d" % i) + else: + raise ValueError("Log level must be 0 <= level <= 7") + + def messageid_match(self, messageid): + """Add match for log entries with specified `messageid`. + + `messageid` can be string of hexadicimal digits or a UUID + instance. Standard message IDs can be found in systemd.id128. + + Equivalent to add_match(MESSAGE_ID=`messageid`). + """ + if isinstance(messageid, _uuid.UUID): + messageid = messageid.get_hex() + self.add_match(MESSAGE_ID=messageid) + + def this_boot(self, bootid=None): + """Add match for _BOOT_ID equal to current boot ID or the specified boot ID. + + If specified, bootid should be either a UUID or a 32 digit hex number. + + Equivalent to add_match(_BOOT_ID='bootid'). + """ + if bootid is None: + bootid = _id128.get_boot().hex + else: + bootid = getattr(bootid, 'hex', bootid) + self.add_match(_BOOT_ID=bootid) + + def this_machine(self, machineid=None): + """Add match for _MACHINE_ID equal to the ID of this machine. + + If specified, machineid should be either a UUID or a 32 digit hex number. + + Equivalent to add_match(_MACHINE_ID='machineid'). + """ + if machineid is None: + machineid = _id128.get_machine().hex + else: + machineid = getattr(machineid, 'hex', machineid) + self.add_match(_MACHINE_ID=machineid) + + +def get_catalog(mid): + if isinstance(mid, _uuid.UUID): + mid = mid.get_hex() + return _get_catalog(mid) + +def _make_line(field, value): + if isinstance(value, bytes): + return field.encode('utf-8') + b'=' + value + elif isinstance(value, int): + return field + '=' + str(value) + else: + return field + '=' + value + +def send(MESSAGE, MESSAGE_ID=None, + CODE_FILE=None, CODE_LINE=None, CODE_FUNC=None, + **kwargs): + r"""Send a message to the journal. + + >>> journal.send('Hello world') + >>> journal.send('Hello, again, world', FIELD2='Greetings!') + >>> journal.send('Binary message', BINARY=b'\xde\xad\xbe\xef') + + Value of the MESSAGE argument will be used for the MESSAGE= + field. MESSAGE must be a string and will be sent as UTF-8 to + the journal. + + MESSAGE_ID can be given to uniquely identify the type of + message. It must be a string or a uuid.UUID object. + + CODE_LINE, CODE_FILE, and CODE_FUNC can be specified to + identify the caller. Unless at least on of the three is given, + values are extracted from the stack frame of the caller of + send(). CODE_FILE and CODE_FUNC must be strings, CODE_LINE + must be an integer. + + Additional fields for the journal entry can only be specified + as keyword arguments. The payload can be either a string or + bytes. A string will be sent as UTF-8, and bytes will be sent + as-is to the journal. + + Other useful fields include PRIORITY, SYSLOG_FACILITY, + SYSLOG_IDENTIFIER, SYSLOG_PID. + """ + + args = ['MESSAGE=' + MESSAGE] + + if MESSAGE_ID is not None: + id = getattr(MESSAGE_ID, 'hex', MESSAGE_ID) + args.append('MESSAGE_ID=' + id) + + if CODE_LINE == CODE_FILE == CODE_FUNC == None: + CODE_FILE, CODE_LINE, CODE_FUNC = \ + _traceback.extract_stack(limit=2)[0][:3] + if CODE_FILE is not None: + args.append('CODE_FILE=' + CODE_FILE) + if CODE_LINE is not None: + args.append('CODE_LINE={:d}'.format(CODE_LINE)) + if CODE_FUNC is not None: + args.append('CODE_FUNC=' + CODE_FUNC) + + args.extend(_make_line(key, val) for key, val in kwargs.items()) + return sendv(*args) + +def stream(identifier, priority=LOG_DEBUG, level_prefix=False): + r"""Return a file object wrapping a stream to journal. + + Log messages written to this file as simple newline sepearted + text strings are written to the journal. + + The file will be line buffered, so messages are actually sent + after a newline character is written. + + >>> stream = journal.stream('myapp') + >>> stream + ', mode 'w' at 0x...> + >>> stream.write('message...\n') + + will produce the following message in the journal:: + + PRIORITY=7 + SYSLOG_IDENTIFIER=myapp + MESSAGE=message... + + Using the interface with print might be more convinient: + + >>> from __future__ import print_function + >>> print('message...', file=stream) + + priority is the syslog priority, one of `LOG_EMERG`, + `LOG_ALERT`, `LOG_CRIT`, `LOG_ERR`, `LOG_WARNING`, + `LOG_NOTICE`, `LOG_INFO`, `LOG_DEBUG`. + + level_prefix is a boolean. If true, kernel-style log priority + level prefixes (such as '<1>') are interpreted. See + sd-daemon(3) for more information. + """ + + fd = stream_fd(identifier, priority, level_prefix) + return _os.fdopen(fd, 'w', 1) + +class JournalHandler(_logging.Handler): + """Journal handler class for the Python logging framework. + + Please see the Python logging module documentation for an + overview: http://docs.python.org/library/logging.html. + + To create a custom logger whose messages go only to journal: + + >>> log = logging.getLogger('custom_logger_name') + >>> log.propagate = False + >>> log.addHandler(journal.JournalHandler()) + >>> log.warn("Some message: %s", detail) + + Note that by default, message levels `INFO` and `DEBUG` are + ignored by the logging framework. To enable those log levels: + + >>> log.setLevel(logging.DEBUG) + + To redirect all logging messages to journal regardless of where + they come from, attach it to the root logger: + + >>> logging.root.addHandler(journal.JournalHandler()) + + For more complex configurations when using `dictConfig` or + `fileConfig`, specify `systemd.journal.JournalHandler` as the + handler class. Only standard handler configuration options + are supported: `level`, `formatter`, `filters`. + + To attach journal MESSAGE_ID, an extra field is supported: + + >>> import uuid + >>> mid = uuid.UUID('0123456789ABCDEF0123456789ABCDEF') + >>> log.warn("Message with ID", extra={'MESSAGE_ID': mid}) + + Fields to be attached to all messages sent through this + handler can be specified as keyword arguments. This probably + makes sense only for SYSLOG_IDENTIFIER and similar fields + which are constant for the whole program: + + >>> journal.JournalHandler(SYSLOG_IDENTIFIER='my-cool-app') + + The following journal fields will be sent: + `MESSAGE`, `PRIORITY`, `THREAD_NAME`, `CODE_FILE`, `CODE_LINE`, + `CODE_FUNC`, `LOGGER` (name as supplied to getLogger call), + `MESSAGE_ID` (optional, see above), `SYSLOG_IDENTIFIER` (defaults + to sys.argv[0]). + """ + + def __init__(self, level=_logging.NOTSET, **kwargs): + super(JournalHandler, self).__init__(level) + + for name in kwargs: + if not _valid_field_name(name): + raise ValueError('Invalid field name: ' + name) + if 'SYSLOG_IDENTIFIER' not in kwargs: + kwargs['SYSLOG_IDENTIFIER'] = _sys.argv[0] + self._extra = kwargs + + def emit(self, record): + """Write record as journal event. + + MESSAGE is taken from the message provided by the + user, and PRIORITY, LOGGER, THREAD_NAME, + CODE_{FILE,LINE,FUNC} fields are appended + automatically. In addition, record.MESSAGE_ID will be + used if present. + """ + try: + msg = self.format(record) + pri = self.mapPriority(record.levelno) + mid = getattr(record, 'MESSAGE_ID', None) + send(msg, + MESSAGE_ID=mid, + PRIORITY=format(pri), + LOGGER=record.name, + THREAD_NAME=record.threadName, + CODE_FILE=record.pathname, + CODE_LINE=record.lineno, + CODE_FUNC=record.funcName, + **self._extra) + except Exception: + self.handleError(record) + + @staticmethod + def mapPriority(levelno): + """Map logging levels to journald priorities. + + Since Python log level numbers are "sparse", we have + to map numbers in between the standard levels too. + """ + if levelno <= _logging.DEBUG: + return LOG_DEBUG + elif levelno <= _logging.INFO: + return LOG_INFO + elif levelno <= _logging.WARNING: + return LOG_WARNING + elif levelno <= _logging.ERROR: + return LOG_ERR + elif levelno <= _logging.CRITICAL: + return LOG_CRIT + else: + return LOG_ALERT diff --git a/src/python-systemd/login.c b/src/python-systemd/login.c new file mode 100644 index 0000000..e844f5f --- /dev/null +++ b/src/python-systemd/login.c @@ -0,0 +1,376 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define PY_SSIZE_T_CLEAN +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#include +#pragma GCC diagnostic pop + +#include "systemd/sd-login.h" +#include "pyutil.h" +#include "util.h" +#include "strv.h" + +PyDoc_STRVAR(module__doc__, + "Python interface to the libsystemd-login library." +); + +#define helper(name) \ +static PyObject* name(PyObject *self, PyObject *args) { \ + _cleanup_strv_free_ char **list = NULL; \ + int r; \ + PyObject *ans; \ + \ + assert(args == NULL); \ + \ + r = sd_get_##name(&list); \ + if (r < 0) { \ + errno = -r; \ + return PyErr_SetFromErrno(PyExc_IOError); \ + } \ + \ + ans = PyList_New(r); \ + if (!ans) \ + return NULL; \ + \ + for (r--; r >= 0; r--) { \ + PyObject *s = unicode_FromString(list[r]); \ + if (!s) { \ + Py_DECREF(ans); \ + return NULL; \ + } \ + \ + PyList_SetItem(ans, r, s); \ + } \ + \ + return ans; \ +} + +helper(seats) +helper(sessions) +helper(machine_names) +#undef helper + +static PyObject* uids(PyObject *self, PyObject *args) { + _cleanup_free_ uid_t *list = NULL; + int r; + PyObject *ans; + + assert(args == NULL); + + r = sd_get_uids(&list); + if (r < 0) { + errno = -r; + return PyErr_SetFromErrno(PyExc_IOError); + } + + ans = PyList_New(r); + if (!ans) + return NULL; + + for (r--; r >= 0; r--) { + PyObject *s = long_FromLong(list[r]); + if (!s) { + Py_DECREF(ans); + return NULL; + } + + PyList_SetItem(ans, r, s); + } + + return ans; +} + +PyDoc_STRVAR(seats__doc__, + "seats() -> list\n\n" + "Returns a list of currently available local seats.\n" + "Wraps sd_get_seats(3)." +); + +PyDoc_STRVAR(sessions__doc__, + "sessions() -> list\n\n" + "Returns a list of current login sessions.\n" + "Wraps sd_get_sessions(3)." +); + +PyDoc_STRVAR(machine_names__doc__, + "machine_names() -> list\n\n" + "Returns a list of currently running virtual machines\n" + "and containers on the system.\n" + "Wraps sd_get_machine_names(3)." +); + +PyDoc_STRVAR(uids__doc__, + "uids() -> list\n\n" + "Returns a list of uids of users who currently have login sessions.\n" + "Wraps sd_get_uids(3)." +); + +static PyMethodDef methods[] = { + { "seats", seats, METH_NOARGS, seats__doc__}, + { "sessions", sessions, METH_NOARGS, sessions__doc__}, + { "machine_names", machine_names, METH_NOARGS, machine_names__doc__}, + { "uids", uids, METH_NOARGS, uids__doc__}, + {} /* Sentinel */ +}; + + +typedef struct { + PyObject_HEAD + sd_login_monitor *monitor; +} Monitor; +static PyTypeObject MonitorType; + +static void Monitor_dealloc(Monitor* self) { + sd_login_monitor_unref(self->monitor); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(Monitor__doc__, + "Monitor([category]) -> ...\n\n" + "Monitor may be used to monitor login sessions, users, seats,\n" + "and virtual machines/containers. Monitor provides a file\n" + "descriptor which can be integrated in an external event loop.\n" + "See man:sd_login_monitor_new(3) for the details about what\n" + "can be monitored."); +static int Monitor_init(Monitor *self, PyObject *args, PyObject *keywds) { + const char *category = NULL; + int r; + + static const char* const kwlist[] = {"category", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|z:__init__", (char**) kwlist, + &category)) + return -1; + + Py_BEGIN_ALLOW_THREADS + r = sd_login_monitor_new(category, &self->monitor); + Py_END_ALLOW_THREADS + + return set_error(r, NULL, "Invalid category"); +} + + +PyDoc_STRVAR(Monitor_fileno__doc__, + "fileno() -> int\n\n" + "Get a file descriptor to poll for events.\n" + "This method wraps sd_login_monitor_get_fd(3)."); +static PyObject* Monitor_fileno(Monitor *self, PyObject *args) { + int fd = sd_login_monitor_get_fd(self->monitor); + set_error(fd, NULL, NULL); + if (fd < 0) + return NULL; + return long_FromLong(fd); +} + + +PyDoc_STRVAR(Monitor_get_events__doc__, + "get_events() -> int\n\n" + "Returns a mask of poll() events to wait for on the file\n" + "descriptor returned by .fileno().\n\n" + "See man:sd_login_monitor_get_events(3) for further discussion."); +static PyObject* Monitor_get_events(Monitor *self, PyObject *args) { + int r = sd_login_monitor_get_events(self->monitor); + set_error(r, NULL, NULL); + if (r < 0) + return NULL; + return long_FromLong(r); +} + + +PyDoc_STRVAR(Monitor_get_timeout__doc__, + "get_timeout() -> int or None\n\n" + "Returns a timeout value for usage in poll(), the time since the\n" + "epoch of clock_gettime(2) in microseconds, or None if no timeout\n" + "is necessary.\n\n" + "The return value must be converted to a relative timeout in\n" + "milliseconds if it is to be used as an argument for poll().\n" + "See man:sd_login_monitor_get_timeout(3) for further discussion."); +static PyObject* Monitor_get_timeout(Monitor *self, PyObject *args) { + int r; + uint64_t t; + + r = sd_login_monitor_get_timeout(self->monitor, &t); + set_error(r, NULL, NULL); + if (r < 0) + return NULL; + + if (t == (uint64_t) -1) + Py_RETURN_NONE; + + assert_cc(sizeof(unsigned long long) == sizeof(t)); + return PyLong_FromUnsignedLongLong(t); +} + + +PyDoc_STRVAR(Monitor_get_timeout_ms__doc__, + "get_timeout_ms() -> int\n\n" + "Returns a timeout value suitable for usage in poll(), the value\n" + "returned by .get_timeout() converted to relative ms, or -1 if\n" + "no timeout is necessary."); +static PyObject* Monitor_get_timeout_ms(Monitor *self, PyObject *args) { + int r; + uint64_t t; + + r = sd_login_monitor_get_timeout(self->monitor, &t); + set_error(r, NULL, NULL); + if (r < 0) + return NULL; + + return absolute_timeout(t); +} + + +PyDoc_STRVAR(Monitor_close__doc__, + "close() -> None\n\n" + "Free resources allocated by this Monitor object.\n" + "This method invokes sd_login_monitor_unref().\n" + "See man:sd_login_monitor_unref(3)."); +static PyObject* Monitor_close(Monitor *self, PyObject *args) { + assert(self); + assert(!args); + + sd_login_monitor_unref(self->monitor); + self->monitor = NULL; + Py_RETURN_NONE; +} + + +PyDoc_STRVAR(Monitor_flush__doc__, + "flush() -> None\n\n" + "Reset the wakeup state of the monitor object.\n" + "This method invokes sd_login_monitor_flush().\n" + "See man:sd_login_monitor_flush(3)."); +static PyObject* Monitor_flush(Monitor *self, PyObject *args) { + assert(self); + assert(!args); + + Py_BEGIN_ALLOW_THREADS + sd_login_monitor_flush(self->monitor); + Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} + + +PyDoc_STRVAR(Monitor___enter____doc__, + "__enter__() -> self\n\n" + "Part of the context manager protocol.\n" + "Returns self.\n"); +static PyObject* Monitor___enter__(PyObject *self, PyObject *args) { + assert(self); + assert(!args); + + Py_INCREF(self); + return self; +} + + +PyDoc_STRVAR(Monitor___exit____doc__, + "__exit__(type, value, traceback) -> None\n\n" + "Part of the context manager protocol.\n" + "Closes the monitor..\n"); +static PyObject* Monitor___exit__(Monitor *self, PyObject *args) { + return Monitor_close(self, args); +} + + +static PyMethodDef Monitor_methods[] = { + {"fileno", (PyCFunction) Monitor_fileno, METH_NOARGS, Monitor_fileno__doc__}, + {"get_events", (PyCFunction) Monitor_get_events, METH_NOARGS, Monitor_get_events__doc__}, + {"get_timeout", (PyCFunction) Monitor_get_timeout, METH_NOARGS, Monitor_get_timeout__doc__}, + {"get_timeout_ms", (PyCFunction) Monitor_get_timeout_ms, METH_NOARGS, Monitor_get_timeout_ms__doc__}, + {"close", (PyCFunction) Monitor_close, METH_NOARGS, Monitor_close__doc__}, + {"flush", (PyCFunction) Monitor_flush, METH_NOARGS, Monitor_flush__doc__}, + {"__enter__", (PyCFunction) Monitor___enter__, METH_NOARGS, Monitor___enter____doc__}, + {"__exit__", (PyCFunction) Monitor___exit__, METH_VARARGS, Monitor___exit____doc__}, + {} /* Sentinel */ +}; + +static PyTypeObject MonitorType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "login.Monitor", + .tp_basicsize = sizeof(Monitor), + .tp_dealloc = (destructor) Monitor_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_doc = Monitor__doc__, + .tp_methods = Monitor_methods, + .tp_init = (initproc) Monitor_init, + .tp_new = PyType_GenericNew, +}; + +#if PY_MAJOR_VERSION < 3 + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC initlogin(void) { + PyObject *m; + + if (PyType_Ready(&MonitorType) < 0) + return; + + m = Py_InitModule3("login", methods, module__doc__); + if (m == NULL) + return; + + PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); + + Py_INCREF(&MonitorType); + PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType); +} +REENABLE_WARNING; + +#else + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + "login", /* name of module */ + module__doc__, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module */ + methods +}; + +DISABLE_WARNING_MISSING_PROTOTYPES; +PyMODINIT_FUNC PyInit_login(void) { + PyObject *m; + + if (PyType_Ready(&MonitorType) < 0) + return NULL; + + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { + Py_DECREF(m); + return NULL; + } + + Py_INCREF(&MonitorType); + if (PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType)) { + Py_DECREF(&MonitorType); + Py_DECREF(m); + return NULL; + } + + return m; +} +REENABLE_WARNING; + +#endif diff --git a/src/python-systemd/pyutil.c b/src/python-systemd/pyutil.c new file mode 100644 index 0000000..722c4f5 --- /dev/null +++ b/src/python-systemd/pyutil.c @@ -0,0 +1,80 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "pyutil.h" + +void cleanup_Py_DECREFp(PyObject **p) { + if (!*p) + return; + + Py_DECREF(*p); +} + +PyObject* absolute_timeout(uint64_t t) { + if (t == (uint64_t) -1) + return PyLong_FromLong(-1); + else { + struct timespec ts; + uint64_t n; + int msec; + + clock_gettime(CLOCK_MONOTONIC, &ts); + n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + msec = t > n ? (int) ((t - n + 999) / 1000) : 0; + + return PyLong_FromLong(msec); + } +} + +int set_error(int r, const char* path, const char* invalid_message) { + if (r >= 0) + return r; + if (r == -EINVAL && invalid_message) + PyErr_SetString(PyExc_ValueError, invalid_message); + else if (r == -ENOMEM) + PyErr_SetString(PyExc_MemoryError, "Not enough memory"); + else { + errno = -r; + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + } + return -1; +} + +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 +int Unicode_FSConverter(PyObject* obj, void *_result) { + PyObject **result = _result; + + assert(result); + + if (!obj) + /* cleanup: we don't return Py_CLEANUP_SUPPORTED, so + * we can assume that it was PyUnicode_FSConverter. */ + return PyUnicode_FSConverter(obj, result); + + if (obj == Py_None) { + *result = NULL; + return 1; + } + + return PyUnicode_FSConverter(obj, result); +} +#endif diff --git a/src/python-systemd/pyutil.h b/src/python-systemd/pyutil.h new file mode 100644 index 0000000..1477e7b --- /dev/null +++ b/src/python-systemd/pyutil.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#ifndef Py_TYPE +/* avoid duplication warnings from errors in Python 2.7 headers */ +# include +#endif + +void cleanup_Py_DECREFp(PyObject **p); +PyObject* absolute_timeout(uint64_t t); +int set_error(int r, const char* path, const char* invalid_message); + +#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 +int Unicode_FSConverter(PyObject* obj, void *_result); +#endif + +#define _cleanup_Py_DECREF_ __attribute__((cleanup(cleanup_Py_DECREFp))) + +#if PY_MAJOR_VERSION >=3 +# define unicode_FromStringAndSize PyUnicode_FromStringAndSize +# define unicode_FromString PyUnicode_FromString +# define long_FromLong PyLong_FromLong +# define long_FromSize_t PyLong_FromSize_t +# define long_Check PyLong_Check +# define long_AsLong PyLong_AsLong +#else +/* Python 3 type naming convention is used */ +# define unicode_FromStringAndSize PyString_FromStringAndSize +# define unicode_FromString PyString_FromString +# define long_FromLong PyInt_FromLong +# define long_FromSize_t PyInt_FromSize_t +# define long_Check PyInt_Check +# define long_AsLong PyInt_AsLong +#endif diff --git a/src/quotacheck.c b/src/quotacheck.c deleted file mode 100644 index 98b59a0..0000000 --- a/src/quotacheck.c +++ /dev/null @@ -1,120 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "util.h" -#include "virt.h" - -static bool arg_skip = false; -static bool arg_force = false; - -static int parse_proc_cmdline(void) { - char *line, *w, *state; - int r; - size_t l; - - if (detect_container(NULL) > 0) - return 0; - - if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) { - log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); - return 0; - } - - FOREACH_WORD_QUOTED(w, l, line, state) { - - if (strneq(w, "quotacheck.mode=auto", l)) - arg_force = arg_skip = false; - else if (strneq(w, "quotacheck.mode=force", l)) - arg_force = true; - else if (strneq(w, "quotacheck.mode=skip", l)) - arg_skip = true; - else if (startswith(w, "quotacheck.mode")) - log_warning("Invalid quotacheck.mode= parameter. Ignoring."); -#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) - else if (strneq(w, "forcequotacheck", l)) - arg_force = true; -#endif - } - - free(line); - return 0; -} - -static void test_files(void) { -#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) - /* This exists only on Fedora or Mandriva */ - if (access("/forcequotacheck", F_OK) >= 0) - arg_force = true; -#endif -} - -int main(int argc, char *argv[]) { - static const char * const cmdline[] = { - "/sbin/quotacheck", - "-anug", - NULL - }; - - int r = EXIT_FAILURE; - pid_t pid; - - if (argc > 1) { - log_error("This program takes no arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - parse_proc_cmdline(); - test_files(); - - if (!arg_force) { - if (arg_skip) - return 0; - - if (access("/run/systemd/quotacheck", F_OK) < 0) - return 0; - } - - if ((pid = fork()) < 0) { - log_error("fork(): %m"); - goto finish; - } else if (pid == 0) { - /* Child */ - execv(cmdline[0], (char**) cmdline); - _exit(1); /* Operational error */ - } - - r = wait_for_terminate_and_warn("quotacheck", pid) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; - -finish: - return r; -} diff --git a/src/quotacheck/Makefile b/src/quotacheck/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/quotacheck/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c new file mode 100644 index 0000000..8ff0f7f --- /dev/null +++ b/src/quotacheck/quotacheck.c @@ -0,0 +1,105 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "fileio.h" + +static bool arg_skip = false; +static bool arg_force = false; + +static int parse_proc_cmdline_word(const char *w) { + if (streq(w, "quotacheck.mode=auto")) + arg_force = arg_skip = false; + else if (streq(w, "quotacheck.mode=force")) + arg_force = true; + else if (streq(w, "quotacheck.mode=skip")) + arg_skip = true; + else if (startswith(w, "quotacheck")) + log_warning("Invalid quotacheck parameter. Ignoring."); +#ifdef HAVE_SYSV_COMPAT + else if (streq(w, "forcequotacheck")) { + log_error("Please use 'quotacheck.mode=force' rather than 'forcequotacheck' on the kernel command line."); + arg_force = true; + } +#endif + + return 0; +} + +static void test_files(void) { +#ifdef HAVE_SYSV_COMPAT + if (access("/forcequotacheck", F_OK) >= 0) { + log_error("Please pass 'quotacheck.mode=force' on the kernel command line rather than creating /forcequotacheck on the root file system."); + arg_force = true; + } +#endif +} + +int main(int argc, char *argv[]) { + + static const char * const cmdline[] = { + QUOTACHECK, + "-anug", + NULL + }; + + pid_t pid; + + if (argc > 1) { + log_error("This program takes no arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + parse_proc_cmdline(parse_proc_cmdline_word); + test_files(); + + if (!arg_force) { + if (arg_skip) + return EXIT_SUCCESS; + + if (access("/run/systemd/quotacheck", F_OK) < 0) + return EXIT_SUCCESS; + } + + pid = fork(); + if (pid < 0) { + log_error("fork(): %m"); + return EXIT_FAILURE; + } else if (pid == 0) { + /* Child */ + execv(cmdline[0], (char**) cmdline); + _exit(1); /* Operational error */ + } + + return wait_for_terminate_and_warn("quotacheck", pid) >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/random-seed.c b/src/random-seed.c deleted file mode 100644 index ee5cae3..0000000 --- a/src/random-seed.c +++ /dev/null @@ -1,143 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" - -#define POOL_SIZE_MIN 512 - -int main(int argc, char *argv[]) { - int seed_fd = -1, random_fd = -1; - int ret = EXIT_FAILURE; - void* buf; - size_t buf_size = 0; - ssize_t r; - FILE *f; - - if (argc != 2) { - log_error("This program requires one argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - /* Read pool size, if possible */ - if ((f = fopen("/proc/sys/kernel/random/poolsize", "re"))) { - fscanf(f, "%zu", &buf_size); - fclose(f); - } - - if (buf_size <= POOL_SIZE_MIN) - buf_size = POOL_SIZE_MIN; - - if (!(buf = malloc(buf_size))) { - log_error("Failed to allocate buffer."); - goto finish; - } - - if (mkdir_parents(RANDOM_SEED, 0755) < 0) { - log_error("Failed to create directories parents of %s: %m", RANDOM_SEED); - goto finish; - } - - /* When we load the seed we read it and write it to the device - * and then immediately update the saved seed with new data, - * to make sure the next boot gets seeded differently. */ - - if (streq(argv[1], "load")) { - - if ((seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { - if ((seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { - log_error("Failed to open random seed: %m"); - goto finish; - } - } - - if ((random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { - if ((random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { - log_error("Failed to open /dev/urandom: %m"); - goto finish; - } - } - - if ((r = loop_read(seed_fd, buf, buf_size, false)) <= 0) { - - if (r != 0) - log_error("Failed to read seed file: %m"); - } else { - lseek(seed_fd, 0, SEEK_SET); - - if ((r = loop_write(random_fd, buf, (size_t) r, false)) <= 0) - log_error("Failed to write seed to /dev/random: %s", r < 0 ? strerror(errno) : "short write"); - } - - } else if (streq(argv[1], "save")) { - - if ((seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { - log_error("Failed to open random seed: %m"); - goto finish; - } - - if ((random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { - log_error("Failed to open /dev/urandom: %m"); - goto finish; - } - } else { - log_error("Unknown verb %s.", argv[1]); - goto finish; - } - - /* This is just a safety measure. Given that we are root and - * most likely created the file ourselves the mode and owner - * should be correct anyway. */ - fchmod(seed_fd, 0600); - fchown(seed_fd, 0, 0); - - if ((r = loop_read(random_fd, buf, buf_size, false)) <= 0) - log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(errno) : "EOF"); - else { - if ((r = loop_write(seed_fd, buf, (size_t) r, false)) <= 0) - log_error("Failed to write new random seed file: %s", r < 0 ? strerror(errno) : "short write"); - } - - ret = EXIT_SUCCESS; - -finish: - if (random_fd >= 0) - close_nointr_nofail(random_fd); - - if (seed_fd >= 0) - close_nointr_nofail(seed_fd); - - free(buf); - - return ret; -} diff --git a/src/random-seed/Makefile b/src/random-seed/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/random-seed/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c new file mode 100644 index 0000000..af79ecf --- /dev/null +++ b/src/random-seed/random-seed.c @@ -0,0 +1,166 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "mkdir.h" + +#define POOL_SIZE_MIN 512 + +int main(int argc, char *argv[]) { + _cleanup_close_ int seed_fd = -1, random_fd = -1; + _cleanup_free_ void* buf = NULL; + size_t buf_size = 0; + ssize_t k; + int r; + FILE *f; + + if (argc != 2) { + log_error("This program requires one argument."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + /* Read pool size, if possible */ + f = fopen("/proc/sys/kernel/random/poolsize", "re"); + if (f) { + if (fscanf(f, "%zu", &buf_size) > 0) { + /* poolsize is in bits on 2.6, but we want bytes */ + buf_size /= 8; + } + + fclose(f); + } + + if (buf_size <= POOL_SIZE_MIN) + buf_size = POOL_SIZE_MIN; + + buf = malloc(buf_size); + if (!buf) { + r = log_oom(); + goto finish; + } + + r = mkdir_parents_label(RANDOM_SEED, 0755); + if (r < 0) { + log_error("Failed to create directory " RANDOM_SEED_DIR ": %s", strerror(-r)); + goto finish; + } + + /* When we load the seed we read it and write it to the device + * and then immediately update the saved seed with new data, + * to make sure the next boot gets seeded differently. */ + + if (streq(argv[1], "load")) { + + seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); + if (seed_fd < 0) { + seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (seed_fd < 0) { + log_error("Failed to open " RANDOM_SEED ": %m"); + r = -errno; + goto finish; + } + } + + random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); + if (random_fd < 0) { + random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); + if (random_fd < 0) { + log_error("Failed to open /dev/urandom: %m"); + r = -errno; + goto finish; + } + } + + k = loop_read(seed_fd, buf, buf_size, false); + if (k <= 0) { + + if (r != 0) + log_error("Failed to read seed from " RANDOM_SEED ": %m"); + + r = k == 0 ? -EIO : (int) k; + + } else { + lseek(seed_fd, 0, SEEK_SET); + + k = loop_write(random_fd, buf, (size_t) k, false); + if (k <= 0) { + log_error("Failed to write seed to /dev/urandom: %s", r < 0 ? strerror(-r) : "short write"); + + r = k == 0 ? -EIO : (int) k; + } + } + + } else if (streq(argv[1], "save")) { + + seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); + if (seed_fd < 0) { + log_error("Failed to open " RANDOM_SEED ": %m"); + r = -errno; + goto finish; + } + + random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (random_fd < 0) { + log_error("Failed to open /dev/urandom: %m"); + r = -errno; + goto finish; + } + + } else { + log_error("Unknown verb %s.", argv[1]); + r = -EINVAL; + goto finish; + } + + /* This is just a safety measure. Given that we are root and + * most likely created the file ourselves the mode and owner + * should be correct anyway. */ + fchmod(seed_fd, 0600); + fchown(seed_fd, 0, 0); + + k = loop_read(random_fd, buf, buf_size, false); + if (k <= 0) { + log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(-r) : "EOF"); + r = k == 0 ? -EIO : (int) k; + } else { + r = loop_write(seed_fd, buf, (size_t) k, false); + if (r <= 0) { + log_error("Failed to write new random seed file: %s", r < 0 ? strerror(-r) : "short write"); + r = r == 0 ? -EIO : r; + } + } + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/ratelimit.c b/src/ratelimit.c deleted file mode 100644 index 1ddc831..0000000 --- a/src/ratelimit.c +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "ratelimit.h" -#include "log.h" - -/* Modelled after Linux' lib/ratelimit.c by Dave Young - * , which is licensed GPLv2. */ - -bool ratelimit_test(RateLimit *r) { - usec_t ts; - - ts = now(CLOCK_MONOTONIC); - - assert(r); - assert(r->interval > 0); - assert(r->burst > 0); - - if (r->begin <= 0 || - r->begin + r->interval < ts) { - r->begin = ts; - - /* Reset counter */ - r->num = 0; - goto good; - } - - if (r->num <= r->burst) - goto good; - - return false; - -good: - r->num++; - return true; -} diff --git a/src/ratelimit.h b/src/ratelimit.h deleted file mode 100644 index a44ef70..0000000 --- a/src/ratelimit.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooratelimithfoo -#define fooratelimithfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "util.h" - -typedef struct RateLimit { - usec_t interval; - usec_t begin; - unsigned burst; - unsigned num; -} RateLimit; - -#define RATELIMIT_DEFINE(_name, _interval, _burst) \ - RateLimit _name = { \ - .interval = (_interval), \ - .burst = (_burst), \ - .num = 0, \ - .begin = 0 \ - } - -#define RATELIMIT_INIT(v, _interval, _burst) \ - do { \ - RateLimit *_r = &(v); \ - _r->interval = (_interval); \ - _r->burst = (_burst); \ - _r->num = 0; \ - _r->begin = 0; \ - } while (false); - -bool ratelimit_test(RateLimit *r); - -#endif diff --git a/src/rc-local-generator/Makefile b/src/rc-local-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/rc-local-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c new file mode 100644 index 0000000..01ff470 --- /dev/null +++ b/src/rc-local-generator/rc-local-generator.c @@ -0,0 +1,102 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2011 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "mkdir.h" + +#ifndef RC_LOCAL_SCRIPT_PATH_START +#define RC_LOCAL_SCRIPT_PATH_START "/etc/rc.d/rc.local" +#endif + +#ifndef RC_LOCAL_SCRIPT_PATH_STOP +#define RC_LOCAL_SCRIPT_PATH_STOP "/sbin/halt.local" +#endif + +const char *arg_dest = "/tmp"; + +static int add_symlink(const char *service, const char *where) { + _cleanup_free_ char *from = NULL, *to = NULL; + int r; + + assert(service); + assert(where); + + from = strjoin(SYSTEM_DATA_UNIT_PATH, "/", service, NULL); + if (!from) + return log_oom(); + + to = strjoin(arg_dest, "/", where, ".wants/", service, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + + r = symlink(from, to); + if (r < 0) { + if (errno == EEXIST) + return 0; + + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r = EXIT_SUCCESS; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[1]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (access(RC_LOCAL_SCRIPT_PATH_START, X_OK) >= 0) { + log_debug("Automatically adding rc-local.service."); + + if (add_symlink("rc-local.service", "multi-user.target") < 0) + r = EXIT_FAILURE; + } + + if (access(RC_LOCAL_SCRIPT_PATH_STOP, X_OK) >= 0) { + log_debug("Automatically adding halt-local.service."); + + if (add_symlink("halt-local.service", "final.target") < 0) + r = EXIT_FAILURE; + } + + return r; +} diff --git a/src/readahead-collect.c b/src/readahead-collect.c deleted file mode 100644 index eac11e7..0000000 --- a/src/readahead-collect.c +++ /dev/null @@ -1,692 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "missing.h" -#include "util.h" -#include "set.h" -#include "sd-daemon.h" -#include "ioprio.h" -#include "readahead-common.h" -#include "virt.h" - -/* fixme: - * - * - detect ssd on btrfs/lvm... - * - read ahead directories - * - gzip? - * - remount rw? - * - handle files where nothing is in mincore - * - does ioprio_set work with fadvise()? - */ - -static unsigned arg_files_max = 16*1024; -static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX; -static usec_t arg_timeout = 2*USEC_PER_MINUTE; - -static ReadaheadShared *shared = NULL; - -/* Avoid collisions with the NULL pointer */ -#define SECTOR_TO_PTR(s) ULONG_TO_PTR((s)+1) -#define PTR_TO_SECTOR(p) (PTR_TO_ULONG(p)-1) - -static int btrfs_defrag(int fd) { - struct btrfs_ioctl_vol_args data; - - zero(data); - data.fd = fd; - - return ioctl(fd, BTRFS_IOC_DEFRAG, &data); -} - -static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { - struct stat st; - void *start = MAP_FAILED; - uint8_t *vec; - uint32_t b, c; - size_t l, pages; - bool mapped; - int r = 0, fd = -1, k; - - assert(pack); - assert(fn); - - if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) { - - if (errno == ENOENT) - return 0; - - if (errno == EPERM || errno == EACCES) - return 0; - - log_warning("open(%s) failed: %m", fn); - r = -errno; - goto finish; - } - - if ((k = file_verify(fd, fn, arg_file_size_max, &st)) <= 0) { - r = k; - goto finish; - } - - if (on_btrfs) - btrfs_defrag(fd); - - l = PAGE_ALIGN(st.st_size); - if ((start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { - log_warning("mmap(%s) failed: %m", fn); - r = -errno; - goto finish; - } - - pages = l / page_size(); - - vec = alloca(pages); - memset(vec, 0, pages); - if (mincore(start, l, vec) < 0) { - log_warning("mincore(%s) failed: %m", fn); - r = -errno; - goto finish; - } - - fputs(fn, pack); - fputc('\n', pack); - - mapped = false; - for (c = 0; c < pages; c++) { - bool new_mapped = !!(vec[c] & 1); - - if (!mapped && new_mapped) - b = c; - else if (mapped && !new_mapped) { - fwrite(&b, sizeof(b), 1, pack); - fwrite(&c, sizeof(c), 1, pack); - - log_debug("%s: page %u to %u", fn, b, c); - } - - mapped = new_mapped; - } - - /* We don't write any range data if we should read the entire file */ - if (mapped && b > 0) { - fwrite(&b, sizeof(b), 1, pack); - fwrite(&c, sizeof(c), 1, pack); - - log_debug("%s: page %u to %u", fn, b, c); - } - - /* End marker */ - b = 0; - fwrite(&b, sizeof(b), 1, pack); - fwrite(&b, sizeof(b), 1, pack); - -finish: - if (start != MAP_FAILED) - munmap(start, l); - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static unsigned long fd_first_block(int fd) { - struct { - struct fiemap fiemap; - struct fiemap_extent extent; - } data; - - zero(data); - data.fiemap.fm_length = ~0ULL; - data.fiemap.fm_extent_count = 1; - - if (ioctl(fd, FS_IOC_FIEMAP, &data) < 0) - return 0; - - if (data.fiemap.fm_mapped_extents <= 0) - return 0; - - if (data.fiemap.fm_extents[0].fe_flags & FIEMAP_EXTENT_UNKNOWN) - return 0; - - return (unsigned long) data.fiemap.fm_extents[0].fe_physical; -} - -struct item { - const char *path; - unsigned long block; -}; - -static int qsort_compare(const void *a, const void *b) { - const struct item *i, *j; - - i = a; - j = b; - - if (i->block < j->block) - return -1; - if (i->block > j->block) - return 1; - - return strcmp(i->path, j->path); -} - -static int collect(const char *root) { - enum { - FD_FANOTIFY, /* Get the actual fs events */ - FD_SIGNAL, - FD_INOTIFY, /* We get notifications to quit early via this fd */ - _FD_MAX - }; - struct pollfd pollfd[_FD_MAX]; - int fanotify_fd = -1, signal_fd = -1, inotify_fd = -1, r = 0; - pid_t my_pid; - Hashmap *files = NULL; - Iterator i; - char *p, *q; - sigset_t mask; - FILE *pack = NULL; - char *pack_fn_new = NULL, *pack_fn = NULL; - bool on_ssd, on_btrfs; - struct statfs sfs; - usec_t not_after; - - assert(root); - - write_one_line_file("/proc/self/oom_score_adj", "1000"); - - if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0) - log_warning("Failed to set IDLE IO priority class: %m"); - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - if (!(files = hashmap_new(string_hash_func, string_compare_func))) { - log_error("Failed to allocate set."); - r = -ENOMEM; - goto finish; - } - - if ((fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME)) < 0) { - log_error("Failed to create fanotify object: %m"); - r = -errno; - goto finish; - } - - if (fanotify_mark(fanotify_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_OPEN, AT_FDCWD, root) < 0) { - log_error("Failed to mark %s: %m", root); - r = -errno; - goto finish; - } - - if ((inotify_fd = open_inotify()) < 0) { - r = inotify_fd; - goto finish; - } - - not_after = now(CLOCK_MONOTONIC) + arg_timeout; - - my_pid = getpid(); - - zero(pollfd); - pollfd[FD_FANOTIFY].fd = fanotify_fd; - pollfd[FD_FANOTIFY].events = POLLIN; - pollfd[FD_SIGNAL].fd = signal_fd; - pollfd[FD_SIGNAL].events = POLLIN; - pollfd[FD_INOTIFY].fd = inotify_fd; - pollfd[FD_INOTIFY].events = POLLIN; - - sd_notify(0, - "READY=1\n" - "STATUS=Collecting readahead data"); - - log_debug("Collecting..."); - - if (access("/run/systemd/readahead/cancel", F_OK) >= 0) { - log_debug("Collection canceled"); - r = -ECANCELED; - goto finish; - } - - if (access("/run/systemd/readahead/done", F_OK) >= 0) { - log_debug("Got termination request"); - goto done; - } - - for (;;) { - union { - struct fanotify_event_metadata metadata; - char buffer[4096]; - } data; - ssize_t n; - struct fanotify_event_metadata *m; - usec_t t; - int h; - - if (hashmap_size(files) > arg_files_max) { - log_debug("Reached maximum number of read ahead files, ending collection."); - break; - } - - t = now(CLOCK_MONOTONIC); - if (t >= not_after) { - log_debug("Reached maximum collection time, ending collection."); - break; - } - - if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) { - - if (errno == EINTR) - continue; - - log_error("poll(): %m"); - r = -errno; - goto finish; - } - - if (h == 0) { - log_debug("Reached maximum collection time, ending collection."); - break; - } - - if (pollfd[FD_SIGNAL].revents) { - log_debug("Got signal."); - break; - } - - if (pollfd[FD_INOTIFY].revents) { - uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; - struct inotify_event *e; - - if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - - log_error("Failed to read inotify event: %m"); - r = -errno; - goto finish; - } - - e = (struct inotify_event*) inotify_buffer; - while (n > 0) { - size_t step; - - if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) { - log_debug("Collection canceled"); - r = -ECANCELED; - goto finish; - } - - if ((e->mask & IN_CREATE) && streq(e->name, "done")) { - log_debug("Got termination request"); - goto done; - } - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) n); - - e = (struct inotify_event*) ((uint8_t*) e + step); - n -= step; - } - } - - if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - /* fanotify sometimes returns EACCES on read() - * where it shouldn't. For now let's just - * ignore it here (which is safe), but - * eventually this should be - * dropped when the kernel is fixed. - * - * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */ - if (errno == EACCES) - continue; - - log_error("Failed to read event: %m"); - r = -errno; - goto finish; - } - - for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) { - char fn[PATH_MAX]; - int k; - - if (m->fd < 0) - goto next_iteration; - - if (m->pid == my_pid) - goto next_iteration; - - __sync_synchronize(); - if (m->pid == shared->replay) - goto next_iteration; - - snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd); - char_array_0(fn); - - if ((k = readlink_malloc(fn, &p)) >= 0) { - if (startswith(p, "/tmp") || - endswith(p, " (deleted)") || - hashmap_get(files, p)) - /* Not interesting, or - * already read */ - free(p); - else { - unsigned long ul; - - ul = fd_first_block(m->fd); - - if ((k = hashmap_put(files, p, SECTOR_TO_PTR(ul))) < 0) { - log_warning("set_put() failed: %s", strerror(-k)); - free(p); - } - } - - } else - log_warning("readlink(%s) failed: %s", fn, strerror(-k)); - - next_iteration: - if (m->fd) - close_nointr_nofail(m->fd); - } - } - -done: - if (fanotify_fd >= 0) { - close_nointr_nofail(fanotify_fd); - fanotify_fd = -1; - } - - log_debug("Writing Pack File..."); - - on_ssd = fs_on_ssd(root) > 0; - log_debug("On SSD: %s", yes_no(on_ssd)); - - on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC; - log_debug("On btrfs: %s", yes_no(on_btrfs)); - - asprintf(&pack_fn, "%s/.readahead", root); - asprintf(&pack_fn_new, "%s/.readahead.new", root); - - if (!pack_fn || !pack_fn_new) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - if (!(pack = fopen(pack_fn_new, "we"))) { - log_error("Failed to open pack file: %m"); - r = -errno; - goto finish; - } - - fputs(CANONICAL_HOST "\n", pack); - putc(on_ssd ? 'S' : 'R', pack); - - if (on_ssd || on_btrfs) { - - /* On SSD or on btrfs, just write things out in the - * order the files were accessed. */ - - HASHMAP_FOREACH_KEY(q, p, files, i) - pack_file(pack, p, on_btrfs); - } else { - struct item *ordered, *j; - unsigned k, n; - - /* On rotating media, order things by the block - * numbers */ - - log_debug("Ordering..."); - - n = hashmap_size(files); - if (!(ordered = new(struct item, n))) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - j = ordered; - HASHMAP_FOREACH_KEY(q, p, files, i) { - j->path = p; - j->block = PTR_TO_SECTOR(q); - j++; - } - - assert(ordered + n == j); - - qsort(ordered, n, sizeof(struct item), qsort_compare); - - for (k = 0; k < n; k++) - pack_file(pack, ordered[k].path, on_btrfs); - - free(ordered); - } - - log_debug("Finalizing..."); - - fflush(pack); - - if (ferror(pack)) { - log_error("Failed to write pack file."); - r = -EIO; - goto finish; - } - - if (rename(pack_fn_new, pack_fn) < 0) { - log_error("Failed to rename readahead file: %m"); - r = -errno; - goto finish; - } - - fclose(pack); - pack = NULL; - - log_debug("Done."); - -finish: - if (fanotify_fd >= 0) - close_nointr_nofail(fanotify_fd); - - if (signal_fd >= 0) - close_nointr_nofail(signal_fd); - - if (inotify_fd >= 0) - close_nointr_nofail(inotify_fd); - - if (pack) { - fclose(pack); - unlink(pack_fn_new); - } - - free(pack_fn_new); - free(pack_fn); - - while ((p = hashmap_steal_first_key(files))) - free(p); - - hashmap_free(files); - - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...] [DIRECTORY]\n\n" - "Collect read-ahead data on early boot.\n\n" - " -h --help Show this help\n" - " --max-files=INT Maximum number of files to read ahead\n" - " --max-file-size=BYTES Maximum size of files to read ahead\n" - " --timeout=USEC Maximum time to spend collecting data\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_FILES_MAX = 0x100, - ARG_FILE_SIZE_MAX, - ARG_TIMEOUT - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "files-max", required_argument, NULL, ARG_FILES_MAX }, - { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX }, - { "timeout", required_argument, NULL, ARG_TIMEOUT }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_FILES_MAX: - if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) { - log_error("Failed to parse maximum number of files %s.", optarg); - return -EINVAL; - } - break; - - case ARG_FILE_SIZE_MAX: { - unsigned long long ull; - - if (safe_atollu(optarg, &ull) < 0 || ull <= 0) { - log_error("Failed to parse maximum file size %s.", optarg); - return -EINVAL; - } - - arg_file_size_max = (off_t) ull; - break; - } - - case ARG_TIMEOUT: - if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) { - log_error("Failed to parse timeout %s.", optarg); - return -EINVAL; - } - - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind != argc && - optind != argc-1) { - help(); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r; - const char *root; - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((r = parse_argv(argc, argv)) <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - - root = optind < argc ? argv[optind] : "/"; - - if (fs_on_read_only(root) > 0) { - log_info("Disabling readahead collector due to read-only media."); - return 0; - } - - if (!enough_ram()) { - log_info("Disabling readahead collector due to low memory."); - return 0; - } - - if (detect_virtualization(NULL) > 0) { - log_info("Disabling readahead collector due to execution in virtualized environment."); - return 0; - } - - if (!(shared = shared_get())) - return 1; - - shared->collect = getpid(); - __sync_synchronize(); - - if (collect(root) < 0) - return 1; - - return 0; -} diff --git a/src/readahead-common.c b/src/readahead-common.c deleted file mode 100644 index 67214ec..0000000 --- a/src/readahead-common.c +++ /dev/null @@ -1,269 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "readahead-common.h" -#include "util.h" - -int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { - assert(fd >= 0); - assert(fn); - assert(st); - - if (fstat(fd, st) < 0) { - log_warning("fstat(%s) failed: %m", fn); - return -errno; - } - - if (!S_ISREG(st->st_mode)) { - log_debug("Not preloading special file %s", fn); - return 0; - } - - if (st->st_size <= 0 || st->st_size > file_size_max) { - log_debug("Not preloading file %s with size out of bounds %llu", fn, (unsigned long long) st->st_size); - return 0; - } - - return 1; -} - -int fs_on_ssd(const char *p) { - struct stat st; - struct udev *udev = NULL; - struct udev_device *udev_device = NULL, *look_at = NULL; - bool b = false; - const char *devtype, *rotational, *model, *id; - - assert(p); - - if (stat(p, &st) < 0) - return -errno; - - if (major(st.st_dev) == 0) - return false; - - if (!(udev = udev_new())) - return -ENOMEM; - - if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev))) - goto finish; - - if ((devtype = udev_device_get_property_value(udev_device, "DEVTYPE")) && - streq(devtype, "partition")) - look_at = udev_device_get_parent(udev_device); - else - look_at = udev_device; - - if (!look_at) - goto finish; - - /* First, try high-level property */ - if ((id = udev_device_get_property_value(look_at, "ID_SSD"))) { - b = streq(id, "1"); - goto finish; - } - - /* Second, try kernel attribute */ - if ((rotational = udev_device_get_sysattr_value(look_at, "queue/rotational"))) - if ((b = streq(rotational, "0"))) - goto finish; - - /* Finally, fallback to heuristics */ - if (!(look_at = udev_device_get_parent(look_at))) - goto finish; - - if ((model = udev_device_get_sysattr_value(look_at, "model"))) - b = !!strstr(model, "SSD"); - -finish: - if (udev_device) - udev_device_unref(udev_device); - - if (udev) - udev_unref(udev); - - return b; -} - -int fs_on_read_only(const char *p) { - struct stat st; - struct udev *udev = NULL; - struct udev_device *udev_device = NULL; - bool b = false; - const char *read_only; - - assert(p); - - if (stat(p, &st) < 0) - return -errno; - - if (major(st.st_dev) == 0) - return false; - - if (!(udev = udev_new())) - return -ENOMEM; - - if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev))) - goto finish; - - if ((read_only = udev_device_get_sysattr_value(udev_device, "ro"))) - if ((b = streq(read_only, "1"))) - goto finish; - -finish: - if (udev_device) - udev_device_unref(udev_device); - - if (udev) - udev_unref(udev); - - return b; -} - -bool enough_ram(void) { - struct sysinfo si; - - assert_se(sysinfo(&si) >= 0); - - /* Enable readahead only with at least 128MB memory */ - return si.totalram > 127 * 1024*1024 / si.mem_unit; -} - -int open_inotify(void) { - int fd; - - if ((fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { - log_error("Failed to create inotify handle: %m"); - return -errno; - } - - mkdir("/run/systemd", 0755); - mkdir("/run/systemd/readahead", 0755); - - if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) { - log_error("Failed to watch /run/systemd/readahead: %m"); - close_nointr_nofail(fd); - return -errno; - } - - return fd; -} - -ReadaheadShared *shared_get(void) { - int fd; - ReadaheadShared *m = NULL; - - mkdir("/run/systemd", 0755); - mkdir("/run/systemd/readahead", 0755); - - if ((fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644)) < 0) { - log_error("Failed to create shared memory segment: %m"); - goto finish; - } - - if (ftruncate(fd, sizeof(ReadaheadShared)) < 0) { - log_error("Failed to truncate shared memory segment: %m"); - goto finish; - } - - if ((m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { - log_error("Failed to mmap shared memory segment: %m"); - m = NULL; - goto finish; - } - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - return m; -} - -#define BUMP_REQUEST_NR (16*1024) - -int bump_request_nr(const char *p) { - struct stat st; - uint64_t u; - char *ap = NULL, *line = NULL; - int r; - dev_t d; - - assert(p); - - if (stat(p, &st) < 0) - return -errno; - - if (major(st.st_dev) == 0) - return 0; - - d = st.st_dev; - block_get_whole_disk(d, &d); - - if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { - r= -ENOMEM; - goto finish; - } - - r = read_one_line_file(ap, &line); - if (r < 0) { - if (r == -ENOENT) - r = 0; - goto finish; - } - - r = safe_atou64(line, &u); - if (r >= 0 && u >= BUMP_REQUEST_NR) { - r = 0; - goto finish; - } - - free(line); - line = NULL; - - if (asprintf(&line, "%lu", (unsigned long) BUMP_REQUEST_NR) < 0) { - r = -ENOMEM; - goto finish; - } - - r = write_one_line_file(ap, line); - if (r < 0) - goto finish; - - log_info("Bumped block_nr parameter of %u:%u to %lu. This is a temporary hack and should be removed one day.", major(d), minor(d), (unsigned long) BUMP_REQUEST_NR); - r = 1; - -finish: - free(ap); - free(line); - - return r; -} diff --git a/src/readahead-common.h b/src/readahead-common.h deleted file mode 100644 index 9547ad2..0000000 --- a/src/readahead-common.h +++ /dev/null @@ -1,50 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooreadaheadcommonhfoo -#define fooreadaheadcommonhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "macro.h" - -#define READAHEAD_FILE_SIZE_MAX (10*1024*1024) - -int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st); - -int fs_on_ssd(const char *p); -int fs_on_read_only(const char *p); - -bool enough_ram(void); - -int open_inotify(void); - -typedef struct ReadaheadShared { - pid_t collect; - pid_t replay; -} _packed_ ReadaheadShared; - -ReadaheadShared *shared_get(void); - -int bump_request_nr(const char *p); - -#endif diff --git a/src/readahead-replay.c b/src/readahead-replay.c deleted file mode 100644 index 65011ac..0000000 --- a/src/readahead-replay.c +++ /dev/null @@ -1,371 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "missing.h" -#include "util.h" -#include "set.h" -#include "sd-daemon.h" -#include "ioprio.h" -#include "readahead-common.h" -#include "virt.h" - -static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX; - -static ReadaheadShared *shared = NULL; - -static int unpack_file(FILE *pack) { - char fn[PATH_MAX]; - int r = 0, fd = -1; - bool any = false; - struct stat st; - - assert(pack); - - if (!fgets(fn, sizeof(fn), pack)) - return 0; - - char_array_0(fn); - truncate_nl(fn); - - if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) { - - if (errno != ENOENT && errno != EPERM && errno != EACCES) - log_warning("open(%s) failed: %m", fn); - - } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) { - close_nointr_nofail(fd); - fd = -1; - } - - for (;;) { - uint32_t b, c; - - if (fread(&b, sizeof(b), 1, pack) != 1 || - fread(&c, sizeof(c), 1, pack) != 1) { - log_error("Premature end of pack file."); - r = -EIO; - goto finish; - } - - if (b == 0 && c == 0) - break; - - if (c <= b) { - log_error("Invalid pack file."); - r = -EIO; - goto finish; - } - - log_debug("%s: page %u to %u", fn, b, c); - - any = true; - - if (fd >= 0) - if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) { - log_warning("posix_fadvise() failed: %m"); - goto finish; - } - } - - if (!any && fd >= 0) { - /* if no range is encoded in the pack file this is - * intended to mean that the whole file shall be - * read */ - - if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) { - log_warning("posix_fadvise() failed: %m"); - goto finish; - } - } - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int replay(const char *root) { - FILE *pack = NULL; - char line[LINE_MAX]; - int r = 0; - char *pack_fn = NULL; - int c; - bool on_ssd, ready = false; - int prio; - int inotify_fd = -1; - - assert(root); - - write_one_line_file("/proc/self/oom_score_adj", "1000"); - bump_request_nr(root); - - if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - if ((!(pack = fopen(pack_fn, "re")))) { - if (errno == ENOENT) - log_debug("No pack file found."); - else { - log_error("Failed to open pack file: %m"); - r = -errno; - } - - goto finish; - } - - posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED); - - if ((inotify_fd = open_inotify()) < 0) { - r = inotify_fd; - goto finish; - } - - if (!(fgets(line, sizeof(line), pack))) { - log_error("Premature end of pack file."); - r = -EIO; - goto finish; - } - - char_array_0(line); - - if (!streq(line, CANONICAL_HOST "\n")) { - log_debug("Pack file host type mismatch."); - goto finish; - } - - if ((c = getc(pack)) == EOF) { - log_debug("Premature end of pack file."); - r = -EIO; - goto finish; - } - - /* We do not retest SSD here, so that we can start replaying - * before udev is up.*/ - on_ssd = c == 'S'; - log_debug("On SSD: %s", yes_no(on_ssd)); - - if (on_ssd) - prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0); - else - prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 7); - - if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0) - log_warning("Failed to set IDLE IO priority class: %m"); - - sd_notify(0, "STATUS=Replaying readahead data"); - - log_debug("Replaying..."); - - if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) { - log_debug("Got termination request"); - goto done; - } - - while (!feof(pack) && !ferror(pack)) { - uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; - int k; - ssize_t n; - - if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { - if (errno != EINTR && errno != EAGAIN) { - log_error("Failed to read inotify event: %m"); - r = -errno; - goto finish; - } - } else { - struct inotify_event *e = (struct inotify_event*) inotify_buffer; - - while (n > 0) { - size_t step; - - if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) { - log_debug("Got termination request"); - goto done; - } - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) n); - - e = (struct inotify_event*) ((uint8_t*) e + step); - n -= step; - } - } - - if ((k = unpack_file(pack)) < 0) { - r = k; - goto finish; - } - - if (!ready) { - /* We delay the ready notification until we - * queued at least one read */ - sd_notify(0, "READY=1"); - ready = true; - } - } - -done: - if (!ready) - sd_notify(0, "READY=1"); - - if (ferror(pack)) { - log_error("Failed to read pack file."); - r = -EIO; - goto finish; - } - - log_debug("Done."); - -finish: - if (pack) - fclose(pack); - - if (inotify_fd >= 0) - close_nointr_nofail(inotify_fd); - - free(pack_fn); - - return r; -} - - -static int help(void) { - - printf("%s [OPTIONS...] [DIRECTORY]\n\n" - "Replay collected read-ahead data on early boot.\n\n" - " -h --help Show this help\n" - " --max-file-size=BYTES Maximum size of files to read ahead\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_FILE_SIZE_MAX - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_FILE_SIZE_MAX: { - unsigned long long ull; - - if (safe_atollu(optarg, &ull) < 0 || ull <= 0) { - log_error("Failed to parse maximum file size %s.", optarg); - return -EINVAL; - } - - arg_file_size_max = (off_t) ull; - break; - } - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind != argc && - optind != argc-1) { - help(); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char*argv[]) { - int r; - const char *root; - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((r = parse_argv(argc, argv)) <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - - root = optind < argc ? argv[optind] : "/"; - - if (!enough_ram()) { - log_info("Disabling readahead replay due to low memory."); - return 0; - } - - if (detect_virtualization(NULL) > 0) { - log_info("Disabling readahead replay due to execution in virtualized environment."); - return 0; - } - - if (!(shared = shared_get())) - return 1; - - shared->replay = getpid(); - __sync_synchronize(); - - if (replay(root) < 0) - return 1; - - return 0; -} diff --git a/src/readahead/Makefile b/src/readahead/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/readahead/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/readahead/readahead-analyze.c b/src/readahead/readahead-analyze.c new file mode 100644 index 0000000..76db3cb --- /dev/null +++ b/src/readahead/readahead-analyze.c @@ -0,0 +1,146 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "readahead-common.h" + +int main_analyze(const char *pack_path) { + char line[LINE_MAX]; + _cleanup_fclose_ FILE *pack = NULL; + int a; + int missing = 0; + size_t tsize = 0; + + if (!pack_path) + pack_path = "/.readahead"; + + pack = fopen(pack_path, "re"); + if (!pack) { + log_error("Pack file missing."); + goto fail; + } + + if (!fgets(line, sizeof(line), pack)) { + log_error("Pack file corrupt."); + goto fail; + } + + char_array_0(line); + + if (!endswith(line, READAHEAD_PACK_FILE_VERSION)) { + log_error("Pack file version incompatible with this parser."); + goto fail; + } + + if ((a = getc(pack)) == EOF) { + log_error("Pack file corrupt."); + goto fail; + } + + fputs(" pct sections size: path\n" + " === ======== ====: ====\n", stdout); + + for (;;) { + char path[PATH_MAX]; + struct stat st; + uint64_t inode; + int pages = 0; + int sections = 0; + + if (!fgets(path, sizeof(path), pack)) + break; /* done */ + + path[strlen(path)-1] = 0; + + if (fread(&inode, sizeof(inode), 1, pack) != 1) { + log_error("Pack file corrupt."); + goto fail; + } + + for (;;) { + uint32_t b, c; + + if (fread(&b, sizeof(b), 1, pack) != 1 || + fread(&c, sizeof(c), 1, pack) != 1) { + log_error("Pack file corrupt."); + goto fail; + } + if ((b == 0) && (c == 0)) + break; + + /* Uncomment this to get all the chunks separately + printf(" %d: %d %d\n", sections, b, c); + */ + + pages += (c - b); + sections++; + } + + if (stat(path, &st) == 0) { + off_t size; + + if (sections == 0) + size = st.st_size; + else + size = pages * page_size(); + + tsize += size; + + printf(" %4jd%% (%2d) %12jd: %s\n", + (intmax_t) (sections && st.st_size ? size * 100 / st.st_size : 100), + sections ? sections : 1, + (intmax_t) size, + path); + } else { + printf(" %4dp (%2d) %12s: %s (MISSING)\n", + sections ? pages : -1, + sections ? sections : 1, + "???", + path); + missing++; + } + + } + + printf("\nHOST: %s" + "TYPE: %c\n" + "MISSING: %d\n" + "TOTAL: %zu\n", + line, + a, + missing, + tsize); + + return EXIT_SUCCESS; + +fail: + return EXIT_FAILURE; +} diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c new file mode 100644 index 0000000..bc38a6b --- /dev/null +++ b/src/readahead/readahead-collect.c @@ -0,0 +1,668 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LINUX_BTRFS_H +#include +#endif + +#ifdef HAVE_FANOTIFY_INIT +#include +#endif + +#include + +#include "missing.h" +#include "util.h" +#include "set.h" +#include "ioprio.h" +#include "readahead-common.h" +#include "virt.h" + +/* fixme: + * + * - detect ssd on btrfs/lvm... + * - read ahead directories + * - gzip? + * - remount rw? + * - handle files where nothing is in mincore + * - does ioprio_set work with fadvise()? + */ + +static ReadaheadShared *shared = NULL; +static usec_t starttime; + +/* Avoid collisions with the NULL pointer */ +#define SECTOR_TO_PTR(s) ULONG_TO_PTR((s)+1) +#define PTR_TO_SECTOR(p) (PTR_TO_ULONG(p)-1) + +static int btrfs_defrag(int fd) { + struct btrfs_ioctl_vol_args data = { .fd = fd }; + + return ioctl(fd, BTRFS_IOC_DEFRAG, &data); +} + +static int pack_file(FILE *pack, const char *fn, bool on_btrfs) { + struct stat st; + void *start = MAP_FAILED; + uint8_t *vec; + uint32_t b, c; + uint64_t inode; + size_t l, pages; + bool mapped; + int r = 0, fd = -1, k; + + assert(pack); + assert(fn); + + fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) { + + if (errno == ENOENT) + return 0; + + if (errno == EPERM || errno == EACCES) + return 0; + + log_warning("open(%s) failed: %m", fn); + r = -errno; + goto finish; + } + + k = file_verify(fd, fn, arg_file_size_max, &st); + if (k <= 0) { + r = k; + goto finish; + } + + if (on_btrfs) + btrfs_defrag(fd); + + l = PAGE_ALIGN(st.st_size); + start = mmap(NULL, l, PROT_READ, MAP_SHARED, fd, 0); + if (start == MAP_FAILED) { + log_warning("mmap(%s) failed: %m", fn); + r = -errno; + goto finish; + } + + pages = l / page_size(); + vec = alloca0(pages); + if (mincore(start, l, vec) < 0) { + log_warning("mincore(%s) failed: %m", fn); + r = -errno; + goto finish; + } + + fputs(fn, pack); + fputc('\n', pack); + + /* Store the inode, so that we notice when the file is deleted */ + inode = (uint64_t) st.st_ino; + fwrite(&inode, sizeof(inode), 1, pack); + + mapped = false; + for (c = 0; c < pages; c++) { + bool new_mapped = !!(vec[c] & 1); + + if (!mapped && new_mapped) + b = c; + else if (mapped && !new_mapped) { + fwrite(&b, sizeof(b), 1, pack); + fwrite(&c, sizeof(c), 1, pack); + + log_debug("%s: page %u to %u", fn, b, c); + } + + mapped = new_mapped; + } + + /* We don't write any range data if we should read the entire file */ + if (mapped && b > 0) { + fwrite(&b, sizeof(b), 1, pack); + fwrite(&c, sizeof(c), 1, pack); + + log_debug("%s: page %u to %u", fn, b, c); + } + + /* End marker */ + b = 0; + fwrite(&b, sizeof(b), 1, pack); + fwrite(&b, sizeof(b), 1, pack); + +finish: + if (start != MAP_FAILED) + munmap(start, l); + + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +static unsigned long fd_first_block(int fd) { + struct { + struct fiemap fiemap; + struct fiemap_extent extent; + } data = { + .fiemap.fm_length = ~0ULL, + .fiemap.fm_extent_count = 1, + }; + + if (ioctl(fd, FS_IOC_FIEMAP, &data) < 0) + return 0; + + if (data.fiemap.fm_mapped_extents <= 0) + return 0; + + if (data.fiemap.fm_extents[0].fe_flags & FIEMAP_EXTENT_UNKNOWN) + return 0; + + return (unsigned long) data.fiemap.fm_extents[0].fe_physical; +} + +struct item { + const char *path; + unsigned long block; + unsigned long bin; +}; + +static int qsort_compare(const void *a, const void *b) { + const struct item *i, *j; + + i = a; + j = b; + + /* sort by bin first */ + if (i->bin < j->bin) + return -1; + if (i->bin > j->bin) + return 1; + + /* then sort by sector */ + if (i->block < j->block) + return -1; + if (i->block > j->block) + return 1; + + return strcmp(i->path, j->path); +} + +static int collect(const char *root) { + enum { + FD_FANOTIFY, /* Get the actual fs events */ + FD_SIGNAL, + FD_INOTIFY, /* We get notifications to quit early via this fd */ + _FD_MAX + }; + struct pollfd pollfd[_FD_MAX] = {}; + int fanotify_fd = -1, signal_fd = -1, inotify_fd = -1, r = 0; + pid_t my_pid; + Hashmap *files = NULL; + Iterator i; + char *p, *q; + sigset_t mask; + FILE *pack = NULL; + char *pack_fn_new = NULL, *pack_fn = NULL; + bool on_ssd, on_btrfs; + struct statfs sfs; + usec_t not_after; + uint64_t previous_block_readahead; + bool previous_block_readahead_set = false; + + assert(root); + +#ifndef CONFIG_TIZEN + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { +#else + if (asprintf(&pack_fn, "%s/.readahead", arg_savedir ? arg_savedir : root) < 0) { +#endif + r = log_oom(); + goto finish; + } + + starttime = now(CLOCK_MONOTONIC); + + /* If there's no pack file yet we lower the kernel readahead + * so that mincore() is accurate. If there is a pack file + * already we assume it is accurate enough so that kernel + * readahead is never triggered. */ + previous_block_readahead_set = + access(pack_fn, F_OK) < 0 && + block_get_readahead(root, &previous_block_readahead) >= 0 && + block_set_readahead(root, 8*1024) >= 0; + + if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0) + log_warning("Failed to set IDLE IO priority class: %m"); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { + log_error("signalfd(): %m"); + r = -errno; + goto finish; + } + + files = hashmap_new(string_hash_func, string_compare_func); + if (!files) { + log_error("Failed to allocate set."); + r = -ENOMEM; + goto finish; + } + + fanotify_fd = fanotify_init(FAN_CLOEXEC|FAN_NONBLOCK, O_RDONLY|O_LARGEFILE|O_CLOEXEC|O_NOATIME); + if (fanotify_fd < 0) { + log_error("Failed to create fanotify object: %m"); + r = -errno; + goto finish; + } + + if (fanotify_mark(fanotify_fd, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_OPEN, AT_FDCWD, root) < 0) { + log_error("Failed to mark %s: %m", root); + r = -errno; + goto finish; + } + + inotify_fd = open_inotify(); + if (inotify_fd < 0) { + r = inotify_fd; + goto finish; + } + + not_after = now(CLOCK_MONOTONIC) + arg_timeout; + + my_pid = getpid(); + + pollfd[FD_FANOTIFY].fd = fanotify_fd; + pollfd[FD_FANOTIFY].events = POLLIN; + pollfd[FD_SIGNAL].fd = signal_fd; + pollfd[FD_SIGNAL].events = POLLIN; + pollfd[FD_INOTIFY].fd = inotify_fd; + pollfd[FD_INOTIFY].events = POLLIN; + + sd_notify(0, + "READY=1\n" + "STATUS=Collecting readahead data"); + + log_debug("Collecting..."); + + if (access("/run/systemd/readahead/cancel", F_OK) >= 0) { + log_debug("Collection canceled"); + r = -ECANCELED; + goto finish; + } + + if (access("/run/systemd/readahead/done", F_OK) >= 0) { + log_debug("Got termination request"); + goto done; + } + + for (;;) { + union { + struct fanotify_event_metadata metadata; + char buffer[4096]; + } data; + ssize_t n; + struct fanotify_event_metadata *m; + usec_t t; + int h; + + if (hashmap_size(files) > arg_files_max) { + log_debug("Reached maximum number of read ahead files, ending collection."); + break; + } + + t = now(CLOCK_MONOTONIC); + if (t >= not_after) { + log_debug("Reached maximum collection time, ending collection."); + break; + } + + if ((h = poll(pollfd, _FD_MAX, (int) ((not_after - t) / USEC_PER_MSEC))) < 0) { + + if (errno == EINTR) + continue; + + log_error("poll(): %m"); + r = -errno; + goto finish; + } + + if (h == 0) { + log_debug("Reached maximum collection time, ending collection."); + break; + } + + if (pollfd[FD_SIGNAL].revents) { + log_debug("Got signal."); + break; + } + + if (pollfd[FD_INOTIFY].revents) { + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; + struct inotify_event *e; + + if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + + log_error("Failed to read inotify event: %m"); + r = -errno; + goto finish; + } + + e = (struct inotify_event*) inotify_buffer; + while (n > 0) { + size_t step; + + if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) { + log_debug("Collection canceled"); + r = -ECANCELED; + goto finish; + } + + if ((e->mask & IN_CREATE) && streq(e->name, "done")) { + log_debug("Got termination request"); + goto done; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) n); + + e = (struct inotify_event*) ((uint8_t*) e + step); + n -= step; + } + } + + n = read(fanotify_fd, &data, sizeof(data)); + if (n < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + /* fanotify sometimes returns EACCES on read() + * where it shouldn't. For now let's just + * ignore it here (which is safe), but + * eventually this should be + * dropped when the kernel is fixed. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */ + if (errno == EACCES) + continue; + + log_error("Failed to read event: %m"); + r = -errno; + goto finish; + } + + for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) { + char fn[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + int k; + + if (m->fd < 0) + goto next_iteration; + + if (m->pid == my_pid) + goto next_iteration; + + __sync_synchronize(); + if (m->pid == shared->replay) + goto next_iteration; + + snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd); + k = readlink_malloc(fn, &p); + if (k >= 0) { + if (startswith(p, "/tmp") || + endswith(p, " (deleted)") || + hashmap_get(files, p)) + /* Not interesting, or + * already read */ + free(p); + else { + unsigned long ul; + usec_t entrytime; + struct item *entry; + + entry = new0(struct item, 1); + if (!entry) { + r = log_oom(); + goto finish; + } + + ul = fd_first_block(m->fd); + + entrytime = now(CLOCK_MONOTONIC); + + entry->block = ul; + entry->path = strdup(p); + if (!entry->path) { + free(entry); + r = log_oom(); + goto finish; + } + entry->bin = (entrytime - starttime) / 2000000; + + k = hashmap_put(files, p, entry); + if (k < 0) { + log_warning("hashmap_put() failed: %s", strerror(-k)); + free(p); + } + } + + } else + log_warning("readlink(%s) failed: %s", fn, strerror(-k)); + + next_iteration: + if (m->fd >= 0) + close_nointr_nofail(m->fd); + } + } + +done: + if (fanotify_fd >= 0) { + close_nointr_nofail(fanotify_fd); + fanotify_fd = -1; + } + + log_debug("Writing Pack File..."); + + on_ssd = fs_on_ssd(root) > 0; + log_debug("On SSD: %s", yes_no(on_ssd)); + + on_btrfs = statfs(root, &sfs) >= 0 && F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); + log_debug("On btrfs: %s", yes_no(on_btrfs)); + +#ifndef CONFIG_TIZEN + if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) { +#else + if (asprintf(&pack_fn_new, "%s/.readahead.new", arg_savedir ? arg_savedir : root) < 0) { +#endif + r = log_oom(); + goto finish; + } + + pack = fopen(pack_fn_new, "we"); + if (!pack) { + log_error("Failed to open pack file: %m"); + r = -errno; + goto finish; + } + + fputs(CANONICAL_HOST READAHEAD_PACK_FILE_VERSION, pack); + putc(on_ssd ? 'S' : 'R', pack); + + if (on_ssd || on_btrfs) { + + /* On SSD or on btrfs, just write things out in the + * order the files were accessed. */ + + HASHMAP_FOREACH_KEY(q, p, files, i) + pack_file(pack, p, on_btrfs); + } else { + unsigned n; + + /* On rotating media, order things by the block + * numbers */ + + log_debug("Ordering..."); + + n = hashmap_size(files); + if (n) { + _cleanup_free_ struct item *ordered; + struct item *j; + unsigned k; + + ordered = new(struct item, n); + if (!ordered) { + r = log_oom(); + goto finish; + } + + j = ordered; + HASHMAP_FOREACH_KEY(q, p, files, i) { + memcpy(j, q, sizeof(struct item)); + j++; + } + + assert(ordered + n == j); + + qsort(ordered, n, sizeof(struct item), qsort_compare); + + for (k = 0; k < n; k++) + pack_file(pack, ordered[k].path, on_btrfs); + } else + log_warning("No pack files"); + } + + log_debug("Finalizing..."); + + fflush(pack); + + if (ferror(pack)) { + log_error("Failed to write pack file."); + r = -EIO; + goto finish; + } + + if (rename(pack_fn_new, pack_fn) < 0) { + log_error("Failed to rename readahead file: %m"); + r = -errno; + goto finish; + } + + fclose(pack); + pack = NULL; + + log_debug("Done."); + +finish: + if (fanotify_fd >= 0) + close_nointr_nofail(fanotify_fd); + + if (signal_fd >= 0) + close_nointr_nofail(signal_fd); + + if (inotify_fd >= 0) + close_nointr_nofail(inotify_fd); + + if (pack) { + fclose(pack); + unlink(pack_fn_new); + } + free(pack_fn_new); + free(pack_fn); + + while ((p = hashmap_steal_first_key(files))) + free(p); + + hashmap_free(files); + + if (previous_block_readahead_set) { + uint64_t bytes; + + /* Restore the original kernel readahead setting if we + * changed it, and nobody has overwritten it since + * yet. */ + if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024) + block_set_readahead(root, previous_block_readahead); + } + + return r; +} + +int main_collect(const char *root) { + + if (!root) + root = "/"; + + /* Skip this step on read-only media. Note that we check the + * underlying block device here, not he read-only flag of the + * file system on top, since that one is most likely mounted + * read-only anyway at boot, even if the underlying block + * device is theoretically writable. */ + if (fs_on_read_only(root) > 0) { + log_info("Disabling readahead collector due to read-only media."); + return EXIT_SUCCESS; + } + + if (!enough_ram()) { + log_info("Disabling readahead collector due to low memory."); + return EXIT_SUCCESS; + } + + shared = shared_get(); + if (!shared) + return EXIT_FAILURE; + + shared->collect = getpid(); + __sync_synchronize(); + + if (collect(root) < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c new file mode 100644 index 0000000..aea1fbe --- /dev/null +++ b/src/readahead/readahead-common.c @@ -0,0 +1,398 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "readahead-common.h" +#include "util.h" +#include "missing.h" +#include "fileio.h" +#include "libudev.h" +#include "udev-util.h" + +int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st) { + assert(fd >= 0); + assert(fn); + assert(st); + + if (fstat(fd, st) < 0) { + log_warning("fstat(%s) failed: %m", fn); + return -errno; + } + + if (!S_ISREG(st->st_mode)) { + log_debug("Not preloading special file %s", fn); + return 0; + } + + if (st->st_size <= 0 || st->st_size > file_size_max) { + log_debug("Not preloading file %s with size out of bounds %llu", fn, (unsigned long long) st->st_size); + return 0; + } + + return 1; +} + +int fs_on_ssd(const char *p) { + struct stat st; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; + struct udev_device *look_at = NULL; + const char *devtype, *rotational, *model, *id; + int r; + + assert(p); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) { + _cleanup_fclose_ FILE *f = NULL; + int mount_id; + struct file_handle *h; + + /* Might be btrfs, which exposes "ssd" as mount flag if it is on ssd. + * + * We first determine the mount ID here, if we can, + * and then lookup the mount ID in mountinfo to find + * the mount options. */ + + h = alloca(MAX_HANDLE_SZ); + h->handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(AT_FDCWD, p, h, &mount_id, AT_SYMLINK_FOLLOW); + if (r < 0) + return false; + + f = fopen("/proc/self/mountinfo", "re"); + if (!f) + return false; + + for (;;) { + char line[LINE_MAX], *e; + _cleanup_free_ char *opts = NULL; + int mid; + + if (!fgets(line, sizeof(line), f)) + return false; + + truncate_nl(line); + + if (sscanf(line, "%i", &mid) != 1) + continue; + + if (mid != mount_id) + continue; + + e = strstr(line, " - "); + if (!e) + continue; + + if (sscanf(e+3, "%*s %*s %ms", &opts) != 1) + continue; + + if (streq(opts, "ssd") || startswith(opts, "ssd,") || endswith(opts, ",ssd") || strstr(opts, ",ssd,")) + return true; + } + + return false; + } + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); + if (!udev_device) + return false; + + devtype = udev_device_get_property_value(udev_device, "DEVTYPE"); + if (devtype && streq(devtype, "partition")) + look_at = udev_device_get_parent(udev_device); + else + look_at = udev_device; + + if (!look_at) + return false; + + /* First, try high-level property */ + id = udev_device_get_property_value(look_at, "ID_SSD"); + if (id) + return streq(id, "1"); + + /* Second, try kernel attribute */ + rotational = udev_device_get_sysattr_value(look_at, "queue/rotational"); + if (rotational) + return streq(rotational, "0"); + + /* Finally, fallback to heuristics */ + look_at = udev_device_get_parent(look_at); + if (!look_at) + return false; + + model = udev_device_get_sysattr_value(look_at, "model"); + if (model) + return !!strstr(model, "SSD"); + + return false; +} + +int fs_on_read_only(const char *p) { + struct stat st; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL; + const char *read_only; + + assert(p); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return false; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev); + if (!udev_device) + return false; + + read_only = udev_device_get_sysattr_value(udev_device, "ro"); + if (read_only) + return streq(read_only, "1"); + + return false; +} + +bool enough_ram(void) { + struct sysinfo si; + + assert_se(sysinfo(&si) >= 0); + + /* Enable readahead only with at least 128MB memory */ + return si.totalram > 127 * 1024*1024 / si.mem_unit; +} + +static void mkdirs(void) { + if (mkdir("/run/systemd", 0755) && errno != EEXIST) + log_warning("Failed to create /run/systemd: %m"); + if (mkdir("/run/systemd/readahead", 0755) && errno != EEXIST) + log_warning("Failed to create /run/systemd: %m"); +} + +int open_inotify(void) { + int fd; + + fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); + if (fd < 0) { + log_error("Failed to create inotify handle: %m"); + return -errno; + } + + mkdirs(); + + if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) { + log_error("Failed to watch /run/systemd/readahead: %m"); + close_nointr_nofail(fd); + return -errno; + } + + return fd; +} + +ReadaheadShared *shared_get(void) { + int _cleanup_close_ fd = -1; + ReadaheadShared *m = NULL; + + mkdirs(); + + fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644); + if (fd < 0) { + log_error("Failed to create shared memory segment: %m"); + return NULL; + } + + if (ftruncate(fd, sizeof(ReadaheadShared)) < 0) { + log_error("Failed to truncate shared memory segment: %m"); + return NULL; + } + + m = mmap(NULL, sizeof(ReadaheadShared), PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); + if (m == MAP_FAILED) { + log_error("Failed to mmap shared memory segment: %m"); + return NULL; + } + + return m; +} + +/* We use 20K instead of the more human digestable 16K here. Why? + Simply so that it is more unlikely that users end up picking this + value too so that we can recognize better whether the user changed + the value while we had it temporarily bumped. */ +#define BUMP_REQUEST_NR (20*1024) + +int block_bump_request_nr(const char *p) { + struct stat st; + uint64_t u; + char *ap = NULL, *line = NULL; + int r; + dev_t d; + + assert(p); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return 0; + + d = st.st_dev; + block_get_whole_disk(d, &d); + + if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { + r= -ENOMEM; + goto finish; + } + + r = read_one_line_file(ap, &line); + if (r < 0) { + if (r == -ENOENT) + r = 0; + goto finish; + } + + r = safe_atou64(line, &u); + if (r >= 0 && u >= BUMP_REQUEST_NR) { + r = 0; + goto finish; + } + + free(line); + line = NULL; + + if (asprintf(&line, "%lu", (unsigned long) BUMP_REQUEST_NR) < 0) { + r = -ENOMEM; + goto finish; + } + + r = write_string_file(ap, line); + if (r < 0) + goto finish; + + log_info("Bumped block_nr parameter of %u:%u to %lu. This is a temporary hack and should be removed one day.", major(d), minor(d), (unsigned long) BUMP_REQUEST_NR); + r = 1; + +finish: + free(ap); + free(line); + + return r; +} + +int block_get_readahead(const char *p, uint64_t *bytes) { + struct stat st; + char *ap = NULL, *line = NULL; + int r; + dev_t d; + uint64_t u; + + assert(p); + assert(bytes); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return 0; + + d = st.st_dev; + block_get_whole_disk(d, &d); + + if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { + r = -ENOMEM; + goto finish; + } + + r = read_one_line_file(ap, &line); + if (r < 0) + goto finish; + + r = safe_atou64(line, &u); + if (r < 0) + goto finish; + + *bytes = u * 1024ULL; + +finish: + free(ap); + free(line); + + return r; +} + +int block_set_readahead(const char *p, uint64_t bytes) { + struct stat st; + char *ap = NULL, *line = NULL; + int r; + dev_t d; + + assert(p); + assert(bytes); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return 0; + + d = st.st_dev; + block_get_whole_disk(d, &d); + + if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { + r = -ENOMEM; + goto finish; + } + + if (asprintf(&line, "%llu", (unsigned long long) bytes / 1024ULL) < 0) { + r = -ENOMEM; + goto finish; + } + + r = write_string_file(ap, line); + if (r < 0) + goto finish; + +finish: + free(ap); + free(line); + + return r; +} diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h new file mode 100644 index 0000000..e6d7da9 --- /dev/null +++ b/src/readahead/readahead-common.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "macro.h" +#include "util.h" + +#define READAHEAD_FILE_SIZE_MAX (10*1024*1024) + +#define READAHEAD_PACK_FILE_VERSION ";VERSION=2\n" + +extern unsigned arg_files_max; +extern off_t arg_file_size_max; +extern usec_t arg_timeout; +#ifdef CONFIG_TIZEN +extern const char *arg_savedir; +#endif + +int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st); + +int fs_on_ssd(const char *p); +int fs_on_read_only(const char *p); + +bool enough_ram(void); + +int open_inotify(void); + +typedef struct ReadaheadShared { + pid_t collect; + pid_t replay; +} _packed_ ReadaheadShared; + +ReadaheadShared *shared_get(void); + +int block_bump_request_nr(const char *p); + +int block_get_readahead(const char *p, uint64_t *bytes); +int block_set_readahead(const char *p, uint64_t bytes); + +int main_collect(const char *root); +int main_replay(const char *root); +int main_analyze(const char *pack_path); diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c new file mode 100644 index 0000000..f16a77c --- /dev/null +++ b/src/readahead/readahead-replay.c @@ -0,0 +1,315 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "missing.h" +#include "util.h" +#include "set.h" +#include "ioprio.h" +#include "readahead-common.h" +#include "virt.h" + +static ReadaheadShared *shared = NULL; + +static int unpack_file(FILE *pack) { + char fn[PATH_MAX]; + int r = 0, fd = -1; + bool any = false; + struct stat st; + uint64_t inode; + + assert(pack); + + if (!fgets(fn, sizeof(fn), pack)) + return 0; + + char_array_0(fn); + truncate_nl(fn); + + fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) { + + if (errno != ENOENT && errno != EPERM && errno != EACCES && errno != ELOOP) + log_warning("open(%s) failed: %m", fn); + + } else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) { + close_nointr_nofail(fd); + fd = -1; + } + + if (fread(&inode, sizeof(inode), 1, pack) != 1) { + log_error("Premature end of pack file."); + r = -EIO; + goto finish; + } + + if (fd >= 0) { + /* If the inode changed the file got deleted, so just + * ignore this entry */ + if (st.st_ino != (uint64_t) inode) { + close_nointr_nofail(fd); + fd = -1; + } + } + + for (;;) { + uint32_t b, c; + + if (fread(&b, sizeof(b), 1, pack) != 1 || + fread(&c, sizeof(c), 1, pack) != 1) { + log_error("Premature end of pack file."); + r = -EIO; + goto finish; + } + + if (b == 0 && c == 0) + break; + + if (c <= b) { + log_error("Invalid pack file."); + r = -EIO; + goto finish; + } + + log_debug("%s: page %u to %u", fn, b, c); + + any = true; + + if (fd >= 0) + if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) { + log_warning("posix_fadvise() failed: %m"); + goto finish; + } + } + + if (!any && fd >= 0) { + /* if no range is encoded in the pack file this is + * intended to mean that the whole file shall be + * read */ + + if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) { + log_warning("posix_fadvise() failed: %m"); + goto finish; + } + } + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + +static int replay(const char *root) { + FILE *pack = NULL; + char line[LINE_MAX]; + int r = 0; + char *pack_fn = NULL; + int c; + bool on_ssd, ready = false; + int prio; + int inotify_fd = -1; + + assert(root); + + block_bump_request_nr(root); + +#ifndef CONFIG_TIZEN + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { +#else + if (asprintf(&pack_fn, "%s/.readahead", arg_savedir ? arg_savedir : root) < 0) { +#endif + r = log_oom(); + goto finish; + } + + pack = fopen(pack_fn, "re"); + if (!pack) { + if (errno == ENOENT) + log_debug("No pack file found."); + else { + log_error("Failed to open pack file: %m"); + r = -errno; + } + + goto finish; + } + + posix_fadvise(fileno(pack), 0, 0, POSIX_FADV_WILLNEED); + + if ((inotify_fd = open_inotify()) < 0) { + r = inotify_fd; + goto finish; + } + + if (!(fgets(line, sizeof(line), pack))) { + log_error("Premature end of pack file."); + r = -EIO; + goto finish; + } + + char_array_0(line); + + if (!streq(line, CANONICAL_HOST READAHEAD_PACK_FILE_VERSION)) { + log_debug("Pack file host or version type mismatch."); + goto finish; + } + + if ((c = getc(pack)) == EOF) { + log_debug("Premature end of pack file."); + r = -EIO; + goto finish; + } + + /* We do not retest SSD here, so that we can start replaying + * before udev is up.*/ + on_ssd = c == 'S'; + log_debug("On SSD: %s", yes_no(on_ssd)); + + if (on_ssd) + prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0); + else + /* We are not using RT here, since we'd starve IO that + we didn't record (which is for example blkid, since + its disk accesses go directly to the block device and + are thus not visible in fallocate) to death. However, + we do ask for an IO prio that is slightly higher than + the default (which is BE. 4) */ + prio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 2); + + if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), prio) < 0) + log_warning("Failed to set IDLE IO priority class: %m"); + + sd_notify(0, "STATUS=Replaying readahead data"); + + log_debug("Replaying..."); + + if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) { + log_debug("Got termination request"); + goto done; + } + + while (!feof(pack) && !ferror(pack)) { + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; + int k; + ssize_t n; + + if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { + if (errno != EINTR && errno != EAGAIN) { + log_error("Failed to read inotify event: %m"); + r = -errno; + goto finish; + } + } else { + struct inotify_event *e = (struct inotify_event*) inotify_buffer; + + while (n > 0) { + size_t step; + + if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) { + log_debug("Got termination request"); + goto done; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) n); + + e = (struct inotify_event*) ((uint8_t*) e + step); + n -= step; + } + } + + if ((k = unpack_file(pack)) < 0) { + r = k; + goto finish; + } + + if (!ready) { + /* We delay the ready notification until we + * queued at least one read */ + sd_notify(0, "READY=1"); + ready = true; + } + } + +done: + if (!ready) + sd_notify(0, "READY=1"); + + if (ferror(pack)) { + log_error("Failed to read pack file."); + r = -EIO; + goto finish; + } + + log_debug("Done."); + +finish: + if (pack) + fclose(pack); + + if (inotify_fd >= 0) + close_nointr_nofail(inotify_fd); + + free(pack_fn); + + return r; +} + +int main_replay(const char *root) { + + if (!root) + root = "/"; + + if (!enough_ram()) { + log_info("Disabling readahead replay due to low memory."); + return EXIT_SUCCESS; + } + + shared = shared_get(); + if (!shared) + return EXIT_FAILURE; + + shared->replay = getpid(); + __sync_synchronize(); + + if (replay(root) < 0) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/src/readahead/readahead.c b/src/readahead/readahead.c new file mode 100644 index 0000000..e317f9f --- /dev/null +++ b/src/readahead/readahead.c @@ -0,0 +1,188 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "def.h" +#include "build.h" +#include "readahead-common.h" + +unsigned arg_files_max = 16*1024; +off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX; +usec_t arg_timeout = 2*USEC_PER_MINUTE; +#ifdef CONFIG_TIZEN +const char *arg_savedir; +#endif + +static int help(void) { + + printf("%s [OPTIONS...] collect [DIRECTORY]\n\n" + "Collect read-ahead data on early boot.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" +#ifdef CONFIG_TIZEN + " --savedir=PATH Directory path to save collecting data\n" +#endif + " --max-files=INT Maximum number of files to read ahead\n" + " --file-size-max=BYTES Maximum size of files to read ahead\n" + " --timeout=USEC Maximum time to spend collecting data\n\n\n", + program_invocation_short_name); + + printf("%s [OPTIONS...] replay [DIRECTORY]\n\n" + "Replay collected read-ahead data on early boot.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" +#ifdef CONFIG_TIZEN + " --savedir=PATH Directory path to save collecting data\n" +#endif + " --file-size-max=BYTES Maximum size of files to read ahead\n\n\n", + program_invocation_short_name); + + printf("%s [OPTIONS...] analyze [PACK FILE]\n\n" + "Analyze collected read-ahead data.\n\n" + " -h --help Show this help\n" + " --version Show package version\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, +#ifdef CONFIG_TIZEN + ARG_SAVEDIR, +#endif + ARG_FILES_MAX, + ARG_FILE_SIZE_MAX, + ARG_TIMEOUT + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, +#ifdef CONFIG_TIZEN + { "savedir", required_argument, NULL, ARG_SAVEDIR }, +#endif + { "files-max", required_argument, NULL, ARG_FILES_MAX }, + { "file-size-max", required_argument, NULL, ARG_FILE_SIZE_MAX }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_FILES_MAX: + if (safe_atou(optarg, &arg_files_max) < 0 || arg_files_max <= 0) { + log_error("Failed to parse maximum number of files %s.", optarg); + return -EINVAL; + } + break; + + case ARG_FILE_SIZE_MAX: { + unsigned long long ull; + + if (safe_atollu(optarg, &ull) < 0 || ull <= 0) { + log_error("Failed to parse maximum file size %s.", optarg); + return -EINVAL; + } + + arg_file_size_max = (off_t) ull; + break; + } + + case ARG_TIMEOUT: + if (parse_sec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) { + log_error("Failed to parse timeout %s.", optarg); + return -EINVAL; + } + + break; + +#ifdef CONFIG_TIZEN + case ARG_SAVEDIR: + arg_savedir = optarg; + break; +#endif + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind != argc-1 && + optind != argc-2) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + if (streq(argv[optind], "collect")) + return main_collect(argv[optind+1]); + else if (streq(argv[optind], "replay")) + return main_replay(argv[optind+1]); + else if (streq(argv[optind], "analyze")) + return main_analyze(argv[optind+1]); + + log_error("Unknown verb %s.", argv[optind]); + return EXIT_FAILURE; +} diff --git a/src/readahead/sd-readahead.c b/src/readahead/sd-readahead.c new file mode 100644 index 0000000..675d82c --- /dev/null +++ b/src/readahead/sd-readahead.c @@ -0,0 +1,89 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + Copyright 2010 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "sd-readahead.h" + +#if (__GNUC__ >= 4) +# ifdef SD_EXPORT_SYMBOLS +/* Export symbols */ +# define _sd_export_ __attribute__ ((visibility("default"))) +# else +/* Don't export the symbols */ +# define _sd_export_ __attribute__ ((visibility("hidden"))) +# endif +#else +# define _sd_export_ +#endif + +static int touch(const char *path) { + +#if !defined(DISABLE_SYSTEMD) && defined(__linux__) + int fd; + + mkdir("/run/systemd", 0755); + mkdir("/run/systemd/readahead", 0755); + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666); + if (fd < 0) + return -errno; + + for (;;) { + if (close(fd) >= 0) + break; + + if (errno != EINTR) + return -errno; + } + +#endif + return 0; +} + +_sd_export_ int sd_readahead(const char *action) { + + if (!action) + return -EINVAL; + + if (strcmp(action, "cancel") == 0) + return touch("/run/systemd/readahead/cancel"); + else if (strcmp(action, "done") == 0) + return touch("/run/systemd/readahead/done"); + else if (strcmp(action, "noreplay") == 0) + return touch("/run/systemd/readahead/noreplay"); + + return -EINVAL; +} diff --git a/src/remount-api-vfs.c b/src/remount-api-vfs.c deleted file mode 100644 index 8bbc021..0000000 --- a/src/remount-api-vfs.c +++ /dev/null @@ -1,150 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "set.h" -#include "mount-setup.h" -#include "exit-status.h" - -/* Goes through /etc/fstab and remounts all API file systems, applying - * options that are in /etc/fstab that systemd might not have - * respected */ - -int main(int argc, char *argv[]) { - int ret = EXIT_FAILURE; - FILE *f = NULL; - struct mntent* me; - Hashmap *pids = NULL; - - if (argc > 1) { - log_error("This program takes no argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if (!(f = setmntent("/etc/fstab", "r"))) { - log_error("Failed to open /etc/fstab: %m"); - goto finish; - } - - if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { - log_error("Failed to allocate set"); - goto finish; - } - - ret = EXIT_SUCCESS; - - while ((me = getmntent(f))) { - pid_t pid; - int k; - char *s; - - if (!mount_point_is_api(me->mnt_dir)) - continue; - - log_debug("Remounting %s", me->mnt_dir); - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - ret = 1; - continue; - } - - if (pid == 0) { - const char *arguments[5]; - /* Child */ - - arguments[0] = "/bin/mount"; - arguments[1] = me->mnt_dir; - arguments[2] = "-o"; - arguments[3] = "remount"; - arguments[4] = NULL; - - execv("/bin/mount", (char **) arguments); - - log_error("Failed to execute /bin/mount: %m"); - _exit(EXIT_FAILURE); - } - - /* Parent */ - - s = strdup(me->mnt_dir); - - if ((k = hashmap_put(pids, UINT_TO_PTR(pid), s)) < 0) { - log_error("Failed to add PID to set: %s", strerror(-k)); - ret = EXIT_FAILURE; - continue; - } - } - - while (!hashmap_isempty(pids)) { - siginfo_t si; - char *s; - - zero(si); - if (waitid(P_ALL, 0, &si, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - log_error("waitid() failed: %m"); - ret = EXIT_FAILURE; - break; - } - - if ((s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { - if (!is_clean_exit(si.si_code, si.si_status)) { - if (si.si_code == CLD_EXITED) - log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status); - else - log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status)); - - ret = EXIT_FAILURE; - } - - free(s); - } - } - -finish: - - if (pids) - hashmap_free_free(pids); - - if (f) - endmntent(f); - - return ret; -} diff --git a/src/remount-fs/Makefile b/src/remount-fs/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/remount-fs/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c new file mode 100644 index 0000000..847637a --- /dev/null +++ b/src/remount-fs/remount-fs.c @@ -0,0 +1,164 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "path-util.h" +#include "set.h" +#include "mount-setup.h" +#include "exit-status.h" + +/* Goes through /etc/fstab and remounts all API file systems, applying + * options that are in /etc/fstab that systemd might not have + * respected */ + +int main(int argc, char *argv[]) { + int ret = EXIT_FAILURE; + _cleanup_endmntent_ FILE *f = NULL; + struct mntent* me; + Hashmap *pids = NULL; + + if (argc > 1) { + log_error("This program takes no argument."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + f = setmntent("/etc/fstab", "r"); + if (!f) { + if (errno == ENOENT) + return EXIT_SUCCESS; + + log_error("Failed to open /etc/fstab: %m"); + return EXIT_FAILURE; + } + + pids = hashmap_new(trivial_hash_func, trivial_compare_func); + if (!pids) { + log_error("Failed to allocate set"); + goto finish; + } + + ret = EXIT_SUCCESS; + + while ((me = getmntent(f))) { + pid_t pid; + int k; + char *s; + + /* Remount the root fs, /usr and all API VFS */ + if (!mount_point_is_api(me->mnt_dir) && + !path_equal(me->mnt_dir, "/") && + !path_equal(me->mnt_dir, "/usr")) + continue; + + log_debug("Remounting %s", me->mnt_dir); + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + ret = EXIT_FAILURE; + continue; + } + + if (pid == 0) { + const char *arguments[5]; + /* Child */ + + arguments[0] = "/bin/mount"; + arguments[1] = me->mnt_dir; + arguments[2] = "-o"; + arguments[3] = "remount"; + arguments[4] = NULL; + + execv("/bin/mount", (char **) arguments); + + log_error("Failed to execute /bin/mount: %m"); + _exit(EXIT_FAILURE); + } + + /* Parent */ + + s = strdup(me->mnt_dir); + if (!s) { + log_oom(); + ret = EXIT_FAILURE; + continue; + } + + + k = hashmap_put(pids, UINT_TO_PTR(pid), s); + if (k < 0) { + log_error("Failed to add PID to set: %s", strerror(-k)); + ret = EXIT_FAILURE; + continue; + } + } + + while (!hashmap_isempty(pids)) { + siginfo_t si = {}; + char *s; + + if (waitid(P_ALL, 0, &si, WEXITED) < 0) { + + if (errno == EINTR) + continue; + + log_error("waitid() failed: %m"); + ret = EXIT_FAILURE; + break; + } + + s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)); + if (s) { + if (!is_clean_exit(si.si_code, si.si_status, NULL)) { + if (si.si_code == CLD_EXITED) + log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status); + else + log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status)); + + ret = EXIT_FAILURE; + } + + free(s); + } + } + +finish: + + if (pids) + hashmap_free_free(pids); + + return ret; +} diff --git a/src/reply-password.c b/src/reply-password.c deleted file mode 100644 index bd55e65..0000000 --- a/src/reply-password.c +++ /dev/null @@ -1,109 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "macro.h" -#include "util.h" - -static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - - assert(fd >= 0); - assert(socket_name); - assert(packet); - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - - if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { - log_error("Failed to send: %m"); - return -1; - } - - return 0; -} - -int main(int argc, char *argv[]) { - int fd = -1, r = EXIT_FAILURE; - char packet[LINE_MAX]; - size_t length; - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - if (argc != 3) { - log_error("Wrong number of arguments."); - goto finish; - } - - if (streq(argv[1], "1")) { - - packet[0] = '+'; - if (!fgets(packet+1, sizeof(packet)-1, stdin)) { - log_error("Failed to read password: %m"); - goto finish; - } - - truncate_nl(packet+1); - length = 1 + strlen(packet+1) + 1; - } else if (streq(argv[1], "0")) { - packet[0] = '-'; - length = 1; - } else { - log_error("Invalid first argument %s", argv[1]); - goto finish; - } - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("socket() failed: %m"); - goto finish; - } - - if (send_on_socket(fd, argv[2], packet, length) < 0) - goto finish; - - r = EXIT_SUCCESS; - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} diff --git a/src/reply-password/Makefile b/src/reply-password/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/reply-password/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c new file mode 100644 index 0000000..2f16898 --- /dev/null +++ b/src/reply-password/reply-password.c @@ -0,0 +1,109 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" + +static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa = { + .un.sun_family = AF_UNIX, + }; + + assert(fd >= 0); + assert(socket_name); + assert(packet); + + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); + + if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { + log_error("Failed to send: %m"); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) { + int fd = -1, r = EXIT_FAILURE; + char packet[LINE_MAX]; + size_t length; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + if (argc != 3) { + log_error("Wrong number of arguments."); + goto finish; + } + + if (streq(argv[1], "1")) { + + packet[0] = '+'; + if (!fgets(packet+1, sizeof(packet)-1, stdin)) { + log_error("Failed to read password: %m"); + goto finish; + } + + truncate_nl(packet+1); + length = 1 + strlen(packet+1) + 1; + } else if (streq(argv[1], "0")) { + packet[0] = '-'; + length = 1; + } else { + log_error("Invalid first argument %s", argv[1]); + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + log_error("socket() failed: %m"); + goto finish; + } + + if (send_on_socket(fd, argv[2], packet, length) < 0) + goto finish; + + r = EXIT_SUCCESS; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} diff --git a/src/rfkill/Makefile b/src/rfkill/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/rfkill/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c new file mode 100644 index 0000000..c7c6592 --- /dev/null +++ b/src/rfkill/rfkill.c @@ -0,0 +1,141 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "mkdir.h" +#include "fileio.h" +#include "libudev.h" +#include "udev-util.h" + +int main(int argc, char *argv[]) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + _cleanup_free_ char *saved = NULL, *escaped_name = NULL, *escaped_path_id = NULL; + const char *name, *path_id; + int r; + + if (argc != 3) { + log_error("This program requires two arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + r = mkdir_p("/var/lib/systemd/rfkill", 0755); + if (r < 0) { + log_error("Failed to create rfkill directory: %s", strerror(-r)); + return EXIT_FAILURE; + } + + udev = udev_new(); + if (!udev) { + log_oom(); + return EXIT_FAILURE; + } + + errno = 0; + device = udev_device_new_from_subsystem_sysname(udev, "rfkill", argv[2]); + if (!device) { + if (errno != 0) + log_error("Failed to get rfkill device '%s': %m", argv[2]); + else + log_oom(); + + return EXIT_FAILURE; + } + + name = udev_device_get_sysattr_value(device, "name"); + if (!name) { + log_error("rfkill device has no name?"); + return EXIT_FAILURE; + } + + escaped_name = cescape(name); + if (!escaped_name) { + log_oom(); + return EXIT_FAILURE; + } + + path_id = udev_device_get_property_value(device, "ID_PATH"); + if (path_id) { + escaped_path_id = cescape(path_id); + if (!escaped_path_id) { + log_oom(); + return EXIT_FAILURE; + } + + saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_name, NULL); + } else + saved = strjoin("/var/lib/systemd/rfkill/", escaped_name, NULL); + + if (!saved) { + log_oom(); + return EXIT_FAILURE; + } + + if (streq(argv[1], "load")) { + _cleanup_free_ char *value = NULL; + + if (!shall_restore_state()) + return EXIT_SUCCESS; + + r = read_one_line_file(saved, &value); + if (r < 0) { + + if (r == -ENOENT) + return EXIT_SUCCESS; + + log_error("Failed to read %s: %s", saved, strerror(-r)); + return EXIT_FAILURE; + } + + r = udev_device_set_sysattr_value(device, "soft", value); + if (r < 0) { + log_error("Failed to write system attribute: %s", strerror(-r)); + return EXIT_FAILURE; + } + + } else if (streq(argv[1], "save")) { + const char *value; + + value = udev_device_get_sysattr_value(device, "soft"); + if (!value) { + log_error("Failed to read system attribute: %s", strerror(-r)); + return EXIT_FAILURE; + } + + r = write_string_file(saved, value); + if (r < 0) { + log_error("Failed to write %s: %s", saved, strerror(-r)); + return EXIT_FAILURE; + } + + } else { + log_error("Unknown verb %s.", argv[1]); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/run/Makefile b/src/run/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/run/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/run/run.c b/src/run/run.c new file mode 100644 index 0000000..885d881 --- /dev/null +++ b/src/run/run.c @@ -0,0 +1,508 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "strv.h" +#include "build.h" +#include "unit-name.h" +#include "path-util.h" +#include "bus-error.h" + +static bool arg_scope = false; +static bool arg_remain_after_exit = false; +static const char *arg_unit = NULL; +static const char *arg_description = NULL; +static const char *arg_slice = NULL; +static bool arg_send_sighup = false; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_user = false; +static const char *arg_service_type = NULL; +static const char *arg_exec_user = NULL; +static const char *arg_exec_group = NULL; +static int arg_nice = 0; +static bool arg_nice_set = false; +static char **arg_environment = NULL; + +static int help(void) { + + printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n" + "Run the specified command in a transient scope or service unit.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --user Run as user unit\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --scope Run this as scope rather than service\n" + " --unit=UNIT Run under the specified unit name\n" + " --description=TEXT Description for unit\n" + " --slice=SLICE Run in the specified slice\n" + " -r --remain-after-exit Leave service around until explicitly stopped\n" + " --send-sighup Send SIGHUP when terminating\n" + " --service-type=TYPE Service type\n" + " --uid=USER Run as system user\n" + " --gid=GROUP Run as system group\n" + " --nice=NICE Nice level\n" + " --setenv=NAME=VALUE Set environment\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_USER, + ARG_SYSTEM, + ARG_SCOPE, + ARG_UNIT, + ARG_DESCRIPTION, + ARG_SLICE, + ARG_SEND_SIGHUP, + ARG_EXEC_USER, + ARG_EXEC_GROUP, + ARG_SERVICE_TYPE, + ARG_NICE, + ARG_SETENV + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "scope", no_argument, NULL, ARG_SCOPE }, + { "unit", required_argument, NULL, ARG_UNIT }, + { "description", required_argument, NULL, ARG_DESCRIPTION }, + { "slice", required_argument, NULL, ARG_SLICE }, + { "remain-after-exit", no_argument, NULL, 'r' }, + { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "service-type", required_argument, NULL, ARG_SERVICE_TYPE }, + { "uid", required_argument, NULL, ARG_EXEC_USER }, + { "gid", required_argument, NULL, ARG_EXEC_GROUP }, + { "nice", required_argument, NULL, ARG_NICE }, + { "setenv", required_argument, NULL, ARG_SETENV }, + {}, + }; + + int r, c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+hrH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_USER: + arg_user = true; + break; + + case ARG_SYSTEM: + arg_user = false; + break; + + case ARG_SCOPE: + arg_scope = true; + break; + + case ARG_UNIT: + arg_unit = optarg; + break; + + case ARG_DESCRIPTION: + arg_description = optarg; + break; + + case ARG_SLICE: + arg_slice = optarg; + break; + + case ARG_SEND_SIGHUP: + arg_send_sighup = true; + break; + + case 'r': + arg_remain_after_exit = true; + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case ARG_SERVICE_TYPE: + arg_service_type = optarg; + break; + + case ARG_EXEC_USER: + arg_exec_user = optarg; + break; + + case ARG_EXEC_GROUP: + arg_exec_group = optarg; + break; + + case ARG_NICE: + r = safe_atoi(optarg, &arg_nice); + if (r < 0) { + log_error("Failed to parse nice value"); + return -EINVAL; + } + + arg_nice_set = true; + break; + + case ARG_SETENV: + + if (strv_extend(&arg_environment, optarg) < 0) + return log_oom(); + + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind >= argc) { + log_error("Command line to execute required."); + return -EINVAL; + } + + if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Execution in user context is not supported on non-local systems."); + return -EINVAL; + } + + if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Scope execution is not supported on non-local systems."); + return -EINVAL; + } + + if (arg_scope && (arg_remain_after_exit || arg_service_type || arg_exec_user || arg_exec_group || arg_nice_set || arg_environment)) { + log_error("--remain-after-exit, --service-type=, --user=, --group=, --nice= and --setenv= are not supported in --scope mode."); + return -EINVAL; + } + + return 1; +} + +static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + assert(name); + assert(ret); + + log_info("Running as unit %s.", name); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "ss", name, "fail"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description); + if (r < 0) + return r; + + if (!isempty(arg_slice)) { + _cleanup_free_ char *slice; + + slice = unit_name_mangle_with_suffix(arg_slice, MANGLE_NOGLOB, ".slice"); + if (!slice) + return -ENOMEM; + + r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); + if (r < 0) + return r; + } + + r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup); + if (r < 0) + return r; + + *ret = m; + m = NULL; + + return 0; +} + +static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) { + int r; + + assert(bus); + assert(m); + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "a(sa(sv))", 0); + if (r < 0) + return r; + + return sd_bus_call(bus, m, 0, error, reply); +} + +static int start_transient_service( + sd_bus *bus, + char **argv, + sd_bus_error *error) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *name = NULL; + int r; + + if (arg_unit) + name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service"); + else + asprintf(&name, "run-%lu.service", (unsigned long) getpid()); + if (!name) + return -ENOMEM; + + r = message_start_transient_unit_new(bus, name, &m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit); + if (r < 0) + return r; + + if (arg_service_type) { + r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type); + if (r < 0) + return r; + } + + if (arg_exec_user) { + r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user); + if (r < 0) + return r; + } + + if (arg_exec_group) { + r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group); + if (r < 0) + return r; + } + + if (arg_nice_set) { + r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice); + if (r < 0) + return r; + } + + if (!strv_isempty(arg_environment)) { + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "s", "Environment"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(m, arg_environment); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + } + + r = sd_bus_message_open_container(m, 'r', "sv"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "s", "ExecStart"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'v', "a(sasb)"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "(sasb)"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'r', "sasb"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "s", argv[0]); + if (r < 0) + return r; + + r = sd_bus_message_append_strv(m, argv); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "b", false); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + return message_start_transient_unit_send(bus, m, error, NULL); +} + +static int start_transient_scope( + sd_bus *bus, + char **argv, + sd_bus_error *error) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_free_ char *name = NULL; + int r; + + assert(bus); + + if (arg_unit) + name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope"); + else + asprintf(&name, "run-%lu.scope", (unsigned long) getpid()); + if (!name) + return -ENOMEM; + + r = message_start_transient_unit_new(bus, name, &m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid()); + if (r < 0) + return r; + + r = message_start_transient_unit_send(bus, m, error, NULL); + if (r < 0) + return r; + + execvp(argv[0], argv); + log_error("Failed to execute: %m"); + return -errno; +} + +int main(int argc, char* argv[]) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_free_ char *description = NULL, *command = NULL; + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = find_binary(argv[optind], &command); + if (r < 0) { + log_error("Failed to find executable %s: %s", argv[optind], strerror(-r)); + goto finish; + } + argv[optind] = command; + + if (!arg_description) { + description = strv_join(argv + optind, " "); + if (!description) { + r = log_oom(); + goto finish; + } + + arg_description = description; + } + + r = bus_open_transport(arg_transport, arg_host, arg_user, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + if (arg_scope) + r = start_transient_scope(bus, argv + optind, &error); + else + r = start_transient_service(bus, argv + optind, &error); + if (r < 0) + log_error("Failed start transient unit: %s", bus_error_message(&error, r)); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/sd-daemon.c b/src/sd-daemon.c deleted file mode 100644 index e68b708..0000000 --- a/src/sd-daemon.c +++ /dev/null @@ -1,526 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - Copyright 2010 Lennart Poettering - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) -#include -#endif - -#include "sd-daemon.h" - -#if (__GNUC__ >= 4) -#ifdef SD_EXPORT_SYMBOLS -/* Export symbols */ -#define _sd_export_ __attribute__ ((visibility("default"))) -#else -/* Don't export the symbols */ -#define _sd_export_ __attribute__ ((visibility("hidden"))) -#endif -#else -#define _sd_export_ -#endif - -_sd_export_ int sd_listen_fds(int unset_environment) { - -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - int r, fd; - const char *e; - char *p = NULL; - unsigned long l; - - if (!(e = getenv("LISTEN_PID"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p || l <= 0) { - r = -EINVAL; - goto finish; - } - - /* Is this for us? */ - if (getpid() != (pid_t) l) { - r = 0; - goto finish; - } - - if (!(e = getenv("LISTEN_FDS"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p) { - r = -EINVAL; - goto finish; - } - - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { - int flags; - - if ((flags = fcntl(fd, F_GETFD)) < 0) { - r = -errno; - goto finish; - } - - if (flags & FD_CLOEXEC) - continue; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { - r = -errno; - goto finish; - } - } - - r = (int) l; - -finish: - if (unset_environment) { - unsetenv("LISTEN_PID"); - unsetenv("LISTEN_FDS"); - } - - return r; -#endif -} - -_sd_export_ int sd_is_fifo(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - memset(&st_fd, 0, sizeof(st_fd)); - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISFIFO(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - memset(&st_path, 0, sizeof(st_path)); - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - } - - return 1; -} - -_sd_export_ int sd_is_special(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) - return st_path.st_rdev == st_fd.st_rdev; - else - return 0; - } - - return 1; -} - -static int sd_is_socket_internal(int fd, int type, int listening) { - struct stat st_fd; - - if (fd < 0 || type < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISSOCK(st_fd.st_mode)) - return 0; - - if (type != 0) { - int other_type = 0; - socklen_t l = sizeof(other_type); - - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) - return -errno; - - if (l != sizeof(other_type)) - return -EINVAL; - - if (other_type != type) - return 0; - } - - if (listening >= 0) { - int accepting = 0; - socklen_t l = sizeof(accepting); - - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) - return -errno; - - if (l != sizeof(accepting)) - return -EINVAL; - - if (!accepting != !listening) - return 0; - } - - return 1; -} - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_storage storage; -}; - -_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { - int r; - - if (family < 0) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - if (family > 0) { - union sockaddr_union sockaddr; - socklen_t l; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - return sockaddr.sa.sa_family == family; - } - - return 1; -} - -_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if (family != 0 && family != AF_INET && family != AF_INET6) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_INET && - sockaddr.sa.sa_family != AF_INET6) - return 0; - - if (family > 0) - if (sockaddr.sa.sa_family != family) - return 0; - - if (port > 0) { - if (sockaddr.sa.sa_family == AF_INET) { - if (l < sizeof(struct sockaddr_in)) - return -EINVAL; - - return htons(port) == sockaddr.in4.sin_port; - } else { - if (l < sizeof(struct sockaddr_in6)) - return -EINVAL; - - return htons(port) == sockaddr.in6.sin6_port; - } - } - - return 1; -} - -_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_UNIX) - return 0; - - if (path) { - if (length <= 0) - length = strlen(path); - - if (length <= 0) - /* Unnamed socket */ - return l == offsetof(struct sockaddr_un, sun_path); - - if (path[0]) - /* Normal path socket */ - return - (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && - memcmp(path, sockaddr.un.sun_path, length+1) == 0; - else - /* Abstract namespace socket */ - return - (l == offsetof(struct sockaddr_un, sun_path) + length) && - memcmp(path, sockaddr.un.sun_path, length) == 0; - } - - return 1; -} - -_sd_export_ int sd_is_mq(int fd, const char *path) { -#if !defined(__linux__) - return 0; -#else - struct mq_attr attr; - - if (fd < 0) - return -EINVAL; - - if (mq_getattr(fd, &attr) < 0) - return -errno; - - if (path) { - char fpath[PATH_MAX]; - struct stat a, b; - - if (path[0] != '/') - return -EINVAL; - - if (fstat(fd, &a) < 0) - return -errno; - - strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); - fpath[sizeof(fpath)-1] = 0; - - if (stat(fpath, &b) < 0) - return -errno; - - if (a.st_dev != b.st_dev || - a.st_ino != b.st_ino) - return 0; - } - - return 1; -#endif -} - -_sd_export_ int sd_notify(int unset_environment, const char *state) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) - return 0; -#else - int fd = -1, r; - struct msghdr msghdr; - struct iovec iovec; - union sockaddr_union sockaddr; - const char *e; - - if (!state) { - r = -EINVAL; - goto finish; - } - - if (!(e = getenv("NOTIFY_SOCKET"))) - return 0; - - /* Must be an abstract socket, or an absolute path */ - if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { - r = -EINVAL; - goto finish; - } - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { - r = -errno; - goto finish; - } - - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sa.sa_family = AF_UNIX; - strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); - - if (sockaddr.un.sun_path[0] == '@') - sockaddr.un.sun_path[0] = 0; - - memset(&iovec, 0, sizeof(iovec)); - iovec.iov_base = (char*) state; - iovec.iov_len = strlen(state); - - memset(&msghdr, 0, sizeof(msghdr)); - msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); - - if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) - msghdr.msg_namelen = sizeof(struct sockaddr_un); - - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - - if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { - r = -errno; - goto finish; - } - - r = 1; - -finish: - if (unset_environment) - unsetenv("NOTIFY_SOCKET"); - - if (fd >= 0) - close(fd); - - return r; -#endif -} - -_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - va_list ap; - char *p = NULL; - int r; - - va_start(ap, format); - r = vasprintf(&p, format, ap); - va_end(ap); - - if (r < 0 || !p) - return -ENOMEM; - - r = sd_notify(unset_environment, p); - free(p); - - return r; -#endif -} - -_sd_export_ int sd_booted(void) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - - struct stat a, b; - - /* We simply test whether the systemd cgroup hierarchy is - * mounted */ - - if (lstat("/sys/fs/cgroup", &a) < 0) - return 0; - - if (lstat("/sys/fs/cgroup/systemd", &b) < 0) - return 0; - - return a.st_dev != b.st_dev; -#endif -} diff --git a/src/sd-daemon.h b/src/sd-daemon.h deleted file mode 100644 index 46dc7fd..0000000 --- a/src/sd-daemon.h +++ /dev/null @@ -1,277 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosddaemonhfoo -#define foosddaemonhfoo - -/*** - Copyright 2010 Lennart Poettering - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - Reference implementation of a few systemd related interfaces for - writing daemons. These interfaces are trivial to implement. To - simplify porting we provide this reference implementation. - Applications are welcome to reimplement the algorithms described - here if they do not want to include these two source files. - - The following functionality is provided: - - - Support for logging with log levels on stderr - - File descriptor passing for socket-based activation - - Daemon startup and status notification - - Detection of systemd boots - - You may compile this with -DDISABLE_SYSTEMD to disable systemd - support. This makes all those calls NOPs that are directly related to - systemd (i.e. only sd_is_xxx() will stay useful). - - Since this is drop-in code we don't want any of our symbols to be - exported in any case. Hence we declare hidden visibility for all of - them. - - You may find an up-to-date version of these source files online: - - http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h - http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c - - This should compile on non-Linux systems, too, but with the - exception of the sd_is_xxx() calls all functions will become NOPs. - - See sd-daemon(7) for more information. -*/ - -#ifndef _sd_printf_attr_ -#if __GNUC__ >= 4 -#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) -#else -#define _sd_printf_attr_(a,b) -#endif -#endif - -/* - Log levels for usage on stderr: - - fprintf(stderr, SD_NOTICE "Hello World!\n"); - - This is similar to printk() usage in the kernel. -*/ -#define SD_EMERG "<0>" /* system is unusable */ -#define SD_ALERT "<1>" /* action must be taken immediately */ -#define SD_CRIT "<2>" /* critical conditions */ -#define SD_ERR "<3>" /* error conditions */ -#define SD_WARNING "<4>" /* warning conditions */ -#define SD_NOTICE "<5>" /* normal but significant condition */ -#define SD_INFO "<6>" /* informational */ -#define SD_DEBUG "<7>" /* debug-level messages */ - -/* The first passed file descriptor is fd 3 */ -#define SD_LISTEN_FDS_START 3 - -/* - Returns how many file descriptors have been passed, or a negative - errno code on failure. Optionally, removes the $LISTEN_FDS and - $LISTEN_PID file descriptors from the environment (recommended, but - problematic in threaded environments). If r is the return value of - this function you'll find the file descriptors passed as fds - SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative - errno style error code on failure. This function call ensures that - the FD_CLOEXEC flag is set for the passed file descriptors, to make - sure they are not passed on to child processes. If FD_CLOEXEC shall - not be set, the caller needs to unset it after this call for all file - descriptors that are used. - - See sd_listen_fds(3) for more information. -*/ -int sd_listen_fds(int unset_environment); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is a FIFO in the file system stored under the - specified path, 0 otherwise. If path is NULL a path name check will - not be done and the call only verifies if the file descriptor - refers to a FIFO. Returns a negative errno style error code on - failure. - - See sd_is_fifo(3) for more information. -*/ -int sd_is_fifo(int fd, const char *path); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is a special character device on the file - system stored under the specified path, 0 otherwise. - If path is NULL a path name check will not be done and the call - only verifies if the file descriptor refers to a special character. - Returns a negative errno style error code on failure. - - See sd_is_special(3) for more information. -*/ -int sd_is_special(int fd, const char *path); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is a socket of the specified family (AF_INET, - ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If - family is 0 a socket family check will not be done. If type is 0 a - socket type check will not be done and the call only verifies if - the file descriptor refers to a socket. If listening is > 0 it is - verified that the socket is in listening mode. (i.e. listen() has - been called) If listening is == 0 it is verified that the socket is - not in listening mode. If listening is < 0 no listening mode check - is done. Returns a negative errno style error code on failure. - - See sd_is_socket(3) for more information. -*/ -int sd_is_socket(int fd, int family, int type, int listening); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is an Internet socket, of the specified family - (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, - SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version - check is not done. If type is 0 a socket type check will not be - done. If port is 0 a socket port check will not be done. The - listening flag is used the same way as in sd_is_socket(). Returns a - negative errno style error code on failure. - - See sd_is_socket_inet(3) for more information. -*/ -int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is an AF_UNIX socket of the specified type - (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 - a socket type check will not be done. If path is NULL a socket path - check will not be done. For normal AF_UNIX sockets set length to - 0. For abstract namespace sockets set length to the length of the - socket name (including the initial 0 byte), and pass the full - socket path in path (including the initial 0 byte). The listening - flag is used the same way as in sd_is_socket(). Returns a negative - errno style error code on failure. - - See sd_is_socket_unix(3) for more information. -*/ -int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length); - -/* - Helper call for identifying a passed file descriptor. Returns 1 if - the file descriptor is a POSIX Message Queue of the specified name, - 0 otherwise. If path is NULL a message queue name check is not - done. Returns a negative errno style error code on failure. -*/ -int sd_is_mq(int fd, const char *path); - -/* - Informs systemd about changed daemon state. This takes a number of - newline separated environment-style variable assignments in a - string. The following variables are known: - - READY=1 Tells systemd that daemon startup is finished (only - relevant for services of Type=notify). The passed - argument is a boolean "1" or "0". Since there is - little value in signaling non-readiness the only - value daemons should send is "READY=1". - - STATUS=... Passes a single-line status string back to systemd - that describes the daemon state. This is free-from - and can be used for various purposes: general state - feedback, fsck-like programs could pass completion - percentages and failing programs could pass a human - readable error message. Example: "STATUS=Completed - 66% of file system check..." - - ERRNO=... If a daemon fails, the errno-style error code, - formatted as string. Example: "ERRNO=2" for ENOENT. - - BUSERROR=... If a daemon fails, the D-Bus error-style error - code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" - - MAINPID=... The main pid of a daemon, in case systemd did not - fork off the process itself. Example: "MAINPID=4711" - - Daemons can choose to send additional variables. However, it is - recommended to prefix variable names not listed above with X_. - - Returns a negative errno-style error code on failure. Returns > 0 - if systemd could be notified, 0 if it couldn't possibly because - systemd is not running. - - Example: When a daemon finished starting up, it could issue this - call to notify systemd about it: - - sd_notify(0, "READY=1"); - - See sd_notifyf() for more complete examples. - - See sd_notify(3) for more information. -*/ -int sd_notify(int unset_environment, const char *state); - -/* - Similar to sd_notify() but takes a format string. - - Example 1: A daemon could send the following after initialization: - - sd_notifyf(0, "READY=1\n" - "STATUS=Processing requests...\n" - "MAINPID=%lu", - (unsigned long) getpid()); - - Example 2: A daemon could send the following shortly before - exiting, on failure: - - sd_notifyf(0, "STATUS=Failed to start up: %s\n" - "ERRNO=%i", - strerror(errno), - errno); - - See sd_notifyf(3) for more information. -*/ -int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3); - -/* - Returns > 0 if the system was booted with systemd. Returns < 0 on - error. Returns 0 if the system was not booted with systemd. Note - that all of the functions above handle non-systemd boots just - fine. You should NOT protect them with a call to this function. Also - note that this function checks whether the system, not the user - session is controlled by systemd. However the functions above work - for both user and system services. - - See sd_booted(3) for more information. -*/ -int sd_booted(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/sd-login.c b/src/sd-login.c deleted file mode 100644 index a0a56c4..0000000 --- a/src/sd-login.c +++ /dev/null @@ -1,726 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "cgroup-util.h" -#include "macro.h" -#include "sd-login.h" -#include "strv.h" - -static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) { - char *cg_process, *cg_init, *p; - int r; - - if (pid == 0) - pid = getpid(); - - if (pid <= 0) - return -EINVAL; - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); - if (r < 0) - return r; - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); - if (r < 0) { - free(cg_process); - return r; - } - - if (endswith(cg_init, "/system")) - cg_init[strlen(cg_init)-7] = 0; - else if (streq(cg_init, "/")) - cg_init[0] = 0; - - if (startswith(cg_process, cg_init)) - p = cg_process + strlen(cg_init); - else - p = cg_process; - - free(cg_init); - - if (cgroup) { - char* c; - - c = strdup(p); - if (!c) { - free(cg_process); - return -ENOMEM; - } - - *cgroup = c; - } - - if (root) { - cg_process[p-cg_process] = 0; - *root = cg_process; - } else - free(cg_process); - - return 0; -} - -_public_ int sd_pid_get_session(pid_t pid, char **session) { - int r; - char *cgroup, *p; - - if (!session) - return -EINVAL; - - r = pid_get_cgroup(pid, NULL, &cgroup); - if (r < 0) - return r; - - if (!startswith(cgroup, "/user/")) { - free(cgroup); - return -ENOENT; - } - - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } - - p++; - if (startswith(p, "shared/") || streq(p, "shared")) { - free(cgroup); - return -ENOENT; - } - - p = strndup(p, strcspn(p, "/")); - free(cgroup); - - if (!p) - return -ENOMEM; - - *session = p; - return 0; -} - -_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { - int r; - char *root, *cgroup, *p, *cc; - struct stat st; - - if (!uid) - return -EINVAL; - - r = pid_get_cgroup(pid, &root, &cgroup); - if (r < 0) - return r; - - if (!startswith(cgroup, "/user/")) { - free(cgroup); - free(root); - return -ENOENT; - } - - p = strchr(cgroup + 6, '/'); - if (!p) { - free(cgroup); - return -ENOENT; - } - - p++; - p += strcspn(p, "/"); - *p = 0; - - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc); - free(root); - free(cgroup); - - if (r < 0) - return -ENOMEM; - - r = lstat(cc, &st); - free(cc); - - if (r < 0) - return -errno; - - if (!S_ISDIR(st.st_mode)) - return -ENOTDIR; - - *uid = st.st_uid; - return 0; -} - -_public_ int sd_uid_get_state(uid_t uid, char**state) { - char *p, *s = NULL; - int r; - - if (!state) - return -EINVAL; - - if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); - free(p); - - if (r == -ENOENT) { - free(s); - s = strdup("offline"); - if (!s) - return -ENOMEM; - - *state = s; - return 0; - } else if (r < 0) { - free(s); - return r; - } else if (!s) - return -EIO; - - *state = s; - return 0; -} - -_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { - char *p, *w, *t, *state, *s = NULL; - size_t l; - int r; - const char *variable; - - if (!seat) - return -EINVAL; - - variable = require_active ? "ACTIVE_UID" : "UIDS"; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, variable, &s, NULL); - free(p); - - if (r < 0) { - free(s); - return r; - } - - if (!s) - return -EIO; - - if (asprintf(&t, "%lu", (unsigned long) uid) < 0) { - free(s); - return -ENOMEM; - } - - FOREACH_WORD(w, l, s, state) { - if (strncmp(t, w, l) == 0) { - free(s); - free(t); - - return 1; - } - } - - free(s); - free(t); - - return 0; -} - -static int uid_get_array(uid_t uid, const char *variable, char ***array) { - char *p, *s = NULL; - char **a; - int r; - - if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, - variable, &s, - NULL); - free(p); - - if (r < 0) { - free(s); - - if (r == -ENOENT) { - if (array) - *array = NULL; - return 0; - } - - return r; - } - - if (!s) { - if (array) - *array = NULL; - return 0; - } - - a = strv_split(s, " "); - free(s); - - if (!a) - return -ENOMEM; - - strv_uniq(a); - r = strv_length(a); - - if (array) - *array = a; - else - strv_free(a); - - return r; -} - -_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) { - return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions); -} - -_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) { - return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats); -} - -_public_ int sd_session_is_active(const char *session) { - int r; - char *p, *s = NULL; - - if (!session) - return -EINVAL; - - p = strappend("/run/systemd/sessions/", session); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); - free(p); - - if (r < 0) { - free(s); - return r; - } - - if (!s) - return -EIO; - - r = parse_boolean(s); - free(s); - - return r; -} - -_public_ int sd_session_get_uid(const char *session, uid_t *uid) { - int r; - char *p, *s = NULL; - - if (!session) - return -EINVAL; - if (!uid) - return -EINVAL; - - p = strappend("/run/systemd/sessions/", session); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "UID", &s, NULL); - free(p); - - if (r < 0) { - free(s); - return r; - } - - if (!s) - return -EIO; - - r = parse_uid(s, uid); - free(s); - - return r; -} - -_public_ int sd_session_get_seat(const char *session, char **seat) { - char *p, *s = NULL; - int r; - - if (!session) - return -EINVAL; - if (!seat) - return -EINVAL; - - p = strappend("/run/systemd/sessions/", session); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "SEAT", &s, NULL); - free(p); - - if (r < 0) { - free(s); - return r; - } - - if (isempty(s)) - return -ENOENT; - - *seat = s; - return 0; -} - -_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { - char *p, *s = NULL, *t = NULL; - int r; - - if (!seat) - return -EINVAL; - if (!session && !uid) - return -EINVAL; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, - "ACTIVE", &s, - "ACTIVE_UID", &t, - NULL); - free(p); - - if (r < 0) { - free(s); - free(t); - return r; - } - - if (session && !s) { - free(t); - return -ENOENT; - } - - if (uid && !t) { - free(s); - return -ENOENT; - } - - if (uid && t) { - r = parse_uid(t, uid); - if (r < 0) { - free(t); - free(s); - return r; - } - } - - free(t); - - if (session && s) - *session = s; - else - free(s); - - return 0; -} - -_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) { - char *p, *s = NULL, *t = NULL, **a = NULL; - uid_t *b = NULL; - unsigned n = 0; - int r; - - if (!seat) - return -EINVAL; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, - "SESSIONS", &s, - "ACTIVE_SESSIONS", &t, - NULL); - free(p); - - if (r < 0) { - free(s); - free(t); - return r; - } - - if (s) { - a = strv_split(s, " "); - if (!a) { - free(s); - free(t); - return -ENOMEM; - } - } - - free(s); - - if (uids && t) { - char *w, *state; - size_t l; - - FOREACH_WORD(w, l, t, state) - n++; - - if (n == 0) - b = NULL; - else { - unsigned i = 0; - - b = new(uid_t, n); - if (!b) { - strv_free(a); - return -ENOMEM; - } - - FOREACH_WORD(w, l, t, state) { - char *k; - - k = strndup(w, l); - if (!k) { - free(t); - free(b); - strv_free(a); - return -ENOMEM; - } - - r = parse_uid(k, b + i); - free(k); - if (r < 0) - continue; - - i++; - } - } - } - - free(t); - - r = strv_length(a); - - if (sessions) - *sessions = a; - else - strv_free(a); - - if (uids) - *uids = b; - - if (n_uids) - *n_uids = n; - - return r; -} - -_public_ int sd_seat_can_multi_session(const char *seat) { - char *p, *s = NULL; - int r; - - if (!seat) - return -EINVAL; - - p = strappend("/run/systemd/seats/", seat); - if (!p) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, - "IS_VTCONSOLE", &s, - NULL); - free(p); - - if (r < 0) { - free(s); - return r; - } - - if (s) { - r = parse_boolean(s); - free(s); - } else - r = 0; - - return r; -} - -_public_ int sd_get_seats(char ***seats) { - return get_files_in_directory("/run/systemd/seats/", seats); -} - -_public_ int sd_get_sessions(char ***sessions) { - return get_files_in_directory("/run/systemd/sessions/", sessions); -} - -_public_ int sd_get_uids(uid_t **users) { - DIR *d; - int r = 0; - unsigned n = 0; - uid_t *l = NULL; - - d = opendir("/run/systemd/users/"); - if (!d) - return -errno; - - for (;;) { - struct dirent buffer, *de; - int k; - uid_t uid; - - k = readdir_r(d, &buffer, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - k = parse_uid(de->d_name, &uid); - if (k < 0) - continue; - - if (users) { - if ((unsigned) r >= n) { - uid_t *t; - - n = MAX(16, 2*r); - t = realloc(l, sizeof(uid_t) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } - - l = t; - } - - assert((unsigned) r < n); - l[r++] = uid; - } else - r++; - } - -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (users) - *users = l; - } else - free(l); - - return r; -} - -static inline int MONITOR_TO_FD(sd_login_monitor *m) { - return (int) (unsigned long) m - 1; -} - -static inline sd_login_monitor* FD_TO_MONITOR(int fd) { - return (sd_login_monitor*) (unsigned long) (fd + 1); -} - -_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { - int fd, k; - bool good = false; - - if (!m) - return -EINVAL; - - fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); - if (fd < 0) - return errno; - - if (!category || streq(category, "seat")) { - k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); - if (k < 0) { - close_nointr_nofail(fd); - return -errno; - } - - good = true; - } - - if (!category || streq(category, "session")) { - k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE); - if (k < 0) { - close_nointr_nofail(fd); - return -errno; - } - - good = true; - } - - if (!category || streq(category, "uid")) { - k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE); - if (k < 0) { - close_nointr_nofail(fd); - return -errno; - } - - good = true; - } - - if (!good) { - close_nointr(fd); - return -EINVAL; - } - - *m = FD_TO_MONITOR(fd); - return 0; -} - -_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { - int fd; - - if (!m) - return NULL; - - fd = MONITOR_TO_FD(m); - close_nointr(fd); - - return NULL; -} - -_public_ int sd_login_monitor_flush(sd_login_monitor *m) { - - if (!m) - return -EINVAL; - - return flush_fd(MONITOR_TO_FD(m)); -} - -_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { - - if (!m) - return -EINVAL; - - return MONITOR_TO_FD(m); -} diff --git a/src/sd-login.h b/src/sd-login.h deleted file mode 100644 index 0cb0bf0..0000000 --- a/src/sd-login.h +++ /dev/null @@ -1,121 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdloginhfoo -#define foosdloginhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -/* - * A few points: - * - * Instead of returning an empty string array or empty uid array, we - * may return NULL. - * - * Free the data we return with libc free(). - * - * We return error codes as negative errno, kernel-style. 0 or - * positive on success. - * - * These functions access data in /proc, /sys/fs/cgroup and /run. All - * of these are virtual file systems, hence the accesses are - * relatively cheap. - */ - -/* Get session from PID. Note that 'shared' processes of a user are - * not attached to a session, but only attached to a user. This will - * return an error for system processes and 'shared' processes of a - * user. */ -int sd_pid_get_session(pid_t pid, char **session); - -/* Get UID of the owner of the session of the PID (or in case the - * process is a 'shared' user process the UID of that user is - * returned). This will not return the UID of the process, but rather - * the UID of the owner of the cgroup the process is in. This will - * return an error for system processes. */ -int sd_pid_get_owner_uid(pid_t pid, uid_t *uid); - -/* Get state from uid. Possible states: offline, lingering, online, active */ -int sd_uid_get_state(uid_t uid, char**state); - -/* Return 1 if uid has session on seat. If require_active is true will - * look for active sessions only. */ -int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat); - -/* Return sessions of user. If require_active is true will look for - * active sessions only. Returns number of sessions as return - * value. If sessions is NULL will just return number of sessions. */ -int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions); - -/* Return seats of user is on. If require_active is true will look for - * active seats only. Returns number of seats. If seats is NULL will - * just return number of seats.*/ -int sd_uid_get_seats(uid_t uid, int require_active, char ***seats); - -/* Return 1 if the session is a active */ -int sd_session_is_active(const char *session); - -/* Determine user id of session */ -int sd_session_get_uid(const char *session, uid_t *uid); - -/* Determine seat of session */ -int sd_session_get_seat(const char *session, char **seat); - -/* Return active session and user of seat */ -int sd_seat_get_active(const char *seat, char **session, uid_t *uid); - -/* Return sessions and users on seat. Returns number of sessions as - * return value. If sessions is NULL returns only the number of - * sessions. */ -int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids); - -/* Return whether the seat is multi-session capable */ -int sd_seat_can_multi_session(const char *seat); - -/* Get all seats, store in *seats. Returns the number of seats. If - * seats is NULL only returns number of seats. */ -int sd_get_seats(char ***seats); - -/* Get all sessions, store in *sessions. Returns the number of - * sessions. If sessions is NULL only returns number of sessions. */ -int sd_get_sessions(char ***sessions); - -/* Get all logged in users, store in *users. Returns the number of - * users. If users is NULL only returns the number of users. */ -int sd_get_uids(uid_t **users); - -/* Monitor object */ -typedef struct sd_login_monitor sd_login_monitor; - -/* Create a new monitor. Category must be NULL, "seat", "session", - * "uid" to get monitor events for the specific category (or all). */ -int sd_login_monitor_new(const char *category, sd_login_monitor** ret); - -/* Destroys the passed monitor. Returns NULL. */ -sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m); - -/* Flushes the monitor */ -int sd_login_monitor_flush(sd_login_monitor *m); - -/* Get FD from monitor */ -int sd_login_monitor_get_fd(sd_login_monitor *m); - -#endif diff --git a/src/sd-readahead.c b/src/sd-readahead.c deleted file mode 100644 index c5cfe67..0000000 --- a/src/sd-readahead.c +++ /dev/null @@ -1,76 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - Copyright 2010 Lennart Poettering - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include - -#include "sd-readahead.h" - -static int touch(const char *path) { - -#if !defined(DISABLE_SYSTEMD) && defined(__linux__) - int fd; - - mkdir("/run/systemd", 0755); - mkdir("/run/systemd/readahead", 0755); - - if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0) - return -errno; - - for (;;) { - if (close(fd) >= 0) - break; - - if (errno != -EINTR) - return -errno; - } - -#endif - return 0; -} - -int sd_readahead(const char *action) { - - if (!action) - return -EINVAL; - - if (strcmp(action, "cancel") == 0) - return touch("/run/systemd/readahead/cancel"); - else if (strcmp(action, "done") == 0) - return touch("/run/systemd/readahead/done"); - else if (strcmp(action, "noreplay") == 0) - return touch("/run/systemd/readahead/noreplay"); - - return -EINVAL; -} diff --git a/src/sd-readahead.h b/src/sd-readahead.h deleted file mode 100644 index 5bf975a..0000000 --- a/src/sd-readahead.h +++ /dev/null @@ -1,81 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdreadaheadhfoo -#define foosdreadaheadhfoo - -/*** - Copyright 2010 Lennart Poettering - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - Reference implementation of a few boot readahead related - interfaces. These interfaces are trivial to implement. To simplify - porting we provide this reference implementation. Applications are - welcome to reimplement the algorithms described here if they do not - want to include these two source files. - - You may compile this with -DDISABLE_SYSTEMD to disable systemd - support. This makes all calls NOPs. - - Since this is drop-in code we don't want any of our symbols to be - exported in any case. Hence we declare hidden visibility for all of - them. - - You may find an up-to-date version of these source files online: - - http://cgit.freedesktop.org/systemd/plain/src/sd-readahead.h - http://cgit.freedesktop.org/systemd/plain/src/sd-readahead.c - - This should compile on non-Linux systems, too, but all functions - will become NOPs. - - See sd-readahead(7) for more information. -*/ - -#ifndef _sd_hidden_ -#if (__GNUC__ >= 4) && !defined(SD_EXPORT_SYMBOLS) -#define _sd_hidden_ __attribute__ ((visibility("hidden"))) -#else -#define _sd_hidden_ -#endif -#endif - -/* - Controls ongoing disk read-ahead operations during boot-up. The argument - must be a string, and either "cancel", "done" or "noreplay". - - cancel = terminate read-ahead data collection, drop collected information - done = terminate read-ahead data collection, keep collected information - noreplay = terminate read-ahead replay -*/ -int sd_readahead(const char *action) _sd_hidden_; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/securebits.h b/src/securebits.h deleted file mode 100644 index ba0bba5..0000000 --- a/src/securebits.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _LINUX_SECUREBITS_H -#define _LINUX_SECUREBITS_H 1 - -/* This is minimal version of Linux' linux/securebits.h header file, - * which is licensed GPL2 */ - -#define SECUREBITS_DEFAULT 0x00000000 - -/* When set UID 0 has no special privileges. When unset, we support - inheritance of root-permissions and suid-root executable under - compatibility mode. We raise the effective and inheritable bitmasks - *of the executable file* if the effective uid of the new process is - 0. If the real uid is 0, we raise the effective (legacy) bit of the - executable file. */ -#define SECURE_NOROOT 0 -#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ - -/* When set, setuid to/from uid 0 does not trigger capability-"fixup". - When unset, to provide compatibility with old programs relying on - set*uid to gain/lose privilege, transitions to/from uid 0 cause - capabilities to be gained/lost. */ -#define SECURE_NO_SETUID_FIXUP 2 -#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ - -/* When set, a process can retain its capabilities even after - transitioning to a non-root user (the set-uid fixup suppressed by - bit 2). Bit-4 is cleared when a process calls exec(); setting both - bit 4 and 5 will create a barrier through exec that no exec()'d - child can use this feature again. */ -#define SECURE_KEEP_CAPS 4 -#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ - -/* Each securesetting is implemented using two bits. One bit specifies - whether the setting is on or off. The other bit specify whether the - setting is locked or not. A setting which is locked cannot be - changed from user-level. */ -#define issecure_mask(X) (1 << (X)) -#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits)) - -#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ - issecure_mask(SECURE_NO_SETUID_FIXUP) | \ - issecure_mask(SECURE_KEEP_CAPS)) -#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) - -#endif /* !_LINUX_SECUREBITS_H */ diff --git a/src/selinux-setup.c b/src/selinux-setup.c deleted file mode 100644 index a7e1fa4..0000000 --- a/src/selinux-setup.c +++ /dev/null @@ -1,112 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#ifdef HAVE_SELINUX -#include -#endif - -#include "selinux-setup.h" -#include "mount-setup.h" -#include "macro.h" -#include "util.h" -#include "log.h" -#include "label.h" - -int selinux_setup(bool *loaded_policy) { - -#ifdef HAVE_SELINUX - int enforce = 0; - usec_t before_load, after_load; - security_context_t con; - int r; - - assert(loaded_policy); - - /* Make sure getcon() works, which needs /proc and /sys */ - mount_setup_early(); - - /* Already initialized by somebody else? */ - r = getcon_raw(&con); - if (r == 0) { - bool initialized; - - initialized = !streq(con, "kernel"); - freecon(con); - - if (initialized) - return 0; - } - - /* Make sure we have no fds open while loading the policy and - * transitioning */ - log_close(); - - /* Now load the policy */ - before_load = now(CLOCK_MONOTONIC); - r = selinux_init_load_policy(&enforce); - - if (r == 0) { - char timespan[FORMAT_TIMESPAN_MAX]; - char *label; - - label_retest_selinux(); - - /* Transition to the new context */ - r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); - if (r < 0 || label == NULL) { - log_open(); - log_error("Failed to compute init label, ignoring."); - } else { - r = setcon(label); - - log_open(); - if (r < 0) - log_error("Failed to transition into init label '%s', ignoring.", label); - - label_free(label); - } - - after_load = now(CLOCK_MONOTONIC); - - log_info("Successfully loaded SELinux policy in %s.", - format_timespan(timespan, sizeof(timespan), after_load - before_load)); - - *loaded_policy = true; - - } else { - log_open(); - - if (enforce > 0) { - log_error("Failed to load SELinux policy. Freezing."); - return -EIO; - } else - log_debug("Unable to load SELinux policy. Ignoring."); - } -#endif - - return 0; -} diff --git a/src/selinux-setup.h b/src/selinux-setup.h deleted file mode 100644 index 6b8fe00..0000000 --- a/src/selinux-setup.h +++ /dev/null @@ -1,29 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooselinuxsetuphfoo -#define fooselinuxsetuphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -int selinux_setup(bool *loaded_policy); - -#endif diff --git a/src/service.c b/src/service.c deleted file mode 100644 index 6184390..0000000 --- a/src/service.c +++ /dev/null @@ -1,3530 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "unit.h" -#include "service.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "strv.h" -#include "unit-name.h" -#include "dbus-service.h" -#include "special.h" -#include "bus-errors.h" -#include "exit-status.h" -#include "def.h" -#include "util.h" - -#ifdef HAVE_SYSV_COMPAT - -#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE) - -typedef enum RunlevelType { - RUNLEVEL_UP, - RUNLEVEL_DOWN, - RUNLEVEL_SYSINIT -} RunlevelType; - -static const struct { - const char *path; - const char *target; - const RunlevelType type; -} rcnd_table[] = { - /* Standard SysV runlevels for start-up */ - { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP }, - { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP }, - { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP }, - { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP }, - { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP }, - -#ifdef TARGET_SUSE - /* SUSE style boot.d */ - { "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT }, -#endif - -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) - /* Debian style rcS.d */ - { "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT }, -#endif - - /* Standard SysV runlevels for shutdown */ - { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN }, - { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN } - - /* Note that the order here matters, as we read the - directories in this order, and we want to make sure that - sysv_start_priority is known when we first load the - unit. And that value we only know from S links. Hence - UP/SYSINIT must be read before DOWN */ -}; - -#define RUNLEVELS_UP "12345" -/* #define RUNLEVELS_DOWN "06" */ -#define RUNLEVELS_BOOT "bBsS" -#endif - -static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { - [SERVICE_DEAD] = UNIT_INACTIVE, - [SERVICE_START_PRE] = UNIT_ACTIVATING, - [SERVICE_START] = UNIT_ACTIVATING, - [SERVICE_START_POST] = UNIT_ACTIVATING, - [SERVICE_RUNNING] = UNIT_ACTIVE, - [SERVICE_EXITED] = UNIT_ACTIVE, - [SERVICE_RELOAD] = UNIT_RELOADING, - [SERVICE_STOP] = UNIT_DEACTIVATING, - [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING, - [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING, - [SERVICE_STOP_POST] = UNIT_DEACTIVATING, - [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING, - [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING, - [SERVICE_FAILED] = UNIT_FAILED, - [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING -}; - -static void service_init(Unit *u) { - Service *s = SERVICE(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - s->timeout_usec = DEFAULT_TIMEOUT_USEC; - s->restart_usec = DEFAULT_RESTART_USEC; - s->timer_watch.type = WATCH_INVALID; -#ifdef HAVE_SYSV_COMPAT - s->sysv_start_priority = -1; - s->sysv_start_priority_from_rcnd = -1; -#endif - s->socket_fd = -1; - s->guess_main_pid = true; - - exec_context_init(&s->exec_context); - - RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5); - - s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; -} - -static void service_unwatch_control_pid(Service *s) { - assert(s); - - if (s->control_pid <= 0) - return; - - unit_unwatch_pid(UNIT(s), s->control_pid); - s->control_pid = 0; -} - -static void service_unwatch_main_pid(Service *s) { - assert(s); - - if (s->main_pid <= 0) - return; - - unit_unwatch_pid(UNIT(s), s->main_pid); - s->main_pid = 0; -} - -static int service_set_main_pid(Service *s, pid_t pid) { - pid_t ppid; - - assert(s); - - if (pid <= 1) - return -EINVAL; - - if (pid == getpid()) - return -EINVAL; - - s->main_pid = pid; - s->main_pid_known = true; - - if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { - log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.", - s->meta.id, (unsigned long) pid); - - s->main_pid_alien = true; - } else - s->main_pid_alien = false; - - exec_status_start(&s->main_exec_status, pid); - - return 0; -} - -static void service_close_socket_fd(Service *s) { - assert(s); - - if (s->socket_fd < 0) - return; - - close_nointr_nofail(s->socket_fd); - s->socket_fd = -1; -} - -static void service_connection_unref(Service *s) { - assert(s); - - if (!s->accept_socket) - return; - - socket_connection_unref(s->accept_socket); - s->accept_socket = NULL; -} - -static void service_done(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - free(s->pid_file); - s->pid_file = NULL; - -#ifdef HAVE_SYSV_COMPAT - free(s->sysv_path); - s->sysv_path = NULL; - - free(s->sysv_runlevels); - s->sysv_runlevels = NULL; -#endif - - free(s->status_text); - s->status_text = NULL; - - exec_context_done(&s->exec_context); - exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX); - s->control_command = NULL; - s->main_command = NULL; - - /* This will leak a process, but at least no memory or any of - * our resources */ - service_unwatch_main_pid(s); - service_unwatch_control_pid(s); - - if (s->bus_name) { - unit_unwatch_bus_name(UNIT(u), s->bus_name); - free(s->bus_name); - s->bus_name = NULL; - } - - service_close_socket_fd(s); - service_connection_unref(s); - - set_free(s->configured_sockets); - - unit_unwatch_timer(u, &s->timer_watch); -} - -#ifdef HAVE_SYSV_COMPAT -static char *sysv_translate_name(const char *name) { - char *r; - - if (!(r = new(char, strlen(name) + sizeof(".service")))) - return NULL; - -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) - if (endswith(name, ".sh")) - /* Drop Debian-style .sh suffix */ - strcpy(stpcpy(r, name) - 3, ".service"); -#endif -#ifdef TARGET_SUSE - if (startswith(name, "boot.")) - /* Drop SuSE-style boot. prefix */ - strcpy(stpcpy(r, name + 5), ".service"); -#endif -#ifdef TARGET_FRUGALWARE - if (startswith(name, "rc.")) - /* Drop Frugalware-style rc. prefix */ - strcpy(stpcpy(r, name + 3), ".service"); -#endif - else - /* Normal init scripts */ - strcpy(stpcpy(r, name), ".service"); - - return r; -} - -static int sysv_translate_facility(const char *name, const char *filename, char **_r) { - - /* We silently ignore the $ prefix here. According to the LSB - * spec it simply indicates whether something is a - * standardized name or a distribution-specific one. Since we - * just follow what already exists and do not introduce new - * uses or names we don't care who introduced a new name. */ - - static const char * const table[] = { - /* LSB defined facilities */ - "local_fs", SPECIAL_LOCAL_FS_TARGET, -#ifndef TARGET_MANDRIVA - /* Due to unfortunate name selection in Mandriva, - * $network is provided by network-up which is ordered - * after network which actually starts interfaces. - * To break the loop, just ignore it */ - "network", SPECIAL_NETWORK_TARGET, -#endif - "named", SPECIAL_NSS_LOOKUP_TARGET, - "portmap", SPECIAL_RPCBIND_TARGET, - "remote_fs", SPECIAL_REMOTE_FS_TARGET, - "syslog", SPECIAL_SYSLOG_TARGET, - "time", SPECIAL_TIME_SYNC_TARGET, - - /* common extensions */ - "mail-transfer-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, - "x-display-manager", SPECIAL_DISPLAY_MANAGER_SERVICE, - "null", NULL, - -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) - "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, -#endif - -#ifdef TARGET_FEDORA - "MTA", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, - "smtpdaemon", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, - "httpd", SPECIAL_HTTP_DAEMON_TARGET, -#endif - -#ifdef TARGET_SUSE - "smtp", SPECIAL_MAIL_TRANSFER_AGENT_TARGET, -#endif - }; - - unsigned i; - char *r; - const char *n; - - assert(name); - assert(_r); - - n = *name == '$' ? name + 1 : name; - - for (i = 0; i < ELEMENTSOF(table); i += 2) { - - if (!streq(table[i], n)) - continue; - - if (!table[i+1]) - return 0; - - if (!(r = strdup(table[i+1]))) - return -ENOMEM; - - goto finish; - } - - /* If we don't know this name, fallback heuristics to figure - * out whether something is a target or a service alias. */ - - if (*name == '$') { - if (!unit_prefix_is_valid(n)) - return -EINVAL; - - /* Facilities starting with $ are most likely targets */ - r = unit_name_build(n, NULL, ".target"); - } else if (filename && streq(name, filename)) - /* Names equaling the file name of the services are redundant */ - return 0; - else - /* Everything else we assume to be normal service names */ - r = sysv_translate_name(n); - - if (!r) - return -ENOMEM; - -finish: - *_r = r; - - return 1; -} - -static int sysv_fix_order(Service *s) { - Meta *other; - int r; - - assert(s); - - if (s->sysv_start_priority < 0) - return 0; - - /* For each pair of services where at least one lacks a LSB - * header, we use the start priority value to order things. */ - - LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) { - Service *t; - UnitDependency d; - bool special_s, special_t; - - t = (Service*) other; - - if (s == t) - continue; - - if (t->meta.load_state != UNIT_LOADED) - continue; - - if (t->sysv_start_priority < 0) - continue; - - /* If both units have modern headers we don't care - * about the priorities */ - if ((s->meta.fragment_path || s->sysv_has_lsb) && - (t->meta.fragment_path || t->sysv_has_lsb)) - continue; - - special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels); - special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels); - - if (special_t && !special_s) - d = UNIT_AFTER; - else if (special_s && !special_t) - d = UNIT_BEFORE; - else if (t->sysv_start_priority < s->sysv_start_priority) - d = UNIT_AFTER; - else if (t->sysv_start_priority > s->sysv_start_priority) - d = UNIT_BEFORE; - else - continue; - - /* FIXME: Maybe we should compare the name here lexicographically? */ - - if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) - return r; - } - - return 0; -} - -static ExecCommand *exec_command_new(const char *path, const char *arg1) { - ExecCommand *c; - - if (!(c = new0(ExecCommand, 1))) - return NULL; - - if (!(c->path = strdup(path))) { - free(c); - return NULL; - } - - if (!(c->argv = strv_new(path, arg1, NULL))) { - free(c->path); - free(c); - return NULL; - } - - return c; -} - -static int sysv_exec_commands(Service *s) { - ExecCommand *c; - - assert(s); - assert(s->sysv_path); - - if (!(c = exec_command_new(s->sysv_path, "start"))) - return -ENOMEM; - exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c); - - if (!(c = exec_command_new(s->sysv_path, "stop"))) - return -ENOMEM; - exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c); - - if (!(c = exec_command_new(s->sysv_path, "reload"))) - return -ENOMEM; - exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c); - - return 0; -} - -static int service_load_sysv_path(Service *s, const char *path) { - FILE *f; - Unit *u; - unsigned line = 0; - int r; - enum { - NORMAL, - DESCRIPTION, - LSB, - LSB_DESCRIPTION - } state = NORMAL; - char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description; - struct stat st; - - assert(s); - assert(path); - - u = UNIT(s); - - if (!(f = fopen(path, "re"))) { - r = errno == ENOENT ? 0 : -errno; - goto finish; - } - - zero(st); - if (fstat(fileno(f), &st) < 0) { - r = -errno; - goto finish; - } - - free(s->sysv_path); - if (!(s->sysv_path = strdup(path))) { - r = -ENOMEM; - goto finish; - } - - s->sysv_mtime = timespec_load(&st.st_mtim); - - if (null_or_empty(&st)) { - u->meta.load_state = UNIT_MASKED; - r = 0; - goto finish; - } - - while (!feof(f)) { - char l[LINE_MAX], *t; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - log_error("Failed to read configuration file '%s': %s", path, strerror(-r)); - goto finish; - } - - line++; - - t = strstrip(l); - if (*t != '#') - continue; - - if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) { - state = LSB; - s->sysv_has_lsb = true; - continue; - } - - if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) { - state = NORMAL; - continue; - } - - t++; - t += strspn(t, WHITESPACE); - - if (state == NORMAL) { - - /* Try to parse Red Hat style chkconfig headers */ - - if (startswith_no_case(t, "chkconfig:")) { - int start_priority; - char runlevels[16], *k; - - state = NORMAL; - - if (sscanf(t+10, "%15s %i %*i", - runlevels, - &start_priority) != 2) { - - log_warning("[%s:%u] Failed to parse chkconfig line. Ignoring.", path, line); - continue; - } - - /* A start priority gathered from the - * symlink farms is preferred over the - * data from the LSB header. */ - if (start_priority < 0 || start_priority > 99) - log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line); - else - s->sysv_start_priority = start_priority; - - char_array_0(runlevels); - k = delete_chars(runlevels, WHITESPACE "-"); - - if (k[0]) { - char *d; - - if (!(d = strdup(k))) { - r = -ENOMEM; - goto finish; - } - - free(s->sysv_runlevels); - s->sysv_runlevels = d; - } - - } else if (startswith_no_case(t, "description:")) { - - size_t k = strlen(t); - char *d; - const char *j; - - if (t[k-1] == '\\') { - state = DESCRIPTION; - t[k-1] = 0; - } - - if ((j = strstrip(t+12)) && *j) { - if (!(d = strdup(j))) { - r = -ENOMEM; - goto finish; - } - } else - d = NULL; - - free(chkconfig_description); - chkconfig_description = d; - - } else if (startswith_no_case(t, "pidfile:")) { - - char *fn; - - state = NORMAL; - - fn = strstrip(t+8); - if (!path_is_absolute(fn)) { - log_warning("[%s:%u] PID file not absolute. Ignoring.", path, line); - continue; - } - - if (!(fn = strdup(fn))) { - r = -ENOMEM; - goto finish; - } - - free(s->pid_file); - s->pid_file = fn; - } - - } else if (state == DESCRIPTION) { - - /* Try to parse Red Hat style description - * continuation */ - - size_t k = strlen(t); - char *j; - - if (t[k-1] == '\\') - t[k-1] = 0; - else - state = NORMAL; - - if ((j = strstrip(t)) && *j) { - char *d = NULL; - - if (chkconfig_description) - d = join(chkconfig_description, " ", j, NULL); - else - d = strdup(j); - - if (!d) { - r = -ENOMEM; - goto finish; - } - - free(chkconfig_description); - chkconfig_description = d; - } - - } else if (state == LSB || state == LSB_DESCRIPTION) { - - if (startswith_no_case(t, "Provides:")) { - char *i, *w; - size_t z; - - state = LSB; - - FOREACH_WORD_QUOTED(w, z, t+9, i) { - char *n, *m; - - if (!(n = strndup(w, z))) { - r = -ENOMEM; - goto finish; - } - - r = sysv_translate_facility(n, file_name_from_path(path), &m); - free(n); - - if (r < 0) - goto finish; - - if (r == 0) - continue; - - if (unit_name_to_type(m) == UNIT_SERVICE) - r = unit_add_name(u, m); - else - /* NB: SysV targets - * which are provided - * by a service are - * pulled in by the - * services, as an - * indication that the - * generic service is - * now available. This - * is strictly - * one-way. The - * targets do NOT pull - * in the SysV - * services! */ - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true); - - if (r < 0) - log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r)); - - free(m); - } - - } else if (startswith_no_case(t, "Required-Start:") || - startswith_no_case(t, "Should-Start:") || - startswith_no_case(t, "X-Start-Before:") || - startswith_no_case(t, "X-Start-After:")) { - char *i, *w; - size_t z; - - state = LSB; - - FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) { - char *n, *m; - - if (!(n = strndup(w, z))) { - r = -ENOMEM; - goto finish; - } - - r = sysv_translate_facility(n, file_name_from_path(path), &m); - - if (r < 0) { - log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r)); - free(n); - continue; - } - - free(n); - - if (r == 0) - continue; - - r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true); - - if (r < 0) - log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", path, line, m, strerror(-r)); - - free(m); - } - } else if (startswith_no_case(t, "Default-Start:")) { - char *k, *d; - - state = LSB; - - k = delete_chars(t+14, WHITESPACE "-"); - - if (k[0] != 0) { - if (!(d = strdup(k))) { - r = -ENOMEM; - goto finish; - } - - free(s->sysv_runlevels); - s->sysv_runlevels = d; - } - - } else if (startswith_no_case(t, "Description:")) { - char *d, *j; - - state = LSB_DESCRIPTION; - - if ((j = strstrip(t+12)) && *j) { - if (!(d = strdup(j))) { - r = -ENOMEM; - goto finish; - } - } else - d = NULL; - - free(long_description); - long_description = d; - - } else if (startswith_no_case(t, "Short-Description:")) { - char *d, *j; - - state = LSB; - - if ((j = strstrip(t+18)) && *j) { - if (!(d = strdup(j))) { - r = -ENOMEM; - goto finish; - } - } else - d = NULL; - - free(short_description); - short_description = d; - - } else if (state == LSB_DESCRIPTION) { - - if (startswith(l, "#\t") || startswith(l, "# ")) { - char *j; - - if ((j = strstrip(t)) && *j) { - char *d = NULL; - - if (long_description) - d = join(long_description, " ", t, NULL); - else - d = strdup(j); - - if (!d) { - r = -ENOMEM; - goto finish; - } - - free(long_description); - long_description = d; - } - - } else - state = LSB; - } - } - } - - if ((r = sysv_exec_commands(s)) < 0) - goto finish; - if (s->sysv_runlevels && - chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) && - chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) { - /* Service has both boot and "up" runlevels - configured. Kill the "up" ones. */ - delete_chars(s->sysv_runlevels, RUNLEVELS_UP); - } - - if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) { - /* If there a runlevels configured for this service - * but none of the standard ones, then we assume this - * is some special kind of service (which might be - * needed for early boot) and don't create any links - * to it. */ - - s->meta.default_dependencies = false; - - /* Don't timeout special services during boot (like fsck) */ - s->timeout_usec = 0; - } else - s->timeout_usec = DEFAULT_SYSV_TIMEOUT_USEC; - - /* Special setting for all SysV services */ - s->type = SERVICE_FORKING; - s->remain_after_exit = !s->pid_file; - s->guess_main_pid = false; - s->restart = SERVICE_RESTART_NO; - - if (s->meta.manager->sysv_console) - s->exec_context.std_output = EXEC_OUTPUT_TTY; - - s->exec_context.kill_mode = KILL_PROCESS; - - /* We use the long description only if - * no short description is set. */ - - if (short_description) - description = short_description; - else if (chkconfig_description) - description = chkconfig_description; - else if (long_description) - description = long_description; - else - description = NULL; - - if (description) { - char *d; - - if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) { - r = -ENOMEM; - goto finish; - } - - u->meta.description = d; - } - - /* The priority that has been set in /etc/rcN.d/ hierarchies - * takes precedence over what is stored as default in the LSB - * header */ - if (s->sysv_start_priority_from_rcnd >= 0) - s->sysv_start_priority = s->sysv_start_priority_from_rcnd; - - u->meta.load_state = UNIT_LOADED; - r = 0; - -finish: - - if (f) - fclose(f); - - free(short_description); - free(long_description); - free(chkconfig_description); - - return r; -} - -static int service_load_sysv_name(Service *s, const char *name) { - char **p; - - assert(s); - assert(name); - - /* For SysV services we strip the boot.*, rc.* and *.sh - * prefixes/suffixes. */ -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) - if (endswith(name, ".sh.service")) - return -ENOENT; -#endif - -#ifdef TARGET_SUSE - if (startswith(name, "boot.")) - return -ENOENT; -#endif - -#ifdef TARGET_FRUGALWARE - if (startswith(name, "rc.")) - return -ENOENT; -#endif - - STRV_FOREACH(p, s->meta.manager->lookup_paths.sysvinit_path) { - char *path; - int r; - - path = join(*p, "/", name, NULL); - if (!path) - return -ENOMEM; - - assert(endswith(path, ".service")); - path[strlen(path)-8] = 0; - - r = service_load_sysv_path(s, path); - -#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM) - if (r >= 0 && s->meta.load_state == UNIT_STUB) { - /* Try Debian style *.sh source'able init scripts */ - strcat(path, ".sh"); - r = service_load_sysv_path(s, path); - } -#endif - free(path); - -#ifdef TARGET_SUSE - if (r >= 0 && s->meta.load_state == UNIT_STUB) { - /* Try SUSE style boot.* init scripts */ - - path = join(*p, "/boot.", name, NULL); - if (!path) - return -ENOMEM; - - /* Drop .service suffix */ - path[strlen(path)-8] = 0; - r = service_load_sysv_path(s, path); - free(path); - } -#endif - -#ifdef TARGET_FRUGALWARE - if (r >= 0 && s->meta.load_state == UNIT_STUB) { - /* Try Frugalware style rc.* init scripts */ - - path = join(*p, "/rc.", name, NULL); - if (!path) - return -ENOMEM; - - /* Drop .service suffix */ - path[strlen(path)-8] = 0; - r = service_load_sysv_path(s, path); - free(path); - } -#endif - - if (r < 0) - return r; - - if ((s->meta.load_state != UNIT_STUB)) - break; - } - - return 0; -} - -static int service_load_sysv(Service *s) { - const char *t; - Iterator i; - int r; - - assert(s); - - /* Load service data from SysV init scripts, preferably with - * LSB headers ... */ - - if (strv_isempty(s->meta.manager->lookup_paths.sysvinit_path)) - return 0; - - if ((t = s->meta.id)) - if ((r = service_load_sysv_name(s, t)) < 0) - return r; - - if (s->meta.load_state == UNIT_STUB) - SET_FOREACH(t, s->meta.names, i) { - if (t == s->meta.id) - continue; - - if ((r = service_load_sysv_name(s, t)) < 0) - return r; - - if (s->meta.load_state != UNIT_STUB) - break; - } - - return 0; -} -#endif - -static int fsck_fix_order(Service *s) { - Meta *other; - int r; - - assert(s); - - if (s->fsck_passno <= 0) - return 0; - - /* For each pair of services where both have an fsck priority - * we order things based on it. */ - - LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) { - Service *t; - UnitDependency d; - - t = (Service*) other; - - if (s == t) - continue; - - if (t->meta.load_state != UNIT_LOADED) - continue; - - if (t->fsck_passno <= 0) - continue; - - if (t->fsck_passno < s->fsck_passno) - d = UNIT_AFTER; - else if (t->fsck_passno > s->fsck_passno) - d = UNIT_BEFORE; - else - continue; - - if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0) - return r; - } - - return 0; -} - -static int service_verify(Service *s) { - assert(s); - - if (s->meta.load_state != UNIT_LOADED) - return 0; - - if (!s->exec_command[SERVICE_EXEC_START]) { - log_error("%s lacks ExecStart setting. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->type != SERVICE_ONESHOT && - s->exec_command[SERVICE_EXEC_START]->command_next) { - log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->type == SERVICE_ONESHOT && - s->exec_command[SERVICE_EXEC_RELOAD]) { - log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->type == SERVICE_DBUS && !s->bus_name) { - log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { - log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", s->meta.id); - return -EINVAL; - } - - return 0; -} - -static int service_add_default_dependencies(Service *s) { - int r; - - assert(s); - - /* Add a number of automatic dependencies useful for the - * majority of services. */ - - /* First, pull in base system */ - if (s->meta.manager->running_as == MANAGER_SYSTEM) { - - if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0) - return r; - - } else if (s->meta.manager->running_as == MANAGER_USER) { - - if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0) - return r; - } - - /* Second, activate normal shutdown */ - return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); -} - -static void service_fix_output(Service *s) { - assert(s); - - /* If nothing has been explicitly configured, patch default - * output in. If input is socket/tty we avoid this however, - * since in that case we want output to default to the same - * place as we read input from. */ - - if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT && - s->exec_context.std_output == EXEC_OUTPUT_INHERIT && - s->exec_context.std_input == EXEC_INPUT_NULL) - s->exec_context.std_error = s->meta.manager->default_std_error; - - if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT && - s->exec_context.std_input == EXEC_INPUT_NULL) - s->exec_context.std_output = s->meta.manager->default_std_output; -} - -static int service_load(Unit *u) { - int r; - Service *s = SERVICE(u); - - assert(s); - - /* Load a .service file */ - if ((r = unit_load_fragment(u)) < 0) - return r; - -#ifdef HAVE_SYSV_COMPAT - /* Load a classic init script as a fallback, if we couldn't find anything */ - if (u->meta.load_state == UNIT_STUB) - if ((r = service_load_sysv(s)) < 0) - return r; -#endif - - /* Still nothing found? Then let's give up */ - if (u->meta.load_state == UNIT_STUB) - return -ENOENT; - - /* We were able to load something, then let's add in the - * dropin directories. */ - if ((r = unit_load_dropin(unit_follow_merge(u))) < 0) - return r; - - /* This is a new unit? Then let's add in some extras */ - if (u->meta.load_state == UNIT_LOADED) { - service_fix_output(s); - - if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) - return r; - - if ((r = unit_add_default_cgroups(u)) < 0) - return r; - -#ifdef HAVE_SYSV_COMPAT - if ((r = sysv_fix_order(s)) < 0) - return r; -#endif - - if ((r = fsck_fix_order(s)) < 0) - return r; - - if (s->bus_name) - if ((r = unit_watch_bus_name(u, s->bus_name)) < 0) - return r; - - if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE) - s->notify_access = NOTIFY_MAIN; - - if (s->type == SERVICE_DBUS || s->bus_name) - if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0) - return r; - - if (s->meta.default_dependencies) - if ((r = service_add_default_dependencies(s)) < 0) - return r; - } - - return service_verify(s); -} - -static void service_dump(Unit *u, FILE *f, const char *prefix) { - - ServiceExecCommand c; - Service *s = SERVICE(u); - const char *prefix2; - char *p2; - - assert(s); - - p2 = strappend(prefix, "\t"); - prefix2 = p2 ? p2 : prefix; - - fprintf(f, - "%sService State: %s\n" - "%sPermissionsStartOnly: %s\n" - "%sRootDirectoryStartOnly: %s\n" - "%sRemainAfterExit: %s\n" - "%sGuessMainPID: %s\n" - "%sType: %s\n" - "%sRestart: %s\n" - "%sNotifyAccess: %s\n", - prefix, service_state_to_string(s->state), - prefix, yes_no(s->permissions_start_only), - prefix, yes_no(s->root_directory_start_only), - prefix, yes_no(s->remain_after_exit), - prefix, yes_no(s->guess_main_pid), - prefix, service_type_to_string(s->type), - prefix, service_restart_to_string(s->restart), - prefix, notify_access_to_string(s->notify_access)); - - if (s->control_pid > 0) - fprintf(f, - "%sControl PID: %lu\n", - prefix, (unsigned long) s->control_pid); - - if (s->main_pid > 0) - fprintf(f, - "%sMain PID: %lu\n" - "%sMain PID Known: %s\n" - "%sMain PID Alien: %s\n", - prefix, (unsigned long) s->main_pid, - prefix, yes_no(s->main_pid_known), - prefix, yes_no(s->main_pid_alien)); - - if (s->pid_file) - fprintf(f, - "%sPIDFile: %s\n", - prefix, s->pid_file); - - if (s->bus_name) - fprintf(f, - "%sBusName: %s\n" - "%sBus Name Good: %s\n", - prefix, s->bus_name, - prefix, yes_no(s->bus_name_good)); - - exec_context_dump(&s->exec_context, f, prefix); - - for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) { - - if (!s->exec_command[c]) - continue; - - fprintf(f, "%s-> %s:\n", - prefix, service_exec_command_to_string(c)); - - exec_command_dump_list(s->exec_command[c], f, prefix2); - } - -#ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) - fprintf(f, - "%sSysV Init Script Path: %s\n" - "%sSysV Init Script has LSB Header: %s\n" - "%sSysVEnabled: %s\n", - prefix, s->sysv_path, - prefix, yes_no(s->sysv_has_lsb), - prefix, yes_no(s->sysv_enabled)); - - if (s->sysv_start_priority >= 0) - fprintf(f, - "%sSysVStartPriority: %i\n", - prefix, s->sysv_start_priority); - - if (s->sysv_runlevels) - fprintf(f, "%sSysVRunLevels: %s\n", - prefix, s->sysv_runlevels); -#endif - - if (s->fsck_passno > 0) - fprintf(f, - "%sFsckPassNo: %i\n", - prefix, s->fsck_passno); - - if (s->status_text) - fprintf(f, "%sStatus Text: %s\n", - prefix, s->status_text); - - free(p2); -} - -static int service_load_pid_file(Service *s, bool warn_if_missing) { - char *k; - int r; - pid_t pid; - - assert(s); - - if (!s->pid_file) - return -ENOENT; - - if ((r = read_one_line_file(s->pid_file, &k)) < 0) { - if (warn_if_missing) - log_warning("Failed to read PID file %s after %s. The service might be broken.", - s->pid_file, service_state_to_string(s->state)); - return r; - } - - r = parse_pid(k, &pid); - free(k); - - if (r < 0) - return r; - - if (kill(pid, 0) < 0 && errno != EPERM) { - log_warning("PID %lu read from file %s does not exist. Your service or init script might be broken.", - (unsigned long) pid, s->pid_file); - return -ESRCH; - } - - if (s->main_pid_known) { - if (pid == s->main_pid) - return 0; - - log_debug("Main PID changing: %lu -> %lu", - (unsigned long) s->main_pid, (unsigned long) pid); - service_unwatch_main_pid(s); - s->main_pid_known = false; - } - - if ((r = service_set_main_pid(s, pid)) < 0) - return r; - - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) - /* FIXME: we need to do something here */ - return r; - - return 0; -} - -static int service_search_main_pid(Service *s) { - pid_t pid; - int r; - - assert(s); - - /* If we know it anyway, don't ever fallback to unreliable - * heuristics */ - if (s->main_pid_known) - return 0; - - if (!s->guess_main_pid) - return 0; - - assert(s->main_pid <= 0); - - if ((pid = cgroup_bonding_search_main_pid_list(s->meta.cgroup_bondings)) <= 0) - return -ENOENT; - - if ((r = service_set_main_pid(s, pid)) < 0) - return r; - - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) - /* FIXME: we need to do something here */ - return r; - - return 0; -} - -static int service_get_sockets(Service *s, Set **_set) { - Set *set; - Iterator i; - char *t; - int r; - - assert(s); - assert(_set); - - if (s->socket_fd >= 0) - return 0; - - if (!set_isempty(s->configured_sockets)) - return 0; - - /* Collects all Socket objects that belong to this - * service. Note that a service might have multiple sockets - * via multiple names. */ - - if (!(set = set_new(NULL, NULL))) - return -ENOMEM; - - SET_FOREACH(t, s->meta.names, i) { - char *k; - Unit *p; - - /* Look for all socket objects that go by any of our - * units and collect their fds */ - - if (!(k = unit_name_change_suffix(t, ".socket"))) { - r = -ENOMEM; - goto fail; - } - - p = manager_get_unit(s->meta.manager, k); - free(k); - - if (!p) - continue; - - if ((r = set_put(set, p)) < 0) - goto fail; - } - - *_set = set; - return 0; - -fail: - set_free(set); - return r; -} - -static int service_notify_sockets_dead(Service *s) { - Iterator i; - Set *set, *free_set = NULL; - Socket *sock; - int r; - - assert(s); - - /* Notifies all our sockets when we die */ - - if (s->socket_fd >= 0) - return 0; - - if (!set_isempty(s->configured_sockets)) - set = s->configured_sockets; - else { - if ((r = service_get_sockets(s, &free_set)) < 0) - return r; - - set = free_set; - } - - SET_FOREACH(sock, set, i) - socket_notify_service_dead(sock); - - set_free(free_set); - - return 0; -} - -static void service_set_state(Service *s, ServiceState state) { - ServiceState old_state; - assert(s); - - old_state = s->state; - s->state = state; - - if (state != SERVICE_START_PRE && - state != SERVICE_START && - state != SERVICE_START_POST && - state != SERVICE_RELOAD && - state != SERVICE_STOP && - state != SERVICE_STOP_SIGTERM && - state != SERVICE_STOP_SIGKILL && - state != SERVICE_STOP_POST && - state != SERVICE_FINAL_SIGTERM && - state != SERVICE_FINAL_SIGKILL && - state != SERVICE_AUTO_RESTART) - unit_unwatch_timer(UNIT(s), &s->timer_watch); - - if (state != SERVICE_START && - state != SERVICE_START_POST && - state != SERVICE_RUNNING && - state != SERVICE_RELOAD && - state != SERVICE_STOP && - state != SERVICE_STOP_SIGTERM && - state != SERVICE_STOP_SIGKILL) { - service_unwatch_main_pid(s); - s->main_command = NULL; - } - - if (state != SERVICE_START_PRE && - state != SERVICE_START && - state != SERVICE_START_POST && - state != SERVICE_RELOAD && - state != SERVICE_STOP && - state != SERVICE_STOP_SIGTERM && - state != SERVICE_STOP_SIGKILL && - state != SERVICE_STOP_POST && - state != SERVICE_FINAL_SIGTERM && - state != SERVICE_FINAL_SIGKILL) { - service_unwatch_control_pid(s); - s->control_command = NULL; - s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; - } - - if (state == SERVICE_DEAD || - state == SERVICE_STOP || - state == SERVICE_STOP_SIGTERM || - state == SERVICE_STOP_SIGKILL || - state == SERVICE_STOP_POST || - state == SERVICE_FINAL_SIGTERM || - state == SERVICE_FINAL_SIGKILL || - state == SERVICE_FAILED || - state == SERVICE_AUTO_RESTART) - service_notify_sockets_dead(s); - - if (state != SERVICE_START_PRE && - state != SERVICE_START && - state != SERVICE_START_POST && - state != SERVICE_RUNNING && - state != SERVICE_RELOAD && - state != SERVICE_STOP && - state != SERVICE_STOP_SIGTERM && - state != SERVICE_STOP_SIGKILL && - state != SERVICE_STOP_POST && - state != SERVICE_FINAL_SIGTERM && - state != SERVICE_FINAL_SIGKILL && - !(state == SERVICE_DEAD && s->meta.job)) { - service_close_socket_fd(s); - service_connection_unref(s); - } - - /* For the inactive states unit_notify() will trim the cgroup, - * but for exit we have to do that ourselves... */ - if (state == SERVICE_EXITED && s->meta.manager->n_reloading <= 0) - cgroup_bonding_trim_list(s->meta.cgroup_bondings, true); - - if (old_state != state) - log_debug("%s changed %s -> %s", s->meta.id, service_state_to_string(old_state), service_state_to_string(state)); - - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], !s->reload_failure); - s->reload_failure = false; -} - -static int service_coldplug(Unit *u) { - Service *s = SERVICE(u); - int r; - - assert(s); - assert(s->state == SERVICE_DEAD); - - if (s->deserialized_state != s->state) { - - if (s->deserialized_state == SERVICE_START_PRE || - s->deserialized_state == SERVICE_START || - s->deserialized_state == SERVICE_START_POST || - s->deserialized_state == SERVICE_RELOAD || - s->deserialized_state == SERVICE_STOP || - s->deserialized_state == SERVICE_STOP_SIGTERM || - s->deserialized_state == SERVICE_STOP_SIGKILL || - s->deserialized_state == SERVICE_STOP_POST || - s->deserialized_state == SERVICE_FINAL_SIGTERM || - s->deserialized_state == SERVICE_FINAL_SIGKILL || - s->deserialized_state == SERVICE_AUTO_RESTART) { - - if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) { - usec_t k; - - k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec; - - if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0) - return r; - } - } - - if ((s->deserialized_state == SERVICE_START && - (s->type == SERVICE_FORKING || - s->type == SERVICE_DBUS || - s->type == SERVICE_ONESHOT || - s->type == SERVICE_NOTIFY)) || - s->deserialized_state == SERVICE_START_POST || - s->deserialized_state == SERVICE_RUNNING || - s->deserialized_state == SERVICE_RELOAD || - s->deserialized_state == SERVICE_STOP || - s->deserialized_state == SERVICE_STOP_SIGTERM || - s->deserialized_state == SERVICE_STOP_SIGKILL) - if (s->main_pid > 0) - if ((r = unit_watch_pid(UNIT(s), s->main_pid)) < 0) - return r; - - if (s->deserialized_state == SERVICE_START_PRE || - s->deserialized_state == SERVICE_START || - s->deserialized_state == SERVICE_START_POST || - s->deserialized_state == SERVICE_RELOAD || - s->deserialized_state == SERVICE_STOP || - s->deserialized_state == SERVICE_STOP_SIGTERM || - s->deserialized_state == SERVICE_STOP_SIGKILL || - s->deserialized_state == SERVICE_STOP_POST || - s->deserialized_state == SERVICE_FINAL_SIGTERM || - s->deserialized_state == SERVICE_FINAL_SIGKILL) - if (s->control_pid > 0) - if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0) - return r; - - service_set_state(s, s->deserialized_state); - } - - return 0; -} - -static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { - Iterator i; - int r; - int *rfds = NULL; - unsigned rn_fds = 0; - Set *set, *free_set = NULL; - Socket *sock; - - assert(s); - assert(fds); - assert(n_fds); - - if (s->socket_fd >= 0) - return 0; - - if (!set_isempty(s->configured_sockets)) - set = s->configured_sockets; - else { - if ((r = service_get_sockets(s, &free_set)) < 0) - return r; - - set = free_set; - } - - SET_FOREACH(sock, set, i) { - int *cfds; - unsigned cn_fds; - - if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0) - goto fail; - - if (!cfds) - continue; - - if (!rfds) { - rfds = cfds; - rn_fds = cn_fds; - } else { - int *t; - - if (!(t = new(int, rn_fds+cn_fds))) { - free(cfds); - r = -ENOMEM; - goto fail; - } - - memcpy(t, rfds, rn_fds * sizeof(int)); - memcpy(t+rn_fds, cfds, cn_fds * sizeof(int)); - free(rfds); - free(cfds); - - rfds = t; - rn_fds = rn_fds+cn_fds; - } - } - - *fds = rfds; - *n_fds = rn_fds; - - set_free(free_set); - - return 0; - -fail: - set_free(set); - free(rfds); - - return r; -} - -static int service_spawn( - Service *s, - ExecCommand *c, - bool timeout, - bool pass_fds, - bool apply_permissions, - bool apply_chroot, - bool apply_tty_stdin, - bool set_notify_socket, - pid_t *_pid) { - - pid_t pid; - int r; - int *fds = NULL, *fdsbuf = NULL; - unsigned n_fds = 0, n_env = 0; - char **argv = NULL, **final_env = NULL, **our_env = NULL; - - assert(s); - assert(c); - assert(_pid); - - if (pass_fds || - s->exec_context.std_input == EXEC_INPUT_SOCKET || - s->exec_context.std_output == EXEC_OUTPUT_SOCKET || - s->exec_context.std_error == EXEC_OUTPUT_SOCKET) { - - if (s->socket_fd >= 0) { - fds = &s->socket_fd; - n_fds = 1; - } else { - if ((r = service_collect_fds(s, &fdsbuf, &n_fds)) < 0) - goto fail; - - fds = fdsbuf; - } - } - - if (timeout && s->timeout_usec) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - } else - unit_unwatch_timer(UNIT(s), &s->timer_watch); - - if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) { - r = -ENOMEM; - goto fail; - } - - if (!(our_env = new0(char*, 4))) { - r = -ENOMEM; - goto fail; - } - - if (set_notify_socket) - if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", s->meta.manager->notify_socket) < 0) { - r = -ENOMEM; - goto fail; - } - - if (s->main_pid > 0) - if (asprintf(our_env + n_env++, "MAINPID=%lu", (unsigned long) s->main_pid) < 0) { - r = -ENOMEM; - goto fail; - } - - if (!(final_env = strv_env_merge(2, - s->meta.manager->environment, - our_env, - NULL))) { - r = -ENOMEM; - goto fail; - } - - r = exec_spawn(c, - argv, - &s->exec_context, - fds, n_fds, - final_env, - apply_permissions, - apply_chroot, - apply_tty_stdin, - s->meta.manager->confirm_spawn, - s->meta.cgroup_bondings, - s->meta.cgroup_attributes, - &pid); - - if (r < 0) - goto fail; - - - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) - /* FIXME: we need to do something here */ - goto fail; - - free(fdsbuf); - strv_free(argv); - strv_free(our_env); - strv_free(final_env); - - *_pid = pid; - - return 0; - -fail: - free(fdsbuf); - strv_free(argv); - strv_free(our_env); - strv_free(final_env); - - if (timeout) - unit_unwatch_timer(UNIT(s), &s->timer_watch); - - return r; -} - -static int main_pid_good(Service *s) { - assert(s); - - /* Returns 0 if the pid is dead, 1 if it is good, -1 if we - * don't know */ - - /* If we know the pid file, then lets just check if it is - * still valid */ - if (s->main_pid_known) { - - /* If it's an alien child let's check if it is still - * alive ... */ - if (s->main_pid_alien) - return kill(s->main_pid, 0) >= 0 || errno != ESRCH; - - /* .. otherwise assume we'll get a SIGCHLD for it, - * which we really should wait for to collect exit - * status and code */ - return s->main_pid > 0; - } - - /* We don't know the pid */ - return -EAGAIN; -} - -static int control_pid_good(Service *s) { - assert(s); - - return s->control_pid > 0; -} - -static int cgroup_good(Service *s) { - int r; - - assert(s); - - if ((r = cgroup_bonding_is_empty_list(s->meta.cgroup_bondings)) < 0) - return r; - - return !r; -} - -static void service_enter_dead(Service *s, bool success, bool allow_restart) { - int r; - assert(s); - - if (!success) - s->failure = true; - - if (allow_restart && - !s->forbid_restart && - (s->restart == SERVICE_RESTART_ALWAYS || - (s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure) || - (s->restart == SERVICE_RESTART_ON_FAILURE && s->failure) || - (s->restart == SERVICE_RESTART_ON_ABORT && s->failure && - (s->main_exec_status.code == CLD_KILLED || - s->main_exec_status.code == CLD_DUMPED)))) { - - if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0) - goto fail; - - service_set_state(s, SERVICE_AUTO_RESTART); - } else - service_set_state(s, s->failure ? SERVICE_FAILED : SERVICE_DEAD); - - s->forbid_restart = false; - - return; - -fail: - log_warning("%s failed to run install restart timer: %s", s->meta.id, strerror(-r)); - service_enter_dead(s, false, false); -} - -static void service_enter_signal(Service *s, ServiceState state, bool success); - -static void service_enter_stop_post(Service *s, bool success) { - int r; - assert(s); - - if (!success) - s->failure = true; - - service_unwatch_control_pid(s); - - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) { - s->control_command_id = SERVICE_EXEC_STOP_POST; - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - true, - false, - &s->control_pid)) < 0) - goto fail; - - - service_set_state(s, SERVICE_STOP_POST); - } else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, true); - - return; - -fail: - log_warning("%s failed to run 'stop-post' task: %s", s->meta.id, strerror(-r)); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); -} - -static void service_enter_signal(Service *s, ServiceState state, bool success) { - int r; - Set *pid_set = NULL; - bool wait_for_exit = false; - - assert(s); - - if (!success) - s->failure = true; - - if (s->exec_context.kill_mode != KILL_NONE) { - int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; - - if (s->main_pid > 0) { - if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH) - log_warning("Failed to kill main process %li: %m", (long) s->main_pid); - else - wait_for_exit = !s->main_pid_alien; - } - - if (s->control_pid > 0) { - if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) - log_warning("Failed to kill control process %li: %m", (long) s->control_pid); - else - wait_for_exit = true; - } - - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { - r = -ENOMEM; - goto fail; - } - - /* Exclude the main/control pids from being killed via the cgroup */ - if (s->main_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) - goto fail; - - if (s->control_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) - goto fail; - - if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, true, pid_set)) < 0) { - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) - log_warning("Failed to kill control group: %s", strerror(-r)); - } else if (r > 0) - wait_for_exit = true; - - set_free(pid_set); - pid_set = NULL; - } - } - - if (wait_for_exit) { - if (s->timeout_usec > 0) - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - - service_set_state(s, state); - } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) - service_enter_stop_post(s, true); - else - service_enter_dead(s, true, true); - - return; - -fail: - log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r)); - - if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL) - service_enter_stop_post(s, false); - else - service_enter_dead(s, false, true); - - if (pid_set) - set_free(pid_set); -} - -static void service_enter_stop(Service *s, bool success) { - int r; - - assert(s); - - if (!success) - s->failure = true; - - service_unwatch_control_pid(s); - - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) { - s->control_command_id = SERVICE_EXEC_STOP; - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - false, - false, - &s->control_pid)) < 0) - goto fail; - - service_set_state(s, SERVICE_STOP); - } else - service_enter_signal(s, SERVICE_STOP_SIGTERM, true); - - return; - -fail: - log_warning("%s failed to run 'stop' task: %s", s->meta.id, strerror(-r)); - service_enter_signal(s, SERVICE_STOP_SIGTERM, false); -} - -static void service_enter_running(Service *s, bool success) { - int main_pid_ok, cgroup_ok; - assert(s); - - if (!success) - s->failure = true; - - main_pid_ok = main_pid_good(s); - cgroup_ok = cgroup_good(s); - - if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) && - (s->bus_name_good || s->type != SERVICE_DBUS)) - service_set_state(s, SERVICE_RUNNING); - else if (s->remain_after_exit) - service_set_state(s, SERVICE_EXITED); - else - service_enter_stop(s, true); -} - -static void service_enter_start_post(Service *s) { - int r; - assert(s); - - service_unwatch_control_pid(s); - - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) { - s->control_command_id = SERVICE_EXEC_START_POST; - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - false, - false, - &s->control_pid)) < 0) - goto fail; - - service_set_state(s, SERVICE_START_POST); - } else - service_enter_running(s, true); - - return; - -fail: - log_warning("%s failed to run 'start-post' task: %s", s->meta.id, strerror(-r)); - service_enter_stop(s, false); -} - -static void service_enter_start(Service *s) { - pid_t pid; - int r; - ExecCommand *c; - - assert(s); - - assert(s->exec_command[SERVICE_EXEC_START]); - assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT); - - if (s->type == SERVICE_FORKING) - service_unwatch_control_pid(s); - else - service_unwatch_main_pid(s); - - if (s->type == SERVICE_FORKING) { - s->control_command_id = SERVICE_EXEC_START; - c = s->control_command = s->exec_command[SERVICE_EXEC_START]; - - s->main_command = NULL; - } else { - s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; - s->control_command = NULL; - - c = s->main_command = s->exec_command[SERVICE_EXEC_START]; - } - - if ((r = service_spawn(s, - c, - s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY, - true, - true, - true, - true, - s->notify_access != NOTIFY_NONE, - &pid)) < 0) - goto fail; - - if (s->type == SERVICE_SIMPLE) { - /* For simple services we immediately start - * the START_POST binaries. */ - - service_set_main_pid(s, pid); - service_enter_start_post(s); - - } else if (s->type == SERVICE_FORKING) { - - /* For forking services we wait until the start - * process exited. */ - - s->control_pid = pid; - service_set_state(s, SERVICE_START); - - } else if (s->type == SERVICE_ONESHOT || - s->type == SERVICE_DBUS || - s->type == SERVICE_NOTIFY) { - - /* For oneshot services we wait until the start - * process exited, too, but it is our main process. */ - - /* For D-Bus services we know the main pid right away, - * but wait for the bus name to appear on the - * bus. Notify services are similar. */ - - service_set_main_pid(s, pid); - service_set_state(s, SERVICE_START); - } else - assert_not_reached("Unknown service type"); - - return; - -fail: - log_warning("%s failed to run 'start' task: %s", s->meta.id, strerror(-r)); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); -} - -static void service_enter_start_pre(Service *s) { - int r; - - assert(s); - - service_unwatch_control_pid(s); - - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) { - s->control_command_id = SERVICE_EXEC_START_PRE; - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - true, - false, - &s->control_pid)) < 0) - goto fail; - - service_set_state(s, SERVICE_START_PRE); - } else - service_enter_start(s); - - return; - -fail: - log_warning("%s failed to run 'start-pre' task: %s", s->meta.id, strerror(-r)); - service_enter_dead(s, false, true); -} - -static void service_enter_restart(Service *s) { - int r; - DBusError error; - - assert(s); - dbus_error_init(&error); - - if (s->meta.job) { - log_info("Job pending for unit, delaying automatic restart."); - - if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0) - goto fail; - } - - service_enter_dead(s, true, false); - - if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, &error, NULL)) < 0) - goto fail; - - log_debug("%s scheduled restart job.", s->meta.id); - return; - -fail: - log_warning("%s failed to schedule restart job: %s", s->meta.id, bus_error(&error, -r)); - service_enter_dead(s, false, false); - - dbus_error_free(&error); -} - -static void service_enter_reload(Service *s) { - int r; - - assert(s); - - service_unwatch_control_pid(s); - - if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) { - s->control_command_id = SERVICE_EXEC_RELOAD; - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - false, - false, - &s->control_pid)) < 0) - goto fail; - - service_set_state(s, SERVICE_RELOAD); - } else - service_enter_running(s, true); - - return; - -fail: - log_warning("%s failed to run 'reload' task: %s", s->meta.id, strerror(-r)); - s->reload_failure = true; - service_enter_running(s, true); -} - -static void service_run_next_control(Service *s, bool success) { - int r; - - assert(s); - assert(s->control_command); - assert(s->control_command->command_next); - - if (!success) - s->failure = true; - - assert(s->control_command_id != SERVICE_EXEC_START); - - s->control_command = s->control_command->command_next; - service_unwatch_control_pid(s); - - if ((r = service_spawn(s, - s->control_command, - true, - false, - !s->permissions_start_only, - !s->root_directory_start_only, - s->control_command_id == SERVICE_EXEC_START_PRE || - s->control_command_id == SERVICE_EXEC_STOP_POST, - false, - &s->control_pid)) < 0) - goto fail; - - return; - -fail: - log_warning("%s failed to run next control task: %s", s->meta.id, strerror(-r)); - - if (s->state == SERVICE_START_PRE) - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - else if (s->state == SERVICE_STOP) - service_enter_signal(s, SERVICE_STOP_SIGTERM, false); - else if (s->state == SERVICE_STOP_POST) - service_enter_dead(s, false, true); - else if (s->state == SERVICE_RELOAD) { - s->reload_failure = true; - service_enter_running(s, true); - } else - service_enter_stop(s, false); -} - -static void service_run_next_main(Service *s, bool success) { - pid_t pid; - int r; - - assert(s); - assert(s->main_command); - assert(s->main_command->command_next); - assert(s->type == SERVICE_ONESHOT); - - if (!success) - s->failure = true; - - s->main_command = s->main_command->command_next; - service_unwatch_main_pid(s); - - if ((r = service_spawn(s, - s->main_command, - false, - true, - true, - true, - true, - s->notify_access != NOTIFY_NONE, - &pid)) < 0) - goto fail; - - service_set_main_pid(s, pid); - - return; - -fail: - log_warning("%s failed to run next main task: %s", s->meta.id, strerror(-r)); - service_enter_stop(s, false); -} - -static int service_start(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - /* We cannot fulfill this request right now, try again later - * please! */ - if (s->state == SERVICE_STOP || - s->state == SERVICE_STOP_SIGTERM || - s->state == SERVICE_STOP_SIGKILL || - s->state == SERVICE_STOP_POST || - s->state == SERVICE_FINAL_SIGTERM || - s->state == SERVICE_FINAL_SIGKILL) - return -EAGAIN; - - /* Already on it! */ - if (s->state == SERVICE_START_PRE || - s->state == SERVICE_START || - s->state == SERVICE_START_POST) - return 0; - - assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART); - - /* Make sure we don't enter a busy loop of some kind. */ - if (!ratelimit_test(&s->ratelimit)) { - log_warning("%s start request repeated too quickly, refusing to start.", u->meta.id); - return -ECANCELED; - } - - s->failure = false; - s->main_pid_known = false; - s->main_pid_alien = false; - s->forbid_restart = false; - - service_enter_start_pre(s); - return 0; -} - -static int service_stop(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - /* This is a user request, so don't do restarts on this - * shutdown. */ - s->forbid_restart = true; - - /* Already on it */ - if (s->state == SERVICE_STOP || - s->state == SERVICE_STOP_SIGTERM || - s->state == SERVICE_STOP_SIGKILL || - s->state == SERVICE_STOP_POST || - s->state == SERVICE_FINAL_SIGTERM || - s->state == SERVICE_FINAL_SIGKILL) - return 0; - - /* Don't allow a restart */ - if (s->state == SERVICE_AUTO_RESTART) { - service_set_state(s, SERVICE_DEAD); - return 0; - } - - /* If there's already something running we go directly into - * kill mode. */ - if (s->state == SERVICE_START_PRE || - s->state == SERVICE_START || - s->state == SERVICE_START_POST || - s->state == SERVICE_RELOAD) { - service_enter_signal(s, SERVICE_STOP_SIGTERM, true); - return 0; - } - - assert(s->state == SERVICE_RUNNING || - s->state == SERVICE_EXITED); - - service_enter_stop(s, true); - return 0; -} - -static int service_reload(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED); - - service_enter_reload(s); - return 0; -} - -static bool service_can_reload(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - return !!s->exec_command[SERVICE_EXEC_RELOAD]; -} - -static int service_serialize(Unit *u, FILE *f, FDSet *fds) { - Service *s = SERVICE(u); - - assert(u); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", service_state_to_string(s->state)); - unit_serialize_item(u, f, "failure", yes_no(s->failure)); - - if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); - - if (s->main_pid_known && s->main_pid > 0) - unit_serialize_item_format(u, f, "main-pid", "%lu", (unsigned long) s->main_pid); - - unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); - - if (s->status_text) - unit_serialize_item(u, f, "status-text", s->status_text); - - /* There's a minor uncleanliness here: if there are multiple - * commands attached here, we will start from the first one - * again */ - if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id)); - - if (s->socket_fd >= 0) { - int copy; - - if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0) - return copy; - - unit_serialize_item_format(u, f, "socket-fd", "%i", copy); - } - - if (s->main_exec_status.pid > 0) { - unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) s->main_exec_status.pid); - dual_timestamp_serialize(f, "main-exec-status-start", &s->main_exec_status.start_timestamp); - dual_timestamp_serialize(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp); - - if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) { - unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code); - unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status); - } - } - - return 0; -} - -static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Service *s = SERVICE(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - ServiceState state; - - if ((state = service_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - s->deserialized_state = state; - } else if (streq(key, "failure")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse failure value %s", value); - else - s->failure = b || s->failure; - } else if (streq(key, "control-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse control-pid value %s", value); - else - s->control_pid = pid; - } else if (streq(key, "main-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse main-pid value %s", value); - else - service_set_main_pid(s, (pid_t) pid); - } else if (streq(key, "main-pid-known")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse main-pid-known value %s", value); - else - s->main_pid_known = b; - } else if (streq(key, "status-text")) { - char *t; - - if ((t = strdup(value))) { - free(s->status_text); - s->status_text = t; - } - - } else if (streq(key, "control-command")) { - ServiceExecCommand id; - - if ((id = service_exec_command_from_string(value)) < 0) - log_debug("Failed to parse exec-command value %s", value); - else { - s->control_command_id = id; - s->control_command = s->exec_command[id]; - } - } else if (streq(key, "socket-fd")) { - int fd; - - if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse socket-fd value %s", value); - else { - - if (s->socket_fd >= 0) - close_nointr_nofail(s->socket_fd); - s->socket_fd = fdset_remove(fds, fd); - } - } else if (streq(key, "main-exec-status-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse main-exec-status-pid value %s", value); - else - s->main_exec_status.pid = pid; - } else if (streq(key, "main-exec-status-code")) { - int i; - - if (safe_atoi(value, &i) < 0) - log_debug("Failed to parse main-exec-status-code value %s", value); - else - s->main_exec_status.code = i; - } else if (streq(key, "main-exec-status-status")) { - int i; - - if (safe_atoi(value, &i) < 0) - log_debug("Failed to parse main-exec-status-status value %s", value); - else - s->main_exec_status.status = i; - } else if (streq(key, "main-exec-status-start")) - dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp); - else if (streq(key, "main-exec-status-exit")) - dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp); - else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState service_active_state(Unit *u) { - assert(u); - - return state_translation_table[SERVICE(u)->state]; -} - -static const char *service_sub_state_to_string(Unit *u) { - assert(u); - - return service_state_to_string(SERVICE(u)->state); -} - -static bool service_check_gc(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - /* Never clean up services that still have a process around, - * even if the service is formally dead. */ - if (cgroup_good(s) > 0 || - main_pid_good(s) > 0 || - control_pid_good(s) > 0) - return true; - -#ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) - return true; -#endif - - return false; -} - -static bool service_check_snapshot(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - return !s->got_socket_fd; -} - -static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { - Service *s = SERVICE(u); - bool success; - - assert(s); - assert(pid >= 0); - - if (!s->meta.fragment_path) - success = is_clean_exit_lsb(code, status); - else - success = is_clean_exit(code, status); - - if (s->main_pid == pid) { - /* Forking services may occasionally move to a new PID. - * As long as they update the PID file before exiting the old - * PID, they're fine. */ - if (service_load_pid_file(s, false) == 0) - return; - - s->main_pid = 0; - exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status); - - /* If this is not a forking service than the main - * process got started and hence we copy the exit - * status so that it is recorded both as main and as - * control process exit status */ - if (s->main_command) { - s->main_command->exec_status = s->main_exec_status; - - if (s->main_command->ignore) - success = true; - } - - log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status); - s->failure = s->failure || !success; - - if (s->main_command && - s->main_command->command_next && - success) { - - /* There is another command to * - * execute, so let's do that. */ - - log_debug("%s running next main command for state %s", u->meta.id, service_state_to_string(s->state)); - service_run_next_main(s, success); - - } else { - - /* The service exited, so the service is officially - * gone. */ - s->main_command = NULL; - - switch (s->state) { - - case SERVICE_START_POST: - case SERVICE_RELOAD: - case SERVICE_STOP: - /* Need to wait until the operation is - * done */ - break; - - case SERVICE_START: - if (s->type == SERVICE_ONESHOT) { - /* This was our main goal, so let's go on */ - if (success) - service_enter_start_post(s); - else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - break; - } else { - assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY); - - /* Fall through */ - } - - case SERVICE_RUNNING: - service_enter_running(s, success); - break; - - case SERVICE_STOP_SIGTERM: - case SERVICE_STOP_SIGKILL: - - if (!control_pid_good(s)) - service_enter_stop_post(s, success); - - /* If there is still a control process, wait for that first */ - break; - - default: - assert_not_reached("Uh, main process died at wrong time."); - } - } - - } else if (s->control_pid == pid) { - - s->control_pid = 0; - - if (s->control_command) { - exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); - - if (s->control_command->ignore) - success = true; - } - - log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); - s->failure = s->failure || !success; - - if (s->control_command && - s->control_command->command_next && - success) { - - /* There is another command to * - * execute, so let's do that. */ - - log_debug("%s running next control command for state %s", u->meta.id, service_state_to_string(s->state)); - service_run_next_control(s, success); - - } else { - /* No further commands for this step, so let's - * figure out what to do next */ - - s->control_command = NULL; - s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; - - log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state)); - - switch (s->state) { - - case SERVICE_START_PRE: - if (success) - service_enter_start(s); - else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - break; - - case SERVICE_START: - assert(s->type == SERVICE_FORKING); - - /* Let's try to load the pid - * file here if we can. We - * ignore the return value, - * since the PID file might - * actually be created by a - * START_POST script */ - - if (success) { - service_load_pid_file(s, !s->exec_command[SERVICE_EXEC_START_POST]); - service_search_main_pid(s); - - service_enter_start_post(s); - } else - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - - break; - - case SERVICE_START_POST: - if (success) { - service_load_pid_file(s, true); - service_search_main_pid(s); - } - - s->reload_failure = !success; - service_enter_running(s, true); - break; - - case SERVICE_RELOAD: - if (success) { - service_load_pid_file(s, true); - service_search_main_pid(s); - } - - s->reload_failure = !success; - service_enter_running(s, true); - break; - - case SERVICE_STOP: - service_enter_signal(s, SERVICE_STOP_SIGTERM, success); - break; - - case SERVICE_STOP_SIGTERM: - case SERVICE_STOP_SIGKILL: - if (main_pid_good(s) <= 0) - service_enter_stop_post(s, success); - - /* If there is still a service - * process around, wait until - * that one quit, too */ - break; - - case SERVICE_STOP_POST: - case SERVICE_FINAL_SIGTERM: - case SERVICE_FINAL_SIGKILL: - service_enter_dead(s, success, true); - break; - - default: - assert_not_reached("Uh, control process died at wrong time."); - } - } - } - - /* Notify clients about changed exit status */ - unit_add_to_dbus_queue(u); -} - -static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { - Service *s = SERVICE(u); - - assert(s); - assert(elapsed == 1); - - assert(w == &s->timer_watch); - - switch (s->state) { - - case SERVICE_START_PRE: - case SERVICE_START: - log_warning("%s operation timed out. Terminating.", u->meta.id); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - break; - - case SERVICE_START_POST: - log_warning("%s operation timed out. Stopping.", u->meta.id); - service_enter_stop(s, false); - break; - - case SERVICE_RELOAD: - log_warning("%s operation timed out. Stopping.", u->meta.id); - s->reload_failure = true; - service_enter_running(s, true); - break; - - case SERVICE_STOP: - log_warning("%s stopping timed out. Terminating.", u->meta.id); - service_enter_signal(s, SERVICE_STOP_SIGTERM, false); - break; - - case SERVICE_STOP_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out. Killing.", u->meta.id); - service_enter_signal(s, SERVICE_STOP_SIGKILL, false); - } else { - log_warning("%s stopping timed out. Skipping SIGKILL.", u->meta.id); - service_enter_stop_post(s, false); - } - - break; - - case SERVICE_STOP_SIGKILL: - /* Uh, we sent a SIGKILL and it is still not gone? - * Must be something we cannot kill, so let's just be - * weirded out and continue */ - - log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id); - service_enter_stop_post(s, false); - break; - - case SERVICE_STOP_POST: - log_warning("%s stopping timed out (2). Terminating.", u->meta.id); - service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); - break; - - case SERVICE_FINAL_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out (2). Killing.", u->meta.id); - service_enter_signal(s, SERVICE_FINAL_SIGKILL, false); - } else { - log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->meta.id); - service_enter_dead(s, false, true); - } - - break; - - case SERVICE_FINAL_SIGKILL: - log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->meta.id); - service_enter_dead(s, false, true); - break; - - case SERVICE_AUTO_RESTART: - log_info("%s holdoff time over, scheduling restart.", u->meta.id); - service_enter_restart(s); - break; - - default: - assert_not_reached("Timeout at wrong time."); - } -} - -static void service_cgroup_notify_event(Unit *u) { - Service *s = SERVICE(u); - - assert(u); - - log_debug("%s: cgroup is empty", u->meta.id); - - switch (s->state) { - - /* Waiting for SIGCHLD is usually more interesting, - * because it includes return codes/signals. Which is - * why we ignore the cgroup events for most cases, - * except when we don't know pid which to expect the - * SIGCHLD for. */ - - case SERVICE_RUNNING: - service_enter_running(s, true); - break; - - case SERVICE_STOP_SIGTERM: - case SERVICE_STOP_SIGKILL: - - if (main_pid_good(s) <= 0 && !control_pid_good(s)) - service_enter_stop_post(s, true); - - break; - - case SERVICE_FINAL_SIGTERM: - case SERVICE_FINAL_SIGKILL: - if (main_pid_good(s) <= 0 && !control_pid_good(s)) - service_enter_dead(s, true, true); - - break; - - default: - ; - } -} - -static void service_notify_message(Unit *u, pid_t pid, char **tags) { - Service *s = SERVICE(u); - const char *e; - - assert(u); - - if (s->notify_access == NOTIFY_NONE) { - log_warning("%s: Got notification message from PID %lu, but reception is disabled.", - u->meta.id, (unsigned long) pid); - return; - } - - if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) { - log_warning("%s: Got notification message from PID %lu, but reception only permitted for PID %lu", - u->meta.id, (unsigned long) pid, (unsigned long) s->main_pid); - return; - } - - log_debug("%s: Got message", u->meta.id); - - /* Interpret MAINPID= */ - if ((e = strv_find_prefix(tags, "MAINPID=")) && - (s->state == SERVICE_START || - s->state == SERVICE_START_POST || - s->state == SERVICE_RUNNING || - s->state == SERVICE_RELOAD)) { - - if (parse_pid(e + 8, &pid) < 0) - log_warning("Failed to parse notification message %s", e); - else { - log_debug("%s: got %s", u->meta.id, e); - service_set_main_pid(s, pid); - } - } - - /* Interpret READY= */ - if (s->type == SERVICE_NOTIFY && - s->state == SERVICE_START && - strv_find(tags, "READY=1")) { - log_debug("%s: got READY=1", u->meta.id); - - service_enter_start_post(s); - } - - /* Interpret STATUS= */ - if ((e = strv_find_prefix(tags, "STATUS="))) { - char *t; - - if (e[7]) { - if (!(t = strdup(e+7))) { - log_error("Failed to allocate string."); - return; - } - - log_debug("%s: got %s", u->meta.id, e); - - free(s->status_text); - s->status_text = t; - } else { - free(s->status_text); - s->status_text = NULL; - } - - } - - /* Notify clients about changed status or main pid */ - unit_add_to_dbus_queue(u); -} - -#ifdef HAVE_SYSV_COMPAT - -#ifdef TARGET_SUSE -static void sysv_facility_in_insserv_conf(Manager *mgr) { - FILE *f=NULL; - int r; - - if (!(f = fopen("/etc/insserv.conf", "re"))) { - r = errno == ENOENT ? 0 : -errno; - goto finish; - } - - while (!feof(f)) { - char l[LINE_MAX], *t; - char **parsed = NULL; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - log_error("Failed to read configuration file '/etc/insserv.conf': %s", strerror(-r)); - goto finish; - } - - t = strstrip(l); - if (*t != '$' && *t != '<') - continue; - - parsed = strv_split(t,WHITESPACE); - /* we ignore , not used, equivalent to X-Interactive */ - if (parsed && !startswith_no_case (parsed[0], "")) { - char *facility; - Unit *u; - if (sysv_translate_facility(parsed[0], NULL, &facility) < 0) - continue; - if ((u = manager_get_unit(mgr, facility)) && (u->meta.type == UNIT_TARGET)) { - UnitDependency e; - char *dep = NULL, *name, **j; - - STRV_FOREACH (j, parsed+1) { - if (*j[0]=='+') { - e = UNIT_WANTS; - name = *j+1; - } - else { - e = UNIT_REQUIRES; - name = *j; - } - if (sysv_translate_facility(name, NULL, &dep) < 0) - continue; - - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, e, dep, NULL, true); - free(dep); - } - } - free(facility); - } - strv_free(parsed); - } -finish: - if (f) - fclose(f); - -} -#endif - -static int service_enumerate(Manager *m) { - char **p; - unsigned i; - DIR *d = NULL; - char *path = NULL, *fpath = NULL, *name = NULL; - Set *runlevel_services[ELEMENTSOF(rcnd_table)], *shutdown_services = NULL; - Unit *service; - Iterator j; - int r; - - assert(m); - - if (m->running_as != MANAGER_SYSTEM) - return 0; - - zero(runlevel_services); - - STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path) - for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { - struct dirent *de; - - free(path); - path = join(*p, "/", rcnd_table[i].path, NULL); - if (!path) { - r = -ENOMEM; - goto finish; - } - - if (d) - closedir(d); - - if (!(d = opendir(path))) { - if (errno != ENOENT) - log_warning("opendir() failed on %s: %s", path, strerror(errno)); - - continue; - } - - while ((de = readdir(d))) { - int a, b; - - if (ignore_file(de->d_name)) - continue; - - if (de->d_name[0] != 'S' && de->d_name[0] != 'K') - continue; - - if (strlen(de->d_name) < 4) - continue; - - a = undecchar(de->d_name[1]); - b = undecchar(de->d_name[2]); - - if (a < 0 || b < 0) - continue; - - free(fpath); - fpath = join(path, "/", de->d_name, NULL); - if (!fpath) { - r = -ENOMEM; - goto finish; - } - - if (access(fpath, X_OK) < 0) { - - if (errno != ENOENT) - log_warning("access() failed on %s: %s", fpath, strerror(errno)); - - continue; - } - - free(name); - if (!(name = sysv_translate_name(de->d_name + 3))) { - r = -ENOMEM; - goto finish; - } - - if ((r = manager_load_unit_prepare(m, name, NULL, NULL, &service)) < 0) { - log_warning("Failed to prepare unit %s: %s", name, strerror(-r)); - continue; - } - - if (de->d_name[0] == 'S') { - - if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) { - SERVICE(service)->sysv_start_priority_from_rcnd = - MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd); - - SERVICE(service)->sysv_enabled = true; - } - - if ((r = set_ensure_allocated(&runlevel_services[i], trivial_hash_func, trivial_compare_func)) < 0) - goto finish; - - if ((r = set_put(runlevel_services[i], service)) < 0) - goto finish; - - } else if (de->d_name[0] == 'K' && - (rcnd_table[i].type == RUNLEVEL_DOWN || - rcnd_table[i].type == RUNLEVEL_SYSINIT)) { - - if ((r = set_ensure_allocated(&shutdown_services, trivial_hash_func, trivial_compare_func)) < 0) - goto finish; - - if ((r = set_put(shutdown_services, service)) < 0) - goto finish; - } - } - } - - /* Now we loaded all stubs and are aware of the lowest - start-up priority for all services, not let's actually load - the services, this will also tell us which services are - actually native now */ - manager_dispatch_load_queue(m); - - /* If this is a native service, rely on native ways to pull in - * a service, don't pull it in via sysv rcN.d links. */ - for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) - SET_FOREACH(service, runlevel_services[i], j) { - service = unit_follow_merge(service); - - if (service->meta.fragment_path) - continue; - - if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0) - goto finish; - } - - /* We honour K links only for halt/reboot. For the normal - * runlevels we assume the stop jobs will be implicitly added - * by the core logic. Also, we don't really distinguish here - * between the runlevels 0 and 6 and just add them to the - * special shutdown target. On SUSE the boot.d/ runlevel is - * also used for shutdown, so we add links for that too to the - * shutdown target.*/ - SET_FOREACH(service, shutdown_services, j) { - service = unit_follow_merge(service); - - if (service->meta.fragment_path) - continue; - - if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0) - goto finish; - } - - r = 0; - -#ifdef TARGET_SUSE - sysv_facility_in_insserv_conf (m); -#endif - -finish: - free(path); - free(fpath); - free(name); - - for (i = 0; i < ELEMENTSOF(rcnd_table); i++) - set_free(runlevel_services[i]); - set_free(shutdown_services); - - if (d) - closedir(d); - - return r; -} -#endif - -static void service_bus_name_owner_change( - Unit *u, - const char *name, - const char *old_owner, - const char *new_owner) { - - Service *s = SERVICE(u); - - assert(s); - assert(name); - - assert(streq(s->bus_name, name)); - assert(old_owner || new_owner); - - if (old_owner && new_owner) - log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner); - else if (old_owner) - log_debug("%s's D-Bus name %s no longer registered by %s", u->meta.id, name, old_owner); - else - log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner); - - s->bus_name_good = !!new_owner; - - if (s->type == SERVICE_DBUS) { - - /* service_enter_running() will figure out what to - * do */ - if (s->state == SERVICE_RUNNING) - service_enter_running(s, true); - else if (s->state == SERVICE_START && new_owner) - service_enter_start_post(s); - - } else if (new_owner && - s->main_pid <= 0 && - (s->state == SERVICE_START || - s->state == SERVICE_START_POST || - s->state == SERVICE_RUNNING || - s->state == SERVICE_RELOAD)) { - - /* Try to acquire PID from bus service */ - log_debug("Trying to acquire PID from D-Bus name..."); - - bus_query_pid(u->meta.manager, name); - } -} - -static void service_bus_query_pid_done( - Unit *u, - const char *name, - pid_t pid) { - - Service *s = SERVICE(u); - - assert(s); - assert(name); - - log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid); - - if (s->main_pid <= 0 && - (s->state == SERVICE_START || - s->state == SERVICE_START_POST || - s->state == SERVICE_RUNNING || - s->state == SERVICE_RELOAD)) - service_set_main_pid(s, pid); -} - -int service_set_socket_fd(Service *s, int fd, Socket *sock) { - assert(s); - assert(fd >= 0); - - /* This is called by the socket code when instantiating a new - * service for a stream socket and the socket needs to be - * configured. */ - - if (s->meta.load_state != UNIT_LOADED) - return -EINVAL; - - if (s->socket_fd >= 0) - return -EBUSY; - - if (s->state != SERVICE_DEAD) - return -EAGAIN; - - s->socket_fd = fd; - s->got_socket_fd = true; - s->accept_socket = sock; - - return 0; -} - -static void service_reset_failed(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - if (s->state == SERVICE_FAILED) - service_set_state(s, SERVICE_DEAD); - - s->failure = false; -} - -static bool service_need_daemon_reload(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - -#ifdef HAVE_SYSV_COMPAT - if (s->sysv_path) { - struct stat st; - - zero(st); - if (stat(s->sysv_path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (s->sysv_mtime > 0 && - timespec_load(&st.st_mtim) != s->sysv_mtime) - return true; - } -#endif - - return false; -} - -static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { - Service *s = SERVICE(u); - int r = 0; - Set *pid_set = NULL; - - assert(s); - - if (s->main_pid <= 0 && who == KILL_MAIN) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); - return -ESRCH; - } - - if (s->control_pid <= 0 && who == KILL_CONTROL) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); - return -ESRCH; - } - - if (who == KILL_CONTROL || who == KILL_ALL) - if (s->control_pid > 0) - if (kill(s->control_pid, signo) < 0) - r = -errno; - - if (who == KILL_MAIN || who == KILL_ALL) - if (s->main_pid > 0) - if (kill(s->main_pid, signo) < 0) - r = -errno; - - if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) { - int q; - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - /* Exclude the control/main pid from being killed via the cgroup */ - if (s->control_pid > 0) - if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) { - r = q; - goto finish; - } - - if (s->main_pid > 0) - if ((q = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0) { - r = q; - goto finish; - } - - if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - } - -finish: - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const service_state_table[_SERVICE_STATE_MAX] = { - [SERVICE_DEAD] = "dead", - [SERVICE_START_PRE] = "start-pre", - [SERVICE_START] = "start", - [SERVICE_START_POST] = "start-post", - [SERVICE_RUNNING] = "running", - [SERVICE_EXITED] = "exited", - [SERVICE_RELOAD] = "reload", - [SERVICE_STOP] = "stop", - [SERVICE_STOP_SIGTERM] = "stop-sigterm", - [SERVICE_STOP_SIGKILL] = "stop-sigkill", - [SERVICE_STOP_POST] = "stop-post", - [SERVICE_FINAL_SIGTERM] = "final-sigterm", - [SERVICE_FINAL_SIGKILL] = "final-sigkill", - [SERVICE_FAILED] = "failed", - [SERVICE_AUTO_RESTART] = "auto-restart", -}; - -DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); - -static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { - [SERVICE_RESTART_NO] = "no", - [SERVICE_RESTART_ON_SUCCESS] = "on-success", - [SERVICE_RESTART_ON_FAILURE] = "on-failure", - [SERVICE_RESTART_ON_ABORT] = "on-abort", - [SERVICE_RESTART_ALWAYS] = "always" -}; - -DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart); - -static const char* const service_type_table[_SERVICE_TYPE_MAX] = { - [SERVICE_SIMPLE] = "simple", - [SERVICE_FORKING] = "forking", - [SERVICE_ONESHOT] = "oneshot", - [SERVICE_DBUS] = "dbus", - [SERVICE_NOTIFY] = "notify" -}; - -DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType); - -static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = { - [SERVICE_EXEC_START_PRE] = "ExecStartPre", - [SERVICE_EXEC_START] = "ExecStart", - [SERVICE_EXEC_START_POST] = "ExecStartPost", - [SERVICE_EXEC_RELOAD] = "ExecReload", - [SERVICE_EXEC_STOP] = "ExecStop", - [SERVICE_EXEC_STOP_POST] = "ExecStopPost", -}; - -DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand); - -static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { - [NOTIFY_NONE] = "none", - [NOTIFY_MAIN] = "main", - [NOTIFY_ALL] = "all" -}; - -DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); - -const UnitVTable service_vtable = { - .suffix = ".service", - .sections = - "Unit\0" - "Service\0" - "Install\0", - .show_status = true, - - .init = service_init, - .done = service_done, - .load = service_load, - - .coldplug = service_coldplug, - - .dump = service_dump, - - .start = service_start, - .stop = service_stop, - .reload = service_reload, - - .can_reload = service_can_reload, - - .kill = service_kill, - - .serialize = service_serialize, - .deserialize_item = service_deserialize_item, - - .active_state = service_active_state, - .sub_state_to_string = service_sub_state_to_string, - - .check_gc = service_check_gc, - .check_snapshot = service_check_snapshot, - - .sigchld_event = service_sigchld_event, - .timer_event = service_timer_event, - - .reset_failed = service_reset_failed, - - .need_daemon_reload = service_need_daemon_reload, - - .cgroup_notify_empty = service_cgroup_notify_event, - .notify_message = service_notify_message, - - .bus_name_owner_change = service_bus_name_owner_change, - .bus_query_pid_done = service_bus_query_pid_done, - - .bus_interface = "org.freedesktop.systemd1.Service", - .bus_message_handler = bus_service_message_handler, - .bus_invalidating_properties = bus_service_invalidating_properties, - -#ifdef HAVE_SYSV_COMPAT - .enumerate = service_enumerate -#endif -}; diff --git a/src/service.h b/src/service.h deleted file mode 100644 index e28f74b..0000000 --- a/src/service.h +++ /dev/null @@ -1,183 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooservicehfoo -#define fooservicehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Service Service; - -#include "unit.h" -#include "ratelimit.h" - -typedef enum ServiceState { - SERVICE_DEAD, - SERVICE_START_PRE, - SERVICE_START, - SERVICE_START_POST, - SERVICE_RUNNING, - SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ - SERVICE_RELOAD, - SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ - SERVICE_STOP_SIGTERM, - SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ - SERVICE_FINAL_SIGKILL, - SERVICE_FAILED, - SERVICE_AUTO_RESTART, - _SERVICE_STATE_MAX, - _SERVICE_STATE_INVALID = -1 -} ServiceState; - -typedef enum ServiceRestart { - SERVICE_RESTART_NO, - SERVICE_RESTART_ON_SUCCESS, - SERVICE_RESTART_ON_FAILURE, - SERVICE_RESTART_ON_ABORT, - SERVICE_RESTART_ALWAYS, - _SERVICE_RESTART_MAX, - _SERVICE_RESTART_INVALID = -1 -} ServiceRestart; - -typedef enum ServiceType { - SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */ - SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */ - SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */ - SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */ - SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */ - _SERVICE_TYPE_MAX, - _SERVICE_TYPE_INVALID = -1 -} ServiceType; - -typedef enum ServiceExecCommand { - SERVICE_EXEC_START_PRE, - SERVICE_EXEC_START, - SERVICE_EXEC_START_POST, - SERVICE_EXEC_RELOAD, - SERVICE_EXEC_STOP, - SERVICE_EXEC_STOP_POST, - _SERVICE_EXEC_COMMAND_MAX, - _SERVICE_EXEC_COMMAND_INVALID = -1 -} ServiceExecCommand; - -typedef enum NotifyAccess { - NOTIFY_NONE, - NOTIFY_ALL, - NOTIFY_MAIN, - _NOTIFY_ACCESS_MAX, - _NOTIFY_ACCESS_INVALID = -1 -} NotifyAccess; - -struct Service { - Meta meta; - - ServiceType type; - ServiceRestart restart; - - /* If set we'll read the main daemon PID from this file */ - char *pid_file; - - usec_t restart_usec; - usec_t timeout_usec; - - ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; - ExecContext exec_context; - - ServiceState state, deserialized_state; - - /* The exit status of the real main process */ - ExecStatus main_exec_status; - - /* The currently executed control process */ - ExecCommand *control_command; - - /* The currently executed main process, which may be NULL if - * the main process got started via forking mode and not by - * us */ - ExecCommand *main_command; - - /* The ID of the control command currently being executed */ - ServiceExecCommand control_command_id; - - pid_t main_pid, control_pid; - int socket_fd; - - int fsck_passno; - - bool permissions_start_only; - bool root_directory_start_only; - bool remain_after_exit; - bool guess_main_pid; - - /* If we shut down, remember why */ - bool failure:1; - bool reload_failure:1; - - bool main_pid_known:1; - bool main_pid_alien:1; - bool bus_name_good:1; - bool forbid_restart:1; - bool got_socket_fd:1; -#ifdef HAVE_SYSV_COMPAT - bool sysv_has_lsb:1; - bool sysv_enabled:1; - int sysv_start_priority_from_rcnd; - int sysv_start_priority; - - char *sysv_path; - char *sysv_runlevels; - usec_t sysv_mtime; -#endif - - char *bus_name; - - char *status_text; - - RateLimit ratelimit; - - struct Socket *accept_socket; - Set *configured_sockets; - - Watch timer_watch; - - NotifyAccess notify_access; -}; - -extern const UnitVTable service_vtable; - -int service_set_socket_fd(Service *s, int fd, struct Socket *socket); - -const char* service_state_to_string(ServiceState i); -ServiceState service_state_from_string(const char *s); - -const char* service_restart_to_string(ServiceRestart i); -ServiceRestart service_restart_from_string(const char *s); - -const char* service_type_to_string(ServiceType i); -ServiceType service_type_from_string(const char *s); - -const char* service_exec_command_to_string(ServiceExecCommand i); -ServiceExecCommand service_exec_command_from_string(const char *s); - -const char* notify_access_to_string(NotifyAccess i); -NotifyAccess notify_access_from_string(const char *s); - -#endif diff --git a/src/set.c b/src/set.c deleted file mode 100644 index 097b9d3..0000000 --- a/src/set.c +++ /dev/null @@ -1,118 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "set.h" -#include "hashmap.h" - -#define MAKE_SET(h) ((Set*) (h)) -#define MAKE_HASHMAP(s) ((Hashmap*) (s)) - -/* For now this is not much more than a wrapper around a hashmap */ - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { - return MAKE_SET(hashmap_new(hash_func, compare_func)); -} - -void set_free(Set* s) { - hashmap_free(MAKE_HASHMAP(s)); -} - -void set_free_free(Set *s) { - hashmap_free_free(MAKE_HASHMAP(s)); -} - -int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) { - return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func); -} - -int set_put(Set *s, void *value) { - return hashmap_put(MAKE_HASHMAP(s), value, value); -} - -int set_replace(Set *s, void *value) { - return hashmap_replace(MAKE_HASHMAP(s), value, value); -} - -void *set_get(Set *s, void *value) { - return hashmap_get(MAKE_HASHMAP(s), value); -} - -void *set_remove(Set *s, void *value) { - return hashmap_remove(MAKE_HASHMAP(s), value); -} - -int set_remove_and_put(Set *s, void *old_value, void *new_value) { - return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value); -} - -unsigned set_size(Set *s) { - return hashmap_size(MAKE_HASHMAP(s)); -} - -bool set_isempty(Set *s) { - return hashmap_isempty(MAKE_HASHMAP(s)); -} - -void *set_iterate(Set *s, Iterator *i) { - return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); -} - -void *set_iterate_backwards(Set *s, Iterator *i) { - return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); -} - -void *set_iterate_skip(Set *s, void *value, Iterator *i) { - return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i); -} - -void *set_steal_first(Set *s) { - return hashmap_steal_first(MAKE_HASHMAP(s)); -} - -void* set_first(Set *s) { - return hashmap_first(MAKE_HASHMAP(s)); -} - -void* set_last(Set *s) { - return hashmap_last(MAKE_HASHMAP(s)); -} - -int set_merge(Set *s, Set *other) { - return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); -} - -void set_move(Set *s, Set *other) { - return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); -} - -int set_move_one(Set *s, Set *other, void *value) { - return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value); -} - -Set* set_copy(Set *s) { - return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s))); -} - -void set_clear(Set *s) { - hashmap_clear(MAKE_HASHMAP(s)); -} diff --git a/src/set.h b/src/set.h deleted file mode 100644 index 885780c..0000000 --- a/src/set.h +++ /dev/null @@ -1,69 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosethfoo -#define foosethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -/* Pretty straightforward set implementation. Internally based on the - * hashmap. That means that as a minor optimization a NULL set - * object will be treated as empty set for all read - * operations. That way it is not necessary to instantiate an object - * for each set use. */ - -#include "hashmap.h" - -typedef struct Set Set; - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func); -void set_free(Set* s); -void set_free_free(Set *s); -Set* set_copy(Set *s); -int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func); - -int set_put(Set *s, void *value); -int set_replace(Set *s, void *value); -void *set_get(Set *s, void *value); -void *set_remove(Set *s, void *value); -int set_remove_and_put(Set *s, void *old_value, void *new_value); - -int set_merge(Set *s, Set *other); -void set_move(Set *s, Set *other); -int set_move_one(Set *s, Set *other, void *value); - -unsigned set_size(Set *s); -bool set_isempty(Set *s); - -void *set_iterate(Set *s, Iterator *i); -void *set_iterate_backwards(Set *s, Iterator *i); -void *set_iterate_skip(Set *s, void *value, Iterator *i); - -void set_clear(Set *s); -void *set_steal_first(Set *s); -void* set_first(Set *s); -void* set_last(Set *s); - -#define SET_FOREACH(e, s, i) \ - for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) - -#define SET_FOREACH_BACKWARDS(e, s, i) \ - for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i))) - -#endif diff --git a/src/shared/.gitignore b/src/shared/.gitignore new file mode 100644 index 0000000..c9b5f81 --- /dev/null +++ b/src/shared/.gitignore @@ -0,0 +1,4 @@ +/errno-from-name.gperf +/errno-from-name.h +/errno-list.txt +/errno-to-name.h diff --git a/src/shared/Makefile b/src/shared/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/shared/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/shared/MurmurHash2.c b/src/shared/MurmurHash2.c new file mode 100644 index 0000000..2f4149d --- /dev/null +++ b/src/shared/MurmurHash2.c @@ -0,0 +1,86 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - This code makes a few assumptions about how your machine behaves - + +// 1. We can read a 4-byte value from any address without crashing +// 2. sizeof(int) == 4 + +// And it has a few limitations - + +// 1. It will not work incrementally. +// 2. It will not produce the same results on little-endian and big-endian +// machines. + +#include "MurmurHash2.h" + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + const uint32_t m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + uint32_t k = *(uint32_t*)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} diff --git a/src/shared/MurmurHash2.h b/src/shared/MurmurHash2.h new file mode 100644 index 0000000..93362dd --- /dev/null +++ b/src/shared/MurmurHash2.h @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _MURMURHASH2_H_ +#define _MURMURHASH2_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +typedef unsigned char uint8_t; +typedef unsigned long uint32_t; +typedef unsigned __int64 uint64_t; + +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ); + +//----------------------------------------------------------------------------- + +#endif // _MURMURHASH2_H_ diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c new file mode 100644 index 0000000..fb04e49 --- /dev/null +++ b/src/shared/acl-util.c @@ -0,0 +1,154 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011,2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "acl-util.h" +#include "util.h" +#include "strv.h" + +int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { + acl_entry_t i; + int found; + + assert(acl); + assert(entry); + + for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + found > 0; + found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + + acl_tag_t tag; + uid_t *u; + bool b; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (tag != ACL_USER) + continue; + + u = acl_get_qualifier(i); + if (!u) + return -errno; + + b = *u == uid; + acl_free(u); + + if (b) { + *entry = i; + return 1; + } + } + + if (found < 0) + return -errno; + + return 0; +} + +int calc_acl_mask_if_needed(acl_t *acl_p) { + acl_entry_t i; + int found; + + assert(acl_p); + + for (found = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + found > 0; + found = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + + acl_tag_t tag; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (tag == ACL_MASK) + return 0; + } + + if (found < 0) + return -errno; + + if (acl_calc_mask(acl_p) < 0) + return -errno; + + return 0; +} + +int search_acl_groups(char*** dst, const char* path, bool* belong) { + acl_t acl; + + assert(path); + assert(belong); + + acl = acl_get_file(path, ACL_TYPE_DEFAULT); + if (acl) { + acl_entry_t entry; + int r; + + r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + while (r > 0) { + acl_tag_t tag; + gid_t *gid; + char *name; + + r = acl_get_tag_type(entry, &tag); + if (r < 0) + break; + + if (tag != ACL_GROUP) + goto next; + + gid = acl_get_qualifier(entry); + if (!gid) + break; + + if (in_gid(*gid) > 0) { + *belong = true; + break; + } + + name = gid_to_name(*gid); + if (!name) { + acl_free(acl); + return log_oom(); + } + + r = strv_push(dst, name); + if (r < 0) { + free(name); + acl_free(acl); + return log_oom(); + } + + next: + r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + } + + acl_free(acl); + } + + return 0; +} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h new file mode 100644 index 0000000..36ef490 --- /dev/null +++ b/src/shared/acl-util.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); +int calc_acl_mask_if_needed(acl_t *acl_p); +int search_acl_groups(char*** dst, const char* path, bool* belong); diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c new file mode 100644 index 0000000..390c323 --- /dev/null +++ b/src/shared/acpi-fpdt.c @@ -0,0 +1,162 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct acpi_table_header { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table_id[8]; + uint32_t oem_revision; + char asl_compiler_id[4]; + uint32_t asl_compiler_revision; +}; + +enum { + ACPI_FPDT_TYPE_BOOT = 0, + ACPI_FPDT_TYPE_S3PERF = 1, +}; + +struct acpi_fpdt_header { + uint16_t type; + uint8_t length; + uint8_t revision; + uint8_t reserved[4]; + uint64_t ptr; +}; + +struct acpi_fpdt_boot_header { + char signature[4]; + uint32_t length; +}; + +enum { + ACPI_FPDT_S3PERF_RESUME_REC = 0, + ACPI_FPDT_S3PERF_SUSPEND_REC = 1, + ACPI_FPDT_BOOT_REC = 2, +}; + +struct acpi_fpdt_boot { + uint16_t type; + uint8_t length; + uint8_t revision; + uint8_t reserved[4]; + uint64_t reset_end; + uint64_t load_start; + uint64_t startup_start; + uint64_t exit_services_entry; + uint64_t exit_services_exit; +}; + +int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { + _cleanup_free_ char *buf = NULL; + struct acpi_table_header *tbl; + size_t l = 0; + struct acpi_fpdt_header *rec; + int r; + uint64_t ptr = 0; + _cleanup_close_ int fd = -1; + struct acpi_fpdt_boot_header hbrec; + struct acpi_fpdt_boot brec; + + r = read_full_file("/sys/firmware/acpi/tables/FPDT", &buf, &l); + if (r < 0) + return r; + + if (l < sizeof(struct acpi_table_header) + sizeof(struct acpi_fpdt_header)) + return -EINVAL; + + tbl = (struct acpi_table_header *)buf; + if (l != tbl->length) + return -EINVAL; + + if (memcmp(tbl->signature, "FPDT", 4) != 0) + return -EINVAL; + + /* find Firmware Basic Boot Performance Pointer Record */ + for (rec = (struct acpi_fpdt_header *)(buf + sizeof(struct acpi_table_header)); + (char *)rec < buf + l; + rec = (struct acpi_fpdt_header *)((char *)rec + rec->length)) { + if (rec->length <= 0) + break; + if (rec->type != ACPI_FPDT_TYPE_BOOT) + continue; + if (rec->length != sizeof(struct acpi_fpdt_header)) + continue; + + ptr = rec->ptr; + break; + } + + if (ptr == 0) + return -EINVAL; + + /* read Firmware Basic Boot Performance Data Record */ + fd = open("/dev/mem", O_CLOEXEC|O_RDONLY); + if (fd < 0) + return -errno; + + l = pread(fd, &hbrec, sizeof(struct acpi_fpdt_boot_header), ptr); + if (l != sizeof(struct acpi_fpdt_boot_header)) + return -EINVAL; + + if (memcmp(hbrec.signature, "FBPT", 4) != 0) + return -EINVAL; + + if (hbrec.length < sizeof(struct acpi_fpdt_boot_header) + sizeof(struct acpi_fpdt_boot)) + return -EINVAL; + + l = pread(fd, &brec, sizeof(struct acpi_fpdt_boot), ptr + sizeof(struct acpi_fpdt_boot_header)); + if (l != sizeof(struct acpi_fpdt_boot)) + return -EINVAL; + + if (brec.length != sizeof(struct acpi_fpdt_boot)) + return -EINVAL; + + if (brec.type != ACPI_FPDT_BOOT_REC) + return -EINVAL; + + if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start) + return -EINVAL; + if (brec.exit_services_exit > NSEC_PER_HOUR) + return -EINVAL; + + if (loader_start) + *loader_start = brec.startup_start / 1000; + if (loader_exit) + *loader_exit = brec.exit_services_exit / 1000; + + return 0; +} diff --git a/src/shared/acpi-fpdt.h b/src/shared/acpi-fpdt.h new file mode 100644 index 0000000..fc4fe6f --- /dev/null +++ b/src/shared/acpi-fpdt.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit); diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c new file mode 100644 index 0000000..2b85da1 --- /dev/null +++ b/src/shared/apparmor-util.c @@ -0,0 +1,41 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "fileio.h" +#include "apparmor-util.h" + +static int use_apparmor_cached = -1; + +bool use_apparmor(void) { + + if (use_apparmor_cached < 0) { + _cleanup_free_ char *p = NULL; + + use_apparmor_cached = + read_one_line_file("/sys/module/apparmor/parameters/enabled", &p) >= 0 && + parse_boolean(p) > 0; + } + + return use_apparmor_cached; +} diff --git a/src/shared/apparmor-util.h b/src/shared/apparmor-util.h new file mode 100644 index 0000000..4b056a1 --- /dev/null +++ b/src/shared/apparmor-util.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +bool use_apparmor(void); diff --git a/src/shared/architecture.c b/src/shared/architecture.c new file mode 100644 index 0000000..ceba492 --- /dev/null +++ b/src/shared/architecture.c @@ -0,0 +1,163 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "architecture.h" + +Architecture uname_architecture(void) { + + /* Return a sanitized enum identifying the architecture we are + * running on. This is based on uname(), and the user may + * hence control what this returns by using + * personality(). This puts the user in control on systems + * that can run binaries of multiple architectures. + * + * We do not translate the string returned by uname() + * 1:1. Instead we try to clean it up and break down the + * confusion on x86 and arm in particular. + * + * We do not try to distuingish CPUs not CPU features, but + * actual architectures, i.e. that have genuinely different + * code. */ + + static const struct { + const char *machine; + Architecture arch; + } arch_map[] = { +#if defined(__x86_64__) || defined(__i386__) + { "x86_64", ARCHITECTURE_X86_64 }, + { "i686", ARCHITECTURE_X86 }, + { "i586", ARCHITECTURE_X86 }, + { "i486", ARCHITECTURE_X86 }, + { "i386", ARCHITECTURE_X86 }, +#elif defined(__powerpc__) || defined(__powerpc64__) + { "ppc64", ARCHITECTURE_PPC64 }, + { "ppc64le", ARCHITECTURE_PPC64_LE }, + { "ppc", ARCHITECTURE_PPC }, + { "ppcle", ARCHITECTURE_PPC_LE }, +#elif defined(__ia64__) + { "ia64", ARCHITECTURE_IA64 }, +#elif defined(__hppa__) || defined(__hppa64__) + { "parisc64", ARCHITECTURE_PARISC64 }, + { "parisc", ARCHITECTURE_PARISC }, +#elif defined(__s390__) || defined(__s390x__) + { "s390x", ARCHITECTURE_S390X }, + { "s390", ARCHITECTURE_S390 }, +#elif defined(__sparc__) || defined(__sparc64__) + { "sparc64", ARCHITECTURE_SPARC64 }, + { "sparc", ARCHITECTURE_SPARC }, +#elif defined(__mips__) || defined(__mips64__) + { "mips64", ARCHITECTURE_MIPS64 }, + { "mips", ARCHITECTURE_MIPS }, +#elif defined(__alpha__) + { "alpha" , ARCHITECTURE_ALPHA }, +#elif defined(__arm__) || defined(__aarch64__) + { "aarch64", ARCHITECTURE_ARM64 }, + { "aarch64_be", ARCHITECTURE_ARM64_BE }, + { "armv4l", ARCHITECTURE_ARM }, + { "armv4b", ARCHITECTURE_ARM_BE }, + { "armv4tl", ARCHITECTURE_ARM }, + { "armv4tb", ARCHITECTURE_ARM_BE }, + { "armv5tl", ARCHITECTURE_ARM }, + { "armv5tb", ARCHITECTURE_ARM_BE }, + { "armv5tel", ARCHITECTURE_ARM }, + { "armv5teb" , ARCHITECTURE_ARM_BE }, + { "armv5tejl", ARCHITECTURE_ARM }, + { "armv5tejb", ARCHITECTURE_ARM_BE }, + { "armv6l", ARCHITECTURE_ARM }, + { "armv6b", ARCHITECTURE_ARM_BE }, + { "armv7l", ARCHITECTURE_ARM }, + { "armv7b", ARCHITECTURE_ARM_BE }, + { "armv7ml", ARCHITECTURE_ARM }, + { "armv7mb", ARCHITECTURE_ARM_BE }, + { "armv4l", ARCHITECTURE_ARM }, + { "armv4b", ARCHITECTURE_ARM_BE }, + { "armv4tl", ARCHITECTURE_ARM }, + { "armv4tb", ARCHITECTURE_ARM_BE }, + { "armv5tl", ARCHITECTURE_ARM }, + { "armv5tb", ARCHITECTURE_ARM_BE }, + { "armv5tel", ARCHITECTURE_ARM }, + { "armv5teb", ARCHITECTURE_ARM_BE }, + { "armv5tejl", ARCHITECTURE_ARM }, + { "armv5tejb", ARCHITECTURE_ARM_BE }, + { "armv6l", ARCHITECTURE_ARM }, + { "armv6b", ARCHITECTURE_ARM_BE }, + { "armv7l", ARCHITECTURE_ARM }, + { "armv7b", ARCHITECTURE_ARM_BE }, + { "armv7ml", ARCHITECTURE_ARM }, + { "armv7mb", ARCHITECTURE_ARM_BE }, + { "armv8l", ARCHITECTURE_ARM }, + { "armv8b", ARCHITECTURE_ARM_BE }, +#elif defined(__sh__) || defined(__sh64__) + { "sh64", ARCHITECTURE_SH64 }, + { "sh", ARCHITECTURE_SH }, +#elif defined(__m68k__) + { "m68k", ARCHITECTURE_M68K }, +#else +#error "Please register your architecture here!" +#endif + }; + + static Architecture cached = _ARCHITECTURE_INVALID; + struct utsname u; + unsigned i; + + if (cached != _ARCHITECTURE_INVALID) + return cached; + + assert_se(uname(&u) >= 0); + + for (i = 0; i < ELEMENTSOF(arch_map); i++) + if (streq(arch_map[i].machine, u.machine)) + return cached = arch_map[i].arch; + + assert_not_reached("Couldn't identify architecture. You need to patch systemd."); + return _ARCHITECTURE_INVALID; +} + +static const char *const architecture_table[_ARCHITECTURE_MAX] = { + [ARCHITECTURE_X86] = "x86", + [ARCHITECTURE_X86_64] = "x86-64", + [ARCHITECTURE_PPC] = "ppc", + [ARCHITECTURE_PPC_LE] = "ppc-le", + [ARCHITECTURE_PPC64] = "ppc64", + [ARCHITECTURE_PPC64_LE] = "ppc64-le", + [ARCHITECTURE_IA64] = "ia64", + [ARCHITECTURE_PARISC] = "parisc", + [ARCHITECTURE_PARISC64] = "parisc64", + [ARCHITECTURE_S390] = "s390", + [ARCHITECTURE_S390X] = "s390x", + [ARCHITECTURE_SPARC] = "sparc", + [ARCHITECTURE_SPARC64] = "sparc64", + [ARCHITECTURE_MIPS] = "mips", + [ARCHITECTURE_MIPS64] = "mips64", + [ARCHITECTURE_ALPHA] = "alpha", + [ARCHITECTURE_ARM] = "arm", + [ARCHITECTURE_ARM_BE] = "arm-be", + [ARCHITECTURE_ARM64] = "arm64", + [ARCHITECTURE_ARM64_BE] = "arm64-be", + [ARCHITECTURE_SH] = "sh", + [ARCHITECTURE_SH64] = "sh64", + [ARCHITECTURE_M68K] = "m68k", +}; + +DEFINE_STRING_TABLE_LOOKUP(architecture, Architecture); diff --git a/src/shared/architecture.h b/src/shared/architecture.h new file mode 100644 index 0000000..3183645 --- /dev/null +++ b/src/shared/architecture.h @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +typedef enum Architecture { + ARCHITECTURE_X86 = 0, + ARCHITECTURE_X86_64, + ARCHITECTURE_PPC, + ARCHITECTURE_PPC_LE, + ARCHITECTURE_PPC64, + ARCHITECTURE_PPC64_LE, + ARCHITECTURE_IA64, + ARCHITECTURE_PARISC, + ARCHITECTURE_PARISC64, + ARCHITECTURE_S390, + ARCHITECTURE_S390X, + ARCHITECTURE_SPARC, + ARCHITECTURE_SPARC64, + ARCHITECTURE_MIPS, + ARCHITECTURE_MIPS64, + ARCHITECTURE_ALPHA, + ARCHITECTURE_ARM, + ARCHITECTURE_ARM_BE, + ARCHITECTURE_ARM64, + ARCHITECTURE_ARM64_BE, + ARCHITECTURE_SH, + ARCHITECTURE_SH64, + ARCHITECTURE_M68K, + _ARCHITECTURE_MAX, + _ARCHITECTURE_INVALID = -1 +} Architecture; + +Architecture uname_architecture(void); + +#if defined(__x86_64__) +# define native_architecture() ARCHITECTURE_X86_64 +#elif defined(__i386__) +# define native_architecture() ARCHITECTURE_X86 +#elif defined(__powerpc64__) +# if defined(WORDS_BIGENDIAN) +# define native_architecture() ARCHITECTURE_PPC64 +# else +# define native_architecture() ARCHITECTURE_PPC64_LE +# endif +#elif defined(__powerpc__) +# if defined(WORDS_BIGENDIAN) +# define native_architecture() ARCHITECTURE_PPC +# else +# define native_architecture() ARCHITECTURE_PPC_LE +# endif +#elif defined(__ia64__) +# define native_architecture() ARCHITECTURE_IA64 +#elif defined(__hppa64__) +# define native_architecture() ARCHITECTURE_PARISC64 +#elif defined(__hppa__) +# define native_architecture() ARCHITECTURE_PARISC +#elif defined(__s390x__) +# define native_architecture() ARCHITECTURE_S390X +#elif defined(__s390__) +# define native_architecture() ARCHITECTURE_S390 +#elif defined(__sparc64__) +# define native_architecture() ARCHITECTURE_SPARC64 +#elif defined(__sparc__) +# define native_architecture() ARCHITECTURE_SPARC +#elif defined(__mips64__) +# define native_architecture() ARCHITECTURE_MIPS64 +#elif defined(__mips__) +# define native_architecture() ARCHITECTURE_MIPS +#elif defined(__alpha__) +# define native_architecture() ARCHITECTURE_ALPHA +#elif defined(__aarch64__) +# if defined(WORDS_BIGENDIAN) +# define native_architecture() ARCHITECTURE_ARM64_BE +# else +# define native_architecture() ARCHITECTURE_ARM64 +# endif +#elif defined(__arm__) +# if defined(WORDS_BIGENDIAN) +# define native_architecture() ARCHITECTURE_ARM_BE +# else +# define native_architecture() ARCHITECTURE_ARM +# endif +#elif defined(__sh64__) +# define native_architecture() ARCHITECTURE_SH64 +#elif defined(__sh__) +# define native_architecture() ARCHITECTURE_SH +#elif defined(__m68k__) +# define native_architecture() ARCHITECTURE_M68K +#else +#error "Please register your architecture here!" +#endif + +const char *architecture_to_string(Architecture a) _const_; +Architecture architecture_from_string(const char *s) _pure_; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c new file mode 100644 index 0000000..a328f14 --- /dev/null +++ b/src/shared/ask-password-api.c @@ -0,0 +1,573 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "strv.h" + +#include "ask-password-api.h" + +static void backspace_chars(int ttyfd, size_t p) { + + if (ttyfd < 0) + return; + + while (p > 0) { + p--; + + loop_write(ttyfd, "\b \b", 3, false); + } +} + +int ask_password_tty( + const char *message, + usec_t until, + const char *flag_file, + char **_passphrase) { + + struct termios old_termios, new_termios; + char passphrase[LINE_MAX]; + size_t p = 0; + int r, ttyfd = -1, notify = -1; + struct pollfd pollfd[2]; + bool reset_tty = false; + bool silent_mode = false; + bool dirty = false; + enum { + POLL_TTY, + POLL_INOTIFY + }; + + assert(message); + assert(_passphrase); + + if (flag_file) { + if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { + r = -errno; + goto finish; + } + } + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) { + + if (tcgetattr(ttyfd, &old_termios) < 0) { + r = -errno; + goto finish; + } + + loop_write(ttyfd, ANSI_HIGHLIGHT_ON, sizeof(ANSI_HIGHLIGHT_ON)-1, false); + loop_write(ttyfd, message, strlen(message), false); + loop_write(ttyfd, " ", 1, false); + loop_write(ttyfd, ANSI_HIGHLIGHT_OFF, sizeof(ANSI_HIGHLIGHT_OFF)-1, false); + + new_termios = old_termios; + new_termios.c_lflag &= ~(ICANON|ECHO); + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) { + r = -errno; + goto finish; + } + + reset_tty = true; + } + + zero(pollfd); + pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO; + pollfd[POLL_TTY].events = POLLIN; + pollfd[POLL_INOTIFY].fd = notify; + pollfd[POLL_INOTIFY].events = POLLIN; + + for (;;) { + char c; + int sleep_for = -1, k; + ssize_t n; + + if (until > 0) { + usec_t y; + + y = now(CLOCK_MONOTONIC); + + if (y > until) { + r = -ETIME; + goto finish; + } + + sleep_for = (int) ((until - y) / USEC_PER_MSEC); + } + + if (flag_file) + if (access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } + + if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } else if (k == 0) { + r = -ETIME; + goto finish; + } + + if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[POLL_TTY].revents == 0) + continue; + + if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + r = -errno; + goto finish; + + } else if (n == 0) + break; + + if (c == '\n') + break; + else if (c == 21) { /* C-u */ + + if (!silent_mode) + backspace_chars(ttyfd, p); + p = 0; + + } else if (c == '\b' || c == 127) { + + if (p > 0) { + + if (!silent_mode) + backspace_chars(ttyfd, 1); + + p--; + } else if (!dirty && !silent_mode) { + + silent_mode = true; + + /* There are two ways to enter silent + * mode. Either by pressing backspace + * as first key (and only as first key), + * or ... */ + if (ttyfd >= 0) + loop_write(ttyfd, "(no echo) ", 10, false); + + } else if (ttyfd >= 0) + loop_write(ttyfd, "\a", 1, false); + + } else if (c == '\t' && !silent_mode) { + + backspace_chars(ttyfd, p); + silent_mode = true; + + /* ... or by pressing TAB at any time. */ + + if (ttyfd >= 0) + loop_write(ttyfd, "(no echo) ", 10, false); + } else { + passphrase[p++] = c; + + if (!silent_mode && ttyfd >= 0) + loop_write(ttyfd, "*", 1, false); + + dirty = true; + } + } + + passphrase[p] = 0; + + if (!(*_passphrase = strdup(passphrase))) { + r = -ENOMEM; + goto finish; + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (ttyfd >= 0) { + + if (reset_tty) { + loop_write(ttyfd, "\n", 1, false); + tcsetattr(ttyfd, TCSADRAIN, &old_termios); + } + + close_nointr_nofail(ttyfd); + } + + return r; +} + +static int create_socket(char **name) { + int fd; + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa = { + .un.sun_family = AF_UNIX, + }; + int one = 1; + int r = 0; + char *c; + + assert(name); + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) { + log_error("socket() failed: %m"); + return -errno; + } + + snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()); + + RUN_WITH_UMASK(0177) { + r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + } + + if (r < 0) { + r = -errno; + log_error("bind() failed: %m"); + goto fail; + } + + if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { + r = -errno; + log_error("SO_PASSCRED failed: %m"); + goto fail; + } + + c = strdup(sa.un.sun_path); + if (!c) { + r = log_oom(); + goto fail; + } + + *name = c; + return fd; + +fail: + close_nointr_nofail(fd); + + return r; +} + +int ask_password_agent( + const char *message, + const char *icon, + usec_t until, + bool accept_cached, + char ***_passphrases) { + + enum { + FD_SOCKET, + FD_SIGNAL, + _FD_MAX + }; + + char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; + char final[sizeof(temp)] = ""; + int fd = -1, r; + FILE *f = NULL; + char *socket_name = NULL; + int socket_fd = -1, signal_fd = -1; + sigset_t mask, oldmask; + struct pollfd pollfd[_FD_MAX]; + + assert(_passphrases); + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); + + mkdir_p_label("/run/systemd/ask-password", 0755); + + fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to create password file: %m"); + r = -errno; + goto finish; + } + + fchmod(fd, 0644); + + if (!(f = fdopen(fd, "w"))) { + log_error("Failed to allocate FILE: %m"); + r = -errno; + goto finish; + } + + fd = -1; + + if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { + log_error("signalfd(): %m"); + r = -errno; + goto finish; + } + + if ((socket_fd = create_socket(&socket_name)) < 0) { + r = socket_fd; + goto finish; + } + + fprintf(f, + "[Ask]\n" + "PID=%lu\n" + "Socket=%s\n" + "AcceptCached=%i\n" + "NotAfter=%llu\n", + (unsigned long) getpid(), + socket_name, + accept_cached ? 1 : 0, + (unsigned long long) until); + + if (message) + fprintf(f, "Message=%s\n", message); + + if (icon) + fprintf(f, "Icon=%s\n", icon); + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write query file: %m"); + r = -errno; + goto finish; + } + + memcpy(final, temp, sizeof(temp)); + + final[sizeof(final)-11] = 'a'; + final[sizeof(final)-10] = 's'; + final[sizeof(final)-9] = 'k'; + + if (rename(temp, final) < 0) { + log_error("Failed to rename query file: %m"); + r = -errno; + goto finish; + } + + zero(pollfd); + pollfd[FD_SOCKET].fd = socket_fd; + pollfd[FD_SOCKET].events = POLLIN; + pollfd[FD_SIGNAL].fd = signal_fd; + pollfd[FD_SIGNAL].events = POLLIN; + + for (;;) { + char passphrase[LINE_MAX+1]; + struct msghdr msghdr; + struct iovec iovec; + struct ucred *ucred; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + ssize_t n; + int k; + usec_t t; + + t = now(CLOCK_MONOTONIC); + + if (until > 0 && until <= t) { + log_notice("Timed out"); + r = -ETIME; + goto finish; + } + + if ((k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1)) < 0) { + + if (errno == EINTR) + continue; + + log_error("poll() failed: %m"); + r = -errno; + goto finish; + } + + if (k <= 0) { + log_notice("Timed out"); + r = -ETIME; + goto finish; + } + + if (pollfd[FD_SIGNAL].revents & POLLIN) { + r = -EINTR; + goto finish; + } + + if (pollfd[FD_SOCKET].revents != POLLIN) { + log_error("Unexpected poll() event."); + r = -EIO; + goto finish; + } + + zero(iovec); + iovec.iov_base = passphrase; + iovec.iov_len = sizeof(passphrase); + + zero(control); + zero(msghdr); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = &control; + msghdr.msg_controllen = sizeof(control); + + if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) { + + if (errno == EAGAIN || + errno == EINTR) + continue; + + log_error("recvmsg() failed: %m"); + r = -errno; + goto finish; + } + + if (n <= 0) { + log_error("Message too short"); + continue; + } + + if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || + control.cmsghdr.cmsg_level != SOL_SOCKET || + control.cmsghdr.cmsg_type != SCM_CREDENTIALS || + control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { + log_warning("Received message without credentials. Ignoring."); + continue; + } + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + if (ucred->uid != 0) { + log_warning("Got request from unprivileged user. Ignoring."); + continue; + } + + if (passphrase[0] == '+') { + char **l; + + if (n == 1) + l = strv_new("", NULL); + else + l = strv_parse_nulstr(passphrase+1, n-1); + /* An empty message refers to the empty password */ + + if (!l) { + r = -ENOMEM; + goto finish; + } + + if (strv_length(l) <= 0) { + strv_free(l); + log_error("Invalid packet"); + continue; + } + + *_passphrases = l; + + } else if (passphrase[0] == '-') { + r = -ECANCELED; + goto finish; + } else { + log_error("Invalid packet"); + continue; + } + + break; + } + + r = 0; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + if (socket_name) { + unlink(socket_name); + free(socket_name); + } + + if (socket_fd >= 0) + close_nointr_nofail(socket_fd); + + if (signal_fd >= 0) + close_nointr_nofail(signal_fd); + + if (f) + fclose(f); + + unlink(temp); + + if (final[0]) + unlink(final); + + assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); + + return r; +} + +int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) { + assert(message); + assert(_passphrases); + + if (isatty(STDIN_FILENO)) { + int r; + char *s = NULL, **l = NULL; + + if ((r = ask_password_tty(message, until, NULL, &s)) < 0) + return r; + + l = strv_new(s, NULL); + free(s); + + if (!l) + return -ENOMEM; + + *_passphrases = l; + return r; + + } else + return ask_password_agent(message, icon, until, accept_cached, _passphrases); +} diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h new file mode 100644 index 0000000..288a0f4 --- /dev/null +++ b/src/shared/ask-password-api.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase); + +int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); + +int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); diff --git a/src/shared/audit.c b/src/shared/audit.c new file mode 100644 index 0000000..5466447 --- /dev/null +++ b/src/shared/audit.c @@ -0,0 +1,85 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "audit.h" +#include "util.h" +#include "log.h" +#include "fileio.h" +#include "virt.h" + +int audit_session_from_pid(pid_t pid, uint32_t *id) { + _cleanup_free_ char *s = NULL; + const char *p; + uint32_t u; + int r; + + assert(id); + + p = procfs_file_alloca(pid, "sessionid"); + + r = read_one_line_file(p, &s); + if (r < 0) + return r; + + r = safe_atou32(s, &u); + if (r < 0) + return r; + + if (u == (uint32_t) -1 || u <= 0) + return -ENXIO; + + *id = u; + return 0; +} + +int audit_loginuid_from_pid(pid_t pid, uid_t *uid) { + _cleanup_free_ char *s = NULL; + const char *p; + uid_t u; + int r; + + assert(uid); + + p = procfs_file_alloca(pid, "loginuid"); + + r = read_one_line_file(p, &s); + if (r < 0) + return r; + + r = parse_uid(s, &u); + if (r < 0) + return r; + + if (u == (uid_t) -1) + return -ENXIO; + + *uid = (uid_t) u; + return 0; +} diff --git a/src/shared/audit.h b/src/shared/audit.h new file mode 100644 index 0000000..0effc0b --- /dev/null +++ b/src/shared/audit.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "capability.h" + +int audit_session_from_pid(pid_t pid, uint32_t *id); +int audit_loginuid_from_pid(pid_t pid, uid_t *uid); diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c new file mode 100644 index 0000000..54e0537 --- /dev/null +++ b/src/shared/boot-timestamps.c @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include + +#include "boot-timestamps.h" +#include "acpi-fpdt.h" +#include "efivars.h" + +int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) { + usec_t x = 0, y = 0, a; + int r; + dual_timestamp _n; + + assert(firmware); + assert(loader); + + if (!n) { + dual_timestamp_get(&_n); + n = &_n; + } + + r = acpi_get_boot_usec(&x, &y); + if (r < 0) { +#ifdef ENABLE_EFI + r = efi_loader_get_boot_usec(&x, &y); + if (r < 0) +#endif + return r; + } + + /* Let's convert this to timestamps where the firmware + * began/loader began working. To make this more confusing: + * since usec_t is unsigned and the kernel's monotonic clock + * begins at kernel initialization we'll actually initialize + * the monotonic timestamps here as negative of the actual + * value. */ + + firmware->monotonic = y; + loader->monotonic = y - x; + + a = n->monotonic + firmware->monotonic; + firmware->realtime = n->realtime > a ? n->realtime - a : 0; + + a = n->monotonic + loader->monotonic; + loader->realtime = n->realtime > a ? n->realtime - a : 0; + + return 0; +} diff --git a/src/shared/boot-timestamps.h b/src/shared/boot-timestamps.h new file mode 100644 index 0000000..a3d2405 --- /dev/null +++ b/src/shared/boot-timestamps.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader); diff --git a/src/shared/bus-errors.h b/src/shared/bus-errors.h new file mode 100644 index 0000000..5637935 --- /dev/null +++ b/src/shared/bus-errors.h @@ -0,0 +1,58 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" +#define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" +#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" +#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" +#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" +#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" +#define BUS_ERROR_ALREADY_SUBSCRIBED "org.freedesktop.systemd1.AlreadySubscribed" +#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" +#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting" +#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" +#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" +#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" +#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" +#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" +#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" +#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" + +#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" +#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" +#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" + +#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" +#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" +#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" +#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID" +#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat" +#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat" +#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl" +#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken" +#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" +#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" +#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" + +#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" diff --git a/src/shared/bus-label.c b/src/shared/bus-label.c new file mode 100644 index 0000000..61eb75b --- /dev/null +++ b/src/shared/bus-label.c @@ -0,0 +1,102 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "def.h" + +#include "bus-label.h" + +char *bus_label_escape(const char *s) { + char *r, *t; + const char *f; + + assert_return(s, NULL); + + /* Escapes all chars that D-Bus' object path cannot deal + * with. Can be reversed with bus_path_unescape(). We special + * case the empty string. */ + + if (*s == 0) + return strdup("_"); + + r = new(char, strlen(s)*3 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + /* Escape everything that is not a-zA-Z0-9. We also + * escape 0-9 if it's the first character */ + + if (!(*f >= 'A' && *f <= 'Z') && + !(*f >= 'a' && *f <= 'z') && + !(f > s && *f >= '0' && *f <= '9')) { + *(t++) = '_'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +char *bus_label_unescape(const char *f) { + char *r, *t; + + assert_return(f, NULL); + + /* Special case for the empty string */ + if (streq(f, "_")) + return strdup(""); + + r = new(char, strlen(f) + 1); + if (!r) + return NULL; + + for (t = r; *f; f++) { + + if (*f == '_') { + int a, b; + + if ((a = unhexchar(f[1])) < 0 || + (b = unhexchar(f[2])) < 0) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '_'; + } else { + *(t++) = (char) ((a << 4) | b); + f += 2; + } + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} diff --git a/src/shared/bus-label.h b/src/shared/bus-label.h new file mode 100644 index 0000000..c27c851 --- /dev/null +++ b/src/shared/bus-label.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +char *bus_label_escape(const char *s); +char *bus_label_unescape(const char *f); diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c new file mode 100644 index 0000000..7075159 --- /dev/null +++ b/src/shared/calendarspec.c @@ -0,0 +1,944 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "calendarspec.h" + +static void free_chain(CalendarComponent *c) { + CalendarComponent *n; + + while (c) { + n = c->next; + free(c); + c = n; + } +} + +void calendar_spec_free(CalendarSpec *c) { + assert(c); + + free_chain(c->year); + free_chain(c->month); + free_chain(c->day); + free_chain(c->hour); + free_chain(c->minute); + free_chain(c->second); + + free(c); +} + +static int component_compare(const void *_a, const void *_b) { + CalendarComponent * const *a = _a, * const *b = _b; + + if ((*a)->value < (*b)->value) + return -1; + if ((*a)->value > (*b)->value) + return 1; + + if ((*a)->repeat < (*b)->repeat) + return -1; + if ((*a)->repeat > (*b)->repeat) + return 1; + + return 0; +} + +static void sort_chain(CalendarComponent **c) { + unsigned n = 0, k; + CalendarComponent **b, *i, **j, *next; + + assert(c); + + for (i = *c; i; i = i->next) + n++; + + if (n <= 1) + return; + + j = b = alloca(sizeof(CalendarComponent*) * n); + for (i = *c; i; i = i->next) + *(j++) = i; + + qsort(b, n, sizeof(CalendarComponent*), component_compare); + + b[n-1]->next = NULL; + next = b[n-1]; + + /* Drop non-unique entries */ + for (k = n-1; k > 0; k--) { + if (b[k-1]->value == next->value && + b[k-1]->repeat == next->repeat) { + free(b[k-1]); + continue; + } + + b[k-1]->next = next; + next = b[k-1]; + } + + *c = next; +} + +static void fix_year(CalendarComponent *c) { + /* Turns 12 → 2012, 89 → 1989 */ + + while(c) { + CalendarComponent *n = c->next; + + if (c->value >= 0 && c->value < 70) + c->value += 2000; + + if (c->value >= 70 && c->value < 100) + c->value += 1900; + + c = n; + } +} + +int calendar_spec_normalize(CalendarSpec *c) { + assert(c); + + if (c->weekdays_bits <= 0 || c->weekdays_bits >= 127) + c->weekdays_bits = -1; + + fix_year(c->year); + + sort_chain(&c->year); + sort_chain(&c->month); + sort_chain(&c->day); + sort_chain(&c->hour); + sort_chain(&c->minute); + sort_chain(&c->second); + + return 0; +} + +_pure_ static bool chain_valid(CalendarComponent *c, int from, int to) { + if (!c) + return true; + + if (c->value < from || c->value > to) + return false; + + if (c->value + c->repeat > to) + return false; + + if (c->next) + return chain_valid(c->next, from, to); + + return true; +} + +_pure_ bool calendar_spec_valid(CalendarSpec *c) { + assert(c); + + if (c->weekdays_bits > 127) + return false; + + if (!chain_valid(c->year, 1970, 2199)) + return false; + + if (!chain_valid(c->month, 1, 12)) + return false; + + if (!chain_valid(c->day, 1, 31)) + return false; + + if (!chain_valid(c->hour, 0, 23)) + return false; + + if (!chain_valid(c->minute, 0, 59)) + return false; + + if (!chain_valid(c->second, 0, 59)) + return false; + + return true; +} + +static void format_weekdays(FILE *f, const CalendarSpec *c) { + static const char *const days[] = { + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun" + }; + + int l, x; + bool need_colon = false; + + assert(f); + assert(c); + assert(c->weekdays_bits > 0 && c->weekdays_bits <= 127); + + for (x = 0, l = -1; x < (int) ELEMENTSOF(days); x++) { + + if (c->weekdays_bits & (1 << x)) { + + if (l < 0) { + if (need_colon) + fputc(',', f); + else + need_colon = true; + + fputs(days[x], f); + l = x; + } + + } else if (l >= 0) { + + if (x > l + 1) { + fputc(x > l + 2 ? '-' : ',', f); + fputs(days[x-1], f); + } + + l = -1; + } + } + + if (l >= 0 && x > l + 1) { + fputc(x > l + 2 ? '-' : ',', f); + fputs(days[x-1], f); + } +} + +static void format_chain(FILE *f, int space, const CalendarComponent *c) { + assert(f); + + if (!c) { + fputc('*', f); + return; + } + + assert(c->value >= 0); + fprintf(f, "%0*i", space, c->value); + + if (c->repeat > 0) + fprintf(f, "/%i", c->repeat); + + if (c->next) { + fputc(',', f); + format_chain(f, space, c->next); + } +} + +int calendar_spec_to_string(const CalendarSpec *c, char **p) { + char *buf = NULL; + size_t sz = 0; + FILE *f; + + assert(c); + assert(p); + + f = open_memstream(&buf, &sz); + if (!f) + return -ENOMEM; + + if (c->weekdays_bits > 0 && c->weekdays_bits <= 127) { + format_weekdays(f, c); + fputc(' ', f); + } + + format_chain(f, 4, c->year); + fputc('-', f); + format_chain(f, 2, c->month); + fputc('-', f); + format_chain(f, 2, c->day); + fputc(' ', f); + format_chain(f, 2, c->hour); + fputc(':', f); + format_chain(f, 2, c->minute); + fputc(':', f); + format_chain(f, 2, c->second); + + fflush(f); + + if (ferror(f)) { + free(buf); + fclose(f); + return -ENOMEM; + } + + fclose(f); + + *p = buf; + return 0; +} + +static int parse_weekdays(const char **p, CalendarSpec *c) { + static const struct { + const char *name; + const int nr; + } day_nr[] = { + { "Monday", 0 }, + { "Mon", 0 }, + { "Tuesday", 1 }, + { "Tue", 1 }, + { "Wednesday", 2 }, + { "Wed", 2 }, + { "Thursday", 3 }, + { "Thu", 3 }, + { "Friday", 4 }, + { "Fri", 4 }, + { "Saturday", 5 }, + { "Sat", 5 }, + { "Sunday", 6 }, + { "Sun", 6 } + }; + + int l = -1; + bool first = true; + + assert(p); + assert(*p); + assert(c); + + for (;;) { + unsigned i; + + if (!first && **p == ' ') + return 0; + + for (i = 0; i < ELEMENTSOF(day_nr); i++) { + size_t skip; + + if (!startswith_no_case(*p, day_nr[i].name)) + continue; + + skip = strlen(day_nr[i].name); + + if ((*p)[skip] != '-' && + (*p)[skip] != ',' && + (*p)[skip] != ' ' && + (*p)[skip] != 0) + return -EINVAL; + + c->weekdays_bits |= 1 << day_nr[i].nr; + + if (l >= 0) { + int j; + + if (l > day_nr[i].nr) + return -EINVAL; + + for (j = l + 1; j < day_nr[i].nr; j++) + c->weekdays_bits |= 1 << j; + } + + *p += skip; + break; + } + + /* Couldn't find this prefix, so let's assume the + weekday was not specified and let's continue with + the date */ + if (i >= ELEMENTSOF(day_nr)) + return first ? 0 : -EINVAL; + + /* We reached the end of the string */ + if (**p == 0) + return 0; + + /* We reached the end of the weekday spec part */ + if (**p == ' ') { + *p += strspn(*p, " "); + return 0; + } + + if (**p == '-') { + if (l >= 0) + return -EINVAL; + + l = day_nr[i].nr; + } else + l = -1; + + *p += 1; + first = false; + } +} + +static int prepend_component(const char **p, CalendarComponent **c) { + unsigned long value, repeat = 0; + char *e = NULL, *ee = NULL; + CalendarComponent *cc; + + assert(p); + assert(c); + + errno = 0; + value = strtoul(*p, &e, 10); + if (errno > 0) + return -errno; + if (e == *p) + return -EINVAL; + if ((unsigned long) (int) value != value) + return -ERANGE; + + if (*e == '/') { + repeat = strtoul(e+1, &ee, 10); + if (errno > 0) + return -errno; + if (ee == e+1) + return -EINVAL; + if ((unsigned long) (int) repeat != repeat) + return -ERANGE; + if (repeat <= 0) + return -ERANGE; + + e = ee; + } + + if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':') + return -EINVAL; + + cc = new0(CalendarComponent, 1); + if (!cc) + return -ENOMEM; + + cc->value = value; + cc->repeat = repeat; + cc->next = *c; + + *p = e; + *c = cc; + + if (*e ==',') { + *p += 1; + return prepend_component(p, c); + } + + return 0; +} + +static int parse_chain(const char **p, CalendarComponent **c) { + const char *t; + CalendarComponent *cc = NULL; + int r; + + assert(p); + assert(c); + + t = *p; + + if (t[0] == '*') { + *p = t + 1; + *c = NULL; + return 0; + } + + r = prepend_component(&t, &cc); + if (r < 0) { + free_chain(cc); + return r; + } + + *p = t; + *c = cc; + return 0; +} + +static int const_chain(int value, CalendarComponent **c) { + CalendarComponent *cc = NULL; + + assert(c); + + cc = new0(CalendarComponent, 1); + if (!cc) + return -ENOMEM; + + cc->value = value; + cc->repeat = 0; + cc->next = NULL; + + *c = cc; + + return 0; +} + +static int parse_date(const char **p, CalendarSpec *c) { + const char *t; + int r; + CalendarComponent *first, *second, *third; + + assert(p); + assert(*p); + assert(c); + + t = *p; + + if (*t == 0) + return 0; + + r = parse_chain(&t, &first); + if (r < 0) + return r; + + /* Already the end? A ':' as separator? In that case this was a time, not a date */ + if (*t == 0 || *t == ':') { + free_chain(first); + return 0; + } + + if (*t != '-') { + free_chain(first); + return -EINVAL; + } + + t++; + r = parse_chain(&t, &second); + if (r < 0) { + free_chain(first); + return r; + } + + /* Got two parts, hence it's month and day */ + if (*t == ' ' || *t == 0) { + *p = t + strspn(t, " "); + c->month = first; + c->day = second; + return 0; + } + + if (*t != '-') { + free_chain(first); + free_chain(second); + return -EINVAL; + } + + t++; + r = parse_chain(&t, &third); + if (r < 0) { + free_chain(first); + free_chain(second); + return r; + } + + /* Got tree parts, hence it is year, month and day */ + if (*t == ' ' || *t == 0) { + *p = t + strspn(t, " "); + c->year = first; + c->month = second; + c->day = third; + return 0; + } + + free_chain(first); + free_chain(second); + free_chain(third); + return -EINVAL; +} + +static int parse_time(const char **p, CalendarSpec *c) { + CalendarComponent *h = NULL, *m = NULL, *s = NULL; + const char *t; + int r; + + assert(p); + assert(*p); + assert(c); + + t = *p; + + if (*t == 0) { + /* If no time is specified at all, but a date of some + * kind, then this means 00:00:00 */ + if (c->day || c->weekdays_bits > 0) + goto null_hour; + + goto finish; + } + + r = parse_chain(&t, &h); + if (r < 0) + goto fail; + + if (*t != ':') { + r = -EINVAL; + goto fail; + } + + t++; + r = parse_chain(&t, &m); + if (r < 0) + goto fail; + + /* Already at the end? Then it's hours and minutes, and seconds are 0 */ + if (*t == 0) { + if (m != NULL) + goto null_second; + + goto finish; + } + + if (*t != ':') { + r = -EINVAL; + goto fail; + } + + t++; + r = parse_chain(&t, &s); + if (r < 0) + goto fail; + + /* At the end? Then it's hours, minutes and seconds */ + if (*t == 0) + goto finish; + + r = -EINVAL; + goto fail; + +null_hour: + r = const_chain(0, &h); + if (r < 0) + goto fail; + + r = const_chain(0, &m); + if (r < 0) + goto fail; + +null_second: + r = const_chain(0, &s); + if (r < 0) + goto fail; + +finish: + *p = t; + c->hour = h; + c->minute = m; + c->second = 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) { + CalendarSpec *c; + int r; + + assert(p); + assert(spec); + + if (isempty(p)) + return -EINVAL; + + c = new0(CalendarSpec, 1); + if (!c) + return -ENOMEM; + + if (strcaseeq(p, "hourly")) { + r = const_chain(0, &c->minute); + if (r < 0) + goto fail; + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else if (strcaseeq(p, "daily")) { + r = const_chain(0, &c->hour); + if (r < 0) + goto fail; + r = const_chain(0, &c->minute); + if (r < 0) + goto fail; + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else if (strcaseeq(p, "monthly")) { + r = const_chain(1, &c->day); + if (r < 0) + goto fail; + r = const_chain(0, &c->hour); + if (r < 0) + goto fail; + r = const_chain(0, &c->minute); + if (r < 0) + goto fail; + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else if (strcaseeq(p, "anually") || strcaseeq(p, "yearly")) { + r = const_chain(1, &c->month); + if (r < 0) + goto fail; + r = const_chain(1, &c->day); + if (r < 0) + goto fail; + r = const_chain(0, &c->hour); + if (r < 0) + goto fail; + r = const_chain(0, &c->minute); + if (r < 0) + goto fail; + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else if (strcaseeq(p, "weekly")) { + + c->weekdays_bits = 1; + + r = const_chain(0, &c->hour); + if (r < 0) + goto fail; + r = const_chain(0, &c->minute); + if (r < 0) + goto fail; + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else { + r = parse_weekdays(&p, c); + if (r < 0) + goto fail; + + r = parse_date(&p, c); + if (r < 0) + goto fail; + + r = parse_time(&p, c); + if (r < 0) + goto fail; + + if (*p != 0) { + r = -EINVAL; + goto fail; + } + } + + r = calendar_spec_normalize(c); + if (r < 0) + goto fail; + + if (!calendar_spec_valid(c)) { + r = -EINVAL; + goto fail; + } + + *spec = c; + return 0; + +fail: + calendar_spec_free(c); + return r; +} + +static int find_matching_component(const CalendarComponent *c, int *val) { + const CalendarComponent *n; + int d = -1; + bool d_set = false; + int r; + + assert(val); + + if (!c) + return 0; + + while (c) { + n = c->next; + + if (c->value >= *val) { + + if (!d_set || c->value < d) { + d = c->value; + d_set = true; + } + + } else if (c->repeat > 0) { + int k; + + k = c->value + c->repeat * ((*val - c->value + c->repeat -1) / c->repeat); + + if (!d_set || k < d) { + d = k; + d_set = true; + } + } + + c = n; + } + + if (!d_set) + return -ENOENT; + + r = *val != d; + *val = d; + return r; +} + +static bool tm_out_of_bounds(const struct tm *tm) { + struct tm t; + assert(tm); + + t = *tm; + + if (mktime(&t) == (time_t) -1) + return true; + + /* Did any normalization take place? If so, it was out of bounds before */ + return + t.tm_year != tm->tm_year || + t.tm_mon != tm->tm_mon || + t.tm_mday != tm->tm_mday || + t.tm_hour != tm->tm_hour || + t.tm_min != tm->tm_min || + t.tm_sec != tm->tm_sec; +} + +static bool matches_weekday(int weekdays_bits, const struct tm *tm) { + struct tm t; + int k; + + if (weekdays_bits < 0 || weekdays_bits >= 127) + return true; + + t = *tm; + if (mktime(&t) == (time_t) -1) + return false; + + k = t.tm_wday == 0 ? 6 : t.tm_wday - 1; + return (weekdays_bits & (1 << k)); +} + +static int find_next(const CalendarSpec *spec, struct tm *tm) { + struct tm c; + int r; + + assert(spec); + assert(tm); + + c = *tm; + + for (;;) { + /* Normalize the current date */ + mktime(&c); + c.tm_isdst = -1; + + c.tm_year += 1900; + r = find_matching_component(spec->year, &c.tm_year); + c.tm_year -= 1900; + + if (r > 0) { + c.tm_mon = 0; + c.tm_mday = 1; + c.tm_hour = c.tm_min = c.tm_sec = 0; + } + if (r < 0 || tm_out_of_bounds(&c)) + return r; + + c.tm_mon += 1; + r = find_matching_component(spec->month, &c.tm_mon); + c.tm_mon -= 1; + + if (r > 0) { + c.tm_mday = 1; + c.tm_hour = c.tm_min = c.tm_sec = 0; + } + if (r < 0 || tm_out_of_bounds(&c)) { + c.tm_year ++; + c.tm_mon = 0; + c.tm_mday = 1; + c.tm_hour = c.tm_min = c.tm_sec = 0; + continue; + } + + r = find_matching_component(spec->day, &c.tm_mday); + if (r > 0) + c.tm_hour = c.tm_min = c.tm_sec = 0; + if (r < 0 || tm_out_of_bounds(&c)) { + c.tm_mon ++; + c.tm_mday = 1; + c.tm_hour = c.tm_min = c.tm_sec = 0; + continue; + } + + if (!matches_weekday(spec->weekdays_bits, &c)) { + c.tm_mday++; + c.tm_hour = c.tm_min = c.tm_sec = 0; + continue; + } + + r = find_matching_component(spec->hour, &c.tm_hour); + if (r > 0) + c.tm_min = c.tm_sec = 0; + if (r < 0 || tm_out_of_bounds(&c)) { + c.tm_mday ++; + c.tm_hour = c.tm_min = c.tm_sec = 0; + continue; + } + + r = find_matching_component(spec->minute, &c.tm_min); + if (r > 0) + c.tm_sec = 0; + if (r < 0 || tm_out_of_bounds(&c)) { + c.tm_hour ++; + c.tm_min = c.tm_sec = 0; + continue; + } + + r = find_matching_component(spec->second, &c.tm_sec); + if (r < 0 || tm_out_of_bounds(&c)) { + c.tm_min ++; + c.tm_sec = 0; + continue; + } + + + *tm = c; + return 0; + } +} + +int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) { + struct tm tm; + time_t t; + int r; + + assert(spec); + assert(next); + + t = (time_t) (usec / USEC_PER_SEC) + 1; + assert_se(localtime_r(&t, &tm)); + + r = find_next(spec, &tm); + if (r < 0) + return r; + + t = mktime(&tm); + if (t == (time_t) -1) + return -EINVAL; + + + *next = (usec_t) t * USEC_PER_SEC; + return 0; +} diff --git a/src/shared/calendarspec.h b/src/shared/calendarspec.h new file mode 100644 index 0000000..7baf318 --- /dev/null +++ b/src/shared/calendarspec.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* A structure for specifying (possibly repetitive) points in calendar + * time, a la cron */ + +#include +#include "util.h" + +typedef struct CalendarComponent { + int value; + int repeat; + + struct CalendarComponent *next; +} CalendarComponent; + +typedef struct CalendarSpec { + int weekdays_bits; + + CalendarComponent *year; + CalendarComponent *month; + CalendarComponent *day; + + CalendarComponent *hour; + CalendarComponent *minute; + CalendarComponent *second; +} CalendarSpec; + +void calendar_spec_free(CalendarSpec *c); + +int calendar_spec_normalize(CalendarSpec *spec); +bool calendar_spec_valid(CalendarSpec *spec); + +int calendar_spec_to_string(const CalendarSpec *spec, char **p); +int calendar_spec_from_string(const char *p, CalendarSpec **spec); + +int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next); diff --git a/src/shared/capability.c b/src/shared/capability.c new file mode 100644 index 0000000..f8ee1c6 --- /dev/null +++ b/src/shared/capability.c @@ -0,0 +1,213 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "capability.h" +#include "util.h" +#include "log.h" +#include "fileio.h" + +int have_effective_cap(int value) { + _cleanup_cap_free_ cap_t cap; + cap_flag_value_t fv; + + cap = cap_get_proc(); + if (!cap) + return -errno; + + if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) + return -errno; + else + return fv == CAP_SET; +} + +unsigned long cap_last_cap(void) { + static thread_local unsigned long saved; + static thread_local bool valid = false; + unsigned long p; + + if (valid) + return saved; + + p = (unsigned long) CAP_LAST_CAP; + + if (prctl(PR_CAPBSET_READ, p) < 0) { + + /* 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++) + if (prctl(PR_CAPBSET_READ, p+1) < 0) + break; + } + + saved = p; + valid = true; + + return p; +} + +int capability_bounding_set_drop(uint64_t drop, bool right_now) { + unsigned long i; + _cleanup_cap_free_ cap_t after_cap = NULL, temp_cap = NULL; + cap_flag_value_t fv; + int r; + + /* If we are run as PID 1 we will lack CAP_SETPCAP by default + * in the effective set (yes, the kernel drops that when + * executing init!), so get it back temporarily so that we can + * call PR_CAPBSET_DROP. */ + + after_cap = cap_get_proc(); + if (!after_cap) + return -errno; + + if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) + return -errno; + + if (fv != CAP_SET) { + static const cap_value_t v = CAP_SETPCAP; + + temp_cap = cap_dup(after_cap); + if (!temp_cap) { + r = -errno; + goto finish; + } + + if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { + r = -errno; + goto finish; + } + + if (cap_set_proc(temp_cap) < 0) { + r = -errno; + goto finish; + } + } + + for (i = 0; i <= cap_last_cap(); i++) { + + if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + cap_value_t v; + + /* Drop it from the bounding set */ + if (prctl(PR_CAPBSET_DROP, i) < 0) { + r = -errno; + goto finish; + } + v = (cap_value_t) i; + + /* Also drop it from the inheritable set, so + * that anything we exec() loses the + * capability for good. */ + if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + + /* If we shall apply this right now drop it + * also from our own capability sets. */ + if (right_now) { + if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || + cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + } + } + } + + r = 0; + +finish: + cap_set_proc(after_cap); + + return r; +} + +static int drop_from_file(const char *fn, uint64_t drop) { + int r, k; + uint32_t hi, lo; + uint64_t current, after; + char *p; + + r = read_one_line_file(fn, &p); + if (r < 0) + return r; + + assert_cc(sizeof(hi) == sizeof(unsigned)); + assert_cc(sizeof(lo) == sizeof(unsigned)); + + k = sscanf(p, "%u %u", &lo, &hi); + free(p); + + if (k != 2) + return -EIO; + + current = (uint64_t) lo | ((uint64_t) hi << 32ULL); + after = current & ~drop; + + if (current == after) + return 0; + + lo = (unsigned) (after & 0xFFFFFFFFULL); + hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL); + + if (asprintf(&p, "%u %u", lo, hi) < 0) + return -ENOMEM; + + r = write_string_file(fn, p); + free(p); + + return r; +} + +int capability_bounding_set_drop_usermode(uint64_t drop) { + int r; + + r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); + if (r < 0) + return r; + + r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); + if (r < 0) + return r; + + return r; +} diff --git a/src/shared/capability.h b/src/shared/capability.h new file mode 100644 index 0000000..64f8641 --- /dev/null +++ b/src/shared/capability.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" + +unsigned long cap_last_cap(void); +int have_effective_cap(int value); +int capability_bounding_set_drop(uint64_t drop, bool right_now); +int capability_bounding_set_drop_usermode(uint64_t drop); + +DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free); +#define _cleanup_cap_free_ _cleanup_(cap_freep) + +static inline void cap_free_charpp(char **p) { + if (*p) + cap_free(*p); +} +#define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp) diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c new file mode 100644 index 0000000..ee14cee --- /dev/null +++ b/src/shared/cgroup-show.c @@ -0,0 +1,292 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "macro.h" +#include "path-util.h" +#include "cgroup-util.h" +#include "cgroup-show.h" + +static int compare(const void *a, const void *b) { + const pid_t *p = a, *q = b; + + if (*p < *q) + return -1; + if (*p > *q) + return 1; + return 0; +} + +static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) { + unsigned i, m, pid_width; + pid_t biggest = 0; + + /* Filter duplicates */ + m = 0; + for (i = 0; i < n_pids; i++) { + unsigned j; + + if (pids[i] > biggest) + biggest = pids[i]; + + for (j = i+1; j < n_pids; j++) + if (pids[i] == pids[j]) + break; + + if (j >= n_pids) + pids[m++] = pids[i]; + } + n_pids = m; + pid_width = DECIMAL_STR_WIDTH(biggest); + + /* And sort */ + qsort_safe(pids, n_pids, sizeof(pid_t), compare); + + if (flags & OUTPUT_FULL_WIDTH) + n_columns = 0; + else { + if (n_columns > pid_width+2) + n_columns -= pid_width+2; + else + n_columns = 20; + } + for (i = 0; i < n_pids; i++) { + _cleanup_free_ char *t = NULL; + + get_process_cmdline(pids[i], n_columns, true, &t); + + printf("%s%s%*lu %s\n", + prefix, + draw_special_char(extra ? DRAW_TRIANGULAR_BULLET : + ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)), + pid_width, + (unsigned long) pids[i], + strna(t)); + } +} + + +static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) { + char *fn; + _cleanup_fclose_ FILE *f = NULL; + size_t n = 0, n_allocated = 0; + _cleanup_free_ pid_t *pids = NULL; + _cleanup_free_ char *p = NULL; + pid_t pid; + int r; + + r = cg_mangle_path(path, &p); + if (r < 0) + return r; + + fn = strappenda(p, "/cgroup.procs"); + f = fopen(fn, "re"); + if (!f) + return -errno; + + while ((r = cg_read_pid(f, &pid)) > 0) { + + if (!kernel_threads && is_kernel_thread(pid) > 0) + continue; + + if (n >= n_allocated) { + pid_t *npids; + + n_allocated = MAX(16U, n*2U); + + npids = realloc(pids, sizeof(pid_t) * n_allocated); + if (!npids) + return -ENOMEM; + + pids = npids; + } + + assert(n < n_allocated); + pids[n++] = pid; + } + + if (r < 0) + return r; + + if (n > 0) + show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags); + + return 0; +} + +int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) { + _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL; + _cleanup_closedir_ DIR *d = NULL; + char *gn = NULL; + bool shown_pids = false; + int r; + + assert(path); + + if (n_columns <= 0) + n_columns = columns(); + + if (!prefix) + prefix = ""; + + r = cg_mangle_path(path, &fn); + if (r < 0) + return r; + + d = opendir(fn); + if (!d) + return -errno; + + while ((r = cg_read_subgroup(d, &gn)) > 0) { + _cleanup_free_ char *k = NULL; + + k = strjoin(fn, "/", gn, NULL); + free(gn); + if (!k) + return -ENOMEM; + + if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k, false) > 0) + continue; + + if (!shown_pids) { + show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags); + shown_pids = true; + } + + if (last) { + printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), + basename(last)); + + if (!p1) { + p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT)); + if (!p1) + return -ENOMEM; + } + + show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags); + free(last); + } + + last = k; + k = NULL; + } + + if (r < 0) + return r; + + if (!shown_pids) + show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags); + + if (last) { + printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), + basename(last)); + + if (!p2) { + p2 = strappend(prefix, " "); + if (!p2) + return -ENOMEM; + } + + show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags); + } + + return 0; +} + +int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) { + _cleanup_free_ char *p = NULL; + int r; + + assert(path); + + r = cg_get_path(controller, path, NULL, &p); + if (r < 0) + return r; + + return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags); +} + +static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) { + _cleanup_free_ pid_t *copy = NULL; + unsigned i, j; + int r; + + assert(path); + + if (n_pids <= 0) + return 0; + + if (n_columns <= 0) + n_columns = columns(); + + prefix = strempty(prefix); + + copy = new(pid_t, n_pids); + if (!copy) + return -ENOMEM; + + for (i = 0, j = 0; i < n_pids; i++) { + _cleanup_free_ char *k = NULL; + + r = cg_pid_get_path(controller, pids[i], &k); + if (r < 0) + return r; + + if (path_startswith(k, path)) + continue; + + copy[j++] = pids[i]; + } + + show_pid_array(copy, j, prefix, n_columns, true, false, false, flags); + + return 0; +} + +int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { + int r; + + assert(path); + + r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags); + if (r < 0) + return r; + + return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags); +} + +int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { + _cleanup_free_ char *controller = NULL, *path = NULL; + int r; + + assert(spec); + + r = cg_split_spec(spec, &controller, &path); + if (r < 0) + return r; + + return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags); +} diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h new file mode 100644 index 0000000..3146f56 --- /dev/null +++ b/src/shared/cgroup-show.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include "util.h" +#include "logs-show.h" + +int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); +int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); + +int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); +int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c new file mode 100644 index 0000000..06eb453 --- /dev/null +++ b/src/shared/cgroup-util.c @@ -0,0 +1,1732 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cgroup-util.h" +#include "log.h" +#include "set.h" +#include "macro.h" +#include "util.h" +#include "path-util.h" +#include "strv.h" +#include "unit-name.h" +#include "fileio.h" +#include "special.h" +#include "mkdir.h" + +int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { + _cleanup_free_ char *fs = NULL; + FILE *f; + int r; + + assert(_f); + + r = cg_get_path(controller, path, "cgroup.procs", &fs); + if (r < 0) + return r; + + f = fopen(fs, "re"); + if (!f) + return -errno; + + *_f = f; + return 0; +} + +int cg_read_pid(FILE *f, pid_t *_pid) { + unsigned long ul; + + /* Note that the cgroup.procs might contain duplicates! See + * cgroups.txt for details. */ + + assert(f); + assert(_pid); + + errno = 0; + if (fscanf(f, "%lu", &ul) != 1) { + + if (feof(f)) + return 0; + + return errno ? -errno : -EIO; + } + + if (ul <= 0) + return -EIO; + + *_pid = (pid_t) ul; + return 1; +} + +int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { + _cleanup_free_ char *fs = NULL; + int r; + DIR *d; + + assert(_d); + + /* This is not recursive! */ + + r = cg_get_path(controller, path, NULL, &fs); + if (r < 0) + return r; + + d = opendir(fs); + if (!d) + return -errno; + + *_d = d; + return 0; +} + +int cg_read_subgroup(DIR *d, char **fn) { + struct dirent *de; + + assert(d); + assert(fn); + + FOREACH_DIRENT(de, d, return -errno) { + char *b; + + if (de->d_type != DT_DIR) + continue; + + if (streq(de->d_name, ".") || + streq(de->d_name, "..")) + continue; + + b = strdup(de->d_name); + if (!b) + return -ENOMEM; + + *fn = b; + return 1; + } + + return 0; +} + +int cg_rmdir(const char *controller, const char *path) { + _cleanup_free_ char *p = NULL; + int r; + + r = cg_get_path(controller, path, NULL, &p); + if (r < 0) + return r; + + r = rmdir(p); + if (r < 0 && errno != ENOENT) + return -errno; + + return 0; +} + +int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { + _cleanup_set_free_ Set *allocated_set = NULL; + bool done = false; + int r, ret = 0; + pid_t my_pid; + + assert(sig >= 0); + + /* This goes through the tasks list and kills them all. This + * is repeated until no further processes are added to the + * tasks list, to properly handle forking processes */ + + if (!s) { + s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); + if (!s) + return -ENOMEM; + } + + my_pid = getpid(); + + do { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid = 0; + done = true; + + r = cg_enumerate_processes(controller, path, &f); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; + + return ret; + } + + while ((r = cg_read_pid(f, &pid)) > 0) { + + if (ignore_self && pid == my_pid) + continue; + + if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) + continue; + + /* If we haven't killed this process yet, kill + * it */ + if (kill(pid, sig) < 0) { + if (ret >= 0 && errno != ESRCH) + ret = -errno; + } else { + if (sigcont) + kill(pid, SIGCONT); + + if (ret == 0) + ret = 1; + } + + done = false; + + r = set_put(s, LONG_TO_PTR(pid)); + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + } + + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + + /* To avoid racing against processes which fork + * quicker than we can kill them we repeat this until + * no new pids need to be killed. */ + + } while (!done); + + return ret; +} + +int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) { + _cleanup_set_free_ Set *allocated_set = NULL; + _cleanup_closedir_ DIR *d = NULL; + int r, ret = 0; + char *fn; + + assert(path); + assert(sig >= 0); + + if (!s) { + s = allocated_set = set_new(trivial_hash_func, trivial_compare_func); + if (!s) + return -ENOMEM; + } + + ret = cg_kill(controller, path, sig, sigcont, ignore_self, s); + + r = cg_enumerate_subgroups(controller, path, &d); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; + + return ret; + } + + while ((r = cg_read_subgroup(d, &fn)) > 0) { + _cleanup_free_ char *p = NULL; + + p = strjoin(path, "/", fn, NULL); + free(fn); + if (!p) + return -ENOMEM; + + r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s); + if (ret >= 0 && r != 0) + ret = r; + } + + if (ret >= 0 && r < 0) + ret = r; + + if (rem) { + r = cg_rmdir(controller, path); + if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY) + return r; + } + + return ret; +} + +int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) { + bool done = false; + _cleanup_set_free_ Set *s = NULL; + int r, ret = 0; + pid_t my_pid; + + assert(cfrom); + assert(pfrom); + assert(cto); + assert(pto); + + s = set_new(trivial_hash_func, trivial_compare_func); + if (!s) + return -ENOMEM; + + my_pid = getpid(); + + do { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid = 0; + done = true; + + r = cg_enumerate_processes(cfrom, pfrom, &f); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; + + return ret; + } + + while ((r = cg_read_pid(f, &pid)) > 0) { + + /* This might do weird stuff if we aren't a + * single-threaded program. However, we + * luckily know we are not */ + if (ignore_self && pid == my_pid) + continue; + + if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) + continue; + + r = cg_attach(cto, pto, pid); + if (r < 0) { + if (ret >= 0 && r != -ESRCH) + ret = r; + } else if (ret == 0) + ret = 1; + + done = false; + + r = set_put(s, LONG_TO_PTR(pid)); + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + } + + if (r < 0) { + if (ret >= 0) + return r; + + return ret; + } + } while (!done); + + return ret; +} + +int cg_migrate_recursive( + const char *cfrom, + const char *pfrom, + const char *cto, + const char *pto, + bool ignore_self, + bool rem) { + + _cleanup_closedir_ DIR *d = NULL; + int r, ret = 0; + char *fn; + + assert(cfrom); + assert(pfrom); + assert(cto); + assert(pto); + + ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self); + + r = cg_enumerate_subgroups(cfrom, pfrom, &d); + if (r < 0) { + if (ret >= 0 && r != -ENOENT) + return r; + + return ret; + } + + while ((r = cg_read_subgroup(d, &fn)) > 0) { + _cleanup_free_ char *p = NULL; + + p = strjoin(pfrom, "/", fn, NULL); + free(fn); + if (!p) { + if (ret >= 0) + return -ENOMEM; + + return ret; + } + + r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem); + if (r != 0 && ret >= 0) + ret = r; + } + + if (r < 0 && ret >= 0) + ret = r; + + if (rem) { + r = cg_rmdir(cfrom, pfrom); + if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY) + return r; + } + + return ret; +} + +int cg_migrate_recursive_fallback( + const char *cfrom, + const char *pfrom, + const char *cto, + const char *pto, + bool ignore_self, + bool rem) { + + int r; + + assert(cfrom); + assert(pfrom); + assert(cto); + assert(pto); + + r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem); + if (r < 0) { + char prefix[strlen(pto) + 1]; + + /* This didn't work? Then let's try all prefixes of the destination */ + + PATH_FOREACH_PREFIX(prefix, pto) { + r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem); + if (r >= 0) + break; + } + } + + return 0; +} + +static const char *normalize_controller(const char *controller) { + + assert(controller); + + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return "systemd"; + else if (startswith(controller, "name=")) + return controller + 5; + else + return controller; +} + +static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { + char *t = NULL; + + if (!isempty(controller)) { + if (!isempty(path) && !isempty(suffix)) + t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL); + else if (!isempty(path)) + t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL); + else if (!isempty(suffix)) + t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL); + else + t = strappend("/sys/fs/cgroup/", controller); + } else { + if (!isempty(path) && !isempty(suffix)) + t = strjoin(path, "/", suffix, NULL); + else if (!isempty(path)) + t = strdup(path); + else + return -EINVAL; + } + + if (!t) + return -ENOMEM; + + path_kill_slashes(t); + + *fs = t; + return 0; +} + +int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { + const char *p; + static thread_local bool good = false; + + assert(fs); + + if (controller && !cg_controller_is_valid(controller, true)) + return -EINVAL; + + if (_unlikely_(!good)) { + int r; + + r = path_is_mount_point("/sys/fs/cgroup", false); + if (r <= 0) + return r < 0 ? r : -ENOENT; + + /* Cache this to save a few stat()s */ + good = true; + } + + p = controller ? normalize_controller(controller) : NULL; + + return join_path(p, path, suffix, fs); +} + +static int check_hierarchy(const char *p) { + char *cc; + + assert(p); + + /* Check if this controller actually really exists */ + cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p)); + strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p); + if (access(cc, F_OK) < 0) + return -errno; + + return 0; +} + +int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) { + const char *p; + int r; + + assert(fs); + + if (!cg_controller_is_valid(controller, true)) + return -EINVAL; + + /* Normalize the controller syntax */ + p = normalize_controller(controller); + + /* Check if this controller actually really exists */ + r = check_hierarchy(p); + if (r < 0) + return r; + + return join_path(p, path, suffix, fs); +} + +static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { + assert(path); + assert(sb); + assert(ftwbuf); + + if (typeflag != FTW_DP) + return 0; + + if (ftwbuf->level < 1) + return 0; + + rmdir(path); + return 0; +} + +int cg_trim(const char *controller, const char *path, bool delete_root) { + _cleanup_free_ char *fs = NULL; + int r = 0; + + assert(path); + + r = cg_get_path(controller, path, NULL, &fs); + if (r < 0) + return r; + + errno = 0; + if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) + r = errno ? -errno : -EIO; + + if (delete_root) { + if (rmdir(fs) < 0 && errno != ENOENT) + return -errno; + } + + return r; +} + +int cg_delete(const char *controller, const char *path) { + _cleanup_free_ char *parent = NULL; + int r; + + assert(path); + + r = path_get_parent(path, &parent); + if (r < 0) + return r; + + r = cg_migrate_recursive(controller, path, controller, parent, false, true); + return r == -ENOENT ? 0 : r; +} + +int cg_create(const char *controller, const char *path) { + _cleanup_free_ char *fs = NULL; + int r; + + r = cg_get_path_and_check(controller, path, NULL, &fs); + if (r < 0) + return r; + + r = mkdir_parents(fs, 0755); + if (r < 0) + return r; + + if (mkdir(fs, 0755) < 0) { + + if (errno == EEXIST) + return 0; + + return -errno; + } + + return 1; +} + +int cg_create_and_attach(const char *controller, const char *path, pid_t pid) { + int r, q; + + assert(pid >= 0); + + r = cg_create(controller, path); + if (r < 0) + return r; + + q = cg_attach(controller, path, pid); + if (q < 0) + return q; + + /* This does not remove the cgroup on failure */ + return r; +} + +int cg_attach(const char *controller, const char *path, pid_t pid) { + _cleanup_free_ char *fs = NULL; + char c[DECIMAL_STR_MAX(pid_t) + 2]; + int r; + + assert(path); + assert(pid >= 0); + + r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs); + if (r < 0) + return r; + + if (pid == 0) + pid = getpid(); + + snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid); + + return write_string_file(fs, c); +} + +int cg_attach_fallback(const char *controller, const char *path, pid_t pid) { + int r; + + assert(controller); + assert(path); + assert(pid >= 0); + + r = cg_attach(controller, path, pid); + if (r < 0) { + char prefix[strlen(path) + 1]; + + /* This didn't work? Then let's try all prefixes of + * the destination */ + + PATH_FOREACH_PREFIX(prefix, path) { + r = cg_attach(controller, prefix, pid); + if (r >= 0) + break; + } + } + + return 0; +} + +int cg_set_group_access( + const char *controller, + const char *path, + mode_t mode, + uid_t uid, + gid_t gid) { + + _cleanup_free_ char *fs = NULL; + int r; + + assert(path); + + if (mode != (mode_t) -1) + mode &= 0777; + + r = cg_get_path(controller, path, NULL, &fs); + if (r < 0) + return r; + + return chmod_and_chown(fs, mode, uid, gid); +} + +int cg_set_task_access( + const char *controller, + const char *path, + mode_t mode, + uid_t uid, + gid_t gid) { + + _cleanup_free_ char *fs = NULL, *procs = NULL; + int r; + + assert(path); + + if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1) + return 0; + + if (mode != (mode_t) -1) + mode &= 0666; + + r = cg_get_path(controller, path, "cgroup.procs", &fs); + if (r < 0) + return r; + + r = chmod_and_chown(fs, mode, uid, gid); + if (r < 0) + return r; + + /* Compatibility, Always keep values for "tasks" in sync with + * "cgroup.procs" */ + r = cg_get_path(controller, path, "tasks", &procs); + if (r < 0) + return r; + + return chmod_and_chown(procs, mode, uid, gid); +} + +int cg_pid_get_path(const char *controller, pid_t pid, char **path) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + const char *fs; + size_t cs; + + assert(path); + assert(pid >= 0); + + if (controller) { + if (!cg_controller_is_valid(controller, true)) + return -EINVAL; + + controller = normalize_controller(controller); + } else + controller = SYSTEMD_CGROUP_CONTROLLER; + + fs = procfs_file_alloca(pid, "cgroup"); + + f = fopen(fs, "re"); + if (!f) + return errno == ENOENT ? -ESRCH : -errno; + + cs = strlen(controller); + + FOREACH_LINE(line, f, return -errno) { + char *l, *p, *w, *e; + size_t k; + char *state; + bool found = false; + + truncate_nl(line); + + l = strchr(line, ':'); + if (!l) + continue; + + l++; + e = strchr(l, ':'); + if (!e) + continue; + + *e = 0; + + FOREACH_WORD_SEPARATOR(w, k, l, ",", state) { + + if (k == cs && memcmp(w, controller, cs) == 0) { + found = true; + break; + } + + if (k == 5 + cs && + memcmp(w, "name=", 5) == 0 && + memcmp(w+5, controller, cs) == 0) { + found = true; + break; + } + } + + if (!found) + continue; + + p = strdup(e + 1); + if (!p) + return -ENOMEM; + + *path = p; + return 0; + } + + return -ENOENT; +} + +int cg_install_release_agent(const char *controller, const char *agent) { + _cleanup_free_ char *fs = NULL, *contents = NULL; + char *sc; + int r; + + assert(agent); + + r = cg_get_path(controller, NULL, "release_agent", &fs); + if (r < 0) + return r; + + r = read_one_line_file(fs, &contents); + if (r < 0) + return r; + + sc = strstrip(contents); + if (sc[0] == 0) { + r = write_string_file(fs, agent); + if (r < 0) + return r; + } else if (!streq(sc, agent)) + return -EEXIST; + + free(fs); + fs = NULL; + r = cg_get_path(controller, NULL, "notify_on_release", &fs); + if (r < 0) + return r; + + free(contents); + contents = NULL; + r = read_one_line_file(fs, &contents); + if (r < 0) + return r; + + sc = strstrip(contents); + if (streq(sc, "0")) { + r = write_string_file(fs, "1"); + if (r < 0) + return r; + + return 1; + } + + if (!streq(sc, "1")) + return -EIO; + + return 0; +} + +int cg_uninstall_release_agent(const char *controller) { + _cleanup_free_ char *fs = NULL; + int r; + + r = cg_get_path(controller, NULL, "notify_on_release", &fs); + if (r < 0) + return r; + + r = write_string_file(fs, "0"); + if (r < 0) + return r; + + free(fs); + fs = NULL; + + r = cg_get_path(controller, NULL, "release_agent", &fs); + if (r < 0) + return r; + + r = write_string_file(fs, ""); + if (r < 0) + return r; + + return 0; +} + +int cg_is_empty(const char *controller, const char *path, bool ignore_self) { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid = 0, self_pid; + bool found = false; + int r; + + assert(path); + + r = cg_enumerate_processes(controller, path, &f); + if (r < 0) + return r == -ENOENT ? 1 : r; + + self_pid = getpid(); + + while ((r = cg_read_pid(f, &pid)) > 0) { + + if (ignore_self && pid == self_pid) + continue; + + found = true; + break; + } + + if (r < 0) + return r; + + return !found; +} + +int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) { + _cleanup_closedir_ DIR *d = NULL; + char *fn; + int r; + + assert(path); + + r = cg_is_empty(controller, path, ignore_self); + if (r <= 0) + return r; + + r = cg_enumerate_subgroups(controller, path, &d); + if (r < 0) + return r == -ENOENT ? 1 : r; + + while ((r = cg_read_subgroup(d, &fn)) > 0) { + _cleanup_free_ char *p = NULL; + + p = strjoin(path, "/", fn, NULL); + free(fn); + if (!p) + return -ENOMEM; + + r = cg_is_empty_recursive(controller, p, ignore_self); + if (r <= 0) + return r; + } + + if (r < 0) + return r; + + return 1; +} + +int cg_split_spec(const char *spec, char **controller, char **path) { + const char *e; + char *t = NULL, *u = NULL; + _cleanup_free_ char *v = NULL; + + assert(spec); + + if (*spec == '/') { + if (!path_is_safe(spec)) + return -EINVAL; + + if (path) { + t = strdup(spec); + if (!t) + return -ENOMEM; + + path_kill_slashes(t); + *path = t; + } + + if (controller) + *controller = NULL; + + return 0; + } + + e = strchr(spec, ':'); + if (!e) { + if (!cg_controller_is_valid(spec, true)) + return -EINVAL; + + if (controller) { + t = strdup(normalize_controller(spec)); + if (!t) + return -ENOMEM; + + *controller = t; + } + + if (path) + *path = NULL; + + return 0; + } + + v = strndup(spec, e-spec); + if (!v) + return -ENOMEM; + t = strdup(normalize_controller(v)); + if (!t) + return -ENOMEM; + if (!cg_controller_is_valid(t, true)) { + free(t); + return -EINVAL; + } + + if (streq(e+1, "")) { + u = strdup("/"); + if (!u) { + free(t); + return -ENOMEM; + } + } else { + u = strdup(e+1); + if (!u) { + free(t); + return -ENOMEM; + } + + if (!path_is_safe(u) || + !path_is_absolute(u)) { + free(t); + free(u); + return -EINVAL; + } + + path_kill_slashes(u); + } + + if (controller) + *controller = t; + else + free(t); + + if (path) + *path = u; + else + free(u); + + return 0; +} + +int cg_mangle_path(const char *path, char **result) { + _cleanup_free_ char *c = NULL, *p = NULL; + char *t; + int r; + + assert(path); + assert(result); + + /* First, check if it already is a filesystem path */ + if (path_startswith(path, "/sys/fs/cgroup")) { + + t = strdup(path); + if (!t) + return -ENOMEM; + + path_kill_slashes(t); + *result = t; + return 0; + } + + /* Otherwise, treat it as cg spec */ + r = cg_split_spec(path, &c, &p); + if (r < 0) + return r; + + return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result); +} + +int cg_get_root_path(char **path) { + char *p, *e; + int r; + + assert(path); + + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p); + if (r < 0) + return r; + + e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); + if (e) + *e = 0; + + *path = p; + return 0; +} + +int cg_shift_path(const char *cgroup, const char *root, const char **shifted) { + _cleanup_free_ char *rt = NULL; + char *p; + int r; + + assert(cgroup); + assert(shifted); + + if (!root) { + /* If the root was specified let's use that, otherwise + * let's determine it from PID 1 */ + + r = cg_get_root_path(&rt); + if (r < 0) + return r; + + root = rt; + } + + p = path_startswith(cgroup, root); + if (p) + *shifted = p - 1; + else + *shifted = cgroup; + + return 0; +} + +int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) { + _cleanup_free_ char *raw = NULL; + const char *c; + int r; + + assert(pid >= 0); + assert(cgroup); + + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw); + if (r < 0) + return r; + + r = cg_shift_path(raw, root, &c); + if (r < 0) + return r; + + if (c == raw) { + *cgroup = raw; + raw = NULL; + } else { + char *n; + + n = strdup(c); + if (!n) + return -ENOMEM; + + *cgroup = n; + } + + return 0; +} + +int cg_path_decode_unit(const char *cgroup, char **unit){ + char *e, *c, *s; + + assert(cgroup); + assert(unit); + + e = strchrnul(cgroup, '/'); + c = strndupa(cgroup, e - cgroup); + c = cg_unescape(c); + + if (!unit_name_is_valid(c, TEMPLATE_INVALID)) + return -EINVAL; + + s = strdup(c); + if (!s) + return -ENOMEM; + + *unit = s; + return 0; +} + +static const char *skip_slices(const char *p) { + /* Skips over all slice assignments */ + + for (;;) { + size_t n; + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) + return p; + + p += n; + } +} + +int cg_path_get_unit(const char *path, char **unit) { + const char *e; + + assert(path); + assert(unit); + + e = skip_slices(path); + + return cg_path_decode_unit(e, unit); +} + +int cg_pid_get_unit(pid_t pid, char **unit) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(unit); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_unit(cgroup, unit); +} + +/** + * Skip session-*.scope, but require it to be there. + */ +static const char *skip_session(const char *p) { + size_t n; + + assert(p); + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0) + return NULL; + + p += n; + p += strspn(p, "/"); + + return p; +} + +/** + * Skip user@*.service, but require it to be there. + */ +static const char *skip_user_manager(const char *p) { + size_t n; + + assert(p); + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0) + return NULL; + + p += n; + p += strspn(p, "/"); + + return p; +} + +int cg_path_get_user_unit(const char *path, char **unit) { + const char *e, *t; + + assert(path); + assert(unit); + + /* We always have to parse the path from the beginning as unit + * cgroups might have arbitrary child cgroups and we shouldn't get + * confused by those */ + + /* Skip slices, if there are any */ + e = skip_slices(path); + + /* Skip the session scope... */ + t = skip_session(e); + if (t) + /* ... and skip more slices if there's one */ + e = skip_slices(t); + else { + /* ... or require a user manager unit to be there */ + e = skip_user_manager(e); + if (!e) + return -ENOENT; + } + + return cg_path_decode_unit(e, unit); +} + +int cg_pid_get_user_unit(pid_t pid, char **unit) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(unit); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_user_unit(cgroup, unit); +} + +int cg_path_get_machine_name(const char *path, char **machine) { + _cleanup_free_ char *u = NULL, *sl = NULL; + int r; + + r = cg_path_get_unit(path, &u); + if (r < 0) + return r; + + sl = strjoin("/run/systemd/machines/unit:", u, NULL); + if (!sl) + return -ENOMEM; + + return readlink_malloc(sl, machine); +} + +int cg_pid_get_machine_name(pid_t pid, char **machine) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(machine); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_machine_name(cgroup, machine); +} + +int cg_path_get_session(const char *path, char **session) { + const char *e, *n, *x; + char *s; + size_t l; + + assert(path); + + /* Skip slices, if there are any */ + e = skip_slices(path); + + n = strchrnul(e, '/'); + if (e == n) + return -ENOENT; + + s = strndupa(e, n - e); + s = cg_unescape(s); + + x = startswith(s, "session-"); + if (!x) + return -ENOENT; + if (!endswith(x, ".scope")) + return -ENOENT; + + l = strlen(x); + if (l <= 6) + return -ENOENT; + + if (session) { + char *r; + + r = strndup(x, l - 6); + if (!r) + return -ENOMEM; + + *session = r; + } + + return 0; +} + +int cg_pid_get_session(pid_t pid, char **session) { + _cleanup_free_ char *cgroup = NULL; + int r; + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_session(cgroup, session); +} + +int cg_path_get_owner_uid(const char *path, uid_t *uid) { + _cleanup_free_ char *slice = NULL; + const char *start, *end; + char *s; + uid_t u; + int r; + + assert(path); + + r = cg_path_get_slice(path, &slice); + if (r < 0) + return r; + + start = startswith(slice, "user-"); + if (!start) + return -ENOENT; + end = endswith(slice, ".slice"); + if (!end) + return -ENOENT; + + s = strndupa(start, end - start); + if (!s) + return -ENOENT; + + if (parse_uid(s, &u) < 0) + return -EIO; + + if (uid) + *uid = u; + + return 0; +} + +int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) { + _cleanup_free_ char *cgroup = NULL; + int r; + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_owner_uid(cgroup, uid); +} + +int cg_path_get_slice(const char *p, char **slice) { + const char *e = NULL; + size_t m = 0; + + assert(p); + assert(slice); + + for (;;) { + size_t n; + + p += strspn(p, "/"); + + n = strcspn(p, "/"); + if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) { + char *s; + + if (!e) + return -ENOENT; + + s = strndup(e, m); + if (!s) + return -ENOMEM; + + *slice = s; + return 0; + } + + e = p; + m = n; + + p += n; + } +} + +int cg_pid_get_slice(pid_t pid, char **slice) { + _cleanup_free_ char *cgroup = NULL; + int r; + + assert(slice); + + r = cg_pid_get_path_shifted(pid, NULL, &cgroup); + if (r < 0) + return r; + + return cg_path_get_slice(cgroup, slice); +} + +char *cg_escape(const char *p) { + bool need_prefix = false; + + /* This implements very minimal escaping for names to be used + * as file names in the cgroup tree: any name which might + * conflict with a kernel name or is prefixed with '_' is + * prefixed with a '_'. That way, when reading cgroup names it + * is sufficient to remove a single prefixing underscore if + * there is one. */ + + /* The return value of this function (unlike cg_unescape()) + * needs free()! */ + + if (p[0] == 0 || + p[0] == '_' || + p[0] == '.' || + streq(p, "notify_on_release") || + streq(p, "release_agent") || + streq(p, "tasks")) + need_prefix = true; + else { + const char *dot; + + dot = strrchr(p, '.'); + if (dot) { + + if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0) + need_prefix = true; + else { + char *n; + + n = strndupa(p, dot - p); + + if (check_hierarchy(n) >= 0) + need_prefix = true; + } + } + } + + if (need_prefix) + return strappend("_", p); + else + return strdup(p); +} + +char *cg_unescape(const char *p) { + assert(p); + + /* The return value of this function (unlike cg_escape()) + * doesn't need free()! */ + + if (p[0] == '_') + return (char*) p+1; + + return (char*) p; +} + +#define CONTROLLER_VALID \ + DIGITS LETTERS \ + "_" + +bool cg_controller_is_valid(const char *p, bool allow_named) { + const char *t, *s; + + if (!p) + return false; + + if (allow_named) { + s = startswith(p, "name="); + if (s) + p = s; + } + + if (*p == 0 || *p == '_') + return false; + + for (t = p; *t; t++) + if (!strchr(CONTROLLER_VALID, *t)) + return false; + + if (t - p > FILENAME_MAX) + return false; + + return true; +} + +int cg_slice_to_path(const char *unit, char **ret) { + _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL; + const char *dash; + + assert(unit); + assert(ret); + + if (!unit_name_is_valid(unit, TEMPLATE_INVALID)) + return -EINVAL; + + if (!endswith(unit, ".slice")) + return -EINVAL; + + p = unit_name_to_prefix(unit); + if (!p) + return -ENOMEM; + + dash = strchr(p, '-'); + while (dash) { + _cleanup_free_ char *escaped = NULL; + char n[dash - p + sizeof(".slice")]; + + strcpy(stpncpy(n, p, dash - p), ".slice"); + + if (!unit_name_is_valid(n, TEMPLATE_INVALID)) + return -EINVAL; + + escaped = cg_escape(n); + if (!escaped) + return -ENOMEM; + + if (!strextend(&s, escaped, "/", NULL)) + return -ENOMEM; + + dash = strchr(dash+1, '-'); + } + + e = cg_escape(unit); + if (!e) + return -ENOMEM; + + if (!strextend(&s, e, NULL)) + return -ENOMEM; + + *ret = s; + s = NULL; + + return 0; +} + +int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) { + _cleanup_free_ char *p = NULL; + int r; + + r = cg_get_path(controller, path, attribute, &p); + if (r < 0) + return r; + + return write_string_file(p, value); +} + +static const char mask_names[] = + "cpu\0" + "cpuacct\0" + "blkio\0" + "memory\0" + "devices\0"; + +int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) { + CGroupControllerMask bit = 1; + const char *n; + int r; + + /* This one will create a cgroup in our private tree, but also + * duplicate it in the trees specified in mask, and remove it + * in all others */ + + /* First create the cgroup in our own hierarchy. */ + r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path); + if (r < 0) + return r; + + /* Then, do the same in the other hierarchies */ + NULSTR_FOREACH(n, mask_names) { + if (mask & bit) + cg_create(n, path); + else if (supported & bit) + cg_trim(n, path, true); + + bit <<= 1; + } + + return 0; +} + +int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) { + CGroupControllerMask bit = 1; + const char *n; + int r; + + r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid); + if (r < 0) + return r; + + NULSTR_FOREACH(n, mask_names) { + if (supported & bit) + cg_attach_fallback(n, path, pid); + + bit <<= 1; + } + + return 0; +} + +int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) { + Iterator i; + void *pidp; + int r = 0; + + SET_FOREACH(pidp, pids, i) { + pid_t pid = PTR_TO_LONG(pidp); + int q; + + q = cg_attach_everywhere(supported, path, pid); + if (q < 0) + r = q; + } + + return r; +} + +int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) { + CGroupControllerMask bit = 1; + const char *n; + int r; + + if (!path_equal(from, to)) { + r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true); + if (r < 0) + return r; + } + + NULSTR_FOREACH(n, mask_names) { + if (supported & bit) { + const char *p = NULL; + + if (to_callback) + p = to_callback(bit, userdata); + + if (!p) + p = to; + + cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false); + } + + bit <<= 1; + } + + return 0; +} + +int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) { + CGroupControllerMask bit = 1; + const char *n; + int r; + + r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root); + if (r < 0) + return r; + + NULSTR_FOREACH(n, mask_names) { + if (supported & bit) + cg_trim(n, path, delete_root); + + bit <<= 1; + } + + return 0; +} + +CGroupControllerMask cg_mask_supported(void) { + CGroupControllerMask bit = 1, mask = 0; + const char *n; + + NULSTR_FOREACH(n, mask_names) { + if (check_hierarchy(n) >= 0) + mask |= bit; + + bit <<= 1; + } + + return mask; +} diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h new file mode 100644 index 0000000..aca4e44 --- /dev/null +++ b/src/shared/cgroup-util.h @@ -0,0 +1,133 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "set.h" +#include "def.h" + +/* A bit mask of well known cgroup controllers */ +typedef enum CGroupControllerMask { + CGROUP_CPU = 1, + CGROUP_CPUACCT = 2, + CGROUP_BLKIO = 4, + CGROUP_MEMORY = 8, + CGROUP_DEVICE = 16 +} CGroupControllerMask; + +/* + * General rules: + * + * We accept named hierarchies in the syntax "foo" and "name=foo". + * + * We expect that named hierarchies do not conflict in name with a + * kernel hierarchy, modulo the "name=" prefix. + * + * We always generate "normalized" controller names, i.e. without the + * "name=" prefix. + * + * We require absolute cgroup paths. When returning, we will always + * generate paths with multiple adjacent / removed. + */ + +int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); +int cg_read_pid(FILE *f, pid_t *_pid); + +int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); +int cg_read_subgroup(DIR *d, char **fn); + +int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); +int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool remove, Set *s); + +int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self); +int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool remove); +int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem); + +int cg_split_spec(const char *spec, char **controller, char **path); +int cg_mangle_path(const char *path, char **result); + +int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs); +int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs); + +int cg_pid_get_path(const char *controller, pid_t pid, char **path); + +int cg_trim(const char *controller, const char *path, bool delete_root); + +int cg_rmdir(const char *controller, const char *path); +int cg_delete(const char *controller, const char *path); + +int cg_create(const char *controller, const char *path); +int cg_attach(const char *controller, const char *path, pid_t pid); +int cg_attach_fallback(const char *controller, const char *path, pid_t pid); +int cg_create_and_attach(const char *controller, const char *path, pid_t pid); + +int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value); + +int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); +int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); + +int cg_install_release_agent(const char *controller, const char *agent); +int cg_uninstall_release_agent(const char *controller); + +int cg_is_empty(const char *controller, const char *path, bool ignore_self); +int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self); + +int cg_get_root_path(char **path); + +int cg_path_get_session(const char *path, char **session); +int cg_path_get_owner_uid(const char *path, uid_t *uid); +int cg_path_get_unit(const char *path, char **unit); +int cg_path_get_user_unit(const char *path, char **unit); +int cg_path_get_machine_name(const char *path, char **machine); +int cg_path_get_slice(const char *path, char **slice); + +int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted); +int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup); + +int cg_pid_get_session(pid_t pid, char **session); +int cg_pid_get_owner_uid(pid_t pid, uid_t *uid); +int cg_pid_get_unit(pid_t pid, char **unit); +int cg_pid_get_user_unit(pid_t pid, char **unit); +int cg_pid_get_machine_name(pid_t pid, char **machine); +int cg_pid_get_slice(pid_t pid, char **slice); + +int cg_path_decode_unit(const char *cgroup, char **unit); + +char *cg_escape(const char *p); +char *cg_unescape(const char *p) _pure_; + +bool cg_controller_is_valid(const char *p, bool allow_named); + +int cg_slice_to_path(const char *unit, char **ret); + +typedef const char* (*cg_migrate_callback_t)(CGroupControllerMask mask, void *userdata); + +int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path); +int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid); +int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids); +int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata); +int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root); + +CGroupControllerMask cg_mask_supported(void); diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c new file mode 100644 index 0000000..9961cb4 --- /dev/null +++ b/src/shared/condition-util.c @@ -0,0 +1,266 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include +#include "util.h" +#include "condition-util.h" +#include "virt.h" +#include "path-util.h" +#include "fileio.h" +#include "unit.h" +#include "architecture.h" + +Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { + Condition *c; + + assert(type < _CONDITION_TYPE_MAX); + + c = new0(Condition, 1); + if (!c) + return NULL; + + c->type = type; + c->trigger = trigger; + c->negate = negate; + + if (parameter) { + c->parameter = strdup(parameter); + if (!c->parameter) { + free(c); + return NULL; + } + } + + return c; +} + +void condition_free(Condition *c) { + assert(c); + + free(c->parameter); + free(c); +} + +void condition_free_list(Condition *first) { + Condition *c, *n; + + LIST_FOREACH_SAFE(conditions, c, n, first) + condition_free(c); +} + +bool condition_test_kernel_command_line(Condition *c) { + char *line, *w, *state, *word = NULL; + bool equal; + int r; + size_t l, pl; + bool found = false; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_KERNEL_COMMAND_LINE); + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return c->negate; + + equal = !!strchr(c->parameter, '='); + pl = strlen(c->parameter); + + FOREACH_WORD_QUOTED(w, l, line, state) { + + free(word); + word = strndup(w, l); + if (!word) + break; + + if (equal) { + if (streq(word, c->parameter)) { + found = true; + break; + } + } else { + if (startswith(word, c->parameter) && (word[pl] == '=' || word[pl] == 0)) { + found = true; + break; + } + } + + } + + free(word); + free(line); + + return found == !c->negate; +} + +bool condition_test_virtualization(Condition *c) { + int b, v; + const char *id; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_VIRTUALIZATION); + + v = detect_virtualization(&id); + if (v < 0) { + log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v)); + return c->negate; + } + + /* First, compare with yes/no */ + b = parse_boolean(c->parameter); + + if (v > 0 && b > 0) + return !c->negate; + + if (v == 0 && b == 0) + return !c->negate; + + /* Then, compare categorization */ + if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm")) + return !c->negate; + + if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container")) + return !c->negate; + + /* Finally compare id */ + return (v > 0 && streq(c->parameter, id)) == !c->negate; +} + +bool condition_test_architecture(Condition *c) { + Architecture a, b; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_ARCHITECTURE); + + a = uname_architecture(); + if (a < 0) + return c->negate; + + if (streq(c->parameter, "native")) + b = native_architecture(); + else + b = architecture_from_string(c->parameter); + + if (b < 0) + return c->negate; + + return (a == b) == !c->negate; +} + +bool condition_test_host(Condition *c) { + sd_id128_t x, y; + char *h; + int r; + bool b; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_HOST); + + if (sd_id128_from_string(c->parameter, &x) >= 0) { + + r = sd_id128_get_machine(&y); + if (r < 0) + return c->negate; + + return sd_id128_equal(x, y) == !c->negate; + } + + h = gethostname_malloc(); + if (!h) + return c->negate; + + b = fnmatch(c->parameter, h, FNM_CASEFOLD) == 0; + free(h); + + return b == !c->negate; +} + +bool condition_test_ac_power(Condition *c) { + int r; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_AC_POWER); + + r = parse_boolean(c->parameter); + if (r < 0) + return !c->negate; + + return ((on_ac_power() != 0) == !!r) == !c->negate; +} + +void condition_dump(Condition *c, FILE *f, const char *prefix) { + assert(c); + assert(f); + + if (!prefix) + prefix = ""; + + fprintf(f, + "%s\t%s: %s%s%s %s\n", + prefix, + condition_type_to_string(c->type), + c->trigger ? "|" : "", + c->negate ? "!" : "", + c->parameter, + c->state < 0 ? "failed" : c->state > 0 ? "succeeded" : "untested"); +} + +void condition_dump_list(Condition *first, FILE *f, const char *prefix) { + Condition *c; + + LIST_FOREACH(conditions, c, first) + condition_dump(c, f, prefix); +} + +static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { + [CONDITION_PATH_EXISTS] = "ConditionPathExists", + [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob", + [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory", + [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink", + [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint", + [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite", + [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty", + [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty", + [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable", + [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", + [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", + [CONDITION_SECURITY] = "ConditionSecurity", + [CONDITION_CAPABILITY] = "ConditionCapability", + [CONDITION_HOST] = "ConditionHost", + [CONDITION_AC_POWER] = "ConditionACPower", + [CONDITION_ARCHITECTURE] = "ConditionArchitecture", + [CONDITION_NULL] = "ConditionNull" +}; + +DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType); diff --git a/src/shared/condition-util.h b/src/shared/condition-util.h new file mode 100644 index 0000000..63d945e --- /dev/null +++ b/src/shared/condition-util.h @@ -0,0 +1,79 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "list.h" +#include "macro.h" + +typedef enum ConditionType { + CONDITION_PATH_EXISTS, + CONDITION_PATH_EXISTS_GLOB, + CONDITION_PATH_IS_DIRECTORY, + CONDITION_PATH_IS_SYMBOLIC_LINK, + CONDITION_PATH_IS_MOUNT_POINT, + CONDITION_PATH_IS_READ_WRITE, + CONDITION_DIRECTORY_NOT_EMPTY, + CONDITION_FILE_NOT_EMPTY, + CONDITION_FILE_IS_EXECUTABLE, + CONDITION_KERNEL_COMMAND_LINE, + CONDITION_VIRTUALIZATION, + CONDITION_SECURITY, + CONDITION_CAPABILITY, + CONDITION_HOST, + CONDITION_AC_POWER, + CONDITION_ARCHITECTURE, + CONDITION_NULL, + _CONDITION_TYPE_MAX, + _CONDITION_TYPE_INVALID = -1 +} ConditionType; + +typedef struct Condition { + ConditionType type; + + bool trigger:1; + bool negate:1; + + char *parameter; + + int state; + + LIST_FIELDS(struct Condition, conditions); +} Condition; + +Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate); +void condition_free(Condition *c); +void condition_free_list(Condition *c); + +bool condition_test_kernel_command_line(Condition *c); +bool condition_test_virtualization(Condition *c); +bool condition_test_architecture(Condition *c); +bool condition_test_host(Condition *c); +bool condition_test_ac_power(Condition *c); + +void condition_dump(Condition *c, FILE *f, const char *prefix); +void condition_dump_list(Condition *c, FILE *f, const char *prefix); + +const char* condition_type_to_string(ConditionType t) _const_; +int condition_type_from_string(const char *s) _pure_; diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c new file mode 100644 index 0000000..5201782 --- /dev/null +++ b/src/shared/conf-files.c @@ -0,0 +1,174 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "missing.h" +#include "log.h" +#include "strv.h" +#include "path-util.h" +#include "hashmap.h" +#include "conf-files.h" + +static int files_add(Hashmap *h, const char *dirpath, const char *suffix) { + _cleanup_closedir_ DIR *dir = NULL; + + dir = opendir(dirpath); + if (!dir) { + if (errno == ENOENT) + return 0; + return -errno; + } + + for (;;) { + struct dirent *de; + char *p; + int r; + + errno = 0; + de = readdir(dir); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + if (!dirent_is_file_with_suffix(de, suffix)) + continue; + + p = strjoin(dirpath, "/", de->d_name, NULL); + if (!p) + return -ENOMEM; + + r = hashmap_put(h, basename(p), p); + if (r == -EEXIST) { + log_debug("Skipping overridden file: %s.", p); + free(p); + } else if (r < 0) { + free(p); + return r; + } else if (r == 0) { + log_debug("Duplicate file %s", p); + free(p); + } + } + + return 0; +} + +static int base_cmp(const void *a, const void *b) { + const char *s1, *s2; + + s1 = *(char * const *)a; + s2 = *(char * const *)b; + return strcmp(basename(s1), basename(s2)); +} + +static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { + Hashmap *fh; + char **files, **p; + int r; + + assert(strv); + assert(suffix); + + /* This alters the dirs string array */ + if (!path_strv_canonicalize_absolute_uniq(dirs, root)) + return -ENOMEM; + + fh = hashmap_new(string_hash_func, string_compare_func); + if (!fh) + return -ENOMEM; + + STRV_FOREACH(p, dirs) { + r = files_add(fh, *p, suffix); + if (r == -ENOMEM) { + hashmap_free_free(fh); + return r; + } else if (r < 0) + log_debug("Failed to search for files in %s: %s", + *p, strerror(-r)); + } + + files = hashmap_get_strv(fh); + if (files == NULL) { + hashmap_free_free(fh); + return -ENOMEM; + } + + qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); + *strv = files; + + hashmap_free(fh); + return 0; +} + +int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) { + _cleanup_strv_free_ char **copy = NULL; + + assert(strv); + assert(suffix); + + copy = strv_copy((char**) dirs); + if (!copy) + return -ENOMEM; + + return conf_files_list_strv_internal(strv, suffix, root, copy); +} + +int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) { + _cleanup_strv_free_ char **dirs = NULL; + va_list ap; + + assert(strv); + assert(suffix); + + va_start(ap, dir); + dirs = strv_new_ap(dir, ap); + va_end(ap); + + if (!dirs) + return -ENOMEM; + + return conf_files_list_strv_internal(strv, suffix, root, dirs); +} + +int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) { + _cleanup_strv_free_ char **dirs = NULL; + + assert(strv); + assert(suffix); + + dirs = strv_split_nulstr(d); + if (!dirs) + return -ENOMEM; + + return conf_files_list_strv_internal(strv, suffix, root, dirs); +} diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h new file mode 100644 index 0000000..368c112 --- /dev/null +++ b/src/shared/conf-files.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + Copyright 2010-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "macro.h" + +int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...); +int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs); +int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c new file mode 100644 index 0000000..cfa669b --- /dev/null +++ b/src/shared/conf-parser.c @@ -0,0 +1,981 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "conf-parser.h" +#include "util.h" +#include "macro.h" +#include "strv.h" +#include "log.h" +#include "utf8.h" +#include "path-util.h" +#include "set.h" +#include "exit-status.h" +#include "sd-messages.h" + +int log_syntax_internal(const char *unit, int level, + const char *file, unsigned line, const char *func, + const char *config_file, unsigned config_line, + int error, const char *format, ...) { + + _cleanup_free_ char *msg = NULL; + int r; + va_list ap; + + va_start(ap, format); + r = vasprintf(&msg, format, ap); + va_end(ap); + if (r < 0) + return log_oom(); + + if (unit) + r = log_struct_internal(level, + file, line, func, + getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, + MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR), + "CONFIG_FILE=%s", config_file, + "CONFIG_LINE=%u", config_line, + "ERRNO=%d", error > 0 ? error : EINVAL, + "MESSAGE=[%s:%u] %s", config_file, config_line, msg, + NULL); + else + r = log_struct_internal(level, + file, line, func, + MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR), + "CONFIG_FILE=%s", config_file, + "CONFIG_LINE=%u", config_line, + "ERRNO=%d", error > 0 ? error : EINVAL, + "MESSAGE=[%s:%u] %s", config_file, config_line, msg, + NULL); + + return r; +} + +int config_item_table_lookup( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata) { + + ConfigTableItem *t; + + assert(table); + assert(lvalue); + assert(func); + assert(ltype); + assert(data); + + for (t = table; t->lvalue; t++) { + + if (!streq(lvalue, t->lvalue)) + continue; + + if (!streq_ptr(section, t->section)) + continue; + + *func = t->parse; + *ltype = t->ltype; + *data = t->data; + return 1; + } + + return 0; +} + +int config_item_perf_lookup( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata) { + + ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; + const ConfigPerfItem *p; + + assert(table); + assert(lvalue); + assert(func); + assert(ltype); + assert(data); + + if (!section) + p = lookup(lvalue, strlen(lvalue)); + else { + char *key; + + key = strjoin(section, ".", lvalue, NULL); + if (!key) + return -ENOMEM; + + p = lookup(key, strlen(key)); + free(key); + } + + if (!p) + return 0; + + *func = p->parse; + *ltype = p->ltype; + *data = (uint8_t*) userdata + p->offset; + return 1; +} + +/* Run the user supplied parser for an assignment */ +static int next_assignment(const char *unit, + const char *filename, + unsigned line, + ConfigItemLookup lookup, + void *table, + const char *section, + unsigned section_line, + const char *lvalue, + const char *rvalue, + bool relaxed, + void *userdata) { + + ConfigParserCallback func = NULL; + int ltype = 0; + void *data = NULL; + int r; + + assert(filename); + assert(line > 0); + assert(lookup); + assert(lvalue); + assert(rvalue); + + r = lookup(table, section, lvalue, &func, <ype, &data, userdata); + if (r < 0) + return r; + + if (r > 0) { + if (func) + return func(unit, filename, line, section, section_line, + lvalue, ltype, rvalue, data, userdata); + + return 0; + } + + /* Warn about unknown non-extension fields. */ + if (!relaxed && !startswith(lvalue, "X-")) + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, + "Unknown lvalue '%s' in section '%s'", lvalue, section); + + return 0; +} + +/* Parse a variable assignment line */ +static int parse_line(const char* unit, + const char *filename, + unsigned line, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + bool allow_include, + char **section, + unsigned *section_line, + char *l, + void *userdata) { + + char *e; + + assert(filename); + assert(line > 0); + assert(lookup); + assert(l); + + l = strstrip(l); + + if (!*l) + return 0; + + if (strchr(COMMENTS "\n", *l)) + return 0; + + if (startswith(l, ".include ")) { + _cleanup_free_ char *fn = NULL; + + /* .includes are a bad idea, we only support them here + * for historical reasons. They create cyclic include + * problems and make it difficult to detect + * configuration file changes with an easy + * stat(). Better approaches, such as .d/ drop-in + * snippets exist. + * + * Support for them should be eventually removed. */ + + if (!allow_include) { + log_syntax(unit, LOG_ERR, filename, line, EBADMSG, + ".include not allowed here. Ignoring."); + return 0; + } + + fn = file_in_same_dir(filename, strstrip(l+9)); + if (!fn) + return -ENOMEM; + + return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, userdata); + } + + if (*l == '[') { + size_t k; + char *n; + + k = strlen(l); + assert(k > 0); + + if (l[k-1] != ']') { + log_syntax(unit, LOG_ERR, filename, line, EBADMSG, + "Invalid section header '%s'", l); + return -EBADMSG; + } + + n = strndup(l+1, k-2); + if (!n) + return -ENOMEM; + + if (sections && !nulstr_contains(sections, n)) { + + if (!relaxed) + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, + "Unknown section '%s'. Ignoring.", n); + + free(n); + free(*section); + *section = NULL; + *section_line = 0; + } else { + free(*section); + *section = n; + *section_line = line; + } + + return 0; + } + + if (sections && !*section) { + + if (!relaxed) + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, + "Assignment outside of section. Ignoring."); + + return 0; + } + + e = strchr(l, '='); + if (!e) { + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='."); + return -EBADMSG; + } + + *e = 0; + e++; + + return next_assignment(unit, + filename, + line, + lookup, + table, + *section, + *section_line, + strstrip(l), + strstrip(e), + relaxed, + userdata); +} + +/* Go through the file and parse each line */ +int config_parse(const char *unit, + const char *filename, + FILE *f, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + bool allow_include, + void *userdata) { + + _cleanup_free_ char *section = NULL, *continuation = NULL; + _cleanup_fclose_ FILE *ours = NULL; + unsigned line = 0, section_line = 0; + int r; + + assert(filename); + assert(lookup); + + if (!f) { + f = ours = fopen(filename, "re"); + if (!f) { + log_error("Failed to open configuration file '%s': %m", filename); + return -errno; + } + } + + fd_warn_permissions(filename, fileno(f)); + + while (!feof(f)) { + char l[LINE_MAX], *p, *c = NULL, *e; + bool escaped = false; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + log_error("Failed to read configuration file '%s': %m", filename); + return -errno; + } + + truncate_nl(l); + + if (continuation) { + c = strappend(continuation, l); + if (!c) + return -ENOMEM; + + free(continuation); + continuation = NULL; + p = c; + } else + p = l; + + for (e = p; *e; e++) { + if (escaped) + escaped = false; + else if (*e == '\\') + escaped = true; + } + + if (escaped) { + *(e-1) = ' '; + + if (c) + continuation = c; + else { + continuation = strdup(l); + if (!continuation) + return -ENOMEM; + } + + continue; + } + + r = parse_line(unit, + filename, + ++line, + sections, + lookup, + table, + relaxed, + allow_include, + §ion, + §ion_line, + p, + userdata); + free(c); + + if (r < 0) + return r; + } + + return 0; +} + +#define DEFINE_PARSER(type, vartype, conv_func) \ + int config_parse_##type(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) { \ + \ + vartype *i = data; \ + int r; \ + \ + assert(filename); \ + assert(lvalue); \ + assert(rvalue); \ + assert(data); \ + \ + r = conv_func(rvalue, i); \ + if (r < 0) \ + log_syntax(unit, LOG_ERR, filename, line, -r, \ + "Failed to parse %s value, ignoring: %s", \ + #vartype, rvalue); \ + \ + return 0; \ + } + +DEFINE_PARSER(int, int, safe_atoi) +DEFINE_PARSER(long, long, safe_atoli) +DEFINE_PARSER(uint64, uint64_t, safe_atou64) +DEFINE_PARSER(unsigned, unsigned, safe_atou) +DEFINE_PARSER(double, double, safe_atod) +DEFINE_PARSER(nsec, nsec_t, parse_nsec) +DEFINE_PARSER(sec, usec_t, parse_sec) + +int config_parse_iec_size(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) { + + size_t *sz = data; + off_t o; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_size(rvalue, 1024, &o); + if (r < 0 || (off_t) (size_t) o != o) { + log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + return 0; + } + + *sz = (size_t) o; + return 0; +} + +int config_parse_si_size(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) { + + size_t *sz = data; + off_t o; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_size(rvalue, 1000, &o); + if (r < 0 || (off_t) (size_t) o != o) { + log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + return 0; + } + + *sz = (size_t) o; + return 0; +} + +int config_parse_iec_off(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) { + + off_t *bytes = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + assert_cc(sizeof(off_t) == sizeof(uint64_t)); + + r = parse_size(rvalue, 1024, bytes); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue); + + return 0; +} + +int config_parse_bool(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 k; + bool *b = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + k = parse_boolean(rvalue); + if (k < 0) { + log_syntax(unit, LOG_ERR, filename, line, -k, + "Failed to parse boolean value, ignoring: %s", rvalue); + return 0; + } + + *b = !!k; + return 0; +} + +int config_parse_show_status(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 k; + ShowStatus *b = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + k = parse_show_status(rvalue, b); + if (k < 0) { + log_syntax(unit, LOG_ERR, filename, line, -k, + "Failed to parse show status setting, ignoring: %s", rvalue); + return 0; + } + + return 0; +} + +int config_parse_string(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) { + + char **s = data; + char *n; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = strdup(rvalue); + if (!n) + return log_oom(); + + if (!utf8_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "String is not UTF-8 clean, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + free(*s); + if (*n) + *s = n; + else { + free(n); + *s = NULL; + } + + return 0; +} + +int config_parse_path(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) { + + char **s = data; + char *n; + int offset; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (!utf8_is_valid(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not UTF-8 clean, ignoring assignment: %s", rvalue); + return 0; + } + + offset = rvalue[0] == '-' && (streq(lvalue, "InaccessibleDirectories") || + streq(lvalue, "ReadOnlyDirectories")); + if (!path_is_absolute(rvalue + offset)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Not an absolute path, ignoring: %s", rvalue); + return 0; + } + + n = strdup(rvalue); + if (!n) + return log_oom(); + + path_kill_slashes(n); + + free(*s); + *s = n; + + return 0; +} + +int config_parse_strv(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) { + + char *** sv = data, *w, *state; + size_t l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + char **empty; + + /* Empty assignment resets the list. As a special rule + * we actually fill in a real empty array here rather + * than NULL, since some code wants to know if + * something was set at all... */ + empty = strv_new(NULL, NULL); + if (!empty) + return log_oom(); + + strv_free(*sv); + *sv = empty; + return 0; + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *n; + + n = cunescape_length(w, l); + if (!n) + return log_oom(); + + if (!utf8_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "String is not UTF-8 clean, ignoring: %s", rvalue); + continue; + } + + r = strv_extend(sv, n); + if (r < 0) + return log_oom(); + } + + return 0; +} + +int config_parse_path_strv(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) { + + char*** sv = data, *w, *state; + size_t l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + strv_free(*sv); + *sv = NULL; + return 0; + } + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *n; + int offset; + + n = strndup(w, l); + if (!n) + return log_oom(); + + if (!utf8_is_valid(n)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Path is not UTF-8 clean, ignoring assignment: %s", rvalue); + continue; + } + + offset = n[0] == '-' && (streq(lvalue, "InaccessibleDirectories") || + streq(lvalue, "ReadOnlyDirectories")); + if (!path_is_absolute(n + offset)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Not an absolute path, ignoring: %s", rvalue); + continue; + } + + path_kill_slashes(n); + r = strv_extend(sv, n); + if (r < 0) + return log_oom(); + } + + return 0; +} + +int config_parse_mode(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + mode_t *m = data; + long l; + char *x = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + errno = 0; + l = strtol(rvalue, &x, 8); + if (!x || x == rvalue || *x || errno) { + log_syntax(unit, LOG_ERR, filename, line, errno, + "Failed to parse mode value, ignoring: %s", rvalue); + return 0; + } + + if (l < 0000 || l > 07777) { + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "Mode value out of range, ignoring: %s", rvalue); + return 0; + } + + *m = (mode_t) l; + return 0; +} + +int config_parse_facility(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 *o = data, x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + x = log_facility_unshifted_from_string(rvalue); + if (x < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse log facility, ignoring: %s", rvalue); + return 0; + } + + *o = (x << 3) | LOG_PRI(*o); + + return 0; +} + +int config_parse_level(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 *o = data, x; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + x = log_level_from_string(rvalue); + if (x < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Failed to parse log level, ignoring: %s", rvalue); + return 0; + } + + *o = (*o & LOG_FACMASK) | x; + return 0; +} + +int config_parse_set_status(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) { + + char *w; + size_t l; + char *state; + int r; + ExitStatusSet *status_set = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + + set_free(status_set->signal); + set_free(status_set->code); + + status_set->signal = status_set->code = NULL; + return 0; + } + + FOREACH_WORD(w, l, rvalue, state) { + int val; + char *temp; + + temp = strndup(w, l); + if (!temp) + return log_oom(); + + r = safe_atoi(temp, &val); + if (r < 0) { + val = signal_from_string_try_harder(temp); + free(temp); + + if (val > 0) { + r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func); + if (r < 0) + return log_oom(); + + r = set_put(status_set->signal, INT_TO_PTR(val)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Unable to store: %s", w); + return r; + } + } else { + log_syntax(unit, LOG_ERR, filename, line, -val, + "Failed to parse value, ignoring: %s", w); + return 0; + } + } else { + free(temp); + + if (val < 0 || val > 255) + log_syntax(unit, LOG_ERR, filename, line, ERANGE, + "Value %d is outside range 0-255, ignoring", val); + else { + r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func); + if (r < 0) + return log_oom(); + + r = set_put(status_set->code, INT_TO_PTR(val)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, -r, + "Unable to store: %s", w); + return r; + } + } + } + } + + return 0; +} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h new file mode 100644 index 0000000..4ccdadd --- /dev/null +++ b/src/shared/conf-parser.h @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "macro.h" + +/* An abstract parser for simple, line based, shallow configuration + * files consisting of variable assignments only. */ + +/* Prototype for a parser for a specific configuration setting */ +typedef int (*ConfigParserCallback)(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); + +/* Wraps information for parsing a specific configuration variable, to + * be stored in a simple array */ +typedef struct ConfigTableItem { + const char *section; /* Section */ + const char *lvalue; /* Name of the variable */ + ConfigParserCallback parse; /* Function that is called to parse the variable's value */ + int ltype; /* Distinguish different variables passed to the same callback */ + void *data; /* Where to store the variable's data */ +} ConfigTableItem; + +/* Wraps information for parsing a specific configuration variable, to + * ve srored in a gperf perfect hashtable */ +typedef struct ConfigPerfItem { + const char *section_and_lvalue; /* Section + "." + name of the variable */ + ConfigParserCallback parse; /* Function that is called to parse the variable's value */ + int ltype; /* Distinguish different variables passed to the same callback */ + size_t offset; /* Offset where to store data, from the beginning of userdata */ +} ConfigPerfItem; + +/* Prototype for a low-level gperf lookup function */ +typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length); + +/* Prototype for a generic high-level lookup function */ +typedef int (*ConfigItemLookup)( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata); + +/* Linear table search implementation of ConfigItemLookup, based on + * ConfigTableItem arrays */ +int config_item_table_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); + +/* gperf implementation of ConfigItemLookup, based on gperf + * ConfigPerfItem tables */ +int config_item_perf_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); + +int config_parse(const char *unit, + const char *filename, + FILE *f, + const char *sections, /* nulstr */ + ConfigItemLookup lookup, + void *table, + bool relaxed, + bool allow_include, + void *userdata); + +/* Generic parsers */ +int config_parse_int(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_unsigned(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_long(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_uint64(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_double(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_iec_size(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_si_size(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_iec_off(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_bool(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_show_status(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_string(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_path(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_strv(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_path_strv(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_sec(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_nsec(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_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_facility(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_level(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_set_status(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 log_syntax_internal(const char *unit, int level, + const char *file, unsigned line, const char *func, + const char *config_file, unsigned config_line, + int error, const char *format, ...) _printf_(9, 10); + +#define log_syntax(unit, level, config_file, config_line, error, ...) \ + log_syntax_internal(unit, level, \ + __FILE__, __LINE__, __func__, \ + config_file, config_line, \ + error, __VA_ARGS__) + +#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ + int function(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) { \ + \ + type *i = data, x; \ + \ + assert(filename); \ + assert(lvalue); \ + assert(rvalue); \ + assert(data); \ + \ + if ((x = name##_from_string(rvalue)) < 0) { \ + log_syntax(unit, LOG_ERR, filename, line, -x, \ + msg ", ignoring: %s", rvalue); \ + return 0; \ + } \ + \ + *i = x; \ + return 0; \ + } + +#define DEFINE_CONFIG_PARSE_ENUMV(function,name,type,invalid,msg) \ + int function(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) { \ + \ + type **enums = data, *xs, x, *ys; \ + char *w, *state; \ + size_t l, i = 0; \ + \ + assert(filename); \ + assert(lvalue); \ + assert(rvalue); \ + assert(data); \ + \ + xs = new0(type, 1); \ + *xs = invalid; \ + \ + FOREACH_WORD(w, l, rvalue, state) { \ + _cleanup_free_ char *en = NULL; \ + \ + en = strndup(w, l); \ + if (!en) \ + return -ENOMEM; \ + \ + if ((x = name##_from_string(en)) < 0) { \ + log_syntax(unit, LOG_ERR, filename, line, \ + -x, msg ", ignoring: %s", en); \ + continue; \ + } \ + \ + for (ys = xs; x != invalid && *ys != invalid; ys++) { \ + if (*ys == x) { \ + log_syntax(unit, LOG_ERR, filename, \ + line, -x, \ + "Duplicate entry, ignoring: %s", \ + en); \ + x = invalid; \ + } \ + } \ + \ + if (x == invalid) \ + continue; \ + \ + *(xs + i) = x; \ + xs = realloc(xs, (++i + 1) * sizeof(type)); \ + if (!xs) \ + return -ENOMEM; \ + *(xs + i) = invalid; \ + } \ + \ + free(*enums); \ + *enums = xs; \ + return 0; \ + } diff --git a/src/shared/def.h b/src/shared/def.h new file mode 100644 index 0000000..7777756 --- /dev/null +++ b/src/shared/def.h @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "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 DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC) +#define DEFAULT_START_LIMIT_BURST 5 + +/* The default time after which exit-on-idle services exit. This + * should be kept lower than the watchdog timeout, because otherwise + * the watchdog pings will keep the loop busy. */ +#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) + +#define SYSTEMD_CGROUP_CONTROLLER "name=systemd" + +#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT +#define SIGNALS_IGNORE SIGPIPE + +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS + +#define REBOOT_PARAM_FILE "/run/systemd/reboot-param" + +#ifdef 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 + +#define UNIX_SYSTEM_BUS_PATH "unix:path=/run/dbus/system_bus_socket" +#define KERNEL_SYSTEM_BUS_PATH "kernel:path=/dev/kdbus/0-system/bus" + +#ifdef ENABLE_KDBUS +# define DEFAULT_SYSTEM_BUS_PATH KERNEL_SYSTEM_BUS_PATH ";" UNIX_SYSTEM_BUS_PATH +#else +# define DEFAULT_SYSTEM_BUS_PATH UNIX_SYSTEM_BUS_PATH +#endif + +#define UNIX_USER_BUS_FMT "unix:path=%s/bus" +#define KERNEL_USER_BUS_FMT "kernel:path=/dev/kdbus/%lu-user/bus" + +#ifndef TTY_GID +#define TTY_GID 5 +#endif diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c new file mode 100644 index 0000000..e025e17 --- /dev/null +++ b/src/shared/dev-setup.c @@ -0,0 +1,84 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "dev-setup.h" +#include "log.h" +#include "macro.h" +#include "util.h" +#include "label.h" + +static int symlink_and_label(const char *old_path, const char *new_path) { + int r; + + assert(old_path); + assert(new_path); + + r = label_context_set(new_path, S_IFLNK); + if (r < 0) + return r; + + if (symlink(old_path, new_path) < 0) + r = -errno; + + label_context_clear(); + + return r; +} + +int dev_setup(const char *prefix) { + const char *j, *k; + + static const char symlinks[] = + "-/proc/kcore\0" "/dev/core\0" + "/proc/self/fd\0" "/dev/fd\0" + "/proc/self/fd/0\0" "/dev/stdin\0" + "/proc/self/fd/1\0" "/dev/stdout\0" + "/proc/self/fd/2\0" "/dev/stderr\0"; + + NULSTR_FOREACH_PAIR(j, k, symlinks) { + if (j[0] == '-') { + j++; + + if (access(j, F_OK)) + continue; + } + + if (prefix) { + _cleanup_free_ char *link_name = NULL; + + link_name = strjoin(prefix, "/", k, NULL); + if (!link_name) + return -ENOMEM; + + symlink_and_label(j, link_name); + } else + symlink_and_label(j, k); + } + + return 0; +} diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h new file mode 100644 index 0000000..d41b6ee --- /dev/null +++ b/src/shared/dev-setup.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int dev_setup(const char *pathprefix); diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c new file mode 100644 index 0000000..9837375 --- /dev/null +++ b/src/shared/device-nodes.c @@ -0,0 +1,74 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2008-2011 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "device-nodes.h" +#include "utf8.h" + +int whitelisted_char_for_devnode(char c, const char *white) { + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr("#+-.:=@_", c) != NULL || + (white != NULL && strchr(white, c) != NULL)) + return 1; + return 0; +} + +int encode_devnode_name(const char *str, char *str_enc, size_t len) { + size_t i, j; + + if (str == NULL || str_enc == NULL) + return -1; + + for (i = 0, j = 0; str[i] != '\0'; i++) { + int seqlen; + + seqlen = utf8_encoded_valid_unichar(&str[i]); + if (seqlen > 1) { + if (len-j < (size_t)seqlen) + goto err; + memcpy(&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen-1); + } else if (str[i] == '\\' || !whitelisted_char_for_devnode(str[i], NULL)) { + if (len-j < 4) + goto err; + sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); + j += 4; + } else { + if (len-j < 1) + goto err; + str_enc[j] = str[i]; + j++; + } + } + if (len-j < 1) + goto err; + str_enc[j] = '\0'; + return 0; +err: + return -1; +} diff --git a/src/shared/device-nodes.h b/src/shared/device-nodes.h new file mode 100644 index 0000000..04ba489 --- /dev/null +++ b/src/shared/device-nodes.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int encode_devnode_name(const char *str, char *str_enc, size_t len); +int whitelisted_char_for_devnode(char c, const char *additional); diff --git a/src/shared/efivars.c b/src/shared/efivars.c new file mode 100644 index 0000000..5ee8f1e --- /dev/null +++ b/src/shared/efivars.c @@ -0,0 +1,464 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "acpi-fpdt.h" +#include "util.h" +#include "utf8.h" +#include "efivars.h" + +#ifdef ENABLE_EFI + +bool is_efi_boot(void) { + return access("/sys/firmware/efi", F_OK) >= 0; +} + +static int read_flag(const char *varname) { + int r; + _cleanup_free_ void *v = NULL; + size_t s; + uint8_t b; + + r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s); + if (r < 0) + return r; + + if (s != 1) + return -EINVAL; + + b = *(uint8_t *)v; + r = b > 0; + return r; +} + +int is_efi_secure_boot(void) { + return read_flag("SecureBoot"); +} + +int is_efi_secure_boot_setup_mode(void) { + return read_flag("SetupMode"); +} + +int efi_get_variable( + sd_id128_t vendor, + const char *name, + uint32_t *attribute, + void **value, + size_t *size) { + + _cleanup_close_ int fd = -1; + _cleanup_free_ char *p = NULL; + uint32_t a; + ssize_t n; + struct stat st; + void *r; + + assert(name); + assert(value); + assert(size); + + if (asprintf(&p, + "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + name, SD_ID128_FORMAT_VAL(vendor)) < 0) + return -ENOMEM; + + fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (fstat(fd, &st) < 0) + return -errno; + if (st.st_size < 4) + return -EIO; + if (st.st_size > 4*1024*1024 + 4) + return -E2BIG; + + n = read(fd, &a, sizeof(a)); + if (n < 0) + return -errno; + if (n != sizeof(a)) + return -EIO; + + r = malloc(st.st_size - 4 + 2); + if (!r) + return -ENOMEM; + + n = read(fd, r, (size_t) st.st_size - 4); + if (n < 0) { + free(r); + return -errno; + } + if (n != (ssize_t) st.st_size - 4) { + free(r); + return -EIO; + } + + /* Always NUL terminate (2 bytes, to protect UTF-16) */ + ((char*) r)[st.st_size - 4] = 0; + ((char*) r)[st.st_size - 4 + 1] = 0; + + *value = r; + *size = (size_t) st.st_size - 4; + + if (attribute) + *attribute = a; + + return 0; +} + +int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { + _cleanup_free_ void *s = NULL; + size_t ss = 0; + int r; + char *x; + + r = efi_get_variable(vendor, name, NULL, &s, &ss); + if (r < 0) + return r; + + x = utf16_to_utf8(s, ss); + if (!x) + return -ENOMEM; + + *p = x; + return 0; +} + +static size_t utf16_size(const uint16_t *s) { + size_t l = 0; + + while (s[l] > 0) + l++; + + return (l+1) * sizeof(uint16_t); +} + +static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) { + struct uuid { + uint32_t u1; + uint16_t u2; + uint16_t u3; + uint8_t u4[8]; + } _packed_; + const struct uuid *uuid = guid; + + id128->bytes[0] = (uuid->u1 >> 24) & 0xff; + id128->bytes[1] = (uuid->u1 >> 16) & 0xff; + id128->bytes[2] = (uuid->u1 >> 8) & 0xff; + id128->bytes[3] = (uuid->u1) & 0xff; + id128->bytes[4] = (uuid->u2 >> 8) & 0xff; + id128->bytes[5] = (uuid->u2) & 0xff; + id128->bytes[6] = (uuid->u3 >> 8) & 0xff; + id128->bytes[7] = (uuid->u3) & 0xff; + memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4)); +} + +int efi_get_boot_option( + uint16_t id, + char **title, + sd_id128_t *part_uuid, + char **path) { + + struct boot_option { + uint32_t attr; + uint16_t path_len; + uint16_t title[]; + } _packed_; + + struct drive_path { + uint32_t part_nr; + uint64_t part_start; + uint64_t part_size; + char signature[16]; + uint8_t mbr_type; + uint8_t signature_type; + } _packed_; + + struct device_path { + uint8_t type; + uint8_t sub_type; + uint16_t length; + union { + uint16_t path[0]; + struct drive_path drive; + }; + } _packed_; + + char boot_id[9]; + _cleanup_free_ uint8_t *buf = NULL; + size_t l; + struct boot_option *header; + size_t title_size; + char *s = NULL; + char *p = NULL; + sd_id128_t p_uuid = SD_ID128_NULL; + int err; + + snprintf(boot_id, sizeof(boot_id), "Boot%04X", id); + err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l); + if (err < 0) + return err; + if (l < sizeof(struct boot_option)) + return -ENOENT; + + header = (struct boot_option *)buf; + title_size = utf16_size(header->title); + if (title_size > l - offsetof(struct boot_option, title)) + return -EINVAL; + + if (title) { + s = utf16_to_utf8(header->title, title_size); + if (!s) { + err = -ENOMEM; + goto err; + } + } + + if (header->path_len > 0) { + uint8_t *dbuf; + size_t dnext; + + dbuf = buf + offsetof(struct boot_option, title) + title_size; + dnext = 0; + while (dnext < header->path_len) { + struct device_path *dpath; + + dpath = (struct device_path *)(dbuf + dnext); + if (dpath->length < 4) + break; + + /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */ + if (dpath->type == 0x7f && dpath->sub_type == 0xff) + break; + + dnext += dpath->length; + + /* Type 0x04 – Media Device Path */ + if (dpath->type != 0x04) + continue; + + /* Sub-Type 1 – Hard Drive */ + if (dpath->sub_type == 0x01) { + /* 0x02 – GUID Partition Table */ + if (dpath->drive.mbr_type != 0x02) + continue; + + /* 0x02 – GUID signature */ + if (dpath->drive.signature_type != 0x02) + continue; + + if (part_uuid) + efi_guid_to_id128(dpath->drive.signature, &p_uuid); + continue; + } + + /* Sub-Type 4 – File Path */ + if (dpath->sub_type == 0x04 && !p && path) { + p = utf16_to_utf8(dpath->path, dpath->length-4); + continue; + } + } + } + + if (title) + *title = s; + if (part_uuid) + *part_uuid = p_uuid; + if (path) + *path = p; + + return 0; +err: + free(s); + free(p); + return err; +} + +int efi_get_boot_order(uint16_t **order) { + void *buf; + size_t l; + int r; + + r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l); + if (r < 0) + return r; + + if (l <= 0) { + free(buf); + return -ENOENT; + } + + if ((l % sizeof(uint16_t) > 0) || + (l / sizeof(uint16_t) > INT_MAX)) { + free(buf); + return -EINVAL; + } + + *order = buf; + return (int) (l / sizeof(uint16_t)); +} + +static int boot_id_hex(const char s[4]) { + int i; + int id = 0; + + for (i = 0; i < 4; i++) + if (s[i] >= '0' && s[i] <= '9') + id |= (s[i] - '0') << (3 - i) * 4; + else if (s[i] >= 'A' && s[i] <= 'F') + id |= (s[i] - 'A' + 10) << (3 - i) * 4; + else + return -1; + + return id; +} + +static int cmp_uint16(const void *_a, const void *_b) { + const uint16_t *a = _a, *b = _b; + + return (int)*a - (int)*b; +} + +int efi_get_boot_options(uint16_t **options) { + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *de; + uint16_t *list = NULL; + int count = 0, r; + + assert(options); + + dir = opendir("/sys/firmware/efi/efivars/"); + if (!dir) + return -errno; + + FOREACH_DIRENT(de, dir, r = -errno; goto fail) { + int id; + uint16_t *t; + + if (strncmp(de->d_name, "Boot", 4) != 0) + continue; + + if (strlen(de->d_name) != 45) + continue; + + if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0) + continue; + + id = boot_id_hex(de->d_name + 4); + if (id < 0) + continue; + + t = realloc(list, (count + 1) * sizeof(uint16_t)); + if (!t) { + r = -ENOMEM; + goto fail; + } + + list = t; + list[count ++] = id; + } + + qsort_safe(list, count, sizeof(uint16_t), cmp_uint16); + + *options = list; + return count; + +fail: + free(list); + return r; +} + +static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) { + _cleanup_free_ char *j = NULL; + int r; + uint64_t x = 0; + + assert(name); + assert(u); + + r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j); + if (r < 0) + return r; + + r = safe_atou64(j, &x); + if (r < 0) + return r; + + *u = x; + return 0; +} + +int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) { + uint64_t x, y; + int r; + + assert(firmware); + assert(loader); + + r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x); + if (r < 0) + return r; + + r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y); + if (r < 0) + return r; + + if (y == 0 || y < x) + return -EIO; + + if (y > USEC_PER_HOUR) + return -EIO; + + *firmware = x; + *loader = y; + + return 0; +} + +int efi_loader_get_device_part_uuid(sd_id128_t *u) { + _cleanup_free_ char *p = NULL; + int r, parsed[16]; + unsigned i; + + assert(u); + + r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p); + if (r < 0) + return r; + + if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &parsed[0], &parsed[1], &parsed[2], &parsed[3], + &parsed[4], &parsed[5], &parsed[6], &parsed[7], + &parsed[8], &parsed[9], &parsed[10], &parsed[11], + &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16) + return -EIO; + + for (i = 0; i < ELEMENTSOF(parsed); i++) + u->bytes[i] = parsed[i]; + + return 0; +} + +#endif diff --git a/src/shared/efivars.h b/src/shared/efivars.h new file mode 100644 index 0000000..7921bed --- /dev/null +++ b/src/shared/efivars.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-id128.h" +#include "time-util.h" + +#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f) +#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c) + +bool is_efi_boot(void); +int is_efi_secure_boot(void); +int is_efi_secure_boot_setup_mode(void); + +int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size); +int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p); + +int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *partuuid, char **path); +int efi_get_boot_order(uint16_t **order); +int efi_get_boot_options(uint16_t **options); + +int efi_loader_get_device_part_uuid(sd_id128_t *u); +int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader); diff --git a/src/shared/env-util.c b/src/shared/env-util.c new file mode 100644 index 0000000..b2e4553 --- /dev/null +++ b/src/shared/env-util.c @@ -0,0 +1,453 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "strv.h" +#include "utf8.h" +#include "util.h" +#include "env-util.h" +#include "def.h" + +#define VALID_CHARS_ENV_NAME \ + DIGITS LETTERS \ + "_" + +#ifndef ARG_MAX +#define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX)) +#endif + +static bool env_name_is_valid_n(const char *e, size_t n) { + const char *p; + + if (!e) + return false; + + if (n <= 0) + return false; + + if (e[0] >= '0' && e[0] <= '9') + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, an individual assignment hence cannot be + * either. Discounting the equal sign and trailing NUL this + * hence leaves ARG_MAX-2 as longest possible variable + * name. */ + if (n > ARG_MAX - 2) + return false; + + for (p = e; p < e + n; p++) + if (!strchr(VALID_CHARS_ENV_NAME, *p)) + return false; + + return true; +} + +bool env_name_is_valid(const char *e) { + if (!e) + return false; + + return env_name_is_valid_n(e, strlen(e)); +} + +bool env_value_is_valid(const char *e) { + if (!e) + return false; + + if (!utf8_is_valid(e)) + return false; + + if (string_has_cc(e)) + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, an individual assignment hence cannot be + * either. Discounting the shortest possible variable name of + * length 1, the equal sign and trailing NUL this hence leaves + * ARG_MAX-3 as longest possible variable value. */ + if (strlen(e) > ARG_MAX - 3) + return false; + + return true; +} + +bool env_assignment_is_valid(const char *e) { + const char *eq; + + eq = strchr(e, '='); + if (!eq) + return false; + + if (!env_name_is_valid_n(e, eq - e)) + return false; + + if (!env_value_is_valid(eq + 1)) + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, hence the individual variable assignments + * cannot be either, but let's leave room for one trailing NUL + * byte. */ + if (strlen(e) > ARG_MAX - 1) + return false; + + return true; +} + +bool strv_env_is_valid(char **e) { + char **p, **q; + + STRV_FOREACH(p, e) { + size_t k; + + if (!env_assignment_is_valid(*p)) + return false; + + /* Check if there are duplicate assginments */ + k = strcspn(*p, "="); + STRV_FOREACH(q, p + 1) + if (strneq(*p, *q, k) && (*q)[k] == '=') + return false; + } + + return true; +} + +bool strv_env_name_or_assignment_is_valid(char **l) { + char **p, **q; + + STRV_FOREACH(p, l) { + if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p)) + return false; + + STRV_FOREACH(q, p + 1) + if (streq(*p, *q)) + return false; + } + + return true; +} + +static int env_append(char **r, char ***k, char **a) { + assert(r); + assert(k); + + if (!a) + return 0; + + /* Add the entries of a to *k unless they already exist in *r + * in which case they are overridden instead. This assumes + * there is enough space in the r array. */ + + for (; *a; a++) { + char **j; + size_t n; + + n = strcspn(*a, "="); + + if ((*a)[n] == '=') + n++; + + for (j = r; j < *k; j++) + if (strneq(*j, *a, n)) + break; + + if (j >= *k) + (*k)++; + else + free(*j); + + *j = strdup(*a); + if (!*j) + return -ENOMEM; + } + + return 0; +} + +char **strv_env_merge(unsigned n_lists, ...) { + size_t n = 0; + char **l, **k, **r; + va_list ap; + unsigned i; + + /* Merges an arbitrary number of environment sets */ + + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + l = va_arg(ap, char**); + n += strv_length(l); + } + va_end(ap); + + r = new(char*, n+1); + if (!r) + return NULL; + + k = r; + + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + l = va_arg(ap, char**); + if (env_append(r, &k, l) < 0) + goto fail; + } + va_end(ap); + + *k = NULL; + + return r; + +fail: + va_end(ap); + strv_free(r); + + return NULL; +} + +_pure_ static bool env_match(const char *t, const char *pattern) { + assert(t); + assert(pattern); + + /* pattern a matches string a + * a matches a= + * a matches a=b + * a= matches a= + * a=b matches a=b + * a= does not match a + * a=b does not match a= + * a=b does not match a + * a=b does not match a=c */ + + if (streq(t, pattern)) + return true; + + if (!strchr(pattern, '=')) { + size_t l = strlen(pattern); + + return strneq(t, pattern, l) && t[l] == '='; + } + + return false; +} + +char **strv_env_delete(char **x, unsigned n_lists, ...) { + size_t n, i = 0; + char **k, **r; + va_list ap; + + /* Deletes every entry from x that is mentioned in the other + * string lists */ + + n = strv_length(x); + + r = new(char*, n+1); + if (!r) + return NULL; + + STRV_FOREACH(k, x) { + unsigned v; + + va_start(ap, n_lists); + for (v = 0; v < n_lists; v++) { + char **l, **j; + + l = va_arg(ap, char**); + STRV_FOREACH(j, l) + if (env_match(*k, *j)) + goto skip; + } + va_end(ap); + + r[i] = strdup(*k); + if (!r[i]) { + strv_free(r); + return NULL; + } + + i++; + continue; + + skip: + va_end(ap); + } + + r[i] = NULL; + + assert(i <= n); + + return r; +} + +char **strv_env_unset(char **l, const char *p) { + + char **f, **t; + + if (!l) + return NULL; + + assert(p); + + /* Drops every occurrence of the env var setting p in the + * string list. Edits in-place. */ + + for (f = t = l; *f; f++) { + + if (env_match(*f, p)) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + +char **strv_env_unset_many(char **l, ...) { + + char **f, **t; + + if (!l) + return NULL; + + /* Like strv_env_unset() but applies many at once. Edits in-place. */ + + for (f = t = l; *f; f++) { + bool found = false; + const char *p; + va_list ap; + + va_start(ap, l); + + while ((p = va_arg(ap, const char*))) { + if (env_match(*f, p)) { + found = true; + break; + } + } + + va_end(ap); + + if (found) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + +char **strv_env_set(char **x, const char *p) { + + char **k, **r; + char* m[2] = { (char*) p, NULL }; + + /* Overrides the env var setting of p, returns a new copy */ + + r = new(char*, strv_length(x)+2); + if (!r) + return NULL; + + k = r; + if (env_append(r, &k, x) < 0) + goto fail; + + if (env_append(r, &k, m) < 0) + goto fail; + + *k = NULL; + + return r; + +fail: + strv_free(r); + return NULL; +} + +char *strv_env_get_n(char **l, const char *name, size_t k) { + char **i; + + assert(name); + + if (k <= 0) + return NULL; + + STRV_FOREACH(i, l) + if (strneq(*i, name, k) && + (*i)[k] == '=') + return *i + k + 1; + + return NULL; +} + +char *strv_env_get(char **l, const char *name) { + assert(name); + + return strv_env_get_n(l, name, strlen(name)); +} + +char **strv_env_clean_log(char **e, const char *message) { + char **p, **q; + int k = 0; + + STRV_FOREACH(p, e) { + size_t n; + bool duplicate = false; + + if (!env_assignment_is_valid(*p)) { + if (message) + log_error("Ignoring invalid environment '%s': %s", *p, message); + free(*p); + continue; + } + + n = strcspn(*p, "="); + STRV_FOREACH(q, p + 1) + if (strneq(*p, *q, n) && (*q)[n] == '=') { + duplicate = true; + break; + } + + if (duplicate) { + free(*p); + continue; + } + + e[k++] = *p; + } + + if (e) + e[k] = NULL; + + return e; +} + +char **strv_env_clean(char **e) { + return strv_env_clean_log(e, NULL); +} diff --git a/src/shared/env-util.h b/src/shared/env-util.h new file mode 100644 index 0000000..c0b1e38 --- /dev/null +++ b/src/shared/env-util.h @@ -0,0 +1,45 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +bool env_name_is_valid(const char *e); +bool env_value_is_valid(const char *e); +bool env_assignment_is_valid(const char *e); + +bool strv_env_is_valid(char **e); +char **strv_env_clean(char **l); +char **strv_env_clean_log(char **e, const char *message); + +bool strv_env_name_or_assignment_is_valid(char **l); + +char **strv_env_merge(unsigned n_lists, ...); +char **strv_env_delete(char **x, unsigned n_lists, ...); /* New copy */ + +char **strv_env_set(char **x, const char *p); /* New copy ... */ +char **strv_env_unset(char **l, const char *p); /* In place ... */ +char **strv_env_unset_many(char **l, ...) _sentinel_; + +char *strv_env_get_n(char **l, const char *name, size_t k) _pure_; +char *strv_env_get(char **x, const char *n) _pure_; diff --git a/src/shared/errno-list.c b/src/shared/errno-list.c new file mode 100644 index 0000000..c63296f --- /dev/null +++ b/src/shared/errno-list.c @@ -0,0 +1,59 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "errno-list.h" + +static const struct errno_name* lookup_errno(register const char *str, + register unsigned int len); + +#include "errno-to-name.h" +#include "errno-from-name.h" + +const char *errno_to_name(int id) { + + if (id < 0) + id = -id; + + if (id >= (int) ELEMENTSOF(errno_names)) + return NULL; + + return errno_names[id]; +} + +int errno_from_name(const char *name) { + const struct errno_name *sc; + + assert(name); + + sc = lookup_errno(name, strlen(name)); + if (!sc) + return 0; + + return sc->id; +} + +int errno_max(void) { + return ELEMENTSOF(errno_names); +} diff --git a/src/shared/errno-list.h b/src/shared/errno-list.h new file mode 100644 index 0000000..ba53329 --- /dev/null +++ b/src/shared/errno-list.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +const char *errno_to_name(int id); +int errno_from_name(const char *name); + +int errno_max(void); diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c new file mode 100644 index 0000000..902f55a --- /dev/null +++ b/src/shared/exit-status.c @@ -0,0 +1,218 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "exit-status.h" +#include "set.h" +#include "macro.h" + +const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { + + /* We cast to int here, so that -Wenum doesn't complain that + * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */ + + switch ((int) status) { + + case EXIT_SUCCESS: + return "SUCCESS"; + + case EXIT_FAILURE: + return "FAILURE"; + } + + + if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) { + switch ((int) status) { + + case EXIT_CHDIR: + return "CHDIR"; + + case EXIT_NICE: + return "NICE"; + + case EXIT_FDS: + return "FDS"; + + case EXIT_EXEC: + return "EXEC"; + + case EXIT_MEMORY: + return "MEMORY"; + + case EXIT_LIMITS: + return "LIMITS"; + + case EXIT_OOM_ADJUST: + return "OOM_ADJUST"; + + case EXIT_SIGNAL_MASK: + return "SIGNAL_MASK"; + + case EXIT_STDIN: + return "STDIN"; + + case EXIT_STDOUT: + return "STDOUT"; + + case EXIT_CHROOT: + return "CHROOT"; + + case EXIT_IOPRIO: + return "IOPRIO"; + + case EXIT_TIMERSLACK: + return "TIMERSLACK"; + + case EXIT_SECUREBITS: + return "SECUREBITS"; + + case EXIT_SETSCHEDULER: + return "SETSCHEDULER"; + + case EXIT_CPUAFFINITY: + return "CPUAFFINITY"; + + case EXIT_GROUP: + return "GROUP"; + + case EXIT_USER: + return "USER"; + + case EXIT_CAPABILITIES: + return "CAPABILITIES"; + + case EXIT_CGROUP: + return "CGROUP"; + + case EXIT_SETSID: + return "SETSID"; + + case EXIT_CONFIRM: + return "CONFIRM"; + + case EXIT_STDERR: + return "STDERR"; + + case EXIT_TCPWRAP: + return "TCPWRAP"; + + case EXIT_PAM: + return "PAM"; + + case EXIT_NETWORK: + return "NETWORK"; + + case EXIT_NAMESPACE: + return "NAMESPACE"; + + case EXIT_NO_NEW_PRIVILEGES: + return "NO_NEW_PRIVILEGES"; + + case EXIT_SECCOMP: + return "SECCOMP"; + + case EXIT_SELINUX_CONTEXT: + return "SELINUX_CONTEXT"; + + case EXIT_PERSONALITY: + return "PERSONALITY"; + + case EXIT_APPARMOR_PROFILE: + return "APPARMOR"; + } + } + + if (level == EXIT_STATUS_LSB) { + switch ((int) status) { + + case EXIT_INVALIDARGUMENT: + return "INVALIDARGUMENT"; + + case EXIT_NOTIMPLEMENTED: + return "NOTIMPLEMENTED"; + + case EXIT_NOPERMISSION: + return "NOPERMISSION"; + + case EXIT_NOTINSTALLED: + return "NOTINSSTALLED"; + + case EXIT_NOTCONFIGURED: + return "NOTCONFIGURED"; + + case EXIT_NOTRUNNING: + return "NOTRUNNING"; + } + } + + return NULL; +} + + +bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { + + if (code == CLD_EXITED) + return status == 0 || + (success_status && + set_contains(success_status->code, INT_TO_PTR(status))); + + /* If a daemon does not implement handlers for some of the + * signals that's not considered an unclean shutdown */ + if (code == CLD_KILLED) + return + status == SIGHUP || + status == SIGINT || + status == SIGTERM || + status == SIGPIPE || + (success_status && + set_contains(success_status->signal, INT_TO_PTR(status))); + + return false; +} + +bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) { + + if (is_clean_exit(code, status, success_status)) + return true; + + return + code == CLD_EXITED && + (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED); +} + +int parse_show_status(const char *v, ShowStatus *ret) { + int r; + + assert(v); + assert(ret); + + if (streq(v, "auto")) { + *ret = SHOW_STATUS_AUTO; + return 0; + } + r = parse_boolean(v); + if (r < 0) + return r; + *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO; + return 0; +} diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h new file mode 100644 index 0000000..de379f1 --- /dev/null +++ b/src/shared/exit-status.h @@ -0,0 +1,103 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "set.h" +typedef enum ExitStatus { + /* EXIT_SUCCESS defined by libc */ + /* EXIT_FAILURE defined by libc */ + EXIT_INVALIDARGUMENT = 2, + EXIT_NOTIMPLEMENTED = 3, + EXIT_NOPERMISSION = 4, + EXIT_NOTINSTALLED = 5, + EXIT_NOTCONFIGURED = 6, + EXIT_NOTRUNNING = 7, + + /* The LSB suggests that error codes >= 200 are "reserved". We + * use them here under the assumption that they hence are + * unused by init scripts. + * + * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ + + EXIT_CHDIR = 200, + EXIT_NICE, + EXIT_FDS, + EXIT_EXEC, + EXIT_MEMORY, + EXIT_LIMITS, + EXIT_OOM_ADJUST, + EXIT_SIGNAL_MASK, + EXIT_STDIN, + EXIT_STDOUT, + EXIT_CHROOT, /* 210 */ + EXIT_IOPRIO, + EXIT_TIMERSLACK, + EXIT_SECUREBITS, + EXIT_SETSCHEDULER, + EXIT_CPUAFFINITY, + EXIT_GROUP, + EXIT_USER, + EXIT_CAPABILITIES, + EXIT_CGROUP, + EXIT_SETSID, /* 220 */ + EXIT_CONFIRM, + EXIT_STDERR, + EXIT_TCPWRAP, + EXIT_PAM, + EXIT_NETWORK, + EXIT_NAMESPACE, + EXIT_NO_NEW_PRIVILEGES, + EXIT_SECCOMP, + EXIT_SELINUX_CONTEXT, + EXIT_PERSONALITY, /* 230 */ + EXIT_APPARMOR_PROFILE +} ExitStatus; + +typedef enum ExitStatusLevel { + EXIT_STATUS_MINIMAL, + EXIT_STATUS_SYSTEMD, + EXIT_STATUS_LSB, + EXIT_STATUS_FULL = EXIT_STATUS_LSB +} ExitStatusLevel; + +typedef struct ExitStatusSet { + Set *code; + Set *signal; +} ExitStatusSet; + +const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) _const_; + +bool is_clean_exit(int code, int status, ExitStatusSet *success_status); +bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status); + +/* Manager status */ + +typedef enum ShowStatus { + _SHOW_STATUS_UNSET = -2, + SHOW_STATUS_AUTO = -1, + SHOW_STATUS_NO = 0, + SHOW_STATUS_YES = 1, + SHOW_STATUS_TEMPORARY = 2, +} ShowStatus; + +int parse_show_status(const char *v, ShowStatus *ret); diff --git a/src/shared/fdset.c b/src/shared/fdset.c new file mode 100644 index 0000000..fd27398 --- /dev/null +++ b/src/shared/fdset.c @@ -0,0 +1,236 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "set.h" +#include "util.h" +#include "macro.h" +#include "fdset.h" +#include "sd-daemon.h" + +#define MAKE_SET(s) ((Set*) s) +#define MAKE_FDSET(s) ((FDSet*) s) + +/* Make sure we can distuingish fd 0 and NULL */ +#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) +#define PTR_TO_FD(p) (PTR_TO_INT(p)-1) + +FDSet *fdset_new(void) { + return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func)); +} + +void fdset_free(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)); + } + + set_free(MAKE_SET(s)); +} + +int fdset_put(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return set_put(MAKE_SET(s), FD_TO_PTR(fd)); +} + +int fdset_put_dup(FDSet *s, int fd) { + int copy, r; + + assert(s); + assert(fd >= 0); + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + r = fdset_put(s, copy); + if (r < 0) { + close_nointr_nofail(copy); + return r; + } + + return copy; +} + +bool fdset_contains(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); +} + +int fdset_remove(FDSet *s, int fd) { + assert(s); + assert(fd >= 0); + + return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; +} + +int fdset_new_fill(FDSet **_s) { + DIR *d; + struct dirent *de; + int r = 0; + FDSet *s; + + assert(_s); + + /* Creates an fdset and fills in all currently open file + * descriptors. */ + + d = opendir("/proc/self/fd"); + if (!d) + return -errno; + + s = fdset_new(); + if (!s) { + r = -ENOMEM; + goto finish; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (ignore_file(de->d_name)) + continue; + + r = safe_atoi(de->d_name, &fd); + if (r < 0) + goto finish; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + r = fdset_put(s, fd); + if (r < 0) + goto finish; + } + + r = 0; + *_s = s; + s = NULL; + +finish: + closedir(d); + + /* We won't close the fds here! */ + if (s) + set_free(MAKE_SET(s)); + + return r; +} + +int fdset_cloexec(FDSet *fds, bool b) { + Iterator i; + void *p; + int r; + + assert(fds); + + SET_FOREACH(p, MAKE_SET(fds), i) + if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0) + return r; + + return 0; +} + +int fdset_new_listen_fds(FDSet **_s, bool unset) { + int n, fd, r; + FDSet *s; + + assert(_s); + + /* Creates an fdset and fills in all passed file descriptors */ + + s = fdset_new(); + if (!s) { + r = -ENOMEM; + goto fail; + } + + n = sd_listen_fds(unset); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { + r = fdset_put(s, fd); + if (r < 0) + goto fail; + } + + *_s = s; + return 0; + + +fail: + if (s) + set_free(MAKE_SET(s)); + + return r; +} + +int fdset_close_others(FDSet *fds) { + void *e; + Iterator i; + int *a; + unsigned j, m; + + j = 0, m = fdset_size(fds); + a = alloca(sizeof(int) * m); + SET_FOREACH(e, MAKE_SET(fds), i) + a[j++] = PTR_TO_FD(e); + + assert(j == m); + + return close_all_fds(a, j); +} + +unsigned fdset_size(FDSet *fds) { + return set_size(MAKE_SET(fds)); +} + +int fdset_iterate(FDSet *s, Iterator *i) { + void *p; + + p = set_iterate(MAKE_SET(s), i); + if (!p) + return -ENOENT; + + return PTR_TO_FD(p); +} diff --git a/src/shared/fdset.h b/src/shared/fdset.h new file mode 100644 index 0000000..907acd7 --- /dev/null +++ b/src/shared/fdset.h @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "set.h" +#include "util.h" + +typedef struct FDSet FDSet; + +FDSet* fdset_new(void); +void fdset_free(FDSet *s); + +int fdset_put(FDSet *s, int fd); +int fdset_put_dup(FDSet *s, int fd); + +bool fdset_contains(FDSet *s, int fd); +int fdset_remove(FDSet *s, int fd); + +int fdset_new_fill(FDSet **_s); +int fdset_new_listen_fds(FDSet **_s, bool unset); + +int fdset_cloexec(FDSet *fds, bool b); + +int fdset_close_others(FDSet *fds); + +unsigned fdset_size(FDSet *fds); + +int fdset_iterate(FDSet *s, Iterator *i); + +#define FDSET_FOREACH(fd, fds, i) \ + for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i))) + +DEFINE_TRIVIAL_CLEANUP_FUNC(FDSet*, fdset_free); +#define _cleanup_fdset_free_ _cleanup_(fdset_freep) diff --git a/src/shared/fileio-label.c b/src/shared/fileio-label.c new file mode 100644 index 0000000..0711826 --- /dev/null +++ b/src/shared/fileio-label.c @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Harald Hoyer + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include +#include + +#include "fileio-label.h" +#include "label.h" + +int write_string_file_atomic_label(const char *fn, const char *line) { + int r; + + r = label_context_set(fn, S_IFREG); + if (r < 0) + return r; + + write_string_file_atomic(fn, line); + + label_context_clear(); + + return r; +} + +int write_env_file_label(const char *fname, char **l) { + int r; + + r = label_context_set(fname, S_IFREG); + if (r < 0) + return r; + + write_env_file(fname, l); + + label_context_clear(); + + return r; +} diff --git a/src/shared/fileio-label.h b/src/shared/fileio-label.h new file mode 100644 index 0000000..fce4fe0 --- /dev/null +++ b/src/shared/fileio-label.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2010 Harald Hoyer + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "fileio.h" + +int write_string_file_atomic_label(const char *fn, const char *line); +int write_env_file_label(const char *fname, char **l); diff --git a/src/shared/fileio.c b/src/shared/fileio.c new file mode 100644 index 0000000..0d3f2e9 --- /dev/null +++ b/src/shared/fileio.c @@ -0,0 +1,783 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include "fileio.h" +#include "util.h" +#include "strv.h" +#include "utf8.h" +#include "ctype.h" + +int write_string_to_file(FILE *f, const char *line) { + errno = 0; + fputs(line, f); + if (!endswith(line, "\n")) + fputc('\n', f); + + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +int write_string_file(const char *fn, const char *line) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(line); + + f = fopen(fn, "we"); + if (!f) + return -errno; + + return write_string_to_file(f, line); +} + +int write_string_file_atomic(const char *fn, const char *line) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(fn); + assert(line); + + r = fopen_temporary(fn, &f, &p); + if (r < 0) + return r; + + fchmod_umask(fileno(f), 0644); + + errno = 0; + fputs(line, f); + if (!endswith(line, "\n")) + fputc('\n', f); + + fflush(f); + + if (ferror(f)) + r = errno ? -errno : -EIO; + else { + if (rename(p, fn) < 0) + r = -errno; + else + r = 0; + } + + if (r < 0) + unlink(p); + + return r; +} + +int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; + char t[LINE_MAX], *c; + + assert(fn); + assert(line); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (!fgets(t, sizeof(t), f)) { + + if (ferror(f)) + return errno ? -errno : -EIO; + + t[0] = 0; + } + + c = strdup(t); + if (!c) + return -ENOMEM; + truncate_nl(c); + + *line = c; + return 0; +} + +ssize_t sendfile_full(int out_fd, const char *fn) { + _cleanup_fclose_ FILE *f; + struct stat st; + int r; + ssize_t s; + + size_t n, l; + _cleanup_free_ char *buf = NULL; + + assert(out_fd > 0); + assert(fn); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + r = fstat(fileno(f), &st); + if (r < 0) + return -errno; + + s = sendfile(out_fd, fileno(f), NULL, st.st_size); + if (s < 0) + if (errno == EINVAL || errno == ENOSYS) { + /* continue below */ + } else + return -errno; + else + return s; + + /* sendfile() failed, fall back to read/write */ + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + while (true) { + char *t; + size_t k; + + t = realloc(buf, n); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + r = write(out_fd, buf, l); + if (r < 0) + return -errno; + + return (ssize_t) l; +} + +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + size_t n, l; + _cleanup_free_ char *buf = NULL; + struct stat st; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (fstat(fileno(f), &st) < 0) + return -errno; + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + for (;;) { + char *t; + size_t k; + + t = realloc(buf, n+1); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + buf[l] = 0; + *contents = buf; + buf = NULL; /* do not free */ + + if (size) + *size = l; + + return 0; +} + +static int parse_env_file_internal( + const char *fname, + const char *newline, + int (*push) (const char *filename, unsigned line, + const char *key, char *value, void *userdata), + void *userdata) { + + _cleanup_free_ char *contents = NULL, *key = NULL; + size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; + char *p, *value = NULL; + int r; + unsigned line = 1; + + enum { + PRE_KEY, + KEY, + PRE_VALUE, + VALUE, + VALUE_ESCAPE, + SINGLE_QUOTE_VALUE, + SINGLE_QUOTE_VALUE_ESCAPE, + DOUBLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE_ESCAPE, + COMMENT, + COMMENT_ESCAPE + } state = PRE_KEY; + + assert(fname); + assert(newline); + + r = read_full_file(fname, &contents, NULL); + if (r < 0) + return r; + + for (p = contents; *p; p++) { + char c = *p; + + switch (state) { + + case PRE_KEY: + if (strchr(COMMENTS, c)) + state = COMMENT; + else if (!strchr(WHITESPACE, c)) { + state = KEY; + last_key_whitespace = (size_t) -1; + + if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } + + key[n_key++] = c; + } + break; + + case KEY: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + n_key = 0; + } else if (c == '=') { + state = PRE_VALUE; + last_value_whitespace = (size_t) -1; + } else { + if (!strchr(WHITESPACE, c)) + last_key_whitespace = (size_t) -1; + else if (last_key_whitespace == (size_t) -1) + last_key_whitespace = n_key; + + if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } + + key[n_key++] = c; + } + + break; + + case PRE_VALUE: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata); + if (r < 0) + goto fail; + + n_key = 0; + value = NULL; + value_alloc = n_value = 0; + + } else if (c == '\'') + state = SINGLE_QUOTE_VALUE; + else if (c == '\"') + state = DOUBLE_QUOTE_VALUE; + else if (c == '\\') + state = VALUE_ESCAPE; + else if (!strchr(WHITESPACE, c)) { + state = VALUE; + + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case VALUE: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + /* Chomp off trailing whitespace from value */ + if (last_value_whitespace != (size_t) -1) + value[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata); + if (r < 0) + goto fail; + + n_key = 0; + value = NULL; + value_alloc = n_value = 0; + + } else if (c == '\\') { + state = VALUE_ESCAPE; + last_value_whitespace = (size_t) -1; + } else { + if (!strchr(WHITESPACE, c)) + last_value_whitespace = (size_t) -1; + else if (last_value_whitespace == (size_t) -1) + last_value_whitespace = n_value; + + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case VALUE_ESCAPE: + state = VALUE; + + if (!strchr(newline, c)) { + /* Escaped newlines we eat up entirely */ + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case SINGLE_QUOTE_VALUE: + if (c == '\'') + state = PRE_VALUE; + else if (c == '\\') + state = SINGLE_QUOTE_VALUE_ESCAPE; + else { + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case SINGLE_QUOTE_VALUE_ESCAPE: + state = SINGLE_QUOTE_VALUE; + + if (!strchr(newline, c)) { + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case DOUBLE_QUOTE_VALUE: + if (c == '\"') + state = PRE_VALUE; + else if (c == '\\') + state = DOUBLE_QUOTE_VALUE_ESCAPE; + else { + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case DOUBLE_QUOTE_VALUE_ESCAPE: + state = DOUBLE_QUOTE_VALUE; + + if (!strchr(newline, c)) { + if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case COMMENT: + if (c == '\\') + state = COMMENT_ESCAPE; + else if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + } + break; + + case COMMENT_ESCAPE: + state = COMMENT; + break; + } + } + + if (state == PRE_VALUE || + state == VALUE || + state == VALUE_ESCAPE || + state == SINGLE_QUOTE_VALUE || + state == SINGLE_QUOTE_VALUE_ESCAPE || + state == DOUBLE_QUOTE_VALUE || + state == DOUBLE_QUOTE_VALUE_ESCAPE) { + + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + if (state == VALUE) + if (last_value_whitespace != (size_t) -1) + value[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata); + if (r < 0) + goto fail; + } + + return 0; + +fail: + free(value); + return r; +} + +static int parse_env_file_push(const char *filename, unsigned line, + const char *key, char *value, void *userdata) { + + const char *k; + va_list aq, *ap = userdata; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *p = utf8_escape_invalid(key); + + log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", + filename, line, p); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *p = utf8_escape_invalid(value); + + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", + filename, line, key, p); + return -EINVAL; + } + + va_copy(aq, *ap); + + while ((k = va_arg(aq, const char *))) { + char **v; + + v = va_arg(aq, char **); + + if (streq(key, k)) { + va_end(aq); + free(*v); + *v = value; + return 1; + } + } + + va_end(aq); + free(value); + return 0; +} + +int parse_env_file( + const char *fname, + const char *newline, ...) { + + va_list ap; + int r; + + if (!newline) + newline = NEWLINE; + + va_start(ap, newline); + r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap); + va_end(ap); + + return r; +} + +static int load_env_file_push(const char *filename, unsigned line, + const char *key, char *value, void *userdata) { + char ***m = userdata; + char *p; + int r; + + if (!utf8_is_valid(key)) { + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", + filename, line, key); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + /* FIXME: filter UTF-8 */ + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", + filename, line, key, value); + return -EINVAL; + } + + p = strjoin(key, "=", strempty(value), NULL); + if (!p) + return -ENOMEM; + + r = strv_push(m, p); + if (r < 0) { + free(p); + return r; + } + + free(value); + return 0; +} + +int load_env_file(const char *fname, const char *newline, char ***rl) { + char **m = NULL; + int r; + + if (!newline) + newline = NEWLINE; + + r = parse_env_file_internal(fname, newline, load_env_file_push, &m); + if (r < 0) { + strv_free(m); + return r; + } + + *rl = m; + return 0; +} + +static void write_env_var(FILE *f, const char *v) { + const char *p; + + p = strchr(v, '='); + if (!p) { + /* Fallback */ + fputs(v, f); + fputc('\n', f); + return; + } + + p++; + fwrite(v, 1, p-v, f); + + if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) { + fputc('\"', f); + + for (; *p; p++) { + if (strchr("\'\"\\`$", *p)) + fputc('\\', f); + + fputc(*p, f); + } + + fputc('\"', f); + } else + fputs(p, f); + + fputc('\n', f); +} + +int write_env_file(const char *fname, char **l) { + char **i; + _cleanup_free_ char *p = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + r = fopen_temporary(fname, &f, &p); + if (r < 0) + return r; + + fchmod_umask(fileno(f), 0644); + + errno = 0; + STRV_FOREACH(i, l) + write_env_var(f, *i); + + fflush(f); + + if (ferror(f)) + r = errno ? -errno : -EIO; + else { + if (rename(p, fname) < 0) + r = -errno; + else + r = 0; + } + + if (r < 0) + unlink(p); + + return r; +} + +int executable_is_script(const char *path, char **interpreter) { + int r; + char _cleanup_free_ *line = NULL; + int len; + char *ans; + + assert(path); + + r = read_one_line_file(path, &line); + if (r < 0) + return r; + + if (!startswith(line, "#!")) + return 0; + + ans = strstrip(line + 2); + len = strcspn(ans, " \t"); + + if (len == 0) + return 0; + + ans = strndup(ans, len); + if (!ans) + return -ENOMEM; + + *interpreter = ans; + return 1; +} + +/** + * Retrieve one field from a file like /proc/self/status. pattern + * should start with '\n' and end with a ':'. Whitespace and zeros + * after the ':' will be skipped. field must be freed afterwards. + */ +int get_status_field(const char *filename, const char *pattern, char **field) { + _cleanup_free_ char *status = NULL; + char *t; + size_t len; + int r; + + assert(filename); + assert(pattern); + assert(field); + + r = read_full_file(filename, &status, NULL); + if (r < 0) + return r; + + t = strstr(status, pattern); + if (!t) + return -ENOENT; + + t += strlen(pattern); + if (*t) { + t += strspn(t, " \t"); + + /* Also skip zeros, because when this is used for + * capabilities, we don't want the zeros. This way the + * same capability set always maps to the same string, + * irrespective of the total capability set size. For + * other numbers it shouldn't matter. */ + t += strspn(t, "0"); + /* Back off one char if there's nothing but whitespace + and zeros */ + if (!*t || isspace(*t)) + t --; + } + + len = strcspn(t, WHITESPACE); + + *field = strndup(t, len); + if (!*field) + return -ENOMEM; + + return 0; +} diff --git a/src/shared/fileio.h b/src/shared/fileio.h new file mode 100644 index 0000000..06c2887 --- /dev/null +++ b/src/shared/fileio.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include + +#include "macro.h" + +int write_string_to_file(FILE *f, const char *line); +int write_string_file(const char *fn, const char *line); +int write_string_file_atomic(const char *fn, const char *line); + +int read_one_line_file(const char *fn, char **line); +int read_full_file(const char *fn, char **contents, size_t *size); +ssize_t sendfile_full(int out_fd, const char *fn); + +int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; +int load_env_file(const char *fname, const char *separator, char ***l); +int write_env_file(const char *fname, char **l); + +int executable_is_script(const char *path, char **interpreter); + +int get_status_field(const char *filename, const char *pattern, char **field); diff --git a/src/shared/gunicode.c b/src/shared/gunicode.c new file mode 100644 index 0000000..d89a2f3 --- /dev/null +++ b/src/shared/gunicode.c @@ -0,0 +1,110 @@ +/* gunicode.c - Unicode manipulation functions + * + * Copyright (C) 1999, 2000 Tom Tromey + * Copyright 2000, 2005 Red Hat, Inc. + */ + +#include "gunicode.h" + +#define unichar uint32_t + +/** + * g_utf8_prev_char: + * @p: a pointer to a position within a UTF-8 encoded string + * + * Finds the previous UTF-8 character in the string before @p. + * + * @p does not have to be at the beginning of a UTF-8 character. No check + * is made to see if the character found is actually valid other than + * it starts with an appropriate byte. If @p might be the first + * character of the string, you must use g_utf8_find_prev_char() instead. + * + * Return value: a pointer to the found character. + **/ +char * +utf8_prev_char (const char *p) +{ + while (1) + { + p--; + if ((*p & 0xc0) != 0x80) + return (char *)p; + } +} + +struct Interval +{ + unichar start, end; +}; + +static int +interval_compare (const void *key, const void *elt) +{ + unichar c = (unichar) (long) (key); + struct Interval *interval = (struct Interval *)elt; + + if (c < interval->start) + return -1; + if (c > interval->end) + return +1; + + return 0; +} + +/* + * NOTE: + * + * The tables for g_unichar_iswide() and g_unichar_iswide_cjk() are + * generated from the Unicode Character Database's file + * extracted/DerivedEastAsianWidth.txt using the gen-iswide-table.py + * in this way: + * + * ./gen-iswide-table.py < path/to/ucd/extracted/DerivedEastAsianWidth.txt | fmt + * + * Last update for Unicode 6.0. + */ + +/** + * g_unichar_iswide: + * @c: a Unicode character + * + * Determines if a character is typically rendered in a double-width + * cell. + * + * Return value: %TRUE if the character is wide + **/ +bool +unichar_iswide (unichar c) +{ + /* See NOTE earlier for how to update this table. */ + static const struct Interval wide[] = { + {0x1100, 0x115F}, {0x2329, 0x232A}, {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, + {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, {0x3000, 0x303E}, {0x3041, 0x3096}, + {0x3099, 0x30FF}, {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA}, + {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x32FE}, + {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C}, + {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, + {0x1B000, 0x1B001}, {0x1F200, 0x1F202}, {0x1F210, 0x1F23A}, + {0x1F240, 0x1F248}, {0x1F250, 0x1F251}, + {0x1F300, 0x1F567}, /* Miscellaneous Symbols and Pictographs */ + {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD}, + }; + + if (bsearch ((void *)(uintptr_t)c, wide, (sizeof (wide) / sizeof ((wide)[0])), sizeof wide[0], + interval_compare)) + return true; + + return false; +} + +const char utf8_skip_data[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; diff --git a/src/shared/gunicode.h b/src/shared/gunicode.h new file mode 100644 index 0000000..a4b2934 --- /dev/null +++ b/src/shared/gunicode.h @@ -0,0 +1,28 @@ +/* gunicode.h - Unicode manipulation functions + * + * Copyright (C) 1999, 2000 Tom Tromey + * Copyright 2000, 2005 Red Hat, Inc. + */ + +#include +#include +#include + +char *utf8_prev_char (const char *p); + +extern const char utf8_skip_data[256]; + +/** + * g_utf8_next_char: + * @p: Pointer to the start of a valid UTF-8 character + * + * Skips to the next character in a UTF-8 string. The string must be + * valid; this macro is as fast as possible, and has no error-checking. + * You would use this macro to iterate over a string character by + * character. The macro returns the start of the next UTF-8 character. + * Before using this macro, use g_utf8_validate() to validate strings + * that may contain invalid UTF-8. + */ +#define utf8_next_char(p) (char *)((p) + utf8_skip_data[*(const unsigned char *)(p)]) + +bool unichar_iswide (uint32_t c); diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c new file mode 100644 index 0000000..65b7b74 --- /dev/null +++ b/src/shared/hashmap.c @@ -0,0 +1,959 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "hashmap.h" +#include "macro.h" +#include "siphash24.h" + +#define INITIAL_N_BUCKETS 31 + +struct hashmap_entry { + const void *key; + void *value; + struct hashmap_entry *bucket_next, *bucket_previous; + struct hashmap_entry *iterate_next, *iterate_previous; +}; + +struct Hashmap { + hash_func_t hash_func; + compare_func_t compare_func; + + struct hashmap_entry *iterate_list_head, *iterate_list_tail; + + struct hashmap_entry ** buckets; + unsigned n_buckets, n_entries; + + uint8_t hash_key[HASH_KEY_SIZE]; + bool from_pool:1; +}; + +struct pool { + struct pool *next; + unsigned n_tiles; + unsigned n_used; +}; + +static struct pool *first_hashmap_pool = NULL; +static void *first_hashmap_tile = NULL; + +static struct pool *first_entry_pool = NULL; +static void *first_entry_tile = NULL; + +static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size, unsigned at_least) { + unsigned i; + + /* When a tile is released we add it to the list and simply + * place the next pointer at its offset 0. */ + + assert(tile_size >= sizeof(void*)); + assert(at_least > 0); + + if (*first_tile) { + void *r; + + r = *first_tile; + *first_tile = * (void**) (*first_tile); + return r; + } + + if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) { + unsigned n; + size_t size; + struct pool *p; + + n = *first_pool ? (*first_pool)->n_tiles : 0; + n = MAX(at_least, n * 2); + size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); + n = (size - ALIGN(sizeof(struct pool))) / tile_size; + + p = malloc(size); + if (!p) + return NULL; + + p->next = *first_pool; + p->n_tiles = n; + p->n_used = 0; + + *first_pool = p; + } + + i = (*first_pool)->n_used++; + + return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size; +} + +static void deallocate_tile(void **first_tile, void *p) { + * (void**) p = *first_tile; + *first_tile = p; +} + +#ifdef VALGRIND + +static void drop_pool(struct pool *p) { + while (p) { + struct pool *n; + n = p->next; + free(p); + p = n; + } +} + +__attribute__((destructor)) static void cleanup_pool(void) { + /* Be nice to valgrind */ + + drop_pool(first_hashmap_pool); + drop_pool(first_entry_pool); +} + +#endif + +unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, p, strlen(p), hash_key); + return (unsigned long) u; +} + +int string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); + return (unsigned long) u; +} + +int trivial_compare_func(const void *a, const void *b) { + return a < b ? -1 : (a > b ? 1 : 0); +} + +unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { + uint64_t u; + siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key); + return (unsigned long) u; +} + +int uint64_compare_func(const void *_a, const void *_b) { + uint64_t a, b; + a = *(const uint64_t*) _a; + b = *(const uint64_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +static unsigned bucket_hash(Hashmap *h, const void *p) { + return (unsigned) (h->hash_func(p, h->hash_key) % h->n_buckets); +} + +static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { + static uint8_t current[HASH_KEY_SIZE]; + static bool current_initialized = false; + + /* Returns a hash function key to use. In order to keep things + * fast we will not generate a new key each time we allocate a + * new hash table. Instead, we'll just reuse the most recently + * generated one, except if we never generated one or when we + * are rehashing an entire hash table because we reached a + * fill level */ + + if (!current_initialized || !reuse_is_ok) { + random_bytes(current, sizeof(current)); + current_initialized = true; + } + + memcpy(hash_key, current, sizeof(current)); +} + +Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { + bool b; + Hashmap *h; + size_t size; + + b = is_main_thread(); + + size = ALIGN(sizeof(Hashmap)) + INITIAL_N_BUCKETS * sizeof(struct hashmap_entry*); + + if (b) { + h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size, 8); + if (!h) + return NULL; + + memzero(h, size); + } else { + h = malloc0(size); + + if (!h) + return NULL; + } + + h->hash_func = hash_func ? hash_func : trivial_hash_func; + h->compare_func = compare_func ? compare_func : trivial_compare_func; + + h->n_buckets = INITIAL_N_BUCKETS; + h->n_entries = 0; + h->iterate_list_head = h->iterate_list_tail = NULL; + + h->buckets = (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))); + + h->from_pool = b; + + get_hash_key(h->hash_key, true); + + return h; +} + +int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) { + Hashmap *q; + + assert(h); + + if (*h) + return 0; + + q = hashmap_new(hash_func, compare_func); + if (!q) + return -ENOMEM; + + *h = q; + return 0; +} + +static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { + assert(h); + assert(e); + + /* Insert into hash table */ + e->bucket_next = h->buckets[hash]; + e->bucket_previous = NULL; + if (h->buckets[hash]) + h->buckets[hash]->bucket_previous = e; + h->buckets[hash] = e; + + /* Insert into iteration list */ + e->iterate_previous = h->iterate_list_tail; + e->iterate_next = NULL; + if (h->iterate_list_tail) { + assert(h->iterate_list_head); + h->iterate_list_tail->iterate_next = e; + } else { + assert(!h->iterate_list_head); + h->iterate_list_head = e; + } + h->iterate_list_tail = e; + + h->n_entries++; + assert(h->n_entries >= 1); +} + +static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { + assert(h); + assert(e); + + /* Remove from iteration list */ + if (e->iterate_next) + e->iterate_next->iterate_previous = e->iterate_previous; + else + h->iterate_list_tail = e->iterate_previous; + + if (e->iterate_previous) + e->iterate_previous->iterate_next = e->iterate_next; + else + h->iterate_list_head = e->iterate_next; + + /* Remove from hash table bucket list */ + if (e->bucket_next) + e->bucket_next->bucket_previous = e->bucket_previous; + + if (e->bucket_previous) + e->bucket_previous->bucket_next = e->bucket_next; + else + h->buckets[hash] = e->bucket_next; + + assert(h->n_entries >= 1); + h->n_entries--; +} + +static void remove_entry(Hashmap *h, struct hashmap_entry *e) { + unsigned hash; + + assert(h); + assert(e); + + hash = bucket_hash(h, e->key); + unlink_entry(h, e, hash); + + if (h->from_pool) + deallocate_tile(&first_entry_tile, e); + else + free(e); +} + +void hashmap_free(Hashmap*h) { + + /* Free the hashmap, but nothing in it */ + + if (!h) + return; + + hashmap_clear(h); + + if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap)))) + free(h->buckets); + + if (h->from_pool) + deallocate_tile(&first_hashmap_tile, h); + else + free(h); +} + +void hashmap_free_free(Hashmap *h) { + + /* Free the hashmap and all data objects in it, but not the + * keys */ + + if (!h) + return; + + hashmap_clear_free(h); + hashmap_free(h); +} + +void hashmap_free_free_free(Hashmap *h) { + + /* Free the hashmap and all data and key objects in it */ + + if (!h) + return; + + hashmap_clear_free_free(h); + hashmap_free(h); +} + +void hashmap_clear(Hashmap *h) { + if (!h) + return; + + while (h->iterate_list_head) + remove_entry(h, h->iterate_list_head); +} + +void hashmap_clear_free(Hashmap *h) { + void *p; + + if (!h) + return; + + while ((p = hashmap_steal_first(h))) + free(p); +} + +void hashmap_clear_free_free(Hashmap *h) { + if (!h) + return; + + while (h->iterate_list_head) { + void *a, *b; + + a = h->iterate_list_head->value; + b = (void*) h->iterate_list_head->key; + remove_entry(h, h->iterate_list_head); + free(a); + free(b); + } +} + +static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { + struct hashmap_entry *e; + assert(h); + assert(hash < h->n_buckets); + + for (e = h->buckets[hash]; e; e = e->bucket_next) + if (h->compare_func(e->key, key) == 0) + return e; + + return NULL; +} + +static bool resize_buckets(Hashmap *h) { + struct hashmap_entry **n, *i; + unsigned m; + uint8_t nkey[HASH_KEY_SIZE]; + + assert(h); + + if (_likely_(h->n_entries*4 < h->n_buckets*3)) + return false; + + /* Increase by four */ + m = (h->n_entries+1)*4-1; + + /* If we hit OOM we simply risk packed hashmaps... */ + n = new0(struct hashmap_entry*, m); + if (!n) + return false; + + /* Let's use a different randomized hash key for the + * extension, so that people cannot guess what we are using + * here forever */ + get_hash_key(nkey, false); + + for (i = h->iterate_list_head; i; i = i->iterate_next) { + unsigned long old_bucket, new_bucket; + + old_bucket = h->hash_func(i->key, h->hash_key) % h->n_buckets; + + /* First, drop from old bucket table */ + if (i->bucket_next) + i->bucket_next->bucket_previous = i->bucket_previous; + + if (i->bucket_previous) + i->bucket_previous->bucket_next = i->bucket_next; + else + h->buckets[old_bucket] = i->bucket_next; + + /* Then, add to new backet table */ + new_bucket = h->hash_func(i->key, nkey) % m; + + i->bucket_next = n[new_bucket]; + i->bucket_previous = NULL; + if (n[new_bucket]) + n[new_bucket]->bucket_previous = i; + n[new_bucket] = i; + } + + if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap)))) + free(h->buckets); + + h->buckets = n; + h->n_buckets = m; + + memcpy(h->hash_key, nkey, HASH_KEY_SIZE); + + return true; +} + +int hashmap_put(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + assert(h); + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (e) { + if (e->value == value) + return 0; + return -EEXIST; + } + + if (resize_buckets(h)) + hash = bucket_hash(h, key); + + if (h->from_pool) + e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry), 64U); + else + e = new(struct hashmap_entry, 1); + + if (!e) + return -ENOMEM; + + e->key = key; + e->value = value; + + link_entry(h, e, hash); + + return 1; +} + +int hashmap_replace(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + assert(h); + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (e) { + e->key = key; + e->value = value; + return 0; + } + + return hashmap_put(h, key, value); +} + +int hashmap_update(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + assert(h); + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return -ENOENT; + + e->value = value; + return 0; +} + +void* hashmap_get(Hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + return e->value; +} + +void* hashmap_get2(Hashmap *h, const void *key, void **key2) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + if (key2) + *key2 = (void*) e->key; + + return e->value; +} + +bool hashmap_contains(Hashmap *h, const void *key) { + unsigned hash; + + if (!h) + return false; + + hash = bucket_hash(h, key); + return !!hash_scan(h, hash, key); +} + +void* hashmap_remove(Hashmap *h, const void *key) { + struct hashmap_entry *e; + unsigned hash; + void *data; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + data = e->value; + remove_entry(h, e); + + return data; +} + +int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { + struct hashmap_entry *e; + unsigned old_hash, new_hash; + + if (!h) + return -ENOENT; + + old_hash = bucket_hash(h, old_key); + e = hash_scan(h, old_hash, old_key); + if (!e) + return -ENOENT; + + new_hash = bucket_hash(h, new_key); + if (hash_scan(h, new_hash, new_key)) + return -EEXIST; + + unlink_entry(h, e, old_hash); + + e->key = new_key; + e->value = value; + + link_entry(h, e, new_hash); + + return 0; +} + +int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { + struct hashmap_entry *e, *k; + unsigned old_hash, new_hash; + + if (!h) + return -ENOENT; + + old_hash = bucket_hash(h, old_key); + e = hash_scan(h, old_hash, old_key); + if (!e) + return -ENOENT; + + new_hash = bucket_hash(h, new_key); + k = hash_scan(h, new_hash, new_key); + if (k) + if (e != k) + remove_entry(h, k); + + unlink_entry(h, e, old_hash); + + e->key = new_key; + e->value = value; + + link_entry(h, e, new_hash); + + return 0; +} + +void* hashmap_remove_value(Hashmap *h, const void *key, void *value) { + struct hashmap_entry *e; + unsigned hash; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + if (e->value != value) + return NULL; + + remove_entry(h, e); + + return value; +} + +void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { + struct hashmap_entry *e; + + assert(i); + + if (!h) + goto at_end; + + if (*i == ITERATOR_LAST) + goto at_end; + + if (*i == ITERATOR_FIRST && !h->iterate_list_head) + goto at_end; + + e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i; + + if (e->iterate_next) + *i = (Iterator) e->iterate_next; + else + *i = ITERATOR_LAST; + + if (key) + *key = e->key; + + return e->value; + +at_end: + *i = ITERATOR_LAST; + + if (key) + *key = NULL; + + return NULL; +} + +void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { + struct hashmap_entry *e; + + assert(i); + + if (!h) + goto at_beginning; + + if (*i == ITERATOR_FIRST) + goto at_beginning; + + if (*i == ITERATOR_LAST && !h->iterate_list_tail) + goto at_beginning; + + e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; + + if (e->iterate_previous) + *i = (Iterator) e->iterate_previous; + else + *i = ITERATOR_FIRST; + + if (key) + *key = e->key; + + return e->value; + +at_beginning: + *i = ITERATOR_FIRST; + + if (key) + *key = NULL; + + return NULL; +} + +void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) { + unsigned hash; + struct hashmap_entry *e; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + *i = (Iterator) e; + + return e->value; +} + +void* hashmap_first(Hashmap *h) { + + if (!h) + return NULL; + + if (!h->iterate_list_head) + return NULL; + + return h->iterate_list_head->value; +} + +void* hashmap_first_key(Hashmap *h) { + + if (!h) + return NULL; + + if (!h->iterate_list_head) + return NULL; + + return (void*) h->iterate_list_head->key; +} + +void* hashmap_last(Hashmap *h) { + + if (!h) + return NULL; + + if (!h->iterate_list_tail) + return NULL; + + return h->iterate_list_tail->value; +} + +void* hashmap_steal_first(Hashmap *h) { + void *data; + + if (!h) + return NULL; + + if (!h->iterate_list_head) + return NULL; + + data = h->iterate_list_head->value; + remove_entry(h, h->iterate_list_head); + + return data; +} + +void* hashmap_steal_first_key(Hashmap *h) { + void *key; + + if (!h) + return NULL; + + if (!h->iterate_list_head) + return NULL; + + key = (void*) h->iterate_list_head->key; + remove_entry(h, h->iterate_list_head); + + return key; +} + +unsigned hashmap_size(Hashmap *h) { + + if (!h) + return 0; + + return h->n_entries; +} + +unsigned hashmap_buckets(Hashmap *h) { + + if (!h) + return 0; + + return h->n_buckets; +} + +bool hashmap_isempty(Hashmap *h) { + + if (!h) + return true; + + return h->n_entries == 0; +} + +int hashmap_merge(Hashmap *h, Hashmap *other) { + struct hashmap_entry *e; + + assert(h); + + if (!other) + return 0; + + for (e = other->iterate_list_head; e; e = e->iterate_next) { + int r; + + r = hashmap_put(h, e->key, e->value); + if (r < 0 && r != -EEXIST) + return r; + } + + return 0; +} + +void hashmap_move(Hashmap *h, Hashmap *other) { + struct hashmap_entry *e, *n; + + assert(h); + + /* The same as hashmap_merge(), but every new item from other + * is moved to h. This function is guaranteed to succeed. */ + + if (!other) + return; + + for (e = other->iterate_list_head; e; e = n) { + unsigned h_hash, other_hash; + + n = e->iterate_next; + + h_hash = bucket_hash(h, e->key); + if (hash_scan(h, h_hash, e->key)) + continue; + + other_hash = bucket_hash(other, e->key); + unlink_entry(other, e, other_hash); + link_entry(h, e, h_hash); + } +} + +int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { + unsigned h_hash, other_hash; + struct hashmap_entry *e; + + if (!other) + return 0; + + assert(h); + + h_hash = bucket_hash(h, key); + if (hash_scan(h, h_hash, key)) + return -EEXIST; + + other_hash = bucket_hash(other, key); + e = hash_scan(other, other_hash, key); + if (!e) + return -ENOENT; + + unlink_entry(other, e, other_hash); + link_entry(h, e, h_hash); + + return 0; +} + +Hashmap *hashmap_copy(Hashmap *h) { + Hashmap *copy; + + assert(h); + + copy = hashmap_new(h->hash_func, h->compare_func); + if (!copy) + return NULL; + + if (hashmap_merge(copy, h) < 0) { + hashmap_free(copy); + return NULL; + } + + return copy; +} + +char **hashmap_get_strv(Hashmap *h) { + char **sv; + Iterator it; + char *item; + int n; + + sv = new(char*, h->n_entries+1); + if (!sv) + return NULL; + + n = 0; + HASHMAP_FOREACH(item, h, it) + sv[n++] = item; + sv[n] = NULL; + + return sv; +} + +void *hashmap_next(Hashmap *h, const void *key) { + unsigned hash; + struct hashmap_entry *e; + + assert(h); + assert(key); + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + e = hash_scan(h, hash, key); + if (!e) + return NULL; + + e = e->iterate_next; + if (!e) + return NULL; + + return e->value; +} diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h new file mode 100644 index 0000000..154f68e --- /dev/null +++ b/src/shared/hashmap.h @@ -0,0 +1,116 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" +#include "util.h" + +/* Pretty straightforward hash table implementation. As a minor + * optimization a NULL hashmap object will be treated as empty hashmap + * for all read operations. That way it is not necessary to + * instantiate an object for each Hashmap use. */ + +#define HASH_KEY_SIZE 16 + +typedef struct Hashmap Hashmap; +typedef struct _IteratorStruct _IteratorStruct; +typedef _IteratorStruct* Iterator; + +#define ITERATOR_FIRST ((Iterator) 0) +#define ITERATOR_LAST ((Iterator) -1) + +typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +typedef int (*compare_func_t)(const void *a, const void *b); + +unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +int string_compare_func(const void *a, const void *b) _pure_; + +/* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ +unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +int trivial_compare_func(const void *a, const void *b) _const_; + +unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +int uint64_compare_func(const void *a, const void *b) _pure_; + +Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); +void hashmap_free(Hashmap *h); +void hashmap_free_free(Hashmap *h); +void hashmap_free_free_free(Hashmap *h); +Hashmap *hashmap_copy(Hashmap *h); +int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func); + +int hashmap_put(Hashmap *h, const void *key, void *value); +int hashmap_update(Hashmap *h, const void *key, void *value); +int hashmap_replace(Hashmap *h, const void *key, void *value); +void *hashmap_get(Hashmap *h, const void *key); +void *hashmap_get2(Hashmap *h, const void *key, void **rkey); +bool hashmap_contains(Hashmap *h, const void *key); +void *hashmap_remove(Hashmap *h, const void *key); +void *hashmap_remove_value(Hashmap *h, const void *key, void *value); +int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); +int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); + +int hashmap_merge(Hashmap *h, Hashmap *other); +void hashmap_move(Hashmap *h, Hashmap *other); +int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key); + +unsigned hashmap_size(Hashmap *h) _pure_; +bool hashmap_isempty(Hashmap *h) _pure_; +unsigned hashmap_buckets(Hashmap *h) _pure_; + +void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); +void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); +void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i); + +void hashmap_clear(Hashmap *h); +void hashmap_clear_free(Hashmap *h); +void hashmap_clear_free_free(Hashmap *h); + +void *hashmap_steal_first(Hashmap *h); +void *hashmap_steal_first_key(Hashmap *h); +void *hashmap_first(Hashmap *h) _pure_; +void *hashmap_first_key(Hashmap *h) _pure_; +void *hashmap_last(Hashmap *h) _pure_; + +void *hashmap_next(Hashmap *h, const void *key); + +char **hashmap_get_strv(Hashmap *h); + +#define HASHMAP_FOREACH(e, h, i) \ + for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) + +#define HASHMAP_FOREACH_KEY(e, k, h, i) \ + for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k))) + +#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \ + for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL)) + +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); +#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) +#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) +#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep) diff --git a/src/shared/hwclock.c b/src/shared/hwclock.c new file mode 100644 index 0000000..7059d9c --- /dev/null +++ b/src/shared/hwclock.c @@ -0,0 +1,154 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "log.h" +#include "strv.h" +#include "hwclock.h" +#include "fileio.h" + +int hwclock_get_time(struct tm *tm) { + _cleanup_close_ int fd = -1; + + assert(tm); + + fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC); + if (fd < 0) + return -errno; + + /* This leaves the timezone fields of struct tm + * uninitialized! */ + if (ioctl(fd, RTC_RD_TIME, tm) < 0) + return -errno; + + /* We don't know daylight saving, so we reset this in order not + * to confuse mktime(). */ + tm->tm_isdst = -1; + + return 0; +} + +int hwclock_set_time(const struct tm *tm) { + _cleanup_close_ int fd = -1; + + assert(tm); + + fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (ioctl(fd, RTC_SET_TIME, tm) < 0) + return -errno; + + return 0; +} + +int hwclock_is_localtime(void) { + _cleanup_fclose_ FILE *f; + + /* + * The third line of adjtime is "UTC" or "LOCAL" or nothing. + * # /etc/adjtime + * 0.0 0 0 + * 0 + * UTC + */ + f = fopen("/etc/adjtime", "re"); + if (f) { + char line[LINE_MAX]; + bool b; + + b = fgets(line, sizeof(line), f) && + fgets(line, sizeof(line), f) && + fgets(line, sizeof(line), f); + if (!b) + return -EIO; + + truncate_nl(line); + return streq(line, "LOCAL"); + + } else if (errno != ENOENT) + return -errno; + + return 0; +} + +int hwclock_set_timezone(int *min) { + const struct timeval *tv_null = NULL; + struct timespec ts; + struct tm *tm; + int minutesdelta; + struct timezone tz; + + assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); + assert_se(tm = localtime(&ts.tv_sec)); + minutesdelta = tm->tm_gmtoff / 60; + + tz.tz_minuteswest = -minutesdelta; + tz.tz_dsttime = 0; /* DST_NONE*/ + + /* + * If the hardware clock does not run in UTC, but in local time: + * The very first time we set the kernel's timezone, it will warp + * the clock so that it runs in UTC instead of local time. + */ + if (settimeofday(tv_null, &tz) < 0) + return -errno; + if (min) + *min = minutesdelta; + return 0; +} + +int hwclock_reset_timezone(void) { + const struct timeval *tv_null = NULL; + struct timezone tz; + + tz.tz_minuteswest = 0; + tz.tz_dsttime = 0; /* DST_NONE*/ + + /* + * The very first time we set the kernel's timezone, it will warp + * the clock. Do a dummy call here, so the time warping is sealed + * and we set only the timezone with next call. + */ + if (settimeofday(tv_null, &tz) < 0) + return -errno; + + return 0; +} diff --git a/src/shared/hwclock.h b/src/shared/hwclock.h new file mode 100644 index 0000000..4330b8e --- /dev/null +++ b/src/shared/hwclock.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int hwclock_is_localtime(void); +int hwclock_set_timezone(int *min); +int hwclock_reset_timezone(void); +int hwclock_get_time(struct tm *tm); +int hwclock_set_time(const struct tm *tm); diff --git a/src/shared/ima-util.c b/src/shared/ima-util.c new file mode 100644 index 0000000..6c1954b --- /dev/null +++ b/src/shared/ima-util.c @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "ima-util.h" + +static int use_ima_cached = -1; + +bool use_ima(void) { + + if (use_ima_cached < 0) + use_ima_cached = access("/sys/kernel/security/ima/", F_OK) >= 0; + + return use_ima_cached; +} diff --git a/src/shared/ima-util.h b/src/shared/ima-util.h new file mode 100644 index 0000000..d382161 --- /dev/null +++ b/src/shared/ima-util.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +bool use_ima(void); diff --git a/src/shared/initreq.h b/src/shared/initreq.h new file mode 100644 index 0000000..710037d --- /dev/null +++ b/src/shared/initreq.h @@ -0,0 +1,77 @@ +/* + * initreq.h Interface to talk to init through /dev/initctl. + * + * Copyright (C) 1995-2004 Miquel van Smoorenburg + * + * This library 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 of the License, or (at your option) any later version. + * + * Version: @(#)initreq.h 1.28 31-Mar-2004 MvS + * + */ +#ifndef _INITREQ_H +#define _INITREQ_H + +#include + +#if defined(__FreeBSD_kernel__) +# define INIT_FIFO "/etc/.initctl" +#else +# define INIT_FIFO "/dev/initctl" +#endif + +#define INIT_MAGIC 0x03091969 +#define INIT_CMD_START 0 +#define INIT_CMD_RUNLVL 1 +#define INIT_CMD_POWERFAIL 2 +#define INIT_CMD_POWERFAILNOW 3 +#define INIT_CMD_POWEROK 4 +#define INIT_CMD_BSD 5 +#define INIT_CMD_SETENV 6 +#define INIT_CMD_UNSETENV 7 + +#define INIT_CMD_CHANGECONS 12345 + +#ifdef MAXHOSTNAMELEN +# define INITRQ_HLEN MAXHOSTNAMELEN +#else +# define INITRQ_HLEN 64 +#endif + +/* + * This is what BSD 4.4 uses when talking to init. + * Linux doesn't use this right now. + */ +struct init_request_bsd { + char gen_id[8]; /* Beats me.. telnetd uses "fe" */ + char tty_id[16]; /* Tty name minus /dev/tty */ + char host[INITRQ_HLEN]; /* Hostname */ + char term_type[16]; /* Terminal type */ + int signal; /* Signal to send */ + int pid; /* Process to send to */ + char exec_name[128]; /* Program to execute */ + char reserved[128]; /* For future expansion. */ +}; + + +/* + * Because of legacy interfaces, "runlevel" and "sleeptime" + * aren't in a separate struct in the union. + * + * The weird sizes are because init expects the whole + * struct to be 384 bytes. + */ +struct init_request { + int magic; /* Magic number */ + int cmd; /* What kind of request */ + int runlevel; /* Runlevel to change to */ + int sleeptime; /* Time between TERM and KILL */ + union { + struct init_request_bsd bsd; + char data[368]; + } i; +}; + +#endif diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c new file mode 100644 index 0000000..1ee1243 --- /dev/null +++ b/src/shared/install-printf.c @@ -0,0 +1,156 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "specifier.h" +#include "unit-name.h" +#include "util.h" +#include "install-printf.h" + +static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { + InstallInfo *i = userdata; + char *n; + + assert(i); + + n = unit_name_to_prefix_and_instance(i->name); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) { + InstallInfo *i = userdata; + char *n; + + assert(i); + + n = unit_name_to_prefix(i->name); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +static int specifier_instance(char specifier, void *data, void *userdata, char **ret) { + InstallInfo *i = userdata; + char *instance; + int r; + + assert(i); + + r = unit_name_to_instance(i->name, &instance); + if (r < 0) + return r; + + if (!instance) { + instance = strdup(""); + if (!instance) + return -ENOMEM; + } + + *ret = instance; + return 0; +} + +static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { + InstallInfo *i = userdata; + const char *username; + _cleanup_free_ char *tmp = NULL; + char *printed = NULL; + + assert(i); + + if (i->user) + username = i->user; + else + /* get USER env from env or our own uid */ + username = tmp = getusername_malloc(); + + switch (specifier) { + case 'u': + printed = strdup(username); + break; + case 'U': { + /* fish username from passwd */ + uid_t uid; + int r; + + r = get_user_creds(&username, &uid, NULL, NULL, NULL); + if (r < 0) + return r; + + if (asprintf(&printed, "%d", uid) < 0) + return -ENOMEM; + break; + }} + + + *ret = printed; + return 0; +} + + +int install_full_printf(InstallInfo *i, const char *format, char **ret) { + + /* This is similar to unit_full_printf() but does not support + * anything path-related. + * + * %n: the full id of the unit (foo@bar.waldo) + * %N: the id of the unit without the suffix (foo@bar) + * %p: the prefix (foo) + * %i: the instance (bar) + + * %U the UID of the configured user or running user + * %u the username of the configured user or running user + * %m the machine ID of the running system + * %H the host name of the running system + * %b the boot ID of the running system + * %v `uname -r` of the running system + */ + + const Specifier table[] = { + { 'n', specifier_string, i->name }, + { 'N', specifier_prefix_and_instance, NULL }, + { 'p', specifier_prefix, NULL }, + { 'i', specifier_instance, NULL }, + + { 'U', specifier_user_name, NULL }, + { 'u', specifier_user_name, NULL }, + + { 'm', specifier_machine_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'b', specifier_boot_id, NULL }, + { 'v', specifier_kernel_release, NULL }, + {} + }; + + assert(i); + assert(format); + assert(ret); + + return specifier_printf(format, table, i, ret); +} diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h new file mode 100644 index 0000000..6ffa488 --- /dev/null +++ b/src/shared/install-printf.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "install.h" +int install_full_printf(InstallInfo *i, const char *format, char **ret); diff --git a/src/shared/install.c b/src/shared/install.c new file mode 100644 index 0000000..1f9d7e2 --- /dev/null +++ b/src/shared/install.c @@ -0,0 +1,2037 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "hashmap.h" +#include "set.h" +#include "path-util.h" +#include "path-lookup.h" +#include "strv.h" +#include "unit-name.h" +#include "install.h" +#include "conf-parser.h" +#include "conf-files.h" +#include "specifier.h" +#include "install-printf.h" +#include "special.h" + +typedef struct { + Hashmap *will_install; + Hashmap *have_installed; +} InstallContext; + +#define _cleanup_install_context_done_ _cleanup_(install_context_done) + +static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) { + assert(paths); + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + zero(*paths); + + return lookup_paths_init(paths, + scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER, + scope == UNIT_FILE_USER, + NULL, NULL, NULL); +} + +static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { + char *p = NULL; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(ret); + + switch (scope) { + + case UNIT_FILE_SYSTEM: + + if (root_dir && runtime) + asprintf(&p, "%s/run/systemd/system", root_dir); + else if (runtime) + p = strdup("/run/systemd/system"); + else if (root_dir) + asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH); + else + p = strdup(SYSTEM_CONFIG_UNIT_PATH); + + break; + + case UNIT_FILE_GLOBAL: + + if (root_dir) + return -EINVAL; + + if (runtime) + p = strdup("/run/systemd/user"); + else + p = strdup(USER_CONFIG_UNIT_PATH); + break; + + case UNIT_FILE_USER: + + if (root_dir || runtime) + return -EINVAL; + + r = user_config_home(&p); + if (r <= 0) + return r < 0 ? r : -ENOENT; + + break; + + default: + assert_not_reached("Bad scope"); + } + + if (!p) + return -ENOMEM; + + *ret = p; + return 0; +} + +static int add_file_change( + UnitFileChange **changes, + unsigned *n_changes, + UnitFileChangeType type, + const char *path, + const char *source) { + + UnitFileChange *c; + unsigned i; + + assert(path); + assert(!changes == !n_changes); + + if (!changes) + return 0; + + c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); + if (!c) + return -ENOMEM; + + *changes = c; + i = *n_changes; + + c[i].type = type; + c[i].path = strdup(path); + if (!c[i].path) + return -ENOMEM; + + if (source) { + c[i].source = strdup(source); + if (!c[i].source) { + free(c[i].path); + return -ENOMEM; + } + } else + c[i].source = NULL; + + *n_changes = i+1; + return 0; +} + +static int mark_symlink_for_removal( + Set **remove_symlinks_to, + const char *p) { + + char *n; + int r; + + assert(p); + + r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func); + if (r < 0) + return r; + + n = strdup(p); + if (!n) + return -ENOMEM; + + path_kill_slashes(n); + + r = set_consume(*remove_symlinks_to, n); + if (r < 0) + return r == -EEXIST ? 0 : r; + + return 0; +} + +static int remove_marked_symlinks_fd( + Set *remove_symlinks_to, + int fd, + const char *path, + const char *config_path, + bool *deleted, + UnitFileChange **changes, + unsigned *n_changes, + char** files) { + + int r = 0; + _cleanup_closedir_ DIR *d = NULL; + + assert(remove_symlinks_to); + assert(fd >= 0); + assert(path); + assert(config_path); + assert(deleted); + + d = fdopendir(fd); + if (!d) { + close_nointr_nofail(fd); + return -errno; + } + + rewinddir(d); + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + r = -errno; + break; + } + + if (!de) + break; + + if (ignore_file(de->d_name)) + continue; + + dirent_ensure_type(d, de); + + if (de->d_type == DT_DIR) { + int nfd, q; + _cleanup_free_ char *p = NULL; + + nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (nfd < 0) { + if (errno == ENOENT) + continue; + + if (r == 0) + r = -errno; + continue; + } + + p = path_make_absolute(de->d_name, path); + if (!p) { + close_nointr_nofail(nfd); + return -ENOMEM; + } + + /* This will close nfd, regardless whether it succeeds or not */ + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files); + + if (r == 0) + r = q; + + } else if (de->d_type == DT_LNK) { + _cleanup_free_ char *p = NULL, *dest = NULL; + int q; + bool found; + + p = path_make_absolute(de->d_name, path); + if (!p) + return -ENOMEM; + + q = readlink_and_canonicalize(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; + + if (r == 0) + r = q; + continue; + } + + found = + set_get(remove_symlinks_to, dest) || + set_get(remove_symlinks_to, basename(dest)); + + if (unit_name_is_instance(p)) + found = found && strv_contains(files, basename(p)); + + if (found) { + + if (unlink(p) < 0 && errno != ENOENT) { + + if (r == 0) + r = -errno; + } else { + rmdir_parents(p, config_path); + path_kill_slashes(p); + + add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + + if (!set_get(remove_symlinks_to, p)) { + + q = mark_symlink_for_removal(&remove_symlinks_to, p); + if (q < 0) { + if (r == 0) + r = q; + } else + *deleted = true; + } + } + } + } + } + + return r; +} + +static int remove_marked_symlinks( + Set *remove_symlinks_to, + const char *config_path, + UnitFileChange **changes, + unsigned *n_changes, + char** files) { + + int fd, r = 0; + bool deleted; + + assert(config_path); + + if (set_size(remove_symlinks_to) <= 0) + return 0; + + fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) + return -errno; + + do { + int q, cfd; + deleted = false; + + cfd = dup(fd); + if (cfd < 0) { + r = -errno; + break; + } + + /* This takes possession of cfd and closes it */ + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files); + if (r == 0) + r = q; + } while (deleted); + + close_nointr_nofail(fd); + + return r; +} + +static int find_symlinks_fd( + const char *name, + int fd, + const char *path, + const char *config_path, + bool *same_name_link) { + + int r = 0; + _cleanup_closedir_ DIR *d = NULL; + + assert(name); + assert(fd >= 0); + assert(path); + assert(config_path); + assert(same_name_link); + + d = fdopendir(fd); + if (!d) { + close_nointr_nofail(fd); + return -errno; + } + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + return r; + + if (ignore_file(de->d_name)) + continue; + + dirent_ensure_type(d, de); + + if (de->d_type == DT_DIR) { + int nfd, q; + _cleanup_free_ char *p = NULL; + + nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (nfd < 0) { + if (errno == ENOENT) + continue; + + if (r == 0) + r = -errno; + continue; + } + + p = path_make_absolute(de->d_name, path); + if (!p) { + close_nointr_nofail(nfd); + return -ENOMEM; + } + + /* This will close nfd, regardless whether it succeeds or not */ + q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); + + if (q > 0) + return 1; + + if (r == 0) + r = q; + + } else if (de->d_type == DT_LNK) { + _cleanup_free_ char *p = NULL, *dest = NULL; + bool found_path, found_dest, b = false; + int q; + + /* Acquire symlink name */ + p = path_make_absolute(de->d_name, path); + if (!p) + return -ENOMEM; + + /* Acquire symlink destination */ + q = readlink_and_canonicalize(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; + + if (r == 0) + r = q; + continue; + } + + /* Check if the symlink itself matches what we + * are looking for */ + if (path_is_absolute(name)) + found_path = path_equal(p, name); + else + found_path = streq(de->d_name, name); + + /* Check if what the symlink points to + * matches what we are looking for */ + if (path_is_absolute(name)) + found_dest = path_equal(dest, name); + else + found_dest = streq(basename(dest), name); + + if (found_path && found_dest) { + _cleanup_free_ char *t = NULL; + + /* Filter out same name links in the main + * config path */ + t = path_make_absolute(name, config_path); + if (!t) + return -ENOMEM; + + b = path_equal(t, p); + } + + if (b) + *same_name_link = true; + else if (found_path || found_dest) + return 1; + } + } + + return r; +} + +static int find_symlinks( + const char *name, + const char *config_path, + bool *same_name_link) { + + int fd; + + assert(name); + assert(config_path); + assert(same_name_link); + + fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) { + if (errno == ENOENT) + return 0; + return -errno; + } + + /* This takes possession of fd and closes it */ + return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); +} + +static int find_symlinks_in_scope( + UnitFileScope scope, + const char *root_dir, + const char *name, + UnitFileState *state) { + + int r; + _cleanup_free_ char *path2 = NULL; + bool same_name_link_runtime = false, same_name_link = false; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + + if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) { + _cleanup_free_ char *path = NULL; + + /* First look in runtime config path */ + r = get_config_path(scope, true, root_dir, &path); + if (r < 0) + return r; + + r = find_symlinks(name, path, &same_name_link_runtime); + if (r < 0) + return r; + else if (r > 0) { + *state = UNIT_FILE_ENABLED_RUNTIME; + return r; + } + } + + /* Then look in the normal config path */ + r = get_config_path(scope, false, root_dir, &path2); + if (r < 0) + return r; + + r = find_symlinks(name, path2, &same_name_link); + if (r < 0) + return r; + else if (r > 0) { + *state = UNIT_FILE_ENABLED; + return r; + } + + /* Hmm, we didn't find it, but maybe we found the same name + * link? */ + if (same_name_link_runtime) { + *state = UNIT_FILE_LINKED_RUNTIME; + return 1; + } else if (same_name_link) { + *state = UNIT_FILE_LINKED; + return 1; + } + + return 0; +} + +int unit_file_mask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + char **i; + _cleanup_free_ char *prefix; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = get_config_path(scope, runtime, root_dir, &prefix); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + + if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { + if (r == 0) + r = -EINVAL; + continue; + } + + path = path_make_absolute(*i, prefix); + if (!path) { + r = -ENOMEM; + break; + } + + if (symlink("/dev/null", path) >= 0) { + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); + + continue; + } + + if (errno == EEXIST) { + + if (null_or_empty_path(path) > 0) + continue; + + if (force) { + unlink(path); + + if (symlink("/dev/null", path) >= 0) { + + add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); + + continue; + } + } + + if (r == 0) + r = -EEXIST; + } else { + if (r == 0) + r = -errno; + } + } + + return r; +} + +int unit_file_unmask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes) { + + char **i, *config_path = NULL; + int r, q; + Set *remove_symlinks_to = NULL; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + goto finish; + + STRV_FOREACH(i, files) { + char *path; + + if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { + if (r == 0) + r = -EINVAL; + continue; + } + + path = path_make_absolute(*i, config_path); + if (!path) { + r = -ENOMEM; + break; + } + + q = null_or_empty_path(path); + if (q > 0) { + if (unlink(path) >= 0) { + mark_symlink_for_removal(&remove_symlinks_to, path); + add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + + free(path); + continue; + } + + q = -errno; + } + + if (q != -ENOENT && r == 0) + r = q; + + free(path); + } + + +finish: + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); + if (r == 0) + r = q; + + set_free_free(remove_symlinks_to); + free(config_path); + + return r; +} + +int unit_file_link( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + char *fn; + struct stat st; + + fn = basename(*i); + + if (!path_is_absolute(*i) || + !unit_name_is_valid(fn, TEMPLATE_VALID)) { + if (r == 0) + r = -EINVAL; + continue; + } + + if (lstat(*i, &st) < 0) { + if (r == 0) + r = -errno; + continue; + } + + if (!S_ISREG(st.st_mode)) { + r = -ENOENT; + continue; + } + + q = in_search_path(*i, paths.unit_path); + if (q < 0) + return q; + + if (q > 0) + continue; + + path = path_make_absolute(fn, config_path); + if (!path) + return -ENOMEM; + + if (symlink(*i, path) >= 0) { + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); + continue; + } + + if (errno == EEXIST) { + _cleanup_free_ char *dest = NULL; + + q = readlink_and_make_absolute(path, &dest); + + if (q < 0 && errno != ENOENT) { + if (r == 0) + r = q; + continue; + } + + if (q >= 0 && path_equal(dest, *i)) + continue; + + if (force) { + unlink(path); + + if (symlink(*i, path) >= 0) { + + add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); + + continue; + } + } + + if (r == 0) + r = -EEXIST; + } else { + if (r == 0) + r = -errno; + } + } + + return r; +} + +void unit_file_list_free(Hashmap *h) { + UnitFileList *i; + + while ((i = hashmap_steal_first(h))) { + free(i->path); + free(i); + } + + hashmap_free(h); +} + +void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { + unsigned i; + + assert(changes || n_changes == 0); + + if (!changes) + return; + + for (i = 0; i < n_changes; i++) { + free(changes[i].path); + free(changes[i].source); + } + + free(changes); +} + +static void install_info_free(InstallInfo *i) { + assert(i); + + free(i->name); + free(i->path); + strv_free(i->aliases); + strv_free(i->wanted_by); + strv_free(i->required_by); + free(i); +} + +static void install_info_hashmap_free(Hashmap *m) { + InstallInfo *i; + + if (!m) + return; + + while ((i = hashmap_steal_first(m))) + install_info_free(i); + + hashmap_free(m); +} + +static void install_context_done(InstallContext *c) { + assert(c); + + install_info_hashmap_free(c->will_install); + install_info_hashmap_free(c->have_installed); + + c->will_install = c->have_installed = NULL; +} + +static int install_info_add( + InstallContext *c, + const char *name, + const char *path) { + InstallInfo *i = NULL; + int r; + + assert(c); + assert(name || path); + + if (!name) + name = basename(path); + + if (!unit_name_is_valid(name, TEMPLATE_VALID)) + return -EINVAL; + + if (hashmap_get(c->have_installed, name) || + hashmap_get(c->will_install, name)) + return 0; + + r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func); + if (r < 0) + return r; + + i = new0(InstallInfo, 1); + if (!i) + return -ENOMEM; + + i->name = strdup(name); + if (!i->name) { + r = -ENOMEM; + goto fail; + } + + if (path) { + i->path = strdup(path); + if (!i->path) { + r = -ENOMEM; + goto fail; + } + } + + r = hashmap_put(c->will_install, i->name, i); + if (r < 0) + goto fail; + + return 0; + +fail: + if (i) + install_info_free(i); + + return r; +} + +static int install_info_add_auto( + InstallContext *c, + const char *name_or_path) { + + assert(c); + assert(name_or_path); + + if (path_is_absolute(name_or_path)) + return install_info_add(c, NULL, name_or_path); + else + return install_info_add(c, name_or_path, NULL); +} + +static int config_parse_also(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) { + + char *w; + size_t l; + char *state; + InstallContext *c = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + + FOREACH_WORD_QUOTED(w, l, rvalue, state) { + _cleanup_free_ char *n; + int r; + + n = strndup(w, l); + if (!n) + return -ENOMEM; + + r = install_info_add(c, n, NULL); + if (r < 0) + return r; + } + + return 0; +} + +static int config_parse_user(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) { + + InstallInfo *i = data; + char* printed; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = install_full_printf(i, rvalue, &printed); + if (r < 0) + return r; + + free(i->user); + i->user = printed; + + return 0; +} + +static int unit_file_load( + InstallContext *c, + InstallInfo *info, + const char *path, + bool allow_symlink) { + + const ConfigTableItem items[] = { + { "Install", "Alias", config_parse_strv, 0, &info->aliases }, + { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, + { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, + { "Install", "Also", config_parse_also, 0, c }, + { "Exec", "User", config_parse_user, 0, info }, + { NULL, NULL, NULL, 0, NULL } + }; + + int fd; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(c); + assert(info); + assert(path); + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); + if (fd < 0) + return -errno; + + f = fdopen(fd, "re"); + if (!f) { + close_nointr_nofail(fd); + return -ENOMEM; + } + + r = config_parse(NULL, path, f, NULL, + config_item_table_lookup, (void*) items, true, true, info); + if (r < 0) + return r; + + return + (int) strv_length(info->aliases) + + (int) strv_length(info->wanted_by) + + (int) strv_length(info->required_by); +} + +static int unit_file_search( + InstallContext *c, + InstallInfo *info, + LookupPaths *paths, + const char *root_dir, + bool allow_symlink) { + + char **p; + int r; + + assert(c); + assert(info); + assert(paths); + + if (info->path) + return unit_file_load(c, info, info->path, allow_symlink); + + assert(info->name); + + STRV_FOREACH(p, paths->unit_path) { + char *path = NULL; + + if (isempty(root_dir)) + asprintf(&path, "%s/%s", *p, info->name); + else + asprintf(&path, "%s/%s/%s", root_dir, *p, info->name); + + if (!path) + return -ENOMEM; + + r = unit_file_load(c, info, path, allow_symlink); + + if (r >= 0) + info->path = path; + else { + if (r == -ENOENT && unit_name_is_instance(info->name)) { + /* Unit file doesn't exist, however instance enablement was requested. + * We will check if it is possible to load template unit file. */ + char *template = NULL, + *template_path = NULL, + *template_dir = NULL; + + template = unit_name_template(info->name); + if (!template) { + free(path); + return -ENOMEM; + } + + /* We will reuse path variable since we don't need it anymore. */ + template_dir = path; + *(strrchr(path, '/') + 1) = '\0'; + + template_path = strjoin(template_dir, template, NULL); + if (!template_path) { + free(path); + free(template); + return -ENOMEM; + } + + /* Let's try to load template unit. */ + r = unit_file_load(c, info, template_path, allow_symlink); + if (r >= 0) { + info->path = strdup(template_path); + if (!info->path) { + free(path); + free(template); + free(template_path); + return -ENOMEM; + } + } + + free(template); + free(template_path); + } + free(path); + } + + if (r != -ENOENT && r != -ELOOP) + return r; + } + + return -ENOENT; +} + +static int unit_file_can_install( + LookupPaths *paths, + const char *root_dir, + const char *name, + bool allow_symlink) { + + _cleanup_install_context_done_ InstallContext c = {}; + InstallInfo *i; + int r; + + assert(paths); + assert(name); + + r = install_info_add_auto(&c, name); + if (r < 0) + return r; + + assert_se(i = hashmap_first(c.will_install)); + + r = unit_file_search(&c, i, paths, root_dir, allow_symlink); + + if (r >= 0) + r = + (int) strv_length(i->aliases) + + (int) strv_length(i->wanted_by) + + (int) strv_length(i->required_by); + + return r; +} + +static int create_symlink( + const char *old_path, + const char *new_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_free_ char *dest = NULL; + int r; + + assert(old_path); + assert(new_path); + + mkdir_parents_label(new_path, 0755); + + if (symlink(old_path, new_path) >= 0) { + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + return 0; + } + + if (errno != EEXIST) + return -errno; + + r = readlink_and_make_absolute(new_path, &dest); + if (r < 0) + return r; + + if (path_equal(dest, old_path)) + return 0; + + if (!force) + return -EEXIST; + + unlink(new_path); + + if (symlink(old_path, new_path) >= 0) { + add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); + add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + return 0; + } + + return -errno; +} + +static int install_info_symlink_alias( + InstallInfo *i, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + char **s; + int r = 0, q; + + assert(i); + assert(config_path); + + STRV_FOREACH(s, i->aliases) { + _cleanup_free_ char *alias_path = NULL, *dst = NULL; + + q = install_full_printf(i, *s, &dst); + if (q < 0) + return q; + + alias_path = path_make_absolute(dst, config_path); + if (!alias_path) + return -ENOMEM; + + q = create_symlink(i->path, alias_path, force, changes, n_changes); + if (r == 0) + r = q; + } + + return r; +} + +static int install_info_symlink_wants( + InstallInfo *i, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + char **s; + int r = 0, q; + + assert(i); + assert(config_path); + + STRV_FOREACH(s, i->wanted_by) { + _cleanup_free_ char *path = NULL, *dst = NULL; + + q = install_full_printf(i, *s, &dst); + if (q < 0) + return q; + + if (!unit_name_is_valid(dst, TEMPLATE_VALID)) { + r = -EINVAL; + continue; + } + + if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0) + return -ENOMEM; + + q = create_symlink(i->path, path, force, changes, n_changes); + + if (r == 0) + r = q; + } + + return r; +} + +static int install_info_symlink_requires( + InstallInfo *i, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + char **s; + int r = 0, q; + + assert(i); + assert(config_path); + + STRV_FOREACH(s, i->required_by) { + _cleanup_free_ char *path = NULL, *dst = NULL; + + q = install_full_printf(i, *s, &dst); + if (q < 0) + return q; + + if (!unit_name_is_valid(dst, TEMPLATE_VALID)) { + r = -EINVAL; + continue; + } + + if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0) + return -ENOMEM; + + q = create_symlink(i->path, path, force, changes, n_changes); + + if (r == 0) + r = q; + } + + return r; +} + +static int install_info_symlink_link( + InstallInfo *i, + LookupPaths *paths, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + int r; + _cleanup_free_ char *path = NULL; + + assert(i); + assert(paths); + assert(config_path); + assert(i->path); + + r = in_search_path(i->path, paths->unit_path); + if (r != 0) + return r; + + if (asprintf(&path, "%s/%s", config_path, i->name) < 0) + return -ENOMEM; + + r = create_symlink(i->path, path, force, changes, n_changes); + return r; +} + +static int install_info_apply( + InstallInfo *i, + LookupPaths *paths, + const char *config_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + int r, q; + + assert(i); + assert(paths); + assert(config_path); + + r = install_info_symlink_alias(i, config_path, force, changes, n_changes); + + q = install_info_symlink_wants(i, config_path, force, changes, n_changes); + if (r == 0) + r = q; + + q = install_info_symlink_requires(i, config_path, force, changes, n_changes); + if (r == 0) + r = q; + + q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); + if (r == 0) + r = q; + + return r; +} + +static int install_context_apply( + InstallContext *c, + LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + InstallInfo *i; + int r = 0, q; + + assert(c); + assert(paths); + assert(config_path); + + while ((i = hashmap_first(c->will_install))) { + + q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); + if (q < 0) + return q; + + assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); + + q = unit_file_search(c, i, paths, root_dir, false); + if (q < 0) { + if (r >= 0) + r = q; + + return r; + } else if (r >= 0) + r += q; + + q = install_info_apply(i, paths, config_path, force, changes, n_changes); + if (r >= 0 && q < 0) + r = q; + } + + return r; +} + +static int install_context_mark_for_removal( + InstallContext *c, + LookupPaths *paths, + Set **remove_symlinks_to, + const char *config_path, + const char *root_dir) { + + InstallInfo *i; + int r = 0, q; + + assert(c); + assert(paths); + assert(config_path); + + /* Marks all items for removal */ + + while ((i = hashmap_first(c->will_install))) { + + q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); + if (q < 0) + return q; + + assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); + + q = unit_file_search(c, i, paths, root_dir, false); + if (q == -ENOENT) { + /* do nothing */ + } else if (q < 0) { + if (r >= 0) + r = q; + + return r; + } else if (r >= 0) + r += q; + + if (unit_name_is_instance(i->name)) { + char *unit_file; + + if (i->path) { + unit_file = basename(i->path); + + if (unit_name_is_instance(unit_file)) + /* unit file named as instance exists, thus all symlinks + * pointing to it will be removed */ + q = mark_symlink_for_removal(remove_symlinks_to, i->name); + else + /* does not exist, thus we will mark for removal symlinks + * to template unit file */ + q = mark_symlink_for_removal(remove_symlinks_to, unit_file); + } else { + /* If i->path is not set, it means that we didn't actually find + * the unit file. But we can still remove symlinks to the + * nonexistent template. */ + unit_file = unit_name_template(i->name); + if (!unit_file) + return log_oom(); + + q = mark_symlink_for_removal(remove_symlinks_to, unit_file); + free(unit_file); + } + } else + q = mark_symlink_for_removal(remove_symlinks_to, i->name); + + if (r >= 0 && q < 0) + r = q; + } + + return r; +} + +int unit_file_enable( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_install_context_done_ InstallContext c = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + r = install_info_add_auto(&c, *i); + if (r < 0) + return r; + } + + /* This will return the number of symlink rules that were + supposed to be created, not the ones actually created. This is + useful to determine whether the passed files had any + installation data at all. */ + r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); + return r; +} + +int unit_file_disable( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_install_context_done_ InstallContext c = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + r = install_info_add_auto(&c, *i); + if (r < 0) + return r; + } + + r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); + + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); + if (r == 0) + r = q; + + return r; +} + +int unit_file_reenable( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + int r; + + r = unit_file_disable(scope, runtime, root_dir, files, + changes, n_changes); + if (r < 0) + return r; + + return unit_file_enable(scope, runtime, root_dir, files, force, + changes, n_changes); +} + +int unit_file_set_default( + UnitFileScope scope, + const char *root_dir, + const char *file, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_install_context_done_ InstallContext c = {}; + _cleanup_free_ char *config_path = NULL; + char *path; + int r; + InstallInfo *i = NULL; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(file); + + if (unit_name_to_type(file) != UNIT_TARGET) + return -EINVAL; + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + r = get_config_path(scope, false, root_dir, &config_path); + if (r < 0) + return r; + + r = install_info_add_auto(&c, file); + if (r < 0) + return r; + + assert_se(i = hashmap_first(c.will_install)); + + r = unit_file_search(&c, i, &paths, root_dir, false); + if (r < 0) + return r; + + path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET); + + r = create_symlink(i->path, path, force, changes, n_changes); + if (r < 0) + return r; + + return 0; +} + +int unit_file_get_default( + UnitFileScope scope, + const char *root_dir, + char **name) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + char **p; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + STRV_FOREACH(p, paths.unit_path) { + _cleanup_free_ char *path = NULL, *tmp = NULL; + char *n; + + if (isempty(root_dir)) + path = strappend(*p, "/" SPECIAL_DEFAULT_TARGET); + else + path = strjoin(root_dir, "/", *p, "/" SPECIAL_DEFAULT_TARGET, NULL); + + if (!path) + return -ENOMEM; + + r = readlink_malloc(path, &tmp); + if (r == -ENOENT) + continue; + else if (r == -EINVAL) + /* not a symlink */ + n = strdup(SPECIAL_DEFAULT_TARGET); + else if (r < 0) + return r; + else + n = strdup(basename(tmp)); + + if (!n) + return -ENOMEM; + + *name = n; + return 0; + } + + return -ENOENT; +} + +UnitFileState unit_file_get_state( + UnitFileScope scope, + const char *root_dir, + const char *name) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + UnitFileState state = _UNIT_FILE_STATE_INVALID; + char **i; + _cleanup_free_ char *path = NULL; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + + if (root_dir && scope != UNIT_FILE_SYSTEM) + return -EINVAL; + + if (!unit_name_is_valid(name, TEMPLATE_VALID)) + return -EINVAL; + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + STRV_FOREACH(i, paths.unit_path) { + struct stat st; + + free(path); + path = NULL; + + if (root_dir) + asprintf(&path, "%s/%s/%s", root_dir, *i, name); + else + asprintf(&path, "%s/%s", *i, name); + + if (!path) + return -ENOMEM; + + /* + * Search for a unit file in our default paths, to + * be sure, that there are no broken symlinks. + */ + if (lstat(path, &st) < 0) { + r = -errno; + if (errno != ENOENT) + return r; + + if (!unit_name_is_instance(name)) + continue; + } else { + if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) + return -ENOENT; + + r = null_or_empty_path(path); + if (r < 0 && r != -ENOENT) + return r; + else if (r > 0) { + state = path_startswith(*i, "/run") ? + UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; + return state; + } + } + + r = find_symlinks_in_scope(scope, root_dir, name, &state); + if (r < 0) + return r; + else if (r > 0) + return state; + + r = unit_file_can_install(&paths, root_dir, path, true); + if (r < 0 && errno != ENOENT) + return r; + else if (r > 0) + return UNIT_FILE_DISABLED; + else if (r == 0) + return UNIT_FILE_STATIC; + } + + return r < 0 ? r : state; +} + +int unit_file_query_preset(UnitFileScope scope, const char *name) { + _cleanup_strv_free_ char **files = NULL; + char **i; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + + if (scope == UNIT_FILE_SYSTEM) + r = conf_files_list(&files, ".preset", NULL, + "/etc/systemd/system-preset", + "/usr/local/lib/systemd/system-preset", + "/usr/lib/systemd/system-preset", +#ifdef HAVE_SPLIT_USR + "/lib/systemd/system-preset", +#endif + NULL); + else if (scope == UNIT_FILE_GLOBAL) + r = conf_files_list(&files, ".preset", NULL, + "/etc/systemd/user-preset", + "/usr/local/lib/systemd/user-preset", + "/usr/lib/systemd/user-preset", + NULL); + else + return 1; + + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + _cleanup_fclose_ FILE *f; + + f = fopen(*i, "re"); + if (!f) { + if (errno == ENOENT) + continue; + + return -errno; + } + + for (;;) { + char line[LINE_MAX], *l; + + if (!fgets(line, sizeof(line), f)) + break; + + l = strstrip(line); + if (!*l) + continue; + + if (strchr(COMMENTS "\n", *l)) + continue; + + if (first_word(l, "enable")) { + l += 6; + l += strspn(l, WHITESPACE); + + if (fnmatch(l, name, FNM_NOESCAPE) == 0) + return 1; + + } else if (first_word(l, "disable")) { + l += 7; + l += strspn(l, WHITESPACE); + + if (fnmatch(l, name, FNM_NOESCAPE) == 0) + return 0; + + } else + log_debug("Couldn't parse line '%s'", l); + } + } + + /* Default is "enable" */ + return 1; +} + +int unit_file_preset( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_install_context_done_ InstallContext plus = {}, minus = {}; + char **i; + _cleanup_free_ char *config_path = NULL; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + + if (!unit_name_is_valid(*i, TEMPLATE_VALID)) + return -EINVAL; + + r = unit_file_query_preset(scope, *i); + if (r < 0) + return r; + + if (r) + r = install_info_add_auto(&plus, *i); + else + r = install_info_add_auto(&minus, *i); + + if (r < 0) + return r; + } + + r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, + config_path, root_dir); + + q = remove_marked_symlinks(remove_symlinks_to, config_path, + changes, n_changes, files); + if (r == 0) + r = q; + + /* Returns number of symlinks that where supposed to be installed. */ + q = install_context_apply(&plus, &paths, config_path, root_dir, force, + changes, n_changes); + if (r == 0) + r = q; + + return r; +} + +static void unitfilelist_free(UnitFileList **f) { + if (!*f) + return; + + free((*f)->path); + free(*f); +} +#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free) + +int unit_file_get_list( + UnitFileScope scope, + const char *root_dir, + Hashmap *h) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + char **i; + _cleanup_free_ char *buf = NULL; + _cleanup_closedir_ DIR *d = NULL; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(h); + + if (root_dir && scope != UNIT_FILE_SYSTEM) + return -EINVAL; + + r = lookup_paths_init_from_scope(&paths, scope); + if (r < 0) + return r; + + STRV_FOREACH(i, paths.unit_path) { + const char *units_dir; + + free(buf); + buf = NULL; + + if (root_dir) { + if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) + return -ENOMEM; + + units_dir = buf; + } else + units_dir = *i; + + if (d) + closedir(d); + + d = opendir(units_dir); + if (!d) { + if (errno == ENOENT) + continue; + + return -errno; + } + + for (;;) { + struct dirent *de; + _cleanup_unitfilelist_free_ UnitFileList *f = NULL; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + if (ignore_file(de->d_name)) + continue; + + if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) + continue; + + if (hashmap_get(h, de->d_name)) + continue; + + r = dirent_ensure_type(d, de); + if (r < 0) { + if (r == -ENOENT) + continue; + + return r; + } + + if (de->d_type != DT_LNK && de->d_type != DT_REG) + continue; + + f = new0(UnitFileList, 1); + if (!f) + return -ENOMEM; + + f->path = path_make_absolute(de->d_name, units_dir); + if (!f->path) + return -ENOMEM; + + r = null_or_empty_path(f->path); + if (r < 0 && r != -ENOENT) + return r; + else if (r > 0) { + f->state = + path_startswith(*i, "/run") ? + UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; + goto found; + } + + r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); + if (r < 0) + return r; + else if (r > 0) { + f->state = UNIT_FILE_ENABLED; + goto found; + } + + r = unit_file_can_install(&paths, root_dir, f->path, true); + if (r == -EINVAL || /* Invalid setting? */ + r == -EBADMSG || /* Invalid format? */ + r == -ENOENT /* Included file not found? */) + f->state = UNIT_FILE_INVALID; + else if (r < 0) + return r; + else if (r > 0) + f->state = UNIT_FILE_DISABLED; + else + f->state = UNIT_FILE_STATIC; + + found: + r = hashmap_put(h, basename(f->path), f); + if (r < 0) + return r; + f = NULL; /* prevent cleanup */ + } + } + + return r; +} + +static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { + [UNIT_FILE_ENABLED] = "enabled", + [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime", + [UNIT_FILE_LINKED] = "linked", + [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime", + [UNIT_FILE_MASKED] = "masked", + [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime", + [UNIT_FILE_STATIC] = "static", + [UNIT_FILE_DISABLED] = "disabled", + [UNIT_FILE_INVALID] = "invalid", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); + +static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { + [UNIT_FILE_SYMLINK] = "symlink", + [UNIT_FILE_UNLINK] = "unlink", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/shared/install.h b/src/shared/install.h new file mode 100644 index 0000000..5d57b1b --- /dev/null +++ b/src/shared/install.h @@ -0,0 +1,99 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "hashmap.h" + +typedef enum UnitFileScope { + UNIT_FILE_SYSTEM, + UNIT_FILE_GLOBAL, + UNIT_FILE_USER, + _UNIT_FILE_SCOPE_MAX, + _UNIT_FILE_SCOPE_INVALID = -1 +} UnitFileScope; + +typedef enum UnitFileState { + UNIT_FILE_ENABLED, + UNIT_FILE_ENABLED_RUNTIME, + UNIT_FILE_LINKED, + UNIT_FILE_LINKED_RUNTIME, + UNIT_FILE_MASKED, + UNIT_FILE_MASKED_RUNTIME, + UNIT_FILE_STATIC, + UNIT_FILE_DISABLED, + UNIT_FILE_INVALID, + _UNIT_FILE_STATE_MAX, + _UNIT_FILE_STATE_INVALID = -1 +} UnitFileState; + +typedef enum UnitFileChangeType { + UNIT_FILE_SYMLINK, + UNIT_FILE_UNLINK, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 +} UnitFileChangeType; + +typedef struct UnitFileChange { + UnitFileChangeType type; + char *path; + char *source; +} UnitFileChange; + +typedef struct UnitFileList { + char *path; + UnitFileState state; +} UnitFileList; + +typedef struct { + char *name; + char *path; + char *user; + + char **aliases; + char **wanted_by; + char **required_by; +} InstallInfo; + +int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); +int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); +int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); + +UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename); + +int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); + +void unit_file_list_free(Hashmap *h); +void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); + +int unit_file_query_preset(UnitFileScope scope, const char *name); + +const char *unit_file_state_to_string(UnitFileState s) _const_; +UnitFileState unit_file_state_from_string(const char *s) _pure_; + +const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_; +UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_; diff --git a/src/shared/ioprio.h b/src/shared/ioprio.h new file mode 100644 index 0000000..e5c71d0 --- /dev/null +++ b/src/shared/ioprio.h @@ -0,0 +1,55 @@ +#ifndef IOPRIO_H +#define IOPRIO_H + +/* This is minimal version of Linux' linux/ioprio.h header file, which + * is licensed GPL2 */ + +#include +#include + +/* + * Gives us 8 prio classes with 13-bits of data for each class + */ +#define IOPRIO_BITS (16) +#define IOPRIO_CLASS_SHIFT (13) +#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) +#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) +#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) + +#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) + +/* + * These are the io priority groups as implemented by CFQ. RT is the realtime + * class, it always gets premium service. BE is the best-effort scheduling + * class, the default for any process. IDLE is the idle scheduling class, it + * is only served when no one else is using the disk. + */ +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +/* + * 8 best effort priority levels are supported + */ +#define IOPRIO_BE_NR (8) + +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, +}; + +static inline int ioprio_set(int which, int who, int ioprio) { + return syscall(__NR_ioprio_set, which, who, ioprio); +} + +static inline int ioprio_get(int which, int who) { + return syscall(__NR_ioprio_get, which, who); +} + +#endif diff --git a/src/shared/label.c b/src/shared/label.c new file mode 100644 index 0000000..beca48a --- /dev/null +++ b/src/shared/label.c @@ -0,0 +1,478 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_XATTR +#include +#endif +#ifdef HAVE_SELINUX +#include +#include +#endif + +#include "label.h" +#include "strv.h" +#include "util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "smack-util.h" + +#ifdef HAVE_SELINUX +static struct selabel_handle *label_hnd = NULL; +#endif + +static int smack_relabel_in_dev(const char *path) { + int r = 0; + +#ifdef HAVE_SMACK + struct stat sb; + const char *label; + + /* + * Path must be in /dev and must exist + */ + if (!path_startswith(path, "/dev")) + return 0; + + r = lstat(path, &sb); + if (r < 0) + return -errno; + + /* + * Label directories and character devices "*". + * Label symlinks "_". + * Don't change anything else. + */ + if (S_ISDIR(sb.st_mode)) + label = SMACK_STAR_LABEL; + else if (S_ISLNK(sb.st_mode)) + label = SMACK_FLOOR_LABEL; + else if (S_ISCHR(sb.st_mode)) + label = SMACK_STAR_LABEL; + else + return 0; + + r = setxattr(path, "security.SMACK64", label, strlen(label), 0); + if (r < 0) { + log_error("Smack relabeling \"%s\" %s", path, strerror(errno)); + return -errno; + } +#endif + + return r; +} + +int label_init(const char *prefix) { + int r = 0; + +#ifdef HAVE_SELINUX + usec_t before_timestamp, after_timestamp; + struct mallinfo before_mallinfo, after_mallinfo; + + if (!use_selinux()) + return 0; + + if (label_hnd) + return 0; + + before_mallinfo = mallinfo(); + before_timestamp = now(CLOCK_MONOTONIC); + + if (prefix) { + struct selinux_opt options[] = { + { .type = SELABEL_OPT_SUBSET, .value = prefix }, + }; + + label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); + } else + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + + if (!label_hnd) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Failed to initialize SELinux context: %m"); + r = security_getenforce() == 1 ? -errno : 0; + } else { + char timespan[FORMAT_TIMESPAN_MAX]; + int l; + + after_timestamp = now(CLOCK_MONOTONIC); + after_mallinfo = mallinfo(); + + l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; + + log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.", + format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0), + (l+1023)/1024); + } +#endif + + return r; +} + +int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs) { + int r = 0; + +#ifdef HAVE_SELINUX + struct stat st; + security_context_t fcon; + + if (!label_hnd) + return 0; + + r = lstat(path, &st); + if (r == 0) { + r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + + /* If there's no label to set, then exit without warning */ + if (r < 0 && errno == ENOENT) + return 0; + + if (r == 0) { + r = lsetfilecon(path, fcon); + freecon(fcon); + + /* If the FS doesn't support labels, then exit without warning */ + if (r < 0 && errno == ENOTSUP) + return 0; + } + } + + if (r < 0) { + /* Ignore ENOENT in some cases */ + if (ignore_enoent && errno == ENOENT) + return 0; + + if (ignore_erofs && errno == EROFS) + return 0; + + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Unable to fix label of %s: %m", path); + r = security_getenforce() == 1 ? -errno : 0; + } +#endif + + return r; +} + +int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { + int r = 0; + + if (use_selinux()) { + r = label_fix_selinux(path, ignore_enoent, ignore_erofs); + if (r < 0) + return r; + } + + if (use_smack()) { + r = smack_relabel_in_dev(path); + if (r < 0) + return r; + } + + return r; +} + +void label_finish(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + if (label_hnd) + selabel_close(label_hnd); +#endif +} + +int label_get_create_label_from_exe(const char *exe, char **label) { + + int r = 0; + +#ifdef HAVE_SELINUX + security_context_t mycon = NULL, fcon = NULL; + security_class_t sclass; + + if (!use_selinux()) { + *label = NULL; + return 0; + } + + r = getcon(&mycon); + if (r < 0) + goto fail; + + r = getfilecon(exe, &fcon); + if (r < 0) + goto fail; + + sclass = string_to_security_class("process"); + r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + if (r == 0) + log_debug("SELinux Socket context for %s will be set to %s", exe, *label); + +fail: + if (r < 0 && security_getenforce() == 1) + r = -errno; + + freecon(mycon); + freecon(fcon); +#endif + + return r; +} + +int label_context_set(const char *path, mode_t mode) { + int r = 0; + +#ifdef HAVE_SELINUX + security_context_t filecon = NULL; + + if (!use_selinux() || !label_hnd) + return 0; + + r = selabel_lookup_raw(label_hnd, &filecon, path, mode); + if (r < 0 && errno != ENOENT) + r = -errno; + else if (r == 0) { + r = setfscreatecon(filecon); + if (r < 0) { + log_error("Failed to set SELinux file context on %s: %m", path); + r = -errno; + } + + freecon(filecon); + } + + if (r < 0 && security_getenforce() == 0) + r = 0; +#endif + + return r; +} + +int label_socket_set(const char *label) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return 0; + + if (setsockcreatecon((security_context_t) label) < 0) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, + "Failed to set SELinux context (%s) on socket: %m", label); + + if (security_getenforce() == 1) + return -errno; + } +#endif + + return 0; +} + +void label_context_clear(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + setfscreatecon(NULL); +#endif +} + +void label_socket_clear(void) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + setsockcreatecon(NULL); +#endif +} + +void label_free(const char *label) { + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return; + + freecon((security_context_t) label); +#endif +} + +static int label_mkdir_selinux(const char *path, mode_t mode) { + int r = 0; + +#ifdef HAVE_SELINUX + /* Creates a directory and labels it according to the SELinux policy */ + security_context_t fcon = NULL; + + if (!label_hnd) + return 0; + + if (path_is_absolute(path)) + r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); + else { + _cleanup_free_ char *newpath; + + newpath = path_make_absolute_cwd(path); + if (!newpath) + return -ENOMEM; + + r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR); + } + + if (r == 0) + r = setfscreatecon(fcon); + + if (r < 0 && errno != ENOENT) { + log_error("Failed to set security context %s for %s: %m", fcon, path); + + if (security_getenforce() == 1) { + r = -errno; + goto finish; + } + } + + r = mkdir(path, mode); + if (r < 0) + r = -errno; + +finish: + setfscreatecon(NULL); + freecon(fcon); +#endif + + return r; +} + +int label_mkdir(const char *path, mode_t mode) { + int r; + + if (use_selinux()) { + r = label_mkdir_selinux(path, mode); + if (r < 0) + return r; + } + + if (use_smack()) { + r = mkdir(path, mode); + if (r < 0 && errno != EEXIST) + return -errno; + + r = smack_relabel_in_dev(path); + if (r < 0) + return r; + } + + r = mkdir(path, mode); + if (r < 0 && errno != EEXIST) + return -errno; + + return 0; +} + +int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { + + /* Binds a socket and label its file system object according to the SELinux policy */ + +#ifdef HAVE_SELINUX + security_context_t fcon = NULL; + const struct sockaddr_un *un; + char *path; + int r; + + assert(fd >= 0); + assert(addr); + assert(addrlen >= sizeof(sa_family_t)); + + if (!use_selinux() || !label_hnd) + goto skipped; + + /* Filter out non-local sockets */ + if (addr->sa_family != AF_UNIX) + goto skipped; + + /* Filter out anonymous sockets */ + if (addrlen < sizeof(sa_family_t) + 1) + goto skipped; + + /* Filter out abstract namespace sockets */ + un = (const struct sockaddr_un*) addr; + if (un->sun_path[0] == 0) + goto skipped; + + path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path)); + + if (path_is_absolute(path)) + r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); + else { + _cleanup_free_ char *newpath; + + newpath = path_make_absolute_cwd(path); + if (!newpath) + return -ENOMEM; + + r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); + } + + if (r == 0) + r = setfscreatecon(fcon); + + if (r < 0 && errno != ENOENT) { + log_error("Failed to set security context %s for %s: %m", fcon, path); + + if (security_getenforce() == 1) { + r = -errno; + goto finish; + } + } + + r = bind(fd, addr, addrlen); + if (r < 0) + r = -errno; + +finish: + setfscreatecon(NULL); + freecon(fcon); + + return r; + +skipped: +#endif + return bind(fd, addr, addrlen) < 0 ? -errno : 0; +} + +int label_apply(const char *path, const char *label) { + int r = 0; + +#ifdef HAVE_SELINUX + if (!use_selinux()) + return 0; + + r = setfilecon(path, (char *)label); +#endif + return r; +} diff --git a/src/shared/label.h b/src/shared/label.h new file mode 100644 index 0000000..86d4271 --- /dev/null +++ b/src/shared/label.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +int label_init(const char *prefix); +void label_finish(void); + +int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); + +int label_socket_set(const char *label); +void label_socket_clear(void); + +int label_context_set(const char *path, mode_t mode); +void label_context_clear(void); + +void label_free(const char *label); + +int label_get_create_label_from_exe(const char *exe, char **label); + +int label_mkdir(const char *path, mode_t mode); + +void label_retest_selinux(void); + +int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); + +int label_apply(const char *path, const char *label); + +int label_write_one_line_file_atomic(const char *fn, const char *line); +int label_write_env_file(const char *fname, char **l); +int label_fopen_temporary(const char *path, FILE **_f, char **_temp_path); +int label_fix_selinux(const char *path, bool ignore_enoent, bool ignore_erofs); diff --git a/src/shared/linux/Makefile b/src/shared/linux/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/shared/linux/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/shared/linux/auto_dev-ioctl.h b/src/shared/linux/auto_dev-ioctl.h new file mode 100644 index 0000000..aeaeb3e --- /dev/null +++ b/src/shared/linux/auto_dev-ioctl.h @@ -0,0 +1,228 @@ +/* + * Copyright 2008 Red Hat, Inc. All rights reserved. + * Copyright 2008 Ian Kent + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + */ + +#ifndef _LINUX_AUTO_DEV_IOCTL_H +#define _LINUX_AUTO_DEV_IOCTL_H + +#include + +#ifdef __KERNEL__ +#include +#else +#include +#endif /* __KERNEL__ */ + +#define AUTOFS_DEVICE_NAME "autofs" + +#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1 +#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0 + +#define AUTOFS_DEVID_LEN 16 + +#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) + +/* + * An ioctl interface for autofs mount point control. + */ + +struct args_protover { + __u32 version; +}; + +struct args_protosubver { + __u32 sub_version; +}; + +struct args_openmount { + __u32 devid; +}; + +struct args_ready { + __u32 token; +}; + +struct args_fail { + __u32 token; + __s32 status; +}; + +struct args_setpipefd { + __s32 pipefd; +}; + +struct args_timeout { + __u64 timeout; +}; + +struct args_requester { + __u32 uid; + __u32 gid; +}; + +struct args_expire { + __u32 how; +}; + +struct args_askumount { + __u32 may_umount; +}; + +struct args_ismountpoint { + union { + struct args_in { + __u32 type; + } in; + struct args_out { + __u32 devid; + __u32 magic; + } out; + }; +}; + +/* + * All the ioctls use this structure. + * When sending a path size must account for the total length + * of the chunk of memory otherwise is is the size of the + * structure. + */ + +struct autofs_dev_ioctl { + __u32 ver_major; + __u32 ver_minor; + __u32 size; /* total size of data passed in + * including this struct */ + __s32 ioctlfd; /* automount command fd */ + + /* Command parameters */ + + union { + struct args_protover protover; + struct args_protosubver protosubver; + struct args_openmount openmount; + struct args_ready ready; + struct args_fail fail; + struct args_setpipefd setpipefd; + struct args_timeout timeout; + struct args_requester requester; + struct args_expire expire; + struct args_askumount askumount; + struct args_ismountpoint ismountpoint; + }; + + char path[0]; +}; + +static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in) { + memset(in, 0, sizeof(struct autofs_dev_ioctl)); + in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; + in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; + in->size = sizeof(struct autofs_dev_ioctl); + in->ioctlfd = -1; + return; +} + +/* + * If you change this make sure you make the corresponding change + * to autofs-dev-ioctl.c:lookup_ioctl() + */ +enum { + /* Get various version info */ + AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71, + AUTOFS_DEV_IOCTL_PROTOVER_CMD, + AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, + + /* Open mount ioctl fd */ + AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, + + /* Close mount ioctl fd */ + AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, + + /* Mount/expire status returns */ + AUTOFS_DEV_IOCTL_READY_CMD, + AUTOFS_DEV_IOCTL_FAIL_CMD, + + /* Activate/deactivate autofs mount */ + AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, + AUTOFS_DEV_IOCTL_CATATONIC_CMD, + + /* Expiry timeout */ + AUTOFS_DEV_IOCTL_TIMEOUT_CMD, + + /* Get mount last requesting uid and gid */ + AUTOFS_DEV_IOCTL_REQUESTER_CMD, + + /* Check for eligible expire candidates */ + AUTOFS_DEV_IOCTL_EXPIRE_CMD, + + /* Request busy status */ + AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, + + /* Check if path is a mountpoint */ + AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, +}; + +#define AUTOFS_IOCTL 0x93 + +#define AUTOFS_DEV_IOCTL_VERSION \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_PROTOVER \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_PROTOSUBVER \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_OPENMOUNT \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_READY \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_FAIL \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_SETPIPEFD \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_CATATONIC \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_TIMEOUT \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_REQUESTER \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_EXPIRE \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_ASKUMOUNT \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl) + +#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \ + _IOWR(AUTOFS_IOCTL, \ + AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl) + +#endif /* _LINUX_AUTO_DEV_IOCTL_H */ diff --git a/src/linux/fanotify.h b/src/shared/linux/fanotify.h similarity index 100% rename from src/linux/fanotify.h rename to src/shared/linux/fanotify.h diff --git a/src/shared/list.h b/src/shared/list.h new file mode 100644 index 0000000..e55b91c --- /dev/null +++ b/src/shared/list.h @@ -0,0 +1,132 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* The head of the linked list. Use this in the structure that shall + * contain the head of the linked list */ +#define LIST_HEAD(t,name) \ + t *name + +/* The pointers in the linked list's items. Use this in the item structure */ +#define LIST_FIELDS(t,name) \ + t *name##_next, *name##_prev + +/* Initialize the list's head */ +#define LIST_HEAD_INIT(head) \ + do { \ + (head) = NULL; } \ + while(false) + +/* Initialize a list item */ +#define LIST_INIT(name,item) \ + do { \ + typeof(*(item)) *_item = (item); \ + assert(_item); \ + _item->name##_prev = _item->name##_next = NULL; \ + } while(false) + +/* Prepend an item to the list */ +#define LIST_PREPEND(name,head,item) \ + do { \ + typeof(*(head)) **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->name##_next = *_head)) \ + _item->name##_next->name##_prev = _item; \ + _item->name##_prev = NULL; \ + *_head = _item; \ + } while(false) + +/* Remove an item from the list */ +#define LIST_REMOVE(name,head,item) \ + do { \ + typeof(*(head)) **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->name##_next) \ + _item->name##_next->name##_prev = _item->name##_prev; \ + if (_item->name##_prev) \ + _item->name##_prev->name##_next = _item->name##_next; \ + else { \ + assert(*_head == _item); \ + *_head = _item->name##_next; \ + } \ + _item->name##_next = _item->name##_prev = NULL; \ + } while(false) + +/* Find the head of the list */ +#define LIST_FIND_HEAD(name,item,head) \ + do { \ + typeof(*(item)) *_item = (item); \ + assert(_item); \ + while (_item->name##_prev) \ + _item = _item->name##_prev; \ + (head) = _item; \ + } while (false) + +/* Find the tail of the list */ +#define LIST_FIND_TAIL(name,item,tail) \ + do { \ + typeof(*(item)) *_item = (item); \ + assert(_item); \ + while (_item->name##_next) \ + _item = _item->name##_next; \ + (tail) = _item; \ + } while (false) + +/* Insert an item after another one (a = where, b = what) */ +#define LIST_INSERT_AFTER(name,head,a,b) \ + do { \ + typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ + assert(_b); \ + if (!_a) { \ + if ((_b->name##_next = *_head)) \ + _b->name##_next->name##_prev = _b; \ + _b->name##_prev = NULL; \ + *_head = _b; \ + } else { \ + if ((_b->name##_next = _a->name##_next)) \ + _b->name##_next->name##_prev = _b; \ + _b->name##_prev = _a; \ + _a->name##_next = _b; \ + } \ + } while(false) + +#define LIST_JUST_US(name,item) \ + (!(item)->name##_prev && !(item)->name##_next) \ + +#define LIST_FOREACH(name,i,head) \ + for ((i) = (head); (i); (i) = (i)->name##_next) + +#define LIST_FOREACH_SAFE(name,i,n,head) \ + for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) + +#define LIST_FOREACH_BEFORE(name,i,p) \ + for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) + +#define LIST_FOREACH_AFTER(name,i,p) \ + for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) + +/* Loop starting from p->next until p->prev. + p can be adjusted meanwhile. */ +#define LIST_LOOP_BUT_ONE(name,i,head,p) \ + for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ + (i) != (p); \ + (i) = (i)->name##_next ? (i)->name##_next : (head)) diff --git a/src/shared/log.c b/src/shared/log.c new file mode 100644 index 0000000..8d1067c --- /dev/null +++ b/src/shared/log.c @@ -0,0 +1,999 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "missing.h" +#include "macro.h" +#include "socket-util.h" + +#define SNDBUF_SIZE (8*1024*1024) + +static LogTarget log_target = LOG_TARGET_CONSOLE; +static int log_max_level = LOG_INFO; +static int log_facility = LOG_DAEMON; + +static int console_fd = STDERR_FILENO; +static int syslog_fd = -1; +static int kmsg_fd = -1; +static int journal_fd = -1; + +static bool syslog_is_stream = false; + +static bool show_color = false; +static bool show_location = false; + +/* Akin to glibc's __abort_msg; which is private and we hence cannot + * use here. */ +static char *log_abort_msg = NULL; + +void log_close_console(void) { + + if (console_fd < 0) + return; + + if (getpid() == 1) { + if (console_fd >= 3) + close_nointr_nofail(console_fd); + + console_fd = -1; + } +} + +static int log_open_console(void) { + + if (console_fd >= 0) + return 0; + + if (getpid() == 1) { + console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (console_fd < 0) + return console_fd; + } else + console_fd = STDERR_FILENO; + + return 0; +} + +void log_close_kmsg(void) { + + if (kmsg_fd < 0) + return; + + close_nointr_nofail(kmsg_fd); + kmsg_fd = -1; +} + +static int log_open_kmsg(void) { + + if (kmsg_fd >= 0) + return 0; + + kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (kmsg_fd < 0) + return -errno; + + return 0; +} + +void log_close_syslog(void) { + + if (syslog_fd < 0) + return; + + close_nointr_nofail(syslog_fd); + syslog_fd = -1; +} + +static int create_log_socket(int type) { + int fd; + struct timeval tv; + + fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + fd_inc_sndbuf(fd, SNDBUF_SIZE); + + /* We need a blocking fd here since we'd otherwise lose + messages way too early. However, let's not hang forever in the + unlikely case of a deadlock. */ + if (getpid() == 1) + timeval_store(&tv, 10 * USEC_PER_MSEC); + else + timeval_store(&tv, 10 * USEC_PER_SEC); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + + return fd; +} + +static int log_open_syslog(void) { + int r; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/dev/log", + }; + + if (syslog_fd >= 0) + return 0; + + syslog_fd = create_log_socket(SOCK_DGRAM); + if (syslog_fd < 0) { + r = syslog_fd; + goto fail; + } + + if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + close_nointr_nofail(syslog_fd); + + /* Some legacy syslog systems still use stream + * sockets. They really shouldn't. But what can we + * do... */ + syslog_fd = create_log_socket(SOCK_STREAM); + if (syslog_fd < 0) { + r = syslog_fd; + goto fail; + } + + if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + r = -errno; + goto fail; + } + + syslog_is_stream = true; + } else + syslog_is_stream = false; + + return 0; + +fail: + log_close_syslog(); + return r; +} + +void log_close_journal(void) { + + if (journal_fd < 0) + return; + + close_nointr_nofail(journal_fd); + journal_fd = -1; +} + +static int log_open_journal(void) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/socket", + }; + int r; + + if (journal_fd >= 0) + return 0; + + journal_fd = create_log_socket(SOCK_DGRAM); + if (journal_fd < 0) { + r = journal_fd; + goto fail; + } + + if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + log_close_journal(); + return r; +} + +int log_open(void) { + int r; + + /* If we don't use the console we close it here, to not get + * killed by SAK. If we don't use syslog we close it here so + * that we are not confused by somebody deleting the socket in + * the fs. If we don't use /dev/kmsg we still keep it open, + * because there is no reason to close it. */ + + if (log_target == LOG_TARGET_NULL) { + log_close_journal(); + log_close_syslog(); + log_close_console(); + return 0; + } + + if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || + getpid() == 1 || + isatty(STDERR_FILENO) <= 0) { + + if (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_JOURNAL) { + r = log_open_journal(); + if (r >= 0) { + log_close_syslog(); + log_close_console(); + return r; + } + } + + if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_SYSLOG) { + r = log_open_syslog(); + if (r >= 0) { + log_close_journal(); + log_close_console(); + return r; + } + } + + if (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_SAFE || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_KMSG) { + r = log_open_kmsg(); + if (r >= 0) { + log_close_journal(); + log_close_syslog(); + log_close_console(); + return r; + } + } + } + + log_close_journal(); + log_close_syslog(); + + return log_open_console(); +} + +void log_set_target(LogTarget target) { + assert(target >= 0); + assert(target < _LOG_TARGET_MAX); + + log_target = target; +} + +void log_close(void) { + log_close_journal(); + log_close_syslog(); + log_close_kmsg(); + log_close_console(); +} + +void log_forget_fds(void) { + console_fd = kmsg_fd = syslog_fd = journal_fd = -1; +} + +void log_set_max_level(int level) { + assert((level & LOG_PRIMASK) == level); + + log_max_level = level; +} + +void log_set_facility(int facility) { + log_facility = facility; +} + +static int write_to_console( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char location[64]; + struct iovec iovec[5] = {}; + unsigned n = 0; + bool highlight; + + if (console_fd < 0) + return 0; + + highlight = LOG_PRI(level) <= LOG_ERR && show_color; + + if (show_location) { + snprintf(location, sizeof(location), "(%s:%u) ", file, line); + char_array_0(location); + IOVEC_SET_STRING(iovec[n++], location); + } + + if (highlight) + IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); + IOVEC_SET_STRING(iovec[n++], buffer); + if (highlight) + IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); + IOVEC_SET_STRING(iovec[n++], "\n"); + + if (writev(console_fd, iovec, n) < 0) { + + if (errno == EIO && getpid() == 1) { + + /* If somebody tried to kick us from our + * console tty (via vhangup() or suchlike), + * try to reconnect */ + + log_close_console(); + log_open_console(); + + if (console_fd < 0) + return 0; + + if (writev(console_fd, iovec, n) < 0) + return -errno; + } else + return -errno; + } + + return 1; +} + +static int write_to_syslog( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char header_priority[16], header_time[64], header_pid[16]; + struct iovec iovec[5] = {}; + struct msghdr msghdr = { + .msg_iov = iovec, + .msg_iovlen = ELEMENTSOF(iovec), + }; + time_t t; + struct tm *tm; + + if (syslog_fd < 0) + return 0; + + snprintf(header_priority, sizeof(header_priority), "<%i>", level); + char_array_0(header_priority); + + t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); + tm = localtime(&t); + if (!tm) + return -EINVAL; + + if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) + return -EINVAL; + + snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); + char_array_0(header_pid); + + IOVEC_SET_STRING(iovec[0], header_priority); + IOVEC_SET_STRING(iovec[1], header_time); + IOVEC_SET_STRING(iovec[2], program_invocation_short_name); + IOVEC_SET_STRING(iovec[3], header_pid); + IOVEC_SET_STRING(iovec[4], buffer); + + /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ + if (syslog_is_stream) + iovec[4].iov_len++; + + for (;;) { + ssize_t n; + + n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL); + if (n < 0) + return -errno; + + if (!syslog_is_stream || + (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) + break; + + IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); + } + + return 1; +} + +static int write_to_kmsg( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char header_priority[16], header_pid[16]; + struct iovec iovec[5] = {}; + + if (kmsg_fd < 0) + return 0; + + snprintf(header_priority, sizeof(header_priority), "<%i>", level); + char_array_0(header_priority); + + snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); + char_array_0(header_pid); + + IOVEC_SET_STRING(iovec[0], header_priority); + IOVEC_SET_STRING(iovec[1], program_invocation_short_name); + IOVEC_SET_STRING(iovec[2], header_pid); + IOVEC_SET_STRING(iovec[3], buffer); + IOVEC_SET_STRING(iovec[4], "\n"); + + if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) + return -errno; + + return 1; +} + +static int log_do_header(char *header, size_t size, + int level, + const char *file, int line, const char *func, + const char *object_name, const char *object) { + snprintf(header, size, + "PRIORITY=%i\n" + "SYSLOG_FACILITY=%i\n" + "%s%.*s%s" + "%s%.*i%s" + "%s%.*s%s" + "%s%.*s%s" + "SYSLOG_IDENTIFIER=%s\n", + LOG_PRI(level), + LOG_FAC(level), + file ? "CODE_FILE=" : "", + file ? LINE_MAX : 0, file, /* %.0s means no output */ + file ? "\n" : "", + line ? "CODE_LINE=" : "", + line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */ + line ? "\n" : "", + func ? "CODE_FUNCTION=" : "", + func ? LINE_MAX : 0, func, + func ? "\n" : "", + object ? object_name : "", + object ? LINE_MAX : 0, object, /* %.0s means no output */ + object ? "\n" : "", + program_invocation_short_name); + header[size - 1] = '\0'; + return 0; +} + +static int write_to_journal( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *buffer) { + + char header[LINE_MAX]; + struct iovec iovec[4] = {}; + struct msghdr mh = {}; + + if (journal_fd < 0) + return 0; + + log_do_header(header, sizeof(header), level, + file, line, func, object_name, object); + + IOVEC_SET_STRING(iovec[0], header); + IOVEC_SET_STRING(iovec[1], "MESSAGE="); + IOVEC_SET_STRING(iovec[2], buffer); + IOVEC_SET_STRING(iovec[3], "\n"); + + mh.msg_iov = iovec; + mh.msg_iovlen = ELEMENTSOF(iovec); + + if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0) + return -errno; + + return 1; +} + +static int log_dispatch( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + char *buffer) { + + int r = 0; + + if (log_target == LOG_TARGET_NULL) + return 0; + + /* Patch in LOG_DAEMON facility if necessary */ + if ((level & LOG_FACMASK) == 0) + level = log_facility | LOG_PRI(level); + + do { + char *e; + int k = 0; + + buffer += strspn(buffer, NEWLINE); + + if (buffer[0] == 0) + break; + + if ((e = strpbrk(buffer, NEWLINE))) + *(e++) = 0; + + if (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_JOURNAL) { + + k = write_to_journal(level, file, line, func, + object_name, object, buffer); + if (k < 0) { + if (k != -EAGAIN) + log_close_journal(); + log_open_kmsg(); + } else if (k > 0) + r++; + } + + if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_SYSLOG) { + + k = write_to_syslog(level, file, line, func, + object_name, object, buffer); + if (k < 0) { + if (k != -EAGAIN) + log_close_syslog(); + log_open_kmsg(); + } else if (k > 0) + r++; + } + + if (k <= 0 && + (log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_SAFE || + log_target == LOG_TARGET_SYSLOG_OR_KMSG || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_KMSG)) { + + k = write_to_kmsg(level, file, line, func, + object_name, object, buffer); + if (k < 0) { + log_close_kmsg(); + log_open_console(); + } else if (k > 0) + r++; + } + + if (k <= 0) { + k = write_to_console(level, file, line, func, + object_name, object, buffer); + if (k < 0) + return k; + } + + buffer = e; + } while (buffer); + + return r; +} + +int log_dump_internal( + int level, + const char*file, + int line, + const char *func, + char *buffer) { + + PROTECT_ERRNO; + + /* This modifies the buffer... */ + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + return log_dispatch(level, file, line, func, NULL, NULL, buffer); +} + +int log_metav( + int level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) { + + PROTECT_ERRNO; + char buffer[LINE_MAX]; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + vsnprintf(buffer, sizeof(buffer), format, ap); + char_array_0(buffer); + + return log_dispatch(level, file, line, func, NULL, NULL, buffer); +} + +int log_meta( + int level, + const char*file, + int line, + const char *func, + const char *format, ...) { + + int r; + va_list ap; + + va_start(ap, format); + r = log_metav(level, file, line, func, format, ap); + va_end(ap); + + return r; +} + +int log_metav_object( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *format, + va_list ap) { + + PROTECT_ERRNO; + char buffer[LINE_MAX]; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + vsnprintf(buffer, sizeof(buffer), format, ap); + char_array_0(buffer); + + return log_dispatch(level, file, line, func, + object_name, object, buffer); +} + +int log_meta_object( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *format, ...) { + + int r; + va_list ap; + + va_start(ap, format); + r = log_metav_object(level, file, line, func, + object_name, object, format, ap); + va_end(ap); + + return r; +} + +static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) { + static char buffer[LINE_MAX]; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return; + + DISABLE_WARNING_FORMAT_NONLITERAL; + snprintf(buffer, sizeof(buffer), format, text, file, line, func); + REENABLE_WARNING; + + char_array_0(buffer); + log_abort_msg = buffer; + + log_dispatch(level, file, line, func, NULL, NULL, buffer); +} + +noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); + abort(); +} + +noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { + log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); + abort(); +} + +void log_assert_failed_return(const char *text, const char *file, int line, const char *func) { + PROTECT_ERRNO; + log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring."); +} + +int log_oom_internal(const char *file, int line, const char *func) { + log_meta(LOG_ERR, file, line, func, "Out of memory."); + return -ENOMEM; +} + +int log_struct_internal( + int level, + const char *file, + int line, + const char *func, + const char *format, ...) { + + PROTECT_ERRNO; + va_list ap; + int r; + + if (_likely_(LOG_PRI(level) > log_max_level)) + return 0; + + if (log_target == LOG_TARGET_NULL) + return 0; + + if ((level & LOG_FACMASK) == 0) + level = log_facility | LOG_PRI(level); + + if ((log_target == LOG_TARGET_AUTO || + log_target == LOG_TARGET_JOURNAL_OR_KMSG || + log_target == LOG_TARGET_JOURNAL) && + journal_fd >= 0) { + + char header[LINE_MAX]; + struct iovec iovec[17] = {}; + unsigned n = 0, i; + struct msghdr mh = { + .msg_iov = iovec, + }; + static const char nl = '\n'; + + /* If the journal is available do structured logging */ + log_do_header(header, sizeof(header), level, + file, line, func, NULL, NULL); + IOVEC_SET_STRING(iovec[n++], header); + + va_start(ap, format); + while (format && n + 1 < ELEMENTSOF(iovec)) { + char *buf; + va_list aq; + + /* We need to copy the va_list structure, + * since vasprintf() leaves it afterwards at + * an undefined location */ + + va_copy(aq, ap); + if (vasprintf(&buf, format, aq) < 0) { + va_end(aq); + r = -ENOMEM; + goto finish; + } + va_end(aq); + + /* Now, jump enough ahead, so that we point to + * the next format string */ + VA_FORMAT_ADVANCE(format, ap); + + IOVEC_SET_STRING(iovec[n++], buf); + + iovec[n].iov_base = (char*) &nl; + iovec[n].iov_len = 1; + n++; + + format = va_arg(ap, char *); + } + + mh.msg_iovlen = n; + + if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0) + r = -errno; + else + r = 1; + + finish: + va_end(ap); + for (i = 1; i < n; i += 2) + free(iovec[i].iov_base); + + } else { + char buf[LINE_MAX]; + bool found = false; + + /* Fallback if journal logging is not available */ + + va_start(ap, format); + while (format) { + va_list aq; + + va_copy(aq, ap); + vsnprintf(buf, sizeof(buf), format, aq); + va_end(aq); + char_array_0(buf); + + if (startswith(buf, "MESSAGE=")) { + found = true; + break; + } + + VA_FORMAT_ADVANCE(format, ap); + + format = va_arg(ap, char *); + } + va_end(ap); + + if (found) + r = log_dispatch(level, file, line, func, + NULL, NULL, buf + 8); + else + r = -EINVAL; + } + + return r; +} + +int log_set_target_from_string(const char *e) { + LogTarget t; + + t = log_target_from_string(e); + if (t < 0) + return -EINVAL; + + log_set_target(t); + return 0; +} + +int log_set_max_level_from_string(const char *e) { + int t; + + t = log_level_from_string(e); + if (t < 0) + return t; + + log_set_max_level(t); + return 0; +} + +void log_parse_environment(void) { + _cleanup_free_ char *line = NULL; + const char *e; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r)); + else if (r > 0) { + char *w, *state; + size_t l; + + FOREACH_WORD_QUOTED(w, l, line, state) { + if (l == 5 && startswith(w, "debug")) { + log_set_max_level(LOG_DEBUG); + break; + } + } + } + + e = secure_getenv("SYSTEMD_LOG_TARGET"); + if (e && log_set_target_from_string(e) < 0) + log_warning("Failed to parse log target %s. Ignoring.", e); + + e = secure_getenv("SYSTEMD_LOG_LEVEL"); + if (e && log_set_max_level_from_string(e) < 0) + log_warning("Failed to parse log level %s. Ignoring.", e); + + e = secure_getenv("SYSTEMD_LOG_COLOR"); + if (e && log_show_color_from_string(e) < 0) + log_warning("Failed to parse bool %s. Ignoring.", e); + + e = secure_getenv("SYSTEMD_LOG_LOCATION"); + if (e && log_show_location_from_string(e) < 0) + log_warning("Failed to parse bool %s. Ignoring.", e); +} + +LogTarget log_get_target(void) { + return log_target; +} + +int log_get_max_level(void) { + return log_max_level; +} + +void log_show_color(bool b) { + show_color = b; +} + +bool log_get_show_color(void) { + return show_color; +} + +void log_show_location(bool b) { + show_location = b; +} + +bool log_get_show_location(void) { + return show_location; +} + +int log_show_color_from_string(const char *e) { + int t; + + t = parse_boolean(e); + if (t < 0) + return t; + + log_show_color(t); + return 0; +} + +int log_show_location_from_string(const char *e) { + int t; + + t = parse_boolean(e); + if (t < 0) + return t; + + log_show_location(t); + return 0; +} + +bool log_on_console(void) { + if (log_target == LOG_TARGET_CONSOLE) + return true; + + return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0; +} + +static const char *const log_target_table[] = { + [LOG_TARGET_CONSOLE] = "console", + [LOG_TARGET_KMSG] = "kmsg", + [LOG_TARGET_JOURNAL] = "journal", + [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg", + [LOG_TARGET_SYSLOG] = "syslog", + [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", + [LOG_TARGET_AUTO] = "auto", + [LOG_TARGET_SAFE] = "safe", + [LOG_TARGET_NULL] = "null" +}; + +DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); + +void log_received_signal(int level, const struct signalfd_siginfo *si) { + if (si->ssi_pid > 0) { + _cleanup_free_ char *p = NULL; + + get_process_comm(si->ssi_pid, &p); + + log_full(level, + "Received SIG%s from PID "PID_FMT" (%s).", + signal_to_string(si->ssi_signo), + si->ssi_pid, strna(p)); + } else + log_full(level, + "Received SIG%s.", + signal_to_string(si->ssi_signo)); + +} diff --git a/src/shared/log.h b/src/shared/log.h new file mode 100644 index 0000000..794af7b --- /dev/null +++ b/src/shared/log.h @@ -0,0 +1,174 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "macro.h" +#include "sd-id128.h" + +typedef enum LogTarget{ + LOG_TARGET_CONSOLE, + LOG_TARGET_KMSG, + LOG_TARGET_JOURNAL, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_SYSLOG, + LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ + LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ + LOG_TARGET_NULL, + _LOG_TARGET_MAX, + _LOG_TARGET_INVALID = -1 +} LogTarget; + +void log_set_target(LogTarget target); +void log_set_max_level(int level); +void log_set_facility(int facility); + +int log_set_target_from_string(const char *e); +int log_set_max_level_from_string(const char *e); + +void log_show_color(bool b); +bool log_get_show_color(void) _pure_; +void log_show_location(bool b); +bool log_get_show_location(void) _pure_; + +int log_show_color_from_string(const char *e); +int log_show_location_from_string(const char *e); + +LogTarget log_get_target(void) _pure_; +int log_get_max_level(void) _pure_; + +int log_open(void); +void log_close(void); +void log_forget_fds(void); + +void log_close_syslog(void); +void log_close_journal(void); +void log_close_kmsg(void); +void log_close_console(void); + +void log_parse_environment(void); + +int log_meta( + int level, + const char*file, + int line, + const char *func, + const char *format, ...) _printf_(5,6); + +int log_metav( + int level, + const char*file, + int line, + const char *func, + const char *format, + va_list ap) _printf_(5,0); + +int log_meta_object( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *format, ...) _printf_(7,8); + +int log_metav_object( + int level, + const char*file, + int line, + const char *func, + const char *object_name, + const char *object, + const char *format, + va_list ap) _printf_(7,0); + +int log_struct_internal( + int level, + const char *file, + int line, + const char *func, + const char *format, ...) _printf_(5,0) _sentinel_; + +int log_oom_internal( + const char *file, + int line, + const char *func); + +/* This modifies the buffer passed! */ +int log_dump_internal( + int level, + const char*file, + int line, + const char *func, + char *buffer); + +noreturn void log_assert_failed( + const char *text, + const char *file, + int line, + const char *func); + +noreturn void log_assert_failed_unreachable( + const char *text, + const char *file, + int line, + const char *func); + +void log_assert_failed_return( + const char *text, + const char *file, + int line, + const char *func); + +#define log_full(level, ...) \ +do { \ + if (log_get_max_level() >= (level)) \ + log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__); \ +} while (0) + +#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) +#define log_info(...) log_full(LOG_INFO, __VA_ARGS__) +#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) +#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) +#define log_error(...) log_full(LOG_ERR, __VA_ARGS__) + +#define log_struct(level, ...) log_struct_internal(level, __FILE__, __LINE__, __func__, __VA_ARGS__) + +#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__) + +/* This modifies the buffer passed! */ +#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer) + +bool log_on_console(void) _pure_; + +const char *log_target_to_string(LogTarget target) _const_; +LogTarget log_target_from_string(const char *s) _pure_; + +#define MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) + +void log_received_signal(int level, const struct signalfd_siginfo *si); diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c new file mode 100644 index 0000000..61c3652 --- /dev/null +++ b/src/shared/logs-show.c @@ -0,0 +1,1289 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "logs-show.h" +#include "log.h" +#include "util.h" +#include "utf8.h" +#include "hashmap.h" +#include "fileio.h" +#include "journal-internal.h" + +/* up to three lines (each up to 100 characters), + or 300 characters, whichever is less */ +#define PRINT_LINE_THRESHOLD 3 +#define PRINT_CHAR_THRESHOLD 300 + +#define JSON_THRESHOLD 4096 + +static int print_catalog(FILE *f, sd_journal *j) { + int r; + _cleanup_free_ char *t = NULL, *z = NULL; + + + r = sd_journal_get_catalog(j, &t); + if (r < 0) + return r; + + z = strreplace(strstrip(t), "\n", "\n-- "); + if (!z) + return log_oom(); + + fputs("-- ", f); + fputs(z, f); + fputc('\n', f); + + return 0; +} + +static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) { + size_t fl, nl; + void *buf; + + assert(data); + assert(field); + assert(target); + assert(target_size); + + fl = strlen(field); + if (length < fl) + return 0; + + if (memcmp(data, field, fl)) + return 0; + + nl = length - fl; + buf = malloc(nl+1); + if (!buf) + return log_oom(); + + memcpy(buf, (const char*) data + fl, nl); + ((char*)buf)[nl] = 0; + + free(*target); + *target = buf; + *target_size = nl; + + return 1; +} + +static bool shall_print(const char *p, size_t l, OutputFlags flags) { + assert(p); + + if (flags & OUTPUT_SHOW_ALL) + return true; + + if (l >= PRINT_CHAR_THRESHOLD) + return false; + + if (!utf8_is_printable(p, l)) + return false; + + return true; +} + +static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) { + const char *color_on = "", *color_off = ""; + const char *pos, *end; + bool ellipsized = false; + int line = 0; + + if (flags & OUTPUT_COLOR) { + if (priority <= LOG_ERR) { + color_on = ANSI_HIGHLIGHT_RED_ON; + color_off = ANSI_HIGHLIGHT_OFF; + } else if (priority <= LOG_NOTICE) { + color_on = ANSI_HIGHLIGHT_ON; + color_off = ANSI_HIGHLIGHT_OFF; + } + } + + for (pos = message; + pos < message + message_len; + pos = end + 1, line++) { + bool continuation = line > 0; + bool tail_line; + int len; + for (end = pos; end < message + message_len && *end != '\n'; end++) + ; + len = end - pos; + assert(len >= 0); + + /* We need to figure out when we are showing not-last line, *and* + * will skip subsequent lines. In that case, we will put the dots + * at the end of the line, instead of putting dots in the middle + * or not at all. + */ + tail_line = + line + 1 == PRINT_LINE_THRESHOLD || + end + 1 >= message + PRINT_CHAR_THRESHOLD; + + if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) || + (prefix + len + 1 < n_columns && !tail_line)) { + fprintf(f, "%*s%s%.*s%s\n", + continuation * prefix, "", + color_on, len, pos, color_off); + continue; + } + + /* Beyond this point, ellipsization will happen. */ + ellipsized = true; + + if (prefix < n_columns && n_columns - prefix >= 3) { + if (n_columns - prefix > (unsigned) len + 3) + fprintf(f, "%*s%s%.*s...%s\n", + continuation * prefix, "", + color_on, len, pos, color_off); + else { + _cleanup_free_ char *e; + + e = ellipsize_mem(pos, len, n_columns - prefix, + tail_line ? 100 : 90); + if (!e) + fprintf(f, "%*s%s%.*s%s\n", + continuation * prefix, "", + color_on, len, pos, color_off); + else + fprintf(f, "%*s%s%s%s\n", + continuation * prefix, "", + color_on, e, color_off); + } + } else + fputs("...\n", f); + + if (tail_line) + break; + } + + return ellipsized; +} + +static int output_short( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) { + + int r; + const void *data; + size_t length; + size_t n = 0; + _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL; + size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0; + int p = LOG_INFO; + bool ellipsized = false; + + assert(f); + assert(j); + + /* Set the threshold to one bigger than the actual print + * threshold, so that if the line is actually longer than what + * we're willing to print, ellipsization will occur. This way + * we won't output a misleading line without any indication of + * truncation. + */ + sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1); + + JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { + + r = parse_field(data, length, "PRIORITY=", &priority, &priority_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "_COMM=", &comm, &comm_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "_PID=", &pid, &pid_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len); + if (r < 0) + return r; + else if (r > 0) + continue; + + r = parse_field(data, length, "MESSAGE=", &message, &message_len); + if (r < 0) + return r; + } + + if (r < 0) + return r; + + if (!message) + return 0; + + if (!(flags & OUTPUT_SHOW_ALL)) + strip_tab_ansi(&message, &message_len); + + if (priority_len == 1 && *priority >= '0' && *priority <= '7') + p = *priority - '0'; + + if (mode == OUTPUT_SHORT_MONOTONIC) { + uint64_t t; + sd_id128_t boot_id; + + r = -ENOENT; + + if (monotonic) + r = safe_atou64(monotonic, &t); + + if (r < 0) + r = sd_journal_get_monotonic_usec(j, &t, &boot_id); + + if (r < 0) { + log_error("Failed to get monotonic timestamp: %s", strerror(-r)); + return r; + } + + fprintf(f, "[%5llu.%06llu]", + (unsigned long long) (t / USEC_PER_SEC), + (unsigned long long) (t % USEC_PER_SEC)); + + n += 1 + 5 + 1 + 6 + 1; + + } else { + char buf[64]; + uint64_t x; + time_t t; + struct tm tm; + + r = -ENOENT; + + if (realtime) + r = safe_atou64(realtime, &x); + + if (r < 0) + r = sd_journal_get_realtime_usec(j, &x); + + if (r < 0) { + log_error("Failed to get realtime timestamp: %s", strerror(-r)); + return r; + } + + t = (time_t) (x / USEC_PER_SEC); + + switch(mode) { + case OUTPUT_SHORT_ISO: + r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm)); + break; + case OUTPUT_SHORT_PRECISE: + r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); + if (r > 0) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + ".%06llu", x % USEC_PER_SEC); + } + break; + default: + r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); + } + + if (r <= 0) { + log_error("Failed to format time."); + return -EINVAL; + } + + fputs(buf, f); + n += strlen(buf); + } + + if (hostname && shall_print(hostname, hostname_len, flags)) { + fprintf(f, " %.*s", (int) hostname_len, hostname); + n += hostname_len + 1; + } + + if (identifier && shall_print(identifier, identifier_len, flags)) { + fprintf(f, " %.*s", (int) identifier_len, identifier); + n += identifier_len + 1; + } else if (comm && shall_print(comm, comm_len, flags)) { + fprintf(f, " %.*s", (int) comm_len, comm); + n += comm_len + 1; + } else + fputc(' ', f); + + if (pid && shall_print(pid, pid_len, flags)) { + fprintf(f, "[%.*s]", (int) pid_len, pid); + n += pid_len + 2; + } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) { + fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid); + n += fake_pid_len + 2; + } + + if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) { + char bytes[FORMAT_BYTES_MAX]; + fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); + } else { + fputs(": ", f); + ellipsized |= + print_multiline(f, n + 2, n_columns, flags, p, message, message_len); + } + + if (flags & OUTPUT_CATALOG) + print_catalog(f, j); + + return ellipsized; +} + +static int output_verbose( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) { + + const void *data; + size_t length; + _cleanup_free_ char *cursor = NULL; + uint64_t realtime; + char ts[FORMAT_TIMESTAMP_MAX + 7]; + int r; + + assert(f); + assert(j); + + sd_journal_set_data_threshold(j, 0); + + r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length); + if (r == -ENOENT) + log_debug("Source realtime timestamp not found"); + else if (r < 0) { + log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, + "Failed to get source realtime timestamp: %s", strerror(-r)); + return r; + } else { + _cleanup_free_ char *value = NULL; + size_t size; + + r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size); + if (r < 0) + log_debug("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r)); + else { + r = safe_atou64(value, &realtime); + if (r < 0) + log_debug("Failed to parse realtime timestamp: %s", + strerror(-r)); + } + } + + if (r < 0) { + r = sd_journal_get_realtime_usec(j, &realtime); + if (r < 0) { + log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, + "Failed to get realtime timestamp: %s", strerror(-r)); + return r; + } + } + + r = sd_journal_get_cursor(j, &cursor); + if (r < 0) { + log_error("Failed to get cursor: %s", strerror(-r)); + return r; + } + + fprintf(f, "%s [%s]\n", + format_timestamp_us(ts, sizeof(ts), realtime), + cursor); + + JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { + const char *c; + int fieldlen; + const char *on = "", *off = ""; + + c = memchr(data, '=', length); + if (!c) { + log_error("Invalid field."); + return -EINVAL; + } + fieldlen = c - (const char*) data; + + if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) { + on = ANSI_HIGHLIGHT_ON; + off = ANSI_HIGHLIGHT_OFF; + } + + if (flags & OUTPUT_SHOW_ALL || + (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) + && utf8_is_printable(data, length))) { + fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data); + print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1); + fputs(off, f); + } else { + char bytes[FORMAT_BYTES_MAX]; + + fprintf(f, " %s%.*s=[%s blob data]%s\n", + on, + (int) (c - (const char*) data), + (const char*) data, + format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1), + off); + } + } + + if (r < 0) + return r; + + if (flags & OUTPUT_CATALOG) + print_catalog(f, j); + + return 0; +} + +static int output_export( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) { + + sd_id128_t boot_id; + char sid[33]; + int r; + usec_t realtime, monotonic; + _cleanup_free_ char *cursor = NULL; + const void *data; + size_t length; + + assert(j); + + sd_journal_set_data_threshold(j, 0); + + r = sd_journal_get_realtime_usec(j, &realtime); + if (r < 0) { + log_error("Failed to get realtime timestamp: %s", strerror(-r)); + return r; + } + + r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); + if (r < 0) { + log_error("Failed to get monotonic timestamp: %s", strerror(-r)); + return r; + } + + r = sd_journal_get_cursor(j, &cursor); + if (r < 0) { + log_error("Failed to get cursor: %s", strerror(-r)); + return r; + } + + fprintf(f, + "__CURSOR=%s\n" + "__REALTIME_TIMESTAMP=%llu\n" + "__MONOTONIC_TIMESTAMP=%llu\n" + "_BOOT_ID=%s\n", + cursor, + (unsigned long long) realtime, + (unsigned long long) monotonic, + sd_id128_to_string(boot_id, sid)); + + JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { + + /* We already printed the boot id, from the data in + * the header, hence let's suppress it here */ + if (length >= 9 && + startswith(data, "_BOOT_ID=")) + continue; + + if (!utf8_is_printable(data, length)) { + const char *c; + uint64_t le64; + + c = memchr(data, '=', length); + if (!c) { + log_error("Invalid field."); + return -EINVAL; + } + + fwrite(data, c - (const char*) data, 1, f); + fputc('\n', f); + le64 = htole64(length - (c - (const char*) data) - 1); + fwrite(&le64, sizeof(le64), 1, f); + fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f); + } else + fwrite(data, length, 1, f); + + fputc('\n', f); + } + + if (r < 0) + return r; + + fputc('\n', f); + + return 0; +} + +void json_escape( + FILE *f, + const char* p, + size_t l, + OutputFlags flags) { + + assert(f); + assert(p); + + if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD) + + fputs("null", f); + + else if (!utf8_is_printable(p, l)) { + bool not_first = false; + + fputs("[ ", f); + + while (l > 0) { + if (not_first) + fprintf(f, ", %u", (uint8_t) *p); + else { + not_first = true; + fprintf(f, "%u", (uint8_t) *p); + } + + p++; + l--; + } + + fputs(" ]", f); + } else { + fputc('\"', f); + + while (l > 0) { + if (*p == '"' || *p == '\\') { + fputc('\\', f); + fputc(*p, f); + } else if (*p == '\n') + fputs("\\n", f); + else if (*p < ' ') + fprintf(f, "\\u%04x", *p); + else + fputc(*p, f); + + p++; + l--; + } + + fputc('\"', f); + } +} + +static int output_json( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) { + + uint64_t realtime, monotonic; + _cleanup_free_ char *cursor = NULL; + const void *data; + size_t length; + sd_id128_t boot_id; + char sid[33], *k; + int r; + Hashmap *h = NULL; + bool done, separator; + + assert(j); + + sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD); + + r = sd_journal_get_realtime_usec(j, &realtime); + if (r < 0) { + log_error("Failed to get realtime timestamp: %s", strerror(-r)); + return r; + } + + r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); + if (r < 0) { + log_error("Failed to get monotonic timestamp: %s", strerror(-r)); + return r; + } + + r = sd_journal_get_cursor(j, &cursor); + if (r < 0) { + log_error("Failed to get cursor: %s", strerror(-r)); + return r; + } + + if (mode == OUTPUT_JSON_PRETTY) + fprintf(f, + "{\n" + "\t\"__CURSOR\" : \"%s\",\n" + "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n" + "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n" + "\t\"_BOOT_ID\" : \"%s\"", + cursor, + (unsigned long long) realtime, + (unsigned long long) monotonic, + sd_id128_to_string(boot_id, sid)); + else { + if (mode == OUTPUT_JSON_SSE) + fputs("data: ", f); + + fprintf(f, + "{ \"__CURSOR\" : \"%s\", " + "\"__REALTIME_TIMESTAMP\" : \"%llu\", " + "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", " + "\"_BOOT_ID\" : \"%s\"", + cursor, + (unsigned long long) realtime, + (unsigned long long) monotonic, + sd_id128_to_string(boot_id, sid)); + } + + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return -ENOMEM; + + /* First round, iterate through the entry and count how often each field appears */ + JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { + const char *eq; + char *n; + unsigned u; + + if (length >= 9 && + memcmp(data, "_BOOT_ID=", 9) == 0) + continue; + + eq = memchr(data, '=', length); + if (!eq) + continue; + + n = strndup(data, eq - (const char*) data); + if (!n) { + r = -ENOMEM; + goto finish; + } + + u = PTR_TO_UINT(hashmap_get(h, n)); + if (u == 0) { + r = hashmap_put(h, n, UINT_TO_PTR(1)); + if (r < 0) { + free(n); + goto finish; + } + } else { + r = hashmap_update(h, n, UINT_TO_PTR(u + 1)); + free(n); + if (r < 0) + goto finish; + } + } + + if (r < 0) + return r; + + separator = true; + do { + done = true; + + SD_JOURNAL_FOREACH_DATA(j, data, length) { + const char *eq; + char *kk, *n; + size_t m; + unsigned u; + + /* We already printed the boot id, from the data in + * the header, hence let's suppress it here */ + if (length >= 9 && + memcmp(data, "_BOOT_ID=", 9) == 0) + continue; + + eq = memchr(data, '=', length); + if (!eq) + continue; + + if (separator) { + if (mode == OUTPUT_JSON_PRETTY) + fputs(",\n\t", f); + else + fputs(", ", f); + } + + m = eq - (const char*) data; + + n = strndup(data, m); + if (!n) { + r = -ENOMEM; + goto finish; + } + + u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk)); + if (u == 0) { + /* We already printed this, let's jump to the next */ + free(n); + separator = false; + + continue; + } else if (u == 1) { + /* Field only appears once, output it directly */ + + json_escape(f, data, m, flags); + fputs(" : ", f); + + json_escape(f, eq + 1, length - m - 1, flags); + + hashmap_remove(h, n); + free(kk); + free(n); + + separator = true; + + continue; + + } else { + /* Field appears multiple times, output it as array */ + json_escape(f, data, m, flags); + fputs(" : [ ", f); + json_escape(f, eq + 1, length - m - 1, flags); + + /* Iterate through the end of the list */ + + while (sd_journal_enumerate_data(j, &data, &length) > 0) { + if (length < m + 1) + continue; + + if (memcmp(data, n, m) != 0) + continue; + + if (((const char*) data)[m] != '=') + continue; + + fputs(", ", f); + json_escape(f, (const char*) data + m + 1, length - m - 1, flags); + } + + fputs(" ]", f); + + hashmap_remove(h, n); + free(kk); + free(n); + + /* Iterate data fields form the beginning */ + done = false; + separator = true; + + break; + } + } + + } while (!done); + + if (mode == OUTPUT_JSON_PRETTY) + fputs("\n}\n", f); + else if (mode == OUTPUT_JSON_SSE) + fputs("}\n\n", f); + else + fputs(" }\n", f); + + r = 0; + +finish: + while ((k = hashmap_steal_first_key(h))) + free(k); + + hashmap_free(h); + + return r; +} + +static int output_cat( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) { + + const void *data; + size_t l; + int r; + + assert(j); + assert(f); + + sd_journal_set_data_threshold(j, 0); + + r = sd_journal_get_data(j, "MESSAGE", &data, &l); + if (r < 0) { + /* An entry without MESSAGE=? */ + if (r == -ENOENT) + return 0; + + log_error("Failed to get data: %s", strerror(-r)); + return r; + } + + assert(l >= 8); + + fwrite((const char*) data + 8, 1, l - 8, f); + fputc('\n', f); + + return 0; +} + +static int (*output_funcs[_OUTPUT_MODE_MAX])( + FILE *f, + sd_journal*j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags) = { + + [OUTPUT_SHORT] = output_short, + [OUTPUT_SHORT_ISO] = output_short, + [OUTPUT_SHORT_PRECISE] = output_short, + [OUTPUT_SHORT_MONOTONIC] = output_short, + [OUTPUT_VERBOSE] = output_verbose, + [OUTPUT_EXPORT] = output_export, + [OUTPUT_JSON] = output_json, + [OUTPUT_JSON_PRETTY] = output_json, + [OUTPUT_JSON_SSE] = output_json, + [OUTPUT_CAT] = output_cat +}; + +int output_journal( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags, + bool *ellipsized) { + + int ret; + assert(mode >= 0); + assert(mode < _OUTPUT_MODE_MAX); + + if (n_columns <= 0) + n_columns = columns(); + + ret = output_funcs[mode](f, j, mode, n_columns, flags); + fflush(stdout); + + if (ellipsized && ret > 0) + *ellipsized = true; + + return ret; +} + +static int show_journal(FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + usec_t not_before, + unsigned how_many, + OutputFlags flags, + bool *ellipsized) { + + int r; + unsigned line = 0; + bool need_seek = false; + int warn_cutoff = flags & OUTPUT_WARN_CUTOFF; + + assert(j); + assert(mode >= 0); + assert(mode < _OUTPUT_MODE_MAX); + + /* Seek to end */ + r = sd_journal_seek_tail(j); + if (r < 0) + goto finish; + + r = sd_journal_previous_skip(j, how_many); + if (r < 0) + goto finish; + + for (;;) { + for (;;) { + usec_t usec; + + if (need_seek) { + r = sd_journal_next(j); + if (r < 0) + goto finish; + } + + if (r == 0) + break; + + need_seek = true; + + if (not_before > 0) { + r = sd_journal_get_monotonic_usec(j, &usec, NULL); + + /* -ESTALE is returned if the + timestamp is not from this boot */ + if (r == -ESTALE) + continue; + else if (r < 0) + goto finish; + + if (usec < not_before) + continue; + } + + line ++; + + r = output_journal(f, j, mode, n_columns, flags, ellipsized); + if (r < 0) + goto finish; + } + + if (warn_cutoff && line < how_many && not_before > 0) { + sd_id128_t boot_id; + usec_t cutoff; + + /* Check whether the cutoff line is too early */ + + r = sd_id128_get_boot(&boot_id); + if (r < 0) + goto finish; + + r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL); + if (r < 0) + goto finish; + + if (r > 0 && not_before < cutoff) + fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n"); + + warn_cutoff = false; + } + + if (!(flags & OUTPUT_FOLLOW)) + break; + + r = sd_journal_wait(j, (usec_t) -1); + if (r < 0) + goto finish; + + } + +finish: + return r; +} + +int add_matches_for_unit(sd_journal *j, const char *unit) { + int r; + char *m1, *m2, *m3, *m4; + + assert(j); + assert(unit); + + m1 = strappenda("_SYSTEMD_UNIT=", unit); + m2 = strappenda("COREDUMP_UNIT=", unit); + m3 = strappenda("UNIT=", unit); + m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit); + + (void)( + /* Look for messages from the service itself */ + (r = sd_journal_add_match(j, m1, 0)) || + + /* Look for coredumps of the service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) || + (r = sd_journal_add_match(j, "_UID=0", 0)) || + (r = sd_journal_add_match(j, m2, 0)) || + + /* Look for messages from PID 1 about this service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, "_PID=1", 0)) || + (r = sd_journal_add_match(j, m3, 0)) || + + /* Look for messages from authorized daemons about this service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, "_UID=0", 0)) || + (r = sd_journal_add_match(j, m4, 0)) + ); + + if (r == 0 && endswith(unit, ".slice")) { + char *m5 = strappend("_SYSTEMD_SLICE=", unit); + + /* Show all messages belonging to a slice */ + (void)( + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, m5, 0)) + ); + } + + return r; +} + +int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) { + int r; + char *m1, *m2, *m3, *m4; + char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)]; + + assert(j); + assert(unit); + + m1 = strappenda("_SYSTEMD_USER_UNIT=", unit); + m2 = strappenda("USER_UNIT=", unit); + m3 = strappenda("COREDUMP_USER_UNIT=", unit); + m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit); + sprintf(muid, "_UID=%lu", (unsigned long) uid); + + (void) ( + /* Look for messages from the user service itself */ + (r = sd_journal_add_match(j, m1, 0)) || + (r = sd_journal_add_match(j, muid, 0)) || + + /* Look for messages from systemd about this service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, m2, 0)) || + (r = sd_journal_add_match(j, muid, 0)) || + + /* Look for coredumps of the service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, m3, 0)) || + (r = sd_journal_add_match(j, muid, 0)) || + (r = sd_journal_add_match(j, "_UID=0", 0)) || + + /* Look for messages from authorized daemons about this service */ + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, m4, 0)) || + (r = sd_journal_add_match(j, muid, 0)) || + (r = sd_journal_add_match(j, "_UID=0", 0)) + ); + + if (r == 0 && endswith(unit, ".slice")) { + char *m5 = strappend("_SYSTEMD_SLICE=", unit); + + /* Show all messages belonging to a slice */ + (void)( + (r = sd_journal_add_disjunction(j)) || + (r = sd_journal_add_match(j, m5, 0)) || + (r = sd_journal_add_match(j, muid, 0)) + ); + } + + return r; +} + +static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { + _cleanup_close_pipe_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + pid_t pid, child; + siginfo_t si; + char buf[37]; + ssize_t k; + int r; + + assert(machine); + assert(boot_id); + + if (!filename_is_safe(machine)) + return -EINVAL; + + r = container_get_leader(machine, &pid); + if (r < 0) + return r; + + r = namespace_open(pid, &pidnsfd, &mntnsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int fd; + + close_nointr_nofail(pair[0]); + pair[0] = -1; + + r = namespace_enter(pidnsfd, mntnsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + _exit(EXIT_FAILURE); + + k = loop_read(fd, buf, 36, false); + close_nointr_nofail(fd); + if (k != 36) + _exit(EXIT_FAILURE); + + k = send(pair[1], buf, 36, MSG_NOSIGNAL); + if (k != 36) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + close_nointr_nofail(pair[1]); + pair[1] = -1; + + r = wait_for_terminate(child, &si); + if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return r < 0 ? r : -EIO; + + k = recv(pair[0], buf, 36, 0); + if (k != 36) + return -EIO; + + buf[36] = 0; + r = sd_id128_from_string(buf, boot_id); + if (r < 0) + return r; + + return 0; +} + +int add_match_this_boot(sd_journal *j, const char *machine) { + char match[9+32+1] = "_BOOT_ID="; + sd_id128_t boot_id; + int r; + + assert(j); + + if (machine) { + r = get_boot_id_for_machine(machine, &boot_id); + if (r < 0) { + log_error("Failed to get boot id of container %s: %s", machine, strerror(-r)); + return r; + } + } else { + r = sd_id128_get_boot(&boot_id); + if (r < 0) { + log_error("Failed to get boot id: %s", strerror(-r)); + return r; + } + } + + sd_id128_to_string(boot_id, match + 9); + r = sd_journal_add_match(j, match, strlen(match)); + if (r < 0) { + log_error("Failed to add match: %s", strerror(-r)); + return r; + } + + r = sd_journal_add_conjunction(j); + if (r < 0) + return r; + + return 0; +} + +int show_journal_by_unit( + FILE *f, + const char *unit, + OutputMode mode, + unsigned n_columns, + usec_t not_before, + unsigned how_many, + uid_t uid, + OutputFlags flags, + bool system, + bool *ellipsized) { + + _cleanup_journal_close_ sd_journal*j = NULL; + int r; + int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM; + + assert(mode >= 0); + assert(mode < _OUTPUT_MODE_MAX); + assert(unit); + + if (how_many <= 0) + return 0; + + r = sd_journal_open(&j, jflags); + if (r < 0) + return r; + + r = add_match_this_boot(j, NULL); + if (r < 0) + return r; + + if (system) + r = add_matches_for_unit(j, unit); + else + r = add_matches_for_user_unit(j, unit, uid); + if (r < 0) + return r; + + if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + _cleanup_free_ char *filter; + + filter = journal_make_match_string(j); + log_debug("Journal filter: %s", filter); + } + + return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized); +} + +static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { + [OUTPUT_SHORT] = "short", + [OUTPUT_SHORT_ISO] = "short-iso", + [OUTPUT_SHORT_PRECISE] = "short-precise", + [OUTPUT_SHORT_MONOTONIC] = "short-monotonic", + [OUTPUT_VERBOSE] = "verbose", + [OUTPUT_EXPORT] = "export", + [OUTPUT_JSON] = "json", + [OUTPUT_JSON_PRETTY] = "json-pretty", + [OUTPUT_JSON_SSE] = "json-sse", + [OUTPUT_CAT] = "cat" +}; + +DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode); diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h new file mode 100644 index 0000000..3a99160 --- /dev/null +++ b/src/shared/logs-show.h @@ -0,0 +1,71 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include + +#include "util.h" +#include "output-mode.h" + +int output_journal( + FILE *f, + sd_journal *j, + OutputMode mode, + unsigned n_columns, + OutputFlags flags, + bool *ellipsized); + +int add_match_this_boot(sd_journal *j, const char *machine); + +int add_matches_for_unit( + sd_journal *j, + const char *unit); + +int add_matches_for_user_unit( + sd_journal *j, + const char *unit, + uid_t uid); + +int show_journal_by_unit( + FILE *f, + const char *unit, + OutputMode mode, + unsigned n_columns, + usec_t not_before, + unsigned how_many, + uid_t uid, + OutputFlags flags, + bool system, + bool *ellipsized); + +void json_escape( + FILE *f, + const char* p, + size_t l, + OutputFlags flags); + +const char* output_mode_to_string(OutputMode m) _const_; +OutputMode output_mode_from_string(const char *s) _pure_; diff --git a/src/shared/macro.h b/src/shared/macro.h new file mode 100644 index 0000000..5fd67c7 --- /dev/null +++ b/src/shared/macro.h @@ -0,0 +1,364 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#define _printf_(a,b) __attribute__ ((format (printf, a, b))) +#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#define _sentinel_ __attribute__ ((sentinel)) +#define _unused_ __attribute__ ((unused)) +#define _destructor_ __attribute__ ((destructor)) +#define _pure_ __attribute__ ((pure)) +#define _const_ __attribute__ ((const)) +#define _deprecated_ __attribute__ ((deprecated)) +#define _packed_ __attribute__ ((packed)) +#define _malloc_ __attribute__ ((malloc)) +#define _weak_ __attribute__ ((weak)) +#define _likely_(x) (__builtin_expect(!!(x),1)) +#define _unlikely_(x) (__builtin_expect(!!(x),0)) +#define _public_ __attribute__ ((visibility("default"))) +#define _hidden_ __attribute__ ((visibility("hidden"))) +#define _weakref_(x) __attribute__((weakref(#x))) +#define _alignas_(x) __attribute__((aligned(__alignof(x)))) +#define _cleanup_(x) __attribute__((cleanup(x))) + +/* Temporarily disable some warnings */ +#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") + +#define DISABLE_WARNING_FORMAT_NONLITERAL \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") + +#define DISABLE_WARNING_MISSING_PROTOTYPES \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") + +#define DISABLE_WARNING_NONNULL \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wnonnull\"") + +#define REENABLE_WARNING \ + _Pragma("GCC diagnostic pop") + +/* automake test harness */ +#define EXIT_TEST_SKIP 77 + +#define XSTRINGIFY(x) #x +#define STRINGIFY(x) XSTRINGIFY(x) + +#define XCONCATENATE(x, y) x ## y +#define CONCATENATE(x, y) XCONCATENATE(x, y) + +#define UNIQUE(prefix) CONCATENATE(prefix, __LINE__) + +/* Rounds up */ + +#define ALIGN4(l) (((l) + 3) & ~3) +#define ALIGN8(l) (((l) + 7) & ~7) + +#if __SIZEOF_POINTER__ == 8 +#define ALIGN(l) ALIGN8(l) +#elif __SIZEOF_POINTER__ == 4 +#define ALIGN(l) ALIGN4(l) +#else +#error "Wut? Pointers are neither 4 nor 8 bytes long?" +#endif + +#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p)) +#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p)) +#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p)) + +static inline size_t ALIGN_TO(size_t l, size_t ali) { + return ((l + ali - 1) & ~(ali - 1)); +} + +#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p)) + +#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) + +/* + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) \ + __extension__ ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) ); \ + }) + +#undef MAX +#define MAX(a,b) \ + __extension__ ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) + +#define MAX3(x,y,z) \ + __extension__ ({ \ + typeof(x) _c = MAX(x,y); \ + MAX(_c, z); \ + }) + +#undef MIN +#define MIN(a,b) \ + __extension__ ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) + +#define LESS_BY(A,B) \ + __extension__ ({ \ + typeof(A) _A = (A); \ + typeof(B) _B = (B); \ + _A > _B ? _A - _B : 0; \ + }) + +#ifndef CLAMP +#define CLAMP(x, low, high) \ + __extension__ ({ \ + typeof(x) _x = (x); \ + typeof(low) _low = (low); \ + typeof(high) _high = (high); \ + ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ + }) +#endif + +#define assert_se(expr) \ + do { \ + if (_unlikely_(!(expr))) \ + log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) \ + +/* We override the glibc assert() here. */ +#undef assert +#ifdef NDEBUG +#define assert(expr) do {} while(false) +#else +#define assert(expr) assert_se(expr) +#endif + +#define assert_not_reached(t) \ + do { \ + log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +#if defined(static_assert) +/* static_assert() is sometimes defined in a way that trips up + * -Wdeclaration-after-statement, hence let's temporarily turn off + * this warning around it. */ +#define assert_cc(expr) \ + DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ + static_assert(expr, #expr); \ + REENABLE_WARNING +#else +#define assert_cc(expr) \ + DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ + struct UNIQUE(_assert_struct_) { \ + char x[(expr) ? 0 : -1]; \ + }; \ + REENABLE_WARNING +#endif + +#define assert_return(expr, r) \ + do { \ + if (_unlikely_(!(expr))) { \ + log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return (r); \ + } \ + } while (false) + +#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) +#define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) +#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) +#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) +#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) +#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) +#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) +#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define memzero(x,l) (memset((x), 0, (l))) +#define zero(x) (memzero(&(x), sizeof(x))) + +#define CHAR_TO_STR(x) ((char[2]) { x, 0 }) + +#define char_array_0(x) x[sizeof(x)-1] = 0; + +#define IOVEC_SET_STRING(i, s) \ + do { \ + struct iovec *_i = &(i); \ + char *_s = (char *)(s); \ + _i->iov_base = _s; \ + _i->iov_len = strlen(_s); \ + } while(false) + +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { + unsigned j; + size_t r = 0; + + for (j = 0; j < n; j++) + r += i[j].iov_len; + + return r; +} + +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { + unsigned j; + + for (j = 0; j < n; j++) { + size_t sub; + + if (_unlikely_(k <= 0)) + break; + + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t*) i[j].iov_base + sub; + k -= sub; + } + + return k; +} + +#define VA_FORMAT_ADVANCE(format, ap) \ +do { \ + int _argtypes[128]; \ + size_t _i, _k; \ + _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ + assert(_k < ELEMENTSOF(_argtypes)); \ + for (_i = 0; _i < _k; _i++) { \ + if (_argtypes[_i] & PA_FLAG_PTR) { \ + (void) va_arg(ap, void*); \ + continue; \ + } \ + \ + switch (_argtypes[_i]) { \ + case PA_INT: \ + case PA_INT|PA_FLAG_SHORT: \ + case PA_CHAR: \ + (void) va_arg(ap, int); \ + break; \ + case PA_INT|PA_FLAG_LONG: \ + (void) va_arg(ap, long int); \ + break; \ + case PA_INT|PA_FLAG_LONG_LONG: \ + (void) va_arg(ap, long long int); \ + break; \ + case PA_WCHAR: \ + (void) va_arg(ap, wchar_t); \ + break; \ + case PA_WSTRING: \ + case PA_STRING: \ + case PA_POINTER: \ + (void) va_arg(ap, void*); \ + break; \ + case PA_FLOAT: \ + case PA_DOUBLE: \ + (void) va_arg(ap, double); \ + break; \ + case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ + (void) va_arg(ap, long double); \ + break; \ + default: \ + assert_not_reached("Unknown format string argument."); \ + } \ + } \ +} while(false) + + /* Because statfs.t_type can be int on some architectures, we have to cast + * the const magic to the type, otherwise the compiler warns about + * signed/unsigned comparison, because the magic can be 32 bit unsigned. + */ +#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) + +/* Returns the number of chars needed to format variables of the + * specified type as a decimal string. Adds in extra space for a + * negative '-' prefix. */ +#define DECIMAL_STR_MAX(type) \ + (2+(sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + +#define SET_FLAG(v, flag, b) \ + (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) + +#define IN_SET(x, ...) \ + ({ \ + const typeof(x) _x = (x); \ + unsigned _i; \ + bool _found = false; \ + for (_i = 0; _i < sizeof((const typeof(_x)[]) { __VA_ARGS__ })/sizeof(const typeof(_x)); _i++) \ + if (((const typeof(_x)[]) { __VA_ARGS__ })[_i] == _x) { \ + _found = true; \ + break; \ + } \ + _found; \ + }) + +/* Define C11 thread_local attribute even on older gcc compiler + * version */ +#ifndef thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#define thread_local _Thread_local +#else +#define thread_local __thread +#endif +#endif + +/* Define C11 noreturn without and even on older gcc + * compiler versions */ +#ifndef noreturn +#if __STDC_VERSION__ >= 201112L +#define noreturn _Noreturn +#else +#define noreturn __attribute__((noreturn)) +#endif +#endif + +#include "log.h" diff --git a/src/shared/missing.h b/src/shared/missing.h new file mode 100644 index 0000000..b09ca33 --- /dev/null +++ b/src/shared/missing.h @@ -0,0 +1,365 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* Missing glibc definitions to access certain kernel APIs */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_AUDIT +#include +#endif + +#include "macro.h" + +#ifdef ARCH_MIPS +#include +#endif + +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_SETPIPE_SZ +#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) +#endif + +#ifndef F_GETPIPE_SZ +#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) +#endif + +#ifndef IP_FREEBIND +#define IP_FREEBIND 15 +#endif + +#ifndef OOM_SCORE_ADJ_MIN +#define OOM_SCORE_ADJ_MIN (-1000) +#endif + +#ifndef OOM_SCORE_ADJ_MAX +#define OOM_SCORE_ADJ_MAX 1000 +#endif + +#ifndef AUDIT_SERVICE_START +#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */ +#endif + +#ifndef AUDIT_SERVICE_STOP +#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ +#endif + +#ifndef TIOCVHANGUP +#define TIOCVHANGUP 0x5437 +#endif + +#ifndef IP_TRANSPARENT +#define IP_TRANSPARENT 19 +#endif + +#ifndef IFLA_CARRIER + #define IFLA_CARRIER 33 + #ifndef IFLA_NUM_RX_QUEUES + #define IFLA_NUM_RX_QUEUES 32 + #ifndef IFLA_NUM_TX_QUEUES + #define IFLA_NUM_TX_QUEUES 31 + #ifndef IFLA_PROMISCUITY + #define IFLA_PROMISCUITY 30 + #endif + #endif + #endif +#endif + +#if !HAVE_DECL_PIVOT_ROOT +static inline int pivot_root(const char *new_root, const char *put_old) { + return syscall(SYS_pivot_root, new_root, put_old); +} +#endif + +#ifdef __x86_64__ +# ifndef __NR_fanotify_init +# define __NR_fanotify_init 300 +# endif +# ifndef __NR_fanotify_mark +# define __NR_fanotify_mark 301 +# endif +#elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# ifndef __NR_fanotify_init +# define __NR_fanotify_init 4336 +# endif +# ifndef __NR_fanotify_mark +# define __NR_fanotify_mark 4337 +# endif +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# ifndef __NR_fanotify_init +# define __NR_fanotify_init 6300 +# endif +# ifndef __NR_fanotify_mark +# define __NR_fanotify_mark 6301 +# endif +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# ifndef __NR_fanotify_init +# define __NR_fanotify_init 5295 +# endif +# ifndef __NR_fanotify_mark +# define __NR_fanotify_mark 5296 +# endif +# endif +#else +# ifndef __NR_fanotify_init +# define __NR_fanotify_init 338 +# endif +# ifndef __NR_fanotify_mark +# define __NR_fanotify_mark 339 +# endif +#endif + +#ifndef HAVE_FANOTIFY_INIT +static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags) { + return syscall(__NR_fanotify_init, flags, event_f_flags); +} +#endif + +#ifndef HAVE_FANOTIFY_MARK +static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t mask, + int dfd, const char *pathname) { +#if defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI32 || defined __powerpc__ && !defined __powerpc64__ \ + || defined __arm__ && !defined __aarch64__ + union { + uint64_t _64; + uint32_t _32[2]; + } _mask; + _mask._64 = mask; + + return syscall(__NR_fanotify_mark, fanotify_fd, flags, + _mask._32[0], _mask._32[1], dfd, pathname); +#else + return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); +#endif +} +#endif + +#ifndef BTRFS_IOCTL_MAGIC +#define BTRFS_IOCTL_MAGIC 0x94 +#endif + +#ifndef BTRFS_PATH_NAME_MAX +#define BTRFS_PATH_NAME_MAX 4087 +#endif + +#ifndef BTRFS_DEVICE_PATH_NAME_MAX +#define BTRFS_DEVICE_PATH_NAME_MAX 1024 +#endif + +#ifndef BTRFS_FSID_SIZE +#define BTRFS_FSID_SIZE 16 +#endif + +#ifndef BTRFS_UUID_SIZE +#define BTRFS_UUID_SIZE 16 +#endif + +#ifndef HAVE_LINUX_BTRFS_H +struct btrfs_ioctl_vol_args { + int64_t fd; + char name[BTRFS_PATH_NAME_MAX + 1]; +}; + +struct btrfs_ioctl_dev_info_args { + uint64_t devid; /* in/out */ + uint8_t uuid[BTRFS_UUID_SIZE]; /* in/out */ + uint64_t bytes_used; /* out */ + uint64_t total_bytes; /* out */ + uint64_t unused[379]; /* pad to 4k */ + char path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ +}; + +struct btrfs_ioctl_fs_info_args { + uint64_t max_id; /* out */ + uint64_t num_devices; /* out */ + uint8_t fsid[BTRFS_FSID_SIZE]; /* out */ + uint64_t reserved[124]; /* pad to 1k */ +}; +#endif + +#ifndef BTRFS_IOC_DEFRAG +#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, struct btrfs_ioctl_vol_args) +#endif + +#ifndef BTRFS_IOC_DEV_INFO +#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ + struct btrfs_ioctl_dev_info_args) +#endif + +#ifndef BTRFS_IOC_FS_INFO +#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ + struct btrfs_ioctl_fs_info_args) +#endif + +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E +#endif + +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif + +#ifndef MS_PRIVATE +#define MS_PRIVATE (1 << 18) +#endif + +#if !HAVE_DECL_GETTID +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} +#endif + +#ifndef SCM_SECURITY +#define SCM_SECURITY 0x03 +#endif + +#ifndef MS_STRICTATIME +#define MS_STRICTATIME (1<<24) +#endif + +#ifndef MS_REC +#define MS_REC 16384 +#endif + +#ifndef MS_SHARED +#define MS_SHARED (1<<20) +#endif + +#ifndef PR_SET_NO_NEW_PRIVS +#define PR_SET_NO_NEW_PRIVS 38 +#endif + +#ifndef PR_SET_CHILD_SUBREAPER +#define PR_SET_CHILD_SUBREAPER 36 +#endif + +#ifndef MAX_HANDLE_SZ +#define MAX_HANDLE_SZ 128 +#endif + +#ifndef __NR_name_to_handle_at +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +#endif + +#if !HAVE_DECL_NAME_TO_HANDLE_AT +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +} +#endif + +#ifndef HAVE_SECURE_GETENV +# ifdef HAVE___SECURE_GETENV +# define secure_getenv __secure_getenv +# else +# error "neither secure_getenv nor __secure_getenv are available" +# endif +#endif + +#ifndef CIFS_MAGIC_NUMBER +# define CIFS_MAGIC_NUMBER 0xFF534D42 +#endif + +#ifndef TFD_TIMER_CANCEL_ON_SET +# define TFD_TIMER_CANCEL_ON_SET (1 << 1) +#endif + +#ifndef SO_REUSEPORT +# define SO_REUSEPORT 15 +#endif + +#ifndef EVIOCREVOKE +# define EVIOCREVOKE _IOW('E', 0x91, int) +#endif + +#ifndef DRM_IOCTL_SET_MASTER +# define DRM_IOCTL_SET_MASTER _IO('d', 0x1e) +#endif + +#ifndef DRM_IOCTL_DROP_MASTER +# define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f) +#endif + +#if defined(__i386__) || defined(__x86_64__) + +/* The precise definition of __O_TMPFILE is arch specific, so let's + * just define this on x86 where we know the value. */ + +#ifndef __O_TMPFILE +#define __O_TMPFILE 020000000 +#endif + +/* a horrid kludge trying to make sure that this will fail on old kernels */ +#ifndef O_TMPFILE +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#endif + +#endif + +#ifndef __NR_setns +# if defined(__x86_64__) +# define __NR_setns 308 +# elif defined(__i386__) +# define __NR_setns 346 +# else +# error "__NR_setns is not defined" +# endif +#endif + +#if !HAVE_DECL_SETNS +static inline int setns(int fd, int nstype) { + return syscall(__NR_setns, fd, nstype); +} +#endif diff --git a/src/shared/mkdir-label.c b/src/shared/mkdir-label.c new file mode 100644 index 0000000..4ee6251 --- /dev/null +++ b/src/shared/mkdir-label.c @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "label.h" +#include "util.h" +#include "path-util.h" +#include "mkdir.h" + +int mkdir_label(const char *path, mode_t mode) { + return label_mkdir(path, mode); +} + +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) { + return mkdir_safe_internal(path, mode, uid, gid, label_mkdir); +} + +int mkdir_parents_label(const char *path, mode_t mode) { + return mkdir_parents_internal(NULL, path, mode, label_mkdir); +} + +int mkdir_parents_prefix_label(const char *prefix, const char *path, mode_t mode) { + return mkdir_parents_internal(prefix, path, mode, label_mkdir); +} + +int mkdir_p_label(const char *path, mode_t mode) { + return mkdir_p_internal(NULL, path, mode, label_mkdir); +} diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c new file mode 100644 index 0000000..43c6ea6 --- /dev/null +++ b/src/shared/mkdir.c @@ -0,0 +1,143 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "label.h" +#include "util.h" +#include "path-util.h" +#include "mkdir.h" + +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { + struct stat st; + + if (_mkdir(path, mode) >= 0) + if (chmod_and_chown(path, mode, uid, gid) < 0) + return -errno; + + if (lstat(path, &st) < 0) + return -errno; + + if ((st.st_mode & 0777) != mode || + st.st_uid != uid || + st.st_gid != gid || + !S_ISDIR(st.st_mode)) { + errno = EEXIST; + return -errno; + } + + return 0; +} + +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) { + return mkdir_safe_internal(path, mode, uid, gid, mkdir); +} + +static int is_dir(const char* path) { + struct stat st; + + if (stat(path, &st) < 0) + return -errno; + + return S_ISDIR(st.st_mode); +} + +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { + const char *p, *e; + int r; + + assert(path); + + if (prefix && !path_startswith(path, prefix)) + return -ENOTDIR; + + /* return immediately if directory exists */ + e = strrchr(path, '/'); + if (!e) + return -EINVAL; + + if (e == path) + return 0; + + p = strndupa(path, e - path); + r = is_dir(p); + if (r > 0) + return 0; + if (r == 0) + return -ENOTDIR; + + /* create every parent directory in the path, except the last component */ + p = path + strspn(path, "/"); + for (;;) { + char t[strlen(path) + 1]; + + e = p + strcspn(p, "/"); + p = e + strspn(e, "/"); + + /* Is this the last component? If so, then we're + * done */ + if (*p == 0) + return 0; + + memcpy(t, path, e - path); + t[e-path] = 0; + + if (prefix && path_startswith(prefix, t)) + continue; + + r = _mkdir(t, mode); + if (r < 0 && errno != EEXIST) + return -errno; + } +} + +int mkdir_parents(const char *path, mode_t mode) { + return mkdir_parents_internal(NULL, path, mode, mkdir); +} + +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { + int r; + + /* Like mkdir -p */ + + r = mkdir_parents_internal(prefix, path, mode, _mkdir); + if (r < 0) + return r; + + r = _mkdir(path, mode); + if (r < 0 && (errno != EEXIST || is_dir(path) <= 0)) + return -errno; + + return 0; +} + +int mkdir_p(const char *path, mode_t mode) { + return mkdir_p_internal(NULL, path, mode, mkdir); +} + +int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode) { + return mkdir_p_internal(prefix, path, mode, mkdir); +} diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h new file mode 100644 index 0000000..eb73902 --- /dev/null +++ b/src/shared/mkdir.h @@ -0,0 +1,43 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_parents(const char *path, mode_t mode); +int mkdir_p(const char *path, mode_t mode); +int mkdir_p_prefix(const char *prefix, const char *path, mode_t mode); + +/* selinux versions */ +int mkdir_label(const char *path, mode_t mode); +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_parents_label(const char *path, mode_t mode); +int mkdir_p_label(const char *path, mode_t mode); +int mkdir_parents_prefix_label(const char *prefix, const char *path, mode_t mode); + +/* internally used */ +typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir); +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); diff --git a/src/shared/net-util.c b/src/shared/net-util.c new file mode 100644 index 0000000..50cfa2c --- /dev/null +++ b/src/shared/net-util.c @@ -0,0 +1,289 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "net-util.h" +#include "log.h" +#include "utf8.h" +#include "util.h" +#include "conf-parser.h" +#include "condition.h" + +bool net_match_config(const struct ether_addr *match_mac, + const char *match_path, + const char *match_driver, + const char *match_type, + const char *match_name, + Condition *match_host, + Condition *match_virt, + Condition *match_kernel, + Condition *match_arch, + const char *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_host(match_host)) + return 0; + + if (match_virt && !condition_test_virtualization(match_virt)) + return 0; + + if (match_kernel && !condition_test_kernel_command_line(match_kernel)) + return 0; + + if (match_arch && !condition_test_architecture(match_arch)) + return 0; + + if (match_mac && (!dev_mac || memcmp(match_mac, ether_aton(dev_mac), ETH_ALEN))) + return 0; + + if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0))) + return 0; + + if (match_driver) { + if (dev_parent_driver && !streq(match_driver, dev_parent_driver)) + return 0; + else if (!streq_ptr(match_driver, dev_driver)) + return 0; + } + + if (match_type && !streq_ptr(match_type, dev_type)) + return 0; + + if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0))) + return 0; + + return 1; +} + +unsigned net_netmask_to_prefixlen(const struct in_addr *addr) { + assert(addr); + + return 32 - u32ctz(be32toh(addr->s_addr)); +} + +int config_parse_net_condition(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) { + + ConditionType cond = ltype; + Condition **ret = data; + bool negate; + Condition *c; + _cleanup_free_ char *s = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + s = strdup(rvalue); + if (!s) + return log_oom(); + + c = condition_new(cond, s, false, negate); + if (!c) + return log_oom(); + + if (*ret) + condition_free(*ret); + + *ret = c; + return 0; +} + +int config_parse_ifname(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) { + + char **s = data; + char *n; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = strdup(rvalue); + if (!n) + return log_oom(); + + if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + free(*s); + if (*n) + *s = n; + else { + free(n); + *s = NULL; + } + + return 0; +} + +int config_parse_ifalias(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + char *n; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = strdup(rvalue); + if (!n) + return log_oom(); + + if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + free(*s); + if (*n) + *s = n; + else { + free(n); + *s = NULL; + } + + return 0; +} + +int config_parse_hwaddr(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + struct ether_addr **hwaddr = data; + struct ether_addr *n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = new0(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &n->ether_addr_octet[0], + &n->ether_addr_octet[1], + &n->ether_addr_octet[2], + &n->ether_addr_octet[3], + &n->ether_addr_octet[4], + &n->ether_addr_octet[5]); + if (r != 6) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Not a valid MAC address, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + free(*hwaddr); + *hwaddr = n; + + return 0; +} + +int net_parse_inaddr(const char *address, unsigned char *family, void *dst) { + int r; + + assert(address); + assert(family); + assert(dst); + + /* IPv4 */ + r = inet_pton(AF_INET, address, dst); + if (r > 0) { + /* succsefully parsed IPv4 address */ + if (*family == AF_UNSPEC) + *family = AF_INET; + else if (*family != AF_INET) + return -EINVAL; + } else if (r < 0) + return -errno; + else { + /* not an IPv4 address, so let's try IPv6 */ + r = inet_pton(AF_INET6, address, dst); + if (r > 0) { + /* successfully parsed IPv6 address */ + if (*family == AF_UNSPEC) + *family = AF_INET6; + else if (*family != AF_INET6) + return -EINVAL; + } else if (r < 0) + return -errno; + else + return -EINVAL; + } + + return 0; +} diff --git a/src/shared/net-util.h b/src/shared/net-util.h new file mode 100644 index 0000000..99479e1 --- /dev/null +++ b/src/shared/net-util.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include +#include +#include + +#include "condition-util.h" + +bool net_match_config(const struct ether_addr *match_mac, + const char *match_path, + const char *match_driver, + const char *match_type, + const char *match_name, + Condition *match_host, + Condition *match_virt, + Condition *match_kernel, + Condition *match_arch, + const char *dev_mac, + const char *dev_path, + const char *dev_parent_driver, + const char *dev_driver, + const char *dev_type, + const char *dev_name); + +unsigned net_netmask_to_prefixlen(const struct in_addr *netmask); + +int config_parse_net_condition(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_hwaddr(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_ifname(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_ifalias(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int net_parse_inaddr(const char *address, unsigned char *family, void *dst); diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h new file mode 100644 index 0000000..9da789d --- /dev/null +++ b/src/shared/output-mode.h @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef enum OutputMode { + OUTPUT_SHORT, + OUTPUT_SHORT_ISO, + OUTPUT_SHORT_PRECISE, + OUTPUT_SHORT_MONOTONIC, + OUTPUT_VERBOSE, + OUTPUT_EXPORT, + OUTPUT_JSON, + OUTPUT_JSON_PRETTY, + OUTPUT_JSON_SSE, + OUTPUT_CAT, + _OUTPUT_MODE_MAX, + _OUTPUT_MODE_INVALID = -1 +} OutputMode; + +typedef enum OutputFlags { + OUTPUT_SHOW_ALL = 1 << 0, + OUTPUT_FOLLOW = 1 << 1, + OUTPUT_WARN_CUTOFF = 1 << 2, + OUTPUT_FULL_WIDTH = 1 << 3, + OUTPUT_COLOR = 1 << 4, + OUTPUT_CATALOG = 1 << 5 +} OutputFlags; diff --git a/src/shared/pager.c b/src/shared/pager.c new file mode 100644 index 0000000..55b13d6 --- /dev/null +++ b/src/shared/pager.c @@ -0,0 +1,152 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "pager.h" +#include "util.h" +#include "macro.h" + +static pid_t pager_pid = 0; + +noreturn static void pager_fallback(void) { + ssize_t n; + + do { + n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0); + } while (n > 0); + + if (n < 0) { + log_error("Internal pager failed: %m"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); +} + +int pager_open(bool jump_to_end) { + int fd[2]; + const char *pager; + pid_t parent_pid; + int r; + + if (pager_pid > 0) + return 1; + + if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) + if (!*pager || streq(pager, "cat")) + return 0; + + if (!on_tty()) + return 0; + + /* Determine and cache number of columns before we spawn the + * pager so that we get the value from the actual tty */ + columns(); + + if (pipe(fd) < 0) { + log_error("Failed to create pager pipe: %m"); + return -errno; + } + + parent_pid = getpid(); + + pager_pid = fork(); + if (pager_pid < 0) { + r = -errno; + log_error("Failed to fork pager: %m"); + close_pipe(fd); + return r; + } + + /* In the child start the pager */ + if (pager_pid == 0) { + const char* less_opts; + + dup2(fd[0], STDIN_FILENO); + close_pipe(fd); + + less_opts = getenv("SYSTEMD_LESS"); + if (!less_opts) + less_opts = "FRSXMK"; + if (jump_to_end) + less_opts = strappenda(less_opts, " +G"); + setenv("LESS", less_opts, 1); + + /* Make sure the pager goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Check whether our parent died before we were able + * to set the death signal */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + if (pager) { + execlp(pager, pager, NULL); + execl("/bin/sh", "sh", "-c", pager, NULL); + } + + /* Debian's alternatives command for pagers is + * called 'pager'. Note that we do not call + * sensible-pagers here, since that is just a + * shell script that implements a logic that + * is similar to this one anyway, but is + * Debian-specific. */ + execlp("pager", "pager", NULL); + + execlp("less", "less", NULL); + execlp("more", "more", NULL); + + pager_fallback(); + /* not reached */ + } + + /* Return in the parent */ + if (dup2(fd[1], STDOUT_FILENO) < 0) { + log_error("Failed to duplicate pager pipe: %m"); + return -errno; + } + + close_pipe(fd); + return 1; +} + +void pager_close(void) { + + if (pager_pid <= 0) + return; + + /* Inform pager that we are done */ + fclose(stdout); + kill(pager_pid, SIGCONT); + wait_for_terminate(pager_pid, NULL); + pager_pid = 0; +} + +bool pager_have(void) { + return pager_pid > 0; +} diff --git a/src/shared/pager.h b/src/shared/pager.h new file mode 100644 index 0000000..03dca8b --- /dev/null +++ b/src/shared/pager.h @@ -0,0 +1,30 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" + +int pager_open(bool jump_to_end); +void pager_close(void); +bool pager_have(void) _pure_; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c new file mode 100644 index 0000000..63af43c --- /dev/null +++ b/src/shared/path-lookup.c @@ -0,0 +1,385 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "strv.h" +#include "path-util.h" +#include "path-lookup.h" + +static const char* const systemd_running_as_table[_SYSTEMD_RUNNING_AS_MAX] = { + [SYSTEMD_SYSTEM] = "system", + [SYSTEMD_USER] = "user" +}; + +DEFINE_STRING_TABLE_LOOKUP(systemd_running_as, SystemdRunningAs); + +int user_config_home(char **config_home) { + const char *e; + char *r; + + e = getenv("XDG_CONFIG_HOME"); + if (e) { + r = strappend(e, "/systemd/user"); + if (!r) + return -ENOMEM; + + *config_home = r; + return 1; + } else { + const char *home; + + home = getenv("HOME"); + if (home) { + r = strappend(home, "/.config/systemd/user"); + if (!r) + return -ENOMEM; + + *config_home = r; + return 1; + } + } + + return 0; +} + +static char** user_dirs( + const char *generator, + const char *generator_early, + const char *generator_late) { + + const char * const config_unit_paths[] = { + USER_CONFIG_UNIT_PATH, + "/etc/systemd/user", + "/run/systemd/user", + NULL + }; + + const char * const data_unit_paths[] = { + "/usr/local/lib/systemd/user", + "/usr/local/share/systemd/user", + USER_DATA_UNIT_PATH, + "/usr/lib/systemd/user", + "/usr/share/systemd/user", + NULL + }; + + const char *home, *e; + _cleanup_free_ char *config_home = NULL, *data_home = NULL; + _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL; + + /* Implement the mechanisms defined in + * + * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html + * + * We look in both the config and the data dirs because we + * want to encourage that distributors ship their unit files + * as data, and allow overriding as configuration. + */ + + if (user_config_home(&config_home) < 0) + goto fail; + + home = getenv("HOME"); + + e = getenv("XDG_CONFIG_DIRS"); + if (e) { + config_dirs = strv_split(e, ":"); + if (!config_dirs) + goto fail; + } + + /* We don't treat /etc/xdg/systemd here as the spec + * suggests because we assume that that is a link to + * /etc/systemd/ anyway. */ + + e = getenv("XDG_DATA_HOME"); + if (e) { + if (asprintf(&data_home, "%s/systemd/user", e) < 0) + goto fail; + + } else if (home) { + if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0) + goto fail; + + /* There is really no need for two unit dirs in $HOME, + * except to be fully compliant with the XDG spec. We + * now try to link the two dirs, so that we can + * minimize disk seeks a little. Further down we'll + * then filter out this link, if it is actually is + * one. */ + + mkdir_parents_label(data_home, 0777); + (void) symlink("../../../.config/systemd/user", data_home); + } + + e = getenv("XDG_DATA_DIRS"); + if (e) + data_dirs = strv_split(e, ":"); + else + data_dirs = strv_new("/usr/local/share", + "/usr/share", + NULL); + if (!data_dirs) + goto fail; + + /* Now merge everything we found. */ + if (generator_early) + if (strv_extend(&r, generator_early) < 0) + goto fail; + + if (config_home) + if (strv_extend(&r, config_home) < 0) + goto fail; + + if (!strv_isempty(config_dirs)) + if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) + goto fail; + + if (strv_extend_strv(&r, (char**) config_unit_paths) < 0) + goto fail; + + if (generator) + if (strv_extend(&r, generator) < 0) + goto fail; + + if (data_home) + if (strv_extend(&r, data_home) < 0) + goto fail; + + if (!strv_isempty(data_dirs)) + if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0) + goto fail; + + if (strv_extend_strv(&r, (char**) data_unit_paths) < 0) + goto fail; + + if (generator_late) + if (strv_extend(&r, generator_late) < 0) + goto fail; + + if (!path_strv_make_absolute_cwd(r)) + goto fail; + + return r; + +fail: + strv_free(r); + return NULL; +} + +int lookup_paths_init( + LookupPaths *p, + SystemdRunningAs running_as, + bool personal, + const char *generator, + const char *generator_early, + const char *generator_late) { + + const char *e; + + assert(p); + + /* First priority is whatever has been passed to us via env + * vars */ + e = getenv("SYSTEMD_UNIT_PATH"); + if (e) { + p->unit_path = path_split_and_make_absolute(e); + if (!p->unit_path) + return -ENOMEM; + } else + p->unit_path = NULL; + + if (strv_isempty(p->unit_path)) { + /* Nothing is set, so let's figure something out. */ + strv_free(p->unit_path); + + /* For the user units we include share/ in the search + * path in order to comply with the XDG basedir + * spec. For the system stuff we avoid such + * nonsense. OTOH we include /lib in the search path + * for the system stuff but avoid it for user + * stuff. */ + + if (running_as == SYSTEMD_USER) { + + if (personal) + p->unit_path = user_dirs(generator, generator_early, generator_late); + else + p->unit_path = strv_new( + /* If you modify this you also want to modify + * systemduserunitpath= in systemd.pc.in, and + * the arrays in user_dirs() above! */ + STRV_IFNOTNULL(generator_early), + USER_CONFIG_UNIT_PATH, + "/etc/systemd/user", + "/run/systemd/user", + STRV_IFNOTNULL(generator), + "/usr/local/lib/systemd/user", + "/usr/local/share/systemd/user", + USER_DATA_UNIT_PATH, + "/usr/lib/systemd/user", + "/usr/share/systemd/user", + STRV_IFNOTNULL(generator_late), + NULL); + + if (!p->unit_path) + return -ENOMEM; + + } else { + p->unit_path = strv_new( + /* If you modify this you also want to modify + * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(generator_early), + SYSTEM_CONFIG_UNIT_PATH, + "/etc/systemd/system", + "/run/systemd/system", + STRV_IFNOTNULL(generator), + "/usr/local/lib/systemd/system", + SYSTEM_DATA_UNIT_PATH, + "/usr/lib/systemd/system", +#ifdef HAVE_SPLIT_USR + "/lib/systemd/system", +#endif + STRV_IFNOTNULL(generator_late), + NULL); + + if (!p->unit_path) + return -ENOMEM; + } + } + + if (!path_strv_canonicalize_absolute(p->unit_path, NULL)) + return -ENOMEM; + + strv_uniq(p->unit_path); + + if (!strv_isempty(p->unit_path)) { + _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); + if (!t) + return -ENOMEM; + log_debug("Looking for unit files in (higher priority first):\n\t%s", t); + } else { + log_debug("Ignoring unit files."); + strv_free(p->unit_path); + p->unit_path = NULL; + } + + if (running_as == SYSTEMD_SYSTEM) { +#ifdef HAVE_SYSV_COMPAT + /* /etc/init.d/ compatibility does not matter to users */ + + e = getenv("SYSTEMD_SYSVINIT_PATH"); + if (e) { + p->sysvinit_path = path_split_and_make_absolute(e); + if (!p->sysvinit_path) + return -ENOMEM; + } else + p->sysvinit_path = NULL; + + if (strv_isempty(p->sysvinit_path)) { + strv_free(p->sysvinit_path); + + p->sysvinit_path = strv_new( + SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ + NULL); + if (!p->sysvinit_path) + return -ENOMEM; + } + + e = getenv("SYSTEMD_SYSVRCND_PATH"); + if (e) { + p->sysvrcnd_path = path_split_and_make_absolute(e); + if (!p->sysvrcnd_path) + return -ENOMEM; + } else + p->sysvrcnd_path = NULL; + + if (strv_isempty(p->sysvrcnd_path)) { + strv_free(p->sysvrcnd_path); + + p->sysvrcnd_path = strv_new( + SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ + NULL); + if (!p->sysvrcnd_path) + return -ENOMEM; + } + + if (!path_strv_canonicalize_absolute(p->sysvinit_path, NULL)) + return -ENOMEM; + + if (!path_strv_canonicalize_absolute(p->sysvrcnd_path, NULL)) + return -ENOMEM; + + strv_uniq(p->sysvinit_path); + strv_uniq(p->sysvrcnd_path); + + if (!strv_isempty(p->sysvinit_path)) { + _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); + if (!t) + return -ENOMEM; + log_debug("Looking for SysV init scripts in:\n\t%s", t); + } else { + log_debug("Ignoring SysV init scripts."); + strv_free(p->sysvinit_path); + p->sysvinit_path = NULL; + } + + if (!strv_isempty(p->sysvrcnd_path)) { + _cleanup_free_ char *t = + strv_join(p->sysvrcnd_path, "\n\t"); + if (!t) + return -ENOMEM; + + log_debug("Looking for SysV rcN.d links in:\n\t%s", t); + } else { + log_debug("Ignoring SysV rcN.d links."); + strv_free(p->sysvrcnd_path); + p->sysvrcnd_path = NULL; + } +#else + log_debug("SysV init scripts and rcN.d links support disabled"); +#endif + } + + return 0; +} + +void lookup_paths_free(LookupPaths *p) { + assert(p); + + strv_free(p->unit_path); + p->unit_path = NULL; + +#ifdef HAVE_SYSV_COMPAT + strv_free(p->sysvinit_path); + strv_free(p->sysvrcnd_path); + p->sysvinit_path = p->sysvrcnd_path = NULL; +#endif +} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h new file mode 100644 index 0000000..a3ef824 --- /dev/null +++ b/src/shared/path-lookup.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef struct LookupPaths { + char **unit_path; +#ifdef HAVE_SYSV_COMPAT + char **sysvinit_path; + char **sysvrcnd_path; +#endif +} LookupPaths; + +typedef enum SystemdRunningAs { + SYSTEMD_SYSTEM, + SYSTEMD_USER, + _SYSTEMD_RUNNING_AS_MAX, + _SYSTEMD_RUNNING_AS_INVALID = -1 +} SystemdRunningAs; + +#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) + +const char* systemd_running_as_to_string(SystemdRunningAs i) _const_; +SystemdRunningAs systemd_running_as_from_string(const char *s) _pure_; + +int user_config_home(char **config_home); + +int lookup_paths_init(LookupPaths *p, SystemdRunningAs running_as, bool personal, const char *generator, const char *generator_early, const char *generator_late); +void lookup_paths_free(LookupPaths *p); diff --git a/src/shared/path-util.c b/src/shared/path-util.c new file mode 100644 index 0000000..bdc54a9 --- /dev/null +++ b/src/shared/path-util.c @@ -0,0 +1,509 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "log.h" +#include "strv.h" +#include "path-util.h" +#include "missing.h" + +bool path_is_absolute(const char *p) { + return p[0] == '/'; +} + +bool is_path(const char *p) { + return !!strchr(p, '/'); +} + +int path_get_parent(const char *path, char **_r) { + const char *e, *a = NULL, *b = NULL, *p; + char *r; + bool slash = false; + + assert(path); + assert(_r); + + if (!*path) + return -EINVAL; + + for (e = path; *e; e++) { + + if (!slash && *e == '/') { + a = b; + b = e; + slash = true; + } else if (slash && *e != '/') + slash = false; + } + + if (*(e-1) == '/') + p = a; + else + p = b; + + if (!p) + return -EINVAL; + + if (p == path) + r = strdup("/"); + else + r = strndup(path, p-path); + + if (!r) + return -ENOMEM; + + *_r = r; + return 0; +} + +char **path_split_and_make_absolute(const char *p) { + char **l; + assert(p); + + l = strv_split(p, ":"); + if (!l) + return NULL; + + if (!path_strv_make_absolute_cwd(l)) { + strv_free(l); + return NULL; + } + + return l; +} + +char *path_make_absolute(const char *p, const char *prefix) { + assert(p); + + /* Makes every item in the list an absolute path by prepending + * the prefix, if specified and necessary */ + + if (path_is_absolute(p) || !prefix) + return strdup(p); + + return strjoin(prefix, "/", p, NULL); +} + +char *path_make_absolute_cwd(const char *p) { + _cleanup_free_ char *cwd = NULL; + + assert(p); + + /* Similar to path_make_absolute(), but prefixes with the + * current working directory. */ + + if (path_is_absolute(p)) + return strdup(p); + + cwd = get_current_dir_name(); + if (!cwd) + return NULL; + + return path_make_absolute(p, cwd); +} + +char **path_strv_make_absolute_cwd(char **l) { + char **s; + + /* Goes through every item in the string list and makes it + * absolute. This works in place and won't rollback any + * changes on failure. */ + + STRV_FOREACH(s, l) { + char *t; + + t = path_make_absolute_cwd(*s); + if (!t) + return NULL; + + free(*s); + *s = t; + } + + return l; +} + +char **path_strv_canonicalize_absolute(char **l, const char *prefix) { + char **s; + unsigned k = 0; + bool enomem = false; + + if (strv_isempty(l)) + return l; + + /* Goes through every item in the string list and canonicalize + * the path. This works in place and won't rollback any + * changes on failure. */ + + STRV_FOREACH(s, l) { + char *t, *u; + + if (!path_is_absolute(*s)) + continue; + + if (prefix) { + t = strappend(prefix, *s); + free(*s); + *s = NULL; + + if (!t) { + enomem = true; + continue; + } + } else { + t = *s; + *s = NULL; + } + + errno = 0; + u = canonicalize_file_name(t); + if (!u) { + if (errno == ENOENT) + u = t; + else { + free(t); + if (errno == ENOMEM || errno == 0) + enomem = true; + + continue; + } + } else + free(t); + + l[k++] = u; + } + + l[k] = NULL; + + if (enomem) + return NULL; + + return l; +} + +char **path_strv_canonicalize_absolute_uniq(char **l, const char *prefix) { + + if (strv_isempty(l)) + return l; + + if (!path_strv_canonicalize_absolute(l, prefix)) + return NULL; + + return strv_uniq(l); +} + +char *path_kill_slashes(char *path) { + char *f, *t; + bool slash = false; + + /* Removes redundant inner and trailing slashes. Modifies the + * passed string in-place. + * + * ///foo///bar/ becomes /foo/bar + */ + + for (f = path, t = path; *f; f++) { + + if (*f == '/') { + slash = true; + continue; + } + + if (slash) { + slash = false; + *(t++) = '/'; + } + + *(t++) = *f; + } + + /* Special rule, if we are talking of the root directory, a + trailing slash is good */ + + if (t == path && slash) + *(t++) = '/'; + + *t = 0; + return path; +} + +char* path_startswith(const char *path, const char *prefix) { + assert(path); + assert(prefix); + + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; + + for (;;) { + size_t a, b; + + path += strspn(path, "/"); + prefix += strspn(prefix, "/"); + + if (*prefix == 0) + return (char*) path; + + if (*path == 0) + return NULL; + + a = strcspn(path, "/"); + b = strcspn(prefix, "/"); + + if (a != b) + return NULL; + + if (memcmp(path, prefix, a) != 0) + return NULL; + + path += a; + prefix += b; + } +} + +bool path_equal(const char *a, const char *b) { + assert(a); + assert(b); + + if ((a[0] == '/') != (b[0] == '/')) + return false; + + for (;;) { + size_t j, k; + + a += strspn(a, "/"); + b += strspn(b, "/"); + + if (*a == 0 && *b == 0) + return true; + + if (*a == 0 || *b == 0) + return false; + + j = strcspn(a, "/"); + k = strcspn(b, "/"); + + if (j != k) + return false; + + if (memcmp(a, b, j) != 0) + return false; + + a += j; + b += k; + } +} + +int path_is_mount_point(const char *t, bool allow_symlink) { + char *parent; + int r; + struct file_handle *h; + int mount_id, mount_id_parent; + struct stat a, b; + + /* We are not actually interested in the file handles, but + * name_to_handle_at() also passes us the mount ID, hence use + * it but throw the handle away */ + + if (path_equal(t, "/")) + return 1; + + h = alloca(MAX_HANDLE_SZ); + h->handle_bytes = MAX_HANDLE_SZ; + + r = name_to_handle_at(AT_FDCWD, t, h, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); + if (r < 0) { + if (errno == ENOSYS || errno == ENOTSUP) + /* This kernel or file system does not support + * name_to_handle_at(), hence fallback to the + * traditional stat() logic */ + goto fallback; + + if (errno == ENOENT) + return 0; + + return -errno; + } + + r = path_get_parent(t, &parent); + if (r < 0) + return r; + + h->handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(AT_FDCWD, parent, h, &mount_id_parent, 0); + free(parent); + + if (r < 0) { + /* The parent can't do name_to_handle_at() but the + * directory we are interested in can? If so, it must + * be a mount point */ + if (errno == ENOTSUP) + return 1; + + return -errno; + } + + return mount_id != mount_id_parent; + +fallback: + if (allow_symlink) + r = stat(t, &a); + else + r = lstat(t, &a); + + if (r < 0) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + r = path_get_parent(t, &parent); + if (r < 0) + return r; + + r = lstat(parent, &b); + free(parent); + + if (r < 0) + return -errno; + + return a.st_dev != b.st_dev; +} + +int path_is_read_only_fs(const char *path) { + struct statvfs st; + + assert(path); + + if (statvfs(path, &st) < 0) + return -errno; + + return !!(st.f_flag & ST_RDONLY); +} + +int path_is_os_tree(const char *path) { + char *p; + int r; + + /* We use /etc/os-release as flag file if something is an OS */ + + p = strappenda(path, "/etc/os-release"); + r = access(p, F_OK); + + return r < 0 ? 0 : 1; +} + +int find_binary(const char *name, char **filename) { + assert(name); + assert(filename); + + if (strchr(name, '/')) { + char *p; + + if (path_is_absolute(name)) + p = strdup(name); + else + p = path_make_absolute_cwd(name); + if (!p) + return -ENOMEM; + + *filename = p; + return 0; + } else { + const char *path; + char *state, *w; + size_t l; + + /** + * Plain getenv, not secure_getenv, because we want + * to actually allow the user to pick the binary. + */ + path = getenv("PATH"); + if (!path) + path = DEFAULT_PATH; + + FOREACH_WORD_SEPARATOR(w, l, path, ":", state) { + char *p; + + if (asprintf(&p, "%.*s/%s", (int) l, w, name) < 0) + return -ENOMEM; + + if (access(p, X_OK) < 0) { + free(p); + continue; + } + + path_kill_slashes(p); + *filename = p; + + return 0; + } + + return -ENOENT; + } +} + +bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { + bool changed = false; + const char* const* i; + + assert(timestamp); + + if (paths == NULL) + return false; + + STRV_FOREACH(i, paths) { + struct stat stats; + usec_t u; + + if (stat(*i, &stats) < 0) + continue; + + u = timespec_load(&stats.st_mtim); + + /* first check */ + if (*timestamp >= u) + continue; + + log_debug("timestamp of '%s' changed", *i); + + /* update timestamp */ + if (update) { + *timestamp = u; + changed = true; + } else + return true; + } + + return changed; +} diff --git a/src/shared/path-util.h b/src/shared/path-util.h new file mode 100644 index 0000000..2b8ea02 --- /dev/null +++ b/src/shared/path-util.h @@ -0,0 +1,68 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" +#include "time-util.h" + +#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" +#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" + +#ifdef HAVE_SPLIT_USR +# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR +#else +# define DEFAULT_PATH DEFAULT_PATH_NORMAL +#endif + +bool is_path(const char *p) _pure_; +char** path_split_and_make_absolute(const char *p); +int path_get_parent(const char *path, char **parent); +bool path_is_absolute(const char *p) _pure_; +char* path_make_absolute(const char *p, const char *prefix); +char* path_make_absolute_cwd(const char *p); +char* path_kill_slashes(char *path); +char* path_startswith(const char *path, const char *prefix) _pure_; +bool path_equal(const char *a, const char *b) _pure_; + +char** path_strv_make_absolute_cwd(char **l); +char** path_strv_canonicalize_absolute(char **l, const char *prefix); +char** path_strv_canonicalize_absolute_uniq(char **l, const char *prefix); + +int path_is_mount_point(const char *path, bool allow_symlink); +int path_is_read_only_fs(const char *path); +int path_is_os_tree(const char *path); + +int find_binary(const char *name, char **filename); + +bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); + +/* Iterates through the path prefixes of the specified path, going up + * the tree, to root. Also returns "" (and not "/"!) for the root + * directory. Excludes the specified directory itself */ +#define PATH_FOREACH_PREFIX(prefix, path) \ + for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && !(*_slash = 0); _slash = strrchr((prefix), '/')) + +/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ +#define PATH_FOREACH_PREFIX_MORE(prefix, path) \ + for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && !(*_slash = 0); _slash = strrchr((prefix), '/')) diff --git a/src/shared/prioq.c b/src/shared/prioq.c new file mode 100644 index 0000000..8af4c51 --- /dev/null +++ b/src/shared/prioq.c @@ -0,0 +1,306 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "prioq.h" + +struct prioq_item { + void *data; + unsigned *idx; +}; + +struct Prioq { + compare_func_t compare_func; + unsigned n_items, n_allocated; + + struct prioq_item *items; +}; + +Prioq *prioq_new(compare_func_t compare_func) { + Prioq *q; + + q = new0(Prioq, 1); + if (!q) + return q; + + q->compare_func = compare_func; + return q; +} + +void prioq_free(Prioq *q) { + if (!q) + return; + + free(q->items); + free(q); +} + +int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) { + assert(q); + + if (*q) + return 0; + + *q = prioq_new(compare_func); + if (!*q) + return -ENOMEM; + + return 0; +} + +static void swap(Prioq *q, unsigned j, unsigned k) { + void *saved_data; + unsigned *saved_idx; + + assert(q); + assert(j < q->n_items); + assert(k < q->n_items); + + assert(!q->items[j].idx || *(q->items[j].idx) == j); + assert(!q->items[k].idx || *(q->items[k].idx) == k); + + saved_data = q->items[j].data; + saved_idx = q->items[j].idx; + q->items[j].data = q->items[k].data; + q->items[j].idx = q->items[k].idx; + q->items[k].data = saved_data; + q->items[k].idx = saved_idx; + + if (q->items[j].idx) + *q->items[j].idx = j; + + if (q->items[k].idx) + *q->items[k].idx = k; +} + +static unsigned shuffle_up(Prioq *q, unsigned idx) { + assert(q); + + while (idx > 0) { + unsigned k; + + k = (idx-1)/2; + + if (q->compare_func(q->items[k].data, q->items[idx].data) < 0) + break; + + swap(q, idx, k); + idx = k; + } + + return idx; +} + +static unsigned shuffle_down(Prioq *q, unsigned idx) { + assert(q); + + for (;;) { + unsigned j, k, s; + + k = (idx+1)*2; /* right child */ + j = k-1; /* left child */ + + if (j >= q->n_items) + break; + + if (q->compare_func(q->items[j].data, q->items[idx].data) < 0) + + /* So our left child is smaller than we are, let's + * remember this fact */ + s = j; + else + s = idx; + + if (k < q->n_items && + q->compare_func(q->items[k].data, q->items[s].data) < 0) + + /* So our right child is smaller than we are, let's + * remember this fact */ + s = k; + + /* s now points to the smallest of the three items */ + + if (s == idx) + /* No swap necessary, we're done */ + break; + + swap(q, idx, s); + idx = s; + } + + return idx; +} + +int prioq_put(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + unsigned k; + + assert(q); + + if (q->n_items >= q->n_allocated) { + unsigned n; + struct prioq_item *j; + + n = MAX((q->n_items+1) * 2, 16u); + j = realloc(q->items, sizeof(struct prioq_item) * n); + if (!j) + return -ENOMEM; + + q->items = j; + q->n_allocated = n; + } + + k = q->n_items++; + i = q->items + k; + i->data = data; + i->idx = idx; + + if (idx) + *idx = k; + + shuffle_up(q, k); + + return 0; +} + +static void remove_item(Prioq *q, struct prioq_item *i) { + struct prioq_item *l; + + assert(q); + assert(i); + + l = q->items + q->n_items - 1; + + if (i == l) + /* Last entry, let's just remove it */ + q->n_items--; + else { + unsigned k; + + /* Not last entry, let's replace the last entry with + * this one, and reshuffle */ + + k = i - q->items; + + i->data = l->data; + i->idx = l->idx; + if (i->idx) + *i->idx = k; + q->n_items--; + + k = shuffle_down(q, k); + shuffle_up(q, k); + } +} + +_pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + + assert(q); + + if (idx) { + if (*idx == PRIOQ_IDX_NULL || + *idx > q->n_items) + return NULL; + + i = q->items + *idx; + if (i->data != data) + return NULL; + + return i; + } else { + for (i = q->items; i < q->items + q->n_items; i++) + if (i->data == data) + return i; + return NULL; + } +} + +int prioq_remove(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + + if (!q) + return 0; + + i = find_item(q, data, idx); + if (!i) + return 0; + + remove_item(q, i); + return 1; +} + +int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + unsigned k; + + assert(q); + + i = find_item(q, data, idx); + if (!i) + return 0; + + k = i - q->items; + k = shuffle_down(q, k); + shuffle_up(q, k); + return 1; +} + +void *prioq_peek(Prioq *q) { + + if (!q) + return NULL; + + if (q->n_items <= 0) + return NULL; + + return q->items[0].data; +} + +void *prioq_pop(Prioq *q) { + void *data; + + if (!q) + return NULL; + + if (q->n_items <= 0) + return NULL; + + data = q->items[0].data; + remove_item(q, q->items); + return data; +} + +unsigned prioq_size(Prioq *q) { + + if (!q) + return 0; + + return q->n_items; +} + +bool prioq_isempty(Prioq *q) { + + if (!q) + return true; + + return q->n_items <= 0; +} diff --git a/src/shared/prioq.h b/src/shared/prioq.h new file mode 100644 index 0000000..d836b36 --- /dev/null +++ b/src/shared/prioq.h @@ -0,0 +1,42 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "hashmap.h" + +typedef struct Prioq Prioq; + +#define PRIOQ_IDX_NULL ((unsigned) -1) + +Prioq *prioq_new(compare_func_t compare); +void prioq_free(Prioq *q); +int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func); + +int prioq_put(Prioq *q, void *data, unsigned *idx); +int prioq_remove(Prioq *q, void *data, unsigned *idx); +int prioq_reshuffle(Prioq *q, void *data, unsigned *idx); + +void *prioq_peek(Prioq *q) _pure_; +void *prioq_pop(Prioq *q); + +unsigned prioq_size(Prioq *q) _pure_; +bool prioq_isempty(Prioq *q) _pure_; diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c new file mode 100644 index 0000000..d44d70b --- /dev/null +++ b/src/shared/ptyfwd.c @@ -0,0 +1,386 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "ptyfwd.h" + +#define ESCAPE_USEC USEC_PER_SEC + +static bool look_for_escape(usec_t *timestamp, unsigned *counter, const char *buffer, size_t n) { + const char *p; + + assert(timestamp); + assert(counter); + assert(buffer); + assert(n > 0); + + for (p = buffer; p < buffer + n; p++) { + + /* Check for ^] */ + if (*p == 0x1D) { + usec_t nw = now(CLOCK_MONOTONIC); + + if (*counter == 0 || nw > *timestamp + USEC_PER_SEC) { + *timestamp = nw; + *counter = 1; + } else { + (*counter)++; + + if (*counter >= 3) + return true; + } + } else { + *timestamp = 0; + *counter = 0; + } + } + + return false; +} + +static int process_pty_loop(int master, sigset_t *mask, pid_t kill_pid, int signo) { + char in_buffer[LINE_MAX], out_buffer[LINE_MAX]; + size_t in_buffer_full = 0, out_buffer_full = 0; + struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev; + bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false; + bool stdin_hangup = false, stdout_hangup = false, master_hangup = false; + bool tried_orderly_shutdown = false, process_signalfd = false, quit = false; + usec_t escape_timestamp = 0; + unsigned escape_counter = 0; + _cleanup_close_ int ep = -1, signal_fd = -1; + + assert(master >= 0); + assert(mask); + assert(kill_pid == 0 || kill_pid > 1); + assert(signo >= 0 && signo < _NSIG); + + fd_nonblock(STDIN_FILENO, true); + fd_nonblock(STDOUT_FILENO, true); + fd_nonblock(master, true); + + signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (signal_fd < 0) { + log_error("signalfd(): %m"); + return -errno; + } + + ep = epoll_create1(EPOLL_CLOEXEC); + if (ep < 0) { + log_error("Failed to create epoll: %m"); + return -errno; + } + + /* We read from STDIN only if this is actually a TTY, + * otherwise we assume non-interactivity. */ + if (isatty(STDIN_FILENO)) { + zero(stdin_ev); + stdin_ev.events = EPOLLIN|EPOLLET; + stdin_ev.data.fd = STDIN_FILENO; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) { + log_error("Failed to register STDIN in epoll: %m"); + return -errno; + } + } + + zero(stdout_ev); + stdout_ev.events = EPOLLOUT|EPOLLET; + stdout_ev.data.fd = STDOUT_FILENO; + + zero(master_ev); + master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET; + master_ev.data.fd = master; + + zero(signal_ev); + signal_ev.events = EPOLLIN; + signal_ev.data.fd = signal_fd; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) { + if (errno != EPERM) { + log_error("Failed to register stdout in epoll: %m"); + return -errno; + } + + /* stdout without epoll support. Likely redirected to regular file. */ + stdout_writable = true; + } + + if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 || + epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) { + log_error("Failed to register fds in epoll: %m"); + return -errno; + } + + for (;;) { + struct epoll_event ev[16]; + ssize_t k; + int i, nfds; + + nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), quit ? 0 : -1); + if (nfds < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + log_error("epoll_wait(): %m"); + return -errno; + } + + if (nfds == 0) + return 0; + + for (i = 0; i < nfds; i++) { + if (ev[i].data.fd == STDIN_FILENO) { + + if (ev[i].events & (EPOLLIN|EPOLLHUP)) + stdin_readable = true; + + } else if (ev[i].data.fd == STDOUT_FILENO) { + + if (ev[i].events & (EPOLLOUT|EPOLLHUP)) + stdout_writable = true; + + } else if (ev[i].data.fd == master) { + + if (ev[i].events & (EPOLLIN|EPOLLHUP)) + master_readable = true; + + if (ev[i].events & (EPOLLOUT|EPOLLHUP)) + master_writable = true; + + } else if (ev[i].data.fd == signal_fd) + process_signalfd = true; + } + + while ((stdin_readable && in_buffer_full <= 0) || + (master_writable && in_buffer_full > 0) || + (master_readable && out_buffer_full <= 0) || + (stdout_writable && out_buffer_full > 0)) { + + if (stdin_readable && in_buffer_full < LINE_MAX) { + + k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full); + if (k < 0) { + + if (errno == EAGAIN) + stdin_readable = false; + else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) { + stdin_readable = false; + stdin_hangup = true; + epoll_ctl(ep, EPOLL_CTL_DEL, STDIN_FILENO, NULL); + } else { + log_error("read(): %m"); + return -errno; + } + } else { + /* Check if ^] has been + * pressed three times within + * one second. If we get this + * we quite immediately. */ + if (look_for_escape(&escape_timestamp, &escape_counter, in_buffer + in_buffer_full, k)) + return !quit; + + in_buffer_full += (size_t) k; + } + } + + if (master_writable && in_buffer_full > 0) { + + k = write(master, in_buffer, in_buffer_full); + if (k < 0) { + + if (errno == EAGAIN || errno == EIO) + master_writable = false; + else if (errno == EPIPE || errno == ECONNRESET) { + master_writable = master_readable = false; + master_hangup = true; + epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL); + } else { + log_error("write(): %m"); + return -errno; + } + + } else { + assert(in_buffer_full >= (size_t) k); + memmove(in_buffer, in_buffer + k, in_buffer_full - k); + in_buffer_full -= k; + } + } + + if (master_readable && out_buffer_full < LINE_MAX) { + + k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full); + if (k < 0) { + + /* Note that EIO on the master + * device might be cause by + * vhangup() or temporary + * closing of everything on + * the other side, we treat it + * like EAGAIN here and try + * again. */ + + if (errno == EAGAIN || errno == EIO) + master_readable = false; + else if (errno == EPIPE || errno == ECONNRESET) { + master_readable = master_writable = false; + master_hangup = true; + epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL); + } else { + log_error("read(): %m"); + return -errno; + } + } else + out_buffer_full += (size_t) k; + } + + if (stdout_writable && out_buffer_full > 0) { + + k = write(STDOUT_FILENO, out_buffer, out_buffer_full); + if (k < 0) { + + if (errno == EAGAIN) + stdout_writable = false; + else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) { + stdout_writable = false; + stdout_hangup = true; + epoll_ctl(ep, EPOLL_CTL_DEL, STDOUT_FILENO, NULL); + } else { + log_error("write(): %m"); + return -errno; + } + + } else { + assert(out_buffer_full >= (size_t) k); + memmove(out_buffer, out_buffer + k, out_buffer_full - k); + out_buffer_full -= k; + } + } + + } + + if (process_signalfd) { + struct signalfd_siginfo sfsi; + ssize_t n; + + n = read(signal_fd, &sfsi, sizeof(sfsi)); + if (n != sizeof(sfsi)) { + + if (n >= 0) { + log_error("Failed to read from signalfd: invalid block size"); + return -EIO; + } + + if (errno != EINTR && errno != EAGAIN) { + log_error("Failed to read from signalfd: %m"); + return -errno; + } + } else { + + if (sfsi.ssi_signo == SIGWINCH) { + struct winsize ws; + + /* The window size changed, let's forward that. */ + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) + ioctl(master, TIOCSWINSZ, &ws); + + } else if (sfsi.ssi_signo == SIGTERM && kill_pid > 0 && signo > 0 && !tried_orderly_shutdown) { + + if (kill(kill_pid, signo) < 0) + quit = true; + else { + log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination."); + + /* This only works for systemd... */ + tried_orderly_shutdown = true; + } + + } else + /* Signals that where + * delivered via signalfd that + * we didn't know are a reason + * for us to quit */ + quit = true; + } + } + + if (stdin_hangup || stdout_hangup || master_hangup) { + /* Exit the loop if any side hung up and if + * there's nothing more to write or nothing we + * could write. */ + + if ((out_buffer_full <= 0 || stdout_hangup) && + (in_buffer_full <= 0 || master_hangup)) + return !quit; + } + } +} + +int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo) { + struct termios saved_stdin_attr, raw_stdin_attr; + struct termios saved_stdout_attr, raw_stdout_attr; + bool saved_stdin = false; + bool saved_stdout = false; + struct winsize ws; + int r; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) + ioctl(master, TIOCSWINSZ, &ws); + + if (tcgetattr(STDIN_FILENO, &saved_stdin_attr) >= 0) { + saved_stdin = true; + + raw_stdin_attr = saved_stdin_attr; + cfmakeraw(&raw_stdin_attr); + raw_stdin_attr.c_oflag = saved_stdin_attr.c_oflag; + tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr); + } + if (tcgetattr(STDOUT_FILENO, &saved_stdout_attr) >= 0) { + saved_stdout = true; + + raw_stdout_attr = saved_stdout_attr; + cfmakeraw(&raw_stdout_attr); + raw_stdout_attr.c_iflag = saved_stdout_attr.c_iflag; + raw_stdout_attr.c_lflag = saved_stdout_attr.c_lflag; + tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr); + } + + r = process_pty_loop(master, mask, kill_pid, signo); + + if (saved_stdout) + tcsetattr(STDOUT_FILENO, TCSANOW, &saved_stdout_attr); + if (saved_stdin) + tcsetattr(STDIN_FILENO, TCSANOW, &saved_stdin_attr); + + /* STDIN/STDOUT should not be nonblocking normally, so let's + * unconditionally reset it */ + fd_nonblock(STDIN_FILENO, false); + fd_nonblock(STDOUT_FILENO, false); + + return r; + +} diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h new file mode 100644 index 0000000..8b65702 --- /dev/null +++ b/src/shared/ptyfwd.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo); diff --git a/src/shared/ratelimit.c b/src/shared/ratelimit.c new file mode 100644 index 0000000..01b62b7 --- /dev/null +++ b/src/shared/ratelimit.c @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "ratelimit.h" +#include "log.h" + +/* Modelled after Linux' lib/ratelimit.c by Dave Young + * , which is licensed GPLv2. */ + +bool ratelimit_test(RateLimit *r) { + usec_t ts; + + assert(r); + + if (r->interval <= 0 || r->burst <= 0) + return true; + + ts = now(CLOCK_MONOTONIC); + + if (r->begin <= 0 || + r->begin + r->interval < ts) { + r->begin = ts; + + /* Reset counter */ + r->num = 0; + goto good; + } + + if (r->num < r->burst) + goto good; + + return false; + +good: + r->num++; + return true; +} diff --git a/src/shared/ratelimit.h b/src/shared/ratelimit.h new file mode 100644 index 0000000..58efca7 --- /dev/null +++ b/src/shared/ratelimit.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +typedef struct RateLimit { + usec_t interval; + usec_t begin; + unsigned burst; + unsigned num; +} RateLimit; + +#define RATELIMIT_DEFINE(_name, _interval, _burst) \ + RateLimit _name = { \ + .interval = (_interval), \ + .burst = (_burst), \ + .num = 0, \ + .begin = 0 \ + } + +#define RATELIMIT_INIT(v, _interval, _burst) \ + do { \ + RateLimit *_r = &(v); \ + _r->interval = (_interval); \ + _r->burst = (_burst); \ + _r->num = 0; \ + _r->begin = 0; \ + } while (false) + +#define RATELIMIT_RESET(v) \ + do { \ + RateLimit *_r = &(v); \ + _r->num = 0; \ + _r->begin = 0; \ + } while (false) + +bool ratelimit_test(RateLimit *r); diff --git a/src/shared/refcnt.h b/src/shared/refcnt.h new file mode 100644 index 0000000..0502c20 --- /dev/null +++ b/src/shared/refcnt.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* A type-safe atomic refcounter */ + +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 }) diff --git a/src/shared/replace-var.c b/src/shared/replace-var.c new file mode 100644 index 0000000..478fc43 --- /dev/null +++ b/src/shared/replace-var.c @@ -0,0 +1,111 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" +#include "util.h" +#include "replace-var.h" +#include "def.h" + +/* + * Generic infrastructure for replacing @FOO@ style variables in + * strings. Will call a callback for each replacement. + */ + +static int get_variable(const char *b, char **r) { + size_t k; + char *t; + + assert(b); + assert(r); + + if (*b != '@') + return 0; + + k = strspn(b + 1, UPPERCASE_LETTERS "_"); + if (k <= 0 || b[k+1] != '@') + return 0; + + t = strndup(b + 1, k); + if (!t) + return -ENOMEM; + + *r = t; + return 1; +} + +char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata) { + char *r, *t; + const char *f; + size_t l; + + assert(text); + assert(lookup); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + _cleanup_free_ char *v = NULL, *n = NULL; + char *a; + int k; + size_t skip, d, nl; + + k = get_variable(f, &v); + if (k < 0) + goto oom; + if (k == 0) { + *(t++) = *(f++); + continue; + } + + n = lookup(v, userdata); + if (!n) + goto oom; + + skip = strlen(v) + 2; + + d = t - r; + nl = l - skip + strlen(n); + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, n); + f += skip; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} diff --git a/src/shared/replace-var.h b/src/shared/replace-var.h new file mode 100644 index 0000000..7eaee93 --- /dev/null +++ b/src/shared/replace-var.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c new file mode 100644 index 0000000..d73a749 --- /dev/null +++ b/src/shared/seccomp-util.c @@ -0,0 +1,89 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "seccomp-util.h" + +const char* seccomp_arch_to_string(uint32_t c) { + + if (c == SCMP_ARCH_NATIVE) + return "native"; + if (c == SCMP_ARCH_X86) + return "x86"; + if (c == SCMP_ARCH_X86_64) + return "x86-64"; + if (c == SCMP_ARCH_X32) + return "x32"; + if (c == SCMP_ARCH_ARM) + return "arm"; + + return NULL; +} + +int seccomp_arch_from_string(const char *n, uint32_t *ret) { + if (!n) + return -EINVAL; + + assert(ret); + + if (streq(n, "native")) + *ret = SCMP_ARCH_NATIVE; + else if (streq(n, "x86")) + *ret = SCMP_ARCH_X86; + else if (streq(n, "x86-64")) + *ret = SCMP_ARCH_X86_64; + else if (streq(n, "x32")) + *ret = SCMP_ARCH_X32; + else if (streq(n, "arm")) + *ret = SCMP_ARCH_ARM; + else + return -EINVAL; + + return 0; +} + +int seccomp_add_secondary_archs(scmp_filter_ctx *c) { + +#if defined(__i386__) || defined(__x86_64__) + int r; + + /* Add in all possible secondary archs we are aware of that + * this kernel might support. */ + + r = seccomp_arch_add(c, SCMP_ARCH_X86); + if (r < 0 && r != -EEXIST) + return r; + + r = seccomp_arch_add(c, SCMP_ARCH_X86_64); + if (r < 0 && r != -EEXIST) + return r; + + r = seccomp_arch_add(c, SCMP_ARCH_X32); + if (r < 0 && r != -EEXIST) + return r; + +#endif + + return 0; + +} diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h new file mode 100644 index 0000000..9a51a85 --- /dev/null +++ b/src/shared/seccomp-util.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + + +const char* seccomp_arch_to_string(uint32_t c); +int seccomp_arch_from_string(const char *n, uint32_t *ret); + +int seccomp_add_secondary_archs(scmp_filter_ctx *c); diff --git a/src/shared/securebits.h b/src/shared/securebits.h new file mode 100644 index 0000000..98fbe0d --- /dev/null +++ b/src/shared/securebits.h @@ -0,0 +1,45 @@ +#ifndef _LINUX_SECUREBITS_H +#define _LINUX_SECUREBITS_H 1 + +/* This is minimal version of Linux' linux/securebits.h header file, + * which is licensed GPL2 */ + +#define SECUREBITS_DEFAULT 0x00000000 + +/* When set UID 0 has no special privileges. When unset, we support + inheritance of root-permissions and suid-root executable under + compatibility mode. We raise the effective and inheritable bitmasks + *of the executable file* if the effective uid of the new process is + 0. If the real uid is 0, we raise the effective (legacy) bit of the + executable file. */ +#define SECURE_NOROOT 0 +#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ + +/* When set, setuid to/from uid 0 does not trigger capability-"fixup". + When unset, to provide compatibility with old programs relying on + set*uid to gain/lose privilege, transitions to/from uid 0 cause + capabilities to be gained/lost. */ +#define SECURE_NO_SETUID_FIXUP 2 +#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ + +/* When set, a process can retain its capabilities even after + transitioning to a non-root user (the set-uid fixup suppressed by + bit 2). Bit-4 is cleared when a process calls exec(); setting both + bit 4 and 5 will create a barrier through exec that no exec()'d + child can use this feature again. */ +#define SECURE_KEEP_CAPS 4 +#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ + +/* Each securesetting is implemented using two bits. One bit specifies + whether the setting is on or off. The other bit specify whether the + setting is locked or not. A setting which is locked cannot be + changed from user-level. */ +#define issecure_mask(X) (1 << (X)) +#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits)) + +#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ + issecure_mask(SECURE_NO_SETUID_FIXUP) | \ + issecure_mask(SECURE_KEEP_CAPS)) +#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) + +#endif /* !_LINUX_SECUREBITS_H */ diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c new file mode 100644 index 0000000..026ae5a --- /dev/null +++ b/src/shared/selinux-util.c @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "selinux-util.h" + +#ifdef HAVE_SELINUX + +#include + +static int use_selinux_cached = -1; + +bool use_selinux(void) { + + if (use_selinux_cached < 0) + use_selinux_cached = is_selinux_enabled() > 0; + + return use_selinux_cached; +} + +void retest_selinux(void) { + use_selinux_cached = -1; +} + +#else + +bool use_selinux(void) { + return false; +} + +void retest_selinux(void) { +} + +#endif diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h new file mode 100644 index 0000000..4b81202 --- /dev/null +++ b/src/shared/selinux-util.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +bool use_selinux(void); +void retest_selinux(void); diff --git a/src/shared/set.c b/src/shared/set.c new file mode 100644 index 0000000..5a4bf11 --- /dev/null +++ b/src/shared/set.c @@ -0,0 +1,140 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "set.h" +#include "hashmap.h" + +#define MAKE_SET(h) ((Set*) (h)) +#define MAKE_HASHMAP(s) ((Hashmap*) (s)) + +/* For now this is not much more than a wrapper around a hashmap */ + +Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { + return MAKE_SET(hashmap_new(hash_func, compare_func)); +} + +void set_free(Set* s) { + hashmap_free(MAKE_HASHMAP(s)); +} + +void set_free_free(Set *s) { + hashmap_free_free(MAKE_HASHMAP(s)); +} + +int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) { + return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func); +} + +int set_put(Set *s, void *value) { + return hashmap_put(MAKE_HASHMAP(s), value, value); +} + +int set_consume(Set *s, void *value) { + int r; + + r = set_put(s, value); + if (r < 0) + free(value); + + return r; +} + +int set_replace(Set *s, void *value) { + return hashmap_replace(MAKE_HASHMAP(s), value, value); +} + +void *set_get(Set *s, void *value) { + return hashmap_get(MAKE_HASHMAP(s), value); +} + +bool set_contains(Set *s, void *value) { + return hashmap_contains(MAKE_HASHMAP(s), value); +} + +void *set_remove(Set *s, void *value) { + return hashmap_remove(MAKE_HASHMAP(s), value); +} + +int set_remove_and_put(Set *s, void *old_value, void *new_value) { + return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value); +} + +unsigned set_size(Set *s) { + return hashmap_size(MAKE_HASHMAP(s)); +} + +bool set_isempty(Set *s) { + return hashmap_isempty(MAKE_HASHMAP(s)); +} + +void *set_iterate(Set *s, Iterator *i) { + return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); +} + +void *set_iterate_backwards(Set *s, Iterator *i) { + return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); +} + +void *set_iterate_skip(Set *s, void *value, Iterator *i) { + return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i); +} + +void *set_steal_first(Set *s) { + return hashmap_steal_first(MAKE_HASHMAP(s)); +} + +void* set_first(Set *s) { + return hashmap_first(MAKE_HASHMAP(s)); +} + +void* set_last(Set *s) { + return hashmap_last(MAKE_HASHMAP(s)); +} + +int set_merge(Set *s, Set *other) { + return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); +} + +void set_move(Set *s, Set *other) { + return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); +} + +int set_move_one(Set *s, Set *other, void *value) { + return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value); +} + +Set* set_copy(Set *s) { + return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s))); +} + +void set_clear(Set *s) { + hashmap_clear(MAKE_HASHMAP(s)); +} + +void set_clear_free(Set *s) { + hashmap_clear_free(MAKE_HASHMAP(s)); +} + +char **set_get_strv(Set *s) { + return hashmap_get_strv(MAKE_HASHMAP(s)); +} diff --git a/src/shared/set.h b/src/shared/set.h new file mode 100644 index 0000000..5612478 --- /dev/null +++ b/src/shared/set.h @@ -0,0 +1,79 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* Pretty straightforward set implementation. Internally based on the + * hashmap. That means that as a minor optimization a NULL set + * object will be treated as empty set for all read + * operations. That way it is not necessary to instantiate an object + * for each set use. */ + +#include "hashmap.h" +#include "util.h" + +typedef struct Set Set; + +Set *set_new(hash_func_t hash_func, compare_func_t compare_func); +void set_free(Set* s); +void set_free_free(Set *s); + +Set* set_copy(Set *s); +int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func); + +int set_put(Set *s, void *value); +int set_consume(Set *s, void *value); +int set_replace(Set *s, void *value); +void *set_get(Set *s, void *value); +bool set_contains(Set *s, void *value); +void *set_remove(Set *s, void *value); +int set_remove_and_put(Set *s, void *old_value, void *new_value); + +int set_merge(Set *s, Set *other); +void set_move(Set *s, Set *other); +int set_move_one(Set *s, Set *other, void *value); + +unsigned set_size(Set *s); +bool set_isempty(Set *s); + +void *set_iterate(Set *s, Iterator *i); +void *set_iterate_backwards(Set *s, Iterator *i); +void *set_iterate_skip(Set *s, void *value, Iterator *i); + +void set_clear(Set *s); +void set_clear_free(Set *s); + +void *set_steal_first(Set *s); +void* set_first(Set *s); +void* set_last(Set *s); + +char **set_get_strv(Set *s); + +#define SET_FOREACH(e, s, i) \ + for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) + +#define SET_FOREACH_BACKWARDS(e, s, i) \ + for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i))) + +DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); +#define _cleanup_set_free_ _cleanup_(set_freep) +#define _cleanup_set_free_free_ _cleanup_(set_free_freep) diff --git a/src/shared/siphash24.c b/src/shared/siphash24.c new file mode 100644 index 0000000..f68bd28 --- /dev/null +++ b/src/shared/siphash24.c @@ -0,0 +1,135 @@ +/* + SipHash reference C implementation + + Written in 2012 by + Jean-Philippe Aumasson + Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + + (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) +*/ +#include +#include +#include + +#include "siphash24.h" + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint8_t u8; + +#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) + +#define U32TO8_LE(p, v) \ + (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \ + (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (u32)((v) )); \ + U32TO8_LE((p) + 4, (u32)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ + v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ + v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ + v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ + } while(0) + +/* SipHash-2-4 */ +void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) +{ + /* "somepseudorandomlygeneratedbytes" */ + u64 v0 = 0x736f6d6570736575ULL; + u64 v1 = 0x646f72616e646f6dULL; + u64 v2 = 0x6c7967656e657261ULL; + u64 v3 = 0x7465646279746573ULL; + u64 b; + u64 k0 = U8TO64_LE( k ); + u64 k1 = U8TO64_LE( k + 8 ); + u64 m; + const u8 *in = _in; + const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); + const int left = inlen & 7; + b = ( ( u64 )inlen ) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + for ( ; in != end; in += 8 ) + { + m = U8TO64_LE( in ); +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); +#endif + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } + + switch( left ) + { + case 7: b |= ( ( u64 )in[ 6] ) << 48; + + case 6: b |= ( ( u64 )in[ 5] ) << 40; + + case 5: b |= ( ( u64 )in[ 4] ) << 32; + + case 4: b |= ( ( u64 )in[ 3] ) << 24; + + case 3: b |= ( ( u64 )in[ 2] ) << 16; + + case 2: b |= ( ( u64 )in[ 1] ) << 8; + + case 1: b |= ( ( u64 )in[ 0] ); break; + + case 0: break; + } + +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); +#endif + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; +#ifdef DEBUG + printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); + printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); + printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); + printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); +#endif + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE( out, b ); +} diff --git a/src/shared/siphash24.h b/src/shared/siphash24.h new file mode 100644 index 0000000..62e1168 --- /dev/null +++ b/src/shared/siphash24.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c new file mode 100644 index 0000000..cf1cd40 --- /dev/null +++ b/src/shared/sleep-config.c @@ -0,0 +1,267 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "conf-parser.h" +#include "sleep-config.h" +#include "fileio.h" +#include "log.h" +#include "strv.h" +#include "util.h" + +#define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) + +int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { + _cleanup_strv_free_ char + **suspend_mode = NULL, **suspend_state = NULL, + **hibernate_mode = NULL, **hibernate_state = NULL, + **hybrid_mode = NULL, **hybrid_state = NULL; + char **modes, **states; + + const ConfigTableItem items[] = { + { "Sleep", "SuspendMode", config_parse_strv, 0, &suspend_mode }, + { "Sleep", "SuspendState", config_parse_strv, 0, &suspend_state }, + { "Sleep", "HibernateMode", config_parse_strv, 0, &hibernate_mode }, + { "Sleep", "HibernateState", config_parse_strv, 0, &hibernate_state }, + { "Sleep", "HybridSleepMode", config_parse_strv, 0, &hybrid_mode }, + { "Sleep", "HybridSleepState", config_parse_strv, 0, &hybrid_state }, + {}}; + + int r; + FILE _cleanup_fclose_ *f; + + f = fopen(PKGSYSCONFDIR "/sleep.conf", "re"); + if (!f) + log_full(errno == ENOENT ? LOG_DEBUG: LOG_WARNING, + "Failed to open configuration file " PKGSYSCONFDIR "/sleep.conf: %m"); + else { + r = config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", f, "Sleep\0", + config_item_table_lookup, (void*) items, false, false, NULL); + if (r < 0) + log_warning("Failed to parse configuration file: %s", strerror(-r)); + } + + if (streq(verb, "suspend")) { + /* empty by default */ + USE(modes, suspend_mode); + + if (suspend_state) + USE(states, suspend_state); + else + states = strv_new("mem", "standby", "freeze", NULL); + + } else if (streq(verb, "hibernate")) { + if (hibernate_mode) + USE(modes, hibernate_mode); + else + modes = strv_new("platform", "shutdown", NULL); + + if (hibernate_state) + USE(states, hibernate_state); + else + states = strv_new("disk", NULL); + + } else if (streq(verb, "hybrid-sleep")) { + if (hybrid_mode) + USE(modes, hybrid_mode); + else + modes = strv_new("suspend", "platform", "shutdown", NULL); + + if (hybrid_state) + USE(states, hybrid_state); + else + states = strv_new("disk", NULL); + + } else + assert_not_reached("what verb"); + + if ((!modes && !streq(verb, "suspend")) || !states) { + strv_free(modes); + strv_free(states); + return log_oom(); + } + + *_modes = modes; + *_states = states; + return 0; +} + +int can_sleep_state(char **types) { + char *w, *state, **type; + int r; + _cleanup_free_ char *p = NULL; + + if (strv_isempty(types)) + return true; + + /* If /sys is read-only we cannot sleep */ + if (access("/sys/power/state", W_OK) < 0) + return false; + + r = read_one_line_file("/sys/power/state", &p); + if (r < 0) + return false; + + STRV_FOREACH(type, types) { + size_t l, k; + + k = strlen(*type); + FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) + if (l == k && memcmp(w, *type, l) == 0) + return true; + } + + return false; +} + +int can_sleep_disk(char **types) { + char *w, *state, **type; + int r; + _cleanup_free_ char *p = NULL; + + if (strv_isempty(types)) + return true; + + /* If /sys is read-only we cannot sleep */ + if (access("/sys/power/disk", W_OK) < 0) + return false; + + r = read_one_line_file("/sys/power/disk", &p); + if (r < 0) + return false; + + STRV_FOREACH(type, types) { + size_t l, k; + + k = strlen(*type); + FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) { + if (l == k && memcmp(w, *type, l) == 0) + return true; + + if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']') + return true; + } + } + + return false; +} + +#define HIBERNATION_SWAP_THRESHOLD 0.98 + +static int hibernation_partition_size(size_t *size, size_t *used) { + _cleanup_fclose_ FILE *f; + int i; + + assert(size); + assert(used); + + f = fopen("/proc/swaps", "re"); + if (!f) { + log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + "Failed to retrieve open /proc/swaps: %m"); + assert(errno > 0); + return -errno; + } + + (void) fscanf(f, "%*s %*s %*s %*s %*s\n"); + + for (i = 1;; i++) { + _cleanup_free_ char *dev = NULL, *type = NULL; + size_t size_field, used_field; + int k; + + k = fscanf(f, + "%ms " /* device/file */ + "%ms " /* type of swap */ + "%zd " /* swap size */ + "%zd " /* used */ + "%*i\n", /* priority */ + &dev, &type, &size_field, &used_field); + if (k != 4) { + if (k == EOF) + break; + + log_warning("Failed to parse /proc/swaps:%u", i); + continue; + } + + if (streq(type, "partition") && endswith(dev, "\\040(deleted)")) { + log_warning("Ignoring deleted swapfile '%s'.", dev); + continue; + } + + *size = size_field; + *used = used_field; + return 0; + } + + log_debug("No swap partitions were found."); + return -ENOSYS; +} + +static bool enough_memory_for_hibernation(void) { + _cleanup_free_ char *active = NULL; + unsigned long long act = 0; + size_t size = 0, used = 0; + int r; + + r = hibernation_partition_size(&size, &used); + if (r < 0) + return false; + + r = get_status_field("/proc/meminfo", "\nActive(anon):", &active); + if (r < 0) { + log_error("Failed to retrieve Active(anon) from /proc/meminfo: %s", strerror(-r)); + return false; + } + + r = safe_atollu(active, &act); + if (r < 0) { + log_error("Failed to parse Active(anon) from /proc/meminfo: %s: %s", + active, strerror(-r)); + return false; + } + + r = act <= (size - used) * HIBERNATION_SWAP_THRESHOLD; + log_debug("Hibernation is %spossible, Active(anon)=%llu kB, size=%zu kB, used=%zu kB, threshold=%.2g%%", + r ? "" : "im", act, size, used, 100*HIBERNATION_SWAP_THRESHOLD); + + return r; +} + +int can_sleep(const char *verb) { + _cleanup_strv_free_ char **modes = NULL, **states = NULL; + int r; + + assert(streq(verb, "suspend") || + streq(verb, "hibernate") || + streq(verb, "hybrid-sleep")); + + r = parse_sleep_config(verb, &modes, &states); + if (r < 0) + return false; + + if (!can_sleep_state(states) || !can_sleep_disk(modes)) + return false; + + return streq(verb, "suspend") || enough_memory_for_hibernation(); +} diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h new file mode 100644 index 0000000..51d2dec --- /dev/null +++ b/src/shared/sleep-config.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int parse_sleep_config(const char *verb, char ***modes, char ***states); + +int can_sleep(const char *verb); +int can_sleep_disk(char **types); +int can_sleep_state(char **types); diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c new file mode 100644 index 0000000..df194e0 --- /dev/null +++ b/src/shared/smack-util.c @@ -0,0 +1,91 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Intel Corporation + + Author: Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#ifdef HAVE_XATTR +#include +#endif + +#include "smack-util.h" + +bool use_smack(void) { +#ifdef HAVE_SMACK + static int use_smack_cached = -1; + + if (use_smack_cached < 0) + use_smack_cached = access("/sys/fs/smackfs/", F_OK) >= 0; + + return use_smack_cached; +#else + return false; +#endif + +} + +int smack_label_path(const char *path, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + if (label) + return setxattr(path, "security.SMACK64", label, strlen(label), 0); + else + return lremovexattr(path, "security.SMACK64"); +#else + return 0; +#endif +} + +int smack_label_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64", label, strlen(label), 0); +#else + return 0; +#endif +} + +int smack_label_ip_out_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64IPOUT", label, strlen(label), 0); +#else + return 0; +#endif +} + +int smack_label_ip_in_fd(int fd, const char *label) { +#ifdef HAVE_SMACK + if (!use_smack()) + return 0; + + return fsetxattr(fd, "security.SMACK64IPIN", label, strlen(label), 0); +#else + return 0; +#endif +} diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h new file mode 100644 index 0000000..7370ae3 --- /dev/null +++ b/src/shared/smack-util.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Intel Corporation + + Author: Auke Kok + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#define SMACK_FLOOR_LABEL "_" +#define SMACK_STAR_LABEL "*" + +bool use_smack(void); + +int smack_label_path(const char *path, const char *label); +int smack_label_fd(int fd, const char *label); +int smack_label_ip_in_fd(int fd, const char *label); +int smack_label_ip_out_fd(int fd, const char *label); diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c new file mode 100644 index 0000000..c8be17a --- /dev/null +++ b/src/shared/socket-label.c @@ -0,0 +1,145 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "mkdir.h" +#include "socket-util.h" +#include "missing.h" +#include "label.h" + +int socket_address_listen( + const SocketAddress *a, + int flags, + int backlog, + SocketAddressBindIPv6Only only, + const char *bind_to_device, + bool free_bind, + bool transparent, + mode_t directory_mode, + mode_t socket_mode, + const char *label) { + + _cleanup_close_ int fd = -1; + int r, one; + + assert(a); + + r = socket_address_verify(a); + if (r < 0) + return r; + + if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported()) + return -EAFNOSUPPORT; + + if (label) { + r = label_socket_set(label); + if (r < 0) + return r; + } + + fd = socket(socket_address_family(a), a->type | flags, a->protocol); + r = fd < 0 ? -errno : 0; + + if (label) + label_socket_clear(); + + if (r < 0) + return r; + + if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { + int flag = only == SOCKET_ADDRESS_IPV6_ONLY; + + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) + return -errno; + } + + if (socket_address_family(a) == AF_INET || socket_address_family(a) == 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 (free_bind) { + one = 1; + if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) + log_warning("IP_FREEBIND failed: %m"); + } + + if (transparent) { + one = 1; + if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) + log_warning("IP_TRANSPARENT failed: %m"); + } + } + + one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) + return -errno; + + if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { + mode_t old_mask; + + /* Create parents */ + mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); + + /* Enforce the right access mode for the socket */ + old_mask = umask(~ socket_mode); + + /* Include the original umask in our mask */ + umask(~socket_mode | old_mask); + + r = label_bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0 && errno == EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + r = bind(fd, &a->sockaddr.sa, a->size); + } + + umask(old_mask); + } else + r = bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0) + return -errno; + + if (socket_address_can_accept(a)) + if (listen(fd, backlog) < 0) + return -errno; + + r = fd; + fd = -1; + + return r; +} diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c new file mode 100644 index 0000000..5ef2e22 --- /dev/null +++ b/src/shared/socket-util.c @@ -0,0 +1,656 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" +#include "mkdir.h" +#include "path-util.h" +#include "socket-util.h" +#include "missing.h" +#include "fileio.h" + +int socket_address_parse(SocketAddress *a, const char *s) { + char *e, *n; + unsigned u; + int r; + + assert(a); + assert(s); + + zero(*a); + a->type = SOCK_STREAM; + + if (*s == '[') { + /* IPv6 in [x:.....:z]:p notation */ + + if (!socket_ipv6_is_supported()) { + log_warning("Binding to IPv6 address not available since kernel does not support IPv6."); + return -EAFNOSUPPORT; + } + + e = strchr(s+1, ']'); + if (!e) + return -EINVAL; + + n = strndupa(s+1, e-s-1); + + errno = 0; + if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) + return errno > 0 ? -errno : -EINVAL; + + e++; + if (*e != ':') + return -EINVAL; + + e++; + r = safe_atou(e, &u); + if (r < 0) + return r; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + a->sockaddr.in6.sin6_family = AF_INET6; + a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->size = sizeof(struct sockaddr_in6); + + } else if (*s == '/') { + /* AF_UNIX socket */ + + size_t l; + + l = strlen(s); + if (l >= sizeof(a->sockaddr.un.sun_path)) + return -EINVAL; + + a->sockaddr.un.sun_family = AF_UNIX; + memcpy(a->sockaddr.un.sun_path, s, l); + a->size = offsetof(struct sockaddr_un, sun_path) + l + 1; + + } else if (*s == '@') { + /* Abstract AF_UNIX socket */ + size_t l; + + l = strlen(s+1); + if (l >= sizeof(a->sockaddr.un.sun_path) - 1) + return -EINVAL; + + a->sockaddr.un.sun_family = AF_UNIX; + memcpy(a->sockaddr.un.sun_path+1, s+1, l); + a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l; + + } else { + e = strchr(s, ':'); + if (e) { + r = safe_atou(e+1, &u); + if (r < 0) + return r; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + n = strndupa(s, e-s); + + /* IPv4 in w.x.y.z:p notation? */ + r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr); + if (r < 0) + return -errno; + + if (r > 0) { + /* Gotcha, it's a traditional IPv4 address */ + a->sockaddr.in.sin_family = AF_INET; + a->sockaddr.in.sin_port = htons((uint16_t) u); + a->size = sizeof(struct sockaddr_in); + } else { + unsigned idx; + + if (strlen(n) > IF_NAMESIZE-1) + return -EINVAL; + + /* Uh, our last resort, an interface name */ + idx = if_nametoindex(n); + if (idx == 0) + return -EINVAL; + + if (!socket_ipv6_is_supported()) { + log_warning("Binding to interface is not available since kernel does not support IPv6."); + return -EAFNOSUPPORT; + } + + a->sockaddr.in6.sin6_family = AF_INET6; + a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_scope_id = idx; + a->sockaddr.in6.sin6_addr = in6addr_any; + a->size = sizeof(struct sockaddr_in6); + } + } else { + + /* Just a port */ + r = safe_atou(s, &u); + if (r < 0) + return r; + + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + + if (socket_ipv6_is_supported()) { + a->sockaddr.in6.sin6_family = AF_INET6; + a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_addr = in6addr_any; + a->size = sizeof(struct sockaddr_in6); + } else { + a->sockaddr.in.sin_family = AF_INET; + a->sockaddr.in.sin_port = htons((uint16_t) u); + a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; + a->size = sizeof(struct sockaddr_in); + } + } + } + + return 0; +} + +int socket_address_parse_netlink(SocketAddress *a, const char *s) { + int family; + unsigned group = 0; + _cleanup_free_ char *sfamily = NULL; + 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; + + family = netlink_family_from_string(sfamily); + if (family < 0) + return -EINVAL; + + a->sockaddr.nl.nl_family = AF_NETLINK; + a->sockaddr.nl.nl_groups = group; + + a->type = SOCK_RAW; + a->size = sizeof(struct sockaddr_nl); + a->protocol = family; + + return 0; +} + +int socket_address_verify(const SocketAddress *a) { + assert(a); + + switch (socket_address_family(a)) { + + case AF_INET: + if (a->size != sizeof(struct sockaddr_in)) + return -EINVAL; + + if (a->sockaddr.in.sin_port == 0) + return -EINVAL; + + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; + + return 0; + + case AF_INET6: + if (a->size != sizeof(struct sockaddr_in6)) + return -EINVAL; + + if (a->sockaddr.in6.sin6_port == 0) + return -EINVAL; + + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; + + return 0; + + case AF_UNIX: + if (a->size < offsetof(struct sockaddr_un, sun_path)) + return -EINVAL; + + if (a->size > offsetof(struct sockaddr_un, sun_path)) { + + if (a->sockaddr.un.sun_path[0] != 0) { + char *e; + + /* path */ + e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path)); + if (!e) + return -EINVAL; + + if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) + return -EINVAL; + } + } + + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET) + return -EINVAL; + + return 0; + + case AF_NETLINK: + + if (a->size != sizeof(struct sockaddr_nl)) + return -EINVAL; + + if (a->type != SOCK_RAW && a->type != SOCK_DGRAM) + return -EINVAL; + + return 0; + + default: + return -EAFNOSUPPORT; + } +} + +int socket_address_print(const SocketAddress *a, char **ret) { + int r; + + assert(a); + assert(ret); + + r = socket_address_verify(a); + if (r < 0) + return r; + + if (socket_address_family(a) == AF_NETLINK) { + _cleanup_free_ char *sfamily = NULL; + + r = netlink_family_to_string_alloc(a->protocol, &sfamily); + if (r < 0) + return r; + + r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups); + if (r < 0) + return -ENOMEM; + + return 0; + } + + return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret); +} + +bool socket_address_can_accept(const SocketAddress *a) { + assert(a); + + return + a->type == SOCK_STREAM || + a->type == SOCK_SEQPACKET; +} + +bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + assert(a); + assert(b); + + /* Invalid addresses are unequal to all */ + if (socket_address_verify(a) < 0 || + socket_address_verify(b) < 0) + return false; + + if (a->type != b->type) + return false; + + if (a->size != b->size) + return false; + + if (socket_address_family(a) != socket_address_family(b)) + return false; + + switch (socket_address_family(a)) { + + case AF_INET: + if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr) + return false; + + if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port) + return false; + + break; + + case AF_INET6: + if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0) + return false; + + if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port) + return false; + + break; + + case AF_UNIX: + + if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) + return false; + + if (a->sockaddr.un.sun_path[0]) { + if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path))) + return false; + } else { + if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0) + return false; + } + + break; + + case AF_NETLINK: + + if (a->protocol != b->protocol) + return false; + + if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups) + return false; + + break; + + default: + /* Cannot compare, so we assume the addresses are different */ + return false; + } + + return true; +} + +bool socket_address_is(const SocketAddress *a, const char *s, int type) { + struct SocketAddress b; + + assert(a); + assert(s); + + if (socket_address_parse(&b, s) < 0) + return false; + + b.type = type; + + return socket_address_equal(a, &b); +} + +bool socket_address_is_netlink(const SocketAddress *a, const char *s) { + struct SocketAddress b; + + assert(a); + assert(s); + + if (socket_address_parse_netlink(&b, s) < 0) + return false; + + return socket_address_equal(a, &b); +} + +const char* socket_address_get_path(const SocketAddress *a) { + assert(a); + + if (socket_address_family(a) != AF_UNIX) + return NULL; + + if (a->sockaddr.un.sun_path[0] == 0) + return NULL; + + return a->sockaddr.un.sun_path; +} + +bool socket_ipv6_is_supported(void) { + _cleanup_free_ char *l = NULL; + + if (access("/sys/module/ipv6", F_OK) != 0) + return 0; + + /* If we can't check "disable" parameter, assume enabled */ + if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0) + return 1; + + /* If module was loaded with disable=1 no IPv6 available */ + return l[0] == '0'; +} + +bool socket_address_matches_fd(const SocketAddress *a, int fd) { + union sockaddr_union sa; + socklen_t salen = sizeof(sa), solen; + int protocol, type; + + assert(a); + assert(fd >= 0); + + if (getsockname(fd, &sa.sa, &salen) < 0) + return false; + + if (sa.sa.sa_family != a->sockaddr.sa.sa_family) + return false; + + solen = sizeof(type); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0) + return false; + + if (type != a->type) + return false; + + if (a->protocol != 0) { + solen = sizeof(protocol); + if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0) + return false; + + if (protocol != a->protocol) + return false; + } + + switch (sa.sa.sa_family) { + + case AF_INET: + return sa.in.sin_port == a->sockaddr.in.sin_port && + sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr; + + case AF_INET6: + return sa.in6.sin6_port == a->sockaddr.in6.sin6_port && + memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0; + + case AF_UNIX: + return salen == a->size && + memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0; + + } + + return false; +} + +int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) { + union sockaddr_union *sa = (union sockaddr_union*) _sa; + char *p; + + assert(sa); + assert(salen >= sizeof(sa->sa.sa_family)); + + switch (sa->sa.sa_family) { + + case AF_INET: { + uint32_t a; + + a = ntohl(sa->in.sin_addr.s_addr); + + if (asprintf(&p, + "%u.%u.%u.%u:%u", + a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, + ntohs(sa->in.sin_port)) < 0) + return -ENOMEM; + + break; + } + + case AF_INET6: { + static const unsigned char ipv4_prefix[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF + }; + + if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) { + const uint8_t *a = sa->in6.sin6_addr.s6_addr+12; + + if (asprintf(&p, + "%u.%u.%u.%u:%u", + a[0], a[1], a[2], a[3], + ntohs(sa->in6.sin6_port)) < 0) + return -ENOMEM; + } else { + char a[INET6_ADDRSTRLEN]; + + if (asprintf(&p, + "[%s]:%u", + inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)), + ntohs(sa->in6.sin6_port)) < 0) + return -ENOMEM; + } + + break; + } + + case AF_UNIX: + if (salen <= offsetof(struct sockaddr_un, sun_path)) { + p = strdup(""); + if (!p) + return -ENOMEM; + + } else if (sa->un.sun_path[0] == 0) { + /* abstract */ + + /* FIXME: We assume we can print the + * socket path here and that it hasn't + * more than one NUL byte. That is + * actually an invalid assumption */ + + p = new(char, sizeof(sa->un.sun_path)+1); + if (!p) + return -ENOMEM; + + p[0] = '@'; + memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1); + p[sizeof(sa->un.sun_path)] = 0; + + } else { + p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path)); + if (!ret) + return -ENOMEM; + } + + break; + + default: + return -ENOTSUP; + } + + + *ret = p; + return 0; +} + +int getpeername_pretty(int fd, char **ret) { + union sockaddr_union sa; + socklen_t salen; + int r; + + assert(fd >= 0); + assert(ret); + + salen = sizeof(sa); + if (getpeername(fd, &sa.sa, &salen) < 0) + return -errno; + + if (sa.sa.sa_family == AF_UNIX) { + struct ucred ucred = {}; + + /* UNIX connection sockets are anonymous, so let's use + * PID/UID as pretty credentials instead */ + + r = getpeercred(fd, &ucred); + if (r < 0) + return r; + + if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.uid) < 0) + return -ENOMEM; + + return 0; + } + + /* For remote sockets we translate IPv6 addresses back to IPv4 + * if applicable, since that's nicer. */ + + return sockaddr_pretty(&sa.sa, salen, true, ret); +} + +int getsockname_pretty(int fd, char **ret) { + union sockaddr_union sa; + socklen_t salen; + + assert(fd >= 0); + assert(ret); + + salen = sizeof(sa); + if (getsockname(fd, &sa.sa, &salen) < 0) + return -errno; + + /* For local sockets we do not translate IPv6 addresses back + * to IPv6 if applicable, since this is usually used for + * listening sockets where the difference between IPv4 and + * IPv6 matters. */ + + return sockaddr_pretty(&sa.sa, salen, false, ret); +} + +static const char* const netlink_family_table[] = { + [NETLINK_ROUTE] = "route", + [NETLINK_FIREWALL] = "firewall", + [NETLINK_INET_DIAG] = "inet-diag", + [NETLINK_NFLOG] = "nflog", + [NETLINK_XFRM] = "xfrm", + [NETLINK_SELINUX] = "selinux", + [NETLINK_ISCSI] = "iscsi", + [NETLINK_AUDIT] = "audit", + [NETLINK_FIB_LOOKUP] = "fib-lookup", + [NETLINK_CONNECTOR] = "connector", + [NETLINK_NETFILTER] = "netfilter", + [NETLINK_IP6_FW] = "ip6-fw", + [NETLINK_DNRTMSG] = "dnrtmsg", + [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", + [NETLINK_GENERIC] = "generic", + [NETLINK_SCSITRANSPORT] = "scsitransport", + [NETLINK_ECRYPTFS] = "ecryptfs" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX); + +static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = { + [SOCKET_ADDRESS_DEFAULT] = "default", + [SOCKET_ADDRESS_BOTH] = "both", + [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h new file mode 100644 index 0000000..84ebc30 --- /dev/null +++ b/src/shared/socket-util.h @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_nl nl; + struct sockaddr_storage storage; + struct sockaddr_ll ll; +}; + +typedef struct SocketAddress { + union sockaddr_union sockaddr; + + /* We store the size here explicitly due to the weird + * sockaddr_un semantics for abstract sockets */ + socklen_t size; + + /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ + int type; + + /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ + int protocol; +} SocketAddress; + +typedef enum SocketAddressBindIPv6Only { + SOCKET_ADDRESS_DEFAULT, + SOCKET_ADDRESS_BOTH, + SOCKET_ADDRESS_IPV6_ONLY, + _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, + _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 +} SocketAddressBindIPv6Only; + +#define socket_address_family(a) ((a)->sockaddr.sa.sa_family) + +int socket_address_parse(SocketAddress *a, const char *s); +int socket_address_parse_netlink(SocketAddress *a, const char *s); +int socket_address_print(const SocketAddress *a, char **p); +int socket_address_verify(const SocketAddress *a) _pure_; + +bool socket_address_can_accept(const SocketAddress *a) _pure_; + +int socket_address_listen( + const SocketAddress *a, + int flags, + int backlog, + SocketAddressBindIPv6Only only, + const char *bind_to_device, + bool free_bind, + bool transparent, + mode_t directory_mode, + mode_t socket_mode, + const char *label); + +bool socket_address_is(const SocketAddress *a, const char *s, int type); +bool socket_address_is_netlink(const SocketAddress *a, const char *s); + +bool socket_address_matches_fd(const SocketAddress *a, int fd); + +bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_; + +const char* socket_address_get_path(const SocketAddress *a); + +bool socket_ipv6_is_supported(void); + +int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret); +int getpeername_pretty(int fd, char **ret); +int getsockname_pretty(int fd, char **ret); + +const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; + +int netlink_family_to_string_alloc(int b, char **s); +int netlink_family_from_string(const char *s) _pure_; diff --git a/src/shared/sparse-endian.h b/src/shared/sparse-endian.h new file mode 100644 index 0000000..eb4dbf3 --- /dev/null +++ b/src/shared/sparse-endian.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2012 Josh Triplett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef SPARSE_ENDIAN_H +#define SPARSE_ENDIAN_H + +#include +#include + +#ifdef __CHECKER__ +#define __bitwise __attribute__((bitwise)) +#define __force __attribute__((force)) +#else +#define __bitwise +#define __force +#endif + +typedef uint16_t __bitwise le16_t; +typedef uint16_t __bitwise be16_t; +typedef uint32_t __bitwise le32_t; +typedef uint32_t __bitwise be32_t; +typedef uint64_t __bitwise le64_t; +typedef uint64_t __bitwise be64_t; + +#undef htobe16 +#undef htole16 +#undef be16toh +#undef le16toh +#undef htobe32 +#undef htole32 +#undef be32toh +#undef le32toh +#undef htobe64 +#undef htole64 +#undef be64toh +#undef le64toh + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define bswap_16_on_le(x) __bswap_16(x) +#define bswap_32_on_le(x) __bswap_32(x) +#define bswap_64_on_le(x) __bswap_64(x) +#define bswap_16_on_be(x) (x) +#define bswap_32_on_be(x) (x) +#define bswap_64_on_be(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define bswap_16_on_le(x) (x) +#define bswap_32_on_le(x) (x) +#define bswap_64_on_le(x) (x) +#define bswap_16_on_be(x) __bswap_16(x) +#define bswap_32_on_be(x) __bswap_32(x) +#define bswap_64_on_be(x) __bswap_64(x) +#endif + +static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } +static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } +static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } + +static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } +static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } +static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } + +static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } +static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } +static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } + +static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } +static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } +static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } + +#endif /* SPARSE_ENDIAN_H */ diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c new file mode 100644 index 0000000..c1a9c58 --- /dev/null +++ b/src/shared/spawn-ask-password-agent.c @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "spawn-ask-password-agent.h" + +static pid_t agent_pid = 0; + +int ask_password_agent_open(void) { + int r; + + if (agent_pid > 0) + return 0; + + /* We check STDIN here, not STDOUT, since this is about input, + * not output */ + if (!isatty(STDIN_FILENO)) + return 0; + + r = fork_agent(&agent_pid, + NULL, 0, + SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, + SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL); + if (r < 0) + log_error("Failed to fork TTY ask password agent: %s", strerror(-r)); + + return r; +} + +void ask_password_agent_close(void) { + + if (agent_pid <= 0) + return; + + /* Inform agent that we are done */ + kill(agent_pid, SIGTERM); + kill(agent_pid, SIGCONT); + wait_for_terminate(agent_pid, NULL); + agent_pid = 0; +} diff --git a/src/shared/spawn-ask-password-agent.h b/src/shared/spawn-ask-password-agent.h new file mode 100644 index 0000000..31b4bea --- /dev/null +++ b/src/shared/spawn-ask-password-agent.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int ask_password_agent_open(void); +void ask_password_agent_close(void); diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c new file mode 100644 index 0000000..f9e52cd --- /dev/null +++ b/src/shared/spawn-polkit-agent.c @@ -0,0 +1,98 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "spawn-polkit-agent.h" + +#ifdef ENABLE_POLKIT +static pid_t agent_pid = 0; + +int polkit_agent_open(void) { + int r; + int pipe_fd[2]; + char notify_fd[10 + 1]; + + if (agent_pid > 0) + return 0; + + /* We check STDIN here, not STDOUT, since this is about input, + * not output */ + if (!isatty(STDIN_FILENO)) + return 0; + + if (pipe2(pipe_fd, 0) < 0) + return -errno; + + snprintf(notify_fd, sizeof(notify_fd), "%i", pipe_fd[1]); + char_array_0(notify_fd); + + r = fork_agent(&agent_pid, + &pipe_fd[1], 1, + POLKIT_AGENT_BINARY_PATH, + POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, "--fallback", NULL); + + /* Close the writing side, because that's the one for the agent */ + close_nointr_nofail(pipe_fd[1]); + + if (r < 0) + log_error("Failed to fork TTY ask password agent: %s", strerror(-r)); + else + /* Wait until the agent closes the fd */ + fd_wait_for_event(pipe_fd[0], POLLHUP, (usec_t) -1); + + close_nointr_nofail(pipe_fd[0]); + + return r; +} + +void polkit_agent_close(void) { + + if (agent_pid <= 0) + return; + + /* Inform agent that we are done */ + kill(agent_pid, SIGTERM); + kill(agent_pid, SIGCONT); + wait_for_terminate(agent_pid, NULL); + agent_pid = 0; +} + +#else + +int polkit_agent_open(void) { + return 0; +} + +void polkit_agent_close(void) { +} + +#endif diff --git a/src/shared/spawn-polkit-agent.h b/src/shared/spawn-polkit-agent.h new file mode 100644 index 0000000..c3bc1b8 --- /dev/null +++ b/src/shared/spawn-polkit-agent.h @@ -0,0 +1,25 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int polkit_agent_open(void); +void polkit_agent_close(void); diff --git a/src/shared/special.h b/src/shared/special.h new file mode 100644 index 0000000..2fe5db5 --- /dev/null +++ b/src/shared/special.h @@ -0,0 +1,122 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#define SPECIAL_DEFAULT_TARGET "default.target" + +/* Shutdown targets */ +#define SPECIAL_UMOUNT_TARGET "umount.target" +/* This is not really intended to be started by directly. This is + * mostly so that other targets (reboot/halt/poweroff) can depend on + * it to bring all services down that want to be brought down on + * system shutdown. */ +#define SPECIAL_SHUTDOWN_TARGET "shutdown.target" +#define SPECIAL_HALT_TARGET "halt.target" +#define SPECIAL_POWEROFF_TARGET "poweroff.target" +#define SPECIAL_REBOOT_TARGET "reboot.target" +#define SPECIAL_KEXEC_TARGET "kexec.target" +#define SPECIAL_EXIT_TARGET "exit.target" +#define SPECIAL_SUSPEND_TARGET "suspend.target" +#define SPECIAL_HIBERNATE_TARGET "hibernate.target" +#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target" + +/* Special boot targets */ +#define SPECIAL_RESCUE_TARGET "rescue.target" +#define SPECIAL_EMERGENCY_TARGET "emergency.target" + +/* Early boot targets */ +#define SPECIAL_SYSINIT_TARGET "sysinit.target" +#define SPECIAL_SOCKETS_TARGET "sockets.target" +#define SPECIAL_BUSNAMES_TARGET "busnames.target" +#define SPECIAL_TIMERS_TARGET "timers.target" +#define SPECIAL_PATHS_TARGET "paths.target" +#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" +#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target" +#define SPECIAL_INITRD_FS_TARGET "initrd-fs.target" +#define SPECIAL_INITRD_ROOT_FS_TARGET "initrd-root-fs.target" +#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */ +#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target" +#define SPECIAL_SWAP_TARGET "swap.target" +#define SPECIAL_NETWORK_ONLINE_TARGET "network-online.target" +#define SPECIAL_BASIC_TARGET "basic.target" + +/* LSB compatibility */ +#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */ +#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target" /* LSB's $named */ +#define SPECIAL_RPCBIND_TARGET "rpcbind.target" /* LSB's $portmap */ +#define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */ + +/* + * Rules regarding adding further high level targets like the above: + * + * - Be conservative, only add more of these when we really need + * them. We need strong usecases for further additions. + * + * - When there can be multiple implementations running side-by-side, + * it needs to be a .target unit which can pull in all + * implementations. + * + * - If something can be implemented with socket activation, and + * without, it needs to be a .target unit, so that it can pull in + * the appropriate unit. + * + * - Otherwise, it should be a .service unit. + * + * - In some cases it is OK to have both a .service and a .target + * unit, i.e. if there can be multiple parallel implementations, but + * only one is the "system" one. Example: syslog. + * + * Or to put this in other words: .service symlinks can be used to + * arbitrate between multiple implementations if there can be only one + * of a kind. .target units can be used to support multiple + * implementations that can run side-by-side. + */ + +/* Magic early boot services */ +#define SPECIAL_FSCK_SERVICE "systemd-fsck@.service" +#define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck.service" +#define SPECIAL_QUOTAON_SERVICE "quotaon.service" +#define SPECIAL_REMOUNT_FS_SERVICE "systemd-remount-fs.service" + +/* Services systemd relies on */ +#define SPECIAL_DBUS_SERVICE "dbus.service" +#define SPECIAL_DBUS_SOCKET "dbus.socket" +#define SPECIAL_JOURNALD_SOCKET "systemd-journald.socket" +#define SPECIAL_JOURNALD_SERVICE "systemd-journald.service" + +/* Magic init signals */ +#define SPECIAL_KBREQUEST_TARGET "kbrequest.target" +#define SPECIAL_SIGPWR_TARGET "sigpwr.target" +#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target" + +/* For SysV compatibility. Usually an alias for a saner target. On + * SysV-free systems this doesn't exist. */ +#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target" +#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target" +#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target" +#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target" + +/* Where we add all our system units, users and machines by default */ +#define SPECIAL_SYSTEM_SLICE "system.slice" +#define SPECIAL_USER_SLICE "user.slice" +#define SPECIAL_MACHINE_SLICE "machine.slice" +#define SPECIAL_ROOT_SLICE "-.slice" diff --git a/src/shared/specifier.c b/src/shared/specifier.c new file mode 100644 index 0000000..8fbf6db --- /dev/null +++ b/src/shared/specifier.c @@ -0,0 +1,182 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "macro.h" +#include "util.h" +#include "specifier.h" + +/* + * Generic infrastructure for replacing %x style specifiers in + * strings. Will call a callback for each replacement. + * + */ + +int specifier_printf(const char *text, const Specifier table[], void *userdata, char **_ret) { + char *ret, *t; + const char *f; + bool percent = false; + size_t l; + int r; + + assert(text); + assert(table); + + l = strlen(text); + ret = new(char, l+1); + if (!ret) + return -ENOMEM; + + t = ret; + + for (f = text; *f; f++, l--) { + + if (percent) { + if (*f == '%') + *(t++) = '%'; + else { + const Specifier *i; + + for (i = table; i->specifier; i++) + if (i->specifier == *f) + break; + + if (i->lookup) { + _cleanup_free_ char *w = NULL; + char *n; + size_t k, j; + + r = i->lookup(i->specifier, i->data, userdata, &w); + if (r < 0) { + free(ret); + return r; + } + + j = t - ret; + k = strlen(w); + + n = new(char, j + k + l + 1); + if (!n) { + free(ret); + return -ENOMEM; + } + + memcpy(n, ret, j); + memcpy(n + j, w, k); + + free(ret); + + ret = n; + t = n + j + k; + } else { + *(t++) = '%'; + *(t++) = *f; + } + } + + percent = false; + } else if (*f == '%') + percent = true; + else + *(t++) = *f; + } + + *t = 0; + *_ret = ret; + return 0; +} + +/* Generic handler for simple string replacements */ + +int specifier_string(char specifier, void *data, void *userdata, char **ret) { + char *n; + + n = strdup(strempty(data)); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int specifier_machine_id(char specifier, void *data, void *userdata, char **ret) { + sd_id128_t id; + char *n; + int r; + + r = sd_id128_get_machine(&id); + if (r < 0) + return r; + + n = new(char, 33); + if (!n) + return -ENOMEM; + + *ret = sd_id128_to_string(id, n); + return 0; +} + +int specifier_boot_id(char specifier, void *data, void *userdata, char **ret) { + sd_id128_t id; + char *n; + int r; + + r = sd_id128_get_boot(&id); + if (r < 0) + return r; + + n = new(char, 33); + if (!n) + return -ENOMEM; + + *ret = sd_id128_to_string(id, n); + return 0; +} + +int specifier_host_name(char specifier, void *data, void *userdata, char **ret) { + char *n; + + n = gethostname_malloc(); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} + +int specifier_kernel_release(char specifier, void *data, void *userdata, char **ret) { + struct utsname uts; + char *n; + int r; + + r = uname(&uts); + if (r < 0) + return -errno; + + n = strdup(uts.release); + if (!n) + return -ENOMEM; + + *ret = n; + return 0; +} diff --git a/src/shared/specifier.h b/src/shared/specifier.h new file mode 100644 index 0000000..fca206f --- /dev/null +++ b/src/shared/specifier.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +typedef int (*SpecifierCallback)(char specifier, void *data, void *userdata, char **ret); + +typedef struct Specifier { + const char specifier; + const SpecifierCallback lookup; + void *data; +} Specifier; + +int specifier_printf(const char *text, const Specifier table[], void *userdata, char **ret); + +int specifier_string(char specifier, void *data, void *userdata, char **ret); + +int specifier_machine_id(char specifier, void *data, void *userdata, char **ret); +int specifier_boot_id(char specifier, void *data, void *userdata, char **ret); +int specifier_host_name(char specifier, void *data, void *userdata, char **ret); +int specifier_kernel_release(char specifier, void *data, void *userdata, char **ret); diff --git a/src/shared/strbuf.c b/src/shared/strbuf.c new file mode 100644 index 0000000..01a076c --- /dev/null +++ b/src/shared/strbuf.c @@ -0,0 +1,201 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "strbuf.h" + +/* + * Strbuf stores given strings in a single continuous allocated memory + * area. Identical strings are de-duplicated and return the same offset + * as the first string stored. If the tail of a string already exists + * in the buffer, the tail is returned. + * + * A trie (http://en.wikipedia.org/wiki/Trie) is used to maintain the + * information about the stored strings. + * + * Example of udev rules: + * $ ./udevadm test . + * ... + * read rules file: /usr/lib/udev/rules.d/99-systemd.rules + * rules contain 196608 bytes tokens (16384 * 12 bytes), 39742 bytes strings + * 23939 strings (207859 bytes), 20404 de-duplicated (171653 bytes), 3536 trie nodes used + * ... + */ + +struct strbuf *strbuf_new(void) { + struct strbuf *str; + + str = new0(struct strbuf, 1); + if (!str) + return NULL; + + str->buf = new0(char, 1); + if (!str->buf) + goto err; + str->len = 1; + + str->root = new0(struct strbuf_node, 1); + if (!str->root) + goto err; + str->nodes_count = 1; + return str; +err: + free(str->buf); + free(str->root); + free(str); + return NULL; +} + +static void strbuf_node_cleanup(struct strbuf_node *node) { + size_t i; + + for (i = 0; i < node->children_count; i++) + strbuf_node_cleanup(node->children[i].child); + free(node->children); + free(node); +} + +/* clean up trie data, leave only the string buffer */ +void strbuf_complete(struct strbuf *str) { + if (!str) + return; + if (str->root) + strbuf_node_cleanup(str->root); + str->root = NULL; +} + +/* clean up everything */ +void strbuf_cleanup(struct strbuf *str) { + if (!str) + return; + if (str->root) + strbuf_node_cleanup(str->root); + free(str->buf); + free(str); +} + +static int strbuf_children_cmp(const struct strbuf_child_entry *n1, + const struct strbuf_child_entry *n2) { + return n1->c - n2->c; +} + +static void bubbleinsert(struct strbuf_node *node, + uint8_t c, + struct strbuf_node *node_child) { + + struct strbuf_child_entry new = { + .c = c, + .child = node_child, + }; + int left = 0, right = node->children_count; + + while (right > left) { + int middle = (right + left) / 2 ; + if (strbuf_children_cmp(&node->children[middle], &new) <= 0) + left = middle + 1; + else + right = middle; + } + + memmove(node->children + left + 1, node->children + left, + sizeof(struct strbuf_child_entry) * (node->children_count - left)); + node->children[left] = new; + + node->children_count ++; +} + +/* add string, return the index/offset into the buffer */ +ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { + uint8_t c; + struct strbuf_node *node; + size_t depth; + char *buf_new; + struct strbuf_child_entry *child; + struct strbuf_node *node_child; + ssize_t off; + + if (!str->root) + return -EINVAL; + + /* search string; start from last character to find possibly matching tails */ + if (len == 0) + return 0; + str->in_count++; + str->in_len += len; + + node = str->root; + c = s[len-1]; + for (depth = 0; depth <= len; depth++) { + struct strbuf_child_entry search; + + /* match against current node */ + off = node->value_off + node->value_len - len; + if (depth == len || (node->value_len >= len && memcmp(str->buf + off, s, len) == 0)) { + str->dedup_len += len; + str->dedup_count++; + return off; + } + + /* lookup child node */ + c = s[len - 1 - depth]; + search.c = c; + child = bsearch(&search, node->children, node->children_count, + sizeof(struct strbuf_child_entry), + (__compar_fn_t) strbuf_children_cmp); + if (!child) + break; + node = child->child; + } + + /* add new string */ + buf_new = realloc(str->buf, str->len + len+1); + if (!buf_new) + return -ENOMEM; + str->buf = buf_new; + off = str->len; + memcpy(str->buf + off, s, len); + str->len += len; + str->buf[str->len++] = '\0'; + + /* new node */ + node_child = new0(struct strbuf_node, 1); + if (!node_child) + return -ENOMEM; + node_child->value_off = off; + node_child->value_len = len; + + /* extend array, add new entry, sort for bisection */ + child = realloc(node->children, (node->children_count + 1) * sizeof(struct strbuf_child_entry)); + if (!child) { + free(node_child); + return -ENOMEM; + } + + str->nodes_count++; + + node->children = child; + bubbleinsert(node, c, node_child); + + return off; +} diff --git a/src/shared/strbuf.h b/src/shared/strbuf.h new file mode 100644 index 0000000..2347fd4 --- /dev/null +++ b/src/shared/strbuf.h @@ -0,0 +1,56 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +struct strbuf { + char *buf; + size_t len; + struct strbuf_node *root; + + size_t nodes_count; + size_t in_count; + size_t in_len; + size_t dedup_len; + size_t dedup_count; +}; + +struct strbuf_node { + size_t value_off; + size_t value_len; + + struct strbuf_child_entry *children; + uint8_t children_count; +}; + +struct strbuf_child_entry { + uint8_t c; + struct strbuf_node *child; +}; + +struct strbuf *strbuf_new(void); +ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); +void strbuf_complete(struct strbuf *str); +void strbuf_cleanup(struct strbuf *str); diff --git a/src/shared/strv.c b/src/shared/strv.c new file mode 100644 index 0000000..13deba7 --- /dev/null +++ b/src/shared/strv.c @@ -0,0 +1,524 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" + +char *strv_find(char **l, const char *name) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (streq(*i, name)) + return *i; + + return NULL; +} + +char *strv_find_prefix(char **l, const char *name) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (startswith(*i, name)) + return *i; + + return NULL; +} + +void strv_free(char **l) { + char **k; + + if (!l) + return; + + for (k = l; *k; k++) + free(*k); + + free(l); +} + +char **strv_copy(char * const *l) { + char **r, **k; + + k = r = new(char*, strv_length(l) + 1); + if (!r) + return NULL; + + if (l) + for (; *l; k++, l++) { + *k = strdup(*l); + if (!*k) { + strv_free(r); + return NULL; + } + } + + *k = NULL; + return r; +} + +unsigned strv_length(char * const *l) { + unsigned n = 0; + + if (!l) + return 0; + + for (; *l; l++) + n++; + + return n; +} + +char **strv_new_ap(const char *x, va_list ap) { + const char *s; + char **a; + unsigned n = 0, i = 0; + va_list aq; + + /* As a special trick we ignore all listed strings that equal + * (const char*) -1. This is supposed to be used with the + * STRV_IFNOTNULL() macro to include possibly NULL strings in + * the string list. */ + + if (x) { + n = x == (const char*) -1 ? 0 : 1; + + va_copy(aq, ap); + while ((s = va_arg(aq, const char*))) { + if (s == (const char*) -1) + continue; + + n++; + } + + va_end(aq); + } + + a = new(char*, n+1); + if (!a) + return NULL; + + if (x) { + if (x != (const char*) -1) { + a[i] = strdup(x); + if (!a[i]) + goto fail; + i++; + } + + while ((s = va_arg(ap, const char*))) { + + if (s == (const char*) -1) + continue; + + a[i] = strdup(s); + if (!a[i]) + goto fail; + + i++; + } + } + + a[i] = NULL; + + return a; + +fail: + strv_free(a); + return NULL; +} + +char **strv_new(const char *x, ...) { + char **r; + va_list ap; + + va_start(ap, x); + r = strv_new_ap(x, ap); + va_end(ap); + + return r; +} + +int strv_extend_strv(char ***a, char **b) { + int r; + char **s; + + STRV_FOREACH(s, b) { + r = strv_extend(a, *s); + if (r < 0) + return r; + } + + return 0; +} + +int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { + int r; + char **s; + + STRV_FOREACH(s, b) { + char *v; + + v = strappend(*s, suffix); + if (!v) + return -ENOMEM; + + r = strv_push(a, v); + if (r < 0) { + free(v); + return r; + } + } + + return 0; +} + +char **strv_split(const char *s, const char *separator) { + char *state; + char *w; + size_t l; + unsigned n, i; + char **r; + + assert(s); + + n = 0; + FOREACH_WORD_SEPARATOR(w, l, s, separator, state) + n++; + + r = new(char*, n+1); + if (!r) + return NULL; + + i = 0; + FOREACH_WORD_SEPARATOR(w, l, s, separator, state) { + r[i] = strndup(w, l); + if (!r[i]) { + strv_free(r); + return NULL; + } + + i++; + } + + r[i] = NULL; + return r; +} + +char **strv_split_quoted(const char *s) { + char *state; + char *w; + size_t l; + unsigned n, i; + char **r; + + assert(s); + + n = 0; + FOREACH_WORD_QUOTED(w, l, s, state) + n++; + + r = new(char*, n+1); + if (!r) + return NULL; + + i = 0; + FOREACH_WORD_QUOTED(w, l, s, state) { + r[i] = cunescape_length(w, l); + if (!r[i]) { + strv_free(r); + return NULL; + } + i++; + } + + r[i] = NULL; + return r; +} + +char **strv_split_newlines(const char *s) { + char **l; + unsigned n; + + assert(s); + + /* Special version of strv_split() that splits on newlines and + * suppresses an empty string at the end */ + + l = strv_split(s, NEWLINE); + if (!l) + return NULL; + + n = strv_length(l); + if (n <= 0) + return l; + + if (isempty(l[n-1])) { + free(l[n-1]); + l[n-1] = NULL; + } + + return l; +} + +char *strv_join(char **l, const char *separator) { + char *r, *e; + char **s; + size_t n, k; + + if (!separator) + separator = " "; + + k = strlen(separator); + + n = 0; + STRV_FOREACH(s, l) { + if (n != 0) + n += k; + n += strlen(*s); + } + + r = new(char, n+1); + if (!r) + return NULL; + + e = r; + STRV_FOREACH(s, l) { + if (e != r) + e = stpcpy(e, separator); + + e = stpcpy(e, *s); + } + + *e = 0; + + return r; +} + +char *strv_join_quoted(char **l) { + char *buf = NULL; + char **s; + size_t allocated = 0, len = 0; + + STRV_FOREACH(s, l) { + /* assuming here that escaped string cannot be more + * than twice as long, and reserving space for the + * separator and quotes. + */ + _cleanup_free_ char *esc = NULL; + size_t needed; + + if (!GREEDY_REALLOC(buf, allocated, + len + strlen(*s) * 2 + 3)) + goto oom; + + esc = cescape(*s); + if (!esc) + goto oom; + + needed = snprintf(buf + len, allocated - len, "%s\"%s\"", + len > 0 ? " " : "", esc); + assert(needed < allocated - len); + len += needed; + } + + if (!buf) + buf = malloc0(1); + + return buf; + + oom: + free(buf); + return NULL; +} + +int strv_push(char ***l, char *value) { + char **c; + unsigned n; + + if (!value) + return 0; + + n = strv_length(*l); + c = realloc(*l, sizeof(char*) * (n + 2)); + if (!c) + return -ENOMEM; + + c[n] = value; + c[n+1] = NULL; + + *l = c; + return 0; +} + +int strv_extend(char ***l, const char *value) { + char *v; + int r; + + if (!value) + return 0; + + v = strdup(value); + if (!v) + return -ENOMEM; + + r = strv_push(l, v); + if (r < 0) + free(v); + + return r; +} + +char **strv_uniq(char **l) { + char **i; + + /* Drops duplicate entries. The first identical string will be + * kept, the others dropped */ + + STRV_FOREACH(i, l) + strv_remove(i+1, *i); + + return l; +} + +char **strv_remove(char **l, const char *s) { + char **f, **t; + + if (!l) + return NULL; + + assert(s); + + /* Drops every occurrence of s in the string list, edits + * in-place. */ + + for (f = t = l; *f; f++) + if (streq(*f, s)) + free(*f); + else + *(t++) = *f; + + *t = NULL; + return l; +} + +char **strv_parse_nulstr(const char *s, size_t l) { + const char *p; + unsigned c = 0, i = 0; + char **v; + + assert(s || l <= 0); + + if (l <= 0) + return new0(char*, 1); + + for (p = s; p < s + l; p++) + if (*p == 0) + c++; + + if (s[l-1] != 0) + c++; + + v = new0(char*, c+1); + if (!v) + return NULL; + + p = s; + while (p < s + l) { + const char *e; + + e = memchr(p, 0, s + l - p); + + v[i] = strndup(p, e ? e - p : s + l - p); + if (!v[i]) { + strv_free(v); + return NULL; + } + + i++; + + if (!e) + break; + + p = e + 1; + } + + assert(i == c); + + return v; +} + +char **strv_split_nulstr(const char *s) { + const char *i; + char **r = NULL; + + NULSTR_FOREACH(i, s) + if (strv_extend(&r, i) < 0) { + strv_free(r); + return NULL; + } + + if (!r) + return strv_new(NULL, NULL); + + return r; +} + +bool strv_overlap(char **a, char **b) { + char **i; + + STRV_FOREACH(i, a) + if (strv_contains(b, *i)) + return true; + + return false; +} + +static int str_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + + return strcmp(*a, *b); +} + +char **strv_sort(char **l) { + + if (strv_isempty(l)) + return l; + + qsort(l, strv_length(l), sizeof(char*), str_compare); + return l; +} + +void strv_print(char **l) { + char **s; + + STRV_FOREACH(s, l) + puts(*s); +} diff --git a/src/shared/strv.h b/src/shared/strv.h new file mode 100644 index 0000000..715bc54 --- /dev/null +++ b/src/shared/strv.h @@ -0,0 +1,117 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" + +char *strv_find(char **l, const char *name) _pure_; +char *strv_find_prefix(char **l, const char *name) _pure_; + +void strv_free(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); +#define _cleanup_strv_free_ _cleanup_(strv_freep) + +char **strv_copy(char * const *l); +unsigned strv_length(char * const *l) _pure_; + +int strv_extend_strv(char ***a, char **b); +int strv_extend_strv_concat(char ***a, char **b, const char *suffix); +int strv_extend(char ***l, const char *value); +int strv_push(char ***l, char *value); + +char **strv_remove(char **l, const char *s); +char **strv_uniq(char **l); + +#define strv_contains(l, s) (!!strv_find((l), (s))) + +char **strv_new(const char *x, ...) _sentinel_; +char **strv_new_ap(const char *x, va_list ap); + +static inline const char* STRV_IFNOTNULL(const char *x) { + return x ? x : (const char *) -1; +} + +static inline bool strv_isempty(char * const *l) { + return !l || !*l; +} + +char **strv_split(const char *s, const char *separator); +char **strv_split_quoted(const char *s); +char **strv_split_newlines(const char *s); + +char *strv_join(char **l, const char *separator); +char *strv_join_quoted(char **l); + +char **strv_parse_nulstr(const char *s, size_t l); +char **strv_split_nulstr(const char *s); + +bool strv_overlap(char **a, char **b) _pure_; + +#define STRV_FOREACH(s, l) \ + for ((s) = (l); (s) && *(s); (s)++) + +#define STRV_FOREACH_BACKWARDS(s, l) \ + STRV_FOREACH(s, l) \ + ; \ + for ((s)--; (l) && ((s) >= (l)); (s)--) + +#define STRV_FOREACH_PAIR(x, y, l) \ + for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) + +char **strv_sort(char **l); +void strv_print(char **l); + +#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) + +#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) + +#define strv_from_stdarg_alloca(first) \ + ({ \ + char **_l; \ + \ + if (!first) \ + _l = (char**) &first; \ + else { \ + unsigned _n; \ + va_list _ap; \ + \ + _n = 1; \ + va_start(_ap, first); \ + while (va_arg(_ap, char*)) \ + _n++; \ + va_end(_ap); \ + \ + _l = newa(char*, _n+1); \ + _l[_n = 0] = (char*) first; \ + va_start(_ap, first); \ + for (;;) { \ + _l[++_n] = va_arg(_ap, char*); \ + if (!_l[_n]) \ + break; \ + } \ + va_end(_ap); \ + } \ + _l; \ + }) diff --git a/src/shared/strxcpyx.c b/src/shared/strxcpyx.c new file mode 100644 index 0000000..6542c0a --- /dev/null +++ b/src/shared/strxcpyx.c @@ -0,0 +1,100 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* + * Concatenates/copies strings. In any case, terminates in all cases + * with '\0' * and moves the @dest pointer forward to the added '\0'. + * Returns the * remaining size, and 0 if the string was truncated. + */ + +#include +#include +#include "strxcpyx.h" + +size_t strpcpy(char **dest, size_t size, const char *src) { + size_t len; + + len = strlen(src); + if (len >= size) { + if (size > 1) + *dest = mempcpy(*dest, src, size-1); + size = 0; + } else { + if (len > 0) { + *dest = mempcpy(*dest, src, len); + size -= len; + } + } + *dest[0] = '\0'; + return size; +} + +size_t strpcpyf(char **dest, size_t size, const char *src, ...) { + va_list va; + int i; + + va_start(va, src); + i = vsnprintf(*dest, size, src, va); + if (i < (int)size) { + *dest += i; + size -= i; + } else { + *dest += size; + size = 0; + } + va_end(va); + *dest[0] = '\0'; + return size; +} + +size_t strpcpyl(char **dest, size_t size, const char *src, ...) { + va_list va; + + va_start(va, src); + do { + size = strpcpy(dest, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); + return size; +} + +size_t strscpy(char *dest, size_t size, const char *src) { + char *s; + + s = dest; + return strpcpy(&s, size, src); +} + +size_t strscpyl(char *dest, size_t size, const char *src, ...) { + va_list va; + char *s; + + va_start(va, src); + s = dest; + do { + size = strpcpy(&s, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); + + return size; +} diff --git a/src/shared/strxcpyx.h b/src/shared/strxcpyx.h new file mode 100644 index 0000000..7be246d --- /dev/null +++ b/src/shared/strxcpyx.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "macro.h" + +size_t strpcpy(char **dest, size_t size, const char *src); +size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4); +size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_; +size_t strscpy(char *dest, size_t size, const char *src); +size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_; diff --git a/src/shared/test-tables.h b/src/shared/test-tables.h new file mode 100644 index 0000000..3261302 --- /dev/null +++ b/src/shared/test-tables.h @@ -0,0 +1,51 @@ +/*** + This file is part of systemd + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +typedef const char* (*lookup_t)(int); +typedef int (*reverse_t)(const char*); + +static inline void _test_table(const char *name, + lookup_t lookup, + reverse_t reverse, + int size, + bool sparse) { + int i; + + for (i = -1; i < size + 1; i++) { + const char* val = lookup(i); + int rev; + + if (val) + rev = reverse(val); + else + rev = reverse("--no-such--value----"); + + printf("%s: %d → %s → %d\n", name, i, val, rev); + if (i >= 0 && i < size ? + sparse ? rev != i && rev != -1 : val == NULL || rev != i : + val != NULL || rev != -1) + exit(EXIT_FAILURE); + } +} + +#define test_table(lower, upper) \ + _test_table(STRINGIFY(lower), lower##_to_string, lower##_from_string, _##upper##_MAX, false) diff --git a/src/shared/time-dst.c b/src/shared/time-dst.c new file mode 100644 index 0000000..65e2998 --- /dev/null +++ b/src/shared/time-dst.c @@ -0,0 +1,332 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Timezone file reading code from glibc 2.16. + + Copyright (C) 1991-2012 Free Software Foundation, Inc. + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "time-dst.h" +#include "util.h" + +/* + * If tzh_version is '2' or greater, the above is followed by a second instance + * of tzhead and a second instance of the data in which each coded transition + * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style + * string for use in handling instants after the last transition time stored in + * the file * (with nothing between the newlines if there is no POSIX + * representation for such instants). + */ +#define TZ_MAGIC "TZif" +struct tzhead { + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_version[1]; /* '\0' or '2' as of 2005 */ + char tzh_reserved[15]; /* reserved--must be zero */ + char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ +}; + +struct ttinfo { + long int offset; /* Seconds east of GMT. */ + unsigned char isdst; /* Used to set tm_isdst. */ + unsigned char idx; /* Index into `zone_names'. */ + unsigned char isstd; /* Transition times are in standard time. */ + unsigned char isgmt; /* Transition times are in GMT. */ +}; + +struct leap { + time_t transition; /* Time the transition takes effect. */ + long int change; /* Seconds of correction to apply. */ +}; + +static inline int decode(const void *ptr) { + return be32toh(*(int *)ptr); +} + +static inline int64_t decode64(const void *ptr) { + return be64toh(*(int64_t *)ptr); +} + +int time_get_dst(time_t date, const char *tzfile, + time_t *switch_cur, char **zone_cur, bool *dst_cur, + time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) { + unsigned char *type_idxs = 0; + size_t num_types = 0; + struct ttinfo *types = NULL; + char *zone_names = NULL; + struct stat st; + size_t num_isstd, num_isgmt; + struct tzhead tzhead; + size_t chars; + size_t i; + size_t total_size; + size_t types_idx; + int trans_width = 4; + size_t tzspec_len; + size_t num_leaps; + size_t lo, hi; + size_t num_transitions = 0; + _cleanup_free_ time_t *transitions = NULL; + _cleanup_fclose_ FILE *f; + + f = fopen(tzfile, "re"); + if (f == NULL) + return -errno; + + if (fstat(fileno(f), &st) < 0) + return -errno; + +read_again: + if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 || + memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0) + return -EINVAL; + + num_transitions = (size_t)decode(tzhead.tzh_timecnt); + num_types = (size_t)decode(tzhead.tzh_typecnt); + chars = (size_t)decode(tzhead.tzh_charcnt); + num_leaps = (size_t)decode(tzhead.tzh_leapcnt); + num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt); + num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt); + + /* For platforms with 64-bit time_t we use the new format if available. */ + if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') { + size_t to_skip; + + /* We use the 8-byte format. */ + trans_width = 8; + + /* Position the stream before the second header. */ + to_skip = (num_transitions * (4 + 1) + + num_types * 6 + + chars + + num_leaps * 8 + num_isstd + num_isgmt); + if (fseek(f, to_skip, SEEK_CUR) != 0) + return -EINVAL; + + goto read_again; + } + + if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1))) + return -EINVAL; + + total_size = num_transitions * (sizeof(time_t) + 1); + total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1)); + types_idx = total_size; + if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo)) + return -EINVAL; + + total_size += num_types * sizeof(struct ttinfo); + if (chars > SIZE_MAX - total_size) + return -EINVAL; + + total_size += chars; + if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size) + return -EINVAL; + + total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1)); + if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap)) + return -EINVAL; + + total_size += num_leaps * sizeof(struct leap); + tzspec_len = 0; + if (sizeof(time_t) == 8 && trans_width == 8) { + off_t rem = st.st_size - ftello(f); + + if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars)) + return -EINVAL; + tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars); + if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12) + return -EINVAL; + tzspec_len -= num_leaps * 12; + if (tzspec_len < num_isstd) + return -EINVAL; + tzspec_len -= num_isstd; + if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt) + return -EINVAL; + tzspec_len -= num_isgmt + 1; + if (SIZE_MAX - total_size < tzspec_len) + return -EINVAL; + } + + transitions = malloc0(total_size + tzspec_len); + if (transitions == NULL) + return -EINVAL; + + type_idxs = (unsigned char *)transitions + (num_transitions + * sizeof(time_t)); + types = (struct ttinfo *)((char *)transitions + types_idx); + zone_names = (char *)types + num_types * sizeof(struct ttinfo); + + if (sizeof(time_t) == 4 || trans_width == 8) { + if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions) + return -EINVAL; + } else { + if (fread(transitions, 4, num_transitions, f) != num_transitions || + fread(type_idxs, 1, num_transitions, f) != num_transitions) + return -EINVAL; + } + + /* Check for bogus indices in the data file, so we can hereafter + safely use type_idxs[T] as indices into `types' and never crash. */ + for (i = 0; i < num_transitions; ++i) + if (type_idxs[i] >= num_types) + return -EINVAL; + + if ((BYTE_ORDER != BIG_ENDIAN && (sizeof(time_t) == 4 || trans_width == 4)) || + (BYTE_ORDER == BIG_ENDIAN && sizeof(time_t) == 8 && trans_width == 4)) { + /* Decode the transition times, stored as 4-byte integers in + network (big-endian) byte order. We work from the end of + the array so as not to clobber the next element to be + processed when sizeof (time_t) > 4. */ + i = num_transitions; + while (i-- > 0) + transitions[i] = decode((char *)transitions + i * 4); + } else if (BYTE_ORDER != BIG_ENDIAN && sizeof(time_t) == 8) { + /* Decode the transition times, stored as 8-byte integers in + network (big-endian) byte order. */ + for (i = 0; i < num_transitions; ++i) + transitions[i] = decode64((char *)transitions + i * 8); + } + + for (i = 0; i < num_types; ++i) { + unsigned char x[4]; + int c; + + if (fread(x, 1, sizeof(x), f) != sizeof(x)) + return -EINVAL; + c = getc(f); + if ((unsigned int)c > 1u) + return -EINVAL; + types[i].isdst = c; + c = getc(f); + if ((size_t) c > chars) + /* Bogus index in data file. */ + return -EINVAL; + types[i].idx = c; + types[i].offset = (long int)decode(x); + } + + if (fread(zone_names, 1, chars, f) != chars) + return -EINVAL; + + for (i = 0; i < num_isstd; ++i) { + int c = getc(f); + if (c == EOF) + return -EINVAL; + types[i].isstd = c != 0; + } + + while (i < num_types) + types[i++].isstd = 0; + + for (i = 0; i < num_isgmt; ++i) { + int c = getc(f); + if (c == EOF) + return -EINVAL; + types[i].isgmt = c != 0; + } + + while (i < num_types) + types[i++].isgmt = 0; + + if (num_transitions == 0) + return -EINVAL; + + if (date < transitions[0] || date >= transitions[num_transitions - 1]) + return -EINVAL; + + /* Find the first transition after TIMER, and + then pick the type of the transition before it. */ + lo = 0; + hi = num_transitions - 1; + + /* Assume that DST is changing twice a year and guess initial + search spot from it. + Half of a gregorian year has on average 365.2425 * 86400 / 2 + = 15778476 seconds. */ + i = (transitions[num_transitions - 1] - date) / 15778476; + if (i < num_transitions) { + i = num_transitions - 1 - i; + if (date < transitions[i]) { + if (i < 10 || date >= transitions[i - 10]) { + /* Linear search. */ + while (date < transitions[i - 1]) + i--; + goto found; + } + hi = i - 10; + } else { + if (i + 10 >= num_transitions || date < transitions[i + 10]) { + /* Linear search. */ + while (date >= transitions[i]) + i++; + goto found; + } + lo = i + 10; + } + } + + /* Binary search. */ + while (lo + 1 < hi) { + i = (lo + hi) / 2; + if (date < transitions[i]) + hi = i; + else + lo = i; + } + i = hi; + +found: + if (switch_cur) + *switch_cur = transitions[i-1]; + if (zone_cur) + *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]); + if (dst_cur) + *dst_cur = types[type_idxs[i-1]].isdst; + + if (switch_next) + *switch_next = transitions[i]; + if (delta_next) + *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60; + if (zone_next) + *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]); + if (dst_next) + *dst_next = types[type_idxs[i]].isdst; + + return 0; +} diff --git a/src/shared/time-dst.h b/src/shared/time-dst.h new file mode 100644 index 0000000..536b6bb --- /dev/null +++ b/src/shared/time-dst.h @@ -0,0 +1,26 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int time_get_dst(time_t date, const char *tzfile, + time_t *switch_cur, char **zone_cur, bool *dst_cur, + time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next); diff --git a/src/shared/time-util.c b/src/shared/time-util.c new file mode 100644 index 0000000..faa3418 --- /dev/null +++ b/src/shared/time-util.c @@ -0,0 +1,825 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "time-util.h" + +usec_t now(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load(&ts); +} + +dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { + assert(ts); + + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + + return ts; +} + +dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { + int64_t delta; + assert(ts); + + if (u == (usec_t) -1) { + ts->realtime = ts->monotonic = (usec_t) -1; + return ts; + } + + ts->realtime = u; + + if (u == 0) + ts->monotonic = 0; + else { + delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; + + ts->monotonic = now(CLOCK_MONOTONIC); + + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; + } + + return ts; +} + +dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { + int64_t delta; + assert(ts); + + if (u == (usec_t) -1) { + ts->realtime = ts->monotonic = (usec_t) -1; + return ts; + } + + ts->monotonic = u; + delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; + + ts->realtime = now(CLOCK_REALTIME); + if ((int64_t) ts->realtime > delta) + ts->realtime -= delta; + else + ts->realtime = 0; + + return ts; +} + +usec_t timespec_load(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return (usec_t) -1; + + if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return (usec_t) -1; + + return + (usec_t) ts->tv_sec * USEC_PER_SEC + + (usec_t) ts->tv_nsec / NSEC_PER_USEC; +} + +struct timespec *timespec_store(struct timespec *ts, usec_t u) { + assert(ts); + + if (u == (usec_t) -1) { + ts->tv_sec = (time_t) -1; + ts->tv_nsec = (long) -1; + return ts; + } + + ts->tv_sec = (time_t) (u / USEC_PER_SEC); + ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); + + return ts; +} + +usec_t timeval_load(const struct timeval *tv) { + assert(tv); + + if (tv->tv_sec == (time_t) -1 && + tv->tv_usec == (suseconds_t) -1) + return (usec_t) -1; + + if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) + return (usec_t) -1; + + return + (usec_t) tv->tv_sec * USEC_PER_SEC + + (usec_t) tv->tv_usec; +} + +struct timeval *timeval_store(struct timeval *tv, usec_t u) { + assert(tv); + + if (u == (usec_t) -1) { + tv->tv_sec = (time_t) -1; + tv->tv_usec = (suseconds_t) -1; + } else { + tv->tv_sec = (time_t) (u / USEC_PER_SEC); + tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); + } + + return tv; +} + +char *format_timestamp(char *buf, size_t l, usec_t t) { + struct tm tm; + time_t sec; + + assert(buf); + assert(l > 0); + + if (t <= 0 || t == (usec_t) -1) + return NULL; + + sec = (time_t) (t / USEC_PER_SEC); + + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0) + return NULL; + + return buf; +} + +char *format_timestamp_us(char *buf, size_t l, usec_t t) { + struct tm tm; + time_t sec; + + assert(buf); + assert(l > 0); + + if (t <= 0 || t == (usec_t) -1) + return NULL; + + sec = (time_t) (t / USEC_PER_SEC); + localtime_r(&sec, &tm); + + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) + return NULL; + snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC); + if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) + return NULL; + + return buf; +} + +char *format_timestamp_relative(char *buf, size_t l, usec_t t) { + const char *s; + usec_t n, d; + + n = now(CLOCK_REALTIME); + + if (t <= 0 || (t == (usec_t) -1)) + return NULL; + + if (n > t) { + d = n - t; + s = "ago"; + } else { + d = t - n; + s = "left"; + } + + if (d >= USEC_PER_YEAR) + snprintf(buf, l, "%llu years %llu months %s", + (unsigned long long) (d / USEC_PER_YEAR), + (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH), s); + else if (d >= USEC_PER_MONTH) + snprintf(buf, l, "%llu months %llu days %s", + (unsigned long long) (d / USEC_PER_MONTH), + (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY), s); + else if (d >= USEC_PER_WEEK) + snprintf(buf, l, "%llu weeks %llu days %s", + (unsigned long long) (d / USEC_PER_WEEK), + (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY), s); + else if (d >= 2*USEC_PER_DAY) + snprintf(buf, l, "%llu days %s", (unsigned long long) (d / USEC_PER_DAY), s); + else if (d >= 25*USEC_PER_HOUR) + snprintf(buf, l, "1 day %lluh %s", + (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR), s); + else if (d >= 6*USEC_PER_HOUR) + snprintf(buf, l, "%lluh %s", + (unsigned long long) (d / USEC_PER_HOUR), s); + else if (d >= USEC_PER_HOUR) + snprintf(buf, l, "%lluh %llumin %s", + (unsigned long long) (d / USEC_PER_HOUR), + (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE), s); + else if (d >= 5*USEC_PER_MINUTE) + snprintf(buf, l, "%llumin %s", + (unsigned long long) (d / USEC_PER_MINUTE), s); + else if (d >= USEC_PER_MINUTE) + snprintf(buf, l, "%llumin %llus %s", + (unsigned long long) (d / USEC_PER_MINUTE), + (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC), s); + else if (d >= USEC_PER_SEC) + snprintf(buf, l, "%llus %s", + (unsigned long long) (d / USEC_PER_SEC), s); + else if (d >= USEC_PER_MSEC) + snprintf(buf, l, "%llums %s", + (unsigned long long) (d / USEC_PER_MSEC), s); + else if (d > 0) + snprintf(buf, l, "%lluus %s", + (unsigned long long) d, s); + else + snprintf(buf, l, "now"); + + buf[l-1] = 0; + return buf; +} + +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "y", USEC_PER_YEAR }, + { "month", USEC_PER_MONTH }, + { "w", USEC_PER_WEEK }, + { "d", USEC_PER_DAY }, + { "h", USEC_PER_HOUR }, + { "min", USEC_PER_MINUTE }, + { "s", USEC_PER_SEC }, + { "ms", USEC_PER_MSEC }, + { "us", 1 }, + }; + + unsigned i; + char *p = buf; + bool something = false; + + assert(buf); + assert(l > 0); + + if (t == (usec_t) -1) + return NULL; + + if (t <= 0) { + snprintf(p, l, "0"); + p[l-1] = 0; + return p; + } + + /* The result of this function can be parsed with parse_sec */ + + for (i = 0; i < ELEMENTSOF(table); i++) { + int k = 0; + size_t n; + bool done = false; + usec_t a, b; + + if (t <= 0) + break; + + if (t < accuracy && something) + break; + + if (t < table[i].usec) + continue; + + if (l <= 1) + break; + + a = t / table[i].usec; + b = t % table[i].usec; + + /* Let's see if we should shows this in dot notation */ + if (t < USEC_PER_MINUTE && b > 0) { + usec_t cc; + int j; + + j = 0; + for (cc = table[i].usec; cc > 1; cc /= 10) + j++; + + for (cc = accuracy; cc > 1; cc /= 10) { + b /= 10; + j--; + } + + if (j > 0) { + k = snprintf(p, l, + "%s%llu.%0*llu%s", + p > buf ? " " : "", + (unsigned long long) a, + j, + (unsigned long long) b, + table[i].suffix); + + t = 0; + done = true; + } + } + + /* No? Then let's show it normally */ + if (!done) { + k = snprintf(p, l, + "%s%llu%s", + p > buf ? " " : "", + (unsigned long long) a, + table[i].suffix); + + t = b; + } + + n = MIN((size_t) k, l); + + l -= n; + p += n; + + something = true; + } + + *p = 0; + + return buf; +} + +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { + + assert(f); + assert(name); + assert(t); + + if (!dual_timestamp_is_set(t)) + return; + + fprintf(f, "%s=%llu %llu\n", + name, + (unsigned long long) t->realtime, + (unsigned long long) t->monotonic); +} + +void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { + unsigned long long a, b; + + assert(value); + assert(t); + + if (sscanf(value, "%llu %llu", &a, &b) != 2) + log_debug("Failed to parse finish timestamp value %s", value); + else { + t->realtime = a; + t->monotonic = b; + } +} + +int parse_timestamp(const char *t, usec_t *usec) { + static const struct { + const char *name; + const int nr; + } day_nr[] = { + { "Sunday", 0 }, + { "Sun", 0 }, + { "Monday", 1 }, + { "Mon", 1 }, + { "Tuesday", 2 }, + { "Tue", 2 }, + { "Wednesday", 3 }, + { "Wed", 3 }, + { "Thursday", 4 }, + { "Thu", 4 }, + { "Friday", 5 }, + { "Fri", 5 }, + { "Saturday", 6 }, + { "Sat", 6 }, + }; + + const char *k; + struct tm tm, copy; + time_t x; + usec_t plus = 0, minus = 0, ret; + int r, weekday = -1; + unsigned i; + + /* + * Allowed syntaxes: + * + * 2012-09-22 16:34:22 + * 2012-09-22 16:34 (seconds will be set to 0) + * 2012-09-22 (time will be set to 00:00:00) + * 16:34:22 (date will be set to today) + * 16:34 (date will be set to today, seconds to 0) + * now + * yesterday (time is set to 00:00:00) + * today (time is set to 00:00:00) + * tomorrow (time is set to 00:00:00) + * +5min + * -5days + * + */ + + assert(t); + assert(usec); + + x = time(NULL); + assert_se(localtime_r(&x, &tm)); + tm.tm_isdst = -1; + + if (streq(t, "now")) + goto finish; + + else if (streq(t, "today")) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (streq(t, "yesterday")) { + tm.tm_mday --; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (streq(t, "tomorrow")) { + tm.tm_mday ++; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (t[0] == '+') { + + r = parse_sec(t+1, &plus); + if (r < 0) + return r; + + goto finish; + } else if (t[0] == '-') { + + r = parse_sec(t+1, &minus); + if (r < 0) + return r; + + goto finish; + + } else if (endswith(t, " ago")) { + _cleanup_free_ char *z; + + z = strndup(t, strlen(t) - 4); + if (!z) + return -ENOMEM; + + r = parse_sec(z, &minus); + if (r < 0) + return r; + + goto finish; + } else if (endswith(t, " left")) { + _cleanup_free_ char *z; + + z = strndup(t, strlen(t) - 4); + if (!z) + return -ENOMEM; + + r = parse_sec(z, &plus); + if (r < 0) + return r; + + goto finish; + } + + for (i = 0; i < ELEMENTSOF(day_nr); i++) { + size_t skip; + + if (!startswith_no_case(t, day_nr[i].name)) + continue; + + skip = strlen(day_nr[i].name); + if (t[skip] != ' ') + continue; + + weekday = day_nr[i].nr; + t += skip + 1; + break; + } + + copy = tm; + k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + return -EINVAL; + +finish: + x = mktime(&tm); + if (x == (time_t) -1) + return -EINVAL; + + if (weekday >= 0 && tm.tm_wday != weekday) + return -EINVAL; + + ret = (usec_t) x * USEC_PER_SEC; + + ret += plus; + if (ret > minus) + ret -= minus; + else + ret = 0; + + *usec = ret; + + return 0; +} + +int parse_sec(const char *t, usec_t *usec) { + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "seconds", USEC_PER_SEC }, + { "second", USEC_PER_SEC }, + { "sec", USEC_PER_SEC }, + { "s", USEC_PER_SEC }, + { "minutes", USEC_PER_MINUTE }, + { "minute", USEC_PER_MINUTE }, + { "min", USEC_PER_MINUTE }, + { "months", USEC_PER_MONTH }, + { "month", USEC_PER_MONTH }, + { "msec", USEC_PER_MSEC }, + { "ms", USEC_PER_MSEC }, + { "m", USEC_PER_MINUTE }, + { "hours", USEC_PER_HOUR }, + { "hour", USEC_PER_HOUR }, + { "hr", USEC_PER_HOUR }, + { "h", USEC_PER_HOUR }, + { "days", USEC_PER_DAY }, + { "day", USEC_PER_DAY }, + { "d", USEC_PER_DAY }, + { "weeks", USEC_PER_WEEK }, + { "week", USEC_PER_WEEK }, + { "w", USEC_PER_WEEK }, + { "years", USEC_PER_YEAR }, + { "year", USEC_PER_YEAR }, + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, + { "", USEC_PER_SEC }, /* default is sec */ + }; + + const char *p; + usec_t r = 0; + bool something = false; + + assert(t); + assert(usec); + + p = t; + for (;;) { + long long l, z = 0; + char *e; + unsigned i, n = 0; + + p += strspn(p, WHITESPACE); + + if (*p == 0) { + if (!something) + return -EINVAL; + + break; + } + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (*e == '.') { + char *b = e + 1; + + errno = 0; + z = strtoll(b, &e, 10); + if (errno > 0) + return -errno; + + if (z < 0) + return -ERANGE; + + if (e == b) + return -EINVAL; + + n = e - b; + + } else if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + usec_t k = (usec_t) z * table[i].usec; + + for (; n > 0; n--) + k /= 10; + + r += (usec_t) l * table[i].usec + k; + p = e + strlen(table[i].suffix); + + something = true; + break; + } + + if (i >= ELEMENTSOF(table)) + return -EINVAL; + + } + + *usec = r; + + return 0; +} + +int parse_nsec(const char *t, nsec_t *nsec) { + static const struct { + const char *suffix; + nsec_t nsec; + } table[] = { + { "seconds", NSEC_PER_SEC }, + { "second", NSEC_PER_SEC }, + { "sec", NSEC_PER_SEC }, + { "s", NSEC_PER_SEC }, + { "minutes", NSEC_PER_MINUTE }, + { "minute", NSEC_PER_MINUTE }, + { "min", NSEC_PER_MINUTE }, + { "months", NSEC_PER_MONTH }, + { "month", NSEC_PER_MONTH }, + { "msec", NSEC_PER_MSEC }, + { "ms", NSEC_PER_MSEC }, + { "m", NSEC_PER_MINUTE }, + { "hours", NSEC_PER_HOUR }, + { "hour", NSEC_PER_HOUR }, + { "hr", NSEC_PER_HOUR }, + { "h", NSEC_PER_HOUR }, + { "days", NSEC_PER_DAY }, + { "day", NSEC_PER_DAY }, + { "d", NSEC_PER_DAY }, + { "weeks", NSEC_PER_WEEK }, + { "week", NSEC_PER_WEEK }, + { "w", NSEC_PER_WEEK }, + { "years", NSEC_PER_YEAR }, + { "year", NSEC_PER_YEAR }, + { "y", NSEC_PER_YEAR }, + { "usec", NSEC_PER_USEC }, + { "us", NSEC_PER_USEC }, + { "nsec", 1ULL }, + { "ns", 1ULL }, + { "", 1ULL }, /* default is nsec */ + }; + + const char *p; + nsec_t r = 0; + bool something = false; + + assert(t); + assert(nsec); + + p = t; + for (;;) { + long long l, z = 0; + char *e; + unsigned i, n = 0; + + p += strspn(p, WHITESPACE); + + if (*p == 0) { + if (!something) + return -EINVAL; + + break; + } + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (*e == '.') { + char *b = e + 1; + + errno = 0; + z = strtoll(b, &e, 10); + if (errno > 0) + return -errno; + + if (z < 0) + return -ERANGE; + + if (e == b) + return -EINVAL; + + n = e - b; + + } else if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + nsec_t k = (nsec_t) z * table[i].nsec; + + for (; n > 0; n--) + k /= 10; + + r += (nsec_t) l * table[i].nsec + k; + p = e + strlen(table[i].suffix); + + something = true; + break; + } + + if (i >= ELEMENTSOF(table)) + return -EINVAL; + + } + + *nsec = r; + + return 0; +} + +bool ntp_synced(void) { + struct timex txc = {}; + + if (adjtimex(&txc) < 0) + return false; + + if (txc.status & STA_UNSYNC) + return false; + + return true; +} diff --git a/src/shared/time-util.h b/src/shared/time-util.h new file mode 100644 index 0000000..96f2ec8 --- /dev/null +++ b/src/shared/time-util.h @@ -0,0 +1,96 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +typedef uint64_t usec_t; +typedef uint64_t nsec_t; + +#define NSEC_FMT "%" PRIu64 +#define USEC_FMT "%" PRIu64 + +#include "macro.h" + +typedef struct dual_timestamp { + usec_t realtime; + usec_t monotonic; +} dual_timestamp; + +#define MSEC_PER_SEC 1000ULL +#define USEC_PER_SEC 1000000ULL +#define USEC_PER_MSEC 1000ULL +#define NSEC_PER_SEC 1000000000ULL +#define NSEC_PER_MSEC 1000000ULL +#define NSEC_PER_USEC 1000ULL + +#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC) +#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC) +#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE) +#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE) +#define USEC_PER_DAY (24ULL*USEC_PER_HOUR) +#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR) +#define USEC_PER_WEEK (7ULL*USEC_PER_DAY) +#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY) +#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC) +#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC) +#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC) +#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC) + +#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ +#define FORMAT_TIMESTAMP_RELATIVE_MAX 256 +#define FORMAT_TIMESPAN_MAX 64 + +#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0, 0 }) + +usec_t now(clockid_t clock); + +dual_timestamp* dual_timestamp_get(dual_timestamp *ts); +dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); +dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); + +static inline bool dual_timestamp_is_set(dual_timestamp *ts) { + return ((ts->realtime > 0 && ts->realtime != (usec_t) -1) || + (ts->monotonic > 0 && ts->monotonic != (usec_t) -1)); +} + +usec_t timespec_load(const struct timespec *ts) _pure_; +struct timespec *timespec_store(struct timespec *ts, usec_t u); + +usec_t timeval_load(const struct timeval *tv) _pure_; +struct timeval *timeval_store(struct timeval *tv, usec_t u); + +char *format_timestamp(char *buf, size_t l, usec_t t); +char *format_timestamp_us(char *buf, size_t l, usec_t t); +char *format_timestamp_relative(char *buf, size_t l, usec_t t); +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); + +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); +void dual_timestamp_deserialize(const char *value, dual_timestamp *t); + +int parse_timestamp(const char *t, usec_t *usec); + +int parse_sec(const char *t, usec_t *usec); +int parse_nsec(const char *t, nsec_t *nsec); + +bool ntp_synced(void); diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h new file mode 100644 index 0000000..40f8b77 --- /dev/null +++ b/src/shared/udev-util.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "udev.h" +#include "util.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_queue*, udev_queue_unref); + +#define _cleanup_udev_unref_ _cleanup_(udev_unrefp) +#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp) +#define _cleanup_udev_enumerate_unref_ _cleanup_(udev_enumerate_unrefp) +#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp) +#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp) +#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp) +#define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp) +#define _cleanup_udev_queue_unref_ _cleanup_(udev_queue_unrefp) +#define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup) diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c new file mode 100644 index 0000000..2924c47 --- /dev/null +++ b/src/shared/unit-name.c @@ -0,0 +1,599 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "path-util.h" +#include "bus-label.h" +#include "util.h" +#include "unit-name.h" +#include "def.h" + +#define VALID_CHARS \ + DIGITS LETTERS \ + ":-_.\\" + +static const char* const unit_type_table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "service", + [UNIT_SOCKET] = "socket", + [UNIT_BUSNAME] = "busname", + [UNIT_TARGET] = "target", + [UNIT_SNAPSHOT] = "snapshot", + [UNIT_DEVICE] = "device", + [UNIT_MOUNT] = "mount", + [UNIT_AUTOMOUNT] = "automount", + [UNIT_SWAP] = "swap", + [UNIT_TIMER] = "timer", + [UNIT_PATH] = "path", + [UNIT_SLICE] = "slice", + [UNIT_SCOPE] = "scope" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); + +static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { + [UNIT_STUB] = "stub", + [UNIT_LOADED] = "loaded", + [UNIT_NOT_FOUND] = "not-found", + [UNIT_ERROR] = "error", + [UNIT_MERGED] = "merged", + [UNIT_MASKED] = "masked" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); + +bool unit_name_is_valid(const char *n, enum template_valid template_ok) { + const char *e, *i, *at; + + /* Valid formats: + * + * string@instance.suffix + * string.suffix + */ + + assert(n); + assert(IN_SET(template_ok, TEMPLATE_VALID, TEMPLATE_INVALID)); + + if (strlen(n) >= UNIT_NAME_MAX) + return false; + + e = strrchr(n, '.'); + if (!e || e == n) + return false; + + if (unit_type_from_string(e + 1) < 0) + return false; + + for (i = n, at = NULL; i < e; i++) { + + if (*i == '@' && !at) + at = i; + + if (!strchr("@" VALID_CHARS, *i)) + return false; + } + + if (at) { + if (at == n) + return false; + + if (!template_ok == TEMPLATE_VALID && at+1 == e) + return false; + } + + return true; +} + +bool unit_instance_is_valid(const char *i) { + assert(i); + + /* The max length depends on the length of the string, so we + * don't really check this here. */ + + if (i[0] == 0) + return false; + + /* We allow additional @ in the instance string, we do not + * allow them in the prefix! */ + + for (; *i; i++) + if (!strchr("@" VALID_CHARS, *i)) + return false; + + return true; +} + +bool unit_prefix_is_valid(const char *p) { + + /* We don't allow additional @ in the instance string */ + + if (p[0] == 0) + return false; + + for (; *p; p++) + if (!strchr(VALID_CHARS, *p)) + return false; + + return true; +} + +int unit_name_to_instance(const char *n, char **instance) { + const char *p, *d; + char *i; + + assert(n); + assert(instance); + + /* Everything past the first @ and before the last . is the instance */ + p = strchr(n, '@'); + if (!p) { + *instance = NULL; + return 0; + } + + assert_se(d = strrchr(n, '.')); + assert(p < d); + + i = strndup(p+1, d-p-1); + if (!i) + return -ENOMEM; + + *instance = i; + return 0; +} + +char *unit_name_to_prefix_and_instance(const char *n) { + const char *d; + + assert(n); + + assert_se(d = strrchr(n, '.')); + + return strndup(n, d - n); +} + +char *unit_name_to_prefix(const char *n) { + const char *p; + + p = strchr(n, '@'); + if (p) + return strndup(n, p - n); + + return unit_name_to_prefix_and_instance(n); +} + +char *unit_name_change_suffix(const char *n, const char *suffix) { + char *e, *r; + size_t a, b; + + assert(n); + assert(unit_name_is_valid(n, TEMPLATE_VALID)); + assert(suffix); + assert(suffix[0] == '.'); + + assert_se(e = strrchr(n, '.')); + a = e - n; + b = strlen(suffix); + + r = new(char, a + b + 1); + if (!r) + return NULL; + + memcpy(r, n, a); + memcpy(r+a, suffix, b+1); + + return r; +} + +char *unit_name_build(const char *prefix, const char *instance, const char *suffix) { + assert(prefix); + assert(unit_prefix_is_valid(prefix)); + assert(!instance || unit_instance_is_valid(instance)); + assert(suffix); + + if (!instance) + return strappend(prefix, suffix); + + return strjoin(prefix, "@", instance, suffix, NULL); +} + +static char *do_escape_char(char c, char *t) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(c >> 4); + *(t++) = hexchar(c); + return t; +} + +static char *do_escape(const char *f, char *t) { + assert(f); + assert(t); + + /* do not create units with a leading '.', like for "/.dotdir" mount points */ + if (*f == '.') { + t = do_escape_char(*f, t); + f++; + } + + for (; *f; f++) { + if (*f == '/') + *(t++) = '-'; + else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) + t = do_escape_char(*f, t); + else + *(t++) = *f; + } + + return t; +} + +char *unit_name_escape(const char *f) { + char *r, *t; + + r = new(char, strlen(f)*4+1); + if (!r) + return NULL; + + t = do_escape(f, r); + *t = 0; + + return r; +} + +char *unit_name_unescape(const char *f) { + char *r, *t; + + assert(f); + + r = strdup(f); + if (!r) + return NULL; + + for (t = r; *f; f++) { + if (*f == '-') + *(t++) = '/'; + else if (*f == '\\') { + int a, b; + + if (f[1] != 'x' || + (a = unhexchar(f[2])) < 0 || + (b = unhexchar(f[3])) < 0) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + } else { + *(t++) = (char) ((a << 4) | b); + f += 3; + } + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +char *unit_name_path_escape(const char *f) { + char *p, *e; + + assert(f); + + p = strdup(f); + if (!p) + return NULL; + + path_kill_slashes(p); + + if (streq(p, "/") || streq(p, "")) { + free(p); + return strdup("-"); + } + + e = unit_name_escape(p[0] == '/' ? p + 1 : p); + free(p); + + return e; +} + +char *unit_name_path_unescape(const char *f) { + char *e; + + assert(f); + + e = unit_name_unescape(f); + if (!e) + return NULL; + + if (e[0] != '/') { + char *w; + + w = strappend("/", e); + free(e); + + return w; + } + + return e; +} + +bool unit_name_is_template(const char *n) { + const char *p; + + assert(n); + + p = strchr(n, '@'); + if (!p) + return false; + + return p[1] == '.'; +} + +bool unit_name_is_instance(const char *n) { + const char *p; + + assert(n); + + p = strchr(n, '@'); + if (!p) + return false; + + return p[1] != '.'; +} + +char *unit_name_replace_instance(const char *f, const char *i) { + const char *p, *e; + char *r, *k; + size_t a, b; + + assert(f); + + p = strchr(f, '@'); + if (!p) + return strdup(f); + + e = strrchr(f, '.'); + if (!e) + assert_se(e = strchr(f, 0)); + + a = p - f; + b = strlen(i); + + r = new(char, a + 1 + b + strlen(e) + 1); + if (!r) + return NULL; + + k = mempcpy(r, f, a + 1); + k = mempcpy(k, i, b); + strcpy(k, e); + + return r; +} + +char *unit_name_template(const char *f) { + const char *p, *e; + char *r; + size_t a; + + p = strchr(f, '@'); + if (!p) + return strdup(f); + + assert_se(e = strrchr(f, '.')); + a = p - f + 1; + + r = new(char, a + strlen(e) + 1); + if (!r) + return NULL; + + strcpy(mempcpy(r, f, a), e); + return r; +} + +char *unit_name_from_path(const char *path, const char *suffix) { + char *p, *r; + + assert(path); + assert(suffix); + + p = unit_name_path_escape(path); + if (!p) + return NULL; + + r = strappend(p, suffix); + free(p); + + return r; +} + +char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) { + char *p, *r; + + assert(prefix); + assert(path); + assert(suffix); + + p = unit_name_path_escape(path); + if (!p) + return NULL; + + r = strjoin(prefix, "@", p, suffix, NULL); + free(p); + + return r; +} + +char *unit_name_to_path(const char *name) { + _cleanup_free_ char *w = NULL; + + assert(name); + + w = unit_name_to_prefix(name); + if (!w) + return NULL; + + return unit_name_path_unescape(w); +} + +char *unit_dbus_path_from_name(const char *name) { + _cleanup_free_ char *e = NULL; + + assert(name); + + e = bus_label_escape(name); + if (!e) + return NULL; + + return strappend("/org/freedesktop/systemd1/unit/", e); +} + +int unit_name_from_dbus_path(const char *path, char **name) { + const char *e; + char *n; + + e = startswith(path, "/org/freedesktop/systemd1/unit/"); + if (!e) + return -EINVAL; + + n = bus_label_unescape(e); + if (!n) + return -ENOMEM; + + *name = n; + return 0; +} + + +/** + * Try to turn a string that might not be a unit name into a + * sensible unit name. + */ +char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) { + char *r, *t; + const char *f; + const char* valid_chars = allow_globs == MANGLE_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS; + + assert(name); + assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB)); + + if (is_device_path(name)) + return unit_name_from_path(name, ".device"); + + if (path_is_absolute(name)) + return unit_name_from_path(name, ".mount"); + + /* We'll only escape the obvious characters here, to play + * safe. */ + + r = new(char, strlen(name) * 4 + 1 + sizeof(".service")-1); + if (!r) + return NULL; + + for (f = name, t = r; *f; f++) { + if (*f == '/') + *(t++) = '-'; + else if (!strchr(valid_chars, *f)) + t = do_escape_char(*f, t); + else + *(t++) = *f; + } + + if (unit_name_to_type(name) < 0) + strcpy(t, ".service"); + else + *t = 0; + + return r; +} + + +/** + * Similar to unit_name_mangle(), but is called when we know + * that this is about a specific unit type. + */ +char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix) { + char *r, *t; + const char *f; + + assert(name); + assert(suffix); + assert(suffix[0] == '.'); + + r = new(char, strlen(name) * 4 + strlen(suffix) + 1); + if (!r) + return NULL; + + for (f = name, t = r; *f; f++) { + if (*f == '/') + *(t++) = '-'; + else if (!strchr(VALID_CHARS, *f)) + t = do_escape_char(*f, t); + else + *(t++) = *f; + } + + if (!endswith(name, suffix)) + strcpy(t, suffix); + else + *t = 0; + + return r; +} + +UnitType unit_name_to_type(const char *n) { + const char *e; + + assert(n); + + e = strrchr(n, '.'); + if (!e) + return _UNIT_TYPE_INVALID; + + return unit_type_from_string(e + 1); +} + +int build_subslice(const char *slice, const char*name, char **subslice) { + char *ret; + + assert(slice); + assert(name); + assert(subslice); + + if (streq(slice, "-.slice")) + ret = strappend(name, ".slice"); + else { + char *e; + + e = endswith(slice, ".slice"); + if (!e) + return -EINVAL; + + ret = new(char, (e - slice) + 1 + strlen(name) + 6 + 1); + if (!ret) + return -ENOMEM; + + stpcpy(stpcpy(stpcpy(mempcpy(ret, slice, e - slice), "-"), name), ".slice"); + } + + *subslice = ret; + return 0; +} diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h new file mode 100644 index 0000000..d06d2b2 --- /dev/null +++ b/src/shared/unit-name.h @@ -0,0 +1,114 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" + +#define UNIT_NAME_MAX 256 + +typedef enum UnitType UnitType; +typedef enum UnitLoadState UnitLoadState; + +enum UnitType { + UNIT_SERVICE = 0, + UNIT_SOCKET, + UNIT_BUSNAME, + UNIT_TARGET, + UNIT_SNAPSHOT, + UNIT_DEVICE, + UNIT_MOUNT, + UNIT_AUTOMOUNT, + UNIT_SWAP, + UNIT_TIMER, + UNIT_PATH, + UNIT_SLICE, + UNIT_SCOPE, + _UNIT_TYPE_MAX, + _UNIT_TYPE_INVALID = -1 +}; + +enum UnitLoadState { + UNIT_STUB = 0, + UNIT_LOADED, + UNIT_NOT_FOUND, + UNIT_ERROR, + UNIT_MERGED, + UNIT_MASKED, + _UNIT_LOAD_STATE_MAX, + _UNIT_LOAD_STATE_INVALID = -1 +}; + +const char *unit_type_to_string(UnitType i) _const_; +UnitType unit_type_from_string(const char *s) _pure_; + +const char *unit_load_state_to_string(UnitLoadState i) _const_; +UnitLoadState unit_load_state_from_string(const char *s) _pure_; + +int unit_name_to_instance(const char *n, char **instance); +char* unit_name_to_prefix(const char *n); +char* unit_name_to_prefix_and_instance(const char *n); + +enum template_valid { + TEMPLATE_INVALID, + TEMPLATE_VALID, +}; + +bool unit_name_is_valid(const char *n, enum template_valid template_ok) _pure_; +bool unit_prefix_is_valid(const char *p) _pure_; +bool unit_instance_is_valid(const char *i) _pure_; + +UnitType unit_name_to_type(const char *n) _pure_; + +char *unit_name_change_suffix(const char *n, const char *suffix); + +char *unit_name_build(const char *prefix, const char *instance, const char *suffix); + +char *unit_name_escape(const char *f); +char *unit_name_unescape(const char *f); +char *unit_name_path_escape(const char *f); +char *unit_name_path_unescape(const char *f); + +bool unit_name_is_template(const char *n) _pure_; +bool unit_name_is_instance(const char *n) _pure_; + +char *unit_name_replace_instance(const char *f, const char *i); + +char *unit_name_template(const char *f); + +char *unit_name_from_path(const char *path, const char *suffix); +char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix); +char *unit_name_to_path(const char *name); + +char *unit_dbus_path_from_name(const char *name); +int unit_name_from_dbus_path(const char *path, char **name); + +enum unit_name_mangle { + MANGLE_NOGLOB, + MANGLE_GLOB, +}; + +char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs); +char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix); + +int build_subslice(const char *slice, const char*name, char **subslice); diff --git a/src/shared/utf8.c b/src/shared/utf8.c new file mode 100644 index 0000000..0b524d8 --- /dev/null +++ b/src/shared/utf8.c @@ -0,0 +1,296 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2008-2011 Kay Sievers + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* Parts of this file are based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "utf8.h" +#include "util.h" + +static inline bool is_unicode_valid(uint32_t ch) { + + if (ch >= 0x110000) /* End of unicode space */ + return false; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return false; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return false; + + return true; +} + +static bool is_unicode_control(uint32_t ch) { + + /* + 0 to ' '-1 is the C0 range. + DEL=0x7F, and DEL+1 to 0x9F is C1 range. + '\t' is in C0 range, but more or less harmless and commonly used. + */ + + return (ch < ' ' && ch != '\t' && ch != '\n') || + (0x7F <= ch && ch <= 0x9F); +} + +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) { + unsigned char c = (unsigned char)str[0]; + + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + return 0; +} + +/* decode one unicode char */ +int utf8_encoded_to_unichar(const char *str) { + int unichar; + int len; + int i; + + len = utf8_encoded_expected_len(str); + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -1; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -1; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; +} + +bool utf8_is_printable(const char* str, size_t length) { + const uint8_t *p; + + assert(str); + + for (p = (const uint8_t*) str; length;) { + int encoded_len = utf8_encoded_valid_unichar((const char *)p); + int val = utf8_encoded_to_unichar((const char*)p); + + if (encoded_len < 0 || val < 0 || is_unicode_control(val)) + return false; + + length -= encoded_len; + p += encoded_len; + } + + return true; +} + +const char *utf8_is_valid(const char *str) { + const uint8_t *p; + + assert(str); + + for (p = (const uint8_t*) str; *p; ) { + int len; + + len = utf8_encoded_valid_unichar((const char *)p); + + if (len < 0) + return NULL; + + p += len; + } + + return str; +} + +char *utf8_escape_invalid(const char *str) { + char *p, *s; + + assert(str); + + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; + + while (*str) { + int len; + + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + s = mempcpy(s, str, len); + str += len; + } else { + s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER)); + str += 1; + } + } + *s = '\0'; + + return p; +} + +char *ascii_is_valid(const char *str) { + const char *p; + + assert(str); + + for (p = str; *p; p++) + if ((unsigned char) *p >= 128) + return NULL; + + return (char*) str; +} + +char *utf16_to_utf8(const void *s, size_t length) { + char *r; + const uint8_t *f; + uint8_t *t; + + r = new(char, (length*3+1)/2 + 1); + if (!r) + return NULL; + + t = (uint8_t*) r; + + for (f = s; f < (const uint8_t*) s + length; f += 2) { + uint16_t c; + + c = (f[1] << 8) | f[0]; + + if (c == 0) { + *t = 0; + return r; + } else if (c < 0x80) { + *(t++) = (uint8_t) c; + } else if (c < 0x800) { + *(t++) = (uint8_t) (0xc0 | (c >> 6)); + *(t++) = (uint8_t) (0x80 | (c & 0x3f)); + } else { + *(t++) = (uint8_t) (0xe0 | (c >> 12)); + *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); + *(t++) = (uint8_t) (0x80 | (c & 0x3f)); + } + } + + *t = 0; + + return r; +} + +/* expected size used to encode one unicode char */ +static int utf8_unichar_to_encoded_len(int unichar) { + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + return 6; +} + +/* validate one encoded unicode char and return its length */ +int utf8_encoded_valid_unichar(const char *str) { + int len; + int unichar; + int i; + + len = utf8_encoded_expected_len(str); + if (len == 0) + return -1; + + /* ascii is valid */ + if (len == 1) + return 1; + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -1; + + unichar = utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -1; + + /* check if value has valid range */ + if (!is_unicode_valid(unichar)) + return -1; + + return len; +} diff --git a/src/shared/utf8.h b/src/shared/utf8.h new file mode 100644 index 0000000..c0eb73a --- /dev/null +++ b/src/shared/utf8.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "macro.h" + +#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" + +const char *utf8_is_valid(const char *s) _pure_; +char *ascii_is_valid(const char *s) _pure_; +char *utf8_escape_invalid(const char *s); + +bool utf8_is_printable(const char* str, size_t length) _pure_; + +char *utf16_to_utf8(const void *s, size_t length); + +int utf8_encoded_valid_unichar(const char *str); +int utf8_encoded_to_unichar(const char *str); diff --git a/src/shared/util.c b/src/shared/util.c new file mode 100644 index 0000000..5cb598c --- /dev/null +++ b/src/shared/util.c @@ -0,0 +1,6271 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef basename + +#ifdef HAVE_SYS_AUXV_H +#include +#endif + +#include "macro.h" +#include "util.h" +#include "ioprio.h" +#include "missing.h" +#include "log.h" +#include "strv.h" +#include "label.h" +#include "path-util.h" +#include "exit-status.h" +#include "hashmap.h" +#include "env-util.h" +#include "fileio.h" +#include "device-nodes.h" +#include "utf8.h" +#include "gunicode.h" +#include "virt.h" +#include "def.h" + +int saved_argc = 0; +char **saved_argv = NULL; + +static volatile unsigned cached_columns = 0; +static volatile unsigned cached_lines = 0; + +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 streq_ptr(const char *a, const char *b) { + + /* Like streq(), but tries to make sense of NULL pointers */ + + if (a && b) + return streq(a, b); + + if (!a && !b) + return true; + + return false; +} + +char* endswith(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +bool first_word(const char *s, const char *word) { + size_t sl, wl; + + assert(s); + assert(word); + + sl = strlen(s); + wl = strlen(word); + + if (sl < wl) + return false; + + if (wl == 0) + return true; + + if (memcmp(s, word, wl) != 0) + return false; + + return s[wl] == 0 || + strchr(WHITESPACE, s[wl]); +} + +int close_nointr(int fd) { + int r; + + assert(fd >= 0); + r = close(fd); + + /* Just ignore EINTR; a retry loop is the wrong + * thing to do on Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (_unlikely_(r < 0 && errno == EINTR)) + return 0; + else if (r >= 0) + return r; + else + return -errno; +} + +void close_nointr_nofail(int fd) { + PROTECT_ERRNO; + + /* like close_nointr() but cannot fail, and guarantees errno + * is unchanged */ + + assert_se(close_nointr(fd) == 0); +} + +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + assert(fds || n_fd <= 0); + + for (i = 0; i < n_fd; i++) + close_nointr_nofail(fds[i]); +} + +int unlink_noerrno(const char *path) { + PROTECT_ERRNO; + int r; + + r = unlink(path); + if (r < 0) + return -errno; + + return 0; +} + +int parse_boolean(const char *v) { + assert(v); + + if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || strcaseeq(v, "on")) + return 1; + else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || strcaseeq(v, "off")) + return 0; + + return -EINVAL; +} + +int parse_pid(const char *s, pid_t* ret_pid) { + unsigned long ul = 0; + pid_t pid; + int r; + + assert(s); + assert(ret_pid); + + r = safe_atolu(s, &ul); + if (r < 0) + return r; + + pid = (pid_t) ul; + + if ((unsigned long) pid != ul) + return -ERANGE; + + if (pid <= 0) + return -ERANGE; + + *ret_pid = pid; + return 0; +} + +int parse_uid(const char *s, uid_t* ret_uid) { + unsigned long ul = 0; + uid_t uid; + int r; + + assert(s); + assert(ret_uid); + + r = safe_atolu(s, &ul); + if (r < 0) + return r; + + uid = (uid_t) ul; + + if ((unsigned long) uid != ul) + return -ERANGE; + + *ret_uid = uid; + return 0; +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + errno = 0; + l = strtoull(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_lli = l; + return 0; +} + +int safe_atod(const char *s, double *ret_d) { + char *x = NULL; + double d = 0; + + assert(s); + assert(ret_d); + + RUN_WITH_LOCALE(LC_NUMERIC_MASK, "C") { + errno = 0; + d = strtod(s, &x); + } + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_d = (double) d; + return 0; +} + +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + size_t n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + return n; + } + return n; +} + +/* Split a string into words. */ +char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state) { + char *current; + + current = *state ? *state : (char*) c; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, separator); + if (!*current) + return NULL; + + if (quoted && strchr("\'\"", *current)) { + char quotechar = *(current++); + *l = strcspn_escaped(current, (char[]){quotechar, '\0'}); + *state = current+*l+1; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + *state = current+*l; + } else { + *l = strcspn(current, separator); + *state = current+*l; + } + + return (char*) current; +} + +int get_parent_of_pid(pid_t pid, pid_t *_ppid) { + int r; + _cleanup_free_ char *line = NULL; + long unsigned ppid; + const char *p; + + assert(pid >= 0); + assert(_ppid); + + if (pid == 0) { + *_ppid = getppid(); + return 0; + } + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + /* Let's skip the pid and comm fields. The latter is enclosed + * in () but does not escape any () in its value, so let's + * skip over it manually */ + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " " + "%*c " /* state */ + "%lu ", /* ppid */ + &ppid) != 1) + return -EIO; + + if ((long unsigned) (pid_t) ppid != ppid) + return -ERANGE; + + *_ppid = (pid_t) ppid; + + return 0; +} + +int get_starttime_of_pid(pid_t pid, unsigned long long *st) { + int r; + _cleanup_free_ char *line = NULL; + const char *p; + + assert(pid >= 0); + assert(st); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + /* Let's skip the pid and comm fields. The latter is enclosed + * in () but does not escape any () in its value, so let's + * skip over it manually */ + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " " + "%*c " /* state */ + "%*d " /* ppid */ + "%*d " /* pgrp */ + "%*d " /* session */ + "%*d " /* tty_nr */ + "%*d " /* tpgid */ + "%*u " /* flags */ + "%*u " /* minflt */ + "%*u " /* cminflt */ + "%*u " /* majflt */ + "%*u " /* cmajflt */ + "%*u " /* utime */ + "%*u " /* stime */ + "%*d " /* cutime */ + "%*d " /* cstime */ + "%*d " /* priority */ + "%*d " /* nice */ + "%*d " /* num_threads */ + "%*d " /* itrealvalue */ + "%llu " /* starttime */, + st) != 1) + return -EIO; + + return 0; +} + +int fchmod_umask(int fd, mode_t m) { + mode_t u; + int r; + + u = umask(0777); + r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; + umask(u); + + return r; +} + +char *truncate_nl(char *s) { + assert(s); + + s[strcspn(s, NEWLINE)] = 0; + return s; +} + +int get_process_state(pid_t pid) { + const char *p; + char state; + int r; + _cleanup_free_ char *line = NULL; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " %c", &state) != 1) + return -EIO; + + return (unsigned char) state; +} + +int get_process_comm(pid_t pid, char **name) { + const char *p; + int r; + + assert(name); + assert(pid >= 0); + + p = procfs_file_alloca(pid, "comm"); + + r = read_one_line_file(p, name); + if (r == -ENOENT) + return -ESRCH; + + return r; +} + +int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { + _cleanup_fclose_ FILE *f = NULL; + char *r = NULL, *k; + const char *p; + int c; + + assert(line); + assert(pid >= 0); + + p = procfs_file_alloca(pid, "cmdline"); + + f = fopen(p, "re"); + if (!f) + return -errno; + + if (max_length == 0) { + size_t len = 0, allocated = 0; + + while ((c = getc(f)) != EOF) { + + if (!GREEDY_REALLOC(r, allocated, len+2)) { + free(r); + return -ENOMEM; + } + + r[len++] = isprint(c) ? c : ' '; + } + + if (len > 0) + r[len-1] = 0; + + } else { + bool space = false; + size_t left; + + r = new(char, max_length); + if (!r) + return -ENOMEM; + + k = r; + left = max_length; + while ((c = getc(f)) != EOF) { + + if (isprint(c)) { + if (space) { + if (left <= 4) + break; + + *(k++) = ' '; + left--; + space = false; + } + + if (left <= 4) + break; + + *(k++) = (char) c; + left--; + } else + space = true; + } + + if (left <= 4) { + size_t n = MIN(left-1, 3U); + memcpy(k, "...", n); + k[n] = 0; + } else + *k = 0; + } + + /* Kernel threads have no argv[] */ + if (r == NULL || r[0] == 0) { + _cleanup_free_ char *t = NULL; + int h; + + free(r); + + if (!comm_fallback) + return -ENOENT; + + h = get_process_comm(pid, &t); + if (h < 0) + return h; + + r = strjoin("[", t, "]", NULL); + if (!r) + return -ENOMEM; + } + + *line = r; + return 0; +} + +int is_kernel_thread(pid_t pid) { + const char *p; + size_t count; + char c; + bool eof; + FILE *f; + + if (pid == 0) + return 0; + + assert(pid > 0); + + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); + if (!f) + return -errno; + + count = fread(&c, 1, 1, f); + eof = feof(f); + fclose(f); + + /* Kernel threads have an empty cmdline */ + + if (count <= 0) + return eof ? 1 : -errno; + + return 0; +} + +int get_process_capeff(pid_t pid, char **capeff) { + const char *p; + + assert(capeff); + assert(pid >= 0); + + p = procfs_file_alloca(pid, "status"); + + return get_status_field(p, "\nCapEff:", capeff); +} + +int get_process_exe(pid_t pid, char **name) { + const char *p; + char *d; + int r; + + assert(pid >= 0); + assert(name); + + p = procfs_file_alloca(pid, "exe"); + + r = readlink_malloc(p, name); + if (r < 0) + return r == -ENOENT ? -ESRCH : r; + + d = endswith(*name, " (deleted)"); + if (d) + *d = '\0'; + + return 0; +} + +static int get_process_id(pid_t pid, const char *field, uid_t *uid) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + const char *p; + + assert(field); + assert(uid); + + if (pid == 0) + return getuid(); + + p = procfs_file_alloca(pid, "status"); + f = fopen(p, "re"); + if (!f) + return -errno; + + FOREACH_LINE(line, f, return -errno) { + char *l; + + l = strstrip(line); + + if (startswith(l, field)) { + l += strlen(field); + l += strspn(l, WHITESPACE); + + l[strcspn(l, WHITESPACE)] = 0; + + return parse_uid(l, uid); + } + } + + return -EIO; +} + +int get_process_uid(pid_t pid, uid_t *uid) { + return get_process_id(pid, "Uid:", uid); +} + +int get_process_gid(pid_t pid, gid_t *gid) { + assert_cc(sizeof(uid_t) == sizeof(gid_t)); + return get_process_id(pid, "Gid:", gid); +} + +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; + char *r; + + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + + assert(s); + assert(suffix); + + a = strlen(s); + if (b > ((size_t) -1) - a) + return NULL; + + r = new(char, a+b+1); + if (!r) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + +int readlink_malloc(const char *p, char **ret) { + size_t l = 100; + int r; + + assert(p); + assert(ret); + + for (;;) { + char *c; + ssize_t n; + + c = new(char, l); + if (!c) + return -ENOMEM; + + n = readlink(p, c, l-1); + if (n < 0) { + r = -errno; + free(c); + return r; + } + + if ((size_t) n < l-1) { + c[n] = 0; + *ret = c; + return 0; + } + + free(c); + l *= 2; + } +} + +int readlink_and_make_absolute(const char *p, char **r) { + _cleanup_free_ char *target = NULL; + char *k; + int j; + + assert(p); + assert(r); + + j = readlink_malloc(p, &target); + if (j < 0) + return j; + + k = file_in_same_dir(p, target); + if (!k) + return -ENOMEM; + + *r = k; + return 0; +} + +int readlink_and_canonicalize(const char *p, char **r) { + char *t, *s; + int j; + + assert(p); + assert(r); + + j = readlink_and_make_absolute(p, &t); + if (j < 0) + return j; + + s = canonicalize_file_name(t); + if (s) { + free(t); + *r = s; + } else + *r = t; + + path_kill_slashes(*r); + + return 0; +} + +int reset_all_signal_handlers(void) { + int sig; + + for (sig = 1; sig < _NSIG; sig++) { + struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + + if (sig == SIGKILL || sig == SIGSTOP) + continue; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if ((sigaction(sig, &sa, NULL) < 0)) + if (errno != EINVAL) + return -errno; + } + + return 0; +} + +char *strstrip(char *s) { + char *e; + + /* Drops trailing whitespace. Modifies the string in + * place. Returns pointer to first non-space character */ + + s += strspn(s, WHITESPACE); + + for (e = strchr(s, 0); e > s; e --) + if (!strchr(WHITESPACE, e[-1])) + break; + + *e = 0; + + return s; +} + +char *delete_chars(char *s, const char *bad) { + char *f, *t; + + /* Drops all whitespace, regardless where in the string */ + + for (f = s, t = s; *f; f++) { + if (strchr(bad, *f)) + continue; + + *(t++) = *f; + } + + *t = 0; + + return s; +} + +bool in_charset(const char *s, const char* charset) { + const char *i; + + assert(s); + assert(charset); + + for (i = s; *i; i++) + if (!strchr(charset, *i)) + return false; + + return true; +} + +char *file_in_same_dir(const char *path, const char *filename) { + char *e, *r; + size_t k; + + assert(path); + assert(filename); + + /* This removes the last component of path and appends + * filename, unless the latter is absolute anyway or the + * former isn't */ + + if (path_is_absolute(filename)) + return strdup(filename); + + if (!(e = strrchr(path, '/'))) + return strdup(filename); + + k = strlen(filename); + if (!(r = new(char, e-path+1+k+1))) + return NULL; + + memcpy(r, path, e-path+1); + memcpy(r+(e-path)+1, filename, k+1); + + return r; +} + +int rmdir_parents(const char *path, const char *stop) { + size_t l; + int r = 0; + + assert(path); + assert(stop); + + l = strlen(path); + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + while (l > 0) { + char *t; + + /* Skip last component */ + while (l > 0 && path[l-1] != '/') + l--; + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + if (l <= 0) + break; + + if (!(t = strndup(path, l))) + return -ENOMEM; + + if (path_startswith(stop, t)) { + free(t); + return 0; + } + + r = rmdir(t); + free(t); + + if (r < 0) + if (errno != ENOENT) + return -errno; + } + + return 0; +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +int unhexchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -1; +} + +char *hexmem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + z = r = malloc(l * 2 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + l; x++) { + *(z++) = hexchar(*x >> 4); + *(z++) = hexchar(*x & 15); + } + + *z = 0; + return r; +} + +void *unhexmem(const char *p, size_t l) { + uint8_t *r, *z; + const char *x; + + assert(p); + + z = r = malloc((l + 1) / 2 + 1); + if (!r) + return NULL; + + for (x = p; x < p + l; x += 2) { + int a, b; + + a = unhexchar(x[0]); + if (x+1 < p + l) + b = unhexchar(x[1]); + else + b = 0; + + *(z++) = (uint8_t) a << 4 | (uint8_t) b; + } + + *z = 0; + return r; +} + +char octchar(int x) { + return '0' + (x & 7); +} + +int unoctchar(char c) { + + if (c >= '0' && c <= '7') + return c - '0'; + + return -1; +} + +char decchar(int x) { + return '0' + (x % 10); +} + +int undecchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + return -1; +} + +char *cescape(const char *s) { + char *r, *t; + const char *f; + + assert(s); + + /* Does C style string escaping. */ + + r = new(char, strlen(s)*4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) + + switch (*f) { + + case '\a': + *(t++) = '\\'; + *(t++) = 'a'; + break; + case '\b': + *(t++) = '\\'; + *(t++) = 'b'; + break; + case '\f': + *(t++) = '\\'; + *(t++) = 'f'; + break; + case '\n': + *(t++) = '\\'; + *(t++) = 'n'; + break; + case '\r': + *(t++) = '\\'; + *(t++) = 'r'; + break; + case '\t': + *(t++) = '\\'; + *(t++) = 't'; + break; + case '\v': + *(t++) = '\\'; + *(t++) = 'v'; + break; + case '\\': + *(t++) = '\\'; + *(t++) = '\\'; + break; + case '"': + *(t++) = '\\'; + *(t++) = '"'; + break; + case '\'': + *(t++) = '\\'; + *(t++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((*f < ' ') || (*f >= 127)) { + *(t++) = '\\'; + *(t++) = octchar((unsigned char) *f >> 6); + *(t++) = octchar((unsigned char) *f >> 3); + *(t++) = octchar((unsigned char) *f); + } else + *(t++) = *f; + break; + } + + *t = 0; + + return r; +} + +char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { + char *r, *t; + const char *f; + size_t pl; + + assert(s); + + /* Undoes C style string escaping, and optionally prefixes it. */ + + pl = prefix ? strlen(prefix) : 0; + + r = new(char, pl+length+1); + if (!r) + return r; + + if (prefix) + memcpy(r, prefix, pl); + + for (f = s, t = r + pl; f < s + length; f++) { + + if (*f != '\\') { + *(t++) = *f; + continue; + } + + f++; + + switch (*f) { + + case 'a': + *(t++) = '\a'; + break; + case 'b': + *(t++) = '\b'; + break; + case 'f': + *(t++) = '\f'; + break; + case 'n': + *(t++) = '\n'; + break; + case 'r': + *(t++) = '\r'; + break; + case 't': + *(t++) = '\t'; + break; + case 'v': + *(t++) = '\v'; + break; + case '\\': + *(t++) = '\\'; + break; + case '"': + *(t++) = '"'; + break; + case '\'': + *(t++) = '\''; + break; + + case 's': + /* This is an extension of the XDG syntax files */ + *(t++) = ' '; + break; + + case 'x': { + /* hexadecimal encoding */ + int a, b; + + a = unhexchar(f[1]); + b = unhexchar(f[2]); + + if (a < 0 || b < 0) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + *(t++) = 'x'; + } else { + *(t++) = (char) ((a << 4) | b); + f += 2; + } + + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + /* octal encoding */ + int a, b, c; + + a = unoctchar(f[0]); + b = unoctchar(f[1]); + c = unoctchar(f[2]); + + if (a < 0 || b < 0 || c < 0) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + *(t++) = f[0]; + } else { + *(t++) = (char) ((a << 6) | (b << 3) | c); + f += 2; + } + + break; + } + + case 0: + /* premature end of string.*/ + *(t++) = '\\'; + goto finish; + + default: + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + *(t++) = *f; + break; + } + } + +finish: + *t = 0; + return r; +} + +char *cunescape_length(const char *s, size_t length) { + return cunescape_length_with_prefix(s, length, NULL); +} + +char *cunescape(const char *s) { + assert(s); + + return cunescape_length(s, strlen(s)); +} + +char *xescape(const char *s, const char *bad) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with + * cunescape. */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + if ((*f < ' ') || (*f >= 127) || + (*f == '\\') || strchr(bad, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +char *ascii_strlower(char *t) { + char *p; + + assert(t); + + for (p = t; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p = *p - 'A' + 'a'; + + return t; +} + +_pure_ static bool ignore_file_allow_backup(const char *filename) { + assert(filename); + + return + filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, ".rpmnew") || + endswith(filename, ".rpmsave") || + endswith(filename, ".rpmorig") || + endswith(filename, ".dpkg-old") || + endswith(filename, ".dpkg-new") || + endswith(filename, ".swp"); +} + +bool ignore_file(const char *filename) { + assert(filename); + + if (endswith(filename, "~")) + return false; + + return ignore_file_allow_backup(filename); +} + +int fd_nonblock(int fd, bool nonblock) { + int flags; + + assert(fd >= 0); + + if ((flags = fcntl(fd, F_GETFL, 0)) < 0) + return -errno; + + if (nonblock) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + + if (fcntl(fd, F_SETFL, flags) < 0) + return -errno; + + return 0; +} + +int fd_cloexec(int fd, bool cloexec) { + int flags; + + assert(fd >= 0); + + if ((flags = fcntl(fd, F_GETFD, 0)) < 0) + return -errno; + + if (cloexec) + flags |= FD_CLOEXEC; + else + flags &= ~FD_CLOEXEC; + + if (fcntl(fd, F_SETFD, flags) < 0) + return -errno; + + return 0; +} + +_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { + unsigned i; + + assert(n_fdset == 0 || fdset); + + for (i = 0; i < n_fdset; i++) + if (fdset[i] == fd) + return true; + + return false; +} + +int close_all_fds(const int except[], unsigned n_except) { + DIR *d; + struct dirent *de; + int r = 0; + + assert(n_except == 0 || except); + + d = opendir("/proc/self/fd"); + if (!d) { + int fd; + struct rlimit rl; + + /* When /proc isn't available (for example in chroots) + * the fallback is brute forcing through the fd + * table */ + + assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); + for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; + } + + return r; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (ignore_file(de->d_name)) + continue; + + if (safe_atoi(de->d_name, &fd) < 0) + /* Let's better ignore this, just in case */ + continue; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } + } + + closedir(d); + return r; +} + +bool chars_intersect(const char *a, const char *b) { + const char *p; + + /* Returns true if any of the chars in a are in b. */ + for (p = a; *p; p++) + if (strchr(b, *p)) + return true; + + return false; +} + +bool fstype_is_network(const char *fstype) { + static const char table[] = + "cifs\0" + "smbfs\0" + "ncpfs\0" + "ncp\0" + "nfs\0" + "nfs4\0" + "gfs\0" + "gfs2\0"; + + return nulstr_contains(table, fstype); +} + +int chvt(int vt) { + _cleanup_close_ int fd; + + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return -errno; + + if (vt < 0) { + int tiocl[2] = { + TIOCL_GETKMSGREDIRECT, + 0 + }; + + if (ioctl(fd, TIOCLINUX, tiocl) < 0) + return -errno; + + vt = tiocl[0] <= 0 ? 1 : tiocl[0]; + } + + if (ioctl(fd, VT_ACTIVATE, vt) < 0) + return -errno; + + return 0; +} + +int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { + struct termios old_termios, new_termios; + char c; + char line[LINE_MAX]; + + assert(f); + assert(ret); + + if (tcgetattr(fileno(f), &old_termios) >= 0) { + new_termios = old_termios; + + new_termios.c_lflag &= ~ICANON; + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) { + size_t k; + + if (t != (usec_t) -1) { + if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) { + tcsetattr(fileno(f), TCSADRAIN, &old_termios); + return -ETIMEDOUT; + } + } + + k = fread(&c, 1, 1, f); + + tcsetattr(fileno(f), TCSADRAIN, &old_termios); + + if (k <= 0) + return -EIO; + + if (need_nl) + *need_nl = c != '\n'; + + *ret = c; + return 0; + } + } + + if (t != (usec_t) -1) + if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) + return -ETIMEDOUT; + + if (!fgets(line, sizeof(line), f)) + return -EIO; + + truncate_nl(line); + + if (strlen(line) != 1) + return -EBADMSG; + + if (need_nl) + *need_nl = false; + + *ret = line[0]; + return 0; +} + +int ask(char *ret, const char *replies, const char *text, ...) { + + assert(ret); + assert(replies); + assert(text); + + for (;;) { + va_list ap; + char c; + int r; + bool need_nl = true; + + if (on_tty()) + fputs(ANSI_HIGHLIGHT_ON, stdout); + + va_start(ap, text); + vprintf(text, ap); + va_end(ap); + + if (on_tty()) + fputs(ANSI_HIGHLIGHT_OFF, stdout); + + fflush(stdout); + + r = read_one_char(stdin, &c, (usec_t) -1, &need_nl); + if (r < 0) { + + if (r == -EBADMSG) { + puts("Bad input, please try again."); + continue; + } + + putchar('\n'); + return r; + } + + if (need_nl) + putchar('\n'); + + if (strchr(replies, c)) { + *ret = c; + return 0; + } + + puts("Read unexpected character, please try again."); + } +} + +int reset_terminal_fd(int fd, bool switch_to_text) { + struct termios termios; + int r = 0; + + /* Set terminal to some sane defaults */ + + assert(fd >= 0); + + /* We leave locked terminal attributes untouched, so that + * Plymouth may set whatever it wants to set, and we don't + * interfere with that. */ + + /* Disable exclusive mode, just in case */ + ioctl(fd, TIOCNXCL); + + /* Switch to text mode */ + if (switch_to_text) + ioctl(fd, KDSETMODE, KD_TEXT); + + /* Enable console unicode mode */ + ioctl(fd, KDSKBMODE, K_UNICODE); + + if (tcgetattr(fd, &termios) < 0) { + r = -errno; + goto finish; + } + + /* We only reset the stuff that matters to the software. How + * hardware is set up we don't touch assuming that somebody + * else will do that for us */ + + termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC); + termios.c_iflag |= ICRNL | IMAXBEL | IUTF8; + termios.c_oflag |= ONLCR; + termios.c_cflag |= CREAD; + termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE; + + termios.c_cc[VINTR] = 03; /* ^C */ + termios.c_cc[VQUIT] = 034; /* ^\ */ + termios.c_cc[VERASE] = 0177; + termios.c_cc[VKILL] = 025; /* ^X */ + termios.c_cc[VEOF] = 04; /* ^D */ + termios.c_cc[VSTART] = 021; /* ^Q */ + termios.c_cc[VSTOP] = 023; /* ^S */ + termios.c_cc[VSUSP] = 032; /* ^Z */ + termios.c_cc[VLNEXT] = 026; /* ^V */ + termios.c_cc[VWERASE] = 027; /* ^W */ + termios.c_cc[VREPRINT] = 022; /* ^R */ + termios.c_cc[VEOL] = 0; + termios.c_cc[VEOL2] = 0; + + termios.c_cc[VTIME] = 0; + termios.c_cc[VMIN] = 1; + + if (tcsetattr(fd, TCSANOW, &termios) < 0) + r = -errno; + +finish: + /* Just in case, flush all crap out */ + tcflush(fd, TCIOFLUSH); + + return r; +} + +int reset_terminal(const char *name) { + int fd, r; + + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = reset_terminal_fd(fd, true); + close_nointr_nofail(fd); + + return r; +} + +int open_terminal(const char *name, int mode) { + int fd, r; + unsigned c = 0; + + /* + * If a TTY is in the process of being closed opening it might + * cause EIO. This is horribly awful, but unlikely to be + * changed in the kernel. Hence we work around this problem by + * retrying a couple of times. + * + * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 + */ + + assert(!(mode & O_CREAT)); + + for (;;) { + fd = open(name, mode, 0); + if (fd >= 0) + break; + + if (errno != EIO) + return -errno; + + /* Max 1s in total */ + if (c >= 20) + return -errno; + + usleep(50 * USEC_PER_MSEC); + c++; + } + + if (fd < 0) + return -errno; + + r = isatty(fd); + if (r < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (!r) { + close_nointr_nofail(fd); + return -ENOTTY; + } + + return fd; +} + +int flush_fd(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + l = read(fd, buf, sizeof(buf)); + if (l < 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } else if (l == 0) + return 0; + } +} + +int acquire_terminal( + const char *name, + bool fail, + bool force, + bool ignore_tiocstty_eperm, + usec_t timeout) { + + int fd = -1, notify = -1, r = 0, wd = -1; + usec_t ts = 0; + + assert(name); + + /* We use inotify to be notified when the tty is closed. We + * create the watch before checking if we can actually acquire + * it, so that we don't lose any event. + * + * Note: strictly speaking this actually watches for the + * device being closed, it does *not* really watch whether a + * tty loses its controlling process. However, unless some + * rogue process uses TIOCNOTTY on /dev/tty *after* closing + * its tty otherwise this will not become a problem. As long + * as the administrator makes sure not configure any service + * on the same tty as an untrusted user this should not be a + * problem. (Which he probably should not do anyway.) */ + + if (timeout != (usec_t) -1) + ts = now(CLOCK_MONOTONIC); + + if (!fail && !force) { + notify = inotify_init1(IN_CLOEXEC | (timeout != (usec_t) -1 ? IN_NONBLOCK : 0)); + if (notify < 0) { + r = -errno; + goto fail; + } + + wd = inotify_add_watch(notify, name, IN_CLOSE); + if (wd < 0) { + r = -errno; + goto fail; + } + } + + for (;;) { + struct sigaction sa_old, sa_new = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + + if (notify >= 0) { + r = flush_fd(notify); + if (r < 0) + goto fail; + } + + /* We pass here O_NOCTTY only so that we can check the return + * value TIOCSCTTY and have a reliable way to figure out if we + * successfully became the controlling process of the tty */ + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed + * if we already own the tty. */ + assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); + + /* First, try to get the tty */ + if (ioctl(fd, TIOCSCTTY, force) < 0) + r = -errno; + + assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); + + /* Sometimes it makes sense to ignore TIOCSCTTY + * returning EPERM, i.e. when very likely we already + * are have this controlling terminal. */ + if (r < 0 && r == -EPERM && ignore_tiocstty_eperm) + r = 0; + + if (r < 0 && (force || fail || r != -EPERM)) { + goto fail; + } + + if (r >= 0) + break; + + assert(!fail); + assert(!force); + assert(notify >= 0); + + for (;;) { + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; + ssize_t l; + struct inotify_event *e; + + if (timeout != (usec_t) -1) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + if (ts + timeout < n) { + r = -ETIMEDOUT; + goto fail; + } + + r = fd_wait_for_event(fd, POLLIN, ts + timeout - n); + if (r < 0) + goto fail; + + if (r == 0) { + r = -ETIMEDOUT; + goto fail; + } + } + + l = read(notify, inotify_buffer, sizeof(inotify_buffer)); + if (l < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + r = -errno; + goto fail; + } + + e = (struct inotify_event*) inotify_buffer; + + while (l > 0) { + size_t step; + + if (e->wd != wd || !(e->mask & IN_CLOSE)) { + r = -EIO; + goto fail; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) l); + + e = (struct inotify_event*) ((uint8_t*) e + step); + l -= step; + } + + break; + } + + /* We close the tty fd here since if the old session + * ended our handle will be dead. It's important that + * we do this after sleeping, so that we don't enter + * an endless loop. */ + close_nointr_nofail(fd); + } + + if (notify >= 0) + close_nointr_nofail(notify); + + r = reset_terminal_fd(fd, true); + if (r < 0) + log_warning("Failed to reset terminal: %s", strerror(-r)); + + return fd; + +fail: + if (fd >= 0) + close_nointr_nofail(fd); + + if (notify >= 0) + close_nointr_nofail(notify); + + return r; +} + +int release_terminal(void) { + int r = 0; + struct sigaction sa_old, sa_new = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + _cleanup_close_ int fd; + + fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC); + if (fd < 0) + return -errno; + + /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed + * by our own TIOCNOTTY */ + assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); + + if (ioctl(fd, TIOCNOTTY) < 0) + r = -errno; + + assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); + + return r; +} + +int sigaction_many(const struct sigaction *sa, ...) { + va_list ap; + int r = 0, sig; + + va_start(ap, sa); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +int ignore_signals(int sig, ...) { + struct sigaction sa = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + va_list ap; + int r = 0; + + + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + + va_start(ap, sig); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +int default_signals(int sig, ...) { + struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + va_list ap; + int r = 0; + + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + + va_start(ap, sig); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +int close_pipe(int p[]) { + int a = 0, b = 0; + + assert(p); + + if (p[0] >= 0) { + a = close_nointr(p[0]); + p[0] = -1; + } + + if (p[1] >= 0) { + b = close_nointr(p[1]); + p[1] = -1; + } + + return a < 0 ? a : b; +} + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { + uint8_t *p = buf; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + while (nbytes > 0) { + ssize_t k; + + k = read(fd, p, nbytes); + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ + + fd_wait_for_event(fd, POLLIN, (usec_t) -1); + continue; + } + + if (k <= 0) + return n > 0 ? n : (k < 0 ? -errno : 0); + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + +ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p = buf; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + while (nbytes > 0) { + ssize_t k; + + k = write(fd, p, nbytes); + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via write() */ + + fd_wait_for_event(fd, POLLOUT, (usec_t) -1); + continue; + } + + if (k <= 0) + return n > 0 ? n : (k < 0 ? -errno : 0); + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + +int parse_size(const char *t, off_t base, off_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffxies, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardrware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { + const char *suffix; + unsigned long long factor; + }; + + static const struct table iec[] = { + { "B", 1 }, + { "K", 1024ULL }, + { "M", 1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "", 1 }, + }; + + static const struct table si[] = { + { "B", 1 }, + { "K", 1000ULL }, + { "M", 1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "", 1 }, + }; + + const struct table *table; + const char *p; + unsigned long long r = 0; + unsigned n_entries; + + assert(t); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } + + p = t; + do { + long long l; + char *e; + unsigned i; + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < n_entries; i++) + if (startswith(e, table[i].suffix)) { + unsigned long long tmp; + if ((unsigned long long) l > ULLONG_MAX / table[i].factor) + return -ERANGE; + tmp = l * table[i].factor; + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (off_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + break; + } + + if (i >= n_entries) + return -EINVAL; + + } while (*p); + + *size = r; + + return 0; +} + +int make_stdio(int fd) { + int r, s, t; + + assert(fd >= 0); + + r = dup3(fd, STDIN_FILENO, 0); + s = dup3(fd, STDOUT_FILENO, 0); + t = dup3(fd, STDERR_FILENO, 0); + + if (fd >= 3) + close_nointr_nofail(fd); + + if (r < 0 || s < 0 || t < 0) + return -errno; + + /* We rely here that the new fd has O_CLOEXEC not set */ + + return 0; +} + +int make_null_stdio(void) { + int null_fd; + + null_fd = open("/dev/null", O_RDWR|O_NOCTTY); + if (null_fd < 0) + return -errno; + + return make_stdio(null_fd); +} + +bool is_device_path(const char *path) { + + /* Returns true on paths that refer to a device, either in + * sysfs or in /dev */ + + return + path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} + +int dir_is_empty(const char *path) { + _cleanup_closedir_ DIR *d; + + d = opendir(path); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + return 1; + + if (!ignore_file(de->d_name)) + return 0; + } +} + +char* dirname_malloc(const char *path) { + char *d, *dir, *dir2; + + d = strdup(path); + if (!d) + return NULL; + dir = dirname(d); + assert(dir); + + if (dir != d) { + dir2 = strdup(dir); + free(d); + return dir2; + } + + return dir; +} + +int dev_urandom(void *p, size_t n) { + _cleanup_close_ int fd; + ssize_t k; + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return errno == ENOENT ? -ENOSYS : -errno; + + k = loop_read(fd, p, n, true); + if (k < 0) + return (int) k; + if ((size_t) k != n) + return -EIO; + + return 0; +} + +void random_bytes(void *p, size_t n) { + static bool srand_called = false; + uint8_t *q; + int r; + + r = dev_urandom(p, n); + if (r >= 0) + return; + + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ + + if (!srand_called) { + unsigned x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in + * auxv, so let's try to make use of that to seed the + * pseudo-random generator. It's better than + * nothing... */ + + void *auxv; + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; + } + + for (q = p; q < (uint8_t*) p + n; q ++) + *q = rand(); +} + +void rename_process(const char name[8]) { + assert(name); + + /* This is a like a poor man's setproctitle(). It changes the + * comm field, argv[0], and also the glibc's internally used + * name of the process. For the first one a limit of 16 chars + * applies, to the second one usually one of 10 (i.e. length + * of "/sbin/init"), to the third one one of 7 (i.e. length of + * "systemd"). If you pass a longer string it will be + * truncated */ + + prctl(PR_SET_NAME, name); + + if (program_invocation_name) + strncpy(program_invocation_name, name, strlen(program_invocation_name)); + + if (saved_argc > 0) { + int i; + + if (saved_argv[0]) + strncpy(saved_argv[0], name, strlen(saved_argv[0])); + + for (i = 1; i < saved_argc; i++) { + if (!saved_argv[i]) + break; + + memzero(saved_argv[i], strlen(saved_argv[i])); + } + } +} + +void sigset_add_many(sigset_t *ss, ...) { + va_list ap; + int sig; + + assert(ss); + + va_start(ap, ss); + while ((sig = va_arg(ap, int)) > 0) + assert_se(sigaddset(ss, sig) == 0); + va_end(ap); +} + +char* gethostname_malloc(void) { + struct utsname u; + + assert_se(uname(&u) >= 0); + + if (!isempty(u.nodename) && !streq(u.nodename, "(none)")) + return strdup(u.nodename); + + return strdup(u.sysname); +} + +bool hostname_is_set(void) { + struct utsname u; + + assert_se(uname(&u) >= 0); + + return !isempty(u.nodename) && !streq(u.nodename, "(none)"); +} + +static char *lookup_uid(uid_t uid) { + long bufsize; + char *name; + _cleanup_free_ char *buf = NULL; + struct passwd pwbuf, *pw = NULL; + + /* Shortcut things to avoid NSS lookups */ + if (uid == 0) + return strdup("root"); + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize <= 0) + bufsize = 4096; + + buf = malloc(bufsize); + if (!buf) + return NULL; + + if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) + return strdup(pw->pw_name); + + if (asprintf(&name, "%lu", (unsigned long) uid) < 0) + return NULL; + + return name; +} + +char* getlogname_malloc(void) { + uid_t uid; + struct stat st; + + if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) + uid = st.st_uid; + else + uid = getuid(); + + return lookup_uid(uid); +} + +char *getusername_malloc(void) { + const char *e; + + e = getenv("USER"); + if (e) + return strdup(e); + + return lookup_uid(getuid()); +} + +int getttyname_malloc(int fd, char **r) { + char path[PATH_MAX], *c; + int k; + + assert(r); + + k = ttyname_r(fd, path, sizeof(path)); + if (k > 0) + return -k; + + char_array_0(path); + + c = strdup(startswith(path, "/dev/") ? path + 5 : path); + if (!c) + return -ENOMEM; + + *r = c; + return 0; +} + +int getttyname_harder(int fd, char **r) { + int k; + char *s; + + k = getttyname_malloc(fd, &s); + if (k < 0) + return k; + + if (streq(s, "tty")) { + free(s); + return get_ctty(0, NULL, r); + } + + *r = s; + return 0; +} + +int get_ctty_devnr(pid_t pid, dev_t *d) { + int r; + _cleanup_free_ char *line = NULL; + const char *p; + unsigned long ttynr; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " " + "%*c " /* state */ + "%*d " /* ppid */ + "%*d " /* pgrp */ + "%*d " /* session */ + "%lu ", /* ttynr */ + &ttynr) != 1) + return -EIO; + + if (major(ttynr) == 0 && minor(ttynr) == 0) + return -ENOENT; + + if (d) + *d = (dev_t) ttynr; + + return 0; +} + +int get_ctty(pid_t pid, dev_t *_devnr, char **r) { + char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; + _cleanup_free_ char *s = NULL; + const char *p; + dev_t devnr; + int k; + + assert(r); + + k = get_ctty_devnr(pid, &devnr); + if (k < 0) + return k; + + snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr)); + + k = readlink_malloc(fn, &s); + if (k < 0) { + + if (k != -ENOENT) + return k; + + /* This is an ugly hack */ + if (major(devnr) == 136) { + asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)); + goto finish; + } + + /* Probably something like the ptys which have no + * symlink in /dev/char. Let's return something + * vaguely useful. */ + + b = strdup(fn + 5); + goto finish; + } + + if (startswith(s, "/dev/")) + p = s + 5; + else if (startswith(s, "../")) + p = s + 3; + else + p = s; + + b = strdup(p); + +finish: + if (!b) + return -ENOMEM; + + *r = b; + if (_devnr) + *_devnr = devnr; + + return 0; +} + +int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { + DIR *d; + int ret = 0; + + assert(fd >= 0); + + /* This returns the first error we run into, but nevertheless + * tries to go on. This closes the passed fd. */ + + d = fdopendir(fd); + if (!d) { + close_nointr_nofail(fd); + + return errno == ENOENT ? 0 : -errno; + } + + for (;;) { + struct dirent *de; + bool is_dir, keep_around; + struct stat st; + int r; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + if (ret == 0) + ret = -errno; + break; + } + + if (!de) + break; + + if (streq(de->d_name, ".") || streq(de->d_name, "..")) + continue; + + if (de->d_type == DT_UNKNOWN || + honour_sticky || + (de->d_type == DT_DIR && root_dev)) { + if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + continue; + } + + is_dir = S_ISDIR(st.st_mode); + keep_around = + honour_sticky && + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); + } else { + is_dir = de->d_type == DT_DIR; + keep_around = false; + } + + if (is_dir) { + int subdir_fd; + + /* if root_dev is set, remove subdirectories only, if device is same as dir */ + if (root_dev && st.st_dev != root_dev->st_dev) + continue; + + subdir_fd = openat(fd, de->d_name, + O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (subdir_fd < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + continue; + } + + r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev); + if (r < 0 && ret == 0) + ret = r; + + if (!keep_around) + if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + } + + } else if (!only_dirs && !keep_around) { + + if (unlinkat(fd, de->d_name, 0) < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + } + } + } + + closedir(d); + + return ret; +} + +_pure_ static int is_temporary_fs(struct statfs *s) { + assert(s); + + return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) || + F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC); +} + +int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { + struct statfs s; + + assert(fd >= 0); + + if (fstatfs(fd, &s) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + /* We refuse to clean disk file systems with this call. This + * is extra paranoia just to be sure we never ever remove + * non-state data */ + if (!is_temporary_fs(&s)) { + log_error("Attempted to remove disk file system, and we can't allow that."); + close_nointr_nofail(fd); + return -EPERM; + } + + return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev); +} + +static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) { + int fd, r; + struct statfs s; + + assert(path); + + /* We refuse to clean the root file system with this + * call. This is extra paranoia to never cause a really + * seriously broken system. */ + if (path_equal(path, "/")) { + log_error("Attempted to remove entire root file system, and we can't allow that."); + return -EPERM; + } + + fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (fd < 0) { + + if (errno != ENOTDIR) + return -errno; + + if (!dangerous) { + if (statfs(path, &s) < 0) + return -errno; + + if (!is_temporary_fs(&s)) { + log_error("Attempted to remove disk file system, and we can't allow that."); + return -EPERM; + } + } + + if (delete_root && !only_dirs) + if (unlink(path) < 0 && errno != ENOENT) + return -errno; + + return 0; + } + + if (!dangerous) { + if (fstatfs(fd, &s) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (!is_temporary_fs(&s)) { + log_error("Attempted to remove disk file system, and we can't allow that."); + close_nointr_nofail(fd); + return -EPERM; + } + } + + r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL); + if (delete_root) { + + if (honour_sticky && file_is_priv_sticky(path) > 0) + return r; + + if (rmdir(path) < 0 && errno != ENOENT) { + if (r == 0) + r = -errno; + } + } + + return r; +} + +int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { + return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false); +} + +int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { + return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true); +} + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { + 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. */ + + if (mode != (mode_t) -1) + if (chmod(path, mode) < 0) + return -errno; + + if (uid != (uid_t) -1 || gid != (gid_t) -1) + if (chown(path, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { + assert(fd >= 0); + + /* 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_t) -1) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != (uid_t) -1 || gid != (gid_t) -1) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} + +cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + cpu_set_t *r; + unsigned n = 1024; + + /* Allocates the cpuset in the right size */ + + for (;;) { + if (!(r = CPU_ALLOC(n))) + return NULL; + + if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { + CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); + + if (ncpus) + *ncpus = n; + + return r; + } + + CPU_FREE(r); + + if (errno != EINVAL) + return NULL; + + n *= 2; + } +} + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { + static const char status_indent[] = " "; /* "[" STATUS "] " */ + _cleanup_free_ char *s = NULL; + _cleanup_close_ int fd = -1; + struct iovec iovec[6] = {}; + int n = 0; + static bool prev_ephemeral; + + assert(format); + + /* This is independent of logging, as status messages are + * optional and go exclusively to the console. */ + + if (vasprintf(&s, format, ap) < 0) + return log_oom(); + + fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + if (ellipse) { + char *e; + size_t emax, sl; + int c; + + c = fd_columns(fd); + if (c <= 0) + c = 80; + + sl = status ? sizeof(status_indent)-1 : 0; + + emax = c - sl - 1; + if (emax < 3) + emax = 3; + + e = ellipsize(s, emax, 75); + if (e) { + free(s); + s = e; + } + } + + if (prev_ephemeral) + IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); + prev_ephemeral = ephemeral; + + if (status) { + if (!isempty(status)) { + IOVEC_SET_STRING(iovec[n++], "["); + IOVEC_SET_STRING(iovec[n++], status); + IOVEC_SET_STRING(iovec[n++], "] "); + } else + IOVEC_SET_STRING(iovec[n++], status_indent); + } + + IOVEC_SET_STRING(iovec[n++], s); + if (!ephemeral) + IOVEC_SET_STRING(iovec[n++], "\n"); + + if (writev(fd, iovec, n) < 0) + return -errno; + + return 0; +} + +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { + va_list ap; + int r; + + assert(format); + + va_start(ap, format); + r = status_vprintf(status, ellipse, ephemeral, format, ap); + va_end(ap); + + return r; +} + +char *replace_env(const char *format, char **env) { + enum { + WORD, + CURLY, + VARIABLE + } state = WORD; + + const char *e, *word = format; + char *r = NULL, *k; + + assert(format); + + for (e = format; *e; e ++) { + + switch (state) { + + case WORD: + if (*e == '$') + state = CURLY; + break; + + case CURLY: + if (*e == '{') { + if (!(k = strnappend(r, word, e-word-1))) + goto fail; + + free(r); + r = k; + + word = e-1; + state = VARIABLE; + + } else if (*e == '$') { + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } else + state = WORD; + break; + + case VARIABLE: + if (*e == '}') { + const char *t; + + t = strempty(strv_env_get_n(env, word+2, e-word-2)); + + k = strappend(r, t); + if (!k) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } + break; + } + } + + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + return k; + +fail: + free(r); + return NULL; +} + +char **replace_env_argv(char **argv, char **env) { + char **r, **i; + unsigned k = 0, l = 0; + + l = strv_length(argv); + + if (!(r = new(char*, l+1))) + return NULL; + + STRV_FOREACH(i, argv) { + + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$' && (*i)[1] != '{') { + char *e; + char **w, **m; + unsigned q; + + e = strv_env_get(env, *i+1); + if (e) { + + if (!(m = strv_split_quoted(e))) { + r[k] = NULL; + strv_free(r); + return NULL; + } + } else + m = NULL; + + q = strv_length(m); + l = l + q - 1; + + if (!(w = realloc(r, sizeof(char*) * (l+1)))) { + r[k] = NULL; + strv_free(r); + strv_free(m); + return NULL; + } + + r = w; + if (m) { + memcpy(r + k, m, q * sizeof(char*)); + free(m); + } + + k += q; + continue; + } + + /* If ${FOO} appears as part of a word, replace it by the variable as-is */ + if (!(r[k++] = replace_env(*i, env))) { + strv_free(r); + return NULL; + } + } + + r[k] = NULL; + return r; +} + +int fd_columns(int fd) { + struct winsize ws = {}; + + if (ioctl(fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_col <= 0) + return -EIO; + + return ws.ws_col; +} + +unsigned columns(void) { + const char *e; + int c; + + if (_likely_(cached_columns > 0)) + return cached_columns; + + c = 0; + e = getenv("COLUMNS"); + if (e) + safe_atoi(e, &c); + + if (c <= 0) + c = fd_columns(STDOUT_FILENO); + + if (c <= 0) + c = 80; + + cached_columns = c; + return c; +} + +int fd_lines(int fd) { + struct winsize ws = {}; + + if (ioctl(fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_row <= 0) + return -EIO; + + return ws.ws_row; +} + +unsigned lines(void) { + const char *e; + unsigned l; + + if (_likely_(cached_lines > 0)) + return cached_lines; + + l = 0; + e = getenv("LINES"); + if (e) + safe_atou(e, &l); + + if (l <= 0) + l = fd_lines(STDOUT_FILENO); + + if (l <= 0) + l = 24; + + cached_lines = l; + return cached_lines; +} + +/* intended to be used as a SIGWINCH sighandler */ +void columns_lines_cache_reset(int signum) { + cached_columns = 0; + cached_lines = 0; +} + +bool on_tty(void) { + static int cached_on_tty = -1; + + if (_unlikely_(cached_on_tty < 0)) + cached_on_tty = isatty(STDOUT_FILENO) > 0; + + return cached_on_tty; +} + +int running_in_chroot(void) { + struct stat a = {}, b = {}; + + /* Only works as root */ + if (stat("/proc/1/root", &a) < 0) + return -errno; + + if (stat("/", &b) < 0) + return -errno; + + return + a.st_dev != b.st_dev || + a.st_ino != b.st_ino; +} + +static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *r; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + r = new0(char, new_length+1); + if (!r) + return NULL; + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + memcpy(r, s, x); + r[x] = '.'; + r[x+1] = '.'; + r[x+2] = '.'; + memcpy(r + x + 3, + s + old_length - (new_length - x - 3), + new_length - x - 3); + + return r; +} + +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *e; + const char *i, *j; + unsigned k, len, len2; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + /* if no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid(s)) + return ascii_ellipsize_mem(s, old_length, new_length, percent); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + k = 0; + for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + int c; + + c = utf8_encoded_to_unichar(i); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + + if (k > x) /* last character was wide and went over quota */ + x ++; + + for (j = s + old_length; k < new_length && j > i; ) { + int c; + + j = utf8_prev_char(j); + c = utf8_encoded_to_unichar(j); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + assert(i <= j); + + /* we don't actually need to ellipsize */ + if (i == j) + return memdup(s, old_length + 1); + + /* make space for ellipsis */ + j = utf8_next_char(j); + + len = i - s; + len2 = s + old_length - j; + e = new(char, len + 3 + len2 + 1); + if (!e) + return NULL; + + /* + printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", + old_length, new_length, x, len, len2, k); + */ + + memcpy(e, s, len); + e[len] = 0xe2; /* tri-dot ellipsis: … */ + e[len + 1] = 0x80; + e[len + 2] = 0xa6; + + memcpy(e + len + 3, j, len2 + 1); + + return e; +} + +char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} + +int touch(const char *path) { + int fd; + + assert(path); + + /* This just opens the file for writing, ensuring it + * exists. It doesn't call utimensat() the way /usr/bin/touch + * does it. */ + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644); + if (fd < 0) + return -errno; + + close_nointr_nofail(fd); + return 0; +} + +char *unquote(const char *s, const char* quotes) { + size_t l; + assert(s); + + /* This is rather stupid, simply removes the heading and + * trailing quotes if there is one. Doesn't care about + * escaping or anything. We should make this smarter one + * day...*/ + + l = strlen(s); + if (l < 2) + return strdup(s); + + if (strchr(quotes, s[0]) && s[l-1] == s[0]) + return strndup(s+1, l-2); + + return strdup(s); +} + +char *normalize_env_assignment(const char *s) { + _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL; + char *eq, *r; + + eq = strchr(s, '='); + if (!eq) { + char *t; + + r = strdup(s); + if (!r) + return NULL; + + t = strstrip(r); + if (t == r) + return r; + + memmove(r, t, strlen(t) + 1); + return r; + } + + name = strndup(s, eq - s); + if (!name) + return NULL; + + p = strdup(eq + 1); + if (!p) + return NULL; + + value = unquote(strstrip(p), QUOTES); + if (!value) + return NULL; + + if (asprintf(&r, "%s=%s", strstrip(name), value) < 0) + r = NULL; + + return r; +} + +int wait_for_terminate(pid_t pid, siginfo_t *status) { + siginfo_t dummy; + + assert(pid >= 1); + + if (!status) + status = &dummy; + + for (;;) { + zero(*status); + + if (waitid(P_PID, pid, status, WEXITED) < 0) { + + if (errno == EINTR) + continue; + + return -errno; + } + + return 0; + } +} + +int wait_for_terminate_and_warn(const char *name, pid_t pid) { + int r; + siginfo_t status; + + assert(name); + assert(pid > 1); + + r = wait_for_terminate(pid, &status); + if (r < 0) { + log_warning("Failed to wait for %s: %s", name, strerror(-r)); + return r; + } + + if (status.si_code == CLD_EXITED) { + if (status.si_status != 0) { + log_warning("%s failed with error code %i.", name, status.si_status); + return status.si_status; + } + + log_debug("%s succeeded.", name); + return 0; + + } else if (status.si_code == CLD_KILLED || + status.si_code == CLD_DUMPED) { + + log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status)); + return -EPROTO; + } + + log_warning("%s failed due to unknown reason.", name); + return -EPROTO; +} + +noreturn void freeze(void) { + + /* Make sure nobody waits for us on a socket anymore */ + close_all_fds(NULL, 0); + + sync(); + + for (;;) + pause(); +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +DIR *xopendirat(int fd, const char *name, int flags) { + int nfd; + DIR *d; + + assert(!(flags & O_CREAT)); + + nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); + if (nfd < 0) + return NULL; + + d = fdopendir(nfd); + if (!d) { + close_nointr_nofail(nfd); + return NULL; + } + + return d; +} + +int signal_from_string_try_harder(const char *s) { + int signo; + assert(s); + + signo = signal_from_string(s); + if (signo <= 0) + if (startswith(s, "SIG")) + return signal_from_string(s+3); + + return signo; +} + +static char *tag_to_udev_node(const char *tagvalue, const char *by) { + _cleanup_free_ char *t = NULL, *u = NULL; + char *dn; + size_t enc_len; + + u = unquote(tagvalue, "\"\'"); + if (u == NULL) + return NULL; + + enc_len = strlen(u) * 4 + 1; + t = new(char, enc_len); + if (t == NULL) + return NULL; + + if (encode_devnode_name(u, t, enc_len) < 0) + return NULL; + + if (asprintf(&dn, "/dev/disk/by-%s/%s", by, t) < 0) + return NULL; + + return dn; +} + +char *fstab_node_to_udev_node(const char *p) { + assert(p); + + if (startswith(p, "LABEL=")) + return tag_to_udev_node(p+6, "label"); + + if (startswith(p, "UUID=")) + return tag_to_udev_node(p+5, "uuid"); + + if (startswith(p, "PARTUUID=")) + return tag_to_udev_node(p+9, "partuuid"); + + if (startswith(p, "PARTLABEL=")) + return tag_to_udev_node(p+10, "partlabel"); + + return strdup(p); +} + +bool tty_is_vc(const char *tty) { + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + return vtnr_from_tty(tty) >= 0; +} + +bool tty_is_console(const char *tty) { + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + return streq(tty, "console"); +} + +int vtnr_from_tty(const char *tty) { + int i, r; + + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + if (!startswith(tty, "tty") ) + return -EINVAL; + + if (tty[3] < '0' || tty[3] > '9') + return -EINVAL; + + r = safe_atoi(tty+3, &i); + if (r < 0) + return r; + + if (i < 0 || i > 63) + return -EINVAL; + + return i; +} + +char *resolve_dev_console(char **active) { + char *tty; + + /* Resolve where /dev/console is pointing to, if /sys is actually ours + * (i.e. not read-only-mounted which is a sign for container setups) */ + + if (path_is_read_only_fs("/sys") > 0) + return NULL; + + if (read_one_line_file("/sys/class/tty/console/active", active) < 0) + return NULL; + + /* If multiple log outputs are configured the last one is what + * /dev/console points to */ + tty = strrchr(*active, ' '); + if (tty) + tty++; + else + tty = *active; + + if (streq(tty, "tty0")) { + char *tmp; + + /* Get the active VC (e.g. tty1) */ + if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) { + free(*active); + tty = *active = tmp; + } + } + + return tty; +} + +bool tty_is_vc_resolve(const char *tty) { + _cleanup_free_ char *active = NULL; + + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + if (streq(tty, "console")) { + tty = resolve_dev_console(&active); + if (!tty) + return false; + } + + return tty_is_vc(tty); +} + +const char *default_term_for_tty(const char *tty) { + assert(tty); + + return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102"; +} + +bool dirent_is_file(const struct dirent *de) { + assert(de); + + if (ignore_file(de->d_name)) + return false; + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + return true; +} + +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { + assert(de); + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + if (ignore_file_allow_backup(de->d_name)) + return false; + + return endswith(de->d_name, suffix); +} + +void execute_directory(const char *directory, DIR *d, char *argv[]) { + DIR *_d = NULL; + struct dirent *de; + Hashmap *pids = NULL; + + assert(directory); + + /* Executes all binaries in a directory in parallel and + * waits for them to finish. */ + + if (!d) { + if (!(_d = opendir(directory))) { + + if (errno == ENOENT) + return; + + log_error("Failed to enumerate directory %s: %m", directory); + return; + } + + d = _d; + } + + if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { + log_error("Failed to allocate set."); + goto finish; + } + + while ((de = readdir(d))) { + char *path; + pid_t pid; + int k; + + if (!dirent_is_file(de)) + continue; + + if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) { + log_oom(); + continue; + } + + if ((pid = fork()) < 0) { + log_error("Failed to fork: %m"); + free(path); + continue; + } + + if (pid == 0) { + char *_argv[2]; + /* Child */ + + if (!argv) { + _argv[0] = path; + _argv[1] = NULL; + argv = _argv; + } else + argv[0] = path; + + execv(path, argv); + + log_error("Failed to execute %s: %m", path); + _exit(EXIT_FAILURE); + } + + log_debug("Spawned %s as %lu", path, (unsigned long) pid); + + if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) { + log_error("Failed to add PID to set: %s", strerror(-k)); + free(path); + } + } + + while (!hashmap_isempty(pids)) { + pid_t pid = PTR_TO_UINT(hashmap_first_key(pids)); + siginfo_t si = {}; + char *path; + + if (waitid(P_PID, pid, &si, WEXITED) < 0) { + + if (errno == EINTR) + continue; + + log_error("waitid() failed: %m"); + goto finish; + } + + if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { + if (!is_clean_exit(si.si_code, si.si_status, NULL)) { + if (si.si_code == CLD_EXITED) + log_error("%s exited with exit status %i.", path, si.si_status); + else + log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status)); + } else + log_debug("%s exited successfully.", path); + + free(path); + } + } + +finish: + if (_d) + closedir(_d); + + if (pids) + hashmap_free_free(pids); +} + +int kill_and_sigcont(pid_t pid, int sig) { + int r; + + r = kill(pid, sig) < 0 ? -errno : 0; + + if (r >= 0) + kill(pid, SIGCONT); + + return r; +} + +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; +} + +bool plymouth_running(void) { + return access("/run/plymouth/pid", F_OK) >= 0; +} + +char* strshorten(char *s, size_t l) { + assert(s); + + if (l < strlen(s)) + s[l] = 0; + + return s; +} + +static bool hostname_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_' || + c == '.'; +} + +bool hostname_is_valid(const char *s) { + const char *p; + bool dot; + + if (isempty(s)) + return false; + + for (p = s, dot = true; *p; p++) { + if (*p == '.') { + if (dot) + return false; + + dot = true; + } else { + if (!hostname_valid_char(*p)) + return false; + + dot = false; + } + } + + if (dot) + return false; + + if (p-s > HOST_NAME_MAX) + return false; + + return true; +} + +char* hostname_cleanup(char *s, bool lowercase) { + char *p, *d; + bool dot; + + for (p = s, d = s, dot = true; *p; p++) { + if (*p == '.') { + if (dot) + continue; + + *(d++) = '.'; + dot = true; + } else if (hostname_valid_char(*p)) { + *(d++) = lowercase ? tolower(*p) : *p; + dot = false; + } + + } + + if (dot && d > s) + d[-1] = 0; + else + *d = 0; + + strshorten(s, HOST_NAME_MAX); + + return s; +} + +int pipe_eof(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN|POLLHUP, + }; + + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents & POLLHUP; +} + +int fd_wait_for_event(int fd, int event, usec_t t) { + + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + + struct timespec ts; + int r; + + r = ppoll(&pollfd, 1, t == (usec_t) -1 ? NULL : timespec_store(&ts, t), NULL); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents; +} + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { + FILE *f; + char *t; + const char *fn; + size_t k; + int fd; + + assert(path); + assert(_f); + assert(_temp_path); + + t = new(char, strlen(path) + 1 + 6 + 1); + if (!t) + return -ENOMEM; + + fn = basename(path); + k = fn - path; + memcpy(t, path, k); + t[k] = '.'; + stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); + + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + free(t); + return -errno; + } + + f = fdopen(fd, "we"); + if (!f) { + unlink(t); + free(t); + return -errno; + } + + *_f = f; + *_temp_path = t; + + return 0; +} + +int terminal_vhangup_fd(int fd) { + assert(fd >= 0); + + if (ioctl(fd, TIOCVHANGUP) < 0) + return -errno; + + return 0; +} + +int terminal_vhangup(const char *name) { + int fd, r; + + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = terminal_vhangup_fd(fd); + close_nointr_nofail(fd); + + return r; +} + +int vt_disallocate(const char *name) { + int fd, r; + unsigned u; + + /* Deallocate the VT if possible. If not possible + * (i.e. because it is the active one), at least clear it + * entirely (including the scrollback buffer) */ + + if (!startswith(name, "/dev/")) + return -EINVAL; + + if (!tty_is_vc(name)) { + /* So this is not a VT. I guess we cannot deallocate + * it then. But let's at least clear the screen */ + + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + loop_write(fd, + "\033[r" /* clear scrolling region */ + "\033[H" /* move home */ + "\033[2J", /* clear screen */ + 10, false); + close_nointr_nofail(fd); + + return 0; + } + + if (!startswith(name, "/dev/tty")) + return -EINVAL; + + r = safe_atou(name+8, &u); + if (r < 0) + return r; + + if (u <= 0) + return -EINVAL; + + /* Try to deallocate */ + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = ioctl(fd, VT_DISALLOCATE, u); + close_nointr_nofail(fd); + + if (r >= 0) + return 0; + + if (errno != EBUSY) + return -errno; + + /* Couldn't deallocate, so let's clear it fully with + * scrollback */ + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + loop_write(fd, + "\033[r" /* clear scrolling region */ + "\033[H" /* move home */ + "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ + 10, false); + close_nointr_nofail(fd); + + return 0; +} + +int copy_file(const char *from, const char *to, int flags) { + _cleanup_close_ int fdf = -1; + int r, fdt; + + assert(from); + assert(to); + + fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fdf < 0) + return -errno; + + fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644); + if (fdt < 0) + return -errno; + + for (;;) { + char buf[PIPE_BUF]; + ssize_t n, k; + + n = read(fdf, buf, sizeof(buf)); + if (n < 0) { + r = -errno; + + close_nointr(fdt); + unlink(to); + + return r; + } + + if (n == 0) + break; + + errno = 0; + k = loop_write(fdt, buf, n, false); + if (n != k) { + r = k < 0 ? k : (errno ? -errno : -EIO); + + close_nointr(fdt); + unlink(to); + + return r; + } + } + + r = close_nointr(fdt); + + if (r < 0) { + unlink(to); + return r; + } + + return 0; +} + +int symlink_atomic(const char *from, const char *to) { + char *x; + _cleanup_free_ char *t; + const char *fn; + size_t k; + uint64_t u; + unsigned i; + int r; + + assert(from); + assert(to); + + t = new(char, strlen(to) + 1 + 16 + 1); + if (!t) + return -ENOMEM; + + fn = basename(to); + k = fn-to; + memcpy(t, to, k); + t[k] = '.'; + x = stpcpy(t+k+1, fn); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + if (symlink(from, t) < 0) + return -errno; + + if (rename(t, to) < 0) { + r = -errno; + unlink(t); + return r; + } + + return 0; +} + +bool display_is_local(const char *display) { + assert(display); + + return + display[0] == ':' && + display[1] >= '0' && + display[1] <= '9'; +} + +int socket_from_display(const char *display, char **path) { + size_t k; + char *f, *c; + + assert(display); + assert(path); + + if (!display_is_local(display)) + return -EINVAL; + + k = strspn(display+1, "0123456789"); + + f = new(char, sizeof("/tmp/.X11-unix/X") + k); + if (!f) + return -ENOMEM; + + c = stpcpy(f, "/tmp/.X11-unix/X"); + memcpy(c, display+1, k); + c[k] = 0; + + *path = f; + + return 0; +} + +int get_user_creds( + const char **username, + uid_t *uid, gid_t *gid, + const char **home, + const char **shell) { + + struct passwd *p; + uid_t u; + + assert(username); + assert(*username); + + /* We enforce some special rules for uid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*username, "root") || streq(*username, "0")) { + *username = "root"; + + if (uid) + *uid = 0; + + if (gid) + *gid = 0; + + if (home) + *home = "/root"; + + if (shell) + *shell = "/bin/sh"; + + return 0; + } + + if (parse_uid(*username, &u) >= 0) { + errno = 0; + p = getpwuid(u); + + /* If there are multiple users with the same id, make + * sure to leave $USER to the configured value instead + * of the first occurrence in the database. However if + * the uid was configured by a numeric uid, then let's + * pick the real username from /etc/passwd. */ + if (p) + *username = p->pw_name; + } else { + errno = 0; + p = getpwnam(*username); + } + + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (uid) + *uid = p->pw_uid; + + if (gid) + *gid = p->pw_gid; + + if (home) + *home = p->pw_dir; + + if (shell) + *shell = p->pw_shell; + + return 0; +} + +char* uid_to_name(uid_t uid) { + struct passwd *p; + char *r; + + if (uid == 0) + return strdup("root"); + + p = getpwuid(uid); + if (p) + return strdup(p->pw_name); + + if (asprintf(&r, "%lu", (unsigned long) uid) < 0) + return NULL; + + return r; +} + +char* gid_to_name(gid_t gid) { + struct group *p; + char *r; + + if (gid == 0) + return strdup("root"); + + p = getgrgid(gid); + if (p) + return strdup(p->gr_name); + + if (asprintf(&r, "%lu", (unsigned long) gid) < 0) + return NULL; + + return r; +} + +int get_group_creds(const char **groupname, gid_t *gid) { + struct group *g; + gid_t id; + + assert(groupname); + + /* We enforce some special rules for gid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*groupname, "root") || streq(*groupname, "0")) { + *groupname = "root"; + + if (gid) + *gid = 0; + + return 0; + } + + if (parse_gid(*groupname, &id) >= 0) { + errno = 0; + g = getgrgid(id); + + if (g) + *groupname = g->gr_name; + } else { + errno = 0; + g = getgrnam(*groupname); + } + + if (!g) + return errno > 0 ? -errno : -ESRCH; + + if (gid) + *gid = g->gr_gid; + + return 0; +} + +int in_gid(gid_t gid) { + gid_t *gids; + int ngroups_max, r, i; + + if (getgid() == gid) + return 1; + + if (getegid() == gid) + return 1; + + ngroups_max = sysconf(_SC_NGROUPS_MAX); + assert(ngroups_max > 0); + + gids = alloca(sizeof(gid_t) * ngroups_max); + + r = getgroups(ngroups_max, gids); + if (r < 0) + return -errno; + + for (i = 0; i < r; i++) + if (gids[i] == gid) + return 1; + + return 0; +} + +int in_group(const char *name) { + int r; + gid_t gid; + + r = get_group_creds(&name, &gid); + if (r < 0) + return r; + + return in_gid(gid); +} + +int glob_exists(const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + + assert(path); + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return 0; + else if (k == GLOB_NOSPACE) + return -ENOMEM; + else if (k == 0) + return !strv_isempty(g.gl_pathv); + else + return errno ? -errno : -EIO; +} + +int glob_extend(char ***strv, const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + char **p; + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return -ENOENT; + else if (k == GLOB_NOSPACE) + return -ENOMEM; + else if (k != 0 || strv_isempty(g.gl_pathv)) + return errno ? -errno : -EIO; + + STRV_FOREACH(p, g.gl_pathv) { + k = strv_extend(strv, *p); + if (k < 0) + break; + } + + return k; +} + +int dirent_ensure_type(DIR *d, struct dirent *de) { + struct stat st; + + assert(d); + assert(de); + + if (de->d_type != DT_UNKNOWN) + return 0; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + de->d_type = + S_ISREG(st.st_mode) ? DT_REG : + S_ISDIR(st.st_mode) ? DT_DIR : + S_ISLNK(st.st_mode) ? DT_LNK : + S_ISFIFO(st.st_mode) ? DT_FIFO : + S_ISSOCK(st.st_mode) ? DT_SOCK : + S_ISCHR(st.st_mode) ? DT_CHR : + S_ISBLK(st.st_mode) ? DT_BLK : + DT_UNKNOWN; + + return 0; +} + +int in_search_path(const char *path, char **search) { + char **i; + _cleanup_free_ char *parent = NULL; + int r; + + r = path_get_parent(path, &parent); + if (r < 0) + return r; + + STRV_FOREACH(i, search) + if (path_equal(parent, *i)) + return 1; + + return 0; +} + +int get_files_in_directory(const char *path, char ***list) { + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; + + assert(path); + + /* Returns all files in a directory in *list, and the number + * of files as return value. If list is NULL returns only the + * number. */ + + d = opendir(path); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + if (list) { + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; + + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; + + l[++n] = NULL; + } else + n++; + } + + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } + + return n; +} + +char *strjoin(const char *x, ...) { + va_list ap; + size_t l; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + + va_end(ap); + } else + r[0] = 0; + + return r; +} + +bool is_main_thread(void) { + static thread_local int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + +int block_get_whole_disk(dev_t d, dev_t *ret) { + char *p, *s; + int r; + unsigned n, m; + + assert(ret); + + /* If it has a queue this is good enough for us */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = d; + return 0; + } + + /* If it is a partition find the originating device */ + if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r < 0) + return -ENOENT; + + /* Get parent dev_t */ + if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &s); + free(p); + + if (r < 0) + return r; + + r = sscanf(s, "%u:%u", &m, &n); + free(s); + + if (r != 2) + return -EINVAL; + + /* Only return this if it is really good enough for us. */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = makedev(m, n); + return 0; + } + + return -ENOENT; +} + +int file_is_priv_sticky(const char *p) { + struct stat st; + + assert(p); + + if (lstat(p, &st) < 0) + return -errno; + + return + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); +} + +static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); + +static const char *const sigchld_code_table[] = { + [CLD_EXITED] = "exited", + [CLD_KILLED] = "killed", + [CLD_DUMPED] = "dumped", + [CLD_TRAPPED] = "trapped", + [CLD_STOPPED] = "stopped", + [CLD_CONTINUED] = "continued", +}; + +DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); + +static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); + +static const char *const log_level_table[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); + +static const char* const sched_policy_table[] = { + [SCHED_OTHER] = "other", + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", + [SCHED_RR] = "rr" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); + +static const char* const rlimit_table[] = { + [RLIMIT_CPU] = "LimitCPU", + [RLIMIT_FSIZE] = "LimitFSIZE", + [RLIMIT_DATA] = "LimitDATA", + [RLIMIT_STACK] = "LimitSTACK", + [RLIMIT_CORE] = "LimitCORE", + [RLIMIT_RSS] = "LimitRSS", + [RLIMIT_NOFILE] = "LimitNOFILE", + [RLIMIT_AS] = "LimitAS", + [RLIMIT_NPROC] = "LimitNPROC", + [RLIMIT_MEMLOCK] = "LimitMEMLOCK", + [RLIMIT_LOCKS] = "LimitLOCKS", + [RLIMIT_SIGPENDING] = "LimitSIGPENDING", + [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", + [RLIMIT_NICE] = "LimitNICE", + [RLIMIT_RTPRIO] = "LimitRTPRIO", + [RLIMIT_RTTIME] = "LimitRTTIME" +}; + +DEFINE_STRING_TABLE_LOOKUP(rlimit, int); + +static const char* const ip_tos_table[] = { + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_RELIABILITY] = "reliability", + [IPTOS_LOWCOST] = "low-cost", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); + +static const char *const __signal_table[] = { + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGBUS] = "BUS", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGUSR1] = "USR1", + [SIGSEGV] = "SEGV", + [SIGUSR2] = "USR2", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", +#ifdef SIGSTKFLT + [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ +#endif + [SIGCHLD] = "CHLD", + [SIGCONT] = "CONT", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGURG] = "URG", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGIO] = "IO", + [SIGPWR] = "PWR", + [SIGSYS] = "SYS" +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); + +const char *signal_to_string(int signo) { + static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; + const char *name; + + name = __signal_to_string(signo); + if (name) + return name; + + if (signo >= SIGRTMIN && signo <= SIGRTMAX) + snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); + else + snprintf(buf, sizeof(buf), "%d", signo); + + return buf; +} + +int signal_from_string(const char *s) { + int signo; + int offset = 0; + unsigned u; + + signo = __signal_from_string(s); + if (signo > 0) + return signo; + + if (startswith(s, "RTMIN+")) { + s += 6; + offset = SIGRTMIN; + } + if (safe_atou(s, &u) >= 0) { + signo = (int) u + offset; + if (signo > 0 && signo < _NSIG) + return signo; + } + return -1; +} + +bool kexec_loaded(void) { + bool loaded = false; + char *s; + + if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { + if (s[0] == '1') + loaded = true; + free(s); + } + return loaded; +} + +int strdup_or_null(const char *a, char **b) { + char *c; + + assert(b); + + if (!a) { + *b = NULL; + return 0; + } + + c = strdup(a); + if (!c) + return -ENOMEM; + + *b = c; + return 0; +} + +int prot_from_flags(int flags) { + + switch (flags & O_ACCMODE) { + + case O_RDONLY: + return PROT_READ; + + case O_WRONLY: + return PROT_WRITE; + + case O_RDWR: + return PROT_READ|PROT_WRITE; + + default: + return -EINVAL; + } +} + +char *format_bytes(char *buf, size_t l, off_t t) { + unsigned i; + + static const struct { + const char *suffix; + off_t factor; + } table[] = { + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + }; + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (t >= table[i].factor) { + snprintf(buf, l, + "%llu.%llu%s", + (unsigned long long) (t / table[i].factor), + (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), + table[i].suffix); + + goto finish; + } + } + + snprintf(buf, l, "%lluB", (unsigned long long) t); + +finish: + buf[l-1] = 0; + return buf; + +} + +void* memdup(const void *p, size_t l) { + void *r; + + assert(p); + + r = malloc(l); + if (!r) + return NULL; + + memcpy(r, p, l); + return r; +} + +int fd_inc_sndbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); + + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; + + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) + return -errno; + + return 1; +} + +int fd_inc_rcvbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); + + r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; + + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) + return -errno; + return 1; +} + +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { + pid_t parent_pid, agent_pid; + int fd; + bool stdout_is_tty, stderr_is_tty; + unsigned n, i; + va_list ap; + char **l; + + assert(pid); + assert(path); + + parent_pid = getpid(); + + /* Spawns a temporary TTY agent, making sure it goes away when + * we go away */ + + agent_pid = fork(); + if (agent_pid < 0) + return -errno; + + if (agent_pid != 0) { + *pid = agent_pid; + return 0; + } + + /* In the child: + * + * Make sure the agent goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Check whether our parent died before we were able + * to set the death signal */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + /* Don't leak fds to the agent */ + close_all_fds(except, n_except); + + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via + * popen() or a similar call that expects to + * read EOF we actually do generate EOF and + * not delay this indefinitely by because we + * keep an unused copy of stdin around. */ + fd = open("/dev/tty", O_WRONLY); + if (fd < 0) { + log_error("Failed to open /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (!stdout_is_tty) + dup2(fd, STDOUT_FILENO); + + if (!stderr_is_tty) + dup2(fd, STDERR_FILENO); + + if (fd > 2) + close(fd); + } + + /* Count arguments */ + va_start(ap, path); + for (n = 0; va_arg(ap, char*); n++) + ; + va_end(ap); + + /* Allocate strv */ + l = alloca(sizeof(char *) * (n + 1)); + + /* Fill in arguments */ + va_start(ap, path); + for (i = 0; i <= n; i++) + l[i] = va_arg(ap, char*); + va_end(ap); + + execv(path, l); + _exit(EXIT_FAILURE); +} + +int setrlimit_closest(int resource, const struct rlimit *rlim) { + struct rlimit highest, fixed; + + assert(rlim); + + if (setrlimit(resource, rlim) >= 0) + return 0; + + if (errno != EPERM) + return -errno; + + /* So we failed to set the desired setrlimit, then let's try + * to get as close as we can */ + assert_se(getrlimit(resource, &highest) == 0); + + fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); + fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); + + if (setrlimit(resource, &fixed) < 0) + return -errno; + + return 0; +} + +int getenv_for_pid(pid_t pid, const char *field, char **_value) { + _cleanup_fclose_ FILE *f = NULL; + char *value = NULL; + int r; + bool done = false; + size_t l; + const char *path; + + assert(pid >= 0); + assert(field); + assert(_value); + + path = procfs_file_alloca(pid, "environ"); + + f = fopen(path, "re"); + if (!f) + return -errno; + + l = strlen(field); + r = 0; + + do { + char line[LINE_MAX]; + unsigned i; + + for (i = 0; i < sizeof(line)-1; i++) { + int c; + + c = getc(f); + if (_unlikely_(c == EOF)) { + done = true; + break; + } else if (c == 0) + break; + + line[i] = c; + } + line[i] = 0; + + if (memcmp(line, field, l) == 0 && line[l] == '=') { + value = strdup(line + l + 1); + if (!value) + return -ENOMEM; + + r = 1; + break; + } + + } while (!done); + + *_value = value; + return r; +} + +bool is_valid_documentation_url(const char *url) { + assert(url); + + if (startswith(url, "http://") && url[7]) + return true; + + if (startswith(url, "https://") && url[8]) + return true; + + if (startswith(url, "file:") && url[5]) + return true; + + if (startswith(url, "info:") && url[5]) + return true; + + if (startswith(url, "man:") && url[4]) + return true; + + return false; +} + +bool in_initrd(void) { + static int saved = -1; + struct statfs s; + + if (saved >= 0) + return saved; + + /* We make two checks here: + * + * 1. the flag file /etc/initrd-release must exist + * 2. the root file system must be a memory file system + * + * The second check is extra paranoia, since misdetecting an + * initrd can have bad bad consequences due the initrd + * emptying when transititioning to the main systemd. + */ + + saved = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); + + return saved; +} + +void warn_melody(void) { + _cleanup_close_ int fd = -1; + + fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return; + + /* Yeah, this is synchronous. Kinda sucks. But well... */ + + ioctl(fd, KIOCSOUND, (int)(1193180/440)); + usleep(125*USEC_PER_MSEC); + + ioctl(fd, KIOCSOUND, (int)(1193180/220)); + usleep(125*USEC_PER_MSEC); + + ioctl(fd, KIOCSOUND, (int)(1193180/220)); + usleep(125*USEC_PER_MSEC); + + ioctl(fd, KIOCSOUND, 0); +} + +int make_console_stdio(void) { + int fd, r; + + /* Make /dev/console the controlling terminal and stdin/stdout/stderr */ + + fd = acquire_terminal("/dev/console", false, true, true, (usec_t) -1); + if (fd < 0) { + log_error("Failed to acquire terminal: %s", strerror(-fd)); + return fd; + } + + r = make_stdio(fd); + if (r < 0) { + log_error("Failed to duplicate terminal fd: %s", strerror(-r)); + return r; + } + + return 0; +} + +int get_home_dir(char **_h) { + struct passwd *p; + const char *e; + char *h; + uid_t u; + + assert(_h); + + /* Take the user specified one */ + e = getenv("HOME"); + if (e) { + h = strdup(e); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + h = strdup("/root"); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_dir)) + return -EINVAL; + + h = strdup(p->pw_dir); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; +} + +int get_shell(char **_s) { + struct passwd *p; + const char *e; + char *s; + uid_t u; + + assert(_s); + + /* Take the user specified one */ + e = getenv("SHELL"); + if (e) { + s = strdup(e); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + s = strdup("/bin/sh"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_shell)) + return -EINVAL; + + s = strdup(p->pw_shell); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; +} + +bool filename_is_safe(const char *p) { + + if (isempty(p)) + return false; + + if (strchr(p, '/')) + return false; + + if (streq(p, ".")) + return false; + + if (streq(p, "..")) + return false; + + if (strlen(p) > FILENAME_MAX) + return false; + + return true; +} + +bool string_is_safe(const char *p) { + const char *t; + + assert(p); + + for (t = p; *t; t++) { + if (*t > 0 && *t < ' ') + return false; + + if (strchr("\\\"\'", *t)) + return false; + } + + return true; +} + +/** + * Check if a string contains control characters. + * Spaces and tabs are not considered control characters. + */ +bool string_has_cc(const char *p) { + const char *t; + + assert(p); + + for (t = p; *t; t++) + if (*t > 0 && *t < ' ' && *t != '\t') + return true; + + return false; +} + +bool path_is_safe(const char *p) { + + if (isempty(p)) + return false; + + if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) + return false; + + if (strlen(p) > PATH_MAX) + return false; + + /* The following two checks are not really dangerous, but hey, they still are confusing */ + if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) + return false; + + if (strstr(p, "//")) + return false; + + return true; +} + +/* 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, + int (*compar) (const void *, const void *, void *), void *arg) { + size_t l, u, idx; + const void *p; + int comparison; + + l = 0; + u = nmemb; + while (l < u) { + idx = (l + u) / 2; + p = (void *)(((const char *) 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 is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + if (streq(set, "UTF-8")) { + cached_answer = true; + goto out; + } + + /* For LC_CTYPE=="C" return true, because CTYPE is effectly + * unset and everything can do to UTF-8 nowadays. */ + set = setlocale(LC_CTYPE, NULL); + if (!set) { + cached_answer = true; + goto out; + } + + /* Check result, but ignore the result if C was set + * explicitly. */ + cached_answer = + streq(set, "C") && + !getenv("LC_ALL") && + !getenv("LC_CTYPE") && + !getenv("LANG"); + +out: + return (bool) cached_answer; +} + +const char *draw_special_char(DrawSpecialChar ch) { + static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { + /* UTF-8 */ { + [DRAW_TREE_VERT] = "\342\224\202 ", /* │ */ + [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ + [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ + [DRAW_TREE_SPACE] = " ", /* */ + [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */ + [DRAW_BLACK_CIRCLE] = "\342\227\217 ", /* ● */ + }, + /* ASCII fallback */ { + [DRAW_TREE_VERT] = "| ", + [DRAW_TREE_BRANCH] = "|-", + [DRAW_TREE_RIGHT] = "`-", + [DRAW_TREE_SPACE] = " ", + [DRAW_TRIANGULAR_BULLET] = "> ", + [DRAW_BLACK_CIRCLE] = "* ", + } + }; + + return draw_table[!is_locale_utf8()][ch]; +} + +char *strreplace(const char *text, const char *old_string, const char *new_string) { + const char *f; + char *t, *r; + size_t l, old_len, new_len; + + assert(text); + assert(old_string); + assert(new_string); + + old_len = strlen(old_string); + new_len = strlen(new_string); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + char *a; + size_t d, nl; + + if (!startswith(f, old_string)) { + *(t++) = *(f++); + continue; + } + + d = t - r; + nl = l - old_len + new_len; + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, new_string); + f += old_len; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} + +char *strip_tab_ansi(char **ibuf, size_t *_isz) { + const char *i, *begin = NULL; + enum { + STATE_OTHER, + STATE_ESCAPE, + STATE_BRACKET + } state = STATE_OTHER; + char *obuf = NULL; + size_t osz = 0, isz; + FILE *f; + + assert(ibuf); + assert(*ibuf); + + /* Strips ANSI color and replaces TABs by 8 spaces */ + + isz = _isz ? *_isz : strlen(*ibuf); + + f = open_memstream(&obuf, &osz); + if (!f) + return NULL; + + for (i = *ibuf; i < *ibuf + isz + 1; i++) { + + switch (state) { + + case STATE_OTHER: + if (i >= *ibuf + isz) /* EOT */ + break; + else if (*i == '\x1B') + state = STATE_ESCAPE; + else if (*i == '\t') + fputs(" ", f); + else + fputc(*i, f); + break; + + case STATE_ESCAPE: + if (i >= *ibuf + isz) { /* EOT */ + fputc('\x1B', f); + break; + } else if (*i == '[') { + state = STATE_BRACKET; + begin = i + 1; + } else { + fputc('\x1B', f); + fputc(*i, f); + state = STATE_OTHER; + } + + break; + + case STATE_BRACKET: + + if (i >= *ibuf + isz || /* EOT */ + (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { + fputc('\x1B', f); + fputc('[', f); + state = STATE_OTHER; + i = begin-1; + } else if (*i == 'm') + state = STATE_OTHER; + break; + } + } + + if (ferror(f)) { + fclose(f); + free(obuf); + return NULL; + } + + fclose(f); + + free(*ibuf); + *ibuf = obuf; + + if (_isz) + *_isz = osz; + + return obuf; +} + +int on_ac_power(void) { + bool found_offline = false, found_online = false; + _cleanup_closedir_ DIR *d = NULL; + + d = opendir("/sys/class/power_supply"); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + _cleanup_close_ int fd = -1, device = -1; + char contents[6]; + ssize_t n; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + if (ignore_file(de->d_name)) + continue; + + device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (device < 0) { + if (errno == ENOENT || errno == ENOTDIR) + continue; + + return -errno; + } + + fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + if (errno == ENOENT) + continue; + + return -errno; + } + + n = read(fd, contents, sizeof(contents)); + if (n < 0) + return -errno; + + if (n != 6 || memcmp(contents, "Mains\n", 6)) + continue; + + close_nointr_nofail(fd); + fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + if (errno == ENOENT) + continue; + + return -errno; + } + + n = read(fd, contents, sizeof(contents)); + if (n < 0) + return -errno; + + if (n != 2 || contents[1] != '\n') + return -EIO; + + if (contents[0] == '1') { + found_online = true; + break; + } else if (contents[0] == '0') + found_offline = true; + else + return -EIO; + } + + return found_online || !found_offline; +} + +static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) { + char **i; + + assert(path); + assert(mode); + assert(_f); + + if (!path_strv_canonicalize_absolute_uniq(search, NULL)) + return -ENOMEM; + + STRV_FOREACH(i, search) { + _cleanup_free_ char *p = NULL; + FILE *f; + + p = strjoin(*i, "/", path, NULL); + if (!p) + return -ENOMEM; + + f = fopen(p, mode); + if (f) { + *_f = f; + return 0; + } + + if (errno != ENOENT) + return -errno; + } + + return -ENOENT; +} + +int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) { + _cleanup_strv_free_ char **copy = NULL; + + assert(path); + assert(mode); + assert(_f); + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + copy = strv_copy((char**) search); + if (!copy) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, copy, _f); +} + +int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) { + _cleanup_strv_free_ char **s = NULL; + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + s = strv_split_nulstr(search); + if (!s) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, s, _f); +} + +char *strextend(char **x, ...) { + va_list ap; + size_t f, l; + char *r, *p; + + assert(x); + + l = f = *x ? strlen(*x) : 0; + + va_start(ap, x); + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + va_end(ap); + + r = realloc(*x, l+1); + if (!r) + return NULL; + + p = r + f; + + va_start(ap, x); + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + va_end(ap); + + *p = 0; + *x = r; + + return r + l; +} + +char *strrep(const char *s, unsigned n) { + size_t l; + char *r, *p; + unsigned i; + + assert(s); + + l = strlen(s); + p = r = malloc(l * n + 1); + if (!r) + return NULL; + + for (i = 0; i < n; i++) + p = stpcpy(p, s); + + *p = 0; + return r; +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need) { + size_t a; + void *q; + + assert(p); + assert(allocated); + + if (*allocated >= need) + return *p; + + a = MAX(64u, need * 2); + + /* check for overflows */ + if (a < need) + return NULL; + + q = realloc(*p, a); + if (!q) + return NULL; + + *p = q; + *allocated = a; + return q; +} + +void* greedy_realloc0(void **p, size_t *allocated, size_t need) { + size_t prev; + uint8_t *q; + + assert(p); + assert(allocated); + + prev = *allocated; + + q = greedy_realloc(p, allocated, need); + if (!q) + return NULL; + + if (*allocated > prev) + memzero(&q[prev], *allocated - prev); + + return q; +} + +bool id128_is_valid(const char *s) { + size_t i, l; + + l = strlen(s); + if (l == 32) { + + /* Simple formatted 128bit hex string */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + + } else if (l == 36) { + + /* Formatted UUID */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if ((i == 8 || i == 13 || i == 18 || i == 23)) { + if (c != '-') + return false; + } else { + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + } + + } else + return false; + + return true; +} + +int split_pair(const char *s, const char *sep, char **l, char **r) { + char *x, *a, *b; + + assert(s); + assert(sep); + assert(l); + assert(r); + + if (isempty(sep)) + return -EINVAL; + + x = strstr(s, sep); + if (!x) + return -EINVAL; + + a = strndup(s, x - s); + if (!a) + return -ENOMEM; + + b = strdup(x + strlen(sep)); + if (!b) { + free(a); + return -ENOMEM; + } + + *l = a; + *r = b; + + return 0; +} + +int shall_restore_state(void) { + _cleanup_free_ char *line; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + return r; + if (r == 0) /* Container ... */ + return 1; + + FOREACH_WORD_QUOTED(w, l, line, state) + if (l == 23 && strneq(w, "systemd.restore_state=0", 23)) + return 0; + + return 1; +} + +int proc_cmdline(char **ret) { + int r; + + if (detect_container(NULL) > 0) { + char *buf = NULL, *p; + size_t sz = 0; + + r = read_full_file("/proc/1/cmdline", &buf, &sz); + if (r < 0) + return r; + + for (p = buf; p + 1 < buf + sz; p++) + if (*p == 0) + *p = ' '; + + *p = 0; + *ret = buf; + return 1; + } + + r = read_one_line_file("/proc/cmdline", ret); + if (r < 0) + return r; + + return 1; +} + +int parse_proc_cmdline(int (*parse_word)(const char *word)) { + _cleanup_free_ char *line = NULL; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return 0; + + FOREACH_WORD_QUOTED(w, l, line, state) { + _cleanup_free_ char *word; + + word = strndup(w, l); + if (!word) + return log_oom(); + + r = parse_word(word); + if (r < 0) { + log_error("Failed on cmdline argument %s: %s", word, strerror(-r)); + return r; + } + } + + return 0; +} + +int container_get_leader(const char *machine, pid_t *pid) { + _cleanup_free_ char *s = NULL, *class = NULL; + const char *p; + pid_t leader; + int r; + + assert(machine); + assert(pid); + + p = strappenda("/run/systemd/machines/", machine); + r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + if (r == -ENOENT) + return -EHOSTDOWN; + if (r < 0) + return r; + if (!s) + return -EIO; + + if (!streq_ptr(class, "container")) + return -EIO; + + r = parse_pid(s, &leader); + if (r < 0) + return r; + if (leader <= 1) + return -EIO; + + *pid = leader; + return 0; +} + +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1; + const char *pidns, *mntns, *root; + int rfd; + + assert(pid >= 0); + assert(pidns_fd); + assert(mntns_fd); + assert(root_fd); + + mntns = procfs_file_alloca(pid, "ns/mnt"); + mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (mntnsfd < 0) + return -errno; + + pidns = procfs_file_alloca(pid, "ns/pid"); + pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (pidnsfd < 0) + return -errno; + + root = procfs_file_alloca(pid, "root"); + rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (rfd < 0) + return -errno; + + *pidns_fd = pidnsfd; + *mntns_fd = mntnsfd; + *root_fd = rfd; + pidnsfd = -1; + mntnsfd = -1; + + return 0; +} + +int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) { + assert(pidns_fd >= 0); + assert(mntns_fd >= 0); + assert(root_fd >= 0); + + if (setns(pidns_fd, CLONE_NEWPID) < 0) + return -errno; + + if (setns(mntns_fd, CLONE_NEWNS) < 0) + return -errno; + + if (fchdir(root_fd) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +} + +bool pid_is_unwaited(pid_t pid) { + /* Checks whether a PID is still valid at all, including a zombie */ + + if (pid <= 0) + return false; + + if (kill(pid, 0) >= 0) + return true; + + return errno != ESRCH; +} + +bool pid_is_alive(pid_t pid) { + int r; + + /* Checks whether a PID is still valid and not a zombie */ + + if (pid <= 0) + return false; + + r = get_process_state(pid); + if (r == -ENOENT || r == 'Z') + return false; + + return true; +} + +int getpeercred(int fd, struct ucred *ucred) { + socklen_t n = sizeof(struct ucred); + struct ucred u; + int r; + + assert(fd >= 0); + assert(ucred); + + r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); + if (r < 0) + return -errno; + + if (n != sizeof(struct ucred)) + return -EIO; + + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + + *ucred = u; + return 0; +} + +int getpeersec(int fd, char **ret) { + socklen_t n = 64; + char *s; + int r; + + assert(fd >= 0); + assert(ret); + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + + if (errno != ERANGE) + return -errno; + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + return -errno; + } + } + + if (isempty(s)) { + free(s); + return -ENOTSUP; + } + + *ret = s; + return 0; +} + +/* This is much like like mkostemp() but is subject to umask(). */ +int mkostemp_safe(char *pattern, int flags) { + _cleanup_umask_ mode_t u; + int fd; + + assert(pattern); + + u = umask(077); + + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; + + return fd; +} + +int open_tmpfile(const char *path, int flags) { + char *p; + int fd; + + assert(path); + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strappenda(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + unlink(p); + return fd; +} + +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +unsigned long personality_from_string(const char *p) { + + /* Parse a personality specifier. We introduce our own + * identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep + * things open for multiple locally supported ABIs for the + * same register size. We try to reuse the ABI identifiers + * used by libseccomp. */ + +#if defined(__x86_64__) + + if (streq(p, "x86")) + return PER_LINUX32; + + if (streq(p, "x86-64")) + return PER_LINUX; + +#elif defined(__i386__) + + if (streq(p, "x86")) + return PER_LINUX; +#endif + + /* personality(7) documents that 0xffffffffUL is used for + * querying the current personality, hence let's use that here + * as error indicator. */ + return 0xffffffffUL; +} + +const char* personality_to_string(unsigned long p) { + +#if defined(__x86_64__) + + if (p == PER_LINUX32) + return "x86"; + + if (p == PER_LINUX) + return "x86-64"; + +#elif defined(__i386__) + + if (p == PER_LINUX) + return "x86"; +#endif + + return NULL; +} diff --git a/src/shared/util.h b/src/shared/util.h new file mode 100644 index 0000000..9913fce --- /dev/null +++ b/src/shared/util.h @@ -0,0 +1,876 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if SIZEOF_PID_T == 4 +# define PID_FMT "%" PRIu32 +#elif SIZEOF_PID_T == 2 +# define PID_FMT "%" PRIu16 +#else +# error Unknown pid_t size +#endif + +#if SIZEOF_UID_T == 4 +# define UID_FMT "%" PRIu32 +#elif SIZEOF_UID_T == 2 +# define UID_FMT "%" PRIu16 +#else +# error Unknown uid_t size +#endif + +#include "macro.h" +#include "time-util.h" + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" + +#define FORMAT_BYTES_MAX 8 + +#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" +#define ANSI_RED_ON "\x1B[31m" +#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" +#define ANSI_GREEN_ON "\x1B[32m" +#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" +#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" +#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m" +#define ANSI_HIGHLIGHT_OFF "\x1B[0m" +#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" + +size_t page_size(void); +#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +bool streq_ptr(const char *a, const char *b) _pure_; + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n), sizeof(t))) + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) + +#define malloc0(n) (calloc((n), 1)) + +static inline const char* yes_no(bool b) { + return b ? "yes" : "no"; +} + +static inline const char* true_false(bool b) { + return b ? "true" : "false"; +} + +static inline const char* strempty(const char *s) { + return s ? s : ""; +} + +static inline const char* strnull(const char *s) { + return s ? s : "(null)"; +} + +static inline const char *strna(const char *s) { + return s ? s : "n/a"; +} + +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + +static inline const char *startswith(const char *s, const char *prefix) { + if (strncmp(s, prefix, strlen(prefix)) == 0) + return s + strlen(prefix); + return NULL; +} + +static inline const char *startswith_no_case(const char *s, const char *prefix) { + if (strncasecmp(s, prefix, strlen(prefix)) == 0) + return s + strlen(prefix); + return NULL; +} + +char *endswith(const char *s, const char *postfix) _pure_; + +bool first_word(const char *s, const char *word) _pure_; + +int close_nointr(int fd); +void close_nointr_nofail(int fd); +void close_many(const int fds[], unsigned n_fd); + +int parse_size(const char *t, off_t base, off_t *size); + +int parse_boolean(const char *v) _pure_; +int parse_pid(const char *s, pid_t* ret_pid); +int parse_uid(const char *s, uid_t* ret_uid); +#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) + +int safe_atou(const char *s, unsigned *ret_u); +int safe_atoi(const char *s, int *ret_i); + +int safe_atollu(const char *s, unsigned long long *ret_u); +int safe_atolli(const char *s, long long int *ret_i); + +int safe_atod(const char *s, double *ret_d); + +#if __WORDSIZE == 32 +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(int)); + return safe_atoi(s, (int*) ret_u); +} +#else +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_u); +} +#endif + +static inline int safe_atou32(const char *s, uint32_t *ret_u) { + assert_cc(sizeof(uint32_t) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} + +static inline int safe_atoi32(const char *s, int32_t *ret_i) { + assert_cc(sizeof(int32_t) == sizeof(int)); + return safe_atoi(s, (int*) ret_i); +} + +static inline int safe_atou64(const char *s, uint64_t *ret_u) { + assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} + +static inline int safe_atoi64(const char *s, int64_t *ret_i) { + assert_cc(sizeof(int64_t) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_i); +} + +char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state); + +#define FOREACH_WORD(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, false, state) + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + _FOREACH_WORD(word, length, s, separator, false, state) + +#define FOREACH_WORD_QUOTED(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define FOREACH_WORD_SEPARATOR_QUOTED(word, length, s, separator, state) \ + _FOREACH_WORD(word, length, s, separator, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = NULL, (word) = split((s), &(length), (separator), (quoted), &(state)); (word); (word) = split((s), &(length), (separator), (quoted), &(state))) + +pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); +int get_starttime_of_pid(pid_t pid, unsigned long long *st); + +char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *replace_env(const char *format, char **env); +char **replace_env_argv(char **argv, char **env); + +int readlink_malloc(const char *p, char **r); +int readlink_and_make_absolute(const char *p, char **r); +int readlink_and_canonicalize(const char *p, char **r); + +int reset_all_signal_handlers(void); + +char *strstrip(char *s); +char *delete_chars(char *s, const char *bad); +char *truncate_nl(char *s); + +char *file_in_same_dir(const char *path, const char *filename); + +int rmdir_parents(const char *path, const char *stop); + +int get_process_state(pid_t pid); +int get_process_comm(pid_t pid, char **name); +int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line); +int get_process_exe(pid_t pid, char **name); +int get_process_uid(pid_t pid, uid_t *uid); +int get_process_gid(pid_t pid, gid_t *gid); +int get_process_capeff(pid_t pid, char **capeff); + +char hexchar(int x) _const_; +int unhexchar(char c) _const_; +char octchar(int x) _const_; +int unoctchar(char c) _const_; +char decchar(int x) _const_; +int undecchar(char c) _const_; + +char *cescape(const char *s); +char *cunescape(const char *s); +char *cunescape_length(const char *s, size_t length); +char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); + +char *xescape(const char *s, const char *bad); + +char *ascii_strlower(char *path); + +bool dirent_is_file(const struct dirent *de) _pure_; +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; + +bool ignore_file(const char *filename) _pure_; + +bool chars_intersect(const char *a, const char *b) _pure_; + +int make_stdio(int fd); +int make_null_stdio(void); +int make_console_stdio(void); + +int dev_urandom(void *p, size_t n); +void random_bytes(void *p, size_t n); + +static inline uint64_t random_u64(void) { + uint64_t u; + random_bytes(&u, sizeof(u)); + return u; +} + +static inline uint32_t random_u32(void) { + uint32_t u; + random_bytes(&u, sizeof(u)); + return u; +} + +/* For basic lookup tables with strictly enumerated entries */ +#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + scope const char *name##_to_string(type i) { \ + if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ + return NULL; \ + return name##_table[i]; \ + } \ + scope type name##_from_string(const char *s) { \ + type i; \ + if (!s) \ + return (type) -1; \ + for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ + if (name##_table[i] && \ + streq(name##_table[i], s)) \ + return i; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + int name##_to_string_alloc(type i, char **str) { \ + char *s; \ + int r; \ + if (i < 0 || i > max) \ + return -ERANGE; \ + if (i < (type) ELEMENTSOF(name##_table)) { \ + s = strdup(name##_table[i]); \ + if (!s) \ + return log_oom(); \ + } else { \ + r = asprintf(&s, "%u", i); \ + if (r < 0) \ + return log_oom(); \ + } \ + *str = s; \ + return 0; \ + } \ + type name##_from_string(const char *s) { \ + type i; \ + unsigned u = 0; \ + assert(s); \ + for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ + if (name##_table[i] && \ + streq(name##_table[i], s)) \ + return i; \ + if (safe_atou(s, &u) >= 0 && u <= max) \ + return (type) u; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +int fd_nonblock(int fd, bool nonblock); +int fd_cloexec(int fd, bool cloexec); + +int close_all_fds(const int except[], unsigned n_except); + +bool fstype_is_network(const char *fstype); + +int chvt(int vt); + +int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl); +int ask(char *ret, const char *replies, const char *text, ...) _printf_(3, 4); + +int reset_terminal_fd(int fd, bool switch_to_text); +int reset_terminal(const char *name); + +int open_terminal(const char *name, int mode); +int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout); +int release_terminal(void); + +int flush_fd(int fd); + +int ignore_signals(int sig, ...); +int default_signals(int sig, ...); +int sigaction_many(const struct sigaction *sa, ...); + +int close_pipe(int p[]); +int fopen_temporary(const char *path, FILE **_f, char **_temp_path); + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); + +bool is_device_path(const char *path); + +int dir_is_empty(const char *path); +char* dirname_malloc(const char *path); + +void rename_process(const char name[8]); + +void sigset_add_many(sigset_t *ss, ...); + +bool hostname_is_set(void); + +char* gethostname_malloc(void); +char* getlogname_malloc(void); +char* getusername_malloc(void); + +int getttyname_malloc(int fd, char **r); +int getttyname_harder(int fd, char **r); + +int get_ctty_devnr(pid_t pid, dev_t *d); +int get_ctty(pid_t, dev_t *_devnr, char **r); + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); + +int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); +int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); +int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); +int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); + +int pipe_eof(int fd); + +cpu_set_t* cpu_set_malloc(unsigned *ncpus); + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); + +int fd_columns(int fd); +unsigned columns(void); +int fd_lines(int fd); +unsigned lines(void); +void columns_lines_cache_reset(int _unused_ signum); + +bool on_tty(void); + +static inline const char *ansi_highlight(void) { + return on_tty() ? ANSI_HIGHLIGHT_ON : ""; +} + +static inline const char *ansi_highlight_red(void) { + return on_tty() ? ANSI_HIGHLIGHT_RED_ON : ""; +} + +static inline const char *ansi_highlight_green(void) { + return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : ""; +} + +static inline const char *ansi_highlight_yellow(void) { + return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : ""; +} + +static inline const char *ansi_highlight_blue(void) { + return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : ""; +} + +static inline const char *ansi_highlight_off(void) { + return on_tty() ? ANSI_HIGHLIGHT_OFF : ""; +} + +int running_in_chroot(void); + +char *ellipsize(const char *s, size_t length, unsigned percent); + /* bytes columns */ +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent); + +int touch(const char *path); + +char *unquote(const char *s, const char *quotes); +char *normalize_env_assignment(const char *s); + +int wait_for_terminate(pid_t pid, siginfo_t *status); +int wait_for_terminate_and_warn(const char *name, pid_t pid); + +noreturn void freeze(void); + +bool null_or_empty(struct stat *st) _pure_; +int null_or_empty_path(const char *fn); + +DIR *xopendirat(int dirfd, const char *name, int flags); + +char *fstab_node_to_udev_node(const char *p); + +char *resolve_dev_console(char **active); +bool tty_is_vc(const char *tty); +bool tty_is_vc_resolve(const char *tty); +bool tty_is_console(const char *tty) _pure_; +int vtnr_from_tty(const char *tty); +const char *default_term_for_tty(const char *tty); + +void execute_directory(const char *directory, DIR *_d, char *argv[]); + +int kill_and_sigcont(pid_t pid, int sig); + +bool nulstr_contains(const char*nulstr, const char *needle); + +bool plymouth_running(void); + +bool hostname_is_valid(const char *s) _pure_; +char* hostname_cleanup(char *s, bool lowercase); + +char* strshorten(char *s, size_t l); + +int terminal_vhangup_fd(int fd); +int terminal_vhangup(const char *name); + +int vt_disallocate(const char *name); + +int copy_file(const char *from, const char *to, int flags); + +int symlink_atomic(const char *from, const char *to); + +int fchmod_umask(int fd, mode_t mode); + +bool display_is_local(const char *display) _pure_; +int socket_from_display(const char *display, char **path); + +int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); +int get_group_creds(const char **groupname, gid_t *gid); + +int in_gid(gid_t gid); +int in_group(const char *name); + +char* uid_to_name(uid_t uid); +char* gid_to_name(gid_t gid); + +int glob_exists(const char *path); +int glob_extend(char ***strv, const char *path); + +int dirent_ensure_type(DIR *d, struct dirent *de); + +int in_search_path(const char *path, char **search); +int get_files_in_directory(const char *path, char ***list); + +char *strjoin(const char *x, ...) _sentinel_; + +bool is_main_thread(void); + +bool in_charset(const char *s, const char* charset) _pure_; + +int block_get_whole_disk(dev_t d, dev_t *ret); + +int file_is_priv_sticky(const char *p); + +int strdup_or_null(const char *a, char **b); + +#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)) + +int ioprio_class_to_string_alloc(int i, char **s); +int ioprio_class_from_string(const char *s); + +const char *sigchld_code_to_string(int i) _const_; +int sigchld_code_from_string(const char *s) _pure_; + +int log_facility_unshifted_to_string_alloc(int i, char **s); +int log_facility_unshifted_from_string(const char *s); + +int log_level_to_string_alloc(int i, char **s); +int log_level_from_string(const char *s); + +int sched_policy_to_string_alloc(int i, char **s); +int sched_policy_from_string(const char *s); + +const char *rlimit_to_string(int i) _const_; +int rlimit_from_string(const char *s) _pure_; + +int ip_tos_to_string_alloc(int i, char **s); +int ip_tos_from_string(const char *s); + +const char *signal_to_string(int i) _const_; +int signal_from_string(const char *s) _pure_; + +int signal_from_string_try_harder(const char *s); + +extern int saved_argc; +extern char **saved_argv; + +bool kexec_loaded(void); + +int prot_from_flags(int flags) _const_; + +char *format_bytes(char *buf, size_t l, off_t t); + +int fd_wait_for_event(int fd, int event, usec_t timeout); + +void* memdup(const void *p, size_t l) _alloc_(2); + +int is_kernel_thread(pid_t pid); + +int fd_inc_sndbuf(int fd, size_t n); +int fd_inc_rcvbuf(int fd, size_t n); + +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); + +int setrlimit_closest(int resource, const struct rlimit *rlim); + +int getenv_for_pid(pid_t pid, const char *field, char **_value); + +bool is_valid_documentation_url(const char *url) _pure_; + +bool in_initrd(void); + +void warn_melody(void); + +int get_home_dir(char **ret); +int get_shell(char **_ret); + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ + static inline void func##p(type *p) { \ + if (*p) \ + func(*p); \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +static inline void closep(int *fd) { + if (*fd >= 0) + close_nointr_nofail(*fd); +} + +static inline void umaskp(mode_t *u) { + umask(*u); +} + +static inline void close_pipep(int (*p)[2]) { + close_pipe(*p); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); + +#define _cleanup_free_ _cleanup_(freep) +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_umask_ _cleanup_(umaskp) +#define _cleanup_globfree_ _cleanup_(globfree) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) +#define _cleanup_endmntent_ _cleanup_(endmntentp) +#define _cleanup_close_pipe_ _cleanup_(close_pipep) + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) + return NULL; + + return malloc(a * b); +} + +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { + if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) + return NULL; + + return memdup(p, a * b); +} + +bool filename_is_safe(const char *p) _pure_; +bool path_is_safe(const char *p) _pure_; +bool string_is_safe(const char *p) _pure_; +bool string_has_cc(const char *p) _pure_; + +/** + * Check if a string contains any glob patterns. + */ +_pure_ static inline bool string_is_glob(const char *p) { + return !!strpbrk(p, GLOB_CHARS); +} + +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + void *arg); + +bool is_locale_utf8(void); + +typedef enum DrawSpecialChar { + DRAW_TREE_VERT, + DRAW_TREE_BRANCH, + DRAW_TREE_RIGHT, + DRAW_TREE_SPACE, + DRAW_TRIANGULAR_BULLET, + DRAW_BLACK_CIRCLE, + _DRAW_SPECIAL_CHAR_MAX +} DrawSpecialChar; +const char *draw_special_char(DrawSpecialChar ch); + +char *strreplace(const char *text, const char *old_string, const char *new_string); + +char *strip_tab_ansi(char **p, size_t *l); + +int on_ac_power(void); + +int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f); +int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f); + +#define FOREACH_LINE(line, f, on_error) \ + for (;;) \ + if (!fgets(line, sizeof(line), f)) { \ + if (ferror(f)) { \ + on_error; \ + } \ + break; \ + } else + +#define FOREACH_DIRENT(de, d, on_error) \ + for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ + if (!de) { \ + if (errno > 0) { \ + on_error; \ + } \ + break; \ + } else if (ignore_file((de)->d_name)) \ + continue; \ + else + +static inline void *mempset(void *s, int c, size_t n) { + memset(s, c, n); + return (uint8_t*)s + n; +} + +char *hexmem(const void *p, size_t l); +void *unhexmem(const char *p, size_t l); + +char *strextend(char **x, ...) _sentinel_; +char *strrep(const char *s, unsigned n); + +void* greedy_realloc(void **p, size_t *allocated, size_t need); +void* greedy_realloc0(void **p, size_t *allocated, size_t need); +#define GREEDY_REALLOC(array, allocated, need) \ + greedy_realloc((void**) &(array), &(allocated), sizeof((array)[0]) * (need)) +#define GREEDY_REALLOC0(array, allocated, need) \ + greedy_realloc0((void**) &(array), &(allocated), sizeof((array)[0]) * (need)) + +static inline void _reset_errno_(int *saved_errno) { + errno = *saved_errno; +} + +#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno + +struct _umask_struct_ { + mode_t mask; + bool quit; +}; + +static inline void _reset_umask_(struct _umask_struct_ *s) { + umask(s->mask); +}; + +#define RUN_WITH_UMASK(mask) \ + for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ + !_saved_umask_.quit ; \ + _saved_umask_.quit = true) + +static inline unsigned u64log2(uint64_t n) { +#if __SIZEOF_LONG_LONG__ == 8 + return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; +#else +#error "Wut?" +#endif +} + +static inline unsigned u32ctz(uint32_t n) { +#if __SIZEOF_INT__ == 4 + return __builtin_ctz(n); +#else +#error "Wut?" +#endif +} + +static inline bool logind_running(void) { + return access("/run/systemd/seats/", F_OK) >= 0; +} + +#define DECIMAL_STR_WIDTH(x) \ + ({ \ + typeof(x) _x_ = (x); \ + unsigned ans = 1; \ + while (_x_ /= 10) \ + ans++; \ + ans; \ + }) + +int unlink_noerrno(const char *path); + +#define alloca0(n) \ + ({ \ + char *_new_; \ + size_t _len_ = n; \ + _new_ = alloca(_len_); \ + (void *) memset(_new_, 0, _len_); \ + }) + +#define strappenda(a, b) \ + ({ \ + const char *_a_ = (a), *_b_ = (b); \ + char *_c_; \ + size_t _x_, _y_; \ + _x_ = strlen(_a_); \ + _y_ = strlen(_b_); \ + _c_ = alloca(_x_ + _y_ + 1); \ + strcpy(stpcpy(_c_, _a_), _b_); \ + _c_; \ + }) + +#define procfs_file_alloca(pid, field) \ + ({ \ + pid_t _pid_ = (pid); \ + const char *_r_; \ + if (_pid_ == 0) { \ + _r_ = ("/proc/self/" field); \ + } else { \ + _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ + sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ + } \ + _r_; \ + }) + +struct _locale_struct_ { + locale_t saved_locale; + locale_t new_locale; + bool quit; +}; + +static inline void _reset_locale_(struct _locale_struct_ *s) { + PROTECT_ERRNO; + if (s->saved_locale != (locale_t) 0) + uselocale(s->saved_locale); + if (s->new_locale != (locale_t) 0) + freelocale(s->new_locale); +} + +#define RUN_WITH_LOCALE(mask, loc) \ + for (_cleanup_(_reset_locale_) struct _locale_struct_ _saved_locale_ = { (locale_t) 0, (locale_t) 0, false }; \ + ({ \ + if (!_saved_locale_.quit) { \ + PROTECT_ERRNO; \ + _saved_locale_.new_locale = newlocale((mask), (loc), (locale_t) 0); \ + if (_saved_locale_.new_locale != (locale_t) 0) \ + _saved_locale_.saved_locale = uselocale(_saved_locale_.new_locale); \ + } \ + !_saved_locale_.quit; }) ; \ + _saved_locale_.quit = true) + +bool id128_is_valid(const char *s) _pure_; + +int split_pair(const char *s, const char *sep, char **l, char **r); + +int shall_restore_state(void); + +/** + * 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, + int (*compar)(const void *, const void *)) { + if (nmemb) { + assert(base); + qsort(base, nmemb, size, compar); + } +} + +int proc_cmdline(char **ret); +int parse_proc_cmdline(int (*parse_word)(const char *word)); + +int container_get_leader(const char *machine, pid_t *pid); + +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd); +int namespace_enter(int pidns_fd, int mntns_fd, int root_fd); + +bool pid_is_alive(pid_t pid); +bool pid_is_unwaited(pid_t pid); + +int getpeercred(int fd, struct ucred *ucred); +int getpeersec(int fd, char **ret); + +int writev_safe(int fd, const struct iovec *w, int j); + +int mkostemp_safe(char *pattern, int flags); +int open_tmpfile(const char *path, int flags); + +int fd_warn_permissions(const char *path, int fd); + +unsigned long personality_from_string(const char *p); +const char *personality_to_string(unsigned long); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c new file mode 100644 index 0000000..32996fa --- /dev/null +++ b/src/shared/utmp-wtmp.c @@ -0,0 +1,403 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "path-util.h" +#include "utmp-wtmp.h" + +int utmp_get_runlevel(int *runlevel, int *previous) { + struct utmpx *found, lookup = { .ut_type = RUN_LVL }; + int r; + const char *e; + + assert(runlevel); + + /* If these values are set in the environment this takes + * precedence. Presumably, sysvinit does this to work around a + * race condition that would otherwise exist where we'd always + * go to disk and hence might read runlevel data that might be + * very new and does not apply to the current script being + * executed. */ + + e = getenv("RUNLEVEL"); + if (e && e[0] > 0) { + *runlevel = e[0]; + + if (previous) { + /* $PREVLEVEL seems to be an Upstart thing */ + + e = getenv("PREVLEVEL"); + if (e && e[0] > 0) + *previous = e[0]; + else + *previous = 0; + } + + return 0; + } + + if (utmpxname(_PATH_UTMPX) < 0) + return -errno; + + setutxent(); + + found = getutxid(&lookup); + if (!found) + r = -errno; + else { + int a, b; + + a = found->ut_pid & 0xFF; + b = (found->ut_pid >> 8) & 0xFF; + + *runlevel = a; + if (previous) + *previous = b; + + r = 0; + } + + endutxent(); + + return r; +} + +static void init_timestamp(struct utmpx *store, usec_t t) { + assert(store); + + zero(*store); + + if (t <= 0) + t = now(CLOCK_REALTIME); + + store->ut_tv.tv_sec = t / USEC_PER_SEC; + store->ut_tv.tv_usec = t % USEC_PER_SEC; +} + +static void init_entry(struct utmpx *store, usec_t t) { + struct utsname uts = {}; + + assert(store); + + init_timestamp(store, t); + + if (uname(&uts) >= 0) + strncpy(store->ut_host, uts.release, sizeof(store->ut_host)); + + strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */ + strncpy(store->ut_id, "~~", sizeof(store->ut_id)); +} + +static int write_entry_utmp(const struct utmpx *store) { + int r; + + assert(store); + + /* utmp is similar to wtmp, but there is only one entry for + * each entry type resp. user; i.e. basically a key/value + * table. */ + + if (utmpxname(_PATH_UTMPX) < 0) + return -errno; + + setutxent(); + + if (!pututxline(store)) + r = -errno; + else + r = 0; + + endutxent(); + + return r; +} + +static int write_entry_wtmp(const struct utmpx *store) { + assert(store); + + /* wtmp is a simple append-only file where each entry is + simply appended to * the end; i.e. basically a log. */ + + errno = 0; + updwtmpx(_PATH_WTMPX, store); + return -errno; +} + +static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) { + int r, s; + + r = write_entry_utmp(store_utmp); + s = write_entry_wtmp(store_wtmp); + + if (r >= 0) + r = s; + + /* If utmp/wtmp have been disabled, that's a good thing, hence + * ignore the errors */ + if (r == -ENOENT) + r = 0; + + return r; +} + +static int write_entry_both(const struct utmpx *store) { + return write_utmp_wtmp(store, store); +} + +int utmp_put_shutdown(void) { + struct utmpx store; + + init_entry(&store, 0); + + store.ut_type = RUN_LVL; + strncpy(store.ut_user, "shutdown", sizeof(store.ut_user)); + + return write_entry_both(&store); +} + +int utmp_put_reboot(usec_t t) { + struct utmpx store; + + init_entry(&store, t); + + store.ut_type = BOOT_TIME; + strncpy(store.ut_user, "reboot", sizeof(store.ut_user)); + + return write_entry_both(&store); +} + +_pure_ static const char *sanitize_id(const char *id) { + size_t l; + + assert(id); + l = strlen(id); + + if (l <= sizeof(((struct utmpx*) NULL)->ut_id)) + return id; + + return id + l - sizeof(((struct utmpx*) NULL)->ut_id); +} + +int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) { + struct utmpx store; + + assert(id); + + init_timestamp(&store, 0); + + store.ut_type = INIT_PROCESS; + store.ut_pid = pid; + store.ut_session = sid; + + strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id)); + + if (line) + strncpy(store.ut_line, basename(line), sizeof(store.ut_line)); + + return write_entry_both(&store); +} + +int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { + struct utmpx lookup, store, store_wtmp, *found; + + assert(id); + + setutxent(); + + zero(lookup); + lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ + strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id)); + + found = getutxid(&lookup); + if (!found) + return 0; + + if (found->ut_pid != pid) + return 0; + + memcpy(&store, found, sizeof(store)); + store.ut_type = DEAD_PROCESS; + store.ut_exit.e_termination = code; + store.ut_exit.e_exit = status; + + zero(store.ut_user); + zero(store.ut_host); + zero(store.ut_tv); + + memcpy(&store_wtmp, &store, sizeof(store_wtmp)); + /* wtmp wants the current time */ + init_timestamp(&store_wtmp, 0); + + return write_utmp_wtmp(&store, &store_wtmp); +} + + +int utmp_put_runlevel(int runlevel, int previous) { + struct utmpx store; + int r; + + assert(runlevel > 0); + + if (previous <= 0) { + /* Find the old runlevel automatically */ + + r = utmp_get_runlevel(&previous, NULL); + if (r < 0) { + if (r != -ESRCH) + return r; + + previous = 0; + } + } + + if (previous == runlevel) + return 0; + + init_entry(&store, 0); + + store.ut_type = RUN_LVL; + store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8); + strncpy(store.ut_user, "runlevel", sizeof(store.ut_user)); + + return write_entry_both(&store); +} + +#define TIMEOUT_MSEC 50 + +static int write_to_terminal(const char *tty, const char *message) { + _cleanup_close_ int fd = -1; + const char *p; + size_t left; + usec_t end; + + assert(tty); + assert(message); + + fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC); + if (fd < 0 || !isatty(fd)) + return -errno; + + p = message; + left = strlen(message); + + end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC; + + while (left > 0) { + ssize_t n; + struct pollfd pollfd = { + .fd = fd, + .events = POLLOUT, + }; + usec_t t; + int k; + + t = now(CLOCK_MONOTONIC); + + if (t >= end) + return -ETIME; + + k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC); + if (k < 0) + return -errno; + + if (k == 0) + return -ETIME; + + n = write(fd, p, left); + if (n < 0) { + if (errno == EAGAIN) + continue; + + return -errno; + } + + assert((size_t) n <= left); + + p += n; + left -= n; + } + + return 0; +} + +int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) { + _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL; + char date[FORMAT_TIMESTAMP_MAX]; + struct utmpx *u; + int r; + + hn = gethostname_malloc(); + un = getlogname_malloc(); + if (!hn || !un) + return -ENOMEM; + + getttyname_harder(STDIN_FILENO, &tty); + + if (asprintf(&text, + "\a\r\n" + "Broadcast message from %s@%s%s%s (%s):\r\n\r\n" + "%s\r\n\r\n", + un, hn, + tty ? " on " : "", strempty(tty), + format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)), + message) < 0) + return -ENOMEM; + + setutxent(); + + r = 0; + + while ((u = getutxent())) { + _cleanup_free_ char *buf = NULL; + const char *path; + int q; + + if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0) + continue; + + /* this access is fine, because strlen("/dev/") << 32 (UT_LINESIZE) */ + if (path_startswith(u->ut_line, "/dev/")) + path = u->ut_line; + else { + if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0) + return -ENOMEM; + + path = buf; + } + + if (!match_tty || match_tty(path)) { + q = write_to_terminal(path, text); + if (q < 0) + r = q; + } + } + + return r; +} diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h new file mode 100644 index 0000000..5924023 --- /dev/null +++ b/src/shared/utmp-wtmp.h @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +int utmp_get_runlevel(int *runlevel, int *previous); + +int utmp_put_shutdown(void); +int utmp_put_reboot(usec_t timestamp); +int utmp_put_runlevel(int runlevel, int previous); + +int utmp_put_dead_process(const char *id, pid_t pid, int code, int status); +int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line); + +int utmp_wall(const char *message, bool (*match_tty)(const char *tty)); diff --git a/src/shared/virt.c b/src/shared/virt.c new file mode 100644 index 0000000..ec2ddcf --- /dev/null +++ b/src/shared/virt.c @@ -0,0 +1,297 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "virt.h" +#include "fileio.h" + +static int detect_vm_cpuid(const char **_id) { + + /* Both CPUID and DMI are x86 specific interfaces... */ +#if defined(__i386__) || defined(__x86_64__) + + static const char cpuid_vendor_table[] = + "XenVMMXenVMM\0" "xen\0" + "KVMKVMKVM\0" "kvm\0" + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + "VMwareVMware\0" "vmware\0" + /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ + "Microsoft Hv\0" "microsoft\0"; + + uint32_t eax, ecx; + union { + uint32_t sig32[3]; + char text[13]; + } sig = {}; + const char *j, *k; + bool hypervisor; + + /* http://lwn.net/Articles/301888/ */ + +#if defined (__i386__) +#define REG_a "eax" +#define REG_b "ebx" +#elif defined (__amd64__) +#define REG_a "rax" +#define REG_b "rbx" +#endif + + /* First detect whether there is a hypervisor */ + eax = 1; + __asm__ __volatile__ ( + /* ebx/rbx is being used for PIC! */ + " push %%"REG_b" \n\t" + " cpuid \n\t" + " pop %%"REG_b" \n\t" + + : "=a" (eax), "=c" (ecx) + : "0" (eax) + ); + + hypervisor = !!(ecx & 0x80000000U); + + if (hypervisor) { + + /* There is a hypervisor, see what it is */ + eax = 0x40000000U; + __asm__ __volatile__ ( + /* ebx/rbx is being used for PIC! */ + " push %%"REG_b" \n\t" + " cpuid \n\t" + " mov %%ebx, %1 \n\t" + " pop %%"REG_b" \n\t" + + : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) + : "0" (eax) + ); + + NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) + if (streq(sig.text, j)) { + *_id = k; + return 1; + } + + *_id = "other"; + return 0; + } +#endif + + return 0; +} + +static int detect_vm_dmi(const char **_id) { + + /* Both CPUID and DMI are x86 specific interfaces... */ +#if defined(__i386__) || defined(__x86_64__) + + static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", + "/sys/class/dmi/id/bios_vendor" + }; + + static const char dmi_vendor_table[] = + "QEMU\0" "qemu\0" + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + "VMware\0" "vmware\0" + "VMW\0" "vmware\0" + "Microsoft Corporation\0" "microsoft\0" + "innotek GmbH\0" "oracle\0" + "Xen\0" "xen\0" + "Bochs\0" "bochs\0"; + unsigned i; + + for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { + _cleanup_free_ char *s = NULL; + const char *j, *k; + int r; + + r = read_one_line_file(dmi_vendors[i], &s); + if (r < 0) { + if (r != -ENOENT) + return r; + + continue; + } + + NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) + if (startswith(s, j)) { + *_id = k; + return 1; + } + } +#endif + + return 0; +} + +/* Returns a short identifier for the various VM implementations */ +int detect_vm(const char **id) { + _cleanup_free_ char *hvtype = NULL, *cpuinfo_contents = NULL; + static thread_local int cached_found = -1; + static thread_local const char *cached_id = NULL; + const char *_id = NULL; + int r; + + if (_likely_(cached_found >= 0)) { + + if (id) + *id = cached_id; + + return cached_found; + } + + /* Try high-level hypervisor sysfs file first: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=61491 */ + r = read_one_line_file("/sys/hypervisor/type", &hvtype); + if (r >= 0) { + if (streq(hvtype, "xen")) { + _id = "xen"; + r = 1; + goto finish; + } + } else if (r != -ENOENT) + return r; + + /* this will set _id to "other" and return 0 for unknown hypervisors */ + r = detect_vm_cpuid(&_id); + if (r != 0) + goto finish; + + r = detect_vm_dmi(&_id); + if (r != 0) + goto finish; + + if (_id) { + /* "other" */ + r = 1; + goto finish; + } + + /* Detect User-Mode Linux by reading /proc/cpuinfo */ + r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); + if (r < 0) + return r; + if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) { + _id = "uml"; + r = 1; + goto finish; + } + + r = 0; + +finish: + cached_found = r; + + cached_id = _id; + if (id) + *id = _id; + + return r; +} + +int detect_container(const char **id) { + + static thread_local int cached_found = -1; + static thread_local const char *cached_id = NULL; + + _cleanup_free_ char *e = NULL; + const char *_id = NULL; + int r; + + if (_likely_(cached_found >= 0)) { + + if (id) + *id = cached_id; + + return cached_found; + } + + /* Unfortunately many of these operations require root access + * in one way or another */ + + r = running_in_chroot(); + if (r < 0) + return r; + if (r > 0) { + _id = "chroot"; + goto finish; + } + + /* /proc/vz exists in container and outside of the container, + * /proc/bc only outside of the container. */ + if (access("/proc/vz", F_OK) >= 0 && + access("/proc/bc", F_OK) < 0) { + _id = "openvz"; + r = 1; + goto finish; + } + + r = getenv_for_pid(1, "container", &e); + if (r < 0) + return r; + if (r == 0) + goto finish; + + /* We only recognize a selected few here, since we want to + * enforce a redacted namespace */ + if (streq(e, "lxc")) + _id ="lxc"; + else if (streq(e, "lxc-libvirt")) + _id = "lxc-libvirt"; + else if (streq(e, "systemd-nspawn")) + _id = "systemd-nspawn"; + else + _id = "other"; + +finish: + cached_found = r; + + cached_id = _id; + if (id) + *id = _id; + + return r; +} + +/* Returns a short identifier for the various VM/container implementations */ +int detect_virtualization(const char **id) { + int r; + + r = detect_container(id); + if (r < 0) + return r; + if (r > 0) + return VIRTUALIZATION_CONTAINER; + + r = detect_vm(id); + if (r < 0) + return r; + if (r > 0) + return VIRTUALIZATION_VM; + + return VIRTUALIZATION_NONE; +} diff --git a/src/shared/virt.h b/src/shared/virt.h new file mode 100644 index 0000000..7194ab2 --- /dev/null +++ b/src/shared/virt.h @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +int detect_vm(const char **id); +int detect_container(const char **id); + +enum { + VIRTUALIZATION_NONE = 0, + VIRTUALIZATION_VM, + VIRTUALIZATION_CONTAINER, + _VIRTUALIZATION_MAX, + _VIRTUALIZATION_INVALID = -1 +}; + +int detect_virtualization(const char **id); diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c new file mode 100644 index 0000000..ddbe7af --- /dev/null +++ b/src/shared/watchdog.c @@ -0,0 +1,169 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "watchdog.h" +#include "log.h" + +static int watchdog_fd = -1; +static usec_t watchdog_timeout = (usec_t) -1; + +static int update_timeout(void) { + int r; + + if (watchdog_fd < 0) + return 0; + + if (watchdog_timeout == (usec_t) -1) + return 0; + else if (watchdog_timeout == 0) { + int flags; + + flags = WDIOS_DISABLECARD; + r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); + if (r < 0) { + log_warning("Failed to disable hardware watchdog: %m"); + return -errno; + } + } else { + int sec, flags; + char buf[FORMAT_TIMESPAN_MAX]; + + sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); + r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec); + if (r < 0) { + log_warning("Failed to set timeout to %is: %m", sec); + return -errno; + } + + watchdog_timeout = (usec_t) sec * USEC_PER_SEC; + log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout, 0)); + + flags = WDIOS_ENABLECARD; + r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); + if (r < 0) { + log_warning("Failed to enable hardware watchdog: %m"); + return -errno; + } + + r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0); + if (r < 0) { + log_warning("Failed to ping hardware watchdog: %m"); + return -errno; + } + } + + return 0; +} + +static int open_watchdog(void) { + struct watchdog_info ident; + + if (watchdog_fd >= 0) + return 0; + + watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC); + if (watchdog_fd < 0) + return -errno; + + if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0) + log_info("Hardware watchdog '%s', version %x", + ident.identity, + ident.firmware_version); + + return update_timeout(); +} + +int watchdog_set_timeout(usec_t *usec) { + int r; + + watchdog_timeout = *usec; + + /* If we didn't open the watchdog yet and didn't get any + * explicit timeout value set, don't do anything */ + if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1) + return 0; + + if (watchdog_fd < 0) + r = open_watchdog(); + else + r = update_timeout(); + + *usec = watchdog_timeout; + + return r; +} + +int watchdog_ping(void) { + int r; + + if (watchdog_fd < 0) { + r = open_watchdog(); + if (r < 0) + return r; + } + + r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0); + if (r < 0) { + log_warning("Failed to ping hardware watchdog: %m"); + return -errno; + } + + return 0; +} + +void watchdog_close(bool disarm) { + int r; + + if (watchdog_fd < 0) + return; + + if (disarm) { + int flags; + + /* Explicitly disarm it */ + flags = WDIOS_DISABLECARD; + r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); + if (r < 0) + log_warning("Failed to disable hardware watchdog: %m"); + + /* To be sure, use magic close logic, too */ + for (;;) { + static const char v = 'V'; + + if (write(watchdog_fd, &v, 1) > 0) + break; + + if (errno != EINTR) { + log_error("Failed to disarm watchdog timer: %m"); + break; + } + } + } + + close_nointr_nofail(watchdog_fd); + watchdog_fd = -1; +} diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h new file mode 100644 index 0000000..b748b15 --- /dev/null +++ b/src/shared/watchdog.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" + +int watchdog_set_timeout(usec_t *usec); +int watchdog_ping(void); +void watchdog_close(bool disarm); diff --git a/src/shared/xml.c b/src/shared/xml.c new file mode 100644 index 0000000..be56b08 --- /dev/null +++ b/src/shared/xml.c @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "xml.h" + +enum { + STATE_TEXT, + STATE_TAG, + STATE_ATTRIBUTE, +}; + +/* We don't actually do real XML here. We only read a simplistic + * subset, that is a bit less strict that XML and lacks all the more + * complex features, like entities, or namespaces. However, we do + * support some HTML5-like simplifications */ + +int xml_tokenize(const char **p, char **name, void **state) { + const char *c, *e, *b; + char *ret; + int t; + + assert(p); + assert(*p); + assert(name); + assert(state); + + t = PTR_TO_INT(*state); + c = *p; + + for (;;) { + if (*c == 0) + return XML_END; + + switch (t) { + + case STATE_TEXT: { + int x; + + e = strchrnul(c, '<'); + if (e > c) { + /* More text... */ + ret = strndup(c, e - c); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_TEXT); + + return XML_TEXT; + } + + assert(*e == '<'); + b = c + 1; + + if (startswith(b, "!--")) { + /* A comment */ + e = strstr(b + 3, "-->"); + if (!e) + return -EINVAL; + + c = e + 3; + continue; + } + + if (*b == '?') { + /* Processing instruction */ + + e = strstr(b + 1, "?>"); + if (!e) + return -EINVAL; + + c = e + 2; + continue; + } + + if (*b == '!') { + /* DTD */ + + e = strchr(b + 1, '>'); + if (!e) + return -EINVAL; + + c = e + 1; + continue; + } + + if (*b == '/') { + /* A closing tag */ + x = XML_TAG_CLOSE; + b++; + } else + x = XML_TAG_OPEN; + + e = strpbrk(b, WHITESPACE "/>"); + if (!e) + return -EINVAL; + + ret = strndup(b, e - b); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_TAG); + + return x; + } + + case STATE_TAG: + + b = c + strspn(c, WHITESPACE); + if (*b == 0) + return -EINVAL; + + e = b + strcspn(b, WHITESPACE "=/>"); + if (e > b) { + /* An attribute */ + + ret = strndup(b, e - b); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e; + *state = INT_TO_PTR(STATE_ATTRIBUTE); + + return XML_ATTRIBUTE_NAME; + } + + if (startswith(b, "/>")) { + /* An empty tag */ + + *name = NULL; /* For empty tags we return a NULL name, the caller must be prepared for that */ + *p = b + 2; + *state = INT_TO_PTR(STATE_TEXT); + + return XML_TAG_CLOSE_EMPTY; + } + + if (*b != '>') + return -EINVAL; + + c = b + 1; + t = STATE_TEXT; + continue; + + case STATE_ATTRIBUTE: + + if (*c == '=') { + c++; + + if (*c == '\'' || *c == '\"') { + /* Tag with a quoted value */ + + e = strchr(c+1, *c); + if (!e) + return -EINVAL; + + ret = strndup(c+1, e - c - 1); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = e + 1; + *state = INT_TO_PTR(STATE_TAG); + + return XML_ATTRIBUTE_VALUE; + + } + + /* Tag with a value without quotes */ + + b = strpbrk(c, WHITESPACE ">"); + if (!b) + b = c; + + ret = strndup(c, b - c); + if (!ret) + return -ENOMEM; + + *name = ret; + *p = b; + *state = INT_TO_PTR(STATE_TAG); + return XML_ATTRIBUTE_VALUE; + } + + t = STATE_TAG; + continue; + } + + } + + assert_not_reached("Bad state"); +} diff --git a/src/shared/xml.h b/src/shared/xml.h new file mode 100644 index 0000000..18ebbd9 --- /dev/null +++ b/src/shared/xml.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +enum { + XML_END, + XML_TEXT, + XML_TAG_OPEN, + XML_TAG_CLOSE, + XML_TAG_CLOSE_EMPTY, + XML_ATTRIBUTE_NAME, + XML_ATTRIBUTE_VALUE +}; + +int xml_tokenize(const char **p, char **name, void **state); diff --git a/src/shutdown.c b/src/shutdown.c deleted file mode 100644 index 11213f9..0000000 --- a/src/shutdown.c +++ /dev/null @@ -1,469 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 ProFUSION embedded systems - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "missing.h" -#include "log.h" -#include "umount.h" -#include "util.h" -#include "virt.h" - -#define TIMEOUT_USEC (5 * USEC_PER_SEC) -#define FINALIZE_ATTEMPTS 50 - -static bool ignore_proc(pid_t pid) { - if (pid == 1) - return true; - - /* TODO: add more ignore rules here: device-mapper, etc */ - - return false; -} - -static bool is_kernel_thread(pid_t pid) -{ - char buf[PATH_MAX]; - FILE *f; - char c; - size_t count; - - snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long)pid); - f = fopen(buf, "re"); - if (!f) - return true; /* not really, but has the desired effect */ - - count = fread(&c, 1, 1, f); - fclose(f); - return count != 1; -} - -static int killall(int sign) { - DIR *dir; - struct dirent *d; - unsigned int n_processes = 0; - - if ((dir = opendir("/proc")) == NULL) - return -errno; - - while ((d = readdir(dir))) { - pid_t pid; - - if (parse_pid(d->d_name, &pid) < 0) - continue; - - if (is_kernel_thread(pid)) - continue; - - if (ignore_proc(pid)) - continue; - - if (kill(pid, sign) == 0) - n_processes++; - else - log_warning("Could not kill %d: %m", pid); - } - - closedir(dir); - - return n_processes; -} - -static void wait_for_children(int n_processes, sigset_t *mask) { - usec_t until; - - assert(mask); - - until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC; - for (;;) { - struct timespec ts; - int k; - usec_t n; - - for (;;) { - pid_t pid = waitpid(-1, NULL, WNOHANG); - - if (pid == 0) - break; - - if (pid < 0 && errno == ECHILD) - return; - - if (n_processes > 0) - if (--n_processes == 0) - return; - } - - n = now(CLOCK_MONOTONIC); - if (n >= until) - return; - - timespec_store(&ts, until - n); - - if ((k = sigtimedwait(mask, NULL, &ts)) != SIGCHLD) { - - if (k < 0 && errno != EAGAIN) { - log_error("sigtimedwait() failed: %m"); - return; - } - - if (k >= 0) - log_warning("sigtimedwait() returned unexpected signal."); - } - } -} - -static void send_signal(int sign) { - sigset_t mask, oldmask; - int n_processes; - - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGCHLD) == 0); - assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); - - if (kill(-1, SIGSTOP) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGSTOP) failed: %m"); - - n_processes = killall(sign); - - if (kill(-1, SIGCONT) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGCONT) failed: %m"); - - if (n_processes <= 0) - goto finish; - - wait_for_children(n_processes, &mask); - -finish: - sigprocmask(SIG_SETMASK, &oldmask, NULL); -} - -static void ultimate_send_signal(int sign) { - sigset_t mask, oldmask; - int r; - - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGCHLD) == 0); - assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); - - if (kill(-1, SIGSTOP) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGSTOP) failed: %m"); - - r = kill(-1, sign); - if (r < 0 && errno != ESRCH) - log_warning("kill(-1, %s) failed: %m", signal_to_string(sign)); - - if (kill(-1, SIGCONT) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGCONT) failed: %m"); - - if (r < 0) - goto finish; - - wait_for_children(0, &mask); - -finish: - sigprocmask(SIG_SETMASK, &oldmask, NULL); -} - -static int prepare_new_root(void) { - static const char dirs[] = - "/run/initramfs/oldroot\0" - "/run/initramfs/proc\0" - "/run/initramfs/sys\0" - "/run/initramfs/dev\0" - "/run/initramfs/run\0"; - - const char *dir; - - if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) { - log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m"); - return -errno; - } - - if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) { - log_error("Failed to make /run/initramfs private mount: %m"); - return -errno; - } - - NULSTR_FOREACH(dir, dirs) - if (mkdir_p(dir, 0755) < 0 && errno != EEXIST) { - log_error("Failed to mkdir %s: %m", dir); - return -errno; - } - - if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) { - log_error("Failed to mount bind /sys on /run/initramfs/sys: %m"); - return -errno; - } - - if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) { - log_error("Failed to mount bind /proc on /run/initramfs/proc: %m"); - return -errno; - } - - if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) { - log_error("Failed to mount bind /dev on /run/initramfs/dev: %m"); - return -errno; - } - - if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) { - log_error("Failed to mount bind /run on /run/initramfs/run: %m"); - return -errno; - } - - return 0; -} - -static int pivot_to_new_root(void) { - int fd; - - chdir("/run/initramfs"); - - /* - In case some evil process made "/" MS_SHARED - It works for pivot_root, but the ref count for the root device - is not decreasing :-/ - */ - if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) < 0) { - log_error("Failed to make \"/\" private mount %m"); - return -errno; - } - - if (pivot_root(".", "oldroot") < 0) { - log_error("pivot failed: %m"); - /* only chroot if pivot root succeded */ - return -errno; - } - - chroot("."); - log_info("Successfully changed into root pivot."); - - fd = open("/dev/console", O_RDWR); - if (fd < 0) - log_error("Failed to open /dev/console: %m"); - else { - make_stdio(fd); - - /* Initialize the controlling terminal */ - setsid(); - ioctl(STDIN_FILENO, TIOCSCTTY, NULL); - } - - return 0; -} - -int main(int argc, char *argv[]) { - int cmd, r; - unsigned retries; - bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; - bool killed_everbody = false, in_container; - - log_parse_environment(); - log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */ - log_open(); - - umask(0022); - - if (getpid() != 1) { - log_error("Not executed by init (pid 1)."); - r = -EPERM; - goto error; - } - - if (argc != 2) { - log_error("Invalid number of arguments."); - r = -EINVAL; - goto error; - } - - in_container = detect_container(NULL) > 0; - - if (streq(argv[1], "reboot")) - cmd = RB_AUTOBOOT; - else if (streq(argv[1], "poweroff")) - cmd = RB_POWER_OFF; - else if (streq(argv[1], "halt")) - cmd = RB_HALT_SYSTEM; - else if (streq(argv[1], "kexec")) - cmd = LINUX_REBOOT_CMD_KEXEC; - else { - log_error("Unknown action '%s'.", argv[1]); - r = -EINVAL; - goto error; - } - - /* lock us into memory */ - if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) - log_warning("Cannot lock process memory: %m"); - - log_info("Sending SIGTERM to remaining processes..."); - send_signal(SIGTERM); - - log_info("Sending SIGKILL to remaining processes..."); - send_signal(SIGKILL); - - if (in_container) - need_swapoff = false; - - /* Unmount all mountpoints, swaps, and loopback devices */ - for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { - bool changed = false; - - if (need_umount) { - log_info("Unmounting file systems."); - r = umount_all(&changed); - if (r == 0) - need_umount = false; - else if (r > 0) - log_info("Not all file systems unmounted, %d left.", r); - else - log_error("Failed to unmount file systems: %s", strerror(-r)); - } - - if (need_swapoff) { - log_info("Disabling swaps."); - r = swapoff_all(&changed); - if (r == 0) - need_swapoff = false; - else if (r > 0) - log_info("Not all swaps are turned off, %d left.", r); - else - log_error("Failed to turn off swaps: %s", strerror(-r)); - } - - if (need_loop_detach) { - log_info("Detaching loop devices."); - r = loopback_detach_all(&changed); - if (r == 0) - need_loop_detach = false; - else if (r > 0) - log_info("Not all loop devices detached, %d left.", r); - else - log_error("Failed to detach loop devices: %s", strerror(-r)); - } - - if (need_dm_detach) { - log_info("Detaching DM devices."); - r = dm_detach_all(&changed); - if (r == 0) - need_dm_detach = false; - else if (r > 0) - log_warning("Not all DM devices detached, %d left.", r); - else - log_error("Failed to detach DM devices: %s", strerror(-r)); - } - - if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { - if (retries > 0) - log_info("All filesystems, swaps, loop devices, DM devices detached."); - /* Yay, done */ - break; - } - - /* If in this iteration we didn't manage to - * unmount/deactivate anything, we either kill more - * processes, or simply give up */ - if (!changed) { - - if (killed_everbody) { - /* Hmm, we already killed everybody, - * let's just give up */ - log_error("Cannot finalize remaining file systems and devices, giving up."); - break; - } - - log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes."); - ultimate_send_signal(SIGTERM); - ultimate_send_signal(SIGKILL); - killed_everbody = true; - } - - log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1); - } - - if (retries >= FINALIZE_ATTEMPTS) - log_error("Too many iterations, giving up."); - - execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL); - - /* If we are in a container, just exit, this will kill our - * container for good. */ - if (in_container) { - log_error("Exiting container."); - exit(0); - } - - if (access("/run/initramfs/shutdown", X_OK) == 0) { - - if (prepare_new_root() >= 0 && - pivot_to_new_root() >= 0) { - execv("/shutdown", argv); - log_error("Failed to execute shutdown binary: %m"); - } - } - - sync(); - - if (cmd == LINUX_REBOOT_CMD_KEXEC) { - /* We cheat and exec kexec to avoid doing all its work */ - pid_t pid = fork(); - - if (pid < 0) - log_error("Could not fork: %m. Falling back to normal reboot."); - else if (pid > 0) { - wait_for_terminate_and_warn("kexec", pid); - log_warning("kexec failed. Falling back to normal reboot."); - } else { - /* Child */ - const char *args[3] = { "/sbin/kexec", "-e", NULL }; - execv(args[0], (char * const *) args); - return EXIT_FAILURE; - } - - cmd = RB_AUTOBOOT; - } - - reboot(cmd); - log_error("Failed to invoke reboot(): %m"); - r = -errno; - - error: - log_error("Critical error while doing system shutdown: %s", strerror(-r)); - - freeze(); - return EXIT_FAILURE; -} diff --git a/src/shutdownd.c b/src/shutdownd.c deleted file mode 100644 index 0ffa8b2..0000000 --- a/src/shutdownd.c +++ /dev/null @@ -1,371 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "shutdownd.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "sd-daemon.h" -#include "utmp-wtmp.h" - -static int read_packet(int fd, struct shutdownd_command *_c) { - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - struct shutdownd_command c; - ssize_t n; - - assert(fd >= 0); - assert(_c); - - zero(iovec); - iovec.iov_base = &c; - iovec.iov_len = sizeof(c); - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(fd, &msghdr, MSG_DONTWAIT)) <= 0) { - if (n >= 0) { - log_error("Short read"); - return -EIO; - } - - if (errno == EAGAIN || errno == EINTR) - return 0; - - log_error("recvmsg(): %m"); - return -errno; - } - - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - control.cmsghdr.cmsg_level != SOL_SOCKET || - control.cmsghdr.cmsg_type != SCM_CREDENTIALS || - control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received message without credentials. Ignoring."); - return 0; - } - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - if (ucred->uid != 0) { - log_warning("Got request from unprivileged user. Ignoring."); - return 0; - } - - if (n != sizeof(c)) { - log_warning("Message has invalid size. Ignoring"); - return 0; - } - - char_array_0(c.wall_message); - - *_c = c; - return 1; -} - -static void warn_wall(usec_t n, struct shutdownd_command *c) { - char date[FORMAT_TIMESTAMP_MAX]; - const char *prefix; - char *l = NULL; - - assert(c); - assert(c->warn_wall); - - if (n >= c->elapse) - return; - - if (c->mode == 'H') - prefix = "The system is going down for system halt at "; - else if (c->mode == 'P') - prefix = "The system is going down for power-off at "; - else if (c->mode == 'r') - prefix = "The system is going down for reboot at "; - else - assert_not_reached("Unknown mode!"); - - if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "", - prefix, format_timestamp(date, sizeof(date), c->elapse)) < 0) - log_error("Failed to allocate wall message"); - else { - utmp_wall(l, NULL); - free(l); - } -} - -static usec_t when_wall(usec_t n, usec_t elapse) { - - static const struct { - usec_t delay; - usec_t interval; - } table[] = { - { 10 * USEC_PER_MINUTE, USEC_PER_MINUTE }, - { USEC_PER_HOUR, 15 * USEC_PER_MINUTE }, - { 3 * USEC_PER_HOUR, 30 * USEC_PER_MINUTE } - }; - - usec_t left, sub; - unsigned i; - - /* If the time is already passed, then don't announce */ - if (n >= elapse) - return 0; - - left = elapse - n; - for (i = 0; i < ELEMENTSOF(table); i++) - if (n + table[i].delay >= elapse) { - sub = ((left / table[i].interval) * table[i].interval); - break; - } - - if (i >= ELEMENTSOF(table)) - sub = ((left / USEC_PER_HOUR) * USEC_PER_HOUR); - - return elapse > sub ? elapse - sub : 1; -} - -static usec_t when_nologin(usec_t elapse) { - return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1; -} - -int main(int argc, char *argv[]) { - enum { - FD_SOCKET, - FD_WALL_TIMER, - FD_NOLOGIN_TIMER, - FD_SHUTDOWN_TIMER, - _FD_MAX - }; - - int r = EXIT_FAILURE, n_fds; - int one = 1; - struct shutdownd_command c; - struct pollfd pollfd[_FD_MAX]; - bool exec_shutdown = false, unlink_nologin = false, failed = false; - unsigned i; - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc > 1) { - log_error("This program does not take arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((n_fds = sd_listen_fds(true)) < 0) { - log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (n_fds != 1) { - log_error("Need exactly one file descriptor."); - return EXIT_FAILURE; - } - - if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - log_error("SO_PASSCRED failed: %m"); - return EXIT_FAILURE; - } - - zero(c); - zero(pollfd); - - pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START; - pollfd[FD_SOCKET].events = POLLIN; - - for (i = 0; i < _FD_MAX; i++) { - - if (i == FD_SOCKET) - continue; - - pollfd[i].events = POLLIN; - - if ((pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) { - log_error("timerfd_create(): %m"); - failed = true; - } - } - - if (failed) - goto finish; - - log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid()); - - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - - do { - int k; - usec_t n; - - if (poll(pollfd, _FD_MAX, -1) < 0) { - - if (errno == EAGAIN || errno == EINTR) - continue; - - log_error("poll(): %m"); - goto finish; - } - - n = now(CLOCK_REALTIME); - - if (pollfd[FD_SOCKET].revents) { - - if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0) - goto finish; - else if (k > 0 && c.elapse > 0) { - struct itimerspec its; - char date[FORMAT_TIMESTAMP_MAX]; - - if (c.warn_wall) { - /* Send wall messages every so often */ - zero(its); - timespec_store(&its.it_value, when_wall(n, c.elapse)); - if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { - log_error("timerfd_settime(): %m"); - goto finish; - } - - /* Warn immediately if less than 15 minutes are left */ - if (n < c.elapse && - n + 15*USEC_PER_MINUTE >= c.elapse) - warn_wall(n, &c); - } - - /* Disallow logins 5 minutes prior to shutdown */ - zero(its); - timespec_store(&its.it_value, when_nologin(c.elapse)); - if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { - log_error("timerfd_settime(): %m"); - goto finish; - } - - /* Shutdown after the specified time is reached */ - zero(its); - timespec_store(&its.it_value, c.elapse); - if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { - log_error("timerfd_settime(): %m"); - goto finish; - } - - sd_notifyf(false, - "STATUS=Shutting down at %s...", - format_timestamp(date, sizeof(date), c.elapse)); - } - } - - if (pollfd[FD_WALL_TIMER].revents) { - struct itimerspec its; - - warn_wall(n, &c); - flush_fd(pollfd[FD_WALL_TIMER].fd); - - /* Restart timer */ - zero(its); - timespec_store(&its.it_value, when_wall(n, c.elapse)); - if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { - log_error("timerfd_settime(): %m"); - goto finish; - } - } - - if (pollfd[FD_NOLOGIN_TIMER].revents) { - int e; - - log_info("Creating /run/nologin, blocking further logins..."); - - if ((e = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0) - log_error("Failed to create /run/nologin: %s", strerror(-e)); - else - unlink_nologin = true; - - flush_fd(pollfd[FD_NOLOGIN_TIMER].fd); - } - - if (pollfd[FD_SHUTDOWN_TIMER].revents) { - exec_shutdown = true; - goto finish; - } - - } while (c.elapse > 0); - - r = EXIT_SUCCESS; - - log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid()); - -finish: - - for (i = 0; i < _FD_MAX; i++) - if (pollfd[i].fd >= 0) - close_nointr_nofail(pollfd[i].fd); - - if (unlink_nologin) - unlink("/run/nologin"); - - if (exec_shutdown && !c.dry_run) { - char sw[3]; - - sw[0] = '-'; - sw[1] = c.mode; - sw[2] = 0; - - execl(SYSTEMCTL_BINARY_PATH, - "shutdown", - sw, - "now", - (c.warn_wall && c.wall_message[0]) ? c.wall_message : - (c.warn_wall ? NULL : "--no-wall"), - NULL); - - log_error("Failed to execute /sbin/shutdown: %m"); - } - - sd_notify(false, - "STATUS=Exiting..."); - - return r; -} diff --git a/src/shutdownd.h b/src/shutdownd.h deleted file mode 100644 index 4581649..0000000 --- a/src/shutdownd.h +++ /dev/null @@ -1,46 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooshutdowndhfoo -#define fooshutdowndhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "util.h" -#include "macro.h" - -/* This is a private message, we don't care much about ABI - * stability. */ - -_packed_ struct shutdownd_command { - usec_t elapse; - char mode; /* H, P, r, i.e. the switches usually passed to - * shutdown to select whether to halt, power-off or - * reboot the machine */ - bool dry_run; - bool warn_wall; - - /* Yepp, sometimes we are lazy and use fixed-size strings like - * this one. Shame on us. But then again, we'd have to - * pre-allocate the receive buffer anyway, so there's nothing - * too bad here. */ - char wall_message[4096]; -}; - -#endif diff --git a/src/shutdownd/Makefile b/src/shutdownd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/shutdownd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c new file mode 100644 index 0000000..4a17198 --- /dev/null +++ b/src/shutdownd/shutdownd.c @@ -0,0 +1,471 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" +#include "utmp-wtmp.h" +#include "mkdir.h" +#include "fileio.h" + +union shutdown_buffer { + struct sd_shutdown_command command; + char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX]; +}; + +static int read_packet(int fd, union shutdown_buffer *_b) { + struct ucred *ucred; + ssize_t n; + + union shutdown_buffer b; /* We maintain our own copy here, in + * order not to corrupt the last message */ + struct iovec iovec = { + iovec.iov_base = &b, + iovec.iov_len = sizeof(b) - 1, + }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + msghdr.msg_iovlen = 1, + msghdr.msg_control = &control, + msghdr.msg_controllen = sizeof(control), + }; + + assert(fd >= 0); + assert(_b); + + n = recvmsg(fd, &msghdr, MSG_DONTWAIT); + if (n <= 0) { + if (n == 0) { + log_error("Short read"); + return -EIO; + } + + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_error("recvmsg(): %m"); + return -errno; + } + + if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || + control.cmsghdr.cmsg_level != SOL_SOCKET || + control.cmsghdr.cmsg_type != SCM_CREDENTIALS || + control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { + log_warning("Received message without credentials. Ignoring."); + return 0; + } + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + if (ucred->uid != 0) { + log_warning("Got request from unprivileged user. Ignoring."); + return 0; + } + + if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) { + log_warning("Message has invalid size. Ignoring."); + return 0; + } + + if (b.command.mode != SD_SHUTDOWN_NONE && + b.command.mode != SD_SHUTDOWN_REBOOT && + b.command.mode != SD_SHUTDOWN_POWEROFF && + b.command.mode != SD_SHUTDOWN_HALT && + b.command.mode != SD_SHUTDOWN_KEXEC) { + log_warning("Message has invalid mode. Ignoring."); + return 0; + } + + b.space[n] = 0; + + *_b = b; + return 1; +} + +static void warn_wall(usec_t n, struct sd_shutdown_command *c) { + char date[FORMAT_TIMESTAMP_MAX]; + const char *prefix; + char *l = NULL; + + assert(c); + assert(c->warn_wall); + + if (n >= c->usec) + return; + + if (c->mode == SD_SHUTDOWN_HALT) + prefix = "The system is going down for system halt at "; + else if (c->mode == SD_SHUTDOWN_POWEROFF) + prefix = "The system is going down for power-off at "; + else if (c->mode == SD_SHUTDOWN_REBOOT) + prefix = "The system is going down for reboot at "; + else if (c->mode == SD_SHUTDOWN_KEXEC) + prefix = "The system is going down for kexec reboot at "; + else if (c->mode == SD_SHUTDOWN_NONE) + prefix = "The system shutdown has been cancelled at "; + else + assert_not_reached("Unknown mode!"); + + if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "", + prefix, format_timestamp(date, sizeof(date), c->usec)) < 0) + log_error("Failed to allocate wall message"); + else { + utmp_wall(l, NULL); + free(l); + } +} + +_const_ static usec_t when_wall(usec_t n, usec_t elapse) { + + static const struct { + usec_t delay; + usec_t interval; + } table[] = { + { 0, USEC_PER_MINUTE }, + { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE }, + { USEC_PER_HOUR, 30 * USEC_PER_MINUTE }, + { 3 * USEC_PER_HOUR, USEC_PER_HOUR }, + }; + + usec_t left, sub; + unsigned i = ELEMENTSOF(table) - 1; + + /* If the time is already passed, then don't announce */ + if (n >= elapse) + return 0; + + left = elapse - n; + while (left < table[i].delay) + i--; + sub = (left / table[i].interval) * table[i].interval; + + assert(sub < elapse); + return elapse - sub; +} + +static usec_t when_nologin(usec_t elapse) { + return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1; +} + +static const char *mode_to_string(enum sd_shutdown_mode m) { + switch (m) { + case SD_SHUTDOWN_REBOOT: + return "reboot"; + case SD_SHUTDOWN_POWEROFF: + return "poweroff"; + case SD_SHUTDOWN_HALT: + return "halt"; + case SD_SHUTDOWN_KEXEC: + return "kexec"; + default: + return NULL; + } +} + +static int update_schedule_file(struct sd_shutdown_command *c) { + int r; + FILE *f; + char *temp_path, *t; + + assert(c); + + r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0); + if (r < 0) { + log_error("Failed to create shutdown subdirectory: %s", strerror(-r)); + return r; + } + + t = cescape(c->wall_message); + if (!t) + return log_oom(); + + r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path); + if (r < 0) { + log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r)); + free(t); + return r; + } + + fchmod(fileno(f), 0644); + + fprintf(f, + "USEC="USEC_FMT"\n" + "WARN_WALL=%i\n" + "MODE=%s\n", + c->usec, + c->warn_wall, + mode_to_string(c->mode)); + + if (c->dry_run) + fputs("DRY_RUN=1\n", f); + + if (!isempty(t)) + fprintf(f, "WALL_MESSAGE=%s\n", t); + + free(t); + + fflush(f); + + if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) { + log_error("Failed to write information about scheduled shutdowns: %m"); + r = -errno; + + unlink(temp_path); + unlink("/run/systemd/shutdown/scheduled"); + } + + fclose(f); + free(temp_path); + + return r; +} + +static bool scheduled(struct sd_shutdown_command *c) { + return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE; +} + +int main(int argc, char *argv[]) { + enum { + FD_SOCKET, + FD_WALL_TIMER, + FD_NOLOGIN_TIMER, + FD_SHUTDOWN_TIMER, + _FD_MAX + }; + + int r = EXIT_FAILURE, n_fds; + union shutdown_buffer b = {}; + struct pollfd pollfd[_FD_MAX] = {}; + bool exec_shutdown = false, unlink_nologin = false; + unsigned i; + + if (getppid() != 1) { + log_error("This program should be invoked by init only."); + return EXIT_FAILURE; + } + + if (argc > 1) { + log_error("This program does not take arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + n_fds = sd_listen_fds(true); + if (n_fds < 0) { + log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); + return EXIT_FAILURE; + } + + if (n_fds != 1) { + log_error("Need exactly one file descriptor."); + return EXIT_FAILURE; + } + + pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START; + pollfd[FD_SOCKET].events = POLLIN; + + for (i = FD_WALL_TIMER; i < _FD_MAX; i++) { + pollfd[i].events = POLLIN; + pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (pollfd[i].fd < 0) { + log_error("timerfd_create(): %m"); + goto finish; + } + } + + log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid()); + + sd_notify(false, + "READY=1\n" + "STATUS=Processing requests..."); + + for (;;) { + int k; + usec_t n; + + k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0); + if (k < 0) { + + if (errno == EAGAIN || errno == EINTR) + continue; + + log_error("poll(): %m"); + goto finish; + } + + /* Exit on idle */ + if (k == 0) + break; + + n = now(CLOCK_REALTIME); + + if (pollfd[FD_SOCKET].revents) { + + k = read_packet(pollfd[FD_SOCKET].fd, &b); + if (k < 0) + goto finish; + else if (k > 0) { + struct itimerspec its; + char date[FORMAT_TIMESTAMP_MAX]; + + if (!scheduled(&b.command)) { + log_info("Shutdown canceled."); + if (b.command.warn_wall) + warn_wall(0, &b.command); + break; + } + + zero(its); + if (b.command.warn_wall) { + /* Send wall messages every so often */ + timespec_store(&its.it_value, when_wall(n, b.command.usec)); + + /* Warn immediately if less than 15 minutes are left */ + if (n < b.command.usec && + n + 15*USEC_PER_MINUTE >= b.command.usec) + warn_wall(n, &b.command); + } + if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { + log_error("timerfd_settime(): %m"); + goto finish; + } + + /* Disallow logins 5 minutes prior to shutdown */ + zero(its); + timespec_store(&its.it_value, when_nologin(b.command.usec)); + if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { + log_error("timerfd_settime(): %m"); + goto finish; + } + + /* Shutdown after the specified time is reached */ + zero(its); + timespec_store(&its.it_value, b.command.usec); + if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { + log_error("timerfd_settime(): %m"); + goto finish; + } + + update_schedule_file(&b.command); + + sd_notifyf(false, + "STATUS=Shutting down at %s (%s)...", + format_timestamp(date, sizeof(date), b.command.usec), + mode_to_string(b.command.mode)); + + log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode)); + } + } + + if (pollfd[FD_WALL_TIMER].revents) { + struct itimerspec its = {}; + + warn_wall(n, &b.command); + flush_fd(pollfd[FD_WALL_TIMER].fd); + + /* Restart timer */ + timespec_store(&its.it_value, when_wall(n, b.command.usec)); + if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) { + log_error("timerfd_settime(): %m"); + goto finish; + } + } + + if (pollfd[FD_NOLOGIN_TIMER].revents) { + int e; + + log_info("Creating /run/nologin, blocking further logins..."); + + e = write_string_file_atomic("/run/nologin", "System is going down."); + if (e < 0) + log_error("Failed to create /run/nologin: %s", strerror(-e)); + else + unlink_nologin = true; + + flush_fd(pollfd[FD_NOLOGIN_TIMER].fd); + } + + if (pollfd[FD_SHUTDOWN_TIMER].revents) { + exec_shutdown = true; + goto finish; + } + } + + r = EXIT_SUCCESS; + + log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid()); + +finish: + + for (i = 0; i < _FD_MAX; i++) + if (pollfd[i].fd >= 0) + close_nointr_nofail(pollfd[i].fd); + + if (unlink_nologin) + unlink("/run/nologin"); + + unlink("/run/systemd/shutdown/scheduled"); + + if (exec_shutdown && !b.command.dry_run) { + char sw[3]; + + sw[0] = '-'; + sw[1] = b.command.mode; + sw[2] = 0; + + execl(SYSTEMCTL_BINARY_PATH, + "shutdown", + sw, + "now", + (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message : + (b.command.warn_wall ? NULL : "--no-wall"), + NULL); + + log_error("Failed to execute /sbin/shutdown: %m"); + } + + sd_notify(false, + "STATUS=Exiting..."); + + return r; +} diff --git a/src/sleep/Makefile b/src/sleep/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/sleep/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c new file mode 100644 index 0000000..8da050c --- /dev/null +++ b/src/sleep/sleep.c @@ -0,0 +1,219 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "systemd/sd-id128.h" +#include "systemd/sd-messages.h" +#include "log.h" +#include "util.h" +#include "strv.h" +#include "fileio.h" +#include "build.h" +#include "sleep-config.h" + +static char* arg_verb = NULL; + +static int write_mode(char **modes) { + int r = 0; + char **mode; + + STRV_FOREACH(mode, modes) { + int k = write_string_file("/sys/power/disk", *mode); + if (k == 0) + return 0; + log_debug("Failed to write '%s' to /sys/power/disk: %s", + *mode, strerror(-k)); + if (r == 0) + r = k; + } + + if (r < 0) + log_error("Failed to write mode to /sys/power/disk: %s", + strerror(-r)); + + return r; +} + +static int write_state(FILE **f, char **states) { + char **state; + int r = 0; + + STRV_FOREACH(state, states) { + int k; + + k = write_string_to_file(*f, *state); + if (k == 0) + return 0; + log_debug("Failed to write '%s' to /sys/power/state: %s", + *state, strerror(-k)); + if (r == 0) + r = k; + + fclose(*f); + *f = fopen("/sys/power/state", "we"); + if (!*f) { + log_error("Failed to open /sys/power/state: %m"); + return -errno; + } + } + + return r; +} + +static int execute(char **modes, char **states) { + char* arguments[4]; + int r; + _cleanup_fclose_ FILE *f = NULL; + const char* note = strappenda("SLEEP=", arg_verb); + + /* This file is opened first, so that if we hit an error, + * we can abort before modifying any state. */ + f = fopen("/sys/power/state", "we"); + if (!f) { + log_error("Failed to open /sys/power/state: %m"); + return -errno; + } + + /* Configure the hibernation mode */ + r = write_mode(modes); + if (r < 0) + return r; + + arguments[0] = NULL; + arguments[1] = (char*) "pre"; + arguments[2] = arg_verb; + arguments[3] = NULL; + execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments); + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SLEEP_START), + "MESSAGE=Suspending system...", + note, + NULL); + + r = write_state(&f, states); + if (r < 0) + return r; + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_SLEEP_STOP), + "MESSAGE=System resumed.", + note, + NULL); + + arguments[1] = (char*) "post"; + execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments); + + return r; +} + +static int help(void) { + printf("%s COMMAND\n\n" + "Suspend the system, hibernate the system, or both.\n\n" + "Commands:\n" + " -h --help Show this help and exit\n" + " --version Print version string and exit\n" + " suspend Suspend the system\n" + " hibernate Hibernate the system\n" + " hybrid-sleep Both hibernate and suspend the system\n" + , program_invocation_short_name + ); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) + switch(c) { + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0 /* done */; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (argc - optind != 1) { + log_error("Usage: %s COMMAND", + program_invocation_short_name); + return -EINVAL; + } + + arg_verb = argv[optind]; + + if (!streq(arg_verb, "suspend") && + !streq(arg_verb, "hibernate") && + !streq(arg_verb, "hybrid-sleep")) { + log_error("Unknown command '%s'.", arg_verb); + return -EINVAL; + } + + return 1 /* work to do */; +} + +int main(int argc, char *argv[]) { + _cleanup_strv_free_ char **modes = NULL, **states = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = parse_sleep_config(arg_verb, &modes, &states); + if (r < 0) + goto finish; + + r = execute(modes, states); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/snapshot.c b/src/snapshot.c deleted file mode 100644 index 270dc4f..0000000 --- a/src/snapshot.c +++ /dev/null @@ -1,308 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" -#include "snapshot.h" -#include "unit-name.h" -#include "dbus-snapshot.h" -#include "bus-errors.h" - -static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = UNIT_INACTIVE, - [SNAPSHOT_ACTIVE] = UNIT_ACTIVE -}; - -static void snapshot_init(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->meta.load_state == UNIT_STUB); - - s->meta.ignore_on_isolate = true; - s->meta.ignore_on_snapshot = true; -} - -static void snapshot_set_state(Snapshot *s, SnapshotState state) { - SnapshotState old_state; - assert(s); - - old_state = s->state; - s->state = state; - - if (state != old_state) - log_debug("%s changed %s -> %s", - s->meta.id, - snapshot_state_to_string(old_state), - snapshot_state_to_string(state)); - - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); -} - -static int snapshot_load(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - /* Make sure that only snapshots created via snapshot_create() - * can be loaded */ - if (!s->by_snapshot_create && s->meta.manager->n_reloading <= 0) - return -ENOENT; - - u->meta.load_state = UNIT_LOADED; - return 0; -} - -static int snapshot_coldplug(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_DEAD); - - if (s->deserialized_state != s->state) - snapshot_set_state(s, s->deserialized_state); - - return 0; -} - -static void snapshot_dump(Unit *u, FILE *f, const char *prefix) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(f); - - fprintf(f, - "%sSnapshot State: %s\n" - "%sClean Up: %s\n", - prefix, snapshot_state_to_string(s->state), - prefix, yes_no(s->cleanup)); -} - -static int snapshot_start(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_DEAD); - - snapshot_set_state(s, SNAPSHOT_ACTIVE); - - if (s->cleanup) - unit_add_to_cleanup_queue(u); - - return 0; -} - -static int snapshot_stop(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_ACTIVE); - - snapshot_set_state(s, SNAPSHOT_DEAD); - return 0; -} - -static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) { - Snapshot *s = SNAPSHOT(u); - Unit *other; - Iterator i; - - assert(s); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state)); - unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup)); - SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i) - unit_serialize_item(u, f, "wants", other->meta.id); - - return 0; -} - -static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Snapshot *s = SNAPSHOT(u); - int r; - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - SnapshotState state; - - if ((state = snapshot_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - s->deserialized_state = state; - - } else if (streq(key, "cleanup")) { - - if ((r = parse_boolean(value)) < 0) - log_debug("Failed to parse cleanup value %s", value); - else - s->cleanup = r; - - } else if (streq(key, "wants")) { - - if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0) - return r; - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState snapshot_active_state(Unit *u) { - assert(u); - - return state_translation_table[SNAPSHOT(u)->state]; -} - -static const char *snapshot_sub_state_to_string(Unit *u) { - assert(u); - - return snapshot_state_to_string(SNAPSHOT(u)->state); -} - -int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) { - Iterator i; - Unit *other, *u = NULL; - char *n = NULL; - int r; - const char *k; - - assert(m); - assert(_s); - - if (name) { - if (!unit_name_is_valid(name, false)) { - dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name); - return -EINVAL; - } - - if (unit_name_to_type(name) != UNIT_SNAPSHOT) { - dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name); - return -EINVAL; - } - - if (manager_get_unit(m, name)) { - dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); - return -EEXIST; - } - - } else { - - for (;;) { - if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0) - return -ENOMEM; - - if (!manager_get_unit(m, n)) - break; - - free(n); - } - - name = n; - } - - r = manager_load_unit_prepare(m, name, NULL, e, &u); - free(n); - - if (r < 0) - goto fail; - - SNAPSHOT(u)->by_snapshot_create = true; - manager_dispatch_load_queue(m); - assert(u->meta.load_state == UNIT_LOADED); - - HASHMAP_FOREACH_KEY(other, k, m->units, i) { - - if (other->meta.ignore_on_snapshot) - continue; - - if (k != other->meta.id) - continue; - - if (UNIT_VTABLE(other)->check_snapshot) - if (!UNIT_VTABLE(other)->check_snapshot(other)) - continue; - - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - continue; - - if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0) - goto fail; - } - - SNAPSHOT(u)->cleanup = cleanup; - *_s = SNAPSHOT(u); - - return 0; - -fail: - if (u) - unit_add_to_cleanup_queue(u); - - return r; -} - -void snapshot_remove(Snapshot *s) { - assert(s); - - unit_add_to_cleanup_queue(UNIT(s)); -} - -static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = "dead", - [SNAPSHOT_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); - -const UnitVTable snapshot_vtable = { - .suffix = ".snapshot", - - .no_alias = true, - .no_instances = true, - .no_gc = true, - - .init = snapshot_init, - - .load = snapshot_load, - .coldplug = snapshot_coldplug, - - .dump = snapshot_dump, - - .start = snapshot_start, - .stop = snapshot_stop, - - .serialize = snapshot_serialize, - .deserialize_item = snapshot_deserialize_item, - - .active_state = snapshot_active_state, - .sub_state_to_string = snapshot_sub_state_to_string, - - .bus_interface = "org.freedesktop.systemd1.Snapshot", - .bus_message_handler = bus_snapshot_message_handler -}; diff --git a/src/snapshot.h b/src/snapshot.h deleted file mode 100644 index 9a30520..0000000 --- a/src/snapshot.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosnapshothfoo -#define foosnapshothfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Snapshot Snapshot; - -#include "unit.h" - -typedef enum SnapshotState { - SNAPSHOT_DEAD, - SNAPSHOT_ACTIVE, - _SNAPSHOT_STATE_MAX, - _SNAPSHOT_STATE_INVALID = -1 -} SnapshotState; - -struct Snapshot { - Meta meta; - - SnapshotState state, deserialized_state; - - bool cleanup; - bool by_snapshot_create:1; -}; - -extern const UnitVTable snapshot_vtable; - -int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **s); -void snapshot_remove(Snapshot *s); - -const char* snapshot_state_to_string(SnapshotState i); -SnapshotState snapshot_state_from_string(const char *s); - -#endif diff --git a/src/socket-proxy/Makefile b/src/socket-proxy/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/socket-proxy/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c new file mode 100644 index 0000000..a42e5ae --- /dev/null +++ b/src/socket-proxy/socket-proxyd.c @@ -0,0 +1,665 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 David Strauss + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" +#include "sd-event.h" +#include "log.h" +#include "socket-util.h" +#include "util.h" +#include "event-util.h" +#include "build.h" +#include "set.h" +#include "path-util.h" + +#define BUFFER_SIZE (256 * 1024) +#define CONNECTIONS_MAX 256 + +#define _cleanup_freeaddrinfo_ _cleanup_(freeaddrinfop) +DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo *, freeaddrinfo); + +typedef struct Context { + Set *listen; + Set *connections; +} Context; + +typedef struct Connection { + Context *context; + + int server_fd, client_fd; + int server_to_client_buffer[2]; /* a pipe */ + int client_to_server_buffer[2]; /* a pipe */ + + size_t server_to_client_buffer_full, client_to_server_buffer_full; + size_t server_to_client_buffer_size, client_to_server_buffer_size; + + sd_event_source *server_event_source, *client_event_source; +} Connection; + +static const char *arg_remote_host = NULL; + +static void connection_free(Connection *c) { + assert(c); + + if (c->context) + set_remove(c->context->connections, c); + + sd_event_source_unref(c->server_event_source); + sd_event_source_unref(c->client_event_source); + + if (c->server_fd >= 0) + close_nointr_nofail(c->server_fd); + if (c->client_fd >= 0) + close_nointr_nofail(c->client_fd); + + close_pipe(c->server_to_client_buffer); + close_pipe(c->client_to_server_buffer); + + free(c); +} + +static void context_free(Context *context) { + sd_event_source *es; + Connection *c; + + assert(context); + + while ((es = set_steal_first(context->listen))) + sd_event_source_unref(es); + + while ((c = set_first(context->connections))) + connection_free(c); + + set_free(context->listen); + set_free(context->connections); +} + +static int get_remote_sockaddr(union sockaddr_union *sa, socklen_t *salen) { + int r; + + assert(sa); + assert(salen); + + if (path_is_absolute(arg_remote_host)) { + sa->un.sun_family = AF_UNIX; + strncpy(sa->un.sun_path, arg_remote_host, sizeof(sa->un.sun_path)-1); + sa->un.sun_path[sizeof(sa->un.sun_path)-1] = 0; + + *salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa->un.sun_path); + + } else if (arg_remote_host[0] == '@') { + sa->un.sun_family = AF_UNIX; + sa->un.sun_path[0] = 0; + strncpy(sa->un.sun_path+1, arg_remote_host+1, sizeof(sa->un.sun_path)-2); + sa->un.sun_path[sizeof(sa->un.sun_path)-1] = 0; + + *salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa->un.sun_path + 1); + + } else { + _cleanup_freeaddrinfo_ struct addrinfo *result = NULL; + const char *node, *service; + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_ADDRCONFIG + }; + + service = strrchr(arg_remote_host, ':'); + if (service) { + node = strndupa(arg_remote_host, service - arg_remote_host); + service ++; + } else { + node = arg_remote_host; + service = "80"; + } + + log_debug("Looking up address info for %s:%s", node, service); + r = getaddrinfo(node, service, &hints, &result); + if (r != 0) { + log_error("Failed to resolve host %s:%s: %s", node, service, gai_strerror(r)); + return -EHOSTUNREACH; + } + + assert(result); + if (result->ai_addrlen > sizeof(union sockaddr_union)) { + log_error("Address too long."); + return -E2BIG; + } + + memcpy(sa, result->ai_addr, result->ai_addrlen); + *salen = result->ai_addrlen; + } + + return 0; +} + +static int connection_create_pipes(Connection *c, int buffer[2], size_t *sz) { + int r; + + assert(c); + assert(buffer); + assert(sz); + + if (buffer[0] >= 0) + return 0; + + r = pipe2(buffer, O_CLOEXEC|O_NONBLOCK); + if (r < 0) { + log_error("Failed to allocate pipe buffer: %m"); + return -errno; + } + + fcntl(buffer[0], F_SETPIPE_SZ, BUFFER_SIZE); + + r = fcntl(buffer[0], F_GETPIPE_SZ); + if (r < 0) { + log_error("Failed to get pipe buffer size: %m"); + return -errno; + } + + assert(r > 0); + *sz = r; + + return 0; +} + +static int connection_shovel( + Connection *c, + int *from, int buffer[2], int *to, + size_t *full, size_t *sz, + sd_event_source **from_source, sd_event_source **to_source) { + + bool shoveled; + + assert(c); + assert(from); + assert(buffer); + assert(buffer[0] >= 0); + assert(buffer[1] >= 0); + assert(to); + assert(full); + assert(sz); + assert(from_source); + assert(to_source); + + do { + ssize_t z; + + shoveled = false; + + if (*full < *sz && *from >= 0 && *to >= 0) { + z = splice(*from, NULL, buffer[1], NULL, *sz - *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK); + if (z > 0) { + *full += z; + shoveled = true; + } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) { + *from_source = sd_event_source_unref(*from_source); + close_nointr_nofail(*from); + *from = -1; + } else if (errno != EAGAIN && errno != EINTR) { + log_error("Failed to splice: %m"); + return -errno; + } + } + + if (*full > 0 && *to >= 0) { + z = splice(buffer[0], NULL, *to, NULL, *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK); + if (z > 0) { + *full -= z; + shoveled = true; + } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) { + *to_source = sd_event_source_unref(*to_source); + close_nointr_nofail(*to); + *to = -1; + } else if (errno != EAGAIN && errno != EINTR) { + log_error("Failed to splice: %m"); + return -errno; + } + } + } while (shoveled); + + return 0; +} + +static int connection_enable_event_sources(Connection *c, sd_event *event); + +static int traffic_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Connection *c = userdata; + int r; + + assert(s); + assert(fd >= 0); + assert(c); + + r = connection_shovel(c, + &c->server_fd, c->server_to_client_buffer, &c->client_fd, + &c->server_to_client_buffer_full, &c->server_to_client_buffer_size, + &c->server_event_source, &c->client_event_source); + if (r < 0) + goto quit; + + r = connection_shovel(c, + &c->client_fd, c->client_to_server_buffer, &c->server_fd, + &c->client_to_server_buffer_full, &c->client_to_server_buffer_size, + &c->client_event_source, &c->server_event_source); + if (r < 0) + goto quit; + + /* EOF on both sides? */ + if (c->server_fd == -1 && c->client_fd == -1) + goto quit; + + /* Server closed, and all data written to client? */ + if (c->server_fd == -1 && c->server_to_client_buffer_full <= 0) + goto quit; + + /* Client closed, and all data written to server? */ + if (c->client_fd == -1 && c->client_to_server_buffer_full <= 0) + goto quit; + + r = connection_enable_event_sources(c, sd_event_source_get_event(s)); + if (r < 0) + goto quit; + + return 1; + +quit: + connection_free(c); + return 0; /* ignore errors, continue serving */ +} + +static int connection_enable_event_sources(Connection *c, sd_event *event) { + uint32_t a = 0, b = 0; + int r; + + assert(c); + assert(event); + + if (c->server_to_client_buffer_full > 0) + b |= EPOLLOUT; + if (c->server_to_client_buffer_full < c->server_to_client_buffer_size) + a |= EPOLLIN; + + if (c->client_to_server_buffer_full > 0) + a |= EPOLLOUT; + if (c->client_to_server_buffer_full < c->client_to_server_buffer_size) + b |= EPOLLIN; + + if (c->server_event_source) + r = sd_event_source_set_io_events(c->server_event_source, a); + else if (c->server_fd >= 0) + r = sd_event_add_io(event, &c->server_event_source, c->server_fd, a, traffic_cb, c); + else + r = 0; + + if (r < 0) { + log_error("Failed to set up server event source: %s", strerror(-r)); + return r; + } + + if (c->client_event_source) + r = sd_event_source_set_io_events(c->client_event_source, b); + else if (c->client_fd >= 0) + r = sd_event_add_io(event, &c->client_event_source, c->client_fd, b, traffic_cb, c); + else + r = 0; + + if (r < 0) { + log_error("Failed to set up client event source: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + Connection *c = userdata; + socklen_t solen; + int error, r; + + assert(s); + assert(fd >= 0); + assert(c); + + solen = sizeof(error); + r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &solen); + if (r < 0) { + log_error("Failed to issue SO_ERROR: %m"); + goto fail; + } + + if (error != 0) { + log_error("Failed to connect to remote host: %s", strerror(error)); + goto fail; + } + + c->client_event_source = sd_event_source_unref(c->client_event_source); + + r = connection_create_pipes(c, c->server_to_client_buffer, &c->server_to_client_buffer_size); + if (r < 0) + goto fail; + + r = connection_create_pipes(c, c->client_to_server_buffer, &c->client_to_server_buffer_size); + if (r < 0) + goto fail; + + r = connection_enable_event_sources(c, sd_event_source_get_event(s)); + if (r < 0) + goto fail; + + return 0; + +fail: + connection_free(c); + return 0; /* ignore errors, continue serving */ +} + +static int add_connection_socket(Context *context, sd_event *event, int fd) { + union sockaddr_union sa = {}; + socklen_t salen; + Connection *c; + int r; + + assert(context); + assert(event); + assert(fd >= 0); + + if (set_size(context->connections) > CONNECTIONS_MAX) { + log_warning("Hit connection limit, refusing connection."); + close_nointr_nofail(fd); + return 0; + } + + r = set_ensure_allocated(&context->connections, trivial_hash_func, trivial_compare_func); + if (r < 0) + return log_oom(); + + c = new0(Connection, 1); + if (!c) + return log_oom(); + + c->context = context; + c->server_fd = fd; + c->client_fd = -1; + c->server_to_client_buffer[0] = c->server_to_client_buffer[1] = -1; + c->client_to_server_buffer[0] = c->client_to_server_buffer[1] = -1; + + r = set_put(context->connections, c); + if (r < 0) { + free(c); + return log_oom(); + } + + r = get_remote_sockaddr(&sa, &salen); + if (r < 0) + goto fail; + + c->client_fd = socket(sa.sa.sa_family, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + if (c->client_fd < 0) { + log_error("Failed to get remote socket: %m"); + goto fail; + } + + r = connect(c->client_fd, &sa.sa, salen); + if (r < 0) { + if (errno == EINPROGRESS) { + r = sd_event_add_io(event, &c->client_event_source, c->client_fd, EPOLLOUT, connect_cb, c); + if (r < 0) { + log_error("Failed to add connection socket: %s", strerror(-r)); + goto fail; + } + + r = sd_event_source_set_enabled(c->client_event_source, SD_EVENT_ONESHOT); + if (r < 0) { + log_error("Failed to enable oneshot event source: %s", strerror(-r)); + goto fail; + } + } else { + log_error("Failed to connect to remote host: %m"); + goto fail; + } + } else { + r = connection_enable_event_sources(c, event); + if (r < 0) + goto fail; + } + + return 0; + +fail: + connection_free(c); + return 0; /* ignore non-OOM errors, continue serving */ +} + +static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_free_ char *peer = NULL; + Context *context = userdata; + int nfd = -1, r; + + assert(s); + assert(fd >= 0); + assert(revents & EPOLLIN); + assert(context); + + nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (nfd < 0) { + if (errno != -EAGAIN) + log_warning("Failed to accept() socket: %m"); + } else { + getpeername_pretty(nfd, &peer); + log_debug("New connection from %s", strna(peer)); + + r = add_connection_socket(context, sd_event_source_get_event(s), nfd); + if (r < 0) { + log_error("Failed to accept connection, ignoring: %s", strerror(-r)); + close_nointr_nofail(fd); + } + } + + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); + if (r < 0) { + log_error("Error while re-enabling listener with ONESHOT: %s", strerror(-r)); + sd_event_exit(sd_event_source_get_event(s), r); + return r; + } + + return 1; +} + +static int add_listen_socket(Context *context, sd_event *event, int fd) { + sd_event_source *source; + int r; + + assert(context); + assert(event); + assert(fd >= 0); + + r = set_ensure_allocated(&context->listen, trivial_hash_func, trivial_compare_func); + if (r < 0) { + log_oom(); + return r; + } + + r = sd_is_socket(fd, 0, SOCK_STREAM, 1); + if (r < 0) { + log_error("Failed to determine socket type: %s", strerror(-r)); + return r; + } + if (r == 0) { + log_error("Passed in socket is not a stream socket."); + return -EINVAL; + } + + r = fd_nonblock(fd, true); + if (r < 0) { + log_error("Failed to mark file descriptor non-blocking: %s", strerror(-r)); + return r; + } + + r = sd_event_add_io(event, &source, fd, EPOLLIN, accept_cb, context); + if (r < 0) { + log_error("Failed to add event source: %s", strerror(-r)); + return r; + } + + r = set_put(context->listen, source); + if (r < 0) { + log_error("Failed to add source to set: %s", strerror(-r)); + sd_event_source_unref(source); + return r; + } + + /* Set the watcher to oneshot in case other processes are also + * watching to accept(). */ + r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); + if (r < 0) { + log_error("Failed to enable oneshot mode: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int help(void) { + + printf("%s [HOST:PORT]\n" + "%s [SOCKET]\n\n" + "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n" + " -h --help Show this help\n" + " --version Show package version\n", + program_invocation_short_name, + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_IGNORE_ENV + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind >= argc) { + log_error("Not enough parameters."); + return -EINVAL; + } + + if (argc != optind+1) { + log_error("Too many parameters."); + return -EINVAL; + } + + arg_remote_host = argv[optind]; + return 1; +} + +int main(int argc, char *argv[]) { + _cleanup_event_unref_ sd_event *event = NULL; + Context context = {}; + int r, n, fd; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = sd_event_default(&event); + if (r < 0) { + log_error("Failed to allocate event loop: %s", strerror(-r)); + goto finish; + } + + sd_event_set_watchdog(event, true); + + n = sd_listen_fds(1); + if (n < 0) { + log_error("Failed to receive sockets from parent."); + r = n; + goto finish; + } else if (n == 0) { + log_error("Didn't get any sockets passed in."); + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + r = add_listen_socket(&context, event, fd); + if (r < 0) + goto finish; + } + + r = sd_event_loop(event); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + goto finish; + } + +finish: + context_free(&context); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/socket-util.c b/src/socket-util.c deleted file mode 100644 index acc4d33..0000000 --- a/src/socket-util.c +++ /dev/null @@ -1,652 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" -#include "socket-util.h" -#include "missing.h" -#include "label.h" - -int socket_address_parse(SocketAddress *a, const char *s) { - int r; - char *e, *n; - unsigned u; - - assert(a); - assert(s); - - zero(*a); - a->type = SOCK_STREAM; - - if (*s == '[') { - /* IPv6 in [x:.....:z]:p notation */ - - if (!socket_ipv6_is_supported()) { - log_warning("Binding to IPv6 address not available since kernel does not support IPv6."); - return -EAFNOSUPPORT; - } - - if (!(e = strchr(s+1, ']'))) - return -EINVAL; - - if (!(n = strndup(s+1, e-s-1))) - return -ENOMEM; - - errno = 0; - if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) { - free(n); - return errno != 0 ? -errno : -EINVAL; - } - - free(n); - - e++; - if (*e != ':') - return -EINVAL; - - e++; - if ((r = safe_atou(e, &u)) < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->size = sizeof(struct sockaddr_in6); - - } else if (*s == '/') { - /* AF_UNIX socket */ - - size_t l; - - l = strlen(s); - if (l >= sizeof(a->sockaddr.un.sun_path)) - return -EINVAL; - - a->sockaddr.un.sun_family = AF_UNIX; - memcpy(a->sockaddr.un.sun_path, s, l); - a->size = offsetof(struct sockaddr_un, sun_path) + l + 1; - - } else if (*s == '@') { - /* Abstract AF_UNIX socket */ - size_t l; - - l = strlen(s+1); - if (l >= sizeof(a->sockaddr.un.sun_path) - 1) - return -EINVAL; - - a->sockaddr.un.sun_family = AF_UNIX; - memcpy(a->sockaddr.un.sun_path+1, s+1, l); - a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l; - - } else { - - if ((e = strchr(s, ':'))) { - - if ((r = safe_atou(e+1, &u)) < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - if (!(n = strndup(s, e-s))) - return -ENOMEM; - - /* IPv4 in w.x.y.z:p notation? */ - if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) { - free(n); - return -errno; - } - - if (r > 0) { - /* Gotcha, it's a traditional IPv4 address */ - free(n); - - a->sockaddr.in4.sin_family = AF_INET; - a->sockaddr.in4.sin_port = htons((uint16_t) u); - a->size = sizeof(struct sockaddr_in); - } else { - unsigned idx; - - if (strlen(n) > IF_NAMESIZE-1) { - free(n); - return -EINVAL; - } - - /* Uh, our last resort, an interface name */ - idx = if_nametoindex(n); - free(n); - - if (idx == 0) - return -EINVAL; - - if (!socket_ipv6_is_supported()) { - log_warning("Binding to interface is not available since kernel does not support IPv6."); - return -EAFNOSUPPORT; - } - - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->sockaddr.in6.sin6_scope_id = idx; - a->sockaddr.in6.sin6_addr = in6addr_any; - a->size = sizeof(struct sockaddr_in6); - } - } else { - - /* Just a port */ - if ((r = safe_atou(s, &u)) < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - if (socket_ipv6_is_supported()) { - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->sockaddr.in6.sin6_addr = in6addr_any; - a->size = sizeof(struct sockaddr_in6); - } else { - a->sockaddr.in4.sin_family = AF_INET; - a->sockaddr.in4.sin_port = htons((uint16_t) u); - a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY; - a->size = sizeof(struct sockaddr_in); - } - } - } - - return 0; -} - -int socket_address_parse_netlink(SocketAddress *a, const char *s) { - int family; - unsigned group = 0; - char* sfamily = NULL; - assert(a); - assert(s); - - zero(*a); - a->type = SOCK_RAW; - - errno = 0; - if (sscanf(s, "%ms %u", &sfamily, &group) < 1) - return errno ? -errno : -EINVAL; - - if ((family = netlink_family_from_string(sfamily)) < 0) - if (safe_atoi(sfamily, &family) < 0) { - free(sfamily); - return -EINVAL; - } - - free(sfamily); - - a->sockaddr.nl.nl_family = AF_NETLINK; - a->sockaddr.nl.nl_groups = group; - - a->type = SOCK_RAW; - a->size = sizeof(struct sockaddr_nl); - a->protocol = family; - - return 0; -} - -int socket_address_verify(const SocketAddress *a) { - assert(a); - - switch (socket_address_family(a)) { - - case AF_INET: - if (a->size != sizeof(struct sockaddr_in)) - return -EINVAL; - - if (a->sockaddr.in4.sin_port == 0) - return -EINVAL; - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - case AF_INET6: - if (a->size != sizeof(struct sockaddr_in6)) - return -EINVAL; - - if (a->sockaddr.in6.sin6_port == 0) - return -EINVAL; - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - case AF_UNIX: - if (a->size < offsetof(struct sockaddr_un, sun_path)) - return -EINVAL; - - if (a->size > offsetof(struct sockaddr_un, sun_path)) { - - if (a->sockaddr.un.sun_path[0] != 0) { - char *e; - - /* path */ - if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path)))) - return -EINVAL; - - if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) - return -EINVAL; - } - } - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET) - return -EINVAL; - - return 0; - - case AF_NETLINK: - - if (a->size != sizeof(struct sockaddr_nl)) - return -EINVAL; - - if (a->type != SOCK_RAW && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - default: - return -EAFNOSUPPORT; - } -} - -int socket_address_print(const SocketAddress *a, char **p) { - int r; - assert(a); - assert(p); - - if ((r = socket_address_verify(a)) < 0) - return r; - - switch (socket_address_family(a)) { - - case AF_INET: { - char *ret; - - if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1))) - return -ENOMEM; - - if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) { - free(ret); - return -errno; - } - - sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port)); - *p = ret; - return 0; - } - - case AF_INET6: { - char *ret; - - if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1))) - return -ENOMEM; - - ret[0] = '['; - if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) { - free(ret); - return -errno; - } - - sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port)); - *p = ret; - return 0; - } - - case AF_UNIX: { - char *ret; - - if (a->size <= offsetof(struct sockaddr_un, sun_path)) { - - if (!(ret = strdup(""))) - return -ENOMEM; - - } else if (a->sockaddr.un.sun_path[0] == 0) { - /* abstract */ - - /* FIXME: We assume we can print the - * socket path here and that it hasn't - * more than one NUL byte. That is - * actually an invalid assumption */ - - if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) - return -ENOMEM; - - ret[0] = '@'; - memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); - ret[sizeof(a->sockaddr.un.sun_path)] = 0; - - } else { - - if (!(ret = strdup(a->sockaddr.un.sun_path))) - return -ENOMEM; - } - - *p = ret; - return 0; - } - - case AF_NETLINK: { - const char *sfamily; - - if ((sfamily = netlink_family_to_string(a->protocol))) - r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups); - else - r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups); - - if (r < 0) - return -ENOMEM; - - return 0; - } - - default: - return -EINVAL; - } -} - -int socket_address_listen( - const SocketAddress *a, - int backlog, - SocketAddressBindIPv6Only only, - const char *bind_to_device, - bool free_bind, - bool transparent, - mode_t directory_mode, - mode_t socket_mode, - const char *label, - int *ret) { - - int r, fd, one; - assert(a); - assert(ret); - - if ((r = socket_address_verify(a)) < 0) - return r; - - if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported()) - return -EAFNOSUPPORT; - - r = label_socket_set(label); - if (r < 0) - return r; - - fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol); - r = fd < 0 ? -errno : 0; - - label_socket_clear(); - - if (r < 0) - return r; - - if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { - int flag = only == SOCKET_ADDRESS_IPV6_ONLY; - - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) - goto fail; - } - - if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) { - if (bind_to_device) - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) - goto fail; - - if (free_bind) { - one = 1; - if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) - log_warning("IP_FREEBIND failed: %m"); - } - - if (transparent) { - one = 1; - if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) - log_warning("IP_TRANSPARENT failed: %m"); - } - } - - one = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) - goto fail; - - if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { - mode_t old_mask; - - /* Create parents */ - mkdir_parents(a->sockaddr.un.sun_path, directory_mode); - - /* Enforce the right access mode for the socket*/ - old_mask = umask(~ socket_mode); - - /* Include the original umask in our mask */ - umask(~socket_mode | old_mask); - - r = label_bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0 && errno == EADDRINUSE) { - /* Unlink and try again */ - unlink(a->sockaddr.un.sun_path); - r = bind(fd, &a->sockaddr.sa, a->size); - } - - umask(old_mask); - } else - r = bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0) - goto fail; - - if (socket_address_can_accept(a)) - if (listen(fd, backlog) < 0) - goto fail; - - *ret = fd; - return 0; - -fail: - r = -errno; - close_nointr_nofail(fd); - return r; -} - -bool socket_address_can_accept(const SocketAddress *a) { - assert(a); - - return - a->type == SOCK_STREAM || - a->type == SOCK_SEQPACKET; -} - -bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { - assert(a); - assert(b); - - /* Invalid addresses are unequal to all */ - if (socket_address_verify(a) < 0 || - socket_address_verify(b) < 0) - return false; - - if (a->type != b->type) - return false; - - if (a->size != b->size) - return false; - - if (socket_address_family(a) != socket_address_family(b)) - return false; - - switch (socket_address_family(a)) { - - case AF_INET: - if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr) - return false; - - if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port) - return false; - - break; - - case AF_INET6: - if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0) - return false; - - if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port) - return false; - - break; - - case AF_UNIX: - - if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) - return false; - - if (a->sockaddr.un.sun_path[0]) { - if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0) - return false; - } else { - if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0) - return false; - } - - break; - - case AF_NETLINK: - - if (a->protocol != b->protocol) - return false; - - if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups) - return false; - - break; - - default: - /* Cannot compare, so we assume the addresses are different */ - return false; - } - - return true; -} - -bool socket_address_is(const SocketAddress *a, const char *s, int type) { - struct SocketAddress b; - - assert(a); - assert(s); - - if (socket_address_parse(&b, s) < 0) - return false; - - b.type = type; - - return socket_address_equal(a, &b); -} - -bool socket_address_is_netlink(const SocketAddress *a, const char *s) { - struct SocketAddress b; - - assert(a); - assert(s); - - if (socket_address_parse_netlink(&b, s) < 0) - return false; - - return socket_address_equal(a, &b); -} - -bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) { - assert(a); - - if (socket_address_family(a) != AF_UNIX) - return false; - - if (a->sockaddr.un.sun_path[0] == 0) - return false; - - return path_startswith(a->sockaddr.un.sun_path, prefix); -} - -bool socket_ipv6_is_supported(void) { - char *l = 0; - bool enabled; - - if (access("/sys/module/ipv6", F_OK) != 0) - return 0; - - /* If we can't check "disable" parameter, assume enabled */ - if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0) - return 1; - - /* If module was loaded with disable=1 no IPv6 available */ - enabled = l[0] == '0'; - free(l); - - return enabled; -} - -static const char* const netlink_family_table[] = { - [NETLINK_ROUTE] = "route", - [NETLINK_FIREWALL] = "firewall", - [NETLINK_INET_DIAG] = "inet-diag", - [NETLINK_NFLOG] = "nflog", - [NETLINK_XFRM] = "xfrm", - [NETLINK_SELINUX] = "selinux", - [NETLINK_ISCSI] = "iscsi", - [NETLINK_AUDIT] = "audit", - [NETLINK_FIB_LOOKUP] = "fib-lookup", - [NETLINK_CONNECTOR] = "connector", - [NETLINK_NETFILTER] = "netfilter", - [NETLINK_IP6_FW] = "ip6-fw", - [NETLINK_DNRTMSG] = "dnrtmsg", - [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", - [NETLINK_GENERIC] = "generic", - [NETLINK_SCSITRANSPORT] = "scsitransport", - [NETLINK_ECRYPTFS] = "ecryptfs" -}; - -DEFINE_STRING_TABLE_LOOKUP(netlink_family, int); - -static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = { - [SOCKET_ADDRESS_DEFAULT] = "default", - [SOCKET_ADDRESS_BOTH] = "both", - [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only" -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); diff --git a/src/socket-util.h b/src/socket-util.h deleted file mode 100644 index 8ccbd37..0000000 --- a/src/socket-util.h +++ /dev/null @@ -1,102 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosocketutilhfoo -#define foosocketutilhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_nl nl; - struct sockaddr_storage storage; -}; - -typedef struct SocketAddress { - union sockaddr_union sockaddr; - - /* We store the size here explicitly due to the weird - * sockaddr_un semantics for abstract sockets */ - socklen_t size; - - /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ - int type; - - /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ - int protocol; -} SocketAddress; - -typedef enum SocketAddressBindIPv6Only { - SOCKET_ADDRESS_DEFAULT, - SOCKET_ADDRESS_BOTH, - SOCKET_ADDRESS_IPV6_ONLY, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 -} SocketAddressBindIPv6Only; - -#define socket_address_family(a) ((a)->sockaddr.sa.sa_family) - -int socket_address_parse(SocketAddress *a, const char *s); -int socket_address_parse_netlink(SocketAddress *a, const char *s); -int socket_address_print(const SocketAddress *a, char **p); -int socket_address_verify(const SocketAddress *a); - -bool socket_address_can_accept(const SocketAddress *a); - -int socket_address_listen( - const SocketAddress *a, - int backlog, - SocketAddressBindIPv6Only only, - const char *bind_to_device, - bool free_bind, - bool transparent, - mode_t directory_mode, - mode_t socket_mode, - const char *label, - int *ret); - -bool socket_address_is(const SocketAddress *a, const char *s, int type); -bool socket_address_is_netlink(const SocketAddress *a, const char *s); - -bool socket_address_equal(const SocketAddress *a, const SocketAddress *b); - -bool socket_address_needs_mount(const SocketAddress *a, const char *prefix); - -const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b); -SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s); - -const char* netlink_family_to_string(int b); -int netlink_family_from_string(const char *s); - -bool socket_ipv6_is_supported(void); - -#endif diff --git a/src/socket.c b/src/socket.c deleted file mode 100644 index 7ddf326..0000000 --- a/src/socket.c +++ /dev/null @@ -1,2136 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "unit.h" -#include "socket.h" -#include "netinet/tcp.h" -#include "log.h" -#include "load-dropin.h" -#include "load-fragment.h" -#include "strv.h" -#include "unit-name.h" -#include "dbus-socket.h" -#include "missing.h" -#include "special.h" -#include "bus-errors.h" -#include "label.h" -#include "exit-status.h" -#include "def.h" - -static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { - [SOCKET_DEAD] = UNIT_INACTIVE, - [SOCKET_START_PRE] = UNIT_ACTIVATING, - [SOCKET_START_POST] = UNIT_ACTIVATING, - [SOCKET_LISTENING] = UNIT_ACTIVE, - [SOCKET_RUNNING] = UNIT_ACTIVE, - [SOCKET_STOP_PRE] = UNIT_DEACTIVATING, - [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING, - [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING, - [SOCKET_STOP_POST] = UNIT_DEACTIVATING, - [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING, - [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING, - [SOCKET_FAILED] = UNIT_FAILED -}; - -static void socket_init(Unit *u) { - Socket *s = SOCKET(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - s->backlog = SOMAXCONN; - s->timeout_usec = DEFAULT_TIMEOUT_USEC; - s->directory_mode = 0755; - s->socket_mode = 0666; - - s->max_connections = 64; - - s->priority = -1; - s->ip_tos = -1; - s->ip_ttl = -1; - s->mark = -1; - - exec_context_init(&s->exec_context); - s->exec_context.std_output = u->meta.manager->default_std_output; - s->exec_context.std_error = u->meta.manager->default_std_error; - - s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; -} - -static void socket_unwatch_control_pid(Socket *s) { - assert(s); - - if (s->control_pid <= 0) - return; - - unit_unwatch_pid(UNIT(s), s->control_pid); - s->control_pid = 0; -} - -static void socket_done(Unit *u) { - Socket *s = SOCKET(u); - SocketPort *p; - Meta *i; - - assert(s); - - while ((p = s->ports)) { - LIST_REMOVE(SocketPort, port, s->ports, p); - - if (p->fd >= 0) { - unit_unwatch_fd(UNIT(s), &p->fd_watch); - close_nointr_nofail(p->fd); - } - - free(p->path); - free(p); - } - - exec_context_done(&s->exec_context); - exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX); - s->control_command = NULL; - - socket_unwatch_control_pid(s); - - s->service = NULL; - - free(s->tcp_congestion); - s->tcp_congestion = NULL; - - free(s->bind_to_device); - s->bind_to_device = NULL; - - unit_unwatch_timer(u, &s->timer_watch); - - /* Make sure no service instance refers to us anymore. */ - LIST_FOREACH(units_by_type, i, u->meta.manager->units_by_type[UNIT_SERVICE]) { - Service *service = (Service *) i; - - if (service->accept_socket == s) - service->accept_socket = NULL; - - set_remove(service->configured_sockets, s); - } -} - -static int socket_instantiate_service(Socket *s) { - char *prefix, *name; - int r; - Unit *u; - - assert(s); - - /* This fills in s->service if it isn't filled in yet. For - * Accept=yes sockets we create the next connection service - * here. For Accept=no this is mostly a NOP since the service - * is figured out at load time anyway. */ - - if (s->service) - return 0; - - assert(s->accept); - - if (!(prefix = unit_name_to_prefix(s->meta.id))) - return -ENOMEM; - - r = asprintf(&name, "%s@%u.service", prefix, s->n_accepted); - free(prefix); - - if (r < 0) - return -ENOMEM; - - r = manager_load_unit(s->meta.manager, name, NULL, NULL, &u); - free(name); - - if (r < 0) - return r; - -#ifdef HAVE_SYSV_COMPAT - if (SERVICE(u)->sysv_path) { - log_error("Using SysV services for socket activation is not supported. Refusing."); - return -ENOENT; - } -#endif - - u->meta.no_gc = true; - s->service = SERVICE(u); - return 0; -} - -static bool have_non_accept_socket(Socket *s) { - SocketPort *p; - - assert(s); - - if (!s->accept) - return true; - - LIST_FOREACH(port, p, s->ports) { - - if (p->type != SOCKET_SOCKET) - return true; - - if (!socket_address_can_accept(&p->address)) - return true; - } - - return false; -} - -static int socket_verify(Socket *s) { - assert(s); - - if (s->meta.load_state != UNIT_LOADED) - return 0; - - if (!s->ports) { - log_error("%s lacks Listen setting. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->accept && have_non_accept_socket(s)) { - log_error("%s configured for accepting sockets, but sockets are non-accepting. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->accept && s->max_connections <= 0) { - log_error("%s's MaxConnection setting too small. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->accept && s->service) { - log_error("Explicit service configuration for accepting sockets not supported on %s. Refusing.", s->meta.id); - return -EINVAL; - } - - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { - log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", s->meta.id); - return -EINVAL; - } - - return 0; -} - -static bool socket_needs_mount(Socket *s, const char *prefix) { - SocketPort *p; - - assert(s); - - LIST_FOREACH(port, p, s->ports) { - - if (p->type == SOCKET_SOCKET) { - if (socket_address_needs_mount(&p->address, prefix)) - return true; - } else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) { - if (path_startswith(p->path, prefix)) - return true; - } - } - - return false; -} - -int socket_add_one_mount_link(Socket *s, Mount *m) { - int r; - - assert(s); - assert(m); - - if (s->meta.load_state != UNIT_LOADED || - m->meta.load_state != UNIT_LOADED) - return 0; - - if (!socket_needs_mount(s, m->where)) - return 0; - - if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - - return 0; -} - -static int socket_add_mount_links(Socket *s) { - Meta *other; - int r; - - assert(s); - - LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_MOUNT]) - if ((r = socket_add_one_mount_link(s, (Mount*) other)) < 0) - return r; - - return 0; -} - -static int socket_add_device_link(Socket *s) { - char *t; - int r; - - assert(s); - - if (!s->bind_to_device) - return 0; - - if (asprintf(&t, "/sys/subsystem/net/devices/%s", s->bind_to_device) < 0) - return -ENOMEM; - - r = unit_add_node_link(UNIT(s), t, false); - free(t); - - return r; -} - -static int socket_add_default_dependencies(Socket *s) { - int r; - assert(s); - - if (s->meta.manager->running_as == MANAGER_SYSTEM) { - if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0) - return r; - - if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0) - return r; - } - - return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); -} - -static int socket_load(Unit *u) { - Socket *s = SOCKET(u); - int r; - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - if ((r = unit_load_fragment_and_dropin(u)) < 0) - return r; - - /* This is a new unit? Then let's add in some extras */ - if (u->meta.load_state == UNIT_LOADED) { - - if (have_non_accept_socket(s)) { - - if (!s->service) - if ((r = unit_load_related_unit(u, ".service", (Unit**) &s->service)) < 0) - return r; - - if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service), true)) < 0) - return r; - } - - if ((r = socket_add_mount_links(s)) < 0) - return r; - - if ((r = socket_add_device_link(s)) < 0) - return r; - - if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) - return r; - - if ((r = unit_add_default_cgroups(u)) < 0) - return r; - - if (s->meta.default_dependencies) - if ((r = socket_add_default_dependencies(s)) < 0) - return r; - } - - return socket_verify(s); -} - -static const char* listen_lookup(int family, int type) { - - if (family == AF_NETLINK) - return "ListenNetlink"; - - if (type == SOCK_STREAM) - return "ListenStream"; - else if (type == SOCK_DGRAM) - return "ListenDatagram"; - else if (type == SOCK_SEQPACKET) - return "ListenSequentialPacket"; - - assert_not_reached("Unknown socket type"); - return NULL; -} - -static void socket_dump(Unit *u, FILE *f, const char *prefix) { - - SocketExecCommand c; - Socket *s = SOCKET(u); - SocketPort *p; - const char *prefix2; - char *p2; - - assert(s); - assert(f); - - p2 = strappend(prefix, "\t"); - prefix2 = p2 ? p2 : prefix; - - fprintf(f, - "%sSocket State: %s\n" - "%sBindIPv6Only: %s\n" - "%sBacklog: %u\n" - "%sSocketMode: %04o\n" - "%sDirectoryMode: %04o\n" - "%sKeepAlive: %s\n" - "%sFreeBind: %s\n" - "%sTransparent: %s\n" - "%sBroadcast: %s\n" - "%sTCPCongestion: %s\n", - prefix, socket_state_to_string(s->state), - prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), - prefix, s->backlog, - prefix, s->socket_mode, - prefix, s->directory_mode, - prefix, yes_no(s->keep_alive), - prefix, yes_no(s->free_bind), - prefix, yes_no(s->transparent), - prefix, yes_no(s->broadcast), - prefix, strna(s->tcp_congestion)); - - if (s->control_pid > 0) - fprintf(f, - "%sControl PID: %lu\n", - prefix, (unsigned long) s->control_pid); - - if (s->bind_to_device) - fprintf(f, - "%sBindToDevice: %s\n", - prefix, s->bind_to_device); - - if (s->accept) - fprintf(f, - "%sAccepted: %u\n" - "%sNConnections: %u\n" - "%sMaxConnections: %u\n", - prefix, s->n_accepted, - prefix, s->n_connections, - prefix, s->max_connections); - - if (s->priority >= 0) - fprintf(f, - "%sPriority: %i\n", - prefix, s->priority); - - if (s->receive_buffer > 0) - fprintf(f, - "%sReceiveBuffer: %zu\n", - prefix, s->receive_buffer); - - if (s->send_buffer > 0) - fprintf(f, - "%sSendBuffer: %zu\n", - prefix, s->send_buffer); - - if (s->ip_tos >= 0) - fprintf(f, - "%sIPTOS: %i\n", - prefix, s->ip_tos); - - if (s->ip_ttl >= 0) - fprintf(f, - "%sIPTTL: %i\n", - prefix, s->ip_ttl); - - if (s->pipe_size > 0) - fprintf(f, - "%sPipeSize: %zu\n", - prefix, s->pipe_size); - - if (s->mark >= 0) - fprintf(f, - "%sMark: %i\n", - prefix, s->mark); - - if (s->mq_maxmsg > 0) - fprintf(f, - "%sMessageQueueMaxMessages: %li\n", - prefix, s->mq_maxmsg); - - if (s->mq_msgsize > 0) - fprintf(f, - "%sMessageQueueMessageSize: %li\n", - prefix, s->mq_msgsize); - - LIST_FOREACH(port, p, s->ports) { - - if (p->type == SOCKET_SOCKET) { - const char *t; - int r; - char *k = NULL; - - if ((r = socket_address_print(&p->address, &k)) < 0) - t = strerror(-r); - else - t = k; - - fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t); - free(k); - } else if (p->type == SOCKET_SPECIAL) - fprintf(f, "%sListenSpecial: %s\n", prefix, p->path); - else if (p->type == SOCKET_MQUEUE) - fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path); - else - fprintf(f, "%sListenFIFO: %s\n", prefix, p->path); - } - - exec_context_dump(&s->exec_context, f, prefix); - - for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) { - if (!s->exec_command[c]) - continue; - - fprintf(f, "%s-> %s:\n", - prefix, socket_exec_command_to_string(c)); - - exec_command_dump_list(s->exec_command[c], f, prefix2); - } - - free(p2); -} - -static int instance_from_socket(int fd, unsigned nr, char **instance) { - socklen_t l; - char *r; - union { - struct sockaddr sa; - struct sockaddr_un un; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_storage storage; - } local, remote; - - assert(fd >= 0); - assert(instance); - - l = sizeof(local); - if (getsockname(fd, &local.sa, &l) < 0) - return -errno; - - l = sizeof(remote); - if (getpeername(fd, &remote.sa, &l) < 0) - return -errno; - - switch (local.sa.sa_family) { - - case AF_INET: { - uint32_t - a = ntohl(local.in.sin_addr.s_addr), - b = ntohl(remote.in.sin_addr.s_addr); - - if (asprintf(&r, - "%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", - a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, - ntohs(local.in.sin_port), - b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF, - ntohs(remote.in.sin_port)) < 0) - return -ENOMEM; - - break; - } - - case AF_INET6: { - static const char ipv4_prefix[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF - }; - - if (memcmp(&local.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0 && - memcmp(&remote.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) { - const uint8_t - *a = local.in6.sin6_addr.s6_addr+12, - *b = remote.in6.sin6_addr.s6_addr+12; - - if (asprintf(&r, - "%u.%u.%u.%u:%u-%u.%u.%u.%u:%u", - a[0], a[1], a[2], a[3], - ntohs(local.in6.sin6_port), - b[0], b[1], b[2], b[3], - ntohs(remote.in6.sin6_port)) < 0) - return -ENOMEM; - } else { - char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN]; - - if (asprintf(&r, - "%s:%u-%s:%u", - inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)), - ntohs(local.in6.sin6_port), - inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)), - ntohs(remote.in6.sin6_port)) < 0) - return -ENOMEM; - } - - break; - } - - case AF_UNIX: { - struct ucred ucred; - - l = sizeof(ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) - return -errno; - - if (asprintf(&r, - "%u-%lu-%lu", - nr, - (unsigned long) ucred.pid, - (unsigned long) ucred.uid) < 0) - return -ENOMEM; - - break; - } - - default: - assert_not_reached("Unhandled socket type."); - } - - *instance = r; - return 0; -} - -static void socket_close_fds(Socket *s) { - SocketPort *p; - - assert(s); - - LIST_FOREACH(port, p, s->ports) { - if (p->fd < 0) - continue; - - unit_unwatch_fd(UNIT(s), &p->fd_watch); - close_nointr_nofail(p->fd); - - /* One little note: we should never delete any sockets - * in the file system here! After all some other - * process we spawned might still have a reference of - * this fd and wants to continue to use it. Therefore - * we delete sockets in the file system before we - * create a new one, not after we stopped using - * one! */ - - p->fd = -1; - } -} - -static void socket_apply_socket_options(Socket *s, int fd) { - assert(s); - assert(fd >= 0); - - if (s->keep_alive) { - int b = s->keep_alive; - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0) - log_warning("SO_KEEPALIVE failed: %m"); - } - - if (s->broadcast) { - int one = 1; - if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) - log_warning("SO_BROADCAST failed: %m"); - } - - if (s->priority >= 0) - if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0) - log_warning("SO_PRIORITY failed: %m"); - - if (s->receive_buffer > 0) { - int value = (int) s->receive_buffer; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) - log_warning("SO_RCVBUFFORCE failed: %m"); - } - - if (s->send_buffer > 0) { - int value = (int) s->send_buffer; - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) - log_warning("SO_SNDBUFFORCE failed: %m"); - } - - if (s->mark >= 0) - if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0) - log_warning("SO_MARK failed: %m"); - - if (s->ip_tos >= 0) - if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0) - log_warning("IP_TOS failed: %m"); - - if (s->ip_ttl >= 0) { - int r, x; - - r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl)); - - if (socket_ipv6_is_supported()) - x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl)); - else { - x = -1; - errno = EAFNOSUPPORT; - } - - if (r < 0 && x < 0) - log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m"); - } - - if (s->tcp_congestion) - if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) - log_warning("TCP_CONGESTION failed: %m"); -} - -static void socket_apply_fifo_options(Socket *s, int fd) { - assert(s); - assert(fd >= 0); - - if (s->pipe_size > 0) - if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0) - log_warning("F_SETPIPE_SZ: %m"); -} - -static int fifo_address_create( - const char *path, - mode_t directory_mode, - mode_t socket_mode, - int *_fd) { - - int fd = -1, r = 0; - struct stat st; - mode_t old_mask; - - assert(path); - assert(_fd); - - mkdir_parents(path, directory_mode); - - if ((r = label_fifofile_set(path)) < 0) - goto fail; - - /* Enforce the right access mode for the fifo */ - old_mask = umask(~ socket_mode); - - /* Include the original umask in our mask */ - umask(~socket_mode | old_mask); - - r = mkfifo(path, socket_mode); - umask(old_mask); - - if (r < 0 && errno != EEXIST) { - r = -errno; - goto fail; - } - - if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { - r = -errno; - goto fail; - } - - label_file_clear(); - - if (fstat(fd, &st) < 0) { - r = -errno; - goto fail; - } - - if (!S_ISFIFO(st.st_mode) || - (st.st_mode & 0777) != (socket_mode & ~old_mask) || - st.st_uid != getuid() || - st.st_gid != getgid()) { - - r = -EEXIST; - goto fail; - } - - *_fd = fd; - return 0; - -fail: - label_file_clear(); - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int special_address_create( - const char *path, - int *_fd) { - - int fd = -1, r = 0; - struct stat st; - - assert(path); - assert(_fd); - - if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { - r = -errno; - goto fail; - } - - if (fstat(fd, &st) < 0) { - r = -errno; - goto fail; - } - - /* Check whether this is a /proc, /sys or /dev file or char device */ - if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { - r = -EEXIST; - goto fail; - } - - *_fd = fd; - return 0; - -fail: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int mq_address_create( - const char *path, - mode_t mq_mode, - long maxmsg, - long msgsize, - int *_fd) { - - int fd = -1, r = 0; - struct stat st; - mode_t old_mask; - struct mq_attr _attr, *attr = NULL; - - assert(path); - assert(_fd); - - if (maxmsg > 0 && msgsize > 0) { - zero(_attr); - _attr.mq_flags = O_NONBLOCK; - _attr.mq_maxmsg = maxmsg; - _attr.mq_msgsize = msgsize; - attr = &_attr; - } - - /* Enforce the right access mode for the mq */ - old_mask = umask(~ mq_mode); - - /* Include the original umask in our mask */ - umask(~mq_mode | old_mask); - - fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); - umask(old_mask); - - if (fd < 0) { - r = -errno; - goto fail; - } - - if (fstat(fd, &st) < 0) { - r = -errno; - goto fail; - } - - if ((st.st_mode & 0777) != (mq_mode & ~old_mask) || - st.st_uid != getuid() || - st.st_gid != getgid()) { - - r = -EEXIST; - goto fail; - } - - *_fd = fd; - return 0; - -fail: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int socket_open_fds(Socket *s) { - SocketPort *p; - int r; - char *label = NULL; - bool know_label = false; - - assert(s); - - LIST_FOREACH(port, p, s->ports) { - - if (p->fd >= 0) - continue; - - if (p->type == SOCKET_SOCKET) { - - if (!know_label) { - - if ((r = socket_instantiate_service(s)) < 0) - return r; - - if (s->service && s->service->exec_command[SERVICE_EXEC_START]) { - r = label_get_create_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label); - - if (r < 0) { - if (r != -EPERM) - return r; - } - } - - know_label = true; - } - - if ((r = socket_address_listen( - &p->address, - s->backlog, - s->bind_ipv6_only, - s->bind_to_device, - s->free_bind, - s->transparent, - s->directory_mode, - s->socket_mode, - label, - &p->fd)) < 0) - goto rollback; - - socket_apply_socket_options(s, p->fd); - - } else if (p->type == SOCKET_SPECIAL) { - - if ((r = special_address_create( - p->path, - &p->fd)) < 0) - goto rollback; - - } else if (p->type == SOCKET_FIFO) { - - if ((r = fifo_address_create( - p->path, - s->directory_mode, - s->socket_mode, - &p->fd)) < 0) - goto rollback; - - socket_apply_fifo_options(s, p->fd); - } else if (p->type == SOCKET_MQUEUE) { - - if ((r = mq_address_create( - p->path, - s->socket_mode, - s->mq_maxmsg, - s->mq_msgsize, - &p->fd)) < 0) - goto rollback; - } else - assert_not_reached("Unknown port type"); - } - - label_free(label); - return 0; - -rollback: - socket_close_fds(s); - label_free(label); - return r; -} - -static void socket_unwatch_fds(Socket *s) { - SocketPort *p; - - assert(s); - - LIST_FOREACH(port, p, s->ports) { - if (p->fd < 0) - continue; - - unit_unwatch_fd(UNIT(s), &p->fd_watch); - } -} - -static int socket_watch_fds(Socket *s) { - SocketPort *p; - int r; - - assert(s); - - LIST_FOREACH(port, p, s->ports) { - if (p->fd < 0) - continue; - - p->fd_watch.socket_accept = - s->accept && - p->type == SOCKET_SOCKET && - socket_address_can_accept(&p->address); - - if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0) - goto fail; - } - - return 0; - -fail: - socket_unwatch_fds(s); - return r; -} - -static void socket_set_state(Socket *s, SocketState state) { - SocketState old_state; - assert(s); - - old_state = s->state; - s->state = state; - - if (state != SOCKET_START_PRE && - state != SOCKET_START_POST && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL && - state != SOCKET_STOP_POST && - state != SOCKET_FINAL_SIGTERM && - state != SOCKET_FINAL_SIGKILL) { - unit_unwatch_timer(UNIT(s), &s->timer_watch); - socket_unwatch_control_pid(s); - s->control_command = NULL; - s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; - } - - if (state != SOCKET_LISTENING) - socket_unwatch_fds(s); - - if (state != SOCKET_START_POST && - state != SOCKET_LISTENING && - state != SOCKET_RUNNING && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL) - socket_close_fds(s); - - if (state != old_state) - log_debug("%s changed %s -> %s", - s->meta.id, - socket_state_to_string(old_state), - socket_state_to_string(state)); - - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); -} - -static int socket_coldplug(Unit *u) { - Socket *s = SOCKET(u); - int r; - - assert(s); - assert(s->state == SOCKET_DEAD); - - if (s->deserialized_state != s->state) { - - if (s->deserialized_state == SOCKET_START_PRE || - s->deserialized_state == SOCKET_START_POST || - s->deserialized_state == SOCKET_STOP_PRE || - s->deserialized_state == SOCKET_STOP_PRE_SIGTERM || - s->deserialized_state == SOCKET_STOP_PRE_SIGKILL || - s->deserialized_state == SOCKET_STOP_POST || - s->deserialized_state == SOCKET_FINAL_SIGTERM || - s->deserialized_state == SOCKET_FINAL_SIGKILL) { - - if (s->control_pid <= 0) - return -EBADMSG; - - if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0) - return r; - - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - return r; - } - - if (s->deserialized_state == SOCKET_START_POST || - s->deserialized_state == SOCKET_LISTENING || - s->deserialized_state == SOCKET_RUNNING || - s->deserialized_state == SOCKET_STOP_PRE || - s->deserialized_state == SOCKET_STOP_PRE_SIGTERM || - s->deserialized_state == SOCKET_STOP_PRE_SIGKILL) - if ((r = socket_open_fds(s)) < 0) - return r; - - if (s->deserialized_state == SOCKET_LISTENING) - if ((r = socket_watch_fds(s)) < 0) - return r; - - socket_set_state(s, s->deserialized_state); - } - - return 0; -} - -static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { - pid_t pid; - int r; - char **argv; - - assert(s); - assert(c); - assert(_pid); - - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - - if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) { - r = -ENOMEM; - goto fail; - } - - r = exec_spawn(c, - argv, - &s->exec_context, - NULL, 0, - s->meta.manager->environment, - true, - true, - true, - s->meta.manager->confirm_spawn, - s->meta.cgroup_bondings, - s->meta.cgroup_attributes, - &pid); - - strv_free(argv); - if (r < 0) - goto fail; - - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) - /* FIXME: we need to do something here */ - goto fail; - - *_pid = pid; - - return 0; - -fail: - unit_unwatch_timer(UNIT(s), &s->timer_watch); - - return r; -} - -static void socket_enter_dead(Socket *s, bool success) { - assert(s); - - if (!success) - s->failure = true; - - socket_set_state(s, s->failure ? SOCKET_FAILED : SOCKET_DEAD); -} - -static void socket_enter_signal(Socket *s, SocketState state, bool success); - -static void socket_enter_stop_post(Socket *s, bool success) { - int r; - assert(s); - - if (!success) - s->failure = true; - - socket_unwatch_control_pid(s); - - s->control_command_id = SOCKET_EXEC_STOP_POST; - - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) { - if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - socket_set_state(s, SOCKET_STOP_POST); - } else - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, true); - - return; - -fail: - log_warning("%s failed to run 'stop-post' task: %s", s->meta.id, strerror(-r)); - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); -} - -static void socket_enter_signal(Socket *s, SocketState state, bool success) { - int r; - Set *pid_set = NULL; - bool wait_for_exit = false; - - assert(s); - - if (!success) - s->failure = true; - - if (s->exec_context.kill_mode != KILL_NONE) { - int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; - - if (s->control_pid > 0) { - if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) - - log_warning("Failed to kill control process %li: %m", (long) s->control_pid); - else - wait_for_exit = true; - } - - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { - r = -ENOMEM; - goto fail; - } - - /* Exclude the control pid from being killed via the cgroup */ - if (s->control_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) - goto fail; - - if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, true, pid_set)) < 0) { - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) - log_warning("Failed to kill control group: %s", strerror(-r)); - } else if (r > 0) - wait_for_exit = true; - - set_free(pid_set); - pid_set = NULL; - } - } - - if (wait_for_exit) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - - socket_set_state(s, state); - } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL) - socket_enter_stop_post(s, true); - else - socket_enter_dead(s, true); - - return; - -fail: - log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r)); - - if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL) - socket_enter_stop_post(s, false); - else - socket_enter_dead(s, false); - - if (pid_set) - set_free(pid_set); -} - -static void socket_enter_stop_pre(Socket *s, bool success) { - int r; - assert(s); - - if (!success) - s->failure = true; - - socket_unwatch_control_pid(s); - - s->control_command_id = SOCKET_EXEC_STOP_PRE; - - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) { - if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - socket_set_state(s, SOCKET_STOP_PRE); - } else - socket_enter_stop_post(s, true); - - return; - -fail: - log_warning("%s failed to run 'stop-pre' task: %s", s->meta.id, strerror(-r)); - socket_enter_stop_post(s, false); -} - -static void socket_enter_listening(Socket *s) { - int r; - assert(s); - - if ((r = socket_watch_fds(s)) < 0) { - log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r)); - goto fail; - } - - socket_set_state(s, SOCKET_LISTENING); - return; - -fail: - socket_enter_stop_pre(s, false); -} - -static void socket_enter_start_post(Socket *s) { - int r; - assert(s); - - if ((r = socket_open_fds(s)) < 0) { - log_warning("%s failed to listen on sockets: %s", s->meta.id, strerror(-r)); - goto fail; - } - - socket_unwatch_control_pid(s); - - s->control_command_id = SOCKET_EXEC_START_POST; - - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) { - if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) { - log_warning("%s failed to run 'start-post' task: %s", s->meta.id, strerror(-r)); - goto fail; - } - - socket_set_state(s, SOCKET_START_POST); - } else - socket_enter_listening(s); - - return; - -fail: - socket_enter_stop_pre(s, false); -} - -static void socket_enter_start_pre(Socket *s) { - int r; - assert(s); - - socket_unwatch_control_pid(s); - - s->control_command_id = SOCKET_EXEC_START_PRE; - - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) { - if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - socket_set_state(s, SOCKET_START_PRE); - } else - socket_enter_start_post(s); - - return; - -fail: - log_warning("%s failed to run 'start-pre' task: %s", s->meta.id, strerror(-r)); - socket_enter_dead(s, false); -} - -static void socket_enter_running(Socket *s, int cfd) { - int r; - DBusError error; - - assert(s); - dbus_error_init(&error); - - /* We don't take connections anymore if we are supposed to - * shut down anyway */ - if (unit_pending_inactive(UNIT(s))) { - log_debug("Suppressing connection request on %s since unit stop is scheduled.", s->meta.id); - - if (cfd >= 0) - close_nointr_nofail(cfd); - else { - /* Flush all sockets by closing and reopening them */ - socket_close_fds(s); - - if ((r = socket_watch_fds(s)) < 0) { - log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r)); - socket_enter_stop_pre(s, false); - } - } - - return; - } - - if (cfd < 0) { - bool pending = false; - Meta *i; - - /* If there's already a start pending don't bother to - * do anything */ - LIST_FOREACH(units_by_type, i, s->meta.manager->units_by_type[UNIT_SERVICE]) { - Service *service = (Service *) i; - - if (!set_get(service->configured_sockets, s)) - continue; - - if (!unit_pending_active(UNIT(service))) - continue; - - pending = true; - break; - } - - if (!pending) - if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0) - goto fail; - - socket_set_state(s, SOCKET_RUNNING); - } else { - char *prefix, *instance = NULL, *name; - Service *service; - - if (s->n_connections >= s->max_connections) { - log_warning("Too many incoming connections (%u)", s->n_connections); - close_nointr_nofail(cfd); - return; - } - - if ((r = socket_instantiate_service(s)) < 0) - goto fail; - - if ((r = instance_from_socket(cfd, s->n_accepted, &instance)) < 0) - goto fail; - - if (!(prefix = unit_name_to_prefix(s->meta.id))) { - free(instance); - r = -ENOMEM; - goto fail; - } - - name = unit_name_build(prefix, instance, ".service"); - free(prefix); - free(instance); - - if (!name) { - r = -ENOMEM; - goto fail; - } - - if ((r = unit_add_name(UNIT(s->service), name)) < 0) { - free(name); - goto fail; - } - - service = s->service; - s->service = NULL; - s->n_accepted ++; - - service->meta.no_gc = false; - - unit_choose_id(UNIT(service), name); - free(name); - - if ((r = service_set_socket_fd(service, cfd, s)) < 0) - goto fail; - - cfd = -1; - s->n_connections ++; - - if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL)) < 0) - goto fail; - - /* Notify clients about changed counters */ - unit_add_to_dbus_queue(UNIT(s)); - } - - return; - -fail: - log_warning("%s failed to queue socket startup job: %s", s->meta.id, bus_error(&error, r)); - socket_enter_stop_pre(s, false); - - if (cfd >= 0) - close_nointr_nofail(cfd); - - dbus_error_free(&error); -} - -static void socket_run_next(Socket *s, bool success) { - int r; - - assert(s); - assert(s->control_command); - assert(s->control_command->command_next); - - if (!success) - s->failure = true; - - socket_unwatch_control_pid(s); - - s->control_command = s->control_command->command_next; - - if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - return; - -fail: - log_warning("%s failed to run next task: %s", s->meta.id, strerror(-r)); - - if (s->state == SOCKET_START_POST) - socket_enter_stop_pre(s, false); - else if (s->state == SOCKET_STOP_POST) - socket_enter_dead(s, false); - else - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); -} - -static int socket_start(Unit *u) { - Socket *s = SOCKET(u); - - assert(s); - - /* We cannot fulfill this request right now, try again later - * please! */ - if (s->state == SOCKET_STOP_PRE || - s->state == SOCKET_STOP_PRE_SIGKILL || - s->state == SOCKET_STOP_PRE_SIGTERM || - s->state == SOCKET_STOP_POST || - s->state == SOCKET_FINAL_SIGTERM || - s->state == SOCKET_FINAL_SIGKILL) - return -EAGAIN; - - if (s->state == SOCKET_START_PRE || - s->state == SOCKET_START_POST) - return 0; - - /* Cannot run this without the service being around */ - if (s->service) { - if (s->service->meta.load_state != UNIT_LOADED) { - log_error("Socket service %s not loaded, refusing.", s->service->meta.id); - return -ENOENT; - } - - /* If the service is already active we cannot start the - * socket */ - if (s->service->state != SERVICE_DEAD && - s->service->state != SERVICE_FAILED && - s->service->state != SERVICE_AUTO_RESTART) { - log_error("Socket service %s already active, refusing.", s->service->meta.id); - return -EBUSY; - } - -#ifdef HAVE_SYSV_COMPAT - if (s->service->sysv_path) { - log_error("Using SysV services for socket activation is not supported. Refusing."); - return -ENOENT; - } -#endif - } - - assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED); - - s->failure = false; - socket_enter_start_pre(s); - return 0; -} - -static int socket_stop(Unit *u) { - Socket *s = SOCKET(u); - - assert(s); - - /* Already on it */ - if (s->state == SOCKET_STOP_PRE || - s->state == SOCKET_STOP_PRE_SIGTERM || - s->state == SOCKET_STOP_PRE_SIGKILL || - s->state == SOCKET_STOP_POST || - s->state == SOCKET_FINAL_SIGTERM || - s->state == SOCKET_FINAL_SIGKILL) - return 0; - - /* If there's already something running we go directly into - * kill mode. */ - if (s->state == SOCKET_START_PRE || - s->state == SOCKET_START_POST) { - socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, true); - return -EAGAIN; - } - - assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING); - - socket_enter_stop_pre(s, true); - return 0; -} - -static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { - Socket *s = SOCKET(u); - SocketPort *p; - int r; - - assert(u); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", socket_state_to_string(s->state)); - unit_serialize_item(u, f, "failure", yes_no(s->failure)); - unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted); - - if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); - - if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id)); - - LIST_FOREACH(port, p, s->ports) { - int copy; - - if (p->fd < 0) - continue; - - if ((copy = fdset_put_dup(fds, p->fd)) < 0) - return copy; - - if (p->type == SOCKET_SOCKET) { - char *t; - - if ((r = socket_address_print(&p->address, &t)) < 0) - return r; - - if (socket_address_family(&p->address) == AF_NETLINK) - unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t); - else - unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t); - free(t); - } else if (p->type == SOCKET_SPECIAL) - unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path); - else { - assert(p->type == SOCKET_FIFO); - unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path); - } - } - - return 0; -} - -static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Socket *s = SOCKET(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - SocketState state; - - if ((state = socket_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - s->deserialized_state = state; - } else if (streq(key, "failure")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse failure value %s", value); - else - s->failure = b || s->failure; - - } else if (streq(key, "n-accepted")) { - unsigned k; - - if (safe_atou(value, &k) < 0) - log_debug("Failed to parse n-accepted value %s", value); - else - s->n_accepted += k; - } else if (streq(key, "control-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse control-pid value %s", value); - else - s->control_pid = pid; - } else if (streq(key, "control-command")) { - SocketExecCommand id; - - if ((id = socket_exec_command_from_string(value)) < 0) - log_debug("Failed to parse exec-command value %s", value); - else { - s->control_command_id = id; - s->control_command = s->exec_command[id]; - } - } else if (streq(key, "fifo")) { - int fd, skip = 0; - SocketPort *p; - - if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse fifo value %s", value); - else { - - LIST_FOREACH(port, p, s->ports) - if (p->type == SOCKET_FIFO && - streq_ptr(p->path, value+skip)) - break; - - if (p) { - if (p->fd >= 0) - close_nointr_nofail(p->fd); - p->fd = fdset_remove(fds, fd); - } - } - - } else if (streq(key, "special")) { - int fd, skip = 0; - SocketPort *p; - - if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse special value %s", value); - else { - - LIST_FOREACH(port, p, s->ports) - if (p->type == SOCKET_SPECIAL && - streq_ptr(p->path, value+skip)) - break; - - if (p) { - if (p->fd >= 0) - close_nointr_nofail(p->fd); - p->fd = fdset_remove(fds, fd); - } - } - - } else if (streq(key, "socket")) { - int fd, type, skip = 0; - SocketPort *p; - - if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse socket value %s", value); - else { - - LIST_FOREACH(port, p, s->ports) - if (socket_address_is(&p->address, value+skip, type)) - break; - - if (p) { - if (p->fd >= 0) - close_nointr_nofail(p->fd); - p->fd = fdset_remove(fds, fd); - } - } - - } else if (streq(key, "netlink")) { - int fd, skip = 0; - SocketPort *p; - - if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) - log_debug("Failed to parse socket value %s", value); - else { - - LIST_FOREACH(port, p, s->ports) - if (socket_address_is_netlink(&p->address, value+skip)) - break; - - if (p) { - if (p->fd >= 0) - close_nointr_nofail(p->fd); - p->fd = fdset_remove(fds, fd); - } - } - - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState socket_active_state(Unit *u) { - assert(u); - - return state_translation_table[SOCKET(u)->state]; -} - -static const char *socket_sub_state_to_string(Unit *u) { - assert(u); - - return socket_state_to_string(SOCKET(u)->state); -} - -static bool socket_check_gc(Unit *u) { - Socket *s = SOCKET(u); - - assert(u); - - return s->n_connections > 0; -} - -static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { - Socket *s = SOCKET(u); - int cfd = -1; - - assert(s); - assert(fd >= 0); - - if (s->state != SOCKET_LISTENING) - return; - - log_debug("Incoming traffic on %s", u->meta.id); - - if (events != EPOLLIN) { - - if (events & EPOLLHUP) - log_error("%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", u->meta.id); - else - log_error("%s: Got unexpected poll event (0x%x) on socket.", u->meta.id, events); - - goto fail; - } - - if (w->socket_accept) { - for (;;) { - - if ((cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK)) < 0) { - - if (errno == EINTR) - continue; - - log_error("Failed to accept socket: %m"); - goto fail; - } - - break; - } - - socket_apply_socket_options(s, cfd); - } - - socket_enter_running(s, cfd); - return; - -fail: - socket_enter_stop_pre(s, false); -} - -static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { - Socket *s = SOCKET(u); - bool success; - - assert(s); - assert(pid >= 0); - - if (pid != s->control_pid) - return; - - s->control_pid = 0; - - success = is_clean_exit(code, status); - - if (s->control_command) { - exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); - - if (s->control_command->ignore) - success = true; - } - - log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); - s->failure = s->failure || !success; - - if (s->control_command && s->control_command->command_next && success) { - log_debug("%s running next command for state %s", u->meta.id, socket_state_to_string(s->state)); - socket_run_next(s, success); - } else { - s->control_command = NULL; - s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; - - /* No further commands for this step, so let's figure - * out what to do next */ - - log_debug("%s got final SIGCHLD for state %s", u->meta.id, socket_state_to_string(s->state)); - - switch (s->state) { - - case SOCKET_START_PRE: - if (success) - socket_enter_start_post(s); - else - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); - break; - - case SOCKET_START_POST: - if (success) - socket_enter_listening(s); - else - socket_enter_stop_pre(s, false); - break; - - case SOCKET_STOP_PRE: - case SOCKET_STOP_PRE_SIGTERM: - case SOCKET_STOP_PRE_SIGKILL: - socket_enter_stop_post(s, success); - break; - - case SOCKET_STOP_POST: - case SOCKET_FINAL_SIGTERM: - case SOCKET_FINAL_SIGKILL: - socket_enter_dead(s, success); - break; - - default: - assert_not_reached("Uh, control process died at wrong time."); - } - } - - /* Notify clients about changed exit status */ - unit_add_to_dbus_queue(u); -} - -static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Socket *s = SOCKET(u); - - assert(s); - assert(elapsed == 1); - assert(w == &s->timer_watch); - - switch (s->state) { - - case SOCKET_START_PRE: - log_warning("%s starting timed out. Terminating.", u->meta.id); - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); - break; - - case SOCKET_START_POST: - log_warning("%s starting timed out. Stopping.", u->meta.id); - socket_enter_stop_pre(s, false); - break; - - case SOCKET_STOP_PRE: - log_warning("%s stopping timed out. Terminating.", u->meta.id); - socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, false); - break; - - case SOCKET_STOP_PRE_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out. Killing.", u->meta.id); - socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false); - } else { - log_warning("%s stopping timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - socket_enter_stop_post(s, false); - } - break; - - case SOCKET_STOP_PRE_SIGKILL: - log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id); - socket_enter_stop_post(s, false); - break; - - case SOCKET_STOP_POST: - log_warning("%s stopping timed out (2). Terminating.", u->meta.id); - socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false); - break; - - case SOCKET_FINAL_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out (2). Killing.", u->meta.id); - socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false); - } else { - log_warning("%s stopping timed out (2). Skipping SIGKILL. Ignoring.", u->meta.id); - socket_enter_dead(s, false); - } - break; - - case SOCKET_FINAL_SIGKILL: - log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->meta.id); - socket_enter_dead(s, false); - break; - - default: - assert_not_reached("Timeout at wrong time."); - } -} - -int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { - int *rfds; - unsigned rn_fds, k; - SocketPort *p; - - assert(s); - assert(fds); - assert(n_fds); - - /* Called from the service code for requesting our fds */ - - rn_fds = 0; - LIST_FOREACH(port, p, s->ports) - if (p->fd >= 0) - rn_fds++; - - if (rn_fds <= 0) { - *fds = NULL; - *n_fds = 0; - return 0; - } - - if (!(rfds = new(int, rn_fds))) - return -ENOMEM; - - k = 0; - LIST_FOREACH(port, p, s->ports) - if (p->fd >= 0) - rfds[k++] = p->fd; - - assert(k == rn_fds); - - *fds = rfds; - *n_fds = rn_fds; - - return 0; -} - -void socket_notify_service_dead(Socket *s) { - assert(s); - - /* The service is dead. Dang! - * - * This is strictly for one-instance-for-all-connections - * services. */ - - if (s->state == SOCKET_RUNNING) { - log_debug("%s got notified about service death.", s->meta.id); - socket_enter_listening(s); - } -} - -void socket_connection_unref(Socket *s) { - assert(s); - - /* The service is dead. Yay! - * - * This is strictly for one-instance-per-connection - * services. */ - - assert(s->n_connections > 0); - s->n_connections--; - - log_debug("%s: One connection closed, %u left.", s->meta.id, s->n_connections); -} - -static void socket_reset_failed(Unit *u) { - Socket *s = SOCKET(u); - - assert(s); - - if (s->state == SOCKET_FAILED) - socket_set_state(s, SOCKET_DEAD); - - s->failure = false; -} - -static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { - Socket *s = SOCKET(u); - int r = 0; - Set *pid_set = NULL; - - assert(s); - - if (who == KILL_MAIN) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Socket units have no main processes"); - return -ESRCH; - } - - if (s->control_pid <= 0 && who == KILL_CONTROL) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); - return -ESRCH; - } - - if (who == KILL_CONTROL || who == KILL_ALL) - if (s->control_pid > 0) - if (kill(s->control_pid, signo) < 0) - r = -errno; - - if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) { - int q; - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - /* Exclude the control pid from being killed via the cgroup */ - if (s->control_pid > 0) - if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) { - r = q; - goto finish; - } - - if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - } - -finish: - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const socket_state_table[_SOCKET_STATE_MAX] = { - [SOCKET_DEAD] = "dead", - [SOCKET_START_PRE] = "start-pre", - [SOCKET_START_POST] = "start-post", - [SOCKET_LISTENING] = "listening", - [SOCKET_RUNNING] = "running", - [SOCKET_STOP_PRE] = "stop-pre", - [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", - [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", - [SOCKET_STOP_POST] = "stop-post", - [SOCKET_FINAL_SIGTERM] = "final-sigterm", - [SOCKET_FINAL_SIGKILL] = "final-sigkill", - [SOCKET_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); - -static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { - [SOCKET_EXEC_START_PRE] = "StartPre", - [SOCKET_EXEC_START_POST] = "StartPost", - [SOCKET_EXEC_STOP_PRE] = "StopPre", - [SOCKET_EXEC_STOP_POST] = "StopPost" -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); - -const UnitVTable socket_vtable = { - .suffix = ".socket", - .sections = - "Unit\0" - "Socket\0" - "Install\0", - - .init = socket_init, - .done = socket_done, - .load = socket_load, - - .kill = socket_kill, - - .coldplug = socket_coldplug, - - .dump = socket_dump, - - .start = socket_start, - .stop = socket_stop, - - .serialize = socket_serialize, - .deserialize_item = socket_deserialize_item, - - .active_state = socket_active_state, - .sub_state_to_string = socket_sub_state_to_string, - - .check_gc = socket_check_gc, - - .fd_event = socket_fd_event, - .sigchld_event = socket_sigchld_event, - .timer_event = socket_timer_event, - - .reset_failed = socket_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Socket", - .bus_message_handler = bus_socket_message_handler, - .bus_invalidating_properties = bus_socket_invalidating_properties -}; diff --git a/src/socket.h b/src/socket.h deleted file mode 100644 index fd13ac4..0000000 --- a/src/socket.h +++ /dev/null @@ -1,155 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosockethfoo -#define foosockethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Socket Socket; - -#include "manager.h" -#include "unit.h" -#include "socket-util.h" -#include "mount.h" - -typedef enum SocketState { - SOCKET_DEAD, - SOCKET_START_PRE, - SOCKET_START_POST, - SOCKET_LISTENING, - SOCKET_RUNNING, - SOCKET_STOP_PRE, - SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL, - SOCKET_STOP_POST, - SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL, - SOCKET_FAILED, - _SOCKET_STATE_MAX, - _SOCKET_STATE_INVALID = -1 -} SocketState; - -typedef enum SocketExecCommand { - SOCKET_EXEC_START_PRE, - SOCKET_EXEC_START_POST, - SOCKET_EXEC_STOP_PRE, - SOCKET_EXEC_STOP_POST, - _SOCKET_EXEC_COMMAND_MAX, - _SOCKET_EXEC_COMMAND_INVALID = -1 -} SocketExecCommand; - -typedef enum SocketType { - SOCKET_SOCKET, - SOCKET_FIFO, - SOCKET_SPECIAL, - SOCKET_MQUEUE, - _SOCKET_FIFO_MAX, - _SOCKET_FIFO_INVALID = -1 -} SocketType; - -typedef struct SocketPort { - SocketType type; - int fd; - - SocketAddress address; - char *path; - Watch fd_watch; - - LIST_FIELDS(struct SocketPort, port); -} SocketPort; - -struct Socket { - Meta meta; - - LIST_HEAD(SocketPort, ports); - - unsigned n_accepted; - unsigned n_connections; - unsigned max_connections; - - unsigned backlog; - usec_t timeout_usec; - - ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX]; - ExecContext exec_context; - - /* For Accept=no sockets refers to the one service we'll - activate. For Accept=yes sockets is either NULL, or filled - when the next service we spawn. */ - Service *service; - - SocketState state, deserialized_state; - - Watch timer_watch; - - ExecCommand* control_command; - SocketExecCommand control_command_id; - pid_t control_pid; - - /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */ - SocketAddressBindIPv6Only bind_ipv6_only; - - mode_t directory_mode; - mode_t socket_mode; - - bool failure; - - bool accept; - - /* Socket options */ - bool keep_alive; - bool free_bind; - bool transparent; - bool broadcast; - int priority; - int mark; - size_t receive_buffer; - size_t send_buffer; - int ip_tos; - int ip_ttl; - size_t pipe_size; - char *bind_to_device; - char *tcp_congestion; - long mq_maxmsg; - long mq_msgsize; -}; - -/* Called from the service code when collecting fds */ -int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds); - -/* Called from the service when it shut down */ -void socket_notify_service_dead(Socket *s); - -/* Called from the mount code figure out if a mount is a dependency of - * any of the sockets of this socket */ -int socket_add_one_mount_link(Socket *s, Mount *m); - -/* Called from the service code when a per-connection service ended */ -void socket_connection_unref(Socket *s); - -extern const UnitVTable socket_vtable; - -const char* socket_state_to_string(SocketState i); -SocketState socket_state_from_string(const char *s); - -const char* socket_exec_command_to_string(SocketExecCommand i); -SocketExecCommand socket_exec_command_from_string(const char *s); - -#endif diff --git a/src/spawn-agent.c b/src/spawn-agent.c deleted file mode 100644 index 2de2530..0000000 --- a/src/spawn-agent.c +++ /dev/null @@ -1,120 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "spawn-agent.h" - -static pid_t agent_pid = 0; - -void agent_open(void) { - pid_t parent_pid; - - if (agent_pid > 0) - return; - - /* We check STDIN here, not STDOUT, since this is about input, - * not output */ - if (!isatty(STDIN_FILENO)) - return; - - parent_pid = getpid(); - - /* Spawns a temporary TTY agent, making sure it goes away when - * we go away */ - - agent_pid = fork(); - if (agent_pid < 0) { - log_error("Failed to fork agent: %m"); - return; - } - - if (agent_pid == 0) { - /* In the child */ - - int fd; - bool stdout_is_tty, stderr_is_tty; - - /* Make sure the agent goes away when the parent dies */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - _exit(EXIT_FAILURE); - - /* Check whether our parent died before we were able - * to set the death signal */ - if (getppid() != parent_pid) - _exit(EXIT_SUCCESS); - - /* Don't leak fds to the agent */ - close_all_fds(NULL, 0); - - stdout_is_tty = isatty(STDOUT_FILENO); - stderr_is_tty = isatty(STDERR_FILENO); - - if (!stdout_is_tty || !stderr_is_tty) { - /* Detach from stdout/stderr. and reopen - * /dev/tty for them. This is important to - * ensure that when systemctl is started via - * popen() or a similar call that expects to - * read EOF we actually do generate EOF and - * not delay this indefinitely by because we - * keep an unused copy of stdin around. */ - fd = open("/dev/tty", O_WRONLY); - if (fd < 0) { - log_error("Failed to open /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - if (!stdout_is_tty) - dup2(fd, STDOUT_FILENO); - - if (!stderr_is_tty) - dup2(fd, STDERR_FILENO); - - if (fd > 2) - close(fd); - } - - execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL); - - log_error("Unable to execute agent: %m"); - _exit(EXIT_FAILURE); - } -} - -void agent_close(void) { - - if (agent_pid <= 0) - return; - - /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); - wait_for_terminate(agent_pid, NULL); - agent_pid = 0; -} diff --git a/src/spawn-agent.h b/src/spawn-agent.h deleted file mode 100644 index fd0a910..0000000 --- a/src/spawn-agent.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foospawnagenthfoo -#define foospawnagenthfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -void agent_open(void); -void agent_close(void); - -#endif diff --git a/src/special.h b/src/special.h deleted file mode 100644 index 3fe34c9..0000000 --- a/src/special.h +++ /dev/null @@ -1,88 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foospecialhfoo -#define foospecialhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#define SPECIAL_DEFAULT_TARGET "default.target" - -/* Shutdown targets */ -#define SPECIAL_UMOUNT_TARGET "umount.target" -/* This is not really intended to be started by directly. This is - * mostly so that other targets (reboot/halt/poweroff) can depend on - * it to bring all services down that want to be brought down on - * system shutdown. */ -#define SPECIAL_SHUTDOWN_TARGET "shutdown.target" -#define SPECIAL_HALT_TARGET "halt.target" -#define SPECIAL_POWEROFF_TARGET "poweroff.target" -#define SPECIAL_REBOOT_TARGET "reboot.target" -#define SPECIAL_KEXEC_TARGET "kexec.target" -#define SPECIAL_EXIT_TARGET "exit.target" - -/* Special boot targets */ -#define SPECIAL_RESCUE_TARGET "rescue.target" -#define SPECIAL_EMERGENCY_TARGET "emergency.target" - -/* Early boot targets */ -#define SPECIAL_SYSINIT_TARGET "sysinit.target" -#define SPECIAL_SOCKETS_TARGET "sockets.target" -#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" /* LSB's $local_fs */ -#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target" -#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */ -#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target" -#define SPECIAL_SWAP_TARGET "swap.target" -#define SPECIAL_BASIC_TARGET "basic.target" - -/* LSB compatibility */ -#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */ -#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target" /* LSB's $named */ -#define SPECIAL_RPCBIND_TARGET "rpcbind.target" /* LSB's $portmap */ -#define SPECIAL_SYSLOG_TARGET "syslog.target" /* LSB's $syslog; Should pull in syslog.socket or syslog.service */ -#define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */ -#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service" /* Debian's $x-display-manager */ -#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Debian's $mail-{transport|transfer-agent */ -#define SPECIAL_HTTP_DAEMON_TARGET "http-daemon.target" - -/* Magic early boot services */ -#define SPECIAL_FSCK_SERVICE "fsck@.service" -#define SPECIAL_QUOTACHECK_SERVICE "quotacheck.service" -#define SPECIAL_QUOTAON_SERVICE "quotaon.service" -#define SPECIAL_REMOUNT_ROOTFS_SERVICE "remount-rootfs.service" - -/* Services systemd relies on */ -#define SPECIAL_DBUS_SERVICE "dbus.service" -#define SPECIAL_DBUS_SOCKET "dbus.socket" -#define SPECIAL_STDOUT_SYSLOG_BRIDGE_SOCKET "systemd-stdout-syslog-bridge.socket" -#define SPECIAL_SYSLOG_SOCKET "syslog.socket" - -/* Magic init signals */ -#define SPECIAL_KBREQUEST_TARGET "kbrequest.target" -#define SPECIAL_SIGPWR_TARGET "sigpwr.target" -#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target" - -/* For SysV compatibility. Usually an alias for a saner target. On - * SysV-free systems this doesn't exist. */ -#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target" -#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target" -#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target" -#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target" - -#endif diff --git a/src/specifier.c b/src/specifier.c deleted file mode 100644 index a9fff88..0000000 --- a/src/specifier.c +++ /dev/null @@ -1,108 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "macro.h" -#include "util.h" -#include "specifier.h" - -/* - * Generic infrastructure for replacing %x style specifiers in - * strings. Will call a callback for each replacement. - * - */ - -char *specifier_printf(const char *text, const Specifier table[], void *userdata) { - char *r, *t; - const char *f; - bool percent = false; - size_t l; - - assert(text); - assert(table); - - l = strlen(text); - if (!(r = new(char, l+1))) - return NULL; - - t = r; - - for (f = text; *f; f++, l--) { - - if (percent) { - if (*f == '%') - *(t++) = '%'; - else { - const Specifier *i; - - for (i = table; i->specifier; i++) - if (i->specifier == *f) - break; - - if (i->lookup) { - char *n, *w; - size_t k, j; - - if (!(w = i->lookup(i->specifier, i->data, userdata))) { - free(r); - return NULL; - } - - j = t - r; - k = strlen(w); - - if (!(n = new(char, j + k + l + 1))) { - free(r); - free(w); - return NULL; - } - - memcpy(n, r, j); - memcpy(n + j, w, k); - - free(r); - free(w); - - r = n; - t = n + j + k; - } else { - *(t++) = '%'; - *(t++) = *f; - } - } - - percent = false; - } else if (*f == '%') - percent = true; - else - *(t++) = *f; - } - - *t = 0; - return r; -} - -/* Generic handler for simple string replacements */ - -char* specifier_string(char specifier, void *data, void *userdata) { - return strdup(strempty(data)); -} diff --git a/src/specifier.h b/src/specifier.h deleted file mode 100644 index 041166c..0000000 --- a/src/specifier.h +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foospecifierhfoo -#define foospecifierhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata); - -typedef struct Specifier { - const char specifier; - const SpecifierCallback lookup; - void *data; -} Specifier; - -char *specifier_printf(const char *text, const Specifier table[], void *userdata); - -char* specifier_string(char specifier, void *data, void *userdata); - -#endif diff --git a/src/stdout-syslog-bridge.c b/src/stdout-syslog-bridge.c deleted file mode 100644 index 721817f..0000000 --- a/src/stdout-syslog-bridge.c +++ /dev/null @@ -1,710 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "log.h" -#include "list.h" -#include "sd-daemon.h" -#include "tcpwrap.h" -#include "def.h" - -#define STREAMS_MAX 4096 -#define SERVER_FD_MAX 16 -#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) - -typedef struct Stream Stream; - -typedef struct Server { - int syslog_fd; - int kmsg_fd; - int epoll_fd; - - unsigned n_server_fd; - - bool syslog_is_stream; - - LIST_HEAD(Stream, streams); - unsigned n_streams; -} Server; - -typedef enum StreamTarget { - STREAM_SYSLOG, - STREAM_KMSG -} StreamTarget; - -typedef enum StreamState { - STREAM_TARGET, - STREAM_PRIORITY, - STREAM_PROCESS, - STREAM_PREFIX, - STREAM_RUNNING -} StreamState; - -struct Stream { - Server *server; - - StreamState state; - - int fd; - - StreamTarget target; - int priority; - char *process; - pid_t pid; - uid_t uid; - gid_t gid; - - bool prefix:1; - bool tee_console:1; - - char buffer[LINE_MAX+1]; - size_t length; - - LIST_FIELDS(Stream, stream); -}; - -static int stream_log(Stream *s, char *p, usec_t ts) { - - char header_priority[16], header_time[64], header_pid[16]; - struct iovec iovec[5]; - int priority; - - assert(s); - assert(p); - - priority = s->priority; - - if (s->prefix) - parse_syslog_priority(&p, &priority); - - if (*p == 0) - return 0; - - /* Patch in configured facility if necessary */ - if ((priority & LOG_FACMASK) == 0) - priority = (s->priority & LOG_FACMASK) | priority; - - /* - * The format glibc uses to talk to the syslog daemon is: - * - * time process[pid]: msg - * - * The format the kernel uses is: - * - * msg\n - * - * We extend the latter to include the process name and pid. - */ - - snprintf(header_priority, sizeof(header_priority), "<%i>", priority); - char_array_0(header_priority); - - if (s->target == STREAM_SYSLOG) { - time_t t; - struct tm *tm; - - t = (time_t) (ts / USEC_PER_SEC); - if (!(tm = localtime(&t))) - return -EINVAL; - - if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) - return -EINVAL; - } - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) s->pid); - char_array_0(header_pid); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header_priority); - - if (s->target == STREAM_SYSLOG) { - struct msghdr msghdr; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - struct ucred *ucred; - - zero(control); - control.cmsghdr.cmsg_level = SOL_SOCKET; - control.cmsghdr.cmsg_type = SCM_CREDENTIALS; - control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - ucred->pid = s->pid; - ucred->uid = s->uid; - ucred->gid = s->gid; - - IOVEC_SET_STRING(iovec[1], header_time); - IOVEC_SET_STRING(iovec[2], s->process); - IOVEC_SET_STRING(iovec[3], header_pid); - IOVEC_SET_STRING(iovec[4], p); - - /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ - if (s->server->syslog_is_stream) - iovec[4].iov_len++; - - zero(msghdr); - msghdr.msg_iov = iovec; - msghdr.msg_iovlen = ELEMENTSOF(iovec); - msghdr.msg_control = &control; - msghdr.msg_controllen = control.cmsghdr.cmsg_len; - - for (;;) { - ssize_t n; - - if ((n = sendmsg(s->server->syslog_fd, &msghdr, MSG_NOSIGNAL)) < 0) { - - if (errno == ESRCH) { - pid_t our_pid; - - /* Hmm, maybe the process this - * line originates from is - * dead? Then let's patch in - * our own pid and retry, - * since we have nothing - * better */ - - our_pid = getpid(); - - if (ucred->pid != our_pid) { - ucred->pid = our_pid; - continue; - } - } - - return -errno; - } - - if (!s->server->syslog_is_stream || - (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) - break; - - IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); - } - - } else if (s->target == STREAM_KMSG) { - IOVEC_SET_STRING(iovec[1], s->process); - IOVEC_SET_STRING(iovec[2], header_pid); - IOVEC_SET_STRING(iovec[3], p); - IOVEC_SET_STRING(iovec[4], (char*) "\n"); - - if (writev(s->server->kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) - return -errno; - } else - assert_not_reached("Unknown log target"); - - if (s->tee_console) { - int console; - - if ((console = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) >= 0) { - IOVEC_SET_STRING(iovec[0], s->process); - IOVEC_SET_STRING(iovec[1], header_pid); - IOVEC_SET_STRING(iovec[2], p); - IOVEC_SET_STRING(iovec[3], (char*) "\n"); - - writev(console, iovec, 4); - } - - } - - return 0; -} - -static int stream_line(Stream *s, char *p, usec_t ts) { - int r; - - assert(s); - assert(p); - - p = strstrip(p); - - switch (s->state) { - - case STREAM_TARGET: - if (streq(p, "syslog") || streq(p, "syslog+console")) - s->target = STREAM_SYSLOG; - else if (streq(p, "kmsg") || streq(p, "kmsg+console")) { - - if (s->server->kmsg_fd >= 0 && s->uid == 0) - s->target = STREAM_KMSG; - else { - log_warning("/dev/kmsg logging not available."); - return -EPERM; - } - } else { - log_warning("Failed to parse log target line."); - return -EBADMSG; - } - - if (endswith(p, "+console")) - s->tee_console = true; - - s->state = STREAM_PRIORITY; - return 0; - - case STREAM_PRIORITY: - if ((r = safe_atoi(p, &s->priority)) < 0) { - log_warning("Failed to parse log priority line: %m"); - return r; - } - - if (s->priority < 0) { - log_warning("Log priority negative: %m"); - return -ERANGE; - } - - s->state = STREAM_PROCESS; - return 0; - - case STREAM_PROCESS: - if (!(s->process = strdup(p))) - return -ENOMEM; - - s->state = STREAM_PREFIX; - return 0; - - case STREAM_PREFIX: - - if ((r = parse_boolean(p)) < 0) - return r; - - s->prefix = r; - s->state = STREAM_RUNNING; - return 0; - - case STREAM_RUNNING: - return stream_log(s, p, ts); - } - - assert_not_reached("Unknown stream state"); -} - -static int stream_scan(Stream *s, usec_t ts) { - char *p; - size_t remaining; - int r = 0; - - assert(s); - - p = s->buffer; - remaining = s->length; - for (;;) { - char *end; - size_t skip; - - end = memchr(p, '\n', remaining); - if (!end) { - if (remaining >= LINE_MAX) { - end = p + LINE_MAX; - skip = LINE_MAX; - } else - break; - } else - skip = end - p + 1; - - *end = 0; - - r = stream_line(s, p, ts); - if (r >= 0) { - remaining -= skip; - p += skip; - } - } - - if (p > s->buffer) { - memmove(s->buffer, p, remaining); - s->length = remaining; - } - - return r; -} - -static int stream_process(Stream *s, usec_t ts) { - ssize_t l; - int r; - assert(s); - - l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length); - if (l < 0) { - - if (errno == EAGAIN) - return 0; - - log_warning("Failed to read from stream: %m"); - return -errno; - } - - - if (l == 0) - return 0; - - s->length += l; - r = stream_scan(s, ts); - - if (r < 0) - return r; - - return 1; -} - -static void stream_free(Stream *s) { - assert(s); - - if (s->server) { - assert(s->server->n_streams > 0); - s->server->n_streams--; - LIST_REMOVE(Stream, stream, s->server->streams, s); - - } - - if (s->fd >= 0) { - if (s->server) - epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL); - - close_nointr_nofail(s->fd); - } - - free(s->process); - free(s); -} - -static int stream_new(Server *s, int server_fd) { - Stream *stream; - int fd; - struct ucred ucred; - socklen_t len = sizeof(ucred); - struct epoll_event ev; - int r; - - assert(s); - - if ((fd = accept(server_fd, NULL, NULL)) < 0) - return -errno; - - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) - return -errno; - - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - return -errno; - - if (s->n_streams >= STREAMS_MAX) { - log_warning("Too many connections, refusing connection."); - close_nointr_nofail(fd); - return 0; - } - - if (!socket_tcpwrap(fd, "systemd-stdout-syslog-bridge")) { - close_nointr_nofail(fd); - return 0; - } - - if (!(stream = new0(Stream, 1))) { - close_nointr_nofail(fd); - return -ENOMEM; - } - - stream->fd = fd; - - if (getsockopt(stream->fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { - r = -errno; - goto fail; - } - - if (shutdown(fd, SHUT_WR) < 0) { - r = -errno; - goto fail; - } - - zero(ev); - ev.data.ptr = stream; - ev.events = EPOLLIN; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - goto fail; - } - - stream->pid = ucred.pid; - stream->uid = ucred.uid; - stream->gid = ucred.gid; - - stream->server = s; - LIST_PREPEND(Stream, stream, s->streams, stream); - s->n_streams ++; - - return 0; - -fail: - stream_free(stream); - return r; -} - -static void server_done(Server *s) { - unsigned i; - assert(s); - - while (s->streams) - stream_free(s->streams); - - for (i = 0; i < s->n_server_fd; i++) - close_nointr_nofail(SD_LISTEN_FDS_START+i); - - if (s->syslog_fd >= 0) - close_nointr_nofail(s->syslog_fd); - - if (s->epoll_fd >= 0) - close_nointr_nofail(s->epoll_fd); - - if (s->kmsg_fd >= 0) - close_nointr_nofail(s->kmsg_fd); -} - -static int server_init(Server *s, unsigned n_sockets) { - int r; - unsigned i; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - - assert(s); - assert(n_sockets > 0); - - zero(*s); - - s->n_server_fd = n_sockets; - s->syslog_fd = -1; - s->kmsg_fd = -1; - - if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) { - r = -errno; - log_error("Failed to create epoll object: %m"); - goto fail; - } - - for (i = 0; i < n_sockets; i++) { - struct epoll_event ev; - int fd; - - fd = SD_LISTEN_FDS_START+i; - - if ((r = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1)) < 0) { - log_error("Failed to determine file descriptor type: %s", strerror(-r)); - goto fail; - } - - if (!r) { - log_error("Wrong file descriptor type."); - r = -EINVAL; - goto fail; - } - - /* We use ev.data.ptr instead of ev.data.fd here, - * since on 64bit archs fd is 32bit while a pointer is - * 64bit. To make sure we can easily distinguish fd - * values and pointer values we want to make sure to - * write the full field unconditionally. */ - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = INT_TO_PTR(fd); - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - log_error("Failed to add server fd to epoll object: %m"); - goto fail; - } - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); - - if ((s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { - r = -errno; - log_error("Failed to create log fd: %m"); - goto fail; - } - - if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) { - close_nointr_nofail(s->syslog_fd); - - if ((s->syslog_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) < 0) { - r = -errno; - log_error("Failed to create log fd: %m"); - goto fail; - } - - if (connect(s->syslog_fd, &sa.sa, sizeof(sa)) < 0) { - r = -errno; - log_error("Failed to connect log socket to /dev/log: %m"); - goto fail; - } - - s->syslog_is_stream = true; - } else - s->syslog_is_stream = false; - - /* /dev/kmsg logging is strictly optional */ - if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) - log_warning("Failed to open /dev/kmsg for logging, disabling kernel log buffer support: %m"); - - return 0; - -fail: - server_done(s); - return r; -} - -static int process_event(Server *s, struct epoll_event *ev) { - int r; - - assert(s); - - /* Yes, this is a bit ugly, we assume that that valid pointers - * are > SD_LISTEN_FDS_START+SERVER_FD_MAX. Which is certainly - * true on Linux (and probably most other OSes, too, since the - * first 4k usually are part of a separate null pointer - * dereference page. */ - - if (PTR_TO_INT(ev->data.ptr) >= SD_LISTEN_FDS_START && - PTR_TO_INT(ev->data.ptr) < SD_LISTEN_FDS_START+(int)s->n_server_fd) { - - if (ev->events != EPOLLIN) { - log_info("Got invalid event from epoll. (1)"); - return -EIO; - } - - if ((r = stream_new(s, PTR_TO_INT(ev->data.ptr))) < 0) { - log_info("Failed to accept new connection: %s", strerror(-r)); - return r; - } - - } else { - usec_t ts; - Stream *stream = ev->data.ptr; - - ts = now(CLOCK_REALTIME); - - if (!(ev->events & EPOLLIN)) { - log_info("Got invalid event from epoll. (2)"); - stream_free(stream); - return 0; - } - - if ((r = stream_process(stream, ts)) <= 0) { - - if (r < 0) - log_info("Got error on stream: %s", strerror(-r)); - - stream_free(stream); - return 0; - } - } - - return 0; -} - -int main(int argc, char *argv[]) { - Server server; - int r = EXIT_FAILURE, n; - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc > 1) { - log_error("This program does not take arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((n = sd_listen_fds(true)) < 0) { - log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (n <= 0 || n > SERVER_FD_MAX) { - log_error("No or too many file descriptors passed."); - return EXIT_FAILURE; - } - - if (server_init(&server, (unsigned) n) < 0) - return EXIT_FAILURE; - - log_debug("systemd-stdout-syslog-bridge running as pid %lu", (unsigned long) getpid()); - - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - - for (;;) { - struct epoll_event event; - int k; - - if ((k = epoll_wait(server.epoll_fd, - &event, 1, - server.n_streams <= 0 ? TIMEOUT_MSEC : -1)) < 0) { - - if (errno == EINTR) - continue; - - log_error("epoll_wait() failed: %m"); - goto fail; - } - - if (k <= 0) - break; - - if (process_event(&server, &event) < 0) - goto fail; - } - - r = EXIT_SUCCESS; - - log_debug("systemd-stdout-syslog-bridge stopped as pid %lu", (unsigned long) getpid()); - -fail: - sd_notify(false, - "STATUS=Shutting down..."); - - server_done(&server); - - return r; -} diff --git a/src/strv.c b/src/strv.c deleted file mode 100644 index bb309d9..0000000 --- a/src/strv.c +++ /dev/null @@ -1,690 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" - -char *strv_find(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (streq(*i, name)) - return *i; - - return NULL; -} - -char *strv_find_prefix(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (startswith(*i, name)) - return *i; - - return NULL; -} - -void strv_free(char **l) { - char **k; - - if (!l) - return; - - for (k = l; *k; k++) - free(*k); - - free(l); -} - -char **strv_copy(char **l) { - char **r, **k; - - k = r = new(char*, strv_length(l)+1); - if (!k) - return NULL; - - if (l) - for (; *l; k++, l++) - if (!(*k = strdup(*l))) - goto fail; - - *k = NULL; - return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; -} - -unsigned strv_length(char **l) { - unsigned n = 0; - - if (!l) - return 0; - - for (; *l; l++) - n++; - - return n; -} - -char **strv_new_ap(const char *x, va_list ap) { - const char *s; - char **a; - unsigned n = 0, i = 0; - va_list aq; - - if (x) { - n = 1; - - va_copy(aq, ap); - while (va_arg(aq, const char*)) - n++; - va_end(aq); - } - - if (!(a = new(char*, n+1))) - return NULL; - - if (x) { - if (!(a[i] = strdup(x))) { - free(a); - return NULL; - } - - i++; - - while ((s = va_arg(ap, const char*))) { - if (!(a[i] = strdup(s))) - goto fail; - - i++; - } - } - - a[i] = NULL; - - return a; - -fail: - - for (; i > 0; i--) - if (a[i-1]) - free(a[i-1]); - - free(a); - - return NULL; -} - -char **strv_new(const char *x, ...) { - char **r; - va_list ap; - - va_start(ap, x); - r = strv_new_ap(x, ap); - va_end(ap); - - return r; -} - -char **strv_merge(char **a, char **b) { - char **r, **k; - - if (!a) - return strv_copy(b); - - if (!b) - return strv_copy(a); - - if (!(r = new(char*, strv_length(a)+strv_length(b)+1))) - return NULL; - - for (k = r; *a; k++, a++) - if (!(*k = strdup(*a))) - goto fail; - for (; *b; k++, b++) - if (!(*k = strdup(*b))) - goto fail; - - *k = NULL; - return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; -} - -char **strv_merge_concat(char **a, char **b, const char *suffix) { - char **r, **k; - - /* Like strv_merge(), but appends suffix to all strings in b, before adding */ - - if (!b) - return strv_copy(a); - - r = new(char*, strv_length(a) + strv_length(b) + 1); - if (!r) - return NULL; - - k = r; - if (a) - for (; *a; k++, a++) { - *k = strdup(*a); - if (!*k) - goto fail; - } - - for (; *b; k++, b++) { - *k = strappend(*b, suffix); - if (!*k) - goto fail; - } - - *k = NULL; - return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; - -} - -char **strv_split(const char *s, const char *separator) { - char *state; - char *w; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_SEPARATOR(w, l, s, separator, state) - n++; - - if (!(r = new(char*, n+1))) - return NULL; - - i = 0; - FOREACH_WORD_SEPARATOR(w, l, s, separator, state) - if (!(r[i++] = strndup(w, l))) { - strv_free(r); - return NULL; - } - - r[i] = NULL; - return r; -} - -char **strv_split_quoted(const char *s) { - char *state; - char *w; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_QUOTED(w, l, s, state) - n++; - - if (!(r = new(char*, n+1))) - return NULL; - - i = 0; - FOREACH_WORD_QUOTED(w, l, s, state) - if (!(r[i++] = cunescape_length(w, l))) { - strv_free(r); - return NULL; - } - - r[i] = NULL; - return r; -} - -char *strv_join(char **l, const char *separator) { - char *r, *e; - char **s; - size_t n, k; - - if (!separator) - separator = " "; - - k = strlen(separator); - - n = 0; - STRV_FOREACH(s, l) { - if (n != 0) - n += k; - n += strlen(*s); - } - - if (!(r = new(char, n+1))) - return NULL; - - e = r; - STRV_FOREACH(s, l) { - if (e != r) - e = stpcpy(e, separator); - - e = stpcpy(e, *s); - } - - *e = 0; - - return r; -} - -char **strv_append(char **l, const char *s) { - char **r, **k; - - if (!l) - return strv_new(s, NULL); - - if (!s) - return strv_copy(l); - - r = new(char*, strv_length(l)+2); - if (!r) - return NULL; - - for (k = r; *l; k++, l++) - if (!(*k = strdup(*l))) - goto fail; - - if (!(*(k++) = strdup(s))) - goto fail; - - *k = NULL; - return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; -} - -char **strv_uniq(char **l) { - char **i; - - /* Drops duplicate entries. The first identical string will be - * kept, the others dropped */ - - STRV_FOREACH(i, l) - strv_remove(i+1, *i); - - return l; -} - -char **strv_remove(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of s in the string list, edits - * in-place. */ - - for (f = t = l; *f; f++) { - - if (streq(*f, s)) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -static int env_append(char **r, char ***k, char **a) { - assert(r); - assert(k); - - if (!a) - return 0; - - /* Add the entries of a to *k unless they already exist in *r - * in which case they are overridden instead. This assumes - * there is enough space in the r array. */ - - for (; *a; a++) { - char **j; - size_t n; - - n = strcspn(*a, "="); - - if ((*a)[n] == '=') - n++; - - for (j = r; j < *k; j++) - if (strncmp(*j, *a, n) == 0) - break; - - if (j >= *k) - (*k)++; - else - free(*j); - - if (!(*j = strdup(*a))) - return -ENOMEM; - } - - return 0; -} - -char **strv_env_merge(unsigned n_lists, ...) { - size_t n = 0; - char **l, **k, **r; - va_list ap; - unsigned i; - - /* Merges an arbitrary number of environment sets */ - - va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { - l = va_arg(ap, char**); - n += strv_length(l); - } - va_end(ap); - - if (!(r = new(char*, n+1))) - return NULL; - - k = r; - - va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { - l = va_arg(ap, char**); - if (env_append(r, &k, l) < 0) - goto fail; - } - va_end(ap); - - *k = NULL; - - return r; - -fail: - va_end(ap); - - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; -} - -static bool env_match(const char *t, const char *pattern) { - assert(t); - assert(pattern); - - /* pattern a matches string a - * a matches a= - * a matches a=b - * a= matches a= - * a=b matches a=b - * a= does not match a - * a=b does not match a= - * a=b does not match a - * a=b does not match a=c */ - - if (streq(t, pattern)) - return true; - - if (!strchr(pattern, '=')) { - size_t l = strlen(pattern); - - return strncmp(t, pattern, l) == 0 && t[l] == '='; - } - - return false; -} - -char **strv_env_delete(char **x, unsigned n_lists, ...) { - size_t n, i = 0; - char **k, **r; - va_list ap; - - /* Deletes every entry from x that is mentioned in the other - * string lists */ - - n = strv_length(x); - - r = new(char*, n+1); - if (!r) - return NULL; - - STRV_FOREACH(k, x) { - unsigned v; - - va_start(ap, n_lists); - for (v = 0; v < n_lists; v++) { - char **l, **j; - - l = va_arg(ap, char**); - STRV_FOREACH(j, l) - if (env_match(*k, *j)) - goto skip; - } - va_end(ap); - - r[i] = strdup(*k); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - continue; - - skip: - va_end(ap); - } - - r[i] = NULL; - - assert(i <= n); - - return r; -} - -char **strv_env_unset(char **l, const char *p) { - - char **f, **t; - - if (!l) - return NULL; - - assert(p); - - /* Drops every occurrence of the env var setting p in the - * string list. edits in-place. */ - - for (f = t = l; *f; f++) { - - if (env_match(*f, p)) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -char **strv_env_set(char **x, const char *p) { - - char **k, **r; - char* m[2] = { (char*) p, NULL }; - - /* Overrides the env var setting of p, returns a new copy */ - - if (!(r = new(char*, strv_length(x)+2))) - return NULL; - - k = r; - if (env_append(r, &k, x) < 0) - goto fail; - - if (env_append(r, &k, m) < 0) - goto fail; - - *k = NULL; - - return r; - -fail: - for (k--; k >= r; k--) - free(*k); - - free(r); - - return NULL; - -} - -char *strv_env_get_with_length(char **l, const char *name, size_t k) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (strncmp(*i, name, k) == 0 && - (*i)[k] == '=') - return *i + k + 1; - - return NULL; -} - -char *strv_env_get(char **l, const char *name) { - return strv_env_get_with_length(l, name, strlen(name)); -} - -char **strv_env_clean(char **l) { - char **r, **ret; - - for (r = ret = l; *l; l++) { - const char *equal; - - equal = strchr(*l, '='); - - if (equal && equal[1] == 0) { - free(*l); - continue; - } - - *(r++) = *l; - } - - *r = NULL; - - return ret; -} - -char **strv_parse_nulstr(const char *s, size_t l) { - const char *p; - unsigned c = 0, i = 0; - char **v; - - assert(s || l <= 0); - - if (l <= 0) - return strv_new(NULL, NULL); - - for (p = s; p < s + l; p++) - if (*p == 0) - c++; - - if (s[l-1] != 0) - c++; - - if (!(v = new0(char*, c+1))) - return NULL; - - p = s; - while (p < s + l) { - const char *e; - - e = memchr(p, 0, s + l - p); - - if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) { - strv_free(v); - return NULL; - } - - if (!e) - break; - - p = e + 1; - } - - assert(i == c); - - return v; -} - -bool strv_overlap(char **a, char **b) { - char **i, **j; - - STRV_FOREACH(i, a) { - STRV_FOREACH(j, b) { - if (streq(*i, *j)) - return true; - } - } - - return false; -} diff --git a/src/strv.h b/src/strv.h deleted file mode 100644 index d038c9f..0000000 --- a/src/strv.h +++ /dev/null @@ -1,79 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foostrvhfoo -#define foostrvhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "macro.h" - -char *strv_find(char **l, const char *name); -char *strv_find_prefix(char **l, const char *name); - -void strv_free(char **l); -char **strv_copy(char **l) _malloc_; -unsigned strv_length(char **l); - -char **strv_merge(char **a, char **b); -char **strv_merge_concat(char **a, char **b, const char *suffix); -char **strv_append(char **l, const char *s); - -char **strv_remove(char **l, const char *s); -char **strv_uniq(char **l); - -#define strv_contains(l, s) (!!strv_find((l), (s))) - -char **strv_new(const char *x, ...) _sentinel_ _malloc_; -char **strv_new_ap(const char *x, va_list ap) _malloc_; - -static inline bool strv_isempty(char **l) { - return !l || !*l; -} - -char **strv_split(const char *s, const char *separator) _malloc_; -char **strv_split_quoted(const char *s) _malloc_; - -char *strv_join(char **l, const char *separator) _malloc_; - -char **strv_env_merge(unsigned n_lists, ...); -char **strv_env_delete(char **x, unsigned n_lists, ...); - -char **strv_env_set(char **x, const char *p); -char **strv_env_unset(char **l, const char *p); - -char *strv_env_get_with_length(char **l, const char *name, size_t k); -char *strv_env_get(char **x, const char *n); - -char **strv_env_clean(char **l); - -char **strv_parse_nulstr(const char *s, size_t l); - -bool strv_overlap(char **a, char **b); - -#define STRV_FOREACH(s, l) \ - for ((s) = (l); (s) && *(s); (s)++) - -#define STRV_FOREACH_BACKWARDS(s, l) \ - for (; (l) && ((s) >= (l)); (s)--) - -#endif diff --git a/src/swap.c b/src/swap.c deleted file mode 100644 index 54a8640..0000000 --- a/src/swap.c +++ /dev/null @@ -1,1387 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "unit.h" -#include "swap.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "unit-name.h" -#include "dbus-swap.h" -#include "special.h" -#include "bus-errors.h" -#include "exit-status.h" -#include "def.h" - -static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { - [SWAP_DEAD] = UNIT_INACTIVE, - [SWAP_ACTIVATING] = UNIT_ACTIVATING, - [SWAP_ACTIVE] = UNIT_ACTIVE, - [SWAP_DEACTIVATING] = UNIT_DEACTIVATING, - [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING, - [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING, - [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING, - [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING, - [SWAP_FAILED] = UNIT_FAILED -}; - -static void swap_unset_proc_swaps(Swap *s) { - Swap *first; - - assert(s); - - if (!s->parameters_proc_swaps.what) - return; - - /* Remove this unit from the chain of swaps which share the - * same kernel swap device. */ - - first = hashmap_get(s->meta.manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what); - LIST_REMOVE(Swap, same_proc_swaps, first, s); - - if (first) - hashmap_remove_and_replace(s->meta.manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what, first->parameters_proc_swaps.what, first); - else - hashmap_remove(s->meta.manager->swaps_by_proc_swaps, s->parameters_proc_swaps.what); - - free(s->parameters_proc_swaps.what); - s->parameters_proc_swaps.what = NULL; -} - - static void swap_init(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - assert(s->meta.load_state == UNIT_STUB); - - s->timeout_usec = DEFAULT_TIMEOUT_USEC; - - exec_context_init(&s->exec_context); - s->exec_context.std_output = EXEC_OUTPUT_KMSG; - - s->parameters_etc_fstab.priority = s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1; - - s->timer_watch.type = WATCH_INVALID; - - s->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; - - s->meta.ignore_on_isolate = true; -} - -static void swap_unwatch_control_pid(Swap *s) { - assert(s); - - if (s->control_pid <= 0) - return; - - unit_unwatch_pid(UNIT(s), s->control_pid); - s->control_pid = 0; -} - -static void swap_done(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - - swap_unset_proc_swaps(s); - - free(s->what); - s->what = NULL; - - free(s->parameters_etc_fstab.what); - free(s->parameters_fragment.what); - s->parameters_etc_fstab.what = s->parameters_fragment.what = NULL; - - exec_context_done(&s->exec_context); - exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); - s->control_command = NULL; - - swap_unwatch_control_pid(s); - - unit_unwatch_timer(u, &s->timer_watch); -} - -int swap_add_one_mount_link(Swap *s, Mount *m) { - int r; - - assert(s); - assert(m); - - if (s->meta.load_state != UNIT_LOADED || - m->meta.load_state != UNIT_LOADED) - return 0; - - if (is_device_path(s->what)) - return 0; - - if (!path_startswith(s->what, m->where)) - return 0; - - if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0) - return r; - - return 0; -} - -static int swap_add_mount_links(Swap *s) { - Meta *other; - int r; - - assert(s); - - LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_MOUNT]) - if ((r = swap_add_one_mount_link(s, (Mount*) other)) < 0) - return r; - - return 0; -} - -static int swap_add_target_links(Swap *s) { - Unit *tu; - SwapParameters *p; - int r; - - assert(s); - - if (s->from_fragment) - p = &s->parameters_fragment; - else if (s->from_etc_fstab) - p = &s->parameters_etc_fstab; - else - return 0; - - if ((r = manager_load_unit(s->meta.manager, SPECIAL_SWAP_TARGET, NULL, NULL, &tu)) < 0) - return r; - - if (!p->noauto && - !p->nofail && - (p->handle || s->meta.manager->swap_auto) && - s->from_etc_fstab && - s->meta.manager->running_as == MANAGER_SYSTEM) - if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(s), true)) < 0) - return r; - - return unit_add_dependency(UNIT(s), UNIT_BEFORE, tu, true); -} - -static int swap_add_device_links(Swap *s) { - SwapParameters *p; - - assert(s); - - if (!s->what) - return 0; - - if (s->from_fragment) - p = &s->parameters_fragment; - else if (s->from_etc_fstab) - p = &s->parameters_etc_fstab; - else - return 0; - - if (is_device_path(s->what)) - return unit_add_node_link(UNIT(s), s->what, - !p->noauto && p->nofail && - s->meta.manager->running_as == MANAGER_SYSTEM); - else - /* File based swap devices need to be ordered after - * remount-rootfs.service, since they might need a - * writable file system. */ - return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_ROOTFS_SERVICE, NULL, true); -} - -static int swap_add_default_dependencies(Swap *s) { - int r; - - assert(s); - - if (s->meta.manager->running_as == MANAGER_SYSTEM) { - - if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0) - return r; - } - - return 0; -} - -static int swap_verify(Swap *s) { - bool b; - char *e; - - if (s->meta.load_state != UNIT_LOADED) - return 0; - - if (!(e = unit_name_from_path(s->what, ".swap"))) - return -ENOMEM; - - b = unit_has_name(UNIT(s), e); - free(e); - - if (!b) { - log_error("%s: Value of \"What\" and unit name do not match, not loading.\n", s->meta.id); - return -EINVAL; - } - - if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) { - log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", s->meta.id); - return -EINVAL; - } - - return 0; -} - -static int swap_load(Unit *u) { - int r; - Swap *s = SWAP(u); - - assert(s); - assert(u->meta.load_state == UNIT_STUB); - - /* Load a .swap file */ - if ((r = unit_load_fragment_and_dropin_optional(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_LOADED) { - if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) - return r; - - if (s->meta.fragment_path) - s->from_fragment = true; - - if (!s->what) { - if (s->parameters_fragment.what) - s->what = strdup(s->parameters_fragment.what); - else if (s->parameters_etc_fstab.what) - s->what = strdup(s->parameters_etc_fstab.what); - else if (s->parameters_proc_swaps.what) - s->what = strdup(s->parameters_proc_swaps.what); - else - s->what = unit_name_to_path(u->meta.id); - - if (!s->what) - return -ENOMEM; - } - - path_kill_slashes(s->what); - - if (!s->meta.description) - if ((r = unit_set_description(u, s->what)) < 0) - return r; - - if ((r = swap_add_device_links(s)) < 0) - return r; - - if ((r = swap_add_mount_links(s)) < 0) - return r; - - if ((r = swap_add_target_links(s)) < 0) - return r; - - if ((r = unit_add_default_cgroups(u)) < 0) - return r; - - if (s->meta.default_dependencies) - if ((r = swap_add_default_dependencies(s)) < 0) - return r; - } - - return swap_verify(s); -} - -int swap_add_one( - Manager *m, - const char *what, - const char *what_proc_swaps, - int priority, - bool noauto, - bool nofail, - bool handle, - bool set_flags) { - - Unit *u = NULL; - char *e = NULL, *wp = NULL; - bool delete = false; - int r; - SwapParameters *p; - - assert(m); - assert(what); - - if (!(e = unit_name_from_path(what, ".swap"))) - return -ENOMEM; - - u = manager_get_unit(m, e); - - if (what_proc_swaps && - u && - SWAP(u)->from_proc_swaps && - !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) - return -EEXIST; - - if (!u) { - delete = true; - - if (!(u = unit_new(m))) { - free(e); - return -ENOMEM; - } - - if ((r = unit_add_name(u, e)) < 0) - goto fail; - - if (!(SWAP(u)->what = strdup(what))) { - r = -ENOMEM; - goto fail; - } - - unit_add_to_load_queue(u); - } else - delete = false; - - if (what_proc_swaps) { - Swap *first; - - p = &SWAP(u)->parameters_proc_swaps; - - if (!p->what) { - if (!(wp = strdup(what_proc_swaps))) { - r = -ENOMEM; - goto fail; - } - - if (!m->swaps_by_proc_swaps) - if (!(m->swaps_by_proc_swaps = hashmap_new(string_hash_func, string_compare_func))) { - r = -ENOMEM; - goto fail; - } - - free(p->what); - p->what = wp; - - first = hashmap_get(m->swaps_by_proc_swaps, wp); - LIST_PREPEND(Swap, same_proc_swaps, first, SWAP(u)); - - if ((r = hashmap_replace(m->swaps_by_proc_swaps, wp, first)) < 0) - goto fail; - } - - if (set_flags) { - SWAP(u)->is_active = true; - SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps; - } - - SWAP(u)->from_proc_swaps = true; - - } else { - p = &SWAP(u)->parameters_etc_fstab; - - if (!(wp = strdup(what))) { - r = -ENOMEM; - goto fail; - } - - free(p->what); - p->what = wp; - - SWAP(u)->from_etc_fstab = true; - } - - p->priority = priority; - p->noauto = noauto; - p->nofail = nofail; - p->handle = handle; - - unit_add_to_dbus_queue(u); - - free(e); - - return 0; - -fail: - log_warning("Failed to load swap unit: %s", strerror(-r)); - - free(wp); - free(e); - - if (delete && u) - unit_free(u); - - return r; -} - -static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) { - struct stat st; - int r = 0, k; - - assert(m); - - if (stat(device, &st) >= 0 && S_ISBLK(st.st_mode)) { - struct udev_device *d; - const char *dn; - struct udev_list_entry *item = NULL, *first = NULL; - - /* So this is a proper swap device. Create swap units - * for all names this swap device is known under */ - - if (!(d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev))) - return -ENOMEM; - - if ((dn = udev_device_get_devnode(d))) - r = swap_add_one(m, dn, device, prio, false, false, false, set_flags); - - /* Add additional units for all symlinks */ - first = udev_device_get_devlinks_list_entry(d); - udev_list_entry_foreach(item, first) { - const char *p; - - /* Don't bother with the /dev/block links */ - p = udev_list_entry_get_name(item); - - if (path_startswith(p, "/dev/block/")) - continue; - - if (stat(p, &st) >= 0) - if ((!S_ISBLK(st.st_mode)) || st.st_rdev != udev_device_get_devnum(d)) - continue; - - if ((k = swap_add_one(m, p, device, prio, false, false, false, set_flags)) < 0) - r = k; - } - - udev_device_unref(d); - } - - if ((k = swap_add_one(m, device, device, prio, false, false, false, set_flags)) < 0) - r = k; - - return r; -} - -static void swap_set_state(Swap *s, SwapState state) { - SwapState old_state; - - assert(s); - - old_state = s->state; - s->state = state; - - if (state != SWAP_ACTIVATING && - state != SWAP_ACTIVATING_SIGTERM && - state != SWAP_ACTIVATING_SIGKILL && - state != SWAP_DEACTIVATING && - state != SWAP_DEACTIVATING_SIGTERM && - state != SWAP_DEACTIVATING_SIGKILL) { - unit_unwatch_timer(UNIT(s), &s->timer_watch); - swap_unwatch_control_pid(s); - s->control_command = NULL; - s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; - } - - if (state != old_state) - log_debug("%s changed %s -> %s", - s->meta.id, - swap_state_to_string(old_state), - swap_state_to_string(state)); - - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); -} - -static int swap_coldplug(Unit *u) { - Swap *s = SWAP(u); - SwapState new_state = SWAP_DEAD; - int r; - - assert(s); - assert(s->state == SWAP_DEAD); - - if (s->deserialized_state != s->state) - new_state = s->deserialized_state; - else if (s->from_proc_swaps) - new_state = SWAP_ACTIVE; - - if (new_state != s->state) { - - if (new_state == SWAP_ACTIVATING || - new_state == SWAP_ACTIVATING_SIGTERM || - new_state == SWAP_ACTIVATING_SIGKILL || - new_state == SWAP_DEACTIVATING || - new_state == SWAP_DEACTIVATING_SIGTERM || - new_state == SWAP_DEACTIVATING_SIGKILL) { - - if (s->control_pid <= 0) - return -EBADMSG; - - if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0) - return r; - - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - return r; - } - - swap_set_state(s, new_state); - } - - return 0; -} - -static void swap_dump(Unit *u, FILE *f, const char *prefix) { - Swap *s = SWAP(u); - SwapParameters *p; - - assert(s); - assert(f); - - if (s->from_proc_swaps) - p = &s->parameters_proc_swaps; - else if (s->from_fragment) - p = &s->parameters_fragment; - else - p = &s->parameters_etc_fstab; - - fprintf(f, - "%sSwap State: %s\n" - "%sWhat: %s\n" - "%sPriority: %i\n" - "%sNoAuto: %s\n" - "%sNoFail: %s\n" - "%sHandle: %s\n" - "%sFrom /etc/fstab: %s\n" - "%sFrom /proc/swaps: %s\n" - "%sFrom fragment: %s\n", - prefix, swap_state_to_string(s->state), - prefix, s->what, - prefix, p->priority, - prefix, yes_no(p->noauto), - prefix, yes_no(p->nofail), - prefix, yes_no(p->handle), - prefix, yes_no(s->from_etc_fstab), - prefix, yes_no(s->from_proc_swaps), - prefix, yes_no(s->from_fragment)); - - if (s->control_pid > 0) - fprintf(f, - "%sControl PID: %lu\n", - prefix, (unsigned long) s->control_pid); - - exec_context_dump(&s->exec_context, f, prefix); -} - -static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { - pid_t pid; - int r; - - assert(s); - assert(c); - assert(_pid); - - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - - if ((r = exec_spawn(c, - NULL, - &s->exec_context, - NULL, 0, - s->meta.manager->environment, - true, - true, - true, - s->meta.manager->confirm_spawn, - s->meta.cgroup_bondings, - s->meta.cgroup_attributes, - &pid)) < 0) - goto fail; - - if ((r = unit_watch_pid(UNIT(s), pid)) < 0) - /* FIXME: we need to do something here */ - goto fail; - - *_pid = pid; - - return 0; - -fail: - unit_unwatch_timer(UNIT(s), &s->timer_watch); - - return r; -} - -static void swap_enter_dead(Swap *s, bool success) { - assert(s); - - if (!success) - s->failure = true; - - swap_set_state(s, s->failure ? SWAP_FAILED : SWAP_DEAD); -} - -static void swap_enter_active(Swap *s, bool success) { - assert(s); - - if (!success) - s->failure = true; - - swap_set_state(s, SWAP_ACTIVE); -} - -static void swap_enter_signal(Swap *s, SwapState state, bool success) { - int r; - Set *pid_set = NULL; - bool wait_for_exit = false; - - assert(s); - - if (!success) - s->failure = true; - - if (s->exec_context.kill_mode != KILL_NONE) { - int sig = (state == SWAP_ACTIVATING_SIGTERM || - state == SWAP_DEACTIVATING_SIGTERM) ? s->exec_context.kill_signal : SIGKILL; - - if (s->control_pid > 0) { - if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH) - - log_warning("Failed to kill control process %li: %m", (long) s->control_pid); - else - wait_for_exit = true; - } - - if (s->exec_context.kill_mode == KILL_CONTROL_GROUP) { - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) { - r = -ENOMEM; - goto fail; - } - - /* Exclude the control pid from being killed via the cgroup */ - if (s->control_pid > 0) - if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) - goto fail; - - if ((r = cgroup_bonding_kill_list(s->meta.cgroup_bondings, sig, true, pid_set)) < 0) { - if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) - log_warning("Failed to kill control group: %s", strerror(-r)); - } else if (r > 0) - wait_for_exit = true; - - set_free(pid_set); - pid_set = NULL; - } - } - - if (wait_for_exit) { - if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0) - goto fail; - - swap_set_state(s, state); - } else - swap_enter_dead(s, true); - - return; - -fail: - log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r)); - - swap_enter_dead(s, false); - - if (pid_set) - set_free(pid_set); -} - -static void swap_enter_activating(Swap *s) { - int r, priority; - - assert(s); - - s->control_command_id = SWAP_EXEC_ACTIVATE; - s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE; - - if (s->from_fragment) - priority = s->parameters_fragment.priority; - else if (s->from_etc_fstab) - priority = s->parameters_etc_fstab.priority; - else - priority = -1; - - if (priority >= 0) { - char p[LINE_MAX]; - - snprintf(p, sizeof(p), "%i", priority); - char_array_0(p); - - r = exec_command_set( - s->control_command, - "/sbin/swapon", - "-p", - p, - s->what, - NULL); - } else - r = exec_command_set( - s->control_command, - "/sbin/swapon", - s->what, - NULL); - - if (r < 0) - goto fail; - - swap_unwatch_control_pid(s); - - if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - swap_set_state(s, SWAP_ACTIVATING); - - return; - -fail: - log_warning("%s failed to run 'swapon' task: %s", s->meta.id, strerror(-r)); - swap_enter_dead(s, false); -} - -static void swap_enter_deactivating(Swap *s, bool success) { - int r; - - assert(s); - - if (!success) - s->failure = true; - - s->control_command_id = SWAP_EXEC_DEACTIVATE; - s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE; - - if ((r = exec_command_set( - s->control_command, - "/sbin/swapoff", - s->what, - NULL)) < 0) - goto fail; - - swap_unwatch_control_pid(s); - - if ((r = swap_spawn(s, s->control_command, &s->control_pid)) < 0) - goto fail; - - swap_set_state(s, SWAP_DEACTIVATING); - - return; - -fail: - log_warning("%s failed to run 'swapoff' task: %s", s->meta.id, strerror(-r)); - swap_enter_active(s, false); -} - -static int swap_start(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - - /* We cannot fulfill this request right now, try again later - * please! */ - - if (s->state == SWAP_DEACTIVATING || - s->state == SWAP_DEACTIVATING_SIGTERM || - s->state == SWAP_DEACTIVATING_SIGKILL || - s->state == SWAP_ACTIVATING_SIGTERM || - s->state == SWAP_ACTIVATING_SIGKILL) - return -EAGAIN; - - if (s->state == SWAP_ACTIVATING) - return 0; - - assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED); - - s->failure = false; - swap_enter_activating(s); - return 0; -} - -static int swap_stop(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - - if (s->state == SWAP_DEACTIVATING || - s->state == SWAP_DEACTIVATING_SIGTERM || - s->state == SWAP_DEACTIVATING_SIGKILL || - s->state == SWAP_ACTIVATING_SIGTERM || - s->state == SWAP_ACTIVATING_SIGKILL) - return 0; - - assert(s->state == SWAP_ACTIVATING || - s->state == SWAP_ACTIVE); - - swap_enter_deactivating(s, true); - return 0; -} - -static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { - Swap *s = SWAP(u); - - assert(s); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", swap_state_to_string(s->state)); - unit_serialize_item(u, f, "failure", yes_no(s->failure)); - - if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); - - if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id)); - - return 0; -} - -static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Swap *s = SWAP(u); - - assert(s); - assert(fds); - - if (streq(key, "state")) { - SwapState state; - - if ((state = swap_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - s->deserialized_state = state; - } else if (streq(key, "failure")) { - int b; - - if ((b = parse_boolean(value)) < 0) - log_debug("Failed to parse failure value %s", value); - else - s->failure = b || s->failure; - - } else if (streq(key, "control-pid")) { - pid_t pid; - - if (parse_pid(value, &pid) < 0) - log_debug("Failed to parse control-pid value %s", value); - else - s->control_pid = pid; - - } else if (streq(key, "control-command")) { - SwapExecCommand id; - - if ((id = swap_exec_command_from_string(value)) < 0) - log_debug("Failed to parse exec-command value %s", value); - else { - s->control_command_id = id; - s->control_command = s->exec_command + id; - } - - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState swap_active_state(Unit *u) { - assert(u); - - return state_translation_table[SWAP(u)->state]; -} - -static const char *swap_sub_state_to_string(Unit *u) { - assert(u); - - return swap_state_to_string(SWAP(u)->state); -} - -static bool swap_check_gc(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - - return s->from_etc_fstab || s->from_proc_swaps; -} - -static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { - Swap *s = SWAP(u); - bool success; - - assert(s); - assert(pid >= 0); - - if (pid != s->control_pid) - return; - - s->control_pid = 0; - - success = is_clean_exit(code, status); - s->failure = s->failure || !success; - - if (s->control_command) { - exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); - s->control_command = NULL; - s->control_command_id = _SWAP_EXEC_COMMAND_INVALID; - } - - log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s swap process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); - - switch (s->state) { - - case SWAP_ACTIVATING: - case SWAP_ACTIVATING_SIGTERM: - case SWAP_ACTIVATING_SIGKILL: - - if (success) - swap_enter_active(s, true); - else - swap_enter_dead(s, false); - break; - - case SWAP_DEACTIVATING: - case SWAP_DEACTIVATING_SIGKILL: - case SWAP_DEACTIVATING_SIGTERM: - - if (success) - swap_enter_dead(s, true); - else - swap_enter_dead(s, false); - break; - - default: - assert_not_reached("Uh, control process died at wrong time."); - } - - /* Notify clients about changed exit status */ - unit_add_to_dbus_queue(u); - - /* Request a reload of /proc/swaps, so that following units - * can follow our state change */ - u->meta.manager->request_reload = true; -} - -static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Swap *s = SWAP(u); - - assert(s); - assert(elapsed == 1); - assert(w == &s->timer_watch); - - switch (s->state) { - - case SWAP_ACTIVATING: - log_warning("%s activation timed out. Stopping.", u->meta.id); - swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, false); - break; - - case SWAP_DEACTIVATING: - log_warning("%s deactivation timed out. Stopping.", u->meta.id); - swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, false); - break; - - case SWAP_ACTIVATING_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s activation timed out. Killing.", u->meta.id); - swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, false); - } else { - log_warning("%s activation timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - swap_enter_dead(s, false); - } - break; - - case SWAP_DEACTIVATING_SIGTERM: - if (s->exec_context.send_sigkill) { - log_warning("%s deactivation timed out. Killing.", u->meta.id); - swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, false); - } else { - log_warning("%s deactivation timed out. Skipping SIGKILL. Ignoring.", u->meta.id); - swap_enter_dead(s, false); - } - break; - - case SWAP_ACTIVATING_SIGKILL: - case SWAP_DEACTIVATING_SIGKILL: - log_warning("%s swap process still around after SIGKILL. Ignoring.", u->meta.id); - swap_enter_dead(s, false); - break; - - default: - assert_not_reached("Timeout at wrong time."); - } -} - -static int swap_load_proc_swaps(Manager *m, bool set_flags) { - unsigned i; - int r = 0; - - assert(m); - - rewind(m->proc_swaps); - - (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n"); - - for (i = 1;; i++) { - char *dev = NULL, *d; - int prio = 0, k; - - if ((k = fscanf(m->proc_swaps, - "%ms " /* device/file */ - "%*s " /* type of swap */ - "%*s " /* swap size */ - "%*s " /* used */ - "%i\n", /* priority */ - &dev, &prio)) != 2) { - - if (k == EOF) - break; - - log_warning("Failed to parse /proc/swaps:%u.", i); - free(dev); - continue; - } - - d = cunescape(dev); - free(dev); - - if (!d) - return -ENOMEM; - - k = swap_process_new_swap(m, d, prio, set_flags); - free(d); - - if (k < 0) - r = k; - } - - return r; -} - -int swap_dispatch_reload(Manager *m) { - /* This function should go as soon as the kernel properly notifies us */ - - if (_likely_(!m->request_reload)) - return 0; - - m->request_reload = false; - - return swap_fd_event(m, EPOLLPRI); -} - -int swap_fd_event(Manager *m, int events) { - Meta *meta; - int r; - - assert(m); - assert(events & EPOLLPRI); - - if ((r = swap_load_proc_swaps(m, true)) < 0) { - log_error("Failed to reread /proc/swaps: %s", strerror(-r)); - - /* Reset flags, just in case, for late calls */ - LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_SWAP]) { - Swap *swap = (Swap*) meta; - - swap->is_active = swap->just_activated = false; - } - - return 0; - } - - manager_dispatch_load_queue(m); - - LIST_FOREACH(units_by_type, meta, m->units_by_type[UNIT_SWAP]) { - Swap *swap = (Swap*) meta; - - if (!swap->is_active) { - /* This has just been deactivated */ - - swap->from_proc_swaps = false; - swap_unset_proc_swaps(swap); - - switch (swap->state) { - - case SWAP_ACTIVE: - swap_enter_dead(swap, true); - break; - - default: - swap_set_state(swap, swap->state); - break; - } - - } else if (swap->just_activated) { - - /* New swap entry */ - - switch (swap->state) { - - case SWAP_DEAD: - case SWAP_FAILED: - swap_enter_active(swap, true); - break; - - default: - /* Nothing really changed, but let's - * issue an notification call - * nonetheless, in case somebody is - * waiting for this. */ - swap_set_state(swap, swap->state); - break; - } - } - - /* Reset the flags for later calls */ - swap->is_active = swap->just_activated = false; - } - - return 1; -} - -static Unit *swap_following(Unit *u) { - Swap *s = SWAP(u); - Swap *other, *first = NULL; - - assert(s); - - if (streq_ptr(s->what, s->parameters_proc_swaps.what)) - return NULL; - - /* Make everybody follow the unit that's named after the swap - * device in the kernel */ - - LIST_FOREACH_AFTER(same_proc_swaps, other, s) - if (streq_ptr(other->what, other->parameters_proc_swaps.what)) - return UNIT(other); - - LIST_FOREACH_BEFORE(same_proc_swaps, other, s) { - if (streq_ptr(other->what, other->parameters_proc_swaps.what)) - return UNIT(other); - - first = other; - } - - return UNIT(first); -} - -static int swap_following_set(Unit *u, Set **_set) { - Swap *s = SWAP(u); - Swap *other; - Set *set; - int r; - - assert(s); - assert(_set); - - if (LIST_JUST_US(same_proc_swaps, s)) { - *_set = NULL; - return 0; - } - - if (!(set = set_new(NULL, NULL))) - return -ENOMEM; - - LIST_FOREACH_AFTER(same_proc_swaps, other, s) - if ((r = set_put(set, other)) < 0) - goto fail; - - LIST_FOREACH_BEFORE(same_proc_swaps, other, s) - if ((r = set_put(set, other)) < 0) - goto fail; - - *_set = set; - return 1; - -fail: - set_free(set); - return r; -} - -static void swap_shutdown(Manager *m) { - assert(m); - - if (m->proc_swaps) { - fclose(m->proc_swaps); - m->proc_swaps = NULL; - } - - hashmap_free(m->swaps_by_proc_swaps); - m->swaps_by_proc_swaps = NULL; -} - -static int swap_enumerate(Manager *m) { - int r; - struct epoll_event ev; - assert(m); - - if (!m->proc_swaps) { - if (!(m->proc_swaps = fopen("/proc/swaps", "re"))) - return (errno == ENOENT) ? 0 : -errno; - - m->swap_watch.type = WATCH_SWAP; - m->swap_watch.fd = fileno(m->proc_swaps); - - zero(ev); - ev.events = EPOLLPRI; - ev.data.ptr = &m->swap_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->swap_watch.fd, &ev) < 0) - return -errno; - } - - /* We rely on mount.c to load /etc/fstab for us */ - - if ((r = swap_load_proc_swaps(m, false)) < 0) - swap_shutdown(m); - - return r; -} - -static void swap_reset_failed(Unit *u) { - Swap *s = SWAP(u); - - assert(s); - - if (s->state == SWAP_FAILED) - swap_set_state(s, SWAP_DEAD); - - s->failure = false; -} - -static int swap_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) { - Swap *s = SWAP(u); - int r = 0; - Set *pid_set = NULL; - - assert(s); - - if (who == KILL_MAIN) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Swap units have no main processes"); - return -ESRCH; - } - - if (s->control_pid <= 0 && who == KILL_CONTROL) { - dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); - return -ESRCH; - } - - if (who == KILL_CONTROL || who == KILL_ALL) - if (s->control_pid > 0) - if (kill(s->control_pid, signo) < 0) - r = -errno; - - if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) { - int q; - - if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - /* Exclude the control pid from being killed via the cgroup */ - if (s->control_pid > 0) - if ((q = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0) { - r = q; - goto finish; - } - - if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0) - if (q != -EAGAIN && q != -ESRCH && q != -ENOENT) - r = q; - } - -finish: - if (pid_set) - set_free(pid_set); - - return r; -} - -static const char* const swap_state_table[_SWAP_STATE_MAX] = { - [SWAP_DEAD] = "dead", - [SWAP_ACTIVATING] = "activating", - [SWAP_ACTIVE] = "active", - [SWAP_DEACTIVATING] = "deactivating", - [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", - [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", - [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", - [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", - [SWAP_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); - -static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { - [SWAP_EXEC_ACTIVATE] = "ExecActivate", - [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", -}; - -DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand); - -const UnitVTable swap_vtable = { - .suffix = ".swap", - .sections = - "Unit\0" - "Swap\0" - "Install\0", - - .no_alias = true, - .no_instances = true, - .show_status = true, - - .init = swap_init, - .load = swap_load, - .done = swap_done, - - .coldplug = swap_coldplug, - - .dump = swap_dump, - - .start = swap_start, - .stop = swap_stop, - - .kill = swap_kill, - - .serialize = swap_serialize, - .deserialize_item = swap_deserialize_item, - - .active_state = swap_active_state, - .sub_state_to_string = swap_sub_state_to_string, - - .check_gc = swap_check_gc, - - .sigchld_event = swap_sigchld_event, - .timer_event = swap_timer_event, - - .reset_failed = swap_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Swap", - .bus_message_handler = bus_swap_message_handler, - .bus_invalidating_properties = bus_swap_invalidating_properties, - - .following = swap_following, - .following_set = swap_following_set, - - .enumerate = swap_enumerate, - .shutdown = swap_shutdown -}; diff --git a/src/swap.h b/src/swap.h deleted file mode 100644 index 0d5c9a2..0000000 --- a/src/swap.h +++ /dev/null @@ -1,114 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooswaphfoo -#define fooswaphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2010 Maarten Lankhorst - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Swap Swap; - -#include "unit.h" - -typedef enum SwapState { - SWAP_DEAD, - SWAP_ACTIVATING, - SWAP_ACTIVE, - SWAP_DEACTIVATING, - SWAP_ACTIVATING_SIGTERM, - SWAP_ACTIVATING_SIGKILL, - SWAP_DEACTIVATING_SIGTERM, - SWAP_DEACTIVATING_SIGKILL, - SWAP_FAILED, - _SWAP_STATE_MAX, - _SWAP_STATE_INVALID = -1 -} SwapState; - -typedef enum SwapExecCommand { - SWAP_EXEC_ACTIVATE, - SWAP_EXEC_DEACTIVATE, - _SWAP_EXEC_COMMAND_MAX, - _SWAP_EXEC_COMMAND_INVALID = -1 -} SwapExecCommand; - -typedef struct SwapParameters { - char *what; - int priority; - bool noauto:1; - bool nofail:1; - bool handle:1; -} SwapParameters; - -struct Swap { - Meta meta; - - char *what; - - SwapParameters parameters_etc_fstab; - SwapParameters parameters_proc_swaps; - SwapParameters parameters_fragment; - - bool from_etc_fstab:1; - bool from_proc_swaps:1; - bool from_fragment:1; - - bool failure:1; - - /* Used while looking for swaps that vanished or got added - * from/to /proc/swaps */ - bool is_active:1; - bool just_activated:1; - - usec_t timeout_usec; - - ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX]; - ExecContext exec_context; - - SwapState state, deserialized_state; - - ExecCommand* control_command; - SwapExecCommand control_command_id; - pid_t control_pid; - - Watch timer_watch; - - /* In order to be able to distinguish dependencies on - different device nodes we might end up creating multiple - devices for the same swap. We chain them up here. */ - - LIST_FIELDS(struct Swap, same_proc_swaps); -}; - -extern const UnitVTable swap_vtable; - -int swap_add_one(Manager *m, const char *what, const char *what_proc_swaps, int prio, bool no_auto, bool no_fail, bool handle, bool set_flags); - -int swap_add_one_mount_link(Swap *s, Mount *m); - -int swap_dispatch_reload(Manager *m); -int swap_fd_event(Manager *m, int events); - -const char* swap_state_to_string(SwapState i); -SwapState swap_state_from_string(const char *s); - -const char* swap_exec_command_to_string(SwapExecCommand i); -SwapExecCommand swap_exec_command_from_string(const char *s); - -#endif diff --git a/src/sysctl.c b/src/sysctl.c deleted file mode 100644 index 8bdfb08..0000000 --- a/src/sysctl.c +++ /dev/null @@ -1,266 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "strv.h" -#include "util.h" -#include "strv.h" - -#define PROC_SYS_PREFIX "/proc/sys/" - -static char **arg_prefixes = NULL; - -static int apply_sysctl(const char *property, const char *value) { - char *p, *n; - int r = 0, k; - - log_debug("Setting '%s' to '%s'", property, value); - - p = new(char, sizeof(PROC_SYS_PREFIX) + strlen(property)); - if (!p) { - log_error("Out of memory"); - return -ENOMEM; - } - - n = stpcpy(p, PROC_SYS_PREFIX); - strcpy(n, property); - - for (; *n; n++) - if (*n == '.') - *n = '/'; - - if (!strv_isempty(arg_prefixes)) { - char **i; - bool good = false; - - STRV_FOREACH(i, arg_prefixes) - if (path_startswith(p, *i)) { - good = true; - break; - } - - if (!good) { - log_debug("Skipping %s", p); - free(p); - return 0; - } - } - - k = write_one_line_file(p, value); - if (k < 0) { - - log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING, - "Failed to write '%s' to '%s': %s", value, p, strerror(-k)); - - if (k != -ENOENT && r == 0) - r = k; - } - - free(p); - - return r; -} - -static int apply_file(const char *path, bool ignore_enoent) { - FILE *f; - int r = 0; - - assert(path); - - if (!(f = fopen(path, "re"))) { - if (ignore_enoent && errno == ENOENT) - return 0; - - log_error("Failed to open file '%s', ignoring: %m", path); - return -errno; - } - - log_debug("apply: %s\n", path); - while (!feof(f)) { - char l[LINE_MAX], *p, *value; - int k; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - log_error("Failed to read file '%s', ignoring: %m", path); - r = -errno; - goto finish; - } - - p = strstrip(l); - - if (!*p) - continue; - - if (strchr(COMMENTS, *p)) - continue; - - if (!(value = strchr(p, '='))) { - log_error("Line is not an assignment in file '%s': %s", path, value); - - if (r == 0) - r = -EINVAL; - continue; - } - - *value = 0; - value++; - - if ((k = apply_sysctl(strstrip(p), strstrip(value))) < 0 && r == 0) - r = k; - } - -finish: - fclose(f); - - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" - "Applies kernel sysctl settings.\n\n" - " -h --help Show this help\n" - " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_PREFIX - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "prefix", required_argument, NULL, ARG_PREFIX }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_PREFIX: { - char *p; - char **l; - - for (p = optarg; *p; p++) - if (*p == '.') - *p = '/'; - - l = strv_append(arg_prefixes, optarg); - if (!l) { - log_error("Out of memory"); - return -ENOMEM; - } - - strv_free(arg_prefixes); - arg_prefixes = l; - - break; - } - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r = 0; - - r = parse_argv(argc, argv); - if (r <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - - if (argc-optind > 1) { - log_error("This program expects one or no arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc > optind) - r = apply_file(argv[optind], false); - else { - char **files, **f; - - r = conf_files_list(&files, ".conf", - "/run/sysctl.d", - "/etc/sysctl.d", - "/usr/local/lib/sysctl.d", - "/usr/lib/sysctl.d", - "/lib/sysctl.d", - NULL); - if (r < 0) { - log_error("Failed to enumerate sysctl.d files: %s", strerror(-r)); - goto finish; - } - - STRV_FOREACH(f, files) { - int k; - - k = apply_file(*f, true); - if (k < 0 && r == 0) - r = k; - } - - apply_file("/etc/sysctl.conf", true); - - strv_free(files); - } -finish: - strv_free(arg_prefixes); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/sysctl/Makefile b/src/sysctl/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/sysctl/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c new file mode 100644 index 0000000..76efacb --- /dev/null +++ b/src/sysctl/sysctl.c @@ -0,0 +1,326 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "strv.h" +#include "util.h" +#include "hashmap.h" +#include "path-util.h" +#include "conf-files.h" +#include "fileio.h" +#include "build.h" + +static char **arg_prefixes = NULL; + +static const char conf_file_dirs[] = + "/etc/sysctl.d\0" + "/run/sysctl.d\0" + "/usr/local/lib/sysctl.d\0" + "/usr/lib/sysctl.d\0" +#ifdef HAVE_SPLIT_USR + "/lib/sysctl.d\0" +#endif + ; + +static char *normalize_sysctl(char *s) { + char *n; + + for (n = s; *n; n++) + if (*n == '.') + *n = '/'; + + return s; +} + +static int apply_sysctl(const char *property, const char *value) { + _cleanup_free_ char *p = NULL; + char *n; + int r = 0, k; + + log_debug("Setting '%s' to '%s'", property, value); + + p = new(char, sizeof("/proc/sys/") + strlen(property)); + if (!p) + return log_oom(); + + n = stpcpy(p, "/proc/sys/"); + strcpy(n, property); + + if (!strv_isempty(arg_prefixes)) { + char **i; + bool good = false; + + STRV_FOREACH(i, arg_prefixes) + if (path_startswith(p, *i)) { + good = true; + break; + } + + if (!good) { + log_debug("Skipping %s", p); + return 0; + } + } + + k = write_string_file(p, value); + if (k < 0) { + log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING, + "Failed to write '%s' to '%s': %s", value, p, strerror(-k)); + + if (k != -ENOENT && r == 0) + r = k; + } + + return r; +} + +static int apply_all(Hashmap *sysctl_options) { + int r = 0; + char *property, *value; + Iterator i; + + assert(sysctl_options); + + HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) { + int k; + + k = apply_sysctl(property, value); + if (k < 0 && r == 0) + r = k; + } + return r; +} + +static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) { + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(path); + + r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f); + if (r < 0) { + if (ignore_enoent && r == -ENOENT) + return 0; + + log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r)); + return r; + } + + log_debug("parse: %s", path); + while (!feof(f)) { + char l[LINE_MAX], *p, *value, *new_value, *property, *existing; + void *v; + int k; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + log_error("Failed to read file '%s', ignoring: %m", path); + return -errno; + } + + p = strstrip(l); + if (!*p) + continue; + + if (strchr(COMMENTS "\n", *p)) + continue; + + value = strchr(p, '='); + if (!value) { + log_error("Line is not an assignment in file '%s': %s", path, value); + + if (r == 0) + r = -EINVAL; + continue; + } + + *value = 0; + value++; + + p = normalize_sysctl(strstrip(p)); + value = strstrip(value); + + existing = hashmap_get2(sysctl_options, p, &v); + if (existing) { + if (streq(value, existing)) + continue; + + log_info("Overwriting earlier assignment of %s in file '%s'.", p, path); + free(hashmap_remove(sysctl_options, p)); + free(v); + } + + property = strdup(p); + if (!property) + return log_oom(); + + new_value = strdup(value); + if (!new_value) { + free(property); + return log_oom(); + } + + k = hashmap_put(sysctl_options, property, new_value); + if (k < 0) { + log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-k)); + free(property); + free(new_value); + return k; + } + } + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" + "Applies kernel sysctl settings.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_PREFIX + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "prefix", required_argument, NULL, ARG_PREFIX }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_PREFIX: { + char *p; + + for (p = optarg; *p; p++) + if (*p == '.') + *p = '/'; + + if (strv_extend(&arg_prefixes, optarg) < 0) + return log_oom(); + + break; + } + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r = 0, k; + Hashmap *sysctl_options; + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + sysctl_options = hashmap_new(string_hash_func, string_compare_func); + if (!sysctl_options) { + r = log_oom(); + goto finish; + } + + r = 0; + + if (argc > optind) { + int i; + + for (i = optind; i < argc; i++) { + k = parse_file(sysctl_options, argv[i], false); + if (k < 0 && r == 0) + r = k; + } + } else { + _cleanup_strv_free_ char **files = NULL; + char **f; + + r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); + if (r < 0) { + log_error("Failed to enumerate sysctl.d files: %s", strerror(-r)); + goto finish; + } + + STRV_FOREACH(f, files) { + k = parse_file(sysctl_options, *f, true); + if (k < 0 && r == 0) + r = k; + } + } + + k = apply_all(sysctl_options); + if (k < 0 && r == 0) + r = k; + +finish: + hashmap_free_free_free(sysctl_options); + strv_free(arg_prefixes); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/sysfs-show.c b/src/sysfs-show.c deleted file mode 100644 index b8b356d..0000000 --- a/src/sysfs-show.c +++ /dev/null @@ -1,187 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "util.h" -#include "sysfs-show.h" - -static int show_sysfs_one( - struct udev *udev, - const char *seat, - struct udev_list_entry **item, - const char *sub, - const char *prefix, - unsigned n_columns) { - - assert(udev); - assert(seat); - assert(item); - assert(prefix); - - while (*item) { - struct udev_list_entry *next, *lookahead; - struct udev_device *d; - const char *sn, *name, *sysfs, *subsystem, *sysname; - char *l, *k; - - sysfs = udev_list_entry_get_name(*item); - if (!path_startswith(sysfs, sub)) - return 0; - - d = udev_device_new_from_syspath(udev, sysfs); - if (!d) { - *item = udev_list_entry_get_next(*item); - continue; - } - - sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(sn)) - sn = "seat0"; - - /* fixme, also check for tag 'seat' here */ - if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) { - udev_device_unref(d); - *item = udev_list_entry_get_next(*item); - continue; - } - - name = udev_device_get_sysattr_value(d, "name"); - if (!name) - name = udev_device_get_sysattr_value(d, "id"); - subsystem = udev_device_get_subsystem(d); - sysname = udev_device_get_sysname(d); - - /* Look if there's more coming after this */ - lookahead = next = udev_list_entry_get_next(*item); - while (lookahead) { - const char *lookahead_sysfs; - - lookahead_sysfs = udev_list_entry_get_name(lookahead); - - if (path_startswith(lookahead_sysfs, sub) && - !path_startswith(lookahead_sysfs, sysfs)) { - struct udev_device *lookahead_d; - - lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs); - if (lookahead_d) { - const char *lookahead_sn; - bool found; - - lookahead_sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(lookahead_sn)) - lookahead_sn = "seat0"; - - found = streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat"); - udev_device_unref(lookahead_d); - - if (found) - break; - } - } - - lookahead = udev_list_entry_get_next(lookahead); - } - - k = ellipsize(sysfs, n_columns, 20); - printf("%s%s %s\n", prefix, lookahead ? "\342\224\234" : "\342\224\224", k ? k : sysfs); - free(k); - - if (asprintf(&l, - "(%s:%s)%s%s%s", - subsystem, sysname, - name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) { - udev_device_unref(d); - return -ENOMEM; - } - - k = ellipsize(l, n_columns, 70); - printf("%s%s %s\n", prefix, lookahead ? "\342\224\202" : " ", k ? k : l); - free(k); - free(l); - - *item = next; - if (*item) { - char *p; - - p = strappend(prefix, lookahead ? "\342\224\202 " : " "); - show_sysfs_one(udev, seat, item, sysfs, p ? p : prefix, n_columns - 2); - free(p); - } - - udev_device_unref(d); - } - - return 0; -} - -int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { - struct udev *udev; - struct udev_list_entry *first = NULL; - struct udev_enumerate *e; - int r; - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - if (isempty(seat)) - seat = "seat0"; - - udev = udev_new(); - if (!udev) - return -ENOMEM; - - e = udev_enumerate_new(udev); - if (!e) { - r = -ENOMEM; - goto finish; - } - - if (!streq(seat, "seat0")) - r = udev_enumerate_add_match_tag(e, seat); - else - r = udev_enumerate_add_match_tag(e, "seat"); - - if (r < 0) - goto finish; - - r = udev_enumerate_scan_devices(e); - if (r < 0) - goto finish; - - first = udev_enumerate_get_list_entry(e); - if (first) - show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); - -finish: - if (e) - udev_enumerate_unref(e); - - if (udev) - udev_unref(udev); - - return r; -} diff --git a/src/sysfs-show.h b/src/sysfs-show.h deleted file mode 100644 index 9939e8b..0000000 --- a/src/sysfs-show.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosysfsshowhfoo -#define foosysfsshowhfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int show_sysfs(const char *seat, const char *prefix, unsigned columns); - -#endif diff --git a/src/system-update-generator/Makefile b/src/system-update-generator/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/system-update-generator/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c new file mode 100644 index 0000000..13b8a0c --- /dev/null +++ b/src/system-update-generator/system-update-generator.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "log.h" +#include "util.h" +#include "unit-name.h" +#include "path-util.h" + +/* + * Implements the logic described in + * http://freedesktop.org/wiki/Software/systemd/SystemUpdates + */ + +static const char *arg_dest = "/tmp"; + +static int generate_symlink(void) { + struct stat st; + char _cleanup_free_ *p = NULL; + + if (lstat("/system-update", &st) < 0) { + if (errno == ENOENT) + return 0; + + log_error("Failed to check for system update: %m"); + return -EINVAL; + } + + p = strappend(arg_dest, "/default.target"); + if (!p) + return log_oom(); + + if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0) { + log_error("Failed to create symlink %s: %m", p); + return -errno; + } + + return 0; +} + +int main(int argc, char *argv[]) { + int r; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) + arg_dest = argv[2]; + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + r = generate_symlink(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/system.conf b/src/system.conf deleted file mode 100644 index 230336d..0000000 --- a/src/system.conf +++ /dev/null @@ -1,26 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# See systemd.conf(5) for details - -[Manager] -LogLevel=notice -#LogTarget=syslog-or-kmsg -#LogColor=yes -#LogLocation=no -#DumpCore=yes -#CrashShell=no -#ShowStatus=yes -#SysVConsole=yes -#CrashChVT=1 -#CPUAffinity=1 2 -#MountAuto=yes -#SwapAuto=yes -#DefaultControllers=cpu -#DefaultStandardOutput=syslog -#DefaultStandardError=inherit -#JoinControllers=cpu,cpuacct diff --git a/src/systemadm.vala b/src/systemadm.vala deleted file mode 100644 index d45ec64..0000000 --- a/src/systemadm.vala +++ /dev/null @@ -1,1018 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -using Gtk; -using GLib; -using Pango; - -static bool user = false; - -public class LeftLabel : Label { - public LeftLabel(string? text = null) { - if (text != null) - set_markup("%s".printf(text)); - set_alignment(0, 0); - set_padding(6, 0); - } -} - -public class RightLabel : Label { - public RightLabel(string? text = null) { - set_text_or_na(text); - set_alignment(0, 0); - set_ellipsize(EllipsizeMode.START); - set_selectable(true); - } - - public void set_text_or_na(string? text = null) { - if (text == null || text == "") - set_markup("n/a"); - else - set_text(text); - } - - public void set_markup_or_na(string? text = null) { - if (text == null || text == "") - set_markup("n/a"); - else - set_markup(text); - } -} - -public class MainWindow : Window { - - private string? current_unit_id; - private uint32 current_job_id; - - private TreeView unit_view; - private TreeView job_view; - - private ListStore unit_model; - private ListStore job_model; - - private Button start_button; - private Button stop_button; - private Button restart_button; - private Button reload_button; - private Button cancel_button; - - private Entry unit_load_entry; - private Button unit_load_button; - - private Button server_snapshot_button; - private Button server_reload_button; - - private Manager manager; - - private RightLabel unit_id_label; - private RightLabel unit_aliases_label; - private RightLabel unit_dependency_label; - private RightLabel unit_description_label; - private RightLabel unit_load_state_label; - private RightLabel unit_active_state_label; - private RightLabel unit_sub_state_label; - private RightLabel unit_fragment_path_label; - private RightLabel unit_active_enter_timestamp_label; - private RightLabel unit_active_exit_timestamp_label; - private RightLabel unit_can_start_label; - private RightLabel unit_can_reload_label; - private RightLabel unit_cgroup_label; - - private RightLabel job_id_label; - private RightLabel job_state_label; - private RightLabel job_type_label; - - private ComboBox unit_type_combo_box; - - public MainWindow() throws IOError { - title = user ? "systemd User Service Manager" : "systemd System Manager"; - set_position(WindowPosition.CENTER); - set_default_size(1000, 700); - set_border_width(12); - destroy.connect(Gtk.main_quit); - - Notebook notebook = new Notebook(); - add(notebook); - - Box unit_vbox = new VBox(false, 12); - notebook.append_page(unit_vbox, new Label("Units")); - unit_vbox.set_border_width(12); - - Box job_vbox = new VBox(false, 12); - notebook.append_page(job_vbox, new Label("Jobs")); - job_vbox.set_border_width(12); - - unit_type_combo_box = new ComboBox.text(); - Box type_hbox = new HBox(false, 6); - type_hbox.pack_start(unit_type_combo_box, false, false, 0); - unit_vbox.pack_start(type_hbox, false, false, 0); - - unit_type_combo_box.append_text("Show All Units"); - unit_type_combo_box.append_text("Show Only Live Units"); - unit_type_combo_box.append_text("Services"); - unit_type_combo_box.append_text("Sockets"); - unit_type_combo_box.append_text("Devices"); - unit_type_combo_box.append_text("Mounts"); - unit_type_combo_box.append_text("Automounts"); - unit_type_combo_box.append_text("Targets"); - unit_type_combo_box.append_text("Snapshots"); - unit_type_combo_box.set_active(1); - unit_type_combo_box.changed.connect(unit_type_changed); - - unit_load_entry = new Entry(); - unit_load_button = new Button.with_mnemonic("_Load"); - unit_load_button.set_sensitive(false); - - unit_load_entry.changed.connect(on_unit_load_entry_changed); - unit_load_entry.activate.connect(on_unit_load); - unit_load_button.clicked.connect(on_unit_load); - - Box unit_load_hbox = new HBox(false, 6); - unit_load_hbox.pack_start(unit_load_entry, false, true, 0); - unit_load_hbox.pack_start(unit_load_button, false, true, 0); - - server_snapshot_button = new Button.with_mnemonic("Take S_napshot"); - server_reload_button = new Button.with_mnemonic("Reload _Configuration"); - - server_snapshot_button.clicked.connect(on_server_snapshot); - server_reload_button.clicked.connect(on_server_reload); - - type_hbox.pack_end(server_snapshot_button, false, true, 0); - type_hbox.pack_end(server_reload_button, false, true, 0); - type_hbox.pack_end(unit_load_hbox, false, true, 24); - - unit_model = new ListStore(7, typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(Unit)); - job_model = new ListStore(6, typeof(string), typeof(string), typeof(string), typeof(string), typeof(Job), typeof(uint32)); - - TreeModelFilter unit_model_filter; - unit_model_filter = new TreeModelFilter(unit_model, null); - unit_model_filter.set_visible_func(unit_filter); - - unit_view = new TreeView.with_model(unit_model_filter); - job_view = new TreeView.with_model(job_model); - - unit_view.cursor_changed.connect(unit_changed); - job_view.cursor_changed.connect(job_changed); - - unit_view.insert_column_with_attributes(-1, "Load State", new CellRendererText(), "text", 2); - unit_view.insert_column_with_attributes(-1, "Active State", new CellRendererText(), "text", 3); - unit_view.insert_column_with_attributes(-1, "Unit State", new CellRendererText(), "text", 4); - unit_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 0); - unit_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 5); - - job_view.insert_column_with_attributes(-1, "Job", new CellRendererText(), "text", 0); - job_view.insert_column_with_attributes(-1, "Unit", new CellRendererText(), "text", 1); - job_view.insert_column_with_attributes(-1, "Type", new CellRendererText(), "text", 2); - job_view.insert_column_with_attributes(-1, "State", new CellRendererText(), "text", 3); - - ScrolledWindow scroll = new ScrolledWindow(null, null); - scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); - scroll.set_shadow_type(ShadowType.IN); - scroll.add(unit_view); - unit_vbox.pack_start(scroll, true, true, 0); - - scroll = new ScrolledWindow(null, null); - scroll.set_policy(PolicyType.AUTOMATIC, PolicyType.AUTOMATIC); - scroll.set_shadow_type(ShadowType.IN); - scroll.add(job_view); - job_vbox.pack_start(scroll, true, true, 0); - - unit_id_label = new RightLabel(); - unit_aliases_label = new RightLabel(); - unit_dependency_label = new RightLabel(); - unit_description_label = new RightLabel(); - unit_load_state_label = new RightLabel(); - unit_active_state_label = new RightLabel(); - unit_sub_state_label = new RightLabel(); - unit_fragment_path_label = new RightLabel(); - unit_active_enter_timestamp_label = new RightLabel(); - unit_active_exit_timestamp_label = new RightLabel(); - unit_can_start_label = new RightLabel(); - unit_can_reload_label = new RightLabel(); - unit_cgroup_label = new RightLabel(); - - job_id_label = new RightLabel(); - job_state_label = new RightLabel(); - job_type_label = new RightLabel(); - - unit_dependency_label.set_track_visited_links(false); - unit_dependency_label.set_selectable(false); - unit_dependency_label.activate_link.connect(on_activate_link); - - unit_fragment_path_label.set_track_visited_links(false); - - Table unit_table = new Table(8, 6, false); - unit_table.set_row_spacings(6); - unit_table.set_border_width(0); - unit_vbox.pack_start(unit_table, false, true, 0); - - Table job_table = new Table(2, 2, false); - job_table.set_row_spacings(6); - job_table.set_border_width(0); - job_vbox.pack_start(job_table, false, true, 0); - - unit_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_id_label, 1, 6, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Aliases:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_aliases_label, 1, 6, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Description:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_description_label, 1, 6, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Dependencies:"), 0, 1, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_dependency_label, 1, 6, 3, 4, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Fragment Path:"), 0, 1, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_fragment_path_label, 1, 6, 4, 5, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Control Group:"), 0, 1, 5, 6, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_cgroup_label, 1, 6, 5, 6, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - - unit_table.attach(new LeftLabel("Load State:"), 0, 1, 6, 7, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_load_state_label, 1, 2, 6, 7, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Active State:"), 0, 1, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_state_label, 1, 2, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Unit State:"), 0, 1, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_sub_state_label, 1, 2, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - - unit_table.attach(new LeftLabel("Active Enter Timestamp:"), 2, 3, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_enter_timestamp_label, 3, 4, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Active Exit Timestamp:"), 2, 3, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_active_exit_timestamp_label, 3, 4, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - - unit_table.attach(new LeftLabel("Can Start/Stop:"), 4, 5, 7, 8, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_can_start_label, 5, 6, 7, 8, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(new LeftLabel("Can Reload:"), 4, 5, 8, 9, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - unit_table.attach(unit_can_reload_label, 5, 6, 8, 9, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - - job_table.attach(new LeftLabel("Id:"), 0, 1, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - job_table.attach(job_id_label, 1, 2, 0, 1, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - job_table.attach(new LeftLabel("State:"), 0, 1, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - job_table.attach(job_state_label, 1, 2, 1, 2, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - job_table.attach(new LeftLabel("Type:"), 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0); - job_table.attach(job_type_label, 1, 2, 2, 3, AttachOptions.EXPAND|AttachOptions.FILL, AttachOptions.FILL, 0, 0); - - ButtonBox bbox = new HButtonBox(); - bbox.set_layout(ButtonBoxStyle.START); - bbox.set_spacing(6); - unit_vbox.pack_start(bbox, false, true, 0); - - start_button = new Button.with_mnemonic("_Start"); - stop_button = new Button.with_mnemonic("Sto_p"); - reload_button = new Button.with_mnemonic("_Reload"); - restart_button = new Button.with_mnemonic("Res_tart"); - - start_button.clicked.connect(on_start); - stop_button.clicked.connect(on_stop); - reload_button.clicked.connect(on_reload); - restart_button.clicked.connect(on_restart); - - bbox.pack_start(start_button, false, true, 0); - bbox.pack_start(stop_button, false, true, 0); - bbox.pack_start(restart_button, false, true, 0); - bbox.pack_start(reload_button, false, true, 0); - - bbox = new HButtonBox(); - bbox.set_layout(ButtonBoxStyle.START); - bbox.set_spacing(6); - job_vbox.pack_start(bbox, false, true, 0); - - cancel_button = new Button.with_mnemonic("_Cancel"); - - cancel_button.clicked.connect(on_cancel); - - bbox.pack_start(cancel_button, false, true, 0); - - manager = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1"); - - manager.unit_new.connect(on_unit_new); - manager.job_new.connect(on_job_new); - manager.unit_removed.connect(on_unit_removed); - manager.job_removed.connect(on_job_removed); - - manager.subscribe(); - - clear_unit(); - clear_job(); - populate_unit_model(); - populate_job_model(); - } - - public void populate_unit_model() throws IOError { - unit_model.clear(); - - var list = manager.list_units(); - - foreach (var i in list) { - TreeIter iter; - - Properties p = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - i.unit_path); - - p.properties_changed.connect(on_unit_changed); - - Unit u = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - i.unit_path); - - unit_model.append(out iter); - unit_model.set(iter, - 0, i.id, - 1, i.description, - 2, i.load_state, - 3, i.active_state, - 4, i.sub_state, - 5, i.job_type != "" ? "→ %s".printf(i.job_type) : "", - 6, u); - } - } - - public void populate_job_model() throws IOError { - job_model.clear(); - - var list = manager.list_jobs(); - - foreach (var i in list) { - TreeIter iter; - - Properties p = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - i.job_path); - - p.properties_changed.connect(on_job_changed); - - Job j = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - i.job_path); - - job_model.append(out iter); - job_model.set(iter, - 0, "%u".printf(i.id), - 1, i.name, - 2, "→ %s".printf(i.type), - 3, i.state, - 4, j, - 5, i.id); - } - } - - public Unit? get_current_unit() { - TreePath p; - unit_view.get_cursor(out p, null); - - if (p == null) - return null; - - TreeModel model = unit_view.get_model(); - TreeIter iter; - Unit u; - - model.get_iter(out iter, p); - model.get(iter, 6, out u); - - return u; - } - - public void unit_changed() { - Unit u = get_current_unit(); - - if (u == null) - clear_unit(); - else - show_unit(u); - } - - public void clear_unit() { - current_unit_id = null; - - start_button.set_sensitive(false); - stop_button.set_sensitive(false); - reload_button.set_sensitive(false); - restart_button.set_sensitive(false); - - unit_id_label.set_text_or_na(); - unit_aliases_label.set_text_or_na(); - unit_description_label.set_text_or_na(); - unit_description_label.set_text_or_na(); - unit_load_state_label.set_text_or_na(); - unit_active_state_label.set_text_or_na(); - unit_sub_state_label.set_text_or_na(); - unit_fragment_path_label.set_text_or_na(); - unit_active_enter_timestamp_label.set_text_or_na(); - unit_active_exit_timestamp_label.set_text_or_na(); - unit_can_reload_label.set_text_or_na(); - unit_can_start_label.set_text_or_na(); - unit_cgroup_label.set_text_or_na(); - } - - public string make_dependency_string(string? prefix, string word, string[] dependencies) { - bool first = true; - string r; - - if (prefix == null) - r = ""; - else - r = prefix; - - foreach (string i in dependencies) { - if (r != "") - r += first ? "\n" : ","; - - if (first) { - r += word; - first = false; - } - - r += " " + i + ""; - } - - return r; - } - - public void show_unit(Unit unit) { - current_unit_id = unit.id; - - unit_id_label.set_text_or_na(current_unit_id); - - string a = ""; - foreach (string i in unit.names) { - if (i == current_unit_id) - continue; - - if (a == "") - a = i; - else - a += "\n" + i; - } - - unit_aliases_label.set_text_or_na(a); - - string[] - requires = unit.requires, - requires_overridable = unit.requires_overridable, - requisite = unit.requisite, - requisite_overridable = unit.requisite_overridable, - wants = unit.wants, - required_by = unit.required_by, - required_by_overridable = unit.required_by_overridable, - wanted_by = unit.wanted_by, - conflicts = unit.conflicts, - before = unit.before, - after = unit.after; - - unit_dependency_label.set_markup_or_na( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string( - make_dependency_string(null, - "requires", requires), - "overridable requires", requires_overridable), - "requisite", requisite), - "overridable requisite", requisite_overridable), - "wants", wants), - "conflicts", conflicts), - "required by", required_by), - "overridable required by", required_by_overridable), - "wanted by", wanted_by), - "after", after), - "before", before)); - - unit_description_label.set_text_or_na(unit.description); - unit_load_state_label.set_text_or_na(unit.load_state); - unit_active_state_label.set_text_or_na(unit.active_state); - unit_sub_state_label.set_text_or_na(unit.sub_state); - - string fp = unit.fragment_path; - if (fp != "") - unit_fragment_path_label.set_markup_or_na("" + fp + "" ); - else - unit_fragment_path_label.set_text_or_na(); - - uint64 t = unit.active_enter_timestamp; - if (t > 0) { - Time timestamp = Time.local((time_t) (t / 1000000)); - unit_active_enter_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z")); - } else - unit_active_enter_timestamp_label.set_text_or_na(); - - t = unit.active_exit_timestamp; - if (t > 0) { - Time timestamp = Time.local((time_t) (t / 1000000)); - unit_active_exit_timestamp_label.set_text_or_na(timestamp.format("%a, %d %b %Y %H:%M:%S %z")); - } else - unit_active_exit_timestamp_label.set_text_or_na(); - - bool b = unit.can_start; - start_button.set_sensitive(b); - stop_button.set_sensitive(b); - restart_button.set_sensitive(b); - unit_can_start_label.set_text_or_na(b ? "Yes" : "No"); - - b = unit.can_reload; - reload_button.set_sensitive(b); - unit_can_reload_label.set_text_or_na(b ? "Yes" : "No"); - - unit_cgroup_label.set_text_or_na(unit.default_control_group); - } - - public Job? get_current_job() { - TreePath p; - job_view.get_cursor(out p, null); - - if (p == null) - return null; - - TreeIter iter; - TreeModel model = job_view.get_model(); - Job *j; - - model.get_iter(out iter, p); - model.get(iter, 4, out j); - - return j; - } - - public void job_changed() { - Job j = get_current_job(); - - if (j == null) - clear_job(); - else - show_job(j); - } - - public void clear_job() { - current_job_id = 0; - - job_id_label.set_text_or_na(); - job_state_label.set_text_or_na(); - job_type_label.set_text_or_na(); - - cancel_button.set_sensitive(false); - } - - public void show_job(Job job) { - current_job_id = job.id; - - job_id_label.set_text_or_na("%u".printf(current_job_id)); - job_state_label.set_text_or_na(job.state); - job_type_label.set_text_or_na(job.job_type); - - cancel_button.set_sensitive(true); - } - - public void on_start() { - Unit u = get_current_unit(); - - if (u == null) - return; - - try { - u.start("replace"); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_stop() { - Unit u = get_current_unit(); - - if (u == null) - return; - - try { - u.stop("replace"); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_reload() { - Unit u = get_current_unit(); - - if (u == null) - return; - - try { - u.reload("replace"); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_restart() { - Unit u = get_current_unit(); - - if (u == null) - return; - - try { - u.restart("replace"); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_cancel() { - Job j = get_current_job(); - - if (j == null) - return; - - try { - j.cancel(); - } catch (IOError e) { - show_error(e.message); - } - } - - public void update_unit_iter(TreeIter iter, string id, Unit u) { - - try { - string t = ""; - Unit.JobLink jl = u.job; - - if (jl.id != 0) { - Job j = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - jl.path); - - t = j.job_type; - } - - unit_model.set(iter, - 0, id, - 1, u.description, - 2, u.load_state, - 3, u.active_state, - 4, u.sub_state, - 5, t != "" ? "→ %s".printf(t) : "", - 6, u); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_unit_new(string id, ObjectPath path) { - try { - - Properties p = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - p.properties_changed.connect(on_unit_changed); - - TreeIter iter; - unit_model.append(out iter); - - Unit u = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - update_unit_iter(iter, id, u); - } catch (IOError e) { - show_error(e.message); - } - } - - public void update_job_iter(TreeIter iter, uint32 id, Job j) { - job_model.set(iter, - 0, "%u".printf(id), - 1, j.unit.id, - 2, "→ %s".printf(j.job_type), - 3, j.state, - 4, j, - 5, id); - } - - public void on_job_new(uint32 id, ObjectPath path) { - - try { - - Properties p = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - p.properties_changed.connect(on_job_changed); - - TreeIter iter; - job_model.append(out iter); - - Job j = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - update_job_iter(iter, id, j); - - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_unit_removed(string id, ObjectPath path) { - TreeIter iter; - if (!(unit_model.get_iter_first(out iter))) - return; - - do { - string name; - - unit_model.get(iter, 0, out name); - - if (id == name) { - if (current_unit_id == name) - clear_unit(); - - unit_model.remove(iter); - break; - } - - } while (unit_model.iter_next(ref iter)); - } - - public void on_job_removed(uint32 id, ObjectPath path, string res) { - TreeIter iter; - if (!(job_model.get_iter_first(out iter))) - return; - - do { - uint32 j; - - job_model.get(iter, 5, out j); - - if (id == j) { - if (current_job_id == j) - clear_job(); - - job_model.remove(iter); - - break; - } - - } while (job_model.iter_next(ref iter)); - } - - public void on_unit_changed(Properties p, string iface, HashTable changed_properties, string[] invalidated_properties) { - - try { - TreeIter iter; - string id; - - Unit u = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - p.get_name(), - p.get_object_path()); - - if (!(unit_model.get_iter_first(out iter))) - return; - - id = u.id; - - do { - string name; - - unit_model.get(iter, 0, out name); - - if (id == name) { - update_unit_iter(iter, id, u); - - if (current_unit_id == id) - show_unit(u); - - break; - } - - } while (unit_model.iter_next(ref iter)); - - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_job_changed(Properties p, string iface, HashTable changed_properties, string[] invalidated_properties) { - try { - TreeIter iter; - uint32 id; - - Job j = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - p.get_name(), - p.get_object_path()); - - if (!(job_model.get_iter_first(out iter))) - return; - - id = j.id; - - do { - uint32 k; - - job_model.get(iter, 5, out k); - - if (id == k) { - update_job_iter(iter, id, j); - - if (current_job_id == id) - show_job(j); - - break; - } - - } while (job_model.iter_next(ref iter)); - - } catch (IOError e) { - show_error(e.message); - } - } - - public bool unit_filter(TreeModel model, TreeIter iter) { - string id, active_state, job; - - model.get(iter, 0, out id, 3, out active_state, 5, out job); - - if (id == null) - return false; - - switch (unit_type_combo_box.get_active()) { - - case 0: - return true; - - case 1: - return active_state != "inactive" || job != ""; - - case 2: - return id.has_suffix(".service"); - - case 3: - return id.has_suffix(".socket"); - - case 4: - return id.has_suffix(".device"); - - case 5: - return id.has_suffix(".mount"); - - case 6: - return id.has_suffix(".automount"); - - case 7: - return id.has_suffix(".target"); - - case 8: - return id.has_suffix(".snapshot"); - } - - return false; - } - - public void unit_type_changed() { - TreeModelFilter model = (TreeModelFilter) unit_view.get_model(); - - model.refilter(); - } - - public void on_server_reload() { - try { - manager.reload(); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_server_snapshot() { - try { - manager.create_snapshot(); - - if (unit_type_combo_box.get_active() != 0) - unit_type_combo_box.set_active(8); - - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_unit_load() { - string t = unit_load_entry.get_text(); - - if (t == "") - return; - - try { - var path = manager.load_unit(t); - - Unit u = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - var m = new MessageDialog(this, - DialogFlags.DESTROY_WITH_PARENT, - MessageType.INFO, - ButtonsType.CLOSE, - "Unit available as id %s", u.id); - m.title = "Unit"; - m.run(); - m.destroy(); - - show_unit(u); - } catch (IOError e) { - show_error(e.message); - } - } - - public void on_unit_load_entry_changed() { - unit_load_button.set_sensitive(unit_load_entry.get_text() != ""); - } - - public bool on_activate_link(string uri) { - - try { - string path = manager.get_unit(uri); - - Unit u = Bus.get_proxy_sync( - user ? BusType.SESSION : BusType.SYSTEM, - "org.freedesktop.systemd1", - path); - - show_unit(u); - } catch (IOError e) { - show_error(e.message); - } - - return true; - } - - public void show_error(string e) { - var m = new MessageDialog(this, - DialogFlags.DESTROY_WITH_PARENT, - MessageType.ERROR, - ButtonsType.CLOSE, "%s", e); - m.title = "Error"; - m.run(); - m.destroy(); - } - -} - -static const OptionEntry entries[] = { - { "user", 0, 0, OptionArg.NONE, out user, "Connect to user service manager", null }, - { "system", 0, OptionFlags.REVERSE, OptionArg.NONE, out user, "Connect to system manager", null }, - { null } -}; - -void show_error(string e) { - var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e); - m.run(); - m.destroy(); -} - -int main(string[] args) { - - try { - Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm"); - - MainWindow window = new MainWindow(); - window.show_all(); - - Gtk.main(); - } catch (IOError e) { - show_error(e.message); - } catch (GLib.Error e) { - stderr.printf("%s\n", e.message); - } - - return 0; -} diff --git a/src/systemctl-bash-completion.sh b/src/systemctl-bash-completion.sh deleted file mode 100644 index 6369a6c..0000000 --- a/src/systemctl-bash-completion.sh +++ /dev/null @@ -1,150 +0,0 @@ -# This file is part of systemd. -# -# Copyright 2010 Ran Benita -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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 General Public License -# along with systemd; If not, see . - -__contains_word () { - local word=$1; shift - for w in $*; do [[ $w = $word ]] && return 0; done - return 1 -} - -__filter_units_by_property () { - local property=$1 value=$2 ; shift ; shift - local -a units=( $* ) - local -a props=( $(systemctl show --property "$property" -- ${units[*]} | grep -v ^$) ) - for ((i=0; $i < ${#units[*]}; i++)); do - if [[ "${props[i]}" = "$property=$value" ]]; then - echo "${units[i]}" - fi - done -} - -__get_all_units () { systemctl list-units --full --all | awk ' {print $1}' ; } -__get_active_units () { systemctl list-units --full | awk ' {print $1}' ; } -__get_inactive_units () { systemctl list-units --full --all | awk '$3 == "inactive" {print $1}' ; } -__get_failed_units () { systemctl list-units --full | awk '$3 == "failed" {print $1}' ; } - -_systemctl () { - local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} - local verb comps - - local -A OPTS=( - [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global - --help -h --no-ask-password --no-block --no-pager --no-reload --no-wall - --order --require --quiet -q --privileged -P --system --user --version' - [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t' - ) - - if __contains_word "$prev" ${OPTS[ARG]}; then - case $prev in - --signal|-s) - comps=$(compgen -A signal | grep '^SIG' | grep -Ev 'RTMIN|RTMAX|JUNK') - ;; - --type|-t) - comps='automount device mount path service snapshot socket swap target timer' - ;; - --kill-who) - comps='all control main' - ;; - --kill-mode) - comps='control-group process' - ;; - --property|-p|--host|-H) - comps='' - ;; - esac - COMPREPLY=( $(compgen -W "$comps" -- "$cur") ) - return 0 - fi - - - if [[ "$cur" = -* ]]; then - COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) - return 0 - fi - - local -A VERBS=( - [ALL_UNITS]='enable disable is-active is-enabled status show' - [FAILED_UNITS]='reset-failed' - [STARTABLE_UNITS]='start' - [STOPPABLE_UNITS]='stop kill try-restart condrestart' - [ISOLATABLE_UNITS]='isolate' - [RELOADABLE_UNITS]='reload reload-or-try-restart force-reload' - [RESTARTABLE_UNITS]='restart reload-or-restart' - [JOBS]='cancel' - [SNAPSHOTS]='delete' - [ENVS]='set-environment unset-environment' - [STANDALONE]='daemon-reexec daemon-reload default dot dump emergency exit halt kexec - list-jobs list-units poweroff reboot rescue show-environment' - [NAME]='snapshot load' - ) - - local verb - 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[ALL_UNITS]}; then - comps=$( __get_all_units ) - - elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then - comps=$( __filter_units_by_property CanStart yes \ - $( __get_inactive_units | grep -Ev '\.(device|snapshot)$' )) - - elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then - comps=$( __filter_units_by_property CanStart yes \ - $( __get_all_units | grep -Ev '\.(device|snapshot|socket|timer)$' )) - - elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then - comps=$( __filter_units_by_property CanStop yes \ - $( __get_active_units ) ) - - elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then - comps=$( __filter_units_by_property CanReload yes \ - $( __get_active_units ) ) - - elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then - comps=$( __filter_units_by_property AllowIsolate yes \ - $( __get_all_units ) ) - - elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then - comps=$( __get_failed_units ) - - elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then - comps='' - - elif __contains_word "$verb" ${VERBS[JOBS]}; then - comps=$( systemctl list-jobs | awk '{print $1}' ) - - elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then - comps=$( systemctl list-units --type snapshot --full --all | awk '{print $1}' ) - - elif __contains_word "$verb" ${VERBS[ENVS]}; then - comps=$( systemctl show-environment | sed 's_\([^=]\+=\).*_\1_' ) - compopt -o nospace - fi - - COMPREPLY=( $(compgen -W "$comps" -- "$cur") ) - return 0 -} -complete -F _systemctl systemctl diff --git a/src/systemctl.c b/src/systemctl.c deleted file mode 100644 index 0de2444..0000000 --- a/src/systemctl.c +++ /dev/null @@ -1,5296 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "macro.h" -#include "set.h" -#include "utmp-wtmp.h" -#include "special.h" -#include "initreq.h" -#include "strv.h" -#include "dbus-common.h" -#include "cgroup-show.h" -#include "cgroup-util.h" -#include "list.h" -#include "path-lookup.h" -#include "conf-parser.h" -#include "sd-daemon.h" -#include "shutdownd.h" -#include "exit-status.h" -#include "bus-errors.h" -#include "build.h" -#include "unit-name.h" -#include "pager.h" -#include "spawn-agent.h" -#include "install.h" - -static const char *arg_type = NULL; -static char **arg_property = NULL; -static bool arg_all = false; -static const char *arg_job_mode = "replace"; -static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; -static bool arg_immediate = false; -static bool arg_no_block = false; -static bool arg_no_legend = false; -static bool arg_no_pager = false; -static bool arg_no_wtmp = false; -static bool arg_no_sync = false; -static bool arg_no_wall = false; -static bool arg_no_reload = false; -static bool arg_dry = false; -static bool arg_quiet = false; -static bool arg_full = false; -static bool arg_force = false; -static bool arg_ask_password = false; -static bool arg_failed = false; -static bool arg_runtime = false; -static char **arg_wall = NULL; -static const char *arg_kill_who = NULL; -static const char *arg_kill_mode = NULL; -static int arg_signal = SIGTERM; -static const char *arg_root = NULL; -static usec_t arg_when = 0; -static enum action { - ACTION_INVALID, - ACTION_SYSTEMCTL, - ACTION_HALT, - ACTION_POWEROFF, - ACTION_REBOOT, - ACTION_KEXEC, - ACTION_EXIT, - ACTION_RUNLEVEL2, - ACTION_RUNLEVEL3, - ACTION_RUNLEVEL4, - ACTION_RUNLEVEL5, - ACTION_RESCUE, - ACTION_EMERGENCY, - ACTION_DEFAULT, - ACTION_RELOAD, - ACTION_REEXEC, - ACTION_RUNLEVEL, - ACTION_CANCEL_SHUTDOWN, - _ACTION_MAX -} arg_action = ACTION_SYSTEMCTL; -static enum dot { - DOT_ALL, - DOT_ORDER, - DOT_REQUIRE -} arg_dot = DOT_ALL; -static enum transport { - TRANSPORT_NORMAL, - TRANSPORT_SSH, - TRANSPORT_POLKIT -} arg_transport = TRANSPORT_NORMAL; -static const char *arg_host = NULL; - -static bool private_bus = false; - -static int daemon_reload(DBusConnection *bus, char **args); - -static bool on_tty(void) { - static int t = -1; - - /* Note that this is invoked relatively early, before we start - * the pager. That means the value we return reflects whether - * we originally were started on a tty, not if we currently - * are. But this is intended, since we want colour and so on - * when run in our own pager. */ - - if (_unlikely_(t < 0)) - t = isatty(STDOUT_FILENO) > 0; - - return t; -} - -static void pager_open_if_enabled(void) { - - /* Cache result before we open the pager */ - on_tty(); - - if (arg_no_pager) - return; - - pager_open(); -} - -static void agent_open_if_enabled(void) { - - /* Open the password agent as a child process if necessary */ - - if (!arg_ask_password) - return; - - if (arg_scope != UNIT_FILE_SYSTEM) - return; - - agent_open(); -} - -static const char *ansi_highlight(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF; -} - -static const char *ansi_highlight_green(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF; -} - -static bool error_is_no_service(const DBusError *error) { - assert(error); - - if (!dbus_error_is_set(error)) - return false; - - if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER)) - return true; - - if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN)) - return true; - - return startswith(error->name, "org.freedesktop.DBus.Error.Spawn."); -} - -static int translate_bus_error_to_exit_status(int r, const DBusError *error) { - assert(error); - - if (!dbus_error_is_set(error)) - return r; - - if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) || - dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) || - dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) || - dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE)) - return EXIT_NOPERMISSION; - - if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT)) - return EXIT_NOTINSTALLED; - - if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) || - dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED)) - return EXIT_NOTIMPLEMENTED; - - if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) - return EXIT_NOTCONFIGURED; - - if (r != 0) - return r; - - return EXIT_FAILURE; -} - -static void warn_wall(enum action action) { - static const char *table[_ACTION_MAX] = { - [ACTION_HALT] = "The system is going down for system halt NOW!", - [ACTION_REBOOT] = "The system is going down for reboot NOW!", - [ACTION_POWEROFF] = "The system is going down for power-off NOW!", - [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!", - [ACTION_RESCUE] = "The system is going down to rescue mode NOW!", - [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!" - }; - - if (arg_no_wall) - return; - - if (arg_wall) { - char *p; - - if (!(p = strv_join(arg_wall, " "))) { - log_error("Failed to join strings."); - return; - } - - if (*p) { - utmp_wall(p, NULL); - free(p); - return; - } - - free(p); - } - - if (!table[action]) - return; - - utmp_wall(table[action], NULL); -} - -static bool avoid_bus(void) { - - if (running_in_chroot() > 0) - return true; - - if (sd_booted() <= 0) - return true; - - if (!isempty(arg_root)) - return true; - - if (arg_scope == UNIT_FILE_GLOBAL) - return true; - - return false; -} - -struct unit_info { - const char *id; - const char *description; - const char *load_state; - const char *active_state; - const char *sub_state; - const char *following; - const char *unit_path; - uint32_t job_id; - const char *job_type; - const char *job_path; -}; - -static int compare_unit_info(const void *a, const void *b) { - const char *d1, *d2; - const struct unit_info *u = a, *v = b; - - d1 = strrchr(u->id, '.'); - d2 = strrchr(v->id, '.'); - - if (d1 && d2) { - int r; - - if ((r = strcasecmp(d1, d2)) != 0) - return r; - } - - return strcasecmp(u->id, v->id); -} - -static bool output_show_unit(const struct unit_info *u) { - const char *dot; - - if (arg_failed) - return streq(u->active_state, "failed"); - - return (!arg_type || ((dot = strrchr(u->id, '.')) && - streq(dot+1, arg_type))) && - (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); -} - -static void output_units_list(const struct unit_info *unit_infos, unsigned c) { - unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0; - const struct unit_info *u; - - max_id_len = sizeof("UNIT")-1; - active_len = sizeof("ACTIVE")-1; - sub_len = sizeof("SUB")-1; - job_len = sizeof("JOB")-1; - desc_len = 0; - - for (u = unit_infos; u < unit_infos + c; u++) { - if (!output_show_unit(u)) - continue; - - max_id_len = MAX(max_id_len, strlen(u->id)); - active_len = MAX(active_len, strlen(u->active_state)); - sub_len = MAX(sub_len, strlen(u->sub_state)); - if (u->job_id != 0) - job_len = MAX(job_len, strlen(u->job_type)); - } - - if (!arg_full) { - unsigned basic_len; - id_len = MIN(max_id_len, 25); - basic_len = 5 + id_len + 6 + active_len + sub_len + job_len; - if (basic_len < (unsigned) columns()) { - unsigned extra_len, incr; - extra_len = columns() - basic_len; - /* Either UNIT already got 25, or is fully satisfied. - * Grant up to 25 to DESC now. */ - incr = MIN(extra_len, 25); - desc_len += incr; - extra_len -= incr; - /* split the remaining space between UNIT and DESC, - * but do not give UNIT more than it needs. */ - if (extra_len > 0) { - incr = MIN(extra_len / 2, max_id_len - id_len); - id_len += incr; - desc_len += extra_len - incr; - } - } - } else - id_len = max_id_len; - - if (!arg_no_legend) { - printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD", - active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB"); - if (!arg_full && arg_no_pager) - printf("%.*s\n", desc_len, "DESCRIPTION"); - else - printf("%s\n", "DESCRIPTION"); - } - - for (u = unit_infos; u < unit_infos + c; u++) { - char *e; - const char *on_loaded, *off_loaded; - const char *on_active, *off_active; - - if (!output_show_unit(u)) - continue; - - n_shown++; - - if (!streq(u->load_state, "loaded") && - !streq(u->load_state, "banned")) { - on_loaded = ansi_highlight(true); - off_loaded = ansi_highlight(false); - } else - on_loaded = off_loaded = ""; - - if (streq(u->active_state, "failed")) { - on_active = ansi_highlight(true); - off_active = ansi_highlight(false); - } else - on_active = off_active = ""; - - e = arg_full ? NULL : ellipsize(u->id, id_len, 33); - - printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ", - id_len, e ? e : u->id, - on_loaded, u->load_state, off_loaded, - on_active, active_len, u->active_state, - sub_len, u->sub_state, off_active, - job_len, u->job_id ? u->job_type : ""); - if (!arg_full && arg_no_pager) - printf("%.*s\n", desc_len, u->description); - else - printf("%s\n", u->description); - - free(e); - } - - if (!arg_no_legend) { - printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n" - "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" - "SUB = The low-level unit activation state, values depend on unit type.\n" - "JOB = Pending job for the unit.\n"); - - if (arg_all) - printf("\n%u units listed.\n", n_shown); - else - printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown); - } -} - -static int list_units(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned c = 0, n_units = 0; - struct unit_info *unit_infos = NULL; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListUnits"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - struct unit_info *u; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (c >= n_units) { - struct unit_info *w; - - n_units = MAX(2*c, 16); - w = realloc(unit_infos, sizeof(struct unit_info) * n_units); - - if (!w) { - log_error("Failed to allocate unit array."); - r = -ENOMEM; - goto finish; - } - - unit_infos = w; - } - - u = unit_infos+c; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_next(&sub); - c++; - } - - if (c > 0) { - qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info); - output_units_list(unit_infos, c); - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - free(unit_infos); - - dbus_error_free(&error); - - return r; -} - -static int compare_unit_file_list(const void *a, const void *b) { - const char *d1, *d2; - const UnitFileList *u = a, *v = b; - - d1 = strrchr(u->path, '.'); - d2 = strrchr(v->path, '.'); - - if (d1 && d2) { - int r; - - r = strcasecmp(d1, d2); - if (r != 0) - return r; - } - - return strcasecmp(file_name_from_path(u->path), file_name_from_path(v->path)); -} - -static bool output_show_unit_file(const UnitFileList *u) { - const char *dot; - - return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type)); -} - -static void output_unit_file_list(const UnitFileList *units, unsigned c) { - unsigned n_shown = 0; - const UnitFileList *u; - - if (on_tty()) - printf("%-25s %-6s\n", "UNIT FILE", "STATE"); - - for (u = units; u < units + c; u++) { - char *e; - const char *on, *off; - const char *id; - - if (!output_show_unit_file(u)) - continue; - - n_shown++; - - if (u->state == UNIT_FILE_MASKED || - u->state == UNIT_FILE_MASKED_RUNTIME || - u->state == UNIT_FILE_DISABLED) { - on = ansi_highlight(true); - off = ansi_highlight(false); - } else if (u->state == UNIT_FILE_ENABLED) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); - } else - on = off = ""; - - id = file_name_from_path(u->path); - - e = arg_full ? NULL : ellipsize(id, 25, 33); - - printf("%-25s %s%-6s%s\n", - e ? e : id, - on, unit_file_state_to_string(u->state), off); - - free(e); - } - - if (on_tty()) - printf("\n%u unit files listed.\n", n_shown); -} - -static int list_unit_files(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned c = 0, n_units = 0; - UnitFileList *units = NULL; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - if (avoid_bus()) { - Hashmap *h; - UnitFileList *u; - Iterator i; - - h = hashmap_new(string_hash_func, string_compare_func); - if (!h) { - log_error("Out of memory"); - return -ENOMEM; - } - - r = unit_file_get_list(arg_scope, arg_root, h); - if (r < 0) { - unit_file_list_free(h); - log_error("Failed to get unit file list: %s", strerror(-r)); - return r; - } - - n_units = hashmap_size(h); - units = new(UnitFileList, n_units); - if (!units) { - unit_file_list_free(h); - log_error("Out of memory"); - return -ENOMEM; - } - - HASHMAP_FOREACH(u, h, i) { - memcpy(units + c++, u, sizeof(UnitFileList)); - free(u); - } - - hashmap_free(h); - } else { - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListUnitFiles"); - if (!m) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - UnitFileList *u; - const char *state; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (c >= n_units) { - UnitFileList *w; - - n_units = MAX(2*c, 16); - w = realloc(units, sizeof(struct UnitFileList) * n_units); - - if (!w) { - log_error("Failed to allocate unit array."); - r = -ENOMEM; - goto finish; - } - - units = w; - } - - u = units+c; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - u->state = unit_file_state_from_string(state); - - dbus_message_iter_next(&sub); - c++; - } - } - - if (c > 0) { - qsort(units, c, sizeof(UnitFileList), compare_unit_file_list); - output_unit_file_list(units, c); - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - free(units); - - dbus_error_free(&error); - - return r; -} - -static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) { - static const char * const colors[] = { - "Requires", "[color=\"black\"]", - "RequiresOverridable", "[color=\"black\"]", - "Requisite", "[color=\"darkblue\"]", - "RequisiteOverridable", "[color=\"darkblue\"]", - "Wants", "[color=\"darkgrey\"]", - "Conflicts", "[color=\"red\"]", - "ConflictedBy", "[color=\"red\"]", - "After", "[color=\"green\"]" - }; - - const char *c = NULL; - unsigned i; - - assert(name); - assert(prop); - assert(iter); - - for (i = 0; i < ELEMENTSOF(colors); i += 2) - if (streq(colors[i], prop)) { - c = colors[i+1]; - break; - } - - if (!c) - return 0; - - if (arg_dot != DOT_ALL) - if ((arg_dot == DOT_ORDER) != streq(prop, "After")) - return 0; - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - printf("\t\"%s\"->\"%s\" %s;\n", name, s, c); - - dbus_message_iter_next(&sub); - } - - return 0; - } - } - - return 0; -} - -static int dot_one(DBusConnection *bus, const char *name, const char *path) { - DBusMessage *m = NULL, *reply = NULL; - const char *interface = "org.freedesktop.systemd1.Unit"; - int r; - DBusError error; - DBusMessageIter iter, sub, sub2, sub3; - - assert(bus); - assert(path); - - dbus_error_init(&error); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "GetAll"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *prop; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub2, &sub3); - - if (dot_one_property(name, prop, &sub3)) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_next(&sub); - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int dot(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - - dbus_error_init(&error); - - assert(bus); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListUnits"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - printf("digraph systemd {\n"); - - dbus_message_iter_recurse(&iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if ((r = dot_one(bus, id, unit_path)) < 0) - goto finish; - - /* printf("\t\"%s\";\n", id); */ - dbus_message_iter_next(&sub); - } - - printf("}\n"); - - log_info(" Color legend: black = Requires\n" - " dark blue = Requisite\n" - " dark grey = Wants\n" - " red = Conflicts\n" - " green = After\n"); - - if (on_tty()) - log_notice("-- You probably want to process this output with graphviz' dot tool.\n" - "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n"); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int list_jobs(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - DBusMessageIter iter, sub, sub2; - unsigned k = 0; - - dbus_error_init(&error); - - assert(bus); - - pager_open_if_enabled(); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListJobs"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (on_tty()) - printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE"); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *name, *type, *state, *job_path, *unit_path; - uint32_t id; - char *e; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - e = arg_full ? NULL : ellipsize(name, 25, 33); - printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state); - free(e); - - k++; - - dbus_message_iter_next(&sub); - } - - if (on_tty()) - printf("\n%u jobs listed.\n", k); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int load_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL; - DBusError error; - int r; - char **name; - - dbus_error_init(&error); - - assert(bus); - assert(args); - - STRV_FOREACH(name, args+1) { - DBusMessage *reply; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "LoadUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - - m = reply = NULL; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return r; -} - -static int cancel_job(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - char **name; - - dbus_error_init(&error); - - assert(bus); - assert(args); - - if (strv_length(args) <= 1) - return daemon_reload(bus, args); - - STRV_FOREACH(name, args+1) { - unsigned id; - const char *path; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetJob"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if ((r = safe_atou(*name, &id)) < 0) { - log_error("Failed to parse job id: %s", strerror(-r)); - goto finish; - } - - assert_cc(sizeof(uint32_t) == sizeof(id)); - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Job", - "Cancel"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static bool need_daemon_reload(DBusConnection *bus, const char *unit) { - DBusMessage *m = NULL, *reply = NULL; - dbus_bool_t b = FALSE; - DBusMessageIter iter, sub; - const char - *interface = "org.freedesktop.systemd1.Unit", - *property = "NeedDaemonReload", - *path; - - /* We ignore all errors here, since this is used to show a warning only */ - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) - goto finish; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &unit, - DBUS_TYPE_INVALID)) - goto finish; - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL))) - goto finish; - - if (!dbus_message_get_args(reply, NULL, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) - goto finish; - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "Get"))) - goto finish; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL))) - goto finish; - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) - goto finish; - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) - goto finish; - - dbus_message_iter_get_basic(&sub, &b); - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return b; -} - -typedef struct WaitData { - Set *set; - char *result; -} WaitData; - -static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) { - DBusError error; - WaitData *d = data; - - assert(connection); - assert(message); - assert(d); - - dbus_error_init(&error); - - log_debug("Got D-Bus request: %s.%s() on %s", - dbus_message_get_interface(message), - dbus_message_get_member(message), - dbus_message_get_path(message)); - - if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - log_error("Warning! D-Bus connection terminated."); - dbus_connection_close(connection); - - } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { - uint32_t id; - const char *path, *result; - dbus_bool_t success = true; - - if (dbus_message_get_args(message, &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_STRING, &result, - DBUS_TYPE_INVALID)) { - char *p; - - if ((p = set_remove(d->set, (char*) path))) - free(p); - - if (*result) - d->result = strdup(result); - - goto finish; - } -#ifndef LEGACY - dbus_error_free(&error); - - if (dbus_message_get_args(message, &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_BOOLEAN, &success, - DBUS_TYPE_INVALID)) { - char *p; - - /* Compatibility with older systemd versions < - * 19 during upgrades. This should be dropped - * one day */ - - if ((p = set_remove(d->set, (char*) path))) - free(p); - - if (!success) - d->result = strdup("failed"); - - goto finish; - } -#endif - - log_error("Failed to parse message: %s", bus_error_message(&error)); - } - -finish: - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static int enable_wait_for_jobs(DBusConnection *bus) { - DBusError error; - - assert(bus); - - if (private_bus) - return 0; - - dbus_error_init(&error); - dbus_bus_add_match(bus, - "type='signal'," - "sender='org.freedesktop.systemd1'," - "interface='org.freedesktop.systemd1.Manager'," - "member='JobRemoved'," - "path='/org/freedesktop/systemd1'", - &error); - - if (dbus_error_is_set(&error)) { - log_error("Failed to add match: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -EIO; - } - - /* This is slightly dirty, since we don't undo the match registrations. */ - return 0; -} - -static int wait_for_jobs(DBusConnection *bus, Set *s) { - int r; - WaitData d; - - assert(bus); - assert(s); - - zero(d); - d.set = s; - - if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) { - log_error("Failed to add filter."); - r = -ENOMEM; - goto finish; - } - - while (!set_isempty(s) && - dbus_connection_read_write_dispatch(bus, -1)) - ; - - if (!arg_quiet && d.result) { - if (streq(d.result, "timeout")) - log_error("Job timed out."); - else if (streq(d.result, "canceled")) - log_error("Job canceled."); - else if (streq(d.result, "dependency")) - log_error("A dependency job failed. See system logs for details."); - else if (!streq(d.result, "done") && !streq(d.result, "skipped")) - log_error("Job failed. See system logs and 'systemctl status' for details."); - } - - if (streq_ptr(d.result, "timeout")) - r = -ETIME; - else if (streq_ptr(d.result, "canceled")) - r = -ECANCELED; - else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped")) - r = -EIO; - else - r = 0; - - free(d.result); - -finish: - /* This is slightly dirty, since we don't undo the filter registration. */ - - return r; -} - -static int start_unit_one( - DBusConnection *bus, - const char *method, - const char *name, - const char *mode, - DBusError *error, - Set *s) { - - DBusMessage *m = NULL, *reply = NULL; - const char *path; - int r; - - assert(bus); - assert(method); - assert(name); - assert(mode); - assert(error); - assert(arg_no_block || s); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) { - - if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) { - /* There's always a fallback possible for - * legacy actions. */ - r = -EADDRNOTAVAIL; - goto finish; - } - - log_error("Failed to issue method call: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - if (need_daemon_reload(bus, name)) - log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.", - arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); - - if (!arg_no_block) { - char *p; - - if (!(p = strdup(path))) { - log_error("Failed to duplicate path."); - r = -ENOMEM; - goto finish; - } - - if ((r = set_put(s, p)) < 0) { - free(p); - log_error("Failed to add path to set."); - goto finish; - } - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return r; -} - -static enum action verb_to_action(const char *verb) { - if (streq(verb, "halt")) - return ACTION_HALT; - else if (streq(verb, "poweroff")) - return ACTION_POWEROFF; - else if (streq(verb, "reboot")) - return ACTION_REBOOT; - else if (streq(verb, "kexec")) - return ACTION_KEXEC; - else if (streq(verb, "rescue")) - return ACTION_RESCUE; - else if (streq(verb, "emergency")) - return ACTION_EMERGENCY; - else if (streq(verb, "default")) - return ACTION_DEFAULT; - else if (streq(verb, "exit")) - return ACTION_EXIT; - else - return ACTION_INVALID; -} - -static int start_unit(DBusConnection *bus, char **args) { - - static const char * const table[_ACTION_MAX] = { - [ACTION_HALT] = SPECIAL_HALT_TARGET, - [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET, - [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET, - [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET, - [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET, - [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET, - [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET, - [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET, - [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET, - [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET, - [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET, - [ACTION_EXIT] = SPECIAL_EXIT_TARGET - }; - - int r, ret = 0; - const char *method, *mode, *one_name; - Set *s = NULL; - DBusError error; - char **name; - - dbus_error_init(&error); - - assert(bus); - - agent_open_if_enabled(); - - if (arg_action == ACTION_SYSTEMCTL) { - method = - streq(args[0], "stop") || - streq(args[0], "condstop") ? "StopUnit" : - streq(args[0], "reload") ? "ReloadUnit" : - streq(args[0], "restart") ? "RestartUnit" : - - streq(args[0], "try-restart") || - streq(args[0], "condrestart") ? "TryRestartUnit" : - - streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" : - - streq(args[0], "reload-or-try-restart") || - streq(args[0], "condreload") || - - streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" : - "StartUnit"; - - mode = - (streq(args[0], "isolate") || - streq(args[0], "rescue") || - streq(args[0], "emergency")) ? "isolate" : arg_job_mode; - - one_name = table[verb_to_action(args[0])]; - - } else { - assert(arg_action < ELEMENTSOF(table)); - assert(table[arg_action]); - - method = "StartUnit"; - - mode = (arg_action == ACTION_EMERGENCY || - arg_action == ACTION_RESCUE || - arg_action == ACTION_RUNLEVEL2 || - arg_action == ACTION_RUNLEVEL3 || - arg_action == ACTION_RUNLEVEL4 || - arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace"; - - one_name = table[arg_action]; - } - - if (!arg_no_block) { - if ((ret = enable_wait_for_jobs(bus)) < 0) { - log_error("Could not watch jobs: %s", strerror(-ret)); - goto finish; - } - - if (!(s = set_new(string_hash_func, string_compare_func))) { - log_error("Failed to allocate set."); - ret = -ENOMEM; - goto finish; - } - } - - if (one_name) { - if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0) - goto finish; - } else { - STRV_FOREACH(name, args+1) - if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) { - ret = translate_bus_error_to_exit_status(r, &error); - dbus_error_free(&error); - } - } - - if (!arg_no_block) - if ((r = wait_for_jobs(bus, s)) < 0) { - ret = r; - goto finish; - } - -finish: - if (s) - set_free_free(s); - - dbus_error_free(&error); - - return ret; -} - -static int start_special(DBusConnection *bus, char **args) { - int r; - - assert(bus); - assert(args); - - if (arg_force && - (streq(args[0], "halt") || - streq(args[0], "poweroff") || - streq(args[0], "reboot") || - streq(args[0], "kexec") || - streq(args[0], "exit"))) - return daemon_reload(bus, args); - - r = start_unit(bus, args); - - if (r >= 0) - warn_wall(verb_to_action(args[0])); - - return r; -} - -static int check_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - const char - *interface = "org.freedesktop.systemd1.Unit", - *property = "ActiveState"; - int r = 3; /* According to LSB: "program is not running" */ - DBusError error; - char **name; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - STRV_FOREACH(name, args+1) { - const char *path = NULL; - const char *state; - DBusMessageIter iter, sub; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - /* Hmm, cannot figure out anything about this unit... */ - if (!arg_quiet) - puts("unknown"); - - dbus_error_free(&error); - dbus_message_unref(m); - m = NULL; - continue; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "Get"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&sub, &state); - - if (!arg_quiet) - puts(state); - - if (streq(state, "active") || streq(state, "reloading")) - r = 0; - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int kill_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL; - int r = 0; - DBusError error; - char **name; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - if (!arg_kill_who) - arg_kill_who = "all"; - - if (!arg_kill_mode) - arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process"; - - STRV_FOREACH(name, args+1) { - DBusMessage *reply; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "KillUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_STRING, &arg_kill_who, - DBUS_TYPE_STRING, &arg_kill_mode, - DBUS_TYPE_INT32, &arg_signal, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - dbus_error_free(&error); - r = -EIO; - } - - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return r; -} - -typedef struct ExecStatusInfo { - char *name; - - char *path; - char **argv; - - bool ignore; - - usec_t start_timestamp; - usec_t exit_timestamp; - pid_t pid; - int code; - int status; - - LIST_FIELDS(struct ExecStatusInfo, exec); -} ExecStatusInfo; - -static void exec_status_info_free(ExecStatusInfo *i) { - assert(i); - - free(i->name); - free(i->path); - strv_free(i->argv); - free(i); -} - -static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) { - uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic; - DBusMessageIter sub2, sub3; - const char*path; - unsigned n; - uint32_t pid; - int32_t code, status; - dbus_bool_t ignore; - - assert(i); - assert(i); - - if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT) - return -EIO; - - dbus_message_iter_recurse(sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0) - return -EIO; - - if (!(i->path = strdup(path))) - return -ENOMEM; - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING) - return -EIO; - - n = 0; - dbus_message_iter_recurse(&sub2, &sub3); - while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) { - assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING); - dbus_message_iter_next(&sub3); - n++; - } - - - if (!(i->argv = new0(char*, n+1))) - return -ENOMEM; - - n = 0; - dbus_message_iter_recurse(&sub2, &sub3); - while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub3, &s); - dbus_message_iter_next(&sub3); - - if (!(i->argv[n++] = strdup(s))) - return -ENOMEM; - } - - if (!dbus_message_iter_next(&sub2) || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0) - return -EIO; - - i->ignore = ignore; - i->start_timestamp = (usec_t) start_timestamp; - i->exit_timestamp = (usec_t) exit_timestamp; - i->pid = (pid_t) pid; - i->code = code; - i->status = status; - - return 0; -} - -typedef struct UnitStatusInfo { - const char *id; - const char *load_state; - const char *active_state; - const char *sub_state; - const char *unit_file_state; - - const char *description; - const char *following; - - const char *path; - const char *default_control_group; - - const char *load_error; - - usec_t inactive_exit_timestamp; - usec_t active_enter_timestamp; - usec_t active_exit_timestamp; - usec_t inactive_enter_timestamp; - - bool need_daemon_reload; - - /* Service */ - pid_t main_pid; - pid_t control_pid; - const char *status_text; - bool running:1; -#ifdef HAVE_SYSV_COMPAT - bool is_sysv:1; -#endif - - usec_t start_timestamp; - usec_t exit_timestamp; - - int exit_code, exit_status; - - usec_t condition_timestamp; - bool condition_result; - - /* Socket */ - unsigned n_accepted; - unsigned n_connections; - bool accept; - - /* Device */ - const char *sysfs_path; - - /* Mount, Automount */ - const char *where; - - /* Swap */ - const char *what; - - LIST_HEAD(ExecStatusInfo, exec); -} UnitStatusInfo; - -static void print_status_info(UnitStatusInfo *i) { - ExecStatusInfo *p; - const char *on, *off, *ss; - usec_t timestamp; - char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1; - char since2[FORMAT_TIMESTAMP_MAX], *s2; - - assert(i); - - /* This shows pretty information about a unit. See - * print_property() for a low-level property printer */ - - printf("%s", strna(i->id)); - - if (i->description && !streq_ptr(i->id, i->description)) - printf(" - %s", i->description); - - printf("\n"); - - if (i->following) - printf("\t Follow: unit currently follows state of %s\n", i->following); - - if (streq_ptr(i->load_state, "failed") || - streq_ptr(i->load_state, "banned")) { - on = ansi_highlight(true); - off = ansi_highlight(false); - } else - on = off = ""; - - if (i->load_error) - printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); - else if (i->path && i->unit_file_state) - printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state); - else if (i->path) - printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path); - else - printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off); - - ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; - - if (streq_ptr(i->active_state, "failed")) { - on = ansi_highlight(true); - off = ansi_highlight(false); - } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); - } else - on = off = ""; - - if (ss) - printf("\t Active: %s%s (%s)%s", - on, - strna(i->active_state), - ss, - off); - else - printf("\t Active: %s%s%s", - on, - strna(i->active_state), - off); - - timestamp = (streq_ptr(i->active_state, "active") || - streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp : - (streq_ptr(i->active_state, "inactive") || - streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp : - streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp : - i->active_exit_timestamp; - - s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp); - s2 = format_timestamp(since2, sizeof(since2), timestamp); - - if (s1) - printf(" since %s; %s\n", s2, s1); - else if (s2) - printf(" since %s\n", s2); - else - printf("\n"); - - if (!i->condition_result && i->condition_timestamp > 0) { - s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp); - s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); - - if (s1) - printf("\t start condition failed at %s; %s\n", s2, s1); - else if (s2) - printf("\t start condition failed at %s\n", s2); - } - - if (i->sysfs_path) - printf("\t Device: %s\n", i->sysfs_path); - if (i->where) - printf("\t Where: %s\n", i->where); - if (i->what) - printf("\t What: %s\n", i->what); - - if (i->accept) - printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections); - - LIST_FOREACH(exec, p, i->exec) { - char *t; - bool good; - - /* Only show exited processes here */ - if (p->code == 0) - continue; - - t = strv_join(p->argv, " "); - printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); - free(t); - -#ifdef HAVE_SYSV_COMPAT - if (i->is_sysv) - good = is_clean_exit_lsb(p->code, p->status); - else -#endif - good = is_clean_exit(p->code, p->status); - - if (!good) { - on = ansi_highlight(true); - off = ansi_highlight(false); - } else - on = off = ""; - - printf("%s(code=%s, ", on, sigchld_code_to_string(p->code)); - - if (p->code == CLD_EXITED) { - const char *c; - - printf("status=%i", p->status); - -#ifdef HAVE_SYSV_COMPAT - if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD))) -#else - if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD))) -#endif - printf("/%s", c); - - } else - printf("signal=%s", signal_to_string(p->status)); - - printf(")%s\n", off); - - if (i->main_pid == p->pid && - i->start_timestamp == p->start_timestamp && - i->exit_timestamp == p->start_timestamp) - /* Let's not show this twice */ - i->main_pid = 0; - - if (p->pid == i->control_pid) - i->control_pid = 0; - } - - if (i->main_pid > 0 || i->control_pid > 0) { - printf("\t"); - - if (i->main_pid > 0) { - printf("Main PID: %u", (unsigned) i->main_pid); - - if (i->running) { - char *t = NULL; - get_process_name(i->main_pid, &t); - if (t) { - printf(" (%s)", t); - free(t); - } - } else if (i->exit_code > 0) { - printf(" (code=%s, ", sigchld_code_to_string(i->exit_code)); - - if (i->exit_code == CLD_EXITED) { - const char *c; - - printf("status=%i", i->exit_status); - -#ifdef HAVE_SYSV_COMPAT - if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD))) -#else - if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD))) -#endif - printf("/%s", c); - - } else - printf("signal=%s", signal_to_string(i->exit_status)); - printf(")"); - } - } - - if (i->main_pid > 0 && i->control_pid > 0) - printf(";"); - - if (i->control_pid > 0) { - char *t = NULL; - - printf(" Control: %u", (unsigned) i->control_pid); - - get_process_name(i->control_pid, &t); - if (t) { - printf(" (%s)", t); - free(t); - } - } - - printf("\n"); - } - - if (i->status_text) - printf("\t Status: \"%s\"\n", i->status_text); - - if (i->default_control_group) { - unsigned c; - - printf("\t CGroup: %s\n", i->default_control_group); - - if (arg_transport != TRANSPORT_SSH) { - if ((c = columns()) > 18) - c -= 18; - else - c = 0; - - show_cgroup_by_path(i->default_control_group, "\t\t ", c); - } - } - - if (i->need_daemon_reload) - printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n", - ansi_highlight(true), - ansi_highlight(false), - arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); -} - -static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) { - - assert(name); - assert(iter); - assert(i); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - - dbus_message_iter_get_basic(iter, &s); - - if (!isempty(s)) { - if (streq(name, "Id")) - i->id = s; - else if (streq(name, "LoadState")) - i->load_state = s; - else if (streq(name, "ActiveState")) - i->active_state = s; - else if (streq(name, "SubState")) - i->sub_state = s; - else if (streq(name, "Description")) - i->description = s; - else if (streq(name, "FragmentPath")) - i->path = s; -#ifdef HAVE_SYSV_COMPAT - else if (streq(name, "SysVPath")) { - i->is_sysv = true; - i->path = s; - } -#endif - else if (streq(name, "DefaultControlGroup")) - i->default_control_group = s; - else if (streq(name, "StatusText")) - i->status_text = s; - else if (streq(name, "SysFSPath")) - i->sysfs_path = s; - else if (streq(name, "Where")) - i->where = s; - else if (streq(name, "What")) - i->what = s; - else if (streq(name, "Following")) - i->following = s; - else if (streq(name, "UnitFileState")) - i->unit_file_state = s; - } - - break; - } - - case DBUS_TYPE_BOOLEAN: { - dbus_bool_t b; - - dbus_message_iter_get_basic(iter, &b); - - if (streq(name, "Accept")) - i->accept = b; - else if (streq(name, "NeedDaemonReload")) - i->need_daemon_reload = b; - else if (streq(name, "ConditionResult")) - i->condition_result = b; - - break; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "MainPID")) { - if (u > 0) { - i->main_pid = (pid_t) u; - i->running = true; - } - } else if (streq(name, "ControlPID")) - i->control_pid = (pid_t) u; - else if (streq(name, "ExecMainPID")) { - if (u > 0) - i->main_pid = (pid_t) u; - } else if (streq(name, "NAccepted")) - i->n_accepted = u; - else if (streq(name, "NConnections")) - i->n_connections = u; - - break; - } - - case DBUS_TYPE_INT32: { - int32_t j; - - dbus_message_iter_get_basic(iter, &j); - - if (streq(name, "ExecMainCode")) - i->exit_code = (int) j; - else if (streq(name, "ExecMainStatus")) - i->exit_status = (int) j; - - break; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - - dbus_message_iter_get_basic(iter, &u); - - if (streq(name, "ExecMainStartTimestamp")) - i->start_timestamp = (usec_t) u; - else if (streq(name, "ExecMainExitTimestamp")) - i->exit_timestamp = (usec_t) u; - else if (streq(name, "ActiveEnterTimestamp")) - i->active_enter_timestamp = (usec_t) u; - else if (streq(name, "InactiveEnterTimestamp")) - i->inactive_enter_timestamp = (usec_t) u; - else if (streq(name, "InactiveExitTimestamp")) - i->inactive_exit_timestamp = (usec_t) u; - else if (streq(name, "ActiveExitTimestamp")) - i->active_exit_timestamp = (usec_t) u; - else if (streq(name, "ConditionTimestamp")) - i->condition_timestamp = (usec_t) u; - - break; - } - - case DBUS_TYPE_ARRAY: { - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && - startswith(name, "Exec")) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - ExecStatusInfo *info; - int r; - - if (!(info = new0(ExecStatusInfo, 1))) - return -ENOMEM; - - if (!(info->name = strdup(name))) { - free(info); - return -ENOMEM; - } - - if ((r = exec_status_info_deserialize(&sub, info)) < 0) { - free(info); - return r; - } - - LIST_PREPEND(ExecStatusInfo, exec, i->exec, info); - - dbus_message_iter_next(&sub); - } - } - - break; - } - - case DBUS_TYPE_STRUCT: { - - if (streq(name, "LoadError")) { - DBusMessageIter sub; - const char *n, *message; - int r; - - dbus_message_iter_recurse(iter, &sub); - - r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true); - if (r < 0) - return r; - - r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false); - if (r < 0) - return r; - - if (!isempty(message)) - i->load_error = message; - } - - break; - } - } - - return 0; -} - -static int print_property(const char *name, DBusMessageIter *iter) { - assert(name); - assert(iter); - - /* This is a low-level property printer, see - * print_status_info() for the nicer output */ - - if (arg_property && !strv_find(arg_property, name)) - return 0; - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRUCT: { - DBusMessageIter sub; - dbus_message_iter_recurse(iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) { - uint32_t u; - - dbus_message_iter_get_basic(&sub, &u); - - if (u) - printf("%s=%u\n", name, (unsigned) u); - else if (arg_all) - printf("%s=\n", name); - - return 0; - } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) { - const char *s; - - dbus_message_iter_get_basic(&sub, &s); - - if (arg_all || s[0]) - printf("%s=%s\n", name, s); - - return 0; - } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) { - const char *a = NULL, *b = NULL; - - if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0) - bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false); - - if (arg_all || !isempty(a) || !isempty(b)) - printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b)); - - return 0; - } - - break; - } - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *path; - dbus_bool_t ignore; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0) - printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore)); - - dbus_message_iter_next(&sub); - } - - return 0; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *type, *path; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) - printf("%s=%s\n", type, path); - - dbus_message_iter_next(&sub); - } - - return 0; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *base; - uint64_t value, next_elapse; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) { - char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX]; - - printf("%s={ value=%s ; next_elapse=%s }\n", - base, - format_timespan(timespan1, sizeof(timespan1), value), - format_timespan(timespan2, sizeof(timespan2), next_elapse)); - } - - dbus_message_iter_next(&sub); - } - - return 0; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) { - DBusMessageIter sub, sub2; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - const char *controller, *attr, *value; - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 && - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) { - - printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n", - controller, - attr, - value); - } - - dbus_message_iter_next(&sub); - } - - return 0; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { - ExecStatusInfo info; - - zero(info); - if (exec_status_info_deserialize(&sub, &info) >= 0) { - char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX]; - char *t; - - t = strv_join(info.argv, " "); - - printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", - name, - strna(info.path), - strna(t), - yes_no(info.ignore), - strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), - strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), - (unsigned) 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(t); - } - - free(info.path); - strv_free(info.argv); - - dbus_message_iter_next(&sub); - } - - return 0; - } - - break; - } - - if (generic_print_property(name, iter, arg_all) > 0) - return 0; - - if (arg_all) - printf("%s=[unprintable]\n", name); - - return 0; -} - -static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { - DBusMessage *m = NULL, *reply = NULL; - const char *interface = ""; - int r; - DBusError error; - DBusMessageIter iter, sub, sub2, sub3; - UnitStatusInfo info; - ExecStatusInfo *p; - - assert(bus); - assert(path); - assert(new_line); - - zero(info); - dbus_error_init(&error); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "GetAll"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (*new_line) - printf("\n"); - - *new_line = true; - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *name; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub2, &sub3); - - if (show_properties) - r = print_property(name, &sub3); - else - r = status_property(name, &sub3, &info); - - if (r < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_next(&sub); - } - - r = 0; - - if (!show_properties) - print_status_info(&info); - - if (!streq_ptr(info.active_state, "active") && - !streq_ptr(info.active_state, "reloading") && - streq(verb, "status")) - /* According to LSB: "program not running" */ - r = 3; - - while ((p = info.exec)) { - LIST_REMOVE(ExecStatusInfo, exec, info.exec, p); - exec_status_info_free(p); - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int show(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - int r, ret = 0; - DBusError error; - bool show_properties, new_line = false; - char **name; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - show_properties = !streq(args[0], "status"); - - if (show_properties) - pager_open_if_enabled(); - - if (show_properties && strv_length(args) <= 1) { - /* If not argument is specified inspect the manager - * itself */ - - ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line); - goto finish; - } - - STRV_FOREACH(name, args+1) { - const char *path = NULL; - uint32_t id; - - if (safe_atou32(*name, &id) < 0) { - - /* Interpret as unit name */ - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "LoadUnit"))) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - dbus_error_free(&error); - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - - if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT)) - ret = 4; /* According to LSB: "program or service status is unknown" */ - else - ret = -EIO; - goto finish; - } - } - - } else if (show_properties) { - - /* Interpret as job id */ - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetJob"))) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - } else { - - /* Interpret as PID */ - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnitByPID"))) { - log_error("Could not allocate message."); - ret = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - ret = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - ret = -EIO; - goto finish; - } - - if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0) - ret = r; - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return ret; -} - -static int dump(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - const char *text; - - dbus_error_init(&error); - - pager_open_if_enabled(); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "Dump"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - fputs(text, stdout); - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int snapshot(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - const char *name = "", *path, *id; - dbus_bool_t cleanup = FALSE; - DBusMessageIter iter, sub; - const char - *interface = "org.freedesktop.systemd1.Unit", - *property = "Id"; - - dbus_error_init(&error); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "CreateSnapshot"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (strv_length(args) > 1) - name = args[1]; - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &cleanup, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "Get"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&sub, &id); - - if (!arg_quiet) - puts(id); - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int delete_snapshot(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - int r; - DBusError error; - char **name; - - assert(bus); - assert(args); - - dbus_error_init(&error); - - STRV_FOREACH(name, args+1) { - const char *path = NULL; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Snapshot", - "Remove"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int daemon_reload(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - const char *method; - - dbus_error_init(&error); - - if (arg_action == ACTION_RELOAD) - method = "Reload"; - else if (arg_action == ACTION_REEXEC) - method = "Reexecute"; - else { - assert(arg_action == ACTION_SYSTEMCTL); - - method = - streq(args[0], "clear-jobs") || - streq(args[0], "cancel") ? "ClearJobs" : - streq(args[0], "daemon-reexec") ? "Reexecute" : - streq(args[0], "reset-failed") ? "ResetFailed" : - streq(args[0], "halt") ? "Halt" : - streq(args[0], "poweroff") ? "PowerOff" : - streq(args[0], "reboot") ? "Reboot" : - streq(args[0], "kexec") ? "KExec" : - streq(args[0], "exit") ? "Exit" : - /* "daemon-reload" */ "Reload"; - } - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) { - /* There's always a fallback possible for - * legacy actions. */ - r = -EADDRNOTAVAIL; - goto finish; - } - - if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) { - /* On reexecution, we expect a disconnect, not - * a reply */ - r = 0; - goto finish; - } - - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int reset_failed(DBusConnection *bus, char **args) { - DBusMessage *m = NULL; - int r; - DBusError error; - char **name; - - assert(bus); - dbus_error_init(&error); - - if (strv_length(args) <= 1) - return daemon_reload(bus, args); - - STRV_FOREACH(name, args+1) { - DBusMessage *reply; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ResetFailedUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - dbus_error_free(&error); - - return r; -} - -static int show_enviroment(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - DBusMessageIter iter, sub, sub2; - int r; - const char - *interface = "org.freedesktop.systemd1.Manager", - *property = "Environment"; - - dbus_error_init(&error); - - pager_open_if_enabled(); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.DBus.Properties", - "Get"))) { - log_error("Could not allocate message."); - return -ENOMEM; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) { - const char *text; - - if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&sub2, &text); - printf("%s\n", text); - - dbus_message_iter_next(&sub2); - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int set_environment(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int r; - const char *method; - DBusMessageIter iter, sub; - char **name; - - dbus_error_init(&error); - - method = streq(args[0], "set-environment") - ? "SetEnvironment" - : "UnsetEnvironment"; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method))) { - - log_error("Could not allocate message."); - return -ENOMEM; - } - - dbus_message_iter_init_append(m, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - STRV_FOREACH(name, args+1) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int enable_sysv_units(char **args) { - int r = 0; - -#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX)) - const char *verb = args[0]; - unsigned f = 1, t = 1; - LookupPaths paths; - - if (arg_scope != UNIT_FILE_SYSTEM) - return 0; - - if (!streq(verb, "enable") && - !streq(verb, "disable") && - !streq(verb, "is-enabled")) - return 0; - - /* Processes all SysV units, and reshuffles the array so that - * afterwards only the native units remain */ - - zero(paths); - r = lookup_paths_init(&paths, MANAGER_SYSTEM, false); - if (r < 0) - return r; - - r = 0; - - for (f = 1; args[f]; f++) { - const char *name; - char *p; - bool found_native = false, found_sysv; - unsigned c = 1; - const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL }; - char **k, *l, *q = NULL; - int j; - pid_t pid; - siginfo_t status; - - name = args[f]; - - if (!endswith(name, ".service")) - continue; - - if (path_is_absolute(name)) - continue; - - STRV_FOREACH(k, paths.unit_path) { - p = NULL; - - if (!isempty(arg_root)) - asprintf(&p, "%s/%s/%s", arg_root, *k, name); - else - asprintf(&p, "%s/%s", *k, name); - - if (!p) { - log_error("No memory"); - r = -ENOMEM; - goto finish; - } - - found_native = access(p, F_OK) >= 0; - free(p); - - if (found_native) - break; - } - - if (found_native) - continue; - - p = NULL; - if (!isempty(arg_root)) - asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name); - else - asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name); - if (!p) { - log_error("No memory"); - r = -ENOMEM; - goto finish; - } - - p[strlen(p) - sizeof(".service") + 1] = 0; - found_sysv = access(p, F_OK) >= 0; - - if (!found_sysv) { - free(p); - continue; - } - - /* Mark this entry, so that we don't try enabling it as native unit */ - args[f] = (char*) ""; - - log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name); - - if (!isempty(arg_root)) - argv[c++] = q = strappend("--root=", arg_root); - - argv[c++] = file_name_from_path(p); - argv[c++] = - streq(verb, "enable") ? "on" : - streq(verb, "disable") ? "off" : "--level=5"; - argv[c] = NULL; - - l = strv_join((char**)argv, " "); - if (!l) { - log_error("No memory."); - free(q); - free(p); - r = -ENOMEM; - goto finish; - } - - log_info("Executing %s", l); - free(l); - - pid = fork(); - if (pid < 0) { - log_error("Failed to fork: %m"); - free(p); - free(q); - r = -errno; - goto finish; - } else if (pid == 0) { - /* Child */ - - execv(argv[0], (char**) argv); - _exit(EXIT_FAILURE); - } - - free(p); - free(q); - - j = wait_for_terminate(pid, &status); - if (j < 0) { - log_error("Failed to wait for child: %s", strerror(-r)); - r = j; - goto finish; - } - - if (status.si_code == CLD_EXITED) { - if (streq(verb, "is-enabled")) { - if (status.si_status == 0) { - if (!arg_quiet) - puts("enabled"); - r = 1; - } else { - if (!arg_quiet) - puts("disabled"); - } - - } else if (status.si_status != 0) { - r = -EINVAL; - goto finish; - } - } else { - r = -EPROTO; - goto finish; - } - } - -finish: - lookup_paths_free(&paths); - - /* Drop all SysV units */ - for (f = 1, t = 1; args[f]; f++) { - - if (isempty(args[f])) - continue; - - args[t++] = args[f]; - } - - args[t] = NULL; - -#endif - return r; -} - -static int enable_unit(DBusConnection *bus, char **args) { - const char *verb = args[0]; - UnitFileChange *changes = NULL; - unsigned n_changes = 0, i; - int carries_install_info = -1; - DBusMessage *m = NULL, *reply = NULL; - int r; - DBusError error; - - dbus_error_init(&error); - - r = enable_sysv_units(args); - if (r < 0) - return r; - - if (!bus || avoid_bus()) { - if (streq(verb, "enable")) { - r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(verb, "disable")) - r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes); - else if (streq(verb, "reenable")) { - r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(verb, "link")) - r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes); - else if (streq(verb, "preset")) { - r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes); - carries_install_info = r; - } else if (streq(verb, "mask")) - r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes); - else if (streq(verb, "unmask")) - r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes); - else - assert_not_reached("Unknown verb"); - - if (r < 0) { - log_error("Operation failed: %s", strerror(-r)); - goto finish; - } - - for (i = 0; i < n_changes; i++) { - if (changes[i].type == UNIT_FILE_SYMLINK) - log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path); - else - log_info("rm '%s'", changes[i].path); - } - - } else { - const char *method; - bool send_force = true, expect_carries_install_info = false; - dbus_bool_t a, b; - DBusMessageIter iter, sub, sub2; - - if (streq(verb, "enable")) { - method = "EnableUnitFiles"; - expect_carries_install_info = true; - } else if (streq(verb, "disable")) { - method = "DisableUnitFiles"; - send_force = false; - } else if (streq(verb, "reenable")) { - method = "ReenableUnitFiles"; - expect_carries_install_info = true; - } else if (streq(verb, "link")) - method = "LinkUnitFiles"; - else if (streq(verb, "preset")) { - method = "PresetUnitFiles"; - expect_carries_install_info = true; - } else if (streq(verb, "mask")) - method = "MaskUnitFiles"; - else if (streq(verb, "unmask")) { - method = "UnmaskUnitFiles"; - send_force = false; - } else - assert_not_reached("Unknown verb"); - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method); - if (!m) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - r = bus_append_strv_iter(&iter, args+1); - if (r < 0) { - log_error("Failed to append unit files."); - goto finish; - } - - a = arg_runtime; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) { - log_error("Failed to append runtime boolean."); - r = -ENOMEM; - goto finish; - } - - if (send_force) { - b = arg_force; - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) { - log_error("Failed to append force boolean."); - r = -ENOMEM; - goto finish; - } - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter)) { - log_error("Failed to initialize iterator."); - goto finish; - } - - if (expect_carries_install_info) { - r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true); - if (r < 0) { - log_error("Failed to parse reply."); - goto finish; - } - - carries_install_info = b; - } - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *type, *path, *source; - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 || - bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - if (streq(type, "symlink")) - log_info("ln -s '%s' '%s'", source, path); - else - log_info("rm '%s'", path); - - dbus_message_iter_next(&sub); - } - - /* Try to reload if enabeld */ - if (!arg_no_reload) - r = daemon_reload(bus, args); - } - - if (carries_install_info == 0) - log_warning("Warning: unit files do not carry install information. No operation executed."); - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - unit_file_changes_free(changes, n_changes); - - dbus_error_free(&error); - return r; -} - -static int unit_is_enabled(DBusConnection *bus, char **args) { - DBusError error; - int r; - DBusMessage *m = NULL, *reply = NULL; - bool enabled; - char **name; - - dbus_error_init(&error); - - r = enable_sysv_units(args); - if (r < 0) - return r; - - enabled = r > 0; - - if (!bus || avoid_bus()) { - - STRV_FOREACH(name, args+1) { - UnitFileState state; - - state = unit_file_get_state(arg_scope, arg_root, *name); - if (state < 0) { - r = state; - goto finish; - } - - if (state == UNIT_FILE_ENABLED || - state == UNIT_FILE_ENABLED_RUNTIME || - state == UNIT_FILE_STATIC) - enabled = true; - - if (!arg_quiet) - puts(unit_file_state_to_string(state)); - } - - } else { - STRV_FOREACH(name, args+1) { - const char *s; - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnitFileState"); - if (!m) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &s, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - - if (streq(s, "enabled") || - streq(s, "enabled-runtime") || - streq(s, "static")) - enabled = true; - - if (!arg_quiet) - puts(s); - } - } - - r = enabled ? 0 : 1; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - return r; -} - -static int systemctl_help(void) { - - pager_open_if_enabled(); - - printf("%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" - " -t --type=TYPE List only units of a particular type\n" - " -p --property=NAME Show only properties by this name\n" - " -a --all Show all units/properties, including dead/empty ones\n" - " --failed Show only failed units\n" - " --full Don't ellipsize unit names on output\n" - " --fail When queueing a new job, fail if conflicting jobs are\n" - " pending\n" - " --ignore-dependencies\n" - " When queueing a new job, ignore all its dependencies\n" - " --kill-who=WHO Who to send signal to\n" - " -s --signal=SIGNAL Which signal to send\n" - " -H --host=[USER@]HOST\n" - " Show information for remote host\n" - " -P --privileged Acquire privileges before execution\n" - " -q --quiet Suppress output\n" - " --no-block Do not wait until operation finished\n" - " --no-wall Don't send wall message before halt/power-off/reboot\n" - " --no-reload When enabling/disabling unit files, don't reload daemon\n" - " configuration\n" - " --no-legend Do not print a legend (column headers and hints)\n" - " --no-pager Do not pipe output into a pager\n" - " --no-ask-password\n" - " Do not ask for system passwords\n" - " --order When generating graph for dot, show only order\n" - " --require When generating graph for dot, show only requirement\n" - " --system Connect to system manager\n" - " --user Connect to user service manager\n" - " --global Enable/disable unit files globally\n" - " -f --force When enabling unit files, override existing symlinks\n" - " When shutting down, execute action immediately\n" - " --root=PATH Enable unit files in the specified root directory\n" - " --runtime Enable unit files only temporarily until next reboot\n\n" - "Unit Commands:\n" - " list-units List loaded units\n" - " start [NAME...] Start (activate) one or more units\n" - " stop [NAME...] Stop (deactivate) one or more units\n" - " reload [NAME...] Reload one or more units\n" - " restart [NAME...] Start or restart one or more units\n" - " try-restart [NAME...] Restart one or more units if active\n" - " reload-or-restart [NAME...] Reload one or more units is possible,\n" - " otherwise start or restart\n" - " reload-or-try-restart [NAME...] Reload one or more units is possible,\n" - " otherwise restart if active\n" - " isolate [NAME] Start one unit and stop all others\n" - " kill [NAME...] Send signal to processes of a unit\n" - " is-active [NAME...] Check whether units are active\n" - " status [NAME...|PID...] Show runtime status of one or more units\n" - " show [NAME...|JOB...] Show properties of one or more\n" - " units/jobs or the manager\n" - " reset-failed [NAME...] Reset failed state for all, one, or more\n" - " units\n" - " load [NAME...] Load one or more units\n\n" - "Unit File Commands:\n" - " list-unit-files List installed unit files\n" - " enable [NAME...] Enable one or more unit files\n" - " disable [NAME...] Disable one or more unit files\n" - " reenable [NAME...] Reenable one or more unit files\n" - " preset [NAME...] Enable/disable one or more unit files\n" - " based on preset configuration\n" - " mask [NAME...] Mask one or more units\n" - " unmask [NAME...] Unmask one or more units\n" - " link [PATH...] Link one or more units files into\n" - " the search path\n" - " is-enabled [NAME...] Check whether unit files are enabled\n\n" - "Job Commands:\n" - " list-jobs List jobs\n" - " cancel [JOB...] Cancel all, one, or more jobs\n\n" - "Status Commands:\n" - " dump Dump server status\n" - " dot Dump dependency graph for dot(1)\n\n" - "Snapshot Commands:\n" - " snapshot [NAME] Create a snapshot\n" - " delete [NAME...] Remove one or more snapshots\n\n" - "Environment Commands:\n" - " show-environment Dump environment\n" - " set-environment [NAME=VALUE...] Set one or more environment variables\n" - " unset-environment [NAME...] Unset one or more environment variables\n\n" - "Manager Lifecycle Commands:\n" - " daemon-reload Reload systemd manager configuration\n" - " daemon-reexec Reexecute systemd manager\n\n" - "System Commands:\n" - " default Enter system default mode\n" - " rescue Enter system rescue mode\n" - " emergency Enter system emergency mode\n" - " halt Shut down and halt the system\n" - " poweroff Shut down and power-off the system\n" - " reboot Shut down and reboot the system\n" - " kexec Shut down and reboot the system with kexec\n" - " exit Ask for user instance termination\n", - program_invocation_short_name); - - return 0; -} - -static int halt_help(void) { - - printf("%s [OPTIONS...]\n\n" - "%s the system.\n\n" - " --help Show this help\n" - " --halt Halt the machine\n" - " -p --poweroff Switch off the machine\n" - " --reboot Reboot the machine\n" - " -f --force Force immediate halt/power-off/reboot\n" - " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n" - " -d --no-wtmp Don't write wtmp record\n" - " -n --no-sync Don't sync before halt/power-off/reboot\n" - " --no-wall Don't send wall message before halt/power-off/reboot\n", - program_invocation_short_name, - arg_action == ACTION_REBOOT ? "Reboot" : - arg_action == ACTION_POWEROFF ? "Power off" : - "Halt"); - - return 0; -} - -static int shutdown_help(void) { - - printf("%s [OPTIONS...] [TIME] [WALL...]\n\n" - "Shut down the system.\n\n" - " --help Show this help\n" - " -H --halt Halt the machine\n" - " -P --poweroff Power-off the machine\n" - " -r --reboot Reboot the machine\n" - " -h Equivalent to --poweroff, overriden by --halt\n" - " -k Don't halt/power-off/reboot, just send warnings\n" - " --no-wall Don't send wall message before halt/power-off/reboot\n" - " -c Cancel a pending shutdown\n", - program_invocation_short_name); - - return 0; -} - -static int telinit_help(void) { - - printf("%s [OPTIONS...] {COMMAND}\n\n" - "Send control commands to the init daemon.\n\n" - " --help Show this help\n" - " --no-wall Don't send wall message before halt/power-off/reboot\n\n" - "Commands:\n" - " 0 Power-off the machine\n" - " 6 Reboot the machine\n" - " 2, 3, 4, 5 Start runlevelX.target unit\n" - " 1, s, S Enter rescue mode\n" - " q, Q Reload init daemon configuration\n" - " u, U Reexecute init daemon\n", - program_invocation_short_name); - - return 0; -} - -static int runlevel_help(void) { - - printf("%s [OPTIONS...]\n\n" - "Prints the previous and current runlevel of the init system.\n\n" - " --help Show this help\n", - program_invocation_short_name); - - return 0; -} - -static int systemctl_parse_argv(int argc, char *argv[]) { - - enum { - ARG_FAIL = 0x100, - ARG_IGNORE_DEPENDENCIES, - ARG_VERSION, - ARG_USER, - ARG_SYSTEM, - ARG_GLOBAL, - ARG_NO_BLOCK, - ARG_NO_LEGEND, - ARG_NO_PAGER, - ARG_NO_WALL, - ARG_ORDER, - ARG_REQUIRE, - ARG_ROOT, - ARG_FULL, - ARG_NO_RELOAD, - ARG_KILL_MODE, - ARG_KILL_WHO, - ARG_NO_ASK_PASSWORD, - ARG_FAILED, - ARG_RUNTIME - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "type", required_argument, NULL, 't' }, - { "property", required_argument, NULL, 'p' }, - { "all", no_argument, NULL, 'a' }, - { "failed", no_argument, NULL, ARG_FAILED }, - { "full", no_argument, NULL, ARG_FULL }, - { "fail", no_argument, NULL, ARG_FAIL }, - { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, - { "user", no_argument, NULL, ARG_USER }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "global", no_argument, NULL, ARG_GLOBAL }, - { "no-block", no_argument, NULL, ARG_NO_BLOCK }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { "quiet", no_argument, NULL, 'q' }, - { "order", no_argument, NULL, ARG_ORDER }, - { "require", no_argument, NULL, ARG_REQUIRE }, - { "root", required_argument, NULL, ARG_ROOT }, - { "force", no_argument, NULL, 'f' }, - { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, - { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */ - { "kill-who", required_argument, NULL, ARG_KILL_WHO }, - { "signal", required_argument, NULL, 's' }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "host", required_argument, NULL, 'H' }, - { "privileged",no_argument, NULL, 'P' }, - { "runtime", no_argument, NULL, ARG_RUNTIME }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - /* Only when running as systemctl we ask for passwords */ - arg_ask_password = true; - - while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - systemctl_help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(DISTRIBUTION); - puts(SYSTEMD_FEATURES); - return 0; - - case 't': - arg_type = optarg; - break; - - case 'p': { - char **l; - - if (!(l = strv_append(arg_property, optarg))) - return -ENOMEM; - - strv_free(arg_property); - arg_property = l; - - /* If the user asked for a particular - * property, show it to him, even if it is - * empty. */ - arg_all = true; - break; - } - - case 'a': - arg_all = true; - break; - - case ARG_FAIL: - arg_job_mode = "fail"; - break; - - case ARG_IGNORE_DEPENDENCIES: - arg_job_mode = "ignore-dependencies"; - break; - - case ARG_USER: - arg_scope = UNIT_FILE_USER; - break; - - case ARG_SYSTEM: - arg_scope = UNIT_FILE_SYSTEM; - break; - - case ARG_GLOBAL: - arg_scope = UNIT_FILE_GLOBAL; - break; - - case ARG_NO_BLOCK: - arg_no_block = true; - break; - - case ARG_NO_LEGEND: - arg_no_legend = true; - break; - - case ARG_NO_PAGER: - arg_no_pager = true; - break; - - case ARG_NO_WALL: - arg_no_wall = true; - break; - - case ARG_ORDER: - arg_dot = DOT_ORDER; - break; - - case ARG_REQUIRE: - arg_dot = DOT_REQUIRE; - break; - - case ARG_ROOT: - arg_root = optarg; - break; - - case ARG_FULL: - arg_full = true; - break; - - case ARG_FAILED: - arg_failed = true; - break; - - case 'q': - arg_quiet = true; - break; - - case 'f': - arg_force = true; - break; - - case ARG_NO_RELOAD: - arg_no_reload = true; - break; - - case ARG_KILL_WHO: - arg_kill_who = optarg; - break; - - case ARG_KILL_MODE: - arg_kill_mode = optarg; - break; - - case 's': - if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) { - log_error("Failed to parse signal string %s.", optarg); - return -EINVAL; - } - break; - - case ARG_NO_ASK_PASSWORD: - arg_ask_password = false; - break; - - case 'P': - arg_transport = TRANSPORT_POLKIT; - break; - - case 'H': - arg_transport = TRANSPORT_SSH; - arg_host = optarg; - break; - - case ARG_RUNTIME: - arg_runtime = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) { - log_error("Cannot access user instance remotely."); - return -EINVAL; - } - - return 1; -} - -static int halt_parse_argv(int argc, char *argv[]) { - - enum { - ARG_HELP = 0x100, - ARG_HALT, - ARG_REBOOT, - ARG_NO_WALL - }; - - static const struct option options[] = { - { "help", no_argument, NULL, ARG_HELP }, - { "halt", no_argument, NULL, ARG_HALT }, - { "poweroff", no_argument, NULL, 'p' }, - { "reboot", no_argument, NULL, ARG_REBOOT }, - { "force", no_argument, NULL, 'f' }, - { "wtmp-only", no_argument, NULL, 'w' }, - { "no-wtmp", no_argument, NULL, 'd' }, - { "no-sync", no_argument, NULL, 'n' }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { NULL, 0, NULL, 0 } - }; - - int c, runlevel; - - assert(argc >= 0); - assert(argv); - - if (utmp_get_runlevel(&runlevel, NULL) >= 0) - if (runlevel == '0' || runlevel == '6') - arg_immediate = true; - - while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) { - switch (c) { - - case ARG_HELP: - halt_help(); - return 0; - - case ARG_HALT: - arg_action = ACTION_HALT; - break; - - case 'p': - if (arg_action != ACTION_REBOOT) - arg_action = ACTION_POWEROFF; - break; - - case ARG_REBOOT: - arg_action = ACTION_REBOOT; - break; - - case 'f': - arg_immediate = true; - break; - - case 'w': - arg_dry = true; - break; - - case 'd': - arg_no_wtmp = true; - break; - - case 'n': - arg_no_sync = true; - break; - - case ARG_NO_WALL: - arg_no_wall = true; - break; - - case 'i': - case 'h': - /* Compatibility nops */ - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind < argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - return 1; -} - -static int parse_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); - - zero(tm); - assert_se(localtime_r(&s, &tm)); - - tm.tm_hour = (int) hour; - tm.tm_min = (int) minute; - tm.tm_sec = 0; - - assert_se(s = mktime(&tm)); - - *_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, - ARG_NO_WALL - }; - - static const struct option options[] = { - { "help", no_argument, NULL, ARG_HELP }, - { "halt", no_argument, NULL, 'H' }, - { "poweroff", no_argument, NULL, 'P' }, - { "reboot", no_argument, NULL, 'r' }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { NULL, 0, NULL, 0 } - }; - - int c, r; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) { - switch (c) { - - case ARG_HELP: - shutdown_help(); - return 0; - - case 'H': - arg_action = ACTION_HALT; - break; - - case 'P': - arg_action = ACTION_POWEROFF; - break; - - case 'r': - if (kexec_loaded()) - arg_action = ACTION_KEXEC; - else - arg_action = ACTION_REBOOT; - break; - - case 'h': - if (arg_action != ACTION_HALT) - arg_action = ACTION_POWEROFF; - break; - - case 'k': - arg_dry = true; - break; - - case ARG_NO_WALL: - arg_no_wall = true; - break; - - case 't': - case 'a': - /* Compatibility nops */ - break; - - case 'c': - arg_action = ACTION_CANCEL_SHUTDOWN; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (argc > optind) { - if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) { - log_error("Failed to parse time specification: %s", argv[optind]); - return r; - } - } else - arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE; - - /* We skip the time argument */ - if (argc > optind + 1) - arg_wall = argv + optind + 1; - - optind = argc; - - return 1; -} - -static int telinit_parse_argv(int argc, char *argv[]) { - - enum { - ARG_HELP = 0x100, - ARG_NO_WALL - }; - - static const struct option options[] = { - { "help", no_argument, NULL, ARG_HELP }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { NULL, 0, NULL, 0 } - }; - - static const struct { - char from; - enum action to; - } table[] = { - { '0', ACTION_POWEROFF }, - { '6', ACTION_REBOOT }, - { '1', ACTION_RESCUE }, - { '2', ACTION_RUNLEVEL2 }, - { '3', ACTION_RUNLEVEL3 }, - { '4', ACTION_RUNLEVEL4 }, - { '5', ACTION_RUNLEVEL5 }, - { 's', ACTION_RESCUE }, - { 'S', ACTION_RESCUE }, - { 'q', ACTION_RELOAD }, - { 'Q', ACTION_RELOAD }, - { 'u', ACTION_REEXEC }, - { 'U', ACTION_REEXEC } - }; - - unsigned i; - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) { - switch (c) { - - case ARG_HELP: - telinit_help(); - return 0; - - case ARG_NO_WALL: - arg_no_wall = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind >= argc) { - telinit_help(); - return -EINVAL; - } - - if (optind + 1 < argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - if (strlen(argv[optind]) != 1) { - log_error("Expected single character argument."); - return -EINVAL; - } - - for (i = 0; i < ELEMENTSOF(table); i++) - if (table[i].from == argv[optind][0]) - break; - - if (i >= ELEMENTSOF(table)) { - log_error("Unknown command %s.", argv[optind]); - return -EINVAL; - } - - arg_action = table[i].to; - - optind ++; - - return 1; -} - -static int runlevel_parse_argv(int argc, char *argv[]) { - - enum { - ARG_HELP = 0x100, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, ARG_HELP }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) { - switch (c) { - - case ARG_HELP: - runlevel_help(); - return 0; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind < argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - return 1; -} - -static int parse_argv(int argc, char *argv[]) { - assert(argc >= 0); - assert(argv); - - if (program_invocation_short_name) { - - if (strstr(program_invocation_short_name, "halt")) { - arg_action = ACTION_HALT; - return halt_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "poweroff")) { - arg_action = ACTION_POWEROFF; - return halt_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "reboot")) { - if (kexec_loaded()) - arg_action = ACTION_KEXEC; - else - arg_action = ACTION_REBOOT; - return halt_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "shutdown")) { - arg_action = ACTION_POWEROFF; - return shutdown_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "init")) { - - if (sd_booted() > 0) { - arg_action = ACTION_INVALID; - return telinit_parse_argv(argc, argv); - } else { - /* Hmm, so some other init system is - * running, we need to forward this - * request to it. For now we simply - * guess that it is Upstart. */ - - execv("/lib/upstart/telinit", argv); - - log_error("Couldn't find an alternative telinit implementation to spawn."); - return -EIO; - } - - } else if (strstr(program_invocation_short_name, "runlevel")) { - arg_action = ACTION_RUNLEVEL; - return runlevel_parse_argv(argc, argv); - } - } - - arg_action = ACTION_SYSTEMCTL; - return systemctl_parse_argv(argc, argv); -} - -static int action_to_runlevel(void) { - - static const char table[_ACTION_MAX] = { - [ACTION_HALT] = '0', - [ACTION_POWEROFF] = '0', - [ACTION_REBOOT] = '6', - [ACTION_RUNLEVEL2] = '2', - [ACTION_RUNLEVEL3] = '3', - [ACTION_RUNLEVEL4] = '4', - [ACTION_RUNLEVEL5] = '5', - [ACTION_RESCUE] = '1' - }; - - assert(arg_action < _ACTION_MAX); - - return table[arg_action]; -} - -static int talk_upstart(void) { - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - int previous, rl, r; - char - env1_buf[] = "RUNLEVEL=X", - env2_buf[] = "PREVLEVEL=X"; - char *env1 = env1_buf, *env2 = env2_buf; - const char *emit = "runlevel"; - dbus_bool_t b_false = FALSE; - DBusMessageIter iter, sub; - DBusConnection *bus; - - dbus_error_init(&error); - - if (!(rl = action_to_runlevel())) - return 0; - - if (utmp_get_runlevel(&previous, NULL) < 0) - previous = 'N'; - - if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) { - if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) { - r = 0; - goto finish; - } - - log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if ((r = bus_check_peercred(bus)) < 0) { - log_error("Failed to verify owner of bus."); - goto finish; - } - - if (!(m = dbus_message_new_method_call( - "com.ubuntu.Upstart", - "/com/ubuntu/Upstart", - "com.ubuntu.Upstart0_6", - "EmitEvent"))) { - - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - env1_buf[sizeof(env1_buf)-2] = rl; - env2_buf[sizeof(env2_buf)-2] = previous; - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - if (error_is_no_service(&error)) { - r = -EADDRNOTAVAIL; - goto finish; - } - - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - r = 1; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - dbus_error_free(&error); - - return r; -} - -static int talk_initctl(void) { - struct init_request request; - int r, fd; - char rl; - - if (!(rl = action_to_runlevel())) - return 0; - - zero(request); - request.magic = INIT_MAGIC; - request.sleeptime = 0; - request.cmd = INIT_CMD_RUNLVL; - request.runlevel = rl; - - if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) { - - if (errno == ENOENT) - return 0; - - log_error("Failed to open "INIT_FIFO": %m"); - return -errno; - } - - errno = 0; - r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); - close_nointr_nofail(fd); - - if (r < 0) { - log_error("Failed to write to "INIT_FIFO": %m"); - return errno ? -errno : -EIO; - } - - return 1; -} - -static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) { - - static const struct { - const char* verb; - const enum { - MORE, - LESS, - EQUAL - } argc_cmp; - const int argc; - int (* const dispatch)(DBusConnection *bus, char **args); - } verbs[] = { - { "list-units", LESS, 1, list_units }, - { "list-unit-files", EQUAL, 1, list_unit_files }, - { "list-jobs", EQUAL, 1, list_jobs }, - { "clear-jobs", EQUAL, 1, daemon_reload }, - { "load", MORE, 2, load_unit }, - { "cancel", MORE, 2, cancel_job }, - { "start", MORE, 2, start_unit }, - { "stop", MORE, 2, start_unit }, - { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ - { "reload", MORE, 2, start_unit }, - { "restart", MORE, 2, start_unit }, - { "try-restart", MORE, 2, start_unit }, - { "reload-or-restart", MORE, 2, start_unit }, - { "reload-or-try-restart", MORE, 2, start_unit }, - { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */ - { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ - { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */ - { "isolate", EQUAL, 2, start_unit }, - { "kill", MORE, 2, kill_unit }, - { "is-active", MORE, 2, check_unit }, - { "check", MORE, 2, check_unit }, - { "show", MORE, 1, show }, - { "status", MORE, 2, show }, - { "dump", EQUAL, 1, dump }, - { "dot", EQUAL, 1, dot }, - { "snapshot", LESS, 2, snapshot }, - { "delete", MORE, 2, delete_snapshot }, - { "daemon-reload", EQUAL, 1, daemon_reload }, - { "daemon-reexec", EQUAL, 1, daemon_reload }, - { "show-environment", EQUAL, 1, show_enviroment }, - { "set-environment", MORE, 2, set_environment }, - { "unset-environment", MORE, 2, set_environment }, - { "halt", EQUAL, 1, start_special }, - { "poweroff", EQUAL, 1, start_special }, - { "reboot", EQUAL, 1, start_special }, - { "kexec", EQUAL, 1, start_special }, - { "default", EQUAL, 1, start_special }, - { "rescue", EQUAL, 1, start_special }, - { "emergency", EQUAL, 1, start_special }, - { "exit", EQUAL, 1, start_special }, - { "reset-failed", MORE, 1, reset_failed }, - { "enable", MORE, 2, enable_unit }, - { "disable", MORE, 2, enable_unit }, - { "is-enabled", MORE, 2, unit_is_enabled }, - { "reenable", MORE, 2, enable_unit }, - { "preset", MORE, 2, enable_unit }, - { "mask", MORE, 2, enable_unit }, - { "unmask", MORE, 2, enable_unit }, - { "link", MORE, 2, enable_unit } - }; - - int left; - unsigned i; - - assert(argc >= 0); - assert(argv); - assert(error); - - left = argc - optind; - - if (left <= 0) - /* Special rule: no arguments means "list-units" */ - i = 0; - else { - if (streq(argv[optind], "help")) { - systemctl_help(); - return 0; - } - - for (i = 0; i < ELEMENTSOF(verbs); i++) - if (streq(argv[optind], verbs[i].verb)) - break; - - if (i >= ELEMENTSOF(verbs)) { - log_error("Unknown operation %s", argv[optind]); - return -EINVAL; - } - } - - switch (verbs[i].argc_cmp) { - - case EQUAL: - if (left != verbs[i].argc) { - log_error("Invalid number of arguments."); - return -EINVAL; - } - - break; - - case MORE: - if (left < verbs[i].argc) { - log_error("Too few arguments."); - return -EINVAL; - } - - break; - - case LESS: - if (left > verbs[i].argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - break; - - default: - assert_not_reached("Unknown comparison operator."); - } - - /* Require a bus connection for all operations but - * enable/disable */ - if (!streq(verbs[i].verb, "enable") && - !streq(verbs[i].verb, "disable") && - !streq(verbs[i].verb, "is-enable") && - !streq(verbs[i].verb, "reenable") && - !streq(verbs[i].verb, "preset") && - !streq(verbs[i].verb, "mask") && - !streq(verbs[i].verb, "unmask") && - !streq(verbs[i].verb, "link")) { - - if (running_in_chroot() > 0) { - log_info("Running in chroot, ignoring request."); - return 0; - } - - if (!bus) { - log_error("Failed to get D-Bus connection: %s", - dbus_error_is_set(error) ? error->message : "No connection to service manager."); - return -EIO; - } - - } else { - - if (!bus && !avoid_bus()) { - log_error("Failed to get D-Bus connection: %s", - dbus_error_is_set(error) ? error->message : "No connection to service manager."); - return -EIO; - } - } - - return verbs[i].dispatch(bus, argv + optind); -} - -static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) { - int fd = -1; - struct msghdr msghdr; - struct iovec iovec; - union sockaddr_union sockaddr; - struct shutdownd_command c; - - zero(c); - c.elapse = t; - c.mode = mode; - c.dry_run = dry_run; - c.warn_wall = warn; - - if (message) - strncpy(c.wall_message, message, sizeof(c.wall_message)); - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) - return -errno; - - zero(sockaddr); - sockaddr.sa.sa_family = AF_UNIX; - sockaddr.un.sun_path[0] = 0; - strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path)); - - zero(iovec); - iovec.iov_base = (char*) &c; - iovec.iov_len = sizeof(c); - - zero(msghdr); - msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1; - - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - - if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - close_nointr_nofail(fd); - return 0; -} - -static int reload_with_fallback(DBusConnection *bus) { - - if (bus) { - /* First, try systemd via D-Bus. */ - if (daemon_reload(bus, NULL) >= 0) - return 0; - } - - /* Nothing else worked, so let's try signals */ - assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC); - - if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) { - log_error("kill() failed: %m"); - return -errno; - } - - return 0; -} - -static int start_with_fallback(DBusConnection *bus) { - - if (bus) { - /* First, try systemd via D-Bus. */ - if (start_unit(bus, NULL) >= 0) - goto done; - } - - /* Hmm, talking to systemd via D-Bus didn't work. Then - * let's try to talk to Upstart via D-Bus. */ - if (talk_upstart() > 0) - goto done; - - /* Nothing else worked, so let's try - * /dev/initctl */ - if (talk_initctl() > 0) - goto done; - - log_error("Failed to talk to init daemon."); - return -EIO; - -done: - warn_wall(arg_action); - return 0; -} - -static int halt_main(DBusConnection *bus) { - int r; - - if (geteuid() != 0) { - log_error("Must be root."); - return -EPERM; - } - - if (arg_when > 0) { - char *m; - char date[FORMAT_TIMESTAMP_MAX]; - - m = strv_join(arg_wall, " "); - r = send_shutdownd(arg_when, - arg_action == ACTION_HALT ? 'H' : - arg_action == ACTION_POWEROFF ? 'P' : - 'r', - arg_dry, - !arg_no_wall, - m); - free(m); - - if (r < 0) - log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r)); - else { - log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", - format_timestamp(date, sizeof(date), arg_when)); - return 0; - } - } - - if (!arg_dry && !arg_immediate) - return start_with_fallback(bus); - - if (!arg_no_wtmp) { - if (sd_booted() > 0) - log_debug("Not writing utmp record, assuming that systemd-update-utmp is used."); - else if ((r = utmp_put_shutdown(0)) < 0) - log_warning("Failed to write utmp record: %s", strerror(-r)); - } - - if (!arg_no_sync) - sync(); - - if (arg_dry) - return 0; - - /* Make sure C-A-D is handled by the kernel from this - * point on... */ - reboot(RB_ENABLE_CAD); - - switch (arg_action) { - - case ACTION_HALT: - log_info("Halting."); - reboot(RB_HALT_SYSTEM); - break; - - case ACTION_POWEROFF: - log_info("Powering off."); - reboot(RB_POWER_OFF); - break; - - case ACTION_REBOOT: - log_info("Rebooting."); - reboot(RB_AUTOBOOT); - break; - - default: - assert_not_reached("Unknown halt action."); - } - - /* We should never reach this. */ - return -ENOSYS; -} - -static int runlevel_main(void) { - int r, runlevel, previous; - - r = utmp_get_runlevel(&runlevel, &previous); - if (r < 0) { - puts("unknown"); - return r; - } - - printf("%c %c\n", - previous <= 0 ? 'N' : previous, - runlevel <= 0 ? 'N' : runlevel); - - return 0; -} - -int main(int argc, char*argv[]) { - int r, retval = EXIT_FAILURE; - DBusConnection *bus = NULL; - DBusError error; - - dbus_error_init(&error); - - log_parse_environment(); - log_open(); - - if ((r = parse_argv(argc, argv)) < 0) - goto finish; - else if (r == 0) { - retval = EXIT_SUCCESS; - goto finish; - } - - /* /sbin/runlevel doesn't need to communicate via D-Bus, so - * let's shortcut this */ - if (arg_action == ACTION_RUNLEVEL) { - r = runlevel_main(); - retval = r < 0 ? EXIT_FAILURE : r; - goto finish; - } - - if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) { - log_info("Running in chroot, ignoring request."); - retval = 0; - goto finish; - } - - if (!avoid_bus()) { - if (arg_transport == TRANSPORT_NORMAL) - bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error); - else if (arg_transport == TRANSPORT_POLKIT) { - bus_connect_system_polkit(&bus, &error); - private_bus = false; - } else if (arg_transport == TRANSPORT_SSH) { - bus_connect_system_ssh(NULL, arg_host, &bus, &error); - private_bus = false; - } else - assert_not_reached("Uh, invalid transport..."); - } - - switch (arg_action) { - - case ACTION_SYSTEMCTL: - r = systemctl_main(bus, argc, argv, &error); - break; - - case ACTION_HALT: - case ACTION_POWEROFF: - case ACTION_REBOOT: - case ACTION_KEXEC: - r = halt_main(bus); - break; - - case ACTION_RUNLEVEL2: - case ACTION_RUNLEVEL3: - case ACTION_RUNLEVEL4: - case ACTION_RUNLEVEL5: - case ACTION_RESCUE: - case ACTION_EMERGENCY: - case ACTION_DEFAULT: - r = start_with_fallback(bus); - break; - - case ACTION_RELOAD: - case ACTION_REEXEC: - r = reload_with_fallback(bus); - break; - - case ACTION_CANCEL_SHUTDOWN: - r = send_shutdownd(0, 0, false, false, NULL); - break; - - case ACTION_INVALID: - case ACTION_RUNLEVEL: - default: - assert_not_reached("Unknown action"); - } - - retval = r < 0 ? EXIT_FAILURE : r; - -finish: - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - dbus_error_free(&error); - - dbus_shutdown(); - - strv_free(arg_property); - - pager_close(); - agent_close(); - - return retval; -} diff --git a/src/systemctl/Makefile b/src/systemctl/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/systemctl/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c new file mode 100644 index 0000000..1a45490 --- /dev/null +++ b/src/systemctl/systemctl.c @@ -0,0 +1,6491 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Marc-Antoine Perennou + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" +#include "sd-shutdown.h" +#include "sd-login.h" +#include "sd-bus.h" +#include "log.h" +#include "util.h" +#include "macro.h" +#include "set.h" +#include "utmp-wtmp.h" +#include "special.h" +#include "initreq.h" +#include "path-util.h" +#include "strv.h" +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "list.h" +#include "path-lookup.h" +#include "conf-parser.h" +#include "exit-status.h" +#include "build.h" +#include "unit-name.h" +#include "pager.h" +#include "spawn-ask-password-agent.h" +#include "spawn-polkit-agent.h" +#include "install.h" +#include "logs-show.h" +#include "socket-util.h" +#include "fileio.h" +#include "env-util.h" +#include "bus-util.h" +#include "bus-message.h" +#include "bus-error.h" +#include "bus-errors.h" + +static char **arg_types = NULL; +static char **arg_states = NULL; +static char **arg_properties = NULL; +static bool arg_all = false; +static bool original_stdout_is_tty; +static enum dependency { + DEPENDENCY_FORWARD, + DEPENDENCY_REVERSE, + DEPENDENCY_AFTER, + DEPENDENCY_BEFORE, + _DEPENDENCY_MAX +} arg_dependency = DEPENDENCY_FORWARD; +static const char *arg_job_mode = "replace"; +static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; +static bool arg_no_block = false; +static bool arg_no_legend = false; +static bool arg_no_pager = false; +static bool arg_no_wtmp = false; +static bool arg_no_wall = false; +static bool arg_no_reload = false; +static bool arg_show_types = false; +static bool arg_ignore_inhibitors = false; +static bool arg_dry = false; +static bool arg_quiet = false; +static bool arg_full = false; +static int arg_force = 0; +static bool arg_ask_password = true; +static bool arg_runtime = false; +static char **arg_wall = NULL; +static const char *arg_kill_who = NULL; +static int arg_signal = SIGTERM; +static const char *arg_root = NULL; +static usec_t arg_when = 0; +static enum action { + _ACTION_INVALID, + ACTION_SYSTEMCTL, + ACTION_HALT, + ACTION_POWEROFF, + ACTION_REBOOT, + ACTION_KEXEC, + ACTION_EXIT, + ACTION_SUSPEND, + ACTION_HIBERNATE, + ACTION_HYBRID_SLEEP, + ACTION_RUNLEVEL2, + ACTION_RUNLEVEL3, + ACTION_RUNLEVEL4, + ACTION_RUNLEVEL5, + ACTION_RESCUE, + ACTION_EMERGENCY, + ACTION_DEFAULT, + ACTION_RELOAD, + ACTION_REEXEC, + ACTION_RUNLEVEL, + ACTION_CANCEL_SHUTDOWN, + _ACTION_MAX +} arg_action = ACTION_SYSTEMCTL; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static unsigned arg_lines = 10; +static OutputMode arg_output = OUTPUT_SHORT; +static bool arg_plain = false; +static const struct { + const char *verb; + const char *method; +} unit_actions[] = { + { "start", "StartUnit" }, + { "stop", "StopUnit" }, + { "condstop", "StopUnit" }, + { "reload", "ReloadUnit" }, + { "restart", "RestartUnit" }, + { "try-restart", "TryRestartUnit" }, + { "condrestart", "TryRestartUnit" }, + { "reload-or-restart", "ReloadOrRestartUnit" }, + { "reload-or-try-restart", "ReloadOrTryRestartUnit" }, + { "condreload", "ReloadOrTryRestartUnit" }, + { "force-reload", "ReloadOrTryRestartUnit" } +}; + +static int daemon_reload(sd_bus *bus, char **args); +static int halt_now(enum action a); + +static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); + +static char** strv_skip_first(char **strv) { + if (strv_length(strv) > 0) + return strv + 1; + return NULL; +} + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static void ask_password_agent_open_if_enabled(void) { + + /* Open the password agent as a child process if necessary */ + + if (!arg_ask_password) + return; + + if (arg_scope != UNIT_FILE_SYSTEM) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + ask_password_agent_open(); +} + +#ifdef HAVE_LOGIND +static void polkit_agent_open_if_enabled(void) { + + /* Open the polkit agent as a child process if necessary */ + + if (!arg_ask_password) + return; + + if (arg_scope != UNIT_FILE_SYSTEM) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + polkit_agent_open(); +} +#endif + +static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) { + assert(error); + + if (!sd_bus_error_is_set(error)) + return r; + + if (sd_bus_error_has_name(error, SD_BUS_ERROR_ACCESS_DENIED) || + sd_bus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) || + sd_bus_error_has_name(error, BUS_ERROR_NO_ISOLATION) || + sd_bus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE)) + return EXIT_NOPERMISSION; + + if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT)) + return EXIT_NOTINSTALLED; + + if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) || + sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED)) + return EXIT_NOTIMPLEMENTED; + + if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) + return EXIT_NOTCONFIGURED; + + if (r != 0) + return r; + + return EXIT_FAILURE; +} + +static void warn_wall(enum action a) { + static const char *table[_ACTION_MAX] = { + [ACTION_HALT] = "The system is going down for system halt NOW!", + [ACTION_REBOOT] = "The system is going down for reboot NOW!", + [ACTION_POWEROFF] = "The system is going down for power-off NOW!", + [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!", + [ACTION_RESCUE] = "The system is going down to rescue mode NOW!", + [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!", + [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!" + }; + + if (arg_no_wall) + return; + + if (arg_wall) { + _cleanup_free_ char *p; + + p = strv_join(arg_wall, " "); + if (!p) { + log_oom(); + return; + } + + if (*p) { + utmp_wall(p, NULL); + return; + } + } + + if (!table[a]) + return; + + utmp_wall(table[a], NULL); +} + +static bool avoid_bus(void) { + + if (running_in_chroot() > 0) + return true; + + if (sd_booted() <= 0) + return true; + + if (!isempty(arg_root)) + return true; + + if (arg_scope == UNIT_FILE_GLOBAL) + return true; + + return false; +} + +static int compare_unit_info(const void *a, const void *b) { + const UnitInfo *u = a, *v = b; + const char *d1, *d2; + + d1 = strrchr(u->id, '.'); + d2 = strrchr(v->id, '.'); + + if (d1 && d2) { + int r; + + r = strcasecmp(d1, d2); + if (r != 0) + return r; + } + + return strcasecmp(u->id, v->id); +} + +static bool output_show_unit(const UnitInfo *u, char **patterns) { + const char *dot; + + if (!strv_isempty(arg_states)) + return + strv_contains(arg_states, u->load_state) || + strv_contains(arg_states, u->sub_state) || + strv_contains(arg_states, u->active_state); + + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0) + return true; + return false; + } + + return (!arg_types || ((dot = strrchr(u->id, '.')) && + strv_find(arg_types, dot+1))) && + (arg_all || !(streq(u->active_state, "inactive") + || u->following[0]) || u->job_id > 0); +} + +static void output_units_list(const UnitInfo *unit_infos, unsigned c) { + unsigned id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len; + const UnitInfo *u; + unsigned n_shown = 0; + int job_count = 0; + + max_id_len = sizeof("UNIT")-1; + load_len = sizeof("LOAD")-1; + active_len = sizeof("ACTIVE")-1; + sub_len = sizeof("SUB")-1; + job_len = sizeof("JOB")-1; + desc_len = 0; + + for (u = unit_infos; u < unit_infos + c; u++) { + max_id_len = MAX(max_id_len, strlen(u->id)); + load_len = MAX(load_len, strlen(u->load_state)); + active_len = MAX(active_len, strlen(u->active_state)); + sub_len = MAX(sub_len, strlen(u->sub_state)); + + if (u->job_id != 0) { + job_len = MAX(job_len, strlen(u->job_type)); + job_count++; + } + } + + if (!arg_full && original_stdout_is_tty) { + unsigned basic_len; + + id_len = MIN(max_id_len, 25u); + basic_len = 5 + id_len + 5 + active_len + sub_len; + + if (job_count) + basic_len += job_len + 1; + + if (basic_len < (unsigned) columns()) { + unsigned extra_len, incr; + extra_len = columns() - basic_len; + + /* Either UNIT already got 25, or is fully satisfied. + * Grant up to 25 to DESC now. */ + incr = MIN(extra_len, 25u); + desc_len += incr; + extra_len -= incr; + + /* split the remaining space between UNIT and DESC, + * but do not give UNIT more than it needs. */ + if (extra_len > 0) { + incr = MIN(extra_len / 2, max_id_len - id_len); + id_len += incr; + desc_len += extra_len - incr; + } + } + } else + id_len = max_id_len; + + for (u = unit_infos; u < unit_infos + c; u++) { + _cleanup_free_ char *e = NULL; + const char *on_loaded, *off_loaded, *on = ""; + const char *on_active, *off_active, *off = ""; + + if (!n_shown && !arg_no_legend) { + printf("%-*s %-*s %-*s %-*s ", + id_len, "UNIT", + load_len, "LOAD", + active_len, "ACTIVE", + sub_len, "SUB"); + + if (job_count) + printf("%-*s ", job_len, "JOB"); + + if (!arg_full && arg_no_pager) + printf("%.*s\n", desc_len, "DESCRIPTION"); + else + printf("%s\n", "DESCRIPTION"); + } + + n_shown++; + + if (streq(u->load_state, "error") || + streq(u->load_state, "not-found")) { + on_loaded = on = ansi_highlight_red(); + off_loaded = off = ansi_highlight_off(); + } else + on_loaded = off_loaded = ""; + + if (streq(u->active_state, "failed")) { + on_active = on = ansi_highlight_red(); + off_active = off = ansi_highlight_off(); + } else + on_active = off_active = ""; + + e = arg_full ? NULL : ellipsize(u->id, id_len, 33); + + printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s", + on, id_len, e ? e : u->id, off, + on_loaded, load_len, u->load_state, off_loaded, + on_active, active_len, u->active_state, + sub_len, u->sub_state, off_active, + job_count ? job_len + 1 : 0, u->job_id ? u->job_type : ""); + + if (desc_len > 0) + printf("%.*s\n", desc_len, u->description); + else + printf("%s\n", u->description); + } + + if (!arg_no_legend) { + const char *on, *off; + + if (n_shown) { + puts("\nLOAD = Reflects whether the unit definition was properly loaded.\n" + "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" + "SUB = The low-level unit activation state, values depend on unit type."); + puts(job_count ? "JOB = Pending job for the unit.\n" : ""); + on = ansi_highlight(); + off = ansi_highlight_off(); + } else { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } + + if (arg_all) + printf("%s%u loaded units listed.%s\n" + "To show all installed unit files use 'systemctl list-unit-files'.\n", + on, n_shown, off); + else + printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n" + "To show all installed unit files use 'systemctl list-unit-files'.\n", + on, n_shown, off); + } +} + +static int get_unit_list( + sd_bus *bus, + sd_bus_message **_reply, + UnitInfo **_unit_infos, + char **patterns) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + size_t size = 0; + int r, c = 0; + UnitInfo u; + + assert(bus); + assert(_reply); + assert(_unit_infos); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits", + &error, + &reply, + NULL); + if (r < 0) { + log_error("Failed to list units: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = bus_parse_unit_info(reply, &u)) > 0) { + if (!output_show_unit(&u, patterns)) + continue; + + if (!GREEDY_REALLOC(unit_infos, size, c+1)) + return log_oom(); + + unit_infos[c++] = u; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + *_reply = reply; + reply = NULL; + + *_unit_infos = unit_infos; + unit_infos = NULL; + + return c; +} + +static int list_units(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + int r; + + pager_open_if_enabled(); + + r = get_unit_list(bus, &reply, &unit_infos, strv_skip_first(args)); + if (r < 0) + return r; + + qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info); + output_units_list(unit_infos, r); + + return 0; +} + +static int get_triggered_units( + sd_bus *bus, + const char* path, + char*** ret) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "Triggers", + &error, + ret); + + if (r < 0) + log_error("Failed to determine triggers: %s", bus_error_message(&error, r)); + + return 0; +} + +static int get_listening( + sd_bus *bus, + const char* unit_path, + char*** listening) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *type, *path; + int r, n = 0; + + r = sd_bus_get_property( + bus, + "org.freedesktop.systemd1", + unit_path, + "org.freedesktop.systemd1.Socket", + "Listen", + &error, + &reply, + "a(ss)"); + if (r < 0) { + log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) { + + r = strv_extend(listening, type); + if (r < 0) + return log_oom(); + + r = strv_extend(listening, path); + if (r < 0) + return log_oom(); + + n++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + return n; +} + +struct socket_info { + const char* id; + + char* type; + char* path; + + /* Note: triggered is a list here, although it almost certainly + * will always be one unit. Nevertheless, dbus API allows for multiple + * values, so let's follow that.*/ + char** triggered; + + /* The strv above is shared. free is set only in the first one. */ + bool own_triggered; +}; + +static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) { + int o; + + assert(a); + assert(b); + + o = strcmp(a->path, b->path); + if (o == 0) + o = strcmp(a->type, b->type); + + return o; +} + +static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { + struct socket_info *s; + unsigned pathlen = sizeof("LISTEN") - 1, + typelen = (sizeof("TYPE") - 1) * arg_show_types, + socklen = sizeof("UNIT") - 1, + servlen = sizeof("ACTIVATES") - 1; + const char *on, *off; + + for (s = socket_infos; s < socket_infos + cs; s++) { + unsigned tmp = 0; + char **a; + + socklen = MAX(socklen, strlen(s->id)); + if (arg_show_types) + typelen = MAX(typelen, strlen(s->type)); + pathlen = MAX(pathlen, strlen(s->path)); + + STRV_FOREACH(a, s->triggered) + tmp += strlen(*a) + 2*(a != s->triggered); + servlen = MAX(servlen, tmp); + } + + if (cs) { + if (!arg_no_legend) + printf("%-*s %-*.*s%-*s %s\n", + pathlen, "LISTEN", + typelen + arg_show_types, typelen + arg_show_types, "TYPE ", + socklen, "UNIT", + "ACTIVATES"); + + for (s = socket_infos; s < socket_infos + cs; s++) { + char **a; + + if (arg_show_types) + printf("%-*s %-*s %-*s", + pathlen, s->path, typelen, s->type, socklen, s->id); + else + printf("%-*s %-*s", + pathlen, s->path, socklen, s->id); + STRV_FOREACH(a, s->triggered) + printf("%s %s", + a == s->triggered ? "" : ",", *a); + printf("\n"); + } + + on = ansi_highlight(); + off = ansi_highlight_off(); + if (!arg_no_legend) + printf("\n"); + } else { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } + + if (!arg_no_legend) { + printf("%s%u sockets listed.%s\n", on, cs, off); + if (!arg_all) + printf("Pass --all to see loaded but inactive sockets, too.\n"); + } + + return 0; +} + +static int list_sockets(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + _cleanup_free_ struct socket_info *socket_infos = NULL; + const UnitInfo *u; + struct socket_info *s; + unsigned cs = 0; + size_t size = 0; + int r = 0, n; + + pager_open_if_enabled(); + + n = get_unit_list(bus, &reply, &unit_infos, strv_skip_first(args)); + if (n < 0) + return n; + + for (u = unit_infos; u < unit_infos + n; u++) { + _cleanup_strv_free_ char **listening = NULL, **triggered = NULL; + int i, c; + + if (!endswith(u->id, ".socket")) + continue; + + r = get_triggered_units(bus, u->unit_path, &triggered); + if (r < 0) + goto cleanup; + + c = get_listening(bus, u->unit_path, &listening); + if (c < 0) { + r = c; + goto cleanup; + } + + if (!GREEDY_REALLOC(socket_infos, size, cs + c)) { + r = log_oom(); + goto cleanup; + } + + for (i = 0; i < c; i++) + socket_infos[cs + i] = (struct socket_info) { + .id = u->id, + .type = listening[i*2], + .path = listening[i*2 + 1], + .triggered = triggered, + .own_triggered = i==0, + }; + + /* from this point on we will cleanup those socket_infos */ + cs += c; + free(listening); + listening = triggered = NULL; /* avoid cleanup */ + } + + qsort_safe(socket_infos, cs, sizeof(struct socket_info), + (__compar_fn_t) socket_info_compare); + + output_sockets_list(socket_infos, cs); + + cleanup: + assert(cs == 0 || socket_infos); + for (s = socket_infos; s < socket_infos + cs; s++) { + free(s->type); + free(s->path); + if (s->own_triggered) + strv_free(s->triggered); + } + + return r; +} + +static int get_next_elapse( + sd_bus *bus, + const char *path, + dual_timestamp *next) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + dual_timestamp t; + int r; + + assert(bus); + assert(path); + assert(next); + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Timer", + "NextElapseUSecMonotonic", + &error, + 't', + &t.monotonic); + if (r < 0) { + log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Timer", + "NextElapseUSecRealtime", + &error, + 't', + &t.realtime); + if (r < 0) { + log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r)); + return r; + } + + *next = t; + return 0; +} + +struct timer_info { + const char* id; + usec_t next_elapse; + char** triggered; +}; + +static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) { + assert(a); + assert(b); + + if (a->next_elapse < b->next_elapse) + return -1; + if (a->next_elapse > b->next_elapse) + return 1; + + return strcmp(a->id, b->id); +} + +static int output_timers_list(struct timer_info *timer_infos, unsigned n) { + struct timer_info *t; + unsigned + nextlen = sizeof("NEXT") - 1, + leftlen = sizeof("LEFT") - 1, + unitlen = sizeof("UNIT") - 1, + activatelen = sizeof("ACTIVATES") - 1; + + const char *on, *off; + + assert(timer_infos || n == 0); + + for (t = timer_infos; t < timer_infos + n; t++) { + unsigned ul = 0; + char **a; + + if (t->next_elapse > 0) { + char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = ""; + + format_timestamp(tstamp, sizeof(tstamp), t->next_elapse); + nextlen = MAX(nextlen, strlen(tstamp) + 1); + + format_timestamp_relative(trel, sizeof(trel), t->next_elapse); + leftlen = MAX(leftlen, strlen(trel)); + } + + unitlen = MAX(unitlen, strlen(t->id)); + + STRV_FOREACH(a, t->triggered) + ul += strlen(*a) + 2*(a != t->triggered); + activatelen = MAX(activatelen, ul); + } + + if (n > 0) { + if (!arg_no_legend) + printf("%-*s %-*s %-*s %s\n", + nextlen, "NEXT", + leftlen, "LEFT", + unitlen, "UNIT", + "ACTIVATES"); + + for (t = timer_infos; t < timer_infos + n; t++) { + char tstamp[FORMAT_TIMESTAMP_MAX] = "n/a", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a"; + char **a; + + format_timestamp(tstamp, sizeof(tstamp), t->next_elapse); + format_timestamp_relative(trel, sizeof(trel), t->next_elapse); + + printf("%-*s %-*s %-*s", + nextlen, tstamp, leftlen, trel, unitlen, t->id); + + STRV_FOREACH(a, t->triggered) + printf("%s %s", + a == t->triggered ? "" : ",", *a); + printf("\n"); + } + + on = ansi_highlight(); + off = ansi_highlight_off(); + if (!arg_no_legend) + printf("\n"); + } else { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } + + if (!arg_no_legend) { + printf("%s%u timers listed.%s\n", on, n, off); + if (!arg_all) + printf("Pass --all to see loaded but inactive timers, too.\n"); + } + + return 0; +} + +static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) { + usec_t next_elapse; + + assert(nw); + assert(next); + + if (next->monotonic != (usec_t) -1 && next->monotonic > 0) { + usec_t converted; + + if (next->monotonic > nw->monotonic) + converted = nw->realtime + (next->monotonic - nw->monotonic); + else + converted = nw->realtime - (nw->monotonic - next->monotonic); + + if (next->realtime != (usec_t) -1 && next->realtime > 0) + next_elapse = MIN(converted, next->realtime); + else + next_elapse = converted; + + } else + next_elapse = next->realtime; + + return next_elapse; +} + +static int list_timers(sd_bus *bus, char **args) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ struct timer_info *timer_infos = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + struct timer_info *t; + const UnitInfo *u; + size_t size = 0; + int n, c = 0; + dual_timestamp nw; + int r = 0; + + pager_open_if_enabled(); + + n = get_unit_list(bus, &reply, &unit_infos, strv_skip_first(args)); + if (n < 0) + return n; + + dual_timestamp_get(&nw); + + for (u = unit_infos; u < unit_infos + n; u++) { + _cleanup_strv_free_ char **triggered = NULL; + dual_timestamp next = {}; + usec_t m; + + if (!endswith(u->id, ".timer")) + continue; + + r = get_triggered_units(bus, u->unit_path, &triggered); + if (r < 0) + goto cleanup; + + r = get_next_elapse(bus, u->unit_path, &next); + if (r < 0) + goto cleanup; + + if (!GREEDY_REALLOC(timer_infos, size, c+1)) { + r = log_oom(); + goto cleanup; + } + + m = calc_next_elapse(&nw, &next); + + timer_infos[c++] = (struct timer_info) { + .id = u->id, + .next_elapse = m, + .triggered = triggered, + }; + + triggered = NULL; /* avoid cleanup */ + } + + qsort_safe(timer_infos, c, sizeof(struct timer_info), + (__compar_fn_t) timer_info_compare); + + output_timers_list(timer_infos, c); + + cleanup: + for (t = timer_infos; t < timer_infos + c; t++) + strv_free(t->triggered); + + return r; +} + +static int compare_unit_file_list(const void *a, const void *b) { + const char *d1, *d2; + const UnitFileList *u = a, *v = b; + + d1 = strrchr(u->path, '.'); + d2 = strrchr(v->path, '.'); + + if (d1 && d2) { + int r; + + r = strcasecmp(d1, d2); + if (r != 0) + return r; + } + + return strcasecmp(basename(u->path), basename(v->path)); +} + +static bool output_show_unit_file(const UnitFileList *u, char **patterns) { + const char *dot; + + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0) + return true; + return false; + } + + return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1)); +} + +static void output_unit_file_list(const UnitFileList *units, unsigned c) { + unsigned max_id_len, id_cols, state_cols, n_shown = 0; + const UnitFileList *u; + + max_id_len = sizeof("UNIT FILE")-1; + state_cols = sizeof("STATE")-1; + + for (u = units; u < units + c; u++) { + max_id_len = MAX(max_id_len, strlen(basename(u->path))); + state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state))); + } + + if (!arg_full) { + unsigned basic_cols; + + id_cols = MIN(max_id_len, 25u); + basic_cols = 1 + id_cols + state_cols; + if (basic_cols < (unsigned) columns()) + id_cols += MIN(columns() - basic_cols, max_id_len - id_cols); + } else + id_cols = max_id_len; + + if (!arg_no_legend) + printf("%-*s %-*s\n", + id_cols, "UNIT FILE", + state_cols, "STATE"); + + for (u = units; u < units + c; u++) { + _cleanup_free_ char *e = NULL; + const char *on, *off; + const char *id; + + n_shown++; + + if (u->state == UNIT_FILE_MASKED || + u->state == UNIT_FILE_MASKED_RUNTIME || + u->state == UNIT_FILE_DISABLED || + u->state == UNIT_FILE_INVALID) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else if (u->state == UNIT_FILE_ENABLED) { + on = ansi_highlight_green(); + off = ansi_highlight_off(); + } else + on = off = ""; + + id = basename(u->path); + + e = arg_full ? NULL : ellipsize(id, id_cols, 33); + + printf("%-*s %s%-*s%s\n", + id_cols, e ? e : id, + on, state_cols, unit_file_state_to_string(u->state), off); + } + + if (!arg_no_legend) + printf("\n%u unit files listed.\n", n_shown); +} + +static int list_unit_files(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ UnitFileList *units = NULL; + UnitFileList *unit; + size_t size = 0; + unsigned c = 0; + const char *state; + char *path; + int r; + + pager_open_if_enabled(); + + if (avoid_bus()) { + Hashmap *h; + UnitFileList *u; + Iterator i; + unsigned n_units; + + h = hashmap_new(string_hash_func, string_compare_func); + if (!h) + return log_oom(); + + r = unit_file_get_list(arg_scope, arg_root, h); + if (r < 0) { + unit_file_list_free(h); + log_error("Failed to get unit file list: %s", strerror(-r)); + return r; + } + + n_units = hashmap_size(h); + units = new(UnitFileList, n_units); + if (!units) { + unit_file_list_free(h); + return log_oom(); + } + + HASHMAP_FOREACH(u, h, i) { + if (!output_show_unit_file(u, strv_skip_first(args))) + continue; + + units[c++] = *u; + free(u); + } + + assert(c <= n_units); + hashmap_free(h); + } else { + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnitFiles", + &error, + &reply, + NULL); + if (r < 0) { + log_error("Failed to list unit files: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) { + + if (!GREEDY_REALLOC(units, size, c + 1)) + return log_oom(); + + units[c] = (struct UnitFileList) { + path, + unit_file_state_from_string(state) + }; + + if (output_show_unit_file(&units[c], strv_skip_first(args))) + c ++; + + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + } + + if (c > 0) { + qsort(units, c, sizeof(UnitFileList), compare_unit_file_list); + output_unit_file_list(units, c); + } + + if (avoid_bus()) + for (unit = units; unit < units + c; unit++) + free(unit->path); + + return 0; +} + +static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) { + _cleanup_free_ char *n = NULL; + size_t max_len = MAX(columns(),20u); + size_t len = 0; + int i; + + if (!arg_plain) { + + for (i = level - 1; i >= 0; i--) { + len += 2; + if (len > max_len - 3 && !arg_full) { + printf("%s...\n",max_len % 2 ? "" : " "); + return 0; + } + printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE)); + } + len += 2; + + if (len > max_len - 3 && !arg_full) { + printf("%s...\n",max_len % 2 ? "" : " "); + return 0; + } + + printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + } + + if (arg_full){ + printf("%s\n", name); + return 0; + } + + n = ellipsize(name, max_len-len, 100); + if (!n) + return log_oom(); + + printf("%s\n", n); + return 0; +} + +static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) { + + static const char *dependencies[_DEPENDENCY_MAX] = { + [DEPENDENCY_FORWARD] = "Requires\0" + "RequiresOverridable\0" + "Requisite\0" + "RequisiteOverridable\0" + "Wants\0", + [DEPENDENCY_REVERSE] = "RequiredBy\0" + "RequiredByOverridable\0" + "WantedBy\0" + "PartOf\0", + [DEPENDENCY_AFTER] = "After\0", + [DEPENDENCY_BEFORE] = "Before\0", + }; + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **ret = NULL; + _cleanup_free_ char *path = NULL; + int r; + + assert(bus); + assert(name); + assert(deps); + assert_cc(ELEMENTSOF(dependencies) == _DEPENDENCY_MAX); + + path = unit_dbus_path_from_name(name); + if (!path) + return log_oom(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", "org.freedesktop.systemd1.Unit"); + if (r < 0) { + log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *prop; + + r = sd_bus_message_read(reply, "s", &prop); + if (r < 0) + return bus_log_parse_error(r); + + if (!nulstr_contains(dependencies[arg_dependency], prop)) { + r = sd_bus_message_skip(reply, "v"); + if (r < 0) + return bus_log_parse_error(r); + } else { + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, "as"); + if (r < 0) + return bus_log_parse_error(r); + + r = bus_message_read_strv_extend(reply, &ret); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + *deps = ret; + ret = NULL; + + return 0; +} + +static int list_dependencies_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + + if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET) + return 1; + if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET) + return -1; + + return strcasecmp(*a, *b); +} + +static int list_dependencies_one( + sd_bus *bus, + const char *name, + int level, + char ***units, + unsigned int branches) { + + _cleanup_strv_free_ char **deps = NULL; + char **c; + int r = 0; + + assert(bus); + assert(name); + assert(units); + + r = strv_extend(units, name); + if (r < 0) + return log_oom(); + + r = list_dependencies_get_dependencies(bus, name, &deps); + if (r < 0) + return r; + + qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare); + + STRV_FOREACH(c, deps) { + int state; + + if (strv_contains(*units, *c)) { + if (!arg_plain) { + r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1); + if (r < 0) + return r; + } + continue; + } + + state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true); + if (state > 0) + printf("%s%s%s", ansi_highlight_green(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off()); + else + printf("%s%s%s", ansi_highlight_red(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off()); + + r = list_dependencies_print(*c, level, branches, c[1] == NULL); + if (r < 0) + return r; + + if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) { + r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1)); + if (r < 0) + return r; + } + } + + if (!arg_plain) + strv_remove(*units, name); + + return 0; +} + +static int list_dependencies(sd_bus *bus, char **args) { + _cleanup_strv_free_ char **units = NULL; + _cleanup_free_ char *unit = NULL; + const char *u; + + assert(bus); + + if (args[1]) { + unit = unit_name_mangle(args[1], MANGLE_NOGLOB); + if (!unit) + return log_oom(); + u = unit; + } else + u = SPECIAL_DEFAULT_TARGET; + + pager_open_if_enabled(); + + puts(u); + + return list_dependencies_one(bus, u, 0, &units, 0); +} + +static int get_default(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *_path = NULL; + const char *path; + int r; + + if (!bus || avoid_bus()) { + r = unit_file_get_default(arg_scope, arg_root, &_path); + if (r < 0) { + log_error("Failed to get default target: %s", strerror(-r)); + return r; + } + path = _path; + + } else { + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetDefaultTarget", + &error, + &reply, + NULL); + if (r < 0) { + log_error("Failed to get default target: %s", bus_error_message(&error, -r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &path); + if (r < 0) + return bus_log_parse_error(r); + } + + if (path) + printf("%s\n", path); + + return 0; +} + +static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) { + unsigned i; + + assert(changes || n_changes == 0); + + for (i = 0; i < n_changes; i++) { + if (changes[i].type == UNIT_FILE_SYMLINK) + log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path); + else + log_info("rm '%s'", changes[i].path); + } +} + +static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) { + const char *type, *path, *source; + int r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { + if (!arg_quiet) { + if (streq(type, "symlink")) + log_info("ln -s '%s' '%s'", source, path); + else + log_info("rm '%s'", path); + } + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; +} + +static int set_default(sd_bus *bus, char **args) { + _cleanup_free_ char *unit = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int r; + + unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target"); + if (!unit) + return log_oom(); + + if (!bus || avoid_bus()) { + r = unit_file_set_default(arg_scope, arg_root, unit, arg_force, &changes, &n_changes); + if (r < 0) { + log_error("Failed to set default target: %s", strerror(-r)); + return r; + } + + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); + + r = 0; + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetDefaultTarget", + &error, + &reply, + "sb", unit, arg_force); + if (r < 0) { + log_error("Failed to set default target: %s", bus_error_message(&error, -r)); + return r; + } + + r = deserialize_and_dump_unit_file_changes(reply); + if (r < 0) + return r; + + /* Try to reload if enabeld */ + if (!arg_no_reload) + r = daemon_reload(bus, args); + else + r = 0; + } + + unit_file_changes_free(changes, n_changes); + + return r; +} + +struct job_info { + uint32_t id; + const char *name, *type, *state; +}; + +static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipped) { + unsigned id_len, unit_len, type_len, state_len; + const struct job_info *j; + const char *on, *off; + bool shorten = false; + + assert(n == 0 || jobs); + + if (n == 0) { + on = ansi_highlight_green(); + off = ansi_highlight_off(); + + printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off); + return; + } + + pager_open_if_enabled(); + + id_len = sizeof("JOB")-1; + unit_len = sizeof("UNIT")-1; + type_len = sizeof("TYPE")-1; + state_len = sizeof("STATE")-1; + + for (j = jobs; j < jobs + n; j++) { + uint32_t id = j->id; + assert(j->name && j->type && j->state); + + id_len = MAX(id_len, DECIMAL_STR_WIDTH(id)); + unit_len = MAX(unit_len, strlen(j->name)); + type_len = MAX(type_len, strlen(j->type)); + state_len = MAX(state_len, strlen(j->state)); + } + + if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) { + unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3); + shorten = true; + } + + if (!arg_no_legend) + printf("%*s %-*s %-*s %-*s\n", + id_len, "JOB", + unit_len, "UNIT", + type_len, "TYPE", + state_len, "STATE"); + + for (j = jobs; j < jobs + n; j++) { + _cleanup_free_ char *e = NULL; + + if (streq(j->state, "running")) { + on = ansi_highlight(); + off = ansi_highlight_off(); + } else + on = off = ""; + + e = shorten ? ellipsize(j->name, unit_len, 33) : NULL; + printf("%*u %s%-*s%s %-*s %s%-*s%s\n", + id_len, j->id, + on, unit_len, e ? e : j->name, off, + type_len, j->type, + on, state_len, j->state, off); + } + + if (!arg_no_legend) { + on = ansi_highlight(); + off = ansi_highlight_off(); + + printf("\n%s%u jobs listed%s.\n", on, n, off); + } +} + +static bool output_show_job(struct job_info *job, char **patterns) { + if (!strv_isempty(patterns)) { + char **pattern; + + STRV_FOREACH(pattern, patterns) + if (fnmatch(*pattern, job->name, FNM_NOESCAPE) == 0) + return true; + return false; + } + + return true; +} + +static int list_jobs(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *name, *type, *state, *job_path, *unit_path; + _cleanup_free_ struct job_info *jobs = NULL; + size_t size = 0; + unsigned c = 0; + uint32_t id; + int r; + bool skipped = false; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListJobs", + &error, + &reply, + NULL); + if (r < 0) { + log_error("Failed to list jobs: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, 'a', "(usssoo)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) { + struct job_info job = { id, name, type, state }; + + if (!output_show_job(&job, strv_skip_first(args))) { + skipped = true; + continue; + } + + if (!GREEDY_REALLOC(jobs, size, c + 1)) + return log_oom(); + + jobs[c++] = job; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + output_jobs_list(jobs, c, skipped); + return r; +} + +static int cancel_job(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char **name; + + assert(args); + + if (strv_length(args) <= 1) + return daemon_reload(bus, args); + + STRV_FOREACH(name, args+1) { + uint32_t id; + int r; + + r = safe_atou32(*name, &id); + if (r < 0) { + log_error("Failed to parse job id \"%s\": %s", *name, strerror(-r)); + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "CancelJob", + &error, + NULL, + "u", id); + if (r < 0) { + log_error("Failed to cancel job %u: %s", (unsigned) id, bus_error_message(&error, r)); + return r; + } + } + + return 0; +} + +static int need_daemon_reload(sd_bus *bus, const char *unit) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *path; + int b, r; + + /* We ignore all errors here, since this is used to show a + * warning only */ + + /* We don't use unit_dbus_path_from_name() directly since we + * don't want to load the unit if it isn't loaded. */ + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnit", + NULL, + &reply, + "s", unit); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return r; + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "NeedDaemonReload", + NULL, + 'b', &b); + if (r < 0) + return r; + + return b; +} + +typedef struct WaitData { + Set *set; + + char *name; + char *result; +} WaitData; + +static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *error) { + WaitData *d = data; + + assert(bus); + assert(m); + assert(d); + + log_debug("Got D-Bus request: %s.%s() on %s", + sd_bus_message_get_interface(m), + sd_bus_message_get_member(m), + sd_bus_message_get_path(m)); + + if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) { + log_error("Warning! D-Bus connection terminated."); + sd_bus_close(bus); + } else if (sd_bus_message_is_signal(m, "org.freedesktop.systemd1.Manager", "JobRemoved")) { + uint32_t id; + const char *path, *result, *unit; + char *ret; + int r; + + r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result); + if (r >= 0) { + ret = set_remove(d->set, (char*) path); + if (!ret) + return 0; + + free(ret); + + if (!isempty(result)) + d->result = strdup(result); + + if (!isempty(unit)) + d->name = strdup(unit); + + return 0; + } +#ifndef NOLEGACY + r = sd_bus_message_read(m, "uos", &id, &path, &result); + if (r >= 0) { + ret = set_remove(d->set, (char*) path); + if (!ret) + return 0; + + free(ret); + + if (*result) + d->result = strdup(result); + + return 0; + } +#endif + + bus_log_parse_error(r); + } + + return 0; +} + +static int enable_wait_for_jobs(sd_bus *bus) { + int r; + + assert(bus); + + r = sd_bus_add_match( + bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + NULL, NULL); + if (r < 0) { + log_error("Failed to add match"); + return -EIO; + } + + /* This is slightly dirty, since we don't undo the match registrations. */ + 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 check_wait_response(WaitData *d) { + int r = 0; + + assert(d->result); + + if (!arg_quiet) { + if (streq(d->result, "timeout")) + log_error("Job for %s timed out.", strna(d->name)); + else if (streq(d->result, "canceled")) + log_error("Job for %s canceled.", strna(d->name)); + else if (streq(d->result, "dependency")) + log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d->name)); + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) + log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d->name), strna(d->name)); + } + + if (streq(d->result, "timeout")) + r = -ETIME; + else if (streq(d->result, "canceled")) + r = -ECANCELED; + else if (streq(d->result, "dependency")) + r = -EIO; + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) + r = -EIO; + + return r; +} + +static int wait_for_jobs(sd_bus *bus, Set *s) { + WaitData d = { .set = s }; + int r = 0, q; + + assert(bus); + assert(s); + + q = sd_bus_add_filter(bus, wait_filter, &d); + if (q < 0) + return log_oom(); + + while (!set_isempty(s)) { + q = bus_process_wait(bus); + if (q < 0) { + log_error("Failed to wait for response: %s", strerror(-r)); + return q; + } + + if (d.result) { + q = check_wait_response(&d); + /* Return the first error as it is most likely to be + * meaningful. */ + if (q < 0 && r == 0) + r = q; + log_debug("Got result %s/%s for job %s", + strna(d.result), strerror(-q), strna(d.name)); + } + + free(d.name); + d.name = NULL; + + free(d.result); + d.result = NULL; + } + + q = sd_bus_remove_filter(bus, wait_filter, &d); + if (q < 0 && r == 0) + r = q; + + return r; +} + +static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ char *n = NULL, *state = NULL; + const char *path; + int r; + + assert(name); + + n = unit_name_mangle(name, MANGLE_NOGLOB); + if (!n) + return log_oom(); + + /* We don't use unit_dbus_path_from_name() directly since we + * don't want to load the unit if it isn't loaded. */ + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnit", + NULL, + &reply, + "s", n); + if (r < 0) { + if (!quiet) + puts("unknown"); + return 0; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + NULL, + &state); + if (r < 0) { + if (!quiet) + puts("unknown"); + return 0; + } + + if (!quiet) + puts(state); + + return nulstr_contains(good_states, state); +} + +static int check_triggering_units( + sd_bus *bus, + const char *name) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL; + _cleanup_strv_free_ char **triggered_by = NULL; + bool print_warning_label = true; + char **i; + int r; + + n = unit_name_mangle(name, MANGLE_NOGLOB); + if (!n) + return log_oom(); + + path = unit_dbus_path_from_name(n); + if (!path) + return log_oom(); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "LoadState", + &error, + &state); + if (r < 0) { + log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r)); + return r; + } + + if (streq(state, "masked")) + return 0; + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "TriggeredBy", + &error, + &triggered_by); + if (r < 0) { + log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); + return r; + } + + STRV_FOREACH(i, triggered_by) { + r = check_one_unit(bus, *i, "active\0reloading\0", true); + if (r < 0) { + log_error("Failed to check unit: %s", strerror(-r)); + return r; + } + + if (r == 0) + continue; + + if (print_warning_label) { + log_warning("Warning: Stopping %s, but it can still be activated by:", n); + print_warning_label = false; + } + + log_warning(" %s", *i); + } + + return 0; +} + +static const char *verb_to_method(const char *verb) { + uint i; + + for (i = 0; i < ELEMENTSOF(unit_actions); i++) + if (streq_ptr(unit_actions[i].verb, verb)) + return unit_actions[i].method; + + return "StartUnit"; +} + +static const char *method_to_verb(const char *method) { + uint i; + + for (i = 0; i < ELEMENTSOF(unit_actions); i++) + if (streq_ptr(unit_actions[i].method, method)) + return unit_actions[i].verb; + + return "n/a"; +} + +static int start_unit_one( + sd_bus *bus, + const char *method, + const char *name, + const char *mode, + sd_bus_error *error, + Set *s) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *path; + int r; + + assert(method); + assert(name); + assert(mode); + assert(error); + + log_debug("Calling manager for %s on %s, %s", method, name, mode); + 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 (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) + /* There's always a fallback possible for + * legacy actions. */ + return -EADDRNOTAVAIL; + + verb = method_to_verb(method); + + log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + if (need_daemon_reload(bus, name) > 0) + log_warning("Warning: Unit file of %s changed on disk, 'systemctl%s daemon-reload' recommended.", + name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + + if (s) { + char *p; + + p = strdup(path); + if (!p) + return log_oom(); + + log_debug("Adding %s to the set", p); + r = set_consume(s, p); + if (r < 0) + return log_oom(); + } + + return 0; +} + +static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **mangled = NULL, **globs = NULL; + char **name; + int r = 0, i; + + STRV_FOREACH(name, names) { + char *t; + + if (suffix) + t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix); + else + t = unit_name_mangle(*name, MANGLE_GLOB); + if (!t) + return log_oom(); + + if (string_is_glob(t)) + r = strv_push(&globs, t); + else + r = strv_push(&mangled, t); + if (r < 0) { + free(t); + return log_oom(); + } + } + + /* Query the manager only if any of the names are a glob, since + * this is fairly expensive */ + if (!strv_isempty(globs)) { + _cleanup_free_ UnitInfo *unit_infos = NULL; + + r = get_unit_list(bus, &reply, &unit_infos, globs); + if (r < 0) + return r; + + for (i = 0; i < r; i++) + if (strv_extend(&mangled, unit_infos[i].id) < 0) + return log_oom(); + } + + *ret = mangled; + mangled = NULL; /* do not free */ + return 0; +} + +static const struct { + const char *target; + const char *verb; + const char *mode; +} action_table[_ACTION_MAX] = { + [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, + [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, + [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" }, + [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" }, + [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_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" }, +}; + +static enum action verb_to_action(const char *verb) { + enum action i; + + for (i = _ACTION_INVALID; i < _ACTION_MAX; i++) + if (streq_ptr(action_table[i].verb, verb)) + return i; + + return _ACTION_INVALID; +} + +static int start_unit(sd_bus *bus, char **args) { + _cleanup_set_free_free_ Set *s = NULL; + _cleanup_strv_free_ char **names = NULL; + const char *method, *mode, *one_name; + char **name; + int r = 0; + + assert(bus); + + ask_password_agent_open_if_enabled(); + + if (arg_action == ACTION_SYSTEMCTL) { + enum action action; + method = verb_to_method(args[0]); + action = verb_to_action(args[0]); + + mode = streq(args[0], "isolate") ? "isolate" : + action_table[action].mode ?: arg_job_mode; + + one_name = action_table[action].target; + } else { + assert(arg_action < ELEMENTSOF(action_table)); + assert(action_table[arg_action].target); + + method = "StartUnit"; + + mode = action_table[arg_action].mode; + one_name = action_table[arg_action].target; + } + + if (one_name) + names = strv_new(one_name, NULL); + else { + r = expand_names(bus, args + 1, NULL, &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + } + + if (!arg_no_block) { + r = enable_wait_for_jobs(bus); + if (r < 0) { + log_error("Could not watch jobs: %s", strerror(-r)); + return r; + } + + s = set_new(string_hash_func, string_compare_func); + if (!s) + return log_oom(); + } + + STRV_FOREACH(name, names) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int q; + + q = start_unit_one(bus, method, *name, mode, &error, s); + if (r >= 0 && q < 0) + r = translate_bus_error_to_exit_status(q, &error); + } + + if (!arg_no_block) { + int q; + + q = wait_for_jobs(bus, s); + if (q < 0) + return q; + + /* When stopping units, warn if they can still be triggered by + * another active unit (socket, path, timer) */ + if (!arg_quiet && streq(method, "StopUnit")) + STRV_FOREACH(name, names) + check_triggering_units(bus, *name); + } + + return r; +} + +/* Ask systemd-logind, which might grant access to unprivileged users + * through PolicyKit */ +static int reboot_with_logind(sd_bus *bus, enum action a) { +#ifdef HAVE_LOGIND + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method; + int r; + + if (!bus) + return -EIO; + + polkit_agent_open_if_enabled(); + + switch (a) { + + case ACTION_REBOOT: + method = "Reboot"; + break; + + case ACTION_POWEROFF: + method = "PowerOff"; + break; + + case ACTION_SUSPEND: + method = "Suspend"; + break; + + case ACTION_HIBERNATE: + method = "Hibernate"; + break; + + case ACTION_HYBRID_SLEEP: + method = "HybridSleep"; + break; + + default: + return -EINVAL; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + method, + &error, + NULL, + "b", true); + if (r < 0) + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + + return r; +#else + return -ENOSYS; +#endif +} + +static int check_inhibitors(sd_bus *bus, enum action a) { +#ifdef HAVE_LOGIND + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **sessions = NULL; + const char *what, *who, *why, *mode; + uint32_t uid, pid; + unsigned c = 0; + char **s; + int r; + + if (!bus) + return 0; + + if (arg_ignore_inhibitors || arg_force > 0) + return 0; + + if (arg_when > 0) + return 0; + + if (geteuid() == 0) + return 0; + + if (!on_tty()) + return 0; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListInhibitors", + NULL, + &reply, + NULL); + if (r < 0) + /* If logind is not around, then there are no inhibitors... */ + return 0; + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) { + _cleanup_free_ char *comm = NULL, *user = NULL; + _cleanup_strv_free_ char **sv = NULL; + + if (!streq(mode, "block")) + continue; + + sv = strv_split(what, ":"); + if (!sv) + return log_oom(); + + if (!strv_contains(sv, + a == ACTION_HALT || + a == ACTION_POWEROFF || + a == ACTION_REBOOT || + a == ACTION_KEXEC ? "shutdown" : "sleep")) + continue; + + get_process_comm(pid, &comm); + user = uid_to_name(uid); + + log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".", + who, (unsigned long) pid, strna(comm), strna(user), why); + + c++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + /* Check for current sessions */ + sd_get_sessions(&sessions); + STRV_FOREACH(s, sessions) { + _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL; + + if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid()) + continue; + + if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user")) + continue; + + if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty"))) + continue; + + sd_session_get_tty(*s, &tty); + sd_session_get_seat(*s, &seat); + sd_session_get_service(*s, &service); + user = uid_to_name(uid); + + log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty); + c++; + } + + if (c <= 0) + return 0; + + log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.", + action_table[a].verb); + + return -EPERM; +#else + return 0; +#endif +} + +static int start_special(sd_bus *bus, char **args) { + enum action a; + int r; + + assert(args); + + a = verb_to_action(args[0]); + + r = check_inhibitors(bus, a); + if (r < 0) + return r; + + if (arg_force >= 2 && geteuid() != 0) { + log_error("Must be root."); + return -EPERM; + } + + if (arg_force >= 2 && + (a == ACTION_HALT || + a == ACTION_POWEROFF || + a == ACTION_REBOOT)) + return halt_now(a); + + if (arg_force >= 1 && + (a == ACTION_HALT || + a == ACTION_POWEROFF || + a == ACTION_REBOOT || + a == ACTION_KEXEC || + a == ACTION_EXIT)) + return daemon_reload(bus, args); + + /* first try logind, to allow authentication with polkit */ + if (geteuid() != 0 && + (a == ACTION_POWEROFF || + a == ACTION_REBOOT || + a == ACTION_SUSPEND || + a == ACTION_HIBERNATE || + a == ACTION_HYBRID_SLEEP)) { + r = reboot_with_logind(bus, a); + if (r >= 0) + return r; + } + + r = start_unit(bus, args); + if (r == EXIT_SUCCESS) + warn_wall(a); + + return r; +} + +static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) { + _cleanup_strv_free_ char **names = NULL; + char **name; + int r; + + assert(bus); + assert(args); + + r = expand_names(bus, args, NULL, &names); + if (r < 0) { + log_error("Failed to expand names: %s", strerror(-r)); + return r; + } + + STRV_FOREACH(name, names) { + int state; + + state = check_one_unit(bus, *name, good_states, arg_quiet); + if (state < 0) + return state; + if (state == 0) + r = code; + } + + return r; +} + +static int check_unit_active(sd_bus *bus, char **args) { + /* According to LSB: 3, "program is not running" */ + return check_unit_generic(bus, 3, "active\0reloading\0", args + 1); +} + +static int check_unit_failed(sd_bus *bus, char **args) { + return check_unit_generic(bus, 1, "failed\0", args + 1); +} + +static int kill_unit(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **names = NULL; + char **name; + int r, q; + + assert(bus); + assert(args); + + if (!arg_kill_who) + arg_kill_who = "all"; + + r = expand_names(bus, args + 1, NULL, &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + + STRV_FOREACH(name, names) { + q = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", *names, arg_kill_who, arg_signal); + if (q < 0) { + log_error("Failed to kill unit %s: %s", + *names, bus_error_message(&error, r)); + if (r == 0) + r = q; + } + } + + return r; +} + +typedef struct ExecStatusInfo { + char *name; + + char *path; + char **argv; + + bool ignore; + + usec_t start_timestamp; + usec_t exit_timestamp; + pid_t pid; + int code; + int status; + + LIST_FIELDS(struct ExecStatusInfo, exec); +} ExecStatusInfo; + +static void exec_status_info_free(ExecStatusInfo *i) { + assert(i); + + free(i->name); + free(i->path); + strv_free(i->argv); + free(i); +} + +static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) { + uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic; + const char *path; + uint32_t pid; + int32_t code, status; + int ignore, r; + + assert(m); + assert(i); + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii"); + if (r < 0) + return bus_log_parse_error(r); + else if (r == 0) + return 0; + + r = sd_bus_message_read(m, "s", &path); + if (r < 0) + return bus_log_parse_error(r); + + i->path = strdup(path); + if (!i->path) + return log_oom(); + + r = sd_bus_message_read_strv(m, &i->argv); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read(m, + "bttttuii", + &ignore, + &start_timestamp, &start_timestamp_monotonic, + &exit_timestamp, &exit_timestamp_monotonic, + &pid, + &code, &status); + if (r < 0) + return bus_log_parse_error(r); + + i->ignore = ignore; + i->start_timestamp = (usec_t) start_timestamp; + i->exit_timestamp = (usec_t) exit_timestamp; + i->pid = (pid_t) pid; + i->code = code; + i->status = status; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 1; +} + +typedef struct UnitStatusInfo { + const char *id; + const char *load_state; + const char *active_state; + const char *sub_state; + const char *unit_file_state; + + const char *description; + const char *following; + + char **documentation; + + const char *fragment_path; + const char *source_path; + const char *control_group; + + char **dropin_paths; + + const char *load_error; + const char *result; + + usec_t inactive_exit_timestamp; + usec_t inactive_exit_timestamp_monotonic; + usec_t active_enter_timestamp; + usec_t active_exit_timestamp; + usec_t inactive_enter_timestamp; + + bool need_daemon_reload; + + /* Service */ + pid_t main_pid; + pid_t control_pid; + const char *status_text; + const char *pid_file; + bool running:1; + + usec_t start_timestamp; + usec_t exit_timestamp; + + int exit_code, exit_status; + + usec_t condition_timestamp; + bool condition_result; + bool failed_condition_trigger; + bool failed_condition_negate; + const char *failed_condition; + const char *failed_condition_param; + + /* Socket */ + unsigned n_accepted; + unsigned n_connections; + bool accept; + + /* Pairs of type, path */ + char **listen; + + /* Device */ + const char *sysfs_path; + + /* Mount, Automount */ + const char *where; + + /* Swap */ + const char *what; + + LIST_HEAD(ExecStatusInfo, exec); +} UnitStatusInfo; + +static void print_status_info( + UnitStatusInfo *i, + bool *ellipsized) { + + ExecStatusInfo *p; + const char *on, *off, *ss; + usec_t timestamp; + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; + char since2[FORMAT_TIMESTAMP_MAX], *s2; + const char *path; + int flags = + arg_all * OUTPUT_SHOW_ALL | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR | + !arg_quiet * OUTPUT_WARN_CUTOFF | + arg_full * OUTPUT_FULL_WIDTH; + char **t, **t2; + + assert(i); + + /* This shows pretty information about a unit. See + * print_property() for a low-level property printer */ + + printf("%s", strna(i->id)); + + if (i->description && !streq_ptr(i->id, i->description)) + printf(" - %s", i->description); + + printf("\n"); + + if (i->following) + printf(" Follow: unit currently follows state of %s\n", i->following); + + if (streq_ptr(i->load_state, "error")) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else + on = off = ""; + + path = i->source_path ? i->source_path : i->fragment_path; + + if (i->load_error) + printf(" Loaded: %s%s%s (Reason: %s)\n", + on, strna(i->load_state), off, i->load_error); + else if (path && i->unit_file_state) + printf(" Loaded: %s%s%s (%s; %s)\n", + on, strna(i->load_state), off, path, i->unit_file_state); + else if (path) + printf(" Loaded: %s%s%s (%s)\n", + on, strna(i->load_state), off, path); + else + printf(" Loaded: %s%s%s\n", + on, strna(i->load_state), off); + + if (!strv_isempty(i->dropin_paths)) { + _cleanup_free_ char *dir = NULL; + bool last = false; + char ** dropin; + + STRV_FOREACH(dropin, i->dropin_paths) { + if (! dir || last) { + printf(dir ? " " : " Drop-In: "); + + free(dir); + dir = NULL; + + if (path_get_parent(*dropin, &dir) < 0) { + log_oom(); + return; + } + + printf("%s\n %s", dir, + draw_special_char(DRAW_TREE_RIGHT)); + } + + last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir)); + + printf("%s%s", basename(*dropin), last ? "\n" : ", "); + } + } + + ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; + + if (streq_ptr(i->active_state, "failed")) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) { + on = ansi_highlight_green(); + off = ansi_highlight_off(); + } else + on = off = ""; + + if (ss) + printf(" Active: %s%s (%s)%s", + on, strna(i->active_state), ss, off); + else + printf(" Active: %s%s%s", + on, strna(i->active_state), off); + + if (!isempty(i->result) && !streq(i->result, "success")) + printf(" (Result: %s)", i->result); + + timestamp = (streq_ptr(i->active_state, "active") || + streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp : + (streq_ptr(i->active_state, "inactive") || + streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp : + streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp : + i->active_exit_timestamp; + + s1 = format_timestamp_relative(since1, sizeof(since1), timestamp); + s2 = format_timestamp(since2, sizeof(since2), timestamp); + + if (s1) + printf(" since %s; %s\n", s2, s1); + else if (s2) + printf(" since %s\n", s2); + else + printf("\n"); + + if (!i->condition_result && i->condition_timestamp > 0) { + s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); + s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); + + printf(" start condition failed at %s%s%s\n", + s2, s1 ? "; " : "", s1 ? s1 : ""); + if (i->failed_condition_trigger) + printf(" none of the trigger conditions were met\n"); + else if (i->failed_condition) + printf(" %s=%s%s was not met\n", + i->failed_condition, + i->failed_condition_negate ? "!" : "", + i->failed_condition_param); + } + + if (i->sysfs_path) + printf(" Device: %s\n", i->sysfs_path); + if (i->where) + printf(" Where: %s\n", i->where); + if (i->what) + printf(" What: %s\n", i->what); + + STRV_FOREACH(t, i->documentation) + printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t); + + STRV_FOREACH_PAIR(t, t2, i->listen) + printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t); + + if (i->accept) + printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections); + + LIST_FOREACH(exec, p, i->exec) { + _cleanup_free_ char *argv = NULL; + bool good; + + /* Only show exited processes here */ + if (p->code == 0) + continue; + + argv = strv_join(p->argv, " "); + printf(" Process: %u %s=%s ", p->pid, p->name, strna(argv)); + + good = is_clean_exit_lsb(p->code, p->status, NULL); + if (!good) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else + on = off = ""; + + printf("%s(code=%s, ", on, sigchld_code_to_string(p->code)); + + if (p->code == CLD_EXITED) { + const char *c; + + printf("status=%i", p->status); + + c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD); + if (c) + printf("/%s", c); + + } else + printf("signal=%s", signal_to_string(p->status)); + + printf(")%s\n", off); + + if (i->main_pid == p->pid && + i->start_timestamp == p->start_timestamp && + i->exit_timestamp == p->start_timestamp) + /* Let's not show this twice */ + i->main_pid = 0; + + if (p->pid == i->control_pid) + i->control_pid = 0; + } + + if (i->main_pid > 0 || i->control_pid > 0) { + if (i->main_pid > 0) { + printf(" Main PID: %u", (unsigned) i->main_pid); + + if (i->running) { + _cleanup_free_ char *comm = NULL; + get_process_comm(i->main_pid, &comm); + if (comm) + printf(" (%s)", comm); + } else if (i->exit_code > 0) { + printf(" (code=%s, ", sigchld_code_to_string(i->exit_code)); + + if (i->exit_code == CLD_EXITED) { + const char *c; + + printf("status=%i", i->exit_status); + + c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD); + if (c) + printf("/%s", c); + + } else + printf("signal=%s", signal_to_string(i->exit_status)); + printf(")"); + } + + if (i->control_pid > 0) + printf(";"); + } + + if (i->control_pid > 0) { + _cleanup_free_ char *c = NULL; + + printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid); + + get_process_comm(i->control_pid, &c); + if (c) + printf(" (%s)", c); + } + + printf("\n"); + } + + if (i->status_text) + printf(" Status: \"%s\"\n", i->status_text); + + if (i->control_group && + (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) { + unsigned c; + + printf(" CGroup: %s\n", i->control_group); + + if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_CONTAINER) { + unsigned k = 0; + pid_t extra[2]; + char prefix[] = " "; + + c = columns(); + if (c > sizeof(prefix) - 1) + c -= sizeof(prefix) - 1; + else + c = 0; + + if (i->main_pid > 0) + extra[k++] = i->main_pid; + + if (i->control_pid > 0) + extra[k++] = i->control_pid; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, + c, false, extra, k, flags); + } + } + + if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) { + printf("\n"); + show_journal_by_unit(stdout, + i->id, + arg_output, + 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, + getuid(), + flags, + arg_scope == UNIT_FILE_SYSTEM, + ellipsized); + } + + if (i->need_daemon_reload) + printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n", + ansi_highlight_red(), + ansi_highlight_off(), + arg_scope == UNIT_FILE_SYSTEM ? "" : "--user "); +} + +static void show_unit_help(UnitStatusInfo *i) { + char **p; + + assert(i); + + if (!i->documentation) { + log_info("Documentation for %s not known.", i->id); + return; + } + + STRV_FOREACH(p, i->documentation) { + + if (startswith(*p, "man:")) { + const char *args[4] = { "man", NULL, NULL, NULL }; + _cleanup_free_ char *page = NULL, *section = NULL; + char *e = NULL; + pid_t pid; + size_t k; + + k = strlen(*p); + + if ((*p)[k-1] == ')') + e = strrchr(*p, '('); + + if (e) { + page = strndup((*p) + 4, e - *p - 4); + section = strndup(e + 1, *p + k - e - 2); + if (!page || !section) { + log_oom(); + return; + } + + args[1] = section; + args[2] = page; + } else + args[1] = *p + 4; + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + continue; + } + + if (pid == 0) { + /* Child */ + execvp(args[0], (char**) args); + log_error("Failed to execute man: %m"); + _exit(EXIT_FAILURE); + } + + wait_for_terminate(pid, NULL); + } else + log_info("Can't show: %s", *p); + } +} + +static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) { + int r; + + assert(name); + assert(m); + assert(i); + + switch (contents[0]) { + + case SD_BUS_TYPE_STRING: { + const char *s; + + r = sd_bus_message_read(m, "s", &s); + if (r < 0) + return bus_log_parse_error(r); + + if (!isempty(s)) { + if (streq(name, "Id")) + i->id = s; + else if (streq(name, "LoadState")) + i->load_state = s; + else if (streq(name, "ActiveState")) + i->active_state = s; + else if (streq(name, "SubState")) + i->sub_state = s; + else if (streq(name, "Description")) + i->description = s; + else if (streq(name, "FragmentPath")) + i->fragment_path = s; + else if (streq(name, "SourcePath")) + i->source_path = s; +#ifndef NOLEGACY + else if (streq(name, "DefaultControlGroup")) { + const char *e; + e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":"); + if (e) + i->control_group = e; + } +#endif + else if (streq(name, "ControlGroup")) + i->control_group = s; + else if (streq(name, "StatusText")) + i->status_text = s; + else if (streq(name, "PIDFile")) + i->pid_file = s; + else if (streq(name, "SysFSPath")) + i->sysfs_path = s; + else if (streq(name, "Where")) + i->where = s; + else if (streq(name, "What")) + i->what = s; + else if (streq(name, "Following")) + i->following = s; + else if (streq(name, "UnitFileState")) + i->unit_file_state = s; + else if (streq(name, "Result")) + i->result = s; + } + + break; + } + + case SD_BUS_TYPE_BOOLEAN: { + int b; + + r = sd_bus_message_read(m, "b", &b); + if (r < 0) + return bus_log_parse_error(r); + + if (streq(name, "Accept")) + i->accept = b; + else if (streq(name, "NeedDaemonReload")) + i->need_daemon_reload = b; + else if (streq(name, "ConditionResult")) + i->condition_result = b; + + break; + } + + case SD_BUS_TYPE_UINT32: { + uint32_t u; + + r = sd_bus_message_read(m, "u", &u); + if (r < 0) + return bus_log_parse_error(r); + + if (streq(name, "MainPID")) { + if (u > 0) { + i->main_pid = (pid_t) u; + i->running = true; + } + } else if (streq(name, "ControlPID")) + i->control_pid = (pid_t) u; + else if (streq(name, "ExecMainPID")) { + if (u > 0) + i->main_pid = (pid_t) u; + } else if (streq(name, "NAccepted")) + i->n_accepted = u; + else if (streq(name, "NConnections")) + i->n_connections = u; + + break; + } + + case SD_BUS_TYPE_INT32: { + int32_t j; + + r = sd_bus_message_read(m, "i", &j); + if (r < 0) + return bus_log_parse_error(r); + + if (streq(name, "ExecMainCode")) + i->exit_code = (int) j; + else if (streq(name, "ExecMainStatus")) + i->exit_status = (int) j; + + break; + } + + case SD_BUS_TYPE_UINT64: { + uint64_t u; + + r = sd_bus_message_read(m, "t", &u); + if (r < 0) + return bus_log_parse_error(r); + + if (streq(name, "ExecMainStartTimestamp")) + i->start_timestamp = (usec_t) u; + else if (streq(name, "ExecMainExitTimestamp")) + i->exit_timestamp = (usec_t) u; + else if (streq(name, "ActiveEnterTimestamp")) + i->active_enter_timestamp = (usec_t) u; + else if (streq(name, "InactiveEnterTimestamp")) + i->inactive_enter_timestamp = (usec_t) u; + else if (streq(name, "InactiveExitTimestamp")) + i->inactive_exit_timestamp = (usec_t) u; + else if (streq(name, "InactiveExitTimestampMonotonic")) + i->inactive_exit_timestamp_monotonic = (usec_t) u; + else if (streq(name, "ActiveExitTimestamp")) + i->active_exit_timestamp = (usec_t) u; + else if (streq(name, "ConditionTimestamp")) + i->condition_timestamp = (usec_t) u; + + break; + } + + case SD_BUS_TYPE_ARRAY: + + if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) { + _cleanup_free_ ExecStatusInfo *info = NULL; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)"); + if (r < 0) + return bus_log_parse_error(r); + + info = new0(ExecStatusInfo, 1); + if (!info) + return log_oom(); + + while ((r = exec_status_info_deserialize(m, info)) > 0) { + + info->name = strdup(name); + if (!info->name) + log_oom(); + + LIST_PREPEND(exec, i->exec, info); + + info = new0(ExecStatusInfo, 1); + if (!info) + 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); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) { + const char *type, *path; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) { + + r = strv_extend(&i->listen, type); + if (r < 0) + return r; + + r = strv_extend(&i->listen, path); + if (r < 0) + return r; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) { + + r = sd_bus_message_read_strv(m, &i->dropin_paths); + if (r < 0) + return bus_log_parse_error(r); + + } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) { + + r = sd_bus_message_read_strv(m, &i->documentation); + if (r < 0) + return bus_log_parse_error(r); + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) { + const char *cond, *param; + int trigger, negate; + int32_t state; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &state)) > 0) { + log_debug("%s %d %d %s %d", cond, trigger, negate, param, state); + if (state < 0 && (!trigger || !i->failed_condition)) { + i->failed_condition = cond; + i->failed_condition_trigger = trigger; + i->failed_condition_negate = negate; + i->failed_condition_param = param; + } + } + 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); + + } else + goto skip; + + break; + + case SD_BUS_TYPE_STRUCT_BEGIN: + + if (streq(name, "LoadError")) { + const char *n, *message; + + r = sd_bus_message_read(m, "(ss)", &n, &message); + if (r < 0) + return bus_log_parse_error(r); + + if (!isempty(message)) + i->load_error = message; + } else + goto skip; + + break; + + default: + goto skip; + } + + return 0; + +skip: + r = sd_bus_message_skip(m, contents); + if (r < 0) + return bus_log_parse_error(r); + + return 0; +} + +static int print_property(const char *name, sd_bus_message *m, const char *contents) { + int r; + + assert(name); + assert(m); + + /* This is a low-level property printer, see + * print_status_info() for the nicer output */ + + if (arg_properties && !strv_find(arg_properties, name)) { + /* skip what we didn't read */ + r = sd_bus_message_skip(m, contents); + return r; + } + + switch (contents[0]) { + + case SD_BUS_TYPE_STRUCT_BEGIN: + + if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) { + uint32_t u; + + r = sd_bus_message_read(m, "(uo)", &u, NULL); + if (r < 0) + return bus_log_parse_error(r); + + if (u > 0) + printf("%s=%u\n", name, (unsigned) u); + else if (arg_all) + printf("%s=\n", name); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) { + const char *s; + + r = sd_bus_message_read(m, "(so)", &s, NULL); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_all || !isempty(s)) + printf("%s=%s\n", name, s); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) { + const char *a = NULL, *b = NULL; + + r = sd_bus_message_read(m, "(ss)", &a, &b); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_all || !isempty(a) || !isempty(b)) + printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b)); + + return 0; + } else if (streq_ptr(name, "SystemCallFilter")) { + _cleanup_strv_free_ char **l = NULL; + int whitelist; + + r = sd_bus_message_enter_container(m, 'r', "bas"); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read(m, "b", &whitelist); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read_strv(m, &l); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_all || whitelist || !strv_isempty(l)) { + bool first = true; + char **i; + + fputs(name, stdout); + fputc('=', stdout); + + if (!whitelist) + fputc('~', stdout); + + STRV_FOREACH(i, l) { + if (first) + first = false; + else + fputc(' ', stdout); + + fputs(*i, stdout); + } + fputc('\n', stdout); + } + + return 0; + } + + break; + + case SD_BUS_TYPE_ARRAY: + + if (contents[1] == 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) + printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore)); + + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) { + const char *type, *path; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) + printf("%s=%s\n", type, path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) { + const char *type, *path; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) + printf("Listen%s=%s\n", type, path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) { + const char *base; + uint64_t value, next_elapse; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) { + char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX]; + + printf("%s={ value=%s ; next_elapse=%s }\n", + base, + format_timespan(timespan1, sizeof(timespan1), value, 0), + format_timespan(timespan2, sizeof(timespan2), next_elapse, 0)); + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) { + ExecStatusInfo info = {}; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = exec_status_info_deserialize(m, &info)) > 0) { + char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX]; + _cleanup_free_ char *tt; + + tt = strv_join(info.argv, " "); + + printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", + name, + 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)), + (unsigned) info. pid, + sigchld_code_to_string(info.code), + info.status, + info.code == CLD_EXITED ? "" : "/", + strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status))); + + free(info.path); + strv_free(info.argv); + zero(info); + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) { + const char *path, *rwm; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0) + printf("%s=%s %s\n", name, strna(path), strna(rwm)); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) { + const char *path; + uint64_t weight; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0) + printf("%s=%s %" PRIu64 "\n", name, strna(path), weight); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { + const char *path; + uint64_t bandwidth; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0) + printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + return 0; + } + + break; + } + + r = bus_print_property(name, m, arg_all); + if (r < 0) + return bus_log_parse_error(r); + + if (r == 0) { + r = sd_bus_message_skip(m, contents); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_all) + printf("%s=[unprintable]\n", name); + } + + return 0; +} + +static int show_one( + const char *verb, + sd_bus *bus, + const char *path, + bool show_properties, + bool *new_line, + bool *ellipsized) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + UnitStatusInfo info = {}; + ExecStatusInfo *p; + int r; + + assert(path); + assert(new_line); + + log_debug("Showing one %s", path); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "GetAll", + &error, + &reply, + "s", ""); + if (r < 0) { + log_error("Failed to get properties: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return bus_log_parse_error(r); + + if (*new_line) + printf("\n"); + + *new_line = true; + + while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *name, *contents; + + r = sd_bus_message_read(reply, "s", &name); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_peek_type(reply, NULL, &contents); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + return bus_log_parse_error(r); + + if (show_properties) + r = print_property(name, reply, contents); + else + r = status_property(name, reply, &info, contents); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = 0; + + if (!show_properties) { + if (streq(verb, "help")) + show_unit_help(&info); + else + print_status_info(&info, ellipsized); + } + + strv_free(info.documentation); + strv_free(info.dropin_paths); + strv_free(info.listen); + + if (!streq_ptr(info.active_state, "active") && + !streq_ptr(info.active_state, "reloading") && + streq(verb, "status")) { + /* According to LSB: "program not running" */ + /* 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 + */ + if (info.pid_file && access(info.pid_file, F_OK) == 0) + r = 1; + else + r = 3; + } + + while ((p = info.exec)) { + LIST_REMOVE(exec, info.exec, p); + exec_status_info_free(p); + } + + return r; +} + +static int get_unit_dbus_path_by_pid( + sd_bus *bus, + uint32_t pid, + char **unit) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + char *u; + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitByPID", + &error, + &reply, + "u", pid); + if (r < 0) { + log_error("Failed to get unit for PID %lu: %s", (unsigned long) pid, bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &u); + if (r < 0) + return bus_log_parse_error(r); + + u = strdup(u); + if (!u) + return log_oom(); + + *unit = u; + return 0; +} + +static int show_all( + const char* verb, + sd_bus *bus, + bool show_properties, + bool *new_line, + bool *ellipsized) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ UnitInfo *unit_infos = NULL; + const UnitInfo *u; + unsigned c; + int r; + + r = get_unit_list(bus, &reply, &unit_infos, NULL); + if (r < 0) + return r; + + pager_open_if_enabled(); + + c = (unsigned) r; + + qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info); + + for (u = unit_infos; u < unit_infos + c; u++) { + _cleanup_free_ char *p = NULL; + + p = unit_dbus_path_from_name(u->id); + if (!p) + return log_oom(); + + r = show_one(verb, bus, p, show_properties, new_line, ellipsized); + if (r != 0) + return r; + } + + return 0; +} + +static int cat(sd_bus *bus, char **args) { + _cleanup_free_ char *unit = NULL; + _cleanup_strv_free_ char **names = NULL; + char **name; + bool first = true; + int r = 0; + + assert(bus); + assert(args); + + r = expand_names(bus, args + 1, NULL, &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + + pager_open_if_enabled(); + + STRV_FOREACH(name, names) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **dropin_paths = NULL; + _cleanup_free_ char *fragment_path = NULL; + char **path; + + unit = unit_dbus_path_from_name(*name); + if (!unit) + return log_oom(); + + if (need_daemon_reload(bus, *name) > 0) + log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.", + *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user"); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "FragmentPath", + &error, + &fragment_path); + if (r < 0) { + log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r)); + continue; + } + + r = sd_bus_get_property_strv( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "DropInPaths", + &error, + &dropin_paths); + if (r < 0) { + log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r)); + continue; + } + + if (first) + first = false; + else + puts(""); + + if (!isempty(fragment_path)) { + printf("%s# %s%s\n", + ansi_highlight_blue(), + fragment_path, + ansi_highlight_off()); + fflush(stdout); + + r = sendfile_full(STDOUT_FILENO, fragment_path); + if (r < 0) { + log_warning("Failed to cat %s: %s", fragment_path, strerror(-r)); + continue; + } + } + + STRV_FOREACH(path, dropin_paths) { + printf("%s%s# %s%s\n", + isempty(fragment_path) && path == dropin_paths ? "" : "\n", + ansi_highlight_blue(), + *path, + ansi_highlight_off()); + fflush(stdout); + + r = sendfile_full(STDOUT_FILENO, *path); + if (r < 0) { + log_warning("Failed to cat %s: %s", *path, strerror(-r)); + continue; + } + } + } + + return r < 0 ? r : 0; +} + +static int show(sd_bus *bus, char **args) { + bool show_properties, show_status, new_line = false; + bool ellipsized = false; + int r, ret = 0; + + assert(bus); + assert(args); + + show_properties = streq(args[0], "show"); + show_status = streq(args[0], "status"); + + if (show_properties) + pager_open_if_enabled(); + + /* If no argument is specified inspect the manager itself */ + + if (show_properties && strv_length(args) <= 1) + return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); + + if (show_status && strv_length(args) <= 1) + ret = show_all(args[0], bus, false, &new_line, &ellipsized); + else { + _cleanup_free_ char **patterns = NULL; + char **name; + + STRV_FOREACH(name, args + 1) { + _cleanup_free_ char *unit = NULL; + uint32_t id; + + if (safe_atou32(*name, &id) < 0) { + if (strv_push(&patterns, *name) < 0) + return log_oom(); + + continue; + } else if (show_properties) { + /* Interpret as job id */ + if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) + return log_oom(); + + } else { + /* Interpret as PID */ + r = get_unit_dbus_path_by_pid(bus, id, &unit); + if (r < 0) { + ret = r; + continue; + } + } + + show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized); + } + + if (!strv_isempty(patterns)) { + _cleanup_strv_free_ char **names = NULL; + + r = expand_names(bus, patterns, NULL, &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + + STRV_FOREACH(name, names) { + _cleanup_free_ char *unit; + + unit = unit_dbus_path_from_name(*name); + if (!unit) + return log_oom(); + + show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized); + } + } + } + + if (ellipsized && !arg_quiet) + printf("Hint: Some lines were ellipsized, use -l to show in full.\n"); + + return ret; +} + +static int append_assignment(sd_bus_message *m, const char *assignment) { + const char *eq; + char *field; + int r; + + assert(m); + assert(assignment); + + eq = strchr(assignment, '='); + if (!eq) { + log_error("Not an assignment: %s", assignment); + return -EINVAL; + } + + field = strndupa(assignment, eq - assignment); + eq ++; + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + if (streq(field, "CPUAccounting") || + streq(field, "MemoryAccounting") || + streq(field, "BlockIOAccounting")) { + + r = parse_boolean(eq); + if (r < 0) { + log_error("Failed to parse boolean assignment %s.", assignment); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "b", r); + + } else if (streq(field, "MemoryLimit")) { + off_t bytes; + + r = parse_size(eq, 1024, &bytes); + if (r < 0) { + log_error("Failed to parse bytes specification %s", assignment); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes); + + } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) { + uint64_t u; + + r = safe_atou64(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + + } else if (streq(field, "DevicePolicy")) + r = sd_bus_message_append(m, "v", "s", eq); + + else if (streq(field, "DeviceAllow")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(ss)", 0); + else { + const char *path, *rwm; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + rwm = e+1; + } else { + path = eq; + rwm = ""; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); + } + + } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(st)", 0); + else { + const char *path, *bandwidth; + off_t bytes; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + bandwidth = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = parse_size(bandwidth, 1000, &bytes); + if (r < 0) { + log_error("Failed to parse byte value %s.", bandwidth); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes); + } + + } else if (streq(field, "BlockIODeviceWeight")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(st)", 0); + else { + const char *path, *weight; + uint64_t u; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + weight = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = safe_atou64(weight, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, weight); + return -EINVAL; + } + r = sd_bus_message_append(m, "v", "a(st)", path, u); + } + + } else { + log_error("Unknown assignment %s.", assignment); + return -EINVAL; + } + + if (r < 0) + return bus_log_create_error(r); + + return 0; +} + +static int set_property(sd_bus *bus, char **args) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *n = NULL; + char **i; + int r; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetUnitProperties"); + if (r < 0) + return bus_log_create_error(r); + + n = unit_name_mangle(args[1], MANGLE_NOGLOB); + if (!n) + return log_oom(); + + r = sd_bus_message_append(m, "sb", n, arg_runtime); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)"); + if (r < 0) + return bus_log_create_error(r); + + STRV_FOREACH(i, args + 2) { + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = append_assignment(m, *i); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) { + log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r)); + return r; + } + + return 0; +} + +static int snapshot(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_free_ char *n = NULL, *id = NULL; + const char *path; + int r; + + if (strv_length(args) > 1) + n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot"); + else + n = strdup(""); + if (!n) + return log_oom(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "CreateSnapshot", + &error, + &reply, + "sb", n, false); + if (r < 0) { + log_error("Failed to create snapshot: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "Id", + &error, + &id); + if (r < 0) { + log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r)); + return r; + } + + if (!arg_quiet) + puts(id); + + return 0; +} + +static int delete_snapshot(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **names = NULL; + char **name; + int r, q; + + assert(args); + + r = expand_names(bus, args + 1, ".snapshot", &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + + STRV_FOREACH(name, names) { + q = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "RemoveSnapshot", + &error, + NULL, + "s", *name); + if (q < 0) { + log_error("Failed to remove snapshot %s: %s", + *name, bus_error_message(&error, r)); + if (r == 0) + r = q; + } + } + + return r; +} + +static int daemon_reload(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method; + int r; + + if (arg_action == ACTION_RELOAD) + method = "Reload"; + else if (arg_action == ACTION_REEXEC) + method = "Reexecute"; + else { + assert(arg_action == ACTION_SYSTEMCTL); + + method = + streq(args[0], "clear-jobs") || + streq(args[0], "cancel") ? "ClearJobs" : + streq(args[0], "daemon-reexec") ? "Reexecute" : + streq(args[0], "reset-failed") ? "ResetFailed" : + streq(args[0], "halt") ? "Halt" : + streq(args[0], "poweroff") ? "PowerOff" : + streq(args[0], "reboot") ? "Reboot" : + streq(args[0], "kexec") ? "KExec" : + streq(args[0], "exit") ? "Exit" : + /* "daemon-reload" */ "Reload"; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method, + &error, + NULL, + NULL); + + if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) + /* There's always a fallback possible for + * legacy actions. */ + r = -EADDRNOTAVAIL; + else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute")) + /* On reexecution, we expect a disconnect, not a + * reply */ + r = 0; + else if (r < 0) + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + + return r < 0 ? r : 0; +} + +static int reset_failed(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **names = NULL; + char **name; + int r, q; + + if (strv_length(args) <= 1) + return daemon_reload(bus, args); + + r = expand_names(bus, args + 1, NULL, &names); + if (r < 0) + log_error("Failed to expand names: %s", strerror(-r)); + + STRV_FOREACH(name, names) { + q = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ResetFailedUnit", + &error, + NULL, + "s", *name); + if (q < 0) { + log_error("Failed to reset failed state of unit %s: %s", + *name, bus_error_message(&error, r)); + if (r == 0) + r = q; + } + } + + return r; +} + +static int show_environment(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *text; + int r; + + pager_open_if_enabled(); + + r = sd_bus_get_property( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Environment", + &error, + &reply, + "as"); + if (r < 0) { + log_error("Failed to get environment: %s", bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) + puts(text); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + return 0; +} + +static int switch_root(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *init = NULL; + const char *root; + unsigned l; + int r; + + l = strv_length(args); + if (l < 2 || l > 3) { + log_error("Wrong number of arguments."); + return -EINVAL; + } + + root = args[1]; + + if (l >= 3) + init = strdup(args[2]); + else { + parse_env_file("/proc/cmdline", WHITESPACE, + "init", &init, + NULL); + + if (!init) + init = strdup(""); + } + + if (!init) + return log_oom(); + + log_debug("switching root - root: %s; init: %s", root, init); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SwitchRoot", + &error, + NULL, + "ss", root, init); + if (r < 0) { + log_error("Failed to switch root: %s", bus_error_message(&error, r)); + return r; + } + + return 0; +} + +static int set_environment(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + const char *method; + int r; + + assert(bus); + assert(args); + + method = streq(args[0], "set-environment") + ? "SetEnvironment" + : "UnsetEnvironment"; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, args + 1); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) { + log_error("Failed to set environment: %s", bus_error_message(&error, r)); + return r; + } + + return 0; +} + +static int import_environment(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r; + + assert(bus); + assert(args); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetEnvironment"); + if (r < 0) + return bus_log_create_error(r); + + if (strv_isempty(args + 1)) + r = sd_bus_message_append_strv(m, environ); + else { + char **a, **b; + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + STRV_FOREACH(a, args + 1) { + + if (!env_name_is_valid(*a)) { + log_error("Not a valid environment variable name: %s", *a); + return -EINVAL; + } + + STRV_FOREACH(b, environ) { + const char *eq; + + eq = startswith(*b, *a); + if (eq && *eq == '=') { + + r = sd_bus_message_append(m, "s", *b); + if (r < 0) + return bus_log_create_error(r); + + break; + } + } + } + + r = sd_bus_message_close_container(m); + } + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, NULL); + if (r < 0) { + log_error("Failed to import environment: %s", bus_error_message(&error, r)); + return r; + } + + return 0; +} + +static int enable_sysv_units(const char *verb, char **args) { + int r = 0; + +#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG) + unsigned f = 1, t = 1; + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + + if (arg_scope != UNIT_FILE_SYSTEM) + return 0; + + if (!streq(verb, "enable") && + !streq(verb, "disable") && + !streq(verb, "is-enabled")) + return 0; + + /* Processes all SysV units, and reshuffles the array so that + * afterwards only the native units remain */ + + r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL); + if (r < 0) + return r; + + r = 0; + for (f = 0; args[f]; f++) { + const char *name; + _cleanup_free_ char *p = NULL, *q = NULL; + bool found_native = false, found_sysv; + unsigned c = 1; + const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL }; + char **k, *l; + int j; + pid_t pid; + siginfo_t status; + + name = args[f]; + + if (!endswith(name, ".service")) + continue; + + if (path_is_absolute(name)) + continue; + + STRV_FOREACH(k, paths.unit_path) { + if (!isempty(arg_root)) + asprintf(&p, "%s/%s/%s", arg_root, *k, name); + else + asprintf(&p, "%s/%s", *k, name); + + if (!p) { + r = log_oom(); + goto finish; + } + + found_native = access(p, F_OK) >= 0; + free(p); + p = NULL; + + if (found_native) + break; + } + + if (found_native) + continue; + + if (!isempty(arg_root)) + asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name); + else + asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name); + if (!p) { + r = log_oom(); + goto finish; + } + + p[strlen(p) - sizeof(".service") + 1] = 0; + found_sysv = access(p, F_OK) >= 0; + + if (!found_sysv) + continue; + + /* Mark this entry, so that we don't try enabling it as native unit */ + args[f] = (char*) ""; + + log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name); + + if (!isempty(arg_root)) + argv[c++] = q = strappend("--root=", arg_root); + + argv[c++] = basename(p); + argv[c++] = + streq(verb, "enable") ? "on" : + streq(verb, "disable") ? "off" : "--level=5"; + argv[c] = NULL; + + l = strv_join((char**)argv, " "); + if (!l) { + r = log_oom(); + goto finish; + } + + log_info("Executing %s", l); + free(l); + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + r = -errno; + goto finish; + } else if (pid == 0) { + /* Child */ + + execv(argv[0], (char**) argv); + _exit(EXIT_FAILURE); + } + + j = wait_for_terminate(pid, &status); + if (j < 0) { + log_error("Failed to wait for child: %s", strerror(-r)); + r = j; + goto finish; + } + + if (status.si_code == CLD_EXITED) { + if (streq(verb, "is-enabled")) { + if (status.si_status == 0) { + if (!arg_quiet) + puts("enabled"); + r = 1; + } else { + if (!arg_quiet) + puts("disabled"); + } + + } else if (status.si_status != 0) { + r = -EINVAL; + goto finish; + } + } else { + r = -EPROTO; + goto finish; + } + } + +finish: + /* Drop all SysV units */ + for (f = 0, t = 0; args[f]; f++) { + + if (isempty(args[f])) + continue; + + args[t++] = args[f]; + } + + args[t] = NULL; + +#endif + return r; +} + +static int mangle_names(char **original_names, char ***mangled_names) { + char **i, **l, **name; + + l = new(char*, strv_length(original_names) + 1); + if (!l) + return log_oom(); + + i = l; + STRV_FOREACH(name, original_names) { + + /* When enabling units qualified path names are OK, + * too, hence allow them explicitly. */ + + if (is_path(*name)) + *i = strdup(*name); + else + *i = unit_name_mangle(*name, MANGLE_NOGLOB); + + if (!*i) { + strv_free(l); + return log_oom(); + } + + i++; + } + + *i = NULL; + *mangled_names = l; + + return 0; +} + +static int enable_unit(sd_bus *bus, char **args) { + _cleanup_strv_free_ char **names = NULL; + const char *verb = args[0]; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int carries_install_info = -1; + int r; + + if (!args[1]) + return 0; + + r = mangle_names(args+1, &names); + if (r < 0) + return r; + + r = enable_sysv_units(verb, names); + if (r < 0) + return r; + + /* If the operation was fully executed by the SysV compat, + * let's finish early */ + if (strv_isempty(names)) + return 0; + + if (!bus || avoid_bus()) { + if (streq(verb, "enable")) { + r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + carries_install_info = r; + } else if (streq(verb, "disable")) + r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); + else if (streq(verb, "reenable")) { + r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + carries_install_info = r; + } else if (streq(verb, "link")) + r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "preset")) { + r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + carries_install_info = r; + } else if (streq(verb, "mask")) + r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "unmask")) + r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); + else + assert_not_reached("Unknown verb"); + + if (r < 0) { + log_error("Operation failed: %s", strerror(-r)); + goto finish; + } + + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); + + r = 0; + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int expect_carries_install_info = false; + bool send_force = true; + const char *method; + + if (streq(verb, "enable")) { + method = "EnableUnitFiles"; + expect_carries_install_info = true; + } else if (streq(verb, "disable")) { + method = "DisableUnitFiles"; + send_force = false; + } else if (streq(verb, "reenable")) { + method = "ReenableUnitFiles"; + expect_carries_install_info = true; + } else if (streq(verb, "link")) + method = "LinkUnitFiles"; + else if (streq(verb, "preset")) { + method = "PresetUnitFiles"; + expect_carries_install_info = true; + } else if (streq(verb, "mask")) + method = "MaskUnitFiles"; + else if (streq(verb, "unmask")) { + method = "UnmaskUnitFiles"; + send_force = false; + } else + assert_not_reached("Unknown verb"); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, names); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "b", arg_runtime); + if (r < 0) + return bus_log_create_error(r); + + if (send_force) { + r = sd_bus_message_append(m, "b", arg_force); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + return r; + } + + if (expect_carries_install_info) { + r = sd_bus_message_read(reply, "b", &carries_install_info); + if (r < 0) + return bus_log_parse_error(r); + } + + r = deserialize_and_dump_unit_file_changes(reply); + if (r < 0) + return r; + + /* Try to reload if enabeld */ + if (!arg_no_reload) + r = daemon_reload(bus, args); + else + r = 0; + } + + if (carries_install_info == 0) + log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" + "using systemctl.\n" + "Possible reasons for having this kind of units are:\n" + "1) A unit may be statically enabled by being symlinked from another unit's\n" + " .wants/ or .requires/ directory.\n" + "2) A unit's purpose may be to act as a helper for some other unit which has\n" + " a requirement dependency on it.\n" + "3) A unit may be started when needed via activation (socket, path, timer,\n" + " D-Bus, udev, scripted systemctl call, ...).\n"); + +finish: + unit_file_changes_free(changes, n_changes); + + return r; +} + +static int unit_is_enabled(sd_bus *bus, char **args) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **names = NULL; + bool enabled; + char **name; + int r; + + r = mangle_names(args+1, &names); + if (r < 0) + return r; + + r = enable_sysv_units(args[0], names); + if (r < 0) + return r; + + enabled = r > 0; + + if (!bus || avoid_bus()) { + + STRV_FOREACH(name, names) { + UnitFileState state; + + state = unit_file_get_state(arg_scope, arg_root, *name); + if (state < 0) { + log_error("Failed to get unit file state for %s: %s", *name, strerror(-state)); + return state; + } + + if (state == UNIT_FILE_ENABLED || + state == UNIT_FILE_ENABLED_RUNTIME || + state == UNIT_FILE_STATIC) + enabled = true; + + if (!arg_quiet) + puts(unit_file_state_to_string(state)); + } + + } else { + STRV_FOREACH(name, names) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + const char *s; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitFileState", + &error, + &reply, + "s", *name); + if (r < 0) { + log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r)); + return r; + } + + r = sd_bus_message_read(reply, "s", &s); + if (r < 0) + return bus_log_parse_error(r); + + if (streq(s, "enabled") || + streq(s, "enabled-runtime") || + streq(s, "static")) + enabled = true; + + if (!arg_quiet) + puts(s); + } + } + + return !enabled; +} + +static int systemctl_help(void) { + + pager_open_if_enabled(); + + printf("%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" + " --system Connect to system manager\n" + " --user Connect to user service manager\n" + " -H --host=[USER@]HOST\n" + " Operate on remote host\n" + " -M --machine=CONTAINER\n" + " Operate on local container\n" + " -t --type=TYPE List only units of a particular type\n" + " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n" + " -p --property=NAME Show only properties by this name\n" + " -a --all Show all loaded units/properties, including dead/empty\n" + " ones. To list all units installed on the system, use\n" + " the 'list-unit-files' command instead.\n" + " -l --full Don't ellipsize unit names on output\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" + " --show-types When showing sockets, explicitly show their type\n" + " -i --ignore-inhibitors\n" + " When shutting down or sleeping, ignore inhibitors\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n" + " -q --quiet Suppress output\n" + " --no-block Do not wait until operation finished\n" + " --no-wall Don't send wall message before halt/power-off/reboot\n" + " --no-reload When enabling/disabling unit files, don't reload daemon\n" + " configuration\n" + " --no-legend Do not print a legend (column headers and hints)\n" + " --no-pager Do not pipe output into a pager\n" + " --no-ask-password\n" + " Do not ask for system passwords\n" + " --global Enable/disable unit files globally\n" + " --runtime Enable unit files only temporarily until next reboot\n" + " -f --force When enabling unit files, override existing symlinks\n" + " When shutting down, execute action immediately\n" + " --root=PATH Enable unit files in the specified root directory\n" + " -n --lines=INTEGER Number of journal entries to show\n" + " -o --output=STRING Change journal output mode (short, short-monotonic,\n" + " verbose, export, json, json-pretty, json-sse, cat)\n" + " --plain Print unit dependencies as a list instead of a tree\n\n" + "Unit Commands:\n" + " list-units [PATTERN...] List loaded units\n" + " list-sockets [PATTERN...] List loaded sockets ordered by address\n" + " list-timers [PATTERN...] List loaded timers ordered by next elapse\n" + " start NAME... Start (activate) one or more units\n" + " stop NAME... Stop (deactivate) one or more units\n" + " reload NAME... Reload one or more units\n" + " restart NAME... Start or restart one or more units\n" + " try-restart NAME... Restart one or more units if active\n" + " reload-or-restart NAME... Reload one or more units if possible,\n" + " otherwise start or restart\n" + " reload-or-try-restart NAME... Reload one or more units if possible,\n" + " otherwise restart if active\n" + " isolate NAME Start one unit and stop all others\n" + " kill NAME... Send signal to processes of a unit\n" + " is-active NAME... Check whether units are active\n" + " is-failed NAME... Check whether units are failed\n" + " status [NAME...|PID...] Show runtime status of one or more units\n" + " show [NAME...|JOB...] Show properties of one or more\n" + " units/jobs or the manager\n" + " cat NAME... Show files and drop-ins of one or more units\n" + " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n" + " help NAME...|PID... Show manual for one or more units\n" + " reset-failed [NAME...] Reset failed state for all, one, or more\n" + " units\n" + " list-dependencies [NAME] 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" + " list-unit-files [PATTERN...] List installed unit files\n" + " enable NAME... Enable one or more unit files\n" + " disable NAME... Disable one or more unit files\n" + " reenable NAME... Reenable one or more unit files\n" + " preset NAME... Enable/disable one or more unit files\n" + " based on preset configuration\n" + " is-enabled NAME... Check whether unit files are enabled\n\n" + " mask NAME... Mask one or more units\n" + " unmask NAME... Unmask one or more units\n" + " link PATH... Link one or more units files into\n" + " the search path\n" + " get-default Get the name of the default target\n" + " set-default NAME Set the default target\n\n" + "Job Commands:\n" + " list-jobs [PATTERN...] List jobs\n" + " cancel [JOB...] Cancel all, one, or more jobs\n\n" + "Snapshot Commands:\n" + " snapshot [NAME] Create a snapshot\n" + " delete NAME... Remove one or more snapshots\n\n" + "Environment Commands:\n" + " show-environment Dump environment\n" + " set-environment NAME=VALUE... Set one or more environment variables\n" + " unset-environment NAME... Unset one or more environment variables\n" + " import-environment NAME... Import all, one or more environment variables\n\n" + "Manager Lifecycle Commands:\n" + " daemon-reload Reload systemd manager configuration\n" + " daemon-reexec Reexecute systemd manager\n\n" + "System Commands:\n" + " default Enter system default mode\n" + " rescue Enter system rescue mode\n" + " emergency Enter system emergency mode\n" + " halt Shut down and halt the system\n" + " poweroff Shut down and power-off the system\n" + " reboot [ARG] Shut down and reboot the system\n" + " kexec Shut down and reboot the system with kexec\n" + " exit Request user instance exit\n" + " switch-root ROOT [INIT] Change to a different root file system\n" + " suspend Suspend the system\n" + " hibernate Hibernate the system\n" + " hybrid-sleep Hibernate and suspend the system\n", + program_invocation_short_name); + + return 0; +} + +static int halt_help(void) { + + printf("%s [OPTIONS...]%s\n\n" + "%s the system.\n\n" + " --help Show this help\n" + " --halt Halt the machine\n" + " -p --poweroff Switch off the machine\n" + " --reboot Reboot the machine\n" + " -f --force Force immediate halt/power-off/reboot\n" + " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n" + " -d --no-wtmp Don't write wtmp record\n" + " --no-wall Don't send wall message before halt/power-off/reboot\n", + program_invocation_short_name, + arg_action == ACTION_REBOOT ? " [ARG]" : "", + arg_action == ACTION_REBOOT ? "Reboot" : + arg_action == ACTION_POWEROFF ? "Power off" : + "Halt"); + + return 0; +} + +static int shutdown_help(void) { + + printf("%s [OPTIONS...] [TIME] [WALL...]\n\n" + "Shut down the system.\n\n" + " --help Show this help\n" + " -H --halt Halt the machine\n" + " -P --poweroff Power-off the machine\n" + " -r --reboot Reboot the machine\n" + " -h Equivalent to --poweroff, overridden by --halt\n" + " -k Don't halt/power-off/reboot, just send warnings\n" + " --no-wall Don't send wall message before halt/power-off/reboot\n" + " -c Cancel a pending shutdown\n", + program_invocation_short_name); + + return 0; +} + +static int telinit_help(void) { + + printf("%s [OPTIONS...] {COMMAND}\n\n" + "Send control commands to the init daemon.\n\n" + " --help Show this help\n" + " --no-wall Don't send wall message before halt/power-off/reboot\n\n" + "Commands:\n" + " 0 Power-off the machine\n" + " 6 Reboot the machine\n" + " 2, 3, 4, 5 Start runlevelX.target unit\n" + " 1, s, S Enter rescue mode\n" + " q, Q Reload init daemon configuration\n" + " u, U Reexecute init daemon\n", + program_invocation_short_name); + + return 0; +} + +static int runlevel_help(void) { + + printf("%s [OPTIONS...]\n\n" + "Prints the previous and current runlevel of the init system.\n\n" + " --help Show this help\n", + program_invocation_short_name); + + return 0; +} + +static int help_types(void) { + int i; + const char *t; + + puts("Available unit types:"); + for (i = 0; i < _UNIT_TYPE_MAX; i++) { + t = unit_type_to_string(i); + if (t) + puts(t); + } + + return 0; +} + +static int systemctl_parse_argv(int argc, char *argv[]) { + + enum { + ARG_FAIL = 0x100, + ARG_REVERSE, + ARG_AFTER, + ARG_BEFORE, + ARG_SHOW_TYPES, + ARG_IRREVERSIBLE, + ARG_IGNORE_DEPENDENCIES, + ARG_VERSION, + ARG_USER, + ARG_SYSTEM, + ARG_GLOBAL, + ARG_NO_BLOCK, + ARG_NO_LEGEND, + ARG_NO_PAGER, + ARG_NO_WALL, + ARG_ROOT, + ARG_NO_RELOAD, + ARG_KILL_WHO, + ARG_NO_ASK_PASSWORD, + ARG_FAILED, + ARG_RUNTIME, + ARG_FORCE, + ARG_PLAIN, + ARG_STATE, + ARG_JOB_MODE + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "property", required_argument, NULL, 'p' }, + { "all", no_argument, NULL, 'a' }, + { "reverse", no_argument, NULL, ARG_REVERSE }, + { "after", no_argument, NULL, ARG_AFTER }, + { "before", no_argument, NULL, ARG_BEFORE }, + { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, + { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */ + { "full", no_argument, NULL, 'l' }, + { "job-mode", required_argument, NULL, ARG_JOB_MODE }, + { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */ + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */ + { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */ + { "ignore-inhibitors", no_argument, NULL, 'i' }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "global", no_argument, NULL, ARG_GLOBAL }, + { "no-block", no_argument, NULL, ARG_NO_BLOCK }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + { "quiet", no_argument, NULL, 'q' }, + { "root", required_argument, NULL, ARG_ROOT }, + { "force", no_argument, NULL, ARG_FORCE }, + { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, + { "kill-who", required_argument, NULL, ARG_KILL_WHO }, + { "signal", required_argument, NULL, 's' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "runtime", no_argument, NULL, ARG_RUNTIME }, + { "lines", required_argument, NULL, 'n' }, + { "output", required_argument, NULL, 'o' }, + { "plain", no_argument, NULL, ARG_PLAIN }, + { "state", required_argument, NULL, ARG_STATE }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:i", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return systemctl_help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 't': { + char *word, *state; + size_t size; + + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + _cleanup_free_ char *type; + + type = strndup(word, size); + if (!type) + return -ENOMEM; + + if (streq(type, "help")) { + help_types(); + return 0; + } + + if (unit_type_from_string(type) >= 0) { + if (strv_push(&arg_types, type)) + return log_oom(); + type = NULL; + continue; + } + + /* It's much nicer to use --state= for + * load states, but let's support this + * in --types= too for compatibility + * with old versions */ + if (unit_load_state_from_string(optarg) >= 0) { + if (strv_push(&arg_states, type) < 0) + return log_oom(); + type = NULL; + continue; + } + + log_error("Unknown unit type or load state '%s'.", type); + log_info("Use -t help to see a list of allowed values."); + return -EINVAL; + } + + break; + } + + 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 { + char *word, *state; + size_t size; + + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char *prop; + + prop = strndup(word, size); + if (!prop) + return log_oom(); + + if (strv_push(&arg_properties, prop) < 0) { + free(prop); + return log_oom(); + } + } + } + + /* If the user asked for a particular + * property, show it to him, even if it is + * empty. */ + arg_all = true; + + break; + } + + case 'a': + arg_all = true; + break; + + case ARG_REVERSE: + arg_dependency = DEPENDENCY_REVERSE; + break; + + case ARG_AFTER: + arg_dependency = DEPENDENCY_AFTER; + break; + + case ARG_BEFORE: + arg_dependency = DEPENDENCY_BEFORE; + break; + + case ARG_SHOW_TYPES: + arg_show_types = true; + break; + + case ARG_JOB_MODE: + arg_job_mode = optarg; + break; + + case ARG_FAIL: + arg_job_mode = "fail"; + break; + + case ARG_IRREVERSIBLE: + arg_job_mode = "replace-irreversibly"; + break; + + case ARG_IGNORE_DEPENDENCIES: + arg_job_mode = "ignore-dependencies"; + break; + + case ARG_USER: + arg_scope = UNIT_FILE_USER; + break; + + case ARG_SYSTEM: + arg_scope = UNIT_FILE_SYSTEM; + break; + + case ARG_GLOBAL: + arg_scope = UNIT_FILE_GLOBAL; + break; + + case ARG_NO_BLOCK: + arg_no_block = true; + break; + + case ARG_NO_LEGEND: + arg_no_legend = true; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case ARG_NO_WALL: + arg_no_wall = true; + break; + + case ARG_ROOT: + arg_root = optarg; + break; + + case 'l': + arg_full = true; + break; + + case ARG_FAILED: + if (strv_extend(&arg_states, "failed") < 0) + return log_oom(); + + break; + + case 'q': + arg_quiet = true; + break; + + case ARG_FORCE: + arg_force ++; + break; + + case 'f': + arg_force ++; + break; + + case ARG_NO_RELOAD: + arg_no_reload = true; + break; + + case ARG_KILL_WHO: + arg_kill_who = optarg; + break; + + case 's': + if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) { + log_error("Failed to parse signal string %s.", optarg); + return -EINVAL; + } + break; + + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case ARG_RUNTIME: + arg_runtime = true; + break; + + case 'n': + if (safe_atou(optarg, &arg_lines) < 0) { + log_error("Failed to parse lines '%s'", optarg); + return -EINVAL; + } + break; + + case 'o': + arg_output = output_mode_from_string(optarg); + if (arg_output < 0) { + log_error("Unknown output '%s'.", optarg); + return -EINVAL; + } + break; + + case 'i': + arg_ignore_inhibitors = true; + break; + + case ARG_PLAIN: + arg_plain = true; + break; + + case ARG_STATE: { + char *word, *state; + size_t size; + + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char *s; + + s = strndup(word, size); + if (!s) + return log_oom(); + + if (strv_push(&arg_states, s) < 0) { + free(s); + return log_oom(); + } + } + break; + } + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) { + log_error("Cannot access user instance remotely."); + return -EINVAL; + } + + return 1; +} + +static int halt_parse_argv(int argc, char *argv[]) { + + enum { + ARG_HELP = 0x100, + ARG_HALT, + ARG_REBOOT, + ARG_NO_WALL + }; + + static const struct option options[] = { + { "help", no_argument, NULL, ARG_HELP }, + { "halt", no_argument, NULL, ARG_HALT }, + { "poweroff", no_argument, NULL, 'p' }, + { "reboot", no_argument, NULL, ARG_REBOOT }, + { "force", no_argument, NULL, 'f' }, + { "wtmp-only", no_argument, NULL, 'w' }, + { "no-wtmp", no_argument, NULL, 'd' }, + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + {} + }; + + int c, r, runlevel; + + assert(argc >= 0); + assert(argv); + + if (utmp_get_runlevel(&runlevel, NULL) >= 0) + if (runlevel == '0' || runlevel == '6') + arg_force = 2; + + while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) { + switch (c) { + + case ARG_HELP: + return halt_help(); + + case ARG_HALT: + arg_action = ACTION_HALT; + break; + + case 'p': + if (arg_action != ACTION_REBOOT) + arg_action = ACTION_POWEROFF; + break; + + case ARG_REBOOT: + arg_action = ACTION_REBOOT; + break; + + case 'f': + arg_force = 2; + break; + + case 'w': + arg_dry = true; + break; + + case 'd': + arg_no_wtmp = true; + break; + + case ARG_NO_WALL: + arg_no_wall = true; + break; + + case 'i': + case 'h': + case 'n': + /* Compatibility nops */ + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (arg_action == ACTION_REBOOT && argc == optind + 1) { + r = write_string_file(REBOOT_PARAM_FILE, argv[optind]); + if (r < 0) { + log_error("Failed to write reboot param to " + REBOOT_PARAM_FILE": %s", strerror(-r)); + return r; + } + } else if (optind < argc) { + log_error("Too many arguments."); + return -EINVAL; + } + +#ifdef CONFIG_TIZEN_WIP + /* FIXME */ + /* Now, in Tizen, some of services are hardly not + * terminated. At last, time-out occurred. It can make serious + * problem in shutdown process. Until we solve this problem + * reboot is performed forcedly. */ + if (arg_action == ACTION_REBOOT || + arg_action == ACTION_POWEROFF) + arg_force = 2; +#endif + + return 1; +} + +static int parse_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; + + assert_se(s = mktime(&tm)); + + *_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, + ARG_NO_WALL + }; + + static const struct option options[] = { + { "help", no_argument, NULL, ARG_HELP }, + { "halt", no_argument, NULL, 'H' }, + { "poweroff", no_argument, NULL, 'P' }, + { "reboot", no_argument, NULL, 'r' }, + { "kexec", no_argument, NULL, 'K' }, /* not documented extension */ + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) { + switch (c) { + + case ARG_HELP: + return shutdown_help(); + + case 'H': + arg_action = ACTION_HALT; + break; + + case 'P': + arg_action = ACTION_POWEROFF; + break; + + case 'r': + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; + break; + + case 'K': + arg_action = ACTION_KEXEC; + break; + + case 'h': + if (arg_action != ACTION_HALT) + arg_action = ACTION_POWEROFF; + break; + + case 'k': + arg_dry = true; + break; + + case ARG_NO_WALL: + arg_no_wall = true; + break; + + case 't': + case 'a': + /* Compatibility nops */ + break; + + case 'c': + arg_action = ACTION_CANCEL_SHUTDOWN; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) { + r = parse_time_spec(argv[optind], &arg_when); + if (r < 0) { + log_error("Failed to parse time specification: %s", argv[optind]); + return r; + } + } else + arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE; + + if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN) + /* No time argument for shutdown cancel */ + arg_wall = argv + optind; + else if (argc > optind + 1) + /* We skip the time argument */ + arg_wall = argv + optind + 1; + + optind = argc; + + return 1; +} + +static int telinit_parse_argv(int argc, char *argv[]) { + + enum { + ARG_HELP = 0x100, + ARG_NO_WALL + }; + + static const struct option options[] = { + { "help", no_argument, NULL, ARG_HELP }, + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + {} + }; + + static const struct { + char from; + enum action to; + } table[] = { + { '0', ACTION_POWEROFF }, + { '6', ACTION_REBOOT }, + { '1', ACTION_RESCUE }, + { '2', ACTION_RUNLEVEL2 }, + { '3', ACTION_RUNLEVEL3 }, + { '4', ACTION_RUNLEVEL4 }, + { '5', ACTION_RUNLEVEL5 }, + { 's', ACTION_RESCUE }, + { 'S', ACTION_RESCUE }, + { 'q', ACTION_RELOAD }, + { 'Q', ACTION_RELOAD }, + { 'u', ACTION_REEXEC }, + { 'U', ACTION_REEXEC } + }; + + unsigned i; + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) { + switch (c) { + + case ARG_HELP: + return telinit_help(); + + case ARG_NO_WALL: + arg_no_wall = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind >= argc) { + telinit_help(); + return -EINVAL; + } + + if (optind + 1 < argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + if (strlen(argv[optind]) != 1) { + log_error("Expected single character argument."); + return -EINVAL; + } + + for (i = 0; i < ELEMENTSOF(table); i++) + if (table[i].from == argv[optind][0]) + break; + + if (i >= ELEMENTSOF(table)) { + log_error("Unknown command '%s'.", argv[optind]); + return -EINVAL; + } + + arg_action = table[i].to; + + optind ++; + + return 1; +} + +static int runlevel_parse_argv(int argc, char *argv[]) { + + enum { + ARG_HELP = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, ARG_HELP }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) { + switch (c) { + + case ARG_HELP: + return runlevel_help(); + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind < argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + return 1; +} + +static int parse_argv(int argc, char *argv[]) { + assert(argc >= 0); + assert(argv); + + if (program_invocation_short_name) { + + if (strstr(program_invocation_short_name, "halt")) { + arg_action = ACTION_HALT; + return halt_parse_argv(argc, argv); + } else if (strstr(program_invocation_short_name, "poweroff")) { + arg_action = ACTION_POWEROFF; + return halt_parse_argv(argc, argv); + } else if (strstr(program_invocation_short_name, "reboot")) { + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; + return halt_parse_argv(argc, argv); + } else if (strstr(program_invocation_short_name, "shutdown")) { + arg_action = ACTION_POWEROFF; + return shutdown_parse_argv(argc, argv); + } else if (strstr(program_invocation_short_name, "init")) { + + if (sd_booted() > 0) { + arg_action = _ACTION_INVALID; + return telinit_parse_argv(argc, argv); + } else { + /* Hmm, so some other init system is + * running, we need to forward this + * request to it. For now we simply + * guess that it is Upstart. */ + + execv(TELINIT, argv); + + log_error("Couldn't find an alternative telinit implementation to spawn."); + return -EIO; + } + + } else if (strstr(program_invocation_short_name, "runlevel")) { + arg_action = ACTION_RUNLEVEL; + return runlevel_parse_argv(argc, argv); + } + } + + arg_action = ACTION_SYSTEMCTL; + return systemctl_parse_argv(argc, argv); +} + +_pure_ static int action_to_runlevel(void) { + + static const char table[_ACTION_MAX] = { + [ACTION_HALT] = '0', + [ACTION_POWEROFF] = '0', + [ACTION_REBOOT] = '6', + [ACTION_RUNLEVEL2] = '2', + [ACTION_RUNLEVEL3] = '3', + [ACTION_RUNLEVEL4] = '4', + [ACTION_RUNLEVEL5] = '5', + [ACTION_RESCUE] = '1' + }; + + assert(arg_action < _ACTION_MAX); + + return table[arg_action]; +} + +static int talk_initctl(void) { + + struct init_request request = { + .magic = INIT_MAGIC, + .sleeptime = 0, + .cmd = INIT_CMD_RUNLVL + }; + + _cleanup_close_ int fd = -1; + char rl; + int r; + + rl = action_to_runlevel(); + if (!rl) + return 0; + + request.runlevel = rl; + + fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + if (errno == ENOENT) + return 0; + + log_error("Failed to open "INIT_FIFO": %m"); + return -errno; + } + + errno = 0; + r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); + if (r) { + log_error("Failed to write to "INIT_FIFO": %m"); + return errno > 0 ? -errno : -EIO; + } + + return 1; +} + +static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args); + const enum { + NOBUS = 1, + FORCE, + } bus; + } verbs[] = { + { "list-units", MORE, 0, list_units }, + { "list-unit-files", MORE, 1, list_unit_files, NOBUS }, + { "list-sockets", MORE, 1, list_sockets }, + { "list-timers", MORE, 1, list_timers }, + { "list-jobs", MORE, 1, list_jobs }, + { "clear-jobs", EQUAL, 1, daemon_reload }, + { "cancel", MORE, 2, cancel_job }, + { "start", MORE, 2, start_unit }, + { "stop", MORE, 2, start_unit }, + { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ + { "reload", MORE, 2, start_unit }, + { "restart", MORE, 2, start_unit }, + { "try-restart", MORE, 2, start_unit }, + { "reload-or-restart", MORE, 2, start_unit }, + { "reload-or-try-restart", MORE, 2, start_unit }, + { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */ + { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ + { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */ + { "isolate", EQUAL, 2, start_unit }, + { "kill", MORE, 2, kill_unit }, + { "is-active", MORE, 2, check_unit_active }, + { "check", MORE, 2, check_unit_active }, + { "is-failed", MORE, 2, check_unit_failed }, + { "show", MORE, 1, show }, + { "cat", MORE, 2, cat }, + { "status", MORE, 1, show }, + { "help", MORE, 2, show }, + { "snapshot", LESS, 2, snapshot }, + { "delete", MORE, 2, delete_snapshot }, + { "daemon-reload", EQUAL, 1, daemon_reload }, + { "daemon-reexec", EQUAL, 1, daemon_reload }, + { "show-environment", EQUAL, 1, show_environment }, + { "set-environment", MORE, 2, set_environment }, + { "unset-environment", MORE, 2, set_environment }, + { "import-environment", MORE, 1, import_environment}, + { "halt", EQUAL, 1, start_special, FORCE }, + { "poweroff", EQUAL, 1, start_special, FORCE }, + { "reboot", EQUAL, 1, start_special, FORCE }, + { "kexec", EQUAL, 1, start_special }, + { "suspend", EQUAL, 1, start_special }, + { "hibernate", EQUAL, 1, start_special }, + { "hybrid-sleep", EQUAL, 1, start_special }, + { "default", EQUAL, 1, start_special }, + { "rescue", EQUAL, 1, start_special }, + { "emergency", EQUAL, 1, start_special }, + { "exit", EQUAL, 1, start_special }, + { "reset-failed", MORE, 1, reset_failed }, + { "enable", MORE, 2, enable_unit, NOBUS }, + { "disable", MORE, 2, enable_unit, NOBUS }, + { "is-enabled", MORE, 2, unit_is_enabled, NOBUS }, + { "reenable", MORE, 2, enable_unit, NOBUS }, + { "preset", MORE, 2, enable_unit, NOBUS }, + { "mask", MORE, 2, enable_unit, NOBUS }, + { "unmask", MORE, 2, enable_unit, NOBUS }, + { "link", MORE, 2, enable_unit, NOBUS }, + { "switch-root", MORE, 2, switch_root }, + { "list-dependencies", LESS, 2, list_dependencies }, + { "set-default", EQUAL, 2, set_default, NOBUS }, + { "get-default", EQUAL, 1, get_default, NOBUS }, + { "set-property", MORE, 3, set_property }, + {} + }, *verb = verbs; + + int left; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + /* Special rule: no arguments (left == 0) means "list-units" */ + if (left > 0) { + if (streq(argv[optind], "help") && !argv[optind+1]) { + log_error("This command expects one or more " + "unit names. Did you mean --help?"); + return -EINVAL; + } + + for (; verb->verb; verb++) + if (streq(argv[optind], verb->verb)) + goto found; + + log_error("Unknown operation '%s'.", argv[optind]); + return -EINVAL; + } +found: + + switch (verb->argc_cmp) { + + case EQUAL: + if (left != verb->argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verb->argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verb->argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + /* Require a bus connection for all operations but + * enable/disable */ + if (verb->bus == NOBUS) { + if (!bus && !avoid_bus()) { + log_error("Failed to get D-Bus connection: %s", strerror(-bus_error)); + return -EIO; + } + + } else { + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + + if ((verb->bus != FORCE || arg_force <= 0) && !bus) { + log_error("Failed to get D-Bus connection: %s", strerror(-bus_error)); + return -EIO; + } + } + + return verb->dispatch(bus, argv + optind); +} + +static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) { + + struct sd_shutdown_command c = { + .usec = t, + .mode = mode, + .dry_run = dry_run, + .warn_wall = warn, + }; + + union sockaddr_union sockaddr = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/shutdownd", + }; + + struct iovec iovec[2] = {{ + .iov_base = (char*) &c, + .iov_len = offsetof(struct sd_shutdown_command, wall_message), + }}; + + struct msghdr msghdr = { + .msg_name = &sockaddr, + .msg_namelen = offsetof(struct sockaddr_un, sun_path) + + sizeof("/run/systemd/shutdownd") - 1, + .msg_iov = iovec, + .msg_iovlen = 1, + }; + + _cleanup_close_ int fd; + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (fd < 0) + return -errno; + + if (!isempty(message)) { + iovec[1].iov_base = (char*) message; + iovec[1].iov_len = strlen(message); + msghdr.msg_iovlen++; + } + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) + return -errno; + + return 0; +} + +static int reload_with_fallback(sd_bus *bus) { + + if (bus) { + /* First, try systemd via D-Bus. */ + if (daemon_reload(bus, NULL) >= 0) + return 0; + } + + /* Nothing else worked, so let's try signals */ + assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC); + + if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) { + log_error("kill() failed: %m"); + return -errno; + } + + return 0; +} + +static int start_with_fallback(sd_bus *bus) { + + if (bus) { + /* First, try systemd via D-Bus. */ + if (start_unit(bus, NULL) >= 0) + goto done; + } + + /* Nothing else worked, so let's try + * /dev/initctl */ + if (talk_initctl() > 0) + goto done; + + log_error("Failed to talk to init daemon."); + return -EIO; + +done: + warn_wall(arg_action); + return 0; +} + +static int halt_now(enum action a) { + +/* Make sure C-A-D is handled by the kernel from this + * point on... */ + reboot(RB_ENABLE_CAD); + + switch (a) { + + case ACTION_HALT: + log_info("Halting."); + reboot(RB_HALT_SYSTEM); + return -errno; + + case ACTION_POWEROFF: + log_info("Powering off."); + reboot(RB_POWER_OFF); + return -errno; + + case ACTION_REBOOT: { + _cleanup_free_ char *param = NULL; + + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + log_info("Rebooting with argument '%s'.", param); + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, param); + } + + log_info("Rebooting."); + reboot(RB_AUTOBOOT); + return -errno; + } + + default: + assert_not_reached("Unknown action."); + } +} + +static int halt_main(sd_bus *bus) { + int r; + + r = check_inhibitors(bus, arg_action); + if (r < 0) + return r; + + if (geteuid() != 0) { + /* Try logind if we are a normal user and no special + * mode applies. Maybe PolicyKit allows us to shutdown + * the machine. */ + + if (arg_when <= 0 && + !arg_dry && + arg_force <= 0 && + (arg_action == ACTION_POWEROFF || + arg_action == ACTION_REBOOT)) { + r = reboot_with_logind(bus, arg_action); + if (r >= 0) + return r; + } + + log_error("Must be root."); + return -EPERM; + } + + if (arg_when > 0) { + _cleanup_free_ char *m; + + m = strv_join(arg_wall, " "); + if (!m) + return log_oom(); + + r = send_shutdownd(arg_when, + arg_action == ACTION_HALT ? 'H' : + arg_action == ACTION_POWEROFF ? 'P' : + arg_action == ACTION_KEXEC ? 'K' : + 'r', + arg_dry, + !arg_no_wall, + m); + + if (r < 0) + log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r)); + else { + char date[FORMAT_TIMESTAMP_MAX]; + + log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", + format_timestamp(date, sizeof(date), arg_when)); + return 0; + } + } + + if (!arg_dry && !arg_force) + return start_with_fallback(bus); + + if (!arg_no_wtmp) { + if (sd_booted() > 0) + log_debug("Not writing utmp record, assuming that systemd-update-utmp is used."); + else { + r = utmp_put_shutdown(); + if (r < 0) + log_warning("Failed to write utmp record: %s", strerror(-r)); + } + } + + if (arg_dry) + return 0; + + r = halt_now(arg_action); + log_error("Failed to reboot: %s", strerror(-r)); + + return r; +} + +static int runlevel_main(void) { + int r, runlevel, previous; + + r = utmp_get_runlevel(&runlevel, &previous); + if (r < 0) { + puts("unknown"); + return r; + } + + printf("%c %c\n", + previous <= 0 ? 'N' : previous, + runlevel <= 0 ? 'N' : runlevel); + + return 0; +} + +int main(int argc, char*argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + /* Explicitly not on_tty() to avoid setting cached value. + * This becomes relevant for piping output which might be + * ellipsized. */ + original_stdout_is_tty = isatty(STDOUT_FILENO); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + /* /sbin/runlevel doesn't need to communicate via D-Bus, so + * let's shortcut this */ + if (arg_action == ACTION_RUNLEVEL) { + r = runlevel_main(); + goto finish; + } + + if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) { + log_info("Running in chroot, ignoring request."); + r = 0; + goto finish; + } + + if (!avoid_bus()) + r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus); + + /* systemctl_main() will print an error message for the bus + * connection, but only if it needs to */ + + switch (arg_action) { + + case ACTION_SYSTEMCTL: + r = systemctl_main(bus, argc, argv, r); + break; + + case ACTION_HALT: + case ACTION_POWEROFF: + case ACTION_REBOOT: + case ACTION_KEXEC: + r = halt_main(bus); + break; + + case ACTION_RUNLEVEL2: + case ACTION_RUNLEVEL3: + case ACTION_RUNLEVEL4: + case ACTION_RUNLEVEL5: + case ACTION_RESCUE: + case ACTION_EMERGENCY: + case ACTION_DEFAULT: + r = start_with_fallback(bus); + break; + + case ACTION_RELOAD: + case ACTION_REEXEC: + r = reload_with_fallback(bus); + break; + + case ACTION_CANCEL_SHUTDOWN: { + _cleanup_free_ char *m = NULL; + + if (arg_wall) { + m = strv_join(arg_wall, " "); + if (!m) { + r = log_oom(); + goto finish; + } + } + + r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m); + if (r < 0) + log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r)); + break; + } + + case ACTION_RUNLEVEL: + case _ACTION_INVALID: + default: + assert_not_reached("Unknown action"); + } + +finish: + pager_close(); + ask_password_agent_close(); + polkit_agent_close(); + + strv_free(arg_types); + strv_free(arg_states); + strv_free(arg_properties); + + return r < 0 ? EXIT_FAILURE : r; +} diff --git a/src/systemd-analyze b/src/systemd-analyze deleted file mode 100755 index 729aa05..0000000 --- a/src/systemd-analyze +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/python - -import dbus, sys - -def acquire_time_data(): - - manager = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.systemd1.Manager') - units = manager.ListUnits() - - l = [] - - for i in units: - if i[5] != "": - continue - - properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', i[6]), 'org.freedesktop.DBus.Properties') - - ixt = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestampMonotonic')) - aet = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestampMonotonic')) - axt = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestampMonotonic')) - iet = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestampMonotonic')) - - l.append((str(i[0]), ixt, aet, axt, iet)) - - return l - -def acquire_start_time(): - properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.DBus.Properties') - - initrd_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'InitRDTimestampMonotonic')) - startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestampMonotonic')) - finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestampMonotonic')) - - assert initrd_time <= startup_time - assert startup_time <= finish_time - - return initrd_time, startup_time, finish_time - -def draw_box(context, j, k, l, m, r = 0, g = 0, b = 0): - context.save() - context.set_source_rgb(r, g, b) - context.rectangle(j, k, l, m) - context.fill() - context.restore() - -def draw_text(context, x, y, text, size = 12, r = 0, g = 0, b = 0, vcenter = 0.5, hcenter = 0.5): - context.save() - - context.set_source_rgb(r, g, b) - context.select_font_face("Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) - context.set_font_size(size) - - if vcenter or hcenter: - x_bearing, y_bearing, width, height = context.text_extents(text)[:4] - - if hcenter: - x = x - width*hcenter - x_bearing - - if vcenter: - y = y - height*vcenter - y_bearing - - context.move_to(x, y) - context.show_text(text) - - context.restore() - -def help(): - sys.stdout.write("""systemd-analyze time -systemd-analyze blame -systemd-analyze plot - -Process systemd profiling information - - -h --help Show this help -""") - - -bus = dbus.SystemBus() - -if len(sys.argv) <= 1 or sys.argv[1] == 'time': - - initrd_time, start_time, finish_time = acquire_start_time() - - if initrd_time > 0: - print "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \ - initrd_time/1000, \ - (start_time - initrd_time)/1000, \ - (finish_time - start_time)/1000, \ - finish_time/1000) - else: - print "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \ - start_time/1000, \ - (finish_time - start_time)/1000, \ - finish_time/1000) - - -elif sys.argv[1] == 'blame': - - data = acquire_time_data() - s = sorted(data, key = lambda i: i[2] - i[1], reverse = True) - - for name, ixt, aet, axt, iet in s: - - if ixt <= 0 or aet <= 0: - continue - - if aet <= ixt: - continue - - sys.stdout.write("%6lums %s\n" % ((aet - ixt) / 1000, name)) - -elif sys.argv[1] == 'plot': - import cairo, os - - initrd_time, start_time, finish_time = acquire_start_time() - data = acquire_time_data() - s = sorted(data, key = lambda i: i[1]) - - # Account for kernel and initramfs bars if they exist - if initrd_time > 0: - count = 3 - else: - count = 2 - - for name, ixt, aet, axt, iet in s: - - if (ixt >= start_time and ixt <= finish_time) or \ - (aet >= start_time and aet <= finish_time) or \ - (axt >= start_time and axt <= finish_time): - count += 1 - - border = 100 - bar_height = 20 - bar_space = bar_height * 0.1 - - # 1000px = 10s, 1px = 10ms - width = finish_time/10000 + border*2 - height = count * (bar_height + bar_space) + border * 2 - - if width < 1000: - width = 1000 - - surface = cairo.SVGSurface(sys.stdout, width, height) - context = cairo.Context(surface) - - draw_box(context, 0, 0, width, height, 1, 1, 1) - - context.translate(border + 0.5, border + 0.5) - - context.save() - context.set_line_width(1) - context.set_source_rgb(0.7, 0.7, 0.7) - - for x in range(0, finish_time/10000 + 100, 100): - context.move_to(x, 0) - context.line_to(x, height-border*2) - - context.move_to(0, 0) - context.line_to(width-border*2, 0) - - context.move_to(0, height-border*2) - context.line_to(width-border*2, height-border*2) - - context.stroke() - context.restore() - - banner = "Running on %s (%s %s) %s" % (os.uname()[1], os.uname()[2], os.uname()[3], os.uname()[4]) - draw_text(context, 0, -15, banner, hcenter = 0, vcenter = 1) - - for x in range(0, finish_time/10000 + 100, 100): - draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0) - - y = 0 - - # draw boxes for kernel and initramfs boot time - if initrd_time > 0: - draw_box(context, 0, y, initrd_time/10000, bar_height, 0.7, 0.7, 0.7) - draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0) - y += bar_height + bar_space - - draw_box(context, initrd_time/10000, y, start_time/10000-initrd_time/10000, bar_height, 0.7, 0.7, 0.7) - draw_text(context, initrd_time/10000 + 10, y + bar_height/2, "initramfs", hcenter = 0) - y += bar_height + bar_space - - else: - draw_box(context, 0, y, start_time/10000, bar_height, 0.6, 0.6, 0.6) - draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0) - y += bar_height + bar_space - - draw_box(context, start_time/10000, y, finish_time/10000-start_time/10000, bar_height, 0.7, 0.7, 0.7) - draw_text(context, start_time/10000 + 10, y + bar_height/2, "userspace", hcenter = 0) - y += bar_height + bar_space - - for name, ixt, aet, axt, iet in s: - - drawn = False - left = -1 - - if ixt >= start_time and ixt <= finish_time: - - # Activating - a = ixt - b = min(filter(lambda x: x >= ixt, (aet, axt, iet, finish_time))) - ixt - - draw_box(context, a/10000, y, b/10000, bar_height, 1, 0, 0) - drawn = True - - if left < 0: - left = a - - if aet >= start_time and aet <= finish_time: - - # Active - a = aet - b = min(filter(lambda x: x >= aet, (axt, iet, finish_time))) - aet - - draw_box(context, a/10000, y, b/10000, bar_height, .8, .6, .6) - drawn = True - - if left < 0: - left = a - - if axt >= start_time and axt <= finish_time: - - # Deactivating - a = axt - b = min(filter(lambda x: x >= axt, (iet, finish_time))) - axt - - draw_box(context, a/10000, y, b/10000, bar_height, .6, .4, .4) - drawn = True - - if left < 0: - left = a - - if drawn: - x = left/10000 - - if x < width/2-border: - draw_text(context, x + 10, y + bar_height/2, name, hcenter = 0) - else: - draw_text(context, x - 10, y + bar_height/2, name, hcenter = 1) - - y += bar_height + bar_space - - draw_text(context, 0, height-border*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter = 0, vcenter = -1) - - if initrd_time > 0: - draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \ - initrd_time/1000, \ - (start_time - initrd_time)/1000, \ - (finish_time - start_time)/1000, \ - finish_time/1000), hcenter = 0, vcenter = -1) - else: - draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \ - start_time/1000, \ - (finish_time - start_time)/1000, \ - finish_time/1000), hcenter = 0, vcenter = -1) - - surface.finish() -elif sys.argv[1] in ("help", "--help", "-h"): - help() -else: - sys.stderr.write("Unknown verb '%s'.\n" % sys.argv[1]) - sys.exit(1) diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala deleted file mode 100644 index a380f79..0000000 --- a/src/systemd-interfaces.vala +++ /dev/null @@ -1,167 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -[DBus (name = "org.freedesktop.systemd1.Manager")] -public interface Manager : DBusProxy { - - public struct UnitInfo { - string id; - string description; - string load_state; - string active_state; - string sub_state; - string following; - ObjectPath unit_path; - uint32 job_id; - string job_type; - ObjectPath job_path; - } - - public struct JobInfo { - uint32 id; - string name; - string type; - string state; - ObjectPath job_path; - ObjectPath unit_path; - } - - public abstract string[] environment { owned get; } - - public abstract UnitInfo[] list_units() throws IOError; - public abstract JobInfo[] list_jobs() throws IOError; - - public abstract ObjectPath get_unit(string name) throws IOError; - public abstract ObjectPath get_unit_by_pid(uint32 pid) throws IOError; - public abstract ObjectPath load_unit(string name) throws IOError; - public abstract ObjectPath get_job(uint32 id) throws IOError; - - public abstract ObjectPath start_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath stop_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath reload_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath restart_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath try_restart_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath reload_or_restart_unit(string name, string mode = "replace") throws IOError; - public abstract ObjectPath reload_or_try_restart_unit(string name, string mode = "replace") throws IOError; - - public abstract void reset_failed_unit(string name = "") throws IOError; - - public abstract void clear_jobs() throws IOError; - - public abstract void subscribe() throws IOError; - public abstract void unsubscribe() throws IOError; - - public abstract string dump() throws IOError; - - public abstract void reload() throws IOError; - public abstract void reexecute() throws IOError; - public abstract void exit() throws IOError; - public abstract void halt() throws IOError; - public abstract void power_off() throws IOError; - public abstract void reboot() throws IOError; - public abstract void kexec() throws IOError; - - public abstract ObjectPath create_snapshot(string name = "", bool cleanup = false) throws IOError; - - public abstract void set_environment(string[] names) throws IOError; - public abstract void unset_environment(string[] names) throws IOError; - - public abstract signal void unit_new(string id, ObjectPath path); - public abstract signal void unit_removed(string id, ObjectPath path); - public abstract signal void job_new(uint32 id, ObjectPath path); - public abstract signal void job_removed(uint32 id, ObjectPath path, string res); -} - -[DBus (name = "org.freedesktop.systemd1.Unit")] -public interface Unit : DBusProxy { - public struct JobLink { - uint32 id; - ObjectPath path; - } - - public abstract string id { owned get; } - public abstract string[] names { owned get; } - public abstract string following { owned get; } - public abstract string[] requires { owned get; } - public abstract string[] requires_overridable { owned get; } - public abstract string[] requisite { owned get; } - public abstract string[] requisite_overridable { owned get; } - public abstract string[] wants { owned get; } - public abstract string[] required_by { owned get; } - public abstract string[] required_by_overridable { owned get; } - public abstract string[] wanted_by { owned get; } - public abstract string[] conflicts { owned get; } - public abstract string[] conflicted_by { owned get; } - public abstract string[] before { owned get; } - public abstract string[] after { owned get; } - public abstract string[] on_failure { owned get; } - public abstract string description { owned get; } - public abstract string load_state { owned get; } - public abstract string active_state { owned get; } - public abstract string sub_state { owned get; } - public abstract string fragment_path { owned get; } - public abstract uint64 inactive_exit_timestamp { owned get; } - public abstract uint64 active_enter_timestamp { owned get; } - public abstract uint64 active_exit_timestamp { owned get; } - public abstract uint64 inactive_enter_timestamp { owned get; } - public abstract bool can_start { owned get; } - public abstract bool can_stop { owned get; } - public abstract bool can_reload { owned get; } - public abstract JobLink job { owned get; } - public abstract bool recursive_stop { owned get; } - public abstract bool stop_when_unneeded { owned get; } - public abstract bool refuse_manual_start { owned get; } - public abstract bool refuse_manual_stop { owned get; } - public abstract bool default_dependencies { owned get; } - public abstract string default_control_group { owned get; } - public abstract string[] control_groups { owned get; } - public abstract bool need_daemon_reload { owned get; } - public abstract uint64 job_timeout_usec { owned get; } - - public abstract ObjectPath start(string mode = "replace") throws IOError; - public abstract ObjectPath stop(string mode = "replace") throws IOError; - public abstract ObjectPath reload(string mode = "replace") throws IOError; - public abstract ObjectPath restart(string mode = "replace") throws IOError; - public abstract ObjectPath try_restart(string mode = "replace") throws IOError; - public abstract ObjectPath reload_or_restart(string mode = "replace") throws IOError; - public abstract ObjectPath reload_or_try_restart(string mode = "replace") throws IOError; - - public abstract void reset_failed() throws IOError; -} - -[DBus (name = "org.freedesktop.systemd1.Job")] -public interface Job : DBusProxy { - public struct UnitLink { - string id; - ObjectPath path; - } - - public abstract uint32 id { owned get; } - public abstract string state { owned get; } - public abstract string job_type { owned get; } - public abstract UnitLink unit { owned get; } - - public abstract void cancel() throws IOError; -} - -[DBus (name = "org.freedesktop.Properties")] -public interface Properties : DBusProxy { - public abstract Variant? get(string iface, string property) throws IOError; - public abstract signal void properties_changed(string iface, HashTable changed_properties, string[] invalidated_properties); -} diff --git a/src/systemd-logind.conf b/src/systemd-logind.conf deleted file mode 100644 index 9909804..0000000 --- a/src/systemd-logind.conf +++ /dev/null @@ -1,16 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# See system-logind.conf(5) for details - -[Login] -#NAutoVTs=6 -#KillUserProcesses=no -#KillOnlyUsers= -#KillExcludeUsers=root -#Controllers= -#ResetControllers=cpu diff --git a/src/systemd/Makefile b/src/systemd/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/systemd/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h new file mode 100644 index 0000000..cc3be93 --- /dev/null +++ b/src/systemd/_sd-common.h @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdcommonhfoo +#define foosdcommonhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* This is a private header, never even think of including this directly! */ + +#if __INCLUDE_LEVEL__ <= 1 +#error "Do not include _sd-common.h directly, it is a private header." +#endif + +#ifndef _sd_printf_ +# if __GNUC__ >= 4 +# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b))) +# else +# define _sd_printf_(a,b) +# endif +#endif + +#ifndef _sd_sentinel_ +# define _sd_sentinel_ __attribute__((sentinel)) +#endif + +#ifndef _sd_packed_ +# define _sd_packed_ __attribute__((packed)) +#endif + +#ifndef _sd_pure_ +# define _sd_pure_ __attribute__((pure)) +#endif + +#ifndef _SD_STRINGIFY +# define _SD_XSTRINGIFY(x) #x +# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) +#endif + +#ifndef _SD_BEGIN_DECLARATIONS +# ifdef __cplusplus +# define _SD_BEGIN_DECLARATIONS \ + extern "C" { \ + struct __useless_struct_to_allow_trailing_semicolon__ +# else +# define _SD_BEGIN_DECLARATIONS \ + struct __useless_struct_to_allow_trailing_semicolon__ +# endif +#endif + +#ifndef _SD_END_DECLARATIONS +# ifdef __cplusplus +# define _SD_END_DECLARATIONS \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ +# else +# define _SD_END_DECLARATIONS \ + struct __useless_struct_to_allow_trailing_semicolon__ +# endif +#endif + +#endif diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h new file mode 100644 index 0000000..439a779 --- /dev/null +++ b/src/systemd/sd-bus-protocol.h @@ -0,0 +1,102 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdbusprotocolhfoo +#define foosdbusprotocolhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* Types of message */ + +enum { + _SD_BUS_MESSAGE_TYPE_INVALID = 0, + SD_BUS_MESSAGE_METHOD_CALL, + SD_BUS_MESSAGE_METHOD_RETURN, + SD_BUS_MESSAGE_METHOD_ERROR, + SD_BUS_MESSAGE_SIGNAL, + _SD_BUS_MESSAGE_TYPE_MAX +}; + +/* Primitive types */ + +enum { + _SD_BUS_TYPE_INVALID = 0, + SD_BUS_TYPE_BYTE = 'y', + SD_BUS_TYPE_BOOLEAN = 'b', + SD_BUS_TYPE_INT16 = 'n', + SD_BUS_TYPE_UINT16 = 'q', + SD_BUS_TYPE_INT32 = 'i', + SD_BUS_TYPE_UINT32 = 'u', + SD_BUS_TYPE_INT64 = 'x', + SD_BUS_TYPE_UINT64 = 't', + SD_BUS_TYPE_DOUBLE = 'd', + SD_BUS_TYPE_STRING = 's', + SD_BUS_TYPE_OBJECT_PATH = 'o', + SD_BUS_TYPE_SIGNATURE = 'g', + SD_BUS_TYPE_UNIX_FD = 'h', + SD_BUS_TYPE_ARRAY = 'a', + SD_BUS_TYPE_VARIANT = 'v', + SD_BUS_TYPE_STRUCT = 'r', /* not actually used in signatures */ + SD_BUS_TYPE_STRUCT_BEGIN = '(', + SD_BUS_TYPE_STRUCT_END = ')', + SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */ + SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{', + SD_BUS_TYPE_DICT_ENTRY_END = '}', +}; + +/* Well-known errors. Note that this is only a sanitized subset of the + * errors that the reference implementation generates. */ + +#define SD_BUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" +#define SD_BUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" +#define SD_BUS_ERROR_SERVICE_UNKNOWN "org.freedesktop.DBus.Error.ServiceUnknown" +#define SD_BUS_ERROR_NAME_HAS_NO_OWNER "org.freedesktop.DBus.Error.NameHasNoOwner" +#define SD_BUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply" +#define SD_BUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError" +#define SD_BUS_ERROR_BAD_ADDRESS "org.freedesktop.DBus.Error.BadAddress" +#define SD_BUS_ERROR_NOT_SUPPORTED "org.freedesktop.DBus.Error.NotSupported" +#define SD_BUS_ERROR_LIMITS_EXCEEDED "org.freedesktop.DBus.Error.LimitsExceeded" +#define SD_BUS_ERROR_ACCESS_DENIED "org.freedesktop.DBus.Error.AccessDenied" +#define SD_BUS_ERROR_AUTH_FAILED "org.freedesktop.DBus.Error.AuthFailed" +#define SD_BUS_ERROR_NO_SERVER "org.freedesktop.DBus.Error.NoServer" +#define SD_BUS_ERROR_TIMEOUT "org.freedesktop.DBus.Error.Timeout" +#define SD_BUS_ERROR_NO_NETWORK "org.freedesktop.DBus.Error.NoNetwork" +#define SD_BUS_ERROR_ADDRESS_IN_USE "org.freedesktop.DBus.Error.AddressInUse" +#define SD_BUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected" +#define SD_BUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" +#define SD_BUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" +#define SD_BUS_ERROR_FILE_EXISTS "org.freedesktop.DBus.Error.FileExists" +#define SD_BUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" +#define SD_BUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" +#define SD_BUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" +#define SD_BUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" +#define SD_BUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" +#define SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN "org.freedesktop.DBus.Error.UnixProcessIdUnknown" +#define SD_BUS_ERROR_INVALID_SIGNATURE "org.freedesktop.DBus.Error.InvalidSignature" +#define SD_BUS_ERROR_INCONSISTENT_MESSAGE "org.freedesktop.DBus.Error.InconsistentMessage" +#define SD_BUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound" +#define SD_BUS_ERROR_MATCH_RULE_INVALID "org.freedesktop.DBus.Error.MatchRuleInvalid" + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h new file mode 100644 index 0000000..a032215 --- /dev/null +++ b/src/systemd/sd-bus-vtable.h @@ -0,0 +1,138 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdbusvtablehfoo +#define foosdbusvtablehfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_bus_vtable sd_bus_vtable; + +#include "sd-bus.h" + +enum { + _SD_BUS_VTABLE_START = '<', + _SD_BUS_VTABLE_END = '>', + _SD_BUS_VTABLE_METHOD = 'M', + _SD_BUS_VTABLE_SIGNAL = 'S', + _SD_BUS_VTABLE_PROPERTY = 'P', + _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W', +}; + +enum { + SD_BUS_VTABLE_DEPRECATED = 1ULL << 0, + SD_BUS_VTABLE_HIDDEN = 1ULL << 1, + SD_BUS_VTABLE_UNPRIVILEGED = 1ULL << 2, + SD_BUS_VTABLE_METHOD_NO_REPLY = 1ULL << 3, + SD_BUS_VTABLE_PROPERTY_CONST = 1ULL << 4, + SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE = 1ULL << 5, + SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION = 1ULL << 6, + _SD_BUS_VTABLE_CAPABILITY_MASK = 0xFFFFULL << 40 +}; + +#define SD_BUS_VTABLE_CAPABILITY(x) ((uint64_t) (((x)+1) & 0xFFFF) << 40) + +struct sd_bus_vtable { + /* Please do not initialize this structure directly, use the + * macros below instead */ + + 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; + } 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; +}; + +#define SD_BUS_VTABLE_START(_flags) \ + { \ + .type = _SD_BUS_VTABLE_START, \ + .flags = _flags, \ + .x.start.element_size = sizeof(sd_bus_vtable), \ + } + +#define SD_BUS_METHOD(_member, _signature, _result, _handler, _flags) \ + { \ + .type = _SD_BUS_VTABLE_METHOD, \ + .flags = _flags, \ + .x.method.member = _member, \ + .x.method.signature = _signature, \ + .x.method.result = _result, \ + .x.method.handler = _handler, \ + } + +#define SD_BUS_SIGNAL(_member, _signature, _flags) \ + { \ + .type = _SD_BUS_VTABLE_SIGNAL, \ + .flags = _flags, \ + .x.signal.member = _member, \ + .x.signal.signature = _signature, \ + } + +#define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags) \ + { \ + .type = _SD_BUS_VTABLE_PROPERTY, \ + .flags = _flags, \ + .x.property.member = _member, \ + .x.property.signature = _signature, \ + .x.property.get = _get, \ + .x.property.offset = _offset, \ + } + +#define SD_BUS_WRITABLE_PROPERTY(_member, _signature, _get, _set, _offset, _flags) \ + { \ + .type = _SD_BUS_VTABLE_WRITABLE_PROPERTY, \ + .flags = _flags, \ + .x.property.member = _member, \ + .x.property.signature = _signature, \ + .x.property.get = _get, \ + .x.property.set = _set, \ + .x.property.offset = _offset, \ + } + +#define SD_BUS_VTABLE_END \ + { \ + .type = _SD_BUS_VTABLE_END, \ + } + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h new file mode 100644 index 0000000..0629e47 --- /dev/null +++ b/src/systemd/sd-bus.h @@ -0,0 +1,355 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdbushfoo +#define foosdbushfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-id128.h" +#include "sd-event.h" +#include "sd-memfd.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* Types */ + +typedef struct sd_bus sd_bus; +typedef struct sd_bus_message sd_bus_message; +typedef struct sd_bus_creds sd_bus_creds; + +typedef struct { + const char *name; + const char *message; + int _need_free; +} sd_bus_error; + +/* Flags */ + +enum { + SD_BUS_CREDS_PID = 1ULL << 0, + SD_BUS_CREDS_PID_STARTTIME = 1ULL << 1, + SD_BUS_CREDS_TID = 1ULL << 2, + SD_BUS_CREDS_UID = 1ULL << 3, + SD_BUS_CREDS_GID = 1ULL << 4, + SD_BUS_CREDS_COMM = 1ULL << 5, + SD_BUS_CREDS_TID_COMM = 1ULL << 6, + SD_BUS_CREDS_EXE = 1ULL << 7, + SD_BUS_CREDS_CMDLINE = 1ULL << 8, + SD_BUS_CREDS_CGROUP = 1ULL << 9, + SD_BUS_CREDS_UNIT = 1ULL << 10, + SD_BUS_CREDS_USER_UNIT = 1ULL << 11, + SD_BUS_CREDS_SLICE = 1ULL << 12, + SD_BUS_CREDS_SESSION = 1ULL << 13, + SD_BUS_CREDS_OWNER_UID = 1ULL << 14, + SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 15, + SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 16, + SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 17, + SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 18, + SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 19, + SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 20, + SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 21, + SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 22, + SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 23, + SD_BUS_CREDS_CONNECTION_NAME = 1ULL << 24, + _SD_BUS_CREDS_ALL = (1ULL << 25) -1, +}; + +enum { + SD_BUS_NAME_REPLACE_EXISTING = 1ULL << 0, + SD_BUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, + SD_BUS_NAME_QUEUE = 1ULL << 2, +}; + +/* Callbacks */ + +typedef int (*sd_bus_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_property_get_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_property_set_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *ret_error); +typedef int (*sd_bus_object_find_t) (sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error); +typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, void *userdata, char ***ret_nodes, sd_bus_error *ret_error); + +#include "sd-bus-protocol.h" +#include "sd-bus-vtable.h" + +/* Connections */ + +int sd_bus_default(sd_bus **ret); +int sd_bus_default_user(sd_bus **ret); +int sd_bus_default_system(sd_bus **ret); + +int sd_bus_open(sd_bus **ret); +int sd_bus_open_user(sd_bus **ret); +int sd_bus_open_system(sd_bus **ret); +int sd_bus_open_system_remote(sd_bus **ret, const char *host); +int sd_bus_open_system_container(sd_bus **ret, const char *machine); + +int sd_bus_new(sd_bus **ret); +int sd_bus_set_address(sd_bus *bus, const char *address); +int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd); +int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]); +int sd_bus_set_bus_client(sd_bus *bus, int b); +int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id); +int sd_bus_set_anonymous(sd_bus *bus, int b); +int sd_bus_set_trusted(sd_bus *bus, int b); +int sd_bus_set_name(sd_bus *bus, const char *name); +int sd_bus_negotiate_fds(sd_bus *bus, int b); +int sd_bus_negotiate_timestamp(sd_bus *bus, int b); +int sd_bus_negotiate_creds(sd_bus *bus, uint64_t creds_mask); +int sd_bus_start(sd_bus *ret); + +int sd_bus_try_close(sd_bus *bus); +void sd_bus_close(sd_bus *bus); + +sd_bus *sd_bus_ref(sd_bus *bus); +sd_bus *sd_bus_unref(sd_bus *bus); + +int sd_bus_is_open(sd_bus *bus); +int sd_bus_can_send(sd_bus *bus, char type); +int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *peer); +int sd_bus_get_peer_creds(sd_bus *bus, uint64_t creds_mask, sd_bus_creds **ret); +int sd_bus_get_name(sd_bus *bus, const char **name); +int sd_bus_get_tid(sd_bus *bus, pid_t *tid); + +int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie); +int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie); +int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply); +int sd_bus_call_async(sd_bus *bus, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *cookie); +int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie); + +int sd_bus_get_fd(sd_bus *bus); +int sd_bus_get_events(sd_bus *bus); +int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec); +int sd_bus_process(sd_bus *bus, sd_bus_message **r); +int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r); +int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec); +int sd_bus_flush(sd_bus *bus); +sd_bus_message* sd_bus_get_current(sd_bus *bus); + +int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority); +int sd_bus_detach_event(sd_bus *bus); +sd_event *sd_bus_get_event(sd_bus *bus); + +int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata); +int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata); + +int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata); +int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata); + +int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata); +int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata); + +int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata); +int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata); + +int sd_bus_add_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata); +int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata); + +int sd_bus_add_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata); +int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata); + +int sd_bus_add_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata); +int sd_bus_remove_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata); + +int sd_bus_add_object_manager(sd_bus *bus, const char *path); +int sd_bus_remove_object_manager(sd_bus *bus, const char *path); + +/* Message object */ + +int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member); +int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member); +int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m); +int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e); +int sd_bus_message_new_method_errorf(sd_bus_message *call, sd_bus_message **m, const char *name, const char *format, ...) _sd_printf_(4, 5); +int sd_bus_message_new_method_errno(sd_bus_message *call, sd_bus_message **m, int error, const sd_bus_error *e); +int sd_bus_message_new_method_errnof(sd_bus_message *call, sd_bus_message **m, int error, const char *format, ...) _sd_printf_(4, 5); + +sd_bus_message* sd_bus_message_ref(sd_bus_message *m); +sd_bus_message* sd_bus_message_unref(sd_bus_message *m); + +int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type); +int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie); +int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie); +int sd_bus_message_get_expect_reply(sd_bus_message *m); +int sd_bus_message_get_auto_start(sd_bus_message *m); +int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority); + +const char *sd_bus_message_get_signature(sd_bus_message *m, int complete); +const char *sd_bus_message_get_path(sd_bus_message *m); +const char *sd_bus_message_get_interface(sd_bus_message *m); +const char *sd_bus_message_get_member(sd_bus_message *m); +const char *sd_bus_message_get_destination(sd_bus_message *m); +const char *sd_bus_message_get_sender(sd_bus_message *m); +const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m); +int sd_bus_message_get_errno(sd_bus_message *m); + +int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec); +int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec); +int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t* seqnum); + +sd_bus* sd_bus_message_get_bus(sd_bus_message *m); +sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m); /* do not unref the result */ + +int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member); +int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member); +int sd_bus_message_is_method_error(sd_bus_message *m, const char *name); + +int sd_bus_message_set_expect_reply(sd_bus_message *m, int b); +int sd_bus_message_set_auto_start(sd_bus_message *m, int b); +int sd_bus_message_set_destination(sd_bus_message *m, const char *destination); +int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority); + +int sd_bus_message_append(sd_bus_message *m, const char *types, ...); +int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p); +int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size); +int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, void **ptr); +int sd_bus_message_append_array_iovec(sd_bus_message *m, char type, const struct iovec *iov, unsigned n); +int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, sd_memfd *memfd); +int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s); +int sd_bus_message_append_string_iovec(sd_bus_message *m, const struct iovec *iov, unsigned n); +int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd* memfd); +int sd_bus_message_append_strv(sd_bus_message *m, char **l); +int sd_bus_message_open_container(sd_bus_message *m, char type, const char *contents); +int sd_bus_message_close_container(sd_bus_message *m); +int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all); + +int sd_bus_message_read(sd_bus_message *m, const char *types, ...); +int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p); +int sd_bus_message_read_array(sd_bus_message *m, char type, const void **ptr, size_t *size); +int sd_bus_message_read_strv(sd_bus_message *m, char ***l); /* free the result! */ +int sd_bus_message_skip(sd_bus_message *m, const char *types); +int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *contents); +int sd_bus_message_exit_container(sd_bus_message *m); +int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents); +int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents); +int sd_bus_message_at_end(sd_bus_message *m, int complete); +int sd_bus_message_rewind(sd_bus_message *m, int complete); + +/* Bus management */ + +int sd_bus_get_unique_name(sd_bus *bus, const char **unique); +int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags); +int sd_bus_release_name(sd_bus *bus, const char *name); +int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatable); /* free the results */ +int sd_bus_get_owner(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds); /* unref the result! */ +int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine); + +/* Convenience calls */ + +int sd_bus_call_method(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *types, ...); +int sd_bus_get_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *type); +int sd_bus_get_property_trivial(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char type, void *ret_ptr); +int sd_bus_get_property_string(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char **ret); /* free the result! */ +int sd_bus_get_property_strv(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char ***ret); /* free the result! */ +int sd_bus_set_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, const char *ret_type, ...); + +int sd_bus_reply_method_return(sd_bus_message *call, const char *types, ...); +int sd_bus_reply_method_error(sd_bus_message *call, const sd_bus_error *e); +int sd_bus_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4); +int sd_bus_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *e); +int sd_bus_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4); + +int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...); + +int sd_bus_emit_properties_changed_strv(sd_bus *bus, const char *path, const char *interface, char **names); +int sd_bus_emit_properties_changed(sd_bus *bus, const char *path, const char *interface, const char *name, ...) _sd_sentinel_; + +int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces); +int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_; +int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces); +int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_; + +int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds); + +/* Credential handling */ + +int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t creds_mask); +sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c); +sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c); +uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c); + +int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid); +int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec); +int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid); +int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid); +int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid); +int sd_bus_creds_get_comm(sd_bus_creds *c, const char **comm); +int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **comm); +int sd_bus_creds_get_exe(sd_bus_creds *c, const char **exe); +int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline); +int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **cgroup); +int sd_bus_creds_get_unit(sd_bus_creds *c, const char **unit); +int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit); +int sd_bus_creds_get_slice(sd_bus_creds *c, const char **slice); +int sd_bus_creds_get_session(sd_bus_creds *c, const char **session); +int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid); +int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability); +int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability); +int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability); +int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability); +int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **context); +int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid); +int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *loginuid); +int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **name); +int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***names); +int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **name); + +/* Error structures */ + +#define SD_BUS_ERROR_MAKE_CONST(name, message) ((const sd_bus_error) {(name), (message), 0}) +#define SD_BUS_ERROR_NULL SD_BUS_ERROR_MAKE_CONST(NULL, NULL) + +void sd_bus_error_free(sd_bus_error *e); +int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message); +int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) _sd_printf_(3, 4); +int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message); +int sd_bus_error_set_errno(sd_bus_error *e, int error); +int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) _sd_printf_(3, 4); +int sd_bus_error_get_errno(const sd_bus_error *e); +int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e); +int sd_bus_error_is_set(const sd_bus_error *e); +int sd_bus_error_has_name(const sd_bus_error *e, const char *name); + +/* Auxiliary macros */ + +#define SD_BUS_MESSAGE_APPEND_ID128(x) 16, \ + (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], \ + (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], \ + (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], \ + (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15] + +#define SD_BUS_MESSAGE_READ_ID128(x) 16, \ + &(x).bytes[0], &(x).bytes[1], &(x).bytes[2], &(x).bytes[3], \ + &(x).bytes[4], &(x).bytes[5], &(x).bytes[6], &(x).bytes[7], \ + &(x).bytes[8], &(x).bytes[9], &(x).bytes[10], &(x).bytes[11], \ + &(x).bytes[12], &(x).bytes[13], &(x).bytes[14], &(x).bytes[15] + +/* Label escaping */ + +char *sd_bus_label_escape(const char *s); +char *sd_bus_label_unescape(const char *f); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h new file mode 100644 index 0000000..1d636df --- /dev/null +++ b/src/systemd/sd-daemon.h @@ -0,0 +1,264 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddaemonhfoo +#define foosddaemonhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* + The following functionality is provided: + + - Support for logging with log levels on stderr + - File descriptor passing for socket-based activation + - Daemon startup and status notification + - Detection of systemd boots + + See sd-daemon(3) for more information. +*/ + +/* + Log levels for usage on stderr: + + fprintf(stderr, SD_NOTICE "Hello World!\n"); + + This is similar to printk() usage in the kernel. +*/ +#define SD_EMERG "<0>" /* system is unusable */ +#define SD_ALERT "<1>" /* action must be taken immediately */ +#define SD_CRIT "<2>" /* critical conditions */ +#define SD_ERR "<3>" /* error conditions */ +#define SD_WARNING "<4>" /* warning conditions */ +#define SD_NOTICE "<5>" /* normal but significant condition */ +#define SD_INFO "<6>" /* informational */ +#define SD_DEBUG "<7>" /* debug-level messages */ + +/* The first passed file descriptor is fd 3 */ +#define SD_LISTEN_FDS_START 3 + +/* + Returns how many file descriptors have been passed, or a negative + errno code on failure. Optionally, removes the $LISTEN_FDS and + $LISTEN_PID file descriptors from the environment (recommended, but + problematic in threaded environments). If r is the return value of + this function you'll find the file descriptors passed as fds + SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative + errno style error code on failure. This function call ensures that + the FD_CLOEXEC flag is set for the passed file descriptors, to make + sure they are not passed on to child processes. If FD_CLOEXEC shall + not be set, the caller needs to unset it after this call for all file + descriptors that are used. + + See sd_listen_fds(3) for more information. +*/ +int sd_listen_fds(int unset_environment); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a FIFO in the file system stored under the + specified path, 0 otherwise. If path is NULL a path name check will + not be done and the call only verifies if the file descriptor + refers to a FIFO. Returns a negative errno style error code on + failure. + + See sd_is_fifo(3) for more information. +*/ +int sd_is_fifo(int fd, const char *path); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a special character device on the file + system stored under the specified path, 0 otherwise. + If path is NULL a path name check will not be done and the call + only verifies if the file descriptor refers to a special character. + Returns a negative errno style error code on failure. + + See sd_is_special(3) for more information. +*/ +int sd_is_special(int fd, const char *path); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a socket of the specified family (AF_INET, + ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If + family is 0 a socket family check will not be done. If type is 0 a + socket type check will not be done and the call only verifies if + the file descriptor refers to a socket. If listening is > 0 it is + verified that the socket is in listening mode. (i.e. listen() has + been called) If listening is == 0 it is verified that the socket is + not in listening mode. If listening is < 0 no listening mode check + is done. Returns a negative errno style error code on failure. + + See sd_is_socket(3) for more information. +*/ +int sd_is_socket(int fd, int family, int type, int listening); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is an Internet socket, of the specified family + (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, + SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version + check is not done. If type is 0 a socket type check will not be + done. If port is 0 a socket port check will not be done. The + listening flag is used the same way as in sd_is_socket(). Returns a + negative errno style error code on failure. + + See sd_is_socket_inet(3) for more information. +*/ +int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is an AF_UNIX socket of the specified type + (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 + a socket type check will not be done. If path is NULL a socket path + check will not be done. For normal AF_UNIX sockets set length to + 0. For abstract namespace sockets set length to the length of the + socket name (including the initial 0 byte), and pass the full + socket path in path (including the initial 0 byte). The listening + flag is used the same way as in sd_is_socket(). Returns a negative + errno style error code on failure. + + See sd_is_socket_unix(3) for more information. +*/ +int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length); + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a POSIX Message Queue of the specified name, + 0 otherwise. If path is NULL a message queue name check is not + done. Returns a negative errno style error code on failure. + + See sd_is_mq(3) for more information. +*/ +int sd_is_mq(int fd, const char *path); + +/* + Informs systemd about changed daemon state. This takes a number of + newline separated environment-style variable assignments in a + string. The following variables are known: + + READY=1 Tells systemd that daemon startup is finished (only + relevant for services of Type=notify). The passed + argument is a boolean "1" or "0". Since there is + little value in signaling non-readiness the only + value daemons should send is "READY=1". + + STATUS=... Passes a single-line status string back to systemd + that describes the daemon state. This is free-from + and can be used for various purposes: general state + feedback, fsck-like programs could pass completion + percentages and failing programs could pass a human + readable error message. Example: "STATUS=Completed + 66% of file system check..." + + ERRNO=... If a daemon fails, the errno-style error code, + formatted as string. Example: "ERRNO=2" for ENOENT. + + BUSERROR=... If a daemon fails, the D-Bus error-style error + code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" + + MAINPID=... The main pid of a daemon, in case systemd did not + fork off the process itself. Example: "MAINPID=4711" + + WATCHDOG=1 Tells systemd to update the watchdog timestamp. + Services using this feature should do this in + regular intervals. A watchdog framework can use the + timestamps to detect failed services. Also see + sd_watchdog_enabled() below. + + Daemons can choose to send additional variables. However, it is + recommended to prefix variable names not listed above with X_. + + Returns a negative errno-style error code on failure. Returns > 0 + if systemd could be notified, 0 if it couldn't possibly because + systemd is not running. + + Example: When a daemon finished starting up, it could issue this + call to notify systemd about it: + + sd_notify(0, "READY=1"); + + See sd_notifyf() for more complete examples. + + See sd_notify(3) for more information. +*/ +int sd_notify(int unset_environment, const char *state); + +/* + Similar to sd_notify() but takes a format string. + + Example 1: A daemon could send the following after initialization: + + sd_notifyf(0, "READY=1\n" + "STATUS=Processing requests...\n" + "MAINPID=%lu", + (unsigned long) getpid()); + + Example 2: A daemon could send the following shortly before + exiting, on failure: + + sd_notifyf(0, "STATUS=Failed to start up: %s\n" + "ERRNO=%i", + strerror(errno), + errno); + + See sd_notifyf(3) for more information. +*/ +int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_(2,3); + +/* + Returns > 0 if the system was booted with systemd. Returns < 0 on + error. Returns 0 if the system was not booted with systemd. Note + that all of the functions above handle non-systemd boots just + fine. You should NOT protect them with a call to this function. Also + note that this function checks whether the system, not the user + session is controlled by systemd. However the functions above work + for both user and system services. + + See sd_booted(3) for more information. +*/ +int sd_booted(void); + +/* + Returns > 0 if the service manager expects watchdog keep-alive + events to be sent regularly via sd_notify(0, "WATCHDOG=1"). Returns + 0 if it does not expect this. If the usec argument is non-NULL + returns the watchdog timeout in µs after which the service manager + will act on a process that has not sent a watchdog keep alive + message. This function is useful to implement services that + recognize automatically if they are being run under supervision of + systemd with WatchdogSec= set. It is recommended for clients to + generate keep-alive pings via sd_notify(0, "WATCHDOG=1") every half + of the returned time. + + See sd_watchdog_enabled(3) for more information. +*/ +int sd_watchdog_enabled(int unset_environment, uint64_t *usec); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h new file mode 100644 index 0000000..87f5adb --- /dev/null +++ b/src/systemd/sd-dhcp-client.h @@ -0,0 +1,74 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddhcpclienthfoo +#define foosddhcpclienthfoo + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-event.h" + +enum { + DHCP_EVENT_STOP = 0, + DHCP_EVENT_NO_LEASE = 1, + DHCP_EVENT_IP_ACQUIRE = 2, + DHCP_EVENT_IP_CHANGE = 3, + DHCP_EVENT_EXPIRED = 4, +}; + +typedef struct sd_dhcp_client sd_dhcp_client; +typedef struct sd_dhcp_lease sd_dhcp_lease; + +typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, + void *userdata); +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, + void *userdata); + + +int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); +int sd_dhcp_client_set_request_address(sd_dhcp_client *client, + const struct in_addr *last_address); +int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); +int sd_dhcp_client_set_mac(sd_dhcp_client *client, + const struct ether_addr *addr); +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); + +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); +int sd_dhcp_lease_get_address(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_dns(sd_dhcp_lease *lease, struct in_addr **addr, size_t *addr_size); +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); + +int sd_dhcp_client_stop(sd_dhcp_client *client); +int sd_dhcp_client_start(sd_dhcp_client *client); +void sd_dhcp_client_free(sd_dhcp_client *client); +int sd_dhcp_client_new(sd_dhcp_client **ret); + +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority); +int sd_dhcp_client_detach_event(sd_dhcp_client *client); +sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); + +#endif diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h new file mode 100644 index 0000000..45c3608 --- /dev/null +++ b/src/systemd/sd-event.h @@ -0,0 +1,126 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdeventhfoo +#define foosdeventhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "_sd-common.h" + +/* + Why is this better than pure epoll? + + - Supports event source priorisation + - Scales better with a large number of time events, since it doesn't require one timerfd each + - Automatically tries to coalesce timer events system-wide + - Handles signals and child PIDs +*/ + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_event sd_event; +typedef struct sd_event_source sd_event_source; + +enum { + SD_EVENT_OFF = 0, + SD_EVENT_ON = 1, + SD_EVENT_ONESHOT = -1 +}; + +enum { + SD_EVENT_PASSIVE, + SD_EVENT_RUNNING, + SD_EVENT_EXITING, + SD_EVENT_FINISHED +}; + +enum { + /* And everything inbetween and outside is good too */ + SD_EVENT_PRIORITY_IMPORTANT = -100, + SD_EVENT_PRIORITY_NORMAL = 0, + SD_EVENT_PRIORITY_IDLE = 100 +}; + +typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); +typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); +typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); +typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); + +int sd_event_default(sd_event **e); + +int sd_event_new(sd_event **e); +sd_event* sd_event_ref(sd_event *e); +sd_event* sd_event_unref(sd_event *e); + +int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata); +int sd_event_add_monotonic(sd_event *e, sd_event_source **s, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); +int sd_event_add_realtime(sd_event *e, sd_event_source **s, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); +int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); +int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); +int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); +int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); + +int sd_event_run(sd_event *e, uint64_t timeout); +int sd_event_loop(sd_event *e); +int sd_event_exit(sd_event *e, int code); + +int sd_event_get_state(sd_event *e); +int sd_event_get_tid(sd_event *e, pid_t *tid); +int sd_event_get_exit_code(sd_event *e, int *code); +int sd_event_get_now_realtime(sd_event *e, uint64_t *usec); +int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec); +int sd_event_set_watchdog(sd_event *e, int b); +int sd_event_get_watchdog(sd_event *e); + +sd_event_source* sd_event_source_ref(sd_event_source *s); +sd_event_source* sd_event_source_unref(sd_event_source *s); + +int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); +int sd_event_source_get_pending(sd_event_source *s); +int sd_event_source_get_priority(sd_event_source *s, int64_t *priority); +int sd_event_source_set_priority(sd_event_source *s, int64_t priority); +int sd_event_source_get_enabled(sd_event_source *s, int *enabled); +int sd_event_source_set_enabled(sd_event_source *s, int enabled); +void* sd_event_source_get_userdata(sd_event_source *s); +void* sd_event_source_set_userdata(sd_event_source *s, void *userdata); +int sd_event_source_get_io_fd(sd_event_source *s); +int sd_event_source_set_io_fd(sd_event_source *s, int fd); +int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events); +int sd_event_source_set_io_events(sd_event_source *s, uint32_t events); +int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents); +int sd_event_source_get_time(sd_event_source *s, uint64_t *usec); +int sd_event_source_set_time(sd_event_source *s, uint64_t usec); +int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); +int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec); +int sd_event_source_get_signal(sd_event_source *s); +int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +sd_event *sd_event_source_get_event(sd_event_source *s); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h new file mode 100644 index 0000000..f14efeb --- /dev/null +++ b/src/systemd/sd-id128.h @@ -0,0 +1,113 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdid128hfoo +#define foosdid128hfoo + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* 128 Bit ID APIs. See sd-id128(3) for more information. */ + +typedef union sd_id128 sd_id128_t; + +union sd_id128 { + uint8_t bytes[16]; + uint64_t qwords[2]; +}; + +#define SD_ID128_STRING_MAX 33 + +char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); + +int sd_id128_from_string(const char *s, sd_id128_t *ret); + +int sd_id128_randomize(sd_id128_t *ret); + +int sd_id128_get_machine(sd_id128_t *ret); + +int sd_id128_get_boot(sd_id128_t *ret); + +#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ + ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ + 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }}) + +#define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ + { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ + 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }} + +/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16 + * times. It is hence not a good idea to call this macro with an + * expensive function as paramater or an expression with side + * effects */ + +#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" +#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15] + +#define SD_ID128_CONST_STR(x) \ + ((const char[SD_ID128_STRING_MAX]) { \ + ((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \ + ((x).bytes[0] & 15) >= 10 ? 'a' + ((x).bytes[0] & 15) - 10 : '0' + ((x).bytes[0] & 15), \ + ((x).bytes[1] >> 4) >= 10 ? 'a' + ((x).bytes[1] >> 4) - 10 : '0' + ((x).bytes[1] >> 4), \ + ((x).bytes[1] & 15) >= 10 ? 'a' + ((x).bytes[1] & 15) - 10 : '0' + ((x).bytes[1] & 15), \ + ((x).bytes[2] >> 4) >= 10 ? 'a' + ((x).bytes[2] >> 4) - 10 : '0' + ((x).bytes[2] >> 4), \ + ((x).bytes[2] & 15) >= 10 ? 'a' + ((x).bytes[2] & 15) - 10 : '0' + ((x).bytes[2] & 15), \ + ((x).bytes[3] >> 4) >= 10 ? 'a' + ((x).bytes[3] >> 4) - 10 : '0' + ((x).bytes[3] >> 4), \ + ((x).bytes[3] & 15) >= 10 ? 'a' + ((x).bytes[3] & 15) - 10 : '0' + ((x).bytes[3] & 15), \ + ((x).bytes[4] >> 4) >= 10 ? 'a' + ((x).bytes[4] >> 4) - 10 : '0' + ((x).bytes[4] >> 4), \ + ((x).bytes[4] & 15) >= 10 ? 'a' + ((x).bytes[4] & 15) - 10 : '0' + ((x).bytes[4] & 15), \ + ((x).bytes[5] >> 4) >= 10 ? 'a' + ((x).bytes[5] >> 4) - 10 : '0' + ((x).bytes[5] >> 4), \ + ((x).bytes[5] & 15) >= 10 ? 'a' + ((x).bytes[5] & 15) - 10 : '0' + ((x).bytes[5] & 15), \ + ((x).bytes[6] >> 4) >= 10 ? 'a' + ((x).bytes[6] >> 4) - 10 : '0' + ((x).bytes[6] >> 4), \ + ((x).bytes[6] & 15) >= 10 ? 'a' + ((x).bytes[6] & 15) - 10 : '0' + ((x).bytes[6] & 15), \ + ((x).bytes[7] >> 4) >= 10 ? 'a' + ((x).bytes[7] >> 4) - 10 : '0' + ((x).bytes[7] >> 4), \ + ((x).bytes[7] & 15) >= 10 ? 'a' + ((x).bytes[7] & 15) - 10 : '0' + ((x).bytes[7] & 15), \ + ((x).bytes[8] >> 4) >= 10 ? 'a' + ((x).bytes[8] >> 4) - 10 : '0' + ((x).bytes[8] >> 4), \ + ((x).bytes[8] & 15) >= 10 ? 'a' + ((x).bytes[8] & 15) - 10 : '0' + ((x).bytes[8] & 15), \ + ((x).bytes[9] >> 4) >= 10 ? 'a' + ((x).bytes[9] >> 4) - 10 : '0' + ((x).bytes[9] >> 4), \ + ((x).bytes[9] & 15) >= 10 ? 'a' + ((x).bytes[9] & 15) - 10 : '0' + ((x).bytes[9] & 15), \ + ((x).bytes[10] >> 4) >= 10 ? 'a' + ((x).bytes[10] >> 4) - 10 : '0' + ((x).bytes[10] >> 4), \ + ((x).bytes[10] & 15) >= 10 ? 'a' + ((x).bytes[10] & 15) - 10 : '0' + ((x).bytes[10] & 15), \ + ((x).bytes[11] >> 4) >= 10 ? 'a' + ((x).bytes[11] >> 4) - 10 : '0' + ((x).bytes[11] >> 4), \ + ((x).bytes[11] & 15) >= 10 ? 'a' + ((x).bytes[11] & 15) - 10 : '0' + ((x).bytes[11] & 15), \ + ((x).bytes[12] >> 4) >= 10 ? 'a' + ((x).bytes[12] >> 4) - 10 : '0' + ((x).bytes[12] >> 4), \ + ((x).bytes[12] & 15) >= 10 ? 'a' + ((x).bytes[12] & 15) - 10 : '0' + ((x).bytes[12] & 15), \ + ((x).bytes[13] >> 4) >= 10 ? 'a' + ((x).bytes[13] >> 4) - 10 : '0' + ((x).bytes[13] >> 4), \ + ((x).bytes[13] & 15) >= 10 ? 'a' + ((x).bytes[13] & 15) - 10 : '0' + ((x).bytes[13] & 15), \ + ((x).bytes[14] >> 4) >= 10 ? 'a' + ((x).bytes[14] >> 4) - 10 : '0' + ((x).bytes[14] >> 4), \ + ((x).bytes[14] & 15) >= 10 ? 'a' + ((x).bytes[14] & 15) - 10 : '0' + ((x).bytes[14] & 15), \ + ((x).bytes[15] >> 4) >= 10 ? 'a' + ((x).bytes[15] >> 4) - 10 : '0' + ((x).bytes[15] >> 4), \ + ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ + 0 }) + +_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { + return memcmp(&a, &b, 16) == 0; +} + +#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h new file mode 100644 index 0000000..eb24372 --- /dev/null +++ b/src/systemd/sd-journal.h @@ -0,0 +1,157 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdjournalhfoo +#define foosdjournalhfoo + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "sd-id128.h" +#include "_sd-common.h" + +/* Journal APIs. See sd-journal(3) for more information. */ + +_SD_BEGIN_DECLARATIONS; + +/* Write to daemon */ +int sd_journal_print(int priority, const char *format, ...) _sd_printf_(2, 3); +int sd_journal_printv(int priority, const char *format, va_list ap) _sd_printf_(2, 0); +int sd_journal_send(const char *format, ...) _sd_printf_(1, 0) _sd_sentinel_; +int sd_journal_sendv(const struct iovec *iov, int n); +int sd_journal_perror(const char *message); + +/* Used by the macros below. You probably don't want to call this directly. */ +int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) _sd_printf_(5, 6); +int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) _sd_printf_(5, 0); +int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) _sd_printf_(4, 0) _sd_sentinel_; +int sd_journal_sendv_with_location(const char *file, const char *line, const char *func, const struct iovec *iov, int n); +int sd_journal_perror_with_location(const char *file, const char *line, const char *func, const char *message); + +/* implicitly add code location to messages sent, if this is enabled */ +#ifndef SD_JOURNAL_SUPPRESS_LOCATION + +#define sd_journal_print(priority, ...) sd_journal_print_with_location(priority, "CODE_FILE=" __FILE__, "CODE_LINE=" _SD_STRINGIFY(__LINE__), __func__, __VA_ARGS__) +#define sd_journal_printv(priority, format, ap) sd_journal_printv_with_location(priority, "CODE_FILE=" __FILE__, "CODE_LINE=" _SD_STRINGIFY(__LINE__), __func__, format, ap) +#define sd_journal_send(...) sd_journal_send_with_location("CODE_FILE=" __FILE__, "CODE_LINE=" _SD_STRINGIFY(__LINE__), __func__, __VA_ARGS__) +#define sd_journal_sendv(iovec, n) sd_journal_sendv_with_location("CODE_FILE=" __FILE__, "CODE_LINE=" _SD_STRINGIFY(__LINE__), __func__, iovec, n) +#define sd_journal_perror(message) sd_journal_perror_with_location("CODE_FILE=" __FILE__, "CODE_LINE=" _SD_STRINGIFY(__LINE__), __func__, message) + +#endif + +int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix); + +/* Browse journal stream */ + +typedef struct sd_journal sd_journal; + +/* Open flags */ +enum { + SD_JOURNAL_LOCAL_ONLY = 1, + SD_JOURNAL_RUNTIME_ONLY = 2, + SD_JOURNAL_SYSTEM = 4, + SD_JOURNAL_CURRENT_USER = 8, + + SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated name */ +}; + +/* Wakeup event types */ +enum { + SD_JOURNAL_NOP, + SD_JOURNAL_APPEND, + SD_JOURNAL_INVALIDATE +}; + +int sd_journal_open(sd_journal **ret, int flags); +int sd_journal_open_directory(sd_journal **ret, const char *path, int flags); +int sd_journal_open_files(sd_journal **ret, const char **paths, int flags); +int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); +void sd_journal_close(sd_journal *j); + +int sd_journal_previous(sd_journal *j); +int sd_journal_next(sd_journal *j); + +int sd_journal_previous_skip(sd_journal *j, uint64_t skip); +int sd_journal_next_skip(sd_journal *j, uint64_t skip); + +int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret); +int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id); + +int sd_journal_set_data_threshold(sd_journal *j, size_t sz); +int sd_journal_get_data_threshold(sd_journal *j, size_t *sz); + +int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *l); +int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *l); +void sd_journal_restart_data(sd_journal *j); + +int sd_journal_add_match(sd_journal *j, const void *data, size_t size); +int sd_journal_add_disjunction(sd_journal *j); +int sd_journal_add_conjunction(sd_journal *j); +void sd_journal_flush_matches(sd_journal *j); + +int sd_journal_seek_head(sd_journal *j); +int sd_journal_seek_tail(sd_journal *j); +int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec); +int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec); +int sd_journal_seek_cursor(sd_journal *j, const char *cursor); + +int sd_journal_get_cursor(sd_journal *j, char **cursor); +int sd_journal_test_cursor(sd_journal *j, const char *cursor); + +int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to); +int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, const sd_id128_t boot_id, uint64_t *from, uint64_t *to); + +int sd_journal_get_usage(sd_journal *j, uint64_t *bytes); + +int sd_journal_query_unique(sd_journal *j, const char *field); +int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l); +void sd_journal_restart_unique(sd_journal *j); + +int sd_journal_get_fd(sd_journal *j); +int sd_journal_get_events(sd_journal *j); +int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec); +int sd_journal_process(sd_journal *j); +int sd_journal_wait(sd_journal *j, uint64_t timeout_usec); +int sd_journal_reliable_fd(sd_journal *j); + +int sd_journal_get_catalog(sd_journal *j, char **text); +int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); + +#define SD_JOURNAL_FOREACH(j) \ + if (sd_journal_seek_head(j) >= 0) \ + while (sd_journal_next(j) > 0) + +#define SD_JOURNAL_FOREACH_BACKWARDS(j) \ + if (sd_journal_seek_tail(j) >= 0) \ + while (sd_journal_previous(j) > 0) + +#define SD_JOURNAL_FOREACH_DATA(j, data, l) \ + for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; ) + +#define SD_JOURNAL_FOREACH_UNIQUE(j, data, l) \ + for (sd_journal_restart_unique(j); sd_journal_enumerate_unique((j), &(data), &(l)) > 0; ) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h new file mode 100644 index 0000000..6de6932 --- /dev/null +++ b/src/systemd/sd-login.h @@ -0,0 +1,196 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdloginhfoo +#define foosdloginhfoo + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "_sd-common.h" + +/* + * A few points: + * + * Instead of returning an empty string array or empty uid array, we + * may return NULL. + * + * Free the data the library returns with libc free(). String arrays + * are NULL terminated and you need to free the array itself in + * addition to the strings contained. + * + * We return error codes as negative errno, kernel-style. 0 or + * positive on success. + * + * These functions access data in /proc, /sys/fs/cgroup and /run. All + * of these are virtual file systems, hence the accesses are + * relatively cheap. + * + * See sd-login(3) for more information. + */ + +_SD_BEGIN_DECLARATIONS; + +/* Get session from PID. Note that 'shared' processes of a user are + * not attached to a session, but only attached to a user. This will + * return an error for system processes and 'shared' processes of a + * user. */ +int sd_pid_get_session(pid_t pid, char **session); + +/* Get UID of the owner of the session of the PID (or in case the + * process is a 'shared' user process the UID of that user is + * returned). This will not return the UID of the process, but rather + * the UID of the owner of the cgroup the process is in. This will + * return an error for system processes. */ +int sd_pid_get_owner_uid(pid_t pid, uid_t *uid); + +/* Get systemd unit (i.e. service) name from PID, for system + * services. This will return an error for non-service processes. */ +int sd_pid_get_unit(pid_t pid, char **unit); + +/* Get systemd unit (i.e. service) name from PID, for user + * services. This will return an error for non-user-service + * processes. */ +int sd_pid_get_user_unit(pid_t pid, char **unit); + +/* Get machine name from PID, for processes assigned to VM or + * container. This will return an error for non-machine processes. */ +int sd_pid_get_machine_name(pid_t pid, char **name); + +/* Get slice name from PID. */ +int sd_pid_get_slice(pid_t pid, char **name); + +/* Get state from uid. Possible states: offline, lingering, online, active, closing */ +int sd_uid_get_state(uid_t uid, char**state); + +/* Return 1 if uid has session on seat. If require_active is true will + * look for active sessions only. */ +int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat); + +/* Return sessions of user. If require_active is true will look for + * active sessions only. Returns number of sessions as return + * value. If sessions is NULL will just return number of sessions. */ +int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions); + +/* Return seats of user is on. If require_active is true will look for + * active seats only. Returns number of seats. If seats is NULL will + * just return number of seats.*/ +int sd_uid_get_seats(uid_t uid, int require_active, char ***seats); + +/* Return 1 if the session is active. */ +int sd_session_is_active(const char *session); + +/* Return 1 if the session is remote. */ +int sd_session_is_remote(const char *session); + +/* Get state from session. Possible states: online, active, closing + * (This function is a more generic version of + * sd_session_is_active().) */ +int sd_session_get_state(const char *session, char **state); + +/* Determine user id of session */ +int sd_session_get_uid(const char *session, uid_t *uid); + +/* Determine seat of session */ +int sd_session_get_seat(const char *session, char **seat); + +/* Determine the (PAM) service name this session was registered by. */ +int sd_session_get_service(const char *session, char **service); + +/* Determine the type of this session, i.e. one of "tty", "x11" or "unspecified". */ +int sd_session_get_type(const char *session, char **type); + +/* Determine the class of this session, i.e. one of "user", "greeter" or "lock-screen". */ +int sd_session_get_class(const char *session, char **clazz); + +/* Determine the X11 display of this session. */ +int sd_session_get_display(const char *session, char **display); + +/* Determine the remote host of this session. */ +int sd_session_get_remote_host(const char *session, char **remote_host); + +/* Determine the remote user of this session (if provided by PAM). */ +int sd_session_get_remote_user(const char *session, char **remote_user); + +/* Determine the TTY of this session. */ +int sd_session_get_tty(const char *session, char **display); + +/* Determine the VT number of this session. */ +int sd_session_get_vt(const char *session, unsigned *vtnr); + +/* Return active session and user of seat */ +int sd_seat_get_active(const char *seat, char **session, uid_t *uid); + +/* Return sessions and users on seat. Returns number of sessions as + * return value. If sessions is NULL returns only the number of + * sessions. */ +int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids); + +/* Return whether the seat is multi-session capable */ +int sd_seat_can_multi_session(const char *seat); + +/* Return whether the seat is TTY capable, i.e. suitable for showing console UIs */ +int sd_seat_can_tty(const char *seat); + +/* Return whether the seat is graphics capable, i.e. suitable for showing graphical UIs */ +int sd_seat_can_graphical(const char *seat); + +/* Get all seats, store in *seats. Returns the number of seats. If + * seats is NULL only returns number of seats. */ +int sd_get_seats(char ***seats); + +/* Get all sessions, store in *sessions. Returns the number of + * sessions. If sessions is NULL only returns number of sessions. */ +int sd_get_sessions(char ***sessions); + +/* Get all logged in users, store in *users. Returns the number of + * users. If users is NULL only returns the number of users. */ +int sd_get_uids(uid_t **users); + +/* Get all running virtual machines/containers */ +int sd_get_machine_names(char ***machines); + +/* Monitor object */ +typedef struct sd_login_monitor sd_login_monitor; + +/* Create a new monitor. Category must be NULL, "seat", "session", + * "uid", "machine" to get monitor events for the specific category + * (or all). */ +int sd_login_monitor_new(const char *category, sd_login_monitor** ret); + +/* Destroys the passed monitor. Returns NULL. */ +sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m); + +/* Flushes the monitor */ +int sd_login_monitor_flush(sd_login_monitor *m); + +/* Get FD from monitor */ +int sd_login_monitor_get_fd(sd_login_monitor *m); + +/* Get poll() mask to monitor */ +int sd_login_monitor_get_events(sd_login_monitor *m); + +/* Get timeout for poll(), as usec value relative to CLOCK_MONOTONIC's epoch */ +int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-memfd.h b/src/systemd/sd-memfd.h new file mode 100644 index 0000000..753ed68 --- /dev/null +++ b/src/systemd/sd-memfd.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdmemfdhfoo +#define foosdmemfdhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_memfd sd_memfd; + +int sd_memfd_new(sd_memfd **m, const char *name); +int sd_memfd_new_from_fd(sd_memfd **m, int fd); +int sd_memfd_new_and_map(sd_memfd **m, const char *name, size_t sz, void **p); + +void sd_memfd_free(sd_memfd *m); + +int sd_memfd_get_fd(sd_memfd *m); +int sd_memfd_dup_fd(sd_memfd *n); +int sd_memfd_get_file(sd_memfd *m, FILE **f); + +int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p); + +int sd_memfd_set_sealed(sd_memfd *m, int b); +int sd_memfd_get_sealed(sd_memfd *m); + +int sd_memfd_get_size(sd_memfd *m, uint64_t *sz); +int sd_memfd_set_size(sd_memfd *m, uint64_t sz); + +int sd_memfd_get_name(sd_memfd *m, char **name); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h new file mode 100644 index 0000000..a8379e0 --- /dev/null +++ b/src/systemd/sd-messages.h @@ -0,0 +1,90 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdmessageshfoo +#define foosdmessageshfoo + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-id128.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* Hey! If you add a new message here, you *must* also update the + * message catalog with an appropriate explanation */ + +/* And if you add a new ID here, make sure to generate a random one + * with journalctl --new-id128. Do not use any other IDs, and do not + * count them up manually. */ + +#define SD_MESSAGE_JOURNAL_START SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b) +#define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b) +#define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e) +#define SD_MESSAGE_JOURNAL_MISSED SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06) +#define SD_MESSAGE_JOURNAL_USAGE SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6) + +#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) + +#define SD_MESSAGE_SESSION_START SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66) +#define SD_MESSAGE_SESSION_STOP SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a) +#define SD_MESSAGE_SEAT_START SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b) +#define SD_MESSAGE_SEAT_STOP SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5) +#define SD_MESSAGE_MACHINE_START SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2) +#define SD_MESSAGE_MACHINE_STOP SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58) + +#define SD_MESSAGE_TIME_CHANGE SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27) +#define SD_MESSAGE_TIMEZONE_CHANGE SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90) + +#define SD_MESSAGE_STARTUP_FINISHED SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff) + +#define SD_MESSAGE_SLEEP_START SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28) +#define SD_MESSAGE_SLEEP_STOP SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14) + +#define SD_MESSAGE_SHUTDOWN SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40) + +#define SD_MESSAGE_UNIT_STARTING SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5) +#define SD_MESSAGE_UNIT_STARTED SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf) +#define SD_MESSAGE_UNIT_STOPPING SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f) +#define SD_MESSAGE_UNIT_STOPPED SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86) +#define SD_MESSAGE_UNIT_FAILED SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d) +#define SD_MESSAGE_UNIT_RELOADING SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25) +#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54) + +#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7) + +#define SD_MESSAGE_FORWARD_SYSLOG_MISSED SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e) + +#define SD_MESSAGE_OVERMOUNTING SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7) + +#define SD_MESSAGE_LID_OPENED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f) +#define SD_MESSAGE_LID_CLOSED SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70) +#define SD_MESSAGE_SYSTEM_DOCKED SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff) +#define SD_MESSAGE_SYSTEM_UNDOCKED SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53) +#define SD_MESSAGE_POWER_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71) +#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72) +#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73) + +#define SD_MESSAGE_CONFIG_ERROR SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01) + +#define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-readahead.h b/src/systemd/sd-readahead.h new file mode 100644 index 0000000..ed8300c --- /dev/null +++ b/src/systemd/sd-readahead.h @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdreadaheadhfoo +#define foosdreadaheadhfoo + +/*** + Copyright 2010 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Reference implementation of a few boot readahead related + interfaces. These interfaces are trivial to implement. To simplify + porting, we provide this reference implementation. Applications are + welcome to reimplement the algorithms described here if they do not + want to include these two source files. + + You may compile this with -DDISABLE_SYSTEMD to disable systemd + support. This makes all calls NOPs. + + Since this is drop-in code we don't want any of our symbols to be + exported in any case. Hence we declare hidden visibility for all of + them. + + You may find an up-to-date version of these source files online: + + http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-readahead.h + http://cgit.freedesktop.org/systemd/systemd/plain/src/readahead/sd-readahead.c + + This should compile on non-Linux systems, too, but all functions + will become NOPs. + + See sd-readahead(3) for more information. +*/ + +/* + Controls ongoing disk read-ahead operations during boot-up. The argument + must be a string, and either "cancel", "done" or "noreplay". + + cancel = terminate read-ahead data collection, drop collected information + done = terminate read-ahead data collection, keep collected information + noreplay = terminate read-ahead replay +*/ +int sd_readahead(const char *action); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h new file mode 100644 index 0000000..df69e4b --- /dev/null +++ b/src/systemd/sd-resolve.h @@ -0,0 +1,148 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdresolvehfoo +#define foosdresolvehfoo + +/*** + This file is part of systemd. + + Copyright 2005-2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/** An opaque sd-resolve session structure */ +typedef struct sd_resolve sd_resolve; + +/** An opaque sd-resolve query structure */ +typedef struct sd_resolve_query sd_resolve_query; + +/** Allocate a new sd-resolve session */ +int sd_resolve_new(sd_resolve **ret); + +/** Free a sd-resolve session. This destroys all attached + * sd_resolve_query objects automatically */ +sd_resolve* sd_resolve_unref(sd_resolve *resolve); + +/** Return the UNIX file descriptor to poll() for events on. Use this + * function to integrate sd-resolve with your custom main loop. */ +int sd_resolve_get_fd(sd_resolve *resolve); + +/** Return the poll() events (a combination of flags like POLLIN, + * POLLOUT, ...) to check for. */ +int sd_resolve_get_events(sd_resolve *resolve); + +/** Return the poll() timeout to pass. Returns (uint64_t) -1 as time + * out if no time out is needed */ +int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *timeout_usec); + +/** Process pending responses. After this function is called you can + * get the next completed query object(s) using + * sd_resolve_get_next(). */ +int sd_resolve_process(sd_resolve *resolve); + +/** Wait for a resolve event to complete */ +int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec); + +/** Issue a name to address query on the specified session. The + * arguments are compatible with the ones of libc's + * getaddrinfo(3). The function returns a new query object. When the + * query is completed you may retrieve the results using + * sd_resolve_getaddrinfo_done(). */ +int sd_resolve_getaddrinfo(sd_resolve *resolve, sd_resolve_query **q, const char *node, const char *service, const struct addrinfo *hints); + +/** Retrieve the results of a preceding sd_resolve_getaddrinfo() + * call. Returns a addrinfo structure and a return value compatible + * with libc's getaddrinfo(3). The query object q is destroyed by this + * call and may not be used any further. Make sure to free the + * returned addrinfo structure with sd_resolve_freeaddrinfo() and not + * libc's freeaddrinfo(3)! If the query is not completed yet EAI_AGAIN + * is returned. */ +int sd_resolve_getaddrinfo_done(sd_resolve_query* q, struct addrinfo **ret_ai); + +/** Free the addrinfo structure as returned by + * sd_resolve_getaddrinfo_done(). Make sure to use this functions instead + * of the libc's freeaddrinfo()! */ +void sd_resolve_freeaddrinfo(struct addrinfo *ai); + +/** Issue an address to name query on the specified session. The + * arguments are compatible with the ones of libc's + * getnameinfo(3). The function returns a new query object. When the + * query is completed you may retrieve the results using + * sd_resolve_getnameinfo_done(). Set gethost (resp. getserv) to non-zero + * if you want to query the hostname (resp. the service name). */ +int sd_resolve_getnameinfo(sd_resolve *resolve, sd_resolve_query **q, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv); + +/** Retrieve the results of a preceding sd_resolve_getnameinfo() + * call. Returns the hostname and the service name in ret_host and + * ret_serv. The query object q is destroyed by this call and may not + * be used any further. If the query is not completed yet EAI_AGAIN is + * returned. */ +int sd_resolve_getnameinfo_done(sd_resolve_query* q, char **ret_host, char **ret_serv); + +/** Issue a resolver query on the specified session. The arguments are + * compatible with the ones of libc's res_query(3). The function returns a new + * query object. When the query is completed you may retrieve the results using + * sd_resolve_res_done(). */ +int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query **q, const char *dname, int class, int type); + +/** Issue an resolver query on the specified session. The arguments are + * compatible with the ones of libc's res_search(3). The function returns a new + * query object. When the query is completed you may retrieve the results using + * sd_resolve_res_done(). */ +int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query **q, const char *dname, int class, int type); + +/** Retrieve the results of a preceding sd_resolve_res_query() or + * resolve_res_search call. The query object q is destroyed by this + * call and may not be used any further. Returns a pointer to the + * answer of the res_query call. If the query is not completed yet + * -EAGAIN is returned, on failure -errno is returned, otherwise the + * length of answer is returned. */ +int sd_resolve_res_done(sd_resolve_query* q, unsigned char **answer); + +/** Return the next completed query object. If no query has been + * completed yet, return NULL. Please note that you need to run + * sd_resolve_wait() before this function will return sensible data. */ +int sd_resolve_get_next(sd_resolve *resolve, sd_resolve_query **q); + +/** Return the number of query objects (completed or not) attached to + * this session */ +int sd_resolve_get_n_queries(sd_resolve *resolve); + +/** Cancel a currently running query. q is is destroyed by this call + * and may not be used any futher. */ +int sd_resolve_cancel(sd_resolve_query* q); + +/** Returns non-zero when the query operation specified by q has been completed */ +int sd_resolve_is_done(sd_resolve_query*q); + +/** Assign some opaque userdata with a query object */ +void* sd_resolve_set_userdata(sd_resolve_query *q, void *userdata); + +/** Return userdata assigned to a query object. Use + * sd_resolve_setuserdata() to set this data. If no data has been set + * prior to this call it returns NULL. */ +void* sd_resolve_get_userdata(sd_resolve_query *q); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h new file mode 100644 index 0000000..f2b3a53 --- /dev/null +++ b/src/systemd/sd-rtnl.h @@ -0,0 +1,111 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdrtnlhfoo +#define foosdrtnlhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_rtnl sd_rtnl; +typedef struct sd_rtnl_message sd_rtnl_message; + +/* callback */ + +typedef int (*sd_rtnl_message_handler_t)(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); + +/* bus */ +int sd_rtnl_open(sd_rtnl **nl, uint32_t groups); + +sd_rtnl *sd_rtnl_ref(sd_rtnl *nl); +sd_rtnl *sd_rtnl_unref(sd_rtnl *nl); + +int sd_rtnl_send(sd_rtnl *nl, sd_rtnl_message *message, uint32_t *serial); +int sd_rtnl_call_async(sd_rtnl *nl, sd_rtnl_message *message, + sd_rtnl_message_handler_t callback, + void *userdata, uint64_t usec, uint32_t *serial); +int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial); +int sd_rtnl_call(sd_rtnl *nl, sd_rtnl_message *message, uint64_t timeout, + sd_rtnl_message **reply); + + +int sd_rtnl_get_events(sd_rtnl *nl); +int sd_rtnl_get_timeout(sd_rtnl *nl, uint64_t *timeout); +int sd_rtnl_process(sd_rtnl *nl, sd_rtnl_message **ret); +int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout); +int sd_rtnl_flush(sd_rtnl *nl); + +int sd_rtnl_add_match(sd_rtnl *nl, uint16_t match, sd_rtnl_message_handler_t c, void *userdata); +int sd_rtnl_remove_match(sd_rtnl *nl, uint16_t match, sd_rtnl_message_handler_t c, void *userdata); + +int sd_rtnl_attach_event(sd_rtnl *nl, sd_event *e, int priority); +int sd_rtnl_detach_event(sd_rtnl *nl); + +/* messages */ +int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index); +int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index, + unsigned char family); +int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, + unsigned char rtm_family); + +sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m); +sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m); + +int sd_rtnl_message_get_errno(sd_rtnl_message *m); +int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type); + +int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen); +int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope); +int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags); + +int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change); +int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type); +int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex); +int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags); + +int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen); + +int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data); +int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data); +int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data); +int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data); +int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data); +int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data); +int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data); + +int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type); +int sd_rtnl_message_close_container(sd_rtnl_message *m); + +int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data); +int sd_rtnl_message_exit_container(sd_rtnl_message *m); + +int sd_rtnl_message_rewind(sd_rtnl_message *m); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-shutdown.h b/src/systemd/sd-shutdown.h new file mode 100644 index 0000000..1d65549 --- /dev/null +++ b/src/systemd/sd-shutdown.h @@ -0,0 +1,120 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdshutdownhfoo +#define foosdshutdownhfoo + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* Interface for scheduling and cancelling timed shutdowns. */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _sd_packed_ +# define _sd_packed_ __attribute__((packed)) +#endif + +typedef enum sd_shutdown_mode { + SD_SHUTDOWN_NONE = 0, + SD_SHUTDOWN_REBOOT = 'r', + SD_SHUTDOWN_POWEROFF = 'P', + SD_SHUTDOWN_HALT = 'H', + SD_SHUTDOWN_KEXEC = 'K' +} sd_shutdown_mode_t; + +/* Calculate the size of the message as "offsetof(struct + * sd_shutdown_command, wall_message) + + * strlen(command.wall_message)" */ +struct sd_shutdown_command { + /* Microseconds after the epoch 1970 UTC */ + uint64_t usec; + + /* H, P, r, i.e. the switches usually passed to + * /usr/bin/shutdown to select whether to halt, power-off or + * reboot the machine */ + sd_shutdown_mode_t mode:8; + + /* If non-zero, don't actually shut down, just pretend */ + unsigned dry_run:1; + + /* If non-zero, send our wall message */ + unsigned warn_wall:1; + + /* The wall message to send around. Leave empty for the + * default wall message */ + char wall_message[]; +} _sd_packed_; + +/* The scheme is very simple: + * + * To schedule a shutdown, simply fill in and send a single + * AF_UNIX/SOCK_DGRAM datagram with the structure above suffixed with + * the wall message to the socket /run/systemd/shutdownd (leave an + * empty wall message for the default shutdown message). To calculate + * the size of the message use "offsetof(struct sd_shutdown_command, + * wall_message) + strlen(command.wall_message)". + * + * To cancel a shutdown, do the same, but send an fully zeroed out + * structure. + * + * To be notified about scheduled shutdowns, create an inotify watch + * on /run/shutdown/. Whenever a file called "scheduled" appears a + * shutdown is scheduled. If it is removed it is canceled. It is + * replaced the scheduled shutdown has been changed. The file contains + * a simple environment-like block, that contains information about + * the scheduled shutdown: + * + * USEC= + * encodes the time for the shutdown in usecs since the epoch UTC, + * formatted as numeric string. + * + * WARN_WALL= + * is 1 if a wall message shall be sent + * + * DRY_RUN= + * is 1 if a dry run shutdown is scheduled + * + * MODE= + * is the shutdown mode, one of "poweroff", "reboot", "halt", "kexec" + * + * WALL_MESSAGE= + * is the wall message to use, with all special characters escape in C style. + * + * Note that some fields might be missing if they do not apply. + * + * Note that the file is first written to a temporary file and then + * renamed, in order to provide atomic properties for readers: if the + * file exists under the name "scheduled" it is guaranteed to be fully + * written. A reader should ignore all files in that directory by any + * other name. + * + * Scheduled shutdowns are only accepted from privileged processes, + * but the directory may be watched and the file in it read by + * anybody. + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/systemd/sd-utf8.h b/src/systemd/sd-utf8.h new file mode 100644 index 0000000..205ee42 --- /dev/null +++ b/src/systemd/sd-utf8.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdutf8hfoo +#define foosdutf8hfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +_sd_pure_ const char *sd_utf8_is_valid(const char *s); +_sd_pure_ const char *sd_ascii_is_valid(const char *s); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/target.c b/src/target.c deleted file mode 100644 index 340e990..0000000 --- a/src/target.c +++ /dev/null @@ -1,223 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "unit.h" -#include "target.h" -#include "load-fragment.h" -#include "log.h" -#include "dbus-target.h" -#include "special.h" -#include "unit-name.h" - -static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = { - [TARGET_DEAD] = UNIT_INACTIVE, - [TARGET_ACTIVE] = UNIT_ACTIVE -}; - -static void target_set_state(Target *t, TargetState state) { - TargetState old_state; - assert(t); - - old_state = t->state; - t->state = state; - - if (state != old_state) - log_debug("%s changed %s -> %s", - t->meta.id, - target_state_to_string(old_state), - target_state_to_string(state)); - - unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); -} - -static int target_add_default_dependencies(Target *t) { - static const UnitDependency deps[] = { - UNIT_REQUIRES, - UNIT_REQUIRES_OVERRIDABLE, - UNIT_REQUISITE, - UNIT_REQUISITE_OVERRIDABLE, - UNIT_WANTS, - UNIT_BIND_TO - }; - - Iterator i; - Unit *other; - int r; - unsigned k; - - assert(t); - - /* Imply ordering for requirement dependencies on target - * units. Note that when the user created a contradicting - * ordering manually we won't add anything in here to make - * sure we don't create a loop. */ - - for (k = 0; k < ELEMENTSOF(deps); k++) - SET_FOREACH(other, t->meta.dependencies[deps[k]], i) - if ((r = unit_add_default_target_dependency(other, UNIT(t))) < 0) - return r; - - /* Make sure targets are unloaded on shutdown */ - return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); -} - -static int target_load(Unit *u) { - Target *t = TARGET(u); - int r; - - assert(t); - - if ((r = unit_load_fragment_and_dropin(u)) < 0) - return r; - - /* This is a new unit? Then let's add in some extras */ - if (u->meta.load_state == UNIT_LOADED) { - if (u->meta.default_dependencies) - if ((r = target_add_default_dependencies(t)) < 0) - return r; - } - - return 0; -} - -static int target_coldplug(Unit *u) { - Target *t = TARGET(u); - - assert(t); - assert(t->state == TARGET_DEAD); - - if (t->deserialized_state != t->state) - target_set_state(t, t->deserialized_state); - - return 0; -} - -static void target_dump(Unit *u, FILE *f, const char *prefix) { - Target *t = TARGET(u); - - assert(t); - assert(f); - - fprintf(f, - "%sTarget State: %s\n", - prefix, target_state_to_string(t->state)); -} - -static int target_start(Unit *u) { - Target *t = TARGET(u); - - assert(t); - assert(t->state == TARGET_DEAD); - - target_set_state(t, TARGET_ACTIVE); - return 0; -} - -static int target_stop(Unit *u) { - Target *t = TARGET(u); - - assert(t); - assert(t->state == TARGET_ACTIVE); - - target_set_state(t, TARGET_DEAD); - return 0; -} - -static int target_serialize(Unit *u, FILE *f, FDSet *fds) { - Target *s = TARGET(u); - - assert(s); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", target_state_to_string(s->state)); - return 0; -} - -static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Target *s = TARGET(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - TargetState state; - - if ((state = target_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - s->deserialized_state = state; - - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState target_active_state(Unit *u) { - assert(u); - - return state_translation_table[TARGET(u)->state]; -} - -static const char *target_sub_state_to_string(Unit *u) { - assert(u); - - return target_state_to_string(TARGET(u)->state); -} - -static const char* const target_state_table[_TARGET_STATE_MAX] = { - [TARGET_DEAD] = "dead", - [TARGET_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); - -const UnitVTable target_vtable = { - .suffix = ".target", - .sections = - "Unit\0" - "Target\0" - "Install\0", - - .load = target_load, - .coldplug = target_coldplug, - - .dump = target_dump, - - .start = target_start, - .stop = target_stop, - - .serialize = target_serialize, - .deserialize_item = target_deserialize_item, - - .active_state = target_active_state, - .sub_state_to_string = target_sub_state_to_string, - - .bus_interface = "org.freedesktop.systemd1.Target", - .bus_message_handler = bus_target_message_handler -}; diff --git a/src/target.h b/src/target.h deleted file mode 100644 index b1d055f..0000000 --- a/src/target.h +++ /dev/null @@ -1,47 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef footargethfoo -#define footargethfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Target Target; - -#include "unit.h" - -typedef enum TargetState { - TARGET_DEAD, - TARGET_ACTIVE, - _TARGET_STATE_MAX, - _TARGET_STATE_INVALID = -1 -} TargetState; - -struct Target { - Meta meta; - - TargetState state, deserialized_state; -}; - -extern const UnitVTable target_vtable; - -const char* target_state_to_string(TargetState i); -TargetState target_state_from_string(const char *s); - -#endif diff --git a/src/tcpwrap.c b/src/tcpwrap.c deleted file mode 100644 index 0aab142..0000000 --- a/src/tcpwrap.c +++ /dev/null @@ -1,68 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#ifdef HAVE_LIBWRAP -#include -#endif - -#include "tcpwrap.h" -#include "log.h" - -bool socket_tcpwrap(int fd, const char *name) { -#ifdef HAVE_LIBWRAP - struct request_info req; - union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_storage storage; - } sa_union; - socklen_t l = sizeof(sa_union); - - if (getsockname(fd, &sa_union.sa, &l) < 0) - return true; - - if (sa_union.sa.sa_family != AF_INET && - sa_union.sa.sa_family != AF_INET6) - return true; - - request_init(&req, - RQ_DAEMON, name, - RQ_FILE, fd, - NULL); - - fromhost(&req); - - if (!hosts_access(&req)) { - log_warning("Connection refused by tcpwrap."); - return false; - } - - log_debug("Connection accepted by tcpwrap."); -#endif - return true; -} diff --git a/src/tcpwrap.h b/src/tcpwrap.h deleted file mode 100644 index 4d4553e..0000000 --- a/src/tcpwrap.h +++ /dev/null @@ -1,29 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foolibwraphfoo -#define foolibwraphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -bool socket_tcpwrap(int fd, const char *name); - -#endif diff --git a/src/test-cgroup.c b/src/test-cgroup.c deleted file mode 100644 index eb18937..0000000 --- a/src/test-cgroup.c +++ /dev/null @@ -1,104 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "cgroup-util.h" -#include "util.h" -#include "log.h" - -int main(int argc, char*argv[]) { - char *path; - char *c, *p; - - assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); - assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); - assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0); - assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c") == 0); - assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0); - - assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); - assert_se(streq(path, "/test-b")); - free(path); - - assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0); - - assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); - assert_se(path_equal(path, "/test-a")); - free(path); - - assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0); - - assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); - assert_se(path_equal(path, "/test-b/test-d")); - free(path); - - assert_se(cg_get_path(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", NULL, &path) == 0); - assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d")); - free(path); - - assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); - assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0); - - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0); - - assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", "/test-a", false, false) > 0); - - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); - - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0); - - cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false); - - assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0); - assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); - - assert_se(cg_split_spec("foobar:/", &c, &p) == 0); - assert(streq(c, "foobar")); - assert(streq(p, "/")); - free(c); - free(p); - - assert_se(cg_split_spec("foobar:", &c, &p) < 0); - assert_se(cg_split_spec("foobar:asdfd", &c, &p) < 0); - assert_se(cg_split_spec(":///", &c, &p) < 0); - assert_se(cg_split_spec(":", &c, &p) < 0); - assert_se(cg_split_spec("", &c, &p) < 0); - assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0); - - assert_se(cg_split_spec("/", &c, &p) >= 0); - assert(c == NULL); - assert(streq(p, "/")); - free(p); - - assert_se(cg_split_spec("foo", &c, &p) >= 0); - assert(streq(c, "foo")); - assert(p == NULL); - free(c); - - return 0; -} diff --git a/src/test-daemon.c b/src/test-daemon.c deleted file mode 100644 index c7600d4..0000000 --- a/src/test-daemon.c +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "sd-daemon.h" - -int main(int argc, char*argv[]) { - - sd_notify(0, "STATUS=Starting up"); - sleep(5); - sd_notify(0, - "STATUS=Running\n" - "READY=1"); - sleep(10); - sd_notify(0, "STATUS=Quitting"); - - return 0; -} diff --git a/src/test-engine.c b/src/test-engine.c deleted file mode 100644 index 60619b9..0000000 --- a/src/test-engine.c +++ /dev/null @@ -1,99 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "manager.h" - -int main(int argc, char *argv[]) { - Manager *m = NULL; - Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; - Job *j; - - assert_se(set_unit_path("test2") >= 0); - - assert_se(manager_new(MANAGER_SYSTEM, &m) >= 0); - - printf("Load1:\n"); - assert_se(manager_load_unit(m, "a.service", NULL, NULL, &a) >= 0); - assert_se(manager_load_unit(m, "b.service", NULL, NULL, &b) >= 0); - assert_se(manager_load_unit(m, "c.service", NULL, NULL, &c) >= 0); - manager_dump_units(m, stdout, "\t"); - - printf("Test1: (Trivial)\n"); - assert_se(manager_add_job(m, JOB_START, c, JOB_REPLACE, false, NULL, &j) == 0); - manager_dump_jobs(m, stdout, "\t"); - - printf("Load2:\n"); - manager_clear_jobs(m); - assert_se(manager_load_unit(m, "d.service", NULL, NULL, &d) >= 0); - assert_se(manager_load_unit(m, "e.service", NULL, NULL, &e) >= 0); - manager_dump_units(m, stdout, "\t"); - - printf("Test2: (Cyclic Order, Unfixable)\n"); - assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -ENOEXEC); - 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, false, 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, false, NULL, &j) == 0); - manager_dump_jobs(m, stdout, "\t"); - - printf("Load3:\n"); - assert_se(manager_load_unit(m, "g.service", NULL, NULL, &g) >= 0); - manager_dump_units(m, stdout, "\t"); - - printf("Test5: (Colliding transaction, fail)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EEXIST); - - printf("Test6: (Colliding transaction, replace)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, 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, false, NULL, &j) == -EEXIST); - - printf("Test8: (Mergeable job type, fail)\n"); - assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, 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, false, NULL, &j) == 0); - manager_dump_jobs(m, stdout, "\t"); - - printf("Load4:\n"); - assert_se(manager_load_unit(m, "h.service", NULL, NULL, &h) >= 0); - 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, false, NULL, &j) == 0); - manager_dump_jobs(m, stdout, "\t"); - - manager_free(m); - - return 0; -} diff --git a/src/test-env-replace.c b/src/test-env-replace.c deleted file mode 100644 index 05dbacd..0000000 --- a/src/test-env-replace.c +++ /dev/null @@ -1,127 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "util.h" -#include "log.h" -#include "strv.h" - -int main(int argc, char *argv[]) { - - const char *env[] = { - "FOO=BAR BAR", - "BAR=waldo", - NULL - }; - - const char *line[] = { - "FOO$FOO", - "FOO$FOOFOO", - "FOO${FOO}$FOO", - "FOO${FOO}", - "${FOO}", - "$FOO", - "$FOO$FOO", - "${FOO}${BAR}", - "${FOO", - NULL - }; - - char **i, **r, *t, **a, **b; - const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx"; - - a = strv_parse_nulstr(nulstr, sizeof(nulstr)-1); - - STRV_FOREACH(i, a) - printf("nulstr--%s\n", *i); - - strv_free(a); - - r = replace_env_argv((char**) line, (char**) env); - - STRV_FOREACH(i, r) - printf("%s\n", *i); - - strv_free(r); - - t = normalize_env_assignment("foo=bar"); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("=bar"); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("foo="); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("="); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment(""); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("a=\"waldo\""); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("a=\"waldo"); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("a=waldo\""); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("a=\'"); - printf("%s\n", t); - free(t); - - t = normalize_env_assignment("a=\'\'"); - printf("%s\n", t); - free(t); - - a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); - b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); - - r = strv_env_merge(2, a, b); - strv_free(a); - strv_free(b); - - STRV_FOREACH(i, r) - printf("%s\n", *i); - - printf("CLEANED UP:\n"); - - r = strv_env_clean(r); - - STRV_FOREACH(i, r) - printf("%s\n", *i); - - strv_free(r); - - return 0; -} diff --git a/src/test-hostname.c b/src/test-hostname.c deleted file mode 100644 index 0a08416..0000000 --- a/src/test-hostname.c +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "hostname-setup.h" -#include "util.h" - -int main(int argc, char* argv[]) { - int r; - - if ((r = hostname_setup()) < 0) - fprintf(stderr, "hostname: %s\n", strerror(-r)); - - return 0; -} diff --git a/src/test-install.c b/src/test-install.c deleted file mode 100644 index f8e87e0..0000000 --- a/src/test-install.c +++ /dev/null @@ -1,264 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "util.h" -#include "install.h" - -static void dump_changes(UnitFileChange *c, unsigned n) { - unsigned i; - - assert(n == 0 || c); - - for (i = 0; i < n; i++) { - if (c[i].type == UNIT_FILE_UNLINK) - printf("rm '%s'\n", c[i].path); - else if (c[i].type == UNIT_FILE_SYMLINK) - printf("ln -s '%s' '%s'\n", c[i].source, c[i].path); - } -} - -int main(int argc, char* argv[]) { - Hashmap *h; - UnitFileList *p; - Iterator i; - int r; - const char *const files[] = { "avahi-daemon.service", NULL }; - const char *const files2[] = { "/home/lennart/test.service", NULL }; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - - h = hashmap_new(string_hash_func, string_compare_func); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); - assert_se(r == 0); - - HASHMAP_FOREACH(p, h, i) { - UnitFileState s; - - s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(p->path)); - - assert_se(p->state == s); - - fprintf(stderr, "%s (%s)\n", - p->path, - unit_file_state_to_string(p->state)); - } - - unit_file_list_free(h); - - log_error("enable"); - - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - - log_error("enable2"); - - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); - - log_error("disable"); - - changes = NULL; - n_changes = 0; - - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); - - log_error("mask"); - changes = NULL; - n_changes = 0; - - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - log_error("mask2"); - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); - - log_error("unmask"); - changes = NULL; - n_changes = 0; - - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - log_error("unmask2"); - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); - - log_error("mask"); - changes = NULL; - n_changes = 0; - - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); - - log_error("disable"); - changes = NULL; - n_changes = 0; - - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - log_error("disable2"); - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); - - log_error("umask"); - changes = NULL; - n_changes = 0; - - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); - - log_error("enable files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == UNIT_FILE_ENABLED); - - log_error("disable files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == _UNIT_FILE_STATE_INVALID); - - log_error("link files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == UNIT_FILE_LINKED); - - log_error("disable files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == _UNIT_FILE_STATE_INVALID); - - log_error("link files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == UNIT_FILE_LINKED); - - log_error("reenable files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == UNIT_FILE_ENABLED); - - log_error("disable files2"); - changes = NULL; - n_changes = 0; - - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files2[0])) == _UNIT_FILE_STATE_INVALID); - log_error("preset files"); - changes = NULL; - n_changes = 0; - - r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); - assert_se(r >= 0); - - dump_changes(changes, n_changes); - unit_file_changes_free(changes, n_changes); - - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, file_name_from_path(files[0])) == UNIT_FILE_ENABLED); - - return 0; -} diff --git a/src/test-job-type.c b/src/test-job-type.c deleted file mode 100644 index 9de21e1..0000000 --- a/src/test-job-type.c +++ /dev/null @@ -1,84 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "job.h" - -int main(int argc, char*argv[]) { - JobType a, b, c, d, e, f, g; - - for (a = 0; a < _JOB_TYPE_MAX; a++) - for (b = 0; b < _JOB_TYPE_MAX; b++) { - - if (!job_type_is_mergeable(a, b)) - printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b)); - - for (c = 0; c < _JOB_TYPE_MAX; c++) { - - /* Verify transitivity of mergeability - * of job types */ - assert(!job_type_is_mergeable(a, b) || - !job_type_is_mergeable(b, c) || - job_type_is_mergeable(a, c)); - - d = a; - if (job_type_merge(&d, b) >= 0) { - - printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(d)); - - /* Verify that merged entries can be - * merged with the same entries they - * can be merged with separately */ - assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(d, c)); - assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(d, c)); - - /* Verify that if a merged - * with b is not mergeable with - * c then either a or b is not - * mergeable with c either. */ - assert(job_type_is_mergeable(d, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); - - e = b; - if (job_type_merge(&e, c) >= 0) { - - /* Verify associativity */ - - f = d; - assert(job_type_merge(&f, c) == 0); - - g = e; - assert(job_type_merge(&g, a) == 0); - - assert(f == g); - - printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(d)); - } - } - } - } - - - return 0; -} diff --git a/src/test-login.c b/src/test-login.c deleted file mode 100644 index 7d6f082..0000000 --- a/src/test-login.c +++ /dev/null @@ -1,170 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "sd-login.h" -#include "util.h" -#include "strv.h" - -int main(int argc, char* argv[]) { - int r, k; - uid_t u, u2; - char *seat; - char *session; - char *state; - char *session2; - char *t; - char **seats, **sessions; - uid_t *uids; - unsigned n; - struct pollfd pollfd; - sd_login_monitor *m; - - assert_se(sd_pid_get_session(0, &session) == 0); - printf("session = %s\n", session); - - assert_se(sd_pid_get_owner_uid(0, &u2) == 0); - printf("user = %lu\n", (unsigned long) u2); - - r = sd_uid_get_sessions(u2, false, &sessions); - assert_se(r >= 0); - assert_se(r == (int) strv_length(sessions)); - assert_se(t = strv_join(sessions, ", ")); - strv_free(sessions); - printf("sessions = %s\n", t); - free(t); - - assert_se(r == sd_uid_get_sessions(u2, false, NULL)); - - r = sd_uid_get_seats(u2, false, &seats); - assert_se(r >= 0); - assert_se(r == (int) strv_length(seats)); - assert_se(t = strv_join(seats, ", ")); - strv_free(seats); - printf("seats = %s\n", t); - free(t); - - assert_se(r == sd_uid_get_seats(u2, false, NULL)); - - r = sd_session_is_active(session); - assert_se(r >= 0); - printf("active = %s\n", yes_no(r)); - - assert_se(sd_session_get_uid(session, &u) >= 0); - printf("uid = %lu\n", (unsigned long) u); - assert_se(u == u2); - - assert_se(sd_session_get_seat(session, &seat) >= 0); - printf("seat = %s\n", seat); - - r = sd_seat_can_multi_session(seat); - assert_se(r >= 0); - printf("can do multi session = %s\n", yes_no(r)); - - assert_se(sd_uid_get_state(u, &state) >= 0); - printf("state = %s\n", state); - - assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); - - k = sd_uid_is_on_seat(u, 1, seat); - assert_se(k >= 0); - assert_se(!!r == !!r); - - assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); - printf("session2 = %s\n", session2); - printf("uid2 = %lu\n", (unsigned long) u2); - - r = sd_seat_get_sessions(seat, &sessions, &uids, &n); - assert_se(r >= 0); - printf("n_sessions = %i\n", r); - assert_se(r == (int) strv_length(sessions)); - assert_se(t = strv_join(sessions, ", ")); - strv_free(sessions); - printf("sessions = %s\n", t); - free(t); - printf("uids ="); - for (k = 0; k < (int) n; k++) - printf(" %lu", (unsigned long) uids[k]); - printf("\n"); - free(uids); - - assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); - - free(session); - free(state); - free(session2); - free(seat); - - r = sd_get_seats(&seats); - assert_se(r >= 0); - assert_se(r == (int) strv_length(seats)); - assert_se(t = strv_join(seats, ", ")); - strv_free(seats); - printf("n_seats = %i\n", r); - printf("seats = %s\n", t); - free(t); - - assert_se(sd_get_seats(NULL) == r); - - r = sd_get_sessions(&sessions); - assert_se(r >= 0); - assert_se(r == (int) strv_length(sessions)); - assert_se(t = strv_join(sessions, ", ")); - strv_free(sessions); - printf("n_sessions = %i\n", r); - printf("sessions = %s\n", t); - free(t); - - assert_se(sd_get_sessions(NULL) == r); - - r = sd_get_uids(&uids); - assert_se(r >= 0); - - printf("uids ="); - for (k = 0; k < r; k++) - printf(" %lu", (unsigned long) uids[k]); - printf("\n"); - free(uids); - - printf("n_uids = %i\n", r); - assert_se(sd_get_uids(NULL) == r); - - r = sd_login_monitor_new("session", &m); - assert_se(r >= 0); - - zero(pollfd); - pollfd.fd = sd_login_monitor_get_fd(m); - pollfd.events = POLLIN; - - for (n = 0; n < 5; n++) { - r = poll(&pollfd, 1, -1); - assert_se(r >= 0); - - sd_login_monitor_flush(m); - printf("Wake!\n"); - } - - sd_login_monitor_unref(m); - - return 0; -} diff --git a/src/test-loopback.c b/src/test-loopback.c deleted file mode 100644 index 9784aaf..0000000 --- a/src/test-loopback.c +++ /dev/null @@ -1,37 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "loopback-setup.h" -#include "util.h" - -int main(int argc, char* argv[]) { - int r; - - if ((r = loopback_setup()) < 0) - fprintf(stderr, "loopback: %s\n", strerror(-r)); - - return 0; -} diff --git a/src/test-ns.c b/src/test-ns.c deleted file mode 100644 index e2bdfc5..0000000 --- a/src/test-ns.c +++ /dev/null @@ -1,60 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "namespace.h" -#include "log.h" - -int main(int argc, char *argv[]) { - const char * const writable[] = { - "/home", - NULL - }; - - const char * const readable[] = { - "/", - "/usr", - "/boot", - NULL - }; - - const char * const inaccessible[] = { - "/home/lennart/projects", - NULL - }; - - int r; - - if ((r = setup_namespace((char**) writable, (char**) readable, (char**) inaccessible, true, MS_SHARED)) < 0) { - log_error("Failed to setup namespace: %s", strerror(-r)); - return 1; - } - - execl("/bin/sh", "/bin/sh", NULL); - log_error("execl(): %m"); - - return 1; -} diff --git a/src/test-strv.c b/src/test-strv.c deleted file mode 100644 index 1d577df..0000000 --- a/src/test-strv.c +++ /dev/null @@ -1,66 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "util.h" -#include "specifier.h" - -int main(int argc, char *argv[]) { - const Specifier table[] = { - { 'a', specifier_string, (char*) "AAAA" }, - { 'b', specifier_string, (char*) "BBBB" }, - { 0, NULL, NULL } - }; - - char *w, *state; - size_t l; - const char test[] = "test a b c 'd' e '' '' hhh '' ''"; - - printf("<%s>\n", test); - - FOREACH_WORD_QUOTED(w, l, test, state) { - char *t; - - assert_se(t = strndup(w, l)); - printf("<%s>\n", t); - free(t); - } - - printf("%s\n", default_term_for_tty("/dev/tty23")); - printf("%s\n", default_term_for_tty("/dev/ttyS23")); - printf("%s\n", default_term_for_tty("/dev/tty0")); - printf("%s\n", default_term_for_tty("/dev/pty0")); - printf("%s\n", default_term_for_tty("/dev/pts/0")); - printf("%s\n", default_term_for_tty("/dev/console")); - printf("%s\n", default_term_for_tty("tty23")); - printf("%s\n", default_term_for_tty("ttyS23")); - printf("%s\n", default_term_for_tty("tty0")); - printf("%s\n", default_term_for_tty("pty0")); - printf("%s\n", default_term_for_tty("pts/0")); - printf("%s\n", default_term_for_tty("console")); - - w = specifier_printf("xxx a=%a b=%b yyy", table, NULL); - printf("<%s>\n", w); - free(w); - - return 0; -} diff --git a/src/test/Makefile b/src/test/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/test/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c new file mode 100644 index 0000000..7e171c7 --- /dev/null +++ b/src/test/test-architecture.c @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "virt.h" +#include "architecture.h" +#include "util.h" +#include "log.h" + +int main(int argc, char *argv[]) { + Architecture a; + int v; + const char *id = NULL; + + v = detect_virtualization(&id); + if (v == -EPERM || v == -EACCES) + return EXIT_TEST_SKIP; + + assert_se(v >= 0); + + log_info("virtualization=%s id=%s", + v == VIRTUALIZATION_CONTAINER ? "container" : v == VIRTUALIZATION_VM ? "vm" : "n/a", + strna(id)); + + a = uname_architecture(); + assert_se(a >= 0); + + log_info("uname architecture=%s", architecture_to_string(a)); + + a = native_architecture(); + assert_se(a >= 0); + + log_info("native architecture=%s", architecture_to_string(a)); + return 0; +} diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c new file mode 100644 index 0000000..4ede318 --- /dev/null +++ b/src/test/test-boot-timestamps.c @@ -0,0 +1,98 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "util.h" +#include "log.h" +#include "boot-timestamps.h" +#include "efivars.h" +#include "acpi-fpdt.h" + +static int test_acpi_fpdt(void) { + usec_t loader_start; + usec_t loader_exit; + char ts_start[FORMAT_TIMESPAN_MAX]; + char ts_exit[FORMAT_TIMESPAN_MAX]; + char ts_span[FORMAT_TIMESPAN_MAX]; + int r; + + r = acpi_get_boot_usec(&loader_start, &loader_exit); + if (r < 0) { + if (r != -ENOENT) + log_error("Failed to read ACPI FPDT: %s", strerror(-r)); + return r; + } + + log_info("ACPI FPDT: loader start=%s exit=%s duration=%s", + format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), + format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), + format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); + + return 0; +} + +static int test_efi_loader(void) { + usec_t loader_start; + usec_t loader_exit; + char ts_start[FORMAT_TIMESPAN_MAX]; + char ts_exit[FORMAT_TIMESPAN_MAX]; + char ts_span[FORMAT_TIMESPAN_MAX]; + int r; + + r = efi_loader_get_boot_usec(&loader_start, &loader_exit); + if (r < 0) { + if (r != -ENOENT) + log_error("Failed to read EFI loader data: %s", strerror(-r)); + return r; + } + + log_info("EFI Loader: start=%s exit=%s duration=%s", + format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), + format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), + format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); + + return 0; +} + +int main(int argc, char* argv[]) { + char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; + int r; + dual_timestamp fw, l, k; + + test_acpi_fpdt(); + test_efi_loader(); + + dual_timestamp_from_monotonic(&k, 0); + + r = boot_timestamps(NULL, &fw, &l); + if (r < 0) { + log_error("Failed to read variables: %s", strerror(-r)); + return 1; + } + + log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); + log_info("Loader began %s before kernel.", format_timespan(s, sizeof(s), l.monotonic, 0)); + log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); + log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); + log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); + + return 0; +} diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c new file mode 100644 index 0000000..21b0024 --- /dev/null +++ b/src/test/test-calendarspec.c @@ -0,0 +1,88 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "calendarspec.h" +#include "util.h" + +static void test_one(const char *input, const char *output) { + CalendarSpec *c; + _cleanup_free_ char *p = NULL, *q = NULL; + usec_t u; + char buf[FORMAT_TIMESTAMP_MAX]; + int r; + + assert_se(calendar_spec_from_string(input, &c) >= 0); + + assert_se(calendar_spec_to_string(c, &p) >= 0); + printf("\"%s\" → \"%s\"\n", input, p); + + assert_se(streq(p, output)); + + u = now(CLOCK_REALTIME); + r = calendar_spec_next_usec(c, u, &u); + printf("Next: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u)); + calendar_spec_free(c); + + assert_se(calendar_spec_from_string(p, &c) >= 0); + assert_se(calendar_spec_to_string(c, &q) >= 0); + calendar_spec_free(c); + + assert_se(streq(q, p)); +} + +int main(int argc, char* argv[]) { + CalendarSpec *c; + + test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon-Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00"); + test_one("Wed *-1", "Wed *-*-01 00:00:00"); + test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00"); + test_one("Wed, 17:48", "Wed *-*-* 17:48:00"); + test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue-Sat 2012-10-15 01:02:03"); + test_one("*-*-7 0:0:0", "*-*-07 00:00:00"); + test_one("10-15", "*-10-15 00:00:00"); + test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00"); + test_one("Mon,Fri *-*-3,1,2 *:30:45", "Mon,Fri *-*-01,02,03 *:30:45"); + test_one("12,14,13,12:20,10,30", "*-*-* 12,13,14:10,20,30:00"); + test_one("mon,fri *-1/2-1,3 *:30:45", "Mon,Fri *-01/2-01,03 *:30:45"); + test_one("03-05 08:05:40", "*-03-05 08:05:40"); + test_one("08:05:40", "*-*-* 08:05:40"); + test_one("05:40", "*-*-* 05:40:00"); + test_one("Sat,Sun 12-05 08:05:40", "Sat,Sun *-12-05 08:05:40"); + test_one("Sat,Sun 08:05:40", "Sat,Sun *-*-* 08:05:40"); + test_one("2003-03-05 05:40", "2003-03-05 05:40:00"); + test_one("2003-03-05", "2003-03-05 00:00:00"); + test_one("03-05", "*-03-05 00:00:00"); + test_one("hourly", "*-*-* *:00:00"); + test_one("daily", "*-*-* 00:00:00"); + test_one("monthly", "*-*-01 00:00:00"); + test_one("weekly", "Mon *-*-* 00:00:00"); + test_one("*:2/3", "*-*-* *:02/3:00"); + + assert_se(calendar_spec_from_string("test", &c) < 0); + assert_se(calendar_spec_from_string("", &c) < 0); + assert_se(calendar_spec_from_string("7", &c) < 0); + assert_se(calendar_spec_from_string("121212:1:2", &c) < 0); + + return 0; +} diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c new file mode 100644 index 0000000..4d60859 --- /dev/null +++ b/src/test/test-cgroup-mask.c @@ -0,0 +1,110 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 David Strauss + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "manager.h" +#include "unit.h" +#include "util.h" +#include "macro.h" +#include "test-helper.h" + +static int test_cgroup_mask(void) { + Manager *m = NULL; + Unit *son, *daughter, *parent, *root, *grandchild, *parent_deep; + FILE *serial = NULL; + FDSet *fdset = NULL; + int r; + const char *dir = TEST_DIR; + + /* Prepare the manager. */ + assert_se(set_unit_path(dir) >= 0); + r = manager_new(SYSTEMD_USER, &m); + if (r == -EPERM || r == -EACCES) { + puts("manager_new: Permission denied. Skipping test."); + return EXIT_TEST_SKIP; + } + assert(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + + /* Load units and verify hierarchy. */ + assert_se(manager_load_unit(m, "parent.slice", NULL, NULL, &parent) >= 0); + assert_se(manager_load_unit(m, "son.service", NULL, NULL, &son) >= 0); + assert_se(manager_load_unit(m, "daughter.service", NULL, NULL, &daughter) >= 0); + assert_se(manager_load_unit(m, "grandchild.service", NULL, NULL, &grandchild) >= 0); + assert_se(manager_load_unit(m, "parent-deep.slice", NULL, NULL, &parent_deep) >= 0); + assert(parent->load_state == UNIT_LOADED); + assert(son->load_state == UNIT_LOADED); + assert(daughter->load_state == UNIT_LOADED); + assert(grandchild->load_state == UNIT_LOADED); + assert(parent_deep->load_state == UNIT_LOADED); + assert(UNIT_DEREF(son->slice) == parent); + assert(UNIT_DEREF(daughter->slice) == parent); + assert(UNIT_DEREF(parent_deep->slice) == parent); + assert(UNIT_DEREF(grandchild->slice) == parent_deep); + root = UNIT_DEREF(parent->slice); + + /* Verify per-unit cgroups settings. */ + assert(unit_get_cgroup_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_cgroup_mask(daughter) == 0); + assert(unit_get_cgroup_mask(grandchild) == 0); + assert(unit_get_cgroup_mask(parent_deep) == CGROUP_MEMORY); + assert(unit_get_cgroup_mask(parent) == CGROUP_BLKIO); + assert(unit_get_cgroup_mask(root) == 0); + + /* Verify aggregation of member masks */ + assert(unit_get_members_mask(son) == 0); + assert(unit_get_members_mask(daughter) == 0); + assert(unit_get_members_mask(grandchild) == 0); + assert(unit_get_members_mask(parent_deep) == 0); + assert(unit_get_members_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); + assert(unit_get_members_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + + /* Verify aggregation of sibling masks. */ + assert(unit_get_siblings_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_siblings_mask(daughter) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_siblings_mask(grandchild) == 0); + assert(unit_get_siblings_mask(parent_deep) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_siblings_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO)); + assert(unit_get_siblings_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO)); + + /* Verify aggregation of target masks. */ + assert(unit_get_target_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_target_mask(daughter) == (CGROUP_CPU | CGROUP_CPUACCT)); + assert(unit_get_target_mask(grandchild) == 0); + assert(unit_get_target_mask(parent_deep) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); + assert(unit_get_target_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + assert(unit_get_target_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + + manager_free(m); + + return 0; +} + +int main(int argc, char* argv[]) { + int rc = 0; + TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); + return rc; +} diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c new file mode 100644 index 0000000..b37468b --- /dev/null +++ b/src/test/test-cgroup-util.c @@ -0,0 +1,263 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "cgroup-util.h" +#include "test-helper.h" + +static void check_p_d_u(const char *path, int code, const char *result) { + _cleanup_free_ char *unit = NULL; + int r; + + r = cg_path_decode_unit(path, &unit); + printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); + assert_se(r == code); + assert_se(streq_ptr(unit, result)); +} + +static void test_path_decode_unit(void) { + check_p_d_u("getty@tty2.service", 0, "getty@tty2.service"); + check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service"); + check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service"); + check_p_d_u("getty@.service/", -EINVAL, NULL); + check_p_d_u("getty@.service", -EINVAL, NULL); + check_p_d_u("getty.service", 0, "getty.service"); + check_p_d_u("getty", -EINVAL, NULL); + check_p_d_u("getty/waldo", -EINVAL, NULL); + check_p_d_u("_cpu.service", 0, "cpu.service"); +} + +static void check_p_g_u(const char *path, int code, const char *result) { + _cleanup_free_ char *unit = NULL; + int r; + + r = cg_path_get_unit(path, &unit); + printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); + assert_se(r == code); + assert_se(streq_ptr(unit, result)); +} + +static void test_path_get_unit(void) { + check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service"); + check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service"); + check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service"); + check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service"); + check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service"); + check_p_g_u("sadfdsafsda", -EINVAL, NULL); + check_p_g_u("/system.slice/getty####@tty6.service/xxx", -EINVAL, NULL); + check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service"); + check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service"); + check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service"); + check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -EINVAL, NULL); +} + +static void check_p_g_u_u(const char *path, int code, const char *result) { + _cleanup_free_ char *unit = NULL; + int r; + + r = cg_path_get_user_unit(path, &unit); + printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code); + assert_se(r == code); + assert_se(streq_ptr(unit, result)); +} + +static void test_path_get_user_unit(void) { + check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service"); + check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service"); + check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service"); + check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service"); + check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -EINVAL, NULL); + check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service"); + check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service"); + check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service"); + check_p_g_u_u("/meh.service", -ENOENT, NULL); + check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service"); + check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service"); + check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENOENT, NULL); +} + +static void check_p_g_s(const char *path, int code, const char *result) { + _cleanup_free_ char *s = NULL; + + assert_se(cg_path_get_session(path, &s) == code); + assert_se(streq_ptr(s, result)); +} + +static void test_path_get_session(void) { + check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2"); + check_p_g_s("/session-3.scope", 0, "3"); + check_p_g_s("", -ENOENT, 0); +} + +static void check_p_g_o_u(const char *path, int code, uid_t result) { + uid_t uid = 0; + + assert_se(cg_path_get_owner_uid(path, &uid) == code); + assert_se(uid == result); +} + +static void test_path_get_owner_uid(void) { + check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000); + check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006); + check_p_g_o_u("", -ENOENT, 0); +} + +static void test_get_paths(void) { + _cleanup_free_ char *a = NULL; + + assert_se(cg_get_root_path(&a) >= 0); + log_info("Root = %s", a); +} + +static void test_proc(void) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r; + + d = opendir("/proc"); + assert_se(d); + + FOREACH_DIRENT(de, d, break) { + _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL; + pid_t pid; + uid_t uid = (uid_t) -1; + + if (de->d_type != DT_DIR && + de->d_type != DT_UNKNOWN) + continue; + + r = parse_pid(de->d_name, &pid); + if (r < 0) + continue; + + if (is_kernel_thread(pid)) + continue; + + cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path); + cg_pid_get_path_shifted(pid, NULL, &path_shifted); + cg_pid_get_owner_uid(pid, &uid); + cg_pid_get_session(pid, &session); + cg_pid_get_unit(pid, &unit); + cg_pid_get_user_unit(pid, &user_unit); + cg_pid_get_machine_name(pid, &machine); + cg_pid_get_slice(pid, &slice); + + printf("%lu\t%s\t%s\t%lu\t%s\t%s\t%s\t%s\t%s\n", + (unsigned long) pid, + path, + path_shifted, + (unsigned long) uid, + session, + unit, + user_unit, + machine, + slice); + } +} + +static void test_escape_one(const char *s, const char *r) { + _cleanup_free_ char *b; + + b = cg_escape(s); + assert_se(b); + assert_se(streq(b, r)); + + assert_se(streq(cg_unescape(b), s)); +} + +static void test_escape(void) { + test_escape_one("foobar", "foobar"); + test_escape_one(".foobar", "_.foobar"); + test_escape_one("foobar.service", "foobar.service"); + test_escape_one("cgroup.service", "_cgroup.service"); + test_escape_one("tasks", "_tasks"); + if (access("/sys/fs/cgroup/cpu", F_OK) == 0) + test_escape_one("cpu.service", "_cpu.service"); + test_escape_one("_foobar", "__foobar"); + test_escape_one("", "_"); + test_escape_one("_", "__"); + test_escape_one(".", "_."); +} + +static void test_controller_is_valid(void) { + assert_se(cg_controller_is_valid("foobar", false)); + assert_se(cg_controller_is_valid("foo_bar", false)); + assert_se(cg_controller_is_valid("name=foo", true)); + assert_se(!cg_controller_is_valid("", false)); + assert_se(!cg_controller_is_valid("name=", true)); + assert_se(!cg_controller_is_valid("=", false)); + assert_se(!cg_controller_is_valid("cpu,cpuacct", false)); + assert_se(!cg_controller_is_valid("_", false)); + assert_se(!cg_controller_is_valid("_foobar", false)); + assert_se(!cg_controller_is_valid("tatü", false)); +} + +static void test_slice_to_path_one(const char *unit, const char *path, int error) { + _cleanup_free_ char *ret = NULL; + + assert_se(cg_slice_to_path(unit, &ret) == error); + assert_se(streq_ptr(ret, path)); +} + +static void test_slice_to_path(void) { + + test_slice_to_path_one("foobar.slice", "foobar.slice", 0); + test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0); + test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL); + test_slice_to_path_one("-.slice", NULL, -EINVAL); + test_slice_to_path_one("-foo-.slice", NULL, -EINVAL); + test_slice_to_path_one("-foo.slice", NULL, -EINVAL); + test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0); + test_slice_to_path_one("a-b-c-d-e.slice", "a.slice/a-b.slice/a-b-c.slice/a-b-c-d.slice/a-b-c-d-e.slice", 0); +} + +static void test_shift_path_one(const char *raw, const char *root, const char *shifted) { + const char *s = NULL; + + assert_se(cg_shift_path(raw, root, &s) >= 0); + assert_se(streq(s, shifted)); +} + +static void test_shift_path(void) { + + test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo"); + test_shift_path_one("/foobar/waldo", "", "/foobar/waldo"); + test_shift_path_one("/foobar/waldo", "/foobar", "/waldo"); + test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo"); +} + +int main(void) { + test_path_decode_unit(); + test_path_get_unit(); + test_path_get_user_unit(); + test_path_get_session(); + test_path_get_owner_uid(); + TEST_REQ_RUNNING_SYSTEMD(test_get_paths()); + test_proc(); + TEST_REQ_RUNNING_SYSTEMD(test_escape()); + test_controller_is_valid(); + test_slice_to_path(); + test_shift_path(); + + return 0; +} diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c new file mode 100644 index 0000000..2a0ce27 --- /dev/null +++ b/src/test/test-cgroup.c @@ -0,0 +1,105 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "cgroup-util.h" +#include "path-util.h" +#include "util.h" +#include "log.h" + +int main(int argc, char*argv[]) { + char *path; + char *c, *p; + + assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); + assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); + assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0); + assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c") == 0); + assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0); + + assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); + assert_se(streq(path, "/test-b")); + free(path); + + assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0); + + assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); + assert_se(path_equal(path, "/test-a")); + free(path); + + assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0); + + assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); + assert_se(path_equal(path, "/test-b/test-d")); + free(path); + + assert_se(cg_get_path(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", NULL, &path) == 0); + assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d")); + free(path); + + assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); + assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0); + + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0); + + assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0); + + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); + + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0); + + cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false); + + assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0); + assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); + + assert_se(cg_split_spec("foobar:/", &c, &p) == 0); + assert(streq(c, "foobar")); + assert(streq(p, "/")); + free(c); + free(p); + + assert_se(cg_split_spec("foobar:", &c, &p) < 0); + assert_se(cg_split_spec("foobar:asdfd", &c, &p) < 0); + assert_se(cg_split_spec(":///", &c, &p) < 0); + assert_se(cg_split_spec(":", &c, &p) < 0); + assert_se(cg_split_spec("", &c, &p) < 0); + assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0); + + assert_se(cg_split_spec("/", &c, &p) >= 0); + assert(c == NULL); + assert(streq(p, "/")); + free(p); + + assert_se(cg_split_spec("foo", &c, &p) >= 0); + assert(streq(c, "foo")); + assert(p == NULL); + free(c); + + return 0; +} diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c new file mode 100644 index 0000000..3215f0c --- /dev/null +++ b/src/test/test-daemon.c @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include + +int main(int argc, char*argv[]) { + + sd_notify(0, "STATUS=Starting up"); + sleep(5); + sd_notify(0, + "STATUS=Running\n" + "READY=1"); + sleep(10); + sd_notify(0, "STATUS=Quitting"); + + return 0; +} diff --git a/src/test/test-date.c b/src/test/test-date.c new file mode 100644 index 0000000..40ffc17 --- /dev/null +++ b/src/test/test-date.c @@ -0,0 +1,61 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" + +static void test_one(const char *p) { + usec_t t, q; + char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; + + assert_se(parse_timestamp(p, &t) >= 0); + log_info("%s", format_timestamp(buf, sizeof(buf), t)); + + /* Chop off timezone */ + *strrchr(buf, ' ') = 0; + + assert_se(parse_timestamp(buf, &q) >= 0); + assert_se(q == t); + + log_info("%s", strna(format_timestamp_relative(buf_relative, sizeof(buf_relative), t))); + assert_se(parse_timestamp(buf, &q) >= 0); +} + +int main(int argc, char *argv[]) { + test_one("17:41"); + test_one("18:42:44"); + test_one("12-10-02 12:13:14"); + test_one("12-10-2 12:13:14"); + test_one("12-10-03 12:13"); + test_one("2012-12-30 18:42"); + test_one("2012-10-02"); + test_one("Tue 2012-10-02"); + test_one("now"); + test_one("yesterday"); + test_one("today"); + test_one("tomorrow"); + test_one("+2d"); + test_one("+2y 4d"); + test_one("5months ago"); + + return 0; +} diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c new file mode 100644 index 0000000..59ba4be --- /dev/null +++ b/src/test/test-device-nodes.c @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Dave Reisner + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "device-nodes.h" +#include "util.h" + +/* helpers for test_encode_devnode_name */ +static char *do_encode_string(const char *in) { + size_t out_len = strlen(in) * 4 + 1; + char *out = malloc(out_len); + + assert_se(out); + assert_se(encode_devnode_name(in, out, out_len) >= 0); + puts(out); + + return out; +} + +static bool expect_encoded_as(const char *in, const char *expected) { + _cleanup_free_ char *encoded = do_encode_string(in); + return streq(encoded, expected); +} + +static void test_encode_devnode_name(void) { + assert_se(expect_encoded_as("systemd sucks", "systemd\\x20sucks")); + assert_se(expect_encoded_as("pinkiepie", "pinkiepie")); + assert_se(expect_encoded_as("valíd\\ųtf8", "valíd\\x5cųtf8")); + assert_se(expect_encoded_as("s/ash/ng", "s\\x2fash\\x2fng")); + assert_se(expect_encoded_as("/", "\\x2f")); + assert_se(expect_encoded_as("!", "\\x21")); +} + +int main(int argc, char *argv[]) { + test_encode_devnode_name(); + + return 0; +} diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c new file mode 100644 index 0000000..f97c78e --- /dev/null +++ b/src/test/test-ellipsize.c @@ -0,0 +1,45 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Shawn Landden + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "utf8.h" +#include "def.h" + +static void test_one(const char *p) { + _cleanup_free_ char *t; + t = ellipsize(p, columns(), 70); + puts(t); +} + +int main(int argc, char *argv[]) { + test_one(DIGITS LETTERS DIGITS LETTERS); + test_one("한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어한국어"); + test_one("-日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国日本国"); + test_one("中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国-中国中国中国中国中国中国中国中国中国中国中国中国中国"); + test_one("sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd sÿstëmd"); + test_one("🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮🐮"); + test_one("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); + test_one("shórt"); + + return 0; +} diff --git a/src/test/test-engine.c b/src/test/test-engine.c new file mode 100644 index 0000000..0f38622 --- /dev/null +++ b/src/test/test-engine.c @@ -0,0 +1,99 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "manager.h" + +int main(int argc, char *argv[]) { + Manager *m = NULL; + Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; + Job *j; + + assert_se(set_unit_path("test") >= 0); + + assert_se(manager_new(SYSTEMD_SYSTEM, &m) >= 0); + + printf("Load1:\n"); + assert_se(manager_load_unit(m, "a.service", NULL, NULL, &a) >= 0); + assert_se(manager_load_unit(m, "b.service", NULL, NULL, &b) >= 0); + assert_se(manager_load_unit(m, "c.service", NULL, NULL, &c) >= 0); + manager_dump_units(m, stdout, "\t"); + + printf("Test1: (Trivial)\n"); + assert_se(manager_add_job(m, JOB_START, c, JOB_REPLACE, false, NULL, &j) == 0); + manager_dump_jobs(m, stdout, "\t"); + + printf("Load2:\n"); + manager_clear_jobs(m); + assert_se(manager_load_unit(m, "d.service", NULL, NULL, &d) >= 0); + assert_se(manager_load_unit(m, "e.service", NULL, NULL, &e) >= 0); + manager_dump_units(m, stdout, "\t"); + + printf("Test2: (Cyclic Order, Unfixable)\n"); + assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -ENOEXEC); + 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, false, 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, false, NULL, &j) == 0); + manager_dump_jobs(m, stdout, "\t"); + + printf("Load3:\n"); + assert_se(manager_load_unit(m, "g.service", NULL, NULL, &g) >= 0); + manager_dump_units(m, stdout, "\t"); + + printf("Test5: (Colliding transaction, fail)\n"); + assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EEXIST); + + printf("Test6: (Colliding transaction, replace)\n"); + assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, 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, false, NULL, &j) == -EEXIST); + + printf("Test8: (Mergeable job type, fail)\n"); + assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, 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, false, NULL, &j) == 0); + manager_dump_jobs(m, stdout, "\t"); + + printf("Load4:\n"); + assert_se(manager_load_unit(m, "h.service", NULL, NULL, &h) >= 0); + 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, false, NULL, &j) == 0); + manager_dump_jobs(m, stdout, "\t"); + + manager_free(m); + + return 0; +} diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c new file mode 100644 index 0000000..0274e97 --- /dev/null +++ b/src/test/test-env-replace.c @@ -0,0 +1,218 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "util.h" +#include "strv.h" +#include "env-util.h" + +static void test_strv_env_delete(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + assert_se(a); + + b = strv_new("PIEP", "FOO", NULL); + assert_se(b); + + c = strv_new("SCHLUMPF", NULL); + assert_se(c); + + d = strv_env_delete(a, 2, b, c); + assert_se(d); + + assert_se(streq(d[0], "WALDO=WALDO")); + assert_se(streq(d[1], "WALDO=")); + assert_se(strv_length(d) == 2); +} + +static void test_strv_env_unset(void) { + _cleanup_strv_free_ char **l = NULL; + + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(l); + + assert_se(strv_env_unset(l, "SCHLUMPF") == l); + + assert_se(streq(l[0], "PIEP")); + assert_se(streq(l[1], "NANANANA=YES")); + assert_se(strv_length(l) == 2); +} + +static void test_strv_env_set(void) { + _cleanup_strv_free_ char **l = NULL, **r = NULL; + + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(l); + + r = strv_env_set(l, "WALDO=WALDO"); + assert_se(r); + + assert_se(streq(r[0], "PIEP")); + assert_se(streq(r[1], "SCHLUMPF=SMURFF")); + assert_se(streq(r[2], "NANANANA=YES")); + assert_se(streq(r[3], "WALDO=WALDO")); + assert_se(strv_length(r) == 4); +} + +static void test_strv_env_merge(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL; + + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + assert_se(a); + + b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(b); + + r = strv_env_merge(2, a, b); + assert_se(r); + assert_se(streq(r[0], "FOO=")); + assert_se(streq(r[1], "WALDO=")); + assert_se(streq(r[2], "PIEP")); + assert_se(streq(r[3], "SCHLUMPF=SMURFF")); + assert_se(streq(r[4], "PIEP=")); + assert_se(streq(r[5], "NANANANA=YES")); + assert_se(strv_length(r) == 6); + + assert_se(strv_env_clean(r) == r); + assert_se(streq(r[0], "FOO=")); + assert_se(streq(r[1], "WALDO=")); + assert_se(streq(r[2], "SCHLUMPF=SMURFF")); + assert_se(streq(r[3], "PIEP=")); + assert_se(streq(r[4], "NANANANA=YES")); + assert_se(strv_length(r) == 5); +} + +static void test_replace_env_arg(void) { + const char *env[] = { + "FOO=BAR BAR", + "BAR=waldo", + NULL + }; + const char *line[] = { + "FOO$FOO", + "FOO$FOOFOO", + "FOO${FOO}$FOO", + "FOO${FOO}", + "${FOO}", + "$FOO", + "$FOO$FOO", + "${FOO}${BAR}", + "${FOO", + NULL + }; + _cleanup_strv_free_ char **r = NULL; + + r = replace_env_argv((char**) line, (char**) env); + assert_se(r); + assert_se(streq(r[0], "FOO$FOO")); + assert_se(streq(r[1], "FOO$FOOFOO")); + assert_se(streq(r[2], "FOOBAR BAR$FOO")); + assert_se(streq(r[3], "FOOBAR BAR")); + assert_se(streq(r[4], "BAR BAR")); + assert_se(streq(r[5], "BAR")); + assert_se(streq(r[6], "BAR")); + assert_se(streq(r[7], "BAR BARwaldo")); + assert_se(streq(r[8], "${FOO")); + assert_se(strv_length(r) == 9); +} + +static void test_one_normalize(const char *input, const char *output) { + _cleanup_free_ char *t; + + t = normalize_env_assignment(input); + assert_se(t); + assert_se(streq(t, output)); +} + +static void test_normalize_env_assignment(void) { + test_one_normalize("foo=bar", "foo=bar"); + test_one_normalize("=bar", "=bar"); + test_one_normalize("foo=", "foo="); + test_one_normalize("=", "="); + test_one_normalize("", ""); + test_one_normalize("a=\"waldo\"", "a=waldo"); + test_one_normalize("a=\"waldo", "a=\"waldo"); + test_one_normalize("a=waldo\"", "a=waldo\""); + test_one_normalize("a=\'", "a='"); + test_one_normalize("a=\'\'", "a="); + test_one_normalize(" xyz ", "xyz"); + test_one_normalize(" xyz = bar ", "xyz=bar"); + test_one_normalize(" xyz = 'bar ' ", "xyz=bar "); + test_one_normalize(" ' xyz' = 'bar ' ", "' xyz'=bar "); +} + +static void test_env_clean(void) { + _cleanup_strv_free_ char **e; + + e = strv_new("FOOBAR=WALDO", + "FOOBAR=WALDO", + "FOOBAR", + "F", + "X=", + "F=F", + "=", + "=F", + "", + "0000=000", + "äöüß=abcd", + "abcd=äöüß", + "xyz\n=xyz", + "xyz=xyz\n", + "another=one", + "another=final one", + NULL); + assert_se(e); + assert_se(!strv_env_is_valid(e)); + assert_se(strv_env_clean(e) == e); + assert_se(strv_env_is_valid(e)); + + assert_se(streq(e[0], "FOOBAR=WALDO")); + assert_se(streq(e[1], "X=")); + assert_se(streq(e[2], "F=F")); + assert_se(streq(e[3], "abcd=äöüß")); + assert_se(streq(e[4], "another=final one")); + assert_se(e[5] == NULL); +} + +static void test_env_name_is_valid(void) { + assert_se(env_name_is_valid("test")); + + assert_se(!env_name_is_valid(NULL)); + assert_se(!env_name_is_valid("")); + assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); + assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); +} + +int main(int argc, char *argv[]) { + test_strv_env_delete(); + test_strv_env_unset(); + test_strv_env_set(); + test_strv_env_merge(); + test_replace_env_arg(); + test_normalize_env_assignment(); + test_env_clean(); + test_env_name_is_valid(); + + return 0; +} diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c new file mode 100644 index 0000000..47a0907 --- /dev/null +++ b/src/test/test-fileio.c @@ -0,0 +1,304 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "fileio.h" +#include "strv.h" +#include "env-util.h" +#include "def.h" +#include "ctype.h" + +static void test_parse_env_file(void) { + char t[] = "/tmp/test-fileio-in-XXXXXX", + p[] = "/tmp/test-fileio-out-XXXXXX"; + int fd, r; + FILE *f; + _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL, + *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL; + _cleanup_strv_free_ char **a = NULL, **b = NULL; + char **i; + unsigned k; + + fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + f = fdopen(fd, "w"); + assert_se(f); + + fputs("one=BAR \n" + "# comment\n" + " # comment \n" + " ; comment \n" + " two = bar \n" + "invalid line\n" + "invalid line #comment\n" + "three = \"333\n" + "xxxx\"\n" + "four = \'44\\\"44\'\n" + "five = \'55\\\'55\' \"FIVE\" cinco \n" + "six = seis sechs\\\n" + " sis\n" + "seven=\"sevenval\" #nocomment\n" + "eight=eightval #nocomment\n" + "export nine=nineval\n" + "ten=", f); + + fflush(f); + fclose(f); + + r = load_env_file(t, NULL, &a); + assert_se(r >= 0); + + STRV_FOREACH(i, a) + log_info("Got: <%s>", *i); + + assert_se(streq_ptr(a[0], "one=BAR")); + assert_se(streq_ptr(a[1], "two=bar")); + assert_se(streq_ptr(a[2], "three=333\nxxxx")); + assert_se(streq_ptr(a[3], "four=44\"44")); + assert_se(streq_ptr(a[4], "five=55\'55FIVEcinco")); + assert_se(streq_ptr(a[5], "six=seis sechs sis")); + assert_se(streq_ptr(a[6], "seven=sevenval#nocomment")); + assert_se(streq_ptr(a[7], "eight=eightval #nocomment")); + assert_se(streq_ptr(a[8], "export nine=nineval")); + assert_se(streq_ptr(a[9], "ten=")); + assert_se(a[10] == NULL); + + strv_env_clean_log(a, "test"); + + k = 0; + STRV_FOREACH(i, b) { + log_info("Got2: <%s>", *i); + assert_se(streq(*i, a[k++])); + } + + r = parse_env_file( + t, NULL, + "one", &one, + "two", &two, + "three", &three, + "four", &four, + "five", &five, + "six", &six, + "seven", &seven, + "eight", &eight, + "export nine", &nine, + "ten", &ten, + NULL); + + assert_se(r >= 0); + + log_info("one=[%s]", strna(one)); + log_info("two=[%s]", strna(two)); + log_info("three=[%s]", strna(three)); + log_info("four=[%s]", strna(four)); + log_info("five=[%s]", strna(five)); + log_info("six=[%s]", strna(six)); + log_info("seven=[%s]", strna(seven)); + log_info("eight=[%s]", strna(eight)); + log_info("export nine=[%s]", strna(nine)); + log_info("ten=[%s]", strna(nine)); + + assert_se(streq(one, "BAR")); + assert_se(streq(two, "bar")); + assert_se(streq(three, "333\nxxxx")); + assert_se(streq(four, "44\"44")); + assert_se(streq(five, "55\'55FIVEcinco")); + assert_se(streq(six, "seis sechs sis")); + assert_se(streq(seven, "sevenval#nocomment")); + assert_se(streq(eight, "eightval #nocomment")); + assert_se(streq(nine, "nineval")); + assert_se(ten == NULL); + + r = write_env_file(p, a); + assert_se(r >= 0); + + r = load_env_file(p, NULL, &b); + assert_se(r >= 0); + + unlink(t); + unlink(p); +} + +static void test_parse_multiline_env_file(void) { + char t[] = "/tmp/test-fileio-in-XXXXXX", + p[] = "/tmp/test-fileio-out-XXXXXX"; + int fd, r; + FILE *f; + _cleanup_strv_free_ char **a = NULL, **b = NULL; + char **i; + + fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + f = fdopen(fd, "w"); + assert_se(f); + + fputs("one=BAR\\\n" + " VAR\\\n" + "\tGAR\n" + "#comment\n" + "two=\"bar\\\n" + " var\\\n" + "\tgar\"\n" + "#comment\n" + "tri=\"bar \\\n" + " var \\\n" + "\tgar \"\n", f); + + fflush(f); + fclose(f); + + r = load_env_file(t, NULL, &a); + assert_se(r >= 0); + + STRV_FOREACH(i, a) + log_info("Got: <%s>", *i); + + assert_se(streq_ptr(a[0], "one=BAR VAR\tGAR")); + assert_se(streq_ptr(a[1], "two=bar var\tgar")); + assert_se(streq_ptr(a[2], "tri=bar var \tgar ")); + assert_se(a[3] == NULL); + + r = write_env_file(p, a); + assert_se(r >= 0); + + r = load_env_file(p, NULL, &b); + assert_se(r >= 0); + + unlink(t); + unlink(p); +} + + +static void test_executable_is_script(void) { + char t[] = "/tmp/test-executable-XXXXXX"; + int fd, r; + FILE *f; + char *command; + + fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + f = fdopen(fd, "w"); + assert_se(f); + + fputs("#! /bin/script -a -b \ngoo goo", f); + fflush(f); + + r = executable_is_script(t, &command); + assert_se(r > 0); + assert_se(streq(command, "/bin/script")); + free(command); + + r = executable_is_script("/bin/sh", &command); + assert_se(r == 0); + + r = executable_is_script("/usr/bin/yum", &command); + assert_se(r > 0 || r == -ENOENT); + if (r > 0) { + assert_se(startswith(command, "/")); + free(command); + } + + fclose(f); + unlink(t); +} + +static void test_status_field(void) { + _cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL; + unsigned long long total = 0, buffers = 0; + int r; + + assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0); + puts(t); + assert_se(streq(t, "1")); + + r = get_status_field("/proc/meminfo", "MemTotal:", &p); + if (r != -ENOENT) { + assert(r == 0); + puts(p); + assert_se(safe_atollu(p, &total) == 0); + } + + r = get_status_field("/proc/meminfo", "\nBuffers:", &s); + if (r != -ENOENT) { + assert(r == 0); + puts(s); + assert_se(safe_atollu(s, &buffers) == 0); + } + + if (p && t) + assert(buffers < total); + + /* Seccomp should be a good test for field full of zeros. */ + r = get_status_field("/proc/meminfo", "\nSeccomp:", &z); + if (r != -ENOENT) { + assert(r == 0); + puts(z); + assert_se(safe_atollu(z, &buffers) == 0); + } +} + +static void test_capeff(void) { + int pid, p; + + for (pid = 0; pid < 2; pid++) { + _cleanup_free_ char *capeff = NULL; + int r; + + r = get_process_capeff(0, &capeff); + log_info("capeff: '%s' (r=%d)", capeff, r); + + if (r == -ENOENT || r == -EPERM) + return; + + assert(r == 0); + assert(*capeff); + p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")]; + assert(!p || isspace(p)); + } +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_parse_env_file(); + test_parse_multiline_env_file(); + test_executable_is_script(); + test_status_field(); + test_capeff(); + + return 0; +} diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c new file mode 100644 index 0000000..56a9b58 --- /dev/null +++ b/src/test/test-hashmap.c @@ -0,0 +1,534 @@ +/*** + This file is part of systemd + + Copyright 2013 Daniel Buch + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include "strv.h" +#include "util.h" +#include "hashmap.h" + +static void test_hashmap_replace(void) { + Hashmap *m; + char *val1, *val2, *val3, *val4, *val5, *r; + + m = hashmap_new(string_hash_func, string_compare_func); + + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); + assert_se(val2); + val3 = strdup("val3"); + assert_se(val3); + val4 = strdup("val4"); + assert_se(val4); + val5 = strdup("val5"); + assert_se(val5); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); + hashmap_put(m, "key 3", val3); + hashmap_put(m, "key 4", val4); + + hashmap_replace(m, "key 3", val1); + r = hashmap_get(m, "key 3"); + assert_se(streq(r, "val1")); + + hashmap_replace(m, "key 5", val5); + r = hashmap_get(m, "key 5"); + assert_se(streq(r, "val5")); + + free(val1); + free(val2); + free(val3); + free(val4); + free(val5); + hashmap_free(m); +} + +static void test_hashmap_copy(void) { + Hashmap *m, *copy; + char *val1, *val2, *val3, *val4, *r; + + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); + assert_se(val2); + val3 = strdup("val3"); + assert_se(val3); + val4 = strdup("val4"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); + hashmap_put(m, "key 3", val3); + hashmap_put(m, "key 4", val4); + + copy = hashmap_copy(m); + + r = hashmap_get(copy, "key 1"); + assert_se(streq(r, "val1")); + r = hashmap_get(copy, "key 2"); + assert_se(streq(r, "val2")); + r = hashmap_get(copy, "key 3"); + assert_se(streq(r, "val3")); + r = hashmap_get(copy, "key 4"); + assert_se(streq(r, "val4")); + + hashmap_free_free(copy); + hashmap_free(m); +} + +static void test_hashmap_get_strv(void) { + Hashmap *m; + char **strv; + char *val1, *val2, *val3, *val4; + + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); + assert_se(val2); + val3 = strdup("val3"); + assert_se(val3); + val4 = strdup("val4"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); + hashmap_put(m, "key 3", val3); + hashmap_put(m, "key 4", val4); + + strv = hashmap_get_strv(m); + + assert_se(streq(strv[0], "val1")); + assert_se(streq(strv[1], "val2")); + assert_se(streq(strv[2], "val3")); + assert_se(streq(strv[3], "val4")); + + strv_free(strv); + + hashmap_free(m); +} + +static void test_hashmap_move_one(void) { + Hashmap *m, *n; + char *val1, *val2, *val3, *val4, *r; + + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); + assert_se(val2); + val3 = strdup("val3"); + assert_se(val3); + val4 = strdup("val4"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + n = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); + hashmap_put(m, "key 3", val3); + hashmap_put(m, "key 4", val4); + + hashmap_move_one(n, m, "key 3"); + hashmap_move_one(n, m, "key 4"); + + r = hashmap_get(n, "key 3"); + assert_se(r && streq(r, "val3")); + r = hashmap_get(n, "key 4"); + assert_se(r && streq(r, "val4")); + r = hashmap_get(m, "key 3"); + assert_se(!r); + + + hashmap_free_free(m); + hashmap_free_free(n); +} + +static void test_hashmap_next(void) { + Hashmap *m; + char *val1, *val2, *val3, *val4, *r; + + m = hashmap_new(string_hash_func, string_compare_func); + val1 = strdup("val1"); + assert_se(val1); + val2 = strdup("val2"); + assert_se(val2); + val3 = strdup("val3"); + assert_se(val3); + val4 = strdup("val4"); + assert_se(val4); + + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); + hashmap_put(m, "key 3", val3); + hashmap_put(m, "key 4", val4); + + r = hashmap_next(m, "key 1"); + assert_se(streq(r, val2)); + r = hashmap_next(m, "key 2"); + assert_se(streq(r, val3)); + r = hashmap_next(m, "key 3"); + assert_se(streq(r, val4)); + r = hashmap_next(m, "key 4"); + assert_se(!r); + + hashmap_free_free(m); +} + +static void test_hashmap_update(void) { + Hashmap *m; + char *val1, *val2, *r; + + m = hashmap_new(string_hash_func, string_compare_func); + val1 = strdup("old_value"); + assert_se(val1); + val2 = strdup("new_value"); + assert_se(val2); + + hashmap_put(m, "key 1", val1); + r = hashmap_get(m, "key 1"); + assert_se(streq(r, "old_value")); + + hashmap_update(m, "key 1", val2); + r = hashmap_get(m, "key 1"); + assert_se(streq(r, "new_value")); + + free(val1); + free(val2); + hashmap_free(m); +} + +static void test_hashmap_put(void) { + Hashmap *m; + int valid_hashmap_put; + + m = hashmap_new(string_hash_func, string_compare_func); + + valid_hashmap_put = hashmap_put(m, "key 1", (void*) (const char *) "val 1"); + assert_se(valid_hashmap_put == 1); + + assert_se(m); + hashmap_free(m); +} + +static void test_hashmap_ensure_allocated(void) { + Hashmap *m; + int valid_hashmap; + + m = hashmap_new(string_hash_func, string_compare_func); + + valid_hashmap = hashmap_ensure_allocated(&m, string_hash_func, string_compare_func); + assert_se(valid_hashmap == 0); + + assert_se(m); + hashmap_free(m); +} + +static void test_hashmap_foreach_key(void) { + Hashmap *m; + Iterator i; + bool key_found[] = { false, false, false, false }; + const char *s; + const char *key; + static const char key_table[] = + "key 1\0" + "key 2\0" + "key 3\0" + "key 4\0"; + + m = hashmap_new(string_hash_func, string_compare_func); + + NULSTR_FOREACH(key, key_table) + hashmap_put(m, key, (void*) (const char*) "my dummy val"); + + HASHMAP_FOREACH_KEY(s, key, m, i) { + if (!key_found[0] && streq(key, "key 1")) + key_found[0] = true; + else if (!key_found[1] && streq(key, "key 2")) + key_found[1] = true; + else if (!key_found[2] && streq(key, "key 3")) + key_found[2] = true; + else if (!key_found[3] && streq(key, "fail")) + key_found[3] = true; + } + + assert_se(m); + assert_se(key_found[0] && key_found[1] && key_found[2] && !key_found[3]); + + hashmap_free(m); +} + +static void test_hashmap_foreach(void) { + Hashmap *m; + Iterator i; + bool value_found[] = { false, false, false, false }; + char *val1, *val2, *val3, *val4, *s; + + val1 = strdup("my val1"); + assert_se(val1); + val2 = strdup("my val2"); + assert_se(val2); + val3 = strdup("my val3"); + assert_se(val3); + val4 = strdup("my val4"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); + hashmap_put(m, "Key 3", val3); + hashmap_put(m, "Key 4", val4); + + HASHMAP_FOREACH(s, m, i) { + if (!value_found[0] && streq(s, val1)) + value_found[0] = true; + else if (!value_found[1] && streq(s, val2)) + value_found[1] = true; + else if (!value_found[2] && streq(s, val3)) + value_found[2] = true; + else if (!value_found[3] && streq(s, val4)) + value_found[3] = true; + } + + assert_se(m); + assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]); + + hashmap_free_free(m); +} + +static void test_hashmap_foreach_backwards(void) { + Hashmap *m; + Iterator i; + char *val1, *val2, *val3, *val4, *s; + bool value_found[] = { false, false, false, false }; + + val1 = strdup("my val1"); + assert_se(val1); + val2 = strdup("my val2"); + assert_se(val2); + val3 = strdup("my val3"); + assert_se(val3); + val4 = strdup("my val4"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); + hashmap_put(m, "Key 3", val3); + hashmap_put(m, "Key 4", val4); + + HASHMAP_FOREACH_BACKWARDS(s, m, i) { + if (!value_found[0] && streq(s, val1)) + value_found[0] = true; + else if (!value_found[1] && streq(s, val2)) + value_found[1] = true; + else if (!value_found[2] && streq(s, val3)) + value_found[2] = true; + else if (!value_found[3] && streq(s, val4)) + value_found[3] = true; + } + + assert_se(m); + assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]); + + hashmap_free_free(m); +} + +static void test_hashmap_merge(void) { + Hashmap *m; + Hashmap *n; + char *val1, *val2, *val3, *val4, *r; + + val1 = strdup("my val1"); + assert_se(val1); + val2 = strdup("my val2"); + assert_se(val2); + val3 = strdup("my val3"); + assert_se(val3); + val4 = strdup("my val4"); + assert_se(val4); + + n = hashmap_new(string_hash_func, string_compare_func); + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); + hashmap_put(n, "Key 3", val3); + hashmap_put(n, "Key 4", val4); + + assert_se(hashmap_merge(m, n) == 0); + r = hashmap_get(m, "Key 3"); + assert_se(r && streq(r, "my val3")); + r = hashmap_get(m, "Key 4"); + assert_se(r && streq(r, "my val4")); + + assert_se(n); + assert_se(m); + hashmap_free(n); + hashmap_free_free(m); +} + +static void test_hashmap_contains(void) { + Hashmap *m; + char *val1; + + val1 = strdup("my val"); + assert_se(val1); + + m = hashmap_new(string_hash_func, string_compare_func); + + assert_se(!hashmap_contains(m, "Key 1")); + hashmap_put(m, "Key 1", val1); + assert_se(hashmap_contains(m, "Key 1")); + + assert_se(m); + hashmap_free_free(m); +} + +static void test_hashmap_isempty(void) { + Hashmap *m; + char *val1; + + val1 = strdup("my val"); + assert_se(val1); + + m = hashmap_new(string_hash_func, string_compare_func); + + assert_se(hashmap_isempty(m)); + hashmap_put(m, "Key 1", val1); + assert_se(!hashmap_isempty(m)); + + assert_se(m); + hashmap_free_free(m); +} + +static void test_hashmap_size(void) { + Hashmap *m; + char *val1, *val2, *val3, *val4; + + val1 = strdup("my val"); + assert_se(val1); + val2 = strdup("my val"); + assert_se(val2); + val3 = strdup("my val"); + assert_se(val3); + val4 = strdup("my val"); + assert_se(val4); + + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "Key 1", val1); + hashmap_put(m, "Key 2", val2); + hashmap_put(m, "Key 3", val3); + hashmap_put(m, "Key 4", val4); + + assert_se(m); + assert_se(hashmap_size(m) == 4); + hashmap_free_free(m); +} + +static void test_hashmap_get(void) { + Hashmap *m; + char *r; + char *val; + + val = strdup("my val"); + assert_se(val); + + m = hashmap_new(string_hash_func, string_compare_func); + + hashmap_put(m, "Key 1", val); + + r = hashmap_get(m, "Key 1"); + assert_se(streq(r, val)); + + assert_se(m); + hashmap_free_free(m); +} + +static void test_hashmap_many(void) { + Hashmap *h; + unsigned i; + +#define N_ENTRIES 100000 + + assert_se(h = hashmap_new(NULL, NULL)); + + for (i = 1; i < N_ENTRIES*3; i+=3) { + assert_se(hashmap_put(h, UINT_TO_PTR(i), UINT_TO_PTR(i)) >= 0); + assert_se(PTR_TO_UINT(hashmap_get(h, UINT_TO_PTR(i))) == i); + } + + for (i = 1; i < N_ENTRIES*3; i++) + assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1)); + + log_info("%u <= %u * 0.75 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.75); + + assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.75); + assert_se(hashmap_size(h) == N_ENTRIES); + + hashmap_free(h); +} + +static void test_uint64_compare_func(void) { + const uint64_t a = 0x100, b = 0x101; + + assert_se(uint64_compare_func(&a, &a) == 0); + assert_se(uint64_compare_func(&a, &b) == -1); + assert_se(uint64_compare_func(&b, &a) == 1); +} + +static void test_trivial_compare_func(void) { + assert_se(trivial_compare_func(INT_TO_PTR('a'), INT_TO_PTR('a')) == 0); + assert_se(trivial_compare_func(INT_TO_PTR('a'), INT_TO_PTR('b')) == -1); + assert_se(trivial_compare_func(INT_TO_PTR('b'), INT_TO_PTR('a')) == 1); +} + +static void test_string_compare_func(void) { + assert_se(!string_compare_func("fred", "wilma") == 0); + assert_se(string_compare_func("fred", "fred") == 0); +} + +int main(int argc, const char *argv[]) { + test_hashmap_copy(); + test_hashmap_get_strv(); + test_hashmap_move_one(); + test_hashmap_next(); + test_hashmap_replace(); + test_hashmap_update(); + test_hashmap_put(); + test_hashmap_ensure_allocated(); + test_hashmap_foreach(); + test_hashmap_foreach_backwards(); + test_hashmap_foreach_key(); + test_hashmap_contains(); + test_hashmap_merge(); + test_hashmap_isempty(); + test_hashmap_get(); + test_hashmap_size(); + test_hashmap_many(); + test_uint64_compare_func(); + test_trivial_compare_func(); + test_string_compare_func(); +} diff --git a/src/test/test-helper.h b/src/test/test-helper.h new file mode 100644 index 0000000..f75dd33 --- /dev/null +++ b/src/test/test-helper.h @@ -0,0 +1,31 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Holger Hans Peter Freyther + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "sd-daemon.h" + +#define TEST_REQ_RUNNING_SYSTEMD(x) \ + if (sd_booted() > 0) { \ + x; \ + } else { \ + printf("systemd not booted skipping '%s'\n", #x); \ + } diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c new file mode 100644 index 0000000..ad4f285 --- /dev/null +++ b/src/test/test-hostname.c @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "hostname-setup.h" +#include "util.h" + +int main(int argc, char* argv[]) { + int r; + + r = hostname_setup(); + if (r < 0) + fprintf(stderr, "hostname: %s\n", strerror(-r)); + + return 0; +} diff --git a/src/test/test-id128.c b/src/test/test-id128.c new file mode 100644 index 0000000..7b92758 --- /dev/null +++ b/src/test/test-id128.c @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include + +#include "util.h" +#include "macro.h" +#include "sd-daemon.h" + +#define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) +#define STR_WALDI "0102030405060708090a0b0c0d0e0f10" +#define UUID_WALDI "01020304-0506-0708-090a-0b0c0d0e0f10" + +int main(int argc, char *argv[]) { + sd_id128_t id, id2; + char t[33]; + _cleanup_free_ char *b = NULL; + + assert_se(sd_id128_randomize(&id) == 0); + printf("random: %s\n", sd_id128_to_string(id, t)); + + assert_se(sd_id128_from_string(t, &id2) == 0); + assert_se(sd_id128_equal(id, id2)); + + if (sd_booted() > 0) { + assert_se(sd_id128_get_machine(&id) == 0); + printf("machine: %s\n", sd_id128_to_string(id, t)); + + assert_se(sd_id128_get_boot(&id) == 0); + printf("boot: %s\n", sd_id128_to_string(id, t)); + } + + printf("waldi: %s\n", sd_id128_to_string(ID128_WALDI, t)); + assert_se(streq(t, STR_WALDI)); + + assert_se(asprintf(&b, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 32); + printf("waldi2: %s\n", b); + assert_se(streq(t, b)); + + assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0); + assert_se(sd_id128_equal(id, ID128_WALDI)); + + assert_se(sd_id128_from_string("", &id) < 0); + assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f101", &id) < 0); + assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f10-", &id) < 0); + assert_se(sd_id128_from_string("01020304-0506-0708-090a0b0c0d0e0f10", &id) < 0); + assert_se(sd_id128_from_string("010203040506-0708-090a-0b0c0d0e0f10", &id) < 0); + + assert_se(id128_is_valid(STR_WALDI)); + assert_se(id128_is_valid(UUID_WALDI)); + assert_se(!id128_is_valid("")); + assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f101")); + assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f10-")); + assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10")); + assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10")); + + return 0; +} diff --git a/src/test/test-install.c b/src/test/test-install.c new file mode 100644 index 0000000..2087d52 --- /dev/null +++ b/src/test/test-install.c @@ -0,0 +1,265 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "path-util.h" +#include "install.h" + +static void dump_changes(UnitFileChange *c, unsigned n) { + unsigned i; + + assert(n == 0 || c); + + for (i = 0; i < n; i++) { + if (c[i].type == UNIT_FILE_UNLINK) + printf("rm '%s'\n", c[i].path); + else if (c[i].type == UNIT_FILE_SYMLINK) + printf("ln -s '%s' '%s'\n", c[i].source, c[i].path); + } +} + +int main(int argc, char* argv[]) { + Hashmap *h; + UnitFileList *p; + Iterator i; + int r; + const char *const files[] = { "avahi-daemon.service", NULL }; + const char *const files2[] = { "/home/lennart/test.service", NULL }; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + h = hashmap_new(string_hash_func, string_compare_func); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + assert_se(r == 0); + + HASHMAP_FOREACH(p, h, i) { + UnitFileState s; + + s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path)); + + assert_se(p->state == s); + + fprintf(stderr, "%s (%s)\n", + p->path, + unit_file_state_to_string(p->state)); + } + + unit_file_list_free(h); + + log_error("enable"); + + r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + + log_error("enable2"); + + r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); + + log_error("disable"); + + changes = NULL; + n_changes = 0; + + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; + n_changes = 0; + + r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + log_error("mask2"); + r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + + log_error("unmask"); + changes = NULL; + n_changes = 0; + + r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_error("unmask2"); + r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; + n_changes = 0; + + r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + + log_error("disable"); + changes = NULL; + n_changes = 0; + + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + log_error("disable2"); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + + log_error("umask"); + changes = NULL; + n_changes = 0; + + r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + + log_error("enable files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + + log_error("link files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + + log_error("link files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + + log_error("reenable files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + log_error("preset files"); + changes = NULL; + n_changes = 0; + + r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED); + + return 0; +} diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c new file mode 100644 index 0000000..1066374 --- /dev/null +++ b/src/test/test-job-type.c @@ -0,0 +1,105 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "job.h" +#include "unit.h" +#include "service.h" + +int main(int argc, char*argv[]) { + JobType a, b, c, ab, bc, ab_c, bc_a, a_bc; + const ServiceState test_states[] = { SERVICE_DEAD, SERVICE_RUNNING }; + unsigned i; + bool merged_ab; + + /* fake a unit */ + static Service s = { + .meta.load_state = UNIT_LOADED, + .type = SERVICE_SIMPLE, + }; + Unit *u = UNIT(&s); + + for (i = 0; i < ELEMENTSOF(test_states); i++) { + s.state = test_states[i]; + printf("\nWith collapsing for service state %s\n" + "=========================================\n", service_state_to_string(s.state)); + for (a = 0; a < _JOB_TYPE_MAX_MERGING; a++) { + for (b = 0; b < _JOB_TYPE_MAX_MERGING; b++) { + + ab = a; + merged_ab = (job_type_merge_and_collapse(&ab, b, u) >= 0); + + if (!job_type_is_mergeable(a, b)) { + assert(!merged_ab); + printf("Not mergeable: %s + %s\n", job_type_to_string(a), job_type_to_string(b)); + continue; + } + + assert(merged_ab); + printf("%s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(ab)); + + for (c = 0; c < _JOB_TYPE_MAX_MERGING; c++) { + + /* Verify transitivity of mergeability of job types */ + assert(!job_type_is_mergeable(a, b) || + !job_type_is_mergeable(b, c) || + job_type_is_mergeable(a, c)); + + /* Verify that merged entries can be merged with the same entries + * they can be merged with separately */ + assert(!job_type_is_mergeable(a, c) || job_type_is_mergeable(ab, c)); + assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(ab, c)); + + /* Verify that if a merged with b is not mergeable with c, then + * either a or b is not mergeable with c either. */ + assert(job_type_is_mergeable(ab, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c)); + + bc = b; + if (job_type_merge_and_collapse(&bc, c, u) >= 0) { + + /* Verify associativity */ + + ab_c = ab; + assert(job_type_merge_and_collapse(&ab_c, c, u) == 0); + + bc_a = bc; + assert(job_type_merge_and_collapse(&bc_a, a, u) == 0); + + a_bc = a; + assert(job_type_merge_and_collapse(&a_bc, bc, u) == 0); + + assert(ab_c == bc_a); + assert(ab_c == a_bc); + + printf("%s + %s + %s = %s\n", job_type_to_string(a), job_type_to_string(b), job_type_to_string(c), job_type_to_string(ab_c)); + } + } + } + } + } + + + return 0; +} diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c new file mode 100644 index 0000000..c233b1e --- /dev/null +++ b/src/test/test-libudev.c @@ -0,0 +1,510 @@ +/*** + This file is part of systemd. + + Copyright 2008-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "udev-util.h" +#include "util.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +_printf_(6,0) +static void log_fn(struct udev *udev, + int priority, const char *file, int line, const char *fn, + const char *format, va_list args) { + printf("test-libudev: %s %s:%d ", fn, file, line); + vprintf(format, args); +} + +static void print_device(struct udev_device *device) { + const char *str; + dev_t devnum; + int count; + struct udev_list_entry *list_entry; + + printf("*** device: %p ***\n", device); + str = udev_device_get_action(device); + if (str != NULL) + printf("action: '%s'\n", str); + + str = udev_device_get_syspath(device); + printf("syspath: '%s'\n", str); + + str = udev_device_get_sysname(device); + printf("sysname: '%s'\n", str); + + str = udev_device_get_sysnum(device); + if (str != NULL) + printf("sysnum: '%s'\n", str); + + str = udev_device_get_devpath(device); + printf("devpath: '%s'\n", str); + + str = udev_device_get_subsystem(device); + if (str != NULL) + printf("subsystem: '%s'\n", str); + + str = udev_device_get_devtype(device); + if (str != NULL) + printf("devtype: '%s'\n", str); + + str = udev_device_get_driver(device); + if (str != NULL) + printf("driver: '%s'\n", str); + + str = udev_device_get_devnode(device); + if (str != NULL) + printf("devname: '%s'\n", str); + + devnum = udev_device_get_devnum(device); + if (major(devnum) > 0) + printf("devnum: %u:%u\n", major(devnum), minor(devnum)); + + count = 0; + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { + printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); + count++; + } + if (count > 0) + printf("found %i links\n", count); + + count = 0; + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { + printf("property: '%s=%s'\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + count++; + } + if (count > 0) + printf("found %i properties\n", count); + + str = udev_device_get_property_value(device, "MAJOR"); + if (str != NULL) + printf("MAJOR: '%s'\n", str); + + str = udev_device_get_sysattr_value(device, "dev"); + if (str != NULL) + printf("attr{dev}: '%s'\n", str); + + printf("\n"); +} + +static int test_device(struct udev *udev, const char *syspath) { + _cleanup_udev_device_unref_ struct udev_device *device; + + printf("looking at device: %s\n", syspath); + device = udev_device_new_from_syspath(udev, syspath); + if (device == NULL) { + printf("no device found\n"); + return -1; + } + print_device(device); + + return 0; +} + +static int test_device_parents(struct udev *udev, const char *syspath) { + _cleanup_udev_device_unref_ struct udev_device *device; + struct udev_device *device_parent; + + printf("looking at device: %s\n", syspath); + device = udev_device_new_from_syspath(udev, syspath); + if (device == NULL) + return -1; + + printf("looking at parents\n"); + device_parent = device; + do { + print_device(device_parent); + device_parent = udev_device_get_parent(device_parent); + } while (device_parent != NULL); + + printf("looking at parents again\n"); + device_parent = device; + do { + print_device(device_parent); + device_parent = udev_device_get_parent(device_parent); + } while (device_parent != NULL); + + return 0; +} + +static int test_device_devnum(struct udev *udev) { + dev_t devnum = makedev(1, 3); + struct udev_device *device; + + printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + device = udev_device_new_from_devnum(udev, 'c', devnum); + if (device == NULL) + return -1; + print_device(device); + udev_device_unref(device); + return 0; +} + +static int test_device_subsys_name(struct udev *udev) { + struct udev_device *device; + + printf("looking up device: 'block':'sda'\n"); + device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); + if (device == NULL) + return -1; + print_device(device); + udev_device_unref(device); + + printf("looking up device: 'subsystem':'pci'\n"); + device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); + if (device == NULL) + return -1; + print_device(device); + udev_device_unref(device); + + printf("looking up device: 'drivers':'scsi:sd'\n"); + device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); + if (device == NULL) + return -1; + print_device(device); + udev_device_unref(device); + + printf("looking up device: 'module':'printk'\n"); + device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); + if (device == NULL) + return -1; + print_device(device); + udev_device_unref(device); + return 0; +} + +static int test_enumerate_print_list(struct udev_enumerate *enumerate) { + struct udev_list_entry *list_entry; + int count = 0; + + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { + struct udev_device *device; + + device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), + udev_list_entry_get_name(list_entry)); + if (device != NULL) { + printf("device: '%s' (%s)\n", + udev_device_get_syspath(device), + udev_device_get_subsystem(device)); + udev_device_unref(device); + count++; + } + } + printf("found %i devices\n\n", count); + return count; +} + +static int test_monitor(struct udev *udev) { + struct udev_monitor *udev_monitor = NULL; + int fd_ep; + int fd_udev = -1; + struct epoll_event ep_udev, ep_stdin; + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + printf("error creating epoll fd: %m\n"); + goto out; + } + + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor == NULL) { + printf("no socket\n"); + goto out; + } + fd_udev = udev_monitor_get_fd(udev_monitor); + + if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || + udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || + udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { + printf("filter failed\n"); + goto out; + } + + if (udev_monitor_enable_receiving(udev_monitor) < 0) { + printf("bind failed\n"); + goto out; + } + + memzero(&ep_udev, sizeof(struct epoll_event)); + ep_udev.events = EPOLLIN; + ep_udev.data.fd = fd_udev; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { + printf("fail to add fd to epoll: %m\n"); + goto out; + } + + memzero(&ep_stdin, sizeof(struct epoll_event)); + ep_stdin.events = EPOLLIN; + ep_stdin.data.fd = STDIN_FILENO; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { + printf("fail to add fd to epoll: %m\n"); + goto out; + } + + for (;;) { + int fdcount; + struct epoll_event ev[4]; + struct udev_device *device; + int i; + + printf("waiting for events from udev, press ENTER to exit\n"); + fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); + printf("epoll fd count: %i\n", fdcount); + + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { + device = udev_monitor_receive_device(udev_monitor); + if (device == NULL) { + printf("no device from socket\n"); + continue; + } + print_device(device); + udev_device_unref(device); + } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { + printf("exiting loop\n"); + goto out; + } + } + } +out: + if (fd_ep >= 0) + close(fd_ep); + udev_monitor_unref(udev_monitor); + return 0; +} + +static int test_queue(struct udev *udev) { + struct udev_queue *udev_queue; + unsigned long long int seqnum; + struct udev_list_entry *list_entry; + + udev_queue = udev_queue_new(udev); + if (udev_queue == NULL) + return -1; + seqnum = udev_queue_get_kernel_seqnum(udev_queue); + printf("seqnum kernel: %llu\n", seqnum); + seqnum = udev_queue_get_udev_seqnum(udev_queue); + printf("seqnum udev : %llu\n", seqnum); + + if (udev_queue_get_queue_is_empty(udev_queue)) + printf("queue is empty\n"); + printf("get queue list\n"); + udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) + printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + printf("\n"); + printf("get queue list again\n"); + udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) + printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + printf("\n"); + + list_entry = udev_queue_get_queued_list_entry(udev_queue); + if (list_entry != NULL) { + printf("event [%llu] is queued\n", seqnum); + seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10); + if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum)) + printf("event [%llu] is not finished\n", seqnum); + else + printf("event [%llu] is finished\n", seqnum); + } + printf("\n"); + udev_queue_unref(udev_queue); + return 0; +} + +static int test_enumerate(struct udev *udev, const char *subsystem) { + struct udev_enumerate *udev_enumerate; + + printf("enumerate '%s'\n", subsystem == NULL ? "" : 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); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'net' + duplicated scan + null + zero\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_add_match_subsystem(udev_enumerate, "net"); + udev_enumerate_scan_devices(udev_enumerate); + udev_enumerate_scan_devices(udev_enumerate); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); + udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); + 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); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'block'\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_add_match_subsystem(udev_enumerate,"block"); + udev_enumerate_add_match_is_initialized(udev_enumerate); + udev_enumerate_scan_devices(udev_enumerate); + test_enumerate_print_list(udev_enumerate); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'not block'\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block"); + udev_enumerate_scan_devices(udev_enumerate); + test_enumerate_print_list(udev_enumerate); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'pci, mem, vc'\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_add_match_subsystem(udev_enumerate, "pci"); + 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); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'subsystem'\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_scan_subsystems(udev_enumerate); + test_enumerate_print_list(udev_enumerate); + udev_enumerate_unref(udev_enumerate); + + printf("enumerate 'property IF_FS_*=filesystem'\n"); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem"); + udev_enumerate_scan_devices(udev_enumerate); + test_enumerate_print_list(udev_enumerate); + udev_enumerate_unref(udev_enumerate); + return 0; +} + +static void test_hwdb(struct udev *udev, const char *modalias) { + struct udev_hwdb *hwdb; + struct udev_list_entry *entry; + + hwdb = udev_hwdb_new(udev); + + udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) + printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); + printf("\n"); + + hwdb = udev_hwdb_unref(hwdb); + assert(hwdb == NULL); +} + +int main(int argc, char *argv[]) { + struct udev *udev = NULL; + static const struct option options[] = { + { "syspath", required_argument, NULL, 'p' }, + { "subsystem", required_argument, NULL, 's' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + const char *syspath = "/devices/virtual/mem/null"; + const char *subsystem = NULL; + char path[1024]; + + udev = udev_new(); + printf("context: %p\n", udev); + if (udev == NULL) { + printf("no context\n"); + return 1; + } + udev_set_log_fn(udev, log_fn); + printf("set log: %p\n", log_fn); + + for (;;) { + int option; + + option = getopt_long(argc, argv, "+p:s:dhV", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'p': + syspath = optarg; + break; + case 's': + subsystem = optarg; + break; + case 'd': + if (udev_get_log_priority(udev) < LOG_INFO) + udev_set_log_priority(udev, LOG_INFO); + break; + case 'h': + printf("--debug --syspath= --subsystem= --help\n"); + goto out; + case 'V': + printf("%s\n", VERSION); + goto out; + default: + goto out; + } + } + + /* add sys path if needed */ + if (!startswith(syspath, "/sys")) { + snprintf(path, sizeof(path), "/sys/%s", syspath); + syspath = path; + } + + test_device(udev, syspath); + test_device_devnum(udev); + test_device_subsys_name(udev); + test_device_parents(udev, syspath); + + test_enumerate(udev, subsystem); + + test_queue(udev); + + test_hwdb(udev, "usb:v0D50p0011*"); + + test_monitor(udev); +out: + udev_unref(udev); + return 0; +} diff --git a/src/test/test-list.c b/src/test/test-list.c new file mode 100644 index 0000000..fa52ad1 --- /dev/null +++ b/src/test/test-list.c @@ -0,0 +1,109 @@ +/*** + This file is part of systemd + + Copyright 2013 Jan Janssen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "list.h" +#include "util.h" + +int main(int argc, const char *argv[]) { + size_t i; + typedef struct list_item { + LIST_FIELDS(struct list_item, item); + } list_item; + LIST_HEAD(list_item, head); + list_item items[4]; + list_item *cursor; + + LIST_HEAD_INIT(head); + assert_se(head == NULL); + + for (i = 0; i < ELEMENTSOF(items); i++) { + LIST_INIT(item, &items[i]); + assert_se(LIST_JUST_US(item, &items[i])); + LIST_PREPEND(item, head, &items[i]); + } + + assert_se(!LIST_JUST_US(item, head)); + + assert_se(items[0].item_next == NULL); + assert_se(items[1].item_next == &items[0]); + assert_se(items[2].item_next == &items[1]); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[0].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_FIND_HEAD(item, &items[0], cursor); + assert_se(cursor == &items[3]); + + LIST_FIND_TAIL(item, &items[3], cursor); + assert_se(cursor == &items[0]); + + LIST_REMOVE(item, head, &items[1]); + assert_se(LIST_JUST_US(item, &items[1])); + + assert_se(items[0].item_next == NULL); + assert_se(items[2].item_next == &items[0]); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[0].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_INSERT_AFTER(item, head, &items[3], &items[1]); + assert_se(items[0].item_next == NULL); + assert_se(items[2].item_next == &items[0]); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[0].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_REMOVE(item, head, &items[0]); + assert_se(LIST_JUST_US(item, &items[0])); + + assert_se(items[2].item_next == NULL); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_REMOVE(item, head, &items[1]); + assert_se(LIST_JUST_US(item, &items[1])); + + assert_se(items[2].item_next == NULL); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_REMOVE(item, head, &items[2]); + assert_se(LIST_JUST_US(item, &items[2])); + assert_se(LIST_JUST_US(item, head)); + + LIST_REMOVE(item, head, &items[3]); + assert_se(LIST_JUST_US(item, &items[3])); + + return 0; +} diff --git a/src/test/test-log.c b/src/test/test-log.c new file mode 100644 index 0000000..8dc3d53 --- /dev/null +++ b/src/test/test-log.c @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "log.h" + +int main(int argc, char* argv[]) { + + log_set_target(LOG_TARGET_CONSOLE); + log_open(); + + log_struct(LOG_INFO, + "MESSAGE=Waldo PID=%lu", (unsigned long) getpid(), + "SERVICE=piepapo", + NULL); + + log_set_target(LOG_TARGET_JOURNAL); + log_open(); + + log_struct(LOG_INFO, + "MESSAGE=Foobar PID=%lu", (unsigned long) getpid(), + "SERVICE=foobar", + NULL); + + log_struct(LOG_INFO, + "MESSAGE=Foobar PID=%lu", (unsigned long) getpid(), + "FORMAT_STR_TEST=1=%i A=%c 2=%hi 3=%li 4=%lli 1=%p foo=%s 2.5=%g 3.5=%g 4.5=%Lg", + (int) 1, 'A', (short) 2, (long int) 3, (long long int) 4, (void*) 1, "foo", (float) 2.5f, (double) 3.5, (long double) 4.5, + "SUFFIX=GOT IT", + NULL); + + return 0; +} diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c new file mode 100644 index 0000000..ab330ac --- /dev/null +++ b/src/test/test-loopback.c @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "loopback-setup.h" +#include "util.h" + +int main(int argc, char* argv[]) { + int r; + + if ((r = loopback_setup()) < 0) + fprintf(stderr, "loopback: %s\n", strerror(-r)); + + return 0; +} diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c new file mode 100644 index 0000000..5b76b9e --- /dev/null +++ b/src/test/test-namespace.c @@ -0,0 +1,145 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "namespace.h" +#include "util.h" + +static void test_tmpdir(const char *id, const char *A, const char *B) { + _cleanup_free_ char *a, *b; + struct stat x, y; + char *c, *d; + + assert_se(setup_tmp_dirs(id, &a, &b) == 0); + assert_se(startswith(a, A)); + assert_se(startswith(b, B)); + + assert_se(stat(a, &x) >= 0); + assert_se(stat(b, &y) >= 0); + + assert_se(S_ISDIR(x.st_mode)); + assert_se(S_ISDIR(y.st_mode)); + + assert_se((x.st_mode & 01777) == 0700); + assert_se((y.st_mode & 01777) == 0700); + + c = strappenda(a, "/tmp"); + d = strappenda(b, "/tmp"); + + assert_se(stat(c, &x) >= 0); + assert_se(stat(d, &y) >= 0); + + assert_se(S_ISDIR(x.st_mode)); + assert_se(S_ISDIR(y.st_mode)); + + assert_se((x.st_mode & 01777) == 01777); + assert_se((y.st_mode & 01777) == 01777); + + assert_se(rmdir(c) >= 0); + assert_se(rmdir(d) >= 0); + + assert_se(rmdir(a) >= 0); + assert_se(rmdir(b) >= 0); +} + +static void test_netns(void) { + _cleanup_close_pipe_ int s[2] = { -1, -1 }; + pid_t pid1, pid2, pid3; + int r, n = 0; + siginfo_t si; + + if (geteuid() > 0) + return; + + assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0); + + pid1 = fork(); + assert_se(pid1 >= 0); + + if (pid1 == 0) { + r = setup_netns(s); + assert_se(r >= 0); + _exit(r); + } + + pid2 = fork(); + assert_se(pid2 >= 0); + + if (pid2 == 0) { + r = setup_netns(s); + assert_se(r >= 0); + exit(r); + } + + pid3 = fork(); + assert_se(pid3 >= 0); + + if (pid3 == 0) { + r = setup_netns(s); + assert_se(r >= 0); + exit(r); + } + + r = wait_for_terminate(pid1, &si); + assert_se(r >= 0); + assert_se(si.si_code == CLD_EXITED); + n += si.si_status; + + r = wait_for_terminate(pid2, &si); + assert_se(r >= 0); + assert_se(si.si_code == CLD_EXITED); + n += si.si_status; + + r = wait_for_terminate(pid3, &si); + assert_se(r >= 0); + assert_se(si.si_code == CLD_EXITED); + n += si.si_status; + + assert_se(n == 1); +} + +int main(int argc, char *argv[]) { + sd_id128_t bid; + char boot_id[SD_ID128_STRING_MAX]; + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL; + + assert_se(sd_id128_get_boot(&bid) >= 0); + sd_id128_to_string(bid, boot_id); + + x = strjoin("/tmp/systemd-private-", boot_id, "-abcd.service-", NULL); + y = strjoin("/var/tmp/systemd-private-", boot_id, "-abcd.service-", NULL); + assert_se(x && y); + + test_tmpdir("abcd.service", x, y); + + z = strjoin("/tmp/systemd-private-", boot_id, "-sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device-", NULL); + zz = strjoin("/var/tmp/systemd-private-", boot_id, "-sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device-", NULL); + + assert_se(z && zz); + + test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz); + + test_netns(); + + return 0; +} diff --git a/src/test/test-ns.c b/src/test/test-ns.c new file mode 100644 index 0000000..ad0d041 --- /dev/null +++ b/src/test/test-ns.c @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "namespace.h" +#include "execute.h" +#include "log.h" + +int main(int argc, char *argv[]) { + const char * const writable[] = { + "/home", + NULL + }; + + const char * const readonly[] = { + "/", + "/usr", + "/boot", + NULL + }; + + const char * const inaccessible[] = { + "/home/lennart/projects", + NULL + }; + + int r; + char tmp_dir[] = "/tmp/systemd-private-XXXXXX", + var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX"; + + assert_se(mkdtemp(tmp_dir)); + assert_se(mkdtemp(var_tmp_dir)); + + r = setup_namespace((char **) writable, + (char **) readonly, + (char **) inaccessible, + tmp_dir, + var_tmp_dir, + true, + 0); + if (r < 0) { + log_error("Failed to setup namespace: %s", strerror(-r)); + return 1; + } + + execl("/bin/sh", "/bin/sh", NULL); + log_error("execl(): %m"); + + return 1; +} diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c new file mode 100644 index 0000000..bec2a83 --- /dev/null +++ b/src/test/test-path-util.c @@ -0,0 +1,166 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "path-util.h" +#include "util.h" +#include "macro.h" + + +static void test_path(void) { + assert_se(path_equal("/goo", "/goo")); + assert_se(path_equal("//goo", "/goo")); + assert_se(path_equal("//goo/////", "/goo")); + assert_se(path_equal("goo/////", "goo")); + + assert_se(path_equal("/goo/boo", "/goo//boo")); + assert_se(path_equal("//goo/boo", "/goo/boo//")); + + assert_se(path_equal("/", "///")); + + assert_se(!path_equal("/x", "x/")); + assert_se(!path_equal("x/", "/")); + + assert_se(!path_equal("/x/./y", "x/y")); + assert_se(!path_equal("x/.y", "x/y")); + + assert_se(path_is_absolute("/")); + assert_se(!path_is_absolute("./")); + + assert_se(is_path("/dir")); + assert_se(is_path("a/b")); + assert_se(!is_path(".")); + + assert_se(streq(basename("./aa/bb/../file.da."), "file.da.")); + assert_se(streq(basename("/aa///.file"), ".file")); + assert_se(streq(basename("/aa///file..."), "file...")); + assert_se(streq(basename("file.../"), "")); + +#define test_parent(x, y) { \ + char _cleanup_free_ *z = NULL; \ + int r = path_get_parent(x, &z); \ + printf("expected: %s\n", y ? y : "error"); \ + printf("actual: %s\n", r<0 ? "error" : z); \ + assert_se((y==NULL) ^ (r==0)); \ + assert_se(y==NULL || path_equal(z, y)); \ + } + + test_parent("./aa/bb/../file.da.", "./aa/bb/.."); + test_parent("/aa///.file", "/aa///"); + test_parent("/aa///file...", "/aa///"); + test_parent("file.../", NULL); + + assert_se(path_is_mount_point("/", true)); + assert_se(path_is_mount_point("/", false)); + + { + char p1[] = "aaa/bbb////ccc"; + char p2[] = "//aaa/.////ccc"; + char p3[] = "/./"; + + assert(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc")); + assert(path_equal(path_kill_slashes(p2), "/aaa/./ccc")); + assert(path_equal(path_kill_slashes(p3), "/./")); + } +} + +static void test_find_binary(void) { + char *p; + + assert(find_binary("/bin/sh", &p) == 0); + puts(p); + assert(streq(p, "/bin/sh")); + free(p); + + assert(find_binary("./test-path-util", &p) == 0); + puts(p); + assert(endswith(p, "/test-path-util")); + assert(path_is_absolute(p)); + free(p); + + assert(find_binary("sh", &p) == 0); + puts(p); + assert(endswith(p, "/sh")); + assert(path_is_absolute(p)); + free(p); + + assert(find_binary("xxxx-xxxx", &p) == -ENOENT); +} + +static void test_prefixes(void) { + static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL}; + unsigned i; + char s[PATH_MAX]; + bool b; + + i = 0; + PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") { + log_error("---%s---", s); + assert_se(streq(s, values[i++])); + } + assert_se(values[i] == NULL); + + i = 1; + PATH_FOREACH_PREFIX(s, "/a/b/c/d") { + log_error("---%s---", s); + assert_se(streq(s, values[i++])); + } + assert_se(values[i] == NULL); + + i = 0; + PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////") + assert_se(streq(s, values[i++])); + assert_se(values[i] == NULL); + + i = 1; + PATH_FOREACH_PREFIX(s, "////a////b////c///d///////") + assert_se(streq(s, values[i++])); + assert_se(values[i] == NULL); + + PATH_FOREACH_PREFIX(s, "////") + assert_not_reached("Wut?"); + + b = false; + PATH_FOREACH_PREFIX_MORE(s, "////") { + assert_se(!b); + assert_se(streq(s, "")); + b = true; + } + assert_se(b); + + PATH_FOREACH_PREFIX(s, "") + assert_not_reached("wut?"); + + b = false; + PATH_FOREACH_PREFIX_MORE(s, "") { + assert(!b); + assert(streq(s, "")); + b = true; + } +} + +int main(void) { + test_path(); + test_find_binary(); + test_prefixes(); + return 0; +} diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c new file mode 100644 index 0000000..cdb1e4a --- /dev/null +++ b/src/test/test-prioq.c @@ -0,0 +1,170 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "set.h" +#include "prioq.h" +#include "siphash24.h" + +#define SET_SIZE 1024*4 + +static int unsigned_compare(const void *a, const void *b) { + const unsigned *x = a, *y = b; + + if (*x < *y) + return -1; + + if (*x > *y) + return 1; + + return 0; +} + +static void test_unsigned(void) { + unsigned buffer[SET_SIZE], i; + Prioq *q; + + srand(0); + + q = prioq_new(trivial_compare_func); + assert_se(q); + + for (i = 0; i < ELEMENTSOF(buffer); i++) { + unsigned u; + + u = (unsigned) rand(); + buffer[i] = u; + assert_se(prioq_put(q, UINT_TO_PTR(u), NULL) >= 0); + } + + qsort(buffer, ELEMENTSOF(buffer), sizeof(buffer[0]), unsigned_compare); + + for (i = 0; i < ELEMENTSOF(buffer); i++) { + unsigned u; + + assert_se(prioq_size(q) == ELEMENTSOF(buffer) - i); + + u = PTR_TO_UINT(prioq_pop(q)); + assert_se(buffer[i] == u); + } + + assert_se(prioq_isempty(q)); + prioq_free(q); +} + +struct test { + unsigned value; + unsigned idx; +}; + +static int test_compare(const void *a, const void *b) { + const struct test *x = a, *y = b; + + if (x->value < y->value) + return -1; + + if (x->value > y->value) + return 1; + + return 0; +} + +static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { + const struct test *x = a; + uint64_t u; + + siphash24((uint8_t*) &u, &x->value, sizeof(x->value), hash_key); + + return (unsigned long) u; +} + +static void test_struct(void) { + Prioq *q; + Set *s; + unsigned previous = 0, i; + int r; + + srand(0); + + q = prioq_new(test_compare); + assert_se(q); + + s = set_new(test_hash, test_compare); + assert_se(s); + + for (i = 0; i < SET_SIZE; i++) { + struct test *t; + + t = new0(struct test, 1); + assert_se(t); + t->value = (unsigned) rand(); + + r = prioq_put(q, t, &t->idx); + assert_se(r >= 0); + + if (i % 4 == 0) { + r = set_consume(s, t); + assert_se(r >= 0); + } + } + + for (;;) { + struct test *t; + + t = set_steal_first(s); + if (!t) + break; + + r = prioq_remove(q, t, &t->idx); + assert_se(r > 0); + + free(t); + } + + for (i = 0; i < SET_SIZE * 3 / 4; i++) { + struct test *t; + + assert_se(prioq_size(q) == (SET_SIZE * 3 / 4) - i); + + t = prioq_pop(q); + assert_se(t); + + assert_se(previous <= t->value); + previous = t->value; + free(t); + } + + assert_se(prioq_isempty(q)); + prioq_free(q); + + assert_se(set_isempty(s)); + set_free(s); +} + +int main(int argc, char* argv[]) { + + test_unsigned(); + test_struct(); + + return 0; +} diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c new file mode 100644 index 0000000..b1d42d7 --- /dev/null +++ b/src/test/test-replace-var.c @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "macro.h" +#include "replace-var.h" + +static char *lookup(const char *variable, void *userdata) { + return strjoin("<<<", variable, ">>>", NULL); +} + +int main(int argc, char *argv[]) { + char *r; + + assert_se(r = replace_var("@@@foobar@xyz@HALLO@foobar@test@@testtest@TEST@...@@@", lookup, NULL)); + puts(r); + assert_se(streq(r, "@@@foobar@xyz<<>>foobar@test@@testtest<<>>...@@@")); + free(r); + + assert_se(r = strreplace("XYZFFFFXYZFFFFXYZ", "XYZ", "ABC")); + puts(r); + assert_se(streq(r, "ABCFFFFABCFFFFABC")); + free(r); + + return 0; +} diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c new file mode 100644 index 0000000..e984ee4 --- /dev/null +++ b/src/test/test-sched-prio.c @@ -0,0 +1,95 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Holger Hans Peter Freyther + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "manager.h" +#include "macro.h" + +int main(int argc, char *argv[]) { + Manager *m = NULL; + Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched; + Service *ser; + FILE *serial = NULL; + FDSet *fdset = NULL; + int r; + const char *dir = TEST_DIR; + + /* prepare the test */ + assert_se(set_unit_path(dir) >= 0); + r = manager_new(SYSTEMD_USER, &m); + if (r == -EPERM || r == -EACCES || r == -EADDRINUSE || r == -EHOSTDOWN) { + printf("Skipping test: manager_new: %s", strerror(-r)); + return EXIT_TEST_SKIP; + } + assert(r >= 0); + assert_se(manager_startup(m, serial, fdset) >= 0); + + /* load idle ok */ + assert_se(manager_load_unit(m, "sched_idle_ok.service", NULL, NULL, &idle_ok) >= 0); + assert_se(idle_ok->load_state == UNIT_LOADED); + ser = SERVICE(idle_ok); + assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER); + assert_se(ser->exec_context.cpu_sched_priority == 0); + + /* + * load idle bad. This should print a warning but we have no way to look at it. + */ + assert_se(manager_load_unit(m, "sched_idle_bad.service", NULL, NULL, &idle_bad) >= 0); + assert_se(idle_bad->load_state == UNIT_LOADED); + ser = SERVICE(idle_ok); + assert_se(ser->exec_context.cpu_sched_policy == SCHED_OTHER); + assert_se(ser->exec_context.cpu_sched_priority == 0); + + /* + * load rr ok. + * Test that the default priority is moving from 0 to 1. + */ + assert_se(manager_load_unit(m, "sched_rr_ok.service", NULL, NULL, &rr_ok) >= 0); + assert_se(rr_ok->load_state == UNIT_LOADED); + ser = SERVICE(rr_ok); + assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR); + assert_se(ser->exec_context.cpu_sched_priority == 1); + + /* + * load rr bad. + * Test that the value of 0 and 100 is ignored. + */ + assert_se(manager_load_unit(m, "sched_rr_bad.service", NULL, NULL, &rr_bad) >= 0); + assert_se(rr_bad->load_state == UNIT_LOADED); + ser = SERVICE(rr_bad); + assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR); + assert_se(ser->exec_context.cpu_sched_priority == 1); + + /* + * load rr change. + * Test that anything between 1 and 99 can be set. + */ + assert_se(manager_load_unit(m, "sched_rr_change.service", NULL, NULL, &rr_sched) >= 0); + assert_se(rr_sched->load_state == UNIT_LOADED); + ser = SERVICE(rr_sched); + assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR); + assert_se(ser->exec_context.cpu_sched_priority == 99); + + manager_free(m); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c new file mode 100644 index 0000000..a1020ad --- /dev/null +++ b/src/test/test-sleep.c @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "sleep-config.h" +#include "strv.h" + +static void test_sleep(void) { + _cleanup_strv_free_ char + **standby = strv_new("standby", NULL), + **mem = strv_new("mem", NULL), + **disk = strv_new("disk", NULL), + **suspend = strv_new("suspend", NULL), + **reboot = strv_new("reboot", NULL), + **platform = strv_new("platform", NULL), + **shutdown = strv_new("shutdown", NULL), + **freez = strv_new("freeze", NULL); + + log_info("Standby configured: %s", yes_no(can_sleep_state(standby) > 0)); + log_info("Suspend configured: %s", yes_no(can_sleep_state(mem) > 0)); + log_info("Hibernate configured: %s", yes_no(can_sleep_state(disk) > 0)); + log_info("Hibernate+Suspend (Hybrid-Sleep) configured: %s", yes_no(can_sleep_disk(suspend) > 0)); + log_info("Hibernate+Reboot configured: %s", yes_no(can_sleep_disk(reboot) > 0)); + log_info("Hibernate+Platform configured: %s", yes_no(can_sleep_disk(platform) > 0)); + log_info("Hibernate+Shutdown configured: %s", yes_no(can_sleep_disk(shutdown) > 0)); + log_info("Freeze configured: %s", yes_no(can_sleep_state(freez) > 0)); + + log_info("Suspend configured and possible: %s", yes_no(can_sleep("suspend") > 0)); + log_info("Hibernation configured and possible: %s", yes_no(can_sleep("hibernate") > 0)); + log_info("Hybrid-sleep configured and possible: %s", yes_no(can_sleep("hybrid-sleep") > 0)); +} + +int main(int argc, char* argv[]) { + log_parse_environment(); + log_open(); + + if (getuid() != 0) + log_warning("This program is unlikely to work for unpriviledged users"); + + test_sleep(); + + return 0; +} diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c new file mode 100644 index 0000000..3334e0b --- /dev/null +++ b/src/test/test-strbuf.c @@ -0,0 +1,92 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "strbuf.h" +#include "strv.h" +#include "util.h" + +static ssize_t add_string(struct strbuf *sb, const char *s) { + return strbuf_add_string(sb, s, strlen(s)); +} + +static void test_strbuf(void) { + struct strbuf *sb; + _cleanup_strv_free_ char **l; + ssize_t a, b, c, d, e, f, g; + + sb = strbuf_new(); + + a = add_string(sb, "waldo"); + b = add_string(sb, "foo"); + c = add_string(sb, "bar"); + d = add_string(sb, "waldo"); /* duplicate */ + e = add_string(sb, "aldo"); /* duplicate */ + f = add_string(sb, "do"); /* duplicate */ + g = add_string(sb, "waldorf"); /* not a duplicate: matches from tail */ + + /* check the content of the buffer directly */ + l = strv_parse_nulstr(sb->buf, sb->len); + + assert(streq(l[0], "")); /* root*/ + assert(streq(l[1], "waldo")); + assert(streq(l[2], "foo")); + assert(streq(l[3], "bar")); + assert(streq(l[4], "waldorf")); + + assert(sb->nodes_count == 5); /* root + 4 non-duplicates */ + assert(sb->dedup_count == 3); + assert(sb->in_count == 7); + + assert(sb->in_len == 29); /* length of all strings added */ + assert(sb->dedup_len == 11); /* length of all strings duplicated */ + assert(sb->len == 23); /* buffer length: in - dedup + \0 for each node */ + + /* check the returned offsets and the respective content in the buffer */ + assert(a == 1); + assert(b == 7); + assert(c == 11); + assert(d == 1); + assert(e == 2); + assert(f == 4); + assert(g == 15); + + assert(streq(sb->buf + a, "waldo")); + assert(streq(sb->buf + b, "foo")); + assert(streq(sb->buf + c, "bar")); + assert(streq(sb->buf + d, "waldo")); + assert(streq(sb->buf + e, "aldo")); + assert(streq(sb->buf + f, "do")); + assert(streq(sb->buf + g, "waldorf")); + + strbuf_complete(sb); + assert(sb->root == NULL); + + strbuf_cleanup(sb); +} + +int main(int argc, const char *argv[]) { + test_strbuf(); + + return 0; +} diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c new file mode 100644 index 0000000..5016906 --- /dev/null +++ b/src/test/test-strip-tab-ansi.c @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" + +int main(int argc, char *argv[]) { + char *p; + + assert_se(p = strdup("\tFoobar\tbar\twaldo\t")); + assert_se(strip_tab_ansi(&p, NULL)); + fprintf(stdout, "<%s>\n", p); + assert_se(streq(p, " Foobar bar waldo ")); + free(p); + + assert_se(p = strdup(ANSI_HIGHLIGHT_ON "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF)); + assert_se(strip_tab_ansi(&p, NULL)); + fprintf(stdout, "<%s>\n", p); + assert_se(streq(p, "Hello world!")); + free(p); + + assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT_ON "\x1B[" "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF)); + assert_se(strip_tab_ansi(&p, NULL)); + assert_se(streq(p, "\x1B[\x1B[ \x1B[\x1B[Hello world!")); + free(p); + + assert_se(p = strdup("\x1B[waldo")); + assert_se(strip_tab_ansi(&p, NULL)); + assert_se(streq(p, "\x1B[waldo")); + free(p); + + return 0; +} diff --git a/src/test/test-strv.c b/src/test/test-strv.c new file mode 100644 index 0000000..c8c5fc9 --- /dev/null +++ b/src/test/test-strv.c @@ -0,0 +1,427 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "specifier.h" +#include "strv.h" + +static void test_specifier_printf(void) { + static const Specifier table[] = { + { 'a', specifier_string, (char*) "AAAA" }, + { 'b', specifier_string, (char*) "BBBB" }, + { 'm', specifier_machine_id, NULL }, + { 'B', specifier_boot_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'v', specifier_kernel_release, NULL }, + {} + }; + + _cleanup_free_ char *w = NULL; + int r; + + r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w); + assert_se(r >= 0); + assert_se(w); + + puts(w); + assert_se(streq(w, "xxx a=AAAA b=BBBB yyy")); + + free(w); + r = specifier_printf("machine=%m, boot=%B, host=%H, version=%v", table, NULL, &w); + assert_se(r >= 0); + assert_se(w); + puts(w); +} + +static const char* const input_table_multiple[] = { + "one", + "two", + "three", + NULL, +}; + +static const char* const input_table_one[] = { + "one", + NULL, +}; + +static const char* const input_table_none[] = { + NULL, +}; + +static const char* const input_table_quotes[] = { + "\"", + "'", + "\"\"", + "\\", + "\\\\", + NULL, +}; +#define QUOTES_STRING \ + "\"\\\"\" " \ + "\"\\\'\" " \ + "\"\\\"\\\"\" " \ + "\"\\\\\" " \ + "\"\\\\\\\\\"" + +static const char * const input_table_spaces[] = { + " ", + "' '", + "\" ", + " \"", + " \\\\ ", + NULL, +}; +#define SPACES_STRING \ + "\" \" " \ + "\"\\' \\'\" " \ + "\"\\\" \" " \ + "\" \\\"\" " \ + "\" \\\\\\\\ \"" + +static void test_strv_find(void) { + assert_se(strv_find((char **)input_table_multiple, "three")); + assert_se(!strv_find((char **)input_table_multiple, "four")); +} + +static void test_strv_find_prefix(void) { + assert_se(strv_find_prefix((char **)input_table_multiple, "o")); + assert_se(strv_find_prefix((char **)input_table_multiple, "one")); + assert_se(strv_find_prefix((char **)input_table_multiple, "")); + assert_se(!strv_find_prefix((char **)input_table_multiple, "xxx")); + assert_se(!strv_find_prefix((char **)input_table_multiple, "onee")); +} + +static void test_strv_join(void) { + _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL; + + p = strv_join((char **)input_table_multiple, ", "); + assert_se(p); + assert_se(streq(p, "one, two, three")); + + q = strv_join((char **)input_table_multiple, ";"); + assert_se(q); + assert_se(streq(q, "one;two;three")); + + r = strv_join((char **)input_table_multiple, NULL); + assert_se(r); + assert_se(streq(r, "one two three")); + + s = strv_join((char **)input_table_one, ", "); + assert_se(s); + assert_se(streq(s, "one")); + + t = strv_join((char **)input_table_none, ", "); + assert_se(t); + assert_se(streq(t, "")); +} + +static void test_strv_quote_unquote(const char* const *split, const char *quoted) { + _cleanup_free_ char *p; + _cleanup_strv_free_ char **s; + char **t; + + p = strv_join_quoted((char **)split); + assert_se(p); + printf("-%s- --- -%s-\n", p, quoted); /* fprintf deals with NULL, puts does not */ + assert_se(p); + assert_se(streq(p, quoted)); + + s = strv_split_quoted(quoted); + assert_se(s); + STRV_FOREACH(t, s) { + assert_se(*t); + assert_se(streq(*t, *split)); + split++; + } +} + +static void test_strv_quote_unquote2(const char *quoted, const char ** list) { + _cleanup_strv_free_ char **s; + unsigned i = 0; + char **t; + + s = strv_split_quoted(quoted); + assert_se(s); + + STRV_FOREACH(t, s) + assert_se(streq(list[i++], *t)); + + assert_se(list[i] == NULL); +} + +static void test_strv_split(void) { + char **s; + unsigned i = 0; + _cleanup_strv_free_ char **l = NULL; + const char str[] = "one,two,three"; + + l = strv_split(str, ","); + + assert(l); + + STRV_FOREACH(s, l) { + assert_se(streq(*s, input_table_multiple[i++])); + } +} + +static void test_strv_split_newlines(void) { + unsigned i = 0; + char **s; + _cleanup_strv_free_ char **l = NULL; + const char str[] = "one\ntwo\nthree"; + + l = strv_split_newlines(str); + + assert(l); + + STRV_FOREACH(s, l) { + assert_se(streq(*s, input_table_multiple[i++])); + } +} + +static void test_strv_split_nulstr(void) { + _cleanup_strv_free_ char **l = NULL; + const char nulstr[] = "str0\0str1\0str2\0str3\0"; + + l = strv_split_nulstr (nulstr); + assert_se(l); + + assert_se(streq(l[0], "str0")); + assert_se(streq(l[1], "str1")); + assert_se(streq(l[2], "str2")); + assert_se(streq(l[3], "str3")); +} + +static void test_strv_parse_nulstr(void) { + _cleanup_strv_free_ char **l = NULL; + const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx"; + + l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1); + assert_se(l); + puts("Parse nulstr:"); + strv_print(l); + + assert_se(streq(l[0], "fuck")); + assert_se(streq(l[1], "fuck2")); + assert_se(streq(l[2], "fuck3")); + assert_se(streq(l[3], "")); + assert_se(streq(l[4], "fuck5")); + assert_se(streq(l[5], "")); + assert_se(streq(l[6], "xxx")); +} + +static void test_strv_overlap(void) { + const char * const input_table[] = { + "one", + "two", + "three", + NULL + }; + const char * const input_table_overlap[] = { + "two", + NULL + }; + const char * const input_table_unique[] = { + "four", + "five", + "six", + NULL + }; + + assert_se(strv_overlap((char **)input_table, (char**)input_table_overlap)); + assert_se(!strv_overlap((char **)input_table, (char**)input_table_unique)); +} + +static void test_strv_sort(void) { + const char* input_table[] = { + "durian", + "apple", + "citrus", + "CAPITAL LETTERS FIRST", + "banana", + NULL + }; + + strv_sort((char **)input_table); + + assert_se(streq(input_table[0], "CAPITAL LETTERS FIRST")); + assert_se(streq(input_table[1], "apple")); + assert_se(streq(input_table[2], "banana")); + assert_se(streq(input_table[3], "citrus")); + assert_se(streq(input_table[4], "durian")); +} + +static void test_strv_extend_strv_concat(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL; + + a = strv_new("without", "suffix", NULL); + b = strv_new("with", "suffix", NULL); + assert_se(a); + assert_se(b); + + assert_se(strv_extend_strv_concat(&a, b, "_suffix") >= 0); + + assert_se(streq(a[0], "without")); + assert_se(streq(a[1], "suffix")); + assert_se(streq(a[2], "with_suffix")); + assert_se(streq(a[3], "suffix_suffix")); +} + +static void test_strv_extend_strv(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL; + + a = strv_new("abc", "def", "ghi", NULL); + b = strv_new("jkl", "mno", "pqr", NULL); + assert_se(a); + assert_se(b); + + assert_se(strv_extend_strv(&a, b) >= 0); + + assert_se(streq(a[0], "abc")); + assert_se(streq(a[1], "def")); + assert_se(streq(a[2], "ghi")); + assert_se(streq(a[3], "jkl")); + assert_se(streq(a[4], "mno")); + assert_se(streq(a[5], "pqr")); + + assert_se(strv_length(a) == 6); +} + +static void test_strv_extend(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL; + + a = strv_new("test", "test1", NULL); + assert_se(a); + assert_se(strv_extend(&a, "test2") >= 0); + assert_se(strv_extend(&b, "test3") >= 0); + + assert_se(streq(a[0], "test")); + assert_se(streq(a[1], "test1")); + assert_se(streq(a[2], "test2")); + assert_se(streq(b[0], "test3")); +} + +static void test_strv_foreach(void) { + _cleanup_strv_free_ char **a; + unsigned i = 0; + char **check; + + a = strv_new("one", "two", "three", NULL); + + assert_se(a); + + STRV_FOREACH(check, a) { + assert_se(streq(*check, input_table_multiple[i++])); + } +} + +static void test_strv_foreach_backwards(void) { + _cleanup_strv_free_ char **a; + unsigned i = 2; + char **check; + + a = strv_new("one", "two", "three", NULL); + + assert_se(a); + + STRV_FOREACH_BACKWARDS(check, a) { + assert_se(streq_ptr(*check, input_table_multiple[i--])); + } +} + +static void test_strv_foreach_pair(void) { + _cleanup_strv_free_ char **a = NULL; + char **x, **y; + + a = strv_new("pair_one", "pair_one", + "pair_two", "pair_two", + "pair_three", "pair_three", + NULL); + + STRV_FOREACH_PAIR(x, y, a) { + assert_se(streq(*x, *y)); + } +} + +static void test_strv_from_stdarg_alloca_one(char **l, const char *first, ...) { + char **j; + unsigned i; + + j = strv_from_stdarg_alloca(first); + + for (i = 0;; i++) { + assert_se(streq_ptr(l[i], j[i])); + + if (!l[i]) + break; + } +} + +static void test_strv_from_stdarg_alloca(void) { + test_strv_from_stdarg_alloca_one(STRV_MAKE("foo", "bar"), "foo", "bar", NULL); + test_strv_from_stdarg_alloca_one(STRV_MAKE("foo"), "foo", NULL); + test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL); +} + +int main(int argc, char *argv[]) { + test_specifier_printf(); + test_strv_foreach(); + test_strv_foreach_backwards(); + test_strv_foreach_pair(); + test_strv_find(); + test_strv_find_prefix(); + test_strv_join(); + + test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\""); + test_strv_quote_unquote(input_table_one, "\"one\""); + test_strv_quote_unquote(input_table_none, ""); + test_strv_quote_unquote(input_table_quotes, QUOTES_STRING); + test_strv_quote_unquote(input_table_spaces, SPACES_STRING); + + test_strv_quote_unquote2(" foo=bar \"waldo\" zzz ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL }); + test_strv_quote_unquote2("", (const char*[]) { NULL }); + test_strv_quote_unquote2(" ", (const char*[]) { NULL }); + test_strv_quote_unquote2(" ", (const char*[]) { NULL }); + test_strv_quote_unquote2(" x", (const char*[]) { "x", NULL }); + test_strv_quote_unquote2("x ", (const char*[]) { "x", NULL }); + test_strv_quote_unquote2(" x ", (const char*[]) { "x", NULL }); + test_strv_quote_unquote2(" \"x\" ", (const char*[]) { "x", NULL }); + test_strv_quote_unquote2(" \'x\' ", (const char*[]) { "x", NULL }); + test_strv_quote_unquote2(" \'x\"\' ", (const char*[]) { "x\"", NULL }); + test_strv_quote_unquote2(" \"x\'\" ", (const char*[]) { "x\'", NULL }); + + test_strv_split(); + test_strv_split_newlines(); + test_strv_split_nulstr(); + test_strv_parse_nulstr(); + test_strv_overlap(); + test_strv_sort(); + test_strv_extend_strv(); + test_strv_extend_strv_concat(); + test_strv_extend(); + test_strv_from_stdarg_alloca(); + + return 0; +} diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c new file mode 100644 index 0000000..b7b70d4 --- /dev/null +++ b/src/test/test-strxcpyx.c @@ -0,0 +1,101 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "util.h" +#include "strv.h" +#include "strxcpyx.h" + +static void test_strpcpy(void) { + char target[25]; + char *s = target; + size_t space_left; + + space_left = sizeof(target); + space_left = strpcpy(&s, space_left, "12345"); + space_left = strpcpy(&s, space_left, "hey hey hey"); + space_left = strpcpy(&s, space_left, "waldo"); + space_left = strpcpy(&s, space_left, "ba"); + space_left = strpcpy(&s, space_left, "r"); + space_left = strpcpy(&s, space_left, "foo"); + + assert(streq(target, "12345hey hey heywaldobar")); + assert(space_left == 0); +} + +static void test_strpcpyf(void) { + char target[25]; + char *s = target; + size_t space_left; + + space_left = sizeof(target); + space_left = strpcpyf(&s, space_left, "space left: %zd. ", space_left); + space_left = strpcpyf(&s, space_left, "foo%s", "bar"); + + assert(streq(target, "space left: 25. foobar")); + assert(space_left == 3); +} + +static void test_strpcpyl(void) { + char target[25]; + char *s = target; + size_t space_left; + + space_left = sizeof(target); + space_left = strpcpyl(&s, space_left, "waldo", " test", " waldo. ", NULL); + space_left = strpcpyl(&s, space_left, "Banana", NULL); + + assert(streq(target, "waldo test waldo. Banana")); + assert(space_left == 1); +} + +static void test_strscpy(void) { + char target[25]; + size_t space_left; + + space_left = sizeof(target); + space_left = strscpy(target, space_left, "12345"); + + assert(streq(target, "12345")); + assert(space_left == 20); +} + +static void test_strscpyl(void) { + char target[25]; + size_t space_left; + + space_left = sizeof(target); + space_left = strscpyl(target, space_left, "12345", "waldo", "waldo", NULL); + + assert(streq(target, "12345waldowaldo")); + assert(space_left == 10); +} + +int main(int argc, char *argv[]) { + test_strpcpy(); + test_strpcpyf(); + test_strpcpyl(); + test_strscpy(); + test_strscpyl(); + + return 0; +} diff --git a/src/test/test-tables.c b/src/test/test-tables.c new file mode 100644 index 0000000..dff6431 --- /dev/null +++ b/src/test/test-tables.c @@ -0,0 +1,102 @@ +/*** + This file is part of systemd + + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "automount.h" +#include "cgroup.h" +#include "condition.h" +#include "device.h" +#include "execute.h" +#include "exit-status.h" +#include "install.h" +#include "job.h" +#include "kill.h" +#include "log.h" +#include "logs-show.h" +#include "mount.h" +#include "path-lookup.h" +#include "path.h" +#include "scope.h" +#include "service.h" +#include "slice.h" +#include "snapshot.h" +#include "socket-util.h" +#include "socket.h" +#include "swap.h" +#include "target.h" +#include "timer.h" +#include "unit-name.h" +#include "unit.h" +#include "util.h" + +#include "test-tables.h" + +int main(int argc, char **argv) { + test_table(automount_result, AUTOMOUNT_RESULT); + test_table(automount_state, AUTOMOUNT_STATE); + test_table(cgroup_device_policy, CGROUP_DEVICE_POLICY); + test_table(condition_type, CONDITION_TYPE); + test_table(device_state, DEVICE_STATE); + test_table(exec_input, EXEC_INPUT); + test_table(exec_output, EXEC_OUTPUT); + test_table(job_mode, JOB_MODE); + test_table(job_result, JOB_RESULT); + test_table(job_state, JOB_STATE); + test_table(job_type, JOB_TYPE); + test_table(kill_mode, KILL_MODE); + test_table(kill_who, KILL_WHO); + test_table(log_target, LOG_TARGET); + test_table(mount_exec_command, MOUNT_EXEC_COMMAND); + test_table(mount_result, MOUNT_RESULT); + test_table(mount_state, MOUNT_STATE); + test_table(notify_access, NOTIFY_ACCESS); + test_table(output_mode, OUTPUT_MODE); + test_table(path_result, PATH_RESULT); + test_table(path_state, PATH_STATE); + test_table(path_type, PATH_TYPE); + test_table(scope_result, SCOPE_RESULT); + test_table(scope_state, SCOPE_STATE); + test_table(service_exec_command, SERVICE_EXEC_COMMAND); + test_table(service_restart, SERVICE_RESTART); + test_table(service_result, SERVICE_RESULT); + test_table(service_state, SERVICE_STATE); + test_table(service_type, SERVICE_TYPE); + test_table(slice_state, SLICE_STATE); + test_table(snapshot_state, SNAPSHOT_STATE); + test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY); + test_table(socket_exec_command, SOCKET_EXEC_COMMAND); + test_table(socket_result, SOCKET_RESULT); + test_table(socket_state, SOCKET_STATE); + test_table(start_limit_action, SERVICE_START_LIMIT); + test_table(swap_exec_command, SWAP_EXEC_COMMAND); + test_table(swap_result, SWAP_RESULT); + test_table(swap_state, SWAP_STATE); + test_table(systemd_running_as, SYSTEMD_RUNNING_AS); + test_table(target_state, TARGET_STATE); + test_table(timer_base, TIMER_BASE); + test_table(timer_result, TIMER_RESULT); + test_table(timer_state, TIMER_STATE); + test_table(unit_active_state, UNIT_ACTIVE_STATE); + test_table(unit_dependency, UNIT_DEPENDENCY); + test_table(unit_file_change_type, UNIT_FILE_CHANGE_TYPE); + test_table(unit_file_state, UNIT_FILE_STATE); + test_table(unit_load_state, UNIT_LOAD_STATE); + test_table(unit_type, UNIT_TYPE); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-time.c b/src/test/test-time.c new file mode 100644 index 0000000..36a3304 --- /dev/null +++ b/src/test/test-time.c @@ -0,0 +1,136 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "time-util.h" + +static void test_parse_sec(void) { + usec_t u; + + assert_se(parse_sec("5s", &u) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + assert_se(parse_sec("5s500ms", &u) >= 0); + assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + assert_se(parse_sec(" 5s 500ms ", &u) >= 0); + assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + assert_se(parse_sec(" 5.5s ", &u) >= 0); + assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0); + assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500); + assert_se(parse_sec(" .22s ", &u) >= 0); + assert_se(u == 220 * USEC_PER_MSEC); + assert_se(parse_sec(" .50y ", &u) >= 0); + assert_se(u == USEC_PER_YEAR / 2); + assert_se(parse_sec("2.5", &u) >= 0); + assert_se(u == 2500 * USEC_PER_MSEC); + assert_se(parse_sec(".7", &u) >= 0); + assert_se(u == 700 * USEC_PER_MSEC); + + assert_se(parse_sec(" xyz ", &u) < 0); + assert_se(parse_sec("", &u) < 0); + assert_se(parse_sec(" . ", &u) < 0); + assert_se(parse_sec(" 5. ", &u) < 0); + assert_se(parse_sec(".s ", &u) < 0); +} + +static void test_parse_nsec(void) { + nsec_t u; + + assert_se(parse_nsec("5s", &u) >= 0); + assert_se(u == 5 * NSEC_PER_SEC); + assert_se(parse_nsec("5s500ms", &u) >= 0); + assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); + assert_se(parse_nsec(" 5s 500ms ", &u) >= 0); + assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); + assert_se(parse_nsec(" 5.5s ", &u) >= 0); + assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); + assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0); + assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC); + assert_se(parse_nsec(" .22s ", &u) >= 0); + assert_se(u == 220 * NSEC_PER_MSEC); + assert_se(parse_nsec(" .50y ", &u) >= 0); + assert_se(u == NSEC_PER_YEAR / 2); + assert_se(parse_nsec("2.5", &u) >= 0); + assert_se(u == 2); + assert_se(parse_nsec(".7", &u) >= 0); + assert_se(u == 0); + + assert_se(parse_nsec(" xyz ", &u) < 0); + assert_se(parse_nsec("", &u) < 0); + assert_se(parse_nsec(" . ", &u) < 0); + assert_se(parse_nsec(" 5. ", &u) < 0); + assert_se(parse_nsec(".s ", &u) < 0); +} + +static void test_format_timespan_one(usec_t x, usec_t accuracy) { + char *r; + char l[FORMAT_TIMESPAN_MAX]; + usec_t y; + + log_info("%llu (at accuracy %llu)", (unsigned long long) x, (unsigned long long) accuracy); + + r = format_timespan(l, sizeof(l), x, accuracy); + assert_se(r); + + log_info(" = <%s>", l); + + assert_se(parse_sec(l, &y) >= 0); + + log_info(" = %llu", (unsigned long long) y); + + if (accuracy <= 0) + accuracy = 1; + + assert_se(x / accuracy == y / accuracy); +} + +static void test_format_timespan(usec_t accuracy) { + test_format_timespan_one(0, accuracy); + test_format_timespan_one(1, accuracy); + test_format_timespan_one(1*USEC_PER_SEC, accuracy); + test_format_timespan_one(999*USEC_PER_MSEC, accuracy); + test_format_timespan_one(1234567, accuracy); + test_format_timespan_one(12, accuracy); + test_format_timespan_one(123, accuracy); + test_format_timespan_one(1234, accuracy); + test_format_timespan_one(12345, accuracy); + test_format_timespan_one(123456, accuracy); + test_format_timespan_one(1234567, accuracy); + test_format_timespan_one(12345678, accuracy); + test_format_timespan_one(1200000, accuracy); + test_format_timespan_one(1230000, accuracy); + test_format_timespan_one(1230000, accuracy); + test_format_timespan_one(1234000, accuracy); + test_format_timespan_one(1234500, accuracy); + test_format_timespan_one(1234560, accuracy); + test_format_timespan_one(1234567, accuracy); + test_format_timespan_one(986087, accuracy); + test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); + test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); +} + +int main(int argc, char *argv[]) { + test_parse_sec(); + test_parse_nsec(); + test_format_timespan(1); + test_format_timespan(USEC_PER_MSEC); + test_format_timespan(USEC_PER_SEC); + return 0; +} diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c new file mode 100644 index 0000000..565f0f8 --- /dev/null +++ b/src/test/test-tmpfiles.c @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "util.h" + +int main(int argc, char** argv) { + const char *p = argv[1] ?: "/tmp"; + char *pattern = strappenda(p, "/systemd-test-XXXXXX"); + _cleanup_close_ int fd, fd2; + _cleanup_free_ char *cmd, *cmd2; + + fd = open_tmpfile(p, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + + assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0); + system(cmd); + + fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(unlink(pattern) == 0); + + assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0); + system(cmd2); + + return 0; +} diff --git a/src/test/test-udev.c b/src/test/test-udev.c new file mode 100644 index 0000000..b064744 --- /dev/null +++ b/src/test/test-udev.c @@ -0,0 +1,167 @@ +/*** + This file is part of systemd. + + Copyright 2003-2004 Greg Kroah-Hartman + Copyright 2004-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "missing.h" +#include "udev.h" +#include "udev-util.h" + +void udev_main_log(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) {} + +static int fake_filesystems(void) { + static const struct fakefs { + const char *src; + const char *target; + const char *error; + } fakefss[] = { + { "test/sys", "/sys", "failed to mount test /sys" }, + { "test/dev", "/dev", "failed to mount test /dev" }, + { "test/run", "/run", "failed to mount test /run" }, + { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, + { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" }, + }; + unsigned int i; + int err; + + err = unshare(CLONE_NEWNS); + if (err < 0) { + err = -errno; + fprintf(stderr, "failed to call unshare(): %m\n"); + goto out; + } + + if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) { + err = -errno; + fprintf(stderr, "failed to mount / as private: %m\n"); + goto out; + } + + for (i = 0; i < ELEMENTSOF(fakefss); i++) { + err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); + if (err < 0) { + err = -errno; + fprintf(stderr, "%s %m", fakefss[i].error); + return err; + } + } +out: + return err; +} + + +int main(int argc, char *argv[]) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_event_unref_ struct udev_event *event = NULL; + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; + _cleanup_udev_rules_unref_ struct udev_rules *rules = NULL; + char syspath[UTIL_PATH_SIZE]; + const char *devpath; + const char *action; + sigset_t mask, sigmask_orig; + int err; + + err = fake_filesystems(); + if (err < 0) + return EXIT_FAILURE; + + udev = udev_new(); + if (udev == NULL) + return EXIT_FAILURE; + + log_debug("version %s", VERSION); + label_init("/dev"); + + sigprocmask(SIG_SETMASK, NULL, &sigmask_orig); + + action = argv[1]; + if (action == NULL) { + log_error("action missing"); + goto out; + } + + devpath = argv[2]; + if (devpath == NULL) { + log_error("devpath missing"); + goto out; + } + + rules = udev_rules_new(udev, 1); + + strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL); + dev = udev_device_new_from_syspath(udev, syspath); + if (dev == NULL) { + log_debug("unknown device '%s'", devpath); + goto out; + } + + udev_device_set_action(dev, action); + event = udev_event_new(dev); + + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); + event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (event->fd_signal < 0) { + fprintf(stderr, "error creating signalfd\n"); + goto out; + } + + /* do what devtmpfs usually provides us */ + if (udev_device_get_devnode(dev) != NULL) { + mode_t mode = 0600; + + if (streq(udev_device_get_subsystem(dev), "block")) + mode |= S_IFBLK; + else + mode |= S_IFCHR; + + if (!streq(action, "remove")) { + mkdir_parents_label(udev_device_get_devnode(dev), 0755); + mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev)); + } else { + unlink(udev_device_get_devnode(dev)); + util_delete_path(udev, udev_device_get_devnode(dev)); + } + } + + err = udev_event_execute_rules(event, rules, &sigmask_orig); + if (err == 0) + udev_event_execute_run(event, NULL); +out: + if (event != NULL && event->fd_signal >= 0) + close(event->fd_signal); + label_finish(); + + return err ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c new file mode 100644 index 0000000..63a8a7d --- /dev/null +++ b/src/test/test-unit-file.c @@ -0,0 +1,387 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include + +#include "install.h" +#include "install-printf.h" +#include "specifier.h" +#include "util.h" +#include "macro.h" +#include "hashmap.h" +#include "load-fragment.h" +#include "strv.h" +#include "fileio.h" +#include "test-helper.h" + +static int test_unit_file_get_set(void) { + int r; + Hashmap *h; + Iterator i; + UnitFileList *p; + + h = hashmap_new(string_hash_func, string_compare_func); + assert(h); + + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + log_full(r == 0 ? LOG_INFO : LOG_ERR, + "unit_file_get_list: %s", strerror(-r)); + if (r < 0) + return EXIT_FAILURE; + + HASHMAP_FOREACH(p, h, i) + printf("%s = %s\n", p->path, unit_file_state_to_string(p->state)); + + unit_file_list_free(h); + + return 0; +} + +static void check_execcommand(ExecCommand *c, + const char* path, + const char* argv0, + const char* argv1, + bool ignore) { + assert_se(c); + log_info("%s %s %s %s", + c->path, c->argv[0], c->argv[1], c->argv[2]); + assert_se(streq(c->path, path)); + assert_se(streq(c->argv[0], argv0)); + assert_se(streq(c->argv[1], argv1)); + assert_se(c->argv[2] == NULL); + assert_se(c->ignore == ignore); +} + +static void test_config_parse_exec(void) { + /* int config_parse_exec( */ + /* 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; + + ExecCommand *c = NULL, *c1; + + /* basic test */ + r = config_parse_exec(NULL, "fake", 1, "section", 1, + "LValue", 0, "/RValue r1", + &c, NULL); + assert_se(r >= 0); + check_execcommand(c, "/RValue", "/RValue", "r1", false); + + r = config_parse_exec(NULL, "fake", 2, "section", 1, + "LValue", 0, "/RValue///slashes/// r1", + &c, NULL); + /* test slashes */ + assert_se(r >= 0); + c1 = c->command_next; + check_execcommand(c1, "/RValue/slashes", "/RValue///slashes///", + "r1", false); + + /* honour_argv0 */ + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, "@/RValue///slashes2/// argv0 r1", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue/slashes2", "argv0", "r1", false); + + /* ignore && honour_argv0 */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "-@/RValue///slashes3/// argv0a r1", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/RValue/slashes3", "argv0a", "r1", true); + + /* ignore && honour_argv0 */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "@-/RValue///slashes4/// argv0b r1", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/RValue/slashes4", "argv0b", "r1", true); + + /* ignore && ignore */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "--/RValue argv0 r1", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + /* ignore && ignore */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "-@-/RValue argv0 r1", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + /* semicolon */ + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; " + "/goo/goo boo", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/RValue", "argv0", "r1", true); + + c1 = c1->command_next; + check_execcommand(c1, + "/goo/goo", "/goo/goo", "boo", false); + + /* trailing semicolon */ + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; ", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/RValue", "argv0", "r1", true); + + assert_se(c1->command_next == NULL); + + /* escaped semicolon */ + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/usr/bin/find \\;", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/usr/bin/find", "/usr/bin/find", ";", false); + + exec_command_free_list(c); +} + +#define env_file_1 \ + "a=a\n" \ + "b=b\\\n" \ + "c\n" \ + "d=d\\\n" \ + "e\\\n" \ + "f\n" \ + "g=g\\ \n" \ + "h=h\n" \ + "i=i\\" + +#define env_file_2 \ + "a=a\\\n" + +#define env_file_3 \ + "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \ + "#--nouser-config \\\n" \ + "normal=line" + +#define env_file_4 \ + "# Generated\n" \ + "\n" \ + "HWMON_MODULES=\"coretemp f71882fg\"\n" \ + "\n" \ + "# For compatibility reasons\n" \ + "\n" \ + "MODULE_0=coretemp\n" \ + "MODULE_1=f71882fg" + + +static void test_load_env_file_1(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1)); + + r = load_env_file(name, NULL, &data); + assert(r == 0); + assert(streq(data[0], "a=a")); + assert(streq(data[1], "b=bc")); + assert(streq(data[2], "d=def")); + assert(streq(data[3], "g=g ")); + assert(streq(data[4], "h=h")); + assert(streq(data[5], "i=i")); + assert(data[6] == NULL); + unlink(name); +} + +static void test_load_env_file_2(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2)); + + r = load_env_file(name, NULL, &data); + assert(r == 0); + assert(streq(data[0], "a=a")); + assert(data[1] == NULL); + unlink(name); +} + +static void test_load_env_file_3(void) { + _cleanup_strv_free_ char **data = NULL; + int r; + + char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3)); + + r = load_env_file(name, NULL, &data); + assert(r == 0); + assert(data == NULL); + unlink(name); +} + +static void test_load_env_file_4(void) { + _cleanup_strv_free_ char **data = NULL; + char name[] = "/tmp/test-load-env-file.XXXXXX"; + _cleanup_close_ int fd; + int r; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert(fd >= 0); + assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4)); + + r = load_env_file(name, NULL, &data); + assert(r == 0); + assert(streq(data[0], "HWMON_MODULES=coretemp f71882fg")); + assert(streq(data[1], "MODULE_0=coretemp")); + assert(streq(data[2], "MODULE_1=f71882fg")); + assert(data[3] == NULL); + unlink(name); +} + + +static void test_install_printf(void) { + char name[] = "name.service", + path[] = "/run/systemd/system/name.service", + user[] = "xxxx-no-such-user"; + InstallInfo i = {name, path, user}; + InstallInfo i2 = {name, path, NULL}; + char name3[] = "name@inst.service", + path3[] = "/run/systemd/system/name.service"; + InstallInfo i3 = {name3, path3, user}; + InstallInfo i4 = {name3, path3, NULL}; + + _cleanup_free_ char *mid, *bid, *host; + + assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); + assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); + assert_se((host = gethostname_malloc())); + +#define expect(src, pattern, result) \ + do { \ + _cleanup_free_ char *t = NULL; \ + _cleanup_free_ char \ + *d1 = strdup(i.name), \ + *d2 = strdup(i.path), \ + *d3 = strdup(i.user); \ + assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \ + memzero(i.name, strlen(i.name)); \ + memzero(i.path, strlen(i.path)); \ + memzero(i.user, strlen(i.user)); \ + assert(d1 && d2 && d3); \ + if (result) { \ + printf("%s\n", t); \ + assert(streq(t, result)); \ + } else assert(t == NULL); \ + strcpy(i.name, d1); \ + strcpy(i.path, d2); \ + strcpy(i.user, d3); \ + } while(false) + + assert_se(setenv("USER", "root", 1) == 0); + + expect(i, "%n", "name.service"); + expect(i, "%N", "name"); + expect(i, "%p", "name"); + expect(i, "%i", ""); + expect(i, "%u", "xxxx-no-such-user"); + + DISABLE_WARNING_NONNULL; + expect(i, "%U", NULL); + REENABLE_WARNING; + + expect(i, "%m", mid); + expect(i, "%b", bid); + expect(i, "%H", host); + + expect(i2, "%u", "root"); + expect(i2, "%U", "0"); + + expect(i3, "%n", "name@inst.service"); + expect(i3, "%N", "name@inst"); + expect(i3, "%p", "name"); + expect(i3, "%u", "xxxx-no-such-user"); + + DISABLE_WARNING_NONNULL; + expect(i3, "%U", NULL); + REENABLE_WARNING; + + expect(i3, "%m", mid); + expect(i3, "%b", bid); + expect(i3, "%H", host); + + expect(i4, "%u", "root"); + expect(i4, "%U", "0"); +} + +int main(int argc, char *argv[]) { + int r; + + log_parse_environment(); + log_open(); + + r = test_unit_file_get_set(); + test_config_parse_exec(); + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); + test_load_env_file_4(); + TEST_REQ_RUNNING_SYSTEMD(test_install_printf()); + + return r; +} diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c new file mode 100644 index 0000000..fff3e16 --- /dev/null +++ b/src/test/test-unit-name.c @@ -0,0 +1,201 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "manager.h" +#include "unit.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "install.h" +#include "specifier.h" +#include "util.h" +#include "macro.h" +#include "test-helper.h" + +static void test_replacements(void) { +#define expect(pattern, repl, expected) \ + { \ + _cleanup_free_ char *t = \ + unit_name_replace_instance(pattern, repl); \ + puts(t); \ + assert(streq(t, expected)); \ + } + + expect("foo@.service", "waldo", "foo@waldo.service"); + expect("foo@xyz.service", "waldo", "foo@waldo.service"); + expect("xyz", "waldo", "xyz"); + expect("", "waldo", ""); + expect("foo.service", "waldo", "foo.service"); + expect(".service", "waldo", ".service"); + expect("foo@", "waldo", "foo@waldo"); + expect("@bar", "waldo", "@waldo"); + + puts("-------------------------------------------------"); +#undef expect +#define expect(path, suffix, expected) \ + { \ + _cleanup_free_ char *k, *t = \ + unit_name_from_path(path, suffix); \ + puts(t); \ + k = unit_name_to_path(t); \ + puts(k); \ + assert(streq(k, expected ? expected : path)); \ + } + + expect("/waldo", ".mount", NULL); + expect("/waldo/quuix", ".mount", NULL); + expect("/waldo/quuix/", ".mount", "/waldo/quuix"); + expect("/", ".mount", NULL); + expect("///", ".mount", "/"); + + puts("-------------------------------------------------"); +#undef expect +#define expect(pattern, path, suffix, expected) \ + { \ + _cleanup_free_ char *t = \ + unit_name_from_path_instance(pattern, path, suffix); \ + puts(t); \ + assert(streq(t, expected)); \ + } + + expect("waldo", "/waldo", ".mount", "waldo@waldo.mount"); + expect("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount"); + expect("waldo", "/", ".mount", "waldo@-.mount"); + expect("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount"); + + puts("-------------------------------------------------"); +#undef expect +#define expect(pattern) \ + { \ + _cleanup_free_ char *k, *t; \ + assert_se(t = unit_name_mangle(pattern, MANGLE_NOGLOB)); \ + assert_se(k = unit_name_mangle(t, MANGLE_NOGLOB)); \ + puts(t); \ + assert_se(streq(t, k)); \ + } + + expect("/home"); + expect("/dev/sda"); + expect("üxknürz.service"); + expect("foobar-meh...waldi.service"); + expect("_____####----.....service"); + expect("_____##@;;;,,,##----.....service"); + expect("xxx@@@@/////\\\\\\\\\\yyy.service"); + +#undef expect +} + +static int test_unit_printf(void) { + Manager *m = NULL; + Unit *u, *u2; + int r; + + _cleanup_free_ char *mid, *bid, *host, *root_uid; + struct passwd *root; + + assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); + assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); + assert_se((host = gethostname_malloc())); + + assert_se((root = getpwnam("root"))); + assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0); + + r = manager_new(SYSTEMD_USER, &m); + if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) { + puts("manager_new: Permission denied. Skipping test."); + return EXIT_TEST_SKIP; + } + assert(r == 0); + +#define expect(unit, pattern, expected) \ + { \ + char *e; \ + _cleanup_free_ char *t; \ + assert_se(unit_full_printf(unit, pattern, &t) >= 0); \ + printf("result: %s\nexpect: %s\n", t, expected); \ + if ((e = endswith(expected, "*"))) \ + assert(strncmp(t, e, e-expected)); \ + else \ + assert(streq(t, expected)); \ + } + + assert_se(setenv("USER", "root", 1) == 0); + assert_se(setenv("HOME", "/root", 1) == 0); + + assert_se(u = unit_new(m, sizeof(Service))); + assert_se(unit_add_name(u, "blah.service") == 0); + assert_se(unit_add_name(u, "blah.service") == 0); + + /* general tests */ + expect(u, "%%", "%"); + expect(u, "%%s", "%s"); + expect(u, "%", ""); // REALLY? + + /* normal unit */ + expect(u, "%n", "blah.service"); + expect(u, "%N", "blah"); + expect(u, "%p", "blah"); + expect(u, "%P", "blah"); + expect(u, "%i", ""); + expect(u, "%u", root->pw_name); + expect(u, "%U", root_uid); + expect(u, "%h", root->pw_dir); + expect(u, "%m", mid); + expect(u, "%b", bid); + expect(u, "%H", host); + expect(u, "%t", "/run/user/*"); + + /* templated */ + assert_se(u2 = unit_new(m, sizeof(Service))); + assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0); + assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0); + + expect(u2, "%n", "blah@foo-foo.service"); + expect(u2, "%N", "blah@foo-foo"); + expect(u2, "%p", "blah"); + expect(u2, "%P", "blah"); + expect(u2, "%i", "foo-foo"); + expect(u2, "%I", "foo/foo"); + expect(u2, "%u", root->pw_name); + expect(u2, "%U", root_uid); + expect(u2, "%h", root->pw_dir); + expect(u2, "%m", mid); + expect(u2, "%b", bid); + expect(u2, "%H", host); + expect(u2, "%t", "/run/user/*"); + + manager_free(m); + + return 0; +} + +int main(int argc, char* argv[]) { + int rc = 0; + test_replacements(); + TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf()); + return rc; +} diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c new file mode 100644 index 0000000..b7d988f --- /dev/null +++ b/src/test/test-utf8.c @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Dave Reisner + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "utf8.h" +#include "util.h" + +static void test_utf8_is_printable(void) { + assert_se(utf8_is_printable("ascii is valid\tunicode", 22)); + assert_se(utf8_is_printable("\342\204\242", 3)); + assert_se(!utf8_is_printable("\341\204", 2)); + assert_se(utf8_is_printable("ąę", 4)); +} + +static void test_utf8_is_valid(void) { + assert_se(utf8_is_valid("ascii is valid unicode")); + assert_se(utf8_is_valid("\342\204\242")); + assert_se(!utf8_is_valid("\341\204")); +} + +static void test_ascii_is_valid(void) { + assert_se(ascii_is_valid("alsdjf\t\vbarr\nba z")); + assert_se(!ascii_is_valid("\342\204\242")); + assert_se(!ascii_is_valid("\341\204")); +} + +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); + +} + +static void test_utf8_escaping(void) { + _cleanup_free_ char *p1, *p2, *p3; + + p1 = utf8_escape_invalid("goo goo goo"); + puts(p1); + assert_se(utf8_is_valid(p1)); + + p2 = utf8_escape_invalid("\341\204\341\204"); + puts(p2); + assert_se(utf8_is_valid(p2)); + + p3 = utf8_escape_invalid("\341\204"); + puts(p3); + assert_se(utf8_is_valid(p3)); +} + +int main(int argc, char *argv[]) { + test_utf8_is_valid(); + test_utf8_is_printable(); + test_ascii_is_valid(); + test_utf8_encoded_valid_unichar(); + test_utf8_escaping(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c new file mode 100644 index 0000000..b718206 --- /dev/null +++ b/src/test/test-util.c @@ -0,0 +1,630 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "strv.h" +#include "def.h" +#include "fileio.h" + +static void test_streq_ptr(void) { + assert_se(streq_ptr(NULL, NULL)); + assert_se(!streq_ptr("abc", "cdef")); +} + +static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); + assert_se(first_word("Hello world", "Hello")); + assert_se(first_word("Hello\tworld", "Hello")); + assert_se(first_word("Hello\nworld", "Hello")); + assert_se(first_word("Hello\rworld", "Hello")); + assert_se(first_word("Hello ", "Hello")); + + assert_se(!first_word("Hello", "Hellooo")); + assert_se(!first_word("Hello", "xxxxx")); + assert_se(!first_word("Hellooo", "Hello")); +} + +static void test_close_many(void) { + int fds[3]; + char name0[] = "/tmp/test-close-many.XXXXXX"; + char name1[] = "/tmp/test-close-many.XXXXXX"; + char name2[] = "/tmp/test-close-many.XXXXXX"; + + fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); + fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); + fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); + + close_many(fds, 2); + + assert_se(fcntl(fds[0], F_GETFD) == -1); + assert_se(fcntl(fds[1], F_GETFD) == -1); + assert_se(fcntl(fds[2], F_GETFD) >= 0); + + close_nointr_nofail(fds[2]); + + unlink(name0); + unlink(name1); + unlink(name2); +} + +static void test_parse_boolean(void) { + assert_se(parse_boolean("1") == 1); + assert_se(parse_boolean("y") == 1); + assert_se(parse_boolean("Y") == 1); + assert_se(parse_boolean("yes") == 1); + assert_se(parse_boolean("YES") == 1); + assert_se(parse_boolean("true") == 1); + assert_se(parse_boolean("TRUE") == 1); + assert_se(parse_boolean("on") == 1); + assert_se(parse_boolean("ON") == 1); + + assert_se(parse_boolean("0") == 0); + assert_se(parse_boolean("n") == 0); + assert_se(parse_boolean("N") == 0); + assert_se(parse_boolean("no") == 0); + assert_se(parse_boolean("NO") == 0); + assert_se(parse_boolean("false") == 0); + assert_se(parse_boolean("FALSE") == 0); + assert_se(parse_boolean("off") == 0); + assert_se(parse_boolean("OFF") == 0); + + assert_se(parse_boolean("garbage") < 0); + assert_se(parse_boolean("") < 0); +} + +static void test_parse_pid(void) { + int r; + pid_t pid; + + r = parse_pid("100", &pid); + assert_se(r == 0); + assert_se(pid == 100); + + r = parse_pid("0x7FFFFFFF", &pid); + assert_se(r == 0); + assert_se(pid == 2147483647); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("-100", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); + assert(r == -ERANGE); + assert_se(pid == 65); +} + +static void test_parse_uid(void) { + int r; + uid_t uid; + + r = parse_uid("100", &uid); + assert_se(r == 0); + assert_se(uid == 100); +} + +static void test_safe_atolli(void) { + int r; + long long l; + + r = safe_atolli("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atod(void) { + int r; + double d; + char *e; + + r = safe_atod("junk", &d); + assert_se(r == -EINVAL); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(abs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); + + /* Check if this really is locale independent */ + setlocale(LC_NUMERIC, "de_DE.utf8"); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(abs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + assert_se(abs(strtod("0,5", &e) - 0.5) < 0.00001); + + /* And check again, reset */ + setlocale(LC_NUMERIC, "C"); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(abs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); +} + +static void test_strappend(void) { + _cleanup_free_ char *t1, *t2, *t3, *t4; + + t1 = strappend(NULL, NULL); + assert_se(streq(t1, "")); + + t2 = strappend(NULL, "suf"); + assert_se(streq(t2, "suf")); + + t3 = strappend("pre", NULL); + assert_se(streq(t3, "pre")); + + t4 = strappend("pre", "suf"); + assert_se(streq(t4, "presuf")); +} + +static void test_strstrip(void) { + char *r; + char input[] = " hello, waldo. "; + + r = strstrip(input); + assert_se(streq(r, "hello, waldo.")); +} + +static void test_delete_chars(void) { + char *r; + char input[] = " hello, waldo. abc"; + + r = delete_chars(input, WHITESPACE); + assert_se(streq(r, "hello,waldo.abc")); +} + +static void test_in_charset(void) { + assert_se(in_charset("dddaaabbbcccc", "abcd")); + assert_se(!in_charset("dddaaabbbcccc", "abc f")); +} + +static void test_hexchar(void) { + assert_se(hexchar(0xa) == 'a'); + assert_se(hexchar(0x0) == '0'); +} + +static void test_unhexchar(void) { + assert_se(unhexchar('a') == 0xA); + assert_se(unhexchar('A') == 0xA); + assert_se(unhexchar('0') == 0x0); +} + +static void test_octchar(void) { + assert_se(octchar(00) == '0'); + assert_se(octchar(07) == '7'); +} + +static void test_unoctchar(void) { + assert_se(unoctchar('0') == 00); + assert_se(unoctchar('7') == 07); +} + +static void test_decchar(void) { + assert_se(decchar(0) == '0'); + assert_se(decchar(9) == '9'); +} + +static void test_undecchar(void) { + assert_se(undecchar('0') == 0); + assert_se(undecchar('9') == 9); +} + +static void test_cescape(void) { + _cleanup_free_ char *escaped; + escaped = cescape("abc\\\"\b\f\n\r\t\v\003\177\234\313"); + assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\003\\177\\234\\313")); +} + +static void test_cunescape(void) { + _cleanup_free_ char *unescaped; + unescaped = cunescape("abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\003\\177\\234\\313"); + assert_se(streq(unescaped, "abc\\\"\b\f\n\r\t\v\003\177\234\313")); +} + +static void test_foreach_word(void) { + char *w, *state; + size_t l; + int i = 0; + const char test[] = "test abc d\te f "; + const char * const expected[] = { + "test", + "abc", + "d", + "e", + "f", + "", + NULL + }; + + FOREACH_WORD(w, l, test, state) { + assert_se(strneq(expected[i++], w, l)); + } +} + +static void test_foreach_word_quoted(void) { + char *w, *state; + size_t l; + int i = 0; + const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\""; + const char * const expected[] = { + "test", + "a", + "b", + "c", + "d", + "e", + "", + "", + "hhh", + "", + "", + "a b c", + NULL + }; + + printf("<%s>\n", test); + FOREACH_WORD_QUOTED(w, l, test, state) { + _cleanup_free_ char *t = NULL; + + assert_se(t = strndup(w, l)); + assert_se(strneq(expected[i++], w, l)); + printf("<%s>\n", t); + } +} + +static void test_default_term_for_tty(void) { + puts(default_term_for_tty("/dev/tty23")); + puts(default_term_for_tty("/dev/ttyS23")); + puts(default_term_for_tty("/dev/tty0")); + puts(default_term_for_tty("/dev/pty0")); + puts(default_term_for_tty("/dev/pts/0")); + puts(default_term_for_tty("/dev/console")); + puts(default_term_for_tty("tty23")); + puts(default_term_for_tty("ttyS23")); + puts(default_term_for_tty("tty0")); + puts(default_term_for_tty("pty0")); + puts(default_term_for_tty("pts/0")); + puts(default_term_for_tty("console")); +} + +static void test_memdup_multiply(void) { + int org[] = {1, 2, 3}; + int *dup; + + dup = (int*)memdup_multiply(org, sizeof(int), 3); + + assert_se(dup); + assert_se(dup[0] == 1); + assert_se(dup[1] == 2); + assert_se(dup[2] == 3); + free(dup); +} + +static void test_hostname_is_valid(void) { + assert(hostname_is_valid("foobar")); + assert(hostname_is_valid("foobar.com")); + assert(!hostname_is_valid("fööbar")); + assert(!hostname_is_valid("")); + assert(!hostname_is_valid(".")); + assert(!hostname_is_valid("..")); + assert(!hostname_is_valid("foobar.")); + assert(!hostname_is_valid(".foobar")); + assert(!hostname_is_valid("foo..bar")); + assert(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); +} + +static void test_u64log2(void) { + assert(u64log2(0) == 0); + assert(u64log2(8) == 3); + assert(u64log2(9) == 3); + assert(u64log2(15) == 3); + assert(u64log2(16) == 4); + assert(u64log2(1024*1024) == 20); + assert(u64log2(1024*1024+5) == 20); +} + +static void test_get_process_comm(void) { + struct stat st; + _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL; + unsigned long long b; + pid_t e; + uid_t u; + gid_t g; + dev_t h; + int r; + + if (stat("/proc/1/comm", &st) == 0) { + assert_se(get_process_comm(1, &a) >= 0); + log_info("pid1 comm: '%s'", a); + } else { + log_warning("/proc/1/comm does not exist."); + } + + assert_se(get_starttime_of_pid(1, &b) >= 0); + log_info("pid1 starttime: '%llu'", b); + + assert_se(get_process_cmdline(1, 0, true, &c) >= 0); + log_info("pid1 cmdline: '%s'", c); + + assert_se(get_process_cmdline(1, 8, false, &d) >= 0); + log_info("pid1 cmdline truncated: '%s'", d); + + assert_se(get_parent_of_pid(1, &e) >= 0); + log_info("pid1 ppid: '%llu'", (unsigned long long) e); + assert_se(e == 0); + + assert_se(is_kernel_thread(1) == 0); + + r = get_process_exe(1, &f); + assert_se(r >= 0 || r == -EACCES); + log_info("pid1 exe: '%s'", strna(f)); + + assert_se(get_process_uid(1, &u) == 0); + log_info("pid1 uid: '%llu'", (unsigned long long) u); + assert_se(u == 0); + + assert_se(get_process_gid(1, &g) == 0); + log_info("pid1 gid: '%llu'", (unsigned long long) g); + assert_se(g == 0); + + assert(get_ctty_devnr(1, &h) == -ENOENT); + + getenv_for_pid(1, "PATH", &i); + log_info("pid1 $PATH: '%s'", strna(i)); +} + +static void test_protect_errno(void) { + errno = 12; + { + PROTECT_ERRNO; + errno = 11; + } + assert(errno == 12); +} + +static void test_parse_size(void) { + off_t bytes; + + assert_se(parse_size("111", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size(" 112 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size("3 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size(" 4 M 11K", 1024, &bytes) == 0); + assert_se(bytes == 4*1024*1024 + 11 * 1024); + + assert_se(parse_size("3B3G", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 3); + + assert_se(parse_size("3B3G4T", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size("12P", 1024, &bytes) == 0); + assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); + + assert_se(parse_size("3E 2P", 1024, &bytes) == 0); + assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); +} + +static void test_strextend(void) { + _cleanup_free_ char *str = strdup("0123"); + strextend(&str, "456", "78", "9", NULL); + assert_se(streq(str, "0123456789")); +} + +static void test_strrep(void) { + _cleanup_free_ char *one, *three, *zero; + one = strrep("waldo", 1); + three = strrep("waldo", 3); + zero = strrep("waldo", 0); + + assert_se(streq(one, "waldo")); + assert_se(streq(three, "waldowaldowaldo")); + assert_se(streq(zero, "")); +} + +static void test_split_pair(void) { + _cleanup_free_ char *a = NULL, *b = NULL; + + assert_se(split_pair("", "", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); + assert_se(split_pair("", "=", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); + assert_se(streq(a, "foo")); + assert_se(streq(b, "bar")); + free(a); + free(b); + assert_se(split_pair("==", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "")); + free(a); + free(b); + + assert_se(split_pair("===", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "=")); +} + +static void test_fstab_node_to_udev_node(void) { + char *n; + + n = fstab_node_to_udev_node("LABEL=applé/jack"); + puts(n); + assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); + free(n); + + n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); + free(n); + + n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + + n = fstab_node_to_udev_node("PONIES=awesome"); + puts(n); + assert_se(streq(n, "PONIES=awesome")); + free(n); + + n = fstab_node_to_udev_node("/dev/xda1"); + puts(n); + assert_se(streq(n, "/dev/xda1")); + free(n); +} + +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &t) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + +static void test_in_set(void) { + assert_se(IN_SET(1, 1)); + assert_se(IN_SET(1, 1, 2, 3, 4)); + assert_se(IN_SET(2, 1, 2, 3, 4)); + assert_se(IN_SET(3, 1, 2, 3, 4)); + assert_se(IN_SET(4, 1, 2, 3, 4)); + assert_se(!IN_SET(0, 1)); + assert_se(!IN_SET(0, 1, 2, 3, 4)); +} + +static void test_writing_tmpfile(void) { + char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; + _cleanup_free_ char *contents = NULL; + size_t size; + int fd, r; + struct iovec iov[3]; + + IOVEC_SET_STRING(iov[0], "abc\n"); + IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); + IOVEC_SET_STRING(iov[2], ""); + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + printf("tmpfile: %s", name); + + r = writev(fd, iov, 3); + assert(r >= 0); + + r = read_full_file(name, &contents, &size); + assert(r == 0); + printf("contents: %s", contents); + assert(streq(contents, "abc\n" ALPHANUMERICAL "\n")); +} + +int main(int argc, char *argv[]) { + test_streq_ptr(); + test_first_word(); + test_close_many(); + test_parse_boolean(); + test_parse_pid(); + test_parse_uid(); + test_safe_atolli(); + test_safe_atod(); + test_strappend(); + test_strstrip(); + test_delete_chars(); + test_in_charset(); + test_hexchar(); + test_unhexchar(); + test_octchar(); + test_unoctchar(); + test_decchar(); + test_undecchar(); + test_cescape(); + test_cunescape(); + test_foreach_word(); + test_foreach_word_quoted(); + test_default_term_for_tty(); + test_memdup_multiply(); + test_hostname_is_valid(); + test_u64log2(); + test_get_process_comm(); + test_protect_errno(); + test_parse_size(); + test_strextend(); + test_strrep(); + test_split_pair(); + test_fstab_node_to_udev_node(); + test_get_files_in_directory(); + test_in_set(); + test_writing_tmpfile(); + + return 0; +} diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c new file mode 100644 index 0000000..ccb1854 --- /dev/null +++ b/src/test/test-watchdog.c @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "watchdog.h" +#include "log.h" + +int main(int argc, char *argv[]) { + usec_t t = 10 * USEC_PER_SEC; + unsigned i; + int r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + r = watchdog_set_timeout(&t); + if (r < 0) + log_warning("Failed to open watchdog: %s", strerror(-r)); + + for (i = 0; i < 5; i++) { + log_info("Pinging..."); + r = watchdog_ping(); + if (r < 0) + log_warning("Failed to ping watchdog: %s", strerror(-r)); + + usleep(t/2); + } + + watchdog_close(true); + return 0; +} diff --git a/src/test/test-xml.c b/src/test/test-xml.c new file mode 100644 index 0000000..7a34f14 --- /dev/null +++ b/src/test/test-xml.c @@ -0,0 +1,83 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include + +#include "xml.h" +#include "util.h" + +static void test_one(const char *data, ...) { + void *state = NULL; + va_list ap; + + va_start(ap, data); + + for (;;) { + _cleanup_free_ char *name = NULL; + int t, tt; + const char *nn; + + t = xml_tokenize(&data, &name, &state); + assert_se(t >= 0); + + tt = va_arg(ap, int); + assert_se(tt >= 0); + + assert_se(t == tt); + if (t == XML_END) + break; + + nn = va_arg(ap, const char *); + assert_se(streq_ptr(nn, name)); + } + + va_end(ap); +} + +int main(int argc, char *argv[]) { + + test_one("", XML_END); + + test_one("", + XML_TAG_OPEN, "foo", + XML_TAG_CLOSE, "foo", + XML_END); + + test_one("", + XML_TAG_OPEN, "foo", + XML_ATTRIBUTE_NAME, "waldo", + XML_ATTRIBUTE_VALUE, "piep", + XML_ATTRIBUTE_NAME, "meh", + XML_ATTRIBUTE_VALUE, "huhu", + XML_TAG_CLOSE_EMPTY, NULL, + XML_END); + + test_one("xxxx\n" + " ", + XML_TEXT, "xxxx\n", + XML_TAG_OPEN, "foo", + XML_TEXT, " ", + XML_TEXT, " ", + XML_TAG_CLOSE, "foo", + XML_END); + + return 0; +} diff --git a/src/timedate/.gitignore b/src/timedate/.gitignore new file mode 100644 index 0000000..48757f0 --- /dev/null +++ b/src/timedate/.gitignore @@ -0,0 +1 @@ +org.freedesktop.timedate1.policy diff --git a/src/timedate/Makefile b/src/timedate/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/timedate/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/timedate/org.freedesktop.timedate1.conf b/src/timedate/org.freedesktop.timedate1.conf new file mode 100644 index 0000000..36557d5 --- /dev/null +++ b/src/timedate/org.freedesktop.timedate1.conf @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/timedate/org.freedesktop.timedate1.policy.in b/src/timedate/org.freedesktop.timedate1.policy.in new file mode 100644 index 0000000..aa30b70 --- /dev/null +++ b/src/timedate/org.freedesktop.timedate1.policy.in @@ -0,0 +1,62 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Set system time + <_message>Authentication is required to set the system time. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.timedate1.set-timezone org.freedesktop.timedate1.set-ntp + + + + <_description>Set system timezone + <_message>Authentication is required to set the system timezone. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Set RTC to local timezone or UTC + <_message>Authentication is required to control whether + the RTC stores the local or UTC time. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Turn network time synchronization on or off + <_message>Authentication is required to control whether + network time synchronization shall be enabled. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + diff --git a/src/timedate/org.freedesktop.timedate1.service b/src/timedate/org.freedesktop.timedate1.service new file mode 100644 index 0000000..875f4be --- /dev/null +++ b/src/timedate/org.freedesktop.timedate1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.timedate1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.timedate1.service diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c new file mode 100644 index 0000000..089a5fe --- /dev/null +++ b/src/timedate/timedatectl.c @@ -0,0 +1,619 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "bus-util.h" +#include "bus-error.h" +#include "util.h" +#include "spawn-polkit-agent.h" +#include "build.h" +#include "strv.h" +#include "pager.h" +#include "time-dst.h" + +static bool arg_no_pager = false; +static bool arg_ask_password = true; +static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static char *arg_host = NULL; +static bool arg_adjust_system_clock = false; + +static void pager_open_if_enabled(void) { + + if (arg_no_pager) + return; + + pager_open(false); +} + +static void polkit_agent_open_if_enabled(void) { + + /* Open the polkit agent as a child process if necessary */ + if (!arg_ask_password) + return; + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return; + + polkit_agent_open(); +} + +typedef struct StatusInfo { + usec_t time; + char *timezone; + + usec_t rtc_time; + bool rtc_local; + + bool ntp_enabled; + bool ntp_capable; + bool ntp_synced; +} StatusInfo; + +static const char *jump_str(int delta_minutes, char *s, size_t size) { + if (delta_minutes == 60) + return "one hour forward"; + if (delta_minutes == -60) + return "one hour backwards"; + if (delta_minutes < 0) { + snprintf(s, size, "%i minutes backwards", -delta_minutes); + return s; + } + if (delta_minutes > 0) { + snprintf(s, size, "%i minutes forward", delta_minutes); + return s; + } + return ""; +} + +static void print_status_info(const StatusInfo *i) { + char a[FORMAT_TIMESTAMP_MAX]; + char b[FORMAT_TIMESTAMP_MAX]; + char s[32]; + struct tm tm; + time_t sec; + bool have_time = false; + _cleanup_free_ char *zc = NULL, *zn = NULL; + time_t t, tc, tn; + int dn = 0; + bool is_dstc = false, is_dstn = false; + int r; + + assert(i); + + /* Enforce the values of /etc/localtime */ + if (getenv("TZ")) { + fprintf(stderr, "Warning: ignoring the TZ variable, reading the system's timezone setting only.\n\n"); + unsetenv("TZ"); + } + + if (i->time != 0) { + sec = (time_t) (i->time / USEC_PER_SEC); + have_time = true; + } else if (arg_transport == BUS_TRANSPORT_LOCAL) { + sec = time(NULL); + have_time = true; + } else + fprintf(stderr, "Warning: could not get time from timedated and not operating locally.\n\n"); + + if (have_time) { + zero(tm); + assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0); + char_array_0(a); + printf(" Local time: %s\n", a); + + zero(tm); + assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0); + char_array_0(a); + printf(" Universal time: %s\n", a); + } else { + printf(" Local time: %s\n", "n/a"); + printf(" Universal time: %s\n", "n/a"); + } + + if (i->rtc_time > 0) { + time_t rtc_sec; + + rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC); + zero(tm); + assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm)) > 0); + char_array_0(a); + printf(" RTC time: %s\n", a); + } else + printf(" RTC time: %s\n", "n/a"); + + zero(tm); + assert_se(strftime(a, sizeof(a), "%Z, %z", localtime_r(&sec, &tm)) > 0); + char_array_0(a); + printf(" Timezone: %s (%s)\n" + " NTP enabled: %s\n" + "NTP synchronized: %s\n" + " RTC in local TZ: %s\n", + strna(i->timezone), a, + i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a", + yes_no(i->ntp_synced), + yes_no(i->rtc_local)); + + r = time_get_dst(sec, "/etc/localtime", + &tc, &zc, &is_dstc, + &tn, &dn, &zn, &is_dstn); + if (r < 0) + printf(" DST active: %s\n", "n/a"); + else if (have_time) { + printf(" DST active: %s\n", yes_no(is_dstc)); + + t = tc - 1; + zero(tm); + assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0); + char_array_0(a); + + zero(tm); + assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0); + char_array_0(b); + printf(" Last DST change: DST %s at\n" + " %s\n" + " %s\n", + is_dstc ? "began" : "ended", a, b); + + t = tn - 1; + zero(tm); + assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0); + char_array_0(a); + + zero(tm); + assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0); + char_array_0(b); + printf(" Next DST change: DST %s (the clock jumps %s) at\n" + " %s\n" + " %s\n", + is_dstn ? "begins" : "ends", jump_str(dn, s, sizeof(s)), a, b); + } else + printf(" DST active: %s\n", yes_no(is_dstc)); + + if (i->rtc_local) + fputs("\n" ANSI_HIGHLIGHT_ON + "Warning: The RTC is configured to maintain time in the local timezone. This\n" + " mode is not fully supported and will create various problems with time\n" + " zone changes and daylight saving adjustments. If at all possible use\n" + " RTC in UTC, by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout); +} + +static int show_status(sd_bus *bus, char **args, unsigned n) { + StatusInfo info = {}; + static const struct bus_properties_map map[] = { + { "Timezone", "s", NULL, offsetof(StatusInfo, timezone) }, + { "LocalRTC", "b", NULL, offsetof(StatusInfo, rtc_local) }, + { "NTP", "b", NULL, offsetof(StatusInfo, ntp_enabled) }, + { "CanNTP", "b", NULL, offsetof(StatusInfo, ntp_capable) }, + { "NTPSynchronized", "b", NULL, offsetof(StatusInfo, ntp_synced) }, + { "TimeUSec", "t", NULL, offsetof(StatusInfo, time) }, + { "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) }, + {} + }; + int r; + + assert(bus); + + r = bus_map_all_properties(bus, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + map, + &info); + if (r < 0) { + log_error("Failed to query server: %s", strerror(-r)); + goto fail; + } + + print_status_info(&info); + +fail: + free(info.timezone); + return r; +} + +static int set_time(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + bool relative = false, interactive = arg_ask_password; + usec_t t; + int r; + + assert(args); + assert(n == 2); + + polkit_agent_open_if_enabled(); + + r = parse_timestamp(args[1], &t); + if (r < 0) { + log_error("Failed to parse time specification: %s", args[1]); + return r; + } + + r = sd_bus_call_method(bus, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetTime", + &error, + NULL, + "xbb", (int64_t)t, relative, interactive); + if (r < 0) + log_error("Failed to set time: %s", bus_error_message(&error, -r)); + + return r; +} + +static int set_timezone(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(args); + assert(n == 2); + + polkit_agent_open_if_enabled(); + + r = sd_bus_call_method(bus, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetTimezone", + &error, + NULL, + "sb", args[1], arg_ask_password); + if (r < 0) + log_error("Failed to set timezone: %s", bus_error_message(&error, -r)); + + return r; +} + +static int set_local_rtc(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r, b; + + assert(args); + assert(n == 2); + + polkit_agent_open_if_enabled(); + + b = parse_boolean(args[1]); + if (b < 0) { + log_error("Failed to parse local RTC setting: %s", args[1]); + return b; + } + + r = sd_bus_call_method(bus, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetLocalRTC", + &error, + NULL, + "bbb", b, arg_adjust_system_clock, arg_ask_password); + if (r < 0) + log_error("Failed to set local RTC: %s", bus_error_message(&error, -r)); + + return r; +} + +static int set_ntp(sd_bus *bus, char **args, unsigned n) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int b, r; + + assert(args); + assert(n == 2); + + polkit_agent_open_if_enabled(); + + b = parse_boolean(args[1]); + if (b < 0) { + log_error("Failed to parse NTP setting: %s", args[1]); + return b; + } + + r = sd_bus_call_method(bus, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetNTP", + &error, + NULL, + "bb", b, arg_ask_password); + if (r < 0) + log_error("Failed to set ntp: %s", bus_error_message(&error, -r)); + + return r; +} + +static int list_timezones(sd_bus *bus, char **args, unsigned n) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **zones = NULL; + size_t n_zones = 0; + + assert(args); + assert(n == 1); + + f = fopen("/usr/share/zoneinfo/zone.tab", "re"); + if (!f) { + log_error("Failed to open timezone database: %m"); + return -errno; + } + + for (;;) { + char l[LINE_MAX], *p, **z, *w; + size_t k; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + log_error("Failed to read timezone database: %m"); + return -errno; + } + + p = strstrip(l); + + if (isempty(p) || *p == '#') + continue; + + + /* Skip over country code */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip over coordinates */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Found timezone name */ + k = strcspn(p, WHITESPACE); + if (k <= 0) + continue; + + w = strndup(p, k); + if (!w) + return log_oom(); + + z = realloc(zones, sizeof(char*) * (n_zones + 2)); + if (!z) { + free(w); + return log_oom(); + } + + zones = z; + zones[n_zones++] = w; + } + + if (zones) + zones[n_zones] = NULL; + + pager_open_if_enabled(); + + strv_sort(zones); + strv_print(zones); + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] COMMAND ...\n\n" + "Query or change system time and date settings.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-ask-password Do not prompt for password\n" + " -H --host=[USER@]HOST Operate on remote host\n" + " -M --machine=CONTAINER Operate on local container\n" + " --adjust-system-clock Adjust system clock when changing local RTC mode\n\n" + "Commands:\n" + " status Show current time settings\n" + " set-time TIME Set system time\n" + " set-timezone ZONE Set system timezone\n" + " list-timezones Show known timezones\n" + " set-local-rtc BOOL Control whether RTC is in local time\n" + " set-ntp BOOL Control whether NTP is enabled\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_ADJUST_SYSTEM_CLOCK, + ARG_NO_ASK_PASSWORD + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "host", required_argument, NULL, 'H' }, + { "machine", required_argument, NULL, 'M' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case 'H': + arg_transport = BUS_TRANSPORT_REMOTE; + arg_host = optarg; + break; + + case 'M': + arg_transport = BUS_TRANSPORT_CONTAINER; + arg_host = optarg; + break; + + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + + case ARG_ADJUST_SYSTEM_CLOCK: + arg_adjust_system_clock = true; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + return 1; +} + +static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) { + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(sd_bus *bus, char **args, unsigned n); + } verbs[] = { + { "status", LESS, 1, show_status }, + { "set-time", EQUAL, 2, set_time }, + { "set-timezone", EQUAL, 2, set_timezone }, + { "list-timezones", EQUAL, 1, list_timezones }, + { "set-local-rtc", EQUAL, 2, set_local_rtc }, + { "set-ntp", EQUAL, 2, set_ntp, }, + }; + + int left; + unsigned i; + + assert(argc >= 0); + assert(argv); + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "status" */ + i = 0; + else { + if (streq(argv[optind], "help")) { + help(); + return 0; + } + + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + return -EINVAL; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + return -EINVAL; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + return -EINVAL; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + return -EINVAL; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + return verbs[i].dispatch(bus, argv + optind, left); +} + +int main(int argc, char *argv[]) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + setlocale(LC_ALL, ""); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = bus_open_transport(arg_transport, arg_host, false, &bus); + if (r < 0) { + log_error("Failed to create bus connection: %s", strerror(-r)); + goto finish; + } + + r = timedatectl_main(bus, argc, argv); + +finish: + pager_close(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c new file mode 100644 index 0000000..d85ce57 --- /dev/null +++ b/src/timedate/timedated.c @@ -0,0 +1,870 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-id128.h" +#include "sd-messages.h" +#include "sd-event.h" +#include "sd-bus.h" + +#include "util.h" +#include "strv.h" +#include "def.h" +#include "hwclock.h" +#include "conf-files.h" +#include "path-util.h" +#include "fileio-label.h" +#include "label.h" +#include "bus-util.h" +#include "event-util.h" + +#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" +#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" + +typedef struct Context { + char *zone; + bool local_rtc; + unsigned can_ntp; + unsigned use_ntp; + Hashmap *polkit_registry; +} Context; + +static void context_reset(Context *c) { + assert(c); + + free(c->zone); + c->zone = NULL; + + c->local_rtc = false; + c->can_ntp = c->use_ntp = -1; +} + +static void context_free(Context *c, sd_bus *bus) { + assert(c); + + context_reset(c); + bus_verify_polkit_async_registry_free(bus, c->polkit_registry); +} + +static bool valid_timezone(const char *name) { + const char *p; + char *t; + bool slash = false; + int r; + struct stat st; + + assert(name); + + if (*name == '/' || *name == 0) + return false; + + for (p = name; *p; p++) { + if (!(*p >= '0' && *p <= '9') && + !(*p >= 'a' && *p <= 'z') && + !(*p >= 'A' && *p <= 'Z') && + !(*p == '-' || *p == '_' || *p == '+' || *p == '/')) + return false; + + if (*p == '/') { + + if (slash) + return false; + + slash = true; + } else + slash = false; + } + + if (slash) + return false; + + t = strappend("/usr/share/zoneinfo/", name); + if (!t) + return false; + + r = stat(t, &st); + free(t); + + if (r < 0) + return false; + + if (!S_ISREG(st.st_mode)) + return false; + + return true; +} + +static int context_read_data(Context *c) { + _cleanup_free_ char *t = NULL; + int r; + + assert(c); + + context_reset(c); + + r = readlink_malloc("/etc/localtime", &t); + if (r < 0) { + if (r == -EINVAL) + log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/."); + else + log_warning("Failed to get target of /etc/localtime: %s", strerror(-r)); + } else { + const char *e; + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); + + if (!e) + log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/."); + else { + c->zone = strdup(e); + if (!c->zone) + return log_oom(); + + goto have_timezone; + } + } + +have_timezone: + if (isempty(c->zone)) { + free(c->zone); + c->zone = NULL; + } + + c->local_rtc = hwclock_is_localtime() > 0; + + return 0; +} + +static int context_write_data_timezone(Context *c) { + _cleanup_free_ char *p = NULL; + int r = 0; + + assert(c); + + if (isempty(c->zone)) { + if (unlink("/etc/localtime") < 0 && errno != ENOENT) + r = -errno; + + return r; + } + + p = strappend("../usr/share/zoneinfo/", c->zone); + if (!p) + return log_oom(); + + r = symlink_atomic(p, "/etc/localtime"); + if (r < 0) + return r; + + return 0; +} + +static int context_write_data_local_rtc(Context *c) { + int r; + _cleanup_free_ char *s = NULL, *w = NULL; + + assert(c); + + r = read_full_file("/etc/adjtime", &s, NULL); + if (r < 0) { + if (r != -ENOENT) + return r; + + if (!c->local_rtc) + return 0; + + w = strdup(NULL_ADJTIME_LOCAL); + if (!w) + return -ENOMEM; + } else { + char *p, *e; + size_t a, b; + + p = strchr(s, '\n'); + if (!p) + return -EIO; + + p = strchr(p+1, '\n'); + if (!p) + return -EIO; + + p++; + e = strchr(p, '\n'); + if (!e) + return -EIO; + + a = p - s; + b = strlen(e); + + w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1); + if (!w) + return -ENOMEM; + + *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; + + if (streq(w, NULL_ADJTIME_UTC)) { + if (unlink("/etc/adjtime") < 0) + if (errno != ENOENT) + return -errno; + + return 0; + } + } + + label_init("/etc"); + return write_string_file_atomic_label("/etc/adjtime", w); +} + +static char** get_ntp_services(void) { + _cleanup_strv_free_ char **r = NULL, **files = NULL; + char **i; + int k; + + k = conf_files_list(&files, ".list", NULL, + "/etc/systemd/ntp-units.d", + "/run/systemd/ntp-units.d", + "/usr/local/lib/systemd/ntp-units.d", + "/usr/lib/systemd/ntp-units.d", + NULL); + if (k < 0) + return NULL; + + STRV_FOREACH(i, files) { + _cleanup_fclose_ FILE *f; + + f = fopen(*i, "re"); + if (!f) + continue; + + for (;;) { + char line[PATH_MAX], *l; + + if (!fgets(line, sizeof(line), f)) { + + if (ferror(f)) + log_error("Failed to read NTP units file: %m"); + + break; + } + + l = strstrip(line); + if (l[0] == 0 || l[0] == '#') + continue; + + if (strv_extend(&r, l) < 0) { + log_oom(); + return NULL; + } + } + } + + i = r; + r = NULL; /* avoid cleanup */ + + return strv_uniq(i); +} + +static int context_read_ntp(Context *c, sd_bus *bus) { + _cleanup_strv_free_ char **l; + char **i; + int r; + + assert(c); + assert(bus); + + l = get_ntp_services(); + STRV_FOREACH(i, l) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus_message *reply = NULL; + const char *s; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitFileState", + &error, + &reply, + "s", + *i); + + if (r < 0) { + /* This implementation does not exist, try next one */ + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)) + continue; + + return r; + } + + r = sd_bus_message_read(reply, "s", &s); + if (r < 0) + return r; + + c->can_ntp = 1; + c->use_ntp = + streq(s, "enabled") || + streq(s, "enabled-runtime"); + + return 0; + } + + /* NTP is not installed. */ + c->can_ntp = 0; + c->use_ntp = 0; + + return 0; +} + +static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + char **i; + int r; + + assert(c); + assert(bus); + assert(error); + + l = get_ntp_services(); + STRV_FOREACH(i, l) { + + if (c->use_ntp) + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit", + error, + NULL, + "ss", *i, "replace"); + else + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StopUnit", + error, + NULL, + "ss", *i, "replace"); + + if (r < 0) { + if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) || + sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") || + sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit")) { + /* This implementation does not exist, try next one */ + sd_bus_error_free(error); + continue; + } + + return r; + } + + return 1; + } + + sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); + return -ENOTSUP; +} + +static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + char **i; + int r; + + assert(c); + assert(bus); + assert(error); + + l = get_ntp_services(); + STRV_FOREACH(i, l) { + if (c->use_ntp) + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "EnableUnitFiles", + error, + NULL, + "asbb", 1, *i, false, true); + else + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "DisableUnitFiles", + error, + NULL, + "asb", 1, *i, false); + + if (r < 0) { + if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND)) { + /* This implementation does not exist, try next one */ + sd_bus_error_free(error); + continue; + } + + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Reload", + error, + NULL, + NULL); + if (r < 0) + return r; + + return 1; + } + + sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported."); + return -ENOTSUP; +} + +static int property_get_rtc_time( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + struct tm tm; + usec_t t; + int r; + + zero(tm); + r = hwclock_get_time(&tm); + if (r == -EBUSY) { + log_warning("/dev/rtc is busy, is somebody keeping it open continously? That's not a good idea... Returning a bogus RTC timestamp."); + t = 0; + } else if (r == -ENOENT) { + log_debug("Not /dev/rtc found."); + t = 0; /* no RTC found */ + } else if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %s", strerror(-r)); + else + t = (usec_t) timegm(&tm) * USEC_PER_SEC; + + return sd_bus_message_append(reply, "t", t); +} + +static int property_get_time( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + return sd_bus_message_append(reply, "t", now(CLOCK_REALTIME)); +} + +static int property_get_ntp_sync( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + return sd_bus_message_append(reply, "b", ntp_synced()); +} + +static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + Context *c = userdata; + const char *z; + int interactive; + char *t; + int r; + + assert(bus); + assert(m); + assert(c); + + r = sd_bus_message_read(m, "sb", &z, &interactive); + if (r < 0) + return r; + + if (!valid_timezone(z)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z); + + if (streq_ptr(z, c->zone)) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-timezone", interactive, error, method_set_timezone, c); + 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 */ + + t = strdup(z); + if (!t) + return -ENOMEM; + + free(c->zone); + c->zone = t; + + /* 1. Write new configuration file */ + r = context_write_data_timezone(c); + if (r < 0) { + log_error("Failed to set timezone: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set timezone: %s", strerror(-r)); + } + + /* 2. Tell the kernel our timezone */ + hwclock_set_timezone(NULL); + + if (c->local_rtc) { + struct timespec ts; + struct tm *tm; + + /* 3. Sync RTC from system clock, with the new delta */ + assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); + assert_se(tm = localtime(&ts.tv_sec)); + hwclock_set_time(tm); + } + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE), + "TIMEZONE=%s", c->zone, + "MESSAGE=Changed timezone to '%s'.", c->zone, + NULL); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int lrtc, fix_system, interactive; + Context *c = userdata; + struct timespec ts; + int r; + + assert(bus); + assert(m); + assert(c); + + r = sd_bus_message_read(m, "bbb", &lrtc, &fix_system, &interactive); + if (r < 0) + return r; + + if (lrtc == c->local_rtc) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-local-rtc", interactive, error, method_set_local_rtc, c); + if (r < 0) + return r; + if (r == 0) + return 1; + + c->local_rtc = lrtc; + + /* 1. Write new configuration file */ + r = context_write_data_local_rtc(c); + if (r < 0) { + log_error("Failed to set RTC to local/UTC: %s", strerror(-r)); + return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %s", strerror(-r)); + } + + /* 2. Tell the kernel our timezone */ + hwclock_set_timezone(NULL); + + /* 3. Synchronize clocks */ + assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); + + if (fix_system) { + struct tm tm; + + /* Sync system clock from RTC; first, + * initialize the timezone fields of + * struct tm. */ + if (c->local_rtc) + tm = *localtime(&ts.tv_sec); + else + tm = *gmtime(&ts.tv_sec); + + /* Override the main fields of + * struct tm, but not the timezone + * fields */ + if (hwclock_get_time(&tm) >= 0) { + + /* And set the system clock + * with this */ + if (c->local_rtc) + ts.tv_sec = mktime(&tm); + else + ts.tv_sec = timegm(&tm); + + clock_settime(CLOCK_REALTIME, &ts); + } + + } else { + struct tm *tm; + + /* Sync RTC from system clock */ + if (c->local_rtc) + tm = localtime(&ts.tv_sec); + else + tm = gmtime(&ts.tv_sec); + + hwclock_set_time(tm); + } + + log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC"); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int relative, interactive; + Context *c = userdata; + int64_t utc; + struct timespec ts; + struct tm* tm; + int r; + + assert(bus); + assert(m); + assert(c); + + r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive); + if (r < 0) + return r; + + if (!relative && utc <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time"); + + if (relative && utc == 0) + return sd_bus_reply_method_return(m, NULL); + + if (relative) { + usec_t n, x; + + n = now(CLOCK_REALTIME); + x = n + utc; + + if ((utc > 0 && x < n) || + (utc < 0 && x > n)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow"); + + timespec_store(&ts, x); + } else + timespec_store(&ts, (usec_t) utc); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-time", interactive, error, method_set_time, c); + if (r < 0) + return r; + if (r == 0) + return 1; + + /* Set system clock */ + if (clock_settime(CLOCK_REALTIME, &ts) < 0) { + log_error("Failed to set local time: %m"); + return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m"); + } + + /* Sync down to RTC */ + if (c->local_rtc) + tm = localtime(&ts.tv_sec); + else + tm = gmtime(&ts.tv_sec); + + hwclock_set_time(tm); + + log_struct(LOG_INFO, + MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), + "REALTIME=%llu", (unsigned long long) timespec_load(&ts), + "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec), + NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { + int ntp, interactive; + Context *c = userdata; + int r; + + r = sd_bus_message_read(m, "bb", &ntp, &interactive); + if (r < 0) + return r; + + if ((bool)ntp == c->use_ntp) + return sd_bus_reply_method_return(m, NULL); + + r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-ntp", interactive, error, method_set_ntp, c); + if (r < 0) + return r; + if (r == 0) + return 1; + + c->use_ntp = ntp; + + r = context_enable_ntp(c, bus, error); + if (r < 0) + return r; + + r = context_start_ntp(c, bus, error); + if (r < 0) + return r; + + log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled"); + + sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL); + + return sd_bus_reply_method_return(m, NULL); +} + +#include + +static const sd_bus_vtable timedate_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("LocalRTC", "b", NULL, offsetof(Context, local_rtc), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("CanNTP", "b", bus_property_get_tristate, offsetof(Context, can_ntp), 0), + SD_BUS_PROPERTY("NTP", "b", bus_property_get_tristate, offsetof(Context, use_ntp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NTPSynchronized", "b", property_get_ntp_sync, 0, 0), + SD_BUS_PROPERTY("TimeUSec", "t", property_get_time, 0, 0), + SD_BUS_PROPERTY("RTCTimeUSec", "t", property_get_rtc_time, 0, 0), + SD_BUS_METHOD("SetTime", "xbb", NULL, method_set_time, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetTimezone", "sb", NULL, method_set_timezone, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLocalRTC", "bbb", NULL, method_set_local_rtc, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetNTP", "bb", NULL, method_set_ntp, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + assert(c); + assert(event); + assert(_bus); + + r = sd_bus_default_system(&bus); + if (r < 0) { + log_error("Failed to get system bus connection: %s", strerror(-r)); + return r; + } + + r = sd_bus_add_object_vtable(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c); + if (r < 0) { + log_error("Failed to register object: %s", strerror(-r)); + return r; + } + + r = sd_bus_request_name(bus, "org.freedesktop.timedate1", 0); + if (r < 0) { + log_error("Failed to register name: %s", strerror(-r)); + return r; + } + + r = sd_bus_attach_event(bus, event, 0); + if (r < 0) { + log_error("Failed to attach bus to event loop: %s", strerror(-r)); + return r; + } + + *_bus = bus; + bus = NULL; + + return 0; +} + +int main(int argc, char *argv[]) { + Context context = { + .zone = NULL, + .local_rtc = false, + .can_ntp = -1, + .use_ntp = -1, + }; + + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_bus_unref_ sd_bus *bus = NULL; + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + r = sd_event_default(&event); + if (r < 0) { + log_error("Failed to allocate event loop: %s", strerror(-r)); + goto finish; + } + + sd_event_set_watchdog(event, true); + + r = connect_bus(&context, event, &bus); + if (r < 0) + goto finish; + + r = context_read_data(&context); + if (r < 0) { + log_error("Failed to read timezone data: %s", strerror(-r)); + goto finish; + } + + r = context_read_ntp(&context, bus); + if (r < 0) { + log_error("Failed to determine whether NTP is enabled: %s", strerror(-r)); + goto finish; + } + + r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC, NULL, NULL); + if (r < 0) { + log_error("Failed to run event loop: %s", strerror(-r)); + goto finish; + } + +finish: + context_free(&context, bus); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/timedated.c b/src/timedated.c deleted file mode 100644 index 16f54b5..0000000 --- a/src/timedated.c +++ /dev/null @@ -1,911 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include -#include -#include - -#include "util.h" -#include "strv.h" -#include "dbus-common.h" -#include "polkit.h" -#include "def.h" - -#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" -#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" - -#define INTERFACE \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" \ - " \n" - -#define INTROSPECTION \ - DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ - "\n" \ - INTERFACE \ - BUS_PROPERTIES_INTERFACE \ - BUS_INTROSPECTABLE_INTERFACE \ - BUS_PEER_INTERFACE \ - "\n" - -#define INTERFACES_LIST \ - BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.timedate1\0" - -const char timedate_interface[] _introspect_("timedate1") = INTERFACE; - -static char *zone = NULL; -static bool local_rtc = false; -static int use_ntp = -1; - -static usec_t remain_until = 0; - -static void free_data(void) { - free(zone); - zone = NULL; - - local_rtc = false; -} - -static bool valid_timezone(const char *name) { - const char *p; - char *t; - bool slash = false; - int r; - struct stat st; - - assert(name); - - if (*name == '/' || *name == 0) - return false; - - for (p = name; *p; p++) { - if (!(*p >= '0' && *p <= '9') && - !(*p >= 'a' && *p <= 'z') && - !(*p >= 'A' && *p <= 'Z') && - !(*p == '-' || *p == '_' || *p == '+' || *p == '/')) - return false; - - if (*p == '/') { - - if (slash) - return false; - - slash = true; - } else - slash = false; - } - - if (slash) - return false; - - t = strappend("/usr/share/zoneinfo/", name); - if (!t) - return false; - - r = stat(t, &st); - free(t); - - if (r < 0) - return false; - - if (!S_ISREG(st.st_mode)) - return false; - - return true; -} - -static void verify_timezone(void) { - char *p, *a = NULL, *b = NULL; - size_t l, q; - int j, k; - - if (!zone) - return; - - p = strappend("/usr/share/zoneinfo/", zone); - if (!p) { - log_error("Out of memory"); - return; - } - - j = read_full_file("/etc/localtime", &a, &l); - k = read_full_file(p, &b, &q); - - free(p); - - if (j < 0 || k < 0 || l != q || memcmp(a, b, l)) { - log_warning("/etc/localtime and /etc/timezone out of sync."); - free(zone); - zone = NULL; - } - - free(a); - free(b); -} - -static int read_data(void) { - int r; - - free_data(); - - r = read_one_line_file("/etc/timezone", &zone); - if (r < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/timezone: %s", strerror(-r)); - -#ifdef TARGET_FEDORA - r = parse_env_file("/etc/sysconfig/clock", NEWLINE, - "ZONE", &zone, - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r)); -#endif - } - - if (isempty(zone)) { - free(zone); - zone = NULL; - } - - verify_timezone(); - - local_rtc = hwclock_is_localtime() > 0; - - return 0; -} - -static int write_data_timezone(void) { - int r = 0; - char *p; - - if (!zone) { - if (unlink("/etc/timezone") < 0 && errno != ENOENT) - r = -errno; - - if (unlink("/etc/localtime") < 0 && errno != ENOENT) - r = -errno; - - return r; - } - - p = strappend("/usr/share/zoneinfo/", zone); - if (!p) { - log_error("Out of memory"); - return -ENOMEM; - } - - r = symlink_or_copy_atomic(p, "/etc/localtime"); - free(p); - - if (r < 0) - return r; - - r = write_one_line_file_atomic("/etc/timezone", zone); - if (r < 0) - return r; - - return 0; -} - -static int write_data_local_rtc(void) { - int r; - char *s, *w; - - r = read_full_file("/etc/adjtime", &s, NULL); - if (r < 0) { - if (r != -ENOENT) - return r; - - if (!local_rtc) - return 0; - - w = strdup(NULL_ADJTIME_LOCAL); - if (!w) - return -ENOMEM; - } else { - char *p, *e; - size_t a, b; - - p = strchr(s, '\n'); - if (!p) { - free(s); - return -EIO; - } - - p = strchr(p+1, '\n'); - if (!p) { - free(s); - return -EIO; - } - - p++; - e = strchr(p, '\n'); - if (!e) { - free(s); - return -EIO; - } - - a = p - s; - b = strlen(e); - - w = new(char, a + (local_rtc ? 5 : 3) + b + 1); - if (!w) { - free(s); - return -ENOMEM; - } - - *(char*) mempcpy(stpcpy(mempcpy(w, s, a), local_rtc ? "LOCAL" : "UTC"), e, b) = 0; - - if (streq(w, NULL_ADJTIME_UTC)) { - free(w); - - if (unlink("/etc/adjtime") < 0) { - if (errno != ENOENT) - return -errno; - } - - return 0; - } - } - - r = write_one_line_file_atomic("/etc/adjtime", w); - free(w); - - return r; -} - -static int read_ntp(DBusConnection *bus) { - DBusMessage *m = NULL, *reply = NULL; - const char *name = "ntpd.service", *s; - DBusError error; - int r; - - assert(bus); - - dbus_error_init(&error); - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnitFileState"); - - if (!m) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &s, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - use_ntp = - streq(s, "enabled") || - streq(s, "enabled-runtime"); - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int start_ntp(DBusConnection *bus, DBusError *error) { - DBusMessage *m = NULL, *reply = NULL; - const char *name = "ntpd.service", *mode = "replace"; - int r; - - assert(bus); - assert(error); - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - use_ntp ? "StartUnit" : "StopUnit"); - if (!m) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return r; -} - -static int enable_ntp(DBusConnection *bus, DBusError *error) { - DBusMessage *m = NULL, *reply = NULL; - const char * const names[] = { "ntpd.service", NULL }; - int r; - DBusMessageIter iter; - dbus_bool_t f = FALSE, t = TRUE; - - assert(bus); - assert(error); - - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - use_ntp ? "EnableUnitFiles" : "DisableUnitFiles"); - - if (!m) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - r = bus_append_strv_iter(&iter, (char**) names); - if (r < 0) { - log_error("Failed to append unit files."); - goto finish; - } - /* send runtime bool */ - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &f)) { - log_error("Failed to append runtime boolean."); - r = -ENOMEM; - goto finish; - } - - if (use_ntp) { - /* send force bool */ - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &t)) { - log_error("Failed to append force boolean."); - r = -ENOMEM; - goto finish; - } - } - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "Reload"); - if (!m) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(error)); - r = -EIO; - goto finish; - } - - r = 0; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return r; -} - -static int property_append_ntp(DBusMessageIter *i, const char *property, void *data) { - dbus_bool_t db; - - assert(i); - assert(property); - - db = use_ntp > 0; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -static DBusHandlerResult timedate_message_handler( - DBusConnection *connection, - DBusMessage *message, - void *userdata) { - - const BusProperty properties[] = { - { "org.freedesktop.timedate1", "Timezone", bus_property_append_string, "s", zone }, - { "org.freedesktop.timedate1", "LocalRTC", bus_property_append_bool, "b", &local_rtc }, - { "org.freedesktop.timedate1", "NTP", property_append_ntp, "b", NULL }, - { NULL, NULL, NULL, NULL, NULL } - }; - - DBusMessage *reply = NULL, *changed = NULL; - DBusError error; - int r; - - assert(connection); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) { - const char *z; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &z, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!valid_timezone(z)) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - if (!streq_ptr(z, zone)) { - char *t; - - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - t = strdup(z); - if (!t) - goto oom; - - free(zone); - zone = t; - - /* 1. Write new configuration file */ - r = write_data_timezone(); - if (r < 0) { - log_error("Failed to set timezone: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - if (local_rtc) { - struct timespec ts; - struct tm *tm; - - /* 2. Teach kernel new timezone */ - hwclock_apply_localtime_delta(NULL); - - /* 3. Sync RTC from system clock, with the new delta */ - assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); - assert_se(tm = localtime(&ts.tv_sec)); - hwclock_set_time(tm); - } - - log_info("Changed timezone to '%s'.", zone); - - changed = bus_properties_changed_new( - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "Timezone\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) { - dbus_bool_t lrtc; - dbus_bool_t fix_system; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_BOOLEAN, &lrtc, - DBUS_TYPE_BOOLEAN, &fix_system, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (lrtc != local_rtc) { - struct timespec ts; - - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - local_rtc = lrtc; - - /* 1. Write new configuration file */ - r = write_data_local_rtc(); - if (r < 0) { - log_error("Failed to set RTC to local/UTC: %s", strerror(-r)); - return bus_send_error_reply(connection, message, NULL, r); - } - - /* 2. Teach kernel new timezone */ - if (local_rtc) - hwclock_apply_localtime_delta(NULL); - else - hwclock_reset_localtime_delta(); - - /* 3. Synchronize clocks */ - assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); - - if (fix_system) { - struct tm tm; - - /* Sync system clock from RTC; first, - * initialize the timezone fields of - * struct tm. */ - if (local_rtc) - tm = *localtime(&ts.tv_sec); - else - tm = *gmtime(&ts.tv_sec); - - /* Override the main fields of - * struct tm, but not the timezone - * fields */ - if (hwclock_get_time(&tm) >= 0) { - - /* And set the system clock - * with this */ - if (local_rtc) - ts.tv_sec = mktime(&tm); - else - ts.tv_sec = timegm(&tm); - - clock_settime(CLOCK_REALTIME, &ts); - } - - } else { - struct tm *tm; - - /* Sync RTC from system clock */ - if (local_rtc) - tm = localtime(&ts.tv_sec); - else - tm = gmtime(&ts.tv_sec); - - hwclock_set_time(tm); - } - - log_info("RTC configured to %s time.", local_rtc ? "local" : "UTC"); - - changed = bus_properties_changed_new( - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "LocalRTC\0"); - if (!changed) - goto oom; - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTime")) { - int64_t utc; - dbus_bool_t relative; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_INT64, &utc, - DBUS_TYPE_BOOLEAN, &relative, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (!relative && utc <= 0) - return bus_send_error_reply(connection, message, NULL, -EINVAL); - - if (!relative || utc != 0) { - struct timespec ts; - struct tm* tm; - - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - if (relative) - timespec_store(&ts, now(CLOCK_REALTIME) + utc); - else - timespec_store(&ts, utc); - - /* Set system clock */ - if (clock_settime(CLOCK_REALTIME, &ts) < 0) { - log_error("Failed to set local time: %m"); - return bus_send_error_reply(connection, message, NULL, -errno); - } - - /* Sync down to RTC */ - if (local_rtc) - tm = localtime(&ts.tv_sec); - else - tm = gmtime(&ts.tv_sec); - - hwclock_set_time(tm); - - log_info("Changed local time to %s", ctime(&ts.tv_sec)); - } - } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetNTP")) { - dbus_bool_t ntp; - dbus_bool_t interactive; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_BOOLEAN, &ntp, - DBUS_TYPE_BOOLEAN, &interactive, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(connection, message, &error, -EINVAL); - - if (ntp != !!use_ntp) { - - r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - use_ntp = !!ntp; - - r = enable_ntp(connection, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - r = start_ntp(connection, &error); - if (r < 0) - return bus_send_error_reply(connection, message, &error, r); - - log_info("Set NTP to %s", use_ntp ? "enabled" : "disabled"); - - changed = bus_properties_changed_new( - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "NTP\0"); - if (!changed) - goto oom; - } - - } else - return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_connection_send(connection, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - reply = NULL; - - if (changed) { - - if (!dbus_connection_send(connection, changed, NULL)) - goto oom; - - dbus_message_unref(changed); - } - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (changed) - dbus_message_unref(changed); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static int connect_bus(DBusConnection **_bus) { - static const DBusObjectPathVTable timedate_vtable = { - .message_function = timedate_message_handler - }; - DBusError error; - DBusConnection *bus = NULL; - int r; - - assert(_bus); - - dbus_error_init(&error); - - bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); - if (!bus) { - log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error)); - r = -ECONNREFUSED; - goto fail; - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) || - !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { - log_error("Not enough memory"); - r = -ENOMEM; - goto fail; - } - - r = dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); - if (dbus_error_is_set(&error)) { - log_error("Failed to register name on bus: %s", bus_error_message(&error)); - r = -EEXIST; - goto fail; - } - - if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - log_error("Failed to acquire name."); - r = -EEXIST; - goto fail; - } - - if (_bus) - *_bus = bus; - - return 0; - -fail: - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_error_free(&error); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - DBusConnection *bus = NULL; - bool exiting = false; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc == 2 && streq(argv[1], "--introspect")) { - fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE - "\n", stdout); - fputs(timedate_interface, stdout); - fputs("\n", stdout); - return 0; - } - - if (argc != 1) { - log_error("This program takes no arguments."); - r = -EINVAL; - goto finish; - } - - r = read_data(); - if (r < 0) { - log_error("Failed to read timezone data: %s", strerror(-r)); - goto finish; - } - - r = connect_bus(&bus); - if (r < 0) - goto finish; - - r = read_ntp(bus); - if (r < 0) { - log_error("Failed to determine whether NTP is enabled: %s", strerror(-r)); - goto finish; - } - - remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - for (;;) { - - if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) - break; - - if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { - exiting = true; - bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); - } - } - - r = 0; - -finish: - free_data(); - - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/timer.c b/src/timer.c deleted file mode 100644 index e6f207f..0000000 --- a/src/timer.c +++ /dev/null @@ -1,510 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "unit.h" -#include "unit-name.h" -#include "timer.h" -#include "dbus-timer.h" -#include "special.h" -#include "bus-errors.h" - -static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { - [TIMER_DEAD] = UNIT_INACTIVE, - [TIMER_WAITING] = UNIT_ACTIVE, - [TIMER_RUNNING] = UNIT_ACTIVE, - [TIMER_ELAPSED] = UNIT_ACTIVE, - [TIMER_FAILED] = UNIT_FAILED -}; - -static void timer_init(Unit *u) { - Timer *t = TIMER(u); - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - t->next_elapse = (usec_t) -1; -} - -static void timer_done(Unit *u) { - Timer *t = TIMER(u); - TimerValue *v; - - assert(t); - - while ((v = t->values)) { - LIST_REMOVE(TimerValue, value, t->values, v); - free(v); - } - - unit_unwatch_timer(u, &t->timer_watch); -} - -static int timer_verify(Timer *t) { - assert(t); - - if (t->meta.load_state != UNIT_LOADED) - return 0; - - if (!t->values) { - log_error("%s lacks value setting. Refusing.", t->meta.id); - return -EINVAL; - } - - return 0; -} - -static int timer_add_default_dependencies(Timer *t) { - int r; - - assert(t); - - if (t->meta.manager->running_as == MANAGER_SYSTEM) { - if ((r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0) - return r; - - if ((r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0) - return r; - } - - return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); -} - -static int timer_load(Unit *u) { - Timer *t = TIMER(u); - int r; - - assert(u); - assert(u->meta.load_state == UNIT_STUB); - - if ((r = unit_load_fragment_and_dropin(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_LOADED) { - - if (!t->unit) - if ((r = unit_load_related_unit(u, ".service", &t->unit))) - return r; - - if ((r = unit_add_dependency(u, UNIT_BEFORE, t->unit, true)) < 0) - return r; - - if (t->meta.default_dependencies) - if ((r = timer_add_default_dependencies(t)) < 0) - return r; - } - - return timer_verify(t); -} - -static void timer_dump(Unit *u, FILE *f, const char *prefix) { - Timer *t = TIMER(u); - TimerValue *v; - char - timespan1[FORMAT_TIMESPAN_MAX]; - - fprintf(f, - "%sTimer State: %s\n" - "%sUnit: %s\n", - prefix, timer_state_to_string(t->state), - prefix, t->unit->meta.id); - - LIST_FOREACH(value, v, t->values) - fprintf(f, - "%s%s: %s\n", - prefix, - timer_base_to_string(v->base), - strna(format_timespan(timespan1, sizeof(timespan1), v->value))); -} - -static void timer_set_state(Timer *t, TimerState state) { - TimerState old_state; - assert(t); - - old_state = t->state; - t->state = state; - - if (state != TIMER_WAITING) - unit_unwatch_timer(UNIT(t), &t->timer_watch); - - if (state != old_state) - log_debug("%s changed %s -> %s", - t->meta.id, - timer_state_to_string(old_state), - timer_state_to_string(state)); - - unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true); -} - -static void timer_enter_waiting(Timer *t, bool initial); - -static int timer_coldplug(Unit *u) { - Timer *t = TIMER(u); - - assert(t); - assert(t->state == TIMER_DEAD); - - if (t->deserialized_state != t->state) { - - if (t->deserialized_state == TIMER_WAITING) - timer_enter_waiting(t, false); - else - timer_set_state(t, t->deserialized_state); - } - - return 0; -} - -static void timer_enter_dead(Timer *t, bool success) { - assert(t); - - if (!success) - t->failure = true; - - timer_set_state(t, t->failure ? TIMER_FAILED : TIMER_DEAD); -} - -static void timer_enter_waiting(Timer *t, bool initial) { - TimerValue *v; - usec_t base = 0, delay, n; - bool found = false; - int r; - - n = now(CLOCK_MONOTONIC); - - LIST_FOREACH(value, v, t->values) { - - if (v->disabled) - continue; - - switch (v->base) { - - case TIMER_ACTIVE: - if (state_translation_table[t->state] == UNIT_ACTIVE) - base = t->meta.inactive_exit_timestamp.monotonic; - else - base = n; - break; - - case TIMER_BOOT: - /* CLOCK_MONOTONIC equals the uptime on Linux */ - base = 0; - break; - - case TIMER_STARTUP: - base = t->meta.manager->startup_timestamp.monotonic; - break; - - case TIMER_UNIT_ACTIVE: - - if (t->unit->meta.inactive_exit_timestamp.monotonic <= 0) - continue; - - base = t->unit->meta.inactive_exit_timestamp.monotonic; - break; - - case TIMER_UNIT_INACTIVE: - - if (t->unit->meta.inactive_enter_timestamp.monotonic <= 0) - continue; - - base = t->unit->meta.inactive_enter_timestamp.monotonic; - break; - - default: - assert_not_reached("Unknown timer base"); - } - - v->next_elapse = base + v->value; - - if (!initial && v->next_elapse < n) { - v->disabled = true; - continue; - } - - if (!found) - t->next_elapse = v->next_elapse; - else - t->next_elapse = MIN(t->next_elapse, v->next_elapse); - - found = true; - } - - if (!found) { - timer_set_state(t, TIMER_ELAPSED); - return; - } - - delay = n < t->next_elapse ? t->next_elapse - n : 0; - - if ((r = unit_watch_timer(UNIT(t), delay, &t->timer_watch)) < 0) - goto fail; - - timer_set_state(t, TIMER_WAITING); - return; - -fail: - log_warning("%s failed to enter waiting state: %s", t->meta.id, strerror(-r)); - timer_enter_dead(t, false); -} - -static void timer_enter_running(Timer *t) { - DBusError error; - int r; - - assert(t); - dbus_error_init(&error); - - /* Don't start job if we are supposed to go down */ - if (t->meta.job && t->meta.job->type == JOB_STOP) - return; - - if ((r = manager_add_job(t->meta.manager, JOB_START, t->unit, JOB_REPLACE, true, &error, NULL)) < 0) - goto fail; - - timer_set_state(t, TIMER_RUNNING); - return; - -fail: - log_warning("%s failed to queue unit startup job: %s", t->meta.id, bus_error(&error, r)); - timer_enter_dead(t, false); - - dbus_error_free(&error); -} - -static int timer_start(Unit *u) { - Timer *t = TIMER(u); - - assert(t); - assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); - - if (t->unit->meta.load_state != UNIT_LOADED) - return -ENOENT; - - t->failure = false; - timer_enter_waiting(t, true); - return 0; -} - -static int timer_stop(Unit *u) { - Timer *t = TIMER(u); - - assert(t); - assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED); - - timer_enter_dead(t, true); - return 0; -} - -static int timer_serialize(Unit *u, FILE *f, FDSet *fds) { - Timer *t = TIMER(u); - - assert(u); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", timer_state_to_string(t->state)); - - return 0; -} - -static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Timer *t = TIMER(u); - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - TimerState state; - - if ((state = timer_state_from_string(value)) < 0) - log_debug("Failed to parse state value %s", value); - else - t->deserialized_state = state; - } else - log_debug("Unknown serialization key '%s'", key); - - return 0; -} - -static UnitActiveState timer_active_state(Unit *u) { - assert(u); - - return state_translation_table[TIMER(u)->state]; -} - -static const char *timer_sub_state_to_string(Unit *u) { - assert(u); - - return timer_state_to_string(TIMER(u)->state); -} - -static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) { - Timer *t = TIMER(u); - - assert(t); - assert(elapsed == 1); - - if (t->state != TIMER_WAITING) - return; - - log_debug("Timer elapsed on %s", u->meta.id); - timer_enter_running(t); -} - -void timer_unit_notify(Unit *u, UnitActiveState new_state) { - char *n; - int r; - Iterator i; - - if (u->meta.type == UNIT_TIMER) - return; - - SET_FOREACH(n, u->meta.names, i) { - char *k; - Unit *p; - Timer *t; - TimerValue *v; - - if (!(k = unit_name_change_suffix(n, ".timer"))) { - r = -ENOMEM; - goto fail; - } - - p = manager_get_unit(u->meta.manager, k); - free(k); - - if (!p) - continue; - - if (p->meta.load_state != UNIT_LOADED) - continue; - - t = TIMER(p); - - if (t->unit != u) - continue; - - /* Reenable all timers that depend on unit state */ - LIST_FOREACH(value, v, t->values) - if (v->base == TIMER_UNIT_ACTIVE || - v->base == TIMER_UNIT_INACTIVE) - v->disabled = false; - - switch (t->state) { - - case TIMER_WAITING: - case TIMER_ELAPSED: - - /* Recalculate sleep time */ - timer_enter_waiting(t, false); - break; - - case TIMER_RUNNING: - - if (UNIT_IS_INACTIVE_OR_FAILED(new_state)) { - log_debug("%s got notified about unit deactivation.", t->meta.id); - timer_enter_waiting(t, false); - } - - break; - - case TIMER_DEAD: - case TIMER_FAILED: - break; - - default: - assert_not_reached("Unknown timer state"); - } - } - - return; - -fail: - log_error("Failed find timer unit: %s", strerror(-r)); -} - -static void timer_reset_failed(Unit *u) { - Timer *t = TIMER(u); - - assert(t); - - if (t->state == TIMER_FAILED) - timer_set_state(t, TIMER_DEAD); - - t->failure = false; -} - -static const char* const timer_state_table[_TIMER_STATE_MAX] = { - [TIMER_DEAD] = "dead", - [TIMER_WAITING] = "waiting", - [TIMER_RUNNING] = "running", - [TIMER_ELAPSED] = "elapsed", - [TIMER_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); - -static const char* const timer_base_table[_TIMER_BASE_MAX] = { - [TIMER_ACTIVE] = "OnActiveSec", - [TIMER_BOOT] = "OnBootSec", - [TIMER_STARTUP] = "OnStartupSec", - [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec", - [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec" -}; - -DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); - -const UnitVTable timer_vtable = { - .suffix = ".timer", - .sections = - "Unit\0" - "Timer\0" - "Install\0", - - .init = timer_init, - .done = timer_done, - .load = timer_load, - - .coldplug = timer_coldplug, - - .dump = timer_dump, - - .start = timer_start, - .stop = timer_stop, - - .serialize = timer_serialize, - .deserialize_item = timer_deserialize_item, - - .active_state = timer_active_state, - .sub_state_to_string = timer_sub_state_to_string, - - .timer_event = timer_timer_event, - - .reset_failed = timer_reset_failed, - - .bus_interface = "org.freedesktop.systemd1.Timer", - .bus_message_handler = bus_timer_message_handler, - .bus_invalidating_properties = bus_timer_invalidating_properties -}; diff --git a/src/timer.h b/src/timer.h deleted file mode 100644 index 6295605..0000000 --- a/src/timer.h +++ /dev/null @@ -1,83 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef footimerhfoo -#define footimerhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -typedef struct Timer Timer; - -#include "unit.h" - -typedef enum TimerState { - TIMER_DEAD, - TIMER_WAITING, - TIMER_RUNNING, - TIMER_ELAPSED, - TIMER_FAILED, - _TIMER_STATE_MAX, - _TIMER_STATE_INVALID = -1 -} TimerState; - -typedef enum TimerBase { - TIMER_ACTIVE, - TIMER_BOOT, - TIMER_STARTUP, - TIMER_UNIT_ACTIVE, - TIMER_UNIT_INACTIVE, - _TIMER_BASE_MAX, - _TIMER_BASE_INVALID = -1 -} TimerBase; - -typedef struct TimerValue { - usec_t value; - usec_t next_elapse; - - LIST_FIELDS(struct TimerValue, value); - - TimerBase base; - bool disabled; -} TimerValue; - -struct Timer { - Meta meta; - - LIST_HEAD(TimerValue, values); - usec_t next_elapse; - - TimerState state, deserialized_state; - Unit *unit; - - Watch timer_watch; - - bool failure; -}; - -void timer_unit_notify(Unit *u, UnitActiveState new_state); - -extern const UnitVTable timer_vtable; - -const char *timer_state_to_string(TimerState i); -TimerState timer_state_from_string(const char *s); - -const char *timer_base_to_string(TimerBase i); -TimerBase timer_base_from_string(const char *s); - -#endif diff --git a/src/timestamp.c b/src/timestamp.c deleted file mode 100644 index ce51429..0000000 --- a/src/timestamp.c +++ /dev/null @@ -1,39 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#include "util.h" - -int main(int argc, char *argv[]) { - struct dual_timestamp t; - - /* This is mostly useful for stuff like init ram disk scripts - * which want to take a proper timestamp to do minimal bootup - * profiling. */ - - dual_timestamp_get(&t); - printf("%llu %llu\n", - (unsigned long long) t.realtime, - (unsigned long long) t.monotonic); - - return 0; -} diff --git a/src/tmpfiles.c b/src/tmpfiles.c deleted file mode 100644 index 21bf44d..0000000 --- a/src/tmpfiles.c +++ /dev/null @@ -1,1042 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering, Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "strv.h" -#include "label.h" -#include "set.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 - * properly owned directories beneath /tmp, /var/tmp, /run, which are - * volatile and hence need to be recreated on bootup. */ - -enum { - /* These ones take file names */ - CREATE_FILE = 'f', - TRUNCATE_FILE = 'F', - CREATE_DIRECTORY = 'd', - TRUNCATE_DIRECTORY = 'D', - CREATE_FIFO = 'p', - - /* These ones take globs */ - IGNORE_PATH = 'x', - REMOVE_PATH = 'r', - RECURSIVE_REMOVE_PATH = 'R' -}; - -typedef struct Item { - char type; - - char *path; - uid_t uid; - gid_t gid; - mode_t mode; - usec_t age; - - bool uid_set:1; - bool gid_set:1; - bool mode_set:1; - bool age_set:1; -} Item; - -static Hashmap *items = NULL, *globs = NULL; -static Set *unix_sockets = NULL; - -static bool arg_create = false; -static bool arg_clean = false; -static bool arg_remove = false; - -static const char *arg_prefix = NULL; - -#define MAX_DEPTH 256 - -static bool needs_glob(int t) { - return t == IGNORE_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH; -} - -static struct Item* find_glob(Hashmap *h, const char *match) { - Item *j; - Iterator i; - - HASHMAP_FOREACH(j, h, i) - if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0) - return j; - - return NULL; -} - -static void load_unix_sockets(void) { - FILE *f = NULL; - char line[LINE_MAX]; - - if (unix_sockets) - return; - - /* We maintain a cache of the sockets we found in - * /proc/net/unix to speed things up a little. */ - - if (!(unix_sockets = set_new(string_hash_func, string_compare_func))) - return; - - if (!(f = fopen("/proc/net/unix", "re"))) - return; - - if (!(fgets(line, sizeof(line), f))) - goto fail; - - for (;;) { - char *p, *s; - int k; - - if (!(fgets(line, sizeof(line), f))) - break; - - truncate_nl(line); - - if (strlen(line) < 53) - continue; - - p = line + 53; - p += strspn(p, WHITESPACE); - p += strcspn(p, WHITESPACE); - p += strspn(p, WHITESPACE); - - if (*p != '/') - continue; - - if (!(s = strdup(p))) - goto fail; - - path_kill_slashes(s); - - if ((k = set_put(unix_sockets, s)) < 0) { - free(s); - - if (k != -EEXIST) - goto fail; - } - } - - fclose(f); - return; - -fail: - set_free_free(unix_sockets); - unix_sockets = NULL; - - if (f) - fclose(f); -} - -static bool unix_socket_alive(const char *fn) { - assert(fn); - - load_unix_sockets(); - - if (unix_sockets) - return !!set_get(unix_sockets, (char*) fn); - - /* We don't know, so assume yes */ - return true; -} - -static int dir_cleanup( - const char *p, - DIR *d, - const struct stat *ds, - usec_t cutoff, - dev_t rootdev, - bool mountpoint, - int maxdepth) -{ - struct dirent *dent; - struct timespec times[2]; - bool deleted = false; - char *sub_path = NULL; - int r = 0; - - while ((dent = readdir(d))) { - struct stat s; - usec_t age; - - if (streq(dent->d_name, ".") || - streq(dent->d_name, "..")) - continue; - - if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) { - - if (errno != ENOENT) { - log_error("stat(%s/%s) failed: %m", p, dent->d_name); - r = -errno; - } - - continue; - } - - /* Stay on the same filesystem */ - if (s.st_dev != rootdev) - continue; - - /* Do not delete read-only files owned by root */ - if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) - continue; - - free(sub_path); - sub_path = NULL; - - if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - /* Is there an item configured for this path? */ - if (hashmap_get(items, sub_path)) - continue; - - if (find_glob(globs, sub_path)) - continue; - - if (S_ISDIR(s.st_mode)) { - - if (mountpoint && - streq(dent->d_name, "lost+found") && - s.st_uid == 0) - continue; - - if (maxdepth <= 0) - log_warning("Reached max depth on %s.", sub_path); - else { - DIR *sub_dir; - int q; - - sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW); - if (sub_dir == NULL) { - if (errno != ENOENT) { - log_error("opendir(%s/%s) failed: %m", p, dent->d_name); - r = -errno; - } - - continue; - } - - q = dir_cleanup(sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1); - closedir(sub_dir); - - if (q < 0) - r = q; - } - - /* Ignore ctime, we change it when deleting */ - age = MAX(timespec_load(&s.st_mtim), - timespec_load(&s.st_atim)); - if (age >= cutoff) - continue; - - log_debug("rmdir '%s'\n", sub_path); - - if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) { - if (errno != ENOENT && errno != ENOTEMPTY) { - log_error("rmdir(%s): %m", sub_path); - r = -errno; - } - } - - } 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. */ - if (s.st_mode & S_ISVTX) - continue; - - if (mountpoint && S_ISREG(s.st_mode)) { - if (streq(dent->d_name, ".journal") && - s.st_uid == 0) - continue; - - if (streq(dent->d_name, "aquota.user") || - streq(dent->d_name, "aquota.group")) - continue; - } - - /* Ignore sockets that are listed in /proc/net/unix */ - if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) - continue; - - /* Ignore device nodes */ - if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) - continue; - - age = MAX3(timespec_load(&s.st_mtim), - timespec_load(&s.st_atim), - timespec_load(&s.st_ctim)); - - if (age >= cutoff) - continue; - - log_debug("unlink '%s'\n", sub_path); - - if (unlinkat(dirfd(d), dent->d_name, 0) < 0) { - if (errno != ENOENT) { - log_error("unlink(%s): %m", sub_path); - r = -errno; - } - } - - deleted = true; - } - } - -finish: - if (deleted) { - /* Restore original directory timestamps */ - times[0] = ds->st_atim; - times[1] = ds->st_mtim; - - if (futimens(dirfd(d), times) < 0) - log_error("utimensat(%s): %m", p); - } - - free(sub_path); - - return r; -} - -static int clean_item(Item *i) { - DIR *d; - struct stat s, ps; - bool mountpoint; - int r; - usec_t cutoff, n; - - assert(i); - - if (i->type != CREATE_DIRECTORY && - i->type != TRUNCATE_DIRECTORY && - i->type != IGNORE_PATH) - return 0; - - if (!i->age_set || i->age <= 0) - return 0; - - n = now(CLOCK_REALTIME); - if (n < i->age) - return 0; - - cutoff = n - i->age; - - d = opendir(i->path); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open directory %s: %m", i->path); - return -errno; - } - - if (fstat(dirfd(d), &s) < 0) { - log_error("stat(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (!S_ISDIR(s.st_mode)) { - log_error("%s is not a directory.", i->path); - r = -ENOTDIR; - goto finish; - } - - if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) { - log_error("stat(%s/..) failed: %m", i->path); - r = -errno; - goto finish; - } - - mountpoint = s.st_dev != ps.st_dev || - (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino); - - r = dir_cleanup(i->path, d, &s, cutoff, s.st_dev, mountpoint, MAX_DEPTH); - -finish: - if (d) - closedir(d); - - return r; -} - -static int create_item(Item *i) { - int fd = -1, r; - mode_t u; - struct stat st; - - assert(i); - - switch (i->type) { - - case IGNORE_PATH: - case REMOVE_PATH: - case RECURSIVE_REMOVE_PATH: - return 0; - - case CREATE_FILE: - case TRUNCATE_FILE: - - u = umask(0); - fd = open(i->path, O_CREAT|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW| - (i->type == TRUNCATE_FILE ? O_TRUNC : 0), i->mode); - umask(u); - - if (fd < 0) { - log_error("Failed to create file %s: %m", i->path); - r = -errno; - goto finish; - } - - if (fstat(fd, &st) < 0) { - log_error("stat(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (!S_ISREG(st.st_mode)) { - log_error("%s is not a file.", i->path); - r = -EEXIST; - goto finish; - } - - if (i->mode_set) - if (fchmod(fd, i->mode) < 0) { - log_error("chmod(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (i->uid_set || i->gid_set) - if (fchown(fd, - i->uid_set ? i->uid : (uid_t) -1, - i->gid_set ? i->gid : (gid_t) -1) < 0) { - log_error("chown(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - break; - - case TRUNCATE_DIRECTORY: - case CREATE_DIRECTORY: - - u = umask(0); - mkdir_parents(i->path, 0755); - r = mkdir(i->path, i->mode); - umask(u); - - if (r < 0 && errno != EEXIST) { - log_error("Failed to create directory %s: %m", i->path); - r = -errno; - goto finish; - } - - if (stat(i->path, &st) < 0) { - log_error("stat(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (!S_ISDIR(st.st_mode)) { - log_error("%s is not a directory.", i->path); - r = -EEXIST; - goto finish; - } - - if (i->mode_set) - if (chmod(i->path, i->mode) < 0) { - log_error("chmod(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (i->uid_set || i->gid_set) - if (chown(i->path, - i->uid_set ? i->uid : (uid_t) -1, - i->gid_set ? i->gid : (gid_t) -1) < 0) { - - log_error("chown(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - break; - - case CREATE_FIFO: - - u = umask(0); - r = mkfifo(i->path, i->mode); - umask(u); - - if (r < 0 && errno != EEXIST) { - log_error("Failed to create fifo %s: %m", i->path); - r = -errno; - goto finish; - } - - if (stat(i->path, &st) < 0) { - log_error("stat(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (!S_ISFIFO(st.st_mode)) { - log_error("%s is not a fifo.", i->path); - r = -EEXIST; - goto finish; - } - - if (i->mode_set) - if (chmod(i->path, i->mode) < 0) { - log_error("chmod(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - if (i->uid_set || i->gid_set) - if (chown(i->path, - i->uid_set ? i->uid : (uid_t) -1, - i->gid_set ? i->gid : (gid_t) -1) < 0) { - log_error("chown(%s) failed: %m", i->path); - r = -errno; - goto finish; - } - - break; - } - - if ((r = label_fix(i->path, false)) < 0) - goto finish; - - log_debug("%s created successfully.", i->path); - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} - -static int remove_item(Item *i, const char *instance) { - int r; - - assert(i); - - switch (i->type) { - - case CREATE_FILE: - case TRUNCATE_FILE: - case CREATE_DIRECTORY: - case CREATE_FIFO: - case IGNORE_PATH: - break; - - case REMOVE_PATH: - if (remove(instance) < 0 && errno != ENOENT) { - log_error("remove(%s): %m", instance); - return -errno; - } - - break; - - case TRUNCATE_DIRECTORY: - case RECURSIVE_REMOVE_PATH: - if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false)) < 0 && - r != -ENOENT) { - log_error("rm_rf(%s): %s", instance, strerror(-r)); - return r; - } - - break; - } - - return 0; -} - -static int remove_item_glob(Item *i) { - assert(i); - - switch (i->type) { - - case CREATE_FILE: - case TRUNCATE_FILE: - case CREATE_DIRECTORY: - case CREATE_FIFO: - case IGNORE_PATH: - break; - - case REMOVE_PATH: - case TRUNCATE_DIRECTORY: - case RECURSIVE_REMOVE_PATH: { - int r = 0, k; - glob_t g; - char **fn; - - zero(g); - - errno = 0; - if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) { - - if (k != GLOB_NOMATCH) { - if (errno != 0) - errno = EIO; - - log_error("glob(%s) failed: %m", i->path); - return -errno; - } - } - - STRV_FOREACH(fn, g.gl_pathv) - if ((k = remove_item(i, *fn)) < 0) - r = k; - - globfree(&g); - return r; - } - } - - return 0; -} - -static int process_item(Item *i) { - int r, q, p; - - assert(i); - - r = arg_create ? create_item(i) : 0; - q = arg_remove ? remove_item_glob(i) : 0; - p = arg_clean ? clean_item(i) : 0; - - if (r < 0) - return r; - - if (q < 0) - return q; - - return p; -} - -static void item_free(Item *i) { - assert(i); - - free(i->path); - free(i); -} - -static bool item_equal(Item *a, Item *b) { - assert(a); - assert(b); - - if (!streq_ptr(a->path, b->path)) - return false; - - if (a->type != b->type) - return false; - - if (a->uid_set != b->uid_set || - (a->uid_set && a->uid != b->uid)) - return false; - - if (a->gid_set != b->gid_set || - (a->gid_set && a->gid != b->gid)) - return false; - - if (a->mode_set != b->mode_set || - (a->mode_set && a->mode != b->mode)) - return false; - - if (a->age_set != b->age_set || - (a->age_set && a->age != b->age)) - return false; - - return true; -} - -static int parse_line(const char *fname, unsigned line, const char *buffer) { - Item *i, *existing; - char *mode = NULL, *user = NULL, *group = NULL, *age = NULL; - Hashmap *h; - int r; - - assert(fname); - assert(line >= 1); - assert(buffer); - - if (!(i = new0(Item, 1))) { - log_error("Out of memory"); - return -ENOMEM; - } - - if (sscanf(buffer, - "%c " - "%ms " - "%ms " - "%ms " - "%ms " - "%ms", - &i->type, - &i->path, - &mode, - &user, - &group, - &age) < 2) { - log_error("[%s:%u] Syntax error.", fname, line); - r = -EIO; - goto finish; - } - - if (i->type != CREATE_FILE && - i->type != TRUNCATE_FILE && - i->type != CREATE_DIRECTORY && - i->type != TRUNCATE_DIRECTORY && - i->type != CREATE_FIFO && - i->type != IGNORE_PATH && - i->type != REMOVE_PATH && - i->type != RECURSIVE_REMOVE_PATH) { - log_error("[%s:%u] Unknown file type '%c'.", fname, line, i->type); - r = -EBADMSG; - goto finish; - } - - if (!path_is_absolute(i->path)) { - log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path); - r = -EBADMSG; - goto finish; - } - - path_kill_slashes(i->path); - - if (arg_prefix && !path_startswith(i->path, arg_prefix)) { - r = 0; - goto finish; - } - - if (user && !streq(user, "-")) { - const char *u = user; - - r = get_user_creds(&u, &i->uid, NULL, NULL); - if (r < 0) { - log_error("[%s:%u] Unknown user '%s'.", fname, line, user); - goto finish; - } - - i->uid_set = true; - } - - if (group && !streq(group, "-")) { - const char *g = group; - - r = get_group_creds(&g, &i->gid); - if (r < 0) { - log_error("[%s:%u] Unknown group '%s'.", fname, line, group); - goto finish; - } - - i->gid_set = true; - } - - if (mode && !streq(mode, "-")) { - unsigned m; - - if (sscanf(mode, "%o", &m) != 1) { - log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode); - r = -ENOENT; - goto finish; - } - - i->mode = m; - i->mode_set = true; - } else - i->mode = i->type == CREATE_DIRECTORY ? 0755 : 0644; - - if (age && !streq(age, "-")) { - if (parse_usec(age, &i->age) < 0) { - log_error("[%s:%u] Invalid age '%s'.", fname, line, age); - r = -EBADMSG; - goto finish; - } - - i->age_set = true; - } - - h = needs_glob(i->type) ? globs : items; - - if ((existing = hashmap_get(h, i->path))) { - - /* Two identical items are fine */ - if (!item_equal(existing, i)) - log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); - - r = 0; - goto finish; - } - - if ((r = hashmap_put(h, i->path, i)) < 0) { - log_error("Failed to insert item %s: %s", i->path, strerror(-r)); - goto finish; - } - - i = NULL; - r = 0; - -finish: - free(user); - free(group); - free(mode); - free(age); - - if (i) - item_free(i); - - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" - "Creates, deletes and cleans up volatile and temporary files and directories.\n\n" - " -h --help Show this help\n" - " --create Create marked files/directories\n" - " --clean Clean up marked directories\n" - " --remove Remove marked files/directories\n" - " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_CREATE, - ARG_CLEAN, - ARG_REMOVE, - ARG_PREFIX - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "create", no_argument, NULL, ARG_CREATE }, - { "clean", no_argument, NULL, ARG_CLEAN }, - { "remove", no_argument, NULL, ARG_REMOVE }, - { "prefix", required_argument, NULL, ARG_PREFIX }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_CREATE: - arg_create = true; - break; - - case ARG_CLEAN: - arg_clean = true; - break; - - case ARG_REMOVE: - arg_remove = true; - break; - - case ARG_PREFIX: - arg_prefix = optarg; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (!arg_clean && !arg_create && !arg_remove) { - log_error("You need to specify at least one of --clean, --create or --remove."); - return -EINVAL; - } - - return 1; -} - -static int read_config_file(const char *fn, bool ignore_enoent) { - FILE *f; - unsigned v = 0; - int r = 0; - - assert(fn); - - if (!(f = fopen(fn, "re"))) { - - if (ignore_enoent && errno == ENOENT) - return 0; - - log_error("Failed to open %s: %m", fn); - return -errno; - } - - log_debug("apply: %s\n", fn); - for (;;) { - char line[LINE_MAX], *l; - int k; - - if (!(fgets(line, sizeof(line), f))) - break; - - v++; - - l = strstrip(line); - if (*l == '#' || *l == 0) - continue; - - if ((k = parse_line(fn, v, l)) < 0) - if (r == 0) - r = k; - } - - if (ferror(f)) { - log_error("Failed to read from file %s: %m", fn); - if (r == 0) - r = -EIO; - } - - fclose(f); - - return r; -} - -int main(int argc, char *argv[]) { - int r; - Item *i; - Iterator iterator; - - if ((r = parse_argv(argc, argv)) <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - label_init(); - - items = hashmap_new(string_hash_func, string_compare_func); - globs = hashmap_new(string_hash_func, string_compare_func); - - if (!items || !globs) { - log_error("Out of memory"); - r = EXIT_FAILURE; - goto finish; - } - - r = EXIT_SUCCESS; - - if (optind < argc) { - int j; - - for (j = optind; j < argc; j++) - if (read_config_file(argv[j], false) < 0) - r = EXIT_FAILURE; - - } else { - char **files, **f; - - r = conf_files_list(&files, ".conf", - "/run/tmpfiles.d", - "/etc/tmpfiles.d", - "/usr/local/lib/tmpfiles.d", - "/usr/lib/tmpfiles.d", - NULL); - if (r < 0) { - r = EXIT_FAILURE; - log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r)); - goto finish; - } - - STRV_FOREACH(f, files) { - if (read_config_file(*f, true) < 0) - r = EXIT_FAILURE; - } - - strv_free(files); - } - - HASHMAP_FOREACH(i, globs, iterator) - process_item(i); - - HASHMAP_FOREACH(i, items, iterator) - process_item(i); - -finish: - while ((i = hashmap_steal_first(items))) - item_free(i); - - while ((i = hashmap_steal_first(globs))) - item_free(i); - - hashmap_free(items); - hashmap_free(globs); - - set_free_free(unix_sockets); - - label_finish(); - - return r; -} diff --git a/src/tmpfiles/Makefile b/src/tmpfiles/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/tmpfiles/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c new file mode 100644 index 0000000..6e36dc7 --- /dev/null +++ b/src/tmpfiles/tmpfiles.c @@ -0,0 +1,1517 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering, Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "macro.h" +#include "missing.h" +#include "mkdir.h" +#include "path-util.h" +#include "strv.h" +#include "label.h" +#include "set.h" +#include "conf-files.h" +#include "capability.h" +#include "specifier.h" +#include "build.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 + * properly owned directories beneath /tmp, /var/tmp, /run, which are + * volatile and hence need to be recreated on bootup. */ + +typedef enum ItemType { + /* These ones take file names */ + CREATE_FILE = 'f', + TRUNCATE_FILE = 'F', + WRITE_FILE = 'w', + CREATE_DIRECTORY = 'd', + TRUNCATE_DIRECTORY = 'D', + CREATE_FIFO = 'p', + CREATE_SYMLINK = 'L', + CREATE_CHAR_DEVICE = 'c', + CREATE_BLOCK_DEVICE = 'b', + ADJUST_MODE = 'm', + + /* These ones take globs */ + IGNORE_PATH = 'x', + IGNORE_DIRECTORY_PATH = 'X', + REMOVE_PATH = 'r', + RECURSIVE_REMOVE_PATH = 'R', + RELABEL_PATH = 'z', + RECURSIVE_RELABEL_PATH = 'Z' +} ItemType; + +typedef struct Item { + ItemType type; + + char *path; + char *argument; + uid_t uid; + gid_t gid; + mode_t mode; + usec_t age; + + dev_t major_minor; + + bool uid_set:1; + bool gid_set:1; + bool mode_set:1; + bool age_set:1; + + bool keep_first_level:1; +} Item; + +static Hashmap *items = NULL, *globs = NULL; +static Set *unix_sockets = NULL; + +static bool arg_create = false; +static bool arg_clean = false; +static bool arg_remove = false; +static bool arg_boot = false; + +static char **include_prefixes = NULL; +static char **exclude_prefixes = NULL; + +static const char conf_file_dirs[] = + "/etc/tmpfiles.d\0" + "/run/tmpfiles.d\0" + "/usr/local/lib/tmpfiles.d\0" + "/usr/lib/tmpfiles.d\0" +#ifdef HAVE_SPLIT_USR + "/lib/tmpfiles.d\0" +#endif + ; + +#define MAX_DEPTH 256 + +static bool needs_glob(ItemType t) { + return t == IGNORE_PATH || t == IGNORE_DIRECTORY_PATH || t == REMOVE_PATH || t == RECURSIVE_REMOVE_PATH || t == RELABEL_PATH || t == RECURSIVE_RELABEL_PATH; +} + +static struct Item* find_glob(Hashmap *h, const char *match) { + Item *j; + Iterator i; + + HASHMAP_FOREACH(j, h, i) + if (fnmatch(j->path, match, FNM_PATHNAME|FNM_PERIOD) == 0) + return j; + + return NULL; +} + +static void load_unix_sockets(void) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + + if (unix_sockets) + return; + + /* We maintain a cache of the sockets we found in + * /proc/net/unix to speed things up a little. */ + + unix_sockets = set_new(string_hash_func, string_compare_func); + if (!unix_sockets) + return; + + f = fopen("/proc/net/unix", "re"); + if (!f) + return; + + /* Skip header */ + if (!fgets(line, sizeof(line), f)) + goto fail; + + for (;;) { + char *p, *s; + int k; + + if (!fgets(line, sizeof(line), f)) + break; + + truncate_nl(line); + + p = strchr(line, ':'); + if (!p) + continue; + + if (strlen(p) < 37) + continue; + + p += 37; + p += strspn(p, WHITESPACE); + p += strcspn(p, WHITESPACE); /* skip one more word */ + p += strspn(p, WHITESPACE); + + if (*p != '/') + continue; + + s = strdup(p); + if (!s) + goto fail; + + path_kill_slashes(s); + + k = set_consume(unix_sockets, s); + if (k < 0 && k != -EEXIST) + goto fail; + } + + return; + +fail: + set_free_free(unix_sockets); + unix_sockets = NULL; +} + +static bool unix_socket_alive(const char *fn) { + assert(fn); + + load_unix_sockets(); + + if (unix_sockets) + return !!set_get(unix_sockets, (char*) fn); + + /* We don't know, so assume yes */ + return true; +} + +static int dir_is_mount_point(DIR *d, const char *subdir) { + struct file_handle *h; + int mount_id_parent, mount_id; + int r_p, r; + + h = alloca(MAX_HANDLE_SZ); + + h->handle_bytes = MAX_HANDLE_SZ; + r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0); + if (r_p < 0) + r_p = -errno; + + h->handle_bytes = MAX_HANDLE_SZ; + r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0); + if (r < 0) + r = -errno; + + /* got no handle; make no assumptions, return error */ + if (r_p < 0 && r < 0) + return r_p; + + /* got both handles; if they differ, it is a mount point */ + if (r_p >= 0 && r >= 0) + return mount_id_parent != mount_id; + + /* got only one handle; assume different mount points if one + * of both queries was not supported by the filesystem */ + if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP) + return true; + + /* return error */ + if (r_p < 0) + return r_p; + return r; +} + +static int dir_cleanup( + Item *i, + const char *p, + DIR *d, + const struct stat *ds, + usec_t cutoff, + dev_t rootdev, + bool mountpoint, + int maxdepth, + bool keep_this_level) { + + struct dirent *dent; + struct timespec times[2]; + bool deleted = false; + int r = 0; + + while ((dent = readdir(d))) { + struct stat s; + usec_t age; + _cleanup_free_ char *sub_path = NULL; + + if (streq(dent->d_name, ".") || + streq(dent->d_name, "..")) + continue; + + if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) { + if (errno == ENOENT) + continue; + + /* FUSE, NFS mounts, SELinux might return EACCES */ + if (errno == EACCES) + log_debug("stat(%s/%s) failed: %m", p, dent->d_name); + else + log_error("stat(%s/%s) failed: %m", p, dent->d_name); + r = -errno; + continue; + } + + /* Stay on the same filesystem */ + if (s.st_dev != rootdev) + continue; + + /* Try to detect bind mounts of the same filesystem instance; they + * do not differ in device major/minors. This type of query is not + * supported on all kernels or filesystem types though. */ + if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0) + continue; + + /* Do not delete read-only files owned by root */ + if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) + continue; + + if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) { + r = log_oom(); + goto finish; + } + + /* Is there an item configured for this path? */ + if (hashmap_get(items, sub_path)) + continue; + + if (find_glob(globs, sub_path)) + continue; + + if (S_ISDIR(s.st_mode)) { + + if (mountpoint && + streq(dent->d_name, "lost+found") && + s.st_uid == 0) + continue; + + if (maxdepth <= 0) + log_warning("Reached max depth on %s.", sub_path); + else { + _cleanup_closedir_ DIR *sub_dir; + int q; + + sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME); + if (sub_dir == NULL) { + if (errno != ENOENT) { + log_error("opendir(%s/%s) failed: %m", p, dent->d_name); + r = -errno; + } + + 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. */ + + if (keep_this_level) + continue; + + /* Ignore ctime, we change it when deleting */ + age = MAX(timespec_load(&s.st_mtim), + timespec_load(&s.st_atim)); + if (age >= cutoff) + continue; + + if (i->type != IGNORE_DIRECTORY_PATH || !streq(dent->d_name, p)) { + log_debug("rmdir '%s'", sub_path); + + if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) { + if (errno != ENOENT && errno != ENOTEMPTY) { + log_error("rmdir(%s): %m", sub_path); + r = -errno; + } + } + } + + } 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. */ + if (s.st_mode & S_ISVTX) + continue; + + if (mountpoint && S_ISREG(s.st_mode)) { + if (streq(dent->d_name, ".journal") && + s.st_uid == 0) + continue; + + if (streq(dent->d_name, "aquota.user") || + streq(dent->d_name, "aquota.group")) + continue; + } + + /* Ignore sockets that are listed in /proc/net/unix */ + if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) + continue; + + /* Ignore device nodes */ + if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) + continue; + + /* Keep files on this level around if this is + * requested */ + if (keep_this_level) + continue; + + age = MAX3(timespec_load(&s.st_mtim), + timespec_load(&s.st_atim), + timespec_load(&s.st_ctim)); + + if (age >= cutoff) + continue; + + log_debug("unlink '%s'", sub_path); + + if (unlinkat(dirfd(d), dent->d_name, 0) < 0) { + if (errno != ENOENT) { + log_error("unlink(%s): %m", sub_path); + r = -errno; + } + } + + deleted = true; + } + } + +finish: + if (deleted) { + /* Restore original directory timestamps */ + times[0] = ds->st_atim; + times[1] = ds->st_mtim; + + if (futimens(dirfd(d), times) < 0) + log_error("utimensat(%s): %m", p); + } + + return r; +} + +static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) { + /* not using i->path directly because it may be a glob */ + if (i->mode_set) + if (chmod(path, i->mode) < 0) { + if (errno != ENOENT || !ignore_enoent) { + log_error("chmod(%s) failed: %m", path); + return -errno; + } + } + + if (i->uid_set || i->gid_set) + if (chown(path, + i->uid_set ? i->uid : (uid_t) -1, + i->gid_set ? i->gid : (gid_t) -1) < 0) { + + if (errno != ENOENT || !ignore_enoent) { + log_error("chown(%s) failed: %m", path); + return -errno; + } + } + + return label_fix(path, ignore_enoent, false); +} + +static int item_set_perms(Item *i, const char *path) { + return item_set_perms_full(i, path, false); +} + +static int write_one_file(Item *i, const char *path) { + int e, flags; + int fd = -1; + struct stat st; + int r = 0; + + flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND : + i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0; + + RUN_WITH_UMASK(0) { + label_context_set(path, S_IFREG); + fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode); + e = errno; + label_context_clear(); + errno = e; + } + + if (fd < 0) { + if (i->type == WRITE_FILE && errno == ENOENT) + return 0; + + log_error("Failed to create file %s: %m", path); + return -errno; + } + + if (i->argument) { + ssize_t n; + size_t l; + _cleanup_free_ char *unescaped; + + unescaped = cunescape(i->argument); + if (unescaped == NULL) { + close_nointr_nofail(fd); + return log_oom(); + } + + l = strlen(unescaped); + n = write(fd, unescaped, l); + + if (n < 0 || (size_t) n < l) { + log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write"); + close_nointr_nofail(fd); + return n < 0 ? n : -EIO; + } + } + + close_nointr_nofail(fd); + + if (stat(path, &st) < 0) { + log_error("stat(%s) failed: %m", path); + return -errno; + } + + if (!S_ISREG(st.st_mode)) { + log_error("%s is not a file.", path); + return -EEXIST; + } + + r = item_set_perms(i, path); + if (r < 0) + return r; + + return 0; +} + +static int recursive_relabel_children(Item *i, const char *path) { + _cleanup_closedir_ DIR *d; + int ret = 0; + + /* This returns the first error we run into, but nevertheless + * tries to go on */ + + d = opendir(path); + if (!d) + return errno == ENOENT ? 0 : -errno; + + for (;;) { + struct dirent *de; + bool is_dir; + int r; + _cleanup_free_ char *entry_path = NULL; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + if (ret == 0) + ret = -errno; + break; + } + + if (!de) + break; + + if (streq(de->d_name, ".") || streq(de->d_name, "..")) + continue; + + if (asprintf(&entry_path, "%s/%s", path, de->d_name) < 0) { + if (ret == 0) + ret = -ENOMEM; + continue; + } + + if (de->d_type == DT_UNKNOWN) { + struct stat st; + + if (lstat(entry_path, &st) < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + continue; + } + + is_dir = S_ISDIR(st.st_mode); + + } else + is_dir = de->d_type == DT_DIR; + + r = item_set_perms(i, entry_path); + if (r < 0) { + if (ret == 0 && r != -ENOENT) + ret = r; + continue; + } + + if (is_dir) { + r = recursive_relabel_children(i, entry_path); + if (r < 0 && ret == 0) + ret = r; + } + } + + return ret; +} + +static int recursive_relabel(Item *i, const char *path) { + int r; + struct stat st; + + r = item_set_perms(i, path); + if (r < 0) + return r; + + if (lstat(path, &st) < 0) + return -errno; + + if (S_ISDIR(st.st_mode)) + r = recursive_relabel_children(i, path); + + return r; +} + +static int glob_item(Item *i, int (*action)(Item *, const char *)) { + int r = 0, k; + _cleanup_globfree_ glob_t g = {}; + char **fn; + + errno = 0; + k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + if (k != 0) + if (k != GLOB_NOMATCH) { + if (errno > 0) + errno = EIO; + + log_error("glob(%s) failed: %m", i->path); + return -errno; + } + + STRV_FOREACH(fn, g.gl_pathv) { + k = action(i, *fn); + if (k < 0) + r = k; + } + + return r; +} + +static int create_item(Item *i) { + int e; + struct stat st; + int r = 0; + + assert(i); + + switch (i->type) { + + case IGNORE_PATH: + case IGNORE_DIRECTORY_PATH: + case REMOVE_PATH: + case RECURSIVE_REMOVE_PATH: + return 0; + + case CREATE_FILE: + case TRUNCATE_FILE: + r = write_one_file(i, i->path); + if (r < 0) + return r; + break; + + case WRITE_FILE: + r = glob_item(i, write_one_file); + if (r < 0) + return r; + + break; + + case ADJUST_MODE: + r = item_set_perms_full(i, i->path, true); + if (r < 0) + return r; + + break; + + case TRUNCATE_DIRECTORY: + case CREATE_DIRECTORY: + + RUN_WITH_UMASK(0000) { + mkdir_parents_label(i->path, 0755); + r = mkdir(i->path, i->mode); + } + + if (r < 0 && errno != EEXIST) { + log_error("Failed to create directory %s: %m", i->path); + return -errno; + } + + if (stat(i->path, &st) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } + + if (!S_ISDIR(st.st_mode)) { + log_error("%s is not a directory.", i->path); + return -EEXIST; + } + + r = item_set_perms(i, i->path); + if (r < 0) + return r; + + break; + + case CREATE_FIFO: + + RUN_WITH_UMASK(0000) { + r = mkfifo(i->path, i->mode); + } + + if (r < 0 && errno != EEXIST) { + log_error("Failed to create fifo %s: %m", i->path); + return -errno; + } + + if (stat(i->path, &st) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } + + if (!S_ISFIFO(st.st_mode)) { + log_error("%s is not a fifo.", i->path); + return -EEXIST; + } + + r = item_set_perms(i, i->path); + if (r < 0) + return r; + + break; + + case CREATE_SYMLINK: { + _cleanup_free_ char *x = NULL; + + label_context_set(i->path, S_IFLNK); + r = symlink(i->argument, i->path); + e = errno; + label_context_clear(); + errno = e; + + if (r < 0 && errno != EEXIST) { + log_error("symlink(%s, %s) failed: %m", i->argument, i->path); + return -errno; + } + + r = readlink_malloc(i->path, &x); + if (r < 0) { + log_error("readlink(%s) failed: %s", i->path, strerror(-r)); + return -errno; + } + + if (!streq(i->argument, x)) { + log_error("%s is not the right symlinks.", i->path); + return -EEXIST; + } + + break; + } + + case CREATE_BLOCK_DEVICE: + case CREATE_CHAR_DEVICE: { + mode_t file_type; + + if (have_effective_cap(CAP_MKNOD) == 0) { + /* In a container we lack CAP_MKNOD. We + shouldn't attempt to create the device node in + that case to avoid noise, and we don't support + virtualized devices in containers anyway. */ + + log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path); + return 0; + } + + file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR); + + RUN_WITH_UMASK(0000) { + label_context_set(i->path, file_type); + r = mknod(i->path, i->mode | file_type, i->major_minor); + e = errno; + label_context_clear(); + errno = e; + } + + if (r < 0 && errno != EEXIST) { + log_error("Failed to create device node %s: %m", i->path); + return -errno; + } + + if (stat(i->path, &st) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } + + if ((st.st_mode & S_IFMT) != file_type) { + log_error("%s is not a device node.", i->path); + return -EEXIST; + } + + r = item_set_perms(i, i->path); + if (r < 0) + return r; + + break; + } + + case RELABEL_PATH: + + r = glob_item(i, item_set_perms); + if (r < 0) + return r; + break; + + case RECURSIVE_RELABEL_PATH: + + r = glob_item(i, recursive_relabel); + if (r < 0) + return r; + } + + log_debug("%s created successfully.", i->path); + + return 0; +} + +static int remove_item_instance(Item *i, const char *instance) { + int r; + + assert(i); + + switch (i->type) { + + case CREATE_FILE: + case TRUNCATE_FILE: + case CREATE_DIRECTORY: + case CREATE_FIFO: + case CREATE_SYMLINK: + case CREATE_BLOCK_DEVICE: + case CREATE_CHAR_DEVICE: + case IGNORE_PATH: + case IGNORE_DIRECTORY_PATH: + case RELABEL_PATH: + case RECURSIVE_RELABEL_PATH: + case WRITE_FILE: + case ADJUST_MODE: + break; + + case REMOVE_PATH: + if (remove(instance) < 0 && errno != ENOENT) { + log_error("remove(%s): %m", instance); + return -errno; + } + + break; + + case TRUNCATE_DIRECTORY: + case RECURSIVE_REMOVE_PATH: + /* FIXME: we probably should use dir_cleanup() here + * instead of rm_rf() so that 'x' is honoured. */ + r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false); + if (r < 0 && r != -ENOENT) { + log_error("rm_rf(%s): %s", instance, strerror(-r)); + return r; + } + + break; + } + + return 0; +} + +static int remove_item(Item *i) { + int r = 0; + + assert(i); + + switch (i->type) { + + case CREATE_FILE: + case TRUNCATE_FILE: + case CREATE_DIRECTORY: + case CREATE_FIFO: + case CREATE_SYMLINK: + case CREATE_CHAR_DEVICE: + case CREATE_BLOCK_DEVICE: + case IGNORE_PATH: + case IGNORE_DIRECTORY_PATH: + case RELABEL_PATH: + case RECURSIVE_RELABEL_PATH: + case WRITE_FILE: + case ADJUST_MODE: + break; + + case REMOVE_PATH: + case TRUNCATE_DIRECTORY: + case RECURSIVE_REMOVE_PATH: + r = glob_item(i, remove_item_instance); + break; + } + + return r; +} + +static int clean_item_instance(Item *i, const char* instance) { + _cleanup_closedir_ DIR *d = NULL; + struct stat s, ps; + bool mountpoint; + int r; + usec_t cutoff, n; + + assert(i); + + if (!i->age_set) + return 0; + + n = now(CLOCK_REALTIME); + if (n < i->age) + return 0; + + cutoff = n - i->age; + + d = opendir(instance); + if (!d) { + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + log_error("Failed to open directory %s: %m", i->path); + return -errno; + } + + if (fstat(dirfd(d), &s) < 0) { + log_error("stat(%s) failed: %m", i->path); + return -errno; + } + + if (!S_ISDIR(s.st_mode)) { + log_error("%s is not a directory.", i->path); + return -ENOTDIR; + } + + if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) { + log_error("stat(%s/..) failed: %m", i->path); + return -errno; + } + + mountpoint = s.st_dev != ps.st_dev || + (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino); + + r = dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint, + MAX_DEPTH, i->keep_first_level); + return r; +} + +static int clean_item(Item *i) { + int r = 0; + + assert(i); + + switch (i->type) { + case CREATE_DIRECTORY: + case TRUNCATE_DIRECTORY: + case IGNORE_PATH: + clean_item_instance(i, i->path); + break; + case IGNORE_DIRECTORY_PATH: + r = glob_item(i, clean_item_instance); + break; + default: + break; + } + + return r; +} + +static int process_item(Item *i) { + int r, q, p; + + assert(i); + + r = arg_create ? create_item(i) : 0; + q = arg_remove ? remove_item(i) : 0; + p = arg_clean ? clean_item(i) : 0; + + if (r < 0) + return r; + + if (q < 0) + return q; + + return p; +} + +static void item_free(Item *i) { + assert(i); + + free(i->path); + free(i->argument); + free(i); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(Item*, item_free); +#define _cleanup_item_free_ _cleanup_(item_freep) + +static bool item_equal(Item *a, Item *b) { + assert(a); + assert(b); + + if (!streq_ptr(a->path, b->path)) + return false; + + if (a->type != b->type) + return false; + + if (a->uid_set != b->uid_set || + (a->uid_set && a->uid != b->uid)) + return false; + + if (a->gid_set != b->gid_set || + (a->gid_set && a->gid != b->gid)) + return false; + + if (a->mode_set != b->mode_set || + (a->mode_set && a->mode != b->mode)) + return false; + + if (a->age_set != b->age_set || + (a->age_set && a->age != b->age)) + return false; + + if ((a->type == CREATE_FILE || + a->type == TRUNCATE_FILE || + a->type == WRITE_FILE || + a->type == CREATE_SYMLINK) && + !streq_ptr(a->argument, b->argument)) + return false; + + if ((a->type == CREATE_CHAR_DEVICE || + a->type == CREATE_BLOCK_DEVICE) && + a->major_minor != b->major_minor) + return false; + + return true; +} + +static bool should_include_path(const char *path) { + char **prefix; + + STRV_FOREACH(prefix, exclude_prefixes) { + if (path_startswith(path, *prefix)) + return false; + } + + STRV_FOREACH(prefix, include_prefixes) { + if (path_startswith(path, *prefix)) + return true; + } + + /* no matches, so we should include this path only if we + * have no whitelist at all */ + return strv_length(include_prefixes) == 0; +} + +static int parse_line(const char *fname, unsigned line, const char *buffer) { + + static const Specifier specifier_table[] = { + { 'm', specifier_machine_id, NULL }, + { 'b', specifier_boot_id, NULL }, + { 'H', specifier_host_name, NULL }, + { 'v', specifier_kernel_release, NULL }, + {} + }; + + _cleanup_item_free_ Item *i = NULL; + Item *existing; + _cleanup_free_ char + *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL; + char type; + Hashmap *h; + int r, n = -1; + + assert(fname); + assert(line >= 1); + assert(buffer); + + r = sscanf(buffer, + "%ms %ms %ms %ms %ms %ms %n", + &action, + &path, + &mode, + &user, + &group, + &age, + &n); + if (r < 2) { + log_error("[%s:%u] Syntax error.", fname, line); + return -EIO; + } + + if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) { + log_error("[%s:%u] Unknown modifier '%s'", fname, line, action); + return -EINVAL; + } else if (strlen(action) > 1 && !arg_boot) + return 0; + + type = action[0]; + + i = new0(Item, 1); + if (!i) + return log_oom(); + + r = specifier_printf(path, specifier_table, NULL, &i->path); + if (r < 0) { + log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, path); + return r; + } + + if (n >= 0) { + n += strspn(buffer+n, WHITESPACE); + if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) { + i->argument = unquote(buffer+n, "\""); + if (!i->argument) + return log_oom(); + } + } + + switch(type) { + + case CREATE_FILE: + case TRUNCATE_FILE: + case CREATE_DIRECTORY: + case TRUNCATE_DIRECTORY: + case CREATE_FIFO: + case IGNORE_PATH: + case IGNORE_DIRECTORY_PATH: + case REMOVE_PATH: + case RECURSIVE_REMOVE_PATH: + case RELABEL_PATH: + case RECURSIVE_RELABEL_PATH: + case ADJUST_MODE: + break; + + case CREATE_SYMLINK: + if (!i->argument) { + log_error("[%s:%u] Symlink file requires argument.", fname, line); + return -EBADMSG; + } + break; + + case WRITE_FILE: + if (!i->argument) { + log_error("[%s:%u] Write file requires argument.", fname, line); + return -EBADMSG; + } + break; + + case CREATE_CHAR_DEVICE: + case CREATE_BLOCK_DEVICE: { + unsigned major, minor; + + if (!i->argument) { + log_error("[%s:%u] Device file requires argument.", fname, line); + return -EBADMSG; + } + + if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) { + log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument); + return -EBADMSG; + } + + i->major_minor = makedev(major, minor); + break; + } + + default: + log_error("[%s:%u] Unknown file type '%c'.", fname, line, type); + return -EBADMSG; + } + + i->type = type; + + if (!path_is_absolute(i->path)) { + log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path); + return -EBADMSG; + } + + path_kill_slashes(i->path); + + if (!should_include_path(i->path)) + return 0; + + if (user && !streq(user, "-")) { + const char *u = user; + + r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); + if (r < 0) { + log_error("[%s:%u] Unknown user '%s'.", fname, line, user); + return r; + } + + i->uid_set = true; + } + + if (group && !streq(group, "-")) { + const char *g = group; + + r = get_group_creds(&g, &i->gid); + if (r < 0) { + log_error("[%s:%u] Unknown group '%s'.", fname, line, group); + return r; + } + + i->gid_set = true; + } + + if (mode && !streq(mode, "-")) { + unsigned m; + + if (sscanf(mode, "%o", &m) != 1) { + log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode); + return -ENOENT; + } + + i->mode = m; + i->mode_set = true; + } else + i->mode = + i->type == CREATE_DIRECTORY || + i->type == TRUNCATE_DIRECTORY ? 0755 : 0644; + + if (age && !streq(age, "-")) { + const char *a = age; + + if (*a == '~') { + i->keep_first_level = true; + a++; + } + + if (parse_sec(a, &i->age) < 0) { + log_error("[%s:%u] Invalid age '%s'.", fname, line, age); + return -EBADMSG; + } + + i->age_set = true; + } + + h = needs_glob(i->type) ? globs : items; + + existing = hashmap_get(h, i->path); + if (existing) { + + /* Two identical items are fine */ + if (!item_equal(existing, i)) + log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); + + return 0; + } + + r = hashmap_put(h, i->path, i); + if (r < 0) { + log_error("Failed to insert item %s: %s", i->path, strerror(-r)); + return r; + } + + i = NULL; /* avoid cleanup */ + + return 0; +} + +static int help(void) { + + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" + "Creates, deletes and cleans up volatile and temporary files and directories.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --create Create marked files/directories\n" + " --clean Clean up marked directories\n" + " --remove Remove marked files/directories\n" + " --boot Execute actions only safe at boot\n" + " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n" + " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_CREATE, + ARG_CLEAN, + ARG_REMOVE, + ARG_BOOT, + ARG_PREFIX, + ARG_EXCLUDE_PREFIX, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "create", no_argument, NULL, ARG_CREATE }, + { "clean", no_argument, NULL, ARG_CLEAN }, + { "remove", no_argument, NULL, ARG_REMOVE }, + { "boot", no_argument, NULL, ARG_BOOT }, + { "prefix", required_argument, NULL, ARG_PREFIX }, + { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_CREATE: + arg_create = true; + break; + + case ARG_CLEAN: + arg_clean = true; + break; + + case ARG_REMOVE: + arg_remove = true; + break; + + case ARG_BOOT: + arg_boot = true; + break; + + case ARG_PREFIX: + if (strv_push(&include_prefixes, optarg) < 0) + return log_oom(); + break; + + case ARG_EXCLUDE_PREFIX: + if (strv_push(&exclude_prefixes, optarg) < 0) + return log_oom(); + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (!arg_clean && !arg_create && !arg_remove) { + log_error("You need to specify at least one of --clean, --create or --remove."); + return -EINVAL; + } + + return 1; +} + +static int read_config_file(const char *fn, bool ignore_enoent) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + Iterator iterator; + unsigned v = 0; + Item *i; + int r; + + assert(fn); + + r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f); + if (r < 0) { + if (ignore_enoent && r == -ENOENT) + return 0; + + log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r)); + return r; + } + + FOREACH_LINE(line, f, break) { + char *l; + int k; + + v++; + + l = strstrip(line); + if (*l == '#' || *l == 0) + continue; + + k = parse_line(fn, v, l); + if (k < 0 && r == 0) + r = k; + } + + /* we have to determine age parameter for each entry of type X */ + HASHMAP_FOREACH(i, globs, iterator) { + Iterator iter; + Item *j, *candidate_item = NULL; + + if (i->type != IGNORE_DIRECTORY_PATH) + continue; + + HASHMAP_FOREACH(j, items, iter) { + if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY) + continue; + + if (path_equal(j->path, i->path)) { + candidate_item = j; + break; + } + + if ((!candidate_item && path_startswith(i->path, j->path)) || + (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0))) + candidate_item = j; + } + + if (candidate_item) { + i->age = candidate_item->age; + i->age_set = true; + } + } + + if (ferror(f)) { + log_error("Failed to read from file %s: %m", fn); + if (r == 0) + r = -EIO; + } + + return r; +} + +int main(int argc, char *argv[]) { + int r, k; + Item *i; + Iterator iterator; + + r = parse_argv(argc, argv); + if (r <= 0) + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + label_init(NULL); + + items = hashmap_new(string_hash_func, string_compare_func); + globs = hashmap_new(string_hash_func, string_compare_func); + + if (!items || !globs) { + r = log_oom(); + goto finish; + } + + r = 0; + + if (optind < argc) { + int j; + + for (j = optind; j < argc; j++) { + k = read_config_file(argv[j], false); + if (k < 0 && r == 0) + r = k; + } + + } else { + _cleanup_strv_free_ char **files = NULL; + char **f; + + r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); + if (r < 0) { + log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r)); + goto finish; + } + + STRV_FOREACH(f, files) { + k = read_config_file(*f, true); + if (k < 0 && r == 0) + r = k; + } + } + + HASHMAP_FOREACH(i, globs, iterator) + process_item(i); + + HASHMAP_FOREACH(i, items, iterator) + process_item(i); + +finish: + while ((i = hashmap_steal_first(items))) + item_free(i); + + while ((i = hashmap_steal_first(globs))) + item_free(i); + + hashmap_free(items); + hashmap_free(globs); + + free(include_prefixes); + free(exclude_prefixes); + + set_free_free(unix_sockets); + + label_finish(); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c deleted file mode 100644 index 43d008f..0000000 --- a/src/tty-ask-password-agent.c +++ /dev/null @@ -1,752 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "conf-parser.h" -#include "utmp-wtmp.h" -#include "socket-util.h" -#include "ask-password-api.h" -#include "strv.h" - -static enum { - ACTION_LIST, - ACTION_QUERY, - ACTION_WATCH, - ACTION_WALL -} arg_action = ACTION_QUERY; - -static bool arg_plymouth = false; -static bool arg_console = false; - -static int ask_password_plymouth( - const char *message, - usec_t until, - const char *flag_file, - bool accept_cached, - char ***_passphrases) { - - int fd = -1, notify = -1; - union sockaddr_union sa; - char *packet = NULL; - ssize_t k; - int r, n; - struct pollfd pollfd[2]; - char buffer[LINE_MAX]; - size_t p = 0; - enum { - POLL_SOCKET, - POLL_INOTIFY - }; - - assert(_passphrases); - - if (flag_file) { - if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { - r = -errno; - goto finish; - } - - if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { - r = -errno; - goto finish; - } - } - - if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - r = -errno; - goto finish; - } - - zero(sa); - sa.sa.sa_family = AF_UNIX; - strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1); - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { - log_error("Failed to connect to Plymouth: %m"); - r = -errno; - goto finish; - } - - if (accept_cached) { - packet = strdup("c"); - n = 1; - } else - asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n); - - if (!packet) { - r = -ENOMEM; - goto finish; - } - - if ((k = loop_write(fd, packet, n+1, true)) != n+1) { - r = k < 0 ? (int) k : -EIO; - goto finish; - } - - zero(pollfd); - pollfd[POLL_SOCKET].fd = fd; - pollfd[POLL_SOCKET].events = POLLIN; - pollfd[POLL_INOTIFY].fd = notify; - pollfd[POLL_INOTIFY].events = POLLIN; - - for (;;) { - int sleep_for = -1, j; - - if (until > 0) { - usec_t y; - - y = now(CLOCK_MONOTONIC); - - if (y > until) { - r = -ETIME; - goto finish; - } - - sleep_for = (int) ((until - y) / USEC_PER_MSEC); - } - - if (flag_file) - if (access(flag_file, F_OK) < 0) { - r = -errno; - goto finish; - } - - if ((j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - goto finish; - } else if (j == 0) { - r = -ETIME; - goto finish; - } - - if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) - flush_fd(notify); - - if (pollfd[POLL_SOCKET].revents == 0) - continue; - - if ((k = read(fd, buffer + p, sizeof(buffer) - p)) <= 0) { - r = k < 0 ? -errno : -EIO; - goto finish; - } - - p += k; - - if (p < 1) - continue; - - if (buffer[0] == 5) { - - if (accept_cached) { - /* Hmm, first try with cached - * passwords failed, so let's retry - * with a normal password request */ - free(packet); - packet = NULL; - - if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) { - r = -ENOMEM; - goto finish; - } - - if ((k = loop_write(fd, packet, n+1, true)) != n+1) { - r = k < 0 ? (int) k : -EIO; - goto finish; - } - - accept_cached = false; - p = 0; - continue; - } - - /* No password, because UI not shown */ - r = -ENOENT; - goto finish; - - } else if (buffer[0] == 2 || buffer[0] == 9) { - uint32_t size; - char **l; - - /* One ore more answers */ - if (p < 5) - continue; - - memcpy(&size, buffer+1, sizeof(size)); - if (size+5 > sizeof(buffer)) { - r = -EIO; - goto finish; - } - - if (p-5 < size) - continue; - - if (!(l = strv_parse_nulstr(buffer + 5, size))) { - r = -ENOMEM; - goto finish; - } - - *_passphrases = l; - break; - - } else { - /* Unknown packet */ - r = -EIO; - goto finish; - } - } - - r = 0; - -finish: - if (notify >= 0) - close_nointr_nofail(notify); - - if (fd >= 0) - close_nointr_nofail(fd); - - free(packet); - - return r; -} - -static int parse_password(const char *filename, char **wall) { - char *socket_name = NULL, *message = NULL, *packet = NULL; - uint64_t not_after = 0; - unsigned pid = 0; - int socket_fd = -1; - bool accept_cached = false; - - const ConfigTableItem items[] = { - { "Ask", "Socket", config_parse_string, 0, &socket_name }, - { "Ask", "NotAfter", config_parse_uint64, 0, ¬_after }, - { "Ask", "Message", config_parse_string, 0, &message }, - { "Ask", "PID", config_parse_unsigned, 0, &pid }, - { "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached }, - { NULL, NULL, NULL, 0, NULL } - }; - - FILE *f; - int r; - - assert(filename); - - f = fopen(filename, "re"); - if (!f) { - if (errno == ENOENT) - return 0; - - log_error("open(%s): %m", filename); - return -errno; - } - - r = config_parse(filename, f, NULL, config_item_table_lookup, (void*) items, true, NULL); - if (r < 0) { - log_error("Failed to parse password file %s: %s", filename, strerror(-r)); - goto finish; - } - - if (!socket_name) { - log_error("Invalid password file %s", filename); - r = -EBADMSG; - goto finish; - } - - if (not_after > 0) { - if (now(CLOCK_MONOTONIC) > not_after) { - r = 0; - goto finish; - } - } - - if (pid > 0 && - kill(pid, 0) < 0 && - errno == ESRCH) { - r = 0; - goto finish; - } - - if (arg_action == ACTION_LIST) - printf("'%s' (PID %u)\n", message, pid); - else if (arg_action == ACTION_WALL) { - char *_wall; - - if (asprintf(&_wall, - "%s%sPassword entry required for \'%s\' (PID %u).\r\n" - "Please enter password with the systemd-tty-ask-password-agent tool!", - *wall ? *wall : "", - *wall ? "\r\n\r\n" : "", - message, - pid) < 0) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - free(*wall); - *wall = _wall; - } else { - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - size_t packet_length = 0; - - assert(arg_action == ACTION_QUERY || - arg_action == ACTION_WATCH); - - if (access(socket_name, W_OK) < 0) { - - if (arg_action == ACTION_QUERY) - log_info("Not querying '%s' (PID %u), lacking privileges.", message, pid); - - r = 0; - goto finish; - } - - if (arg_plymouth) { - char **passwords = NULL; - - if ((r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords)) >= 0) { - char **p; - - packet_length = 1; - STRV_FOREACH(p, passwords) - packet_length += strlen(*p) + 1; - - if (!(packet = new(char, packet_length))) - r = -ENOMEM; - else { - char *d; - - packet[0] = '+'; - d = packet+1; - - STRV_FOREACH(p, passwords) - d = stpcpy(d, *p) + 1; - } - } - - } else { - int tty_fd = -1; - char *password; - - if (arg_console) - if ((tty_fd = acquire_terminal("/dev/console", false, false, false)) < 0) { - r = tty_fd; - goto finish; - } - - r = ask_password_tty(message, not_after, filename, &password); - - if (arg_console) { - close_nointr_nofail(tty_fd); - release_terminal(); - } - - if (r >= 0) { - packet_length = 1+strlen(password)+1; - if (!(packet = new(char, packet_length))) - r = -ENOMEM; - else { - packet[0] = '+'; - strcpy(packet+1, password); - } - - free(password); - } - } - - if (r == -ETIME || r == -ENOENT) { - /* If the query went away, that's OK */ - r = 0; - goto finish; - } - - if (r < 0) { - log_error("Failed to query password: %s", strerror(-r)); - goto finish; - } - - if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { - log_error("socket(): %m"); - r = -errno; - goto finish; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - - if (sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { - log_error("Failed to send: %m"); - r = -errno; - goto finish; - } - } - -finish: - fclose(f); - - if (socket_fd >= 0) - close_nointr_nofail(socket_fd); - - free(packet); - free(socket_name); - free(message); - - return r; -} - -static int wall_tty_block(void) { - char *p; - int fd, r; - dev_t devnr; - - r = get_ctty_devnr(0, &devnr); - if (r < 0) - return -r; - - if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0) - return -ENOMEM; - - mkdir_parents(p, 0700); - mkfifo(p, 0600); - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - free(p); - - if (fd < 0) - return -errno; - - return fd; -} - -static bool wall_tty_match(const char *path) { - int fd, k; - char *p; - struct stat st; - - if (path_is_absolute(path)) - k = lstat(path, &st); - else { - if (asprintf(&p, "/dev/%s", path) < 0) - return true; - - k = lstat(p, &st); - free(p); - } - - if (k < 0) - return true; - - if (!S_ISCHR(st.st_mode)) - return true; - - /* We use named pipes to ensure that wall messages suggesting - * password entry are not printed over password prompts - * already shown. We use the fact here that opening a pipe in - * non-blocking mode for write-only will succeed only if - * there's some writer behind it. Using pipes has the - * advantage that the block will automatically go away if the - * process dies. */ - - if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) - return true; - - fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - free(p); - - if (fd < 0) - return true; - - /* What, we managed to open the pipe? Then this tty is filtered. */ - close_nointr_nofail(fd); - return false; -} - -static int show_passwords(void) { - DIR *d; - struct dirent *de; - int r = 0; - - if (!(d = opendir("/run/systemd/ask-password"))) { - if (errno == ENOENT) - return 0; - - log_error("opendir(): %m"); - return -errno; - } - - while ((de = readdir(d))) { - char *p; - int q; - char *wall; - - /* We only support /dev on tmpfs, hence we can rely on - * d_type to be reliable */ - - if (de->d_type != DT_REG) - continue; - - if (ignore_file(de->d_name)) - continue; - - if (!startswith(de->d_name, "ask.")) - continue; - - if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - wall = NULL; - if ((q = parse_password(p, &wall)) < 0) - r = q; - - free(p); - - if (wall) { - utmp_wall(wall, wall_tty_match); - free(wall); - } - } - -finish: - if (d) - closedir(d); - - return r; -} - -static int watch_passwords(void) { - enum { - FD_INOTIFY, - FD_SIGNAL, - _FD_MAX - }; - - int notify = -1, signal_fd = -1, tty_block_fd = -1; - struct pollfd pollfd[_FD_MAX]; - sigset_t mask; - int r; - - tty_block_fd = wall_tty_block(); - - mkdir_p("/run/systemd/ask-password", 0755); - - if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { - r = -errno; - goto finish; - } - - if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) { - r = -errno; - goto finish; - } - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - zero(pollfd); - pollfd[FD_INOTIFY].fd = notify; - pollfd[FD_INOTIFY].events = POLLIN; - pollfd[FD_SIGNAL].fd = signal_fd; - pollfd[FD_SIGNAL].events = POLLIN; - - for (;;) { - if ((r = show_passwords()) < 0) - log_error("Failed to show password: %s", strerror(-r)); - - if (poll(pollfd, _FD_MAX, -1) < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - goto finish; - } - - if (pollfd[FD_INOTIFY].revents != 0) - flush_fd(notify); - - if (pollfd[FD_SIGNAL].revents != 0) - break; - } - - r = 0; - -finish: - if (notify >= 0) - close_nointr_nofail(notify); - - if (signal_fd >= 0) - close_nointr_nofail(signal_fd); - - if (tty_block_fd >= 0) - close_nointr_nofail(tty_block_fd); - - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "Process system password requests.\n\n" - " -h --help Show this help\n" - " --list Show pending password requests\n" - " --query Process pending password requests\n" - " --watch Continuously process password requests\n" - " --wall Continuously forward password requests to wall\n" - " --plymouth Ask question with Plymouth instead of on TTY\n" - " --console Ask question on /dev/console instead of current TTY\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_LIST = 0x100, - ARG_QUERY, - ARG_WATCH, - ARG_WALL, - ARG_PLYMOUTH, - ARG_CONSOLE - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "list", no_argument, NULL, ARG_LIST }, - { "query", no_argument, NULL, ARG_QUERY }, - { "watch", no_argument, NULL, ARG_WATCH }, - { "wall", no_argument, NULL, ARG_WALL }, - { "plymouth", no_argument, NULL, ARG_PLYMOUTH }, - { "console", no_argument, NULL, ARG_CONSOLE }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_LIST: - arg_action = ACTION_LIST; - break; - - case ARG_QUERY: - arg_action = ACTION_QUERY; - break; - - case ARG_WATCH: - arg_action = ACTION_WATCH; - break; - - case ARG_WALL: - arg_action = ACTION_WALL; - break; - - case ARG_PLYMOUTH: - arg_plymouth = true; - break; - - case ARG_CONSOLE: - arg_console = true; - break; - - case '?': - return -EINVAL; - - default: - log_error("Unknown option code %c", c); - return -EINVAL; - } - } - - if (optind != argc) { - help(); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r; - - log_parse_environment(); - log_open(); - - umask(0022); - - if ((r = parse_argv(argc, argv)) <= 0) - goto finish; - - if (arg_console) { - setsid(); - release_terminal(); - } - - if (arg_action == ACTION_WATCH || - arg_action == ACTION_WALL) - r = watch_passwords(); - else - r = show_passwords(); - - if (r < 0) - log_error("Error: %s", strerror(-r)); - -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/tty-ask-password-agent/Makefile b/src/tty-ask-password-agent/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/tty-ask-password-agent/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c new file mode 100644 index 0000000..7a90e65 --- /dev/null +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -0,0 +1,755 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "mkdir.h" +#include "path-util.h" +#include "conf-parser.h" +#include "utmp-wtmp.h" +#include "socket-util.h" +#include "ask-password-api.h" +#include "strv.h" +#include "build.h" + +static enum { + ACTION_LIST, + ACTION_QUERY, + ACTION_WATCH, + ACTION_WALL +} arg_action = ACTION_QUERY; + +static bool arg_plymouth = false; +static bool arg_console = false; + +static int ask_password_plymouth( + const char *message, + usec_t until, + const char *flag_file, + bool accept_cached, + char ***_passphrases) { + + int fd = -1, notify = -1; + union sockaddr_union sa = {}; + char *packet = NULL; + ssize_t k; + int r, n; + struct pollfd pollfd[2] = {}; + char buffer[LINE_MAX]; + size_t p = 0; + enum { + POLL_SOCKET, + POLL_INOTIFY + }; + + assert(_passphrases); + + if (flag_file) { + if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { + r = -errno; + goto finish; + } + } + + if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + r = -errno; + goto finish; + } + + sa.sa.sa_family = AF_UNIX; + strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1); + if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + log_error("Failed to connect to Plymouth: %m"); + r = -errno; + goto finish; + } + + if (accept_cached) { + packet = strdup("c"); + n = 1; + } else + asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n); + + if (!packet) { + r = -ENOMEM; + goto finish; + } + + if ((k = loop_write(fd, packet, n+1, true)) != n+1) { + r = k < 0 ? (int) k : -EIO; + goto finish; + } + + pollfd[POLL_SOCKET].fd = fd; + pollfd[POLL_SOCKET].events = POLLIN; + pollfd[POLL_INOTIFY].fd = notify; + pollfd[POLL_INOTIFY].events = POLLIN; + + for (;;) { + int sleep_for = -1, j; + + if (until > 0) { + usec_t y; + + y = now(CLOCK_MONOTONIC); + + if (y > until) { + r = -ETIME; + goto finish; + } + + sleep_for = (int) ((until - y) / USEC_PER_MSEC); + } + + if (flag_file) + if (access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } + + if ((j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } else if (j == 0) { + r = -ETIME; + goto finish; + } + + if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[POLL_SOCKET].revents == 0) + continue; + + if ((k = read(fd, buffer + p, sizeof(buffer) - p)) <= 0) { + r = k < 0 ? -errno : -EIO; + goto finish; + } + + p += k; + + if (p < 1) + continue; + + if (buffer[0] == 5) { + + if (accept_cached) { + /* Hmm, first try with cached + * passwords failed, so let's retry + * with a normal password request */ + free(packet); + packet = NULL; + + if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) { + r = -ENOMEM; + goto finish; + } + + if ((k = loop_write(fd, packet, n+1, true)) != n+1) { + r = k < 0 ? (int) k : -EIO; + goto finish; + } + + accept_cached = false; + p = 0; + continue; + } + + /* No password, because UI not shown */ + r = -ENOENT; + goto finish; + + } else if (buffer[0] == 2 || buffer[0] == 9) { + uint32_t size; + char **l; + + /* One ore more answers */ + if (p < 5) + continue; + + memcpy(&size, buffer+1, sizeof(size)); + size = le32toh(size); + if (size+5 > sizeof(buffer)) { + r = -EIO; + goto finish; + } + + if (p-5 < size) + continue; + + if (!(l = strv_parse_nulstr(buffer + 5, size))) { + r = -ENOMEM; + goto finish; + } + + *_passphrases = l; + break; + + } else { + /* Unknown packet */ + r = -EIO; + goto finish; + } + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (fd >= 0) + close_nointr_nofail(fd); + + free(packet); + + return r; +} + +static int parse_password(const char *filename, char **wall) { + char *socket_name = NULL, *message = NULL, *packet = NULL; + uint64_t not_after = 0; + unsigned pid = 0; + int socket_fd = -1; + bool accept_cached = false; + + const ConfigTableItem items[] = { + { "Ask", "Socket", config_parse_string, 0, &socket_name }, + { "Ask", "NotAfter", config_parse_uint64, 0, ¬_after }, + { "Ask", "Message", config_parse_string, 0, &message }, + { "Ask", "PID", config_parse_unsigned, 0, &pid }, + { "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached }, + { NULL, NULL, NULL, 0, NULL } + }; + + FILE *f; + int r; + + assert(filename); + + f = fopen(filename, "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + log_error("open(%s): %m", filename); + return -errno; + } + + r = config_parse(NULL, filename, f, NULL, config_item_table_lookup, (void*) items, true, false, NULL); + if (r < 0) { + log_error("Failed to parse password file %s: %s", filename, strerror(-r)); + goto finish; + } + + if (!socket_name) { + log_error("Invalid password file %s", filename); + r = -EBADMSG; + goto finish; + } + + if (not_after > 0) { + if (now(CLOCK_MONOTONIC) > not_after) { + r = 0; + goto finish; + } + } + + if (pid > 0 && !pid_is_alive(pid)) { + r = 0; + goto finish; + } + + if (arg_action == ACTION_LIST) + printf("'%s' (PID %u)\n", message, pid); + else if (arg_action == ACTION_WALL) { + char *_wall; + + if (asprintf(&_wall, + "%s%sPassword entry required for \'%s\' (PID %u).\r\n" + "Please enter password with the systemd-tty-ask-password-agent tool!", + *wall ? *wall : "", + *wall ? "\r\n\r\n" : "", + message, + pid) < 0) { + r = log_oom(); + goto finish; + } + + free(*wall); + *wall = _wall; + } else { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa = {}; + size_t packet_length = 0; + + assert(arg_action == ACTION_QUERY || + arg_action == ACTION_WATCH); + + if (access(socket_name, W_OK) < 0) { + + if (arg_action == ACTION_QUERY) + log_info("Not querying '%s' (PID %u), lacking privileges.", message, pid); + + r = 0; + goto finish; + } + + if (arg_plymouth) { + _cleanup_strv_free_ char **passwords = NULL; + + if ((r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords)) >= 0) { + char **p; + + packet_length = 1; + STRV_FOREACH(p, passwords) + packet_length += strlen(*p) + 1; + + if (!(packet = new(char, packet_length))) + r = -ENOMEM; + else { + char *d; + + packet[0] = '+'; + d = packet+1; + + STRV_FOREACH(p, passwords) + d = stpcpy(d, *p) + 1; + } + } + + } else { + int tty_fd = -1; + char *password = NULL; + + if (arg_console) + if ((tty_fd = acquire_terminal("/dev/console", false, false, false, (usec_t) -1)) < 0) { + r = tty_fd; + goto finish; + } + + r = ask_password_tty(message, not_after, filename, &password); + + if (arg_console) { + close_nointr_nofail(tty_fd); + release_terminal(); + } + + if (r >= 0) { + packet_length = 1+strlen(password)+1; + if (!(packet = new(char, packet_length))) + r = -ENOMEM; + else { + packet[0] = '+'; + strcpy(packet+1, password); + } + + free(password); + } + } + + if (r == -ETIME || r == -ENOENT) { + /* If the query went away, that's OK */ + r = 0; + goto finish; + } + + if (r < 0) { + log_error("Failed to query password: %s", strerror(-r)); + goto finish; + } + + if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + log_error("socket(): %m"); + r = -errno; + goto finish; + } + + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); + + if (sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { + log_error("Failed to send: %m"); + r = -errno; + goto finish; + } + } + +finish: + fclose(f); + + if (socket_fd >= 0) + close_nointr_nofail(socket_fd); + + free(packet); + free(socket_name); + free(message); + + return r; +} + +static int wall_tty_block(void) { + char *p; + int fd, r; + dev_t devnr; + + r = get_ctty_devnr(0, &devnr); + if (r < 0) + return -r; + + if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0) + return -ENOMEM; + + mkdir_parents_label(p, 0700); + mkfifo(p, 0600); + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + free(p); + + if (fd < 0) + return -errno; + + return fd; +} + +static bool wall_tty_match(const char *path) { + int fd, k; + char *p; + struct stat st; + + if (path_is_absolute(path)) + k = lstat(path, &st); + else { + if (asprintf(&p, "/dev/%s", path) < 0) + return true; + + k = lstat(p, &st); + free(p); + } + + if (k < 0) + return true; + + if (!S_ISCHR(st.st_mode)) + return true; + + /* We use named pipes to ensure that wall messages suggesting + * password entry are not printed over password prompts + * already shown. We use the fact here that opening a pipe in + * non-blocking mode for write-only will succeed only if + * there's some writer behind it. Using pipes has the + * advantage that the block will automatically go away if the + * process dies. */ + + if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) + return true; + + fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + free(p); + + if (fd < 0) + return true; + + /* What, we managed to open the pipe? Then this tty is filtered. */ + close_nointr_nofail(fd); + return false; +} + +static int show_passwords(void) { + DIR *d; + struct dirent *de; + int r = 0; + + if (!(d = opendir("/run/systemd/ask-password"))) { + if (errno == ENOENT) + return 0; + + log_error("opendir(): %m"); + return -errno; + } + + while ((de = readdir(d))) { + char *p; + int q; + char *wall; + + /* We only support /dev on tmpfs, hence we can rely on + * d_type to be reliable */ + + if (de->d_type != DT_REG) + continue; + + if (ignore_file(de->d_name)) + continue; + + if (!startswith(de->d_name, "ask.")) + continue; + + if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) { + r = log_oom(); + goto finish; + } + + wall = NULL; + if ((q = parse_password(p, &wall)) < 0) + r = q; + + free(p); + + if (wall) { + utmp_wall(wall, wall_tty_match); + free(wall); + } + } + +finish: + if (d) + closedir(d); + + return r; +} + +static int watch_passwords(void) { + enum { + FD_INOTIFY, + FD_SIGNAL, + _FD_MAX + }; + + int notify = -1, signal_fd = -1, tty_block_fd = -1; + struct pollfd pollfd[_FD_MAX] = {}; + sigset_t mask; + int r; + + tty_block_fd = wall_tty_block(); + + mkdir_p_label("/run/systemd/ask-password", 0755); + + if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) { + r = -errno; + goto finish; + } + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { + log_error("signalfd(): %m"); + r = -errno; + goto finish; + } + + pollfd[FD_INOTIFY].fd = notify; + pollfd[FD_INOTIFY].events = POLLIN; + pollfd[FD_SIGNAL].fd = signal_fd; + pollfd[FD_SIGNAL].events = POLLIN; + + for (;;) { + if ((r = show_passwords()) < 0) + log_error("Failed to show password: %s", strerror(-r)); + + if (poll(pollfd, _FD_MAX, -1) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } + + if (pollfd[FD_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[FD_SIGNAL].revents != 0) + break; + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (signal_fd >= 0) + close_nointr_nofail(signal_fd); + + if (tty_block_fd >= 0) + close_nointr_nofail(tty_block_fd); + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Process system password requests.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --list Show pending password requests\n" + " --query Process pending password requests\n" + " --watch Continuously process password requests\n" + " --wall Continuously forward password requests to wall\n" + " --plymouth Ask question with Plymouth instead of on TTY\n" + " --console Ask question on /dev/console instead of current TTY\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_LIST = 0x100, + ARG_QUERY, + ARG_WATCH, + ARG_WALL, + ARG_PLYMOUTH, + ARG_CONSOLE, + ARG_VERSION + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "list", no_argument, NULL, ARG_LIST }, + { "query", no_argument, NULL, ARG_QUERY }, + { "watch", no_argument, NULL, ARG_WATCH }, + { "wall", no_argument, NULL, ARG_WALL }, + { "plymouth", no_argument, NULL, ARG_PLYMOUTH }, + { "console", no_argument, NULL, ARG_CONSOLE }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(SYSTEMD_FEATURES); + return 0; + + case ARG_LIST: + arg_action = ACTION_LIST; + break; + + case ARG_QUERY: + arg_action = ACTION_QUERY; + break; + + case ARG_WATCH: + arg_action = ACTION_WATCH; + break; + + case ARG_WALL: + arg_action = ACTION_WALL; + break; + + case ARG_PLYMOUTH: + arg_plymouth = true; + break; + + case ARG_CONSOLE: + arg_console = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind != argc) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if ((r = parse_argv(argc, argv)) <= 0) + goto finish; + + if (arg_console) { + setsid(); + release_terminal(); + } + + if (arg_action == ACTION_WATCH || + arg_action == ACTION_WALL) + r = watch_passwords(); + else + r = show_passwords(); + + if (r < 0) + log_error("Error: %s", strerror(-r)); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/uaccess.c b/src/uaccess.c deleted file mode 100644 index 49ac4af..0000000 --- a/src/uaccess.c +++ /dev/null @@ -1,90 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "logind-acl.h" -#include "util.h" -#include "log.h" -#include "sd-daemon.h" -#include "sd-login.h" - -int main(int argc, char *argv[]) { - int r; - const char *path = NULL, *seat; - bool changed_acl = false; - uid_t uid; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argc < 2 || argc > 3) { - log_error("This program expects one or two arguments."); - r = -EINVAL; - goto finish; - } - - /* Make sure we don't muck around with ACLs the system is not - * running systemd. */ - if (!sd_booted()) - return 0; - - path = argv[1]; - seat = argc < 3 || isempty(argv[2]) ? "seat0" : argv[2]; - - r = sd_seat_get_active(seat, NULL, &uid); - if (r == -ENOENT) { - /* No active session on this seat */ - r = 0; - goto finish; - } else if (r < 0) { - log_error("Failed to determine active user on seat %s.", seat); - goto finish; - } - - r = devnode_acl(path, true, false, 0, true, uid); - if (r < 0) { - log_error("Failed to apply ACL on %s: %s", path, strerror(-r)); - goto finish; - } - - changed_acl = true; - r = 0; - -finish: - if (path && !changed_acl) { - int k; - /* Better be safe that sorry and reset ACL */ - - k = devnode_acl(path, true, false, 0, false, 0); - if (k < 0) { - log_error("Failed to apply ACL on %s: %s", path, strerror(-k)); - if (r >= 0) - r = k; - } - } - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/udev/.gitignore b/src/udev/.gitignore new file mode 100644 index 0000000..a229430 --- /dev/null +++ b/src/udev/.gitignore @@ -0,0 +1,5 @@ +/udev.pc +/keyboard-keys-from-name.gperf +/keyboard-keys-from-name.h +/keyboard-keys-to-name.h +/keyboard-keys.txt diff --git a/src/udev/.vimrc b/src/udev/.vimrc new file mode 100644 index 0000000..366fbdc --- /dev/null +++ b/src/udev/.vimrc @@ -0,0 +1,4 @@ +" 'set exrc' in ~/.vimrc will read .vimrc from the current directory +set tabstop=8 +set shiftwidth=8 +set expandtab diff --git a/src/udev/Makefile b/src/udev/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/udev/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/udev/accelerometer/accelerometer.c b/src/udev/accelerometer/accelerometer.c new file mode 100644 index 0000000..925d38d --- /dev/null +++ b/src/udev/accelerometer/accelerometer.c @@ -0,0 +1,343 @@ +/* + * accelerometer - exports device orientation through property + * + * When an "change" event is received on an accelerometer, + * open its device node, and from the value, as well as the previous + * value of the property, calculate the device's new orientation, + * and export it as ID_INPUT_ACCELEROMETER_ORIENTATION. + * + * Possible values are: + * undefined + * * normal + * * bottom-up + * * left-up + * * right-up + * + * The property will be persistent across sessions, and the new + * orientations can be deducted from the previous one (it allows + * for a threshold for switching between opposite ends of the + * orientation). + * + * Copyright (C) 2011 Red Hat, Inc. + * Author: + * Bastien Nocera + * + * orientation_calc() from the sensorfw package + * Copyright (C) 2009-2010 Nokia Corporation + * Authors: + * Üstün Ergenoglu + * Timo Rongas + * Lihan Guo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +/* we must use this kernel-compatible implementation */ +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +static int debug = 0; + +_printf_(6,0) +static void log_fn(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + if (debug) { + fprintf(stderr, "%s: ", fn); + vfprintf(stderr, format, args); + } else { + vsyslog(priority, format, args); + } +} + +typedef enum { + ORIENTATION_UNDEFINED, + ORIENTATION_NORMAL, + ORIENTATION_BOTTOM_UP, + ORIENTATION_LEFT_UP, + ORIENTATION_RIGHT_UP +} OrientationUp; + +static const char *orientations[] = { + "undefined", + "normal", + "bottom-up", + "left-up", + "right-up", + NULL +}; + +#define ORIENTATION_UP_UP ORIENTATION_NORMAL + +#define DEFAULT_THRESHOLD 250 +#define RADIANS_TO_DEGREES 180.0/M_PI +#define SAME_AXIS_LIMIT 5 + +#define THRESHOLD_LANDSCAPE 25 +#define THRESHOLD_PORTRAIT 20 + +static const char * +orientation_to_string (OrientationUp o) +{ + return orientations[o]; +} + +static OrientationUp +string_to_orientation (const char *orientation) +{ + int i; + + if (orientation == NULL) + return ORIENTATION_UNDEFINED; + for (i = 0; orientations[i] != NULL; i++) { + if (streq (orientation, orientations[i])) + return i; + } + return ORIENTATION_UNDEFINED; +} + +static OrientationUp +orientation_calc (OrientationUp prev, + int x, int y, int z) +{ + int rotation; + OrientationUp ret = prev; + + /* Portrait check */ + rotation = round(atan((double) x / sqrt(y * y + z * z)) * RADIANS_TO_DEGREES); + + if (abs(rotation) > THRESHOLD_PORTRAIT) { + ret = (rotation < 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP; + + /* Some threshold to switching between portrait modes */ + if (prev == ORIENTATION_LEFT_UP || prev == ORIENTATION_RIGHT_UP) { + if (abs(rotation) < SAME_AXIS_LIMIT) { + ret = prev; + } + } + + } else { + /* Landscape check */ + rotation = round(atan((double) y / sqrt(x * x + z * z)) * RADIANS_TO_DEGREES); + + if (abs(rotation) > THRESHOLD_LANDSCAPE) { + ret = (rotation < 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL; + + /* Some threshold to switching between landscape modes */ + if (prev == ORIENTATION_BOTTOM_UP || prev == ORIENTATION_NORMAL) { + if (abs(rotation) < SAME_AXIS_LIMIT) { + ret = prev; + } + } + } + } + + return ret; +} + +static OrientationUp +get_prev_orientation(struct udev_device *dev) +{ + const char *value; + + value = udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER_ORIENTATION"); + if (value == NULL) + return ORIENTATION_UNDEFINED; + return string_to_orientation(value); +} + +#define SET_AXIS(axis, code_) if (ev[i].code == code_) { if (got_##axis == 0) { axis = ev[i].value; got_##axis = true; } } + +/* accelerometers */ +static void test_orientation(struct udev *udev, + struct udev_device *dev, + const char *devpath) +{ + OrientationUp old, new; + _cleanup_close_ int fd = -1; + struct input_event ev[64]; + bool got_syn = false; + bool got_x = false, got_y = false, got_z = false; + int x = 0, y = 0, z = 0; + char text[64]; + + old = get_prev_orientation(dev); + + fd = open(devpath, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return; + + while (1) { + int i, r; + + r = read(fd, ev, sizeof(struct input_event) * 64); + + if (r < (int) sizeof(struct input_event)) + return; + + for (i = 0; i < r / (int) sizeof(struct input_event); i++) { + if (got_syn) { + if (ev[i].type == EV_ABS) { + SET_AXIS(x, ABS_X); + SET_AXIS(y, ABS_Y); + SET_AXIS(z, ABS_Z); + } + } + if (ev[i].type == EV_SYN && ev[i].code == SYN_REPORT) + got_syn = true; + if (got_x && got_y && got_z) + goto read_dev; + } + } + +read_dev: + new = orientation_calc(old, x, y, z); + snprintf(text, sizeof(text), + "ID_INPUT_ACCELEROMETER_ORIENTATION=%s", orientation_to_string(new)); + puts(text); +} + +static void help(void) +{ + printf("Usage: accelerometer [options] \n" + " --debug debug to stderr\n" + " --help print this help text\n\n"); +} + +int main (int argc, char** argv) +{ + struct udev *udev; + struct udev_device *dev; + + static const struct option options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + char devpath[PATH_MAX]; + char *devnode; + struct udev_enumerate *enumerate; + struct udev_list_entry *list_entry; + + udev = udev_new(); + if (udev == NULL) + return 1; + + log_open(); + udev_set_log_fn(udev, log_fn); + + /* CLI argument parsing */ + while (1) { + int option; + + option = getopt_long(argc, argv, "dxh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'd': + debug = 1; + log_set_max_level(LOG_DEBUG); + udev_set_log_priority(udev, LOG_DEBUG); + break; + case 'h': + help(); + exit(0); + default: + exit(1); + } + } + + if (argv[optind] == NULL) { + help(); + exit(1); + } + + /* get the device */ + snprintf(devpath, sizeof(devpath), "/sys/%s", argv[optind]); + dev = udev_device_new_from_syspath(udev, devpath); + if (dev == NULL) { + fprintf(stderr, "unable to access '%s'\n", devpath); + return 1; + } + + /* Get the children devices and find the devnode */ + devnode = NULL; + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_parent(enumerate, dev); + udev_enumerate_scan_devices(enumerate); + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { + struct udev_device *device; + const char *node; + + device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), + udev_list_entry_get_name(list_entry)); + if (device == NULL) + continue; + /* Already found it */ + if (devnode != NULL) { + udev_device_unref(device); + continue; + } + + node = udev_device_get_devnode(device); + if (node == NULL) { + udev_device_unref(device); + continue; + } + /* Use the event sub-device */ + if (strstr(node, "/event") == NULL) { + udev_device_unref(device); + continue; + } + + devnode = strdup(node); + udev_device_unref(device); + } + + if (devnode == NULL) { + fprintf(stderr, "unable to get device node for '%s'\n", devpath); + return 0; + } + + log_debug("opening accelerometer device %s", devnode); + test_orientation(udev, dev, devnode); + free(devnode); + log_close(); + return 0; +} diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c new file mode 100644 index 0000000..f84281d --- /dev/null +++ b/src/udev/ata_id/ata_id.c @@ -0,0 +1,691 @@ +/* + * ata_id - reads product/serial number from ATA drives + * + * Copyright (C) 2005-2008 Kay Sievers + * Copyright (C) 2009 Lennart Poettering + * Copyright (C) 2009-2010 David Zeuthen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "log.h" + +#define COMMAND_TIMEOUT_MSEC (30 * 1000) + +static int disk_scsi_inquiry_command(int fd, + void *buf, + size_t buf_len) +{ + uint8_t cdb[6] = { + /* + * INQUIRY, see SPC-4 section 6.4 + */ + [0] = 0x12, /* OPERATION CODE: INQUIRY */ + [3] = (buf_len >> 8), /* ALLOCATION LENGTH */ + [4] = (buf_len & 0xff), + }; + uint8_t sense[32] = {}; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof(cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof(sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + int ret; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof(sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) + return ret; + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_hdr.status == 0 && + io_hdr.host_status == 0 && + io_hdr.driver_status == 0)) { + errno = EIO; + return -1; + } + } else + return ret; + } + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_v4.device_status == 0 && + io_v4.transport_status == 0 && + io_v4.driver_status == 0)) { + errno = EIO; + return -1; + } + + return 0; +} + +static int disk_identify_command(int fd, + void *buf, + size_t buf_len) +{ + uint8_t cdb[12] = { + /* + * ATA Pass-Through 12 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + [0] = 0xa1, /* OPERATION CODE: 12 byte pass through */ + [1] = 4 << 1, /* PROTOCOL: PIO Data-in */ + [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + [3] = 0, /* FEATURES */ + [4] = 1, /* SECTORS */ + [5] = 0, /* LBA LOW */ + [6] = 0, /* LBA MID */ + [7] = 0, /* LBA HIGH */ + [8] = 0 & 0x4F, /* SELECT */ + [9] = 0xEC, /* Command: ATA IDENTIFY DEVICE */ + }; + uint8_t sense[32] = {}; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof(cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof(sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + int ret; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof (sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) + return ret; + } else + return ret; + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { + errno = EIO; + return -1; + } + + return 0; +} + +static int disk_identify_packet_device_command(int fd, + void *buf, + size_t buf_len) +{ + uint8_t cdb[16] = { + /* + * ATA Pass-Through 16 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + [0] = 0x85, /* OPERATION CODE: 16 byte pass through */ + [1] = 4 << 1, /* PROTOCOL: PIO Data-in */ + [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + [3] = 0, /* FEATURES */ + [4] = 0, /* FEATURES */ + [5] = 0, /* SECTORS */ + [6] = 1, /* SECTORS */ + [7] = 0, /* LBA LOW */ + [8] = 0, /* LBA LOW */ + [9] = 0, /* LBA MID */ + [10] = 0, /* LBA MID */ + [11] = 0, /* LBA HIGH */ + [12] = 0, /* LBA HIGH */ + [13] = 0, /* DEVICE */ + [14] = 0xA1, /* Command: ATA IDENTIFY PACKET DEVICE */ + [15] = 0, /* CONTROL */ + }; + uint8_t sense[32] = {}; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4 = { + .guard = 'Q', + .protocol = BSG_PROTOCOL_SCSI, + .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD, + .request_len = sizeof (cdb), + .request = (uintptr_t) cdb, + .max_response_len = sizeof (sense), + .response = (uintptr_t) sense, + .din_xfer_len = buf_len, + .din_xferp = (uintptr_t) buf, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + int ret; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + struct sg_io_hdr io_hdr = { + .interface_id = 'S', + .cmdp = (unsigned char*) cdb, + .cmd_len = sizeof (cdb), + .dxferp = buf, + .dxfer_len = buf_len, + .sbp = sense, + .mx_sb_len = sizeof (sense), + .dxfer_direction = SG_DXFER_FROM_DEV, + .timeout = COMMAND_TIMEOUT_MSEC, + }; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) + return ret; + } else + return ret; + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { + errno = EIO; + return -1; + } + + return 0; +} + +/** + * disk_identify_get_string: + * @identify: A block of IDENTIFY data + * @offset_words: Offset of the string to get, in words. + * @dest: Destination buffer for the string. + * @dest_len: Length of destination buffer, in bytes. + * + * Copies the ATA string from @identify located at @offset_words into @dest. + */ +static void disk_identify_get_string(uint8_t identify[512], + unsigned int offset_words, + char *dest, + size_t dest_len) +{ + unsigned int c1; + unsigned int c2; + + while (dest_len > 0) { + c1 = identify[offset_words * 2 + 1]; + c2 = identify[offset_words * 2]; + *dest = c1; + dest++; + *dest = c2; + dest++; + offset_words++; + dest_len -= 2; + } +} + +static void disk_identify_fixup_string(uint8_t identify[512], + unsigned int offset_words, + size_t len) +{ + disk_identify_get_string(identify, offset_words, + (char *) identify + offset_words * 2, len); +} + +static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offset_words) +{ + uint16_t *p; + + p = (uint16_t *) identify; + p[offset_words] = le16toh (p[offset_words]); +} + +/** + * disk_identify: + * @udev: The libudev context. + * @fd: File descriptor for the block device. + * @out_identify: Return location for IDENTIFY data. + * @out_is_packet_device: Return location for whether returned data is from a IDENTIFY PACKET DEVICE. + * + * Sends the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command to the + * device represented by @fd. If successful, then the result will be + * copied into @out_identify and @out_is_packet_device. + * + * This routine is based on code from libatasmart, Copyright 2008 + * Lennart Poettering, LGPL v2.1. + * + * Returns: 0 if the data was successfully obtained, otherwise + * non-zero with errno set. + */ +static int disk_identify(struct udev *udev, + int fd, + uint8_t out_identify[512], + int *out_is_packet_device) +{ + int ret; + uint8_t inquiry_buf[36]; + int peripheral_device_type; + int all_nul_bytes; + int n; + int is_packet_device = 0; + + /* init results */ + memzero(out_identify, 512); + + /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device + * we could accidentally blank media. This is because MMC's BLANK + * command has the same op-code (0x61). + * + * To prevent this from happening we bail out if the device + * isn't a Direct Access Block Device, e.g. SCSI type 0x00 + * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY + * command first... libata is handling this via its SCSI + * emulation layer. + * + * This also ensures that we're actually dealing with a device + * that understands SCSI commands. + * + * (Yes, it is a bit perverse that we're tunneling the ATA + * command through SCSI and relying on the ATA driver + * emulating SCSI well-enough...) + * + * (See commit 160b069c25690bfb0c785994c7c3710289179107 for + * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 + * for the original bug-report.) + */ + ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf)); + if (ret != 0) + goto out; + + /* SPC-4, section 6.4.2: Standard INQUIRY data */ + peripheral_device_type = inquiry_buf[0] & 0x1f; + if (peripheral_device_type == 0x05) + { + is_packet_device = 1; + ret = disk_identify_packet_device_command(fd, out_identify, 512); + goto check_nul_bytes; + } + if (peripheral_device_type != 0x00) { + ret = -1; + errno = EIO; + goto out; + } + + /* OK, now issue the IDENTIFY DEVICE command */ + ret = disk_identify_command(fd, out_identify, 512); + if (ret != 0) + goto out; + + check_nul_bytes: + /* Check if IDENTIFY data is all NUL bytes - if so, bail */ + all_nul_bytes = 1; + for (n = 0; n < 512; n++) { + if (out_identify[n] != '\0') { + all_nul_bytes = 0; + break; + } + } + + if (all_nul_bytes) { + ret = -1; + errno = EIO; + goto out; + } + +out: + if (out_is_packet_device != NULL) + *out_is_packet_device = is_packet_device; + return ret; +} + +_printf_(6,0) +static void log_fn(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + vsyslog(priority, format, args); +} + +int main(int argc, char *argv[]) +{ + struct udev *udev; + struct hd_driveid id; + uint8_t identify[512]; + uint16_t *identify_words; + char model[41]; + char model_enc[256]; + char serial[21]; + char revision[9]; + const char *node = NULL; + int export = 0; + int fd; + uint16_t word; + int rc = 0; + int is_packet_device = 0; + static const struct option options[] = { + { "export", no_argument, NULL, 'x' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + udev = udev_new(); + if (udev == NULL) + goto exit; + + log_open(); + udev_set_log_fn(udev, log_fn); + + while (1) { + int option; + + option = getopt_long(argc, argv, "xh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'x': + export = 1; + break; + case 'h': + printf("Usage: ata_id [--export] [--help] \n" + " --export print values as environment keys\n" + " --help print this help text\n\n"); + goto exit; + } + } + + node = argv[optind]; + if (node == NULL) { + log_error("no node specified"); + rc = 1; + goto exit; + } + + fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC); + if (fd < 0) { + log_error("unable to open '%s'", node); + rc = 1; + goto exit; + } + + if (disk_identify(udev, fd, identify, &is_packet_device) == 0) { + /* + * fix up only the fields from the IDENTIFY data that we are going to + * use and copy it into the hd_driveid struct for convenience + */ + disk_identify_fixup_string(identify, 10, 20); /* serial */ + disk_identify_fixup_string(identify, 23, 8); /* fwrev */ + disk_identify_fixup_string(identify, 27, 40); /* model */ + disk_identify_fixup_uint16(identify, 0); /* configuration */ + disk_identify_fixup_uint16(identify, 75); /* queue depth */ + disk_identify_fixup_uint16(identify, 75); /* SATA capabilities */ + disk_identify_fixup_uint16(identify, 82); /* command set supported */ + disk_identify_fixup_uint16(identify, 83); /* command set supported */ + disk_identify_fixup_uint16(identify, 84); /* command set supported */ + disk_identify_fixup_uint16(identify, 85); /* command set supported */ + disk_identify_fixup_uint16(identify, 86); /* command set supported */ + disk_identify_fixup_uint16(identify, 87); /* command set supported */ + disk_identify_fixup_uint16(identify, 89); /* time required for SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify, 90); /* time required for enhanced SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify, 91); /* current APM values */ + disk_identify_fixup_uint16(identify, 94); /* current AAM value */ + disk_identify_fixup_uint16(identify, 128); /* device lock function */ + disk_identify_fixup_uint16(identify, 217); /* nominal media rotation rate */ + memcpy(&id, identify, sizeof id); + } else { + /* If this fails, then try HDIO_GET_IDENTITY */ + if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { + log_debug("HDIO_GET_IDENTITY failed for '%s': %m", node); + rc = 2; + goto close; + } + } + identify_words = (uint16_t *) identify; + + memcpy (model, id.model, 40); + model[40] = '\0'; + udev_util_encode_string(model, model_enc, sizeof(model_enc)); + util_replace_whitespace((char *) id.model, model, 40); + util_replace_chars(model, NULL); + util_replace_whitespace((char *) id.serial_no, serial, 20); + util_replace_chars(serial, NULL); + util_replace_whitespace((char *) id.fw_rev, revision, 8); + util_replace_chars(revision, NULL); + + if (export) { + /* Set this to convey the disk speaks the ATA protocol */ + printf("ID_ATA=1\n"); + + if ((id.config >> 8) & 0x80) { + /* This is an ATAPI device */ + switch ((id.config >> 8) & 0x1f) { + case 0: + printf("ID_TYPE=cd\n"); + break; + case 1: + printf("ID_TYPE=tape\n"); + break; + case 5: + printf("ID_TYPE=cd\n"); + break; + case 7: + printf("ID_TYPE=optical\n"); + break; + default: + printf("ID_TYPE=generic\n"); + break; + } + } else { + printf("ID_TYPE=disk\n"); + } + printf("ID_BUS=ata\n"); + printf("ID_MODEL=%s\n", model); + printf("ID_MODEL_ENC=%s\n", model_enc); + printf("ID_REVISION=%s\n", revision); + if (serial[0] != '\0') { + printf("ID_SERIAL=%s_%s\n", model, serial); + printf("ID_SERIAL_SHORT=%s\n", serial); + } else { + printf("ID_SERIAL=%s\n", model); + } + + if (id.command_set_1 & (1<<5)) { + printf ("ID_ATA_WRITE_CACHE=1\n"); + printf ("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id.cfs_enable_1 & (1<<5)) ? 1 : 0); + } + if (id.command_set_1 & (1<<10)) { + printf("ID_ATA_FEATURE_SET_HPA=1\n"); + printf("ID_ATA_FEATURE_SET_HPA_ENABLED=%d\n", (id.cfs_enable_1 & (1<<10)) ? 1 : 0); + + /* + * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address + * so it is easy to check whether the protected area is in use. + */ + } + if (id.command_set_1 & (1<<3)) { + printf("ID_ATA_FEATURE_SET_PM=1\n"); + printf("ID_ATA_FEATURE_SET_PM_ENABLED=%d\n", (id.cfs_enable_1 & (1<<3)) ? 1 : 0); + } + if (id.command_set_1 & (1<<1)) { + printf("ID_ATA_FEATURE_SET_SECURITY=1\n"); + printf("ID_ATA_FEATURE_SET_SECURITY_ENABLED=%d\n", (id.cfs_enable_1 & (1<<1)) ? 1 : 0); + printf("ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=%d\n", id.trseuc * 2); + if ((id.cfs_enable_1 & (1<<1))) /* enabled */ { + if (id.dlf & (1<<8)) + printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=maximum\n"); + else + printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=high\n"); + } + if (id.dlf & (1<<5)) + printf("ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=%d\n", id.trsEuc * 2); + if (id.dlf & (1<<4)) + printf("ID_ATA_FEATURE_SET_SECURITY_EXPIRE=1\n"); + if (id.dlf & (1<<3)) + printf("ID_ATA_FEATURE_SET_SECURITY_FROZEN=1\n"); + if (id.dlf & (1<<2)) + printf("ID_ATA_FEATURE_SET_SECURITY_LOCKED=1\n"); + } + if (id.command_set_1 & (1<<0)) { + printf("ID_ATA_FEATURE_SET_SMART=1\n"); + printf("ID_ATA_FEATURE_SET_SMART_ENABLED=%d\n", (id.cfs_enable_1 & (1<<0)) ? 1 : 0); + } + if (id.command_set_2 & (1<<9)) { + printf("ID_ATA_FEATURE_SET_AAM=1\n"); + printf("ID_ATA_FEATURE_SET_AAM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<9)) ? 1 : 0); + printf("ID_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE=%d\n", id.acoustic >> 8); + printf("ID_ATA_FEATURE_SET_AAM_CURRENT_VALUE=%d\n", id.acoustic & 0xff); + } + if (id.command_set_2 & (1<<5)) { + printf("ID_ATA_FEATURE_SET_PUIS=1\n"); + printf("ID_ATA_FEATURE_SET_PUIS_ENABLED=%d\n", (id.cfs_enable_2 & (1<<5)) ? 1 : 0); + } + if (id.command_set_2 & (1<<3)) { + printf("ID_ATA_FEATURE_SET_APM=1\n"); + printf("ID_ATA_FEATURE_SET_APM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<3)) ? 1 : 0); + if ((id.cfs_enable_2 & (1<<3))) + printf("ID_ATA_FEATURE_SET_APM_CURRENT_VALUE=%d\n", id.CurAPMvalues & 0xff); + } + if (id.command_set_2 & (1<<0)) + printf("ID_ATA_DOWNLOAD_MICROCODE=1\n"); + + /* + * Word 76 indicates the capabilities of a SATA device. A PATA device shall set + * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then + * the device does not claim compliance with the Serial ATA specification and words + * 76 through 79 are not valid and shall be ignored. + */ + word = *((uint16_t *) identify + 76); + if (word != 0x0000 && word != 0xffff) { + printf("ID_ATA_SATA=1\n"); + /* + * If bit 2 of word 76 is set to one, then the device supports the Gen2 + * signaling rate of 3.0 Gb/s (see SATA 2.6). + * + * If bit 1 of word 76 is set to one, then the device supports the Gen1 + * signaling rate of 1.5 Gb/s (see SATA 2.6). + */ + if (word & (1<<2)) + printf("ID_ATA_SATA_SIGNAL_RATE_GEN2=1\n"); + if (word & (1<<1)) + printf("ID_ATA_SATA_SIGNAL_RATE_GEN1=1\n"); + } + + /* Word 217 indicates the nominal media rotation rate of the device */ + word = *((uint16_t *) identify + 217); + if (word != 0x0000) { + if (word == 0x0001) { + printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */ + } else if (word >= 0x0401 && word <= 0xfffe) { + printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word); + } + } + + /* + * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier + * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. + * All other values are reserved. + */ + word = *((uint16_t *) identify + 108); + if ((word & 0xf000) == 0x5000) { + uint64_t wwwn; + + wwwn = *((uint16_t *) identify + 108); + wwwn <<= 16; + wwwn |= *((uint16_t *) identify + 109); + wwwn <<= 16; + wwwn |= *((uint16_t *) identify + 110); + wwwn <<= 16; + wwwn |= *((uint16_t *) identify + 111); + printf("ID_WWN=0x%llx\n", (unsigned long long int) wwwn); + /* ATA devices have no vendor extension */ + printf("ID_WWN_WITH_EXTENSION=0x%llx\n", (unsigned long long int) wwwn); + } + + /* from Linux's include/linux/ata.h */ + if (identify_words[0] == 0x848a || identify_words[0] == 0x844a) { + printf("ID_ATA_CFA=1\n"); + } else { + if ((identify_words[83] & 0xc004) == 0x4004) { + printf("ID_ATA_CFA=1\n"); + } + } + } else { + if (serial[0] != '\0') + printf("%s_%s\n", model, serial); + else + printf("%s\n", model); + } +close: + close(fd); +exit: + udev_unref(udev); + log_close(); + return rc; +} diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c new file mode 100644 index 0000000..93467c2 --- /dev/null +++ b/src/udev/cdrom_id/cdrom_id.c @@ -0,0 +1,1098 @@ +/* + * cdrom_id - optical drive and media information prober + * + * Copyright (C) 2008-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" + +static bool debug; + +_printf_(6,0) +static void log_fn(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + if (debug) { + fprintf(stderr, "%s: ", fn); + vfprintf(stderr, format, args); + } else { + vsyslog(priority, format, args); + } +} + +/* device info */ +static unsigned int cd_cd_rom; +static unsigned int cd_cd_r; +static unsigned int cd_cd_rw; +static unsigned int cd_dvd_rom; +static unsigned int cd_dvd_r; +static unsigned int cd_dvd_rw; +static unsigned int cd_dvd_ram; +static unsigned int cd_dvd_plus_r; +static unsigned int cd_dvd_plus_rw; +static unsigned int cd_dvd_plus_r_dl; +static unsigned int cd_dvd_plus_rw_dl; +static unsigned int cd_bd; +static unsigned int cd_bd_r; +static unsigned int cd_bd_re; +static unsigned int cd_hddvd; +static unsigned int cd_hddvd_r; +static unsigned int cd_hddvd_rw; +static unsigned int cd_mo; +static unsigned int cd_mrw; +static unsigned int cd_mrw_w; + +/* media info */ +static unsigned int cd_media; +static unsigned int cd_media_cd_rom; +static unsigned int cd_media_cd_r; +static unsigned int cd_media_cd_rw; +static unsigned int cd_media_dvd_rom; +static unsigned int cd_media_dvd_r; +static unsigned int cd_media_dvd_rw; +static unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */ +static unsigned int cd_media_dvd_rw_seq; /* sequential mode */ +static unsigned int cd_media_dvd_ram; +static unsigned int cd_media_dvd_plus_r; +static unsigned int cd_media_dvd_plus_rw; +static unsigned int cd_media_dvd_plus_r_dl; +static unsigned int cd_media_dvd_plus_rw_dl; +static unsigned int cd_media_bd; +static unsigned int cd_media_bd_r; +static unsigned int cd_media_bd_re; +static unsigned int cd_media_hddvd; +static unsigned int cd_media_hddvd_r; +static unsigned int cd_media_hddvd_rw; +static unsigned int cd_media_mo; +static unsigned int cd_media_mrw; +static unsigned int cd_media_mrw_w; + +static const char *cd_media_state = NULL; +static unsigned int cd_media_session_next; +static unsigned int cd_media_session_count; +static unsigned int cd_media_track_count; +static unsigned int cd_media_track_count_data; +static unsigned int cd_media_track_count_audio; +static unsigned long long int cd_media_session_last_offset; + +#define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13])) +#define SK(errcode) (((errcode) >> 16) & 0xF) +#define ASC(errcode) (((errcode) >> 8) & 0xFF) +#define ASCQ(errcode) ((errcode) & 0xFF) + +static bool is_mounted(const char *device) +{ + struct stat statbuf; + FILE *fp; + int maj, min; + bool mounted = false; + + if (stat(device, &statbuf) < 0) + return -ENODEV; + + fp = fopen("/proc/self/mountinfo", "re"); + if (fp == NULL) + return -ENOSYS; + while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) { + if (makedev(maj, min) == statbuf.st_rdev) { + mounted = true; + break; + } + } + fclose(fp); + return mounted; +} + +static void info_scsi_cmd_err(struct udev *udev, const char *cmd, int err) +{ + if (err == -1) { + log_debug("%s failed", cmd); + return; + } + log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err)); +} + +struct scsi_cmd { + struct cdrom_generic_command cgc; + union { + struct request_sense s; + unsigned char u[18]; + } _sense; + struct sg_io_hdr sg_io; +}; + +static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd) +{ + memzero(cmd, sizeof(struct scsi_cmd)); + cmd->cgc.quiet = 1; + cmd->cgc.sense = &cmd->_sense.s; + cmd->sg_io.interface_id = 'S'; + cmd->sg_io.mx_sb_len = sizeof(cmd->_sense); + cmd->sg_io.cmdp = cmd->cgc.cmd; + cmd->sg_io.sbp = cmd->_sense.u; + cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO; +} + +static void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg) +{ + cmd->sg_io.cmd_len = i + 1; + cmd->cgc.cmd[i] = arg; +} + +#define CHECK_CONDITION 0x01 + +static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize) +{ + int ret = 0; + + if (bufsize > 0) { + cmd->sg_io.dxferp = buf; + cmd->sg_io.dxfer_len = bufsize; + cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV; + } else { + cmd->sg_io.dxfer_direction = SG_DXFER_NONE; + } + if (ioctl(fd, SG_IO, &cmd->sg_io)) + return -1; + + if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) { + errno = EIO; + ret = -1; + if (cmd->sg_io.masked_status & CHECK_CONDITION) { + ret = ERRCODE(cmd->_sense.u); + if (ret == 0) + ret = -1; + } + } + return ret; +} + +static int media_lock(struct udev *udev, int fd, bool lock) +{ + int err; + + /* disable the kernel's lock logic */ + err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK); + if (err < 0) + log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed"); + + err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0); + if (err < 0) + log_debug("CDROM_LOCKDOOR failed"); + + return err; +} + +static int media_eject(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + int err; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x1b); + scsi_cmd_set(udev, &sc, 4, 0x02); + scsi_cmd_set(udev, &sc, 5, 0); + err = scsi_cmd_run(udev, &sc, fd, NULL, 0); + if ((err != 0)) { + info_scsi_cmd_err(udev, "START_STOP_UNIT", err); + return -1; + } + return 0; +} + +static int cd_capability_compat(struct udev *udev, int fd) +{ + int capability; + + capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL); + if (capability < 0) { + log_debug("CDROM_GET_CAPABILITY failed"); + return -1; + } + + if (capability & CDC_CD_R) + cd_cd_r = 1; + if (capability & CDC_CD_RW) + cd_cd_rw = 1; + if (capability & CDC_DVD) + cd_dvd_rom = 1; + if (capability & CDC_DVD_R) + cd_dvd_r = 1; + if (capability & CDC_DVD_RAM) + cd_dvd_ram = 1; + if (capability & CDC_MRW) + cd_mrw = 1; + if (capability & CDC_MRW_W) + cd_mrw_w = 1; + return 0; +} + +static int cd_media_compat(struct udev *udev, int fd) +{ + if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) { + log_debug("CDROM_DRIVE_STATUS != CDS_DISC_OK"); + return -1; + } + cd_media = 1; + return 0; +} + +static int cd_inquiry(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + unsigned char inq[128]; + int err; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x12); + scsi_cmd_set(udev, &sc, 4, 36); + scsi_cmd_set(udev, &sc, 5, 0); + err = scsi_cmd_run(udev, &sc, fd, inq, 36); + if ((err != 0)) { + info_scsi_cmd_err(udev, "INQUIRY", err); + return -1; + } + + if ((inq[0] & 0x1F) != 5) { + log_debug("not an MMC unit"); + return -1; + } + + log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32); + return 0; +} + +static void feature_profile_media(struct udev *udev, int cur_profile) +{ + switch (cur_profile) { + case 0x03: + case 0x04: + case 0x05: + log_debug("profile 0x%02x ", cur_profile); + cd_media = 1; + cd_media_mo = 1; + break; + case 0x08: + log_debug("profile 0x%02x media_cd_rom", cur_profile); + cd_media = 1; + cd_media_cd_rom = 1; + break; + case 0x09: + log_debug("profile 0x%02x media_cd_r", cur_profile); + cd_media = 1; + cd_media_cd_r = 1; + break; + case 0x0a: + log_debug("profile 0x%02x media_cd_rw", cur_profile); + cd_media = 1; + cd_media_cd_rw = 1; + break; + case 0x10: + log_debug("profile 0x%02x media_dvd_ro", cur_profile); + cd_media = 1; + cd_media_dvd_rom = 1; + break; + case 0x11: + log_debug("profile 0x%02x media_dvd_r", cur_profile); + cd_media = 1; + cd_media_dvd_r = 1; + break; + case 0x12: + log_debug("profile 0x%02x media_dvd_ram", cur_profile); + cd_media = 1; + cd_media_dvd_ram = 1; + break; + case 0x13: + log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile); + cd_media = 1; + cd_media_dvd_rw = 1; + cd_media_dvd_rw_ro = 1; + break; + case 0x14: + log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile); + cd_media = 1; + cd_media_dvd_rw = 1; + cd_media_dvd_rw_seq = 1; + break; + case 0x1B: + log_debug("profile 0x%02x media_dvd_plus_r", cur_profile); + cd_media = 1; + cd_media_dvd_plus_r = 1; + break; + case 0x1A: + log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile); + cd_media = 1; + cd_media_dvd_plus_rw = 1; + break; + case 0x2A: + log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile); + cd_media = 1; + cd_media_dvd_plus_rw_dl = 1; + break; + case 0x2B: + log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile); + cd_media = 1; + cd_media_dvd_plus_r_dl = 1; + break; + case 0x40: + log_debug("profile 0x%02x media_bd", cur_profile); + cd_media = 1; + cd_media_bd = 1; + break; + case 0x41: + case 0x42: + log_debug("profile 0x%02x media_bd_r", cur_profile); + cd_media = 1; + cd_media_bd_r = 1; + break; + case 0x43: + log_debug("profile 0x%02x media_bd_re", cur_profile); + cd_media = 1; + cd_media_bd_re = 1; + break; + case 0x50: + log_debug("profile 0x%02x media_hddvd", cur_profile); + cd_media = 1; + cd_media_hddvd = 1; + break; + case 0x51: + log_debug("profile 0x%02x media_hddvd_r", cur_profile); + cd_media = 1; + cd_media_hddvd_r = 1; + break; + case 0x52: + log_debug("profile 0x%02x media_hddvd_rw", cur_profile); + cd_media = 1; + cd_media_hddvd_rw = 1; + break; + default: + log_debug("profile 0x%02x ", cur_profile); + break; + } +} + +static int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size) +{ + unsigned int i; + + for (i = 0; i+4 <= size; i += 4) { + int profile; + + profile = profiles[i] << 8 | profiles[i+1]; + switch (profile) { + case 0x03: + case 0x04: + case 0x05: + log_debug("profile 0x%02x mo", profile); + cd_mo = 1; + break; + case 0x08: + log_debug("profile 0x%02x cd_rom", profile); + cd_cd_rom = 1; + break; + case 0x09: + log_debug("profile 0x%02x cd_r", profile); + cd_cd_r = 1; + break; + case 0x0A: + log_debug("profile 0x%02x cd_rw", profile); + cd_cd_rw = 1; + break; + case 0x10: + log_debug("profile 0x%02x dvd_rom", profile); + cd_dvd_rom = 1; + break; + case 0x12: + log_debug("profile 0x%02x dvd_ram", profile); + cd_dvd_ram = 1; + break; + case 0x13: + case 0x14: + log_debug("profile 0x%02x dvd_rw", profile); + cd_dvd_rw = 1; + break; + case 0x1B: + log_debug("profile 0x%02x dvd_plus_r", profile); + cd_dvd_plus_r = 1; + break; + case 0x1A: + log_debug("profile 0x%02x dvd_plus_rw", profile); + cd_dvd_plus_rw = 1; + break; + case 0x2A: + log_debug("profile 0x%02x dvd_plus_rw_dl", profile); + cd_dvd_plus_rw_dl = 1; + break; + case 0x2B: + log_debug("profile 0x%02x dvd_plus_r_dl", profile); + cd_dvd_plus_r_dl = 1; + break; + case 0x40: + cd_bd = 1; + log_debug("profile 0x%02x bd", profile); + break; + case 0x41: + case 0x42: + cd_bd_r = 1; + log_debug("profile 0x%02x bd_r", profile); + break; + case 0x43: + cd_bd_re = 1; + log_debug("profile 0x%02x bd_re", profile); + break; + case 0x50: + cd_hddvd = 1; + log_debug("profile 0x%02x hddvd", profile); + break; + case 0x51: + cd_hddvd_r = 1; + log_debug("profile 0x%02x hddvd_r", profile); + break; + case 0x52: + cd_hddvd_rw = 1; + log_debug("profile 0x%02x hddvd_rw", profile); + break; + default: + log_debug("profile 0x%02x ", profile); + break; + } + } + return 0; +} + +/* returns 0 if media was detected */ +static int cd_profiles_old_mmc(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + int err; + + unsigned char header[32]; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x51); + scsi_cmd_set(udev, &sc, 8, sizeof(header)); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ DISC INFORMATION", err); + if (cd_media == 1) { + log_debug("no current profile, but disc is present; assuming CD-ROM"); + cd_media_cd_rom = 1; + cd_media_track_count = 1; + cd_media_track_count_data = 1; + return 0; + } else { + log_debug("no current profile, assuming no media"); + return -1; + } + }; + + cd_media = 1; + + if (header[2] & 16) { + cd_media_cd_rw = 1; + log_debug("profile 0x0a media_cd_rw"); + } else if ((header[2] & 3) < 2 && cd_cd_r) { + cd_media_cd_r = 1; + log_debug("profile 0x09 media_cd_r"); + } else { + cd_media_cd_rom = 1; + log_debug("profile 0x08 media_cd_rom"); + } + return 0; +} + +/* returns 0 if media was detected */ +static int cd_profiles(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + unsigned char features[65530]; + unsigned int cur_profile = 0; + unsigned int len; + unsigned int i; + int err; + int ret; + + ret = -1; + + /* First query the current profile */ + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x46); + scsi_cmd_set(udev, &sc, 8, 8); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, features, 8); + if ((err != 0)) { + info_scsi_cmd_err(udev, "GET CONFIGURATION", err); + /* handle pre-MMC2 drives which do not support GET CONFIGURATION */ + if (SK(err) == 0x5 && ASC(err) == 0x20) { + log_debug("drive is pre-MMC2 and does not support 46h get configuration command"); + log_debug("trying to work around the problem"); + ret = cd_profiles_old_mmc(udev, fd); + } + goto out; + } + + cur_profile = features[6] << 8 | features[7]; + if (cur_profile > 0) { + log_debug("current profile 0x%02x", cur_profile); + feature_profile_media (udev, cur_profile); + ret = 0; /* we have media */ + } else { + log_debug("no current profile, assuming no media"); + } + + len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; + log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len); + + if (len > sizeof(features)) { + log_debug("can not get features in a single query, truncating"); + len = sizeof(features); + } else if (len <= 8) { + len = sizeof(features); + } + + /* Now get the full feature buffer */ + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x46); + scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff); + scsi_cmd_set(udev, &sc, 8, len & 0xff); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, features, len); + if ((err != 0)) { + info_scsi_cmd_err(udev, "GET CONFIGURATION", err); + return -1; + } + + /* parse the length once more, in case the drive decided to have other features suddenly :) */ + len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; + log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len); + + if (len > sizeof(features)) { + log_debug("can not get features in a single query, truncating"); + len = sizeof(features); + } + + /* device features */ + for (i = 8; i+4 < len; i += (4 + features[i+3])) { + unsigned int feature; + + feature = features[i] << 8 | features[i+1]; + + switch (feature) { + case 0x00: + log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4); + feature_profiles(udev, &features[i]+4, features[i+3]); + break; + default: + log_debug("GET CONFIGURATION: feature 0x%04x , with 0x%02x bytes", feature, features[i+3]); + break; + } + } +out: + return ret; +} + +static int cd_media_info(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + unsigned char header[32]; + static const char *media_status[] = { + "blank", + "appendable", + "complete", + "other" + }; + int err; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x51); + scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ DISC INFORMATION", err); + return -1; + }; + + cd_media = 1; + log_debug("disk type %02x", header[8]); + log_debug("hardware reported media status: %s", media_status[header[2] & 3]); + + /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */ + if (!cd_media_cd_rom) + cd_media_state = media_status[header[2] & 3]; + + /* fresh DVD-RW in restricted overwite mode reports itself as + * "appendable"; change it to "blank" to make it consistent with what + * gets reported after blanking, and what userspace expects */ + if (cd_media_dvd_rw_ro && (header[2] & 3) == 1) + cd_media_state = media_status[0]; + + /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are + * always "complete", DVD-RAM are "other" or "complete" if the disc is + * write protected; we need to check the contents if it is blank */ + if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) { + unsigned char buffer[32 * 2048]; + unsigned char result, len; + int block, offset; + + if (cd_media_dvd_ram) { + /* a write protected dvd-ram may report "complete" status */ + + unsigned char dvdstruct[8]; + unsigned char format[12]; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0xAD); + scsi_cmd_set(udev, &sc, 7, 0xC0); + scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct)); + scsi_cmd_set(udev, &sc, 11, 0); + err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err); + return -1; + } + if (dvdstruct[4] & 0x02) { + cd_media_state = media_status[2]; + log_debug("write-protected DVD-RAM media inserted"); + goto determined; + } + + /* let's make sure we don't try to read unformatted media */ + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x23); + scsi_cmd_set(udev, &sc, 8, sizeof(format)); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err); + return -1; + } + + len = format[3]; + if (len & 7 || len < 16) { + log_debug("invalid format capacities length"); + return -1; + } + + switch(format[8] & 3) { + case 1: + log_debug("unformatted DVD-RAM media inserted"); + /* This means that last format was interrupted + * or failed, blank dvd-ram discs are factory + * formatted. Take no action here as it takes + * quite a while to reformat a dvd-ram and it's + * not automatically started */ + goto determined; + + case 2: + log_debug("formatted DVD-RAM media inserted"); + break; + + case 3: + cd_media = 0; //return no media + log_debug("format capacities returned no media"); + return -1; + } + } + + /* Take a closer look at formatted media (unformatted DVD+RW + * has "blank" status", DVD-RAM was examined earlier) and check + * for ISO and UDF PVDs or a fs superblock presence and do it + * in one ioctl (we need just sectors 0 and 16) */ + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x28); + scsi_cmd_set(udev, &sc, 5, 0); + scsi_cmd_set(udev, &sc, 8, 32); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer)); + if ((err != 0)) { + cd_media = 0; + info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err); + return -1; + } + + /* if any non-zero data is found in sector 16 (iso and udf) or + * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc + * is assumed non-blank */ + result = 0; + + for (block = 32768; block >= 0 && !result; block -= 32768) { + offset = block; + while (offset < (block + 2048) && !result) { + result = buffer [offset]; + offset++; + } + } + + if (!result) { + cd_media_state = media_status[0]; + log_debug("no data in blocks 0 or 16, assuming blank"); + } else { + log_debug("data in blocks 0 or 16, assuming complete"); + } + } + +determined: + /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in + * restricted overwrite mode can never append, only in sequential mode */ + if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro) + cd_media_session_next = header[10] << 8 | header[5]; + cd_media_session_count = header[9] << 8 | header[4]; + cd_media_track_count = header[11] << 8 | header[6]; + + return 0; +} + +static int cd_media_toc(struct udev *udev, int fd) +{ + struct scsi_cmd sc; + unsigned char header[12]; + unsigned char toc[65536]; + unsigned int len, i, num_tracks; + unsigned char *p; + int err; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x43); + scsi_cmd_set(udev, &sc, 6, 1); + scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ TOC", err); + return -1; + } + + len = (header[0] << 8 | header[1]) + 2; + log_debug("READ TOC: len: %d, start track: %d, end track: %d", len, header[2], header[3]); + if (len > sizeof(toc)) + return -1; + if (len < 2) + return -1; + /* 2: first track, 3: last track */ + num_tracks = header[3] - header[2] + 1; + + /* empty media has no tracks */ + if (len < 8) + return 0; + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x43); + scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */ + scsi_cmd_set(udev, &sc, 7, (len >> 8) & 0xff); + scsi_cmd_set(udev, &sc, 8, len & 0xff); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, toc, len); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ TOC (tracks)", err); + return -1; + } + + /* Take care to not iterate beyond the last valid track as specified in + * the TOC, but also avoid going beyond the TOC length, just in case + * the last track number is invalidly large */ + for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) { + unsigned int block; + unsigned int is_data_track; + + is_data_track = (p[1] & 0x04) != 0; + + block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; + log_debug("track=%u info=0x%x(%s) start_block=%u", + p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block); + + if (is_data_track) + cd_media_track_count_data++; + else + cd_media_track_count_audio++; + } + + scsi_cmd_init(udev, &sc); + scsi_cmd_set(udev, &sc, 0, 0x43); + scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */ + scsi_cmd_set(udev, &sc, 8, sizeof(header)); + scsi_cmd_set(udev, &sc, 9, 0); + err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); + if ((err != 0)) { + info_scsi_cmd_err(udev, "READ TOC (multi session)", err); + return -1; + } + len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7]; + log_debug("last track %u starts at block %u", header[4+2], len); + cd_media_session_last_offset = (unsigned long long int)len * 2048; + return 0; +} + +int main(int argc, char *argv[]) +{ + struct udev *udev; + static const struct option options[] = { + { "lock-media", no_argument, NULL, 'l' }, + { "unlock-media", no_argument, NULL, 'u' }, + { "eject-media", no_argument, NULL, 'e' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + bool eject = false; + bool lock = false; + bool unlock = false; + const char *node = NULL; + int fd = -1; + int cnt; + int rc = 0; + + udev = udev_new(); + if (udev == NULL) + goto exit; + + log_open(); + udev_set_log_fn(udev, log_fn); + + while (1) { + int option; + + option = getopt_long(argc, argv, "deluh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'l': + lock = true; + break; + case 'u': + unlock = true; + break; + case 'e': + eject = true; + break; + case 'd': + debug = true; + log_set_max_level(LOG_DEBUG); + udev_set_log_priority(udev, LOG_DEBUG); + break; + case 'h': + printf("Usage: cdrom_id [options] \n" + " --lock-media lock the media (to enable eject request events)\n" + " --unlock-media unlock the media\n" + " --eject-media eject the media\n" + " --debug debug to stderr\n" + " --help print this help text\n\n"); + goto exit; + default: + rc = 1; + goto exit; + } + } + + node = argv[optind]; + if (!node) { + log_error("no device"); + fprintf(stderr, "no device\n"); + rc = 1; + goto exit; + } + + srand((unsigned int)getpid()); + for (cnt = 20; cnt > 0; cnt--) { + struct timespec duration; + + fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC|(is_mounted(node) ? 0 : O_EXCL)); + if (fd >= 0 || errno != EBUSY) + break; + duration.tv_sec = 0; + duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); + nanosleep(&duration, NULL); + } + if (fd < 0) { + log_debug("unable to open '%s'", node); + fprintf(stderr, "unable to open '%s'\n", node); + rc = 1; + goto exit; + } + log_debug("probing: '%s'", node); + + /* same data as original cdrom_id */ + if (cd_capability_compat(udev, fd) < 0) { + rc = 1; + goto exit; + } + + /* check for media - don't bail if there's no media as we still need to + * to read profiles */ + cd_media_compat(udev, fd); + + /* check if drive talks MMC */ + if (cd_inquiry(udev, fd) < 0) + goto work; + + /* read drive and possibly current profile */ + if (cd_profiles(udev, fd) != 0) + goto work; + + /* at this point we are guaranteed to have media in the drive - find out more about it */ + + /* get session/track info */ + cd_media_toc(udev, fd); + + /* get writable media state */ + cd_media_info(udev, fd); + +work: + /* lock the media, so we enable eject button events */ + if (lock && cd_media) { + log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)"); + media_lock(udev, fd, true); + } + + if (unlock && cd_media) { + log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)"); + media_lock(udev, fd, false); + } + + if (eject) { + log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)"); + media_lock(udev, fd, false); + log_debug("START_STOP_UNIT (eject)"); + media_eject(udev, fd); + } + + printf("ID_CDROM=1\n"); + if (cd_cd_rom) + printf("ID_CDROM_CD=1\n"); + if (cd_cd_r) + printf("ID_CDROM_CD_R=1\n"); + if (cd_cd_rw) + printf("ID_CDROM_CD_RW=1\n"); + if (cd_dvd_rom) + printf("ID_CDROM_DVD=1\n"); + if (cd_dvd_r) + printf("ID_CDROM_DVD_R=1\n"); + if (cd_dvd_rw) + printf("ID_CDROM_DVD_RW=1\n"); + if (cd_dvd_ram) + printf("ID_CDROM_DVD_RAM=1\n"); + if (cd_dvd_plus_r) + printf("ID_CDROM_DVD_PLUS_R=1\n"); + if (cd_dvd_plus_rw) + printf("ID_CDROM_DVD_PLUS_RW=1\n"); + if (cd_dvd_plus_r_dl) + printf("ID_CDROM_DVD_PLUS_R_DL=1\n"); + if (cd_dvd_plus_rw_dl) + printf("ID_CDROM_DVD_PLUS_RW_DL=1\n"); + if (cd_bd) + printf("ID_CDROM_BD=1\n"); + if (cd_bd_r) + printf("ID_CDROM_BD_R=1\n"); + if (cd_bd_re) + printf("ID_CDROM_BD_RE=1\n"); + if (cd_hddvd) + printf("ID_CDROM_HDDVD=1\n"); + if (cd_hddvd_r) + printf("ID_CDROM_HDDVD_R=1\n"); + if (cd_hddvd_rw) + printf("ID_CDROM_HDDVD_RW=1\n"); + if (cd_mo) + printf("ID_CDROM_MO=1\n"); + if (cd_mrw) + printf("ID_CDROM_MRW=1\n"); + if (cd_mrw_w) + printf("ID_CDROM_MRW_W=1\n"); + + if (cd_media) + printf("ID_CDROM_MEDIA=1\n"); + if (cd_media_mo) + printf("ID_CDROM_MEDIA_MO=1\n"); + if (cd_media_mrw) + printf("ID_CDROM_MEDIA_MRW=1\n"); + if (cd_media_mrw_w) + printf("ID_CDROM_MEDIA_MRW_W=1\n"); + if (cd_media_cd_rom) + printf("ID_CDROM_MEDIA_CD=1\n"); + if (cd_media_cd_r) + printf("ID_CDROM_MEDIA_CD_R=1\n"); + if (cd_media_cd_rw) + printf("ID_CDROM_MEDIA_CD_RW=1\n"); + if (cd_media_dvd_rom) + printf("ID_CDROM_MEDIA_DVD=1\n"); + if (cd_media_dvd_r) + printf("ID_CDROM_MEDIA_DVD_R=1\n"); + if (cd_media_dvd_ram) + printf("ID_CDROM_MEDIA_DVD_RAM=1\n"); + if (cd_media_dvd_rw) + printf("ID_CDROM_MEDIA_DVD_RW=1\n"); + if (cd_media_dvd_plus_r) + printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n"); + if (cd_media_dvd_plus_rw) + printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n"); + if (cd_media_dvd_plus_rw_dl) + printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n"); + if (cd_media_dvd_plus_r_dl) + printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n"); + if (cd_media_bd) + printf("ID_CDROM_MEDIA_BD=1\n"); + if (cd_media_bd_r) + printf("ID_CDROM_MEDIA_BD_R=1\n"); + if (cd_media_bd_re) + printf("ID_CDROM_MEDIA_BD_RE=1\n"); + if (cd_media_hddvd) + printf("ID_CDROM_MEDIA_HDDVD=1\n"); + if (cd_media_hddvd_r) + printf("ID_CDROM_MEDIA_HDDVD_R=1\n"); + if (cd_media_hddvd_rw) + printf("ID_CDROM_MEDIA_HDDVD_RW=1\n"); + + if (cd_media_state != NULL) + printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state); + if (cd_media_session_next > 0) + printf("ID_CDROM_MEDIA_SESSION_NEXT=%d\n", cd_media_session_next); + if (cd_media_session_count > 0) + printf("ID_CDROM_MEDIA_SESSION_COUNT=%d\n", cd_media_session_count); + if (cd_media_session_count > 1 && cd_media_session_last_offset > 0) + printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset); + if (cd_media_track_count > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT=%d\n", cd_media_track_count); + if (cd_media_track_count_audio > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%d\n", cd_media_track_count_audio); + if (cd_media_track_count_data > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%d\n", cd_media_track_count_data); +exit: + if (fd >= 0) + close(fd); + udev_unref(udev); + log_close(); + return rc; +} diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c new file mode 100644 index 0000000..4ecb6b0 --- /dev/null +++ b/src/udev/collect/collect.c @@ -0,0 +1,492 @@ +/* + * Collect variables across events. + * + * usage: collect [--add|--remove] + * + * Adds ID to the list governed by . + * must be part of the ID list . + * If all IDs given by are listed (ie collect has been + * invoked for each ID in ) collect returns 0, the + * number of missing IDs otherwise. + * A negative number is returned on error. + * + * Copyright(C) 2007, Hannes Reinecke + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "macro.h" + +#define BUFSIZE 16 +#define UDEV_ALARM_TIMEOUT 180 + +enum collect_state { + STATE_NONE, + STATE_OLD, + STATE_CONFIRMED, +}; + +struct _mate { + struct udev_list_node node; + char *name; + enum collect_state state; +}; + +static struct udev_list_node bunch; +static int debug; + +/* This can increase dynamically */ +static size_t bufsize = BUFSIZE; + +static inline struct _mate *node_to_mate(struct udev_list_node *node) +{ + return container_of(node, struct _mate, node); +} + +noreturn static void sig_alrm(int signo) +{ + exit(4); +} + +static void usage(void) +{ + printf("usage: collect [--add|--remove] [--debug] \n" + "\n" + " Adds ID to the list governed by .\n" + " must be part of the list .\n" + " If all IDs given by are listed (ie collect has been\n" + " invoked for each ID in ) collect returns 0, the\n" + " number of missing IDs otherwise.\n" + " On error a negative number is returned.\n" + "\n"); +} + +/* + * prepare + * + * Prepares the database file + */ +static int prepare(char *dir, char *filename) +{ + struct stat statbuf; + char buf[512]; + int fd; + + if (stat(dir, &statbuf) < 0) + mkdir(dir, 0700); + + snprintf(buf, sizeof(buf), "%s/%s", dir, filename); + + fd = open(buf,O_RDWR|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR); + if (fd < 0) + fprintf(stderr, "Cannot open %s: %m\n", buf); + + if (lockf(fd,F_TLOCK,0) < 0) { + if (debug) + fprintf(stderr, "Lock taken, wait for %d seconds\n", UDEV_ALARM_TIMEOUT); + if (errno == EAGAIN || errno == EACCES) { + alarm(UDEV_ALARM_TIMEOUT); + lockf(fd, F_LOCK, 0); + if (debug) + fprintf(stderr, "Acquired lock on %s\n", buf); + } else { + if (debug) + fprintf(stderr, "Could not get lock on %s: %m\n", buf); + } + } + + return fd; +} + +/* + * Read checkpoint file + * + * Tricky reading this. We allocate a buffer twice as large + * as we're going to read. Then we read into the upper half + * of that buffer and start parsing. + * Once we do _not_ find end-of-work terminator (whitespace + * character) we move the upper half to the lower half, + * adjust the read pointer and read the next bit. + * Quite clever methinks :-) + * I should become a programmer ... + * + * Yes, one could have used fgets() for this. But then we'd + * have to use freopen etc which I found quite tedious. + */ +static int checkout(int fd) +{ + int len; + char *buf, *ptr, *word = NULL; + struct _mate *him; + + restart: + len = bufsize >> 1; + buf = malloc(bufsize + 1); + if (!buf) + return log_oom(); + memset(buf, ' ', bufsize); + buf[bufsize] = '\0'; + + ptr = buf + len; + while ((read(fd, buf + len, len)) > 0) { + while (ptr && *ptr) { + word = ptr; + ptr = strpbrk(word," \n\t\r"); + if (!ptr && word < (buf + len)) { + bufsize = bufsize << 1; + if (debug) + fprintf(stderr, "ID overflow, restarting with size %zi\n", bufsize); + free(buf); + lseek(fd, 0, SEEK_SET); + goto restart; + } + if (ptr) { + *ptr = '\0'; + ptr++; + if (!strlen(word)) + continue; + + if (debug) + fprintf(stderr, "Found word %s\n", word); + him = malloc(sizeof (struct _mate)); + if (!him) { + free(buf); + return log_oom(); + } + him->name = strdup(word); + if (!him->name) { + free(buf); + free(him); + return log_oom(); + } + him->state = STATE_OLD; + udev_list_node_append(&him->node, &bunch); + word = NULL; + } + } + memcpy(buf, buf + len, len); + memset(buf + len, ' ', len); + + if (!ptr) + ptr = word; + if (!ptr) + break; + ptr -= len; + } + + free(buf); + return 0; +} + +/* + * invite + * + * Adds a new ID 'us' to the internal list, + * marks it as confirmed. + */ +static void invite(char *us) +{ + struct udev_list_node *him_node; + struct _mate *who = NULL; + + if (debug) + fprintf(stderr, "Adding ID '%s'\n", us); + + udev_list_node_foreach(him_node, &bunch) { + struct _mate *him = node_to_mate(him_node); + + if (streq(him->name, us)) { + him->state = STATE_CONFIRMED; + who = him; + } + } + if (debug && !who) + fprintf(stderr, "ID '%s' not in database\n", us); + +} + +/* + * reject + * + * Marks the ID 'us' as invalid, + * causing it to be removed when the + * list is written out. + */ +static void reject(char *us) +{ + struct udev_list_node *him_node; + struct _mate *who = NULL; + + if (debug) + fprintf(stderr, "Removing ID '%s'\n", us); + + udev_list_node_foreach(him_node, &bunch) { + struct _mate *him = node_to_mate(him_node); + + if (streq(him->name, us)) { + him->state = STATE_NONE; + who = him; + } + } + if (debug && !who) + fprintf(stderr, "ID '%s' not in database\n", us); +} + +/* + * kickout + * + * Remove all IDs in the internal list which are not part + * of the list passed via the commandline. + */ +static void kickout(void) +{ + struct udev_list_node *him_node; + struct udev_list_node *tmp; + + udev_list_node_foreach_safe(him_node, tmp, &bunch) { + struct _mate *him = node_to_mate(him_node); + + if (him->state == STATE_OLD) { + udev_list_node_remove(&him->node); + free(him->name); + free(him); + } + } +} + +/* + * missing + * + * Counts all missing IDs in the internal list. + */ +static int missing(int fd) +{ + char *buf; + int ret = 0; + struct udev_list_node *him_node; + + buf = malloc(bufsize); + if (!buf) + return log_oom(); + + udev_list_node_foreach(him_node, &bunch) { + struct _mate *him = node_to_mate(him_node); + + if (him->state == STATE_NONE) { + ret++; + } else { + while (strlen(him->name)+1 >= bufsize) { + char *tmpbuf; + + bufsize = bufsize << 1; + tmpbuf = realloc(buf, bufsize); + if (!tmpbuf) { + free(buf); + return log_oom(); + } + buf = tmpbuf; + } + snprintf(buf, strlen(him->name)+2, "%s ", him->name); + if (write(fd, buf, strlen(buf)) < 0) { + free(buf); + return -1; + } + } + } + + free(buf); + return ret; +} + +/* + * everybody + * + * Prints out the status of the internal list. + */ +static void everybody(void) +{ + struct udev_list_node *him_node; + const char *state = ""; + + udev_list_node_foreach(him_node, &bunch) { + struct _mate *him = node_to_mate(him_node); + + switch (him->state) { + case STATE_NONE: + state = "none"; + break; + case STATE_OLD: + state = "old"; + break; + case STATE_CONFIRMED: + state = "confirmed"; + break; + } + fprintf(stderr, "ID: %s=%s\n", him->name, state); + } +} + +int main(int argc, char **argv) +{ + struct udev *udev; + static const struct option options[] = { + { "add", no_argument, NULL, 'a' }, + { "remove", no_argument, NULL, 'r' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + int argi; + char *checkpoint, *us; + int fd; + int i; + int ret = EXIT_SUCCESS; + int prune = 0; + char tmpdir[UTIL_PATH_SIZE]; + + udev = udev_new(); + if (udev == NULL) { + ret = EXIT_FAILURE; + goto exit; + } + + while (1) { + int option; + + option = getopt_long(argc, argv, "ardh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'a': + prune = 0; + break; + case 'r': + prune = 1; + break; + case 'd': + debug = 1; + break; + case 'h': + usage(); + goto exit; + default: + ret = 1; + goto exit; + } + } + + argi = optind; + if (argi + 2 > argc) { + printf("Missing parameter(s)\n"); + ret = 1; + goto exit; + } + checkpoint = argv[argi++]; + us = argv[argi++]; + + if (signal(SIGALRM, sig_alrm) == SIG_ERR) { + fprintf(stderr, "Cannot set SIGALRM: %m\n"); + ret = 2; + goto exit; + } + + udev_list_node_init(&bunch); + + if (debug) + fprintf(stderr, "Using checkpoint '%s'\n", checkpoint); + + strscpyl(tmpdir, sizeof(tmpdir), "/run/udev/collect", NULL); + fd = prepare(tmpdir, checkpoint); + if (fd < 0) { + ret = 3; + goto out; + } + + if (checkout(fd) < 0) { + ret = 2; + goto out; + } + + for (i = argi; i < argc; i++) { + struct udev_list_node *him_node; + struct _mate *who; + + who = NULL; + udev_list_node_foreach(him_node, &bunch) { + struct _mate *him = node_to_mate(him_node); + + if (streq(him->name, argv[i])) + who = him; + } + if (!who) { + struct _mate *him; + + if (debug) + fprintf(stderr, "ID %s: not in database\n", argv[i]); + him = new(struct _mate, 1); + if (!him) { + ret = ENOMEM; + goto out; + } + + him->name = strdup(argv[i]); + if (!him->name) { + free(him); + ret = ENOMEM; + goto out; + } + + him->state = STATE_NONE; + udev_list_node_append(&him->node, &bunch); + } else { + if (debug) + fprintf(stderr, "ID %s: found in database\n", argv[i]); + who->state = STATE_CONFIRMED; + } + } + + if (prune) + reject(us); + else + invite(us); + + if (debug) { + everybody(); + fprintf(stderr, "Prune lists\n"); + } + kickout(); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + ret = missing(fd); + + lockf(fd, F_ULOCK, 0); + close(fd); +out: + if (debug) + everybody(); + if (ret >= 0) + printf("COLLECT_%s=%d\n", checkpoint, ret); +exit: + udev_unref(udev); + return ret; +} diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c new file mode 100644 index 0000000..13c757b --- /dev/null +++ b/src/udev/mtd_probe/mtd_probe.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * + * mtd_probe is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mtd_probe 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 General Public License + * along with mtd_probe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ +#include "mtd_probe.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + int mtd_fd; + int error; + mtd_info_t mtd_info; + + if (argc != 2) { + printf("usage: mtd_probe /dev/mtd[n]\n"); + return 1; + } + + mtd_fd = open(argv[1], O_RDONLY|O_CLOEXEC); + if (mtd_fd == -1) { + perror("open"); + exit(-1); + } + + error = ioctl(mtd_fd, MEMGETINFO, &mtd_info); + if (error == -1) { + perror("ioctl"); + exit(-1); + } + + probe_smart_media(mtd_fd, &mtd_info); + return -1; +} diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h new file mode 100644 index 0000000..2a37ede --- /dev/null +++ b/src/udev/mtd_probe/mtd_probe.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * + * mtd_probe is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mtd_probe 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 General Public License + * along with mtd_probe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +/* Full oob structure as written on the flash */ +struct sm_oob { + uint32_t reserved; + uint8_t data_status; + uint8_t block_status; + uint8_t lba_copy1[2]; + uint8_t ecc2[3]; + uint8_t lba_copy2[2]; + uint8_t ecc1[3]; +} __attribute__((packed)); + + +/* one sector is always 512 bytes, but it can consist of two nand pages */ +#define SM_SECTOR_SIZE 512 + +/* oob area is also 16 bytes, but might be from two pages */ +#define SM_OOB_SIZE 16 + +/* This is maximum zone size, and all devices that have more that one zone + have this size */ +#define SM_MAX_ZONE_SIZE 1024 + +/* support for small page nand */ +#define SM_SMALL_PAGE 256 +#define SM_SMALL_OOB_SIZE 8 + + +void probe_smart_media(int mtd_fd, mtd_info_t *info); diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c new file mode 100644 index 0000000..a007cce --- /dev/null +++ b/src/udev/mtd_probe/probe_smartmedia.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * + * mtd_probe is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mtd_probe 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 General Public License + * along with mtd_probe; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mtd_probe.h" + +static const uint8_t cis_signature[] = { + 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 +}; + + +void probe_smart_media(int mtd_fd, mtd_info_t* info) +{ + int sector_size; + int block_size; + int size_in_megs; + int spare_count; + char* cis_buffer = malloc(SM_SECTOR_SIZE); + int offset; + int cis_found = 0; + + if (!cis_buffer) + return; + + if (info->type != MTD_NANDFLASH) + goto exit; + + sector_size = info->writesize; + block_size = info->erasesize; + size_in_megs = info->size / (1024 * 1024); + + if (sector_size != SM_SECTOR_SIZE && sector_size != SM_SMALL_PAGE) + goto exit; + + switch(size_in_megs) { + case 1: + case 2: + spare_count = 6; + break; + case 4: + spare_count = 12; + break; + default: + spare_count = 24; + break; + } + + for (offset = 0 ; offset < block_size * spare_count ; + offset += sector_size) { + lseek(mtd_fd, SEEK_SET, offset); + if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE){ + cis_found = 1; + break; + } + } + + if (!cis_found) + goto exit; + + if (memcmp(cis_buffer, cis_signature, sizeof(cis_signature)) != 0 && + (memcmp(cis_buffer + SM_SMALL_PAGE, cis_signature, + sizeof(cis_signature)) != 0)) + goto exit; + + printf("MTD_FTL=smartmedia\n"); + free(cis_buffer); + exit(0); +exit: + free(cis_buffer); + return; +} diff --git a/src/udev/net/.gitignore b/src/udev/net/.gitignore new file mode 100644 index 0000000..9ca85ba --- /dev/null +++ b/src/udev/net/.gitignore @@ -0,0 +1 @@ +/link-config-gperf.c diff --git a/src/udev/net/Makefile b/src/udev/net/Makefile new file mode 120000 index 0000000..94aaae2 --- /dev/null +++ b/src/udev/net/Makefile @@ -0,0 +1 @@ +../../Makefile \ No newline at end of file diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c new file mode 100644 index 0000000..6346530 --- /dev/null +++ b/src/udev/net/ethtool-util.c @@ -0,0 +1,194 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include + +#include "ethtool-util.h" + +#include "strxcpyx.h" +#include "util.h" +#include "log.h" +#include "conf-parser.h" + +static const char* const duplex_table[] = { + [DUP_FULL] = "full", + [DUP_HALF] = "half" +}; + +DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex); +DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting"); + +static const char* const wol_table[] = { + [WOL_PHY] = "phy", + [WOL_MAGIC] = "magic", + [WOL_OFF] = "off" +}; + +DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan); +DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting"); + +int ethtool_connect(int *ret) { + int fd; + + assert_return(ret, -EINVAL); + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + return -errno; + } + + *ret = fd; + + return 0; +} + +int ethtool_get_driver(int fd, const char *ifname, char **ret) { + struct ethtool_drvinfo ecmd = { + .cmd = ETHTOOL_GDRVINFO + }; + struct ifreq ifr = { + .ifr_data = (void*) &ecmd + }; + char *d; + int r; + + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + + r = ioctl(fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + + d = strdup(ecmd.driver); + if (!d) + return -ENOMEM; + + *ret = d; + return 0; +} + +int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex duplex) +{ + struct ethtool_cmd ecmd = { + .cmd = ETHTOOL_GSET + }; + struct ifreq ifr = { + .ifr_data = (void*) &ecmd + }; + bool need_update = false; + int r; + + if (speed == 0 && duplex == _DUP_INVALID) + return 0; + + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + + r = ioctl(fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + + if (ethtool_cmd_speed(&ecmd) != speed) { + ethtool_cmd_speed_set(&ecmd, speed); + need_update = true; + } + + switch (duplex) { + case DUP_HALF: + if (ecmd.duplex != DUPLEX_HALF) { + ecmd.duplex = DUPLEX_HALF; + need_update = true; + } + break; + case DUP_FULL: + if (ecmd.duplex != DUPLEX_FULL) { + ecmd.duplex = DUPLEX_FULL; + need_update = true; + } + break; + default: + break; + } + + if (need_update) { + ecmd.cmd = ETHTOOL_SSET; + + r = ioctl(fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + } + + return 0; +} + +int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) { + struct ethtool_wolinfo ecmd = { + .cmd = ETHTOOL_GWOL + }; + struct ifreq ifr = { + .ifr_data = (void*) &ecmd + }; + bool need_update = false; + int r; + + if (wol == _WOL_INVALID) + return 0; + + strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + + r = ioctl(fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + + switch (wol) { + case WOL_PHY: + if (ecmd.wolopts != WAKE_PHY) { + ecmd.wolopts = WAKE_PHY; + need_update = true; + } + break; + case WOL_MAGIC: + if (ecmd.wolopts != WAKE_MAGIC) { + ecmd.wolopts = WAKE_MAGIC; + need_update = true; + } + break; + case WOL_OFF: + if (ecmd.wolopts != 0) { + ecmd.wolopts = 0; + need_update = true; + } + break; + default: + break; + } + + if (need_update) { + ecmd.cmd = ETHTOOL_SWOL; + + r = ioctl(fd, SIOCETHTOOL, &ifr); + if (r < 0) + return -errno; + } + + return 0; +} diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h new file mode 100644 index 0000000..f44de50 --- /dev/null +++ b/src/udev/net/ethtool-util.h @@ -0,0 +1,56 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include + +/* we can't use DUPLEX_ prefix, as it + * clashes with */ +typedef enum Duplex { + DUP_FULL, + DUP_HALF, + _DUP_MAX, + _DUP_INVALID = -1 +} Duplex; + +typedef enum WakeOnLan { + WOL_PHY, + WOL_MAGIC, + WOL_OFF, + _WOL_MAX, + _WOL_INVALID = -1 +} WakeOnLan; + +int ethtool_connect(int *ret); + +int ethtool_get_driver(int fd, const char *ifname, char **ret); +int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex duplex); +int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol); + +const char *duplex_to_string(Duplex d) _const_; +Duplex duplex_from_string(const char *d) _pure_; + +const char *wol_to_string(WakeOnLan wol) _const_; +WakeOnLan wol_from_string(const char *wol) _pure_; + +int config_parse_duplex(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_wol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf new file mode 100644 index 0000000..819e93c --- /dev/null +++ b/src/udev/net/link-config-gperf.gperf @@ -0,0 +1,36 @@ +%{ +#include +#include "conf-parser.h" +#include "net-util.h" +#include "link-config.h" +#include "ethtool-util.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name link_config_gperf_hash +%define lookup-function-name link_config_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Match.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, match_mac) +Match.Path, config_parse_string, 0, offsetof(link_config, match_path) +Match.Driver, config_parse_string, 0, offsetof(link_config, match_driver) +Match.Type, config_parse_string, 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) +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_iec_size, 0, 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.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c new file mode 100644 index 0000000..05225e0 --- /dev/null +++ b/src/udev/net/link-config.c @@ -0,0 +1,486 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "sd-id128.h" + +#include "link-config.h" +#include "ethtool-util.h" + +#include "libudev-private.h" +#include "sd-rtnl.h" +#include "util.h" +#include "log.h" +#include "strv.h" +#include "path-util.h" +#include "conf-parser.h" +#include "conf-files.h" +#include "fileio.h" +#include "hashmap.h" +#include "rtnl-util.h" +#include "net-util.h" +#include "siphash24.h" + +struct link_config_ctx { + LIST_HEAD(link_config, links); + + int ethtool_fd; + + bool enable_name_policy; + + sd_rtnl *rtnl; + + usec_t link_dirs_ts_usec; +}; + +static const char* const link_dirs[] = { + "/etc/systemd/network", + "/run/systemd/network", + "/usr/lib/systemd/network", +#ifdef HAVE_SPLIT_USR + "/lib/systemd/network", +#endif + NULL}; + +DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free); +#define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep) + +int link_config_ctx_new(link_config_ctx **ret) { + _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL; + + if (!ret) + return -EINVAL; + + ctx = new0(link_config_ctx, 1); + if (!ctx) + return -ENOMEM; + + LIST_HEAD_INIT(ctx->links); + + ctx->ethtool_fd = -1; + + ctx->enable_name_policy = true; + + *ret = ctx; + ctx = NULL; + + return 0; +} + +static int link_config_ctx_connect(link_config_ctx *ctx) { + int r; + + if (ctx->ethtool_fd == -1) { + r = ethtool_connect(&ctx->ethtool_fd); + if (r < 0) + return r; + } + + if (!ctx->rtnl) { + r = sd_rtnl_open(&ctx->rtnl, 0); + if (r < 0) + return r; + } + + return 0; +} + +static void link_configs_free(link_config_ctx *ctx) { + link_config *link, *link_next; + + if (!ctx) + return; + + LIST_FOREACH_SAFE(links, link, link_next, ctx->links) { + free(link->filename); + free(link->match_path); + free(link->match_driver); + free(link->match_type); + free(link->description); + free(link->alias); + + free(link); + } +} + +void link_config_ctx_free(link_config_ctx *ctx) { + if (!ctx) + return; + + if (ctx->ethtool_fd >= 0) + close_nointr_nofail(ctx->ethtool_fd); + + sd_rtnl_unref(ctx->rtnl); + + link_configs_free(ctx); + + free(ctx); + + return; +} + +static int load_link(link_config_ctx *ctx, const char *filename) { + link_config *link; + _cleanup_fclose_ FILE *file; + int r; + + assert(ctx); + assert(filename); + + file = fopen(filename, "re"); + if (!file) { + if (errno == ENOENT) + return 0; + else + return errno; + } + + link = new0(link_config, 1); + if (!link) { + r = log_oom(); + goto failure; + } + + link->mac_policy = _MACPOLICY_INVALID; + link->wol = _WOL_INVALID; + link->duplex = _DUP_INVALID; + + r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup, + (void*) link_config_gperf_lookup, false, false, link); + if (r < 0) { + log_warning("Could not parse config file %s: %s", filename, strerror(-r)); + goto failure; + } else + log_debug("Parsed configuration file %s", filename); + + link->filename = strdup(filename); + + LIST_PREPEND(links, ctx->links, link); + + return 0; + +failure: + free(link); + return r; +} + +static bool enable_name_policy(void) { + _cleanup_free_ char *line; + char *w, *state; + int r; + size_t l; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return true; + + FOREACH_WORD_QUOTED(w, l, line, state) + if (strneq(w, "net.ifnames=0", l)) + return false; + + return true; +} + +int link_config_load(link_config_ctx *ctx) { + int r; + char **files, **f; + + link_configs_free(ctx); + + if (!enable_name_policy()) { + ctx->enable_name_policy = false; + log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring."); + } + + /* update timestamp */ + paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true); + + r = conf_files_list_strv(&files, ".link", NULL, link_dirs); + if (r < 0) { + log_error("failed to enumerate link files: %s", strerror(-r)); + return r; + } + + STRV_FOREACH_BACKWARDS(f, files) { + r = load_link(ctx, *f); + if (r < 0) + return r; + } + + return 0; +} + +bool link_config_should_reload(link_config_ctx *ctx) { + return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false); +} + +int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) { + link_config *link; + + LIST_FOREACH(links, link, ctx->links) { + + if (net_match_config(link->match_mac, link->match_path, link->match_driver, + link->match_type, NULL, link->match_host, + link->match_virt, link->match_kernel, link->match_arch, + udev_device_get_sysattr_value(device, "address"), + udev_device_get_property_value(device, "ID_PATH"), + udev_device_get_driver(udev_device_get_parent(device)), + udev_device_get_property_value(device, "ID_NET_DRIVER"), + udev_device_get_devtype(device), + NULL)) { + log_debug("Config file %s applies to device %s", + link->filename, + udev_device_get_sysname(device)); + *ret = link; + return 0; + } + } + + *ret = NULL; + + return -ENOENT; +} + +static bool mac_is_random(struct udev_device *device) { + const char *s; + unsigned type; + int r; + + s = udev_device_get_sysattr_value(device, "addr_assign_type"); + if (!s) + return false; /* if we don't know, assume it is not random */ + r = safe_atou(s, &type); + if (r < 0) + return false; + + /* check for NET_ADDR_RANDOM */ + return type == 1; +} + +static bool mac_is_permanent(struct udev_device *device) { + const char *s; + unsigned type; + int r; + + s = udev_device_get_sysattr_value(device, "addr_assign_type"); + if (!s) + return true; /* if we don't know, assume it is permanent */ + r = safe_atou(s, &type); + if (r < 0) + return true; + + /* check for NET_ADDR_PERM */ + return type == 0; +} + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) + +static int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) { + int r; + + if (want_random) + random_bytes(mac->ether_addr_octet, ETH_ALEN); + else { + const char *name; + uint8_t result[8]; + size_t l, sz; + uint8_t *v; + + /* fetch some persistent data unique (on this machine) to this device */ + name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD"); + if (!name) { + name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT"); + if (!name) { + name = udev_device_get_property_value(device, "ID_NET_NAME_PATH"); + if (!name) + return -ENOENT; + } + } + + l = strlen(name); + sz = sizeof(sd_id128_t) + l; + v = alloca(sz); + + /* 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. */ + siphash24(result, v, sz, HASH_KEY.bytes); + + 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; +} + +int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device, const char **name) { + const char *old_name; + const char *new_name = NULL; + struct ether_addr generated_mac; + struct ether_addr *mac = NULL; + int r, ifindex; + + assert(ctx); + assert(config); + assert(device); + assert(name); + + r = link_config_ctx_connect(ctx); + if (r < 0) + return r; + + old_name = udev_device_get_sysname(device); + if (!old_name) + return -EINVAL; + + r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex); + if (r < 0) + log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s", + old_name, config->speed / 1024, duplex_to_string(config->duplex), + strerror(-r)); + + r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol); + if (r < 0) + log_warning("Could not set WakeOnLan of %s to %s: %s", + old_name, wol_to_string(config->wol), strerror(-r)); + + ifindex = udev_device_get_ifindex(device); + if (ifindex <= 0) { + log_warning("Could not find ifindex"); + return -ENODEV; + } + + if (ctx->enable_name_policy && config->name_policy) { + NamePolicy *policy; + + for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) { + switch (*policy) { + case NAMEPOLICY_DATABASE: + new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE"); + break; + case NAMEPOLICY_ONBOARD: + new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD"); + break; + case NAMEPOLICY_SLOT: + new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT"); + break; + case NAMEPOLICY_PATH: + new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH"); + break; + case NAMEPOLICY_MAC: + new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC"); + break; + default: + break; + } + } + } + + if (new_name) + *name = new_name; /* a name was set by a policy */ + else if (config->name) + *name = config->name; /* a name was set manually in the config */ + else + *name = NULL; + + switch (config->mac_policy) { + case MACPOLICY_PERSISTENT: + if (!mac_is_permanent(device)) { + r = get_mac(device, false, &generated_mac); + 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 < 0) + return r; + mac = &generated_mac; + } + break; + default: + mac = config->mac; + } + + r = rtnl_set_link_properties(ctx->rtnl, ifindex, config->alias, mac, config->mtu); + if (r < 0) { + log_warning("Could not set Alias, MACAddress or MTU on %s: %s", old_name, strerror(-r)); + return r; + } + + return 0; +} + +int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) { + const char *name; + char *driver; + int r; + + r = link_config_ctx_connect(ctx); + if (r < 0) + return r; + + name = udev_device_get_sysname(device); + if (!name) + return -EINVAL; + + r = ethtool_get_driver(ctx->ethtool_fd, name, &driver); + if (r < 0) + return r; + + *ret = driver; + return 0; +} + +static const char* const mac_policy_table[] = { + [MACPOLICY_PERSISTENT] = "persistent", + [MACPOLICY_RANDOM] = "random" +}; + +DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy); +DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, "Failed to parse MAC address policy"); + +static const char* const name_policy_table[] = { + [NAMEPOLICY_DATABASE] = "database", + [NAMEPOLICY_ONBOARD] = "onboard", + [NAMEPOLICY_SLOT] = "slot", + [NAMEPOLICY_PATH] = "path", + [NAMEPOLICY_MAC] = "mac" +}; + +DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy); +DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy, _NAMEPOLICY_INVALID, "Failed to parse interface name policy"); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h new file mode 100644 index 0000000..24fdb87 --- /dev/null +++ b/src/udev/net/link-config.h @@ -0,0 +1,98 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "ethtool-util.h" + +#include "condition-util.h" +#include "libudev.h" +#include "util.h" +#include "list.h" + +typedef struct link_config_ctx link_config_ctx; +typedef struct link_config link_config; + +typedef enum MACPolicy { + MACPOLICY_PERSISTENT, + MACPOLICY_RANDOM, + _MACPOLICY_MAX, + _MACPOLICY_INVALID = -1 +} MACPolicy; + +typedef enum NamePolicy { + NAMEPOLICY_DATABASE, + NAMEPOLICY_ONBOARD, + NAMEPOLICY_SLOT, + NAMEPOLICY_PATH, + NAMEPOLICY_MAC, + _NAMEPOLICY_MAX, + _NAMEPOLICY_INVALID = -1 +} NamePolicy; + +struct link_config { + char *filename; + + struct ether_addr *match_mac; + char *match_path; + char *match_driver; + char *match_type; + Condition *match_host; + Condition *match_virt; + Condition *match_kernel; + Condition *match_arch; + + char *description; + struct ether_addr *mac; + MACPolicy mac_policy; + NamePolicy *name_policy; + char *name; + char *alias; + unsigned int mtu; + unsigned int speed; + Duplex duplex; + WakeOnLan wol; + + LIST_FIELDS(link_config, links); +}; + +int link_config_ctx_new(link_config_ctx **ret); +void link_config_ctx_free(link_config_ctx *ctx); + +int link_config_load(link_config_ctx *ctx); +bool link_config_should_reload(link_config_ctx *ctx); + +int link_config_get(link_config_ctx *ctx, struct udev_device *device, struct link_config **ret); +int link_config_apply(link_config_ctx *ctx, struct link_config *config, struct udev_device *device, const char **name); + +int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret); + +const char *name_policy_to_string(NamePolicy p) _const_; +NamePolicy name_policy_from_string(const char *p) _pure_; + +const char *mac_policy_to_string(MACPolicy p) _const_; +MACPolicy mac_policy_from_string(const char *p) _pure_; + +/* gperf lookup function */ +const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, unsigned length); + +int config_parse_mac_policy(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_name_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/udev/scsi_id/.gitignore b/src/udev/scsi_id/.gitignore new file mode 100644 index 0000000..6aebddd --- /dev/null +++ b/src/udev/scsi_id/.gitignore @@ -0,0 +1 @@ +scsi_id_version.h diff --git a/src/udev/scsi_id/README b/src/udev/scsi_id/README new file mode 100644 index 0000000..9cfe739 --- /dev/null +++ b/src/udev/scsi_id/README @@ -0,0 +1,4 @@ +scsi_id - generate a SCSI unique identifier for a given SCSI device + +Please send questions, comments or patches to or +. diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h new file mode 100644 index 0000000..c423cac --- /dev/null +++ b/src/udev/scsi_id/scsi.h @@ -0,0 +1,97 @@ +/* + * scsi.h + * + * General scsi and linux scsi specific defines and structs. + * + * Copyright (C) IBM Corp. 2003 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#include + +struct scsi_ioctl_command { + unsigned int inlen; /* excluding scsi command length */ + unsigned int outlen; + unsigned char data[1]; + /* on input, scsi command starts here then opt. data */ +}; + +/* + * Default 5 second timeout + */ +#define DEF_TIMEOUT 5000 + +#define SENSE_BUFF_LEN 32 + +/* + * The request buffer size passed to the SCSI INQUIRY commands, use 254, + * as this is a nice value for some devices, especially some of the usb + * mass storage devices. + */ +#define SCSI_INQ_BUFF_LEN 254 + +/* + * SCSI INQUIRY vendor and model (really product) lengths. + */ +#define VENDOR_LENGTH 8 +#define MODEL_LENGTH 16 + +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 + +/* + * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the + * SCSI Primary Commands specification for details. + */ + +/* + * id type values of id descriptors. These are assumed to fit in 4 bits. + */ +#define SCSI_ID_VENDOR_SPECIFIC 0 +#define SCSI_ID_T10_VENDOR 1 +#define SCSI_ID_EUI_64 2 +#define SCSI_ID_NAA 3 +#define SCSI_ID_RELPORT 4 +#define SCSI_ID_TGTGROUP 5 +#define SCSI_ID_LUNGROUP 6 +#define SCSI_ID_MD5 7 +#define SCSI_ID_NAME 8 + +/* + * Supported NAA values. These fit in 4 bits, so the "don't care" value + * cannot conflict with real values. + */ +#define SCSI_ID_NAA_DONT_CARE 0xff +#define SCSI_ID_NAA_IEEE_REG 5 +#define SCSI_ID_NAA_IEEE_REG_EXTENDED 6 + +/* + * Supported Code Set values. + */ +#define SCSI_ID_BINARY 1 +#define SCSI_ID_ASCII 2 + +struct scsi_id_search_values { + u_char id_type; + u_char naa_type; + u_char code_set; +}; + +/* + * Following are the "true" SCSI status codes. Linux has traditionally + * used a 1 bit right and masked version of these. So now CHECK_CONDITION + * and friends (in ) are deprecated. + */ +#define SCSI_CHECK_CONDITION 0x2 +#define SCSI_CONDITION_MET 0x4 +#define SCSI_BUSY 0x8 +#define SCSI_IMMEDIATE 0x10 +#define SCSI_IMMEDIATE_CONDITION_MET 0x14 +#define SCSI_RESERVATION_CONFLICT 0x18 +#define SCSI_COMMAND_TERMINATED 0x22 +#define SCSI_TASK_SET_FULL 0x28 +#define SCSI_ACA_ACTIVE 0x30 +#define SCSI_TASK_ABORTED 0x40 diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c new file mode 100644 index 0000000..03bd3a9 --- /dev/null +++ b/src/udev/scsi_id/scsi_id.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) IBM Corp. 2003 + * Copyright (C) SUSE Linux Products GmbH, 2006 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "scsi_id.h" +#include "udev-util.h" + +static const struct option options[] = { + { "device", required_argument, NULL, 'd' }, + { "config", required_argument, NULL, 'f' }, + { "page", required_argument, NULL, 'p' }, + { "blacklisted", no_argument, NULL, 'b' }, + { "whitelisted", no_argument, NULL, 'g' }, + { "replace-whitespace", no_argument, NULL, 'u' }, + { "sg-version", required_argument, NULL, 's' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, /* don't advertise -V */ + { "export", no_argument, NULL, 'x' }, + { "help", no_argument, NULL, 'h' }, + {} +}; + +static bool all_good = false; +static bool dev_specified = false; +static char config_file[MAX_PATH_LEN] = "/etc/scsi_id.config"; +static enum page_code default_page_code = PAGE_UNSPECIFIED; +static int sg_version = 4; +static int debug = 0; +static bool reformat_serial = false; +static bool export = false; +static char vendor_str[64]; +static char model_str[64]; +static char vendor_enc_str[256]; +static char model_enc_str[256]; +static char revision_str[16]; +static char type_str[16]; + +_printf_(6,0) +static void log_fn(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + vsyslog(priority, format, args); +} + +static void set_type(const char *from, char *to, size_t len) +{ + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 0: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + type = "optical"; + break; + case 5: + type = "cd"; + break; + case 7: + type = "optical"; + break; + case 0xe: + type = "disk"; + break; + case 0xf: + type = "optical"; + break; + default: + break; + } + } + strscpy(to, len, type); +} + +/* + * get_value: + * + * buf points to an '=' followed by a quoted string ("foo") or a string ending + * with a space or ','. + * + * Return a pointer to the NUL terminated string, returns NULL if no + * matches. + */ +static char *get_value(char **buffer) +{ + static const char *quote_string = "\"\n"; + static const char *comma_string = ",\n"; + char *val; + const char *end; + + if (**buffer == '"') { + /* + * skip leading quote, terminate when quote seen + */ + (*buffer)++; + end = quote_string; + } else { + end = comma_string; + } + val = strsep(buffer, end); + if (val && end == quote_string) + /* + * skip trailing quote + */ + (*buffer)++; + + while (isspace(**buffer)) + (*buffer)++; + + return val; +} + +static int argc_count(char *opts) +{ + int i = 0; + while (*opts != '\0') + if (*opts++ == ' ') + i++; + return i; +} + +/* + * get_file_options: + * + * If vendor == NULL, find a line in the config file with only "OPTIONS="; + * if vendor and model are set find the first OPTIONS line in the config + * file that matches. Set argc and argv to match the OPTIONS string. + * + * vendor and model can end in '\n'. + */ +static int get_file_options(struct udev *udev, + const char *vendor, const char *model, + int *argc, char ***newargv) +{ + char *buffer; + _cleanup_fclose_ FILE *f; + char *buf; + char *str1; + char *vendor_in, *model_in, *options_in; /* read in from file */ + int lineno; + int c; + int retval = 0; + + f = fopen(config_file, "re"); + if (f == NULL) { + if (errno == ENOENT) + return 1; + else { + log_error("can't open %s: %m", config_file); + return -1; + } + } + + /* + * Allocate a buffer rather than put it on the stack so we can + * keep it around to parse any options (any allocated newargv + * points into this buffer for its strings). + */ + buffer = malloc(MAX_BUFFER_LEN); + if (!buffer) + return log_oom(); + + *newargv = NULL; + lineno = 0; + while (1) { + vendor_in = model_in = options_in = NULL; + + buf = fgets(buffer, MAX_BUFFER_LEN, f); + if (buf == NULL) + break; + lineno++; + if (buf[strlen(buffer) - 1] != '\n') { + log_error("Config file line %d too long", lineno); + break; + } + + while (isspace(*buf)) + buf++; + + /* blank or all whitespace line */ + if (*buf == '\0') + continue; + + /* comment line */ + if (*buf == '#') + continue; + + str1 = strsep(&buf, "="); + if (str1 && strcaseeq(str1, "VENDOR")) { + str1 = get_value(&buf); + if (!str1) { + retval = log_oom(); + break; + } + vendor_in = str1; + + str1 = strsep(&buf, "="); + if (str1 && strcaseeq(str1, "MODEL")) { + str1 = get_value(&buf); + if (!str1) { + retval = log_oom(); + break; + } + model_in = str1; + str1 = strsep(&buf, "="); + } + } + + if (str1 && strcaseeq(str1, "OPTIONS")) { + str1 = get_value(&buf); + if (!str1) { + retval = log_oom(); + break; + } + options_in = str1; + } + + /* + * Only allow: [vendor=foo[,model=bar]]options=stuff + */ + if (!options_in || (!vendor_in && model_in)) { + log_error("Error parsing config file line %d '%s'", lineno, buffer); + retval = -1; + break; + } + if (vendor == NULL) { + if (vendor_in == NULL) + break; + } else if (vendor_in && + strneq(vendor, vendor_in, strlen(vendor_in)) && + (!model_in || + (strneq(model, model_in, strlen(model_in))))) { + /* + * Matched vendor and optionally model. + * + * Note: a short vendor_in or model_in can + * give a partial match (that is FOO + * matches FOOBAR). + */ + break; + } + } + + if (retval == 0) { + if (vendor_in != NULL || model_in != NULL || + options_in != NULL) { + /* + * Something matched. Allocate newargv, and store + * values found in options_in. + */ + strcpy(buffer, options_in); + c = argc_count(buffer) + 2; + *newargv = calloc(c, sizeof(**newargv)); + if (!*newargv) { + retval = log_oom(); + } else { + *argc = c; + c = 0; + /* + * argv[0] at 0 is skipped by getopt, but + * store the buffer address there for + * later freeing + */ + (*newargv)[c] = buffer; + for (c = 1; c < *argc; c++) + (*newargv)[c] = strsep(&buffer, " \t"); + } + } else { + /* No matches */ + retval = 1; + } + } + if (retval != 0) + free(buffer); + return retval; +} + +static void help(void) { + printf("Usage: scsi_id [OPTION...] DEVICE\n" + " -d,--device= device node for SG_IO commands\n" + " -f,--config= location of config file\n" + " -p,--page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" + " -s,--sg-version=3|4 use SGv3 or SGv4\n" + " -b,--blacklisted threat device as blacklisted\n" + " -g,--whitelisted threat device as whitelisted\n" + " -u,--replace-whitespace replace all whitespace by underscores\n" + " -v,--verbose verbose logging\n" + " --version print version\n" + " -x,--export print values as environment keys\n" + " -h,--help print this help text\n\n"); + +} + +static int set_options(struct udev *udev, + int argc, char **argv, + char *maj_min_dev) +{ + int option; + + /* + * optind is a global extern used by getopt. Since we can call + * set_options twice (once for command line, and once for config + * file) we have to reset this back to 1. + */ + optind = 1; + while ((option = getopt_long(argc, argv, "d:f:gp:uvVxh", options, NULL)) >= 0) + switch (option) { + case 'b': + all_good = false; + break; + + case 'd': + dev_specified = true; + strscpy(maj_min_dev, MAX_PATH_LEN, optarg); + break; + + case 'f': + strscpy(config_file, MAX_PATH_LEN, optarg); + break; + + case 'g': + all_good = true; + break; + + case 'h': + help(); + exit(0); + + case 'p': + if (streq(optarg, "0x80")) + default_page_code = PAGE_80; + else if (streq(optarg, "0x83")) + default_page_code = PAGE_83; + else if (streq(optarg, "pre-spc3-83")) + default_page_code = PAGE_83_PRE_SPC3; + else { + log_error("Unknown page code '%s'", optarg); + return -1; + } + break; + + case 's': + sg_version = atoi(optarg); + if (sg_version < 3 || sg_version > 4) { + log_error("Unknown SG version '%s'", optarg); + return -1; + } + break; + + case 'u': + reformat_serial = true; + break; + + case 'v': + debug++; + break; + + case 'V': + printf("%s\n", VERSION); + exit(0); + break; + + case 'x': + export = true; + break; + + case '?': + return -1; + + default: + assert_not_reached("Unknown option"); + } + + if (optind < argc && !dev_specified) { + dev_specified = true; + strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]); + } + + return 0; +} + +static int per_dev_options(struct udev *udev, + struct scsi_id_device *dev_scsi, int *good_bad, int *page_code) +{ + int retval; + int newargc; + char **newargv = NULL; + int option; + + *good_bad = all_good; + *page_code = default_page_code; + + retval = get_file_options(udev, vendor_str, model_str, &newargc, &newargv); + + optind = 1; /* reset this global extern */ + while (retval == 0) { + option = getopt_long(newargc, newargv, "bgp:", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'b': + *good_bad = 0; + break; + + case 'g': + *good_bad = 1; + break; + + case 'p': + if (streq(optarg, "0x80")) { + *page_code = PAGE_80; + } else if (streq(optarg, "0x83")) { + *page_code = PAGE_83; + } else if (streq(optarg, "pre-spc3-83")) { + *page_code = PAGE_83_PRE_SPC3; + } else { + log_error("Unknown page code '%s'", optarg); + retval = -1; + } + break; + + default: + log_error("Unknown or bad option '%c' (0x%x)", option, option); + retval = -1; + break; + } + } + + if (newargv) { + free(newargv[0]); + free(newargv); + } + return retval; +} + +static int set_inq_values(struct udev *udev, struct scsi_id_device *dev_scsi, const char *path) +{ + int retval; + + dev_scsi->use_sg = sg_version; + + retval = scsi_std_inquiry(udev, dev_scsi, path); + if (retval) + return retval; + + udev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); + udev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); + + util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)); + util_replace_chars(vendor_str, NULL); + util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)); + util_replace_chars(model_str, NULL); + set_type(dev_scsi->type, type_str, sizeof(type_str)); + util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)); + util_replace_chars(revision_str, NULL); + return 0; +} + +/* + * scsi_id: try to get an id, if one is found, printf it to stdout. + * returns a value passed to exit() - 0 if printed an id, else 1. + */ +static int scsi_id(struct udev *udev, char *maj_min_dev) +{ + struct scsi_id_device dev_scsi = {}; + int good_dev; + int page_code; + int retval = 0; + + if (set_inq_values(udev, &dev_scsi, maj_min_dev) < 0) { + retval = 1; + goto out; + } + + /* get per device (vendor + model) options from the config file */ + per_dev_options(udev, &dev_scsi, &good_dev, &page_code); + if (!good_dev) { + retval = 1; + goto out; + } + + /* read serial number from mode pages (no values for optical drives) */ + scsi_get_serial(udev, &dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); + + if (export) { + char serial_str[MAX_SERIAL_LEN]; + + printf("ID_SCSI=1\n"); + printf("ID_VENDOR=%s\n", vendor_str); + printf("ID_VENDOR_ENC=%s\n", vendor_enc_str); + printf("ID_MODEL=%s\n", model_str); + printf("ID_MODEL_ENC=%s\n", model_enc_str); + printf("ID_REVISION=%s\n", revision_str); + printf("ID_TYPE=%s\n", type_str); + if (dev_scsi.serial[0] != '\0') { + util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); + util_replace_chars(serial_str, NULL); + printf("ID_SERIAL=%s\n", serial_str); + util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)); + util_replace_chars(serial_str, NULL); + printf("ID_SERIAL_SHORT=%s\n", serial_str); + } + if (dev_scsi.wwn[0] != '\0') { + printf("ID_WWN=0x%s\n", dev_scsi.wwn); + if (dev_scsi.wwn_vendor_extension[0] != '\0') { + printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension); + printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension); + } else { + printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn); + } + } + if (dev_scsi.tgpt_group[0] != '\0') { + printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group); + } + if (dev_scsi.unit_serial_number[0] != '\0') { + printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); + } + goto out; + } + + if (dev_scsi.serial[0] == '\0') { + retval = 1; + goto out; + } + + if (reformat_serial) { + char serial_str[MAX_SERIAL_LEN]; + + util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); + util_replace_chars(serial_str, NULL); + printf("%s\n", serial_str); + goto out; + } + + printf("%s\n", dev_scsi.serial); +out: + return retval; +} + +int main(int argc, char **argv) +{ + _cleanup_udev_unref_ struct udev *udev; + int retval = 0; + char maj_min_dev[MAX_PATH_LEN]; + int newargc; + char **newargv = NULL; + + udev = udev_new(); + if (udev == NULL) + goto exit; + + log_open(); + udev_set_log_fn(udev, log_fn); + + /* + * Get config file options. + */ + retval = get_file_options(udev, NULL, NULL, &newargc, &newargv); + if (retval < 0) { + retval = 1; + goto exit; + } + if (retval == 0) { + assert(newargv); + + if (set_options(udev, newargc, newargv, maj_min_dev) < 0) { + retval = 2; + goto exit; + } + } + + /* + * Get command line options (overriding any config file settings). + */ + if (set_options(udev, argc, argv, maj_min_dev) < 0) + exit(1); + + if (!dev_specified) { + log_error("no device specified"); + retval = 1; + goto exit; + } + + retval = scsi_id(udev, maj_min_dev); + +exit: + if (newargv) { + free(newargv[0]); + free(newargv); + } + log_close(); + return retval; +} diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h new file mode 100644 index 0000000..648b5ce --- /dev/null +++ b/src/udev/scsi_id/scsi_id.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) IBM Corp. 2003 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#define MAX_PATH_LEN 512 + +/* + * MAX_ATTR_LEN: maximum length of the result of reading a sysfs + * attribute. + */ +#define MAX_ATTR_LEN 256 + +/* + * MAX_SERIAL_LEN: the maximum length of the serial number, including + * added prefixes such as vendor and product (model) strings. + */ +#define MAX_SERIAL_LEN 256 + +/* + * MAX_BUFFER_LEN: maximum buffer size and line length used while reading + * the config file. + */ +#define MAX_BUFFER_LEN 256 + +struct scsi_id_device { + char vendor[9]; + char model[17]; + char revision[5]; + char type[33]; + char kernel[64]; + char serial[MAX_SERIAL_LEN]; + char serial_short[MAX_SERIAL_LEN]; + int use_sg; + + /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ + char unit_serial_number[MAX_SERIAL_LEN]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ + char wwn[17]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ + char wwn_vendor_extension[17]; + + /* NULs if not set - otherwise decimal number */ + char tgpt_group[8]; +}; + +int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname); +int scsi_get_serial(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len); + +/* + * Page code values. + */ +enum page_code { + PAGE_83_PRE_SPC3 = -0x83, + PAGE_UNSPECIFIED = 0x00, + PAGE_80 = 0x80, + PAGE_83 = 0x83, +}; diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c new file mode 100644 index 0000000..378a73d --- /dev/null +++ b/src/udev/scsi_id/scsi_serial.c @@ -0,0 +1,966 @@ +/* + * Copyright (C) IBM Corp. 2003 + * + * Author: Patrick Mansfield + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libudev.h" +#include "libudev-private.h" +#include "scsi.h" +#include "scsi_id.h" + +/* + * A priority based list of id, naa, and binary/ascii for the identifier + * descriptor in VPD page 0x83. + * + * Brute force search for a match starting with the first value in the + * following id_search_list. This is not a performance issue, since there + * is normally one or some small number of descriptors. + */ +static const struct scsi_id_search_values id_search_list[] = { + { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, + /* + * Devices already exist using NAA values that are now marked + * reserved. These should not conflict with other values, or it is + * a bug in the device. As long as we find the IEEE extended one + * first, we really don't care what other ones are used. Using + * don't care here means that a device that returns multiple + * non-IEEE descriptors in a random order will get different + * names. + */ + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, +}; + +static const char hex_str[]="0123456789abcdef"; + +/* + * Values returned in the result/status, only the ones used by the code + * are used here. + */ + +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ + +/* The following "category" function returns one of the following */ +#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ +#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ +#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ +#define SG_ERR_CAT_TIMEOUT 3 +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ +#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ + +static int do_scsi_page80_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int max_len); + +static int sg_err_category_new(struct udev *udev, + int scsi_status, int msg_status, int + host_status, int driver_status, const + unsigned char *sense_buffer, int sb_len) +{ + scsi_status &= 0x7e; + + /* + * XXX change to return only two values - failed or OK. + */ + + if (!scsi_status && !host_status && !driver_status) + return SG_ERR_CAT_CLEAN; + + if ((scsi_status == SCSI_CHECK_CONDITION) || + (scsi_status == SCSI_COMMAND_TERMINATED) || + ((driver_status & 0xf) == DRIVER_SENSE)) { + if (sense_buffer && (sb_len > 2)) { + int sense_key; + unsigned char asc; + + if (sense_buffer[0] & 0x2) { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + } else { + sense_key = sense_buffer[2] & 0xf; + asc = (sb_len > 12) ? sense_buffer[12] : 0; + } + + if (sense_key == RECOVERED_ERROR) + return SG_ERR_CAT_RECOVERED; + else if (sense_key == UNIT_ATTENTION) { + if (0x28 == asc) + return SG_ERR_CAT_MEDIA_CHANGED; + if (0x29 == asc) + return SG_ERR_CAT_RESET; + } else if (sense_key == ILLEGAL_REQUEST) { + return SG_ERR_CAT_NOTSUPPORTED; + } + } + return SG_ERR_CAT_SENSE; + } + if (host_status) { + if ((host_status == DID_NO_CONNECT) || + (host_status == DID_BUS_BUSY) || + (host_status == DID_TIME_OUT)) + return SG_ERR_CAT_TIMEOUT; + } + if (driver_status) { + if (driver_status == DRIVER_TIMEOUT) + return SG_ERR_CAT_TIMEOUT; + } + return SG_ERR_CAT_OTHER; +} + +static int sg_err_category3(struct udev *udev, struct sg_io_hdr *hp) +{ + return sg_err_category_new(udev, + hp->status, hp->msg_status, + hp->host_status, hp->driver_status, + hp->sbp, hp->sb_len_wr); +} + +static int sg_err_category4(struct udev *udev, struct sg_io_v4 *hp) +{ + return sg_err_category_new(udev, hp->device_status, 0, + hp->transport_status, hp->driver_status, + (unsigned char *)(uintptr_t)hp->response, + hp->response_len); +} + +static int scsi_dump_sense(struct udev *udev, + struct scsi_id_device *dev_scsi, + unsigned char *sense_buffer, int sb_len) +{ + int s; + int code; + int sense_class; + int sense_key; + int asc, ascq; +#ifdef DUMP_SENSE + char out_buffer[256]; + int i, j; +#endif + + /* + * Figure out and print the sense key, asc and ascq. + * + * If you want to suppress these for a particular drive model, add + * a black list entry in the scsi_id config file. + * + * XXX We probably need to: lookup the sense/asc/ascq in a retry + * table, and if found return 1 (after dumping the sense, asc, and + * ascq). So, if/when we get something like a power on/reset, + * we'll retry the command. + */ + + if (sb_len < 1) { + log_debug("%s: sense buffer empty", dev_scsi->kernel); + return -1; + } + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + + if (sense_class == 7) { + /* + * extended sense data. + */ + s = sense_buffer[7] + 8; + if (sb_len < s) { + log_debug("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, s - sb_len); + return -1; + } + if ((code == 0x0) || (code == 0x1)) { + sense_key = sense_buffer[2] & 0xf; + if (s < 14) { + /* + * Possible? + */ + log_debug("%s: sense result too" " small %d bytes", + dev_scsi->kernel, s); + return -1; + } + asc = sense_buffer[12]; + ascq = sense_buffer[13]; + } else if ((code == 0x2) || (code == 0x3)) { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + ascq = sense_buffer[3]; + } else { + log_debug("%s: invalid sense code 0x%x", + dev_scsi->kernel, code); + return -1; + } + log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", + dev_scsi->kernel, sense_key, asc, ascq); + } else { + if (sb_len < 4) { + log_debug("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, 4 - sb_len); + return -1; + } + + if (sense_buffer[0] < 15) + log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f); + else + log_debug("%s: sense = %2x %2x", + dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); + log_debug("%s: non-extended sense class %d code 0x%0x", + dev_scsi->kernel, sense_class, code); + + } + +#ifdef DUMP_SENSE + for (i = 0, j = 0; (i < s) && (j < 254); i++) { + out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; + out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; + out_buffer[j++] = ' '; + } + out_buffer[j] = '\0'; + log_debug("%s: sense dump:", dev_scsi->kernel); + log_debug("%s: %s", dev_scsi->kernel, out_buffer); + +#endif + return -1; +} + +static int scsi_dump(struct udev *udev, + struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) +{ + if (!io->status && !io->host_status && !io->msg_status && + !io->driver_status) { + /* + * Impossible, should not be called. + */ + log_debug("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", + dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); + if (io->status == SCSI_CHECK_CONDITION) + return scsi_dump_sense(udev, dev_scsi, io->sbp, io->sb_len_wr); + else + return -1; +} + +static int scsi_dump_v4(struct udev *udev, + struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) +{ + if (!io->device_status && !io->transport_status && + !io->driver_status) { + /* + * Impossible, should not be called. + */ + log_debug("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", + dev_scsi->kernel, io->driver_status, io->transport_status, + io->device_status); + if (io->device_status == SCSI_CHECK_CONDITION) + return scsi_dump_sense(udev, dev_scsi, (unsigned char *)(uintptr_t)io->response, + io->response_len); + else + return -1; +} + +static int scsi_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + unsigned char evpd, unsigned char page, + unsigned char *buf, unsigned int buflen) +{ + unsigned char inq_cmd[INQUIRY_CMDLEN] = + { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; + unsigned char sense[SENSE_BUFF_LEN]; + void *io_buf; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int retry = 3; /* rather random */ + int retval; + + if (buflen > SCSI_INQ_BUFF_LEN) { + log_debug("buflen %d too long", buflen); + return -1; + } + +resend: + if (dev_scsi->use_sg == 4) { + memzero(&io_v4, sizeof(struct sg_io_v4)); + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof(inq_cmd); + io_v4.request = (uintptr_t)inq_cmd; + io_v4.max_response_len = sizeof(sense); + io_v4.response = (uintptr_t)sense; + io_v4.din_xfer_len = buflen; + io_v4.din_xferp = (uintptr_t)buf; + io_buf = (void *)&io_v4; + } else { + memzero(&io_hdr, sizeof(struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inq_cmd); + io_hdr.mx_sb_len = sizeof(sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = buflen; + io_hdr.dxferp = buf; + io_hdr.cmdp = inq_cmd; + io_hdr.sbp = sense; + io_hdr.timeout = DEF_TIMEOUT; + io_buf = (void *)&io_hdr; + } + + retval = ioctl(fd, SG_IO, io_buf); + if (retval < 0) { + if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) { + dev_scsi->use_sg = 3; + goto resend; + } + log_debug("%s: ioctl failed: %m", dev_scsi->kernel); + goto error; + } + + if (dev_scsi->use_sg == 4) + retval = sg_err_category4(udev, io_buf); + else + retval = sg_err_category3(udev, io_buf); + + switch (retval) { + case SG_ERR_CAT_NOTSUPPORTED: + buf[1] = 0; + /* Fallthrough */ + case SG_ERR_CAT_CLEAN: + case SG_ERR_CAT_RECOVERED: + retval = 0; + break; + + default: + if (dev_scsi->use_sg == 4) + retval = scsi_dump_v4(udev, dev_scsi, io_buf); + else + retval = scsi_dump(udev, dev_scsi, io_buf); + } + + if (!retval) { + retval = buflen; + } else if (retval > 0) { + if (--retry > 0) + goto resend; + retval = -1; + } + +error: + if (retval < 0) + log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", + dev_scsi->kernel, evpd, page); + + return retval; +} + +/* Get list of supported EVPD pages */ +static int do_scsi_page0_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + unsigned char *buffer, unsigned int len) +{ + int retval; + + memzero(buffer, len); + retval = scsi_inquiry(udev, dev_scsi, fd, 1, 0x0, buffer, len); + if (retval < 0) + return 1; + + if (buffer[1] != 0) { + log_debug("%s: page 0 not available.", dev_scsi->kernel); + return 1; + } + if (buffer[3] > len) { + log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]); + return 1; + } + + /* + * Following check is based on code once included in the 2.5.x + * kernel. + * + * Some ill behaved devices return the standard inquiry here + * rather than the evpd data, snoop the data to verify. + */ + if (buffer[3] > MODEL_LENGTH) { + /* + * If the vendor id appears in the page assume the page is + * invalid. + */ + if (strneq((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) { + log_debug("%s: invalid page0 data", dev_scsi->kernel); + return 1; + } + } + return 0; +} + +/* + * The caller checks that serial is long enough to include the vendor + + * model. + */ +static int prepend_vendor_model(struct udev *udev, + struct scsi_id_device *dev_scsi, char *serial) +{ + int ind; + + strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH); + strncat(serial, dev_scsi->model, MODEL_LENGTH); + ind = strlen(serial); + + /* + * This is not a complete check, since we are using strncat/cpy + * above, ind will never be too large. + */ + if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { + log_debug("%s: expected length %d, got length %d", + dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); + return -1; + } + return ind; +} + +/* + * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill + * serial number. + */ +static int check_fill_0x83_id(struct udev *udev, + struct scsi_id_device *dev_scsi, + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, + int max_len, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) +{ + int i, j, s, len; + + /* + * ASSOCIATION must be with the device (value 0) + * or with the target port for SCSI_ID_TGTPORT + */ + if ((page_83[1] & 0x30) == 0x10) { + if (id_search->id_type != SCSI_ID_TGTGROUP) + return 1; + } else if ((page_83[1] & 0x30) != 0) { + return 1; + } + + if ((page_83[1] & 0x0f) != id_search->id_type) + return 1; + + /* + * Possibly check NAA sub-type. + */ + if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) && + (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) + return 1; + + /* + * Check for matching code set - ASCII or BINARY. + */ + if ((page_83[0] & 0x0f) != id_search->code_set) + return 1; + + /* + * page_83[3]: identifier length + */ + len = page_83[3]; + if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) + /* + * If not ASCII, use two bytes for each binary value. + */ + len *= 2; + + /* + * Add one byte for the NUL termination, and one for the id_type. + */ + len += 2; + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) + len += VENDOR_LENGTH + MODEL_LENGTH; + + if (max_len < len) { + log_debug("%s: length %d too short - need %d", + dev_scsi->kernel, max_len, len); + return 1; + } + + if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { + unsigned int group; + + group = ((unsigned int)page_83[6] << 8) | page_83[7]; + sprintf(tgpt_group,"%x", group); + return 1; + } + + serial[0] = hex_str[id_search->id_type]; + + /* + * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before + * the id since it is not unique across all vendors and models, + * this differs from SCSI_ID_T10_VENDOR, where the vendor is + * included in the identifier. + */ + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) + if (prepend_vendor_model(udev, dev_scsi, &serial[1]) < 0) + return 1; + + i = 4; /* offset to the start of the identifier */ + s = j = strlen(serial); + if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { + /* + * ASCII descriptor. + */ + while (i < (4 + page_83[3])) + serial[j++] = page_83[i++]; + } else { + /* + * Binary descriptor, convert to ASCII, using two bytes of + * ASCII for each byte in the page_83. + */ + while (i < (4 + page_83[3])) { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + } + + strcpy(serial_short, &serial[s]); + + if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { + strncpy(wwn, &serial[s], 16); + if (wwn_vendor_extension != NULL) { + strncpy(wwn_vendor_extension, &serial[s + 16], 16); + } + } + + return 0; +} + +/* Extract the raw binary from VPD 0x83 pre-SPC devices */ +static int check_fill_0x83_prespc3(struct udev *udev, + struct scsi_id_device *dev_scsi, + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, int max_len) +{ + int i, j; + + serial[0] = hex_str[id_search->id_type]; + /* serial has been memset to zero before */ + j = strlen(serial); /* j = 1; */ + + for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) { + serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4]; + serial[j++] = hex_str[ page_83[4+i] & 0x0f]; + } + serial[max_len-1] = 0; + strncpy(serial_short, serial, max_len-1); + return 0; +} + + +/* Get device identification VPD page */ +static int do_scsi_page83_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int len, + char *unit_serial_number, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) +{ + int retval; + unsigned int id_ind, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + /* also pick up the page 80 serial number */ + do_scsi_page80_inquiry(udev, dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN); + + memzero(page_83, SCSI_INQ_BUFF_LEN); + retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, + SCSI_INQ_BUFF_LEN); + if (retval < 0) + return 1; + + if (page_83[1] != PAGE_83) { + log_debug("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + + /* + * XXX Some devices (IBM 3542) return all spaces for an identifier if + * the LUN is not actually configured. This leads to identifiers of + * the form: "1 ". + */ + + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + + if (page_83[6] != 0) + return check_fill_0x83_prespc3(udev, + dev_scsi, page_83, id_search_list, + serial, serial_short, len); + + /* + * Search for a match in the prioritized id_search_list - since WWN ids + * come first we can pick up the WWN in check_fill_0x83_id(). + */ + for (id_ind = 0; + id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]); + id_ind++) { + /* + * Examine each descriptor returned. There is normally only + * one or a small number of descriptors. + */ + for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) { + retval = check_fill_0x83_id(udev, + dev_scsi, &page_83[j], + &id_search_list[id_ind], + serial, serial_short, len, + wwn, wwn_vendor_extension, + tgpt_group); + if (!retval) + return retval; + else if (retval < 0) + return retval; + } + } + return 1; +} + +/* + * Get device identification VPD page for older SCSI-2 device which is not + * compliant with either SPC-2 or SPC-3 format. + * + * Return the hard coded error code value 2 if the page 83 reply is not + * conformant to the SCSI-2 format. + */ +static int do_scsi_page83_prespc3_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int len) +{ + int retval; + int i, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + memzero(page_83, SCSI_INQ_BUFF_LEN); + retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); + if (retval < 0) + return 1; + + if (page_83[1] != PAGE_83) { + log_debug("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + if (page_83[6] == 0) + return 2; + + serial[0] = hex_str[id_search_list[0].id_type]; + /* + * The first four bytes contain data, not a descriptor. + */ + i = 4; + j = strlen(serial); + /* + * Binary descriptor, convert to ASCII, + * using two bytes of ASCII for each byte + * in the page_83. + */ + while (i < (page_83[3]+4)) { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + return 0; +} + +/* Get unit serial number VPD page */ +static int do_scsi_page80_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int max_len) +{ + int retval; + int ser_ind; + int i; + int len; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + + memzero(buf, SCSI_INQ_BUFF_LEN); + retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); + if (retval < 0) + return retval; + + if (buf[1] != PAGE_80) { + log_debug("%s: Invalid page 0x80", dev_scsi->kernel); + return 1; + } + + len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; + if (max_len < len) { + log_debug("%s: length %d too short - need %d", + dev_scsi->kernel, max_len, len); + return 1; + } + /* + * Prepend 'S' to avoid unlikely collision with page 0x83 vendor + * specific type where we prepend '0' + vendor + model. + */ + len = buf[3]; + if (serial != NULL) { + serial[0] = 'S'; + ser_ind = prepend_vendor_model(udev, dev_scsi, &serial[1]); + if (ser_ind < 0) + return 1; + ser_ind++; /* for the leading 'S' */ + for (i = 4; i < len + 4; i++, ser_ind++) + serial[ser_ind] = buf[i]; + } + if (serial_short != NULL) { + memcpy(serial_short, &buf[4], len); + serial_short[len] = '\0'; + } + return 0; +} + +int scsi_std_inquiry(struct udev *udev, + struct scsi_id_device *dev_scsi, const char *devname) +{ + int fd; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + struct stat statbuf; + int err = 0; + + fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + log_debug("scsi_id: cannot open %s: %m", devname); + return 1; + } + + if (fstat(fd, &statbuf) < 0) { + log_debug("scsi_id: cannot stat %s: %m", devname); + err = 2; + goto out; + } + sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev), + minor(statbuf.st_rdev)); + + memzero(buf, SCSI_INQ_BUFF_LEN); + err = scsi_inquiry(udev, dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); + if (err < 0) + goto out; + + err = 0; + memcpy(dev_scsi->vendor, buf + 8, 8); + dev_scsi->vendor[8] = '\0'; + memcpy(dev_scsi->model, buf + 16, 16); + dev_scsi->model[16] = '\0'; + memcpy(dev_scsi->revision, buf + 32, 4); + dev_scsi->revision[4] = '\0'; + sprintf(dev_scsi->type,"%x", buf[0] & 0x1f); + +out: + close(fd); + return err; +} + +int scsi_get_serial(struct udev *udev, + struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len) +{ + unsigned char page0[SCSI_INQ_BUFF_LEN]; + int fd = -1; + int cnt; + int ind; + int retval; + + memzero(dev_scsi->serial, len); + srand((unsigned int)getpid()); + for (cnt = 20; cnt > 0; cnt--) { + struct timespec duration; + + fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd >= 0 || errno != EBUSY) + break; + duration.tv_sec = 0; + duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); + nanosleep(&duration, NULL); + } + if (fd < 0) + return 1; + + if (page_code == PAGE_80) { + if (do_scsi_page80_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } else if (page_code == PAGE_83) { + if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } else if (page_code == PAGE_83_PRE_SPC3) { + retval = do_scsi_page83_prespc3_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len); + if (retval) { + /* + * Fallback to servicing a SPC-2/3 compliant page 83 + * inquiry if the page 83 reply format does not + * conform to pre-SPC3 expectations. + */ + if (retval == 2) { + if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } + else { + retval = 1; + goto completed; + } + } else { + retval = 0; + goto completed; + } + } else if (page_code != 0x00) { + log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code); + retval = 1; + goto completed; + } + + /* + * Get page 0, the page of the pages. By default, try from best to + * worst of supported pages: 0x83 then 0x80. + */ + if (do_scsi_page0_inquiry(udev, dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { + /* + * Don't try anything else. Black list if a specific page + * should be used for this vendor+model, or maybe have an + * optional fall-back to page 0x80 or page 0x83. + */ + retval = 1; + goto completed; + } + + for (ind = 4; ind <= page0[3] + 3; ind++) + if (page0[ind] == PAGE_83) + if (!do_scsi_page83_inquiry(udev, dev_scsi, fd, + dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { + /* + * Success + */ + retval = 0; + goto completed; + } + + for (ind = 4; ind <= page0[3] + 3; ind++) + if (page0[ind] == PAGE_80) + if (!do_scsi_page80_inquiry(udev, dev_scsi, fd, + dev_scsi->serial, dev_scsi->serial_short, len)) { + /* + * Success + */ + retval = 0; + goto completed; + } + retval = 1; + +completed: + close(fd); + return retval; +} diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c new file mode 100644 index 0000000..c806bd6 --- /dev/null +++ b/src/udev/udev-builtin-blkid.c @@ -0,0 +1,223 @@ +/* + * probe disks for filesystems and partitions + * + * Copyright (C) 2011 Kay Sievers + * Copyright (C) 2011 Karel Zak + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) +{ + char s[265]; + + s[0] = '\0'; + + if (streq(name, "TYPE")) { + udev_builtin_add_property(dev, test, "ID_FS_TYPE", value); + + } else if (streq(name, "USAGE")) { + udev_builtin_add_property(dev, test, "ID_FS_USAGE", value); + + } else if (streq(name, "VERSION")) { + udev_builtin_add_property(dev, test, "ID_FS_VERSION", value); + + } else if (streq(name, "UUID")) { + blkid_safe_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_UUID", s); + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s); + + } else if (streq(name, "UUID_SUB")) { + blkid_safe_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s); + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s); + + } else if (streq(name, "LABEL")) { + blkid_safe_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_LABEL", s); + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s); + + } else if (streq(name, "PTTYPE")) { + udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value); + + } else if (streq(name, "PTUUID")) { + udev_builtin_add_property(dev, test, "ID_PART_TABLE_UUID", value); + + } else if (streq(name, "PART_ENTRY_NAME")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s); + + } else if (streq(name, "PART_ENTRY_TYPE")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s); + + } else if (startswith(name, "PART_ENTRY_")) { + strscpyl(s, sizeof(s), "ID_", name, NULL); + udev_builtin_add_property(dev, test, s, value); + + } else if (streq(name, "SYSTEM_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_SYSTEM_ID", s); + + } else if (streq(name, "PUBLISHER_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_PUBLISHER_ID", s); + + } else if (streq(name, "APPLICATION_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_APPLICATION_ID", s); + + } else if (streq(name, "BOOT_SYSTEM_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s); + } +} + +static int probe_superblocks(blkid_probe pr) +{ + struct stat st; + int rc; + + if (fstat(blkid_probe_get_fd(pr), &st)) + return -1; + + blkid_probe_enable_partitions(pr, 1); + + if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440 && + blkid_probe_is_wholedisk(pr)) { + /* + * check if the small disk is partitioned, if yes then + * don't probe for filesystems. + */ + blkid_probe_enable_superblocks(pr, 0); + + rc = blkid_do_fullprobe(pr); + if (rc < 0) + return rc; /* -1 = error, 1 = nothing, 0 = succes */ + + if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) + return 0; /* partition table detected */ + } + + blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); + blkid_probe_enable_superblocks(pr, 1); + + return blkid_do_safeprobe(pr); +} + +static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool test) +{ + int64_t offset = 0; + bool noraid = false; + int fd = -1; + blkid_probe pr; + const char *data; + const char *name; + int nvals; + int i; + size_t len; + int err = 0; + + static const struct option options[] = { + { "offset", optional_argument, NULL, 'o' }, + { "noraid", no_argument, NULL, 'R' }, + {} + }; + + for (;;) { + int option; + + option = getopt_long(argc, argv, "oR", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'o': + offset = strtoull(optarg, NULL, 0); + break; + case 'R': + noraid = true; + break; + } + } + + pr = blkid_new_probe(); + if (!pr) + return EXIT_FAILURE; + + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | + BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); + + if (noraid) + blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID); + + fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "error: %s: %m\n", udev_device_get_devnode(dev)); + goto out; + } + + err = blkid_probe_set_device(pr, fd, offset, 0); + if (err < 0) + goto out; + + log_debug("probe %s %sraid offset=%llu", + udev_device_get_devnode(dev), + noraid ? "no" : "", (unsigned long long) offset); + + err = probe_superblocks(pr); + if (err < 0) + goto out; + + nvals = blkid_probe_numof_values(pr); + for (i = 0; i < nvals; i++) { + if (blkid_probe_get_value(pr, i, &name, &data, &len)) + continue; + len = strnlen((char *) data, len); + print_property(dev, test, name, (char *) data); + } + + blkid_free_probe(pr); +out: + if (fd > 0) + close(fd); + if (err < 0) + return EXIT_FAILURE; + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_blkid = { + .name = "blkid", + .cmd = builtin_blkid, + .help = "filesystem and partition probing", + .run_once = true, +}; diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c new file mode 100644 index 0000000..2baafe6 --- /dev/null +++ b/src/udev/udev-builtin-btrfs.c @@ -0,0 +1,64 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +#define BTRFS_PATH_NAME_MAX 4087 +struct btrfs_ioctl_vol_args { + int64_t fd; + char name[BTRFS_PATH_NAME_MAX + 1]; +}; +#define BTRFS_IOCTL_MAGIC 0x94 +#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, struct btrfs_ioctl_vol_args) + +static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) +{ + struct btrfs_ioctl_vol_args args; + _cleanup_close_ int fd = -1; + int err; + + if (argc != 3 || !streq(argv[1], "ready")) + return EXIT_FAILURE; + + fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); + if (fd < 0) + return EXIT_FAILURE; + + strscpy(args.name, sizeof(args.name), argv[2]); + err = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); + if (err < 0) + return EXIT_FAILURE; + + udev_builtin_add_property(dev, test, "ID_BTRFS_READY", err == 0 ? "1" : "0"); + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_btrfs = { + .name = "btrfs", + .cmd = builtin_btrfs, + .help = "btrfs volume management", +}; diff --git a/src/udev/udev-builtin-firmware.c b/src/udev/udev-builtin-firmware.c new file mode 100644 index 0000000..0ca54a8 --- /dev/null +++ b/src/udev/udev-builtin-firmware.c @@ -0,0 +1,198 @@ +/* + * firmware - Kernel firmware loader + * + * Copyright (C) 2009 Piter Punk + * Copyright (C) 2009-2011 Kay Sievers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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:* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static bool set_loading(struct udev *udev, char *loadpath, const char *state) +{ + FILE *ldfile; + + ldfile = fopen(loadpath, "we"); + if (ldfile == NULL) { + log_error("error: can not open '%s'", loadpath); + return false; + }; + fprintf(ldfile, "%s\n", state); + fclose(ldfile); + return true; +} + +static bool copy_firmware(struct udev *udev, const char *source, const char *target, size_t size) +{ + char *buf; + FILE *fsource = NULL, *ftarget = NULL; + bool ret = false; + + buf = malloc(size); + if (buf == NULL) { + log_error("No memory available to load firmware file"); + return false; + } + + log_debug("writing '%s' (%zi) to '%s'", source, size, target); + + fsource = fopen(source, "re"); + if (fsource == NULL) + goto exit; + ftarget = fopen(target, "we"); + if (ftarget == NULL) + goto exit; + if (fread(buf, size, 1, fsource) != 1) + goto exit; + if (fwrite(buf, size, 1, ftarget) == 1) + ret = true; +exit: + if (ftarget != NULL) + fclose(ftarget); + if (fsource != NULL) + fclose(fsource); + free(buf); + return ret; +} + +#ifdef CONFIG_TIZEN +static FILE* find_firmware(const char *path, const char *fwpath, const char *firmware) +{ + char searchpath[UTIL_PATH_SIZE]; + FILE *fwfile = NULL; + DIR *srcdir; + struct dirent *dent; + struct stat statbuf; + + srcdir = opendir(path); + while ((dent = readdir(srcdir)) != NULL) { + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) + continue; + if (fstatat(dirfd(srcdir), dent->d_name, &statbuf, 0) < 0) + continue; + if (S_ISDIR(statbuf.st_mode)) { + strscpyl(fwpath, UTIL_PATH_SIZE, path, dent->d_name, "/", firmware, NULL); + fwfile = fopen(fwpath, "re"); + if (fwfile == NULL) { + strscpyl(searchpath, UTIL_PATH_SIZE, path, dent->d_name, "/", NULL); + fwfile = find_firmware(searchpath, fwpath, firmware); + } + if (fwfile != NULL) + return fwfile; + } + } + return NULL; +} +#endif + +static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test) +{ + struct udev *udev = udev_device_get_udev(dev); + static const char *searchpath[] = { FIRMWARE_PATH }; + char loadpath[UTIL_PATH_SIZE]; + char datapath[UTIL_PATH_SIZE]; + char fwpath[UTIL_PATH_SIZE]; + const char *firmware; + FILE *fwfile = NULL; + struct utsname kernel; + struct stat statbuf; + unsigned int i; + int rc = EXIT_SUCCESS; + + firmware = udev_device_get_property_value(dev, "FIRMWARE"); + if (firmware == NULL) { + log_error("firmware parameter missing"); + rc = EXIT_FAILURE; + goto exit; + } + + /* lookup firmware file */ + uname(&kernel); + for (i = 0; i < ELEMENTSOF(searchpath); i++) { + strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL); + fwfile = fopen(fwpath, "re"); + if (fwfile != NULL) + break; + + strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL); + fwfile = fopen(fwpath, "re"); + if (fwfile != NULL) + break; + } + +#ifdef CONFIG_TIZEN + /* If not found, try to find firmware in sub-directories. */ + if (fwfile == NULL) { + for (i = 0; i < ELEMENTSOF(searchpath); i++) { + fwfile = find_firmware(searchpath[i], fwpath, firmware); + if (fwfile != NULL) + break; + } + } +#endif + + strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL); + + if (fwfile == NULL) { + log_debug("did not find firmware file '%s'", firmware); + rc = EXIT_FAILURE; + /* + * Do not cancel the request in the initrd, the real root might have + * the firmware file and the 'coldplug' run in the real root will find + * this pending request and fulfill or cancel it. + * */ + if (!in_initrd()) + set_loading(udev, loadpath, "-1"); + goto exit; + } + + if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) { + if (!in_initrd()) + set_loading(udev, loadpath, "-1"); + rc = EXIT_FAILURE; + goto exit; + } + + if (!set_loading(udev, loadpath, "1")) + goto exit; + + strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL); + if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) { + log_error("error sending firmware '%s' to device", firmware); + set_loading(udev, loadpath, "-1"); + rc = EXIT_FAILURE; + goto exit; + }; + + set_loading(udev, loadpath, "0"); +exit: + if (fwfile) + fclose(fwfile); + return rc; +} + +const struct udev_builtin udev_builtin_firmware = { + .name = "firmware", + .cmd = builtin_firmware, + .help = "kernel firmware loader", + .run_once = true, +}; diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c new file mode 100644 index 0000000..d6aa96b --- /dev/null +++ b/src/udev/udev-builtin-hwdb.c @@ -0,0 +1,215 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static struct udev_hwdb *hwdb; + +int udev_builtin_hwdb_lookup(struct udev_device *dev, + const char *prefix, const char *modalias, + const char *filter, bool test) { + struct udev_list_entry *list; + struct udev_list_entry *entry; + int n = 0; + + if (!hwdb) + return -ENOENT; + + if (prefix) { + _cleanup_free_ const char *lookup; + + lookup = strjoin(prefix, modalias, NULL); + if (!lookup) + return -ENOMEM; + list = udev_hwdb_get_properties_list_entry(hwdb, lookup, 0); + } else + list = udev_hwdb_get_properties_list_entry(hwdb, modalias, 0); + + udev_list_entry_foreach(entry, list) { + if (filter && fnmatch(filter, udev_list_entry_get_name(entry), FNM_NOESCAPE) != 0) + continue; + + if (udev_builtin_add_property(dev, test, + udev_list_entry_get_name(entry), + udev_list_entry_get_value(entry)) < 0) + return -ENOMEM; + n++; + } + return n; +} + +static const char *modalias_usb(struct udev_device *dev, char *s, size_t size) { + const char *v, *p; + int vn, pn; + + v = udev_device_get_sysattr_value(dev, "idVendor"); + if (!v) + return NULL; + p = udev_device_get_sysattr_value(dev, "idProduct"); + if (!p) + return NULL; + vn = strtol(v, NULL, 16); + if (vn <= 0) + return NULL; + pn = strtol(p, NULL, 16); + if (pn <= 0) + return NULL; + snprintf(s, size, "usb:v%04Xp%04X*", vn, pn); + return s; +} + +static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device *srcdev, + const char *subsystem, const char *prefix, + const char *filter, bool test) { + struct udev_device *d; + char s[16]; + int n = 0; + + for (d = srcdev; d; d = udev_device_get_parent(d)) { + const char *dsubsys; + const char *modalias = NULL; + + dsubsys = udev_device_get_subsystem(d); + if (!dsubsys) + continue; + + /* look only at devices of a specific subsystem */ + if (subsystem && !streq(dsubsys, subsystem)) + continue; + + modalias = udev_device_get_property_value(d, "MODALIAS"); + + /* the usb_device does not have a modalias, compose one */ + if (!modalias && streq(dsubsys, "usb")) + modalias = modalias_usb(d, s, sizeof(s)); + + if (!modalias) + continue; + + n = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test); + if (n > 0) + break; + } + + return n; +} + +static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) { + static const struct option options[] = { + { "filter", required_argument, NULL, 'f' }, + { "device", required_argument, NULL, 'd' }, + { "subsystem", required_argument, NULL, 's' }, + { "lookup-prefix", required_argument, NULL, 'p' }, + {} + }; + const char *filter = NULL; + const char *device = NULL; + const char *subsystem = NULL; + const char *prefix = NULL; + struct udev_device *srcdev; + + if (!hwdb) + return EXIT_FAILURE; + + for (;;) { + int option; + + option = getopt_long(argc, argv, "f:d:s:p:", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'f': + filter = optarg; + break; + + case 'd': + device = optarg; + break; + + case 's': + subsystem = optarg; + break; + + case 'p': + prefix = optarg; + break; + } + } + + /* query a specific key given as argument */ + if (argv[optind]) { + if (udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test) > 0) + return EXIT_SUCCESS; + return EXIT_FAILURE; + } + + /* read data from another device than the device we will store the data */ + if (device) { + srcdev = udev_device_new_from_device_id(udev_device_get_udev(dev), device); + if (!srcdev) + return EXIT_FAILURE; + } else + srcdev = dev; + + if (udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test) > 0) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} + +/* called at udev startup and reload */ +static int builtin_hwdb_init(struct udev *udev) +{ + if (hwdb) + return 0; + hwdb = udev_hwdb_new(udev); + if (!hwdb) + return -ENOMEM; + return 0; +} + +/* called on udev shutdown and reload request */ +static void builtin_hwdb_exit(struct udev *udev) +{ + hwdb = udev_hwdb_unref(hwdb); +} + +/* called every couple of seconds during event activity; 'true' if config has changed */ +static bool builtin_hwdb_validate(struct udev *udev) +{ + return udev_hwdb_validate(hwdb); +} + +const struct udev_builtin udev_builtin_hwdb = { + .name = "hwdb", + .cmd = builtin_hwdb, + .init = builtin_hwdb_init, + .exit = builtin_hwdb_exit, + .validate = builtin_hwdb_validate, + .help = "hardware database", +}; diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c new file mode 100644 index 0000000..828b349 --- /dev/null +++ b/src/udev/udev-builtin-input_id.c @@ -0,0 +1,219 @@ +/* + * compose persistent device path + * + * Copyright (C) 2009 Martin Pitt + * Portions Copyright (C) 2004 David Zeuthen, + * Copyright (C) 2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +/* we must use this kernel-compatible implementation */ +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +/* + * Read a capability attribute and return bitmask. + * @param dev udev_device + * @param attr sysfs attribute name (e. g. "capabilities/key") + * @param bitmask: Output array which has a sizeof of bitmask_size + */ +static void get_cap_mask(struct udev_device *dev, + struct udev_device *pdev, const char* attr, + unsigned long *bitmask, size_t bitmask_size, + bool test) +{ + char text[4096]; + unsigned i; + char* word; + unsigned long val; + + snprintf(text, sizeof(text), "%s", udev_device_get_sysattr_value(pdev, attr)); + log_debug("%s raw kernel attribute: %s", attr, text); + + memzero(bitmask, bitmask_size); + i = 0; + while ((word = strrchr(text, ' ')) != NULL) { + val = strtoul (word+1, NULL, 16); + if (i < bitmask_size/sizeof(unsigned long)) + bitmask[i] = val; + else + log_debug("ignoring %s block %lX which is larger than maximum size", attr, val); + *word = '\0'; + ++i; + } + val = strtoul (text, NULL, 16); + if (i < bitmask_size / sizeof(unsigned long)) + bitmask[i] = val; + else + log_debug("ignoring %s block %lX which is larger than maximum size", attr, val); + + if (test) { + /* printf pattern with the right unsigned long number of hex chars */ + snprintf(text, sizeof(text), " bit %%4u: %%0%zilX\n", 2 * sizeof(unsigned long)); + log_debug("%s decoded bit map:", attr); + val = bitmask_size / sizeof (unsigned long); + /* skip over leading zeros */ + while (bitmask[val-1] == 0 && val > 0) + --val; + for (i = 0; i < val; ++i) { + DISABLE_WARNING_FORMAT_NONLITERAL; + log_debug(text, i * BITS_PER_LONG, bitmask[i]); + REENABLE_WARNING; + } + } +} + +/* pointer devices */ +static void test_pointers (struct udev_device *dev, + const unsigned long* bitmask_ev, + const unsigned long* bitmask_abs, + const unsigned long* bitmask_key, + const unsigned long* bitmask_rel, + bool test) +{ + int is_mouse = 0; + int is_touchpad = 0; + + if (!test_bit (EV_KEY, bitmask_ev)) { + if (test_bit (EV_ABS, bitmask_ev) && + test_bit (ABS_X, bitmask_abs) && + test_bit (ABS_Y, bitmask_abs) && + test_bit (ABS_Z, bitmask_abs)) + udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1"); + return; + } + + if (test_bit (EV_ABS, bitmask_ev) && + test_bit (ABS_X, bitmask_abs) && test_bit (ABS_Y, bitmask_abs)) { + if (test_bit (BTN_STYLUS, bitmask_key) || test_bit (BTN_TOOL_PEN, bitmask_key)) + udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1"); + else if (test_bit (BTN_TOOL_FINGER, bitmask_key) && !test_bit (BTN_TOOL_PEN, bitmask_key)) + is_touchpad = 1; + else if (test_bit (BTN_TRIGGER, bitmask_key) || + test_bit (BTN_A, bitmask_key) || + test_bit (BTN_1, bitmask_key)) + udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1"); + else if (test_bit (BTN_MOUSE, bitmask_key)) + /* This path is taken by VMware's USB mouse, which has + * absolute axes, but no touch/pressure button. */ + is_mouse = 1; + else if (test_bit (BTN_TOUCH, bitmask_key)) + udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1"); + } + + if (test_bit (EV_REL, bitmask_ev) && + test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel) && + test_bit (BTN_MOUSE, bitmask_key)) + is_mouse = 1; + + if (is_mouse) + udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1"); + if (is_touchpad) + udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1"); +} + +/* key like devices */ +static void test_key (struct udev_device *dev, + const unsigned long* bitmask_ev, + const unsigned long* bitmask_key, + bool test) +{ + unsigned i; + unsigned long found; + unsigned long mask; + + /* do we have any KEY_* capability? */ + if (!test_bit (EV_KEY, bitmask_ev)) { + log_debug("test_key: no EV_KEY capability"); + return; + } + + /* only consider KEY_* here, not BTN_* */ + found = 0; + for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) { + found |= bitmask_key[i]; + log_debug("test_key: checking bit block %lu for any keys; found=%i", (unsigned long)i*BITS_PER_LONG, found > 0); + } + /* If there are no keys in the lower block, check the higher block */ + if (!found) { + for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) { + if (test_bit (i, bitmask_key)) { + log_debug("test_key: Found key %x in high block", i); + found = 1; + break; + } + } + } + + if (found > 0) + udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1"); + + /* the first 32 bits are ESC, numbers, and Q to D; if we have all of + * those, consider it a full keyboard; do not test KEY_RESERVED, though */ + mask = 0xFFFFFFFE; + if ((bitmask_key[0] & mask) == mask) + udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1"); +} + +static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], bool test) +{ + struct udev_device *pdev; + unsigned long bitmask_ev[NBITS(EV_MAX)]; + unsigned long bitmask_abs[NBITS(ABS_MAX)]; + unsigned long bitmask_key[NBITS(KEY_MAX)]; + unsigned long bitmask_rel[NBITS(REL_MAX)]; + + /* walk up the parental chain until we find the real input device; the + * argument is very likely a subdevice of this, like eventN */ + pdev = dev; + while (pdev != NULL && udev_device_get_sysattr_value(pdev, "capabilities/ev") == NULL) + pdev = udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL); + + /* not an "input" class device */ + if (pdev == NULL) + return EXIT_SUCCESS; + + /* Use this as a flag that input devices were detected, so that this + * program doesn't need to be called more than once per device */ + udev_builtin_add_property(dev, test, "ID_INPUT", "1"); + get_cap_mask(dev, pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), test); + get_cap_mask(dev, pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test); + get_cap_mask(dev, pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test); + get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test); + test_pointers(dev, bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel, test); + test_key(dev, bitmask_ev, bitmask_key, test); + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_input_id = { + .name = "input_id", + .cmd = builtin_input_id, + .help = "input device properties", +}; diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c new file mode 100644 index 0000000..614e44e --- /dev/null +++ b/src/udev/udev-builtin-keyboard.c @@ -0,0 +1,163 @@ +/*** + This file is part of systemd. + + Copyright 2013 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static const struct key *keyboard_lookup_key(const char *str, unsigned int len); +#include "keyboard-keys-from-name.h" +#include "keyboard-keys-to-name.h" + +static int install_force_release(struct udev_device *dev, const unsigned int *release, unsigned int release_count) { + struct udev_device *atkbd; + const char *cur; + char codes[4096]; + char *s; + size_t l; + unsigned int i; + int ret; + + atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL); + if (!atkbd) + return -ENODEV; + + cur = udev_device_get_sysattr_value(atkbd, "force_release"); + if (!cur) + return -ENODEV; + + s = codes; + l = sizeof(codes); + + /* copy current content */ + l = strpcpy(&s, l, cur); + + /* append new codes */ + for (i = 0; i < release_count; i++) + l = strpcpyf(&s, l, ",%d", release[i]); + + log_debug("keyboard: updating force-release list with '%s'", codes); + ret = udev_device_set_sysattr_value(atkbd, "force_release", codes); + if (ret < 0) + log_error("Error writing force-release attribute: %s", strerror(-ret)); + return ret; +} + +static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { + struct udev_list_entry *entry; + struct { + unsigned int scan; + unsigned int key; + } map[1024]; + unsigned int map_count = 0; + unsigned int release[1024]; + unsigned int release_count = 0; + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { + const char *key; + unsigned int scancode; + char *endptr; + const char *keycode; + const struct key *k; + + key = udev_list_entry_get_name(entry); + if (!startswith(key, "KEYBOARD_KEY_")) + continue; + + /* KEYBOARD_KEY_= */ + scancode = strtoul(key + 13, &endptr, 16); + if (endptr[0] != '\0') { + log_error("Error, unable to parse scan code from '%s'", key); + continue; + } + + keycode = udev_list_entry_get_value(entry); + + /* a leading '!' needs a force-release entry */ + if (keycode[0] == '!') { + keycode++; + + release[release_count] = scancode; + if (release_count < ELEMENTSOF(release)-1) + release_count++; + + if (keycode[0] == '\0') + continue; + } + + /* translate identifier to key code */ + k = keyboard_lookup_key(keycode, strlen(keycode)); + if (!k) { + log_error("Error, unknown key identifier '%s'", keycode); + continue; + } + + map[map_count].scan = scancode; + map[map_count].key = k->id; + if (map_count < ELEMENTSOF(map)-1) + map_count++; + } + + if (map_count > 0 || release_count > 0) { + const char *node; + int fd; + unsigned int i; + + node = udev_device_get_devnode(dev); + if (!node) { + log_error("Error, no device node for '%s'", udev_device_get_syspath(dev)); + return EXIT_FAILURE; + } + + fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (fd < 0) { + log_error("Error, opening device '%s': %m", node); + return EXIT_FAILURE; + } + + /* install list of map codes */ + for (i = 0; i < map_count; i++) { + log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", + map[i].scan, map[i].scan, map[i].key, map[i].key); + if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0) + log_error("Error calling EVIOCSKEYCODE (scan code 0x%x, key code %d): %m", map[i].scan, map[i].key); + } + + /* install list of force-release codes */ + if (release_count > 0) + install_force_release(dev, release, release_count); + + close(fd); + } + + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_keyboard = { + .name = "keyboard", + .cmd = builtin_keyboard, + .help = "keyboard scan code to key mapping", +}; diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c new file mode 100644 index 0000000..5880c38 --- /dev/null +++ b/src/udev/udev-builtin-kmod.c @@ -0,0 +1,135 @@ +/* + * load kernel modules + * + * Copyright (C) 2011-2012 Kay Sievers + * Copyright (C) 2011 ProFUSION embedded systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static struct kmod_ctx *ctx; + +static int load_module(struct udev *udev, const char *alias) +{ + struct kmod_list *list = NULL; + struct kmod_list *l; + int err; + + err = kmod_module_new_from_lookup(ctx, alias, &list); + if (err < 0) + return err; + + if (list == NULL) + log_debug("no module matches '%s'", alias); + + kmod_list_foreach(l, list) { + struct kmod_module *mod = kmod_module_get_module(l); + + err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL); + if (err == KMOD_PROBE_APPLY_BLACKLIST) + log_debug("module '%s' is blacklisted", kmod_module_get_name(mod)); + else if (err == 0) + log_debug("inserted '%s'", kmod_module_get_name(mod)); + else + log_debug("failed to insert '%s'", kmod_module_get_name(mod)); + + kmod_module_unref(mod); + } + + kmod_module_unref_list(list); + return err; +} + +_printf_(6,0) +static void udev_kmod_log(void *data, int priority, const char *file, int line, + const char *fn, const char *format, va_list args) +{ + udev_main_log(data, priority, file, line, fn, format, args); +} + +static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool test) +{ + struct udev *udev = udev_device_get_udev(dev); + int i; + + if (!ctx) + return 0; + + if (argc < 3 || !streq(argv[1], "load")) { + log_error("expect: %s load ", argv[0]); + return EXIT_FAILURE; + } + + for (i = 2; argv[i]; i++) { + log_debug("execute '%s' '%s'", argv[1], argv[i]); + load_module(udev, argv[i]); + } + + return EXIT_SUCCESS; +} + +/* called at udev startup and reload */ +static int builtin_kmod_init(struct udev *udev) +{ + if (ctx) + return 0; + + ctx = kmod_new(NULL, NULL); + if (!ctx) + return -ENOMEM; + + log_debug("load module index"); + kmod_set_log_fn(ctx, udev_kmod_log, udev); + kmod_load_resources(ctx); + return 0; +} + +/* called on udev shutdown and reload request */ +static void builtin_kmod_exit(struct udev *udev) +{ + log_debug("unload module index"); + ctx = kmod_unref(ctx); +} + +/* called every couple of seconds during event activity; 'true' if config has changed */ +static bool builtin_kmod_validate(struct udev *udev) +{ + log_debug("validate module index"); + if (!ctx) + return false; + return (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK); +} + +const struct udev_builtin udev_builtin_kmod = { + .name = "kmod", + .cmd = builtin_kmod, + .init = builtin_kmod_init, + .exit = builtin_kmod_exit, + .validate = builtin_kmod_validate, + .help = "kernel module loader", + .run_once = false, +}; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c new file mode 100644 index 0000000..4f2b2c1 --- /dev/null +++ b/src/udev/udev-builtin-net_id.c @@ -0,0 +1,605 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* + * Predictable network interface device names based on: + * - firmware/bios-provided index numbers for on-board devices + * - firmware-provided pci-express hotplug slot index number + * - physical/geographical location of the hardware + * - the interface's MAC address + * + * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames + * + * Two character prefixes based on the type of interface: + * en -- ethernet + * sl -- serial line IP (slip) + * wl -- wlan + * ww -- wwan + * + * Type of names: + * o -- on-board device index number + * s[f][d] -- hotplug slot index number + * x -- MAC address + * [P]ps[f][d] + * -- PCI geographical location + * [P]ps[f][u][..][c][i] + * -- USB port number chain + * + * All multi-function PCI devices will carry the [f] number in the + * device name, including the function 0 device. + * + * When using PCI geography, The PCI domain is only prepended when it is not 0. + * + * For USB devices the full chain of port numbers of hubs is composed. If the + * name gets longer than the maximum number of 15 characters, the name is not + * exported. + * The usual USB configuration == 1 and interface == 0 values are suppressed. + * + * PCI ethernet card with firmware index "1": + * ID_NET_NAME_ONBOARD=eno1 + * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1 + * + * PCI ethernet card in hotplug slot with firmware index number: + * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1 + * ID_NET_NAME_MAC=enx000000000466 + * ID_NET_NAME_PATH=enp5s0 + * ID_NET_NAME_SLOT=ens1 + * + * PCI ethernet multi-function card with 2 ports: + * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0 + * ID_NET_NAME_MAC=enx78e7d1ea46da + * ID_NET_NAME_PATH=enp2s0f0 + * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1 + * ID_NET_NAME_MAC=enx78e7d1ea46dc + * ID_NET_NAME_PATH=enp2s0f1 + * + * PCI wlan card: + * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0 + * ID_NET_NAME_MAC=wlx0024d7e31130 + * ID_NET_NAME_PATH=wlp3s0 + * + * USB built-in 3G modem: + * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6 + * ID_NET_NAME_MAC=wwx028037ec0200 + * ID_NET_NAME_PATH=wwp0s29u1u4i6 + * + * USB Android phone: + * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2 + * ID_NET_NAME_MAC=enxd626b3450fb5 + * ID_NET_NAME_PATH=enp0s29u1u2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "fileio.h" + +enum netname_type{ + NET_UNDEF, + NET_PCI, + NET_USB, + NET_BCMA, + NET_VIRTIO, + NET_CCWGROUP, +}; + +struct netnames { + enum netname_type type; + + uint8_t mac[6]; + bool mac_valid; + + struct udev_device *pcidev; + char pci_slot[IFNAMSIZ]; + char pci_path[IFNAMSIZ]; + char pci_onboard[IFNAMSIZ]; + const char *pci_onboard_label; + + char usb_ports[IFNAMSIZ]; + + char bcma_core[IFNAMSIZ]; + + char virtio_core[IFNAMSIZ]; + + char ccw_core[IFNAMSIZ]; +}; + +/* retrieve on-board index number and label from firmware */ +static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + const char *index; + int idx; + + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ + index = udev_device_get_sysattr_value(names->pcidev, "acpi_index"); + /* SMBIOS type 41 -- Onboard Devices Extended Information */ + if (!index) + index = udev_device_get_sysattr_value(names->pcidev, "index"); + if (!index) + return -ENOENT; + idx = strtoul(index, NULL, 0); + if (idx <= 0) + return -EINVAL; + snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx); + + names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label"); + return 0; +} + +/* read the 256 bytes PCI configuration space to check the multi-function bit */ +static bool is_pci_multifunction(struct udev_device *dev) { + char filename[256]; + FILE *f = NULL; + char config[64]; + bool multi = false; + + snprintf(filename, sizeof(filename), "%s/config", udev_device_get_syspath(dev)); + f = fopen(filename, "re"); + if (!f) + goto out; + if (fread(&config, sizeof(config), 1, f) != 1) + goto out; + + /* bit 0-6 header type, bit 7 multi/single function device */ + if ((config[PCI_HEADER_TYPE] & 0x80) != 0) + multi = true; +out: + if (f) + fclose(f); + return multi; +} + +static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + struct udev *udev = udev_device_get_udev(names->pcidev); + unsigned domain, bus, slot, func, dev_id = 0; + size_t l; + char *s; + const char *attr; + struct udev_device *pci = NULL; + char slots[256], str[256]; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *dent; + int hotplug_slot = 0, err = 0; + + if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4) + return -ENOENT; + + /* kernel provided multi-device index */ + attr = udev_device_get_sysattr_value(dev, "dev_id"); + if (attr) + dev_id = strtol(attr, NULL, 16); + + /* compose a name based on the raw kernel's PCI bus, slot numbers */ + s = names->pci_path; + l = sizeof(names->pci_path); + if (domain > 0) + l = strpcpyf(&s, l, "P%d", domain); + l = strpcpyf(&s, l, "p%ds%d", bus, slot); + if (func > 0 || is_pci_multifunction(names->pcidev)) + l = strpcpyf(&s, l, "f%d", func); + if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; + + /* ACPI _SUN -- slot user number */ + pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); + if (!pci) { + err = -ENOENT; + goto out; + } + snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci)); + dir = opendir(slots); + if (!dir) { + err = -errno; + goto out; + } + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + int i; + char *rest; + char *address; + + if (dent->d_name[0] == '.') + continue; + i = strtol(dent->d_name, &rest, 10); + if (rest[0] != '\0') + continue; + if (i < 1) + continue; + snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name); + if (read_one_line_file(str, &address) >= 0) { + /* match slot address with device by stripping the function */ + if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address))) + hotplug_slot = i; + free(address); + } + + if (hotplug_slot > 0) + break; + } + + if (hotplug_slot > 0) { + s = names->pci_slot; + l = sizeof(names->pci_slot); + if (domain > 0) + l = strpcpyf(&s, l, "P%d", domain); + l = strpcpyf(&s, l, "s%d", hotplug_slot); + if (func > 0 || is_pci_multifunction(names->pcidev)) + l = strpcpyf(&s, l, "f%d", func); + if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; + } +out: + udev_device_unref(pci); + return err; +} + +static int names_pci(struct udev_device *dev, struct netnames *names) { + struct udev_device *parent; + + parent = udev_device_get_parent(dev); + if (!parent) + return -ENOENT; + /* check if our direct parent is a PCI device with no other bus in-between */ + if (streq_ptr("pci", udev_device_get_subsystem(parent))) { + names->type = NET_PCI; + names->pcidev = parent; + } else { + names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL); + if (!names->pcidev) + return -ENOENT; + } + dev_pci_onboard(dev, names); + dev_pci_slot(dev, names); + return 0; +} + +static int names_usb(struct udev_device *dev, struct netnames *names) { + struct udev_device *usbdev; + char name[256]; + char *ports; + char *config; + char *interf; + size_t l; + char *s; + + usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface"); + if (!usbdev) + return -ENOENT; + + /* get USB port number chain, configuration, interface */ + strscpy(name, sizeof(name), udev_device_get_sysname(usbdev)); + s = strchr(name, '-'); + if (!s) + return -EINVAL; + ports = s+1; + + s = strchr(ports, ':'); + if (!s) + return -EINVAL; + s[0] = '\0'; + config = s+1; + + s = strchr(config, '.'); + if (!s) + return -EINVAL; + s[0] = '\0'; + interf = s+1; + + /* prefix every port number in the chain with "u"*/ + s = ports; + while ((s = strchr(s, '.'))) + s[0] = 'u'; + s = names->usb_ports; + l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL); + + /* append USB config number, suppress the common config == 1 */ + if (!streq(config, "1")) + l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL); + + /* append USB interface number, suppress the interface == 0 */ + if (!streq(interf, "0")) + l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL); + if (l == 0) + return -ENAMETOOLONG; + + names->type = NET_USB; + return 0; +} + +static int names_bcma(struct udev_device *dev, struct netnames *names) { + struct udev_device *bcmadev; + unsigned int core; + + bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL); + if (!bcmadev) + return -ENOENT; + + /* bus num:core num */ + if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1) + return -EINVAL; + /* suppress the common core == 0 */ + if (core > 0) + snprintf(names->bcma_core, sizeof(names->bcma_core), "b%u", core); + + names->type = NET_BCMA; + return 0; +} + +static int names_virtio(struct udev_device *dev, struct netnames *names) { + struct udev_device *virtdev; + unsigned int core; + + virtdev = udev_device_get_parent_with_subsystem_devtype(dev, "virtio", NULL); + if (!virtdev) + return -ENOENT; + + /* core num */ + if (sscanf(udev_device_get_sysname(virtdev), "virtio%u", &core) != 1) + return -EINVAL; + /* suppress the common core == 0 */ + if (core > 0) + snprintf(names->virtio_core, sizeof(names->virtio_core), "v%u", core); + + names->type = NET_VIRTIO; + return 0; +} + +static int names_ccw(struct udev_device *dev, struct netnames *names) { + struct udev_device *cdev; + const char *bus_id; + size_t bus_id_len; + int rc; + + /* Retrieve the associated CCW device */ + cdev = udev_device_get_parent(dev); + if (!cdev) + return -ENOENT; + + /* Network devices are always grouped CCW devices */ + if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev))) + return -ENOENT; + + /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely + * identifies the network device on the Linux on System z channel + * subsystem. Note that the bus-ID contains lowercase characters. + */ + bus_id = udev_device_get_sysname(cdev); + if (!bus_id) + return -ENOENT; + + /* Check the length of the bus-ID. Rely on that the kernel provides + * a correct bus-ID; alternatively, improve this check and parse and + * verify each bus-ID part... + */ + bus_id_len = strlen(bus_id); + if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9) + return -EINVAL; + + /* Store the CCW bus-ID for use as network device name */ + rc = snprintf(names->ccw_core, sizeof(names->ccw_core), "ccw%s", bus_id); + if (rc >= 0 && rc < (int)sizeof(names->ccw_core)) + names->type = NET_CCWGROUP; + return 0; +} + +static int names_mac(struct udev_device *dev, struct netnames *names) { + const char *s; + unsigned int i; + unsigned int a1, a2, a3, a4, a5, a6; + + /* check for NET_ADDR_PERM, skip random MAC addresses */ + s = udev_device_get_sysattr_value(dev, "addr_assign_type"); + if (!s) + return EXIT_FAILURE; + i = strtoul(s, NULL, 0); + if (i != 0) + return 0; + + s = udev_device_get_sysattr_value(dev, "address"); + if (!s) + return -ENOENT; + if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) + return -EINVAL; + + /* skip empty MAC addresses */ + if (a1 + a2 + a3 + a4 + a5 + a6 == 0) + return -EINVAL; + + names->mac[0] = a1; + names->mac[1] = a2; + names->mac[2] = a3; + names->mac[3] = a4; + names->mac[4] = a5; + names->mac[5] = a6; + names->mac_valid = true; + return 0; +} + +/* IEEE Organizationally Unique Identifier vendor string */ +static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) { + char str[32]; + + if (!names->mac_valid) + return -ENOENT; + /* skip commonly misused 00:00:00 (Xerox) prefix */ + if (memcmp(names->mac, "\0\0\0", 3) == 0) + return -EINVAL; + snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", + names->mac[0], names->mac[1], names->mac[2], + names->mac[3], names->mac[4], names->mac[5]); + udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); + return 0; +} + +static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) { + const char *s; + const char *p; + unsigned int i; + const char *devtype; + const char *prefix = "en"; + struct netnames names = {}; + int err; + + /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */ + s = udev_device_get_sysattr_value(dev, "type"); + if (!s) + return EXIT_FAILURE; + i = strtoul(s, NULL, 0); + switch (i) { + case 1: /* ARPHRD_ETHER */ + prefix = "en"; + break; + case 256: /* ARPHRD_SLIP */ + prefix = "sl"; + break; + default: + return 0; + } + + /* skip stacked devices, like VLANs, ... */ + s = udev_device_get_sysattr_value(dev, "ifindex"); + if (!s) + return EXIT_FAILURE; + p = udev_device_get_sysattr_value(dev, "iflink"); + if (!p) + return EXIT_FAILURE; + if (!streq(s, p)) + return 0; + + devtype = udev_device_get_devtype(dev); + if (devtype) { + if (streq("wlan", devtype)) + prefix = "wl"; + else if (streq("wwan", devtype)) + prefix = "ww"; + } + + err = names_mac(dev, &names); + if (err >= 0 && names.mac_valid) { + char str[IFNAMSIZ]; + + snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix, + names.mac[0], names.mac[1], names.mac[2], + names.mac[3], names.mac[4], names.mac[5]); + udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str); + + ieee_oui(dev, &names, test); + } + + /* get path names for Linux on System z network devices */ + err = names_ccw(dev, &names); + if (err >= 0 && names.type == NET_CCWGROUP) { + char str[IFNAMSIZ]; + + if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_core) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + goto out; + } + + /* get PCI based path names, we compose only PCI based paths */ + err = names_pci(dev, &names); + if (err < 0) + goto out; + + /* plain PCI device */ + if (names.type == NET_PCI) { + char str[IFNAMSIZ]; + + if (names.pci_onboard[0]) + if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str); + + if (names.pci_onboard_label) + if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str); + + if (names.pci_path[0]) + if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + + if (names.pci_slot[0]) + if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + goto out; + } + + /* USB device */ + err = names_usb(dev, &names); + if (err >= 0 && names.type == NET_USB) { + char str[IFNAMSIZ]; + + if (names.pci_path[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + + if (names.pci_slot[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + goto out; + } + + /* Broadcom bus */ + err = names_bcma(dev, &names); + if (err >= 0 && names.type == NET_BCMA) { + char str[IFNAMSIZ]; + + if (names.pci_path[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + + if (names.pci_slot[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + goto out; + } + + /* virtio bus */ + err = names_virtio(dev, &names); + if (err >= 0 && names.type == NET_VIRTIO) { + char str[IFNAMSIZ]; + + if (names.pci_path[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.virtio_core) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); + + if (names.pci_slot[0]) + if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.virtio_core) < (int)sizeof(str)) + udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str); + goto out; + } + +out: + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_net_id = { + .name = "net_id", + .cmd = builtin_net_id, + .help = "network device properties", +}; diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c new file mode 100644 index 0000000..3cd384e --- /dev/null +++ b/src/udev/udev-builtin-net_setup_link.c @@ -0,0 +1,106 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "link-config.h" +#include "udev.h" +#include "log.h" + +static link_config_ctx *ctx = NULL; + +static int builtin_net_setup_link(struct udev_device *dev, int argc, char **argv, bool test) { + _cleanup_free_ char *driver = NULL; + const char *name; + link_config *link; + int r; + + if (argc > 1) { + log_error("This program takes no arguments."); + return EXIT_FAILURE; + } + + r = link_get_driver(ctx, dev, &driver); + if (r >= 0) + udev_builtin_add_property(dev, test, "ID_NET_DRIVER", driver); + + r = link_config_get(ctx, dev, &link); + if (r < 0) { + if (r == -ENOENT) { + log_debug("No matching link configuration found"); + return EXIT_SUCCESS; + } else { + log_error("Could not get link config"); + return EXIT_FAILURE; + } + } + + r = link_config_apply(ctx, link, dev, &name); + if (r < 0) { + log_error("Could not apply link config to %s", udev_device_get_sysname(dev)); + return EXIT_FAILURE; + } + + if (name) + udev_builtin_add_property(dev, test, "ID_NET_NAME", name); + + return EXIT_SUCCESS; +} + +static int builtin_net_setup_link_init(struct udev *udev) { + int r; + + if (ctx) + return 0; + + r = link_config_ctx_new(&ctx); + if (r < 0) + return r; + + r = link_config_load(ctx); + if (r < 0) + return r; + + log_debug("Created link configuration context"); + return 0; +} + +static void builtin_net_setup_link_exit(struct udev *udev) { + link_config_ctx_free(ctx); + ctx = NULL; + log_debug("Unloaded link configuration context"); +} + +static bool builtin_net_setup_link_validate(struct udev *udev) { + log_debug("Check if link configuration needs reloading"); + if (!ctx) + return false; + + return link_config_should_reload(ctx); +} + +const struct udev_builtin udev_builtin_net_setup_link = { + .name = "net_setup_link", + .cmd = builtin_net_setup_link, + .init = builtin_net_setup_link_init, + .exit = builtin_net_setup_link_exit, + .validate = builtin_net_setup_link_validate, + .help = "configure network link", + .run_once = false, +}; diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c new file mode 100644 index 0000000..0599980 --- /dev/null +++ b/src/udev/udev-builtin-path_id.c @@ -0,0 +1,611 @@ +/* + * compose persistent device path + * + * Copyright (C) 2009-2011 Kay Sievers + * + * Logic based on Hannes Reinecke's shell script. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +_printf_(2,3) +static int path_prepend(char **path, const char *fmt, ...) +{ + va_list va; + char *pre; + int err = 0; + + va_start(va, fmt); + err = vasprintf(&pre, fmt, va); + va_end(va); + if (err < 0) + goto out; + + if (*path != NULL) { + char *new; + + err = asprintf(&new, "%s-%s", pre, *path); + free(pre); + if (err < 0) + goto out; + free(*path); + *path = new; + } else { + *path = pre; + } +out: + return err; +} + +/* +** Linux only supports 32 bit luns. +** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details. +*/ +static int format_lun_number(struct udev_device *dev, char **path) +{ + unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10); + + /* address method 0, peripheral device addressing with bus id of zero */ + if (lun < 256) + return path_prepend(path, "lun-%lu", lun); + /* handle all other lun addressing methods by using a variant of the original lun format */ + return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, (lun >> 16) & 0xffff); +} + +static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) +{ + struct udev_device *parent = dev; + + while (parent != NULL) { + const char *subsystem; + + subsystem = udev_device_get_subsystem(parent); + if (subsystem == NULL || !streq(subsystem, subsys)) + break; + dev = parent; + parent = udev_device_get_parent(parent); + } + return dev; +} + +static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) +{ + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; + struct udev_device *fcdev = NULL; + const char *port; + char *lun = NULL; + + targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); + if (targetdev == NULL) + return NULL; + + fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); + if (fcdev == NULL) + return NULL; + port = udev_device_get_sysattr_value(fcdev, "port_name"); + if (port == NULL) { + parent = NULL; + goto out; + } + + format_lun_number(parent, &lun); + path_prepend(path, "fc-%s-%s", port, lun); + if (lun) + free(lun); +out: + udev_device_unref(fcdev); + return parent; +} + +static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) +{ + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; + struct udev_device *target_parent; + struct udev_device *sasdev; + const char *sas_address; + char *lun = NULL; + + targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); + if (targetdev == NULL) + return NULL; + + target_parent = udev_device_get_parent(targetdev); + if (target_parent == NULL) + return NULL; + + sasdev = udev_device_new_from_subsystem_sysname(udev, "sas_device", + udev_device_get_sysname(target_parent)); + if (sasdev == NULL) + return NULL; + + sas_address = udev_device_get_sysattr_value(sasdev, "sas_address"); + if (sas_address == NULL) { + parent = NULL; + goto out; + } + + format_lun_number(parent, &lun); + path_prepend(path, "sas-%s-%s", sas_address, lun); + if (lun) + free(lun); +out: + udev_device_unref(sasdev); + return parent; +} + +static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) +{ + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *transportdev; + struct udev_device *sessiondev = NULL; + const char *target; + char *connname; + struct udev_device *conndev = NULL; + const char *addr; + const char *port; + char *lun = NULL; + + /* find iscsi session */ + transportdev = parent; + for (;;) { + transportdev = udev_device_get_parent(transportdev); + if (transportdev == NULL) + return NULL; + if (startswith(udev_device_get_sysname(transportdev), "session")) + break; + } + + /* find iscsi session device */ + sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev)); + if (sessiondev == NULL) + return NULL; + target = udev_device_get_sysattr_value(sessiondev, "targetname"); + if (target == NULL) { + parent = NULL; + goto out; + } + + if (asprintf(&connname, "connection%s:0", udev_device_get_sysnum(transportdev)) < 0) { + parent = NULL; + goto out; + } + conndev = udev_device_new_from_subsystem_sysname(udev, "iscsi_connection", connname); + free(connname); + if (conndev == NULL) { + parent = NULL; + goto out; + } + addr = udev_device_get_sysattr_value(conndev, "persistent_address"); + port = udev_device_get_sysattr_value(conndev, "persistent_port"); + if (addr == NULL || port == NULL) { + parent = NULL; + goto out; + } + + format_lun_number(parent, &lun); + path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); + if (lun) + free(lun); +out: + udev_device_unref(sessiondev); + udev_device_unref(conndev); + return parent; +} + +static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path) +{ + struct udev_device *hostdev; + int host, bus, target, lun; + const char *name; + char *base; + char *pos; + DIR *dir; + struct dirent *dent; + int basenum; + + hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); + if (hostdev == NULL) + return NULL; + + name = udev_device_get_sysname(parent); + if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) + return NULL; + + /* + * Rebase host offset to get the local relative number + * + * Note: This is by definition racy, unreliable and too simple. + * Please do not copy this model anywhere. It's just a left-over + * from the time we had no idea how things should look like in + * the end. + * + * Making assumptions about a global in-kernel counter and use + * that to calculate a local offset is a very broken concept. It + * can only work as long as things are in strict order. + * + * The kernel needs to export the instance/port number of a + * controller directly, without the need for rebase magic like + * this. Manual driver unbind/bind, parallel hotplug/unplug will + * get into the way of this "I hope it works" logic. + */ + basenum = -1; + base = strdup(udev_device_get_syspath(hostdev)); + if (base == NULL) + return NULL; + pos = strrchr(base, '/'); + if (pos == NULL) { + parent = NULL; + goto out; + } + pos[0] = '\0'; + dir = opendir(base); + if (dir == NULL) { + parent = NULL; + goto out; + } + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char *rest; + int i; + + if (dent->d_name[0] == '.') + continue; + if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) + continue; + if (!startswith(dent->d_name, "host")) + continue; + i = strtoul(&dent->d_name[4], &rest, 10); + if (rest[0] != '\0') + continue; + /* + * find the smallest number; the host really needs to export its + * own instance number per parent device; relying on the global host + * enumeration and plainly rebasing the numbers sounds unreliable + */ + if (basenum == -1 || i < basenum) + basenum = i; + } + closedir(dir); + if (basenum == -1) { + parent = NULL; + goto out; + } + host -= basenum; + + path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); +out: + free(base); + return hostdev; +} + +static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char **path) { + struct udev_device *hostdev; + struct udev_device *vmbusdev; + const char *guid_str; + char *lun = NULL; + char guid[38]; + size_t i, k; + + hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); + if (!hostdev) + return NULL; + + vmbusdev = udev_device_get_parent(hostdev); + if (!vmbusdev) + return NULL; + + guid_str = udev_device_get_sysattr_value(vmbusdev, "device_id"); + if (!guid_str) + return NULL; + + if (strlen(guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}') + return NULL; + + for (i = 1, k = 0; i < 36; i++) { + if (guid_str[i] == '-') + continue; + guid[k++] = guid_str[i]; + } + guid[k] = '\0'; + + format_lun_number(parent, &lun); + path_prepend(path, "vmbus-%s-%s", guid, lun); + free(lun); + return parent; +} + +static struct udev_device *handle_scsi(struct udev_device *parent, char **path) +{ + const char *devtype; + const char *name; + const char *id; + + devtype = udev_device_get_devtype(parent); + if (devtype == NULL || !streq(devtype, "scsi_device")) + return parent; + + /* firewire */ + id = udev_device_get_sysattr_value(parent, "ieee1394_id"); + if (id != NULL) { + parent = skip_subsystem(parent, "scsi"); + path_prepend(path, "ieee1394-0x%s", id); + goto out; + } + + /* scsi sysfs does not have a "subsystem" for the transport */ + name = udev_device_get_syspath(parent); + + if (strstr(name, "/rport-") != NULL) { + parent = handle_scsi_fibre_channel(parent, path); + goto out; + } + + if (strstr(name, "/end_device-") != NULL) { + parent = handle_scsi_sas(parent, path); + goto out; + } + + if (strstr(name, "/session") != NULL) { + parent = handle_scsi_iscsi(parent, path); + goto out; + } + + /* + * We do not support the ATA transport class, it uses global counters + * to name the ata devices which numbers spread across multiple + * controllers. + * + * The real link numbers are not exported. Also, possible chains of ports + * behind port multipliers cannot be composed that way. + * + * Until all that is solved at the kernel level, there are no by-path/ + * links for ATA devices. + */ + if (strstr(name, "/ata") != NULL) { + parent = NULL; + goto out; + } + + if (strstr(name, "/vmbus_") != NULL) { + parent = handle_scsi_hyperv(parent, path); + goto out; + } + + parent = handle_scsi_default(parent, path); +out: + return parent; +} + +static struct udev_device *handle_cciss(struct udev_device *parent, char **path) +{ + const char *str; + unsigned int controller, disk; + + str = udev_device_get_sysname(parent); + if (sscanf(str, "c%ud%u%*s", &controller, &disk) != 2) + return NULL; + + path_prepend(path, "cciss-disk%u", disk); + parent = skip_subsystem(parent, "cciss"); + return parent; +} + +static void handle_scsi_tape(struct udev_device *dev, char **path) +{ + const char *name; + + /* must be the last device in the syspath */ + if (*path != NULL) + return; + + name = udev_device_get_sysname(dev); + if (startswith(name, "nst") && strchr("lma", name[3]) != NULL) + path_prepend(path, "nst%c", name[3]); + else if (startswith(name, "st") && strchr("lma", name[2]) != NULL) + path_prepend(path, "st%c", name[2]); +} + +static struct udev_device *handle_usb(struct udev_device *parent, char **path) +{ + const char *devtype; + const char *str; + const char *port; + + devtype = udev_device_get_devtype(parent); + if (devtype == NULL) + return parent; + if (!streq(devtype, "usb_interface") && !streq(devtype, "usb_device")) + return parent; + + str = udev_device_get_sysname(parent); + port = strchr(str, '-'); + if (port == NULL) + return parent; + port++; + + parent = skip_subsystem(parent, "usb"); + path_prepend(path, "usb-0:%s", port); + return parent; +} + +static struct udev_device *handle_bcma(struct udev_device *parent, char **path) +{ + const char *sysname; + unsigned int core; + + sysname = udev_device_get_sysname(parent); + if (sscanf(sysname, "bcma%*u:%u", &core) != 1) + return NULL; + + path_prepend(path, "bcma-%u", core); + return parent; +} + +static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) +{ + struct udev_device *scsi_dev; + + scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); + if (scsi_dev != NULL) { + const char *wwpn; + const char *lun; + const char *hba_id; + + hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id"); + wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn"); + lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun"); + if (hba_id != NULL && lun != NULL && wwpn != NULL) { + path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); + goto out; + } + } + + path_prepend(path, "ccw-%s", udev_device_get_sysname(parent)); +out: + parent = skip_subsystem(parent, "ccw"); + return parent; +} + +static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test) +{ + struct udev_device *parent; + char *path = NULL; + bool some_transport = false; + + /* S390 ccw bus */ + parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); + if (parent != NULL) { + handle_ccw(parent, dev, &path); + goto out; + } + + /* walk up the chain of devices and compose path */ + parent = dev; + while (parent != NULL) { + const char *subsys; + + subsys = udev_device_get_subsystem(parent); + if (subsys == NULL) { + ; + } else if (streq(subsys, "scsi_tape")) { + handle_scsi_tape(parent, &path); + } else if (streq(subsys, "scsi")) { + parent = handle_scsi(parent, &path); + some_transport = true; + } else if (streq(subsys, "cciss")) { + parent = handle_cciss(parent, &path); + some_transport = true; + } else if (streq(subsys, "usb")) { + parent = handle_usb(parent, &path); + some_transport = true; + } else if (streq(subsys, "bcma")) { + parent = handle_bcma(parent, &path); + some_transport = true; + } else if (streq(subsys, "serio")) { + path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent)); + parent = skip_subsystem(parent, "serio"); + } else if (streq(subsys, "pci")) { + path_prepend(&path, "pci-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "pci"); + } else if (streq(subsys, "platform")) { + path_prepend(&path, "platform-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "platform"); + some_transport = true; + } else if (streq(subsys, "acpi")) { + path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "acpi"); + } else if (streq(subsys, "xen")) { + path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "xen"); + } else if (streq(subsys, "virtio")) { + path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "virtio"); + } else if (streq(subsys, "scm")) { + path_prepend(&path, "scm-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "scm"); + some_transport = true; + } + + parent = udev_device_get_parent(parent); + } + + /* + * Do not return a single-parent-device-only for block + * devices, they might have entire buses behind it which + * do not get unique IDs only by using the parent device. + */ + if (!some_transport && streq(udev_device_get_subsystem(dev), "block")) { + free(path); + path = NULL; + } + +out: + if (path != NULL) { + char tag[UTIL_NAME_SIZE]; + size_t i; + const char *p; + + /* compose valid udev tag name */ + for (p = path, i = 0; *p; p++) { + if ((*p >= '0' && *p <= '9') || + (*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + *p == '-') { + tag[i++] = *p; + continue; + } + + /* skip all leading '_' */ + if (i == 0) + continue; + + /* avoid second '_' */ + if (tag[i-1] == '_') + continue; + + tag[i++] = '_'; + } + /* strip trailing '_' */ + while (i > 0 && tag[i-1] == '_') + i--; + tag[i] = '\0'; + + udev_builtin_add_property(dev, test, "ID_PATH", path); + udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag); + free(path); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +const struct udev_builtin udev_builtin_path_id = { + .name = "path_id", + .cmd = builtin_path_id, + .help = "compose persistent device path", + .run_once = true, +}; diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c new file mode 100644 index 0000000..ddb0157 --- /dev/null +++ b/src/udev/udev-builtin-uaccess.c @@ -0,0 +1,94 @@ +/* + * manage device node user ACL + * + * Copyright 2010-2012 Kay Sievers + * Copyright 2010 Lennart Poettering + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "logind-acl.h" +#include "udev.h" +#include "util.h" + +static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool test) +{ + int r; + const char *path = NULL, *seat; + bool changed_acl = false; + uid_t uid; + + umask(0022); + + /* don't muck around with ACLs when the system is not running systemd */ + if (!logind_running()) + return 0; + + path = udev_device_get_devnode(dev); + seat = udev_device_get_property_value(dev, "ID_SEAT"); + if (!seat) + seat = "seat0"; + + r = sd_seat_get_active(seat, NULL, &uid); + if (r == -ENOENT) { + /* No active session on this seat */ + r = 0; + goto finish; + } else if (r < 0) { + log_error("Failed to determine active user on seat %s.", seat); + goto finish; + } + + r = devnode_acl(path, true, false, 0, true, uid); + if (r < 0) { + log_error("Failed to apply ACL on %s: %s", path, strerror(-r)); + goto finish; + } + + changed_acl = true; + r = 0; + +finish: + if (path && !changed_acl) { + int k; + + /* Better be safe than sorry and reset ACL */ + k = devnode_acl(path, true, false, 0, false, 0); + if (k < 0) { + log_error("Failed to apply ACL on %s: %s", path, strerror(-k)); + if (r >= 0) + r = k; + } + } + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_uaccess = { + .name = "uaccess", + .cmd = builtin_uaccess, + .help = "manage device node user ACL", +}; diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c new file mode 100644 index 0000000..883e11e --- /dev/null +++ b/src/udev/udev-builtin-usb_id.c @@ -0,0 +1,481 @@ +/* + * USB device properties and persistent device path + * + * Copyright (c) 2005 SUSE Linux Products GmbH, Germany + * Author: Hannes Reinecke + * + * Copyright (C) 2005-2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void set_usb_iftype(char *to, int if_class_num, size_t len) +{ + const char *type = "generic"; + + switch (if_class_num) { + case 1: + type = "audio"; + break; + case 2: /* CDC-Control */ + break; + case 3: + type = "hid"; + break; + case 5: /* Physical */ + break; + case 6: + type = "media"; + break; + case 7: + type = "printer"; + break; + case 8: + type = "storage"; + break; + case 9: + type = "hub"; + break; + case 0x0a: /* CDC-Data */ + break; + case 0x0b: /* Chip/Smart Card */ + break; + case 0x0d: /* Content Security */ + break; + case 0x0e: + type = "video"; + break; + case 0xdc: /* Diagnostic Device */ + break; + case 0xe0: /* Wireless Controller */ + break; + case 0xfe: /* Application-specific */ + break; + case 0xff: /* Vendor-specific */ + break; + default: + break; + } + strncpy(to, type, len); + to[len-1] = '\0'; +} + +static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len) +{ + int type_num = 0; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 1: /* RBC devices */ + type = "rbc"; + break; + case 2: + type = "atapi"; + break; + case 3: + type = "tape"; + break; + case 4: /* UFI */ + type = "floppy"; + break; + case 6: /* Transparent SPC-2 devices */ + type = "scsi"; + break; + default: + break; + } + } + strscpy(to, len, type); + return type_num; +} + +static void set_scsi_type(char *to, const char *from, size_t len) +{ + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 0: + case 0xe: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + case 7: + case 0xf: + type = "optical"; + break; + case 5: + type = "cd"; + break; + default: + break; + } + } + strscpy(to, len, type); +} + +#define USB_DT_DEVICE 0x01 +#define USB_DT_INTERFACE 0x04 + +static int dev_if_packed_info(struct udev_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]; + int pos = 0; + unsigned strpos = 0; + struct usb_interface_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bInterfaceNumber; + u_int8_t bAlternateSetting; + u_int8_t bNumEndpoints; + u_int8_t bInterfaceClass; + u_int8_t bInterfaceSubClass; + u_int8_t bInterfaceProtocol; + u_int8_t iInterface; + } __attribute__((packed)); + + if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0) + return log_oom(); + + fd = open(filename, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "error opening USB device 'descriptors' file\n"); + return -errno; + } + + size = read(fd, buf, sizeof(buf)); + if (size < 18 || size == sizeof(buf)) + return -EIO; + + ifs_str[0] = '\0'; + while (pos < size && strpos+7 < len-2) { + struct usb_interface_descriptor *desc; + char if_str[8]; + + desc = (struct usb_interface_descriptor *) &buf[pos]; + if (desc->bLength < 3) + break; + pos += desc->bLength; + + if (desc->bDescriptorType != USB_DT_INTERFACE) + continue; + + if (snprintf(if_str, 8, ":%02x%02x%02x", + desc->bInterfaceClass, + desc->bInterfaceSubClass, + desc->bInterfaceProtocol) != 7) + continue; + + if (strstr(ifs_str, if_str) != NULL) + continue; + + memcpy(&ifs_str[strpos], if_str, 8), + strpos += 7; + } + + if (strpos > 0) { + ifs_str[strpos++] = ':'; + ifs_str[strpos++] = '\0'; + } + + return 0; +} + +/* + * A unique USB identification is generated like this: + * + * 1.) Get the USB device type from InterfaceClass and InterfaceSubClass + * 2.) If the device type is 'Mass-Storage/SPC-2' or 'Mass-Storage/RBC', + * use the SCSI vendor and model as USB-Vendor and USB-model. + * 3.) Otherwise, use the USB manufacturer and product as + * USB-Vendor and USB-model. Any non-printable characters + * in those strings will be skipped; a slash '/' will be converted + * into a full stop '.'. + * 4.) If that fails, too, we will use idVendor and idProduct + * as USB-Vendor and USB-model. + * 5.) The USB identification is the USB-vendor and USB-model + * string concatenated with an underscore '_'. + * 6.) If the device supplies a serial number, this number + * is concatenated with the identification with an underscore '_'. + */ +static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test) +{ + char vendor_str[64]; + char vendor_str_enc[256]; + const char *vendor_id; + char model_str[64]; + char model_str_enc[256]; + const char *product_id; + char serial_str[UTIL_NAME_SIZE]; + char packed_if_str[UTIL_NAME_SIZE]; + char revision_str[64]; + char type_str[64]; + char instance_str[64]; + const char *ifnum = NULL; + const char *driver = NULL; + char serial[256]; + + struct udev_device *dev_interface = NULL; + struct udev_device *dev_usb = NULL; + const char *if_class, *if_subclass; + int if_class_num; + int protocol = 0; + size_t l; + char *s; + + vendor_str[0] = '\0'; + model_str[0] = '\0'; + serial_str[0] = '\0'; + packed_if_str[0] = '\0'; + revision_str[0] = '\0'; + type_str[0] = '\0'; + instance_str[0] = '\0'; + + /* shortcut, if we are called directly for a "usb_device" type */ + if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) { + dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str)); + dev_usb = dev; + goto fallback; + } + + /* usb interface directory */ + dev_interface = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface"); + if (dev_interface == NULL) { + log_debug("unable to access usb_interface device of '%s'", + udev_device_get_syspath(dev)); + return EXIT_FAILURE; + } + + ifnum = udev_device_get_sysattr_value(dev_interface, "bInterfaceNumber"); + driver = udev_device_get_sysattr_value(dev_interface, "driver"); + + if_class = udev_device_get_sysattr_value(dev_interface, "bInterfaceClass"); + if (!if_class) { + log_debug("%s: cannot get bInterfaceClass attribute", + udev_device_get_sysname(dev)); + return EXIT_FAILURE; + } + + if_class_num = strtoul(if_class, NULL, 16); + if (if_class_num == 8) { + /* mass storage */ + if_subclass = udev_device_get_sysattr_value(dev_interface, "bInterfaceSubClass"); + if (if_subclass != NULL) + protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1); + } else { + set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1); + } + + log_debug("%s: if_class %d protocol %d", + udev_device_get_syspath(dev_interface), if_class_num, protocol); + + /* usb device directory */ + dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device"); + if (!dev_usb) { + log_debug("unable to find parent 'usb' device of '%s'", + udev_device_get_syspath(dev)); + return EXIT_FAILURE; + } + + /* all interfaces of the device in a single string */ + dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str)); + + /* mass storage : SCSI or ATAPI */ + if ((protocol == 6 || protocol == 2)) { + struct udev_device *dev_scsi; + const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev; + int host, bus, target, lun; + + /* get scsi device */ + dev_scsi = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); + if (dev_scsi == NULL) { + log_debug("unable to find parent 'scsi' device of '%s'", + udev_device_get_syspath(dev)); + goto fallback; + } + if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) { + log_debug("invalid scsi device '%s'", udev_device_get_sysname(dev_scsi)); + goto fallback; + } + + /* Generic SPC-2 device */ + scsi_vendor = udev_device_get_sysattr_value(dev_scsi, "vendor"); + if (!scsi_vendor) { + log_debug("%s: cannot get SCSI vendor attribute", + udev_device_get_sysname(dev_scsi)); + goto fallback; + } + udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc)); + util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1); + util_replace_chars(vendor_str, NULL); + + scsi_model = udev_device_get_sysattr_value(dev_scsi, "model"); + if (!scsi_model) { + log_debug("%s: cannot get SCSI model attribute", + udev_device_get_sysname(dev_scsi)); + goto fallback; + } + udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc)); + util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1); + util_replace_chars(model_str, NULL); + + scsi_type = udev_device_get_sysattr_value(dev_scsi, "type"); + if (!scsi_type) { + log_debug("%s: cannot get SCSI type attribute", + udev_device_get_sysname(dev_scsi)); + goto fallback; + } + set_scsi_type(type_str, scsi_type, sizeof(type_str)-1); + + scsi_rev = udev_device_get_sysattr_value(dev_scsi, "rev"); + if (!scsi_rev) { + log_debug("%s: cannot get SCSI revision attribute", + udev_device_get_sysname(dev_scsi)); + goto fallback; + } + util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1); + util_replace_chars(revision_str, NULL); + + /* + * some broken devices have the same identifiers + * for all luns, export the target:lun number + */ + sprintf(instance_str, "%d:%d", target, lun); + } + +fallback: + vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor"); + product_id = udev_device_get_sysattr_value(dev_usb, "idProduct"); + + /* fallback to USB vendor & device */ + if (vendor_str[0] == '\0') { + const char *usb_vendor = NULL; + + usb_vendor = udev_device_get_sysattr_value(dev_usb, "manufacturer"); + if (!usb_vendor) + usb_vendor = vendor_id; + if (!usb_vendor) { + log_debug("No USB vendor information available"); + return EXIT_FAILURE; + } + udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc)); + util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1); + util_replace_chars(vendor_str, NULL); + } + + if (model_str[0] == '\0') { + const char *usb_model = NULL; + + usb_model = udev_device_get_sysattr_value(dev_usb, "product"); + if (!usb_model) + usb_model = product_id; + if (!usb_model) + return EXIT_FAILURE; + udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc)); + util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1); + util_replace_chars(model_str, NULL); + } + + if (revision_str[0] == '\0') { + const char *usb_rev; + + usb_rev = udev_device_get_sysattr_value(dev_usb, "bcdDevice"); + if (usb_rev) { + util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1); + util_replace_chars(revision_str, NULL); + } + } + + if (serial_str[0] == '\0') { + const char *usb_serial; + + usb_serial = udev_device_get_sysattr_value(dev_usb, "serial"); + if (usb_serial) { + const unsigned char *p; + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */ + for (p = (unsigned char *)usb_serial; *p != '\0'; p++) + if (*p < 0x20 || *p > 0x7f || *p == ',') { + usb_serial = NULL; + break; + } + } + + if (usb_serial) { + util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1); + util_replace_chars(serial_str, NULL); + } + } + + s = serial; + l = strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL); + if (serial_str[0] != '\0') + l = strpcpyl(&s, l, "_", serial_str, NULL); + + if (instance_str[0] != '\0') + strpcpyl(&s, l, "-", instance_str, NULL); + + udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str); + udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc); + udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id); + udev_builtin_add_property(dev, test, "ID_MODEL", model_str); + udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc); + udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id); + udev_builtin_add_property(dev, test, "ID_REVISION", revision_str); + udev_builtin_add_property(dev, test, "ID_SERIAL", serial); + if (serial_str[0] != '\0') + udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str); + if (type_str[0] != '\0') + udev_builtin_add_property(dev, test, "ID_TYPE", type_str); + if (instance_str[0] != '\0') + udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str); + udev_builtin_add_property(dev, test, "ID_BUS", "usb"); + if (packed_if_str[0] != '\0') + udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str); + if (ifnum != NULL) + udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum); + if (driver != NULL) + udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver); + return EXIT_SUCCESS; +} + +const struct udev_builtin udev_builtin_usb_id = { + .name = "usb_id", + .cmd = builtin_usb_id, + .help = "usb device properties", + .run_once = true, +}; diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c new file mode 100644 index 0000000..fd373d0 --- /dev/null +++ b/src/udev/udev-builtin.c @@ -0,0 +1,152 @@ +/*** + This file is part of systemd. + + Copyright 2007-2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static bool initialized; + +static const struct udev_builtin *builtins[] = { +#ifdef HAVE_BLKID + [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid, +#endif + [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs, +#ifdef HAVE_FIRMWARE + [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware, +#endif + [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb, + [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id, + [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard, +#ifdef HAVE_KMOD + [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod, +#endif + [UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id, + [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link, + [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id, + [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id, +#ifdef HAVE_ACL + [UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess, +#endif +}; + +void udev_builtin_init(struct udev *udev) +{ + unsigned int i; + + if (initialized) + return; + + for (i = 0; i < ELEMENTSOF(builtins); i++) + if (builtins[i]->init) + builtins[i]->init(udev); + + initialized = true; +} + +void udev_builtin_exit(struct udev *udev) +{ + unsigned int i; + + if (!initialized) + return; + + for (i = 0; i < ELEMENTSOF(builtins); i++) + if (builtins[i]->exit) + builtins[i]->exit(udev); + + initialized = false; +} + +bool udev_builtin_validate(struct udev *udev) +{ + unsigned int i; + + for (i = 0; i < ELEMENTSOF(builtins); i++) + if (builtins[i]->validate && builtins[i]->validate(udev)) + return true; + return false; +} + +void udev_builtin_list(struct udev *udev) +{ + unsigned int i; + + for (i = 0; i < ELEMENTSOF(builtins); i++) + fprintf(stderr, " %-12s %s\n", builtins[i]->name, builtins[i]->help); +} + +const char *udev_builtin_name(enum udev_builtin_cmd cmd) +{ + return builtins[cmd]->name; +} + +bool udev_builtin_run_once(enum udev_builtin_cmd cmd) +{ + return builtins[cmd]->run_once; +} + +enum udev_builtin_cmd udev_builtin_lookup(const char *command) +{ + char name[UTIL_PATH_SIZE]; + enum udev_builtin_cmd i; + char *pos; + + strscpy(name, sizeof(name), command); + pos = strchr(name, ' '); + if (pos) + pos[0] = '\0'; + for (i = 0; i < ELEMENTSOF(builtins); i++) + if (streq(builtins[i]->name, name)) + return i; + return UDEV_BUILTIN_MAX; +} + +int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) +{ + char arg[UTIL_PATH_SIZE]; + int argc; + char *argv[128]; + + /* we need '0' here to reset the internal state */ + optind = 0; + strscpy(arg, sizeof(arg), command); + udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv); + return builtins[cmd]->cmd(dev, argc, argv, test); +} + +int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val) +{ + struct udev_list_entry *entry; + + entry = udev_device_add_property(dev, key, val); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_num(entry, true); + + if (test) + printf("%s=%s\n", key, val); + return 0; +} diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c new file mode 100644 index 0000000..1e91ec2 --- /dev/null +++ b/src/udev/udev-ctrl.c @@ -0,0 +1,485 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers + * + * This library 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.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 int magic; + enum udev_ctrl_msg_type type; + union { + int intval; + char buf[256]; + }; +}; + +struct udev_ctrl_msg { + int refcount; + struct udev_ctrl_connection *conn; + struct udev_ctrl_msg_wire ctrl_msg_wire; +}; + +struct udev_ctrl { + int refcount; + struct udev *udev; + int sock; + struct sockaddr_un saddr; + socklen_t addrlen; + bool bound; + bool cleanup_socket; + bool connected; +}; + +struct udev_ctrl_connection { + int refcount; + struct udev_ctrl *uctrl; + int sock; +}; + +struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) +{ + struct udev_ctrl *uctrl; + const int on = 1; + + uctrl = new0(struct udev_ctrl, 1); + if (uctrl == NULL) + return NULL; + uctrl->refcount = 1; + uctrl->udev = udev; + + if (fd < 0) { + uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + if (uctrl->sock < 0) { + log_error("error getting socket: %m"); + udev_ctrl_unref(uctrl); + return NULL; + } + } else { + uctrl->bound = true; + uctrl->sock = fd; + } + setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + + uctrl->saddr.sun_family = AF_LOCAL; + strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control"); + uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path); + return uctrl; +} + +struct udev_ctrl *udev_ctrl_new(struct udev *udev) +{ + return udev_ctrl_new_from_fd(udev, -1); +} + +int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) +{ + int err; + + if (!uctrl->bound) { + err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen); + if (err < 0 && errno == EADDRINUSE) { + unlink(uctrl->saddr.sun_path); + err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen); + } + + if (err < 0) { + err = -errno; + log_error("bind failed: %m"); + return err; + } + + err = listen(uctrl->sock, 0); + if (err < 0) { + err = -errno; + log_error("listen failed: %m"); + return err; + } + + uctrl->bound = true; + uctrl->cleanup_socket = true; + } + return 0; +} + +struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl) +{ + return uctrl->udev; +} + +static struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl) +{ + if (uctrl == NULL) + return NULL; + uctrl->refcount++; + return uctrl; +} + +struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl) +{ + if (uctrl == NULL) + return NULL; + uctrl->refcount--; + if (uctrl->refcount > 0) + return uctrl; + if (uctrl->sock >= 0) + close(uctrl->sock); + free(uctrl); + return NULL; +} + +int udev_ctrl_cleanup(struct udev_ctrl *uctrl) +{ + if (uctrl == NULL) + return 0; + if (uctrl->cleanup_socket) + unlink(uctrl->saddr.sun_path); + return 0; +} + +int udev_ctrl_get_fd(struct udev_ctrl *uctrl) +{ + if (uctrl == NULL) + 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 = {}; + const int on = 1; + int r; + + conn = new(struct udev_ctrl_connection, 1); + if (conn == NULL) + return NULL; + conn->refcount = 1; + conn->uctrl = uctrl; + + conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); + if (conn->sock < 0) { + if (errno != EINTR) + log_error("unable to receive ctrl connection: %m"); + goto err; + } + + /* check peer credential of connection */ + r = getpeercred(conn->sock, &ucred); + if (r < 0) { + log_error("unable to receive credentials of ctrl connection: %s", strerror(-r)); + goto err; + } + if (ucred.uid > 0) { + log_error("sender uid=%i, message ignored", ucred.uid); + goto err; + } + + /* enable receiving of the sender credentials in the messages */ + setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + udev_ctrl_ref(uctrl); + return conn; +err: + if (conn->sock >= 0) + close(conn->sock); + free(conn); + return NULL; +} + +struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn) +{ + if (conn == NULL) + return NULL; + conn->refcount++; + return conn; +} + +struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn) +{ + if (conn == NULL) + return NULL; + conn->refcount--; + if (conn->refcount > 0) + return conn; + if (conn->sock >= 0) + close(conn->sock); + udev_ctrl_unref(conn->uctrl); + free(conn); + return NULL; +} + +static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) +{ + struct udev_ctrl_msg_wire ctrl_msg_wire; + int err = 0; + + memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire)); + strcpy(ctrl_msg_wire.version, "udev-" VERSION); + ctrl_msg_wire.magic = UDEV_CTRL_MAGIC; + ctrl_msg_wire.type = type; + + if (buf != NULL) + strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf); + else + ctrl_msg_wire.intval = intval; + + if (!uctrl->connected) { + if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) { + err = -errno; + goto out; + } + uctrl->connected = true; + } + if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) { + err = -errno; + goto out; + } + + /* wait for peer message handling or disconnect */ + for (;;) { + struct pollfd pfd[1]; + int r; + + pfd[0].fd = uctrl->sock; + pfd[0].events = POLLIN; + r = poll(pfd, 1, timeout * 1000); + if (r < 0) { + if (errno == EINTR) + continue; + err = -errno; + break; + } + + if (r > 0 && pfd[0].revents & POLLERR) { + err = -EIO; + break; + } + + if (r == 0) + err = -ETIMEDOUT; + break; + } +out: + return err; +} + +int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout); +} + +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout); +} + +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout); +} + +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); +} + +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout); +} + +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout); +} + +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) +{ + return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); +} + +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int 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; + char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; + struct msghdr smsg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cred_msg, + .msg_controllen = sizeof(cred_msg), + }; + struct ucred *cred; + + uctrl_msg = new0(struct udev_ctrl_msg, 1); + if (uctrl_msg == NULL) + return NULL; + uctrl_msg->refcount = 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("ctrl connection error: %m"); + goto err; + } + } + + break; + } + + iov.iov_base = &uctrl_msg->ctrl_msg_wire; + iov.iov_len = sizeof(struct udev_ctrl_msg_wire); + + size = recvmsg(conn->sock, &smsg, 0); + if (size < 0) { + log_error("unable to receive ctrl message: %m"); + goto err; + } + cmsg = CMSG_FIRSTHDR(&smsg); + cred = (struct ucred *) CMSG_DATA(cmsg); + + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { + log_error("no sender credentials received, message ignored"); + goto err; + } + + if (cred->uid != 0) { + log_error("sender uid=%i, message ignored", cred->uid); + goto err; + } + + if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) { + log_error("message magic 0x%08x doesn't match, ignore it", uctrl_msg->ctrl_msg_wire.magic); + goto err; + } + + return uctrl_msg; +err: + udev_ctrl_msg_unref(uctrl_msg); + return NULL; +} + +struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg) +{ + if (ctrl_msg == NULL) + return NULL; + ctrl_msg->refcount--; + if (ctrl_msg->refcount > 0) + return ctrl_msg; + udev_ctrl_connection_unref(ctrl_msg->conn); + free(ctrl_msg); + return NULL; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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_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_get_ping(struct udev_ctrl_msg *ctrl_msg) +{ + if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING) + return 1; + return -1; +} + +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; +} diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c new file mode 100644 index 0000000..0b3ade0 --- /dev/null +++ b/src/udev/udev-event.c @@ -0,0 +1,912 @@ +/* + * Copyright (C) 2003-2013 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "rtnl-util.h" + +struct udev_event *udev_event_new(struct udev_device *dev) +{ + struct udev *udev = udev_device_get_udev(dev); + struct udev_event *event; + + event = new0(struct udev_event, 1); + if (event == NULL) + return NULL; + event->dev = dev; + event->udev = udev; + udev_list_init(udev, &event->run_list, false); + udev_list_init(udev, &event->seclabel_list, false); + event->fd_signal = -1; + event->birth_usec = now(CLOCK_MONOTONIC); + event->timeout_usec = 30 * 1000 * 1000; + return event; +} + +void udev_event_unref(struct udev_event *event) +{ + if (event == NULL) + return; + udev_list_cleanup(&event->run_list); + udev_list_cleanup(&event->seclabel_list); + free(event->program_result); + free(event->name); + free(event); +} + +size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size) +{ + struct udev_device *dev = event->dev; + enum subst_type { + SUBST_UNKNOWN, + SUBST_DEVNODE, + SUBST_ATTR, + SUBST_ENV, + SUBST_KERNEL, + SUBST_KERNEL_NUMBER, + SUBST_DRIVER, + SUBST_DEVPATH, + SUBST_ID, + SUBST_MAJOR, + SUBST_MINOR, + SUBST_RESULT, + SUBST_PARENT, + SUBST_NAME, + SUBST_LINKS, + SUBST_ROOT, + SUBST_SYS, + }; + static const struct subst_map { + const char *name; + const char fmt; + enum subst_type type; + } map[] = { + { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE }, + { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE }, + { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, + { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, + { .name = "env", .fmt = 'E', .type = SUBST_ENV }, + { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, + { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, + { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER }, + { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, + { .name = "id", .fmt = 'b', .type = SUBST_ID }, + { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, + { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, + { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, + { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, + { .name = "name", .fmt = 'D', .type = SUBST_NAME }, + { .name = "links", .fmt = 'L', .type = SUBST_LINKS }, + { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, + { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, + }; + const char *from; + char *s; + size_t l; + + from = src; + s = dest; + l = size; + + for (;;) { + enum subst_type type = SUBST_UNKNOWN; + char attrbuf[UTIL_PATH_SIZE]; + char *attr = NULL; + + while (from[0] != '\0') { + if (from[0] == '$') { + /* substitute named variable */ + unsigned int i; + + if (from[1] == '$') { + from++; + goto copy; + } + + for (i = 0; i < ELEMENTSOF(map); i++) { + if (startswith(&from[1], map[i].name)) { + type = map[i].type; + from += strlen(map[i].name)+1; + goto subst; + } + } + } else if (from[0] == '%') { + /* substitute format char */ + unsigned int i; + + if (from[1] == '%') { + from++; + goto copy; + } + + for (i = 0; i < ELEMENTSOF(map); i++) { + if (from[1] == map[i].fmt) { + type = map[i].type; + from += 2; + goto subst; + } + } + } +copy: + /* copy char */ + if (l == 0) + goto out; + s[0] = from[0]; + from++; + s++; + l--; + } + + goto out; +subst: + /* extract possible $format{attr} */ + if (from[0] == '{') { + unsigned int i; + + from++; + for (i = 0; from[i] != '}'; i++) { + if (from[i] == '\0') { + log_error("missing closing brace for format '%s'", src); + goto out; + } + } + if (i >= sizeof(attrbuf)) + goto out; + memcpy(attrbuf, from, i); + attrbuf[i] = '\0'; + from += i+1; + attr = attrbuf; + } else { + attr = NULL; + } + + switch (type) { + case SUBST_DEVPATH: + l = strpcpy(&s, l, udev_device_get_devpath(dev)); + break; + case SUBST_KERNEL: + l = strpcpy(&s, l, udev_device_get_sysname(dev)); + break; + case SUBST_KERNEL_NUMBER: + if (udev_device_get_sysnum(dev) == NULL) + break; + l = strpcpy(&s, l, udev_device_get_sysnum(dev)); + break; + case SUBST_ID: + if (event->dev_parent == NULL) + break; + l = strpcpy(&s, l, udev_device_get_sysname(event->dev_parent)); + break; + case SUBST_DRIVER: { + const char *driver; + + if (event->dev_parent == NULL) + break; + + driver = udev_device_get_driver(event->dev_parent); + if (driver == NULL) + break; + l = strpcpy(&s, l, driver); + break; + } + case SUBST_MAJOR: { + char num[UTIL_PATH_SIZE]; + + sprintf(num, "%d", major(udev_device_get_devnum(dev))); + l = strpcpy(&s, l, num); + break; + } + case SUBST_MINOR: { + char num[UTIL_PATH_SIZE]; + + sprintf(num, "%d", minor(udev_device_get_devnum(dev))); + l = strpcpy(&s, l, num); + break; + } + case SUBST_RESULT: { + char *rest; + int i; + + if (event->program_result == NULL) + break; + /* get part part of the result string */ + i = 0; + if (attr != NULL) + i = strtoul(attr, &rest, 10); + if (i > 0) { + char result[UTIL_PATH_SIZE]; + char tmp[UTIL_PATH_SIZE]; + char *cpos; + + strscpy(result, sizeof(result), event->program_result); + cpos = result; + while (--i) { + while (cpos[0] != '\0' && !isspace(cpos[0])) + cpos++; + while (isspace(cpos[0])) + cpos++; + } + if (i > 0) { + log_error("requested part of result string not found"); + break; + } + strscpy(tmp, sizeof(tmp), cpos); + /* %{2+}c copies the whole string from the second part on */ + if (rest[0] != '+') { + cpos = strchr(tmp, ' '); + if (cpos) + cpos[0] = '\0'; + } + l = strpcpy(&s, l, tmp); + } else { + l = strpcpy(&s, l, event->program_result); + } + break; + } + case SUBST_ATTR: { + const char *value = NULL; + char vbuf[UTIL_NAME_SIZE]; + size_t len; + int count; + + if (attr == NULL) { + log_error("missing file parameter for attr"); + break; + } + + /* try to read the value specified by "[dmi/id]product_name" */ + if (util_resolve_subsys_kernel(event->udev, attr, vbuf, sizeof(vbuf), 1) == 0) + value = vbuf; + + /* try to read the attribute the device */ + if (value == NULL) + value = udev_device_get_sysattr_value(event->dev, attr); + + /* try to read the attribute of the parent device, other matches have selected */ + if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev) + value = udev_device_get_sysattr_value(event->dev_parent, attr); + + if (value == NULL) + break; + + /* strip trailing whitespace, and replace unwanted characters */ + if (value != vbuf) + strscpy(vbuf, sizeof(vbuf), value); + len = strlen(vbuf); + while (len > 0 && isspace(vbuf[--len])) + vbuf[len] = '\0'; + count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT); + if (count > 0) + log_debug("%i character(s) replaced" , count); + l = strpcpy(&s, l, vbuf); + break; + } + case SUBST_PARENT: { + struct udev_device *dev_parent; + const char *devnode; + + dev_parent = udev_device_get_parent(event->dev); + if (dev_parent == NULL) + break; + devnode = udev_device_get_devnode(dev_parent); + if (devnode != NULL) + l = strpcpy(&s, l, devnode + strlen("/dev/")); + break; + } + case SUBST_DEVNODE: + if (udev_device_get_devnode(dev) != NULL) + l = strpcpy(&s, l, udev_device_get_devnode(dev)); + break; + case SUBST_NAME: + if (event->name != NULL) + l = strpcpy(&s, l, event->name); + else if (udev_device_get_devnode(dev) != NULL) + l = strpcpy(&s, l, udev_device_get_devnode(dev) + strlen("/dev/")); + else + l = strpcpy(&s, l, udev_device_get_sysname(dev)); + break; + case SUBST_LINKS: { + struct udev_list_entry *list_entry; + + list_entry = udev_device_get_devlinks_list_entry(dev); + if (list_entry == NULL) + break; + l = strpcpy(&s, l, udev_list_entry_get_name(list_entry) + strlen("/dev/")); + udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) + l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry) + strlen("/dev/"), NULL); + break; + } + case SUBST_ROOT: + l = strpcpy(&s, l, "/dev"); + break; + case SUBST_SYS: + l = strpcpy(&s, l, "/sys"); + break; + case SUBST_ENV: + if (attr == NULL) { + break; + } else { + const char *value; + + value = udev_device_get_property_value(event->dev, attr); + if (value == NULL) + break; + l = strpcpy(&s, l, value); + break; + } + default: + log_error("unknown substitution type=%i", type); + break; + } + } + +out: + s[0] = '\0'; + return l; +} + +static int spawn_exec(struct udev_event *event, + const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask, + int fd_stdout, int fd_stderr) +{ + int err; + int fd; + + /* discard child output or connect to pipe */ + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, STDIN_FILENO); + if (fd_stdout < 0) + dup2(fd, STDOUT_FILENO); + if (fd_stderr < 0) + dup2(fd, STDERR_FILENO); + close(fd); + } else { + log_error("open /dev/null failed: %m"); + } + + /* connect pipes to std{out,err} */ + if (fd_stdout >= 0) { + dup2(fd_stdout, STDOUT_FILENO); + close(fd_stdout); + } + if (fd_stderr >= 0) { + dup2(fd_stderr, STDERR_FILENO); + close(fd_stderr); + } + + /* terminate child in case parent goes away */ + prctl(PR_SET_PDEATHSIG, SIGTERM); + + /* restore original udev sigmask before exec */ + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, NULL); + + execve(argv[0], argv, envp); + + /* exec failed */ + err = -errno; + log_error("failed to execute '%s' '%s': %m", argv[0], cmd); + return err; +} + +static void spawn_read(struct udev_event *event, + const char *cmd, + int fd_stdout, int fd_stderr, + char *result, size_t ressize) +{ + size_t respos = 0; + int fd_ep = -1; + struct epoll_event ep_outpipe, ep_errpipe; + + /* read from child if requested */ + if (fd_stdout < 0 && fd_stderr < 0) + return; + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error("error creating epoll fd: %m"); + goto out; + } + + if (fd_stdout >= 0) { + memzero(&ep_outpipe, sizeof(struct epoll_event)); + ep_outpipe.events = EPOLLIN; + ep_outpipe.data.ptr = &fd_stdout; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe) < 0) { + log_error("fail to add fd to epoll: %m"); + goto out; + } + } + + if (fd_stderr >= 0) { + memzero(&ep_errpipe, sizeof(struct epoll_event)); + ep_errpipe.events = EPOLLIN; + ep_errpipe.data.ptr = &fd_stderr; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe) < 0) { + log_error("fail to add fd to epoll: %m"); + goto out; + } + } + + /* read child output */ + while (fd_stdout >= 0 || fd_stderr >= 0) { + int timeout; + int fdcount; + struct epoll_event ev[4]; + int i; + + if (event->timeout_usec > 0) { + usec_t age_usec; + + age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; + if (age_usec >= event->timeout_usec) { + log_error("timeout '%s'", cmd); + goto out; + } + timeout = ((event->timeout_usec - age_usec) / 1000) + 1000; + } else { + timeout = -1; + } + + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout); + if (fdcount < 0) { + if (errno == EINTR) + continue; + log_error("failed to poll: %m"); + goto out; + } + if (fdcount == 0) { + log_error("timeout '%s'", cmd); + goto out; + } + + for (i = 0; i < fdcount; i++) { + int *fd = (int *)ev[i].data.ptr; + + if (ev[i].events & EPOLLIN) { + ssize_t count; + char buf[4096]; + + count = read(*fd, buf, sizeof(buf)-1); + if (count <= 0) + continue; + buf[count] = '\0'; + + /* store stdout result */ + if (result != NULL && *fd == fd_stdout) { + if (respos + count < ressize) { + memcpy(&result[respos], buf, count); + respos += count; + } else { + log_error("'%s' ressize %zd too short", cmd, ressize); + } + } + + /* log debug output only if we watch stderr */ + if (fd_stderr >= 0) { + char *pos; + char *line; + + pos = buf; + while ((line = strsep(&pos, "\n"))) { + if (pos != NULL || line[0] != '\0') + log_debug("'%s'(%s) '%s'", cmd, *fd == fd_stdout ? "out" : "err" , line); + } + } + } else if (ev[i].events & EPOLLHUP) { + if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL) < 0) { + log_error("failed to remove fd from epoll: %m"); + goto out; + } + *fd = -1; + } + } + } + + /* return the child's stdout string */ + if (result != NULL) + result[respos] = '\0'; +out: + if (fd_ep >= 0) + close(fd_ep); +} + +static int spawn_wait(struct udev_event *event, const char *cmd, pid_t pid) +{ + struct pollfd pfd[1]; + int err = 0; + + pfd[0].events = POLLIN; + pfd[0].fd = event->fd_signal; + + while (pid > 0) { + int timeout; + int fdcount; + + if (event->timeout_usec > 0) { + usec_t age_usec; + + age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; + if (age_usec >= event->timeout_usec) + timeout = 1000; + else + timeout = ((event->timeout_usec - age_usec) / 1000) + 1000; + } else { + timeout = -1; + } + + fdcount = poll(pfd, 1, timeout); + if (fdcount < 0) { + if (errno == EINTR) + continue; + err = -errno; + log_error("failed to poll: %m"); + goto out; + } + if (fdcount == 0) { + log_error("timeout: killing '%s' [%u]", cmd, pid); + kill(pid, SIGKILL); + } + + if (pfd[0].revents & POLLIN) { + struct signalfd_siginfo fdsi; + int status; + ssize_t size; + + size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); + if (size != sizeof(struct signalfd_siginfo)) + continue; + + switch (fdsi.ssi_signo) { + case SIGTERM: + event->sigterm = true; + break; + case SIGCHLD: + if (waitpid(pid, &status, WNOHANG) < 0) + break; + if (WIFEXITED(status)) { + log_debug("'%s' [%u] exit with return code %i", cmd, pid, WEXITSTATUS(status)); + if (WEXITSTATUS(status) != 0) + err = -1; + } else if (WIFSIGNALED(status)) { + log_error("'%s' [%u] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status))); + err = -1; + } else if (WIFSTOPPED(status)) { + log_error("'%s' [%u] stopped", cmd, pid); + err = -1; + } else if (WIFCONTINUED(status)) { + log_error("'%s' [%u] continued", cmd, pid); + err = -1; + } else { + log_error("'%s' [%u] exit with status 0x%04x", cmd, pid, status); + err = -1; + } + pid = 0; + break; + } + } + } +out: + return err; +} + +int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) +{ + int i = 0; + char *pos; + + if (strchr(cmd, ' ') == NULL) { + argv[i++] = cmd; + goto out; + } + + pos = cmd; + while (pos != NULL && pos[0] != '\0') { + if (pos[0] == '\'') { + /* do not separate quotes */ + pos++; + argv[i] = strsep(&pos, "\'"); + if (pos != NULL) + while (pos[0] == ' ') + pos++; + } else { + argv[i] = strsep(&pos, " "); + if (pos != NULL) + while (pos[0] == ' ') + pos++; + } + i++; + } +out: + argv[i] = NULL; + if (argc) + *argc = i; + return 0; +} + +int udev_event_spawn(struct udev_event *event, + const char *cmd, char **envp, const sigset_t *sigmask, + char *result, size_t ressize) +{ + struct udev *udev = event->udev; + int outpipe[2] = {-1, -1}; + int errpipe[2] = {-1, -1}; + pid_t pid; + char arg[UTIL_PATH_SIZE]; + char *argv[128]; + char program[UTIL_PATH_SIZE]; + int err = 0; + + strscpy(arg, sizeof(arg), cmd); + udev_build_argv(event->udev, arg, NULL, argv); + + /* pipes from child to parent */ + if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) { + if (pipe2(outpipe, O_NONBLOCK) != 0) { + err = -errno; + log_error("pipe failed: %m"); + goto out; + } + } + if (udev_get_log_priority(udev) >= LOG_INFO) { + if (pipe2(errpipe, O_NONBLOCK) != 0) { + err = -errno; + log_error("pipe failed: %m"); + goto out; + } + } + + /* allow programs in /usr/lib/udev/ to be called without the path */ + if (argv[0][0] != '/') { + strscpyl(program, sizeof(program), UDEVLIBEXECDIR "/", argv[0], NULL); + argv[0] = program; + } + + pid = fork(); + switch(pid) { + case 0: + /* child closes parent's ends of pipes */ + if (outpipe[READ_END] >= 0) { + close(outpipe[READ_END]); + outpipe[READ_END] = -1; + } + if (errpipe[READ_END] >= 0) { + close(errpipe[READ_END]); + errpipe[READ_END] = -1; + } + + log_debug("starting '%s'", cmd); + + spawn_exec(event, cmd, argv, envp, sigmask, + outpipe[WRITE_END], errpipe[WRITE_END]); + + _exit(2 ); + case -1: + log_error("fork of '%s' failed: %m", cmd); + err = -1; + goto out; + default: + /* parent closed child's ends of pipes */ + if (outpipe[WRITE_END] >= 0) { + close(outpipe[WRITE_END]); + outpipe[WRITE_END] = -1; + } + if (errpipe[WRITE_END] >= 0) { + close(errpipe[WRITE_END]); + errpipe[WRITE_END] = -1; + } + + spawn_read(event, cmd, + outpipe[READ_END], errpipe[READ_END], + result, ressize); + + err = spawn_wait(event, cmd, pid); + } + +out: + if (outpipe[READ_END] >= 0) + close(outpipe[READ_END]); + if (outpipe[WRITE_END] >= 0) + close(outpipe[WRITE_END]); + if (errpipe[READ_END] >= 0) + close(errpipe[READ_END]); + if (errpipe[WRITE_END] >= 0) + close(errpipe[WRITE_END]); + return err; +} + +static int rename_netif(struct udev_event *event) +{ + struct udev_device *dev = event->dev; + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + char name[IFNAMSIZ]; + const char *oldname; + int r; + + oldname = udev_device_get_sysname(dev); + + log_debug("changing net interface name from '%s' to '%s'", + oldname, event->name); + + strscpy(name, IFNAMSIZ, event->name); + + r = sd_rtnl_open(&rtnl, 0); + if (r < 0) + return r; + + r = rtnl_set_link_name(rtnl, udev_device_get_ifindex(dev), name); + if (r < 0) + log_error("error changing net interface name %s to %s: %s", + oldname, name, strerror(-r)); + else + print_kmsg("renamed network interface %s to %s", oldname, name); + + return r; +} + +int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigmask) +{ + struct udev_device *dev = event->dev; + int err = 0; + + if (udev_device_get_subsystem(dev) == NULL) + return -1; + + if (streq(udev_device_get_action(dev), "remove")) { + udev_device_read_db(dev, NULL); + udev_device_delete_db(dev); + udev_device_tag_index(dev, NULL, false); + + if (major(udev_device_get_devnum(dev)) != 0) + udev_watch_end(event->udev, dev); + + udev_rules_apply_to_event(rules, event, sigmask); + + if (major(udev_device_get_devnum(dev)) != 0) + udev_node_remove(dev); + } else { + event->dev_db = udev_device_new(event->udev); + if (event->dev_db != NULL) { + udev_device_set_syspath(event->dev_db, udev_device_get_syspath(dev)); + udev_device_set_subsystem(event->dev_db, udev_device_get_subsystem(dev)); + udev_device_read_db(event->dev_db, NULL); + udev_device_set_info_loaded(event->dev_db); + + /* disable watch during event processing */ + if (major(udev_device_get_devnum(dev)) != 0) + udev_watch_end(event->udev, event->dev_db); + } + + udev_rules_apply_to_event(rules, event, sigmask); + + /* rename a new network interface, if needed */ + if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && + event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) { + char syspath[UTIL_PATH_SIZE]; + char *pos; + + err = rename_netif(event); + if (err == 0) { + log_debug("renamed netif to '%s'", event->name); + + /* remember old name */ + udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev)); + + /* now change the devpath, because the kernel device name has changed */ + strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev)); + pos = strrchr(syspath, '/'); + if (pos != NULL) { + pos++; + strscpy(pos, sizeof(syspath) - (pos - syspath), event->name); + udev_device_set_syspath(event->dev, syspath); + udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev)); + log_debug("changed devpath to '%s'", udev_device_get_devpath(dev)); + } + } + } + + if (major(udev_device_get_devnum(dev)) > 0) { + bool apply; + + /* remove/update possible left-over symlinks from old database entry */ + if (event->dev_db != NULL) + udev_node_update_old_links(dev, event->dev_db); + + if (!event->owner_set) + event->uid = udev_device_get_devnode_uid(dev); + + if (!event->group_set) + event->gid = udev_device_get_devnode_gid(dev); + + if (!event->mode_set) { + if (udev_device_get_devnode_mode(dev) > 0) { + /* kernel supplied value */ + event->mode = udev_device_get_devnode_mode(dev); + } else if (event->gid > 0) { + /* default 0660 if a group is assigned */ + event->mode = 0660; + } else { + /* default 0600 */ + event->mode = 0600; + } + } + + apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; + udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list); + } + + /* preserve old, or get new initialization timestamp */ + if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0) + udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db)); + else if (udev_device_get_usec_initialized(event->dev) == 0) + udev_device_set_usec_initialized(event->dev, now(CLOCK_MONOTONIC)); + + /* (re)write database file */ + udev_device_update_db(dev); + udev_device_tag_index(dev, event->dev_db, true); + udev_device_set_is_initialized(dev); + + udev_device_unref(event->dev_db); + event->dev_db = NULL; + } + return err; +} + +void udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask) +{ + struct udev_list_entry *list_entry; + + udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) { + const char *cmd = udev_list_entry_get_name(list_entry); + enum udev_builtin_cmd builtin_cmd = udev_list_entry_get_num(list_entry); + + if (builtin_cmd < UDEV_BUILTIN_MAX) { + char command[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, cmd, command, sizeof(command)); + udev_builtin_run(event->dev, builtin_cmd, command, false); + } else { + char program[UTIL_PATH_SIZE]; + char **envp; + + if (event->exec_delay > 0) { + log_debug("delay execution of '%s'", program); + sleep(event->exec_delay); + } + + udev_event_apply_format(event, cmd, program, sizeof(program)); + envp = udev_device_get_properties_envp(event->dev); + udev_event_spawn(event, program, envp, sigmask, NULL, 0); + } + } +} diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c new file mode 100644 index 0000000..0b0e9e0 --- /dev/null +++ b/src/udev/udev-node.c @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2003-2013 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "smack-util.h" + +static int node_symlink(struct udev_device *dev, const char *node, const char *slink) +{ + struct stat stats; + char target[UTIL_PATH_SIZE]; + char *s; + size_t l; + char slink_tmp[UTIL_PATH_SIZE + 32]; + int i = 0; + int tail = 0; + int err = 0; + + /* use relative link */ + target[0] = '\0'; + while (node[i] && (node[i] == slink[i])) { + if (node[i] == '/') + tail = i+1; + i++; + } + s = target; + l = sizeof(target); + while (slink[i] != '\0') { + if (slink[i] == '/') + l = strpcpy(&s, l, "../"); + i++; + } + l = strscpy(s, l, &node[tail]); + if (l == 0) { + err = -EINVAL; + goto exit; + } + + /* preserve link with correct target, do not replace node of other device */ + if (lstat(slink, &stats) == 0) { + if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) { + log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node); + goto exit; + } else if (S_ISLNK(stats.st_mode)) { + char buf[UTIL_PATH_SIZE]; + int len; + + len = readlink(slink, buf, sizeof(buf)); + if (len > 0 && len < (int)sizeof(buf)) { + buf[len] = '\0'; + if (streq(target, buf)) { + log_debug("preserve already existing symlink '%s' to '%s'", slink, target); + label_fix(slink, true, false); + utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); + goto exit; + } + } + } + } else { + log_debug("creating symlink '%s' to '%s'", slink, target); + do { + err = mkdir_parents_label(slink, 0755); + if (err != 0 && err != -ENOENT) + break; + label_context_set(slink, S_IFLNK); + err = symlink(target, slink); + if (err != 0) + err = -errno; + label_context_clear(); + } while (err == -ENOENT); + if (err == 0) + goto exit; + } + + log_debug("atomically replace '%s'", slink); + strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL); + unlink(slink_tmp); + do { + err = mkdir_parents_label(slink_tmp, 0755); + if (err != 0 && err != -ENOENT) + break; + label_context_set(slink_tmp, S_IFLNK); + err = symlink(target, slink_tmp); + if (err != 0) + err = -errno; + label_context_clear(); + } while (err == -ENOENT); + if (err != 0) { + log_error("symlink '%s' '%s' failed: %m", target, slink_tmp); + goto exit; + } + err = rename(slink_tmp, slink); + if (err != 0) { + log_error("rename '%s' '%s' failed: %m", slink_tmp, slink); + unlink(slink_tmp); + } +exit: + return err; +} + +/* find device node of device with highest priority */ +static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) +{ + struct udev *udev = udev_device_get_udev(dev); + DIR *dir; + int priority = 0; + const char *target = NULL; + + if (add) { + priority = udev_device_get_devlink_priority(dev); + strscpy(buf, bufsize, udev_device_get_devnode(dev)); + target = buf; + } + + dir = opendir(stackdir); + if (dir == NULL) + return target; + for (;;) { + struct udev_device *dev_db; + struct dirent *dent; + + dent = readdir(dir); + if (dent == NULL || dent->d_name[0] == '\0') + break; + if (dent->d_name[0] == '.') + continue; + + log_debug("found '%s' claiming '%s'", dent->d_name, stackdir); + + /* did we find ourself? */ + if (streq(dent->d_name, udev_device_get_id_filename(dev))) + continue; + + dev_db = udev_device_new_from_device_id(udev, dent->d_name); + if (dev_db != NULL) { + const char *devnode; + + devnode = udev_device_get_devnode(dev_db); + if (devnode != NULL) { + if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { + log_debug("'%s' claims priority %i for '%s'", + udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); + priority = udev_device_get_devlink_priority(dev_db); + strscpy(buf, bufsize, devnode); + target = buf; + } + } + udev_device_unref(dev_db); + } + } + closedir(dir); + return target; +} + +/* manage "stack of names" with possibly specified device priorities */ +static void link_update(struct udev_device *dev, const char *slink, bool add) +{ + struct udev *udev = udev_device_get_udev(dev); + char name_enc[UTIL_PATH_SIZE]; + char filename[UTIL_PATH_SIZE * 2]; + char dirname[UTIL_PATH_SIZE]; + const char *target; + char buf[UTIL_PATH_SIZE]; + + util_path_encode(slink + strlen("/dev"), name_enc, sizeof(name_enc)); + strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL); + strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); + + if (!add && unlink(filename) == 0) + rmdir(dirname); + + target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); + if (target == NULL) { + log_debug("no reference left, remove '%s'", slink); + if (unlink(slink) == 0) + util_delete_path(udev, slink); + } else { + log_debug("creating link '%s' to '%s'", slink, target); + node_symlink(dev, target, slink); + } + + if (add) { + int err; + + do { + int fd; + + err = mkdir_parents(filename, 0755); + if (err != 0 && err != -ENOENT) + break; + fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); + if (fd >= 0) + close(fd); + else + err = -errno; + } while (err == -ENOENT); + } +} + +void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) +{ + struct udev_list_entry *list_entry; + + /* update possible left-over symlinks */ + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { + const char *name = udev_list_entry_get_name(list_entry); + struct udev_list_entry *list_entry_current; + int found; + + /* check if old link name still belongs to this device */ + found = 0; + udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { + const char *name_current = udev_list_entry_get_name(list_entry_current); + + if (streq(name, name_current)) { + found = 1; + break; + } + } + if (found) + continue; + + log_debug("update old name, '%s' no longer belonging to '%s'", + name, udev_device_get_devpath(dev)); + link_update(dev, name, false); + } +} + +static int node_permissions_apply(struct udev_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, + struct udev_list *seclabel_list) { + const char *devnode = udev_device_get_devnode(dev); + dev_t devnum = udev_device_get_devnum(dev); + struct stat stats; + struct udev_list_entry *entry; + int err = 0; + + if (streq(udev_device_get_subsystem(dev), "block")) + mode |= S_IFBLK; + else + mode |= S_IFCHR; + + if (lstat(devnode, &stats) != 0) { + err = -errno; + log_debug("can not stat() node '%s' (%m)", devnode); + goto out; + } + + if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { + err = -EEXIST; + log_debug("found node '%s' with non-matching devnum %s, skip handling", + udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); + goto out; + } + + if (apply) { + bool selinux = false; + bool smack = false; + + if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { + log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); + chmod(devnode, mode); + chown(devnode, uid, gid); + } else { + log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); + } + + /* apply SECLABEL{$module}=$label */ + udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) { + const char *name, *label; + + name = udev_list_entry_get_name(entry); + label = udev_list_entry_get_value(entry); + + if (streq(name, "selinux")) { + selinux = true; + if (label_apply(devnode, label) < 0) + log_error("SECLABEL: failed to set SELinux label '%s'", label); + else + log_debug("SECLABEL: set SELinux label '%s'", label); + + } else if (streq(name, "smack")) { + smack = true; + if (smack_label_path(devnode, label) < 0) + log_error("SECLABEL: failed to set SMACK label '%s'", label); + else + log_debug("SECLABEL: set SMACK label '%s'", label); + + } else + log_error("SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label); + } + + /* set the defaults */ + if (!selinux && use_selinux()) + label_fix_selinux(devnode, true, false); + if (!smack) + smack_label_path(devnode, NULL); + } + + /* always update timestamp when we re-use the node, like on media change events */ + utimensat(AT_FDCWD, devnode, NULL, 0); +out: + return err; +} + +void udev_node_add(struct udev_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, + struct udev_list *seclabel_list) { + char filename[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + + log_debug("handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d", + udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); + + if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0) + return; + + /* always add /dev/{block,char}/$major:$minor */ + snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", + streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", + major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); + node_symlink(dev, udev_device_get_devnode(dev), filename); + + /* create/update symlinks, add symlinks to name index */ + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) + link_update(dev, udev_list_entry_get_name(list_entry), true); +} + +void udev_node_remove(struct udev_device *dev) +{ + struct udev_list_entry *list_entry; + char filename[UTIL_PATH_SIZE]; + + /* remove/update symlinks, remove symlinks from name index */ + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) + link_update(dev, udev_list_entry_get_name(list_entry), false); + + /* remove /dev/{block,char}/$major:$minor */ + snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", + streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", + major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); + unlink(filename); +} diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c new file mode 100644 index 0000000..47bde61 --- /dev/null +++ b/src/udev/udev-rules.c @@ -0,0 +1,2648 @@ +/* + * Copyright (C) 2003-2012 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "path-util.h" +#include "conf-files.h" +#include "strbuf.h" +#include "strv.h" +#include "util.h" + +#define PREALLOC_TOKEN 2048 + +struct uid_gid { + unsigned int name_off; + union { + uid_t uid; + gid_t gid; + }; +}; + +static const char* const rules_dirs[] = { + "/etc/udev/rules.d", + "/run/udev/rules.d", + UDEVLIBEXECDIR "/rules.d", + NULL}; + +struct udev_rules { + struct udev *udev; + usec_t dirs_ts_usec; + int resolve_names; + + /* every key in the rules file becomes a token */ + struct token *tokens; + unsigned int token_cur; + unsigned int 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 int uids_cur; + unsigned int uids_max; + struct uid_gid *gids; + unsigned int gids_cur; + unsigned int gids_max; +}; + +static char *rules_str(struct udev_rules *rules, unsigned int off) { + return rules->strbuf->buf + off; +} + +static unsigned int rules_add_string(struct udev_rules *rules, const char *s) { + return strbuf_add_string(rules->strbuf, s, strlen(s)); +} + +/* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */ +enum operation_type { + OP_UNSET, + + OP_MATCH, + OP_NOMATCH, + OP_MATCH_MAX, + + OP_ADD, + OP_ASSIGN, + OP_ASSIGN_FINAL, +}; + +enum string_glob_type { + GL_UNSET, + GL_PLAIN, /* no special chars */ + GL_GLOB, /* shell globs ?,*,[] */ + GL_SPLIT, /* multi-value A|B */ + GL_SPLIT_GLOB, /* multi-value with glob A*|B* */ + GL_SOMETHING, /* commonly used "?*" */ +}; + +enum string_subst_type { + SB_UNSET, + SB_NONE, + SB_FORMAT, + SB_SUBSYS, +}; + +/* tokens of a rule are sorted/handled in this order */ +enum token_type { + TK_UNSET, + TK_RULE, + + TK_M_ACTION, /* val */ + TK_M_DEVPATH, /* val */ + TK_M_KERNEL, /* val */ + TK_M_DEVLINK, /* val */ + TK_M_NAME, /* val */ + TK_M_ENV, /* val, attr */ + TK_M_TAG, /* val */ + TK_M_SUBSYSTEM, /* val */ + TK_M_DRIVER, /* val */ + TK_M_WAITFOR, /* val */ + TK_M_ATTR, /* val, attr */ + + TK_M_PARENTS_MIN, + TK_M_KERNELS, /* val */ + TK_M_SUBSYSTEMS, /* val */ + TK_M_DRIVERS, /* val */ + TK_M_ATTRS, /* val, attr */ + TK_M_TAGS, /* val */ + TK_M_PARENTS_MAX, + + TK_M_TEST, /* val, mode_t */ + TK_M_EVENT_TIMEOUT, /* int */ + TK_M_PROGRAM, /* val */ + TK_M_IMPORT_FILE, /* val */ + TK_M_IMPORT_PROG, /* val */ + TK_M_IMPORT_BUILTIN, /* val */ + TK_M_IMPORT_DB, /* val */ + TK_M_IMPORT_CMDLINE, /* val */ + TK_M_IMPORT_PARENT, /* val */ + TK_M_RESULT, /* val */ + TK_M_MAX, + + TK_A_STRING_ESCAPE_NONE, + TK_A_STRING_ESCAPE_REPLACE, + TK_A_DB_PERSIST, + TK_A_INOTIFY_WATCH, /* int */ + TK_A_DEVLINK_PRIO, /* int */ + TK_A_OWNER, /* val */ + TK_A_GROUP, /* val */ + TK_A_MODE, /* val */ + TK_A_OWNER_ID, /* uid_t */ + TK_A_GROUP_ID, /* gid_t */ + TK_A_MODE_ID, /* mode_t */ + TK_A_TAG, /* val */ + TK_A_STATIC_NODE, /* val */ + TK_A_SECLABEL, /* val, attr */ + TK_A_ENV, /* val, attr */ + TK_A_NAME, /* val */ + TK_A_DEVLINK, /* val */ + TK_A_ATTR, /* val, attr */ + TK_A_RUN_BUILTIN, /* val, bool */ + TK_A_RUN_PROGRAM, /* val, bool */ + TK_A_GOTO, /* size_t */ + + TK_END, +}; + +/* we try to pack stuff in a way that we take only 12 bytes per token */ +struct token { + union { + unsigned char type; /* same in rule and key */ + struct { + enum token_type type:8; + bool can_set_name:1; + bool has_static_node:1; + unsigned int unused:6; + unsigned short token_count; + unsigned int label_off; + unsigned short filename_off; + unsigned short filename_line; + } rule; + struct { + enum token_type type:8; + enum operation_type op:8; + enum string_glob_type glob:8; + enum string_subst_type subst:4; + enum string_subst_type attrsubst:4; + unsigned int value_off; + union { + unsigned int attr_off; + unsigned int rule_goto; + mode_t mode; + uid_t uid; + gid_t gid; + int devlink_prio; + int event_timeout; + int watch; + enum udev_builtin_cmd builtin_cmd; + }; + } key; + }; +}; + +#define MAX_TK 64 +struct rule_tmp { + struct udev_rules *rules; + struct token rule; + struct token token[MAX_TK]; + unsigned int token_cur; +}; + +#ifdef DEBUG +static const char *operation_str(enum operation_type type) +{ + static const char *operation_strs[] = { + [OP_UNSET] = "UNSET", + [OP_MATCH] = "match", + [OP_NOMATCH] = "nomatch", + [OP_MATCH_MAX] = "MATCH_MAX", + + [OP_ADD] = "add", + [OP_ASSIGN] = "assign", + [OP_ASSIGN_FINAL] = "assign-final", +} ; + + return operation_strs[type]; +} + +static const char *string_glob_str(enum string_glob_type type) +{ + static const char *string_glob_strs[] = { + [GL_UNSET] = "UNSET", + [GL_PLAIN] = "plain", + [GL_GLOB] = "glob", + [GL_SPLIT] = "split", + [GL_SPLIT_GLOB] = "split-glob", + [GL_SOMETHING] = "split-glob", + }; + + return string_glob_strs[type]; +} + +static const char *token_str(enum token_type type) +{ + static const char *token_strs[] = { + [TK_UNSET] = "UNSET", + [TK_RULE] = "RULE", + + [TK_M_ACTION] = "M ACTION", + [TK_M_DEVPATH] = "M DEVPATH", + [TK_M_KERNEL] = "M KERNEL", + [TK_M_DEVLINK] = "M DEVLINK", + [TK_M_NAME] = "M NAME", + [TK_M_ENV] = "M ENV", + [TK_M_TAG] = "M TAG", + [TK_M_SUBSYSTEM] = "M SUBSYSTEM", + [TK_M_DRIVER] = "M DRIVER", + [TK_M_WAITFOR] = "M WAITFOR", + [TK_M_ATTR] = "M ATTR", + + [TK_M_PARENTS_MIN] = "M PARENTS_MIN", + [TK_M_KERNELS] = "M KERNELS", + [TK_M_SUBSYSTEMS] = "M SUBSYSTEMS", + [TK_M_DRIVERS] = "M DRIVERS", + [TK_M_ATTRS] = "M ATTRS", + [TK_M_TAGS] = "M TAGS", + [TK_M_PARENTS_MAX] = "M PARENTS_MAX", + + [TK_M_TEST] = "M TEST", + [TK_M_EVENT_TIMEOUT] = "M EVENT_TIMEOUT", + [TK_M_PROGRAM] = "M PROGRAM", + [TK_M_IMPORT_FILE] = "M IMPORT_FILE", + [TK_M_IMPORT_PROG] = "M IMPORT_PROG", + [TK_M_IMPORT_BUILTIN] = "M IMPORT_BUILTIN", + [TK_M_IMPORT_DB] = "M IMPORT_DB", + [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE", + [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT", + [TK_M_RESULT] = "M RESULT", + [TK_M_MAX] = "M MAX", + + [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE", + [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE", + [TK_A_DB_PERSIST] = "A DB_PERSIST", + [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH", + [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO", + [TK_A_OWNER] = "A OWNER", + [TK_A_GROUP] = "A GROUP", + [TK_A_MODE] = "A MODE", + [TK_A_OWNER_ID] = "A OWNER_ID", + [TK_A_GROUP_ID] = "A GROUP_ID", + [TK_A_STATIC_NODE] = "A STATIC_NODE", + [TK_A_SECLABEL] = "A SECLABEL", + [TK_A_MODE_ID] = "A MODE_ID", + [TK_A_ENV] = "A ENV", + [TK_A_TAG] = "A ENV", + [TK_A_NAME] = "A NAME", + [TK_A_DEVLINK] = "A DEVLINK", + [TK_A_ATTR] = "A ATTR", + [TK_A_RUN_BUILTIN] = "A RUN_BUILTIN", + [TK_A_RUN_PROGRAM] = "A RUN_PROGRAM", + [TK_A_GOTO] = "A GOTO", + + [TK_END] = "END", + }; + + return token_strs[type]; +} + +static void dump_token(struct udev_rules *rules, struct token *token) +{ + enum token_type type = token->type; + enum operation_type op = token->key.op; + enum string_glob_type glob = token->key.glob; + const char *value = str(rules, token->key.value_off); + const char *attr = &rules->buf[token->key.attr_off]; + + switch (type) { + case TK_RULE: + { + const char *tks_ptr = (char *)rules->tokens; + const char *tk_ptr = (char *)token; + unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token); + + log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'", + &rules->buf[token->rule.filename_off], token->rule.filename_line, + idx, token->rule.token_count, + &rules->buf[token->rule.label_off]); + break; + } + case TK_M_ACTION: + case TK_M_DEVPATH: + case TK_M_KERNEL: + case TK_M_SUBSYSTEM: + case TK_M_DRIVER: + case TK_M_WAITFOR: + case TK_M_DEVLINK: + case TK_M_NAME: + case TK_M_KERNELS: + case TK_M_SUBSYSTEMS: + case TK_M_DRIVERS: + case TK_M_TAGS: + case TK_M_PROGRAM: + case TK_M_IMPORT_FILE: + case TK_M_IMPORT_PROG: + case TK_M_IMPORT_DB: + case TK_M_IMPORT_CMDLINE: + case TK_M_IMPORT_PARENT: + case TK_M_RESULT: + case TK_A_NAME: + case TK_A_DEVLINK: + case TK_A_OWNER: + case TK_A_GROUP: + case TK_A_MODE: + case TK_A_RUN_BUILTIN: + case TK_A_RUN_PROGRAM: + log_debug("%s %s '%s'(%s)", + token_str(type), operation_str(op), value, string_glob_str(glob)); + break; + case TK_M_IMPORT_BUILTIN: + log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value); + break; + case TK_M_ATTR: + case TK_M_ATTRS: + case TK_M_ENV: + case TK_A_ATTR: + case TK_A_ENV: + log_debug("%s %s '%s' '%s'(%s)", + token_str(type), operation_str(op), attr, value, string_glob_str(glob)); + break; + case TK_M_TAG: + case TK_A_TAG: + log_debug("%s %s '%s'", token_str(type), operation_str(op), value); + break; + case TK_A_STRING_ESCAPE_NONE: + case TK_A_STRING_ESCAPE_REPLACE: + case TK_A_DB_PERSIST: + log_debug("%s", token_str(type)); + break; + case TK_M_TEST: + log_debug("%s %s '%s'(%s) %#o", + token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode); + break; + case TK_A_INOTIFY_WATCH: + log_debug("%s %u", token_str(type), token->key.watch); + break; + case TK_A_DEVLINK_PRIO: + log_debug("%s %u", token_str(type), token->key.devlink_prio); + break; + case TK_A_OWNER_ID: + log_debug("%s %s %u", token_str(type), operation_str(op), token->key.uid); + break; + case TK_A_GROUP_ID: + log_debug("%s %s %u", token_str(type), operation_str(op), token->key.gid); + break; + case TK_A_MODE_ID: + log_debug("%s %s %#o", token_str(type), operation_str(op), token->key.mode); + break; + case TK_A_STATIC_NODE: + log_debug("%s '%s'", token_str(type), value); + break; + case TK_A_SECLABEL: + log_debug("%s %s '%s' '%s'", token_str(type), operation_str(op), attr, value); + break; + case TK_M_EVENT_TIMEOUT: + log_debug("%s %u", token_str(type), token->key.event_timeout); + break; + case TK_A_GOTO: + log_debug("%s '%s' %u", token_str(type), value, token->key.rule_goto); + break; + case TK_END: + log_debug("* %s", token_str(type)); + break; + case TK_M_PARENTS_MIN: + case TK_M_PARENTS_MAX: + case TK_M_MAX: + case TK_UNSET: + log_debug("unknown type %u", type); + break; + } +} + +static void dump_rules(struct udev_rules *rules) +{ + unsigned int i; + + log_debug("dumping %u (%zu bytes) tokens, %u (%zu bytes) strings", + rules->token_cur, + rules->token_cur * sizeof(struct token), + rules->buf_count, + rules->buf_cur); + for (i = 0; i < rules->token_cur; i++) + dump_token(rules, &rules->tokens[i]); +} +#else +static inline void dump_token(struct udev_rules *rules, struct token *token) {} +static inline void dump_rules(struct udev_rules *rules) {} +#endif /* DEBUG */ + +static int add_token(struct udev_rules *rules, struct token *token) +{ + /* grow buffer if needed */ + if (rules->token_cur+1 >= rules->token_max) { + struct token *tokens; + unsigned int add; + + /* double the buffer size */ + add = rules->token_max; + if (add < 8) + add = 8; + + tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token)); + if (tokens == NULL) + return -1; + rules->tokens = tokens; + rules->token_max += add; + } + memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token)); + rules->token_cur++; + return 0; +} + +static uid_t add_uid(struct udev_rules *rules, const char *owner) +{ + unsigned int i; + uid_t uid; + unsigned int off; + + /* 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; + } + } + uid = util_lookup_user(rules->udev, owner); + + /* grow buffer if needed */ + if (rules->uids_cur+1 >= rules->uids_max) { + struct uid_gid *uids; + unsigned int add; + + /* double the buffer size */ + add = rules->uids_max; + if (add < 1) + add = 8; + + uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid)); + if (uids == NULL) + return uid; + rules->uids = uids; + rules->uids_max += add; + } + rules->uids[rules->uids_cur].uid = uid; + off = rules_add_string(rules, owner); + if (off <= 0) + return uid; + rules->uids[rules->uids_cur].name_off = off; + rules->uids_cur++; + return uid; +} + +static gid_t add_gid(struct udev_rules *rules, const char *group) +{ + unsigned int i; + gid_t gid; + unsigned int off; + + /* 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; + } + } + gid = util_lookup_group(rules->udev, group); + + /* grow buffer if needed */ + if (rules->gids_cur+1 >= rules->gids_max) { + struct uid_gid *gids; + unsigned int add; + + /* double the buffer size */ + add = rules->gids_max; + if (add < 1) + add = 8; + + gids = realloc(rules->gids, (rules->gids_max + add ) * sizeof(struct uid_gid)); + if (gids == NULL) + return gid; + rules->gids = gids; + rules->gids_max += add; + } + rules->gids[rules->gids_cur].gid = gid; + off = rules_add_string(rules, group); + if (off <= 0) + return gid; + rules->gids[rules->gids_cur].name_off = off; + rules->gids_cur++; + return gid; +} + +static int import_property_from_string(struct udev_device *dev, char *line) +{ + char *key; + char *val; + size_t len; + struct udev_list_entry *entry; + + /* find key */ + key = line; + while (isspace(key[0])) + key++; + + /* comment or empty line */ + if (key[0] == '#' || key[0] == '\0') + return -1; + + /* split key/value */ + val = strchr(key, '='); + if (val == NULL) + return -1; + val[0] = '\0'; + val++; + + /* find value */ + while (isspace(val[0])) + val++; + + /* terminate key */ + len = strlen(key); + if (len == 0) + return -1; + while (isspace(key[len-1])) + len--; + key[len] = '\0'; + + /* terminate value */ + len = strlen(val); + if (len == 0) + return -1; + while (isspace(val[len-1])) + len--; + val[len] = '\0'; + + if (len == 0) + return -1; + + /* unquote */ + if (val[0] == '"' || val[0] == '\'') { + if (val[len-1] != val[0]) { + log_debug("inconsistent quoting: '%s', skip", line); + return -1; + } + val[len-1] = '\0'; + val++; + } + + entry = udev_device_add_property(dev, key, val); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_num(entry, true); + + return 0; +} + +static int import_file_into_properties(struct udev_device *dev, const char *filename) +{ + FILE *f; + char line[UTIL_LINE_SIZE]; + + f = fopen(filename, "re"); + if (f == NULL) + return -1; + while (fgets(line, sizeof(line), f) != NULL) + import_property_from_string(dev, line); + fclose(f); + return 0; +} + +static int import_program_into_properties(struct udev_event *event, const char *program, const sigset_t *sigmask) +{ + struct udev_device *dev = event->dev; + char **envp; + char result[UTIL_LINE_SIZE]; + char *line; + int err; + + envp = udev_device_get_properties_envp(dev); + err = udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)); + if (err < 0) + return err; + + line = result; + while (line != NULL) { + char *pos; + + pos = strchr(line, '\n'); + if (pos != NULL) { + pos[0] = '\0'; + pos = &pos[1]; + } + import_property_from_string(dev, line); + line = pos; + } + return 0; +} + +static int import_parent_into_properties(struct udev_device *dev, const char *filter) +{ + struct udev_device *dev_parent; + struct udev_list_entry *list_entry; + + dev_parent = udev_device_get_parent(dev); + if (dev_parent == NULL) + return -1; + + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) { + const char *key = udev_list_entry_get_name(list_entry); + const char *val = udev_list_entry_get_value(list_entry); + + if (fnmatch(filter, key, 0) == 0) { + struct udev_list_entry *entry; + + entry = udev_device_add_property(dev, key, val); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_num(entry, true); + } + } + return 0; +} + +#define WAIT_LOOP_PER_SECOND 50 +static int wait_for_file(struct udev_device *dev, const char *file, int timeout) +{ + char filepath[UTIL_PATH_SIZE]; + char devicepath[UTIL_PATH_SIZE]; + struct stat stats; + int loop = timeout * WAIT_LOOP_PER_SECOND; + + /* a relative path is a device attribute */ + devicepath[0] = '\0'; + if (file[0] != '/') { + strscpyl(devicepath, sizeof(devicepath), udev_device_get_syspath(dev), NULL); + strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL); + file = filepath; + } + + while (--loop) { + const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND }; + + /* lookup file */ + if (stat(file, &stats) == 0) { + log_debug("file '%s' appeared after %i loops", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1); + return 0; + } + /* make sure, the device did not disappear in the meantime */ + if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) { + log_debug("device disappeared while waiting for '%s'", file); + return -2; + } + log_debug("wait for '%s' for %i mseconds", file, 1000 / WAIT_LOOP_PER_SECOND); + nanosleep(&duration, NULL); + } + log_debug("waiting for '%s' failed", file); + return -1; +} + +static int attr_subst_subdir(char *attr, size_t len) +{ + bool found = false; + + if (strstr(attr, "/*/")) { + char *pos; + char dirname[UTIL_PATH_SIZE]; + const char *tail; + DIR *dir; + + strscpy(dirname, sizeof(dirname), attr); + pos = strstr(dirname, "/*/"); + if (pos == NULL) + return -1; + pos[0] = '\0'; + tail = &pos[2]; + dir = opendir(dirname); + if (dir != NULL) { + struct dirent *dent; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct stat stats; + + if (dent->d_name[0] == '.') + continue; + strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL); + if (stat(attr, &stats) == 0) { + found = true; + break; + } + } + closedir(dir); + } + } + + return found; +} + +static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) +{ + char *linepos; + char *temp; + + linepos = *line; + if (linepos == NULL || linepos[0] == '\0') + return -1; + + /* skip whitespace */ + while (isspace(linepos[0]) || linepos[0] == ',') + linepos++; + + /* get the key */ + if (linepos[0] == '\0') + return -1; + *key = linepos; + + for (;;) { + linepos++; + if (linepos[0] == '\0') + return -1; + if (isspace(linepos[0])) + break; + if (linepos[0] == '=') + break; + if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':')) + if (linepos[1] == '=') + break; + } + + /* remember end of key */ + temp = linepos; + + /* skip whitespace after key */ + while (isspace(linepos[0])) + linepos++; + if (linepos[0] == '\0') + return -1; + + /* get operation type */ + if (linepos[0] == '=' && linepos[1] == '=') { + *op = OP_MATCH; + linepos += 2; + } else if (linepos[0] == '!' && linepos[1] == '=') { + *op = OP_NOMATCH; + linepos += 2; + } else if (linepos[0] == '+' && linepos[1] == '=') { + *op = OP_ADD; + linepos += 2; + } else if (linepos[0] == '=') { + *op = OP_ASSIGN; + linepos++; + } else if (linepos[0] == ':' && linepos[1] == '=') { + *op = OP_ASSIGN_FINAL; + linepos += 2; + } else + return -1; + + /* terminate key */ + temp[0] = '\0'; + + /* skip whitespace after operator */ + while (isspace(linepos[0])) + linepos++; + if (linepos[0] == '\0') + return -1; + + /* get the value */ + if (linepos[0] == '"') + linepos++; + else + return -1; + *value = linepos; + + /* terminate */ + temp = strchr(linepos, '"'); + if (!temp) + return -1; + temp[0] = '\0'; + temp++; + + /* move line to next key */ + *line = temp; + return 0; +} + +/* extract possible KEY{attr} */ +static const char *get_key_attribute(struct udev *udev, char *str) +{ + char *pos; + char *attr; + + attr = strchr(str, '{'); + if (attr != NULL) { + attr++; + pos = strchr(attr, '}'); + if (pos == NULL) { + log_error("missing closing brace for format"); + return NULL; + } + pos[0] = '\0'; + return attr; + } + return NULL; +} + +static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + enum operation_type op, + const char *value, const void *data) +{ + struct token *token = &rule_tmp->token[rule_tmp->token_cur]; + const char *attr = NULL; + + memzero(token, sizeof(struct token)); + + switch (type) { + case TK_M_ACTION: + case TK_M_DEVPATH: + case TK_M_KERNEL: + case TK_M_SUBSYSTEM: + case TK_M_DRIVER: + case TK_M_WAITFOR: + case TK_M_DEVLINK: + case TK_M_NAME: + case TK_M_KERNELS: + case TK_M_SUBSYSTEMS: + case TK_M_DRIVERS: + case TK_M_TAGS: + case TK_M_PROGRAM: + case TK_M_IMPORT_FILE: + case TK_M_IMPORT_PROG: + case TK_M_IMPORT_DB: + case TK_M_IMPORT_CMDLINE: + case TK_M_IMPORT_PARENT: + case TK_M_RESULT: + case TK_A_OWNER: + case TK_A_GROUP: + case TK_A_MODE: + case TK_A_DEVLINK: + case TK_A_NAME: + case TK_A_GOTO: + case TK_M_TAG: + case TK_A_TAG: + case TK_A_STATIC_NODE: + token->key.value_off = rules_add_string(rule_tmp->rules, value); + break; + case TK_M_IMPORT_BUILTIN: + token->key.value_off = rules_add_string(rule_tmp->rules, value); + token->key.builtin_cmd = *(enum udev_builtin_cmd *)data; + break; + case TK_M_ENV: + case TK_M_ATTR: + case TK_M_ATTRS: + case TK_A_ATTR: + case TK_A_ENV: + case TK_A_SECLABEL: + attr = data; + token->key.value_off = rules_add_string(rule_tmp->rules, value); + token->key.attr_off = rules_add_string(rule_tmp->rules, attr); + break; + case TK_M_TEST: + token->key.value_off = rules_add_string(rule_tmp->rules, value); + if (data != NULL) + token->key.mode = *(mode_t *)data; + break; + case TK_A_STRING_ESCAPE_NONE: + case TK_A_STRING_ESCAPE_REPLACE: + case TK_A_DB_PERSIST: + break; + case TK_A_RUN_BUILTIN: + case TK_A_RUN_PROGRAM: + token->key.builtin_cmd = *(enum udev_builtin_cmd *)data; + token->key.value_off = rules_add_string(rule_tmp->rules, value); + break; + case TK_A_INOTIFY_WATCH: + case TK_A_DEVLINK_PRIO: + token->key.devlink_prio = *(int *)data; + break; + case TK_A_OWNER_ID: + token->key.uid = *(uid_t *)data; + break; + case TK_A_GROUP_ID: + token->key.gid = *(gid_t *)data; + break; + case TK_A_MODE_ID: + token->key.mode = *(mode_t *)data; + break; + case TK_M_EVENT_TIMEOUT: + token->key.event_timeout = *(int *)data; + break; + case TK_RULE: + case TK_M_PARENTS_MIN: + case TK_M_PARENTS_MAX: + case TK_M_MAX: + case TK_END: + case TK_UNSET: + log_error("wrong type %u", type); + return -1; + } + + if (value != NULL && type < TK_M_MAX) { + /* check if we need to split or call fnmatch() while matching rules */ + enum string_glob_type glob; + int has_split; + int has_glob; + + has_split = (strchr(value, '|') != NULL); + has_glob = string_is_glob(value); + if (has_split && has_glob) { + glob = GL_SPLIT_GLOB; + } else if (has_split) { + glob = GL_SPLIT; + } else if (has_glob) { + if (streq(value, "?*")) + glob = GL_SOMETHING; + else + glob = GL_GLOB; + } else { + glob = GL_PLAIN; + } + token->key.glob = glob; + } + + if (value != NULL && type > TK_M_MAX) { + /* check if assigned value has substitution chars */ + if (value[0] == '[') + token->key.subst = SB_SUBSYS; + else if (strchr(value, '%') != NULL || strchr(value, '$') != NULL) + token->key.subst = SB_FORMAT; + else + token->key.subst = SB_NONE; + } + + if (attr != NULL) { + /* check if property/attribute name has substitution chars */ + if (attr[0] == '[') + token->key.attrsubst = SB_SUBSYS; + else if (strchr(attr, '%') != NULL || strchr(attr, '$') != NULL) + token->key.attrsubst = SB_FORMAT; + else + token->key.attrsubst = SB_NONE; + } + + token->key.type = type; + token->key.op = op; + rule_tmp->token_cur++; + if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) { + log_error("temporary rule array too small"); + return -1; + } + return 0; +} + +static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) +{ + unsigned int i; + unsigned int start = 0; + unsigned int end = rule_tmp->token_cur; + + for (i = 0; i < rule_tmp->token_cur; i++) { + enum token_type next_val = TK_UNSET; + unsigned int next_idx = 0; + unsigned int j; + + /* find smallest value */ + for (j = start; j < end; j++) { + if (rule_tmp->token[j].type == TK_UNSET) + continue; + if (next_val == TK_UNSET || rule_tmp->token[j].type < next_val) { + next_val = rule_tmp->token[j].type; + next_idx = j; + } + } + + /* add token and mark done */ + if (add_token(rules, &rule_tmp->token[next_idx]) != 0) + return -1; + rule_tmp->token[next_idx].type = TK_UNSET; + + /* shrink range */ + if (next_idx == start) + start++; + if (next_idx+1 == end) + end--; + } + return 0; +} + +static int add_rule(struct udev_rules *rules, char *line, + const char *filename, unsigned int filename_off, unsigned int lineno) +{ + char *linepos; + const char *attr; + struct rule_tmp rule_tmp; + + memzero(&rule_tmp, sizeof(struct rule_tmp)); + rule_tmp.rules = rules; + rule_tmp.rule.type = TK_RULE; + /* the offset in the rule is limited to unsigned short */ + if (filename_off < USHRT_MAX) + rule_tmp.rule.rule.filename_off = filename_off; + rule_tmp.rule.rule.filename_line = lineno; + + linepos = line; + for (;;) { + char *key; + char *value; + enum operation_type op; + + if (get_key(rules->udev, &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(). */ + while (isblank(*linepos)) + linepos++; + + /* If we aren't at the end of the line, this is a parsing error. + * Make a best effort to describe where the problem is. */ + if (*linepos != '\n') { + char buf[2] = {linepos[1]}; + _cleanup_free_ char *tmp; + + tmp = cescape(buf); + log_error("invalid key/value pair in file %s on line %u," + "starting at character %tu ('%s')\n", + filename, lineno, linepos - line + 1, tmp); + if (linepos[1] == '#') + log_error("hint: comments can only start at beginning of line"); + } + break; + } + + if (streq(key, "ACTION")) { + if (op > OP_MATCH_MAX) { + log_error("invalid ACTION operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); + continue; + } + + if (streq(key, "DEVPATH")) { + if (op > OP_MATCH_MAX) { + log_error("invalid DEVPATH operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); + continue; + } + + if (streq(key, "KERNEL")) { + if (op > OP_MATCH_MAX) { + log_error("invalid KERNEL operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); + continue; + } + + if (streq(key, "SUBSYSTEM")) { + if (op > OP_MATCH_MAX) { + log_error("invalid SUBSYSTEM operation"); + goto invalid; + } + /* bus, class, subsystem events should all be the same */ + if (streq(value, "subsystem") || + streq(value, "bus") || + streq(value, "class")) { + if (streq(value, "bus") || streq(value, "class")) + log_error("'%s' must be specified as 'subsystem' " + "please fix it in %s:%u", value, filename, lineno); + rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); + } else + rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); + continue; + } + + if (streq(key, "DRIVER")) { + if (op > OP_MATCH_MAX) { + log_error("invalid DRIVER operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); + continue; + } + + if (startswith(key, "ATTR{")) { + attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1); + if (attr == NULL) { + log_error("error parsing ATTR attribute"); + goto invalid; + } + if (op < OP_MATCH_MAX) { + rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); + } else { + rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + } + continue; + } + + if (startswith(key, "SECLABEL{")) { + attr = get_key_attribute(rules->udev, key + sizeof("SECLABEL")-1); + if (!attr) { + log_error("error parsing SECLABEL attribute"); + goto invalid; + } + + rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); + continue; + } + + if (streq(key, "KERNELS")) { + if (op > OP_MATCH_MAX) { + log_error("invalid KERNELS operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); + continue; + } + + if (streq(key, "SUBSYSTEMS")) { + if (op > OP_MATCH_MAX) { + log_error("invalid SUBSYSTEMS operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); + continue; + } + + if (streq(key, "DRIVERS")) { + if (op > OP_MATCH_MAX) { + log_error("invalid DRIVERS operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); + continue; + } + + if (startswith(key, "ATTRS{")) { + if (op > OP_MATCH_MAX) { + log_error("invalid ATTRS operation"); + goto invalid; + } + attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1); + if (attr == NULL) { + log_error("error parsing ATTRS attribute"); + goto invalid; + } + if (startswith(attr, "device/")) + log_error("the 'device' link may not be available in a future kernel, " + "please fix it in %s:%u", filename, lineno); + else if (strstr(attr, "../") != NULL) + log_error("do not reference parent sysfs directories directly, " + "it may break with a future kernel, please fix it in %s:%u", filename, lineno); + rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); + continue; + } + + if (streq(key, "TAGS")) { + if (op > OP_MATCH_MAX) { + log_error("invalid TAGS operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); + continue; + } + + if (startswith(key, "ENV{")) { + attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1); + if (attr == NULL) { + log_error("error parsing ENV attribute"); + goto invalid; + } + if (op < OP_MATCH_MAX) { + if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) + goto invalid; + } else { + static const char *blacklist[] = { + "ACTION", + "SUBSYSTEM", + "DEVTYPE", + "MAJOR", + "MINOR", + "DRIVER", + "IFINDEX", + "DEVNAME", + "DEVLINKS", + "DEVPATH", + "TAGS", + }; + unsigned int i; + + for (i = 0; i < ELEMENTSOF(blacklist); i++) { + if (!streq(attr, blacklist[i])) + continue; + log_error("invalid ENV attribute, '%s' can not be set %s:%u", attr, filename, lineno); + goto invalid; + } + if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0) + goto invalid; + } + continue; + } + + if (streq(key, "TAG")) { + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); + else + rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + continue; + } + + if (streq(key, "PROGRAM")) { + rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); + continue; + } + + if (streq(key, "RESULT")) { + if (op > OP_MATCH_MAX) { + log_error("invalid RESULT operation"); + goto invalid; + } + rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); + continue; + } + + if (startswith(key, "IMPORT")) { + attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1); + if (attr == NULL) { + log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno); + continue; + } + if (streq(attr, "program")) { + /* find known built-in command */ + if (value[0] != '/') { + enum udev_builtin_cmd cmd; + + cmd = udev_builtin_lookup(value); + if (cmd < UDEV_BUILTIN_MAX) { + log_debug("IMPORT found builtin '%s', replacing %s:%u", + value, filename, lineno); + rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + continue; + } + } + rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); + } else if (streq(attr, "builtin")) { + enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + + if (cmd < UDEV_BUILTIN_MAX) + rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + else + log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno); + } else if (streq(attr, "file")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); + } else if (streq(attr, "db")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); + } else if (streq(attr, "cmdline")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); + } else if (streq(attr, "parent")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); + } else + log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u", filename, lineno); + continue; + } + + if (startswith(key, "TEST")) { + mode_t mode = 0; + + if (op > OP_MATCH_MAX) { + log_error("invalid TEST operation"); + goto invalid; + } + attr = get_key_attribute(rules->udev, key + sizeof("TEST")-1); + if (attr != NULL) { + mode = strtol(attr, NULL, 8); + rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); + } else { + rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); + } + continue; + } + + if (startswith(key, "RUN")) { + attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1); + if (attr == NULL) + attr = "program"; + + if (streq(attr, "builtin")) { + enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + + if (cmd < UDEV_BUILTIN_MAX) + rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); + else + log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno); + } else if (streq(attr, "program")) { + enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; + + rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); + } else { + log_error("RUN{} unknown type, ignoring RUN %s:%u", filename, lineno); + } + + continue; + } + + if (streq(key, "WAIT_FOR") || streq(key, "WAIT_FOR_SYSFS")) { + rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL); + continue; + } + + if (streq(key, "LABEL")) { + rule_tmp.rule.rule.label_off = rules_add_string(rules, value); + continue; + } + + if (streq(key, "GOTO")) { + rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); + continue; + } + + if (startswith(key, "NAME")) { + if (op < OP_MATCH_MAX) { + rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); + } else { + if (streq(value, "%k")) { + log_error("NAME=\"%%k\" is ignored, because it breaks kernel supplied names, " + "please remove it from %s:%u\n", filename, lineno); + continue; + } + if (value[0] == '\0') { + log_debug("NAME=\"\" is ignored, because udev will not delete any device nodes, " + "please remove it from %s:%u\n", filename, lineno); + continue; + } + rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); + } + rule_tmp.rule.rule.can_set_name = true; + continue; + } + + if (streq(key, "SYMLINK")) { + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); + else + rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + rule_tmp.rule.rule.can_set_name = true; + continue; + } + + if (streq(key, "OWNER")) { + uid_t uid; + char *endptr; + + uid = strtoul(value, &endptr, 10); + if (endptr[0] == '\0') { + rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + uid = add_uid(rules, value); + rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); + } else if (rules->resolve_names >= 0) { + rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); + } + rule_tmp.rule.rule.can_set_name = true; + continue; + } + + if (streq(key, "GROUP")) { + gid_t gid; + char *endptr; + + gid = strtoul(value, &endptr, 10); + if (endptr[0] == '\0') { + rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + gid = add_gid(rules, value); + rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); + } else if (rules->resolve_names >= 0) { + rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); + } + rule_tmp.rule.rule.can_set_name = true; + continue; + } + + if (streq(key, "MODE")) { + mode_t mode; + char *endptr; + + mode = strtol(value, &endptr, 8); + if (endptr[0] == '\0') + rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); + else + rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); + rule_tmp.rule.rule.can_set_name = true; + continue; + } + + if (streq(key, "OPTIONS")) { + const char *pos; + + pos = strstr(value, "link_priority="); + if (pos != NULL) { + int prio = atoi(&pos[strlen("link_priority=")]); + + rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); + } + + pos = strstr(value, "event_timeout="); + if (pos != NULL) { + int tout = atoi(&pos[strlen("event_timeout=")]); + + rule_add_key(&rule_tmp, TK_M_EVENT_TIMEOUT, op, NULL, &tout); + } + + pos = strstr(value, "string_escape="); + if (pos != NULL) { + pos = &pos[strlen("string_escape=")]; + if (startswith(pos, "none")) + rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); + else if (startswith(pos, "replace")) + rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); + } + + pos = strstr(value, "db_persist"); + if (pos != NULL) + rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL); + + pos = strstr(value, "nowatch"); + if (pos != NULL) { + const int off = 0; + + rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &off); + } else { + pos = strstr(value, "watch"); + if (pos != NULL) { + const int on = 1; + + rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on); + } + } + + pos = strstr(value, "static_node="); + if (pos != NULL) { + rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL); + rule_tmp.rule.rule.has_static_node = true; + } + + continue; + } + + log_error("unknown key '%s' in %s:%u", key, filename, lineno); + goto invalid; + } + + /* add rule token */ + rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur; + if (add_token(rules, &rule_tmp.rule) != 0) + goto invalid; + + /* add tokens to list, sorted by type */ + if (sort_token(rules, &rule_tmp) != 0) + goto invalid; + + return 0; +invalid: + log_error("invalid rule '%s:%u'", filename, lineno); + return -1; +} + +static int parse_file(struct udev_rules *rules, const char *filename) +{ + FILE *f; + unsigned int first_token; + unsigned int filename_off; + char line[UTIL_LINE_SIZE]; + int line_nr = 0; + unsigned int i; + + if (null_or_empty_path(filename)) { + log_debug("skip empty file: %s", filename); + return 0; + } + log_debug("read rules file: %s", filename); + + f = fopen(filename, "re"); + if (f == NULL) + return -1; + + first_token = rules->token_cur; + filename_off = rules_add_string(rules, filename); + + while (fgets(line, sizeof(line), f) != NULL) { + char *key; + size_t len; + + /* skip whitespace */ + line_nr++; + key = line; + while (isspace(key[0])) + key++; + + /* comment */ + if (key[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) == NULL) + break; + if (strlen(&line[len-2]) < 2) + break; + line_nr++; + len = strlen(line); + } + + if (len+1 >= sizeof(line)) { + log_error("line too long '%s':%u, ignored", filename, line_nr); + continue; + } + add_rule(rules, key, filename, filename_off, line_nr); + } + fclose(f); + + /* 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 int j; + + for (j = i+1; j < rules->token_cur; j++) { + if (rules->tokens[j].type != TK_RULE) + continue; + if (rules->tokens[j].rule.label_off == 0) + continue; + if (!streq(label, rules_str(rules, rules->tokens[j].rule.label_off))) + continue; + rules->tokens[i].key.rule_goto = j; + break; + } + if (rules->tokens[i].key.rule_goto == 0) + log_error("GOTO '%s' has no matching label in: '%s'", label, filename); + } + } + return 0; +} + +struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) +{ + struct udev_rules *rules; + struct udev_list file_list; + struct token end_token; + char **files, **f; + int r; + + rules = new0(struct udev_rules, 1); + if (rules == NULL) + return NULL; + rules->udev = udev; + rules->resolve_names = resolve_names; + udev_list_init(udev, &file_list, true); + + /* init token array and string buffer */ + rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token)); + if (rules->tokens == NULL) + return udev_rules_unref(rules); + rules->token_max = PREALLOC_TOKEN; + + rules->strbuf = strbuf_new(); + if (!rules->strbuf) + return udev_rules_unref(rules); + + udev_rules_check_timestamp(rules); + + r = conf_files_list_strv(&files, ".rules", NULL, rules_dirs); + if (r < 0) { + log_error("failed to enumerate rules files: %s", strerror(-r)); + return udev_rules_unref(rules); + } + + /* + * The offset value in the rules strct is limited; add all + * rules file names to the beginning of the string buffer. + */ + STRV_FOREACH(f, files) + rules_add_string(rules, *f); + + STRV_FOREACH(f, files) + parse_file(rules, *f); + + strv_free(files); + + memzero(&end_token, sizeof(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", + rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len); + + /* cleanup temporary strbuf data */ + log_debug("%zu strings (%zu bytes), %zu de-duplicated (%zu bytes), %zu trie nodes used", + rules->strbuf->in_count, rules->strbuf->in_len, + rules->strbuf->dedup_count, rules->strbuf->dedup_len, rules->strbuf->nodes_count); + strbuf_complete(rules->strbuf); + + /* cleanup uid/gid cache */ + free(rules->uids); + rules->uids = NULL; + rules->uids_cur = 0; + rules->uids_max = 0; + free(rules->gids); + rules->gids = NULL; + rules->gids_cur = 0; + rules->gids_max = 0; + + dump_rules(rules); + return rules; +} + +struct udev_rules *udev_rules_unref(struct udev_rules *rules) +{ + if (rules == NULL) + return NULL; + free(rules->tokens); + strbuf_cleanup(rules->strbuf); + free(rules->uids); + free(rules->gids); + free(rules); + return NULL; +} + +bool udev_rules_check_timestamp(struct udev_rules *rules) +{ + if (!rules) + return false; + + return paths_check_timestamp(rules_dirs, &rules->dirs_ts_usec, true); +} + +static int match_key(struct udev_rules *rules, struct token *token, const char *val) +{ + char *key_value = rules_str(rules, token->key.value_off); + char *pos; + bool match = false; + + if (val == NULL) + val = ""; + + switch (token->key.glob) { + case GL_PLAIN: + match = (streq(key_value, val)); + break; + case GL_GLOB: + match = (fnmatch(key_value, val, 0) == 0); + break; + case GL_SPLIT: + { + const char *s; + size_t len; + + s = rules_str(rules, token->key.value_off); + len = strlen(val); + for (;;) { + const char *next; + + next = strchr(s, '|'); + if (next != NULL) { + size_t matchlen = (size_t)(next - s); + + match = (matchlen == len && strneq(s, val, matchlen)); + if (match) + break; + } else { + match = (streq(s, val)); + break; + } + s = &next[1]; + } + break; + } + case GL_SPLIT_GLOB: + { + char value[UTIL_PATH_SIZE]; + + strscpy(value, sizeof(value), rules_str(rules, token->key.value_off)); + key_value = value; + while (key_value != NULL) { + pos = strchr(key_value, '|'); + if (pos != NULL) { + pos[0] = '\0'; + pos = &pos[1]; + } + match = (fnmatch(key_value, val, 0) == 0); + if (match) + break; + key_value = pos; + } + break; + } + case GL_SOMETHING: + match = (val[0] != '\0'); + break; + case GL_UNSET: + return -1; + } + + if (match && (token->key.op == OP_MATCH)) + return 0; + if (!match && (token->key.op == OP_NOMATCH)) + return 0; + return -1; +} + +static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) +{ + const char *name; + char nbuf[UTIL_NAME_SIZE]; + const char *value; + char vbuf[UTIL_NAME_SIZE]; + size_t len; + + name = rules_str(rules, cur->key.attr_off); + switch (cur->key.attrsubst) { + case SB_FORMAT: + udev_event_apply_format(event, name, nbuf, sizeof(nbuf)); + name = nbuf; + /* fall through */ + case SB_NONE: + value = udev_device_get_sysattr_value(dev, name); + if (value == NULL) + return -1; + break; + case SB_SUBSYS: + if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0) + return -1; + value = vbuf; + break; + default: + return -1; + } + + /* remove trailing whitespace, if not asked to match for it */ + len = strlen(value); + if (len > 0 && isspace(value[len-1])) { + const char *key_value; + size_t klen; + + key_value = rules_str(rules, cur->key.value_off); + klen = strlen(key_value); + if (klen > 0 && !isspace(key_value[klen-1])) { + if (value != vbuf) { + strscpy(vbuf, sizeof(vbuf), value); + value = vbuf; + } + while (len > 0 && isspace(vbuf[--len])) + vbuf[len] = '\0'; + } + } + + return match_key(rules, cur, value); +} + +enum escape_type { + ESCAPE_UNSET, + ESCAPE_NONE, + ESCAPE_REPLACE, +}; + +int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask) +{ + struct token *cur; + struct token *rule; + enum escape_type esc = ESCAPE_UNSET; + bool can_set_name; + + if (rules->tokens == NULL) + return -1; + + can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) && + (major(udev_device_get_devnum(event->dev)) > 0 || + udev_device_get_ifindex(event->dev) > 0)); + + /* loop through token list, match, run actions or forward to next rule */ + cur = &rules->tokens[0]; + rule = cur; + for (;;) { + dump_token(rules, cur); + switch (cur->type) { + case TK_RULE: + /* current rule */ + rule = cur; + /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */ + if (!can_set_name && rule->rule.can_set_name) + goto nomatch; + esc = ESCAPE_UNSET; + break; + case TK_M_ACTION: + if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0) + goto nomatch; + break; + case TK_M_DEVPATH: + if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0) + goto nomatch; + break; + case TK_M_KERNEL: + if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0) + goto nomatch; + break; + case TK_M_DEVLINK: { + struct udev_list_entry *list_entry; + bool match = false; + + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) { + const char *devlink; + + devlink = udev_list_entry_get_name(list_entry) + strlen("/dev/"); + if (match_key(rules, cur, devlink) == 0) { + match = true; + break; + } + } + if (!match) + goto nomatch; + break; + } + case TK_M_NAME: + if (match_key(rules, cur, event->name) != 0) + goto nomatch; + break; + case TK_M_ENV: { + const char *key_name = rules_str(rules, cur->key.attr_off); + const char *value; + + value = udev_device_get_property_value(event->dev, key_name); + if (value == NULL) + value = ""; + if (match_key(rules, cur, value)) + goto nomatch; + break; + } + case TK_M_TAG: { + struct udev_list_entry *list_entry; + bool match = false; + + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) { + if (streq(rules_str(rules, cur->key.value_off), udev_list_entry_get_name(list_entry))) { + match = true; + break; + } + } + if (!match && (cur->key.op != OP_NOMATCH)) + goto nomatch; + break; + } + case TK_M_SUBSYSTEM: + if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0) + goto nomatch; + break; + case TK_M_DRIVER: + if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0) + goto nomatch; + break; + case TK_M_WAITFOR: { + char filename[UTIL_PATH_SIZE]; + int found; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename)); + found = (wait_for_file(event->dev, filename, 10) == 0); + if (!found && (cur->key.op != OP_NOMATCH)) + goto nomatch; + break; + } + case TK_M_ATTR: + if (match_attr(rules, event->dev, event, cur) != 0) + goto nomatch; + break; + case TK_M_KERNELS: + case TK_M_SUBSYSTEMS: + case TK_M_DRIVERS: + case TK_M_ATTRS: + case TK_M_TAGS: { + struct token *next; + + /* get whole sequence of parent matches */ + next = cur; + while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX) + next++; + + /* loop over parents */ + event->dev_parent = event->dev; + for (;;) { + struct token *key; + + /* loop over sequence of parent match keys */ + for (key = cur; key < next; key++ ) { + dump_token(rules, key); + switch(key->type) { + case TK_M_KERNELS: + if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0) + goto try_parent; + break; + case TK_M_SUBSYSTEMS: + if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0) + goto try_parent; + break; + case TK_M_DRIVERS: + if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0) + goto try_parent; + break; + case TK_M_ATTRS: + if (match_attr(rules, event->dev_parent, event, key) != 0) + goto try_parent; + break; + case TK_M_TAGS: { + bool match = udev_device_has_tag(event->dev_parent, rules_str(rules, cur->key.value_off)); + + if (match && key->key.op == OP_NOMATCH) + goto try_parent; + if (!match && key->key.op == OP_MATCH) + goto try_parent; + break; + } + default: + goto nomatch; + } + } + break; + + try_parent: + event->dev_parent = udev_device_get_parent(event->dev_parent); + if (event->dev_parent == NULL) + goto nomatch; + } + /* move behind our sequence of parent match keys */ + cur = next; + continue; + } + case TK_M_TEST: { + char filename[UTIL_PATH_SIZE]; + struct stat statbuf; + int match; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename)); + if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) { + if (filename[0] != '/') { + char tmp[UTIL_PATH_SIZE]; + + strscpy(tmp, sizeof(tmp), filename); + strscpyl(filename, sizeof(filename), + udev_device_get_syspath(event->dev), "/", tmp, NULL); + } + } + attr_subst_subdir(filename, sizeof(filename)); + + match = (stat(filename, &statbuf) == 0); + if (match && cur->key.mode > 0) + match = ((statbuf.st_mode & cur->key.mode) > 0); + if (match && cur->key.op == OP_NOMATCH) + goto nomatch; + if (!match && cur->key.op == OP_MATCH) + goto nomatch; + break; + } + case TK_M_EVENT_TIMEOUT: + log_debug("OPTIONS event_timeout=%u", cur->key.event_timeout); + event->timeout_usec = cur->key.event_timeout * 1000 * 1000; + break; + case TK_M_PROGRAM: { + char program[UTIL_PATH_SIZE]; + char **envp; + char result[UTIL_PATH_SIZE]; + + free(event->program_result); + event->program_result = NULL; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program)); + envp = udev_device_get_properties_envp(event->dev); + log_debug("PROGRAM '%s' %s:%u", + program, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + + if (udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)) < 0) { + if (cur->key.op != OP_NOMATCH) + goto nomatch; + } else { + int count; + + util_remove_trailing_chars(result, '\n'); + if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) { + count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); + if (count > 0) + log_debug("%i character(s) replaced" , count); + } + event->program_result = strdup(result); + if (cur->key.op == OP_NOMATCH) + goto nomatch; + } + break; + } + case TK_M_IMPORT_FILE: { + char import[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import)); + if (import_file_into_properties(event->dev, import) != 0) + if (cur->key.op != OP_NOMATCH) + goto nomatch; + break; + } + case TK_M_IMPORT_PROG: { + char import[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import)); + log_debug("IMPORT '%s' %s:%u", + import, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + + if (import_program_into_properties(event, import, sigmask) != 0) + if (cur->key.op != OP_NOMATCH) + goto nomatch; + break; + } + case TK_M_IMPORT_BUILTIN: { + char command[UTIL_PATH_SIZE]; + + if (udev_builtin_run_once(cur->key.builtin_cmd)) { + /* check if we ran already */ + if (event->builtin_run & (1 << cur->key.builtin_cmd)) { + log_debug("IMPORT builtin skip '%s' %s:%u", + udev_builtin_name(cur->key.builtin_cmd), + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + /* return the result from earlier run */ + if (event->builtin_ret & (1 << cur->key.builtin_cmd)) + if (cur->key.op != OP_NOMATCH) + goto nomatch; + break; + } + /* mark as ran */ + event->builtin_run |= (1 << cur->key.builtin_cmd); + } + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), command, sizeof(command)); + log_debug("IMPORT builtin '%s' %s:%u", + udev_builtin_name(cur->key.builtin_cmd), + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + + if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) { + /* remember failure */ + log_debug("IMPORT builtin '%s' returned non-zero", + udev_builtin_name(cur->key.builtin_cmd)); + event->builtin_ret |= (1 << cur->key.builtin_cmd); + if (cur->key.op != OP_NOMATCH) + goto nomatch; + } + break; + } + case TK_M_IMPORT_DB: { + const char *key = rules_str(rules, cur->key.value_off); + const char *value; + + value = udev_device_get_property_value(event->dev_db, key); + if (value != NULL) { + struct udev_list_entry *entry; + + entry = udev_device_add_property(event->dev, key, value); + udev_list_entry_set_num(entry, true); + } else { + if (cur->key.op != OP_NOMATCH) + goto nomatch; + } + break; + } + case TK_M_IMPORT_CMDLINE: { + FILE *f; + bool imported = false; + + f = fopen("/proc/cmdline", "re"); + if (f != NULL) { + char cmdline[4096]; + + if (fgets(cmdline, sizeof(cmdline), f) != NULL) { + const char *key = rules_str(rules, cur->key.value_off); + char *pos; + + pos = strstr(cmdline, key); + if (pos != NULL) { + struct udev_list_entry *entry; + + pos += strlen(key); + if (pos[0] == '\0' || isspace(pos[0])) { + /* we import simple flags as 'FLAG=1' */ + entry = udev_device_add_property(event->dev, key, "1"); + udev_list_entry_set_num(entry, true); + imported = true; + } else if (pos[0] == '=') { + const char *value; + + pos++; + value = pos; + while (pos[0] != '\0' && !isspace(pos[0])) + pos++; + pos[0] = '\0'; + entry = udev_device_add_property(event->dev, key, value); + udev_list_entry_set_num(entry, true); + imported = true; + } + } + } + fclose(f); + } + if (!imported && cur->key.op != OP_NOMATCH) + goto nomatch; + break; + } + case TK_M_IMPORT_PARENT: { + char import[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import)); + if (import_parent_into_properties(event->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) + goto nomatch; + break; + case TK_A_STRING_ESCAPE_NONE: + esc = ESCAPE_NONE; + break; + case TK_A_STRING_ESCAPE_REPLACE: + esc = ESCAPE_REPLACE; + break; + case TK_A_DB_PERSIST: + udev_device_set_db_persist(event->dev); + break; + case TK_A_INOTIFY_WATCH: + if (event->inotify_watch_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->inotify_watch_final = true; + event->inotify_watch = cur->key.watch; + break; + case TK_A_DEVLINK_PRIO: + udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio); + break; + case TK_A_OWNER: { + char owner[UTIL_NAME_SIZE]; + + if (event->owner_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->owner_final = true; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner)); + event->owner_set = true; + event->uid = util_lookup_user(event->udev, owner); + log_debug("OWNER %u %s:%u", + event->uid, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } + case TK_A_GROUP: { + char group[UTIL_NAME_SIZE]; + + if (event->group_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->group_final = true; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group)); + event->group_set = true; + event->gid = util_lookup_group(event->udev, group); + log_debug("GROUP %u %s:%u", + event->gid, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } + case TK_A_MODE: { + char mode_str[UTIL_NAME_SIZE]; + mode_t mode; + char *endptr; + + if (event->mode_final) + break; + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), mode_str, sizeof(mode_str)); + mode = strtol(mode_str, &endptr, 8); + if (endptr[0] != '\0') { + log_error("ignoring invalid mode '%s'", mode_str); + break; + } + if (cur->key.op == OP_ASSIGN_FINAL) + event->mode_final = true; + event->mode_set = true; + event->mode = mode; + log_debug("MODE %#o %s:%u", + event->mode, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } + case TK_A_OWNER_ID: + if (event->owner_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->owner_final = true; + event->owner_set = true; + event->uid = cur->key.uid; + log_debug("OWNER %u %s:%u", + event->uid, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + case TK_A_GROUP_ID: + if (event->group_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->group_final = true; + event->group_set = true; + event->gid = cur->key.gid; + log_debug("GROUP %u %s:%u", + event->gid, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + case TK_A_MODE_ID: + if (event->mode_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->mode_final = true; + event->mode_set = true; + event->mode = cur->key.mode; + log_debug("MODE %#o %s:%u", + event->mode, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + case TK_A_SECLABEL: { + const char *name, *label; + + name = rules_str(rules, cur->key.attr_off); + label = rules_str(rules, cur->key.value_off); + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_list_cleanup(&event->seclabel_list); + udev_list_entry_add(&event->seclabel_list, name, label); + log_debug("SECLABEL{%s}='%s' %s:%u", + name, label, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } + case TK_A_ENV: { + const char *name = rules_str(rules, cur->key.attr_off); + char *value = rules_str(rules, cur->key.value_off); + char value_new[UTIL_NAME_SIZE]; + const char *value_old = NULL; + struct udev_list_entry *entry; + + if (value[0] == '\0') { + if (cur->key.op == OP_ADD) + break; + udev_device_add_property(event->dev, name, NULL); + break; + } + + if (cur->key.op == OP_ADD) + value_old = udev_device_get_property_value(event->dev, name); + if (value_old) { + char temp[UTIL_NAME_SIZE]; + + /* append value separated by space */ + udev_event_apply_format(event, value, temp, sizeof(temp)); + strscpyl(value_new, sizeof(value_new), value_old, " ", temp, NULL); + } else + udev_event_apply_format(event, value, value_new, sizeof(value_new)); + + entry = udev_device_add_property(event->dev, name, value_new); + /* store in db, skip private keys */ + if (name[0] != '.') + udev_list_entry_set_num(entry, true); + break; + } + case TK_A_TAG: { + char tag[UTIL_PATH_SIZE]; + const char *p; + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag)); + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_device_cleanup_tags_list(event->dev); + for (p = tag; *p != '\0'; p++) { + if ((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9') || + *p == '-' || *p == '_') + continue; + log_error("ignoring invalid tag name '%s'", tag); + break; + } + udev_device_add_tag(event->dev, tag); + break; + } + case TK_A_NAME: { + const char *name = rules_str(rules, cur->key.value_off); + + char name_str[UTIL_PATH_SIZE]; + int count; + + if (event->name_final) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->name_final = true; + udev_event_apply_format(event, name, name_str, sizeof(name_str)); + if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) { + count = util_replace_chars(name_str, "/"); + if (count > 0) + log_debug("%i character(s) replaced", count); + } + if (major(udev_device_get_devnum(event->dev)) && + (!streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/")))) { + log_error("NAME=\"%s\" ignored, kernel device nodes " + "can not be renamed; please fix it in %s:%u\n", name, + rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + break; + } + free(event->name); + event->name = strdup(name_str); + log_debug("NAME '%s' %s:%u", + event->name, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } + case TK_A_DEVLINK: { + char temp[UTIL_PATH_SIZE]; + char filename[UTIL_PATH_SIZE]; + char *pos, *next; + int count = 0; + + if (event->devlink_final) + break; + if (major(udev_device_get_devnum(event->dev)) == 0) + break; + if (cur->key.op == OP_ASSIGN_FINAL) + event->devlink_final = true; + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_device_cleanup_devlinks_list(event->dev); + + /* allow multiple symlinks separated by spaces */ + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp)); + if (esc == ESCAPE_UNSET) + count = util_replace_chars(temp, "/ "); + else if (esc == ESCAPE_REPLACE) + count = util_replace_chars(temp, "/"); + if (count > 0) + log_debug("%i character(s) replaced" , count); + pos = temp; + while (isspace(pos[0])) + pos++; + next = strchr(pos, ' '); + while (next != NULL) { + next[0] = '\0'; + log_debug("LINK '%s' %s:%u", pos, + rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + strscpyl(filename, sizeof(filename), "/dev/", pos, NULL); + udev_device_add_devlink(event->dev, filename); + while (isspace(next[1])) + next++; + pos = &next[1]; + next = strchr(pos, ' '); + } + if (pos[0] != '\0') { + log_debug("LINK '%s' %s:%u", pos, + rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + strscpyl(filename, sizeof(filename), "/dev/", pos, NULL); + udev_device_add_devlink(event->dev, filename); + } + break; + } + case TK_A_ATTR: { + const char *key_name = rules_str(rules, cur->key.attr_off); + char attr[UTIL_PATH_SIZE]; + char value[UTIL_NAME_SIZE]; + FILE *f; + + if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) + strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); + attr_subst_subdir(attr, sizeof(attr)); + + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value)); + log_debug("ATTR '%s' writing '%s' %s:%u", attr, value, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + f = fopen(attr, "we"); + if (f != NULL) { + if (fprintf(f, "%s", value) <= 0) + log_error("error writing ATTR{%s}: %m", attr); + fclose(f); + } else { + log_error("error opening ATTR{%s} for writing: %m", attr); + } + break; + } + case TK_A_RUN_BUILTIN: + case TK_A_RUN_PROGRAM: { + struct udev_list_entry *entry; + + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_list_cleanup(&event->run_list); + log_debug("RUN '%s' %s:%u", + rules_str(rules, cur->key.value_off), + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + entry = udev_list_entry_add(&event->run_list, rules_str(rules, cur->key.value_off), NULL); + udev_list_entry_set_num(entry, cur->key.builtin_cmd); + break; + } + case TK_A_GOTO: + if (cur->key.rule_goto == 0) + break; + cur = &rules->tokens[cur->key.rule_goto]; + continue; + case TK_END: + return 0; + + case TK_M_PARENTS_MIN: + case TK_M_PARENTS_MAX: + case TK_M_MAX: + case TK_UNSET: + log_error("wrong type %u", cur->type); + goto nomatch; + } + + cur++; + continue; + nomatch: + /* fast-forward to next rule */ + cur = rule + rule->rule.token_count; + } +} + +int udev_rules_apply_static_dev_perms(struct udev_rules *rules) +{ + struct token *cur; + struct token *rule; + uid_t uid = 0; + gid_t gid = 0; + mode_t mode = 0; + _cleanup_strv_free_ char **tags = NULL; + char **t; + FILE *f = NULL; + _cleanup_free_ char *path = NULL; + int r = 0; + + if (rules->tokens == NULL) + return 0; + + cur = &rules->tokens[0]; + rule = cur; + for (;;) { + switch (cur->type) { + case TK_RULE: + /* current rule */ + rule = cur; + + /* skip rules without a static_node tag */ + if (!rule->rule.has_static_node) + goto next; + + uid = 0; + gid = 0; + mode = 0; + strv_free(tags); + tags = NULL; + break; + case TK_A_OWNER_ID: + uid = cur->key.uid; + break; + case TK_A_GROUP_ID: + gid = cur->key.gid; + break; + case TK_A_MODE_ID: + mode = cur->key.mode; + break; + case TK_A_TAG: + r = strv_extend(&tags, rules_str(rules, cur->key.value_off)); + if (r < 0) + goto finish; + + break; + case TK_A_STATIC_NODE: { + char device_node[UTIL_PATH_SIZE]; + char tags_dir[UTIL_PATH_SIZE]; + char tag_symlink[UTIL_PATH_SIZE]; + struct stat stats; + + /* we assure, that the permissions tokens are sorted before the static token */ + if (mode == 0 && uid == 0 && gid == 0 && tags == NULL) + goto next; + + strscpyl(device_node, sizeof(device_node), "/dev/", rules_str(rules, cur->key.value_off), NULL); + + /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */ + if (tags) { + STRV_FOREACH(t, tags) { + _cleanup_free_ char *unescaped_filename = NULL; + + strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL); + r = mkdir_p(tags_dir, 0755); + if (r < 0) { + log_error("failed to create %s: %s", tags_dir, strerror(-r)); + return r; + } + + unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/."); + + strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL); + r = symlink(device_node, tag_symlink); + if (r < 0 && errno != EEXIST) { + log_error("failed to create symlink %s -> %s: %m", tag_symlink, device_node); + return -errno; + } else + r = 0; + } + } + + /* don't touch the permissions if only the tags were set */ + if (mode == 0 && uid == 0 && gid == 0) + break; + + if (stat(device_node, &stats) != 0) + break; + if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) + break; + + if (mode == 0) { + if (gid > 0) + mode = 0660; + else + mode = 0600; + } + if (mode != (stats.st_mode & 01777)) { + r = chmod(device_node, mode); + if (r < 0) { + log_error("failed to chmod '%s' %#o", device_node, mode); + return -errno; + } else + log_debug("chmod '%s' %#o", device_node, mode); + } + + if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { + r = chown(device_node, uid, gid); + if (r < 0) { + log_error("failed to chown '%s' %u %u ", device_node, uid, gid); + return -errno; + } else + log_debug("chown '%s' %u %u", device_node, uid, gid); + } + + utimensat(AT_FDCWD, device_node, NULL, 0); + break; + } + case TK_END: + goto finish; + } + + cur++; + continue; +next: + /* fast-forward to next rule */ + cur = rule + rule->rule.token_count; + continue; + } + +finish: + if (f) { + fflush(f); + fchmod(fileno(f), 0644); + if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) { + r = -errno; + unlink("/run/udev/static_node-tags"); + unlink(path); + } + fclose(f); + } + + return r; +} diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c new file mode 100644 index 0000000..cbe0c37 --- /dev/null +++ b/src/udev/udev-watch.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2004-2012 Kay Sievers + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static int inotify_fd = -1; + +/* inotify descriptor, will be shared with rules directory; + * set to cloexec since we need our children to be able to add + * watches for us + */ +int udev_watch_init(struct udev *udev) +{ + inotify_fd = inotify_init1(IN_CLOEXEC); + if (inotify_fd < 0) + log_error("inotify_init failed: %m"); + return inotify_fd; +} + +/* move any old watches directory out of the way, and then restore + * the watches + */ +void udev_watch_restore(struct udev *udev) +{ + if (inotify_fd < 0) + return; + + if (rename("/run/udev/watch", "/run/udev/watch.old") == 0) { + DIR *dir; + struct dirent *ent; + + dir = opendir("/run/udev/watch.old"); + if (dir == NULL) { + log_error("unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m"); + return; + } + + for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { + char device[UTIL_PATH_SIZE]; + ssize_t len; + struct udev_device *dev; + + if (ent->d_name[0] == '.') + continue; + + len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device)); + if (len <= 0 || len == (ssize_t)sizeof(device)) + goto unlink; + device[len] = '\0'; + + dev = udev_device_new_from_device_id(udev, device); + if (dev == NULL) + goto unlink; + + log_debug("restoring old watch on '%s'", udev_device_get_devnode(dev)); + udev_watch_begin(udev, dev); + udev_device_unref(dev); +unlink: + unlinkat(dirfd(dir), ent->d_name, 0); + } + + closedir(dir); + rmdir("/run/udev/watch.old"); + + } else if (errno != ENOENT) { + log_error("unable to move watches dir /run/udev/watch; old watches will not be restored: %m"); + } +} + +void udev_watch_begin(struct udev *udev, struct udev_device *dev) +{ + char filename[UTIL_PATH_SIZE]; + int wd; + int r; + + if (inotify_fd < 0) + return; + + log_debug("adding watch on '%s'", udev_device_get_devnode(dev)); + wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE); + if (wd < 0) { + log_error("inotify_add_watch(%d, %s, %o) failed: %m", + inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE); + return; + } + + snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + mkdir_parents(filename, 0755); + unlink(filename); + r = symlink(udev_device_get_id_filename(dev), filename); + if (r < 0) + log_error("Failed to create symlink %s: %m", filename); + + udev_device_set_watch_handle(dev, wd); +} + +void udev_watch_end(struct udev *udev, struct udev_device *dev) +{ + int wd; + char filename[UTIL_PATH_SIZE]; + + if (inotify_fd < 0) + return; + + wd = udev_device_get_watch_handle(dev); + if (wd < 0) + return; + + log_debug("removing watch on '%s'", udev_device_get_devnode(dev)); + inotify_rm_watch(inotify_fd, wd); + + snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + unlink(filename); + + udev_device_set_watch_handle(dev, -1); +} + +struct udev_device *udev_watch_lookup(struct udev *udev, int wd) +{ + char filename[UTIL_PATH_SIZE]; + char device[UTIL_NAME_SIZE]; + ssize_t len; + + if (inotify_fd < 0 || wd < 0) + return NULL; + + snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + len = readlink(filename, device, sizeof(device)); + if (len <= 0 || (size_t)len == sizeof(device)) + return NULL; + device[len] = '\0'; + + return udev_device_new_from_device_id(udev, device); +} diff --git a/src/udev/udev.conf b/src/udev/udev.conf new file mode 100644 index 0000000..f39253e --- /dev/null +++ b/src/udev/udev.conf @@ -0,0 +1,3 @@ +# see udev(7) for details + +#udev_log="info" diff --git a/src/udev/udev.h b/src/udev/udev.h new file mode 100644 index 0000000..936adfb --- /dev/null +++ b/src/udev/udev.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2003 Greg Kroah-Hartman + * Copyright (C) 2003-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "macro.h" +#include "libudev.h" +#include "libudev-private.h" +#include "util.h" +#include "label.h" +#include "strv.h" + +struct udev_event { + struct udev *udev; + struct udev_device *dev; + struct udev_device *dev_parent; + struct udev_device *dev_db; + char *name; + char *program_result; + mode_t mode; + uid_t uid; + gid_t gid; + struct udev_list seclabel_list; + struct udev_list run_list; + int exec_delay; + usec_t birth_usec; + usec_t timeout_usec; + int fd_signal; + unsigned int builtin_run; + unsigned int builtin_ret; + bool sigterm; + bool inotify_watch; + bool inotify_watch_final; + bool group_set; + bool group_final; + bool owner_set; + bool owner_final; + bool mode_set; + bool mode_final; + bool name_final; + bool devlink_final; + bool run_final; +}; + +struct udev_watch { + struct udev_list_node node; + int handle; + char *name; +}; + +/* udev-rules.c */ +struct udev_rules; +struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names); +struct udev_rules *udev_rules_unref(struct udev_rules *rules); +bool udev_rules_check_timestamp(struct udev_rules *rules); +int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask); +int udev_rules_apply_static_dev_perms(struct udev_rules *rules); + +/* udev-event.c */ +struct udev_event *udev_event_new(struct udev_device *dev); +void udev_event_unref(struct udev_event *event); +size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size); +int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string, + char *result, size_t maxsize, int read_value); +int udev_event_spawn(struct udev_event *event, + const char *cmd, char **envp, const sigset_t *sigmask, + char *result, size_t ressize); +int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigset); +void udev_event_execute_run(struct udev_event *event, const sigset_t *sigset); +int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]); + +/* udev-watch.c */ +int udev_watch_init(struct udev *udev); +void udev_watch_restore(struct udev *udev); +void udev_watch_begin(struct udev *udev, struct udev_device *dev); +void udev_watch_end(struct udev *udev, struct udev_device *dev); +struct udev_device *udev_watch_lookup(struct udev *udev, int wd); + +/* udev-node.c */ +void udev_node_add(struct udev_device *dev, bool apply, + mode_t mode, uid_t uid, gid_t gid, + struct udev_list *seclabel_list); +void udev_node_remove(struct udev_device *dev); +void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old); + +/* udev-ctrl.c */ +struct udev_ctrl; +struct udev_ctrl *udev_ctrl_new(struct udev *udev); +struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd); +int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); +struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); +int udev_ctrl_cleanup(struct udev_ctrl *uctrl); +struct udev *udev_ctrl_get_udev(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, int timeout); +int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout); +int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout); +int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout); +int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout); +int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout); +int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout); +int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int 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); + +/* built-in commands */ +enum udev_builtin_cmd { +#ifdef HAVE_BLKID + UDEV_BUILTIN_BLKID, +#endif + UDEV_BUILTIN_BTRFS, +#ifdef HAVE_FIRMWARE + UDEV_BUILTIN_FIRMWARE, +#endif + UDEV_BUILTIN_HWDB, + UDEV_BUILTIN_INPUT_ID, + UDEV_BUILTIN_KEYBOARD, +#ifdef HAVE_KMOD + UDEV_BUILTIN_KMOD, +#endif + UDEV_BUILTIN_NET_ID, + UDEV_BUILTIN_NET_LINK, + UDEV_BUILTIN_PATH_ID, + UDEV_BUILTIN_USB_ID, +#ifdef HAVE_ACL + UDEV_BUILTIN_UACCESS, +#endif + UDEV_BUILTIN_MAX +}; +struct udev_builtin { + const char *name; + int (*cmd)(struct udev_device *dev, int argc, char *argv[], bool test); + const char *help; + int (*init)(struct udev *udev); + void (*exit)(struct udev *udev); + bool (*validate)(struct udev *udev); + bool run_once; +}; +#ifdef HAVE_BLKID +extern const struct udev_builtin udev_builtin_blkid; +#endif +extern const struct udev_builtin udev_builtin_btrfs; +#ifdef HAVE_FIRMWARE +extern const struct udev_builtin udev_builtin_firmware; +#endif +extern const struct udev_builtin udev_builtin_hwdb; +extern const struct udev_builtin udev_builtin_input_id; +extern const struct udev_builtin udev_builtin_keyboard; +#ifdef HAVE_KMOD +extern const struct udev_builtin udev_builtin_kmod; +#endif +extern const struct udev_builtin udev_builtin_net_id; +extern const struct udev_builtin udev_builtin_net_setup_link; +extern const struct udev_builtin udev_builtin_path_id; +extern const struct udev_builtin udev_builtin_usb_id; +extern const struct udev_builtin udev_builtin_uaccess; +void udev_builtin_init(struct udev *udev); +void udev_builtin_exit(struct udev *udev); +enum udev_builtin_cmd udev_builtin_lookup(const char *command); +const char *udev_builtin_name(enum udev_builtin_cmd cmd); +bool udev_builtin_run_once(enum udev_builtin_cmd cmd); +int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test); +void udev_builtin_list(struct udev *udev); +bool udev_builtin_validate(struct udev *udev); +int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val); +int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const char *modalias, + const char *filter, bool test); + +/* udev logging */ +void udev_main_log(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) _printf_(6, 0); + +/* udevadm commands */ +struct udevadm_cmd { + const char *name; + int (*cmd)(struct udev *udev, int argc, char *argv[]); + const char *help; + int debug; +}; +extern const struct udevadm_cmd udevadm_info; +extern const struct udevadm_cmd udevadm_trigger; +extern const struct udevadm_cmd udevadm_settle; +extern const struct udevadm_cmd udevadm_control; +extern const struct udevadm_cmd udevadm_monitor; +extern const struct udevadm_cmd udevadm_hwdb; +extern const struct udevadm_cmd udevadm_test; +extern const struct udevadm_cmd udevadm_test_builtin; diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in new file mode 100644 index 0000000..a0c2e82 --- /dev/null +++ b/src/udev/udev.pc.in @@ -0,0 +1,5 @@ +Name: udev +Description: udev +Version: @VERSION@ + +udevdir=@udevlibexecdir@ diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c new file mode 100644 index 0000000..3a6c8ef --- /dev/null +++ b/src/udev/udevadm-control.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2005-2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" + +static void print_help(void) +{ + printf("Usage: udevadm control COMMAND\n" + " -e,--exit instruct the daemon to cleanup and exit\n" + " -l,--log-priority=LEVEL set the udev log level for the daemon\n" + " -s,--stop-exec-queue do not execute events, queue only\n" + " -S,--start-exec-queue execute events, flush queue\n" + " -R,--reload reload rules and databases\n" + " -p,--property=KEY=VALUE set a global property for all events\n" + " -m,--children-max=N maximum number of children\n" + " --timeout=SECONDS maximum time to block for a reply\n" + " -h,--help print this help text\n\n"); +} + +static int adm_control(struct udev *udev, int argc, char *argv[]) +{ + _cleanup_udev_ctrl_unref_ struct udev_ctrl *uctrl = NULL; + int timeout = 60; + int rc = 1, c; + + static const struct option options[] = { + { "exit", no_argument, NULL, 'e' }, + { "log-priority", required_argument, NULL, 'l' }, + { "stop-exec-queue", no_argument, NULL, 's' }, + { "start-exec-queue", no_argument, NULL, 'S' }, + { "reload", no_argument, NULL, 'R' }, + { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ + { "property", required_argument, NULL, 'p' }, + { "env", required_argument, NULL, 'p' }, /* alias for -p */ + { "children-max", required_argument, NULL, 'm' }, + { "timeout", required_argument, NULL, 't' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + if (getuid() != 0) { + fprintf(stderr, "root privileges required\n"); + return 1; + } + + uctrl = udev_ctrl_new(udev); + if (uctrl == NULL) + return 2; + + while ((c = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL)) >= 0) + switch (c) { + case 'e': + if (udev_ctrl_send_exit(uctrl, timeout) < 0) + rc = 2; + else + rc = 0; + break; + case 'l': { + int i; + + i = util_log_priority(optarg); + if (i < 0) { + fprintf(stderr, "invalid number '%s'\n", optarg); + return rc; + } + if (udev_ctrl_send_set_log_level(uctrl, util_log_priority(optarg), timeout) < 0) + rc = 2; + else + rc = 0; + break; + } + case 's': + if (udev_ctrl_send_stop_exec_queue(uctrl, timeout) < 0) + rc = 2; + else + rc = 0; + break; + case 'S': + if (udev_ctrl_send_start_exec_queue(uctrl, timeout) < 0) + rc = 2; + else + rc = 0; + break; + case 'R': + if (udev_ctrl_send_reload(uctrl, timeout) < 0) + rc = 2; + else + rc = 0; + break; + case 'p': + if (strchr(optarg, '=') == NULL) { + fprintf(stderr, "expect = instead of '%s'\n", optarg); + return rc; + } + if (udev_ctrl_send_set_env(uctrl, optarg, timeout) < 0) + rc = 2; + else + rc = 0; + break; + case 'm': { + char *endp; + int i; + + i = strtoul(optarg, &endp, 0); + if (endp[0] != '\0' || i < 1) { + fprintf(stderr, "invalid number '%s'\n", optarg); + return rc; + } + if (udev_ctrl_send_set_children_max(uctrl, i, timeout) < 0) + rc = 2; + else + rc = 0; + break; + } + case 't': { + int seconds; + + seconds = atoi(optarg); + if (seconds >= 0) + timeout = seconds; + else + fprintf(stderr, "invalid timeout value\n"); + break; + } + case 'h': + print_help(); + rc = 0; + break; + } + + if (optind < argc) + fprintf(stderr, "Extraneous argument: %s\n", argv[optind]); + else if (optind == 1) + fprintf(stderr, "Option missing\n"); + return rc; +} + +const struct udevadm_cmd udevadm_control = { + .name = "control", + .cmd = adm_control, + .help = "control the udev daemon", +}; diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c new file mode 100644 index 0000000..65cbf61 --- /dev/null +++ b/src/udev/udevadm-hwdb.c @@ -0,0 +1,664 @@ +/*** + This file is part of systemd. + + Copyright 2012 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "strbuf.h" +#include "conf-files.h" + +#include "udev.h" +#include "libudev-hwdb-def.h" + +/* + * Generic udev properties, key/value database based on modalias strings. + * Uses a Patricia/radix trie to index all matches for efficient lookup. + */ + +static const char * const conf_file_dirs[] = { + "/etc/udev/hwdb.d", + UDEVLIBEXECDIR "/hwdb.d", + NULL +}; + +/* in-memory trie objects */ +struct trie { + struct trie_node *root; + struct strbuf *strings; + + size_t nodes_count; + size_t children_count; + size_t values_count; +}; + +struct trie_node { + /* prefix, common part for all children of this node */ + size_t prefix_off; + + /* sorted array of pointers to children nodes */ + struct trie_child_entry *children; + uint8_t children_count; + + /* sorted array of key/value pairs */ + struct trie_value_entry *values; + size_t values_count; +}; + +/* children array item with char (0-255) index */ +struct trie_child_entry { + uint8_t c; + struct trie_node *child; +}; + +/* value array item with key/value pairs */ +struct trie_value_entry { + size_t key_off; + size_t value_off; +}; + +static int trie_children_cmp(const void *v1, const void *v2) { + const struct trie_child_entry *n1 = v1; + const struct trie_child_entry *n2 = v2; + + return n1->c - n2->c; +} + +static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) { + struct trie_child_entry *child; + + /* extend array, add new entry, sort for bisection */ + child = realloc(node->children, (node->children_count + 1) * sizeof(struct trie_child_entry)); + if (!child) + return -ENOMEM; + + node->children = child; + trie->children_count++; + node->children[node->children_count].c = c; + node->children[node->children_count].child = node_child; + node->children_count++; + qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp); + trie->nodes_count++; + + return 0; +} + +static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) { + struct trie_child_entry *child; + struct trie_child_entry search; + + search.c = c; + child = bsearch(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp); + if (child) + return child->child; + return NULL; +} + +static void trie_node_cleanup(struct trie_node *node) { + size_t i; + + for (i = 0; i < node->children_count; i++) + trie_node_cleanup(node->children[i].child); + free(node->children); + free(node->values); + free(node); +} + +static int trie_values_cmp(const void *v1, const void *v2, void *arg) { + const struct trie_value_entry *val1 = v1; + const struct trie_value_entry *val2 = v2; + struct trie *trie = arg; + + return strcmp(trie->strings->buf + val1->key_off, + trie->strings->buf + val2->key_off); +} + +static int trie_node_add_value(struct trie *trie, struct trie_node *node, + const char *key, const char *value) { + ssize_t k, v; + struct trie_value_entry *val; + + k = strbuf_add_string(trie->strings, key, strlen(key)); + if (k < 0) + return k; + v = strbuf_add_string(trie->strings, value, strlen(value)); + if (v < 0) + return v; + + if (node->values_count) { + struct trie_value_entry search = { + .key_off = k, + .value_off = v, + }; + + val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); + if (val) { + /* replace existing earlier key with new value */ + val->value_off = v; + return 0; + } + } + + /* extend array, add new entry, sort for bisection */ + val = realloc(node->values, (node->values_count + 1) * sizeof(struct trie_value_entry)); + if (!val) + return -ENOMEM; + trie->values_count++; + node->values = val; + node->values[node->values_count].key_off = k; + node->values[node->values_count].value_off = v; + node->values_count++; + qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); + return 0; +} + +static int trie_insert(struct trie *trie, struct trie_node *node, const char *search, + const char *key, const char *value) { + size_t i = 0; + int err = 0; + + for (;;) { + size_t p; + uint8_t c; + struct trie_node *child; + + for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) { + _cleanup_free_ char *s = NULL; + ssize_t off; + _cleanup_free_ struct trie_node *new_child = NULL; + + if (c == search[i + p]) + continue; + + /* split node */ + new_child = new0(struct trie_node, 1); + if (!new_child) + return -ENOMEM; + + /* move values from parent to child */ + new_child->prefix_off = node->prefix_off + p+1; + new_child->children = node->children; + new_child->children_count = node->children_count; + new_child->values = node->values; + new_child->values_count = node->values_count; + + /* update parent; use strdup() because the source gets realloc()d */ + s = strndup(trie->strings->buf + node->prefix_off, p); + if (!s) + return -ENOMEM; + + off = strbuf_add_string(trie->strings, s, p); + if (off < 0) + return off; + + node->prefix_off = off; + node->children = NULL; + node->children_count = 0; + node->values = NULL; + node->values_count = 0; + err = node_add_child(trie, node, new_child, c); + if (err) + return err; + + new_child = NULL; /* avoid cleanup */ + break; + } + i += p; + + c = search[i]; + if (c == '\0') + return trie_node_add_value(trie, node, key, value); + + child = node_lookup(node, c); + if (!child) { + ssize_t off; + + /* new child */ + child = new0(struct trie_node, 1); + if (!child) + return -ENOMEM; + + off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1)); + if (off < 0) { + free(child); + return off; + } + + child->prefix_off = off; + err = node_add_child(trie, node, child, c); + if (err) { + free(child); + return err; + } + + return trie_node_add_value(trie, child, key, value); + } + + node = child; + i++; + } +} + +struct trie_f { + FILE *f; + struct trie *trie; + uint64_t strings_off; + + uint64_t nodes_count; + uint64_t children_count; + uint64_t values_count; +}; + +/* calculate the storage space for the nodes, children arrays, value arrays */ +static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) { + uint64_t i; + + for (i = 0; i < node->children_count; i++) + trie_store_nodes_size(trie, node->children[i].child); + + trie->strings_off += sizeof(struct trie_node_f); + for (i = 0; i < node->children_count; i++) + trie->strings_off += sizeof(struct trie_child_entry_f); + for (i = 0; i < node->values_count; i++) + trie->strings_off += sizeof(struct trie_value_entry_f); +} + +static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) { + uint64_t i; + struct trie_node_f n = { + .prefix_off = htole64(trie->strings_off + node->prefix_off), + .children_count = node->children_count, + .values_count = htole64(node->values_count), + }; + struct trie_child_entry_f *children = NULL; + int64_t node_off; + + if (node->children_count) { + children = new0(struct trie_child_entry_f, node->children_count); + if (!children) + return -ENOMEM; + } + + /* post-order recursion */ + for (i = 0; i < node->children_count; i++) { + int64_t child_off; + + child_off = trie_store_nodes(trie, node->children[i].child); + if (child_off < 0) { + free(children); + return child_off; + } + children[i].c = node->children[i].c; + children[i].child_off = htole64(child_off); + } + + /* write node */ + node_off = ftello(trie->f); + fwrite(&n, sizeof(struct trie_node_f), 1, trie->f); + trie->nodes_count++; + + /* append children array */ + if (node->children_count) { + fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f); + trie->children_count += node->children_count; + free(children); + } + + /* append values array */ + for (i = 0; i < node->values_count; i++) { + struct trie_value_entry_f v = { + .key_off = htole64(trie->strings_off + node->values[i].key_off), + .value_off = htole64(trie->strings_off + node->values[i].value_off), + }; + + fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f); + trie->values_count++; + } + + return node_off; +} + +static int trie_store(struct trie *trie, const char *filename) { + struct trie_f t = { + .trie = trie, + }; + _cleanup_free_ char *filename_tmp = NULL; + int64_t pos; + int64_t root_off; + int64_t size; + struct trie_header_f h = { + .signature = HWDB_SIG, + .tool_version = htole64(atoi(VERSION)), + .header_size = htole64(sizeof(struct trie_header_f)), + .node_size = htole64(sizeof(struct trie_node_f)), + .child_entry_size = htole64(sizeof(struct trie_child_entry_f)), + .value_entry_size = htole64(sizeof(struct trie_value_entry_f)), + }; + int err; + + /* calculate size of header, nodes, children entries, value entries */ + t.strings_off = sizeof(struct trie_header_f); + trie_store_nodes_size(&t, trie->root); + + err = fopen_temporary(filename , &t.f, &filename_tmp); + if (err < 0) + return err; + fchmod(fileno(t.f), 0444); + + /* write nodes */ + fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET); + root_off = trie_store_nodes(&t, trie->root); + h.nodes_root_off = htole64(root_off); + pos = ftello(t.f); + h.nodes_len = htole64(pos - sizeof(struct trie_header_f)); + + /* write string buffer */ + fwrite(trie->strings->buf, trie->strings->len, 1, t.f); + h.strings_len = htole64(trie->strings->len); + + /* write header */ + size = ftello(t.f); + h.file_size = htole64(size); + fseeko(t.f, 0, SEEK_SET); + fwrite(&h, sizeof(struct trie_header_f), 1, t.f); + err = ferror(t.f); + if (err) + err = -errno; + fclose(t.f); + if (err < 0 || rename(filename_tmp, filename) < 0) { + unlink_noerrno(filename_tmp); + return err < 0 ? err : -errno; + } + + log_debug("=== trie on-disk ==="); + log_debug("size: %8"PRIu64" bytes", size); + log_debug("header: %8zu bytes", sizeof(struct trie_header_f)); + log_debug("nodes: %8"PRIu64" bytes (%8"PRIu64")", + t.nodes_count * sizeof(struct trie_node_f), t.nodes_count); + log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")", + t.children_count * sizeof(struct trie_child_entry_f), t.children_count); + log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")", + t.values_count * sizeof(struct trie_value_entry_f), t.values_count); + log_debug("string store: %8zu bytes", trie->strings->len); + log_debug("strings start: %8"PRIu64, t.strings_off); + + return 0; +} + +static int insert_data(struct trie *trie, struct udev_list *match_list, + char *line, const char *filename) { + char *value; + struct udev_list_entry *entry; + + value = strchr(line, '='); + if (!value) { + log_error("Error, key/value pair expected but got '%s' in '%s':", line, filename); + return -EINVAL; + } + + value[0] = '\0'; + value++; + + if (line[0] == '\0' || value[0] == '\0') { + log_error("Error, empty key or value '%s' in '%s':", line, filename); + return -EINVAL; + } + + udev_list_entry_foreach(entry, udev_list_get_entry(match_list)) + trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value); + + return 0; +} + +static int import_file(struct udev *udev, struct trie *trie, const char *filename) { + enum { + HW_MATCH, + HW_DATA, + HW_NONE, + } state = HW_NONE; + FILE *f; + char line[LINE_MAX]; + struct udev_list match_list; + + udev_list_init(udev, &match_list, false); + + f = fopen(filename, "re"); + if (f == NULL) + return -errno; + + while (fgets(line, sizeof(line), f)) { + size_t len; + char *pos; + + /* comment line */ + if (line[0] == '#') + continue; + + /* strip trailing comment */ + pos = strchr(line, '#'); + if (pos) + pos[0] = '\0'; + + /* strip trailing whitespace */ + len = strlen(line); + while (len > 0 && isspace(line[len-1])) + len--; + line[len] = '\0'; + + switch (state) { + case HW_NONE: + if (len == 0) + break; + + if (line[0] == ' ') { + log_error("Error, MATCH expected but got '%s' in '%s':", line, filename); + break; + } + + /* start of record, first match */ + state = HW_MATCH; + udev_list_entry_add(&match_list, line, NULL); + break; + + case HW_MATCH: + if (len == 0) { + log_error("Error, DATA expected but got empty line in '%s':", filename); + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } + + /* another match */ + if (line[0] != ' ') { + udev_list_entry_add(&match_list, line, NULL); + break; + } + + /* first data */ + state = HW_DATA; + insert_data(trie, &match_list, line, filename); + break; + + case HW_DATA: + /* end of record */ + if (len == 0) { + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } + + if (line[0] != ' ') { + log_error("Error, DATA expected but got '%s' in '%s':", line, filename); + state = HW_NONE; + udev_list_cleanup(&match_list); + break; + } + + insert_data(trie, &match_list, line, filename); + break; + }; + } + + fclose(f); + udev_list_cleanup(&match_list); + return 0; +} + +static void help(void) { + printf("Usage: udevadm hwdb OPTIONS\n" + " -u,--update update the hardware database\n" + " -t,--test=MODALIAS query database and print result\n" + " -r,--root=PATH alternative root path in the filesystem\n" + " -h,--help\n\n"); +} + +static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { + static const struct option options[] = { + { "update", no_argument, NULL, 'u' }, + { "test", required_argument, NULL, 't' }, + { "root", required_argument, NULL, 'r' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + const char *test = NULL; + const char *root = ""; + bool update = false; + struct trie *trie = NULL; + int err, c; + int rc = EXIT_SUCCESS; + + while ((c = getopt_long(argc, argv, "ut:r:h", options, NULL)) >= 0) + switch(c) { + case 'u': + update = true; + break; + case 't': + test = optarg; + break; + case 'r': + root = optarg; + break; + case 'h': + help(); + return EXIT_SUCCESS; + case '?': + return EXIT_FAILURE; + default: + assert_not_reached("Unknown option"); + } + + if (!update && !test) { + log_error("Either --update or --test must be used"); + return EXIT_FAILURE; + } + + if (update) { + char **files, **f; + _cleanup_free_ char *hwdb_bin = NULL; + + trie = new0(struct trie, 1); + if (!trie) { + rc = EXIT_FAILURE; + goto out; + } + + /* string store */ + trie->strings = strbuf_new(); + if (!trie->strings) { + rc = EXIT_FAILURE; + goto out; + } + + /* index */ + trie->root = new0(struct trie_node, 1); + if (!trie->root) { + rc = EXIT_FAILURE; + goto out; + } + trie->nodes_count++; + + err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs); + if (err < 0) { + log_error("failed to enumerate hwdb files: %s", strerror(-err)); + rc = EXIT_FAILURE; + goto out; + } + STRV_FOREACH(f, files) { + log_debug("reading file '%s'", *f); + import_file(udev, trie, *f); + } + strv_free(files); + + strbuf_complete(trie->strings); + + log_debug("=== trie in-memory ==="); + log_debug("nodes: %8zu bytes (%8zu)", + trie->nodes_count * sizeof(struct trie_node), trie->nodes_count); + log_debug("children arrays: %8zu bytes (%8zu)", + trie->children_count * sizeof(struct trie_child_entry), trie->children_count); + log_debug("values arrays: %8zu bytes (%8zu)", + trie->values_count * sizeof(struct trie_value_entry), trie->values_count); + log_debug("strings: %8zu bytes", + trie->strings->len); + log_debug("strings incoming: %8zu bytes (%8zu)", + trie->strings->in_len, trie->strings->in_count); + log_debug("strings dedup'ed: %8zu bytes (%8zu)", + trie->strings->dedup_len, trie->strings->dedup_count); + + if (asprintf(&hwdb_bin, "%s/etc/udev/hwdb.bin", root) < 0) { + rc = EXIT_FAILURE; + goto out; + } + mkdir_parents(hwdb_bin, 0755); + err = trie_store(trie, hwdb_bin); + if (err < 0) { + log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err)); + rc = EXIT_FAILURE; + } + } + + if (test) { + struct udev_hwdb *hwdb = udev_hwdb_new(udev); + + if (hwdb) { + struct udev_list_entry *entry; + + udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0)) + printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); + udev_hwdb_unref(hwdb); + } + } +out: + if (trie) { + if (trie->root) + trie_node_cleanup(trie->root); + strbuf_cleanup(trie->strings); + free(trie); + } + return rc; +} + +const struct udevadm_cmd udevadm_hwdb = { + .name = "hwdb", + .cmd = adm_hwdb, + .help = "maintain the hardware database index", +}; diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c new file mode 100644 index 0000000..64bb537 --- /dev/null +++ b/src/udev/udevadm-info.c @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2004-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" + +static bool skip_attribute(const char *name) +{ + static const char* const skip[] = { + "uevent", + "dev", + "modalias", + "resource", + "driver", + "subsystem", + "module", + }; + unsigned int i; + + for (i = 0; i < ELEMENTSOF(skip); i++) + if (streq(name, skip[i])) + return true; + return false; +} + +static void print_all_attributes(struct udev_device *device, const char *key) +{ + struct udev_list_entry *sysattr; + + udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) { + const char *name; + const char *value; + size_t len; + + name = udev_list_entry_get_name(sysattr); + if (skip_attribute(name)) + continue; + + value = udev_device_get_sysattr_value(device, name); + if (value == NULL) + continue; + + /* skip any values that look like a path */ + if (value[0] == '/') + continue; + + /* skip nonprintable attributes */ + len = strlen(value); + while (len > 0 && isprint(value[len-1])) + len--; + if (len > 0) + continue; + + printf(" %s{%s}==\"%s\"\n", key, name, value); + } + printf("\n"); +} + +static int print_device_chain(struct udev_device *device) +{ + struct udev_device *device_parent; + const char *str; + + printf("\n" + "Udevadm info starts with the device specified by the devpath and then\n" + "walks up the chain of parent devices. It prints for every device\n" + "found, all possible attributes in the udev rules key format.\n" + "A rule to match, can be composed by the attributes of the device\n" + "and the attributes from one single parent device.\n" + "\n"); + + printf(" looking at device '%s':\n", udev_device_get_devpath(device)); + printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device)); + str = udev_device_get_subsystem(device); + if (str == NULL) + str = ""; + printf(" SUBSYSTEM==\"%s\"\n", str); + str = udev_device_get_driver(device); + if (str == NULL) + str = ""; + printf(" DRIVER==\"%s\"\n", str); + print_all_attributes(device, "ATTR"); + + device_parent = device; + do { + device_parent = udev_device_get_parent(device_parent); + if (device_parent == NULL) + break; + printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent)); + printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent)); + str = udev_device_get_subsystem(device_parent); + if (str == NULL) + str = ""; + printf(" SUBSYSTEMS==\"%s\"\n", str); + str = udev_device_get_driver(device_parent); + if (str == NULL) + str = ""; + printf(" DRIVERS==\"%s\"\n", str); + print_all_attributes(device_parent, "ATTRS"); + } while (device_parent != NULL); + + return 0; +} + +static void print_record(struct udev_device *device) +{ + const char *str; + int i; + struct udev_list_entry *list_entry; + + printf("P: %s\n", udev_device_get_devpath(device)); + + str = udev_device_get_devnode(device); + if (str != NULL) + printf("N: %s\n", str + strlen("/dev/")); + + i = udev_device_get_devlink_priority(device); + if (i != 0) + printf("L: %i\n", i); + + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) + printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/")); + + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) + printf("E: %s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + printf("\n"); +} + +static int stat_device(const char *name, bool export, const char *prefix) +{ + struct stat statbuf; + + if (stat(name, &statbuf) != 0) + return -1; + + if (export) { + if (prefix == NULL) + prefix = "INFO_"; + printf("%sMAJOR=%d\n" + "%sMINOR=%d\n", + prefix, major(statbuf.st_dev), + prefix, minor(statbuf.st_dev)); + } else + printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev)); + return 0; +} + +static int export_devices(struct udev *udev) +{ + struct udev_enumerate *udev_enumerate; + struct udev_list_entry *list_entry; + + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return -1; + udev_enumerate_scan_devices(udev_enumerate); + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) { + struct udev_device *device; + + device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); + if (device != NULL) { + print_record(device); + udev_device_unref(device); + } + } + udev_enumerate_unref(udev_enumerate); + return 0; +} + +static void cleanup_dir(DIR *dir, mode_t mask, int depth) +{ + struct dirent *dent; + + if (depth <= 0) + return; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct stat stats; + + if (dent->d_name[0] == '.') + continue; + if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0) + continue; + if ((stats.st_mode & mask) != 0) + continue; + if (S_ISDIR(stats.st_mode)) { + DIR *dir2; + + dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); + if (dir2 != NULL) { + cleanup_dir(dir2, mask, depth-1); + closedir(dir2); + } + unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR); + } else { + unlinkat(dirfd(dir), dent->d_name, 0); + } + } +} + +static void cleanup_db(struct udev *udev) +{ + DIR *dir; + + unlink("/run/udev/queue.bin"); + + dir = opendir("/run/udev/data"); + if (dir != NULL) { + cleanup_dir(dir, S_ISVTX, 1); + closedir(dir); + } + + dir = opendir("/run/udev/links"); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + dir = opendir("/run/udev/tags"); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + dir = opendir("/run/udev/static_node-tags"); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + dir = opendir("/run/udev/watch"); + if (dir != NULL) { + cleanup_dir(dir, 0, 1); + closedir(dir); + } +} + +static struct udev_device *find_device(struct udev *udev, const char *id, const char *prefix) +{ + char name[UTIL_PATH_SIZE]; + + if (prefix && !startswith(id, prefix)) { + strscpyl(name, sizeof(name), prefix, id, NULL); + id = name; + } + + if (startswith(id, "/dev/")) { + struct stat statbuf; + char type; + + if (stat(id, &statbuf) < 0) + return NULL; + + if (S_ISBLK(statbuf.st_mode)) + type = 'b'; + else if (S_ISCHR(statbuf.st_mode)) + type = 'c'; + else + return NULL; + + return udev_device_new_from_devnum(udev, type, statbuf.st_rdev); + } else if (startswith(id, "/sys/")) + return udev_device_new_from_syspath(udev, id); + else + return NULL; +} + +static int uinfo(struct udev *udev, int argc, char *argv[]) +{ + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + bool root = 0; + bool export = 0; + const char *export_prefix = NULL; + char name[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + int c; + + static const struct option options[] = { + { "name", required_argument, NULL, 'n' }, + { "path", required_argument, NULL, 'p' }, + { "query", required_argument, NULL, 'q' }, + { "attribute-walk", no_argument, NULL, 'a' }, + { "cleanup-db", no_argument, NULL, 'c' }, + { "export-db", no_argument, NULL, 'e' }, + { "root", no_argument, NULL, 'r' }, + { "device-id-of-file", required_argument, NULL, 'd' }, + { "export", no_argument, NULL, 'x' }, + { "export-prefix", required_argument, NULL, 'P' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + static const char *usage = + "Usage: udevadm info [OPTIONS] [DEVPATH|FILE]\n" + " -q,--query=TYPE query device information:\n" + " name name of device node\n" + " symlink pointing to node\n" + " path sys device path\n" + " property the device properties\n" + " all all values\n" + " -p,--path=SYSPATH sys device path used for query or attribute walk\n" + " -n,--name=NAME node or symlink name used for query or attribute walk\n" + " -r,--root prepend dev directory to path names\n" + " -a,--attribute-walk print all key matches walking along the chain\n" + " of parent devices\n" + " -d,--device-id-of-file=FILE print major:minor of device containing this file\n" + " -x,--export export key/value pairs\n" + " -P,--export-prefix export the key name with a prefix\n" + " -e,--export-db export the content of the udev database\n" + " -c,--cleanup-db cleanup the udev database\n" + " --version print version of the program\n" + " -h,--help print this message\n"; + + enum action_type { + ACTION_QUERY, + ACTION_ATTRIBUTE_WALK, + ACTION_DEVICE_ID_FILE, + } action = ACTION_QUERY; + + enum query_type { + QUERY_NAME, + QUERY_PATH, + QUERY_SYMLINK, + QUERY_PROPERTY, + QUERY_ALL, + } query = QUERY_ALL; + + while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0) + switch (c) { + case 'n': { + if (device != NULL) { + fprintf(stderr, "device already specified\n"); + return 2; + } + + device = find_device(udev, optarg, "/dev/"); + if (device == NULL) { + fprintf(stderr, "device node not found\n"); + return 2; + } + break; + } + case 'p': + if (device != NULL) { + fprintf(stderr, "device already specified\n"); + return 2; + } + + device = find_device(udev, optarg, "/sys"); + if (device == NULL) { + fprintf(stderr, "syspath not found\n"); + return 2; + } + break; + case 'q': + action = ACTION_QUERY; + if (streq(optarg, "property") || streq(optarg, "env")) + query = QUERY_PROPERTY; + else if (streq(optarg, "name")) + query = QUERY_NAME; + else if (streq(optarg, "symlink")) + query = QUERY_SYMLINK; + else if (streq(optarg, "path")) + query = QUERY_PATH; + else if (streq(optarg, "all")) + query = QUERY_ALL; + else { + fprintf(stderr, "unknown query type\n"); + return 3; + } + break; + case 'r': + root = true; + break; + case 'd': + action = ACTION_DEVICE_ID_FILE; + strscpy(name, sizeof(name), optarg); + break; + case 'a': + action = ACTION_ATTRIBUTE_WALK; + break; + case 'e': + export_devices(udev); + return 0; + case 'c': + cleanup_db(udev); + return 0; + case 'x': + export = true; + break; + case 'P': + export_prefix = optarg; + break; + case 'V': + printf("%s\n", VERSION); + return 0; + case 'h': + printf("%s\n", usage); + return 0; + default: + return 1; + } + + switch (action) { + case ACTION_QUERY: + if (!device) { + if (!argv[optind]) { + fprintf(stderr, "%s\n", usage); + return 2; + } + device = find_device(udev, argv[optind], NULL); + if (!device) { + fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n"); + return 4; + } + } + + switch(query) { + case QUERY_NAME: { + const char *node = udev_device_get_devnode(device); + + if (node == NULL) { + fprintf(stderr, "no device node found\n"); + return 5; + } + + if (root) + printf("%s\n", udev_device_get_devnode(device)); + else + printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/")); + break; + } + case QUERY_SYMLINK: + list_entry = udev_device_get_devlinks_list_entry(device); + while (list_entry != NULL) { + if (root) + printf("%s", udev_list_entry_get_name(list_entry)); + else + printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/")); + list_entry = udev_list_entry_get_next(list_entry); + if (list_entry != NULL) + printf(" "); + } + printf("\n"); + break; + case QUERY_PATH: + printf("%s\n", udev_device_get_devpath(device)); + return 0; + case QUERY_PROPERTY: + list_entry = udev_device_get_properties_list_entry(device); + while (list_entry != NULL) { + if (export) { + const char *prefix = export_prefix; + + if (prefix == NULL) + prefix = ""; + printf("%s%s='%s'\n", prefix, + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } else { + printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); + } + list_entry = udev_list_entry_get_next(list_entry); + } + break; + case QUERY_ALL: + print_record(device); + break; + default: + fprintf(stderr, "unknown query type\n"); + break; + } + break; + case ACTION_ATTRIBUTE_WALK: + if (!device && argv[optind]) { + device = find_device(udev, argv[optind], NULL); + if (!device) { + fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n"); + return 4; + } + } + if (!device) { + fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n"); + return 4; + } + print_device_chain(device); + break; + case ACTION_DEVICE_ID_FILE: + if (stat_device(name, export, export_prefix) != 0) + return 1; + break; + } + + return 0; +} + +const struct udevadm_cmd udevadm_info = { + .name = "info", + .cmd = uinfo, + .help = "query sysfs or the udev database", +}; diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c new file mode 100644 index 0000000..b2f7f6b --- /dev/null +++ b/src/udev/udevadm-monitor.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2004-2010 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" + +static bool udev_exit; + +static void sig_handler(int signum) +{ + if (signum == SIGINT || signum == SIGTERM) + udev_exit = true; +} + +static void print_device(struct udev_device *device, const char *source, int prop) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + printf("%-6s[%llu.%06u] %-8s %s (%s)\n", + source, + (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000, + udev_device_get_action(device), + udev_device_get_devpath(device), + udev_device_get_subsystem(device)); + if (prop) { + struct udev_list_entry *list_entry; + + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) + printf("%s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + printf("\n"); + } +} + +static void help(void) { + printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n" + " -p,--property print the event properties\n" + " -k,--kernel print kernel uevents\n" + " -u,--udev print udev events\n" + " -s,--subsystem-match=SUBSYSTEM[/DEVTYPE] filter events by subsystem\n" + " -t,--tag-match=TAG filter events by tag\n" + " -h,--help\n\n"); +} + +static int adm_monitor(struct udev *udev, int argc, char *argv[]) +{ + struct sigaction act = {}; + sigset_t mask; + bool prop = false; + bool print_kernel = false; + bool print_udev = false; + _cleanup_udev_list_cleanup_ struct udev_list subsystem_match_list; + _cleanup_udev_list_cleanup_ struct udev_list tag_match_list; + _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor = NULL; + _cleanup_udev_monitor_unref_ struct udev_monitor *kernel_monitor = NULL; + _cleanup_close_ int fd_ep = -1; + int fd_kernel = -1, fd_udev = -1; + struct epoll_event ep_kernel, ep_udev; + int c; + + static const struct option options[] = { + { "property", no_argument, NULL, 'p' }, + { "environment", no_argument, NULL, 'e' }, /* alias for -p */ + { "kernel", no_argument, NULL, 'k' }, + { "udev", no_argument, NULL, 'u' }, + { "subsystem-match", required_argument, NULL, 's' }, + { "tag-match", required_argument, NULL, 't' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + udev_list_init(udev, &subsystem_match_list, true); + udev_list_init(udev, &tag_match_list, true); + + while((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0) + switch (c) { + case 'p': + case 'e': + prop = true; + break; + case 'k': + print_kernel = true; + break; + case 'u': + print_udev = true; + break; + case 's': + { + char subsys[UTIL_NAME_SIZE]; + char *devtype; + + strscpy(subsys, sizeof(subsys), optarg); + devtype = strchr(subsys, '/'); + if (devtype != NULL) { + devtype[0] = '\0'; + devtype++; + } + udev_list_entry_add(&subsystem_match_list, subsys, devtype); + break; + } + case 't': + udev_list_entry_add(&tag_match_list, optarg, NULL); + break; + case 'h': + help(); + return 0; + default: + return 1; + } + + if (!print_kernel && !print_udev) { + print_kernel = true; + print_udev = true; + } + + /* set signal handlers */ + act.sa_handler = sig_handler; + act.sa_flags = SA_RESTART; + sigaction(SIGINT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error("error creating epoll fd: %m"); + return 1; + } + + printf("monitor will print the received events for:\n"); + if (print_udev) { + struct udev_list_entry *entry; + + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor == NULL) { + fprintf(stderr, "error: unable to create netlink socket\n"); + return 1; + } + udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024); + fd_udev = udev_monitor_get_fd(udev_monitor); + + udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) { + const char *subsys = udev_list_entry_get_name(entry); + const char *devtype = udev_list_entry_get_value(entry); + + if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, subsys, devtype) < 0) + fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys); + } + + udev_list_entry_foreach(entry, udev_list_get_entry(&tag_match_list)) { + const char *tag = udev_list_entry_get_name(entry); + + if (udev_monitor_filter_add_match_tag(udev_monitor, tag) < 0) + fprintf(stderr, "error: unable to apply tag filter '%s'\n", tag); + } + + if (udev_monitor_enable_receiving(udev_monitor) < 0) { + fprintf(stderr, "error: unable to subscribe to udev events\n"); + return 2; + } + + memzero(&ep_udev, sizeof(struct epoll_event)); + ep_udev.events = EPOLLIN; + ep_udev.data.fd = fd_udev; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { + log_error("fail to add fd to epoll: %m"); + return 2; + } + + printf("UDEV - the event which udev sends out after rule processing\n"); + } + + if (print_kernel) { + struct udev_list_entry *entry; + + kernel_monitor = udev_monitor_new_from_netlink(udev, "kernel"); + if (kernel_monitor == NULL) { + fprintf(stderr, "error: unable to create netlink socket\n"); + return 3; + } + udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024); + fd_kernel = udev_monitor_get_fd(kernel_monitor); + + udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) { + const char *subsys = udev_list_entry_get_name(entry); + + if (udev_monitor_filter_add_match_subsystem_devtype(kernel_monitor, subsys, NULL) < 0) + fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys); + } + + if (udev_monitor_enable_receiving(kernel_monitor) < 0) { + fprintf(stderr, "error: unable to subscribe to kernel events\n"); + return 4; + } + + memzero(&ep_kernel, sizeof(struct epoll_event)); + ep_kernel.events = EPOLLIN; + ep_kernel.data.fd = fd_kernel; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_kernel, &ep_kernel) < 0) { + log_error("fail to add fd to epoll: %m"); + return 5; + } + + printf("KERNEL - the kernel uevent\n"); + } + printf("\n"); + + while (!udev_exit) { + int fdcount; + struct epoll_event ev[4]; + int i; + + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); + if (fdcount < 0) { + if (errno != EINTR) + fprintf(stderr, "error receiving uevent message: %m\n"); + continue; + } + + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_kernel && ev[i].events & EPOLLIN) { + struct udev_device *device; + + device = udev_monitor_receive_device(kernel_monitor); + if (device == NULL) + continue; + print_device(device, "KERNEL", prop); + udev_device_unref(device); + } else if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { + struct udev_device *device; + + device = udev_monitor_receive_device(udev_monitor); + if (device == NULL) + continue; + print_device(device, "UDEV", prop); + udev_device_unref(device); + } + } + } + + return 0; +} + +const struct udevadm_cmd udevadm_monitor = { + .name = "monitor", + .cmd = adm_monitor, + .help = "listen to kernel and udev events", +}; diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c new file mode 100644 index 0000000..b026155 --- /dev/null +++ b/src/udev/udevadm-settle.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2006-2009 Kay Sievers + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" +#include "util.h" + +static void help(void) { + printf("Usage: udevadm settle OPTIONS\n" + " -t,--timeout= maximum time to wait for events\n" + " -s,--seq-start= first seqnum to wait for\n" + " -e,--seq-end= last seqnum to wait for\n" + " -E,--exit-if-exists= stop waiting if file exists\n" + " -q,--quiet do not print list after timeout\n" + " -h,--help\n\n"); +} + +static int adm_settle(struct udev *udev, int argc, char *argv[]) +{ + static const struct option options[] = { + { "seq-start", required_argument, NULL, 's' }, + { "seq-end", required_argument, NULL, 'e' }, + { "timeout", required_argument, NULL, 't' }, + { "exit-if-exists", required_argument, NULL, 'E' }, + { "quiet", no_argument, NULL, 'q' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + usec_t start_usec = now(CLOCK_MONOTONIC); + usec_t start = 0; + usec_t end = 0; + int quiet = 0; + const char *exists = NULL; + unsigned int timeout = 120; + struct pollfd pfd[1] = { {.fd = -1}, }; + _cleanup_udev_queue_unref_ struct udev_queue *udev_queue = NULL; + int rc = EXIT_FAILURE, c; + + while ((c = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL)) >= 0) + switch (c) { + case 's': + start = strtoull(optarg, NULL, 0); + break; + case 'e': + end = strtoull(optarg, NULL, 0); + break; + case 't': { + int r; + + r = safe_atou(optarg, &timeout); + if (r < 0) { + fprintf(stderr, "Invalid timeout value '%s': %s\n", + optarg, strerror(-r)); + exit(EXIT_FAILURE); + }; + break; + } + case 'E': + exists = optarg; + break; + case 'q': + quiet = 1; + break; + case 'h': + help(); + exit(EXIT_SUCCESS); + case '?': + exit(EXIT_FAILURE); + default: + assert_not_reached("Unkown argument"); + } + + if (optind < argc) { + fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]); + exit(EXIT_FAILURE); + } + + udev_queue = udev_queue_new(udev); + if (udev_queue == NULL) + exit(2); + + if (start > 0) { + unsigned long long kernel_seq; + + kernel_seq = udev_queue_get_kernel_seqnum(udev_queue); + + /* unless specified, the last event is the current kernel seqnum */ + if (end == 0) + end = udev_queue_get_kernel_seqnum(udev_queue); + + if (start > end) { + log_error("seq-start larger than seq-end, ignoring"); + start = 0; + end = 0; + } + + if (start > kernel_seq || end > kernel_seq) { + log_error("seq-start or seq-end larger than current kernel value, ignoring"); + start = 0; + end = 0; + } + log_debug("start=%llu end=%llu current=%llu", (unsigned long long)start, (unsigned long long)end, kernel_seq); + } else { + if (end > 0) { + log_error("seq-end needs seq-start parameter, ignoring"); + end = 0; + } + } + + /* guarantee that the udev daemon isn't pre-processing */ + if (getuid() == 0) { + struct udev_ctrl *uctrl; + + uctrl = udev_ctrl_new(udev); + if (uctrl != NULL) { + if (udev_ctrl_send_ping(uctrl, timeout) < 0) { + log_debug("no connection to daemon"); + udev_ctrl_unref(uctrl); + rc = EXIT_SUCCESS; + goto out; + } + udev_ctrl_unref(uctrl); + } + } + + pfd[0].events = POLLIN; + pfd[0].fd = inotify_init1(IN_CLOEXEC); + if (pfd[0].fd < 0) { + log_error("inotify_init failed: %m"); + } else { + if (inotify_add_watch(pfd[0].fd, "/run/udev" , IN_MOVED_TO) < 0) { + log_error("watching /run/udev failed"); + close(pfd[0].fd); + pfd[0].fd = -1; + } + } + + for (;;) { + struct stat statbuf; + + if (exists != NULL && stat(exists, &statbuf) == 0) { + rc = EXIT_SUCCESS; + break; + } + + if (start > 0) { + /* if asked for, wait for a specific sequence of events */ + if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) { + rc = EXIT_SUCCESS; + break; + } + } else { + /* exit if queue is empty */ + if (udev_queue_get_queue_is_empty(udev_queue)) { + rc = EXIT_SUCCESS; + break; + } + } + + if (pfd[0].fd >= 0) { + int delay; + + if (exists != NULL || start > 0) + delay = 100; + else + delay = 1000; + /* wake up after delay, or immediately after the queue is rebuilt */ + if (poll(pfd, 1, delay) > 0 && pfd[0].revents & POLLIN) { + char buf[sizeof(struct inotify_event) + PATH_MAX]; + + read(pfd[0].fd, buf, sizeof(buf)); + } + } else { + sleep(1); + } + + if (timeout > 0) { + usec_t age_usec; + + age_usec = now(CLOCK_MONOTONIC) - start_usec; + if (age_usec / (1000 * 1000) >= timeout) { + struct udev_list_entry *list_entry; + + if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) { + log_debug("timeout waiting for udev queue"); + printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout); + udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) + printf(" %s (%s)\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } + + break; + } + } + } +out: + if (pfd[0].fd >= 0) + close(pfd[0].fd); + return rc; +} + +const struct udevadm_cmd udevadm_settle = { + .name = "settle", + .cmd = adm_settle, + .help = "wait for the event queue to finish", +}; diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c new file mode 100644 index 0000000..8041878 --- /dev/null +++ b/src/udev/udevadm-test-builtin.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +static void help(struct udev *udev) +{ + fprintf(stderr, "\n"); + fprintf(stderr, "Usage: udevadm builtin [--help] COMMAND SYSPATH\n"); + udev_builtin_list(udev); + fprintf(stderr, "\n"); +} + +static int adm_builtin(struct udev *udev, int argc, char *argv[]) +{ + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + {} + }; + char *command = NULL; + char *syspath = NULL; + char filename[UTIL_PATH_SIZE]; + struct udev_device *dev = NULL; + enum udev_builtin_cmd cmd; + int rc = EXIT_SUCCESS, c; + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + switch (c) { + case 'h': + help(udev); + goto out; + } + + command = argv[optind++]; + if (command == NULL) { + fprintf(stderr, "command missing\n"); + help(udev); + rc = 2; + goto out; + } + + syspath = argv[optind++]; + if (syspath == NULL) { + fprintf(stderr, "syspath missing\n"); + rc = 3; + goto out; + } + + udev_builtin_init(udev); + + cmd = udev_builtin_lookup(command); + if (cmd >= UDEV_BUILTIN_MAX) { + fprintf(stderr, "unknown command '%s'\n", command); + help(udev); + rc = 5; + goto out; + } + + /* add /sys if needed */ + if (!startswith(syspath, "/sys")) + strscpyl(filename, sizeof(filename), "/sys", syspath, NULL); + else + strscpy(filename, sizeof(filename), syspath); + util_remove_trailing_chars(filename, '/'); + + dev = udev_device_new_from_syspath(udev, filename); + if (dev == NULL) { + fprintf(stderr, "unable to open device '%s'\n\n", filename); + rc = 4; + goto out; + } + + rc = udev_builtin_run(dev, cmd, command, true); + if (rc < 0) { + fprintf(stderr, "error executing '%s', exit code %i\n\n", command, rc); + rc = 6; + } +out: + udev_device_unref(dev); + udev_builtin_exit(udev); + return rc; +} + +const struct udevadm_cmd udevadm_test_builtin = { + .name = "test-builtin", + .cmd = adm_builtin, + .help = "test a built-in command", + .debug = true, +}; diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c new file mode 100644 index 0000000..6cd311b --- /dev/null +++ b/src/udev/udevadm-test.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2003-2004 Greg Kroah-Hartman + * Copyright (C) 2004-2008 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" + +static int adm_test(struct udev *udev, int argc, char *argv[]) +{ + int resolve_names = 1; + char filename[UTIL_PATH_SIZE]; + const char *action = "add"; + const char *syspath = NULL; + struct udev_list_entry *entry; + _cleanup_udev_rules_unref_ struct udev_rules *rules = NULL; + _cleanup_udev_device_unref_ struct udev_device *dev = NULL; + _cleanup_udev_event_unref_ struct udev_event *event = NULL; + sigset_t mask, sigmask_orig; + int err; + int rc = 0, c; + + static const struct option options[] = { + { "action", required_argument, NULL, 'a' }, + { "resolve-names", required_argument, NULL, 'N' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + + log_debug("version %s", VERSION); + + while((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0) + switch (c) { + case 'a': + action = optarg; + break; + case 'N': + if (streq (optarg, "early")) { + resolve_names = 1; + } else if (streq (optarg, "late")) { + resolve_names = 0; + } else if (streq (optarg, "never")) { + resolve_names = -1; + } else { + fprintf(stderr, "resolve-names must be early, late or never\n"); + log_error("resolve-names must be early, late or never"); + exit(EXIT_FAILURE); + } + break; + case 'h': + printf("Usage: udevadm test OPTIONS \n" + " -a,--action=ACTION set action string\n" + " -N,--resolve-names=early|late|never when to resolve names\n" + " -h,--help print this help string\n" + "\n"); + exit(EXIT_SUCCESS); + case '?': + exit(EXIT_FAILURE); + default: + assert_not_reached("Unknown option"); + } + + syspath = argv[optind]; + if (syspath == NULL) { + fprintf(stderr, "syspath parameter missing\n"); + rc = 2; + goto out; + } + + printf("This program is for debugging only, it does not run any program\n" + "specified by a RUN key. It may show incorrect results, because\n" + "some values may be different, or not available at a simulation run.\n" + "\n"); + + sigprocmask(SIG_SETMASK, NULL, &sigmask_orig); + + udev_builtin_init(udev); + + rules = udev_rules_new(udev, resolve_names); + if (rules == NULL) { + fprintf(stderr, "error reading rules\n"); + rc = 3; + goto out; + } + + /* add /sys if needed */ + if (!startswith(syspath, "/sys")) + strscpyl(filename, sizeof(filename), "/sys", syspath, NULL); + else + strscpy(filename, sizeof(filename), syspath); + util_remove_trailing_chars(filename, '/'); + + dev = udev_device_new_from_syspath(udev, filename); + if (dev == NULL) { + fprintf(stderr, "unable to open device '%s'\n", filename); + rc = 4; + goto out; + } + + /* skip reading of db, but read kernel parameters */ + udev_device_set_info_loaded(dev); + udev_device_read_uevent_file(dev); + + udev_device_set_action(dev, action); + event = udev_event_new(dev); + + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); + event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (event->fd_signal < 0) { + fprintf(stderr, "error creating signalfd\n"); + rc = 5; + goto out; + } + + err = udev_event_execute_rules(event, rules, &sigmask_orig); + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) + printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); + + if (err == 0) { + udev_list_entry_foreach(entry, udev_list_get_entry(&event->run_list)) { + char program[UTIL_PATH_SIZE]; + + udev_event_apply_format(event, udev_list_entry_get_name(entry), program, sizeof(program)); + printf("run: '%s'\n", program); + } + } +out: + if (event != NULL && event->fd_signal >= 0) + close(event->fd_signal); + udev_builtin_exit(udev); + return rc; +} + +const struct udevadm_cmd udevadm_test = { + .name = "test", + .cmd = adm_test, + .help = "test an event run", + .debug = true, +}; diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c new file mode 100644 index 0000000..0ee27bb --- /dev/null +++ b/src/udev/udevadm-trigger.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2008-2009 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev-util.h" +#include "util.h" + +static int verbose; +static int dry_run; + +static void exec_list(struct udev_enumerate *udev_enumerate, const char *action) +{ + struct udev_list_entry *entry; + + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) { + char filename[UTIL_PATH_SIZE]; + int fd; + + if (verbose) + printf("%s\n", udev_list_entry_get_name(entry)); + if (dry_run) + continue; + strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL); + fd = open(filename, O_WRONLY|O_CLOEXEC); + if (fd < 0) + continue; + if (write(fd, action, strlen(action)) < 0) + log_debug("error writing '%s' to '%s': %m", action, filename); + close(fd); + } +} + +static const char *keyval(const char *str, const char **val, char *buf, size_t size) +{ + char *pos; + + strscpy(buf, size,str); + pos = strchr(buf, '='); + if (pos != NULL) { + pos[0] = 0; + pos++; + } + *val = pos; + return buf; +} + +static void help(void) { + printf("Usage: udevadm trigger OPTIONS\n" + " -v,--verbose print the list of devices while running\n" + " -n,--dry-run do not actually trigger the events\n" + " -t,--type= type of events to trigger\n" + " devices sys devices (default)\n" + " subsystems sys subsystems and drivers\n" + " -c,--action= event action value, default is \"change\"\n" + " -s,--subsystem-match= trigger devices from a matching subsystem\n" + " -S,--subsystem-nomatch= exclude devices from a matching subsystem\n" + " -a,--attr-match=]> trigger devices with a matching attribute\n" + " -A,--attr-nomatch=]> exclude devices with a matching attribute\n" + " -p,--property-match== trigger devices with a matching property\n" + " -g,--tag-match== trigger devices with a matching property\n" + " -y,--sysname-match= trigger devices with a matching name\n" + " -b,--parent-match= trigger devices with that parent device\n" + " -h,--help\n\n"); +} + +static int adm_trigger(struct udev *udev, int argc, char *argv[]) +{ + static const struct option options[] = { + { "verbose", no_argument, NULL, 'v' }, + { "dry-run", no_argument, NULL, 'n' }, + { "type", required_argument, NULL, 't' }, + { "action", required_argument, NULL, 'c' }, + { "subsystem-match", required_argument, NULL, 's' }, + { "subsystem-nomatch", required_argument, NULL, 'S' }, + { "attr-match", required_argument, NULL, 'a' }, + { "attr-nomatch", required_argument, NULL, 'A' }, + { "property-match", required_argument, NULL, 'p' }, + { "tag-match", required_argument, NULL, 'g' }, + { "sysname-match", required_argument, NULL, 'y' }, + { "parent-match", required_argument, NULL, 'b' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + enum { + TYPE_DEVICES, + TYPE_SUBSYSTEMS, + } device_type = TYPE_DEVICES; + const char *action = "change"; + _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate = NULL; + int c; + + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) + return 1; + + while ((c = getopt_long(argc, argv, "vno:t:c:s:S:a:A:p:g:y:b:h", options, NULL)) >= 0) { + const char *key; + const char *val; + char buf[UTIL_PATH_SIZE]; + + switch (c) { + case 'v': + verbose = 1; + break; + case 'n': + dry_run = 1; + break; + case 't': + if (streq(optarg, "devices")) + device_type = TYPE_DEVICES; + else if (streq(optarg, "subsystems")) + device_type = TYPE_SUBSYSTEMS; + else { + log_error("unknown type --type=%s", optarg); + return 2; + } + break; + case 'c': + if (!nulstr_contains("add\0" "remove\0" "change\0", optarg)) { + log_error("unknown action '%s'", optarg); + return 2; + } else + action = optarg; + + break; + case 's': + udev_enumerate_add_match_subsystem(udev_enumerate, optarg); + break; + case 'S': + udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg); + break; + case 'a': + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_match_sysattr(udev_enumerate, key, val); + break; + case 'A': + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val); + break; + case 'p': + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_match_property(udev_enumerate, key, val); + break; + case 'g': + udev_enumerate_add_match_tag(udev_enumerate, optarg); + break; + case 'y': + udev_enumerate_add_match_sysname(udev_enumerate, optarg); + break; + case 'b': { + char path[UTIL_PATH_SIZE]; + struct udev_device *dev; + + /* add sys dir if needed */ + if (!startswith(optarg, "/sys")) + strscpyl(path, sizeof(path), "/sys", optarg, NULL); + else + strscpy(path, sizeof(path), optarg); + util_remove_trailing_chars(path, '/'); + dev = udev_device_new_from_syspath(udev, path); + if (dev == NULL) { + log_error("unable to open the device '%s'", optarg); + return 2; + } + udev_enumerate_add_match_parent(udev_enumerate, dev); + /* drop reference immediately, enumerate pins the device as long as needed */ + udev_device_unref(dev); + break; + } + case 'h': + help(); + return 0; + case '?': + return 1; + default: + assert_not_reached("Unknown option"); + } + } + + if (optind < argc) { + fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]); + return 1; + } + + switch (device_type) { + case TYPE_SUBSYSTEMS: + udev_enumerate_scan_subsystems(udev_enumerate); + exec_list(udev_enumerate, action); + return 0; + case TYPE_DEVICES: + udev_enumerate_scan_devices(udev_enumerate); + exec_list(udev_enumerate, action); + return 0; + default: + assert_not_reached("device_type"); + } +} + +const struct udevadm_cmd udevadm_trigger = { + .name = "trigger", + .cmd = adm_trigger, + .help = "request events from the kernel", +}; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c new file mode 100644 index 0000000..dbca369 --- /dev/null +++ b/src/udev/udevadm.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2007-2012 Kay Sievers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" + +void udev_main_log(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + log_metav(priority, file, line, fn, format, args); +} + +static int adm_version(struct udev *udev, int argc, char *argv[]) +{ + printf("%s\n", VERSION); + return 0; +} + +static const struct udevadm_cmd udevadm_version = { + .name = "version", + .cmd = adm_version, +}; + +static int adm_help(struct udev *udev, int argc, char *argv[]); + +static const struct udevadm_cmd udevadm_help = { + .name = "help", + .cmd = adm_help, +}; + +static const struct udevadm_cmd *udevadm_cmds[] = { + &udevadm_info, + &udevadm_trigger, + &udevadm_settle, + &udevadm_control, + &udevadm_monitor, + &udevadm_hwdb, + &udevadm_test, + &udevadm_test_builtin, + &udevadm_version, + &udevadm_help, +}; + +static int adm_help(struct udev *udev, int argc, char *argv[]) +{ + unsigned int i; + + fprintf(stderr, "Usage: udevadm [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n"); + for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++) + if (udevadm_cmds[i]->help != NULL) + printf(" %-12s %s\n", udevadm_cmds[i]->name, udevadm_cmds[i]->help); + fprintf(stderr, "\n"); + return 0; +} + +static int run_command(struct udev *udev, const struct udevadm_cmd *cmd, int argc, char *argv[]) +{ + if (cmd->debug) + log_set_max_level(LOG_DEBUG); + log_debug("calling: %s", cmd->name); + return cmd->cmd(udev, argc, argv); +} + +int main(int argc, char *argv[]) +{ + struct udev *udev; + static const struct option options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + const char *command; + unsigned int i; + int rc = 1; + + udev = udev_new(); + if (udev == NULL) + goto out; + + log_parse_environment(); + log_open(); + udev_set_log_fn(udev, udev_main_log); + label_init("/dev"); + + for (;;) { + int option; + + option = getopt_long(argc, argv, "+dhV", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'd': + log_set_max_level(LOG_DEBUG); + udev_set_log_priority(udev, LOG_DEBUG); + break; + case 'h': + rc = adm_help(udev, argc, argv); + goto out; + case 'V': + rc = adm_version(udev, argc, argv); + goto out; + default: + goto out; + } + } + command = argv[optind]; + + if (command != NULL) + for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++) { + if (streq(udevadm_cmds[i]->name, command)) { + argc -= optind; + argv += optind; + /* we need '0' here to reset the internal state */ + optind = 0; + rc = run_command(udev, udevadm_cmds[i], argc, argv); + goto out; + } + } + + fprintf(stderr, "missing or unknown command\n\n"); + adm_help(udev, argc, argv); + rc = 2; +out: + label_finish(); + udev_unref(udev); + log_close(); + return rc; +} diff --git a/src/udev/udevd.c b/src/udev/udevd.c new file mode 100644 index 0000000..f21c227 --- /dev/null +++ b/src/udev/udevd.c @@ -0,0 +1,1416 @@ +/* + * Copyright (C) 2004-2012 Kay Sievers + * Copyright (C) 2004 Chris Friesen + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "sd-daemon.h" +#include "cgroup-util.h" +#include "dev-setup.h" +#include "fileio.h" + +static bool debug; + +void udev_main_log(struct udev *udev, int priority, + const char *file, int line, const char *fn, + const char *format, va_list args) +{ + log_metav(priority, file, line, fn, format, args); +} + +static struct udev_rules *rules; +static struct udev_queue_export *udev_queue_export; +static struct udev_ctrl *udev_ctrl; +static struct udev_monitor *monitor; +static int worker_watch[2] = { -1, -1 }; +static int fd_signal = -1; +static int fd_ep = -1; +static int fd_inotify = -1; +static bool stop_exec_queue; +static bool reload; +static int children; +static int children_max; +static int exec_delay; +static sigset_t sigmask_orig; +static UDEV_LIST(event_list); +static UDEV_LIST(worker_list); +static char *udev_cgroup; +static bool udev_exit; + +enum event_state { + EVENT_UNDEF, + EVENT_QUEUED, + EVENT_RUNNING, +}; + +struct event { + struct udev_list_node node; + struct udev *udev; + struct udev_device *dev; + enum event_state state; + int exitcode; + unsigned long long int delaying_seqnum; + unsigned long long int seqnum; + const char *devpath; + size_t devpath_len; + const char *devpath_old; + dev_t devnum; + int ifindex; + bool is_block; +#ifdef HAVE_FIRMWARE + bool nodelay; +#endif +}; + +static inline struct event *node_to_event(struct udev_list_node *node) +{ + return container_of(node, struct event, node); +} + +static void event_queue_cleanup(struct udev *udev, enum event_state type); + +enum worker_state { + WORKER_UNDEF, + WORKER_RUNNING, + WORKER_IDLE, + WORKER_KILLED, +}; + +struct worker { + struct udev_list_node node; + struct udev *udev; + int refcount; + pid_t pid; + struct udev_monitor *monitor; + enum worker_state state; + struct event *event; + usec_t event_start_usec; +}; + +/* passed from worker to main process */ +struct worker_message { + pid_t pid; + int exitcode; +}; + +static inline struct worker *node_to_worker(struct udev_list_node *node) +{ + return container_of(node, struct worker, node); +} + +static void event_queue_delete(struct event *event, bool export) +{ + udev_list_node_remove(&event->node); + + if (export) { + udev_queue_export_device_finished(udev_queue_export, event->dev); + log_debug("seq %llu done with %i", udev_device_get_seqnum(event->dev), event->exitcode); + } + udev_device_unref(event->dev); + free(event); +} + +static struct worker *worker_ref(struct worker *worker) +{ + worker->refcount++; + return worker; +} + +static void worker_cleanup(struct worker *worker) +{ + udev_list_node_remove(&worker->node); + udev_monitor_unref(worker->monitor); + children--; + free(worker); +} + +static void worker_unref(struct worker *worker) +{ + worker->refcount--; + if (worker->refcount > 0) + return; + log_debug("worker [%u] cleaned up", worker->pid); + worker_cleanup(worker); +} + +static void worker_list_cleanup(struct udev *udev) +{ + struct udev_list_node *loop, *tmp; + + udev_list_node_foreach_safe(loop, tmp, &worker_list) { + struct worker *worker = node_to_worker(loop); + + worker_cleanup(worker); + } +} + +static void worker_new(struct event *event) +{ + struct udev *udev = event->udev; + struct worker *worker; + struct udev_monitor *worker_monitor; + pid_t pid; + + /* listen for new events */ + worker_monitor = udev_monitor_new_from_netlink(udev, NULL); + if (worker_monitor == NULL) + return; + /* allow the main daemon netlink address to send devices to the worker */ + udev_monitor_allow_unicast_sender(worker_monitor, monitor); + udev_monitor_enable_receiving(worker_monitor); + + worker = new0(struct worker, 1); + if (worker == NULL) { + udev_monitor_unref(worker_monitor); + return; + } + /* worker + event reference */ + worker->refcount = 2; + worker->udev = udev; + + pid = fork(); + switch (pid) { + case 0: { + struct udev_device *dev = NULL; + int fd_monitor; + struct epoll_event ep_signal, ep_monitor; + sigset_t mask; + int rc = EXIT_SUCCESS; + + /* take initial device from queue */ + dev = event->dev; + event->dev = NULL; + + free(worker); + worker_list_cleanup(udev); + event_queue_cleanup(udev, EVENT_UNDEF); + udev_queue_export_unref(udev_queue_export); + udev_monitor_unref(monitor); + udev_ctrl_unref(udev_ctrl); + close(fd_signal); + close(fd_ep); + close(worker_watch[READ_END]); + + sigfillset(&mask); + fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (fd_signal < 0) { + log_error("error creating signalfd %m"); + rc = 2; + goto out; + } + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error("error creating epoll fd: %m"); + rc = 3; + goto out; + } + + memzero(&ep_signal, sizeof(struct epoll_event)); + ep_signal.events = EPOLLIN; + ep_signal.data.fd = fd_signal; + + fd_monitor = udev_monitor_get_fd(worker_monitor); + memzero(&ep_monitor, sizeof(struct epoll_event)); + ep_monitor.events = EPOLLIN; + ep_monitor.data.fd = fd_monitor; + + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) { + log_error("fail to add fds to epoll: %m"); + rc = 4; + goto out; + } + + /* request TERM signal if parent exits */ + prctl(PR_SET_PDEATHSIG, SIGTERM); + + /* reset OOM score, we only protect the main daemon */ + write_string_file("/proc/self/oom_score_adj", "0"); + + for (;;) { + struct udev_event *udev_event; + struct worker_message msg; + int err; + + log_debug("seq %llu running", udev_device_get_seqnum(dev)); + udev_event = udev_event_new(dev); + if (udev_event == NULL) { + rc = 5; + goto out; + } + + /* needed for SIGCHLD/SIGTERM in spawn() */ + udev_event->fd_signal = fd_signal; + + if (exec_delay > 0) + udev_event->exec_delay = exec_delay; + + /* apply rules, create node, symlinks */ + err = udev_event_execute_rules(udev_event, rules, &sigmask_orig); + + if (err == 0) + udev_event_execute_run(udev_event, &sigmask_orig); + + /* apply/restore inotify watch */ + if (err == 0 && udev_event->inotify_watch) { + udev_watch_begin(udev, dev); + udev_device_update_db(dev); + } + + /* send processed event back to libudev listeners */ + udev_monitor_send_device(worker_monitor, NULL, dev); + + /* send udevd the result of the event execution */ + memzero(&msg, sizeof(struct worker_message)); + if (err != 0) + msg.exitcode = err; + msg.pid = getpid(); + send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0); + + log_debug("seq %llu processed with %i", udev_device_get_seqnum(dev), err); + + udev_device_unref(dev); + dev = NULL; + + if (udev_event->sigterm) { + udev_event_unref(udev_event); + goto out; + } + + udev_event_unref(udev_event); + + /* wait for more device messages from main udevd, or term signal */ + while (dev == NULL) { + struct epoll_event ev[4]; + int fdcount; + int i; + + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); + if (fdcount < 0) { + if (errno == EINTR) + continue; + log_error("failed to poll: %m"); + goto out; + } + + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) { + dev = udev_monitor_receive_device(worker_monitor); + break; + } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) { + struct signalfd_siginfo fdsi; + ssize_t size; + + size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); + if (size != sizeof(struct signalfd_siginfo)) + continue; + switch (fdsi.ssi_signo) { + case SIGTERM: + goto out; + } + } + } + } + } +out: + udev_device_unref(dev); + if (fd_signal >= 0) + close(fd_signal); + if (fd_ep >= 0) + close(fd_ep); + close(fd_inotify); + close(worker_watch[WRITE_END]); + udev_rules_unref(rules); + udev_builtin_exit(udev); + udev_monitor_unref(worker_monitor); + udev_unref(udev); + log_close(); + exit(rc); + } + case -1: + udev_monitor_unref(worker_monitor); + event->state = EVENT_QUEUED; + free(worker); + log_error("fork of child failed: %m"); + break; + default: + /* close monitor, but keep address around */ + udev_monitor_disconnect(worker_monitor); + worker->monitor = worker_monitor; + worker->pid = pid; + worker->state = WORKER_RUNNING; + worker->event_start_usec = now(CLOCK_MONOTONIC); + worker->event = event; + event->state = EVENT_RUNNING; + udev_list_node_append(&worker->node, &worker_list); + children++; + log_debug("seq %llu forked new worker [%u]", udev_device_get_seqnum(event->dev), pid); + break; + } +} + +static void event_run(struct event *event) +{ + struct udev_list_node *loop; + + udev_list_node_foreach(loop, &worker_list) { + struct worker *worker = node_to_worker(loop); + ssize_t count; + + if (worker->state != WORKER_IDLE) + continue; + + count = udev_monitor_send_device(monitor, worker->monitor, event->dev); + if (count < 0) { + log_error("worker [%u] did not accept message %zi (%m), kill it", worker->pid, count); + kill(worker->pid, SIGKILL); + worker->state = WORKER_KILLED; + continue; + } + worker_ref(worker); + worker->event = event; + worker->state = WORKER_RUNNING; + worker->event_start_usec = now(CLOCK_MONOTONIC); + event->state = EVENT_RUNNING; + return; + } + + if (children >= children_max) { + if (children_max > 1) + log_debug("maximum number (%i) of children reached", children); + return; + } + + /* start new worker and pass initial device */ + worker_new(event); +} + +static int event_queue_insert(struct udev_device *dev) +{ + struct event *event; + + event = new0(struct event, 1); + if (event == NULL) + return -1; + + event->udev = udev_device_get_udev(dev); + event->dev = dev; + event->seqnum = udev_device_get_seqnum(dev); + event->devpath = udev_device_get_devpath(dev); + event->devpath_len = strlen(event->devpath); + event->devpath_old = udev_device_get_devpath_old(dev); + event->devnum = udev_device_get_devnum(dev); + event->is_block = streq("block", udev_device_get_subsystem(dev)); + event->ifindex = udev_device_get_ifindex(dev); +#ifdef HAVE_FIRMWARE + if (streq(udev_device_get_subsystem(dev), "firmware")) + event->nodelay = true; +#endif + + udev_queue_export_device_queued(udev_queue_export, dev); + log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev), + udev_device_get_action(dev), udev_device_get_subsystem(dev)); + + event->state = EVENT_QUEUED; + udev_list_node_append(&event->node, &event_list); + return 0; +} + +static void worker_kill(struct udev *udev) +{ + struct udev_list_node *loop; + + udev_list_node_foreach(loop, &worker_list) { + struct worker *worker = node_to_worker(loop); + + if (worker->state == WORKER_KILLED) + continue; + + worker->state = WORKER_KILLED; + kill(worker->pid, SIGTERM); + } +} + +/* lookup event for identical, parent, child device */ +static bool is_devpath_busy(struct event *event) +{ + struct udev_list_node *loop; + size_t common; + + /* check if queue contains events we depend on */ + udev_list_node_foreach(loop, &event_list) { + struct event *loop_event = node_to_event(loop); + + /* we already found a later event, earlier can not block us, no need to check again */ + if (loop_event->seqnum < event->delaying_seqnum) + continue; + + /* event we checked earlier still exists, no need to check again */ + if (loop_event->seqnum == event->delaying_seqnum) + return true; + + /* found ourself, no later event can block us */ + if (loop_event->seqnum >= event->seqnum) + break; + + /* check major/minor */ + if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block) + return true; + + /* check network device ifindex */ + if (event->ifindex != 0 && event->ifindex == loop_event->ifindex) + return true; + + /* check our old name */ + if (event->devpath_old != NULL && streq(loop_event->devpath, event->devpath_old)) { + event->delaying_seqnum = loop_event->seqnum; + return true; + } + + /* compare devpath */ + common = MIN(loop_event->devpath_len, event->devpath_len); + + /* one devpath is contained in the other? */ + if (memcmp(loop_event->devpath, event->devpath, common) != 0) + continue; + + /* identical device event found */ + if (loop_event->devpath_len == event->devpath_len) { + /* devices names might have changed/swapped in the meantime */ + if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block)) + continue; + if (event->ifindex != 0 && event->ifindex != loop_event->ifindex) + continue; + event->delaying_seqnum = loop_event->seqnum; + return true; + } + +#ifdef HAVE_FIRMWARE + /* allow to bypass the dependency tracking */ + if (event->nodelay) + continue; +#endif + + /* parent device event found */ + if (event->devpath[common] == '/') { + event->delaying_seqnum = loop_event->seqnum; + return true; + } + + /* child device event found */ + if (loop_event->devpath[common] == '/') { + event->delaying_seqnum = loop_event->seqnum; + return true; + } + + /* no matching device */ + continue; + } + + return false; +} + +static void event_queue_start(struct udev *udev) +{ + struct udev_list_node *loop; + + udev_list_node_foreach(loop, &event_list) { + struct event *event = node_to_event(loop); + + if (event->state != EVENT_QUEUED) + continue; + + /* do not start event if parent or child event is still running */ + if (is_devpath_busy(event)) + continue; + + event_run(event); + } +} + +static void event_queue_cleanup(struct udev *udev, enum event_state match_type) +{ + struct udev_list_node *loop, *tmp; + + udev_list_node_foreach_safe(loop, tmp, &event_list) { + struct event *event = node_to_event(loop); + + if (match_type != EVENT_UNDEF && match_type != event->state) + continue; + + event_queue_delete(event, false); + } +} + +static void worker_returned(int fd_worker) +{ + for (;;) { + struct worker_message msg; + ssize_t size; + struct udev_list_node *loop; + + size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT); + if (size != sizeof(struct worker_message)) + break; + + /* lookup worker who sent the signal */ + udev_list_node_foreach(loop, &worker_list) { + struct worker *worker = node_to_worker(loop); + + if (worker->pid != msg.pid) + continue; + + /* worker returned */ + if (worker->event) { + worker->event->exitcode = msg.exitcode; + event_queue_delete(worker->event, true); + worker->event = NULL; + } + if (worker->state != WORKER_KILLED) + worker->state = WORKER_IDLE; + worker_unref(worker); + break; + } + } +} + +/* receive the udevd message from userspace */ +static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) +{ + struct udev *udev = udev_ctrl_get_udev(uctrl); + struct udev_ctrl_connection *ctrl_conn; + struct udev_ctrl_msg *ctrl_msg = NULL; + const char *str; + int i; + + ctrl_conn = udev_ctrl_get_connection(uctrl); + if (ctrl_conn == NULL) + goto out; + + ctrl_msg = udev_ctrl_receive_msg(ctrl_conn); + if (ctrl_msg == NULL) + goto out; + + i = udev_ctrl_get_set_log_level(ctrl_msg); + if (i >= 0) { + log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i); + log_set_max_level(i); + udev_set_log_priority(udev, i); + worker_kill(udev); + } + + if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) { + log_debug("udevd message (STOP_EXEC_QUEUE) received"); + stop_exec_queue = true; + } + + if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) { + log_debug("udevd message (START_EXEC_QUEUE) received"); + stop_exec_queue = false; + } + + if (udev_ctrl_get_reload(ctrl_msg) > 0) { + log_debug("udevd message (RELOAD) received"); + reload = true; + } + + str = udev_ctrl_get_set_env(ctrl_msg); + if (str != NULL) { + char *key; + + key = strdup(str); + if (key != NULL) { + char *val; + + val = strchr(key, '='); + if (val != NULL) { + val[0] = '\0'; + val = &val[1]; + if (val[0] == '\0') { + log_debug("udevd message (ENV) received, unset '%s'", key); + udev_add_property(udev, key, NULL); + } else { + log_debug("udevd message (ENV) received, set '%s=%s'", key, val); + udev_add_property(udev, key, val); + } + } else { + log_error("wrong key format '%s'", key); + } + free(key); + } + worker_kill(udev); + } + + i = udev_ctrl_get_set_children_max(ctrl_msg); + if (i >= 0) { + log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i); + children_max = i; + } + + if (udev_ctrl_get_ping(ctrl_msg) > 0) + log_debug("udevd message (SYNC) received"); + + if (udev_ctrl_get_exit(ctrl_msg) > 0) { + log_debug("udevd message (EXIT) received"); + udev_exit = true; + /* keep reference to block the client until we exit */ + udev_ctrl_connection_ref(ctrl_conn); + } +out: + udev_ctrl_msg_unref(ctrl_msg); + return udev_ctrl_connection_unref(ctrl_conn); +} + +/* read inotify messages */ +static int handle_inotify(struct udev *udev) +{ + int nbytes, pos; + char *buf; + struct inotify_event *ev; + + if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0)) + return 0; + + buf = malloc(nbytes); + if (buf == NULL) { + log_error("error getting buffer for inotify"); + return -1; + } + + nbytes = read(fd_inotify, buf, nbytes); + + for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) { + struct udev_device *dev; + + ev = (struct inotify_event *)(buf + pos); + dev = udev_watch_lookup(udev, ev->wd); + if (dev != NULL) { + log_debug("inotify event: %x for %s", ev->mask, udev_device_get_devnode(dev)); + if (ev->mask & IN_CLOSE_WRITE) { + char filename[UTIL_PATH_SIZE]; + int fd; + + log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev)); + strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); + fd = open(filename, O_WRONLY|O_CLOEXEC); + if (fd >= 0) { + if (write(fd, "change", 6) < 0) + log_debug("error writing uevent: %m"); + close(fd); + } + } + if (ev->mask & IN_IGNORED) + udev_watch_end(udev, dev); + + udev_device_unref(dev); + } + + } + + free(buf); + return 0; +} + +static void handle_signal(struct udev *udev, int signo) +{ + switch (signo) { + case SIGINT: + case SIGTERM: + udev_exit = true; + break; + case SIGCHLD: + for (;;) { + pid_t pid; + int status; + struct udev_list_node *loop, *tmp; + + pid = waitpid(-1, &status, WNOHANG); + if (pid <= 0) + break; + + udev_list_node_foreach_safe(loop, tmp, &worker_list) { + struct worker *worker = node_to_worker(loop); + + if (worker->pid != pid) + continue; + log_debug("worker [%u] exit", pid); + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + log_error("worker [%u] exit with return code %i", + pid, WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + log_error("worker [%u] terminated by signal %i (%s)", + pid, WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (WIFSTOPPED(status)) { + log_error("worker [%u] stopped", pid); + } else if (WIFCONTINUED(status)) { + log_error("worker [%u] continued", pid); + } else { + log_error("worker [%u] exit with status 0x%04x", pid, status); + } + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + if (worker->event) { + log_error("worker [%u] failed while handling '%s'", + pid, worker->event->devpath); + worker->event->exitcode = -32; + event_queue_delete(worker->event, true); + /* drop reference taken for state 'running' */ + worker_unref(worker); + } + } + worker_unref(worker); + break; + } + } + break; + case SIGHUP: + reload = true; + break; + } +} + +static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) +{ + int ctrl = -1, netlink = -1; + int fd, n; + + n = sd_listen_fds(true); + if (n <= 0) + return -1; + + for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { + if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) { + if (ctrl >= 0) + return -1; + ctrl = fd; + continue; + } + + if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) { + if (netlink >= 0) + return -1; + netlink = fd; + continue; + } + + return -1; + } + + if (ctrl < 0 || netlink < 0) + return -1; + + log_debug("ctrl=%i netlink=%i", ctrl, netlink); + *rctrl = ctrl; + *rnetlink = netlink; + return 0; +} + +/* + * read the kernel commandline, in case we need to get into debug mode + * udev.log-priority= syslog priority + * udev.children-max= events are fully serialized if set to 1 + * udev.exec-delay= delay execution of every executed program + */ +static void kernel_cmdline_options(struct udev *udev) +{ + _cleanup_free_ char *line = NULL; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return; + + FOREACH_WORD_QUOTED(w, l, line, state) { + char *s, *opt; + + s = strndup(w, l); + if (!s) + break; + + /* accept the same options for the initrd, prefixed with "rd." */ + if (in_initrd() && startswith(s, "rd.")) + opt = s + 3; + else + opt = s; + + if (startswith(opt, "udev.log-priority=")) { + int prio; + + prio = util_log_priority(opt + 18); + log_set_max_level(prio); + udev_set_log_priority(udev, prio); + } else if (startswith(opt, "udev.children-max=")) { + children_max = strtoul(opt + 18, NULL, 0); + } else if (startswith(opt, "udev.exec-delay=")) { + exec_delay = strtoul(opt + 16, NULL, 0); + } + + free(s); + } +} + +int main(int argc, char *argv[]) +{ + struct udev *udev; + sigset_t mask; + int daemonize = false; + int resolve_names = 1; + static const struct option options[] = { + { "daemon", no_argument, NULL, 'd' }, + { "debug", no_argument, NULL, 'D' }, + { "children-max", required_argument, NULL, 'c' }, + { "exec-delay", required_argument, NULL, 'e' }, + { "resolve-names", required_argument, NULL, 'N' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + int fd_ctrl = -1; + int fd_netlink = -1; + int fd_worker = -1; + struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; + struct udev_ctrl_connection *ctrl_conn = NULL; + int rc = 1; + + udev = udev_new(); + if (udev == NULL) + goto exit; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + udev_set_log_fn(udev, udev_main_log); + log_set_max_level(udev_get_log_priority(udev)); + + log_debug("version %s", VERSION); + label_init("/dev"); + + for (;;) { + int option; + + option = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'd': + daemonize = true; + break; + case 'c': + children_max = strtoul(optarg, NULL, 0); + break; + case 'e': + exec_delay = strtoul(optarg, NULL, 0); + break; + case 'D': + debug = true; + log_set_max_level(LOG_DEBUG); + udev_set_log_priority(udev, LOG_DEBUG); + break; + case 'N': + if (streq(optarg, "early")) { + resolve_names = 1; + } else if (streq(optarg, "late")) { + resolve_names = 0; + } else if (streq(optarg, "never")) { + resolve_names = -1; + } else { + fprintf(stderr, "resolve-names must be early, late or never\n"); + log_error("resolve-names must be early, late or never"); + goto exit; + } + break; + case 'h': + printf("Usage: udevd OPTIONS\n" + " --daemon\n" + " --debug\n" + " --children-max=\n" + " --exec-delay=\n" + " --resolve-names=early|late|never\n" + " --version\n" + " --help\n" + "\n"); + goto exit; + case 'V': + printf("%s\n", VERSION); + goto exit; + default: + goto exit; + } + } + + kernel_cmdline_options(udev); + + if (getuid() != 0) { + fprintf(stderr, "root privileges required\n"); + log_error("root privileges required"); + goto exit; + } + + /* set umask before creating any file/directory */ + chdir("/"); + umask(022); + + mkdir("/run/udev", 0755); + + dev_setup(NULL); + + /* before opening new files, make sure std{in,out,err} fds are in a sane state */ + if (daemonize) { + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + if (write(STDOUT_FILENO, 0, 0) < 0) + dup2(fd, STDOUT_FILENO); + if (write(STDERR_FILENO, 0, 0) < 0) + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } else { + fprintf(stderr, "cannot open /dev/null\n"); + log_error("cannot open /dev/null"); + } + } + + if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) { + /* get control and netlink socket from systemd */ + udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl); + if (udev_ctrl == NULL) { + log_error("error taking over udev control socket"); + rc = 1; + goto exit; + } + + monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink); + if (monitor == NULL) { + log_error("error taking over netlink socket"); + rc = 3; + goto exit; + } + + /* get our own cgroup, we regularly kill everything udev has left behind */ + if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &udev_cgroup) < 0) + udev_cgroup = NULL; + } else { + /* open control and netlink socket */ + udev_ctrl = udev_ctrl_new(udev); + if (udev_ctrl == NULL) { + fprintf(stderr, "error initializing udev control socket"); + log_error("error initializing udev control socket"); + rc = 1; + goto exit; + } + fd_ctrl = udev_ctrl_get_fd(udev_ctrl); + + monitor = udev_monitor_new_from_netlink(udev, "kernel"); + if (monitor == NULL) { + fprintf(stderr, "error initializing netlink socket\n"); + log_error("error initializing netlink socket"); + rc = 3; + goto exit; + } + fd_netlink = udev_monitor_get_fd(monitor); + } + + if (udev_monitor_enable_receiving(monitor) < 0) { + fprintf(stderr, "error binding netlink socket\n"); + log_error("error binding netlink socket"); + rc = 3; + goto exit; + } + + if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { + fprintf(stderr, "error binding udev control socket\n"); + log_error("error binding udev control socket"); + rc = 1; + goto exit; + } + + udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024); + + /* create queue file before signalling 'ready', to make sure we block 'settle' */ + udev_queue_export = udev_queue_export_new(udev); + if (udev_queue_export == NULL) { + log_error("error creating queue file"); + goto exit; + } + + if (daemonize) { + pid_t pid; + + pid = fork(); + switch (pid) { + case 0: + break; + case -1: + log_error("fork of daemon failed: %m"); + rc = 4; + goto exit; + default: + rc = EXIT_SUCCESS; + goto exit_daemonize; + } + + setsid(); + + write_string_file("/proc/self/oom_score_adj", "-1000"); + } else { + sd_notify(1, "READY=1"); + } + + print_kmsg("starting version " VERSION "\n"); + + if (!debug) { + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + } + + fd_inotify = udev_watch_init(udev); + if (fd_inotify < 0) { + fprintf(stderr, "error initializing inotify\n"); + log_error("error initializing inotify"); + rc = 4; + goto exit; + } + udev_watch_restore(udev); + + /* block and listen to all signals on signalfd */ + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); + fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (fd_signal < 0) { + fprintf(stderr, "error creating signalfd\n"); + log_error("error creating signalfd"); + rc = 5; + goto exit; + } + + /* unnamed socket from workers to the main daemon */ + if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) { + fprintf(stderr, "error creating socketpair\n"); + log_error("error creating socketpair"); + rc = 6; + goto exit; + } + fd_worker = worker_watch[READ_END]; + + udev_builtin_init(udev); + + rules = udev_rules_new(udev, resolve_names); + if (rules == NULL) { + log_error("error reading rules"); + goto exit; + } + + memzero(&ep_ctrl, sizeof(struct epoll_event)); + ep_ctrl.events = EPOLLIN; + ep_ctrl.data.fd = fd_ctrl; + + memzero(&ep_inotify, sizeof(struct epoll_event)); + ep_inotify.events = EPOLLIN; + ep_inotify.data.fd = fd_inotify; + + memzero(&ep_signal, sizeof(struct epoll_event)); + ep_signal.events = EPOLLIN; + ep_signal.data.fd = fd_signal; + + memzero(&ep_netlink, sizeof(struct epoll_event)); + ep_netlink.events = EPOLLIN; + ep_netlink.data.fd = fd_netlink; + + memzero(&ep_worker, sizeof(struct epoll_event)); + ep_worker.events = EPOLLIN; + ep_worker.data.fd = fd_worker; + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + log_error("error creating epoll fd: %m"); + goto exit; + } + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) { + log_error("fail to add fds to epoll: %m"); + goto exit; + } + + if (children_max <= 0) { + cpu_set_t cpu_set; + + children_max = 8; + + if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) { + children_max += CPU_COUNT(&cpu_set) * 2; + } + } + log_debug("set children_max to %u", children_max); + + rc = udev_rules_apply_static_dev_perms(rules); + if (rc < 0) + log_error("failed to apply permissions on static device nodes - %s", strerror(-rc)); + + udev_list_node_init(&event_list); + udev_list_node_init(&worker_list); + + for (;;) { + static usec_t last_usec; + struct epoll_event ev[8]; + int fdcount; + int timeout; + bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl; + int i; + + if (udev_exit) { + /* close sources of new events and discard buffered events */ + if (fd_ctrl >= 0) { + epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL); + fd_ctrl = -1; + } + if (monitor != NULL) { + epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL); + udev_monitor_unref(monitor); + monitor = NULL; + } + if (fd_inotify >= 0) { + epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL); + close(fd_inotify); + fd_inotify = -1; + } + + /* discard queued events and kill workers */ + event_queue_cleanup(udev, EVENT_QUEUED); + worker_kill(udev); + + /* exit after all has cleaned up */ + if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list)) + break; + + /* timeout at exit for workers to finish */ + timeout = 30 * 1000; + } else if (udev_list_node_is_empty(&event_list) && !children) { + /* we are idle */ + timeout = -1; + + /* cleanup possible left-over processes in our cgroup */ + if (udev_cgroup) + cg_kill(SYSTEMD_CGROUP_CONTROLLER, udev_cgroup, SIGKILL, false, true, NULL); + } else { + /* kill idle or hanging workers */ + timeout = 3 * 1000; + } + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout); + if (fdcount < 0) + continue; + + if (fdcount == 0) { + struct udev_list_node *loop; + + /* timeout */ + if (udev_exit) { + log_error("timeout, giving up waiting for workers to finish"); + break; + } + + /* kill idle workers */ + if (udev_list_node_is_empty(&event_list)) { + log_debug("cleanup idle workers"); + worker_kill(udev); + } + + /* check for hanging events */ + udev_list_node_foreach(loop, &worker_list) { + struct worker *worker = node_to_worker(loop); + + if (worker->state != WORKER_RUNNING) + continue; + + if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * 1000 * 1000) { + log_error("worker [%u] %s timeout; kill it", worker->pid, + worker->event ? worker->event->devpath : ""); + kill(worker->pid, SIGKILL); + worker->state = WORKER_KILLED; + /* drop reference taken for state 'running' */ + worker_unref(worker); + if (worker->event) { + log_error("seq %llu '%s' killed", + udev_device_get_seqnum(worker->event->dev), worker->event->devpath); + worker->event->exitcode = -64; + event_queue_delete(worker->event, true); + worker->event = NULL; + } + } + } + + } + + is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false; + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN) + is_worker = true; + else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN) + is_netlink = true; + else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) + is_signal = true; + else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN) + is_inotify = true; + else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN) + is_ctrl = true; + } + + /* check for changed config, every 3 seconds at most */ + if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * 1000 * 1000) { + if (udev_rules_check_timestamp(rules)) + reload = true; + if (udev_builtin_validate(udev)) + reload = true; + + last_usec = now(CLOCK_MONOTONIC); + } + + /* reload requested, HUP signal received, rules changed, builtin changed */ + if (reload) { + worker_kill(udev); + rules = udev_rules_unref(rules); + udev_builtin_exit(udev); + reload = false; + } + + /* event has finished */ + if (is_worker) + worker_returned(fd_worker); + + if (is_netlink) { + struct udev_device *dev; + + dev = udev_monitor_receive_device(monitor); + if (dev != NULL) { + udev_device_set_usec_initialized(dev, now(CLOCK_MONOTONIC)); + if (event_queue_insert(dev) < 0) + udev_device_unref(dev); + } + } + + /* start new events */ + if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) { + udev_builtin_init(udev); + if (rules == NULL) + rules = udev_rules_new(udev, resolve_names); + if (rules != NULL) + event_queue_start(udev); + } + + if (is_signal) { + struct signalfd_siginfo fdsi; + ssize_t size; + + size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); + if (size == sizeof(struct signalfd_siginfo)) + handle_signal(udev, fdsi.ssi_signo); + } + + /* we are shutting down, the events below are not handled anymore */ + if (udev_exit) + continue; + + /* device node watch */ + if (is_inotify) + handle_inotify(udev); + + /* + * This needs to be after the inotify handling, to make sure, + * that the ping is send back after the possibly generated + * "change" events by the inotify device node watch. + * + * A single time we may receive a client connection which we need to + * keep open to block the client. It will be closed right before we + * exit. + */ + if (is_ctrl) + ctrl_conn = handle_ctrl_msg(udev_ctrl); + } + + rc = EXIT_SUCCESS; +exit: + udev_queue_export_cleanup(udev_queue_export); + udev_ctrl_cleanup(udev_ctrl); +exit_daemonize: + if (fd_ep >= 0) + close(fd_ep); + worker_list_cleanup(udev); + event_queue_cleanup(udev, EVENT_UNDEF); + udev_rules_unref(rules); + udev_builtin_exit(udev); + if (fd_signal >= 0) + close(fd_signal); + if (worker_watch[READ_END] >= 0) + close(worker_watch[READ_END]); + if (worker_watch[WRITE_END] >= 0) + close(worker_watch[WRITE_END]); + udev_monitor_unref(monitor); + udev_queue_export_unref(udev_queue_export); + udev_ctrl_connection_unref(ctrl_conn); + udev_ctrl_unref(udev_ctrl); + label_finish(); + udev_unref(udev); + log_close(); + return rc; +} diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c new file mode 100644 index 0000000..d5463b2 --- /dev/null +++ b/src/udev/v4l_id/v4l_id.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Kay Sievers + * Copyright (c) 2009 Filippo Argiolas + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + {} + }; + int fd; + char *device; + struct v4l2_capability v2cap; + + while (1) { + int option; + + option = getopt_long(argc, argv, "h", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'h': + printf("Usage: v4l_id [--help] \n\n"); + return 0; + default: + return 1; + } + } + device = argv[optind]; + + if (device == NULL) + return 2; + fd = open (device, O_RDONLY); + if (fd < 0) + return 3; + + if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) { + 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) + printf("capture:"); + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) + printf("video_output:"); + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) + printf("video_overlay:"); + if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) + printf("audio:"); + if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) + printf("tuner:"); + if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) + printf("radio:"); + printf("\n"); + } + + close (fd); + return 0; +} diff --git a/src/umount.c b/src/umount.c deleted file mode 100644 index 4e036d8..0000000 --- a/src/umount.c +++ /dev/null @@ -1,640 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 ProFUSION embedded systems - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "list.h" -#include "mount-setup.h" -#include "umount.h" -#include "util.h" - -typedef struct MountPoint { - char *path; - dev_t devnum; - bool skip_ro; - LIST_FIELDS (struct MountPoint, mount_point); -} MountPoint; - -static void mount_point_free(MountPoint **head, MountPoint *m) { - assert(head); - assert(m); - - LIST_REMOVE(MountPoint, mount_point, *head, m); - - free(m->path); - free(m); -} - -static void mount_points_list_free(MountPoint **head) { - assert(head); - - while (*head) - mount_point_free(head, *head); -} - -static int mount_points_list_get(MountPoint **head) { - FILE *proc_self_mountinfo; - char *path, *p; - unsigned int i; - int r; - - assert(head); - - if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"))) - return -errno; - - for (i = 1;; i++) { - int k; - MountPoint *m; - char *root; - bool skip_ro; - - path = p = NULL; - - if ((k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%ms " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &root, - &path)) != 2) { - if (k == EOF) - break; - - log_warning("Failed to parse /proc/self/mountinfo:%u.", i); - - free(path); - continue; - } - - /* If we encounter a bind mount, don't try to remount - * the source dir too early */ - skip_ro = !streq(root, "/"); - free(root); - - p = cunescape(path); - free(path); - - if (!p) { - r = -ENOMEM; - goto finish; - } - - if (mount_point_is_api(p) || mount_point_ignore(p)) { - free(p); - continue; - } - - if (!(m = new0(MountPoint, 1))) { - free(p); - r = -ENOMEM; - goto finish; - } - - m->path = p; - m->skip_ro = skip_ro; - LIST_PREPEND(MountPoint, mount_point, *head, m); - } - - r = 0; - -finish: - fclose(proc_self_mountinfo); - - return r; -} - -static int swap_list_get(MountPoint **head) { - FILE *proc_swaps; - unsigned int i; - int r; - - assert(head); - - if (!(proc_swaps = fopen("/proc/swaps", "re"))) - return (errno == ENOENT) ? 0 : -errno; - - (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n"); - - for (i = 2;; i++) { - MountPoint *swap; - char *dev = NULL, *d; - int k; - - if ((k = fscanf(proc_swaps, - "%ms " /* device/file */ - "%*s " /* type of swap */ - "%*s " /* swap size */ - "%*s " /* used */ - "%*s\n", /* priority */ - &dev)) != 1) { - - if (k == EOF) - break; - - log_warning("Failed to parse /proc/swaps:%u.", i); - - free(dev); - continue; - } - - if (endswith(dev, "(deleted)")) { - free(dev); - continue; - } - - d = cunescape(dev); - free(dev); - - if (!d) { - r = -ENOMEM; - goto finish; - } - - if (!(swap = new0(MountPoint, 1))) { - free(d); - r = -ENOMEM; - goto finish; - } - - swap->path = d; - LIST_PREPEND(MountPoint, mount_point, *head, swap); - } - - r = 0; - -finish: - fclose(proc_swaps); - - return r; -} - -static int loopback_list_get(MountPoint **head) { - int r; - struct udev *udev; - struct udev_enumerate *e = NULL; - struct udev_list_entry *item = NULL, *first = NULL; - - assert(head); - - if (!(udev = udev_new())) { - r = -ENOMEM; - goto finish; - } - - if (!(e = udev_enumerate_new(udev))) { - r = -ENOMEM; - goto finish; - } - - if (udev_enumerate_add_match_subsystem(e, "block") < 0 || - udev_enumerate_add_match_sysname(e, "loop*") < 0) { - r = -EIO; - goto finish; - } - - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; - goto finish; - } - - first = udev_enumerate_get_list_entry(e); - udev_list_entry_foreach(item, first) { - MountPoint *lb; - struct udev_device *d; - char *loop; - const char *dn; - - if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) { - r = -ENOMEM; - goto finish; - } - - if (!(dn = udev_device_get_devnode(d))) { - udev_device_unref(d); - continue; - } - - loop = strdup(dn); - udev_device_unref(d); - - if (!loop) { - r = -ENOMEM; - goto finish; - } - - if (!(lb = new0(MountPoint, 1))) { - free(loop); - r = -ENOMEM; - goto finish; - } - - lb->path = loop; - LIST_PREPEND(MountPoint, mount_point, *head, lb); - } - - r = 0; - -finish: - if (e) - udev_enumerate_unref(e); - - if (udev) - udev_unref(udev); - - return r; -} - -static int dm_list_get(MountPoint **head) { - int r; - struct udev *udev; - struct udev_enumerate *e = NULL; - struct udev_list_entry *item = NULL, *first = NULL; - - assert(head); - - if (!(udev = udev_new())) { - r = -ENOMEM; - goto finish; - } - - if (!(e = udev_enumerate_new(udev))) { - r = -ENOMEM; - goto finish; - } - - if (udev_enumerate_add_match_subsystem(e, "block") < 0 || - udev_enumerate_add_match_sysname(e, "dm-*") < 0) { - r = -EIO; - goto finish; - } - - if (udev_enumerate_scan_devices(e) < 0) { - r = -EIO; - goto finish; - } - - first = udev_enumerate_get_list_entry(e); - - udev_list_entry_foreach(item, first) { - MountPoint *m; - struct udev_device *d; - dev_t devnum; - char *node; - const char *dn; - - if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) { - r = -ENOMEM; - goto finish; - } - - devnum = udev_device_get_devnum(d); - dn = udev_device_get_devnode(d); - - if (major(devnum) == 0 || !dn) { - udev_device_unref(d); - continue; - } - - node = strdup(dn); - udev_device_unref(d); - - if (!node) { - r = -ENOMEM; - goto finish; - } - - if (!(m = new(MountPoint, 1))) { - free(node); - r = -ENOMEM; - goto finish; - } - - m->path = node; - m->devnum = devnum; - LIST_PREPEND(MountPoint, mount_point, *head, m); - } - - r = 0; - -finish: - if (e) - udev_enumerate_unref(e); - - if (udev) - udev_unref(udev); - - return r; -} - -static int delete_loopback(const char *device) { - int fd, r; - - if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0) - return errno == ENOENT ? 0 : -errno; - - r = ioctl(fd, LOOP_CLR_FD, 0); - close_nointr_nofail(fd); - - if (r >= 0) - return 1; - - /* ENXIO: not bound, so no error */ - if (errno == ENXIO) - return 0; - - return -errno; -} - -static int delete_dm(dev_t devnum) { - int fd, r; - struct dm_ioctl dm; - - assert(major(devnum) != 0); - - if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0) - return -errno; - - zero(dm); - dm.version[0] = DM_VERSION_MAJOR; - dm.version[1] = DM_VERSION_MINOR; - dm.version[2] = DM_VERSION_PATCHLEVEL; - - dm.data_size = sizeof(dm); - dm.dev = devnum; - - r = ioctl(fd, DM_DEV_REMOVE, &dm); - close_nointr_nofail(fd); - - return r >= 0 ? 0 : -errno; -} - -static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) { - MountPoint *m, *n; - int n_failed = 0; - - assert(head); - - LIST_FOREACH_SAFE(mount_point, m, n, *head) { - if (streq(m->path, "/")) { - n_failed++; - continue; - } - - /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */ - if (umount2(m->path, MNT_FORCE) == 0) { - log_info("Unmounted %s.", m->path); - if (changed) - *changed = true; - - mount_point_free(head, m); - } else if (log_error) { - log_warning("Could not unmount %s: %m", m->path); - n_failed++; - } - } - - return n_failed; -} - -static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) { - MountPoint *m, *n; - int n_failed = 0; - - assert(head); - - LIST_FOREACH_SAFE(mount_point, m, n, *head) { - - if (m->skip_ro) { - n_failed++; - continue; - } - - /* Trying to remount read-only */ - if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) { - if (changed) - *changed = true; - - mount_point_free(head, m); - } else { - log_warning("Could not remount as read-only %s: %m", m->path); - n_failed++; - } - } - - return n_failed; -} - -static int swap_points_list_off(MountPoint **head, bool *changed) { - MountPoint *m, *n; - int n_failed = 0; - - assert(head); - - LIST_FOREACH_SAFE(mount_point, m, n, *head) { - if (swapoff(m->path) == 0) { - if (changed) - *changed = true; - - mount_point_free(head, m); - } else { - log_warning("Could not deactivate swap %s: %m", m->path); - n_failed++; - } - } - - return n_failed; -} - -static int loopback_points_list_detach(MountPoint **head, bool *changed) { - MountPoint *m, *n; - int n_failed = 0, k; - struct stat root_st; - - assert(head); - - k = lstat("/", &root_st); - - LIST_FOREACH_SAFE(mount_point, m, n, *head) { - int r; - struct stat loopback_st; - - if (k >= 0 && - major(root_st.st_dev) != 0 && - lstat(m->path, &loopback_st) >= 0 && - root_st.st_dev == loopback_st.st_rdev) { - n_failed ++; - continue; - } - - if ((r = delete_loopback(m->path)) >= 0) { - - if (r > 0 && changed) - *changed = true; - - mount_point_free(head, m); - } else { - log_warning("Could not delete loopback %s: %m", m->path); - n_failed++; - } - } - - return n_failed; -} - -static int dm_points_list_detach(MountPoint **head, bool *changed) { - MountPoint *m, *n; - int n_failed = 0, k; - struct stat root_st; - - assert(head); - - k = lstat("/", &root_st); - - LIST_FOREACH_SAFE(mount_point, m, n, *head) { - int r; - - if (k >= 0 && - major(root_st.st_dev) != 0 && - root_st.st_dev == m->devnum) { - n_failed ++; - continue; - } - - if ((r = delete_dm(m->devnum)) >= 0) { - - if (r > 0 && changed) - *changed = true; - - mount_point_free(head, m); - } else { - log_warning("Could not delete dm %s: %m", m->path); - n_failed++; - } - } - - return n_failed; -} - -int umount_all(bool *changed) { - int r; - bool umount_changed; - - LIST_HEAD(MountPoint, mp_list_head); - - LIST_HEAD_INIT(MountPoint, mp_list_head); - - r = mount_points_list_get(&mp_list_head); - if (r < 0) - goto end; - - /* retry umount, until nothing can be umounted anymore */ - do { - umount_changed = false; - - mount_points_list_umount(&mp_list_head, &umount_changed, false); - if (umount_changed) - *changed = true; - - } while (umount_changed); - - /* umount one more time with logging enabled */ - r = mount_points_list_umount(&mp_list_head, &umount_changed, true); - if (r <= 0) - goto end; - - r = mount_points_list_remount_read_only(&mp_list_head, changed); - - end: - mount_points_list_free(&mp_list_head); - - return r; -} - -int swapoff_all(bool *changed) { - int r; - LIST_HEAD(MountPoint, swap_list_head); - - LIST_HEAD_INIT(MountPoint, swap_list_head); - - r = swap_list_get(&swap_list_head); - if (r < 0) - goto end; - - r = swap_points_list_off(&swap_list_head, changed); - - end: - mount_points_list_free(&swap_list_head); - - return r; -} - -int loopback_detach_all(bool *changed) { - int r; - LIST_HEAD(MountPoint, loopback_list_head); - - LIST_HEAD_INIT(MountPoint, loopback_list_head); - - r = loopback_list_get(&loopback_list_head); - if (r < 0) - goto end; - - r = loopback_points_list_detach(&loopback_list_head, changed); - - end: - mount_points_list_free(&loopback_list_head); - - return r; -} - -int dm_detach_all(bool *changed) { - int r; - LIST_HEAD(MountPoint, dm_list_head); - - LIST_HEAD_INIT(MountPoint, dm_list_head); - - r = dm_list_get(&dm_list_head); - if (r < 0) - goto end; - - r = dm_points_list_detach(&dm_list_head, changed); - - end: - mount_points_list_free(&dm_list_head); - - return r; -} diff --git a/src/umount.h b/src/umount.h deleted file mode 100644 index acdf09a..0000000 --- a/src/umount.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooumounthfoo -#define fooumounthfoo - -/*** - This file is part of systemd. - - Copyright 2010 ProFUSION embedded systems - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int umount_all(bool *changed); - -int swapoff_all(bool *changed); - -int loopback_detach_all(bool *changed); - -int dm_detach_all(bool *changed); - -#endif diff --git a/src/unit-name.c b/src/unit-name.c deleted file mode 100644 index 1cbb804..0000000 --- a/src/unit-name.c +++ /dev/null @@ -1,448 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "util.h" -#include "unit-name.h" - -#define VALID_CHARS \ - "0123456789" \ - "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - ":-_.\\" - -bool unit_name_is_valid_no_type(const char *n, bool template_ok) { - const char *e, *i, *at; - - /* Valid formats: - * - * string@instance.suffix - * string.suffix - */ - - assert(n); - - if (strlen(n) >= UNIT_NAME_MAX) - return false; - - e = strrchr(n, '.'); - if (!e || e == n) - return false; - - for (i = n, at = NULL; i < e; i++) { - - if (*i == '@' && !at) - at = i; - - if (!strchr("@" VALID_CHARS, *i)) - return false; - } - - if (at) { - if (at == n) - return false; - - if (!template_ok && at+1 == e) - return false; - } - - return true; -} - -bool unit_instance_is_valid(const char *i) { - assert(i); - - /* The max length depends on the length of the string, so we - * don't really check this here. */ - - if (i[0] == 0) - return false; - - /* We allow additional @ in the instance string, we do not - * allow them in the prefix! */ - - for (; *i; i++) - if (!strchr("@" VALID_CHARS, *i)) - return false; - - return true; -} - -bool unit_prefix_is_valid(const char *p) { - - /* We don't allow additional @ in the instance string */ - - if (p[0] == 0) - return false; - - for (; *p; p++) - if (!strchr(VALID_CHARS, *p)) - return false; - - return true; -} - -int unit_name_to_instance(const char *n, char **instance) { - const char *p, *d; - char *i; - - assert(n); - assert(instance); - - /* Everything past the first @ and before the last . is the instance */ - if (!(p = strchr(n, '@'))) { - *instance = NULL; - return 0; - } - - assert_se(d = strrchr(n, '.')); - assert(p < d); - - if (!(i = strndup(p+1, d-p-1))) - return -ENOMEM; - - *instance = i; - return 0; -} - -char *unit_name_to_prefix_and_instance(const char *n) { - const char *d; - - assert(n); - - assert_se(d = strrchr(n, '.')); - - return strndup(n, d - n); -} - -char *unit_name_to_prefix(const char *n) { - const char *p; - - if ((p = strchr(n, '@'))) - return strndup(n, p - n); - - return unit_name_to_prefix_and_instance(n); -} - -char *unit_name_change_suffix(const char *n, const char *suffix) { - char *e, *r; - size_t a, b; - - assert(n); - assert(unit_name_is_valid_no_type(n, true)); - assert(suffix); - - assert_se(e = strrchr(n, '.')); - a = e - n; - b = strlen(suffix); - - if (!(r = new(char, a + b + 1))) - return NULL; - - memcpy(r, n, a); - memcpy(r+a, suffix, b+1); - - return r; -} - -char *unit_name_build(const char *prefix, const char *instance, const char *suffix) { - assert(prefix); - assert(unit_prefix_is_valid(prefix)); - assert(!instance || unit_instance_is_valid(instance)); - assert(suffix); - - if (!instance) - return strappend(prefix, suffix); - - return join(prefix, "@", instance, suffix, NULL); -} - -static char* do_escape(const char *f, char *t) { - assert(f); - assert(t); - - for (; *f; f++) { - if (*f == '/') - *(t++) = '-'; - else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - return t; -} - -char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) { - char *r, *t; - size_t a, b, c; - - assert(prefix); - assert(suffix); - - /* Takes a arbitrary string for prefix and instance plus a - * suffix and makes a nice string suitable as unit name of it, - * escaping all weird chars on the way. - * - * / becomes ., and all chars not allowed in a unit name get - * escaped as \xFF, including \ and ., of course. This - * escaping is hence reversible. - * - * This is primarily useful to make nice unit names from - * strings, but is actually useful for any kind of string. - */ - - a = strlen(prefix); - c = strlen(suffix); - - if (instance) { - b = strlen(instance); - - if (!(r = new(char, a*4 + 1 + b*4 + c + 1))) - return NULL; - - t = do_escape(prefix, r); - *(t++) = '@'; - t = do_escape(instance, t); - } else { - - if (!(r = new(char, a*4 + c + 1))) - return NULL; - - t = do_escape(prefix, r); - } - - strcpy(t, suffix); - return r; -} - -char *unit_name_escape(const char *f) { - char *r, *t; - - if (!(r = new(char, strlen(f)*4+1))) - return NULL; - - t = do_escape(f, r); - *t = 0; - - return r; - -} - -char *unit_name_unescape(const char *f) { - char *r, *t; - - assert(f); - - if (!(r = strdup(f))) - return NULL; - - for (t = r; *f; f++) { - if (*f == '-') - *(t++) = '/'; - else if (*f == '\\') { - int a, b; - - if (f[1] != 'x' || - (a = unhexchar(f[2])) < 0 || - (b = unhexchar(f[3])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 3; - } - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -bool unit_name_is_template(const char *n) { - const char *p; - - assert(n); - - if (!(p = strchr(n, '@'))) - return false; - - return p[1] == '.'; -} - -char *unit_name_replace_instance(const char *f, const char *i) { - const char *p, *e; - char *r, *k; - size_t a; - - assert(f); - - p = strchr(f, '@'); - assert_se(e = strrchr(f, '.')); - - a = p - f; - - if (p) { - size_t b; - - b = strlen(i); - - if (!(r = new(char, a + 1 + b + strlen(e) + 1))) - return NULL; - - k = mempcpy(r, f, a + 1); - k = mempcpy(k, i, b); - } else { - - if (!(r = new(char, a + strlen(e) + 1))) - return NULL; - - k = mempcpy(r, f, a); - } - - strcpy(k, e); - return r; -} - -char *unit_name_template(const char *f) { - const char *p, *e; - char *r; - size_t a; - - if (!(p = strchr(f, '@'))) - return strdup(f); - - assert_se(e = strrchr(f, '.')); - a = p - f + 1; - - if (!(r = new(char, a + strlen(e) + 1))) - return NULL; - - strcpy(mempcpy(r, f, a), e); - return r; - -} - -char *unit_name_from_path(const char *path, const char *suffix) { - char *p, *r; - - assert(path); - assert(suffix); - - if (!(p = strdup(path))) - return NULL; - - path_kill_slashes(p); - - path = p[0] == '/' ? p + 1 : p; - - if (path[0] == 0) { - free(p); - return strappend("-", suffix); - } - - r = unit_name_build_escape(path, NULL, suffix); - free(p); - - return r; -} - -char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) { - char *p, *r; - - assert(path); - assert(suffix); - - if (!(p = strdup(path))) - return NULL; - - path_kill_slashes(p); - - path = p[0] == '/' ? p + 1 : p; - - if (path[0] == 0) { - free(p); - return unit_name_build_escape(prefix, "-", suffix); - } - - r = unit_name_build_escape(prefix, path, suffix); - free(p); - - return r; -} - -char *unit_name_to_path(const char *name) { - char *w, *e; - - assert(name); - - if (!(w = unit_name_to_prefix(name))) - return NULL; - - e = unit_name_unescape(w); - free(w); - - if (!e) - return NULL; - - if (e[0] != '/') { - w = strappend("/", e); - free(e); - - if (!w) - return NULL; - - e = w; - } - - return e; -} - -char *unit_name_path_unescape(const char *f) { - char *e; - - assert(f); - - if (!(e = unit_name_unescape(f))) - return NULL; - - if (e[0] != '/') { - char *w; - - w = strappend("/", e); - free(e); - - if (!w) - return NULL; - - e = w; - } - - return e; -} diff --git a/src/unit-name.h b/src/unit-name.h deleted file mode 100644 index e369910..0000000 --- a/src/unit-name.h +++ /dev/null @@ -1,57 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foounitnamehfoo -#define foounitnamehfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include - -#define UNIT_NAME_MAX 256 - -int unit_name_to_instance(const char *n, char **instance); -char* unit_name_to_prefix(const char *n); -char* unit_name_to_prefix_and_instance(const char *n); - -bool unit_name_is_valid_no_type(const char *n, bool template_ok); -bool unit_prefix_is_valid(const char *p); -bool unit_instance_is_valid(const char *i); - -char *unit_name_change_suffix(const char *n, const char *suffix); - -char *unit_name_build(const char *prefix, const char *instance, const char *suffix); -char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix); - -char *unit_name_escape(const char *f); -char *unit_name_unescape(const char *f); - -char *unit_name_path_unescape(const char *f); - -bool unit_name_is_template(const char *n); - -char *unit_name_replace_instance(const char *f, const char *i); - -char *unit_name_template(const char *f); - -char *unit_name_from_path(const char *path, const char *suffix); -char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix); -char *unit_name_to_path(const char *name); - -#endif diff --git a/src/unit.c b/src/unit.c deleted file mode 100644 index 903a8e4..0000000 --- a/src/unit.c +++ /dev/null @@ -1,2619 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "set.h" -#include "unit.h" -#include "macro.h" -#include "strv.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "unit-name.h" -#include "specifier.h" -#include "dbus-unit.h" -#include "special.h" -#include "cgroup-util.h" -#include "missing.h" -#include "cgroup-attr.h" - -const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { - [UNIT_SERVICE] = &service_vtable, - [UNIT_TIMER] = &timer_vtable, - [UNIT_SOCKET] = &socket_vtable, - [UNIT_TARGET] = &target_vtable, - [UNIT_DEVICE] = &device_vtable, - [UNIT_MOUNT] = &mount_vtable, - [UNIT_AUTOMOUNT] = &automount_vtable, - [UNIT_SNAPSHOT] = &snapshot_vtable, - [UNIT_SWAP] = &swap_vtable, - [UNIT_PATH] = &path_vtable -}; - -Unit *unit_new(Manager *m) { - Unit *u; - - assert(m); - - if (!(u = new0(Unit, 1))) - return NULL; - - if (!(u->meta.names = set_new(string_hash_func, string_compare_func))) { - free(u); - return NULL; - } - - u->meta.manager = m; - u->meta.type = _UNIT_TYPE_INVALID; - u->meta.deserialized_job = _JOB_TYPE_INVALID; - u->meta.default_dependencies = true; - u->meta.unit_file_state = _UNIT_FILE_STATE_INVALID; - - return u; -} - -bool unit_has_name(Unit *u, const char *name) { - assert(u); - assert(name); - - return !!set_get(u->meta.names, (char*) name); -} - -int unit_add_name(Unit *u, const char *text) { - UnitType t; - char *s, *i = NULL; - int r; - - assert(u); - assert(text); - - if (unit_name_is_template(text)) { - if (!u->meta.instance) - return -EINVAL; - - s = unit_name_replace_instance(text, u->meta.instance); - } else - s = strdup(text); - - if (!s) - return -ENOMEM; - - if (!unit_name_is_valid(s, false)) { - r = -EINVAL; - goto fail; - } - - assert_se((t = unit_name_to_type(s)) >= 0); - - if (u->meta.type != _UNIT_TYPE_INVALID && t != u->meta.type) { - r = -EINVAL; - goto fail; - } - - if ((r = unit_name_to_instance(s, &i)) < 0) - goto fail; - - if (i && unit_vtable[t]->no_instances) { - r = -EINVAL; - goto fail; - } - - /* Ensure that this unit is either instanced or not instanced, - * but not both. */ - if (u->meta.type != _UNIT_TYPE_INVALID && !u->meta.instance != !i) { - r = -EINVAL; - goto fail; - } - - if (unit_vtable[t]->no_alias && - !set_isempty(u->meta.names) && - !set_get(u->meta.names, s)) { - r = -EEXIST; - goto fail; - } - - if (hashmap_size(u->meta.manager->units) >= MANAGER_MAX_NAMES) { - r = -E2BIG; - goto fail; - } - - if ((r = set_put(u->meta.names, s)) < 0) { - if (r == -EEXIST) - r = 0; - goto fail; - } - - if ((r = hashmap_put(u->meta.manager->units, s, u)) < 0) { - set_remove(u->meta.names, s); - goto fail; - } - - if (u->meta.type == _UNIT_TYPE_INVALID) { - - u->meta.type = t; - u->meta.id = s; - u->meta.instance = i; - - LIST_PREPEND(Meta, units_by_type, u->meta.manager->units_by_type[t], &u->meta); - - if (UNIT_VTABLE(u)->init) - UNIT_VTABLE(u)->init(u); - } else - free(i); - - unit_add_to_dbus_queue(u); - return 0; - -fail: - free(s); - free(i); - - return r; -} - -int unit_choose_id(Unit *u, const char *name) { - char *s, *t = NULL, *i; - int r; - - assert(u); - assert(name); - - if (unit_name_is_template(name)) { - - if (!u->meta.instance) - return -EINVAL; - - if (!(t = unit_name_replace_instance(name, u->meta.instance))) - return -ENOMEM; - - name = t; - } - - /* Selects one of the names of this unit as the id */ - s = set_get(u->meta.names, (char*) name); - free(t); - - if (!s) - return -ENOENT; - - if ((r = unit_name_to_instance(s, &i)) < 0) - return r; - - u->meta.id = s; - - free(u->meta.instance); - u->meta.instance = i; - - unit_add_to_dbus_queue(u); - - return 0; -} - -int unit_set_description(Unit *u, const char *description) { - char *s; - - assert(u); - - if (!(s = strdup(description))) - return -ENOMEM; - - free(u->meta.description); - u->meta.description = s; - - unit_add_to_dbus_queue(u); - return 0; -} - -bool unit_check_gc(Unit *u) { - assert(u); - - if (u->meta.load_state == UNIT_STUB) - return true; - - if (UNIT_VTABLE(u)->no_gc) - return true; - - if (u->meta.no_gc) - return true; - - if (u->meta.job) - return true; - - if (unit_active_state(u) != UNIT_INACTIVE) - return true; - - if (UNIT_VTABLE(u)->check_gc) - if (UNIT_VTABLE(u)->check_gc(u)) - return true; - - return false; -} - -void unit_add_to_load_queue(Unit *u) { - assert(u); - assert(u->meta.type != _UNIT_TYPE_INVALID); - - if (u->meta.load_state != UNIT_STUB || u->meta.in_load_queue) - return; - - LIST_PREPEND(Meta, load_queue, u->meta.manager->load_queue, &u->meta); - u->meta.in_load_queue = true; -} - -void unit_add_to_cleanup_queue(Unit *u) { - assert(u); - - if (u->meta.in_cleanup_queue) - return; - - LIST_PREPEND(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta); - u->meta.in_cleanup_queue = true; -} - -void unit_add_to_gc_queue(Unit *u) { - assert(u); - - if (u->meta.in_gc_queue || u->meta.in_cleanup_queue) - return; - - if (unit_check_gc(u)) - return; - - LIST_PREPEND(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta); - u->meta.in_gc_queue = true; - - u->meta.manager->n_in_gc_queue ++; - - if (u->meta.manager->gc_queue_timestamp <= 0) - u->meta.manager->gc_queue_timestamp = now(CLOCK_MONOTONIC); -} - -void unit_add_to_dbus_queue(Unit *u) { - assert(u); - assert(u->meta.type != _UNIT_TYPE_INVALID); - - if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue) - return; - - /* Shortcut things if nobody cares */ - if (!bus_has_subscriber(u->meta.manager)) { - u->meta.sent_dbus_new_signal = true; - return; - } - - LIST_PREPEND(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); - u->meta.in_dbus_queue = true; -} - -static void bidi_set_free(Unit *u, Set *s) { - Iterator i; - Unit *other; - - assert(u); - - /* Frees the set and makes sure we are dropped from the - * inverse pointers */ - - SET_FOREACH(other, s, i) { - UnitDependency d; - - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - set_remove(other->meta.dependencies[d], u); - - unit_add_to_gc_queue(other); - } - - set_free(s); -} - -void unit_free(Unit *u) { - UnitDependency d; - Iterator i; - char *t; - - assert(u); - - bus_unit_send_removed_signal(u); - - if (u->meta.load_state != UNIT_STUB) - if (UNIT_VTABLE(u)->done) - UNIT_VTABLE(u)->done(u); - - SET_FOREACH(t, u->meta.names, i) - hashmap_remove_value(u->meta.manager->units, t, u); - - if (u->meta.job) - job_free(u->meta.job); - - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - bidi_set_free(u, u->meta.dependencies[d]); - - if (u->meta.type != _UNIT_TYPE_INVALID) - LIST_REMOVE(Meta, units_by_type, u->meta.manager->units_by_type[u->meta.type], &u->meta); - - if (u->meta.in_load_queue) - LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta); - - if (u->meta.in_dbus_queue) - LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); - - if (u->meta.in_cleanup_queue) - LIST_REMOVE(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta); - - if (u->meta.in_gc_queue) { - LIST_REMOVE(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta); - u->meta.manager->n_in_gc_queue--; - } - - cgroup_bonding_free_list(u->meta.cgroup_bondings, u->meta.manager->n_reloading <= 0); - cgroup_attribute_free_list(u->meta.cgroup_attributes); - - free(u->meta.description); - free(u->meta.fragment_path); - - set_free_free(u->meta.names); - - condition_free_list(u->meta.conditions); - - free(u->meta.instance); - free(u); -} - -UnitActiveState unit_active_state(Unit *u) { - assert(u); - - if (u->meta.load_state == UNIT_MERGED) - return unit_active_state(unit_follow_merge(u)); - - /* After a reload it might happen that a unit is not correctly - * loaded but still has a process around. That's why we won't - * shortcut failed loading to UNIT_INACTIVE_FAILED. */ - - return UNIT_VTABLE(u)->active_state(u); -} - -const char* unit_sub_state_to_string(Unit *u) { - assert(u); - - return UNIT_VTABLE(u)->sub_state_to_string(u); -} - -static void complete_move(Set **s, Set **other) { - assert(s); - assert(other); - - if (!*other) - return; - - if (*s) - set_move(*s, *other); - else { - *s = *other; - *other = NULL; - } -} - -static void merge_names(Unit *u, Unit *other) { - char *t; - Iterator i; - - assert(u); - assert(other); - - complete_move(&u->meta.names, &other->meta.names); - - set_free_free(other->meta.names); - other->meta.names = NULL; - other->meta.id = NULL; - - SET_FOREACH(t, u->meta.names, i) - assert_se(hashmap_replace(u->meta.manager->units, t, u) == 0); -} - -static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) { - Iterator i; - Unit *back; - int r; - - assert(u); - assert(other); - assert(d < _UNIT_DEPENDENCY_MAX); - - /* Fix backwards pointers */ - SET_FOREACH(back, other->meta.dependencies[d], i) { - UnitDependency k; - - for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) - if ((r = set_remove_and_put(back->meta.dependencies[k], other, u)) < 0) { - - if (r == -EEXIST) - set_remove(back->meta.dependencies[k], other); - else - assert(r == -ENOENT); - } - } - - complete_move(&u->meta.dependencies[d], &other->meta.dependencies[d]); - - set_free(other->meta.dependencies[d]); - other->meta.dependencies[d] = NULL; -} - -int unit_merge(Unit *u, Unit *other) { - UnitDependency d; - - assert(u); - assert(other); - assert(u->meta.manager == other->meta.manager); - assert(u->meta.type != _UNIT_TYPE_INVALID); - - other = unit_follow_merge(other); - - if (other == u) - return 0; - - if (u->meta.type != other->meta.type) - return -EINVAL; - - if (!u->meta.instance != !other->meta.instance) - return -EINVAL; - - if (other->meta.load_state != UNIT_STUB && - other->meta.load_state != UNIT_ERROR) - return -EEXIST; - - if (other->meta.job) - return -EEXIST; - - if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) - return -EEXIST; - - /* Merge names */ - merge_names(u, other); - - /* Merge dependencies */ - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - merge_dependencies(u, other, d); - - other->meta.load_state = UNIT_MERGED; - other->meta.merged_into = u; - - /* If there is still some data attached to the other node, we - * don't need it anymore, and can free it. */ - if (other->meta.load_state != UNIT_STUB) - if (UNIT_VTABLE(other)->done) - UNIT_VTABLE(other)->done(other); - - unit_add_to_dbus_queue(u); - unit_add_to_cleanup_queue(other); - - return 0; -} - -int unit_merge_by_name(Unit *u, const char *name) { - Unit *other; - int r; - char *s = NULL; - - assert(u); - assert(name); - - if (unit_name_is_template(name)) { - if (!u->meta.instance) - return -EINVAL; - - if (!(s = unit_name_replace_instance(name, u->meta.instance))) - return -ENOMEM; - - name = s; - } - - if (!(other = manager_get_unit(u->meta.manager, name))) - r = unit_add_name(u, name); - else - r = unit_merge(u, other); - - free(s); - return r; -} - -Unit* unit_follow_merge(Unit *u) { - assert(u); - - while (u->meta.load_state == UNIT_MERGED) - assert_se(u = u->meta.merged_into); - - return u; -} - -int unit_add_exec_dependencies(Unit *u, ExecContext *c) { - int r; - - assert(u); - assert(c); - - if (c->std_output != EXEC_OUTPUT_KMSG && - c->std_output != EXEC_OUTPUT_SYSLOG && - c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE && - c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE && - c->std_error != EXEC_OUTPUT_KMSG && - c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE && - c->std_error != EXEC_OUTPUT_KMSG && - c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE) - return 0; - - /* If syslog or kernel logging is requested, make sure our own - * logging daemon is run first. */ - - if (u->meta.manager->running_as == MANAGER_SYSTEM) - if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_STDOUT_SYSLOG_BRIDGE_SOCKET, NULL, true)) < 0) - return r; - - return 0; -} - -const char *unit_description(Unit *u) { - assert(u); - - if (u->meta.description) - return u->meta.description; - - return strna(u->meta.id); -} - -void unit_dump(Unit *u, FILE *f, const char *prefix) { - char *t; - UnitDependency d; - Iterator i; - char *p2; - const char *prefix2; - char - timestamp1[FORMAT_TIMESTAMP_MAX], - timestamp2[FORMAT_TIMESTAMP_MAX], - timestamp3[FORMAT_TIMESTAMP_MAX], - timestamp4[FORMAT_TIMESTAMP_MAX], - timespan[FORMAT_TIMESPAN_MAX]; - Unit *following; - - assert(u); - assert(u->meta.type >= 0); - - if (!prefix) - prefix = ""; - p2 = strappend(prefix, "\t"); - prefix2 = p2 ? p2 : prefix; - - fprintf(f, - "%s-> Unit %s:\n" - "%s\tDescription: %s\n" - "%s\tInstance: %s\n" - "%s\tUnit Load State: %s\n" - "%s\tUnit Active State: %s\n" - "%s\tInactive Exit Timestamp: %s\n" - "%s\tActive Enter Timestamp: %s\n" - "%s\tActive Exit Timestamp: %s\n" - "%s\tInactive Enter Timestamp: %s\n" - "%s\tGC Check Good: %s\n" - "%s\tNeed Daemon Reload: %s\n", - prefix, u->meta.id, - prefix, unit_description(u), - prefix, strna(u->meta.instance), - prefix, unit_load_state_to_string(u->meta.load_state), - prefix, unit_active_state_to_string(unit_active_state(u)), - prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.inactive_exit_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp.realtime)), - prefix, yes_no(unit_check_gc(u)), - prefix, yes_no(unit_need_daemon_reload(u))); - - SET_FOREACH(t, u->meta.names, i) - fprintf(f, "%s\tName: %s\n", prefix, t); - - if ((following = unit_following(u))) - fprintf(f, "%s\tFollowing: %s\n", prefix, following->meta.id); - - if (u->meta.fragment_path) - fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path); - - if (u->meta.job_timeout > 0) - fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->meta.job_timeout)); - - condition_dump_list(u->meta.conditions, f, prefix); - - if (dual_timestamp_is_set(&u->meta.condition_timestamp)) - fprintf(f, - "%s\tCondition Timestamp: %s\n" - "%s\tCondition Result: %s\n", - prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.condition_timestamp.realtime)), - prefix, yes_no(u->meta.condition_result)); - - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { - Unit *other; - - SET_FOREACH(other, u->meta.dependencies[d], i) - fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->meta.id); - } - - if (u->meta.load_state == UNIT_LOADED) { - CGroupBonding *b; - CGroupAttribute *a; - - fprintf(f, - "%s\tStopWhenUnneeded: %s\n" - "%s\tRefuseManualStart: %s\n" - "%s\tRefuseManualStop: %s\n" - "%s\tDefaultDependencies: %s\n" - "%s\tOnFailureIsolate: %s\n" - "%s\tIgnoreOnIsolate: %s\n" - "%s\tIgnoreOnSnapshot: %s\n", - prefix, yes_no(u->meta.stop_when_unneeded), - prefix, yes_no(u->meta.refuse_manual_start), - prefix, yes_no(u->meta.refuse_manual_stop), - prefix, yes_no(u->meta.default_dependencies), - prefix, yes_no(u->meta.on_failure_isolate), - prefix, yes_no(u->meta.ignore_on_isolate), - prefix, yes_no(u->meta.ignore_on_snapshot)); - - LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings) - fprintf(f, "%s\tControlGroup: %s:%s\n", - prefix, b->controller, b->path); - - LIST_FOREACH(by_unit, a, u->meta.cgroup_attributes) { - char *v = NULL; - - if (a->map_callback) - a->map_callback(a->controller, a->name, a->value, &v); - - fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n", - prefix, a->controller, a->name, v ? v : a->value); - - free(v); - } - - if (UNIT_VTABLE(u)->dump) - UNIT_VTABLE(u)->dump(u, f, prefix2); - - } else if (u->meta.load_state == UNIT_MERGED) - fprintf(f, - "%s\tMerged into: %s\n", - prefix, u->meta.merged_into->meta.id); - else if (u->meta.load_state == UNIT_ERROR) - fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->meta.load_error)); - - - if (u->meta.job) - job_dump(u->meta.job, f, prefix2); - - free(p2); -} - -/* Common implementation for multiple backends */ -int unit_load_fragment_and_dropin(Unit *u) { - int r; - - assert(u); - - /* Load a .service file */ - if ((r = unit_load_fragment(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_STUB) - return -ENOENT; - - /* Load drop-in directory data */ - if ((r = unit_load_dropin(unit_follow_merge(u))) < 0) - return r; - - return 0; -} - -/* Common implementation for multiple backends */ -int unit_load_fragment_and_dropin_optional(Unit *u) { - int r; - - assert(u); - - /* Same as unit_load_fragment_and_dropin(), but whether - * something can be loaded or not doesn't matter. */ - - /* Load a .service file */ - if ((r = unit_load_fragment(u)) < 0) - return r; - - if (u->meta.load_state == UNIT_STUB) - u->meta.load_state = UNIT_LOADED; - - /* Load drop-in directory data */ - if ((r = unit_load_dropin(unit_follow_merge(u))) < 0) - return r; - - return 0; -} - -int unit_add_default_target_dependency(Unit *u, Unit *target) { - assert(u); - assert(target); - - if (target->meta.type != UNIT_TARGET) - return 0; - - /* Only add the dependency if both units are loaded, so that - * that loop check below is reliable */ - if (u->meta.load_state != UNIT_LOADED || - target->meta.load_state != UNIT_LOADED) - return 0; - - /* If either side wants no automatic dependencies, then let's - * skip this */ - if (!u->meta.default_dependencies || - !target->meta.default_dependencies) - return 0; - - /* Don't create loops */ - if (set_get(target->meta.dependencies[UNIT_BEFORE], u)) - return 0; - - return unit_add_dependency(target, UNIT_AFTER, u, true); -} - -static int unit_add_default_dependencies(Unit *u) { - static const UnitDependency deps[] = { - UNIT_REQUIRED_BY, - UNIT_REQUIRED_BY_OVERRIDABLE, - UNIT_WANTED_BY, - UNIT_BOUND_BY - }; - - Unit *target; - Iterator i; - int r; - unsigned k; - - assert(u); - - for (k = 0; k < ELEMENTSOF(deps); k++) - SET_FOREACH(target, u->meta.dependencies[deps[k]], i) - if ((r = unit_add_default_target_dependency(u, target)) < 0) - return r; - - return 0; -} - -int unit_load(Unit *u) { - int r; - - assert(u); - - if (u->meta.in_load_queue) { - LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta); - u->meta.in_load_queue = false; - } - - if (u->meta.type == _UNIT_TYPE_INVALID) - return -EINVAL; - - if (u->meta.load_state != UNIT_STUB) - return 0; - - if (UNIT_VTABLE(u)->load) - if ((r = UNIT_VTABLE(u)->load(u)) < 0) - goto fail; - - if (u->meta.load_state == UNIT_STUB) { - r = -ENOENT; - goto fail; - } - - if (u->meta.load_state == UNIT_LOADED && - u->meta.default_dependencies) - if ((r = unit_add_default_dependencies(u)) < 0) - goto fail; - - if (u->meta.on_failure_isolate && - set_size(u->meta.dependencies[UNIT_ON_FAILURE]) > 1) { - - log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.", - u->meta.id); - - r = -EINVAL; - goto fail; - } - - assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into); - - unit_add_to_dbus_queue(unit_follow_merge(u)); - unit_add_to_gc_queue(u); - - return 0; - -fail: - u->meta.load_state = UNIT_ERROR; - u->meta.load_error = r; - unit_add_to_dbus_queue(u); - - log_debug("Failed to load configuration for %s: %s", u->meta.id, strerror(-r)); - - return r; -} - -bool unit_condition_test(Unit *u) { - assert(u); - - dual_timestamp_get(&u->meta.condition_timestamp); - u->meta.condition_result = condition_test_list(u->meta.conditions); - - return u->meta.condition_result; -} - -/* Errors: - * -EBADR: This unit type does not support starting. - * -EALREADY: Unit is already started. - * -EAGAIN: An operation is already in progress. Retry later. - * -ECANCELED: Too many requests for now. - */ -int unit_start(Unit *u) { - UnitActiveState state; - Unit *following; - - assert(u); - - if (u->meta.load_state != UNIT_LOADED) - return -EINVAL; - - /* If this is already started, then this will succeed. Note - * that this will even succeed if this unit is not startable - * by the user. This is relied on to detect when we need to - * wait for units and when waiting is finished. */ - state = unit_active_state(u); - if (UNIT_IS_ACTIVE_OR_RELOADING(state)) - return -EALREADY; - - /* 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_debug("Starting of %s requested but condition failed. Ignoring.", u->meta.id); - return -EALREADY; - } - - /* Forward to the main object, if we aren't it. */ - if ((following = unit_following(u))) { - log_debug("Redirecting start request from %s to %s.", u->meta.id, following->meta.id); - return unit_start(following); - } - - /* If it is stopped, but we cannot start it, then fail */ - 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. */ - - unit_add_to_dbus_queue(u); - - unit_status_printf(u, "Starting %s...\n", unit_description(u)); - return UNIT_VTABLE(u)->start(u); -} - -bool unit_can_start(Unit *u) { - assert(u); - - return !!UNIT_VTABLE(u)->start; -} - -bool unit_can_isolate(Unit *u) { - assert(u); - - return unit_can_start(u) && - u->meta.allow_isolate; -} - -/* Errors: - * -EBADR: This unit type does not support stopping. - * -EALREADY: Unit is already stopped. - * -EAGAIN: An operation is already in progress. Retry later. - */ -int unit_stop(Unit *u) { - UnitActiveState state; - Unit *following; - - assert(u); - - state = unit_active_state(u); - if (UNIT_IS_INACTIVE_OR_FAILED(state)) - return -EALREADY; - - if ((following = unit_following(u))) { - log_debug("Redirecting stop request from %s to %s.", u->meta.id, following->meta.id); - return unit_stop(following); - } - - if (!UNIT_VTABLE(u)->stop) - return -EBADR; - - unit_add_to_dbus_queue(u); - - unit_status_printf(u, "Stopping %s...\n", unit_description(u)); - return UNIT_VTABLE(u)->stop(u); -} - -/* Errors: - * -EBADR: This unit type does not support reloading. - * -ENOEXEC: Unit is not started. - * -EAGAIN: An operation is already in progress. Retry later. - */ -int unit_reload(Unit *u) { - UnitActiveState state; - Unit *following; - - assert(u); - - if (u->meta.load_state != UNIT_LOADED) - return -EINVAL; - - if (!unit_can_reload(u)) - return -EBADR; - - state = unit_active_state(u); - if (state == UNIT_RELOADING) - return -EALREADY; - - if (state != UNIT_ACTIVE) - return -ENOEXEC; - - if ((following = unit_following(u))) { - log_debug("Redirecting reload request from %s to %s.", u->meta.id, following->meta.id); - return unit_reload(following); - } - - unit_add_to_dbus_queue(u); - return UNIT_VTABLE(u)->reload(u); -} - -bool unit_can_reload(Unit *u) { - assert(u); - - if (!UNIT_VTABLE(u)->reload) - return false; - - if (!UNIT_VTABLE(u)->can_reload) - return true; - - return UNIT_VTABLE(u)->can_reload(u); -} - -static void unit_check_unneeded(Unit *u) { - Iterator i; - Unit *other; - - assert(u); - - /* If this service shall be shut down when unneeded then do - * so. */ - - if (!u->meta.stop_when_unneeded) - return; - - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) - return; - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - return; - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - return; - - SET_FOREACH(other, u->meta.dependencies[UNIT_WANTED_BY], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - return; - - SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - return; - - log_info("Service %s is not needed anymore. Stopping.", u->meta.id); - - /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ - manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); -} - -static void retroactively_start_dependencies(Unit *u) { - Iterator i; - Unit *other; - - assert(u); - assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))); - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i) - if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_BIND_TO], i) - if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i) - if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i) - if (!set_get(u->meta.dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); - - SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTED_BY], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); -} - -static void retroactively_stop_dependencies(Unit *u) { - Iterator i; - Unit *other; - - assert(u); - assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); - - /* Pull down units which are bound to us recursively if enabled */ - SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); - - /* Garbage collect services that might not be needed anymore, if enabled */ - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); - SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); - SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); - SET_FOREACH(other, u->meta.dependencies[UNIT_BIND_TO], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); -} - -void unit_trigger_on_failure(Unit *u) { - Unit *other; - Iterator i; - - assert(u); - - if (set_size(u->meta.dependencies[UNIT_ON_FAILURE]) <= 0) - return; - - log_info("Triggering OnFailure= dependencies of %s.", u->meta.id); - - SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i) { - int r; - - if ((r = manager_add_job(u->meta.manager, JOB_START, other, u->meta.on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL)) < 0) - log_error("Failed to enqueue OnFailure= job: %s", strerror(-r)); - } -} - -void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) { - bool unexpected; - - assert(u); - assert(os < _UNIT_ACTIVE_STATE_MAX); - assert(ns < _UNIT_ACTIVE_STATE_MAX); - - /* Note that this is called for all low-level state changes, - * even if they might map to the same high-level - * UnitActiveState! That means that ns == os is OK an expected - * behaviour here. For example: if a mount point is remounted - * this function will be called too! */ - - if (u->meta.manager->n_reloading <= 0) { - dual_timestamp ts; - - dual_timestamp_get(&ts); - - if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns)) - u->meta.inactive_exit_timestamp = ts; - else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns)) - u->meta.inactive_enter_timestamp = ts; - - if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) - u->meta.active_enter_timestamp = ts; - else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) - u->meta.active_exit_timestamp = ts; - - timer_unit_notify(u, ns); - path_unit_notify(u, ns); - } - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - cgroup_bonding_trim_list(u->meta.cgroup_bondings, true); - - if (u->meta.job) { - unexpected = false; - - if (u->meta.job->state == JOB_WAITING) - - /* So we reached a different state for this - * job. Let's see if we can run it now if it - * failed previously due to EAGAIN. */ - job_add_to_run_queue(u->meta.job); - - /* Let's check whether this state change constitutes a - * finished job, or maybe contradicts a running job and - * hence needs to invalidate jobs. */ - - switch (u->meta.job->type) { - - case JOB_START: - case JOB_VERIFY_ACTIVE: - - if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) - job_finish_and_invalidate(u->meta.job, JOB_DONE); - else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { - unexpected = true; - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->meta.job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE); - } - - break; - - case JOB_RELOAD: - case JOB_RELOAD_OR_START: - - if (u->meta.job->state == JOB_RUNNING) { - if (ns == UNIT_ACTIVE) - job_finish_and_invalidate(u->meta.job, reload_success ? JOB_DONE : JOB_FAILED); - else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { - unexpected = true; - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->meta.job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE); - } - } - - break; - - case JOB_STOP: - case JOB_RESTART: - case JOB_TRY_RESTART: - - if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->meta.job, JOB_DONE); - else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { - unexpected = true; - job_finish_and_invalidate(u->meta.job, JOB_FAILED); - } - - break; - - default: - assert_not_reached("Job type unknown"); - } - - } else - unexpected = true; - - if (u->meta.manager->n_reloading <= 0) { - - /* If this state change happened without being - * requested by a job, then let's retroactively start - * or stop dependencies. We skip that step when - * deserializing, since we don't want to create any - * additional jobs just because something is already - * activated. */ - - if (unexpected) { - if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) - retroactively_start_dependencies(u); - else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) - retroactively_stop_dependencies(u); - } - - if (ns != os && ns == UNIT_FAILED) { - log_notice("Unit %s entered failed state.", u->meta.id); - unit_trigger_on_failure(u); - } - } - - /* Some names are special */ - if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) { - - if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) - /* The bus just might have become available, - * hence try to connect to it, if we aren't - * yet connected. */ - bus_init(u->meta.manager, true); - - if (u->meta.type == UNIT_SERVICE && - !UNIT_IS_ACTIVE_OR_RELOADING(os) && - u->meta.manager->n_reloading <= 0) { - /* Write audit record if we have just finished starting up */ - manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_START, true); - u->meta.in_audit = true; - } - - if (!UNIT_IS_ACTIVE_OR_RELOADING(os)) - manager_send_unit_plymouth(u->meta.manager, u); - - } else { - - /* We don't care about D-Bus here, since we'll get an - * asynchronous notification for it anyway. */ - - if (u->meta.type == UNIT_SERVICE && - UNIT_IS_INACTIVE_OR_FAILED(ns) && - !UNIT_IS_INACTIVE_OR_FAILED(os) && - u->meta.manager->n_reloading <= 0) { - - /* Hmm, if there was no start record written - * write it now, so that we always have a nice - * pair */ - if (!u->meta.in_audit) { - manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE); - - if (ns == UNIT_INACTIVE) - manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_STOP, true); - } else - /* Write audit record if we have just finished shutting down */ - manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE); - - u->meta.in_audit = false; - } - } - - manager_recheck_syslog(u->meta.manager); - - /* Maybe we finished startup and are now ready for being - * stopped because unneeded? */ - unit_check_unneeded(u); - - unit_add_to_dbus_queue(u); - unit_add_to_gc_queue(u); -} - -int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { - struct epoll_event ev; - - assert(u); - assert(fd >= 0); - assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u)); - - zero(ev); - ev.data.ptr = w; - ev.events = events; - - if (epoll_ctl(u->meta.manager->epoll_fd, - w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, - fd, - &ev) < 0) - return -errno; - - w->fd = fd; - w->type = WATCH_FD; - w->data.unit = u; - - return 0; -} - -void unit_unwatch_fd(Unit *u, Watch *w) { - assert(u); - assert(w); - - if (w->type == WATCH_INVALID) - return; - - assert(w->type == WATCH_FD); - assert(w->data.unit == u); - assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - - w->fd = -1; - w->type = WATCH_INVALID; - w->data.unit = NULL; -} - -int unit_watch_pid(Unit *u, pid_t pid) { - assert(u); - assert(pid >= 1); - - /* Watch a specific PID. We only support one unit watching - * each PID for now. */ - - return hashmap_put(u->meta.manager->watch_pids, LONG_TO_PTR(pid), u); -} - -void unit_unwatch_pid(Unit *u, pid_t pid) { - assert(u); - assert(pid >= 1); - - hashmap_remove_value(u->meta.manager->watch_pids, LONG_TO_PTR(pid), u); -} - -int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { - struct itimerspec its; - int flags, fd; - bool ours; - - assert(u); - assert(w); - assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u)); - - /* This will try to reuse the old timer if there is one */ - - if (w->type == WATCH_UNIT_TIMER) { - assert(w->data.unit == u); - assert(w->fd >= 0); - - ours = false; - fd = w->fd; - } else if (w->type == WATCH_INVALID) { - - ours = true; - if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) - return -errno; - } else - assert_not_reached("Invalid watch type"); - - zero(its); - - if (delay <= 0) { - /* Set absolute time in the past, but not 0, since we - * don't want to disarm the timer */ - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 1; - - flags = TFD_TIMER_ABSTIME; - } else { - timespec_store(&its.it_value, delay); - flags = 0; - } - - /* This will also flush the elapse counter */ - if (timerfd_settime(fd, flags, &its, NULL) < 0) - goto fail; - - if (w->type == WATCH_INVALID) { - struct epoll_event ev; - - zero(ev); - ev.data.ptr = w; - ev.events = EPOLLIN; - - if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) - goto fail; - } - - w->type = WATCH_UNIT_TIMER; - w->fd = fd; - w->data.unit = u; - - return 0; - -fail: - if (ours) - close_nointr_nofail(fd); - - return -errno; -} - -void unit_unwatch_timer(Unit *u, Watch *w) { - assert(u); - assert(w); - - if (w->type == WATCH_INVALID) - return; - - assert(w->type == WATCH_UNIT_TIMER); - assert(w->data.unit == u); - assert(w->fd >= 0); - - assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - close_nointr_nofail(w->fd); - - w->fd = -1; - w->type = WATCH_INVALID; - w->data.unit = NULL; -} - -bool unit_job_is_applicable(Unit *u, JobType j) { - assert(u); - assert(j >= 0 && j < _JOB_TYPE_MAX); - - switch (j) { - - case JOB_VERIFY_ACTIVE: - case JOB_START: - case JOB_STOP: - return true; - - case JOB_RESTART: - case JOB_TRY_RESTART: - return unit_can_start(u); - - case JOB_RELOAD: - return unit_can_reload(u); - - case JOB_RELOAD_OR_START: - return unit_can_reload(u) && unit_can_start(u); - - default: - assert_not_reached("Invalid job type"); - } -} - -int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) { - - static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = { - [UNIT_REQUIRES] = UNIT_REQUIRED_BY, - [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, - [UNIT_WANTS] = UNIT_WANTED_BY, - [UNIT_REQUISITE] = UNIT_REQUIRED_BY, - [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, - [UNIT_BIND_TO] = UNIT_BOUND_BY, - [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID, - [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID, - [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID, - [UNIT_BOUND_BY] = UNIT_BIND_TO, - [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY, - [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS, - [UNIT_BEFORE] = UNIT_AFTER, - [UNIT_AFTER] = UNIT_BEFORE, - [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID, - [UNIT_REFERENCES] = UNIT_REFERENCED_BY, - [UNIT_REFERENCED_BY] = UNIT_REFERENCES - }; - int r, q = 0, v = 0, w = 0; - - assert(u); - assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX); - assert(other); - - u = unit_follow_merge(u); - other = unit_follow_merge(other); - - /* We won't allow dependencies on ourselves. We will not - * consider them an error however. */ - if (u == other) - return 0; - - if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0) - return r; - - if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) - if ((r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0) - return r; - - if (add_reference) - if ((r = set_ensure_allocated(&u->meta.dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 || - (r = set_ensure_allocated(&other->meta.dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0) - return r; - - if ((q = set_put(u->meta.dependencies[d], other)) < 0) - return q; - - if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) - if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) { - r = v; - goto fail; - } - - if (add_reference) { - if ((w = set_put(u->meta.dependencies[UNIT_REFERENCES], other)) < 0) { - r = w; - goto fail; - } - - if ((r = set_put(other->meta.dependencies[UNIT_REFERENCED_BY], u)) < 0) - goto fail; - } - - unit_add_to_dbus_queue(u); - return 0; - -fail: - if (q > 0) - set_remove(u->meta.dependencies[d], other); - - if (v > 0) - set_remove(other->meta.dependencies[inverse_table[d]], u); - - if (w > 0) - set_remove(u->meta.dependencies[UNIT_REFERENCES], other); - - return r; -} - -int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) { - int r; - - assert(u); - - if ((r = unit_add_dependency(u, d, other, add_reference)) < 0) - return r; - - if ((r = unit_add_dependency(u, e, other, add_reference)) < 0) - return r; - - return 0; -} - -static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) { - char *s; - - assert(u); - assert(name || path); - - if (!name) - name = file_name_from_path(path); - - if (!unit_name_is_template(name)) { - *p = NULL; - return name; - } - - if (u->meta.instance) - s = unit_name_replace_instance(name, u->meta.instance); - else { - char *i; - - if (!(i = unit_name_to_prefix(u->meta.id))) - return NULL; - - s = unit_name_replace_instance(name, i); - free(i); - } - - if (!s) - return NULL; - - *p = s; - return s; -} - -int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { - Unit *other; - int r; - char *s; - - assert(u); - assert(name || path); - - if (!(name = resolve_template(u, name, path, &s))) - return -ENOMEM; - - if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) - goto finish; - - r = unit_add_dependency(u, d, other, add_reference); - -finish: - free(s); - return r; -} - -int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { - Unit *other; - int r; - char *s; - - assert(u); - assert(name || path); - - if (!(name = resolve_template(u, name, path, &s))) - return -ENOMEM; - - if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) - goto finish; - - r = unit_add_two_dependencies(u, d, e, other, add_reference); - -finish: - free(s); - return r; -} - -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { - Unit *other; - int r; - char *s; - - assert(u); - assert(name || path); - - if (!(name = resolve_template(u, name, path, &s))) - return -ENOMEM; - - if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) - goto finish; - - r = unit_add_dependency(other, d, u, add_reference); - -finish: - free(s); - return r; -} - -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { - Unit *other; - int r; - char *s; - - assert(u); - assert(name || path); - - if (!(name = resolve_template(u, name, path, &s))) - return -ENOMEM; - - if ((r = manager_load_unit(u->meta.manager, name, path, NULL, &other)) < 0) - goto finish; - - if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0) - goto finish; - -finish: - free(s); - return r; -} - -int set_unit_path(const char *p) { - char *cwd, *c; - int r; - - /* This is mostly for debug purposes */ - - if (path_is_absolute(p)) { - if (!(c = strdup(p))) - return -ENOMEM; - } else { - if (!(cwd = get_current_dir_name())) - return -errno; - - r = asprintf(&c, "%s/%s", cwd, p); - free(cwd); - - if (r < 0) - return -ENOMEM; - } - - if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) { - r = -errno; - free(c); - return r; - } - - return 0; -} - -char *unit_dbus_path(Unit *u) { - char *p, *e; - - assert(u); - - if (!u->meta.id) - return NULL; - - if (!(e = bus_path_escape(u->meta.id))) - return NULL; - - p = strappend("/org/freedesktop/systemd1/unit/", e); - free(e); - - return p; -} - -int unit_add_cgroup(Unit *u, CGroupBonding *b) { - int r; - - assert(u); - assert(b); - - assert(b->path); - - if (!b->controller) { - if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER))) - return -ENOMEM; - - b->ours = true; - } - - /* Ensure this hasn't been added yet */ - assert(!b->unit); - - if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) { - CGroupBonding *l; - - l = hashmap_get(u->meta.manager->cgroup_bondings, b->path); - LIST_PREPEND(CGroupBonding, by_path, l, b); - - if ((r = hashmap_replace(u->meta.manager->cgroup_bondings, b->path, l)) < 0) { - LIST_REMOVE(CGroupBonding, by_path, l, b); - return r; - } - } - - LIST_PREPEND(CGroupBonding, by_unit, u->meta.cgroup_bondings, b); - b->unit = u; - - return 0; -} - -static char *default_cgroup_path(Unit *u) { - char *p; - - assert(u); - - if (u->meta.instance) { - char *t; - - t = unit_name_template(u->meta.id); - if (!t) - return NULL; - - p = join(u->meta.manager->cgroup_hierarchy, "/", t, "/", u->meta.instance, NULL); - free(t); - } else - p = join(u->meta.manager->cgroup_hierarchy, "/", u->meta.id, NULL); - - return p; -} - -int unit_add_cgroup_from_text(Unit *u, const char *name) { - char *controller = NULL, *path = NULL; - CGroupBonding *b = NULL; - bool ours = false; - int r; - - assert(u); - assert(name); - - if ((r = cg_split_spec(name, &controller, &path)) < 0) - return r; - - if (!path) { - path = default_cgroup_path(u); - ours = true; - } - - if (!controller) { - controller = strdup(SYSTEMD_CGROUP_CONTROLLER); - ours = true; - } - - if (!path || !controller) { - free(path); - free(controller); - - return -ENOMEM; - } - - if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) { - r = -EEXIST; - goto fail; - } - - if (!(b = new0(CGroupBonding, 1))) { - r = -ENOMEM; - goto fail; - } - - b->controller = controller; - b->path = path; - b->ours = ours; - b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER); - - if ((r = unit_add_cgroup(u, b)) < 0) - goto fail; - - return 0; - -fail: - free(path); - free(controller); - free(b); - - return r; -} - -static int unit_add_one_default_cgroup(Unit *u, const char *controller) { - CGroupBonding *b = NULL; - int r = -ENOMEM; - - assert(u); - - if (!controller) - controller = SYSTEMD_CGROUP_CONTROLLER; - - if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) - return 0; - - if (!(b = new0(CGroupBonding, 1))) - return -ENOMEM; - - if (!(b->controller = strdup(controller))) - goto fail; - - if (!(b->path = default_cgroup_path(u))) - goto fail; - - b->ours = true; - b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER); - - if ((r = unit_add_cgroup(u, b)) < 0) - goto fail; - - return 0; - -fail: - free(b->path); - free(b->controller); - free(b); - - return r; -} - -int unit_add_default_cgroups(Unit *u) { - CGroupAttribute *a; - char **c; - int r; - - assert(u); - - /* Adds in the default cgroups, if they weren't specified - * otherwise. */ - - if (!u->meta.manager->cgroup_hierarchy) - return 0; - - if ((r = unit_add_one_default_cgroup(u, NULL)) < 0) - return r; - - STRV_FOREACH(c, u->meta.manager->default_controllers) - unit_add_one_default_cgroup(u, *c); - - LIST_FOREACH(by_unit, a, u->meta.cgroup_attributes) - unit_add_one_default_cgroup(u, a->controller); - - return 0; -} - -CGroupBonding* unit_get_default_cgroup(Unit *u) { - assert(u); - - return cgroup_bonding_find_list(u->meta.cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER); -} - -int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) { - int r; - char *c = NULL; - CGroupAttribute *a; - - assert(u); - assert(name); - assert(value); - - if (!controller) { - const char *dot; - - dot = strchr(name, '.'); - if (!dot) - return -EINVAL; - - c = strndup(name, dot - name); - if (!c) - return -ENOMEM; - - controller = c; - } - - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { - r = -EINVAL; - goto finish; - } - - a = new0(CGroupAttribute, 1); - if (!a) { - r = -ENOMEM; - goto finish; - } - - if (c) { - a->controller = c; - c = NULL; - } else - a->controller = strdup(controller); - - a->name = strdup(name); - a->value = strdup(value); - - if (!a->controller || !a->name || !a->value) { - free(a->controller); - free(a->name); - free(a->value); - free(a); - - return -ENOMEM; - } - - a->map_callback = map_callback; - - LIST_PREPEND(CGroupAttribute, by_unit, u->meta.cgroup_attributes, a); - - r = 0; - -finish: - free(c); - return r; -} - -int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { - char *t; - int r; - - assert(u); - assert(type); - assert(_found); - - if (!(t = unit_name_change_suffix(u->meta.id, type))) - return -ENOMEM; - - assert(!unit_has_name(u, t)); - - r = manager_load_unit(u->meta.manager, t, NULL, NULL, _found); - free(t); - - assert(r < 0 || *_found != u); - - return r; -} - -int unit_get_related_unit(Unit *u, const char *type, Unit **_found) { - Unit *found; - char *t; - - assert(u); - assert(type); - assert(_found); - - if (!(t = unit_name_change_suffix(u->meta.id, type))) - return -ENOMEM; - - assert(!unit_has_name(u, t)); - - found = manager_get_unit(u->meta.manager, t); - free(t); - - if (!found) - return -ENOENT; - - *_found = found; - return 0; -} - -static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return unit_name_to_prefix_and_instance(u->meta.id); -} - -static char *specifier_prefix(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return unit_name_to_prefix(u->meta.id); -} - -static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) { - Unit *u = userdata; - char *p, *r; - - assert(u); - - if (!(p = unit_name_to_prefix(u->meta.id))) - return NULL; - - r = unit_name_unescape(p); - free(p); - - return r; -} - -static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->meta.instance) - return unit_name_unescape(u->meta.instance); - - return strdup(""); -} - -static char *specifier_filename(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->meta.instance) - return unit_name_path_unescape(u->meta.instance); - - return unit_name_to_path(u->meta.instance); -} - -static char *specifier_cgroup(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return default_cgroup_path(u); -} - -static char *specifier_cgroup_root(char specifier, void *data, void *userdata) { - Unit *u = userdata; - char *p; - assert(u); - - if (specifier == 'r') - return strdup(u->meta.manager->cgroup_hierarchy); - - if (parent_of_path(u->meta.manager->cgroup_hierarchy, &p) < 0) - return strdup(""); - - if (streq(p, "/")) { - free(p); - return strdup(""); - } - - return p; -} - -static char *specifier_runtime(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->meta.manager->running_as == MANAGER_USER) { - const char *e; - - e = getenv("XDG_RUNTIME_DIR"); - if (e) - return strdup(e); - } - - return strdup("/run"); -} - -char *unit_name_printf(Unit *u, const char* format) { - - /* - * This will use the passed string as format string and - * replace the following specifiers: - * - * %n: the full id of the unit (foo@bar.waldo) - * %N: the id of the unit without the suffix (foo@bar) - * %p: the prefix (foo) - * %i: the instance (bar) - */ - - const Specifier table[] = { - { 'n', specifier_string, u->meta.id }, - { 'N', specifier_prefix_and_instance, NULL }, - { 'p', specifier_prefix, NULL }, - { 'i', specifier_string, u->meta.instance }, - { 0, NULL, NULL } - }; - - assert(u); - assert(format); - - return specifier_printf(format, table, u); -} - -char *unit_full_printf(Unit *u, const char *format) { - - /* This is similar to unit_name_printf() but also supports - * unescaping. Also, adds a couple of additional codes: - * - * %c cgroup path of unit - * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711") - * %R parent of root cgroup path (e.g. "/usr/lennart/shared") - * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) - */ - - const Specifier table[] = { - { 'n', specifier_string, u->meta.id }, - { 'N', specifier_prefix_and_instance, NULL }, - { 'p', specifier_prefix, NULL }, - { 'P', specifier_prefix_unescaped, NULL }, - { 'i', specifier_string, u->meta.instance }, - { 'I', specifier_instance_unescaped, NULL }, - { 'f', specifier_filename, NULL }, - { 'c', specifier_cgroup, NULL }, - { 'r', specifier_cgroup_root, NULL }, - { 'R', specifier_cgroup_root, NULL }, - { 't', specifier_runtime, NULL }, - { 0, NULL, NULL } - }; - - assert(u); - assert(format); - - return specifier_printf(format, table, u); -} - -char **unit_full_printf_strv(Unit *u, char **l) { - size_t n; - char **r, **i, **j; - - /* Applies unit_full_printf to every entry in l */ - - assert(u); - - n = strv_length(l); - if (!(r = new(char*, n+1))) - return NULL; - - for (i = l, j = r; *i; i++, j++) - if (!(*j = unit_full_printf(u, *i))) - goto fail; - - *j = NULL; - return r; - -fail: - for (j--; j >= r; j--) - free(*j); - - free(r); - - return NULL; -} - -int unit_watch_bus_name(Unit *u, const char *name) { - assert(u); - assert(name); - - /* Watch a specific name on the bus. We only support one unit - * watching each name for now. */ - - return hashmap_put(u->meta.manager->watch_bus, name, u); -} - -void unit_unwatch_bus_name(Unit *u, const char *name) { - assert(u); - assert(name); - - hashmap_remove_value(u->meta.manager->watch_bus, name, u); -} - -bool unit_can_serialize(Unit *u) { - assert(u); - - return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; -} - -int unit_serialize(Unit *u, FILE *f, FDSet *fds) { - int r; - - assert(u); - assert(f); - assert(fds); - - if (!unit_can_serialize(u)) - return 0; - - if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0) - return r; - - if (u->meta.job) - unit_serialize_item(u, f, "job", job_type_to_string(u->meta.job->type)); - - dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->meta.inactive_exit_timestamp); - dual_timestamp_serialize(f, "active-enter-timestamp", &u->meta.active_enter_timestamp); - dual_timestamp_serialize(f, "active-exit-timestamp", &u->meta.active_exit_timestamp); - dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->meta.inactive_enter_timestamp); - dual_timestamp_serialize(f, "condition-timestamp", &u->meta.condition_timestamp); - - if (dual_timestamp_is_set(&u->meta.condition_timestamp)) - unit_serialize_item(u, f, "condition-result", yes_no(u->meta.condition_result)); - - /* End marker */ - fputc('\n', f); - return 0; -} - -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { - va_list ap; - - assert(u); - assert(f); - assert(key); - assert(format); - - fputs(key, f); - fputc('=', f); - - va_start(ap, format); - vfprintf(f, format, ap); - va_end(ap); - - fputc('\n', f); -} - -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { - assert(u); - assert(f); - assert(key); - assert(value); - - fprintf(f, "%s=%s\n", key, value); -} - -int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { - int r; - - assert(u); - assert(f); - assert(fds); - - if (!unit_can_serialize(u)) - return 0; - - for (;;) { - char line[LINE_MAX], *l, *v; - size_t k; - - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - return 0; - return -errno; - } - - char_array_0(line); - l = strstrip(line); - - /* End marker */ - if (l[0] == 0) - return 0; - - k = strcspn(l, "="); - - if (l[k] == '=') { - l[k] = 0; - v = l+k+1; - } else - v = l+k; - - if (streq(l, "job")) { - JobType type; - - if ((type = job_type_from_string(v)) < 0) - log_debug("Failed to parse job type value %s", v); - else - u->meta.deserialized_job = type; - - continue; - } else if (streq(l, "inactive-exit-timestamp")) { - dual_timestamp_deserialize(v, &u->meta.inactive_exit_timestamp); - continue; - } else if (streq(l, "active-enter-timestamp")) { - dual_timestamp_deserialize(v, &u->meta.active_enter_timestamp); - continue; - } else if (streq(l, "active-exit-timestamp")) { - dual_timestamp_deserialize(v, &u->meta.active_exit_timestamp); - continue; - } else if (streq(l, "inactive-enter-timestamp")) { - dual_timestamp_deserialize(v, &u->meta.inactive_enter_timestamp); - continue; - } else if (streq(l, "condition-timestamp")) { - dual_timestamp_deserialize(v, &u->meta.condition_timestamp); - continue; - } else if (streq(l, "condition-result")) { - int b; - - if ((b = parse_boolean(v)) < 0) - log_debug("Failed to parse condition result value %s", v); - else - u->meta.condition_result = b; - - continue; - } - - if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0) - return r; - } -} - -int unit_add_node_link(Unit *u, const char *what, bool wants) { - Unit *device; - char *e; - int r; - - assert(u); - - if (!what) - return 0; - - /* Adds in links to the device node that this unit is based on */ - - if (!is_device_path(what)) - return 0; - - if (!(e = unit_name_build_escape(what+1, NULL, ".device"))) - return -ENOMEM; - - r = manager_load_unit(u->meta.manager, e, NULL, NULL, &device); - free(e); - - if (r < 0) - return r; - - if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BIND_TO, device, true)) < 0) - return r; - - if (wants) - if ((r = unit_add_dependency(device, UNIT_WANTS, u, false)) < 0) - return r; - - return 0; -} - -int unit_coldplug(Unit *u) { - int r; - - assert(u); - - if (UNIT_VTABLE(u)->coldplug) - if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) - return r; - - if (u->meta.deserialized_job >= 0) { - if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0) - return r; - - u->meta.deserialized_job = _JOB_TYPE_INVALID; - } - - return 0; -} - -void unit_status_printf(Unit *u, const char *format, ...) { - va_list ap; - - assert(u); - assert(format); - - if (!UNIT_VTABLE(u)->show_status) - return; - - if (!manager_get_show_status(u->meta.manager)) - return; - - if (!manager_is_booting_or_shutting_down(u->meta.manager)) - return; - - va_start(ap, format); - status_vprintf(format, ap); - va_end(ap); -} - -bool unit_need_daemon_reload(Unit *u) { - assert(u); - - if (u->meta.fragment_path) { - struct stat st; - - zero(st); - if (stat(u->meta.fragment_path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (u->meta.fragment_mtime > 0 && - timespec_load(&st.st_mtim) != u->meta.fragment_mtime) - return true; - } - - if (UNIT_VTABLE(u)->need_daemon_reload) - return UNIT_VTABLE(u)->need_daemon_reload(u); - - return false; -} - -void unit_reset_failed(Unit *u) { - assert(u); - - if (UNIT_VTABLE(u)->reset_failed) - UNIT_VTABLE(u)->reset_failed(u); -} - -Unit *unit_following(Unit *u) { - assert(u); - - if (UNIT_VTABLE(u)->following) - return UNIT_VTABLE(u)->following(u); - - return NULL; -} - -bool unit_pending_inactive(Unit *u) { - assert(u); - - /* Returns true if the unit is inactive or going down */ - - if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))) - return true; - - if (u->meta.job && u->meta.job->type == JOB_STOP) - return true; - - return false; -} - -bool unit_pending_active(Unit *u) { - assert(u); - - /* Returns true if the unit is inactive or going down */ - - if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) - return true; - - if (u->meta.job && - (u->meta.job->type == JOB_START || - u->meta.job->type == JOB_RELOAD_OR_START || - u->meta.job->type == JOB_RESTART)) - return true; - - return false; -} - -UnitType unit_name_to_type(const char *n) { - UnitType t; - - assert(n); - - for (t = 0; t < _UNIT_TYPE_MAX; t++) - if (endswith(n, unit_vtable[t]->suffix)) - return t; - - return _UNIT_TYPE_INVALID; -} - -bool unit_name_is_valid(const char *n, bool template_ok) { - UnitType t; - - t = unit_name_to_type(n); - if (t < 0 || t >= _UNIT_TYPE_MAX) - return false; - - return unit_name_is_valid_no_type(n, template_ok); -} - -int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error) { - assert(u); - assert(w >= 0 && w < _KILL_WHO_MAX); - assert(m >= 0 && m < _KILL_MODE_MAX); - assert(signo > 0); - assert(signo < _NSIG); - - if (m == KILL_NONE) - return 0; - - if (!UNIT_VTABLE(u)->kill) - return -ENOTSUP; - - return UNIT_VTABLE(u)->kill(u, w, m, signo, error); -} - -int unit_following_set(Unit *u, Set **s) { - assert(u); - assert(s); - - if (UNIT_VTABLE(u)->following_set) - return UNIT_VTABLE(u)->following_set(u, s); - - *s = NULL; - return 0; -} - -UnitFileState unit_get_unit_file_state(Unit *u) { - assert(u); - - if (u->meta.unit_file_state < 0 && u->meta.fragment_path) - u->meta.unit_file_state = unit_file_get_state( - u->meta.manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, - NULL, file_name_from_path(u->meta.fragment_path)); - - return u->meta.unit_file_state; -} - -static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { - [UNIT_STUB] = "stub", - [UNIT_LOADED] = "loaded", - [UNIT_ERROR] = "error", - [UNIT_MERGED] = "merged", - [UNIT_MASKED] = "masked" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); - -static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { - [UNIT_ACTIVE] = "active", - [UNIT_RELOADING] = "reloading", - [UNIT_INACTIVE] = "inactive", - [UNIT_FAILED] = "failed", - [UNIT_ACTIVATING] = "activating", - [UNIT_DEACTIVATING] = "deactivating" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); - -static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { - [UNIT_REQUIRES] = "Requires", - [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", - [UNIT_WANTS] = "Wants", - [UNIT_REQUISITE] = "Requisite", - [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable", - [UNIT_REQUIRED_BY] = "RequiredBy", - [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", - [UNIT_BIND_TO] = "BindTo", - [UNIT_WANTED_BY] = "WantedBy", - [UNIT_CONFLICTS] = "Conflicts", - [UNIT_CONFLICTED_BY] = "ConflictedBy", - [UNIT_BOUND_BY] = "BoundBy", - [UNIT_BEFORE] = "Before", - [UNIT_AFTER] = "After", - [UNIT_REFERENCES] = "References", - [UNIT_REFERENCED_BY] = "ReferencedBy", - [UNIT_ON_FAILURE] = "OnFailure" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); diff --git a/src/unit.h b/src/unit.h deleted file mode 100644 index 7da5723..0000000 --- a/src/unit.h +++ /dev/null @@ -1,548 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foounithfoo -#define foounithfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include - -typedef union Unit Unit; -typedef struct Meta Meta; -typedef struct UnitVTable UnitVTable; -typedef enum UnitType UnitType; -typedef enum UnitLoadState UnitLoadState; -typedef enum UnitActiveState UnitActiveState; -typedef enum UnitDependency UnitDependency; - -#include "set.h" -#include "util.h" -#include "list.h" -#include "socket-util.h" -#include "execute.h" -#include "condition.h" -#include "install.h" - -enum UnitType { - UNIT_SERVICE = 0, - UNIT_SOCKET, - UNIT_TARGET, - UNIT_DEVICE, - UNIT_MOUNT, - UNIT_AUTOMOUNT, - UNIT_SNAPSHOT, - UNIT_TIMER, - UNIT_SWAP, - UNIT_PATH, - _UNIT_TYPE_MAX, - _UNIT_TYPE_INVALID = -1 -}; - -enum UnitLoadState { - UNIT_STUB, - UNIT_LOADED, - UNIT_ERROR, - UNIT_MERGED, - UNIT_MASKED, - _UNIT_LOAD_STATE_MAX, - _UNIT_LOAD_STATE_INVALID = -1 -}; - -enum UnitActiveState { - UNIT_ACTIVE, - UNIT_RELOADING, - UNIT_INACTIVE, - UNIT_FAILED, - UNIT_ACTIVATING, - UNIT_DEACTIVATING, - _UNIT_ACTIVE_STATE_MAX, - _UNIT_ACTIVE_STATE_INVALID = -1 -}; - -static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) { - return t == UNIT_ACTIVE || t == UNIT_RELOADING; -} - -static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) { - return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING; -} - -static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) { - return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING; -} - -static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) { - return t == UNIT_INACTIVE || t == UNIT_FAILED; -} - -enum UnitDependency { - /* Positive dependencies */ - UNIT_REQUIRES, - UNIT_REQUIRES_OVERRIDABLE, - UNIT_REQUISITE, - UNIT_REQUISITE_OVERRIDABLE, - UNIT_WANTS, - UNIT_BIND_TO, - - /* Inverse of the above */ - UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ - UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ - UNIT_WANTED_BY, /* inverse of 'wants' */ - UNIT_BOUND_BY, /* inverse of 'bind_to' */ - - /* Negative dependencies */ - UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ - UNIT_CONFLICTED_BY, - - /* Order */ - UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */ - UNIT_AFTER, - - /* On Failure */ - UNIT_ON_FAILURE, - - /* Reference information for GC logic */ - UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ - UNIT_REFERENCED_BY, - - _UNIT_DEPENDENCY_MAX, - _UNIT_DEPENDENCY_INVALID = -1 -}; - -#include "manager.h" -#include "job.h" -#include "cgroup.h" -#include "cgroup-attr.h" - -struct Meta { - Manager *manager; - - UnitType type; - UnitLoadState load_state; - Unit *merged_into; - - char *id; /* One name is special because we use it for identification. Points to an entry in the names set */ - char *instance; - - Set *names; - Set *dependencies[_UNIT_DEPENDENCY_MAX]; - - char *description; - - char *fragment_path; /* if loaded from a config file this is the primary path to it */ - usec_t fragment_mtime; - - /* If there is something to do with this unit, then this is - * the job for it */ - Job *job; - - usec_t job_timeout; - - /* Conditions to check */ - LIST_HEAD(Condition, conditions); - - dual_timestamp condition_timestamp; - - dual_timestamp inactive_exit_timestamp; - dual_timestamp active_enter_timestamp; - dual_timestamp active_exit_timestamp; - dual_timestamp inactive_enter_timestamp; - - /* Counterparts in the cgroup filesystem */ - CGroupBonding *cgroup_bondings; - CGroupAttribute *cgroup_attributes; - - /* Per type list */ - LIST_FIELDS(Meta, units_by_type); - - /* Load queue */ - LIST_FIELDS(Meta, load_queue); - - /* D-Bus queue */ - LIST_FIELDS(Meta, dbus_queue); - - /* Cleanup queue */ - LIST_FIELDS(Meta, cleanup_queue); - - /* GC queue */ - LIST_FIELDS(Meta, gc_queue); - - /* Used during GC sweeps */ - unsigned gc_marker; - - /* When deserializing, temporarily store the job type for this - * unit here, if there was a job scheduled */ - int deserialized_job; /* This is actually of type JobType */ - - /* Error code when we didn't manage to load the unit (negative) */ - int load_error; - - /* Cached unit file state */ - UnitFileState unit_file_state; - - /* Garbage collect us we nobody wants or requires us anymore */ - bool stop_when_unneeded; - - /* Create default dependencies */ - bool default_dependencies; - - /* Refuse manual starting, allow starting only indirectly via dependency. */ - bool refuse_manual_start; - - /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */ - bool refuse_manual_stop; - - /* Allow isolation requests */ - bool allow_isolate; - - /* Isolate OnFailure unit */ - bool on_failure_isolate; - - /* Ignore this unit when isolating */ - bool ignore_on_isolate; - - /* Ignore this unit when snapshotting */ - bool ignore_on_snapshot; - - /* Did the last condition check suceed? */ - bool condition_result; - - bool in_load_queue:1; - bool in_dbus_queue:1; - bool in_cleanup_queue:1; - bool in_gc_queue:1; - - bool sent_dbus_new_signal:1; - - bool no_gc:1; - - bool in_audit:1; -}; - -#include "service.h" -#include "timer.h" -#include "socket.h" -#include "target.h" -#include "device.h" -#include "mount.h" -#include "automount.h" -#include "snapshot.h" -#include "swap.h" -#include "path.h" - -union Unit { - Meta meta; - Service service; - Timer timer; - Socket socket; - Target target; - Device device; - Mount mount; - Automount automount; - Snapshot snapshot; - Swap swap; - Path path; -}; - -struct UnitVTable { - const char *suffix; - - /* Config file sections this unit type understands, separated - * by NUL chars */ - const char *sections; - - /* This should reset all type-specific variables. This should - * not allocate memory, and is called with zero-initialized - * data. It should hence only initialize variables that need - * to be set != 0. */ - void (*init)(Unit *u); - - /* This should free all type-specific variables. It should be - * idempotent. */ - void (*done)(Unit *u); - - /* Actually load data from disk. This may fail, and should set - * load_state to UNIT_LOADED, UNIT_MERGED or leave it at - * UNIT_STUB if no configuration could be found. */ - int (*load)(Unit *u); - - /* If a a lot of units got created via enumerate(), this is - * where to actually set the state and call unit_notify(). */ - int (*coldplug)(Unit *u); - - void (*dump)(Unit *u, FILE *f, const char *prefix); - - int (*start)(Unit *u); - int (*stop)(Unit *u); - int (*reload)(Unit *u); - - int (*kill)(Unit *u, KillWho w, KillMode m, int signo, DBusError *error); - - bool (*can_reload)(Unit *u); - - /* Write all data that cannot be restored from other sources - * away using unit_serialize_item() */ - int (*serialize)(Unit *u, FILE *f, FDSet *fds); - - /* Restore one item from the serialization */ - int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds); - - /* Boils down the more complex internal state of this unit to - * a simpler one that the engine can understand */ - UnitActiveState (*active_state)(Unit *u); - - /* Returns the substate specific to this unit type as - * string. This is purely information so that we can give the - * user a more fine grained explanation in which actual state a - * unit is in. */ - const char* (*sub_state_to_string)(Unit *u); - - /* Return true when there is reason to keep this entry around - * even nothing references it and it isn't active in any - * way */ - bool (*check_gc)(Unit *u); - - /* Return true when this unit is suitable for snapshotting */ - bool (*check_snapshot)(Unit *u); - - void (*fd_event)(Unit *u, int fd, uint32_t events, Watch *w); - void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); - void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w); - - /* Check whether unit needs a daemon reload */ - bool (*need_daemon_reload)(Unit *u); - - /* Reset failed state if we are in failed state */ - void (*reset_failed)(Unit *u); - - /* Called whenever any of the cgroups this unit watches for - * ran empty */ - void (*cgroup_notify_empty)(Unit *u); - - /* Called whenever a process of this unit sends us a message */ - void (*notify_message)(Unit *u, pid_t pid, char **tags); - - /* Called whenever a name thus Unit registered for comes or - * goes away. */ - void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner); - - /* Called whenever a bus PID lookup finishes */ - void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid); - - /* Called for each message received on the bus */ - DBusHandlerResult (*bus_message_handler)(Unit *u, DBusConnection *c, DBusMessage *message); - - /* Return the unit this unit is following */ - Unit *(*following)(Unit *u); - - /* Return the set of units that are following each other */ - int (*following_set)(Unit *u, Set **s); - - /* This is called for each unit type and should be used to - * enumerate existing devices and load them. However, - * everything that is loaded here should still stay in - * inactive state. It is the job of the coldplug() call above - * to put the units into the initial state. */ - int (*enumerate)(Manager *m); - - /* Type specific cleanups. */ - void (*shutdown)(Manager *m); - - /* When sending out PropertiesChanged signal, which properties - * shall be invalidated? This is a NUL separated list of - * strings, to minimize relocations a little. */ - const char *bus_invalidating_properties; - - /* The interface name */ - const char *bus_interface; - - /* Can units of this type have multiple names? */ - bool no_alias:1; - - /* Instances make no sense for this type */ - bool no_instances:1; - - /* Exclude from automatic gc */ - bool no_gc:1; - - /* Show status updates on the console */ - bool show_status:1; -}; - -extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX]; - -#define UNIT_VTABLE(u) unit_vtable[(u)->meta.type] - -/* For casting a unit into the various unit types */ -#define DEFINE_CAST(UPPERCASE, MixedCase) \ - static inline MixedCase* UPPERCASE(Unit *u) { \ - if (_unlikely_(!u || u->meta.type != UNIT_##UPPERCASE)) \ - return NULL; \ - \ - return (MixedCase*) u; \ - } - -/* For casting the various unit types into a unit */ -#define UNIT(u) ((Unit*) (&(u)->meta)) - -DEFINE_CAST(SOCKET, Socket); -DEFINE_CAST(TIMER, Timer); -DEFINE_CAST(SERVICE, Service); -DEFINE_CAST(TARGET, Target); -DEFINE_CAST(DEVICE, Device); -DEFINE_CAST(MOUNT, Mount); -DEFINE_CAST(AUTOMOUNT, Automount); -DEFINE_CAST(SNAPSHOT, Snapshot); -DEFINE_CAST(SWAP, Swap); -DEFINE_CAST(PATH, Path); - -Unit *unit_new(Manager *m); -void unit_free(Unit *u); - -int unit_add_name(Unit *u, const char *name); - -int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference); -int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference); - -int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); -int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); - -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); - -int unit_add_exec_dependencies(Unit *u, ExecContext *c); - -int unit_add_cgroup(Unit *u, CGroupBonding *b); -int unit_add_cgroup_from_text(Unit *u, const char *name); -int unit_add_default_cgroups(Unit *u); -CGroupBonding* unit_get_default_cgroup(Unit *u); -int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback); - -int unit_choose_id(Unit *u, const char *name); -int unit_set_description(Unit *u, const char *description); - -bool unit_check_gc(Unit *u); - -void unit_add_to_load_queue(Unit *u); -void unit_add_to_dbus_queue(Unit *u); -void unit_add_to_cleanup_queue(Unit *u); -void unit_add_to_gc_queue(Unit *u); - -int unit_merge(Unit *u, Unit *other); -int unit_merge_by_name(Unit *u, const char *other); - -Unit *unit_follow_merge(Unit *u); - -int unit_load_fragment_and_dropin(Unit *u); -int unit_load_fragment_and_dropin_optional(Unit *u); -int unit_load(Unit *unit); - -const char *unit_description(Unit *u); - -bool unit_has_name(Unit *u, const char *name); - -UnitActiveState unit_active_state(Unit *u); - -const char* unit_sub_state_to_string(Unit *u); - -void unit_dump(Unit *u, FILE *f, const char *prefix); - -bool unit_can_reload(Unit *u); -bool unit_can_start(Unit *u); -bool unit_can_isolate(Unit *u); - -int unit_start(Unit *u); -int unit_stop(Unit *u); -int unit_reload(Unit *u); - -int unit_kill(Unit *u, KillWho w, KillMode m, int signo, DBusError *error); - -void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success); - -int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w); -void unit_unwatch_fd(Unit *u, Watch *w); - -int unit_watch_pid(Unit *u, pid_t pid); -void unit_unwatch_pid(Unit *u, pid_t pid); - -int unit_watch_timer(Unit *u, usec_t delay, Watch *w); -void unit_unwatch_timer(Unit *u, Watch *w); - -int unit_watch_bus_name(Unit *u, const char *name); -void unit_unwatch_bus_name(Unit *u, const char *name); - -bool unit_job_is_applicable(Unit *u, JobType j); - -int set_unit_path(const char *p); - -char *unit_dbus_path(Unit *u); - -int unit_load_related_unit(Unit *u, const char *type, Unit **_found); -int unit_get_related_unit(Unit *u, const char *type, Unit **_found); - -char *unit_name_printf(Unit *u, const char* text); -char *unit_full_printf(Unit *u, const char *text); -char **unit_full_printf_strv(Unit *u, char **l); - -bool unit_can_serialize(Unit *u); -int unit_serialize(Unit *u, FILE *f, FDSet *fds); -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5); -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); -int unit_deserialize(Unit *u, FILE *f, FDSet *fds); - -int unit_add_node_link(Unit *u, const char *what, bool wants); - -int unit_coldplug(Unit *u); - -void unit_status_printf(Unit *u, const char *format, ...); - -bool unit_need_daemon_reload(Unit *u); - -void unit_reset_failed(Unit *u); - -Unit *unit_following(Unit *u); - -bool unit_pending_inactive(Unit *u); -bool unit_pending_active(Unit *u); - -int unit_add_default_target_dependency(Unit *u, Unit *target); - -int unit_following_set(Unit *u, Set **s); - -UnitType unit_name_to_type(const char *n); -bool unit_name_is_valid(const char *n, bool template_ok); - -void unit_trigger_on_failure(Unit *u); - -bool unit_condition_test(Unit *u); - -UnitFileState unit_get_unit_file_state(Unit *u); - -const char *unit_load_state_to_string(UnitLoadState i); -UnitLoadState unit_load_state_from_string(const char *s); - -const char *unit_active_state_to_string(UnitActiveState i); -UnitActiveState unit_active_state_from_string(const char *s); - -const char *unit_dependency_to_string(UnitDependency i); -UnitDependency unit_dependency_from_string(const char *s); - -#endif diff --git a/src/update-utmp.c b/src/update-utmp.c deleted file mode 100644 index f81e7f4..0000000 --- a/src/update-utmp.c +++ /dev/null @@ -1,420 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_AUDIT -#include -#endif - -#include "log.h" -#include "macro.h" -#include "util.h" -#include "special.h" -#include "utmp-wtmp.h" -#include "dbus-common.h" - -typedef struct Context { - DBusConnection *bus; -#ifdef HAVE_AUDIT - int audit_fd; -#endif -} Context; - -static usec_t get_startup_time(Context *c) { - const char - *interface = "org.freedesktop.systemd1.Manager", - *property = "StartupTimestamp"; - - DBusError error; - usec_t t = 0; - DBusMessage *m = NULL, *reply = NULL; - DBusMessageIter iter, sub; - - dbus_error_init(&error); - - assert(c); - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.DBus.Properties", - "Get"))) { - log_error("Could not allocate message."); - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) { - log_error("Failed to send command: %s", bus_error_message(&error)); - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT64) { - log_error("Failed to parse reply."); - goto finish; - } - - dbus_message_iter_get_basic(&sub, &t); - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return t; -} - -static int get_current_runlevel(Context *c) { - static const struct { - const int runlevel; - const char *special; - } table[] = { - /* The first target of this list that is active or has - * a job scheduled wins. We prefer runlevels 5 and 3 - * here over the others, since these are the main - * runlevels used on Fedora. It might make sense to - * change the order on some distributions. */ - { '5', SPECIAL_RUNLEVEL5_TARGET }, - { '3', SPECIAL_RUNLEVEL3_TARGET }, - { '4', SPECIAL_RUNLEVEL4_TARGET }, - { '2', SPECIAL_RUNLEVEL2_TARGET }, - { 'S', SPECIAL_RESCUE_TARGET }, - }; - const char - *interface = "org.freedesktop.systemd1.Unit", - *property = "ActiveState"; - - DBusMessage *m = NULL, *reply = NULL; - int r = 0; - unsigned i; - DBusError error; - - assert(c); - - dbus_error_init(&error); - - for (i = 0; i < ELEMENTSOF(table); i++) { - const char *path = NULL, *state; - DBusMessageIter iter, sub; - - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &table[i].special, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) { - dbus_error_free(&error); - continue; - } - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "Get"))) { - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) { - log_error("Failed to send command: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter, &sub); - - if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { - log_error("Failed to parse reply."); - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&sub, &state); - - if (streq(state, "active") || streq(state, "reloading")) - r = table[i].runlevel; - - dbus_message_unref(m); - dbus_message_unref(reply); - m = reply = NULL; - - if (r) - break; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return r; -} - -static int on_reboot(Context *c) { - int r = 0, q; - usec_t t; - - assert(c); - - /* We finished start-up, so let's write the utmp - * record and send the audit msg */ - -#ifdef HAVE_AUDIT - if (c->audit_fd >= 0) - if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "init", NULL, NULL, NULL, 1) < 0) { - log_error("Failed to send audit message: %m"); - r = -errno; - } -#endif - - /* If this call fails it will return 0, which - * utmp_put_reboot() will then fix to the current time */ - t = get_startup_time(c); - - if ((q = utmp_put_reboot(t)) < 0) { - log_error("Failed to write utmp record: %s", strerror(-q)); - r = q; - } - - return r; -} - -static int on_shutdown(Context *c) { - int r = 0, q; - - assert(c); - - /* We started shut-down, so let's write the utmp - * record and send the audit msg */ - -#ifdef HAVE_AUDIT - if (c->audit_fd >= 0) - if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "init", NULL, NULL, NULL, 1) < 0) { - log_error("Failed to send audit message: %m"); - r = -errno; - } -#endif - - if ((q = utmp_put_shutdown(0)) < 0) { - log_error("Failed to write utmp record: %s", strerror(-q)); - r = q; - } - - return r; -} - -static int on_runlevel(Context *c) { - int r = 0, q, previous, runlevel; - - assert(c); - - /* We finished changing runlevel, so let's write the - * utmp record and send the audit msg */ - - /* First, get last runlevel */ - if ((q = utmp_get_runlevel(&previous, NULL)) < 0) { - - if (q != -ESRCH && q != -ENOENT) { - log_error("Failed to get current runlevel: %s", strerror(-q)); - return q; - } - - /* Hmm, we didn't find any runlevel, that means we - * have been rebooted */ - r = on_reboot(c); - previous = 0; - } - - /* Secondly, get new runlevel */ - if ((runlevel = get_current_runlevel(c)) < 0) - return runlevel; - - if (previous == runlevel) - return 0; - -#ifdef HAVE_AUDIT - if (c->audit_fd >= 0) { - char *s = NULL; - - if (asprintf(&s, "old-level=%c new-level=%c", - previous > 0 ? previous : 'N', - runlevel > 0 ? runlevel : 'N') < 0) - return -ENOMEM; - - if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0) { - log_error("Failed to send audit message: %m"); - r = -errno; - } - - free(s); - } -#endif - - if ((q = utmp_put_runlevel(0, runlevel, previous)) < 0) { - log_error("Failed to write utmp record: %s", strerror(-q)); - r = q; - } - - return r; -} - -int main(int argc, char *argv[]) { - int r; - DBusError error; - Context c; - - dbus_error_init(&error); - - zero(c); -#ifdef HAVE_AUDIT - c.audit_fd = -1; -#endif - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc != 2) { - log_error("This program requires one argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - -#ifdef HAVE_AUDIT - if ((c.audit_fd = audit_open()) < 0) - log_error("Failed to connect to audit log: %m"); -#endif - - if (bus_connect(DBUS_BUS_SYSTEM, &c.bus, NULL, &error) < 0) { - log_error("Failed to get D-Bus connection: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - log_debug("systemd-update-utmp running as pid %lu", (unsigned long) getpid()); - - if (streq(argv[1], "reboot")) - r = on_reboot(&c); - else if (streq(argv[1], "shutdown")) - r = on_shutdown(&c); - else if (streq(argv[1], "runlevel")) - r = on_runlevel(&c); - else { - log_error("Unknown command %s", argv[1]); - r = -EINVAL; - } - - log_debug("systemd-update-utmp stopped as pid %lu", (unsigned long) getpid()); - -finish: -#ifdef HAVE_AUDIT - if (c.audit_fd >= 0) - audit_close(c.audit_fd); -#endif - - if (c.bus) { - dbus_connection_flush(c.bus); - dbus_connection_close(c.bus); - dbus_connection_unref(c.bus); - } - - dbus_error_free(&error); - dbus_shutdown(); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/update-utmp/Makefile b/src/update-utmp/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/update-utmp/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c new file mode 100644 index 0000000..e5fb5f8 --- /dev/null +++ b/src/update-utmp/update-utmp.c @@ -0,0 +1,298 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include + +#ifdef HAVE_AUDIT +#include +#endif + +#include "sd-bus.h" + +#include "log.h" +#include "macro.h" +#include "util.h" +#include "special.h" +#include "utmp-wtmp.h" +#include "bus-util.h" +#include "bus-error.h" +#include "unit-name.h" + +typedef struct Context { + sd_bus *bus; +#ifdef HAVE_AUDIT + int audit_fd; +#endif +} Context; + +static usec_t get_startup_time(Context *c) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + usec_t t = 0; + int r; + + assert(c); + + r = sd_bus_get_property_trivial( + c->bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UserspaceTimestamp", + &error, + 't', &t); + if (r < 0) { + log_error("Failed to get timestamp: %s", bus_error_message(&error, -r)); + return 0; + } + + return t; +} + +static int get_current_runlevel(Context *c) { + static const struct { + const int runlevel; + const char *special; + } table[] = { + /* The first target of this list that is active or has + * a job scheduled wins. We prefer runlevels 5 and 3 + * here over the others, since these are the main + * runlevels used on Fedora. It might make sense to + * change the order on some distributions. */ + { '5', SPECIAL_RUNLEVEL5_TARGET }, + { '3', SPECIAL_RUNLEVEL3_TARGET }, + { '4', SPECIAL_RUNLEVEL4_TARGET }, + { '2', SPECIAL_RUNLEVEL2_TARGET }, + { '1', SPECIAL_RESCUE_TARGET }, + }; + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + unsigned i; + + assert(c); + + for (i = 0; i < ELEMENTSOF(table); i++) { + _cleanup_free_ char *state = NULL, *path = NULL; + + path = unit_dbus_path_from_name(table[i].special); + if (!path) + return log_oom(); + + r = sd_bus_get_property_string( + c->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &state); + if (r < 0) { + log_warning("Failed to get state: %s", bus_error_message(&error, -r)); + return r; + } + + if (streq(state, "active") || streq(state, "reloading")) + return table[i].runlevel; + } + + return 0; +} + +static int on_reboot(Context *c) { + int r = 0, q; + usec_t t; + + assert(c); + + /* We finished start-up, so let's write the utmp + * record and send the audit msg */ + +#ifdef HAVE_AUDIT + if (c->audit_fd >= 0) + if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "init", NULL, NULL, NULL, 1) < 0 && + errno != EPERM) { + log_error("Failed to send audit message: %m"); + r = -errno; + } +#endif + + /* If this call fails it will return 0, which + * utmp_put_reboot() will then fix to the current time */ + t = get_startup_time(c); + + q = utmp_put_reboot(t); + if (q < 0) { + log_error("Failed to write utmp record: %s", strerror(-q)); + r = q; + } + + return r; +} + +static int on_shutdown(Context *c) { + int r = 0, q; + + assert(c); + + /* We started shut-down, so let's write the utmp + * record and send the audit msg */ + +#ifdef HAVE_AUDIT + if (c->audit_fd >= 0) + if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "init", NULL, NULL, NULL, 1) < 0 && + errno != EPERM) { + log_error("Failed to send audit message: %m"); + r = -errno; + } +#endif + + q = utmp_put_shutdown(); + if (q < 0) { + log_error("Failed to write utmp record: %s", strerror(-q)); + r = q; + } + + return r; +} + +static int on_runlevel(Context *c) { + int r = 0, q, previous, runlevel; + + assert(c); + + /* We finished changing runlevel, so let's write the + * utmp record and send the audit msg */ + + /* First, get last runlevel */ + q = utmp_get_runlevel(&previous, NULL); + + if (q < 0) { + if (q != -ESRCH && q != -ENOENT) { + log_error("Failed to get current runlevel: %s", strerror(-q)); + return q; + } + + previous = 0; + } + + /* Secondly, get new runlevel */ + runlevel = get_current_runlevel(c); + + if (runlevel < 0) + return runlevel; + + if (previous == runlevel) + return 0; + +#ifdef HAVE_AUDIT + if (c->audit_fd >= 0) { + _cleanup_free_ char *s = NULL; + + if (asprintf(&s, "old-level=%c new-level=%c", + previous > 0 ? previous : 'N', + runlevel > 0 ? runlevel : 'N') < 0) + return log_oom(); + + if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0 && + errno != EPERM) { + log_error("Failed to send audit message: %m"); + r = -errno; + } + } +#endif + + q = utmp_put_runlevel(runlevel, previous); + if (q < 0 && q != -ESRCH && q != -ENOENT) { + log_error("Failed to write utmp record: %s", strerror(-q)); + r = q; + } + + return r; +} + +int main(int argc, char *argv[]) { + Context c = { +#ifdef HAVE_AUDIT + .audit_fd = -1 +#endif + }; + int r; + + if (getppid() != 1) { + log_error("This program should be invoked by init only."); + return EXIT_FAILURE; + } + + if (argc != 2) { + log_error("This program requires one argument."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + +#ifdef HAVE_AUDIT + /* If the kernel lacks netlink or audit support, + * don't worry about it. */ + c.audit_fd = audit_open(); + if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) + log_error("Failed to connect to audit log: %m"); +#endif + r = bus_open_system_systemd(&c.bus); + if (r < 0) { + log_error("Failed to get D-Bus connection: %s", strerror(-r)); + r = -EIO; + goto finish; + } + + log_debug("systemd-update-utmp running as pid %lu", (unsigned long) getpid()); + + if (streq(argv[1], "reboot")) + r = on_reboot(&c); + else if (streq(argv[1], "shutdown")) + r = on_shutdown(&c); + else if (streq(argv[1], "runlevel")) + r = on_runlevel(&c); + else { + log_error("Unknown command %s", argv[1]); + r = -EINVAL; + } + + log_debug("systemd-update-utmp stopped as pid %lu", (unsigned long) getpid()); + +finish: +#ifdef HAVE_AUDIT + if (c.audit_fd >= 0) + audit_close(c.audit_fd); +#endif + + if (c.bus) + sd_bus_unref(c.bus); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/user-sessions.c b/src/user-sessions.c deleted file mode 100644 index df46b76..0000000 --- a/src/user-sessions.c +++ /dev/null @@ -1,100 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "log.h" -#include "util.h" -#include "cgroup-util.h" - -int main(int argc, char*argv[]) { - int ret = EXIT_FAILURE; - - if (argc != 2) { - log_error("This program requires one argument."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); - log_parse_environment(); - log_open(); - - umask(0022); - - if (streq(argv[1], "start")) { - int q = 0, r = 0; - - if (unlink("/run/nologin") < 0 && errno != ENOENT) { - log_error("Failed to remove /run/nologin file: %m"); - r = -errno; - } - - if (unlink("/etc/nologin") < 0 && errno != ENOENT) { - - /* If the file doesn't exist and /etc simply - * was read-only (in which case unlink() - * returns EROFS even if the file doesn't - * exist), don't complain */ - - if (errno != EROFS || access("/etc/nologin", F_OK) >= 0) { - log_error("Failed to remove /etc/nologin file: %m"); - q = -errno; - } - } - - if (r < 0 || q < 0) - goto finish; - - } else if (streq(argv[1], "stop")) { - int r, q; - char *cgroup_user_tree = NULL; - - if ((r = write_one_line_file_atomic("/run/nologin", "System is going down.")) < 0) - log_error("Failed to create /run/nologin: %s", strerror(-r)); - - if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) { - log_error("Failed to determine use path: %s", strerror(-q)); - goto finish; - } - - q = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, true); - free(cgroup_user_tree); - - if (q < 0) { - log_error("Failed to kill sessions: %s", strerror(-q)); - goto finish; - } - - if (r < 0) - goto finish; - - } else { - log_error("Unknown verb %s.", argv[1]); - goto finish; - } - - ret = EXIT_SUCCESS; - -finish: - return ret; -} diff --git a/src/user.conf b/src/user.conf deleted file mode 100644 index 9508a02..0000000 --- a/src/user.conf +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# See systemd.conf(5) for details - -[Manager] -#LogLevel=info -#LogTarget=console -#LogColor=yes -#LogLocation=no -#DefaultControllers=cpu -#DefaultStandardOutput=inherit -#DefaultStandardError=inherit diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 6ad2430..0000000 --- a/src/util.c +++ /dev/null @@ -1,5713 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" -#include "ioprio.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "label.h" -#include "exit-status.h" -#include "hashmap.h" - -int saved_argc = 0; -char **saved_argv = NULL; - -size_t page_size(void) { - static __thread size_t pgsz = 0; - long r; - - if (_likely_(pgsz)) - return pgsz; - - assert_se((r = sysconf(_SC_PAGESIZE)) > 0); - - pgsz = (size_t) r; - - return pgsz; -} - -bool streq_ptr(const char *a, const char *b) { - - /* Like streq(), but tries to make sense of NULL pointers */ - - if (a && b) - return streq(a, b); - - if (!a && !b) - return true; - - return false; -} - -usec_t now(clockid_t clock_id) { - struct timespec ts; - - assert_se(clock_gettime(clock_id, &ts) == 0); - - return timespec_load(&ts); -} - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { - assert(ts); - - ts->realtime = now(CLOCK_REALTIME); - ts->monotonic = now(CLOCK_MONOTONIC); - - return ts; -} - -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { - int64_t delta; - assert(ts); - - ts->realtime = u; - - if (u == 0) - ts->monotonic = 0; - else { - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - - ts->monotonic = now(CLOCK_MONOTONIC); - - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; - } - - return ts; -} - -usec_t timespec_load(const struct timespec *ts) { - assert(ts); - - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; -} - -struct timespec *timespec_store(struct timespec *ts, usec_t u) { - assert(ts); - - ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); - - return ts; -} - -usec_t timeval_load(const struct timeval *tv) { - assert(tv); - - return - (usec_t) tv->tv_sec * USEC_PER_SEC + - (usec_t) tv->tv_usec; -} - -struct timeval *timeval_store(struct timeval *tv, usec_t u) { - assert(tv); - - tv->tv_sec = (time_t) (u / USEC_PER_SEC); - tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); - - return tv; -} - -bool endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return true; - - if (sl < pl) - return false; - - return memcmp(s + sl - pl, postfix, pl) == 0; -} - -bool startswith(const char *s, const char *prefix) { - size_t sl, pl; - - assert(s); - assert(prefix); - - sl = strlen(s); - pl = strlen(prefix); - - if (pl == 0) - return true; - - if (sl < pl) - return false; - - return memcmp(s, prefix, pl) == 0; -} - -bool startswith_no_case(const char *s, const char *prefix) { - size_t sl, pl; - unsigned i; - - assert(s); - assert(prefix); - - sl = strlen(s); - pl = strlen(prefix); - - if (pl == 0) - return true; - - if (sl < pl) - return false; - - for(i = 0; i < pl; ++i) { - if (tolower(s[i]) != tolower(prefix[i])) - return false; - } - - return true; -} - -bool first_word(const char *s, const char *word) { - size_t sl, wl; - - assert(s); - assert(word); - - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return false; - - if (wl == 0) - return true; - - if (memcmp(s, word, wl) != 0) - return false; - - return s[wl] == 0 || - strchr(WHITESPACE, s[wl]); -} - -int close_nointr(int fd) { - assert(fd >= 0); - - for (;;) { - int r; - - r = close(fd); - if (r >= 0) - return r; - - if (errno != EINTR) - return -errno; - } -} - -void close_nointr_nofail(int fd) { - int saved_errno = errno; - - /* like close_nointr() but cannot fail, and guarantees errno - * is unchanged */ - - assert_se(close_nointr(fd) == 0); - - errno = saved_errno; -} - -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - for (i = 0; i < n_fd; i++) - close_nointr_nofail(fds[i]); -} - -int parse_boolean(const char *v) { - assert(v); - - if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) - return 1; - else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - return -EINVAL; -} - -int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul = 0; - pid_t pid; - int r; - - assert(s); - assert(ret_pid); - - if ((r = safe_atolu(s, &ul)) < 0) - return r; - - pid = (pid_t) ul; - - if ((unsigned long) pid != ul) - return -ERANGE; - - if (pid <= 0) - return -ERANGE; - - *ret_pid = pid; - return 0; -} - -int parse_uid(const char *s, uid_t* ret_uid) { - unsigned long ul = 0; - uid_t uid; - int r; - - assert(s); - assert(ret_uid); - - if ((r = safe_atolu(s, &ul)) < 0) - return r; - - uid = (uid_t) ul; - - if ((unsigned long) uid != ul) - return -ERANGE; - - *ret_uid = uid; - return 0; -} - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || *x || errno) - return errno ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || *x || errno) - return errno ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -/* Split a string into words. */ -char *split(const char *c, size_t *l, const char *separator, char **state) { - char *current; - - current = *state ? *state : (char*) c; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, separator); - *l = strcspn(current, separator); - *state = current+*l; - - return (char*) current; -} - -/* Split a string into words, but consider strings enclosed in '' and - * "" as words even if they include spaces. */ -char *split_quoted(const char *c, size_t *l, char **state) { - char *current, *e; - bool escaped = false; - - current = *state ? *state : (char*) c; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - - if (*current == '\'') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\'') - break; - } - - *l = e-current; - *state = *e == 0 ? e : e+1; - } else if (*current == '\"') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\"') - break; - } - - *l = e-current; - *state = *e == 0 ? e : e+1; - } else { - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (strchr(WHITESPACE, *e)) - break; - } - *l = e-current; - *state = e; - } - - return (char*) current; -} - -char **split_path_and_make_absolute(const char *p) { - char **l; - assert(p); - - if (!(l = strv_split(p, ":"))) - return NULL; - - if (!strv_path_make_absolute_cwd(l)) { - strv_free(l); - return NULL; - } - - return l; -} - -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { - int r; - FILE *f; - char fn[PATH_MAX], line[LINE_MAX], *p; - long unsigned ppid; - - assert(pid > 0); - assert(_ppid); - - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); - char_array_0(fn); - - if (!(f = fopen(fn, "re"))) - return -errno; - - if (!(fgets(line, sizeof(line), f))) { - r = -errno; - fclose(f); - return r; - } - - fclose(f); - - /* Let's skip the pid and comm fields. The latter is enclosed - * in () but does not escape any () in its value, so let's - * skip over it manually */ - - if (!(p = strrchr(line, ')'))) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%lu ", /* ppid */ - &ppid) != 1) - return -EIO; - - if ((long unsigned) (pid_t) ppid != ppid) - return -ERANGE; - - *_ppid = (pid_t) ppid; - - return 0; -} - -int get_starttime_of_pid(pid_t pid, unsigned long long *st) { - int r; - FILE *f; - char fn[PATH_MAX], line[LINE_MAX], *p; - - assert(pid > 0); - assert(st); - - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); - char_array_0(fn); - - if (!(f = fopen(fn, "re"))) - return -errno; - - if (!(fgets(line, sizeof(line), f))) { - r = -errno; - fclose(f); - return r; - } - - fclose(f); - - /* Let's skip the pid and comm fields. The latter is enclosed - * in () but does not escape any () in its value, so let's - * skip over it manually */ - - if (!(p = strrchr(line, ')'))) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%*d " /* ppid */ - "%*d " /* pgrp */ - "%*d " /* session */ - "%*d " /* tty_nr */ - "%*d " /* tpgid */ - "%*u " /* flags */ - "%*u " /* minflt */ - "%*u " /* cminflt */ - "%*u " /* majflt */ - "%*u " /* cmajflt */ - "%*u " /* utime */ - "%*u " /* stime */ - "%*d " /* cutime */ - "%*d " /* cstime */ - "%*d " /* priority */ - "%*d " /* nice */ - "%*d " /* num_threads */ - "%*d " /* itrealvalue */ - "%llu " /* starttime */, - st) != 1) - return -EIO; - - return 0; -} - -int write_one_line_file(const char *fn, const char *line) { - FILE *f; - int r; - - assert(fn); - assert(line); - - if (!(f = fopen(fn, "we"))) - return -errno; - - errno = 0; - if (fputs(line, f) < 0) { - r = -errno; - goto finish; - } - - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) { - if (errno != 0) - r = -errno; - else - r = -EIO; - } else - r = 0; - -finish: - fclose(f); - return r; -} - -int fchmod_umask(int fd, mode_t m) { - mode_t u; - int r; - - u = umask(0777); - r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; - umask(u); - - return r; -} - -int write_one_line_file_atomic(const char *fn, const char *line) { - FILE *f; - int r; - char *p; - - assert(fn); - assert(line); - - r = fopen_temporary(fn, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - errno = 0; - if (fputs(line, f) < 0) { - r = -errno; - goto finish; - } - - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) { - if (errno != 0) - r = -errno; - else - r = -EIO; - } else { - if (rename(p, fn) < 0) - r = -errno; - else - r = 0; - } - -finish: - if (r < 0) - unlink(p); - - fclose(f); - free(p); - - return r; -} - -int read_one_line_file(const char *fn, char **line) { - FILE *f; - int r; - char t[LINE_MAX], *c; - - assert(fn); - assert(line); - - if (!(f = fopen(fn, "re"))) - return -errno; - - if (!(fgets(t, sizeof(t), f))) { - r = -errno; - goto finish; - } - - if (!(c = strdup(t))) { - r = -ENOMEM; - goto finish; - } - - truncate_nl(c); - - *line = c; - r = 0; - -finish: - fclose(f); - return r; -} - -int read_full_file(const char *fn, char **contents, size_t *size) { - FILE *f; - int r; - size_t n, l; - char *buf = NULL; - struct stat st; - - if (!(f = fopen(fn, "re"))) - return -errno; - - if (fstat(fileno(f), &st) < 0) { - r = -errno; - goto finish; - } - - /* Safety check */ - if (st.st_size > 4*1024*1024) { - r = -E2BIG; - goto finish; - } - - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; - - for (;;) { - char *t; - size_t k; - - if (!(t = realloc(buf, n+1))) { - r = -ENOMEM; - goto finish; - } - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) { - r = -errno; - goto finish; - } - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) { - r = -E2BIG; - goto finish; - } - } - - buf[l] = 0; - *contents = buf; - buf = NULL; - - if (size) - *size = l; - - r = 0; - -finish: - fclose(f); - free(buf); - - return r; -} - -int parse_env_file( - const char *fname, - const char *separator, ...) { - - int r = 0; - char *contents = NULL, *p; - - assert(fname); - assert(separator); - - if ((r = read_full_file(fname, &contents, NULL)) < 0) - return r; - - p = contents; - for (;;) { - const char *key = NULL; - - p += strspn(p, separator); - p += strspn(p, WHITESPACE); - - if (!*p) - break; - - if (!strchr(COMMENTS, *p)) { - va_list ap; - char **value; - - va_start(ap, separator); - while ((key = va_arg(ap, char *))) { - size_t n; - char *v; - - value = va_arg(ap, char **); - - n = strlen(key); - if (strncmp(p, key, n) != 0 || - p[n] != '=') - continue; - - p += n + 1; - n = strcspn(p, separator); - - if (n >= 2 && - strchr(QUOTES, p[0]) && - p[n-1] == p[0]) - v = strndup(p+1, n-2); - else - v = strndup(p, n); - - if (!v) { - r = -ENOMEM; - va_end(ap); - goto fail; - } - - if (v[0] == '\0') { - /* return empty value strings as NULL */ - free(v); - v = NULL; - } - - free(*value); - *value = v; - - p += n; - - r ++; - break; - } - va_end(ap); - } - - if (!key) - p += strcspn(p, separator); - } - -fail: - free(contents); - return r; -} - -int load_env_file( - const char *fname, - char ***rl) { - - FILE *f; - char **m = 0; - int r; - - assert(fname); - assert(rl); - - if (!(f = fopen(fname, "re"))) - return -errno; - - while (!feof(f)) { - char l[LINE_MAX], *p, *u; - char **t; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - goto finish; - } - - p = strstrip(l); - - if (!*p) - continue; - - if (strchr(COMMENTS, *p)) - continue; - - if (!(u = normalize_env_assignment(p))) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - t = strv_append(m, u); - free(u); - - if (!t) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - - strv_free(m); - m = t; - } - - r = 0; - - *rl = m; - m = NULL; - -finish: - if (f) - fclose(f); - - strv_free(m); - - return r; -} - -int write_env_file(const char *fname, char **l) { - char **i, *p; - FILE *f; - int r; - - r = fopen_temporary(fname, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - errno = 0; - STRV_FOREACH(i, l) { - fputs(*i, f); - fputc('\n', f); - } - - fflush(f); - - if (ferror(f)) { - if (errno != 0) - r = -errno; - else - r = -EIO; - } else { - if (rename(p, fname) < 0) - r = -errno; - else - r = 0; - } - - if (r < 0) - unlink(p); - - fclose(f); - free(p); - - return r; -} - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -int get_process_name(pid_t pid, char **name) { - char *p; - int r; - - assert(pid >= 1); - assert(name); - - if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0) - return -ENOMEM; - - r = read_one_line_file(p, name); - free(p); - - if (r < 0) - return r; - - return 0; -} - -int get_process_cmdline(pid_t pid, size_t max_length, char **line) { - char *p, *r, *k; - int c; - bool space = false; - size_t left; - FILE *f; - - assert(pid >= 1); - assert(max_length > 0); - assert(line); - - if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(p, "re"); - free(p); - - if (!f) - return -errno; - - if (!(r = new(char, max_length))) { - fclose(f); - return -ENOMEM; - } - - k = r; - left = max_length; - while ((c = getc(f)) != EOF) { - - if (isprint(c)) { - if (space) { - if (left <= 4) - break; - - *(k++) = ' '; - left--; - space = false; - } - - if (left <= 4) - break; - - *(k++) = (char) c; - left--; - } else - space = true; - } - - if (left <= 4) { - size_t n = MIN(left-1, 3U); - memcpy(k, "...", n); - k[n] = 0; - } else - *k = 0; - - fclose(f); - - /* Kernel threads have no argv[] */ - if (r[0] == 0) { - char *t; - int h; - - free(r); - - if ((h = get_process_name(pid, &t)) < 0) - return h; - - h = asprintf(&r, "[%s]", t); - free(t); - - if (h < 0) - return -ENOMEM; - } - - *line = r; - return 0; -} - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - - if (!(r = new(char, a+b+1))) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -int readlink_malloc(const char *p, char **r) { - size_t l = 100; - - assert(p); - assert(r); - - for (;;) { - char *c; - ssize_t n; - - if (!(c = new(char, l))) - return -ENOMEM; - - if ((n = readlink(p, c, l-1)) < 0) { - int ret = -errno; - free(c); - return ret; - } - - if ((size_t) n < l-1) { - c[n] = 0; - *r = c; - return 0; - } - - free(c); - l *= 2; - } -} - -int readlink_and_make_absolute(const char *p, char **r) { - char *target, *k; - int j; - - assert(p); - assert(r); - - if ((j = readlink_malloc(p, &target)) < 0) - return j; - - k = file_in_same_dir(p, target); - free(target); - - if (!k) - return -ENOMEM; - - *r = k; - return 0; -} - -int readlink_and_canonicalize(const char *p, char **r) { - char *t, *s; - int j; - - assert(p); - assert(r); - - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; - - s = canonicalize_file_name(t); - if (s) { - free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); - - return 0; -} - -int parent_of_path(const char *path, char **_r) { - const char *e, *a = NULL, *b = NULL, *p; - char *r; - bool slash = false; - - assert(path); - assert(_r); - - if (!*path) - return -EINVAL; - - for (e = path; *e; e++) { - - if (!slash && *e == '/') { - a = b; - b = e; - slash = true; - } else if (slash && *e != '/') - slash = false; - } - - if (*(e-1) == '/') - p = a; - else - p = b; - - if (!p) - return -EINVAL; - - if (p == path) - r = strdup("/"); - else - r = strndup(path, p-path); - - if (!r) - return -ENOMEM; - - *_r = r; - return 0; -} - - -char *file_name_from_path(const char *p) { - char *r; - - assert(p); - - if ((r = strrchr(p, '/'))) - return r + 1; - - return (char*) p; -} - -bool path_is_absolute(const char *p) { - assert(p); - - return p[0] == '/'; -} - -bool is_path(const char *p) { - - return !!strchr(p, '/'); -} - -char *path_make_absolute(const char *p, const char *prefix) { - assert(p); - - /* Makes every item in the list an absolute path by prepending - * the prefix, if specified and necessary */ - - if (path_is_absolute(p) || !prefix) - return strdup(p); - - return join(prefix, "/", p, NULL); -} - -char *path_make_absolute_cwd(const char *p) { - char *cwd, *r; - - assert(p); - - /* Similar to path_make_absolute(), but prefixes with the - * current working directory. */ - - if (path_is_absolute(p)) - return strdup(p); - - if (!(cwd = get_current_dir_name())) - return NULL; - - r = path_make_absolute(p, cwd); - free(cwd); - - return r; -} - -char **strv_path_make_absolute_cwd(char **l) { - char **s; - - /* Goes through every item in the string list and makes it - * absolute. This works in place and won't rollback any - * changes on failure. */ - - STRV_FOREACH(s, l) { - char *t; - - if (!(t = path_make_absolute_cwd(*s))) - return NULL; - - free(*s); - *s = t; - } - - return l; -} - -char **strv_path_canonicalize(char **l) { - char **s; - unsigned k = 0; - bool enomem = false; - - if (strv_isempty(l)) - return l; - - /* Goes through every item in the string list and canonicalize - * the path. This works in place and won't rollback any - * changes on failure. */ - - STRV_FOREACH(s, l) { - char *t, *u; - - t = path_make_absolute_cwd(*s); - free(*s); - - if (!t) { - enomem = true; - continue; - } - - errno = 0; - u = canonicalize_file_name(t); - free(t); - - if (!u) { - if (errno == ENOMEM || !errno) - enomem = true; - - continue; - } - - l[k++] = u; - } - - l[k] = NULL; - - if (enomem) - return NULL; - - return l; -} - -char **strv_path_remove_empty(char **l) { - char **f, **t; - - if (!l) - return NULL; - - for (f = t = l; *f; f++) { - - if (dir_is_empty(*f) > 0) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -int reset_all_signal_handlers(void) { - int sig; - - for (sig = 1; sig < _NSIG; sig++) { - struct sigaction sa; - - if (sig == SIGKILL || sig == SIGSTOP) - continue; - - zero(sa); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_RESTART; - - /* On Linux the first two RT signals are reserved by - * glibc, and sigaction() will return EINVAL for them. */ - if ((sigaction(sig, &sa, NULL) < 0)) - if (errno != EINVAL) - return -errno; - } - - return 0; -} - -char *strstrip(char *s) { - char *e; - - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; - - return s; -} - -char *delete_chars(char *s, const char *bad) { - char *f, *t; - - /* Drops all whitespace, regardless where in the string */ - - for (f = s, t = s; *f; f++) { - if (strchr(bad, *f)) - continue; - - *(t++) = *f; - } - - *t = 0; - - return s; -} - -bool in_charset(const char *s, const char* charset) { - const char *i; - - assert(s); - assert(charset); - - for (i = s; *i; i++) - if (!strchr(charset, *i)) - return false; - - return true; -} - -char *file_in_same_dir(const char *path, const char *filename) { - char *e, *r; - size_t k; - - assert(path); - assert(filename); - - /* This removes the last component of path and appends - * filename, unless the latter is absolute anyway or the - * former isn't */ - - if (path_is_absolute(filename)) - return strdup(filename); - - if (!(e = strrchr(path, '/'))) - return strdup(filename); - - k = strlen(filename); - if (!(r = new(char, e-path+1+k+1))) - return NULL; - - memcpy(r, path, e-path+1); - memcpy(r+(e-path)+1, filename, k+1); - - return r; -} - -int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { - struct stat st; - - if (label_mkdir(path, mode) >= 0) - if (chmod_and_chown(path, mode, uid, gid) < 0) - return -errno; - - if (lstat(path, &st) < 0) - return -errno; - - if ((st.st_mode & 0777) != mode || - st.st_uid != uid || - st.st_gid != gid || - !S_ISDIR(st.st_mode)) { - errno = EEXIST; - return -errno; - } - - return 0; -} - - -int mkdir_parents(const char *path, mode_t mode) { - const char *p, *e; - - assert(path); - - /* Creates every parent directory in the path except the last - * component. */ - - p = path + strspn(path, "/"); - for (;;) { - int r; - char *t; - - e = p + strcspn(p, "/"); - p = e + strspn(e, "/"); - - /* Is this the last component? If so, then we're - * done */ - if (*p == 0) - return 0; - - if (!(t = strndup(path, e - path))) - return -ENOMEM; - - r = label_mkdir(t, mode); - free(t); - - if (r < 0 && errno != EEXIST) - return -errno; - } -} - -int mkdir_p(const char *path, mode_t mode) { - int r; - - /* Like mkdir -p */ - - if ((r = mkdir_parents(path, mode)) < 0) - return r; - - if (label_mkdir(path, mode) < 0 && errno != EEXIST) - return -errno; - - return 0; -} - -int rmdir_parents(const char *path, const char *stop) { - size_t l; - int r = 0; - - assert(path); - assert(stop); - - l = strlen(path); - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - while (l > 0) { - char *t; - - /* Skip last component */ - while (l > 0 && path[l-1] != '/') - l--; - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - if (l <= 0) - break; - - if (!(t = strndup(path, l))) - return -ENOMEM; - - if (path_startswith(stop, t)) { - free(t); - return 0; - } - - r = rmdir(t); - free(t); - - if (r < 0) - if (errno != ENOENT) - return -errno; - } - - return 0; -} - - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -1; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -1; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -1; -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. */ - - if (!(r = new(char, strlen(s)*4 + 1))) - return NULL; - - for (f = s, t = r; *f; f++) - - switch (*f) { - - case '\a': - *(t++) = '\\'; - *(t++) = 'a'; - break; - case '\b': - *(t++) = '\\'; - *(t++) = 'b'; - break; - case '\f': - *(t++) = '\\'; - *(t++) = 'f'; - break; - case '\n': - *(t++) = '\\'; - *(t++) = 'n'; - break; - case '\r': - *(t++) = '\\'; - *(t++) = 'r'; - break; - case '\t': - *(t++) = '\\'; - *(t++) = 't'; - break; - case '\v': - *(t++) = '\\'; - *(t++) = 'v'; - break; - case '\\': - *(t++) = '\\'; - *(t++) = '\\'; - break; - case '"': - *(t++) = '\\'; - *(t++) = '"'; - break; - case '\'': - *(t++) = '\\'; - *(t++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((*f < ' ') || (*f >= 127)) { - *(t++) = '\\'; - *(t++) = octchar((unsigned char) *f >> 6); - *(t++) = octchar((unsigned char) *f >> 3); - *(t++) = octchar((unsigned char) *f); - } else - *(t++) = *f; - break; - } - - *t = 0; - - return r; -} - -char *cunescape_length(const char *s, size_t length) { - char *r, *t; - const char *f; - - assert(s); - - /* Undoes C style string escaping */ - - if (!(r = new(char, length+1))) - return r; - - for (f = s, t = r; f < s + length; f++) { - - if (*f != '\\') { - *(t++) = *f; - continue; - } - - f++; - - switch (*f) { - - case 'a': - *(t++) = '\a'; - break; - case 'b': - *(t++) = '\b'; - break; - case 'f': - *(t++) = '\f'; - break; - case 'n': - *(t++) = '\n'; - break; - case 'r': - *(t++) = '\r'; - break; - case 't': - *(t++) = '\t'; - break; - case 'v': - *(t++) = '\v'; - break; - case '\\': - *(t++) = '\\'; - break; - case '"': - *(t++) = '"'; - break; - case '\'': - *(t++) = '\''; - break; - - case 's': - /* This is an extension of the XDG syntax files */ - *(t++) = ' '; - break; - - case 'x': { - /* hexadecimal encoding */ - int a, b; - - if ((a = unhexchar(f[1])) < 0 || - (b = unhexchar(f[2])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = 'x'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 2; - } - - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - /* octal encoding */ - int a, b, c; - - if ((a = unoctchar(f[0])) < 0 || - (b = unoctchar(f[1])) < 0 || - (c = unoctchar(f[2])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = f[0]; - } else { - *(t++) = (char) ((a << 6) | (b << 3) | c); - f += 2; - } - - break; - } - - case 0: - /* premature end of string.*/ - *(t++) = '\\'; - goto finish; - - default: - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = *f; - break; - } - } - -finish: - *t = 0; - return r; -} - -char *cunescape(const char *s) { - return cunescape_length(s, strlen(s)); -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape. */ - - if (!(r = new(char, strlen(s)*4+1))) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *bus_path_escape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Escapes all chars that D-Bus' object path cannot deal - * with. Can be reverse with bus_path_unescape() */ - - if (!(r = new(char, strlen(s)*3+1))) - return NULL; - - for (f = s, t = r; *f; f++) { - - if (!(*f >= 'A' && *f <= 'Z') && - !(*f >= 'a' && *f <= 'z') && - !(*f >= '0' && *f <= '9')) { - *(t++) = '_'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *bus_path_unescape(const char *f) { - char *r, *t; - - assert(f); - - if (!(r = strdup(f))) - return NULL; - - for (t = r; *f; f++) { - - if (*f == '_') { - int a, b; - - if ((a = unhexchar(f[1])) < 0 || - (b = unhexchar(f[2])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '_'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 2; - } - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *path_kill_slashes(char *path) { - char *f, *t; - bool slash = false; - - /* Removes redundant inner and trailing slashes. Modifies the - * passed string in-place. - * - * ///foo///bar/ becomes /foo/bar - */ - - for (f = path, t = path; *f; f++) { - - if (*f == '/') { - slash = true; - continue; - } - - if (slash) { - slash = false; - *(t++) = '/'; - } - - *(t++) = *f; - } - - /* Special rule, if we are talking of the root directory, a - trailing slash is good */ - - if (t == path && slash) - *(t++) = '/'; - - *t = 0; - return path; -} - -bool path_startswith(const char *path, const char *prefix) { - assert(path); - assert(prefix); - - if ((path[0] == '/') != (prefix[0] == '/')) - return false; - - for (;;) { - size_t a, b; - - path += strspn(path, "/"); - prefix += strspn(prefix, "/"); - - if (*prefix == 0) - return true; - - if (*path == 0) - return false; - - a = strcspn(path, "/"); - b = strcspn(prefix, "/"); - - if (a != b) - return false; - - if (memcmp(path, prefix, a) != 0) - return false; - - path += a; - prefix += b; - } -} - -bool path_equal(const char *a, const char *b) { - assert(a); - assert(b); - - if ((a[0] == '/') != (b[0] == '/')) - return false; - - for (;;) { - size_t j, k; - - a += strspn(a, "/"); - b += strspn(b, "/"); - - if (*a == 0 && *b == 0) - return true; - - if (*a == 0 || *b == 0) - return false; - - j = strcspn(a, "/"); - k = strcspn(b, "/"); - - if (j != k) - return false; - - if (memcmp(a, b, j) != 0) - return false; - - a += j; - b += k; - } -} - -char *ascii_strlower(char *t) { - char *p; - - assert(t); - - for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - - return t; -} - -bool ignore_file(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, "~") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".swp"); -} - -int fd_nonblock(int fd, bool nonblock) { - int flags; - - assert(fd >= 0); - - if ((flags = fcntl(fd, F_GETFL, 0)) < 0) - return -errno; - - if (nonblock) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags; - - assert(fd >= 0); - - if ((flags = fcntl(fd, F_GETFD, 0)) < 0) - return -errno; - - if (cloexec) - flags |= FD_CLOEXEC; - else - flags &= ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) < 0) - return -errno; - - return 0; -} - -int close_all_fds(const int except[], unsigned n_except) { - DIR *d; - struct dirent *de; - int r = 0; - - if (!(d = opendir("/proc/self/fd"))) - return -errno; - - while ((de = readdir(d))) { - int fd = -1; - - if (ignore_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (except) { - bool found; - unsigned i; - - found = false; - for (i = 0; i < n_except; i++) - if (except[i] == fd) { - found = true; - break; - } - - if (found) - continue; - } - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - closedir(d); - return r; -} - -bool chars_intersect(const char *a, const char *b) { - const char *p; - - /* Returns true if any of the chars in a are in b. */ - for (p = a; *p; p++) - if (strchr(b, *p)) - return true; - - return false; -} - -char *format_timestamp(char *buf, size_t l, usec_t t) { - struct tm tm; - time_t sec; - - assert(buf); - assert(l > 0); - - if (t <= 0) - return NULL; - - sec = (time_t) (t / USEC_PER_SEC); - - if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0) - return NULL; - - return buf; -} - -char *format_timestamp_pretty(char *buf, size_t l, usec_t t) { - usec_t n, d; - - n = now(CLOCK_REALTIME); - - if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t) - return NULL; - - d = n - t; - - if (d >= USEC_PER_YEAR) - snprintf(buf, l, "%llu years and %llu months ago", - (unsigned long long) (d / USEC_PER_YEAR), - (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH)); - else if (d >= USEC_PER_MONTH) - snprintf(buf, l, "%llu months and %llu days ago", - (unsigned long long) (d / USEC_PER_MONTH), - (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY)); - else if (d >= USEC_PER_WEEK) - snprintf(buf, l, "%llu weeks and %llu days ago", - (unsigned long long) (d / USEC_PER_WEEK), - (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY)); - else if (d >= 2*USEC_PER_DAY) - snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY)); - else if (d >= 25*USEC_PER_HOUR) - snprintf(buf, l, "1 day and %lluh ago", - (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR)); - else if (d >= 6*USEC_PER_HOUR) - snprintf(buf, l, "%lluh ago", - (unsigned long long) (d / USEC_PER_HOUR)); - else if (d >= USEC_PER_HOUR) - snprintf(buf, l, "%lluh %llumin ago", - (unsigned long long) (d / USEC_PER_HOUR), - (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE)); - else if (d >= 5*USEC_PER_MINUTE) - snprintf(buf, l, "%llumin ago", - (unsigned long long) (d / USEC_PER_MINUTE)); - else if (d >= USEC_PER_MINUTE) - snprintf(buf, l, "%llumin %llus ago", - (unsigned long long) (d / USEC_PER_MINUTE), - (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC)); - else if (d >= USEC_PER_SEC) - snprintf(buf, l, "%llus ago", - (unsigned long long) (d / USEC_PER_SEC)); - else if (d >= USEC_PER_MSEC) - snprintf(buf, l, "%llums ago", - (unsigned long long) (d / USEC_PER_MSEC)); - else if (d > 0) - snprintf(buf, l, "%lluus ago", - (unsigned long long) d); - else - snprintf(buf, l, "now"); - - buf[l-1] = 0; - return buf; -} - -char *format_timespan(char *buf, size_t l, usec_t t) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "w", USEC_PER_WEEK }, - { "d", USEC_PER_DAY }, - { "h", USEC_PER_HOUR }, - { "min", USEC_PER_MINUTE }, - { "s", USEC_PER_SEC }, - { "ms", USEC_PER_MSEC }, - { "us", 1 }, - }; - - unsigned i; - char *p = buf; - - assert(buf); - assert(l > 0); - - if (t == (usec_t) -1) - return NULL; - - if (t == 0) { - snprintf(p, l, "0"); - p[l-1] = 0; - return p; - } - - /* The result of this function can be parsed with parse_usec */ - - for (i = 0; i < ELEMENTSOF(table); i++) { - int k; - size_t n; - - if (t < table[i].usec) - continue; - - if (l <= 1) - break; - - k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix); - n = MIN((size_t) k, l); - - l -= n; - p += n; - - t %= table[i].usec; - } - - *p = 0; - - return buf; -} - -bool fstype_is_network(const char *fstype) { - static const char * const table[] = { - "cifs", - "smbfs", - "ncpfs", - "nfs", - "nfs4", - "gfs", - "gfs2" - }; - - unsigned i; - - for (i = 0; i < ELEMENTSOF(table); i++) - if (streq(table[i], fstype)) - return true; - - return false; -} - -int chvt(int vt) { - int fd, r = 0; - - if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) - return -errno; - - if (vt < 0) { - int tiocl[2] = { - TIOCL_GETKMSGREDIRECT, - 0 - }; - - if (ioctl(fd, TIOCLINUX, tiocl) < 0) { - r = -errno; - goto fail; - } - - vt = tiocl[0] <= 0 ? 1 : tiocl[0]; - } - - if (ioctl(fd, VT_ACTIVATE, vt) < 0) - r = -errno; - -fail: - close_nointr_nofail(fd); - return r; -} - -int read_one_char(FILE *f, char *ret, bool *need_nl) { - struct termios old_termios, new_termios; - char c; - char line[LINE_MAX]; - - assert(f); - assert(ret); - - if (tcgetattr(fileno(f), &old_termios) >= 0) { - new_termios = old_termios; - - new_termios.c_lflag &= ~ICANON; - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) { - size_t k; - - k = fread(&c, 1, 1, f); - - tcsetattr(fileno(f), TCSADRAIN, &old_termios); - - if (k <= 0) - return -EIO; - - if (need_nl) - *need_nl = c != '\n'; - - *ret = c; - return 0; - } - } - - if (!(fgets(line, sizeof(line), f))) - return -EIO; - - truncate_nl(line); - - if (strlen(line) != 1) - return -EBADMSG; - - if (need_nl) - *need_nl = false; - - *ret = line[0]; - return 0; -} - -int ask(char *ret, const char *replies, const char *text, ...) { - bool on_tty; - - assert(ret); - assert(replies); - assert(text); - - on_tty = isatty(STDOUT_FILENO); - - for (;;) { - va_list ap; - char c; - int r; - bool need_nl = true; - - if (on_tty) - fputs("\x1B[1m", stdout); - - va_start(ap, text); - vprintf(text, ap); - va_end(ap); - - if (on_tty) - fputs("\x1B[0m", stdout); - - fflush(stdout); - - if ((r = read_one_char(stdin, &c, &need_nl)) < 0) { - - if (r == -EBADMSG) { - puts("Bad input, please try again."); - continue; - } - - putchar('\n'); - return r; - } - - if (need_nl) - putchar('\n'); - - if (strchr(replies, c)) { - *ret = c; - return 0; - } - - puts("Read unexpected character, please try again."); - } -} - -int reset_terminal_fd(int fd) { - struct termios termios; - int r = 0; - long arg; - - /* Set terminal to some sane defaults */ - - assert(fd >= 0); - - /* We leave locked terminal attributes untouched, so that - * Plymouth may set whatever it wants to set, and we don't - * interfere with that. */ - - /* Disable exclusive mode, just in case */ - ioctl(fd, TIOCNXCL); - - /* Enable console unicode mode */ - arg = K_UNICODE; - ioctl(fd, KDSKBMODE, &arg); - - if (tcgetattr(fd, &termios) < 0) { - r = -errno; - goto finish; - } - - /* We only reset the stuff that matters to the software. How - * hardware is set up we don't touch assuming that somebody - * else will do that for us */ - - termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC); - termios.c_iflag |= ICRNL | IMAXBEL | IUTF8; - termios.c_oflag |= ONLCR; - termios.c_cflag |= CREAD; - termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE; - - termios.c_cc[VINTR] = 03; /* ^C */ - termios.c_cc[VQUIT] = 034; /* ^\ */ - termios.c_cc[VERASE] = 0177; - termios.c_cc[VKILL] = 025; /* ^X */ - termios.c_cc[VEOF] = 04; /* ^D */ - termios.c_cc[VSTART] = 021; /* ^Q */ - termios.c_cc[VSTOP] = 023; /* ^S */ - termios.c_cc[VSUSP] = 032; /* ^Z */ - termios.c_cc[VLNEXT] = 026; /* ^V */ - termios.c_cc[VWERASE] = 027; /* ^W */ - termios.c_cc[VREPRINT] = 022; /* ^R */ - termios.c_cc[VEOL] = 0; - termios.c_cc[VEOL2] = 0; - - termios.c_cc[VTIME] = 0; - termios.c_cc[VMIN] = 1; - - if (tcsetattr(fd, TCSANOW, &termios) < 0) - r = -errno; - -finish: - /* Just in case, flush all crap out */ - tcflush(fd, TCIOFLUSH); - - return r; -} - -int reset_terminal(const char *name) { - int fd, r; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = reset_terminal_fd(fd); - close_nointr_nofail(fd); - - return r; -} - -int open_terminal(const char *name, int mode) { - int fd, r; - unsigned c = 0; - - /* - * If a TTY is in the process of being closed opening it might - * cause EIO. This is horribly awful, but unlikely to be - * changed in the kernel. Hence we work around this problem by - * retrying a couple of times. - * - * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 - */ - - for (;;) { - if ((fd = open(name, mode)) >= 0) - break; - - if (errno != EIO) - return -errno; - - if (c >= 20) - return -errno; - - usleep(50 * USEC_PER_MSEC); - c++; - } - - if (fd < 0) - return -errno; - - if ((r = isatty(fd)) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - if (!r) { - close_nointr_nofail(fd); - return -ENOTTY; - } - - return fd; -} - -int flush_fd(int fd) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - if ((r = poll(&pollfd, 1, 0)) < 0) { - - if (errno == EINTR) - continue; - - return -errno; - } - - if (r == 0) - return 0; - - if ((l = read(fd, buf, sizeof(buf))) < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } - - if (l <= 0) - return 0; - } -} - -int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) { - int fd = -1, notify = -1, r, wd = -1; - - assert(name); - - /* We use inotify to be notified when the tty is closed. We - * create the watch before checking if we can actually acquire - * it, so that we don't lose any event. - * - * Note: strictly speaking this actually watches for the - * device being closed, it does *not* really watch whether a - * tty loses its controlling process. However, unless some - * rogue process uses TIOCNOTTY on /dev/tty *after* closing - * its tty otherwise this will not become a problem. As long - * as the administrator makes sure not configure any service - * on the same tty as an untrusted user this should not be a - * problem. (Which he probably should not do anyway.) */ - - if (!fail && !force) { - if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { - r = -errno; - goto fail; - } - - if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) { - r = -errno; - goto fail; - } - } - - for (;;) { - if (notify >= 0) - if ((r = flush_fd(notify)) < 0) - goto fail; - - /* We pass here O_NOCTTY only so that we can check the return - * value TIOCSCTTY and have a reliable way to figure out if we - * successfully became the controlling process of the tty */ - if ((fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) - return fd; - - /* First, try to get the tty */ - r = ioctl(fd, TIOCSCTTY, force); - - /* Sometimes it makes sense to ignore TIOCSCTTY - * returning EPERM, i.e. when very likely we already - * are have this controlling terminal. */ - if (r < 0 && errno == EPERM && ignore_tiocstty_eperm) - r = 0; - - if (r < 0 && (force || fail || errno != EPERM)) { - r = -errno; - goto fail; - } - - if (r >= 0) - break; - - assert(!fail); - assert(!force); - assert(notify >= 0); - - for (;;) { - uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; - ssize_t l; - struct inotify_event *e; - - if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - goto fail; - } - - e = (struct inotify_event*) inotify_buffer; - - while (l > 0) { - size_t step; - - if (e->wd != wd || !(e->mask & IN_CLOSE)) { - r = -EIO; - goto fail; - } - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) l); - - e = (struct inotify_event*) ((uint8_t*) e + step); - l -= step; - } - - break; - } - - /* We close the tty fd here since if the old session - * ended our handle will be dead. It's important that - * we do this after sleeping, so that we don't enter - * an endless loop. */ - close_nointr_nofail(fd); - } - - if (notify >= 0) - close_nointr_nofail(notify); - - if ((r = reset_terminal_fd(fd)) < 0) - log_warning("Failed to reset terminal: %s", strerror(-r)); - - return fd; - -fail: - if (fd >= 0) - close_nointr_nofail(fd); - - if (notify >= 0) - close_nointr_nofail(notify); - - return r; -} - -int release_terminal(void) { - int r = 0, fd; - struct sigaction sa_old, sa_new; - - if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC)) < 0) - return -errno; - - /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed - * by our own TIOCNOTTY */ - - zero(sa_new); - sa_new.sa_handler = SIG_IGN; - sa_new.sa_flags = SA_RESTART; - assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); - - if (ioctl(fd, TIOCNOTTY) < 0) - r = -errno; - - assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - - close_nointr_nofail(fd); - return r; -} - -int sigaction_many(const struct sigaction *sa, ...) { - va_list ap; - int r = 0, sig; - - va_start(ap, sa); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int ignore_signals(int sig, ...) { - struct sigaction sa; - va_list ap; - int r = 0; - - zero(sa); - sa.sa_handler = SIG_IGN; - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int default_signals(int sig, ...) { - struct sigaction sa; - va_list ap; - int r = 0; - - zero(sa); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int close_pipe(int p[]) { - int a = 0, b = 0; - - assert(p); - - if (p[0] >= 0) { - a = close_nointr(p[0]); - p[0] = -1; - } - - if (p[1] >= 0) { - b = close_nointr(p[1]); - p[1] = -1; - } - - return a < 0 ? a : b; -} - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - p = buf; - - while (nbytes > 0) { - ssize_t k; - - if ((k = read(fd, p, nbytes)) <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; - - return n > 0 ? n : -errno; - } - - if (pollfd.revents != POLLIN) - return n > 0 ? n : -EIO; - - continue; - } - - return n > 0 ? n : (k < 0 ? -errno : 0); - } - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - p = buf; - - while (nbytes > 0) { - ssize_t k; - - if ((k = write(fd, p, nbytes)) <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLOUT; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; - - return n > 0 ? n : -errno; - } - - if (pollfd.revents != POLLOUT) - return n > 0 ? n : -EIO; - - continue; - } - - return n > 0 ? n : (k < 0 ? -errno : 0); - } - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -int path_is_mount_point(const char *t, bool allow_symlink) { - struct stat a, b; - char *parent; - int r; - - if (allow_symlink) - r = stat(t, &a); - else - r = lstat(t, &a); - - if (r < 0) { - if (errno == ENOENT) - return 0; - - return -errno; - } - - r = parent_of_path(t, &parent); - if (r < 0) - return r; - - r = lstat(parent, &b); - free(parent); - - if (r < 0) - return -errno; - - return a.st_dev != b.st_dev; -} - -int parse_usec(const char *t, usec_t *usec) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, - { "min", USEC_PER_MINUTE }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "d", USEC_PER_DAY }, - { "w", USEC_PER_WEEK }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "usec", 1ULL }, - { "us", 1ULL }, - { "", USEC_PER_SEC }, - }; - - const char *p; - usec_t r = 0; - - assert(t); - assert(usec); - - p = t; - do { - long long l; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno != 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - r += (usec_t) l * table[i].usec; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } while (*p != 0); - - *usec = r; - - return 0; -} - -int parse_bytes(const char *t, off_t *bytes) { - static const struct { - const char *suffix; - off_t factor; - } table[] = { - { "B", 1 }, - { "K", 1024ULL }, - { "M", 1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "", 1 }, - }; - - const char *p; - off_t r = 0; - - assert(t); - assert(bytes); - - p = t; - do { - long long l; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno != 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - r += (off_t) l * table[i].factor; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } while (*p != 0); - - *bytes = r; - - return 0; -} - -int make_stdio(int fd) { - int r, s, t; - - assert(fd >= 0); - - r = dup2(fd, STDIN_FILENO); - s = dup2(fd, STDOUT_FILENO); - t = dup2(fd, STDERR_FILENO); - - if (fd >= 3) - close_nointr_nofail(fd); - - if (r < 0 || s < 0 || t < 0) - return -errno; - - fd_cloexec(STDIN_FILENO, false); - fd_cloexec(STDOUT_FILENO, false); - fd_cloexec(STDERR_FILENO, false); - - return 0; -} - -int make_null_stdio(void) { - int null_fd; - - if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0) - return -errno; - - return make_stdio(null_fd); -} - -bool is_device_path(const char *path) { - - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ - - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); -} - -int dir_is_empty(const char *path) { - DIR *d; - int r; - struct dirent buf, *de; - - if (!(d = opendir(path))) - return -errno; - - for (;;) { - if ((r = readdir_r(d, &buf, &de)) > 0) { - r = -r; - break; - } - - if (!de) { - r = 1; - break; - } - - if (!ignore_file(de->d_name)) { - r = 0; - break; - } - } - - closedir(d); - return r; -} - -unsigned long long random_ull(void) { - int fd; - uint64_t ull; - ssize_t r; - - if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) - goto fallback; - - r = loop_read(fd, &ull, sizeof(ull), true); - close_nointr_nofail(fd); - - if (r != sizeof(ull)) - goto fallback; - - return ull; - -fallback: - return random() * RAND_MAX + random(); -} - -void rename_process(const char name[8]) { - assert(name); - - prctl(PR_SET_NAME, name); - - /* This is a like a poor man's setproctitle(). The string - * passed should fit in 7 chars (i.e. the length of - * "systemd") */ - - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); - - if (saved_argc > 0) { - int i; - - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); - - for (i = 1; i < saved_argc; i++) { - if (!saved_argv[i]) - break; - - memset(saved_argv[i], 0, strlen(saved_argv[i])); - } - } -} - -void sigset_add_many(sigset_t *ss, ...) { - va_list ap; - int sig; - - assert(ss); - - va_start(ap, ss); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(ss, sig) == 0); - va_end(ap); -} - -char* gethostname_malloc(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - if (u.nodename[0]) - return strdup(u.nodename); - - return strdup(u.sysname); -} - -char* getlogname_malloc(void) { - uid_t uid; - long bufsize; - char *buf, *name; - struct passwd pwbuf, *pw = NULL; - struct stat st; - - if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) - uid = st.st_uid; - else - uid = getuid(); - - /* Shortcut things to avoid NSS lookups */ - if (uid == 0) - return strdup("root"); - - if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0) - bufsize = 4096; - - if (!(buf = malloc(bufsize))) - return NULL; - - if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) { - name = strdup(pw->pw_name); - free(buf); - return name; - } - - free(buf); - - if (asprintf(&name, "%lu", (unsigned long) uid) < 0) - return NULL; - - return name; -} - -int getttyname_malloc(int fd, char **r) { - char path[PATH_MAX], *c; - int k; - - assert(r); - - if ((k = ttyname_r(fd, path, sizeof(path))) != 0) - return -k; - - char_array_0(path); - - if (!(c = strdup(startswith(path, "/dev/") ? path + 5 : path))) - return -ENOMEM; - - *r = c; - return 0; -} - -int getttyname_harder(int fd, char **r) { - int k; - char *s; - - if ((k = getttyname_malloc(fd, &s)) < 0) - return k; - - if (streq(s, "tty")) { - free(s); - return get_ctty(0, NULL, r); - } - - *r = s; - return 0; -} - -int get_ctty_devnr(pid_t pid, dev_t *d) { - int k; - char line[LINE_MAX], *p, *fn; - unsigned long ttynr; - FILE *f; - - if (asprintf(&fn, "/proc/%lu/stat", (unsigned long) (pid <= 0 ? getpid() : pid)) < 0) - return -ENOMEM; - - f = fopen(fn, "re"); - free(fn); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) { - k = -errno; - fclose(f); - return k; - } - - fclose(f); - - p = strrchr(line, ')'); - if (!p) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%*d " /* ppid */ - "%*d " /* pgrp */ - "%*d " /* session */ - "%lu ", /* ttynr */ - &ttynr) != 1) - return -EIO; - - *d = (dev_t) ttynr; - return 0; -} - -int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - int k; - char fn[PATH_MAX], *s, *b, *p; - dev_t devnr; - - assert(r); - - k = get_ctty_devnr(pid, &devnr); - if (k < 0) - return k; - - snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr)); - char_array_0(fn); - - if ((k = readlink_malloc(fn, &s)) < 0) { - - if (k != -ENOENT) - return k; - - /* This is an ugly hack */ - if (major(devnr) == 136) { - if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; - } - - /* Probably something like the ptys which have no - * symlink in /dev/char. Let's return something - * vaguely useful. */ - - if (!(b = strdup(fn + 5))) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; - } - - if (startswith(s, "/dev/")) - p = s + 5; - else if (startswith(s, "../")) - p = s + 3; - else - p = s; - - b = strdup(p); - free(s); - - if (!b) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; -} - -static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) { - DIR *d; - int ret = 0; - - assert(fd >= 0); - - /* This returns the first error we run into, but nevertheless - * tries to go on */ - - if (!(d = fdopendir(fd))) { - close_nointr_nofail(fd); - - return errno == ENOENT ? 0 : -errno; - } - - for (;;) { - struct dirent buf, *de; - bool is_dir, keep_around = false; - int r; - - if ((r = readdir_r(d, &buf, &de)) != 0) { - if (ret == 0) - ret = -r; - break; - } - - if (!de) - break; - - if (streq(de->d_name, ".") || streq(de->d_name, "..")) - continue; - - if (de->d_type == DT_UNKNOWN) { - struct stat st; - - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - if (honour_sticky) - keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX); - - is_dir = S_ISDIR(st.st_mode); - - } else { - if (honour_sticky) { - struct stat st; - - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX); - } - - is_dir = de->d_type == DT_DIR; - } - - if (is_dir) { - int subdir_fd; - - if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - if ((r = rm_rf_children(subdir_fd, only_dirs, honour_sticky)) < 0) { - if (ret == 0) - ret = r; - } - - if (!keep_around) - if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - - } else if (!only_dirs && !keep_around) { - - if (unlinkat(fd, de->d_name, 0) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - } - } - - closedir(d); - - return ret; -} - -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { - int fd; - int r; - - assert(path); - - if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) { - - if (errno != ENOTDIR) - return -errno; - - if (delete_root && !only_dirs) - if (unlink(path) < 0) - return -errno; - - return 0; - } - - r = rm_rf_children(fd, only_dirs, honour_sticky); - - if (delete_root) { - - if (honour_sticky && file_is_sticky(path) > 0) - return r; - - if (rmdir(path) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - } - } - - return r; -} - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - 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. */ - - if (chmod(path, mode) < 0) - return -errno; - - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} - -void status_vprintf(const char *format, va_list ap) { - char *s = NULL; - int fd = -1; - - assert(format); - - /* This independent of logging, as status messages are - * optional and go exclusively to the console. */ - - if (vasprintf(&s, format, ap) < 0) - goto finish; - - if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) - goto finish; - - write(fd, s, strlen(s)); - -finish: - free(s); - - if (fd >= 0) - close_nointr_nofail(fd); -} - -void status_printf(const char *format, ...) { - va_list ap; - - assert(format); - - va_start(ap, format); - status_vprintf(format, ap); - va_end(ap); -} - -void status_welcome(void) { - char *pretty_name = NULL, *ansi_color = NULL; - const char *const_pretty = NULL, *const_color = NULL; - int r; - - if ((r = parse_env_file("/etc/os-release", NEWLINE, - "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/os-release: %s", strerror(-r)); - } - -#if defined(TARGET_FEDORA) - if (!pretty_name) { - if ((r = read_one_line_file("/etc/system-release", &pretty_name)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/system-release: %s", strerror(-r)); - } - } - - if (!ansi_color && pretty_name) { - - /* This tries to mimic the color magic the old Red Hat sysinit - * script did. */ - - if (startswith(pretty_name, "Red Hat")) - const_color = "0;31"; /* Red for RHEL */ - else if (startswith(pretty_name, "Fedora")) - const_color = "0;34"; /* Blue for Fedora */ - } - -#elif defined(TARGET_SUSE) - - if (!pretty_name) { - if ((r = read_one_line_file("/etc/SuSE-release", &pretty_name)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/SuSE-release: %s", strerror(-r)); - } - } - - if (!ansi_color) - const_color = "0;32"; /* Green for openSUSE */ - -#elif defined(TARGET_GENTOO) - - if (!pretty_name) { - if ((r = read_one_line_file("/etc/gentoo-release", &pretty_name)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r)); - } - } - - if (!ansi_color) - const_color = "1;34"; /* Light Blue for Gentoo */ - -#elif defined(TARGET_ALTLINUX) - - if (!pretty_name) { - if ((r = read_one_line_file("/etc/altlinux-release", &pretty_name)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/altlinux-release: %s", strerror(-r)); - } - } - - if (!ansi_color) - const_color = "0;36"; /* Cyan for ALTLinux */ - - -#elif defined(TARGET_DEBIAN) - - if (!pretty_name) { - char *version; - - if ((r = read_one_line_file("/etc/debian_version", &version)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/debian_version: %s", strerror(-r)); - } else { - pretty_name = strappend("Debian ", version); - free(version); - - if (!pretty_name) - log_warning("Failed to allocate Debian version string."); - } - } - - if (!ansi_color) - const_color = "1;31"; /* Light Red for Debian */ - -#elif defined(TARGET_UBUNTU) - - if ((r = parse_env_file("/etc/lsb-release", NEWLINE, - "DISTRIB_DESCRIPTION", &pretty_name, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/lsb-release: %s", strerror(-r)); - } - - if (!ansi_color) - const_color = "0;33"; /* Orange/Brown for Ubuntu */ - -#elif defined(TARGET_SLP) - - if (!const_pretty) - const_pretty = "Samsung Linux Platform (SLP)"; - - if (!ansi_color) - const_color = "1;31"; /* Light Red */ - -#elif defined(TARGET_MANDRIVA) - - if (!pretty_name) { - char *s, *p; - - if ((r = read_one_line_file("/etc/mandriva-release", &s) < 0)) { - if (r != -ENOENT) - log_warning("Failed to read /etc/mandriva-release: %s", strerror(-r)); - } else { - p = strstr(s, " release "); - if (p) { - *p = '\0'; - p += 9; - p[strcspn(p, " ")] = '\0'; - - /* This corresponds to standard rc.sysinit */ - if (asprintf(&pretty_name, "%s\x1B[0;39m %s", s, p) > 0) - const_color = "1;36"; - else - log_warning("Failed to allocate Mandriva version string."); - } else - log_warning("Failed to parse /etc/mandriva-release"); - free(s); - } - } -#elif defined(TARGET_MEEGO) - - if (!pretty_name) { - if ((r = read_one_line_file("/etc/meego-release", &pretty_name)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/meego-release: %s", strerror(-r)); - } - } - - if (!ansi_color) - const_color = "1;35"; /* Bright Magenta for MeeGo */ -#endif - - if (!pretty_name && !const_pretty) - const_pretty = "Linux"; - - if (!ansi_color && !const_color) - const_color = "1"; - - status_printf("\nWelcome to \x1B[%sm%s\x1B[0m!\n\n", - const_color ? const_color : ansi_color, - const_pretty ? const_pretty : pretty_name); - - free(ansi_color); - free(pretty_name); -} - -char *replace_env(const char *format, char **env) { - enum { - WORD, - CURLY, - VARIABLE - } state = WORD; - - const char *e, *word = format; - char *r = NULL, *k; - - assert(format); - - for (e = format; *e; e ++) { - - switch (state) { - - case WORD: - if (*e == '$') - state = CURLY; - break; - - case CURLY: - if (*e == '{') { - if (!(k = strnappend(r, word, e-word-1))) - goto fail; - - free(r); - r = k; - - word = e-1; - state = VARIABLE; - - } else if (*e == '$') { - if (!(k = strnappend(r, word, e-word))) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } else - state = WORD; - break; - - case VARIABLE: - if (*e == '}') { - const char *t; - - if (!(t = strv_env_get_with_length(env, word+2, e-word-2))) - t = ""; - - if (!(k = strappend(r, t))) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } - break; - } - } - - if (!(k = strnappend(r, word, e-word))) - goto fail; - - free(r); - return k; - -fail: - free(r); - return NULL; -} - -char **replace_env_argv(char **argv, char **env) { - char **r, **i; - unsigned k = 0, l = 0; - - l = strv_length(argv); - - if (!(r = new(char*, l+1))) - return NULL; - - STRV_FOREACH(i, argv) { - - /* If $FOO appears as single word, replace it by the split up variable */ - if ((*i)[0] == '$' && (*i)[1] != '{') { - char *e; - char **w, **m; - unsigned q; - - if ((e = strv_env_get(env, *i+1))) { - - if (!(m = strv_split_quoted(e))) { - r[k] = NULL; - strv_free(r); - return NULL; - } - } else - m = NULL; - - q = strv_length(m); - l = l + q - 1; - - if (!(w = realloc(r, sizeof(char*) * (l+1)))) { - r[k] = NULL; - strv_free(r); - strv_free(m); - return NULL; - } - - r = w; - if (m) { - memcpy(r + k, m, q * sizeof(char*)); - free(m); - } - - k += q; - continue; - } - - /* If ${FOO} appears as part of a word, replace it by the variable as-is */ - if (!(r[k++] = replace_env(*i, env))) { - strv_free(r); - return NULL; - } - } - - r[k] = NULL; - return r; -} - -int columns(void) { - static __thread int parsed_columns = 0; - const char *e; - - if (_likely_(parsed_columns > 0)) - return parsed_columns; - - if ((e = getenv("COLUMNS"))) - parsed_columns = atoi(e); - - if (parsed_columns <= 0) { - struct winsize ws; - zero(ws); - - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) - parsed_columns = ws.ws_col; - } - - if (parsed_columns <= 0) - parsed_columns = 80; - - return parsed_columns; -} - -int running_in_chroot(void) { - struct stat a, b; - - zero(a); - zero(b); - - /* Only works as root */ - - if (stat("/proc/1/root", &a) < 0) - return -errno; - - if (stat("/", &b) < 0) - return -errno; - - return - a.st_dev != b.st_dev || - a.st_ino != b.st_ino; -} - -char *ellipsize(const char *s, unsigned length, unsigned percent) { - size_t l, x; - char *r; - - assert(s); - assert(percent <= 100); - assert(length >= 3); - - l = strlen(s); - - if (l <= 3 || l <= length) - return strdup(s); - - if (!(r = new0(char, length+1))) - return r; - - x = (length * percent) / 100; - - if (x > length - 3) - x = length - 3; - - memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - memcpy(r + x + 3, - s + l - (length - x - 3), - length - x - 3); - - return r; -} - -int touch(const char *path) { - int fd; - - assert(path); - - if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644)) < 0) - return -errno; - - close_nointr_nofail(fd); - return 0; -} - -char *unquote(const char *s, const char* quotes) { - size_t l; - assert(s); - - if ((l = strlen(s)) < 2) - return strdup(s); - - if (strchr(quotes, s[0]) && s[l-1] == s[0]) - return strndup(s+1, l-2); - - return strdup(s); -} - -char *normalize_env_assignment(const char *s) { - char *name, *value, *p, *r; - - p = strchr(s, '='); - - if (!p) { - if (!(r = strdup(s))) - return NULL; - - return strstrip(r); - } - - if (!(name = strndup(s, p - s))) - return NULL; - - if (!(p = strdup(p+1))) { - free(name); - return NULL; - } - - value = unquote(strstrip(p), QUOTES); - free(p); - - if (!value) { - free(name); - return NULL; - } - - if (asprintf(&r, "%s=%s", name, value) < 0) - r = NULL; - - free(value); - free(name); - - return r; -} - -int wait_for_terminate(pid_t pid, siginfo_t *status) { - siginfo_t dummy; - - assert(pid >= 1); - - if (!status) - status = &dummy; - - for (;;) { - zero(*status); - - if (waitid(P_PID, pid, status, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - return -errno; - } - - return 0; - } -} - -int wait_for_terminate_and_warn(const char *name, pid_t pid) { - int r; - siginfo_t status; - - assert(name); - assert(pid > 1); - - if ((r = wait_for_terminate(pid, &status)) < 0) { - log_warning("Failed to wait for %s: %s", name, strerror(-r)); - return r; - } - - if (status.si_code == CLD_EXITED) { - if (status.si_status != 0) { - log_warning("%s failed with error code %i.", name, status.si_status); - return status.si_status; - } - - log_debug("%s succeeded.", name); - return 0; - - } else if (status.si_code == CLD_KILLED || - status.si_code == CLD_DUMPED) { - - log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status)); - return -EPROTO; - } - - log_warning("%s failed due to unknown reason.", name); - return -EPROTO; - -} - -void freeze(void) { - - /* Make sure nobody waits for us on a socket anymore */ - close_all_fds(NULL, 0); - - sync(); - - for (;;) - pause(); -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -DIR *xopendirat(int fd, const char *name, int flags) { - int nfd; - DIR *d; - - if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0) - return NULL; - - if (!(d = fdopendir(nfd))) { - close_nointr_nofail(nfd); - return NULL; - } - - return d; -} - -int signal_from_string_try_harder(const char *s) { - int signo; - assert(s); - - if ((signo = signal_from_string(s)) <= 0) - if (startswith(s, "SIG")) - return signal_from_string(s+3); - - return signo; -} - -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { - - assert(f); - assert(name); - assert(t); - - if (!dual_timestamp_is_set(t)) - return; - - fprintf(f, "%s=%llu %llu\n", - name, - (unsigned long long) t->realtime, - (unsigned long long) t->monotonic); -} - -void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { - unsigned long long a, b; - - assert(value); - assert(t); - - if (sscanf(value, "%lli %llu", &a, &b) != 2) - log_debug("Failed to parse finish timestamp value %s", value); - else { - t->realtime = a; - t->monotonic = b; - } -} - -char *fstab_node_to_udev_node(const char *p) { - char *dn, *t, *u; - int r; - - /* FIXME: to follow udev's logic 100% we need to leave valid - * UTF8 chars unescaped */ - - if (startswith(p, "LABEL=")) { - - if (!(u = unquote(p+6, "\"\'"))) - return NULL; - - t = xescape(u, "/ "); - free(u); - - if (!t) - return NULL; - - r = asprintf(&dn, "/dev/disk/by-label/%s", t); - free(t); - - if (r < 0) - return NULL; - - return dn; - } - - if (startswith(p, "UUID=")) { - - if (!(u = unquote(p+5, "\"\'"))) - return NULL; - - t = xescape(u, "/ "); - free(u); - - if (!t) - return NULL; - - r = asprintf(&dn, "/dev/disk/by-uuid/%s", t); - free(t); - - if (r < 0) - return NULL; - - return dn; - } - - return strdup(p); -} - -void filter_environ(const char *prefix) { - int i, j; - assert(prefix); - - if (!environ) - return; - - for (i = 0, j = 0; environ[i]; i++) { - - if (startswith(environ[i], prefix)) - continue; - - environ[j++] = environ[i]; - } - - environ[j] = NULL; -} - -bool tty_is_vc(const char *tty) { - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - return vtnr_from_tty(tty) >= 0; -} - -int vtnr_from_tty(const char *tty) { - int i, r; - - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - if (!startswith(tty, "tty") ) - return -EINVAL; - - if (tty[3] < '0' || tty[3] > '9') - return -EINVAL; - - r = safe_atoi(tty+3, &i); - if (r < 0) - return r; - - if (i < 0 || i > 63) - return -EINVAL; - - return i; -} - -const char *default_term_for_tty(const char *tty) { - char *active = NULL; - const char *term; - - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - /* Resolve where /dev/console is pointing when determining - * TERM */ - if (streq(tty, "console")) - if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { - /* If multiple log outputs are configured the - * last one is what /dev/console points to */ - if ((tty = strrchr(active, ' '))) - tty++; - else - tty = active; - } - - term = tty_is_vc(tty) ? "TERM=linux" : "TERM=vt100"; - free(active); - - return term; -} - -bool dirent_is_file(struct dirent *de) { - assert(de); - - if (ignore_file(de->d_name)) - return false; - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - return true; -} - -void execute_directory(const char *directory, DIR *d, char *argv[]) { - DIR *_d = NULL; - struct dirent *de; - Hashmap *pids = NULL; - - assert(directory); - - /* Executes all binaries in a directory in parallel and waits - * until all they all finished. */ - - if (!d) { - if (!(_d = opendir(directory))) { - - if (errno == ENOENT) - return; - - log_error("Failed to enumerate directory %s: %m", directory); - return; - } - - d = _d; - } - - if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { - log_error("Failed to allocate set."); - goto finish; - } - - while ((de = readdir(d))) { - char *path; - pid_t pid; - int k; - - if (!dirent_is_file(de)) - continue; - - if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) { - log_error("Out of memory"); - continue; - } - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - free(path); - continue; - } - - if (pid == 0) { - char *_argv[2]; - /* Child */ - - if (!argv) { - _argv[0] = path; - _argv[1] = NULL; - argv = _argv; - } else - if (!argv[0]) - argv[0] = path; - - execv(path, argv); - - log_error("Failed to execute %s: %m", path); - _exit(EXIT_FAILURE); - } - - log_debug("Spawned %s as %lu", path, (unsigned long) pid); - - if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) { - log_error("Failed to add PID to set: %s", strerror(-k)); - free(path); - } - } - - while (!hashmap_isempty(pids)) { - siginfo_t si; - char *path; - - zero(si); - if (waitid(P_ALL, 0, &si, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - log_error("waitid() failed: %m"); - goto finish; - } - - if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { - if (!is_clean_exit(si.si_code, si.si_status)) { - if (si.si_code == CLD_EXITED) - log_error("%s exited with exit status %i.", path, si.si_status); - else - log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status)); - } else - log_debug("%s exited successfully.", path); - - free(path); - } - } - -finish: - if (_d) - closedir(_d); - - if (pids) - hashmap_free_free(pids); -} - -int kill_and_sigcont(pid_t pid, int sig) { - int r; - - r = kill(pid, sig) < 0 ? -errno : 0; - - if (r >= 0) - kill(pid, SIGCONT); - - return r; -} - -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; -} - -bool plymouth_running(void) { - return access("/run/plymouth/pid", F_OK) >= 0; -} - -void parse_syslog_priority(char **p, int *priority) { - int a = 0, b = 0, c = 0; - int k; - - assert(p); - assert(*p); - assert(priority); - - if ((*p)[0] != '<') - return; - - if (!strchr(*p, '>')) - return; - - if ((*p)[2] == '>') { - c = undecchar((*p)[1]); - k = 3; - } else if ((*p)[3] == '>') { - b = undecchar((*p)[1]); - c = undecchar((*p)[2]); - k = 4; - } else if ((*p)[4] == '>') { - a = undecchar((*p)[1]); - b = undecchar((*p)[2]); - c = undecchar((*p)[3]); - k = 5; - } else - return; - - if (a < 0 || b < 0 || c < 0) - return; - - *priority = a*100+b*10+c; - *p += k; -} - -int have_effective_cap(int value) { - cap_t cap; - cap_flag_value_t fv; - int r; - - if (!(cap = cap_get_proc())) - return -errno; - - if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) - r = -errno; - else - r = fv == CAP_SET; - - cap_free(cap); - return r; -} - -char* strshorten(char *s, size_t l) { - assert(s); - - if (l < strlen(s)) - s[l] = 0; - - return s; -} - -static bool hostname_valid_char(char c) { - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '-' || - c == '_' || - c == '.'; -} - -bool hostname_is_valid(const char *s) { - const char *p; - - if (isempty(s)) - return false; - - for (p = s; *p; p++) - if (!hostname_valid_char(*p)) - return false; - - if (p-s > HOST_NAME_MAX) - return false; - - return true; -} - -char* hostname_cleanup(char *s) { - char *p, *d; - - for (p = s, d = s; *p; p++) - if ((*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || - *p == '-' || - *p == '_' || - *p == '.') - *(d++) = *p; - - *d = 0; - - strshorten(s, HOST_NAME_MAX); - return s; -} - -int pipe_eof(int fd) { - struct pollfd pollfd; - int r; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN|POLLHUP; - - r = poll(&pollfd, 1, 0); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents & POLLHUP; -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - const char *fn; - size_t k; - int fd; - - assert(path); - assert(_f); - assert(_temp_path); - - t = new(char, strlen(path) + 1 + 6 + 1); - if (!t) - return -ENOMEM; - - fn = file_name_from_path(path); - k = fn-path; - memcpy(t, path, k); - t[k] = '.'; - stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); - - fd = mkostemp(t, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink(t); - free(t); - return -errno; - } - - *_f = f; - *_temp_path = t; - - return 0; -} - -int terminal_vhangup_fd(int fd) { - assert(fd >= 0); - - if (ioctl(fd, TIOCVHANGUP) < 0) - return -errno; - - return 0; -} - -int terminal_vhangup(const char *name) { - int fd, r; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = terminal_vhangup_fd(fd); - close_nointr_nofail(fd); - - return r; -} - -int vt_disallocate(const char *name) { - int fd, r; - unsigned u; - - /* Deallocate the VT if possible. If not possible - * (i.e. because it is the active one), at least clear it - * entirely (including the scrollback buffer) */ - - if (!startswith(name, "/dev/")) - return -EINVAL; - - if (!tty_is_vc(name)) { - /* So this is not a VT. I guess we cannot deallocate - * it then. But let's at least clear the screen */ - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - loop_write(fd, - "\033[r" /* clear scrolling region */ - "\033[H" /* move home */ - "\033[2J", /* clear screen */ - 10, false); - close_nointr_nofail(fd); - - return 0; - } - - if (!startswith(name, "/dev/tty")) - return -EINVAL; - - r = safe_atou(name+8, &u); - if (r < 0) - return r; - - if (u <= 0) - return -EINVAL; - - /* Try to deallocate */ - fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = ioctl(fd, VT_DISALLOCATE, u); - close_nointr_nofail(fd); - - if (r >= 0) - return 0; - - if (errno != EBUSY) - return -errno; - - /* Couldn't deallocate, so let's clear it fully with - * scrollback */ - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - loop_write(fd, - "\033[r" /* clear scrolling region */ - "\033[H" /* move home */ - "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ - 10, false); - close_nointr_nofail(fd); - - return 0; -} - - -static int file_is_conf(const struct dirent *d, const char *suffix) { - assert(d); - - if (ignore_file(d->d_name)) - return 0; - - if (d->d_type != DT_REG && - d->d_type != DT_LNK && - d->d_type != DT_UNKNOWN) - return 0; - - return endswith(d->d_name, suffix); -} - -static int files_add(Hashmap *h, const char *path, const char *suffix) { - DIR *dir; - struct dirent buffer, *de; - int r = 0; - - dir = opendir(path); - if (!dir) { - if (errno == ENOENT) - return 0; - return -errno; - } - - for (;;) { - int k; - char *p, *f; - - k = readdir_r(dir, &buffer, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - if (!file_is_conf(de, suffix)) - continue; - - if (asprintf(&p, "%s/%s", path, de->d_name) < 0) { - r = -ENOMEM; - goto finish; - } - - f = canonicalize_file_name(p); - if (!f) { - log_error("Failed to canonicalize file name '%s': %m", p); - free(p); - continue; - } - free(p); - - log_debug("found: %s\n", f); - if (hashmap_put(h, file_name_from_path(f), f) <= 0) - free(f); - } - -finish: - closedir(dir); - return r; -} - -static int base_cmp(const void *a, const void *b) { - const char *s1, *s2; - - s1 = *(char * const *)a; - s2 = *(char * const *)b; - return strcmp(file_name_from_path(s1), file_name_from_path(s2)); -} - -int conf_files_list(char ***strv, const char *suffix, const char *dir, ...) { - Hashmap *fh = NULL; - char **dirs = NULL; - char **files = NULL; - char **p; - va_list ap; - int r = 0; - - va_start(ap, dir); - dirs = strv_new_ap(dir, ap); - va_end(ap); - if (!dirs) { - r = -ENOMEM; - goto finish; - } - if (!strv_path_canonicalize(dirs)) { - r = -ENOMEM; - goto finish; - } - if (!strv_uniq(dirs)) { - r = -ENOMEM; - goto finish; - } - - fh = hashmap_new(string_hash_func, string_compare_func); - if (!fh) { - r = -ENOMEM; - goto finish; - } - - STRV_FOREACH(p, dirs) { - if (files_add(fh, *p, suffix) < 0) { - log_error("Failed to search for files."); - r = -EINVAL; - goto finish; - } - } - - files = hashmap_get_strv(fh); - if (files == NULL) { - log_error("Failed to compose list of files."); - r = -ENOMEM; - goto finish; - } - - qsort(files, hashmap_size(fh), sizeof(char *), base_cmp); - -finish: - strv_free(dirs); - hashmap_free(fh); - *strv = files; - return r; -} - -int hwclock_is_localtime(void) { - FILE *f; - bool local = false; - - /* - * The third line of adjtime is "UTC" or "LOCAL" or nothing. - * # /etc/adjtime - * 0.0 0 0 - * 0 - * UTC - */ - f = fopen("/etc/adjtime", "re"); - if (f) { - char line[LINE_MAX]; - bool b; - - b = fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f); - - fclose(f); - - if (!b) - return -EIO; - - - truncate_nl(line); - local = streq(line, "LOCAL"); - - } else if (errno != -ENOENT) - return -errno; - - return local; -} - -int hwclock_apply_localtime_delta(int *min) { - const struct timeval *tv_null = NULL; - struct timespec ts; - struct tm *tm; - int minuteswest; - struct timezone tz; - - assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); - assert_se(tm = localtime(&ts.tv_sec)); - minuteswest = tm->tm_gmtoff / 60; - - tz.tz_minuteswest = -minuteswest; - tz.tz_dsttime = 0; /* DST_NONE*/ - - /* - * If the hardware clock does not run in UTC, but in local time: - * The very first time we set the kernel's timezone, it will warp - * the clock so that it runs in UTC instead of local time. - */ - if (settimeofday(tv_null, &tz) < 0) - return -errno; - if (min) - *min = minuteswest; - return 0; -} - -int hwclock_reset_localtime_delta(void) { - const struct timeval *tv_null = NULL; - struct timezone tz; - - tz.tz_minuteswest = 0; - tz.tz_dsttime = 0; /* DST_NONE*/ - - if (settimeofday(tv_null, &tz) < 0) - return -errno; - - return 0; -} - -int hwclock_get_time(struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - /* This leaves the timezone fields of struct tm - * uninitialized! */ - if (ioctl(fd, RTC_RD_TIME, tm) < 0) - err = -errno; - - /* We don't now daylight saving, so we reset this in order not - * to confused mktime(). */ - tm->tm_isdst = -1; - - close_nointr_nofail(fd); - - return err; -} - -int hwclock_set_time(const struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - if (ioctl(fd, RTC_SET_TIME, tm) < 0) - err = -errno; - - close_nointr_nofail(fd); - - return err; -} - -int copy_file(const char *from, const char *to) { - int r, fdf, fdt; - - assert(from); - assert(to); - - fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fdf < 0) - return -errno; - - fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644); - if (fdt < 0) { - close_nointr_nofail(fdf); - return -errno; - } - - for (;;) { - char buf[PIPE_BUF]; - ssize_t n, k; - - n = read(fdf, buf, sizeof(buf)); - if (n < 0) { - r = -errno; - - close_nointr_nofail(fdf); - close_nointr(fdt); - unlink(to); - - return r; - } - - if (n == 0) - break; - - errno = 0; - k = loop_write(fdt, buf, n, false); - if (n != k) { - r = k < 0 ? k : (errno ? -errno : -EIO); - - close_nointr_nofail(fdf); - close_nointr(fdt); - - unlink(to); - return r; - } - } - - close_nointr_nofail(fdf); - r = close_nointr(fdt); - - if (r < 0) { - unlink(to); - return r; - } - - return 0; -} - -int symlink_or_copy(const char *from, const char *to) { - char *pf = NULL, *pt = NULL; - struct stat a, b; - int r; - - assert(from); - assert(to); - - if (parent_of_path(from, &pf) < 0 || - parent_of_path(to, &pt) < 0) { - r = -ENOMEM; - goto finish; - } - - if (stat(pf, &a) < 0 || - stat(pt, &b) < 0) { - r = -errno; - goto finish; - } - - if (a.st_dev != b.st_dev) { - free(pf); - free(pt); - - return copy_file(from, to); - } - - if (symlink(from, to) < 0) { - r = -errno; - goto finish; - } - - r = 0; - -finish: - free(pf); - free(pt); - - return r; -} - -int symlink_or_copy_atomic(const char *from, const char *to) { - char *t, *x; - const char *fn; - size_t k; - unsigned long long ull; - unsigned i; - int r; - - assert(from); - assert(to); - - t = new(char, strlen(to) + 1 + 16 + 1); - if (!t) - return -ENOMEM; - - fn = file_name_from_path(to); - k = fn-to; - memcpy(t, to, k); - t[k] = '.'; - x = stpcpy(t+k+1, fn); - - ull = random_ull(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(ull & 0xF); - ull >>= 4; - } - - *x = 0; - - r = symlink_or_copy(from, t); - if (r < 0) { - unlink(t); - free(t); - return r; - } - - if (rename(t, to) < 0) { - r = -errno; - unlink(t); - free(t); - return r; - } - - free(t); - return r; -} - -int audit_session_from_pid(pid_t pid, uint32_t *id) { - char *p, *s; - uint32_t u; - int r; - - assert(pid >= 1); - assert(id); - - if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0) - return -ENOENT; - - if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - if (r < 0) - return r; - - r = safe_atou32(s, &u); - free(s); - - if (r < 0) - return r; - - if (u == (uint32_t) -1 || u <= 0) - return -ENOENT; - - *id = u; - return 0; -} - -bool display_is_local(const char *display) { - assert(display); - - return - display[0] == ':' && - display[1] >= '0' && - display[1] <= '9'; -} - -int socket_from_display(const char *display, char **path) { - size_t k; - char *f, *c; - - assert(display); - assert(path); - - if (!display_is_local(display)) - return -EINVAL; - - k = strspn(display+1, "0123456789"); - - f = new(char, sizeof("/tmp/.X11-unix/X") + k); - if (!f) - return -ENOMEM; - - c = stpcpy(f, "/tmp/.X11-unix/X"); - memcpy(c, display+1, k); - c[k] = 0; - - *path = f; - - return 0; -} - -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) { - struct passwd *p; - uid_t u; - - assert(username); - assert(*username); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - - if (uid) - *uid = 0; - - if (gid) - *gid = 0; - - if (home) - *home = "/root"; - return 0; - } - - if (parse_uid(*username, &u) >= 0) { - errno = 0; - p = getpwuid(u); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno != 0 ? -errno : -ESRCH; - - if (uid) - *uid = p->pw_uid; - - if (gid) - *gid = p->pw_gid; - - if (home) - *home = p->pw_dir; - - return 0; -} - -int get_group_creds(const char **groupname, gid_t *gid) { - struct group *g; - gid_t id; - - assert(groupname); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*groupname, "root") || streq(*groupname, "0")) { - *groupname = "root"; - - if (gid) - *gid = 0; - - return 0; - } - - if (parse_gid(*groupname, &id) >= 0) { - errno = 0; - g = getgrgid(id); - - if (g) - *groupname = g->gr_name; - } else { - errno = 0; - g = getgrnam(*groupname); - } - - if (!g) - return errno != 0 ? -errno : -ESRCH; - - if (gid) - *gid = g->gr_gid; - - return 0; -} - -int glob_exists(const char *path) { - glob_t g; - int r, k; - - assert(path); - - zero(g); - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - r = 0; - else if (k == GLOB_NOSPACE) - r = -ENOMEM; - else if (k == 0) - r = !strv_isempty(g.gl_pathv); - else - r = errno ? -errno : -EIO; - - globfree(&g); - - return r; -} - -int dirent_ensure_type(DIR *d, struct dirent *de) { - struct stat st; - - assert(d); - assert(de); - - if (de->d_type != DT_UNKNOWN) - return 0; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; - - de->d_type = - S_ISREG(st.st_mode) ? DT_REG : - S_ISDIR(st.st_mode) ? DT_DIR : - S_ISLNK(st.st_mode) ? DT_LNK : - S_ISFIFO(st.st_mode) ? DT_FIFO : - S_ISSOCK(st.st_mode) ? DT_SOCK : - S_ISCHR(st.st_mode) ? DT_CHR : - S_ISBLK(st.st_mode) ? DT_BLK : - DT_UNKNOWN; - - return 0; -} - -int in_search_path(const char *path, char **search) { - char **i, *parent; - int r; - - r = parent_of_path(path, &parent); - if (r < 0) - return r; - - r = 0; - - STRV_FOREACH(i, search) { - if (path_equal(parent, *i)) { - r = 1; - break; - } - } - - free(parent); - - return r; -} - -int get_files_in_directory(const char *path, char ***list) { - DIR *d; - int r = 0; - unsigned n = 0; - char **l = NULL; - - assert(path); - - /* Returns all files in a directory in *list, and the number - * of files as return value. If list is NULL returns only the - * number */ - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent buffer, *de; - int k; - - k = readdir_r(d, &buffer, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - if (list) { - if ((unsigned) r >= n) { - char **t; - - n = MAX(16, 2*r); - t = realloc(l, sizeof(char*) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } - - l = t; - } - - assert((unsigned) r < n); - - l[r] = strdup(de->d_name); - if (!l[r]) { - r = -ENOMEM; - goto finish; - } - - l[++r] = NULL; - } else - r++; - } - -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (list) - *list = l; - } else - strv_free(l); - - return r; -} - -char *join(const char *x, ...) { - va_list ap; - size_t l; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - l += strlen(t); - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -bool is_main_thread(void) { - static __thread int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - -int block_get_whole_disk(dev_t d, dev_t *ret) { - char *p, *s; - int r; - unsigned n, m; - - assert(ret); - - /* If it has a queue this is good enough for us */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = d; - return 0; - } - - /* If it is a partition find the originating device */ - if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r < 0) - return -ENOENT; - - /* Get parent dev_t */ - if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - - if (r < 0) - return r; - - r = sscanf(s, "%u:%u", &m, &n); - free(s); - - if (r != 2) - return -EINVAL; - - /* Only return this if it is really good enough for us. */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = makedev(m, n); - return 0; - } - - return -ENOENT; -} - -int file_is_sticky(const char *p) { - struct stat st; - - assert(p); - - if (lstat(p, &st) < 0) - return -errno; - - return - st.st_uid == 0 && - (st.st_mode & S_ISVTX); -} - -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP(log_level, int); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP(sched_policy, int); - -static const char* const rlimit_table[] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -DEFINE_STRING_TABLE_LOOKUP(ip_tos, int); - -static const char *const __signal_table[] = { - [SIGHUP] = "HUP", - [SIGINT] = "INT", - [SIGQUIT] = "QUIT", - [SIGILL] = "ILL", - [SIGTRAP] = "TRAP", - [SIGABRT] = "ABRT", - [SIGBUS] = "BUS", - [SIGFPE] = "FPE", - [SIGKILL] = "KILL", - [SIGUSR1] = "USR1", - [SIGSEGV] = "SEGV", - [SIGUSR2] = "USR2", - [SIGPIPE] = "PIPE", - [SIGALRM] = "ALRM", - [SIGTERM] = "TERM", -#ifdef SIGSTKFLT - [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ -#endif - [SIGCHLD] = "CHLD", - [SIGCONT] = "CONT", - [SIGSTOP] = "STOP", - [SIGTSTP] = "TSTP", - [SIGTTIN] = "TTIN", - [SIGTTOU] = "TTOU", - [SIGURG] = "URG", - [SIGXCPU] = "XCPU", - [SIGXFSZ] = "XFSZ", - [SIGVTALRM] = "VTALRM", - [SIGPROF] = "PROF", - [SIGWINCH] = "WINCH", - [SIGIO] = "IO", - [SIGPWR] = "PWR", - [SIGSYS] = "SYS" -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); - -const char *signal_to_string(int signo) { - static __thread char buf[12]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf) - 1, "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf) - 1, "%d", signo); - char_array_0(buf); - return buf; -} - -int signal_from_string(const char *s) { - int signo; - int offset = 0; - unsigned u; - - signo =__signal_from_string(s); - if (signo > 0) - return signo; - - if (startswith(s, "RTMIN+")) { - s += 6; - offset = SIGRTMIN; - } - if (safe_atou(s, &u) >= 0) { - signo = (int) u + offset; - if (signo > 0 && signo < _NSIG) - return signo; - } - return -1; -} - -bool kexec_loaded(void) { - bool loaded = false; - char *s; - - if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { - if (s[0] == '1') - loaded = true; - free(s); - } - return loaded; -} - -int strdup_or_null(const char *a, char **b) { - char *c; - - assert(b); - - if (!a) { - *b = NULL; - return 0; - } - - c = strdup(a); - if (!c) - return -ENOMEM; - - *b = c; - return 0; -} diff --git a/src/util.h b/src/util.h deleted file mode 100644 index ccbe8a3..0000000 --- a/src/util.h +++ /dev/null @@ -1,509 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooutilhfoo -#define fooutilhfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" - -typedef uint64_t usec_t; - -typedef struct dual_timestamp { - usec_t realtime; - usec_t monotonic; -} dual_timestamp; - -#define MSEC_PER_SEC 1000ULL -#define USEC_PER_SEC 1000000ULL -#define USEC_PER_MSEC 1000ULL -#define NSEC_PER_SEC 1000000000ULL -#define NSEC_PER_MSEC 1000000ULL -#define NSEC_PER_USEC 1000ULL - -#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC) -#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE) -#define USEC_PER_DAY (24ULL*USEC_PER_HOUR) -#define USEC_PER_WEEK (7ULL*USEC_PER_DAY) -#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC) -#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC) - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;\n" - -#define FORMAT_TIMESTAMP_MAX 64 -#define FORMAT_TIMESTAMP_PRETTY_MAX 256 -#define FORMAT_TIMESPAN_MAX 64 - -#define ANSI_HIGHLIGHT_ON "\x1B[1;31m" -#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" -#define ANSI_HIGHLIGHT_OFF "\x1B[0m" - -usec_t now(clockid_t clock); - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts); -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); - -#define dual_timestamp_is_set(ts) ((ts)->realtime > 0) - -usec_t timespec_load(const struct timespec *ts); -struct timespec *timespec_store(struct timespec *ts, usec_t u); - -usec_t timeval_load(const struct timeval *tv); -struct timeval *timeval_store(struct timeval *tv, usec_t u); - -size_t page_size(void); -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) - -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b); - -#define new(t, n) ((t*) malloc(sizeof(t)*(n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) - -#define malloc0(n) (calloc((n), 1)) - -static inline const char* yes_no(bool b) { - return b ? "yes" : "no"; -} - -static inline const char* strempty(const char *s) { - return s ? s : ""; -} - -static inline const char* strnull(const char *s) { - return s ? s : "(null)"; -} - -static inline const char *strna(const char *s) { - return s ? s : "n/a"; -} - -static inline bool is_path_absolute(const char *p) { - return *p == '/'; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -bool endswith(const char *s, const char *postfix); -bool startswith(const char *s, const char *prefix); -bool startswith_no_case(const char *s, const char *prefix); - -bool first_word(const char *s, const char *word); - -int close_nointr(int fd); -void close_nointr_nofail(int fd); -void close_many(const int fds[], unsigned n_fd); - -int parse_boolean(const char *v); -int parse_usec(const char *t, usec_t *usec); -int parse_bytes(const char *t, off_t *bytes); -int parse_pid(const char *s, pid_t* ret_pid); -int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -#if __WORDSIZE == 32 -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); - return safe_atoi(s, (int*) ret_u); -} -#else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); -} -#endif - -static inline int safe_atou32(const char *s, uint32_t *ret_u) { - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} - -static inline int safe_atoi32(const char *s, int32_t *ret_i) { - assert_cc(sizeof(int32_t) == sizeof(int)); - return safe_atoi(s, (int*) ret_i); -} - -static inline int safe_atou64(const char *s, uint64_t *ret_u) { - assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} - -static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); -} - -char *split(const char *c, size_t *l, const char *separator, char **state); -char *split_quoted(const char *c, size_t *l, char **state); - -#define FOREACH_WORD(word, length, s, state) \ - for ((state) = NULL, (word) = split((s), &(length), WHITESPACE, &(state)); (word); (word) = split((s), &(length), WHITESPACE, &(state))) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state))) - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state))) - -char **split_path_and_make_absolute(const char *p); - -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); -int get_starttime_of_pid(pid_t pid, unsigned long long *st); - -int write_one_line_file(const char *fn, const char *line); -int write_one_line_file_atomic(const char *fn, const char *line); -int read_one_line_file(const char *fn, char **line); -int read_full_file(const char *fn, char **contents, size_t *size); - -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; -int load_env_file(const char *fname, char ***l); -int write_env_file(const char *fname, char **l); - -char *strappend(const char *s, const char *suffix); -char *strnappend(const char *s, const char *suffix, size_t length); - -char *replace_env(const char *format, char **env); -char **replace_env_argv(char **argv, char **env); - -int readlink_malloc(const char *p, char **r); -int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); - -char *file_name_from_path(const char *p); -bool is_path(const char *p); - -bool path_is_absolute(const char *p); -char *path_make_absolute(const char *p, const char *prefix); -char *path_make_absolute_cwd(const char *p); - -char **strv_path_make_absolute_cwd(char **l); -char **strv_path_canonicalize(char **l); -char **strv_path_remove_empty(char **l); - -int reset_all_signal_handlers(void); - -char *strstrip(char *s); -char *delete_chars(char *s, const char *bad); -char *truncate_nl(char *s); - -char *file_in_same_dir(const char *path, const char *filename); -int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid); -int mkdir_parents(const char *path, mode_t mode); -int mkdir_p(const char *path, mode_t mode); - -int parent_of_path(const char *path, char **parent); - -int rmdir_parents(const char *path, const char *stop); - -int get_process_name(pid_t pid, char **name); -int get_process_cmdline(pid_t pid, size_t max_length, char **line); - -char hexchar(int x); -int unhexchar(char c); -char octchar(int x); -int unoctchar(char c); -char decchar(int x); -int undecchar(char c); - -char *cescape(const char *s); -char *cunescape(const char *s); -char *cunescape_length(const char *s, size_t length); - -char *xescape(const char *s, const char *bad); - -char *bus_path_escape(const char *s); -char *bus_path_unescape(const char *s); - -char *path_kill_slashes(char *path); - -bool path_startswith(const char *path, const char *prefix); -bool path_equal(const char *a, const char *b); - -char *ascii_strlower(char *path); - -bool dirent_is_file(struct dirent *de); -bool ignore_file(const char *filename); - -bool chars_intersect(const char *a, const char *b); - -char *format_timestamp(char *buf, size_t l, usec_t t); -char *format_timestamp_pretty(char *buf, size_t l, usec_t t); -char *format_timespan(char *buf, size_t l, usec_t t); - -int make_stdio(int fd); -int make_null_stdio(void); - -unsigned long long random_ull(void); - -#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - scope const char *name##_to_string(type i) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } \ - scope type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && \ - u < ELEMENTSOF(name##_table)) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) - -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -int close_all_fds(const int except[], unsigned n_except); - -bool fstype_is_network(const char *fstype); - -int chvt(int vt); - -int read_one_char(FILE *f, char *ret, bool *need_nl); -int ask(char *ret, const char *replies, const char *text, ...); - -int reset_terminal_fd(int fd); -int reset_terminal(const char *name); - -int open_terminal(const char *name, int mode); -int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm); -int release_terminal(void); - -int flush_fd(int fd); - -int ignore_signals(int sig, ...); -int default_signals(int sig, ...); -int sigaction_many(const struct sigaction *sa, ...); - -int close_pipe(int p[]); -int fopen_temporary(const char *path, FILE **_f, char **_temp_path); - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); - -int path_is_mount_point(const char *path, bool allow_symlink); - -bool is_device_path(const char *path); - -int dir_is_empty(const char *path); - -void rename_process(const char name[8]); - -void sigset_add_many(sigset_t *ss, ...); - -char* gethostname_malloc(void); -char* getlogname_malloc(void); - -int getttyname_malloc(int fd, char **r); -int getttyname_harder(int fd, char **r); - -int get_ctty_devnr(pid_t pid, dev_t *d); -int get_ctty(pid_t, dev_t *_devnr, char **r); - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); - -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); - -int pipe_eof(int fd); - -cpu_set_t* cpu_set_malloc(unsigned *ncpus); - -void status_vprintf(const char *format, va_list ap); -void status_printf(const char *format, ...); -void status_welcome(void); - -int columns(void); - -int running_in_chroot(void); - -char *ellipsize(const char *s, unsigned length, unsigned percent); - -int touch(const char *path); - -char *unquote(const char *s, const char *quotes); -char *normalize_env_assignment(const char *s); - -int wait_for_terminate(pid_t pid, siginfo_t *status); -int wait_for_terminate_and_warn(const char *name, pid_t pid); - -_noreturn_ void freeze(void); - -bool null_or_empty(struct stat *st); -int null_or_empty_path(const char *fn); - -DIR *xopendirat(int dirfd, const char *name, int flags); - -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); -void dual_timestamp_deserialize(const char *value, dual_timestamp *t); - -char *fstab_node_to_udev_node(const char *p); - -void filter_environ(const char *prefix); - -bool tty_is_vc(const char *tty); -int vtnr_from_tty(const char *tty); -const char *default_term_for_tty(const char *tty); - -void execute_directory(const char *directory, DIR *_d, char *argv[]); - -int kill_and_sigcont(pid_t pid, int sig); - -bool nulstr_contains(const char*nulstr, const char *needle); - -bool plymouth_running(void); - -void parse_syslog_priority(char **p, int *priority); - -int have_effective_cap(int value); - -bool hostname_is_valid(const char *s); -char* hostname_cleanup(char *s); - -char* strshorten(char *s, size_t l); - -int terminal_vhangup_fd(int fd); -int terminal_vhangup(const char *name); - -int vt_disallocate(const char *name); - -int copy_file(const char *from, const char *to); -int symlink_or_copy(const char *from, const char *to); -int symlink_or_copy_atomic(const char *from, const char *to); - -int fchmod_umask(int fd, mode_t mode); - -int conf_files_list(char ***strv, const char *suffix, const char *dir, ...); - -int hwclock_is_localtime(void); -int hwclock_apply_localtime_delta(int *min); -int hwclock_reset_localtime_delta(void); -int hwclock_get_time(struct tm *tm); -int hwclock_set_time(const struct tm *tm); - -int audit_session_from_pid(pid_t pid, uint32_t *id); - -bool display_is_local(const char *display); -int socket_from_display(const char *display, char **path); - -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home); -int get_group_creds(const char **groupname, gid_t *gid); - -int glob_exists(const char *path); - -int dirent_ensure_type(DIR *d, struct dirent *de); - -int in_search_path(const char *path, char **search); -int get_files_in_directory(const char *path, char ***list); - -char *join(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -bool in_charset(const char *s, const char* charset); - -int block_get_whole_disk(dev_t d, dev_t *ret); - -int file_is_sticky(const char *p); - -int strdup_or_null(const char *a, char **b); - -#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)) - -const char *ioprio_class_to_string(int i); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i); -int sigchld_code_from_string(const char *s); - -const char *log_facility_unshifted_to_string(int i); -int log_facility_unshifted_from_string(const char *s); - -const char *log_level_to_string(int i); -int log_level_from_string(const char *s); - -const char *sched_policy_to_string(int i); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i); -int rlimit_from_string(const char *s); - -const char *ip_tos_to_string(int i); -int ip_tos_from_string(const char *s); - -const char *signal_to_string(int i); -int signal_from_string(const char *s); - -int signal_from_string_try_harder(const char *s); - -extern int saved_argc; -extern char **saved_argv; - -bool kexec_loaded(void); - -#endif diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c deleted file mode 100644 index b03a3e7..0000000 --- a/src/utmp-wtmp.c +++ /dev/null @@ -1,424 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "utmp-wtmp.h" - -int utmp_get_runlevel(int *runlevel, int *previous) { - struct utmpx lookup, *found; - int r; - const char *e; - - assert(runlevel); - - /* If these values are set in the environment this takes - * precedence. Presumably, sysvinit does this to work around a - * race condition that would otherwise exist where we'd always - * go to disk and hence might read runlevel data that might be - * very new and does not apply to the current script being - * executed. */ - - if ((e = getenv("RUNLEVEL")) && e[0] > 0) { - *runlevel = e[0]; - - if (previous) { - /* $PREVLEVEL seems to be an Upstart thing */ - - if ((e = getenv("PREVLEVEL")) && e[0] > 0) - *previous = e[0]; - else - *previous = 0; - } - - return 0; - } - - if (utmpxname(_PATH_UTMPX) < 0) - return -errno; - - setutxent(); - - zero(lookup); - lookup.ut_type = RUN_LVL; - - if (!(found = getutxid(&lookup))) - r = -errno; - else { - int a, b; - - a = found->ut_pid & 0xFF; - b = (found->ut_pid >> 8) & 0xFF; - - if (a < 0 || b < 0) - r = -EIO; - else { - *runlevel = a; - - if (previous) - *previous = b; - r = 0; - } - } - - endutxent(); - - return r; -} - -static void init_timestamp(struct utmpx *store, usec_t t) { - assert(store); - - zero(*store); - - if (t <= 0) - t = now(CLOCK_REALTIME); - - store->ut_tv.tv_sec = t / USEC_PER_SEC; - store->ut_tv.tv_usec = t % USEC_PER_SEC; -} - -static void init_entry(struct utmpx *store, usec_t t) { - struct utsname uts; - - assert(store); - - init_timestamp(store, t); - - zero(uts); - - if (uname(&uts) >= 0) - strncpy(store->ut_host, uts.release, sizeof(store->ut_host)); - - strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */ - strncpy(store->ut_id, "~~", sizeof(store->ut_id)); -} - -static int write_entry_utmp(const struct utmpx *store) { - int r; - - assert(store); - - /* utmp is similar to wtmp, but there is only one entry for - * each entry type resp. user; i.e. basically a key/value - * table. */ - - if (utmpxname(_PATH_UTMPX) < 0) - return -errno; - - setutxent(); - - if (!pututxline(store)) - r = -errno; - else - r = 0; - - endutxent(); - - return r; -} - -static int write_entry_wtmp(const struct utmpx *store) { - assert(store); - - /* wtmp is a simple append-only file where each entry is - simply appended to * the end; i.e. basically a log. */ - - errno = 0; - updwtmpx(_PATH_WTMPX, store); - return -errno; -} - -static int write_entry_both(const struct utmpx *store) { - int r, s; - - r = write_entry_utmp(store); - s = write_entry_wtmp(store); - - if (r >= 0) - r = s; - - /* If utmp/wtmp have been disabled, that's a good thing, hence - * ignore the errors */ - if (r == -ENOENT) - r = 0; - - return r; -} - -int utmp_put_shutdown(usec_t t) { - struct utmpx store; - - init_entry(&store, t); - - store.ut_type = RUN_LVL; - strncpy(store.ut_user, "shutdown", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -int utmp_put_reboot(usec_t t) { - struct utmpx store; - - init_entry(&store, t); - - store.ut_type = BOOT_TIME; - strncpy(store.ut_user, "reboot", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -static const char *sanitize_id(const char *id) { - size_t l; - - assert(id); - l = strlen(id); - - if (l <= sizeof(((struct utmpx*) NULL)->ut_id)) - return id; - - return id + l - sizeof(((struct utmpx*) NULL)->ut_id); -} - -int utmp_put_init_process(usec_t t, const char *id, pid_t pid, pid_t sid, const char *line) { - struct utmpx store; - - assert(id); - - init_timestamp(&store, t); - - store.ut_type = INIT_PROCESS; - store.ut_pid = pid; - store.ut_session = sid; - - strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id)); - - if (line) - strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line)); - - return write_entry_both(&store); -} - -int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { - struct utmpx lookup, store, *found; - - assert(id); - - setutxent(); - - zero(lookup); - lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ - strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id)); - - if (!(found = getutxid(&lookup))) - return 0; - - if (found->ut_pid != pid) - return 0; - - zero(store); - - memcpy(&store, &lookup, sizeof(store)); - store.ut_type = DEAD_PROCESS; - store.ut_exit.e_termination = code; - store.ut_exit.e_exit = status; - - zero(store.ut_user); - zero(store.ut_host); - zero(store.ut_tv); - - return write_entry_both(&store); -} - - -int utmp_put_runlevel(usec_t t, int runlevel, int previous) { - struct utmpx store; - int r; - - assert(runlevel > 0); - - if (previous <= 0) { - /* Find the old runlevel automatically */ - - if ((r = utmp_get_runlevel(&previous, NULL)) < 0) { - if (r != -ESRCH) - return r; - - previous = 0; - } - } - - if (previous == runlevel) - return 0; - - init_entry(&store, t); - - store.ut_type = RUN_LVL; - store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8); - strncpy(store.ut_user, "runlevel", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -#define TIMEOUT_MSEC 50 - -static int write_to_terminal(const char *tty, const char *message) { - int fd, r; - const char *p; - size_t left; - usec_t end; - - assert(tty); - assert(message); - - if ((fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC)) < 0) - return -errno; - - if (!isatty(fd)) { - r = -errno; - goto finish; - } - - p = message; - left = strlen(message); - - end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC; - - while (left > 0) { - ssize_t n; - struct pollfd pollfd; - usec_t t; - int k; - - t = now(CLOCK_MONOTONIC); - - if (t >= end) { - r = -ETIME; - goto finish; - } - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLOUT; - - if ((k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC)) < 0) - return -errno; - - if (k <= 0) { - r = -ETIME; - goto finish; - } - - if ((n = write(fd, p, left)) < 0) { - - if (errno == EAGAIN) - continue; - - r = -errno; - goto finish; - } - - assert((size_t) n <= left); - - p += n; - left -= n; - } - - r = 0; - -finish: - close_nointr_nofail(fd); - - return r; -} - -int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) { - struct utmpx *u; - char date[FORMAT_TIMESTAMP_MAX]; - char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL; - int r; - - if (!(hn = gethostname_malloc()) || - !(un = getlogname_malloc())) { - r = -ENOMEM; - goto finish; - } - - getttyname_harder(STDIN_FILENO, &tty); - - if (asprintf(&text, - "\a\r\n" - "Broadcast message from %s@%s%s%s (%s):\r\n\r\n" - "%s\r\n\r\n", - un, hn, - tty ? " on " : "", strempty(tty), - format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)), - message) < 0) { - r = -ENOMEM; - goto finish; - } - - setutxent(); - - r = 0; - - while ((u = getutxent())) { - int q; - const char *path; - char *buf = NULL; - - if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0) - continue; - - if (path_startswith(u->ut_line, "/dev/")) - path = u->ut_line; - else { - if (asprintf(&buf, "/dev/%s", u->ut_line) < 0) { - r = -ENOMEM; - goto finish; - } - - path = buf; - } - - if (!match_tty || match_tty(path)) - if ((q = write_to_terminal(path, text)) < 0) - r = q; - - free(buf); - } - -finish: - free(hn); - free(un); - free(tty); - free(text); - - return r; -} diff --git a/src/utmp-wtmp.h b/src/utmp-wtmp.h deleted file mode 100644 index 4054aff..0000000 --- a/src/utmp-wtmp.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooutmpwtmphfoo -#define fooutmpwtmphfoo - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include "util.h" - -int utmp_get_runlevel(int *runlevel, int *previous); - -int utmp_put_shutdown(usec_t timestamp); -int utmp_put_reboot(usec_t timestamp); -int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous); - -int utmp_put_dead_process(const char *id, pid_t pid, int code, int status); -int utmp_put_init_process(usec_t timestamp, const char *id, pid_t pid, pid_t sid, const char *line); - -int utmp_wall(const char *message, bool (*match_tty)(const char *tty)); - -#endif diff --git a/src/vconsole-setup.c b/src/vconsole-setup.c deleted file mode 100644 index c5f3628..0000000 --- a/src/vconsole-setup.c +++ /dev/null @@ -1,459 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "log.h" -#include "macro.h" -#include "virt.h" - -static bool is_vconsole(int fd) { - unsigned char data[1]; - - data[0] = TIOCL_GETFGCONSOLE; - return ioctl(fd, TIOCLINUX, data) >= 0; -} - -static bool is_locale_utf8(void) { - const char *set; - - if (!setlocale(LC_ALL, "")) - return true; - - set = nl_langinfo(CODESET); - if (!set) - return true; - - return streq(set, "UTF-8"); -} - -static int disable_utf8(int fd) { - int r = 0, k; - - if (ioctl(fd, KDSKBMODE, K_XLATE) < 0) - r = -errno; - - if (loop_write(fd, "\033%@", 3, false) < 0) - r = -errno; - - if ((k = write_one_line_file("/sys/module/vt/parameters/default_utf8", "0")) < 0) - r = k; - - if (r < 0) - log_warning("Failed to disable UTF-8: %s", strerror(errno)); - - return r; -} - -static int load_keymap(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) { - const char *args[8]; - int i = 0; - pid_t pid; - - if (isempty(map)) { - /* An empty map means kernel map */ - *_pid = 0; - return 0; - } - - args[i++] = KBD_LOADKEYS; - args[i++] = "-q"; - args[i++] = "-C"; - args[i++] = vc; - if (utf8) - args[i++] = "-u"; - args[i++] = map; - if (map_toggle) - args[i++] = map_toggle; - args[i++] = NULL; - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - return -errno; - } else if (pid == 0) { - execv(args[0], (char **) args); - _exit(EXIT_FAILURE); - } - - *_pid = pid; - return 0; -} - -static int load_font(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) { - const char *args[9]; - int i = 0; - pid_t pid; - - if (isempty(font)) { - /* An empty font means kernel font */ - *_pid = 0; - return 0; - } - - args[i++] = KBD_SETFONT; - args[i++] = "-C"; - args[i++] = vc; - args[i++] = font; - if (map) { - args[i++] = "-m"; - args[i++] = map; - } - if (unimap) { - args[i++] = "-u"; - args[i++] = unimap; - } - args[i++] = NULL; - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - return -errno; - } else if (pid == 0) { - execv(args[0], (char **) args); - _exit(EXIT_FAILURE); - } - - *_pid = pid; - return 0; -} - -int main(int argc, char **argv) { - const char *vc; - char *vc_keymap = NULL; - char *vc_keymap_toggle = NULL; - char *vc_font = NULL; - char *vc_font_map = NULL; - char *vc_font_unimap = NULL; -#ifdef TARGET_GENTOO - char *vc_unicode = NULL; -#endif -#ifdef TARGET_MANDRIVA - char *vc_keytable = NULL; -#endif - int fd = -1; - bool utf8; - int r = EXIT_FAILURE; - pid_t font_pid = 0, keymap_pid = 0; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if (argv[1]) - vc = argv[1]; - else - vc = "/dev/tty0"; - - if ((fd = open_terminal(vc, O_RDWR|O_CLOEXEC)) < 0) { - log_error("Failed to open %s: %m", vc); - goto finish; - } - - if (!is_vconsole(fd)) { - log_error("Device %s is not a virtual console.", vc); - goto finish; - } - - utf8 = is_locale_utf8(); - - vc_keymap = strdup("us"); - vc_font = strdup(DEFAULT_FONT); - - if (!vc_keymap || !vc_font) { - log_error("Failed to allocate strings."); - goto finish; - } - - r = 0; - - if (detect_container(NULL) <= 0) - if ((r = parse_env_file("/proc/cmdline", WHITESPACE, - "vconsole.keymap", &vc_keymap, - "vconsole.keymap.toggle", &vc_keymap_toggle, - "vconsole.font", &vc_font, - "vconsole.font.map", &vc_font_map, - "vconsole.font.unimap", &vc_font_unimap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); - } - - /* Hmm, nothing set on the kernel cmd line? Then let's - * try /etc/vconsole.conf */ - if (r <= 0 && - (r = parse_env_file("/etc/vconsole.conf", NEWLINE, - "KEYMAP", &vc_keymap, - "KEYMAP_TOGGLE", &vc_keymap_toggle, - "FONT", &vc_font, - "FONT_MAP", &vc_font_map, - "FONT_UNIMAP", &vc_font_unimap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r)); - } - - if (r <= 0) { -#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO) - if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "SYSFONT", &vc_font, - "SYSFONTACM", &vc_font_map, - "UNIMAP", &vc_font_unimap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - - if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, - "KEYTABLE", &vc_keymap, - "KEYMAP", &vc_keymap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - - if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) { - char *t; - - if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) { - log_error("Out of memory."); - goto finish; - } - - free(vc_keymap); - vc_keymap = t; - } - -#elif defined(TARGET_SUSE) - if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, - "KEYTABLE", &vc_keymap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r)); - } - - if ((r = parse_env_file("/etc/sysconfig/console", NEWLINE, - "CONSOLE_FONT", &vc_font, - "CONSOLE_SCREENMAP", &vc_font_map, - "CONSOLE_UNICODEMAP", &vc_font_unimap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r)); - } - -#elif defined(TARGET_ARCH) - if ((r = parse_env_file("/etc/rc.conf", NEWLINE, - "KEYMAP", &vc_keymap, - "CONSOLEFONT", &vc_font, - "CONSOLEMAP", &vc_font_map, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/rc.conf: %s", strerror(-r)); - } - -#elif defined(TARGET_FRUGALWARE) - if ((r = parse_env_file("/etc/sysconfig/keymap", NEWLINE, - "keymap", &vc_keymap, - NULL)) < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/keymap: %s", strerror(-r)); - } - if ((r = parse_env_file("/etc/sysconfig/font", NEWLINE, - "font", &vc_font, - NULL)) < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/font: %s", strerror(-r)); - } - -#elif defined(TARGET_ALTLINUX) - if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, - "KEYTABLE", &vc_keymap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/keyboard: %s", strerror(-r)); - } - - if ((r = parse_env_file("/etc/sysconfig/consolefont", NEWLINE, - "SYSFONT", &vc_font, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/console: %s", strerror(-r)); - } - -#elif defined(TARGET_GENTOO) - if ((r = parse_env_file("/etc/rc.conf", NEWLINE, - "unicode", &vc_unicode, - NULL)) < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/rc.conf: %s", strerror(-r)); - } - - if (vc_unicode) { - int rc_unicode; - - if ((rc_unicode = parse_boolean(vc_unicode)) < 0) - log_error("Unknown value for /etc/rc.conf unicode=%s", vc_unicode); - else { - if (rc_unicode && !utf8) - log_warning("/etc/rc.conf wants unicode, but current locale is not UTF-8 capable!"); - else if (!rc_unicode && utf8) { - log_debug("/etc/rc.conf does not want unicode, leave it on in kernel but does not apply to vconsole."); - utf8 = false; - } - } - } - - /* /etc/conf.d/consolefont comments and gentoo - * documentation mention uppercase, but the actual - * contents are lowercase. the existing - * /etc/init.d/consolefont tries both - */ - if ((r = parse_env_file("/etc/conf.d/consolefont", NEWLINE, - "CONSOLEFONT", &vc_font, - "consolefont", &vc_font, - "consoletranslation", &vc_font_map, - "CONSOLETRANSLATION", &vc_font_map, - "unicodemap", &vc_font_unimap, - "UNICODEMAP", &vc_font_unimap, - NULL)) < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/conf.d/consolefont: %s", strerror(-r)); - } - - if ((r = parse_env_file("/etc/conf.d/keymaps", NEWLINE, - "keymap", &vc_keymap, - "KEYMAP", &vc_keymap, - NULL)) < 0) { - if (r != -ENOENT) - log_warning("Failed to read /etc/conf.d/keymaps: %s", strerror(-r)); - } - -#elif defined(TARGET_MANDRIVA) - - if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, - "SYSFONT", &vc_font, - "SYSFONTACM", &vc_font_map, - "UNIMAP", &vc_font_unimap, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - - if ((r = parse_env_file("/etc/sysconfig/keyboard", NEWLINE, - "KEYTABLE", &vc_keytable, - "KEYMAP", &vc_keymap, - "UNIKEYTABLE", &vc_keymap, - "GRP_TOGGLE", &vc_keymap_toggle, - NULL)) < 0) { - - if (r != -ENOENT) - log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r)); - } - - if (vc_keytable) { - if (vc_keymap) - free(vc_keymap); - if (utf8) { - if (endswith(vc_keytable, ".uni") || strstr(vc_keytable, ".uni.")) - vc_keymap = strdup(vc_keytable); - else { - char *s; - if ((s = strstr(vc_keytable, ".map"))) - vc_keytable[s-vc_keytable+1] = '\0'; - vc_keymap = strappend(vc_keytable, ".uni"); - } - } else - vc_keymap = strdup(vc_keytable); - - free(vc_keytable); - - if (!vc_keymap) { - log_error("Out of memory."); - goto finish; - } - } - - if (access("/etc/sysconfig/console/default.kmap", F_OK) >= 0) { - char *t; - - if (!(t = strdup("/etc/sysconfig/console/default.kmap"))) { - log_error("Out of memory."); - goto finish; - } - - free(vc_keymap); - vc_keymap = t; - } -#endif - } - - r = EXIT_FAILURE; - - if (!utf8) - disable_utf8(fd); - - if (load_keymap(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 && - load_font(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0) - r = EXIT_SUCCESS; - -finish: - if (keymap_pid > 0) - wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid); - - if (font_pid > 0) - wait_for_terminate_and_warn(KBD_SETFONT, font_pid); - - free(vc_keymap); - free(vc_font); - free(vc_font_map); - free(vc_font_unimap); - - if (fd >= 0) - close_nointr_nofail(fd); - - return r; -} diff --git a/src/vconsole/Makefile b/src/vconsole/Makefile new file mode 120000 index 0000000..d0b0e8e --- /dev/null +++ b/src/vconsole/Makefile @@ -0,0 +1 @@ +../Makefile \ No newline at end of file diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c new file mode 100644 index 0000000..1bbf737 --- /dev/null +++ b/src/vconsole/vconsole-setup.c @@ -0,0 +1,308 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Kay Sievers + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "log.h" +#include "macro.h" +#include "virt.h" +#include "fileio.h" + +static bool is_vconsole(int fd) { + unsigned char data[1]; + + data[0] = TIOCL_GETFGCONSOLE; + return ioctl(fd, TIOCLINUX, data) >= 0; +} + +static int disable_utf8(int fd) { + int r = 0, k; + + if (ioctl(fd, KDSKBMODE, K_XLATE) < 0) + r = -errno; + + if (loop_write(fd, "\033%@", 3, false) < 0) + r = -errno; + + k = write_string_file("/sys/module/vt/parameters/default_utf8", "0"); + if (k < 0) + r = k; + + if (r < 0) + log_warning("Failed to disable UTF-8: %s", strerror(-r)); + + return r; +} + +static int enable_utf8(int fd) { + int r = 0, k; + long current = 0; + + if (ioctl(fd, KDGKBMODE, ¤t) < 0 || current == K_XLATE) { + /* + * Change the current keyboard to unicode, unless it + * is currently in raw or off mode anyway. We + * shouldn't interfere with X11's processing of the + * key events. + * + * http://lists.freedesktop.org/archives/systemd-devel/2013-February/008573.html + * + */ + + if (ioctl(fd, KDSKBMODE, K_UNICODE) < 0) + r = -errno; + } + + if (loop_write(fd, "\033%G", 3, false) < 0) + r = -errno; + + k = write_string_file("/sys/module/vt/parameters/default_utf8", "1"); + if (k < 0) + r = k; + + if (r < 0) + log_warning("Failed to enable UTF-8: %s", strerror(-r)); + + return r; +} + +static int keymap_load(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) { + const char *args[8]; + int i = 0; + pid_t pid; + + if (isempty(map)) { + /* An empty map means kernel map */ + *_pid = 0; + return 0; + } + + args[i++] = KBD_LOADKEYS; + args[i++] = "-q"; + args[i++] = "-C"; + args[i++] = vc; + if (utf8) + args[i++] = "-u"; + args[i++] = map; + if (map_toggle) + args[i++] = map_toggle; + args[i++] = NULL; + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + return -errno; + } else if (pid == 0) { + execv(args[0], (char **) args); + _exit(EXIT_FAILURE); + } + + *_pid = pid; + return 0; +} + +static int font_load(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) { + const char *args[9]; + int i = 0; + pid_t pid; + + if (isempty(font)) { + /* An empty font means kernel font */ + *_pid = 0; + return 0; + } + + args[i++] = KBD_SETFONT; + args[i++] = "-C"; + args[i++] = vc; + args[i++] = font; + if (map) { + args[i++] = "-m"; + args[i++] = map; + } + if (unimap) { + args[i++] = "-u"; + args[i++] = unimap; + } + args[i++] = NULL; + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + return -errno; + } else if (pid == 0) { + execv(args[0], (char **) args); + _exit(EXIT_FAILURE); + } + + *_pid = pid; + return 0; +} + +/* + * A newly allocated VT uses the font from the active VT. Here + * we update all possibly already allocated VTs with the configured + * font. It also allows to restart systemd-vconsole-setup.service, + * to apply a new font to all VTs. + */ +static void font_copy_to_all_vcs(int fd) { + struct vt_stat vcs = {}; + int i, r; + + /* get active, and 16 bit mask of used VT numbers */ + r = ioctl(fd, VT_GETSTATE, &vcs); + if (r < 0) + return; + + for (i = 1; i <= 15; i++) { + char vcname[16]; + _cleanup_close_ int vcfd = -1; + struct console_font_op cfo = {}; + + if (i == vcs.v_active) + continue; + + /* skip non-allocated ttys */ + snprintf(vcname, sizeof(vcname), "/dev/vcs%i", i); + if (access(vcname, F_OK) < 0) + continue; + + snprintf(vcname, sizeof(vcname), "/dev/tty%i", i); + vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC); + if (vcfd < 0) + continue; + + /* copy font from active VT, where the font was uploaded to */ + cfo.op = KD_FONT_OP_COPY; + cfo.height = vcs.v_active-1; /* tty1 == index 0 */ + ioctl(vcfd, KDFONTOP, &cfo); + } +} + +int main(int argc, char **argv) { + const char *vc; + char *vc_keymap = NULL; + char *vc_keymap_toggle = NULL; + char *vc_font = NULL; + char *vc_font_map = NULL; + char *vc_font_unimap = NULL; + int fd = -1; + bool utf8; + pid_t font_pid = 0, keymap_pid = 0; + bool font_copy = false; + int r = EXIT_FAILURE; + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + umask(0022); + + if (argv[1]) + vc = argv[1]; + else { + vc = "/dev/tty0"; + font_copy = true; + } + + fd = open_terminal(vc, O_RDWR|O_CLOEXEC); + if (fd < 0) { + log_error("Failed to open %s: %m", vc); + goto finish; + } + + if (!is_vconsole(fd)) { + log_error("Device %s is not a virtual console.", vc); + goto finish; + } + + utf8 = is_locale_utf8(); + + r = parse_env_file("/etc/vconsole.conf", NEWLINE, + "KEYMAP", &vc_keymap, + "KEYMAP_TOGGLE", &vc_keymap_toggle, + "FONT", &vc_font, + "FONT_MAP", &vc_font_map, + "FONT_UNIMAP", &vc_font_unimap, + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r)); + + /* Let the kernel command line override /etc/vconsole.conf */ + if (detect_container(NULL) <= 0) { + r = parse_env_file("/proc/cmdline", WHITESPACE, + "vconsole.keymap", &vc_keymap, + "vconsole.keymap.toggle", &vc_keymap_toggle, + "vconsole.font", &vc_font, + "vconsole.font.map", &vc_font_map, + "vconsole.font.unimap", &vc_font_unimap, + NULL); + + if (r < 0 && r != -ENOENT) + log_warning("Failed to read /proc/cmdline: %s", strerror(-r)); + } + + if (utf8) + enable_utf8(fd); + else + disable_utf8(fd); + + r = EXIT_FAILURE; + if (keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid) >= 0 && + font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid) >= 0) + r = EXIT_SUCCESS; + +finish: + if (keymap_pid > 0) + wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid); + + if (font_pid > 0) { + wait_for_terminate_and_warn(KBD_SETFONT, font_pid); + if (font_copy) + font_copy_to_all_vcs(fd); + } + + free(vc_keymap); + free(vc_font); + free(vc_font_map); + free(vc_font_unimap); + + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} diff --git a/src/virt.c b/src/virt.c deleted file mode 100644 index 380fabd..0000000 --- a/src/virt.c +++ /dev/null @@ -1,314 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "util.h" -#include "virt.h" - -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - -#if defined(__i386__) || defined(__x86_64__) - - /* Both CPUID and DMI are x86 specific interfaces... */ - - static const char *const dmi_vendors[] = { - "/sys/class/dmi/id/sys_vendor", - "/sys/class/dmi/id/board_vendor", - "/sys/class/dmi/id/bios_vendor" - }; - - static const char dmi_vendor_table[] = - "QEMU\0" "qemu\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMware\0" "vmware\0" - "VMW\0" "vmware\0" - "Microsoft Corporation\0" "microsoft\0" - "innotek GmbH\0" "oracle\0" - "Xen\0" "xen\0" - "Bochs\0" "bochs\0"; - - static const char cpuid_vendor_table[] = - "XenVMMXenVMM\0" "xen\0" - "KVMKVMKVM\0" "kvm\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMwareVMware\0" "vmware\0" - /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ - "Microsoft Hv\0" "microsoft\0"; - - uint32_t eax, ecx; - union { - uint32_t sig32[3]; - char text[13]; - } sig; - unsigned i; - const char *j, *k; - bool hypervisor; - - /* http://lwn.net/Articles/301888/ */ - zero(sig); - -#if defined (__i386__) -#define REG_a "eax" -#define REG_b "ebx" -#elif defined (__amd64__) -#define REG_a "rax" -#define REG_b "rbx" -#endif - - /* First detect whether there is a hypervisor */ - eax = 1; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=c" (ecx) - : "0" (eax) - ); - - hypervisor = !!(ecx & 0x80000000U); - - if (hypervisor) { - - /* There is a hypervisor, see what it is */ - eax = 0x40000000U; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " mov %%ebx, %1 \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) - : "0" (eax) - ); - - NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) - if (streq(sig.text, j)) { - - if (id) - *id = k; - - return 1; - } - } - - for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { - char *s; - int r; - const char *found = NULL; - - if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) { - if (r != -ENOENT) - return r; - - continue; - } - - NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) - if (startswith(s, j)) - found = k; - free(s); - - if (found) { - if (id) - *id = found; - - return 1; - } - } - - if (hypervisor) { - if (id) - *id = "other"; - - return 1; - } - -#endif - return 0; -} - -int detect_container(const char **id) { - FILE *f; - - /* Unfortunately many of these operations require root access - * in one way or another */ - - if (geteuid() != 0) - return -EPERM; - - if (running_in_chroot() > 0) { - - if (id) - *id = "chroot"; - - return 1; - } - - /* /proc/vz exists in container and outside of the container, - * /proc/bc only outside of the container. */ - if (access("/proc/vz", F_OK) >= 0 && - access("/proc/bc", F_OK) < 0) { - - if (id) - *id = "openvz"; - - return 1; - } - - f = fopen("/proc/1/environ", "re"); - if (f) { - bool done = false; - - do { - char line[LINE_MAX]; - unsigned i; - - for (i = 0; i < sizeof(line)-1; i++) { - int c; - - c = getc(f); - if (_unlikely_(c == EOF)) { - done = true; - break; - } else if (c == 0) - break; - - line[i] = c; - } - line[i] = 0; - - if (streq(line, "container=lxc")) { - fclose(f); - - if (id) - *id = "lxc"; - return 1; - - } else if (streq(line, "container=systemd-nspawn")) { - fclose(f); - - if (id) - *id = "systemd-nspawn"; - return 1; - - } else if (startswith(line, "container=")) { - fclose(f); - - if (id) - *id = "other"; - return 1; - } - - } while (!done); - - fclose(f); - } - - f = fopen("/proc/self/cgroup", "re"); - if (f) { - - for (;;) { - char line[LINE_MAX], *p; - - if (!fgets(line, sizeof(line), f)) - break; - - p = strchr(strstrip(line), ':'); - if (!p) - continue; - - if (strncmp(p, ":ns:", 4)) - continue; - - if (!streq(p, ":ns:/")) { - fclose(f); - - if (id) - *id = "pidns"; - - return 1; - } - } - - fclose(f); - } - - return 0; -} - -/* Returns a short identifier for the various VM/container implementations */ -Virtualization detect_virtualization(const char **id) { - - static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID; - static __thread const char *cached_id = NULL; - - const char *_id; - int r; - Virtualization v; - - if (_likely_(cached_virt >= 0)) { - - if (id && cached_virt > 0) - *id = cached_id; - - return cached_virt; - } - - r = detect_container(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_CONTAINER; - goto finish; - } - - r = detect_vm(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_VM; - goto finish; - } - - v = VIRTUALIZATION_NONE; - -finish: - if (v > 0) { - cached_id = _id; - - if (id) - *id = _id; - } - - if (v >= 0) - cached_virt = v; - - return v; -} diff --git a/src/virt.h b/src/virt.h deleted file mode 100644 index f55c9a6..0000000 --- a/src/virt.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foovirthfoo -#define foovirthfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 General Public License - along with systemd; If not, see . -***/ - -int detect_vm(const char **id); -int detect_container(const char **id); - -typedef enum Virtualization { - VIRTUALIZATION_NONE = 0, - VIRTUALIZATION_VM, - VIRTUALIZATION_CONTAINER, - _VIRTUALIZATION_MAX, - _VIRTUALIZATION_INVALID = -1 -} Virtualization; - -Virtualization detect_virtualization(const char **id); - -#endif diff --git a/sysctl.d/.gitignore b/sysctl.d/.gitignore new file mode 100644 index 0000000..e326c18 --- /dev/null +++ b/sysctl.d/.gitignore @@ -0,0 +1 @@ +/50-coredump.conf diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in new file mode 100644 index 0000000..d5795a3 --- /dev/null +++ b/sysctl.d/50-coredump.conf.in @@ -0,0 +1,10 @@ +# 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. + +# See sysctl.d(5) and core(5) for for details. + +kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %p %u %g %s %t %e diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf new file mode 100644 index 0000000..46bae21 --- /dev/null +++ b/sysctl.d/50-default.conf @@ -0,0 +1,24 @@ +# 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. + +# See sysctl.d(5) and core(5) for for details. + +# System Request functionality of the kernel (SYNC) +kernel.sysrq = 16 + +# Append the PID to the core filename +kernel.core_uses_pid = 1 + +# Source route verification +net.ipv4.conf.default.rp_filter = 1 + +# Do not accept source routing +net.ipv4.conf.default.accept_source_route = 0 + +# Enable hard and soft link protection +fs.protected_hardlinks = 1 +fs.protected_symlinks = 1 diff --git a/sysctl.d/Makefile b/sysctl.d/Makefile new file mode 120000 index 0000000..bd10475 --- /dev/null +++ b/sysctl.d/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/systemd.pc.in b/systemd.pc.in deleted file mode 100644 index 29376e5..0000000 --- a/systemd.pc.in +++ /dev/null @@ -1,20 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -systemdsystemunitdir=@systemunitdir@ -systemduserunitdir=@userunitdir@ -systemdsystemconfdir=@pkgsysconfdir@/system -systemduserconfdir=@pkgsysconfdir@/user -systemdsystemunitpath=/run/systemd/system:${systemdsystemconfdir}:/etc/systemd/system:/usr/local/share/systemd/system:/usr/local/lib/systemd/system:/usr/share/systemd/system:/usr/lib/systemd/system:/lib/systemd/system:${systemdsystemunitdir} -systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/usr/local/share/systemd/user:/usr/local/lib/systemd/user:/usr/share/systemd/user:/usr/lib/systemd/user:${systemduserunitdir} - -Name: systemd -Description: systemd System and Service Manager -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..fd7483d --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,5 @@ +.testdir +test.log +/dev +/run +/sys diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..987a325 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,20 @@ +# Just a little hook script to easy building when in this directory +.PHONY: all check clean + +all: + $(MAKE) -C .. + +clean: + @for i in TEST-[0-9]*; do \ + [ -d $$i ] || continue ; \ + [ -f $$i/Makefile ] || continue ; \ + make -C $$i clean ; \ + done + +check: + $(MAKE) -C .. all + @for i in TEST-[0-9]*; do \ + [ -d $$i ] || continue ; \ + [ -f $$i/Makefile ] || continue ; \ + make -C $$i all ; \ + done diff --git a/test/README.testsuite b/test/README.testsuite new file mode 100644 index 0000000..2ae85a2 --- /dev/null +++ b/test/README.testsuite @@ -0,0 +1,48 @@ +The extended testsuite only works with uid=0. It contains of several +subdirectories named "test/TEST-??-*", which are run one by one. + +To run the extended testsuite do the following: + +$ make all +$ cd test +$ sudo make clean check +... +make[1]: Entering directory `/mnt/data/harald/git/systemd/test/TEST-01-BASIC' +Making all in . +Making all in po +Making all in docs/libudev +Making all in docs/gudev +TEST: Basic systemd setup [OK] +make[1]: Leaving directory `/mnt/data/harald/git/systemd/test/TEST-01-BASIC' +... + +If one of the tests fails, then $subdir/test.log contains the log file of +the test. + +To debug a special testcase of the testsuite do: + +$ make all +$ cd test/TEST-01-BASIC +$ sudo make clean setup run + +QEMU +==== + +If you want to log in the testsuite virtual machine, you can specify +additional kernel command line parameter with $KERNEL_APPEND. + +$ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" clean setup run + +you can even skip the "clean" and "setup" if you want to run the machine again. + +$ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" run + +You can specify a different kernel and initramfs with $KERNEL_BIN and $INITRD. +(Fedora's default kernel path and initramfs are used by default) + +$ sudo make KERNEL_BIN=/boot/vmlinuz-foo INITRD=/boot/initramfs-bar clean check + +A script will try to find your QEMU binary. If you want to specify a different +one you can use $QEMU_BIN. + +$ sudo make QEMU_BIN=/path/to/qemu/qemu-kvm clean check diff --git a/test/TEST-01-BASIC/Makefile b/test/TEST-01-BASIC/Makefile new file mode 100644 index 0000000..5e89a29 --- /dev/null +++ b/test/TEST-01-BASIC/Makefile @@ -0,0 +1,10 @@ +all: + @make -s --no-print-directory -C ../.. all + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all +setup: + @make --no-print-directory -C ../.. all + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup +clean: + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean +run: + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh new file mode 100755 index 0000000..84ccf26 --- /dev/null +++ b/test/TEST-01-BASIC/test.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Basic systemd setup" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service < /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +Type=oneshot +EOF + + setup_testsuite + ) + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-02-CRYPTSETUP/Makefile b/test/TEST-02-CRYPTSETUP/Makefile new file mode 120000 index 0000000..e9f93b1 --- /dev/null +++ b/test/TEST-02-CRYPTSETUP/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh new file mode 100755 index 0000000..b243254 --- /dev/null +++ b/test/TEST-02-CRYPTSETUP/test.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="cryptsetup systemd setup" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile + mount /dev/mapper/varcrypt $TESTDIR/root/var + [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root/var + umount $TESTDIR/root + cryptsetup luksClose /dev/mapper/varcrypt + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + echo -n test >$TESTDIR/keyfile + cryptsetup -q luksFormat ${LOOPDEV}p2 $TESTDIR/keyfile + cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile + mkfs.ext3 -L var /dev/mapper/varcrypt + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + mkdir -p $TESTDIR/root/var + mount /dev/mapper/varcrypt $TESTDIR/root/var + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=/dev/mapper/varcrypt) + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service < /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +Type=oneshot +EOF + + setup_testsuite + + install_dmevent + generate_module_dependencies + cat >$initdir/etc/crypttab < $initdir/etc/varkey + cat $initdir/etc/crypttab | ddebug + + cat >>$initdir/etc/fstab </dev/null + [[ -b /dev/mapper/varcrypt ]] && cryptsetup luksClose /dev/mapper/varcrypt + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-03-JOBS/Makefile b/test/TEST-03-JOBS/Makefile new file mode 120000 index 0000000..e9f93b1 --- /dev/null +++ b/test/TEST-03-JOBS/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh new file mode 100755 index 0000000..12b38af --- /dev/null +++ b/test/TEST-03-JOBS/test-jobs.sh @@ -0,0 +1,41 @@ +#!/bin/bash -x + +# Test merging of a --ignore-dependencies job into a previously +# installed job. + +systemctl start --no-block hello-after-sleep.target +# sleep is now running, hello/start is waiting. Verify that: +systemctl list-jobs > /root/list-jobs.txt +grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 +grep 'hello\.service.*waiting' /root/list-jobs.txt || exit 1 + +# This is supposed to finish quickly, not wait for sleep to finish. +START_SEC=$(date -u '+%s') +systemctl start --ignore-dependencies hello +END_SEC=$(date -u '+%s') +ELAPSED=$(($END_SEC-$START_SEC)) + +[ "$ELAPSED" -lt 3 ] || exit 1 + +# sleep should still be running, hello not. +systemctl list-jobs > /root/list-jobs.txt +grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 +grep 'hello\.service' /root/list-jobs.txt && exit 1 + +# TODO: add more job queueing/merging tests here. + +# Test for irreversible jobs +systemctl start unstoppable.service || exit 1 + +# This is expected to fail with 'job cancelled' +systemctl stop unstoppable.service && exit 1 +# But this should succeed +systemctl stop --irreversible unstoppable.service || exit 1 + +# We're going to shutdown soon. Let's see if it succeeds when +# there's an active service that tries to be unstoppable. +# Shutdown of the container/VM will hang if not. +systemctl start unstoppable.service || exit 1 + +touch /testok +exit 0 diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh new file mode 100755 index 0000000..41e02e2 --- /dev/null +++ b/test/TEST-03-JOBS/test.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Job-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service </dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-04-SECCOMP/Makefile b/test/TEST-04-SECCOMP/Makefile new file mode 120000 index 0000000..e9f93b1 --- /dev/null +++ b/test/TEST-04-SECCOMP/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-04-SECCOMP/test-seccomp.sh b/test/TEST-04-SECCOMP/test-seccomp.sh new file mode 100755 index 0000000..2496190 --- /dev/null +++ b/test/TEST-04-SECCOMP/test-seccomp.sh @@ -0,0 +1,13 @@ +#!/bin/bash -x + +systemctl start will-fail.service +systemctl start will-fail2.service +systemctl start will-not-fail.service +systemctl start will-not-fail2.service +systemctl is-failed will-fail.service || exit 1 +systemctl is-failed will-fail2.service || exit 1 +systemctl is-failed will-not-fail.service && exit 1 +systemctl is-failed will-not-fail2.service && exit 1 + +touch /testok +exit 0 diff --git a/test/TEST-04-SECCOMP/test.sh b/test/TEST-04-SECCOMP/test.sh new file mode 100755 index 0000000..a85b50c --- /dev/null +++ b/test/TEST-04-SECCOMP/test.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="seccomp tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service </dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-04-SECCOMP/will-fail.service b/test/TEST-04-SECCOMP/will-fail.service new file mode 100644 index 0000000..c4e0be9 --- /dev/null +++ b/test/TEST-04-SECCOMP/will-fail.service @@ -0,0 +1,8 @@ +[Unit] +Description=Will fail + +[Service] +ExecStart=/bin/echo "This should not be seen" +SystemCallFilter=ioperm +SystemCallFilter=~ioperm +SystemCallFilter=ioperm diff --git a/test/TEST-04-SECCOMP/will-fail2.service b/test/TEST-04-SECCOMP/will-fail2.service new file mode 100644 index 0000000..f7f1ae9 --- /dev/null +++ b/test/TEST-04-SECCOMP/will-fail2.service @@ -0,0 +1,6 @@ +[Unit] +Description=Will fail 2 + +[Service] +ExecStart=/bin/echo "This should not be seen" +SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST diff --git a/test/TEST-04-SECCOMP/will-not-fail.service b/test/TEST-04-SECCOMP/will-not-fail.service new file mode 100644 index 0000000..5c1b594 --- /dev/null +++ b/test/TEST-04-SECCOMP/will-not-fail.service @@ -0,0 +1,9 @@ +[Unit] +Description=Will not fail + +[Service] +ExecStart=/bin/echo "Foo bar" +SystemCallFilter=~read write open execve ioperm +SystemCallFilter=ioctl +SystemCallFilter=read write open execve +SystemCallFilter=~ioperm diff --git a/test/TEST-04-SECCOMP/will-not-fail2.service b/test/TEST-04-SECCOMP/will-not-fail2.service new file mode 100644 index 0000000..2df05e3 --- /dev/null +++ b/test/TEST-04-SECCOMP/will-not-fail2.service @@ -0,0 +1,6 @@ +[Unit] +Description=Reset SystemCallFilter + +[Service] +ExecStart=/bin/echo "Foo bar" +SystemCallFilter= diff --git a/test2/a.service b/test/a.service similarity index 100% rename from test2/a.service rename to test/a.service diff --git a/test2/b.service b/test/b.service similarity index 100% rename from test2/b.service rename to test/b.service diff --git a/test2/c.service b/test/c.service similarity index 100% rename from test2/c.service rename to test/c.service diff --git a/test2/d.service b/test/d.service similarity index 100% rename from test2/d.service rename to test/d.service diff --git a/test/daughter.service b/test/daughter.service new file mode 100644 index 0000000..aebedca --- /dev/null +++ b/test/daughter.service @@ -0,0 +1,7 @@ +[Unit] +Description=Daughter Service + +[Service] +Slice=parent.slice +Type=oneshot +ExecStart=/bin/true diff --git a/test2/e.service b/test/e.service similarity index 100% rename from test2/e.service rename to test/e.service diff --git a/test/end.service b/test/end.service new file mode 100644 index 0000000..0f04dfe --- /dev/null +++ b/test/end.service @@ -0,0 +1,6 @@ +[Unit] +Description=End the test +After=testsuite.service + +[Service] +ExecStart=/usr/bin/systemctl poweroff --no-block diff --git a/test2/f.service b/test/f.service similarity index 100% rename from test2/f.service rename to test/f.service diff --git a/test2/g.service b/test/g.service similarity index 100% rename from test2/g.service rename to test/g.service diff --git a/test/grandchild.service b/test/grandchild.service new file mode 100644 index 0000000..ab64130 --- /dev/null +++ b/test/grandchild.service @@ -0,0 +1,7 @@ +[Unit] +Description=Grandchild Service + +[Service] +Slice=parent-deep.slice +Type=oneshot +ExecStart=/bin/true diff --git a/test2/h.service b/test/h.service similarity index 100% rename from test2/h.service rename to test/h.service diff --git a/test/hello-after-sleep.target b/test/hello-after-sleep.target new file mode 100644 index 0000000..526fbd2 --- /dev/null +++ b/test/hello-after-sleep.target @@ -0,0 +1,5 @@ +[Unit] +Description=Sleep for a minute, then say hello. +Wants=sleep.service hello.service +After=sleep.service +Before=hello.service diff --git a/test/hello.service b/test/hello.service new file mode 100644 index 0000000..82907b6 --- /dev/null +++ b/test/hello.service @@ -0,0 +1,5 @@ +[Unit] +Description=Hello World + +[Service] +ExecStart=/bin/echo "Hello World" diff --git a/test/parent-deep.slice b/test/parent-deep.slice new file mode 100644 index 0000000..79b302f --- /dev/null +++ b/test/parent-deep.slice @@ -0,0 +1,5 @@ +[Unit] +Description=Deeper Parent Slice + +[Slice] +MemoryLimit=3G diff --git a/test/parent.slice b/test/parent.slice new file mode 100644 index 0000000..0222f8e --- /dev/null +++ b/test/parent.slice @@ -0,0 +1,5 @@ +[Unit] +Description=Parent Slice + +[Slice] +BlockIOWeight=200 diff --git a/test/rule-syntax-check.py b/test/rule-syntax-check.py new file mode 100755 index 0000000..ce4f5c7 --- /dev/null +++ b/test/rule-syntax-check.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +# Simple udev rules syntax checker +# +# (C) 2010 Canonical Ltd. +# Author: Martin Pitt +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +import re +import sys + +if len(sys.argv) < 2: + print >> sys.stderr, 'Usage: %s [...]' % sys.argv[0] + sys.exit(2) + +no_args_tests = re.compile('(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST)\s*(?:=|!)=\s*"([^"]*)"$') +args_tests = re.compile('(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$') +no_args_assign = re.compile('(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*"([^"]*)"$') +args_assign = re.compile('(ATTR|ENV|IMPORT|RUN){([a-zA-Z0-9/_.*%-]+)}\s*(=|\+=)\s*"([^"]*)"$') + +result = 0 +buffer = '' +for path in sys.argv[1:]: + lineno = 0 + for line in open(path): + lineno += 1 + + # handle line continuation + if line.endswith('\\\n'): + buffer += line[:-2] + continue + else: + line = buffer + line + buffer = '' + + # filter out comments and empty lines + line = line.strip() + if not line or line.startswith('#'): + continue + + for clause in line.split(','): + clause = clause.strip() + if not (no_args_tests.match(clause) or args_tests.match(clause) or + no_args_assign.match(clause) or args_assign.match(clause)): + + print('Invalid line %s:%i: %s' % (path, lineno, line)) + print(' clause:', clause) + print() + result = 1 + break + +sys.exit(result) diff --git a/test/rules-test.sh b/test/rules-test.sh new file mode 100755 index 0000000..47d42cb --- /dev/null +++ b/test/rules-test.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Call the udev rule syntax checker on all rules that we ship +# +# (C) 2010 Canonical Ltd. +# Author: Martin Pitt +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +[ -n "$srcdir" ] || srcdir=`dirname $0`/.. + +# skip if we don't have python +type python >/dev/null 2>&1 || { + echo "$0: No python installed, skipping udev rule syntax check" + exit 0 +} + +$srcdir/test/rule-syntax-check.py `find $srcdir/rules -name '*.rules'` diff --git a/test/sched_idle_bad.service b/test/sched_idle_bad.service new file mode 100644 index 0000000..589a87c --- /dev/null +++ b/test/sched_idle_bad.service @@ -0,0 +1,6 @@ +[Unit] +Description=Bad sched priority for Idle + +[Service] +ExecStart=/bin/true +CPUSchedulingPriority=1 diff --git a/test/sched_idle_ok.service b/test/sched_idle_ok.service new file mode 100644 index 0000000..262ef3e --- /dev/null +++ b/test/sched_idle_ok.service @@ -0,0 +1,6 @@ +[Unit] +Description=Sched idle with prio 0 + +[Service] +ExecStart=/bin/true +CPUSchedulingPriority=0 diff --git a/test/sched_rr_bad.service b/test/sched_rr_bad.service new file mode 100644 index 0000000..0be534a --- /dev/null +++ b/test/sched_rr_bad.service @@ -0,0 +1,8 @@ +[Unit] +Description=Bad sched priority for RR + +[Service] +ExecStart=/bin/true +CPUSchedulingPolicy=rr +CPUSchedulingPriority=0 +CPUSchedulingPriority=100 diff --git a/test/sched_rr_change.service b/test/sched_rr_change.service new file mode 100644 index 0000000..b3e3a00 --- /dev/null +++ b/test/sched_rr_change.service @@ -0,0 +1,9 @@ +[Unit] +Description=Change prio + +[Service] +ExecStart=/bin/true +CPUSchedulingPolicy=rr +CPUSchedulingPriority=1 +CPUSchedulingPriority=2 +CPUSchedulingPriority=99 diff --git a/test/sched_rr_ok.service b/test/sched_rr_ok.service new file mode 100644 index 0000000..b88adc5 --- /dev/null +++ b/test/sched_rr_ok.service @@ -0,0 +1,6 @@ +[Unit] +Description=Default prio for RR + +[Service] +ExecStart=/bin/true +CPUSchedulingPolicy=rr diff --git a/test/sleep.service b/test/sleep.service new file mode 100644 index 0000000..946c44b --- /dev/null +++ b/test/sleep.service @@ -0,0 +1,6 @@ +[Unit] +Description=Sleep for 1 minute + +[Service] +Type=oneshot +ExecStart=/bin/sleep 60 diff --git a/test/son.service b/test/son.service new file mode 100644 index 0000000..50bb96a --- /dev/null +++ b/test/son.service @@ -0,0 +1,8 @@ +[Unit] +Description=Son Service + +[Service] +Slice=parent.slice +Type=oneshot +ExecStart=/bin/true +CPUShares=100 diff --git a/test/sys.tar.xz b/test/sys.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..49ee8027b2e1cba42a8312d56de4bb65d4a2d470 GIT binary patch literal 165116 zcmV(pK=8l)H+ooF000E$*0e?f03iVu0001VFXf~E|EGjMT>v?rN~uw$QGMs1W~ZOV zrh(^8AyYIvK!^P^ZitFEZ|T+k4Sh**k*D;>rX9&bUxW146lE3;v^(^-$??!2xcC_w z8&r|uy3?}ZJk?zkuE-&-6xq1a{(`jYOa)++$4uDi+P5Qy_f_g6qo7Is20eH=ay#ml zy}J{?bOrLpwmAY%WLsL>JLfNvl}%;BF$wrozCj&FRkofKB^o!yY0D?bt`I7r2nEX+ z1@i<54gK13ehnORj_Mz7-k|AN+AClloxpCu z)^MgnU!3Ga=|2O}3xyj6q`OvuDqI}M51Oo}C)fuL;dDc}-VMj=zeKcCuV&qIYZ1GoUbEn)kHoQFetJZCn)>nqo@uscx`37 zJj9n^q7Ki^9NM00;~4SvZn^I?$$yu^1C|(njv3f{_7yHx!Y=q3ZHY@jV=E<8L)+f@ zEza3$ZyIf}==miPDHFkgYL_FM8AJ3v(C?qlqf$<+zE%z_#L2JOe;sGAd#%2&`0@DZ zWL`kS=CfN`H*{bX#VCr>xG^zn%Avv)3$nUM#t+GB;E7i4b1Be91-ETQlH3wX7WKZE z>=JdcH;+zacvS)I5aZ0sLnfNo8Wjb=HBX?gWitw-1|~d^{FbZ&+5~5T*1#I=+elW^ z#N$>!)v!_3{n%E{7NTcL=9*W^q?VM%d=j!{>j}A&IVxN;!JLa_FDxBPCfJLI8pc(& zo6%k4Q8_2pROhM|v|WlJv;GIvUB{VdYKnvn%Sp?H8$>@^DlBN?2O(3VIv#!^e$K6) zeM(mgtJN`1@|}$*kb-DJliFUaL>b{VbfH-m55|Wb)K^441vK8<7TOBL8PXAzem+TI zh=Sa^M?Kj54}tZDT7O_IGg@dK^3ZGrk z#wZCduskEik7y=Hf)G@VLN9OT0hB4oN~RlPzTwEvui+L_=J3O=t*nbqP1=lMaY1?b|BEt3tl+FJrw&Q`w&eb@ebd~nuuRe{*%0{ z85^w_ZbiU0Ym5)A&KxnG`t_0y*E)m~hBi*RDHV5)ZCZk8WK64<0T;`*So>2Q3eBSP zcfT9J9mt+;vP#t<1KP3jA#V=>oSlM!Y2_e(s1@&Tg4Msm`d27sK-5UZb|`3x3ICqOaR1Ket68X?N zMBPyHXd=yNJSp&Qi5x;`T^4wRBp$wv;F0~cl56K@7Ed%`+D59U07<7ZjoNH+=8>6# zM%V4w?K8!5E2I!JxBj)lO~Bqma>Ma^x@PVZMDB zF%f!MylHtp1p^DQfBsWO)<#eU#OXqI$qz6*WNzo-hhrGV0Zlgo&=z5ENhgCT_~}$Z zfx7NtMzUw?Y8i>Z?)G}RtH^K|CD)b}u|{3khhSW2r@=x1YLf`yHb5}<%krVsuxF6N z$d}!MPOM7%=?dA1W3weAujp3I&oi`^5xLE}(el3YpC-g~5D(W`UtTL;ne88}M*C@u z27x^KfnEs78DKmgM?pEJLyBp}A#y2KsQa;yOf79iY5>vn4zylO%Tm!r`kVF)0>#vC zq@%`cf%6?RMb>FA96m+xFble`jd!hsU|2ZHJ771CSC`K*^fu_84Z9w^>T4weES>o| zc^!~qaN(Ykl*v`*mm(5_o3%Md3nZpfO;_mo%buu)!e&~9)Q<@WSuyCpQ;P?PBQjg1 z3^ta;(l9)ohwfvQVpNNSOjdDDe?^g^D>4^yU&C9DBE3j>i+@99Zw3hxXfc<$fbqP< zl9`WDeL9tRObz^k=k4$G+Pt3imUpUWmIr_B=eg(AL>9CP+lf!G?HJ`BJYnz}iF)k; z=^$~?*hPAxl}{gNT)2S2w^twhX*yHe0EG`5-0qsXqHg5~S=Tq#+uC)HpCsnouEq zP@_VL$ZhJ^FHff{DL{!iJym-WK1Fh<(K zK*fJ%&}e8PIvc^~3ozL`$RJA$GvX^-6oL{j)`|2I&kZB|2g9A!2{lLFlXOIO5Wlou`wF!l#Va3>TU4F=e&$F zM$u#B21h}SiF1OP3uEg}GL4;rvp8EEy^r;YI{-V3-`>tXC}F{kl0#LD%%#|CoUs~| zAtYNuXSQe|j*#zqwF3*)cBZ?0G7F2EUXH^vvr0@ksC^OC3vEr@*%C5;K!3`xg{Ma@ z8#SLv2Fs>4)VB4I*CDu_bru91s?A>yiF{SO?$+})55Va~cwj(ZB=Fv)qjf@-5h4J7 zXRf7}KTXkKB&02on6R8am&(L8*4!;;(p5=pjH$e!Gga=2?pi5;TYSA3^=UTpm#r?hl zhV#RXDOZ+6SE_SZW{zk`QpSc>#5jFUS~z?D1|w!t2(<`ylT)kGej!ro{}gLAwviw_ z7|Gm=Nu#@)=eo_Wq=Bh%j4sZuHMn=Z>o25RFFP=+m}}J#!eF;O?M!a&i~FGC^Hz^^QoJKu4>~Y=*1(^7RUMh2 z+7<4XvY4&Vx%$mO6Wi4$MHcT}xA(+l;z>j3{bqN|M>i&5VwUO&Riw!4oYalR4|+2i z#iNyrMc)^5;+s=aNS1?H8vnqagiIG#FDwxFd0S&(Ehv$1haT*5(iNE75UwXr$I`DS z&U`f{Ed;f23vz4K_kGF1iMI;l!lNkCnok(caG&JcnbN}A!DMlacLM|>pM)Gs>+OID zkrESffOXZ!F(d|KhHe%l$t{LZzFMMB13bkFcn;CH0D&bge7*YWkCFW8R#Inm^tT=e)RSY1iKtbXk$>#6LS+_C ztg_y|zBmK&D_=A|CNp|khBr!BHPEnZH`xD%p`zXPC>%&d#s(L69es%gvUPRH5)v9B@dfbB~lw(T? zI-$?$F(t?pGD+PviKA{+eD6CgWKQY$Qlx8Z2;R7yzgKY|jG1L50K+rw9yVmIx!YSF{P$Wu zO>R{hAbjW9??v^a#S>UEZE>eq$?IX#JR*!pRQXr^jlC(lA3D zgyNs7mKzjdY?4Z4wB3j<4I~@L2T7-r$OA8erY8ws)W3EPZA1|`AE~VdSu#rXR%*Bn!lf9ci=P*(#go4 znx?MW>2w4q!%~ARK?Tz}`o{Ju=TOQ9Es~{k#udFyO%Vac)=^64W^--wwBB&1rEBtc z-f!i!Sp;+3_N}(??3`x|76!oT39Bbjs>Rp=z z#9&xZ=p5ff*d?Y~Z73^l%BGY6p*_%x86+XGI>aM#bi=t4o20A|@me6K0U;Z1GsmAE z*WO=gpQhWZ`^{r~3 z|AmL6%DNXv5N$1RV^)dQ)(=5962n{RyW3Ti&12xg=x(uOT20!7%;s`)xPRkmck;# zr64d)UG3jC=g|q6SIw@bXV_!FRfGfZrDlu0mB8BSo9a&~qf=9;^X|}u>5O8J2E!@4 z!@v~Yw~QVuIX<2lC=EF3=ab?RwP+a9_F~LvbDLm7aFiT`&g6r7?M&qn2_uky7fyT? zc>cwjB+U64e8RLi6+ig?BET$-P!T&q$_zP7w%@QTm{8*~XjsU32sdfCI7S{Tz(iKb zNjO%+mMd%3A`&+Xc1wq%f^ip*cTrP2Sif?dBz?qdMzB&Hli$R>Jo;dWF1SMLRvYu+ zaFr2*8AR} zQV|tqM8CzgrYC=?GScD|j(!fTj{+NgE0LmhCPMNMw}_r?l5VU=fOdr}eVU5&w)wDH z`!D&Ur%Md=ASDUm$F`$&;BudR4)U6!6d}r_LI|mhIVFNE1sR{Mh6;3~9-A-x#CwUw)k1U@7 zxSoi%uH~%?xBf26R3No+?{FOtn9~L_zhQ>^=xZVgjfZY{+AT|%h>>rc>l62;)BE6AV&R9}pugG{Z|4 z?GFkAlX!POZNDZSE^T5|mSN`qOyGQM=S^rmpMXoapagJvI}MP(SAJ0F%{o@k2Knzg zN|q@UA&zFVj_Jdt9HTkr=IawXw~BtgKb$0B_YA=(m7;|e69JXyK-bXjTjuBJV zijmIC-{-bs3&yW!ASHnrHZ63g#+sEm3A`&5D(v47@miO~3YjM2>`bPoRC!N|8}9OsbE1_)@w^MKawC~ZEzx}<${IO;|9TP_?sN9GtN=gC@wWTQ z$KVaz&S%g^y(-C8Zrl!R5hJ2$kM$U69QkKVnv0gli#;;1uaDL^-rNhkj=o{!t#s|~ zH50m@0}gyko@3TlYNdZloY2;Nd{*V;%mLiJa5vfC%`B1?;E&@}rI&RsOlx8%2(Y$9 z?mDRxDNz0IEMu89!l-}6zA0wOEpQdh&LD@f_Bl`KFVPvU3iQ3@OhM>P4jAx?mt89- zR{EAb!_of4vBvGuj>~FjEABe}4TZ*-5Rc6#DZ7oUV}p2A!RY_O;Z60eR$Eo`MdEWzlN$zqTG5YbmEEdm5%IoGSMYuTrIe+@gfb9Zo z@`xS|-^)+!CbE25vx&Iq;Ut^9;I$CUROQvf2D$MP?ntM8pciphoc}VV58;?C{4m{5 zQ4Zqj-a@^%_Tf`SFF00KuI>uF!+2jq3oeXO5#T>M`f&fb`NvuTl-1NFZ6lL`8cXFg z#-kUi9}$R+i)1P))a$02_oDKl0@pJIocExKpYuVN%3Hnjv625EmzZU)qcVT)Tx;^J zlpdv##I+|M3u|wy;{GZWv)0*5Zfqdi8htFvsWb17>vWr87-cxdHaX%^9cIB2V-KAl zX^1egmX16%0tpvT^5&+V#FjpHV0)V}^I0ZbH~OYYt;z5OhsL5$kFRqTYbt||QicuV zbgQBp6LU+ZnNB(M%YE(lXhF&HU{9)lJ*gHEZXA$rI7OSLg8?j}I4tjhjEE;tOI`p# zt>WkZTt-0AG85sN1ZG{RQpwMm2r+2thTCBnlcAlI$zwI0IQus5V0r%@L^7l*ykKG|Ad+oKN80}|)FS6~gV9yfu>Zjj#N*sj)w z0CZ~aX}U|w?MnpuEJ&2=(0bfdp6-@vph@GSyV0aQE|t_^n5qV!gPArAuoB(G#euVE zXgEeVH)CeabM=2D+=X?m0X=o#e`2W%Sk>=VeL%m*Mlt6q_A*4r*mT<;%QIf1cj+_2 zH8k2ycqc>6J4rNN*Pp|}LhON4Y2o}r&ZLgxT)fqDQ!X%c{)ck}l!H9LpREttXl#&< zQFasoZS#;={LeOF?2KnVhn;4pMp~;tljkF7;is=&X&Z7oSJ|Ga%u5aoSQb@@_UF2f zrvhJz0a=S7;5NuV=~wO~MChR{MDvUG76K33GW%h9}_woEB4X1EFV~e&f##4F#iaO* ziE$-nk;Qs+DwYs_jI25&_b z>zAYZN*%?cv3gg1A@X0B`k1aDh~|BHS0V2PBU{40pE z=J-O9dYEPfIL&N8Lr^otoPRrF;u{K3; z^uL7;p!n9wZ@Y>MN_n}IrxntfS5U@OE7m-DMe&WPnR^flWw|vYQ-U7Uku?~mw+0zB z2-QUXNESKu#utRa6{Ak5XrKpDv#uF1F(a0m0Au)&r!agV4S2R4J?nY~4LVlSS@;rkX@3>XSBS(I*Wj==I}YtR_((`6_PKNz zPJ_Op-w~6d@2p=t%8KM=fXq)%AF!O87++;%0$SNZJDPWA26~{c%n+M>jmuFXn9XdW z{%KYAoIsX7Yp3djE-;P)Kivcsn6%OukGJ*i2-8`4!)?)66GndZgTpG+AaG`;;$h_J zaOm0Oe|jtEr84x?I6b|tV&loo<&VvE3wSB zo;p)^Cw_yWy>yHt)sF)lE0o7E=bkoEGFVkOi~qaa{){ewb&vQ^9I@kn{=PUw zO#6&l*)yuzWET+q5KrPf-)Q+D3>BA-3kUUBdSOv#`4#P6fT4>SeFnDuHvt#`LhZ8f z-hI8c;;5J8O;PI=56}eXyk|)X`V&gsxx?lJsg_!4V7hdx%s_qf|7W?^ex3s3&C;Y8 zG$~q!Nkr*!AmvbtpL24Hu(Fc3+-JHefsTVAh$u>3>DBmlA%LTg)cYfl{h> zk-@Qb0RP|BTvCYf5^Rb*Q?cZ;U?MFPqzY3)P*;^M*17RmN_%5=GRhj8AFEZ7q^SN z3h{>qdYpHos@+-MUb%~5siq&w@=?3zQr{WT81cXNo15Kz#q>BuxC^Ze=1P6T z2gtG7WCuVvCL~H7K+sf;J`9(D{XGuL2NdJ6;iR+Ee<@Y1Tqbo-nS6bDOPrWJwAy*L zG!6Qg#RT)obHqOW*PWSTLcM*}CiW$@osYnEV(KGOE>~#qXNKNW*?x{ocyMPLk>=!Rr=53fUl*u zM3C@a7mp#+?j)?Igl4ln3OZn{CJ@QsqvIXtJT%1VSb)|z*3zc}u)aAmP8&(W#o$_# zv${Rkoab~`@`7lC`y@jwJ(pue5lX*ikDt1OZuUoZP$puuxgAC|xh9W|O0O^yz_gl1 zn};+>71YKF-TkSkw@avetv#-HZo%tQ$4Yz1XXC!IE0Xg}m3w-5DNAruM0onUA}>x) zhuEM%?xVTt!dc?mr1LO8B<5H_IR?+f8ZyrmmSvKmfSPt&6f9`SZS)f}G{b35V44EW zq-E;hGf9}X@Z5iRKGpVjq$|$$4-fXor(h~$(F33ne~m4`z6KXU&+RtA|F+}lREr@w z7QTA8L%RDhhr02-Ppeq+4_F7J?oO*UfmTf0q8pDG3Zv-Lkeacdyc(C7@4Z4fT6dMnO<*v$dO7Xh{ z#F9BfZC;5j{#VxQEa6m?o7Z=Qyno#v%C{~qNA%oxz3ddSI7?H3l9N;mxguXN5a34c zZ6uA(rxfZ!#KyX4Dn3&C+{BDzwj+PV&T)rFT%VdO84Kf-M&VnGeP)gbc^FzMMTpG(h|&9RRZMPW1GC&RdG|S)7IVbtlVNN0|7mPcQ3z- z`|^LRbmWiifY(m6>y5)E`q;Wez`HeqV^6e*p2oh$8g`W&QlDstfce1?=!@)`=!uc) z*&4WUxc_P>;ldb9na-U)BW(HYukb6u#$F*XNX}>SgYUZD@$ppBOU@{ln5)38md-sliV8E3jb!!2vwog zx{%tP28F2?xxK{MUsf+eVJSxdTd9?xq{-7|9yK8}ui-ncD^MnJq%#Pytr8WP?ITma zd>r`{7^)v?*xHOIPY+OHGe3(wIcltZXhSs!Tr9xjWMT7$dL*&INe&|>`-!*aorGg5bv$uC6mDU-7aO6d=^8f;@-Oe-+z!5`B|TZSSxX=H3%aQB zeh`wB%@%U0$#F+;2zpsc-+M1kN`XjDrSQBwSr45mUJp(p8KJuCV++iD&{Ili98>Za zs_HJjk8!GZD2l3kEo?3u1yTl!mvNwqu2Sp2&*gfWN3w(N$VPeFc2QHAaYTcV)A6h| zj?rcX(H%hC<@7TA{s5{w(C>+498!#akvOZw@@I4iqC`3zdh;ThE8p42%$>$Dc+#q# zHw27zqTs4&^^aMshFm^cKo305usE214cptS5j{jv;&KF9)j)&!30#D0ixnG<_0P+k{%%KnzmT(-BL0E3b>jnDUyjLTs3Z~* zQyne-0G5C~{z@>-UH}5Hal(yU_??!?H_bEKTKq|#!7S7n;5km1g95(ZsAy?CQKQH# z7R2P0$3PNkR0IbvE%m3P?Q)6WSr(HZVbOniZKKP`km}b+C0lJB zL=Q-C1|a62@?bO0*y(h^{Orz?yv72crZL`yS`$J}i6KzR>+`UvR&>F%Qxu-k?6bC)9hI}vM8x+n8gsnGpb$H1# zWl7DsA?_~->h!V~fz1z6%Q{@vEE_Y8a59N&y)d2dm2Q9cqh7>*ew+J8ng{3(S^|x9 zi8P}F@9C+ul6n&+0|LJmE938ZZ-;)b=uat_yutSl!ePOr&6g#q%*BI%vn;=4vAmSI z_@Qc?yW4y4EYHGzUroKS%u%W&I@8l;E-9d9!MT&v&_FMU43wASOI`wX_u{!TLk3{m z!mR8Qv{xMC&x7#AQkS=EVrjAiXg^=-@Uv!$slt+!JVc3;Xu-b3J?adjz=cmmlzL8v zKM^MWbyZxS*{NlsCt@ESypitSk8)FrofBG2a`D&GITq`s5)#>bNY1@h z(AWkmFztEa;~Kh(BTqT!i@(>kl+z)VAMs2qpEk}$@oiIqN@1L;6FJdJtJFxfvjO&$ zw5t2V(4lqi4gs)5GuB%Tn9^6q_7`LdP2@U`#crFbm1~E7F*( zl%fj>=$TCE0n>VN(iA^(BbN4REBHp2A!oxm!93tmVf+$N8Jf+$p4`C@Al@+bxs1h>7RLWnfrAK=T8p5>6FzI@E! z!A&k1|AJLIyUsISGfq$c#vsqYf0p?L5AEMfjMrs zTK)t1JTrPFdxo8BiAH@Fr=RFtskw{RuRV%Z!XnR|&xHDk;nB4Xo z?e++RLw^d4Mc?{0K1@DJuq62^L#_J+24rD8NP`NN9-Sz ze&S!H=1&YqpEeI z;MP=Ye(betP}_@Ye%+K{fo{gfzVG00;D`ec)GLm%R%Tv!gDw;lX_HXG|LFL&Zj7n> zs~W{&HDjrJ=e(<*)Sl}MqhBqqx_)JG;Lvyv#R^s417m4zH2E+$;7Qzd8iAT5?)JiJ z3p>?5{WEtn!uo5HZKtW$6qR-LSBR`Eb{){JaAXA6@>{i?6?^#Y&+6d8vHBo_qP-)@ z$=#pMzaZ%ZUPS-An4LYTxGT`1T|SL~N2G4&_j+D91#ILjynJVGlK=f<>ap|smzhA1 z9+lPV((JnC^dl|s<(9arq+7{T*l%eDMipB%{q=rlrR)Y}f2xJB)LYOgB$8NYFv7Lv zXwRl8c%~=u_R`cg*0hrqG_4>F<3Ykm+jqN<;6_36mxS5ok{+#!hzi!KmtKo0u6$L$Q3pu2}i+ZutIOJPzORI zT^1EO>^9~;JLM$YMx7SYlLQg4_`L9`R zUbP%(k1|9Sy2jde*yRFXMIju=F34(^UXod@K!bl1hOixf8ng<(y-*hS2je7sR#V7^ zEK}s1w8m47#y^ejP4|4S3H;u*<9mBaTc~e3on;&3Wdm4sMAZIJy~&v*AG(TiiT*#& zN#8Lla_fQ)$qc5Qo1|6rGRdXcMniJUq4GWHcrFlSoP17ngJ$MDy*_>}bxA&1^wH#c z=ro(9k`xeCi~JyQ^`5WQJWX|4%~v}t*S_1>(TP>&?eY2u&=ewVM8%MK5F5y@iGlaE zR@UJuMoB#l+f2aZz&G-`8>a%tvzu5VyGd`erD(1Y7+v$-|E(?!t6j7WxzWkMP<9T7 zSC#8tEV^>UFc}=lL{!`HgOk*Kee-2hUrW{o6iP^UU7i!`-hN(eCU7OR+9kep=zu>t zx17I|HmedLYOB7fp4%Zp#@ZHV%!|H+1O~Rby>w}jvyvWe!)R^Q zlt)RZHDzA89^>YV{e0o38(KNZ=&bI%voyrrNIJ8XbL=Lb%EpAj^fBE8)!u;tfnEDN z5!#M_#YSc-x|M!(t4UW_m+wHvdRI=oB;gHp*3v68gOLa>0Wc2$w|@GrRb+;p$N#VU zwj4o{2vMu5di)f(_>{C4al9|DF@xQL{Weq#y06-r=iJsfdPa^T`Z>xfq&dcN{v$yU z%YVlMGhNo&qmZMAq@d$6aFYC8{x$GnwN;vL6;ht3#6`h$J}3|xHn`*%Nobb-U8dIR7At+NverLRse%z>st1x8;W3{GLxW=lx=HDJ37}7<2 zkR}&|CIkQ+FR?n9xE`-rBjr3q?v;~aIj*z+d8@F7vP>kVQm)|H;zs_SN`IHMKeq48 z_yJ73Lb4ui5>IO^drSpO7(5JytDos=Yr)aM^V!;EUu9)ct?7K5Zm$k&uL#$orXzz7 z2A>#5@GW2+_blW%h%Ica5>83tCrv^0Aw5A3Fgi%S1Nvelx17nBu66&fciHYO@=)Og ztKzgf>v(WR?}qpwnC==Ln?(I75v-q^1B7E}Q_`_Oh19q?ORnh1Vw?dElV%-l`tO$B zm6vc1f5B)20k|uywT&W1ZB8;$t!O#V6BJf+*S75#MUoDJA+v4w`=VC?hkRkrLnyFR5Eu}@Xk{!+8s(VW_m}#*VnTfqbMow9c0Cf1H zS_PGCFNa>KaR^U+?VGG?6VRLfJRo2aeiZ9`aS#kbj1(N}@D0FEXbB$2I!g)F{tHfV z4Fsj#j{n2IN;6pwv5<8JYx_SO&9w~8JR||(7v*AEVR7YzhDeVK8-OlgU2(AJRWkf1 zcyTjH3j2p71rUgNKB7W5JMkNe?0$Hg%d11W|9UtjnJrU=y|?kB7~SU9AicATc8$W{ zRjVLdisd>Y?CnNMWakm5eZY4Q|E*u=OMrj@D+?7b>2!GI?>LUok_VQUzXfIwE6%)P zL$=8F_$+|nhN5pw=0(49#Ezro*7Od91J-F55N9-kg{9CWZ<+SU+qsT7Lc{Ah7{(Pz z7f>`H`oR(jugWnlY>g3AKzPNJWlIB#_+|5h0iUXrtC}zpy4H7X8n&V40(xBj-h&eH zR4D9gzM*a3D$d_;CXex$pWZ!XD}ad3&xt6{zgF9WW9OO+#5{@aM@JF&3;m4~lelu=FfEr!UAJye8TlqB* z!8M?MjN~sMi%S4u=yD`JNa5bCPA*yf<$y)1EOC+ar@IQA<-~)Cx!cM$Z(HGq)VJy| z&G2kWwKahMONsk6Q^M-9sM_n8VA|_4)FK5yQ9D4xlNa(2|Fyz%c$7SZ6K}1ViQGqWH2ASHg1-j(=GsC zosI323&I{6LKt5<4K$xitRX`1B18w@A3aUa!b(1l(<|x#W3Z`t&K-L#Hd8R0AcIe# zlHY3+dhNR-lrl&+s#ksD0p+`&#)gea6e;M)JN4es36#Q35C!qH ztCt7Gr_-QtHgJG7rA2hM2TQ-bG|d+s98Hq3w1qY?3e?Vilr!`&@q)WIRZj$*$ya7D zx`1IC$@#^tK@`Ct;T(;ssN>2cqWLnkv|rP(~>THu~sr=*H3C1uG{rMf7g)4eypB-s0v`{oPP zCf;99)zp*C7ic4T8xf>|93y_Nt&YP_NV)0oK*!25w7M|)IYiziE^s^PbwPTzo zYj-GBqG)dUP~E2NCu-!jtuc>6MJZ(;epj;uj`-GcLM?2@im(jX@9R`wqo{ywMMsBG zYYI9bzK6o|M$gbdyS)F}K(ZR-wd<26q;8G%&l3gIalPuf%bKBtpS{3;0Ka-NJbH+t zvtYV7ia3C$Nv5xzKa!2a3J_-}bLdpCc3}s1Wc6&N_JE6(Iy7(8CtjMgSu&i!6zxK; zYm+z&<^K8;pusV8QXfs$dUB^e4iH2Tn}M7LNOuO$N$G>yXJb)O-qL7CGn%hzMidMX z*?IVkKa3ynE>e3<(34`M3GItx_gQd+KwCJ+bXc))C z1CXRkwxVi~V@#9Y(45!>A{%ijC6rPO=96WFqd~_YY0F2|2KWe@bcRc*^)UOj%-;zs zT!>a$nCO&-H0;w6x=Nw+7Ocab`6f|?!QJ;NI_AM>xSuG@zl(I>NV`%Buc(H@rAR38 zK+;Iuz`i`qepRy#zGZC7Ty13$B9klU)QDaSZCSDFF^HG1Rgmy#P-q{q=>}MSs@$^0 z!>6mUIT!KEm+cTfj6<+nGIEa<8MVWQ5LxAEXU0LOlko**^E~H6FOF%)OS?@sd5;vd zkG~g`>({dv{c!Hwr)vUXbO6~oL%Bm`Chc&%K?~XJ*Q}zj}-mX^x z<(eZl6q6(YWXJoomGn_AxpCBrgo`2oJWck{_2MThq2ZV$S#U7RB1$8HB7zq>wK}9F z#F|G?(D&O_zx^XTCr}Nga_{p)V?6syQw3hJiduue#LRDX6+`a4H9Pp_pI8=teWs}A zlEr0VIawL0hn2G?QjE`Ij7ka>nWJ?DYQ9n!)#PVxAn4?Wev__IpK?2}_ly&Of_la< z0fc9kVJ4G&SxZ*%0CgBS_%PL`xAXPnLd_y!l`#omlzjChZQGAMO1ocm{+&Y zYEhtM-zs7PDkhfK*pnw*D4V(ZchOb|+ONG49#{fX{=Uc4TLEp`;LR9=yYwNjj33f* zkypg5?TFg<5(+{!SaSEj={sIesv|6MhLm<%v;!+M`}GTLJLI0X7=_VCW9sQKWEApD zm!F^@#86;b*f{%(^}A#xHmgfJfsrj68O3_?#DxWS(Iz~+5wJa}l_oiR8GyCVU)T*l zwY+8w=7`#}rR;+DGYPZX28SLBb^ZiC_I&VBQNF7f8a2AG2fYF**$;3ErSQ+Ti2TGo zoI(lkkDsXB^M9yia6$6|u$_c8US+HM0>wg4AHR%_28`9TG=CFoZPcq-9`u^e*KX?@wtfV^IV67M2;s+%5 zn{JB07MO}Ms`=o_BnW?8oC&3roYLnVHC9FNkU=fy2iL6L)Xve7Y$Pn}CmeI!*rVZH zSeKvh5ZfH!Xv6v?28~QS9bqGUA|J4~EKfwdXjVawM*(fe#HpcQ#AdhZL|t~=dE!Dn z!^0+~+Z9oW5RFQg#Y3=QF_#P5xI|4&f4mCV*Rx6cqu<|oH5cK@k#z>A0p^pEl@juiVx7pdp&)Vlzve4QkA4s&Mzg+%()z$vv{MajZiBO{s0bFU-RZTnABaM*7-c zs1_qX1UKO@7d^AvTBd`!{}q0dCUGMkZ=Opt+%>2U)>Ilcbn?nXL;jw`52*~}gyn%> zn&WmRBCwiy>eD0N{B>MMy3`Xb5&#^1MN!p}7S+{x=+%JE)uuHmYuM~^hV}|pKHN8G z_@P#zp>uQlJ)@Ucl9%he!Jw@IVV7c}jYfbpVa-M@tK*yDk>|vMcj7ZL~F3WKbJeA>b%D{@7Gr!YeN0=ZWOm17Oo8;T9lAileBJ_Rn-Gz4`G!RwqDwT)y0z zxsPSmiO$|nI?R7a#+C$qElyrkZzgVK6m2n-wCiEhJvM?P$yu&T_8r0}kVvJ30_sPj zmu@aU7+erMD}$2}Hv@M-NCqi!cN^piskO-k&m(p~1}H@!!qW15N{ZBn>c+(V9yt7f z3}Il{ILX1dB@{ZQpE6JO8<=yu$O*8s#SSntjba5?se0~b8@l7V)SztA^|+>1zdIK6 zfLnisyg}q2^v{spRObQuHFU#k>|X-wW2I+6619&d72j8ueY^xs&0W_y;=1+5H3Wv% za!5?&-sMtKg3Gd!ak>$_V)=wc+ntVZ$+B5*9-D5U`;+lXuAkW!15u(Pk&vGhZOxXG z_5v`|KZ;?cNIBK>=dZ#}R$HZ*f9QW2?nt_^Svf*?!*Aqqg&_ZB-t%~la=`Hd8_}j0 zd_`-J)SJmSra1D9u#E1uo2q!{8PqaAK_#Z^RS^fvp{@S%H1$$V()D?<(C*MVs+#U+ zr2c!0nd85)&1f3iP~i*NTy>%_x8e<|seKINz`i#6;btC+=cm zFel-b>7KEO*QTkL!_7uNuIze|TnVS8bk_c|l9`1m=Vg^=e8q3UD zMVTdQGni!q{TSL4(47s~(uUUp!2I3xuloo`Hu(;ux4Nv0bwJ@Tg)T3&^9rEWY8G~3 zkMi;m-P^IahNs|joAFx1Gyi-_pR?lJgx>%;K*ql&LK~{7EDUuTF8ozfHc7KQK1^b$ zOYhL8BuM$;o=AjrbZ*4`tFydgJ`fTQ<;j{Z4d6D5y$_?&UymyD9z;?AIdGF&sVWrB zkz>k8!X~l3)KuWXZXE1oILL6w{hrAfhFJG!dS)Eai%cdV(XK2lioFEdGA6=9K@9)Z z9>r)1U|9D5axK=}>saeqqF=}u2C=|Wv@hy2m-c|4>&&i#W`BKJa0pX=Wx&@L-4$!y zms!S4?(LF{$wCTvDeN-cKaf7234a3W;+zYR_3<|bZY~V=4kq59K&Kk72 z-e6geU9|csqqZ>o*@%M7C1Sl@EMj1bsSkwlD#W|Hwx$R!S5n&(znh8cTeV-IZt-S}RLQka@=p2( zDFtKUtEVss(>fQ2m+qItBu^Z&KdAf(hdH04mi!Ha{wf{>&498jC3=Yqg}kOT6SD$U zS_GjT$(hG}3(lW05>~>?EzO{1Ccwt*2PIm7Oo>{?MYgK^D+;!x%;~nnlaif)sRHXY zjp^9^1-4WNYI)Mq!h;h9>OdfEHM*PIM07PbJ+IT5!dNb+0+Q_qqQxdrB69t0gMD3o z&1@p(?V)m!Onu#JiuJmBFVX6HRk zK6y$7LqWRfm~71uMiQ!oOg}p}w=cSCpC&3obi~A&fEh|es;N3{HcioXTVwuR*ETK` zxR@&~){2lH&8wEf84qVTfJsy@0d&)v!l5-DjpUw=A(oIEm#SE`3@5|`w&segd0~oI zTZb3jPR-|6+dSc|rro%Ku`xFFp=Mbx_`ixv@0mI7m!$#5iCOLh6;QJmN;6Ru!ZEp>g$*iJxeLzIc5G*POG2A%2YHW`0gr z9a^qu#v#pgEtgwauY1$ekK#qkv8)c(Mr0go2LZN&7E)TA4ZMi~nfYd0j6n7sW(;Mp z0h4Plr6$FX2GJq5D?e9)+Pcnp&^m4Rwi}0hUL$P%7MKG7jd*$|?fz58_0BsG&!so{ znFlp81r2A3d$pNL?W$1TATjaz^&ZkpN#6G+W1l{56dnCS^p`}!j7d-et+LnQJ|!l+Hz=r~Skdnaxj91s=uiZlhi!rBF&sxY4B0(^^~>aQrT;nzcQi;4LRe+GWE~S_+L8uFTu< z;g9aJ=sro@Z`!+Uykad-uqURrhU-pV8P5~)Fii|}%zz=UZ{B4eDESIZ!i1@nAl_%W zYq$nq@-%<%o;?!G@0fG%GWW%EuWPvokhq4Cdyx3RDVM-Ifl8(e-mydR-0nG-fS0D5 z)Hq!F6HEd+`8SLq(nXT%Qs#vgZFwgEvp0wLy(z`!v*7)Q2E(s8L&4DSz1Int-~`m8pTCqJF^IjKaSvM&>iyZhnITVDfm;%{T+WEYhCiWFX-Uvk-% zfWoApgN}JDmDf-?{U@HIvRi-xEotu_o*bv^f%>y&OCfFWZ=B2^Sawbjn{eQoUtQr@ z(T$Ogulw!KTlp@?#vr$Ol9{ z>$z)Q93FW=UZ!Y0(qE}Na$M_+EHdEUvm)d}N8U+0CXeO@Az9()psxs}%t_j_n#%tc4Hzfq zB@N_H)xkRHz2QN`F8m#P2#@#eRqnEB;x(5ClX~?cPI5yy8XW-4_z_BI_3@8#fz+?F z)v2x5H2KsM40kO6U-s&9%p-qEkL>d>+{fbeR@IWzo}{>O2whB}!S&PXB~a#p=cvUU(lW-R8Iipr)nkC)ySM1_dMo zDhoZbX!$vh%zq@ip-mai|DY^tFxgkYIpu$*q&&R6Dv=M;O{zb`a0~$TC`BIjB7Fn={tKTS7 zhz4W*k<+@9cMh)20|#bk9MbBJfDsy7RaJ+9T&0~}802S5Eyr*)-RjeX<*prR#i2`+k?vJKYyxR1 z9Xn?xtG1vwj!C!OT%dzLiBE=&hEA0#xCP(BBUhNc0C?pqspTU63aTG@Sz)L}2!NKV z{*tIBlh8KUEMpGI?UB8xXxs0UJ<{K<4^}|&?qh9PEQWp=aQE#}3Zg5=p1CQk_X_~m zyp|>Dl)P?fwq_+Y|8rJd?UQ9GLtGZ(R5&^^7}CVngAkb>5!$=Y0q$F1)FHG>z_zUB zl*WVX_PV^4j4JbskU?#6tyuGz$4By_LWQL`w~)h{HJRnLMd^z@XSmxdR5!K6n=tz# zHx-P%ggO?)V|hvM!cv?f12O&_FNZs*mEX3VMl ztbg^R&qz{tt%|%9LSLOl>S@UTH1b z!&_nWZs5l$SK#94O)3RH0!*Lp>|MK91v>Y^RKF<&DcP;u0m|!!3Nb#^4z?YhY_`O! zzrrM>#0>LJG~uswTuS}X@!bK|m}fk1V@0FE{&%5!F-K*2vUce7K~zD|AB1p-Fh+%8 zwa^w{paznBQaB?q9`ip`#i`DDJ3NPS2Ae(8jG?Bm9hPCge4a2Yz0;U9ja4G2%B@QU zjDMXeBTba|H6@Kqn=|sJxdx6 zVT1C1ms zD_}YpPsH%Ns9q10=2I1XcvtLzzWZ_or71asSuYWn7T)f`3y+!wI7zs$H6ydw>&iuc zn{Y2sKG@r2AAuX%~W+F8YQAEYI1 zxMTrs#o&vsc%8!#&knYN!vQlfU#<5AW8Dlf)^y(U0tWyyO*fbmsnD^J4^h53B7a zT&be~3@6k|)F_7q{kIs_8Tn6;u2pn&0c7tCQL{6#?G;}Cm@q>kCkKAJ+LaZBBuownB928JJF?^cHW!YhciKn4(jILcyqfq>c*{$x=3tZ=_6<6hMPsBo$U9 z`mS`Mnx|}nye4;!CBF9gzhXI6@fg3RO1M9P07J;N`q~}MRw*i$de&4=96%J%FsCw6 zR;`O+70?KT@!yh3DEFoBMPFfIsr-r34@8K2ga0zVGMf;Px)QTDL)xS2!S{oVE?3s} zwou(o#teTpuC8YjrAMgsv3`x-3kFdxF$L=^NRtg55Ivylu1F~=W7^yvzQo_NM*OyP zSp&=^GYZNhN-hs~{qE}SeaeK3vlnjTR~^3HI^CG{;&$1nFuq}3W8k%xnij(HWXuML zT9lpN@tWgTnk2zHOr?*2>L)<=yQ7x%-LxrBnwL(%cuq;|vdc`74L z#VsQUhAp-ES9b&tA4N)K7BzS zYVqg4o7!ST1$?-+!a{JBF}25eaizPGY5S88(wq~VwC4atpOe`R^$E3U-P^ro&8Z@t z*JMSRv;tK>H}sqybxvkj*CnNR%XqzG63|dRrNmUaW^kiWN9NG_#tImfZ-E7OrJy5g z5rYbHR3PJ~EC;tgeGH8f_Cw~t*WQJF^XN-4{kbpDRNs>5wtMRU+u?`{$04d4*AhW! zwI>|XC_Al}*Tf&K?-|N#WV?=H?VyOvo->;fK-$*v0+8Kb zjDKO^^}!tbSv)Yy_KbNfh^~O4{)XGpLtgxoXhS^jD+HIu_f38~f;S^odoWll9-fDR zOhiLumv%aN+gF{vSJm!-`7N>fcG6#McV3Nbg~ICHUV)3F;Y1%H=;ktM2(P9WD~ zZ_r8y)9d@euLz{1KcKG2_Q)f{rYV)P@O?wD7LshaxA$e>Ss;P;8S|KI`_)+1SXn~o zFv{Lgj>l;aOv(=LDC%8rZp+X17u$C4V61OFFuZ1}5cS_3E$ zai}&dj*HGQNT$sMdsyU}-1syvNSEo%!)E3#1fIDLv^oL1{dPo!lB)dt^MS@AYb*K2 z&)b3()nmzi|M*l=GQ0oa0kv7VMJ)YF=_~mgw88y*0?)=kW%twrPe`GHsm%tO%`CR( zEF5iP<{D|*#F;H$8I8hgRG#jPmh>|PFUvLqKLmDz@)#eq_g6cj?Jc1P#Dsd08>L5u zJ;X*#6A81>A7bIw>ZKkUPl!8$h#>e2=?b=wg2|lqMX)1=(da~s^{u*-Y_3=?hJXtl z!^!`{qtO}OtyQ*DfUjDgH@YYgFK|x3VA=XTs}C!77e00$R_@ehLiH$SqXZlF+g`4oOWeL_~UAbJ=D+Z>2|Iu-uW`GAb=g$rftC^w3~;yC!E zQ&B|JPt>DYe5X&ukz{Y?S55vt>ezRTrYmST$4?GxccAgMktq`T{k&}zG)kk$!Mt{b2+fk{Cir>MWkZa*M#sk$T}A$Vu|07wyH>yH~$rz^K?I7+L|^HvDg_} ztlrj$d8c@$2WX}glQ>oBrz5ad8^_=#OfG+DyHXBe5jawRCns!Kb-@wYl-LU4`zrW6 zChq+rH0=h*BAK|v7C782$~>dOf86(K&cRfuT=kE(VoEcof>n;csElr~@1L7UH&mqd zdYKxR0Tzi&{_E%Qq$A=`S-z>$nukPT2*_5QPGVkSrp5SKI|5Tx*R~^6?uw4osD7NO z!<(u0UmvhDAY|O$izWzXY*D21%4C=71QH)Ra--+$faUa)ngZOQ3Tw9=i5G5R+LGG! z7GLLB8Aes#MILTv|LT=v5(H5bkUsOfCf!&VGCfqnl!rbxg94P*sQl4pzA=I65jqdl z9EbEh7pyaoXsxnE_UGZ!sNt?=OZtaQeqpAQlYs-X^|9W*)~mhz?={4VKKCVfi7_C1 zQTA>lG;z54iOmH^nv5(XC=o5aO(S*qzUNjh_aO|?LB1K!-8?*@*nLJh)}#QbJmsYPeKEI>4u?j z_q^5j`?6hQ&6>Q;-5mgoO7+_oD!hP0dV3q;mStGSzq(F~96e?l3?nIXZ8=x4RCAz^ zgePlQc3-#}v>?Hg=60!21MELMkgCS;0ZfoR8=mhX+CkdT${bzUa`1)8tD=ii8l0zV zg8j=G+B5xYVsx3h{VY68LKNWVhm51^lI$m&sQceVVfSC*-IcXO_PY_2ShOsQa{8fh zR?E@RhC4(-6#c?+tIf3~_|JKnY>Iaz-X&5xQ^8xM0DVN!TyPcm3}SU0EuF&9hd^@ z#rwchNCi6l7Qa`iJ`?i8qyVU^x0=zmmyEull#<~q?8v$dClv`it|i|`JAq`~ytBNF zLn3u_Il%KSldfHGv6FQztjNZNpnzm+xNX>yQ6v(Hpr!B-eQY{&Vyrafvwdi>zTzBQ zn}rUxxLpW?Z`+aon6bgxN?n>JW-kydUq z!j}2o8I&CmKretS{QoCa#J{w8gW1zJ{wognB2vVoKc`QIy%J8BHt3DM7J9TpzVxmA z4j4wEzgQ7q!p$z>i^6|R=G^z?Uni5Zaez=y3Y#tfrL)~j^8610g2IVYzpkL6)p|>cZo^I=*XUX7nJ>Y% z84`>3yg}p-2+uLR`_RLrXdB)g<3MJXa`FT=#^`YL*+1A`)c1SSoiCgN`;7wo<~iQEG@5dCQ@v8? zGJ5psQe+4d;!(~DHSSMx>9>M>~?#>>0wJRfrQ#EVv5DD&ZmF2aA#hdwGQA^ zL(8}{){1ENDtDH@-*nm*JL-e_;R2%_e310SqdCa40GpF{nwWKsI!bL26BoPv{mO6D zsu{8&y-%pdJ$^M@Q~xt!IZ=k$;U#{!b9mGgPqVsQ6w$L4CaN~*$oFC*6mEgI2S!X% zRAp{yB)Ls()-V1=EwMNW|E5jWsQVWN0dDl@BDp;&kIn5i$qKo|%_)CAfQE(-mD$$( zn3X_k|DF4zFIF?jq=$SxrSCa5MaECYx&xNn5I^ol(9y)(BtlpKa7)G0H5Hc)+Cioi z&l)p2X#CfhV0rb{?CqhzG?~R7E_6jN;7mk^`D;^^`=}*iRRB&6BdzT>v~gM^qJtSQ zzw{TSJuL83%j}un9}DW@ow;U}{GnZ+#h*n8nW(H1TSoH?d>?5#-N-Uv0l)EP+k%=}@ANIZ6 z5Z_h+82V-}Ks{qI@YGl*TT!V_wYQaN7*pC~Ir_A#w%e%FCn)(#3x?TcB4YIMB6*i^ zk2$Q{gHxKVV^o8lKXcnv0@(K8V3*$1E^y^|ptT?Yg+d}m;^L#RPLN#aktHGNhrb0G zMm*w)22L~QZY$}8dAJzcF%JcMo%Z6Xs;5*(>Ro=4um41hA^fxfDvi#o8n);=(#I7c z157j6q5X(%o7!?0+}5I;Rb1q=L;pY1ahatwn z_~Q6sK&JiGv5KN}eEb(5f_ahu3t5Jm;e!%puv&dSOX}-q+7#9(o(}35LjoF4wE2T; zPW9`%QYq2W0j|fVDq*qzFzY0nCwZSC+kdr>%-sop5~4~`0Vh)AiL z^-r%G3L3(Z(=DU3pvkr7H`dYy!qRKxHDlt;b`Ld5y#!*6p{&XbU`8ZDJ)T z@P$4{AqT&USdnd~c6LGJp`I|ZrY0hM*yPo-B%B}S3Hqj%d*O88qkfBTI362qD|d`m zMG!|<>0Xtl036I1<@X?`AY9G3$V8vp#C?!A^%16|oUUB=j@o-xFK^E_pper5Syqk1 zGCH>T=VifJ9kJ%=TJ`!VUJP(MS6vpKZYlaPg(>sVO8NWEM3bDJv*KgX z=JPewmx~j0sWa^ik1qx;u#ti-m7v4-+S{2i`SdgDSuY+^9ap^9+HOyst-;bGaN^L> zQ1-XF*Kk$}bN@md+70fnZ}h5L2O*sTR@8ZrGGt`dAO({PQpA*4;nUoaesGD1fwl_xHUc33JcxFW&ie z*TMVA4A9tI%g1+lW-Oor6<%0!;C1z5lnkzn8zYyIN(V7AVO8mz&r|JOpd+|A_EXs@ zV8ROt%5tKGkoa7QRy9%s%YJ$=6@;w(Co!mlotow(DXCK-P=kg6|3-=KTNyPsKkQMe z)6D_zsVf7-A&Rj5hc9@_M5^{NLG9NnJt%k+8Uup6Z&Y9bIeF2w-u=n#fJXswAJ~rn zc^kF9!ZlA&xJR9dOoMxTDuIx96Uij+Mqm#`(h2Q{S^OTkW?JatvI-Ro*!%ImR)Dk1 z)oOetn@yelCKPdheZm%)DdE_XXDdHLAHPP;>y3dhu`)8n%9lS>p+;&vE{K*z^hSp~ z<@huFf~bL%^6XQCd0G$*SR&Pjh&`o}*r5@AQDf6SKOZ}mPhSp!T@kFGAW#t4&2H7+ znmHtjy#HCRS+yc<<$&s%&wE!w0rLi}SL8ZLSY{N_yw1^!HxsTG3Hh+QzXlJ>svKFy z7pEI=Babas+l577B0ovc%=WMh+$D=`Z`6G*}z7CwWbeo zSk6q{*o{wMI7Eql2#deKqeM;_wVSU3YRL{m`&xzw z_@feVrHKw}Ij4t&8x##Okmk^=jxtZUPq#*cu~>?HRe+35b7J*C2h;1CsIZxvYLwUM zB2f>L^CONTIN5qqp+^yur!%0_>3s*|f?SZP?aOo2`4vQOjGR=N!vSv9i1qX1(L{rH z=Ns2(eTyTw_X|F$5SJBTt*-avIDhGPo#gzzG*3(*qT5IHoXP)KY(i|OTpD;>gtg#% zPHF$5`-M>%FT!>?h~T7TTjbUkFtTqbCYC~;rb!;ks9Fppv~BZp=qN=R@i|456h^yl zuR~}(g4IN{9Zsu4QPNg~I<8T3aQTb_hBU>u{`Gm%)N3kp@U6-m`=})LoU7xxG$0?8AKD8^k%7u1ap!)~&D#}zwT;G@d~GuRxowj6un zVij<^svwot;igv9kFj2CEIGzgX)2TCc_0DpAgcSGlVGi5$3k4Q8DPZY>60K zo*w1L>fHKlHg4`cHyYQ+>Nc#AZ9E9B>`*c=h+bO$32^JuGuGmZADZ0L$aq)aP{MCF`1P1L(J!v*v{V@kBaYBZQjB$d8Gs7E#&JyDAIoo%k=z zQW2m;2}sUS$>_^K%}g2@v5)C81T}+Xhz*495`^@`j9|2dBI@kHMv@t+gx*T{%5GMokf|bwqO+JuAn{8&V%GGT*i zTkb}b)rR){WfarjFWF6`C^sWH0Rn0_wXA$90`gS@EMMS7u z@wMDgPkJe1XeV+DS0ma2Pwg)sXDg53(F*&PIugP8X$LUpo66cR>}&D1MVL915L(4B zk=cV^47OEBoa~3I&Tgsm@$R7J;k&os`qYK{+-1i*g0q|%dd#5f+ z=zMN>3l&)=kPpkd*XSA4^HPPADdNa^c~ z?Kilu%DqoYCvegMaU{)`5_bAS!)atNJpP>z_*Rnv7ip(++bA@9w`v#jQyUpK}SDW%5)XS$fib=&+%uVBmz z_gfK^ES&G3N$yFpw}MG#cUm4zag>RQAZfD3YI(HLtW9PO^GP8^Lr-cg(}9bj?3cN! zLl{?08f1HUOM1B9UTzYE&w;HxNGQYqPL?W_ue!HZpNrn~#9%5~gC+Kx@PX^P z)^B=kvjPBRDG#qO1U-@lSt0e!o^iyO?R^7#Gt|p!6<(}iKOre1qwU=1#HfC7VuFa;I2rvD;!zx(gtB{Rt%0m2x*GI|N}yMn0#T*|+Vi zP)`u&`JxHfJsf#nwOyP#>buCLexv9Gm!2G6UP4 z^KKP)iaTpZs=jgQ>y24pIfDHT&p=8`=>V-zdQ>RrlwGw&K_MvY_2I3f2vFfzsR z@xY?@4JHf!1{19tJUvrIz0c%Bck&h4HW35w*?t2#4-l+tTXP)F6B?xr&DIfhg*joM zcv&uaXz+laLa`Ayn^Uy|q;{IIQ(7E*wl=-g0$bf7HppF~jDy-zsHCy<6%oBhABnJx zIB^|y-Qyc=*3B2nIn)Q%b2!QnPCMBr+($lgnBQ}Z8K z#V#ac^^28J8XxptC}Nk3QqV`sjzbL_CXjOXRYwexeuA9fbavt3j0s#&Un~Sx_(c|Q zuR@ifWe@j#HG6L)up|bJIHi(I3pc47HB$~G7UfJ5XKyw$G-!|LRw*h7pfyZLt2kZi z`pHH9L7}eCW`Lq0wNQ2t79A(DOuxP)MZl~mQtvv1Z*ETpg)$Fo7cA(@(s^HHT{8cu zWW`DV!7cpZyAi1jS6d*CHG~aTjvhiWZ@YD0DsGrQZp+$g$v=$XQ)>M_&ocY`h^qzp&$Fd{590>3Xk$x5E9-|cd;1=J zvRmC$m80+;(L{?={U(f>-~EvK%VJsY5gyaF(I&thAPGz>8~ZhVV-jFV>q3N6o<9ix z0IM9>dr_AmXV7sIZUQB1SU}#$rU3UCtRC6?U#3(u&W%csmRff}N$b!FmbgcGWbnJm(lI1pG zG=hZBPs5$tv#tIaLAf!8W_HOW>eFhG1XG`yGNiJ+$Zp^kjhVG~#nm1GCGuZkF+8UT zBXA+%|ioy;Z0X>U* zM`2wV_YrtJ0<{^v-JgPUe)i2W7Sq&d`pi~j_EwzC80pIj_4r}E2Al@lOE_dXt#&o~ z2X-ysoE*9av>CUC;obu4btDjMTd%W@!H|I=xDW15hUH$J$1f zzIFd}ztnaX%FY5NHtReOd+yns#L5$LK%s8JRr$CnHU*hodZ+wupwSy(N6h}*#-R~y z_$elkM9EiG2vVKj!dP>8SeXnwf;?Qz+~Enw32wdn;lT40+fP<#FvmON)7eWK9yvKI zGB{^~oXm|E@-6?LW;-O|0WY(fVKAz5&k@Xfhar>Xb47scjxscVaB+@D`xy&vTApbt zWK0)cojwMo1o}-P=*;~qy@==!QSw{INK!tv`J6D#&MX?2*gE^hoBIL$8lcIzf~Gby z?~KvtUMaWu>bNhh1f>WRicB&J)^D_-o|x-L0K5J>Mm-}IS^1Eq^nGxLomce@RALpR zDm9`<4I^kSB!hjObCtDpRRk)^Qzvr)RHrA6ODk+}ujGdybk*d0n zS6V$TO!Bl$qRIkU@YL0FXU!T-cSh*tO(PlA0tPwUyHZhV^W`w1WH_>PKNV9uuZJ3wB3!!N63!@ z4GrPi@AKh?(-pA$mrTF3!MDE9eVLk; z%abs#p=JtYQn_KY`>a9Y`Cmj|{0@yJST>@B^b-CIo+y}WSoZpU{8N#rZC+5kMAXaX zCl3{G)MUls^-<-4X@Zc>w>R-l5z)U+K_Ox! zil(AECl~PjZ=r4?4wYp4Y1R^j7A(cL-oiPiWa`6DT>S7TFUsA*Lc61A+7-&Gu-tTC$?3r z?@!Yb0CiJH-8^N+qj>>$mZHT6<*w;ZVm*?u9-b;3U3}jX^qF6UiuwX9<5Fe$Mt$Go zy$dP&Ya9WeSRKakIJERIMJ45;4ox0e%|D)|jqzW{<%H^%h&8ES?c0l0O*NpwZ-Uhm zl_2}3bdnq8zEDJ=;gh|KcxY4A&AqHlV>&oja~WU-Ir-kpJJ>BhR&&@oU9O-)MDN$T zX5yz?!!8kqKQPBLza(kxue!3XA3(iTxfkh@|AomX+$ z#Ms)K3#pVIDC}*)gRWMV<^jY54)c1vT8udrFa_)XEEiCkK% zTMCQy!u&p(;m4K7Zp6_1Z`1bkkhq5A_}|Hh&miWk=W?<)(PY&b*krJ4ptVU^;eF{G zX)_zdwy<^DKyOfj@0rBe#ymWN4~&67 zhqKE85-*uArP5CRQ-JCeLiGZr1;egi!r@2#>%$D@`Lg?o{_$W*6w5-GipEdOf$k#ujcGro%*#tDVvq+GOt{q( z0d%!%qO-xo>>%tw$SeNM-;Pz*1J+ zBJ->CWCWE0ztqr2UOlPwbI^M4ZY7c@&H31liV*_jRSBkl`$Wv07wy=rL&_$jI)pRl zU0bggiDOIm$eYXzhy`yAv7bL6gR#RQCmI7i$Gs8T@_DV?KeMpyDiGzI`iQ+Q&fS^BCJ|2BjmSZudU(&# zCYZSHx(G%iodU&?T{-JqMm9HxIpfaOfA~;&@(~cKSafeJ`O)Orma5>H^(6?791P7g zz)okhc-rB)KS*C5FbjkR$8Q36MipVE6~PiWSi<04c%`;LH&J}%BG8ZP*}}C|6yFs$ zPW}N%&s|;e^Uy|2Y>oENmW?fwfk`^>V@)v^4Nqk3PMsZRpViFr_!@Ksy~eTEP!zNT zoc!lI^|wNKMyg-$@BB1S*}RW{N0|C4z|+Af(rh!btShgfew=bMm^SmG6!CSQ<=^Ya z5zM+fu1Q-Q+G{1w6@3jh`s34~Y}FRSsF)hSs1nS=OW*q)paYk%|HXrd8WIF_9{-<6bk}z`)+|TD=n^eg!}! zxQ0``3Eaf0?aJlPL}?>0h_uX&(QnSBpLMHSqoeX~|D z^R6@YqXVMUSE-`R7(#+HaA8~`iSL6AguP&ux?>*BFrt&N@{PR-IinIGvPiPF!&1Zs zB$GhTH1INFwcIHV6-UtPtv0?{M*VsjaH)*sA99Ej)>PRAj}LN3hFz zj35O3QW`8{DW3&xmJ|s_o4GNDt5mw zNC*m@%{-qvR=vn77vuTUpoG9L!1gb0Jy(lJ%po2@K{vV6I+flPsW>VzWA(s%TuyLB z^k2{(KltPRJY%8PAG#hH_s_p{p!kq}0VqIldz5@nw>6})s+ZCIuB#{~GyM%j?)uY- zDH^yJK9Fwf7g0YZw`#cSDrt1E_VJINa;e4f#n=m3DY*APLNdwigqC`SNc=9ys;l6kI?VW}k@-3exOnuqF%0$EYMEE z)OiTW&}%2o0BUqwAVtpCdgf+@fyCX9(pcNump885 z-0nC$Zj?>)!;X=Oc|DZ*`F*Ss1)l_{c%MG+*VeOhcOI`(XlN^>t|G8G-7_{;Md@2ew!W%$L+AGj*5$rx z0X}c~)<~)H^wO|W_1OhPn?nzpOf?RkO38oho~W&%(ej0>I&=w@tK?-9ORtV0gVr;W-$rfKZkJU6^xoQag!LGLKQ(kLVlP_( zt7HtP=5O@YWT+x|3Zagsh>mAp4Qu@dN>WtM3$?x5MgAKu1t?<(T%z|au5nsxRUnqb zjKC~t2`q1j+uHJ+IMl>hZV^)e@~^mMFu_nL2WcRT8q9!B4I^Bq;etM3q#U$Kx;mSz zJH#ab{(>dUtG7xtq(j>XS(gnLB7Sa0FNnSnyjuM?YFc}gpF(RG05d?$zl#p8o?A3T z5icl_{(2oKgesgjCRoPYBX$sG>4JaNsU(~_zlUy$ce*U;s}tv&X;^L(ljs=qZN$~I zp3OHOmfb4j+;ERY*7`q)lN=)_Mo6Oxz4nMjf_t@d(^JVYJ`T(?{)`JgtfJnrzB!Pf z5ipBe8;%8xv-~+_ht<0F`2@TjU13V=SkqNN@rqv|eVx1;Pw{t-teeS|bA$zZd8)&d z38?IR1b?q2-#QLnLr(nRqnrb7wsyQ#5IJto*alc>K+cCo4KWAJHme!;7yy_eXIr@T za^tQ7*FN)Y`2fRyNaVDak=$+!lr}-K*yiZMOeR*UC9sLT>7=-WR8dT49U+>2B-0iI znJSBhh%g8hn7`_4@D8xgTgaYD~lANfFB_e zX1E1s2}*dE!n^mTX#oFn)RiJQI)>jKU~eiKaa=fsbAb%(tL z#W$V~rNQs0ve8h|j?5KjfQnRjN&06W8ktrX|6a^=B|Xb^(%vJv79jz9kn@a~E0dBz z+oDxiUG<~pjTGSTu%BIsW6M=ap{y(oNw#V~`jR54|MsHk^`*zVZWEe3=4G*Zqn`Ej zYFl6f8tLzg+1$Hao;KDA`VbUKZn6BQo>+76K$ZVm>m%n~YXd0Iyq+IBleVKs@I@+0 zV82d5Q!fvVu{Cu7O1vUroI?gCFVvjV56CJfhH0)y0B^7T9wxFdf@(jPK9MLdL;E` z1-gZIet^r;=F;6e-MI)!hRyOianABYCzl|{Qt*{^NKE#`oAF3-d1CPX0JfbY;%Vn# z)qJs>^IBb60LrQ^59tq{>9-8Wk&u9u=(P5e2;s?RQl5$TUQ>rHn9lK=MON+)(xti0 zw*R_eq^8Z|fWb0WdoEuSj|RSv@yHHuGXxy(B3=X%u_vCN6*#>#&8fBy>Fk+txyARp zh=O4`?}S)X3b_jV9Xj)E5fu6O>A2^0H^I!L2I-+j0tk*MK_Ju3CGtg$*N;iuJQIGk zYhVbKZ7)n3k?evll{rWgcVOOp;$8f?24+_753oS%tnr$PU<~V25bzTf`+-sgEuf0s zDRqrgY6u8P-+>eIArG1M#tFQEO04>^NZ$!D{-`~~Rcl1L1 znekkP|4zeXcfpAn2F}aWuzZ?Q*@T7KR}8leNnAr^&y+5}{fM}P9MgWcN#*c%4+HuQ z#mn6Aiw=0)^2L(EFZbd=fcxsY)~^!6fY+Qxz2(e^S#uhxBG^JREBP_w7nJGFx(o33 z^B7$gevX%=1V1pLl3J9^%Sb4V+dp*b&BZN)3k%TiWWdy7(f=;I!T8_*EJdfy35EXH zCcN!}x!8&}dS~&GFXwi>DK%XI`)vp;$u7$?3D;}U{U+Knog*T@kPsktT|+_+0FqyD z&x@3BQk3a4C0LtKjbFoAM9N>~3?^);ic-&d=1HOW#HY`*hOx3d(eOmJ8!UxdR&` zf9dk*6Xl>ewKwJ5_KlzQm+*>10vNocS18+T`jdIOAx3qkJ28C1&-G7Q*>K#=8C zKwZXh5`{t+P?My_o@F=;EAHf+&~1U6|40YrIk6+d9D%?b?hpiu>=?|xTb8O+Tklxd zyd*Js$AVjSF36146Xl$tTr&3oy?pZZ47=GFapws!BS5EGWVt2 zHP=O!eyS=6$3GW{EF#X{v*TA(;pCrcre3$^4F3OwDJyyhBcwl@*%?p){c4omj~0K{ zm82!FbrPLMGMqKHDuiR#0mx-67xk4m(-9nrxGLz5p-WP~=SKsN%UeD>1?9~JoDbw5 z;Uj@p6O-;H-}x=K><#xYIF?t!z^mtob2CKNvWJ^Fb;U16a(AMajkG7uc3*o1KGaAc z9W)1*2LaEGuyY;~L0#0dC2A!ZosJ_;xS;yC>y*K@zRwmzqK_wi6O|I2lPj!C28wgY zK5Y%xnz>FedR1>6Wk1f82Vz@F8y`z>ZQ|}I+9rMW!hS6TGHuHhU*`8r<7y8}C{*FR z22an}6_h56MM;^*pyb5F7SBR;OW4YwB*%g9>Wrj7Qfx(lre)ByHcnqGzEPZdRF7*I zXkI_C9n%_LmHx?z8b9)FM!oGTU^ksPABf79(>xNM{v~rjsSiRd7Od3cW|TM79xgft zXL3kfaFAXVJ=${UMPe3%$uh_Vz+WUzWE?i8dDG30A!K673pv{G?N{Rq+a7jVaq-LK zdbo*vOm3{w(jUS_7ys-{h}Wh~+C+ZJ<0fnFeweh-sRWDQLgvJJ%1(lu=JTcS!{;eK zDUwO&N>v_9&ni@mAyl#vu5RwcRDEs16mUfcx;zV{!dL-5o{s6yGY3MyOKEEqx?ZH5 zQ^Zt;j@DKcl&I@k%_$Ro5^9I)F$rQ?5z^@FH5{L%mT)F{3DA|rDtJHL2YO*sT`@rOUs%67518{20e9N?v{?{(d zg&;BfZ#Z)VMYCfQb{3sm=m$=AYT2tBp#rl;Z6wtwbq==((Tl0y}b~j?8}P`^QuHfPEpm1+!=84^1iIKGax=(4Yd$b`dubri0dDEfSs`|c!(>F`Dm?@ zUqGEwL4`_|-3*q6g@8LxoF-zFZ#Ij4Q6K!``+kO=JRem20C*o_Dv*Xxvb`O?eqE(i z_K=@$AsIPfFv=S6Woc=kt0ns;$aZFJ@TQpkOSX9#vdlBh^~};iMk-MQbN(t z8z;=H9q%WgBTh&2vtnKos^EDTY`;-1=O;W}hd6%F>%9hj!~A!8!@jR38wN^@ZVyu% zw)tIVsW8wQ;KaC3ENao{tkb(_!qCF3qh~))<<%52Zb7o&U%U4G@l#^p;3Hoj%>(_{;GB~pO z#Ei)rCzK#e7jY{4{t)bnk}dE_CW}v|53OK6NB1buE!pUjGlI=p0X`@MC+o+$a0N@5 z7)$w=tBKZ{ByMhqXDmLj!*V;qshk)TOB2aaVcx7m41!`3N^xi&uEvP~`(70(WUCU1 z?{>Qig>aPSG(yp#G6998FumiY3U@61d z0~HG+YbQ{TCMeATe*#?osYr|5VNxJM_rsK>5G0jF!-3;OV4Vpy#guVK=s1S#t^58S za2r4nllh-}WE#T(=I3y*A$wuXD?%FSbMa2(=`d8V&9@AOFLA;=)Q^TnXYFz<@0-_f z>fFw@yH_0t<97lOm4k4979gC&;+OAn1y5V{HhHKHG+>I{7Ij%UL1}6Bh{H25-n7QE z_9>sctwdDHdXGVM!2tf_*W6X8todcfv*9nkp5y{=nT^R(k(-pTqEI1R?&L TF~f zc64x@X+6TF^h`|Q9Hr~^+Ab}9wI0*01)U7Xm92N*!GSp%tVsFGu>p~_IL~T5 zwmGX;9-vk#q9hVFdW$gM3(&)+xXZm+vI)oy*k(uXF7>ERL)4-<@rgp`^@v}ed`|pM z(x7(t%>={|iZHur!<8Fi>$$zX_l3Lm=n8Dx26Hc4YzfZQB}k+&=c#j238N2#xK2dB z4EbI#?^~3&q_+DgSQ$e6^gigX`!=XJ(f}j2VDfu00T(Hrz-2r0E2#-6W@?Fuof5GygKfV>Pb z7@Uuh-2{>Dyi@luz1sa?OH!U*{;+=MZc;l2C}8YhKq-D)hn|s4;ML4i1~CW*l(I#R zxw4+*4#h1EDl*}6D|(6W`UOZ^z34rl!Cb^U8+~(qfz2p!3lmF^s^2}}_F7DA66+mB zD+!o|k3_*`yU=DTGdy`04V;1yYQXaa_3~1|K0dXmL6t7nO1S70h=R8c?8AmyOqqKO zHJTfWESZXS%^4V{YljdivhsLD>vyH>j7)u#vX zj7(b*dh1n&<9O95{mhLad9Wjgs-af&7B>23A%Qz4Qw9noBC7u^tMMKAvfUzL3f>-) zEuh5SxWB<1NzZY2*gX>%I}@sE`>0PaxZ3pmHZnCI0UUeDAb!|?roeB3}=8ILRz1c^?suI`?pVZE|<(848MoMj??qLmDQ~a7RF+l#%q>$&~7SQni{dt zAZO=%csSd#{B3Vl99V6_{l%~a%hJ45N4Ec=Zu5hOc(O6{B_wAsV-{3{!zdz$F8#j1)4kQz5l%e6yvO z*DvMIUW-%FCPlVrBx<9)b8|TKc)e|)f!tL7Clzfxc#YnTE7GK@Dlmed^#@>boEpI6 z1O8BHhVBaKIs5dgTU-lD;^ez5V@9TT)<6AMmi>}j0Dh?fh{4iGd(pJcrMj| zW_)_S`g6_DrF!+Eb8%B2Pq1=EM1ZgzLL9~Cs{+y&;*4*&Xs4F)|EIi3;!uG#2zJeK zm2+>7XiUM+5RrY;7}|v!H-4&1eKU;nj-)?hL9WmKHCV1rTV%rufDwd0td6rgaKWIt zg`N%G+%SjTVQQBd0vPV@C4(ijU=TfYOSOq_u90~Rv6$AXAKrPoiuIw12@@A*byd6yhR$fl3_Mm=2gEyaD6*947m0|g765l zqk!!$;TxH}O&wIvJl8lmL+*Lsl~f*O@oqyZh{voDG8yI(l`VB=*lekd{Qp@F^%2$B zJ{jO?^PYn~;7Py$dFR6tV=+hs=0NUS3b2U=jHtO$un@ZfYx8N9@K&*u3IPXc*sL7XHnXQ#Nw7 zf{}x$Z=hbQ6mxg;2^t$Dz00;-VJE#N>|`dq_w)OS2VbN4n~s9E;1u@~uiHTK9L&G8i0 zG_QCu4_3UPWYFT!K%!8fm)~#Y3>xH~z=}NZHyT*0_^0Am7};dHdq?r-S{0tH@QU=LbM-l-;c1N~iP>1sQ7chugU20!<@1>Y zEOLmjKirk48>uTfU}V-IIRLd7$mu-hcI6yGed(V6JSVBC?<~oLmU$2N3C#;MIizL5 zPXE*|Mf3|O8a2naGQ3e|CdT(O>5toY(Mm@;7L5dhNCW}aUF!oKuIy&$_`Whjzczkr z=&MlLQ`F-X;|e6lz9Fv%IzTxpy|E%7FR1|o6NpaJCi^_G!*|EC*Ek{Oi{}W|VjE%y+-gbIWv;5 zd)?5tCOkaOs`Kt|4hE19`v%!fVu+w5A3U0rHWh8a7(xvrtUNR%)Qj7|<=LcGYA^Ug z-{S*EU4Kqrtpmp_3#*;Up`>k7dFJ-Q`2CPNVPpxlMd5qxxBvcS*-fwf@Vz_0prLv4 zgXK1?{=+3&GdW!t=uaF}C_+TM+8dCJxa{vxfB_f+=2Gim$VyixcJi6Ln4krPq(s#_ zO8Qn;-m}psBbIweF^RQ3=yUT4&wr8@EOqZhH(YAU-mp^vX@!x0f@6%9S|xSz@$laM zeynVzz~4lg$)t`(H=pBGi>Kk{lEVG{ErT;@fqT>R)?>*Lr&a%_Hw9GZG|_u&Ou*ixfdN5rkF}=rGPIl9O7SnT7y9fe8UccGlZAOMU!yvzC@DC+k*Pm z>tHau>Zd`JW;5HSOiL9WxtX*5nDJd4JS^$#up#hj-LV@H!`$Cf>x$e$r88w({y+GK z=}}#o3~4<)L@DNc2|+F8$22XxWllK;5*a0`iuBhHIcq5%{X=z@PF}lN$adcfZ#LBa zIm5S7Dmgq!z?8T*iQ8YPDw{NW)KM8ZAu&Rwxze_rx+7f)iKG|=P^?5gK%a(QJY0s- zH-e6dQ7Bt25sB*`>mxndmajuCNX-NVZRiPD%hEPZvB0eadp0E8%d5UcE9+sWEZa_=BXF0B5@Q$phH!gKa-i*9rO6<|wcZd$ zu3iyVVLq*>VD!?R&HsR~7pJ|>vQw9nb)u+$R3HHqWt3P{_8}CyNR0O6h?cN|42tVl z*P-x^g`E6c9UuF^o>6E$Y1BHeAHZh=WDXq*;*>j(3ec6Hb{D=@=>1l5X+K>C*i_>o&z(Uqnm5mbv^U!|J@P% z)SEh`2hE{F_lj_`)BGKsF53L4*@dwebLHBvtMm?l;)D!cs7g#Sj&#escI@unXA=8!q8Rs}Y)8-gcT3eg0tJcxdGz z2jMvEydZyl^QY6}N=Wo3;0;s#&6S~V`0KT80Q@F@nj2EXjD?l0#uUND!e1%7n3u4& z(N(SE{|^`Gd<+r9WUz*W>TVoPD9cE;<0hs?D*MKW$+`TeMG8n!+US9luB9L5D&3 z-sE8#H4b&P7}a>_sxlIfCdM#`e^~ zmO`0*;We!3b1EhcdJ0}p?a(Oszd{+l2eHQX3T?HhT&`aQ-*YlcOxodlu7@Y=`OFJt6_!*RDmILll*M-v;KBa*j3Y{fn2%%>C-IxI{wI2E|V#>>i5U* z)%V1o%Z0v#KSYr7T*qtvU{&JQLGQm)%Ot`BMv+i9L;G*4)jn5Oq(tARB4UO2&%Dgs z7;|zEg}fQB#_wy-{`Zp#d4_kw_h7()N?B?u=oC)`k>Hf@(~pT|oPi@s9l_5}MtPMT zYj%nG6h=rHk%z%bF(nYLl|10~Wo!sz(W(wrwQv{lC@MU?BAYE)s^YUBS@pdAhITuM zTTcm*gCAd5ATo~T;zb01N9zlOtvk@CZeY)2e>_+wO*jZ*&?jB4#RRUT|y{K+0wB2dQnEAzgOmT! z6z@g)J9k95x=Cs}D8xM+itp>~e#h|Mn`!>n=6a=o;fIaSdE1z-k(d|RCalw@@GSPw zNR$i~U6E+J8x5ufEF}}}icEtU4*R*dPdELF$NeAz(7FkmplQ;OxG;-d3!%ZS9!PPU zx*+m{->i>WT?5nHQ8fuC=Rsm$retlxjPlrRbfQ4E!(j75mjoT`sm;aSJG%1RAY{mz zBs2owvYZPXAX+HHD9Wy;!8#TXC+=)uX?TYh`4adBg4DE-x5H`M3;><`ET*(iR~&(; zJp7|Fv!H>tp9uf36v7PCENY=aLkIAQ-`&b%CbFodLP%tI+Ie}@=vKk&+;ro!zKV`8 ziD559*7$xnZj;6w>KMbX7_1=;MzK)7>ID0!8aBn)*GSrP$U|jJRf)r%B&n=RT({G% zQyJs^oe?L(CDB{e!sC~$hkKXOhvI*&dII+@d|Gjvyro1JceHY|`eM9SppHP?p%31* z$T6@#dWPR}lsYJwV3;|=Z(HE~MguYvd%m*6us+QtM{zvk2>tq)sx#&o8O%bLIkk0G zyOLH|t}-2spQt6*`fec!zQc*Fjg5nJO3ykzm?K`yg5F|GHg#?90i^I(ZsoXl_ z5(raIZ|=!0Egb=j%ORiIwfUTNk?@u98P{%N7kArq@6pWx^$S=kG9x@i7?+l24(Ags zoIdwG)|U(XHm-!FQ$pZgDP7tI*J@2YV!wnzL_G|aHtjF{hbUU_wheF7OhY%K%@k^S z3?sp)u>Z?Q2sodESh6DWb(~Hl3C{%v{bWF!aWT2%GJl~`8WW`zfHce}eKWvcYG>~$ zf7Ybt$&QdXNAY$mn0XBV@R3w_QjuR5+qzg4*L7oL&wUifiR27zc+sV4Rl^;Oa@{2= zo;DMKq-1>x@H-q?Dd3H{pEuEzBKz4tAp0}up#xaXOC)tTdh8N$qmvNn2?^Jg&apoUKkW*E*PyDM7slF8E&fWRSQ2&sQg``2~h`KB5 zNN_sCH=b|NV$o)GM>rkldYWPDef?L!p;3r`^JG`u z+i2ZuqJ&31ArlJIY*)9`Tq4b93Y-q&%1L>e&Xy&;RJR{uqImYxpab5%VC{F=W_^hU z?qsOK=a)>7*Ktgw1xH`~UN*g-cC^FpJDP0(I8=UbCQ1x6_=rO4e$l8{{WT(E2ci?) zsWr&K5lfx|Lx!Qap+A~p7Y(xy>Gea&7Pktib)HMsZ|1MK?~jeB!rpeOKcx>Du&I7}2R0GPQ}s}NhV z>{IAQLExwgm`XzzM~x}aNy(_EMn=7t@rT0A&{_eJuB()-DG&MBuA~s2a_%z{QDyVc zVUt`)!k+A)Yu7TR%Ypz>Gnm8v8xW}g4qGxg&joZfG7~N$x9ak2YNCWqAtt=yq zy;4KxjN@4Lj&2{InvrgkGE)szu?jb7(}@}Fi=NoJ*?AzUF?wMHN^CR6Y;*4EYTHHr zv5;d~e~#^Sb~oimboIvBJNuBJvPrp8wn^jKxKE@v;2;Tf?+7%E{T=%S5kR|WP9E8o z@hZ&LN2bF(!(ATIvSyffA*{3W?ZpKs{4}Cm=mv0h%`KGKH^c?GTUJnwc!8Ei86Ecm*W1mPyOgS2mdE_WFx+??Bo_}_^bV zGpH^7-CObTx>QD4Yr_Gi=LdJ$+6WJWZfUwEn`!9h#t;jFLERlhN9?YaOc-g zUEzX^CsXNSYLML``7{4I10Hv$g`rkC+|&}#i87}5CDuQKe1(Y*E`RRtN8X2zgP41^ zQEnhThkm!${qBif*9KUgF zxqp9=C-Xbeq*D!gY6kO1 zcDX&RUus!WPA4X;(mN8cvXA*!sa1w7nVNprF(8Xs2Gi*qXO`_@44G7czS30~kqv*+ z$>%wvRfooy_X_5a*Rp@x5SFurT(QbM)kTl4?7rF0C}L3b_QaR$ZNZy1UIxLG2z7}Y zUhu@nZM$(Rh|NEm3{WnptiQ)TrEvKF8EjDW+g(N{cuk55=#eiyf++vr#25%%hrZ-z z+rO`TKcMl?*=vvwSS``Ds&d^Zk6?}+_~HHBC|x7w;@%ZRAzc3?2=Nc4G!?gci^6GS z8c|M`3JfqxcW?3sL}AR%Av_@ybC_Q^$Xp!Js9xu1T;-Sld9=~zJ={9p(*Vjz4DzQ2 zCqS)_8vZ}BrBGx^0|eSw@K`W`9V)ZdOn6>X_Bq7mQaBlr$e5&Nb4FKxj(A_tc zZgQ`j+Y=&*)LQ}XuO6cNt?nH{Qj14?-1^ry?CCOtxv>&Ed58Kf%BV6mmO7-45sK{AM`;KS-- zFzAN%0MmGR>npxM-sMOXxd>!YE@9^ydl!E!h7_50K0!q9dP|+8mP74KvQEicWIBYD zilGC{Cq>(-iRt&47YrMq}J=VEHE1!itq@9%4)9S^pK{&X}oZRMQ82#3xtQ&oQdT@mW&a6XpqF7Jl z`kbRqpc6|euX@1IQRpUrPJIU8D#}!1N*CwY%>O2g+g+xnUWFML z1Lf_<ZlHI;4+;95iA^yFge*+1=>PYP4E7MkR%t4q*NgytUM~t+l3WzPU(n`gkCWaGHS* zn8t}Y$NZO6lgxd9qU(^6-;aawq`$woSw%Ty7;Rw z#>*l$9EM|H)cWZ>bGXRD{j$>XhmVv>giqEq$o0lPIhstq>G9>9s zC`^-d;QXt=K&1~G^5^OW4MbM8N2xVQH>Y9Mti+@$&^5f;$uB*7Az8XRfoxmzA*CA> zk|BF>U^tG&(v&*f;#+1=v>+!rCnh8FvjVLG8k+pCDZ#5ct02) z-#{JW-ucZ~FUJl~ED|VeAvHL6=BIEL3*;Z|Jn6ZlHzE%}cnpO7HnE?BcwsQ9eZyHS zLg)0pp{TPO`(Yd@tUT7d9S1(^hh$=q`!Q1?kne;YxR^{ zlRd?p1`VYIXN^zP-XK6J3(2*LXal#_lj9Y=&sB5qQW_t6Q_$~m0!DmP*;uVFB>!vb zNe!}r^s*IW+?uh0z7;~RRCGFtt0bQcTK^;)q6$^$tvh=xd2@RfwGXOY#mZyS}& zvQwUy^3)0(?u!r^s~iZkKp5JNwU)tQ52=s$8niLm@$E^2uQls!={)w>^n_g*#z<)4 zF7=dAHx6cl>?V@&o&%7JqK7Plm zqUoRO?lJS}oso13N;;<#^07{$rOEcuYob^nfe6J;G(DeXu08O^86|@!CWL4qDLD#G z`TaLJjO6kcq<1C^VyM85pIBRVW+7%IYpds_X)mR@mSaXQmFg&g4!wI8rY?L*757xc zVQDdZFc1}XEkxjr0}4PLE~-#`iys>~OPBf9KK^!+))>sbxspbulJA5=R3TXX0ttBt-^tJKcmQ=_^*{L_9xnNu3(G0BW z;znFIisa{ZDqWRaH4W#cDabEqIY9-=$hJqJ?{@D8PCSfQH0u#-^=v+n8BtzZx;E>; zf_>K0m9?(GAvCA{E`JAA$+DnjVGTj?!)v8f?QV&F(paHM$57*>ybGdPt-6j7iiy`E ztF)eW859gdeBw%kiw8oF2T#8xTB~XDpgU()4l5K-VriDL)L<4{#%Mo_Kk8*m%^b7% zi?9{sN}vd2dZpKrY;~MpsNI};e2rRE*fp*kbZ%68`u6i_!zR&HPtqBcI}Mgaflpsl z>LCw#E;k&AtOTkz{yzVdo^KCTc6&J0eVG(@d`Jl?d;nTjXqo0%x?y}5;ody}xmLlj z>0=ettfU|%*hFnR9-_BvB)_H->w8`M^>Tsq^;bm6q04`j9)A(NK)vm<;0}*=O%?NZ zDTa28kfJm=tpjM_ilO`urM-gH4A};I8;x;pREchk#jC$n*~DyodI^CEA4_)Jv)NJ=)c|{)w}$Q?4HQb*sd_CNFw~utSjfL#Y7d7}GIPfJ002A6XFxmqzx>Oie1EVsHOtvEAFSGJsSs zEu9*hO@Q$oK$VZlnQ~X)M+Z(pP|7X>U^P)d>tk^`Qh^TxysSjysLU@6=6h*Kl_)EN zdh-p9VK|aK0vo46a4WIHD%V$-@$f{Vlo0jZ+tn@E*`khQNKP)o{6%1=;b=sZx$Nt0 z4Bryp+K~Qsw-;hV`0#RN`#zJSbhckH2*}y#d^e_sI?>;iyB#kBPBvQBVs1T(%t7Nhn_8vT0pU z6mr!M_(YHk3^sTdeJrTnNIFP!wOxbV+W-x%uxkoVTkwk&Z;uwr!b=U>1wBt+9&ws? zUA4v7^^G4pN9LDGd0tUy7@!t`b1rco9+H{ZUuU#2M1IG(%d1+kJt=#(1cP1q+z{s> zvEBKv0t#37%5AXbws2zqr!#qA%pV+U-%;QFg}<`b(J@kN&vNrgQow zwV{jR>*R7IX^AZ!mN(Ez1MIHPAvc*u4sxk<+h>yhv1E15Q;{WHK%riy4z0M@ITmEn zfl;)WiE5XFTsIDoq1{T;yJ|Dv#Y<^!-^4{Ehs`y!hS0fXc^A8sm@J!!_F!CcWyY?L zYS((EW(YOeHNSHt*Qqk2J-wlmi(kCNU}{COa{eFiX^rHM_g)l0I$n-&jUd(4aga}V z(0%G}AL}RJJanp2Mqu4uLlLHmDk8?ZL78oLptDO2NL=&GEl2B9Nk7`q5$U(V(gx&0 znBYO$(x)l+c}L_ zatAB&nF2n@&Ta2wig&f$q}yt!%>!YsO_`jz8WnbUxxQV4If9GWksRRNZmc0%#r!q+zwT{olFpJONLVByzH1 z{ZXa0r7S5cXB)dU+09R$i%4F`Le_(T9DXr;r#}7GQ8=kKTjTXNfcsKuzKv#jhR(C^ z#vJIk(ps-pn8=<=%nD)&NX^kT>Q;;M*P4e_o=XGRPIo{m2?mVpBQ=;1a{R9@WMA_0 zwzg-1rJ3|!4%}XYk@2#lUR5I+VmbN3LZSE~@yR13y1PLE`dy&O*oOdh6~_(q8kM4E ztXEhndR4)|*>6)s>@8PyB=2E+yV63cy{VFDnx}u4$l9#fOL%sD7IX@QdhnRc*?nV4 z%Nw-YJ)~DV5?D#^ZvV<$<iDtvQIh2H+3euRVJOS0hugrkHf{5HbQ~_Hc)q@VWgKvPKRSpIakGV<*XEZY z9OPU3-vK+eo7klf`e>efcM9Wm)6b80(mN=FLlCTdNfr3hSS(rFtxcS7MpvgB;O*xqLMjnMS2|bCUfYRsp?zi+`{?R4>fhp}%f_Ys&o6y=LVh5Bi4)}%PimxnCQ%de zhsC8IilhE8$1nn>*|8ECX?b0kDbt@X78?Fv2B_z3H{!BQhP+Jt;6F`U6tE{!m$iO* z6IF!Qk<)@mfvO*Teo<|$!$CXp0MioqYG-k95as&}Y_qED5p9y98Y%5zPlXD-l4zVY zlK~Flpc2ancoHA^=^(h+>Q%O{UBI-QqES;m zD=%I|tx1>ju_+8`^c-4R{KB>^;Qbg9kEDGf$Y~;rxPB0&?k&c6dLbPNjlNHm!jrnW z;gboJNHpy(R=srlv-))ooy{$z7O6VEU{Vl4gdZzlD`mMjf$Q*uaqg4DNX({dY05Ps z3I_!xUTCJI0^d<#?W7%KK3NXO`4AJ}hhhYkzHV9TDKoYM_B|}oT&}bqqb+zdHq}y& zwu0)J%B;B5rhi&hc#AJ)&W-{0(pcsyAWmQCH~}g3k{FG<9ANhOJO#mW zP(lF*alQpagD%Vin0w;HK;-ZGg4xtSwJg2O)NZ5ry_{J8ic?mGNvydsY9{0VIOUEgyT*{I>jik#Dpa>0qq3FKW@TboMV1$fR%eZv(Ca=XlAn~~^R z7}olCyh;nB>yp)dZ+ORt*e_?+vlew+vqs`MY6$ievhDMV*l(E?V-v4JCKIAlpJWw4wUsOY?ukRYrIdtM|}E97+_SzqiO)_*3rUQ0mIG9C3H zlP%5gRqzAOWh|>hktz4Gr-1sqLgtkEc|x4xK}KulHyC3}%jEUC9O_@9iKvMJJYbDi z^5Zr_n}AwJ9O-PgQdpEDFkwCFF5oCV%S% zs{e|`tP?%lF!3T)ZKSA&W)F}O~!d=;dk(~Ib$;Gmp`6)-R zrIZn_G%St||3Law%on1!@*HRhPI@ASKqZnBE4IqdXWUJ{GDDQIZB&QUCYq_Sbk@J zJjg*_6cIzq{k#%^_f3fd6#BA>%xJsNmQ}cD_EY#lxc6bvjOnivwak`F8q;|bii)au z=ygj3*Pb*q5vfJo+^-WszDY)l(C>sd?L_T(-Qa#x>H?*s*Z$)japeFLT7@dJfBV-Z2V{-TZj+r50h; zgT*OuSiua1@1PIy^<%h+=llLn@wSyf+S}hPDWL9s|0^k$LlnJG?RN8%<=Y1468jSj zo90tw!S(3h|F=mxBwaIboBVOVFoGJ2Vu43D)?WI;X(U?JI*0qDqvB34-*+^}PO`jK z;@kYVdvng>PQ=$zwrC$Zt=)u>q_25aLPTieKzm)kN4n=F%YoG793?MpaLyowChGh> zT8ZC3rQ@zrj(uT+PjFU5Q*mAjnVHv9JaTs@nEeun*6y1IhcJSGFZeRD9xFCjj@%PG zqe<=dZxz2ms07CxpN{98iW4r~5Cy>D?#c1IC7MA{>1_%#J&1PaUtI^_mea8uc&_$g zh_lfz^Ll-{9T%@K})9_L@Sn=o~{%!K{GKPhv zk4>cQI2wW}eh+XZnMVA>j&XWGcUX>m!MBe425rzmFAs1Bxg4JHU(&?95Z^gI7?N|i zXv88k4xi6x)X)(yr!Lmykmq9vT!8^nGkz2pDz>p%kWDq~L-qoBme zm|ni2Z+ipifWU8eVYlX3jTfB*244uzSU|%=0~>L>eLD$Xsl2C#4z3#P&*gU^sGe0u~<3GpgmzOeAR?73(@Asd=K*4#88y z(YgW$%k1=@ayv7ynt{w~{x{#QO)jh{3WhsVo7=(U9~h4TU~i5~$3Qp?{yyBe05?F$ zzmI*Ep$!TPnPg`FRWYayLU`#4tXJCB?Iq6Ub$Q=;iAmiPMsYO03X@??B^IxsAdF!h z7tC{Imy@55ZL)eppjCc3*09pO71#lDN)$}1_x3)aj;TkbpuhS@lqk4wV-s4{{$fT( zUaHO;r$=unWukumWHjo0p%7ntjAva0BX?!5!?g^0yD!|sJs5j%^|5m@ws(!wq4B9F zQfM+&84@K>;s-i_vGjWUH#@6&1p#e^cwEJW{8O#0@72&NW(mtC&Ci^{X#YBFa$4Qw zQ*rN0Ovp%F5b}IB&VrSi%$NP<8G*Fqh&Xh+R3QgPJi&7*jnn{cG=W z5UzxtCNmCl|xVn$qAdA{^JL~0JQOGc|!SShXp ze?p3!8|^vo@{h&J+FWbssGdg;A!lV_uj0H?sDgBDD0^hO7o?T=i+RnLOwb6W&@;M` zq6%NXZA#+o({Fx$JyL>fPE{LMyhTGBNxrXU^SJabW0)wR2-ObPd=K0sg;7LkVr@|# zgXNTStLM$&zrepC&R$$eOSc$Rb+Ht^OKr{w$0F^^s$v+2N#%!i*xp4v?D5mZQb<=R zV~*OID+~|;ZgX;qBD#`zJ&&b$vj8M?c+KyTGqz&k?ZC-uY$hY)mY|Mvc-ep8*+%q# zjQyaf2awJOwmM6ch);8~$!ODIY(Mtx+r9rMxxG61eZ9%~pYWE;I!H*5{?GR&m}1tB z8!||>vzqcAvlqY)RE6mwMxUzS7H+*?!f~4)JgO2pijK!&g87qx%pt@y`zYyD%_bb3 zqIZ!FS+QwIXnfXioTJUZTxc` z5&oiLgw_-at8k6IlNTmey=3EsuDy5bd-ai~gwK5j*N~lk8i0WtOlq%LS$tKlWf*VQ zH}5O_IVjwq!j7kftnZ6*kGL812$mJ+A?>mh+klOISuYQv%1v`bv@%3Qdm>Lc4Y28TQnnN^h^r%GVvY?M|V$>~J5{9s35DmemrR z4n;{s4A%;ba!c{s?z3QK8QY8><)uut_)g2Y%b_dJkYG&$h)v-yrO*ha$HeEd^g|3p(QEwm4JBgWC^9whKe5DI2s@8e?n z27f)YwL~saTa~8rZM6KHgq|N7kZ1+r9g5Ub_azx)q=yj?CmMUasnrQ-hS5)SE&^X} z!wRT=9pUV=jT5@Y-5r6p1*Bn`-wQOQZtasRfge!#p|U65ETUpR2Zzyc&d))KSPwRC z-!{%{=wATK%=cF~gaok5ma%+Df35$1Ct4t{$}RrqM@>m+$U}nqm?jsjaDkiB0l{>S zlRNLy%t&sh^qfe!0h>7VAJ-5R(5EV7t_ETL(UgDT7wk366aIc}0v^KYV%bwPoI8HU zpw6W=N^`LL1)3`xG`bC7%j=~9=GLfK;N11$H9f{3Q7j=AUJ?( zjq0Rs|59j6AQ{PjEEOiRaX8Y^R=4?g5O#7Dp^=axYp15*Dop`F_PcO)!8NHj`G6K+ zVQn$Z!30!q3KlP)9%NVJ0c}^B5tk^GG5b6rf=}G-w6#&nhp>Z5QQ6j+ep|m?hF(_f z6sK42GNjwS#`R&eU6H@G$WU0&X8hxgR8Agep=&3|cV=8?52QM{wQ^Um#-yaK9iWHk zzexah$+F1D{G>^D7|D8ntCRP81!$!sO)@XC6FozI^eUr=EWKBuS|Ky$Cx+Z5JgFEd zyj0~;>gQ49<~Jc;_MQyfC?*1N#?ST(zTE7CfzN;hB}>H@Oc@6`O9j{|p|gu*_35X6 zo@{m%q_(V*bvlUHuaqViZsIyMW&=g#M9h!1^+_irPW8rJv_2gpiA)0Us0mub7|H1# z80R06x7-%wkBa1v$zJN2`YnjV;*LZ7jQrMDw`{24!{jx?kDgaMANnpx;vos|{G!c2 zX}!4$lR8%gsrpp8?Z)DhB1=O&551$beZgHY$PDXpSP$f=S>dVQ4IS%3r|vdD|FEj+ ze$&>4ppc;mtiOfuOHW{KU~**wyb_=f5W@Z2$mWRw_1_+Mg)_{wSb0l{ZjdRleSBoLYJdx0Wl`mAG@fr*vpW>U7U=+ z-%Z7~qCzIjY3Ht0ae{##dL*UHZ54CfVdKYabl5fMYF0tL5w_LNj7t*;Zm^gOg#KCV zL%`rpfHvA!!m0V~9B%$2t5WVB5k`*#6Pkdz)c!Dk6r^WFWq~GOL~z}!ip^psY9>E) zcPO_-*ZMiBp=Lbc+i*-{jF|prHBnFg;;L16!uX|D*<;zLT)hURpv~HUM3O&-++5>$ zv$e$OWjEVUExHelXQpYI4E&loZykT!2ia?@J_RN-&VH0H{JnD4UO6CthEauEHrK%r zpRl{`Wte0U#t0YTp1lZ6tl17*1c16yD1G9Vo3LJm#wvI=Sm*HoGcR0o#d>~8Eo}?} z#W)WtLRLj$-sd&2uS9>;-^p%;! z5!dpGk3Ev`v?}_%(uuP{_vVY{l+{O_o(6`24tDt`Qa)K5K`P84XG(Bf!~%A%(rF|~ zbrOQvrBAA4f06+fBMhr4nAL1pUq51Zo@u4fz$m-)Bxmnobu&4Y&3b9lJt+*thVL zP(Dgf$vF*$BN3l90NZ4O4i=)?EV#w;k)vGNW9|_`_}-lW<}DMmdQnTflM$}JTwI^} z)uvlmO$;1`GfYkQGEUmeQ2-!>$<#oyvR@`{>oqwrKLIjFRysc%YnwIOeV_s=9>Fj@ z#2YiSc+jgLnWh>7VuUjPGEUOkN+7YfZL0{zMJJHs5dNWw!W*eeLno=o^0&U>$25|8aIF^ba3 z&u)KeXp)+tVq7sRn0=O{7#}BX*It|u*SL_eqdgp=UTA0-V^LA2*UpfQL@<3<(%_?` zQ{_gv{6tUorJ-NT4y-ee`W=G70E&}7Gspw=tb0B)BrLpYq`P`t7C|a4a84@-S!BlwnBxZehCEZiz8~g% zc08j-1ULp^Y2dT|?L@aO?rd~xL*$b<1_xJ)I>lgd)Gz;-4z&iN;P5sY2&6EUyWC)g z;(8`%5k4UFY%>BC)Mm!g?FBX$VfWL-W0#iJ9CP3OSMhq0_;B~U4qR^5&IV@ylwunS z%mZ)!DSh$BVOr{@YBo88RnlZku}g0V&Iz>zjL-F zt`Y|W+#evsqw}i?|A(cw%Nwr)J$$c#poL%cTDGsr3Q#Zkh3T*#q!`DS)kvt}Pf5f1 z$yC&QE_jHvv+26#{hgnSTE(NDHqP|tdn{a6SihZ2I;yEg`c!!2NSDSo4QzS=Q+X6s z9Eb#wcxH<)55fqlI$j>=s@H{Uhwjrm61#LSUHPNLeYZ`+;G+4CU+geMVuC_;Ctv2+ znF%;L1ko*#=B+dohg*OFLjmX0M*k3$pXc&$XS&$Qc7DDaG3`;{;79KXok5iaIcr$- z@evP^7vT5?`n`=|dx`s5F!Njf71*%2_={ds9 z>ld?Epbc{%^kLMaKKvy`RNKRgE)K6{`Nv4xUmgA022Tl&N>g^X>F}f)w=sQFZ<;p` zH)Km;mZcMu@q}4`NRI3y63KE4J>0>o$tp_SgSXpF&5mc>_+ucQbMcL4OaLHSd%K%O z2T8u_(5e?|aju55bBN_&zK&VHVk~Mx4ta2;Xg2lF;WvS2si7Q!BpoCy(1_$vF35Vn znfP~j_klDMJh!nz)mPB+9pawsW1V0F=q8VEVa+X=Gq|UWk8a zaJh#h^)gG4_hy_Pd@j@{zwsO^nk+-!el0pM#+DB1Ze(JL>vVw%-o&T^_n}UT>}u*u z`X~agJ|l}zVbTFrZ*jy@`jgOL|C%||+88%(oE=NmA>(yPX1xs6fS{+A#T*mjTIlvL zzNWV?Rv)Q0pEsgk{wr6x=y{1YU&kilJp+;t1l*W=wHQj_AgwUA4?CofASDR(dqBik zh<%I0UgTP2X( zvs}xaLZ%8v&24>Dzqp}2GGCX_UZRO&5!A$8v(nTvZ<0CZ3Uj2xAWe8atX?xE<*#bq zB)rVBn8g>j`~wmeo$TxAp{Gj6^fy>Aac$S|pd@e^3pE{Os&vgn3HNd?J$@459bMM} zcRwGkWPLmJP}FdSM@V=^v2l?uf|gN7+xGf1O`DCqk1g#s51@IB#|hnShFQ=&;c!odn#9Mg6K57SE z)7>9L-q{#h8%UcTw|gKf@NmeyPlougp~{;U3rnMjk;t)eat~+=BW%Y{k_>I+3db*~ zJVyVvk`3s3Dkw##txi%_4#QfanLQ2rdPk?t8Bn_4ETK`fb_0pgR1#8 zLPZRy2sOICYd>z#&&s}8zlfrLueB0zc+d#wEB=S^X%mk7Ig7No5IQp46<5ucO5lR} z9&wPt%8~|&j5}L@osEL@!q42YLKF5l`ux#1j>EvAEOYV$o%))FVmPY;zKXM# zkEK1oq02wqQT30l>jv6^!Tn=ZN#R&ty7S!_jy%}e_=NU|5gQd;W@LJ|7=nxaiS64Y{O49aEhLf6S8lh&47-Qxe6-D1kP78TJBiMn| z2VVCNm}ZGkXAoJ}DJG!T8QO$+_Gr9P&K&T4L5|cLgwSV+8TuPL*+mCfHbM@lY4^na znW@%m0DQ~g9Rdmyw9}pDL^tG+D~74pgE!6laU!)xJ#Nei-HzLU++4ASZBSv8HwxAh z-!C4<{01V7WL=uLeG6cKpCBU~)9E2s>7OgH+6Ud3e^cvBcNUS#<_VcCkS5z5D28Et zeifFWe=T9wiRc{=C|r8-;K_XRrvUM3YjPM9YC&}3RPkvx6QR*r`>47fpFX{=ysKBM zh{~fZ0P5muP{E#FY$08`3X;V;MeIj+@`pk6k%e1#y9(lg>zz+p4XP*(-rhH2tz=Ox zp$yBeRwL0?_F9`T;43B;b=^AZ zT<#p5QH+$xXA3HM8&JIws9d1k(?;hOpjDDE7G-N9Mco80N-I73;L00EQ$DPhn!>V! zAf_q*Z|LF9!Nw75qRh;1Wa!1}E<0&#A+e+UQ5-iavC5R$Z)-mL#pnRn$&RrlRO0%i zq>cO&1GW@@HZ#+lZ>|0E(75w6V?j)BW=uJ2fq{#}t3+~qai010O zaRW9H@E=q~Ag8Y^?xWSk@YRG5oRMU6e+K!;5NbhMNn!$d?TY-U1m3?8xAr+Ps7my6 z08M}#iL3rY!sS^&!)`Srot|E?yw(eY0kb*!H0D9uEw!4XIC+wjIkjZrQ=RWJy+;d_ z`2|`z+Cg?>cPqB!MXs%bZ38!|=$%a&?5VmPgWb9XmC^>v+w*~R{4R-|FHEp34#gQb zf%zQ&Bh(41;$Q#@bHxhMiPR7eNu|Wcpwk%E6c=S5HG{9qb^km{lMUs=ANqjLGDpN( zb{?8TY$Fj#3Mc4{tcxE{2ck4Pc#&w0B|LFLduu>6c5d#8_!zIXEH^-=!Oyi5$)eom zZn3K_4R~Sj{F2|4+uw!^Ctfamu)#;b!YF`ZDoq`z?B*cZo~R%nM}Vw6a-jEK$zbLA zql3Z_2*qw!zBpNWbGt3I&*fR3?e??k2cdaAkF8QG`vfLm+?O0a0xbT=j8e5zU&=Nq zrude~`rdwamhW?2+tspI6;iRxZ%ehpknZK*Yn&y}S{i(U&Y!!GLm8m2*Z{c=u z_8#s&174xd9ca|*i?2;bZ5xwIs;K6T*6QMx{e8HBaaoFs(MMrTKy5x2Y!&vHV&)JP z_o*K5aX@4S+>BiXHFtp9_$X;{59e#N!ssWK*aRcU^s@v#CZJUk8<03<*<_DMs&cc7 zR~V#v2*FnyniS^8$j~MS&3*i0pzAhCdGNN7xkx~pA7?BY0tI0aPr{F8?S(Uo#d zqz^`>=F^bJ5Ell|k5~pFxF6ZG;^ARAKK4z?rCvD&{RSFnk)en zD2k8XJ(qT%%n(&5+r1|xZO^5HW}R&z%dI1%la(&eITHtzM2;9d?`N_&70ZUaU%9X! z`GCssA5WDnx1=bx=%OD4?JlV!|IK#X;mr8lLE=P0Qqa4*mUQ}4If@ZW&XG$#yYgR^ zNrVwf+ZsHu1SJ^DuNxiT0BOSkjzPxMB+#?0vp8x+rH}Uz+xQ@awQ#bNH5<4h;L*48 zJ?~8rU5A8d;Z8%-_He}PgJbQW7zJKEZL=0n^?W9sQS{LIi7(GaC zn$9%Q_558%_Q~v;6P4b_QVysr-JG%;LbV5WP|<;fTZ^>vwAt-N$C{09#RhS2Qa$po zDu!u&nunoX54ClIjcY?vJ{wC`c#h=0+SZxAk? znPCDz5IM#n!-$BDbkMpeP4u$CHf>TRIueY(p`lj&OK;<<0Z*VwUOdP|sB|zZF?ZF? zx&BjJ7nJwp+|Kc*;j)ElN4NdbiT;w^|3(kNFF6OhE*V@3k66_{>9)`IyU>;}V1`_$ z{<)F^e6oRpa21F?&P70`G}S{dDbXFG$_N~M3&IjQ#=NMWq7n6u&G)~=DMWu}Bi9|6d18Z_*W_!^*=unuT zhv~Nbd9P{inUZw#!+jgj7p@}22TvGz&h*G?mL+a*pAM;VjbVu zptnRuF9lAD!B5g4Hl`|YvHlDEEAKMfoIIht%eC{u?}4rz{4RvT3pMVMw2-yAMc=E&;~!{WuRCO763$O#F{*VY8HJg=j~&=P2=N4tFP z;!a1Qn#ertA`AE#6rjAVhI1Pa38j+}0H*2}CgBM{+(_^uLt zw{O_$0bGaESq&U1=xM36m1Ydfa^+mV*Q|M%+H#tKerwV%UiUgGf&IjR`5%ZY zRWSqt)>$%IKOHKt8d6YWhG$=U}!Y+XxvNw8bDX;k3A>9NwZ!b{ZNOEJozgP*6=lgSn*%vg zX7XBwj}QZeb(7+=>fY--k^xC9&sOYAM9&Xziqn``1elj>3Zx3D?S|rq#(z?Y(8sg~ z79YS4NWYWAdApDh_`9D{q`r91aow-6!reCAw;lYj!|9CW9Z>dlVQ@}^7;XmO(cf%- zC#^If;C)hZ5VoQ>13E+s4?ID7=nmJrQUkyY{OBbp9 zBY9Auze|GAH+I+hNhOX|6$c3sv4nFM8fUDx*8f`SLN5= z>h2KJimb-9g|51bgSxT(D#S+*d1^RxALm)6v+^|1bp;Ij?f?)z8|DC6 zQv@BoQ#^|9VuR}6@qPCh>hyzJx7F9T zJp7Tdu2%RNy(Vhg=U68%kxWxJf$d7hn#uMI--HasdeOdA9ju;iO@08eht|xT+<(L5 zqwq#uQ=uKl+3H^BfWY`I0nAqop${&QUSHkm0~DU8c>s1k5m3kf%e5|dC;dRV|i}%ZthC% z%mX?rj_Fafb~aO9uU6h=GDlwJw%=oXk1q*4 zd;qEOCc~tT4J?%cb8D-F683=k?wm4XTpwNp&HLU}3Jvua?vAi8ZicPIDWLAj<`l(xmL>OWog z6?55saX7SDa@lrn&5K$5oa-58fOLHGlQzwr-}oJ8XB{uP_sB)H64N*L16xe1jHquc zJ+1Cat>PTYF-#GdsUO|;6X~yEu;dF7vxe#Rtf6d{Rf6BwD7oC01%5Qc#s@L~ya)c~ z7q@}$VnwbsAX3c3L{v<>CoB4Zd7y$=ft9C&gaU)Ju!b1jhNoRyd1%I4d+T*RPOk9p z*qDADk&l$(r$zzoXtH_`{#TH}KNoE|b40q37+yq`hWmx=!$w4M9VIblpt3rRMd|Xv zy#V4u)dCHM;aqO3=>fA>3fY0xrOcbRg=Sgo3FcI5DPAK1GBC&|@HNv8n@T`PB=;0a zIUw=~mH(|;B=Dv9(Cc7quT#>m?G+&gN^^lr^fgjqkqmvdz!gW%U~Y82fNhAlpk;qB zx4uZ$5e4(&SXra}7B1tBJPU@Ub5^QTA0naPyvfzv{7ziq!XHwiI7N zdE=@)6bPnkF^u#4=rXR(ufCrH@f5|pC}?~X{-r5u&JfW2IH@79^{FVGc7;6<(;r~5 ztrOqLDBtpIPZ~D+_Be zqSH9qNU%ltXA12)6lfOKn4zEh(Us>Ui9eMF@U;&s<#ChomqlHBpQb$?#(;YTyG6{q z?(J>!C7-#yke21DtNICu_@PBbnNV->@if??+sJ=1!J9S|577%x zh5ty(gnjNGqnkE!(PWwxXQuF(OBlnCmtvbOMx3# z^5*v}?|cT^T@e@_Ky2{&<)J(fn9XMG70H6NCL%F(ofSl|q18kDKl`3x)8+=w5P7Hu znH$%Yo^P|No5t3bYIkaITZEIY!>LsQZ#Gadq~jA`8=S06vFYWY8ZOa^+GV@(UGpP(%c*zNc1&c_Q6&psqMp zD7p{Ei-ZQ?PWmMYHmG*(>G1MgvYHk7jHm8_xuxmpkXiW0qQxfN1?J+i6fu(joP~BX zl)I(B7m23cQ*Q_C_nF zLkWu;-RTh(Fi6}WxPjBaopo2tuzZe_dX+2ec&FR}c-qPv9K+3}iEe z_gqPK}8tMTx+;YDSxmC zug%^AC>c^{p1}v16f){_(U`$Dj=gq&N?IHH)bSUxy$mD2UiZzpJR9B8!SZiWB`%Qj zF_jJCDPV{uRU2%i;L(tnl_yx+Y}Npo@PR=owFw>7)%)bPwP`Yp6PuW6UG(Z`A{(dI z3b=pIcn56{N*G=Pxr@Zun|5(SnJuJ~W9dQeX12`;gpYu@85TFRezx&Ny?DOs@ZtL4 zf^^fF3r!5O1WNu>e}8B#N(b&isl-5d=Tjey>&5g5+~a5w2%5b;p_Xt@99t%|gf~4= zlVCJZQrYYplUkd&6~ZPJ+dC{M?f2Dk0^<1YMC*__MI#75=n$^XvXMBO+@eO2alYn5 z*k_9>{h&|$?2zLR1lKnwz};Ij5QUQtg1Pt-KHlAd_4GqNfx#8*JnC={xl`dF7^d19 zMcgT_YnP}+s9c%~Ylz4Q$o$0}%v-uPtS=B^IF6TQa*$9*gIB0D&c8Jg)=ei{Z^s~C zzZfP91jubyt`GPydh}$^J@X%^>~>Lp)S%$7V0)WI-V)moUa6km?ANc=|=L#(C{uN@+C; zMKl{5$LqfZwaY8pEPCEb>u3d8Q~FL@>il9mCD3)a_yCD>UQ#kJad#Kzs`1D841c)3 z8E~Xs{OnS}K&SbpvWo%)NK|$bZB{(;{GmH7QIT(9KpSIRi<8VQ1%hRx1SHev-WuZ1 zc5d(%mg9qY$DA8Krq5>$B~m2le-38&tJ`kcxT64Jda2|?6Ld-0>&QDTPGdfM71f@F zc+^iW#O4nCxgPI&zeOk|Tt*`ZJm^=I^#Z>5IRDXAu=Hw{RT zjAto%+x>LyTFK1J>WHS=y*(FeRP+kP0`LEnvQ0A5V6r|EhhZ@Kq!U{mrs!0)^v9Q@ z2!>Of1{j9$bT`9y%=A3bVUW#I+xui;amAAO3!|Q#A

ylNCyuY~M#6!2O4!)bC)+ zCoqT$Hp8F3Hqt4ZU8|YCpmJ{Ko%j9@y-#af zmDBK*tdo|cU6|U9X`(RLS3<{Wvql|Lk5A=zzERUf7i?w_*o(zv4B29Ae#WVtm6WT< zZrom>I_J(ya%!x}%frg04G#=5Fcm@-w>aUabBh8@_!>x(fqKx>1g&fI>fn=LORJy# zN8NLy31ZbQ`9Ol`K3>}Gi;&g8@#7DCQhOz4U3udd>!h)f_Xie z!==GvQf1aKh|5MP);ZZ9)9&S|c-~o>-P*F}^kq!HZ8MNh{CYYJKlzp<`axG)87eae zvf4?`nso{y*&@$m=M(_kAkP33fb@VV6rGW9YgLb|%+hiPJN_Sk>dn=L_9;s|`2_su zJjEWU<2$lyJ!A3Ds(TJ!2qh{7iUX-9{?8~5i*SmO?^uW4W!^n@uuEcz=3_9i1i*V+ zf1~+a-KM)r5q3gxc{2#?xjA|rS!>?wUCW2hmD24#Jo@T{pExqrU7(PY_~1FZ&Mo)E z3R96|$ciH;t<)^MMppvez2Ug)?^RuUOYNApc2G*+nR@NvGxlmOob=v0x_VH;JSqQ$ zKeft&ms!#?kUatp9UXQ{vpiK4hAy%~fR*x;cYaJ}{GD~LloGoBZuG#SMV4;IcELIR zp4u0W^1a`SXtuNVV_}@+Cd7M3(;nF&j*2C2-G?ZJ4u(IqKPr{hT~ARULLuC?(5txU zS6mmLEyEoJqS|pX0h1_We{CY*?3d8V_-U^JsWc!sj`7WoI~`qRqv<^Ql4YJQNsr%C zW6X2q5--j=Vt;iKgo2_+<5yAry-c%sPS5sgm!CC^O;j{L>hbf(AH%BTt$Ke7b_jtx zwWLSDNDTE@Ol#)q=*Wzis0r$10<72UA{blQ<0=7|TbVJFk120kP3@^N0*k1Wh&>0L z^iuX7lkv#t5us!ebsaL1j2Rs3-k_&LIHU~BqxX{wWwYsJY3L)zN`^`22zi!{ffgcc zLK9n6k%=QOn~x~p$v2p;@YV+@?wPlr#&_E$DGiz3g#Pw=;UT$?G{tJa83K{B2budo zBNaTzfNe~zO2{>dFLj@l66T8{Pd+tP_h3LkTUkI*i{(DtOo*Z|$>ueTmazC^@?4)4xFr(pez_ewy{larr)l5| zbWHnYPhWZM+BU6v*-*k_%=5tkw0o?T|B+^}avt@;47hXJ*A+yMmio59AWbdefSt#> zK0JlBR)5h|9sSPGTK5Y25SDZn2+~O6MXgkynaG;@>OZ&ciACVLP*;8tZs4AEAZ2FS z)GRk-(0Q*WC+TQFXpe|d48;<70G3|IzSgzd`Mr~ch$gC`oJiI)&hAD}*yg4Y2f+K$ zVr~ltU;4fEYm$upR#dE7o*Np_)<)Ij+=uFf=x6p?wd)3_migZxCOFk(&HYc3xFJhk z>BZfOEY#884GuWD&3ARrAcjOpMstaxSfYnLu`LoH7D37&fy?SLnQd6>ks7!QMp3sY zM?_T_x7Jl}>oS|ezMT=`E~@p4UZ`_edjDk?LQ0RV%P3N(QM~%o_|tOSWBm(hPUYn? zBIZDDEwQv3hM9n++G>`%-|ON_ipOGy<}G=a!|-0#SrKqxST44v)@z*pcR0g|QXTe< zFs3`Az`E0Op(i_=^O_jsUr$3bGXaD-(L0N0Zi`dWQGCXoK&_@k|IgAHz9Uwk-yv8#;Aq|za8=|(jG>14OyHPK={dJ_R2D>TBRGBINiwJ+x zm-MP)uB-Qn_vceemV@0MGCFvSsyp6^;*L#h)YH)I(BhAU=Bn8CQK(39s^dH{jgOmFD(U$9PKUCSq5eJ))bq- zfd~Rxtc`+2wjwImQy{>7k%kQAYx)?xVUTl=AsN^5k8GH;_MJrnaGQ-?y{x55ODSrc zxj#tPb5e9EN~LFu9N--ez-?O%7zOs~`ge3rJ`ZKdfjjExK2w$)lSTJ~lI0 zSpP^>XlV3UNC{?;&4n34#VhJfL9Yv83&+(&`ts+$QA9?5Q-spAoBaBkfws~|a1`S| zsGzbd+Y+Jd}>ogj4p&a>8)0Bd?`*tuD)O>fOZ zqVbMgC0?6z0ufM<(I`N|tZczhFuuU_5JGA0AyC@w5ZI}vw$l5=cKb959-OZjhq-Xi zEOX*3J=rW2PZmq{nJt>)a@94BykWh3>4f6P4%M~V znqeNCd}To+P&+gC7SHI=E>emebBrTsB6Ovw0rG=-3lCC!-wB)k^<-L3{1iseS zVi?~x&gqH~hz>2qICeAu?ecvsZu#V(T=`J)j_Hst4;(u@)V#`N1;e17WabQyGBaYY z2JVi7<^m9{3*-9s18CNX7kwwLy(d5kayRe?`x}J0Tm4@zwXcz6$Zv)n6~)m-HIpd3 z)Vn@XKhGBTxgTqFLb9cDn$@rOar9B>>%uF6{1hEQVb&kj4vyZ6>esr&DP(W%0++X`)n9aDOxsQU$7$JriDch3Mi&19oD-n13!3|3xr)T-g)t0Ma}>U-HGx4gM_W3IyX^x-6T$ELUbsQljvRu`XYdUVQ4;G$D- z5dn+UEN5#~+9XsP$+MCXm7{I#^G2tjS=j&_@^*-q zI5JAiMaK``SX}oZ*3o7rN@s0yV8IEmfCAhrVEJ&QP#e4NT?;#4kL-t3971i^+b%b} z47xP)Uv9eep%fV8P0;rcIO7(aHX394_oX6ry~JApxA+HHNzu*xxvFcDKIAs795?v& zT}|QTP~HJkRyI7bRKsTF+=hzoYOxF;^@d^h*1vg`Zo|1TsEJZ%e2i^dXL^9g?#7L{W8*7yqDL zh+%BgRI^`tstNe9-H$-DP_>2+0R(B?Z&J;K2B9F*@%E-UE~zj!!^oEdST6r`yHgHT zdRWt}wbZ_eFmORW=EF&R+q=)vL~EK~RwP5=x%ec3WC3ozy$ksutRb_w!A>{z6Y4lf z1}L~_kDJKj*pivm*QI=M3y06-A*K?>gMDZxnKgs~^h(P6k?^ufXt(6q)?8YmcG{m~ zdQunqS5_(HB?m%=zqzrcgApjcZT!?*Hp(pgx&H_G6h zSuw&x(HrT2{82`;6WZ(V0Txv=6h*h|qNFsFgjQ#OSidQlVELymgpM*1d^=20m1UfS z_OW3;GCpFYNQ540j`QWGV!pQ(9{1eY%Ls$yqpCeKc7Iu`Btxy!BtSZTpd3#WmAv!v zYWlK;DTN+R8hPHe0%dpczUkB@s2FIMK-t*Fkf9O$-l;0KbhC&WH7A_IB_v)v1k-Q% z9`4_NnF^JAPFRXDYv(s8p#z%gko+(V40Is`y=EXWIq3E@aE}@Z!5*X;ti-qW7%H-z z6(flw$Q)E3Jj0>PIkzD$L@d zbJen&v*3s2MkDuWC9_8gO=4E(RiVeDVq5aqxt{g6qtE=H(AzY0&Lb~;G@CGFL2obbkTZxNE-WyB0&8*`4 zklfSO3S1`XN9iNN`Rh<+JuZs>KZ9b|22<+pW*NGYJ_hpce{8JE!jXGzrYvYSp3YPi z_rja_?$2R17+BEAzJp+yKfLIiv%}xiam1l|Lff( zfgub}Tc|t&v`&f>p_mv6ss#WK>!HwDQ9f)Y9pePLY~b1txSi51taXxRQbCGcbQbf( zcD*N?R`D=nu7%13*o_sGTB%`92d8NlmZ_^D7DF>uxZlRf8$4UBWQ6csJHbxJuBo(W zfUCyFH#Ux`G?rcVN3#&58GrN=Xub>$;ua-KZU8cHPZ0~w0M3pPef*Rfr!m|CFf*AC zHq*Lx-H02s+CdRnvgYy!$bSzyWs@F(+V@Iw7p%!+ee@*VlBA{pdhx?u0$@O%UsBmm z{ce@LP~m-)xZOiElc|2S&O@Q1U%`jHf_EdsrZdl}Y3txb=g%jUnaN(cw3@etG$Zss!p27;vMY-mcQ8SJ@1Uv6+uTb28&9JMR~pnQ zZ`crpK9xBw3qh&w2+{*qepf8V^r9lJVj-?Aw3b?{#D{k*RCZfc(lm_W)qg=aUQ!1% z9t6!yjJcnnMBb;!G1iFHrbI?4l-)Z_318j{Py3!R48x0=;z{;m^0d6=-2k}vc6kAO ziPJN^)%781|Bq;U%};BV&S+h*VH(Rj47?AOmr?W6S|&{~!mXV6IdqadC;sUEx;w)W zM@j>(;@y;HcD6<`vGUYz4bvV3!>i4nKMnGo$+mssvHS{aa%0L97VerY^>1F;GGnkM zeAZ67#ONEZKHnAMd0kB}HSaMq@Z1W%iJF!q4dqcmffLuZi-sz+JD%Z3=}Okk7Y7y= z_oBf)LnP#Mp<(7Q#x~(-H`_f|C_+N$FH(3{+hrS=t;4ksJt#DG^w;nJ`^LO2rj zK`KD53M+`i(6^wmm)x>}y~B&ZysP9sMT!R1%!8W#y2Ov<5=ru$oe`VtJyw&FG{kk{ zUx_V-6G1Av^#azN%qO9nc(eYRpdWQT$iypkNT3OG=_PpsN)R;c<4)MVrzGwUM<9g9 z?4AD&nMn{_Q=zuYVhMf&%-he?A5`W7dj_yYiO5dkYo1Pt_Mv#&N=%1NV!8h)xiDy& z8w~`n(m71Q!H^h!>1g;3)0sx?w#`#!FGXJup}a_CPt&5| z?@As^jGU746j56#aNEB92l(KABq>LG8EEqZQks=`ZGGvpKqe`ZSAU`Ii{W*CzXzi{ zrnd#Q+MBIU$%T`f-V5Y9eY@!wvfvVzwgehzH~ZSxq(%Qdf$$NBT%W1QIruqW8s#2F zM}y4&yi2b;6~%-3F|L#RUwvcT!ux-YSB;XhMML&Y8S~dFas9t@)91oSLVv)AP?)I) zSi~IyuyP%l*V^YHu1DFKn=GBS?R~j00uIFdKCq+}>51J1-DZWh;quN-9ooRE9w{mp zNrRa~3MpEos?^yQ4WfV|b!4-8&tA-<%Y0r+nP^tBKNNZV>nR$|HU}YT8I1JbOT zJ=+U($r~is07F2$zgCu`DljSUqV#?YD7no9r#wds(6Sstasy>+QhxdbJQ<>Bxm^BK z@4|}Nibxeh;LDx7dW53n4zBJ@8<8}k$N@@szWUH1C0Px8f1Cq58Y{3UW_>dnOsUP! zcbB|SfcfV;-~-D!pUlUKd>r0ENs>$acPwcZ>6Ajg6lC&ZLF3@d?mOKfZiN#%{!sL< z^Mi?Lod9S$2B{H`mjooTwuMW6n`+vMuSD|eQR%T(ln_$3JTY;xaF%VNMrLO0mfU^% z`141a7;>_n8UHvm{0U5##`2qaLyW5?QO^^TZrl+3!a4Ll&H%f>4C39}8QnCvIk}7= zyenEYN%qU^E68Kz7De&^Rj(Aif`MOVkY@M*Q5pH)hZPGBvKejp)h_59VS=Eo7RvSn zmb^j#ye&}fynSTCyYrNF(?CvbW%mL2TRr5v0+BBkA=3rcwL#J)Skwo@A2Zec6bM?u z|H4k;XVGDLij6_2I}J*30a&|Q3Yfm*`&!y**PUkb@42^>X;DB)yT9@7dXss1I$;8F zeOk58igm9=bah4hrNI|pA&iU~L=SdX^f-Hk{>&$x3Gzbk2O3^xe0-;(6rqLzB#;9x z3Yr#h@}AQ_mqT>N*nnRsnX?j^B#FWV_)Yiq6g&D$nC+sq*#!wZ?8orZ4CyvAzQno7 z8mb9{h zp(jJZrrAkn3#0Ol#BwbcHFiwm+zm`MmqD(-3jpipQ}R{OObw9_tq;@iW;#$m>W`Mp zD@(up2QU|0l^98BmdiD5J4f%RHMyGjndCO1c`{+~k*$RV)}!e(Mdq>=zj8Pxr!YJI zVx-iWszq&V|FDH#TUH3d)qFO=$>vt9+ZhlQP5AlmNGf+jlQe#^mdf*)QuYs6Sg-de zfb6UQ(&n!)i*js)&FqQw_K)-(Ia}*70RLSO*O&U?MBlRHL1W5>>Up${p|}km(29YR zhV$oIQT*DC56aa~<^GqS1>_(|2FbTF?Tk07pXxwT*9M`~jxymt6nV|)ZG&%ft#C}1 zZ8)(Xfds$rNs33Q4`mmwre$?OOC_#Nw8hlN=d4KjL~!j}FU&=ODusX9yjR?I?s|}d zcL2k~+pqt7_g$A^S#`qMpEw6+S`f1g%-bNbT1AT*4hj>dwz(xgOYluD1aq$!Ifj)= zDqmur2A6|mc36|B5_NFfS=AcJkOKVqJw|Ig0KzVzvOiX^`IOX1k7%hOFb>d4P69np z61=a0s5mdq*DSsQO=^{B3lcQsC8G^kh0<%`{kEsZA~2q}HKsmc#lqMQy4+PdG8djD zd)+Eb{9XdPXGmNQr+b zXKxclzZf9Cp7n@OW;8Y_(c`yzCcQ3yvt z5Wvp73E9{y+L%ot=9=%1(x#f@BiDU_4KhqIK6=g+e@_uIWPmre)C>7qOC4yt@K4LOuEw^#hz4#$AeeWDq3>;*p|26-;WYATK=w&Tv#>HHAz zz3+*lZokEj9;33lt72C( z4zVLRoC`JUTx82X$Q8Iyhbic-(~|c1Y30N;4@Q9*+AaG+g$zIT6EP|Lc-~fMHH}36 zgC$5vv2i7h%T5bV!4GwCNEJkwzu)aAUAj&u06f{yA}4kaeL`pp&ng~S;GBRKkFC-C zxti-%Umi%|EK#wB9+N`CLf>Za@`r_wH(rL^BPd3u4w|7y? zS_`jes-Pd=0xYBhYb(yT ze(~&i(DXHuVtbzFyvaZ!jQ@<}$lDJ1nB0(9Mu(7hKF$b?J1Ro2{?^19Lkq?2qa(fM z5t4)_-j?oArZyJea&LU-Rma~J*5KJ7_me5Vbdr=>%Q1){z8YtBGIU#N(slLjqH z$C9{dEENir5KEd^p9q_;tB#$8ZJZa!g*`V}T-O?^U8g~gvy^@sWvhvSog;?Pwf=Wd zQ`O&*J!CkQN9iXNSDl+P5}gm!>KQ7Z>FAAtD!>@xLHr9bpUVp`$`*#xVr-y;_zKL9iWJ*C0D~Kh>2=zPP z**BdGf`(fd1pCg+;?Xy@ds#vP1(l%$n~#|XI+k(~M1Y;DF=zQu*J~g65tufZf=F`C zxFQnSE&TN+#w;+pi5W$qFS;$b3b89^UbBLH5xodTf zm2;pgh|n{NjTo3t`gn`jkYJg;af`eN1{`o|3!vwBsQW>zf}M@H3~c?j{`dAwPjFhQ zz_$J(wa%9Im`2wbBRhQ^o%~b6%aGckO)FZQ}TtDk>POAn%t>&u}gDuNz z+tFso{BS`5UMv7VlIBBQokVa9=*brUV~XZIw7LesG_|s{{uW~>WFQA$$Idbo$+7l{ zs#abKftSloF=vqAAS4qR8Grf-+gkldkDXQ?eO~^@J2lPRO-@m^zAcnX>z@|R3%{YQ zX|mMFGvnf!klZk|r85QDkqUKwq3xy-mcn)G87=YStVID@T|zd=JLWF*yrgrjO>Lhv z;6uo4%3qjPox9{?tTLbF76nMZU#U79ENzkW;F~|w z3v{eWb2U>eMPBi!x(n2(J))OUB94Ri5N|(qUv;1xV%fGw1a>+vgJ@3FT6yGoQEDaT z%g(y(PE-=9QeOafV@&BtHri1YIC0rWu7iP`5$$H0;k*!QzAE&-anH8U^>5K{*azGw z;j_pZyQXL={8WPffoc{|htHNXi?0iNSss9a0nXeQMmG|_u-*W=OglT-n3;&qRq5D_ zrU$pZjer`?XaKh~x8}*cy;m2t*KbjumiSb%RHo9Q2}!bUawM@kNlid#%(lU0ad^m5 zew+4|`5E*Z=>AGD=tV))Wmz6&=a7Cz5!eV=Sl(kx98Hns!K0M`@UGEo&yt|nbI0a( z&8{C{>bgq`WE}asI_*5sU6?1FckRd;88l#;C&m((!omoUM-)4fzq+vXQdZc%R>T1} z3H}&#O8e0@Nzo}td(n0JuRBB3?9()^&(qqj{Ar?5-w2g*?0?^EKbx87udpf-nFRK` zl*pV1csrq1ydOr|Q5 z1}WemV-(E+Av8g%+%|9h({UM~mN41Oq#PYmoD~VR@V_?rWnjz;Udai&-hdCobuRkEmL@*-DvUXg z`H65Myw#Lfk6gsrk0;R}6>7r7|D$Z0{e?(MI*foDjnvP8_wf2KpIQ=}MnUfs;u&(<1+lSFN9mk0nFESl z&4W56etuDyoT$ml4rTH{{1Xdyo*nKG=Kh~bc{Bu*l?Rv5CSV7GZy^kXWnfU0YD2)f zE4!A(!sv|;(*9@xNj`6X4Qog?R`<--fS>ZWO!I?wmtMxKP{RZU!A!omPitS<<0*HJ$eqfu}^>zGT1c~y=k*o)s3z!YL1U-9 zoluvQ4`o?5vwY9J{S>UU(t2P!$g@Y#xj>Z{N)eNzGVE)c)SvwA6CW>)OXfa-ppn1+T zBl`M1tVM_`*M?7olg9JBe|EG7$%BN1c8O^Ph2KG0A^i8HtSGkOyTi}#EInqmW3c{q zud*?fQg&X5)Uw?3UDHA~*C8a!o&yxFfub9Zgvm5GLPA0=huIPNmvGgY_Xj<=p(PGb zyR+ou^jxCv-La}ntGO2cg(fEa6CQ}^ zOxp*I(vBBCylP@Gdj8Bzr;pGwgt-xmRLhLlkgkI)+=PLBxl@MeF8`Rd;M;Ewv$+0E zGX4@*RqL5|j!cNU)HBp?pwd&vBftDFCzLGc>_H~__Fb$T>;PzRK-Q>^ND9uMrT&TT z6Vxd|5u9oCvn7EBmC*eEmbwPV*j=FRZ9^dsSo9#SSJR0=UyR3V)brhjq zghxXAGhWFf-OA&X&zUQ#v<6DR%9Ae4H*~O?QwyB1NN;s5`4So?N0MBalh)ol$>^_+ zO7S5vcwWKy`n7Ji$MMd4lT^OcQFNV2IVHg( zT@yCMwa~k{|7n|}hd^_+5z*Z|3^ob1-sI_TDepBeL)q z9N^s?J>Qb2HJQz}sD<{w0$bPko%3V^@;1Y#1p&T#rG_pVc!#2w+1O{el0kMfmGpyei&iG%L4n>Q~sWdoWEQ(8VqAQDS1!uZUYq~cH^JkSZ zSn*X6JsYx&YS(pY=JQ7q8D8Ibqn2m{rb`NtJ5J)CgoQ>Rj2q@;GDf^m^djGzZR z))5W7e5hN&YO*)?UZFC5B`T3~Lr4o7_W2trk*KkeMH4wH>fa7Ks=_)>#s=cYvlybx z19tcxOLqKNrFl=io}am_a{%tdjX{8_;zt5D+>x9uJEzVTHXlMUh!)#D{q9I6CT(|t zHA+0s@Z4GTA&Iq=RGE)%WEL_uhe3h+NhCt=rOw4*lkRe!69mzu<$e?QawW_v!irQFJ+<3~40Q3b`WxB2aCwPia)=n#*nLsBC?@e>)VfYlZS1@J!W0DEB*>you{85Z{^Ah)U02D)7 z@sEyO225}aIuzyfb|SsCGf!f8AhCrTBCKXvKO5Gs{)f>}{o2YNLUx}hJv4sj&3vs# z7sO}F4x&UMZpZs7n;IQuQV+_sTL=Crw=e7`xr+P%y&EF4_bv`4#gfN$c%7oCH0PO!}w3&+Jn3Iur9~QF+ z)h0Tqcyo?UaJ@Pc1hYVh|BzJAliBNfi%%LVJ9n#6+}Pk@Tne$}T>Ow;oI=s$QDx#s zY4_|)Y)QJ_2L%r4_w~i^ZZ3WAz>KD--04fk0lJ?W@=_axq>3yyI!)hMBe)F5bM=CF zAvaCX6z8$ful-e~YVzBbh!TjE8WbJzLChTt4PY=JfNN|!i+u%5UBJdqaG*9y6~L9L z9VF~a?Rc~Ya^F4F^Tc+1L1P1TJhu9qubT@46NwaS3-BBk|4p`HYXtXvW9nt#AL`1Gn;h~ z$;2E}Y_LeM+8L-2FAdy(n2;CRV zSm4!8XN$m}>&Pmt-+cj-WcxstSnp(7mX$nk#Y?=`Q9-E@U%m*~>kleSH&SX25(XaBdcHg#)tO;5bUG_$mBzr;F2o_4tsq(i zpofb2A6;6RQ5lL4k$PSNV`bdtsJ}Y zzah<85@duJ$S0W{26rKuLwYPPl}UKXE+Lu)^VU7Q#LB8EZL+*K^I!FbH7#*nhL_4E zK0&GPVIzh3=XUmQ{^0g;cXiO`9|S>tm}pp*f#fX#$(}j`l7fjeC9|B$zY@KxA1zM; z!k*wC?O>iT=O`I_y~RO@EWVdj;FN1Df9xar^y*NEo+Q0DHOub9*#)UxL10U1qO|Rm zV4VsG0t>$NKu>U)$@0xruOIMW50Xo4U%iSyr@yN=doDWK545wu>Uj_9P|rM2&SO6K zi7_>6ODtHSUO?BY&ml8zH?V+lBt>pO@J1*N-KHxVUo&3ur=X@-Ae`6dl4%W;Azn!$L({cLs+ z0jpa#h~THQ+($u^;ZOqv2^a@@pC(lA%kHihg4SG``}mA2V_ch07)dlmnGuy|deWUkSQhU{L*>bd+Yj-rO>JQm zsOE2eAxjNF@ag2f+=x)H^ePb3rjr%0h zw|~bQN2NTBpr*;tn6udSxLWWmmF^p(n$l$fTpXaWX2aIJaO#Ni(M}b}%766%B~<0A zVP0SzfhiaG-O>N4TsG!+iYF|3;`1uYMC7_Z+qZ{=1%oL=Ib%W~(Qy+u_Gc**viA3@>YnLc)O_%j)$5aRXv$hg zTw*JibjHB5!^2ikZy*kPeZCzRK2D^HF?x#uCe9}0w$`H!Y^Xo{*Ckwe4d zAXGwS>A42n6Z=&Jkq*OUyKfmV+{yobwHm-EJ%ZRm`V5R&~RZ zG}d@C(23HPwvpynx&|2O_VQ)qEqS2mmsA@|C!LYI>hG1xfx1m2wl_PgsbRbx4*%c1 z)|Iy2E%`qC{5PpU6@E}tgz(&^^AW59Z@m2734e2TbpD8EuM+RA!rmE7h# z;z($gY7ihWzCgoBZ~7sc^c6dOLHEMjec)F3DKRY=7}OsKzIB|~>*7zJXu9MhJF!xJcR$&$2>AXzm{=TuS-&9tmc#>J zU958}r{!~kOP^K(+zsP}HgAP}0rok9V1{5hl9d!N$jL#+&z+nckew}a1~B}Hv;UM6 zQ|vcRFW2q>b$ioFiVRQ}uany_*@AlRVgS}m=#Tz9MDyF{TOHI}xf6i&M3~Y=9)sEz zUmG9OQTW#vCVLl3Vg-d=bY!VCj6N7iQ~ntlDWYg0hK+G;ih$i3HY)Iz!ej z$INn1W?(U5@{i6rAg@gpvrWuf7GFi#F3b#8>o+Z>=ataJ+t zx{YXY)PN)u9)W1?`(Vwb1nJ0>H6e-3)5ro7I>P3VQGmM|4w^?~O!3xkAfJ5eoRt3# z9NSy?(sJ{%9fka^1owN>`SXs^c-Ow8*z>1tT#A0F?4_fBQd`E}xK`U!2edyNrUsD# zuYDfKt8lqb0Sz&CJG3~dam`)pT@56)2Hk8p;~~bZ3PE|loIGN~Ri6NXL!wI@@Ih;% zqx2H=?gO+>L)RA9v@6WH@*!qs0KC%OVfGOP)nm(kd&=yPum!dI5`PN9Knmv_bCjaY zp7MSd2+u$C&*+lXRmj90^8{7RP+f8zf1ibCx@*9+RI=ag9Q_Jz_+LX}2JG%Njf%9xh_7!8AJEDsZSGP2H17yKq`}>1}a8up=cqr;3DxxaN^4=(4g@ z9yB;NcygTpqGmLyfa)Is6Z2@%GeYpEsb`b#JIHQl0~{hnQ_uXDgC0n)dvk=HPP)l! zF{=65xgWO38IEgmqBlCYVL|oP7_7lO0TYWA3T>gTCcokci+j8MS*LU8P(+|$I&Y4^ zhd&Nofn?VKsS=bgMjAQh2PlAy1BhI#yx^A~r3ZZEUWnF>a<^6@gJVK;bAC0iN9rpK zhf^m!s>2G7>u{`}q=SoL>#gaPFO*|4EaBl4%u{Wn!!)M=Ji?owe1UTTEjomJS=uo) z)5vk=3Xu!}q}g!i-N%NI;L|-j6h|Vr0uKs)SKM_rri<`au;M3(C)S@YFe(&x@%xtB zibkGlMwBf5Y_+)Y72J9&2|Z5F%*;Sv3zBH!Ex<-CCf(-9w*mt*q^f*=tYjI95B$cw zJHXVUW=XYp($f@~d_X7A&7){h7CVp`-Ti0j)g>+Fyx!Rh4x`%TL(5RvvyoA`dG zF8Q%um!MX?Tp|Ui=%(7E^CIQnLZgk5oeD4rAtI=x`qI1E;7>wJU5hkPEjAf8-apQEEWS_AmZ+87D?s*D=hdMjluM?t43Q@!Btqn@~HVLCH$;0;s z6Ay1ZS$!LB?DmkeN2?k3q0=wM@y`ACnLQVjz8TDG8S&;f6Z)j~5V7qxj$NjXKx`jZ zbnJeri9*1P8$M(UKjWiRUUzFKQoCdx(sdHQV`7 z)3W~cT@ZIj9@rmzT2o@h9yyO8so>kfSV}DZRPqygK|FlXgGG}H0x8hE3$^n1+1H8l zJhAJDo9Qw*nB_$^Ij?Qcf2>EB>_{qltFA+RrCU^2Z)EM`3C8k)j}FhVm&>@zvwr3ucGdWk1Ono#>#YX*)Njj<0u{xF`YT9T!eo~2MGbI0pSKJ41cJ`= zF_syV<+xR_kn1|B>9g@Xx|31m*f>1KwIHxSCWt{*mX0%k{a`tfiG`Upk}swgHny}k zq$h8nvf?NsA?o~2X`uhR$BOAgW*WE}Q=IYq&*RJaG>5<009bwhQ00wwK6+f8#8`}9 z!lgZ|$!`%lQWf8LaB8kr@z?K40}-LM4M6f;KpG*C71Y?r^1AX=!cMCuO3?@{cOI&J zvtUeCKkAn)^HRJtN6u>02Ic-~v9*=twI#UmW)xd-tMc|o50H*OoBIM;Xpj5MxsK6w z5KYojE=|BdbC|)4sT6g2m!6zEd7D&`61bAihgSE$tMUr``XDg1=KVH~vJ0)#6%u^W zgl~UZJ##?W#FfI#e3YU3sh}`sybi?c;A!T-zhNYy?@foSsWtv##p80wGDWTf;x7Xq zbS&<@5gGv?8F>?B$ao0z$P?=^+=;G@X*TNW@1YwD-aSa^9axr3) z@B0fQkVng`^Zl<|G1g|z&>IVrB^7M1h?k7>w1XO{1Rn#gA9>S!Ip z3VH&MBC}$u+COH(og}S%H)be+(yO>`4~}^ieLlcTivWMjuN& zGSxZMktn;|#{@6HNw!7Na{5mZ9het{9o+Q-|2{XEiW|3hloJt1F`I-Ma~VEAe3xE0 zPAv213RP4tj3lB`oLApnCC#y6IdB84S>XY(^^|j!+tIk9!xqkzsCF&!&g8-U$QxHw zO{E!V;7zpEuf96Tk!SEhz$=4Wsb`c+?FA|0zd(X0(6CU`=jVEMM9fq_%qS&DHG`#e zvv4i#m01%A#a#&ak(6#f2ElC~HpE-Xje`RsYbP<$zOJsTcz4SouBCWZ-n1arkoT;5 z)$B(V26bd%op&rhHoHc|F7ICK%G57&H|0XCX2*=(RCu*WoPd4~cnRC60lTCD01Gpa(sjdR zT)t&5fCk(<e#DDF%xTD4nKgj1{ zzwb1M`|A1Ab)@+yA>cbv0~A%=Y!I<%#$+#ZsoayYXHZKdqXe`yO_{1-VM5-9xfitt zBQ+<-z-w}?0zfWs)gM+J;tD6B1yk$A?dOGd%o?6Wb@baw#C%L@S97)*bKWv(z&j3Q zLAnLbBeYJBXgaQ?vM=cRq+#mBT;32wD$zwKH&W9y+4WEEFl3BZbqR3Ta&AQEm(M%N zWm$aG8&`9{66F%$AgwX9JVX69(~E59rF{%Lur`Ccf73?}mPuSD%VE4-HI|JQ#TLQc zNU$;wFQETk{6ojKTg$a~rMvEnwWP?%LyXyRV#3ZPe(7Ss4$f99F;w$rV6}M%*0ydm+@d*~9k!L5$06@5 z7u!#PE!Z#wr_2@!hnx-D$>N@_s#0BVv+iMV)wI_xI@?QNM`Y4ZZfQs&XTmwjp20gv z3P3|{iV+EjssDnq-90TFv;Fu8S*3m@6^$Ho-s}Mr{_I@lx$lUhO62u<+9M&Cr~G1# ztr&fWzd8`4_hPY5R%gL7ztYOZ321H7&RhBtG-W_^tgHKE@%%sR&j+Yf_TesSm_A_~ zv1fdzZ8b2d{5JQgRw8AQ^Lq-wq$Km1s}6)PGUrfSQR@6eSWF?(kX(TZ0=ODy`^dH< zyBj1kdiP8tZ$Hf~3;Y-56mqpM!zqR9upL_@9dPNsz+LP?jm5{9S5DjidndSXca-IA ziGoiXx-cp)xF~?6Pax1LtIGPbV1-6t(>ps987dY1|5-6=2cYVUM~R|Nrg1wyI7vgN zVfDA{i0|?Xz%P(hVsiWhVwAe4_(Th0EGxWf0G`1pfU+r-5R?LQt^Fi=vvyP}Gvl&jQ(b z+!p@7BAY?B;ZL9d7vybYU|R0*5labha3qe0d2?yP!rd*VYOwQT44{f&zh!AGzax)f zJb~m@DtuY~abm}zjZjw!F$W`ku66#RQw%?pu)h>Lkiy8>Xp{wKPhVmCnZZC#k`2O!k^UB$UtHLAW9z&fb*fHXK zr2ss=@S+;X?^K^%h=Aw`Oi~w4@Y!S2KDz*cFprS{oZOM%O({=Bwfh(kbCW7+hOokdZl-B~W;6o~S*3qSk;32RIhna8FQ&{0r&CJ_Y2w zj=54%zx{LwEfHeUh`495~u**GT@Hd!u!@ z&BaBA#Z}A7c~$iyFJYJJvQ&S+r0nMQcH@lg?2b(q>v|_*0y3p^1*7&XD{#91JjLDO zukZAyYm~b^wj@Ue8Ld2qVREmEyY-EBL*Yu39(fS(LJoJ82DDp%*W5%f&hOr+-U`3Ua17$zk3TGv9CDhgx4Y1Xiz~an zt>BYw*j<#IVKO2X;>ZGkB%>s?YJG1~OnmQf@L0H-2ym)!IzdF39ck^>XyZWLWhwtM z;5`0o+)4To{2q3SBb#Y!q?!fR1SOd0uwKw_fmT`eb+UFsd+LYpsq^)n8y+lk+|Lw+ zq~c33P?$o+jna+%jSVjkN#)e}i#u!yLQG{r`;VT`O>FGZ&klif0abuNx)vr9IifD- zK!o3)4WO*t*EkoFO`NR8vPuuB?1p{1&T(joS%f1<@eLfpC7g+X*!*RC$vRocuWlqA_@sCP+LHn2zRO z%3jxi;~D~cyYQ(D^~+A|q?k`PJ)0&qe9`({_PWw>o_NWSzh+a`A%SJ%S()Fq5+x_{ ztu?R23Loa=J&E_lL*FHQhkE^PcK!?A8ZjJI6BAT>FT%$min|)QMH_L z7?MC@E)9xaNP+)^SD!4-t9Vhae`6+P*k#x_W8VL_3x`5Tyl?qukIP?t$%jdOG5~`l zxvYZ^!4`8*i_v8<>j++5L{*u64fJkHf%I* zt3uAv9O`!R;#}Kc&Oxu=@biU;+;9OV=J^X~ebTPyhiCpVf2(DhpEtcIL1xjSckG&i zt<>fPKcrKT0%?5AUxNUky^_P%Q})|K{=n&LVlv$M(~h57eJtSo32`?$p zZx}TN`D^KUGHJQQX@JaXz(tHqwtM~`3Cy5j#hp-{%{|aVnh%J*_w6ya(gq$~dC_a@ zNL0_{RROuP{b5Q%@a|NVsYDjdw4QtwZuGM8^r^6H)lHEyY@0S2hw*O*Y5bSR-v=~% ziZlACScGII?VHNOz3kaqR~u!S&&&mq>}B6C20W4l#kF1S1Ek0AoH2{Cf7_EjBPk8+ z6${7Q{?m8ko&(o+8s;L0<7wIvUvp#bv@hOMJ1$TPsY0TU(D6!NC)49zOL2z48WhyY zrITSPE#PCF&~pw|gq23#^1nMkBn7Fz(t04UJL&fg)7)_^vUm=?9?;p7f~vM8uL!dA z-W-=Vp4JjR zm5agzD=?uVQmJ@YCr)#A+ybkokFWloLD~OtQp@3RxGq&t4EqIFO6i=n<94TSvZCIW zu2SZu-L25dPHZ?@gUPLI->=a^gq3gD8luT^Jy?ZH=bsJh!3>pC_91R9QEaHM?o_E4 zXcPzHG)Y^q=dVJP#9DkNcK`w;E@mO}xx!T@XrsvAiq(fe)zZCa6;Y3xYqVMTc3tJ> z8W6aJwFOh_*955e?B4sX6siBMMFazJ7+S+m^7}Xx)l(i?tj?ll*8pbJsE+MW#(TN% z1-JD%C68`CovIZ|YnTlBm2U0+{i9M!9LXd1043^pXX%2XG!ZaIgF_pYQT_p8KID15dw26f?kQZ1LwXTg!`IpX zIj~~fdR6zs;kf1hkAjJ{;Um+8^Q=fB%DB|Vb8X-OJ%+8xQKbFQPei=>+@}%r0XNE^ zDm!m|JH6qlyZJYN!spT-QnHX3BoV-az7Wk*!tUH`&xo2IL!09p9-&G`T54j2cE1I@ zUz3=ZzvHzcmBdr&3D;huZMd`sYuFcpz(s$A@3Qlirh^G0f3C~#{}|<80-p9Lw_8HE z-uxjEZONwVSKvn%m7@gh0KDzfF_UgEDvq`y z=r#GJ`OP#@yjLHR{JqDV!o@xAMnsc}q{ML!-#_Yp;eSNON3GSGq{uZWXw+zm&kAB+ zD9uvsu1ShHDcM#I`@tBr!U9p4Z8fq%Qgh40EVXYG*hw~t7j;OHL4^`_N)wC%ltf=j zZy7x2ub+Yh=nYD6x#QQ*JD@N>dw)ml`#(!XvJbez>Jp8=gboh~+q^P)^eNbo{x_5E zJm&_o0aQoa=l9pmzKINcSv+F*s+b?k2me5?ft)u}O=sY&c7{j=*8#fIlPMcFS} zxX{pqzWIK?%O2~G&6l%OQz*@t*rm;GaHUorr%J#wS0xF=a}sJ%eR{!I;yEhU5_Dm6 z%t_T+SA|q0$CpIh#&ZkdA?jJKYl0UZU#;7?L;D*pmVb(51lQ_Fw)3@akEYyjD_nX7 zvHHg%u3GpYoTXqr8v1JSPR@^DenMXox8MCb{yVj#94~#e`Ew4O*Q|f{OOv(Epql(v zKY9F&v?+4?>srR2(BFwOv~Cfe~;T<&s|g^!{#bgN`FMX5n651 zZWLBv!jQLLuXRe;J5qws(l^#a33YUMOQL!l`2I?X!m;ZfO698f;Y8xOc5K$_kK~zZ z?ZG@WDiO(H1oR@yyq?^vq~&iLOnA z3aKPsT?T@T>xOIPP0kDeJ^zG(0Ln^DpDK7UVT5uKAj~JBAruPk?9p~QCd#|zNKt!TXK2T`#s)&4z_P!qB zf+sa`G79{xLYLcQ0S<5B_{?dM4ajXMOWgivI;Ogdb{?vfC#doLN6QDbg9YG=N9uK1 z{#9C(%BoV-#YZ=Ho2lxzK517H(2ls@MleAYw(qVp+FOq0I{MLOqFH)?-Ilc=;>ezS z6;2QcA=&I?&;)sNb=Jf33dk8?`-$?zWy5jwdsfo7g;QUR8@U4LJP`06CA-Yp|x!`^EnZbWe_-%3cGH@)n2TS#LYp)Hn zrKKZOwdrWt6iY}j@1cx!$e|LH&n!R_Mogh;U&Y$W zS}Q(bqNG(S{_eE+fxA8}{dHxzqS`y>VNEWl-s_NV|ITVB3HpCke4iK2@qAQqd*d?C z4pR2vAk8(K-0Uou48{_My}oU_Cmp9aA&q*g!4lVpGwXhFOrKIEjY0swRVKVLL*kXb3S>% z@}{MX>iducg{EeOlyOK7Hl>82(b(oxQ7m4lRr-SF94|H`IP`_Bktt@>N-;ovC(e#R zP4q0#Bq-STzjYqdNa9hF9F+jHuYoAgs5?5Hlop-FHDK_xRBAl>jWVK(x}7xzJE(b7er$jLZocMOC-Hyo;uI_vKwZL6N$ZM~iYau$0$rrZdFd zu0nOWhdA!zH4jH>*DLR{zwd&5UXOH!+O{wEi26;bh=SJ-Yc3#uV5=Qmo*UC2lX|(l zAA#T5*O~fuQX0Zf+;g$4HFk*ghKwMdx&#-Y^#-C*n+|QniTZ~pNM(g$O5@jrG9oV` z%WY=G8LTL6)RRl(`_qpHgAVVMUGe{5PZr-rdww-F!^Td06&BLUz$RQaHhjfRholm2 zr1;-|NeIv1zmX~&TfbF6E3Y473X|}Vk!LnAkmEPSo!P?V!82ogTxyN|+5+&G4J6ft zy(g$^s+NJTAtQaKLMj1?!ON>C?`AgqY6}NL8GF3g~Ej zL1Lk3QimEhXY&qZB_D~6YzDRft8y9M}2)e%@uR*pNq-xZg$rg}!;aCW_@$p(C6 zW7I-?hWoD1;j^$;Nosj8QgMGqlHN3mh|os0@~Tf3UIPfF$YdTeN-&hpVE!j=V0%>| zQB@j&JpZWvRqvJVB@%jmZyf4H_T?OrFEYp8^_26{#pv+C7-(X0uFRC;(w`yN4arP0PI8|qWRgsQe}F_?*H%Z~7996jZ|e<37b*?kKu++=hF`y0Bx{#^K>GjZuaWAX zHR^T0YZn&!8VBnI0bHPS71D-HR<6)tcf^{v23`k42N(aF735irI{ z-Q}+A#sRs_sGOWOb)1jBO*jD*Wg=6)dyxI6J7{Xq06jp$zw08QEClf zOinFvj>3#O$fK;yL5wCSr7#M%+Sr`rImai)ywO~C}vzcwn+jsY90n~2bWVr%gP57}4KhI<0M5Qgn+73&FzPwPOWB^tCbTX(Q_{IY;9%tz zvZ;XTaWFcPTYBe?#~O0(OP>JTHYoos_v_&4O*)KX6`Um0SoHrNz?sI8%s-KG?o&Rs zc253uM&OflDIv_*AcAwtoF@^i>8;yWM@{o@naKR^gEx!(b02{-8gQNcapD? z=1fn^eJ+{AHpir)&aF!8s3*I?K_QhDfHt8vl=r!-g{bD=F_E9_3D#$sg$=zUyzuvy z`NPC#*S}nEwa&|pu@>}kjN46DGaRbxtinf7In4p?4`xw{s&|8MSH?LjH=CjPHi-Uu z9U%jc^js_HC4;&Hm<-aUCxY`e1GfVzmTa&6lmTb}86<~#tZlKagPu@e?6yP+YzbwVhkl(Z|sLd5cn&JrmO`U-)uD!?+YH@33dw35vVNjZa1n0d;3Gu zZXx!(Bq^nYb)20?GnHp92p3U|%ZW)Xyr0L|xA&jeDF+x$fDeb4GfETS4(#-=)f=xH z!N7gh`Zlxs(aTra+e!d*FLO(oO_t&1k<;IYIhi@pI%$_9^l7}3aJ(R*{_JJ?Qh-U% zSj7j!>R?%!$_Q8pqX|wBaD0TU3C%W>*d=Y8@pgEhpBTX63O7hEXQUZ3i!0N$rb)q$&Z5HgANir4tAyb{O+sR-I=d|8>-8vconBNl8A`QA}f2l-3giwitLW$^JzyXdJGqyXknB=0V zmp5|x2#fsRo~S9v9Uw+3Dac|3q%ny%QqeghlWiWARWe`bCXU-8eCF!>;Md1GxMfUl z*Q1W+?AX_=Pe+FqTXp2h1p2@D2;r9prfL0o~@+o4hs_SII?TDU~QGzGqxu>M^L2y$N_T8 zq!EFDgt*^NN$zW1RbG^*{IAZ!$a|lgq-mspP*A}}YeKi(07uT|jqsUnLQmJSp0U89 z7|P;whJ(W7(NVu$A>P>`QBjJQ(i2x$>N1jd3}cWl_4Ip7KS|XOVisxvj^J-KI!75O zomaOsR@4j1?Zm$YF>q9wkl>`t#2*tBF^m?F4agL-<*}fYvXZ#Ye(NY8*pg6{$0+-^ z-|X!t3islHd-!tR0GV(xwIM;Q-L$*#x9U|!Am6YwdJ;QV9|lJ#dkk2pRL>*gYZL^SYMkd7T;k< z?#cN(AyjI@dCO!YAPDi@$c-_BiY#>7u1O9B1h!i4N7)wD7xymS#V+`ogc~>X!n)Ky z1>j3H$Mbs5EX5fUHHqk1jJ`8$?d|JnXneROI#jd(seSg7X3#I3gTEEx_N%=mZ;Dk3 zfWdb^Uf|j4X|}j=kiR-~K4VdX^%8A~@p4;i>)PQr?$SyxEs1g1*~r^mby2T8&#AOb zxd9RlUgFW&$R@1>%g*@?ca1}J`B-7XCo%7CRku@;O1eFX?art;@C#?ywb+pY`i}?E zQ#_D@gA3m6uFf1s7%s!Aa5q>(DG9wrffE(n%4=6SW((q%D?4nOX-%dFFIaW)*E{^C z2kWXfLAeLW>D5#r%(q=oGXRRk>qD|XWE_s&-^Yy)&Ki5yb#$P|6<}sk*J)Uak_R(Y zTIz*Ws;jX*H7}a@ADrf-%WSvC-5j!s#|R7x@H3EnB0_^K3Xu} zELgX`|MXUHTV$gErs;mtD-nJV^+8roj*F?{rg?Tz*5qYkQsM-lCt%}%@<@?&=Nt(BmbwnN(xSSDbK0)Qy}n?vEC zvqOyTF&$k+?#~UKVK9-*@2Bj&tn@qb-*`wjDIydRx>khFb7GM8NZ7P{Yfv&$%*^-^ z)k|qerz?krq2=)rKjV|Xevsgbm95kn=GLg)9|}OsjbUg%B#WG%(?GnlF9NcGnj&tX zzb-CMEfO_dlmzu(tNM|76 z88%bjV~cfwhRxnVS(nPYl_Du^3@GbQ}rvNu^f)@p0DPJ5cfVEtY%G zQwT1ppo5^82^#Alf5p6DdZ+SrEHo!Pd-tBwQESqn@rrrdp~ie{++Gbdx3_%Jm0zYC z04!01GVnsi2gCg9uO1qm`insm4hG3C@fH5COV^K}bNya1662%SIy}RHP0G7=PjE9W z0RV1q7}IRkO73;COUw~ykLi}33z&Nh+vQ%Ww=LNgu|~>W`30lJy0VzUpeIV@G(jP- zVMPjT<2?tZH8N8>UL1awd15ta<$-(P=ziWd5x38<#5sKgFpU3LHRY4b;vh zVP{7(+L>P;U9@~Q20BZ#fQBV>#?* zFh#RuzT>QG#z%8xK9&SM^bYb(a2UIVc3X1S+To0f@%T~2gc5P*+=C)SnU2@%SGJnS zi?rSu0g?D7ah))cP=V`rE1Ue+K>xBja#QmcQ2qaARTJ<5N8>nU$A z+P&LAWhqclPl}rn%OTkj+Iemwtx*EtWiYmvfWgI7cYp?$_%BP$R?<(OvZPzG(GO*R z#GcR%N7iGWBHp6X>SISm_A1-Wg-(tOd)lbg($~w!IKp{6a58TqeExUw&~~rdYHH6* zMt@YpQT_Fu(XiUdwuyQH-?|t0*Y>PE2MT_`PvY5E$p#%CQv&O+sKL^dVL`?n*@=Rk zVlm&0!kl!V9k3?~tdI^Ug5MD>Z}VCL-{Czsn8VyLRF1TNq()l@_HpRmG1{-ND0}O9 zxI4z;S>)2>!}27Omvfyv^b|mRC%3QruK(J)8`iBi!n>KA1#>0%N~>YbTo>U;#nj0F z%?cp>9A&iQ%~nQVhBo zGex!!vR@zQL|J#gF~nZ|brN(%{6xQz=(d?j+RF3?3jcX<+^1v;svTGTs4fdboeXMrAaPoO631+Yd^LjhAE#vF@C`oG z9w(s%XYAw181+<&R-Wb7GO%rxfmCsjBP{{u|WK;g&ej5Z|nB0|O6aOr2 zh_Pth^UqaVoLO{b#7jad!6)wy@NyVyLm^Yfj#39wMgl(Hjx71`eJc3!=@R^0JD$*( zM0?eybCT4c0X-;lk3Gbu>|xK<4I#(UOXmNeky&Oq<9XP}%(l!-#)hj7 zg72iy=m3((*jFs|!;?fC4+-82a1rOBtNiEHr4dX%bSH^|DiXcqYt<@y&u|Y zGewYW!GGIO*XaE3q`c!^(5k9%E`JCUp9+^Lex7|i+qOl%qfb0+O5zv#pXl2cb zhfIoR?c8DObzWCNwkDWLDCF!;5%bLR8#_CR^})tnTdo|Uyn+q?Rb@Ze!3%6gVm7~A zcJd!Bn?>-?0vFJijHb(})XDvC;_3i7uI&gvecD@F-7*@0Tes290n%fjm|m%ZTgg?7 zZyyhB+bGWRC%KV!5%#x8X=yfj%TYj1eXJGP6r#>p5FMvsF<3}Des0w;0LBCNbQH5F zNesNq$er%7$=M0ERcr}Gf4D{hAnf8cBe*T3BHl%rHW+4pM*$26Uv?{cXF8wqBgjMN zCsWf_tD4l9UC_oA5U5!u1%b;Yb^mqZGgFgeKK&B)R^MfDr)f0+@}ta9Q#0ISxxz$y10 zp0K1Br8XwyO#De!RgB;PR;&up^n0n{gPm01S8m_H53u2;c_#LTO>#7(>qcf$*(C%s z+<4Z>0O%P;iN>d2_+T2ESU{f(zu&Lw61kLPG#Np*ssZ3 zoSlBVPk^1@D>c?$5F3C8f8?8$F4@%ho^q{Jis<_=96>FD3@e=s_9y* z=NBmAoAnhQ>mWYCR5WB3RvNXd3;0`iSMhACbX0)4@nc{*XGA>5u;ORMt50B)+f3*I zl+DJ?m)cD}Y>sm^>m+z@V=UYTk_e4$TzP2+q!bp_f}0npeBdJTz5B(#zBqKw?SqyZ zCopX&!(pO+434dSX#lXE&GRfK9zo)MK`N~lP`|Vi zEFNlZOF`q%Fsw~0+(i}?#dJCZNjAxI7f)m7t#*^hgo0W>Zo-tL5ZzEW)}7@8$q}L~ zH4Igvn8Ou;3BtFtm{p518EShR6`e2!+-!j4!wWpLCZqKX#mZ11&P|M>#^*W&lKA z{KDs4u1(%r5ru9KJ)^y;pc)-tB9!g@J>5;%)}`Vz57fJt@?7}BT^iH~sRzt^;g;B@ zFiH~dNPa-8Fcp7WdIcvz@3VK##~zf?U*R9rHal7sk@TtkM=#fd7|b?npx5yJOwP5F z8L<@^b#a4OA~N=Z3$zd%9gLH7?Q8=v&MGN6c?5V0)y{nzAY-y4>URf2r0JzhgKrd3 zj*c%Da zP0(GZFtdPv>@jC>i&|ATrLb|ZPwZ(rM4{qsyGY84*Q_E!{frRV$*#u3)n-Cb_a#d> zcn~|FO~Y;yZo2r>dh)&Ax@g;MTU#0Q(HDZ`kxpr67=7O{<(} zTeI+vcyN)DNNyj-o104@2v$n;`!U#tJajEL%L)aYfywFgTlil37TQ$K(dkNC&PKBG z_FzMJQ%fIDJI8?*f_^R_VmQzLvpF?su|%VNsqTzR>UX-VTZDcgVavMGGU2S+>Y%eT z`eujqxGD)CfF=F$9>2k!e*V+<;REFrY-({Wx9k7_<+>YNz2E3pjm*Q?r!f`ufkK-Z zTa9`bMjo8x0w4j2BLIX&v}Ay-IBbI@r68Dyp1du)T#C;?wcsFTHWW*D2c)ah31Rs- zs%ez`Z3Jb(yDR*Sx%tt|@WAprjB6LZ&4e1|e@ISEK<>B+u&qkd zPWW}+CYFpvnHf7xa1Am>X+HNPDtZ*mzS}0Eoh8d+(bef7wiV|*uK0Q}QC9=sd^

NFb`PNsL9s2&~*V(65v4;gbT>0Ay`$j+ex>_9IT*DJ6JXLU(CJ-PDe3Sl8mIP zDW(BG=;q@u0z?4L+uUYhELbfUhp{SV?QRAtV{^dC%IQ?^yQQ?2=I4*Y=z- zr*EuKjNR{(82eKkc+h`?%s7cS5MVZ5)^Aa}5wAp{eC}1D9P%mMNi3d6$b)CFvKrqN zn}jv<+I6pAn-x3YtHE-klSmD)P~ItkqtZQe|3u(~*S@Q!2G?x%he*1}RdzQ06OsPf z4P4wvwBWI$jLm(RG_!zXrl0ml0kKqJJ#bbB6Y8;YS(<+BsU9@>862OQ{+pVe$$LWL zLQE^!cHQn?RuT(C>;&(F-$*ay3FQH9vBa`PeeKZ=;02Wl{fn-y!J%BY^Km12>L+Ic zr2;l>99AJC9H51$1i1lG5cR`eY0*q&cv(cRRH&@#dOu+q7M(Gi9NL#r6>u;z2;SkuhU`;j zouh7a>$vn&o^WjXlf21r5wVbR%u|rUm2G(*jM<8pXtSPT7#^?wqE5E_Vt{Aig9tB% z&mpFb-9V$wR0H@k?Q^L(f+{z-lmJ;doBk8Jw&K|*j9?En_YORXPf?M}0C2nR=QO{= zv%fj%BCunAN8MoA6Pj%MMwF6JwoP7!!xCw5+odBwqjCX&Ty@5OO`SQdL+IQAUa11s zWL$go26+bGvCWdZix`MK;vDmj6iQ11k0U@=4`AL*F-X@4Wi5a#P~)t;!u1eEX$Lcl zZAt?*(Rr?uDy*wdcM#D1Kwk9&erx=*zm&oN(XWKo4Ae^sn*<8KS0biI$b;ZT`Fp>a zU(UlYy%BiXh&OI&E*QbiVM^B|FmNO+t|g%p3-MajM@K|%_23&sB6FFPMm*@^LK|>j ze61RjO9=Lw%f6R7yMA1^M1!S?xVw6(pX))hRfVW*9>udolxAt!Xd}YPQ16fVIy2Fz z+5zhDl4dF69(P-3BmaHOx%t}UAGPE7{%eUd=JvZ94cMznU+!fO?B`15C4Y-ydrQS- zMi-91CA`?k0%Fy_-Dt83Wnpis*oVGLfYx@lHfI!XnUn^{kV(Yg0}xE~3G-gimCwQ0 zRw(2o4z}Rmk?@Lt63298S%W}2#0yQQqIIi5p6i1_bT_%z)v%rYCJ0nYYNAk>q9eaB zS(A0uinD2)U|qs!zqD~#r~oj$e4>=slYTn|PlGm-jKIG?E`^6qQ`q5o-go*p>V`P$ zm+EpH&dnyAc`o8sr-j_|2`_}9RikJnMx=kKkGEM&?CtCWWmz7NA+}5kN=<+akB`HV zgIOe&7nJ17UP)MkSv2Ftjr0>d4TK}gMJ`8Z+zziXFn@vcjqh7JbFw(!Em&!lSK)V*#XW)XP9wZRM}YW+YXJ+0E&^K5Vk@ z;Y%QYf)Mq&O+59>qG#PLpGztG|I|O(&*4yS-9UYln5DhiD5qoA4a82#1}q35mz{>dm8xH3SUncLv2$rmJmj)G0xz&wn;aPiR$4c`#Sw;_P!F z7Kw=jidh;0>tJp=BV%1kedqLT$M@s!t$StP)2>80?1SnOXL&(R8#Cu=F#$8`{*ph% z`SsrIotO!^>2tp!ef`I(;z#A3lB8PmDqy4uqlT6d2P8#!TH_bIZ0_HcQJcGI{4f?VJ78lZ>&~i9i2NpwJ zoX8Yt5!-G6XMIS?&STS$T&)S#;I(B2M+Uuq##-<*_z1e<0Y;i{whX~JzD>PI{=h#1 z_(Mq=f&pwWR{leMQZm2f*Jgefo?2oxJX6=nPzmKVJcvM!3yb?habc^AZ*tFJDOzRK z`Gb7QKv?ImBhSaE5=PMg^l_@5(x79~UxiP+HP<>-tO=@dUi2KDm-)#Ce&blqffZ1f zw2n)vWh^u(e|g0ri5FE-P)S%l7(B%QdEcj1BF(MP=@_3ca|o`9Bo&z{%FhT$qeK+ zke04@fTJ%cybcKX_70)0L6A@Sdt!rB}P2wGagHRvIevISlOW3qJGi0{j?Y+rNK z$6w*>2ox5MyP`G|Xxv3=uCbF_iNk{P&p3cFuzSjgGMo^unwJ346*B}hCuyK5UQQT$ zTnsW4A$XcI=8pA@Y)(3V)Q{j)fPa!-o@{rHGn9iUiDIFVWsVa#dy~ui!xPxENAvXz zzu)hNth!1RBf(To%pIr2gYyYdl7ie0iNtHL1+kNVeD=zf=&KgiOA4VVd*ly?!Zs|u zDaY`JmH!E!kQa9#cTS#f6&>GC_2~#Cn<$7ol-GmF7}7=35Tq^ONYjYjcr@O0=r|k3 zXDOlUP#Gzn_@)0rF^9gA?a$*CE-CZQUCx02Mygc`Y;Jw!OikU|InrIH8Nxrp5tP{% zD$AQ$@&gg2j4R^bVJ#FUu0_JKWOu#d(lED_PeGUIHz^@QL*&T2UBWhF6qtKwlO%f! zwTMjO!P<$S3O73mVo@@e*~j0{df6P^ZZ=9JLR?a9SY38nqx>LM&b-ud!H(}8o91(Q zdg;X1EerUdp)OgW`sp$Z!8o*_A^2NI_y>~R+5N`p4kKm0^?v21Lt5Dr;1BXa+N>9O zHQCfEk%x{Toyo{2vA(vNMOE)8U+Kao5Pv#s{KEka|5SD}Z#Tr;I^Q6rVjsAM+%v=UW3BsAopG6Pm7 zQ;R;dQ(8t=p(m3?0%8mLS_#k{LC01`=MbSOE}nVb(J>>cbvim)(m6%N;0|u@q!}uU zky-f0=-Ts+g26+B+M?R75DNajXz+4Ugw{mO$3$W_u-b`kb?^fIxyQvD>qSF{E_1Oe zL~&j87fMeE!cI&CZXHZ1&3iM4tw4kO`Eypq42=2zCQ=}+yU-W#!ob?d31kk;I%*>L zJ%MdNT8S;Au4O5)_~Y$GN}<^PK(NkwC(Q?os79-HBUY*(gK~}(7{83i3HmHvFdl#6 zfWL0rWoZs+N_^2XRd5Iiu6yQE4SmET9*br?MWJ>E_j+V!t69mYgFtM{Grf8kM2$Js zSp;TnYraFJ5R|c-J--G^pf5?S6xK5Tmp>r--@tln%em!C!}Y|JOBgV|)T|rsTB@X( zR=JeVz!QNyH$GFgZ!=SICaNi+wmw-PW6eK%j`Q?oZj%`AkvLx&dCn37=*$LO5RbRo zEdV!#^aiJCsf21*TNFYr0Uzs@f94h^3^0%h8O2GxqoV!u{K3d~7}UEl4&|*>Gl})E zG$*MlwGgs^W*6RDHiwN(%KKS)iEFMwX{}Q}PO?^DUPRYr=l#qx zx1kxtO>NbuEExykub)YAG&zdid|)B;Ok>=N7KdAG{LW?{^xwEI;0faFhwH7|>ZAoP z26(=4PGhEv#a!{=DmF`UAJ0(Zuu7ZL9mT0}ptzJ)pZ^({p|W`{kLoiA>`Y#ql~5YG zs+yvFwhc87qiJkz>5m}xqAGct0HVQ*Vf~<3)V3E; zy?)sY_qd*3MjIp zXFPO7zeMeDyTX|VVVoMX3D};tgIhDV5S4zy$fm4vTrI!gDloZH35CK60m_#LS>x|( zFiF)O;+&IGjJ?W}KTynsPhiJc7OsmLq$tHcCDPX#_Ubj5a^ zbv~KrktmQ7x(;sD57BoPspd$`_?$Ts+Iw896Wid3{bFRqNwgKxuTRrtL7^wICW0SSx2(*J<1a?Q!MTnY*;# zkSm%*LXZ0k13iz^KAugZKWhg)G4^jpMY%My?;G#X@0KL0W@;c$eRTcmXvk@c1rEK_!^Z6hj7d$`{+#ra6AoqH0WPK1qwh$9!z}Xq+H-SU-h+53 zEdL3wxI6$JA|3~tx0bu6R_kiZ;^be3>0)4(m+L=Jwllsv;4c-C0N%*G2u;$PCxShe zJBJxM18V)V5@Dv!UV1F49nwLz``#UNOU!SaGix5hBqD0vilx%C5Qhn|$FekoD^!AN z7QBMfZe08)9{HKo>^1ND-iaYx`@!Y`<#LFn-De!P{ry^$>1TrK{>otT9P_24z)J3* zt!x-nCQ|7{<(pViQ@2b5Rkzr9laFO{vF_<6Eje@fD%*UGp*a-|1FReB>x8%<9S<7#GH^|&uJDK>+Gi>=@}QsR5T2+$UI|?&?L>Cg_^D@ zBbOxk^BDpxaw?X9Gc(z&H2M}zr+VMhaQW+S81$@DnBua7y4>)QUcGaOD zzq$ScBkmeqSu{`Y$uPoE1&0rt~D@YuVSZ@Z{ zOcwKt-3drH67~yZ7}o+h%A>5NXrqAQze1hz_`oMJmL;}ynb>A~=f`)2I5_AD*w@EUgX6etJA&~Z_&V<6Fc~V<4KUAQm zrZ(_*kasN*r_WmmX--@%2lPJ|uz+(EAw}m`1w-KL3?nLT1j%J5(y2PN$gZ=M5nFkzMLM zIpdN3N@pUq4~vfq11QfMl1}eNTM>&n`xb_MUF2RGV79|g#$ugCVoAXFnm|XuDBN%Z z2UvlANjwv%rC0YWh@B4GPha5$3gcPDF-(m6U|->eJItm>o*}_ZmtbBxcZrdIcw{?D zM=30u@#SU=7MaZ|w=-LqaoWHHZ$_SCz8)NN#}@7vR=~Xf^kK$o@IH@rt9OLqMg|Wa zY`>*GaYG#moh0Qoi?Yh!-6at>!|9Qjli%&ATWwzQ6lwL9+k=XN8-`ehKQ)t+kPv4KAt&dWQprLH%1r2RVRPK2QMRC zzN;Y{k*T)T7j#WUMfouenjkfS*+ShOKKAvVAaF#qx5sl(uH&})@b9yZCCmOHjGhz-!gy`!>?age}!%cLd282x{_;<2_(ZR0*GA?wt*uG<{ zk&v3HnBBy#cb!L$jd6W)D4<5Nb`7C@n|!Za3M{~}%kyMd!to&b#mr2HC&=b;{xGTW zT&kH1wN|%2)kC@NOB5F2#VoWF8LU3Ztngp)Yb)iU<9OKYQao)j&{uZ@i40ptohGzD z9h>}j#d3eOSc8o0$Xnr^GC$4IF3wpHhZPSMKfBCeFCT+V&DVS2K1|L zm4q2fl9)R{(UV1glbCc*kehqcwtb3}{&`;?E@Fd!4r;F0a{-+HZ-Y~$nxG!Klv|D8 z2Zd(-dm&|4d>eL)?rhJTuuk>M z?hB~x6&oCQ6q7kJzDi+M`zsUZCN+9Un^kC$^~1mgzs#|8uj!~bc0i~T4dSqkfmnhF z%MwO96oy<^smz7zzX^VppO1wY;~>+}l_+u^=0mt?vU|P)9-}TvB<dsa#X0G$DCuHIkn z*(3JCQt*h%qhD==Vk6Ct+Rj!`A{cZ$1LZqAV^Y0~Xdq!4mDbGuwvOC!8IwA9epLD` z3Zr*2cJ*Qf-QI;#F`J?6{GNfZ4LqqiFfsZx=-!zC?RHP6>y^+Y0&cNi^1dYO$ks_Q zd&fTBR8&w(i1{bqNF;IgNj)4-v*@Wi-HjVkF)+R`KqQHq;{P^{MMTAzg`@S9TKgD* zD{|tI@<1C3tcZ0^n-C)=>NAM@GWisSb=!{%NS**!ZebK4D)~F~FDdUWf2wX#Z0IR{ zGWbtBWKG0Za{{#U0R7~lzM9zTK|3|t0Sh}oC>6P7W>Z|V$94F=uj?yr>qPHEo!<3q zgeu)fgmy1)c!?1$P8H-4TfB42ySF?*loQtk-(Q2UgMi^B8{f~Z-WCK>9jve|CW9k0^QJFDq9>r%oIIe|4cd2b06n=OH zO@Op2Kg$e>3P(rGFKCRIShb!G`SQRK|@ zPZ07&!e$|1SeL2cSXmWil{L#N{Pk8XI2D~phl;%1lliExZ&Z(`WvS5L0llYgkg(FF zn2P&cQEcp-l-zoAnLbGt$p|LLN!#?SLA>`mAKw4{o# zGD`+|P3MBnh`04RqoASPDj?Jyg~W#@gb>l@OXrAXlq6-W#@3=Fm_4?mBK`+}C1S|; zxa^!A<~_>+;wWEu$$4h>ZElNoHeTlTPi!G4;y5I(W!>m_BN#cA0Z-Mo{2(=Xg-8E(jdW{`=jdk&>P1~)DaF71Gc;z2 z8+p?nMA;bO_==w@CJ61fnHpOfMfkOwUsd2jpJgb4>+X{fe`B;4X$BzHXYxdU!T?xt zAkrufefL^31a}9&;*bgv{zLL+K0=8A%dhT+7(F^bYbV3Gcedu))s-3TXx^v85pWZ+ z>Hk>0wfwr6gu0`I^}}WHUqu4I;3QPNCSmaWsM>AkabIrSz&tJEym1V-53pK>mCAGU z8QljKF$vWAJFuaV+aE@g4JI#sOYyua&kq%0i>h-EN)Kw?T6!>OuB{AW+O-#R>EtmZ zY-E#&5QFXQtq+9W@;u6g&^8KMW=s*JvD&3biTMgv)WY$*+RE@X$ni~N9d%i=y`%*~ z*wSN>h_$hT=Q3DOS@nfWSdAxmai}J<#?Fs9e@IutyJ+SAXf3IvI_s~CoPaBsf?-bZ z9v4HlCI;dHZaR1YLeX9YeM4yr&)knTL;)wr*-nAj>^ZpH0ag9azR4XbjJ@Sa?;JJs z?2ar;19krX@+k?@f^;kzap%gE;hn9TyobR&aU{IKMj4k9POJ4u7iKiCMA=`5Kc)!a zHh2_Y*h-8;xh%cXsT}C31M8fKf41VtUh2;pedknQl}xwaXo+Zx16>)AeS?=XkTFna zkhV9wJt{iz)OsWU*%_b(5JVey(u7PFZJdZ~_A9Jts#OmFufE&y!oz)i8)VSU@1-oS zr0`9h=BTKWf{NwHi_=4^zTX}K?RKbn zb@_o^tv3H?j@F(5V<&btvZSaxpy1{CdHrogFuL$itx)rM?7Bk3JOu>?H=W(IxlX2Q z@#R9+1nqDe;T|@*%Yg>Hy`sqZP65W0y$&+CaUZ30-Fhboj6|rlv=#kH#6w-Kdxk#h zuPx^?W6*k~x%#6OZVk(MO`E#a$3wFVvDs;zgUC(|S4UEp*6=vxX(nHAv`O_=kgPtJ z?3ihvP1S|X(}LI!#dF2xzbsmiyeM;}d8p&!dmEFvR27G=Qe#(?N+2t_T&2;6M=5Hw z`XJ|)4BTUff(=(6PD{fKA{ZA+HtSmQ#so;jqb~Bzr@SeCgxEYpGRZVzx?%Vpo&Yrp z&HStRSyu!&_g@R8k&>ce92^;E+`gBB*T~S9;yZQ~DO@ZEr^Pf58d%EQB_C9g5YKBR z%P0fdtgbsam+}j zF*K8(1Bq0fks*W?1=u50C%6J-Cd~rIp6^@|P7`u4m;+jqP{qIO;AQJIl)@J?Uy1IG1=Cnt0%qJLJ(7Lp(c2k&n0P*BBPc(1C_r81A8 z)G9@4NS-UIC4ZtLW}a;M$n+F?6n@g)0N8^RGW-y00=|TyDlSByM}5Ehg}5S^89qtp z(L)yRu2Hzj%WRKgiKr*0B~@|YL|dYC|&JsL=FU;Kw zVDAcQZFkCPyIi5%=%PELB45eXQk6`t+=u>riLrAc@DfjyuB5}vDS zjLWf#xzc>_F3AnBUE@;*z%bD7in^0vz)R*B?3E&ZmibmU!Jm}ai5vJoesYOcFezLA zeBBYqrd8b7sVv_dOg5`x%s5R;N0hXPFj&ffh38F1`VxI`Ty2a2x%yT6RIJqCSRS#O zxw6W;Hzd6K8-db>Ch|>2JkE?7&}cF`+@VormFT;@gP?rn4NCb(U|D~yymjm-OayMh z(A0hBuCJ$kA@_>Y^j+%b5F)A_Mkw}>Ad}i^;j!~33D|*vYbF`_%&FWacj&z*r0zvD z3}u!nq5G{=}Vg9t5WS!jDu~c5QH$8z(mn;;!?p! zLqlav{(eob{uB&t{BO+1vx7BgLOU0d3!z|B;b8+HiTH12^_{0nZH~nIgJ9WKOtP;4 zleW9x+rpW1CRbGiUz%G_uS#x&=qEP;9K&Dc9+My-H{!7AIGvhK!Dt9eJWFFK?!!eRQ{*9?Q!IPHuWaGpZ^hT zfdI1?Mv$i4Fie}&n-zAFFk7&H2LGx=JS4v}R@fz%^WNKaqDcqI6K>z9%T~;^|NSaf z$75z5ZxfL)Rk1;-V*hZP4iFl0EoI{4EB2}T1M9U{-PO&r{Y&mtec34|lD$g3qvJc` z&tBbL-E ze+lZ2ay5_Pi2$B z`-if@O?|-u8Wz}HH5{LXJ1C!O>*-dRRikSVaOKBSV{DD8i5$!1hoGAfRL#s&orJKX z`S;ho&vo7CX?=;*rE!(^Q-64#tA3O{{JRan(sjpP^ebkhXY!V=eCDvOtaTFAR?U%C z;ANOK3u8cxH(>8HFT$Td!*(#y3Dgdr=9@#19cs@Fzc~iuVT*p_(w5XD>8_Vw1ZiBsiOUQHf$ZY*PCv-R9LkMZKQM!4+ zfl?$3ojzZ)Y{cR5G0MWvYVcmUdj6U?Y1~wU^-s>}nnjf}>)bfHR!lhhqtg1|dvB718xXNP}9SKPaEjO=$u)%c!v3ne<<_LM7*|* zGJ}2;?qSRD&46Y)KR%tT87sW-v&-JH8!rPc(u*eLfkFGZ7 zh#CN8;B>7zoJ2>Q<5DaqZ)_{c5)iAP6fk3PM^AZt zRWHJo?$V{7#W+9d=#`!2>I%KiG$wvZrgeneav$dPX?@H2PWK{hNmr9`@^B<5{ZP+jj;-bxpsI}*jih>0L2}%x#W1I z^5%=f)GZje*;KXHrHiBdO+9F|G6$qa9t|8Pa(REmg+{;NFTpt`d8kf{z_8b4Yc1Sk zVAZ$=lFAwU>tMGd$Yhxy`(js6b&0r)1jn5Y(}o!#TVPo|L?&4mj9Y80UbEs(C_LIvILhM6~Ht4xG9u}#YM zT{bs`_uGva|3!XdK*wyxb`^r$tv7mBY^uXXVp3Ysmwn}#B8H`A%I;rU8T9e)PtJvP z9*ov-Pr$}P1B6sr2*++sng-Bm0<|(LI+7pQAj{bgxK0nM<9K2s(9JFs&uGZBYQ|#a zZk*vsV_uV-(T74|dVQ-OkGEY)l`wsi`D-n_^Exs#-F-lj=E~Jk2q!V-RNX&;X*YZr z^<-^1RDSV8g-?)cB?$_GMg^k<7rtO{nJ|bgej!y(kOqvJ=QA+}RpdJnjaa6A3@7K< z_&mB1w-uM|BDn(%az0de9&*eJZ$v5W*U2-IE-GVIlYFh#5foymO394Y_1Nhj19p{9 z>?$RzG=$W=al)%bjdbNw_*C9nX0w#`)z`mhI3@1PYJ_$`xaxI*#$qp5CAKMeXZy2D zhYnOM`Z#gi_e<_Twwepo_?0CYjrxPPh1_bHU2W~tFZw!*opIrI%mE&~I7ITu{>rRz zYsf|Ahtc=X3x#P-pg$BLZjev^7vyWWftwH~{{*%62|dtiMS(tth6eN|eKOazNTKF! zZCt_Eq}B`U59D&(W8dlqO|TJ%R<;+R9#%%=c!);P_#7XXw87i4;yA(Yoaw`+xlcj6 zzIyD^X{xA5(;IM{Zl0N?NILZIthEuJ=Q5WmGM6zKaBwT=w-Oh`u6TY8YwB_U@j)`N zr)~Fg(l0x+M2yQ8AyBR#ODCYnD%y~N#j&@D6a!Qg zjr4)>-749>z(0-;*#u$A)Ead9#0g?vqR?6Mq4udTR9OY^6Hz+R?E!opUV$*3Jo869 zj}gkdWtu5A7G>#W95-^3DDZp|CMKOYQLvIua6SEk1a<8A;mAp~aY;-Vb%Y9cf^Wgh z6huDy>L9m6`gs7G0{LHzLUFLXEY%V^P`4wnu^_~3i8o^qzHjIB|J4&B^)nJCQ$JOhT$2d zlm7I5%C;}OeVldglkX2ge*oV&K*OCH?#mfGWt_M%QtUgr#$dhKs*+Y%5Yn#tuJ)Z? zQ9TkPOBH}8fYh&6+zNq2GuI4@q&3N20{+mnB5%t47-4BK_UuYPUj-fz?M@!D9suBm z3R*NsFx{vBudFLHm#vRJ8~*w+yJCSnJ#mugyxMrDQrE(Pop@0rA;+Q z_ZgAzKgCo|sUFmHdjDfzXg#w*aOcPg~F(kWs2`U0U|(;3o6h$l@uRnJh9D$p;`}y2bQq_@oOEE!Cq$$HtDpV z3?58ccTTN6$v%m@p43K*>V09^lro7Q2R^3Hf<=4u-`+tRQ_81H&T?a$j3IQ#9QL>n z$t@jpSEOp_tk;hKo_hS(${#pW5S_}V)7DQ5fjs&tpwrwl_Q301Tj7hxcy@e3(M7_i z?U=2a(KXR)AHyKC&flN;7$lpx!4JF2D^hD7CQgSWlPn4h>?TcAU6pZC;ZW>ZEM? z?&9dMF>TM@&3YWYyj)2x!z6-NsnW8`!3#{=Rt(-ZBryoDaC!dFxb~6_T~)k*bZ(` z4@7+!X!3-2i0`#P&~WOfNG)zcXeVc-frxf<)EgQ)2=B_m{E+Z1S->Hv@!x;<4smRR zg3rgkeEjNUC{zrZZ^g(H0#BK~HHu!@105ZBpmwr0?!5(15a_X#yCmZOd*_S1T9 zsYoKNuiv&1oLI^PK_kLCxWMh(Vg^LpBRJ#vJd72Qbj-2Y&-_;SD?CzxR%YmfmTLBN zcuU21QoDuFOydh$YKl49=_3M>QaSR)i0PO z03UfLk_*7jg)WL0*%>#66u(T>+V5gv$3ARh9cRMbdJfj1iHewpO~esk!@3b<*;%#EWWapvV44uH&TIgr~QrcJ_@}Zag=u~ zwfPoED(ue0jzp<+MHwAgh`bi(odQyle=8A5o?4EKuCNK>vH!~>@Ll%)++)8IQg4fM zyi3Wuruuz3DHT5*wb0Quwb4_1WumK&q6ymE9C;%0jhbn4 zb{xVgihH1r68hyc%b2C_JBr$Em5z%vwlJ+I5Mk|21pB-ILuWuY{XXPV^ptrMP z3}0pU!*M%k#)?M`yp_7U)_>mL(lj@5Lu2fGW5yTzq3y=oqIQruv2?l(>$u%DZI}`( zoNN+|eD#5#KH@B=OkEMO(CRh>Qc(KDgiYtybYI5;+wf5krJ*=bu-|w5pb2#Hv|;u* z77vXYRhy;^`Ay-S4_Y#RA_&2)u{1h*+l0t>2(@EDsHqjsv2h9}D9m1`6H=|R2=lJc zyRN&!8uykMyQ|qB?E`L+x>W3WxPLb;QlE+`TjR%y@I!Z}5$mR+v$VJ%j;|^Jbq?!e zML88-k<{%5aG(d&EKfq_grV^_?kaD-*DZ!#kva?t%qD?7nkiu;>Y>J>e){+;Oe=P5 zqxey-d=z{q7WOqslqag(yhjW)WvyvXl0k1Pxx0YM%Q+)@Rml5@D+gL#aZ#`;4Qr~} zvexG1GWsmp=zTM#^OR%?>ZP4 z=0x3TUAi?>954|(&Ia&F$X=CUt1n+qcDb;zV+S|Z54h<$dMOUU9Z@@rJ8~)@LdHUK zXwL)eyLspi{s7#uL^(&2rRkOdj{&6EXe@GaDwF@HN5|G|$nt);BDNdswtq3qa(q8OEhnu;t?x&dvDpc=-4Uu@P-IoC4k7P?I zH72+4$efbep)W$jC2OpXGnNV2OBzMGlOCIRzPT7lhEB%@zhhyABSZk%dLB0RKgJu3 zy%?$3RswM~=k^3SA$FHE&#ssSKac4!$XqF~qOQ}mq=expm6R{A^35J(^nOc_jfe36 zQ|_;EnLScz*bVL}%V?%wh>5GwfVzUm$MaIB&NO$Q%IU!BO;8AixwudgO&c|*7 zBlpoxonm&{(X@y#d8ub_dl>@Am~Dx^N)tATfSs6kWkFJFP^=hZRm zF?aLU!g?NV9`C<#-Q*-(5O!Q+0%CPju7VOb9Xv;02)k2OJH9VQ^l_@KI&`#jEjO3xjw1 zQjU zT&ytbLaHA0Ik7>IJ6fHWd-Oh*&R$NBK_w=IOWo6b!J(fBw`{_HuU2(H`U*wgdfb{jmeg8aN@&m3nm;6Yxi|p>AJM*si66#>S?&X}r$HM+d5|(Ns z|H>10DFIB}(jGzK=P(618al0@;267z{Xxl%a^anL@kzR#h*VhNyCP&q=R;kUEsxlU z4+G?w=@$;{@)(_atwvp>2?IvAasY!`Q%|adt-5-cGgLGbp}XZ`a!m)I>#Q(@kN>5# zdE`CuC}Ix}-?+JiiIbSRsXWi7K##dwVoKwlRPb>*>#sjZZrgU3?$^2%u9|9+26a@u z0I|)#V2PJ+C3+bv5%o&X;~yL!;{#8r zotBY~CbdecubES!OsavIYE?c!_R|g`n=N}m1I$dOzm<_2enqlWDxDNaH{Lu+3YWe> zhJ4TVY5=+jM^3Me#nws_vY3m~8h0pwEm(RS7i9uJLVJ2pJ7o%WwR4O`zL&ZHD#Dl+ z5DIzAly^A7XNwkTJzaK<*76j)@T?~ZJcN)gR7H)Rd}O$&{GxX!sA0TJn<$(vXbg(D zX$aOkhKF>l zqir6!>^R+w6#k>eA}|eq#iwVlv%?uq(s712g8S;h*`_=zMN4Jwrr;MEw_Kw3e^#IR^Z}#0(H60@#FHT}?-IgR*n-I; zONO|2^w|nGiX6y%SH3*AGU)<97V zk?{S&29~-ou zf>!Gt{0++lH=sOtOGhj)Bh@gHv6w7AXP=ZgmNXoN+MvP9moTGUI%HTY;0(Z-%le41 zX>v594&a!$=HBv(aD!(sHh)3cvy+3DNJ0jtsb{%$zATw4`{#l!i#t=04*E-*`t!Lk zrTA+Vkj`*~B)M9l2)%sglN2i49uJR{HOFT}n9=hzgUvQ#&2sn7lSS=wn2Okf|Hb9? z*Od|~$o_#e*^Z_WyIyWr8dlz;PNza7V3(~QIfpYt#mH8g76MTP-Jx1cAK)nHZ7wNK zXq>)`sFo~5R3cL|RcCU_`v(&_=M8pV5^}|iDu;onT9B)#UA%%zelj>T1qkgtyIrop zvXe`h)H*?lY<(2|CAe<*LDE>qe>B}o`8|skyvw`YwNbs{EAOAQ^53U{Q}YIr}`G$Uk6I+^S-C?0r*P-bV-#&Sf zR%=n*RK!GOnTHRvWYQQ26)}3{Z?6X#eLAZf_QF^M@ooK(h|F0}yX8j_y?5)meUH8w zy+lc;rtDOrzrRcdleTehxGKbH-Efs+!Pd6eue>Ti(Yw-fQK@j1rG=0HBBClsDanS zPvSXC-v&I3k^$uatQEIPmRdwkx9dS=`yJjnxFxIg$wjT_arb>;oaaq@UhkBv0@(h< zvkAG20?JffP?vlU3fDhWj1zk0_VUPLzU11e6iUea2|Cjr%O<~tX9zN*Mml6_4(Sfn ztE@_NdgAYfM;)#QpkU-T`JE#ocVPI)ibc-&?lXXO8D6pFK)KXcY(rA}1@8jyA|6*_ z#PS^F&=yh3$yv^)`JVhfMf0*CQeXny;-cK4lfy#9ttSy^sF|oq;4$wSqRqRzGpaJ- zA;rch0x@1Mwb{`FZN556Bj(Y<%{vmD4@UsU%;+d`9FKqrFJKdw%zN9vs?O7O*Ax_4!X4FOHVqUEppkSO62bXz_`D1!d1+qAK)8{~}e z6%aKlHeH-K?*W7}K3`GoZa0GptkecbXzK@`3IM&`hRL@1v2JmrsSG7t6w zxc`Qwl#Z#r9zp&k-tYg z8b0B?;93f^TR-fM;AJ}M$#7~J@{8*}bukpk+=u3K)j@@dz2Ppp#JQL53?wqu-9jdw zhzBCvSZofcF$=@4k!+~aCd@ElvAJ@l{4Twi{s%P7z$t_iD`|26cwj=es5zRwy*p9j z$3u1t=H^~lemWsAp^Jq4-#F-ZPsr0lE1R)KuQ#E`Suf3p$+HVC7Ao zm}x|V_gVu|<$q#K@FqA0WL;OVknxYx=$kI;HKm!j%S#*DI#m{Mprx+>Z0d>nou%|m zzVCmxwxP3FOX)q``jEnDCu%nwc@7vu*J(7*+IXQxLbHXvW#evP*JV`BWj_cMSEzz{n>hj|Y2Z=R<%XhuVC zw!}CBO4{s-(PdqX&6sr-p}g9n)hf{M!EfAtJ?<51nqb$@BNo#iiiVwRm2G=qOI>iA z8F>L=O=I+*7gV=?m9Ko&BIJ~2d_$5mrSOL0BJXxVqAoj}Mx4wYGF7 zB`(Bor{J|kx@O-i4JJ{FT!!j*Ym4KzN<0IU2(i#-(dmX+uheJQgRw5D3lNsfOW`3Y z=dob)Q8AwfKBa6K($I2(dwf-XRolF=$Pg z2sL)mWl5sXvCI=-RCTlV7~q?hxZQgV6?O|0sk zxgrO9T|Gq*E?yY07SS>a(cI)f(z>ZQ7f!}!ZZsp~24#36)BhI)(Dn}Tu+7P)Acq`c zseO>+d6pa=SrcB6sMEP9Pre%_dPOj}TI_gvV`MOdVTj&Oa-W1aenKr~OoadQJEuD> zrn`d76#czO$2z1yhy6=-@ElM43UdW8C)tEs^z{h@1{qBIUY=c%JEib^#EXWSkzlp2 z%YMv=M2M02l+{95tD^UjyFYD_wgZpfC?=;@lWA!wyCynWE)9hg!6Jl}csTUWXNQ=7 zMSzK98DkCe0V-K3aac(Xo(yl>yi)z&X=DkV{^SVR0jacjp&Nf)HzOT`E-oyyZWt|F#6>urefd82D zD3BZBrS%FZIb{=BzVqFPY-( zY=oQPSVPF99q_~mSa^8TxZ9-BpVJV>gnNXd@i%|NRvL`K>4zELM37VKfHTgZ1H)tI zV*#mi`fVYXxQ8Y0&OE%S`&%(ErJS7i;5%NswJ92js+tCW6okkC0AD?SLiwbpg%w-a zO1vW|u5H~2ih4;W^luog4SW+LJO$9pf;4lJCURxq`ptBxkPc!7UHqL64^UF(zrNsS z`sSpmMU`-ZJ|l9aa^at8@Dm&Hdkv>EByjbM`IAQ4N6pCfBLTyQ`zXk{_`kPUG=_l( zbZM1A?9TW__hE=YS!^4PWjq{J#NN})MsSJ-gv9b7Enl{C{#|-RA)(|Ba{CcFK`)0;M_2s89Ww(DMBB<4K`kkd)cp#OY$~ zZ{O0D=v?tQN{D*yN=Gi(I^0KbdsX#Tp$GiLawRF4D3Ki*DwF$@n!fx#Uti$R8mSK= zB4s-l%XPGKMFoV$iY=M{dq9K%2SlN<03{hOp!9Imo)Aqyn4Aq+&}eA?tm8|Ye?+y} z6(`D{3JX5lHUTOl9uBmXU*_kFHvJmVOpj}zlJR#xzc3c*3kzDy9o5>Zr~?;1(!Ze- zpncVYd%!&J$WLKQ@bkXp50iWfobZ>CFWs>9!DydksKdy3XrLGY+$G zF0NfCuM%0LJ_aTGWq_lIYnQ#DepQ*CRg+CED(5tJH=}YQ!qFgOCX&xW^a+YTJVTXVq<631!+zKnf)781MGb;+lj4_~LG z`t$Bap`#qa*|=mxG@o8I*PF4&?OrKr&%^`BC%l$H&y&X8zQ2L%xk{i< ze`;T9CKjIZ-1t?2`4m1Lvo(f;;*|f4<%ZEqZ&znDrv1m0!MAIhx&-w0tTbhq%gPev z=>oa}ZcNbr}f9A2OXaCH^OBl!^M9A`kz9{65e0* za|?WFs>53&C_B9URTy_=@WOar8j8;c}^@aDg_Dhk(Z-N@d*b{kbo{<8J6!W#UaO9RgE zdAm#CLdkwkk&%lveTu5PeC7!MDCAQT-OvVz&aG8f6HuLuSW%V-p z$F4lC;|^!C7{ifh|C`wj!%50z1&Q_&xxB17K_NQb;*?Q9T9Se2-Q{PV@DY;N(($+_ zZZPCb1(sx<2a2|MC%a7IM_@_>LJJ$P65xB%+mvUn+!N)z`*-A0zj796-$ioDVqFq# zU{UFG#i(Penlp$|mQ_vS$ko1bkt*BXX>w#@+)|k6E^oZ`%hQc`F&R&U5e)<3vYto# zI+++-?3a8m(cyMW)F4MyXF?PM`})Cg=BD2z@9G{eYA|IiAATU2XGh`@Y&l?NOgy!D z0Tjb6UBU_cHTX`?D50CFlmCku>ojD+7c@BovyIU9Da}oHyj^$Q1KCaOYr>~Ln<-qm zoVfrw1_I%jfespH!36AT#$$YKvkuzqOzN_ElgEW?90q-OTF=vY8HHp#eOa7e;fEIUibn(a%>` z79bhR>9~kn^uQ4rmxq${lE@`?Z*!LA{302gAg4>x@fU37M%D!*w0lvG?RY9srL+j? zE#&Dw5C2{^B&EQh!X|X~qj~3($8l9>4<|W=m0JsD@&0tfwo__-bwGXh!~q66X2;p6 z#3SSDOj=5M)-e;8oty2BBhlh(-_InPMpZ(w&fJ@Xz3e=;&k0)4a2*#ZG%MQ^`el^EYt;2q0>#nCSHEIg0*sI|p9$g{IVoE~! zZj6+*o!3^g-MjI|es7paf7JIE9q|UOwjdGu#3i0MyI9%I*U!{C?AY`>enC69-5|AaRQ`V!o z)IM(c4oIJYF&+x|Il`5(cK!l(Hk+UHLJ<^1c=!FQ)f6f%iKC1Y?L22;17SZDvG z%uIdDnNPA%5v?<%?&biyg^m2M;tR(@5%;^GjnZrM=e*>GGb{c{zTp=ItokG|_EgX( zX|lGxte#tb9wa_Y25-Uh=i)i0ShDZQ=9xqf4}6sZ0rq}B@s!#c(N_V|bwDMPL(|E1#X@LzAsBDV#KmXas%WZ~*}9T@zT$;)C%<>M8Rnh`@oKtC&e1uWPn?T@yA_ z>mT2{002i~6*SKML=9Tb9tIJqs37Ns=1I&f{5*bm%`T}^Wl`plf{9J`DfnP27NiK( z7RcCQaA_JDB~dT9^^fY?iU$o#wt|=1^(9SJer1wh(9!yVCCweHVX>UoOs8f-e^66= z+z9#(_r@|)y1r)n+dn_WlJK=7+7l0wrpD;}X$~ykd{m{fX}#EYsUT4#>U1UjamrsHrX| zyNKPhs75wmC8WM?9^zX1qyuYCetBJMDLJJCg?z8r_rdEM^5()4Fl4l=B?CQpO_ zalx83^My=g&IScd&EHZ|5{7UwPg+*dY~HK1QtG*Q#iu#r-g<{|Cv>HhSntuE3KU7h zab4y%97lONsOT}ItDrIN6__IS@rDLS(HY$L)y=*q1_f2vvK`eVweqGE1#%kCb?ZZD z%fdCzBlup$p#DFgPs+FNPM!EZb&r}=%X~9X_Rt-EW(V~P0z~0VtB#MVm0w--9h&a- zcboHsML@3UY_i-4GAF!CFWApDj5$8u0#wLB8-3QaSH{A#S4+rdn8q+4Io3&jn*YA& z&g(CD;bU#nkm|p9y5Wl^m{&q5O0Ocyhd9%2I;DXMEH&^uv`_CVeYEsuY;(<=@lMYN zSXSph^wqKaP<_-6_juh0{?i{lxR9V?N4b~+d?g-P2d#cfQlLF9qrK5T-#F8cak=x` zET$dmCJBA0Kvj?(nUNz}4xt)P@dwB&sgB#T+!p}3U^nu(yF?gtj{0%{j6o9+7AAPQ zYHy`QkZQDvel~_+VUnKI^v^vNEN6In+d8pF-LpjgBygqqIN^$v$WHzvIbwfW*1f} zXux)<%dg$oiUyB)+rb7$`!`muGH%IH#kjJmn5Y%tNWk&Bd^CbJfqp|FGns-nj2&_{ z`R({7skw>yyrFq7qU-m^h=@+>>1UIrF;WNBy&VQy$ICGTzRWjj_9s=y7U%I?gwh)e z4#P(Ya~SF(1c>d?q>#*f&gC8}j<#ER24{6)9C)1nUo*%gl*$l z8v9nWX%S+`$?xiNwdiXtG|p0eMbm=OT;PQe&rKlnpSS%U^Kd3GJwaHBJ$n2&kkC&@ z{uvl@eY%uiu6|#|L-{L1blTUnef)sQd*@>pSs&-zGfsa6P173ZW42B?AMZ;jk1#yq z+Em!UptW}?t=j#04Q;f2C}}9IzIMqopKX|&Uh_Q@RjQZTzV)qz7yKv_SB$asWo?c8 z4Jpt=G_(^7o8e0)|5kz|y%&?&gduv4mLCXL_Em@l~$fK*QgOs zGps1Imoq*A;zm!=inl#o5XPt;9QJ3nh8K2u_C&tzI|M?5hp0*Y#?fj&pYTGzEOK`2 z9HEaxa0waiV)+)rNS&8QWQ>dgFmtVAc02(Zx_vJFn>wQ@)WSWcJBE_Tjz)jWE?JtOX;@Wlj3;J%0qF-@-@(nx-mowFAMk^mkw&9>AkhHi{ z7WlHhgqb*Xi#C=76NSwd<9k{HH5F&139r%;gmE-i7ib=BR~yxTk4He|9a8Q%AHms- z4EGN}dn#WAd9jrGcJ~_mfhT5e&g<976e-b6Cfe@NCOAcwJORFOJ{i&6n(eV9)sk3I zV)2R%zez^}y3z7O4!r2Ng>l2&&12ScC10ZLRhP)Wagsyb+uql?$;0xui%QmgFh^`& z9H+cDk(Uwx=$o2W4c*qv2N&VUq>6+q5yDPvi^eGEuhroloS~Z|EBsG|gDbv4&=tj2 zoylO)r~@6_q8rDCt)6AS8uw}Y#g=g<3gLv%!MPQ+Z%J8Xgl7FfNC|Z5H)c8I0N{5@ zg0{E1OIY_&mH4miW4$7lW6UL>)LTCO527hV_y}o|DwIirTzKpjOuDc&N z^^C#x(#JjWa;humZrv%#5Ix0&5bkLH&^pz>7i$7PB?s_y#4(k zOiIe})@{(kYQ(>Z&)ndIDzYymwDqS>W-um1LX`hCVuhsEW%e`y+4Ix*6nb}^@4`YN z8DR`U`vfG7XUkSWM4s|BaKk_;Qe}8v#QmY1N!8n2GNR!6q(@g zinTY1TdCH-cH7u;l{B_V2Uf(<8O~;hLe$IWE162&0c5nRd07L)*EXA3kah~tUx|ln z0KleEc~rLWvS-PVx|&0$^oRpQ)_t<1>SJ2Gsu0m@2eHR0Atc#_OQr1}%i}g^O8)1a zcs_hQd5fF5p7)|P_Z=US`>t`b2$YhEmxOT6v8tgsRm~k(V(`Y8higAl?kKcYP6~jtns=kVJ?h`&hQdY5DW0Q%*gi#~ z>X;&Fx?q8Bqu-4txsUoz=!!DaVap{Mb=J@f@&lP(rk&{)z${)oWbk_nD;{T0o&OIG z=`Mdc+e$gT5)%n@qm=jB@+SfM4kFl|K_3^pi2S~#BtZ8|O#VRP@xcSP1RY@BE;{qt z(Y^nlw`Pet4RUp0b&O+B$M^#-EYft+)q`&?pu~&K%E-fFEg^TzqqTAY)k=sytfsBM z>~^LcnwF(zhn{NbQy72#Kb0$tkevDP;GbhSoLR0rE6iO<*cGBcI{9()n_BPiRqkWB zuS|;^;3w2Y4}>JZmS_(CFod8_yM_gjJ+gQ;_vK$=5{lG;l$~Y>%kg;1a5jV3!=Ru> zz?zIW{E1(Cgz`hJknM(Fg0VU$`vcbus1NN%Pr$zXM63tB-LA2(sWdqY4fya&*TKax2 z{j((?vX!j;iK7#p$xNM|I5px;OE8xm2qNFB@03#~Mk;7Tie*D*rHx+JyG$>XDuW^N z4Y3kz*O@lHp_7>~AiPr@*rE=Pm)WbD_(-Ervdv*xkh5e*C}Lt zaJywDwl;Ytx!O#Is|06leVsJ41Wf&+yS)$2e20d!H}T2!CmLEn45jTGX1T4AuQ^m7 z9jsi?4Bu@zRS|l%(qhX}1oncT1QxvniRgEhW5*)22HUN_Bq0ICvp`!tKYrh#OD%w| z8JBV^>)`ntAakJoEFfaXc=qq=Jq5MR|L#CuR;%tV3ZGJ@ZmsX5pI5RB|U3 zfTx(Q4v527_h#9nwgT#tHgmo|OW_lDT`iB{^Oy$JlNX|O=voT@#&6N>sZ|NFy96)t zr|wZ^Z@Uv)tB|*teX!6+d1E)qxz7*a{;O&QSYd-S_JI>2bJ-P#$PEWQyoSaPJ=ZdC zsaLmh5(Ax6hilECPpnXJ2c0fZoVD8SgrY+rcYT3c0)e)=o+c^Yf~$G*KkKmdI#% z>I}%#a&N7tT8_Z$S#=-r8|L;b=9vEDTG&Zk)DQwLKm-6?R}hydcGgZ?{wBeRiMYeb zDhB}zxv6!D9RX4B*koZS*JCEOt(-%lm{6-}vIX9+Sx%(R-PJDy;Kcj-WaGTL>1<{s z=1ab3=MVDy4l;V@Ibp2^=qPFs>0_Qx|I?g&mW2>mbp@&FxcIXVvAx*P9ojgPd(lJ8 zApmxO-XPGtd<14Ctd=my)%TLkIEZZF*Pw<4u-Tpyk-|oAA?b$oXDEr!Xr<#oi3R>tAJ>LxTeLT0?I;)|oloDg)a$3mCiAfS zHmcB+9IU#O@SANlWV%OKcOSF15l_}49~Lne(n<@dvm^i~%`QOtNsZ!p1Xa1mAyvAk^e+Nl-E1b|$kQ=-n0( zEDKx!*^lWO?=T~a;cVcQ#Nqhh#r8D#(q)3;X)?vuvPx0o{L6}K3Mhw&G=-*taiH|? zN1lGrMFsj(_u0cDo|BoTnK?>yIO>yMQm?)cG8-iJ)pvevD-Ek~`Jgvx4rt{I4 z(ANF@SasO1!p-WPeAfjDuPiFZgY<5R8mxglfxj3~f{+8C2*ynCAx=zzF_)Ifgr@t| z(xXw?e}G!)YejU}nC?G3JwFklYz9jn8WdIZQ7(JafA5h=@v-e;N3dhc%^Tl(UzSL} z5tVxg@&-Y=NSW>^$mQTUJWt*Q=&Py2*S&D#)pv^`{}l71So1O_)&Og%tc`lZk-m&R z-ebHN%VJ&5xUZjg8LOHR2>Rk`H)B<5P%&v}b>- zJJ06Ji2J&8)r|>o$BwXJ0U%QV6TR65j%P>cbj`_jr&O?Lq#2HT*jN7xbAVc_y%C<4tt8l6kBu^7O9|^;Y{m zRN`p9rzOe7mwz;ORKLW>+VtwJNXoZ5)>uGVEpilw_4MZHXQ6BxyK%?Kk|4*1#o2@) zQu}sSvg<_oVM=$XsRyfe#>VLsbs|I}Rz zheO9>k44gW%CVq2Py5#APGYu8Cy)gE9E3f-yf;?@6bX<%a3K#!;MKL=&LhC#k&ad! zv(epJys!1woE6PUC8B^{^Kp@_b#jxlgnVZT#wujE%vLKEL0j zd?dmXOG=5mxabB@Og(MyE`p$Py0)IP!^%@M>x+Du63wUu!UJ6!WVDVgqbX^yNS|Z5 znWe}90IXI?ai(G_rxjQ$IVZ+95X0*rta}+hvz=NJGN$7wq@%4#DPD3TPf;{q8V+K{ zq2YCa7lQW5>-Nb*?lEky)X?P?jvg~n`G>1OvcUlUigQhBA*9hyoBI2+V3*2JVR_8F zLxD>M5Md0E)k-sUbtzJS6!(tSIrKk!tk3?4wM=f2`EkP7`S?C7- zr=7n8yd$@g1VajOi6V7{YpU6FKDD~!$Kvr-P_vIS0eph+NlttOfPzFGz;jnOum;k4Dj>3 zN}KwE94#=e07F2$zw*NdYqR5+BJ=J>qg37e#<7Fnl;IXy*b3mF{MJ=GB{$QgQV48M zEa5WEp%;$bwIyI#m8qM;>!K!&+KV3v7FHjy81VFHCjXIx|Ch>aCz5mO&PaVY1Jc!L zofl2~_pc3QRNul4D<{S!?p`eh>Nfs>K&S!WWpx)6&|&aCrdm^1Psky>YA zznkkBE7!^{LzC9|p{^sGn5Mb8 z#|BD=v%NV~dRk=u=$~JE( zaRedul0?wpm0s>aeEE;8YVib6G0%99R$T5Y`joUb-~c8RXOj6z{I-R9m_a&e&&E}E z5An-qOvYN>6~7#WTby5rFsx5lg*~3l{aYf;%6hgv{aw;gl4sQop_pG*mC{$3Uusw)e3>%HI*A8eo=0sr5yO1vcEA$UXBQWaQJWwL? z5<=O7!c7;Sb8jXr=-BlHWxy;5PgbFSpuV=EWmtiR?B@ccwYPW0>n8E{ROsSO-RG#D zwyoL8PgDmGB%v*r7uYx7ca^LwRE4_gpUH63`C{~jtIfBowFw;d`#uo+jL=%Z$*na@ zTS8|*CLjDjUX&StRb^I_qKYR;>bl3B6|V5cWg-3YQ7coWg%!C zhLr!KU?%CZBQtQ-+w+Fq$1%rCEG(~-wCA<01(v2^OAS}6%S=S|iv^=?E&Cop+&iSw zpmt$M6^5}8ZPDoEy37hcn6D3c>#;Q5-G7%@Hc|PjEuLj@9F-l?jE(jh>^SqgUc5|& zziC~U6C|1E?ndpFD8&EY=M`rNz*wW!;1g+536*Da;V>w!P0tB$vl8-GB&1Y}5Bn`0 z=MLX-Ggsl&VS(%4w4+X}}M-X0{{OTULmf_mcm>aLZ-YRYKU7rMB^+XMPWb~45 z8!`q8jPh9U*5t~%H{7(hD0#IxF-}Hl&YC)Sz;eX~2GS@Z02YL)_l@iC<*AD)L{Ee$ zXd)OEx{YB(%K%oC29N7A53~zf%vJ|fyJNIfz6fg7=Vv_IEiTvG-D9RkK90Z&xvDR! zUgepXg0=%(U4fknd#E)5#5NkIeYTfwvh{fq=Bu+*-q4!m+sLh%L$ z+X7AdGW|fmk-YD)sfvv_~UzDOGGBFQqLow^lu|WaggFQgm!*!2c_U&pUc3 zmYC_BK0-U8ugWIjCEwhSKoX~TjI_QFaMG%(j>D2;`Un za_Ycamkd#g?&*RlT^QCXWTVE4jSad@zuYLLkb$5ihI~kgvxPfBYP&*St*Ag?!u+-= zAY_p0%fod?yaW>XR`_Ve)+M>N(r%#>55U+y=O+`TphZ)wT(rm1{q znSKaAV8k?8ok`fBndkr|2>`6rrIBPaG4@dKIrWHtFgN6+k7E%{Ra>;#&WmH=9-;p$> z5ICSAqhO&j5JIkM!-kmW2m~5o0%9-Ajd)_U>T@EHf*L<;&jH@-d6LhO`_3!pADR6< z0C5C1&RPGy`Pc?^_9aViOKC7IDbuTCy}kD{ahqOE9jKN%WD-x5Dp0ltgX&&IRkjUS zKv82ZZuxn%Rn^T6YmCTm3gHBB zc$q}UvzE$L+T_w;cp9!T%!T$4dr}DeS^$yY2}$}5raz4Ht!mSGHFJ|-Z_q2>`USYB z>^xRc`RMuoBU0nIZu*q@jCW=R@`Ka01|YHq9CNwDgoe)*5=sfS&Qk_PurnUf)Lk6m zN!bnZOQyXo7~9nDD(0w=KK^0Va$~KC#&NNa8Kqnd6e`*x@ocXnFl|ZBxsMUVKtCYc zT)S+!O5w_yH8_4Kb`5H3jB)A~2PDkt*2E>}mVYP&PqIHDL#gd)d=o3=)1ke?u`WK` z%n=3x91w_1EuL8YmEL?^-nNlRE8 zuTQINw5I)d-|+wq9V;}Eui;K{f13}`lN>_)uY~nrZeu0*6lDzKZ71rrJxQ~$ZRYoD zvSpf<1%lY$JtNLjksWV30?RREw|K7oJf6%VSQQ0l;2)cJ4(=cRy z8Wu^5lV?5}f+<(HfE;-KopHXRyAVF@U3CnGMZwbst7#`MnKX!tqAF0gpq-?+fss;k za&&mOP`n|l+u=5!I|^h1iUbTqsl4tj*LMp_*C1Ues6|QAhREhzfdCJrU?IXsur@TV zF)%Kb-vt9LwP)%8tNyeDw1Xv`E}Q@U*SAscW$v0>+S%Xmsv$W5EKL~c97ZOU<6@g* z;d@eAJognd*(a>Q)gTv~V^?1a`goQEUH|QxxE3|r94H~L2yJ0}8mw5)$~#~B4pYl{ z(xsjy!cQP;NAo!VMn|U7R*&Q~sh?I~p?(q?>V&?D4dY5Qi z{QJ``mX3*4YNa!w%5u$yR>v5{ z&1GdI?oOI!uCr4Tv2lw>2OA&x_eQzXmu%^3Z5Jc)U;!UDuObk}sh3tEsUS7&Z`2>Y zdVNUYRVZSL72-w;juN*KL5fTi4%~^vPOXaODqrgXXVZjTut+XR;AY9PPVRs(ZUQ=w z-02`*d$xVqi)xY9JBmCEMb+Klcd+8yttOI?2sZ?g`Lte+XgW5O0P+v5DZ@J(hJ4(6 zT};4Uk(qTtQspvXr1S1^m_oSPaLtW+RA07jSB;Z0Fqk6{>_(DekfV!Ivh1^&W+)RI z3in`RNJ*wpb1V=Ke01zs9%R4^nyei5!2(K1&yRrJenN}3qyWMOI*DPrr>O4Wsh+Ol zOmB&{<%3tnGF3X5BZbx%=x-+uDlLVsz7<7k5#GyX>vT|&?bC7;?g-Efg@RwfoNE?* zvN?1Tz_A(i5THj{bO?uM$eFR@uannfCln4ib3m^}$lKeX|a2%Kmsyy=mv^ z82)W1qhHcL!5Yzs30A94>Tzr+)z2_65SUXE%#5>(2lc6hO^!`&@g9(-PLQv1$~}-r z{|?xu>07@{5=Jdvw>gK+^RU)%KiVt#l0sjp*c&@ z#6Ka;&4cG!61C&KIa#m$lNdIcF}s%B?JN37=`_`K5^*Jm4CiL<1HK{WW@l~Xxo#dD z8U76k*$5dR9DQL&rcdu`R)>xQTt3xRh>I@*>@~rV-#Vr=G&jsfAGLv4y}Cf`vuB>g zk8F>Y`<0lD6E)@oLhjPPESc33GC1x$Nvs@owDN?jbD-s|=fXcaPN7V8mJVN&3M-=r zh{Eo!S9TQ=>P?2q12zoMq$F~NPSB<6vkqWjT&(;pTV^I`@O(Su7B$f3#~A5tQA+*; zr2(FqjqWDezwcF?$cVu}8oN8~A$_J?Dje0rzGLB<3i*x^5~r`R|J_HBXnzTcXA%>4 zxtt$EOg6d7acYY})T}SJ`~_*NtOyFTZIP|nOcWfWV!ld6Sl#UZvAD-5v|lVE1?XfbCWw7fDekPY zhUujRYc?4Vy5T?NKrcP!f-O@o%zoXwGxiC6K^#Wn1(n^5-$F7K+yn1zQXd%5WqU)^ zTeIE;-0rc209cslsGGFa+|)XN_js=jO?Q@gw<;09!W#QS{m?fi(FB>0ew#^3vo`Si zB<$GDb>q_vp10ZRauM^17R!=GNu#KI9W0C18g^w})-(jg1?{3h#8={TO>8L}d_qEU z;fl2#L6tbnbjfCbGw8!RWcv!{9g>_%>obe>%`vB3D&Cl~veAU1Bh*wI!Xb4BH$RCu zP5Ps=O(oSo0;V@SDN0u)20rja<;m%ce#rJ>JPa4RZzSvd4qixzk)E)*Ze8(S&eG>& z%B4N@qNajfgOnS=MPrDYM^15&c_YpRa+&bsYO7ZJwJM#1IP`{L`z02oa{?90Q2s=B zq{hKj=(K|_Cy*WQRhTf19PE4{Yt2XMP`o)sYL?dkNj>4E1fp&owdr07Q8~8ZH#v)% zx8PJGjMmRCLGri$sP$(|1;o{-!84)tB$>$g;f4OL{DPU%@>XLqR?Op2n8RNWF!gys z#fE`G95|6RK?@_CB5<%s=p z^tF{S!$<1k)Z1596YY9>tdPC*h~3BGY~PBZt7>-O{ZRg(sQEFb8^gavc76gIl$LRu zgpEqy$-4VH?4T^DRIny9_gmb+2zHuah5VtGQvk3-uedE0#8$^+6?7FyB%_?ov*+T* zI?x_IgTAwG7Q^v)(Tn(($gI3S8xt&f=n`nXg1FduBEuPOfRFa;e3UE}P9(oLWIC%B6y=p`)JLWxt*n zZr*{xXRw}?P6;lzR6ba4f$Cv3+y%~J2TcXj>?(r}yE6Kqhjd^ewD zfCU5aP2=~;V{oXX-*tibVwR*xUn7`nEx8mnc~mFeCkObX%h86X{IWa;^WQrpi3|eM z1b-eTwY38%Hgz%%LLJY37~X+v*ptWv1cKd8kfbMKMd(7?{TlvfQ-N_B5$cq8f&&7h z7_ilay3$2ncWal;kXMB6K6(4Mr!nF6{V19mhf?K%iYsIRd(%17apql#2s*Qf8sCu} znOY%h7jVzv=>LF-={7&jP(57w9(b3$CrzysGn+|8W%IL`QkXr&#<|b;1(<27Jm3va z#t zR-HNs21J_Q34j$$xJ;pNP0hYvIvAKN;Ms>~j-gwly%Al@05<-V5mJ(y06Hv`ljP1; zTQtO2&a8J=uM?gNcA^GQLdvJdVT&`wnQ*CxI7^?Pf4DaRZs5bmu^^s@eB8UR{n!qY zGZXmtMUTZhK~OkRyvrN&c8_rV`!p0Exf*Gn8&+=X|C7w>| zIrqUQ#tPDbPZ8QKKk~d1ic7?=$15C!;smTc35lU_5J_unAx-+nl5%`4qG=QzXt~(0G zbC{t=$lsE&;z^oU z;_&TWa}D%S*uvEd0>D+au;q7utFHTsgOJE-j|nOn6M}o#C*way4kq5#LJ_TAeZcoX zYi`s&|2t1hz{U?z2Ud2$HiTk^_c4S8>;Ls)<Was|N}0Ji$3TSST_uaELrgx%kG04@Cu{wrjPvIV(nia z1IbLn79X1uSL-e`L0hTKm)!S^g9cSPjT#%CtSrL)Pd2V3noxP7p-hh#sU#A8vY=~N zz7mwl)!(DP#9VSpE+SI*Na#=^5tgAaKLWIBAD%}0iVsWZ;AOxUZ4C*4p$LZGk#g5V zkNM7*@;iV3zjKhkS#G-~w~Hq;BdKGGue==RlP|gm0()XKbwTpXPPB?ypTWYh2Y&B< zZJ~B7AR^=gz(L?9?!y8m`K?@o+?!fXheRRm@+Z{t;x#l`1;Dzc;i0G5-2uG>*w#ue zvmNlZb{OFn!yLtkXv9J@sEr;Xpgr>3x1|B{Iz`o z{EmIOVs^cZy~}HV!Upy#jr&EoU-{Nw&s1xyrWBg=W4|XWGAQqMtdQ>P4n4`dZpu10 z=?C6O(8x)y;U@;2qzDGTBMVfgIjiDq=fU-32=@A-oLPQ0@(7f}h+26Xr`gKljyr)5 z<@T^KfA&eIa=r9;-pG|^NX!jYbAy4yJ**~5zQF`B+SM=IC-m58@xAU6x%Y%dOzE9Z zd#AExI~}yu3Maq28++(AS%TE|NtLtA!9Ui_$%ejOWV*c$B#rB$AObL>GK;AXV>>2> zP~m-apljozW&hYE(dOzc-q@j)vUsPHg0oQynBk+y_IL}V-fi!_bN7q)hYuWUgBlf{ z%@i0iHuT)0{Y1#a*$Gi>nvIH}x-a<6C&iCO7@Z0R%T)*MvWbaoPh`z5IJVNHmHnwd z8Ywqc*`Z=fi9E@mWmOC}YRM+hb+Q_dN1$-ySB^bP|Drhqkx{RYrhZS{ka z209)4;9Jp@yFDZ42((iA<+Dj3?N@Ppecv_}THQbH`nr<6G7a9eqxIe$E0Z3%;h(hP z`Zi@ElFY8ubkjT|gm9&zw*#qp9ZIh?3LzOK_cx?;GmP~~-<}TXv%qL$!MI5&aZS$( zYH9JZ6lP0hCAHAekk8RTK2DGYy6>pgLLAlcmb6*q0&{9A73XZLmsEf_`ZReDhpemd zBHOgkc2Kd^?ZsWxn!`RyI}%7|zG@16*id{c$1!#ILu=_BS9^n(Cv$=C$eQdZ+7cbr zj_E;!QPRvyJUP{p)Th3yk^5#w@!iXV%zzo>K$!nQ(mSKJ%`?2p8!2V-%*#)oCx@AO z3eq!zgz%*d*1H3{9TuL(yVZ9@urG3gT5yAWJmg&Zc*o3x5#^cVz@FR@dV)7MpUv&v zpcvch*xE|ee=uf!a7$NpRV`tf5Zr_|SI;*{d-tQ_Z(zb(l_Nont1M-6)V42Th3xae z;+cluqLM>)ETA*h(eHNWk*q!yC0!#x>uXP|4gT?4#BxJIw=EA(ESY$T<|jL7y+>>@ zXbNd^m?UiOZ@84VmmRz_0+aP(8K`zKqMqpBQ^irLsadG34`x-+p$RA5%q$qJb5H6- z_W7>DQ(Nk>Epo6}WfSYC8l_LsYDz$Fm{4_U0W}S*Y%*WvIY7!5#X``8lBnZ*Hs5F} zsqcRgMMJ3%Y{$FUnzZ4;*am>#z`KxT#2{ir7g*L9)bDM*%&*D(a*+il(H3kB7^JLz z9!2YZ@xiC_DrZ$xlYHjw3*F>u;D%9_6{|?VVB0Ye>(T3SIM(K@C2vY>y3o+{APZ{; zdK_QnWwof<$Rx@2f{`%At*5GfsCv7dLC+XJ@H2tp&1lQfsEkt z9Eel73&7_@F2Mcd^N$%tH6_&>`diYq)ezcR;%XI+GJ1z_g)e2iel ztFFbnDprQ0DpIzKEpVhG&JzNYvbhmC>fq6;h;SHmz5{EVX|-Hu&)KV9t@U^qzPx`pJp0C zaG9U*7qSzSg69mD*PqyPQlaRoMQ=VZ{Ia|SsN~WTOJ+WGUgX+7XI&?nK?UFDRF)1)qc=yDD?@bNZ^-Ymziat zflj$?v&9&dxRH_W4Jfih_Lmq|Wz^8MdZcY!U>ZAZ?44+PrCBCL&?C zh>b3tDkO6M0J%9M*BZ>CKn2bZrb^%_Mm2+pu6MRP^5l~+>~%9EP`5tVpoWRJJ2Ld? znSvCYs4J}!TxvX$hHmsZslq?l+%LTegG!f|+y#>q^JTV~VLCKfw>QpLeK~vGoO|H6 zimE*B>d^3*g|j_^KEup35KV*Tw@1aoxsW!_DwaNw6`?y(PWF3A^xLHykY#9 zt)9<|s-MEA&oCqn28H1%R!kL1F0u57#iV=Z{#}7Z=<(K0oXT2CjUpKT*r5=8gH(8f zqwRF95_B0+TMkJ`1f}KglD;!VAWVng&9p{bIl0~1X_vFcuq63j6vrCazF|DMGp3IV zs(bR;yg}|nkYFF=!U{Nz{J_&v!R}o5Id&XDr+1A84h-TZu+dO%wOBOi z#SpfoNPPaa4wE$TJ#-R9#3yaI&-YhBPxZ3NjEP`v>Zz}0V%N~hS=84jvh6_&==sgB z#`bdasb4u~MP0^xu;n&DUKy}fdVL#S9bN#Zd}9Vi=v;;kw>pWFflc_BRl3hWPI(@4 zUHNICDQVu=yk7h5P?cuhEXv+i#MjP83k_M*p}SS{Hi}Cj%nhbL=CqV;O(PTNi!hE& zpL6l(Gs-BX1lYOL6oO=S#J%W}@MGVKsK@!o6zMnwoaYx{Svk@q)#Ys|@;Jd15?0H} zctX=QxyvERe3D_Wo@SU`$O334%t<)*X~c#3E6$bv>Zuwc|6hZ;0+`5C>j9L2%qOq7V2CY7T{lC!mO?z(!)+B|hsi&(j8(-$ zl%ACJ*aeb=GQ>SOd*O-oDkOcqta`OT=?{x}CV_=4-Db^l*&*wYxKB(86uu{$c^`@l z0nuwJb_dFQT!~jep$_HCH= zrS%O}q_!e`nJDHwe|R~YO3y5v+(e4isVdEVqkxfq`^LM5?=uF zL~d;GLjG}koCBk?>86WLLNN^zNp1h)$4l^>a3%nGH1UCzjC#wp3^6Vrb$Uf1er_

8ejJX%`JWsLLL}HQF(wKFscfzWKn#zJ=q&&PKJxAFVi37EU!-X?a7)08 zJPxj*q}hm1q7&f9O}K*i*$tVTKmSOcVnPlJs+|uY>;6v96%u8^`+m93tg0iJ%^2eI z*(Virbm!ia#p*h<{g=ny3lGKgsy4tB5^frGezw*R{mJmpIf41P=!(Y*^74 zzjP%pgSA#i3EwM^zMcN>jKj)xN=wiVFEWoBdKWr#f6}~UYijgLIB!>2OnNe;32&%p zdzXw|?yw^gb_)!Nb0yLGi8oU+gwcm9(OFEC>6uERMrJNc>;T?O92auZ&h$==?1M`mXTsVAsm!QRCd4A9_q8_dI~yS0Q97BX@bv|8P| z2M$ewx_pxo6VmHU?7g8xDTc5k$~gg5g>zYx*sC??cLS>_Kd|uDDeAEY53x?aK-f<^ zm=-{&{cR_NI?_J)X|dZx>YSp)$!+nkl^?O1G!?&?7Z3L+NcJwYd*URkyJf~k(S&?c z6DPSn8@y+i_L1rMX)c800yBVtpyN2$7S0L6bK?FmYBJ4nreeoURFSZ)cMr+9<|F#M zRi&)JqDTng4MBO`y( zZMPOEdK2w8#+8bzcD+s^yz<{rI{{?r7w-`CK z*bg|}H#qCJ1$mEgHOiBkYvI*Y&}K^p0GT!DEweFA+^7zC5Zgm2 zuvuY74f4B2Hx*6<=BZ@p{!vF=u;IUq7)Yu7BM<)}MsUNsk_M47cjKaAUl z5WT)89CNj`blXc;_V2FwtUo>6UF`%A3q?32;eqg`EXc)-=X8PDbHb|to4vdM%Qo1O zveK(*pJ6cRs>;vj0GFB^v!Ya259~qE(941OywgetIs^BX%Gb5e#NYp(&s&~6zfy=` zSD%MU{`PI-s4?~(bn>VteZl`2!CuVLCJ$IltYFUgiB;y-u20vLZcwrYIDUF`YXW-r zp$G0<<$>>O;Mk{t{#Cemtw-gd4V4mCn1le65zF=a*w9Q!y#_VOso>6Zh_AE1aW19n zZ8Ak=yKbnwF`q*S5Vh2M|5*DeWfG36erD?HwHOf^Mc12sGN@h7xN?J|yBhd7-Gsg{ zdf<}9A@?@o@P1o#M0;?L&#&lh9L;DB9rh74{@}f9$_xW(V2pzqin(2&`l%EWr+q$y zS<%A@CTWEV?{F<~PKigX^g7)e9fmS;I%$HlOIq#>PI*4;WYIBQA#qlo>5A&!$NN zeAGEE1rXI9^J!lZg~wSoZ2sk;I;g?K4rb1M`}U~k9Gzls4{Xy!P1G#vRd?m82l{kM z)kG-*&8`sR!AArREN!H5YhM+@hMFC0CZIOrd*@v};wVjktV|S(KT-_5! zz;Hr%5|T#ln>>UhXJMMbV1Di*mVDS|JR|`=aX7_I&>7cH13vk*xhKX5Mze@&w!n0D z0L7dmo~yZYMZ?ENgTA{rI)V<=eRwa$D3$R|<<5{7Hf!ZC@Z2hkUhCuk3^*@7u}8A$?t&@kAV7Q|s1O&3IM) zs)68VWm@`)QQN|_kyy;1nD}1uvYn>c8GPj#sW>^(RgPBd^~Bl2lmpNALhv_*=x2M1 z5RK}IZ!j1pfDr|}*k4F+W$nCM^2aVuj`Mn@|C` zmFN6RQ#`rqLgK=SZt@PjeKE-<-MxDk&(YN|5dDaJ6`#P{0zdEMU{Zo7lK|^&(5Xcf zM2u;Sy&qdaL@HVdG2ZXI=HC^zUWA=`UfN)l0SoA@32l`wtTE=7#$dW*QM*tpknIMq z-iV-VR1*1B5T5Niou_4!tw8nC$focPz`gAa1zAba`y8NAUey@tamD6(Vu{^9wGO{M z=BoHFTCk#1L7jSsG}IkG2)ELYx@1{1!1N&OCy*$!qM6D~B8Speve85XnHuPbj?BW4 z08KS_B|DS|+CpeENnF!diKnjdU#WEkt`7Z2QkY4v(HhSsrHh5yr4^X=8E7VNCU}71 zyBI+#Nhho(3gGynppyPw;M9-$r28_g^m7ZW;-7U|^Br|9K78rq8(Q1zjR86Y|GRx7 zK5Afejtg^Z_@p7kG>=@={jE<=U$`lC+@}l3z>z1_ZfF94-r`Wid!2ACqY`3tjXj2( zG(FBlC>N%sn3?0G-HhDg5#V<*v1ax&*g7vn22Pe}pH=s#p=mI^C)As88xlkZuZwhy=XI3*k zZGuJS6LJ(Hiv}WB_&@)6%x0y1^4VKh$$OEDS!YFvj)1KCk~ai3Py)SvT?rMaf5Ma` z+EeSvPzcI_t>j+1_44UeEWZbzdiVghq;1x5i!I4^RDTZM=#5xmn@-{C!VYEULPd&l z39I_tY8yfr$C?=k0Y?`6JCL^bsQV*AnRz?uL>iQhbB`I_K#JZ4I1@~xCvENe4QHLm zZP|Dalv%=g^R%_yqN;b^zGih)4(Y$*_Hd+-07XppFYF(+wRfX&Jnh}HSKdNs4BVq@ zpm1ud8+~#JPlal2@4rL{RPe(Kil2l2W9Xf?VXsiAco*UZ%jsSG_X2RtVnF0`Aw@$P zWwW`{M+B|?O+T0M>EfZfMQUB zQCs=UR{_Y`ux>hh+e1X*rd#>dH={lc*5l?iLS$3i@W>)ab0}ul-}in~KT~twEYvAV zXEfk#=Nx+2L+m8btTEGVJ%b5MA7^%hl$7dgjv;qV43X2({O$F%dG zJ35Z8o$BpCcM(}9Rf?TCc}A)kr7XFJrqYy_0|ql*0nuF)<`{sidlR}VO&F-B8WMhw&*TWx?8YgBv zFbuAF?MytBUaqrN^qnZvw;v$`iQpB8N;>|9R%!^MW(=_0N2iOc&G@rd%J{wM17+LNEEewV5n*&p61vaa_d1xhD8?YBh+X zaKbKlgG+zhAVNE~%(&TrCA!RI7SXcsX#yt-(?2o6S(px3ABkPK0PHj zf_(TfA>?WPD)TQ0Y)JUzY41I>G_czbHR8Kex~fVU5EJN zR;BAZqYoUlaaT*vvPMkkOp>&fTYdxEVk#;>x**>H@dOi)BW?p34teK-ZrWGg0*)~e zz^`^#)O97#>FYDF376skisC$ zqm`Ujun02>5p%FkeaeITklNXrY;kf2i|DiAqjrzE?WE#E1(gwjD%U)vBuR?m@Ok%q z^2&Ji)~e?8h;zAejYMSCeTSYuiD^-?S|SRs!BLHt{t0dg@G@97bS>Rld3MB!FGSvc zZMQZuFa9lyT003T7nPG<8~rn*zV=?-4+gq$~{RAsSc@6I>a@XGyY(bkHhT34;1PwF7}$LXp# z-!>G0!pp@c!~KWC-ULh6mYR3WtGILa0%yYU6$#GQ)5vuLdYyF7eFxji1X~cRh07M_ zY4%L@dHCH|Sg;d38@eJ4B2DDFD~)9jaM+iE*pmDif)BAhu8ZPbn+m)5uLN|c0dQOz z)fk4bW}O$hpQFa)&W4F5#)#~buLkJJ2XZPvdLu-)W-a3tXFJA2ohL!`=aLbf7jLQ#x=1 z7Jq->-LSN8u~y4H|^T()mk=_4H@ArhCcrJTxIj^dFy+#3+NSzMbN@IAH||S-lK}M-aX@L-`&M{2 z)?JFuWNvMv|E1ZTQUQ!0nS46fqjEc=mMG0ByC_;IDc#jLNEYZs?3 zlz(q((rX&dQiqtXGAGgjP@wUt2BhjO^WGCIhc6A!rpd+RApn?*D@4#-V9!|%7<^$^ zX*eM;`A27ruEm{tAWt-Uv;-4M-9|Q$^>p|pEUP+Vs&LI*xdbz$tMh%(yS``c#e*l$ zF?eqrr;`B;H(UJ&W$GNOOz()rL?UP7+;q76x3OUR2E4!CdzB^Ky1lP|P31u#XXfywBGX7*FH!6YI56{hCXs1C>-T4a36y!hK@|jtm>qkd6*MM zPM^9l3NDpaH-Lj!MoF0#h|dRac?n6wmEbwFJ;;!>prR~7Xs&aMxA2|I^|infIkeWt zIG=wRL&=cs>cUb`-s!rb^xhA>J1 zk-@vEOFP5h}2YMHYk!sJJZVmJdl~ZM*T#_|36X;O5xqK z_Jm^)(!MogVEZL~vr#j;tF|&q$s^SC-Es-w3tMNWzWuAl=#=-SyxXYNnVAn|xbHaJ zE=ee+hz|@_5Rmlw&>a;Lb4gLgGx?lEL}uwtkYe+)rCBdE51=-rBnbbSY!q>tgSxIY z4~z`QkeRo*Kjyuu%d!H-3{n@jg|BT=h7eY|OQg+ZuPM=2DyfP=8K;k`(zxE5Le|mU{A8om0 z1fg$r#i35BS>}K?_7+|H4%><6V|9`2% zLIWWMi3L9GK~!IX7xT1?`t6a0t0n9&)u1v@R1k&r<5vEEtBSF#KNd7(`ml{1t)@hn z&Z@!_S2r9@`(wc_+igWY>5nbi15IQSF+9pL9wz?(7oRDe2~U>lkfN5*!Gk)2uU1+^ zS>KURw0!yUQk~$6GyPP^0jq6=nzp|(_Pvmq%Q|neOXJf5zSC;ozU{tIR){Ty(O5(T z7ky=!hX}bZ*e63;fJ&2OJTGf75cx2z23(BW^ZFRi##1) zLI6kN)h{1o3Zh!ro(8?FE^rzncW@$k^Dysy8NRv)2suD8aZ(;Wu=wL!XLk`T2f07C zEi#1O@v_DXxd|$SGm?@1AW*tc31^=V`^687@_oiou?h%{EZ}Is-6H88hGoCal&+4+ zhXquGD&I!8-?@_yuAAj|BWV3yK&d8wDhK}Hn?QSP06##$zaU`);l}y?ukI zQJpEnkGha|&AV+M{6b$`RAyR!^-iI%z%`jH-&A3*!#*zZwM8kHcerkbH!7>yNXjgX z*w(0LH$q$f!2>%}r56cifLjwy8GO4CeQTKY7awUP{f<~Ulf;ASk#>yEE+6~0iT13% zw%;PB`@J<0Nm6PseM1kpympE<(#Gb;bM#|158obE6&=0PWeXQKsOmy%(TeSd_yQgJ z?QL@9Tm&;CZ6|5t|8RbJR}tvvOXt-4JC_pIHZXEJAZQ3+DqkjtS$rpOO~}kHNyTJh zUm|kBjPW!TclJ*Nc z4Tcqqev!ft0`otC@YMQQ5XjJzX11M6ogwFpo=)u8!1M0TC=#~G#j>3oT~ai=EHN#d zr)V&WaM?;wrCy=sB+m<0ueP1_I5`ysNAC^w)-9BNMN7upQPv&m<=ULOi~v^;iGG9d zXjK6-JMzM3Y;?)u_X=PPw(9TCL)F`7@)j)}w zJo)|gw&-|vCvQL!;$+Y`0euNkB#R-m6^;m?J6{50=lA;7`F|woVn*si1i-@x$yptOccy4& z#s4*;@yjoR$V$icY3-8->PDX&i5qEs(Xd|CU^Pgq_jimYX#eF%`G*Lkn$wcORffsa zLeP+#f#f~E9=@c1CQNaZZ(Z?a^Oo7>2$n_guYKJ9qonJ=doe@jcUXa_V&5)z`Hz2F zV)~t0%$Kypm`|ZvKElhyS57LuL6WidyD8viH!=aif=$nIGNceJCj>TAvYI(y7$a82 zY%CjYR-Izog5<*7dWo2%pqhi=$J`$}iux$cdq)?!g|Ur%}OdhuRaZ6PK!i zl^bP<6-d`l^(cj|kIc-Kn?0s(zrRIixf0XmSz21oIoBM64i&CEn)<(cHDZuM*Pe4M zI{Y|~HIyD85{HUT=;evl&K+~$|NK+^;^ae06pfHNEZw)zsudVFZJni;(-vAZ0a^Tc zCiFzh;6gs43KO7>zY54lXIwZqUFm9=6?n5jLiF;y8<$1M#qX+FTg^6yC@$) z%rNvsp0Th}TUzlUgA2j|=9IRv0>P~TY<^l-)d&JG9WwFIuBC~eeGr>Da=(nDLPZ3} zZifmzp;ifJj8$EOPZx~L#4DE=iJDY>nU58K8}xIW8RtnLTq+%XrO))Kx#s{JOXO;E zCb6u_1-Hg9+$4SR7Q2{@R+K3F-ixIVY#-}|3lS~pu<1d3$PZwO2UPa2c5Jfx zl`{$z|I5F$S!Y6M8Y=JaNAhaS0Pev5BbSwZ(N69$!*p-yZzL+Ik=*#3ZYvSOzyK69 z=8=U6Cg5qXPp|498??s4Ee$yL7#LTtGafBtyuUrEO|2;(qZc9OC6N<&UUOvWxq(pg zP*oN$XvJ))#gEu>~tKfcdcvM^9y;G%e3iQLa94u5*@wV#HK zFIreTfLKSOgrIhBP#N4?4595D>9hht{aBatu;U^Fu3Si^^XdPOELsou9P^Q*)?Je3#4_L_k_{@S07 zAR3lGTF=#>kNVH{X)DuBl?vVQR{}Mj_si)}GmTDkFx%wE&NeS34s+#1rMeLpiE6VJ z=*MIUw3J>%|NNFtZ#b4o6>18I+8BNtVCERSF=|9%~bg=)s6CLPl!4z{D}Q1aq`;Jl-qf0>ceRXd^y2COr|4L z`yyb&!*aHi*)P6$gC4@Hw{xF-2YLR-B4W5^Igpx|C1OU&w8z&DY%IC@9%g%+g4>|R zo$us{4t2y%;Uy=T6P6yuSoPkE&f!a6YUDiF#Fk?rnzzo@=Zv42?zSSmAn3w})UGC31gR~y-Fx&mw=q}eZ z|M~pr%T9SDU=TkkN0-O1bJ34kbW?#W??7daWdkUcu$H;t+FkrILPuxFS(=Ja7m@Mp z1GI?Mus1ck6K)!QKLj_UFg(ms_LvgwGQ6;yXXrK3kKq`sIdkQ?UauMrJ`F@{=rd0P zex?Q6!%ulk4W}99z(Y_1Kc)AGx|*ie$FMi|``+g4045-1K%Vrp_uJoxH_wvYUGRbg zXW<=52BCwwB|G_GDG#2Ox-OaBTJb}WG0hbRjTPdKcObsN+Iod%C`($V9F9=-C@d>) zpp+gWE=J(?J_;=BSu##)x4O$Dl%~aaJ|ZS|FFHrui0Ufm0Hp%l>j{DGvcP&a(2#Zz zQ9PwchJ;*z0-ILz^R$?DFX?!lfy?INflTxkUFAp0g3C3>lB!XxpK!|IKpGqP_hO{% z#~RnjoVAE8q4%br2+)xvg2aoHeUG_xc)O{Ni69f#2})?$pV4g+Kz#$C=;Z3$d|RKb zX76Lo|518I^8fQP3<{gHp%T|R**97h+3*SZ9W5oMa2W9VK8S`B?ErKjWioe)b7Md~ zl-I!00YHg7uUsbhGanN@kuC!s%+?*UJ;`izW*dt(w){qi#KQ31*5lX*T?%?wKwL4oG|Cg0*0&Ex|#TH#UKWBzdKaj70~&H&CpRZ zBg@!x@+{l=f8D0hMjQrODRxQf?w}{WCl|F>kn)oyIjh^*B5A>p<93BJ-J4p3DM~t2 znuviycLaG=#f$`KuU$naQN4V`)%~6n!`B zSg4PS;a$v4dLFVd(w5V_NvPsz^Zv;7_7eAlEEkb`4 zcoM#NiG}miQAe8~UMooR&UHm-P#fVe!CpW}YAbfDJs7*3L;D%G_*uvB`e&0{JxB#lnA!!LCbYC%-eK>9N z!2gt4SUP$#TCSfF+X}HS63jahqQ#V?w3@10PKv!Nw_EBIfYodfD_M=Ax z6W0|}$-KR=!3vUYvzh{#3}X-kHX|+MR42)Tsh0vQjng@oT5+|XKw{cu06n#1AI~Eq zElf+Unlb^*U!G)AsIapjO2B~{u0tYq>Tqh{+*2(#@KIcGtVkum3^BFG!mG1m&wrk@ zYM~*h0`*w%Fkzzea-(69QMLi5+%^AgA?ra6Lis5}uXQG1D zOO4_jh(tI*6W^g(6&PYEf%i_j4MkUezCwBDFT|boNVF{WH<91&=gt#G1 zi!Zgz=+kvMr*Sjl)Obv@XaDJ(trew<|+5ESeCn0-(x-#e4oZxZ1xB|R%&?! z%Uns_5bA6|EIm*B2vwfl7DN($1x3l}-f9gor}N&PsIPTg73GMrVXJ(DI^nupiUKe& zuA%ePn8>k8xA;uZd5(bd^@7;ZRU%$-KyZ?r;=|ph8=*thr_-{@ggrzNE)BO1p|T86 z(Z@TzUC~uzFG5{Q3|h1YOQ8#=7Pzebfjhc~9W!y*oPZB-1y|LUAQD6^Qmk_J4OY19 zBbb^8nvWw#)FI_wW2^sAYGwsTvoa)m{JOhJyo=^WdfyM_KBv5@XHNY>&{HN)zwo{+ z1mlcuAb>AH`=LyddNZDFwHY)~V zCZMVta;Nryb?7+S^A6G!z6BR(qmO>GrZ+lJt`#_SI2~9Px>L-X0L% z@N5ttCoJ@TsFw*hfYTjSvM|{lOSL=0spWySEc%gzcY>xa^NL6mUA?r|ciS{vhV{~+ zmTE#&KSAL`+J~igQ+=W*`dD)(JhZ3yWl52Thq&K1vxu%d(K1!@Db$IXeQryO$9}gb zgUDLRJ$Mq7K}Lp;A=wb8%ObSm@x&Pai8MX*HVU=) zq{Y=OpAdcL$xLzA#~UhsYEw_v2gSJWU;4DOchtqs%7^;+Bi3-xs8XgC0IpJQ~s;a`40X+Xeh$bGRsFE69 ziX(k#n2lisi{T<1GwWN;z1s?c#Ikx;P~xtq-8X!g9q5D9tMeZ+XH&Is>AG)_0XA)x z)YWW_6s+HS`gS9ldEZ zf&QU~t$a#XboHKexM`1`?Fpj$l-COx8k}#?>aa94dfR9KeB8S->SLR_a6~zbc%Mzw z!wz=XB^I|xgz25tBjdJ@AUAd7Aea0}HO)XT)cE%$Q{QMi^K)%iDSHwXB7CH?xz6}( zVV0zU#3b7bJ(1q=^Byvhz`xYyD2~{G&aRlKEnSGcl`~V@Ersv6j=Qf$BROR*YKokP z=8Fyd{uzsbM()k3Tj*B60U8V$j_dEGU+uS@ldB;iY>77rWce%05PdtCbT%OXq)#FM zFb8r}eZP;8#{6C{G%5ZI%9{F9IO+|zy|frR+>?`4Rp#KY?~h)D%i566_NQ(ksK{Jt z(7gAorU{w>dBQ2^(aj5&uQFe|mPmK9zVct;#XaJ3>;0m5hmDW z9fxxTbw#KKWY!+#O+I54Tj+R_EKyk`(=6w_%^6&U#{@sI^`;w6o!>Aay zxx+GrB#+eRzt{xBI6xoTjbfo!WF~vL_gIYg)*znIK;qB=1!N%%&xNgq$E#t&0Z`w@ zU!mt>L}EMdpvOdti3kQDN0hrFrwGW_^IN&ZOL;a1>xG1EkHF%5CjWHFS|8WOu|2-C zXve+Rf1e^Yhfyi(rrnvfY|1Ny_@e0BWXY(Q)8q9>}|i;PHTht0GKSqukEDap<@ zaA4H;qhgD8paEK1SLd3>s;TT#Kg30#nR$equ{_vF3jpaEI5n@NY;liT#O4$kBQWAo zpIv;us!2v=9fm~~P>++*MIo>i73I#pmZwJy(c#utah&G#0xN>SYG@)pfHG%A7K5D3`DjjJgUx(SgeU#_?p z$vkI0{pjMr10_rhz#D=d{211BWGp!eionqX1wvqx_Kx9|ERrjyY0FXzd!#l{g?Q!T znh(xLH3KG8A2dax-rGN8GhIZ!gUel2fy28%#+ILC=^py$Gr3=iW|L9#u1vW%kv!dO4v6#<%cZ#s>3hT zWja7$TV|^Fyjvf&GI)tEZPSt{1nm$%l&Rka@2ix96mOj={Vq2wzaB`9i8(pkXT&U= zY8sf+9Ced!?I71nN0OgKy1Ic$KjNVXKMDL6Yuk(;MeC%i5M^8F|MzEC&Baq&iC?0H zA?f0=jT9K5;p|R1PbQvvoZk?GFO;pVdjh^rc6K9Le)sisi3Kmhjy!5fmpGCfVa9Kq zS8x;xqo2;NyqaMkb4HV5hQ+Pu*7Z1?4v|8C3)-F$vFXLYp(+^#U9fxHcV>9Dq^&={ z?8GNYaxS_(1}TMuxGki4a1R(;Izc&bJ`%l&IN|%lE$#7e-JiL9^BLQ`{3dl;+H&jy z0GNZusz#VTWt~VV-ZlbJP6!BSJaMe2dk>$4=hKwVucapThkK~ik)t{iqJAv z*kp9wJt;*G?~#~YjgN}p2CwganAlLrP>&g?SO+wIHR~cIWU3J#fmHB53s#AP_Dj!v zrmz?pUjthvHr5{L_xR;;Mk1?nGadyG8GoDGu3w;DxRA#;5^_VTn5b&80H)&eO5p6| z$oXL0V5YVRzvF!@Bur6{50Q2)6ebM>PdEK*m|MDpG;ewJQ<#ddAmiU3__9@o9|2~ERc}jCz&x$dR9xb{o+HM6_CRS+NE=Fu&Y*{ z%H!FquHI@@`}EV z?+Pbq+>Kz|(U$zi_@1LD9)jO38FA^~>qTOSG_7dO(eA3w=gT4v4HH8#8o;!4S)Xzn zyNjZ?9BVylX}D~z4P4a`Z-jnL7W&=Fw9Rl~wc{<*dZV;4+c$%IBTHaebgYn&=$DdC zLqLCv(C8v~o2=GrzyOE6C4B<4Mvm&MfQj@5y-RpO9Tk;v$g{~d0&-~>YTlrznl6e8 z)i@7fpwwCw>hlia2+cxnc@lT;2v`DSttN?kJcqE+`q+U_=TS~uQ9=L*J8HWUFfuX9 z6I<&!+`SOs2=>2tITFW1qdkq^!8S5lc@e&f)}!+eJ(T^o)qcrfaXuv>Xt@W?Crken zzMtxd2QzxlGj&9GG}VdheqmEL1`X%DG+wY%tvx)JY#_x^@sgVUF2%#suY5p(+}O*s zoY{X{Tf3@LGR+*CakBzOpLrGRY>*3cL8MyvNPVSDxufESXJDxM=7&P-*y+}DVqNIo=hc4Q$4hUmV_@Aw?N)>1lx;u@aA z9-A4_KTn8>vYkCqH0MOT!0O+1$mP6ZOnfK+{veZ`i1P2 zevax2>;R_K764xmz+cC}x0MyuMLwsNkGZH0q15&u11)famwDn{bwYvCjF*A;F{+Ez zRXYx!-1g4Nl<8%em8F0G2>PCmX%`KKC%XEip$9}6bhV07czuty9P9ljo}dT93Obma zIeg!UCdLzaQa%l}oE@W6I!tZwdo;NQ8(`T@LG|)WxW|h!9zVK>lKWTL-`rTd9Zddz z;CHOzTk*BGblBjVE|9c(Y6kxM#rIZ$I{;mr6I2EJ^qszU(zG5BCjcq2^$p_xM426~ zGIQV;M`;vkw~r^um%~;-lHS=${9^8c`dhlq-zAyll2`c2%)&OnYTNhrMs<)P?TxN>if@+Mt%w6|rYid{ zu7YH7qlYVR*z&KsJKDC$oPw=SNHJ!?JeJsa zWE={n#e>Gqwnn{LqB1*+{LaL{V555$6 zHV6Q2C1}L#njh@?nycON#0TY&dN#;Th3~2bfnl_xFTIc$GpK`WqKpgBk|*b|c`!rv zpp%EGAhMo-d8-v~vsQ)Bs{O_e!(%WQB6rZT96R9T72{jEd7Xci8%J@ML_7ImP( z!6#7$%01Af{{sacL2GBXmP)ZHH)31KvL~Oz)_}?hE3b~LtyoYe<*nPX$ocRH;vu1F zrU=OU=gztgva98Ze!^@x16^L!?f*c0A~Z^YIMaKcD7+_B*~#1#_QgQ;FwKRa5K6ic z@1u`%-?}=3s2LE>`!t|#WTy;a&>u(SqS*PJgeAy-&J9Ca^ zgQ2@97$@vG$K}lBt_J?ZvZRQN*BzJr0~v;+dT{V8osL&l0$aNymQl+# z*3aDBmz#vqark;v`1KdahOWopaaR3dk)TPx@GMNlPe%*3M^%sGnsR$FO|rVK`9-?c z1+lgiuKJ9cS9}Y$(<-!j3r1_Zc7jIU@^?0ATUdQmR?O$<4ft4l38_ro-Z8~Xu33sSa0~t9Dq?b;=qywPsyJ!H+qJTbjr8nhAw~)2E%CZ6zx3?iW|bFpQiiK z5M=(jng31&ET&cvXSz8{NvX0&GGD0+HGmt0tUo1sB@&A~4Ci{Gx98E>#FN0~*;9RY zX)DFwAJT));)cLZAD`JGAPup;qBnfYod^oCQ?*9ewgdZkG=t$mG1^564=_jbsn8fi z?Xc4?$t(x-sS|=-2o;kOzabcAiG-mF(s)4AKcO}BzG%11gN!ubHrWk{supxtZUGOn z=*h`0dm%Wr$4>f34ewKDhwFB9dF8Zm^Nf~@aA*FNC&K)CS*IK68zWF*-X6caF{S357BAssL@yn^fJhYWEX z*&q?GZ=J%-naRBBr=7~}(oz<>!|WCRA#$RcwM2K}Fz?hvW_RUO!a(ROIDi9Fh^eb2 zR5r_uNHQnIJK5M7sEv7br?qoJuSsQY7TQbW)PhOzGDuhM(C!Us(^?OcJYj61r^SAR zvs-$)e#F}sTpNGwSS9A8rhroPMie^eA8~QBSRvg`5I_gBs%f!_;0kw^i)X-Goht*M zn_K&Jx6E$?hS}zZf9!$>nF9ylbfqZ?BL&5D85$;2vqk+OKt`eKEatd_;=j21q>1AG z!IH;dU5wU=uV;wAccJld?XwY71nmrzG$&(ezLs4tg;X$^$t&_CK8Nxut42JcFeGik z`jRrYtcY@H@7bVNJ`wbM?sj_!0c#q0tNf;6t?X(ZC&rUZM-8S5mWzgPZFN3kh$J@7 z$$;wGP-1|#@uM+-piCeF(m`ZSzi4t+;P&aXF~$`soPnF}EiC@I=<2_5Ut?g}&WaN- zGG*)~3Vjv~F=JBjEN+Q7qzPuruzSW=Ejx;$#?PSSSDPFC*as=#kRL`T8%Z)!$8Tu2o zWp|!hrDQ18W-5bk3(g+y_XyzS7;&?g*FQSMXw6xS)nau!<&B&h)g?00jdmVI28WJR_!Hn)2aJd_uj7t6$4*AikRccT>m@(B zVs4SLD?w9Ncp)JwMMf*R1NbiS=twRzTlR9zr;AL`7LpK<2JO&ibdAbin1hb(!2#~t zf12H|=@hYTKnHi>^N9)4c?K__ zw^$l3=lFwfCoBruJZdArl7K84SL2x+*h8_*YiH@S7Q`+td4Gt9w-1Yo)(oEl3SY^D z`2LQmP3}nS`%KzI4IgI+AUH?Bu7o2pf=LEaKmZY)ZghaJRWd6A=ZO_gwKL};#{F7a zgO2OJ50nh0PAIXtyVu#k+JR(W0%rcSF(jktvWEla;oUlV_d4zHD;2+0sQUIynNb^5 zzoz>0`+XTbdm%?7CSC@WHLc+?AX3G*@d}64JYWlAX1rOVYzMw3(DDKaFDS3^tv1OA z|AzBwe`zQT$(3UjAeEa!k4E1L4&c}=F~TDYe51`)Pv;BnoxLN{fZTQuIf`JWl54Y< zK7X0T$uC|sHyV~|-S1mOk4~Xg(OIIN>CYOJxA!mkcpf(Vow?Twki$m~0SdCt4c{|W zOQw&YSe$qHQ?uRszT<{FwZ!gXvC-$kjj>&EObk`dBT=jL6oA?cBKz{iupmZFe^=$k z$K|CNhu}H7M5siN=vnMRGHZ_U-agFlSzCvFL(^joT-~HOKc4rch@LNX8Bd>5gK;0e zz8|0AHwt}Befa5e<&%YMwQu0yE!c#sSqVB?N7(3CFcfzto~B|jsm1)Q%M`Ii%q4HU zyz`i#iS~W^P*=-_L%rhrxUa$xUzdHyQ+LWR53<@q03iuHLl;347>Eo;wJ!bBejwAI zHu%jN>XfHM9n6iS2sS}_sNGkSzY#=J4X7ei-at4Fuw!$%QGW${k%F!w{k6}qyjlD< zI=33-CNf0AIp#hLjg4Dl?*VFzd?@}y>&7mvE*m;6< zQ?LcuirAHOJrhd0eGsmr%EVt%i37@7{2fK_N50BhDmU>3&JX!Yf0sjv2Ga>_*-vB$ zvP(CGhY7ZPChBr0q2bG6x_ig@`^&sCx+eA~cNjZB2JO2C_jM#G-(bXiBqxnuyGs2`mm$)BPk6Qsx6q3x{h{q9w38``I~QXHi`TnifB5 zNNrI(egL!HPTY?8BGRpbE3p7Gh*NH06sd20Z$16m z7lULTU%^zBVkyL!9(b7^AA;}it4SWnm#7M3dWFFcxir=k{O7h5Zn0?wKGht&`7449 zo0L@ob)3quR$W(MpY_iTD;QyVRqsNJpzxOcgK`@!Gz$D9+o$rto+tE~B5I6}5Jg~@ z6?wLWL&^ceiK{SjK4oR61@)}I8+TD9cPFYJjR-%(08=YwprFPqbZ?2VZbzVrM{E@r zCvNxyw|+&DX_?aoIId&;;h$o5^#kb-C6G)$Ob%fXFN89x{So?a7ZjnbTw?jl1?2^} z_mji3f9fc*2(MzERS@FGJn*_VkS}KKU-j$2hj54K3T$hI6`$M&w!dscY=F$-R%T|= z4F-q|Q}&F!;9?f9X6RU1L@tBmqDRF=1d4#Gq!ubg@Nzo{uN4i2`+E|Eanc_{rOjH{ zB$#IbB&pL2o@$JwRhs)B{spTufd9iTg~n5=jJJnb6-MY5zuzpAT2qI5*AO>1Q-$5m z@q<_-`88vitWlv&6edcYp}v5Kl#vXzd$1S|g$CIOfXi}fQC?5EtI+M0y1WcEKJhTW zG)AcB!iYrxjG!q6XhMS@TDh!Q9J^iXX!%LccA86vd#OO5zI`evJ2`JxADk1+z#&J- zj{4qE6~V~de}iBWjEd}f1rHys=1g~ja#bvFCDef*<6KH?M=X`Wn-XBfFaF?t=t_>9 zR|(}|kb55HRv`%ngqSS5v40Nqf=wVX%}2^JGfW3!dp}HG*D@m(LC?UWn^m~o5e-;D=zUR8cc9xY{`z*MsgGWY)i z1QE<%Zd4jTIhqC*ms?P9uW{J^qT=LDv-Y1@O!ea8m&2`0TEBlQDtYJgdhv<^7$9nX z7I(shmM#s~S0YE&fEJD=uuUNkz74{$j`JP%W(za4KgBQD~z; zer~^|cao0pLTUT%RA`BX9{EGL4+`+6U%Oo8S`EC`;XwC_aq%k@39ez>9Ga0v_TM~# zB23iqp?(db_cE=)pv`~v4gyL~OY@-jc4t{n+*W8%r|a$KuoE(5Ws6_kWN8~O-9?Cg zahYIg(Oc^Q2CSZKW2%6qc}6fvK1jsltgs+O5|xQfAeN@~T9F16V6)6&{2N^b!EBH> zVj{WCbwy_k2Bd|i9pc?P&iPqg5Fj_Hkm1^tccoF$$hy(e)e{4XG>BppG%Y`4*PEQV zu*MB>>Pnb8Ymd2CWgLm2?UWpwGBjj#!1J|{-vJ};ToEhUE4%!^TR@hWhrqw8wR*Y$3oa z2oB0@ZArMAD4QGC&jG--C?X;*;x+@-OwJ!z&3IDNv{kDsz-03Y+n+cW@uRv<6d;M& zbXMg%719=>Kb$B3%xq$y2%n;4_%D7cY7p>*X6B4v!+X__dk8m0%ETFY^*5V9@^h0X z6Bv4zoSBB8W;wGx$&?rtzN9tC3*%|Rz-p!4JkcjbwhI;@Y(#%;q+dNVlIb@!0G zxItk@BNj%CX_X^-nashO5Yz?}jhT4ss;FtA!-UmL?!6E?*Ww%Elf~%7Arzj~OuZK? zTpncj{U1AkKjZLRXo#bu`!G<)lADGKl$DmM<|&U{is^ZId@$g>g`Dsi@S|bp=$G6Z zYWrTPrc{k-;~`)W`eB?a&V}7CseE)^Vp$T$n$AOZES$nFDV#|spIoXX<_iGtazsZN z)MmCK5%*A(SVE5PnvKjTnZFL~&nMxZq#QZ7LYGj4xa}Caz~Vy#i>f7`&D04`6C(EX zPml!ztUrvi<+%ic_&0NW3?#kElt@D2=f09Luy?B=r^caZ0S(5gEcXPB*xmDRR4{eZ zN|f-|Efuam4SCVyX>436$=&C`PT9qY%Buf7%m-(F|KJI=TB~3wf^u}v=mEipC)!k! zfYmwBo8kuw!7W?A9qevfg=n`1O=J`!(C3`S9Pngl#lZVdk(Q6IaX0Kmtw}3{#abkA+kC0h9=}1>?ID{ zXee>KU)FiS^icZq16(qDONt9TcKTeEuOLZ{Ry^61|9J~q`qPO#({Y2h9kHHH3#zEx-dY3m`X zH<1SeiiGHcCNtAiUkI(*}*>Yo5DX%cS-1 zx&|m@4+7?|QgiAi7DXw1pi)+t7o2YvU4mk=HdNDA>TC>wqO!*?GN;g zE$WzlJj6C)d8KYG!}2F@cJ{F^#Z;SK%E2Q-E@hB^A^RjYC@RIBBjJO;cy1Uyh_Ge9 z+1{dF7i5Y=_+oMRwQ@D9NtZI?pt}P<35W`m>~cH4llL!_@NF9|c`R37H>O28NYz6w5yMRJMvFdzaj!(FpaERr!(h=>`zje(owz_i`q}&R%um8(7d&On zAy120b0lnFHB?Xw0OsalKAZfsq1(txh9SEN{7LN6lD@*MQG#yD(8H}F)Jk6GvrsQq z3*WJG8uYo%g!{}i0I6t;q+^3~-)|@?uYcqD z`Qn1G>V~PTH~YILsw~6Gu>z^uJC_z-zLdO(7GjzBXnRA7j8%&iSH#d>v6P++ zAt@kWG8gu1rQ%MN#Nyk*Dhm%G6&lfq7*y+!ylOGAThhqv{arf+GID;gi&7^95YoP! z9bF4c7s@o`Sgd6KsKQs|k2sUJ0V2tlpR!XlIDDf65{EXjONE}DH+l1O3-$Ih%Yol+ z3iqL|wU*Fo$FqA0z5+?va=oa1(HKpajNMp=`b<^(?NxPLQ@+C&hS{IjI;X(Y7e-+3 zh_9Y$mLfR?=XC|71y@!f4S!QGg`kF#z>&>nd&J2_wVT~wP8?c!=PIuVeC1?QNCCFnmGJaJjI<+k=2RgZ z?}wGKGJWRcohV6Ctt^&J{3xU2Q#yq*fAA3;506!fu{~iSf)@Y<$c89vXQ(Ca z{Txh}Kcf`&U8DK&Bm7B(L0codY;yTWVk+H=rVG1+ji{+ke_I0TwSb!ZDw(e9yxo_D zHwOZX9poxx@NJ;VrmST2rhWtd&fqEWZU#Xy z4S6STVYpK-J*$d(=9J1YU-qhz<_Bv^r*wn>AcVK#ad6SGc9?&JH0|}@^_ikfV3)-{T^^=al0MLb) z0*g^CycC;{beepKmvNJ|an1Em2AR-AhRy*<9YRHI4gCk z3MGeWVkKFGCfMimLCI8VE{}*>3_RmX7&K6=f5U@+R)z#8R%oadA#-@OgbXk)UwBCE zv0>o_LM@ZSvr6NI&ho@>{)c>FOS0+J`?^YW0!Fs%B6$A!^3vgl6R#>rR z)NtX+&LLHsQD{t2?(o#cT)O0`obB=wh&94SAAXGbKV<&p*GNG-aFnYuU-xnLrbUpA zn9?m}Yv%O|B49t6IZpF*Ii$O%&*!ZqDboh*T!ZBE;PwwZjj8rcIG9lV({s(G2?})+ z{*X_%YMD$2gWki}!vOht)`z9?A-My^kZud3-v5(qjK;8y}s)wK*M)nxVQP(-cx_sJ9Nv z#9TBDd+K)lU+c=)7R0{{rRF^lK_c78cJtl08itIYkI6oVZan{dAf6^S-=_gQ0Lg8P zJZq`V)C8A=vAqD48O%02IwOj@iZaM+;v~!Q&|O!FPHG7C6o!F3ZUa_nipLvyIZpTZ zJ_Cgi06=hKMQLk;QT?!mQ-|=wn-lkkf}))9b_vFq5fW|M@wG~%$fqzvNC<+VhppxG zrA(+QNU|gF{lSw{jFd>eU$(J!13R3`>e%zM@9F=LQyeY&Y-yv>-~ddv3LYM!W#a_> z@x6b}<*)z=#G!$i>Jvbs=cIwzU4J}nfLlBep{!Vwr|W)^m*m&{?8YDJ7@*?K3lXLd z>b4s!66oa~X2@e<;ettRdoUJ4Mkg2ZJ2q~d{ZEYM1N$PCx! zU{&hwK(4K1;eQ*6C-tB)yJar2a>6Fm-7Y^S zvz@wvw0cJ2lF61zM+8+2Dsl!ne+NjCj7EzS{%(?~ikOZ##?F#A*>%nLqn}cD`M%rD z>c4Pv-p3!y`}h^+{7t#bl_*h+U_PK#4mI12?S`)dUPgy|exx6#*AC}rwy@LULm5sG zn@he837*E0FHQWK!B-DS$Usto1LMkVHZ7~NKjz2-fl&iiH1Tz+Q#UhlAvYb2hia9- z7Vv7DieBM{=UA`$Lg0`UiGNclRdAEM99M9fNcwAinIoGGYW5;Yy;T>S!Qj^LeX8w% z?gg8;D$guk$cHK`*Mo3Z=doaVp6K06DD2;r9@z|L>_vC0-N+qrO|38o^u7e2zUM;(Lk-ZF&!qJ0U!hWK44 zlu$ueWeTXyS@DDEJTNeJrJy30;XbSY9hC5u$izsik!_H&^31uI9r4dR^V;6~20^$w z8b3>C;PKYLaYz2QvDml$&)!b3eX@dnTC)0}BCh;iC6&z5#@lMCZic5kruk}I;Sf0T z04qS$ztO>3hgc*+DkmECi#_t|q5+K`9biGLf|+vWEN36Hnw^HCN7+dwvZ?ixQ{S#N5XMupfz4 zrCO5HF!Sx2g5~XW{rcb;)B6VXTdCl5=OlI5p^-Fq{_$F(Hm*d`Ps8-X+pY>zU~p+! zEF&%UAx`CH6=lHWhlcJXg`wj^3?1l2YjEvL;EBs_;>9Oo3SXikyF={vhm-5KRMoBF zOAKEgCy?=-5|^QC-i4PYW#1P4!jm@^O{?LyPuhPXd@CuU{ZV{!N+f%#va~()ePn;& z2xA2B0;X#pSz;|g+lW25?8OgP0)zetLck-2^BC6bzeF_|K46D(j9-KWjnM}=S5*OZ zoeH8`MO;3@jMIr_OC!mcwUR#-rUvxd?&3RG5XQun3;82*NNXSIVuDnmo~1z@0J-sqb7~4#fDr zSMh~j*de{>ho$5#8hyta7W;GVC&_jv?m`~#LG?0G0TQ9|@}ayH$eFQY&O*iA$B1t5 zAqG?7l*>^)=wl>Zi@ayaAh?ma;a<7+i1^^koj)%GV2*LnGZdQ1?YJ=+oVv}Ty2`bN ziM8X{@4&TNw`=obWHxyJ6{=<4rmz z8QAb~Kat5Pzv+6&9uiFrA1I^AFV`(xY}XEPyZ+GMpud~AVCxBca#dG2A+Bxl6iz}8 zjV?R71p(x)lTQ(=+A1@wxaakb9f89W7-{#CPV-%Z)5p8a8g!CGpWU@aWgT$EtgU&ae7t$#B%O_g!8xMTyN6||29x%1x{XSl%3JjCuGzw z^fY!G#LnTaYade^{xXZEYvV!(3-qn8K4I_aU{BsFWow?Taa2Z2-mHb@N~jM?AkFa4 z+1r$J%TDhkGXDnc=&JjkqfgoXFtI!~3Pmch*aE{n+5utWA2>G*V!T$@k|rC?Unm31 z(mJ!i5WbNahryZ?ZmW<=adLFVrp?e2QYWD~zN)FS=_SqzwPeSq3JzJV7gbm#<0Ge% zYy8$tT*7;(7=Pe~_^_H$W za&7f-5)#U55l_U0OlNJDQmK0tzVRVP!nsDKZs1;e{S|gzW#OH^PXzgstdNp?+MpF> zTl5#>>40h$YTAB#LP^n#TQ=u=Xw_7V1(c%2?rHvdR;nKz7`x`m2TH;8myS*zpN#Ss zRb?(aRrk1fDlZ6b^Se-X!mG9ef>m;8XpUo4sRzwE(PibF8rW@FN;q(9+FMR?f?Kqn z-HzJxResglI%|PqB}lGx0&hsgFJN7(N#`)Ez?rX!9A~@zdX6+$@!r)PpaE06V5R2+ zA@4$MB|NSF(@~3YQG6LMgIX#gA-Z*|`4*|6ur&Qc!W-%!X{sDnr!uK#wPe!=N^Gg; zY?4am*EX!8a`0X%uPH^TTsE_w!v96NXV*L3jf7<@huO+Saa1rOr5sZj(h8Iw*!~?w z^J1YG^Y-2iYz1S`czg=jB#()b2IK%DID(%_Ais4bUa<<2Tw)UhFuYR9Ldks9U;pus z7I_-%-hR;wBXkjc`p#`RJg<0JejNsN!Zgo@bk_7q5)y%fS}eN{Q+>S7sLr~zQ^KRQ z9uU{C#eJF-W^MxihgAtR^8-D){ zUVKw;kv;zMri}c8@`q3+k|31Fpdm`Vg65wJS2_awE(Z@=piL8)(=Wjy=S(}ohmQ#a z5H51JiD5{I3Cfdfp`li(U12ZI0iYU;AW>A#c*DCISaz_ZRwr*0LHWCkR&TDFf*7?d z3cz=xtIIXc#usrnOQ`ub1ds!9!fp?4eO_*4>R~c#MO%u<`8!b#S?ujbIgGeh$7g$& z-Xvje%|Yj*A}O48O4e0et3RrF(d@ziJifdHv-9Rd*W?xBY>j$zim zzw>>B5}dU?X0_g8%Q^X+e8*!i=o6^FTsiI*3b>SxIN#7~-pOe{UdkztqF{U!8!?0e zj*lIWO!Me0D@y0Yo0R{&3SHYA*9gyyAzdH9zwc3NH|kU};gKC1PXa%WFPp)+2^Z&` zWLXyAq6=y3kRKxls0iZvrOkFPj0_@qC~H;)z(ZlQcKCP5)`*c~S2XIJY3urKsxTI> zPJI{;gISeZn8X;Ynipc3ejQNKvLJI4j^)eyRy5@b^QSjI7R4%|EXH);)Dkdu#k+zN z(13#bTNa}*&QZ6!X%S$E#%Ggiz4s=B{$VWFb6-KK4%mrC?B7(^EPo+sHP>K=Swi#B zUV2Q#l-#*G$O)rCWMIv#AMkWDE`*_etmsiWe^;f=m0~ejAG>+46GdHMn9W`)eg|QJ zcNf4KLJWvoEkGBmMbE-D7+nd z&Nh1bEJ}N+pXLvcLHbW8vUHK z&nwpYfFaGlIZUd7KW+;l+xbjDu7y(Dkd{P~@5M9!kdrR>sDsj%xtM$sqGI_^s{8d9 zbe}$*DoYcbSg|4!Bc=>{{l9glEX)1mwqHPYlB0`mmJgXO!N@Qq*w$#f9O@WD1L$4g zEJAxWrmG*SLOuoH0O%HaOb57u#&VfAe|uvCN7GeR7SIbl%gGhtEKOip6H()1aVx84 zK!nZP7MaZ0mU=vrUq&Xl+QwuI?1+hKmhvA7wF!5gN*OK~iq8SIsdyC%cyB|RBt&Jk z>d@>?+{4Yij5qJAGGkgK8EzZzJcowPRB$m2)0(4q6bks^7+-G8+1K>*0 z|LBX52MnY=x78QHpxZ&G0!jk{Huc4x=ltO!3o>ft`P(gbul^qA8@d0+Q^5Mx1Q1HE zV;b^+bG^@pGAsB}J9O{v!h@2%yvORFgdpaiD}fPUD?n z;eF}DAbOS)J-fJGb8cG4vh2{?czvx*?a8NH-l}UlDRz1#BAI*%vzA9q6oDk8gD_1W z*c|SHBLlW!ShgA8T8w8Z>YK-huV2WG1n>Bkf-fzquZz0`q5S%WuCNE*;K56eXlQbA z>xedjJbOoA8D+Vx7xB&g?;G|yNp*7n-EQrxz6VezBuTtAn5@MWheL&=Gi~B&dtw}_tl_YNl zF%Z!+i4FS0u!=r0odS=Io>1AWG2M?A3=}xUTi-ivrO-=IfmZ>nU+#gJL9=+CxKXJ= zyd#G8hbM*7Ky0`+S9{Xi#>vht`0U`qr}%{5YfZpjNRGcRuB>;3P9gFX0Eti-qO9r( z=tS`LoO(|R8ti7Vw(uc9S_Y>=iS=fNAduX4JWy=gL_c3@@NUHo;$$L3;o!7Q)+Fg` zJfzF&%u$oUi21lKnY|St2kk)bfrl1!Qp4`+HLP%lahM)g@m#~WK(7#}JJc#`BzG{5 z0NnVv#_W2W?Uai(UzBXss^=r$$ee{TV2feJ^_Pr$3=$&EGOONAonq@);)=pzr(6G% zH@o}#8)?6@hR^sqC7yE>;qT3K+*?~Di3eRP^#>YLg}-9$$Zn)P|5V3bqYURiq%_}1 z{KF?wzwTCy4g~ksdOny(%ZK_e{^ZR~e^gc&IE}dGf%PE3CD!DopG$1pBbFGa0|frz znp|W*evmc{)lr~=6FbaT+JL*5T2oJ?xy$Z|_LK&=Ls8^Mq|et?k^f6V9nWulNR zSUkZ(O#e4>6`X`R3bT!Q`4vDK6{R-Nk{DRz_502_X`Gb}ab&YFp%Q;8Agt>0WK7c4QVp9ewfy#| zIZklFeg%dO*UHF)_6~MB*JQW|G?24h4iYEglAP=f5m2iZ*QN1BZMyTYamtw(bzj1@ z7!K!6NCP2@`;I0`vBN$ix6dH%87F8=)0tNGEZq&YWP|Pb~1D_^?NBM8s z5&)Z#EwUstU2H)>Cl z434})CObB?$%-Jrn<#?m#iY%&-LOhxm*!kJ=Sscw3F&X@{_>)V^ZbDi*E+9BceQW~ z#nr7r1mp1jUaq(OXY{sGl$0HeQk-opnF79+amv+Q!56M|I)cJ1f!XNg%7Ja%SXxw5 zV!CXqWFw#0Hz=O#v*?4-W^Xq-d^Qf;hC4^biO$92B?Yk@YzEnr>4 zIbslrF~tg$v~&1-P|>(&+X;RK4>bwZ<1*YSg#*xOzH~UQz#;p4_4OO|rrp?p;nJAj zRp{W0pP{fIm7!!dZjs;gt~68=koizKTH?6>s^rZ)*rTrKD!NTfjMQjj{TI}y>fN+G zEn^KGl1CE+?5+lcT7zS?0H=!7!5xqTh>y2y*_oi&uSrQ0e#W^|jhXxi6gLVgFqh}5 z!4Cl~-Uwvi1)b+&cKD!a?9b(K+#NilF*ohpLMtnzSr8OV-Vifa0+;Lz_0x%Dx$osz z^I}Yu(XW&lz0^(*cqf}sL*`7|-ch$B-Jv-7Q?%leT;+a`OiejIN(%aes_qUfZX`1T z3XEGz0rGH>+%HnnZH5h19O0OeeBPOjC-maaOsB4w(oJ)+Mu(EV474#{cZ4QN?A?ce|D7H(d7Rv+>I0b#{cq!k-+B@Z#&)|ge-wW5BM7#|zZVKWAi-63dD{DZ~DAFMN zQZf;lkS*%>{VO#LdmR9qKLEgMMx(ml*)tgXp;P>v?I_0-EhMn;U<$MlA}m8-3$ku` zYyuDM zPPD0Y$Ydx>^s^x{Bpx3BiZp|VGN6=QDdi#D>OmAMd2oK|Qk7n;t9OKJC58D;v&tab;b7?K4>tB|bWY_05`n@)4~`oC^y>@T zT_Yg|l;Xd$efWkGIu6M)%vt@^Xz}N*O$foz6FT-VFzb&#Cii7^B~#^ju0X+Z_?kn1 zG~GLU9OdoFGb(^i8_<4()9OlsIw4qa@vT2Z;)@p^PP_Q)diu|G!+p8Iezdz7)Bj4R zc>5Wm#>M;&weLF`nsV^`*oc)Z9a5veS`OwM76+vaA3zK73Ms?rdCxstdZC{YEBckf z{IK1C0bz`CODNpnLej*z9Th9SjLC+!_9e%*OUBgIy_}-2CoicSHI}}AzYu)up>y$> ziz9sLyxBQOa;PX-khQw?y+-qH8TV2R=rlM!Wzp=HkuZ7Hk6$<9e*7{W_Nt9lp5~C9 zR~iv4`sbgy?PCD>14&esI?zC_=5sQG**&UQO0${CYfXFum!(TG(hYSr*-u|n&ty97 zVKH(TW4W`*ipE5f3igPfV%jQuRM<9GZ}TU~TPKENO;r&3VQ;~(MiSo|IJ5Ocazss0 zW9PjBj32|I*7Xuen0?bi^EquKuq2J05x9bGi$-Tn=0;o?Y`XFqITX58Tpt3OrdY{u zyrDr7x`J|glUn55LbIsXIbdJ!ux35cU3XtcCE!X}-w)!}khxaEG=RQj}!{ z(RTB4 z6ZLZJH86ey1(Mq~VlBr^predpxxB3!0H}+fZeWZNnqw`ffLe5{!-UzfczbjKPNbZ% zuQx%bFP;e1zauT%RNNPA^9GzhUwKQ(AK^&veTpT0lPGpfRro3Rz~HWk0P)(r5@&Kt zPlW2NE(V$y-An{Z!{jCy3tTCvfFAY^DF>qQo+6h&*iPcI_InMlOh_ax@pj?Nr?G+w z=CJjo&ca3wFTy?1omko-XL4`AkZB5iQ1>;q{#{e`-OMmx%(?JWQLx_3-tNoSYtN$k zS1sOZdDeyke z(s0L&lh;NId^7KrSV2Y@0S?f84x5HjO2JzxWgv^?$N0S>g9`QcF*!j)?=k8ow2J|Z z1P)OiE=0R~`NFw`{N|x-rpL@5ic_JtYg%iPndy;j?1dD<(~f=r7-@JnWc3El`FBm!!QA4 z(L9vrYZSBno}ZqmtJ)?c)Z=r!S2ZrZH$QH_ z+5?Ll-Yk$qs!bJrF@YWsNYd;U6b`e3=S-y!hp<<_*g&~(z;Juwcrv@&zv#kzHtZFW z?RBhCEn?P~fe$4xZe{0mBchmI_~b~MKU(UE6ju^@5aK`aqw{-pK*?^NSPcq?J^9h! zmQLc=X!keuEM6w|z9#@@6xN&vd^ZW711Jisb>oXej__%K_b${Z47pyZf1sz^Q?9~- zhE&wu2kLYQw$EN?p?f&#xNo!U;#aS5cq}xCk;7Ju8^VW0_e2Q_uoF7;%`&cj@ld7& zbFYihBuyrMk=r~(MQ9bV=4wco`<;34(-=tv@J_=k4q%B3Pu)@uom15avL{eUDqvHS-0TfiK~IQMEO`Rwt1W(@gH!E{9epEAK$|xEd=z0lY&Ty9Ja2||!*2p}2*}cV%b1jrsQ_Me*)o53q z$s_WN+0dmrbOoN8AIi$V0q}Jhtkg6o zi{j_IDO}H3V7Gtlda^-Y25}Wk{VQigm-ZyEM%c6yO z^%h*3dLfppUC~)l068)E(B&rGAAYgAijFA*J0cKk#((s5$20|-J0CkT@!>JzQGO=v=L)_In2NK+AZ~f;tWIAMrxmxv_b?yNOG}O@Bc2Vq(r4Ph{Kq&` z$op?IKKu9rA<@Dv+${acm6y9d1#{kmE(noNVkx%!#6fn{yZ5Haix95Z@RmF~sD(e& zDsZVgkg|PBfV`djWx2wfGjr+c5LV}N@IIiez<)UtR8liJO{+}}#N2FS=se=B`h(#x z6v@~fX~Y6*x8CHCD2N}uZ}aJRzj28l6zOB}qPkqu>&%(F<)xJ9yjw@=xy^}eWi?!( zX!9WOmeuhFw;vv4Y+T*4h{VjZ!)+mAP(D2ypTG}ccfPO{8-%?pMMmel>y7C;^12>Y zT$${plb(_0Ks?3p#ytL3V#AKc09@o}o1?i;;8%&cuwz7Le*_}o7T#Phe1^(nCh{zvQ}F^b8uyRzTCY!4~!-9S)`wk6^HgjNX(LrtIGTFRVvDKjOM3C zp_c?J2;Mmg%3cepDESCx;Y{bykRm2;!K7I2XDVqmeW35w;)#xQ8eY%X4$Vu&0=tne zS>aTS@eiX(Rt=l-{ewk1>>fAz6@Vjn-%-WGZd_T11$&_RI2UyekCVOcVdHjoBt7Rs z7d=iGmaa$b11Rc&5O=u{!m=Qub`gM_&a%g>)2WBg8=Cx73!}v(qtZd1Ooaz86d7t8 zZsEpPlSjYrJ8{*G@}z+Xk<@p2t`2NcnH>#!o!=%Q!0C74ha7;*A@Gv5bi8@>=w)?p zcs3GJF$v z-UNAY>av)vgP?H)gEU0?u0!`*!tovF4eK{2eSvLc3e*y2Hojm|r<_FzG4zm??Qqyl z<~rGUBn1@aG3QQ{Zf@@Lp7W~whV^XyvDMuzP6@?8mwM-q_?qzX2$kFY0e0e5`@@_k zDt;`hPhq?6XB5Ii>%gak9=};@+B|zmduia92G!Se7bjZ^Rel0Q>DAP2*5#ycb5qQ_ z!g+@6V-{3b0o14^#yw-zGpRrx%|l0^m<^8I?)qC>#0eN+=t?7vZ5!Ra_`_dti!A#(gbVb|KRz-@Zzig^((HeQxfOJqS`2w(t_4t6BqkHc*N&m#5y4X= zA7I{xPdd~IP2UA$fo^g-E#!66&Q7bI|+Q|E?=*L-xfBs~>3b86TV| zkc!_4kHjF_iCH9jB3-e{A$t7N#v}ndN35W4qvNVJ=FoTRj46M9iXMd-l7>~_>vyp2 zazYDtP}N|vw>++JM%;w?6nIdt_#`4+*UvZm4`C$7F^E)b=w zatbnjB-2H$0zHsv{*nt2KomxMCpSyQ$s-k7%$6wM_p0=R;$7 znl?^U`eNz_>AYpzgE&8vnA8|_8d&tK!XVlEx^1U(3ZUc*T7hF0Z6;zR4A!A=A!c@v z-)Kn1T!JW!2HYX6DqRD9m_ruWX)m>0jf9S_pS_QI-jBo=^6RfEBEKM0B8V^*uakVc=Oz6IE5N{4Hhc^x-C#>v!66w0j}LykeS#;l~vgtsQz zx~U-#SeF#j@R~E)bYTd7a}wTuEsJbWoVf%h!WW7_mSSm?dzpN=`wpEhB5TVmya6gi zAT|N&^UG8h362e|)ea7iGVF5Si&)?hWxv^J|^+2lnWrC5YDdo2Il+ieaM z+^r=v|NSZ|-G$8sX^7$;DGE|Ds5)@P(?S+Mn2w2k9N=))kV|Fp=qN89T*S(Hbv=B zGZ_zzg>pjQ0rgE4)bnq+h%QWHAK4QO!4Q+Eu<~WLw7!Ed)qj(Y`71=kx6oH53Q(1r zWhqcB*xoBj?GC)8#m-?PRs=C^(zFfnelY@3=DwZnplB;FMu4qOM?jfR%_L27Czvli z`HwI78dP$cVN*b+>v0aJNjtFzcCds4083AF*$~f$%Um%I&NNGM1eqcKY%% zL+x@9#B}ey31+r7(C8Qd7qjs7Z++uswVs(4#Fv4?FU5>UeLji?Jmo_5xf1H@c2$*( z*L=)U!P5aMPA%|1C*yBH18^W4yBT-Lrm$x}xiPm?zU%yPl!C`4r63~h$dV?~-t|E8 z>_tG_sZ?TjJqsgt(a+0Uh@_x^CkM3hcQi;hdx+GvJ>tCAKiza0!XP@Op0EmBTPtW| zgF&v9Qy}hX!*{CAy(nS*XAzw}wh3AQu^eaakame_7rP@F&|aL21NNrDP} zE6Vmxsy!|1fY@&qNM}RZjk*G(v&HDQa&_@@1r;d$q&F*ahQJCy3B!`pjH6$Yz0{+t z+u|n)5ZL&XaowQQK|=$O*5m`;C2y93vl@i45JR5UFrD=H2D+$b z_|Mhv!If~>cUdJX=i6~poDecU}r680y$8#il+ z`J^8+=S~53tQKZJL39~5H6>RXf8JmjW;GK+stA|hNasmSD!<;;*j5ZuZV=b=`x;i& z)#dT*hFXD*{Q{9>C{4({wu_uJj5*}5v)h2gR^l!l3V|68QX%&n6nAIozZxmVR&PT~ z@`=P$E}dabx~{=PT*bypvDw`nQqGYPOKJWW&a^jU{o1$V)CbA&`*dAGm`H~*HU(E{ zA)<83fuX1e*tLY}qNnIF(QzhaJkxUi#!`8Mh&7~a1{ep`@`>AZX$QzjmHR)zFWOCj z8vLt;JHA%UuNz}8S~+XkT2nz{5*SlMq2$%LxE(07D_dMWZ6gIzSFG{$i%oO6!%r@f znPxH|L24Z$XY;JiH4MBXyylM|#%D})(8a3k|Ak#m=Wl4lLzH1DP?w^!RW|C8!K-%j z24rF`Npk&?$I<#vlIo6?77)lrs;;=XKy*0g$bgSNpIiaPw$p!T_4aGP_fOeeTXb+b zPY#*go?$E6PTyuX(A_)7K;dCD2PHANw^Tc&3~xp7yhf)chU3@n=uMPVI&V@V7_}!3+OzE9PR&U__~o!` zs?T(^ndCZAUB!+95q}xx+2rx}q1AyuB>O_ie*f~4IqjO2QJlW1@Ad<+-e5b+7;7fc zx5mjq!~;TD~*s*Bw)tuOS^|rrAb`4l$obnyhz8wO#YcY-yejykgV(y zwpg*aNaREw&|;&%XIUE1%3c#$ckF(tTC^t!O}qEX!yIlR#WDjwHabqJ*AmhI61)MPaQBsXFZqXcqy1H$%_-k5+`i!KP~SgM zD>rO>wpeqfkwaTVY9orw5e7P+LYsM)Y;EY=649=-%(Swb^D0^gPX;?m2bb$_3Jlq; z9k4nkpf!x25?yfQvJrYyNfzmd2<0sKLHx3HMR>>8L#O9wL)VLv1yh8g9aGP&7Vgwf zzOU49PH6Fi!*?*h1)X_H2E=LmyS-CxRgXbhc7h0_Vl1Mk`+I*bNZp=>MRCnQQ1Yq4 zaPPkjKnTB6bnhHhL>UtiLQuy%G1%}&Jh81IqOwdojz5LQ_g3oh>YeEeX45auk~7FY z2=7S#!vrHku-Z>Q9Nq`vhHdNm^nMYZnK>0`WaPDqKj=kcC;i+x(5f&lnD;G#1BKg z_|p|nh-rFHgAqs{pQi5#TPrwXg|988;3BO}p#AK|%em zoSy_Te0+!TLm}A0)Wf>UcG(0uk}@Vn6k5BZR;>>gHXqB_l|MCGZSJIJtrMkArjnZB z%05;fq^HB;$}&?95u@+Lce;kt-VAYk0;nR#mN2`;913x23B zXkA->1I}zGVRGo*^I|^!PH;)(HLnmfq&R>~WjL5d7I^|gWoR=cA#o%sznj*v4~d11 z5Wl0kih4hu4kwO_`UFK&C~I%ddQBpz92PPhlS;5~E%v-xAq())T+z!_J0$@izq@LT zZ{aBBO#gMcy#{4a{2rbn+_|!mYhY8L)qHanrsr%(kdYS*xoSnVmMex?J{8XD#FboO zwK@XloWG)90y?iF2JrwXfZIwckA{42>>@5QaJgtkDR@(+kXCpz4R7ne9j_kUH&V6W z`~kC_n{aVF83D@CB8;7SDrp;jc2)A2DAY8rBreRy>p`iq=~B|SGOc!8%2 znTwkT<@RW%sTqq9mcH>e^gBjHloZeuchw|w%xS55vW2lntFY{|LGyyC4GAM*Q^s?0 zr-hQ+!`Ue|5A!-!@f&42^@==rGFNUk{FHN~y)^}~^nnIT9pl+jM`aGpa6*x4Xojb~ z0!>Ygqzx{Hcup2xDI<61PNGjf{UMA5D+@DH&YOa7og54y!hPo-bX0GfcJos*|M#B) zXr7t#Rdk zWGWvL?T&}&cn_$olRFtooebv94=rKcgKUXv;Sc4^i;XoNk>9sCynukFzaovSR=7P= z6H$j)E*>~$S0gOlO@~rhxJv}}YI)ThAKnWM7Nmw7M_^;M%Wj!v^n|+5)jB!A{%d7n zmEcg1iP9a9VHd!i!LYBjd=XT{=IKXgnMFu=kNg80(v#bUDib6dYVSqG{i?18*UZ<< z`~S5$=o88-i#&4bsfr7W@+$y3u!U}-m^XTY55EWoT2!u@FDLzI>!sGlIfJRi`!9{M z(8|KeCiol`F(9|6x)!3*AH0@t_U=DkKWbBG-(Zg7_lmDYq(^L zU#pV=Muy0Ow-SeAdEB+t+5DEVw`mwWIF$}(w=@c_ZY@lM{k8xx`RPOunY7w7xjZ%| zLe`?wBR6%T*|Cm=MDk;@u#zHp?qtnqc(Qz0qxfTHpZ0oc6SM$Xe<`f7;c@>L{<0h< zVc$S}81bZM_6)fdN`B;1x;?@)01p*2BuHx8-1VaGoxm(a2f=Gb_|&yeUzuD^qrBA5 zE+IEVWeDT|>LGEa(}BA)WS_UW#Ybu|iG6?rX8BB{9O-Xunsiw0&Ci5v%uN66JyviV zn4IywhmAwyO=(eerN9mKE;WGn(_%`UzGbn7VY&rcqF{e^MFyI2Jyw0B)H{nC;-9+R zzDm=Xa0h=3<7}aKBIwbS=mVRQG}VEoVRQ;AS0=g@Q|3qBx!t=kiP?>JnFV6+LtIfX zc$AsU@AOx&o(kToX<#MWcFvseq}-`rI1iO}7hzqS9@qyw zk9v3_qR`T=+N(&mtpPu)ItZV#b#P|r=DSa&9xen~s#(F(e6C}l8*4Ir1~e$$C!Cvt zbBCqJkl8Nb%wAU`uVwCTIUU~&^r`@AJyN>QiyYI$Q_2rKYVj2Mn@SEHL3a1Z0o7gW zx(*>JXLQ3~rP0>-MJv9nE-|y$+0!!&+ME8Q$THL(arhMEA1!BdNjF-iFE#YPaBQ)TS*D8XVW2l#(F4ko*lvx$GiWT{ zVsolf4g+Y6n;nq@U)c>_dsV&!5L1BF2CByBn_bgT)Q-?g62)C_nzU87r+fa@9>%Pk z-etcFn|3%fw)O|s;fKr0PPZVwm(JLljF@lNwAqFN5kAjra{^vM!V;Am(1k~9*p7c@ zdL0Ra)1gbp1>=Q4vaoZ02}DpJ$Z?aE!g(#Ea!cB?AzPw;3Z*s7dW@J>HxUY?bOzx* zSG+3g8@3#*V;$t604W6OF&rN1UDweGTI*u;i^V5J*icxxZHb_CO0x^t<<-@{+9noi zg?|C&D!vo1>c!<2*-kT0iA9ct2)N}|TIYwJYRwBSqC%=0Vaf!@7YU&WM*<2H)`#w2 z-9_bRZ5Q>uiIveI`MuWE2UparIqw&zhbFQY(#+W*^m{8MIqSO98~cSOMz1&S6mg5= zcF1_@G!BfzXrY~(~E2JGTFyt}M5NDWqcJsOiZ+5kPtd%%kgy^P)2!J+HQ=L(_ z80HYJItb_Ya3Oph-8OF?{9w?{A^Ey+!N~1L;K4M?U+#Dt6#KhDp}=ueGn%hvGz){f zqNFT{e+;M2Ip)M9Y-}hewY5c5W}B0^0Y4&RNi^1&jW$1H1g^{ui0Z#n&>k&7o;F~8 zriAA!{qDiUG2ed%NatEH`S3v0=Z}@=XdvQ(Q}oNMVz+C@q*8PKpex4!(_b(1>P7^l zR(_EW;t-XBUu)FaWLwd+Nbm}La_$+Q`b%htKbp9H&ii|$t01SPO4+^fQRu;{LGw)B zIeE{08r>#~Kn5jfp;>PLqyoU+2D`*7RRTnpq}K%Z*C5-`_kYJq>48=JvPTgw4g63fbd8%X$zGGL_v*K+Xj4rXh%g4`T=d|dRh7l;Z z({f%Ev9VXi*f3SD7wU<6M*4gyE;WE6tdu9zB07We2iR*iDScDsMWGYnhkN%bZaVYg zkIL(jpJWsbF&c2eND|1=sb{?WZ-?D&5)`}O>taDIGG&uyVUcXUb7v{EUq*=yS#!9o zYr79lie`>e6`W{>xJpxZ4zpnawA_xvGV7-aE(I}W8B_LP=#&+^ zflXyFJ-$i}YkYi$Slm_BIwHh$7>AD$7%HY1-;2n8w?G4=0SiakwL_aF&Jl(4B&2Op z6_hqj5lz{_3N$OuZrrcR98jy9!T8Uo{XdY#s~oS^5O|CJJ44*Hsb zvY5}5AJeZs%_<~6!9q~9V9tMt+%%`)COE|tVx~ndnlD)vvmT-@uhp{eDyxFj(&KR4 zDfbr-BtcDn`DSL=K{p{q9ut;4~Lt;W#5mdmZ`F% zuyCjO-&hW;$YRyc0qCWO_o$mJ$BU1Qh#EsQy>#|3+QDAztX(vpI(z2?t{Ces;f z4uv<5bU@eK3PIdg4sp;*PhzP+Kw#(D2k&S@O!;@4&TR*st9K=kklah88+M&Dw_%zZ zuQk0p(}l(9a_jg_)tk`VKp5gb>ya6L&+lisXK$g!iiqy($nQIO!+o0P9M-^!ty~lbQtG)8Z|e zvxytzd2dO{FqLEUa+Go@0T(TirvAMw1Mem#SbaN2d{Z;zynakiVbF)%!>{mU=co(LO8e*Cz^cLwGXryh11Pb=8Z017mWQ zznBGg0BiSx*H!t9#brIi-xQDzX<^LlS-~XWsL439b0|_K zYV#B57G4hY>r0`)L^`UgYuK!z<F!++s~ZwkAS3yP{p|E zsam5VTUPw?PN`h+2-YjjZbyEDe>oKtb{{XG*iWba=SD`HmNOlrS}Pw67}PNra1J&y zp~iYl%byavVHB;ACO;P6t4Lx)UJ<~_SBnJ1V1`IrKwjnw5!GhFTPtH4j8~EV*{4+quDz@0PP*WM6-ZcY3?m2Ra=XT5FOK9 zX2H}kZApCsKibU$=1#(DVv1s6s^@id{kW{}E7)&T`5Ol+;Pj0^p4-pJ&KD|?I3c^t zJwxy28Zd?f!>OIpXs!(^sLwhE%vpA0VI*G8AdAsZFiNv_JE-7WvE_mXp>~L-!-V=3$&0wlys{EKg-kXcscOxw`7Na2&3{8!1#@ONMu5ympUO&aRd^-uS78WdW0 zdG8i%Y0@_Fa_=Fow?CM z?AjWG2N+g~9D04|IXMqA8S-?GCElb`(~WXrg{m6ZVXD_oYf(jVGEAE*n4w$p`~YGL zB)v|j)LMeY6t{q2ET@mwByjw->(%*!C!pP?X;`DIF(T4*J;zUPHx6q%UAAV0UBbu~ z#!0Y9H>7Ok*U{lPl*;Unj?K@qmsvs< zV=N|Xc@O+|!4`fW6QVhEh|gx$teg{6q1#dC`e>i>j|6CYQ?}7~P=K9GIK$iI zhH(Hsfi~F}r*ckPw3$%DNWXuUE;AvIQG{0vN5#n4{|V$e=VKg{N=!6(Mk75-MkqX2 zQk=uO_UT3(W6&+n8ft~ykc_1RZ0duC{m8y`EL>bp4^ZRBw&P|zeGzNc57Dz|$Lo1& zvoo=Ff{QkF+;jevk?KYeL=FNSf(6~d+-C#U#E8|^Bbmd_C`Q916B< zF-n!QP^>>fak+at>yZz=y{dgLwc%JX9SD1!hXCJ>2PYG#2TsF!3Ntx*U`mEh8R%AY zm}FAIo8IR}#VNR2NVf>7=E0$Ur0Tk-htWRamK~lIA8$pf3*OIrl4HGPbC;dW1u7m2>~!V3G%# zYRyiU;&x1usU%hxcw??AWaDt^dYP$5u`Yx^Q;5~0NgJ7p@*c4!{3LQx{`70QM3msG z0)6;QreLF=00=TxbL-C{KX+>{An@5glqvrnzFE}|0W<#reQ3J^%(H=ztY#>pUU#OX z5kZ$=c2i>X)03QJ$!#SGIqDC1;B4FuK!_1EM>l&i4P**W&K4*X)sY0HBw_*73T;az z7yUIvysUPZ=OxzSB@A-hQmIy>0o%fKKYoXXy;Wp!(&?54GI~L#c}ezcQN^N#t2F8# zGg@uq%FL`<20UF%0r4QL*O)q-s(yr&4fEr%+==&Xj$L2W?g>$}zdMvDiCy6Tvwf-~ z16_>j6xP8Yt}e`V4rII(*Cg5Z7xyFW-U2CV!fuKdAQ}N$Nxsw(vYBmGfYQqFuKSx- zl@Iw;QR+O^$lxV0eJivdDLhGa;T54 z5mARGlOz>1hqT=kHBg4)PWoaVJ~RGuLG3EPl}U9B%4+7eXnkI9xSGdjL5uK`Emuxk zo{w2kO45>}ZeAsTR#(

5#Za+c*6P=J8VpOUpA9eQcAgCS~d!T);&OO_Z?FAE?JSMhv}QIsXC`jDfgTz(lee^n6AN@X z=x`WVNP}W>rTtvEE5kY<7_oI>Kf!2Z<^l z0q6o3{e&>Q06ge&`jpe@ub%zxX-7B9oJuNGC9aw#FsS#U3a7rM`z|`S00EWk&ga#H zqVS-qyzbMb_qRLM1{X;3{=JkQj`qhtF44?W@JGev+>72A>VaR)z zto*q#7X~npWUu$?c@t5}Qj}xvNSv0BTxbC-BJf1`B_1OSxBXOH=!#9Laz(OfZ1O>tv^r9%5UU6te|BEELMntzVF^`AEmD>5r`W7bAdJ=C@=DjU`iqpv`a zR3O-}#K)-MiE%wz;Hz>?sP(_h>EUU1%Bf7WcHElaQ=+#Fnat_8AyP`>q=5*gtggzblBngv~iL zkU;=-1L#QQjyI^#EEBjr;Z_rb>(6AlSmZ7;W*cd?y-FM+?aR?0)yZTiL@?C9!q(ZQ~iPz`1MG71cy%h;bZEd&iRF>u}V3BpiCUEfuK&-gX z)VeBZBGV?{8jsA7IX_1~xDYpM>R$_-Q|f$JxA!2447fUfFuJyo1{B7(pFm->Uacz? z)zcc6W|^^Zy{%)uvD6;+z}yr&|I6U8CBnEX{{)pF-Ku7yvbag{E5Kwg@8fL;LTwI? z1P|XEv@PftjtMLsHdVZK+B;Ksa5@po8e}|jt540G1A36APE`8wNcyi40-8Ml+v8vq z2F=|N{u|Y7eCGW4KJYDj1@1Gc)^g^~W&``lnOKpoe2)MC0OQA1MZJ}o+yDX6i3)(A Y)C2$k0M%KP*c2B#FarPp000D8T01=OssI20 literal 0 HcmV?d00001 diff --git a/test/test-functions b/test/test-functions new file mode 100644 index 0000000..dac0dcc --- /dev/null +++ b/test/test-functions @@ -0,0 +1,1167 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +PATH=/sbin:/bin:/usr/sbin:/usr/bin +export PATH + +KERNEL_VER=${KERNEL_VER-$(uname -r)} +KERNEL_MODS="/lib/modules/$KERNEL_VER/" + +BASICTOOLS="sh bash setsid loadkeys setfont login sushell sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe" +DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort" + +function find_qemu_bin() { + # SUSE and Red Hat call the binary qemu-kvm + # Debian and Gentoo call it kvm + [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1) + + [ "$ARCH" ] || ARCH=$(uname -m) + case $ARCH in + x86_64) + # QEMU's own build system calls it qemu-system-x86_64 + [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-x86_64 2>/dev/null | grep '^/' -m1) + ;; + i*86) + # new i386 version of QEMU + [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-i386 2>/dev/null | grep '^/' -m1) + + # i386 version of QEMU + [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu 2>/dev/null | grep '^/' -m1) + ;; + esac + + if [ ! -e "$QEMU_BIN" ]; then + echo "Could not find a suitable QEMU binary" >&2 + return 1 + fi +} + +run_qemu() { + [ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER + [ "$INITRD" ] || INITRD=/boot/initramfs-${KERNEL_VER}.img + [ "$QEMU_SMP" ] || QEMU_SMP=1 + + find_qemu_bin || return 1 + + KERNEL_APPEND="root=/dev/sda1 \ +systemd.log_level=debug \ +raid=noautodetect \ +loglevel=2 \ +init=/usr/lib/systemd/systemd \ +ro \ +console=ttyS0 \ +selinux=0 \ +$KERNEL_APPEND \ +" + + QEMU_OPTIONS="-machine accel=kvm:tcg \ +-smp $QEMU_SMP \ +-net none \ +-m 512M \ +-nographic \ +-kernel $KERNEL_BIN \ +" + + if [ "$INITRD" ]; then + QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD" + fi + + ( set -x + $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1 +} + +run_nspawn() { + set -x + ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root /usr/lib/systemd/systemd $KERNEL_APPEND +} + +setup_basic_environment() { + # create the basic filesystem layout + setup_basic_dirs + + install_systemd + install_missing_libraries + install_config_files + create_rc_local + install_basic_tools + install_libnss + install_pam + install_dbus + install_fonts + install_keymaps + install_terminfo + install_execs + install_plymouth + install_debug_tools + install_ld_so_conf + strip_binaries + install_depmod_files + generate_module_dependencies + # softlink mtab + ln -fs /proc/self/mounts $initdir/etc/mtab +} + +install_dmevent() { + instmods dm_crypt =crypto + type -P dmeventd >/dev/null && dracut_install dmeventd + inst_libdir_file "libdevmapper-event.so*" + inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules +} + +install_systemd() { + # install compiled files + (cd $TEST_BASE_DIR/..; set -x; make DESTDIR=$initdir install) + # remove unneeded documentation + rm -fr $initdir/usr/share/{man,doc,gtk-doc} + # we strip binaries since debug symbols increase binaries size a lot + # and it could fill the available space + strip_binaries +} + +install_missing_libraries() { + # install possible missing libraries + for i in $initdir/{sbin,bin}/* $initdir/lib/systemd/*; do + inst_libs $i + done +} + +create_empty_image() { + rm -f "$TESTDIR/rootdisk.img" + # Create the blank file to use as a root filesystem + dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300 + LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img) + [ -b "$LOOPDEV" ] || return 1 + echo "LOOPDEV=$LOOPDEV" >> $STATEFILE + sfdisk -C 9600 -H 2 -S 32 -L "$LOOPDEV" <$initdir/etc/rc.d/rc.local < $initdir/etc/environment + > $initdir/etc/machine-id + # set the hostname + echo systemd-testsuite > $initdir/etc/hostname + # fstab + cat >$initdir/etc/fstab </dev/null | while read _line; do + [[ $_line = 'not a dynamic executable' ]] && break + + if [[ $_line =~ $_so_regex ]]; then + _file=${BASH_REMATCH[1]} + [[ -e ${initdir}/$_file ]] && continue + inst_library "$_file" + continue + fi + + if [[ $_line =~ not\ found ]]; then + dfatal "Missing a shared library required by $_bin." + dfatal "Run \"ldd $_bin\" to find out what it is." + dfatal "$_line" + dfatal "dracut cannot create an initrd." + exit 1 + fi + done +} + +import_testdir() { + STATEFILE=".testdir" + [[ -e $STATEFILE ]] && . $STATEFILE + if [[ -z "$TESTDIR" ]] || [[ ! -d "$TESTDIR" ]]; then + TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX) + echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE + export TESTDIR + fi +} + +import_initdir() { + initdir=$TESTDIR/root + export initdir +} + +## @brief Converts numeric logging level to the first letter of level name. +# +# @param lvl Numeric logging level in range from 1 to 6. +# @retval 1 if @a lvl is out of range. +# @retval 0 if @a lvl is correct. +# @result Echoes first letter of level name. +_lvl2char() { + case "$1" in + 1) echo F;; + 2) echo E;; + 3) echo W;; + 4) echo I;; + 5) echo D;; + 6) echo T;; + *) return 1;; + esac +} + +## @brief Internal helper function for _do_dlog() +# +# @param lvl Numeric logging level. +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +# +# @note This function is not supposed to be called manually. Please use +# dtrace(), ddebug(), or others instead which wrap this one. +# +# This function calls _do_dlog() either with parameter msg, or if +# none is given, it will read standard input and will use every line as +# a message. +# +# This enables: +# dwarn "This is a warning" +# echo "This is a warning" | dwarn +LOG_LEVEL=4 + +dlog() { + [ -z "$LOG_LEVEL" ] && return 0 + [ $1 -le $LOG_LEVEL ] || return 0 + local lvl="$1"; shift + local lvlc=$(_lvl2char "$lvl") || return 0 + + if [ $# -ge 1 ]; then + echo "$lvlc: $*" + else + while read line; do + echo "$lvlc: " "$line" + done + fi +} + +## @brief Logs message at TRACE level (6) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +dtrace() { + set +x + dlog 6 "$@" + [ -n "$debug" ] && set -x || : +} + +## @brief Logs message at DEBUG level (5) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +ddebug() { +# set +x + dlog 5 "$@" +# [ -n "$debug" ] && set -x || : +} + +## @brief Logs message at INFO level (4) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +dinfo() { + set +x + dlog 4 "$@" + [ -n "$debug" ] && set -x || : +} + +## @brief Logs message at WARN level (3) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +dwarn() { + set +x + dlog 3 "$@" + [ -n "$debug" ] && set -x || : +} + +## @brief Logs message at ERROR level (2) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +derror() { +# set +x + dlog 2 "$@" +# [ -n "$debug" ] && set -x || : +} + +## @brief Logs message at FATAL level (1) +# +# @param msg Message. +# @retval 0 It's always returned, even if logging failed. +dfatal() { + set +x + dlog 1 "$@" + [ -n "$debug" ] && set -x || : +} + + +# Generic substring function. If $2 is in $1, return 0. +strstr() { [ "${1#*$2*}" != "$1" ]; } + +# normalize_path +# Prints the normalized path, where it removes any duplicated +# and trailing slashes. +# Example: +# $ normalize_path ///test/test// +# /test/test +normalize_path() { + shopt -q -s extglob + set -- "${1//+(\/)//}" + shopt -q -u extglob + echo "${1%/}" +} + +# convert_abs_rel +# Prints the relative path, when creating a symlink to from . +# Example: +# $ convert_abs_rel /usr/bin/test /bin/test-2 +# ../../bin/test-2 +# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test +convert_abs_rel() { + local __current __absolute __abssize __cursize __newpath + local -i __i __level + + set -- "$(normalize_path "$1")" "$(normalize_path "$2")" + + # corner case #1 - self looping link + [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; } + + # corner case #2 - own dir link + [[ "${1%/*}" == "$2" ]] && { echo "."; return; } + + IFS="/" __current=($1) + IFS="/" __absolute=($2) + + __abssize=${#__absolute[@]} + __cursize=${#__current[@]} + + while [[ ${__absolute[__level]} == ${__current[__level]} ]] + do + (( __level++ )) + if (( __level > __abssize || __level > __cursize )) + then + break + fi + done + + for ((__i = __level; __i < __cursize-1; __i++)) + do + if ((__i > __level)) + then + __newpath=$__newpath"/" + fi + __newpath=$__newpath".." + done + + for ((__i = __level; __i < __abssize; __i++)) + do + if [[ -n $__newpath ]] + then + __newpath=$__newpath"/" + fi + __newpath=$__newpath${__absolute[__i]} + done + + echo "$__newpath" +} + + +# Install a directory, keeping symlinks as on the original system. +# Example: if /lib points to /lib64 on the host, "inst_dir /lib/file" +# will create ${initdir}/lib64, ${initdir}/lib64/file, +# and a symlink ${initdir}/lib -> lib64. +inst_dir() { + [[ -e ${initdir}/"$1" ]] && return 0 # already there + + local _dir="$1" _part="${1%/*}" _file + while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do + _dir="$_part $_dir" + _part=${_part%/*} + done + + # iterate over parent directories + for _file in $_dir; do + [[ -e "${initdir}/$_file" ]] && continue + if [[ -L $_file ]]; then + inst_symlink "$_file" + else + # create directory + mkdir -m 0755 -p "${initdir}/$_file" || return 1 + [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file" + chmod u+w "${initdir}/$_file" + fi + done +} + +# $1 = file to copy to ramdisk +# $2 (optional) Name for the file on the ramdisk +# Location of the image dir is assumed to be $initdir +# We never overwrite the target if it exists. +inst_simple() { + [[ -f "$1" ]] || return 1 + strstr "$1" "/" || return 1 + + local _src=$1 target="${2:-$1}" + if ! [[ -d ${initdir}/$target ]]; then + [[ -e ${initdir}/$target ]] && return 0 + [[ -L ${initdir}/$target ]] && return 0 + [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}" + fi + # install checksum files also + if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then + inst "${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac" + fi + ddebug "Installing $_src" + cp --sparse=always -pfL "$_src" "${initdir}/$target" +} + +# find symlinks linked to given library file +# $1 = library file +# Function searches for symlinks by stripping version numbers appended to +# library filename, checks if it points to the same target and finally +# prints the list of symlinks to stdout. +# +# Example: +# rev_lib_symlinks libfoo.so.8.1 +# output: libfoo.so.8 libfoo.so +# (Only if libfoo.so.8 and libfoo.so exists on host system.) +rev_lib_symlinks() { + [[ ! $1 ]] && return 0 + + local fn="$1" orig="$(readlink -f "$1")" links='' + + [[ ${fn} =~ .*\.so\..* ]] || return 1 + + until [[ ${fn##*.} == so ]]; do + fn="${fn%.*}" + [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}" + done + + echo "${links}" +} + +# Same as above, but specialized to handle dynamic libraries. +# It handles making symlinks according to how the original library +# is referenced. +inst_library() { + local _src="$1" _dest=${2:-$1} _lib _reallib _symlink + strstr "$1" "/" || return 1 + [[ -e $initdir/$_dest ]] && return 0 + if [[ -L $_src ]]; then + # install checksum files also + if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then + inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac" + fi + _reallib=$(readlink -f "$_src") + inst_simple "$_reallib" "$_reallib" + inst_dir "${_dest%/*}" + [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/} + ln -sfn $(convert_abs_rel "${_dest}" "${_reallib}") "${initdir}/${_dest}" + else + inst_simple "$_src" "$_dest" + fi + + # Create additional symlinks. See rev_symlinks description. + for _symlink in $(rev_lib_symlinks $_src) $(rev_lib_symlinks $_reallib); do + [[ ! -e $initdir/$_symlink ]] && { + ddebug "Creating extra symlink: $_symlink" + inst_symlink $_symlink + } + done +} + +# find a binary. If we were not passed the full path directly, +# search in the usual places to find the binary. +find_binary() { + if [[ -z ${1##/*} ]]; then + if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then + echo $1 + return 0 + fi + fi + + type -P $1 +} + +# Same as above, but specialized to install binary executables. +# Install binary executable, and all shared library dependencies, if any. +inst_binary() { + local _bin _target + _bin=$(find_binary "$1") || return 1 + _target=${2:-$_bin} + [[ -e $initdir/$_target ]] && return 0 + [[ -L $_bin ]] && inst_symlink $_bin $_target && return 0 + local _file _line + local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)' + # I love bash! + LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do + [[ $_line = 'not a dynamic executable' ]] && break + + if [[ $_line =~ $_so_regex ]]; then + _file=${BASH_REMATCH[1]} + [[ -e ${initdir}/$_file ]] && continue + inst_library "$_file" + continue + fi + + if [[ $_line =~ not\ found ]]; then + dfatal "Missing a shared library required by $_bin." + dfatal "Run \"ldd $_bin\" to find out what it is." + dfatal "$_line" + dfatal "dracut cannot create an initrd." + exit 1 + fi + done + inst_simple "$_bin" "$_target" +} + +# same as above, except for shell scripts. +# If your shell script does not start with shebang, it is not a shell script. +inst_script() { + local _bin + _bin=$(find_binary "$1") || return 1 + shift + local _line _shebang_regex + read -r -n 80 _line <"$_bin" + # If debug is set, clean unprintable chars to prevent messing up the term + [[ $debug ]] && _line=$(echo -n "$_line" | tr -c -d '[:print:][:space:]') + _shebang_regex='(#! *)(/[^ ]+).*' + [[ $_line =~ $_shebang_regex ]] || return 1 + inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@" +} + +# same as above, but specialized for symlinks +inst_symlink() { + local _src=$1 _target=${2:-$1} _realsrc + strstr "$1" "/" || return 1 + [[ -L $1 ]] || return 1 + [[ -L $initdir/$_target ]] && return 0 + _realsrc=$(readlink -f "$_src") + if ! [[ -e $initdir/$_realsrc ]]; then + if [[ -d $_realsrc ]]; then + inst_dir "$_realsrc" + else + inst "$_realsrc" + fi + fi + [[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}" + [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/} + ln -sfn $(convert_abs_rel "${_target}" "${_realsrc}") "$initdir/$_target" +} + +# attempt to install any programs specified in a udev rule +inst_rule_programs() { + local _prog _bin + + if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then + for _prog in $(grep -E 'PROGRAM==?"[^ "]+' "$1" | sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do + if [ -x /lib/udev/$_prog ]; then + _bin=/lib/udev/$_prog + else + _bin=$(find_binary "$_prog") || { + dinfo "Skipping program $_prog using in udev rule $(basename $1) as it cannot be found" + continue; + } + fi + + #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)" + dracut_install "$_bin" + done + fi +} + +# udev rules always get installed in the same place, so +# create a function to install them to make life simpler. +inst_rules() { + local _target=/etc/udev/rules.d _rule _found + + inst_dir "/lib/udev/rules.d" + inst_dir "$_target" + for _rule in "$@"; do + if [ "${rule#/}" = "$rule" ]; then + for r in /lib/udev/rules.d /etc/udev/rules.d; do + if [[ -f $r/$_rule ]]; then + _found="$r/$_rule" + inst_simple "$_found" + inst_rule_programs "$_found" + fi + done + fi + for r in '' ./ $dracutbasedir/rules.d/; do + if [[ -f ${r}$_rule ]]; then + _found="${r}$_rule" + inst_simple "$_found" "$_target/${_found##*/}" + inst_rule_programs "$_found" + fi + done + [[ $_found ]] || dinfo "Skipping udev rule: $_rule" + done +} + +# general purpose installation function +# Same args as above. +inst() { + local _x + + case $# in + 1) ;; + 2) [[ ! $initdir && -d $2 ]] && export initdir=$2 + [[ $initdir = $2 ]] && set $1;; + 3) [[ -z $initdir ]] && export initdir=$2 + set $1 $3;; + *) dfatal "inst only takes 1 or 2 or 3 arguments" + exit 1;; + esac + for _x in inst_symlink inst_script inst_binary inst_simple; do + $_x "$@" && return 0 + done + return 1 +} + +# install any of listed files +# +# If first argument is '-d' and second some destination path, first accessible +# source is installed into this path, otherwise it will installed in the same +# path as source. If none of listed files was installed, function return 1. +# On first successful installation it returns with 0 status. +# +# Example: +# +# inst_any -d /bin/foo /bin/bar /bin/baz +# +# Lets assume that /bin/baz exists, so it will be installed as /bin/foo in +# initramfs. +inst_any() { + local to f + + [[ $1 = '-d' ]] && to="$2" && shift 2 + + for f in "$@"; do + if [[ -e $f ]]; then + [[ $to ]] && inst "$f" "$to" && return 0 + inst "$f" && return 0 + fi + done + + return 1 +} + +# dracut_install [-o ] [ ... ] +# Install to the initramfs image +# -o optionally install the and don't fail, if it is not there +dracut_install() { + local _optional=no + if [[ $1 = '-o' ]]; then + _optional=yes + shift + fi + while (($# > 0)); do + if ! inst "$1" ; then + if [[ $_optional = yes ]]; then + dinfo "Skipping program $1 as it cannot be found and is" \ + "flagged to be optional" + else + dfatal "Failed to install $1" + exit 1 + fi + fi + shift + done +} + +# Install a single kernel module along with any firmware it may require. +# $1 = full path to kernel module to install +install_kmod_with_fw() { + # no need to go further if the module is already installed + + [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \ + && return 0 + + [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0 + + if [[ $omit_drivers ]]; then + local _kmod=${1##*/} + _kmod=${_kmod%.ko} + _kmod=${_kmod/-/_} + if [[ "$_kmod" =~ $omit_drivers ]]; then + dinfo "Omitting driver $_kmod" + return 1 + fi + if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~ $omit_drivers ]]; then + dinfo "Omitting driver $_kmod" + return 1 + fi + fi + + [ -d "$initdir/.kernelmodseen" ] && \ + > "$initdir/.kernelmodseen/${1##*/}" + + inst_simple "$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \ + || return $? + + local _modname=${1##*/} _fwdir _found _fw + _modname=${_modname%.ko*} + for _fw in $(modinfo -k $KERNEL_VER -F firmware $1 2>/dev/null); do + _found='' + for _fwdir in $fw_dir; do + if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then + inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw" + _found=yes + fi + done + if [[ $_found != yes ]]; then + if ! grep -qe "\<${_modname//-/_}\>" /proc/modules; then + dinfo "Possible missing firmware \"${_fw}\" for kernel module" \ + "\"${_modname}.ko\"" + else + dwarn "Possible missing firmware \"${_fw}\" for kernel module" \ + "\"${_modname}.ko\"" + fi + fi + done + return 0 +} + +# Do something with all the dependencies of a kernel module. +# Note that kernel modules depend on themselves using the technique we use +# $1 = function to call for each dependency we find +# It will be passed the full path to the found kernel module +# $2 = module to get dependencies for +# rest of args = arguments to modprobe +# _fderr specifies FD passed from surrounding scope +for_each_kmod_dep() { + local _func=$1 _kmod=$2 _cmd _modpath _options _found=0 + shift 2 + modprobe "$@" --ignore-install --show-depends $_kmod 2>&${_fderr} | ( + while read _cmd _modpath _options; do + [[ $_cmd = insmod ]] || continue + $_func ${_modpath} || exit $? + _found=1 + done + [[ $_found -eq 0 ]] && exit 1 + exit 0 + ) +} + +# filter kernel modules to install certain modules that meet specific +# requirements. +# $1 = search only in subdirectory of /kernel/$1 +# $2 = function to call with module name to filter. +# This function will be passed the full path to the module to test. +# The behavior of this function can vary depending on whether $hostonly is set. +# If it is, we will only look at modules that are already in memory. +# If it is not, we will look at all kernel modules +# This function returns the full filenames of modules that match $1 +filter_kernel_modules_by_path () ( + local _modname _filtercmd + if ! [[ $hostonly ]]; then + _filtercmd='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"' + _filtercmd+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"' + _filtercmd+=' -o -name "*.ko.xz"' + _filtercmd+=' 2>/dev/null' + else + _filtercmd='cut -d " " -f 1 $initdir/$$.ko + $2 $initdir/$$.ko && echo "$_modname" + rm -f $initdir/$$.ko + ;; + *.ko.xz) xz -dc "$_modname" > $initdir/$$.ko + $2 $initdir/$$.ko && echo "$_modname" + rm -f $initdir/$$.ko + ;; + esac + done +) +find_kernel_modules_by_path () ( + if ! [[ $hostonly ]]; then + find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \ + -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev/null + else + cut -d " " -f 1 /dev/null + fi +) + +filter_kernel_modules () { + filter_kernel_modules_by_path drivers "$1" +} + +find_kernel_modules () { + find_kernel_modules_by_path drivers +} + +# instmods [-c] [ ... ] +# instmods [-c] +# install kernel modules along with all their dependencies. +# can be e.g. "=block" or "=drivers/usb/storage" +instmods() { + [[ $no_kernel = yes ]] && return + # called [sub]functions inherit _fderr + local _fderr=9 + local _check=no + if [[ $1 = '-c' ]]; then + _check=yes + shift + fi + + function inst1mod() { + local _ret=0 _mod="$1" + case $_mod in + =*) + if [ -f $KERNEL_MODS/modules.${_mod#=} ]; then + ( [[ "$_mpargs" ]] && echo $_mpargs + cat "${KERNEL_MODS}/modules.${_mod#=}" ) \ + | instmods + else + ( [[ "$_mpargs" ]] && echo $_mpargs + find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \ + | instmods + fi + ;; + --*) _mpargs+=" $_mod" ;; + i2o_scsi) return ;; # Do not load this diagnostic-only module + *) + _mod=${_mod##*/} + # if we are already installed, skip this module and go on + # to the next one. + [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return + + if [[ $omit_drivers ]] && [[ "$1" =~ $omit_drivers ]]; then + dinfo "Omitting driver ${_mod##$KERNEL_MODS}" + return + fi + # If we are building a host-specific initramfs and this + # module is not already loaded, move on to the next one. + [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc/modules \ + && ! echo $add_drivers | grep -qe "\<${_mod}\>" \ + && return + + # We use '-d' option in modprobe only if modules prefix path + # differs from default '/'. This allows us to use Dracut with + # old version of modprobe which doesn't have '-d' option. + local _moddirname=${KERNEL_MODS%%/lib/modules/*} + [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/" + + # ok, load the module, all its dependencies, and any firmware + # it may require + for_each_kmod_dep install_kmod_with_fw $_mod \ + --set-version $KERNEL_VER ${_moddirname} $_mpargs + ((_ret+=$?)) + ;; + esac + return $_ret + } + + function instmods_1() { + local _mod _mpargs + if (($# == 0)); then # filenames from stdin + while read _mod; do + inst1mod "${_mod%.ko*}" || { + if [ "$_check" = "yes" ]; then + dfatal "Failed to install $_mod" + return 1 + fi + } + done + fi + while (($# > 0)); do # filenames as arguments + inst1mod ${1%.ko*} || { + if [ "$_check" = "yes" ]; then + dfatal "Failed to install $1" + return 1 + fi + } + shift + done + return 0 + } + + local _ret _filter_not_found='FATAL: Module .* not found.' + set -o pipefail + # Capture all stderr from modprobe to _fderr. We could use {var}>... + # redirections, but that would make dracut require bash4 at least. + eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \ + | while read line; do [[ "$line" =~ $_filter_not_found ]] && echo $line || echo $line >&2 ;done | derror + _ret=$? + set +o pipefail + return $_ret +} + +# inst_libdir_file [-n ] [...] +# Install a located on a lib directory to the initramfs image +# -n install non-matching files +inst_libdir_file() { + if [[ "$1" == "-n" ]]; then + local _pattern=$1 + shift 2 + for _dir in $libdirs; do + for _i in "$@"; do + for _f in "$_dir"/$_i; do + [[ "$_i" =~ $_pattern ]] || continue + [[ -e "$_i" ]] && dracut_install "$_i" + done + done + done + else + for _dir in $libdirs; do + for _i in "$@"; do + for _f in "$_dir"/$_i; do + [[ -e "$_f" ]] && dracut_install "$_f" + done + done + done + fi +} + +check_nspawn() { + [[ -d /sys/fs/cgroup/systemd ]] +} + + +do_test() { + if [[ $UID != "0" ]]; then + echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2 + exit 0 + fi + +# Detect lib paths + [[ $libdir ]] || for libdir in /lib64 /lib; do + [[ -d $libdir ]] && libdirs+=" $libdir" && break + done + + [[ $usrlibdir ]] || for usrlibdir in /usr/lib64 /usr/lib; do + [[ -d $usrlibdir ]] && libdirs+=" $usrlibdir" && break + done + + import_testdir + import_initdir + + while (($# > 0)); do + case $1 in + --run) + echo "TEST RUN: $TEST_DESCRIPTION" + test_run + ret=$? + if [ $ret -eq 0 ]; then + echo "TEST RUN: $TEST_DESCRIPTION [OK]" + else + echo "TEST RUN: $TEST_DESCRIPTION [FAILED]" + fi + exit $ret;; + --setup) + echo "TEST SETUP: $TEST_DESCRIPTION" + test_setup + exit $?;; + --clean) + echo "TEST CLEANUP: $TEST_DESCRIPTION" + test_cleanup + rm -fr "$TESTDIR" + rm -f .testdir + exit $?;; + --all) + echo -n "TEST: $TEST_DESCRIPTION "; + ( + test_setup && test_run + ret=$? + test_cleanup + rm -fr "$TESTDIR" + rm -f .testdir + exit $ret + ) test.log 2>&1 + ret=$? + if [ $ret -eq 0 ]; then + rm test.log + echo "[OK]" + else + echo "[FAILED]" + echo "see $(pwd)/test.log" + fi + exit $ret;; + *) break ;; + esac + shift + done +} diff --git a/test/testsuite.target b/test/testsuite.target new file mode 100644 index 0000000..1a7e5b3 --- /dev/null +++ b/test/testsuite.target @@ -0,0 +1,6 @@ +[Unit] +Description=Testsuite target +Requires=multi-user.target +After=multi-user.target +Conflicts=rescue.target +AllowIsolate=yes diff --git a/test/udev-test.pl b/test/udev-test.pl new file mode 100755 index 0000000..23f1b72 --- /dev/null +++ b/test/udev-test.pl @@ -0,0 +1,1530 @@ +#!/usr/bin/perl + +# udev test +# +# Provides automated testing of the udev binary. +# The whole test is self contained in this file, except the matching sysfs tree. +# Simply extend the @tests array, to add a new test variant. +# +# Every test is driven by its own temporary config file. +# This program prepares the environment, creates the config and calls udev. +# +# udev parses the rules, looks at the provided sysfs and +# first creates and then removes the device node. +# After creation and removal the result is checked against the +# expected value and the result is printed. +# +# Copyright (C) 2004-2012 Kay Sievers +# Copyright (C) 2004 Leann Ogasawara + +use warnings; +use strict; + +my $udev_bin = "./test-udev"; +my $valgrind = 0; +my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin"; +my $udev_dev = "test/dev"; +my $udev_run = "test/run"; +my $udev_rules_dir = "$udev_run/udev/rules.d"; +my $udev_rules = "$udev_rules_dir/udev-test.rules"; + +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_rem_error => "yes", + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "catch device by *", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "modem/0" , + rules => < "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" , + rules => < "catch device by ?", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "modem/0" , + rules => < "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" , + rules => < "replace kernel name", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "modem" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "preserve backslashes, if they are not for a newline", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "aaa", + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "import of shell-value returned from program", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node12345678", + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "test substitution by variable name", + 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", + rules => < "test substitution by variable name 2", + 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", + rules => < "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" , + rules => < "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" , + rules => < "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" , + rules => < "non matching SUBSYSTEMS for device with no parent", + devpath => "/devices/virtual/tty/console", + exp_name => "TTY", + rules => < "non matching SUBSYSTEMS", + devpath => "/devices/virtual/tty/console", + exp_name => "TTY" , + rules => < "ATTRS match", + devpath => "/devices/virtual/tty/console", + exp_name => "foo" , + rules => < "ATTR (empty file)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "empty" , + rules => < "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" , + rules => < "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" , + rules => < "sysfs parent hierarchy", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "modem" , + rules => < "name test with ! in the name", + devpath => "/devices/virtual/block/fake!blockdev0", + exp_name => "is/a/fake/blockdev0" , + rules => < "name test with ! in the name, but no matching rule", + devpath => "/devices/virtual/block/fake!blockdev0", + exp_name => "fake/blockdev0" , + exp_rem_error => "yes", + rules => < "KERNELS rule", + 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 => < "KERNELS wildcard all", + 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 => < "KERNELS wildcard partial", + 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 => < "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 => < "substitute attr with link target value (first match)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "driver-is-sd", + rules => < "substitute attr with link target value (currently selected device)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "driver-is-ahci", + rules => < "ignore ATTRS attribute whitespace", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "ignored", + rules => < "do not ignore ATTRS attribute whitespace", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "matched-with-space", + rules => < "permissions USER=bad GROUP=name", + devpath => "/devices/virtual/tty/tty33", + exp_name => "tty33", + exp_perms => "0:0:0600", + rules => < "permissions OWNER=5000", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => "5000::0600", + rules => < "permissions GROUP=100", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => ":100:0660", + rules => < "textual user id", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => "nobody::0600", + rules => < "textual group id", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => ":daemon:0660", + rules => < "textual user/group id", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => "root:mail:0660", + rules => < "permissions MODE=0777", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => "::0777", + rules => < "permissions OWNER=5000 GROUP=100 MODE=0777", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_perms => "5000:100:0777", + rules => < "permissions OWNER to 5000", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "5000::", + rules => < "permissions GROUP to 100", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => ":100:0660", + rules => < "permissions MODE to 0060", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "::0060", + rules => < "permissions OWNER, GROUP, MODE", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "5000:100:0777", + rules => < "permissions only rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "5000:100:0777", + rules => < "multiple permissions only rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "3000:4000:0777", + rules => < "permissions only rule with override at SYMLINK+ rule", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "ttyACM0", + exp_perms => "3000:8000:0777", + rules => < "major/minor number test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + exp_majorminor => "8:0", + rules => < "big major number test", + devpath => "/devices/virtual/misc/misc-fake1", + exp_name => "node", + exp_majorminor => "4095:1", + rules => < "big major and big minor number test", + devpath => "/devices/virtual/misc/misc-fake89999", + exp_name => "node", + exp_majorminor => "4095:89999", + rules => < "multiple symlinks with format char", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "symlink2-ttyACM0", + rules => < "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 => " ", + rules => < "symlink creation (same directory)", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "modem0", + rules => < "multiple symlinks", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "second-0" , + rules => < "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", + rules => < "symlink node to itself", + devpath => "/devices/virtual/tty/tty0", + exp_name => "link", + exp_add_error => "yes", + exp_rem_error => "yes", + option => "clean", + rules => < "symlink %n substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "symlink0", + rules => < "symlink %k substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "symlink-ttyACM0", + rules => < "symlink %M:%m substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "major-166:0", + rules => < "symlink %b substitution", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "symlink-0:0:0:0", + rules => < "symlink %c substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "test", + rules => < "symlink %c{N} substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "test", + rules => < "symlink %c{N+} substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "this", + rules => < "symlink only rule with %c{N+}", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "test", + rules => < "symlink %s{filename} substitution", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "166:0", + rules => < "program result substitution (numbered part of)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", + exp_name => "link1", + rules => < "program result substitution (numbered part of+)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", + exp_name => "link4", + rules => < "SUBSYSTEM match test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + rules => < "DRIVERS match test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + rules => < "devnode substitution test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node", + rules => < "parent node name substitution test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "sda-part-1", + rules => < "udev_root substitution", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "start-/dev-end", + rules => < "last_rule option", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "last", + rules => < "negation KERNEL!=", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "match", + rules => < "negation SUBSYSTEM!=", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "not-anything", + rules => < "negation PROGRAM!= exit code", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "nonzero-program", + rules => < "ENV{} test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "true", + rules => < "ENV{} test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "true", + rules => < "ENV{} test (assign)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "true", + rules => < "ENV{} test (assign 2 times)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "true", + rules => < "ENV{} test (assign2)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "part", + rules => < "untrusted string sanitize", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "sane", + rules => < "untrusted string sanitize (don't replace utf8)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "uber", + rules => < "untrusted string sanitize (replace invalid utf8)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "replaced", + rules => < "read sysfs value from parent device", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "serial-354172020305000", + rules => < "match against empty key string", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "ok", + rules => < "check ACTION value", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "ok", + rules => < "final assignment", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "ok", + exp_perms => "root:tty:0640", + rules => < "final assignment 2", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "ok", + exp_perms => "root:tty:0640", + rules => < "env substitution", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "node-add-me", + rules => < "reset list to current value", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "three", + not_exp_name => "two", + rules => < "test empty SYMLINK+ (empty override)", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "right", + not_exp_name => "wrong", + rules => < "test multi matches", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "right", + rules => < "test multi matches 2", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "right", + rules => < "test multi matches 3", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "right", + rules => < "test multi matches 4", + devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", + exp_name => "right", + rules => < "IMPORT parent test sequence 1/2 (keep)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "parent", + option => "keep", + rules => < "IMPORT parent test sequence 2/2 (keep)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "parentenv-parent_right", + option => "clean", + rules => < "GOTO test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "right", + rules => < "GOTO label does not exist", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "right", + rules => < "SYMLINK+ compare test", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "right", + not_exp_name => "wrong", + rules => < "invalid key operation", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "yes", + rules => < "operator chars in attribute", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "yes", + rules => < "overlong comment line", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", + exp_name => "yes", + rules => < "magic subsys/kernel lookup", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "00:16:41:e2:8d:ff", + rules => < "TEST absolute path", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "there", + rules => < "TEST subsys/kernel lookup", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "yes", + rules => < "TEST relative path", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "relative", + rules => < "TEST wildcard substitution (find queue/nr_requests)", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "found-subdir", + rules => < "TEST MODE=0000", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "sda", + exp_perms => "0:0:0000", + exp_rem_error => "yes", + rules => < "TEST PROGRAM feeds OWNER, GROUP, MODE", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "sda", + exp_perms => "5000:100:0400", + exp_rem_error => "yes", + rules => < "TEST PROGRAM feeds MODE with overflow", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "sda", + exp_perms => "0:0:0440", + exp_rem_error => "yes", + rules => < "magic [subsys/sysname] attribute substitution", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "sda-8741C4G-end", + exp_perms => "0:0:0600", + rules => < "builtin path_id", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0", + rules => <$udev_rules" || die "unable to create rules file: $udev_rules"; + print CONF $$rules; + close CONF; + + if ($valgrind > 0) { + system("$udev_bin_valgrind $action $devpath"); + } else { + system("$udev_bin", "$action", "$devpath"); + } +} + +my $error = 0; + +sub permissions_test { + my($rules, $uid, $gid, $mode) = @_; + + my $wrong = 0; + my $userid; + my $groupid; + + $rules->{exp_perms} =~ m/^(.*):(.*):(.*)$/; + if ($1 ne "") { + if (defined(getpwnam($1))) { + $userid = int(getpwnam($1)); + } else { + $userid = $1; + } + if ($uid != $userid) { $wrong = 1; } + } + if ($2 ne "") { + if (defined(getgrnam($2))) { + $groupid = int(getgrnam($2)); + } else { + $groupid = $2; + } + if ($gid != $groupid) { $wrong = 1; } + } + if ($3 ne "") { + if (($mode & 07777) != oct($3)) { $wrong = 1; }; + } + if ($wrong == 0) { + print "permissions: ok\n"; + } else { + printf " expected permissions are: %s:%s:%#o\n", $1, $2, oct($3); + printf " created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777; + print "permissions: error\n"; + $error++; + sleep(1); + } +} + +sub major_minor_test { + my($rules, $rdev) = @_; + + my $major = ($rdev >> 8) & 0xfff; + my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00); + my $wrong = 0; + + $rules->{exp_majorminor} =~ m/^(.*):(.*)$/; + if ($1 ne "") { + if ($major != $1) { $wrong = 1; }; + } + if ($2 ne "") { + if ($minor != $2) { $wrong = 1; }; + } + if ($wrong == 0) { + print "major:minor: ok\n"; + } else { + printf " expected major:minor is: %i:%i\n", $1, $2; + printf " created major:minor is : %i:%i\n", $major, $minor; + print "major:minor: error\n"; + $error++; + sleep(1); + } +} + +sub udev_setup { + system("rm", "-rf", "$udev_dev"); + mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n"; + # setting group and mode of udev_dev ensures the tests work + # even if the parent directory has setgid bit enabled. + chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n"; + chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n"; + + system("rm", "-rf", "$udev_run"); +} + +sub run_test { + my ($rules, $number) = @_; + + print "TEST $number: $rules->{desc}\n"; + print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n"; + + udev("add", $rules->{devpath}, \$rules->{rules}); + if (defined($rules->{not_exp_name})) { + if ((-e "$udev_dev/$rules->{not_exp_name}") || + (-l "$udev_dev/$rules->{not_exp_name}")) { + print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n"; + $error++; + sleep(1); + } + } + + if ((-e "$udev_dev/$rules->{exp_name}") || + (-l "$udev_dev/$rules->{exp_name}")) { + + my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, + $atime, $mtime, $ctime, $blksize, $blocks) = stat("$udev_dev/$rules->{exp_name}"); + + if (defined($rules->{exp_perms})) { + permissions_test($rules, $uid, $gid, $mode); + } + if (defined($rules->{exp_majorminor})) { + major_minor_test($rules, $rdev); + } + print "add: ok\n"; + } else { + print "add: error"; + if ($rules->{exp_add_error}) { + print " as expected\n"; + } else { + print "\n"; + system("tree", "$udev_dev"); + print "\n"; + $error++; + sleep(1); + } + } + + if (defined($rules->{option}) && $rules->{option} eq "keep") { + print "\n\n"; + return; + } + + udev("remove", $rules->{devpath}, \$rules->{rules}); + if ((-e "$udev_dev/$rules->{exp_name}") || + (-l "$udev_dev/$rules->{exp_name}")) { + print "remove: error"; + if ($rules->{exp_rem_error}) { + print " as expected\n"; + } else { + print "\n"; + system("tree", "$udev_dev"); + print "\n"; + $error++; + sleep(1); + } + } else { + print "remove: ok\n"; + } + + print "\n"; + + if (defined($rules->{option}) && $rules->{option} eq "clean") { + udev_setup(); + } + +} + +# only run if we have root permissions +# due to mknod restrictions +if (!($<==0)) { + print "Must have root permissions to run properly.\n"; + exit; +} + +udev_setup(); + +my $test_num = 1; +my @list; + +foreach my $arg (@ARGV) { + if ($arg =~ m/--valgrind/) { + $valgrind = 1; + printf("using valgrind\n"); + } else { + push(@list, $arg); + } +} + +if ($list[0]) { + foreach my $arg (@list) { + if (defined($tests[$arg-1]->{desc})) { + print "udev-test will run test number $arg:\n\n"; + run_test($tests[$arg-1], $arg); + } else { + print "test does not exist.\n"; + } + } +} else { + # test all + print "\nudev-test will run ".($#tests + 1)." tests:\n\n"; + + foreach my $rules (@tests) { + run_test($rules, $test_num); + $test_num++; + } +} + +print "$error errors occurred\n\n"; + +# cleanup +system("rm", "-rf", "$udev_dev"); +system("rm", "-rf", "$udev_run"); + +if ($error > 0) { + exit(1); +} +exit(0); diff --git a/test/unstoppable.service b/test/unstoppable.service new file mode 100644 index 0000000..24fb0a2 --- /dev/null +++ b/test/unstoppable.service @@ -0,0 +1,5 @@ +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/echo 'I'm unstoppable!' +ExecStop=/bin/systemctl start --no-block unstoppable.service diff --git a/test1/default.target b/test1/default.target deleted file mode 120000 index 264d980..0000000 --- a/test1/default.target +++ /dev/null @@ -1 +0,0 @@ -multiuser.target \ No newline at end of file diff --git a/test1/exec-demo.service b/test1/exec-demo.service deleted file mode 100644 index 5802e37..0000000 --- a/test1/exec-demo.service +++ /dev/null @@ -1,9 +0,0 @@ -[Meta] -Description=Simple Execution Demo - -[Service] -ExecStartPre=/bin/ps -eo pid,uid,args,cgroup -ExecStartPre=/bin/cat /etc/hosts -ExecStart=/bin/bash -c '/bin/sleep 5 &' -Type=forking -Output=syslog diff --git a/test1/fifo-demo.service b/test1/fifo-demo.service deleted file mode 100644 index 51b1996..0000000 --- a/test1/fifo-demo.service +++ /dev/null @@ -1,8 +0,0 @@ -[Meta] -Description=FIFO Activation Demo Service - -[Service] -ExecStartPre=/bin/echo "Wow, es geht los!" -#ExecStart=/bin/bash -c 'read a <&3 ; echo "GOT: $a"' -ExecStart=/bin/bash -c 'cat <&3' -Type=simple diff --git a/test1/fifo-demo.socket b/test1/fifo-demo.socket deleted file mode 100644 index 75ce7a6..0000000 --- a/test1/fifo-demo.socket +++ /dev/null @@ -1,6 +0,0 @@ -[Meta] -Description=FIFO Activation Demo Socket - -[Socket] -ListenFIFO=/tmp/systemd-fifo-demo -ExecStartPost=/bin/echo "OK, we're ready, now write something to /tmp/systemd-fifo-demo" diff --git a/test1/mail-transfer-agent.service b/test1/mail-transfer-agent.service deleted file mode 120000 index bca89da..0000000 --- a/test1/mail-transfer-agent.service +++ /dev/null @@ -1 +0,0 @@ -postfix.service \ No newline at end of file diff --git a/test1/mail-transfer-agent.socket b/test1/mail-transfer-agent.socket deleted file mode 120000 index daf3277..0000000 --- a/test1/mail-transfer-agent.socket +++ /dev/null @@ -1 +0,0 @@ -postfix.socket \ No newline at end of file diff --git a/test1/multiuser.target b/test1/multiuser.target deleted file mode 100644 index f105e3c..0000000 --- a/test1/multiuser.target +++ /dev/null @@ -1,2 +0,0 @@ -[Meta] -Description=Multi-User Target diff --git a/test1/multiuser.target.wants/exec-demo.service b/test1/multiuser.target.wants/exec-demo.service deleted file mode 120000 index 0ec1e35..0000000 --- a/test1/multiuser.target.wants/exec-demo.service +++ /dev/null @@ -1 +0,0 @@ -../exec-demo.service \ No newline at end of file diff --git a/test1/multiuser.target.wants/fifo-demo.socket b/test1/multiuser.target.wants/fifo-demo.socket deleted file mode 120000 index 4c3d621..0000000 --- a/test1/multiuser.target.wants/fifo-demo.socket +++ /dev/null @@ -1 +0,0 @@ -../fifo-demo.socket \ No newline at end of file diff --git a/test1/multiuser.target.wants/mail-transfer-agent.socket b/test1/multiuser.target.wants/mail-transfer-agent.socket deleted file mode 120000 index 3c3a2db..0000000 --- a/test1/multiuser.target.wants/mail-transfer-agent.socket +++ /dev/null @@ -1 +0,0 @@ -../mail-transfer-agent.socket \ No newline at end of file diff --git a/test1/multiuser.target.wants/permissions.service b/test1/multiuser.target.wants/permissions.service deleted file mode 120000 index 98f3d5f..0000000 --- a/test1/multiuser.target.wants/permissions.service +++ /dev/null @@ -1 +0,0 @@ -../permissions.service \ No newline at end of file diff --git a/test1/multiuser.target.wants/systemd-logger.socket b/test1/multiuser.target.wants/systemd-logger.socket deleted file mode 120000 index 4ce0a61..0000000 --- a/test1/multiuser.target.wants/systemd-logger.socket +++ /dev/null @@ -1 +0,0 @@ -../systemd-logger.socket \ No newline at end of file diff --git a/test1/permissions.service b/test1/permissions.service deleted file mode 100644 index cb0664f..0000000 --- a/test1/permissions.service +++ /dev/null @@ -1,11 +0,0 @@ -[Meta] -Description=Permission Enforcement checker - -[Service] -ExecStart=/usr/bin/id -ExecStartPost=/usr/bin/env -ExecStartPost=/bin/sleep 5 -Type=oneshot -Capabilities=all= cap_dac_override=eip -User=nobody -Group=nobody diff --git a/test1/postfix.service b/test1/postfix.service deleted file mode 100644 index fbf39ec..0000000 --- a/test1/postfix.service +++ /dev/null @@ -1,7 +0,0 @@ -[Meta] -Names=mail-transfer-agent.service -Description=Postfix Mail Server -Requires=syslog.socket - -[Service] -ExecStart=/usr/bin/postfix diff --git a/test1/postfix.socket b/test1/postfix.socket deleted file mode 100644 index 9d650a1..0000000 --- a/test1/postfix.socket +++ /dev/null @@ -1,13 +0,0 @@ -[Meta] -Description=Postfix SMTP Socket - -[Socket] -ListenStream=53333 -ListenFIFO=/tmp/systemd-postfix-fifo -ExecStartPre=/bin/echo "About to create sockets..." -ExecStartPre=/bin/echo "About to create sockets... 2" -ExecStartPost=/bin/echo "Created sockets..." -ExecStopPre=/bin/echo "About to delete sockets..." -ExecStopPost=/bin/echo "Deleted sockets..." -ExecStopPost=/bin/echo "Deleted sockets... 2" -#BindToDevice=eth0 diff --git a/test1/syslog.service b/test1/syslog.service deleted file mode 100644 index 8fe47ae..0000000 --- a/test1/syslog.service +++ /dev/null @@ -1,5 +0,0 @@ -[Meta] -Description=System Logging Daemon - -[Service] -ExecStart=/usr/bin/rsyslogd --foobar 'waldo' diff --git a/test1/syslog.socket b/test1/syslog.socket deleted file mode 100644 index f2d3297..0000000 --- a/test1/syslog.socket +++ /dev/null @@ -1,8 +0,0 @@ -[Meta] -Description=Syslog Socket - -[Socket] -ListenDatagram=/tmp/foobar/waldo/systemd-syslog-socket -ListenStream=eth0:3456 -DirectoryMode=0700 -SocketMode=0600 diff --git a/test1/systemd-logger.service b/test1/systemd-logger.service deleted file mode 100644 index c406d26..0000000 --- a/test1/systemd-logger.service +++ /dev/null @@ -1,13 +0,0 @@ -[Meta] -Description=systemd Logging Daemon - -[Service] -ExecStart=/home/lennart/projects/systemd/systemd-logger -Type=simple -TimerSlackNS=1000000 -OOMScoreAdjust=40 -LimitCORE=0 -LimitFSIZE=0 -LimitLOCKS=0 -LimitMEMLOCK=0 -LimitNOFILE=512 diff --git a/test1/systemd-logger.socket b/test1/systemd-logger.socket deleted file mode 100644 index eb012c8..0000000 --- a/test1/systemd-logger.socket +++ /dev/null @@ -1,5 +0,0 @@ -[Meta] -Description=systemd Logging Socket - -[Socket] -ListenStream=@/org/freedesktop/systemd1/logger diff --git a/test2/Makefile b/test2/Makefile deleted file mode 100644 index 9aa46b4..0000000 --- a/test2/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# Just a little hook script to easy building when in this directory - -all: - $(MAKE) -C .. - -clean: - $(MAKE) -C .. clean diff --git a/tmpfiles.d/Makefile b/tmpfiles.d/Makefile new file mode 120000 index 0000000..bd10475 --- /dev/null +++ b/tmpfiles.d/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/tmpfiles.d/legacy.conf b/tmpfiles.d/legacy.conf index c357b18..a165687 100644 --- a/tmpfiles.d/legacy.conf +++ b/tmpfiles.d/legacy.conf @@ -1,22 +1,34 @@ # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. # See tmpfiles.d(5) for details # These files are considered legacy and are unnecessary on legacy-free -# systems. /run/lock/subsys is used for serializing SysV service -# execution, and hence without use on SysV-less systems. -# +# systems. + +d /run/lock 0755 root root - + +# /run/lock/subsys is used for serializing SysV service execution, and +# hence without use on SysV-less systems. + +d /run/lock/subsys 0755 root root - + # /run/lock/lockdev is used to serialize access to tty devices via # LCK..xxx style lock files, For more information see: # http://lists.freedesktop.org/archives/systemd-devel/2011-March/001823.html # On modern systems a BSD file lock is a better choice if # serialization is needed on those devices. -d /run/lock 1777 root root - -d /run/lock/subsys 0755 root root - -d /run/lock/lockdev 0775 root root - +d /run/lock/lockdev 0775 root lock - + +# /forcefsck, /fastboot and /forcequotecheck are deprecated in favor of the +# kernel command line options 'fsck.mode=force', 'fsck.mode=skip' and +# 'quotacheck.mode=force' + +r! /forcefsck +r! /fastboot +r! /forcequotacheck diff --git a/tmpfiles.d/systemd-nologin.conf b/tmpfiles.d/systemd-nologin.conf new file mode 100644 index 0000000..d61232b --- /dev/null +++ b/tmpfiles.d/systemd-nologin.conf @@ -0,0 +1,11 @@ +# 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. + +# See tmpfiles.d(5) and systemd-forbid-user-logins.service(5). +# This file has special suffix so it is not run by mistake. + +F! /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)" diff --git a/tmpfiles.d/systemd.conf b/tmpfiles.d/systemd.conf index be29c06..7c6d6b9 100644 --- a/tmpfiles.d/systemd.conf +++ b/tmpfiles.d/systemd.conf @@ -1,25 +1,28 @@ # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. # See tmpfiles.d(5) for details -d /run/user 0755 root root 10d -F /run/utmp 0664 root utmp - +d /run/user 0755 root root ~10d +F! /run/utmp 0664 root utmp - f /var/log/wtmp 0664 root utmp - f /var/log/btmp 0600 root utmp - d /var/cache/man - - - 30d -r /forcefsck -r /forcequotacheck -r /fastboot - d /run/systemd/ask-password 0755 root root - d /run/systemd/seats 0755 root root - d /run/systemd/sessions 0755 root root - d /run/systemd/users 0755 root root - +d /run/systemd/machines 0755 root root - +d /run/systemd/shutdown 0755 root root - + +m /var/log/journal 2755 root systemd-journal - - +m /var/log/journal/%m 2755 root systemd-journal - - +m /run/log/journal 2755 root systemd-journal - - +m /run/log/journal/%m 2755 root systemd-journal - - diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf index 8915b82..b80dab4 100644 --- a/tmpfiles.d/tmp.conf +++ b/tmpfiles.d/tmp.conf @@ -1,8 +1,8 @@ # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. # See tmpfiles.d(5) for details @@ -10,3 +10,9 @@ # Clear tmp directories separately, to make them easier to override d /tmp 1777 root root 10d d /var/tmp 1777 root root 30d + +# Exclude namespace mountpoints created with PrivateTmp=yes +x /tmp/systemd-private-%b-* +X /tmp/systemd-private-%b-*/tmp +x /var/tmp/systemd-private-%b-* +X /var/tmp/systemd-private-%b-*/tmp diff --git a/tmpfiles.d/x11.conf b/tmpfiles.d/x11.conf index 7f81af6..4c96a54 100644 --- a/tmpfiles.d/x11.conf +++ b/tmpfiles.d/x11.conf @@ -1,8 +1,8 @@ # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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. # See tmpfiles.d(5) for details @@ -15,4 +15,4 @@ d /tmp/.font-unix 1777 root root 10d d /tmp/.Test-unix 1777 root root 10d # Unlink the X11 lock files -r /tmp/.X[0-9]*-lock +r! /tmp/.X[0-9]*-lock diff --git a/tools/check-includes.pl b/tools/check-includes.pl new file mode 100755 index 0000000..bf23929 --- /dev/null +++ b/tools/check-includes.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +# +# checkincludes: Find files included more than once in (other) files. +# Copyright abandoned, 2000, Niels Kristian Bech Jensen . + +foreach $file (@ARGV) { + open(FILE, $file) or die "Cannot open $file: $!.\n"; + + my %includedfiles = (); + + while () { + if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { + ++$includedfiles{$1}; + } + } + foreach $filename (keys %includedfiles) { + if ($includedfiles{$filename} > 1) { + print "$file: $filename is included more than once.\n"; + } + } + + close(FILE); +} diff --git a/tools/make-directive-index.py b/tools/make-directive-index.py new file mode 100755 index 0000000..2ff304f --- /dev/null +++ b/tools/make-directive-index.py @@ -0,0 +1,320 @@ +# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2012-2013 Zbigniew Jędrzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . + +import sys +import collections +import re +from xml_helper import * +from copy import deepcopy + +TEMPLATE = '''\ + + + + systemd.directives + systemd + + + + Developer + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + systemd.directives + 7 + + + + systemd.directives + Index of configuration directives + + + + Unit directives + + Directives for configuring units, used in unit + files. + + + + + + Options on the kernel command line + + Kernel boot options for configuring the behaviour of the + systemd process. + + + + + + Environment variables + + Environment variables understood by the systemd + manager and other programs. + + + + + + UDEV directives + + Directives for configuring systemd units through the + udev database. + + + + + + Network directives + + Directives for configuring network links through the + net-setup-link udev builtin and networks through + systemd-networkd. + + + + + + Journal fields + + Fields in the journal events with a well known meaning. + + + + + + PAM configuration directives + + Directives for configuring PAM behaviour. + + + + + + crypttab options + + Options which influence mounted filesystems and + encrypted volumes. + + + + + + System manager directives + + Directives for configuring the behaviour of the + systemd process. + + + + + + bootchart.conf directives + + Directives for configuring the behaviour of the + systemd-bootchart process. + + + + + + command-line options + + Command-line options accepted by programs in the + systemd suite. + + + + + + Constants + + Various constant used and/or defined by systemd. + + + + + + Miscellaneous options and directives + + Other configuration elements which don't fit in + any of the above groups. + + + + + + Files and directories + + Paths and file names referred to in the + documentation. + + + + + + Colophon + + + +''' + +COLOPHON = '''\ +This index contains {count} entries in {sections} sections, +referring to {pages} individual manual pages. +''' + +def _extract_directives(directive_groups, formatting, page): + t = xml_parse(page) + section = t.find('./refmeta/manvolnum').text + pagename = t.find('./refmeta/refentrytitle').text + + storopt = directive_groups['options'] + for variablelist in t.iterfind('.//variablelist'): + klass = variablelist.attrib.get('class') + storvar = directive_groups[klass or 'miscellaneous'] + #